summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/Kconfig11
-rw-r--r--drivers/acpi/Makefile3
-rw-r--r--drivers/acpi/acpi_adxl.c192
-rw-r--r--drivers/acpi/acpi_ipmi.c4
-rw-r--r--drivers/acpi/acpi_lpit.c6
-rw-r--r--drivers/acpi/acpi_lpss.c120
-rw-r--r--drivers/acpi/acpi_memhotplug.c4
-rw-r--r--drivers/acpi/acpi_pad.c1
-rw-r--r--drivers/acpi/acpi_processor.c7
-rw-r--r--drivers/acpi/acpi_tad.c201
-rw-r--r--drivers/acpi/acpica/Makefile1
-rw-r--r--drivers/acpi/acpica/acevents.h2
-rw-r--r--drivers/acpi/acpica/acinterp.h23
-rw-r--r--drivers/acpi/acpica/aclocal.h2
-rw-r--r--drivers/acpi/acpica/amlcode.h10
-rw-r--r--drivers/acpi/acpica/dsopcode.c4
-rw-r--r--drivers/acpi/acpica/evregion.c17
-rw-r--r--drivers/acpi/acpica/evrgnini.c6
-rw-r--r--drivers/acpi/acpica/evxfregn.c1
-rw-r--r--drivers/acpi/acpica/exfield.c326
-rw-r--r--drivers/acpi/acpica/exserial.c360
-rw-r--r--drivers/acpi/acpica/psloop.c16
-rw-r--r--drivers/acpi/acpica/tbxfload.c3
-rw-r--r--drivers/acpi/arm64/iort.c2
-rw-r--r--drivers/acpi/bus.c44
-rw-r--r--drivers/acpi/cppc_acpi.c8
-rw-r--r--drivers/acpi/custom_method.c3
-rw-r--r--drivers/acpi/device_pm.c1
-rw-r--r--drivers/acpi/glue.c2
-rw-r--r--drivers/acpi/nfit/core.c286
-rw-r--r--drivers/acpi/nfit/intel.h38
-rw-r--r--drivers/acpi/nfit/mce.c8
-rw-r--r--drivers/acpi/nfit/nfit.h21
-rw-r--r--drivers/acpi/numa.c1
-rw-r--r--drivers/acpi/osl.c16
-rw-r--r--drivers/acpi/pci_root.c17
-rw-r--r--drivers/acpi/pmic/intel_pmic_bxtwc.c12
-rw-r--r--drivers/acpi/pmic/intel_pmic_chtdc_ti.c1
-rw-r--r--drivers/acpi/pmic/intel_pmic_chtwc.c10
-rw-r--r--drivers/acpi/pmic/intel_pmic_crc.c16
-rw-r--r--drivers/acpi/pmic/intel_pmic_xpower.c33
-rw-r--r--drivers/acpi/pmic/tps68470_pmic.c2
-rw-r--r--drivers/acpi/pptt.c33
-rw-r--r--drivers/acpi/processor_idle.c1
-rw-r--r--drivers/acpi/property.c97
-rw-r--r--drivers/acpi/sbs.c8
-rw-r--r--drivers/acpi/sbshc.c2
-rw-r--r--drivers/acpi/scan.c11
-rw-r--r--drivers/acpi/tables.c3
-rw-r--r--drivers/acpi/x86/apple.c6
-rw-r--r--drivers/acpi/x86/utils.c2
-rw-r--r--drivers/android/Kconfig2
-rw-r--r--drivers/android/binder.c489
-rw-r--r--drivers/android/binder_trace.h36
-rw-r--r--drivers/ata/Kconfig5
-rw-r--r--drivers/ata/ahci.h2
-rw-r--r--drivers/ata/ahci_brcm.c8
-rw-r--r--drivers/ata/ahci_platform.c15
-rw-r--r--drivers/ata/ahci_sunxi.c3
-rw-r--r--drivers/ata/libahci_platform.c54
-rw-r--r--drivers/ata/libata-core.c1
-rw-r--r--drivers/ata/libata-scsi.c4
-rw-r--r--drivers/ata/pata_atiixp.c2
-rw-r--r--drivers/ata/pata_ep93xx.c8
-rw-r--r--drivers/ata/sata_inic162x.c2
-rw-r--r--drivers/ata/sata_rcar.c6
-rw-r--r--drivers/atm/eni.c3
-rw-r--r--drivers/atm/fore200e.c401
-rw-r--r--drivers/atm/fore200e.h8
-rw-r--r--drivers/atm/nicstar.c3
-rw-r--r--drivers/atm/zatm.c42
-rw-r--r--drivers/auxdisplay/hd44780.c61
-rw-r--r--drivers/auxdisplay/panel.c7
-rw-r--r--drivers/base/arch_topology.c26
-rw-r--r--drivers/base/cacheinfo.c2
-rw-r--r--drivers/base/component.c6
-rw-r--r--drivers/base/dd.c12
-rw-r--r--drivers/base/devres.c36
-rw-r--r--drivers/base/devtmpfs.c2
-rw-r--r--drivers/base/firmware_loader/main.c7
-rw-r--r--drivers/base/memory.c22
-rw-r--r--drivers/base/node.c19
-rw-r--r--drivers/base/platform-msi.c14
-rw-r--r--drivers/base/platform.c13
-rw-r--r--drivers/base/power/domain.c20
-rw-r--r--drivers/base/power/main.c5
-rw-r--r--drivers/base/regmap/internal.h5
-rw-r--r--drivers/base/regmap/regmap.c99
-rw-r--r--drivers/block/DAC960.c7229
-rw-r--r--drivers/block/DAC960.h4414
-rw-r--r--drivers/block/Kconfig13
-rw-r--r--drivers/block/Makefile1
-rw-r--r--drivers/block/amiflop.c318
-rw-r--r--drivers/block/aoe/aoe.h5
-rw-r--r--drivers/block/aoe/aoeblk.c70
-rw-r--r--drivers/block/aoe/aoecmd.c19
-rw-r--r--drivers/block/aoe/aoedev.c15
-rw-r--r--drivers/block/ataflop.c273
-rw-r--r--drivers/block/brd.c16
-rw-r--r--drivers/block/cryptoloop.c22
-rw-r--r--drivers/block/drbd/Kconfig1
-rw-r--r--drivers/block/drbd/drbd_int.h15
-rw-r--r--drivers/block/drbd/drbd_main.c18
-rw-r--r--drivers/block/drbd/drbd_nl.c39
-rw-r--r--drivers/block/drbd/drbd_protocol.h4
-rw-r--r--drivers/block/drbd/drbd_receiver.c37
-rw-r--r--drivers/block/drbd/drbd_req.c2
-rw-r--r--drivers/block/drbd/drbd_worker.c65
-rw-r--r--drivers/block/floppy.c71
-rw-r--r--drivers/block/loop.c9
-rw-r--r--drivers/block/mtip32xx/mtip32xx.c53
-rw-r--r--drivers/block/nbd.c12
-rw-r--r--drivers/block/null_blk.h11
-rw-r--r--drivers/block/null_blk_main.c141
-rw-r--r--drivers/block/null_blk_zoned.c57
-rw-r--r--drivers/block/paride/pcd.c88
-rw-r--r--drivers/block/paride/pd.c94
-rw-r--r--drivers/block/paride/pf.c56
-rw-r--r--drivers/block/pktcdvd.c2
-rw-r--r--drivers/block/ps3disk.c88
-rw-r--r--drivers/block/ps3vram.c2
-rw-r--r--drivers/block/rbd.c28
-rw-r--r--drivers/block/rsxx/core.c4
-rw-r--r--drivers/block/rsxx/cregs.c2
-rw-r--r--drivers/block/rsxx/dev.c2
-rw-r--r--drivers/block/rsxx/dma.c52
-rw-r--r--drivers/block/skd_main.c69
-rw-r--r--drivers/block/sunvdc.c16
-rw-r--r--drivers/block/swim.c106
-rw-r--r--drivers/block/swim3.c211
-rw-r--r--drivers/block/sx8.c166
-rw-r--r--drivers/block/umem.c42
-rw-r--r--drivers/block/virtio_blk.c68
-rw-r--r--drivers/block/xen-blkfront.c6
-rw-r--r--drivers/block/xsysace.c80
-rw-r--r--drivers/block/z2ram.c90
-rw-r--r--drivers/block/zram/Kconfig2
-rw-r--r--drivers/block/zram/zram_drv.c28
-rw-r--r--drivers/bluetooth/ath3k.c11
-rw-r--r--drivers/bluetooth/bt3c_cs.c9
-rw-r--r--drivers/bluetooth/btbcm.c1
-rw-r--r--drivers/bluetooth/btrsi.c13
-rw-r--r--drivers/bluetooth/btrtl.c10
-rw-r--r--drivers/bluetooth/btsdio.c14
-rw-r--r--drivers/bluetooth/btusb.c2
-rw-r--r--drivers/bluetooth/hci_ldisc.c1
-rw-r--r--drivers/bluetooth/hci_qca.c71
-rw-r--r--drivers/bluetooth/hci_serdev.c10
-rw-r--r--drivers/bus/fsl-mc/fsl-mc-bus.c27
-rw-r--r--drivers/bus/imx-weim.c3
-rw-r--r--drivers/bus/mvebu-mbus.c2
-rw-r--r--drivers/bus/ti-sysc.c171
-rw-r--r--drivers/bus/ts-nbus.c20
-rw-r--r--drivers/cdrom/cdrom.c29
-rw-r--r--drivers/cdrom/gdrom.c180
-rw-r--r--drivers/char/Kconfig2
-rw-r--r--drivers/char/hw_random/core.c4
-rw-r--r--drivers/char/ipmi/ipmi_bt_sm.c66
-rw-r--r--drivers/char/ipmi/ipmi_devintf.c11
-rw-r--r--drivers/char/ipmi/ipmi_dmi.c31
-rw-r--r--drivers/char/ipmi/ipmi_kcs_sm.c4
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c53
-rw-r--r--drivers/char/ipmi/ipmi_powernv.c4
-rw-r--r--drivers/char/ipmi/ipmi_poweroff.c67
-rw-r--r--drivers/char/ipmi/ipmi_si_hardcode.c9
-rw-r--r--drivers/char/ipmi/ipmi_si_hotmod.c17
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c28
-rw-r--r--drivers/char/ipmi/ipmi_si_mem_io.c2
-rw-r--r--drivers/char/ipmi/ipmi_si_pci.c21
-rw-r--r--drivers/char/ipmi/ipmi_si_platform.c26
-rw-r--r--drivers/char/ipmi/ipmi_smic_sm.c26
-rw-r--r--drivers/char/ipmi/ipmi_ssif.c307
-rw-r--r--drivers/char/ipmi/ipmi_watchdog.c52
-rw-r--r--drivers/char/pcmcia/cm4000_cs.c4
-rw-r--r--drivers/char/pcmcia/cm4040_cs.c2
-rw-r--r--drivers/char/pcmcia/synclink_cs.c3
-rw-r--r--drivers/char/random.c24
-rw-r--r--drivers/char/tpm/Kconfig2
-rw-r--r--drivers/char/tpm/tpm-dev-common.c147
-rw-r--r--drivers/char/tpm/tpm-dev.c11
-rw-r--r--drivers/char/tpm/tpm-dev.h18
-rw-r--r--drivers/char/tpm/tpm-interface.c30
-rw-r--r--drivers/char/tpm/tpm.h2
-rw-r--r--drivers/char/tpm/tpm2-cmd.c4
-rw-r--r--drivers/char/tpm/tpmrm-dev.c15
-rw-r--r--drivers/char/tpm/xen-tpmfront.c2
-rw-r--r--drivers/clk/Kconfig2
-rw-r--r--drivers/clk/Makefile4
-rw-r--r--drivers/clk/actions/Kconfig1
-rw-r--r--drivers/clk/actions/Makefile1
-rw-r--r--drivers/clk/actions/owl-common.c3
-rw-r--r--drivers/clk/actions/owl-common.h5
-rw-r--r--drivers/clk/actions/owl-reset.c66
-rw-r--r--drivers/clk/actions/owl-reset.h31
-rw-r--r--drivers/clk/actions/owl-s700.c55
-rw-r--r--drivers/clk/actions/owl-s900.c86
-rw-r--r--drivers/clk/at91/Makefile5
-rw-r--r--drivers/clk/at91/at91sam9260.c494
-rw-r--r--drivers/clk/at91/at91sam9rl.c171
-rw-r--r--drivers/clk/at91/at91sam9x5.c309
-rw-r--r--drivers/clk/at91/clk-audio-pll.c109
-rw-r--r--drivers/clk/at91/clk-generated.c81
-rw-r--r--drivers/clk/at91/clk-h32mx.c22
-rw-r--r--drivers/clk/at91/clk-i2s-mux.c40
-rw-r--r--drivers/clk/at91/clk-main.c112
-rw-r--r--drivers/clk/at91/clk-master.c99
-rw-r--r--drivers/clk/at91/clk-peripheral.c81
-rw-r--r--drivers/clk/at91/clk-pll.c190
-rw-r--r--drivers/clk/at91/clk-plldiv.c27
-rw-r--r--drivers/clk/at91/clk-programmable.c81
-rw-r--r--drivers/clk/at91/clk-slow.c32
-rw-r--r--drivers/clk/at91/clk-smd.c34
-rw-r--r--drivers/clk/at91/clk-system.c39
-rw-r--r--drivers/clk/at91/clk-usb.c94
-rw-r--r--drivers/clk/at91/clk-utmi.c45
-rw-r--r--drivers/clk/at91/dt-compat.c961
-rw-r--r--drivers/clk/at91/pmc.c78
-rw-r--r--drivers/clk/at91/pmc.h159
-rw-r--r--drivers/clk/at91/sama5d2.c336
-rw-r--r--drivers/clk/at91/sama5d4.c264
-rw-r--r--drivers/clk/axs10x/pll_clock.c4
-rw-r--r--drivers/clk/bcm/clk-kona-setup.c22
-rw-r--r--drivers/clk/clk-asm9260.c4
-rw-r--r--drivers/clk/clk-bulk.c80
-rw-r--r--drivers/clk/clk-cdce925.c11
-rw-r--r--drivers/clk/clk-devres.c24
-rw-r--r--drivers/clk/clk-fixed-factor.c9
-rw-r--r--drivers/clk/clk-fixed-rate.c1
-rw-r--r--drivers/clk/clk-gpio.c8
-rw-r--r--drivers/clk/clk-hsdk-pll.c4
-rw-r--r--drivers/clk/clk-max77686.c27
-rw-r--r--drivers/clk/clk-nomadik.c4
-rw-r--r--drivers/clk/clk-npcm7xx.c2
-rw-r--r--drivers/clk/clk-palmas.c4
-rw-r--r--drivers/clk/clk-qoriq.c14
-rw-r--r--drivers/clk/clk-s2mps11.c58
-rw-r--r--drivers/clk/clk-scmi.c2
-rw-r--r--drivers/clk/clk-scpi.c6
-rw-r--r--drivers/clk/clk-si5351.c4
-rw-r--r--drivers/clk/clk-stm32f4.c2
-rw-r--r--drivers/clk/clk-stm32h7.c2
-rw-r--r--drivers/clk/clk-stm32mp1.c2
-rw-r--r--drivers/clk/clk-tango4.c10
-rw-r--r--drivers/clk/clk.c95
-rw-r--r--drivers/clk/davinci/psc.c18
-rw-r--r--drivers/clk/hisilicon/Kconfig7
-rw-r--r--drivers/clk/hisilicon/Makefile1
-rw-r--r--drivers/clk/hisilicon/clk-hi3670.c1016
-rw-r--r--drivers/clk/hisilicon/reset.c5
-rw-r--r--drivers/clk/imx/clk-cpu.c2
-rw-r--r--drivers/clk/imx/clk-imx6q.c1
-rw-r--r--drivers/clk/imx/clk-imx6sl.c2
-rw-r--r--drivers/clk/imx/clk-imx6sll.c1
-rw-r--r--drivers/clk/imx/clk-imx6sx.c1
-rw-r--r--drivers/clk/imx/clk-imx6ul.c1
-rw-r--r--drivers/clk/imx/clk-imx7d.c28
-rw-r--r--drivers/clk/imx/clk.h7
-rw-r--r--drivers/clk/ingenic/Kconfig47
-rw-r--r--drivers/clk/ingenic/Makefile9
-rw-r--r--drivers/clk/ingenic/jz4725b-cgu.c225
-rw-r--r--drivers/clk/keystone/Kconfig2
-rw-r--r--drivers/clk/keystone/gate.c7
-rw-r--r--drivers/clk/keystone/pll.c7
-rw-r--r--drivers/clk/mediatek/clk-mt2701.c5
-rw-r--r--drivers/clk/meson/axg-audio.c34
-rw-r--r--drivers/clk/meson/axg.c345
-rw-r--r--drivers/clk/meson/axg.h8
-rw-r--r--drivers/clk/meson/clk-pll.c156
-rw-r--r--drivers/clk/meson/clkc.h16
-rw-r--r--drivers/clk/meson/gxbb.c530
-rw-r--r--drivers/clk/meson/gxbb.h10
-rw-r--r--drivers/clk/meson/meson8b.c280
-rw-r--r--drivers/clk/meson/meson8b.h5
-rw-r--r--drivers/clk/mmp/clk-of-mmp2.c4
-rw-r--r--drivers/clk/mvebu/ap806-system-controller.c5
-rw-r--r--drivers/clk/mvebu/armada-370.c4
-rw-r--r--drivers/clk/mvebu/armada-375.c4
-rw-r--r--drivers/clk/mvebu/armada-37xx-periph.c58
-rw-r--r--drivers/clk/mvebu/armada-37xx-tbg.c8
-rw-r--r--drivers/clk/mvebu/armada-37xx-xtal.c4
-rw-r--r--drivers/clk/mvebu/armada-38x.c4
-rw-r--r--drivers/clk/mvebu/armada-39x.c4
-rw-r--r--drivers/clk/mvebu/armada-xp.c4
-rw-r--r--drivers/clk/mvebu/clk-corediv.c4
-rw-r--r--drivers/clk/mvebu/clk-cpu.c8
-rw-r--r--drivers/clk/mvebu/common.c4
-rw-r--r--drivers/clk/mvebu/common.h4
-rw-r--r--drivers/clk/mvebu/cp110-system-controller.c4
-rw-r--r--drivers/clk/mvebu/dove.c4
-rw-r--r--drivers/clk/mvebu/kirkwood.c4
-rw-r--r--drivers/clk/mvebu/mv98dx3236.c4
-rw-r--r--drivers/clk/mvebu/orion.c4
-rw-r--r--drivers/clk/qcom/Kconfig53
-rw-r--r--drivers/clk/qcom/Makefile8
-rw-r--r--drivers/clk/qcom/camcc-sdm845.c1745
-rw-r--r--drivers/clk/qcom/clk-alpha-pll.c1
-rw-r--r--drivers/clk/qcom/clk-branch.c2
-rw-r--r--drivers/clk/qcom/clk-hfpll.c244
-rw-r--r--drivers/clk/qcom/clk-hfpll.h44
-rw-r--r--drivers/clk/qcom/clk-krait.c126
-rw-r--r--drivers/clk/qcom/clk-krait.h40
-rw-r--r--drivers/clk/qcom/clk-rcg.h11
-rw-r--r--drivers/clk/qcom/clk-rcg2.c195
-rw-r--r--drivers/clk/qcom/gcc-ipq806x.c82
-rw-r--r--drivers/clk/qcom/gcc-msm8960.c172
-rw-r--r--drivers/clk/qcom/gcc-msm8996.c152
-rw-r--r--drivers/clk/qcom/gcc-qcs404.c2744
-rw-r--r--drivers/clk/qcom/gcc-sdm660.c2480
-rw-r--r--drivers/clk/qcom/gcc-sdm845.c321
-rw-r--r--drivers/clk/qcom/hfpll.c96
-rw-r--r--drivers/clk/qcom/kpss-xcc.c87
-rw-r--r--drivers/clk/qcom/krait-cc.c397
-rw-r--r--drivers/clk/renesas/Kconfig19
-rw-r--r--drivers/clk/renesas/Makefile3
-rw-r--r--drivers/clk/renesas/clk-div6.c17
-rw-r--r--drivers/clk/renesas/clk-emev2.c22
-rw-r--r--drivers/clk/renesas/clk-mstp.c13
-rw-r--r--drivers/clk/renesas/clk-r8a73a4.c9
-rw-r--r--drivers/clk/renesas/clk-r8a7740.c9
-rw-r--r--drivers/clk/renesas/clk-r8a7778.c9
-rw-r--r--drivers/clk/renesas/clk-r8a7779.c9
-rw-r--r--drivers/clk/renesas/clk-rcar-gen2.c9
-rw-r--r--drivers/clk/renesas/clk-rz.c9
-rw-r--r--drivers/clk/renesas/clk-sh73a0.c9
-rw-r--r--drivers/clk/renesas/r7s9210-cpg-mssr.c217
-rw-r--r--drivers/clk/renesas/r8a7743-cpg-mssr.c18
-rw-r--r--drivers/clk/renesas/r8a7745-cpg-mssr.c5
-rw-r--r--drivers/clk/renesas/r8a774a1-cpg-mssr.c323
-rw-r--r--drivers/clk/renesas/r8a774c0-cpg-mssr.c286
-rw-r--r--drivers/clk/renesas/r8a7790-cpg-mssr.c5
-rw-r--r--drivers/clk/renesas/r8a7791-cpg-mssr.c5
-rw-r--r--drivers/clk/renesas/r8a7792-cpg-mssr.c5
-rw-r--r--drivers/clk/renesas/r8a7794-cpg-mssr.c5
-rw-r--r--drivers/clk/renesas/r8a7795-cpg-mssr.c72
-rw-r--r--drivers/clk/renesas/r8a7796-cpg-mssr.c72
-rw-r--r--drivers/clk/renesas/r8a77965-cpg-mssr.c69
-rw-r--r--drivers/clk/renesas/r8a77970-cpg-mssr.c81
-rw-r--r--drivers/clk/renesas/r8a77980-cpg-mssr.c32
-rw-r--r--drivers/clk/renesas/r8a77990-cpg-mssr.c17
-rw-r--r--drivers/clk/renesas/r8a77995-cpg-mssr.c17
-rw-r--r--drivers/clk/renesas/r9a06g032-clocks.c3
-rw-r--r--drivers/clk/renesas/rcar-gen2-cpg.c5
-rw-r--r--drivers/clk/renesas/rcar-gen2-cpg.h7
-rw-r--r--drivers/clk/renesas/rcar-gen3-cpg.c45
-rw-r--r--drivers/clk/renesas/rcar-gen3-cpg.h33
-rw-r--r--drivers/clk/renesas/rcar-usb2-clock-sel.c5
-rw-r--r--drivers/clk/renesas/renesas-cpg-mssr.c205
-rw-r--r--drivers/clk/renesas/renesas-cpg-mssr.h38
-rw-r--r--drivers/clk/rockchip/clk-ddr.c4
-rw-r--r--drivers/clk/rockchip/clk-rk3188.c2
-rw-r--r--drivers/clk/rockchip/clk-rk3288.c29
-rw-r--r--drivers/clk/rockchip/clk-rk3328.c8
-rw-r--r--drivers/clk/samsung/clk-cpu.c6
-rw-r--r--drivers/clk/samsung/clk-cpu.h2
-rw-r--r--drivers/clk/samsung/clk-exynos-audss.c1
-rw-r--r--drivers/clk/samsung/clk-exynos3250.c1
-rw-r--r--drivers/clk/samsung/clk-exynos4.c226
-rw-r--r--drivers/clk/samsung/clk-exynos5250.c42
-rw-r--r--drivers/clk/samsung/clk-exynos5420.c76
-rw-r--r--drivers/clk/samsung/clk-exynos5433.c33
-rw-r--r--drivers/clk/samsung/clk-s3c2410.c43
-rw-r--r--drivers/clk/samsung/clk-s3c2412.c43
-rw-r--r--drivers/clk/samsung/clk-s3c2443.c43
-rw-r--r--drivers/clk/samsung/clk-s3c64xx.c66
-rw-r--r--drivers/clk/samsung/clk-s5pv210.c41
-rw-r--r--drivers/clk/samsung/clk.c23
-rw-r--r--drivers/clk/samsung/clk.h18
-rw-r--r--drivers/clk/st/clkgen-fsyn.c2
-rw-r--r--drivers/clk/sunxi-ng/ccu-sun4i-a10.c10
-rw-r--r--drivers/clk/sunxi-ng/ccu-sun50i-a64.c48
-rw-r--r--drivers/clk/sunxi-ng/ccu-sun50i-a64.h4
-rw-r--r--drivers/clk/sunxi-ng/ccu-sun50i-h6.c53
-rw-r--r--drivers/clk/sunxi-ng/ccu-sun8i-a83t.c2
-rw-r--r--drivers/clk/sunxi-ng/ccu-sun8i-h3.c25
-rw-r--r--drivers/clk/sunxi-ng/ccu-sun8i-r40.c52
-rw-r--r--drivers/clk/sunxi-ng/ccu_nkmp.c7
-rw-r--r--drivers/clk/sunxi-ng/ccu_nkmp.h1
-rw-r--r--drivers/clk/sunxi-ng/ccu_nm.c7
-rw-r--r--drivers/clk/sunxi-ng/ccu_nm.h30
-rw-r--r--drivers/clk/sunxi/clk-mod0.c6
-rw-r--r--drivers/clk/sunxi/clk-sun9i-core.c20
-rw-r--r--drivers/clk/sunxi/clk-sunxi.c4
-rw-r--r--drivers/clk/tegra/clk-dfll.c8
-rw-r--r--drivers/clk/tegra/clk-tegra210.c7
-rw-r--r--drivers/clk/ti/Makefile9
-rw-r--r--drivers/clk/ti/apll.c18
-rw-r--r--drivers/clk/ti/clk-33xx-compat.c218
-rw-r--r--drivers/clk/ti/clk-33xx.c232
-rw-r--r--drivers/clk/ti/clk-43xx-compat.c225
-rw-r--r--drivers/clk/ti/clk-43xx.c249
-rw-r--r--drivers/clk/ti/clk-7xx-compat.c823
-rw-r--r--drivers/clk/ti/clk-7xx.c590
-rw-r--r--drivers/clk/ti/clk-dra7-atl.c4
-rw-r--r--drivers/clk/ti/clk.c32
-rw-r--r--drivers/clk/ti/clkctrl.c101
-rw-r--r--drivers/clk/ti/clock.h11
-rw-r--r--drivers/clk/ti/composite.c14
-rw-r--r--drivers/clk/ti/divider.c40
-rw-r--r--drivers/clk/ti/dpll.c18
-rw-r--r--drivers/clk/ti/dpll3xxx.c124
-rw-r--r--drivers/clk/ti/fapll.c8
-rw-r--r--drivers/clk/ti/fixed-factor.c4
-rw-r--r--drivers/clk/ti/gate.c5
-rw-r--r--drivers/clk/ti/interface.c2
-rw-r--r--drivers/clk/ti/mux.c33
-rw-r--r--drivers/clk/zynq/clkc.c4
-rw-r--r--drivers/clk/zynqmp/Kconfig10
-rw-r--r--drivers/clk/zynqmp/Makefile4
-rw-r--r--drivers/clk/zynqmp/clk-gate-zynqmp.c144
-rw-r--r--drivers/clk/zynqmp/clk-mux-zynqmp.c141
-rw-r--r--drivers/clk/zynqmp/clk-zynqmp.h68
-rw-r--r--drivers/clk/zynqmp/clkc.c716
-rw-r--r--drivers/clk/zynqmp/divider.c217
-rw-r--r--drivers/clk/zynqmp/pll.c335
-rw-r--r--drivers/clocksource/Kconfig18
-rw-r--r--drivers/clocksource/Makefile28
-rw-r--r--drivers/clocksource/arm_arch_timer.c15
-rw-r--r--drivers/clocksource/asm9260_timer.c2
-rw-r--r--drivers/clocksource/dw_apb_timer_of.c20
-rw-r--r--drivers/clocksource/i8253.c14
-rw-r--r--drivers/clocksource/pxa_timer.c6
-rw-r--r--drivers/clocksource/renesas-ostm.c11
-rw-r--r--drivers/clocksource/riscv_timer.c12
-rw-r--r--drivers/clocksource/sh_cmt.c106
-rw-r--r--drivers/clocksource/sh_mtu2.c10
-rw-r--r--drivers/clocksource/sh_tmu.c10
-rw-r--r--drivers/clocksource/timer-armada-370-xp.c (renamed from drivers/clocksource/time-armada-370-xp.c)0
-rw-r--r--drivers/clocksource/timer-cadence-ttc.c (renamed from drivers/clocksource/cadence_ttc_timer.c)2
-rw-r--r--drivers/clocksource/timer-efm32.c (renamed from drivers/clocksource/time-efm32.c)0
-rw-r--r--drivers/clocksource/timer-fsl-ftm.c (renamed from drivers/clocksource/fsl_ftm_timer.c)0
-rw-r--r--drivers/clocksource/timer-gx6605s.c154
-rw-r--r--drivers/clocksource/timer-integrator-ap.c2
-rw-r--r--drivers/clocksource/timer-lpc32xx.c (renamed from drivers/clocksource/time-lpc32xx.c)0
-rw-r--r--drivers/clocksource/timer-mp-csky.c173
-rw-r--r--drivers/clocksource/timer-orion.c (renamed from drivers/clocksource/time-orion.c)8
-rw-r--r--drivers/clocksource/timer-owl.c (renamed from drivers/clocksource/owl-timer.c)0
-rw-r--r--drivers/clocksource/timer-pistachio.c (renamed from drivers/clocksource/time-pistachio.c)0
-rw-r--r--drivers/clocksource/timer-qcom.c (renamed from drivers/clocksource/qcom-timer.c)0
-rw-r--r--drivers/clocksource/timer-sp804.c2
-rw-r--r--drivers/clocksource/timer-versatile.c (renamed from drivers/clocksource/versatile.c)0
-rw-r--r--drivers/clocksource/timer-vf-pit.c (renamed from drivers/clocksource/vf_pit_timer.c)0
-rw-r--r--drivers/clocksource/timer-vt8500.c (renamed from drivers/clocksource/vt8500_timer.c)0
-rw-r--r--drivers/clocksource/timer-zevio.c (renamed from drivers/clocksource/zevio-timer.c)8
-rw-r--r--drivers/cpufreq/Kconfig.arm9
-rw-r--r--drivers/cpufreq/Makefile3
-rw-r--r--drivers/cpufreq/acpi-cpufreq.c5
-rw-r--r--drivers/cpufreq/amd_freq_sensitivity.c9
-rw-r--r--drivers/cpufreq/arm_big_little_dt.c100
-rw-r--r--drivers/cpufreq/cppc_cpufreq.c2
-rw-r--r--drivers/cpufreq/cpufreq-dt-platdev.c6
-rw-r--r--drivers/cpufreq/cpufreq-dt.c34
-rw-r--r--drivers/cpufreq/cpufreq.c2
-rw-r--r--drivers/cpufreq/cpufreq_conservative.c6
-rw-r--r--drivers/cpufreq/imx6q-cpufreq.c59
-rw-r--r--drivers/cpufreq/intel_pstate.c52
-rw-r--r--drivers/cpufreq/mvebu-cpufreq.c9
-rw-r--r--drivers/cpufreq/s5pv210-cpufreq.c4
-rw-r--r--drivers/cpufreq/tegra186-cpufreq.c2
-rw-r--r--drivers/cpuidle/cpuidle-arm.c40
-rw-r--r--drivers/cpuidle/cpuidle.c16
-rw-r--r--drivers/cpuidle/governors/ladder.c2
-rw-r--r--drivers/cpuidle/governors/menu.c141
-rw-r--r--drivers/cpuidle/poll_state.c8
-rw-r--r--drivers/crypto/Kconfig11
-rw-r--r--drivers/crypto/Makefile2
-rw-r--r--drivers/crypto/atmel-aes.c5
-rw-r--r--drivers/crypto/atmel-authenc.h13
-rw-r--r--drivers/crypto/atmel-ecc.c11
-rw-r--r--drivers/crypto/atmel-ecc.h14
-rw-r--r--drivers/crypto/atmel-sha.c5
-rw-r--r--drivers/crypto/atmel-tdes.c5
-rw-r--r--drivers/crypto/axis/artpec6_crypto.c20
-rw-r--r--drivers/crypto/caam/Kconfig57
-rw-r--r--drivers/crypto/caam/Makefile10
-rw-r--r--drivers/crypto/caam/caamalg.c732
-rw-r--r--drivers/crypto/caam/caamalg_desc.c143
-rw-r--r--drivers/crypto/caam/caamalg_desc.h28
-rw-r--r--drivers/crypto/caam/caamalg_qi.c627
-rw-r--r--drivers/crypto/caam/caamalg_qi2.c5165
-rw-r--r--drivers/crypto/caam/caamalg_qi2.h223
-rw-r--r--drivers/crypto/caam/caamhash.c80
-rw-r--r--drivers/crypto/caam/caamhash_desc.c80
-rw-r--r--drivers/crypto/caam/caamhash_desc.h21
-rw-r--r--drivers/crypto/caam/caampkc.c1
-rw-r--r--drivers/crypto/caam/caamrng.c1
-rw-r--r--drivers/crypto/caam/compat.h2
-rw-r--r--drivers/crypto/caam/ctrl.c1
-rw-r--r--drivers/crypto/caam/dpseci.c426
-rw-r--r--drivers/crypto/caam/dpseci.h333
-rw-r--r--drivers/crypto/caam/dpseci_cmd.h149
-rw-r--r--drivers/crypto/caam/error.c79
-rw-r--r--drivers/crypto/caam/error.h6
-rw-r--r--drivers/crypto/caam/jr.c1
-rw-r--r--drivers/crypto/caam/qi.c43
-rw-r--r--drivers/crypto/caam/qi.h3
-rw-r--r--drivers/crypto/caam/regs.h30
-rw-r--r--drivers/crypto/caam/sg_sw_qm.h29
-rw-r--r--drivers/crypto/caam/sg_sw_qm2.h30
-rw-r--r--drivers/crypto/cavium/cpt/cptvf_reqmanager.c20
-rw-r--r--drivers/crypto/cavium/nitrox/Makefile3
-rw-r--r--drivers/crypto/cavium/nitrox/nitrox_common.h19
-rw-r--r--drivers/crypto/cavium/nitrox/nitrox_csr.h111
-rw-r--r--drivers/crypto/cavium/nitrox/nitrox_debugfs.c115
-rw-r--r--drivers/crypto/cavium/nitrox/nitrox_dev.h162
-rw-r--r--drivers/crypto/cavium/nitrox/nitrox_hal.c71
-rw-r--r--drivers/crypto/cavium/nitrox/nitrox_hal.h23
-rw-r--r--drivers/crypto/cavium/nitrox/nitrox_isr.c337
-rw-r--r--drivers/crypto/cavium/nitrox/nitrox_isr.h10
-rw-r--r--drivers/crypto/cavium/nitrox/nitrox_lib.c98
-rw-r--r--drivers/crypto/cavium/nitrox/nitrox_main.c203
-rw-r--r--drivers/crypto/cavium/nitrox/nitrox_reqmgr.c49
-rw-r--r--drivers/crypto/cavium/nitrox/nitrox_sriov.c151
-rw-r--r--drivers/crypto/ccp/ccp-crypto-aes-xts.c13
-rw-r--r--drivers/crypto/ccp/ccp-crypto.h2
-rw-r--r--drivers/crypto/ccp/psp-dev.c47
-rw-r--r--drivers/crypto/ccp/sp-platform.c53
-rw-r--r--drivers/crypto/ccree/cc_hw_queue_defs.h6
-rw-r--r--drivers/crypto/chelsio/chcr_algo.c62
-rw-r--r--drivers/crypto/chelsio/chcr_core.c6
-rw-r--r--drivers/crypto/chelsio/chcr_crypto.h4
-rw-r--r--drivers/crypto/chelsio/chtls/chtls_cm.c7
-rw-r--r--drivers/crypto/chelsio/chtls/chtls_main.c3
-rw-r--r--drivers/crypto/hisilicon/sec/sec_algs.c31
-rw-r--r--drivers/crypto/inside-secure/safexcel.c8
-rw-r--r--drivers/crypto/mxs-dcp.c195
-rw-r--r--drivers/crypto/omap-aes.c17
-rw-r--r--drivers/crypto/omap-aes.h2
-rw-r--r--drivers/crypto/picoxcell_crypto.c21
-rw-r--r--drivers/crypto/qat/qat_c3xxx/adf_drv.c6
-rw-r--r--drivers/crypto/qat/qat_c3xxxvf/adf_drv.c6
-rw-r--r--drivers/crypto/qat/qat_c62x/adf_drv.c6
-rw-r--r--drivers/crypto/qat/qat_c62xvf/adf_drv.c6
-rw-r--r--drivers/crypto/qat/qat_common/adf_aer.c1
-rw-r--r--drivers/crypto/qat/qat_common/qat_algs.c60
-rw-r--r--drivers/crypto/qat/qat_dh895xcc/adf_drv.c6
-rw-r--r--drivers/crypto/qat/qat_dh895xccvf/adf_drv.c6
-rw-r--r--drivers/crypto/qce/ablkcipher.c13
-rw-r--r--drivers/crypto/qce/cipher.h2
-rw-r--r--drivers/crypto/s5p-sss.c113
-rw-r--r--drivers/crypto/sahara.c31
-rw-r--r--drivers/crypto/vmx/aes_cbc.c22
-rw-r--r--drivers/crypto/vmx/aes_ctr.c18
-rw-r--r--drivers/crypto/vmx/aes_xts.c18
-rw-r--r--drivers/devfreq/devfreq.c118
-rw-r--r--drivers/devfreq/event/exynos-ppmu.c4
-rw-r--r--drivers/devfreq/governor.h6
-rw-r--r--drivers/devfreq/governor_performance.c5
-rw-r--r--drivers/devfreq/governor_powersave.c2
-rw-r--r--drivers/devfreq/governor_simpleondemand.c12
-rw-r--r--drivers/devfreq/governor_userspace.c16
-rw-r--r--drivers/dma-buf/reservation.c189
-rw-r--r--drivers/dma/Kconfig13
-rw-r--r--drivers/dma/Makefile3
-rw-r--r--drivers/dma/at_hdmac.c2
-rw-r--r--drivers/dma/at_xdmac.c4
-rw-r--r--drivers/dma/bcm2835-dma.c8
-rw-r--r--drivers/dma/coh901318.c28
-rw-r--r--drivers/dma/dma-jz4740.c21
-rw-r--r--drivers/dma/dma-jz4780.c289
-rw-r--r--drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c4
-rw-r--r--drivers/dma/dw/core.c5
-rw-r--r--drivers/dma/dw/platform.c2
-rw-r--r--drivers/dma/ep93xx_dma.c21
-rw-r--r--drivers/dma/fsl-edma-common.c626
-rw-r--r--drivers/dma/fsl-edma-common.h233
-rw-r--r--drivers/dma/fsl-edma.c729
-rw-r--r--drivers/dma/fsldma.c4
-rw-r--r--drivers/dma/hsu/hsu.c4
-rw-r--r--drivers/dma/idma64.c9
-rw-r--r--drivers/dma/imx-dma.c20
-rw-r--r--drivers/dma/ioat/init.c23
-rw-r--r--drivers/dma/k3dma.c36
-rw-r--r--drivers/dma/mcf-edma.c317
-rw-r--r--drivers/dma/mmp_tdma.c29
-rw-r--r--drivers/dma/mv_xor.c4
-rw-r--r--drivers/dma/mxs-dma.c3
-rw-r--r--drivers/dma/nbpfaxi.c9
-rw-r--r--drivers/dma/owl-dma.c283
-rw-r--r--drivers/dma/ppc4xx/adma.c2
-rw-r--r--drivers/dma/pxa_dma.c5
-rw-r--r--drivers/dma/sh/rcar-dmac.c3
-rw-r--r--drivers/dma/sh/shdma-arm.h5
-rw-r--r--drivers/dma/sh/shdma-base.c5
-rw-r--r--drivers/dma/sh/shdma-of.c5
-rw-r--r--drivers/dma/sh/shdma-r8a73a4.c5
-rw-r--r--drivers/dma/sh/shdma.h6
-rw-r--r--drivers/dma/sh/shdmac.c6
-rw-r--r--drivers/dma/sh/sudmac.c5
-rw-r--r--drivers/dma/sh/usb-dmac.c5
-rw-r--r--drivers/dma/sprd-dma.c81
-rw-r--r--drivers/dma/st_fdma.c7
-rw-r--r--drivers/dma/ste_dma40.c14
-rw-r--r--drivers/dma/stm32-dma.c20
-rw-r--r--drivers/dma/stm32-mdma.c4
-rw-r--r--drivers/dma/timb_dma.c2
-rw-r--r--drivers/edac/Kconfig15
-rw-r--r--drivers/edac/Makefile1
-rw-r--r--drivers/edac/altera_edac.c670
-rw-r--r--drivers/edac/altera_edac.h73
-rw-r--r--drivers/edac/amd64_edac.c24
-rw-r--r--drivers/edac/amd64_edac.h3
-rw-r--r--drivers/edac/cpc925_edac.c20
-rw-r--r--drivers/edac/ghes_edac.c23
-rw-r--r--drivers/edac/i3200_edac.c2
-rw-r--r--drivers/edac/i7core_edac.c5
-rw-r--r--drivers/edac/mce_amd.c4
-rw-r--r--drivers/edac/pnd2_edac.c2
-rw-r--r--drivers/edac/qcom_edac.c414
-rw-r--r--drivers/edac/sb_edac.c204
-rw-r--r--drivers/edac/skx_edac.c200
-rw-r--r--drivers/edac/thunderx_edac.c4
-rw-r--r--drivers/extcon/extcon-intel-cht-wc.c60
-rw-r--r--drivers/extcon/extcon-intel-int3496.c12
-rw-r--r--drivers/extcon/extcon-max14577.c24
-rw-r--r--drivers/extcon/extcon-max77693.c22
-rw-r--r--drivers/extcon/extcon-max77843.c19
-rw-r--r--drivers/extcon/extcon-max8997.c22
-rw-r--r--drivers/extcon/extcon.c15
-rw-r--r--drivers/firewire/core-iso.c7
-rw-r--r--drivers/firewire/core-transaction.c10
-rw-r--r--drivers/firmware/Kconfig30
-rw-r--r--drivers/firmware/Makefile4
-rw-r--r--drivers/firmware/arm_scmi/base.c2
-rw-r--r--drivers/firmware/arm_scmi/clock.c2
-rw-r--r--drivers/firmware/arm_scmi/perf.c30
-rw-r--r--drivers/firmware/arm_scmi/power.c2
-rw-r--r--drivers/firmware/arm_scmi/sensors.c2
-rw-r--r--drivers/firmware/dmi_scan.c2
-rw-r--r--drivers/firmware/efi/apple-properties.c4
-rw-r--r--drivers/firmware/efi/arm-init.c4
-rw-r--r--drivers/firmware/efi/arm-runtime.c2
-rw-r--r--drivers/firmware/efi/efi.c70
-rw-r--r--drivers/firmware/efi/efivars.c16
-rw-r--r--drivers/firmware/efi/libstub/Makefile3
-rw-r--r--drivers/firmware/efi/libstub/arm-stub.c30
-rw-r--r--drivers/firmware/efi/libstub/fdt.c4
-rw-r--r--drivers/firmware/efi/memmap.c5
-rw-r--r--drivers/firmware/efi/runtime-wrappers.c63
-rw-r--r--drivers/firmware/efi/test/efi_test.c27
-rw-r--r--drivers/firmware/efi/test/efi_test.h10
-rw-r--r--drivers/firmware/google/Kconfig32
-rw-r--r--drivers/firmware/google/Makefile2
-rw-r--r--drivers/firmware/google/coreboot_table-acpi.c88
-rw-r--r--drivers/firmware/google/coreboot_table-of.c82
-rw-r--r--drivers/firmware/google/coreboot_table.c126
-rw-r--r--drivers/firmware/google/coreboot_table.h6
-rw-r--r--drivers/firmware/google/gsmi.c122
-rw-r--r--drivers/firmware/google/vpd.c2
-rw-r--r--drivers/firmware/imx/Kconfig11
-rw-r--r--drivers/firmware/imx/Makefile2
-rw-r--r--drivers/firmware/imx/imx-scu.c270
-rw-r--r--drivers/firmware/imx/misc.c99
-rw-r--r--drivers/firmware/iscsi_ibft_find.c2
-rw-r--r--drivers/firmware/memmap.c5
-rw-r--r--drivers/firmware/meson/meson_sm.c56
-rw-r--r--drivers/firmware/qcom_scm.c74
-rw-r--r--drivers/firmware/scpi_pm_domain.c2
-rw-r--r--drivers/firmware/tegra/bpmp.c19
-rw-r--r--drivers/firmware/ti_sci.c24
-rw-r--r--drivers/firmware/xilinx/Kconfig23
-rw-r--r--drivers/firmware/xilinx/Makefile5
-rw-r--r--drivers/firmware/xilinx/zynqmp-debug.c250
-rw-r--r--drivers/firmware/xilinx/zynqmp-debug.h24
-rw-r--r--drivers/firmware/xilinx/zynqmp.c565
-rw-r--r--drivers/fpga/altera-cvp.c8
-rw-r--r--drivers/fpga/altera-fpga2sdram.c8
-rw-r--r--drivers/fpga/altera-freeze-bridge.c13
-rw-r--r--drivers/fpga/altera-hps2fpga.c7
-rw-r--r--drivers/fpga/altera-pr-ip-core.c9
-rw-r--r--drivers/fpga/altera-ps-spi.c11
-rw-r--r--drivers/fpga/dfl-afu-dma-region.c2
-rw-r--r--drivers/fpga/dfl-fme-br.c11
-rw-r--r--drivers/fpga/dfl-fme-mgr.c13
-rw-r--r--drivers/fpga/dfl-fme-region.c10
-rw-r--r--drivers/fpga/dfl.c6
-rw-r--r--drivers/fpga/fpga-bridge.c70
-rw-r--r--drivers/fpga/fpga-mgr.c64
-rw-r--r--drivers/fpga/fpga-region.c65
-rw-r--r--drivers/fpga/ice40-spi.c10
-rw-r--r--drivers/fpga/machxo2-spi.c11
-rw-r--r--drivers/fpga/of-fpga-region.c9
-rw-r--r--drivers/fpga/socfpga-a10.c5
-rw-r--r--drivers/fpga/socfpga.c10
-rw-r--r--drivers/fpga/ts73xx-fpga.c11
-rw-r--r--drivers/fpga/xilinx-pr-decoupler.c4
-rw-r--r--drivers/fpga/xilinx-spi.c12
-rw-r--r--drivers/fpga/zynq-fpga.c5
-rw-r--r--drivers/fsi/fsi-sbefifo.c4
-rw-r--r--drivers/gpio/Kconfig31
-rw-r--r--drivers/gpio/Makefile5
-rw-r--r--drivers/gpio/gpio-adp5520.c2
-rw-r--r--drivers/gpio/gpio-adp5588.c2
-rw-r--r--drivers/gpio/gpio-bcm-kona.c14
-rw-r--r--drivers/gpio/gpio-brcmstb.c15
-rw-r--r--drivers/gpio/gpio-creg-snps.c191
-rw-r--r--drivers/gpio/gpio-davinci.c60
-rw-r--r--drivers/gpio/gpio-ep93xx.c297
-rw-r--r--drivers/gpio/gpio-ftgpio010.c115
-rw-r--r--drivers/gpio/gpio-htc-egpio.c10
-rw-r--r--drivers/gpio/gpio-ingenic.c392
-rw-r--r--drivers/gpio/gpio-max3191x.c16
-rw-r--r--drivers/gpio/gpio-mmio.c6
-rw-r--r--drivers/gpio/gpio-mockup.c82
-rw-r--r--drivers/gpio/gpio-mxs.c4
-rw-r--r--drivers/gpio/gpio-omap.c356
-rw-r--r--drivers/gpio/gpio-pxa.c6
-rw-r--r--drivers/gpio/gpio-rcar.c6
-rw-r--r--drivers/gpio/gpio-siox.c293
-rw-r--r--drivers/gpio/gpio-syscon.c2
-rw-r--r--drivers/gpio/gpio-tb10x.c123
-rw-r--r--drivers/gpio/gpio-tps65086.c12
-rw-r--r--drivers/gpio/gpio-tps6586x.c15
-rw-r--r--drivers/gpio/gpio-tps65910.c9
-rw-r--r--drivers/gpio/gpio-tps65912.c16
-rw-r--r--drivers/gpio/gpio-ts5500.c13
-rw-r--r--drivers/gpio/gpio-twl4030.c59
-rw-r--r--drivers/gpio/gpio-twl6040.c31
-rw-r--r--drivers/gpio/gpio-uniphier.c2
-rw-r--r--drivers/gpio/gpio-vf610.c13
-rw-r--r--drivers/gpio/gpio-viperboard.c10
-rw-r--r--drivers/gpio/gpio-vr41xx.c55
-rw-r--r--drivers/gpio/gpio-vx855.c20
-rw-r--r--drivers/gpio/gpio-wm831x.c8
-rw-r--r--drivers/gpio/gpio-wm8350.c8
-rw-r--r--drivers/gpio/gpio-wm8994.c8
-rw-r--r--drivers/gpio/gpio-xlp.c12
-rw-r--r--drivers/gpio/gpio-xtensa.c7
-rw-r--r--drivers/gpio/gpio-zevio.c2
-rw-r--r--drivers/gpio/gpiolib-acpi.c8
-rw-r--r--drivers/gpio/gpiolib-devprop.c26
-rw-r--r--drivers/gpio/gpiolib-devres.c (renamed from drivers/gpio/devres.c)12
-rw-r--r--drivers/gpio/gpiolib-legacy.c1
-rw-r--r--drivers/gpio/gpiolib-of.c60
-rw-r--r--drivers/gpio/gpiolib-sysfs.c11
-rw-r--r--drivers/gpio/gpiolib.c643
-rw-r--r--drivers/gpio/gpiolib.h25
-rw-r--r--drivers/gpu/drm/Makefile5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/Makefile3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu.h5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c20
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h20
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c25
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c25
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c120
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c33
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c9
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_csa.c117
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_csa.h39
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_device.c39
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c11
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gart.h1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h54
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c49
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c21
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_job.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_job.h2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c25
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h8
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_object.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c223
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h61
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c28
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h8
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c282
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.h98
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c28
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h15
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c105
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h12
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c18
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c38
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c100
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c140
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h13
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c22
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c36
-rw-r--r--drivers/gpu/drm/amd/amdgpu/ci_dpm.c6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cik_sdma.c66
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c144
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c276
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c351
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c382
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c25
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.h2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c110
-rw-r--r--drivers/gpu/drm/amd/amdgpu/kv_dpm.c6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c25
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.h2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/psp_v11_0.c141
-rw-r--r--drivers/gpu/drm/amd/amdgpu/psp_v3_1.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c69
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c69
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c702
-rw-r--r--drivers/gpu/drm/amd/amdgpu/si_dma.c68
-rw-r--r--drivers/gpu/drm/amd/amdgpu/ta_xgmi_if.h130
-rw-r--r--drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c29
-rw-r--r--drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c28
-rw-r--r--drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c76
-rw-r--r--drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c74
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vce_v2_0.c6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vce_v3_0.c13
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vce_v4_0.c15
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c42
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vega10_ih.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vega20_reg_init.c1
-rw-r--r--drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c3
-rw-r--r--drivers/gpu/drm/amd/amdkfd/cik_regs.h2
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_chardev.c21
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_crat.c9
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_device.c12
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c24
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c3
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c5
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_pasid.c5
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_priv.h1
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_process.c34
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_topology.c10
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c197
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h78
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c2
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c5
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c115
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c79
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h1
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c20
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/bios_parser.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c93
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h4
-rw-r--r--drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c32
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc.c60
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_debug.c7
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_link.c59
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_resource.c76
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_stream.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_surface.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc.h10
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_bios_types.h5
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_link.h11
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/Makefile2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_abm.c104
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c879
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.h (renamed from drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h)105
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c947
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h52
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c73
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.h5
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c25
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c282
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h11
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c33
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c39
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c20
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce80/dce80_hw_sequencer.c3
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c41
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/Makefile2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.c379
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.h37
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c253
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c163
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h20
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c8
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c17
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c32
-rw-r--r--drivers/gpu/drm/amd/display/dc/dm_pp_smu.h28
-rw-r--r--drivers/gpu/drm/amd/display/dc/dm_services_types.h18
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/bw_fixed.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/core_types.h5
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/dcn_calcs.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/abm.h12
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h (renamed from drivers/gpu/drm/amd/display/dc/inc/hw/display_clock.h)34
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h44
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h16
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/mem_input.h4
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h20
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/resource.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/os_types.h2
-rw-r--r--drivers/gpu/drm/amd/display/modules/color/color_gamma.c186
-rw-r--r--drivers/gpu/drm/amd/display/modules/color/color_gamma.h11
-rw-r--r--drivers/gpu/drm/amd/display/modules/freesync/freesync.c37
-rw-r--r--drivers/gpu/drm/amd/include/amd_shared.h4
-rw-r--r--drivers/gpu/drm/amd/include/atomfirmware.h7
-rw-r--r--drivers/gpu/drm/amd/include/kgd_kfd_interface.h115
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c12
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.c32
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c36
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c192
-rw-r--r--drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.h1
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/hwmgr.h1
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/smu7_common.h4
-rw-r--r--drivers/gpu/drm/amd/powerplay/inc/vega20_ppsmc.h3
-rw-r--r--drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c1
-rw-r--r--drivers/gpu/drm/amd/powerplay/smumgr/smu10_smumgr.c1
-rw-r--r--drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c49
-rw-r--r--drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c3
-rw-r--r--drivers/gpu/drm/amd/powerplay/smumgr/vegam_smumgr.c1
-rw-r--r--drivers/gpu/drm/arc/arcpgu.h4
-rw-r--r--drivers/gpu/drm/arc/arcpgu_crtc.c3
-rw-r--r--drivers/gpu/drm/arc/arcpgu_drv.c34
-rw-r--r--drivers/gpu/drm/arm/malidp_hw.c14
-rw-r--r--drivers/gpu/drm/arm/malidp_planes.c28
-rw-r--r--drivers/gpu/drm/ast/ast_drv.h2
-rw-r--r--drivers/gpu/drm/ast/ast_ttm.c64
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c2
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c15
-rw-r--r--drivers/gpu/drm/bochs/bochs.h4
-rw-r--r--drivers/gpu/drm/bochs/bochs_hw.c30
-rw-r--r--drivers/gpu/drm/bochs/bochs_kms.c20
-rw-r--r--drivers/gpu/drm/bochs/bochs_mm.c65
-rw-r--r--drivers/gpu/drm/bridge/analogix/analogix_dp_core.c12
-rw-r--r--drivers/gpu/drm/bridge/synopsys/dw-hdmi.c6
-rw-r--r--drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c114
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_drv.h2
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_ttm.c64
-rw-r--r--drivers/gpu/drm/drm_atomic.c5
-rw-r--r--drivers/gpu/drm/drm_atomic_helper.c610
-rw-r--r--drivers/gpu/drm/drm_atomic_state_helper.c601
-rw-r--r--drivers/gpu/drm/drm_bufs.c3
-rw-r--r--drivers/gpu/drm/drm_client.c35
-rw-r--r--drivers/gpu/drm/drm_connector.c22
-rw-r--r--drivers/gpu/drm/drm_crtc.c10
-rw-r--r--drivers/gpu/drm/drm_crtc_helper.c115
-rw-r--r--drivers/gpu/drm/drm_dp_cec.c2
-rw-r--r--drivers/gpu/drm/drm_dp_mst_topology.c12
-rw-r--r--drivers/gpu/drm/drm_drv.c10
-rw-r--r--drivers/gpu/drm/drm_edid.c5
-rw-r--r--drivers/gpu/drm/drm_fb_cma_helper.c47
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c101
-rw-r--r--drivers/gpu/drm/drm_fourcc.c80
-rw-r--r--drivers/gpu/drm/drm_framebuffer.c13
-rw-r--r--drivers/gpu/drm/drm_gem_framebuffer_helper.c2
-rw-r--r--drivers/gpu/drm/drm_global.c137
-rw-r--r--drivers/gpu/drm/drm_lease.c44
-rw-r--r--drivers/gpu/drm/drm_memory.c10
-rw-r--r--drivers/gpu/drm/drm_mode_object.c3
-rw-r--r--drivers/gpu/drm/drm_modes.c4
-rw-r--r--drivers/gpu/drm/drm_modeset_helper.c15
-rw-r--r--drivers/gpu/drm/drm_panel_orientation_quirks.c16
-rw-r--r--drivers/gpu/drm/drm_pci.c5
-rw-r--r--drivers/gpu/drm/drm_plane.c23
-rw-r--r--drivers/gpu/drm/drm_plane_helper.c331
-rw-r--r--drivers/gpu/drm/drm_prime.c30
-rw-r--r--drivers/gpu/drm/drm_simple_kms_helper.c8
-rw-r--r--drivers/gpu/drm/drm_syncobj.c359
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c2
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_sched.c7
-rw-r--r--drivers/gpu/drm/exynos/exynos5433_drm_decon.c9
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_crtc.c11
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.h1
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dsi.c14
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fbdev.c2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_iommu.h34
-rw-r--r--drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c33
-rw-r--r--drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c25
-rw-r--r--drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h1
-rw-r--r--drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h2
-rw-r--r--drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c57
-rw-r--r--drivers/gpu/drm/i2c/tda9950.c5
-rw-r--r--drivers/gpu/drm/i915/Makefile2
-rw-r--r--drivers/gpu/drm/i915/gvt/gtt.c115
-rw-r--r--drivers/gpu/drm/i915/gvt/gtt.h9
-rw-r--r--drivers/gpu/drm/i915/gvt/handlers.c8
-rw-r--r--drivers/gpu/drm/i915/gvt/mmio_context.c2
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c17
-rw-r--r--drivers/gpu/drm/i915/i915_gem_execbuffer.c2
-rw-r--r--drivers/gpu/drm/i915/i915_vma.c2
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c3
-rw-r--r--drivers/gpu/drm/mediatek/mtk_drm_crtc.c2
-rw-r--r--drivers/gpu/drm/mediatek/mtk_hdmi.c5
-rw-r--r--drivers/gpu/drm/meson/meson_drv.c19
-rw-r--r--drivers/gpu/drm/meson/meson_drv.h1
-rw-r--r--drivers/gpu/drm/meson/meson_venc.c15
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_drv.h2
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_ttm.c64
-rw-r--r--drivers/gpu/drm/msm/adreno/a5xx_gpu.c5
-rw-r--r--drivers/gpu/drm/msm/adreno/adreno_gpu.c5
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c4
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c2
-rw-r--r--drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c1
-rw-r--r--drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c1
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi.c2
-rw-r--r--drivers/gpu/drm/msm/msm_drv.c1
-rw-r--r--drivers/gpu/drm/msm/msm_gem_submit.c3
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/disp.c15
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fence.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_ttm.c67
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dsi.c22
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dss.c11
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi4.c37
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi5.c27
-rw-r--r--drivers/gpu/drm/omapdrm/dss/venc.c7
-rw-r--r--drivers/gpu/drm/omapdrm/omap_crtc.c6
-rw-r--r--drivers/gpu/drm/panel/Kconfig25
-rw-r--r--drivers/gpu/drm/panel/Makefile3
-rw-r--r--drivers/gpu/drm/panel/panel-innolux-p079zca.c3
-rw-r--r--drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c330
-rw-r--r--drivers/gpu/drm/panel/panel-samsung-s6d16d0.c264
-rw-r--r--drivers/gpu/drm/panel/panel-seiko-43wvf1g.c7
-rw-r--r--drivers/gpu/drm/panel/panel-simple.c157
-rw-r--r--drivers/gpu/drm/panel/panel-truly-nt35597.c675
-rw-r--r--drivers/gpu/drm/qxl/qxl_cmd.c7
-rw-r--r--drivers/gpu/drm/qxl/qxl_debugfs.c5
-rw-r--r--drivers/gpu/drm/qxl/qxl_dev.h1
-rw-r--r--drivers/gpu/drm/qxl/qxl_display.c19
-rw-r--r--drivers/gpu/drm/qxl/qxl_draw.c11
-rw-r--r--drivers/gpu/drm/qxl/qxl_drv.h32
-rw-r--r--drivers/gpu/drm/qxl/qxl_dumb.c3
-rw-r--r--drivers/gpu/drm/qxl/qxl_fb.c4
-rw-r--r--drivers/gpu/drm/qxl/qxl_image.c4
-rw-r--r--drivers/gpu/drm/qxl/qxl_ioctl.c2
-rw-r--r--drivers/gpu/drm/qxl/qxl_kms.c2
-rw-r--r--drivers/gpu/drm/qxl/qxl_object.c5
-rw-r--r--drivers/gpu/drm/qxl/qxl_object.h2
-rw-r--r--drivers/gpu/drm/qxl/qxl_prime.c1
-rw-r--r--drivers/gpu/drm/qxl/qxl_release.c3
-rw-r--r--drivers/gpu/drm/qxl/qxl_ttm.c73
-rw-r--r--drivers/gpu/drm/radeon/r300.c4
-rw-r--r--drivers/gpu/drm/radeon/r420.c1
-rw-r--r--drivers/gpu/drm/radeon/radeon.h3
-rw-r--r--drivers/gpu/drm/radeon/radeon_legacy_tv.c10
-rw-r--r--drivers/gpu/drm/radeon/radeon_object.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_ttm.c65
-rw-r--r--drivers/gpu/drm/radeon/radeon_vm.c2
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_drv.c21
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_drv.h1
-rw-r--r--drivers/gpu/drm/rockchip/Kconfig2
-rw-r--r--drivers/gpu/drm/rockchip/Makefile2
-rw-r--r--drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c1076
-rw-r--r--drivers/gpu/drm/rockchip/dw-mipi-dsi.c1349
-rw-r--r--drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c128
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_drv.c2
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_drv.h3
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_psr.c4
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_vop.c3
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_vop.h4
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_vop_reg.c7
-rw-r--r--drivers/gpu/drm/scheduler/sched_entity.c10
-rw-r--r--drivers/gpu/drm/scheduler/sched_main.c33
-rw-r--r--drivers/gpu/drm/selftests/Makefile5
-rw-r--r--drivers/gpu/drm/selftests/drm_modeset_selftests.h (renamed from drivers/gpu/drm/selftests/drm_helper_selftests.h)4
-rw-r--r--drivers/gpu/drm/selftests/test-drm_format.c280
-rw-r--r--drivers/gpu/drm/selftests/test-drm_framebuffer.c346
-rw-r--r--drivers/gpu/drm/selftests/test-drm_modeset_common.c32
-rw-r--r--drivers/gpu/drm/selftests/test-drm_modeset_common.h22
-rw-r--r--drivers/gpu/drm/selftests/test-drm_plane_helper.c (renamed from drivers/gpu/drm/selftests/test-drm-helper.c)38
-rw-r--r--drivers/gpu/drm/sti/sti_crtc.c2
-rw-r--r--drivers/gpu/drm/sti/sti_cursor.c1
-rw-r--r--drivers/gpu/drm/sti/sti_drv.c6
-rw-r--r--drivers/gpu/drm/sti/sti_gdp.c3
-rw-r--r--drivers/gpu/drm/sti/sti_hqvdp.c1
-rw-r--r--drivers/gpu/drm/stm/drv.c13
-rw-r--r--drivers/gpu/drm/stm/ltdc.c45
-rw-r--r--drivers/gpu/drm/stm/ltdc.h5
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_dotclock.c12
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_drv.c12
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_framebuffer.c12
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_framebuffer.h3
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c4
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_lvds.c4
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_rgb.c4
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_tcon.c5
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_csc.c83
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c45
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h14
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c201
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_mixer.c57
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_mixer.h80
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_tcon_top.c52
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_ui_layer.c47
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_ui_layer.h37
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_ui_scaler.c47
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_ui_scaler.h28
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_vi_layer.c55
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_vi_layer.h25
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_vi_scaler.c70
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_vi_scaler.h68
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_drv.c11
-rw-r--r--drivers/gpu/drm/tinydrm/Kconfig11
-rw-r--r--drivers/gpu/drm/tinydrm/Makefile1
-rw-r--r--drivers/gpu/drm/tinydrm/core/tinydrm-core.c1
-rw-r--r--drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c6
-rw-r--r--drivers/gpu/drm/tinydrm/hx8357d.c270
-rw-r--r--drivers/gpu/drm/tinydrm/mipi-dbi.c4
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo.c73
-rw-r--r--drivers/gpu/drm/ttm/ttm_execbuf_util.c6
-rw-r--r--drivers/gpu/drm/ttm/ttm_memory.c14
-rw-r--r--drivers/gpu/drm/udl/udl_main.c7
-rw-r--r--drivers/gpu/drm/v3d/v3d_debugfs.c46
-rw-r--r--drivers/gpu/drm/v3d/v3d_drv.h5
-rw-r--r--drivers/gpu/drm/v3d/v3d_gem.c14
-rw-r--r--drivers/gpu/drm/v3d/v3d_regs.h30
-rw-r--r--drivers/gpu/drm/v3d/v3d_sched.c5
-rw-r--r--drivers/gpu/drm/vc4/vc4_drv.c3
-rw-r--r--drivers/gpu/drm/vc4/vc4_gem.c4
-rw-r--r--drivers/gpu/drm/vc4/vc4_plane.c164
-rw-r--r--drivers/gpu/drm/vc4/vc4_regs.h8
-rw-r--r--drivers/gpu/drm/vgem/vgem_drv.c19
-rw-r--r--drivers/gpu/drm/vgem/vgem_fence.c2
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_drm_bus.c31
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_drv.h17
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_fb.c7
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_gem.c8
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_ioctl.c25
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_kms.c45
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_object.c17
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_ttm.c65
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_vq.c37
-rw-r--r--drivers/gpu/drm/vkms/vkms_drv.c21
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.c15
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.h6
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.c24
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c1
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c1
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c1
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c54
-rw-r--r--drivers/gpu/drm/zte/zx_drm_drv.c5
-rw-r--r--drivers/gpu/drm/zte/zx_plane.c1
-rw-r--r--drivers/gpu/ipu-v3/ipu-csi.c6
-rw-r--r--drivers/gpu/vga/vga_switcheroo.c3
-rw-r--r--drivers/gpu/vga/vgaarb.c21
-rw-r--r--drivers/hid/Kconfig16
-rw-r--r--drivers/hid/Makefile1
-rw-r--r--drivers/hid/hid-alps.c18
-rw-r--r--drivers/hid/hid-asus.c26
-rw-r--r--drivers/hid/hid-bigbenff.c414
-rw-r--r--drivers/hid/hid-core.c2
-rw-r--r--drivers/hid/hid-cougar.c66
-rw-r--r--drivers/hid/hid-elan.c2
-rw-r--r--drivers/hid/hid-google-hammer.c413
-rw-r--r--drivers/hid/hid-ids.h10
-rw-r--r--drivers/hid/hid-input.c63
-rw-r--r--drivers/hid/hid-logitech-hidpp.c309
-rw-r--r--drivers/hid/hid-magicmouse.c142
-rw-r--r--drivers/hid/hid-microsoft.c141
-rw-r--r--drivers/hid/hid-multitouch.c72
-rw-r--r--drivers/hid/hid-picolcd_cir.c3
-rw-r--r--drivers/hid/hid-quirks.c2
-rw-r--r--drivers/hid/i2c-hid/Makefile3
-rw-r--r--drivers/hid/i2c-hid/i2c-hid-core.c (renamed from drivers/hid/i2c-hid/i2c-hid.c)106
-rw-r--r--drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c385
-rw-r--r--drivers/hid/i2c-hid/i2c-hid.h20
-rw-r--r--drivers/hid/intel-ish-hid/ipc/hw-ish.h1
-rw-r--r--drivers/hid/intel-ish-hid/ipc/ipc.c32
-rw-r--r--drivers/hid/intel-ish-hid/ipc/pci-ish.c76
-rw-r--r--drivers/hid/intel-ish-hid/ishtp-hid-client.c41
-rw-r--r--drivers/hid/intel-ish-hid/ishtp/bus.c52
-rw-r--r--drivers/hid/intel-ish-hid/ishtp/bus.h5
-rw-r--r--drivers/hid/intel-ish-hid/ishtp/client-buffers.c49
-rw-r--r--drivers/hid/intel-ish-hid/ishtp/client.c24
-rw-r--r--drivers/hid/intel-ish-hid/ishtp/client.h5
-rw-r--r--drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h2
-rw-r--r--drivers/hid/usbhid/hiddev.c18
-rw-r--r--drivers/hid/wacom_wac.c19
-rw-r--r--drivers/hv/channel.c300
-rw-r--r--drivers/hv/channel_mgmt.c54
-rw-r--r--drivers/hv/connection.c8
-rw-r--r--drivers/hv/hv.c15
-rw-r--r--drivers/hv/hv_balloon.c2
-rw-r--r--drivers/hv/hv_kvp.c14
-rw-r--r--drivers/hv/ring_buffer.c1
-rw-r--r--drivers/hv/vmbus_drv.c118
-rw-r--r--drivers/hwmon/aspeed-pwm-tacho.c2
-rw-r--r--drivers/hwmon/asus_atk0110.c4
-rw-r--r--drivers/hwmon/hwmon.c36
-rw-r--r--drivers/hwmon/ibmaem.c2
-rw-r--r--drivers/hwmon/ibmpex.c2
-rw-r--r--drivers/hwmon/ibmpowernv.c17
-rw-r--r--drivers/hwmon/iio_hwmon.c16
-rw-r--r--drivers/hwmon/ina3221.c592
-rw-r--r--drivers/hwmon/k10temp.c5
-rw-r--r--drivers/hwmon/lm75.c21
-rw-r--r--drivers/hwmon/lm92.c14
-rw-r--r--drivers/hwmon/lm95245.c3
-rw-r--r--drivers/hwmon/mc13783-adc.c14
-rw-r--r--drivers/hwmon/nct6775.c302
-rw-r--r--drivers/hwmon/npcm750-pwm-fan.c6
-rw-r--r--drivers/hwmon/pmbus/Kconfig18
-rw-r--r--drivers/hwmon/pmbus/ltc2978.c9
-rw-r--r--drivers/hwmon/pmbus/pmbus.c2
-rw-r--r--drivers/hwmon/pmbus/pmbus_core.c5
-rw-r--r--drivers/hwmon/pwm-fan.c20
-rw-r--r--drivers/hwmon/scmi-hwmon.c2
-rw-r--r--drivers/hwmon/scpi-hwmon.c4
-rw-r--r--drivers/hwmon/sht15.c5
-rw-r--r--drivers/hwmon/tmp102.c3
-rw-r--r--drivers/hwmon/tmp108.c3
-rw-r--r--drivers/hwmon/tmp421.c6
-rw-r--r--drivers/hwtracing/coresight/coresight-catu.c6
-rw-r--r--drivers/hwtracing/coresight/coresight-dynamic-replicator.c81
-rw-r--r--drivers/hwtracing/coresight/coresight-etb10.c183
-rw-r--r--drivers/hwtracing/coresight/coresight-etm-perf.c132
-rw-r--r--drivers/hwtracing/coresight/coresight-etm-perf.h26
-rw-r--r--drivers/hwtracing/coresight/coresight-etm3x.c58
-rw-r--r--drivers/hwtracing/coresight/coresight-etm4x.c93
-rw-r--r--drivers/hwtracing/coresight/coresight-funnel.c28
-rw-r--r--drivers/hwtracing/coresight/coresight-priv.h9
-rw-r--r--drivers/hwtracing/coresight/coresight-replicator.c4
-rw-r--r--drivers/hwtracing/coresight/coresight-stm.c4
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc-etf.c198
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc-etr.c385
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc.c4
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc.h4
-rw-r--r--drivers/hwtracing/coresight/coresight-tpiu.c6
-rw-r--r--drivers/hwtracing/coresight/coresight.c184
-rw-r--r--drivers/hwtracing/coresight/of_coresight.c262
-rw-r--r--drivers/hwtracing/stm/Kconfig29
-rw-r--r--drivers/hwtracing/stm/Makefile6
-rw-r--r--drivers/hwtracing/stm/core.c292
-rw-r--r--drivers/hwtracing/stm/heartbeat.c2
-rw-r--r--drivers/hwtracing/stm/p_basic.c48
-rw-r--r--drivers/hwtracing/stm/p_sys-t.c382
-rw-r--r--drivers/hwtracing/stm/policy.c147
-rw-r--r--drivers/hwtracing/stm/stm.h56
-rw-r--r--drivers/i2c/busses/Kconfig18
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-aspeed.c205
-rw-r--r--drivers/i2c/busses/i2c-designware-baytrail.c141
-rw-r--r--drivers/i2c/busses/i2c-designware-common.c6
-rw-r--r--drivers/i2c/busses/i2c-designware-core.h18
-rw-r--r--drivers/i2c/busses/i2c-designware-master.c6
-rw-r--r--drivers/i2c/busses/i2c-designware-platdrv.c92
-rw-r--r--drivers/i2c/busses/i2c-isch.c2
-rw-r--r--drivers/i2c/busses/i2c-mt65xx.c62
-rw-r--r--drivers/i2c/busses/i2c-nvidia-gpu.c368
-rw-r--r--drivers/i2c/busses/i2c-omap.c8
-rw-r--r--drivers/i2c/busses/i2c-powermac.c17
-rw-r--r--drivers/i2c/busses/i2c-qcom-geni.c170
-rw-r--r--drivers/i2c/busses/i2c-qup.c14
-rw-r--r--drivers/i2c/busses/i2c-rcar.c6
-rw-r--r--drivers/i2c/busses/i2c-scmi.c1
-rw-r--r--drivers/i2c/busses/i2c-sh_mobile.c18
-rw-r--r--drivers/i2c/busses/i2c-synquacer.c2
-rw-r--r--drivers/i2c/busses/i2c-tegra.c4
-rw-r--r--drivers/i2c/busses/i2c-uniphier-f.c59
-rw-r--r--drivers/i2c/busses/i2c-zx2967.c8
-rw-r--r--drivers/i2c/i2c-core-base.c52
-rw-r--r--drivers/i2c/muxes/i2c-mux-gpio.c14
-rw-r--r--drivers/i2c/muxes/i2c-mux-gpmux.c4
-rw-r--r--drivers/i2c/muxes/i2c-mux-ltc4306.c2
-rw-r--r--drivers/i2c/muxes/i2c-mux-mlxcpld.c2
-rw-r--r--drivers/i2c/muxes/i2c-mux-pca954x.c2
-rw-r--r--drivers/ide/ide-cd.c2
-rw-r--r--drivers/ide/ide-gd.c2
-rw-r--r--drivers/idle/intel_idle.c77
-rw-r--r--drivers/iio/accel/Kconfig27
-rw-r--r--drivers/iio/accel/Makefile3
-rw-r--r--drivers/iio/accel/adxl345_i2c.c5
-rw-r--r--drivers/iio/accel/adxl372.c975
-rw-r--r--drivers/iio/accel/adxl372.h17
-rw-r--r--drivers/iio/accel/adxl372_i2c.c61
-rw-r--r--drivers/iio/accel/adxl372_spi.c52
-rw-r--r--drivers/iio/adc/Kconfig30
-rw-r--r--drivers/iio/adc/Makefile2
-rw-r--r--drivers/iio/adc/ad7298.c2
-rw-r--r--drivers/iio/adc/ad7476.c2
-rw-r--r--drivers/iio/adc/ad7793.c2
-rw-r--r--drivers/iio/adc/ad7887.c2
-rw-r--r--drivers/iio/adc/ad7923.c2
-rw-r--r--drivers/iio/adc/ad799x.c2
-rw-r--r--drivers/iio/adc/at91_adc.c6
-rw-r--r--drivers/iio/adc/envelope-detector.c5
-rw-r--r--drivers/iio/adc/fsl-imx25-gcq.c6
-rw-r--r--drivers/iio/adc/max9611.c2
-rw-r--r--drivers/iio/adc/mcp3911.c363
-rw-r--r--drivers/iio/adc/meson_saradc.c70
-rw-r--r--drivers/iio/adc/qcom-pm8xxx-xoadc.c4
-rw-r--r--drivers/iio/adc/qcom-spmi-adc5.c793
-rw-r--r--drivers/iio/adc/qcom-vadc-common.c189
-rw-r--r--drivers/iio/adc/qcom-vadc-common.h54
-rw-r--r--drivers/iio/adc/rcar-gyroadc.c12
-rw-r--r--drivers/iio/adc/sc27xx_adc.c154
-rw-r--r--drivers/iio/adc/ti-ads7950.c53
-rw-r--r--drivers/iio/adc/ti_am335x_adc.c12
-rw-r--r--drivers/iio/amplifiers/ad8366.c2
-rw-r--r--drivers/iio/chemical/bme680.h19
-rw-r--r--drivers/iio/chemical/bme680_core.c154
-rw-r--r--drivers/iio/dac/Kconfig10
-rw-r--r--drivers/iio/dac/Makefile1
-rw-r--r--drivers/iio/dac/ad5064.c53
-rw-r--r--drivers/iio/dac/ad5446.c2
-rw-r--r--drivers/iio/dac/ad5504.c2
-rw-r--r--drivers/iio/dac/ad5686.c2
-rw-r--r--drivers/iio/dac/ad5758.c26
-rw-r--r--drivers/iio/dac/ad5791.c2
-rw-r--r--drivers/iio/dac/dpot-dac.c5
-rw-r--r--drivers/iio/dac/ltc1660.c250
-rw-r--r--drivers/iio/dac/max517.c11
-rw-r--r--drivers/iio/dac/max5821.c11
-rw-r--r--drivers/iio/dac/mcp4725.c12
-rw-r--r--drivers/iio/dac/mcp4922.c11
-rw-r--r--drivers/iio/dac/ti-dac5571.c1
-rw-r--r--drivers/iio/frequency/ad9523.c2
-rw-r--r--drivers/iio/frequency/adf4350.c2
-rw-r--r--drivers/iio/health/max30102.c6
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_core.c62
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h2
-rw-r--r--drivers/iio/imu/st_lsm6dsx/Kconfig2
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h18
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c166
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c51
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c5
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c5
-rw-r--r--drivers/iio/light/apds9960.c3
-rw-r--r--drivers/iio/light/bh1750.c25
-rw-r--r--drivers/iio/light/max44000.c24
-rw-r--r--drivers/iio/light/tsl2772.c194
-rw-r--r--drivers/iio/magnetometer/hmc5843.h2
-rw-r--r--drivers/iio/multiplexer/iio-mux.c5
-rw-r--r--drivers/iio/potentiometer/max5481.c7
-rw-r--r--drivers/iio/potentiometer/mcp4018.c9
-rw-r--r--drivers/iio/potentiometer/mcp4531.c14
-rw-r--r--drivers/iio/pressure/ms5611.h5
-rw-r--r--drivers/iio/pressure/ms5611_core.c5
-rw-r--r--drivers/iio/pressure/ms5611_i2c.c7
-rw-r--r--drivers/iio/pressure/ms5611_spi.c7
-rw-r--r--drivers/iio/proximity/Kconfig11
-rw-r--r--drivers/iio/proximity/Makefile2
-rw-r--r--drivers/iio/proximity/isl29501.c12
-rw-r--r--drivers/iio/proximity/vl53l0x-i2c.c164
-rw-r--r--drivers/iio/temperature/mlx90632.c3
-rw-r--r--drivers/iio/trigger/iio-trig-sysfs.c2
-rw-r--r--drivers/infiniband/Kconfig1
-rw-r--r--drivers/infiniband/core/addr.c406
-rw-r--r--drivers/infiniband/core/cache.c79
-rw-r--r--drivers/infiniband/core/cm.c9
-rw-r--r--drivers/infiniband/core/cma.c251
-rw-r--r--drivers/infiniband/core/cma_configfs.c2
-rw-r--r--drivers/infiniband/core/core_priv.h12
-rw-r--r--drivers/infiniband/core/cq.c10
-rw-r--r--drivers/infiniband/core/device.c264
-rw-r--r--drivers/infiniband/core/fmr_pool.c5
-rw-r--r--drivers/infiniband/core/iwcm.c2
-rw-r--r--drivers/infiniband/core/mad.c80
-rw-r--r--drivers/infiniband/core/mad_priv.h2
-rw-r--r--drivers/infiniband/core/netlink.c4
-rw-r--r--drivers/infiniband/core/nldev.c37
-rw-r--r--drivers/infiniband/core/rdma_core.c56
-rw-r--r--drivers/infiniband/core/rdma_core.h1
-rw-r--r--drivers/infiniband/core/restrack.c30
-rw-r--r--drivers/infiniband/core/rw.c11
-rw-r--r--drivers/infiniband/core/sa.h8
-rw-r--r--drivers/infiniband/core/sa_query.c70
-rw-r--r--drivers/infiniband/core/security.c7
-rw-r--r--drivers/infiniband/core/sysfs.c101
-rw-r--r--drivers/infiniband/core/ucm.c3
-rw-r--r--drivers/infiniband/core/ucma.c3
-rw-r--r--drivers/infiniband/core/umem.c125
-rw-r--r--drivers/infiniband/core/umem_odp.c621
-rw-r--r--drivers/infiniband/core/user_mad.c13
-rw-r--r--drivers/infiniband/core/uverbs.h15
-rw-r--r--drivers/infiniband/core/uverbs_cmd.c43
-rw-r--r--drivers/infiniband/core/uverbs_ioctl.c140
-rw-r--r--drivers/infiniband/core/uverbs_main.c340
-rw-r--r--drivers/infiniband/core/uverbs_std_types_flow_action.c7
-rw-r--r--drivers/infiniband/core/uverbs_uapi.c12
-rw-r--r--drivers/infiniband/core/verbs.c65
-rw-r--r--drivers/infiniband/hw/bnxt_re/bnxt_re.h3
-rw-r--r--drivers/infiniband/hw/bnxt_re/hw_counters.c11
-rw-r--r--drivers/infiniband/hw/bnxt_re/hw_counters.h3
-rw-r--r--drivers/infiniband/hw/bnxt_re/ib_verbs.c4
-rw-r--r--drivers/infiniband/hw/bnxt_re/main.c125
-rw-r--r--drivers/infiniband/hw/bnxt_re/qplib_fp.c134
-rw-r--r--drivers/infiniband/hw/bnxt_re/qplib_rcfw.c88
-rw-r--r--drivers/infiniband/hw/bnxt_re/qplib_rcfw.h4
-rw-r--r--drivers/infiniband/hw/bnxt_re/qplib_res.c29
-rw-r--r--drivers/infiniband/hw/bnxt_re/qplib_sp.c77
-rw-r--r--drivers/infiniband/hw/bnxt_re/qplib_sp.h10
-rw-r--r--drivers/infiniband/hw/bnxt_re/roce_hsi.h5
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_provider.c55
-rw-r--r--drivers/infiniband/hw/cxgb4/cm.c3
-rw-r--r--drivers/infiniband/hw/cxgb4/cq.c2
-rw-r--r--drivers/infiniband/hw/cxgb4/provider.c50
-rw-r--r--drivers/infiniband/hw/cxgb4/qp.c20
-rw-r--r--drivers/infiniband/hw/cxgb4/t4.h2
-rw-r--r--drivers/infiniband/hw/hfi1/Makefile42
-rw-r--r--drivers/infiniband/hw/hfi1/affinity.c4
-rw-r--r--drivers/infiniband/hw/hfi1/chip.c486
-rw-r--r--drivers/infiniband/hw/hfi1/chip.h71
-rw-r--r--drivers/infiniband/hw/hfi1/chip_registers.h4
-rw-r--r--drivers/infiniband/hw/hfi1/file_ops.c4
-rw-r--r--drivers/infiniband/hw/hfi1/hfi.h48
-rw-r--r--drivers/infiniband/hw/hfi1/init.c113
-rw-r--r--drivers/infiniband/hw/hfi1/iowait.c94
-rw-r--r--drivers/infiniband/hw/hfi1/iowait.h192
-rw-r--r--drivers/infiniband/hw/hfi1/mad.c4
-rw-r--r--drivers/infiniband/hw/hfi1/mmu_rb.c1
-rw-r--r--drivers/infiniband/hw/hfi1/msix.c363
-rw-r--r--drivers/infiniband/hw/hfi1/msix.h64
-rw-r--r--drivers/infiniband/hw/hfi1/pcie.c75
-rw-r--r--drivers/infiniband/hw/hfi1/pio.c8
-rw-r--r--drivers/infiniband/hw/hfi1/qp.c100
-rw-r--r--drivers/infiniband/hw/hfi1/qp.h31
-rw-r--r--drivers/infiniband/hw/hfi1/rc.c24
-rw-r--r--drivers/infiniband/hw/hfi1/ruc.c382
-rw-r--r--drivers/infiniband/hw/hfi1/sdma.c56
-rw-r--r--drivers/infiniband/hw/hfi1/sdma.h21
-rw-r--r--drivers/infiniband/hw/hfi1/sysfs.c69
-rw-r--r--drivers/infiniband/hw/hfi1/trace.h3
-rw-r--r--drivers/infiniband/hw/hfi1/trace_iowait.h54
-rw-r--r--drivers/infiniband/hw/hfi1/uc.c14
-rw-r--r--drivers/infiniband/hw/hfi1/ud.c22
-rw-r--r--drivers/infiniband/hw/hfi1/user_sdma.c137
-rw-r--r--drivers/infiniband/hw/hfi1/user_sdma.h20
-rw-r--r--drivers/infiniband/hw/hfi1/verbs.c251
-rw-r--r--drivers/infiniband/hw/hfi1/verbs.h35
-rw-r--r--drivers/infiniband/hw/hfi1/verbs_txreq.h11
-rw-r--r--drivers/infiniband/hw/hfi1/vnic_main.c12
-rw-r--r--drivers/infiniband/hw/hfi1/vnic_sdma.c21
-rw-r--r--drivers/infiniband/hw/hns/Kconfig1
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_ah.c6
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_device.h45
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_hw_v1.c4
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_hw_v2.c629
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_hw_v2.h96
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_main.c123
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_mr.c212
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_qp.c41
-rw-r--r--drivers/infiniband/hw/i40iw/i40iw_cm.c2
-rw-r--r--drivers/infiniband/hw/i40iw/i40iw_verbs.c73
-rw-r--r--drivers/infiniband/hw/mlx4/Kconfig1
-rw-r--r--drivers/infiniband/hw/mlx4/mad.c20
-rw-r--r--drivers/infiniband/hw/mlx4/main.c182
-rw-r--r--drivers/infiniband/hw/mlx4/mcg.c2
-rw-r--r--drivers/infiniband/hw/mlx4/mlx4_ib.h5
-rw-r--r--drivers/infiniband/hw/mlx4/qp.c8
-rw-r--r--drivers/infiniband/hw/mlx4/sysfs.c6
-rw-r--r--drivers/infiniband/hw/mlx5/cmd.c129
-rw-r--r--drivers/infiniband/hw/mlx5/cmd.h14
-rw-r--r--drivers/infiniband/hw/mlx5/cq.c34
-rw-r--r--drivers/infiniband/hw/mlx5/devx.c364
-rw-r--r--drivers/infiniband/hw/mlx5/flow.c393
-rw-r--r--drivers/infiniband/hw/mlx5/ib_rep.c3
-rw-r--r--drivers/infiniband/hw/mlx5/main.c546
-rw-r--r--drivers/infiniband/hw/mlx5/mem.c9
-rw-r--r--drivers/infiniband/hw/mlx5/mlx5_ib.h99
-rw-r--r--drivers/infiniband/hw/mlx5/mr.c26
-rw-r--r--drivers/infiniband/hw/mlx5/odp.c123
-rw-r--r--drivers/infiniband/hw/mlx5/qp.c491
-rw-r--r--drivers/infiniband/hw/mlx5/srq.c1
-rw-r--r--drivers/infiniband/hw/mthca/mthca_mad.c5
-rw-r--r--drivers/infiniband/hw/mthca/mthca_main.c6
-rw-r--r--drivers/infiniband/hw/mthca/mthca_provider.c44
-rw-r--r--drivers/infiniband/hw/mthca/mthca_qp.c4
-rw-r--r--drivers/infiniband/hw/nes/nes.c3
-rw-r--r--drivers/infiniband/hw/nes/nes.h9
-rw-r--r--drivers/infiniband/hw/nes/nes_hw.c2
-rw-r--r--drivers/infiniband/hw/nes/nes_mgt.c8
-rw-r--r--drivers/infiniband/hw/nes/nes_nic.c2
-rw-r--r--drivers/infiniband/hw/nes/nes_verbs.c63
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_hw.c2
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_main.c74
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_stats.c3
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_verbs.c3
-rw-r--r--drivers/infiniband/hw/qedr/main.c73
-rw-r--r--drivers/infiniband/hw/qedr/qedr.h2
-rw-r--r--drivers/infiniband/hw/qedr/qedr_roce_cm.c4
-rw-r--r--drivers/infiniband/hw/qedr/verbs.c5
-rw-r--r--drivers/infiniband/hw/qib/qib.h2
-rw-r--r--drivers/infiniband/hw/qib/qib_pcie.c1
-rw-r--r--drivers/infiniband/hw/qib/qib_qp.c17
-rw-r--r--drivers/infiniband/hw/qib/qib_rc.c18
-rw-r--r--drivers/infiniband/hw/qib/qib_ruc.c342
-rw-r--r--drivers/infiniband/hw/qib/qib_sdma.c2
-rw-r--r--drivers/infiniband/hw/qib/qib_sysfs.c101
-rw-r--r--drivers/infiniband/hw/qib/qib_uc.c12
-rw-r--r--drivers/infiniband/hw/qib/qib_ud.c17
-rw-r--r--drivers/infiniband/hw/qib/qib_verbs.c47
-rw-r--r--drivers/infiniband/hw/qib/qib_verbs.h15
-rw-r--r--drivers/infiniband/hw/usnic/usnic_debugfs.c3
-rw-r--r--drivers/infiniband/hw/usnic/usnic_ib_main.c39
-rw-r--r--drivers/infiniband/hw/usnic/usnic_ib_sysfs.c74
-rw-r--r--drivers/infiniband/hw/usnic/usnic_ib_sysfs.h2
-rw-r--r--drivers/infiniband/hw/usnic/usnic_ib_verbs.c16
-rw-r--r--drivers/infiniband/hw/usnic/usnic_transport.c2
-rw-r--r--drivers/infiniband/hw/usnic/usnic_uiom.c91
-rw-r--r--drivers/infiniband/hw/usnic/usnic_uiom.h3
-rw-r--r--drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c46
-rw-r--r--drivers/infiniband/hw/vmw_pvrdma/pvrdma_qp.c2
-rw-r--r--drivers/infiniband/sw/rdmavt/Kconfig2
-rw-r--r--drivers/infiniband/sw/rdmavt/qp.c677
-rw-r--r--drivers/infiniband/sw/rdmavt/qp.h2
-rw-r--r--drivers/infiniband/sw/rdmavt/trace_tx.h42
-rw-r--r--drivers/infiniband/sw/rdmavt/vt.c15
-rw-r--r--drivers/infiniband/sw/rxe/rxe.c13
-rw-r--r--drivers/infiniband/sw/rxe/rxe_comp.c39
-rw-r--r--drivers/infiniband/sw/rxe/rxe_cq.c4
-rw-r--r--drivers/infiniband/sw/rxe/rxe_loc.h5
-rw-r--r--drivers/infiniband/sw/rxe/rxe_mr.c35
-rw-r--r--drivers/infiniband/sw/rxe/rxe_net.c49
-rw-r--r--drivers/infiniband/sw/rxe/rxe_param.h4
-rw-r--r--drivers/infiniband/sw/rxe/rxe_pool.c55
-rw-r--r--drivers/infiniband/sw/rxe/rxe_pool.h6
-rw-r--r--drivers/infiniband/sw/rxe/rxe_qp.c18
-rw-r--r--drivers/infiniband/sw/rxe/rxe_recv.c4
-rw-r--r--drivers/infiniband/sw/rxe/rxe_req.c17
-rw-r--r--drivers/infiniband/sw/rxe/rxe_resp.c10
-rw-r--r--drivers/infiniband/sw/rxe/rxe_srq.c10
-rw-r--r--drivers/infiniband/sw/rxe/rxe_sysfs.c2
-rw-r--r--drivers/infiniband/sw/rxe/rxe_verbs.c29
-rw-r--r--drivers/infiniband/sw/rxe/rxe_verbs.h4
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib.h8
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_cm.c8
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c168
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_netlink.c23
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_verbs.c2
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_vlan.c19
-rw-r--r--drivers/infiniband/ulp/iser/iser_initiator.c18
-rw-r--r--drivers/infiniband/ulp/iser/iser_verbs.c9
-rw-r--r--drivers/infiniband/ulp/isert/ib_isert.c2
-rw-r--r--drivers/infiniband/ulp/opa_vnic/opa_vnic_encap.c3
-rw-r--r--drivers/infiniband/ulp/opa_vnic/opa_vnic_vema.c3
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c19
-rw-r--r--drivers/infiniband/ulp/srpt/ib_srpt.c28
-rw-r--r--drivers/input/evdev.c1
-rw-r--r--drivers/input/joystick/xpad.c3
-rw-r--r--drivers/input/keyboard/hilkbd.c2
-rw-r--r--drivers/input/keyboard/sun4i-lradc-keys.c6
-rw-r--r--drivers/input/misc/uinput.c1
-rw-r--r--drivers/input/misc/xen-kbdfront.c2
-rw-r--r--drivers/input/mouse/cyapa_gen3.c4
-rw-r--r--drivers/input/mouse/elan_i2c_core.c1
-rw-r--r--drivers/input/mouse/synaptics.c4
-rw-r--r--drivers/input/mousedev.c1
-rw-r--r--drivers/input/serio/i8042.c29
-rw-r--r--drivers/input/serio/serport.c2
-rw-r--r--drivers/input/serio/xilinx_ps2.c2
-rw-r--r--drivers/input/touchscreen/atmel_mxt_ts.c3
-rw-r--r--drivers/input/touchscreen/elants_i2c.c7
-rw-r--r--drivers/input/touchscreen/of_touchscreen.c36
-rw-r--r--drivers/input/touchscreen/silead.c13
-rw-r--r--drivers/input/touchscreen/st1232.c1
-rw-r--r--drivers/input/touchscreen/ti_am335x_tsc.c22
-rw-r--r--drivers/input/touchscreen/tsc200x-core.c3
-rw-r--r--drivers/input/touchscreen/wm97xx-core.c3
-rw-r--r--drivers/iommu/Kconfig21
-rw-r--r--drivers/iommu/Makefile1
-rw-r--r--drivers/iommu/amd_iommu.c4
-rw-r--r--drivers/iommu/amd_iommu_init.c16
-rw-r--r--drivers/iommu/amd_iommu_v2.c1
-rw-r--r--drivers/iommu/arm-smmu-v3.c140
-rw-r--r--drivers/iommu/arm-smmu.c106
-rw-r--r--drivers/iommu/dma-iommu.c55
-rw-r--r--drivers/iommu/fsl_pamu.c2
-rw-r--r--drivers/iommu/fsl_pamu_domain.c119
-rw-r--r--drivers/iommu/intel-iommu-debugfs.c314
-rw-r--r--drivers/iommu/intel-iommu.c36
-rw-r--r--drivers/iommu/intel-svm.c1
-rw-r--r--drivers/iommu/intel_irq_remapping.c2
-rw-r--r--drivers/iommu/io-pgtable-arm-v7s.c11
-rw-r--r--drivers/iommu/io-pgtable-arm.c23
-rw-r--r--drivers/iommu/io-pgtable.h5
-rw-r--r--drivers/iommu/iommu.c58
-rw-r--r--drivers/iommu/iova.c22
-rw-r--r--drivers/iommu/ipmmu-vmsa.c5
-rw-r--r--drivers/iommu/mtk_iommu.c2
-rw-r--r--drivers/iommu/mtk_iommu_v1.c2
-rw-r--r--drivers/iommu/of_iommu.c25
-rw-r--r--drivers/irqchip/Kconfig20
-rw-r--r--drivers/irqchip/Makefile3
-rw-r--r--drivers/irqchip/irq-csky-apb-intc.c274
-rw-r--r--drivers/irqchip/irq-csky-mpintc.c198
-rw-r--r--drivers/irqchip/irq-gic-v3-its.c249
-rw-r--r--drivers/irqchip/irq-gic-v3.c85
-rw-r--r--drivers/irqchip/irq-mvebu-icu.c253
-rw-r--r--drivers/irqchip/irq-mvebu-sei.c507
-rw-r--r--drivers/irqchip/irq-sifive-plic.c10
-rw-r--r--drivers/irqchip/qcom-pdc.c1
-rw-r--r--drivers/isdn/capi/capi.c7
-rw-r--r--drivers/isdn/gigaset/asyncdata.c4
-rw-r--r--drivers/isdn/gigaset/ev-layer.c4
-rw-r--r--drivers/isdn/gigaset/interface.c13
-rw-r--r--drivers/isdn/gigaset/isocdata.c2
-rw-r--r--drivers/isdn/hisax/amd7930_fn.c2
-rw-r--r--drivers/isdn/hisax/hfc_pci.c11
-rw-r--r--drivers/isdn/hisax/hfc_pci.h4
-rw-r--r--drivers/isdn/hisax/hfc_sx.c6
-rw-r--r--drivers/isdn/hisax/hisax.h2
-rw-r--r--drivers/isdn/hisax/w6692.c4
-rw-r--r--drivers/isdn/i4l/isdn_tty.c19
-rw-r--r--drivers/isdn/mISDN/l1oip_core.c3
-rw-r--r--drivers/isdn/mISDN/socket.c3
-rw-r--r--drivers/isdn/mISDN/tei.c7
-rw-r--r--drivers/leds/Kconfig10
-rw-r--r--drivers/leds/Makefile1
-rw-r--r--drivers/leds/leds-an30259a.c368
-rw-r--r--drivers/leds/leds-as3645a.c4
-rw-r--r--drivers/leds/leds-gpio.c94
-rw-r--r--drivers/leds/leds-pwm.c5
-rw-r--r--drivers/leds/leds-sc27xx-bltc.c121
-rw-r--r--drivers/leds/trigger/Kconfig7
-rw-r--r--drivers/leds/trigger/Makefile1
-rw-r--r--drivers/leds/trigger/ledtrig-pattern.c400
-rw-r--r--drivers/lightnvm/Kconfig3
-rw-r--r--drivers/lightnvm/core.c334
-rw-r--r--drivers/lightnvm/pblk-cache.c1
-rw-r--r--drivers/lightnvm/pblk-core.c587
-rw-r--r--drivers/lightnvm/pblk-gc.c11
-rw-r--r--drivers/lightnvm/pblk-init.c321
-rw-r--r--drivers/lightnvm/pblk-map.c13
-rw-r--r--drivers/lightnvm/pblk-rb.c110
-rw-r--r--drivers/lightnvm/pblk-read.c86
-rw-r--r--drivers/lightnvm/pblk-recovery.c471
-rw-r--r--drivers/lightnvm/pblk-rl.c5
-rw-r--r--drivers/lightnvm/pblk-sysfs.c12
-rw-r--r--drivers/lightnvm/pblk-trace.h145
-rw-r--r--drivers/lightnvm/pblk-write.c90
-rw-r--r--drivers/lightnvm/pblk.h221
-rw-r--r--drivers/macintosh/adb-iop.c50
-rw-r--r--drivers/macintosh/adb.c8
-rw-r--r--drivers/macintosh/adbhid.c53
-rw-r--r--drivers/macintosh/macio_asic.c8
-rw-r--r--drivers/macintosh/macio_sysfs.c8
-rw-r--r--drivers/macintosh/smu.c7
-rw-r--r--drivers/macintosh/via-cuda.c35
-rw-r--r--drivers/macintosh/via-macii.c352
-rw-r--r--drivers/macintosh/via-pmu.c33
-rw-r--r--drivers/macintosh/windfarm_smu_controls.c4
-rw-r--r--drivers/macintosh/windfarm_smu_sat.c25
-rw-r--r--drivers/mailbox/Kconfig8
-rw-r--r--drivers/mailbox/bcm-flexrm-mailbox.c6
-rw-r--r--drivers/mailbox/mtk-cmdq-mailbox.c3
-rw-r--r--drivers/mailbox/pcc.c7
-rw-r--r--drivers/mailbox/qcom-apcs-ipc-mailbox.c1
-rw-r--r--drivers/mailbox/ti-msgmgr.c4
-rw-r--r--drivers/md/Kconfig11
-rw-r--r--drivers/md/bcache/alloc.c2
-rw-r--r--drivers/md/bcache/bcache.h2
-rw-r--r--drivers/md/bcache/btree.c2
-rw-r--r--drivers/md/bcache/closure.h3
-rw-r--r--drivers/md/bcache/debug.c2
-rw-r--r--drivers/md/bcache/extents.c2
-rw-r--r--drivers/md/bcache/request.c9
-rw-r--r--drivers/md/bcache/request.h2
-rw-r--r--drivers/md/bcache/super.c113
-rw-r--r--drivers/md/bcache/sysfs.c2
-rw-r--r--drivers/md/dm-cache-metadata.c4
-rw-r--r--drivers/md/dm-cache-policy-smq.c2
-rw-r--r--drivers/md/dm-cache-target.c14
-rw-r--r--drivers/md/dm-core.h10
-rw-r--r--drivers/md/dm-crypt.c15
-rw-r--r--drivers/md/dm-flakey.c32
-rw-r--r--drivers/md/dm-integrity.c26
-rw-r--r--drivers/md/dm-ioctl.c18
-rw-r--r--drivers/md/dm-linear.c37
-rw-r--r--drivers/md/dm-mpath.c40
-rw-r--r--drivers/md/dm-raid.c4
-rw-r--r--drivers/md/dm-rq.c316
-rw-r--r--drivers/md/dm-rq.h4
-rw-r--r--drivers/md/dm-sysfs.c3
-rw-r--r--drivers/md/dm-table.c56
-rw-r--r--drivers/md/dm-thin-metadata.c6
-rw-r--r--drivers/md/dm-thin.c8
-rw-r--r--drivers/md/dm-verity-fec.c5
-rw-r--r--drivers/md/dm-writecache.c5
-rw-r--r--drivers/md/dm-zoned-metadata.c80
-rw-r--r--drivers/md/dm-zoned-target.c23
-rw-r--r--drivers/md/dm.c179
-rw-r--r--drivers/md/dm.h1
-rw-r--r--drivers/md/md-bitmap.c9
-rw-r--r--drivers/md/md-cluster.c234
-rw-r--r--drivers/md/md-cluster.h2
-rw-r--r--drivers/md/md.c113
-rw-r--r--drivers/md/md.h1
-rw-r--r--drivers/md/raid1.c1
-rw-r--r--drivers/md/raid10.c109
-rw-r--r--drivers/md/raid5-cache.c2
-rw-r--r--drivers/md/raid5.c12
-rw-r--r--drivers/media/Makefile3
-rw-r--r--drivers/media/cec/Makefile2
-rw-r--r--drivers/media/cec/cec-adap.c107
-rw-r--r--drivers/media/cec/cec-api.c24
-rw-r--r--drivers/media/cec/cec-core.c8
-rw-r--r--drivers/media/cec/cec-edid.c155
-rw-r--r--drivers/media/cec/cec-pin.c20
-rw-r--r--drivers/media/common/b2c2/flexcop-i2c.c12
-rw-r--r--drivers/media/common/cx2341x.c2
-rw-r--r--drivers/media/common/saa7146/saa7146_fops.c2
-rw-r--r--drivers/media/common/saa7146/saa7146_video.c8
-rw-r--r--drivers/media/common/siano/smscoreapi.c4
-rw-r--r--drivers/media/common/siano/smsir.c10
-rw-r--r--drivers/media/common/v4l2-tpg/v4l2-tpg-colors.c262
-rw-r--r--drivers/media/common/v4l2-tpg/v4l2-tpg-core.c41
-rw-r--r--drivers/media/common/videobuf2/videobuf2-core.c269
-rw-r--r--drivers/media/common/videobuf2/videobuf2-v4l2.c528
-rw-r--r--drivers/media/dvb-core/dmxdev.c1
-rw-r--r--drivers/media/dvb-core/dvb_frontend.c2
-rw-r--r--drivers/media/dvb-core/dvb_vb2.c7
-rw-r--r--drivers/media/dvb-core/dvbdev.c23
-rw-r--r--drivers/media/dvb-frontends/Kconfig10
-rw-r--r--drivers/media/dvb-frontends/Makefile1
-rw-r--r--drivers/media/dvb-frontends/au8522_decoder.c10
-rw-r--r--drivers/media/dvb-frontends/au8522_priv.h9
-rw-r--r--drivers/media/dvb-frontends/cx24123.c2
-rw-r--r--drivers/media/dvb-frontends/cxd2099.c3
-rw-r--r--drivers/media/dvb-frontends/cxd2099.h1
-rw-r--r--drivers/media/dvb-frontends/cxd2820r_core.c2
-rw-r--r--drivers/media/dvb-frontends/dibx000_common.c2
-rw-r--r--drivers/media/dvb-frontends/drx39xyj/drxj.c10
-rw-r--r--drivers/media/dvb-frontends/lgdt330x.c2
-rw-r--r--drivers/media/dvb-frontends/lnbh29.c168
-rw-r--r--drivers/media/dvb-frontends/lnbh29.h36
-rw-r--r--drivers/media/dvb-frontends/m88ds3103.c2
-rw-r--r--drivers/media/dvb-frontends/mt312.c9
-rw-r--r--drivers/media/dvb-frontends/mxl5xx.c5
-rw-r--r--drivers/media/dvb-frontends/mxl5xx.h22
-rw-r--r--drivers/media/dvb-frontends/mxl5xx_defs.h1
-rw-r--r--drivers/media/dvb-frontends/mxl5xx_regs.h1
-rw-r--r--drivers/media/dvb-frontends/rtl2832_sdr.c15
-rw-r--r--drivers/media/dvb-frontends/s5h1420.c2
-rw-r--r--drivers/media/dvb-frontends/stv0910.c3
-rw-r--r--drivers/media/dvb-frontends/stv0910.h18
-rw-r--r--drivers/media/dvb-frontends/stv0910_regs.h1
-rw-r--r--drivers/media/dvb-frontends/stv6111.c4
-rw-r--r--drivers/media/dvb-frontends/stv6111.h16
-rw-r--r--drivers/media/dvb-frontends/tc90522.c2
-rw-r--r--drivers/media/dvb-frontends/ts2020.c2
-rw-r--r--drivers/media/dvb-frontends/zd1301_demod.c3
-rw-r--r--drivers/media/dvb-frontends/zl10039.c5
-rw-r--r--drivers/media/firewire/firedtv-fe.c2
-rw-r--r--drivers/media/i2c/Kconfig24
-rw-r--r--drivers/media/i2c/Makefile2
-rw-r--r--drivers/media/i2c/ad5820.c2
-rw-r--r--drivers/media/i2c/adv7180.c13
-rw-r--r--drivers/media/i2c/adv748x/adv748x-afe.c8
-rw-r--r--drivers/media/i2c/adv748x/adv748x-core.c93
-rw-r--r--drivers/media/i2c/adv748x/adv748x-csi2.c35
-rw-r--r--drivers/media/i2c/adv748x/adv748x-hdmi.c8
-rw-r--r--drivers/media/i2c/adv748x/adv748x.h25
-rw-r--r--drivers/media/i2c/adv7511.c8
-rw-r--r--drivers/media/i2c/adv7604.c14
-rw-r--r--drivers/media/i2c/adv7842.c19
-rw-r--r--drivers/media/i2c/ak881x.c1
-rw-r--r--drivers/media/i2c/cs53l32a.c2
-rw-r--r--drivers/media/i2c/cx25840/cx25840-ir.c6
-rw-r--r--drivers/media/i2c/dw9714.c5
-rw-r--r--drivers/media/i2c/dw9807-vcm.c4
-rw-r--r--drivers/media/i2c/imx274.c165
-rw-r--r--drivers/media/i2c/imx319.c2560
-rw-r--r--drivers/media/i2c/imx355.c1860
-rw-r--r--drivers/media/i2c/lm3560.c3
-rw-r--r--drivers/media/i2c/lm3646.c3
-rw-r--r--drivers/media/i2c/m5mols/m5mols_core.c3
-rw-r--r--drivers/media/i2c/max2175.c12
-rw-r--r--drivers/media/i2c/max2175.h12
-rw-r--r--drivers/media/i2c/msp3400-driver.c8
-rw-r--r--drivers/media/i2c/msp3400-driver.h8
-rw-r--r--drivers/media/i2c/mt9m111.c1
-rw-r--r--drivers/media/i2c/mt9t112.c6
-rw-r--r--drivers/media/i2c/mt9v032.c2
-rw-r--r--drivers/media/i2c/noon010pc30.c3
-rw-r--r--drivers/media/i2c/ov13858.c12
-rw-r--r--drivers/media/i2c/ov2640.c1
-rw-r--r--drivers/media/i2c/ov2659.c14
-rw-r--r--drivers/media/i2c/ov2680.c16
-rw-r--r--drivers/media/i2c/ov2685.c2
-rw-r--r--drivers/media/i2c/ov5640.c309
-rw-r--r--drivers/media/i2c/ov5645.c2
-rw-r--r--drivers/media/i2c/ov5647.c2
-rw-r--r--drivers/media/i2c/ov5670.c12
-rw-r--r--drivers/media/i2c/ov5695.c2
-rw-r--r--drivers/media/i2c/ov6650.c1
-rw-r--r--drivers/media/i2c/ov7251.c4
-rw-r--r--drivers/media/i2c/ov7670.c29
-rw-r--r--drivers/media/i2c/ov772x.c194
-rw-r--r--drivers/media/i2c/ov7740.c2
-rw-r--r--drivers/media/i2c/ov9650.c161
-rw-r--r--drivers/media/i2c/rj54n1cb0c.c1
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3-core.c9
-rw-r--r--drivers/media/i2c/s5k4ecgx.c3
-rw-r--r--drivers/media/i2c/s5k5baf.c6
-rw-r--r--drivers/media/i2c/s5k6aa.c5
-rw-r--r--drivers/media/i2c/saa7115.c24
-rw-r--r--drivers/media/i2c/saa7127.c4
-rw-r--r--drivers/media/i2c/smiapp/smiapp-core.c48
-rw-r--r--drivers/media/i2c/soc_camera/Makefile18
-rw-r--r--drivers/media/i2c/soc_camera/soc_mt9m001.c (renamed from drivers/media/i2c/soc_camera/mt9m001.c)1
-rw-r--r--drivers/media/i2c/soc_camera/soc_mt9t112.c (renamed from drivers/media/i2c/soc_camera/mt9t112.c)6
-rw-r--r--drivers/media/i2c/soc_camera/soc_mt9v022.c (renamed from drivers/media/i2c/soc_camera/mt9v022.c)1
-rw-r--r--drivers/media/i2c/soc_camera/soc_ov5642.c (renamed from drivers/media/i2c/soc_camera/ov5642.c)3
-rw-r--r--drivers/media/i2c/soc_camera/soc_ov772x.c (renamed from drivers/media/i2c/soc_camera/ov772x.c)1
-rw-r--r--drivers/media/i2c/soc_camera/soc_ov9640.c (renamed from drivers/media/i2c/soc_camera/ov9640.c)1
-rw-r--r--drivers/media/i2c/soc_camera/soc_ov9740.c (renamed from drivers/media/i2c/soc_camera/ov9740.c)1
-rw-r--r--drivers/media/i2c/soc_camera/soc_rj54n1cb0c.c (renamed from drivers/media/i2c/soc_camera/rj54n1cb0c.c)1
-rw-r--r--drivers/media/i2c/soc_camera/soc_tw9910.c (renamed from drivers/media/i2c/soc_camera/tw9910.c)0
-rw-r--r--drivers/media/i2c/sr030pc30.c3
-rw-r--r--drivers/media/i2c/tc358743.c36
-rw-r--r--drivers/media/i2c/tda1997x.c6
-rw-r--r--drivers/media/i2c/tvaudio.c2
-rw-r--r--drivers/media/i2c/tvp514x.c2
-rw-r--r--drivers/media/i2c/tvp5150.c560
-rw-r--r--drivers/media/i2c/tvp5150_reg.h3
-rw-r--r--drivers/media/i2c/tvp7002.c2
-rw-r--r--drivers/media/i2c/video-i2c.c8
-rw-r--r--drivers/media/media-device.c52
-rw-r--r--drivers/media/media-entity.c26
-rw-r--r--drivers/media/media-request.c501
-rw-r--r--drivers/media/pci/bt8xx/bttv-driver.c13
-rw-r--r--drivers/media/pci/bt8xx/bttv-i2c.c6
-rw-r--r--drivers/media/pci/bt8xx/bttv-input.c4
-rw-r--r--drivers/media/pci/bt8xx/dvb-bt8xx.c3
-rw-r--r--drivers/media/pci/cobalt/cobalt-alsa-main.c2
-rw-r--r--drivers/media/pci/cobalt/cobalt-alsa-pcm.c4
-rw-r--r--drivers/media/pci/cobalt/cobalt-v4l2.c23
-rw-r--r--drivers/media/pci/cx18/cx18-alsa-main.c2
-rw-r--r--drivers/media/pci/cx18/cx18-alsa-pcm.c2
-rw-r--r--drivers/media/pci/cx18/cx18-cards.c8
-rw-r--r--drivers/media/pci/cx18/cx18-driver.c4
-rw-r--r--drivers/media/pci/cx18/cx18-i2c.c2
-rw-r--r--drivers/media/pci/cx18/cx18-ioctl.c8
-rw-r--r--drivers/media/pci/cx23885/altera-ci.c10
-rw-r--r--drivers/media/pci/cx23885/cx23885-417.c10
-rw-r--r--drivers/media/pci/cx23885/cx23885-alsa.c4
-rw-r--r--drivers/media/pci/cx23885/cx23885-dvb.c54
-rw-r--r--drivers/media/pci/cx23885/cx23885-i2c.c6
-rw-r--r--drivers/media/pci/cx23885/cx23885-ioctl.c4
-rw-r--r--drivers/media/pci/cx23885/cx23885-video.c15
-rw-r--r--drivers/media/pci/cx23885/cx23888-ir.c6
-rw-r--r--drivers/media/pci/cx25821/cx25821-alsa.c8
-rw-r--r--drivers/media/pci/cx25821/cx25821-i2c.c2
-rw-r--r--drivers/media/pci/cx25821/cx25821-video.c10
-rw-r--r--drivers/media/pci/cx88/cx88-alsa.c6
-rw-r--r--drivers/media/pci/cx88/cx88-blackbird.c8
-rw-r--r--drivers/media/pci/cx88/cx88-cards.c2
-rw-r--r--drivers/media/pci/cx88/cx88-i2c.c4
-rw-r--r--drivers/media/pci/cx88/cx88-input.c7
-rw-r--r--drivers/media/pci/cx88/cx88-video.c14
-rw-r--r--drivers/media/pci/cx88/cx88-vp3054-i2c.c2
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-ci.c4
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-ci.h4
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-core.c6
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-hw.c2
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-hw.h2
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-i2c.c2
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-i2c.h4
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-io.h2
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-main.c4
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-max.c2
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-max.h2
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-regs.h5
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-sx8.c4
-rw-r--r--drivers/media/pci/ddbridge/ddbridge.h5
-rw-r--r--drivers/media/pci/dm1105/dm1105.c5
-rw-r--r--drivers/media/pci/dt3155/dt3155.c8
-rw-r--r--drivers/media/pci/intel/ipu3/ipu3-cio2.c30
-rw-r--r--drivers/media/pci/ivtv/ivtv-alsa-main.c2
-rw-r--r--drivers/media/pci/ivtv/ivtv-alsa-pcm.c2
-rw-r--r--drivers/media/pci/ivtv/ivtv-cards.c12
-rw-r--r--drivers/media/pci/ivtv/ivtv-i2c.c6
-rw-r--r--drivers/media/pci/ivtv/ivtv-ioctl.c42
-rw-r--r--drivers/media/pci/ivtv/ivtv-streams.c9
-rw-r--r--drivers/media/pci/ivtv/ivtv-yuv.c2
-rw-r--r--drivers/media/pci/ivtv/ivtvfb.c2
-rw-r--r--drivers/media/pci/meye/meye.c12
-rw-r--r--drivers/media/pci/ngene/ngene-i2c.c2
-rw-r--r--drivers/media/pci/pluto2/pluto2.c2
-rw-r--r--drivers/media/pci/pt1/pt1.c2
-rw-r--r--drivers/media/pci/pt3/pt3.c2
-rw-r--r--drivers/media/pci/saa7134/saa7134-alsa.c8
-rw-r--r--drivers/media/pci/saa7134/saa7134-cards.c15
-rw-r--r--drivers/media/pci/saa7134/saa7134-core.c9
-rw-r--r--drivers/media/pci/saa7134/saa7134-empress.c6
-rw-r--r--drivers/media/pci/saa7134/saa7134-go7007.c2
-rw-r--r--drivers/media/pci/saa7134/saa7134-i2c.c2
-rw-r--r--drivers/media/pci/saa7134/saa7134-input.c2
-rw-r--r--drivers/media/pci/saa7134/saa7134-video.c17
-rw-r--r--drivers/media/pci/saa7134/saa7134.h8
-rw-r--r--drivers/media/pci/saa7146/mxb.c2
-rw-r--r--drivers/media/pci/saa7164/saa7164-core.c2
-rw-r--r--drivers/media/pci/saa7164/saa7164-dvb.c10
-rw-r--r--drivers/media/pci/saa7164/saa7164-encoder.c10
-rw-r--r--drivers/media/pci/saa7164/saa7164-i2c.c2
-rw-r--r--drivers/media/pci/saa7164/saa7164-vbi.c4
-rw-r--r--drivers/media/pci/smipcie/smipcie-main.c12
-rw-r--r--drivers/media/pci/solo6x10/solo6x10-g723.c8
-rw-r--r--drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c12
-rw-r--r--drivers/media/pci/solo6x10/solo6x10-v4l2.c6
-rw-r--r--drivers/media/pci/sta2x11/sta2x11_vip.c6
-rw-r--r--drivers/media/pci/ttpci/av7110.c3
-rw-r--r--drivers/media/pci/ttpci/av7110_av.c58
-rw-r--r--drivers/media/pci/ttpci/av7110_v4l.c2
-rw-r--r--drivers/media/pci/ttpci/budget-core.c6
-rw-r--r--drivers/media/pci/tw5864/tw5864-video.c2
-rw-r--r--drivers/media/pci/tw68/tw68-video.c6
-rw-r--r--drivers/media/pci/tw686x/tw686x-audio.c8
-rw-r--r--drivers/media/pci/tw686x/tw686x-video.c4
-rw-r--r--drivers/media/platform/Kconfig10
-rw-r--r--drivers/media/platform/Makefile2
-rw-r--r--drivers/media/platform/am437x/am437x-vpfe.c93
-rw-r--r--drivers/media/platform/atmel/atmel-isc.c26
-rw-r--r--drivers/media/platform/atmel/atmel-isi.c29
-rw-r--r--drivers/media/platform/cadence/cdns-csi2rx.c32
-rw-r--r--drivers/media/platform/cadence/cdns-csi2tx.c4
-rw-r--r--drivers/media/platform/coda/coda-common.c14
-rw-r--r--drivers/media/platform/davinci/isif.c3
-rw-r--r--drivers/media/platform/davinci/vpbe_display.c10
-rw-r--r--drivers/media/platform/davinci/vpbe_venc.c2
-rw-r--r--drivers/media/platform/davinci/vpfe_capture.c6
-rw-r--r--drivers/media/platform/davinci/vpif_capture.c88
-rw-r--r--drivers/media/platform/davinci/vpif_display.c29
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-core.c2
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-m2m.c4
-rw-r--r--drivers/media/platform/exynos4-is/common.c4
-rw-r--r--drivers/media/platform/exynos4-is/fimc-capture.c4
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is-i2c.c2
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is.c2
-rw-r--r--drivers/media/platform/exynos4-is/fimc-isp-video.c2
-rw-r--r--drivers/media/platform/exynos4-is/fimc-lite.c6
-rw-r--r--drivers/media/platform/exynos4-is/media-dev.c42
-rw-r--r--drivers/media/platform/exynos4-is/media-dev.h1
-rw-r--r--drivers/media/platform/exynos4-is/mipi-csis.c2
-rw-r--r--drivers/media/platform/fsl-viu.c8
-rw-r--r--drivers/media/platform/imx-pxp.c1754
-rw-r--r--drivers/media/platform/imx-pxp.h1685
-rw-r--r--drivers/media/platform/m2m-deinterlace.c8
-rw-r--r--drivers/media/platform/marvell-ccic/cafe-driver.c2
-rw-r--r--drivers/media/platform/marvell-ccic/mcam-core.c16
-rw-r--r--drivers/media/platform/marvell-ccic/mmp-driver.c4
-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.c6
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c6
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c5
-rw-r--r--drivers/media/platform/mtk-vpu/mtk_vpu.c7
-rw-r--r--drivers/media/platform/mx2_emmaprp.c2
-rw-r--r--drivers/media/platform/omap/omap_vout.c10
-rw-r--r--drivers/media/platform/omap3isp/isp.c5
-rw-r--r--drivers/media/platform/omap3isp/ispccdc.c2
-rw-r--r--drivers/media/platform/omap3isp/ispccp2.c2
-rw-r--r--drivers/media/platform/omap3isp/ispcsi2.c2
-rw-r--r--drivers/media/platform/omap3isp/isppreview.c2
-rw-r--r--drivers/media/platform/omap3isp/ispresizer.c2
-rw-r--r--drivers/media/platform/omap3isp/ispvideo.c12
-rw-r--r--drivers/media/platform/pxa_camera.c39
-rw-r--r--drivers/media/platform/qcom/camss/camss-video.c8
-rw-r--r--drivers/media/platform/qcom/camss/camss.c91
-rw-r--r--drivers/media/platform/qcom/camss/camss.h3
-rw-r--r--drivers/media/platform/qcom/venus/helpers.c2
-rw-r--r--drivers/media/platform/qcom/venus/vdec.c11
-rw-r--r--drivers/media/platform/qcom/venus/venc.c8
-rw-r--r--drivers/media/platform/rcar-vin/rcar-core.c13
-rw-r--r--drivers/media/platform/rcar-vin/rcar-csi2.c26
-rw-r--r--drivers/media/platform/rcar-vin/rcar-v4l2.c8
-rw-r--r--drivers/media/platform/rcar_drif.c24
-rw-r--r--drivers/media/platform/rcar_fdp1.c6
-rw-r--r--drivers/media/platform/rcar_jpu.c10
-rw-r--r--drivers/media/platform/renesas-ceu.c78
-rw-r--r--drivers/media/platform/rockchip/rga/rga.c6
-rw-r--r--drivers/media/platform/s3c-camif/camif-capture.c14
-rw-r--r--drivers/media/platform/s3c-camif/camif-core.c4
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-core.c10
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_dec.c10
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_enc.c10
-rw-r--r--drivers/media/platform/sh_veu.c9
-rw-r--r--drivers/media/platform/sh_vou.c10
-rw-r--r--drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c6
-rw-r--r--drivers/media/platform/soc_camera/soc_camera.c50
-rw-r--r--drivers/media/platform/soc_camera/soc_camera_platform.c2
-rw-r--r--drivers/media/platform/soc_camera/soc_mediabus.c2
-rw-r--r--drivers/media/platform/soc_camera/soc_scale_crop.c2
-rw-r--r--drivers/media/platform/sti/bdisp/bdisp-v4l2.c4
-rw-r--r--drivers/media/platform/sti/delta/delta-v4l2.c4
-rw-r--r--drivers/media/platform/sti/hva/hva-v4l2.c4
-rw-r--r--drivers/media/platform/stm32/stm32-dcmi.c43
-rw-r--r--drivers/media/platform/ti-vpe/cal.c61
-rw-r--r--drivers/media/platform/via-camera.c10
-rw-r--r--drivers/media/platform/vicodec/Kconfig2
-rw-r--r--drivers/media/platform/vicodec/Makefile2
-rw-r--r--drivers/media/platform/vicodec/codec-fwht.c (renamed from drivers/media/platform/vicodec/vicodec-codec.c)160
-rw-r--r--drivers/media/platform/vicodec/codec-fwht.h (renamed from drivers/media/platform/vicodec/vicodec-codec.h)82
-rw-r--r--drivers/media/platform/vicodec/codec-v4l2-fwht.c332
-rw-r--r--drivers/media/platform/vicodec/codec-v4l2-fwht.h47
-rw-r--r--drivers/media/platform/vicodec/vicodec-core.c520
-rw-r--r--drivers/media/platform/video-mux.c38
-rw-r--r--drivers/media/platform/vim2m.c52
-rw-r--r--drivers/media/platform/vimc/vimc-capture.c6
-rw-r--r--drivers/media/platform/vimc/vimc-common.c2
-rw-r--r--drivers/media/platform/vimc/vimc-core.c4
-rw-r--r--drivers/media/platform/vimc/vimc-sensor.c20
-rw-r--r--drivers/media/platform/vivid/vivid-cec.c4
-rw-r--r--drivers/media/platform/vivid/vivid-core.c78
-rw-r--r--drivers/media/platform/vivid/vivid-core.h10
-rw-r--r--drivers/media/platform/vivid/vivid-ctrls.c52
-rw-r--r--drivers/media/platform/vivid/vivid-kthread-cap.c12
-rw-r--r--drivers/media/platform/vivid/vivid-kthread-out.c12
-rw-r--r--drivers/media/platform/vivid/vivid-osd.c2
-rw-r--r--drivers/media/platform/vivid/vivid-radio-common.c4
-rw-r--r--drivers/media/platform/vivid/vivid-radio-rx.c2
-rw-r--r--drivers/media/platform/vivid/vivid-radio-tx.c2
-rw-r--r--drivers/media/platform/vivid/vivid-rds-gen.c4
-rw-r--r--drivers/media/platform/vivid/vivid-sdr-cap.c20
-rw-r--r--drivers/media/platform/vivid/vivid-vbi-cap.c10
-rw-r--r--drivers/media/platform/vivid/vivid-vbi-out.c10
-rw-r--r--drivers/media/platform/vivid/vivid-vid-cap.c21
-rw-r--r--drivers/media/platform/vivid/vivid-vid-common.c30
-rw-r--r--drivers/media/platform/vivid/vivid-vid-out.c12
-rw-r--r--drivers/media/platform/vsp1/vsp1_brx.c4
-rw-r--r--drivers/media/platform/vsp1/vsp1_drm.c11
-rw-r--r--drivers/media/platform/vsp1/vsp1_drv.c8
-rw-r--r--drivers/media/platform/vsp1/vsp1_entity.c2
-rw-r--r--drivers/media/platform/vsp1/vsp1_histo.c4
-rw-r--r--drivers/media/platform/vsp1/vsp1_lif.c29
-rw-r--r--drivers/media/platform/vsp1/vsp1_regs.h2
-rw-r--r--drivers/media/platform/vsp1/vsp1_rpf.c4
-rw-r--r--drivers/media/platform/vsp1/vsp1_sru.c7
-rw-r--r--drivers/media/platform/vsp1/vsp1_uds.c14
-rw-r--r--drivers/media/platform/vsp1/vsp1_video.c13
-rw-r--r--drivers/media/platform/vsp1/vsp1_wpf.c2
-rw-r--r--drivers/media/platform/xilinx/xilinx-dma.c14
-rw-r--r--drivers/media/platform/xilinx/xilinx-tpg.c2
-rw-r--r--drivers/media/platform/xilinx/xilinx-vipp.c175
-rw-r--r--drivers/media/platform/xilinx/xilinx-vipp.h4
-rw-r--r--drivers/media/radio/dsbr100.c9
-rw-r--r--drivers/media/radio/radio-cadet.c12
-rw-r--r--drivers/media/radio/radio-isa.c10
-rw-r--r--drivers/media/radio/radio-keene.c8
-rw-r--r--drivers/media/radio/radio-ma901.c8
-rw-r--r--drivers/media/radio/radio-maxiradio.c2
-rw-r--r--drivers/media/radio/radio-miropcm20.c10
-rw-r--r--drivers/media/radio/radio-mr800.c8
-rw-r--r--drivers/media/radio/radio-raremono.c8
-rw-r--r--drivers/media/radio/radio-sf16fmi.c12
-rw-r--r--drivers/media/radio/radio-sf16fmr2.c6
-rw-r--r--drivers/media/radio/radio-shark.c2
-rw-r--r--drivers/media/radio/radio-shark2.c2
-rw-r--r--drivers/media/radio/radio-si476x.c12
-rw-r--r--drivers/media/radio/radio-tea5764.c6
-rw-r--r--drivers/media/radio/radio-tea5777.c12
-rw-r--r--drivers/media/radio/radio-timb.c8
-rw-r--r--drivers/media/radio/radio-wl1273.c12
-rw-r--r--drivers/media/radio/si470x/radio-si470x-common.c2
-rw-r--r--drivers/media/radio/si470x/radio-si470x-i2c.c4
-rw-r--r--drivers/media/radio/si470x/radio-si470x-usb.c4
-rw-r--r--drivers/media/radio/si4713/radio-platform-si4713.c6
-rw-r--r--drivers/media/radio/si4713/radio-usb-si4713.c6
-rw-r--r--drivers/media/radio/tea575x.c10
-rw-r--r--drivers/media/radio/tef6862.c2
-rw-r--r--drivers/media/radio/wl128x/fmdrv_v4l2.c13
-rw-r--r--drivers/media/rc/ati_remote.c2
-rw-r--r--drivers/media/rc/ene_ir.c12
-rw-r--r--drivers/media/rc/fintek-cir.c3
-rw-r--r--drivers/media/rc/igorplugusb.c2
-rw-r--r--drivers/media/rc/iguanair.c4
-rw-r--r--drivers/media/rc/imon_raw.c2
-rw-r--r--drivers/media/rc/ir-hix5hd2.c2
-rw-r--r--drivers/media/rc/ir-imon-decoder.c62
-rw-r--r--drivers/media/rc/ir-mce_kbd-decoder.c77
-rw-r--r--drivers/media/rc/ir-rc6-decoder.c9
-rw-r--r--drivers/media/rc/ite-cir.c5
-rw-r--r--drivers/media/rc/keymaps/rc-behold.c2
-rw-r--r--drivers/media/rc/keymaps/rc-delock-61959.c2
-rw-r--r--drivers/media/rc/keymaps/rc-imon-rsc.c2
-rw-r--r--drivers/media/rc/keymaps/rc-it913x-v1.c2
-rw-r--r--drivers/media/rc/keymaps/rc-it913x-v2.c2
-rw-r--r--drivers/media/rc/keymaps/rc-msi-digivox-iii.c2
-rw-r--r--drivers/media/rc/keymaps/rc-pixelview-002t.c2
-rw-r--r--drivers/media/rc/keymaps/rc-pixelview-mk12.c2
-rw-r--r--drivers/media/rc/keymaps/rc-reddo.c2
-rw-r--r--drivers/media/rc/keymaps/rc-terratec-slim.c2
-rw-r--r--drivers/media/rc/keymaps/rc-tivo.c2
-rw-r--r--drivers/media/rc/keymaps/rc-total-media-in-hand.c2
-rw-r--r--drivers/media/rc/mceusb.c17
-rw-r--r--drivers/media/rc/meson-ir.c2
-rw-r--r--drivers/media/rc/mtk-cir.c2
-rw-r--r--drivers/media/rc/nuvoton-cir.c2
-rw-r--r--drivers/media/rc/rc-core-priv.h12
-rw-r--r--drivers/media/rc/rc-ir-raw.c12
-rw-r--r--drivers/media/rc/rc-loopback.c2
-rw-r--r--drivers/media/rc/rc-main.c20
-rw-r--r--drivers/media/rc/redrat3.c10
-rw-r--r--drivers/media/rc/serial_ir.c10
-rw-r--r--drivers/media/rc/sir_ir.c2
-rw-r--r--drivers/media/rc/st_rc.c5
-rw-r--r--drivers/media/rc/streamzap.c14
-rw-r--r--drivers/media/rc/sunxi-cir.c2
-rw-r--r--drivers/media/rc/ttusbir.c4
-rw-r--r--drivers/media/rc/winbond-cir.c12
-rw-r--r--drivers/media/tuners/e4000.c2
-rw-r--r--drivers/media/tuners/fc2580.c2
-rw-r--r--drivers/media/tuners/msi001.c2
-rw-r--r--drivers/media/tuners/mt20xx.c2
-rw-r--r--drivers/media/tuners/si2157.c13
-rw-r--r--drivers/media/tuners/si2157_priv.h9
-rw-r--r--drivers/media/tuners/tuner-simple.c2
-rw-r--r--drivers/media/usb/airspy/airspy.c10
-rw-r--r--drivers/media/usb/au0828/au0828-core.c17
-rw-r--r--drivers/media/usb/au0828/au0828-i2c.c2
-rw-r--r--drivers/media/usb/au0828/au0828-input.c5
-rw-r--r--drivers/media/usb/au0828/au0828-video.c22
-rw-r--r--drivers/media/usb/cpia2/cpia2_v4l.c14
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-417.c4
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-audio.c8
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-input.c2
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-video.c33
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9035.c2
-rw-r--r--drivers/media/usb/dvb-usb-v2/anysee.c2
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvb_usb_core.c2
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvbsky.c16
-rw-r--r--drivers/media/usb/dvb-usb-v2/gl861.c2
-rw-r--r--drivers/media/usb/dvb-usb-v2/lmedm04.c2
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf.c8
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf.h8
-rw-r--r--drivers/media/usb/dvb-usb-v2/rtl28xxu.c22
-rw-r--r--drivers/media/usb/dvb-usb-v2/zd1301.c2
-rw-r--r--drivers/media/usb/dvb-usb/cxusb.c4
-rw-r--r--drivers/media/usb/dvb-usb/dib0700_devices.c4
-rw-r--r--drivers/media/usb/dvb-usb/dvb-usb-i2c.c2
-rw-r--r--drivers/media/usb/dvb-usb/dw2102.c4
-rw-r--r--drivers/media/usb/dvb-usb/technisat-usb2.c5
-rw-r--r--drivers/media/usb/em28xx/em28xx-audio.c21
-rw-r--r--drivers/media/usb/em28xx/em28xx-cards.c33
-rw-r--r--drivers/media/usb/em28xx/em28xx-core.c5
-rw-r--r--drivers/media/usb/em28xx/em28xx-i2c.c3
-rw-r--r--drivers/media/usb/em28xx/em28xx-video.c124
-rw-r--r--drivers/media/usb/em28xx/em28xx.h8
-rw-r--r--drivers/media/usb/go7007/go7007-driver.c2
-rw-r--r--drivers/media/usb/go7007/go7007-v4l2.c16
-rw-r--r--drivers/media/usb/go7007/snd-go7007.c8
-rw-r--r--drivers/media/usb/gspca/gspca.c10
-rw-r--r--drivers/media/usb/gspca/sn9c20x.c2
-rw-r--r--drivers/media/usb/gspca/sq930x.c2
-rw-r--r--drivers/media/usb/hackrf/hackrf.c12
-rw-r--r--drivers/media/usb/hdpvr/hdpvr-video.c9
-rw-r--r--drivers/media/usb/msi2500/msi2500.c10
-rw-r--r--drivers/media/usb/pulse8-cec/pulse8-cec.c3
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-debug.h2
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-hdw.c8
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c34
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-main.c4
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-v4l2.c14
-rw-r--r--drivers/media/usb/pwc/pwc-if.c2
-rw-r--r--drivers/media/usb/pwc/pwc-v4l.c12
-rw-r--r--drivers/media/usb/rainshadow-cec/rainshadow-cec.c3
-rw-r--r--drivers/media/usb/s2255/s2255drv.c10
-rw-r--r--drivers/media/usb/stk1160/stk1160-i2c.c2
-rw-r--r--drivers/media/usb/stk1160/stk1160-v4l.c6
-rw-r--r--drivers/media/usb/stkwebcam/stk-webcam.c16
-rw-r--r--drivers/media/usb/tm6000/tm6000-alsa.c6
-rw-r--r--drivers/media/usb/tm6000/tm6000-i2c.c4
-rw-r--r--drivers/media/usb/tm6000/tm6000-video.c20
-rw-r--r--drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c2
-rw-r--r--drivers/media/usb/usbtv/usbtv-audio.c6
-rw-r--r--drivers/media/usb/usbtv/usbtv-video.c14
-rw-r--r--drivers/media/usb/usbvision/usbvision-core.c3
-rw-r--r--drivers/media/usb/usbvision/usbvision-video.c26
-rw-r--r--drivers/media/usb/usbvision/usbvision.h1
-rw-r--r--drivers/media/usb/uvc/uvc_ctrl.c18
-rw-r--r--drivers/media/usb/uvc/uvc_debugfs.c6
-rw-r--r--drivers/media/usb/uvc/uvc_driver.c75
-rw-r--r--drivers/media/usb/uvc/uvc_entity.c2
-rw-r--r--drivers/media/usb/uvc/uvc_metadata.c11
-rw-r--r--drivers/media/usb/uvc/uvc_queue.c5
-rw-r--r--drivers/media/usb/uvc/uvc_v4l2.c13
-rw-r--r--drivers/media/usb/uvc/uvcvideo.h11
-rw-r--r--drivers/media/usb/zr364xx/zr364xx.c10
-rw-r--r--drivers/media/v4l2-core/tuner-core.c54
-rw-r--r--drivers/media/v4l2-core/v4l2-async.c313
-rw-r--r--drivers/media/v4l2-core/v4l2-common.c25
-rw-r--r--drivers/media/v4l2-core/v4l2-compat-ioctl32.c19
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls.c634
-rw-r--r--drivers/media/v4l2-core/v4l2-dev.c18
-rw-r--r--drivers/media/v4l2-core/v4l2-device.c5
-rw-r--r--drivers/media/v4l2-core/v4l2-dv-timings.c202
-rw-r--r--drivers/media/v4l2-core/v4l2-event.c38
-rw-r--r--drivers/media/v4l2-core/v4l2-fh.c2
-rw-r--r--drivers/media/v4l2-core/v4l2-flash-led-class.c2
-rw-r--r--drivers/media/v4l2-core/v4l2-fwnode.c845
-rw-r--r--drivers/media/v4l2-core/v4l2-ioctl.c58
-rw-r--r--drivers/media/v4l2-core/v4l2-mc.c147
-rw-r--r--drivers/media/v4l2-core/v4l2-mem2mem.c67
-rw-r--r--drivers/media/v4l2-core/v4l2-subdev.c11
-rw-r--r--drivers/memory/atmel-ebi.c3
-rw-r--r--drivers/memstick/core/ms_block.c2
-rw-r--r--drivers/memstick/core/mspro_block.c2
-rw-r--r--drivers/message/fusion/lsi/mpi_cnfg.h2
-rw-r--r--drivers/message/fusion/mptbase.c12
-rw-r--r--drivers/message/fusion/mptsas.c8
-rw-r--r--drivers/mfd/Kconfig26
-rw-r--r--drivers/mfd/Makefile1
-rw-r--r--drivers/mfd/adp5520.c2
-rw-r--r--drivers/mfd/altera-a10sr.c3
-rw-r--r--drivers/mfd/arizona-core.c10
-rw-r--r--drivers/mfd/at91-usart.c72
-rw-r--r--drivers/mfd/cros_ec.c3
-rw-r--r--drivers/mfd/cros_ec_dev.c1
-rw-r--r--drivers/mfd/cros_ec_dev.h13
-rw-r--r--drivers/mfd/da9052-spi.c3
-rw-r--r--drivers/mfd/intel_msic.c49
-rw-r--r--drivers/mfd/intel_soc_pmic_bxtwc.c56
-rw-r--r--drivers/mfd/intel_soc_pmic_chtdc_ti.c5
-rw-r--r--drivers/mfd/intel_soc_pmic_chtwc.c5
-rw-r--r--drivers/mfd/intel_soc_pmic_core.c25
-rw-r--r--drivers/mfd/intel_soc_pmic_core.h12
-rw-r--r--drivers/mfd/intel_soc_pmic_crc.c78
-rw-r--r--drivers/mfd/madera-core.c33
-rw-r--r--drivers/mfd/max14577.c28
-rw-r--r--drivers/mfd/max77620.c2
-rw-r--r--drivers/mfd/max77686.c32
-rw-r--r--drivers/mfd/max77693.c34
-rw-r--r--drivers/mfd/max77843.c19
-rw-r--r--drivers/mfd/max8997-irq.c30
-rw-r--r--drivers/mfd/max8997.c40
-rw-r--r--drivers/mfd/max8998-irq.c18
-rw-r--r--drivers/mfd/max8998.c28
-rw-r--r--drivers/mfd/mc13xxx-core.c3
-rw-r--r--drivers/mfd/mc13xxx-spi.c3
-rw-r--r--drivers/mfd/menelaus.c13
-rw-r--r--drivers/mfd/motorola-cpcap.c51
-rw-r--r--drivers/mfd/rohm-bd718x7.c162
-rw-r--r--drivers/mfd/sec-core.c16
-rw-r--r--drivers/mfd/sec-irq.c24
-rw-r--r--drivers/mfd/ti-lmu.c91
-rw-r--r--drivers/mfd/ti_am335x_tscadc.c14
-rw-r--r--drivers/mfd/twl6040.c3
-rw-r--r--drivers/misc/ad525x_dpot-i2c.c2
-rw-r--r--drivers/misc/ad525x_dpot-spi.c2
-rw-r--r--drivers/misc/ad525x_dpot.c6
-rw-r--r--drivers/misc/apds990x.c1
-rw-r--r--drivers/misc/bh1770glc.c3
-rw-r--r--drivers/misc/cxl/flash.c4
-rw-r--r--drivers/misc/cxl/guest.c2
-rw-r--r--drivers/misc/echo/echo.c2
-rw-r--r--drivers/misc/eeprom/Kconfig11
-rw-r--r--drivers/misc/eeprom/Makefile1
-rw-r--r--drivers/misc/eeprom/at24.c43
-rw-r--r--drivers/misc/eeprom/at25.c13
-rw-r--r--drivers/misc/eeprom/ee1004.c281
-rw-r--r--drivers/misc/eeprom/eeprom_93xx46.c19
-rw-r--r--drivers/misc/genwqe/card_base.c1
-rw-r--r--drivers/misc/genwqe/card_base.h2
-rw-r--r--drivers/misc/genwqe/card_ddcb.c1
-rw-r--r--drivers/misc/genwqe/card_dev.c9
-rw-r--r--drivers/misc/genwqe/card_utils.c15
-rw-r--r--drivers/misc/kgdbts.c16
-rw-r--r--drivers/misc/lkdtm/Makefile2
-rw-r--r--drivers/misc/lkdtm/core.c2
-rw-r--r--drivers/misc/lkdtm/lkdtm.h4
-rw-r--r--drivers/misc/lkdtm/stackleak.c73
-rw-r--r--drivers/misc/lkdtm/usercopy.c15
-rw-r--r--drivers/misc/mei/bus-fixup.c1
-rw-r--r--drivers/misc/mei/main.c4
-rw-r--r--drivers/misc/mic/scif/scif_dma.c9
-rw-r--r--drivers/misc/mic/scif/scif_fence.c2
-rw-r--r--drivers/misc/ocxl/config.c4
-rw-r--r--drivers/misc/sgi-gru/grukservices.c4
-rw-r--r--drivers/misc/sgi-gru/grutlbpurge.c1
-rw-r--r--drivers/misc/sgi-xp/xpc_channel.c6
-rw-r--r--drivers/misc/sgi-xp/xpc_partition.c3
-rw-r--r--drivers/misc/sgi-xp/xpc_sn2.c2
-rw-r--r--drivers/misc/sgi-xp/xpc_uv.c2
-rw-r--r--drivers/misc/sram.c6
-rw-r--r--drivers/misc/vmw_balloon.c1802
-rw-r--r--drivers/misc/vmw_vmci/vmci_driver.c2
-rw-r--r--drivers/misc/vmw_vmci/vmci_host.c4
-rw-r--r--drivers/misc/vmw_vmci/vmci_queue_pair.c6
-rw-r--r--drivers/misc/vmw_vmci/vmci_resource.c3
-rw-r--r--drivers/mmc/core/Kconfig2
-rw-r--r--drivers/mmc/core/block.c12
-rw-r--r--drivers/mmc/core/host.c2
-rw-r--r--drivers/mmc/core/pwrseq_simple.c14
-rw-r--r--drivers/mmc/core/slot-gpio.c2
-rw-r--r--drivers/mmc/host/Kconfig40
-rw-r--r--drivers/mmc/host/Makefile3
-rw-r--r--drivers/mmc/host/dw_mmc-exynos.c11
-rw-r--r--drivers/mmc/host/dw_mmc-hi3798cv200.c8
-rw-r--r--drivers/mmc/host/jz4740_mmc.c5
-rw-r--r--drivers/mmc/host/meson-mx-sdio.c2
-rw-r--r--drivers/mmc/host/mmci.c698
-rw-r--r--drivers/mmc/host/mmci.h174
-rw-r--r--drivers/mmc/host/mmci_qcom_dml.c17
-rw-r--r--drivers/mmc/host/mmci_stm32_sdmmc.c282
-rw-r--r--drivers/mmc/host/mtk-sd.c298
-rw-r--r--drivers/mmc/host/mxcmmc.c5
-rw-r--r--drivers/mmc/host/omap_hsmmc.c171
-rw-r--r--drivers/mmc/host/renesas_sdhi.h5
-rw-r--r--drivers/mmc/host/renesas_sdhi_core.c66
-rw-r--r--drivers/mmc/host/renesas_sdhi_internal_dmac.c30
-rw-r--r--drivers/mmc/host/renesas_sdhi_sys_dmac.c18
-rw-r--r--drivers/mmc/host/sdhci-acpi.c70
-rw-r--r--drivers/mmc/host/sdhci-esdhc.h1
-rw-r--r--drivers/mmc/host/sdhci-iproc.c59
-rw-r--r--drivers/mmc/host/sdhci-of-arasan.c96
-rw-r--r--drivers/mmc/host/sdhci-of-dwcmshc.c39
-rw-r--r--drivers/mmc/host/sdhci-of-esdhc.c44
-rw-r--r--drivers/mmc/host/sdhci-pci-o2micro.c3
-rw-r--r--drivers/mmc/host/sdhci-pltfm.c68
-rw-r--r--drivers/mmc/host/sdhci-pltfm.h7
-rw-r--r--drivers/mmc/host/sdhci-pxav3.c14
-rw-r--r--drivers/mmc/host/sdhci-sirf.c28
-rw-r--r--drivers/mmc/host/sdhci-spear.c33
-rw-r--r--drivers/mmc/host/sdhci-sprd.c498
-rw-r--r--drivers/mmc/host/sdhci-tegra.c675
-rw-r--r--drivers/mmc/host/sdhci-xenon-phy.c4
-rw-r--r--drivers/mmc/host/sdhci.c289
-rw-r--r--drivers/mmc/host/sdhci.h37
-rw-r--r--drivers/mmc/host/sh_mmcif.c7
-rw-r--r--drivers/mmc/host/sunxi-mmc.c24
-rw-r--r--drivers/mmc/host/tifm_sd.c3
-rw-r--r--drivers/mmc/host/tmio_mmc.c80
-rw-r--r--drivers/mmc/host/tmio_mmc.h16
-rw-r--r--drivers/mmc/host/tmio_mmc_core.c129
-rw-r--r--drivers/mmc/host/uniphier-sd.c698
-rw-r--r--drivers/mmc/host/usdhi6rol0.c5
-rw-r--r--drivers/mtd/ar7part.c2
-rw-r--r--drivers/mtd/devices/Kconfig2
-rw-r--r--drivers/mtd/devices/m25p80.c23
-rw-r--r--drivers/mtd/maps/gpio-addr-flash.c146
-rw-r--r--drivers/mtd/maps/physmap_of_core.c27
-rw-r--r--drivers/mtd/maps/physmap_of_gemini.c5
-rw-r--r--drivers/mtd/maps/sa1100-flash.c10
-rw-r--r--drivers/mtd/mtd_blkdevs.c102
-rw-r--r--drivers/mtd/nand/raw/Kconfig20
-rw-r--r--drivers/mtd/nand/raw/Makefile6
-rw-r--r--drivers/mtd/nand/raw/ams-delta.c249
-rw-r--r--drivers/mtd/nand/raw/atmel/nand-controller.c111
-rw-r--r--drivers/mtd/nand/raw/au1550nd.c124
-rw-r--r--drivers/mtd/nand/raw/bcm47xxnflash/main.c2
-rw-r--r--drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c58
-rw-r--r--drivers/mtd/nand/raw/brcmnand/brcmnand.c93
-rw-r--r--drivers/mtd/nand/raw/cafe_nand.c74
-rw-r--r--drivers/mtd/nand/raw/cmx270_nand.c48
-rw-r--r--drivers/mtd/nand/raw/cs553x_nand.c75
-rw-r--r--drivers/mtd/nand/raw/davinci_nand.c93
-rw-r--r--drivers/mtd/nand/raw/denali.c151
-rw-r--r--drivers/mtd/nand/raw/denali.h10
-rw-r--r--drivers/mtd/nand/raw/denali_dt.c12
-rw-r--r--drivers/mtd/nand/raw/denali_pci.c10
-rw-r--r--drivers/mtd/nand/raw/diskonchip.c156
-rw-r--r--drivers/mtd/nand/raw/docg4.c1442
-rw-r--r--drivers/mtd/nand/raw/fsl_elbc_nand.c70
-rw-r--r--drivers/mtd/nand/raw/fsl_ifc_nand.c106
-rw-r--r--drivers/mtd/nand/raw/fsl_upm.c66
-rw-r--r--drivers/mtd/nand/raw/fsmc_nand.c44
-rw-r--r--drivers/mtd/nand/raw/gpio.c29
-rw-r--r--drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c3
-rw-r--r--drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c111
-rw-r--r--drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h2
-rw-r--r--drivers/mtd/nand/raw/hisi504_nand.c68
-rw-r--r--drivers/mtd/nand/raw/internals.h115
-rw-r--r--drivers/mtd/nand/raw/jz4740_nand.c53
-rw-r--r--drivers/mtd/nand/raw/jz4780_nand.c42
-rw-r--r--drivers/mtd/nand/raw/lpc32xx_mlc.c59
-rw-r--r--drivers/mtd/nand/raw/lpc32xx_slc.c83
-rw-r--r--drivers/mtd/nand/raw/marvell_nand.c275
-rw-r--r--drivers/mtd/nand/raw/mpc5121_nfc.c65
-rw-r--r--drivers/mtd/nand/raw/mtk_nand.c93
-rw-r--r--drivers/mtd/nand/raw/mxc_nand.c114
-rw-r--r--drivers/mtd/nand/raw/nand_amd.c2
-rw-r--r--drivers/mtd/nand/raw/nand_base.c1722
-rw-r--r--drivers/mtd/nand/raw/nand_bbt.c24
-rw-r--r--drivers/mtd/nand/raw/nand_bch.c10
-rw-r--r--drivers/mtd/nand/raw/nand_ecc.c99
-rw-r--r--drivers/mtd/nand/raw/nand_esmt.c47
-rw-r--r--drivers/mtd/nand/raw/nand_hynix.c15
-rw-r--r--drivers/mtd/nand/raw/nand_ids.c26
-rw-r--r--drivers/mtd/nand/raw/nand_jedec.c113
-rw-r--r--drivers/mtd/nand/raw/nand_legacy.c642
-rw-r--r--drivers/mtd/nand/raw/nand_macronix.c2
-rw-r--r--drivers/mtd/nand/raw/nand_micron.c19
-rw-r--r--drivers/mtd/nand/raw/nand_onfi.c305
-rw-r--r--drivers/mtd/nand/raw/nand_samsung.c2
-rw-r--r--drivers/mtd/nand/raw/nand_timings.c18
-rw-r--r--drivers/mtd/nand/raw/nand_toshiba.c88
-rw-r--r--drivers/mtd/nand/raw/nandsim.c50
-rw-r--r--drivers/mtd/nand/raw/ndfc.c43
-rw-r--r--drivers/mtd/nand/raw/nuc900_nand.c47
-rw-r--r--drivers/mtd/nand/raw/omap2.c200
-rw-r--r--drivers/mtd/nand/raw/orion_nand.c26
-rw-r--r--drivers/mtd/nand/raw/oxnas_nand.c29
-rw-r--r--drivers/mtd/nand/raw/pasemi_nand.c51
-rw-r--r--drivers/mtd/nand/raw/plat_nand.c23
-rw-r--r--drivers/mtd/nand/raw/qcom_nandc.c92
-rw-r--r--drivers/mtd/nand/raw/r852.c80
-rw-r--r--drivers/mtd/nand/raw/r852.h2
-rw-r--r--drivers/mtd/nand/raw/s3c2410.c106
-rw-r--r--drivers/mtd/nand/raw/sh_flctl.c68
-rw-r--r--drivers/mtd/nand/raw/sharpsl.c36
-rw-r--r--drivers/mtd/nand/raw/sm_common.c7
-rw-r--r--drivers/mtd/nand/raw/socrates_nand.c60
-rw-r--r--drivers/mtd/nand/raw/sunxi_nand.c96
-rw-r--r--drivers/mtd/nand/raw/tango_nand.c77
-rw-r--r--drivers/mtd/nand/raw/tegra_nand.c36
-rw-r--r--drivers/mtd/nand/raw/tmio_nand.c78
-rw-r--r--drivers/mtd/nand/raw/txx9ndfmc.c53
-rw-r--r--drivers/mtd/nand/raw/vf610_nfc.c43
-rw-r--r--drivers/mtd/nand/raw/xway_nand.c39
-rw-r--r--drivers/mtd/sm_ftl.c20
-rw-r--r--drivers/mtd/spi-nor/cadence-quadspi.c6
-rw-r--r--drivers/mtd/spi-nor/fsl-quadspi.c15
-rw-r--r--drivers/mtd/spi-nor/intel-spi-pci.c1
-rw-r--r--drivers/mtd/spi-nor/spi-nor.c919
-rw-r--r--drivers/mtd/tests/mtd_nandecctest.c21
-rw-r--r--drivers/mtd/ubi/attach.c1
-rw-r--r--drivers/mtd/ubi/build.c2
-rw-r--r--drivers/mux/adgs1408.c2
-rw-r--r--drivers/mux/gpio.c12
-rw-r--r--drivers/net/arcnet/arc-rimi.c2
-rw-r--r--drivers/net/arcnet/com20020-isa.c2
-rw-r--r--drivers/net/arcnet/com90io.c2
-rw-r--r--drivers/net/bonding/bond_main.c72
-rw-r--r--drivers/net/bonding/bond_netlink.c3
-rw-r--r--drivers/net/can/rx-offload.c8
-rw-r--r--drivers/net/dsa/Kconfig8
-rw-r--r--drivers/net/dsa/Makefile1
-rw-r--r--drivers/net/dsa/b53/Kconfig10
-rw-r--r--drivers/net/dsa/b53/Makefile1
-rw-r--r--drivers/net/dsa/b53/b53_common.c252
-rw-r--r--drivers/net/dsa/b53/b53_priv.h36
-rw-r--r--drivers/net/dsa/b53/b53_serdes.c214
-rw-r--r--drivers/net/dsa/b53/b53_serdes.h128
-rw-r--r--drivers/net/dsa/b53/b53_srab.c215
-rw-r--r--drivers/net/dsa/bcm_sf2.c23
-rw-r--r--drivers/net/dsa/lantiq_gswip.c1167
-rw-r--r--drivers/net/dsa/lantiq_pce.h153
-rw-r--r--drivers/net/dsa/microchip/ksz_common.c10
-rw-r--r--drivers/net/dsa/mt7530.c6
-rw-r--r--drivers/net/dsa/mv88e6xxx/chip.c28
-rw-r--r--drivers/net/dsa/mv88e6xxx/global1.c2
-rw-r--r--drivers/net/dsa/mv88e6xxx/phy.c3
-rw-r--r--drivers/net/dsa/mv88e6xxx/port.c25
-rw-r--r--drivers/net/dsa/mv88e6xxx/port.h1
-rw-r--r--drivers/net/dsa/mv88e6xxx/serdes.c105
-rw-r--r--drivers/net/dsa/mv88e6xxx/serdes.h16
-rw-r--r--drivers/net/dsa/qca8k.c6
-rw-r--r--drivers/net/ethernet/8390/ax88796.c4
-rw-r--r--drivers/net/ethernet/8390/etherh.c35
-rw-r--r--drivers/net/ethernet/Kconfig7
-rw-r--r--drivers/net/ethernet/Makefile1
-rw-r--r--drivers/net/ethernet/aeroflex/greth.c4
-rw-r--r--drivers/net/ethernet/agere/et131x.c12
-rw-r--r--drivers/net/ethernet/alacritech/slic.h1
-rw-r--r--drivers/net/ethernet/allwinner/sun4i-emac.c3
-rw-r--r--drivers/net/ethernet/altera/altera_tse_main.c5
-rw-r--r--drivers/net/ethernet/amazon/Kconfig2
-rw-r--r--drivers/net/ethernet/amazon/ena/ena_admin_defs.h425
-rw-r--r--drivers/net/ethernet/amazon/ena/ena_com.c302
-rw-r--r--drivers/net/ethernet/amazon/ena/ena_com.h72
-rw-r--r--drivers/net/ethernet/amazon/ena/ena_common_defs.h4
-rw-r--r--drivers/net/ethernet/amazon/ena/ena_eth_com.c285
-rw-r--r--drivers/net/ethernet/amazon/ena/ena_eth_com.h72
-rw-r--r--drivers/net/ethernet/amazon/ena/ena_eth_io_defs.h229
-rw-r--r--drivers/net/ethernet/amazon/ena/ena_ethtool.c2
-rw-r--r--drivers/net/ethernet/amazon/ena/ena_netdev.c505
-rw-r--r--drivers/net/ethernet/amazon/ena/ena_netdev.h42
-rw-r--r--drivers/net/ethernet/amazon/ena/ena_regs_defs.h206
-rw-r--r--drivers/net/ethernet/amd/am79c961a.c2
-rw-r--r--drivers/net/ethernet/amd/atarilance.c6
-rw-r--r--drivers/net/ethernet/amd/au1000_eth.c12
-rw-r--r--drivers/net/ethernet/amd/declance.c12
-rw-r--r--drivers/net/ethernet/amd/ni65.c4
-rw-r--r--drivers/net/ethernet/amd/sun3lance.c6
-rw-r--r--drivers/net/ethernet/amd/sunlance.c2
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-drv.c5
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c19
-rw-r--r--drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c30
-rw-r--r--drivers/net/ethernet/apm/xgene/xgene_enet_hw.c10
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/aq_common.h5
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c121
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/aq_hw.h19
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/aq_main.c10
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/aq_nic.c42
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/aq_nic.h6
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c12
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/aq_ring.c39
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c41
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0_internal.h6
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c96
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0_internal.h6
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c16
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h6
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h31
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c163
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h130
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c252
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/ver.h2
-rw-r--r--drivers/net/ethernet/atheros/alx/alx.h1
-rw-r--r--drivers/net/ethernet/atheros/alx/main.c4
-rw-r--r--drivers/net/ethernet/atheros/atlx/atl1.c22
-rw-r--r--drivers/net/ethernet/aurora/nb8800.c9
-rw-r--r--drivers/net/ethernet/broadcom/bcm63xx_enet.c22
-rw-r--r--drivers/net/ethernet/broadcom/bcmsysport.c110
-rw-r--r--drivers/net/ethernet/broadcom/bcmsysport.h2
-rw-r--r--drivers/net/ethernet/broadcom/bgmac.c2
-rw-r--r--drivers/net/ethernet/broadcom/bnx2.c7
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c1
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h1
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c19
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c81
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h2
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.c1699
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.h250
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c6
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c86
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.h7
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c112
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h310
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c15
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c5
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.h3
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c2
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmgenet.c13
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmmii.c18
-rw-r--r--drivers/net/ethernet/broadcom/sb1250-mac.c20
-rw-r--r--drivers/net/ethernet/broadcom/tg3.c71
-rw-r--r--drivers/net/ethernet/brocade/bna/bna_enet.c4
-rw-r--r--drivers/net/ethernet/cadence/macb_main.c18
-rw-r--r--drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c4
-rw-r--r--drivers/net/ethernet/cavium/liquidio/lio_core.c547
-rw-r--r--drivers/net/ethernet/cavium/liquidio/lio_ethtool.c342
-rw-r--r--drivers/net/ethernet/cavium/liquidio/lio_main.c404
-rw-r--r--drivers/net/ethernet/cavium/liquidio/lio_vf_main.c226
-rw-r--r--drivers/net/ethernet/cavium/liquidio/lio_vf_rep.c53
-rw-r--r--drivers/net/ethernet/cavium/liquidio/liquidio_common.h31
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_config.h3
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_device.c12
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_device.h7
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_droq.c122
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_droq.h5
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_iq.h17
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_main.h98
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_network.h35
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_nic.c61
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_nic.h9
-rw-r--r--drivers/net/ethernet/cavium/liquidio/request_manager.c125
-rw-r--r--drivers/net/ethernet/cavium/liquidio/response_manager.c82
-rw-r--r--drivers/net/ethernet/cavium/liquidio/response_manager.h4
-rw-r--r--drivers/net/ethernet/cavium/octeon/octeon_mgmt.c5
-rw-r--r--drivers/net/ethernet/chelsio/Kconfig1
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c21
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c3
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/Makefile3
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h42
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h3
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c238
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h106
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4.h24
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c4
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c31
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h2
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c1
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c33
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_thermal.c114
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c66
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h2
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/l2t.c6
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/sched.c68
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/sched.h2
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/sge.c4
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_hw.c16
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h2
-rw-r--r--drivers/net/ethernet/cortina/gemini.c5
-rw-r--r--drivers/net/ethernet/davicom/dm9000.c6
-rw-r--r--drivers/net/ethernet/dnet.c8
-rw-r--r--drivers/net/ethernet/emulex/benet/be.h1
-rw-r--r--drivers/net/ethernet/emulex/benet/be_main.c12
-rw-r--r--drivers/net/ethernet/ethoc.c5
-rw-r--r--drivers/net/ethernet/faraday/ftgmac100.c24
-rw-r--r--drivers/net/ethernet/faraday/ftmac100.c7
-rw-r--r--drivers/net/ethernet/freescale/Kconfig1
-rw-r--r--drivers/net/ethernet/freescale/Makefile2
-rw-r--r--drivers/net/ethernet/freescale/dpaa/dpaa_eth.c16
-rw-r--r--drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c28
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/Kconfig16
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/Makefile13
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-trace.h (renamed from drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth-trace.h)0
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c (renamed from drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c)390
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h (renamed from drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h)36
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c630
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpaa2-ptp.c (renamed from drivers/staging/fsl-dpaa2/rtc/rtc.c)57
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpaa2-ptp.h (renamed from drivers/staging/fsl-dpaa2/rtc/rtc.h)0
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpkg.h (renamed from drivers/staging/fsl-dpaa2/ethernet/dpkg.h)0
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h (renamed from drivers/staging/fsl-dpaa2/ethernet/dpni-cmd.h)51
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpni.c (renamed from drivers/staging/fsl-dpaa2/ethernet/dpni.c)152
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpni.h (renamed from drivers/staging/fsl-dpaa2/ethernet/dpni.h)97
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dprtc-cmd.h40
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dprtc.c194
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dprtc.h45
-rw-r--r--drivers/net/ethernet/freescale/fec.h4
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c47
-rw-r--r--drivers/net/ethernet/freescale/fec_mpc52xx.c3
-rw-r--r--drivers/net/ethernet/freescale/fman/mac.c6
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c3
-rw-r--r--drivers/net/ethernet/freescale/fsl_pq_mdio.c4
-rw-r--r--drivers/net/ethernet/freescale/gianfar.c17
-rw-r--r--drivers/net/ethernet/freescale/gianfar_ethtool.c55
-rw-r--r--drivers/net/ethernet/freescale/ucc_geth.c10
-rw-r--r--drivers/net/ethernet/hisilicon/hip04_eth.c3
-rw-r--r--drivers/net/ethernet/hisilicon/hix5hd2_gmac.c2
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hnae.c2
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c2
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c8
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_enet.c48
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h3
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hnae3.c12
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hnae3.h65
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3_enet.c711
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3_enet.h17
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c216
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/Makefile2
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c26
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h147
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c14
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c1090
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h83
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c2522
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h379
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c64
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c8
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c28
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h6
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c12
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h8
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c640
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h25
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h2
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_hw_qp.c121
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_hw_qp.h27
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_hw_wq.c14
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_hw_wq.h2
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_hw_wqe.h97
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_main.c43
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_port.c32
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_port.h18
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_tx.c295
-rw-r--r--drivers/net/ethernet/ibm/ehea/ehea_main.c19
-rw-r--r--drivers/net/ethernet/ibm/ehea/ehea_qmr.c4
-rw-r--r--drivers/net/ethernet/ibm/emac/core.c13
-rw-r--r--drivers/net/ethernet/ibm/emac/core.h3
-rw-r--r--drivers/net/ethernet/ibm/emac/mal.h2
-rw-r--r--drivers/net/ethernet/ibm/ibmveth.c1
-rw-r--r--drivers/net/ethernet/ibm/ibmvnic.c151
-rw-r--r--drivers/net/ethernet/ibm/ibmvnic.h9
-rw-r--r--drivers/net/ethernet/intel/Kconfig75
-rw-r--r--drivers/net/ethernet/intel/Makefile3
-rw-r--r--drivers/net/ethernet/intel/e100.c2
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_main.c5
-rw-r--r--drivers/net/ethernet/intel/e1000e/netdev.c4
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_iov.c51
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_main.c4
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_pci.c4
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_type.h2
-rw-r--r--drivers/net/ethernet/intel/i40e/Makefile3
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e.h19
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_debugfs.c2
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_ethtool.c437
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_main.c406
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_ptp.c3
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_txrx.c202
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_txrx.h20
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_txrx_common.h94
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c447
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_xsk.c967
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_xsk.h25
-rw-r--r--drivers/net/ethernet/intel/i40evf/Makefile16
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h2717
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40e_alloc.h35
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40e_common.c1320
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40e_devids.h34
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40e_hmc.h215
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40e_lan_hmc.h158
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40e_prototype.h130
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40e_register.h313
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40e_type.h1496
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40evf.h427
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c820
-rw-r--r--drivers/net/ethernet/intel/iavf/Makefile15
-rw-r--r--drivers/net/ethernet/intel/iavf/i40e_adminq.c (renamed from drivers/net/ethernet/intel/i40evf/i40e_adminq.c)311
-rw-r--r--drivers/net/ethernet/intel/iavf/i40e_adminq.h (renamed from drivers/net/ethernet/intel/i40evf/i40e_adminq.h)35
-rw-r--r--drivers/net/ethernet/intel/iavf/i40e_adminq_cmd.h530
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf.h418
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_alloc.h31
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_client.c (renamed from drivers/net/ethernet/intel/i40evf/i40evf_client.c)224
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_client.h (renamed from drivers/net/ethernet/intel/i40evf/i40evf_client.h)30
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_common.c955
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_devids.h12
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_ethtool.c1036
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_main.c (renamed from drivers/net/ethernet/intel/i40evf/i40evf_main.c)1734
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_osdep.h (renamed from drivers/net/ethernet/intel/i40evf/i40e_osdep.h)28
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_prototype.h67
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_register.h68
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_status.h (renamed from drivers/net/ethernet/intel/i40evf/i40e_status.h)8
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_trace.h (renamed from drivers/net/ethernet/intel/i40evf/i40e_trace.h)86
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_txrx.c (renamed from drivers/net/ethernet/intel/i40evf/i40e_txrx.c)813
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_txrx.h (renamed from drivers/net/ethernet/intel/i40evf/i40e_txrx.h)359
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_type.h688
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_virtchnl.c (renamed from drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c)530
-rw-r--r--drivers/net/ethernet/intel/ice/Makefile2
-rw-r--r--drivers/net/ethernet/intel/ice/ice.h76
-rw-r--r--drivers/net/ethernet/intel/ice/ice_adminq_cmd.h124
-rw-r--r--drivers/net/ethernet/intel/ice/ice_common.c941
-rw-r--r--drivers/net/ethernet/intel/ice/ice_common.h50
-rw-r--r--drivers/net/ethernet/intel/ice/ice_controlq.c89
-rw-r--r--drivers/net/ethernet/intel/ice/ice_controlq.h7
-rw-r--r--drivers/net/ethernet/intel/ice/ice_devids.h16
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ethtool.c825
-rw-r--r--drivers/net/ethernet/intel/ice/ice_hw_autogen.h540
-rw-r--r--drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h37
-rw-r--r--drivers/net/ethernet/intel/ice/ice_lib.c2621
-rw-r--r--drivers/net/ethernet/intel/ice/ice_lib.h76
-rw-r--r--drivers/net/ethernet/intel/ice/ice_main.c3722
-rw-r--r--drivers/net/ethernet/intel/ice/ice_nvm.c2
-rw-r--r--drivers/net/ethernet/intel/ice/ice_sched.c379
-rw-r--r--drivers/net/ethernet/intel/ice/ice_sched.h5
-rw-r--r--drivers/net/ethernet/intel/ice/ice_sriov.c127
-rw-r--r--drivers/net/ethernet/intel/ice/ice_sriov.h34
-rw-r--r--drivers/net/ethernet/intel/ice/ice_status.h4
-rw-r--r--drivers/net/ethernet/intel/ice/ice_switch.c1698
-rw-r--r--drivers/net/ethernet/intel/ice/ice_switch.h93
-rw-r--r--drivers/net/ethernet/intel/ice/ice_txrx.c12
-rw-r--r--drivers/net/ethernet/intel/ice/ice_txrx.h40
-rw-r--r--drivers/net/ethernet/intel/ice/ice_type.h113
-rw-r--r--drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c2673
-rw-r--r--drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h173
-rw-r--r--drivers/net/ethernet/intel/igb/igb_main.c11
-rw-r--r--drivers/net/ethernet/intel/igb/igb_ptp.c10
-rw-r--r--drivers/net/ethernet/intel/igbvf/netdev.c2
-rw-r--r--drivers/net/ethernet/intel/igc/Makefile10
-rw-r--r--drivers/net/ethernet/intel/igc/igc.h443
-rw-r--r--drivers/net/ethernet/intel/igc/igc_base.c541
-rw-r--r--drivers/net/ethernet/intel/igc/igc_base.h107
-rw-r--r--drivers/net/ethernet/intel/igc/igc_defines.h389
-rw-r--r--drivers/net/ethernet/intel/igc/igc_hw.h321
-rw-r--r--drivers/net/ethernet/intel/igc/igc_i225.c490
-rw-r--r--drivers/net/ethernet/intel/igc/igc_i225.h13
-rw-r--r--drivers/net/ethernet/intel/igc/igc_mac.c806
-rw-r--r--drivers/net/ethernet/intel/igc/igc_mac.h41
-rw-r--r--drivers/net/ethernet/intel/igc/igc_main.c3901
-rw-r--r--drivers/net/ethernet/intel/igc/igc_nvm.c215
-rw-r--r--drivers/net/ethernet/intel/igc/igc_nvm.h14
-rw-r--r--drivers/net/ethernet/intel/igc/igc_phy.c791
-rw-r--r--drivers/net/ethernet/intel/igc/igc_phy.h21
-rw-r--r--drivers/net/ethernet/intel/igc/igc_regs.h221
-rw-r--r--drivers/net/ethernet/intel/ixgb/ixgb_main.c2
-rw-r--r--drivers/net/ethernet/intel/ixgbe/Makefile5
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe.h57
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c9
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c282
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.h13
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c17
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_main.c386
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h5
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c21
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_txrx_common.h50
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_type.h4
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c15
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c801
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/Makefile1
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/defines.h10
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/ethtool.c2
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/ipsec.c670
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/ipsec.h66
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/ixgbevf.h33
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c80
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/mbx.h5
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/vf.c4
-rw-r--r--drivers/net/ethernet/lantiq_etop.c12
-rw-r--r--drivers/net/ethernet/lantiq_xrx200.c567
-rw-r--r--drivers/net/ethernet/marvell/Kconfig3
-rw-r--r--drivers/net/ethernet/marvell/Makefile1
-rw-r--r--drivers/net/ethernet/marvell/mv643xx_eth.c6
-rw-r--r--drivers/net/ethernet/marvell/mvneta.c47
-rw-r--r--drivers/net/ethernet/marvell/mvpp2/mvpp2.h29
-rw-r--r--drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c464
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/Kconfig17
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/Makefile6
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/Makefile11
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/cgx.c721
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/cgx.h111
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/cgx_fw_if.h186
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/common.h211
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/mbox.c303
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/mbox.h525
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/npc.h262
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/npc_profile.h5709
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu.c1772
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu.h368
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c515
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c1959
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c472
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c816
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.c71
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h502
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h917
-rw-r--r--drivers/net/ethernet/marvell/pxa168_eth.c7
-rw-r--r--drivers/net/ethernet/mediatek/mtk_eth_soc.c16
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/alloc.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_main.c9
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_netdev.c1
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_rx.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_tx.c6
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/icm.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/main.c43
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4_en.h2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/cmd.c12
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/cq.c4
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/diag/fs_tracepoint.h8
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en.h48
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/fs.h2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/port.c208
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/port.h12
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c7
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_common.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c181
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c56
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_main.c271
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_rep.c254
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_rx.c104
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_stats.c60
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_stats.h4
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_tc.c740
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_tx.c22
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eq.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eswitch.c12
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eswitch.h58
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c484
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c11
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c89
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fs_core.c195
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fs_core.h18
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c201
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fw.c50
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/health.c25
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c188
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h15
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c19
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c34
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/clock.h8
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/main.c29
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h24
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/qp.c81
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/srq.c32
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/transobj.c5
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/vport.c9
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/wq.c125
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/wq.h11
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/Makefile3
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/core.c26
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/core.h4
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c17
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/pci.c11
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/pci_hw.h2
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/reg.h625
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/resources.h4
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.c173
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.h106
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum2_kvdl.c1
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c488
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c225
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c982
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.h49
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c249
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c138
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h15
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c575
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/trap.h2
-rw-r--r--drivers/net/ethernet/micrel/ks8695net.c2
-rw-r--r--drivers/net/ethernet/micrel/ks8851_mll.c4
-rw-r--r--drivers/net/ethernet/microchip/Kconfig1
-rw-r--r--drivers/net/ethernet/microchip/lan743x_main.c7
-rw-r--r--drivers/net/ethernet/microchip/lan743x_ptp.c4
-rw-r--r--drivers/net/ethernet/mscc/Kconfig2
-rw-r--r--drivers/net/ethernet/mscc/ocelot.c24
-rw-r--r--drivers/net/ethernet/mscc/ocelot.h79
-rw-r--r--drivers/net/ethernet/mscc/ocelot_board.c65
-rw-r--r--drivers/net/ethernet/mscc/ocelot_dev_gmii.h154
-rw-r--r--drivers/net/ethernet/mscc/ocelot_hsio.h785
-rw-r--r--drivers/net/ethernet/mscc/ocelot_regs.c93
-rw-r--r--drivers/net/ethernet/myricom/myri10ge/myri10ge.c1
-rw-r--r--drivers/net/ethernet/neterion/s2io.c7
-rw-r--r--drivers/net/ethernet/neterion/s2io.h22
-rw-r--r--drivers/net/ethernet/neterion/vxge/vxge-config.c1
-rw-r--r--drivers/net/ethernet/neterion/vxge/vxge-config.h20
-rw-r--r--drivers/net/ethernet/neterion/vxge/vxge-traffic.c3
-rw-r--r--drivers/net/ethernet/netronome/nfp/abm/ctrl.c67
-rw-r--r--drivers/net/ethernet/netronome/nfp/abm/main.c69
-rw-r--r--drivers/net/ethernet/netronome/nfp/abm/main.h35
-rw-r--r--drivers/net/ethernet/netronome/nfp/bpf/cmsg.c105
-rw-r--r--drivers/net/ethernet/netronome/nfp/bpf/fw.h45
-rw-r--r--drivers/net/ethernet/netronome/nfp/bpf/jit.c415
-rw-r--r--drivers/net/ethernet/netronome/nfp/bpf/main.c91
-rw-r--r--drivers/net/ethernet/netronome/nfp/bpf/main.h107
-rw-r--r--drivers/net/ethernet/netronome/nfp/bpf/offload.c77
-rw-r--r--drivers/net/ethernet/netronome/nfp/bpf/verifier.c234
-rw-r--r--drivers/net/ethernet/netronome/nfp/flower/action.c85
-rw-r--r--drivers/net/ethernet/netronome/nfp/flower/cmsg.c34
-rw-r--r--drivers/net/ethernet/netronome/nfp/flower/cmsg.h34
-rw-r--r--drivers/net/ethernet/netronome/nfp/flower/lag_conf.c34
-rw-r--r--drivers/net/ethernet/netronome/nfp/flower/main.c49
-rw-r--r--drivers/net/ethernet/netronome/nfp/flower/main.h57
-rw-r--r--drivers/net/ethernet/netronome/nfp/flower/match.c34
-rw-r--r--drivers/net/ethernet/netronome/nfp/flower/metadata.c179
-rw-r--r--drivers/net/ethernet/netronome/nfp/flower/offload.c65
-rw-r--r--drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c37
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_abi.h35
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_app.c39
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_app.h39
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_app_nic.c34
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_asm.c34
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_asm.h43
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_devlink.c54
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_hwmon.c34
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_main.c78
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_main.h34
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net.h34
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net_common.c111
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.c41
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h43
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net_debugdump.c84
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c34
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c34
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net_main.c42
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net_repr.c34
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net_repr.h34
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net_sriov.c34
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net_sriov.h34
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c34
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_port.c34
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_port.h34
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_shared_buf.c35
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/crc32.h34
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp.h34
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000/nfp6000.h34
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000/nfp_xpb.h34
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c84
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.h34
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp_arm.h34
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h46
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c70
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpplib.c46
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp_hwinfo.c34
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp_mip.c34
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp_mutex.c34
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.c66
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h72
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c364
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h46
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_cmds.c34
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c34
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c34
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c303
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c46
-rw-r--r--drivers/net/ethernet/netronome/nfp/nic/main.c34
-rw-r--r--drivers/net/ethernet/ni/Kconfig3
-rw-r--r--drivers/net/ethernet/ni/nixge.c168
-rw-r--r--drivers/net/ethernet/nxp/lpc_eth.c78
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c29
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed.h3
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_cxt.c1
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_dcbx.c5
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_debug.c248
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_dev.c14
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_fcoe.c11
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_hsi.h358
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_int.c2
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_iscsi.c1
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_iwarp.c13
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_l2.c12
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_ll2.c25
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_ll2.h4
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_main.c258
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_mcp.c325
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_mcp.h51
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_ooo.c14
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_rdma.c3
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_roce.c16
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_sp.h14
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_sp_commands.c24
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_spq.c72
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_sriov.c1
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_vf.c7
-rw-r--r--drivers/net/ethernet/qlogic/qede/qede.h2
-rw-r--r--drivers/net/ethernet/qlogic/qede/qede_ethtool.c102
-rw-r--r--drivers/net/ethernet/qlogic/qla3xxx.c2
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic.h8
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c4
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h3
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c2
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h3
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c20
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c46
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c6
-rw-r--r--drivers/net/ethernet/qualcomm/qca_7k.c34
-rw-r--r--drivers/net/ethernet/qualcomm/qca_7k.h2
-rw-r--r--drivers/net/ethernet/qualcomm/qca_debug.c1
-rw-r--r--drivers/net/ethernet/qualcomm/qca_spi.c28
-rw-r--r--drivers/net/ethernet/qualcomm/qca_spi.h1
-rw-r--r--drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c7
-rw-r--r--drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c6
-rw-r--r--drivers/net/ethernet/rdc/r6040.c12
-rw-r--r--drivers/net/ethernet/realtek/r8169.c213
-rw-r--r--drivers/net/ethernet/renesas/ravb.h6
-rw-r--r--drivers/net/ethernet/renesas/ravb_main.c150
-rw-r--r--drivers/net/ethernet/rocker/rocker_main.c5
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c4
-rw-r--r--drivers/net/ethernet/sfc/efx.c34
-rw-r--r--drivers/net/ethernet/sfc/falcon/efx.c34
-rw-r--r--drivers/net/ethernet/smsc/smc911x.c3
-rw-r--r--drivers/net/ethernet/smsc/smc91x.c6
-rw-r--r--drivers/net/ethernet/smsc/smsc911x.c9
-rw-r--r--drivers/net/ethernet/smsc/smsc9420.c6
-rw-r--r--drivers/net/ethernet/socionext/netsec.c45
-rw-r--r--drivers/net/ethernet/socionext/sni_ave.c29
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/common.h3
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/descs_com.h2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c12
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h12
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c19
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c19
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/enh_desc.c2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/hwif.c8
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/ring_mode.c6
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c15
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c2
-rw-r--r--drivers/net/ethernet/sun/ldmvsw.c2
-rw-r--r--drivers/net/ethernet/sun/sunbmac.c3
-rw-r--r--drivers/net/ethernet/sun/sunhme.c2
-rw-r--r--drivers/net/ethernet/sun/sunqe.c2
-rw-r--r--drivers/net/ethernet/sun/sunvnet.c2
-rw-r--r--drivers/net/ethernet/sun/sunvnet_common.c14
-rw-r--r--drivers/net/ethernet/sun/sunvnet_common.h7
-rw-r--r--drivers/net/ethernet/ti/cpsw.c72
-rw-r--r--drivers/net/ethernet/ti/cpsw_ale.c12
-rw-r--r--drivers/net/ethernet/ti/cpsw_ale.h8
-rw-r--r--drivers/net/ethernet/ti/davinci_emac.c6
-rw-r--r--drivers/net/ethernet/ti/netcp_core.c22
-rw-r--r--drivers/net/ethernet/ti/netcp_ethss.c42
-rw-r--r--drivers/net/ethernet/toshiba/ps3_gelic_net.c4
-rw-r--r--drivers/net/ethernet/toshiba/ps3_gelic_net.h2
-rw-r--r--drivers/net/ethernet/toshiba/ps3_gelic_wireless.c9
-rw-r--r--drivers/net/ethernet/toshiba/spider_net.c4
-rw-r--r--drivers/net/ethernet/toshiba/tc35815.c8
-rw-r--r--drivers/net/ethernet/wiznet/w5300.c6
-rw-r--r--drivers/net/ethernet/xilinx/ll_temac_main.c3
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_axienet_main.c3
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_emaclite.c12
-rw-r--r--drivers/net/fddi/Kconfig11
-rw-r--r--drivers/net/fddi/Makefile1
-rw-r--r--drivers/net/fddi/defza.c1565
-rw-r--r--drivers/net/fddi/defza.h792
-rw-r--r--drivers/net/fddi/skfp/ecm.c3
-rw-r--r--drivers/net/fddi/skfp/h/cmtdef.h9
-rw-r--r--drivers/net/fddi/skfp/pcmplc.c11
-rw-r--r--drivers/net/geneve.c61
-rw-r--r--drivers/net/hamradio/6pack.c21
-rw-r--r--drivers/net/hamradio/mkiss.c21
-rw-r--r--drivers/net/hamradio/yam.c4
-rw-r--r--drivers/net/hyperv/hyperv_net.h51
-rw-r--r--drivers/net/hyperv/netvsc.c18
-rw-r--r--drivers/net/hyperv/netvsc_drv.c97
-rw-r--r--drivers/net/hyperv/rndis_filter.c97
-rw-r--r--drivers/net/ieee802154/adf7242.c3
-rw-r--r--drivers/net/ieee802154/ca8210.c6
-rw-r--r--drivers/net/ieee802154/mac802154_hwsim.c8
-rw-r--r--drivers/net/ieee802154/mcr20a.c72
-rw-r--r--drivers/net/loopback.c10
-rw-r--r--drivers/net/macsec.c38
-rw-r--r--drivers/net/macvlan.c2
-rw-r--r--drivers/net/net_failover.c8
-rw-r--r--drivers/net/netdevsim/bpf.c8
-rw-r--r--drivers/net/nlmon.c6
-rw-r--r--drivers/net/ntb_netdev.c30
-rw-r--r--drivers/net/phy/Kconfig2
-rw-r--r--drivers/net/phy/aquantia.c12
-rw-r--r--drivers/net/phy/at803x.c2
-rw-r--r--drivers/net/phy/bcm63xx.c9
-rw-r--r--drivers/net/phy/broadcom.c18
-rw-r--r--drivers/net/phy/dp83640.c18
-rw-r--r--drivers/net/phy/et1011c.c3
-rw-r--r--drivers/net/phy/marvell.c67
-rw-r--r--drivers/net/phy/marvell10g.c17
-rw-r--r--drivers/net/phy/mdio-bcm-unimac.c83
-rw-r--r--drivers/net/phy/mdio-mux-bcm-iproc.c6
-rw-r--r--drivers/net/phy/mdio-mux-gpio.c11
-rw-r--r--drivers/net/phy/mdio-thunder.c4
-rw-r--r--drivers/net/phy/mdio_bus.c1
-rw-r--r--drivers/net/phy/micrel.c130
-rw-r--r--drivers/net/phy/microchip.c33
-rw-r--r--drivers/net/phy/microchip_t1.c2
-rw-r--r--drivers/net/phy/mscc.c1520
-rw-r--r--drivers/net/phy/phy-c45.c2
-rw-r--r--drivers/net/phy/phy.c132
-rw-r--r--drivers/net/phy/phy_device.c301
-rw-r--r--drivers/net/phy/phylink.c78
-rw-r--r--drivers/net/phy/realtek.c2
-rw-r--r--drivers/net/phy/sfp.c9
-rw-r--r--drivers/net/phy/ste10Xp.c4
-rw-r--r--drivers/net/ppp/ppp_generic.c2
-rw-r--r--drivers/net/ppp/ppp_mppe.c27
-rw-r--r--drivers/net/slip/slip.c25
-rw-r--r--drivers/net/tap.c94
-rw-r--r--drivers/net/team/team.c11
-rw-r--r--drivers/net/thunderbolt.c5
-rw-r--r--drivers/net/tun.c341
-rw-r--r--drivers/net/usb/asix_common.c3
-rw-r--r--drivers/net/usb/ax88179_178a.c3
-rw-r--r--drivers/net/usb/cdc_ncm.c6
-rw-r--r--drivers/net/usb/lan78xx.c66
-rw-r--r--drivers/net/usb/lan78xx.h14
-rw-r--r--drivers/net/usb/qmi_wwan.c1
-rw-r--r--drivers/net/usb/r8152.c3
-rw-r--r--drivers/net/usb/smsc75xx.c4
-rw-r--r--drivers/net/usb/smsc95xx.c12
-rw-r--r--drivers/net/usb/sr9800.c3
-rw-r--r--drivers/net/usb/usbnet.c13
-rw-r--r--drivers/net/veth.c200
-rw-r--r--drivers/net/virtio_net.c68
-rw-r--r--drivers/net/vrf.c11
-rw-r--r--drivers/net/vsockmon.c14
-rw-r--r--drivers/net/vxlan.c203
-rw-r--r--drivers/net/wan/c101.c1
-rw-r--r--drivers/net/wan/fsl_ucc_hdlc.c77
-rw-r--r--drivers/net/wan/fsl_ucc_hdlc.h1
-rw-r--r--drivers/net/wan/pci200syn.c1
-rw-r--r--drivers/net/wan/x25_asy.c19
-rw-r--r--drivers/net/wimax/i2400m/control.c2
-rw-r--r--drivers/net/wireless/ath/ath10k/Kconfig4
-rw-r--r--drivers/net/wireless/ath/ath10k/Makefile4
-rw-r--r--drivers/net/wireless/ath/ath10k/ahb.c13
-rw-r--r--drivers/net/wireless/ath/ath10k/bmi.c23
-rw-r--r--drivers/net/wireless/ath/ath10k/bmi.h36
-rw-r--r--drivers/net/wireless/ath/ath10k/ce.c42
-rw-r--r--drivers/net/wireless/ath/ath10k/ce.h11
-rw-r--r--drivers/net/wireless/ath/ath10k/core.c766
-rw-r--r--drivers/net/wireless/ath/ath10k/core.h69
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.c144
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.h10
-rw-r--r--drivers/net/wireless/ath/ath10k/debugfs_sta.c130
-rw-r--r--drivers/net/wireless/ath/ath10k/htc.c82
-rw-r--r--drivers/net/wireless/ath/ath10k/htt.h52
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_rx.c297
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_tx.c155
-rw-r--r--drivers/net/wireless/ath/ath10k/hw.c191
-rw-r--r--drivers/net/wireless/ath/ath10k/hw.h37
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c154
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.h1
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.c101
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.h3
-rw-r--r--drivers/net/wireless/ath/ath10k/qmi.c1019
-rw-r--r--drivers/net/wireless/ath/ath10k/qmi.h129
-rw-r--r--drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c2072
-rw-r--r--drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h677
-rw-r--r--drivers/net/wireless/ath/ath10k/rx_desc.h15
-rw-r--r--drivers/net/wireless/ath/ath10k/sdio.c8
-rw-r--r--drivers/net/wireless/ath/ath10k/snoc.c281
-rw-r--r--drivers/net/wireless/ath/ath10k/snoc.h4
-rw-r--r--drivers/net/wireless/ath/ath10k/targaddrs.h4
-rw-r--r--drivers/net/wireless/ath/ath10k/txrx.c3
-rw-r--r--drivers/net/wireless/ath/ath10k/usb.c7
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-ops.h21
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-tlv.c198
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-tlv.h254
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.c84
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.h100
-rw-r--r--drivers/net/wireless/ath/ath10k/wow.c170
-rw-r--r--drivers/net/wireless/ath/ath5k/debug.c2
-rw-r--r--drivers/net/wireless/ath/ath6kl/init.c4
-rw-r--r--drivers/net/wireless/ath/ath6kl/main.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/antenna.c8
-rw-r--r--drivers/net/wireless/ath/ath9k/ar5008_phy.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/common-debug.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/common-debug.h4
-rw-r--r--drivers/net/wireless/ath/ath9k/common-spectral.c83
-rw-r--r--drivers/net/wireless/ath/ath9k/common-spectral.h17
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c37
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.h20
-rw-r--r--drivers/net/wireless/ath/ath9k/debug_sta.c20
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c6
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c18
-rw-r--r--drivers/net/wireless/ath/ath9k/tx99.c10
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c18
-rw-r--r--drivers/net/wireless/ath/carl9170/tx.c4
-rw-r--r--drivers/net/wireless/ath/wcn36xx/dxe.c19
-rw-r--r--drivers/net/wireless/ath/wcn36xx/smd.c4
-rw-r--r--drivers/net/wireless/ath/wil6210/cfg80211.c333
-rw-r--r--drivers/net/wireless/ath/wil6210/debugfs.c63
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c13
-rw-r--r--drivers/net/wireless/ath/wil6210/pcie_bus.c1
-rw-r--r--drivers/net/wireless/ath/wil6210/pm.c3
-rw-r--r--drivers/net/wireless/ath/wil6210/rx_reorder.c12
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.c98
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx_edma.c26
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h19
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c350
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.h2
-rw-r--r--drivers/net/wireless/broadcom/b43/b43.h2
-rw-r--r--drivers/net/wireless/broadcom/b43/dma.c8
-rw-r--r--drivers/net/wireless/broadcom/b43/main.c10
-rw-r--r--drivers/net/wireless/broadcom/b43legacy/dma.c2
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c2
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c8
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c4
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c2
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c26
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.h2
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c1
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c7
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.c3
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c32
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.h1
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c4
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmutil/d11.c34
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h3
-rw-r--r--drivers/net/wireless/intel/ipw2x00/ipw2200.c2
-rw-r--r--drivers/net/wireless/intel/iwlegacy/4965.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/cfg/1000.c5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/cfg/2000.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/cfg/22000.c73
-rw-r--r--drivers/net/wireless/intel/iwlwifi/cfg/5000.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/cfg/6000.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/cfg/7000.c5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/cfg/8000.c5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/cfg/9000.c6
-rw-r--r--drivers/net/wireless/intel/iwlwifi/dvm/agn.h5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/dvm/calib.c5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/dvm/calib.h5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/dvm/commands.h5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/dvm/dev.h4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/dvm/devices.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/dvm/led.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/dvm/led.h4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/dvm/lib.c5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/dvm/main.c6
-rw-r--r--drivers/net/wireless/intel/iwlwifi/dvm/power.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/dvm/power.h4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/dvm/rs.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/dvm/rs.h4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/dvm/rx.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/dvm/rxon.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/dvm/scan.c5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/dvm/sta.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/dvm/tt.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/dvm/tt.h4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/dvm/tx.c5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/dvm/ucode.c5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/acpi.c3
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/acpi.h3
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/coex.h3
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/commands.h3
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/d3.h89
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/debug.h32
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h49
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/mac.h14
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h81
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/power.h30
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/rs.h78
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/rx.h189
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/scan.h6
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/sta.h4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/tx.h8
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/dbg.c649
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/dbg.h141
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/debugfs.c188
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/debugfs.h3
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/error-dump.h10
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/file.h39
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/img.h46
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/notif-wait.c5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/notif-wait.h5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/runtime.h3
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-agn-hw.h5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-config.h18
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-context-info.h25
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-csr.h6
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-debug.c5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-debug.h4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h40
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-devtrace-io.h4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h69
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-devtrace-msg.h4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-devtrace-ucode.h4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-devtrace.c7
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-devtrace.h22
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-drv.c99
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-drv.h5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c7
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-eeprom-read.c5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-eeprom-read.h5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-fh.h5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-io.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-io.h4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-modparams.h3
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c66
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h7
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-phy-db.c5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-phy-db.h5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-prph.h5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-scd.h5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-trans.c5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-trans.h45
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/binding.c5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/coex.c23
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/constants.h5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/d3.c207
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c50
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/debugfs.h5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/fw.c49
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/led.c5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c82
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c137
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mvm.h90
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/nvm.c30
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/offloading.c5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/ops.c108
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/power.c5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/quota.c5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c35
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rs.c49
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rs.h4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rx.c34
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c782
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/scan.c144
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/sf.c5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/sta.c867
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/sta.h8
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/tdls.c3
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/testmode.h5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/time-event.c11
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/time-event.h5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/tof.c5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/tof.h5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/tt.c5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/tx.c211
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/utils.c453
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c28
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/drv.c60
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/internal.h109
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/rx.c52
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c9
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/trans.c269
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c212
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/tx.c108
-rw-r--r--drivers/net/wireless/intersil/orinoco/orinoco_usb.c6
-rw-r--r--drivers/net/wireless/intersil/p54/txrx.c4
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c65
-rw-r--r--drivers/net/wireless/marvell/libertas/if_cs.c4
-rw-r--r--drivers/net/wireless/marvell/libertas/if_sdio.c8
-rw-r--r--drivers/net/wireless/marvell/libertas/if_spi.c4
-rw-r--r--drivers/net/wireless/marvell/libertas/if_usb.c7
-rw-r--r--drivers/net/wireless/marvell/libertas/main.c17
-rw-r--r--drivers/net/wireless/marvell/libertas_tf/if_usb.c5
-rw-r--r--drivers/net/wireless/marvell/mwifiex/usb.c13
-rw-r--r--drivers/net/wireless/mediatek/mt76/Kconfig32
-rw-r--r--drivers/net/wireless/mediatek/mt76/Makefile27
-rw-r--r--drivers/net/wireless/mediatek/mt76/debugfs.c31
-rw-r--r--drivers/net/wireless/mediatek/mt76/dma.c16
-rw-r--r--drivers/net/wireless/mediatek/mt76/dma.h51
-rw-r--r--drivers/net/wireless/mediatek/mt76/mac80211.c12
-rw-r--r--drivers/net/wireless/mediatek/mt76/mmio.c40
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76.h136
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig20
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/Makefile13
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/core.c34
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c85
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/dma.c522
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/dma.h126
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c567
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h135
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/init.c570
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/initvals.h406
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/mac.c489
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/mac.h154
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/main.c349
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c656
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h69
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h315
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/pci.c221
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/pci_mcu.c147
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/phy.c538
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/regs.h651
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/trace.h15
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/tx.c270
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/usb.c382
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/usb.h61
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/usb_mcu.c175
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/util.c42
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02.h215
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_dfs.h (renamed from drivers/net/wireless/mediatek/mt76/mt76x2_dfs.h)40
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_dma.h77
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.c153
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h (renamed from drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h)144
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_mac.c (renamed from drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c)680
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_mac.h (renamed from drivers/net/wireless/mediatek/mt76/mt76x2_mac.h)140
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c224
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h113
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c260
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_phy.c258
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_phy.h61
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_regs.h (renamed from drivers/net/wireless/mediatek/mt76/mt76x2_regs.h)78
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_trace.c (renamed from drivers/net/wireless/mediatek/mt76/mt76x2_trace.c)2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_trace.h (renamed from drivers/net/wireless/mediatek/mt76/mt76x2_trace.h)33
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c202
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_usb.h34
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c107
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c359
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_util.c446
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2.h330
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig20
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/Makefile16
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/debugfs.c (renamed from drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c)35
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/dfs.h (renamed from drivers/net/wireless/mediatek/mt76/mt76x2_dma.h)21
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c (renamed from drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c)346
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.h94
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/init.c (renamed from drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c)85
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/mac.c54
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/mac.h37
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c123
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/mcu.h (renamed from drivers/net/wireless/mediatek/mt76/mt76x2_mcu.h)79
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h105
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h60
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/pci.c (renamed from drivers/net/wireless/mediatek/mt76/mt76x2_pci.c)8
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/pci_dfs.c (renamed from drivers/net/wireless/mediatek/mt76/mt76x2_dfs.c)145
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c (renamed from drivers/net/wireless/mediatek/mt76/mt76x2_init.c)160
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c (renamed from drivers/net/wireless/mediatek/mt76/mt76x2_mac.c)111
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c (renamed from drivers/net/wireless/mediatek/mt76/mt76x2_main.c)130
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/pci_mcu.c188
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c (renamed from drivers/net/wireless/mediatek/mt76/mt76x2_phy.c)164
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/pci_tx.c (renamed from drivers/net/wireless/mediatek/mt76/mt76x2_tx.c)48
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/phy.c (renamed from drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c)199
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/usb.c (renamed from drivers/net/wireless/mediatek/mt76/mt76x2_usb.c)25
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c (renamed from drivers/net/wireless/mediatek/mt76/mt76x2u_init.c)81
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c (renamed from drivers/net/wireless/mediatek/mt76/mt76x2u_mac.c)42
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c (renamed from drivers/net/wireless/mediatek/mt76/mt76x2u_main.c)70
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/usb_mcu.c (renamed from drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c)235
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c (renamed from drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c)121
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2_common.c350
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2_core.c88
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2_dma.c163
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c427
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c149
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2u.h83
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2u_core.c108
-rw-r--r--drivers/net/wireless/mediatek/mt76/tx.c53
-rw-r--r--drivers/net/wireless/mediatek/mt76/usb.c129
-rw-r--r--drivers/net/wireless/mediatek/mt76/usb_mcu.c204
-rw-r--r--drivers/net/wireless/quantenna/Kconfig2
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/Kconfig2
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/Makefile3
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/bus.h5
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/cfg80211.c196
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/commands.c535
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/core.c39
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/core.h8
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/event.c18
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c392
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/pcie/pcie_priv.h85
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c1249
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_ipc.h (renamed from drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_ipc.h)80
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_regs.h121
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c1494
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_bus_priv.h91
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_regs_pearl.h356
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/qlink.h5
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/qlink_util.h8
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/qtn_hw_ids.h14
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/shm_ipc.c13
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/shm_ipc.h4
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2800lib.c154
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2800lib.h3
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2800mmio.c277
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2800mmio.h1
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2800pci.c2
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2800usb.c143
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2x00.h3
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2x00debug.c18
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2x00mac.c4
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2x00queue.c2
-rw-r--r--drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c13
-rw-r--r--drivers/net/wireless/realtek/rtl818x/rtl8187/leds.c2
-rw-r--r--drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c7
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c6
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c6
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c4
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c71
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/wifi.h4
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_hal.c4
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_mac80211.c2
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_usb.c11
-rw-r--r--drivers/net/wireless/rsi/rsi_common.h1
-rw-r--r--drivers/net/wireless/st/cw1200/txrx.c4
-rw-r--r--drivers/net/wireless/ti/wlcore/main.c48
-rw-r--r--drivers/net/wireless/ti/wlcore/sdio.c17
-rw-r--r--drivers/net/wireless/ti/wlcore/wlcore.h2
-rw-r--r--drivers/net/wireless/zydas/zd1211rw/zd_mac.c2
-rw-r--r--drivers/net/xen-netback/common.h3
-rw-r--r--drivers/net/xen-netback/hash.c51
-rw-r--r--drivers/net/xen-netback/interface.c6
-rw-r--r--drivers/net/xen-netback/netback.c3
-rw-r--r--drivers/net/xen-netback/xenbus.c3
-rw-r--r--drivers/nfc/nfcmrvl/uart.c5
-rw-r--r--drivers/ntb/hw/idt/Kconfig5
-rw-r--r--drivers/ntb/hw/idt/ntb_hw_idt.c327
-rw-r--r--drivers/ntb/hw/idt/ntb_hw_idt.h87
-rw-r--r--drivers/ntb/hw/intel/ntb_hw_gen1.c2
-rw-r--r--drivers/ntb/ntb_transport.c88
-rw-r--r--drivers/nvdimm/blk.c2
-rw-r--r--drivers/nvdimm/btt.c2
-rw-r--r--drivers/nvdimm/bus.c20
-rw-r--r--drivers/nvdimm/dimm.c6
-rw-r--r--drivers/nvdimm/dimm_devs.c60
-rw-r--r--drivers/nvdimm/label.c144
-rw-r--r--drivers/nvdimm/label.h4
-rw-r--r--drivers/nvdimm/namespace_devs.c1
-rw-r--r--drivers/nvdimm/nd-core.h1
-rw-r--r--drivers/nvdimm/nd.h2
-rw-r--r--drivers/nvdimm/pfn_devs.c61
-rw-r--r--drivers/nvdimm/pmem.c6
-rw-r--r--drivers/nvdimm/region_devs.c11
-rw-r--r--drivers/nvme/host/core.c57
-rw-r--r--drivers/nvme/host/fabrics.c37
-rw-r--r--drivers/nvme/host/fabrics.h2
-rw-r--r--drivers/nvme/host/fc.c155
-rw-r--r--drivers/nvme/host/lightnvm.c137
-rw-r--r--drivers/nvme/host/multipath.c80
-rw-r--r--drivers/nvme/host/nvme.h36
-rw-r--r--drivers/nvme/host/pci.c112
-rw-r--r--drivers/nvme/host/rdma.c78
-rw-r--r--drivers/nvme/host/trace.h28
-rw-r--r--drivers/nvme/target/admin-cmd.c4
-rw-r--r--drivers/nvme/target/configfs.c47
-rw-r--r--drivers/nvme/target/core.c183
-rw-r--r--drivers/nvme/target/discovery.c6
-rw-r--r--drivers/nvme/target/fc.c136
-rw-r--r--drivers/nvme/target/fcloop.c1
-rw-r--r--drivers/nvme/target/io-cmd-bdev.c12
-rw-r--r--drivers/nvme/target/io-cmd-file.c5
-rw-r--r--drivers/nvme/target/nvmet.h18
-rw-r--r--drivers/nvme/target/rdma.c22
-rw-r--r--drivers/nvmem/core.c533
-rw-r--r--drivers/nvmem/lpc18xx_eeprom.c7
-rw-r--r--drivers/nvmem/mxs-ocotp.c4
-rw-r--r--drivers/nvmem/sunxi_sid.c22
-rw-r--r--drivers/of/base.c201
-rw-r--r--drivers/of/device.c21
-rw-r--r--drivers/of/fdt.c35
-rw-r--r--drivers/of/irq.c5
-rw-r--r--drivers/of/of_mdio.c12
-rw-r--r--drivers/of/of_numa.c28
-rw-r--r--drivers/of/of_private.h8
-rw-r--r--drivers/of/of_reserved_mem.c14
-rw-r--r--drivers/of/overlay.c4
-rw-r--r--drivers/of/platform.c8
-rw-r--r--drivers/of/unittest-data/overlay_15.dts4
-rw-r--r--drivers/of/unittest-data/tests-overlay.dtsi4
-rw-r--r--drivers/of/unittest.c59
-rw-r--r--drivers/opp/core.c149
-rw-r--r--drivers/opp/cpu.c15
-rw-r--r--drivers/opp/of.c237
-rw-r--r--drivers/opp/opp.h19
-rw-r--r--drivers/parisc/Makefile3
-rw-r--r--drivers/parisc/ccio-dma.c12
-rw-r--r--drivers/parisc/ccio-rm-dma.c202
-rw-r--r--drivers/parisc/dino.c5
-rw-r--r--drivers/parisc/sba_iommu.c17
-rw-r--r--drivers/pci/Kconfig20
-rw-r--r--drivers/pci/Makefile2
-rw-r--r--drivers/pci/access.c4
-rw-r--r--drivers/pci/controller/Kconfig4
-rw-r--r--drivers/pci/controller/dwc/Makefile2
-rw-r--r--drivers/pci/controller/dwc/pci-dra7xx.c11
-rw-r--r--drivers/pci/controller/dwc/pci-imx6.c176
-rw-r--r--drivers/pci/controller/dwc/pci-keystone-dw.c484
-rw-r--r--drivers/pci/controller/dwc/pci-keystone.c788
-rw-r--r--drivers/pci/controller/dwc/pci-keystone.h57
-rw-r--r--drivers/pci/controller/dwc/pcie-designware.h4
-rw-r--r--drivers/pci/controller/dwc/pcie-kirin.c4
-rw-r--r--drivers/pci/controller/dwc/pcie-qcom.c56
-rw-r--r--drivers/pci/controller/pci-aardvark.c129
-rw-r--r--drivers/pci/controller/pci-host-common.c8
-rw-r--r--drivers/pci/controller/pci-mvebu.c436
-rw-r--r--drivers/pci/controller/pcie-cadence-ep.c13
-rw-r--r--drivers/pci/controller/pcie-cadence-host.c7
-rw-r--r--drivers/pci/controller/pcie-cadence.c24
-rw-r--r--drivers/pci/controller/pcie-iproc.c8
-rw-r--r--drivers/pci/controller/pcie-mediatek.c321
-rw-r--r--drivers/pci/controller/pcie-mobiveil.c7
-rw-r--r--drivers/pci/controller/pcie-xilinx-nwl.c9
-rw-r--r--drivers/pci/controller/pcie-xilinx.c7
-rw-r--r--drivers/pci/controller/vmd.c6
-rw-r--r--drivers/pci/hotplug/TODO74
-rw-r--r--drivers/pci/hotplug/acpiphp.h12
-rw-r--r--drivers/pci/hotplug/acpiphp_core.c40
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c2
-rw-r--r--drivers/pci/hotplug/acpiphp_ibm.c2
-rw-r--r--drivers/pci/hotplug/cpci_hotplug.h11
-rw-r--r--drivers/pci/hotplug/cpci_hotplug_core.c105
-rw-r--r--drivers/pci/hotplug/cpci_hotplug_pci.c6
-rw-r--r--drivers/pci/hotplug/cpqphp.h9
-rw-r--r--drivers/pci/hotplug/cpqphp_core.c61
-rw-r--r--drivers/pci/hotplug/cpqphp_ctrl.c31
-rw-r--r--drivers/pci/hotplug/ibmphp.h9
-rw-r--r--drivers/pci/hotplug/ibmphp_core.c121
-rw-r--r--drivers/pci/hotplug/ibmphp_ebda.c70
-rw-r--r--drivers/pci/hotplug/pci_hotplug_core.c53
-rw-r--r--drivers/pci/hotplug/pciehp.h133
-rw-r--r--drivers/pci/hotplug/pciehp_core.c168
-rw-r--r--drivers/pci/hotplug/pciehp_ctrl.c263
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c184
-rw-r--r--drivers/pci/hotplug/pciehp_pci.c41
-rw-r--r--drivers/pci/hotplug/pnv_php.c40
-rw-r--r--drivers/pci/hotplug/rpaphp.h10
-rw-r--r--drivers/pci/hotplug/rpaphp_core.c20
-rw-r--r--drivers/pci/hotplug/rpaphp_pci.c11
-rw-r--r--drivers/pci/hotplug/rpaphp_slot.c22
-rw-r--r--drivers/pci/hotplug/s390_pci_hpc.c44
-rw-r--r--drivers/pci/hotplug/sgi_hotplug.c63
-rw-r--r--drivers/pci/hotplug/shpchp.h8
-rw-r--r--drivers/pci/hotplug/shpchp_core.c48
-rw-r--r--drivers/pci/hotplug/shpchp_ctrl.c21
-rw-r--r--drivers/pci/iov.c3
-rw-r--r--drivers/pci/msi.c9
-rw-r--r--drivers/pci/of.c101
-rw-r--r--drivers/pci/p2pdma.c805
-rw-r--r--drivers/pci/pci-acpi.c58
-rw-r--r--drivers/pci/pci-bridge-emul.c408
-rw-r--r--drivers/pci/pci-bridge-emul.h124
-rw-r--r--drivers/pci/pci-mid.c4
-rw-r--r--drivers/pci/pci.c139
-rw-r--r--drivers/pci/pci.h78
-rw-r--r--drivers/pci/pcie/Kconfig4
-rw-r--r--drivers/pci/pcie/aer.c239
-rw-r--r--drivers/pci/pcie/aer_inject.c96
-rw-r--r--drivers/pci/pcie/aspm.c4
-rw-r--r--drivers/pci/pcie/dpc.c72
-rw-r--r--drivers/pci/pcie/err.c281
-rw-r--r--drivers/pci/pcie/pme.c30
-rw-r--r--drivers/pci/pcie/portdrv.h32
-rw-r--r--drivers/pci/pcie/portdrv_core.c21
-rw-r--r--drivers/pci/pcie/portdrv_pci.c31
-rw-r--r--drivers/pci/probe.c24
-rw-r--r--drivers/pci/quirks.c96
-rw-r--r--drivers/pci/remove.c4
-rw-r--r--drivers/pci/setup-bus.c28
-rw-r--r--drivers/pci/slot.c3
-rw-r--r--drivers/pcmcia/electra_cf.c2
-rw-r--r--drivers/pcmcia/pcmcia_resource.c4
-rw-r--r--drivers/pcmcia/ricoh.h35
-rw-r--r--drivers/pcmcia/soc_common.c9
-rw-r--r--drivers/pcmcia/yenta_socket.c3
-rw-r--r--drivers/perf/arm_pmu.c8
-rw-r--r--drivers/perf/arm_pmu_platform.c6
-rw-r--r--drivers/phy/Kconfig3
-rw-r--r--drivers/phy/Makefile3
-rw-r--r--drivers/phy/broadcom/Kconfig3
-rw-r--r--drivers/phy/broadcom/phy-bcm-cygnus-pcie.c4
-rw-r--r--drivers/phy/broadcom/phy-brcm-sata.c74
-rw-r--r--drivers/phy/broadcom/phy-brcm-usb.c4
-rw-r--r--drivers/phy/cadence/Kconfig10
-rw-r--r--drivers/phy/cadence/Makefile1
-rw-r--r--drivers/phy/cadence/phy-cadence-dp.c541
-rw-r--r--drivers/phy/lantiq/phy-lantiq-rcu-usb2.c5
-rw-r--r--drivers/phy/marvell/Kconfig11
-rw-r--r--drivers/phy/marvell/Makefile1
-rw-r--r--drivers/phy/marvell/phy-berlin-sata.c6
-rw-r--r--drivers/phy/marvell/phy-pxa-usb.c345
-rw-r--r--drivers/phy/motorola/phy-mapphone-mdm6600.c19
-rw-r--r--drivers/phy/mscc/Kconfig11
-rw-r--r--drivers/phy/mscc/Makefile5
-rw-r--r--drivers/phy/mscc/phy-ocelot-serdes.c295
-rw-r--r--drivers/phy/qualcomm/Kconfig17
-rw-r--r--drivers/phy/qualcomm/Makefile4
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp.c222
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp.h15
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qusb2.c4
-rw-r--r--drivers/phy/qualcomm/phy-qcom-ufs-i.h2
-rw-r--r--drivers/phy/qualcomm/phy-qcom-ufs.c50
-rw-r--r--drivers/phy/renesas/Kconfig1
-rw-r--r--drivers/phy/renesas/Makefile1
-rw-r--r--drivers/phy/renesas/phy-rcar-gen2.c5
-rw-r--r--drivers/phy/renesas/phy-rcar-gen3-usb2.c86
-rw-r--r--drivers/phy/renesas/phy-rcar-gen3-usb3.c5
-rw-r--r--drivers/phy/rockchip/Kconfig8
-rw-r--r--drivers/phy/rockchip/Makefile1
-rw-r--r--drivers/phy/rockchip/phy-rockchip-emmc.c4
-rw-r--r--drivers/phy/rockchip/phy-rockchip-inno-hdmi.c1277
-rw-r--r--drivers/phy/rockchip/phy-rockchip-inno-usb2.c8
-rw-r--r--drivers/phy/rockchip/phy-rockchip-typec.c8
-rw-r--r--drivers/phy/rockchip/phy-rockchip-usb.c145
-rw-r--r--drivers/phy/socionext/Kconfig34
-rw-r--r--drivers/phy/socionext/Makefile8
-rw-r--r--drivers/phy/socionext/phy-uniphier-pcie.c240
-rw-r--r--drivers/phy/socionext/phy-uniphier-usb2.c244
-rw-r--r--drivers/phy/socionext/phy-uniphier-usb3hs.c422
-rw-r--r--drivers/phy/socionext/phy-uniphier-usb3ss.c349
-rw-r--r--drivers/phy/tegra/xusb.c4
-rw-r--r--drivers/phy/ti/phy-twl4030-usb.c29
-rw-r--r--drivers/pinctrl/Kconfig17
-rw-r--r--drivers/pinctrl/Makefile2
-rw-r--r--drivers/pinctrl/aspeed/pinctrl-aspeed.c2
-rw-r--r--drivers/pinctrl/bcm/Kconfig13
-rw-r--r--drivers/pinctrl/bcm/Makefile1
-rw-r--r--drivers/pinctrl/bcm/pinctrl-ns.c372
-rw-r--r--drivers/pinctrl/berlin/berlin.c6
-rw-r--r--drivers/pinctrl/cirrus/pinctrl-madera-core.c10
-rw-r--r--drivers/pinctrl/core.c4
-rw-r--r--drivers/pinctrl/freescale/pinctrl-imx.c7
-rw-r--r--drivers/pinctrl/freescale/pinctrl-imx1-core.c12
-rw-r--r--drivers/pinctrl/freescale/pinctrl-mxs.c1
-rw-r--r--drivers/pinctrl/intel/pinctrl-baytrail.c41
-rw-r--r--drivers/pinctrl/intel/pinctrl-broxton.c154
-rw-r--r--drivers/pinctrl/intel/pinctrl-cannonlake.c19
-rw-r--r--drivers/pinctrl/intel/pinctrl-cedarfork.c7
-rw-r--r--drivers/pinctrl/intel/pinctrl-cherryview.c147
-rw-r--r--drivers/pinctrl/intel/pinctrl-denverton.c7
-rw-r--r--drivers/pinctrl/intel/pinctrl-geminilake.c75
-rw-r--r--drivers/pinctrl/intel/pinctrl-icelake.c7
-rw-r--r--drivers/pinctrl/intel/pinctrl-intel.c150
-rw-r--r--drivers/pinctrl/intel/pinctrl-intel.h42
-rw-r--r--drivers/pinctrl/intel/pinctrl-lewisburg.c7
-rw-r--r--drivers/pinctrl/intel/pinctrl-merrifield.c56
-rw-r--r--drivers/pinctrl/intel/pinctrl-sunrisepoint.c19
-rw-r--r--drivers/pinctrl/mediatek/Kconfig49
-rw-r--r--drivers/pinctrl/mediatek/Makefile5
-rw-r--r--drivers/pinctrl/mediatek/mtk-eint.c2
-rw-r--r--drivers/pinctrl/mediatek/mtk-eint.h4
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-moore.c690
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-moore.h51
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt6765.c1108
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt7622.c1407
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt7623.c1441
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8183.c544
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c670
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h291
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mtk-common.c4
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mtk-mt6765.h1754
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mtk-mt8183.h1916
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-paris.c907
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-paris.h63
-rw-r--r--drivers/pinctrl/meson/Kconfig6
-rw-r--r--drivers/pinctrl/meson/Makefile1
-rw-r--r--drivers/pinctrl/meson/pinctrl-meson-g12a.c1404
-rw-r--r--drivers/pinctrl/meson/pinctrl-meson-gxbb.c2
-rw-r--r--drivers/pinctrl/meson/pinctrl-meson-gxl.c2
-rw-r--r--drivers/pinctrl/meson/pinctrl-meson.c6
-rw-r--r--drivers/pinctrl/meson/pinctrl-meson.h2
-rw-r--r--drivers/pinctrl/meson/pinctrl-meson8.c2
-rw-r--r--drivers/pinctrl/meson/pinctrl-meson8b.c2
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-mvebu.c6
-rw-r--r--drivers/pinctrl/nomadik/pinctrl-ab8500.c2
-rw-r--r--drivers/pinctrl/nomadik/pinctrl-ab8505.c2
-rw-r--r--drivers/pinctrl/nomadik/pinctrl-abx500.c2
-rw-r--r--drivers/pinctrl/nomadik/pinctrl-nomadik.c12
-rw-r--r--drivers/pinctrl/nuvoton/Kconfig12
-rw-r--r--drivers/pinctrl/nuvoton/Makefile4
-rw-r--r--drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c2072
-rw-r--r--drivers/pinctrl/pinctrl-amd.c2
-rw-r--r--drivers/pinctrl/pinctrl-as3722.c2
-rw-r--r--drivers/pinctrl/pinctrl-at91-pio4.c29
-rw-r--r--drivers/pinctrl/pinctrl-at91.c40
-rw-r--r--drivers/pinctrl/pinctrl-coh901.c2
-rw-r--r--drivers/pinctrl/pinctrl-digicolor.c1
-rw-r--r--drivers/pinctrl/pinctrl-falcon.c2
-rw-r--r--drivers/pinctrl/pinctrl-gemini.c79
-rw-r--r--drivers/pinctrl/pinctrl-ingenic.c462
-rw-r--r--drivers/pinctrl/pinctrl-lantiq.c8
-rw-r--r--drivers/pinctrl/pinctrl-lpc18xx.c6
-rw-r--r--drivers/pinctrl/pinctrl-mcp23s08.c15
-rw-r--r--drivers/pinctrl/pinctrl-pistachio.c1
-rw-r--r--drivers/pinctrl/pinctrl-rockchip.c10
-rw-r--r--drivers/pinctrl/pinctrl-rza1.c21
-rw-r--r--drivers/pinctrl/pinctrl-rzn1.c947
-rw-r--r--drivers/pinctrl/pinctrl-single.c32
-rw-r--r--drivers/pinctrl/pinctrl-st.c6
-rw-r--r--drivers/pinctrl/qcom/Kconfig17
-rw-r--r--drivers/pinctrl/qcom/Makefile2
-rw-r--r--drivers/pinctrl/qcom/pinctrl-msm.c250
-rw-r--r--drivers/pinctrl/qcom/pinctrl-msm.h4
-rw-r--r--drivers/pinctrl/qcom/pinctrl-qcs404.c1697
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sdm660.c1455
-rw-r--r--drivers/pinctrl/qcom/pinctrl-spmi-gpio.c2
-rw-r--r--drivers/pinctrl/qcom/pinctrl-spmi-mpp.c29
-rw-r--r--drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c30
-rw-r--r--drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c2
-rw-r--r--drivers/pinctrl/samsung/pinctrl-samsung.c2
-rw-r--r--drivers/pinctrl/samsung/pinctrl-samsung.h2
-rw-r--r--drivers/pinctrl/sh-pfc/Kconfig16
-rw-r--r--drivers/pinctrl/sh-pfc/Makefile3
-rw-r--r--drivers/pinctrl/sh-pfc/core.c23
-rw-r--r--drivers/pinctrl/sh-pfc/core.h7
-rw-r--r--drivers/pinctrl/sh-pfc/gpio.c5
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-emev2.c5
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a73a4.c15
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7740.c15
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a77470.c408
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7778.c10
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7779.c14
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7790.c15
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7791.c43
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7792.c5
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7794.c5
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7795-es1.c5
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7795.c5
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7796.c842
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a77965.c419
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a77970.c5
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a77990.c981
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a77995.c370
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-sh7203.c5
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-sh7264.c5
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-sh7269.c5
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-sh73a0.c15
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-sh7720.c5
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-sh7723.c5
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-sh7724.c5
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-sh7734.c5
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-sh7757.c5
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-sh7785.c5
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-sh7786.c5
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-shx3.c5
-rw-r--r--drivers/pinctrl/sh-pfc/pinctrl.c5
-rw-r--r--drivers/pinctrl/sh-pfc/sh_pfc.h10
-rw-r--r--drivers/pinctrl/sirf/pinctrl-atlas7.c11
-rw-r--r--drivers/pinctrl/sirf/pinctrl-sirf.c2
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear.h2
-rw-r--r--drivers/pinctrl/sprd/pinctrl-sprd.c13
-rw-r--r--drivers/pinctrl/stm32/pinctrl-stm32.c4
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sunxi.c34
-rw-r--r--drivers/pinctrl/tegra/pinctrl-tegra.c1
-rw-r--r--drivers/pinctrl/ti/pinctrl-ti-iodelay.c8
-rw-r--r--drivers/pinctrl/uniphier/pinctrl-uniphier-pro4.c5
-rw-r--r--drivers/pinctrl/uniphier/pinctrl-uniphier.h2
-rw-r--r--drivers/pinctrl/vt8500/pinctrl-wmt.c6
-rw-r--r--drivers/pinctrl/vt8500/pinctrl-wmt.h2
-rw-r--r--drivers/platform/chrome/chromeos_tbmc.c2
-rw-r--r--drivers/platform/chrome/cros_ec_lpc.c18
-rw-r--r--drivers/platform/chrome/cros_ec_lpc_mec.c3
-rw-r--r--drivers/platform/chrome/cros_ec_lpc_mec.h90
-rw-r--r--drivers/platform/chrome/cros_ec_lpc_reg.c3
-rw-r--r--drivers/platform/chrome/cros_ec_lpc_reg.h61
-rw-r--r--drivers/platform/chrome/cros_ec_proto.c2
-rw-r--r--drivers/platform/goldfish/goldfish_pipe.c399
-rw-r--r--drivers/platform/goldfish/goldfish_pipe_qemu.h98
-rw-r--r--drivers/platform/x86/Kconfig61
-rw-r--r--drivers/platform/x86/Makefile4
-rw-r--r--drivers/platform/x86/acerhdf.c68
-rw-r--r--drivers/platform/x86/asus-wmi.c158
-rw-r--r--drivers/platform/x86/dcdbas.c (renamed from drivers/firmware/dcdbas.c)125
-rw-r--r--drivers/platform/x86/dcdbas.h (renamed from drivers/firmware/dcdbas.h)10
-rw-r--r--drivers/platform/x86/dell-smbios-smm.c2
-rw-r--r--drivers/platform/x86/dell_rbu.c (renamed from drivers/firmware/dell_rbu.c)8
-rw-r--r--drivers/platform/x86/eeepc-laptop.c43
-rw-r--r--drivers/platform/x86/ideapad-laptop.c9
-rw-r--r--drivers/platform/x86/intel-hid.c12
-rw-r--r--drivers/platform/x86/intel-rst.c23
-rw-r--r--drivers/platform/x86/intel-smartconnect.c22
-rw-r--r--drivers/platform/x86/intel-wmi-thunderbolt.c18
-rw-r--r--drivers/platform/x86/intel_atomisp2_pm.c119
-rw-r--r--drivers/platform/x86/intel_bxtwc_tmu.c13
-rw-r--r--drivers/platform/x86/intel_cht_int33fe.c58
-rw-r--r--drivers/platform/x86/intel_chtdc_ti_pwrbtn.c1
-rw-r--r--drivers/platform/x86/intel_int0002_vgpio.c29
-rw-r--r--drivers/platform/x86/intel_ips.c15
-rw-r--r--drivers/platform/x86/intel_ips.h13
-rw-r--r--drivers/platform/x86/intel_menlow.c28
-rw-r--r--drivers/platform/x86/intel_mid_powerbtn.c18
-rw-r--r--drivers/platform/x86/intel_mid_thermal.c30
-rw-r--r--drivers/platform/x86/intel_oaktrail.c32
-rw-r--r--drivers/platform/x86/intel_pmc_core.c11
-rw-r--r--drivers/platform/x86/intel_pmc_core.h11
-rw-r--r--drivers/platform/x86/intel_pmc_ipc.c35
-rw-r--r--drivers/platform/x86/intel_punit_ipc.c12
-rw-r--r--drivers/platform/x86/intel_scu_ipc.c16
-rw-r--r--drivers/platform/x86/intel_scu_ipcutil.c24
-rw-r--r--drivers/platform/x86/intel_telemetry_core.c12
-rw-r--r--drivers/platform/x86/intel_telemetry_debugfs.c27
-rw-r--r--drivers/platform/x86/intel_telemetry_pltdrv.c14
-rw-r--r--drivers/platform/x86/intel_turbo_max_3.c18
-rw-r--r--drivers/platform/x86/lg-laptop.c700
-rw-r--r--drivers/platform/x86/mlx-platform.c2
-rw-r--r--drivers/platform/x86/touchscreen_dmi.c107
-rw-r--r--drivers/platform/x86/wmi.c6
-rw-r--r--drivers/power/reset/at91-sama5d2_shdwc.c119
-rw-r--r--drivers/power/reset/qcom-pon.c1
-rw-r--r--drivers/power/reset/rmobile-reset.c5
-rw-r--r--drivers/power/supply/Kconfig7
-rw-r--r--drivers/power/supply/Makefile1
-rw-r--r--drivers/power/supply/ab8500_fg.c52
-rw-r--r--drivers/power/supply/bq25890_charger.c62
-rw-r--r--drivers/power/supply/bq27xxx_battery.c9
-rw-r--r--drivers/power/supply/bq27xxx_battery_i2c.c2
-rw-r--r--drivers/power/supply/cros_usbpd-charger.c117
-rw-r--r--drivers/power/supply/ds2780_battery.c2
-rw-r--r--drivers/power/supply/ds2781_battery.c2
-rw-r--r--drivers/power/supply/ds2782_battery.c2
-rw-r--r--drivers/power/supply/max14577_charger.c22
-rw-r--r--drivers/power/supply/max17040_battery.c18
-rw-r--r--drivers/power/supply/max17042_battery.c32
-rw-r--r--drivers/power/supply/max77693_charger.c22
-rw-r--r--drivers/power/supply/max8925_power.c1
-rw-r--r--drivers/power/supply/max8997_charger.c26
-rw-r--r--drivers/power/supply/max8998_charger.c28
-rw-r--r--drivers/power/supply/power_supply_sysfs.c3
-rw-r--r--drivers/power/supply/sc2731_charger.c504
-rw-r--r--drivers/power/supply/twl4030_charger.c35
-rw-r--r--drivers/powercap/intel_rapl.c73
-rw-r--r--drivers/ptp/ptp_chardev.c4
-rw-r--r--drivers/ptp/ptp_clock.c6
-rw-r--r--drivers/ptp/ptp_dte.c6
-rw-r--r--drivers/pwm/Kconfig5
-rw-r--r--drivers/pwm/pwm-lpss-platform.c24
-rw-r--r--drivers/pwm/pwm-lpss.c61
-rw-r--r--drivers/pwm/pwm-lpss.h14
-rw-r--r--drivers/pwm/pwm-rcar.c5
-rw-r--r--drivers/pwm/pwm-renesas-tpu.c10
-rw-r--r--drivers/pwm/pwm-tegra.c1
-rw-r--r--drivers/pwm/sysfs.c12
-rw-r--r--drivers/regulator/Kconfig21
-rw-r--r--drivers/regulator/Makefile4
-rw-r--r--drivers/regulator/arizona-ldo1.c2
-rw-r--r--drivers/regulator/axp20x-regulator.c3
-rw-r--r--drivers/regulator/bd71837-regulator.c645
-rw-r--r--drivers/regulator/bd718x7-regulator.c1119
-rw-r--r--drivers/regulator/core.c124
-rw-r--r--drivers/regulator/da9052-regulator.c2
-rw-r--r--drivers/regulator/da9055-regulator.c2
-rw-r--r--drivers/regulator/da9211-regulator.c10
-rw-r--r--drivers/regulator/fixed-helper.c1
-rw-r--r--drivers/regulator/fixed.c57
-rw-r--r--drivers/regulator/helpers.c243
-rw-r--r--drivers/regulator/isl9305.c4
-rw-r--r--drivers/regulator/lm363x-regulator.c6
-rw-r--r--drivers/regulator/lochnagar-regulator.c254
-rw-r--r--drivers/regulator/lp8788-ldo.c7
-rw-r--r--drivers/regulator/ltc3589.c3
-rw-r--r--drivers/regulator/ltc3676.c3
-rw-r--r--drivers/regulator/max8952.c1
-rw-r--r--drivers/regulator/max8973-regulator.c1
-rw-r--r--drivers/regulator/max8997-regulator.c4
-rw-r--r--drivers/regulator/mc13xxx-regulator-core.c2
-rw-r--r--drivers/regulator/of_regulator.c44
-rw-r--r--drivers/regulator/pfuze100-regulator.c91
-rw-r--r--drivers/regulator/qcom-rpmh-regulator.c17
-rw-r--r--drivers/regulator/qcom_smd-regulator.c77
-rw-r--r--drivers/regulator/s5m8767.c25
-rw-r--r--drivers/regulator/stpmic1_regulator.c674
-rw-r--r--drivers/regulator/tps65090-regulator.c1
-rw-r--r--drivers/remoteproc/Kconfig46
-rw-r--r--drivers/remoteproc/Makefile5
-rw-r--r--drivers/remoteproc/da8xx_remoteproc.c2
-rw-r--r--drivers/remoteproc/qcom_q6v5.c43
-rw-r--r--drivers/remoteproc/qcom_q6v5_adsp.c497
-rw-r--r--drivers/remoteproc/qcom_q6v5_mss.c (renamed from drivers/remoteproc/qcom_q6v5_pil.c)420
-rw-r--r--drivers/remoteproc/qcom_q6v5_pas.c (renamed from drivers/remoteproc/qcom_adsp_pil.c)28
-rw-r--r--drivers/remoteproc/remoteproc_core.c595
-rw-r--r--drivers/remoteproc/remoteproc_debugfs.c1
-rw-r--r--drivers/remoteproc/remoteproc_internal.h2
-rw-r--r--drivers/remoteproc/remoteproc_sysfs.c5
-rw-r--r--drivers/remoteproc/remoteproc_virtio.c14
-rw-r--r--drivers/reset/Kconfig9
-rw-r--r--drivers/reset/Makefile1
-rw-r--r--drivers/reset/core.c15
-rw-r--r--drivers/reset/reset-imx7.c1
-rw-r--r--drivers/reset/reset-qcom-pdc.c124
-rw-r--r--drivers/rpmsg/qcom_glink_native.c3
-rw-r--r--drivers/rpmsg/qcom_glink_smem.c14
-rw-r--r--drivers/rpmsg/qcom_smd.c9
-rw-r--r--drivers/rpmsg/rpmsg_char.c27
-rw-r--r--drivers/rtc/Kconfig14
-rw-r--r--drivers/rtc/Makefile12
-rw-r--r--drivers/rtc/class.c12
-rw-r--r--drivers/rtc/hctosys.c4
-rw-r--r--drivers/rtc/interface.c3
-rw-r--r--drivers/rtc/rtc-ab8500.c96
-rw-r--r--drivers/rtc/rtc-abx80x.c143
-rw-r--r--drivers/rtc/rtc-armada38x.c46
-rw-r--r--drivers/rtc/rtc-cmos.c45
-rw-r--r--drivers/rtc/rtc-core.h14
-rw-r--r--drivers/rtc/rtc-ds1307.c145
-rw-r--r--drivers/rtc/rtc-ds1685.c194
-rw-r--r--drivers/rtc/rtc-isl1208.c34
-rw-r--r--drivers/rtc/rtc-lib.c2
-rw-r--r--drivers/rtc/rtc-m41t80.c2
-rw-r--r--drivers/rtc/rtc-mrst.c5
-rw-r--r--drivers/rtc/rtc-mt6397.c13
-rw-r--r--drivers/rtc/rtc-mv.c8
-rw-r--r--drivers/rtc/rtc-omap.c28
-rw-r--r--drivers/rtc/rtc-pcf2127.c3
-rw-r--r--drivers/rtc/rtc-pl030.c15
-rw-r--r--drivers/rtc/rtc-pl031.c18
-rw-r--r--drivers/rtc/rtc-rs5c348.c65
-rw-r--r--drivers/rtc/rtc-rv8803.c7
-rw-r--r--drivers/rtc/rtc-s35390a.c2
-rw-r--r--drivers/rtc/rtc-sc27xx.c60
-rw-r--r--drivers/rtc/rtc-sun6i.c3
-rw-r--r--drivers/rtc/rtc-sysfs.c4
-rw-r--r--drivers/rtc/rtc-tegra.c10
-rw-r--r--drivers/rtc/rtc-test.c7
-rw-r--r--drivers/rtc/rtc-tx4939.c4
-rw-r--r--drivers/rtc/rtc-vr41xx.c9
-rw-r--r--drivers/s390/block/dasd.c6
-rw-r--r--drivers/s390/block/dasd_genhd.c2
-rw-r--r--drivers/s390/block/dcssblk.c2
-rw-r--r--drivers/s390/block/scm_blk.c2
-rw-r--r--drivers/s390/char/Makefile1
-rw-r--r--drivers/s390/char/fs3270.c2
-rw-r--r--drivers/s390/char/monwriter.c33
-rw-r--r--drivers/s390/char/sclp.h52
-rw-r--r--drivers/s390/char/sclp_cmd.c11
-rw-r--r--drivers/s390/char/sclp_early.c123
-rw-r--r--drivers/s390/char/sclp_early_core.c127
-rw-r--r--drivers/s390/char/sclp_pci.c10
-rw-r--r--drivers/s390/char/tape_3590.c2
-rw-r--r--drivers/s390/char/tty3270.c2
-rw-r--r--drivers/s390/char/vmlogrdr.c2
-rw-r--r--drivers/s390/cio/ccwgroup.c30
-rw-r--r--drivers/s390/cio/cmf.c2
-rw-r--r--drivers/s390/cio/qdio_main.c15
-rw-r--r--drivers/s390/cio/qdio_setup.c1
-rw-r--r--drivers/s390/cio/vfio_ccw_cp.c2
-rw-r--r--drivers/s390/cio/vfio_ccw_drv.c24
-rw-r--r--drivers/s390/cio/vfio_ccw_fsm.c6
-rw-r--r--drivers/s390/cio/vfio_ccw_ops.c4
-rw-r--r--drivers/s390/cio/vfio_ccw_private.h2
-rw-r--r--drivers/s390/crypto/Makefile6
-rw-r--r--drivers/s390/crypto/ap_bus.c79
-rw-r--r--drivers/s390/crypto/ap_bus.h25
-rw-r--r--drivers/s390/crypto/pkey_api.c521
-rw-r--r--drivers/s390/crypto/vfio_ap_drv.c157
-rw-r--r--drivers/s390/crypto/vfio_ap_ops.c939
-rw-r--r--drivers/s390/crypto/vfio_ap_private.h88
-rw-r--r--drivers/s390/crypto/zcrypt_api.c627
-rw-r--r--drivers/s390/crypto/zcrypt_api.h15
-rw-r--r--drivers/s390/crypto/zcrypt_card.c2
-rw-r--r--drivers/s390/crypto/zcrypt_cca_key.h2
-rw-r--r--drivers/s390/crypto/zcrypt_cex2a.c6
-rw-r--r--drivers/s390/crypto/zcrypt_cex2a.h6
-rw-r--r--drivers/s390/crypto/zcrypt_cex2c.c (renamed from drivers/s390/crypto/zcrypt_pcixcc.c)125
-rw-r--r--drivers/s390/crypto/zcrypt_cex2c.h (renamed from drivers/s390/crypto/zcrypt_pcixcc.h)14
-rw-r--r--drivers/s390/crypto/zcrypt_cex4.c20
-rw-r--r--drivers/s390/crypto/zcrypt_error.h24
-rw-r--r--drivers/s390/crypto/zcrypt_msgtype50.c24
-rw-r--r--drivers/s390/crypto/zcrypt_msgtype50.h2
-rw-r--r--drivers/s390/crypto/zcrypt_msgtype6.c74
-rw-r--r--drivers/s390/crypto/zcrypt_msgtype6.h15
-rw-r--r--drivers/s390/crypto/zcrypt_queue.c2
-rw-r--r--drivers/s390/net/ism_drv.c4
-rw-r--r--drivers/s390/net/qeth_core.h70
-rw-r--r--drivers/s390/net/qeth_core_main.c1001
-rw-r--r--drivers/s390/net/qeth_core_mpc.c33
-rw-r--r--drivers/s390/net/qeth_core_mpc.h34
-rw-r--r--drivers/s390/net/qeth_core_sys.c15
-rw-r--r--drivers/s390/net/qeth_l2_main.c189
-rw-r--r--drivers/s390/net/qeth_l3_main.c570
-rw-r--r--drivers/s390/virtio/virtio_ccw.c2
-rw-r--r--drivers/sbus/char/openprom.c11
-rw-r--r--drivers/sbus/char/oradax.c3
-rw-r--r--drivers/scsi/3w-9xxx.c62
-rw-r--r--drivers/scsi/3w-sas.c46
-rw-r--r--drivers/scsi/3w-xxxx.c20
-rw-r--r--drivers/scsi/3w-xxxx.h1
-rw-r--r--drivers/scsi/53c700.h2
-rw-r--r--drivers/scsi/BusLogic.c36
-rw-r--r--drivers/scsi/FlashPoint.c6
-rw-r--r--drivers/scsi/Kconfig42
-rw-r--r--drivers/scsi/Makefile2
-rw-r--r--drivers/scsi/NCR5380.c169
-rw-r--r--drivers/scsi/NCR5380.h2
-rw-r--r--drivers/scsi/a100u2w.c20
-rw-r--r--drivers/scsi/aacraid/aachba.c7
-rw-r--r--drivers/scsi/aacraid/commsup.c2
-rw-r--r--drivers/scsi/aacraid/linit.c4
-rw-r--r--drivers/scsi/advansys.c4
-rw-r--r--drivers/scsi/aha152x.c14
-rw-r--r--drivers/scsi/aic7xxx/aic7770.c6
-rw-r--r--drivers/scsi/aic7xxx/aic79xx.h6
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_core.c44
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_pci.c8
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx.h6
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_93cx6.c6
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_core.c41
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_pci.c7
-rw-r--r--drivers/scsi/aic7xxx/aicasm/aicasm.h4
-rw-r--r--drivers/scsi/aic7xxx/aicasm/aicasm_gram.y4
-rw-r--r--drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y4
-rw-r--r--drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l4
-rw-r--r--drivers/scsi/aic7xxx/aicasm/aicasm_scan.l4
-rw-r--r--drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c4
-rw-r--r--drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h4
-rw-r--r--drivers/scsi/aic94xx/aic94xx_init.c9
-rw-r--r--drivers/scsi/aic94xx/aic94xx_scb.c5
-rw-r--r--drivers/scsi/aic94xx/aic94xx_task.c46
-rw-r--r--drivers/scsi/am53c974.c54
-rw-r--r--drivers/scsi/arcmsr/arcmsr_hba.c29
-rw-r--r--drivers/scsi/atp870u.c6
-rw-r--r--drivers/scsi/be2iscsi/be_cmds.c10
-rw-r--r--drivers/scsi/be2iscsi/be_iscsi.c15
-rw-r--r--drivers/scsi/be2iscsi/be_main.c75
-rw-r--r--drivers/scsi/be2iscsi/be_mgmt.c27
-rw-r--r--drivers/scsi/bfa/bfa_defs_svc.h2
-rw-r--r--drivers/scsi/bfa/bfa_fcbuild.c108
-rw-r--r--drivers/scsi/bfa/bfa_fcbuild.h9
-rw-r--r--drivers/scsi/bfa/bfad.c2
-rw-r--r--drivers/scsi/bfa/bfad_im.h2
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_fcoe.c9
-rw-r--r--drivers/scsi/csiostor/csio_init.c8
-rw-r--r--drivers/scsi/csiostor/csio_lnode.c6
-rw-r--r--drivers/scsi/csiostor/csio_scsi.c12
-rw-r--r--drivers/scsi/csiostor/csio_wr.c17
-rw-r--r--drivers/scsi/cxgbi/cxgb4i/cxgb4i.c154
-rw-r--r--drivers/scsi/cxgbi/libcxgbi.c5
-rw-r--r--drivers/scsi/cxgbi/libcxgbi.h3
-rw-r--r--drivers/scsi/dc395x.c191
-rw-r--r--drivers/scsi/esp_scsi.c286
-rw-r--r--drivers/scsi/esp_scsi.h38
-rw-r--r--drivers/scsi/fnic/fnic_fcs.c41
-rw-r--r--drivers/scsi/fnic/fnic_main.c19
-rw-r--r--drivers/scsi/fnic/fnic_scsi.c99
-rw-r--r--drivers/scsi/fnic/vnic_dev.c26
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas.h3
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_main.c161
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_v1_hw.c3
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_v2_hw.c17
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_v3_hw.c17
-rw-r--r--drivers/scsi/hpsa.c148
-rw-r--r--drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c1
-rw-r--r--drivers/scsi/ips.c81
-rw-r--r--drivers/scsi/isci/host.c8
-rw-r--r--drivers/scsi/isci/host.h2
-rw-r--r--drivers/scsi/isci/request.c4
-rw-r--r--drivers/scsi/isci/task.c4
-rw-r--r--drivers/scsi/iscsi_tcp.c3
-rw-r--r--drivers/scsi/jazz_esp.c30
-rw-r--r--drivers/scsi/libfc/fc_fcp.c6
-rw-r--r--drivers/scsi/libfc/fc_rport.c22
-rw-r--r--drivers/scsi/libsas/sas_ata.c2
-rw-r--r--drivers/scsi/libsas/sas_discover.c2
-rw-r--r--drivers/scsi/libsas/sas_expander.c22
-rw-r--r--drivers/scsi/lpfc/lpfc.h29
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c111
-rw-r--r--drivers/scsi/lpfc/lpfc_bsg.c344
-rw-r--r--drivers/scsi/lpfc/lpfc_bsg.h36
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h7
-rw-r--r--drivers/scsi/lpfc/lpfc_ct.c11
-rw-r--r--drivers/scsi/lpfc/lpfc_debugfs.c4
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c3
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c10
-rw-r--r--drivers/scsi/lpfc/lpfc_hw4.h45
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c111
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c3
-rw-r--r--drivers/scsi/lpfc/lpfc_nvme.c19
-rw-r--r--drivers/scsi/lpfc/lpfc_nvmet.c20
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c34
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c310
-rw-r--r--drivers/scsi/lpfc/lpfc_sli4.h1
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_vport.c14
-rw-r--r--drivers/scsi/mac_esp.c217
-rw-r--r--drivers/scsi/megaraid/megaraid_mbox.c117
-rw-r--r--drivers/scsi/megaraid/megaraid_mbox.h2
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_base.c153
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fusion.c16
-rw-r--r--drivers/scsi/mesh.c8
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_base.c1189
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_base.h9
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_config.c89
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_ctl.c527
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_scsih.c1488
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_transport.c355
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c101
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_warpdrive.c70
-rw-r--r--drivers/scsi/mvsas/mv_init.c21
-rw-r--r--drivers/scsi/mvsas/mv_sas.c18
-rw-r--r--drivers/scsi/mvumi.c89
-rw-r--r--drivers/scsi/myrb.c3657
-rw-r--r--drivers/scsi/myrb.h958
-rw-r--r--drivers/scsi/myrs.c3271
-rw-r--r--drivers/scsi/myrs.h1134
-rw-r--r--drivers/scsi/nsp32.c18
-rw-r--r--drivers/scsi/osd/osd_initiator.c2
-rw-r--r--drivers/scsi/pcmcia/aha152x_core.c2
-rw-r--r--drivers/scsi/pcmcia/aha152x_stub.c14
-rw-r--r--drivers/scsi/pcmcia/nsp_cs.c15
-rw-r--r--drivers/scsi/pcmcia/nsp_cs.h4
-rw-r--r--drivers/scsi/pcmcia/qlogic_stub.c19
-rw-r--r--drivers/scsi/pcmcia/sym53c500_cs.c16
-rw-r--r--drivers/scsi/pm8001/pm8001_defs.h8
-rw-r--r--drivers/scsi/pm8001/pm8001_hwi.c31
-rw-r--r--drivers/scsi/pm8001/pm8001_hwi.h4
-rw-r--r--drivers/scsi/pm8001/pm8001_init.c31
-rw-r--r--drivers/scsi/pm8001/pm8001_sas.c49
-rw-r--r--drivers/scsi/pm8001/pm8001_sas.h3
-rw-r--r--drivers/scsi/pm8001/pm80xx_hwi.c119
-rw-r--r--drivers/scsi/pm8001/pm80xx_hwi.h9
-rw-r--r--drivers/scsi/qedf/qedf_main.c8
-rw-r--r--drivers/scsi/qedi/qedi_main.c9
-rw-r--r--drivers/scsi/qla1280.c26
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c587
-rw-r--r--drivers/scsi/qla2xxx/qla_bsg.c2
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h32
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h17
-rw-r--r--drivers/scsi/qla2xxx/qla_gs.c536
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c420
-rw-r--r--drivers/scsi/qla2xxx/qla_inline.h23
-rw-r--r--drivers/scsi/qla2xxx/qla_iocb.c47
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c90
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c58
-rw-r--r--drivers/scsi/qla2xxx/qla_mr.c21
-rw-r--r--drivers/scsi/qla2xxx/qla_nvme.c7
-rw-r--r--drivers/scsi/qla2xxx/qla_nx.c6
-rw-r--r--drivers/scsi/qla2xxx/qla_nx2.c2
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c323
-rw-r--r--drivers/scsi/qla2xxx/qla_sup.c2
-rw-r--r--drivers/scsi/qla2xxx/qla_target.c550
-rw-r--r--drivers/scsi/qla2xxx/qla_target.h8
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h2
-rw-r--r--drivers/scsi/qla2xxx/tcm_qla2xxx.c51
-rw-r--r--drivers/scsi/qla4xxx/ql4_init.c10
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c26
-rw-r--r--drivers/scsi/raid_class.c4
-rw-r--r--drivers/scsi/scsi_error.c3
-rw-r--r--drivers/scsi/scsi_lib.c24
-rw-r--r--drivers/scsi/scsi_pm.c1
-rw-r--r--drivers/scsi/scsi_transport_sas.c2
-rw-r--r--drivers/scsi/sd.c18
-rw-r--r--drivers/scsi/sd.h15
-rw-r--r--drivers/scsi/sd_zbc.c501
-rw-r--r--drivers/scsi/sg.c2
-rw-r--r--drivers/scsi/smartpqi/smartpqi_init.c100
-rw-r--r--drivers/scsi/smartpqi/smartpqi_sis.c11
-rw-r--r--drivers/scsi/snic/snic_disc.c7
-rw-r--r--drivers/scsi/snic/snic_io.c25
-rw-r--r--drivers/scsi/snic/snic_main.c24
-rw-r--r--drivers/scsi/snic/snic_scsi.c15
-rw-r--r--drivers/scsi/snic/vnic_dev.c29
-rw-r--r--drivers/scsi/sr.c3
-rw-r--r--drivers/scsi/sun3x_esp.c30
-rw-r--r--drivers/scsi/sun_esp.c61
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_hipd.c15
-rw-r--r--drivers/scsi/ufs/Kconfig19
-rw-r--r--drivers/scsi/ufs/Makefile3
-rw-r--r--drivers/scsi/ufs/ufs-qcom.c82
-rw-r--r--drivers/scsi/ufs/ufs-qcom.h5
-rw-r--r--drivers/scsi/ufs/ufs.h94
-rw-r--r--drivers/scsi/ufs/ufs_bsg.c210
-rw-r--r--drivers/scsi/ufs/ufs_bsg.h23
-rw-r--r--drivers/scsi/ufs/ufshcd.c438
-rw-r--r--drivers/scsi/ufs/ufshcd.h12
-rw-r--r--drivers/scsi/ufs/ufshci.h25
-rw-r--r--drivers/scsi/vmw_pvscsi.c77
-rw-r--r--drivers/scsi/zorro_esp.c290
-rw-r--r--drivers/sfi/sfi_core.c2
-rw-r--r--drivers/slimbus/core.c37
-rw-r--r--drivers/slimbus/qcom-ngd-ctrl.c34
-rw-r--r--drivers/soc/Makefile2
-rw-r--r--drivers/soc/actions/Kconfig2
-rw-r--r--drivers/soc/actions/Makefile2
-rw-r--r--drivers/soc/actions/owl-sps-helper.c6
-rw-r--r--drivers/soc/actions/owl-sps.c64
-rw-r--r--drivers/soc/amlogic/Kconfig7
-rw-r--r--drivers/soc/amlogic/Makefile1
-rw-r--r--drivers/soc/amlogic/meson-canvas.c185
-rw-r--r--drivers/soc/dove/pmu.c8
-rw-r--r--drivers/soc/fsl/dpio/dpio-driver.c3
-rw-r--r--drivers/soc/fsl/dpio/dpio-service.c58
-rw-r--r--drivers/soc/fsl/qbman/Kconfig2
-rw-r--r--drivers/soc/fsl/qbman/bman.c6
-rw-r--r--drivers/soc/fsl/qbman/bman_ccsr.c11
-rw-r--r--drivers/soc/fsl/qbman/bman_portal.c14
-rw-r--r--drivers/soc/fsl/qbman/dpaa_sys.h20
-rw-r--r--drivers/soc/fsl/qbman/qman.c56
-rw-r--r--drivers/soc/fsl/qbman/qman_ccsr.c13
-rw-r--r--drivers/soc/fsl/qbman/qman_portal.c14
-rw-r--r--drivers/soc/fsl/qe/qe.c6
-rw-r--r--drivers/soc/fsl/qe/qe_tdm.c4
-rw-r--r--drivers/soc/fsl/qe/ucc.c2
-rw-r--r--drivers/soc/imx/gpc.c26
-rw-r--r--drivers/soc/imx/gpcv2.c100
-rw-r--r--drivers/soc/mediatek/mtk-pmic-wrap.c519
-rw-r--r--drivers/soc/qcom/Kconfig21
-rw-r--r--drivers/soc/qcom/apr.c6
-rw-r--r--drivers/soc/qcom/llcc-slice.c74
-rw-r--r--drivers/soc/qcom/qcom-geni-se.c41
-rw-r--r--drivers/soc/qcom/rmtfs_mem.c5
-rw-r--r--drivers/soc/qcom/rpmh-rsc.c2
-rw-r--r--drivers/soc/qcom/smem.c174
-rw-r--r--drivers/soc/qcom/spm.c3
-rw-r--r--drivers/soc/qcom/wcnss_ctrl.c2
-rw-r--r--drivers/soc/renesas/Kconfig19
-rw-r--r--drivers/soc/renesas/Makefile2
-rw-r--r--drivers/soc/renesas/r8a7743-sysc.c5
-rw-r--r--drivers/soc/renesas/r8a7745-sysc.c5
-rw-r--r--drivers/soc/renesas/r8a774a1-sysc.c45
-rw-r--r--drivers/soc/renesas/r8a774c0-sysc.c68
-rw-r--r--drivers/soc/renesas/r8a7779-sysc.c5
-rw-r--r--drivers/soc/renesas/r8a7790-sysc.c5
-rw-r--r--drivers/soc/renesas/r8a7791-sysc.c5
-rw-r--r--drivers/soc/renesas/r8a7792-sysc.c5
-rw-r--r--drivers/soc/renesas/r8a7794-sysc.c5
-rw-r--r--drivers/soc/renesas/r8a7795-sysc.c5
-rw-r--r--drivers/soc/renesas/r8a7796-sysc.c5
-rw-r--r--drivers/soc/renesas/r8a77970-sysc.c5
-rw-r--r--drivers/soc/renesas/r8a77995-sysc.c5
-rw-r--r--drivers/soc/renesas/rcar-rst.c11
-rw-r--r--drivers/soc/renesas/rcar-sysc.c13
-rw-r--r--drivers/soc/renesas/rcar-sysc.h9
-rw-r--r--drivers/soc/renesas/renesas-soc.c100
-rw-r--r--drivers/soc/rockchip/pm_domains.c44
-rw-r--r--drivers/soc/tegra/pmc.c525
-rw-r--r--drivers/soc/ti/knav_dma.c12
-rw-r--r--drivers/soc/ti/knav_qmss.h10
-rw-r--r--drivers/soc/ti/knav_qmss_acc.c10
-rw-r--r--drivers/soc/ti/knav_qmss_queue.c30
-rw-r--r--drivers/soundwire/bus.c6
-rw-r--r--drivers/soundwire/bus.h4
-rw-r--r--drivers/soundwire/intel.c68
-rw-r--r--drivers/soundwire/intel_init.c2
-rw-r--r--drivers/soundwire/stream.c488
-rw-r--r--drivers/spi/Kconfig53
-rw-r--r--drivers/spi/Makefile6
-rw-r--r--drivers/spi/spi-at91-usart.c432
-rw-r--r--drivers/spi/spi-atmel.c10
-rw-r--r--drivers/spi/spi-bcm-qspi.c4
-rw-r--r--drivers/spi/spi-bcm63xx-hsspi.c20
-rw-r--r--drivers/spi/spi-davinci.c19
-rw-r--r--drivers/spi/spi-dw-mmio.c38
-rw-r--r--drivers/spi/spi-dw.c28
-rw-r--r--drivers/spi/spi-dw.h2
-rw-r--r--drivers/spi/spi-ep93xx.c36
-rw-r--r--drivers/spi/spi-fsl-espi.c4
-rw-r--r--drivers/spi/spi-fsl-lpspi.c2
-rw-r--r--drivers/spi/spi-geni-qcom.c703
-rw-r--r--drivers/spi/spi-gpio.c12
-rw-r--r--drivers/spi/spi-imx.c53
-rw-r--r--drivers/spi/spi-mem.c69
-rw-r--r--drivers/spi/spi-mt65xx.c37
-rw-r--r--drivers/spi/spi-omap2-mcspi.c177
-rw-r--r--drivers/spi/spi-orion.c22
-rw-r--r--drivers/spi/spi-pic32-sqi.c4
-rw-r--r--drivers/spi/spi-pic32.c6
-rw-r--r--drivers/spi/spi-pl022.c10
-rw-r--r--drivers/spi/spi-pxa2xx.c100
-rw-r--r--drivers/spi/spi-qcom-qspi.c581
-rw-r--r--drivers/spi/spi-rb4xx.c2
-rw-r--r--drivers/spi/spi-rockchip.c62
-rw-r--r--drivers/spi/spi-rspi.c10
-rw-r--r--drivers/spi/spi-sh-hspi.c12
-rw-r--r--drivers/spi/spi-sh-msiof.c10
-rw-r--r--drivers/spi/spi-sh.c12
-rw-r--r--drivers/spi/spi-slave-mt27xx.c554
-rw-r--r--drivers/spi/spi-slave-system-control.c1
-rw-r--r--drivers/spi/spi-sprd.c745
-rw-r--r--drivers/spi/spi-stm32-qspi.c512
-rw-r--r--drivers/spi/spi.c106
-rw-r--r--drivers/spi/spidev.c9
-rw-r--r--drivers/ssb/driver_chipcommon.c2
-rw-r--r--drivers/staging/Kconfig2
-rw-r--r--drivers/staging/Makefile1
-rw-r--r--drivers/staging/android/ion/Kconfig2
-rw-r--r--drivers/staging/android/ion/ion.h5
-rw-r--r--drivers/staging/android/ion/ion_page_pool.c8
-rw-r--r--drivers/staging/android/ion/ion_system_heap.c24
-rw-r--r--drivers/staging/axis-fifo/axis-fifo.c24
-rw-r--r--drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c20
-rw-r--r--drivers/staging/comedi/Kconfig4
-rw-r--r--drivers/staging/comedi/comedi.h174
-rw-r--r--drivers/staging/comedi/comedi_fops.c73
-rw-r--r--drivers/staging/comedi/comedidev.h14
-rw-r--r--drivers/staging/comedi/drivers.c19
-rw-r--r--drivers/staging/comedi/drivers/Makefile28
-rw-r--r--drivers/staging/comedi/drivers/comedi_test.c44
-rw-r--r--drivers/staging/comedi/drivers/ni_660x.c363
-rw-r--r--drivers/staging/comedi/drivers/ni_mio_common.c944
-rw-r--r--drivers/staging/comedi/drivers/ni_pcidio.c13
-rw-r--r--drivers/staging/comedi/drivers/ni_pcimio.c21
-rw-r--r--drivers/staging/comedi/drivers/ni_routes.c523
-rw-r--r--drivers/staging/comedi/drivers/ni_routes.h329
-rw-r--r--drivers/staging/comedi/drivers/ni_routing/README240
-rw-r--r--drivers/staging/comedi/drivers/ni_routing/ni_device_routes.c51
-rw-r--r--drivers/staging/comedi/drivers/ni_routing/ni_device_routes.h32
-rw-r--r--drivers/staging/comedi/drivers/ni_routing/ni_device_routes/all.h54
-rw-r--r--drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6070e.c639
-rw-r--r--drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6220.c1418
-rw-r--r--drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6221.c1602
-rw-r--r--drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6229.c1602
-rw-r--r--drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6251.c1652
-rw-r--r--drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6254.c1464
-rw-r--r--drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6259.c1652
-rw-r--r--drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6534.c290
-rw-r--r--drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6602.c3378
-rw-r--r--drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6713.c400
-rw-r--r--drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6723.c400
-rw-r--r--drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6733.c428
-rw-r--r--drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxi-6030e.c608
-rw-r--r--drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxi-6224.c1432
-rw-r--r--drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxi-6225.c1613
-rw-r--r--drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxi-6251.c1655
-rw-r--r--drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxi-6733.c428
-rw-r--r--drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxie-6251.c1656
-rw-r--r--drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxie-6535.c575
-rw-r--r--drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxie-6738.c3083
-rw-r--r--drivers/staging/comedi/drivers/ni_routing/ni_route_values.c42
-rw-r--r--drivers/staging/comedi/drivers/ni_routing/ni_route_values.h98
-rw-r--r--drivers/staging/comedi/drivers/ni_routing/ni_route_values/all.h37
-rw-r--r--drivers/staging/comedi/drivers/ni_routing/ni_route_values/ni_660x.c650
-rw-r--r--drivers/staging/comedi/drivers/ni_routing/ni_route_values/ni_eseries.c602
-rw-r--r--drivers/staging/comedi/drivers/ni_routing/ni_route_values/ni_mseries.c1752
-rw-r--r--drivers/staging/comedi/drivers/ni_routing/tools/.gitignore7
-rw-r--r--drivers/staging/comedi/drivers/ni_routing/tools/Makefile79
-rw-r--r--drivers/staging/comedi/drivers/ni_routing/tools/convert_c_to_py.c159
-rwxr-xr-xdrivers/staging/comedi/drivers/ni_routing/tools/convert_csv_to_c.py503
-rwxr-xr-xdrivers/staging/comedi/drivers/ni_routing/tools/convert_py_to_csv.py67
-rw-r--r--drivers/staging/comedi/drivers/ni_routing/tools/csv_collection.py40
-rwxr-xr-xdrivers/staging/comedi/drivers/ni_routing/tools/make_blank_csv.py32
-rw-r--r--drivers/staging/comedi/drivers/ni_routing/tools/ni_names.py56
-rw-r--r--drivers/staging/comedi/drivers/ni_stc.h79
-rw-r--r--drivers/staging/comedi/drivers/ni_tio.c461
-rw-r--r--drivers/staging/comedi/drivers/ni_tio.h42
-rw-r--r--drivers/staging/comedi/drivers/ni_tio_internal.h2
-rw-r--r--drivers/staging/comedi/drivers/ni_tiocmd.c66
-rw-r--r--drivers/staging/comedi/drivers/tests/Makefile7
-rw-r--r--drivers/staging/comedi/drivers/tests/example_test.c72
-rw-r--r--drivers/staging/comedi/drivers/tests/ni_routes_test.c613
-rw-r--r--drivers/staging/comedi/drivers/tests/unittest.h63
-rw-r--r--drivers/staging/dgnc/Kconfig6
-rw-r--r--drivers/staging/dgnc/Makefile4
-rw-r--r--drivers/staging/dgnc/TODO6
-rw-r--r--drivers/staging/dgnc/dgnc_cls.c1135
-rw-r--r--drivers/staging/dgnc/dgnc_cls.h67
-rw-r--r--drivers/staging/dgnc/dgnc_driver.c404
-rw-r--r--drivers/staging/dgnc/dgnc_driver.h345
-rw-r--r--drivers/staging/dgnc/dgnc_tty.c2590
-rw-r--r--drivers/staging/dgnc/dgnc_tty.h24
-rw-r--r--drivers/staging/dgnc/digi.h128
-rw-r--r--drivers/staging/emxx_udc/emxx_udc.c43
-rw-r--r--drivers/staging/erofs/Kconfig9
-rw-r--r--drivers/staging/erofs/data.c105
-rw-r--r--drivers/staging/erofs/dir.c15
-rw-r--r--drivers/staging/erofs/erofs_fs.h11
-rw-r--r--drivers/staging/erofs/include/trace/events/erofs.h20
-rw-r--r--drivers/staging/erofs/inode.c50
-rw-r--r--drivers/staging/erofs/internal.h111
-rw-r--r--drivers/staging/erofs/namei.c47
-rw-r--r--drivers/staging/erofs/super.c96
-rw-r--r--drivers/staging/erofs/unzip_vle.c447
-rw-r--r--drivers/staging/erofs/unzip_vle.h12
-rw-r--r--drivers/staging/erofs/unzip_vle_lz4.c69
-rw-r--r--drivers/staging/erofs/utils.c20
-rw-r--r--drivers/staging/erofs/xattr.c196
-rw-r--r--drivers/staging/fbtft/fbtft.h58
-rw-r--r--drivers/staging/fsl-dpaa2/Kconfig16
-rw-r--r--drivers/staging/fsl-dpaa2/Makefile2
-rw-r--r--drivers/staging/fsl-dpaa2/ethernet/Makefile11
-rw-r--r--drivers/staging/fsl-dpaa2/ethernet/TODO18
-rw-r--r--drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c280
-rw-r--r--drivers/staging/fsl-dpaa2/ethernet/ethernet-driver.rst185
-rw-r--r--drivers/staging/fsl-dpaa2/ethsw/ethsw.c6
-rw-r--r--drivers/staging/fsl-dpaa2/rtc/Makefile7
-rw-r--r--drivers/staging/fsl-dpaa2/rtc/dprtc-cmd.h137
-rw-r--r--drivers/staging/fsl-dpaa2/rtc/dprtc.c701
-rw-r--r--drivers/staging/fsl-dpaa2/rtc/dprtc.h164
-rw-r--r--drivers/staging/fwserial/fwserial.c66
-rw-r--r--drivers/staging/gasket/Kconfig5
-rw-r--r--drivers/staging/gasket/apex_driver.c6
-rw-r--r--drivers/staging/gasket/gasket_core.c145
-rw-r--r--drivers/staging/gasket/gasket_core.h21
-rw-r--r--drivers/staging/gasket/gasket_interrupt.c110
-rw-r--r--drivers/staging/gasket/gasket_interrupt.h24
-rw-r--r--drivers/staging/gasket/gasket_page_table.c162
-rw-r--r--drivers/staging/gasket/gasket_sysfs.h4
-rw-r--r--drivers/staging/greybus/audio_codec.c1
-rw-r--r--drivers/staging/greybus/loopback.c8
-rw-r--r--drivers/staging/greybus/tools/README.loopback2
-rw-r--r--drivers/staging/greybus/tools/loopback_test.c2
-rw-r--r--drivers/staging/greybus/uart.c47
-rw-r--r--drivers/staging/iio/adc/Kconfig2
-rw-r--r--drivers/staging/iio/adc/ad7192.c2
-rw-r--r--drivers/staging/iio/adc/ad7280a.c2
-rw-r--r--drivers/staging/iio/adc/ad7606.c50
-rw-r--r--drivers/staging/iio/adc/ad7606.h31
-rw-r--r--drivers/staging/iio/adc/ad7606_par.c5
-rw-r--r--drivers/staging/iio/adc/ad7606_spi.c3
-rw-r--r--drivers/staging/iio/adc/ad7780.c2
-rw-r--r--drivers/staging/iio/cdc/ad7746.c2
-rw-r--r--drivers/staging/iio/frequency/ad9832.c2
-rw-r--r--drivers/staging/iio/frequency/ad9834.c2
-rw-r--r--drivers/staging/iio/impedance-analyzer/ad5933.c2
-rw-r--r--drivers/staging/ks7010/ks_hostif.c5
-rw-r--r--drivers/staging/media/Kconfig2
-rw-r--r--drivers/staging/media/Makefile1
-rw-r--r--drivers/staging/media/bcm2048/radio-bcm2048.c4
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_ipipe.c8
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_ipipeif.c2
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_isif.c2
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_resizer.c8
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_resizer.h2
-rw-r--r--drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c3
-rw-r--r--drivers/staging/media/davinci_vpfe/vpfe_video.c13
-rw-r--r--drivers/staging/media/imx/TODO29
-rw-r--r--drivers/staging/media/imx/imx-media-capture.c4
-rw-r--r--drivers/staging/media/imx/imx-media-csi.c70
-rw-r--r--drivers/staging/media/imx/imx-media-dev.c164
-rw-r--r--drivers/staging/media/imx/imx-media-fim.c2
-rw-r--r--drivers/staging/media/imx/imx-media-internal-sd.c5
-rw-r--r--drivers/staging/media/imx/imx-media-of.c108
-rw-r--r--drivers/staging/media/imx/imx-media-utils.c4
-rw-r--r--drivers/staging/media/imx/imx-media.h6
-rw-r--r--drivers/staging/media/imx/imx6-mipi-csi2.c33
-rw-r--r--drivers/staging/media/imx074/imx074.c3
-rw-r--r--drivers/staging/media/mt9t031/mt9t031.c1
-rw-r--r--drivers/staging/media/omap4iss/Kconfig2
-rw-r--r--drivers/staging/media/omap4iss/Makefile3
-rw-r--r--drivers/staging/media/omap4iss/iss.c8
-rw-r--r--drivers/staging/media/omap4iss/iss.h6
-rw-r--r--drivers/staging/media/omap4iss/iss_csi2.c6
-rw-r--r--drivers/staging/media/omap4iss/iss_csi2.h6
-rw-r--r--drivers/staging/media/omap4iss/iss_csiphy.c6
-rw-r--r--drivers/staging/media/omap4iss/iss_csiphy.h6
-rw-r--r--drivers/staging/media/omap4iss/iss_ipipe.c8
-rw-r--r--drivers/staging/media/omap4iss/iss_ipipe.h6
-rw-r--r--drivers/staging/media/omap4iss/iss_ipipeif.c8
-rw-r--r--drivers/staging/media/omap4iss/iss_ipipeif.h6
-rw-r--r--drivers/staging/media/omap4iss/iss_regs.h6
-rw-r--r--drivers/staging/media/omap4iss/iss_resizer.c8
-rw-r--r--drivers/staging/media/omap4iss/iss_resizer.h6
-rw-r--r--drivers/staging/media/omap4iss/iss_video.c19
-rw-r--r--drivers/staging/media/omap4iss/iss_video.h6
-rw-r--r--drivers/staging/media/sunxi/Kconfig15
-rw-r--r--drivers/staging/media/sunxi/Makefile1
-rw-r--r--drivers/staging/media/sunxi/cedrus/Kconfig14
-rw-r--r--drivers/staging/media/sunxi/cedrus/Makefile3
-rw-r--r--drivers/staging/media/sunxi/cedrus/TODO7
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus.c431
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus.h167
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_dec.c70
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_dec.h27
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_hw.c327
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_hw.h30
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c246
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_regs.h235
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_video.c542
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_video.h30
-rw-r--r--drivers/staging/media/zoran/zoran_card.c6
-rw-r--r--drivers/staging/media/zoran/zoran_driver.c6
-rw-r--r--drivers/staging/most/cdev/cdev.c12
-rw-r--r--drivers/staging/most/core.c49
-rw-r--r--drivers/staging/most/net/net.c2
-rw-r--r--drivers/staging/most/usb/usb.c55
-rw-r--r--drivers/staging/most/video/video.c4
-rw-r--r--drivers/staging/mt29f_spinand/mt29f_spinand.c47
-rw-r--r--drivers/staging/mt7621-dma/ralink-gdma.c1
-rw-r--r--drivers/staging/mt7621-eth/gsw_mt7621.c1
-rw-r--r--drivers/staging/mt7621-eth/mdio.c6
-rw-r--r--drivers/staging/mt7621-eth/mtk_eth_soc.c1
-rw-r--r--drivers/staging/mt7621-mmc/dbg.c104
-rw-r--r--drivers/staging/mt7621-mmc/dbg.h100
-rw-r--r--drivers/staging/mt7621-mmc/sd.c708
-rw-r--r--drivers/staging/mt7621-pci/pci-mt7621.c76
-rw-r--r--drivers/staging/octeon-usb/octeon-hcd.c58
-rw-r--r--drivers/staging/olpc_dcon/Kconfig1
-rw-r--r--drivers/staging/olpc_dcon/olpc_dcon.c5
-rw-r--r--drivers/staging/olpc_dcon/olpc_dcon_xo_1.c5
-rw-r--r--drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c5
-rw-r--r--drivers/staging/pi433/rf69.c3
-rw-r--r--drivers/staging/rtl8188eu/Makefile2
-rw-r--r--drivers/staging/rtl8188eu/TODO2
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_ap.c25
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_cmd.c57
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_debug.c25
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_efuse.c80
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_ieee80211.c24
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_ioctl_set.c142
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_led.c242
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_mlme.c69
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_mlme_ext.c60
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_pwrctrl.c9
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_recv.c43
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_security.c13
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_wlan_util.c73
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_xmit.c187
-rw-r--r--drivers/staging/rtl8188eu/hal/bb_cfg.c8
-rw-r--r--drivers/staging/rtl8188eu/hal/fw.c6
-rw-r--r--drivers/staging/rtl8188eu/hal/hal8188e_rate_adaptive.c18
-rw-r--r--drivers/staging/rtl8188eu/hal/hal_com.c11
-rw-r--r--drivers/staging/rtl8188eu/hal/odm.c21
-rw-r--r--drivers/staging/rtl8188eu/hal/odm_hwconfig.c (renamed from drivers/staging/rtl8188eu/hal/odm_HWConfig.c)100
-rw-r--r--drivers/staging/rtl8188eu/hal/odm_rtl8188e.c67
-rw-r--r--drivers/staging/rtl8188eu/hal/phy.c27
-rw-r--r--drivers/staging/rtl8188eu/hal/pwrseq.c5
-rw-r--r--drivers/staging/rtl8188eu/hal/rf_cfg.c2
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c101
-rw-r--r--drivers/staging/rtl8188eu/hal/usb_halinit.c26
-rw-r--r--drivers/staging/rtl8188eu/include/drv_types.h7
-rw-r--r--drivers/staging/rtl8188eu/include/hal_com.h12
-rw-r--r--drivers/staging/rtl8188eu/include/odm_hwconfig.h (renamed from drivers/staging/rtl8188eu/include/odm_HWConfig.h)0
-rw-r--r--drivers/staging/rtl8188eu/include/odm_precomp.h4
-rw-r--r--drivers/staging/rtl8188eu/include/odm_reg.h106
-rw-r--r--drivers/staging/rtl8188eu/include/osdep_service.h2
-rw-r--r--drivers/staging/rtl8188eu/include/phy.h1
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_mlme.h3
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_mlme_ext.h18
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_qos.h18
-rw-r--r--drivers/staging/rtl8188eu/include/wifi.h8
-rw-r--r--drivers/staging/rtl8188eu/os_dep/ioctl_linux.c25
-rw-r--r--drivers/staging/rtl8188eu/os_dep/mlme_linux.c2
-rw-r--r--drivers/staging/rtl8188eu/os_dep/os_intfs.c2
-rw-r--r--drivers/staging/rtl8188eu/os_dep/osdep_service.c14
-rw-r--r--drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c4
-rw-r--r--drivers/staging/rtl8188eu/os_dep/xmit_linux.c47
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_core.c2
-rw-r--r--drivers/staging/rtl8192e/rtllib_crypt_tkip.c34
-rw-r--r--drivers/staging/rtl8192e/rtllib_crypt_wep.c28
-rw-r--r--drivers/staging/rtl8192e/rtllib_softmac.c16
-rw-r--r--drivers/staging/rtl8192u/ieee80211/dot11d.c108
-rw-r--r--drivers/staging/rtl8192u/ieee80211/dot11d.h77
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211.h18
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_tkip.c34
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_wep.c26
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_module.c35
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c12
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c14
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c4
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c6
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl819x_BA.h84
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c184
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl819x_HT.h161
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c138
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl819x_TS.h6
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c16
-rw-r--r--drivers/staging/rtl8192u/r8180_93cx6.h19
-rw-r--r--drivers/staging/rtl8192u/r8190_rtl8256.c33
-rw-r--r--drivers/staging/rtl8192u/r8190_rtl8256.h11
-rw-r--r--drivers/staging/rtl8192u/r8192U.h46
-rw-r--r--drivers/staging/rtl8192u/r8192U_core.c105
-rw-r--r--drivers/staging/rtl8192u/r8192U_hw.h204
-rw-r--r--drivers/staging/rtl8192u/r819xU_firmware.c4
-rw-r--r--drivers/staging/rtl8192u/r819xU_firmware.h11
-rw-r--r--drivers/staging/rtl8192u/r819xU_phy.c31
-rw-r--r--drivers/staging/rtl8192u/r819xU_phy.h6
-rw-r--r--drivers/staging/rtl8712/basic_types.h10
-rw-r--r--drivers/staging/rtl8712/drv_types.h10
-rw-r--r--drivers/staging/rtl8712/ethernet.h10
-rw-r--r--drivers/staging/rtl8712/hal_init.c10
-rw-r--r--drivers/staging/rtl8712/ieee80211.c10
-rw-r--r--drivers/staging/rtl8712/ieee80211.h13
-rw-r--r--drivers/staging/rtl8712/mlme_linux.c14
-rw-r--r--drivers/staging/rtl8712/mlme_osdep.h14
-rw-r--r--drivers/staging/rtl8712/mp_custom_oid.h14
-rw-r--r--drivers/staging/rtl8712/os_intfs.c10
-rw-r--r--drivers/staging/rtl8712/osdep_intf.h14
-rw-r--r--drivers/staging/rtl8712/osdep_service.h14
-rw-r--r--drivers/staging/rtl8712/recv_linux.c14
-rw-r--r--drivers/staging/rtl8712/recv_osdep.h14
-rw-r--r--drivers/staging/rtl8712/rtl8712_bitdef.h15
-rw-r--r--drivers/staging/rtl8712/rtl8712_cmd.c14
-rw-r--r--drivers/staging/rtl8712/rtl8712_cmd.h14
-rw-r--r--drivers/staging/rtl8712/rtl8712_cmdctrl_bitdef.h15
-rw-r--r--drivers/staging/rtl8712/rtl8712_cmdctrl_regdef.h15
-rw-r--r--drivers/staging/rtl8712/rtl8712_debugctrl_bitdef.h15
-rw-r--r--drivers/staging/rtl8712/rtl8712_debugctrl_regdef.h15
-rw-r--r--drivers/staging/rtl8712/rtl8712_edcasetting_bitdef.h14
-rw-r--r--drivers/staging/rtl8712/rtl8712_edcasetting_regdef.h15
-rw-r--r--drivers/staging/rtl8712/rtl8712_efuse.c14
-rw-r--r--drivers/staging/rtl8712/rtl8712_event.h14
-rw-r--r--drivers/staging/rtl8712/rtl8712_fifoctrl_bitdef.h15
-rw-r--r--drivers/staging/rtl8712/rtl8712_fifoctrl_regdef.h15
-rw-r--r--drivers/staging/rtl8712/rtl8712_gp_bitdef.h14
-rw-r--r--drivers/staging/rtl8712/rtl8712_gp_regdef.h14
-rw-r--r--drivers/staging/rtl8712/rtl8712_hal.h14
-rw-r--r--drivers/staging/rtl8712/rtl8712_interrupt_bitdef.h15
-rw-r--r--drivers/staging/rtl8712/rtl8712_io.c14
-rw-r--r--drivers/staging/rtl8712/rtl8712_led.c14
-rw-r--r--drivers/staging/rtl8712/rtl8712_macsetting_bitdef.h15
-rw-r--r--drivers/staging/rtl8712/rtl8712_macsetting_regdef.h15
-rw-r--r--drivers/staging/rtl8712/rtl8712_powersave_bitdef.h15
-rw-r--r--drivers/staging/rtl8712/rtl8712_powersave_regdef.h15
-rw-r--r--drivers/staging/rtl8712/rtl8712_ratectrl_bitdef.h15
-rw-r--r--drivers/staging/rtl8712/rtl8712_ratectrl_regdef.h14
-rw-r--r--drivers/staging/rtl8712/rtl8712_recv.c14
-rw-r--r--drivers/staging/rtl8712/rtl8712_recv.h14
-rw-r--r--drivers/staging/rtl8712/rtl8712_regdef.h14
-rw-r--r--drivers/staging/rtl8712/rtl8712_security_bitdef.h15
-rw-r--r--drivers/staging/rtl8712/rtl8712_spec.h14
-rw-r--r--drivers/staging/rtl8712/rtl8712_syscfg_bitdef.h14
-rw-r--r--drivers/staging/rtl8712/rtl8712_syscfg_regdef.h14
-rw-r--r--drivers/staging/rtl8712/rtl8712_timectrl_bitdef.h15
-rw-r--r--drivers/staging/rtl8712/rtl8712_timectrl_regdef.h15
-rw-r--r--drivers/staging/rtl8712/rtl8712_wmac_bitdef.h14
-rw-r--r--drivers/staging/rtl8712/rtl8712_wmac_regdef.h14
-rw-r--r--drivers/staging/rtl8712/rtl8712_xmit.c14
-rw-r--r--drivers/staging/rtl8712/rtl8712_xmit.h14
-rw-r--r--drivers/staging/rtl8712/rtl871x_cmd.c14
-rw-r--r--drivers/staging/rtl8712/rtl871x_cmd.h14
-rw-r--r--drivers/staging/rtl8712/rtl871x_debug.h14
-rw-r--r--drivers/staging/rtl8712/rtl871x_eeprom.c14
-rw-r--r--drivers/staging/rtl8712/rtl871x_eeprom.h15
-rw-r--r--drivers/staging/rtl8712/rtl871x_event.h14
-rw-r--r--drivers/staging/rtl8712/rtl871x_ht.h14
-rw-r--r--drivers/staging/rtl8712/rtl871x_io.c20
-rw-r--r--drivers/staging/rtl8712/rtl871x_io.h14
-rw-r--r--drivers/staging/rtl8712/rtl871x_ioctl_linux.c21
-rw-r--r--drivers/staging/rtl8712/rtl871x_ioctl_rtl.c14
-rw-r--r--drivers/staging/rtl8712/rtl871x_ioctl_rtl.h14
-rw-r--r--drivers/staging/rtl8712/rtl871x_ioctl_set.c14
-rw-r--r--drivers/staging/rtl8712/rtl871x_ioctl_set.h14
-rw-r--r--drivers/staging/rtl8712/rtl871x_led.h14
-rw-r--r--drivers/staging/rtl8712/rtl871x_mlme.c14
-rw-r--r--drivers/staging/rtl8712/rtl871x_mlme.h14
-rw-r--r--drivers/staging/rtl8712/rtl871x_mp.c14
-rw-r--r--drivers/staging/rtl8712/rtl871x_mp.h14
-rw-r--r--drivers/staging/rtl8712/rtl871x_mp_ioctl.c14
-rw-r--r--drivers/staging/rtl8712/rtl871x_mp_ioctl.h14
-rw-r--r--drivers/staging/rtl8712/rtl871x_pwrctrl.c14
-rw-r--r--drivers/staging/rtl8712/rtl871x_pwrctrl.h14
-rw-r--r--drivers/staging/rtl8712/rtl871x_recv.c14
-rw-r--r--drivers/staging/rtl8712/rtl871x_rf.h14
-rw-r--r--drivers/staging/rtl8712/rtl871x_security.c14
-rw-r--r--drivers/staging/rtl8712/rtl871x_security.h14
-rw-r--r--drivers/staging/rtl8712/rtl871x_sta_mgt.c14
-rw-r--r--drivers/staging/rtl8712/rtl871x_wlan_sme.h14
-rw-r--r--drivers/staging/rtl8712/rtl871x_xmit.c16
-rw-r--r--drivers/staging/rtl8712/rtl871x_xmit.h14
-rw-r--r--drivers/staging/rtl8712/sta_info.h14
-rw-r--r--drivers/staging/rtl8712/usb_halinit.c14
-rw-r--r--drivers/staging/rtl8712/usb_intf.c14
-rw-r--r--drivers/staging/rtl8712/usb_ops.c14
-rw-r--r--drivers/staging/rtl8712/usb_ops.h14
-rw-r--r--drivers/staging/rtl8712/usb_ops_linux.c14
-rw-r--r--drivers/staging/rtl8712/usb_osintf.h14
-rw-r--r--drivers/staging/rtl8712/wifi.h14
-rw-r--r--drivers/staging/rtl8712/wlan_bssdef.h14
-rw-r--r--drivers/staging/rtl8712/xmit_linux.c14
-rw-r--r--drivers/staging/rtl8712/xmit_osdep.h14
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_ap.c24
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_debug.c2
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_mlme.c2
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_mlme_ext.c11
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_pwrctrl.c4
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_security.c5
-rw-r--r--drivers/staging/rtl8723bs/hal/hal_com_phycfg.c11
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_DIG.c4
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_EdcaTurboCheck.c2
-rw-r--r--drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c2
-rw-r--r--drivers/staging/rtl8723bs/include/drv_types.h2
-rw-r--r--drivers/staging/rtl8723bs/os_dep/ioctl_linux.c30
-rw-r--r--drivers/staging/rtl8723bs/os_dep/sdio_intf.c2
-rw-r--r--drivers/staging/rtlwifi/btcoexist/halbtcoutsrc.c10
-rw-r--r--drivers/staging/rtlwifi/efuse.c3
-rw-r--r--drivers/staging/rtlwifi/halmac/rtl_halmac.c4
-rw-r--r--drivers/staging/rtlwifi/phydm/phydm_adc_sampling.c2
-rw-r--r--drivers/staging/rtlwifi/phydm/phydm_dig.c4
-rw-r--r--drivers/staging/rtlwifi/regd.c2
-rw-r--r--drivers/staging/rtlwifi/wifi.h4
-rw-r--r--drivers/staging/rts5208/ms.c619
-rw-r--r--drivers/staging/rts5208/rtsx_card.c92
-rw-r--r--drivers/staging/rts5208/rtsx_card.h3
-rw-r--r--drivers/staging/rts5208/rtsx_chip.c396
-rw-r--r--drivers/staging/rts5208/rtsx_scsi.c108
-rw-r--r--drivers/staging/rts5208/sd.c649
-rw-r--r--drivers/staging/rts5208/spi.c141
-rw-r--r--drivers/staging/rts5208/xd.c210
-rw-r--r--drivers/staging/sm750fb/ddk750_mode.c2
-rw-r--r--drivers/staging/sm750fb/ddk750_sii164.c8
-rw-r--r--drivers/staging/sm750fb/sm750.c10
-rw-r--r--drivers/staging/speakup/spk_ttyio.c4
-rw-r--r--drivers/staging/vboxvideo/TODO1
-rw-r--r--drivers/staging/vboxvideo/vbox_drv.c165
-rw-r--r--drivers/staging/vboxvideo/vbox_drv.h88
-rw-r--r--drivers/staging/vboxvideo/vbox_fb.c152
-rw-r--r--drivers/staging/vboxvideo/vbox_irq.c8
-rw-r--r--drivers/staging/vboxvideo/vbox_main.c185
-rw-r--r--drivers/staging/vboxvideo/vbox_mode.c922
-rw-r--r--drivers/staging/vboxvideo/vbox_ttm.c143
-rw-r--r--drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c235
-rw-r--r--drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c338
-rw-r--r--drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c883
-rw-r--r--drivers/staging/vc04_services/bcm2835-audio/bcm2835.c222
-rw-r--r--drivers/staging/vc04_services/bcm2835-audio/bcm2835.h86
-rw-r--r--drivers/staging/vc04_services/bcm2835-camera/TODO6
-rw-r--r--drivers/staging/vc04_services/bcm2835-camera/controls.c2
-rw-r--r--drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c10
-rw-r--r--drivers/staging/vc04_services/interface/vchi/connections/connection.h324
-rw-r--r--drivers/staging/vc04_services/interface/vchi/message_drivers/message.h196
-rw-r--r--drivers/staging/vc04_services/interface/vchi/vchi.h227
-rw-r--r--drivers/staging/vc04_services/interface/vchi/vchi_cfg.h2
-rw-r--r--drivers/staging/vc04_services/interface/vchi/vchi_cfg_internal.h71
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c4
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c35
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h5
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_genversion88
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_shim.c38
-rw-r--r--drivers/staging/vt6655/rxtx.c29
-rw-r--r--drivers/staging/wilc1000/Kconfig8
-rw-r--r--drivers/staging/wilc1000/Makefile5
-rw-r--r--drivers/staging/wilc1000/coreconfigurator.c4
-rw-r--r--drivers/staging/wilc1000/host_interface.c277
-rw-r--r--drivers/staging/wilc1000/host_interface.h19
-rw-r--r--drivers/staging/wilc1000/linux_mon.c3
-rw-r--r--drivers/staging/wilc1000/linux_wlan.c129
-rw-r--r--drivers/staging/wilc1000/wilc_debugfs.c115
-rw-r--r--drivers/staging/wilc1000/wilc_sdio.c56
-rw-r--r--drivers/staging/wilc1000/wilc_spi.c57
-rw-r--r--drivers/staging/wilc1000/wilc_wfi_cfgoperations.c281
-rw-r--r--drivers/staging/wilc1000/wilc_wfi_cfgoperations.h4
-rw-r--r--drivers/staging/wilc1000/wilc_wfi_netdevice.h55
-rw-r--r--drivers/staging/wilc1000/wilc_wlan.c208
-rw-r--r--drivers/staging/wilc1000/wilc_wlan.h8
-rw-r--r--drivers/staging/wilc1000/wilc_wlan_cfg.c294
-rw-r--r--drivers/staging/wilc1000/wilc_wlan_cfg.h26
-rw-r--r--drivers/staging/wilc1000/wilc_wlan_if.h4
-rw-r--r--drivers/staging/wlan-ng/cfg80211.c49
-rw-r--r--drivers/staging/wlan-ng/hfa384x_usb.c46
-rw-r--r--drivers/staging/wlan-ng/p80211conv.c2
-rw-r--r--drivers/staging/wlan-ng/p80211metadef.h121
-rw-r--r--drivers/staging/wlan-ng/p80211metastruct.h3
-rw-r--r--drivers/staging/wlan-ng/p80211netdev.c12
-rw-r--r--drivers/staging/wlan-ng/p80211req.c36
-rw-r--r--drivers/staging/wlan-ng/prism2fw.c37
-rw-r--r--drivers/staging/wlan-ng/prism2mib.c76
-rw-r--r--drivers/staging/wlan-ng/prism2sta.c86
-rw-r--r--drivers/target/iscsi/cxgbit/cxgbit_cm.c23
-rw-r--r--drivers/target/iscsi/iscsi_target.c2
-rw-r--r--drivers/target/iscsi/iscsi_target_erl0.c15
-rw-r--r--drivers/target/iscsi/iscsi_target_erl1.c17
-rw-r--r--drivers/target/iscsi/iscsi_target_erl2.c2
-rw-r--r--drivers/target/iscsi/iscsi_target_erl2.h2
-rw-r--r--drivers/target/iscsi/iscsi_target_login.c2
-rw-r--r--drivers/target/iscsi/iscsi_target_stat.c4
-rw-r--r--drivers/target/iscsi/iscsi_target_util.c50
-rw-r--r--drivers/target/iscsi/iscsi_target_util.h1
-rw-r--r--drivers/target/target_core_alua.c2
-rw-r--r--drivers/target/target_core_file.c6
-rw-r--r--drivers/target/target_core_iblock.c58
-rw-r--r--drivers/target/target_core_iblock.h1
-rw-r--r--drivers/target/target_core_sbc.c23
-rw-r--r--drivers/target/target_core_spc.c6
-rw-r--r--drivers/target/target_core_transport.c25
-rw-r--r--drivers/target/target_core_xcopy.c3
-rw-r--r--drivers/tc/tc.c8
-rw-r--r--drivers/tee/optee/core.c2
-rw-r--r--drivers/tee/tee_core.c113
-rw-r--r--drivers/thermal/Kconfig2
-rw-r--r--drivers/thermal/Makefile2
-rw-r--r--drivers/thermal/armada_thermal.c4
-rw-r--r--drivers/thermal/da9062-thermal.c4
-rw-r--r--drivers/thermal/hisi_thermal.c249
-rw-r--r--drivers/thermal/imx_thermal.c31
-rw-r--r--drivers/thermal/intel_soc_dts_thermal.c2
-rw-r--r--drivers/thermal/of-thermal.c152
-rw-r--r--drivers/thermal/qcom-spmi-temp-alarm.c158
-rw-r--r--drivers/thermal/qcom/tsens-8916.c12
-rw-r--r--drivers/thermal/qcom/tsens-8960.c41
-rw-r--r--drivers/thermal/qcom/tsens-8974.c12
-rw-r--r--drivers/thermal/qcom/tsens-common.c62
-rw-r--r--drivers/thermal/qcom/tsens-v2.c8
-rw-r--r--drivers/thermal/qcom/tsens.c19
-rw-r--r--drivers/thermal/qcom/tsens.h23
-rw-r--r--drivers/thermal/qoriq_thermal.c5
-rw-r--r--drivers/thermal/rcar_gen3_thermal.c2
-rw-r--r--drivers/thermal/rcar_thermal.c11
-rw-r--r--drivers/thermal/st/Kconfig14
-rw-r--r--drivers/thermal/st/Makefile1
-rw-r--r--drivers/thermal/st/stm_thermal.c760
-rw-r--r--drivers/thermal/thermal_core.c9
-rw-r--r--drivers/thunderbolt/cap.c3
-rw-r--r--drivers/thunderbolt/ctl.c12
-rw-r--r--drivers/thunderbolt/ctl.h3
-rw-r--r--drivers/thunderbolt/dma_port.c5
-rw-r--r--drivers/thunderbolt/dma_port.h5
-rw-r--r--drivers/thunderbolt/domain.c7
-rw-r--r--drivers/thunderbolt/eeprom.c5
-rw-r--r--drivers/thunderbolt/icm.c54
-rw-r--r--drivers/thunderbolt/nhi.c35
-rw-r--r--drivers/thunderbolt/nhi.h3
-rw-r--r--drivers/thunderbolt/nhi_regs.h1
-rw-r--r--drivers/thunderbolt/path.c26
-rw-r--r--drivers/thunderbolt/property.c5
-rw-r--r--drivers/thunderbolt/switch.c71
-rw-r--r--drivers/thunderbolt/tb.c10
-rw-r--r--drivers/thunderbolt/tb.h9
-rw-r--r--drivers/thunderbolt/tb_msgs.h5
-rw-r--r--drivers/thunderbolt/tb_regs.h3
-rw-r--r--drivers/thunderbolt/xdomain.c5
-rw-r--r--drivers/tty/amiserial.c90
-rw-r--r--drivers/tty/cyclades.c77
-rw-r--r--drivers/tty/ehv_bytechan.c12
-rw-r--r--drivers/tty/ipwireless/tty.c36
-rw-r--r--drivers/tty/isicom.c72
-rw-r--r--drivers/tty/moxa.c79
-rw-r--r--drivers/tty/mxser.c97
-rw-r--r--drivers/tty/n_gsm.c11
-rw-r--r--drivers/tty/n_r3964.c22
-rw-r--r--drivers/tty/n_tty.c20
-rw-r--r--drivers/tty/pty.c14
-rw-r--r--drivers/tty/serial/8250/8250_core.c6
-rw-r--r--drivers/tty/serial/8250/8250_dw.c4
-rw-r--r--drivers/tty/serial/8250/8250_of.c22
-rw-r--r--drivers/tty/serial/8250/8250_port.c29
-rw-r--r--drivers/tty/serial/8250/8250_uniphier.c62
-rw-r--r--drivers/tty/serial/8250/Kconfig2
-rw-r--r--drivers/tty/serial/Kconfig1
-rw-r--r--drivers/tty/serial/atmel_serial.c232
-rw-r--r--drivers/tty/serial/atmel_serial.h3
-rw-r--r--drivers/tty/serial/cpm_uart/cpm_uart_core.c10
-rw-r--r--drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c2
-rw-r--r--drivers/tty/serial/cpm_uart/cpm_uart_cpm2.c2
-rw-r--r--drivers/tty/serial/fsl_lpuart.c12
-rw-r--r--drivers/tty/serial/imx.c38
-rw-r--r--drivers/tty/serial/kgdboc.c46
-rw-r--r--drivers/tty/serial/mxs-auart.c3
-rw-r--r--drivers/tty/serial/pmac_zilog.c8
-rw-r--r--drivers/tty/serial/qcom_geni_serial.c73
-rw-r--r--drivers/tty/serial/samsung.c8
-rw-r--r--drivers/tty/serial/sc16is7xx.c47
-rw-r--r--drivers/tty/serial/serial_core.c103
-rw-r--r--drivers/tty/serial/serial_mctrl_gpio.c7
-rw-r--r--drivers/tty/serial/sh-sci.c73
-rw-r--r--drivers/tty/serial/sn_console.c15
-rw-r--r--drivers/tty/serial/sprd_serial.c98
-rw-r--r--drivers/tty/serial/uartlite.c71
-rw-r--r--drivers/tty/serial/xilinx_uartps.c303
-rw-r--r--drivers/tty/synclink.c3
-rw-r--r--drivers/tty/synclink_gt.c19
-rw-r--r--drivers/tty/synclinkmp.c3
-rw-r--r--drivers/tty/sysrq.c2
-rw-r--r--drivers/tty/tty_baudrate.c4
-rw-r--r--drivers/tty/tty_buffer.c13
-rw-r--r--drivers/tty/tty_io.c237
-rw-r--r--drivers/tty/tty_ioctl.c16
-rw-r--r--drivers/tty/tty_port.c7
-rw-r--r--drivers/tty/vt/vt.c2
-rw-r--r--drivers/tty/vt/vt_ioctl.c31
-rw-r--r--drivers/uio/uio.c35
-rw-r--r--drivers/uio/uio_dmem_genirq.c3
-rw-r--r--drivers/uio/uio_fsl_elbc_gpcm.c3
-rw-r--r--drivers/uio/uio_hv_generic.c116
-rw-r--r--drivers/uio/uio_pdrv_genirq.c3
-rw-r--r--drivers/usb/chipidea/ci_hdrc_imx.c19
-rw-r--r--drivers/usb/chipidea/core.c19
-rw-r--r--drivers/usb/chipidea/host.c9
-rw-r--r--drivers/usb/chipidea/otg.c9
-rw-r--r--drivers/usb/chipidea/otg.h3
-rw-r--r--drivers/usb/chipidea/udc.c9
-rw-r--r--drivers/usb/chipidea/usbmisc_imx.c4
-rw-r--r--drivers/usb/class/cdc-acm.c63
-rw-r--r--drivers/usb/class/usbtmc.c1583
-rw-r--r--drivers/usb/core/buffer.c8
-rw-r--r--drivers/usb/core/devio.c8
-rw-r--r--drivers/usb/core/driver.c3
-rw-r--r--drivers/usb/core/generic.c27
-rw-r--r--drivers/usb/core/hcd.c14
-rw-r--r--drivers/usb/core/hub.c42
-rw-r--r--drivers/usb/core/phy.c7
-rw-r--r--drivers/usb/core/port.c10
-rw-r--r--drivers/usb/dwc2/core.h29
-rw-r--r--drivers/usb/dwc2/debugfs.c1
-rw-r--r--drivers/usb/dwc2/gadget.c121
-rw-r--r--drivers/usb/dwc2/hcd.c48
-rw-r--r--drivers/usb/dwc2/hw.h15
-rw-r--r--drivers/usb/dwc2/params.c7
-rw-r--r--drivers/usb/dwc2/platform.c8
-rw-r--r--drivers/usb/dwc3/Kconfig2
-rw-r--r--drivers/usb/dwc3/core.c2
-rw-r--r--drivers/usb/dwc3/dwc3-exynos.c212
-rw-r--r--drivers/usb/dwc3/gadget.c29
-rw-r--r--drivers/usb/early/xhci-dbc.c17
-rw-r--r--drivers/usb/gadget/function/f_mass_storage.c7
-rw-r--r--drivers/usb/gadget/function/f_uac2.c216
-rw-r--r--drivers/usb/gadget/function/f_uvc.c57
-rw-r--r--drivers/usb/gadget/function/u_uvc.h3
-rw-r--r--drivers/usb/gadget/function/uvc.h16
-rw-r--r--drivers/usb/gadget/function/uvc_configfs.c1168
-rw-r--r--drivers/usb/gadget/function/uvc_queue.c2
-rw-r--r--drivers/usb/gadget/function/uvc_v4l2.c4
-rw-r--r--drivers/usb/gadget/function/uvc_video.c48
-rw-r--r--drivers/usb/gadget/function/uvc_video.h2
-rw-r--r--drivers/usb/gadget/udc/aspeed-vhub/epn.c2
-rw-r--r--drivers/usb/gadget/udc/atmel_usba_udc.c8
-rw-r--r--drivers/usb/gadget/udc/core.c9
-rw-r--r--drivers/usb/gadget/udc/fotg210-udc.c2
-rw-r--r--drivers/usb/gadget/udc/fsl_udc_core.c36
-rw-r--r--drivers/usb/gadget/udc/mv_udc_core.c2
-rw-r--r--drivers/usb/gadget/udc/net2280.c3
-rw-r--r--drivers/usb/gadget/udc/renesas_usb3.c14
-rw-r--r--drivers/usb/gadget/udc/udc-xilinx.c2
-rw-r--r--drivers/usb/host/Kconfig2
-rw-r--r--drivers/usb/host/Makefile1
-rw-r--r--drivers/usb/host/ehci-hcd.c11
-rw-r--r--drivers/usb/host/ehci-mv.c181
-rw-r--r--drivers/usb/host/ehci-q.c4
-rw-r--r--drivers/usb/host/ehci-timer.c2
-rw-r--r--drivers/usb/host/ehci.h4
-rw-r--r--drivers/usb/host/fotg210-hcd.c50
-rw-r--r--drivers/usb/host/fotg210.h7
-rw-r--r--drivers/usb/host/ohci-at91.c2
-rw-r--r--drivers/usb/host/pci-quirks.c12
-rw-r--r--drivers/usb/host/xhci-hub.c5
-rw-r--r--drivers/usb/host/xhci-mtk-sch.c429
-rw-r--r--drivers/usb/host/xhci-mtk.c4
-rw-r--r--drivers/usb/host/xhci-mtk.h23
-rw-r--r--drivers/usb/host/xhci-pci.c32
-rw-r--r--drivers/usb/host/xhci-plat.c3
-rw-r--r--drivers/usb/host/xhci-ring.c20
-rw-r--r--drivers/usb/host/xhci-tegra.c144
-rw-r--r--drivers/usb/host/xhci.h3
-rw-r--r--drivers/usb/misc/appledisplay.c7
-rw-r--r--drivers/usb/misc/iowarrior.c4
-rw-r--r--drivers/usb/misc/trancevibrator.c4
-rw-r--r--drivers/usb/mtu3/mtu3_core.c4
-rw-r--r--drivers/usb/mtu3/mtu3_gadget.c22
-rw-r--r--drivers/usb/phy/phy-ab8500-usb.c8
-rw-r--r--drivers/usb/phy/phy-mxs-usb.c2
-rw-r--r--drivers/usb/renesas_usbhs/common.c113
-rw-r--r--drivers/usb/renesas_usbhs/common.h5
-rw-r--r--drivers/usb/renesas_usbhs/rcar3.c27
-rw-r--r--drivers/usb/roles/intel-xhci-usb-role-switch.c2
-rw-r--r--drivers/usb/serial/ark3116.c38
-rw-r--r--drivers/usb/serial/cypress_m8.c7
-rw-r--r--drivers/usb/serial/f81232.c36
-rw-r--r--drivers/usb/serial/f81534.c38
-rw-r--r--drivers/usb/serial/ftdi_sio.c439
-rw-r--r--drivers/usb/serial/ftdi_sio.h28
-rw-r--r--drivers/usb/serial/io_edgeport.c37
-rw-r--r--drivers/usb/serial/io_ti.c47
-rw-r--r--drivers/usb/serial/mos7720.c86
-rw-r--r--drivers/usb/serial/mos7840.c39
-rw-r--r--drivers/usb/serial/opticon.c43
-rw-r--r--drivers/usb/serial/option.c18
-rw-r--r--drivers/usb/serial/pl2303.c29
-rw-r--r--drivers/usb/serial/quatech2.c42
-rw-r--r--drivers/usb/serial/ssu100.c42
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c74
-rw-r--r--drivers/usb/serial/usb-serial-simple.c3
-rw-r--r--drivers/usb/serial/usb-serial.c20
-rw-r--r--drivers/usb/serial/usb-wwan.h6
-rw-r--r--drivers/usb/serial/usb_wwan.c63
-rw-r--r--drivers/usb/serial/whiteheat.c42
-rw-r--r--drivers/usb/storage/Kconfig23
-rw-r--r--drivers/usb/storage/isd200.c2
-rw-r--r--drivers/usb/typec/Kconfig45
-rw-r--r--drivers/usb/typec/Makefile6
-rw-r--r--drivers/usb/typec/class.c40
-rw-r--r--drivers/usb/typec/fusb302/Kconfig7
-rw-r--r--drivers/usb/typec/fusb302/Makefile2
-rw-r--r--drivers/usb/typec/tcpm/Kconfig52
-rw-r--r--drivers/usb/typec/tcpm/Makefile7
-rw-r--r--drivers/usb/typec/tcpm/fusb302.c (renamed from drivers/usb/typec/fusb302/fusb302.c)75
-rw-r--r--drivers/usb/typec/tcpm/fusb302_reg.h (renamed from drivers/usb/typec/fusb302/fusb302_reg.h)0
-rw-r--r--drivers/usb/typec/tcpm/tcpci.c (renamed from drivers/usb/typec/tcpci.c)0
-rw-r--r--drivers/usb/typec/tcpm/tcpci.h (renamed from drivers/usb/typec/tcpci.h)0
-rw-r--r--drivers/usb/typec/tcpm/tcpci_rt1711h.c (renamed from drivers/usb/typec/tcpci_rt1711h.c)0
-rw-r--r--drivers/usb/typec/tcpm/tcpm.c (renamed from drivers/usb/typec/tcpm.c)17
-rw-r--r--drivers/usb/typec/tcpm/wcove.c (renamed from drivers/usb/typec/typec_wcove.c)0
-rw-r--r--drivers/usb/typec/ucsi/Kconfig10
-rw-r--r--drivers/usb/typec/ucsi/Makefile2
-rw-r--r--drivers/usb/typec/ucsi/ucsi_ccg.c307
-rw-r--r--drivers/usb/usbip/usbip_common.c2
-rw-r--r--drivers/usb/usbip/vhci_hcd.c57
-rw-r--r--drivers/usb/usbip/vudc_main.c10
-rw-r--r--drivers/usb/wusbcore/crypto.c16
-rw-r--r--drivers/usb/wusbcore/wa-rpipe.c6
-rw-r--r--drivers/vfio/Kconfig2
-rw-r--r--drivers/vfio/pci/vfio_pci.c8
-rw-r--r--drivers/vfio/pci/vfio_pci_config.c31
-rw-r--r--drivers/vfio/vfio_iommu_spapr_tce.c23
-rw-r--r--drivers/vhost/net.c326
-rw-r--r--drivers/vhost/scsi.c426
-rw-r--r--drivers/vhost/vhost.c26
-rw-r--r--drivers/video/backlight/Kconfig16
-rw-r--r--drivers/video/backlight/Makefile2
-rw-r--r--drivers/video/backlight/adp5520_bl.c2
-rw-r--r--drivers/video/backlight/adp8860_bl.c2
-rw-r--r--drivers/video/backlight/adp8870_bl.c2
-rw-r--r--drivers/video/backlight/as3711_bl.c7
-rw-r--r--drivers/video/backlight/ld9040.c811
-rw-r--r--drivers/video/backlight/ld9040_gamma.h202
-rw-r--r--drivers/video/backlight/lm3639_bl.c6
-rw-r--r--drivers/video/backlight/pwm_bl.c81
-rw-r--r--drivers/video/backlight/s6e63m0.c857
-rw-r--r--drivers/video/backlight/s6e63m0_gamma.h266
-rw-r--r--drivers/video/fbdev/Kconfig59
-rw-r--r--drivers/video/fbdev/Makefile1
-rw-r--r--drivers/video/fbdev/arcfb.c2
-rw-r--r--drivers/video/fbdev/atmel_lcdfb.c43
-rw-r--r--drivers/video/fbdev/aty/atyfb.h15
-rw-r--r--drivers/video/fbdev/aty/atyfb_base.c43
-rw-r--r--drivers/video/fbdev/aty/mach64_accel.c32
-rw-r--r--drivers/video/fbdev/aty/mach64_ct.c10
-rw-r--r--drivers/video/fbdev/cg14.c4
-rw-r--r--drivers/video/fbdev/cg3.c2
-rw-r--r--drivers/video/fbdev/chipsfb.c3
-rw-r--r--drivers/video/fbdev/clps711xfb.c314
-rw-r--r--drivers/video/fbdev/controlfb.c5
-rw-r--r--drivers/video/fbdev/core/fbmon.c4
-rw-r--r--drivers/video/fbdev/efifb.c6
-rw-r--r--drivers/video/fbdev/fsl-diu-fb.c2
-rw-r--r--drivers/video/fbdev/imsttfb.c2
-rw-r--r--drivers/video/fbdev/leo.c2
-rw-r--r--drivers/video/fbdev/mmp/hw/Kconfig1
-rw-r--r--drivers/video/fbdev/mmp/panel/Kconfig1
-rw-r--r--drivers/video/fbdev/offb.c12
-rw-r--r--drivers/video/fbdev/omap/lcd_ams_delta.c55
-rw-r--r--drivers/video/fbdev/omap2/omapfb/dss/Kconfig7
-rw-r--r--drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c5
-rw-r--r--drivers/video/fbdev/p9100.c2
-rw-r--r--drivers/video/fbdev/platinumfb.c5
-rw-r--r--drivers/video/fbdev/pxa168fb.c9
-rw-r--r--drivers/video/fbdev/sbuslib.c28
-rw-r--r--drivers/video/fbdev/sh7760fb.c7
-rw-r--r--drivers/video/fbdev/sis/init301.c4
-rw-r--r--drivers/video/fbdev/ssd1307fb.c4
-rw-r--r--drivers/video/fbdev/stifb.c2
-rw-r--r--drivers/video/fbdev/udlfb.c141
-rw-r--r--drivers/video/fbdev/valkyriefb.c12
-rw-r--r--drivers/video/hdmi.c519
-rw-r--r--drivers/video/of_display_timing.c2
-rw-r--r--drivers/video/vgastate.c2
-rw-r--r--drivers/virtio/virtio_balloon.c374
-rw-r--r--drivers/vme/vme.c1
-rw-r--r--drivers/w1/masters/omap_hdq.c2
-rw-r--r--drivers/w1/slaves/w1_ds2438.c66
-rw-r--r--drivers/watchdog/Kconfig12
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/armada_37xx_wdt.c388
-rw-r--r--drivers/watchdog/booke_wdt.c2
-rw-r--r--drivers/watchdog/hpwdt.c24
-rw-r--r--drivers/watchdog/iTCO_vendor.h4
-rw-r--r--drivers/watchdog/iTCO_vendor_support.c168
-rw-r--r--drivers/watchdog/iTCO_wdt.c4
-rw-r--r--drivers/watchdog/lantiq_wdt.c311
-rw-r--r--drivers/watchdog/mpc8xxx_wdt.c46
-rw-r--r--drivers/watchdog/renesas_wdt.c6
-rw-r--r--drivers/watchdog/rza_wdt.c93
-rw-r--r--drivers/watchdog/sama5d4_wdt.c6
-rw-r--r--drivers/watchdog/ts4800_wdt.c1
-rw-r--r--drivers/watchdog/via_wdt.c4
-rw-r--r--drivers/watchdog/w83627hf_wdt.c8
-rw-r--r--drivers/watchdog/watchdog_dev.c10
-rw-r--r--drivers/xen/Kconfig13
-rw-r--r--drivers/xen/balloon.c5
-rw-r--r--drivers/xen/biomerge.c3
-rw-r--r--drivers/xen/events/events_base.c2
-rw-r--r--drivers/xen/grant-table.c4
-rw-r--r--drivers/xen/privcmd-buf.c22
-rw-r--r--drivers/xen/pvcalls-back.c8
-rw-r--r--drivers/xen/swiotlb-xen.c18
-rw-r--r--drivers/xen/time.c2
-rw-r--r--drivers/xen/xen-acpi-pad.c1
-rw-r--r--drivers/xen/xen-balloon.c13
-rw-r--r--drivers/xen/xen-selfballoon.c2
-rw-r--r--drivers/xen/xenbus/xenbus_client.c6
5163 files changed, 318958 insertions, 142226 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index dd1eea90f67f..7cea769c37df 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -138,7 +138,6 @@ config ACPI_REV_OVERRIDE_POSSIBLE
config ACPI_EC_DEBUGFS
tristate "EC read/write access through /sys/kernel/debug/ec"
- default n
help
Say N to disable Embedded Controller /sys/kernel/debug interface
@@ -283,7 +282,6 @@ config ACPI_PROCESSOR
config ACPI_IPMI
tristate "IPMI"
depends on IPMI_HANDLER
- default n
help
This driver enables the ACPI to access the BMC controller. And it
uses the IPMI request/response message to communicate with BMC
@@ -361,7 +359,6 @@ config ACPI_TABLE_UPGRADE
config ACPI_DEBUG
bool "Debug Statements"
- default n
help
The ACPI subsystem can produce debug output. Saying Y enables this
output and increases the kernel size by around 50K.
@@ -374,7 +371,6 @@ config ACPI_DEBUG
config ACPI_PCI_SLOT
bool "PCI slot detection driver"
depends on SYSFS
- default n
help
This driver creates entries in /sys/bus/pci/slots/ for all PCI
slots in the system. This can help correlate PCI bus addresses,
@@ -436,7 +432,6 @@ config ACPI_HED
config ACPI_CUSTOM_METHOD
tristate "Allow ACPI methods to be inserted/replaced at run time"
depends on DEBUG_FS
- default n
help
This debug facility allows ACPI AML methods to be inserted and/or
replaced without rebooting the system. For details refer to:
@@ -481,7 +476,6 @@ config ACPI_EXTLOG
tristate "Extended Error Log support"
depends on X86_MCE && X86_LOCAL_APIC && EDAC
select UEFI_CPER
- default n
help
Certain usages such as Predictive Failure Analysis (PFA) require
more information about the error than what can be described in
@@ -498,6 +492,9 @@ config ACPI_EXTLOG
driver adds support for that functionality with corresponding
tracepoint which carries that information to userspace.
+config ACPI_ADXL
+ bool
+
menuconfig PMIC_OPREGION
bool "PMIC (Power Management Integrated Circuit) operation region support"
help
@@ -515,7 +512,7 @@ config CRC_PMIC_OPREGION
config XPOWER_PMIC_OPREGION
bool "ACPI operation region support for XPower AXP288 PMIC"
- depends on MFD_AXP20X_I2C
+ depends on MFD_AXP20X_I2C && IOSF_MBI=y
help
This config adds ACPI operation region support for XPower AXP288 PMIC.
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 6d59aa109a91..edc039313cd6 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -61,6 +61,9 @@ acpi-$(CONFIG_ACPI_LPIT) += acpi_lpit.o
acpi-$(CONFIG_ACPI_GENERIC_GSI) += irq.o
acpi-$(CONFIG_ACPI_WATCHDOG) += acpi_watchdog.o
+# Address translation
+acpi-$(CONFIG_ACPI_ADXL) += acpi_adxl.o
+
# These are (potentially) separate modules
# IPMI may be used by other drivers, so it has to initialise before them
diff --git a/drivers/acpi/acpi_adxl.c b/drivers/acpi/acpi_adxl.c
new file mode 100644
index 000000000000..13c8f7b50c46
--- /dev/null
+++ b/drivers/acpi/acpi_adxl.c
@@ -0,0 +1,192 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Address translation interface via ACPI DSM.
+ * Copyright (C) 2018 Intel Corporation
+ *
+ * Specification for this interface is available at:
+ *
+ * https://cdrdv2.intel.com/v1/dl/getContent/603354
+ */
+
+#include <linux/acpi.h>
+#include <linux/adxl.h>
+
+#define ADXL_REVISION 0x1
+#define ADXL_IDX_GET_ADDR_PARAMS 0x1
+#define ADXL_IDX_FORWARD_TRANSLATE 0x2
+#define ACPI_ADXL_PATH "\\_SB.ADXL"
+
+/*
+ * The specification doesn't provide a limit on how many
+ * components are in a memory address. But since we allocate
+ * memory based on the number the BIOS tells us, we should
+ * defend against insane values.
+ */
+#define ADXL_MAX_COMPONENTS 500
+
+#undef pr_fmt
+#define pr_fmt(fmt) "ADXL: " fmt
+
+static acpi_handle handle;
+static union acpi_object *params;
+static const guid_t adxl_guid =
+ GUID_INIT(0xAA3C050A, 0x7EA4, 0x4C1F,
+ 0xAF, 0xDA, 0x12, 0x67, 0xDF, 0xD3, 0xD4, 0x8D);
+
+static int adxl_count;
+static char **adxl_component_names;
+
+static union acpi_object *adxl_dsm(int cmd, union acpi_object argv[])
+{
+ union acpi_object *obj, *o;
+
+ obj = acpi_evaluate_dsm_typed(handle, &adxl_guid, ADXL_REVISION,
+ cmd, argv, ACPI_TYPE_PACKAGE);
+ if (!obj) {
+ pr_info("DSM call failed for cmd=%d\n", cmd);
+ return NULL;
+ }
+
+ if (obj->package.count != 2) {
+ pr_info("Bad pkg count %d\n", obj->package.count);
+ goto err;
+ }
+
+ o = obj->package.elements;
+ if (o->type != ACPI_TYPE_INTEGER) {
+ pr_info("Bad 1st element type %d\n", o->type);
+ goto err;
+ }
+ if (o->integer.value) {
+ pr_info("Bad ret val %llu\n", o->integer.value);
+ goto err;
+ }
+
+ o = obj->package.elements + 1;
+ if (o->type != ACPI_TYPE_PACKAGE) {
+ pr_info("Bad 2nd element type %d\n", o->type);
+ goto err;
+ }
+ return obj;
+
+err:
+ ACPI_FREE(obj);
+ return NULL;
+}
+
+/**
+ * adxl_get_component_names - get list of memory component names
+ * Returns NULL terminated list of string names
+ *
+ * Give the caller a pointer to the list of memory component names
+ * e.g. { "SystemAddress", "ProcessorSocketId", "ChannelId", ... NULL }
+ * Caller should count how many strings in order to allocate a buffer
+ * for the return from adxl_decode().
+ */
+const char * const *adxl_get_component_names(void)
+{
+ return (const char * const *)adxl_component_names;
+}
+EXPORT_SYMBOL_GPL(adxl_get_component_names);
+
+/**
+ * adxl_decode - ask BIOS to decode a system address to memory address
+ * @addr: the address to decode
+ * @component_values: pointer to array of values for each component
+ * Returns 0 on success, negative error code otherwise
+ *
+ * The index of each value returned in the array matches the index of
+ * each component name returned by adxl_get_component_names().
+ * Components that are not defined for this address translation (e.g.
+ * mirror channel number for a non-mirrored address) are set to ~0ull.
+ */
+int adxl_decode(u64 addr, u64 component_values[])
+{
+ union acpi_object argv4[2], *results, *r;
+ int i, cnt;
+
+ if (!adxl_component_names)
+ return -EOPNOTSUPP;
+
+ 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 = addr;
+
+ results = adxl_dsm(ADXL_IDX_FORWARD_TRANSLATE, argv4);
+ if (!results)
+ return -EINVAL;
+
+ r = results->package.elements + 1;
+ cnt = r->package.count;
+ if (cnt != adxl_count) {
+ ACPI_FREE(results);
+ return -EINVAL;
+ }
+ r = r->package.elements;
+
+ for (i = 0; i < cnt; i++)
+ component_values[i] = r[i].integer.value;
+
+ ACPI_FREE(results);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(adxl_decode);
+
+static int __init adxl_init(void)
+{
+ char *path = ACPI_ADXL_PATH;
+ union acpi_object *p;
+ acpi_status status;
+ int i;
+
+ status = acpi_get_handle(NULL, path, &handle);
+ if (ACPI_FAILURE(status)) {
+ pr_debug("No ACPI handle for path %s\n", path);
+ return -ENODEV;
+ }
+
+ if (!acpi_has_method(handle, "_DSM")) {
+ pr_info("No DSM method\n");
+ return -ENODEV;
+ }
+
+ if (!acpi_check_dsm(handle, &adxl_guid, ADXL_REVISION,
+ ADXL_IDX_GET_ADDR_PARAMS |
+ ADXL_IDX_FORWARD_TRANSLATE)) {
+ pr_info("DSM method does not support forward translate\n");
+ return -ENODEV;
+ }
+
+ params = adxl_dsm(ADXL_IDX_GET_ADDR_PARAMS, NULL);
+ if (!params) {
+ pr_info("Failed to get component names\n");
+ return -ENODEV;
+ }
+
+ p = params->package.elements + 1;
+ adxl_count = p->package.count;
+ if (adxl_count > ADXL_MAX_COMPONENTS) {
+ pr_info("Insane number of address component names %d\n", adxl_count);
+ ACPI_FREE(params);
+ return -ENODEV;
+ }
+ p = p->package.elements;
+
+ /*
+ * Allocate one extra for NULL termination.
+ */
+ adxl_component_names = kcalloc(adxl_count + 1, sizeof(char *), GFP_KERNEL);
+ if (!adxl_component_names) {
+ ACPI_FREE(params);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < adxl_count; i++)
+ adxl_component_names[i] = p[i].string.pointer;
+
+ return 0;
+}
+subsys_initcall(adxl_init);
diff --git a/drivers/acpi/acpi_ipmi.c b/drivers/acpi/acpi_ipmi.c
index 1b64419e2fec..712fd31674a6 100644
--- a/drivers/acpi/acpi_ipmi.c
+++ b/drivers/acpi/acpi_ipmi.c
@@ -46,7 +46,7 @@ struct acpi_ipmi_device {
spinlock_t tx_msg_lock;
acpi_handle handle;
struct device *dev;
- ipmi_user_t user_interface;
+ struct ipmi_user *user_interface;
int ipmi_ifnum; /* IPMI interface number */
long curr_msgid;
bool dead;
@@ -125,7 +125,7 @@ ipmi_dev_alloc(int iface, struct device *dev, acpi_handle handle)
{
struct acpi_ipmi_device *ipmi_device;
int err;
- ipmi_user_t user;
+ struct ipmi_user *user;
ipmi_device = kzalloc(sizeof(*ipmi_device), GFP_KERNEL);
if (!ipmi_device)
diff --git a/drivers/acpi/acpi_lpit.c b/drivers/acpi/acpi_lpit.c
index cf4fc0161164..e43cb71b6972 100644
--- a/drivers/acpi/acpi_lpit.c
+++ b/drivers/acpi/acpi_lpit.c
@@ -117,11 +117,17 @@ static void lpit_update_residency(struct lpit_residency_info *info,
if (!info->iomem_addr)
return;
+ if (!(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0))
+ return;
+
/* Silently fail, if cpuidle attribute group is not present */
sysfs_add_file_to_group(&cpu_subsys.dev_root->kobj,
&dev_attr_low_power_idle_system_residency_us.attr,
"cpuidle");
} else if (info->gaddr.space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) {
+ if (!(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0))
+ return;
+
/* Silently fail, if cpuidle attribute group is not present */
sysfs_add_file_to_group(&cpu_subsys.dev_root->kobj,
&dev_attr_low_power_idle_cpu_residency_us.attr,
diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c
index bf64cfa30feb..b9bda06d344d 100644
--- a/drivers/acpi/acpi_lpss.c
+++ b/drivers/acpi/acpi_lpss.c
@@ -16,6 +16,7 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/mutex.h>
+#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/platform_data/clk-lpss.h>
#include <linux/platform_data/x86/pmc_atom.h>
@@ -83,6 +84,7 @@ struct lpss_device_desc {
size_t prv_size_override;
struct property_entry *properties;
void (*setup)(struct lpss_private_data *pdata);
+ bool resume_from_noirq;
};
static const struct lpss_device_desc lpss_dma_desc = {
@@ -99,6 +101,9 @@ struct lpss_private_data {
u32 prv_reg_ctx[LPSS_PRV_REG_COUNT];
};
+/* Devices which need to be in D3 before lpss_iosf_enter_d3_state() proceeds */
+static u32 pmc_atom_d3_mask = 0xfe000ffe;
+
/* LPSS run time quirks */
static unsigned int lpss_quirks;
@@ -175,6 +180,21 @@ static void byt_pwm_setup(struct lpss_private_data *pdata)
static void byt_i2c_setup(struct lpss_private_data *pdata)
{
+ const char *uid_str = acpi_device_uid(pdata->adev);
+ acpi_handle handle = pdata->adev->handle;
+ unsigned long long shared_host = 0;
+ acpi_status status;
+ 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));
+
lpss_deassert_reset(pdata);
if (readl(pdata->mmio_base + pdata->dev_desc->prv_offset))
@@ -274,12 +294,14 @@ static const struct lpss_device_desc byt_i2c_dev_desc = {
.flags = LPSS_CLK | LPSS_SAVE_CTX,
.prv_offset = 0x800,
.setup = byt_i2c_setup,
+ .resume_from_noirq = true,
};
static const struct lpss_device_desc bsw_i2c_dev_desc = {
.flags = LPSS_CLK | LPSS_SAVE_CTX | LPSS_NO_D3_DELAY,
.prv_offset = 0x800,
.setup = byt_i2c_setup,
+ .resume_from_noirq = true,
};
static const struct lpss_device_desc bsw_spi_dev_desc = {
@@ -292,7 +314,7 @@ static const struct lpss_device_desc bsw_spi_dev_desc = {
#define ICPU(model) { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, }
static const struct x86_cpu_id lpss_cpu_ids[] = {
- ICPU(INTEL_FAM6_ATOM_SILVERMONT1), /* Valleyview, Bay Trail */
+ ICPU(INTEL_FAM6_ATOM_SILVERMONT), /* Valleyview, Bay Trail */
ICPU(INTEL_FAM6_ATOM_AIRMONT), /* Braswell, Cherry Trail */
{}
};
@@ -327,9 +349,11 @@ static const struct acpi_device_id acpi_lpss_device_ids[] = {
{ "INT33FC", },
/* Braswell LPSS devices */
+ { "80862286", LPSS_ADDR(lpss_dma_desc) },
{ "80862288", LPSS_ADDR(bsw_pwm_dev_desc) },
{ "8086228A", LPSS_ADDR(bsw_uart_dev_desc) },
{ "8086228E", LPSS_ADDR(bsw_spi_dev_desc) },
+ { "808622C0", LPSS_ADDR(lpss_dma_desc) },
{ "808622C1", LPSS_ADDR(bsw_i2c_dev_desc) },
/* Broadwell LPSS devices */
@@ -451,26 +475,35 @@ struct lpss_device_links {
*/
static const struct lpss_device_links lpss_device_links[] = {
{"808622C1", "7", "80860F14", "3", DL_FLAG_PM_RUNTIME},
+ {"808622C1", "7", "LNXVIDEO", NULL, DL_FLAG_PM_RUNTIME},
+ {"80860F41", "5", "LNXVIDEO", NULL, DL_FLAG_PM_RUNTIME},
};
-static bool hid_uid_match(const char *hid1, const char *uid1,
+static bool hid_uid_match(struct acpi_device *adev,
const char *hid2, const char *uid2)
{
- return !strcmp(hid1, hid2) && uid1 && uid2 && !strcmp(uid1, uid2);
+ const char *hid1 = acpi_device_hid(adev);
+ const char *uid1 = acpi_device_uid(adev);
+
+ if (strcmp(hid1, hid2))
+ return false;
+
+ if (!uid2)
+ return true;
+
+ return uid1 && !strcmp(uid1, uid2);
}
static bool acpi_lpss_is_supplier(struct acpi_device *adev,
const struct lpss_device_links *link)
{
- return hid_uid_match(acpi_device_hid(adev), acpi_device_uid(adev),
- link->supplier_hid, link->supplier_uid);
+ return hid_uid_match(adev, link->supplier_hid, link->supplier_uid);
}
static bool acpi_lpss_is_consumer(struct acpi_device *adev,
const struct lpss_device_links *link)
{
- return hid_uid_match(acpi_device_hid(adev), acpi_device_uid(adev),
- link->consumer_hid, link->consumer_uid);
+ return hid_uid_match(adev, link->consumer_hid, link->consumer_uid);
}
struct hid_uid {
@@ -486,18 +519,23 @@ static int match_hid_uid(struct device *dev, void *data)
if (!adev)
return 0;
- return hid_uid_match(acpi_device_hid(adev), acpi_device_uid(adev),
- id->hid, id->uid);
+ return hid_uid_match(adev, id->hid, id->uid);
}
static struct device *acpi_lpss_find_device(const char *hid, const char *uid)
{
+ struct device *dev;
+
struct hid_uid data = {
.hid = hid,
.uid = uid,
};
- return bus_find_device(&platform_bus_type, NULL, &data, match_hid_uid);
+ dev = bus_find_device(&platform_bus_type, NULL, &data, match_hid_uid);
+ if (dev)
+ return dev;
+
+ return bus_find_device(&pci_bus_type, NULL, &data, match_hid_uid);
}
static bool acpi_lpss_dep(struct acpi_device *adev, acpi_handle handle)
@@ -892,7 +930,7 @@ static void lpss_iosf_enter_d3_state(void)
* Here we read the values related to LPSS power island, i.e. LPSS
* devices, excluding both LPSS DMA controllers, along with SCC domain.
*/
- u32 func_dis, d3_sts_0, pmc_status, pmc_mask = 0xfe000ffe;
+ u32 func_dis, d3_sts_0, pmc_status;
int ret;
ret = pmc_atom_read(PMC_FUNC_DIS, &func_dis);
@@ -910,7 +948,7 @@ static void lpss_iosf_enter_d3_state(void)
* Shutdown both LPSS DMA controllers if and only if all other devices
* are already in D3hot.
*/
- pmc_status = (~(d3_sts_0 | func_dis)) & pmc_mask;
+ pmc_status = (~(d3_sts_0 | func_dis)) & pmc_atom_d3_mask;
if (pmc_status)
goto exit;
@@ -1004,7 +1042,7 @@ static int acpi_lpss_resume(struct device *dev)
}
#ifdef CONFIG_PM_SLEEP
-static int acpi_lpss_suspend_late(struct device *dev)
+static int acpi_lpss_do_suspend_late(struct device *dev)
{
int ret;
@@ -1015,12 +1053,62 @@ static int acpi_lpss_suspend_late(struct device *dev)
return ret ? ret : acpi_lpss_suspend(dev, device_may_wakeup(dev));
}
-static int acpi_lpss_resume_early(struct device *dev)
+static int acpi_lpss_suspend_late(struct device *dev)
+{
+ struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+
+ if (pdata->dev_desc->resume_from_noirq)
+ return 0;
+
+ return acpi_lpss_do_suspend_late(dev);
+}
+
+static int acpi_lpss_suspend_noirq(struct device *dev)
+{
+ struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+ int ret;
+
+ if (pdata->dev_desc->resume_from_noirq) {
+ ret = acpi_lpss_do_suspend_late(dev);
+ if (ret)
+ return ret;
+ }
+
+ return acpi_subsys_suspend_noirq(dev);
+}
+
+static int acpi_lpss_do_resume_early(struct device *dev)
{
int ret = acpi_lpss_resume(dev);
return ret ? ret : pm_generic_resume_early(dev);
}
+
+static int acpi_lpss_resume_early(struct device *dev)
+{
+ struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+
+ if (pdata->dev_desc->resume_from_noirq)
+ return 0;
+
+ return acpi_lpss_do_resume_early(dev);
+}
+
+static int acpi_lpss_resume_noirq(struct device *dev)
+{
+ struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+ int ret;
+
+ ret = acpi_subsys_resume_noirq(dev);
+ if (ret)
+ return ret;
+
+ if (!dev_pm_may_skip_resume(dev) && pdata->dev_desc->resume_from_noirq)
+ ret = acpi_lpss_do_resume_early(dev);
+
+ return ret;
+}
+
#endif /* CONFIG_PM_SLEEP */
static int acpi_lpss_runtime_suspend(struct device *dev)
@@ -1050,8 +1138,8 @@ static struct dev_pm_domain acpi_lpss_pm_domain = {
.complete = acpi_subsys_complete,
.suspend = acpi_subsys_suspend,
.suspend_late = acpi_lpss_suspend_late,
- .suspend_noirq = acpi_subsys_suspend_noirq,
- .resume_noirq = acpi_subsys_resume_noirq,
+ .suspend_noirq = acpi_lpss_suspend_noirq,
+ .resume_noirq = acpi_lpss_resume_noirq,
.resume_early = acpi_lpss_resume_early,
.freeze = acpi_subsys_freeze,
.freeze_late = acpi_subsys_freeze_late,
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index 6b0d3ef7309c..8fe0960ea572 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -228,7 +228,7 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
if (node < 0)
node = memory_add_physaddr_to_nid(info->start_addr);
- result = add_memory(node, info->start_addr, info->length);
+ result = __add_memory(node, info->start_addr, info->length);
/*
* If the memory block has been used by the kernel, add_memory()
@@ -282,7 +282,7 @@ static void acpi_memory_remove_memory(struct acpi_memory_device *mem_device)
nid = memory_add_physaddr_to_nid(info->start_addr);
acpi_unbind_memory_blocks(info);
- remove_memory(nid, info->start_addr, info->length);
+ __remove_memory(nid, info->start_addr, info->length);
list_del(&info->list);
kfree(info);
}
diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c
index 552c1f725b6c..a47676a55b84 100644
--- a/drivers/acpi/acpi_pad.c
+++ b/drivers/acpi/acpi_pad.c
@@ -70,6 +70,7 @@ static void power_saving_mwait_init(void)
#if defined(CONFIG_X86)
switch (boot_cpu_data.x86_vendor) {
+ case X86_VENDOR_HYGON:
case X86_VENDOR_AMD:
case X86_VENDOR_INTEL:
/*
diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c
index 449d86d39965..fc447410ae4d 100644
--- a/drivers/acpi/acpi_processor.c
+++ b/drivers/acpi/acpi_processor.c
@@ -643,7 +643,7 @@ static acpi_status __init acpi_processor_ids_walk(acpi_handle handle,
status = acpi_get_type(handle, &acpi_type);
if (ACPI_FAILURE(status))
- return false;
+ return status;
switch (acpi_type) {
case ACPI_TYPE_PROCESSOR:
@@ -663,11 +663,12 @@ static acpi_status __init acpi_processor_ids_walk(acpi_handle handle,
}
processor_validated_ids_update(uid);
- return true;
+ return AE_OK;
err:
+ /* Exit on error, but don't abort the namespace walk */
acpi_handle_info(handle, "Invalid processor object\n");
- return false;
+ return AE_OK;
}
diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c
index e99c4ed7e677..33a4bcdaa4d7 100644
--- a/drivers/acpi/acpi_tad.c
+++ b/drivers/acpi/acpi_tad.c
@@ -52,6 +52,201 @@ struct acpi_tad_driver_data {
u32 capabilities;
};
+struct acpi_tad_rt {
+ u16 year; /* 1900 - 9999 */
+ u8 month; /* 1 - 12 */
+ u8 day; /* 1 - 31 */
+ u8 hour; /* 0 - 23 */
+ u8 minute; /* 0 - 59 */
+ u8 second; /* 0 - 59 */
+ u8 valid; /* 0 (failed) or 1 (success) for reads, 0 for writes */
+ u16 msec; /* 1 - 1000 */
+ s16 tz; /* -1440 to 1440 or 2047 (unspecified) */
+ u8 daylight;
+ u8 padding[3]; /* must be 0 */
+} __packed;
+
+static int acpi_tad_set_real_time(struct device *dev, struct acpi_tad_rt *rt)
+{
+ acpi_handle handle = ACPI_HANDLE(dev);
+ union acpi_object args[] = {
+ { .type = ACPI_TYPE_BUFFER, },
+ };
+ struct acpi_object_list arg_list = {
+ .pointer = args,
+ .count = ARRAY_SIZE(args),
+ };
+ unsigned long long retval;
+ acpi_status status;
+
+ if (rt->year < 1900 || rt->year > 9999 ||
+ rt->month < 1 || rt->month > 12 ||
+ rt->hour > 23 || rt->minute > 59 || rt->second > 59 ||
+ rt->tz < -1440 || (rt->tz > 1440 && rt->tz != 2047) ||
+ rt->daylight > 3)
+ return -ERANGE;
+
+ args[0].buffer.pointer = (u8 *)rt;
+ args[0].buffer.length = sizeof(*rt);
+
+ pm_runtime_get_sync(dev);
+
+ status = acpi_evaluate_integer(handle, "_SRT", &arg_list, &retval);
+
+ pm_runtime_put_sync(dev);
+
+ if (ACPI_FAILURE(status) || retval)
+ return -EIO;
+
+ return 0;
+}
+
+static int acpi_tad_get_real_time(struct device *dev, struct acpi_tad_rt *rt)
+{
+ acpi_handle handle = ACPI_HANDLE(dev);
+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER };
+ union acpi_object *out_obj;
+ struct acpi_tad_rt *data;
+ acpi_status status;
+ int ret = -EIO;
+
+ pm_runtime_get_sync(dev);
+
+ status = acpi_evaluate_object(handle, "_GRT", NULL, &output);
+
+ pm_runtime_put_sync(dev);
+
+ if (ACPI_FAILURE(status))
+ goto out_free;
+
+ out_obj = output.pointer;
+ if (out_obj->type != ACPI_TYPE_BUFFER)
+ goto out_free;
+
+ if (out_obj->buffer.length != sizeof(*rt))
+ goto out_free;
+
+ data = (struct acpi_tad_rt *)(out_obj->buffer.pointer);
+ if (!data->valid)
+ goto out_free;
+
+ memcpy(rt, data, sizeof(*rt));
+ ret = 0;
+
+out_free:
+ ACPI_FREE(output.pointer);
+ return ret;
+}
+
+static char *acpi_tad_rt_next_field(char *s, int *val)
+{
+ char *p;
+
+ p = strchr(s, ':');
+ if (!p)
+ return NULL;
+
+ *p = '\0';
+ if (kstrtoint(s, 10, val))
+ return NULL;
+
+ return p + 1;
+}
+
+static ssize_t time_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct acpi_tad_rt rt;
+ char *str, *s;
+ int val, ret = -ENODATA;
+
+ str = kmemdup_nul(buf, count, GFP_KERNEL);
+ if (!str)
+ return -ENOMEM;
+
+ s = acpi_tad_rt_next_field(str, &val);
+ if (!s)
+ goto out_free;
+
+ rt.year = val;
+
+ s = acpi_tad_rt_next_field(s, &val);
+ if (!s)
+ goto out_free;
+
+ rt.month = val;
+
+ s = acpi_tad_rt_next_field(s, &val);
+ if (!s)
+ goto out_free;
+
+ rt.day = val;
+
+ s = acpi_tad_rt_next_field(s, &val);
+ if (!s)
+ goto out_free;
+
+ rt.hour = val;
+
+ s = acpi_tad_rt_next_field(s, &val);
+ if (!s)
+ goto out_free;
+
+ rt.minute = val;
+
+ s = acpi_tad_rt_next_field(s, &val);
+ if (!s)
+ goto out_free;
+
+ rt.second = val;
+
+ s = acpi_tad_rt_next_field(s, &val);
+ if (!s)
+ goto out_free;
+
+ rt.tz = val;
+
+ if (kstrtoint(s, 10, &val))
+ goto out_free;
+
+ rt.daylight = val;
+
+ rt.valid = 0;
+ rt.msec = 0;
+ memset(rt.padding, 0, 3);
+
+ ret = acpi_tad_set_real_time(dev, &rt);
+
+out_free:
+ kfree(str);
+ return ret ? ret : count;
+}
+
+static ssize_t time_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct acpi_tad_rt rt;
+ int ret;
+
+ ret = acpi_tad_get_real_time(dev, &rt);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%u:%u:%u:%u:%u:%u:%d:%u\n",
+ rt.year, rt.month, rt.day, rt.hour, rt.minute, rt.second,
+ rt.tz, rt.daylight);
+}
+
+static DEVICE_ATTR(time, S_IRUSR | S_IWUSR, time_show, time_store);
+
+static struct attribute *acpi_tad_time_attrs[] = {
+ &dev_attr_time.attr,
+ NULL,
+};
+static const struct attribute_group acpi_tad_time_attr_group = {
+ .attrs = acpi_tad_time_attrs,
+};
+
static int acpi_tad_wake_set(struct device *dev, char *method, u32 timer_id,
u32 value)
{
@@ -448,6 +643,12 @@ static int acpi_tad_probe(struct platform_device *pdev)
goto fail;
}
+ if (caps & ACPI_TAD_RT) {
+ ret = sysfs_create_group(&dev->kobj, &acpi_tad_time_attr_group);
+ if (ret)
+ goto fail;
+ }
+
return 0;
fail:
diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile
index 71f6f2624deb..b14621da5413 100644
--- a/drivers/acpi/acpica/Makefile
+++ b/drivers/acpi/acpica/Makefile
@@ -65,6 +65,7 @@ acpi-y += \
exresnte.o \
exresolv.o \
exresop.o \
+ exserial.o \
exstore.o \
exstoren.o \
exstorob.o \
diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h
index 704bebbd35b0..b412aa909907 100644
--- a/drivers/acpi/acpica/acevents.h
+++ b/drivers/acpi/acpica/acevents.h
@@ -229,6 +229,8 @@ acpi_ev_default_region_setup(acpi_handle handle,
acpi_status acpi_ev_initialize_region(union acpi_operand_object *region_obj);
+u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node);
+
/*
* evsci - SCI (System Control Interrupt) handling/dispatch
*/
diff --git a/drivers/acpi/acpica/acinterp.h b/drivers/acpi/acpica/acinterp.h
index 9613b0115dad..c5b2be0b6613 100644
--- a/drivers/acpi/acpica/acinterp.h
+++ b/drivers/acpi/acpica/acinterp.h
@@ -124,6 +124,9 @@ acpi_ex_trace_point(acpi_trace_event_type type,
* exfield - ACPI AML (p-code) execution - field manipulation
*/
acpi_status
+acpi_ex_get_protocol_buffer_length(u32 protocol_id, u32 *return_length);
+
+acpi_status
acpi_ex_common_buffer_setup(union acpi_operand_object *obj_desc,
u32 buffer_length, u32 * datum_count);
@@ -268,6 +271,26 @@ acpi_ex_prep_common_field_object(union acpi_operand_object *obj_desc,
acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info);
/*
+ * exserial - field_unit support for serial address spaces
+ */
+acpi_status
+acpi_ex_read_serial_bus(union acpi_operand_object *obj_desc,
+ union acpi_operand_object **return_buffer);
+
+acpi_status
+acpi_ex_write_serial_bus(union acpi_operand_object *source_desc,
+ union acpi_operand_object *obj_desc,
+ union acpi_operand_object **return_buffer);
+
+acpi_status
+acpi_ex_read_gpio(union acpi_operand_object *obj_desc, void *buffer);
+
+acpi_status
+acpi_ex_write_gpio(union acpi_operand_object *source_desc,
+ union acpi_operand_object *obj_desc,
+ union acpi_operand_object **return_buffer);
+
+/*
* exsystem - Interface to OS services
*/
acpi_status
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index 0f28a38a43ea..99b0da899109 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -395,9 +395,9 @@ struct acpi_simple_repair_info {
/* Info for running the _REG methods */
struct acpi_reg_walk_info {
- acpi_adr_space_type space_id;
u32 function;
u32 reg_run_count;
+ acpi_adr_space_type space_id;
};
/*****************************************************************************
diff --git a/drivers/acpi/acpica/amlcode.h b/drivers/acpi/acpica/amlcode.h
index 250dba02bab6..6c05355447c1 100644
--- a/drivers/acpi/acpica/amlcode.h
+++ b/drivers/acpi/acpica/amlcode.h
@@ -432,15 +432,15 @@ typedef enum {
*/
typedef enum {
AML_FIELD_ATTRIB_QUICK = 0x02,
- AML_FIELD_ATTRIB_SEND_RCV = 0x04,
+ AML_FIELD_ATTRIB_SEND_RECEIVE = 0x04,
AML_FIELD_ATTRIB_BYTE = 0x06,
AML_FIELD_ATTRIB_WORD = 0x08,
AML_FIELD_ATTRIB_BLOCK = 0x0A,
- AML_FIELD_ATTRIB_MULTIBYTE = 0x0B,
- AML_FIELD_ATTRIB_WORD_CALL = 0x0C,
- AML_FIELD_ATTRIB_BLOCK_CALL = 0x0D,
+ AML_FIELD_ATTRIB_BYTES = 0x0B,
+ AML_FIELD_ATTRIB_PROCESS_CALL = 0x0C,
+ AML_FIELD_ATTRIB_BLOCK_PROCESS_CALL = 0x0D,
AML_FIELD_ATTRIB_RAW_BYTES = 0x0E,
- AML_FIELD_ATTRIB_RAW_PROCESS = 0x0F
+ AML_FIELD_ATTRIB_RAW_PROCESS_BYTES = 0x0F
} AML_ACCESS_ATTRIBUTE;
/* Bit fields in the AML method_flags byte */
diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c
index e9fb0bf3c8d2..78f9de260d5f 100644
--- a/drivers/acpi/acpica/dsopcode.c
+++ b/drivers/acpi/acpica/dsopcode.c
@@ -417,6 +417,10 @@ acpi_ds_eval_region_operands(struct acpi_walk_state *walk_state,
ACPI_FORMAT_UINT64(obj_desc->region.address),
obj_desc->region.length));
+ status = acpi_ut_add_address_range(obj_desc->region.space_id,
+ obj_desc->region.address,
+ obj_desc->region.length, node);
+
/* Now the address and length are valid for this opregion */
obj_desc->region.flags |= AOPOBJ_DATA_VALID;
diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c
index 70c2bd169f66..49decca4e08f 100644
--- a/drivers/acpi/acpica/evregion.c
+++ b/drivers/acpi/acpica/evregion.c
@@ -653,6 +653,19 @@ acpi_ev_execute_reg_methods(struct acpi_namespace_node *node,
ACPI_FUNCTION_TRACE(ev_execute_reg_methods);
+ /*
+ * These address spaces do not need a call to _REG, since the ACPI
+ * specification defines them as: "must always be accessible". Since
+ * they never change state (never become unavailable), no need to ever
+ * call _REG on them. Also, a data_table is not a "real" address space,
+ * so do not call _REG. September 2018.
+ */
+ if ((space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) ||
+ (space_id == ACPI_ADR_SPACE_SYSTEM_IO) ||
+ (space_id == ACPI_ADR_SPACE_DATA_TABLE)) {
+ return_VOID;
+ }
+
info.space_id = space_id;
info.function = function;
info.reg_run_count = 0;
@@ -714,8 +727,8 @@ acpi_ev_reg_run(acpi_handle obj_handle,
}
/*
- * We only care about regions.and objects that are allowed to have address
- * space handlers
+ * We only care about regions and objects that are allowed to have
+ * address space handlers
*/
if ((node->type != ACPI_TYPE_REGION) && (node != acpi_gbl_root_node)) {
return (AE_OK);
diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c
index 39284deedd88..17df5dacd43c 100644
--- a/drivers/acpi/acpica/evrgnini.c
+++ b/drivers/acpi/acpica/evrgnini.c
@@ -16,9 +16,6 @@
#define _COMPONENT ACPI_EVENTS
ACPI_MODULE_NAME("evrgnini")
-/* Local prototypes */
-static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node);
-
/*******************************************************************************
*
* FUNCTION: acpi_ev_system_memory_region_setup
@@ -33,7 +30,6 @@ static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node);
* DESCRIPTION: Setup a system_memory operation region
*
******************************************************************************/
-
acpi_status
acpi_ev_system_memory_region_setup(acpi_handle handle,
u32 function,
@@ -313,7 +309,7 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
*
******************************************************************************/
-static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node)
+u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node)
{
acpi_status status;
struct acpi_pnp_device_id *hid;
diff --git a/drivers/acpi/acpica/evxfregn.c b/drivers/acpi/acpica/evxfregn.c
index 091415b14fbf..3b3a25d9f0e6 100644
--- a/drivers/acpi/acpica/evxfregn.c
+++ b/drivers/acpi/acpica/evxfregn.c
@@ -193,7 +193,6 @@ acpi_remove_address_space_handler(acpi_handle device,
*/
region_obj =
handler_obj->address_space.region_list;
-
}
/* Remove this Handler object from the list */
diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c
index b272c329d45d..e5798f15793a 100644
--- a/drivers/acpi/acpica/exfield.c
+++ b/drivers/acpi/acpica/exfield.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
/******************************************************************************
*
- * Module Name: exfield - ACPI AML (p-code) execution - field manipulation
+ * Module Name: exfield - AML execution - field_unit read/write
*
* Copyright (C) 2000 - 2018, Intel Corp.
*
@@ -16,64 +16,62 @@
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exfield")
-/* Local prototypes */
-static u32
-acpi_ex_get_serial_access_length(u32 accessor_type, u32 access_length);
+/*
+ * This table maps the various Attrib protocols to the byte transfer
+ * length. Used for the generic serial bus.
+ */
+#define ACPI_INVALID_PROTOCOL_ID 0x80
+#define ACPI_MAX_PROTOCOL_ID 0x0F
+const u8 acpi_protocol_lengths[] = {
+ ACPI_INVALID_PROTOCOL_ID, /* 0 - reserved */
+ ACPI_INVALID_PROTOCOL_ID, /* 1 - reserved */
+ 0x00, /* 2 - ATTRIB_QUICK */
+ ACPI_INVALID_PROTOCOL_ID, /* 3 - reserved */
+ 0x01, /* 4 - ATTRIB_SEND_RECEIVE */
+ ACPI_INVALID_PROTOCOL_ID, /* 5 - reserved */
+ 0x01, /* 6 - ATTRIB_BYTE */
+ ACPI_INVALID_PROTOCOL_ID, /* 7 - reserved */
+ 0x02, /* 8 - ATTRIB_WORD */
+ ACPI_INVALID_PROTOCOL_ID, /* 9 - reserved */
+ 0xFF, /* A - ATTRIB_BLOCK */
+ 0xFF, /* B - ATTRIB_BYTES */
+ 0x02, /* C - ATTRIB_PROCESS_CALL */
+ 0xFF, /* D - ATTRIB_BLOCK_PROCESS_CALL */
+ 0xFF, /* E - ATTRIB_RAW_BYTES */
+ 0xFF /* F - ATTRIB_RAW_PROCESS_BYTES */
+};
/*******************************************************************************
*
- * FUNCTION: acpi_ex_get_serial_access_length
+ * FUNCTION: acpi_ex_get_protocol_buffer_length
*
- * PARAMETERS: accessor_type - The type of the protocol indicated by region
+ * PARAMETERS: protocol_id - The type of the protocol indicated by region
* field access attributes
- * access_length - The access length of the region field
+ * return_length - Where the protocol byte transfer length is
+ * returned
*
- * RETURN: Decoded access length
+ * RETURN: Status and decoded byte transfer length
*
* DESCRIPTION: This routine returns the length of the generic_serial_bus
* protocol bytes
*
******************************************************************************/
-static u32
-acpi_ex_get_serial_access_length(u32 accessor_type, u32 access_length)
+acpi_status
+acpi_ex_get_protocol_buffer_length(u32 protocol_id, u32 *return_length)
{
- u32 length;
-
- switch (accessor_type) {
- case AML_FIELD_ATTRIB_QUICK:
-
- length = 0;
- break;
-
- case AML_FIELD_ATTRIB_SEND_RCV:
- case AML_FIELD_ATTRIB_BYTE:
-
- length = 1;
- break;
-
- case AML_FIELD_ATTRIB_WORD:
- case AML_FIELD_ATTRIB_WORD_CALL:
-
- length = 2;
- break;
- case AML_FIELD_ATTRIB_MULTIBYTE:
- case AML_FIELD_ATTRIB_RAW_BYTES:
- case AML_FIELD_ATTRIB_RAW_PROCESS:
+ if ((protocol_id > ACPI_MAX_PROTOCOL_ID) ||
+ (acpi_protocol_lengths[protocol_id] == ACPI_INVALID_PROTOCOL_ID)) {
+ ACPI_ERROR((AE_INFO,
+ "Invalid Field/AccessAs protocol ID: 0x%4.4X",
+ protocol_id));
- length = access_length;
- break;
-
- case AML_FIELD_ATTRIB_BLOCK:
- case AML_FIELD_ATTRIB_BLOCK_CALL:
- default:
-
- length = ACPI_GSBUS_BUFFER_SIZE - 2;
- break;
+ return (AE_AML_PROTOCOL);
}
- return (length);
+ *return_length = acpi_protocol_lengths[protocol_id];
+ return (AE_OK);
}
/*******************************************************************************
@@ -98,10 +96,8 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
{
acpi_status status;
union acpi_operand_object *buffer_desc;
- acpi_size length;
void *buffer;
- u32 function;
- u16 accessor_type;
+ u32 buffer_length;
ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field, obj_desc);
@@ -132,60 +128,11 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
ACPI_ADR_SPACE_GSBUS
|| obj_desc->field.region_obj->region.space_id ==
ACPI_ADR_SPACE_IPMI)) {
- /*
- * This is an SMBus, GSBus or IPMI read. We must create a buffer to
- * hold the data and then directly access the region handler.
- *
- * Note: SMBus and GSBus protocol value is passed in upper 16-bits
- * of Function
- */
- if (obj_desc->field.region_obj->region.space_id ==
- ACPI_ADR_SPACE_SMBUS) {
- length = ACPI_SMBUS_BUFFER_SIZE;
- function =
- ACPI_READ | (obj_desc->field.attribute << 16);
- } else if (obj_desc->field.region_obj->region.space_id ==
- ACPI_ADR_SPACE_GSBUS) {
- accessor_type = obj_desc->field.attribute;
- length =
- acpi_ex_get_serial_access_length(accessor_type,
- obj_desc->field.
- access_length);
-
- /*
- * Add additional 2 bytes for the generic_serial_bus data buffer:
- *
- * Status; (Byte 0 of the data buffer)
- * Length; (Byte 1 of the data buffer)
- * Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
- */
- length += 2;
- function = ACPI_READ | (accessor_type << 16);
- } else { /* IPMI */
-
- length = ACPI_IPMI_BUFFER_SIZE;
- function = ACPI_READ;
- }
-
- buffer_desc = acpi_ut_create_buffer_object(length);
- if (!buffer_desc) {
- return_ACPI_STATUS(AE_NO_MEMORY);
- }
-
- /* Lock entire transaction if requested */
-
- acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
-
- /* Call the region handler for the read */
- status = acpi_ex_access_region(obj_desc, 0,
- ACPI_CAST_PTR(u64,
- buffer_desc->
- buffer.pointer),
- function);
+ /* SMBus, GSBus, IPMI serial */
- acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
- goto exit;
+ status = acpi_ex_read_serial_bus(obj_desc, ret_buffer_desc);
+ return_ACPI_STATUS(status);
}
/*
@@ -198,14 +145,14 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
*
* Note: Field.length is in bits.
*/
- length =
+ buffer_length =
(acpi_size)ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->field.bit_length);
- if (length > acpi_gbl_integer_byte_width) {
+ if (buffer_length > acpi_gbl_integer_byte_width) {
/* Field is too large for an Integer, create a Buffer instead */
- buffer_desc = acpi_ut_create_buffer_object(length);
+ buffer_desc = acpi_ut_create_buffer_object(buffer_length);
if (!buffer_desc) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
@@ -218,47 +165,24 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
return_ACPI_STATUS(AE_NO_MEMORY);
}
- length = acpi_gbl_integer_byte_width;
+ buffer_length = acpi_gbl_integer_byte_width;
buffer = &buffer_desc->integer.value;
}
if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
(obj_desc->field.region_obj->region.space_id ==
ACPI_ADR_SPACE_GPIO)) {
- /*
- * For GPIO (general_purpose_io), the Address will be the bit offset
- * from the previous Connection() operator, making it effectively a
- * pin number index. The bit_length is the length of the field, which
- * is thus the number of pins.
- */
- ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
- "GPIO FieldRead [FROM]: Pin %u Bits %u\n",
- obj_desc->field.pin_number_index,
- obj_desc->field.bit_length));
-
- /* Lock entire transaction if requested */
- acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
+ /* General Purpose I/O */
- /* Perform the write */
-
- status =
- acpi_ex_access_region(obj_desc, 0, (u64 *)buffer,
- ACPI_READ);
-
- acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
- if (ACPI_FAILURE(status)) {
- acpi_ut_remove_reference(buffer_desc);
- } else {
- *ret_buffer_desc = buffer_desc;
- }
- return_ACPI_STATUS(status);
+ status = acpi_ex_read_gpio(obj_desc, buffer);
+ goto exit;
}
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
"FieldRead [TO]: Obj %p, Type %X, Buf %p, ByteLen %X\n",
obj_desc, obj_desc->common.type, buffer,
- (u32) length));
+ buffer_length));
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
"FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n",
obj_desc->common_field.bit_length,
@@ -271,7 +195,7 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
/* Read from the field */
- status = acpi_ex_extract_from_field(obj_desc, buffer, (u32) length);
+ status = acpi_ex_extract_from_field(obj_desc, buffer, buffer_length);
acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
exit:
@@ -304,11 +228,8 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
union acpi_operand_object **result_desc)
{
acpi_status status;
- u32 length;
+ u32 buffer_length;
void *buffer;
- union acpi_operand_object *buffer_desc;
- u32 function;
- u16 accessor_type;
ACPI_FUNCTION_TRACE_PTR(ex_write_data_to_field, obj_desc);
@@ -331,130 +252,25 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
}
} else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
(obj_desc->field.region_obj->region.space_id ==
- ACPI_ADR_SPACE_SMBUS
- || obj_desc->field.region_obj->region.space_id ==
- ACPI_ADR_SPACE_GSBUS
- || obj_desc->field.region_obj->region.space_id ==
- ACPI_ADR_SPACE_IPMI)) {
- /*
- * This is an SMBus, GSBus or IPMI write. We will bypass the entire
- * field mechanism and handoff the buffer directly to the handler.
- * For these address spaces, the buffer is bi-directional; on a
- * write, return data is returned in the same buffer.
- *
- * Source must be a buffer of sufficient size:
- * ACPI_SMBUS_BUFFER_SIZE, ACPI_GSBUS_BUFFER_SIZE, or
- * ACPI_IPMI_BUFFER_SIZE.
- *
- * Note: SMBus and GSBus protocol type is passed in upper 16-bits
- * of Function
- */
- if (source_desc->common.type != ACPI_TYPE_BUFFER) {
- ACPI_ERROR((AE_INFO,
- "SMBus/IPMI/GenericSerialBus write requires "
- "Buffer, found type %s",
- acpi_ut_get_object_type_name(source_desc)));
-
- return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
- }
-
- if (obj_desc->field.region_obj->region.space_id ==
- ACPI_ADR_SPACE_SMBUS) {
- length = ACPI_SMBUS_BUFFER_SIZE;
- function =
- ACPI_WRITE | (obj_desc->field.attribute << 16);
- } else if (obj_desc->field.region_obj->region.space_id ==
- ACPI_ADR_SPACE_GSBUS) {
- accessor_type = obj_desc->field.attribute;
- length =
- acpi_ex_get_serial_access_length(accessor_type,
- obj_desc->field.
- access_length);
-
- /*
- * Add additional 2 bytes for the generic_serial_bus data buffer:
- *
- * Status; (Byte 0 of the data buffer)
- * Length; (Byte 1 of the data buffer)
- * Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
- */
- length += 2;
- function = ACPI_WRITE | (accessor_type << 16);
- } else { /* IPMI */
-
- length = ACPI_IPMI_BUFFER_SIZE;
- function = ACPI_WRITE;
- }
-
- if (source_desc->buffer.length < length) {
- ACPI_ERROR((AE_INFO,
- "SMBus/IPMI/GenericSerialBus write requires "
- "Buffer of length %u, found length %u",
- length, source_desc->buffer.length));
-
- return_ACPI_STATUS(AE_AML_BUFFER_LIMIT);
- }
-
- /* Create the bi-directional buffer */
-
- buffer_desc = acpi_ut_create_buffer_object(length);
- if (!buffer_desc) {
- return_ACPI_STATUS(AE_NO_MEMORY);
- }
-
- buffer = buffer_desc->buffer.pointer;
- memcpy(buffer, source_desc->buffer.pointer, length);
-
- /* Lock entire transaction if requested */
+ ACPI_ADR_SPACE_GPIO)) {
- acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
+ /* General Purpose I/O */
- /*
- * Perform the write (returns status and perhaps data in the
- * same buffer)
- */
- status =
- acpi_ex_access_region(obj_desc, 0, (u64 *)buffer, function);
- acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
-
- *result_desc = buffer_desc;
+ status = acpi_ex_write_gpio(source_desc, obj_desc, result_desc);
return_ACPI_STATUS(status);
} else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
(obj_desc->field.region_obj->region.space_id ==
- ACPI_ADR_SPACE_GPIO)) {
- /*
- * For GPIO (general_purpose_io), we will bypass the entire field
- * mechanism and handoff the bit address and bit width directly to
- * the handler. The Address will be the bit offset
- * from the previous Connection() operator, making it effectively a
- * pin number index. The bit_length is the length of the field, which
- * is thus the number of pins.
- */
- if (source_desc->common.type != ACPI_TYPE_INTEGER) {
- return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
- }
-
- ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
- "GPIO FieldWrite [FROM]: (%s:%X), Val %.8X [TO]: Pin %u Bits %u\n",
- acpi_ut_get_type_name(source_desc->common.
- type),
- source_desc->common.type,
- (u32)source_desc->integer.value,
- obj_desc->field.pin_number_index,
- obj_desc->field.bit_length));
-
- buffer = &source_desc->integer.value;
-
- /* Lock entire transaction if requested */
-
- acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
+ ACPI_ADR_SPACE_SMBUS
+ || obj_desc->field.region_obj->region.space_id ==
+ ACPI_ADR_SPACE_GSBUS
+ || obj_desc->field.region_obj->region.space_id ==
+ ACPI_ADR_SPACE_IPMI)) {
- /* Perform the write */
+ /* SMBus, GSBus, IPMI serial */
status =
- acpi_ex_access_region(obj_desc, 0, (u64 *)buffer,
- ACPI_WRITE);
- acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
+ acpi_ex_write_serial_bus(source_desc, obj_desc,
+ result_desc);
return_ACPI_STATUS(status);
}
@@ -464,23 +280,22 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
case ACPI_TYPE_INTEGER:
buffer = &source_desc->integer.value;
- length = sizeof(source_desc->integer.value);
+ buffer_length = sizeof(source_desc->integer.value);
break;
case ACPI_TYPE_BUFFER:
buffer = source_desc->buffer.pointer;
- length = source_desc->buffer.length;
+ buffer_length = source_desc->buffer.length;
break;
case ACPI_TYPE_STRING:
buffer = source_desc->string.pointer;
- length = source_desc->string.length;
+ buffer_length = source_desc->string.length;
break;
default:
-
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
}
@@ -488,7 +303,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
"FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n",
source_desc,
acpi_ut_get_type_name(source_desc->common.type),
- source_desc->common.type, buffer, length));
+ source_desc->common.type, buffer, buffer_length));
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
"FieldWrite [TO]: Obj %p (%s:%X), BitLen %X, BitOff %X, ByteOff %X\n",
@@ -505,8 +320,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
/* Write to the field */
- status = acpi_ex_insert_into_field(obj_desc, buffer, length);
+ status = acpi_ex_insert_into_field(obj_desc, buffer, buffer_length);
acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
-
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/acpica/exserial.c b/drivers/acpi/acpica/exserial.c
new file mode 100644
index 000000000000..0d42f30e5b25
--- /dev/null
+++ b/drivers/acpi/acpica/exserial.c
@@ -0,0 +1,360 @@
+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+/******************************************************************************
+ *
+ * Module Name: exserial - field_unit support for serial address spaces
+ *
+ * Copyright (C) 2000 - 2018, Intel Corp.
+ *
+ *****************************************************************************/
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acdispat.h"
+#include "acinterp.h"
+#include "amlcode.h"
+
+#define _COMPONENT ACPI_EXECUTER
+ACPI_MODULE_NAME("exserial")
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_read_gpio
+ *
+ * PARAMETERS: obj_desc - The named field to read
+ * buffer - Where the return data is returnd
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Read from a named field that references a Generic Serial Bus
+ * field
+ *
+ ******************************************************************************/
+acpi_status acpi_ex_read_gpio(union acpi_operand_object *obj_desc, void *buffer)
+{
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE_PTR(ex_read_gpio, obj_desc);
+
+ /*
+ * For GPIO (general_purpose_io), the Address will be the bit offset
+ * from the previous Connection() operator, making it effectively a
+ * pin number index. The bit_length is the length of the field, which
+ * is thus the number of pins.
+ */
+ ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
+ "GPIO FieldRead [FROM]: Pin %u Bits %u\n",
+ obj_desc->field.pin_number_index,
+ obj_desc->field.bit_length));
+
+ /* Lock entire transaction if requested */
+
+ acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
+
+ /* Perform the read */
+
+ status = acpi_ex_access_region(obj_desc, 0, (u64 *)buffer, ACPI_READ);
+
+ acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_write_gpio
+ *
+ * PARAMETERS: source_desc - Contains data to write. Expect to be
+ * an Integer object.
+ * obj_desc - The named field
+ * result_desc - Where the return value is returned, if any
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Write to a named field that references a General Purpose I/O
+ * field.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_write_gpio(union acpi_operand_object *source_desc,
+ union acpi_operand_object *obj_desc,
+ union acpi_operand_object **return_buffer)
+{
+ acpi_status status;
+ void *buffer;
+
+ ACPI_FUNCTION_TRACE_PTR(ex_write_gpio, obj_desc);
+
+ /*
+ * For GPIO (general_purpose_io), we will bypass the entire field
+ * mechanism and handoff the bit address and bit width directly to
+ * the handler. The Address will be the bit offset
+ * from the previous Connection() operator, making it effectively a
+ * pin number index. The bit_length is the length of the field, which
+ * is thus the number of pins.
+ */
+ if (source_desc->common.type != ACPI_TYPE_INTEGER) {
+ return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
+ "GPIO FieldWrite [FROM]: (%s:%X), Value %.8X [TO]: Pin %u Bits %u\n",
+ acpi_ut_get_type_name(source_desc->common.type),
+ source_desc->common.type,
+ (u32)source_desc->integer.value,
+ obj_desc->field.pin_number_index,
+ obj_desc->field.bit_length));
+
+ buffer = &source_desc->integer.value;
+
+ /* Lock entire transaction if requested */
+
+ acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
+
+ /* Perform the write */
+
+ status = acpi_ex_access_region(obj_desc, 0, (u64 *)buffer, ACPI_WRITE);
+ acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_read_serial_bus
+ *
+ * PARAMETERS: obj_desc - The named field to read
+ * return_buffer - Where the return value is returned, if any
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Read from a named field that references a serial bus
+ * (SMBus, IPMI, or GSBus).
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_read_serial_bus(union acpi_operand_object *obj_desc,
+ union acpi_operand_object **return_buffer)
+{
+ acpi_status status;
+ u32 buffer_length;
+ union acpi_operand_object *buffer_desc;
+ u32 function;
+ u16 accessor_type;
+
+ ACPI_FUNCTION_TRACE_PTR(ex_read_serial_bus, obj_desc);
+
+ /*
+ * This is an SMBus, GSBus or IPMI read. We must create a buffer to
+ * hold the data and then directly access the region handler.
+ *
+ * Note: SMBus and GSBus protocol value is passed in upper 16-bits
+ * of Function
+ *
+ * Common buffer format:
+ * Status; (Byte 0 of the data buffer)
+ * Length; (Byte 1 of the data buffer)
+ * Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
+ */
+ switch (obj_desc->field.region_obj->region.space_id) {
+ case ACPI_ADR_SPACE_SMBUS:
+
+ buffer_length = ACPI_SMBUS_BUFFER_SIZE;
+ function = ACPI_READ | (obj_desc->field.attribute << 16);
+ break;
+
+ case ACPI_ADR_SPACE_IPMI:
+
+ buffer_length = ACPI_IPMI_BUFFER_SIZE;
+ function = ACPI_READ;
+ break;
+
+ case ACPI_ADR_SPACE_GSBUS:
+
+ accessor_type = obj_desc->field.attribute;
+ if (accessor_type == AML_FIELD_ATTRIB_RAW_PROCESS_BYTES) {
+ ACPI_ERROR((AE_INFO,
+ "Invalid direct read using bidirectional write-then-read protocol"));
+
+ return_ACPI_STATUS(AE_AML_PROTOCOL);
+ }
+
+ status =
+ acpi_ex_get_protocol_buffer_length(accessor_type,
+ &buffer_length);
+ if (ACPI_FAILURE(status)) {
+ ACPI_ERROR((AE_INFO,
+ "Invalid protocol ID for GSBus: 0x%4.4X",
+ accessor_type));
+
+ return_ACPI_STATUS(status);
+ }
+
+ /* Add header length to get the full size of the buffer */
+
+ buffer_length += ACPI_SERIAL_HEADER_SIZE;
+ function = ACPI_READ | (accessor_type << 16);
+ break;
+
+ default:
+ return_ACPI_STATUS(AE_AML_INVALID_SPACE_ID);
+ }
+
+ /* Create the local transfer buffer that is returned to the caller */
+
+ buffer_desc = acpi_ut_create_buffer_object(buffer_length);
+ if (!buffer_desc) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ /* Lock entire transaction if requested */
+
+ acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
+
+ /* Call the region handler for the write-then-read */
+
+ status = acpi_ex_access_region(obj_desc, 0,
+ ACPI_CAST_PTR(u64,
+ buffer_desc->buffer.
+ pointer), function);
+ acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
+
+ *return_buffer = buffer_desc;
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_write_serial_bus
+ *
+ * PARAMETERS: source_desc - Contains data to write
+ * obj_desc - The named field
+ * return_buffer - Where the return value is returned, if any
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Write to a named field that references a serial bus
+ * (SMBus, IPMI, GSBus).
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_write_serial_bus(union acpi_operand_object *source_desc,
+ union acpi_operand_object *obj_desc,
+ union acpi_operand_object **return_buffer)
+{
+ acpi_status status;
+ u32 buffer_length;
+ u32 data_length;
+ void *buffer;
+ union acpi_operand_object *buffer_desc;
+ u32 function;
+ u16 accessor_type;
+
+ ACPI_FUNCTION_TRACE_PTR(ex_write_serial_bus, obj_desc);
+
+ /*
+ * This is an SMBus, GSBus or IPMI write. We will bypass the entire
+ * field mechanism and handoff the buffer directly to the handler.
+ * For these address spaces, the buffer is bidirectional; on a
+ * write, return data is returned in the same buffer.
+ *
+ * Source must be a buffer of sufficient size, these are fixed size:
+ * ACPI_SMBUS_BUFFER_SIZE, or ACPI_IPMI_BUFFER_SIZE.
+ *
+ * Note: SMBus and GSBus protocol type is passed in upper 16-bits
+ * of Function
+ *
+ * Common buffer format:
+ * Status; (Byte 0 of the data buffer)
+ * Length; (Byte 1 of the data buffer)
+ * Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
+ */
+ if (source_desc->common.type != ACPI_TYPE_BUFFER) {
+ ACPI_ERROR((AE_INFO,
+ "SMBus/IPMI/GenericSerialBus write requires "
+ "Buffer, found type %s",
+ acpi_ut_get_object_type_name(source_desc)));
+
+ return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
+ }
+
+ switch (obj_desc->field.region_obj->region.space_id) {
+ case ACPI_ADR_SPACE_SMBUS:
+
+ buffer_length = ACPI_SMBUS_BUFFER_SIZE;
+ data_length = ACPI_SMBUS_DATA_SIZE;
+ function = ACPI_WRITE | (obj_desc->field.attribute << 16);
+ break;
+
+ case ACPI_ADR_SPACE_IPMI:
+
+ buffer_length = ACPI_IPMI_BUFFER_SIZE;
+ data_length = ACPI_IPMI_DATA_SIZE;
+ function = ACPI_WRITE;
+ break;
+
+ case ACPI_ADR_SPACE_GSBUS:
+
+ accessor_type = obj_desc->field.attribute;
+ status =
+ acpi_ex_get_protocol_buffer_length(accessor_type,
+ &buffer_length);
+ if (ACPI_FAILURE(status)) {
+ ACPI_ERROR((AE_INFO,
+ "Invalid protocol ID for GSBus: 0x%4.4X",
+ accessor_type));
+
+ return_ACPI_STATUS(status);
+ }
+
+ /* Add header length to get the full size of the buffer */
+
+ buffer_length += ACPI_SERIAL_HEADER_SIZE;
+ data_length = source_desc->buffer.pointer[1];
+ function = ACPI_WRITE | (accessor_type << 16);
+ break;
+
+ default:
+ return_ACPI_STATUS(AE_AML_INVALID_SPACE_ID);
+ }
+
+#if 0
+ OBSOLETE ?
+ /* Check for possible buffer overflow */
+ if (data_length > source_desc->buffer.length) {
+ ACPI_ERROR((AE_INFO,
+ "Length in buffer header (%u)(%u) is greater than "
+ "the physical buffer length (%u) and will overflow",
+ data_length, buffer_length,
+ source_desc->buffer.length));
+
+ return_ACPI_STATUS(AE_AML_BUFFER_LIMIT);
+ }
+#endif
+
+ /* Create the transfer/bidirectional/return buffer */
+
+ buffer_desc = acpi_ut_create_buffer_object(buffer_length);
+ if (!buffer_desc) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ /* Copy the input buffer data to the transfer buffer */
+
+ buffer = buffer_desc->buffer.pointer;
+ memcpy(buffer, source_desc->buffer.pointer, data_length);
+
+ /* Lock entire transaction if requested */
+
+ acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
+
+ /*
+ * Perform the write (returns status and perhaps data in the
+ * same buffer)
+ */
+ status = acpi_ex_access_region(obj_desc, 0, (u64 *)buffer, function);
+ acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
+
+ *return_buffer = buffer_desc;
+ return_ACPI_STATUS(status);
+}
diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c
index 34fc2f7476ed..0fa01c9e353e 100644
--- a/drivers/acpi/acpica/psloop.c
+++ b/drivers/acpi/acpica/psloop.c
@@ -147,7 +147,7 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state,
* future. Use of this option can cause problems with AML code that
* depends upon in-order immediate execution of module-level code.
*/
- if (acpi_gbl_group_module_level_code &&
+ if (!acpi_gbl_execute_tables_as_methods &&
(walk_state->pass_number <= ACPI_IMODE_LOAD_PASS2) &&
((walk_state->parse_flags & ACPI_PARSE_DISASSEMBLE) == 0)) {
/*
@@ -417,6 +417,7 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
union acpi_parse_object *op = NULL; /* current op */
struct acpi_parse_state *parser_state;
u8 *aml_op_start = NULL;
+ u8 opcode_length;
ACPI_FUNCTION_TRACE_PTR(ps_parse_loop, walk_state);
@@ -540,8 +541,19 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
"Skip parsing opcode %s",
acpi_ps_get_opcode_name
(walk_state->opcode)));
+
+ /*
+ * Determine the opcode length before skipping the opcode.
+ * An opcode can be 1 byte or 2 bytes in length.
+ */
+ opcode_length = 1;
+ if ((walk_state->opcode & 0xFF00) ==
+ AML_EXTENDED_OPCODE) {
+ opcode_length = 2;
+ }
walk_state->parser_state.aml =
- walk_state->aml + 1;
+ walk_state->aml + opcode_length;
+
walk_state->parser_state.aml =
acpi_ps_get_next_package_end
(&walk_state->parser_state);
diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c
index 2f40f71c06db..9011297552af 100644
--- a/drivers/acpi/acpica/tbxfload.c
+++ b/drivers/acpi/acpica/tbxfload.c
@@ -69,8 +69,7 @@ acpi_status ACPI_INIT_FUNCTION acpi_load_tables(void)
"While loading namespace from ACPI tables"));
}
- if (acpi_gbl_execute_tables_as_methods
- || !acpi_gbl_group_module_level_code) {
+ if (acpi_gbl_execute_tables_as_methods) {
/*
* If the module-level code support is enabled, initialize the objects
* in the namespace that remain uninitialized. This runs the executable
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 08f26db2da7e..2a361e22d38d 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -1428,7 +1428,7 @@ static int __init iort_add_platform_device(struct acpi_iort_node *node,
return 0;
dma_deconfigure:
- acpi_dma_deconfigure(&pdev->dev);
+ arch_teardown_dma_ops(&pdev->dev);
dev_put:
platform_device_put(pdev);
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index d2e29a19890d..bb3d96dea6db 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -1054,15 +1054,17 @@ void __init acpi_early_init(void)
goto error0;
}
- if (!acpi_gbl_execute_tables_as_methods &&
- acpi_gbl_group_module_level_code) {
- status = acpi_load_tables();
- if (ACPI_FAILURE(status)) {
- printk(KERN_ERR PREFIX
- "Unable to load the System Description Tables\n");
- goto error0;
- }
- }
+ /*
+ * ACPI 2.0 requires the EC driver to be loaded and work before
+ * the EC device is found in the namespace (i.e. before
+ * acpi_load_tables() is called).
+ *
+ * This is accomplished by looking for the ECDT table, and getting
+ * the EC parameters out of that.
+ *
+ * Ignore the result. Not having an ECDT is not fatal.
+ */
+ status = acpi_ec_ecdt_probe();
#ifdef CONFIG_X86
if (!acpi_ioapic) {
@@ -1133,25 +1135,11 @@ static int __init acpi_bus_init(void)
acpi_os_initialize1();
- /*
- * ACPI 2.0 requires the EC driver to be loaded and work before
- * the EC device is found in the namespace (i.e. before
- * acpi_load_tables() is called).
- *
- * This is accomplished by looking for the ECDT table, and getting
- * the EC parameters out of that.
- */
- status = acpi_ec_ecdt_probe();
- /* Ignore result. Not having an ECDT is not fatal. */
-
- if (acpi_gbl_execute_tables_as_methods ||
- !acpi_gbl_group_module_level_code) {
- status = acpi_load_tables();
- if (ACPI_FAILURE(status)) {
- printk(KERN_ERR PREFIX
- "Unable to load the System Description Tables\n");
- goto error1;
- }
+ status = acpi_load_tables();
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR PREFIX
+ "Unable to load the System Description Tables\n");
+ goto error1;
}
status = acpi_enable_subsystem(ACPI_NO_ACPI_ENABLE);
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index d9ce4b162e2c..217a782c3e55 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -1061,9 +1061,9 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
{
struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpunum);
struct cpc_register_resource *highest_reg, *lowest_reg,
- *lowest_non_linear_reg, *nominal_reg,
+ *lowest_non_linear_reg, *nominal_reg, *guaranteed_reg,
*low_freq_reg = NULL, *nom_freq_reg = NULL;
- u64 high, low, nom, min_nonlinear, low_f = 0, nom_f = 0;
+ u64 high, low, guaranteed, nom, min_nonlinear, low_f = 0, nom_f = 0;
int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpunum);
struct cppc_pcc_data *pcc_ss_data = NULL;
int ret = 0, regs_in_pcc = 0;
@@ -1079,6 +1079,7 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
nominal_reg = &cpc_desc->cpc_regs[NOMINAL_PERF];
low_freq_reg = &cpc_desc->cpc_regs[LOWEST_FREQ];
nom_freq_reg = &cpc_desc->cpc_regs[NOMINAL_FREQ];
+ guaranteed_reg = &cpc_desc->cpc_regs[GUARANTEED_PERF];
/* Are any of the regs PCC ?*/
if (CPC_IN_PCC(highest_reg) || CPC_IN_PCC(lowest_reg) ||
@@ -1107,6 +1108,9 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
cpc_read(cpunum, nominal_reg, &nom);
perf_caps->nominal_perf = nom;
+ cpc_read(cpunum, guaranteed_reg, &guaranteed);
+ perf_caps->guaranteed_perf = guaranteed;
+
cpc_read(cpunum, lowest_non_linear_reg, &min_nonlinear);
perf_caps->lowest_nonlinear_perf = min_nonlinear;
diff --git a/drivers/acpi/custom_method.c b/drivers/acpi/custom_method.c
index e967c1173ba3..4451877f83b6 100644
--- a/drivers/acpi/custom_method.c
+++ b/drivers/acpi/custom_method.c
@@ -92,8 +92,7 @@ static int __init acpi_custom_method_init(void)
static void __exit acpi_custom_method_exit(void)
{
- if (cm_dentry)
- debugfs_remove(cm_dentry);
+ debugfs_remove(cm_dentry);
}
module_init(acpi_custom_method_init);
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index a7c2673ffd36..824ae985ad93 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -126,6 +126,7 @@ int acpi_device_get_power(struct acpi_device *device, int *state)
return 0;
}
+EXPORT_SYMBOL(acpi_device_get_power);
static int acpi_dev_pm_explicit_set(struct acpi_device *adev, int state)
{
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 3be1433853bf..12ba2bee8789 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -320,7 +320,7 @@ static int acpi_platform_notify(struct device *dev)
if (!adev)
goto out;
- if (dev->bus == &platform_bus_type)
+ if (dev_is_platform(dev))
acpi_configure_pmsi_domain(dev);
if (type && type->setup)
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c
index b072cfc5f20e..14d9f5bea015 100644
--- a/drivers/acpi/nfit/core.c
+++ b/drivers/acpi/nfit/core.c
@@ -25,6 +25,7 @@
#include <asm/cacheflush.h>
#include <acpi/nfit.h>
#include "nfit.h"
+#include "intel.h"
/*
* For readq() and writeq() on 32-bit builds, the hi-lo, lo-hi order is
@@ -191,18 +192,20 @@ static int xlat_nvdimm_status(struct nvdimm *nvdimm, void *buf, unsigned int cmd
* In the _LSI, _LSR, _LSW case the locked status is
* communicated via the read/write commands
*/
- if (nfit_mem->has_lsr)
+ if (test_bit(NFIT_MEM_LSR, &nfit_mem->flags))
break;
if (status >> 16 & ND_CONFIG_LOCKED)
return -EACCES;
break;
case ND_CMD_GET_CONFIG_DATA:
- if (nfit_mem->has_lsr && status == ACPI_LABELS_LOCKED)
+ if (test_bit(NFIT_MEM_LSR, &nfit_mem->flags)
+ && status == ACPI_LABELS_LOCKED)
return -EACCES;
break;
case ND_CMD_SET_CONFIG_DATA:
- if (nfit_mem->has_lsw && status == ACPI_LABELS_LOCKED)
+ if (test_bit(NFIT_MEM_LSW, &nfit_mem->flags)
+ && status == ACPI_LABELS_LOCKED)
return -EACCES;
break;
default:
@@ -480,14 +483,16 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
min_t(u32, 256, in_buf.buffer.length), true);
/* call the BIOS, prefer the named methods over _DSM if available */
- if (nvdimm && cmd == ND_CMD_GET_CONFIG_SIZE && nfit_mem->has_lsr)
+ if (nvdimm && cmd == ND_CMD_GET_CONFIG_SIZE
+ && test_bit(NFIT_MEM_LSR, &nfit_mem->flags))
out_obj = acpi_label_info(handle);
- else if (nvdimm && cmd == ND_CMD_GET_CONFIG_DATA && nfit_mem->has_lsr) {
+ else if (nvdimm && cmd == ND_CMD_GET_CONFIG_DATA
+ && test_bit(NFIT_MEM_LSR, &nfit_mem->flags)) {
struct nd_cmd_get_config_data_hdr *p = buf;
out_obj = acpi_label_read(handle, p->in_offset, p->in_length);
} else if (nvdimm && cmd == ND_CMD_SET_CONFIG_DATA
- && nfit_mem->has_lsw) {
+ && test_bit(NFIT_MEM_LSW, &nfit_mem->flags)) {
struct nd_cmd_set_config_hdr *p = buf;
out_obj = acpi_label_write(handle, p->in_offset, p->in_length,
@@ -1547,7 +1552,12 @@ static DEVICE_ATTR_RO(dsm_mask);
static ssize_t flags_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- u16 flags = to_nfit_memdev(dev)->flags;
+ struct nvdimm *nvdimm = to_nvdimm(dev);
+ struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
+ u16 flags = __to_nfit_memdev(nfit_mem)->flags;
+
+ if (test_bit(NFIT_MEM_DIRTY, &nfit_mem->flags))
+ flags |= ACPI_NFIT_MEM_FLUSH_FAILED;
return sprintf(buf, "%s%s%s%s%s%s%s\n",
flags & ACPI_NFIT_MEM_SAVE_FAILED ? "save_fail " : "",
@@ -1578,6 +1588,16 @@ static ssize_t id_show(struct device *dev,
}
static DEVICE_ATTR_RO(id);
+static ssize_t dirty_shutdown_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct nvdimm *nvdimm = to_nvdimm(dev);
+ struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
+
+ return sprintf(buf, "%d\n", nfit_mem->dirty_shutdown);
+}
+static DEVICE_ATTR_RO(dirty_shutdown);
+
static struct attribute *acpi_nfit_dimm_attributes[] = {
&dev_attr_handle.attr,
&dev_attr_phys_id.attr,
@@ -1595,6 +1615,7 @@ static struct attribute *acpi_nfit_dimm_attributes[] = {
&dev_attr_id.attr,
&dev_attr_family.attr,
&dev_attr_dsm_mask.attr,
+ &dev_attr_dirty_shutdown.attr,
NULL,
};
@@ -1603,6 +1624,7 @@ static umode_t acpi_nfit_dimm_attr_visible(struct kobject *kobj,
{
struct device *dev = container_of(kobj, struct device, kobj);
struct nvdimm *nvdimm = to_nvdimm(dev);
+ struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
if (!to_nfit_dcr(dev)) {
/* Without a dcr only the memdev attributes can be surfaced */
@@ -1616,6 +1638,11 @@ static umode_t acpi_nfit_dimm_attr_visible(struct kobject *kobj,
if (a == &dev_attr_format1.attr && num_nvdimm_formats(nvdimm) <= 1)
return 0;
+
+ if (!test_bit(NFIT_MEM_DIRTY_COUNT, &nfit_mem->flags)
+ && a == &dev_attr_dirty_shutdown.attr)
+ return 0;
+
return a->mode;
}
@@ -1694,6 +1721,56 @@ static bool acpi_nvdimm_has_method(struct acpi_device *adev, char *method)
return false;
}
+__weak void nfit_intel_shutdown_status(struct nfit_mem *nfit_mem)
+{
+ struct nd_intel_smart smart = { 0 };
+ union acpi_object in_buf = {
+ .type = ACPI_TYPE_BUFFER,
+ .buffer.pointer = (char *) &smart,
+ .buffer.length = sizeof(smart),
+ };
+ union acpi_object in_obj = {
+ .type = ACPI_TYPE_PACKAGE,
+ .package.count = 1,
+ .package.elements = &in_buf,
+ };
+ const u8 func = ND_INTEL_SMART;
+ const guid_t *guid = to_nfit_uuid(nfit_mem->family);
+ u8 revid = nfit_dsm_revid(nfit_mem->family, func);
+ struct acpi_device *adev = nfit_mem->adev;
+ acpi_handle handle = adev->handle;
+ union acpi_object *out_obj;
+
+ if ((nfit_mem->dsm_mask & (1 << func)) == 0)
+ return;
+
+ out_obj = acpi_evaluate_dsm(handle, guid, revid, func, &in_obj);
+ if (!out_obj)
+ return;
+
+ if (smart.flags & ND_INTEL_SMART_SHUTDOWN_VALID) {
+ if (smart.shutdown_state)
+ set_bit(NFIT_MEM_DIRTY, &nfit_mem->flags);
+ }
+
+ if (smart.flags & ND_INTEL_SMART_SHUTDOWN_COUNT_VALID) {
+ set_bit(NFIT_MEM_DIRTY_COUNT, &nfit_mem->flags);
+ nfit_mem->dirty_shutdown = smart.shutdown_count;
+ }
+ ACPI_FREE(out_obj);
+}
+
+static void populate_shutdown_status(struct nfit_mem *nfit_mem)
+{
+ /*
+ * For DIMMs that provide a dynamic facility to retrieve a
+ * dirty-shutdown status and/or a dirty-shutdown count, cache
+ * these values in nfit_mem.
+ */
+ if (nfit_mem->family == NVDIMM_FAMILY_INTEL)
+ nfit_intel_shutdown_status(nfit_mem);
+}
+
static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc,
struct nfit_mem *nfit_mem, u32 device_handle)
{
@@ -1708,8 +1785,11 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc,
nfit_mem->dsm_mask = acpi_desc->dimm_cmd_force_en;
nfit_mem->family = NVDIMM_FAMILY_INTEL;
adev = to_acpi_dev(acpi_desc);
- if (!adev)
+ if (!adev) {
+ /* unit test case */
+ populate_shutdown_status(nfit_mem);
return 0;
+ }
adev_dimm = acpi_find_child_device(adev, device_handle, false);
nfit_mem->adev = adev_dimm;
@@ -1784,14 +1864,17 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc,
if (acpi_nvdimm_has_method(adev_dimm, "_LSI")
&& acpi_nvdimm_has_method(adev_dimm, "_LSR")) {
dev_dbg(dev, "%s: has _LSR\n", dev_name(&adev_dimm->dev));
- nfit_mem->has_lsr = true;
+ set_bit(NFIT_MEM_LSR, &nfit_mem->flags);
}
- if (nfit_mem->has_lsr && acpi_nvdimm_has_method(adev_dimm, "_LSW")) {
+ if (test_bit(NFIT_MEM_LSR, &nfit_mem->flags)
+ && acpi_nvdimm_has_method(adev_dimm, "_LSW")) {
dev_dbg(dev, "%s: has _LSW\n", dev_name(&adev_dimm->dev));
- nfit_mem->has_lsw = true;
+ set_bit(NFIT_MEM_LSW, &nfit_mem->flags);
}
+ populate_shutdown_status(nfit_mem);
+
return 0;
}
@@ -1878,11 +1961,11 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
cmd_mask |= nfit_mem->dsm_mask & NVDIMM_STANDARD_CMDMASK;
}
- if (nfit_mem->has_lsr) {
+ if (test_bit(NFIT_MEM_LSR, &nfit_mem->flags)) {
set_bit(ND_CMD_GET_CONFIG_SIZE, &cmd_mask);
set_bit(ND_CMD_GET_CONFIG_DATA, &cmd_mask);
}
- if (nfit_mem->has_lsw)
+ if (test_bit(NFIT_MEM_LSW, &nfit_mem->flags))
set_bit(ND_CMD_SET_CONFIG_DATA, &cmd_mask);
flush = nfit_mem->nfit_flush ? nfit_mem->nfit_flush->flush
@@ -2466,7 +2549,8 @@ static int ars_get_cap(struct acpi_nfit_desc *acpi_desc,
return cmd_rc;
}
-static int ars_start(struct acpi_nfit_desc *acpi_desc, struct nfit_spa *nfit_spa)
+static int ars_start(struct acpi_nfit_desc *acpi_desc,
+ struct nfit_spa *nfit_spa, enum nfit_ars_state req_type)
{
int rc;
int cmd_rc;
@@ -2477,7 +2561,7 @@ static int ars_start(struct acpi_nfit_desc *acpi_desc, struct nfit_spa *nfit_spa
memset(&ars_start, 0, sizeof(ars_start));
ars_start.address = spa->address;
ars_start.length = spa->length;
- if (test_bit(ARS_SHORT, &nfit_spa->ars_state))
+ if (req_type == ARS_REQ_SHORT)
ars_start.flags = ND_ARS_RETURN_PREV_DATA;
if (nfit_spa_type(spa) == NFIT_SPA_PM)
ars_start.type = ND_ARS_PERSISTENT;
@@ -2534,6 +2618,15 @@ static void ars_complete(struct acpi_nfit_desc *acpi_desc,
struct nd_region *nd_region = nfit_spa->nd_region;
struct device *dev;
+ lockdep_assert_held(&acpi_desc->init_mutex);
+ /*
+ * Only advance the ARS state for ARS runs initiated by the
+ * kernel, ignore ARS results from BIOS initiated runs for scrub
+ * completion tracking.
+ */
+ if (acpi_desc->scrub_spa != nfit_spa)
+ return;
+
if ((ars_status->address >= spa->address && ars_status->address
< spa->address + spa->length)
|| (ars_status->address < spa->address)) {
@@ -2553,28 +2646,13 @@ static void ars_complete(struct acpi_nfit_desc *acpi_desc,
} else
return;
- if (test_bit(ARS_DONE, &nfit_spa->ars_state))
- return;
-
- if (!test_and_clear_bit(ARS_REQ, &nfit_spa->ars_state))
- return;
-
+ acpi_desc->scrub_spa = NULL;
if (nd_region) {
dev = nd_region_dev(nd_region);
nvdimm_region_notify(nd_region, NVDIMM_REVALIDATE_POISON);
} else
dev = acpi_desc->dev;
-
- dev_dbg(dev, "ARS: range %d %s complete\n", spa->range_index,
- test_bit(ARS_SHORT, &nfit_spa->ars_state)
- ? "short" : "long");
- clear_bit(ARS_SHORT, &nfit_spa->ars_state);
- if (test_and_clear_bit(ARS_REQ_REDO, &nfit_spa->ars_state)) {
- set_bit(ARS_SHORT, &nfit_spa->ars_state);
- set_bit(ARS_REQ, &nfit_spa->ars_state);
- dev_dbg(dev, "ARS: processing scrub request received while in progress\n");
- } else
- set_bit(ARS_DONE, &nfit_spa->ars_state);
+ dev_dbg(dev, "ARS: range %d complete\n", spa->range_index);
}
static int ars_status_process_records(struct acpi_nfit_desc *acpi_desc)
@@ -2850,51 +2928,60 @@ static int acpi_nfit_query_poison(struct acpi_nfit_desc *acpi_desc)
return rc;
if (ars_status_process_records(acpi_desc))
- return -ENOMEM;
+ dev_err(acpi_desc->dev, "Failed to process ARS records\n");
- return 0;
+ return rc;
}
-static int ars_register(struct acpi_nfit_desc *acpi_desc, struct nfit_spa *nfit_spa,
- int *query_rc)
+static int ars_register(struct acpi_nfit_desc *acpi_desc,
+ struct nfit_spa *nfit_spa)
{
- int rc = *query_rc;
+ int rc;
- if (no_init_ars)
+ if (no_init_ars || test_bit(ARS_FAILED, &nfit_spa->ars_state))
return acpi_nfit_register_region(acpi_desc, nfit_spa);
- set_bit(ARS_REQ, &nfit_spa->ars_state);
- set_bit(ARS_SHORT, &nfit_spa->ars_state);
+ set_bit(ARS_REQ_SHORT, &nfit_spa->ars_state);
+ set_bit(ARS_REQ_LONG, &nfit_spa->ars_state);
- switch (rc) {
+ switch (acpi_nfit_query_poison(acpi_desc)) {
case 0:
case -EAGAIN:
- rc = ars_start(acpi_desc, nfit_spa);
- if (rc == -EBUSY) {
- *query_rc = rc;
+ rc = ars_start(acpi_desc, nfit_spa, ARS_REQ_SHORT);
+ /* shouldn't happen, try again later */
+ if (rc == -EBUSY)
break;
- } else if (rc == 0) {
- rc = acpi_nfit_query_poison(acpi_desc);
- } else {
+ if (rc) {
set_bit(ARS_FAILED, &nfit_spa->ars_state);
break;
}
- if (rc == -EAGAIN)
- clear_bit(ARS_SHORT, &nfit_spa->ars_state);
- else if (rc == 0)
- ars_complete(acpi_desc, nfit_spa);
+ clear_bit(ARS_REQ_SHORT, &nfit_spa->ars_state);
+ rc = acpi_nfit_query_poison(acpi_desc);
+ if (rc)
+ break;
+ acpi_desc->scrub_spa = nfit_spa;
+ ars_complete(acpi_desc, nfit_spa);
+ /*
+ * If ars_complete() says we didn't complete the
+ * short scrub, we'll try again with a long
+ * request.
+ */
+ acpi_desc->scrub_spa = NULL;
break;
case -EBUSY:
+ case -ENOMEM:
case -ENOSPC:
+ /*
+ * BIOS was using ARS, wait for it to complete (or
+ * resources to become available) and then perform our
+ * own scrubs.
+ */
break;
default:
set_bit(ARS_FAILED, &nfit_spa->ars_state);
break;
}
- if (test_and_clear_bit(ARS_DONE, &nfit_spa->ars_state))
- set_bit(ARS_REQ, &nfit_spa->ars_state);
-
return acpi_nfit_register_region(acpi_desc, nfit_spa);
}
@@ -2916,6 +3003,8 @@ static unsigned int __acpi_nfit_scrub(struct acpi_nfit_desc *acpi_desc,
struct device *dev = acpi_desc->dev;
struct nfit_spa *nfit_spa;
+ lockdep_assert_held(&acpi_desc->init_mutex);
+
if (acpi_desc->cancel)
return 0;
@@ -2939,21 +3028,49 @@ static unsigned int __acpi_nfit_scrub(struct acpi_nfit_desc *acpi_desc,
ars_complete_all(acpi_desc);
list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
+ enum nfit_ars_state req_type;
+ int rc;
+
if (test_bit(ARS_FAILED, &nfit_spa->ars_state))
continue;
- if (test_bit(ARS_REQ, &nfit_spa->ars_state)) {
- int rc = ars_start(acpi_desc, nfit_spa);
-
- clear_bit(ARS_DONE, &nfit_spa->ars_state);
- dev = nd_region_dev(nfit_spa->nd_region);
- dev_dbg(dev, "ARS: range %d ARS start (%d)\n",
- nfit_spa->spa->range_index, rc);
- if (rc == 0 || rc == -EBUSY)
- return 1;
- dev_err(dev, "ARS: range %d ARS failed (%d)\n",
- nfit_spa->spa->range_index, rc);
- set_bit(ARS_FAILED, &nfit_spa->ars_state);
+
+ /* prefer short ARS requests first */
+ if (test_bit(ARS_REQ_SHORT, &nfit_spa->ars_state))
+ req_type = ARS_REQ_SHORT;
+ else if (test_bit(ARS_REQ_LONG, &nfit_spa->ars_state))
+ req_type = ARS_REQ_LONG;
+ else
+ continue;
+ rc = ars_start(acpi_desc, nfit_spa, req_type);
+
+ dev = nd_region_dev(nfit_spa->nd_region);
+ dev_dbg(dev, "ARS: range %d ARS start %s (%d)\n",
+ nfit_spa->spa->range_index,
+ req_type == ARS_REQ_SHORT ? "short" : "long",
+ rc);
+ /*
+ * Hmm, we raced someone else starting ARS? Try again in
+ * a bit.
+ */
+ if (rc == -EBUSY)
+ return 1;
+ if (rc == 0) {
+ dev_WARN_ONCE(dev, acpi_desc->scrub_spa,
+ "scrub start while range %d active\n",
+ acpi_desc->scrub_spa->spa->range_index);
+ clear_bit(req_type, &nfit_spa->ars_state);
+ acpi_desc->scrub_spa = nfit_spa;
+ /*
+ * Consider this spa last for future scrub
+ * requests
+ */
+ list_move_tail(&nfit_spa->list, &acpi_desc->spas);
+ return 1;
}
+
+ dev_err(dev, "ARS: range %d ARS failed (%d)\n",
+ nfit_spa->spa->range_index, rc);
+ set_bit(ARS_FAILED, &nfit_spa->ars_state);
}
return 0;
}
@@ -3009,6 +3126,7 @@ static void acpi_nfit_init_ars(struct acpi_nfit_desc *acpi_desc,
struct nd_cmd_ars_cap ars_cap;
int rc;
+ set_bit(ARS_FAILED, &nfit_spa->ars_state);
memset(&ars_cap, 0, sizeof(ars_cap));
rc = ars_get_cap(acpi_desc, &ars_cap, nfit_spa);
if (rc < 0)
@@ -3025,16 +3143,14 @@ static void acpi_nfit_init_ars(struct acpi_nfit_desc *acpi_desc,
nfit_spa->clear_err_unit = ars_cap.clear_err_unit;
acpi_desc->max_ars = max(nfit_spa->max_ars, acpi_desc->max_ars);
clear_bit(ARS_FAILED, &nfit_spa->ars_state);
- set_bit(ARS_REQ, &nfit_spa->ars_state);
}
static int acpi_nfit_register_regions(struct acpi_nfit_desc *acpi_desc)
{
struct nfit_spa *nfit_spa;
- int rc, query_rc;
+ int rc;
list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
- set_bit(ARS_FAILED, &nfit_spa->ars_state);
switch (nfit_spa_type(nfit_spa->spa)) {
case NFIT_SPA_VOLATILE:
case NFIT_SPA_PM:
@@ -3043,20 +3159,12 @@ static int acpi_nfit_register_regions(struct acpi_nfit_desc *acpi_desc)
}
}
- /*
- * Reap any results that might be pending before starting new
- * short requests.
- */
- query_rc = acpi_nfit_query_poison(acpi_desc);
- if (query_rc == 0)
- ars_complete_all(acpi_desc);
-
list_for_each_entry(nfit_spa, &acpi_desc->spas, list)
switch (nfit_spa_type(nfit_spa->spa)) {
case NFIT_SPA_VOLATILE:
case NFIT_SPA_PM:
/* register regions and kick off initial ARS run */
- rc = ars_register(acpi_desc, nfit_spa, &query_rc);
+ rc = ars_register(acpi_desc, nfit_spa);
if (rc)
return rc;
break;
@@ -3242,8 +3350,8 @@ static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc,
/*
* The kernel and userspace may race to initiate a scrub, but
* the scrub thread is prepared to lose that initial race. It
- * just needs guarantees that any ars it initiates are not
- * interrupted by any intervening start reqeusts from userspace.
+ * just needs guarantees that any ARS it initiates are not
+ * interrupted by any intervening start requests from userspace.
*/
if (work_busy(&acpi_desc->dwork.work))
return -EBUSY;
@@ -3251,7 +3359,8 @@ static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc,
return 0;
}
-int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc, unsigned long flags)
+int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc,
+ enum nfit_ars_state req_type)
{
struct device *dev = acpi_desc->dev;
int scheduled = 0, busy = 0;
@@ -3271,14 +3380,10 @@ int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc, unsigned long flags)
if (test_bit(ARS_FAILED, &nfit_spa->ars_state))
continue;
- if (test_and_set_bit(ARS_REQ, &nfit_spa->ars_state)) {
+ if (test_and_set_bit(req_type, &nfit_spa->ars_state))
busy++;
- set_bit(ARS_REQ_REDO, &nfit_spa->ars_state);
- } else {
- if (test_bit(ARS_SHORT, &flags))
- set_bit(ARS_SHORT, &nfit_spa->ars_state);
+ else
scheduled++;
- }
}
if (scheduled) {
sched_ars(acpi_desc);
@@ -3464,10 +3569,11 @@ static void acpi_nfit_update_notify(struct device *dev, acpi_handle handle)
static void acpi_nfit_uc_error_notify(struct device *dev, acpi_handle handle)
{
struct acpi_nfit_desc *acpi_desc = dev_get_drvdata(dev);
- unsigned long flags = (acpi_desc->scrub_mode == HW_ERROR_SCRUB_ON) ?
- 0 : 1 << ARS_SHORT;
- acpi_nfit_ars_rescan(acpi_desc, flags);
+ if (acpi_desc->scrub_mode == HW_ERROR_SCRUB_ON)
+ acpi_nfit_ars_rescan(acpi_desc, ARS_REQ_LONG);
+ else
+ acpi_nfit_ars_rescan(acpi_desc, ARS_REQ_SHORT);
}
void __acpi_nfit_notify(struct device *dev, acpi_handle handle, u32 event)
diff --git a/drivers/acpi/nfit/intel.h b/drivers/acpi/nfit/intel.h
new file mode 100644
index 000000000000..86746312381f
--- /dev/null
+++ b/drivers/acpi/nfit/intel.h
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright(c) 2018 Intel Corporation. All rights reserved.
+ * Intel specific definitions for NVDIMM Firmware Interface Table - NFIT
+ */
+#ifndef _NFIT_INTEL_H_
+#define _NFIT_INTEL_H_
+
+#define ND_INTEL_SMART 1
+
+#define ND_INTEL_SMART_SHUTDOWN_COUNT_VALID (1 << 5)
+#define ND_INTEL_SMART_SHUTDOWN_VALID (1 << 10)
+
+struct nd_intel_smart {
+ u32 status;
+ union {
+ struct {
+ u32 flags;
+ u8 reserved0[4];
+ u8 health;
+ u8 spares;
+ u8 life_used;
+ u8 alarm_flags;
+ u16 media_temperature;
+ u16 ctrl_temperature;
+ u32 shutdown_count;
+ u8 ait_status;
+ u16 pmic_temperature;
+ u8 reserved1[8];
+ u8 shutdown_state;
+ u32 vendor_size;
+ u8 vendor_data[92];
+ } __packed;
+ u8 data[128];
+ };
+} __packed;
+
+#endif
diff --git a/drivers/acpi/nfit/mce.c b/drivers/acpi/nfit/mce.c
index e9626bf6ca29..d6c1b10f6c25 100644
--- a/drivers/acpi/nfit/mce.c
+++ b/drivers/acpi/nfit/mce.c
@@ -25,8 +25,12 @@ static int nfit_handle_mce(struct notifier_block *nb, unsigned long val,
struct acpi_nfit_desc *acpi_desc;
struct nfit_spa *nfit_spa;
- /* We only care about memory errors */
- if (!mce_is_memory_error(mce))
+ /* We only care about uncorrectable memory errors */
+ if (!mce_is_memory_error(mce) || mce_is_correctable(mce))
+ return NOTIFY_DONE;
+
+ /* Verify the address reported in the MCE is valid. */
+ if (!mce_usable_address(mce))
return NOTIFY_DONE;
/*
diff --git a/drivers/acpi/nfit/nfit.h b/drivers/acpi/nfit/nfit.h
index d1274ea2d251..df0f6b8407e7 100644
--- a/drivers/acpi/nfit/nfit.h
+++ b/drivers/acpi/nfit/nfit.h
@@ -118,10 +118,8 @@ enum nfit_dimm_notifiers {
};
enum nfit_ars_state {
- ARS_REQ,
- ARS_REQ_REDO,
- ARS_DONE,
- ARS_SHORT,
+ ARS_REQ_SHORT,
+ ARS_REQ_LONG,
ARS_FAILED,
};
@@ -159,6 +157,13 @@ struct nfit_memdev {
struct acpi_nfit_memory_map memdev[0];
};
+enum nfit_mem_flags {
+ NFIT_MEM_LSR,
+ NFIT_MEM_LSW,
+ NFIT_MEM_DIRTY,
+ NFIT_MEM_DIRTY_COUNT,
+};
+
/* assembled tables for a given dimm/memory-device */
struct nfit_mem {
struct nvdimm *nvdimm;
@@ -178,9 +183,9 @@ struct nfit_mem {
struct acpi_nfit_desc *acpi_desc;
struct resource *flush_wpq;
unsigned long dsm_mask;
+ unsigned long flags;
+ u32 dirty_shutdown;
int family;
- bool has_lsr;
- bool has_lsw;
};
struct acpi_nfit_desc {
@@ -198,6 +203,7 @@ struct acpi_nfit_desc {
struct device *dev;
u8 ars_start_flags;
struct nd_cmd_ars_status *ars_status;
+ struct nfit_spa *scrub_spa;
struct delayed_work dwork;
struct list_head list;
struct kernfs_node *scrub_count_state;
@@ -252,7 +258,8 @@ struct nfit_blk {
extern struct list_head acpi_descs;
extern struct mutex acpi_desc_lock;
-int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc, unsigned long flags);
+int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc,
+ enum nfit_ars_state req_type);
#ifdef CONFIG_X86_MCE
void nfit_mce_register(void);
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
index 85167603b9c9..274699463b4f 100644
--- a/drivers/acpi/numa.c
+++ b/drivers/acpi/numa.c
@@ -27,7 +27,6 @@
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/acpi.h>
-#include <linux/bootmem.h>
#include <linux/memblock.h>
#include <linux/numa.h>
#include <linux/nodemask.h>
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 8df9abfa947b..b48874b8e1ea 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -617,15 +617,18 @@ void acpi_os_stall(u32 us)
}
/*
- * Support ACPI 3.0 AML Timer operand
- * Returns 64-bit free-running, monotonically increasing timer
- * with 100ns granularity
+ * Support ACPI 3.0 AML Timer operand. Returns a 64-bit free-running,
+ * monotonically increasing timer with 100ns granularity. Do not use
+ * ktime_get() to implement this function because this function may get
+ * called after timekeeping has been suspended. Note: calling this function
+ * after timekeeping has been suspended may lead to unexpected results
+ * because when timekeeping is suspended the jiffies counter is not
+ * incremented. See also timekeeping_suspend().
*/
u64 acpi_os_get_timer(void)
{
- u64 time_ns = ktime_to_ns(ktime_get());
- do_div(time_ns, 100);
- return time_ns;
+ return (get_jiffies_64() - INITIAL_JIFFIES) *
+ (ACPI_100NSEC_PER_SEC / HZ);
}
acpi_status acpi_os_read_port(acpi_io_address port, u32 * value, u32 width)
@@ -1129,6 +1132,7 @@ void acpi_os_wait_events_complete(void)
flush_workqueue(kacpid_wq);
flush_workqueue(kacpi_notify_wq);
}
+EXPORT_SYMBOL(acpi_os_wait_events_complete);
struct acpi_hp_work {
struct work_struct work;
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 7433035ded95..707aafc7c2aa 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -421,7 +421,8 @@ out:
}
EXPORT_SYMBOL(acpi_pci_osc_control_set);
-static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm)
+static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm,
+ bool is_pcie)
{
u32 support, control, requested;
acpi_status status;
@@ -455,9 +456,15 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm)
decode_osc_support(root, "OS supports", support);
status = acpi_pci_osc_support(root, support);
if (ACPI_FAILURE(status)) {
- dev_info(&device->dev, "_OSC failed (%s); disabling ASPM\n",
- acpi_format_exception(status));
*no_aspm = 1;
+
+ /* _OSC is optional for PCI host bridges */
+ if ((status == AE_NOT_FOUND) && !is_pcie)
+ return;
+
+ dev_info(&device->dev, "_OSC failed (%s)%s\n",
+ acpi_format_exception(status),
+ pcie_aspm_support_enabled() ? "; disabling ASPM" : "");
return;
}
@@ -533,6 +540,7 @@ static int acpi_pci_root_add(struct acpi_device *device,
acpi_handle handle = device->handle;
int no_aspm = 0;
bool hotadd = system_state == SYSTEM_RUNNING;
+ bool is_pcie;
root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL);
if (!root)
@@ -590,7 +598,8 @@ static int acpi_pci_root_add(struct acpi_device *device,
root->mcfg_addr = acpi_pci_root_get_mcfg_addr(handle);
- negotiate_os_control(root, &no_aspm);
+ is_pcie = strcmp(acpi_device_hid(device), "PNP0A08") == 0;
+ negotiate_os_control(root, &no_aspm, is_pcie);
/*
* TBD: Need PCI interface for enumeration/configuration of roots.
diff --git a/drivers/acpi/pmic/intel_pmic_bxtwc.c b/drivers/acpi/pmic/intel_pmic_bxtwc.c
index 886ac8b93cd0..bd7621edd60b 100644
--- a/drivers/acpi/pmic/intel_pmic_bxtwc.c
+++ b/drivers/acpi/pmic/intel_pmic_bxtwc.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
- * intel_pmic_bxtwc.c - Intel BXT WhiskeyCove PMIC operation region driver
+ * Intel BXT WhiskeyCove PMIC operation region driver
*
* Copyright (C) 2015 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/init.h>
diff --git a/drivers/acpi/pmic/intel_pmic_chtdc_ti.c b/drivers/acpi/pmic/intel_pmic_chtdc_ti.c
index f6d73a243d80..7ccd7d9660bc 100644
--- a/drivers/acpi/pmic/intel_pmic_chtdc_ti.c
+++ b/drivers/acpi/pmic/intel_pmic_chtdc_ti.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Dollar Cove TI PMIC operation region driver
* Copyright (C) 2014 Intel Corporation. All rights reserved.
diff --git a/drivers/acpi/pmic/intel_pmic_chtwc.c b/drivers/acpi/pmic/intel_pmic_chtwc.c
index 9912422c8185..078b0448f30a 100644
--- a/drivers/acpi/pmic/intel_pmic_chtwc.c
+++ b/drivers/acpi/pmic/intel_pmic_chtwc.c
@@ -1,18 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Intel CHT Whiskey Cove PMIC operation region driver
* Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
*
* Based on various non upstream patches to support the CHT Whiskey Cove PMIC:
* Copyright (C) 2013-2015 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/acpi.h>
diff --git a/drivers/acpi/pmic/intel_pmic_crc.c b/drivers/acpi/pmic/intel_pmic_crc.c
index 22c9e374c923..a0f411a6e5ac 100644
--- a/drivers/acpi/pmic/intel_pmic_crc.c
+++ b/drivers/acpi/pmic/intel_pmic_crc.c
@@ -1,23 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
/*
- * intel_pmic_crc.c - Intel CrystalCove PMIC operation region driver
+ * Intel CrystalCove PMIC operation region driver
*
* Copyright (C) 2014 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.
*/
-#include <linux/init.h>
#include <linux/acpi.h>
+#include <linux/init.h>
#include <linux/mfd/intel_soc_pmic.h>
-#include <linux/regmap.h>
#include <linux/platform_device.h>
+#include <linux/regmap.h>
#include "intel_pmic.h"
#define PWR_SOURCE_SELECT BIT(1)
diff --git a/drivers/acpi/pmic/intel_pmic_xpower.c b/drivers/acpi/pmic/intel_pmic_xpower.c
index 316e55174aa9..2579675b7082 100644
--- a/drivers/acpi/pmic/intel_pmic_xpower.c
+++ b/drivers/acpi/pmic/intel_pmic_xpower.c
@@ -1,23 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0
/*
- * intel_pmic_xpower.c - XPower AXP288 PMIC operation region driver
+ * XPower AXP288 PMIC operation region driver
*
* Copyright (C) 2014 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.
*/
-#include <linux/init.h>
#include <linux/acpi.h>
+#include <linux/init.h>
#include <linux/mfd/axp20x.h>
#include <linux/regmap.h>
#include <linux/platform_device.h>
+#include <asm/iosf_mbi.h>
#include "intel_pmic.h"
#define XPOWER_GPADC_LOW 0x5b
@@ -180,15 +173,21 @@ static int intel_xpower_pmic_get_power(struct regmap *regmap, int reg,
static int intel_xpower_pmic_update_power(struct regmap *regmap, int reg,
int bit, bool on)
{
- int data;
+ int data, ret;
/* GPIO1 LDO regulator needs special handling */
if (reg == XPOWER_GPI1_CTRL)
return regmap_update_bits(regmap, reg, GPI1_LDO_MASK,
on ? GPI1_LDO_ON : GPI1_LDO_OFF);
- if (regmap_read(regmap, reg, &data))
- return -EIO;
+ ret = iosf_mbi_block_punit_i2c_access();
+ if (ret)
+ return ret;
+
+ if (regmap_read(regmap, reg, &data)) {
+ ret = -EIO;
+ goto out;
+ }
if (on)
data |= BIT(bit);
@@ -196,9 +195,11 @@ static int intel_xpower_pmic_update_power(struct regmap *regmap, int reg,
data &= ~BIT(bit);
if (regmap_write(regmap, reg, data))
- return -EIO;
+ ret = -EIO;
+out:
+ iosf_mbi_unblock_punit_i2c_access();
- return 0;
+ return ret;
}
/**
diff --git a/drivers/acpi/pmic/tps68470_pmic.c b/drivers/acpi/pmic/tps68470_pmic.c
index a083de507009..ebd03e472955 100644
--- a/drivers/acpi/pmic/tps68470_pmic.c
+++ b/drivers/acpi/pmic/tps68470_pmic.c
@@ -10,8 +10,8 @@
*/
#include <linux/acpi.h>
-#include <linux/mfd/tps68470.h>
#include <linux/init.h>
+#include <linux/mfd/tps68470.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
diff --git a/drivers/acpi/pptt.c b/drivers/acpi/pptt.c
index d1e26cb599bf..da031b1df6f5 100644
--- a/drivers/acpi/pptt.c
+++ b/drivers/acpi/pptt.c
@@ -338,9 +338,6 @@ static struct acpi_pptt_cache *acpi_find_cache_node(struct acpi_table_header *ta
return found;
}
-/* total number of attributes checked by the properties code */
-#define PPTT_CHECKED_ATTRIBUTES 4
-
/**
* update_cache_properties() - Update cacheinfo for the given processor
* @this_leaf: Kernel cache info structure being updated
@@ -357,25 +354,15 @@ static void update_cache_properties(struct cacheinfo *this_leaf,
struct acpi_pptt_cache *found_cache,
struct acpi_pptt_processor *cpu_node)
{
- int valid_flags = 0;
-
this_leaf->fw_token = cpu_node;
- if (found_cache->flags & ACPI_PPTT_SIZE_PROPERTY_VALID) {
+ if (found_cache->flags & ACPI_PPTT_SIZE_PROPERTY_VALID)
this_leaf->size = found_cache->size;
- valid_flags++;
- }
- if (found_cache->flags & ACPI_PPTT_LINE_SIZE_VALID) {
+ if (found_cache->flags & ACPI_PPTT_LINE_SIZE_VALID)
this_leaf->coherency_line_size = found_cache->line_size;
- valid_flags++;
- }
- if (found_cache->flags & ACPI_PPTT_NUMBER_OF_SETS_VALID) {
+ if (found_cache->flags & ACPI_PPTT_NUMBER_OF_SETS_VALID)
this_leaf->number_of_sets = found_cache->number_of_sets;
- valid_flags++;
- }
- if (found_cache->flags & ACPI_PPTT_ASSOCIATIVITY_VALID) {
+ if (found_cache->flags & ACPI_PPTT_ASSOCIATIVITY_VALID)
this_leaf->ways_of_associativity = found_cache->associativity;
- valid_flags++;
- }
if (found_cache->flags & ACPI_PPTT_WRITE_POLICY_VALID) {
switch (found_cache->attributes & ACPI_PPTT_MASK_WRITE_POLICY) {
case ACPI_PPTT_CACHE_POLICY_WT:
@@ -402,11 +389,17 @@ static void update_cache_properties(struct cacheinfo *this_leaf,
}
}
/*
- * If the above flags are valid, and the cache type is NOCACHE
- * update the cache type as well.
+ * If cache type is NOCACHE, then the cache hasn't been specified
+ * via other mechanisms. Update the type if a cache type has been
+ * provided.
+ *
+ * Note, we assume such caches are unified based on conventional system
+ * design and known examples. Significant work is required elsewhere to
+ * fully support data/instruction only type caches which are only
+ * specified in PPTT.
*/
if (this_leaf->type == CACHE_TYPE_NOCACHE &&
- valid_flags == PPTT_CHECKED_ATTRIBUTES)
+ found_cache->flags & ACPI_PPTT_CACHE_TYPE_VALID)
this_leaf->type = CACHE_TYPE_UNIFIED;
}
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index abb559cd28d7..b2131c4ea124 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -205,6 +205,7 @@ static void lapic_timer_state_broadcast(struct acpi_processor *pr,
static void tsc_check_state(int state)
{
switch (boot_cpu_data.x86_vendor) {
+ case X86_VENDOR_HYGON:
case X86_VENDOR_AMD:
case X86_VENDOR_INTEL:
case X86_VENDOR_CENTAUR:
diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c
index 693cf05b0cc4..8c7c4583b52d 100644
--- a/drivers/acpi/property.c
+++ b/drivers/acpi/property.c
@@ -24,11 +24,15 @@ static int acpi_data_get_property_array(const struct acpi_device_data *data,
acpi_object_type type,
const union acpi_object **obj);
-/* ACPI _DSD device properties GUID: daffd814-6eba-4d8c-8a91-bc9bbf4aa301 */
-static const guid_t prp_guid =
+static const guid_t prp_guids[] = {
+ /* ACPI _DSD device properties GUID: daffd814-6eba-4d8c-8a91-bc9bbf4aa301 */
GUID_INIT(0xdaffd814, 0x6eba, 0x4d8c,
- 0x8a, 0x91, 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x01);
-/* ACPI _DSD data subnodes GUID: dbb8e3e6-5886-4ba6-8795-1319f52a966b */
+ 0x8a, 0x91, 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x01),
+ /* Hotplug in D3 GUID: 6211e2c0-58a3-4af3-90e1-927a4e0c55a4 */
+ GUID_INIT(0x6211e2c0, 0x58a3, 0x4af3,
+ 0x90, 0xe1, 0x92, 0x7a, 0x4e, 0x0c, 0x55, 0xa4),
+};
+
static const guid_t ads_guid =
GUID_INIT(0xdbb8e3e6, 0x5886, 0x4ba6,
0x87, 0x95, 0x13, 0x19, 0xf5, 0x2a, 0x96, 0x6b);
@@ -56,6 +60,7 @@ static bool acpi_nondev_subnode_extract(const union acpi_object *desc,
dn->name = link->package.elements[0].string.pointer;
dn->fwnode.ops = &acpi_data_fwnode_ops;
dn->parent = parent;
+ INIT_LIST_HEAD(&dn->data.properties);
INIT_LIST_HEAD(&dn->data.subnodes);
result = acpi_extract_properties(desc, &dn->data);
@@ -288,6 +293,35 @@ static void acpi_init_of_compatible(struct acpi_device *adev)
adev->flags.of_compatible_ok = 1;
}
+static bool acpi_is_property_guid(const guid_t *guid)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(prp_guids); i++) {
+ if (guid_equal(guid, &prp_guids[i]))
+ return true;
+ }
+
+ return false;
+}
+
+struct acpi_device_properties *
+acpi_data_add_props(struct acpi_device_data *data, const guid_t *guid,
+ const union acpi_object *properties)
+{
+ struct acpi_device_properties *props;
+
+ props = kzalloc(sizeof(*props), GFP_KERNEL);
+ if (props) {
+ INIT_LIST_HEAD(&props->list);
+ props->guid = guid;
+ props->properties = properties;
+ list_add_tail(&props->list, &data->properties);
+ }
+
+ return props;
+}
+
static bool acpi_extract_properties(const union acpi_object *desc,
struct acpi_device_data *data)
{
@@ -312,7 +346,7 @@ static bool acpi_extract_properties(const union acpi_object *desc,
properties->type != ACPI_TYPE_PACKAGE)
break;
- if (!guid_equal((guid_t *)guid->buffer.pointer, &prp_guid))
+ if (!acpi_is_property_guid((guid_t *)guid->buffer.pointer))
continue;
/*
@@ -320,13 +354,13 @@ static bool acpi_extract_properties(const union acpi_object *desc,
* package immediately following it.
*/
if (!acpi_properties_format_valid(properties))
- break;
+ continue;
- data->properties = properties;
- return true;
+ acpi_data_add_props(data, (const guid_t *)guid->buffer.pointer,
+ properties);
}
- return false;
+ return !list_empty(&data->properties);
}
void acpi_init_properties(struct acpi_device *adev)
@@ -336,6 +370,7 @@ void acpi_init_properties(struct acpi_device *adev)
acpi_status status;
bool acpi_of = false;
+ INIT_LIST_HEAD(&adev->data.properties);
INIT_LIST_HEAD(&adev->data.subnodes);
if (!adev->handle)
@@ -398,11 +433,16 @@ static void acpi_destroy_nondev_subnodes(struct list_head *list)
void acpi_free_properties(struct acpi_device *adev)
{
+ struct acpi_device_properties *props, *tmp;
+
acpi_destroy_nondev_subnodes(&adev->data.subnodes);
ACPI_FREE((void *)adev->data.pointer);
adev->data.of_compatible = NULL;
adev->data.pointer = NULL;
- adev->data.properties = NULL;
+ list_for_each_entry_safe(props, tmp, &adev->data.properties, list) {
+ list_del(&props->list);
+ kfree(props);
+ }
}
/**
@@ -427,32 +467,37 @@ static int acpi_data_get_property(const struct acpi_device_data *data,
const char *name, acpi_object_type type,
const union acpi_object **obj)
{
- const union acpi_object *properties;
- int i;
+ const struct acpi_device_properties *props;
if (!data || !name)
return -EINVAL;
- if (!data->pointer || !data->properties)
+ if (!data->pointer || list_empty(&data->properties))
return -EINVAL;
- properties = data->properties;
- for (i = 0; i < properties->package.count; i++) {
- const union acpi_object *propname, *propvalue;
- const union acpi_object *property;
+ list_for_each_entry(props, &data->properties, list) {
+ const union acpi_object *properties;
+ unsigned int i;
- property = &properties->package.elements[i];
+ properties = props->properties;
+ for (i = 0; i < properties->package.count; i++) {
+ const union acpi_object *propname, *propvalue;
+ const union acpi_object *property;
- propname = &property->package.elements[0];
- propvalue = &property->package.elements[1];
+ property = &properties->package.elements[i];
- if (!strcmp(name, propname->string.pointer)) {
- if (type != ACPI_TYPE_ANY && propvalue->type != type)
- return -EPROTO;
- if (obj)
- *obj = propvalue;
+ propname = &property->package.elements[0];
+ propvalue = &property->package.elements[1];
- return 0;
+ if (!strcmp(name, propname->string.pointer)) {
+ if (type != ACPI_TYPE_ANY &&
+ propvalue->type != type)
+ return -EPROTO;
+ if (obj)
+ *obj = propvalue;
+
+ return 0;
+ }
}
}
return -EINVAL;
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index 295b59271189..96c5e27967f4 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -441,9 +441,13 @@ static int acpi_ac_get_present(struct acpi_sbs *sbs)
/*
* The spec requires that bit 4 always be 1. If it's not set, assume
- * that the implementation doesn't support an SBS charger
+ * that the implementation doesn't support an SBS charger.
+ *
+ * And on some MacBooks a status of 0xffff is always returned, no
+ * matter whether the charger is plugged in or not, which is also
+ * wrong, so ignore the SBS charger for those too.
*/
- if (!((status >> 4) & 0x1))
+ if (!((status >> 4) & 0x1) || status == 0xffff)
return -ENODEV;
sbs->charger_present = (status >> 15) & 0x1;
diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c
index 7a3431018e0a..5008ead4609a 100644
--- a/drivers/acpi/sbshc.c
+++ b/drivers/acpi/sbshc.c
@@ -196,6 +196,7 @@ int acpi_smbus_unregister_callback(struct acpi_smb_hc *hc)
hc->callback = NULL;
hc->context = NULL;
mutex_unlock(&hc->lock);
+ acpi_os_wait_events_complete();
return 0;
}
@@ -292,6 +293,7 @@ static int acpi_smbus_hc_remove(struct acpi_device *device)
hc = acpi_driver_data(device);
acpi_ec_remove_query_handler(hc->ec, hc->query_bit);
+ acpi_os_wait_events_complete();
kfree(hc);
device->driver_data = NULL;
return 0;
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index e1b6231cfa1c..bd1c59fb0e17 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -1469,16 +1469,6 @@ int acpi_dma_configure(struct device *dev, enum dev_dma_attr attr)
}
EXPORT_SYMBOL_GPL(acpi_dma_configure);
-/**
- * acpi_dma_deconfigure - Tear-down DMA configuration for the device.
- * @dev: The pointer to the device
- */
-void acpi_dma_deconfigure(struct device *dev)
-{
- arch_teardown_dma_ops(dev);
-}
-EXPORT_SYMBOL_GPL(acpi_dma_deconfigure);
-
static void acpi_init_coherency(struct acpi_device *adev)
{
unsigned long long cca = 0;
@@ -1550,6 +1540,7 @@ static bool acpi_device_enumeration_by_parent(struct acpi_device *device)
*/
static const struct acpi_device_id i2c_multi_instantiate_ids[] = {
{"BSG1160", },
+ {"INT33FE", },
{}
};
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index a3d012b08fc5..61203eebf3a1 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -31,9 +31,8 @@
#include <linux/irq.h>
#include <linux/errno.h>
#include <linux/acpi.h>
-#include <linux/bootmem.h>
-#include <linux/earlycpio.h>
#include <linux/memblock.h>
+#include <linux/earlycpio.h>
#include <linux/initrd.h>
#include "internal.h"
diff --git a/drivers/acpi/x86/apple.c b/drivers/acpi/x86/apple.c
index 51b4cf9f25da..b7c98ff82d78 100644
--- a/drivers/acpi/x86/apple.c
+++ b/drivers/acpi/x86/apple.c
@@ -62,7 +62,7 @@ void acpi_extract_apple_properties(struct acpi_device *adev)
if (!numprops)
goto out_free;
- valid = kcalloc(BITS_TO_LONGS(numprops), sizeof(long), GFP_KERNEL);
+ valid = bitmap_zalloc(numprops, GFP_KERNEL);
if (!valid)
goto out_free;
@@ -132,10 +132,10 @@ void acpi_extract_apple_properties(struct acpi_device *adev)
}
WARN_ON(free_space != (void *)newprops + newsize);
- adev->data.properties = newprops;
adev->data.pointer = newprops;
+ acpi_data_add_props(&adev->data, &apple_prp_guid, newprops);
out_free:
ACPI_FREE(props);
- kfree(valid);
+ bitmap_free(valid);
}
diff --git a/drivers/acpi/x86/utils.c b/drivers/acpi/x86/utils.c
index 06c31ec3cc70..9a8e286dd86f 100644
--- a/drivers/acpi/x86/utils.c
+++ b/drivers/acpi/x86/utils.c
@@ -54,7 +54,7 @@ static const struct always_present_id always_present_ids[] = {
* Bay / Cherry Trail PWM directly poked by GPU driver in win10,
* but Linux uses a separate PWM driver, harmless if not used.
*/
- ENTRY("80860F09", "1", ICPU(INTEL_FAM6_ATOM_SILVERMONT1), {}),
+ ENTRY("80860F09", "1", ICPU(INTEL_FAM6_ATOM_SILVERMONT), {}),
ENTRY("80862288", "1", ICPU(INTEL_FAM6_ATOM_AIRMONT), {}),
/*
* The INT0002 device is necessary to clear wakeup interrupt sources
diff --git a/drivers/android/Kconfig b/drivers/android/Kconfig
index 432e9ad77070..51e8250d113f 100644
--- a/drivers/android/Kconfig
+++ b/drivers/android/Kconfig
@@ -10,7 +10,7 @@ if ANDROID
config ANDROID_BINDER_IPC
bool "Android Binder IPC Driver"
- depends on MMU
+ depends on MMU && !CPU_CACHE_VIVT
default n
---help---
Binder is used in Android for both communication between processes,
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index d58763b6b009..cb30a524d16d 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -71,6 +71,7 @@
#include <linux/security.h>
#include <linux/spinlock.h>
#include <linux/ratelimit.h>
+#include <linux/syscalls.h>
#include <uapi/linux/android/binder.h>
@@ -457,9 +458,8 @@ struct binder_ref {
};
enum binder_deferred_state {
- BINDER_DEFERRED_PUT_FILES = 0x01,
- BINDER_DEFERRED_FLUSH = 0x02,
- BINDER_DEFERRED_RELEASE = 0x04,
+ BINDER_DEFERRED_FLUSH = 0x01,
+ BINDER_DEFERRED_RELEASE = 0x02,
};
/**
@@ -480,9 +480,6 @@ enum binder_deferred_state {
* (invariant after initialized)
* @tsk task_struct for group_leader of process
* (invariant after initialized)
- * @files files_struct for process
- * (protected by @files_lock)
- * @files_lock mutex to protect @files
* @deferred_work_node: element for binder_deferred_list
* (protected by binder_deferred_lock)
* @deferred_work: bitmap of deferred work to perform
@@ -527,8 +524,6 @@ struct binder_proc {
struct list_head waiting_threads;
int pid;
struct task_struct *tsk;
- struct files_struct *files;
- struct mutex files_lock;
struct hlist_node deferred_work_node;
int deferred_work;
bool is_dead;
@@ -611,6 +606,23 @@ struct binder_thread {
bool is_dead;
};
+/**
+ * struct binder_txn_fd_fixup - transaction fd fixup list element
+ * @fixup_entry: list entry
+ * @file: struct file to be associated with new fd
+ * @offset: offset in buffer data to this fixup
+ *
+ * List element for fd fixups in a transaction. Since file
+ * descriptors need to be allocated in the context of the
+ * target process, we pass each fd to be processed in this
+ * struct.
+ */
+struct binder_txn_fd_fixup {
+ struct list_head fixup_entry;
+ struct file *file;
+ size_t offset;
+};
+
struct binder_transaction {
int debug_id;
struct binder_work work;
@@ -628,6 +640,7 @@ struct binder_transaction {
long priority;
long saved_priority;
kuid_t sender_euid;
+ struct list_head fd_fixups;
/**
* @lock: protects @from, @to_proc, and @to_thread
*
@@ -822,6 +835,7 @@ static void
binder_enqueue_deferred_thread_work_ilocked(struct binder_thread *thread,
struct binder_work *work)
{
+ WARN_ON(!list_empty(&thread->waiting_thread_node));
binder_enqueue_work_ilocked(work, &thread->todo);
}
@@ -839,6 +853,7 @@ static void
binder_enqueue_thread_work_ilocked(struct binder_thread *thread,
struct binder_work *work)
{
+ WARN_ON(!list_empty(&thread->waiting_thread_node));
binder_enqueue_work_ilocked(work, &thread->todo);
thread->process_todo = true;
}
@@ -920,66 +935,6 @@ static void binder_free_thread(struct binder_thread *thread);
static void binder_free_proc(struct binder_proc *proc);
static void binder_inc_node_tmpref_ilocked(struct binder_node *node);
-static int task_get_unused_fd_flags(struct binder_proc *proc, int flags)
-{
- unsigned long rlim_cur;
- unsigned long irqs;
- int ret;
-
- mutex_lock(&proc->files_lock);
- if (proc->files == NULL) {
- ret = -ESRCH;
- goto err;
- }
- if (!lock_task_sighand(proc->tsk, &irqs)) {
- ret = -EMFILE;
- goto err;
- }
- rlim_cur = task_rlimit(proc->tsk, RLIMIT_NOFILE);
- unlock_task_sighand(proc->tsk, &irqs);
-
- ret = __alloc_fd(proc->files, 0, rlim_cur, flags);
-err:
- mutex_unlock(&proc->files_lock);
- return ret;
-}
-
-/*
- * copied from fd_install
- */
-static void task_fd_install(
- struct binder_proc *proc, unsigned int fd, struct file *file)
-{
- mutex_lock(&proc->files_lock);
- if (proc->files)
- __fd_install(proc->files, fd, file);
- mutex_unlock(&proc->files_lock);
-}
-
-/*
- * copied from sys_close
- */
-static long task_close_fd(struct binder_proc *proc, unsigned int fd)
-{
- int retval;
-
- mutex_lock(&proc->files_lock);
- if (proc->files == NULL) {
- retval = -ESRCH;
- goto err;
- }
- retval = __close_fd(proc->files, fd);
- /* can't restart close syscall because file table entry was cleared */
- if (unlikely(retval == -ERESTARTSYS ||
- retval == -ERESTARTNOINTR ||
- retval == -ERESTARTNOHAND ||
- retval == -ERESTART_RESTARTBLOCK))
- retval = -EINTR;
-err:
- mutex_unlock(&proc->files_lock);
- return retval;
-}
-
static bool binder_has_work_ilocked(struct binder_thread *thread,
bool do_proc_work)
{
@@ -1270,19 +1225,12 @@ static int binder_inc_node_nilocked(struct binder_node *node, int strong,
} else
node->local_strong_refs++;
if (!node->has_strong_ref && target_list) {
+ struct binder_thread *thread = container_of(target_list,
+ struct binder_thread, todo);
binder_dequeue_work_ilocked(&node->work);
- /*
- * Note: this function is the only place where we queue
- * directly to a thread->todo without using the
- * corresponding binder_enqueue_thread_work() helper
- * functions; in this case it's ok to not set the
- * process_todo flag, since we know this node work will
- * always be followed by other work that starts queue
- * processing: in case of synchronous transactions, a
- * BR_REPLY or BR_ERROR; in case of oneway
- * transactions, a BR_TRANSACTION_COMPLETE.
- */
- binder_enqueue_work_ilocked(&node->work, target_list);
+ BUG_ON(&thread->todo != target_list);
+ binder_enqueue_deferred_thread_work_ilocked(thread,
+ &node->work);
}
} else {
if (!internal)
@@ -1958,10 +1906,32 @@ static struct binder_thread *binder_get_txn_from_and_acq_inner(
return NULL;
}
+/**
+ * binder_free_txn_fixups() - free unprocessed fd fixups
+ * @t: binder transaction for t->from
+ *
+ * If the transaction is being torn down prior to being
+ * processed by the target process, free all of the
+ * fd fixups and fput the file structs. It is safe to
+ * call this function after the fixups have been
+ * processed -- in that case, the list will be empty.
+ */
+static void binder_free_txn_fixups(struct binder_transaction *t)
+{
+ struct binder_txn_fd_fixup *fixup, *tmp;
+
+ list_for_each_entry_safe(fixup, tmp, &t->fd_fixups, fixup_entry) {
+ fput(fixup->file);
+ list_del(&fixup->fixup_entry);
+ kfree(fixup);
+ }
+}
+
static void binder_free_transaction(struct binder_transaction *t)
{
if (t->buffer)
t->buffer->transaction = NULL;
+ binder_free_txn_fixups(t);
kfree(t);
binder_stats_deleted(BINDER_STAT_TRANSACTION);
}
@@ -2262,12 +2232,17 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
} break;
case BINDER_TYPE_FD: {
- struct binder_fd_object *fp = to_binder_fd_object(hdr);
-
- binder_debug(BINDER_DEBUG_TRANSACTION,
- " fd %d\n", fp->fd);
- if (failed_at)
- task_close_fd(proc, fp->fd);
+ /*
+ * No need to close the file here since user-space
+ * closes it for for successfully delivered
+ * transactions. For transactions that weren't
+ * delivered, the new fd was never allocated so
+ * there is no need to close and the fput on the
+ * file is done when the transaction is torn
+ * down.
+ */
+ WARN_ON(failed_at &&
+ proc->tsk == current->group_leader);
} break;
case BINDER_TYPE_PTR:
/*
@@ -2283,6 +2258,15 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
size_t fd_index;
binder_size_t fd_buf_size;
+ if (proc->tsk != current->group_leader) {
+ /*
+ * Nothing to do if running in sender context
+ * The fd fixups have not been applied so no
+ * fds need to be closed.
+ */
+ continue;
+ }
+
fda = to_binder_fd_array_object(hdr);
parent = binder_validate_ptr(buffer, fda->parent,
off_start,
@@ -2315,7 +2299,7 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
}
fd_array = (u32 *)(parent_buffer + (uintptr_t)fda->parent_offset);
for (fd_index = 0; fd_index < fda->num_fds; fd_index++)
- task_close_fd(proc, fd_array[fd_index]);
+ ksys_close(fd_array[fd_index]);
} break;
default:
pr_err("transaction release %d bad object type %x\n",
@@ -2447,17 +2431,18 @@ done:
return ret;
}
-static int binder_translate_fd(int fd,
+static int binder_translate_fd(u32 *fdp,
struct binder_transaction *t,
struct binder_thread *thread,
struct binder_transaction *in_reply_to)
{
struct binder_proc *proc = thread->proc;
struct binder_proc *target_proc = t->to_proc;
- int target_fd;
+ struct binder_txn_fd_fixup *fixup;
struct file *file;
- int ret;
+ int ret = 0;
bool target_allows_fd;
+ int fd = *fdp;
if (in_reply_to)
target_allows_fd = !!(in_reply_to->flags & TF_ACCEPT_FDS);
@@ -2485,19 +2470,24 @@ static int binder_translate_fd(int fd,
goto err_security;
}
- target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC);
- if (target_fd < 0) {
+ /*
+ * Add fixup record for this transaction. The allocation
+ * of the fd in the target needs to be done from a
+ * target thread.
+ */
+ fixup = kzalloc(sizeof(*fixup), GFP_KERNEL);
+ if (!fixup) {
ret = -ENOMEM;
- goto err_get_unused_fd;
+ goto err_alloc;
}
- task_fd_install(target_proc, target_fd, file);
- trace_binder_transaction_fd(t, fd, target_fd);
- binder_debug(BINDER_DEBUG_TRANSACTION, " fd %d -> %d\n",
- fd, target_fd);
+ fixup->file = file;
+ fixup->offset = (uintptr_t)fdp - (uintptr_t)t->buffer->data;
+ trace_binder_transaction_fd_send(t, fd, fixup->offset);
+ list_add_tail(&fixup->fixup_entry, &t->fd_fixups);
- return target_fd;
+ return ret;
-err_get_unused_fd:
+err_alloc:
err_security:
fput(file);
err_fget:
@@ -2511,8 +2501,7 @@ static int binder_translate_fd_array(struct binder_fd_array_object *fda,
struct binder_thread *thread,
struct binder_transaction *in_reply_to)
{
- binder_size_t fdi, fd_buf_size, num_installed_fds;
- int target_fd;
+ binder_size_t fdi, fd_buf_size;
uintptr_t parent_buffer;
u32 *fd_array;
struct binder_proc *proc = thread->proc;
@@ -2544,23 +2533,12 @@ static int binder_translate_fd_array(struct binder_fd_array_object *fda,
return -EINVAL;
}
for (fdi = 0; fdi < fda->num_fds; fdi++) {
- target_fd = binder_translate_fd(fd_array[fdi], t, thread,
+ int ret = binder_translate_fd(&fd_array[fdi], t, thread,
in_reply_to);
- if (target_fd < 0)
- goto err_translate_fd_failed;
- fd_array[fdi] = target_fd;
+ if (ret < 0)
+ return ret;
}
return 0;
-
-err_translate_fd_failed:
- /*
- * Failed to allocate fd or security error, free fds
- * installed so far.
- */
- num_installed_fds = fdi;
- for (fdi = 0; fdi < num_installed_fds; fdi++)
- task_close_fd(target_proc, fd_array[fdi]);
- return target_fd;
}
static int binder_fixup_parent(struct binder_transaction *t,
@@ -2723,6 +2701,7 @@ static void binder_transaction(struct binder_proc *proc,
{
int ret;
struct binder_transaction *t;
+ struct binder_work *w;
struct binder_work *tcomplete;
binder_size_t *offp, *off_end, *off_start;
binder_size_t off_min;
@@ -2864,6 +2843,29 @@ static void binder_transaction(struct binder_proc *proc,
goto err_invalid_target_handle;
}
binder_inner_proc_lock(proc);
+
+ w = list_first_entry_or_null(&thread->todo,
+ struct binder_work, entry);
+ if (!(tr->flags & TF_ONE_WAY) && w &&
+ w->type == BINDER_WORK_TRANSACTION) {
+ /*
+ * Do not allow new outgoing transaction from a
+ * thread that has a transaction at the head of
+ * its todo list. Only need to check the head
+ * because binder_select_thread_ilocked picks a
+ * thread from proc->waiting_threads to enqueue
+ * the transaction, and nothing is queued to the
+ * todo list while the thread is on waiting_threads.
+ */
+ binder_user_error("%d:%d new transaction not allowed when there is a transaction on thread todo\n",
+ proc->pid, thread->pid);
+ binder_inner_proc_unlock(proc);
+ return_error = BR_FAILED_REPLY;
+ return_error_param = -EPROTO;
+ return_error_line = __LINE__;
+ goto err_bad_todo_list;
+ }
+
if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) {
struct binder_transaction *tmp;
@@ -2911,6 +2913,7 @@ static void binder_transaction(struct binder_proc *proc,
return_error_line = __LINE__;
goto err_alloc_t_failed;
}
+ INIT_LIST_HEAD(&t->fd_fixups);
binder_stats_created(BINDER_STAT_TRANSACTION);
spin_lock_init(&t->lock);
@@ -3066,17 +3069,16 @@ static void binder_transaction(struct binder_proc *proc,
case BINDER_TYPE_FD: {
struct binder_fd_object *fp = to_binder_fd_object(hdr);
- int target_fd = binder_translate_fd(fp->fd, t, thread,
- in_reply_to);
+ int ret = binder_translate_fd(&fp->fd, t, thread,
+ in_reply_to);
- if (target_fd < 0) {
+ if (ret < 0) {
return_error = BR_FAILED_REPLY;
- return_error_param = target_fd;
+ return_error_param = ret;
return_error_line = __LINE__;
goto err_translate_failed;
}
fp->pad_binder = 0;
- fp->fd = target_fd;
} break;
case BINDER_TYPE_FDA: {
struct binder_fd_array_object *fda =
@@ -3233,6 +3235,7 @@ err_bad_object_type:
err_bad_offset:
err_bad_parent:
err_copy_data_failed:
+ binder_free_txn_fixups(t);
trace_binder_transaction_failed_buffer_release(t->buffer);
binder_transaction_buffer_release(target_proc, t->buffer, offp);
if (target_node)
@@ -3247,6 +3250,7 @@ err_alloc_tcomplete_failed:
kfree(t);
binder_stats_deleted(BINDER_STAT_TRANSACTION);
err_alloc_t_failed:
+err_bad_todo_list:
err_bad_call_stack:
err_empty_call_stack:
err_dead_binder:
@@ -3294,6 +3298,47 @@ err_invalid_target_handle:
}
}
+/**
+ * binder_free_buf() - free the specified buffer
+ * @proc: binder proc that owns buffer
+ * @buffer: buffer to be freed
+ *
+ * If buffer for an async transaction, enqueue the next async
+ * transaction from the node.
+ *
+ * Cleanup buffer and free it.
+ */
+static void
+binder_free_buf(struct binder_proc *proc, struct binder_buffer *buffer)
+{
+ if (buffer->transaction) {
+ buffer->transaction->buffer = NULL;
+ buffer->transaction = NULL;
+ }
+ if (buffer->async_transaction && buffer->target_node) {
+ struct binder_node *buf_node;
+ struct binder_work *w;
+
+ buf_node = buffer->target_node;
+ binder_node_inner_lock(buf_node);
+ BUG_ON(!buf_node->has_async_transaction);
+ BUG_ON(buf_node->proc != proc);
+ w = binder_dequeue_work_head_ilocked(
+ &buf_node->async_todo);
+ if (!w) {
+ buf_node->has_async_transaction = false;
+ } else {
+ binder_enqueue_work_ilocked(
+ w, &proc->todo);
+ binder_wakeup_proc_ilocked(proc);
+ }
+ binder_node_inner_unlock(buf_node);
+ }
+ trace_binder_transaction_buffer_release(buffer);
+ binder_transaction_buffer_release(proc, buffer, NULL);
+ binder_alloc_free_buf(&proc->alloc, buffer);
+}
+
static int binder_thread_write(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer, size_t size,
@@ -3480,33 +3525,7 @@ static int binder_thread_write(struct binder_proc *proc,
proc->pid, thread->pid, (u64)data_ptr,
buffer->debug_id,
buffer->transaction ? "active" : "finished");
-
- if (buffer->transaction) {
- buffer->transaction->buffer = NULL;
- buffer->transaction = NULL;
- }
- if (buffer->async_transaction && buffer->target_node) {
- struct binder_node *buf_node;
- struct binder_work *w;
-
- buf_node = buffer->target_node;
- binder_node_inner_lock(buf_node);
- BUG_ON(!buf_node->has_async_transaction);
- BUG_ON(buf_node->proc != proc);
- w = binder_dequeue_work_head_ilocked(
- &buf_node->async_todo);
- if (!w) {
- buf_node->has_async_transaction = false;
- } else {
- binder_enqueue_work_ilocked(
- w, &proc->todo);
- binder_wakeup_proc_ilocked(proc);
- }
- binder_node_inner_unlock(buf_node);
- }
- trace_binder_transaction_buffer_release(buffer);
- binder_transaction_buffer_release(proc, buffer, NULL);
- binder_alloc_free_buf(&proc->alloc, buffer);
+ binder_free_buf(proc, buffer);
break;
}
@@ -3829,6 +3848,76 @@ static int binder_wait_for_work(struct binder_thread *thread,
return ret;
}
+/**
+ * binder_apply_fd_fixups() - finish fd translation
+ * @t: binder transaction with list of fd fixups
+ *
+ * Now that we are in the context of the transaction target
+ * process, we can allocate and install fds. Process the
+ * list of fds to translate and fixup the buffer with the
+ * new fds.
+ *
+ * If we fail to allocate an fd, then free the resources by
+ * fput'ing files that have not been processed and ksys_close'ing
+ * any fds that have already been allocated.
+ */
+static int binder_apply_fd_fixups(struct binder_transaction *t)
+{
+ struct binder_txn_fd_fixup *fixup, *tmp;
+ int ret = 0;
+
+ list_for_each_entry(fixup, &t->fd_fixups, fixup_entry) {
+ int fd = get_unused_fd_flags(O_CLOEXEC);
+ u32 *fdp;
+
+ if (fd < 0) {
+ binder_debug(BINDER_DEBUG_TRANSACTION,
+ "failed fd fixup txn %d fd %d\n",
+ t->debug_id, fd);
+ ret = -ENOMEM;
+ break;
+ }
+ binder_debug(BINDER_DEBUG_TRANSACTION,
+ "fd fixup txn %d fd %d\n",
+ t->debug_id, fd);
+ trace_binder_transaction_fd_recv(t, fd, fixup->offset);
+ fd_install(fd, fixup->file);
+ fixup->file = NULL;
+ fdp = (u32 *)(t->buffer->data + fixup->offset);
+ /*
+ * This store can cause problems for CPUs with a
+ * VIVT cache (eg ARMv5) since the cache cannot
+ * detect virtual aliases to the same physical cacheline.
+ * To support VIVT, this address and the user-space VA
+ * would both need to be flushed. Since this kernel
+ * VA is not constructed via page_to_virt(), we can't
+ * use flush_dcache_page() on it, so we'd have to use
+ * an internal function. If devices with VIVT ever
+ * need to run Android, we'll either need to go back
+ * to patching the translated fd from the sender side
+ * (using the non-standard kernel functions), or rework
+ * how the kernel uses the buffer to use page_to_virt()
+ * addresses instead of allocating in our own vm area.
+ *
+ * For now, we disable compilation if CONFIG_CPU_CACHE_VIVT.
+ */
+ *fdp = fd;
+ }
+ list_for_each_entry_safe(fixup, tmp, &t->fd_fixups, fixup_entry) {
+ if (fixup->file) {
+ fput(fixup->file);
+ } else if (ret) {
+ u32 *fdp = (u32 *)(t->buffer->data + fixup->offset);
+
+ ksys_close(*fdp);
+ }
+ list_del(&fixup->fixup_entry);
+ kfree(fixup);
+ }
+
+ return ret;
+}
+
static int binder_thread_read(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer, size_t size,
@@ -4110,6 +4199,34 @@ retry:
tr.sender_pid = 0;
}
+ ret = binder_apply_fd_fixups(t);
+ if (ret) {
+ struct binder_buffer *buffer = t->buffer;
+ bool oneway = !!(t->flags & TF_ONE_WAY);
+ int tid = t->debug_id;
+
+ if (t_from)
+ binder_thread_dec_tmpref(t_from);
+ buffer->transaction = NULL;
+ binder_cleanup_transaction(t, "fd fixups failed",
+ BR_FAILED_REPLY);
+ binder_free_buf(proc, buffer);
+ binder_debug(BINDER_DEBUG_FAILED_TRANSACTION,
+ "%d:%d %stransaction %d fd fixups failed %d/%d, line %d\n",
+ proc->pid, thread->pid,
+ oneway ? "async " :
+ (cmd == BR_REPLY ? "reply " : ""),
+ tid, BR_FAILED_REPLY, ret, __LINE__);
+ if (cmd == BR_REPLY) {
+ cmd = BR_FAILED_REPLY;
+ if (put_user(cmd, (uint32_t __user *)ptr))
+ return -EFAULT;
+ ptr += sizeof(uint32_t);
+ binder_stat_br(proc, thread, cmd);
+ break;
+ }
+ continue;
+ }
tr.data_size = t->buffer->data_size;
tr.offsets_size = t->buffer->offsets_size;
tr.data.ptr.buffer = (binder_uintptr_t)
@@ -4544,6 +4661,42 @@ out:
return ret;
}
+static int binder_ioctl_get_node_info_for_ref(struct binder_proc *proc,
+ struct binder_node_info_for_ref *info)
+{
+ struct binder_node *node;
+ struct binder_context *context = proc->context;
+ __u32 handle = info->handle;
+
+ if (info->strong_count || info->weak_count || info->reserved1 ||
+ info->reserved2 || info->reserved3) {
+ binder_user_error("%d BINDER_GET_NODE_INFO_FOR_REF: only handle may be non-zero.",
+ proc->pid);
+ return -EINVAL;
+ }
+
+ /* This ioctl may only be used by the context manager */
+ mutex_lock(&context->context_mgr_node_lock);
+ if (!context->binder_context_mgr_node ||
+ context->binder_context_mgr_node->proc != proc) {
+ mutex_unlock(&context->context_mgr_node_lock);
+ return -EPERM;
+ }
+ mutex_unlock(&context->context_mgr_node_lock);
+
+ node = binder_get_node_from_ref(proc, handle, true, NULL);
+ if (!node)
+ return -EINVAL;
+
+ info->strong_count = node->local_strong_refs +
+ node->internal_strong_refs;
+ info->weak_count = node->local_weak_refs;
+
+ binder_put_node(node);
+
+ return 0;
+}
+
static int binder_ioctl_get_node_debug_info(struct binder_proc *proc,
struct binder_node_debug_info *info)
{
@@ -4638,6 +4791,25 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
}
break;
}
+ case BINDER_GET_NODE_INFO_FOR_REF: {
+ struct binder_node_info_for_ref info;
+
+ if (copy_from_user(&info, ubuf, sizeof(info))) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ ret = binder_ioctl_get_node_info_for_ref(proc, &info);
+ if (ret < 0)
+ goto err;
+
+ if (copy_to_user(ubuf, &info, sizeof(info))) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ break;
+ }
case BINDER_GET_NODE_DEBUG_INFO: {
struct binder_node_debug_info info;
@@ -4693,7 +4865,6 @@ static void binder_vma_close(struct vm_area_struct *vma)
(vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags,
(unsigned long)pgprot_val(vma->vm_page_prot));
binder_alloc_vma_close(&proc->alloc);
- binder_defer_work(proc, BINDER_DEFERRED_PUT_FILES);
}
static vm_fault_t binder_vm_fault(struct vm_fault *vmf)
@@ -4739,9 +4910,6 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
ret = binder_alloc_mmap_handler(&proc->alloc, vma);
if (ret)
return ret;
- mutex_lock(&proc->files_lock);
- proc->files = get_files_struct(current);
- mutex_unlock(&proc->files_lock);
return 0;
err_bad_arg:
@@ -4765,7 +4933,6 @@ static int binder_open(struct inode *nodp, struct file *filp)
spin_lock_init(&proc->outer_lock);
get_task_struct(current->group_leader);
proc->tsk = current->group_leader;
- mutex_init(&proc->files_lock);
INIT_LIST_HEAD(&proc->todo);
proc->default_priority = task_nice(current);
binder_dev = container_of(filp->private_data, struct binder_device,
@@ -4915,8 +5082,6 @@ static void binder_deferred_release(struct binder_proc *proc)
struct rb_node *n;
int threads, nodes, incoming_refs, outgoing_refs, active_transactions;
- BUG_ON(proc->files);
-
mutex_lock(&binder_procs_lock);
hlist_del(&proc->proc_node);
mutex_unlock(&binder_procs_lock);
@@ -4998,7 +5163,6 @@ static void binder_deferred_release(struct binder_proc *proc)
static void binder_deferred_func(struct work_struct *work)
{
struct binder_proc *proc;
- struct files_struct *files;
int defer;
@@ -5016,23 +5180,11 @@ static void binder_deferred_func(struct work_struct *work)
}
mutex_unlock(&binder_deferred_lock);
- files = NULL;
- if (defer & BINDER_DEFERRED_PUT_FILES) {
- mutex_lock(&proc->files_lock);
- files = proc->files;
- if (files)
- proc->files = NULL;
- mutex_unlock(&proc->files_lock);
- }
-
if (defer & BINDER_DEFERRED_FLUSH)
binder_deferred_flush(proc);
if (defer & BINDER_DEFERRED_RELEASE)
binder_deferred_release(proc); /* frees proc */
-
- if (files)
- put_files_struct(files);
} while (proc);
}
static DECLARE_WORK(binder_deferred_work, binder_deferred_func);
@@ -5667,12 +5819,11 @@ static int __init binder_init(void)
* Copy the module_parameter string, because we don't want to
* tokenize it in-place.
*/
- device_names = kzalloc(strlen(binder_devices_param) + 1, GFP_KERNEL);
+ device_names = kstrdup(binder_devices_param, GFP_KERNEL);
if (!device_names) {
ret = -ENOMEM;
goto err_alloc_device_names_failed;
}
- strcpy(device_names, binder_devices_param);
device_tmp = device_names;
while ((device_name = strsep(&device_tmp, ","))) {
diff --git a/drivers/android/binder_trace.h b/drivers/android/binder_trace.h
index 588eb3ec3507..14de7ac57a34 100644
--- a/drivers/android/binder_trace.h
+++ b/drivers/android/binder_trace.h
@@ -223,22 +223,40 @@ TRACE_EVENT(binder_transaction_ref_to_ref,
__entry->dest_ref_debug_id, __entry->dest_ref_desc)
);
-TRACE_EVENT(binder_transaction_fd,
- TP_PROTO(struct binder_transaction *t, int src_fd, int dest_fd),
- TP_ARGS(t, src_fd, dest_fd),
+TRACE_EVENT(binder_transaction_fd_send,
+ TP_PROTO(struct binder_transaction *t, int fd, size_t offset),
+ TP_ARGS(t, fd, offset),
TP_STRUCT__entry(
__field(int, debug_id)
- __field(int, src_fd)
- __field(int, dest_fd)
+ __field(int, fd)
+ __field(size_t, offset)
+ ),
+ TP_fast_assign(
+ __entry->debug_id = t->debug_id;
+ __entry->fd = fd;
+ __entry->offset = offset;
+ ),
+ TP_printk("transaction=%d src_fd=%d offset=%zu",
+ __entry->debug_id, __entry->fd, __entry->offset)
+);
+
+TRACE_EVENT(binder_transaction_fd_recv,
+ TP_PROTO(struct binder_transaction *t, int fd, size_t offset),
+ TP_ARGS(t, fd, offset),
+
+ TP_STRUCT__entry(
+ __field(int, debug_id)
+ __field(int, fd)
+ __field(size_t, offset)
),
TP_fast_assign(
__entry->debug_id = t->debug_id;
- __entry->src_fd = src_fd;
- __entry->dest_fd = dest_fd;
+ __entry->fd = fd;
+ __entry->offset = offset;
),
- TP_printk("transaction=%d src_fd=%d ==> dest_fd=%d",
- __entry->debug_id, __entry->src_fd, __entry->dest_fd)
+ TP_printk("transaction=%d dest_fd=%d offset=%zu",
+ __entry->debug_id, __entry->fd, __entry->offset)
);
DECLARE_EVENT_CLASS(binder_buffer_class,
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 39b181d6bd0d..4ca7a6b4eaae 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -33,7 +33,6 @@ if ATA
config ATA_NONSTANDARD
bool
- default n
config ATA_VERBOSE_ERROR
bool "Verbose ATA error reporting"
@@ -62,7 +61,6 @@ config ATA_ACPI
config SATA_ZPODD
bool "SATA Zero Power Optical Disc Drive (ZPODD) support"
depends on ATA_ACPI && PM
- default n
help
This option adds support for SATA Zero Power Optical Disc
Drive (ZPODD). It requires both the ODD and the platform
@@ -121,7 +119,8 @@ config SATA_AHCI_PLATFORM
config AHCI_BRCM
tristate "Broadcom AHCI SATA support"
- depends on ARCH_BRCMSTB || BMIPS_GENERIC || ARCH_BCM_NSP
+ depends on ARCH_BRCMSTB || BMIPS_GENERIC || ARCH_BCM_NSP || \
+ ARCH_BCM_63XX
help
This option enables support for the AHCI SATA3 controller found on
Broadcom SoC's.
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index 6a1515f0da40..ef356e70e6de 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -352,6 +352,8 @@ struct ahci_host_priv {
struct clk *clks[AHCI_MAX_CLKS]; /* Optional */
struct reset_control *rsts; /* Optional */
struct regulator **target_pwrs; /* Optional */
+ struct regulator *ahci_regulator;/* Optional */
+ struct regulator *phy_regulator;/* Optional */
/*
* If platform uses PHYs. There is a 1:1 relation between the port number and
* the PHY position in this array.
diff --git a/drivers/ata/ahci_brcm.c b/drivers/ata/ahci_brcm.c
index f3d557777d82..fba5a3044c8a 100644
--- a/drivers/ata/ahci_brcm.c
+++ b/drivers/ata/ahci_brcm.c
@@ -25,6 +25,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
+#include <linux/reset.h>
#include <linux/string.h>
#include "ahci.h"
@@ -94,6 +95,7 @@ struct brcm_ahci_priv {
u32 port_mask;
u32 quirks;
enum brcm_ahci_version version;
+ struct reset_control *rcdev;
};
static inline u32 brcm_sata_readreg(void __iomem *addr)
@@ -381,6 +383,7 @@ static struct scsi_host_template ahci_platform_sht = {
static const struct of_device_id ahci_of_match[] = {
{.compatible = "brcm,bcm7425-ahci", .data = (void *)BRCM_SATA_BCM7425},
{.compatible = "brcm,bcm7445-ahci", .data = (void *)BRCM_SATA_BCM7445},
+ {.compatible = "brcm,bcm63138-ahci", .data = (void *)BRCM_SATA_BCM7445},
{.compatible = "brcm,bcm-nsp-ahci", .data = (void *)BRCM_SATA_NSP},
{},
};
@@ -411,6 +414,11 @@ static int brcm_ahci_probe(struct platform_device *pdev)
if (IS_ERR(priv->top_ctrl))
return PTR_ERR(priv->top_ctrl);
+ /* Reset is optional depending on platform */
+ priv->rcdev = devm_reset_control_get(&pdev->dev, "ahci");
+ if (!IS_ERR_OR_NULL(priv->rcdev))
+ reset_control_deassert(priv->rcdev);
+
if ((priv->version == BRCM_SATA_BCM7425) ||
(priv->version == BRCM_SATA_NSP)) {
priv->quirks |= BRCM_AHCI_QUIRK_NO_NCQ;
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 46f0bd75eff7..cf1e0e18a7a9 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -33,6 +33,13 @@ static const struct ata_port_info ahci_port_info = {
.port_ops = &ahci_platform_ops,
};
+static const struct ata_port_info ahci_port_info_nolpm = {
+ .flags = AHCI_FLAG_COMMON | ATA_FLAG_NO_LPM,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &ahci_platform_ops,
+};
+
static struct scsi_host_template ahci_platform_sht = {
AHCI_SHT(DRV_NAME),
};
@@ -41,6 +48,7 @@ static int ahci_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct ahci_host_priv *hpriv;
+ const struct ata_port_info *port;
int rc;
hpriv = ahci_platform_get_resources(pdev,
@@ -58,7 +66,11 @@ static int ahci_probe(struct platform_device *pdev)
if (of_device_is_compatible(dev->of_node, "hisilicon,hisi-ahci"))
hpriv->flags |= AHCI_HFLAG_NO_FBS | AHCI_HFLAG_NO_NCQ;
- rc = ahci_platform_init_host(pdev, hpriv, &ahci_port_info,
+ port = acpi_device_get_match_data(dev);
+ if (!port)
+ port = &ahci_port_info;
+
+ rc = ahci_platform_init_host(pdev, hpriv, port,
&ahci_platform_sht);
if (rc)
goto disable_resources;
@@ -85,6 +97,7 @@ static const struct of_device_id ahci_of_match[] = {
MODULE_DEVICE_TABLE(of, ahci_of_match);
static const struct acpi_device_id ahci_acpi_match[] = {
+ { "APMC0D33", (unsigned long)&ahci_port_info_nolpm },
{ ACPI_DEVICE_CLASS(PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff) },
{},
};
diff --git a/drivers/ata/ahci_sunxi.c b/drivers/ata/ahci_sunxi.c
index 631610b72aa5..911710643305 100644
--- a/drivers/ata/ahci_sunxi.c
+++ b/drivers/ata/ahci_sunxi.c
@@ -181,7 +181,7 @@ static int ahci_sunxi_probe(struct platform_device *pdev)
struct ahci_host_priv *hpriv;
int rc;
- hpriv = ahci_platform_get_resources(pdev, 0);
+ hpriv = ahci_platform_get_resources(pdev, AHCI_PLATFORM_GET_RESETS);
if (IS_ERR(hpriv))
return PTR_ERR(hpriv);
@@ -250,6 +250,7 @@ static SIMPLE_DEV_PM_OPS(ahci_sunxi_pm_ops, ahci_platform_suspend,
static const struct of_device_id ahci_sunxi_of_match[] = {
{ .compatible = "allwinner,sun4i-a10-ahci", },
+ { .compatible = "allwinner,sun8i-r40-ahci", },
{ },
};
MODULE_DEVICE_TABLE(of, ahci_sunxi_of_match);
diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
index c92c10d55374..4b900fc659f7 100644
--- a/drivers/ata/libahci_platform.c
+++ b/drivers/ata/libahci_platform.c
@@ -139,7 +139,7 @@ EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
* ahci_platform_enable_regulators - Enable regulators
* @hpriv: host private area to store config values
*
- * This function enables all the regulators found in
+ * This function enables all the regulators found in controller and
* hpriv->target_pwrs, if any. If a regulator fails to be enabled, it
* disables all the regulators already enabled in reverse order and
* returns an error.
@@ -151,6 +151,18 @@ int ahci_platform_enable_regulators(struct ahci_host_priv *hpriv)
{
int rc, i;
+ if (hpriv->ahci_regulator) {
+ rc = regulator_enable(hpriv->ahci_regulator);
+ if (rc)
+ return rc;
+ }
+
+ if (hpriv->phy_regulator) {
+ rc = regulator_enable(hpriv->phy_regulator);
+ if (rc)
+ goto disable_ahci_pwrs;
+ }
+
for (i = 0; i < hpriv->nports; i++) {
if (!hpriv->target_pwrs[i])
continue;
@@ -167,6 +179,11 @@ disable_target_pwrs:
if (hpriv->target_pwrs[i])
regulator_disable(hpriv->target_pwrs[i]);
+ if (hpriv->phy_regulator)
+ regulator_disable(hpriv->phy_regulator);
+disable_ahci_pwrs:
+ if (hpriv->ahci_regulator)
+ regulator_disable(hpriv->ahci_regulator);
return rc;
}
EXPORT_SYMBOL_GPL(ahci_platform_enable_regulators);
@@ -175,7 +192,8 @@ EXPORT_SYMBOL_GPL(ahci_platform_enable_regulators);
* ahci_platform_disable_regulators - Disable regulators
* @hpriv: host private area to store config values
*
- * This function disables all regulators found in hpriv->target_pwrs.
+ * This function disables all regulators found in hpriv->target_pwrs and
+ * AHCI controller.
*/
void ahci_platform_disable_regulators(struct ahci_host_priv *hpriv)
{
@@ -186,6 +204,11 @@ void ahci_platform_disable_regulators(struct ahci_host_priv *hpriv)
continue;
regulator_disable(hpriv->target_pwrs[i]);
}
+
+ if (hpriv->ahci_regulator)
+ regulator_disable(hpriv->ahci_regulator);
+ if (hpriv->phy_regulator)
+ regulator_disable(hpriv->phy_regulator);
}
EXPORT_SYMBOL_GPL(ahci_platform_disable_regulators);
/**
@@ -303,8 +326,8 @@ static int ahci_platform_get_phy(struct ahci_host_priv *hpriv, u32 port,
/* No PHY support. Check if PHY is required. */
if (of_find_property(node, "phys", NULL)) {
dev_err(dev,
- "couldn't get PHY in node %s: ENOSYS\n",
- node->name);
+ "couldn't get PHY in node %pOFn: ENOSYS\n",
+ node);
break;
}
/* fall through */
@@ -316,8 +339,8 @@ static int ahci_platform_get_phy(struct ahci_host_priv *hpriv, u32 port,
default:
dev_err(dev,
- "couldn't get PHY in node %s: %d\n",
- node->name, rc);
+ "couldn't get PHY in node %pOFn: %d\n",
+ node, rc);
break;
}
@@ -351,6 +374,7 @@ static int ahci_platform_get_regulator(struct ahci_host_priv *hpriv, u32 port,
*
* 1) mmio registers (IORESOURCE_MEM 0, mandatory)
* 2) regulator for controlling the targets power (optional)
+ * regulator for controlling the AHCI controller (optional)
* 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node,
* or for non devicetree enabled platforms a single clock
* 4) resets, if flags has AHCI_PLATFORM_GET_RESETS (optional)
@@ -408,6 +432,24 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
hpriv->clks[i] = clk;
}
+ hpriv->ahci_regulator = devm_regulator_get_optional(dev, "ahci");
+ if (IS_ERR(hpriv->ahci_regulator)) {
+ rc = PTR_ERR(hpriv->ahci_regulator);
+ if (rc == -EPROBE_DEFER)
+ goto err_out;
+ rc = 0;
+ hpriv->ahci_regulator = NULL;
+ }
+
+ hpriv->phy_regulator = devm_regulator_get_optional(dev, "phy");
+ if (IS_ERR(hpriv->phy_regulator)) {
+ rc = PTR_ERR(hpriv->phy_regulator);
+ if (rc == -EPROBE_DEFER)
+ goto err_out;
+ rc = 0;
+ hpriv->phy_regulator = NULL;
+ }
+
if (flags & AHCI_PLATFORM_GET_RESETS) {
hpriv->rsts = devm_reset_control_array_get_optional_shared(dev);
if (IS_ERR(hpriv->rsts)) {
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index a9dd4ea7467d..a7f5202a4815 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -4553,6 +4553,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
/* These specific Samsung models/firmware-revs do not handle LPM well */
{ "SAMSUNG MZMPC128HBFU-000MV", "CXM14M1Q", ATA_HORKAGE_NOLPM, },
{ "SAMSUNG SSD PM830 mSATA *", "CXM13D1Q", ATA_HORKAGE_NOLPM, },
+ { "SAMSUNG MZ7TD256HAFV-000L9", NULL, ATA_HORKAGE_NOLPM, },
/* devices that don't properly handle queued TRIM commands */
{ "Micron_M500IT_*", "MU01", ATA_HORKAGE_NO_NCQ_TRIM |
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 1984fc78c750..3d4887d0e84a 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -639,8 +639,8 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
if (args[0] == ATA_CMD_SMART) { /* hack -- ide driver does this too */
scsi_cmd[6] = args[3];
scsi_cmd[8] = args[1];
- scsi_cmd[10] = 0x4f;
- scsi_cmd[12] = 0xc2;
+ scsi_cmd[10] = ATA_SMART_LBAM_PASS;
+ scsi_cmd[12] = ATA_SMART_LBAH_PASS;
} else {
scsi_cmd[6] = args[1];
}
diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c
index 4d49fd3c927b..843bb200a1ee 100644
--- a/drivers/ata/pata_atiixp.c
+++ b/drivers/ata/pata_atiixp.c
@@ -279,7 +279,7 @@ static int atiixp_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
const struct ata_port_info *ppi[] = { &info, &info };
/* SB600 doesn't have secondary port wired */
- if((pdev->device == PCI_DEVICE_ID_ATI_IXP600_IDE))
+ if (pdev->device == PCI_DEVICE_ID_ATI_IXP600_IDE)
ppi[1] = &ata_dummy_port_info;
return ata_pci_bmdma_init_one(pdev, ppi, &atiixp_sht, NULL,
diff --git a/drivers/ata/pata_ep93xx.c b/drivers/ata/pata_ep93xx.c
index 0a550190955a..cc6d06c1b2c7 100644
--- a/drivers/ata/pata_ep93xx.c
+++ b/drivers/ata/pata_ep93xx.c
@@ -659,7 +659,7 @@ static void ep93xx_pata_dma_init(struct ep93xx_pata_data *drv_data)
* start of new transfer.
*/
drv_data->dma_rx_data.port = EP93XX_DMA_IDE;
- drv_data->dma_rx_data.direction = DMA_FROM_DEVICE;
+ drv_data->dma_rx_data.direction = DMA_DEV_TO_MEM;
drv_data->dma_rx_data.name = "ep93xx-pata-rx";
drv_data->dma_rx_channel = dma_request_channel(mask,
ep93xx_pata_dma_filter, &drv_data->dma_rx_data);
@@ -667,7 +667,7 @@ static void ep93xx_pata_dma_init(struct ep93xx_pata_data *drv_data)
return;
drv_data->dma_tx_data.port = EP93XX_DMA_IDE;
- drv_data->dma_tx_data.direction = DMA_TO_DEVICE;
+ drv_data->dma_tx_data.direction = DMA_MEM_TO_DEV;
drv_data->dma_tx_data.name = "ep93xx-pata-tx";
drv_data->dma_tx_channel = dma_request_channel(mask,
ep93xx_pata_dma_filter, &drv_data->dma_tx_data);
@@ -678,7 +678,7 @@ static void ep93xx_pata_dma_init(struct ep93xx_pata_data *drv_data)
/* Configure receive channel direction and source address */
memset(&conf, 0, sizeof(conf));
- conf.direction = DMA_FROM_DEVICE;
+ conf.direction = DMA_DEV_TO_MEM;
conf.src_addr = drv_data->udma_in_phys;
conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
if (dmaengine_slave_config(drv_data->dma_rx_channel, &conf)) {
@@ -689,7 +689,7 @@ static void ep93xx_pata_dma_init(struct ep93xx_pata_data *drv_data)
/* Configure transmit channel direction and destination address */
memset(&conf, 0, sizeof(conf));
- conf.direction = DMA_TO_DEVICE;
+ conf.direction = DMA_MEM_TO_DEV;
conf.dst_addr = drv_data->udma_out_phys;
conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
if (dmaengine_slave_config(drv_data->dma_tx_channel, &conf)) {
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c
index 9b6d7930d1c7..e0bcf9b2dab0 100644
--- a/drivers/ata/sata_inic162x.c
+++ b/drivers/ata/sata_inic162x.c
@@ -873,7 +873,7 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
* like others but it will lock up the whole machine HARD if
* 65536 byte PRD entry is fed. Reduce maximum segment size.
*/
- rc = pci_set_dma_max_seg_size(pdev, 65536 - 512);
+ rc = dma_set_max_seg_size(&pdev->dev, 65536 - 512);
if (rc) {
dev_err(&pdev->dev, "failed to set the maximum segment size\n");
return rc;
diff --git a/drivers/ata/sata_rcar.c b/drivers/ata/sata_rcar.c
index 10ecb232245d..4b1ff5bc256a 100644
--- a/drivers/ata/sata_rcar.c
+++ b/drivers/ata/sata_rcar.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Renesas R-Car SATA driver
*
* Author: Vladimir Barinov <source@cogentembedded.com>
* Copyright (C) 2013-2015 Cogent Embedded, Inc.
* Copyright (C) 2013-2015 Renesas Solutions Corp.
- *
- * 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.
*/
#include <linux/kernel.h>
diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c
index 6470e3c4c990..f8c703426c90 100644
--- a/drivers/atm/eni.c
+++ b/drivers/atm/eni.c
@@ -241,7 +241,8 @@ static void __iomem *eni_alloc_mem(struct eni_dev *eni_dev, unsigned long *size)
len = eni_dev->free_len;
if (*size < MID_MIN_BUF_SIZE) *size = MID_MIN_BUF_SIZE;
if (*size > MID_MAX_BUF_SIZE) return NULL;
- for (order = 0; (1 << order) < *size; order++);
+ for (order = 0; (1 << order) < *size; order++)
+ ;
DPRINTK("trying: %ld->%d\n",*size,order);
best_order = 65; /* we don't have more than 2^64 of anything ... */
index = 0; /* silence GCC */
diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c
index 99a38115b0a8..f55ffde877b5 100644
--- a/drivers/atm/fore200e.c
+++ b/drivers/atm/fore200e.c
@@ -106,7 +106,6 @@
static const struct atmdev_ops fore200e_ops;
-static const struct fore200e_bus fore200e_bus[];
static LIST_HEAD(fore200e_boards);
@@ -183,10 +182,9 @@ fore200e_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, i
alignment = 0;
chunk->alloc_size = size + alignment;
- chunk->align_size = size;
chunk->direction = direction;
- chunk->alloc_addr = kzalloc(chunk->alloc_size, GFP_KERNEL | GFP_DMA);
+ chunk->alloc_addr = kzalloc(chunk->alloc_size, GFP_KERNEL);
if (chunk->alloc_addr == NULL)
return -ENOMEM;
@@ -195,8 +193,12 @@ fore200e_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, i
chunk->align_addr = chunk->alloc_addr + offset;
- chunk->dma_addr = fore200e->bus->dma_map(fore200e, chunk->align_addr, chunk->align_size, direction);
-
+ chunk->dma_addr = dma_map_single(fore200e->dev, chunk->align_addr,
+ size, direction);
+ if (dma_mapping_error(fore200e->dev, chunk->dma_addr)) {
+ kfree(chunk->alloc_addr);
+ return -ENOMEM;
+ }
return 0;
}
@@ -206,11 +208,39 @@ fore200e_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, i
static void
fore200e_chunk_free(struct fore200e* fore200e, struct chunk* chunk)
{
- fore200e->bus->dma_unmap(fore200e, chunk->dma_addr, chunk->dma_size, chunk->direction);
-
+ dma_unmap_single(fore200e->dev, chunk->dma_addr, chunk->dma_size,
+ chunk->direction);
kfree(chunk->alloc_addr);
}
+/*
+ * Allocate a DMA consistent chunk of memory intended to act as a communication
+ * mechanism (to hold descriptors, status, queues, etc.) shared by the driver
+ * and the adapter.
+ */
+static int
+fore200e_dma_chunk_alloc(struct fore200e *fore200e, struct chunk *chunk,
+ int size, int nbr, int alignment)
+{
+ /* returned chunks are page-aligned */
+ chunk->alloc_size = size * nbr;
+ chunk->alloc_addr = dma_alloc_coherent(fore200e->dev, chunk->alloc_size,
+ &chunk->dma_addr, GFP_KERNEL);
+ if (!chunk->alloc_addr)
+ return -ENOMEM;
+ chunk->align_addr = chunk->alloc_addr;
+ return 0;
+}
+
+/*
+ * Free a DMA consistent chunk of memory.
+ */
+static void
+fore200e_dma_chunk_free(struct fore200e* fore200e, struct chunk* chunk)
+{
+ dma_free_coherent(fore200e->dev, chunk->alloc_size, chunk->alloc_addr,
+ chunk->dma_addr);
+}
static void
fore200e_spin(int msecs)
@@ -303,10 +333,10 @@ fore200e_uninit_bs_queue(struct fore200e* fore200e)
struct chunk* rbd_block = &fore200e->host_bsq[ scheme ][ magn ].rbd_block;
if (status->alloc_addr)
- fore200e->bus->dma_chunk_free(fore200e, status);
+ fore200e_dma_chunk_free(fore200e, status);
if (rbd_block->alloc_addr)
- fore200e->bus->dma_chunk_free(fore200e, rbd_block);
+ fore200e_dma_chunk_free(fore200e, rbd_block);
}
}
}
@@ -372,17 +402,17 @@ fore200e_shutdown(struct fore200e* fore200e)
/* fall through */
case FORE200E_STATE_INIT_RXQ:
- fore200e->bus->dma_chunk_free(fore200e, &fore200e->host_rxq.status);
- fore200e->bus->dma_chunk_free(fore200e, &fore200e->host_rxq.rpd);
+ fore200e_dma_chunk_free(fore200e, &fore200e->host_rxq.status);
+ fore200e_dma_chunk_free(fore200e, &fore200e->host_rxq.rpd);
/* fall through */
case FORE200E_STATE_INIT_TXQ:
- fore200e->bus->dma_chunk_free(fore200e, &fore200e->host_txq.status);
- fore200e->bus->dma_chunk_free(fore200e, &fore200e->host_txq.tpd);
+ fore200e_dma_chunk_free(fore200e, &fore200e->host_txq.status);
+ fore200e_dma_chunk_free(fore200e, &fore200e->host_txq.tpd);
/* fall through */
case FORE200E_STATE_INIT_CMDQ:
- fore200e->bus->dma_chunk_free(fore200e, &fore200e->host_cmdq.status);
+ fore200e_dma_chunk_free(fore200e, &fore200e->host_cmdq.status);
/* fall through */
case FORE200E_STATE_INITIALIZE:
@@ -429,81 +459,6 @@ static void fore200e_pca_write(u32 val, volatile u32 __iomem *addr)
writel(cpu_to_le32(val), addr);
}
-
-static u32
-fore200e_pca_dma_map(struct fore200e* fore200e, void* virt_addr, int size, int direction)
-{
- u32 dma_addr = dma_map_single(&((struct pci_dev *) fore200e->bus_dev)->dev, virt_addr, size, direction);
-
- DPRINTK(3, "PCI DVMA mapping: virt_addr = 0x%p, size = %d, direction = %d, --> dma_addr = 0x%08x\n",
- virt_addr, size, direction, dma_addr);
-
- return dma_addr;
-}
-
-
-static void
-fore200e_pca_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size, int direction)
-{
- DPRINTK(3, "PCI DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d\n",
- dma_addr, size, direction);
-
- dma_unmap_single(&((struct pci_dev *) fore200e->bus_dev)->dev, dma_addr, size, direction);
-}
-
-
-static void
-fore200e_pca_dma_sync_for_cpu(struct fore200e* fore200e, u32 dma_addr, int size, int direction)
-{
- DPRINTK(3, "PCI DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
-
- dma_sync_single_for_cpu(&((struct pci_dev *) fore200e->bus_dev)->dev, dma_addr, size, direction);
-}
-
-static void
-fore200e_pca_dma_sync_for_device(struct fore200e* fore200e, u32 dma_addr, int size, int direction)
-{
- DPRINTK(3, "PCI DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
-
- dma_sync_single_for_device(&((struct pci_dev *) fore200e->bus_dev)->dev, dma_addr, size, direction);
-}
-
-
-/* allocate a DMA consistent chunk of memory intended to act as a communication mechanism
- (to hold descriptors, status, queues, etc.) shared by the driver and the adapter */
-
-static int
-fore200e_pca_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk,
- int size, int nbr, int alignment)
-{
- /* returned chunks are page-aligned */
- chunk->alloc_size = size * nbr;
- chunk->alloc_addr = dma_alloc_coherent(&((struct pci_dev *) fore200e->bus_dev)->dev,
- chunk->alloc_size,
- &chunk->dma_addr,
- GFP_KERNEL);
-
- if ((chunk->alloc_addr == NULL) || (chunk->dma_addr == 0))
- return -ENOMEM;
-
- chunk->align_addr = chunk->alloc_addr;
-
- return 0;
-}
-
-
-/* free a DMA consistent chunk of memory */
-
-static void
-fore200e_pca_dma_chunk_free(struct fore200e* fore200e, struct chunk* chunk)
-{
- dma_free_coherent(&((struct pci_dev *) fore200e->bus_dev)->dev,
- chunk->alloc_size,
- chunk->alloc_addr,
- chunk->dma_addr);
-}
-
-
static int
fore200e_pca_irq_check(struct fore200e* fore200e)
{
@@ -571,7 +526,7 @@ fore200e_pca_unmap(struct fore200e* fore200e)
static int fore200e_pca_configure(struct fore200e *fore200e)
{
- struct pci_dev* pci_dev = (struct pci_dev*)fore200e->bus_dev;
+ struct pci_dev *pci_dev = to_pci_dev(fore200e->dev);
u8 master_ctrl, latency;
DPRINTK(2, "device %s being configured\n", fore200e->name);
@@ -623,7 +578,10 @@ fore200e_pca_prom_read(struct fore200e* fore200e, struct prom_data* prom)
opcode.opcode = OPCODE_GET_PROM;
opcode.pad = 0;
- prom_dma = fore200e->bus->dma_map(fore200e, prom, sizeof(struct prom_data), DMA_FROM_DEVICE);
+ prom_dma = dma_map_single(fore200e->dev, prom, sizeof(struct prom_data),
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(fore200e->dev, prom_dma))
+ return -ENOMEM;
fore200e->bus->write(prom_dma, &entry->cp_entry->cmd.prom_block.prom_haddr);
@@ -635,7 +593,7 @@ fore200e_pca_prom_read(struct fore200e* fore200e, struct prom_data* prom)
*entry->status = STATUS_FREE;
- fore200e->bus->dma_unmap(fore200e, prom_dma, sizeof(struct prom_data), DMA_FROM_DEVICE);
+ dma_unmap_single(fore200e->dev, prom_dma, sizeof(struct prom_data), DMA_FROM_DEVICE);
if (ok == 0) {
printk(FORE200E "unable to get PROM data from device %s\n", fore200e->name);
@@ -658,15 +616,31 @@ fore200e_pca_prom_read(struct fore200e* fore200e, struct prom_data* prom)
static int
fore200e_pca_proc_read(struct fore200e* fore200e, char *page)
{
- struct pci_dev* pci_dev = (struct pci_dev*)fore200e->bus_dev;
+ struct pci_dev *pci_dev = to_pci_dev(fore200e->dev);
return sprintf(page, " PCI bus/slot/function:\t%d/%d/%d\n",
pci_dev->bus->number, PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn));
}
+static const struct fore200e_bus fore200e_pci_ops = {
+ .model_name = "PCA-200E",
+ .proc_name = "pca200e",
+ .descr_alignment = 32,
+ .buffer_alignment = 4,
+ .status_alignment = 32,
+ .read = fore200e_pca_read,
+ .write = fore200e_pca_write,
+ .configure = fore200e_pca_configure,
+ .map = fore200e_pca_map,
+ .reset = fore200e_pca_reset,
+ .prom_read = fore200e_pca_prom_read,
+ .unmap = fore200e_pca_unmap,
+ .irq_check = fore200e_pca_irq_check,
+ .irq_ack = fore200e_pca_irq_ack,
+ .proc_read = fore200e_pca_proc_read,
+};
#endif /* CONFIG_PCI */
-
#ifdef CONFIG_SBUS
static u32 fore200e_sba_read(volatile u32 __iomem *addr)
@@ -679,78 +653,6 @@ static void fore200e_sba_write(u32 val, volatile u32 __iomem *addr)
sbus_writel(val, addr);
}
-static u32 fore200e_sba_dma_map(struct fore200e *fore200e, void* virt_addr, int size, int direction)
-{
- struct platform_device *op = fore200e->bus_dev;
- u32 dma_addr;
-
- dma_addr = dma_map_single(&op->dev, virt_addr, size, direction);
-
- DPRINTK(3, "SBUS DVMA mapping: virt_addr = 0x%p, size = %d, direction = %d --> dma_addr = 0x%08x\n",
- virt_addr, size, direction, dma_addr);
-
- return dma_addr;
-}
-
-static void fore200e_sba_dma_unmap(struct fore200e *fore200e, u32 dma_addr, int size, int direction)
-{
- struct platform_device *op = fore200e->bus_dev;
-
- DPRINTK(3, "SBUS DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d,\n",
- dma_addr, size, direction);
-
- dma_unmap_single(&op->dev, dma_addr, size, direction);
-}
-
-static void fore200e_sba_dma_sync_for_cpu(struct fore200e *fore200e, u32 dma_addr, int size, int direction)
-{
- struct platform_device *op = fore200e->bus_dev;
-
- DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
-
- dma_sync_single_for_cpu(&op->dev, dma_addr, size, direction);
-}
-
-static void fore200e_sba_dma_sync_for_device(struct fore200e *fore200e, u32 dma_addr, int size, int direction)
-{
- struct platform_device *op = fore200e->bus_dev;
-
- DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
-
- dma_sync_single_for_device(&op->dev, dma_addr, size, direction);
-}
-
-/* Allocate a DVMA consistent chunk of memory intended to act as a communication mechanism
- * (to hold descriptors, status, queues, etc.) shared by the driver and the adapter.
- */
-static int fore200e_sba_dma_chunk_alloc(struct fore200e *fore200e, struct chunk *chunk,
- int size, int nbr, int alignment)
-{
- struct platform_device *op = fore200e->bus_dev;
-
- chunk->alloc_size = chunk->align_size = size * nbr;
-
- /* returned chunks are page-aligned */
- chunk->alloc_addr = dma_alloc_coherent(&op->dev, chunk->alloc_size,
- &chunk->dma_addr, GFP_ATOMIC);
-
- if ((chunk->alloc_addr == NULL) || (chunk->dma_addr == 0))
- return -ENOMEM;
-
- chunk->align_addr = chunk->alloc_addr;
-
- return 0;
-}
-
-/* free a DVMA consistent chunk of memory */
-static void fore200e_sba_dma_chunk_free(struct fore200e *fore200e, struct chunk *chunk)
-{
- struct platform_device *op = fore200e->bus_dev;
-
- dma_free_coherent(&op->dev, chunk->alloc_size,
- chunk->alloc_addr, chunk->dma_addr);
-}
-
static void fore200e_sba_irq_enable(struct fore200e *fore200e)
{
u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY;
@@ -777,7 +679,7 @@ static void fore200e_sba_reset(struct fore200e *fore200e)
static int __init fore200e_sba_map(struct fore200e *fore200e)
{
- struct platform_device *op = fore200e->bus_dev;
+ struct platform_device *op = to_platform_device(fore200e->dev);
unsigned int bursts;
/* gain access to the SBA specific registers */
@@ -807,7 +709,7 @@ static int __init fore200e_sba_map(struct fore200e *fore200e)
static void fore200e_sba_unmap(struct fore200e *fore200e)
{
- struct platform_device *op = fore200e->bus_dev;
+ struct platform_device *op = to_platform_device(fore200e->dev);
of_iounmap(&op->resource[0], fore200e->regs.sba.hcr, SBA200E_HCR_LENGTH);
of_iounmap(&op->resource[1], fore200e->regs.sba.bsr, SBA200E_BSR_LENGTH);
@@ -823,7 +725,7 @@ static int __init fore200e_sba_configure(struct fore200e *fore200e)
static int __init fore200e_sba_prom_read(struct fore200e *fore200e, struct prom_data *prom)
{
- struct platform_device *op = fore200e->bus_dev;
+ struct platform_device *op = to_platform_device(fore200e->dev);
const u8 *prop;
int len;
@@ -847,7 +749,7 @@ static int __init fore200e_sba_prom_read(struct fore200e *fore200e, struct prom_
static int fore200e_sba_proc_read(struct fore200e *fore200e, char *page)
{
- struct platform_device *op = fore200e->bus_dev;
+ struct platform_device *op = to_platform_device(fore200e->dev);
const struct linux_prom_registers *regs;
regs = of_get_property(op->dev.of_node, "reg", NULL);
@@ -855,8 +757,26 @@ static int fore200e_sba_proc_read(struct fore200e *fore200e, char *page)
return sprintf(page, " SBUS slot/device:\t\t%d/'%s'\n",
(regs ? regs->which_io : 0), op->dev.of_node->name);
}
-#endif /* CONFIG_SBUS */
+static const struct fore200e_bus fore200e_sbus_ops = {
+ .model_name = "SBA-200E",
+ .proc_name = "sba200e",
+ .descr_alignment = 32,
+ .buffer_alignment = 64,
+ .status_alignment = 32,
+ .read = fore200e_sba_read,
+ .write = fore200e_sba_write,
+ .configure = fore200e_sba_configure,
+ .map = fore200e_sba_map,
+ .reset = fore200e_sba_reset,
+ .prom_read = fore200e_sba_prom_read,
+ .unmap = fore200e_sba_unmap,
+ .irq_enable = fore200e_sba_irq_enable,
+ .irq_check = fore200e_sba_irq_check,
+ .irq_ack = fore200e_sba_irq_ack,
+ .proc_read = fore200e_sba_proc_read,
+};
+#endif /* CONFIG_SBUS */
static void
fore200e_tx_irq(struct fore200e* fore200e)
@@ -884,7 +804,7 @@ fore200e_tx_irq(struct fore200e* fore200e)
kfree(entry->data);
/* remove DMA mapping */
- fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length,
+ dma_unmap_single(fore200e->dev, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length,
DMA_TO_DEVICE);
vc_map = entry->vc_map;
@@ -1105,12 +1025,14 @@ fore200e_push_rpd(struct fore200e* fore200e, struct atm_vcc* vcc, struct rpd* rp
buffer = FORE200E_HDL2BUF(rpd->rsd[ i ].handle);
/* Make device DMA transfer visible to CPU. */
- fore200e->bus->dma_sync_for_cpu(fore200e, buffer->data.dma_addr, rpd->rsd[ i ].length, DMA_FROM_DEVICE);
+ dma_sync_single_for_cpu(fore200e->dev, buffer->data.dma_addr,
+ rpd->rsd[i].length, DMA_FROM_DEVICE);
skb_put_data(skb, buffer->data.align_addr, rpd->rsd[i].length);
/* Now let the device get at it again. */
- fore200e->bus->dma_sync_for_device(fore200e, buffer->data.dma_addr, rpd->rsd[ i ].length, DMA_FROM_DEVICE);
+ dma_sync_single_for_device(fore200e->dev, buffer->data.dma_addr,
+ rpd->rsd[i].length, DMA_FROM_DEVICE);
}
DPRINTK(3, "rx skb: len = %d, truesize = %d\n", skb->len, skb->truesize);
@@ -1611,7 +1533,7 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb)
}
if (tx_copy) {
- data = kmalloc(tx_len, GFP_ATOMIC | GFP_DMA);
+ data = kmalloc(tx_len, GFP_ATOMIC);
if (data == NULL) {
if (vcc->pop) {
vcc->pop(vcc, skb);
@@ -1679,7 +1601,14 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb)
entry->data = tx_copy ? data : NULL;
tpd = entry->tpd;
- tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, data, tx_len, DMA_TO_DEVICE);
+ tpd->tsd[ 0 ].buffer = dma_map_single(fore200e->dev, data, tx_len,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(fore200e->dev, tpd->tsd[0].buffer)) {
+ if (tx_copy)
+ kfree(data);
+ spin_unlock_irqrestore(&fore200e->q_lock, flags);
+ return -ENOMEM;
+ }
tpd->tsd[ 0 ].length = tx_len;
FORE200E_NEXT_ENTRY(txq->head, QUEUE_SIZE_TX);
@@ -1747,13 +1676,15 @@ fore200e_getstats(struct fore200e* fore200e)
u32 stats_dma_addr;
if (fore200e->stats == NULL) {
- fore200e->stats = kzalloc(sizeof(struct stats), GFP_KERNEL | GFP_DMA);
+ fore200e->stats = kzalloc(sizeof(struct stats), GFP_KERNEL);
if (fore200e->stats == NULL)
return -ENOMEM;
}
- stats_dma_addr = fore200e->bus->dma_map(fore200e, fore200e->stats,
- sizeof(struct stats), DMA_FROM_DEVICE);
+ stats_dma_addr = dma_map_single(fore200e->dev, fore200e->stats,
+ sizeof(struct stats), DMA_FROM_DEVICE);
+ if (dma_mapping_error(fore200e->dev, stats_dma_addr))
+ return -ENOMEM;
FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD);
@@ -1770,7 +1701,7 @@ fore200e_getstats(struct fore200e* fore200e)
*entry->status = STATUS_FREE;
- fore200e->bus->dma_unmap(fore200e, stats_dma_addr, sizeof(struct stats), DMA_FROM_DEVICE);
+ dma_unmap_single(fore200e->dev, stats_dma_addr, sizeof(struct stats), DMA_FROM_DEVICE);
if (ok == 0) {
printk(FORE200E "unable to get statistics from device %s\n", fore200e->name);
@@ -2049,7 +1980,7 @@ static int fore200e_irq_request(struct fore200e *fore200e)
static int fore200e_get_esi(struct fore200e *fore200e)
{
- struct prom_data* prom = kzalloc(sizeof(struct prom_data), GFP_KERNEL | GFP_DMA);
+ struct prom_data* prom = kzalloc(sizeof(struct prom_data), GFP_KERNEL);
int ok, i;
if (!prom)
@@ -2156,7 +2087,7 @@ static int fore200e_init_bs_queue(struct fore200e *fore200e)
bsq = &fore200e->host_bsq[ scheme ][ magn ];
/* allocate and align the array of status words */
- if (fore200e->bus->dma_chunk_alloc(fore200e,
+ if (fore200e_dma_chunk_alloc(fore200e,
&bsq->status,
sizeof(enum status),
QUEUE_SIZE_BS,
@@ -2165,13 +2096,13 @@ static int fore200e_init_bs_queue(struct fore200e *fore200e)
}
/* allocate and align the array of receive buffer descriptors */
- if (fore200e->bus->dma_chunk_alloc(fore200e,
+ if (fore200e_dma_chunk_alloc(fore200e,
&bsq->rbd_block,
sizeof(struct rbd_block),
QUEUE_SIZE_BS,
fore200e->bus->descr_alignment) < 0) {
- fore200e->bus->dma_chunk_free(fore200e, &bsq->status);
+ fore200e_dma_chunk_free(fore200e, &bsq->status);
return -ENOMEM;
}
@@ -2212,7 +2143,7 @@ static int fore200e_init_rx_queue(struct fore200e *fore200e)
DPRINTK(2, "receive queue is being initialized\n");
/* allocate and align the array of status words */
- if (fore200e->bus->dma_chunk_alloc(fore200e,
+ if (fore200e_dma_chunk_alloc(fore200e,
&rxq->status,
sizeof(enum status),
QUEUE_SIZE_RX,
@@ -2221,13 +2152,13 @@ static int fore200e_init_rx_queue(struct fore200e *fore200e)
}
/* allocate and align the array of receive PDU descriptors */
- if (fore200e->bus->dma_chunk_alloc(fore200e,
+ if (fore200e_dma_chunk_alloc(fore200e,
&rxq->rpd,
sizeof(struct rpd),
QUEUE_SIZE_RX,
fore200e->bus->descr_alignment) < 0) {
- fore200e->bus->dma_chunk_free(fore200e, &rxq->status);
+ fore200e_dma_chunk_free(fore200e, &rxq->status);
return -ENOMEM;
}
@@ -2271,7 +2202,7 @@ static int fore200e_init_tx_queue(struct fore200e *fore200e)
DPRINTK(2, "transmit queue is being initialized\n");
/* allocate and align the array of status words */
- if (fore200e->bus->dma_chunk_alloc(fore200e,
+ if (fore200e_dma_chunk_alloc(fore200e,
&txq->status,
sizeof(enum status),
QUEUE_SIZE_TX,
@@ -2280,13 +2211,13 @@ static int fore200e_init_tx_queue(struct fore200e *fore200e)
}
/* allocate and align the array of transmit PDU descriptors */
- if (fore200e->bus->dma_chunk_alloc(fore200e,
+ if (fore200e_dma_chunk_alloc(fore200e,
&txq->tpd,
sizeof(struct tpd),
QUEUE_SIZE_TX,
fore200e->bus->descr_alignment) < 0) {
- fore200e->bus->dma_chunk_free(fore200e, &txq->status);
+ fore200e_dma_chunk_free(fore200e, &txq->status);
return -ENOMEM;
}
@@ -2333,7 +2264,7 @@ static int fore200e_init_cmd_queue(struct fore200e *fore200e)
DPRINTK(2, "command queue is being initialized\n");
/* allocate and align the array of status words */
- if (fore200e->bus->dma_chunk_alloc(fore200e,
+ if (fore200e_dma_chunk_alloc(fore200e,
&cmdq->status,
sizeof(enum status),
QUEUE_SIZE_CMD,
@@ -2487,25 +2418,15 @@ static void fore200e_monitor_puts(struct fore200e *fore200e, char *str)
static int fore200e_load_and_start_fw(struct fore200e *fore200e)
{
const struct firmware *firmware;
- struct device *device;
const struct fw_header *fw_header;
const __le32 *fw_data;
u32 fw_size;
u32 __iomem *load_addr;
char buf[48];
- int err = -ENODEV;
-
- if (strcmp(fore200e->bus->model_name, "PCA-200E") == 0)
- device = &((struct pci_dev *) fore200e->bus_dev)->dev;
-#ifdef CONFIG_SBUS
- else if (strcmp(fore200e->bus->model_name, "SBA-200E") == 0)
- device = &((struct platform_device *) fore200e->bus_dev)->dev;
-#endif
- else
- return err;
+ int err;
sprintf(buf, "%s%s", fore200e->bus->proc_name, FW_EXT);
- if ((err = request_firmware(&firmware, buf, device)) < 0) {
+ if ((err = request_firmware(&firmware, buf, fore200e->dev)) < 0) {
printk(FORE200E "problem loading firmware image %s\n", fore200e->bus->model_name);
return err;
}
@@ -2631,7 +2552,6 @@ static const struct of_device_id fore200e_sba_match[];
static int fore200e_sba_probe(struct platform_device *op)
{
const struct of_device_id *match;
- const struct fore200e_bus *bus;
struct fore200e *fore200e;
static int index = 0;
int err;
@@ -2639,18 +2559,17 @@ static int fore200e_sba_probe(struct platform_device *op)
match = of_match_device(fore200e_sba_match, &op->dev);
if (!match)
return -EINVAL;
- bus = match->data;
fore200e = kzalloc(sizeof(struct fore200e), GFP_KERNEL);
if (!fore200e)
return -ENOMEM;
- fore200e->bus = bus;
- fore200e->bus_dev = op;
+ fore200e->bus = &fore200e_sbus_ops;
+ fore200e->dev = &op->dev;
fore200e->irq = op->archdata.irqs[0];
fore200e->phys_base = op->resource[0].start;
- sprintf(fore200e->name, "%s-%d", bus->model_name, index);
+ sprintf(fore200e->name, "SBA-200E-%d", index);
err = fore200e_init(fore200e, &op->dev);
if (err < 0) {
@@ -2678,7 +2597,6 @@ static int fore200e_sba_remove(struct platform_device *op)
static const struct of_device_id fore200e_sba_match[] = {
{
.name = SBA200E_PROM_NAME,
- .data = (void *) &fore200e_bus[1],
},
{},
};
@@ -2698,7 +2616,6 @@ static struct platform_driver fore200e_sba_driver = {
static int fore200e_pca_detect(struct pci_dev *pci_dev,
const struct pci_device_id *pci_ent)
{
- const struct fore200e_bus* bus = (struct fore200e_bus*) pci_ent->driver_data;
struct fore200e* fore200e;
int err = 0;
static int index = 0;
@@ -2719,20 +2636,19 @@ static int fore200e_pca_detect(struct pci_dev *pci_dev,
goto out_disable;
}
- fore200e->bus = bus;
- fore200e->bus_dev = pci_dev;
+ fore200e->bus = &fore200e_pci_ops;
+ fore200e->dev = &pci_dev->dev;
fore200e->irq = pci_dev->irq;
fore200e->phys_base = pci_resource_start(pci_dev, 0);
- sprintf(fore200e->name, "%s-%d", bus->model_name, index - 1);
+ sprintf(fore200e->name, "PCA-200E-%d", index - 1);
pci_set_master(pci_dev);
- printk(FORE200E "device %s found at 0x%lx, IRQ %s\n",
- fore200e->bus->model_name,
+ printk(FORE200E "device PCA-200E found at 0x%lx, IRQ %s\n",
fore200e->phys_base, fore200e_irq_itoa(fore200e->irq));
- sprintf(fore200e->name, "%s-%d", bus->model_name, index);
+ sprintf(fore200e->name, "PCA-200E-%d", index);
err = fore200e_init(fore200e, &pci_dev->dev);
if (err < 0) {
@@ -2767,8 +2683,7 @@ static void fore200e_pca_remove_one(struct pci_dev *pci_dev)
static const struct pci_device_id fore200e_pca_tbl[] = {
- { PCI_VENDOR_ID_FORE, PCI_DEVICE_ID_FORE_PCA200E, PCI_ANY_ID, PCI_ANY_ID,
- 0, 0, (unsigned long) &fore200e_bus[0] },
+ { PCI_VENDOR_ID_FORE, PCI_DEVICE_ID_FORE_PCA200E, PCI_ANY_ID, PCI_ANY_ID },
{ 0, }
};
@@ -3108,8 +3023,7 @@ module_init(fore200e_module_init);
module_exit(fore200e_module_cleanup);
-static const struct atmdev_ops fore200e_ops =
-{
+static const struct atmdev_ops fore200e_ops = {
.open = fore200e_open,
.close = fore200e_close,
.ioctl = fore200e_ioctl,
@@ -3121,53 +3035,6 @@ static const struct atmdev_ops fore200e_ops =
.owner = THIS_MODULE
};
-
-static const struct fore200e_bus fore200e_bus[] = {
-#ifdef CONFIG_PCI
- { "PCA-200E", "pca200e", 32, 4, 32,
- fore200e_pca_read,
- fore200e_pca_write,
- fore200e_pca_dma_map,
- fore200e_pca_dma_unmap,
- fore200e_pca_dma_sync_for_cpu,
- fore200e_pca_dma_sync_for_device,
- fore200e_pca_dma_chunk_alloc,
- fore200e_pca_dma_chunk_free,
- fore200e_pca_configure,
- fore200e_pca_map,
- fore200e_pca_reset,
- fore200e_pca_prom_read,
- fore200e_pca_unmap,
- NULL,
- fore200e_pca_irq_check,
- fore200e_pca_irq_ack,
- fore200e_pca_proc_read,
- },
-#endif
-#ifdef CONFIG_SBUS
- { "SBA-200E", "sba200e", 32, 64, 32,
- fore200e_sba_read,
- fore200e_sba_write,
- fore200e_sba_dma_map,
- fore200e_sba_dma_unmap,
- fore200e_sba_dma_sync_for_cpu,
- fore200e_sba_dma_sync_for_device,
- fore200e_sba_dma_chunk_alloc,
- fore200e_sba_dma_chunk_free,
- fore200e_sba_configure,
- fore200e_sba_map,
- fore200e_sba_reset,
- fore200e_sba_prom_read,
- fore200e_sba_unmap,
- fore200e_sba_irq_enable,
- fore200e_sba_irq_check,
- fore200e_sba_irq_ack,
- fore200e_sba_proc_read,
- },
-#endif
- {}
-};
-
MODULE_LICENSE("GPL");
#ifdef CONFIG_PCI
#ifdef __LITTLE_ENDIAN__
diff --git a/drivers/atm/fore200e.h b/drivers/atm/fore200e.h
index c8a02c8fba15..caf0ea6a328a 100644
--- a/drivers/atm/fore200e.h
+++ b/drivers/atm/fore200e.h
@@ -805,12 +805,6 @@ typedef struct fore200e_bus {
int status_alignment; /* status words DMA alignment requirement */
u32 (*read)(volatile u32 __iomem *);
void (*write)(u32, volatile u32 __iomem *);
- u32 (*dma_map)(struct fore200e*, void*, int, int);
- void (*dma_unmap)(struct fore200e*, u32, int, int);
- void (*dma_sync_for_cpu)(struct fore200e*, u32, int, int);
- void (*dma_sync_for_device)(struct fore200e*, u32, int, int);
- int (*dma_chunk_alloc)(struct fore200e*, struct chunk*, int, int, int);
- void (*dma_chunk_free)(struct fore200e*, struct chunk*);
int (*configure)(struct fore200e*);
int (*map)(struct fore200e*);
void (*reset)(struct fore200e*);
@@ -844,7 +838,7 @@ typedef struct fore200e {
enum fore200e_state state; /* device state */
char name[16]; /* device name */
- void* bus_dev; /* bus-specific kernel data */
+ struct device *dev;
int irq; /* irq number */
unsigned long phys_base; /* physical base address */
void __iomem * virt_base; /* virtual base address */
diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c
index cbec9adc01c7..ae4aa02e4dc6 100644
--- a/drivers/atm/nicstar.c
+++ b/drivers/atm/nicstar.c
@@ -2689,11 +2689,10 @@ static void ns_poll(struct timer_list *unused)
PRINTK("nicstar: Entering ns_poll().\n");
for (i = 0; i < num_cards; i++) {
card = cards[i];
- if (spin_is_locked(&card->int_lock)) {
+ if (!spin_trylock_irqsave(&card->int_lock, flags)) {
/* Probably it isn't worth spinning */
continue;
}
- spin_lock_irqsave(&card->int_lock, flags);
stat_w = 0;
stat_r = readl(card->membase + STAT);
diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c
index e89146ddede6..d5c76b50d357 100644
--- a/drivers/atm/zatm.c
+++ b/drivers/atm/zatm.c
@@ -126,7 +126,7 @@ static unsigned long dummy[2] = {0,0};
#define zin_n(r) inl(zatm_dev->base+r*4)
#define zin(r) inl(zatm_dev->base+uPD98401_##r*4)
#define zout(v,r) outl(v,zatm_dev->base+uPD98401_##r*4)
-#define zwait while (zin(CMR) & uPD98401_BUSY)
+#define zwait() do {} while (zin(CMR) & uPD98401_BUSY)
/* RX0, RX1, TX0, TX1 */
static const int mbx_entries[NR_MBX] = { 1024,1024,1024,1024 };
@@ -140,7 +140,7 @@ static const int mbx_esize[NR_MBX] = { 16,16,4,4 }; /* entry size in bytes */
static void zpokel(struct zatm_dev *zatm_dev,u32 value,u32 addr)
{
- zwait;
+ zwait();
zout(value,CER);
zout(uPD98401_IND_ACC | uPD98401_IA_BALL |
(uPD98401_IA_TGT_CM << uPD98401_IA_TGT_SHIFT) | addr,CMR);
@@ -149,10 +149,10 @@ static void zpokel(struct zatm_dev *zatm_dev,u32 value,u32 addr)
static u32 zpeekl(struct zatm_dev *zatm_dev,u32 addr)
{
- zwait;
+ zwait();
zout(uPD98401_IND_ACC | uPD98401_IA_BALL | uPD98401_IA_RW |
(uPD98401_IA_TGT_CM << uPD98401_IA_TGT_SHIFT) | addr,CMR);
- zwait;
+ zwait();
return zin(CER);
}
@@ -241,7 +241,7 @@ static void refill_pool(struct atm_dev *dev,int pool)
}
if (first) {
spin_lock_irqsave(&zatm_dev->lock, flags);
- zwait;
+ zwait();
zout(virt_to_bus(first),CER);
zout(uPD98401_ADD_BAT | (pool << uPD98401_POOL_SHIFT) | count,
CMR);
@@ -508,9 +508,9 @@ static int open_rx_first(struct atm_vcc *vcc)
}
if (zatm_vcc->pool < 0) return -EMSGSIZE;
spin_lock_irqsave(&zatm_dev->lock, flags);
- zwait;
+ zwait();
zout(uPD98401_OPEN_CHAN,CMR);
- zwait;
+ zwait();
DPRINTK("0x%x 0x%x\n",zin(CMR),zin(CER));
chan = (zin(CMR) & uPD98401_CHAN_ADDR) >> uPD98401_CHAN_ADDR_SHIFT;
spin_unlock_irqrestore(&zatm_dev->lock, flags);
@@ -571,21 +571,21 @@ static void close_rx(struct atm_vcc *vcc)
pos = vcc->vci >> 1;
shift = (1-(vcc->vci & 1)) << 4;
zpokel(zatm_dev,zpeekl(zatm_dev,pos) & ~(0xffff << shift),pos);
- zwait;
+ zwait();
zout(uPD98401_NOP,CMR);
- zwait;
+ zwait();
zout(uPD98401_NOP,CMR);
spin_unlock_irqrestore(&zatm_dev->lock, flags);
}
spin_lock_irqsave(&zatm_dev->lock, flags);
- zwait;
+ zwait();
zout(uPD98401_DEACT_CHAN | uPD98401_CHAN_RT | (zatm_vcc->rx_chan <<
uPD98401_CHAN_ADDR_SHIFT),CMR);
- zwait;
+ zwait();
udelay(10); /* why oh why ... ? */
zout(uPD98401_CLOSE_CHAN | uPD98401_CHAN_RT | (zatm_vcc->rx_chan <<
uPD98401_CHAN_ADDR_SHIFT),CMR);
- zwait;
+ zwait();
if (!(zin(CMR) & uPD98401_CHAN_ADDR))
printk(KERN_CRIT DEV_LABEL "(itf %d): can't close RX channel "
"%d\n",vcc->dev->number,zatm_vcc->rx_chan);
@@ -699,7 +699,7 @@ printk("NONONONOO!!!!\n");
skb_queue_tail(&zatm_vcc->tx_queue,skb);
DPRINTK("QRP=0x%08lx\n",zpeekl(zatm_dev,zatm_vcc->tx_chan*VC_SIZE/4+
uPD98401_TXVC_QRP));
- zwait;
+ zwait();
zout(uPD98401_TX_READY | (zatm_vcc->tx_chan <<
uPD98401_CHAN_ADDR_SHIFT),CMR);
spin_unlock_irqrestore(&zatm_dev->lock, flags);
@@ -891,12 +891,12 @@ static void close_tx(struct atm_vcc *vcc)
}
spin_lock_irqsave(&zatm_dev->lock, flags);
#if 0
- zwait;
+ zwait();
zout(uPD98401_DEACT_CHAN | (chan << uPD98401_CHAN_ADDR_SHIFT),CMR);
#endif
- zwait;
+ zwait();
zout(uPD98401_CLOSE_CHAN | (chan << uPD98401_CHAN_ADDR_SHIFT),CMR);
- zwait;
+ zwait();
if (!(zin(CMR) & uPD98401_CHAN_ADDR))
printk(KERN_CRIT DEV_LABEL "(itf %d): can't close TX channel "
"%d\n",vcc->dev->number,chan);
@@ -926,9 +926,9 @@ static int open_tx_first(struct atm_vcc *vcc)
zatm_vcc->tx_chan = 0;
if (vcc->qos.txtp.traffic_class == ATM_NONE) return 0;
spin_lock_irqsave(&zatm_dev->lock, flags);
- zwait;
+ zwait();
zout(uPD98401_OPEN_CHAN,CMR);
- zwait;
+ zwait();
DPRINTK("0x%x 0x%x\n",zin(CMR),zin(CER));
chan = (zin(CMR) & uPD98401_CHAN_ADDR) >> uPD98401_CHAN_ADDR_SHIFT;
spin_unlock_irqrestore(&zatm_dev->lock, flags);
@@ -1557,7 +1557,7 @@ static void zatm_phy_put(struct atm_dev *dev,unsigned char value,
struct zatm_dev *zatm_dev;
zatm_dev = ZATM_DEV(dev);
- zwait;
+ zwait();
zout(value,CER);
zout(uPD98401_IND_ACC | uPD98401_IA_B0 |
(uPD98401_IA_TGT_PHY << uPD98401_IA_TGT_SHIFT) | addr,CMR);
@@ -1569,10 +1569,10 @@ static unsigned char zatm_phy_get(struct atm_dev *dev,unsigned long addr)
struct zatm_dev *zatm_dev;
zatm_dev = ZATM_DEV(dev);
- zwait;
+ zwait();
zout(uPD98401_IND_ACC | uPD98401_IA_B0 | uPD98401_IA_RW |
(uPD98401_IA_TGT_PHY << uPD98401_IA_TGT_SHIFT) | addr,CMR);
- zwait;
+ zwait();
return zin(CER) & 0xff;
}
diff --git a/drivers/auxdisplay/hd44780.c b/drivers/auxdisplay/hd44780.c
index f1a42f0f1ded..9ad93ea42fdc 100644
--- a/drivers/auxdisplay/hd44780.c
+++ b/drivers/auxdisplay/hd44780.c
@@ -62,20 +62,15 @@ static void hd44780_strobe_gpio(struct hd44780 *hd)
/* write to an LCD panel register in 8 bit GPIO mode */
static void hd44780_write_gpio8(struct hd44780 *hd, u8 val, unsigned int rs)
{
- int values[10]; /* for DATA[0-7], RS, RW */
- unsigned int i, n;
-
- for (i = 0; i < 8; i++)
- values[PIN_DATA0 + i] = !!(val & BIT(i));
- values[PIN_CTRL_RS] = rs;
- n = 9;
- if (hd->pins[PIN_CTRL_RW]) {
- values[PIN_CTRL_RW] = 0;
- n++;
- }
+ DECLARE_BITMAP(values, 10); /* for DATA[0-7], RS, RW */
+ unsigned int n;
+
+ values[0] = val;
+ __assign_bit(8, values, rs);
+ n = hd->pins[PIN_CTRL_RW] ? 10 : 9;
/* Present the data to the port */
- gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA0], values);
+ gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA0], NULL, values);
hd44780_strobe_gpio(hd);
}
@@ -83,32 +78,25 @@ static void hd44780_write_gpio8(struct hd44780 *hd, u8 val, unsigned int rs)
/* write to an LCD panel register in 4 bit GPIO mode */
static void hd44780_write_gpio4(struct hd44780 *hd, u8 val, unsigned int rs)
{
- int values[10]; /* for DATA[0-7], RS, RW, but DATA[0-3] is unused */
- unsigned int i, n;
+ DECLARE_BITMAP(values, 6); /* for DATA[4-7], RS, RW */
+ unsigned int n;
/* High nibble + RS, RW */
- for (i = 4; i < 8; i++)
- values[PIN_DATA0 + i] = !!(val & BIT(i));
- values[PIN_CTRL_RS] = rs;
- n = 5;
- if (hd->pins[PIN_CTRL_RW]) {
- values[PIN_CTRL_RW] = 0;
- n++;
- }
+ values[0] = val >> 4;
+ __assign_bit(4, values, rs);
+ n = hd->pins[PIN_CTRL_RW] ? 6 : 5;
/* Present the data to the port */
- gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4],
- &values[PIN_DATA4]);
+ gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], NULL, values);
hd44780_strobe_gpio(hd);
/* Low nibble */
- for (i = 0; i < 4; i++)
- values[PIN_DATA4 + i] = !!(val & BIT(i));
+ values[0] &= ~0x0fUL;
+ values[0] |= val & 0x0f;
/* Present the data to the port */
- gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4],
- &values[PIN_DATA4]);
+ gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], NULL, values);
hd44780_strobe_gpio(hd);
}
@@ -155,23 +143,16 @@ static void hd44780_write_cmd_gpio4(struct charlcd *lcd, int cmd)
/* Send 4-bits of a command to the LCD panel in raw 4 bit GPIO mode */
static void hd44780_write_cmd_raw_gpio4(struct charlcd *lcd, int cmd)
{
- int values[10]; /* for DATA[0-7], RS, RW, but DATA[0-3] is unused */
+ DECLARE_BITMAP(values, 6); /* for DATA[4-7], RS, RW */
struct hd44780 *hd = lcd->drvdata;
- unsigned int i, n;
+ unsigned int n;
/* Command nibble + RS, RW */
- for (i = 0; i < 4; i++)
- values[PIN_DATA4 + i] = !!(cmd & BIT(i));
- values[PIN_CTRL_RS] = 0;
- n = 5;
- if (hd->pins[PIN_CTRL_RW]) {
- values[PIN_CTRL_RW] = 0;
- n++;
- }
+ values[0] = cmd & 0x0f;
+ n = hd->pins[PIN_CTRL_RW] ? 6 : 5;
/* Present the data to the port */
- gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4],
- &values[PIN_DATA4]);
+ gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], NULL, values);
hd44780_strobe_gpio(hd);
}
diff --git a/drivers/auxdisplay/panel.c b/drivers/auxdisplay/panel.c
index 3b25a643058c..21b9b2f2470a 100644
--- a/drivers/auxdisplay/panel.c
+++ b/drivers/auxdisplay/panel.c
@@ -155,10 +155,9 @@ struct logical_input {
int release_data;
} std;
struct { /* valid when type == INPUT_TYPE_KBD */
- /* strings can be non null-terminated */
- char press_str[sizeof(void *) + sizeof(int)];
- char repeat_str[sizeof(void *) + sizeof(int)];
- char release_str[sizeof(void *) + sizeof(int)];
+ char press_str[sizeof(void *) + sizeof(int)] __nonstring;
+ char repeat_str[sizeof(void *) + sizeof(int)] __nonstring;
+ char release_str[sizeof(void *) + sizeof(int)] __nonstring;
} kbd;
} u;
};
diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c
index e7cb0c6ade81..edfcf8d982e4 100644
--- a/drivers/base/arch_topology.c
+++ b/drivers/base/arch_topology.c
@@ -15,6 +15,7 @@
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/sched/topology.h>
+#include <linux/cpuset.h>
DEFINE_PER_CPU(unsigned long, freq_scale) = SCHED_CAPACITY_SCALE;
@@ -47,6 +48,9 @@ static ssize_t cpu_capacity_show(struct device *dev,
return sprintf(buf, "%lu\n", topology_get_cpu_scale(NULL, cpu->dev.id));
}
+static void update_topology_flags_workfn(struct work_struct *work);
+static DECLARE_WORK(update_topology_flags_work, update_topology_flags_workfn);
+
static ssize_t cpu_capacity_store(struct device *dev,
struct device_attribute *attr,
const char *buf,
@@ -72,6 +76,8 @@ static ssize_t cpu_capacity_store(struct device *dev,
topology_set_cpu_scale(i, new_capacity);
mutex_unlock(&cpu_scale_mutex);
+ schedule_work(&update_topology_flags_work);
+
return count;
}
@@ -96,6 +102,25 @@ static int register_cpu_capacity_sysctl(void)
}
subsys_initcall(register_cpu_capacity_sysctl);
+static int update_topology;
+
+int topology_update_cpu_topology(void)
+{
+ return update_topology;
+}
+
+/*
+ * Updating the sched_domains can't be done directly from cpufreq callbacks
+ * due to locking, so queue the work for later.
+ */
+static void update_topology_flags_workfn(struct work_struct *work)
+{
+ update_topology = 1;
+ rebuild_sched_domains();
+ pr_debug("sched_domain hierarchy rebuilt, flags updated\n");
+ update_topology = 0;
+}
+
static u32 capacity_scale;
static u32 *raw_capacity;
@@ -201,6 +226,7 @@ init_cpu_capacity_callback(struct notifier_block *nb,
if (cpumask_empty(cpus_to_visit)) {
topology_normalize_cpu_scale();
+ schedule_work(&update_topology_flags_work);
free_raw_capacity();
pr_debug("cpu_capacity: parsing done\n");
schedule_work(&parsing_done_work);
diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c
index 5d5b5988e88b..cf78fa6d470d 100644
--- a/drivers/base/cacheinfo.c
+++ b/drivers/base/cacheinfo.c
@@ -615,6 +615,8 @@ static int cache_add_dev(unsigned int cpu)
this_leaf = this_cpu_ci->info_list + i;
if (this_leaf->disable_sysfs)
continue;
+ if (this_leaf->type == CACHE_TYPE_NOCACHE)
+ break;
cache_groups = cache_get_attribute_groups(this_leaf);
ci_dev = cpu_device_create(parent, this_leaf, cache_groups,
"index%1u", i);
diff --git a/drivers/base/component.c b/drivers/base/component.c
index 8946dfee4768..e8d676fad0c9 100644
--- a/drivers/base/component.c
+++ b/drivers/base/component.c
@@ -536,9 +536,9 @@ int component_bind_all(struct device *master_dev, void *data)
}
if (ret != 0) {
- for (; i--; )
- if (!master->match->compare[i].duplicate) {
- c = master->match->compare[i].component;
+ for (; i > 0; i--)
+ if (!master->match->compare[i - 1].duplicate) {
+ c = master->match->compare[i - 1].component;
component_unbind(c, master, data);
}
}
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index edfc9f0b1180..169412ee4ae8 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -480,9 +480,11 @@ re_probe:
if (ret)
goto pinctrl_bind_failed;
- ret = dma_configure(dev);
- if (ret)
- goto dma_failed;
+ if (dev->bus->dma_configure) {
+ ret = dev->bus->dma_configure(dev);
+ if (ret)
+ goto dma_failed;
+ }
if (driver_sysfs_add(dev)) {
printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
@@ -537,7 +539,7 @@ re_probe:
goto done;
probe_failed:
- dma_deconfigure(dev);
+ arch_teardown_dma_ops(dev);
dma_failed:
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
@@ -966,7 +968,7 @@ static void __device_release_driver(struct device *dev, struct device *parent)
drv->remove(dev);
device_links_driver_cleanup(dev);
- dma_deconfigure(dev);
+ arch_teardown_dma_ops(dev);
devres_release_all(dev);
dev->driver = NULL;
diff --git a/drivers/base/devres.c b/drivers/base/devres.c
index f98a097e73f2..4aaf00d2098b 100644
--- a/drivers/base/devres.c
+++ b/drivers/base/devres.c
@@ -11,6 +11,8 @@
#include <linux/slab.h>
#include <linux/percpu.h>
+#include <asm/sections.h>
+
#include "base.h"
struct devres_node {
@@ -823,6 +825,28 @@ char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp)
EXPORT_SYMBOL_GPL(devm_kstrdup);
/**
+ * devm_kstrdup_const - resource managed conditional string duplication
+ * @dev: device for which to duplicate the string
+ * @s: the string to duplicate
+ * @gfp: the GFP mask used in the kmalloc() call when allocating memory
+ *
+ * Strings allocated by devm_kstrdup_const will be automatically freed when
+ * the associated device is detached.
+ *
+ * RETURNS:
+ * Source string if it is in .rodata section otherwise it falls back to
+ * devm_kstrdup.
+ */
+const char *devm_kstrdup_const(struct device *dev, const char *s, gfp_t gfp)
+{
+ if (is_kernel_rodata((unsigned long)s))
+ return s;
+
+ return devm_kstrdup(dev, s, gfp);
+}
+EXPORT_SYMBOL_GPL(devm_kstrdup_const);
+
+/**
* devm_kvasprintf - Allocate resource managed space and format a string
* into that.
* @dev: Device to allocate memory for
@@ -885,11 +909,19 @@ EXPORT_SYMBOL_GPL(devm_kasprintf);
*
* Free memory allocated with devm_kmalloc().
*/
-void devm_kfree(struct device *dev, void *p)
+void devm_kfree(struct device *dev, const void *p)
{
int rc;
- rc = devres_destroy(dev, devm_kmalloc_release, devm_kmalloc_match, p);
+ /*
+ * Special case: pointer to a string in .rodata returned by
+ * devm_kstrdup_const().
+ */
+ if (unlikely(is_kernel_rodata((unsigned long)p)))
+ return;
+
+ rc = devres_destroy(dev, devm_kmalloc_release,
+ devm_kmalloc_match, (void *)p);
WARN_ON(rc);
}
EXPORT_SYMBOL_GPL(devm_kfree);
diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c
index f7768077e817..b93fc862d365 100644
--- a/drivers/base/devtmpfs.c
+++ b/drivers/base/devtmpfs.c
@@ -252,7 +252,7 @@ static int dev_rmdir(const char *name)
static int delete_path(const char *nodepath)
{
- const char *path;
+ char *path;
int err = 0;
path = kstrdup(nodepath, GFP_KERNEL);
diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c
index b3c0498ee433..8e9213b36e31 100644
--- a/drivers/base/firmware_loader/main.c
+++ b/drivers/base/firmware_loader/main.c
@@ -226,8 +226,11 @@ static int alloc_lookup_fw_priv(const char *fw_name,
}
tmp = __allocate_fw_priv(fw_name, fwc, dbuf, size);
- if (tmp && !(opt_flags & FW_OPT_NOCACHE))
- list_add(&tmp->list, &fwc->head);
+ if (tmp) {
+ INIT_LIST_HEAD(&tmp->list);
+ if (!(opt_flags & FW_OPT_NOCACHE))
+ list_add(&tmp->list, &fwc->head);
+ }
spin_unlock(&fwc->lock);
*fw_priv = tmp;
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index 817320c7c4c1..0e5985682642 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -228,7 +228,6 @@ static bool pages_correctly_probed(unsigned long start_pfn)
/*
* MEMORY_HOTPLUG depends on SPARSEMEM in mm/Kconfig, so it is
* OK to have direct references to sparsemem variables in here.
- * Must already be protected by mem_hotplug_begin().
*/
static int
memory_block_action(unsigned long phys_index, unsigned long action, int online_type)
@@ -294,7 +293,6 @@ static int memory_subsys_online(struct device *dev)
if (mem->online_type < 0)
mem->online_type = MMOP_ONLINE_KEEP;
- /* Already under protection of mem_hotplug_begin() */
ret = memory_block_change_state(mem, MEM_ONLINE, MEM_OFFLINE);
/* clear online_type */
@@ -341,19 +339,11 @@ store_mem_state(struct device *dev,
goto err;
}
- /*
- * Memory hotplug needs to hold mem_hotplug_begin() for probe to find
- * the correct memory block to online before doing device_online(dev),
- * which will take dev->mutex. Take the lock early to prevent an
- * inversion, memory_subsys_online() callbacks will be implemented by
- * assuming it's already protected.
- */
- mem_hotplug_begin();
-
switch (online_type) {
case MMOP_ONLINE_KERNEL:
case MMOP_ONLINE_MOVABLE:
case MMOP_ONLINE_KEEP:
+ /* mem->online_type is protected by device_hotplug_lock */
mem->online_type = online_type;
ret = device_online(&mem->dev);
break;
@@ -364,7 +354,6 @@ store_mem_state(struct device *dev,
ret = -EINVAL; /* should never happen */
}
- mem_hotplug_done();
err:
unlock_device_hotplug();
@@ -519,15 +508,20 @@ memory_probe_store(struct device *dev, struct device_attribute *attr,
if (phys_addr & ((pages_per_block << PAGE_SHIFT) - 1))
return -EINVAL;
+ ret = lock_device_hotplug_sysfs();
+ if (ret)
+ goto out;
+
nid = memory_add_physaddr_to_nid(phys_addr);
- ret = add_memory(nid, phys_addr,
- MIN_MEMORY_BLOCK_SIZE * sections_per_block);
+ ret = __add_memory(nid, phys_addr,
+ MIN_MEMORY_BLOCK_SIZE * sections_per_block);
if (ret)
goto out;
ret = count;
out:
+ unlock_device_hotplug();
return ret;
}
diff --git a/drivers/base/node.c b/drivers/base/node.c
index 1ac4c36e13bb..86d6cd92ce3d 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -67,8 +67,11 @@ static ssize_t node_read_meminfo(struct device *dev,
int nid = dev->id;
struct pglist_data *pgdat = NODE_DATA(nid);
struct sysinfo i;
+ unsigned long sreclaimable, sunreclaimable;
si_meminfo_node(&i, nid);
+ sreclaimable = node_page_state(pgdat, NR_SLAB_RECLAIMABLE);
+ sunreclaimable = node_page_state(pgdat, NR_SLAB_UNRECLAIMABLE);
n = sprintf(buf,
"Node %d MemTotal: %8lu kB\n"
"Node %d MemFree: %8lu kB\n"
@@ -118,6 +121,7 @@ static ssize_t node_read_meminfo(struct device *dev,
"Node %d NFS_Unstable: %8lu kB\n"
"Node %d Bounce: %8lu kB\n"
"Node %d WritebackTmp: %8lu kB\n"
+ "Node %d KReclaimable: %8lu kB\n"
"Node %d Slab: %8lu kB\n"
"Node %d SReclaimable: %8lu kB\n"
"Node %d SUnreclaim: %8lu kB\n"
@@ -138,20 +142,21 @@ static ssize_t node_read_meminfo(struct device *dev,
nid, K(node_page_state(pgdat, NR_UNSTABLE_NFS)),
nid, K(sum_zone_node_page_state(nid, NR_BOUNCE)),
nid, K(node_page_state(pgdat, NR_WRITEBACK_TEMP)),
- nid, K(node_page_state(pgdat, NR_SLAB_RECLAIMABLE) +
- node_page_state(pgdat, NR_SLAB_UNRECLAIMABLE)),
- nid, K(node_page_state(pgdat, NR_SLAB_RECLAIMABLE)),
+ nid, K(sreclaimable +
+ node_page_state(pgdat, NR_KERNEL_MISC_RECLAIMABLE)),
+ nid, K(sreclaimable + sunreclaimable),
+ nid, K(sreclaimable),
+ nid, K(sunreclaimable)
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
- nid, K(node_page_state(pgdat, NR_SLAB_UNRECLAIMABLE)),
+ ,
nid, K(node_page_state(pgdat, NR_ANON_THPS) *
HPAGE_PMD_NR),
nid, K(node_page_state(pgdat, NR_SHMEM_THPS) *
HPAGE_PMD_NR),
nid, K(node_page_state(pgdat, NR_SHMEM_PMDMAPPED) *
- HPAGE_PMD_NR));
-#else
- nid, K(node_page_state(pgdat, NR_SLAB_UNRECLAIMABLE)));
+ HPAGE_PMD_NR)
#endif
+ );
n += hugetlb_report_node_meminfo(nid, buf + n);
return n;
}
diff --git a/drivers/base/platform-msi.c b/drivers/base/platform-msi.c
index 60d6cc618f1c..f39a920496fb 100644
--- a/drivers/base/platform-msi.c
+++ b/drivers/base/platform-msi.c
@@ -321,11 +321,12 @@ void *platform_msi_get_host_data(struct irq_domain *domain)
* Returns an irqdomain for @nvec interrupts
*/
struct irq_domain *
-platform_msi_create_device_domain(struct device *dev,
- unsigned int nvec,
- irq_write_msi_msg_t write_msi_msg,
- const struct irq_domain_ops *ops,
- void *host_data)
+__platform_msi_create_device_domain(struct device *dev,
+ unsigned int nvec,
+ bool is_tree,
+ irq_write_msi_msg_t write_msi_msg,
+ const struct irq_domain_ops *ops,
+ void *host_data)
{
struct platform_msi_priv_data *data;
struct irq_domain *domain;
@@ -336,7 +337,8 @@ platform_msi_create_device_domain(struct device *dev,
return NULL;
data->host_data = host_data;
- domain = irq_domain_create_hierarchy(dev->msi_domain, 0, nvec,
+ domain = irq_domain_create_hierarchy(dev->msi_domain, 0,
+ is_tree ? 0 : nvec,
dev->fwnode, ops, data);
if (!domain)
goto free_priv;
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index dff82a3c2caa..41b91af95afb 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -16,7 +16,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/dma-mapping.h>
-#include <linux/bootmem.h>
+#include <linux/memblock.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
@@ -1180,7 +1180,7 @@ int __init platform_bus_init(void)
}
#ifndef ARCH_HAS_DMA_GET_REQUIRED_MASK
-u64 dma_get_required_mask(struct device *dev)
+static u64 dma_default_get_required_mask(struct device *dev)
{
u32 low_totalram = ((max_pfn - 1) << PAGE_SHIFT);
u32 high_totalram = ((max_pfn - 1) >> (32 - PAGE_SHIFT));
@@ -1198,6 +1198,15 @@ u64 dma_get_required_mask(struct device *dev)
}
return mask;
}
+
+u64 dma_get_required_mask(struct device *dev)
+{
+ const struct dma_map_ops *ops = get_dma_ops(dev);
+
+ if (ops->get_required_mask)
+ return ops->get_required_mask(dev);
+ return dma_default_get_required_mask(dev);
+}
EXPORT_SYMBOL_GPL(dma_get_required_mask);
#endif
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 4b5714199490..7f38a92b444a 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -467,6 +467,10 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool one_dev_on,
return -EAGAIN;
}
+ /* Default to shallowest state. */
+ if (!genpd->gov)
+ genpd->state_idx = 0;
+
if (genpd->power_off) {
int ret;
@@ -1687,6 +1691,8 @@ int pm_genpd_init(struct generic_pm_domain *genpd,
ret = genpd_set_default_power_state(genpd);
if (ret)
return ret;
+ } else if (!gov) {
+ pr_warn("%s : no governor for states\n", genpd->name);
}
device_initialize(&genpd->dev);
@@ -2478,8 +2484,8 @@ static int genpd_iterate_idle_states(struct device_node *dn,
*
* Returns the device states parsed from the OF node. The memory for the states
* is allocated by this function and is the responsibility of the caller to
- * free the memory after use. If no domain idle states is found it returns
- * -EINVAL and in case of errors, a negative error code.
+ * free the memory after use. If any or zero compatible domain idle states is
+ * found it returns 0 and in case of errors, a negative error code is returned.
*/
int of_genpd_parse_idle_states(struct device_node *dn,
struct genpd_power_state **states, int *n)
@@ -2488,8 +2494,14 @@ int of_genpd_parse_idle_states(struct device_node *dn,
int ret;
ret = genpd_iterate_idle_states(dn, NULL);
- if (ret <= 0)
- return ret < 0 ? ret : -EINVAL;
+ if (ret < 0)
+ return ret;
+
+ if (!ret) {
+ *states = NULL;
+ *n = 0;
+ return 0;
+ }
st = kcalloc(ret, sizeof(*st), GFP_KERNEL);
if (!st)
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 3f68e2919dc5..a690fd400260 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -1713,8 +1713,10 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
dpm_wait_for_subordinate(dev, async);
- if (async_error)
+ if (async_error) {
+ dev->power.direct_complete = false;
goto Complete;
+ }
/*
* If a device configured to wake up the system from sleep states
@@ -1726,6 +1728,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
pm_wakeup_event(dev, 0);
if (pm_wakeup_pending()) {
+ dev->power.direct_complete = false;
async_error = -EBUSY;
goto Complete;
}
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index a6bf34d6394e..a98fced9bff8 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -94,11 +94,13 @@ struct regmap {
bool (*readable_reg)(struct device *dev, unsigned int reg);
bool (*volatile_reg)(struct device *dev, unsigned int reg);
bool (*precious_reg)(struct device *dev, unsigned int reg);
+ bool (*writeable_noinc_reg)(struct device *dev, unsigned int reg);
bool (*readable_noinc_reg)(struct device *dev, unsigned int reg);
const struct regmap_access_table *wr_table;
const struct regmap_access_table *rd_table;
const struct regmap_access_table *volatile_table;
const struct regmap_access_table *precious_table;
+ const struct regmap_access_table *wr_noinc_table;
const struct regmap_access_table *rd_noinc_table;
int (*reg_read)(void *context, unsigned int reg, unsigned int *val);
@@ -149,7 +151,7 @@ struct regmap {
/* if set, converts bulk read to single read */
bool use_single_read;
- /* if set, converts bulk read to single read */
+ /* if set, converts bulk write to single write */
bool use_single_write;
/* if set, the device supports multi write mode */
bool can_multi_write;
@@ -183,6 +185,7 @@ bool regmap_writeable(struct regmap *map, unsigned int reg);
bool regmap_readable(struct regmap *map, unsigned int reg);
bool regmap_volatile(struct regmap *map, unsigned int reg);
bool regmap_precious(struct regmap *map, unsigned int reg);
+bool regmap_writeable_noinc(struct regmap *map, unsigned int reg);
bool regmap_readable_noinc(struct regmap *map, unsigned int reg);
int _regmap_write(struct regmap *map, unsigned int reg,
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 0360a90ad6b6..4f822e087def 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -35,6 +35,16 @@
*/
#undef LOG_DEVICE
+#ifdef LOG_DEVICE
+static inline bool regmap_should_log(struct regmap *map)
+{
+ return (map->dev && strcmp(dev_name(map->dev), LOG_DEVICE) == 0);
+}
+#else
+static inline bool regmap_should_log(struct regmap *map) { return false; }
+#endif
+
+
static int _regmap_update_bits(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val,
bool *change, bool force_write);
@@ -168,6 +178,17 @@ bool regmap_precious(struct regmap *map, unsigned int reg)
return false;
}
+bool regmap_writeable_noinc(struct regmap *map, unsigned int reg)
+{
+ if (map->writeable_noinc_reg)
+ return map->writeable_noinc_reg(map->dev, reg);
+
+ if (map->wr_noinc_table)
+ return regmap_check_range_table(map, reg, map->wr_noinc_table);
+
+ return true;
+}
+
bool regmap_readable_noinc(struct regmap *map, unsigned int reg)
{
if (map->readable_noinc_reg)
@@ -762,8 +783,8 @@ struct regmap *__regmap_init(struct device *dev,
map->reg_stride_order = ilog2(map->reg_stride);
else
map->reg_stride_order = -1;
- map->use_single_read = config->use_single_rw || !bus || !bus->read;
- map->use_single_write = config->use_single_rw || !bus || !bus->write;
+ map->use_single_read = config->use_single_read || !bus || !bus->read;
+ map->use_single_write = config->use_single_write || !bus || !bus->write;
map->can_multi_write = config->can_multi_write && bus && bus->write;
if (bus) {
map->max_raw_read = bus->max_raw_read;
@@ -777,11 +798,13 @@ struct regmap *__regmap_init(struct device *dev,
map->rd_table = config->rd_table;
map->volatile_table = config->volatile_table;
map->precious_table = config->precious_table;
+ map->wr_noinc_table = config->wr_noinc_table;
map->rd_noinc_table = config->rd_noinc_table;
map->writeable_reg = config->writeable_reg;
map->readable_reg = config->readable_reg;
map->volatile_reg = config->volatile_reg;
map->precious_reg = config->precious_reg;
+ map->writeable_noinc_reg = config->writeable_noinc_reg;
map->readable_noinc_reg = config->readable_noinc_reg;
map->cache_type = config->cache_type;
@@ -1298,6 +1321,7 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
map->readable_reg = config->readable_reg;
map->volatile_reg = config->volatile_reg;
map->precious_reg = config->precious_reg;
+ map->writeable_noinc_reg = config->writeable_noinc_reg;
map->readable_noinc_reg = config->readable_noinc_reg;
map->cache_type = config->cache_type;
@@ -1755,10 +1779,8 @@ int _regmap_write(struct regmap *map, unsigned int reg,
}
}
-#ifdef LOG_DEVICE
- if (map->dev && strcmp(dev_name(map->dev), LOG_DEVICE) == 0)
+ if (regmap_should_log(map))
dev_info(map->dev, "%x <= %x\n", reg, val);
-#endif
trace_regmap_reg_write(map, reg, val);
@@ -1898,6 +1920,69 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
EXPORT_SYMBOL_GPL(regmap_raw_write);
/**
+ * regmap_noinc_write(): Write data from a register without incrementing the
+ * register number
+ *
+ * @map: Register map to write to
+ * @reg: Register to write to
+ * @val: Pointer to data buffer
+ * @val_len: Length of output buffer in bytes.
+ *
+ * The regmap API usually assumes that bulk bus write operations will write a
+ * range of registers. Some devices have certain registers for which a write
+ * operation can write to an internal FIFO.
+ *
+ * The target register must be volatile but registers after it can be
+ * completely unrelated cacheable registers.
+ *
+ * This will attempt multiple writes as required to write val_len bytes.
+ *
+ * A value of zero will be returned on success, a negative errno will be
+ * returned in error cases.
+ */
+int regmap_noinc_write(struct regmap *map, unsigned int reg,
+ const void *val, size_t val_len)
+{
+ size_t write_len;
+ int ret;
+
+ if (!map->bus)
+ return -EINVAL;
+ if (!map->bus->write)
+ return -ENOTSUPP;
+ if (val_len % map->format.val_bytes)
+ return -EINVAL;
+ if (!IS_ALIGNED(reg, map->reg_stride))
+ return -EINVAL;
+ if (val_len == 0)
+ return -EINVAL;
+
+ map->lock(map->lock_arg);
+
+ if (!regmap_volatile(map, reg) || !regmap_writeable_noinc(map, reg)) {
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ while (val_len) {
+ if (map->max_raw_write && map->max_raw_write < val_len)
+ write_len = map->max_raw_write;
+ else
+ write_len = val_len;
+ ret = _regmap_raw_write(map, reg, val, write_len);
+ if (ret)
+ goto out_unlock;
+ val = ((u8 *)val) + write_len;
+ val_len -= write_len;
+ }
+
+out_unlock:
+ map->unlock(map->lock_arg);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regmap_noinc_write);
+
+/**
* regmap_field_update_bits_base() - Perform a read/modify/write cycle a
* register field.
*
@@ -2450,10 +2535,8 @@ static int _regmap_read(struct regmap *map, unsigned int reg,
ret = map->reg_read(context, reg, val);
if (ret == 0) {
-#ifdef LOG_DEVICE
- if (map->dev && strcmp(dev_name(map->dev), LOG_DEVICE) == 0)
+ if (regmap_should_log(map))
dev_info(map->dev, "%x => %x\n", reg, *val);
-#endif
trace_regmap_reg_read(map, reg, *val);
diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c
deleted file mode 100644
index 581312ac375f..000000000000
--- a/drivers/block/DAC960.c
+++ /dev/null
@@ -1,7229 +0,0 @@
-/*
-
- Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers
-
- Copyright 1998-2001 by Leonard N. Zubkoff <lnz@dandelion.com>
- Portions Copyright 2002 by Mylex (An IBM Business Unit)
-
- This program is free software; you may redistribute 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 complete details.
-
-*/
-
-
-#define DAC960_DriverVersion "2.5.49"
-#define DAC960_DriverDate "21 Aug 2007"
-
-
-#include <linux/compiler.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/miscdevice.h>
-#include <linux/blkdev.h>
-#include <linux/bio.h>
-#include <linux/completion.h>
-#include <linux/delay.h>
-#include <linux/genhd.h>
-#include <linux/hdreg.h>
-#include <linux/blkpg.h>
-#include <linux/dma-mapping.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/mutex.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/reboot.h>
-#include <linux/spinlock.h>
-#include <linux/timer.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/jiffies.h>
-#include <linux/random.h>
-#include <linux/scatterlist.h>
-#include <asm/io.h>
-#include <linux/uaccess.h>
-#include "DAC960.h"
-
-#define DAC960_GAM_MINOR 252
-
-
-static DEFINE_MUTEX(DAC960_mutex);
-static DAC960_Controller_T *DAC960_Controllers[DAC960_MaxControllers];
-static int DAC960_ControllerCount;
-static struct proc_dir_entry *DAC960_ProcDirectoryEntry;
-
-static long disk_size(DAC960_Controller_T *p, int drive_nr)
-{
- if (p->FirmwareType == DAC960_V1_Controller) {
- if (drive_nr >= p->LogicalDriveCount)
- return 0;
- return p->V1.LogicalDriveInformation[drive_nr].
- LogicalDriveSize;
- } else {
- DAC960_V2_LogicalDeviceInfo_T *i =
- p->V2.LogicalDeviceInformation[drive_nr];
- if (i == NULL)
- return 0;
- return i->ConfigurableDeviceSize;
- }
-}
-
-static int DAC960_open(struct block_device *bdev, fmode_t mode)
-{
- struct gendisk *disk = bdev->bd_disk;
- DAC960_Controller_T *p = disk->queue->queuedata;
- int drive_nr = (long)disk->private_data;
- int ret = -ENXIO;
-
- mutex_lock(&DAC960_mutex);
- if (p->FirmwareType == DAC960_V1_Controller) {
- if (p->V1.LogicalDriveInformation[drive_nr].
- LogicalDriveState == DAC960_V1_LogicalDrive_Offline)
- goto out;
- } else {
- DAC960_V2_LogicalDeviceInfo_T *i =
- p->V2.LogicalDeviceInformation[drive_nr];
- if (!i || i->LogicalDeviceState == DAC960_V2_LogicalDevice_Offline)
- goto out;
- }
-
- check_disk_change(bdev);
-
- if (!get_capacity(p->disks[drive_nr]))
- goto out;
- ret = 0;
-out:
- mutex_unlock(&DAC960_mutex);
- return ret;
-}
-
-static int DAC960_getgeo(struct block_device *bdev, struct hd_geometry *geo)
-{
- struct gendisk *disk = bdev->bd_disk;
- DAC960_Controller_T *p = disk->queue->queuedata;
- int drive_nr = (long)disk->private_data;
-
- if (p->FirmwareType == DAC960_V1_Controller) {
- geo->heads = p->V1.GeometryTranslationHeads;
- geo->sectors = p->V1.GeometryTranslationSectors;
- geo->cylinders = p->V1.LogicalDriveInformation[drive_nr].
- LogicalDriveSize / (geo->heads * geo->sectors);
- } else {
- DAC960_V2_LogicalDeviceInfo_T *i =
- p->V2.LogicalDeviceInformation[drive_nr];
- switch (i->DriveGeometry) {
- case DAC960_V2_Geometry_128_32:
- geo->heads = 128;
- geo->sectors = 32;
- break;
- case DAC960_V2_Geometry_255_63:
- geo->heads = 255;
- geo->sectors = 63;
- break;
- default:
- DAC960_Error("Illegal Logical Device Geometry %d\n",
- p, i->DriveGeometry);
- return -EINVAL;
- }
-
- geo->cylinders = i->ConfigurableDeviceSize /
- (geo->heads * geo->sectors);
- }
-
- return 0;
-}
-
-static unsigned int DAC960_check_events(struct gendisk *disk,
- unsigned int clearing)
-{
- DAC960_Controller_T *p = disk->queue->queuedata;
- int drive_nr = (long)disk->private_data;
-
- if (!p->LogicalDriveInitiallyAccessible[drive_nr])
- return DISK_EVENT_MEDIA_CHANGE;
- return 0;
-}
-
-static int DAC960_revalidate_disk(struct gendisk *disk)
-{
- DAC960_Controller_T *p = disk->queue->queuedata;
- int unit = (long)disk->private_data;
-
- set_capacity(disk, disk_size(p, unit));
- return 0;
-}
-
-static const struct block_device_operations DAC960_BlockDeviceOperations = {
- .owner = THIS_MODULE,
- .open = DAC960_open,
- .getgeo = DAC960_getgeo,
- .check_events = DAC960_check_events,
- .revalidate_disk = DAC960_revalidate_disk,
-};
-
-
-/*
- DAC960_AnnounceDriver announces the Driver Version and Date, Author's Name,
- Copyright Notice, and Electronic Mail Address.
-*/
-
-static void DAC960_AnnounceDriver(DAC960_Controller_T *Controller)
-{
- DAC960_Announce("***** DAC960 RAID Driver Version "
- DAC960_DriverVersion " of "
- DAC960_DriverDate " *****\n", Controller);
- DAC960_Announce("Copyright 1998-2001 by Leonard N. Zubkoff "
- "<lnz@dandelion.com>\n", Controller);
-}
-
-
-/*
- DAC960_Failure prints a standardized error message, and then returns false.
-*/
-
-static bool DAC960_Failure(DAC960_Controller_T *Controller,
- unsigned char *ErrorMessage)
-{
- DAC960_Error("While configuring DAC960 PCI RAID Controller at\n",
- Controller);
- if (Controller->IO_Address == 0)
- DAC960_Error("PCI Bus %d Device %d Function %d I/O Address N/A "
- "PCI Address 0x%X\n", Controller,
- Controller->Bus, Controller->Device,
- Controller->Function, Controller->PCI_Address);
- else DAC960_Error("PCI Bus %d Device %d Function %d I/O Address "
- "0x%X PCI Address 0x%X\n", Controller,
- Controller->Bus, Controller->Device,
- Controller->Function, Controller->IO_Address,
- Controller->PCI_Address);
- DAC960_Error("%s FAILED - DETACHING\n", Controller, ErrorMessage);
- return false;
-}
-
-/*
- init_dma_loaf() and slice_dma_loaf() are helper functions for
- aggregating the dma-mapped memory for a well-known collection of
- data structures that are of different lengths.
-
- These routines don't guarantee any alignment. The caller must
- include any space needed for alignment in the sizes of the structures
- that are passed in.
- */
-
-static bool init_dma_loaf(struct pci_dev *dev, struct dma_loaf *loaf,
- size_t len)
-{
- void *cpu_addr;
- dma_addr_t dma_handle;
-
- cpu_addr = pci_alloc_consistent(dev, len, &dma_handle);
- if (cpu_addr == NULL)
- return false;
-
- loaf->cpu_free = loaf->cpu_base = cpu_addr;
- loaf->dma_free =loaf->dma_base = dma_handle;
- loaf->length = len;
- memset(cpu_addr, 0, len);
- return true;
-}
-
-static void *slice_dma_loaf(struct dma_loaf *loaf, size_t len,
- dma_addr_t *dma_handle)
-{
- void *cpu_end = loaf->cpu_free + len;
- void *cpu_addr = loaf->cpu_free;
-
- BUG_ON(cpu_end > loaf->cpu_base + loaf->length);
- *dma_handle = loaf->dma_free;
- loaf->cpu_free = cpu_end;
- loaf->dma_free += len;
- return cpu_addr;
-}
-
-static void free_dma_loaf(struct pci_dev *dev, struct dma_loaf *loaf_handle)
-{
- if (loaf_handle->cpu_base != NULL)
- pci_free_consistent(dev, loaf_handle->length,
- loaf_handle->cpu_base, loaf_handle->dma_base);
-}
-
-
-/*
- DAC960_CreateAuxiliaryStructures allocates and initializes the auxiliary
- data structures for Controller. It returns true on success and false on
- failure.
-*/
-
-static bool DAC960_CreateAuxiliaryStructures(DAC960_Controller_T *Controller)
-{
- int CommandAllocationLength, CommandAllocationGroupSize;
- int CommandsRemaining = 0, CommandIdentifier, CommandGroupByteCount;
- void *AllocationPointer = NULL;
- void *ScatterGatherCPU = NULL;
- dma_addr_t ScatterGatherDMA;
- struct dma_pool *ScatterGatherPool;
- void *RequestSenseCPU = NULL;
- dma_addr_t RequestSenseDMA;
- struct dma_pool *RequestSensePool = NULL;
-
- if (Controller->FirmwareType == DAC960_V1_Controller)
- {
- CommandAllocationLength = offsetof(DAC960_Command_T, V1.EndMarker);
- CommandAllocationGroupSize = DAC960_V1_CommandAllocationGroupSize;
- ScatterGatherPool = dma_pool_create("DAC960_V1_ScatterGather",
- &Controller->PCIDevice->dev,
- DAC960_V1_ScatterGatherLimit * sizeof(DAC960_V1_ScatterGatherSegment_T),
- sizeof(DAC960_V1_ScatterGatherSegment_T), 0);
- if (ScatterGatherPool == NULL)
- return DAC960_Failure(Controller,
- "AUXILIARY STRUCTURE CREATION (SG)");
- Controller->ScatterGatherPool = ScatterGatherPool;
- }
- else
- {
- CommandAllocationLength = offsetof(DAC960_Command_T, V2.EndMarker);
- CommandAllocationGroupSize = DAC960_V2_CommandAllocationGroupSize;
- ScatterGatherPool = dma_pool_create("DAC960_V2_ScatterGather",
- &Controller->PCIDevice->dev,
- DAC960_V2_ScatterGatherLimit * sizeof(DAC960_V2_ScatterGatherSegment_T),
- sizeof(DAC960_V2_ScatterGatherSegment_T), 0);
- if (ScatterGatherPool == NULL)
- return DAC960_Failure(Controller,
- "AUXILIARY STRUCTURE CREATION (SG)");
- RequestSensePool = dma_pool_create("DAC960_V2_RequestSense",
- &Controller->PCIDevice->dev, sizeof(DAC960_SCSI_RequestSense_T),
- sizeof(int), 0);
- if (RequestSensePool == NULL) {
- dma_pool_destroy(ScatterGatherPool);
- return DAC960_Failure(Controller,
- "AUXILIARY STRUCTURE CREATION (SG)");
- }
- Controller->ScatterGatherPool = ScatterGatherPool;
- Controller->V2.RequestSensePool = RequestSensePool;
- }
- Controller->CommandAllocationGroupSize = CommandAllocationGroupSize;
- Controller->FreeCommands = NULL;
- for (CommandIdentifier = 1;
- CommandIdentifier <= Controller->DriverQueueDepth;
- CommandIdentifier++)
- {
- DAC960_Command_T *Command;
- if (--CommandsRemaining <= 0)
- {
- CommandsRemaining =
- Controller->DriverQueueDepth - CommandIdentifier + 1;
- if (CommandsRemaining > CommandAllocationGroupSize)
- CommandsRemaining = CommandAllocationGroupSize;
- CommandGroupByteCount =
- CommandsRemaining * CommandAllocationLength;
- AllocationPointer = kzalloc(CommandGroupByteCount, GFP_ATOMIC);
- if (AllocationPointer == NULL)
- return DAC960_Failure(Controller,
- "AUXILIARY STRUCTURE CREATION");
- }
- Command = (DAC960_Command_T *) AllocationPointer;
- AllocationPointer += CommandAllocationLength;
- Command->CommandIdentifier = CommandIdentifier;
- Command->Controller = Controller;
- Command->Next = Controller->FreeCommands;
- Controller->FreeCommands = Command;
- Controller->Commands[CommandIdentifier-1] = Command;
- ScatterGatherCPU = dma_pool_alloc(ScatterGatherPool, GFP_ATOMIC,
- &ScatterGatherDMA);
- if (ScatterGatherCPU == NULL)
- return DAC960_Failure(Controller, "AUXILIARY STRUCTURE CREATION");
-
- if (RequestSensePool != NULL) {
- RequestSenseCPU = dma_pool_alloc(RequestSensePool, GFP_ATOMIC,
- &RequestSenseDMA);
- if (RequestSenseCPU == NULL) {
- dma_pool_free(ScatterGatherPool, ScatterGatherCPU,
- ScatterGatherDMA);
- return DAC960_Failure(Controller,
- "AUXILIARY STRUCTURE CREATION");
- }
- }
- if (Controller->FirmwareType == DAC960_V1_Controller) {
- Command->cmd_sglist = Command->V1.ScatterList;
- Command->V1.ScatterGatherList =
- (DAC960_V1_ScatterGatherSegment_T *)ScatterGatherCPU;
- Command->V1.ScatterGatherListDMA = ScatterGatherDMA;
- sg_init_table(Command->cmd_sglist, DAC960_V1_ScatterGatherLimit);
- } else {
- Command->cmd_sglist = Command->V2.ScatterList;
- Command->V2.ScatterGatherList =
- (DAC960_V2_ScatterGatherSegment_T *)ScatterGatherCPU;
- Command->V2.ScatterGatherListDMA = ScatterGatherDMA;
- Command->V2.RequestSense =
- (DAC960_SCSI_RequestSense_T *)RequestSenseCPU;
- Command->V2.RequestSenseDMA = RequestSenseDMA;
- sg_init_table(Command->cmd_sglist, DAC960_V2_ScatterGatherLimit);
- }
- }
- return true;
-}
-
-
-/*
- DAC960_DestroyAuxiliaryStructures deallocates the auxiliary data
- structures for Controller.
-*/
-
-static void DAC960_DestroyAuxiliaryStructures(DAC960_Controller_T *Controller)
-{
- int i;
- struct dma_pool *ScatterGatherPool = Controller->ScatterGatherPool;
- struct dma_pool *RequestSensePool = NULL;
- void *ScatterGatherCPU;
- dma_addr_t ScatterGatherDMA;
- void *RequestSenseCPU;
- dma_addr_t RequestSenseDMA;
- DAC960_Command_T *CommandGroup = NULL;
-
-
- if (Controller->FirmwareType == DAC960_V2_Controller)
- RequestSensePool = Controller->V2.RequestSensePool;
-
- Controller->FreeCommands = NULL;
- for (i = 0; i < Controller->DriverQueueDepth; i++)
- {
- DAC960_Command_T *Command = Controller->Commands[i];
-
- if (Command == NULL)
- continue;
-
- if (Controller->FirmwareType == DAC960_V1_Controller) {
- ScatterGatherCPU = (void *)Command->V1.ScatterGatherList;
- ScatterGatherDMA = Command->V1.ScatterGatherListDMA;
- RequestSenseCPU = NULL;
- RequestSenseDMA = (dma_addr_t)0;
- } else {
- ScatterGatherCPU = (void *)Command->V2.ScatterGatherList;
- ScatterGatherDMA = Command->V2.ScatterGatherListDMA;
- RequestSenseCPU = (void *)Command->V2.RequestSense;
- RequestSenseDMA = Command->V2.RequestSenseDMA;
- }
- if (ScatterGatherCPU != NULL)
- dma_pool_free(ScatterGatherPool, ScatterGatherCPU, ScatterGatherDMA);
- if (RequestSenseCPU != NULL)
- dma_pool_free(RequestSensePool, RequestSenseCPU, RequestSenseDMA);
-
- if ((Command->CommandIdentifier
- % Controller->CommandAllocationGroupSize) == 1) {
- /*
- * We can't free the group of commands until all of the
- * request sense and scatter gather dma structures are free.
- * Remember the beginning of the group, but don't free it
- * until we've reached the beginning of the next group.
- */
- kfree(CommandGroup);
- CommandGroup = Command;
- }
- Controller->Commands[i] = NULL;
- }
- kfree(CommandGroup);
-
- if (Controller->CombinedStatusBuffer != NULL)
- {
- kfree(Controller->CombinedStatusBuffer);
- Controller->CombinedStatusBuffer = NULL;
- Controller->CurrentStatusBuffer = NULL;
- }
-
- dma_pool_destroy(ScatterGatherPool);
- if (Controller->FirmwareType == DAC960_V1_Controller)
- return;
-
- dma_pool_destroy(RequestSensePool);
-
- for (i = 0; i < DAC960_MaxLogicalDrives; i++) {
- kfree(Controller->V2.LogicalDeviceInformation[i]);
- Controller->V2.LogicalDeviceInformation[i] = NULL;
- }
-
- for (i = 0; i < DAC960_V2_MaxPhysicalDevices; i++)
- {
- kfree(Controller->V2.PhysicalDeviceInformation[i]);
- Controller->V2.PhysicalDeviceInformation[i] = NULL;
- kfree(Controller->V2.InquiryUnitSerialNumber[i]);
- Controller->V2.InquiryUnitSerialNumber[i] = NULL;
- }
-}
-
-
-/*
- DAC960_V1_ClearCommand clears critical fields of Command for DAC960 V1
- Firmware Controllers.
-*/
-
-static inline void DAC960_V1_ClearCommand(DAC960_Command_T *Command)
-{
- DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
- memset(CommandMailbox, 0, sizeof(DAC960_V1_CommandMailbox_T));
- Command->V1.CommandStatus = 0;
-}
-
-
-/*
- DAC960_V2_ClearCommand clears critical fields of Command for DAC960 V2
- Firmware Controllers.
-*/
-
-static inline void DAC960_V2_ClearCommand(DAC960_Command_T *Command)
-{
- DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
- memset(CommandMailbox, 0, sizeof(DAC960_V2_CommandMailbox_T));
- Command->V2.CommandStatus = 0;
-}
-
-
-/*
- DAC960_AllocateCommand allocates a Command structure from Controller's
- free list. During driver initialization, a special initialization command
- has been placed on the free list to guarantee that command allocation can
- never fail.
-*/
-
-static inline DAC960_Command_T *DAC960_AllocateCommand(DAC960_Controller_T
- *Controller)
-{
- DAC960_Command_T *Command = Controller->FreeCommands;
- if (Command == NULL) return NULL;
- Controller->FreeCommands = Command->Next;
- Command->Next = NULL;
- return Command;
-}
-
-
-/*
- DAC960_DeallocateCommand deallocates Command, returning it to Controller's
- free list.
-*/
-
-static inline void DAC960_DeallocateCommand(DAC960_Command_T *Command)
-{
- DAC960_Controller_T *Controller = Command->Controller;
-
- Command->Request = NULL;
- Command->Next = Controller->FreeCommands;
- Controller->FreeCommands = Command;
-}
-
-
-/*
- DAC960_WaitForCommand waits for a wake_up on Controller's Command Wait Queue.
-*/
-
-static void DAC960_WaitForCommand(DAC960_Controller_T *Controller)
-{
- spin_unlock_irq(&Controller->queue_lock);
- __wait_event(Controller->CommandWaitQueue, Controller->FreeCommands);
- spin_lock_irq(&Controller->queue_lock);
-}
-
-/*
- DAC960_GEM_QueueCommand queues Command for DAC960 GEM Series Controllers.
-*/
-
-static void DAC960_GEM_QueueCommand(DAC960_Command_T *Command)
-{
- DAC960_Controller_T *Controller = Command->Controller;
- void __iomem *ControllerBaseAddress = Controller->BaseAddress;
- DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
- DAC960_V2_CommandMailbox_T *NextCommandMailbox =
- Controller->V2.NextCommandMailbox;
-
- CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier;
- DAC960_GEM_WriteCommandMailbox(NextCommandMailbox, CommandMailbox);
-
- if (Controller->V2.PreviousCommandMailbox1->Words[0] == 0 ||
- Controller->V2.PreviousCommandMailbox2->Words[0] == 0)
- DAC960_GEM_MemoryMailboxNewCommand(ControllerBaseAddress);
-
- Controller->V2.PreviousCommandMailbox2 =
- Controller->V2.PreviousCommandMailbox1;
- Controller->V2.PreviousCommandMailbox1 = NextCommandMailbox;
-
- if (++NextCommandMailbox > Controller->V2.LastCommandMailbox)
- NextCommandMailbox = Controller->V2.FirstCommandMailbox;
-
- Controller->V2.NextCommandMailbox = NextCommandMailbox;
-}
-
-/*
- DAC960_BA_QueueCommand queues Command for DAC960 BA Series Controllers.
-*/
-
-static void DAC960_BA_QueueCommand(DAC960_Command_T *Command)
-{
- DAC960_Controller_T *Controller = Command->Controller;
- void __iomem *ControllerBaseAddress = Controller->BaseAddress;
- DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
- DAC960_V2_CommandMailbox_T *NextCommandMailbox =
- Controller->V2.NextCommandMailbox;
- CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier;
- DAC960_BA_WriteCommandMailbox(NextCommandMailbox, CommandMailbox);
- if (Controller->V2.PreviousCommandMailbox1->Words[0] == 0 ||
- Controller->V2.PreviousCommandMailbox2->Words[0] == 0)
- DAC960_BA_MemoryMailboxNewCommand(ControllerBaseAddress);
- Controller->V2.PreviousCommandMailbox2 =
- Controller->V2.PreviousCommandMailbox1;
- Controller->V2.PreviousCommandMailbox1 = NextCommandMailbox;
- if (++NextCommandMailbox > Controller->V2.LastCommandMailbox)
- NextCommandMailbox = Controller->V2.FirstCommandMailbox;
- Controller->V2.NextCommandMailbox = NextCommandMailbox;
-}
-
-
-/*
- DAC960_LP_QueueCommand queues Command for DAC960 LP Series Controllers.
-*/
-
-static void DAC960_LP_QueueCommand(DAC960_Command_T *Command)
-{
- DAC960_Controller_T *Controller = Command->Controller;
- void __iomem *ControllerBaseAddress = Controller->BaseAddress;
- DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
- DAC960_V2_CommandMailbox_T *NextCommandMailbox =
- Controller->V2.NextCommandMailbox;
- CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier;
- DAC960_LP_WriteCommandMailbox(NextCommandMailbox, CommandMailbox);
- if (Controller->V2.PreviousCommandMailbox1->Words[0] == 0 ||
- Controller->V2.PreviousCommandMailbox2->Words[0] == 0)
- DAC960_LP_MemoryMailboxNewCommand(ControllerBaseAddress);
- Controller->V2.PreviousCommandMailbox2 =
- Controller->V2.PreviousCommandMailbox1;
- Controller->V2.PreviousCommandMailbox1 = NextCommandMailbox;
- if (++NextCommandMailbox > Controller->V2.LastCommandMailbox)
- NextCommandMailbox = Controller->V2.FirstCommandMailbox;
- Controller->V2.NextCommandMailbox = NextCommandMailbox;
-}
-
-
-/*
- DAC960_LA_QueueCommandDualMode queues Command for DAC960 LA Series
- Controllers with Dual Mode Firmware.
-*/
-
-static void DAC960_LA_QueueCommandDualMode(DAC960_Command_T *Command)
-{
- DAC960_Controller_T *Controller = Command->Controller;
- void __iomem *ControllerBaseAddress = Controller->BaseAddress;
- DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
- DAC960_V1_CommandMailbox_T *NextCommandMailbox =
- Controller->V1.NextCommandMailbox;
- CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier;
- DAC960_LA_WriteCommandMailbox(NextCommandMailbox, CommandMailbox);
- if (Controller->V1.PreviousCommandMailbox1->Words[0] == 0 ||
- Controller->V1.PreviousCommandMailbox2->Words[0] == 0)
- DAC960_LA_MemoryMailboxNewCommand(ControllerBaseAddress);
- Controller->V1.PreviousCommandMailbox2 =
- Controller->V1.PreviousCommandMailbox1;
- Controller->V1.PreviousCommandMailbox1 = NextCommandMailbox;
- if (++NextCommandMailbox > Controller->V1.LastCommandMailbox)
- NextCommandMailbox = Controller->V1.FirstCommandMailbox;
- Controller->V1.NextCommandMailbox = NextCommandMailbox;
-}
-
-
-/*
- DAC960_LA_QueueCommandSingleMode queues Command for DAC960 LA Series
- Controllers with Single Mode Firmware.
-*/
-
-static void DAC960_LA_QueueCommandSingleMode(DAC960_Command_T *Command)
-{
- DAC960_Controller_T *Controller = Command->Controller;
- void __iomem *ControllerBaseAddress = Controller->BaseAddress;
- DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
- DAC960_V1_CommandMailbox_T *NextCommandMailbox =
- Controller->V1.NextCommandMailbox;
- CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier;
- DAC960_LA_WriteCommandMailbox(NextCommandMailbox, CommandMailbox);
- if (Controller->V1.PreviousCommandMailbox1->Words[0] == 0 ||
- Controller->V1.PreviousCommandMailbox2->Words[0] == 0)
- DAC960_LA_HardwareMailboxNewCommand(ControllerBaseAddress);
- Controller->V1.PreviousCommandMailbox2 =
- Controller->V1.PreviousCommandMailbox1;
- Controller->V1.PreviousCommandMailbox1 = NextCommandMailbox;
- if (++NextCommandMailbox > Controller->V1.LastCommandMailbox)
- NextCommandMailbox = Controller->V1.FirstCommandMailbox;
- Controller->V1.NextCommandMailbox = NextCommandMailbox;
-}
-
-
-/*
- DAC960_PG_QueueCommandDualMode queues Command for DAC960 PG Series
- Controllers with Dual Mode Firmware.
-*/
-
-static void DAC960_PG_QueueCommandDualMode(DAC960_Command_T *Command)
-{
- DAC960_Controller_T *Controller = Command->Controller;
- void __iomem *ControllerBaseAddress = Controller->BaseAddress;
- DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
- DAC960_V1_CommandMailbox_T *NextCommandMailbox =
- Controller->V1.NextCommandMailbox;
- CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier;
- DAC960_PG_WriteCommandMailbox(NextCommandMailbox, CommandMailbox);
- if (Controller->V1.PreviousCommandMailbox1->Words[0] == 0 ||
- Controller->V1.PreviousCommandMailbox2->Words[0] == 0)
- DAC960_PG_MemoryMailboxNewCommand(ControllerBaseAddress);
- Controller->V1.PreviousCommandMailbox2 =
- Controller->V1.PreviousCommandMailbox1;
- Controller->V1.PreviousCommandMailbox1 = NextCommandMailbox;
- if (++NextCommandMailbox > Controller->V1.LastCommandMailbox)
- NextCommandMailbox = Controller->V1.FirstCommandMailbox;
- Controller->V1.NextCommandMailbox = NextCommandMailbox;
-}
-
-
-/*
- DAC960_PG_QueueCommandSingleMode queues Command for DAC960 PG Series
- Controllers with Single Mode Firmware.
-*/
-
-static void DAC960_PG_QueueCommandSingleMode(DAC960_Command_T *Command)
-{
- DAC960_Controller_T *Controller = Command->Controller;
- void __iomem *ControllerBaseAddress = Controller->BaseAddress;
- DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
- DAC960_V1_CommandMailbox_T *NextCommandMailbox =
- Controller->V1.NextCommandMailbox;
- CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier;
- DAC960_PG_WriteCommandMailbox(NextCommandMailbox, CommandMailbox);
- if (Controller->V1.PreviousCommandMailbox1->Words[0] == 0 ||
- Controller->V1.PreviousCommandMailbox2->Words[0] == 0)
- DAC960_PG_HardwareMailboxNewCommand(ControllerBaseAddress);
- Controller->V1.PreviousCommandMailbox2 =
- Controller->V1.PreviousCommandMailbox1;
- Controller->V1.PreviousCommandMailbox1 = NextCommandMailbox;
- if (++NextCommandMailbox > Controller->V1.LastCommandMailbox)
- NextCommandMailbox = Controller->V1.FirstCommandMailbox;
- Controller->V1.NextCommandMailbox = NextCommandMailbox;
-}
-
-
-/*
- DAC960_PD_QueueCommand queues Command for DAC960 PD Series Controllers.
-*/
-
-static void DAC960_PD_QueueCommand(DAC960_Command_T *Command)
-{
- DAC960_Controller_T *Controller = Command->Controller;
- void __iomem *ControllerBaseAddress = Controller->BaseAddress;
- DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
- CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier;
- while (DAC960_PD_MailboxFullP(ControllerBaseAddress))
- udelay(1);
- DAC960_PD_WriteCommandMailbox(ControllerBaseAddress, CommandMailbox);
- DAC960_PD_NewCommand(ControllerBaseAddress);
-}
-
-
-/*
- DAC960_P_QueueCommand queues Command for DAC960 P Series Controllers.
-*/
-
-static void DAC960_P_QueueCommand(DAC960_Command_T *Command)
-{
- DAC960_Controller_T *Controller = Command->Controller;
- void __iomem *ControllerBaseAddress = Controller->BaseAddress;
- DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
- CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier;
- switch (CommandMailbox->Common.CommandOpcode)
- {
- case DAC960_V1_Enquiry:
- CommandMailbox->Common.CommandOpcode = DAC960_V1_Enquiry_Old;
- break;
- case DAC960_V1_GetDeviceState:
- CommandMailbox->Common.CommandOpcode = DAC960_V1_GetDeviceState_Old;
- break;
- case DAC960_V1_Read:
- CommandMailbox->Common.CommandOpcode = DAC960_V1_Read_Old;
- DAC960_PD_To_P_TranslateReadWriteCommand(CommandMailbox);
- break;
- case DAC960_V1_Write:
- CommandMailbox->Common.CommandOpcode = DAC960_V1_Write_Old;
- DAC960_PD_To_P_TranslateReadWriteCommand(CommandMailbox);
- break;
- case DAC960_V1_ReadWithScatterGather:
- CommandMailbox->Common.CommandOpcode =
- DAC960_V1_ReadWithScatterGather_Old;
- DAC960_PD_To_P_TranslateReadWriteCommand(CommandMailbox);
- break;
- case DAC960_V1_WriteWithScatterGather:
- CommandMailbox->Common.CommandOpcode =
- DAC960_V1_WriteWithScatterGather_Old;
- DAC960_PD_To_P_TranslateReadWriteCommand(CommandMailbox);
- break;
- default:
- break;
- }
- while (DAC960_PD_MailboxFullP(ControllerBaseAddress))
- udelay(1);
- DAC960_PD_WriteCommandMailbox(ControllerBaseAddress, CommandMailbox);
- DAC960_PD_NewCommand(ControllerBaseAddress);
-}
-
-
-/*
- DAC960_ExecuteCommand executes Command and waits for completion.
-*/
-
-static void DAC960_ExecuteCommand(DAC960_Command_T *Command)
-{
- DAC960_Controller_T *Controller = Command->Controller;
- DECLARE_COMPLETION_ONSTACK(Completion);
- unsigned long flags;
- Command->Completion = &Completion;
-
- spin_lock_irqsave(&Controller->queue_lock, flags);
- DAC960_QueueCommand(Command);
- spin_unlock_irqrestore(&Controller->queue_lock, flags);
-
- if (in_interrupt())
- return;
- wait_for_completion(&Completion);
-}
-
-
-/*
- DAC960_V1_ExecuteType3 executes a DAC960 V1 Firmware Controller Type 3
- Command and waits for completion. It returns true on success and false
- on failure.
-*/
-
-static bool DAC960_V1_ExecuteType3(DAC960_Controller_T *Controller,
- DAC960_V1_CommandOpcode_T CommandOpcode,
- dma_addr_t DataDMA)
-{
- DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
- DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
- DAC960_V1_CommandStatus_T CommandStatus;
- DAC960_V1_ClearCommand(Command);
- Command->CommandType = DAC960_ImmediateCommand;
- CommandMailbox->Type3.CommandOpcode = CommandOpcode;
- CommandMailbox->Type3.BusAddress = DataDMA;
- DAC960_ExecuteCommand(Command);
- CommandStatus = Command->V1.CommandStatus;
- DAC960_DeallocateCommand(Command);
- return (CommandStatus == DAC960_V1_NormalCompletion);
-}
-
-
-/*
- DAC960_V1_ExecuteTypeB executes a DAC960 V1 Firmware Controller Type 3B
- Command and waits for completion. It returns true on success and false
- on failure.
-*/
-
-static bool DAC960_V1_ExecuteType3B(DAC960_Controller_T *Controller,
- DAC960_V1_CommandOpcode_T CommandOpcode,
- unsigned char CommandOpcode2,
- dma_addr_t DataDMA)
-{
- DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
- DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
- DAC960_V1_CommandStatus_T CommandStatus;
- DAC960_V1_ClearCommand(Command);
- Command->CommandType = DAC960_ImmediateCommand;
- CommandMailbox->Type3B.CommandOpcode = CommandOpcode;
- CommandMailbox->Type3B.CommandOpcode2 = CommandOpcode2;
- CommandMailbox->Type3B.BusAddress = DataDMA;
- DAC960_ExecuteCommand(Command);
- CommandStatus = Command->V1.CommandStatus;
- DAC960_DeallocateCommand(Command);
- return (CommandStatus == DAC960_V1_NormalCompletion);
-}
-
-
-/*
- DAC960_V1_ExecuteType3D executes a DAC960 V1 Firmware Controller Type 3D
- Command and waits for completion. It returns true on success and false
- on failure.
-*/
-
-static bool DAC960_V1_ExecuteType3D(DAC960_Controller_T *Controller,
- DAC960_V1_CommandOpcode_T CommandOpcode,
- unsigned char Channel,
- unsigned char TargetID,
- dma_addr_t DataDMA)
-{
- DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
- DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
- DAC960_V1_CommandStatus_T CommandStatus;
- DAC960_V1_ClearCommand(Command);
- Command->CommandType = DAC960_ImmediateCommand;
- CommandMailbox->Type3D.CommandOpcode = CommandOpcode;
- CommandMailbox->Type3D.Channel = Channel;
- CommandMailbox->Type3D.TargetID = TargetID;
- CommandMailbox->Type3D.BusAddress = DataDMA;
- DAC960_ExecuteCommand(Command);
- CommandStatus = Command->V1.CommandStatus;
- DAC960_DeallocateCommand(Command);
- return (CommandStatus == DAC960_V1_NormalCompletion);
-}
-
-
-/*
- DAC960_V2_GeneralInfo executes a DAC960 V2 Firmware General Information
- Reading IOCTL Command and waits for completion. It returns true on success
- and false on failure.
-
- Return data in The controller's HealthStatusBuffer, which is dma-able memory
-*/
-
-static bool DAC960_V2_GeneralInfo(DAC960_Controller_T *Controller)
-{
- DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
- DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
- DAC960_V2_CommandStatus_T CommandStatus;
- DAC960_V2_ClearCommand(Command);
- Command->CommandType = DAC960_ImmediateCommand;
- CommandMailbox->Common.CommandOpcode = DAC960_V2_IOCTL;
- CommandMailbox->Common.CommandControlBits
- .DataTransferControllerToHost = true;
- CommandMailbox->Common.CommandControlBits
- .NoAutoRequestSense = true;
- CommandMailbox->Common.DataTransferSize = sizeof(DAC960_V2_HealthStatusBuffer_T);
- CommandMailbox->Common.IOCTL_Opcode = DAC960_V2_GetHealthStatus;
- CommandMailbox->Common.DataTransferMemoryAddress
- .ScatterGatherSegments[0]
- .SegmentDataPointer =
- Controller->V2.HealthStatusBufferDMA;
- CommandMailbox->Common.DataTransferMemoryAddress
- .ScatterGatherSegments[0]
- .SegmentByteCount =
- CommandMailbox->Common.DataTransferSize;
- DAC960_ExecuteCommand(Command);
- CommandStatus = Command->V2.CommandStatus;
- DAC960_DeallocateCommand(Command);
- return (CommandStatus == DAC960_V2_NormalCompletion);
-}
-
-
-/*
- DAC960_V2_ControllerInfo executes a DAC960 V2 Firmware Controller
- Information Reading IOCTL Command and waits for completion. It returns
- true on success and false on failure.
-
- Data is returned in the controller's V2.NewControllerInformation dma-able
- memory buffer.
-*/
-
-static bool DAC960_V2_NewControllerInfo(DAC960_Controller_T *Controller)
-{
- DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
- DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
- DAC960_V2_CommandStatus_T CommandStatus;
- DAC960_V2_ClearCommand(Command);
- Command->CommandType = DAC960_ImmediateCommand;
- CommandMailbox->ControllerInfo.CommandOpcode = DAC960_V2_IOCTL;
- CommandMailbox->ControllerInfo.CommandControlBits
- .DataTransferControllerToHost = true;
- CommandMailbox->ControllerInfo.CommandControlBits
- .NoAutoRequestSense = true;
- CommandMailbox->ControllerInfo.DataTransferSize = sizeof(DAC960_V2_ControllerInfo_T);
- CommandMailbox->ControllerInfo.ControllerNumber = 0;
- CommandMailbox->ControllerInfo.IOCTL_Opcode = DAC960_V2_GetControllerInfo;
- CommandMailbox->ControllerInfo.DataTransferMemoryAddress
- .ScatterGatherSegments[0]
- .SegmentDataPointer =
- Controller->V2.NewControllerInformationDMA;
- CommandMailbox->ControllerInfo.DataTransferMemoryAddress
- .ScatterGatherSegments[0]
- .SegmentByteCount =
- CommandMailbox->ControllerInfo.DataTransferSize;
- DAC960_ExecuteCommand(Command);
- CommandStatus = Command->V2.CommandStatus;
- DAC960_DeallocateCommand(Command);
- return (CommandStatus == DAC960_V2_NormalCompletion);
-}
-
-
-/*
- DAC960_V2_LogicalDeviceInfo executes a DAC960 V2 Firmware Controller Logical
- Device Information Reading IOCTL Command and waits for completion. It
- returns true on success and false on failure.
-
- Data is returned in the controller's V2.NewLogicalDeviceInformation
-*/
-
-static bool DAC960_V2_NewLogicalDeviceInfo(DAC960_Controller_T *Controller,
- unsigned short LogicalDeviceNumber)
-{
- DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
- DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
- DAC960_V2_CommandStatus_T CommandStatus;
-
- DAC960_V2_ClearCommand(Command);
- Command->CommandType = DAC960_ImmediateCommand;
- CommandMailbox->LogicalDeviceInfo.CommandOpcode =
- DAC960_V2_IOCTL;
- CommandMailbox->LogicalDeviceInfo.CommandControlBits
- .DataTransferControllerToHost = true;
- CommandMailbox->LogicalDeviceInfo.CommandControlBits
- .NoAutoRequestSense = true;
- CommandMailbox->LogicalDeviceInfo.DataTransferSize =
- sizeof(DAC960_V2_LogicalDeviceInfo_T);
- CommandMailbox->LogicalDeviceInfo.LogicalDevice.LogicalDeviceNumber =
- LogicalDeviceNumber;
- CommandMailbox->LogicalDeviceInfo.IOCTL_Opcode = DAC960_V2_GetLogicalDeviceInfoValid;
- CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress
- .ScatterGatherSegments[0]
- .SegmentDataPointer =
- Controller->V2.NewLogicalDeviceInformationDMA;
- CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress
- .ScatterGatherSegments[0]
- .SegmentByteCount =
- CommandMailbox->LogicalDeviceInfo.DataTransferSize;
- DAC960_ExecuteCommand(Command);
- CommandStatus = Command->V2.CommandStatus;
- DAC960_DeallocateCommand(Command);
- return (CommandStatus == DAC960_V2_NormalCompletion);
-}
-
-
-/*
- DAC960_V2_PhysicalDeviceInfo executes a DAC960 V2 Firmware Controller "Read
- Physical Device Information" IOCTL Command and waits for completion. It
- returns true on success and false on failure.
-
- The Channel, TargetID, LogicalUnit arguments should be 0 the first time
- this function is called for a given controller. This will return data
- for the "first" device on that controller. The returned data includes a
- Channel, TargetID, LogicalUnit that can be passed in to this routine to
- get data for the NEXT device on that controller.
-
- Data is stored in the controller's V2.NewPhysicalDeviceInfo dma-able
- memory buffer.
-
-*/
-
-static bool DAC960_V2_NewPhysicalDeviceInfo(DAC960_Controller_T *Controller,
- unsigned char Channel,
- unsigned char TargetID,
- unsigned char LogicalUnit)
-{
- DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
- DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
- DAC960_V2_CommandStatus_T CommandStatus;
-
- DAC960_V2_ClearCommand(Command);
- Command->CommandType = DAC960_ImmediateCommand;
- CommandMailbox->PhysicalDeviceInfo.CommandOpcode = DAC960_V2_IOCTL;
- CommandMailbox->PhysicalDeviceInfo.CommandControlBits
- .DataTransferControllerToHost = true;
- CommandMailbox->PhysicalDeviceInfo.CommandControlBits
- .NoAutoRequestSense = true;
- CommandMailbox->PhysicalDeviceInfo.DataTransferSize =
- sizeof(DAC960_V2_PhysicalDeviceInfo_T);
- CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.LogicalUnit = LogicalUnit;
- CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.TargetID = TargetID;
- CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.Channel = Channel;
- CommandMailbox->PhysicalDeviceInfo.IOCTL_Opcode =
- DAC960_V2_GetPhysicalDeviceInfoValid;
- CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress
- .ScatterGatherSegments[0]
- .SegmentDataPointer =
- Controller->V2.NewPhysicalDeviceInformationDMA;
- CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress
- .ScatterGatherSegments[0]
- .SegmentByteCount =
- CommandMailbox->PhysicalDeviceInfo.DataTransferSize;
- DAC960_ExecuteCommand(Command);
- CommandStatus = Command->V2.CommandStatus;
- DAC960_DeallocateCommand(Command);
- return (CommandStatus == DAC960_V2_NormalCompletion);
-}
-
-
-static void DAC960_V2_ConstructNewUnitSerialNumber(
- DAC960_Controller_T *Controller,
- DAC960_V2_CommandMailbox_T *CommandMailbox, int Channel, int TargetID,
- int LogicalUnit)
-{
- CommandMailbox->SCSI_10.CommandOpcode = DAC960_V2_SCSI_10_Passthru;
- CommandMailbox->SCSI_10.CommandControlBits
- .DataTransferControllerToHost = true;
- CommandMailbox->SCSI_10.CommandControlBits
- .NoAutoRequestSense = true;
- CommandMailbox->SCSI_10.DataTransferSize =
- sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T);
- CommandMailbox->SCSI_10.PhysicalDevice.LogicalUnit = LogicalUnit;
- CommandMailbox->SCSI_10.PhysicalDevice.TargetID = TargetID;
- CommandMailbox->SCSI_10.PhysicalDevice.Channel = Channel;
- CommandMailbox->SCSI_10.CDBLength = 6;
- CommandMailbox->SCSI_10.SCSI_CDB[0] = 0x12; /* INQUIRY */
- CommandMailbox->SCSI_10.SCSI_CDB[1] = 1; /* EVPD = 1 */
- CommandMailbox->SCSI_10.SCSI_CDB[2] = 0x80; /* Page Code */
- CommandMailbox->SCSI_10.SCSI_CDB[3] = 0; /* Reserved */
- CommandMailbox->SCSI_10.SCSI_CDB[4] =
- sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T);
- CommandMailbox->SCSI_10.SCSI_CDB[5] = 0; /* Control */
- CommandMailbox->SCSI_10.DataTransferMemoryAddress
- .ScatterGatherSegments[0]
- .SegmentDataPointer =
- Controller->V2.NewInquiryUnitSerialNumberDMA;
- CommandMailbox->SCSI_10.DataTransferMemoryAddress
- .ScatterGatherSegments[0]
- .SegmentByteCount =
- CommandMailbox->SCSI_10.DataTransferSize;
-}
-
-
-/*
- DAC960_V2_NewUnitSerialNumber executes an SCSI pass-through
- Inquiry command to a SCSI device identified by Channel number,
- Target id, Logical Unit Number. This function Waits for completion
- of the command.
-
- The return data includes Unit Serial Number information for the
- specified device.
-
- Data is stored in the controller's V2.NewPhysicalDeviceInfo dma-able
- memory buffer.
-*/
-
-static bool DAC960_V2_NewInquiryUnitSerialNumber(DAC960_Controller_T *Controller,
- int Channel, int TargetID, int LogicalUnit)
-{
- DAC960_Command_T *Command;
- DAC960_V2_CommandMailbox_T *CommandMailbox;
- DAC960_V2_CommandStatus_T CommandStatus;
-
- Command = DAC960_AllocateCommand(Controller);
- CommandMailbox = &Command->V2.CommandMailbox;
- DAC960_V2_ClearCommand(Command);
- Command->CommandType = DAC960_ImmediateCommand;
-
- DAC960_V2_ConstructNewUnitSerialNumber(Controller, CommandMailbox,
- Channel, TargetID, LogicalUnit);
-
- DAC960_ExecuteCommand(Command);
- CommandStatus = Command->V2.CommandStatus;
- DAC960_DeallocateCommand(Command);
- return (CommandStatus == DAC960_V2_NormalCompletion);
-}
-
-
-/*
- DAC960_V2_DeviceOperation executes a DAC960 V2 Firmware Controller Device
- Operation IOCTL Command and waits for completion. It returns true on
- success and false on failure.
-*/
-
-static bool DAC960_V2_DeviceOperation(DAC960_Controller_T *Controller,
- DAC960_V2_IOCTL_Opcode_T IOCTL_Opcode,
- DAC960_V2_OperationDevice_T
- OperationDevice)
-{
- DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
- DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
- DAC960_V2_CommandStatus_T CommandStatus;
- DAC960_V2_ClearCommand(Command);
- Command->CommandType = DAC960_ImmediateCommand;
- CommandMailbox->DeviceOperation.CommandOpcode = DAC960_V2_IOCTL;
- CommandMailbox->DeviceOperation.CommandControlBits
- .DataTransferControllerToHost = true;
- CommandMailbox->DeviceOperation.CommandControlBits
- .NoAutoRequestSense = true;
- CommandMailbox->DeviceOperation.IOCTL_Opcode = IOCTL_Opcode;
- CommandMailbox->DeviceOperation.OperationDevice = OperationDevice;
- DAC960_ExecuteCommand(Command);
- CommandStatus = Command->V2.CommandStatus;
- DAC960_DeallocateCommand(Command);
- return (CommandStatus == DAC960_V2_NormalCompletion);
-}
-
-
-/*
- DAC960_V1_EnableMemoryMailboxInterface enables the Memory Mailbox Interface
- for DAC960 V1 Firmware Controllers.
-
- PD and P controller types have no memory mailbox, but still need the
- other dma mapped memory.
-*/
-
-static bool DAC960_V1_EnableMemoryMailboxInterface(DAC960_Controller_T
- *Controller)
-{
- void __iomem *ControllerBaseAddress = Controller->BaseAddress;
- DAC960_HardwareType_T hw_type = Controller->HardwareType;
- struct pci_dev *PCI_Device = Controller->PCIDevice;
- struct dma_loaf *DmaPages = &Controller->DmaPages;
- size_t DmaPagesSize;
- size_t CommandMailboxesSize;
- size_t StatusMailboxesSize;
-
- DAC960_V1_CommandMailbox_T *CommandMailboxesMemory;
- dma_addr_t CommandMailboxesMemoryDMA;
-
- DAC960_V1_StatusMailbox_T *StatusMailboxesMemory;
- dma_addr_t StatusMailboxesMemoryDMA;
-
- DAC960_V1_CommandMailbox_T CommandMailbox;
- DAC960_V1_CommandStatus_T CommandStatus;
- int TimeoutCounter;
- int i;
-
- memset(&CommandMailbox, 0, sizeof(DAC960_V1_CommandMailbox_T));
-
- if (pci_set_dma_mask(Controller->PCIDevice, DMA_BIT_MASK(32)))
- return DAC960_Failure(Controller, "DMA mask out of range");
-
- if ((hw_type == DAC960_PD_Controller) || (hw_type == DAC960_P_Controller)) {
- CommandMailboxesSize = 0;
- StatusMailboxesSize = 0;
- } else {
- CommandMailboxesSize = DAC960_V1_CommandMailboxCount * sizeof(DAC960_V1_CommandMailbox_T);
- StatusMailboxesSize = DAC960_V1_StatusMailboxCount * sizeof(DAC960_V1_StatusMailbox_T);
- }
- DmaPagesSize = CommandMailboxesSize + StatusMailboxesSize +
- sizeof(DAC960_V1_DCDB_T) + sizeof(DAC960_V1_Enquiry_T) +
- sizeof(DAC960_V1_ErrorTable_T) + sizeof(DAC960_V1_EventLogEntry_T) +
- sizeof(DAC960_V1_RebuildProgress_T) +
- sizeof(DAC960_V1_LogicalDriveInformationArray_T) +
- sizeof(DAC960_V1_BackgroundInitializationStatus_T) +
- sizeof(DAC960_V1_DeviceState_T) + sizeof(DAC960_SCSI_Inquiry_T) +
- sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T);
-
- if (!init_dma_loaf(PCI_Device, DmaPages, DmaPagesSize))
- return false;
-
-
- if ((hw_type == DAC960_PD_Controller) || (hw_type == DAC960_P_Controller))
- goto skip_mailboxes;
-
- CommandMailboxesMemory = slice_dma_loaf(DmaPages,
- CommandMailboxesSize, &CommandMailboxesMemoryDMA);
-
- /* These are the base addresses for the command memory mailbox array */
- Controller->V1.FirstCommandMailbox = CommandMailboxesMemory;
- Controller->V1.FirstCommandMailboxDMA = CommandMailboxesMemoryDMA;
-
- CommandMailboxesMemory += DAC960_V1_CommandMailboxCount - 1;
- Controller->V1.LastCommandMailbox = CommandMailboxesMemory;
- Controller->V1.NextCommandMailbox = Controller->V1.FirstCommandMailbox;
- Controller->V1.PreviousCommandMailbox1 = Controller->V1.LastCommandMailbox;
- Controller->V1.PreviousCommandMailbox2 =
- Controller->V1.LastCommandMailbox - 1;
-
- /* These are the base addresses for the status memory mailbox array */
- StatusMailboxesMemory = slice_dma_loaf(DmaPages,
- StatusMailboxesSize, &StatusMailboxesMemoryDMA);
-
- Controller->V1.FirstStatusMailbox = StatusMailboxesMemory;
- Controller->V1.FirstStatusMailboxDMA = StatusMailboxesMemoryDMA;
- StatusMailboxesMemory += DAC960_V1_StatusMailboxCount - 1;
- Controller->V1.LastStatusMailbox = StatusMailboxesMemory;
- Controller->V1.NextStatusMailbox = Controller->V1.FirstStatusMailbox;
-
-skip_mailboxes:
- Controller->V1.MonitoringDCDB = slice_dma_loaf(DmaPages,
- sizeof(DAC960_V1_DCDB_T),
- &Controller->V1.MonitoringDCDB_DMA);
-
- Controller->V1.NewEnquiry = slice_dma_loaf(DmaPages,
- sizeof(DAC960_V1_Enquiry_T),
- &Controller->V1.NewEnquiryDMA);
-
- Controller->V1.NewErrorTable = slice_dma_loaf(DmaPages,
- sizeof(DAC960_V1_ErrorTable_T),
- &Controller->V1.NewErrorTableDMA);
-
- Controller->V1.EventLogEntry = slice_dma_loaf(DmaPages,
- sizeof(DAC960_V1_EventLogEntry_T),
- &Controller->V1.EventLogEntryDMA);
-
- Controller->V1.RebuildProgress = slice_dma_loaf(DmaPages,
- sizeof(DAC960_V1_RebuildProgress_T),
- &Controller->V1.RebuildProgressDMA);
-
- Controller->V1.NewLogicalDriveInformation = slice_dma_loaf(DmaPages,
- sizeof(DAC960_V1_LogicalDriveInformationArray_T),
- &Controller->V1.NewLogicalDriveInformationDMA);
-
- Controller->V1.BackgroundInitializationStatus = slice_dma_loaf(DmaPages,
- sizeof(DAC960_V1_BackgroundInitializationStatus_T),
- &Controller->V1.BackgroundInitializationStatusDMA);
-
- Controller->V1.NewDeviceState = slice_dma_loaf(DmaPages,
- sizeof(DAC960_V1_DeviceState_T),
- &Controller->V1.NewDeviceStateDMA);
-
- Controller->V1.NewInquiryStandardData = slice_dma_loaf(DmaPages,
- sizeof(DAC960_SCSI_Inquiry_T),
- &Controller->V1.NewInquiryStandardDataDMA);
-
- Controller->V1.NewInquiryUnitSerialNumber = slice_dma_loaf(DmaPages,
- sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T),
- &Controller->V1.NewInquiryUnitSerialNumberDMA);
-
- if ((hw_type == DAC960_PD_Controller) || (hw_type == DAC960_P_Controller))
- return true;
-
- /* Enable the Memory Mailbox Interface. */
- Controller->V1.DualModeMemoryMailboxInterface = true;
- CommandMailbox.TypeX.CommandOpcode = 0x2B;
- CommandMailbox.TypeX.CommandIdentifier = 0;
- CommandMailbox.TypeX.CommandOpcode2 = 0x14;
- CommandMailbox.TypeX.CommandMailboxesBusAddress =
- Controller->V1.FirstCommandMailboxDMA;
- CommandMailbox.TypeX.StatusMailboxesBusAddress =
- Controller->V1.FirstStatusMailboxDMA;
-#define TIMEOUT_COUNT 1000000
-
- for (i = 0; i < 2; i++)
- switch (Controller->HardwareType)
- {
- case DAC960_LA_Controller:
- TimeoutCounter = TIMEOUT_COUNT;
- while (--TimeoutCounter >= 0)
- {
- if (!DAC960_LA_HardwareMailboxFullP(ControllerBaseAddress))
- break;
- udelay(10);
- }
- if (TimeoutCounter < 0) return false;
- DAC960_LA_WriteHardwareMailbox(ControllerBaseAddress, &CommandMailbox);
- DAC960_LA_HardwareMailboxNewCommand(ControllerBaseAddress);
- TimeoutCounter = TIMEOUT_COUNT;
- while (--TimeoutCounter >= 0)
- {
- if (DAC960_LA_HardwareMailboxStatusAvailableP(
- ControllerBaseAddress))
- break;
- udelay(10);
- }
- if (TimeoutCounter < 0) return false;
- CommandStatus = DAC960_LA_ReadStatusRegister(ControllerBaseAddress);
- DAC960_LA_AcknowledgeHardwareMailboxInterrupt(ControllerBaseAddress);
- DAC960_LA_AcknowledgeHardwareMailboxStatus(ControllerBaseAddress);
- if (CommandStatus == DAC960_V1_NormalCompletion) return true;
- Controller->V1.DualModeMemoryMailboxInterface = false;
- CommandMailbox.TypeX.CommandOpcode2 = 0x10;
- break;
- case DAC960_PG_Controller:
- TimeoutCounter = TIMEOUT_COUNT;
- while (--TimeoutCounter >= 0)
- {
- if (!DAC960_PG_HardwareMailboxFullP(ControllerBaseAddress))
- break;
- udelay(10);
- }
- if (TimeoutCounter < 0) return false;
- DAC960_PG_WriteHardwareMailbox(ControllerBaseAddress, &CommandMailbox);
- DAC960_PG_HardwareMailboxNewCommand(ControllerBaseAddress);
-
- TimeoutCounter = TIMEOUT_COUNT;
- while (--TimeoutCounter >= 0)
- {
- if (DAC960_PG_HardwareMailboxStatusAvailableP(
- ControllerBaseAddress))
- break;
- udelay(10);
- }
- if (TimeoutCounter < 0) return false;
- CommandStatus = DAC960_PG_ReadStatusRegister(ControllerBaseAddress);
- DAC960_PG_AcknowledgeHardwareMailboxInterrupt(ControllerBaseAddress);
- DAC960_PG_AcknowledgeHardwareMailboxStatus(ControllerBaseAddress);
- if (CommandStatus == DAC960_V1_NormalCompletion) return true;
- Controller->V1.DualModeMemoryMailboxInterface = false;
- CommandMailbox.TypeX.CommandOpcode2 = 0x10;
- break;
- default:
- DAC960_Failure(Controller, "Unknown Controller Type\n");
- break;
- }
- return false;
-}
-
-
-/*
- DAC960_V2_EnableMemoryMailboxInterface enables the Memory Mailbox Interface
- for DAC960 V2 Firmware Controllers.
-
- Aggregate the space needed for the controller's memory mailbox and
- the other data structures that will be targets of dma transfers with
- the controller. Allocate a dma-mapped region of memory to hold these
- structures. Then, save CPU pointers and dma_addr_t values to reference
- the structures that are contained in that region.
-*/
-
-static bool DAC960_V2_EnableMemoryMailboxInterface(DAC960_Controller_T
- *Controller)
-{
- void __iomem *ControllerBaseAddress = Controller->BaseAddress;
- struct pci_dev *PCI_Device = Controller->PCIDevice;
- struct dma_loaf *DmaPages = &Controller->DmaPages;
- size_t DmaPagesSize;
- size_t CommandMailboxesSize;
- size_t StatusMailboxesSize;
-
- DAC960_V2_CommandMailbox_T *CommandMailboxesMemory;
- dma_addr_t CommandMailboxesMemoryDMA;
-
- DAC960_V2_StatusMailbox_T *StatusMailboxesMemory;
- dma_addr_t StatusMailboxesMemoryDMA;
-
- DAC960_V2_CommandMailbox_T *CommandMailbox;
- dma_addr_t CommandMailboxDMA;
- DAC960_V2_CommandStatus_T CommandStatus;
-
- if (pci_set_dma_mask(Controller->PCIDevice, DMA_BIT_MASK(64)) &&
- pci_set_dma_mask(Controller->PCIDevice, DMA_BIT_MASK(32)))
- return DAC960_Failure(Controller, "DMA mask out of range");
-
- /* This is a temporary dma mapping, used only in the scope of this function */
- CommandMailbox = pci_alloc_consistent(PCI_Device,
- sizeof(DAC960_V2_CommandMailbox_T), &CommandMailboxDMA);
- if (CommandMailbox == NULL)
- return false;
-
- CommandMailboxesSize = DAC960_V2_CommandMailboxCount * sizeof(DAC960_V2_CommandMailbox_T);
- StatusMailboxesSize = DAC960_V2_StatusMailboxCount * sizeof(DAC960_V2_StatusMailbox_T);
- DmaPagesSize =
- CommandMailboxesSize + StatusMailboxesSize +
- sizeof(DAC960_V2_HealthStatusBuffer_T) +
- sizeof(DAC960_V2_ControllerInfo_T) +
- sizeof(DAC960_V2_LogicalDeviceInfo_T) +
- sizeof(DAC960_V2_PhysicalDeviceInfo_T) +
- sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T) +
- sizeof(DAC960_V2_Event_T) +
- sizeof(DAC960_V2_PhysicalToLogicalDevice_T);
-
- if (!init_dma_loaf(PCI_Device, DmaPages, DmaPagesSize)) {
- pci_free_consistent(PCI_Device, sizeof(DAC960_V2_CommandMailbox_T),
- CommandMailbox, CommandMailboxDMA);
- return false;
- }
-
- CommandMailboxesMemory = slice_dma_loaf(DmaPages,
- CommandMailboxesSize, &CommandMailboxesMemoryDMA);
-
- /* These are the base addresses for the command memory mailbox array */
- Controller->V2.FirstCommandMailbox = CommandMailboxesMemory;
- Controller->V2.FirstCommandMailboxDMA = CommandMailboxesMemoryDMA;
-
- CommandMailboxesMemory += DAC960_V2_CommandMailboxCount - 1;
- Controller->V2.LastCommandMailbox = CommandMailboxesMemory;
- Controller->V2.NextCommandMailbox = Controller->V2.FirstCommandMailbox;
- Controller->V2.PreviousCommandMailbox1 = Controller->V2.LastCommandMailbox;
- Controller->V2.PreviousCommandMailbox2 =
- Controller->V2.LastCommandMailbox - 1;
-
- /* These are the base addresses for the status memory mailbox array */
- StatusMailboxesMemory = slice_dma_loaf(DmaPages,
- StatusMailboxesSize, &StatusMailboxesMemoryDMA);
-
- Controller->V2.FirstStatusMailbox = StatusMailboxesMemory;
- Controller->V2.FirstStatusMailboxDMA = StatusMailboxesMemoryDMA;
- StatusMailboxesMemory += DAC960_V2_StatusMailboxCount - 1;
- Controller->V2.LastStatusMailbox = StatusMailboxesMemory;
- Controller->V2.NextStatusMailbox = Controller->V2.FirstStatusMailbox;
-
- Controller->V2.HealthStatusBuffer = slice_dma_loaf(DmaPages,
- sizeof(DAC960_V2_HealthStatusBuffer_T),
- &Controller->V2.HealthStatusBufferDMA);
-
- Controller->V2.NewControllerInformation = slice_dma_loaf(DmaPages,
- sizeof(DAC960_V2_ControllerInfo_T),
- &Controller->V2.NewControllerInformationDMA);
-
- Controller->V2.NewLogicalDeviceInformation = slice_dma_loaf(DmaPages,
- sizeof(DAC960_V2_LogicalDeviceInfo_T),
- &Controller->V2.NewLogicalDeviceInformationDMA);
-
- Controller->V2.NewPhysicalDeviceInformation = slice_dma_loaf(DmaPages,
- sizeof(DAC960_V2_PhysicalDeviceInfo_T),
- &Controller->V2.NewPhysicalDeviceInformationDMA);
-
- Controller->V2.NewInquiryUnitSerialNumber = slice_dma_loaf(DmaPages,
- sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T),
- &Controller->V2.NewInquiryUnitSerialNumberDMA);
-
- Controller->V2.Event = slice_dma_loaf(DmaPages,
- sizeof(DAC960_V2_Event_T),
- &Controller->V2.EventDMA);
-
- Controller->V2.PhysicalToLogicalDevice = slice_dma_loaf(DmaPages,
- sizeof(DAC960_V2_PhysicalToLogicalDevice_T),
- &Controller->V2.PhysicalToLogicalDeviceDMA);
-
- /*
- Enable the Memory Mailbox Interface.
-
- I don't know why we can't just use one of the memory mailboxes
- we just allocated to do this, instead of using this temporary one.
- Try this change later.
- */
- memset(CommandMailbox, 0, sizeof(DAC960_V2_CommandMailbox_T));
- CommandMailbox->SetMemoryMailbox.CommandIdentifier = 1;
- CommandMailbox->SetMemoryMailbox.CommandOpcode = DAC960_V2_IOCTL;
- CommandMailbox->SetMemoryMailbox.CommandControlBits.NoAutoRequestSense = true;
- CommandMailbox->SetMemoryMailbox.FirstCommandMailboxSizeKB =
- (DAC960_V2_CommandMailboxCount * sizeof(DAC960_V2_CommandMailbox_T)) >> 10;
- CommandMailbox->SetMemoryMailbox.FirstStatusMailboxSizeKB =
- (DAC960_V2_StatusMailboxCount * sizeof(DAC960_V2_StatusMailbox_T)) >> 10;
- CommandMailbox->SetMemoryMailbox.SecondCommandMailboxSizeKB = 0;
- CommandMailbox->SetMemoryMailbox.SecondStatusMailboxSizeKB = 0;
- CommandMailbox->SetMemoryMailbox.RequestSenseSize = 0;
- CommandMailbox->SetMemoryMailbox.IOCTL_Opcode = DAC960_V2_SetMemoryMailbox;
- CommandMailbox->SetMemoryMailbox.HealthStatusBufferSizeKB = 1;
- CommandMailbox->SetMemoryMailbox.HealthStatusBufferBusAddress =
- Controller->V2.HealthStatusBufferDMA;
- CommandMailbox->SetMemoryMailbox.FirstCommandMailboxBusAddress =
- Controller->V2.FirstCommandMailboxDMA;
- CommandMailbox->SetMemoryMailbox.FirstStatusMailboxBusAddress =
- Controller->V2.FirstStatusMailboxDMA;
- switch (Controller->HardwareType)
- {
- case DAC960_GEM_Controller:
- while (DAC960_GEM_HardwareMailboxFullP(ControllerBaseAddress))
- udelay(1);
- DAC960_GEM_WriteHardwareMailbox(ControllerBaseAddress, CommandMailboxDMA);
- DAC960_GEM_HardwareMailboxNewCommand(ControllerBaseAddress);
- while (!DAC960_GEM_HardwareMailboxStatusAvailableP(ControllerBaseAddress))
- udelay(1);
- CommandStatus = DAC960_GEM_ReadCommandStatus(ControllerBaseAddress);
- DAC960_GEM_AcknowledgeHardwareMailboxInterrupt(ControllerBaseAddress);
- DAC960_GEM_AcknowledgeHardwareMailboxStatus(ControllerBaseAddress);
- break;
- case DAC960_BA_Controller:
- while (DAC960_BA_HardwareMailboxFullP(ControllerBaseAddress))
- udelay(1);
- DAC960_BA_WriteHardwareMailbox(ControllerBaseAddress, CommandMailboxDMA);
- DAC960_BA_HardwareMailboxNewCommand(ControllerBaseAddress);
- while (!DAC960_BA_HardwareMailboxStatusAvailableP(ControllerBaseAddress))
- udelay(1);
- CommandStatus = DAC960_BA_ReadCommandStatus(ControllerBaseAddress);
- DAC960_BA_AcknowledgeHardwareMailboxInterrupt(ControllerBaseAddress);
- DAC960_BA_AcknowledgeHardwareMailboxStatus(ControllerBaseAddress);
- break;
- case DAC960_LP_Controller:
- while (DAC960_LP_HardwareMailboxFullP(ControllerBaseAddress))
- udelay(1);
- DAC960_LP_WriteHardwareMailbox(ControllerBaseAddress, CommandMailboxDMA);
- DAC960_LP_HardwareMailboxNewCommand(ControllerBaseAddress);
- while (!DAC960_LP_HardwareMailboxStatusAvailableP(ControllerBaseAddress))
- udelay(1);
- CommandStatus = DAC960_LP_ReadCommandStatus(ControllerBaseAddress);
- DAC960_LP_AcknowledgeHardwareMailboxInterrupt(ControllerBaseAddress);
- DAC960_LP_AcknowledgeHardwareMailboxStatus(ControllerBaseAddress);
- break;
- default:
- DAC960_Failure(Controller, "Unknown Controller Type\n");
- CommandStatus = DAC960_V2_AbormalCompletion;
- break;
- }
- pci_free_consistent(PCI_Device, sizeof(DAC960_V2_CommandMailbox_T),
- CommandMailbox, CommandMailboxDMA);
- return (CommandStatus == DAC960_V2_NormalCompletion);
-}
-
-
-/*
- DAC960_V1_ReadControllerConfiguration reads the Configuration Information
- from DAC960 V1 Firmware Controllers and initializes the Controller structure.
-*/
-
-static bool DAC960_V1_ReadControllerConfiguration(DAC960_Controller_T
- *Controller)
-{
- DAC960_V1_Enquiry2_T *Enquiry2;
- dma_addr_t Enquiry2DMA;
- DAC960_V1_Config2_T *Config2;
- dma_addr_t Config2DMA;
- int LogicalDriveNumber, Channel, TargetID;
- struct dma_loaf local_dma;
-
- if (!init_dma_loaf(Controller->PCIDevice, &local_dma,
- sizeof(DAC960_V1_Enquiry2_T) + sizeof(DAC960_V1_Config2_T)))
- return DAC960_Failure(Controller, "LOGICAL DEVICE ALLOCATION");
-
- Enquiry2 = slice_dma_loaf(&local_dma, sizeof(DAC960_V1_Enquiry2_T), &Enquiry2DMA);
- Config2 = slice_dma_loaf(&local_dma, sizeof(DAC960_V1_Config2_T), &Config2DMA);
-
- if (!DAC960_V1_ExecuteType3(Controller, DAC960_V1_Enquiry,
- Controller->V1.NewEnquiryDMA)) {
- free_dma_loaf(Controller->PCIDevice, &local_dma);
- return DAC960_Failure(Controller, "ENQUIRY");
- }
- memcpy(&Controller->V1.Enquiry, Controller->V1.NewEnquiry,
- sizeof(DAC960_V1_Enquiry_T));
-
- if (!DAC960_V1_ExecuteType3(Controller, DAC960_V1_Enquiry2, Enquiry2DMA)) {
- free_dma_loaf(Controller->PCIDevice, &local_dma);
- return DAC960_Failure(Controller, "ENQUIRY2");
- }
-
- if (!DAC960_V1_ExecuteType3(Controller, DAC960_V1_ReadConfig2, Config2DMA)) {
- free_dma_loaf(Controller->PCIDevice, &local_dma);
- return DAC960_Failure(Controller, "READ CONFIG2");
- }
-
- if (!DAC960_V1_ExecuteType3(Controller, DAC960_V1_GetLogicalDriveInformation,
- Controller->V1.NewLogicalDriveInformationDMA)) {
- free_dma_loaf(Controller->PCIDevice, &local_dma);
- return DAC960_Failure(Controller, "GET LOGICAL DRIVE INFORMATION");
- }
- memcpy(&Controller->V1.LogicalDriveInformation,
- Controller->V1.NewLogicalDriveInformation,
- sizeof(DAC960_V1_LogicalDriveInformationArray_T));
-
- for (Channel = 0; Channel < Enquiry2->ActualChannels; Channel++)
- for (TargetID = 0; TargetID < Enquiry2->MaxTargets; TargetID++) {
- if (!DAC960_V1_ExecuteType3D(Controller, DAC960_V1_GetDeviceState,
- Channel, TargetID,
- Controller->V1.NewDeviceStateDMA)) {
- free_dma_loaf(Controller->PCIDevice, &local_dma);
- return DAC960_Failure(Controller, "GET DEVICE STATE");
- }
- memcpy(&Controller->V1.DeviceState[Channel][TargetID],
- Controller->V1.NewDeviceState, sizeof(DAC960_V1_DeviceState_T));
- }
- /*
- Initialize the Controller Model Name and Full Model Name fields.
- */
- switch (Enquiry2->HardwareID.SubModel)
- {
- case DAC960_V1_P_PD_PU:
- if (Enquiry2->SCSICapability.BusSpeed == DAC960_V1_Ultra)
- strcpy(Controller->ModelName, "DAC960PU");
- else strcpy(Controller->ModelName, "DAC960PD");
- break;
- case DAC960_V1_PL:
- strcpy(Controller->ModelName, "DAC960PL");
- break;
- case DAC960_V1_PG:
- strcpy(Controller->ModelName, "DAC960PG");
- break;
- case DAC960_V1_PJ:
- strcpy(Controller->ModelName, "DAC960PJ");
- break;
- case DAC960_V1_PR:
- strcpy(Controller->ModelName, "DAC960PR");
- break;
- case DAC960_V1_PT:
- strcpy(Controller->ModelName, "DAC960PT");
- break;
- case DAC960_V1_PTL0:
- strcpy(Controller->ModelName, "DAC960PTL0");
- break;
- case DAC960_V1_PRL:
- strcpy(Controller->ModelName, "DAC960PRL");
- break;
- case DAC960_V1_PTL1:
- strcpy(Controller->ModelName, "DAC960PTL1");
- break;
- case DAC960_V1_1164P:
- strcpy(Controller->ModelName, "DAC1164P");
- break;
- default:
- free_dma_loaf(Controller->PCIDevice, &local_dma);
- return DAC960_Failure(Controller, "MODEL VERIFICATION");
- }
- strcpy(Controller->FullModelName, "Mylex ");
- strcat(Controller->FullModelName, Controller->ModelName);
- /*
- Initialize the Controller Firmware Version field and verify that it
- is a supported firmware version. The supported firmware versions are:
-
- DAC1164P 5.06 and above
- DAC960PTL/PRL/PJ/PG 4.06 and above
- DAC960PU/PD/PL 3.51 and above
- DAC960PU/PD/PL/P 2.73 and above
- */
-#if defined(CONFIG_ALPHA)
- /*
- DEC Alpha machines were often equipped with DAC960 cards that were
- OEMed from Mylex, and had their own custom firmware. Version 2.70,
- the last custom FW revision to be released by DEC for these older
- controllers, appears to work quite well with this driver.
-
- Cards tested successfully were several versions each of the PD and
- PU, called by DEC the KZPSC and KZPAC, respectively, and having
- the Manufacturer Numbers (from Mylex), usually on a sticker on the
- back of the board, of:
-
- KZPSC: D040347 (1-channel) or D040348 (2-channel) or D040349 (3-channel)
- KZPAC: D040395 (1-channel) or D040396 (2-channel) or D040397 (3-channel)
- */
-# define FIRMWARE_27X "2.70"
-#else
-# define FIRMWARE_27X "2.73"
-#endif
-
- if (Enquiry2->FirmwareID.MajorVersion == 0)
- {
- Enquiry2->FirmwareID.MajorVersion =
- Controller->V1.Enquiry.MajorFirmwareVersion;
- Enquiry2->FirmwareID.MinorVersion =
- Controller->V1.Enquiry.MinorFirmwareVersion;
- Enquiry2->FirmwareID.FirmwareType = '0';
- Enquiry2->FirmwareID.TurnID = 0;
- }
- snprintf(Controller->FirmwareVersion, sizeof(Controller->FirmwareVersion),
- "%d.%02d-%c-%02d",
- Enquiry2->FirmwareID.MajorVersion,
- Enquiry2->FirmwareID.MinorVersion,
- Enquiry2->FirmwareID.FirmwareType,
- Enquiry2->FirmwareID.TurnID);
- if (!((Controller->FirmwareVersion[0] == '5' &&
- strcmp(Controller->FirmwareVersion, "5.06") >= 0) ||
- (Controller->FirmwareVersion[0] == '4' &&
- strcmp(Controller->FirmwareVersion, "4.06") >= 0) ||
- (Controller->FirmwareVersion[0] == '3' &&
- strcmp(Controller->FirmwareVersion, "3.51") >= 0) ||
- (Controller->FirmwareVersion[0] == '2' &&
- strcmp(Controller->FirmwareVersion, FIRMWARE_27X) >= 0)))
- {
- DAC960_Failure(Controller, "FIRMWARE VERSION VERIFICATION");
- DAC960_Error("Firmware Version = '%s'\n", Controller,
- Controller->FirmwareVersion);
- free_dma_loaf(Controller->PCIDevice, &local_dma);
- return false;
- }
- /*
- Initialize the Controller Channels, Targets, Memory Size, and SAF-TE
- Enclosure Management Enabled fields.
- */
- Controller->Channels = Enquiry2->ActualChannels;
- Controller->Targets = Enquiry2->MaxTargets;
- Controller->MemorySize = Enquiry2->MemorySize >> 20;
- Controller->V1.SAFTE_EnclosureManagementEnabled =
- (Enquiry2->FaultManagementType == DAC960_V1_SAFTE);
- /*
- Initialize the Controller Queue Depth, Driver Queue Depth, Logical Drive
- Count, Maximum Blocks per Command, Controller Scatter/Gather Limit, and
- Driver Scatter/Gather Limit. The Driver Queue Depth must be at most one
- less than the Controller Queue Depth to allow for an automatic drive
- rebuild operation.
- */
- Controller->ControllerQueueDepth = Controller->V1.Enquiry.MaxCommands;
- Controller->DriverQueueDepth = Controller->ControllerQueueDepth - 1;
- if (Controller->DriverQueueDepth > DAC960_MaxDriverQueueDepth)
- Controller->DriverQueueDepth = DAC960_MaxDriverQueueDepth;
- Controller->LogicalDriveCount =
- Controller->V1.Enquiry.NumberOfLogicalDrives;
- Controller->MaxBlocksPerCommand = Enquiry2->MaxBlocksPerCommand;
- Controller->ControllerScatterGatherLimit = Enquiry2->MaxScatterGatherEntries;
- Controller->DriverScatterGatherLimit =
- Controller->ControllerScatterGatherLimit;
- if (Controller->DriverScatterGatherLimit > DAC960_V1_ScatterGatherLimit)
- Controller->DriverScatterGatherLimit = DAC960_V1_ScatterGatherLimit;
- /*
- Initialize the Stripe Size, Segment Size, and Geometry Translation.
- */
- Controller->V1.StripeSize = Config2->BlocksPerStripe * Config2->BlockFactor
- >> (10 - DAC960_BlockSizeBits);
- Controller->V1.SegmentSize = Config2->BlocksPerCacheLine * Config2->BlockFactor
- >> (10 - DAC960_BlockSizeBits);
- switch (Config2->DriveGeometry)
- {
- case DAC960_V1_Geometry_128_32:
- Controller->V1.GeometryTranslationHeads = 128;
- Controller->V1.GeometryTranslationSectors = 32;
- break;
- case DAC960_V1_Geometry_255_63:
- Controller->V1.GeometryTranslationHeads = 255;
- Controller->V1.GeometryTranslationSectors = 63;
- break;
- default:
- free_dma_loaf(Controller->PCIDevice, &local_dma);
- return DAC960_Failure(Controller, "CONFIG2 DRIVE GEOMETRY");
- }
- /*
- Initialize the Background Initialization Status.
- */
- if ((Controller->FirmwareVersion[0] == '4' &&
- strcmp(Controller->FirmwareVersion, "4.08") >= 0) ||
- (Controller->FirmwareVersion[0] == '5' &&
- strcmp(Controller->FirmwareVersion, "5.08") >= 0))
- {
- Controller->V1.BackgroundInitializationStatusSupported = true;
- DAC960_V1_ExecuteType3B(Controller,
- DAC960_V1_BackgroundInitializationControl, 0x20,
- Controller->
- V1.BackgroundInitializationStatusDMA);
- memcpy(&Controller->V1.LastBackgroundInitializationStatus,
- Controller->V1.BackgroundInitializationStatus,
- sizeof(DAC960_V1_BackgroundInitializationStatus_T));
- }
- /*
- Initialize the Logical Drive Initially Accessible flag.
- */
- for (LogicalDriveNumber = 0;
- LogicalDriveNumber < Controller->LogicalDriveCount;
- LogicalDriveNumber++)
- if (Controller->V1.LogicalDriveInformation
- [LogicalDriveNumber].LogicalDriveState !=
- DAC960_V1_LogicalDrive_Offline)
- Controller->LogicalDriveInitiallyAccessible[LogicalDriveNumber] = true;
- Controller->V1.LastRebuildStatus = DAC960_V1_NoRebuildOrCheckInProgress;
- free_dma_loaf(Controller->PCIDevice, &local_dma);
- return true;
-}
-
-
-/*
- DAC960_V2_ReadControllerConfiguration reads the Configuration Information
- from DAC960 V2 Firmware Controllers and initializes the Controller structure.
-*/
-
-static bool DAC960_V2_ReadControllerConfiguration(DAC960_Controller_T
- *Controller)
-{
- DAC960_V2_ControllerInfo_T *ControllerInfo =
- &Controller->V2.ControllerInformation;
- unsigned short LogicalDeviceNumber = 0;
- int ModelNameLength;
-
- /* Get data into dma-able area, then copy into permanent location */
- if (!DAC960_V2_NewControllerInfo(Controller))
- return DAC960_Failure(Controller, "GET CONTROLLER INFO");
- memcpy(ControllerInfo, Controller->V2.NewControllerInformation,
- sizeof(DAC960_V2_ControllerInfo_T));
-
-
- if (!DAC960_V2_GeneralInfo(Controller))
- return DAC960_Failure(Controller, "GET HEALTH STATUS");
-
- /*
- Initialize the Controller Model Name and Full Model Name fields.
- */
- ModelNameLength = sizeof(ControllerInfo->ControllerName);
- if (ModelNameLength > sizeof(Controller->ModelName)-1)
- ModelNameLength = sizeof(Controller->ModelName)-1;
- memcpy(Controller->ModelName, ControllerInfo->ControllerName,
- ModelNameLength);
- ModelNameLength--;
- while (Controller->ModelName[ModelNameLength] == ' ' ||
- Controller->ModelName[ModelNameLength] == '\0')
- ModelNameLength--;
- Controller->ModelName[++ModelNameLength] = '\0';
- strcpy(Controller->FullModelName, "Mylex ");
- strcat(Controller->FullModelName, Controller->ModelName);
- /*
- Initialize the Controller Firmware Version field.
- */
- sprintf(Controller->FirmwareVersion, "%d.%02d-%02d",
- ControllerInfo->FirmwareMajorVersion,
- ControllerInfo->FirmwareMinorVersion,
- ControllerInfo->FirmwareTurnNumber);
- if (ControllerInfo->FirmwareMajorVersion == 6 &&
- ControllerInfo->FirmwareMinorVersion == 0 &&
- ControllerInfo->FirmwareTurnNumber < 1)
- {
- DAC960_Info("FIRMWARE VERSION %s DOES NOT PROVIDE THE CONTROLLER\n",
- Controller, Controller->FirmwareVersion);
- DAC960_Info("STATUS MONITORING FUNCTIONALITY NEEDED BY THIS DRIVER.\n",
- Controller);
- DAC960_Info("PLEASE UPGRADE TO VERSION 6.00-01 OR ABOVE.\n",
- Controller);
- }
- /*
- Initialize the Controller Channels, Targets, and Memory Size.
- */
- Controller->Channels = ControllerInfo->NumberOfPhysicalChannelsPresent;
- Controller->Targets =
- ControllerInfo->MaximumTargetsPerChannel
- [ControllerInfo->NumberOfPhysicalChannelsPresent-1];
- Controller->MemorySize = ControllerInfo->MemorySizeMB;
- /*
- Initialize the Controller Queue Depth, Driver Queue Depth, Logical Drive
- Count, Maximum Blocks per Command, Controller Scatter/Gather Limit, and
- Driver Scatter/Gather Limit. The Driver Queue Depth must be at most one
- less than the Controller Queue Depth to allow for an automatic drive
- rebuild operation.
- */
- Controller->ControllerQueueDepth = ControllerInfo->MaximumParallelCommands;
- Controller->DriverQueueDepth = Controller->ControllerQueueDepth - 1;
- if (Controller->DriverQueueDepth > DAC960_MaxDriverQueueDepth)
- Controller->DriverQueueDepth = DAC960_MaxDriverQueueDepth;
- Controller->LogicalDriveCount = ControllerInfo->LogicalDevicesPresent;
- Controller->MaxBlocksPerCommand =
- ControllerInfo->MaximumDataTransferSizeInBlocks;
- Controller->ControllerScatterGatherLimit =
- ControllerInfo->MaximumScatterGatherEntries;
- Controller->DriverScatterGatherLimit =
- Controller->ControllerScatterGatherLimit;
- if (Controller->DriverScatterGatherLimit > DAC960_V2_ScatterGatherLimit)
- Controller->DriverScatterGatherLimit = DAC960_V2_ScatterGatherLimit;
- /*
- Initialize the Logical Device Information.
- */
- while (true)
- {
- DAC960_V2_LogicalDeviceInfo_T *NewLogicalDeviceInfo =
- Controller->V2.NewLogicalDeviceInformation;
- DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo;
- DAC960_V2_PhysicalDevice_T PhysicalDevice;
-
- if (!DAC960_V2_NewLogicalDeviceInfo(Controller, LogicalDeviceNumber))
- break;
- LogicalDeviceNumber = NewLogicalDeviceInfo->LogicalDeviceNumber;
- if (LogicalDeviceNumber >= DAC960_MaxLogicalDrives) {
- DAC960_Error("DAC960: Logical Drive Number %d not supported\n",
- Controller, LogicalDeviceNumber);
- break;
- }
- if (NewLogicalDeviceInfo->DeviceBlockSizeInBytes != DAC960_BlockSize) {
- DAC960_Error("DAC960: Logical Drive Block Size %d not supported\n",
- Controller, NewLogicalDeviceInfo->DeviceBlockSizeInBytes);
- LogicalDeviceNumber++;
- continue;
- }
- PhysicalDevice.Controller = 0;
- PhysicalDevice.Channel = NewLogicalDeviceInfo->Channel;
- PhysicalDevice.TargetID = NewLogicalDeviceInfo->TargetID;
- PhysicalDevice.LogicalUnit = NewLogicalDeviceInfo->LogicalUnit;
- Controller->V2.LogicalDriveToVirtualDevice[LogicalDeviceNumber] =
- PhysicalDevice;
- if (NewLogicalDeviceInfo->LogicalDeviceState !=
- DAC960_V2_LogicalDevice_Offline)
- Controller->LogicalDriveInitiallyAccessible[LogicalDeviceNumber] = true;
- LogicalDeviceInfo = kmalloc(sizeof(DAC960_V2_LogicalDeviceInfo_T),
- GFP_ATOMIC);
- if (LogicalDeviceInfo == NULL)
- return DAC960_Failure(Controller, "LOGICAL DEVICE ALLOCATION");
- Controller->V2.LogicalDeviceInformation[LogicalDeviceNumber] =
- LogicalDeviceInfo;
- memcpy(LogicalDeviceInfo, NewLogicalDeviceInfo,
- sizeof(DAC960_V2_LogicalDeviceInfo_T));
- LogicalDeviceNumber++;
- }
- return true;
-}
-
-
-/*
- DAC960_ReportControllerConfiguration reports the Configuration Information
- for Controller.
-*/
-
-static bool DAC960_ReportControllerConfiguration(DAC960_Controller_T
- *Controller)
-{
- DAC960_Info("Configuring Mylex %s PCI RAID Controller\n",
- Controller, Controller->ModelName);
- DAC960_Info(" Firmware Version: %s, Channels: %d, Memory Size: %dMB\n",
- Controller, Controller->FirmwareVersion,
- Controller->Channels, Controller->MemorySize);
- DAC960_Info(" PCI Bus: %d, Device: %d, Function: %d, I/O Address: ",
- Controller, Controller->Bus,
- Controller->Device, Controller->Function);
- if (Controller->IO_Address == 0)
- DAC960_Info("Unassigned\n", Controller);
- else DAC960_Info("0x%X\n", Controller, Controller->IO_Address);
- DAC960_Info(" PCI Address: 0x%X mapped at 0x%lX, IRQ Channel: %d\n",
- Controller, Controller->PCI_Address,
- (unsigned long) Controller->BaseAddress,
- Controller->IRQ_Channel);
- DAC960_Info(" Controller Queue Depth: %d, "
- "Maximum Blocks per Command: %d\n",
- Controller, Controller->ControllerQueueDepth,
- Controller->MaxBlocksPerCommand);
- DAC960_Info(" Driver Queue Depth: %d, "
- "Scatter/Gather Limit: %d of %d Segments\n",
- Controller, Controller->DriverQueueDepth,
- Controller->DriverScatterGatherLimit,
- Controller->ControllerScatterGatherLimit);
- if (Controller->FirmwareType == DAC960_V1_Controller)
- {
- DAC960_Info(" Stripe Size: %dKB, Segment Size: %dKB, "
- "BIOS Geometry: %d/%d\n", Controller,
- Controller->V1.StripeSize,
- Controller->V1.SegmentSize,
- Controller->V1.GeometryTranslationHeads,
- Controller->V1.GeometryTranslationSectors);
- if (Controller->V1.SAFTE_EnclosureManagementEnabled)
- DAC960_Info(" SAF-TE Enclosure Management Enabled\n", Controller);
- }
- return true;
-}
-
-
-/*
- DAC960_V1_ReadDeviceConfiguration reads the Device Configuration Information
- for DAC960 V1 Firmware Controllers by requesting the SCSI Inquiry and SCSI
- Inquiry Unit Serial Number information for each device connected to
- Controller.
-*/
-
-static bool DAC960_V1_ReadDeviceConfiguration(DAC960_Controller_T
- *Controller)
-{
- struct dma_loaf local_dma;
-
- dma_addr_t DCDBs_dma[DAC960_V1_MaxChannels];
- DAC960_V1_DCDB_T *DCDBs_cpu[DAC960_V1_MaxChannels];
-
- dma_addr_t SCSI_Inquiry_dma[DAC960_V1_MaxChannels];
- DAC960_SCSI_Inquiry_T *SCSI_Inquiry_cpu[DAC960_V1_MaxChannels];
-
- dma_addr_t SCSI_NewInquiryUnitSerialNumberDMA[DAC960_V1_MaxChannels];
- DAC960_SCSI_Inquiry_UnitSerialNumber_T *SCSI_NewInquiryUnitSerialNumberCPU[DAC960_V1_MaxChannels];
-
- struct completion Completions[DAC960_V1_MaxChannels];
- unsigned long flags;
- int Channel, TargetID;
-
- if (!init_dma_loaf(Controller->PCIDevice, &local_dma,
- DAC960_V1_MaxChannels*(sizeof(DAC960_V1_DCDB_T) +
- sizeof(DAC960_SCSI_Inquiry_T) +
- sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T))))
- return DAC960_Failure(Controller,
- "DMA ALLOCATION FAILED IN ReadDeviceConfiguration");
-
- for (Channel = 0; Channel < Controller->Channels; Channel++) {
- DCDBs_cpu[Channel] = slice_dma_loaf(&local_dma,
- sizeof(DAC960_V1_DCDB_T), DCDBs_dma + Channel);
- SCSI_Inquiry_cpu[Channel] = slice_dma_loaf(&local_dma,
- sizeof(DAC960_SCSI_Inquiry_T),
- SCSI_Inquiry_dma + Channel);
- SCSI_NewInquiryUnitSerialNumberCPU[Channel] = slice_dma_loaf(&local_dma,
- sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T),
- SCSI_NewInquiryUnitSerialNumberDMA + Channel);
- }
-
- for (TargetID = 0; TargetID < Controller->Targets; TargetID++)
- {
- /*
- * For each channel, submit a probe for a device on that channel.
- * The timeout interval for a device that is present is 10 seconds.
- * With this approach, the timeout periods can elapse in parallel
- * on each channel.
- */
- for (Channel = 0; Channel < Controller->Channels; Channel++)
- {
- dma_addr_t NewInquiryStandardDataDMA = SCSI_Inquiry_dma[Channel];
- DAC960_V1_DCDB_T *DCDB = DCDBs_cpu[Channel];
- dma_addr_t DCDB_dma = DCDBs_dma[Channel];
- DAC960_Command_T *Command = Controller->Commands[Channel];
- struct completion *Completion = &Completions[Channel];
-
- init_completion(Completion);
- DAC960_V1_ClearCommand(Command);
- Command->CommandType = DAC960_ImmediateCommand;
- Command->Completion = Completion;
- Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_DCDB;
- Command->V1.CommandMailbox.Type3.BusAddress = DCDB_dma;
- DCDB->Channel = Channel;
- DCDB->TargetID = TargetID;
- DCDB->Direction = DAC960_V1_DCDB_DataTransferDeviceToSystem;
- DCDB->EarlyStatus = false;
- DCDB->Timeout = DAC960_V1_DCDB_Timeout_10_seconds;
- DCDB->NoAutomaticRequestSense = false;
- DCDB->DisconnectPermitted = true;
- DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_T);
- DCDB->BusAddress = NewInquiryStandardDataDMA;
- DCDB->CDBLength = 6;
- DCDB->TransferLengthHigh4 = 0;
- DCDB->SenseLength = sizeof(DCDB->SenseData);
- DCDB->CDB[0] = 0x12; /* INQUIRY */
- DCDB->CDB[1] = 0; /* EVPD = 0 */
- DCDB->CDB[2] = 0; /* Page Code */
- DCDB->CDB[3] = 0; /* Reserved */
- DCDB->CDB[4] = sizeof(DAC960_SCSI_Inquiry_T);
- DCDB->CDB[5] = 0; /* Control */
-
- spin_lock_irqsave(&Controller->queue_lock, flags);
- DAC960_QueueCommand(Command);
- spin_unlock_irqrestore(&Controller->queue_lock, flags);
- }
- /*
- * Wait for the problems submitted in the previous loop
- * to complete. On the probes that are successful,
- * get the serial number of the device that was found.
- */
- for (Channel = 0; Channel < Controller->Channels; Channel++)
- {
- DAC960_SCSI_Inquiry_T *InquiryStandardData =
- &Controller->V1.InquiryStandardData[Channel][TargetID];
- DAC960_SCSI_Inquiry_T *NewInquiryStandardData = SCSI_Inquiry_cpu[Channel];
- dma_addr_t NewInquiryUnitSerialNumberDMA =
- SCSI_NewInquiryUnitSerialNumberDMA[Channel];
- DAC960_SCSI_Inquiry_UnitSerialNumber_T *NewInquiryUnitSerialNumber =
- SCSI_NewInquiryUnitSerialNumberCPU[Channel];
- DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber =
- &Controller->V1.InquiryUnitSerialNumber[Channel][TargetID];
- DAC960_Command_T *Command = Controller->Commands[Channel];
- DAC960_V1_DCDB_T *DCDB = DCDBs_cpu[Channel];
- struct completion *Completion = &Completions[Channel];
-
- wait_for_completion(Completion);
-
- if (Command->V1.CommandStatus != DAC960_V1_NormalCompletion) {
- memset(InquiryStandardData, 0, sizeof(DAC960_SCSI_Inquiry_T));
- InquiryStandardData->PeripheralDeviceType = 0x1F;
- continue;
- } else
- memcpy(InquiryStandardData, NewInquiryStandardData, sizeof(DAC960_SCSI_Inquiry_T));
-
- /* Preserve Channel and TargetID values from the previous loop */
- Command->Completion = Completion;
- DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T);
- DCDB->BusAddress = NewInquiryUnitSerialNumberDMA;
- DCDB->SenseLength = sizeof(DCDB->SenseData);
- DCDB->CDB[0] = 0x12; /* INQUIRY */
- DCDB->CDB[1] = 1; /* EVPD = 1 */
- DCDB->CDB[2] = 0x80; /* Page Code */
- DCDB->CDB[3] = 0; /* Reserved */
- DCDB->CDB[4] = sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T);
- DCDB->CDB[5] = 0; /* Control */
-
- spin_lock_irqsave(&Controller->queue_lock, flags);
- DAC960_QueueCommand(Command);
- spin_unlock_irqrestore(&Controller->queue_lock, flags);
- wait_for_completion(Completion);
-
- if (Command->V1.CommandStatus != DAC960_V1_NormalCompletion) {
- memset(InquiryUnitSerialNumber, 0,
- sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T));
- InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F;
- } else
- memcpy(InquiryUnitSerialNumber, NewInquiryUnitSerialNumber,
- sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T));
- }
- }
- free_dma_loaf(Controller->PCIDevice, &local_dma);
- return true;
-}
-
-
-/*
- DAC960_V2_ReadDeviceConfiguration reads the Device Configuration Information
- for DAC960 V2 Firmware Controllers by requesting the Physical Device
- Information and SCSI Inquiry Unit Serial Number information for each
- device connected to Controller.
-*/
-
-static bool DAC960_V2_ReadDeviceConfiguration(DAC960_Controller_T
- *Controller)
-{
- unsigned char Channel = 0, TargetID = 0, LogicalUnit = 0;
- unsigned short PhysicalDeviceIndex = 0;
-
- while (true)
- {
- DAC960_V2_PhysicalDeviceInfo_T *NewPhysicalDeviceInfo =
- Controller->V2.NewPhysicalDeviceInformation;
- DAC960_V2_PhysicalDeviceInfo_T *PhysicalDeviceInfo;
- DAC960_SCSI_Inquiry_UnitSerialNumber_T *NewInquiryUnitSerialNumber =
- Controller->V2.NewInquiryUnitSerialNumber;
- DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber;
-
- if (!DAC960_V2_NewPhysicalDeviceInfo(Controller, Channel, TargetID, LogicalUnit))
- break;
-
- PhysicalDeviceInfo = kmalloc(sizeof(DAC960_V2_PhysicalDeviceInfo_T),
- GFP_ATOMIC);
- if (PhysicalDeviceInfo == NULL)
- return DAC960_Failure(Controller, "PHYSICAL DEVICE ALLOCATION");
- Controller->V2.PhysicalDeviceInformation[PhysicalDeviceIndex] =
- PhysicalDeviceInfo;
- memcpy(PhysicalDeviceInfo, NewPhysicalDeviceInfo,
- sizeof(DAC960_V2_PhysicalDeviceInfo_T));
-
- InquiryUnitSerialNumber = kmalloc(
- sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T), GFP_ATOMIC);
- if (InquiryUnitSerialNumber == NULL) {
- kfree(PhysicalDeviceInfo);
- return DAC960_Failure(Controller, "SERIAL NUMBER ALLOCATION");
- }
- Controller->V2.InquiryUnitSerialNumber[PhysicalDeviceIndex] =
- InquiryUnitSerialNumber;
-
- Channel = NewPhysicalDeviceInfo->Channel;
- TargetID = NewPhysicalDeviceInfo->TargetID;
- LogicalUnit = NewPhysicalDeviceInfo->LogicalUnit;
-
- /*
- Some devices do NOT have Unit Serial Numbers.
- This command fails for them. But, we still want to
- remember those devices are there. Construct a
- UnitSerialNumber structure for the failure case.
- */
- if (!DAC960_V2_NewInquiryUnitSerialNumber(Controller, Channel, TargetID, LogicalUnit)) {
- memset(InquiryUnitSerialNumber, 0,
- sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T));
- InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F;
- } else
- memcpy(InquiryUnitSerialNumber, NewInquiryUnitSerialNumber,
- sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T));
-
- PhysicalDeviceIndex++;
- LogicalUnit++;
- }
- return true;
-}
-
-
-/*
- DAC960_SanitizeInquiryData sanitizes the Vendor, Model, Revision, and
- Product Serial Number fields of the Inquiry Standard Data and Inquiry
- Unit Serial Number structures.
-*/
-
-static void DAC960_SanitizeInquiryData(DAC960_SCSI_Inquiry_T
- *InquiryStandardData,
- DAC960_SCSI_Inquiry_UnitSerialNumber_T
- *InquiryUnitSerialNumber,
- unsigned char *Vendor,
- unsigned char *Model,
- unsigned char *Revision,
- unsigned char *SerialNumber)
-{
- int SerialNumberLength, i;
- if (InquiryStandardData->PeripheralDeviceType == 0x1F) return;
- for (i = 0; i < sizeof(InquiryStandardData->VendorIdentification); i++)
- {
- unsigned char VendorCharacter =
- InquiryStandardData->VendorIdentification[i];
- Vendor[i] = (VendorCharacter >= ' ' && VendorCharacter <= '~'
- ? VendorCharacter : ' ');
- }
- Vendor[sizeof(InquiryStandardData->VendorIdentification)] = '\0';
- for (i = 0; i < sizeof(InquiryStandardData->ProductIdentification); i++)
- {
- unsigned char ModelCharacter =
- InquiryStandardData->ProductIdentification[i];
- Model[i] = (ModelCharacter >= ' ' && ModelCharacter <= '~'
- ? ModelCharacter : ' ');
- }
- Model[sizeof(InquiryStandardData->ProductIdentification)] = '\0';
- for (i = 0; i < sizeof(InquiryStandardData->ProductRevisionLevel); i++)
- {
- unsigned char RevisionCharacter =
- InquiryStandardData->ProductRevisionLevel[i];
- Revision[i] = (RevisionCharacter >= ' ' && RevisionCharacter <= '~'
- ? RevisionCharacter : ' ');
- }
- Revision[sizeof(InquiryStandardData->ProductRevisionLevel)] = '\0';
- if (InquiryUnitSerialNumber->PeripheralDeviceType == 0x1F) return;
- SerialNumberLength = InquiryUnitSerialNumber->PageLength;
- if (SerialNumberLength >
- sizeof(InquiryUnitSerialNumber->ProductSerialNumber))
- SerialNumberLength = sizeof(InquiryUnitSerialNumber->ProductSerialNumber);
- for (i = 0; i < SerialNumberLength; i++)
- {
- unsigned char SerialNumberCharacter =
- InquiryUnitSerialNumber->ProductSerialNumber[i];
- SerialNumber[i] =
- (SerialNumberCharacter >= ' ' && SerialNumberCharacter <= '~'
- ? SerialNumberCharacter : ' ');
- }
- SerialNumber[SerialNumberLength] = '\0';
-}
-
-
-/*
- DAC960_V1_ReportDeviceConfiguration reports the Device Configuration
- Information for DAC960 V1 Firmware Controllers.
-*/
-
-static bool DAC960_V1_ReportDeviceConfiguration(DAC960_Controller_T
- *Controller)
-{
- int LogicalDriveNumber, Channel, TargetID;
- DAC960_Info(" Physical Devices:\n", Controller);
- for (Channel = 0; Channel < Controller->Channels; Channel++)
- for (TargetID = 0; TargetID < Controller->Targets; TargetID++)
- {
- DAC960_SCSI_Inquiry_T *InquiryStandardData =
- &Controller->V1.InquiryStandardData[Channel][TargetID];
- DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber =
- &Controller->V1.InquiryUnitSerialNumber[Channel][TargetID];
- DAC960_V1_DeviceState_T *DeviceState =
- &Controller->V1.DeviceState[Channel][TargetID];
- DAC960_V1_ErrorTableEntry_T *ErrorEntry =
- &Controller->V1.ErrorTable.ErrorTableEntries[Channel][TargetID];
- char Vendor[1+sizeof(InquiryStandardData->VendorIdentification)];
- char Model[1+sizeof(InquiryStandardData->ProductIdentification)];
- char Revision[1+sizeof(InquiryStandardData->ProductRevisionLevel)];
- char SerialNumber[1+sizeof(InquiryUnitSerialNumber
- ->ProductSerialNumber)];
- if (InquiryStandardData->PeripheralDeviceType == 0x1F) continue;
- DAC960_SanitizeInquiryData(InquiryStandardData, InquiryUnitSerialNumber,
- Vendor, Model, Revision, SerialNumber);
- DAC960_Info(" %d:%d%s Vendor: %s Model: %s Revision: %s\n",
- Controller, Channel, TargetID, (TargetID < 10 ? " " : ""),
- Vendor, Model, Revision);
- if (InquiryUnitSerialNumber->PeripheralDeviceType != 0x1F)
- DAC960_Info(" Serial Number: %s\n", Controller, SerialNumber);
- if (DeviceState->Present &&
- DeviceState->DeviceType == DAC960_V1_DiskType)
- {
- if (Controller->V1.DeviceResetCount[Channel][TargetID] > 0)
- DAC960_Info(" Disk Status: %s, %u blocks, %d resets\n",
- Controller,
- (DeviceState->DeviceState == DAC960_V1_Device_Dead
- ? "Dead"
- : DeviceState->DeviceState
- == DAC960_V1_Device_WriteOnly
- ? "Write-Only"
- : DeviceState->DeviceState
- == DAC960_V1_Device_Online
- ? "Online" : "Standby"),
- DeviceState->DiskSize,
- Controller->V1.DeviceResetCount[Channel][TargetID]);
- else
- DAC960_Info(" Disk Status: %s, %u blocks\n", Controller,
- (DeviceState->DeviceState == DAC960_V1_Device_Dead
- ? "Dead"
- : DeviceState->DeviceState
- == DAC960_V1_Device_WriteOnly
- ? "Write-Only"
- : DeviceState->DeviceState
- == DAC960_V1_Device_Online
- ? "Online" : "Standby"),
- DeviceState->DiskSize);
- }
- if (ErrorEntry->ParityErrorCount > 0 ||
- ErrorEntry->SoftErrorCount > 0 ||
- ErrorEntry->HardErrorCount > 0 ||
- ErrorEntry->MiscErrorCount > 0)
- DAC960_Info(" Errors - Parity: %d, Soft: %d, "
- "Hard: %d, Misc: %d\n", Controller,
- ErrorEntry->ParityErrorCount,
- ErrorEntry->SoftErrorCount,
- ErrorEntry->HardErrorCount,
- ErrorEntry->MiscErrorCount);
- }
- DAC960_Info(" Logical Drives:\n", Controller);
- for (LogicalDriveNumber = 0;
- LogicalDriveNumber < Controller->LogicalDriveCount;
- LogicalDriveNumber++)
- {
- DAC960_V1_LogicalDriveInformation_T *LogicalDriveInformation =
- &Controller->V1.LogicalDriveInformation[LogicalDriveNumber];
- DAC960_Info(" /dev/rd/c%dd%d: RAID-%d, %s, %u blocks, %s\n",
- Controller, Controller->ControllerNumber, LogicalDriveNumber,
- LogicalDriveInformation->RAIDLevel,
- (LogicalDriveInformation->LogicalDriveState
- == DAC960_V1_LogicalDrive_Online
- ? "Online"
- : LogicalDriveInformation->LogicalDriveState
- == DAC960_V1_LogicalDrive_Critical
- ? "Critical" : "Offline"),
- LogicalDriveInformation->LogicalDriveSize,
- (LogicalDriveInformation->WriteBack
- ? "Write Back" : "Write Thru"));
- }
- return true;
-}
-
-
-/*
- DAC960_V2_ReportDeviceConfiguration reports the Device Configuration
- Information for DAC960 V2 Firmware Controllers.
-*/
-
-static bool DAC960_V2_ReportDeviceConfiguration(DAC960_Controller_T
- *Controller)
-{
- int PhysicalDeviceIndex, LogicalDriveNumber;
- DAC960_Info(" Physical Devices:\n", Controller);
- for (PhysicalDeviceIndex = 0;
- PhysicalDeviceIndex < DAC960_V2_MaxPhysicalDevices;
- PhysicalDeviceIndex++)
- {
- DAC960_V2_PhysicalDeviceInfo_T *PhysicalDeviceInfo =
- Controller->V2.PhysicalDeviceInformation[PhysicalDeviceIndex];
- DAC960_SCSI_Inquiry_T *InquiryStandardData =
- (DAC960_SCSI_Inquiry_T *) &PhysicalDeviceInfo->SCSI_InquiryData;
- DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber =
- Controller->V2.InquiryUnitSerialNumber[PhysicalDeviceIndex];
- char Vendor[1+sizeof(InquiryStandardData->VendorIdentification)];
- char Model[1+sizeof(InquiryStandardData->ProductIdentification)];
- char Revision[1+sizeof(InquiryStandardData->ProductRevisionLevel)];
- char SerialNumber[1+sizeof(InquiryUnitSerialNumber->ProductSerialNumber)];
- if (PhysicalDeviceInfo == NULL) break;
- DAC960_SanitizeInquiryData(InquiryStandardData, InquiryUnitSerialNumber,
- Vendor, Model, Revision, SerialNumber);
- DAC960_Info(" %d:%d%s Vendor: %s Model: %s Revision: %s\n",
- Controller,
- PhysicalDeviceInfo->Channel,
- PhysicalDeviceInfo->TargetID,
- (PhysicalDeviceInfo->TargetID < 10 ? " " : ""),
- Vendor, Model, Revision);
- if (PhysicalDeviceInfo->NegotiatedSynchronousMegaTransfers == 0)
- DAC960_Info(" %sAsynchronous\n", Controller,
- (PhysicalDeviceInfo->NegotiatedDataWidthBits == 16
- ? "Wide " :""));
- else
- DAC960_Info(" %sSynchronous at %d MB/sec\n", Controller,
- (PhysicalDeviceInfo->NegotiatedDataWidthBits == 16
- ? "Wide " :""),
- (PhysicalDeviceInfo->NegotiatedSynchronousMegaTransfers
- * PhysicalDeviceInfo->NegotiatedDataWidthBits/8));
- if (InquiryUnitSerialNumber->PeripheralDeviceType != 0x1F)
- DAC960_Info(" Serial Number: %s\n", Controller, SerialNumber);
- if (PhysicalDeviceInfo->PhysicalDeviceState ==
- DAC960_V2_Device_Unconfigured)
- continue;
- DAC960_Info(" Disk Status: %s, %u blocks\n", Controller,
- (PhysicalDeviceInfo->PhysicalDeviceState
- == DAC960_V2_Device_Online
- ? "Online"
- : PhysicalDeviceInfo->PhysicalDeviceState
- == DAC960_V2_Device_Rebuild
- ? "Rebuild"
- : PhysicalDeviceInfo->PhysicalDeviceState
- == DAC960_V2_Device_Missing
- ? "Missing"
- : PhysicalDeviceInfo->PhysicalDeviceState
- == DAC960_V2_Device_Critical
- ? "Critical"
- : PhysicalDeviceInfo->PhysicalDeviceState
- == DAC960_V2_Device_Dead
- ? "Dead"
- : PhysicalDeviceInfo->PhysicalDeviceState
- == DAC960_V2_Device_SuspectedDead
- ? "Suspected-Dead"
- : PhysicalDeviceInfo->PhysicalDeviceState
- == DAC960_V2_Device_CommandedOffline
- ? "Commanded-Offline"
- : PhysicalDeviceInfo->PhysicalDeviceState
- == DAC960_V2_Device_Standby
- ? "Standby" : "Unknown"),
- PhysicalDeviceInfo->ConfigurableDeviceSize);
- if (PhysicalDeviceInfo->ParityErrors == 0 &&
- PhysicalDeviceInfo->SoftErrors == 0 &&
- PhysicalDeviceInfo->HardErrors == 0 &&
- PhysicalDeviceInfo->MiscellaneousErrors == 0 &&
- PhysicalDeviceInfo->CommandTimeouts == 0 &&
- PhysicalDeviceInfo->Retries == 0 &&
- PhysicalDeviceInfo->Aborts == 0 &&
- PhysicalDeviceInfo->PredictedFailuresDetected == 0)
- continue;
- DAC960_Info(" Errors - Parity: %d, Soft: %d, "
- "Hard: %d, Misc: %d\n", Controller,
- PhysicalDeviceInfo->ParityErrors,
- PhysicalDeviceInfo->SoftErrors,
- PhysicalDeviceInfo->HardErrors,
- PhysicalDeviceInfo->MiscellaneousErrors);
- DAC960_Info(" Timeouts: %d, Retries: %d, "
- "Aborts: %d, Predicted: %d\n", Controller,
- PhysicalDeviceInfo->CommandTimeouts,
- PhysicalDeviceInfo->Retries,
- PhysicalDeviceInfo->Aborts,
- PhysicalDeviceInfo->PredictedFailuresDetected);
- }
- DAC960_Info(" Logical Drives:\n", Controller);
- for (LogicalDriveNumber = 0;
- LogicalDriveNumber < DAC960_MaxLogicalDrives;
- LogicalDriveNumber++)
- {
- DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo =
- Controller->V2.LogicalDeviceInformation[LogicalDriveNumber];
- static const unsigned char *ReadCacheStatus[] = {
- "Read Cache Disabled",
- "Read Cache Enabled",
- "Read Ahead Enabled",
- "Intelligent Read Ahead Enabled",
- "-", "-", "-", "-"
- };
- static const unsigned char *WriteCacheStatus[] = {
- "Write Cache Disabled",
- "Logical Device Read Only",
- "Write Cache Enabled",
- "Intelligent Write Cache Enabled",
- "-", "-", "-", "-"
- };
- unsigned char *GeometryTranslation;
- if (LogicalDeviceInfo == NULL) continue;
- switch (LogicalDeviceInfo->DriveGeometry)
- {
- case DAC960_V2_Geometry_128_32:
- GeometryTranslation = "128/32";
- break;
- case DAC960_V2_Geometry_255_63:
- GeometryTranslation = "255/63";
- break;
- default:
- GeometryTranslation = "Invalid";
- DAC960_Error("Illegal Logical Device Geometry %d\n",
- Controller, LogicalDeviceInfo->DriveGeometry);
- break;
- }
- DAC960_Info(" /dev/rd/c%dd%d: RAID-%d, %s, %u blocks\n",
- Controller, Controller->ControllerNumber, LogicalDriveNumber,
- LogicalDeviceInfo->RAIDLevel,
- (LogicalDeviceInfo->LogicalDeviceState
- == DAC960_V2_LogicalDevice_Online
- ? "Online"
- : LogicalDeviceInfo->LogicalDeviceState
- == DAC960_V2_LogicalDevice_Critical
- ? "Critical" : "Offline"),
- LogicalDeviceInfo->ConfigurableDeviceSize);
- DAC960_Info(" Logical Device %s, BIOS Geometry: %s\n",
- Controller,
- (LogicalDeviceInfo->LogicalDeviceControl
- .LogicalDeviceInitialized
- ? "Initialized" : "Uninitialized"),
- GeometryTranslation);
- if (LogicalDeviceInfo->StripeSize == 0)
- {
- if (LogicalDeviceInfo->CacheLineSize == 0)
- DAC960_Info(" Stripe Size: N/A, "
- "Segment Size: N/A\n", Controller);
- else
- DAC960_Info(" Stripe Size: N/A, "
- "Segment Size: %dKB\n", Controller,
- 1 << (LogicalDeviceInfo->CacheLineSize - 2));
- }
- else
- {
- if (LogicalDeviceInfo->CacheLineSize == 0)
- DAC960_Info(" Stripe Size: %dKB, "
- "Segment Size: N/A\n", Controller,
- 1 << (LogicalDeviceInfo->StripeSize - 2));
- else
- DAC960_Info(" Stripe Size: %dKB, "
- "Segment Size: %dKB\n", Controller,
- 1 << (LogicalDeviceInfo->StripeSize - 2),
- 1 << (LogicalDeviceInfo->CacheLineSize - 2));
- }
- DAC960_Info(" %s, %s\n", Controller,
- ReadCacheStatus[
- LogicalDeviceInfo->LogicalDeviceControl.ReadCache],
- WriteCacheStatus[
- LogicalDeviceInfo->LogicalDeviceControl.WriteCache]);
- if (LogicalDeviceInfo->SoftErrors > 0 ||
- LogicalDeviceInfo->CommandsFailed > 0 ||
- LogicalDeviceInfo->DeferredWriteErrors)
- DAC960_Info(" Errors - Soft: %d, Failed: %d, "
- "Deferred Write: %d\n", Controller,
- LogicalDeviceInfo->SoftErrors,
- LogicalDeviceInfo->CommandsFailed,
- LogicalDeviceInfo->DeferredWriteErrors);
-
- }
- return true;
-}
-
-/*
- DAC960_RegisterBlockDevice registers the Block Device structures
- associated with Controller.
-*/
-
-static bool DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller)
-{
- int MajorNumber = DAC960_MAJOR + Controller->ControllerNumber;
- int n;
-
- /*
- Register the Block Device Major Number for this DAC960 Controller.
- */
- if (register_blkdev(MajorNumber, "dac960") < 0)
- return false;
-
- for (n = 0; n < DAC960_MaxLogicalDrives; n++) {
- struct gendisk *disk = Controller->disks[n];
- struct request_queue *RequestQueue;
-
- /* for now, let all request queues share controller's lock */
- RequestQueue = blk_init_queue(DAC960_RequestFunction,&Controller->queue_lock);
- if (!RequestQueue) {
- printk("DAC960: failure to allocate request queue\n");
- continue;
- }
- Controller->RequestQueue[n] = RequestQueue;
- RequestQueue->queuedata = Controller;
- blk_queue_max_segments(RequestQueue, Controller->DriverScatterGatherLimit);
- blk_queue_max_hw_sectors(RequestQueue, Controller->MaxBlocksPerCommand);
- disk->queue = RequestQueue;
- sprintf(disk->disk_name, "rd/c%dd%d", Controller->ControllerNumber, n);
- disk->major = MajorNumber;
- disk->first_minor = n << DAC960_MaxPartitionsBits;
- disk->fops = &DAC960_BlockDeviceOperations;
- }
- /*
- Indicate the Block Device Registration completed successfully,
- */
- return true;
-}
-
-
-/*
- DAC960_UnregisterBlockDevice unregisters the Block Device structures
- associated with Controller.
-*/
-
-static void DAC960_UnregisterBlockDevice(DAC960_Controller_T *Controller)
-{
- int MajorNumber = DAC960_MAJOR + Controller->ControllerNumber;
- int disk;
-
- /* does order matter when deleting gendisk and cleanup in request queue? */
- for (disk = 0; disk < DAC960_MaxLogicalDrives; disk++) {
- del_gendisk(Controller->disks[disk]);
- blk_cleanup_queue(Controller->RequestQueue[disk]);
- Controller->RequestQueue[disk] = NULL;
- }
-
- /*
- Unregister the Block Device Major Number for this DAC960 Controller.
- */
- unregister_blkdev(MajorNumber, "dac960");
-}
-
-/*
- DAC960_ComputeGenericDiskInfo computes the values for the Generic Disk
- Information Partition Sector Counts and Block Sizes.
-*/
-
-static void DAC960_ComputeGenericDiskInfo(DAC960_Controller_T *Controller)
-{
- int disk;
- for (disk = 0; disk < DAC960_MaxLogicalDrives; disk++)
- set_capacity(Controller->disks[disk], disk_size(Controller, disk));
-}
-
-/*
- DAC960_ReportErrorStatus reports Controller BIOS Messages passed through
- the Error Status Register when the driver performs the BIOS handshaking.
- It returns true for fatal errors and false otherwise.
-*/
-
-static bool DAC960_ReportErrorStatus(DAC960_Controller_T *Controller,
- unsigned char ErrorStatus,
- unsigned char Parameter0,
- unsigned char Parameter1)
-{
- switch (ErrorStatus)
- {
- case 0x00:
- DAC960_Notice("Physical Device %d:%d Not Responding\n",
- Controller, Parameter1, Parameter0);
- break;
- case 0x08:
- if (Controller->DriveSpinUpMessageDisplayed) break;
- DAC960_Notice("Spinning Up Drives\n", Controller);
- Controller->DriveSpinUpMessageDisplayed = true;
- break;
- case 0x30:
- DAC960_Notice("Configuration Checksum Error\n", Controller);
- break;
- case 0x60:
- DAC960_Notice("Mirror Race Recovery Failed\n", Controller);
- break;
- case 0x70:
- DAC960_Notice("Mirror Race Recovery In Progress\n", Controller);
- break;
- case 0x90:
- DAC960_Notice("Physical Device %d:%d COD Mismatch\n",
- Controller, Parameter1, Parameter0);
- break;
- case 0xA0:
- DAC960_Notice("Logical Drive Installation Aborted\n", Controller);
- break;
- case 0xB0:
- DAC960_Notice("Mirror Race On A Critical Logical Drive\n", Controller);
- break;
- case 0xD0:
- DAC960_Notice("New Controller Configuration Found\n", Controller);
- break;
- case 0xF0:
- DAC960_Error("Fatal Memory Parity Error for Controller at\n", Controller);
- return true;
- default:
- DAC960_Error("Unknown Initialization Error %02X for Controller at\n",
- Controller, ErrorStatus);
- return true;
- }
- return false;
-}
-
-
-/*
- * DAC960_DetectCleanup releases the resources that were allocated
- * during DAC960_DetectController(). DAC960_DetectController can
- * has several internal failure points, so not ALL resources may
- * have been allocated. It's important to free only
- * resources that HAVE been allocated. The code below always
- * tests that the resource has been allocated before attempting to
- * free it.
- */
-static void DAC960_DetectCleanup(DAC960_Controller_T *Controller)
-{
- int i;
-
- /* Free the memory mailbox, status, and related structures */
- free_dma_loaf(Controller->PCIDevice, &Controller->DmaPages);
- if (Controller->MemoryMappedAddress) {
- switch(Controller->HardwareType)
- {
- case DAC960_GEM_Controller:
- DAC960_GEM_DisableInterrupts(Controller->BaseAddress);
- break;
- case DAC960_BA_Controller:
- DAC960_BA_DisableInterrupts(Controller->BaseAddress);
- break;
- case DAC960_LP_Controller:
- DAC960_LP_DisableInterrupts(Controller->BaseAddress);
- break;
- case DAC960_LA_Controller:
- DAC960_LA_DisableInterrupts(Controller->BaseAddress);
- break;
- case DAC960_PG_Controller:
- DAC960_PG_DisableInterrupts(Controller->BaseAddress);
- break;
- case DAC960_PD_Controller:
- DAC960_PD_DisableInterrupts(Controller->BaseAddress);
- break;
- case DAC960_P_Controller:
- DAC960_PD_DisableInterrupts(Controller->BaseAddress);
- break;
- }
- iounmap(Controller->MemoryMappedAddress);
- }
- if (Controller->IRQ_Channel)
- free_irq(Controller->IRQ_Channel, Controller);
- if (Controller->IO_Address)
- release_region(Controller->IO_Address, 0x80);
- pci_disable_device(Controller->PCIDevice);
- for (i = 0; (i < DAC960_MaxLogicalDrives) && Controller->disks[i]; i++)
- put_disk(Controller->disks[i]);
- DAC960_Controllers[Controller->ControllerNumber] = NULL;
- kfree(Controller);
-}
-
-
-/*
- DAC960_DetectController detects Mylex DAC960/AcceleRAID/eXtremeRAID
- PCI RAID Controllers by interrogating the PCI Configuration Space for
- Controller Type.
-*/
-
-static DAC960_Controller_T *
-DAC960_DetectController(struct pci_dev *PCI_Device,
- const struct pci_device_id *entry)
-{
- struct DAC960_privdata *privdata =
- (struct DAC960_privdata *)entry->driver_data;
- irq_handler_t InterruptHandler = privdata->InterruptHandler;
- unsigned int MemoryWindowSize = privdata->MemoryWindowSize;
- DAC960_Controller_T *Controller = NULL;
- unsigned char DeviceFunction = PCI_Device->devfn;
- unsigned char ErrorStatus, Parameter0, Parameter1;
- unsigned int IRQ_Channel;
- void __iomem *BaseAddress;
- int i;
-
- Controller = kzalloc(sizeof(DAC960_Controller_T), GFP_ATOMIC);
- if (Controller == NULL) {
- DAC960_Error("Unable to allocate Controller structure for "
- "Controller at\n", NULL);
- return NULL;
- }
- Controller->ControllerNumber = DAC960_ControllerCount;
- DAC960_Controllers[DAC960_ControllerCount++] = Controller;
- Controller->Bus = PCI_Device->bus->number;
- Controller->FirmwareType = privdata->FirmwareType;
- Controller->HardwareType = privdata->HardwareType;
- Controller->Device = DeviceFunction >> 3;
- Controller->Function = DeviceFunction & 0x7;
- Controller->PCIDevice = PCI_Device;
- strcpy(Controller->FullModelName, "DAC960");
-
- if (pci_enable_device(PCI_Device))
- goto Failure;
-
- switch (Controller->HardwareType)
- {
- case DAC960_GEM_Controller:
- Controller->PCI_Address = pci_resource_start(PCI_Device, 0);
- break;
- case DAC960_BA_Controller:
- Controller->PCI_Address = pci_resource_start(PCI_Device, 0);
- break;
- case DAC960_LP_Controller:
- Controller->PCI_Address = pci_resource_start(PCI_Device, 0);
- break;
- case DAC960_LA_Controller:
- Controller->PCI_Address = pci_resource_start(PCI_Device, 0);
- break;
- case DAC960_PG_Controller:
- Controller->PCI_Address = pci_resource_start(PCI_Device, 0);
- break;
- case DAC960_PD_Controller:
- Controller->IO_Address = pci_resource_start(PCI_Device, 0);
- Controller->PCI_Address = pci_resource_start(PCI_Device, 1);
- break;
- case DAC960_P_Controller:
- Controller->IO_Address = pci_resource_start(PCI_Device, 0);
- Controller->PCI_Address = pci_resource_start(PCI_Device, 1);
- break;
- }
-
- pci_set_drvdata(PCI_Device, (void *)((long)Controller->ControllerNumber));
- for (i = 0; i < DAC960_MaxLogicalDrives; i++) {
- Controller->disks[i] = alloc_disk(1<<DAC960_MaxPartitionsBits);
- if (!Controller->disks[i])
- goto Failure;
- Controller->disks[i]->private_data = (void *)((long)i);
- }
- init_waitqueue_head(&Controller->CommandWaitQueue);
- init_waitqueue_head(&Controller->HealthStatusWaitQueue);
- spin_lock_init(&Controller->queue_lock);
- DAC960_AnnounceDriver(Controller);
- /*
- Map the Controller Register Window.
- */
- if (MemoryWindowSize < PAGE_SIZE)
- MemoryWindowSize = PAGE_SIZE;
- Controller->MemoryMappedAddress =
- ioremap_nocache(Controller->PCI_Address & PAGE_MASK, MemoryWindowSize);
- Controller->BaseAddress =
- Controller->MemoryMappedAddress + (Controller->PCI_Address & ~PAGE_MASK);
- if (Controller->MemoryMappedAddress == NULL)
- {
- DAC960_Error("Unable to map Controller Register Window for "
- "Controller at\n", Controller);
- goto Failure;
- }
- BaseAddress = Controller->BaseAddress;
- switch (Controller->HardwareType)
- {
- case DAC960_GEM_Controller:
- DAC960_GEM_DisableInterrupts(BaseAddress);
- DAC960_GEM_AcknowledgeHardwareMailboxStatus(BaseAddress);
- udelay(1000);
- while (DAC960_GEM_InitializationInProgressP(BaseAddress))
- {
- if (DAC960_GEM_ReadErrorStatus(BaseAddress, &ErrorStatus,
- &Parameter0, &Parameter1) &&
- DAC960_ReportErrorStatus(Controller, ErrorStatus,
- Parameter0, Parameter1))
- goto Failure;
- udelay(10);
- }
- if (!DAC960_V2_EnableMemoryMailboxInterface(Controller))
- {
- DAC960_Error("Unable to Enable Memory Mailbox Interface "
- "for Controller at\n", Controller);
- goto Failure;
- }
- DAC960_GEM_EnableInterrupts(BaseAddress);
- Controller->QueueCommand = DAC960_GEM_QueueCommand;
- Controller->ReadControllerConfiguration =
- DAC960_V2_ReadControllerConfiguration;
- Controller->ReadDeviceConfiguration =
- DAC960_V2_ReadDeviceConfiguration;
- Controller->ReportDeviceConfiguration =
- DAC960_V2_ReportDeviceConfiguration;
- Controller->QueueReadWriteCommand =
- DAC960_V2_QueueReadWriteCommand;
- break;
- case DAC960_BA_Controller:
- DAC960_BA_DisableInterrupts(BaseAddress);
- DAC960_BA_AcknowledgeHardwareMailboxStatus(BaseAddress);
- udelay(1000);
- while (DAC960_BA_InitializationInProgressP(BaseAddress))
- {
- if (DAC960_BA_ReadErrorStatus(BaseAddress, &ErrorStatus,
- &Parameter0, &Parameter1) &&
- DAC960_ReportErrorStatus(Controller, ErrorStatus,
- Parameter0, Parameter1))
- goto Failure;
- udelay(10);
- }
- if (!DAC960_V2_EnableMemoryMailboxInterface(Controller))
- {
- DAC960_Error("Unable to Enable Memory Mailbox Interface "
- "for Controller at\n", Controller);
- goto Failure;
- }
- DAC960_BA_EnableInterrupts(BaseAddress);
- Controller->QueueCommand = DAC960_BA_QueueCommand;
- Controller->ReadControllerConfiguration =
- DAC960_V2_ReadControllerConfiguration;
- Controller->ReadDeviceConfiguration =
- DAC960_V2_ReadDeviceConfiguration;
- Controller->ReportDeviceConfiguration =
- DAC960_V2_ReportDeviceConfiguration;
- Controller->QueueReadWriteCommand =
- DAC960_V2_QueueReadWriteCommand;
- break;
- case DAC960_LP_Controller:
- DAC960_LP_DisableInterrupts(BaseAddress);
- DAC960_LP_AcknowledgeHardwareMailboxStatus(BaseAddress);
- udelay(1000);
- while (DAC960_LP_InitializationInProgressP(BaseAddress))
- {
- if (DAC960_LP_ReadErrorStatus(BaseAddress, &ErrorStatus,
- &Parameter0, &Parameter1) &&
- DAC960_ReportErrorStatus(Controller, ErrorStatus,
- Parameter0, Parameter1))
- goto Failure;
- udelay(10);
- }
- if (!DAC960_V2_EnableMemoryMailboxInterface(Controller))
- {
- DAC960_Error("Unable to Enable Memory Mailbox Interface "
- "for Controller at\n", Controller);
- goto Failure;
- }
- DAC960_LP_EnableInterrupts(BaseAddress);
- Controller->QueueCommand = DAC960_LP_QueueCommand;
- Controller->ReadControllerConfiguration =
- DAC960_V2_ReadControllerConfiguration;
- Controller->ReadDeviceConfiguration =
- DAC960_V2_ReadDeviceConfiguration;
- Controller->ReportDeviceConfiguration =
- DAC960_V2_ReportDeviceConfiguration;
- Controller->QueueReadWriteCommand =
- DAC960_V2_QueueReadWriteCommand;
- break;
- case DAC960_LA_Controller:
- DAC960_LA_DisableInterrupts(BaseAddress);
- DAC960_LA_AcknowledgeHardwareMailboxStatus(BaseAddress);
- udelay(1000);
- while (DAC960_LA_InitializationInProgressP(BaseAddress))
- {
- if (DAC960_LA_ReadErrorStatus(BaseAddress, &ErrorStatus,
- &Parameter0, &Parameter1) &&
- DAC960_ReportErrorStatus(Controller, ErrorStatus,
- Parameter0, Parameter1))
- goto Failure;
- udelay(10);
- }
- if (!DAC960_V1_EnableMemoryMailboxInterface(Controller))
- {
- DAC960_Error("Unable to Enable Memory Mailbox Interface "
- "for Controller at\n", Controller);
- goto Failure;
- }
- DAC960_LA_EnableInterrupts(BaseAddress);
- if (Controller->V1.DualModeMemoryMailboxInterface)
- Controller->QueueCommand = DAC960_LA_QueueCommandDualMode;
- else Controller->QueueCommand = DAC960_LA_QueueCommandSingleMode;
- Controller->ReadControllerConfiguration =
- DAC960_V1_ReadControllerConfiguration;
- Controller->ReadDeviceConfiguration =
- DAC960_V1_ReadDeviceConfiguration;
- Controller->ReportDeviceConfiguration =
- DAC960_V1_ReportDeviceConfiguration;
- Controller->QueueReadWriteCommand =
- DAC960_V1_QueueReadWriteCommand;
- break;
- case DAC960_PG_Controller:
- DAC960_PG_DisableInterrupts(BaseAddress);
- DAC960_PG_AcknowledgeHardwareMailboxStatus(BaseAddress);
- udelay(1000);
- while (DAC960_PG_InitializationInProgressP(BaseAddress))
- {
- if (DAC960_PG_ReadErrorStatus(BaseAddress, &ErrorStatus,
- &Parameter0, &Parameter1) &&
- DAC960_ReportErrorStatus(Controller, ErrorStatus,
- Parameter0, Parameter1))
- goto Failure;
- udelay(10);
- }
- if (!DAC960_V1_EnableMemoryMailboxInterface(Controller))
- {
- DAC960_Error("Unable to Enable Memory Mailbox Interface "
- "for Controller at\n", Controller);
- goto Failure;
- }
- DAC960_PG_EnableInterrupts(BaseAddress);
- if (Controller->V1.DualModeMemoryMailboxInterface)
- Controller->QueueCommand = DAC960_PG_QueueCommandDualMode;
- else Controller->QueueCommand = DAC960_PG_QueueCommandSingleMode;
- Controller->ReadControllerConfiguration =
- DAC960_V1_ReadControllerConfiguration;
- Controller->ReadDeviceConfiguration =
- DAC960_V1_ReadDeviceConfiguration;
- Controller->ReportDeviceConfiguration =
- DAC960_V1_ReportDeviceConfiguration;
- Controller->QueueReadWriteCommand =
- DAC960_V1_QueueReadWriteCommand;
- break;
- case DAC960_PD_Controller:
- if (!request_region(Controller->IO_Address, 0x80,
- Controller->FullModelName)) {
- DAC960_Error("IO port 0x%lx busy for Controller at\n",
- Controller, Controller->IO_Address);
- goto Failure;
- }
- DAC960_PD_DisableInterrupts(BaseAddress);
- DAC960_PD_AcknowledgeStatus(BaseAddress);
- udelay(1000);
- while (DAC960_PD_InitializationInProgressP(BaseAddress))
- {
- if (DAC960_PD_ReadErrorStatus(BaseAddress, &ErrorStatus,
- &Parameter0, &Parameter1) &&
- DAC960_ReportErrorStatus(Controller, ErrorStatus,
- Parameter0, Parameter1))
- goto Failure;
- udelay(10);
- }
- if (!DAC960_V1_EnableMemoryMailboxInterface(Controller))
- {
- DAC960_Error("Unable to allocate DMA mapped memory "
- "for Controller at\n", Controller);
- goto Failure;
- }
- DAC960_PD_EnableInterrupts(BaseAddress);
- Controller->QueueCommand = DAC960_PD_QueueCommand;
- Controller->ReadControllerConfiguration =
- DAC960_V1_ReadControllerConfiguration;
- Controller->ReadDeviceConfiguration =
- DAC960_V1_ReadDeviceConfiguration;
- Controller->ReportDeviceConfiguration =
- DAC960_V1_ReportDeviceConfiguration;
- Controller->QueueReadWriteCommand =
- DAC960_V1_QueueReadWriteCommand;
- break;
- case DAC960_P_Controller:
- if (!request_region(Controller->IO_Address, 0x80,
- Controller->FullModelName)){
- DAC960_Error("IO port 0x%lx busy for Controller at\n",
- Controller, Controller->IO_Address);
- goto Failure;
- }
- DAC960_PD_DisableInterrupts(BaseAddress);
- DAC960_PD_AcknowledgeStatus(BaseAddress);
- udelay(1000);
- while (DAC960_PD_InitializationInProgressP(BaseAddress))
- {
- if (DAC960_PD_ReadErrorStatus(BaseAddress, &ErrorStatus,
- &Parameter0, &Parameter1) &&
- DAC960_ReportErrorStatus(Controller, ErrorStatus,
- Parameter0, Parameter1))
- goto Failure;
- udelay(10);
- }
- if (!DAC960_V1_EnableMemoryMailboxInterface(Controller))
- {
- DAC960_Error("Unable to allocate DMA mapped memory"
- "for Controller at\n", Controller);
- goto Failure;
- }
- DAC960_PD_EnableInterrupts(BaseAddress);
- Controller->QueueCommand = DAC960_P_QueueCommand;
- Controller->ReadControllerConfiguration =
- DAC960_V1_ReadControllerConfiguration;
- Controller->ReadDeviceConfiguration =
- DAC960_V1_ReadDeviceConfiguration;
- Controller->ReportDeviceConfiguration =
- DAC960_V1_ReportDeviceConfiguration;
- Controller->QueueReadWriteCommand =
- DAC960_V1_QueueReadWriteCommand;
- break;
- }
- /*
- Acquire shared access to the IRQ Channel.
- */
- IRQ_Channel = PCI_Device->irq;
- if (request_irq(IRQ_Channel, InterruptHandler, IRQF_SHARED,
- Controller->FullModelName, Controller) < 0)
- {
- DAC960_Error("Unable to acquire IRQ Channel %d for Controller at\n",
- Controller, Controller->IRQ_Channel);
- goto Failure;
- }
- Controller->IRQ_Channel = IRQ_Channel;
- Controller->InitialCommand.CommandIdentifier = 1;
- Controller->InitialCommand.Controller = Controller;
- Controller->Commands[0] = &Controller->InitialCommand;
- Controller->FreeCommands = &Controller->InitialCommand;
- return Controller;
-
-Failure:
- if (Controller->IO_Address == 0)
- DAC960_Error("PCI Bus %d Device %d Function %d I/O Address N/A "
- "PCI Address 0x%X\n", Controller,
- Controller->Bus, Controller->Device,
- Controller->Function, Controller->PCI_Address);
- else
- DAC960_Error("PCI Bus %d Device %d Function %d I/O Address "
- "0x%X PCI Address 0x%X\n", Controller,
- Controller->Bus, Controller->Device,
- Controller->Function, Controller->IO_Address,
- Controller->PCI_Address);
- DAC960_DetectCleanup(Controller);
- DAC960_ControllerCount--;
- return NULL;
-}
-
-/*
- DAC960_InitializeController initializes Controller.
-*/
-
-static bool
-DAC960_InitializeController(DAC960_Controller_T *Controller)
-{
- if (DAC960_ReadControllerConfiguration(Controller) &&
- DAC960_ReportControllerConfiguration(Controller) &&
- DAC960_CreateAuxiliaryStructures(Controller) &&
- DAC960_ReadDeviceConfiguration(Controller) &&
- DAC960_ReportDeviceConfiguration(Controller) &&
- DAC960_RegisterBlockDevice(Controller))
- {
- /*
- Initialize the Monitoring Timer.
- */
- timer_setup(&Controller->MonitoringTimer,
- DAC960_MonitoringTimerFunction, 0);
- Controller->MonitoringTimer.expires =
- jiffies + DAC960_MonitoringTimerInterval;
- add_timer(&Controller->MonitoringTimer);
- Controller->ControllerInitialized = true;
- return true;
- }
- return false;
-}
-
-
-/*
- DAC960_FinalizeController finalizes Controller.
-*/
-
-static void DAC960_FinalizeController(DAC960_Controller_T *Controller)
-{
- if (Controller->ControllerInitialized)
- {
- unsigned long flags;
-
- /*
- * Acquiring and releasing lock here eliminates
- * a very low probability race.
- *
- * The code below allocates controller command structures
- * from the free list without holding the controller lock.
- * This is safe assuming there is no other activity on
- * the controller at the time.
- *
- * But, there might be a monitoring command still
- * in progress. Setting the Shutdown flag while holding
- * the lock ensures that there is no monitoring command
- * in the interrupt handler currently, and any monitoring
- * commands that complete from this time on will NOT return
- * their command structure to the free list.
- */
-
- spin_lock_irqsave(&Controller->queue_lock, flags);
- Controller->ShutdownMonitoringTimer = 1;
- spin_unlock_irqrestore(&Controller->queue_lock, flags);
-
- del_timer_sync(&Controller->MonitoringTimer);
- if (Controller->FirmwareType == DAC960_V1_Controller)
- {
- DAC960_Notice("Flushing Cache...", Controller);
- DAC960_V1_ExecuteType3(Controller, DAC960_V1_Flush, 0);
- DAC960_Notice("done\n", Controller);
-
- if (Controller->HardwareType == DAC960_PD_Controller)
- release_region(Controller->IO_Address, 0x80);
- }
- else
- {
- DAC960_Notice("Flushing Cache...", Controller);
- DAC960_V2_DeviceOperation(Controller, DAC960_V2_PauseDevice,
- DAC960_V2_RAID_Controller);
- DAC960_Notice("done\n", Controller);
- }
- }
- DAC960_UnregisterBlockDevice(Controller);
- DAC960_DestroyAuxiliaryStructures(Controller);
- DAC960_DestroyProcEntries(Controller);
- DAC960_DetectCleanup(Controller);
-}
-
-
-/*
- DAC960_Probe verifies controller's existence and
- initializes the DAC960 Driver for that controller.
-*/
-
-static int
-DAC960_Probe(struct pci_dev *dev, const struct pci_device_id *entry)
-{
- int disk;
- DAC960_Controller_T *Controller;
-
- if (DAC960_ControllerCount == DAC960_MaxControllers)
- {
- DAC960_Error("More than %d DAC960 Controllers detected - "
- "ignoring from Controller at\n",
- NULL, DAC960_MaxControllers);
- return -ENODEV;
- }
-
- Controller = DAC960_DetectController(dev, entry);
- if (!Controller)
- return -ENODEV;
-
- if (!DAC960_InitializeController(Controller)) {
- DAC960_FinalizeController(Controller);
- return -ENODEV;
- }
-
- for (disk = 0; disk < DAC960_MaxLogicalDrives; disk++) {
- set_capacity(Controller->disks[disk], disk_size(Controller, disk));
- add_disk(Controller->disks[disk]);
- }
- DAC960_CreateProcEntries(Controller);
- return 0;
-}
-
-
-/*
- DAC960_Finalize finalizes the DAC960 Driver.
-*/
-
-static void DAC960_Remove(struct pci_dev *PCI_Device)
-{
- int Controller_Number = (long)pci_get_drvdata(PCI_Device);
- DAC960_Controller_T *Controller = DAC960_Controllers[Controller_Number];
- if (Controller != NULL)
- DAC960_FinalizeController(Controller);
-}
-
-
-/*
- DAC960_V1_QueueReadWriteCommand prepares and queues a Read/Write Command for
- DAC960 V1 Firmware Controllers.
-*/
-
-static void DAC960_V1_QueueReadWriteCommand(DAC960_Command_T *Command)
-{
- DAC960_Controller_T *Controller = Command->Controller;
- DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
- DAC960_V1_ScatterGatherSegment_T *ScatterGatherList =
- Command->V1.ScatterGatherList;
- struct scatterlist *ScatterList = Command->V1.ScatterList;
-
- DAC960_V1_ClearCommand(Command);
-
- if (Command->SegmentCount == 1)
- {
- if (Command->DmaDirection == PCI_DMA_FROMDEVICE)
- CommandMailbox->Type5.CommandOpcode = DAC960_V1_Read;
- else
- CommandMailbox->Type5.CommandOpcode = DAC960_V1_Write;
-
- CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
- CommandMailbox->Type5.LD.LogicalDriveNumber = Command->LogicalDriveNumber;
- CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber;
- CommandMailbox->Type5.BusAddress =
- (DAC960_BusAddress32_T)sg_dma_address(ScatterList);
- }
- else
- {
- int i;
-
- if (Command->DmaDirection == PCI_DMA_FROMDEVICE)
- CommandMailbox->Type5.CommandOpcode = DAC960_V1_ReadWithScatterGather;
- else
- CommandMailbox->Type5.CommandOpcode = DAC960_V1_WriteWithScatterGather;
-
- CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
- CommandMailbox->Type5.LD.LogicalDriveNumber = Command->LogicalDriveNumber;
- CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber;
- CommandMailbox->Type5.BusAddress = Command->V1.ScatterGatherListDMA;
-
- CommandMailbox->Type5.ScatterGatherCount = Command->SegmentCount;
-
- for (i = 0; i < Command->SegmentCount; i++, ScatterList++, ScatterGatherList++) {
- ScatterGatherList->SegmentDataPointer =
- (DAC960_BusAddress32_T)sg_dma_address(ScatterList);
- ScatterGatherList->SegmentByteCount =
- (DAC960_ByteCount32_T)sg_dma_len(ScatterList);
- }
- }
- DAC960_QueueCommand(Command);
-}
-
-
-/*
- DAC960_V2_QueueReadWriteCommand prepares and queues a Read/Write Command for
- DAC960 V2 Firmware Controllers.
-*/
-
-static void DAC960_V2_QueueReadWriteCommand(DAC960_Command_T *Command)
-{
- DAC960_Controller_T *Controller = Command->Controller;
- DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
- struct scatterlist *ScatterList = Command->V2.ScatterList;
-
- DAC960_V2_ClearCommand(Command);
-
- CommandMailbox->SCSI_10.CommandOpcode = DAC960_V2_SCSI_10;
- CommandMailbox->SCSI_10.CommandControlBits.DataTransferControllerToHost =
- (Command->DmaDirection == PCI_DMA_FROMDEVICE);
- CommandMailbox->SCSI_10.DataTransferSize =
- Command->BlockCount << DAC960_BlockSizeBits;
- CommandMailbox->SCSI_10.RequestSenseBusAddress = Command->V2.RequestSenseDMA;
- CommandMailbox->SCSI_10.PhysicalDevice =
- Controller->V2.LogicalDriveToVirtualDevice[Command->LogicalDriveNumber];
- CommandMailbox->SCSI_10.RequestSenseSize = sizeof(DAC960_SCSI_RequestSense_T);
- CommandMailbox->SCSI_10.CDBLength = 10;
- CommandMailbox->SCSI_10.SCSI_CDB[0] =
- (Command->DmaDirection == PCI_DMA_FROMDEVICE ? 0x28 : 0x2A);
- CommandMailbox->SCSI_10.SCSI_CDB[2] = Command->BlockNumber >> 24;
- CommandMailbox->SCSI_10.SCSI_CDB[3] = Command->BlockNumber >> 16;
- CommandMailbox->SCSI_10.SCSI_CDB[4] = Command->BlockNumber >> 8;
- CommandMailbox->SCSI_10.SCSI_CDB[5] = Command->BlockNumber;
- CommandMailbox->SCSI_10.SCSI_CDB[7] = Command->BlockCount >> 8;
- CommandMailbox->SCSI_10.SCSI_CDB[8] = Command->BlockCount;
-
- if (Command->SegmentCount == 1)
- {
- CommandMailbox->SCSI_10.DataTransferMemoryAddress
- .ScatterGatherSegments[0]
- .SegmentDataPointer =
- (DAC960_BusAddress64_T)sg_dma_address(ScatterList);
- CommandMailbox->SCSI_10.DataTransferMemoryAddress
- .ScatterGatherSegments[0]
- .SegmentByteCount =
- CommandMailbox->SCSI_10.DataTransferSize;
- }
- else
- {
- DAC960_V2_ScatterGatherSegment_T *ScatterGatherList;
- int i;
-
- if (Command->SegmentCount > 2)
- {
- ScatterGatherList = Command->V2.ScatterGatherList;
- CommandMailbox->SCSI_10.CommandControlBits
- .AdditionalScatterGatherListMemory = true;
- CommandMailbox->SCSI_10.DataTransferMemoryAddress
- .ExtendedScatterGather.ScatterGatherList0Length = Command->SegmentCount;
- CommandMailbox->SCSI_10.DataTransferMemoryAddress
- .ExtendedScatterGather.ScatterGatherList0Address =
- Command->V2.ScatterGatherListDMA;
- }
- else
- ScatterGatherList = CommandMailbox->SCSI_10.DataTransferMemoryAddress
- .ScatterGatherSegments;
-
- for (i = 0; i < Command->SegmentCount; i++, ScatterList++, ScatterGatherList++) {
- ScatterGatherList->SegmentDataPointer =
- (DAC960_BusAddress64_T)sg_dma_address(ScatterList);
- ScatterGatherList->SegmentByteCount =
- (DAC960_ByteCount64_T)sg_dma_len(ScatterList);
- }
- }
- DAC960_QueueCommand(Command);
-}
-
-
-static int DAC960_process_queue(DAC960_Controller_T *Controller, struct request_queue *req_q)
-{
- struct request *Request;
- DAC960_Command_T *Command;
-
- while(1) {
- Request = blk_peek_request(req_q);
- if (!Request)
- return 1;
-
- Command = DAC960_AllocateCommand(Controller);
- if (Command == NULL)
- return 0;
-
- if (rq_data_dir(Request) == READ) {
- Command->DmaDirection = PCI_DMA_FROMDEVICE;
- Command->CommandType = DAC960_ReadCommand;
- } else {
- Command->DmaDirection = PCI_DMA_TODEVICE;
- Command->CommandType = DAC960_WriteCommand;
- }
- Command->Completion = Request->end_io_data;
- Command->LogicalDriveNumber = (long)Request->rq_disk->private_data;
- Command->BlockNumber = blk_rq_pos(Request);
- Command->BlockCount = blk_rq_sectors(Request);
- Command->Request = Request;
- blk_start_request(Request);
- Command->SegmentCount = blk_rq_map_sg(req_q,
- Command->Request, Command->cmd_sglist);
- /* pci_map_sg MAY change the value of SegCount */
- Command->SegmentCount = pci_map_sg(Controller->PCIDevice, Command->cmd_sglist,
- Command->SegmentCount, Command->DmaDirection);
-
- DAC960_QueueReadWriteCommand(Command);
- }
-}
-
-/*
- DAC960_ProcessRequest attempts to remove one I/O Request from Controller's
- I/O Request Queue and queues it to the Controller. WaitForCommand is true if
- this function should wait for a Command to become available if necessary.
- This function returns true if an I/O Request was queued and false otherwise.
-*/
-static void DAC960_ProcessRequest(DAC960_Controller_T *controller)
-{
- int i;
-
- if (!controller->ControllerInitialized)
- return;
-
- /* Do this better later! */
- for (i = controller->req_q_index; i < DAC960_MaxLogicalDrives; i++) {
- struct request_queue *req_q = controller->RequestQueue[i];
-
- if (req_q == NULL)
- continue;
-
- if (!DAC960_process_queue(controller, req_q)) {
- controller->req_q_index = i;
- return;
- }
- }
-
- if (controller->req_q_index == 0)
- return;
-
- for (i = 0; i < controller->req_q_index; i++) {
- struct request_queue *req_q = controller->RequestQueue[i];
-
- if (req_q == NULL)
- continue;
-
- if (!DAC960_process_queue(controller, req_q)) {
- controller->req_q_index = i;
- return;
- }
- }
-}
-
-
-/*
- DAC960_queue_partial_rw extracts one bio from the request already
- associated with argument command, and construct a new command block to retry I/O
- only on that bio. Queue that command to the controller.
-
- This function re-uses a previously-allocated Command,
- there is no failure mode from trying to allocate a command.
-*/
-
-static void DAC960_queue_partial_rw(DAC960_Command_T *Command)
-{
- DAC960_Controller_T *Controller = Command->Controller;
- struct request *Request = Command->Request;
- struct request_queue *req_q = Controller->RequestQueue[Command->LogicalDriveNumber];
-
- if (Command->DmaDirection == PCI_DMA_FROMDEVICE)
- Command->CommandType = DAC960_ReadRetryCommand;
- else
- Command->CommandType = DAC960_WriteRetryCommand;
-
- /*
- * We could be more efficient with these mapping requests
- * and map only the portions that we need. But since this
- * code should almost never be called, just go with a
- * simple coding.
- */
- (void)blk_rq_map_sg(req_q, Command->Request, Command->cmd_sglist);
-
- (void)pci_map_sg(Controller->PCIDevice, Command->cmd_sglist, 1, Command->DmaDirection);
- /*
- * Resubmitting the request sector at a time is really tedious.
- * But, this should almost never happen. So, we're willing to pay
- * this price so that in the end, as much of the transfer is completed
- * successfully as possible.
- */
- Command->SegmentCount = 1;
- Command->BlockNumber = blk_rq_pos(Request);
- Command->BlockCount = 1;
- DAC960_QueueReadWriteCommand(Command);
- return;
-}
-
-/*
- DAC960_RequestFunction is the I/O Request Function for DAC960 Controllers.
-*/
-
-static void DAC960_RequestFunction(struct request_queue *RequestQueue)
-{
- DAC960_ProcessRequest(RequestQueue->queuedata);
-}
-
-/*
- DAC960_ProcessCompletedBuffer performs completion processing for an
- individual Buffer.
-*/
-
-static inline bool DAC960_ProcessCompletedRequest(DAC960_Command_T *Command,
- bool SuccessfulIO)
-{
- struct request *Request = Command->Request;
- blk_status_t Error = SuccessfulIO ? BLK_STS_OK : BLK_STS_IOERR;
-
- pci_unmap_sg(Command->Controller->PCIDevice, Command->cmd_sglist,
- Command->SegmentCount, Command->DmaDirection);
-
- if (!__blk_end_request(Request, Error, Command->BlockCount << 9)) {
- if (Command->Completion) {
- complete(Command->Completion);
- Command->Completion = NULL;
- }
- return true;
- }
- return false;
-}
-
-/*
- DAC960_V1_ReadWriteError prints an appropriate error message for Command
- when an error occurs on a Read or Write operation.
-*/
-
-static void DAC960_V1_ReadWriteError(DAC960_Command_T *Command)
-{
- DAC960_Controller_T *Controller = Command->Controller;
- unsigned char *CommandName = "UNKNOWN";
- switch (Command->CommandType)
- {
- case DAC960_ReadCommand:
- case DAC960_ReadRetryCommand:
- CommandName = "READ";
- break;
- case DAC960_WriteCommand:
- case DAC960_WriteRetryCommand:
- CommandName = "WRITE";
- break;
- case DAC960_MonitoringCommand:
- case DAC960_ImmediateCommand:
- case DAC960_QueuedCommand:
- break;
- }
- switch (Command->V1.CommandStatus)
- {
- case DAC960_V1_IrrecoverableDataError:
- DAC960_Error("Irrecoverable Data Error on %s:\n",
- Controller, CommandName);
- break;
- case DAC960_V1_LogicalDriveNonexistentOrOffline:
- DAC960_Error("Logical Drive Nonexistent or Offline on %s:\n",
- Controller, CommandName);
- break;
- case DAC960_V1_AccessBeyondEndOfLogicalDrive:
- DAC960_Error("Attempt to Access Beyond End of Logical Drive "
- "on %s:\n", Controller, CommandName);
- break;
- case DAC960_V1_BadDataEncountered:
- DAC960_Error("Bad Data Encountered on %s:\n", Controller, CommandName);
- break;
- default:
- DAC960_Error("Unexpected Error Status %04X on %s:\n",
- Controller, Command->V1.CommandStatus, CommandName);
- break;
- }
- DAC960_Error(" /dev/rd/c%dd%d: absolute blocks %u..%u\n",
- Controller, Controller->ControllerNumber,
- Command->LogicalDriveNumber, Command->BlockNumber,
- Command->BlockNumber + Command->BlockCount - 1);
-}
-
-
-/*
- DAC960_V1_ProcessCompletedCommand performs completion processing for Command
- for DAC960 V1 Firmware Controllers.
-*/
-
-static void DAC960_V1_ProcessCompletedCommand(DAC960_Command_T *Command)
-{
- DAC960_Controller_T *Controller = Command->Controller;
- DAC960_CommandType_T CommandType = Command->CommandType;
- DAC960_V1_CommandOpcode_T CommandOpcode =
- Command->V1.CommandMailbox.Common.CommandOpcode;
- DAC960_V1_CommandStatus_T CommandStatus = Command->V1.CommandStatus;
-
- if (CommandType == DAC960_ReadCommand ||
- CommandType == DAC960_WriteCommand)
- {
-
-#ifdef FORCE_RETRY_DEBUG
- CommandStatus = DAC960_V1_IrrecoverableDataError;
-#endif
-
- if (CommandStatus == DAC960_V1_NormalCompletion) {
-
- if (!DAC960_ProcessCompletedRequest(Command, true))
- BUG();
-
- } else if (CommandStatus == DAC960_V1_IrrecoverableDataError ||
- CommandStatus == DAC960_V1_BadDataEncountered)
- {
- /*
- * break the command down into pieces and resubmit each
- * piece, hoping that some of them will succeed.
- */
- DAC960_queue_partial_rw(Command);
- return;
- }
- else
- {
- if (CommandStatus != DAC960_V1_LogicalDriveNonexistentOrOffline)
- DAC960_V1_ReadWriteError(Command);
-
- if (!DAC960_ProcessCompletedRequest(Command, false))
- BUG();
- }
- }
- else if (CommandType == DAC960_ReadRetryCommand ||
- CommandType == DAC960_WriteRetryCommand)
- {
- bool normal_completion;
-#ifdef FORCE_RETRY_FAILURE_DEBUG
- static int retry_count = 1;
-#endif
- /*
- Perform completion processing for the portion that was
- retried, and submit the next portion, if any.
- */
- normal_completion = true;
- if (CommandStatus != DAC960_V1_NormalCompletion) {
- normal_completion = false;
- if (CommandStatus != DAC960_V1_LogicalDriveNonexistentOrOffline)
- DAC960_V1_ReadWriteError(Command);
- }
-
-#ifdef FORCE_RETRY_FAILURE_DEBUG
- if (!(++retry_count % 10000)) {
- printk("V1 error retry failure test\n");
- normal_completion = false;
- DAC960_V1_ReadWriteError(Command);
- }
-#endif
-
- if (!DAC960_ProcessCompletedRequest(Command, normal_completion)) {
- DAC960_queue_partial_rw(Command);
- return;
- }
- }
-
- else if (CommandType == DAC960_MonitoringCommand)
- {
- if (Controller->ShutdownMonitoringTimer)
- return;
- if (CommandOpcode == DAC960_V1_Enquiry)
- {
- DAC960_V1_Enquiry_T *OldEnquiry = &Controller->V1.Enquiry;
- DAC960_V1_Enquiry_T *NewEnquiry = Controller->V1.NewEnquiry;
- unsigned int OldCriticalLogicalDriveCount =
- OldEnquiry->CriticalLogicalDriveCount;
- unsigned int NewCriticalLogicalDriveCount =
- NewEnquiry->CriticalLogicalDriveCount;
- if (NewEnquiry->NumberOfLogicalDrives > Controller->LogicalDriveCount)
- {
- int LogicalDriveNumber = Controller->LogicalDriveCount - 1;
- while (++LogicalDriveNumber < NewEnquiry->NumberOfLogicalDrives)
- DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
- "Now Exists\n", Controller,
- LogicalDriveNumber,
- Controller->ControllerNumber,
- LogicalDriveNumber);
- Controller->LogicalDriveCount = NewEnquiry->NumberOfLogicalDrives;
- DAC960_ComputeGenericDiskInfo(Controller);
- }
- if (NewEnquiry->NumberOfLogicalDrives < Controller->LogicalDriveCount)
- {
- int LogicalDriveNumber = NewEnquiry->NumberOfLogicalDrives - 1;
- while (++LogicalDriveNumber < Controller->LogicalDriveCount)
- DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
- "No Longer Exists\n", Controller,
- LogicalDriveNumber,
- Controller->ControllerNumber,
- LogicalDriveNumber);
- Controller->LogicalDriveCount = NewEnquiry->NumberOfLogicalDrives;
- DAC960_ComputeGenericDiskInfo(Controller);
- }
- if (NewEnquiry->StatusFlags.DeferredWriteError !=
- OldEnquiry->StatusFlags.DeferredWriteError)
- DAC960_Critical("Deferred Write Error Flag is now %s\n", Controller,
- (NewEnquiry->StatusFlags.DeferredWriteError
- ? "TRUE" : "FALSE"));
- if ((NewCriticalLogicalDriveCount > 0 ||
- NewCriticalLogicalDriveCount != OldCriticalLogicalDriveCount) ||
- (NewEnquiry->OfflineLogicalDriveCount > 0 ||
- NewEnquiry->OfflineLogicalDriveCount !=
- OldEnquiry->OfflineLogicalDriveCount) ||
- (NewEnquiry->DeadDriveCount > 0 ||
- NewEnquiry->DeadDriveCount !=
- OldEnquiry->DeadDriveCount) ||
- (NewEnquiry->EventLogSequenceNumber !=
- OldEnquiry->EventLogSequenceNumber) ||
- Controller->MonitoringTimerCount == 0 ||
- time_after_eq(jiffies, Controller->SecondaryMonitoringTime
- + DAC960_SecondaryMonitoringInterval))
- {
- Controller->V1.NeedLogicalDriveInformation = true;
- Controller->V1.NewEventLogSequenceNumber =
- NewEnquiry->EventLogSequenceNumber;
- Controller->V1.NeedErrorTableInformation = true;
- Controller->V1.NeedDeviceStateInformation = true;
- Controller->V1.StartDeviceStateScan = true;
- Controller->V1.NeedBackgroundInitializationStatus =
- Controller->V1.BackgroundInitializationStatusSupported;
- Controller->SecondaryMonitoringTime = jiffies;
- }
- if (NewEnquiry->RebuildFlag == DAC960_V1_StandbyRebuildInProgress ||
- NewEnquiry->RebuildFlag
- == DAC960_V1_BackgroundRebuildInProgress ||
- OldEnquiry->RebuildFlag == DAC960_V1_StandbyRebuildInProgress ||
- OldEnquiry->RebuildFlag == DAC960_V1_BackgroundRebuildInProgress)
- {
- Controller->V1.NeedRebuildProgress = true;
- Controller->V1.RebuildProgressFirst =
- (NewEnquiry->CriticalLogicalDriveCount <
- OldEnquiry->CriticalLogicalDriveCount);
- }
- if (OldEnquiry->RebuildFlag == DAC960_V1_BackgroundCheckInProgress)
- switch (NewEnquiry->RebuildFlag)
- {
- case DAC960_V1_NoStandbyRebuildOrCheckInProgress:
- DAC960_Progress("Consistency Check Completed Successfully\n",
- Controller);
- break;
- case DAC960_V1_StandbyRebuildInProgress:
- case DAC960_V1_BackgroundRebuildInProgress:
- break;
- case DAC960_V1_BackgroundCheckInProgress:
- Controller->V1.NeedConsistencyCheckProgress = true;
- break;
- case DAC960_V1_StandbyRebuildCompletedWithError:
- DAC960_Progress("Consistency Check Completed with Error\n",
- Controller);
- break;
- case DAC960_V1_BackgroundRebuildOrCheckFailed_DriveFailed:
- DAC960_Progress("Consistency Check Failed - "
- "Physical Device Failed\n", Controller);
- break;
- case DAC960_V1_BackgroundRebuildOrCheckFailed_LogicalDriveFailed:
- DAC960_Progress("Consistency Check Failed - "
- "Logical Drive Failed\n", Controller);
- break;
- case DAC960_V1_BackgroundRebuildOrCheckFailed_OtherCauses:
- DAC960_Progress("Consistency Check Failed - Other Causes\n",
- Controller);
- break;
- case DAC960_V1_BackgroundRebuildOrCheckSuccessfullyTerminated:
- DAC960_Progress("Consistency Check Successfully Terminated\n",
- Controller);
- break;
- }
- else if (NewEnquiry->RebuildFlag
- == DAC960_V1_BackgroundCheckInProgress)
- Controller->V1.NeedConsistencyCheckProgress = true;
- Controller->MonitoringAlertMode =
- (NewEnquiry->CriticalLogicalDriveCount > 0 ||
- NewEnquiry->OfflineLogicalDriveCount > 0 ||
- NewEnquiry->DeadDriveCount > 0);
- if (NewEnquiry->RebuildFlag > DAC960_V1_BackgroundCheckInProgress)
- {
- Controller->V1.PendingRebuildFlag = NewEnquiry->RebuildFlag;
- Controller->V1.RebuildFlagPending = true;
- }
- memcpy(&Controller->V1.Enquiry, &Controller->V1.NewEnquiry,
- sizeof(DAC960_V1_Enquiry_T));
- }
- else if (CommandOpcode == DAC960_V1_PerformEventLogOperation)
- {
- static char
- *DAC960_EventMessages[] =
- { "killed because write recovery failed",
- "killed because of SCSI bus reset failure",
- "killed because of double check condition",
- "killed because it was removed",
- "killed because of gross error on SCSI chip",
- "killed because of bad tag returned from drive",
- "killed because of timeout on SCSI command",
- "killed because of reset SCSI command issued from system",
- "killed because busy or parity error count exceeded limit",
- "killed because of 'kill drive' command from system",
- "killed because of selection timeout",
- "killed due to SCSI phase sequence error",
- "killed due to unknown status" };
- DAC960_V1_EventLogEntry_T *EventLogEntry =
- Controller->V1.EventLogEntry;
- if (EventLogEntry->SequenceNumber ==
- Controller->V1.OldEventLogSequenceNumber)
- {
- unsigned char SenseKey = EventLogEntry->SenseKey;
- unsigned char AdditionalSenseCode =
- EventLogEntry->AdditionalSenseCode;
- unsigned char AdditionalSenseCodeQualifier =
- EventLogEntry->AdditionalSenseCodeQualifier;
- if (SenseKey == DAC960_SenseKey_VendorSpecific &&
- AdditionalSenseCode == 0x80 &&
- AdditionalSenseCodeQualifier <
- ARRAY_SIZE(DAC960_EventMessages))
- DAC960_Critical("Physical Device %d:%d %s\n", Controller,
- EventLogEntry->Channel,
- EventLogEntry->TargetID,
- DAC960_EventMessages[
- AdditionalSenseCodeQualifier]);
- else if (SenseKey == DAC960_SenseKey_UnitAttention &&
- AdditionalSenseCode == 0x29)
- {
- if (Controller->MonitoringTimerCount > 0)
- Controller->V1.DeviceResetCount[EventLogEntry->Channel]
- [EventLogEntry->TargetID]++;
- }
- else if (!(SenseKey == DAC960_SenseKey_NoSense ||
- (SenseKey == DAC960_SenseKey_NotReady &&
- AdditionalSenseCode == 0x04 &&
- (AdditionalSenseCodeQualifier == 0x01 ||
- AdditionalSenseCodeQualifier == 0x02))))
- {
- DAC960_Critical("Physical Device %d:%d Error Log: "
- "Sense Key = %X, ASC = %02X, ASCQ = %02X\n",
- Controller,
- EventLogEntry->Channel,
- EventLogEntry->TargetID,
- SenseKey,
- AdditionalSenseCode,
- AdditionalSenseCodeQualifier);
- DAC960_Critical("Physical Device %d:%d Error Log: "
- "Information = %02X%02X%02X%02X "
- "%02X%02X%02X%02X\n",
- Controller,
- EventLogEntry->Channel,
- EventLogEntry->TargetID,
- EventLogEntry->Information[0],
- EventLogEntry->Information[1],
- EventLogEntry->Information[2],
- EventLogEntry->Information[3],
- EventLogEntry->CommandSpecificInformation[0],
- EventLogEntry->CommandSpecificInformation[1],
- EventLogEntry->CommandSpecificInformation[2],
- EventLogEntry->CommandSpecificInformation[3]);
- }
- }
- Controller->V1.OldEventLogSequenceNumber++;
- }
- else if (CommandOpcode == DAC960_V1_GetErrorTable)
- {
- DAC960_V1_ErrorTable_T *OldErrorTable = &Controller->V1.ErrorTable;
- DAC960_V1_ErrorTable_T *NewErrorTable = Controller->V1.NewErrorTable;
- int Channel, TargetID;
- for (Channel = 0; Channel < Controller->Channels; Channel++)
- for (TargetID = 0; TargetID < Controller->Targets; TargetID++)
- {
- DAC960_V1_ErrorTableEntry_T *NewErrorEntry =
- &NewErrorTable->ErrorTableEntries[Channel][TargetID];
- DAC960_V1_ErrorTableEntry_T *OldErrorEntry =
- &OldErrorTable->ErrorTableEntries[Channel][TargetID];
- if ((NewErrorEntry->ParityErrorCount !=
- OldErrorEntry->ParityErrorCount) ||
- (NewErrorEntry->SoftErrorCount !=
- OldErrorEntry->SoftErrorCount) ||
- (NewErrorEntry->HardErrorCount !=
- OldErrorEntry->HardErrorCount) ||
- (NewErrorEntry->MiscErrorCount !=
- OldErrorEntry->MiscErrorCount))
- DAC960_Critical("Physical Device %d:%d Errors: "
- "Parity = %d, Soft = %d, "
- "Hard = %d, Misc = %d\n",
- Controller, Channel, TargetID,
- NewErrorEntry->ParityErrorCount,
- NewErrorEntry->SoftErrorCount,
- NewErrorEntry->HardErrorCount,
- NewErrorEntry->MiscErrorCount);
- }
- memcpy(&Controller->V1.ErrorTable, Controller->V1.NewErrorTable,
- sizeof(DAC960_V1_ErrorTable_T));
- }
- else if (CommandOpcode == DAC960_V1_GetDeviceState)
- {
- DAC960_V1_DeviceState_T *OldDeviceState =
- &Controller->V1.DeviceState[Controller->V1.DeviceStateChannel]
- [Controller->V1.DeviceStateTargetID];
- DAC960_V1_DeviceState_T *NewDeviceState =
- Controller->V1.NewDeviceState;
- if (NewDeviceState->DeviceState != OldDeviceState->DeviceState)
- DAC960_Critical("Physical Device %d:%d is now %s\n", Controller,
- Controller->V1.DeviceStateChannel,
- Controller->V1.DeviceStateTargetID,
- (NewDeviceState->DeviceState
- == DAC960_V1_Device_Dead
- ? "DEAD"
- : NewDeviceState->DeviceState
- == DAC960_V1_Device_WriteOnly
- ? "WRITE-ONLY"
- : NewDeviceState->DeviceState
- == DAC960_V1_Device_Online
- ? "ONLINE" : "STANDBY"));
- if (OldDeviceState->DeviceState == DAC960_V1_Device_Dead &&
- NewDeviceState->DeviceState != DAC960_V1_Device_Dead)
- {
- Controller->V1.NeedDeviceInquiryInformation = true;
- Controller->V1.NeedDeviceSerialNumberInformation = true;
- Controller->V1.DeviceResetCount
- [Controller->V1.DeviceStateChannel]
- [Controller->V1.DeviceStateTargetID] = 0;
- }
- memcpy(OldDeviceState, NewDeviceState,
- sizeof(DAC960_V1_DeviceState_T));
- }
- else if (CommandOpcode == DAC960_V1_GetLogicalDriveInformation)
- {
- int LogicalDriveNumber;
- for (LogicalDriveNumber = 0;
- LogicalDriveNumber < Controller->LogicalDriveCount;
- LogicalDriveNumber++)
- {
- DAC960_V1_LogicalDriveInformation_T *OldLogicalDriveInformation =
- &Controller->V1.LogicalDriveInformation[LogicalDriveNumber];
- DAC960_V1_LogicalDriveInformation_T *NewLogicalDriveInformation =
- &(*Controller->V1.NewLogicalDriveInformation)[LogicalDriveNumber];
- if (NewLogicalDriveInformation->LogicalDriveState !=
- OldLogicalDriveInformation->LogicalDriveState)
- DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
- "is now %s\n", Controller,
- LogicalDriveNumber,
- Controller->ControllerNumber,
- LogicalDriveNumber,
- (NewLogicalDriveInformation->LogicalDriveState
- == DAC960_V1_LogicalDrive_Online
- ? "ONLINE"
- : NewLogicalDriveInformation->LogicalDriveState
- == DAC960_V1_LogicalDrive_Critical
- ? "CRITICAL" : "OFFLINE"));
- if (NewLogicalDriveInformation->WriteBack !=
- OldLogicalDriveInformation->WriteBack)
- DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
- "is now %s\n", Controller,
- LogicalDriveNumber,
- Controller->ControllerNumber,
- LogicalDriveNumber,
- (NewLogicalDriveInformation->WriteBack
- ? "WRITE BACK" : "WRITE THRU"));
- }
- memcpy(&Controller->V1.LogicalDriveInformation,
- Controller->V1.NewLogicalDriveInformation,
- sizeof(DAC960_V1_LogicalDriveInformationArray_T));
- }
- else if (CommandOpcode == DAC960_V1_GetRebuildProgress)
- {
- unsigned int LogicalDriveNumber =
- Controller->V1.RebuildProgress->LogicalDriveNumber;
- unsigned int LogicalDriveSize =
- Controller->V1.RebuildProgress->LogicalDriveSize;
- unsigned int BlocksCompleted =
- LogicalDriveSize - Controller->V1.RebuildProgress->RemainingBlocks;
- if (CommandStatus == DAC960_V1_NoRebuildOrCheckInProgress &&
- Controller->V1.LastRebuildStatus == DAC960_V1_NormalCompletion)
- CommandStatus = DAC960_V1_RebuildSuccessful;
- switch (CommandStatus)
- {
- case DAC960_V1_NormalCompletion:
- Controller->EphemeralProgressMessage = true;
- DAC960_Progress("Rebuild in Progress: "
- "Logical Drive %d (/dev/rd/c%dd%d) "
- "%d%% completed\n",
- Controller, LogicalDriveNumber,
- Controller->ControllerNumber,
- LogicalDriveNumber,
- (100 * (BlocksCompleted >> 7))
- / (LogicalDriveSize >> 7));
- Controller->EphemeralProgressMessage = false;
- break;
- case DAC960_V1_RebuildFailed_LogicalDriveFailure:
- DAC960_Progress("Rebuild Failed due to "
- "Logical Drive Failure\n", Controller);
- break;
- case DAC960_V1_RebuildFailed_BadBlocksOnOther:
- DAC960_Progress("Rebuild Failed due to "
- "Bad Blocks on Other Drives\n", Controller);
- break;
- case DAC960_V1_RebuildFailed_NewDriveFailed:
- DAC960_Progress("Rebuild Failed due to "
- "Failure of Drive Being Rebuilt\n", Controller);
- break;
- case DAC960_V1_NoRebuildOrCheckInProgress:
- break;
- case DAC960_V1_RebuildSuccessful:
- DAC960_Progress("Rebuild Completed Successfully\n", Controller);
- break;
- case DAC960_V1_RebuildSuccessfullyTerminated:
- DAC960_Progress("Rebuild Successfully Terminated\n", Controller);
- break;
- }
- Controller->V1.LastRebuildStatus = CommandStatus;
- if (CommandType != DAC960_MonitoringCommand &&
- Controller->V1.RebuildStatusPending)
- {
- Command->V1.CommandStatus = Controller->V1.PendingRebuildStatus;
- Controller->V1.RebuildStatusPending = false;
- }
- else if (CommandType == DAC960_MonitoringCommand &&
- CommandStatus != DAC960_V1_NormalCompletion &&
- CommandStatus != DAC960_V1_NoRebuildOrCheckInProgress)
- {
- Controller->V1.PendingRebuildStatus = CommandStatus;
- Controller->V1.RebuildStatusPending = true;
- }
- }
- else if (CommandOpcode == DAC960_V1_RebuildStat)
- {
- unsigned int LogicalDriveNumber =
- Controller->V1.RebuildProgress->LogicalDriveNumber;
- unsigned int LogicalDriveSize =
- Controller->V1.RebuildProgress->LogicalDriveSize;
- unsigned int BlocksCompleted =
- LogicalDriveSize - Controller->V1.RebuildProgress->RemainingBlocks;
- if (CommandStatus == DAC960_V1_NormalCompletion)
- {
- Controller->EphemeralProgressMessage = true;
- DAC960_Progress("Consistency Check in Progress: "
- "Logical Drive %d (/dev/rd/c%dd%d) "
- "%d%% completed\n",
- Controller, LogicalDriveNumber,
- Controller->ControllerNumber,
- LogicalDriveNumber,
- (100 * (BlocksCompleted >> 7))
- / (LogicalDriveSize >> 7));
- Controller->EphemeralProgressMessage = false;
- }
- }
- else if (CommandOpcode == DAC960_V1_BackgroundInitializationControl)
- {
- unsigned int LogicalDriveNumber =
- Controller->V1.BackgroundInitializationStatus->LogicalDriveNumber;
- unsigned int LogicalDriveSize =
- Controller->V1.BackgroundInitializationStatus->LogicalDriveSize;
- unsigned int BlocksCompleted =
- Controller->V1.BackgroundInitializationStatus->BlocksCompleted;
- switch (CommandStatus)
- {
- case DAC960_V1_NormalCompletion:
- switch (Controller->V1.BackgroundInitializationStatus->Status)
- {
- case DAC960_V1_BackgroundInitializationInvalid:
- break;
- case DAC960_V1_BackgroundInitializationStarted:
- DAC960_Progress("Background Initialization Started\n",
- Controller);
- break;
- case DAC960_V1_BackgroundInitializationInProgress:
- if (BlocksCompleted ==
- Controller->V1.LastBackgroundInitializationStatus.
- BlocksCompleted &&
- LogicalDriveNumber ==
- Controller->V1.LastBackgroundInitializationStatus.
- LogicalDriveNumber)
- break;
- Controller->EphemeralProgressMessage = true;
- DAC960_Progress("Background Initialization in Progress: "
- "Logical Drive %d (/dev/rd/c%dd%d) "
- "%d%% completed\n",
- Controller, LogicalDriveNumber,
- Controller->ControllerNumber,
- LogicalDriveNumber,
- (100 * (BlocksCompleted >> 7))
- / (LogicalDriveSize >> 7));
- Controller->EphemeralProgressMessage = false;
- break;
- case DAC960_V1_BackgroundInitializationSuspended:
- DAC960_Progress("Background Initialization Suspended\n",
- Controller);
- break;
- case DAC960_V1_BackgroundInitializationCancelled:
- DAC960_Progress("Background Initialization Cancelled\n",
- Controller);
- break;
- }
- memcpy(&Controller->V1.LastBackgroundInitializationStatus,
- Controller->V1.BackgroundInitializationStatus,
- sizeof(DAC960_V1_BackgroundInitializationStatus_T));
- break;
- case DAC960_V1_BackgroundInitSuccessful:
- if (Controller->V1.BackgroundInitializationStatus->Status ==
- DAC960_V1_BackgroundInitializationInProgress)
- DAC960_Progress("Background Initialization "
- "Completed Successfully\n", Controller);
- Controller->V1.BackgroundInitializationStatus->Status =
- DAC960_V1_BackgroundInitializationInvalid;
- break;
- case DAC960_V1_BackgroundInitAborted:
- if (Controller->V1.BackgroundInitializationStatus->Status ==
- DAC960_V1_BackgroundInitializationInProgress)
- DAC960_Progress("Background Initialization Aborted\n",
- Controller);
- Controller->V1.BackgroundInitializationStatus->Status =
- DAC960_V1_BackgroundInitializationInvalid;
- break;
- case DAC960_V1_NoBackgroundInitInProgress:
- break;
- }
- }
- else if (CommandOpcode == DAC960_V1_DCDB)
- {
- /*
- This is a bit ugly.
-
- The InquiryStandardData and
- the InquiryUntitSerialNumber information
- retrieval operations BOTH use the DAC960_V1_DCDB
- commands. the test above can't distinguish between
- these two cases.
-
- Instead, we rely on the order of code later in this
- function to ensure that DeviceInquiryInformation commands
- are submitted before DeviceSerialNumber commands.
- */
- if (Controller->V1.NeedDeviceInquiryInformation)
- {
- DAC960_SCSI_Inquiry_T *InquiryStandardData =
- &Controller->V1.InquiryStandardData
- [Controller->V1.DeviceStateChannel]
- [Controller->V1.DeviceStateTargetID];
- if (CommandStatus != DAC960_V1_NormalCompletion)
- {
- memset(InquiryStandardData, 0,
- sizeof(DAC960_SCSI_Inquiry_T));
- InquiryStandardData->PeripheralDeviceType = 0x1F;
- }
- else
- memcpy(InquiryStandardData,
- Controller->V1.NewInquiryStandardData,
- sizeof(DAC960_SCSI_Inquiry_T));
- Controller->V1.NeedDeviceInquiryInformation = false;
- }
- else if (Controller->V1.NeedDeviceSerialNumberInformation)
- {
- DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber =
- &Controller->V1.InquiryUnitSerialNumber
- [Controller->V1.DeviceStateChannel]
- [Controller->V1.DeviceStateTargetID];
- if (CommandStatus != DAC960_V1_NormalCompletion)
- {
- memset(InquiryUnitSerialNumber, 0,
- sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T));
- InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F;
- }
- else
- memcpy(InquiryUnitSerialNumber,
- Controller->V1.NewInquiryUnitSerialNumber,
- sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T));
- Controller->V1.NeedDeviceSerialNumberInformation = false;
- }
- }
- /*
- Begin submitting new monitoring commands.
- */
- if (Controller->V1.NewEventLogSequenceNumber
- - Controller->V1.OldEventLogSequenceNumber > 0)
- {
- Command->V1.CommandMailbox.Type3E.CommandOpcode =
- DAC960_V1_PerformEventLogOperation;
- Command->V1.CommandMailbox.Type3E.OperationType =
- DAC960_V1_GetEventLogEntry;
- Command->V1.CommandMailbox.Type3E.OperationQualifier = 1;
- Command->V1.CommandMailbox.Type3E.SequenceNumber =
- Controller->V1.OldEventLogSequenceNumber;
- Command->V1.CommandMailbox.Type3E.BusAddress =
- Controller->V1.EventLogEntryDMA;
- DAC960_QueueCommand(Command);
- return;
- }
- if (Controller->V1.NeedErrorTableInformation)
- {
- Controller->V1.NeedErrorTableInformation = false;
- Command->V1.CommandMailbox.Type3.CommandOpcode =
- DAC960_V1_GetErrorTable;
- Command->V1.CommandMailbox.Type3.BusAddress =
- Controller->V1.NewErrorTableDMA;
- DAC960_QueueCommand(Command);
- return;
- }
- if (Controller->V1.NeedRebuildProgress &&
- Controller->V1.RebuildProgressFirst)
- {
- Controller->V1.NeedRebuildProgress = false;
- Command->V1.CommandMailbox.Type3.CommandOpcode =
- DAC960_V1_GetRebuildProgress;
- Command->V1.CommandMailbox.Type3.BusAddress =
- Controller->V1.RebuildProgressDMA;
- DAC960_QueueCommand(Command);
- return;
- }
- if (Controller->V1.NeedDeviceStateInformation)
- {
- if (Controller->V1.NeedDeviceInquiryInformation)
- {
- DAC960_V1_DCDB_T *DCDB = Controller->V1.MonitoringDCDB;
- dma_addr_t DCDB_DMA = Controller->V1.MonitoringDCDB_DMA;
-
- dma_addr_t NewInquiryStandardDataDMA =
- Controller->V1.NewInquiryStandardDataDMA;
-
- Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_DCDB;
- Command->V1.CommandMailbox.Type3.BusAddress = DCDB_DMA;
- DCDB->Channel = Controller->V1.DeviceStateChannel;
- DCDB->TargetID = Controller->V1.DeviceStateTargetID;
- DCDB->Direction = DAC960_V1_DCDB_DataTransferDeviceToSystem;
- DCDB->EarlyStatus = false;
- DCDB->Timeout = DAC960_V1_DCDB_Timeout_10_seconds;
- DCDB->NoAutomaticRequestSense = false;
- DCDB->DisconnectPermitted = true;
- DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_T);
- DCDB->BusAddress = NewInquiryStandardDataDMA;
- DCDB->CDBLength = 6;
- DCDB->TransferLengthHigh4 = 0;
- DCDB->SenseLength = sizeof(DCDB->SenseData);
- DCDB->CDB[0] = 0x12; /* INQUIRY */
- DCDB->CDB[1] = 0; /* EVPD = 0 */
- DCDB->CDB[2] = 0; /* Page Code */
- DCDB->CDB[3] = 0; /* Reserved */
- DCDB->CDB[4] = sizeof(DAC960_SCSI_Inquiry_T);
- DCDB->CDB[5] = 0; /* Control */
- DAC960_QueueCommand(Command);
- return;
- }
- if (Controller->V1.NeedDeviceSerialNumberInformation)
- {
- DAC960_V1_DCDB_T *DCDB = Controller->V1.MonitoringDCDB;
- dma_addr_t DCDB_DMA = Controller->V1.MonitoringDCDB_DMA;
- dma_addr_t NewInquiryUnitSerialNumberDMA =
- Controller->V1.NewInquiryUnitSerialNumberDMA;
-
- Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_DCDB;
- Command->V1.CommandMailbox.Type3.BusAddress = DCDB_DMA;
- DCDB->Channel = Controller->V1.DeviceStateChannel;
- DCDB->TargetID = Controller->V1.DeviceStateTargetID;
- DCDB->Direction = DAC960_V1_DCDB_DataTransferDeviceToSystem;
- DCDB->EarlyStatus = false;
- DCDB->Timeout = DAC960_V1_DCDB_Timeout_10_seconds;
- DCDB->NoAutomaticRequestSense = false;
- DCDB->DisconnectPermitted = true;
- DCDB->TransferLength =
- sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T);
- DCDB->BusAddress = NewInquiryUnitSerialNumberDMA;
- DCDB->CDBLength = 6;
- DCDB->TransferLengthHigh4 = 0;
- DCDB->SenseLength = sizeof(DCDB->SenseData);
- DCDB->CDB[0] = 0x12; /* INQUIRY */
- DCDB->CDB[1] = 1; /* EVPD = 1 */
- DCDB->CDB[2] = 0x80; /* Page Code */
- DCDB->CDB[3] = 0; /* Reserved */
- DCDB->CDB[4] = sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T);
- DCDB->CDB[5] = 0; /* Control */
- DAC960_QueueCommand(Command);
- return;
- }
- if (Controller->V1.StartDeviceStateScan)
- {
- Controller->V1.DeviceStateChannel = 0;
- Controller->V1.DeviceStateTargetID = 0;
- Controller->V1.StartDeviceStateScan = false;
- }
- else if (++Controller->V1.DeviceStateTargetID == Controller->Targets)
- {
- Controller->V1.DeviceStateChannel++;
- Controller->V1.DeviceStateTargetID = 0;
- }
- if (Controller->V1.DeviceStateChannel < Controller->Channels)
- {
- Controller->V1.NewDeviceState->DeviceState =
- DAC960_V1_Device_Dead;
- Command->V1.CommandMailbox.Type3D.CommandOpcode =
- DAC960_V1_GetDeviceState;
- Command->V1.CommandMailbox.Type3D.Channel =
- Controller->V1.DeviceStateChannel;
- Command->V1.CommandMailbox.Type3D.TargetID =
- Controller->V1.DeviceStateTargetID;
- Command->V1.CommandMailbox.Type3D.BusAddress =
- Controller->V1.NewDeviceStateDMA;
- DAC960_QueueCommand(Command);
- return;
- }
- Controller->V1.NeedDeviceStateInformation = false;
- }
- if (Controller->V1.NeedLogicalDriveInformation)
- {
- Controller->V1.NeedLogicalDriveInformation = false;
- Command->V1.CommandMailbox.Type3.CommandOpcode =
- DAC960_V1_GetLogicalDriveInformation;
- Command->V1.CommandMailbox.Type3.BusAddress =
- Controller->V1.NewLogicalDriveInformationDMA;
- DAC960_QueueCommand(Command);
- return;
- }
- if (Controller->V1.NeedRebuildProgress)
- {
- Controller->V1.NeedRebuildProgress = false;
- Command->V1.CommandMailbox.Type3.CommandOpcode =
- DAC960_V1_GetRebuildProgress;
- Command->V1.CommandMailbox.Type3.BusAddress =
- Controller->V1.RebuildProgressDMA;
- DAC960_QueueCommand(Command);
- return;
- }
- if (Controller->V1.NeedConsistencyCheckProgress)
- {
- Controller->V1.NeedConsistencyCheckProgress = false;
- Command->V1.CommandMailbox.Type3.CommandOpcode =
- DAC960_V1_RebuildStat;
- Command->V1.CommandMailbox.Type3.BusAddress =
- Controller->V1.RebuildProgressDMA;
- DAC960_QueueCommand(Command);
- return;
- }
- if (Controller->V1.NeedBackgroundInitializationStatus)
- {
- Controller->V1.NeedBackgroundInitializationStatus = false;
- Command->V1.CommandMailbox.Type3B.CommandOpcode =
- DAC960_V1_BackgroundInitializationControl;
- Command->V1.CommandMailbox.Type3B.CommandOpcode2 = 0x20;
- Command->V1.CommandMailbox.Type3B.BusAddress =
- Controller->V1.BackgroundInitializationStatusDMA;
- DAC960_QueueCommand(Command);
- return;
- }
- Controller->MonitoringTimerCount++;
- Controller->MonitoringTimer.expires =
- jiffies + DAC960_MonitoringTimerInterval;
- add_timer(&Controller->MonitoringTimer);
- }
- if (CommandType == DAC960_ImmediateCommand)
- {
- complete(Command->Completion);
- Command->Completion = NULL;
- return;
- }
- if (CommandType == DAC960_QueuedCommand)
- {
- DAC960_V1_KernelCommand_T *KernelCommand = Command->V1.KernelCommand;
- KernelCommand->CommandStatus = Command->V1.CommandStatus;
- Command->V1.KernelCommand = NULL;
- if (CommandOpcode == DAC960_V1_DCDB)
- Controller->V1.DirectCommandActive[KernelCommand->DCDB->Channel]
- [KernelCommand->DCDB->TargetID] =
- false;
- DAC960_DeallocateCommand(Command);
- KernelCommand->CompletionFunction(KernelCommand);
- return;
- }
- /*
- Queue a Status Monitoring Command to the Controller using the just
- completed Command if one was deferred previously due to lack of a
- free Command when the Monitoring Timer Function was called.
- */
- if (Controller->MonitoringCommandDeferred)
- {
- Controller->MonitoringCommandDeferred = false;
- DAC960_V1_QueueMonitoringCommand(Command);
- return;
- }
- /*
- Deallocate the Command.
- */
- DAC960_DeallocateCommand(Command);
- /*
- Wake up any processes waiting on a free Command.
- */
- wake_up(&Controller->CommandWaitQueue);
-}
-
-
-/*
- DAC960_V2_ReadWriteError prints an appropriate error message for Command
- when an error occurs on a Read or Write operation.
-*/
-
-static void DAC960_V2_ReadWriteError(DAC960_Command_T *Command)
-{
- DAC960_Controller_T *Controller = Command->Controller;
- static const unsigned char *SenseErrors[] = {
- "NO SENSE", "RECOVERED ERROR",
- "NOT READY", "MEDIUM ERROR",
- "HARDWARE ERROR", "ILLEGAL REQUEST",
- "UNIT ATTENTION", "DATA PROTECT",
- "BLANK CHECK", "VENDOR-SPECIFIC",
- "COPY ABORTED", "ABORTED COMMAND",
- "EQUAL", "VOLUME OVERFLOW",
- "MISCOMPARE", "RESERVED"
- };
- unsigned char *CommandName = "UNKNOWN";
- switch (Command->CommandType)
- {
- case DAC960_ReadCommand:
- case DAC960_ReadRetryCommand:
- CommandName = "READ";
- break;
- case DAC960_WriteCommand:
- case DAC960_WriteRetryCommand:
- CommandName = "WRITE";
- break;
- case DAC960_MonitoringCommand:
- case DAC960_ImmediateCommand:
- case DAC960_QueuedCommand:
- break;
- }
- DAC960_Error("Error Condition %s on %s:\n", Controller,
- SenseErrors[Command->V2.RequestSense->SenseKey], CommandName);
- DAC960_Error(" /dev/rd/c%dd%d: absolute blocks %u..%u\n",
- Controller, Controller->ControllerNumber,
- Command->LogicalDriveNumber, Command->BlockNumber,
- Command->BlockNumber + Command->BlockCount - 1);
-}
-
-
-/*
- DAC960_V2_ReportEvent prints an appropriate message when a Controller Event
- occurs.
-*/
-
-static void DAC960_V2_ReportEvent(DAC960_Controller_T *Controller,
- DAC960_V2_Event_T *Event)
-{
- DAC960_SCSI_RequestSense_T *RequestSense =
- (DAC960_SCSI_RequestSense_T *) &Event->RequestSenseData;
- unsigned char MessageBuffer[DAC960_LineBufferSize];
- static struct { int EventCode; unsigned char *EventMessage; } EventList[] =
- { /* Physical Device Events (0x0000 - 0x007F) */
- { 0x0001, "P Online" },
- { 0x0002, "P Standby" },
- { 0x0005, "P Automatic Rebuild Started" },
- { 0x0006, "P Manual Rebuild Started" },
- { 0x0007, "P Rebuild Completed" },
- { 0x0008, "P Rebuild Cancelled" },
- { 0x0009, "P Rebuild Failed for Unknown Reasons" },
- { 0x000A, "P Rebuild Failed due to New Physical Device" },
- { 0x000B, "P Rebuild Failed due to Logical Drive Failure" },
- { 0x000C, "S Offline" },
- { 0x000D, "P Found" },
- { 0x000E, "P Removed" },
- { 0x000F, "P Unconfigured" },
- { 0x0010, "P Expand Capacity Started" },
- { 0x0011, "P Expand Capacity Completed" },
- { 0x0012, "P Expand Capacity Failed" },
- { 0x0013, "P Command Timed Out" },
- { 0x0014, "P Command Aborted" },
- { 0x0015, "P Command Retried" },
- { 0x0016, "P Parity Error" },
- { 0x0017, "P Soft Error" },
- { 0x0018, "P Miscellaneous Error" },
- { 0x0019, "P Reset" },
- { 0x001A, "P Active Spare Found" },
- { 0x001B, "P Warm Spare Found" },
- { 0x001C, "S Sense Data Received" },
- { 0x001D, "P Initialization Started" },
- { 0x001E, "P Initialization Completed" },
- { 0x001F, "P Initialization Failed" },
- { 0x0020, "P Initialization Cancelled" },
- { 0x0021, "P Failed because Write Recovery Failed" },
- { 0x0022, "P Failed because SCSI Bus Reset Failed" },
- { 0x0023, "P Failed because of Double Check Condition" },
- { 0x0024, "P Failed because Device Cannot Be Accessed" },
- { 0x0025, "P Failed because of Gross Error on SCSI Processor" },
- { 0x0026, "P Failed because of Bad Tag from Device" },
- { 0x0027, "P Failed because of Command Timeout" },
- { 0x0028, "P Failed because of System Reset" },
- { 0x0029, "P Failed because of Busy Status or Parity Error" },
- { 0x002A, "P Failed because Host Set Device to Failed State" },
- { 0x002B, "P Failed because of Selection Timeout" },
- { 0x002C, "P Failed because of SCSI Bus Phase Error" },
- { 0x002D, "P Failed because Device Returned Unknown Status" },
- { 0x002E, "P Failed because Device Not Ready" },
- { 0x002F, "P Failed because Device Not Found at Startup" },
- { 0x0030, "P Failed because COD Write Operation Failed" },
- { 0x0031, "P Failed because BDT Write Operation Failed" },
- { 0x0039, "P Missing at Startup" },
- { 0x003A, "P Start Rebuild Failed due to Physical Drive Too Small" },
- { 0x003C, "P Temporarily Offline Device Automatically Made Online" },
- { 0x003D, "P Standby Rebuild Started" },
- /* Logical Device Events (0x0080 - 0x00FF) */
- { 0x0080, "M Consistency Check Started" },
- { 0x0081, "M Consistency Check Completed" },
- { 0x0082, "M Consistency Check Cancelled" },
- { 0x0083, "M Consistency Check Completed With Errors" },
- { 0x0084, "M Consistency Check Failed due to Logical Drive Failure" },
- { 0x0085, "M Consistency Check Failed due to Physical Device Failure" },
- { 0x0086, "L Offline" },
- { 0x0087, "L Critical" },
- { 0x0088, "L Online" },
- { 0x0089, "M Automatic Rebuild Started" },
- { 0x008A, "M Manual Rebuild Started" },
- { 0x008B, "M Rebuild Completed" },
- { 0x008C, "M Rebuild Cancelled" },
- { 0x008D, "M Rebuild Failed for Unknown Reasons" },
- { 0x008E, "M Rebuild Failed due to New Physical Device" },
- { 0x008F, "M Rebuild Failed due to Logical Drive Failure" },
- { 0x0090, "M Initialization Started" },
- { 0x0091, "M Initialization Completed" },
- { 0x0092, "M Initialization Cancelled" },
- { 0x0093, "M Initialization Failed" },
- { 0x0094, "L Found" },
- { 0x0095, "L Deleted" },
- { 0x0096, "M Expand Capacity Started" },
- { 0x0097, "M Expand Capacity Completed" },
- { 0x0098, "M Expand Capacity Failed" },
- { 0x0099, "L Bad Block Found" },
- { 0x009A, "L Size Changed" },
- { 0x009B, "L Type Changed" },
- { 0x009C, "L Bad Data Block Found" },
- { 0x009E, "L Read of Data Block in BDT" },
- { 0x009F, "L Write Back Data for Disk Block Lost" },
- { 0x00A0, "L Temporarily Offline RAID-5/3 Drive Made Online" },
- { 0x00A1, "L Temporarily Offline RAID-6/1/0/7 Drive Made Online" },
- { 0x00A2, "L Standby Rebuild Started" },
- /* Fault Management Events (0x0100 - 0x017F) */
- { 0x0140, "E Fan %d Failed" },
- { 0x0141, "E Fan %d OK" },
- { 0x0142, "E Fan %d Not Present" },
- { 0x0143, "E Power Supply %d Failed" },
- { 0x0144, "E Power Supply %d OK" },
- { 0x0145, "E Power Supply %d Not Present" },
- { 0x0146, "E Temperature Sensor %d Temperature Exceeds Safe Limit" },
- { 0x0147, "E Temperature Sensor %d Temperature Exceeds Working Limit" },
- { 0x0148, "E Temperature Sensor %d Temperature Normal" },
- { 0x0149, "E Temperature Sensor %d Not Present" },
- { 0x014A, "E Enclosure Management Unit %d Access Critical" },
- { 0x014B, "E Enclosure Management Unit %d Access OK" },
- { 0x014C, "E Enclosure Management Unit %d Access Offline" },
- /* Controller Events (0x0180 - 0x01FF) */
- { 0x0181, "C Cache Write Back Error" },
- { 0x0188, "C Battery Backup Unit Found" },
- { 0x0189, "C Battery Backup Unit Charge Level Low" },
- { 0x018A, "C Battery Backup Unit Charge Level OK" },
- { 0x0193, "C Installation Aborted" },
- { 0x0195, "C Battery Backup Unit Physically Removed" },
- { 0x0196, "C Memory Error During Warm Boot" },
- { 0x019E, "C Memory Soft ECC Error Corrected" },
- { 0x019F, "C Memory Hard ECC Error Corrected" },
- { 0x01A2, "C Battery Backup Unit Failed" },
- { 0x01AB, "C Mirror Race Recovery Failed" },
- { 0x01AC, "C Mirror Race on Critical Drive" },
- /* Controller Internal Processor Events */
- { 0x0380, "C Internal Controller Hung" },
- { 0x0381, "C Internal Controller Firmware Breakpoint" },
- { 0x0390, "C Internal Controller i960 Processor Specific Error" },
- { 0x03A0, "C Internal Controller StrongARM Processor Specific Error" },
- { 0, "" } };
- int EventListIndex = 0, EventCode;
- unsigned char EventType, *EventMessage;
- if (Event->EventCode == 0x1C &&
- RequestSense->SenseKey == DAC960_SenseKey_VendorSpecific &&
- (RequestSense->AdditionalSenseCode == 0x80 ||
- RequestSense->AdditionalSenseCode == 0x81))
- Event->EventCode = ((RequestSense->AdditionalSenseCode - 0x80) << 8) |
- RequestSense->AdditionalSenseCodeQualifier;
- while (true)
- {
- EventCode = EventList[EventListIndex].EventCode;
- if (EventCode == Event->EventCode || EventCode == 0) break;
- EventListIndex++;
- }
- EventType = EventList[EventListIndex].EventMessage[0];
- EventMessage = &EventList[EventListIndex].EventMessage[2];
- if (EventCode == 0)
- {
- DAC960_Critical("Unknown Controller Event Code %04X\n",
- Controller, Event->EventCode);
- return;
- }
- switch (EventType)
- {
- case 'P':
- DAC960_Critical("Physical Device %d:%d %s\n", Controller,
- Event->Channel, Event->TargetID, EventMessage);
- break;
- case 'L':
- DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) %s\n", Controller,
- Event->LogicalUnit, Controller->ControllerNumber,
- Event->LogicalUnit, EventMessage);
- break;
- case 'M':
- DAC960_Progress("Logical Drive %d (/dev/rd/c%dd%d) %s\n", Controller,
- Event->LogicalUnit, Controller->ControllerNumber,
- Event->LogicalUnit, EventMessage);
- break;
- case 'S':
- if (RequestSense->SenseKey == DAC960_SenseKey_NoSense ||
- (RequestSense->SenseKey == DAC960_SenseKey_NotReady &&
- RequestSense->AdditionalSenseCode == 0x04 &&
- (RequestSense->AdditionalSenseCodeQualifier == 0x01 ||
- RequestSense->AdditionalSenseCodeQualifier == 0x02)))
- break;
- DAC960_Critical("Physical Device %d:%d %s\n", Controller,
- Event->Channel, Event->TargetID, EventMessage);
- DAC960_Critical("Physical Device %d:%d Request Sense: "
- "Sense Key = %X, ASC = %02X, ASCQ = %02X\n",
- Controller,
- Event->Channel,
- Event->TargetID,
- RequestSense->SenseKey,
- RequestSense->AdditionalSenseCode,
- RequestSense->AdditionalSenseCodeQualifier);
- DAC960_Critical("Physical Device %d:%d Request Sense: "
- "Information = %02X%02X%02X%02X "
- "%02X%02X%02X%02X\n",
- Controller,
- Event->Channel,
- Event->TargetID,
- RequestSense->Information[0],
- RequestSense->Information[1],
- RequestSense->Information[2],
- RequestSense->Information[3],
- RequestSense->CommandSpecificInformation[0],
- RequestSense->CommandSpecificInformation[1],
- RequestSense->CommandSpecificInformation[2],
- RequestSense->CommandSpecificInformation[3]);
- break;
- case 'E':
- if (Controller->SuppressEnclosureMessages) break;
- sprintf(MessageBuffer, EventMessage, Event->LogicalUnit);
- DAC960_Critical("Enclosure %d %s\n", Controller,
- Event->TargetID, MessageBuffer);
- break;
- case 'C':
- DAC960_Critical("Controller %s\n", Controller, EventMessage);
- break;
- default:
- DAC960_Critical("Unknown Controller Event Code %04X\n",
- Controller, Event->EventCode);
- break;
- }
-}
-
-
-/*
- DAC960_V2_ReportProgress prints an appropriate progress message for
- Logical Device Long Operations.
-*/
-
-static void DAC960_V2_ReportProgress(DAC960_Controller_T *Controller,
- unsigned char *MessageString,
- unsigned int LogicalDeviceNumber,
- unsigned long BlocksCompleted,
- unsigned long LogicalDeviceSize)
-{
- Controller->EphemeralProgressMessage = true;
- DAC960_Progress("%s in Progress: Logical Drive %d (/dev/rd/c%dd%d) "
- "%d%% completed\n", Controller,
- MessageString,
- LogicalDeviceNumber,
- Controller->ControllerNumber,
- LogicalDeviceNumber,
- (100 * (BlocksCompleted >> 7)) / (LogicalDeviceSize >> 7));
- Controller->EphemeralProgressMessage = false;
-}
-
-
-/*
- DAC960_V2_ProcessCompletedCommand performs completion processing for Command
- for DAC960 V2 Firmware Controllers.
-*/
-
-static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command)
-{
- DAC960_Controller_T *Controller = Command->Controller;
- DAC960_CommandType_T CommandType = Command->CommandType;
- DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
- DAC960_V2_IOCTL_Opcode_T IOCTLOpcode = CommandMailbox->Common.IOCTL_Opcode;
- DAC960_V2_CommandOpcode_T CommandOpcode = CommandMailbox->SCSI_10.CommandOpcode;
- DAC960_V2_CommandStatus_T CommandStatus = Command->V2.CommandStatus;
-
- if (CommandType == DAC960_ReadCommand ||
- CommandType == DAC960_WriteCommand)
- {
-
-#ifdef FORCE_RETRY_DEBUG
- CommandStatus = DAC960_V2_AbormalCompletion;
-#endif
- Command->V2.RequestSense->SenseKey = DAC960_SenseKey_MediumError;
-
- if (CommandStatus == DAC960_V2_NormalCompletion) {
-
- if (!DAC960_ProcessCompletedRequest(Command, true))
- BUG();
-
- } else if (Command->V2.RequestSense->SenseKey == DAC960_SenseKey_MediumError)
- {
- /*
- * break the command down into pieces and resubmit each
- * piece, hoping that some of them will succeed.
- */
- DAC960_queue_partial_rw(Command);
- return;
- }
- else
- {
- if (Command->V2.RequestSense->SenseKey != DAC960_SenseKey_NotReady)
- DAC960_V2_ReadWriteError(Command);
- /*
- Perform completion processing for all buffers in this I/O Request.
- */
- (void)DAC960_ProcessCompletedRequest(Command, false);
- }
- }
- else if (CommandType == DAC960_ReadRetryCommand ||
- CommandType == DAC960_WriteRetryCommand)
- {
- bool normal_completion;
-
-#ifdef FORCE_RETRY_FAILURE_DEBUG
- static int retry_count = 1;
-#endif
- /*
- Perform completion processing for the portion that was
- retried, and submit the next portion, if any.
- */
- normal_completion = true;
- if (CommandStatus != DAC960_V2_NormalCompletion) {
- normal_completion = false;
- if (Command->V2.RequestSense->SenseKey != DAC960_SenseKey_NotReady)
- DAC960_V2_ReadWriteError(Command);
- }
-
-#ifdef FORCE_RETRY_FAILURE_DEBUG
- if (!(++retry_count % 10000)) {
- printk("V2 error retry failure test\n");
- normal_completion = false;
- DAC960_V2_ReadWriteError(Command);
- }
-#endif
-
- if (!DAC960_ProcessCompletedRequest(Command, normal_completion)) {
- DAC960_queue_partial_rw(Command);
- return;
- }
- }
- else if (CommandType == DAC960_MonitoringCommand)
- {
- if (Controller->ShutdownMonitoringTimer)
- return;
- if (IOCTLOpcode == DAC960_V2_GetControllerInfo)
- {
- DAC960_V2_ControllerInfo_T *NewControllerInfo =
- Controller->V2.NewControllerInformation;
- DAC960_V2_ControllerInfo_T *ControllerInfo =
- &Controller->V2.ControllerInformation;
- Controller->LogicalDriveCount =
- NewControllerInfo->LogicalDevicesPresent;
- Controller->V2.NeedLogicalDeviceInformation = true;
- Controller->V2.NeedPhysicalDeviceInformation = true;
- Controller->V2.StartLogicalDeviceInformationScan = true;
- Controller->V2.StartPhysicalDeviceInformationScan = true;
- Controller->MonitoringAlertMode =
- (NewControllerInfo->LogicalDevicesCritical > 0 ||
- NewControllerInfo->LogicalDevicesOffline > 0 ||
- NewControllerInfo->PhysicalDisksCritical > 0 ||
- NewControllerInfo->PhysicalDisksOffline > 0);
- memcpy(ControllerInfo, NewControllerInfo,
- sizeof(DAC960_V2_ControllerInfo_T));
- }
- else if (IOCTLOpcode == DAC960_V2_GetEvent)
- {
- if (CommandStatus == DAC960_V2_NormalCompletion) {
- DAC960_V2_ReportEvent(Controller, Controller->V2.Event);
- }
- Controller->V2.NextEventSequenceNumber++;
- }
- else if (IOCTLOpcode == DAC960_V2_GetPhysicalDeviceInfoValid &&
- CommandStatus == DAC960_V2_NormalCompletion)
- {
- DAC960_V2_PhysicalDeviceInfo_T *NewPhysicalDeviceInfo =
- Controller->V2.NewPhysicalDeviceInformation;
- unsigned int PhysicalDeviceIndex = Controller->V2.PhysicalDeviceIndex;
- DAC960_V2_PhysicalDeviceInfo_T *PhysicalDeviceInfo =
- Controller->V2.PhysicalDeviceInformation[PhysicalDeviceIndex];
- DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber =
- Controller->V2.InquiryUnitSerialNumber[PhysicalDeviceIndex];
- unsigned int DeviceIndex;
- while (PhysicalDeviceInfo != NULL &&
- (NewPhysicalDeviceInfo->Channel >
- PhysicalDeviceInfo->Channel ||
- (NewPhysicalDeviceInfo->Channel ==
- PhysicalDeviceInfo->Channel &&
- (NewPhysicalDeviceInfo->TargetID >
- PhysicalDeviceInfo->TargetID ||
- (NewPhysicalDeviceInfo->TargetID ==
- PhysicalDeviceInfo->TargetID &&
- NewPhysicalDeviceInfo->LogicalUnit >
- PhysicalDeviceInfo->LogicalUnit)))))
- {
- DAC960_Critical("Physical Device %d:%d No Longer Exists\n",
- Controller,
- PhysicalDeviceInfo->Channel,
- PhysicalDeviceInfo->TargetID);
- Controller->V2.PhysicalDeviceInformation
- [PhysicalDeviceIndex] = NULL;
- Controller->V2.InquiryUnitSerialNumber
- [PhysicalDeviceIndex] = NULL;
- kfree(PhysicalDeviceInfo);
- kfree(InquiryUnitSerialNumber);
- for (DeviceIndex = PhysicalDeviceIndex;
- DeviceIndex < DAC960_V2_MaxPhysicalDevices - 1;
- DeviceIndex++)
- {
- Controller->V2.PhysicalDeviceInformation[DeviceIndex] =
- Controller->V2.PhysicalDeviceInformation[DeviceIndex+1];
- Controller->V2.InquiryUnitSerialNumber[DeviceIndex] =
- Controller->V2.InquiryUnitSerialNumber[DeviceIndex+1];
- }
- Controller->V2.PhysicalDeviceInformation
- [DAC960_V2_MaxPhysicalDevices-1] = NULL;
- Controller->V2.InquiryUnitSerialNumber
- [DAC960_V2_MaxPhysicalDevices-1] = NULL;
- PhysicalDeviceInfo =
- Controller->V2.PhysicalDeviceInformation[PhysicalDeviceIndex];
- InquiryUnitSerialNumber =
- Controller->V2.InquiryUnitSerialNumber[PhysicalDeviceIndex];
- }
- if (PhysicalDeviceInfo == NULL ||
- (NewPhysicalDeviceInfo->Channel !=
- PhysicalDeviceInfo->Channel) ||
- (NewPhysicalDeviceInfo->TargetID !=
- PhysicalDeviceInfo->TargetID) ||
- (NewPhysicalDeviceInfo->LogicalUnit !=
- PhysicalDeviceInfo->LogicalUnit))
- {
- PhysicalDeviceInfo =
- kmalloc(sizeof(DAC960_V2_PhysicalDeviceInfo_T), GFP_ATOMIC);
- InquiryUnitSerialNumber =
- kmalloc(sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T),
- GFP_ATOMIC);
- if (InquiryUnitSerialNumber == NULL ||
- PhysicalDeviceInfo == NULL)
- {
- kfree(InquiryUnitSerialNumber);
- InquiryUnitSerialNumber = NULL;
- kfree(PhysicalDeviceInfo);
- PhysicalDeviceInfo = NULL;
- }
- DAC960_Critical("Physical Device %d:%d Now Exists%s\n",
- Controller,
- NewPhysicalDeviceInfo->Channel,
- NewPhysicalDeviceInfo->TargetID,
- (PhysicalDeviceInfo != NULL
- ? "" : " - Allocation Failed"));
- if (PhysicalDeviceInfo != NULL)
- {
- memset(PhysicalDeviceInfo, 0,
- sizeof(DAC960_V2_PhysicalDeviceInfo_T));
- PhysicalDeviceInfo->PhysicalDeviceState =
- DAC960_V2_Device_InvalidState;
- memset(InquiryUnitSerialNumber, 0,
- sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T));
- InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F;
- for (DeviceIndex = DAC960_V2_MaxPhysicalDevices - 1;
- DeviceIndex > PhysicalDeviceIndex;
- DeviceIndex--)
- {
- Controller->V2.PhysicalDeviceInformation[DeviceIndex] =
- Controller->V2.PhysicalDeviceInformation[DeviceIndex-1];
- Controller->V2.InquiryUnitSerialNumber[DeviceIndex] =
- Controller->V2.InquiryUnitSerialNumber[DeviceIndex-1];
- }
- Controller->V2.PhysicalDeviceInformation
- [PhysicalDeviceIndex] =
- PhysicalDeviceInfo;
- Controller->V2.InquiryUnitSerialNumber
- [PhysicalDeviceIndex] =
- InquiryUnitSerialNumber;
- Controller->V2.NeedDeviceSerialNumberInformation = true;
- }
- }
- if (PhysicalDeviceInfo != NULL)
- {
- if (NewPhysicalDeviceInfo->PhysicalDeviceState !=
- PhysicalDeviceInfo->PhysicalDeviceState)
- DAC960_Critical(
- "Physical Device %d:%d is now %s\n", Controller,
- NewPhysicalDeviceInfo->Channel,
- NewPhysicalDeviceInfo->TargetID,
- (NewPhysicalDeviceInfo->PhysicalDeviceState
- == DAC960_V2_Device_Online
- ? "ONLINE"
- : NewPhysicalDeviceInfo->PhysicalDeviceState
- == DAC960_V2_Device_Rebuild
- ? "REBUILD"
- : NewPhysicalDeviceInfo->PhysicalDeviceState
- == DAC960_V2_Device_Missing
- ? "MISSING"
- : NewPhysicalDeviceInfo->PhysicalDeviceState
- == DAC960_V2_Device_Critical
- ? "CRITICAL"
- : NewPhysicalDeviceInfo->PhysicalDeviceState
- == DAC960_V2_Device_Dead
- ? "DEAD"
- : NewPhysicalDeviceInfo->PhysicalDeviceState
- == DAC960_V2_Device_SuspectedDead
- ? "SUSPECTED-DEAD"
- : NewPhysicalDeviceInfo->PhysicalDeviceState
- == DAC960_V2_Device_CommandedOffline
- ? "COMMANDED-OFFLINE"
- : NewPhysicalDeviceInfo->PhysicalDeviceState
- == DAC960_V2_Device_Standby
- ? "STANDBY" : "UNKNOWN"));
- if ((NewPhysicalDeviceInfo->ParityErrors !=
- PhysicalDeviceInfo->ParityErrors) ||
- (NewPhysicalDeviceInfo->SoftErrors !=
- PhysicalDeviceInfo->SoftErrors) ||
- (NewPhysicalDeviceInfo->HardErrors !=
- PhysicalDeviceInfo->HardErrors) ||
- (NewPhysicalDeviceInfo->MiscellaneousErrors !=
- PhysicalDeviceInfo->MiscellaneousErrors) ||
- (NewPhysicalDeviceInfo->CommandTimeouts !=
- PhysicalDeviceInfo->CommandTimeouts) ||
- (NewPhysicalDeviceInfo->Retries !=
- PhysicalDeviceInfo->Retries) ||
- (NewPhysicalDeviceInfo->Aborts !=
- PhysicalDeviceInfo->Aborts) ||
- (NewPhysicalDeviceInfo->PredictedFailuresDetected !=
- PhysicalDeviceInfo->PredictedFailuresDetected))
- {
- DAC960_Critical("Physical Device %d:%d Errors: "
- "Parity = %d, Soft = %d, "
- "Hard = %d, Misc = %d\n",
- Controller,
- NewPhysicalDeviceInfo->Channel,
- NewPhysicalDeviceInfo->TargetID,
- NewPhysicalDeviceInfo->ParityErrors,
- NewPhysicalDeviceInfo->SoftErrors,
- NewPhysicalDeviceInfo->HardErrors,
- NewPhysicalDeviceInfo->MiscellaneousErrors);
- DAC960_Critical("Physical Device %d:%d Errors: "
- "Timeouts = %d, Retries = %d, "
- "Aborts = %d, Predicted = %d\n",
- Controller,
- NewPhysicalDeviceInfo->Channel,
- NewPhysicalDeviceInfo->TargetID,
- NewPhysicalDeviceInfo->CommandTimeouts,
- NewPhysicalDeviceInfo->Retries,
- NewPhysicalDeviceInfo->Aborts,
- NewPhysicalDeviceInfo
- ->PredictedFailuresDetected);
- }
- if ((PhysicalDeviceInfo->PhysicalDeviceState
- == DAC960_V2_Device_Dead ||
- PhysicalDeviceInfo->PhysicalDeviceState
- == DAC960_V2_Device_InvalidState) &&
- NewPhysicalDeviceInfo->PhysicalDeviceState
- != DAC960_V2_Device_Dead)
- Controller->V2.NeedDeviceSerialNumberInformation = true;
- memcpy(PhysicalDeviceInfo, NewPhysicalDeviceInfo,
- sizeof(DAC960_V2_PhysicalDeviceInfo_T));
- }
- NewPhysicalDeviceInfo->LogicalUnit++;
- Controller->V2.PhysicalDeviceIndex++;
- }
- else if (IOCTLOpcode == DAC960_V2_GetPhysicalDeviceInfoValid)
- {
- unsigned int DeviceIndex;
- for (DeviceIndex = Controller->V2.PhysicalDeviceIndex;
- DeviceIndex < DAC960_V2_MaxPhysicalDevices;
- DeviceIndex++)
- {
- DAC960_V2_PhysicalDeviceInfo_T *PhysicalDeviceInfo =
- Controller->V2.PhysicalDeviceInformation[DeviceIndex];
- DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber =
- Controller->V2.InquiryUnitSerialNumber[DeviceIndex];
- if (PhysicalDeviceInfo == NULL) break;
- DAC960_Critical("Physical Device %d:%d No Longer Exists\n",
- Controller,
- PhysicalDeviceInfo->Channel,
- PhysicalDeviceInfo->TargetID);
- Controller->V2.PhysicalDeviceInformation[DeviceIndex] = NULL;
- Controller->V2.InquiryUnitSerialNumber[DeviceIndex] = NULL;
- kfree(PhysicalDeviceInfo);
- kfree(InquiryUnitSerialNumber);
- }
- Controller->V2.NeedPhysicalDeviceInformation = false;
- }
- else if (IOCTLOpcode == DAC960_V2_GetLogicalDeviceInfoValid &&
- CommandStatus == DAC960_V2_NormalCompletion)
- {
- DAC960_V2_LogicalDeviceInfo_T *NewLogicalDeviceInfo =
- Controller->V2.NewLogicalDeviceInformation;
- unsigned short LogicalDeviceNumber =
- NewLogicalDeviceInfo->LogicalDeviceNumber;
- DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo =
- Controller->V2.LogicalDeviceInformation[LogicalDeviceNumber];
- if (LogicalDeviceInfo == NULL)
- {
- DAC960_V2_PhysicalDevice_T PhysicalDevice;
- PhysicalDevice.Controller = 0;
- PhysicalDevice.Channel = NewLogicalDeviceInfo->Channel;
- PhysicalDevice.TargetID = NewLogicalDeviceInfo->TargetID;
- PhysicalDevice.LogicalUnit = NewLogicalDeviceInfo->LogicalUnit;
- Controller->V2.LogicalDriveToVirtualDevice[LogicalDeviceNumber] =
- PhysicalDevice;
- LogicalDeviceInfo = kmalloc(sizeof(DAC960_V2_LogicalDeviceInfo_T),
- GFP_ATOMIC);
- Controller->V2.LogicalDeviceInformation[LogicalDeviceNumber] =
- LogicalDeviceInfo;
- DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
- "Now Exists%s\n", Controller,
- LogicalDeviceNumber,
- Controller->ControllerNumber,
- LogicalDeviceNumber,
- (LogicalDeviceInfo != NULL
- ? "" : " - Allocation Failed"));
- if (LogicalDeviceInfo != NULL)
- {
- memset(LogicalDeviceInfo, 0,
- sizeof(DAC960_V2_LogicalDeviceInfo_T));
- DAC960_ComputeGenericDiskInfo(Controller);
- }
- }
- if (LogicalDeviceInfo != NULL)
- {
- unsigned long LogicalDeviceSize =
- NewLogicalDeviceInfo->ConfigurableDeviceSize;
- if (NewLogicalDeviceInfo->LogicalDeviceState !=
- LogicalDeviceInfo->LogicalDeviceState)
- DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
- "is now %s\n", Controller,
- LogicalDeviceNumber,
- Controller->ControllerNumber,
- LogicalDeviceNumber,
- (NewLogicalDeviceInfo->LogicalDeviceState
- == DAC960_V2_LogicalDevice_Online
- ? "ONLINE"
- : NewLogicalDeviceInfo->LogicalDeviceState
- == DAC960_V2_LogicalDevice_Critical
- ? "CRITICAL" : "OFFLINE"));
- if ((NewLogicalDeviceInfo->SoftErrors !=
- LogicalDeviceInfo->SoftErrors) ||
- (NewLogicalDeviceInfo->CommandsFailed !=
- LogicalDeviceInfo->CommandsFailed) ||
- (NewLogicalDeviceInfo->DeferredWriteErrors !=
- LogicalDeviceInfo->DeferredWriteErrors))
- DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) Errors: "
- "Soft = %d, Failed = %d, Deferred Write = %d\n",
- Controller, LogicalDeviceNumber,
- Controller->ControllerNumber,
- LogicalDeviceNumber,
- NewLogicalDeviceInfo->SoftErrors,
- NewLogicalDeviceInfo->CommandsFailed,
- NewLogicalDeviceInfo->DeferredWriteErrors);
- if (NewLogicalDeviceInfo->ConsistencyCheckInProgress)
- DAC960_V2_ReportProgress(Controller,
- "Consistency Check",
- LogicalDeviceNumber,
- NewLogicalDeviceInfo
- ->ConsistencyCheckBlockNumber,
- LogicalDeviceSize);
- else if (NewLogicalDeviceInfo->RebuildInProgress)
- DAC960_V2_ReportProgress(Controller,
- "Rebuild",
- LogicalDeviceNumber,
- NewLogicalDeviceInfo
- ->RebuildBlockNumber,
- LogicalDeviceSize);
- else if (NewLogicalDeviceInfo->BackgroundInitializationInProgress)
- DAC960_V2_ReportProgress(Controller,
- "Background Initialization",
- LogicalDeviceNumber,
- NewLogicalDeviceInfo
- ->BackgroundInitializationBlockNumber,
- LogicalDeviceSize);
- else if (NewLogicalDeviceInfo->ForegroundInitializationInProgress)
- DAC960_V2_ReportProgress(Controller,
- "Foreground Initialization",
- LogicalDeviceNumber,
- NewLogicalDeviceInfo
- ->ForegroundInitializationBlockNumber,
- LogicalDeviceSize);
- else if (NewLogicalDeviceInfo->DataMigrationInProgress)
- DAC960_V2_ReportProgress(Controller,
- "Data Migration",
- LogicalDeviceNumber,
- NewLogicalDeviceInfo
- ->DataMigrationBlockNumber,
- LogicalDeviceSize);
- else if (NewLogicalDeviceInfo->PatrolOperationInProgress)
- DAC960_V2_ReportProgress(Controller,
- "Patrol Operation",
- LogicalDeviceNumber,
- NewLogicalDeviceInfo
- ->PatrolOperationBlockNumber,
- LogicalDeviceSize);
- if (LogicalDeviceInfo->BackgroundInitializationInProgress &&
- !NewLogicalDeviceInfo->BackgroundInitializationInProgress)
- DAC960_Progress("Logical Drive %d (/dev/rd/c%dd%d) "
- "Background Initialization %s\n",
- Controller,
- LogicalDeviceNumber,
- Controller->ControllerNumber,
- LogicalDeviceNumber,
- (NewLogicalDeviceInfo->LogicalDeviceControl
- .LogicalDeviceInitialized
- ? "Completed" : "Failed"));
- memcpy(LogicalDeviceInfo, NewLogicalDeviceInfo,
- sizeof(DAC960_V2_LogicalDeviceInfo_T));
- }
- Controller->V2.LogicalDriveFoundDuringScan
- [LogicalDeviceNumber] = true;
- NewLogicalDeviceInfo->LogicalDeviceNumber++;
- }
- else if (IOCTLOpcode == DAC960_V2_GetLogicalDeviceInfoValid)
- {
- int LogicalDriveNumber;
- for (LogicalDriveNumber = 0;
- LogicalDriveNumber < DAC960_MaxLogicalDrives;
- LogicalDriveNumber++)
- {
- DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo =
- Controller->V2.LogicalDeviceInformation[LogicalDriveNumber];
- if (LogicalDeviceInfo == NULL ||
- Controller->V2.LogicalDriveFoundDuringScan
- [LogicalDriveNumber])
- continue;
- DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
- "No Longer Exists\n", Controller,
- LogicalDriveNumber,
- Controller->ControllerNumber,
- LogicalDriveNumber);
- Controller->V2.LogicalDeviceInformation
- [LogicalDriveNumber] = NULL;
- kfree(LogicalDeviceInfo);
- Controller->LogicalDriveInitiallyAccessible
- [LogicalDriveNumber] = false;
- DAC960_ComputeGenericDiskInfo(Controller);
- }
- Controller->V2.NeedLogicalDeviceInformation = false;
- }
- else if (CommandOpcode == DAC960_V2_SCSI_10_Passthru)
- {
- DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber =
- Controller->V2.InquiryUnitSerialNumber[Controller->V2.PhysicalDeviceIndex - 1];
-
- if (CommandStatus != DAC960_V2_NormalCompletion) {
- memset(InquiryUnitSerialNumber,
- 0, sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T));
- InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F;
- } else
- memcpy(InquiryUnitSerialNumber,
- Controller->V2.NewInquiryUnitSerialNumber,
- sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T));
-
- Controller->V2.NeedDeviceSerialNumberInformation = false;
- }
-
- if (Controller->V2.HealthStatusBuffer->NextEventSequenceNumber
- - Controller->V2.NextEventSequenceNumber > 0)
- {
- CommandMailbox->GetEvent.CommandOpcode = DAC960_V2_IOCTL;
- CommandMailbox->GetEvent.DataTransferSize = sizeof(DAC960_V2_Event_T);
- CommandMailbox->GetEvent.EventSequenceNumberHigh16 =
- Controller->V2.NextEventSequenceNumber >> 16;
- CommandMailbox->GetEvent.ControllerNumber = 0;
- CommandMailbox->GetEvent.IOCTL_Opcode =
- DAC960_V2_GetEvent;
- CommandMailbox->GetEvent.EventSequenceNumberLow16 =
- Controller->V2.NextEventSequenceNumber & 0xFFFF;
- CommandMailbox->GetEvent.DataTransferMemoryAddress
- .ScatterGatherSegments[0]
- .SegmentDataPointer =
- Controller->V2.EventDMA;
- CommandMailbox->GetEvent.DataTransferMemoryAddress
- .ScatterGatherSegments[0]
- .SegmentByteCount =
- CommandMailbox->GetEvent.DataTransferSize;
- DAC960_QueueCommand(Command);
- return;
- }
- if (Controller->V2.NeedPhysicalDeviceInformation)
- {
- if (Controller->V2.NeedDeviceSerialNumberInformation)
- {
- DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber =
- Controller->V2.NewInquiryUnitSerialNumber;
- InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F;
-
- DAC960_V2_ConstructNewUnitSerialNumber(Controller, CommandMailbox,
- Controller->V2.NewPhysicalDeviceInformation->Channel,
- Controller->V2.NewPhysicalDeviceInformation->TargetID,
- Controller->V2.NewPhysicalDeviceInformation->LogicalUnit - 1);
-
-
- DAC960_QueueCommand(Command);
- return;
- }
- if (Controller->V2.StartPhysicalDeviceInformationScan)
- {
- Controller->V2.PhysicalDeviceIndex = 0;
- Controller->V2.NewPhysicalDeviceInformation->Channel = 0;
- Controller->V2.NewPhysicalDeviceInformation->TargetID = 0;
- Controller->V2.NewPhysicalDeviceInformation->LogicalUnit = 0;
- Controller->V2.StartPhysicalDeviceInformationScan = false;
- }
- CommandMailbox->PhysicalDeviceInfo.CommandOpcode = DAC960_V2_IOCTL;
- CommandMailbox->PhysicalDeviceInfo.DataTransferSize =
- sizeof(DAC960_V2_PhysicalDeviceInfo_T);
- CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.LogicalUnit =
- Controller->V2.NewPhysicalDeviceInformation->LogicalUnit;
- CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.TargetID =
- Controller->V2.NewPhysicalDeviceInformation->TargetID;
- CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.Channel =
- Controller->V2.NewPhysicalDeviceInformation->Channel;
- CommandMailbox->PhysicalDeviceInfo.IOCTL_Opcode =
- DAC960_V2_GetPhysicalDeviceInfoValid;
- CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress
- .ScatterGatherSegments[0]
- .SegmentDataPointer =
- Controller->V2.NewPhysicalDeviceInformationDMA;
- CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress
- .ScatterGatherSegments[0]
- .SegmentByteCount =
- CommandMailbox->PhysicalDeviceInfo.DataTransferSize;
- DAC960_QueueCommand(Command);
- return;
- }
- if (Controller->V2.NeedLogicalDeviceInformation)
- {
- if (Controller->V2.StartLogicalDeviceInformationScan)
- {
- int LogicalDriveNumber;
- for (LogicalDriveNumber = 0;
- LogicalDriveNumber < DAC960_MaxLogicalDrives;
- LogicalDriveNumber++)
- Controller->V2.LogicalDriveFoundDuringScan
- [LogicalDriveNumber] = false;
- Controller->V2.NewLogicalDeviceInformation->LogicalDeviceNumber = 0;
- Controller->V2.StartLogicalDeviceInformationScan = false;
- }
- CommandMailbox->LogicalDeviceInfo.CommandOpcode = DAC960_V2_IOCTL;
- CommandMailbox->LogicalDeviceInfo.DataTransferSize =
- sizeof(DAC960_V2_LogicalDeviceInfo_T);
- CommandMailbox->LogicalDeviceInfo.LogicalDevice.LogicalDeviceNumber =
- Controller->V2.NewLogicalDeviceInformation->LogicalDeviceNumber;
- CommandMailbox->LogicalDeviceInfo.IOCTL_Opcode =
- DAC960_V2_GetLogicalDeviceInfoValid;
- CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress
- .ScatterGatherSegments[0]
- .SegmentDataPointer =
- Controller->V2.NewLogicalDeviceInformationDMA;
- CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress
- .ScatterGatherSegments[0]
- .SegmentByteCount =
- CommandMailbox->LogicalDeviceInfo.DataTransferSize;
- DAC960_QueueCommand(Command);
- return;
- }
- Controller->MonitoringTimerCount++;
- Controller->MonitoringTimer.expires =
- jiffies + DAC960_HealthStatusMonitoringInterval;
- add_timer(&Controller->MonitoringTimer);
- }
- if (CommandType == DAC960_ImmediateCommand)
- {
- complete(Command->Completion);
- Command->Completion = NULL;
- return;
- }
- if (CommandType == DAC960_QueuedCommand)
- {
- DAC960_V2_KernelCommand_T *KernelCommand = Command->V2.KernelCommand;
- KernelCommand->CommandStatus = CommandStatus;
- KernelCommand->RequestSenseLength = Command->V2.RequestSenseLength;
- KernelCommand->DataTransferLength = Command->V2.DataTransferResidue;
- Command->V2.KernelCommand = NULL;
- DAC960_DeallocateCommand(Command);
- KernelCommand->CompletionFunction(KernelCommand);
- return;
- }
- /*
- Queue a Status Monitoring Command to the Controller using the just
- completed Command if one was deferred previously due to lack of a
- free Command when the Monitoring Timer Function was called.
- */
- if (Controller->MonitoringCommandDeferred)
- {
- Controller->MonitoringCommandDeferred = false;
- DAC960_V2_QueueMonitoringCommand(Command);
- return;
- }
- /*
- Deallocate the Command.
- */
- DAC960_DeallocateCommand(Command);
- /*
- Wake up any processes waiting on a free Command.
- */
- wake_up(&Controller->CommandWaitQueue);
-}
-
-/*
- DAC960_GEM_InterruptHandler handles hardware interrupts from DAC960 GEM Series
- Controllers.
-*/
-
-static irqreturn_t DAC960_GEM_InterruptHandler(int IRQ_Channel,
- void *DeviceIdentifier)
-{
- DAC960_Controller_T *Controller = DeviceIdentifier;
- void __iomem *ControllerBaseAddress = Controller->BaseAddress;
- DAC960_V2_StatusMailbox_T *NextStatusMailbox;
- unsigned long flags;
-
- spin_lock_irqsave(&Controller->queue_lock, flags);
- DAC960_GEM_AcknowledgeInterrupt(ControllerBaseAddress);
- NextStatusMailbox = Controller->V2.NextStatusMailbox;
- while (NextStatusMailbox->Fields.CommandIdentifier > 0)
- {
- DAC960_V2_CommandIdentifier_T CommandIdentifier =
- NextStatusMailbox->Fields.CommandIdentifier;
- DAC960_Command_T *Command = Controller->Commands[CommandIdentifier-1];
- Command->V2.CommandStatus = NextStatusMailbox->Fields.CommandStatus;
- Command->V2.RequestSenseLength =
- NextStatusMailbox->Fields.RequestSenseLength;
- Command->V2.DataTransferResidue =
- NextStatusMailbox->Fields.DataTransferResidue;
- NextStatusMailbox->Words[0] = 0;
- if (++NextStatusMailbox > Controller->V2.LastStatusMailbox)
- NextStatusMailbox = Controller->V2.FirstStatusMailbox;
- DAC960_V2_ProcessCompletedCommand(Command);
- }
- Controller->V2.NextStatusMailbox = NextStatusMailbox;
- /*
- Attempt to remove additional I/O Requests from the Controller's
- I/O Request Queue and queue them to the Controller.
- */
- DAC960_ProcessRequest(Controller);
- spin_unlock_irqrestore(&Controller->queue_lock, flags);
- return IRQ_HANDLED;
-}
-
-/*
- DAC960_BA_InterruptHandler handles hardware interrupts from DAC960 BA Series
- Controllers.
-*/
-
-static irqreturn_t DAC960_BA_InterruptHandler(int IRQ_Channel,
- void *DeviceIdentifier)
-{
- DAC960_Controller_T *Controller = DeviceIdentifier;
- void __iomem *ControllerBaseAddress = Controller->BaseAddress;
- DAC960_V2_StatusMailbox_T *NextStatusMailbox;
- unsigned long flags;
-
- spin_lock_irqsave(&Controller->queue_lock, flags);
- DAC960_BA_AcknowledgeInterrupt(ControllerBaseAddress);
- NextStatusMailbox = Controller->V2.NextStatusMailbox;
- while (NextStatusMailbox->Fields.CommandIdentifier > 0)
- {
- DAC960_V2_CommandIdentifier_T CommandIdentifier =
- NextStatusMailbox->Fields.CommandIdentifier;
- DAC960_Command_T *Command = Controller->Commands[CommandIdentifier-1];
- Command->V2.CommandStatus = NextStatusMailbox->Fields.CommandStatus;
- Command->V2.RequestSenseLength =
- NextStatusMailbox->Fields.RequestSenseLength;
- Command->V2.DataTransferResidue =
- NextStatusMailbox->Fields.DataTransferResidue;
- NextStatusMailbox->Words[0] = 0;
- if (++NextStatusMailbox > Controller->V2.LastStatusMailbox)
- NextStatusMailbox = Controller->V2.FirstStatusMailbox;
- DAC960_V2_ProcessCompletedCommand(Command);
- }
- Controller->V2.NextStatusMailbox = NextStatusMailbox;
- /*
- Attempt to remove additional I/O Requests from the Controller's
- I/O Request Queue and queue them to the Controller.
- */
- DAC960_ProcessRequest(Controller);
- spin_unlock_irqrestore(&Controller->queue_lock, flags);
- return IRQ_HANDLED;
-}
-
-
-/*
- DAC960_LP_InterruptHandler handles hardware interrupts from DAC960 LP Series
- Controllers.
-*/
-
-static irqreturn_t DAC960_LP_InterruptHandler(int IRQ_Channel,
- void *DeviceIdentifier)
-{
- DAC960_Controller_T *Controller = DeviceIdentifier;
- void __iomem *ControllerBaseAddress = Controller->BaseAddress;
- DAC960_V2_StatusMailbox_T *NextStatusMailbox;
- unsigned long flags;
-
- spin_lock_irqsave(&Controller->queue_lock, flags);
- DAC960_LP_AcknowledgeInterrupt(ControllerBaseAddress);
- NextStatusMailbox = Controller->V2.NextStatusMailbox;
- while (NextStatusMailbox->Fields.CommandIdentifier > 0)
- {
- DAC960_V2_CommandIdentifier_T CommandIdentifier =
- NextStatusMailbox->Fields.CommandIdentifier;
- DAC960_Command_T *Command = Controller->Commands[CommandIdentifier-1];
- Command->V2.CommandStatus = NextStatusMailbox->Fields.CommandStatus;
- Command->V2.RequestSenseLength =
- NextStatusMailbox->Fields.RequestSenseLength;
- Command->V2.DataTransferResidue =
- NextStatusMailbox->Fields.DataTransferResidue;
- NextStatusMailbox->Words[0] = 0;
- if (++NextStatusMailbox > Controller->V2.LastStatusMailbox)
- NextStatusMailbox = Controller->V2.FirstStatusMailbox;
- DAC960_V2_ProcessCompletedCommand(Command);
- }
- Controller->V2.NextStatusMailbox = NextStatusMailbox;
- /*
- Attempt to remove additional I/O Requests from the Controller's
- I/O Request Queue and queue them to the Controller.
- */
- DAC960_ProcessRequest(Controller);
- spin_unlock_irqrestore(&Controller->queue_lock, flags);
- return IRQ_HANDLED;
-}
-
-
-/*
- DAC960_LA_InterruptHandler handles hardware interrupts from DAC960 LA Series
- Controllers.
-*/
-
-static irqreturn_t DAC960_LA_InterruptHandler(int IRQ_Channel,
- void *DeviceIdentifier)
-{
- DAC960_Controller_T *Controller = DeviceIdentifier;
- void __iomem *ControllerBaseAddress = Controller->BaseAddress;
- DAC960_V1_StatusMailbox_T *NextStatusMailbox;
- unsigned long flags;
-
- spin_lock_irqsave(&Controller->queue_lock, flags);
- DAC960_LA_AcknowledgeInterrupt(ControllerBaseAddress);
- NextStatusMailbox = Controller->V1.NextStatusMailbox;
- while (NextStatusMailbox->Fields.Valid)
- {
- DAC960_V1_CommandIdentifier_T CommandIdentifier =
- NextStatusMailbox->Fields.CommandIdentifier;
- DAC960_Command_T *Command = Controller->Commands[CommandIdentifier-1];
- Command->V1.CommandStatus = NextStatusMailbox->Fields.CommandStatus;
- NextStatusMailbox->Word = 0;
- if (++NextStatusMailbox > Controller->V1.LastStatusMailbox)
- NextStatusMailbox = Controller->V1.FirstStatusMailbox;
- DAC960_V1_ProcessCompletedCommand(Command);
- }
- Controller->V1.NextStatusMailbox = NextStatusMailbox;
- /*
- Attempt to remove additional I/O Requests from the Controller's
- I/O Request Queue and queue them to the Controller.
- */
- DAC960_ProcessRequest(Controller);
- spin_unlock_irqrestore(&Controller->queue_lock, flags);
- return IRQ_HANDLED;
-}
-
-
-/*
- DAC960_PG_InterruptHandler handles hardware interrupts from DAC960 PG Series
- Controllers.
-*/
-
-static irqreturn_t DAC960_PG_InterruptHandler(int IRQ_Channel,
- void *DeviceIdentifier)
-{
- DAC960_Controller_T *Controller = DeviceIdentifier;
- void __iomem *ControllerBaseAddress = Controller->BaseAddress;
- DAC960_V1_StatusMailbox_T *NextStatusMailbox;
- unsigned long flags;
-
- spin_lock_irqsave(&Controller->queue_lock, flags);
- DAC960_PG_AcknowledgeInterrupt(ControllerBaseAddress);
- NextStatusMailbox = Controller->V1.NextStatusMailbox;
- while (NextStatusMailbox->Fields.Valid)
- {
- DAC960_V1_CommandIdentifier_T CommandIdentifier =
- NextStatusMailbox->Fields.CommandIdentifier;
- DAC960_Command_T *Command = Controller->Commands[CommandIdentifier-1];
- Command->V1.CommandStatus = NextStatusMailbox->Fields.CommandStatus;
- NextStatusMailbox->Word = 0;
- if (++NextStatusMailbox > Controller->V1.LastStatusMailbox)
- NextStatusMailbox = Controller->V1.FirstStatusMailbox;
- DAC960_V1_ProcessCompletedCommand(Command);
- }
- Controller->V1.NextStatusMailbox = NextStatusMailbox;
- /*
- Attempt to remove additional I/O Requests from the Controller's
- I/O Request Queue and queue them to the Controller.
- */
- DAC960_ProcessRequest(Controller);
- spin_unlock_irqrestore(&Controller->queue_lock, flags);
- return IRQ_HANDLED;
-}
-
-
-/*
- DAC960_PD_InterruptHandler handles hardware interrupts from DAC960 PD Series
- Controllers.
-*/
-
-static irqreturn_t DAC960_PD_InterruptHandler(int IRQ_Channel,
- void *DeviceIdentifier)
-{
- DAC960_Controller_T *Controller = DeviceIdentifier;
- void __iomem *ControllerBaseAddress = Controller->BaseAddress;
- unsigned long flags;
-
- spin_lock_irqsave(&Controller->queue_lock, flags);
- while (DAC960_PD_StatusAvailableP(ControllerBaseAddress))
- {
- DAC960_V1_CommandIdentifier_T CommandIdentifier =
- DAC960_PD_ReadStatusCommandIdentifier(ControllerBaseAddress);
- DAC960_Command_T *Command = Controller->Commands[CommandIdentifier-1];
- Command->V1.CommandStatus =
- DAC960_PD_ReadStatusRegister(ControllerBaseAddress);
- DAC960_PD_AcknowledgeInterrupt(ControllerBaseAddress);
- DAC960_PD_AcknowledgeStatus(ControllerBaseAddress);
- DAC960_V1_ProcessCompletedCommand(Command);
- }
- /*
- Attempt to remove additional I/O Requests from the Controller's
- I/O Request Queue and queue them to the Controller.
- */
- DAC960_ProcessRequest(Controller);
- spin_unlock_irqrestore(&Controller->queue_lock, flags);
- return IRQ_HANDLED;
-}
-
-
-/*
- DAC960_P_InterruptHandler handles hardware interrupts from DAC960 P Series
- Controllers.
-
- Translations of DAC960_V1_Enquiry and DAC960_V1_GetDeviceState rely
- on the data having been placed into DAC960_Controller_T, rather than
- an arbitrary buffer.
-*/
-
-static irqreturn_t DAC960_P_InterruptHandler(int IRQ_Channel,
- void *DeviceIdentifier)
-{
- DAC960_Controller_T *Controller = DeviceIdentifier;
- void __iomem *ControllerBaseAddress = Controller->BaseAddress;
- unsigned long flags;
-
- spin_lock_irqsave(&Controller->queue_lock, flags);
- while (DAC960_PD_StatusAvailableP(ControllerBaseAddress))
- {
- DAC960_V1_CommandIdentifier_T CommandIdentifier =
- DAC960_PD_ReadStatusCommandIdentifier(ControllerBaseAddress);
- DAC960_Command_T *Command = Controller->Commands[CommandIdentifier-1];
- DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
- DAC960_V1_CommandOpcode_T CommandOpcode =
- CommandMailbox->Common.CommandOpcode;
- Command->V1.CommandStatus =
- DAC960_PD_ReadStatusRegister(ControllerBaseAddress);
- DAC960_PD_AcknowledgeInterrupt(ControllerBaseAddress);
- DAC960_PD_AcknowledgeStatus(ControllerBaseAddress);
- switch (CommandOpcode)
- {
- case DAC960_V1_Enquiry_Old:
- Command->V1.CommandMailbox.Common.CommandOpcode = DAC960_V1_Enquiry;
- DAC960_P_To_PD_TranslateEnquiry(Controller->V1.NewEnquiry);
- break;
- case DAC960_V1_GetDeviceState_Old:
- Command->V1.CommandMailbox.Common.CommandOpcode =
- DAC960_V1_GetDeviceState;
- DAC960_P_To_PD_TranslateDeviceState(Controller->V1.NewDeviceState);
- break;
- case DAC960_V1_Read_Old:
- Command->V1.CommandMailbox.Common.CommandOpcode = DAC960_V1_Read;
- DAC960_P_To_PD_TranslateReadWriteCommand(CommandMailbox);
- break;
- case DAC960_V1_Write_Old:
- Command->V1.CommandMailbox.Common.CommandOpcode = DAC960_V1_Write;
- DAC960_P_To_PD_TranslateReadWriteCommand(CommandMailbox);
- break;
- case DAC960_V1_ReadWithScatterGather_Old:
- Command->V1.CommandMailbox.Common.CommandOpcode =
- DAC960_V1_ReadWithScatterGather;
- DAC960_P_To_PD_TranslateReadWriteCommand(CommandMailbox);
- break;
- case DAC960_V1_WriteWithScatterGather_Old:
- Command->V1.CommandMailbox.Common.CommandOpcode =
- DAC960_V1_WriteWithScatterGather;
- DAC960_P_To_PD_TranslateReadWriteCommand(CommandMailbox);
- break;
- default:
- break;
- }
- DAC960_V1_ProcessCompletedCommand(Command);
- }
- /*
- Attempt to remove additional I/O Requests from the Controller's
- I/O Request Queue and queue them to the Controller.
- */
- DAC960_ProcessRequest(Controller);
- spin_unlock_irqrestore(&Controller->queue_lock, flags);
- return IRQ_HANDLED;
-}
-
-
-/*
- DAC960_V1_QueueMonitoringCommand queues a Monitoring Command to DAC960 V1
- Firmware Controllers.
-*/
-
-static void DAC960_V1_QueueMonitoringCommand(DAC960_Command_T *Command)
-{
- DAC960_Controller_T *Controller = Command->Controller;
- DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
- DAC960_V1_ClearCommand(Command);
- Command->CommandType = DAC960_MonitoringCommand;
- CommandMailbox->Type3.CommandOpcode = DAC960_V1_Enquiry;
- CommandMailbox->Type3.BusAddress = Controller->V1.NewEnquiryDMA;
- DAC960_QueueCommand(Command);
-}
-
-
-/*
- DAC960_V2_QueueMonitoringCommand queues a Monitoring Command to DAC960 V2
- Firmware Controllers.
-*/
-
-static void DAC960_V2_QueueMonitoringCommand(DAC960_Command_T *Command)
-{
- DAC960_Controller_T *Controller = Command->Controller;
- DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
- DAC960_V2_ClearCommand(Command);
- Command->CommandType = DAC960_MonitoringCommand;
- CommandMailbox->ControllerInfo.CommandOpcode = DAC960_V2_IOCTL;
- CommandMailbox->ControllerInfo.CommandControlBits
- .DataTransferControllerToHost = true;
- CommandMailbox->ControllerInfo.CommandControlBits
- .NoAutoRequestSense = true;
- CommandMailbox->ControllerInfo.DataTransferSize =
- sizeof(DAC960_V2_ControllerInfo_T);
- CommandMailbox->ControllerInfo.ControllerNumber = 0;
- CommandMailbox->ControllerInfo.IOCTL_Opcode = DAC960_V2_GetControllerInfo;
- CommandMailbox->ControllerInfo.DataTransferMemoryAddress
- .ScatterGatherSegments[0]
- .SegmentDataPointer =
- Controller->V2.NewControllerInformationDMA;
- CommandMailbox->ControllerInfo.DataTransferMemoryAddress
- .ScatterGatherSegments[0]
- .SegmentByteCount =
- CommandMailbox->ControllerInfo.DataTransferSize;
- DAC960_QueueCommand(Command);
-}
-
-
-/*
- DAC960_MonitoringTimerFunction is the timer function for monitoring
- the status of DAC960 Controllers.
-*/
-
-static void DAC960_MonitoringTimerFunction(struct timer_list *t)
-{
- DAC960_Controller_T *Controller = from_timer(Controller, t, MonitoringTimer);
- DAC960_Command_T *Command;
- unsigned long flags;
-
- if (Controller->FirmwareType == DAC960_V1_Controller)
- {
- spin_lock_irqsave(&Controller->queue_lock, flags);
- /*
- Queue a Status Monitoring Command to Controller.
- */
- Command = DAC960_AllocateCommand(Controller);
- if (Command != NULL)
- DAC960_V1_QueueMonitoringCommand(Command);
- else Controller->MonitoringCommandDeferred = true;
- spin_unlock_irqrestore(&Controller->queue_lock, flags);
- }
- else
- {
- DAC960_V2_ControllerInfo_T *ControllerInfo =
- &Controller->V2.ControllerInformation;
- unsigned int StatusChangeCounter =
- Controller->V2.HealthStatusBuffer->StatusChangeCounter;
- bool ForceMonitoringCommand = false;
- if (time_after(jiffies, Controller->SecondaryMonitoringTime
- + DAC960_SecondaryMonitoringInterval))
- {
- int LogicalDriveNumber;
- for (LogicalDriveNumber = 0;
- LogicalDriveNumber < DAC960_MaxLogicalDrives;
- LogicalDriveNumber++)
- {
- DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo =
- Controller->V2.LogicalDeviceInformation[LogicalDriveNumber];
- if (LogicalDeviceInfo == NULL) continue;
- if (!LogicalDeviceInfo->LogicalDeviceControl
- .LogicalDeviceInitialized)
- {
- ForceMonitoringCommand = true;
- break;
- }
- }
- Controller->SecondaryMonitoringTime = jiffies;
- }
- if (StatusChangeCounter == Controller->V2.StatusChangeCounter &&
- Controller->V2.HealthStatusBuffer->NextEventSequenceNumber
- == Controller->V2.NextEventSequenceNumber &&
- (ControllerInfo->BackgroundInitializationsActive +
- ControllerInfo->LogicalDeviceInitializationsActive +
- ControllerInfo->PhysicalDeviceInitializationsActive +
- ControllerInfo->ConsistencyChecksActive +
- ControllerInfo->RebuildsActive +
- ControllerInfo->OnlineExpansionsActive == 0 ||
- time_before(jiffies, Controller->PrimaryMonitoringTime
- + DAC960_MonitoringTimerInterval)) &&
- !ForceMonitoringCommand)
- {
- Controller->MonitoringTimer.expires =
- jiffies + DAC960_HealthStatusMonitoringInterval;
- add_timer(&Controller->MonitoringTimer);
- return;
- }
- Controller->V2.StatusChangeCounter = StatusChangeCounter;
- Controller->PrimaryMonitoringTime = jiffies;
-
- spin_lock_irqsave(&Controller->queue_lock, flags);
- /*
- Queue a Status Monitoring Command to Controller.
- */
- Command = DAC960_AllocateCommand(Controller);
- if (Command != NULL)
- DAC960_V2_QueueMonitoringCommand(Command);
- else Controller->MonitoringCommandDeferred = true;
- spin_unlock_irqrestore(&Controller->queue_lock, flags);
- /*
- Wake up any processes waiting on a Health Status Buffer change.
- */
- wake_up(&Controller->HealthStatusWaitQueue);
- }
-}
-
-/*
- DAC960_CheckStatusBuffer verifies that there is room to hold ByteCount
- additional bytes in the Combined Status Buffer and grows the buffer if
- necessary. It returns true if there is enough room and false otherwise.
-*/
-
-static bool DAC960_CheckStatusBuffer(DAC960_Controller_T *Controller,
- unsigned int ByteCount)
-{
- unsigned char *NewStatusBuffer;
- if (Controller->InitialStatusLength + 1 +
- Controller->CurrentStatusLength + ByteCount + 1 <=
- Controller->CombinedStatusBufferLength)
- return true;
- if (Controller->CombinedStatusBufferLength == 0)
- {
- unsigned int NewStatusBufferLength = DAC960_InitialStatusBufferSize;
- while (NewStatusBufferLength < ByteCount)
- NewStatusBufferLength *= 2;
- Controller->CombinedStatusBuffer = kmalloc(NewStatusBufferLength,
- GFP_ATOMIC);
- if (Controller->CombinedStatusBuffer == NULL) return false;
- Controller->CombinedStatusBufferLength = NewStatusBufferLength;
- return true;
- }
- NewStatusBuffer = kmalloc_array(2, Controller->CombinedStatusBufferLength,
- GFP_ATOMIC);
- if (NewStatusBuffer == NULL)
- {
- DAC960_Warning("Unable to expand Combined Status Buffer - Truncating\n",
- Controller);
- return false;
- }
- memcpy(NewStatusBuffer, Controller->CombinedStatusBuffer,
- Controller->CombinedStatusBufferLength);
- kfree(Controller->CombinedStatusBuffer);
- Controller->CombinedStatusBuffer = NewStatusBuffer;
- Controller->CombinedStatusBufferLength *= 2;
- Controller->CurrentStatusBuffer =
- &NewStatusBuffer[Controller->InitialStatusLength + 1];
- return true;
-}
-
-
-/*
- DAC960_Message prints Driver Messages.
-*/
-
-static void DAC960_Message(DAC960_MessageLevel_T MessageLevel,
- unsigned char *Format,
- DAC960_Controller_T *Controller,
- ...)
-{
- static unsigned char Buffer[DAC960_LineBufferSize];
- static bool BeginningOfLine = true;
- va_list Arguments;
- int Length = 0;
- va_start(Arguments, Controller);
- Length = vsprintf(Buffer, Format, Arguments);
- va_end(Arguments);
- if (Controller == NULL)
- printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel],
- DAC960_ControllerCount, Buffer);
- else if (MessageLevel == DAC960_AnnounceLevel ||
- MessageLevel == DAC960_InfoLevel)
- {
- if (!Controller->ControllerInitialized)
- {
- if (DAC960_CheckStatusBuffer(Controller, Length))
- {
- strcpy(&Controller->CombinedStatusBuffer
- [Controller->InitialStatusLength],
- Buffer);
- Controller->InitialStatusLength += Length;
- Controller->CurrentStatusBuffer =
- &Controller->CombinedStatusBuffer
- [Controller->InitialStatusLength + 1];
- }
- if (MessageLevel == DAC960_AnnounceLevel)
- {
- static int AnnouncementLines = 0;
- if (++AnnouncementLines <= 2)
- printk("%sDAC960: %s", DAC960_MessageLevelMap[MessageLevel],
- Buffer);
- }
- else
- {
- if (BeginningOfLine)
- {
- if (Buffer[0] != '\n' || Length > 1)
- printk("%sDAC960#%d: %s",
- DAC960_MessageLevelMap[MessageLevel],
- Controller->ControllerNumber, Buffer);
- }
- else printk("%s", Buffer);
- }
- }
- else if (DAC960_CheckStatusBuffer(Controller, Length))
- {
- strcpy(&Controller->CurrentStatusBuffer[
- Controller->CurrentStatusLength], Buffer);
- Controller->CurrentStatusLength += Length;
- }
- }
- else if (MessageLevel == DAC960_ProgressLevel)
- {
- strcpy(Controller->ProgressBuffer, Buffer);
- Controller->ProgressBufferLength = Length;
- if (Controller->EphemeralProgressMessage)
- {
- if (time_after_eq(jiffies, Controller->LastProgressReportTime
- + DAC960_ProgressReportingInterval))
- {
- printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel],
- Controller->ControllerNumber, Buffer);
- Controller->LastProgressReportTime = jiffies;
- }
- }
- else printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel],
- Controller->ControllerNumber, Buffer);
- }
- else if (MessageLevel == DAC960_UserCriticalLevel)
- {
- strcpy(&Controller->UserStatusBuffer[Controller->UserStatusLength],
- Buffer);
- Controller->UserStatusLength += Length;
- if (Buffer[0] != '\n' || Length > 1)
- printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel],
- Controller->ControllerNumber, Buffer);
- }
- else
- {
- if (BeginningOfLine)
- printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel],
- Controller->ControllerNumber, Buffer);
- else printk("%s", Buffer);
- }
- BeginningOfLine = (Buffer[Length-1] == '\n');
-}
-
-
-/*
- DAC960_ParsePhysicalDevice parses spaces followed by a Physical Device
- Channel:TargetID specification from a User Command string. It updates
- Channel and TargetID and returns true on success and false on failure.
-*/
-
-static bool DAC960_ParsePhysicalDevice(DAC960_Controller_T *Controller,
- char *UserCommandString,
- unsigned char *Channel,
- unsigned char *TargetID)
-{
- char *NewUserCommandString = UserCommandString;
- unsigned long XChannel, XTargetID;
- while (*UserCommandString == ' ') UserCommandString++;
- if (UserCommandString == NewUserCommandString)
- return false;
- XChannel = simple_strtoul(UserCommandString, &NewUserCommandString, 10);
- if (NewUserCommandString == UserCommandString ||
- *NewUserCommandString != ':' ||
- XChannel >= Controller->Channels)
- return false;
- UserCommandString = ++NewUserCommandString;
- XTargetID = simple_strtoul(UserCommandString, &NewUserCommandString, 10);
- if (NewUserCommandString == UserCommandString ||
- *NewUserCommandString != '\0' ||
- XTargetID >= Controller->Targets)
- return false;
- *Channel = XChannel;
- *TargetID = XTargetID;
- return true;
-}
-
-
-/*
- DAC960_ParseLogicalDrive parses spaces followed by a Logical Drive Number
- specification from a User Command string. It updates LogicalDriveNumber and
- returns true on success and false on failure.
-*/
-
-static bool DAC960_ParseLogicalDrive(DAC960_Controller_T *Controller,
- char *UserCommandString,
- unsigned char *LogicalDriveNumber)
-{
- char *NewUserCommandString = UserCommandString;
- unsigned long XLogicalDriveNumber;
- while (*UserCommandString == ' ') UserCommandString++;
- if (UserCommandString == NewUserCommandString)
- return false;
- XLogicalDriveNumber =
- simple_strtoul(UserCommandString, &NewUserCommandString, 10);
- if (NewUserCommandString == UserCommandString ||
- *NewUserCommandString != '\0' ||
- XLogicalDriveNumber > DAC960_MaxLogicalDrives - 1)
- return false;
- *LogicalDriveNumber = XLogicalDriveNumber;
- return true;
-}
-
-
-/*
- DAC960_V1_SetDeviceState sets the Device State for a Physical Device for
- DAC960 V1 Firmware Controllers.
-*/
-
-static void DAC960_V1_SetDeviceState(DAC960_Controller_T *Controller,
- DAC960_Command_T *Command,
- unsigned char Channel,
- unsigned char TargetID,
- DAC960_V1_PhysicalDeviceState_T
- DeviceState,
- const unsigned char *DeviceStateString)
-{
- DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
- CommandMailbox->Type3D.CommandOpcode = DAC960_V1_StartDevice;
- CommandMailbox->Type3D.Channel = Channel;
- CommandMailbox->Type3D.TargetID = TargetID;
- CommandMailbox->Type3D.DeviceState = DeviceState;
- CommandMailbox->Type3D.Modifier = 0;
- DAC960_ExecuteCommand(Command);
- switch (Command->V1.CommandStatus)
- {
- case DAC960_V1_NormalCompletion:
- DAC960_UserCritical("%s of Physical Device %d:%d Succeeded\n", Controller,
- DeviceStateString, Channel, TargetID);
- break;
- case DAC960_V1_UnableToStartDevice:
- DAC960_UserCritical("%s of Physical Device %d:%d Failed - "
- "Unable to Start Device\n", Controller,
- DeviceStateString, Channel, TargetID);
- break;
- case DAC960_V1_NoDeviceAtAddress:
- DAC960_UserCritical("%s of Physical Device %d:%d Failed - "
- "No Device at Address\n", Controller,
- DeviceStateString, Channel, TargetID);
- break;
- case DAC960_V1_InvalidChannelOrTargetOrModifier:
- DAC960_UserCritical("%s of Physical Device %d:%d Failed - "
- "Invalid Channel or Target or Modifier\n",
- Controller, DeviceStateString, Channel, TargetID);
- break;
- case DAC960_V1_ChannelBusy:
- DAC960_UserCritical("%s of Physical Device %d:%d Failed - "
- "Channel Busy\n", Controller,
- DeviceStateString, Channel, TargetID);
- break;
- default:
- DAC960_UserCritical("%s of Physical Device %d:%d Failed - "
- "Unexpected Status %04X\n", Controller,
- DeviceStateString, Channel, TargetID,
- Command->V1.CommandStatus);
- break;
- }
-}
-
-
-/*
- DAC960_V1_ExecuteUserCommand executes a User Command for DAC960 V1 Firmware
- Controllers.
-*/
-
-static bool DAC960_V1_ExecuteUserCommand(DAC960_Controller_T *Controller,
- unsigned char *UserCommand)
-{
- DAC960_Command_T *Command;
- DAC960_V1_CommandMailbox_T *CommandMailbox;
- unsigned long flags;
- unsigned char Channel, TargetID, LogicalDriveNumber;
-
- spin_lock_irqsave(&Controller->queue_lock, flags);
- while ((Command = DAC960_AllocateCommand(Controller)) == NULL)
- DAC960_WaitForCommand(Controller);
- spin_unlock_irqrestore(&Controller->queue_lock, flags);
- Controller->UserStatusLength = 0;
- DAC960_V1_ClearCommand(Command);
- Command->CommandType = DAC960_ImmediateCommand;
- CommandMailbox = &Command->V1.CommandMailbox;
- if (strcmp(UserCommand, "flush-cache") == 0)
- {
- CommandMailbox->Type3.CommandOpcode = DAC960_V1_Flush;
- DAC960_ExecuteCommand(Command);
- DAC960_UserCritical("Cache Flush Completed\n", Controller);
- }
- else if (strncmp(UserCommand, "kill", 4) == 0 &&
- DAC960_ParsePhysicalDevice(Controller, &UserCommand[4],
- &Channel, &TargetID))
- {
- DAC960_V1_DeviceState_T *DeviceState =
- &Controller->V1.DeviceState[Channel][TargetID];
- if (DeviceState->Present &&
- DeviceState->DeviceType == DAC960_V1_DiskType &&
- DeviceState->DeviceState != DAC960_V1_Device_Dead)
- DAC960_V1_SetDeviceState(Controller, Command, Channel, TargetID,
- DAC960_V1_Device_Dead, "Kill");
- else DAC960_UserCritical("Kill of Physical Device %d:%d Illegal\n",
- Controller, Channel, TargetID);
- }
- else if (strncmp(UserCommand, "make-online", 11) == 0 &&
- DAC960_ParsePhysicalDevice(Controller, &UserCommand[11],
- &Channel, &TargetID))
- {
- DAC960_V1_DeviceState_T *DeviceState =
- &Controller->V1.DeviceState[Channel][TargetID];
- if (DeviceState->Present &&
- DeviceState->DeviceType == DAC960_V1_DiskType &&
- DeviceState->DeviceState == DAC960_V1_Device_Dead)
- DAC960_V1_SetDeviceState(Controller, Command, Channel, TargetID,
- DAC960_V1_Device_Online, "Make Online");
- else DAC960_UserCritical("Make Online of Physical Device %d:%d Illegal\n",
- Controller, Channel, TargetID);
-
- }
- else if (strncmp(UserCommand, "make-standby", 12) == 0 &&
- DAC960_ParsePhysicalDevice(Controller, &UserCommand[12],
- &Channel, &TargetID))
- {
- DAC960_V1_DeviceState_T *DeviceState =
- &Controller->V1.DeviceState[Channel][TargetID];
- if (DeviceState->Present &&
- DeviceState->DeviceType == DAC960_V1_DiskType &&
- DeviceState->DeviceState == DAC960_V1_Device_Dead)
- DAC960_V1_SetDeviceState(Controller, Command, Channel, TargetID,
- DAC960_V1_Device_Standby, "Make Standby");
- else DAC960_UserCritical("Make Standby of Physical "
- "Device %d:%d Illegal\n",
- Controller, Channel, TargetID);
- }
- else if (strncmp(UserCommand, "rebuild", 7) == 0 &&
- DAC960_ParsePhysicalDevice(Controller, &UserCommand[7],
- &Channel, &TargetID))
- {
- CommandMailbox->Type3D.CommandOpcode = DAC960_V1_RebuildAsync;
- CommandMailbox->Type3D.Channel = Channel;
- CommandMailbox->Type3D.TargetID = TargetID;
- DAC960_ExecuteCommand(Command);
- switch (Command->V1.CommandStatus)
- {
- case DAC960_V1_NormalCompletion:
- DAC960_UserCritical("Rebuild of Physical Device %d:%d Initiated\n",
- Controller, Channel, TargetID);
- break;
- case DAC960_V1_AttemptToRebuildOnlineDrive:
- DAC960_UserCritical("Rebuild of Physical Device %d:%d Failed - "
- "Attempt to Rebuild Online or "
- "Unresponsive Drive\n",
- Controller, Channel, TargetID);
- break;
- case DAC960_V1_NewDiskFailedDuringRebuild:
- DAC960_UserCritical("Rebuild of Physical Device %d:%d Failed - "
- "New Disk Failed During Rebuild\n",
- Controller, Channel, TargetID);
- break;
- case DAC960_V1_InvalidDeviceAddress:
- DAC960_UserCritical("Rebuild of Physical Device %d:%d Failed - "
- "Invalid Device Address\n",
- Controller, Channel, TargetID);
- break;
- case DAC960_V1_RebuildOrCheckAlreadyInProgress:
- DAC960_UserCritical("Rebuild of Physical Device %d:%d Failed - "
- "Rebuild or Consistency Check Already "
- "in Progress\n", Controller, Channel, TargetID);
- break;
- default:
- DAC960_UserCritical("Rebuild of Physical Device %d:%d Failed - "
- "Unexpected Status %04X\n", Controller,
- Channel, TargetID, Command->V1.CommandStatus);
- break;
- }
- }
- else if (strncmp(UserCommand, "check-consistency", 17) == 0 &&
- DAC960_ParseLogicalDrive(Controller, &UserCommand[17],
- &LogicalDriveNumber))
- {
- CommandMailbox->Type3C.CommandOpcode = DAC960_V1_CheckConsistencyAsync;
- CommandMailbox->Type3C.LogicalDriveNumber = LogicalDriveNumber;
- CommandMailbox->Type3C.AutoRestore = true;
- DAC960_ExecuteCommand(Command);
- switch (Command->V1.CommandStatus)
- {
- case DAC960_V1_NormalCompletion:
- DAC960_UserCritical("Consistency Check of Logical Drive %d "
- "(/dev/rd/c%dd%d) Initiated\n",
- Controller, LogicalDriveNumber,
- Controller->ControllerNumber,
- LogicalDriveNumber);
- break;
- case DAC960_V1_DependentDiskIsDead:
- DAC960_UserCritical("Consistency Check of Logical Drive %d "
- "(/dev/rd/c%dd%d) Failed - "
- "Dependent Physical Device is DEAD\n",
- Controller, LogicalDriveNumber,
- Controller->ControllerNumber,
- LogicalDriveNumber);
- break;
- case DAC960_V1_InvalidOrNonredundantLogicalDrive:
- DAC960_UserCritical("Consistency Check of Logical Drive %d "
- "(/dev/rd/c%dd%d) Failed - "
- "Invalid or Nonredundant Logical Drive\n",
- Controller, LogicalDriveNumber,
- Controller->ControllerNumber,
- LogicalDriveNumber);
- break;
- case DAC960_V1_RebuildOrCheckAlreadyInProgress:
- DAC960_UserCritical("Consistency Check of Logical Drive %d "
- "(/dev/rd/c%dd%d) Failed - Rebuild or "
- "Consistency Check Already in Progress\n",
- Controller, LogicalDriveNumber,
- Controller->ControllerNumber,
- LogicalDriveNumber);
- break;
- default:
- DAC960_UserCritical("Consistency Check of Logical Drive %d "
- "(/dev/rd/c%dd%d) Failed - "
- "Unexpected Status %04X\n",
- Controller, LogicalDriveNumber,
- Controller->ControllerNumber,
- LogicalDriveNumber, Command->V1.CommandStatus);
- break;
- }
- }
- else if (strcmp(UserCommand, "cancel-rebuild") == 0 ||
- strcmp(UserCommand, "cancel-consistency-check") == 0)
- {
- /*
- the OldRebuildRateConstant is never actually used
- once its value is retrieved from the controller.
- */
- unsigned char *OldRebuildRateConstant;
- dma_addr_t OldRebuildRateConstantDMA;
-
- OldRebuildRateConstant = pci_alloc_consistent( Controller->PCIDevice,
- sizeof(char), &OldRebuildRateConstantDMA);
- if (OldRebuildRateConstant == NULL) {
- DAC960_UserCritical("Cancellation of Rebuild or "
- "Consistency Check Failed - "
- "Out of Memory",
- Controller);
- goto failure;
- }
- CommandMailbox->Type3R.CommandOpcode = DAC960_V1_RebuildControl;
- CommandMailbox->Type3R.RebuildRateConstant = 0xFF;
- CommandMailbox->Type3R.BusAddress = OldRebuildRateConstantDMA;
- DAC960_ExecuteCommand(Command);
- switch (Command->V1.CommandStatus)
- {
- case DAC960_V1_NormalCompletion:
- DAC960_UserCritical("Rebuild or Consistency Check Cancelled\n",
- Controller);
- break;
- default:
- DAC960_UserCritical("Cancellation of Rebuild or "
- "Consistency Check Failed - "
- "Unexpected Status %04X\n",
- Controller, Command->V1.CommandStatus);
- break;
- }
-failure:
- pci_free_consistent(Controller->PCIDevice, sizeof(char),
- OldRebuildRateConstant, OldRebuildRateConstantDMA);
- }
- else DAC960_UserCritical("Illegal User Command: '%s'\n",
- Controller, UserCommand);
-
- spin_lock_irqsave(&Controller->queue_lock, flags);
- DAC960_DeallocateCommand(Command);
- spin_unlock_irqrestore(&Controller->queue_lock, flags);
- return true;
-}
-
-
-/*
- DAC960_V2_TranslatePhysicalDevice translates a Physical Device Channel and
- TargetID into a Logical Device. It returns true on success and false
- on failure.
-*/
-
-static bool DAC960_V2_TranslatePhysicalDevice(DAC960_Command_T *Command,
- unsigned char Channel,
- unsigned char TargetID,
- unsigned short
- *LogicalDeviceNumber)
-{
- DAC960_V2_CommandMailbox_T SavedCommandMailbox, *CommandMailbox;
- DAC960_Controller_T *Controller = Command->Controller;
-
- CommandMailbox = &Command->V2.CommandMailbox;
- memcpy(&SavedCommandMailbox, CommandMailbox,
- sizeof(DAC960_V2_CommandMailbox_T));
-
- CommandMailbox->PhysicalDeviceInfo.CommandOpcode = DAC960_V2_IOCTL;
- CommandMailbox->PhysicalDeviceInfo.CommandControlBits
- .DataTransferControllerToHost = true;
- CommandMailbox->PhysicalDeviceInfo.CommandControlBits
- .NoAutoRequestSense = true;
- CommandMailbox->PhysicalDeviceInfo.DataTransferSize =
- sizeof(DAC960_V2_PhysicalToLogicalDevice_T);
- CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.TargetID = TargetID;
- CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.Channel = Channel;
- CommandMailbox->PhysicalDeviceInfo.IOCTL_Opcode =
- DAC960_V2_TranslatePhysicalToLogicalDevice;
- CommandMailbox->Common.DataTransferMemoryAddress
- .ScatterGatherSegments[0]
- .SegmentDataPointer =
- Controller->V2.PhysicalToLogicalDeviceDMA;
- CommandMailbox->Common.DataTransferMemoryAddress
- .ScatterGatherSegments[0]
- .SegmentByteCount =
- CommandMailbox->Common.DataTransferSize;
-
- DAC960_ExecuteCommand(Command);
- *LogicalDeviceNumber = Controller->V2.PhysicalToLogicalDevice->LogicalDeviceNumber;
-
- memcpy(CommandMailbox, &SavedCommandMailbox,
- sizeof(DAC960_V2_CommandMailbox_T));
- return (Command->V2.CommandStatus == DAC960_V2_NormalCompletion);
-}
-
-
-/*
- DAC960_V2_ExecuteUserCommand executes a User Command for DAC960 V2 Firmware
- Controllers.
-*/
-
-static bool DAC960_V2_ExecuteUserCommand(DAC960_Controller_T *Controller,
- unsigned char *UserCommand)
-{
- DAC960_Command_T *Command;
- DAC960_V2_CommandMailbox_T *CommandMailbox;
- unsigned long flags;
- unsigned char Channel, TargetID, LogicalDriveNumber;
- unsigned short LogicalDeviceNumber;
-
- spin_lock_irqsave(&Controller->queue_lock, flags);
- while ((Command = DAC960_AllocateCommand(Controller)) == NULL)
- DAC960_WaitForCommand(Controller);
- spin_unlock_irqrestore(&Controller->queue_lock, flags);
- Controller->UserStatusLength = 0;
- DAC960_V2_ClearCommand(Command);
- Command->CommandType = DAC960_ImmediateCommand;
- CommandMailbox = &Command->V2.CommandMailbox;
- CommandMailbox->Common.CommandOpcode = DAC960_V2_IOCTL;
- CommandMailbox->Common.CommandControlBits.DataTransferControllerToHost = true;
- CommandMailbox->Common.CommandControlBits.NoAutoRequestSense = true;
- if (strcmp(UserCommand, "flush-cache") == 0)
- {
- CommandMailbox->DeviceOperation.IOCTL_Opcode = DAC960_V2_PauseDevice;
- CommandMailbox->DeviceOperation.OperationDevice =
- DAC960_V2_RAID_Controller;
- DAC960_ExecuteCommand(Command);
- DAC960_UserCritical("Cache Flush Completed\n", Controller);
- }
- else if (strncmp(UserCommand, "kill", 4) == 0 &&
- DAC960_ParsePhysicalDevice(Controller, &UserCommand[4],
- &Channel, &TargetID) &&
- DAC960_V2_TranslatePhysicalDevice(Command, Channel, TargetID,
- &LogicalDeviceNumber))
- {
- CommandMailbox->SetDeviceState.LogicalDevice.LogicalDeviceNumber =
- LogicalDeviceNumber;
- CommandMailbox->SetDeviceState.IOCTL_Opcode =
- DAC960_V2_SetDeviceState;
- CommandMailbox->SetDeviceState.DeviceState.PhysicalDeviceState =
- DAC960_V2_Device_Dead;
- DAC960_ExecuteCommand(Command);
- DAC960_UserCritical("Kill of Physical Device %d:%d %s\n",
- Controller, Channel, TargetID,
- (Command->V2.CommandStatus
- == DAC960_V2_NormalCompletion
- ? "Succeeded" : "Failed"));
- }
- else if (strncmp(UserCommand, "make-online", 11) == 0 &&
- DAC960_ParsePhysicalDevice(Controller, &UserCommand[11],
- &Channel, &TargetID) &&
- DAC960_V2_TranslatePhysicalDevice(Command, Channel, TargetID,
- &LogicalDeviceNumber))
- {
- CommandMailbox->SetDeviceState.LogicalDevice.LogicalDeviceNumber =
- LogicalDeviceNumber;
- CommandMailbox->SetDeviceState.IOCTL_Opcode =
- DAC960_V2_SetDeviceState;
- CommandMailbox->SetDeviceState.DeviceState.PhysicalDeviceState =
- DAC960_V2_Device_Online;
- DAC960_ExecuteCommand(Command);
- DAC960_UserCritical("Make Online of Physical Device %d:%d %s\n",
- Controller, Channel, TargetID,
- (Command->V2.CommandStatus
- == DAC960_V2_NormalCompletion
- ? "Succeeded" : "Failed"));
- }
- else if (strncmp(UserCommand, "make-standby", 12) == 0 &&
- DAC960_ParsePhysicalDevice(Controller, &UserCommand[12],
- &Channel, &TargetID) &&
- DAC960_V2_TranslatePhysicalDevice(Command, Channel, TargetID,
- &LogicalDeviceNumber))
- {
- CommandMailbox->SetDeviceState.LogicalDevice.LogicalDeviceNumber =
- LogicalDeviceNumber;
- CommandMailbox->SetDeviceState.IOCTL_Opcode =
- DAC960_V2_SetDeviceState;
- CommandMailbox->SetDeviceState.DeviceState.PhysicalDeviceState =
- DAC960_V2_Device_Standby;
- DAC960_ExecuteCommand(Command);
- DAC960_UserCritical("Make Standby of Physical Device %d:%d %s\n",
- Controller, Channel, TargetID,
- (Command->V2.CommandStatus
- == DAC960_V2_NormalCompletion
- ? "Succeeded" : "Failed"));
- }
- else if (strncmp(UserCommand, "rebuild", 7) == 0 &&
- DAC960_ParsePhysicalDevice(Controller, &UserCommand[7],
- &Channel, &TargetID) &&
- DAC960_V2_TranslatePhysicalDevice(Command, Channel, TargetID,
- &LogicalDeviceNumber))
- {
- CommandMailbox->LogicalDeviceInfo.LogicalDevice.LogicalDeviceNumber =
- LogicalDeviceNumber;
- CommandMailbox->LogicalDeviceInfo.IOCTL_Opcode =
- DAC960_V2_RebuildDeviceStart;
- DAC960_ExecuteCommand(Command);
- DAC960_UserCritical("Rebuild of Physical Device %d:%d %s\n",
- Controller, Channel, TargetID,
- (Command->V2.CommandStatus
- == DAC960_V2_NormalCompletion
- ? "Initiated" : "Not Initiated"));
- }
- else if (strncmp(UserCommand, "cancel-rebuild", 14) == 0 &&
- DAC960_ParsePhysicalDevice(Controller, &UserCommand[14],
- &Channel, &TargetID) &&
- DAC960_V2_TranslatePhysicalDevice(Command, Channel, TargetID,
- &LogicalDeviceNumber))
- {
- CommandMailbox->LogicalDeviceInfo.LogicalDevice.LogicalDeviceNumber =
- LogicalDeviceNumber;
- CommandMailbox->LogicalDeviceInfo.IOCTL_Opcode =
- DAC960_V2_RebuildDeviceStop;
- DAC960_ExecuteCommand(Command);
- DAC960_UserCritical("Rebuild of Physical Device %d:%d %s\n",
- Controller, Channel, TargetID,
- (Command->V2.CommandStatus
- == DAC960_V2_NormalCompletion
- ? "Cancelled" : "Not Cancelled"));
- }
- else if (strncmp(UserCommand, "check-consistency", 17) == 0 &&
- DAC960_ParseLogicalDrive(Controller, &UserCommand[17],
- &LogicalDriveNumber))
- {
- CommandMailbox->ConsistencyCheck.LogicalDevice.LogicalDeviceNumber =
- LogicalDriveNumber;
- CommandMailbox->ConsistencyCheck.IOCTL_Opcode =
- DAC960_V2_ConsistencyCheckStart;
- CommandMailbox->ConsistencyCheck.RestoreConsistency = true;
- CommandMailbox->ConsistencyCheck.InitializedAreaOnly = false;
- DAC960_ExecuteCommand(Command);
- DAC960_UserCritical("Consistency Check of Logical Drive %d "
- "(/dev/rd/c%dd%d) %s\n",
- Controller, LogicalDriveNumber,
- Controller->ControllerNumber,
- LogicalDriveNumber,
- (Command->V2.CommandStatus
- == DAC960_V2_NormalCompletion
- ? "Initiated" : "Not Initiated"));
- }
- else if (strncmp(UserCommand, "cancel-consistency-check", 24) == 0 &&
- DAC960_ParseLogicalDrive(Controller, &UserCommand[24],
- &LogicalDriveNumber))
- {
- CommandMailbox->ConsistencyCheck.LogicalDevice.LogicalDeviceNumber =
- LogicalDriveNumber;
- CommandMailbox->ConsistencyCheck.IOCTL_Opcode =
- DAC960_V2_ConsistencyCheckStop;
- DAC960_ExecuteCommand(Command);
- DAC960_UserCritical("Consistency Check of Logical Drive %d "
- "(/dev/rd/c%dd%d) %s\n",
- Controller, LogicalDriveNumber,
- Controller->ControllerNumber,
- LogicalDriveNumber,
- (Command->V2.CommandStatus
- == DAC960_V2_NormalCompletion
- ? "Cancelled" : "Not Cancelled"));
- }
- else if (strcmp(UserCommand, "perform-discovery") == 0)
- {
- CommandMailbox->Common.IOCTL_Opcode = DAC960_V2_StartDiscovery;
- DAC960_ExecuteCommand(Command);
- DAC960_UserCritical("Discovery %s\n", Controller,
- (Command->V2.CommandStatus
- == DAC960_V2_NormalCompletion
- ? "Initiated" : "Not Initiated"));
- if (Command->V2.CommandStatus == DAC960_V2_NormalCompletion)
- {
- CommandMailbox->ControllerInfo.CommandOpcode = DAC960_V2_IOCTL;
- CommandMailbox->ControllerInfo.CommandControlBits
- .DataTransferControllerToHost = true;
- CommandMailbox->ControllerInfo.CommandControlBits
- .NoAutoRequestSense = true;
- CommandMailbox->ControllerInfo.DataTransferSize =
- sizeof(DAC960_V2_ControllerInfo_T);
- CommandMailbox->ControllerInfo.ControllerNumber = 0;
- CommandMailbox->ControllerInfo.IOCTL_Opcode =
- DAC960_V2_GetControllerInfo;
- /*
- * How does this NOT race with the queued Monitoring
- * usage of this structure?
- */
- CommandMailbox->ControllerInfo.DataTransferMemoryAddress
- .ScatterGatherSegments[0]
- .SegmentDataPointer =
- Controller->V2.NewControllerInformationDMA;
- CommandMailbox->ControllerInfo.DataTransferMemoryAddress
- .ScatterGatherSegments[0]
- .SegmentByteCount =
- CommandMailbox->ControllerInfo.DataTransferSize;
- while (1) {
- DAC960_ExecuteCommand(Command);
- if (!Controller->V2.NewControllerInformation->PhysicalScanActive)
- break;
- msleep(1000);
- }
- DAC960_UserCritical("Discovery Completed\n", Controller);
- }
- }
- else if (strcmp(UserCommand, "suppress-enclosure-messages") == 0)
- Controller->SuppressEnclosureMessages = true;
- else DAC960_UserCritical("Illegal User Command: '%s'\n",
- Controller, UserCommand);
-
- spin_lock_irqsave(&Controller->queue_lock, flags);
- DAC960_DeallocateCommand(Command);
- spin_unlock_irqrestore(&Controller->queue_lock, flags);
- return true;
-}
-
-static int __maybe_unused dac960_proc_show(struct seq_file *m, void *v)
-{
- unsigned char *StatusMessage = "OK\n";
- int ControllerNumber;
- for (ControllerNumber = 0;
- ControllerNumber < DAC960_ControllerCount;
- ControllerNumber++)
- {
- DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber];
- if (Controller == NULL) continue;
- if (Controller->MonitoringAlertMode)
- {
- StatusMessage = "ALERT\n";
- break;
- }
- }
- seq_puts(m, StatusMessage);
- return 0;
-}
-
-static int __maybe_unused dac960_initial_status_proc_show(struct seq_file *m,
- void *v)
-{
- DAC960_Controller_T *Controller = (DAC960_Controller_T *)m->private;
- seq_printf(m, "%.*s", Controller->InitialStatusLength, Controller->CombinedStatusBuffer);
- return 0;
-}
-
-static int __maybe_unused dac960_current_status_proc_show(struct seq_file *m,
- void *v)
-{
- DAC960_Controller_T *Controller = (DAC960_Controller_T *) m->private;
- unsigned char *StatusMessage =
- "No Rebuild or Consistency Check in Progress\n";
- int ProgressMessageLength = strlen(StatusMessage);
- if (jiffies != Controller->LastCurrentStatusTime)
- {
- Controller->CurrentStatusLength = 0;
- DAC960_AnnounceDriver(Controller);
- DAC960_ReportControllerConfiguration(Controller);
- DAC960_ReportDeviceConfiguration(Controller);
- if (Controller->ProgressBufferLength > 0)
- ProgressMessageLength = Controller->ProgressBufferLength;
- if (DAC960_CheckStatusBuffer(Controller, 2 + ProgressMessageLength))
- {
- unsigned char *CurrentStatusBuffer = Controller->CurrentStatusBuffer;
- CurrentStatusBuffer[Controller->CurrentStatusLength++] = ' ';
- CurrentStatusBuffer[Controller->CurrentStatusLength++] = ' ';
- if (Controller->ProgressBufferLength > 0)
- strcpy(&CurrentStatusBuffer[Controller->CurrentStatusLength],
- Controller->ProgressBuffer);
- else
- strcpy(&CurrentStatusBuffer[Controller->CurrentStatusLength],
- StatusMessage);
- Controller->CurrentStatusLength += ProgressMessageLength;
- }
- Controller->LastCurrentStatusTime = jiffies;
- }
- seq_printf(m, "%.*s", Controller->CurrentStatusLength, Controller->CurrentStatusBuffer);
- return 0;
-}
-
-static int dac960_user_command_proc_show(struct seq_file *m, void *v)
-{
- DAC960_Controller_T *Controller = (DAC960_Controller_T *)m->private;
-
- seq_printf(m, "%.*s", Controller->UserStatusLength, Controller->UserStatusBuffer);
- return 0;
-}
-
-static int dac960_user_command_proc_open(struct inode *inode, struct file *file)
-{
- return single_open(file, dac960_user_command_proc_show, PDE_DATA(inode));
-}
-
-static ssize_t dac960_user_command_proc_write(struct file *file,
- const char __user *Buffer,
- size_t Count, loff_t *pos)
-{
- DAC960_Controller_T *Controller = PDE_DATA(file_inode(file));
- unsigned char CommandBuffer[80];
- int Length;
- if (Count > sizeof(CommandBuffer)-1) return -EINVAL;
- if (copy_from_user(CommandBuffer, Buffer, Count)) return -EFAULT;
- CommandBuffer[Count] = '\0';
- Length = strlen(CommandBuffer);
- if (Length > 0 && CommandBuffer[Length-1] == '\n')
- CommandBuffer[--Length] = '\0';
- if (Controller->FirmwareType == DAC960_V1_Controller)
- return (DAC960_V1_ExecuteUserCommand(Controller, CommandBuffer)
- ? Count : -EBUSY);
- else
- return (DAC960_V2_ExecuteUserCommand(Controller, CommandBuffer)
- ? Count : -EBUSY);
-}
-
-static const struct file_operations dac960_user_command_proc_fops = {
- .owner = THIS_MODULE,
- .open = dac960_user_command_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .write = dac960_user_command_proc_write,
-};
-
-/*
- DAC960_CreateProcEntries creates the /proc/rd/... entries for the
- DAC960 Driver.
-*/
-
-static void DAC960_CreateProcEntries(DAC960_Controller_T *Controller)
-{
- struct proc_dir_entry *ControllerProcEntry;
-
- if (DAC960_ProcDirectoryEntry == NULL) {
- DAC960_ProcDirectoryEntry = proc_mkdir("rd", NULL);
- proc_create_single("status", 0, DAC960_ProcDirectoryEntry,
- dac960_proc_show);
- }
-
- snprintf(Controller->ControllerName, sizeof(Controller->ControllerName),
- "c%d", Controller->ControllerNumber);
- ControllerProcEntry = proc_mkdir(Controller->ControllerName,
- DAC960_ProcDirectoryEntry);
- proc_create_single_data("initial_status", 0, ControllerProcEntry,
- dac960_initial_status_proc_show, Controller);
- proc_create_single_data("current_status", 0, ControllerProcEntry,
- dac960_current_status_proc_show, Controller);
- proc_create_data("user_command", 0600, ControllerProcEntry, &dac960_user_command_proc_fops, Controller);
- Controller->ControllerProcEntry = ControllerProcEntry;
-}
-
-
-/*
- DAC960_DestroyProcEntries destroys the /proc/rd/... entries for the
- DAC960 Driver.
-*/
-
-static void DAC960_DestroyProcEntries(DAC960_Controller_T *Controller)
-{
- if (Controller->ControllerProcEntry == NULL)
- return;
- remove_proc_entry("initial_status", Controller->ControllerProcEntry);
- remove_proc_entry("current_status", Controller->ControllerProcEntry);
- remove_proc_entry("user_command", Controller->ControllerProcEntry);
- remove_proc_entry(Controller->ControllerName, DAC960_ProcDirectoryEntry);
- Controller->ControllerProcEntry = NULL;
-}
-
-#ifdef DAC960_GAM_MINOR
-
-static long DAC960_gam_get_controller_info(DAC960_ControllerInfo_T __user *UserSpaceControllerInfo)
-{
- DAC960_ControllerInfo_T ControllerInfo;
- DAC960_Controller_T *Controller;
- int ControllerNumber;
- long ErrorCode;
-
- if (UserSpaceControllerInfo == NULL)
- ErrorCode = -EINVAL;
- else ErrorCode = get_user(ControllerNumber,
- &UserSpaceControllerInfo->ControllerNumber);
- if (ErrorCode != 0)
- goto out;
- ErrorCode = -ENXIO;
- if (ControllerNumber < 0 ||
- ControllerNumber > DAC960_ControllerCount - 1) {
- goto out;
- }
- Controller = DAC960_Controllers[ControllerNumber];
- if (Controller == NULL)
- goto out;
- memset(&ControllerInfo, 0, sizeof(DAC960_ControllerInfo_T));
- ControllerInfo.ControllerNumber = ControllerNumber;
- ControllerInfo.FirmwareType = Controller->FirmwareType;
- ControllerInfo.Channels = Controller->Channels;
- ControllerInfo.Targets = Controller->Targets;
- ControllerInfo.PCI_Bus = Controller->Bus;
- ControllerInfo.PCI_Device = Controller->Device;
- ControllerInfo.PCI_Function = Controller->Function;
- ControllerInfo.IRQ_Channel = Controller->IRQ_Channel;
- ControllerInfo.PCI_Address = Controller->PCI_Address;
- strcpy(ControllerInfo.ModelName, Controller->ModelName);
- strcpy(ControllerInfo.FirmwareVersion, Controller->FirmwareVersion);
- ErrorCode = (copy_to_user(UserSpaceControllerInfo, &ControllerInfo,
- sizeof(DAC960_ControllerInfo_T)) ? -EFAULT : 0);
-out:
- return ErrorCode;
-}
-
-static long DAC960_gam_v1_execute_command(DAC960_V1_UserCommand_T __user *UserSpaceUserCommand)
-{
- DAC960_V1_UserCommand_T UserCommand;
- DAC960_Controller_T *Controller;
- DAC960_Command_T *Command = NULL;
- DAC960_V1_CommandOpcode_T CommandOpcode;
- DAC960_V1_CommandStatus_T CommandStatus;
- DAC960_V1_DCDB_T DCDB;
- DAC960_V1_DCDB_T *DCDB_IOBUF = NULL;
- dma_addr_t DCDB_IOBUFDMA;
- unsigned long flags;
- int ControllerNumber, DataTransferLength;
- unsigned char *DataTransferBuffer = NULL;
- dma_addr_t DataTransferBufferDMA;
- long ErrorCode;
-
- if (UserSpaceUserCommand == NULL) {
- ErrorCode = -EINVAL;
- goto out;
- }
- if (copy_from_user(&UserCommand, UserSpaceUserCommand,
- sizeof(DAC960_V1_UserCommand_T))) {
- ErrorCode = -EFAULT;
- goto out;
- }
- ControllerNumber = UserCommand.ControllerNumber;
- ErrorCode = -ENXIO;
- if (ControllerNumber < 0 ||
- ControllerNumber > DAC960_ControllerCount - 1)
- goto out;
- Controller = DAC960_Controllers[ControllerNumber];
- if (Controller == NULL)
- goto out;
- ErrorCode = -EINVAL;
- if (Controller->FirmwareType != DAC960_V1_Controller)
- goto out;
- CommandOpcode = UserCommand.CommandMailbox.Common.CommandOpcode;
- DataTransferLength = UserCommand.DataTransferLength;
- if (CommandOpcode & 0x80)
- goto out;
- if (CommandOpcode == DAC960_V1_DCDB)
- {
- if (copy_from_user(&DCDB, UserCommand.DCDB,
- sizeof(DAC960_V1_DCDB_T))) {
- ErrorCode = -EFAULT;
- goto out;
- }
- if (DCDB.Channel >= DAC960_V1_MaxChannels)
- goto out;
- if (!((DataTransferLength == 0 &&
- DCDB.Direction
- == DAC960_V1_DCDB_NoDataTransfer) ||
- (DataTransferLength > 0 &&
- DCDB.Direction
- == DAC960_V1_DCDB_DataTransferDeviceToSystem) ||
- (DataTransferLength < 0 &&
- DCDB.Direction
- == DAC960_V1_DCDB_DataTransferSystemToDevice)))
- goto out;
- if (((DCDB.TransferLengthHigh4 << 16) | DCDB.TransferLength)
- != abs(DataTransferLength))
- goto out;
- DCDB_IOBUF = pci_alloc_consistent(Controller->PCIDevice,
- sizeof(DAC960_V1_DCDB_T), &DCDB_IOBUFDMA);
- if (DCDB_IOBUF == NULL) {
- ErrorCode = -ENOMEM;
- goto out;
- }
- }
- ErrorCode = -ENOMEM;
- if (DataTransferLength > 0)
- {
- DataTransferBuffer = pci_zalloc_consistent(Controller->PCIDevice,
- DataTransferLength,
- &DataTransferBufferDMA);
- if (DataTransferBuffer == NULL)
- goto out;
- }
- else if (DataTransferLength < 0)
- {
- DataTransferBuffer = pci_alloc_consistent(Controller->PCIDevice,
- -DataTransferLength, &DataTransferBufferDMA);
- if (DataTransferBuffer == NULL)
- goto out;
- if (copy_from_user(DataTransferBuffer,
- UserCommand.DataTransferBuffer,
- -DataTransferLength)) {
- ErrorCode = -EFAULT;
- goto out;
- }
- }
- if (CommandOpcode == DAC960_V1_DCDB)
- {
- spin_lock_irqsave(&Controller->queue_lock, flags);
- while ((Command = DAC960_AllocateCommand(Controller)) == NULL)
- DAC960_WaitForCommand(Controller);
- while (Controller->V1.DirectCommandActive[DCDB.Channel]
- [DCDB.TargetID])
- {
- spin_unlock_irq(&Controller->queue_lock);
- __wait_event(Controller->CommandWaitQueue,
- !Controller->V1.DirectCommandActive
- [DCDB.Channel][DCDB.TargetID]);
- spin_lock_irq(&Controller->queue_lock);
- }
- Controller->V1.DirectCommandActive[DCDB.Channel]
- [DCDB.TargetID] = true;
- spin_unlock_irqrestore(&Controller->queue_lock, flags);
- DAC960_V1_ClearCommand(Command);
- Command->CommandType = DAC960_ImmediateCommand;
- memcpy(&Command->V1.CommandMailbox, &UserCommand.CommandMailbox,
- sizeof(DAC960_V1_CommandMailbox_T));
- Command->V1.CommandMailbox.Type3.BusAddress = DCDB_IOBUFDMA;
- DCDB.BusAddress = DataTransferBufferDMA;
- memcpy(DCDB_IOBUF, &DCDB, sizeof(DAC960_V1_DCDB_T));
- }
- else
- {
- spin_lock_irqsave(&Controller->queue_lock, flags);
- while ((Command = DAC960_AllocateCommand(Controller)) == NULL)
- DAC960_WaitForCommand(Controller);
- spin_unlock_irqrestore(&Controller->queue_lock, flags);
- DAC960_V1_ClearCommand(Command);
- Command->CommandType = DAC960_ImmediateCommand;
- memcpy(&Command->V1.CommandMailbox, &UserCommand.CommandMailbox,
- sizeof(DAC960_V1_CommandMailbox_T));
- if (DataTransferBuffer != NULL)
- Command->V1.CommandMailbox.Type3.BusAddress =
- DataTransferBufferDMA;
- }
- DAC960_ExecuteCommand(Command);
- CommandStatus = Command->V1.CommandStatus;
- spin_lock_irqsave(&Controller->queue_lock, flags);
- DAC960_DeallocateCommand(Command);
- spin_unlock_irqrestore(&Controller->queue_lock, flags);
- if (DataTransferLength > 0)
- {
- if (copy_to_user(UserCommand.DataTransferBuffer,
- DataTransferBuffer, DataTransferLength)) {
- ErrorCode = -EFAULT;
- goto Failure1;
- }
- }
- if (CommandOpcode == DAC960_V1_DCDB)
- {
- /*
- I don't believe Target or Channel in the DCDB_IOBUF
- should be any different from the contents of DCDB.
- */
- Controller->V1.DirectCommandActive[DCDB.Channel]
- [DCDB.TargetID] = false;
- if (copy_to_user(UserCommand.DCDB, DCDB_IOBUF,
- sizeof(DAC960_V1_DCDB_T))) {
- ErrorCode = -EFAULT;
- goto Failure1;
- }
- }
- ErrorCode = CommandStatus;
- Failure1:
- if (DataTransferBuffer != NULL)
- pci_free_consistent(Controller->PCIDevice, abs(DataTransferLength),
- DataTransferBuffer, DataTransferBufferDMA);
- if (DCDB_IOBUF != NULL)
- pci_free_consistent(Controller->PCIDevice, sizeof(DAC960_V1_DCDB_T),
- DCDB_IOBUF, DCDB_IOBUFDMA);
- out:
- return ErrorCode;
-}
-
-static long DAC960_gam_v2_execute_command(DAC960_V2_UserCommand_T __user *UserSpaceUserCommand)
-{
- DAC960_V2_UserCommand_T UserCommand;
- DAC960_Controller_T *Controller;
- DAC960_Command_T *Command = NULL;
- DAC960_V2_CommandMailbox_T *CommandMailbox;
- DAC960_V2_CommandStatus_T CommandStatus;
- unsigned long flags;
- int ControllerNumber, DataTransferLength;
- int DataTransferResidue, RequestSenseLength;
- unsigned char *DataTransferBuffer = NULL;
- dma_addr_t DataTransferBufferDMA;
- unsigned char *RequestSenseBuffer = NULL;
- dma_addr_t RequestSenseBufferDMA;
- long ErrorCode = -EINVAL;
-
- if (UserSpaceUserCommand == NULL)
- goto out;
- if (copy_from_user(&UserCommand, UserSpaceUserCommand,
- sizeof(DAC960_V2_UserCommand_T))) {
- ErrorCode = -EFAULT;
- goto out;
- }
- ErrorCode = -ENXIO;
- ControllerNumber = UserCommand.ControllerNumber;
- if (ControllerNumber < 0 ||
- ControllerNumber > DAC960_ControllerCount - 1)
- goto out;
- Controller = DAC960_Controllers[ControllerNumber];
- if (Controller == NULL)
- goto out;
- if (Controller->FirmwareType != DAC960_V2_Controller){
- ErrorCode = -EINVAL;
- goto out;
- }
- DataTransferLength = UserCommand.DataTransferLength;
- ErrorCode = -ENOMEM;
- if (DataTransferLength > 0)
- {
- DataTransferBuffer = pci_zalloc_consistent(Controller->PCIDevice,
- DataTransferLength,
- &DataTransferBufferDMA);
- if (DataTransferBuffer == NULL)
- goto out;
- }
- else if (DataTransferLength < 0)
- {
- DataTransferBuffer = pci_alloc_consistent(Controller->PCIDevice,
- -DataTransferLength, &DataTransferBufferDMA);
- if (DataTransferBuffer == NULL)
- goto out;
- if (copy_from_user(DataTransferBuffer,
- UserCommand.DataTransferBuffer,
- -DataTransferLength)) {
- ErrorCode = -EFAULT;
- goto Failure2;
- }
- }
- RequestSenseLength = UserCommand.RequestSenseLength;
- if (RequestSenseLength > 0)
- {
- RequestSenseBuffer = pci_zalloc_consistent(Controller->PCIDevice,
- RequestSenseLength,
- &RequestSenseBufferDMA);
- if (RequestSenseBuffer == NULL)
- {
- ErrorCode = -ENOMEM;
- goto Failure2;
- }
- }
- spin_lock_irqsave(&Controller->queue_lock, flags);
- while ((Command = DAC960_AllocateCommand(Controller)) == NULL)
- DAC960_WaitForCommand(Controller);
- spin_unlock_irqrestore(&Controller->queue_lock, flags);
- DAC960_V2_ClearCommand(Command);
- Command->CommandType = DAC960_ImmediateCommand;
- CommandMailbox = &Command->V2.CommandMailbox;
- memcpy(CommandMailbox, &UserCommand.CommandMailbox,
- sizeof(DAC960_V2_CommandMailbox_T));
- CommandMailbox->Common.CommandControlBits
- .AdditionalScatterGatherListMemory = false;
- CommandMailbox->Common.CommandControlBits
- .NoAutoRequestSense = true;
- CommandMailbox->Common.DataTransferSize = 0;
- CommandMailbox->Common.DataTransferPageNumber = 0;
- memset(&CommandMailbox->Common.DataTransferMemoryAddress, 0,
- sizeof(DAC960_V2_DataTransferMemoryAddress_T));
- if (DataTransferLength != 0)
- {
- if (DataTransferLength > 0)
- {
- CommandMailbox->Common.CommandControlBits
- .DataTransferControllerToHost = true;
- CommandMailbox->Common.DataTransferSize = DataTransferLength;
- }
- else
- {
- CommandMailbox->Common.CommandControlBits
- .DataTransferControllerToHost = false;
- CommandMailbox->Common.DataTransferSize = -DataTransferLength;
- }
- CommandMailbox->Common.DataTransferMemoryAddress
- .ScatterGatherSegments[0]
- .SegmentDataPointer = DataTransferBufferDMA;
- CommandMailbox->Common.DataTransferMemoryAddress
- .ScatterGatherSegments[0]
- .SegmentByteCount =
- CommandMailbox->Common.DataTransferSize;
- }
- if (RequestSenseLength > 0)
- {
- CommandMailbox->Common.CommandControlBits
- .NoAutoRequestSense = false;
- CommandMailbox->Common.RequestSenseSize = RequestSenseLength;
- CommandMailbox->Common.RequestSenseBusAddress =
- RequestSenseBufferDMA;
- }
- DAC960_ExecuteCommand(Command);
- CommandStatus = Command->V2.CommandStatus;
- RequestSenseLength = Command->V2.RequestSenseLength;
- DataTransferResidue = Command->V2.DataTransferResidue;
- spin_lock_irqsave(&Controller->queue_lock, flags);
- DAC960_DeallocateCommand(Command);
- spin_unlock_irqrestore(&Controller->queue_lock, flags);
- if (RequestSenseLength > UserCommand.RequestSenseLength)
- RequestSenseLength = UserCommand.RequestSenseLength;
- if (copy_to_user(&UserSpaceUserCommand->DataTransferLength,
- &DataTransferResidue,
- sizeof(DataTransferResidue))) {
- ErrorCode = -EFAULT;
- goto Failure2;
- }
- if (copy_to_user(&UserSpaceUserCommand->RequestSenseLength,
- &RequestSenseLength, sizeof(RequestSenseLength))) {
- ErrorCode = -EFAULT;
- goto Failure2;
- }
- if (DataTransferLength > 0)
- {
- if (copy_to_user(UserCommand.DataTransferBuffer,
- DataTransferBuffer, DataTransferLength)) {
- ErrorCode = -EFAULT;
- goto Failure2;
- }
- }
- if (RequestSenseLength > 0)
- {
- if (copy_to_user(UserCommand.RequestSenseBuffer,
- RequestSenseBuffer, RequestSenseLength)) {
- ErrorCode = -EFAULT;
- goto Failure2;
- }
- }
- ErrorCode = CommandStatus;
- Failure2:
- pci_free_consistent(Controller->PCIDevice, abs(DataTransferLength),
- DataTransferBuffer, DataTransferBufferDMA);
- if (RequestSenseBuffer != NULL)
- pci_free_consistent(Controller->PCIDevice, RequestSenseLength,
- RequestSenseBuffer, RequestSenseBufferDMA);
-out:
- return ErrorCode;
-}
-
-static long DAC960_gam_v2_get_health_status(DAC960_V2_GetHealthStatus_T __user *UserSpaceGetHealthStatus)
-{
- DAC960_V2_GetHealthStatus_T GetHealthStatus;
- DAC960_V2_HealthStatusBuffer_T HealthStatusBuffer;
- DAC960_Controller_T *Controller;
- int ControllerNumber;
- long ErrorCode;
-
- if (UserSpaceGetHealthStatus == NULL) {
- ErrorCode = -EINVAL;
- goto out;
- }
- if (copy_from_user(&GetHealthStatus, UserSpaceGetHealthStatus,
- sizeof(DAC960_V2_GetHealthStatus_T))) {
- ErrorCode = -EFAULT;
- goto out;
- }
- ErrorCode = -ENXIO;
- ControllerNumber = GetHealthStatus.ControllerNumber;
- if (ControllerNumber < 0 ||
- ControllerNumber > DAC960_ControllerCount - 1)
- goto out;
- Controller = DAC960_Controllers[ControllerNumber];
- if (Controller == NULL)
- goto out;
- if (Controller->FirmwareType != DAC960_V2_Controller) {
- ErrorCode = -EINVAL;
- goto out;
- }
- if (copy_from_user(&HealthStatusBuffer,
- GetHealthStatus.HealthStatusBuffer,
- sizeof(DAC960_V2_HealthStatusBuffer_T))) {
- ErrorCode = -EFAULT;
- goto out;
- }
- ErrorCode = wait_event_interruptible_timeout(Controller->HealthStatusWaitQueue,
- !(Controller->V2.HealthStatusBuffer->StatusChangeCounter
- == HealthStatusBuffer.StatusChangeCounter &&
- Controller->V2.HealthStatusBuffer->NextEventSequenceNumber
- == HealthStatusBuffer.NextEventSequenceNumber),
- DAC960_MonitoringTimerInterval);
- if (ErrorCode == -ERESTARTSYS) {
- ErrorCode = -EINTR;
- goto out;
- }
- if (copy_to_user(GetHealthStatus.HealthStatusBuffer,
- Controller->V2.HealthStatusBuffer,
- sizeof(DAC960_V2_HealthStatusBuffer_T)))
- ErrorCode = -EFAULT;
- else
- ErrorCode = 0;
-
-out:
- return ErrorCode;
-}
-
-/*
- * DAC960_gam_ioctl is the ioctl function for performing RAID operations.
-*/
-
-static long DAC960_gam_ioctl(struct file *file, unsigned int Request,
- unsigned long Argument)
-{
- long ErrorCode = 0;
- void __user *argp = (void __user *)Argument;
- if (!capable(CAP_SYS_ADMIN)) return -EACCES;
-
- mutex_lock(&DAC960_mutex);
- switch (Request)
- {
- case DAC960_IOCTL_GET_CONTROLLER_COUNT:
- ErrorCode = DAC960_ControllerCount;
- break;
- case DAC960_IOCTL_GET_CONTROLLER_INFO:
- ErrorCode = DAC960_gam_get_controller_info(argp);
- break;
- case DAC960_IOCTL_V1_EXECUTE_COMMAND:
- ErrorCode = DAC960_gam_v1_execute_command(argp);
- break;
- case DAC960_IOCTL_V2_EXECUTE_COMMAND:
- ErrorCode = DAC960_gam_v2_execute_command(argp);
- break;
- case DAC960_IOCTL_V2_GET_HEALTH_STATUS:
- ErrorCode = DAC960_gam_v2_get_health_status(argp);
- break;
- default:
- ErrorCode = -ENOTTY;
- }
- mutex_unlock(&DAC960_mutex);
- return ErrorCode;
-}
-
-static const struct file_operations DAC960_gam_fops = {
- .owner = THIS_MODULE,
- .unlocked_ioctl = DAC960_gam_ioctl,
- .llseek = noop_llseek,
-};
-
-static struct miscdevice DAC960_gam_dev = {
- DAC960_GAM_MINOR,
- "dac960_gam",
- &DAC960_gam_fops
-};
-
-static int DAC960_gam_init(void)
-{
- int ret;
-
- ret = misc_register(&DAC960_gam_dev);
- if (ret)
- printk(KERN_ERR "DAC960_gam: can't misc_register on minor %d\n", DAC960_GAM_MINOR);
- return ret;
-}
-
-static void DAC960_gam_cleanup(void)
-{
- misc_deregister(&DAC960_gam_dev);
-}
-
-#endif /* DAC960_GAM_MINOR */
-
-static struct DAC960_privdata DAC960_GEM_privdata = {
- .HardwareType = DAC960_GEM_Controller,
- .FirmwareType = DAC960_V2_Controller,
- .InterruptHandler = DAC960_GEM_InterruptHandler,
- .MemoryWindowSize = DAC960_GEM_RegisterWindowSize,
-};
-
-
-static struct DAC960_privdata DAC960_BA_privdata = {
- .HardwareType = DAC960_BA_Controller,
- .FirmwareType = DAC960_V2_Controller,
- .InterruptHandler = DAC960_BA_InterruptHandler,
- .MemoryWindowSize = DAC960_BA_RegisterWindowSize,
-};
-
-static struct DAC960_privdata DAC960_LP_privdata = {
- .HardwareType = DAC960_LP_Controller,
- .FirmwareType = DAC960_V2_Controller,
- .InterruptHandler = DAC960_LP_InterruptHandler,
- .MemoryWindowSize = DAC960_LP_RegisterWindowSize,
-};
-
-static struct DAC960_privdata DAC960_LA_privdata = {
- .HardwareType = DAC960_LA_Controller,
- .FirmwareType = DAC960_V1_Controller,
- .InterruptHandler = DAC960_LA_InterruptHandler,
- .MemoryWindowSize = DAC960_LA_RegisterWindowSize,
-};
-
-static struct DAC960_privdata DAC960_PG_privdata = {
- .HardwareType = DAC960_PG_Controller,
- .FirmwareType = DAC960_V1_Controller,
- .InterruptHandler = DAC960_PG_InterruptHandler,
- .MemoryWindowSize = DAC960_PG_RegisterWindowSize,
-};
-
-static struct DAC960_privdata DAC960_PD_privdata = {
- .HardwareType = DAC960_PD_Controller,
- .FirmwareType = DAC960_V1_Controller,
- .InterruptHandler = DAC960_PD_InterruptHandler,
- .MemoryWindowSize = DAC960_PD_RegisterWindowSize,
-};
-
-static struct DAC960_privdata DAC960_P_privdata = {
- .HardwareType = DAC960_P_Controller,
- .FirmwareType = DAC960_V1_Controller,
- .InterruptHandler = DAC960_P_InterruptHandler,
- .MemoryWindowSize = DAC960_PD_RegisterWindowSize,
-};
-
-static const struct pci_device_id DAC960_id_table[] = {
- {
- .vendor = PCI_VENDOR_ID_MYLEX,
- .device = PCI_DEVICE_ID_MYLEX_DAC960_GEM,
- .subvendor = PCI_VENDOR_ID_MYLEX,
- .subdevice = PCI_ANY_ID,
- .driver_data = (unsigned long) &DAC960_GEM_privdata,
- },
- {
- .vendor = PCI_VENDOR_ID_MYLEX,
- .device = PCI_DEVICE_ID_MYLEX_DAC960_BA,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (unsigned long) &DAC960_BA_privdata,
- },
- {
- .vendor = PCI_VENDOR_ID_MYLEX,
- .device = PCI_DEVICE_ID_MYLEX_DAC960_LP,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (unsigned long) &DAC960_LP_privdata,
- },
- {
- .vendor = PCI_VENDOR_ID_DEC,
- .device = PCI_DEVICE_ID_DEC_21285,
- .subvendor = PCI_VENDOR_ID_MYLEX,
- .subdevice = PCI_DEVICE_ID_MYLEX_DAC960_LA,
- .driver_data = (unsigned long) &DAC960_LA_privdata,
- },
- {
- .vendor = PCI_VENDOR_ID_MYLEX,
- .device = PCI_DEVICE_ID_MYLEX_DAC960_PG,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (unsigned long) &DAC960_PG_privdata,
- },
- {
- .vendor = PCI_VENDOR_ID_MYLEX,
- .device = PCI_DEVICE_ID_MYLEX_DAC960_PD,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (unsigned long) &DAC960_PD_privdata,
- },
- {
- .vendor = PCI_VENDOR_ID_MYLEX,
- .device = PCI_DEVICE_ID_MYLEX_DAC960_P,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (unsigned long) &DAC960_P_privdata,
- },
- {0, },
-};
-
-MODULE_DEVICE_TABLE(pci, DAC960_id_table);
-
-static struct pci_driver DAC960_pci_driver = {
- .name = "DAC960",
- .id_table = DAC960_id_table,
- .probe = DAC960_Probe,
- .remove = DAC960_Remove,
-};
-
-static int __init DAC960_init_module(void)
-{
- int ret;
-
- ret = pci_register_driver(&DAC960_pci_driver);
-#ifdef DAC960_GAM_MINOR
- if (!ret)
- DAC960_gam_init();
-#endif
- return ret;
-}
-
-static void __exit DAC960_cleanup_module(void)
-{
- int i;
-
-#ifdef DAC960_GAM_MINOR
- DAC960_gam_cleanup();
-#endif
-
- for (i = 0; i < DAC960_ControllerCount; i++) {
- DAC960_Controller_T *Controller = DAC960_Controllers[i];
- if (Controller == NULL)
- continue;
- DAC960_FinalizeController(Controller);
- }
- if (DAC960_ProcDirectoryEntry != NULL) {
- remove_proc_entry("rd/status", NULL);
- remove_proc_entry("rd", NULL);
- }
- DAC960_ControllerCount = 0;
- pci_unregister_driver(&DAC960_pci_driver);
-}
-
-module_init(DAC960_init_module);
-module_exit(DAC960_cleanup_module);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/block/DAC960.h b/drivers/block/DAC960.h
deleted file mode 100644
index 1439e651928b..000000000000
--- a/drivers/block/DAC960.h
+++ /dev/null
@@ -1,4414 +0,0 @@
-/*
-
- Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers
-
- Copyright 1998-2001 by Leonard N. Zubkoff <lnz@dandelion.com>
-
- This program is free software; you may redistribute 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 complete details.
-
- The author respectfully requests that any modifications to this software be
- sent directly to him for evaluation and testing.
-
-*/
-
-
-/*
- Define the maximum number of DAC960 Controllers supported by this driver.
-*/
-
-#define DAC960_MaxControllers 8
-
-
-/*
- Define the maximum number of Controller Channels supported by DAC960
- V1 and V2 Firmware Controllers.
-*/
-
-#define DAC960_V1_MaxChannels 3
-#define DAC960_V2_MaxChannels 4
-
-
-/*
- Define the maximum number of Targets per Channel supported by DAC960
- V1 and V2 Firmware Controllers.
-*/
-
-#define DAC960_V1_MaxTargets 16
-#define DAC960_V2_MaxTargets 128
-
-
-/*
- Define the maximum number of Logical Drives supported by DAC960
- V1 and V2 Firmware Controllers.
-*/
-
-#define DAC960_MaxLogicalDrives 32
-
-
-/*
- Define the maximum number of Physical Devices supported by DAC960
- V1 and V2 Firmware Controllers.
-*/
-
-#define DAC960_V1_MaxPhysicalDevices 45
-#define DAC960_V2_MaxPhysicalDevices 272
-
-/*
- Define a 32/64 bit I/O Address data type.
-*/
-
-typedef unsigned long DAC960_IO_Address_T;
-
-
-/*
- Define a 32/64 bit PCI Bus Address data type.
-*/
-
-typedef unsigned long DAC960_PCI_Address_T;
-
-
-/*
- Define a 32 bit Bus Address data type.
-*/
-
-typedef unsigned int DAC960_BusAddress32_T;
-
-
-/*
- Define a 64 bit Bus Address data type.
-*/
-
-typedef unsigned long long DAC960_BusAddress64_T;
-
-
-/*
- Define a 32 bit Byte Count data type.
-*/
-
-typedef unsigned int DAC960_ByteCount32_T;
-
-
-/*
- Define a 64 bit Byte Count data type.
-*/
-
-typedef unsigned long long DAC960_ByteCount64_T;
-
-
-/*
- dma_loaf is used by helper routines to divide a region of
- dma mapped memory into smaller pieces, where those pieces
- are not of uniform size.
- */
-
-struct dma_loaf {
- void *cpu_base;
- dma_addr_t dma_base;
- size_t length;
- void *cpu_free;
- dma_addr_t dma_free;
-};
-
-/*
- Define the SCSI INQUIRY Standard Data structure.
-*/
-
-typedef struct DAC960_SCSI_Inquiry
-{
- unsigned char PeripheralDeviceType:5; /* Byte 0 Bits 0-4 */
- unsigned char PeripheralQualifier:3; /* Byte 0 Bits 5-7 */
- unsigned char DeviceTypeModifier:7; /* Byte 1 Bits 0-6 */
- bool RMB:1; /* Byte 1 Bit 7 */
- unsigned char ANSI_ApprovedVersion:3; /* Byte 2 Bits 0-2 */
- unsigned char ECMA_Version:3; /* Byte 2 Bits 3-5 */
- unsigned char ISO_Version:2; /* Byte 2 Bits 6-7 */
- unsigned char ResponseDataFormat:4; /* Byte 3 Bits 0-3 */
- unsigned char :2; /* Byte 3 Bits 4-5 */
- bool TrmIOP:1; /* Byte 3 Bit 6 */
- bool AENC:1; /* Byte 3 Bit 7 */
- unsigned char AdditionalLength; /* Byte 4 */
- unsigned char :8; /* Byte 5 */
- unsigned char :8; /* Byte 6 */
- bool SftRe:1; /* Byte 7 Bit 0 */
- bool CmdQue:1; /* Byte 7 Bit 1 */
- bool :1; /* Byte 7 Bit 2 */
- bool Linked:1; /* Byte 7 Bit 3 */
- bool Sync:1; /* Byte 7 Bit 4 */
- bool WBus16:1; /* Byte 7 Bit 5 */
- bool WBus32:1; /* Byte 7 Bit 6 */
- bool RelAdr:1; /* Byte 7 Bit 7 */
- unsigned char VendorIdentification[8]; /* Bytes 8-15 */
- unsigned char ProductIdentification[16]; /* Bytes 16-31 */
- unsigned char ProductRevisionLevel[4]; /* Bytes 32-35 */
-}
-DAC960_SCSI_Inquiry_T;
-
-
-/*
- Define the SCSI INQUIRY Unit Serial Number structure.
-*/
-
-typedef struct DAC960_SCSI_Inquiry_UnitSerialNumber
-{
- unsigned char PeripheralDeviceType:5; /* Byte 0 Bits 0-4 */
- unsigned char PeripheralQualifier:3; /* Byte 0 Bits 5-7 */
- unsigned char PageCode; /* Byte 1 */
- unsigned char :8; /* Byte 2 */
- unsigned char PageLength; /* Byte 3 */
- unsigned char ProductSerialNumber[28]; /* Bytes 4-31 */
-}
-DAC960_SCSI_Inquiry_UnitSerialNumber_T;
-
-
-/*
- Define the SCSI REQUEST SENSE Sense Key type.
-*/
-
-typedef enum
-{
- DAC960_SenseKey_NoSense = 0x0,
- DAC960_SenseKey_RecoveredError = 0x1,
- DAC960_SenseKey_NotReady = 0x2,
- DAC960_SenseKey_MediumError = 0x3,
- DAC960_SenseKey_HardwareError = 0x4,
- DAC960_SenseKey_IllegalRequest = 0x5,
- DAC960_SenseKey_UnitAttention = 0x6,
- DAC960_SenseKey_DataProtect = 0x7,
- DAC960_SenseKey_BlankCheck = 0x8,
- DAC960_SenseKey_VendorSpecific = 0x9,
- DAC960_SenseKey_CopyAborted = 0xA,
- DAC960_SenseKey_AbortedCommand = 0xB,
- DAC960_SenseKey_Equal = 0xC,
- DAC960_SenseKey_VolumeOverflow = 0xD,
- DAC960_SenseKey_Miscompare = 0xE,
- DAC960_SenseKey_Reserved = 0xF
-}
-__attribute__ ((packed))
-DAC960_SCSI_RequestSenseKey_T;
-
-
-/*
- Define the SCSI REQUEST SENSE structure.
-*/
-
-typedef struct DAC960_SCSI_RequestSense
-{
- unsigned char ErrorCode:7; /* Byte 0 Bits 0-6 */
- bool Valid:1; /* Byte 0 Bit 7 */
- unsigned char SegmentNumber; /* Byte 1 */
- DAC960_SCSI_RequestSenseKey_T SenseKey:4; /* Byte 2 Bits 0-3 */
- unsigned char :1; /* Byte 2 Bit 4 */
- bool ILI:1; /* Byte 2 Bit 5 */
- bool EOM:1; /* Byte 2 Bit 6 */
- bool Filemark:1; /* Byte 2 Bit 7 */
- unsigned char Information[4]; /* Bytes 3-6 */
- unsigned char AdditionalSenseLength; /* Byte 7 */
- unsigned char CommandSpecificInformation[4]; /* Bytes 8-11 */
- unsigned char AdditionalSenseCode; /* Byte 12 */
- unsigned char AdditionalSenseCodeQualifier; /* Byte 13 */
-}
-DAC960_SCSI_RequestSense_T;
-
-
-/*
- Define the DAC960 V1 Firmware Command Opcodes.
-*/
-
-typedef enum
-{
- /* I/O Commands */
- DAC960_V1_ReadExtended = 0x33,
- DAC960_V1_WriteExtended = 0x34,
- DAC960_V1_ReadAheadExtended = 0x35,
- DAC960_V1_ReadExtendedWithScatterGather = 0xB3,
- DAC960_V1_WriteExtendedWithScatterGather = 0xB4,
- DAC960_V1_Read = 0x36,
- DAC960_V1_ReadWithScatterGather = 0xB6,
- DAC960_V1_Write = 0x37,
- DAC960_V1_WriteWithScatterGather = 0xB7,
- DAC960_V1_DCDB = 0x04,
- DAC960_V1_DCDBWithScatterGather = 0x84,
- DAC960_V1_Flush = 0x0A,
- /* Controller Status Related Commands */
- DAC960_V1_Enquiry = 0x53,
- DAC960_V1_Enquiry2 = 0x1C,
- DAC960_V1_GetLogicalDriveElement = 0x55,
- DAC960_V1_GetLogicalDriveInformation = 0x19,
- DAC960_V1_IOPortRead = 0x39,
- DAC960_V1_IOPortWrite = 0x3A,
- DAC960_V1_GetSDStats = 0x3E,
- DAC960_V1_GetPDStats = 0x3F,
- DAC960_V1_PerformEventLogOperation = 0x72,
- /* Device Related Commands */
- DAC960_V1_StartDevice = 0x10,
- DAC960_V1_GetDeviceState = 0x50,
- DAC960_V1_StopChannel = 0x13,
- DAC960_V1_StartChannel = 0x12,
- DAC960_V1_ResetChannel = 0x1A,
- /* Commands Associated with Data Consistency and Errors */
- DAC960_V1_Rebuild = 0x09,
- DAC960_V1_RebuildAsync = 0x16,
- DAC960_V1_CheckConsistency = 0x0F,
- DAC960_V1_CheckConsistencyAsync = 0x1E,
- DAC960_V1_RebuildStat = 0x0C,
- DAC960_V1_GetRebuildProgress = 0x27,
- DAC960_V1_RebuildControl = 0x1F,
- DAC960_V1_ReadBadBlockTable = 0x0B,
- DAC960_V1_ReadBadDataTable = 0x25,
- DAC960_V1_ClearBadDataTable = 0x26,
- DAC960_V1_GetErrorTable = 0x17,
- DAC960_V1_AddCapacityAsync = 0x2A,
- DAC960_V1_BackgroundInitializationControl = 0x2B,
- /* Configuration Related Commands */
- DAC960_V1_ReadConfig2 = 0x3D,
- DAC960_V1_WriteConfig2 = 0x3C,
- DAC960_V1_ReadConfigurationOnDisk = 0x4A,
- DAC960_V1_WriteConfigurationOnDisk = 0x4B,
- DAC960_V1_ReadConfiguration = 0x4E,
- DAC960_V1_ReadBackupConfiguration = 0x4D,
- DAC960_V1_WriteConfiguration = 0x4F,
- DAC960_V1_AddConfiguration = 0x4C,
- DAC960_V1_ReadConfigurationLabel = 0x48,
- DAC960_V1_WriteConfigurationLabel = 0x49,
- /* Firmware Upgrade Related Commands */
- DAC960_V1_LoadImage = 0x20,
- DAC960_V1_StoreImage = 0x21,
- DAC960_V1_ProgramImage = 0x22,
- /* Diagnostic Commands */
- DAC960_V1_SetDiagnosticMode = 0x31,
- DAC960_V1_RunDiagnostic = 0x32,
- /* Subsystem Service Commands */
- DAC960_V1_GetSubsystemData = 0x70,
- DAC960_V1_SetSubsystemParameters = 0x71,
- /* Version 2.xx Firmware Commands */
- DAC960_V1_Enquiry_Old = 0x05,
- DAC960_V1_GetDeviceState_Old = 0x14,
- DAC960_V1_Read_Old = 0x02,
- DAC960_V1_Write_Old = 0x03,
- DAC960_V1_ReadWithScatterGather_Old = 0x82,
- DAC960_V1_WriteWithScatterGather_Old = 0x83
-}
-__attribute__ ((packed))
-DAC960_V1_CommandOpcode_T;
-
-
-/*
- Define the DAC960 V1 Firmware Command Identifier type.
-*/
-
-typedef unsigned char DAC960_V1_CommandIdentifier_T;
-
-
-/*
- Define the DAC960 V1 Firmware Command Status Codes.
-*/
-
-#define DAC960_V1_NormalCompletion 0x0000 /* Common */
-#define DAC960_V1_CheckConditionReceived 0x0002 /* Common */
-#define DAC960_V1_NoDeviceAtAddress 0x0102 /* Common */
-#define DAC960_V1_InvalidDeviceAddress 0x0105 /* Common */
-#define DAC960_V1_InvalidParameter 0x0105 /* Common */
-#define DAC960_V1_IrrecoverableDataError 0x0001 /* I/O */
-#define DAC960_V1_LogicalDriveNonexistentOrOffline 0x0002 /* I/O */
-#define DAC960_V1_AccessBeyondEndOfLogicalDrive 0x0105 /* I/O */
-#define DAC960_V1_BadDataEncountered 0x010C /* I/O */
-#define DAC960_V1_DeviceBusy 0x0008 /* DCDB */
-#define DAC960_V1_DeviceNonresponsive 0x000E /* DCDB */
-#define DAC960_V1_CommandTerminatedAbnormally 0x000F /* DCDB */
-#define DAC960_V1_UnableToStartDevice 0x0002 /* Device */
-#define DAC960_V1_InvalidChannelOrTargetOrModifier 0x0105 /* Device */
-#define DAC960_V1_ChannelBusy 0x0106 /* Device */
-#define DAC960_V1_ChannelNotStopped 0x0002 /* Device */
-#define DAC960_V1_AttemptToRebuildOnlineDrive 0x0002 /* Consistency */
-#define DAC960_V1_RebuildBadBlocksEncountered 0x0003 /* Consistency */
-#define DAC960_V1_NewDiskFailedDuringRebuild 0x0004 /* Consistency */
-#define DAC960_V1_RebuildOrCheckAlreadyInProgress 0x0106 /* Consistency */
-#define DAC960_V1_DependentDiskIsDead 0x0002 /* Consistency */
-#define DAC960_V1_InconsistentBlocksFound 0x0003 /* Consistency */
-#define DAC960_V1_InvalidOrNonredundantLogicalDrive 0x0105 /* Consistency */
-#define DAC960_V1_NoRebuildOrCheckInProgress 0x0105 /* Consistency */
-#define DAC960_V1_RebuildInProgress_DataValid 0x0000 /* Consistency */
-#define DAC960_V1_RebuildFailed_LogicalDriveFailure 0x0002 /* Consistency */
-#define DAC960_V1_RebuildFailed_BadBlocksOnOther 0x0003 /* Consistency */
-#define DAC960_V1_RebuildFailed_NewDriveFailed 0x0004 /* Consistency */
-#define DAC960_V1_RebuildSuccessful 0x0100 /* Consistency */
-#define DAC960_V1_RebuildSuccessfullyTerminated 0x0107 /* Consistency */
-#define DAC960_V1_BackgroundInitSuccessful 0x0100 /* Consistency */
-#define DAC960_V1_BackgroundInitAborted 0x0005 /* Consistency */
-#define DAC960_V1_NoBackgroundInitInProgress 0x0105 /* Consistency */
-#define DAC960_V1_AddCapacityInProgress 0x0004 /* Consistency */
-#define DAC960_V1_AddCapacityFailedOrSuspended 0x00F4 /* Consistency */
-#define DAC960_V1_Config2ChecksumError 0x0002 /* Configuration */
-#define DAC960_V1_ConfigurationSuspended 0x0106 /* Configuration */
-#define DAC960_V1_FailedToConfigureNVRAM 0x0105 /* Configuration */
-#define DAC960_V1_ConfigurationNotSavedStateChange 0x0106 /* Configuration */
-#define DAC960_V1_SubsystemNotInstalled 0x0001 /* Subsystem */
-#define DAC960_V1_SubsystemFailed 0x0002 /* Subsystem */
-#define DAC960_V1_SubsystemBusy 0x0106 /* Subsystem */
-
-typedef unsigned short DAC960_V1_CommandStatus_T;
-
-
-/*
- Define the DAC960 V1 Firmware Enquiry Command reply structure.
-*/
-
-typedef struct DAC960_V1_Enquiry
-{
- unsigned char NumberOfLogicalDrives; /* Byte 0 */
- unsigned int :24; /* Bytes 1-3 */
- unsigned int LogicalDriveSizes[32]; /* Bytes 4-131 */
- unsigned short FlashAge; /* Bytes 132-133 */
- struct {
- bool DeferredWriteError:1; /* Byte 134 Bit 0 */
- bool BatteryLow:1; /* Byte 134 Bit 1 */
- unsigned char :6; /* Byte 134 Bits 2-7 */
- } StatusFlags;
- unsigned char :8; /* Byte 135 */
- unsigned char MinorFirmwareVersion; /* Byte 136 */
- unsigned char MajorFirmwareVersion; /* Byte 137 */
- enum {
- DAC960_V1_NoStandbyRebuildOrCheckInProgress = 0x00,
- DAC960_V1_StandbyRebuildInProgress = 0x01,
- DAC960_V1_BackgroundRebuildInProgress = 0x02,
- DAC960_V1_BackgroundCheckInProgress = 0x03,
- DAC960_V1_StandbyRebuildCompletedWithError = 0xFF,
- DAC960_V1_BackgroundRebuildOrCheckFailed_DriveFailed = 0xF0,
- DAC960_V1_BackgroundRebuildOrCheckFailed_LogicalDriveFailed = 0xF1,
- DAC960_V1_BackgroundRebuildOrCheckFailed_OtherCauses = 0xF2,
- DAC960_V1_BackgroundRebuildOrCheckSuccessfullyTerminated = 0xF3
- } __attribute__ ((packed)) RebuildFlag; /* Byte 138 */
- unsigned char MaxCommands; /* Byte 139 */
- unsigned char OfflineLogicalDriveCount; /* Byte 140 */
- unsigned char :8; /* Byte 141 */
- unsigned short EventLogSequenceNumber; /* Bytes 142-143 */
- unsigned char CriticalLogicalDriveCount; /* Byte 144 */
- unsigned int :24; /* Bytes 145-147 */
- unsigned char DeadDriveCount; /* Byte 148 */
- unsigned char :8; /* Byte 149 */
- unsigned char RebuildCount; /* Byte 150 */
- struct {
- unsigned char :3; /* Byte 151 Bits 0-2 */
- bool BatteryBackupUnitPresent:1; /* Byte 151 Bit 3 */
- unsigned char :3; /* Byte 151 Bits 4-6 */
- unsigned char :1; /* Byte 151 Bit 7 */
- } MiscFlags;
- struct {
- unsigned char TargetID;
- unsigned char Channel;
- } DeadDrives[21]; /* Bytes 152-194 */
- unsigned char Reserved[62]; /* Bytes 195-255 */
-}
-__attribute__ ((packed))
-DAC960_V1_Enquiry_T;
-
-
-/*
- Define the DAC960 V1 Firmware Enquiry2 Command reply structure.
-*/
-
-typedef struct DAC960_V1_Enquiry2
-{
- struct {
- enum {
- DAC960_V1_P_PD_PU = 0x01,
- DAC960_V1_PL = 0x02,
- DAC960_V1_PG = 0x10,
- DAC960_V1_PJ = 0x11,
- DAC960_V1_PR = 0x12,
- DAC960_V1_PT = 0x13,
- DAC960_V1_PTL0 = 0x14,
- DAC960_V1_PRL = 0x15,
- DAC960_V1_PTL1 = 0x16,
- DAC960_V1_1164P = 0x20
- } __attribute__ ((packed)) SubModel; /* Byte 0 */
- unsigned char ActualChannels; /* Byte 1 */
- enum {
- DAC960_V1_FiveChannelBoard = 0x01,
- DAC960_V1_ThreeChannelBoard = 0x02,
- DAC960_V1_TwoChannelBoard = 0x03,
- DAC960_V1_ThreeChannelASIC_DAC = 0x04
- } __attribute__ ((packed)) Model; /* Byte 2 */
- enum {
- DAC960_V1_EISA_Controller = 0x01,
- DAC960_V1_MicroChannel_Controller = 0x02,
- DAC960_V1_PCI_Controller = 0x03,
- DAC960_V1_SCSItoSCSI_Controller = 0x08
- } __attribute__ ((packed)) ProductFamily; /* Byte 3 */
- } HardwareID; /* Bytes 0-3 */
- /* MajorVersion.MinorVersion-FirmwareType-TurnID */
- struct {
- unsigned char MajorVersion; /* Byte 4 */
- unsigned char MinorVersion; /* Byte 5 */
- unsigned char TurnID; /* Byte 6 */
- char FirmwareType; /* Byte 7 */
- } FirmwareID; /* Bytes 4-7 */
- unsigned char :8; /* Byte 8 */
- unsigned int :24; /* Bytes 9-11 */
- unsigned char ConfiguredChannels; /* Byte 12 */
- unsigned char ActualChannels; /* Byte 13 */
- unsigned char MaxTargets; /* Byte 14 */
- unsigned char MaxTags; /* Byte 15 */
- unsigned char MaxLogicalDrives; /* Byte 16 */
- unsigned char MaxArms; /* Byte 17 */
- unsigned char MaxSpans; /* Byte 18 */
- unsigned char :8; /* Byte 19 */
- unsigned int :32; /* Bytes 20-23 */
- unsigned int MemorySize; /* Bytes 24-27 */
- unsigned int CacheSize; /* Bytes 28-31 */
- unsigned int FlashMemorySize; /* Bytes 32-35 */
- unsigned int NonVolatileMemorySize; /* Bytes 36-39 */
- struct {
- enum {
- DAC960_V1_RamType_DRAM = 0x0,
- DAC960_V1_RamType_EDO = 0x1,
- DAC960_V1_RamType_SDRAM = 0x2,
- DAC960_V1_RamType_Last = 0x7
- } __attribute__ ((packed)) RamType:3; /* Byte 40 Bits 0-2 */
- enum {
- DAC960_V1_ErrorCorrection_None = 0x0,
- DAC960_V1_ErrorCorrection_Parity = 0x1,
- DAC960_V1_ErrorCorrection_ECC = 0x2,
- DAC960_V1_ErrorCorrection_Last = 0x7
- } __attribute__ ((packed)) ErrorCorrection:3; /* Byte 40 Bits 3-5 */
- bool FastPageMode:1; /* Byte 40 Bit 6 */
- bool LowPowerMemory:1; /* Byte 40 Bit 7 */
- unsigned char :8; /* Bytes 41 */
- } MemoryType;
- unsigned short ClockSpeed; /* Bytes 42-43 */
- unsigned short MemorySpeed; /* Bytes 44-45 */
- unsigned short HardwareSpeed; /* Bytes 46-47 */
- unsigned int :32; /* Bytes 48-51 */
- unsigned int :32; /* Bytes 52-55 */
- unsigned char :8; /* Byte 56 */
- unsigned char :8; /* Byte 57 */
- unsigned short :16; /* Bytes 58-59 */
- unsigned short MaxCommands; /* Bytes 60-61 */
- unsigned short MaxScatterGatherEntries; /* Bytes 62-63 */
- unsigned short MaxDriveCommands; /* Bytes 64-65 */
- unsigned short MaxIODescriptors; /* Bytes 66-67 */
- unsigned short MaxCombinedSectors; /* Bytes 68-69 */
- unsigned char Latency; /* Byte 70 */
- unsigned char :8; /* Byte 71 */
- unsigned char SCSITimeout; /* Byte 72 */
- unsigned char :8; /* Byte 73 */
- unsigned short MinFreeLines; /* Bytes 74-75 */
- unsigned int :32; /* Bytes 76-79 */
- unsigned int :32; /* Bytes 80-83 */
- unsigned char RebuildRateConstant; /* Byte 84 */
- unsigned char :8; /* Byte 85 */
- unsigned char :8; /* Byte 86 */
- unsigned char :8; /* Byte 87 */
- unsigned int :32; /* Bytes 88-91 */
- unsigned int :32; /* Bytes 92-95 */
- unsigned short PhysicalDriveBlockSize; /* Bytes 96-97 */
- unsigned short LogicalDriveBlockSize; /* Bytes 98-99 */
- unsigned short MaxBlocksPerCommand; /* Bytes 100-101 */
- unsigned short BlockFactor; /* Bytes 102-103 */
- unsigned short CacheLineSize; /* Bytes 104-105 */
- struct {
- enum {
- DAC960_V1_Narrow_8bit = 0x0,
- DAC960_V1_Wide_16bit = 0x1,
- DAC960_V1_Wide_32bit = 0x2
- } __attribute__ ((packed)) BusWidth:2; /* Byte 106 Bits 0-1 */
- enum {
- DAC960_V1_Fast = 0x0,
- DAC960_V1_Ultra = 0x1,
- DAC960_V1_Ultra2 = 0x2
- } __attribute__ ((packed)) BusSpeed:2; /* Byte 106 Bits 2-3 */
- bool Differential:1; /* Byte 106 Bit 4 */
- unsigned char :3; /* Byte 106 Bits 5-7 */
- } SCSICapability;
- unsigned char :8; /* Byte 107 */
- unsigned int :32; /* Bytes 108-111 */
- unsigned short FirmwareBuildNumber; /* Bytes 112-113 */
- enum {
- DAC960_V1_AEMI = 0x01,
- DAC960_V1_OEM1 = 0x02,
- DAC960_V1_OEM2 = 0x04,
- DAC960_V1_OEM3 = 0x08,
- DAC960_V1_Conner = 0x10,
- DAC960_V1_SAFTE = 0x20
- } __attribute__ ((packed)) FaultManagementType; /* Byte 114 */
- unsigned char :8; /* Byte 115 */
- struct {
- bool Clustering:1; /* Byte 116 Bit 0 */
- bool MylexOnlineRAIDExpansion:1; /* Byte 116 Bit 1 */
- bool ReadAhead:1; /* Byte 116 Bit 2 */
- bool BackgroundInitialization:1; /* Byte 116 Bit 3 */
- unsigned int :28; /* Bytes 116-119 */
- } FirmwareFeatures;
- unsigned int :32; /* Bytes 120-123 */
- unsigned int :32; /* Bytes 124-127 */
-}
-DAC960_V1_Enquiry2_T;
-
-
-/*
- Define the DAC960 V1 Firmware Logical Drive State type.
-*/
-
-typedef enum
-{
- DAC960_V1_LogicalDrive_Online = 0x03,
- DAC960_V1_LogicalDrive_Critical = 0x04,
- DAC960_V1_LogicalDrive_Offline = 0xFF
-}
-__attribute__ ((packed))
-DAC960_V1_LogicalDriveState_T;
-
-
-/*
- Define the DAC960 V1 Firmware Logical Drive Information structure.
-*/
-
-typedef struct DAC960_V1_LogicalDriveInformation
-{
- unsigned int LogicalDriveSize; /* Bytes 0-3 */
- DAC960_V1_LogicalDriveState_T LogicalDriveState; /* Byte 4 */
- unsigned char RAIDLevel:7; /* Byte 5 Bits 0-6 */
- bool WriteBack:1; /* Byte 5 Bit 7 */
- unsigned short :16; /* Bytes 6-7 */
-}
-DAC960_V1_LogicalDriveInformation_T;
-
-
-/*
- Define the DAC960 V1 Firmware Get Logical Drive Information Command
- reply structure.
-*/
-
-typedef DAC960_V1_LogicalDriveInformation_T
- DAC960_V1_LogicalDriveInformationArray_T[DAC960_MaxLogicalDrives];
-
-
-/*
- Define the DAC960 V1 Firmware Perform Event Log Operation Types.
-*/
-
-typedef enum
-{
- DAC960_V1_GetEventLogEntry = 0x00
-}
-__attribute__ ((packed))
-DAC960_V1_PerformEventLogOpType_T;
-
-
-/*
- Define the DAC960 V1 Firmware Get Event Log Entry Command reply structure.
-*/
-
-typedef struct DAC960_V1_EventLogEntry
-{
- unsigned char MessageType; /* Byte 0 */
- unsigned char MessageLength; /* Byte 1 */
- unsigned char TargetID:5; /* Byte 2 Bits 0-4 */
- unsigned char Channel:3; /* Byte 2 Bits 5-7 */
- unsigned char LogicalUnit:6; /* Byte 3 Bits 0-5 */
- unsigned char :2; /* Byte 3 Bits 6-7 */
- unsigned short SequenceNumber; /* Bytes 4-5 */
- unsigned char ErrorCode:7; /* Byte 6 Bits 0-6 */
- bool Valid:1; /* Byte 6 Bit 7 */
- unsigned char SegmentNumber; /* Byte 7 */
- DAC960_SCSI_RequestSenseKey_T SenseKey:4; /* Byte 8 Bits 0-3 */
- unsigned char :1; /* Byte 8 Bit 4 */
- bool ILI:1; /* Byte 8 Bit 5 */
- bool EOM:1; /* Byte 8 Bit 6 */
- bool Filemark:1; /* Byte 8 Bit 7 */
- unsigned char Information[4]; /* Bytes 9-12 */
- unsigned char AdditionalSenseLength; /* Byte 13 */
- unsigned char CommandSpecificInformation[4]; /* Bytes 14-17 */
- unsigned char AdditionalSenseCode; /* Byte 18 */
- unsigned char AdditionalSenseCodeQualifier; /* Byte 19 */
- unsigned char Dummy[12]; /* Bytes 20-31 */
-}
-DAC960_V1_EventLogEntry_T;
-
-
-/*
- Define the DAC960 V1 Firmware Physical Device State type.
-*/
-
-typedef enum
-{
- DAC960_V1_Device_Dead = 0x00,
- DAC960_V1_Device_WriteOnly = 0x02,
- DAC960_V1_Device_Online = 0x03,
- DAC960_V1_Device_Standby = 0x10
-}
-__attribute__ ((packed))
-DAC960_V1_PhysicalDeviceState_T;
-
-
-/*
- Define the DAC960 V1 Firmware Get Device State Command reply structure.
- The structure is padded by 2 bytes for compatibility with Version 2.xx
- Firmware.
-*/
-
-typedef struct DAC960_V1_DeviceState
-{
- bool Present:1; /* Byte 0 Bit 0 */
- unsigned char :7; /* Byte 0 Bits 1-7 */
- enum {
- DAC960_V1_OtherType = 0x0,
- DAC960_V1_DiskType = 0x1,
- DAC960_V1_SequentialType = 0x2,
- DAC960_V1_CDROM_or_WORM_Type = 0x3
- } __attribute__ ((packed)) DeviceType:2; /* Byte 1 Bits 0-1 */
- bool :1; /* Byte 1 Bit 2 */
- bool Fast20:1; /* Byte 1 Bit 3 */
- bool Sync:1; /* Byte 1 Bit 4 */
- bool Fast:1; /* Byte 1 Bit 5 */
- bool Wide:1; /* Byte 1 Bit 6 */
- bool TaggedQueuingSupported:1; /* Byte 1 Bit 7 */
- DAC960_V1_PhysicalDeviceState_T DeviceState; /* Byte 2 */
- unsigned char :8; /* Byte 3 */
- unsigned char SynchronousMultiplier; /* Byte 4 */
- unsigned char SynchronousOffset:5; /* Byte 5 Bits 0-4 */
- unsigned char :3; /* Byte 5 Bits 5-7 */
- unsigned int DiskSize __attribute__ ((packed)); /* Bytes 6-9 */
- unsigned short :16; /* Bytes 10-11 */
-}
-DAC960_V1_DeviceState_T;
-
-
-/*
- Define the DAC960 V1 Firmware Get Rebuild Progress Command reply structure.
-*/
-
-typedef struct DAC960_V1_RebuildProgress
-{
- unsigned int LogicalDriveNumber; /* Bytes 0-3 */
- unsigned int LogicalDriveSize; /* Bytes 4-7 */
- unsigned int RemainingBlocks; /* Bytes 8-11 */
-}
-DAC960_V1_RebuildProgress_T;
-
-
-/*
- Define the DAC960 V1 Firmware Background Initialization Status Command
- reply structure.
-*/
-
-typedef struct DAC960_V1_BackgroundInitializationStatus
-{
- unsigned int LogicalDriveSize; /* Bytes 0-3 */
- unsigned int BlocksCompleted; /* Bytes 4-7 */
- unsigned char Reserved1[12]; /* Bytes 8-19 */
- unsigned int LogicalDriveNumber; /* Bytes 20-23 */
- unsigned char RAIDLevel; /* Byte 24 */
- enum {
- DAC960_V1_BackgroundInitializationInvalid = 0x00,
- DAC960_V1_BackgroundInitializationStarted = 0x02,
- DAC960_V1_BackgroundInitializationInProgress = 0x04,
- DAC960_V1_BackgroundInitializationSuspended = 0x05,
- DAC960_V1_BackgroundInitializationCancelled = 0x06
- } __attribute__ ((packed)) Status; /* Byte 25 */
- unsigned char Reserved2[6]; /* Bytes 26-31 */
-}
-DAC960_V1_BackgroundInitializationStatus_T;
-
-
-/*
- Define the DAC960 V1 Firmware Error Table Entry structure.
-*/
-
-typedef struct DAC960_V1_ErrorTableEntry
-{
- unsigned char ParityErrorCount; /* Byte 0 */
- unsigned char SoftErrorCount; /* Byte 1 */
- unsigned char HardErrorCount; /* Byte 2 */
- unsigned char MiscErrorCount; /* Byte 3 */
-}
-DAC960_V1_ErrorTableEntry_T;
-
-
-/*
- Define the DAC960 V1 Firmware Get Error Table Command reply structure.
-*/
-
-typedef struct DAC960_V1_ErrorTable
-{
- DAC960_V1_ErrorTableEntry_T
- ErrorTableEntries[DAC960_V1_MaxChannels][DAC960_V1_MaxTargets];
-}
-DAC960_V1_ErrorTable_T;
-
-
-/*
- Define the DAC960 V1 Firmware Read Config2 Command reply structure.
-*/
-
-typedef struct DAC960_V1_Config2
-{
- unsigned char :1; /* Byte 0 Bit 0 */
- bool ActiveNegationEnabled:1; /* Byte 0 Bit 1 */
- unsigned char :5; /* Byte 0 Bits 2-6 */
- bool NoRescanIfResetReceivedDuringScan:1; /* Byte 0 Bit 7 */
- bool StorageWorksSupportEnabled:1; /* Byte 1 Bit 0 */
- bool HewlettPackardSupportEnabled:1; /* Byte 1 Bit 1 */
- bool NoDisconnectOnFirstCommand:1; /* Byte 1 Bit 2 */
- unsigned char :2; /* Byte 1 Bits 3-4 */
- bool AEMI_ARM:1; /* Byte 1 Bit 5 */
- bool AEMI_OFM:1; /* Byte 1 Bit 6 */
- unsigned char :1; /* Byte 1 Bit 7 */
- enum {
- DAC960_V1_OEMID_Mylex = 0x00,
- DAC960_V1_OEMID_IBM = 0x08,
- DAC960_V1_OEMID_HP = 0x0A,
- DAC960_V1_OEMID_DEC = 0x0C,
- DAC960_V1_OEMID_Siemens = 0x10,
- DAC960_V1_OEMID_Intel = 0x12
- } __attribute__ ((packed)) OEMID; /* Byte 2 */
- unsigned char OEMModelNumber; /* Byte 3 */
- unsigned char PhysicalSector; /* Byte 4 */
- unsigned char LogicalSector; /* Byte 5 */
- unsigned char BlockFactor; /* Byte 6 */
- bool ReadAheadEnabled:1; /* Byte 7 Bit 0 */
- bool LowBIOSDelay:1; /* Byte 7 Bit 1 */
- unsigned char :2; /* Byte 7 Bits 2-3 */
- bool ReassignRestrictedToOneSector:1; /* Byte 7 Bit 4 */
- unsigned char :1; /* Byte 7 Bit 5 */
- bool ForceUnitAccessDuringWriteRecovery:1; /* Byte 7 Bit 6 */
- bool EnableLeftSymmetricRAID5Algorithm:1; /* Byte 7 Bit 7 */
- unsigned char DefaultRebuildRate; /* Byte 8 */
- unsigned char :8; /* Byte 9 */
- unsigned char BlocksPerCacheLine; /* Byte 10 */
- unsigned char BlocksPerStripe; /* Byte 11 */
- struct {
- enum {
- DAC960_V1_Async = 0x0,
- DAC960_V1_Sync_8MHz = 0x1,
- DAC960_V1_Sync_5MHz = 0x2,
- DAC960_V1_Sync_10or20MHz = 0x3 /* Byte 11 Bits 0-1 */
- } __attribute__ ((packed)) Speed:2;
- bool Force8Bit:1; /* Byte 11 Bit 2 */
- bool DisableFast20:1; /* Byte 11 Bit 3 */
- unsigned char :3; /* Byte 11 Bits 4-6 */
- bool EnableTaggedQueuing:1; /* Byte 11 Bit 7 */
- } __attribute__ ((packed)) ChannelParameters[6]; /* Bytes 12-17 */
- unsigned char SCSIInitiatorID; /* Byte 18 */
- unsigned char :8; /* Byte 19 */
- enum {
- DAC960_V1_StartupMode_ControllerSpinUp = 0x00,
- DAC960_V1_StartupMode_PowerOnSpinUp = 0x01
- } __attribute__ ((packed)) StartupMode; /* Byte 20 */
- unsigned char SimultaneousDeviceSpinUpCount; /* Byte 21 */
- unsigned char SecondsDelayBetweenSpinUps; /* Byte 22 */
- unsigned char Reserved1[29]; /* Bytes 23-51 */
- bool BIOSDisabled:1; /* Byte 52 Bit 0 */
- bool CDROMBootEnabled:1; /* Byte 52 Bit 1 */
- unsigned char :3; /* Byte 52 Bits 2-4 */
- enum {
- DAC960_V1_Geometry_128_32 = 0x0,
- DAC960_V1_Geometry_255_63 = 0x1,
- DAC960_V1_Geometry_Reserved1 = 0x2,
- DAC960_V1_Geometry_Reserved2 = 0x3
- } __attribute__ ((packed)) DriveGeometry:2; /* Byte 52 Bits 5-6 */
- unsigned char :1; /* Byte 52 Bit 7 */
- unsigned char Reserved2[9]; /* Bytes 53-61 */
- unsigned short Checksum; /* Bytes 62-63 */
-}
-DAC960_V1_Config2_T;
-
-
-/*
- Define the DAC960 V1 Firmware DCDB request structure.
-*/
-
-typedef struct DAC960_V1_DCDB
-{
- unsigned char TargetID:4; /* Byte 0 Bits 0-3 */
- unsigned char Channel:4; /* Byte 0 Bits 4-7 */
- enum {
- DAC960_V1_DCDB_NoDataTransfer = 0,
- DAC960_V1_DCDB_DataTransferDeviceToSystem = 1,
- DAC960_V1_DCDB_DataTransferSystemToDevice = 2,
- DAC960_V1_DCDB_IllegalDataTransfer = 3
- } __attribute__ ((packed)) Direction:2; /* Byte 1 Bits 0-1 */
- bool EarlyStatus:1; /* Byte 1 Bit 2 */
- unsigned char :1; /* Byte 1 Bit 3 */
- enum {
- DAC960_V1_DCDB_Timeout_24_hours = 0,
- DAC960_V1_DCDB_Timeout_10_seconds = 1,
- DAC960_V1_DCDB_Timeout_60_seconds = 2,
- DAC960_V1_DCDB_Timeout_10_minutes = 3
- } __attribute__ ((packed)) Timeout:2; /* Byte 1 Bits 4-5 */
- bool NoAutomaticRequestSense:1; /* Byte 1 Bit 6 */
- bool DisconnectPermitted:1; /* Byte 1 Bit 7 */
- unsigned short TransferLength; /* Bytes 2-3 */
- DAC960_BusAddress32_T BusAddress; /* Bytes 4-7 */
- unsigned char CDBLength:4; /* Byte 8 Bits 0-3 */
- unsigned char TransferLengthHigh4:4; /* Byte 8 Bits 4-7 */
- unsigned char SenseLength; /* Byte 9 */
- unsigned char CDB[12]; /* Bytes 10-21 */
- unsigned char SenseData[64]; /* Bytes 22-85 */
- unsigned char Status; /* Byte 86 */
- unsigned char :8; /* Byte 87 */
-}
-DAC960_V1_DCDB_T;
-
-
-/*
- Define the DAC960 V1 Firmware Scatter/Gather List Type 1 32 Bit Address
- 32 Bit Byte Count structure.
-*/
-
-typedef struct DAC960_V1_ScatterGatherSegment
-{
- DAC960_BusAddress32_T SegmentDataPointer; /* Bytes 0-3 */
- DAC960_ByteCount32_T SegmentByteCount; /* Bytes 4-7 */
-}
-DAC960_V1_ScatterGatherSegment_T;
-
-
-/*
- Define the 13 Byte DAC960 V1 Firmware Command Mailbox structure. Bytes 13-15
- are not used. The Command Mailbox structure is padded to 16 bytes for
- efficient access.
-*/
-
-typedef union DAC960_V1_CommandMailbox
-{
- unsigned int Words[4]; /* Words 0-3 */
- unsigned char Bytes[16]; /* Bytes 0-15 */
- struct {
- DAC960_V1_CommandOpcode_T CommandOpcode; /* Byte 0 */
- DAC960_V1_CommandIdentifier_T CommandIdentifier; /* Byte 1 */
- unsigned char Dummy[14]; /* Bytes 2-15 */
- } __attribute__ ((packed)) Common;
- struct {
- DAC960_V1_CommandOpcode_T CommandOpcode; /* Byte 0 */
- DAC960_V1_CommandIdentifier_T CommandIdentifier; /* Byte 1 */
- unsigned char Dummy1[6]; /* Bytes 2-7 */
- DAC960_BusAddress32_T BusAddress; /* Bytes 8-11 */
- unsigned char Dummy2[4]; /* Bytes 12-15 */
- } __attribute__ ((packed)) Type3;
- struct {
- DAC960_V1_CommandOpcode_T CommandOpcode; /* Byte 0 */
- DAC960_V1_CommandIdentifier_T CommandIdentifier; /* Byte 1 */
- unsigned char CommandOpcode2; /* Byte 2 */
- unsigned char Dummy1[5]; /* Bytes 3-7 */
- DAC960_BusAddress32_T BusAddress; /* Bytes 8-11 */
- unsigned char Dummy2[4]; /* Bytes 12-15 */
- } __attribute__ ((packed)) Type3B;
- struct {
- DAC960_V1_CommandOpcode_T CommandOpcode; /* Byte 0 */
- DAC960_V1_CommandIdentifier_T CommandIdentifier; /* Byte 1 */
- unsigned char Dummy1[5]; /* Bytes 2-6 */
- unsigned char LogicalDriveNumber:6; /* Byte 7 Bits 0-6 */
- bool AutoRestore:1; /* Byte 7 Bit 7 */
- unsigned char Dummy2[8]; /* Bytes 8-15 */
- } __attribute__ ((packed)) Type3C;
- struct {
- DAC960_V1_CommandOpcode_T CommandOpcode; /* Byte 0 */
- DAC960_V1_CommandIdentifier_T CommandIdentifier; /* Byte 1 */
- unsigned char Channel; /* Byte 2 */
- unsigned char TargetID; /* Byte 3 */
- DAC960_V1_PhysicalDeviceState_T DeviceState:5; /* Byte 4 Bits 0-4 */
- unsigned char Modifier:3; /* Byte 4 Bits 5-7 */
- unsigned char Dummy1[3]; /* Bytes 5-7 */
- DAC960_BusAddress32_T BusAddress; /* Bytes 8-11 */
- unsigned char Dummy2[4]; /* Bytes 12-15 */
- } __attribute__ ((packed)) Type3D;
- struct {
- DAC960_V1_CommandOpcode_T CommandOpcode; /* Byte 0 */
- DAC960_V1_CommandIdentifier_T CommandIdentifier; /* Byte 1 */
- DAC960_V1_PerformEventLogOpType_T OperationType; /* Byte 2 */
- unsigned char OperationQualifier; /* Byte 3 */
- unsigned short SequenceNumber; /* Bytes 4-5 */
- unsigned char Dummy1[2]; /* Bytes 6-7 */
- DAC960_BusAddress32_T BusAddress; /* Bytes 8-11 */
- unsigned char Dummy2[4]; /* Bytes 12-15 */
- } __attribute__ ((packed)) Type3E;
- struct {
- DAC960_V1_CommandOpcode_T CommandOpcode; /* Byte 0 */
- DAC960_V1_CommandIdentifier_T CommandIdentifier; /* Byte 1 */
- unsigned char Dummy1[2]; /* Bytes 2-3 */
- unsigned char RebuildRateConstant; /* Byte 4 */
- unsigned char Dummy2[3]; /* Bytes 5-7 */
- DAC960_BusAddress32_T BusAddress; /* Bytes 8-11 */
- unsigned char Dummy3[4]; /* Bytes 12-15 */
- } __attribute__ ((packed)) Type3R;
- struct {
- DAC960_V1_CommandOpcode_T CommandOpcode; /* Byte 0 */
- DAC960_V1_CommandIdentifier_T CommandIdentifier; /* Byte 1 */
- unsigned short TransferLength; /* Bytes 2-3 */
- unsigned int LogicalBlockAddress; /* Bytes 4-7 */
- DAC960_BusAddress32_T BusAddress; /* Bytes 8-11 */
- unsigned char LogicalDriveNumber; /* Byte 12 */
- unsigned char Dummy[3]; /* Bytes 13-15 */
- } __attribute__ ((packed)) Type4;
- struct {
- DAC960_V1_CommandOpcode_T CommandOpcode; /* Byte 0 */
- DAC960_V1_CommandIdentifier_T CommandIdentifier; /* Byte 1 */
- struct {
- unsigned short TransferLength:11; /* Bytes 2-3 */
- unsigned char LogicalDriveNumber:5; /* Byte 3 Bits 3-7 */
- } __attribute__ ((packed)) LD;
- unsigned int LogicalBlockAddress; /* Bytes 4-7 */
- DAC960_BusAddress32_T BusAddress; /* Bytes 8-11 */
- unsigned char ScatterGatherCount:6; /* Byte 12 Bits 0-5 */
- enum {
- DAC960_V1_ScatterGather_32BitAddress_32BitByteCount = 0x0,
- DAC960_V1_ScatterGather_32BitAddress_16BitByteCount = 0x1,
- DAC960_V1_ScatterGather_32BitByteCount_32BitAddress = 0x2,
- DAC960_V1_ScatterGather_16BitByteCount_32BitAddress = 0x3
- } __attribute__ ((packed)) ScatterGatherType:2; /* Byte 12 Bits 6-7 */
- unsigned char Dummy[3]; /* Bytes 13-15 */
- } __attribute__ ((packed)) Type5;
- struct {
- DAC960_V1_CommandOpcode_T CommandOpcode; /* Byte 0 */
- DAC960_V1_CommandIdentifier_T CommandIdentifier; /* Byte 1 */
- unsigned char CommandOpcode2; /* Byte 2 */
- unsigned char :8; /* Byte 3 */
- DAC960_BusAddress32_T CommandMailboxesBusAddress; /* Bytes 4-7 */
- DAC960_BusAddress32_T StatusMailboxesBusAddress; /* Bytes 8-11 */
- unsigned char Dummy[4]; /* Bytes 12-15 */
- } __attribute__ ((packed)) TypeX;
-}
-DAC960_V1_CommandMailbox_T;
-
-
-/*
- Define the DAC960 V2 Firmware Command Opcodes.
-*/
-
-typedef enum
-{
- DAC960_V2_MemCopy = 0x01,
- DAC960_V2_SCSI_10_Passthru = 0x02,
- DAC960_V2_SCSI_255_Passthru = 0x03,
- DAC960_V2_SCSI_10 = 0x04,
- DAC960_V2_SCSI_256 = 0x05,
- DAC960_V2_IOCTL = 0x20
-}
-__attribute__ ((packed))
-DAC960_V2_CommandOpcode_T;
-
-
-/*
- Define the DAC960 V2 Firmware IOCTL Opcodes.
-*/
-
-typedef enum
-{
- DAC960_V2_GetControllerInfo = 0x01,
- DAC960_V2_GetLogicalDeviceInfoValid = 0x03,
- DAC960_V2_GetPhysicalDeviceInfoValid = 0x05,
- DAC960_V2_GetHealthStatus = 0x11,
- DAC960_V2_GetEvent = 0x15,
- DAC960_V2_StartDiscovery = 0x81,
- DAC960_V2_SetDeviceState = 0x82,
- DAC960_V2_RebuildDeviceStart = 0x88,
- DAC960_V2_RebuildDeviceStop = 0x89,
- DAC960_V2_ConsistencyCheckStart = 0x8C,
- DAC960_V2_ConsistencyCheckStop = 0x8D,
- DAC960_V2_SetMemoryMailbox = 0x8E,
- DAC960_V2_PauseDevice = 0x92,
- DAC960_V2_TranslatePhysicalToLogicalDevice = 0xC5
-}
-__attribute__ ((packed))
-DAC960_V2_IOCTL_Opcode_T;
-
-
-/*
- Define the DAC960 V2 Firmware Command Identifier type.
-*/
-
-typedef unsigned short DAC960_V2_CommandIdentifier_T;
-
-
-/*
- Define the DAC960 V2 Firmware Command Status Codes.
-*/
-
-#define DAC960_V2_NormalCompletion 0x00
-#define DAC960_V2_AbormalCompletion 0x02
-#define DAC960_V2_DeviceBusy 0x08
-#define DAC960_V2_DeviceNonresponsive 0x0E
-#define DAC960_V2_DeviceNonresponsive2 0x0F
-#define DAC960_V2_DeviceRevervationConflict 0x18
-
-typedef unsigned char DAC960_V2_CommandStatus_T;
-
-
-/*
- Define the DAC960 V2 Firmware Memory Type structure.
-*/
-
-typedef struct DAC960_V2_MemoryType
-{
- enum {
- DAC960_V2_MemoryType_Reserved = 0x00,
- DAC960_V2_MemoryType_DRAM = 0x01,
- DAC960_V2_MemoryType_EDRAM = 0x02,
- DAC960_V2_MemoryType_EDO = 0x03,
- DAC960_V2_MemoryType_SDRAM = 0x04,
- DAC960_V2_MemoryType_Last = 0x1F
- } __attribute__ ((packed)) MemoryType:5; /* Byte 0 Bits 0-4 */
- bool :1; /* Byte 0 Bit 5 */
- bool MemoryParity:1; /* Byte 0 Bit 6 */
- bool MemoryECC:1; /* Byte 0 Bit 7 */
-}
-DAC960_V2_MemoryType_T;
-
-
-/*
- Define the DAC960 V2 Firmware Processor Type structure.
-*/
-
-typedef enum
-{
- DAC960_V2_ProcessorType_i960CA = 0x01,
- DAC960_V2_ProcessorType_i960RD = 0x02,
- DAC960_V2_ProcessorType_i960RN = 0x03,
- DAC960_V2_ProcessorType_i960RP = 0x04,
- DAC960_V2_ProcessorType_NorthBay = 0x05,
- DAC960_V2_ProcessorType_StrongArm = 0x06,
- DAC960_V2_ProcessorType_i960RM = 0x07
-}
-__attribute__ ((packed))
-DAC960_V2_ProcessorType_T;
-
-
-/*
- Define the DAC960 V2 Firmware Get Controller Info reply structure.
-*/
-
-typedef struct DAC960_V2_ControllerInfo
-{
- unsigned char :8; /* Byte 0 */
- enum {
- DAC960_V2_SCSI_Bus = 0x00,
- DAC960_V2_Fibre_Bus = 0x01,
- DAC960_V2_PCI_Bus = 0x03
- } __attribute__ ((packed)) BusInterfaceType; /* Byte 1 */
- enum {
- DAC960_V2_DAC960E = 0x01,
- DAC960_V2_DAC960M = 0x08,
- DAC960_V2_DAC960PD = 0x10,
- DAC960_V2_DAC960PL = 0x11,
- DAC960_V2_DAC960PU = 0x12,
- DAC960_V2_DAC960PE = 0x13,
- DAC960_V2_DAC960PG = 0x14,
- DAC960_V2_DAC960PJ = 0x15,
- DAC960_V2_DAC960PTL0 = 0x16,
- DAC960_V2_DAC960PR = 0x17,
- DAC960_V2_DAC960PRL = 0x18,
- DAC960_V2_DAC960PT = 0x19,
- DAC960_V2_DAC1164P = 0x1A,
- DAC960_V2_DAC960PTL1 = 0x1B,
- DAC960_V2_EXR2000P = 0x1C,
- DAC960_V2_EXR3000P = 0x1D,
- DAC960_V2_AcceleRAID352 = 0x1E,
- DAC960_V2_AcceleRAID170 = 0x1F,
- DAC960_V2_AcceleRAID160 = 0x20,
- DAC960_V2_DAC960S = 0x60,
- DAC960_V2_DAC960SU = 0x61,
- DAC960_V2_DAC960SX = 0x62,
- DAC960_V2_DAC960SF = 0x63,
- DAC960_V2_DAC960SS = 0x64,
- DAC960_V2_DAC960FL = 0x65,
- DAC960_V2_DAC960LL = 0x66,
- DAC960_V2_DAC960FF = 0x67,
- DAC960_V2_DAC960HP = 0x68,
- DAC960_V2_RAIDBRICK = 0x69,
- DAC960_V2_METEOR_FL = 0x6A,
- DAC960_V2_METEOR_FF = 0x6B
- } __attribute__ ((packed)) ControllerType; /* Byte 2 */
- unsigned char :8; /* Byte 3 */
- unsigned short BusInterfaceSpeedMHz; /* Bytes 4-5 */
- unsigned char BusWidthBits; /* Byte 6 */
- unsigned char FlashCodeTypeOrProductID; /* Byte 7 */
- unsigned char NumberOfHostPortsPresent; /* Byte 8 */
- unsigned char Reserved1[7]; /* Bytes 9-15 */
- unsigned char BusInterfaceName[16]; /* Bytes 16-31 */
- unsigned char ControllerName[16]; /* Bytes 32-47 */
- unsigned char Reserved2[16]; /* Bytes 48-63 */
- /* Firmware Release Information */
- unsigned char FirmwareMajorVersion; /* Byte 64 */
- unsigned char FirmwareMinorVersion; /* Byte 65 */
- unsigned char FirmwareTurnNumber; /* Byte 66 */
- unsigned char FirmwareBuildNumber; /* Byte 67 */
- unsigned char FirmwareReleaseDay; /* Byte 68 */
- unsigned char FirmwareReleaseMonth; /* Byte 69 */
- unsigned char FirmwareReleaseYearHigh2Digits; /* Byte 70 */
- unsigned char FirmwareReleaseYearLow2Digits; /* Byte 71 */
- /* Hardware Release Information */
- unsigned char HardwareRevision; /* Byte 72 */
- unsigned int :24; /* Bytes 73-75 */
- unsigned char HardwareReleaseDay; /* Byte 76 */
- unsigned char HardwareReleaseMonth; /* Byte 77 */
- unsigned char HardwareReleaseYearHigh2Digits; /* Byte 78 */
- unsigned char HardwareReleaseYearLow2Digits; /* Byte 79 */
- /* Hardware Manufacturing Information */
- unsigned char ManufacturingBatchNumber; /* Byte 80 */
- unsigned char :8; /* Byte 81 */
- unsigned char ManufacturingPlantNumber; /* Byte 82 */
- unsigned char :8; /* Byte 83 */
- unsigned char HardwareManufacturingDay; /* Byte 84 */
- unsigned char HardwareManufacturingMonth; /* Byte 85 */
- unsigned char HardwareManufacturingYearHigh2Digits; /* Byte 86 */
- unsigned char HardwareManufacturingYearLow2Digits; /* Byte 87 */
- unsigned char MaximumNumberOfPDDperXLD; /* Byte 88 */
- unsigned char MaximumNumberOfILDperXLD; /* Byte 89 */
- unsigned short NonvolatileMemorySizeKB; /* Bytes 90-91 */
- unsigned char MaximumNumberOfXLD; /* Byte 92 */
- unsigned int :24; /* Bytes 93-95 */
- /* Unique Information per Controller */
- unsigned char ControllerSerialNumber[16]; /* Bytes 96-111 */
- unsigned char Reserved3[16]; /* Bytes 112-127 */
- /* Vendor Information */
- unsigned int :24; /* Bytes 128-130 */
- unsigned char OEM_Code; /* Byte 131 */
- unsigned char VendorName[16]; /* Bytes 132-147 */
- /* Other Physical/Controller/Operation Information */
- bool BBU_Present:1; /* Byte 148 Bit 0 */
- bool ActiveActiveClusteringMode:1; /* Byte 148 Bit 1 */
- unsigned char :6; /* Byte 148 Bits 2-7 */
- unsigned char :8; /* Byte 149 */
- unsigned short :16; /* Bytes 150-151 */
- /* Physical Device Scan Information */
- bool PhysicalScanActive:1; /* Byte 152 Bit 0 */
- unsigned char :7; /* Byte 152 Bits 1-7 */
- unsigned char PhysicalDeviceChannelNumber; /* Byte 153 */
- unsigned char PhysicalDeviceTargetID; /* Byte 154 */
- unsigned char PhysicalDeviceLogicalUnit; /* Byte 155 */
- /* Maximum Command Data Transfer Sizes */
- unsigned short MaximumDataTransferSizeInBlocks; /* Bytes 156-157 */
- unsigned short MaximumScatterGatherEntries; /* Bytes 158-159 */
- /* Logical/Physical Device Counts */
- unsigned short LogicalDevicesPresent; /* Bytes 160-161 */
- unsigned short LogicalDevicesCritical; /* Bytes 162-163 */
- unsigned short LogicalDevicesOffline; /* Bytes 164-165 */
- unsigned short PhysicalDevicesPresent; /* Bytes 166-167 */
- unsigned short PhysicalDisksPresent; /* Bytes 168-169 */
- unsigned short PhysicalDisksCritical; /* Bytes 170-171 */
- unsigned short PhysicalDisksOffline; /* Bytes 172-173 */
- unsigned short MaximumParallelCommands; /* Bytes 174-175 */
- /* Channel and Target ID Information */
- unsigned char NumberOfPhysicalChannelsPresent; /* Byte 176 */
- unsigned char NumberOfVirtualChannelsPresent; /* Byte 177 */
- unsigned char NumberOfPhysicalChannelsPossible; /* Byte 178 */
- unsigned char NumberOfVirtualChannelsPossible; /* Byte 179 */
- unsigned char MaximumTargetsPerChannel[16]; /* Bytes 180-195 */
- unsigned char Reserved4[12]; /* Bytes 196-207 */
- /* Memory/Cache Information */
- unsigned short MemorySizeMB; /* Bytes 208-209 */
- unsigned short CacheSizeMB; /* Bytes 210-211 */
- unsigned int ValidCacheSizeInBytes; /* Bytes 212-215 */
- unsigned int DirtyCacheSizeInBytes; /* Bytes 216-219 */
- unsigned short MemorySpeedMHz; /* Bytes 220-221 */
- unsigned char MemoryDataWidthBits; /* Byte 222 */
- DAC960_V2_MemoryType_T MemoryType; /* Byte 223 */
- unsigned char CacheMemoryTypeName[16]; /* Bytes 224-239 */
- /* Execution Memory Information */
- unsigned short ExecutionMemorySizeMB; /* Bytes 240-241 */
- unsigned short ExecutionL2CacheSizeMB; /* Bytes 242-243 */
- unsigned char Reserved5[8]; /* Bytes 244-251 */
- unsigned short ExecutionMemorySpeedMHz; /* Bytes 252-253 */
- unsigned char ExecutionMemoryDataWidthBits; /* Byte 254 */
- DAC960_V2_MemoryType_T ExecutionMemoryType; /* Byte 255 */
- unsigned char ExecutionMemoryTypeName[16]; /* Bytes 256-271 */
- /* First CPU Type Information */
- unsigned short FirstProcessorSpeedMHz; /* Bytes 272-273 */
- DAC960_V2_ProcessorType_T FirstProcessorType; /* Byte 274 */
- unsigned char FirstProcessorCount; /* Byte 275 */
- unsigned char Reserved6[12]; /* Bytes 276-287 */
- unsigned char FirstProcessorName[16]; /* Bytes 288-303 */
- /* Second CPU Type Information */
- unsigned short SecondProcessorSpeedMHz; /* Bytes 304-305 */
- DAC960_V2_ProcessorType_T SecondProcessorType; /* Byte 306 */
- unsigned char SecondProcessorCount; /* Byte 307 */
- unsigned char Reserved7[12]; /* Bytes 308-319 */
- unsigned char SecondProcessorName[16]; /* Bytes 320-335 */
- /* Debugging/Profiling/Command Time Tracing Information */
- unsigned short CurrentProfilingDataPageNumber; /* Bytes 336-337 */
- unsigned short ProgramsAwaitingProfilingData; /* Bytes 338-339 */
- unsigned short CurrentCommandTimeTraceDataPageNumber; /* Bytes 340-341 */
- unsigned short ProgramsAwaitingCommandTimeTraceData; /* Bytes 342-343 */
- unsigned char Reserved8[8]; /* Bytes 344-351 */
- /* Error Counters on Physical Devices */
- unsigned short PhysicalDeviceBusResets; /* Bytes 352-353 */
- unsigned short PhysicalDeviceParityErrors; /* Bytes 355-355 */
- unsigned short PhysicalDeviceSoftErrors; /* Bytes 356-357 */
- unsigned short PhysicalDeviceCommandsFailed; /* Bytes 358-359 */
- unsigned short PhysicalDeviceMiscellaneousErrors; /* Bytes 360-361 */
- unsigned short PhysicalDeviceCommandTimeouts; /* Bytes 362-363 */
- unsigned short PhysicalDeviceSelectionTimeouts; /* Bytes 364-365 */
- unsigned short PhysicalDeviceRetriesDone; /* Bytes 366-367 */
- unsigned short PhysicalDeviceAbortsDone; /* Bytes 368-369 */
- unsigned short PhysicalDeviceHostCommandAbortsDone; /* Bytes 370-371 */
- unsigned short PhysicalDevicePredictedFailuresDetected; /* Bytes 372-373 */
- unsigned short PhysicalDeviceHostCommandsFailed; /* Bytes 374-375 */
- unsigned short PhysicalDeviceHardErrors; /* Bytes 376-377 */
- unsigned char Reserved9[6]; /* Bytes 378-383 */
- /* Error Counters on Logical Devices */
- unsigned short LogicalDeviceSoftErrors; /* Bytes 384-385 */
- unsigned short LogicalDeviceCommandsFailed; /* Bytes 386-387 */
- unsigned short LogicalDeviceHostCommandAbortsDone; /* Bytes 388-389 */
- unsigned short :16; /* Bytes 390-391 */
- /* Error Counters on Controller */
- unsigned short ControllerMemoryErrors; /* Bytes 392-393 */
- unsigned short ControllerHostCommandAbortsDone; /* Bytes 394-395 */
- unsigned int :32; /* Bytes 396-399 */
- /* Long Duration Activity Information */
- unsigned short BackgroundInitializationsActive; /* Bytes 400-401 */
- unsigned short LogicalDeviceInitializationsActive; /* Bytes 402-403 */
- unsigned short PhysicalDeviceInitializationsActive; /* Bytes 404-405 */
- unsigned short ConsistencyChecksActive; /* Bytes 406-407 */
- unsigned short RebuildsActive; /* Bytes 408-409 */
- unsigned short OnlineExpansionsActive; /* Bytes 410-411 */
- unsigned short PatrolActivitiesActive; /* Bytes 412-413 */
- unsigned short :16; /* Bytes 414-415 */
- /* Flash ROM Information */
- unsigned char FlashType; /* Byte 416 */
- unsigned char :8; /* Byte 417 */
- unsigned short FlashSizeMB; /* Bytes 418-419 */
- unsigned int FlashLimit; /* Bytes 420-423 */
- unsigned int FlashCount; /* Bytes 424-427 */
- unsigned int :32; /* Bytes 428-431 */
- unsigned char FlashTypeName[16]; /* Bytes 432-447 */
- /* Firmware Run Time Information */
- unsigned char RebuildRate; /* Byte 448 */
- unsigned char BackgroundInitializationRate; /* Byte 449 */
- unsigned char ForegroundInitializationRate; /* Byte 450 */
- unsigned char ConsistencyCheckRate; /* Byte 451 */
- unsigned int :32; /* Bytes 452-455 */
- unsigned int MaximumDP; /* Bytes 456-459 */
- unsigned int FreeDP; /* Bytes 460-463 */
- unsigned int MaximumIOP; /* Bytes 464-467 */
- unsigned int FreeIOP; /* Bytes 468-471 */
- unsigned short MaximumCombLengthInBlocks; /* Bytes 472-473 */
- unsigned short NumberOfConfigurationGroups; /* Bytes 474-475 */
- bool InstallationAbortStatus:1; /* Byte 476 Bit 0 */
- bool MaintenanceModeStatus:1; /* Byte 476 Bit 1 */
- unsigned int :24; /* Bytes 476-479 */
- unsigned char Reserved10[32]; /* Bytes 480-511 */
- unsigned char Reserved11[512]; /* Bytes 512-1023 */
-}
-DAC960_V2_ControllerInfo_T;
-
-
-/*
- Define the DAC960 V2 Firmware Logical Device State type.
-*/
-
-typedef enum
-{
- DAC960_V2_LogicalDevice_Online = 0x01,
- DAC960_V2_LogicalDevice_Offline = 0x08,
- DAC960_V2_LogicalDevice_Critical = 0x09
-}
-__attribute__ ((packed))
-DAC960_V2_LogicalDeviceState_T;
-
-
-/*
- Define the DAC960 V2 Firmware Get Logical Device Info reply structure.
-*/
-
-typedef struct DAC960_V2_LogicalDeviceInfo
-{
- unsigned char :8; /* Byte 0 */
- unsigned char Channel; /* Byte 1 */
- unsigned char TargetID; /* Byte 2 */
- unsigned char LogicalUnit; /* Byte 3 */
- DAC960_V2_LogicalDeviceState_T LogicalDeviceState; /* Byte 4 */
- unsigned char RAIDLevel; /* Byte 5 */
- unsigned char StripeSize; /* Byte 6 */
- unsigned char CacheLineSize; /* Byte 7 */
- struct {
- enum {
- DAC960_V2_ReadCacheDisabled = 0x0,
- DAC960_V2_ReadCacheEnabled = 0x1,
- DAC960_V2_ReadAheadEnabled = 0x2,
- DAC960_V2_IntelligentReadAheadEnabled = 0x3,
- DAC960_V2_ReadCache_Last = 0x7
- } __attribute__ ((packed)) ReadCache:3; /* Byte 8 Bits 0-2 */
- enum {
- DAC960_V2_WriteCacheDisabled = 0x0,
- DAC960_V2_LogicalDeviceReadOnly = 0x1,
- DAC960_V2_WriteCacheEnabled = 0x2,
- DAC960_V2_IntelligentWriteCacheEnabled = 0x3,
- DAC960_V2_WriteCache_Last = 0x7
- } __attribute__ ((packed)) WriteCache:3; /* Byte 8 Bits 3-5 */
- bool :1; /* Byte 8 Bit 6 */
- bool LogicalDeviceInitialized:1; /* Byte 8 Bit 7 */
- } LogicalDeviceControl; /* Byte 8 */
- /* Logical Device Operations Status */
- bool ConsistencyCheckInProgress:1; /* Byte 9 Bit 0 */
- bool RebuildInProgress:1; /* Byte 9 Bit 1 */
- bool BackgroundInitializationInProgress:1; /* Byte 9 Bit 2 */
- bool ForegroundInitializationInProgress:1; /* Byte 9 Bit 3 */
- bool DataMigrationInProgress:1; /* Byte 9 Bit 4 */
- bool PatrolOperationInProgress:1; /* Byte 9 Bit 5 */
- unsigned char :2; /* Byte 9 Bits 6-7 */
- unsigned char RAID5WriteUpdate; /* Byte 10 */
- unsigned char RAID5Algorithm; /* Byte 11 */
- unsigned short LogicalDeviceNumber; /* Bytes 12-13 */
- /* BIOS Info */
- bool BIOSDisabled:1; /* Byte 14 Bit 0 */
- bool CDROMBootEnabled:1; /* Byte 14 Bit 1 */
- bool DriveCoercionEnabled:1; /* Byte 14 Bit 2 */
- bool WriteSameDisabled:1; /* Byte 14 Bit 3 */
- bool HBA_ModeEnabled:1; /* Byte 14 Bit 4 */
- enum {
- DAC960_V2_Geometry_128_32 = 0x0,
- DAC960_V2_Geometry_255_63 = 0x1,
- DAC960_V2_Geometry_Reserved1 = 0x2,
- DAC960_V2_Geometry_Reserved2 = 0x3
- } __attribute__ ((packed)) DriveGeometry:2; /* Byte 14 Bits 5-6 */
- bool SuperReadAheadEnabled:1; /* Byte 14 Bit 7 */
- unsigned char :8; /* Byte 15 */
- /* Error Counters */
- unsigned short SoftErrors; /* Bytes 16-17 */
- unsigned short CommandsFailed; /* Bytes 18-19 */
- unsigned short HostCommandAbortsDone; /* Bytes 20-21 */
- unsigned short DeferredWriteErrors; /* Bytes 22-23 */
- unsigned int :32; /* Bytes 24-27 */
- unsigned int :32; /* Bytes 28-31 */
- /* Device Size Information */
- unsigned short :16; /* Bytes 32-33 */
- unsigned short DeviceBlockSizeInBytes; /* Bytes 34-35 */
- unsigned int OriginalDeviceSize; /* Bytes 36-39 */
- unsigned int ConfigurableDeviceSize; /* Bytes 40-43 */
- unsigned int :32; /* Bytes 44-47 */
- unsigned char LogicalDeviceName[32]; /* Bytes 48-79 */
- unsigned char SCSI_InquiryData[36]; /* Bytes 80-115 */
- unsigned char Reserved1[12]; /* Bytes 116-127 */
- DAC960_ByteCount64_T LastReadBlockNumber; /* Bytes 128-135 */
- DAC960_ByteCount64_T LastWrittenBlockNumber; /* Bytes 136-143 */
- DAC960_ByteCount64_T ConsistencyCheckBlockNumber; /* Bytes 144-151 */
- DAC960_ByteCount64_T RebuildBlockNumber; /* Bytes 152-159 */
- DAC960_ByteCount64_T BackgroundInitializationBlockNumber; /* Bytes 160-167 */
- DAC960_ByteCount64_T ForegroundInitializationBlockNumber; /* Bytes 168-175 */
- DAC960_ByteCount64_T DataMigrationBlockNumber; /* Bytes 176-183 */
- DAC960_ByteCount64_T PatrolOperationBlockNumber; /* Bytes 184-191 */
- unsigned char Reserved2[64]; /* Bytes 192-255 */
-}
-DAC960_V2_LogicalDeviceInfo_T;
-
-
-/*
- Define the DAC960 V2 Firmware Physical Device State type.
-*/
-
-typedef enum
-{
- DAC960_V2_Device_Unconfigured = 0x00,
- DAC960_V2_Device_Online = 0x01,
- DAC960_V2_Device_Rebuild = 0x03,
- DAC960_V2_Device_Missing = 0x04,
- DAC960_V2_Device_Critical = 0x05,
- DAC960_V2_Device_Dead = 0x08,
- DAC960_V2_Device_SuspectedDead = 0x0C,
- DAC960_V2_Device_CommandedOffline = 0x10,
- DAC960_V2_Device_Standby = 0x21,
- DAC960_V2_Device_InvalidState = 0xFF
-}
-__attribute__ ((packed))
-DAC960_V2_PhysicalDeviceState_T;
-
-
-/*
- Define the DAC960 V2 Firmware Get Physical Device Info reply structure.
-*/
-
-typedef struct DAC960_V2_PhysicalDeviceInfo
-{
- unsigned char :8; /* Byte 0 */
- unsigned char Channel; /* Byte 1 */
- unsigned char TargetID; /* Byte 2 */
- unsigned char LogicalUnit; /* Byte 3 */
- /* Configuration Status Bits */
- bool PhysicalDeviceFaultTolerant:1; /* Byte 4 Bit 0 */
- bool PhysicalDeviceConnected:1; /* Byte 4 Bit 1 */
- bool PhysicalDeviceLocalToController:1; /* Byte 4 Bit 2 */
- unsigned char :5; /* Byte 4 Bits 3-7 */
- /* Multiple Host/Controller Status Bits */
- bool RemoteHostSystemDead:1; /* Byte 5 Bit 0 */
- bool RemoteControllerDead:1; /* Byte 5 Bit 1 */
- unsigned char :6; /* Byte 5 Bits 2-7 */
- DAC960_V2_PhysicalDeviceState_T PhysicalDeviceState; /* Byte 6 */
- unsigned char NegotiatedDataWidthBits; /* Byte 7 */
- unsigned short NegotiatedSynchronousMegaTransfers; /* Bytes 8-9 */
- /* Multiported Physical Device Information */
- unsigned char NumberOfPortConnections; /* Byte 10 */
- unsigned char DriveAccessibilityBitmap; /* Byte 11 */
- unsigned int :32; /* Bytes 12-15 */
- unsigned char NetworkAddress[16]; /* Bytes 16-31 */
- unsigned short MaximumTags; /* Bytes 32-33 */
- /* Physical Device Operations Status */
- bool ConsistencyCheckInProgress:1; /* Byte 34 Bit 0 */
- bool RebuildInProgress:1; /* Byte 34 Bit 1 */
- bool MakingDataConsistentInProgress:1; /* Byte 34 Bit 2 */
- bool PhysicalDeviceInitializationInProgress:1; /* Byte 34 Bit 3 */
- bool DataMigrationInProgress:1; /* Byte 34 Bit 4 */
- bool PatrolOperationInProgress:1; /* Byte 34 Bit 5 */
- unsigned char :2; /* Byte 34 Bits 6-7 */
- unsigned char LongOperationStatus; /* Byte 35 */
- unsigned char ParityErrors; /* Byte 36 */
- unsigned char SoftErrors; /* Byte 37 */
- unsigned char HardErrors; /* Byte 38 */
- unsigned char MiscellaneousErrors; /* Byte 39 */
- unsigned char CommandTimeouts; /* Byte 40 */
- unsigned char Retries; /* Byte 41 */
- unsigned char Aborts; /* Byte 42 */
- unsigned char PredictedFailuresDetected; /* Byte 43 */
- unsigned int :32; /* Bytes 44-47 */
- unsigned short :16; /* Bytes 48-49 */
- unsigned short DeviceBlockSizeInBytes; /* Bytes 50-51 */
- unsigned int OriginalDeviceSize; /* Bytes 52-55 */
- unsigned int ConfigurableDeviceSize; /* Bytes 56-59 */
- unsigned int :32; /* Bytes 60-63 */
- unsigned char PhysicalDeviceName[16]; /* Bytes 64-79 */
- unsigned char Reserved1[16]; /* Bytes 80-95 */
- unsigned char Reserved2[32]; /* Bytes 96-127 */
- unsigned char SCSI_InquiryData[36]; /* Bytes 128-163 */
- unsigned char Reserved3[20]; /* Bytes 164-183 */
- unsigned char Reserved4[8]; /* Bytes 184-191 */
- DAC960_ByteCount64_T LastReadBlockNumber; /* Bytes 192-199 */
- DAC960_ByteCount64_T LastWrittenBlockNumber; /* Bytes 200-207 */
- DAC960_ByteCount64_T ConsistencyCheckBlockNumber; /* Bytes 208-215 */
- DAC960_ByteCount64_T RebuildBlockNumber; /* Bytes 216-223 */
- DAC960_ByteCount64_T MakingDataConsistentBlockNumber; /* Bytes 224-231 */
- DAC960_ByteCount64_T DeviceInitializationBlockNumber; /* Bytes 232-239 */
- DAC960_ByteCount64_T DataMigrationBlockNumber; /* Bytes 240-247 */
- DAC960_ByteCount64_T PatrolOperationBlockNumber; /* Bytes 248-255 */
- unsigned char Reserved5[256]; /* Bytes 256-511 */
-}
-DAC960_V2_PhysicalDeviceInfo_T;
-
-
-/*
- Define the DAC960 V2 Firmware Health Status Buffer structure.
-*/
-
-typedef struct DAC960_V2_HealthStatusBuffer
-{
- unsigned int MicrosecondsFromControllerStartTime; /* Bytes 0-3 */
- unsigned int MillisecondsFromControllerStartTime; /* Bytes 4-7 */
- unsigned int SecondsFrom1January1970; /* Bytes 8-11 */
- unsigned int :32; /* Bytes 12-15 */
- unsigned int StatusChangeCounter; /* Bytes 16-19 */
- unsigned int :32; /* Bytes 20-23 */
- unsigned int DebugOutputMessageBufferIndex; /* Bytes 24-27 */
- unsigned int CodedMessageBufferIndex; /* Bytes 28-31 */
- unsigned int CurrentTimeTracePageNumber; /* Bytes 32-35 */
- unsigned int CurrentProfilerPageNumber; /* Bytes 36-39 */
- unsigned int NextEventSequenceNumber; /* Bytes 40-43 */
- unsigned int :32; /* Bytes 44-47 */
- unsigned char Reserved1[16]; /* Bytes 48-63 */
- unsigned char Reserved2[64]; /* Bytes 64-127 */
-}
-DAC960_V2_HealthStatusBuffer_T;
-
-
-/*
- Define the DAC960 V2 Firmware Get Event reply structure.
-*/
-
-typedef struct DAC960_V2_Event
-{
- unsigned int EventSequenceNumber; /* Bytes 0-3 */
- unsigned int EventTime; /* Bytes 4-7 */
- unsigned int EventCode; /* Bytes 8-11 */
- unsigned char :8; /* Byte 12 */
- unsigned char Channel; /* Byte 13 */
- unsigned char TargetID; /* Byte 14 */
- unsigned char LogicalUnit; /* Byte 15 */
- unsigned int :32; /* Bytes 16-19 */
- unsigned int EventSpecificParameter; /* Bytes 20-23 */
- unsigned char RequestSenseData[40]; /* Bytes 24-63 */
-}
-DAC960_V2_Event_T;
-
-
-/*
- Define the DAC960 V2 Firmware Command Control Bits structure.
-*/
-
-typedef struct DAC960_V2_CommandControlBits
-{
- bool ForceUnitAccess:1; /* Byte 0 Bit 0 */
- bool DisablePageOut:1; /* Byte 0 Bit 1 */
- bool :1; /* Byte 0 Bit 2 */
- bool AdditionalScatterGatherListMemory:1; /* Byte 0 Bit 3 */
- bool DataTransferControllerToHost:1; /* Byte 0 Bit 4 */
- bool :1; /* Byte 0 Bit 5 */
- bool NoAutoRequestSense:1; /* Byte 0 Bit 6 */
- bool DisconnectProhibited:1; /* Byte 0 Bit 7 */
-}
-DAC960_V2_CommandControlBits_T;
-
-
-/*
- Define the DAC960 V2 Firmware Command Timeout structure.
-*/
-
-typedef struct DAC960_V2_CommandTimeout
-{
- unsigned char TimeoutValue:6; /* Byte 0 Bits 0-5 */
- enum {
- DAC960_V2_TimeoutScale_Seconds = 0,
- DAC960_V2_TimeoutScale_Minutes = 1,
- DAC960_V2_TimeoutScale_Hours = 2,
- DAC960_V2_TimeoutScale_Reserved = 3
- } __attribute__ ((packed)) TimeoutScale:2; /* Byte 0 Bits 6-7 */
-}
-DAC960_V2_CommandTimeout_T;
-
-
-/*
- Define the DAC960 V2 Firmware Physical Device structure.
-*/
-
-typedef struct DAC960_V2_PhysicalDevice
-{
- unsigned char LogicalUnit; /* Byte 0 */
- unsigned char TargetID; /* Byte 1 */
- unsigned char Channel:3; /* Byte 2 Bits 0-2 */
- unsigned char Controller:5; /* Byte 2 Bits 3-7 */
-}
-__attribute__ ((packed))
-DAC960_V2_PhysicalDevice_T;
-
-
-/*
- Define the DAC960 V2 Firmware Logical Device structure.
-*/
-
-typedef struct DAC960_V2_LogicalDevice
-{
- unsigned short LogicalDeviceNumber; /* Bytes 0-1 */
- unsigned char :3; /* Byte 2 Bits 0-2 */
- unsigned char Controller:5; /* Byte 2 Bits 3-7 */
-}
-__attribute__ ((packed))
-DAC960_V2_LogicalDevice_T;
-
-
-/*
- Define the DAC960 V2 Firmware Operation Device type.
-*/
-
-typedef enum
-{
- DAC960_V2_Physical_Device = 0x00,
- DAC960_V2_RAID_Device = 0x01,
- DAC960_V2_Physical_Channel = 0x02,
- DAC960_V2_RAID_Channel = 0x03,
- DAC960_V2_Physical_Controller = 0x04,
- DAC960_V2_RAID_Controller = 0x05,
- DAC960_V2_Configuration_Group = 0x10,
- DAC960_V2_Enclosure = 0x11
-}
-__attribute__ ((packed))
-DAC960_V2_OperationDevice_T;
-
-
-/*
- Define the DAC960 V2 Firmware Translate Physical To Logical Device structure.
-*/
-
-typedef struct DAC960_V2_PhysicalToLogicalDevice
-{
- unsigned short LogicalDeviceNumber; /* Bytes 0-1 */
- unsigned short :16; /* Bytes 2-3 */
- unsigned char PreviousBootController; /* Byte 4 */
- unsigned char PreviousBootChannel; /* Byte 5 */
- unsigned char PreviousBootTargetID; /* Byte 6 */
- unsigned char PreviousBootLogicalUnit; /* Byte 7 */
-}
-DAC960_V2_PhysicalToLogicalDevice_T;
-
-
-
-/*
- Define the DAC960 V2 Firmware Scatter/Gather List Entry structure.
-*/
-
-typedef struct DAC960_V2_ScatterGatherSegment
-{
- DAC960_BusAddress64_T SegmentDataPointer; /* Bytes 0-7 */
- DAC960_ByteCount64_T SegmentByteCount; /* Bytes 8-15 */
-}
-DAC960_V2_ScatterGatherSegment_T;
-
-
-/*
- Define the DAC960 V2 Firmware Data Transfer Memory Address structure.
-*/
-
-typedef union DAC960_V2_DataTransferMemoryAddress
-{
- DAC960_V2_ScatterGatherSegment_T ScatterGatherSegments[2]; /* Bytes 0-31 */
- struct {
- unsigned short ScatterGatherList0Length; /* Bytes 0-1 */
- unsigned short ScatterGatherList1Length; /* Bytes 2-3 */
- unsigned short ScatterGatherList2Length; /* Bytes 4-5 */
- unsigned short :16; /* Bytes 6-7 */
- DAC960_BusAddress64_T ScatterGatherList0Address; /* Bytes 8-15 */
- DAC960_BusAddress64_T ScatterGatherList1Address; /* Bytes 16-23 */
- DAC960_BusAddress64_T ScatterGatherList2Address; /* Bytes 24-31 */
- } ExtendedScatterGather;
-}
-DAC960_V2_DataTransferMemoryAddress_T;
-
-
-/*
- Define the 64 Byte DAC960 V2 Firmware Command Mailbox structure.
-*/
-
-typedef union DAC960_V2_CommandMailbox
-{
- unsigned int Words[16]; /* Words 0-15 */
- struct {
- DAC960_V2_CommandIdentifier_T CommandIdentifier; /* Bytes 0-1 */
- DAC960_V2_CommandOpcode_T CommandOpcode; /* Byte 2 */
- DAC960_V2_CommandControlBits_T CommandControlBits; /* Byte 3 */
- DAC960_ByteCount32_T DataTransferSize:24; /* Bytes 4-6 */
- unsigned char DataTransferPageNumber; /* Byte 7 */
- DAC960_BusAddress64_T RequestSenseBusAddress; /* Bytes 8-15 */
- unsigned int :24; /* Bytes 16-18 */
- DAC960_V2_CommandTimeout_T CommandTimeout; /* Byte 19 */
- unsigned char RequestSenseSize; /* Byte 20 */
- unsigned char IOCTL_Opcode; /* Byte 21 */
- unsigned char Reserved[10]; /* Bytes 22-31 */
- DAC960_V2_DataTransferMemoryAddress_T
- DataTransferMemoryAddress; /* Bytes 32-63 */
- } Common;
- struct {
- DAC960_V2_CommandIdentifier_T CommandIdentifier; /* Bytes 0-1 */
- DAC960_V2_CommandOpcode_T CommandOpcode; /* Byte 2 */
- DAC960_V2_CommandControlBits_T CommandControlBits; /* Byte 3 */
- DAC960_ByteCount32_T DataTransferSize; /* Bytes 4-7 */
- DAC960_BusAddress64_T RequestSenseBusAddress; /* Bytes 8-15 */
- DAC960_V2_PhysicalDevice_T PhysicalDevice; /* Bytes 16-18 */
- DAC960_V2_CommandTimeout_T CommandTimeout; /* Byte 19 */
- unsigned char RequestSenseSize; /* Byte 20 */
- unsigned char CDBLength; /* Byte 21 */
- unsigned char SCSI_CDB[10]; /* Bytes 22-31 */
- DAC960_V2_DataTransferMemoryAddress_T
- DataTransferMemoryAddress; /* Bytes 32-63 */
- } SCSI_10;
- struct {
- DAC960_V2_CommandIdentifier_T CommandIdentifier; /* Bytes 0-1 */
- DAC960_V2_CommandOpcode_T CommandOpcode; /* Byte 2 */
- DAC960_V2_CommandControlBits_T CommandControlBits; /* Byte 3 */
- DAC960_ByteCount32_T DataTransferSize; /* Bytes 4-7 */
- DAC960_BusAddress64_T RequestSenseBusAddress; /* Bytes 8-15 */
- DAC960_V2_PhysicalDevice_T PhysicalDevice; /* Bytes 16-18 */
- DAC960_V2_CommandTimeout_T CommandTimeout; /* Byte 19 */
- unsigned char RequestSenseSize; /* Byte 20 */
- unsigned char CDBLength; /* Byte 21 */
- unsigned short :16; /* Bytes 22-23 */
- DAC960_BusAddress64_T SCSI_CDB_BusAddress; /* Bytes 24-31 */
- DAC960_V2_DataTransferMemoryAddress_T
- DataTransferMemoryAddress; /* Bytes 32-63 */
- } SCSI_255;
- struct {
- DAC960_V2_CommandIdentifier_T CommandIdentifier; /* Bytes 0-1 */
- DAC960_V2_CommandOpcode_T CommandOpcode; /* Byte 2 */
- DAC960_V2_CommandControlBits_T CommandControlBits; /* Byte 3 */
- DAC960_ByteCount32_T DataTransferSize:24; /* Bytes 4-6 */
- unsigned char DataTransferPageNumber; /* Byte 7 */
- DAC960_BusAddress64_T RequestSenseBusAddress; /* Bytes 8-15 */
- unsigned short :16; /* Bytes 16-17 */
- unsigned char ControllerNumber; /* Byte 18 */
- DAC960_V2_CommandTimeout_T CommandTimeout; /* Byte 19 */
- unsigned char RequestSenseSize; /* Byte 20 */
- unsigned char IOCTL_Opcode; /* Byte 21 */
- unsigned char Reserved[10]; /* Bytes 22-31 */
- DAC960_V2_DataTransferMemoryAddress_T
- DataTransferMemoryAddress; /* Bytes 32-63 */
- } ControllerInfo;
- struct {
- DAC960_V2_CommandIdentifier_T CommandIdentifier; /* Bytes 0-1 */
- DAC960_V2_CommandOpcode_T CommandOpcode; /* Byte 2 */
- DAC960_V2_CommandControlBits_T CommandControlBits; /* Byte 3 */
- DAC960_ByteCount32_T DataTransferSize:24; /* Bytes 4-6 */
- unsigned char DataTransferPageNumber; /* Byte 7 */
- DAC960_BusAddress64_T RequestSenseBusAddress; /* Bytes 8-15 */
- DAC960_V2_LogicalDevice_T LogicalDevice; /* Bytes 16-18 */
- DAC960_V2_CommandTimeout_T CommandTimeout; /* Byte 19 */
- unsigned char RequestSenseSize; /* Byte 20 */
- unsigned char IOCTL_Opcode; /* Byte 21 */
- unsigned char Reserved[10]; /* Bytes 22-31 */
- DAC960_V2_DataTransferMemoryAddress_T
- DataTransferMemoryAddress; /* Bytes 32-63 */
- } LogicalDeviceInfo;
- struct {
- DAC960_V2_CommandIdentifier_T CommandIdentifier; /* Bytes 0-1 */
- DAC960_V2_CommandOpcode_T CommandOpcode; /* Byte 2 */
- DAC960_V2_CommandControlBits_T CommandControlBits; /* Byte 3 */
- DAC960_ByteCount32_T DataTransferSize:24; /* Bytes 4-6 */
- unsigned char DataTransferPageNumber; /* Byte 7 */
- DAC960_BusAddress64_T RequestSenseBusAddress; /* Bytes 8-15 */
- DAC960_V2_PhysicalDevice_T PhysicalDevice; /* Bytes 16-18 */
- DAC960_V2_CommandTimeout_T CommandTimeout; /* Byte 19 */
- unsigned char RequestSenseSize; /* Byte 20 */
- unsigned char IOCTL_Opcode; /* Byte 21 */
- unsigned char Reserved[10]; /* Bytes 22-31 */
- DAC960_V2_DataTransferMemoryAddress_T
- DataTransferMemoryAddress; /* Bytes 32-63 */
- } PhysicalDeviceInfo;
- struct {
- DAC960_V2_CommandIdentifier_T CommandIdentifier; /* Bytes 0-1 */
- DAC960_V2_CommandOpcode_T CommandOpcode; /* Byte 2 */
- DAC960_V2_CommandControlBits_T CommandControlBits; /* Byte 3 */
- DAC960_ByteCount32_T DataTransferSize:24; /* Bytes 4-6 */
- unsigned char DataTransferPageNumber; /* Byte 7 */
- DAC960_BusAddress64_T RequestSenseBusAddress; /* Bytes 8-15 */
- unsigned short EventSequenceNumberHigh16; /* Bytes 16-17 */
- unsigned char ControllerNumber; /* Byte 18 */
- DAC960_V2_CommandTimeout_T CommandTimeout; /* Byte 19 */
- unsigned char RequestSenseSize; /* Byte 20 */
- unsigned char IOCTL_Opcode; /* Byte 21 */
- unsigned short EventSequenceNumberLow16; /* Bytes 22-23 */
- unsigned char Reserved[8]; /* Bytes 24-31 */
- DAC960_V2_DataTransferMemoryAddress_T
- DataTransferMemoryAddress; /* Bytes 32-63 */
- } GetEvent;
- struct {
- DAC960_V2_CommandIdentifier_T CommandIdentifier; /* Bytes 0-1 */
- DAC960_V2_CommandOpcode_T CommandOpcode; /* Byte 2 */
- DAC960_V2_CommandControlBits_T CommandControlBits; /* Byte 3 */
- DAC960_ByteCount32_T DataTransferSize:24; /* Bytes 4-6 */
- unsigned char DataTransferPageNumber; /* Byte 7 */
- DAC960_BusAddress64_T RequestSenseBusAddress; /* Bytes 8-15 */
- DAC960_V2_LogicalDevice_T LogicalDevice; /* Bytes 16-18 */
- DAC960_V2_CommandTimeout_T CommandTimeout; /* Byte 19 */
- unsigned char RequestSenseSize; /* Byte 20 */
- unsigned char IOCTL_Opcode; /* Byte 21 */
- union {
- DAC960_V2_LogicalDeviceState_T LogicalDeviceState;
- DAC960_V2_PhysicalDeviceState_T PhysicalDeviceState;
- } DeviceState; /* Byte 22 */
- unsigned char Reserved[9]; /* Bytes 23-31 */
- DAC960_V2_DataTransferMemoryAddress_T
- DataTransferMemoryAddress; /* Bytes 32-63 */
- } SetDeviceState;
- struct {
- DAC960_V2_CommandIdentifier_T CommandIdentifier; /* Bytes 0-1 */
- DAC960_V2_CommandOpcode_T CommandOpcode; /* Byte 2 */
- DAC960_V2_CommandControlBits_T CommandControlBits; /* Byte 3 */
- DAC960_ByteCount32_T DataTransferSize:24; /* Bytes 4-6 */
- unsigned char DataTransferPageNumber; /* Byte 7 */
- DAC960_BusAddress64_T RequestSenseBusAddress; /* Bytes 8-15 */
- DAC960_V2_LogicalDevice_T LogicalDevice; /* Bytes 16-18 */
- DAC960_V2_CommandTimeout_T CommandTimeout; /* Byte 19 */
- unsigned char RequestSenseSize; /* Byte 20 */
- unsigned char IOCTL_Opcode; /* Byte 21 */
- bool RestoreConsistency:1; /* Byte 22 Bit 0 */
- bool InitializedAreaOnly:1; /* Byte 22 Bit 1 */
- unsigned char :6; /* Byte 22 Bits 2-7 */
- unsigned char Reserved[9]; /* Bytes 23-31 */
- DAC960_V2_DataTransferMemoryAddress_T
- DataTransferMemoryAddress; /* Bytes 32-63 */
- } ConsistencyCheck;
- struct {
- DAC960_V2_CommandIdentifier_T CommandIdentifier; /* Bytes 0-1 */
- DAC960_V2_CommandOpcode_T CommandOpcode; /* Byte 2 */
- DAC960_V2_CommandControlBits_T CommandControlBits; /* Byte 3 */
- unsigned char FirstCommandMailboxSizeKB; /* Byte 4 */
- unsigned char FirstStatusMailboxSizeKB; /* Byte 5 */
- unsigned char SecondCommandMailboxSizeKB; /* Byte 6 */
- unsigned char SecondStatusMailboxSizeKB; /* Byte 7 */
- DAC960_BusAddress64_T RequestSenseBusAddress; /* Bytes 8-15 */
- unsigned int :24; /* Bytes 16-18 */
- DAC960_V2_CommandTimeout_T CommandTimeout; /* Byte 19 */
- unsigned char RequestSenseSize; /* Byte 20 */
- unsigned char IOCTL_Opcode; /* Byte 21 */
- unsigned char HealthStatusBufferSizeKB; /* Byte 22 */
- unsigned char :8; /* Byte 23 */
- DAC960_BusAddress64_T HealthStatusBufferBusAddress; /* Bytes 24-31 */
- DAC960_BusAddress64_T FirstCommandMailboxBusAddress; /* Bytes 32-39 */
- DAC960_BusAddress64_T FirstStatusMailboxBusAddress; /* Bytes 40-47 */
- DAC960_BusAddress64_T SecondCommandMailboxBusAddress; /* Bytes 48-55 */
- DAC960_BusAddress64_T SecondStatusMailboxBusAddress; /* Bytes 56-63 */
- } SetMemoryMailbox;
- struct {
- DAC960_V2_CommandIdentifier_T CommandIdentifier; /* Bytes 0-1 */
- DAC960_V2_CommandOpcode_T CommandOpcode; /* Byte 2 */
- DAC960_V2_CommandControlBits_T CommandControlBits; /* Byte 3 */
- DAC960_ByteCount32_T DataTransferSize:24; /* Bytes 4-6 */
- unsigned char DataTransferPageNumber; /* Byte 7 */
- DAC960_BusAddress64_T RequestSenseBusAddress; /* Bytes 8-15 */
- DAC960_V2_PhysicalDevice_T PhysicalDevice; /* Bytes 16-18 */
- DAC960_V2_CommandTimeout_T CommandTimeout; /* Byte 19 */
- unsigned char RequestSenseSize; /* Byte 20 */
- unsigned char IOCTL_Opcode; /* Byte 21 */
- DAC960_V2_OperationDevice_T OperationDevice; /* Byte 22 */
- unsigned char Reserved[9]; /* Bytes 23-31 */
- DAC960_V2_DataTransferMemoryAddress_T
- DataTransferMemoryAddress; /* Bytes 32-63 */
- } DeviceOperation;
-}
-DAC960_V2_CommandMailbox_T;
-
-
-/*
- Define the DAC960 Driver IOCTL requests.
-*/
-
-#define DAC960_IOCTL_GET_CONTROLLER_COUNT 0xDAC001
-#define DAC960_IOCTL_GET_CONTROLLER_INFO 0xDAC002
-#define DAC960_IOCTL_V1_EXECUTE_COMMAND 0xDAC003
-#define DAC960_IOCTL_V2_EXECUTE_COMMAND 0xDAC004
-#define DAC960_IOCTL_V2_GET_HEALTH_STATUS 0xDAC005
-
-
-/*
- Define the DAC960_IOCTL_GET_CONTROLLER_INFO reply structure.
-*/
-
-typedef struct DAC960_ControllerInfo
-{
- unsigned char ControllerNumber;
- unsigned char FirmwareType;
- unsigned char Channels;
- unsigned char Targets;
- unsigned char PCI_Bus;
- unsigned char PCI_Device;
- unsigned char PCI_Function;
- unsigned char IRQ_Channel;
- DAC960_PCI_Address_T PCI_Address;
- unsigned char ModelName[20];
- unsigned char FirmwareVersion[12];
-}
-DAC960_ControllerInfo_T;
-
-
-/*
- Define the User Mode DAC960_IOCTL_V1_EXECUTE_COMMAND request structure.
-*/
-
-typedef struct DAC960_V1_UserCommand
-{
- unsigned char ControllerNumber;
- DAC960_V1_CommandMailbox_T CommandMailbox;
- int DataTransferLength;
- void __user *DataTransferBuffer;
- DAC960_V1_DCDB_T __user *DCDB;
-}
-DAC960_V1_UserCommand_T;
-
-
-/*
- Define the Kernel Mode DAC960_IOCTL_V1_EXECUTE_COMMAND request structure.
-*/
-
-typedef struct DAC960_V1_KernelCommand
-{
- unsigned char ControllerNumber;
- DAC960_V1_CommandMailbox_T CommandMailbox;
- int DataTransferLength;
- void *DataTransferBuffer;
- DAC960_V1_DCDB_T *DCDB;
- DAC960_V1_CommandStatus_T CommandStatus;
- void (*CompletionFunction)(struct DAC960_V1_KernelCommand *);
- void *CompletionData;
-}
-DAC960_V1_KernelCommand_T;
-
-
-/*
- Define the User Mode DAC960_IOCTL_V2_EXECUTE_COMMAND request structure.
-*/
-
-typedef struct DAC960_V2_UserCommand
-{
- unsigned char ControllerNumber;
- DAC960_V2_CommandMailbox_T CommandMailbox;
- int DataTransferLength;
- int RequestSenseLength;
- void __user *DataTransferBuffer;
- void __user *RequestSenseBuffer;
-}
-DAC960_V2_UserCommand_T;
-
-
-/*
- Define the Kernel Mode DAC960_IOCTL_V2_EXECUTE_COMMAND request structure.
-*/
-
-typedef struct DAC960_V2_KernelCommand
-{
- unsigned char ControllerNumber;
- DAC960_V2_CommandMailbox_T CommandMailbox;
- int DataTransferLength;
- int RequestSenseLength;
- void *DataTransferBuffer;
- void *RequestSenseBuffer;
- DAC960_V2_CommandStatus_T CommandStatus;
- void (*CompletionFunction)(struct DAC960_V2_KernelCommand *);
- void *CompletionData;
-}
-DAC960_V2_KernelCommand_T;
-
-
-/*
- Define the User Mode DAC960_IOCTL_V2_GET_HEALTH_STATUS request structure.
-*/
-
-typedef struct DAC960_V2_GetHealthStatus
-{
- unsigned char ControllerNumber;
- DAC960_V2_HealthStatusBuffer_T __user *HealthStatusBuffer;
-}
-DAC960_V2_GetHealthStatus_T;
-
-
-/*
- Import the Kernel Mode IOCTL interface.
-*/
-
-extern int DAC960_KernelIOCTL(unsigned int Request, void *Argument);
-
-
-/*
- DAC960_DriverVersion protects the private portion of this file.
-*/
-
-#ifdef DAC960_DriverVersion
-
-
-/*
- Define the maximum Driver Queue Depth and Controller Queue Depth supported
- by DAC960 V1 and V2 Firmware Controllers.
-*/
-
-#define DAC960_MaxDriverQueueDepth 511
-#define DAC960_MaxControllerQueueDepth 512
-
-
-/*
- Define the maximum number of Scatter/Gather Segments supported for any
- DAC960 V1 and V2 Firmware controller.
-*/
-
-#define DAC960_V1_ScatterGatherLimit 33
-#define DAC960_V2_ScatterGatherLimit 128
-
-
-/*
- Define the number of Command Mailboxes and Status Mailboxes used by the
- DAC960 V1 and V2 Firmware Memory Mailbox Interface.
-*/
-
-#define DAC960_V1_CommandMailboxCount 256
-#define DAC960_V1_StatusMailboxCount 1024
-#define DAC960_V2_CommandMailboxCount 512
-#define DAC960_V2_StatusMailboxCount 512
-
-
-/*
- Define the DAC960 Controller Monitoring Timer Interval.
-*/
-
-#define DAC960_MonitoringTimerInterval (10 * HZ)
-
-
-/*
- Define the DAC960 Controller Secondary Monitoring Interval.
-*/
-
-#define DAC960_SecondaryMonitoringInterval (60 * HZ)
-
-
-/*
- Define the DAC960 Controller Health Status Monitoring Interval.
-*/
-
-#define DAC960_HealthStatusMonitoringInterval (1 * HZ)
-
-
-/*
- Define the DAC960 Controller Progress Reporting Interval.
-*/
-
-#define DAC960_ProgressReportingInterval (60 * HZ)
-
-
-/*
- Define the maximum number of Partitions allowed for each Logical Drive.
-*/
-
-#define DAC960_MaxPartitions 8
-#define DAC960_MaxPartitionsBits 3
-
-/*
- Define the DAC960 Controller fixed Block Size and Block Size Bits.
-*/
-
-#define DAC960_BlockSize 512
-#define DAC960_BlockSizeBits 9
-
-
-/*
- Define the number of Command structures that should be allocated as a
- group to optimize kernel memory allocation.
-*/
-
-#define DAC960_V1_CommandAllocationGroupSize 11
-#define DAC960_V2_CommandAllocationGroupSize 29
-
-
-/*
- Define the Controller Line Buffer, Progress Buffer, User Message, and
- Initial Status Buffer sizes.
-*/
-
-#define DAC960_LineBufferSize 100
-#define DAC960_ProgressBufferSize 200
-#define DAC960_UserMessageSize 200
-#define DAC960_InitialStatusBufferSize (8192-32)
-
-
-/*
- Define the DAC960 Controller Firmware Types.
-*/
-
-typedef enum
-{
- DAC960_V1_Controller = 1,
- DAC960_V2_Controller = 2
-}
-DAC960_FirmwareType_T;
-
-
-/*
- Define the DAC960 Controller Hardware Types.
-*/
-
-typedef enum
-{
- DAC960_BA_Controller = 1, /* eXtremeRAID 2000 */
- DAC960_LP_Controller = 2, /* AcceleRAID 352 */
- DAC960_LA_Controller = 3, /* DAC1164P */
- DAC960_PG_Controller = 4, /* DAC960PTL/PJ/PG */
- DAC960_PD_Controller = 5, /* DAC960PU/PD/PL/P */
- DAC960_P_Controller = 6, /* DAC960PU/PD/PL/P */
- DAC960_GEM_Controller = 7, /* AcceleRAID 4/5/600 */
-}
-DAC960_HardwareType_T;
-
-
-/*
- Define the Driver Message Levels.
-*/
-
-typedef enum DAC960_MessageLevel
-{
- DAC960_AnnounceLevel = 0,
- DAC960_InfoLevel = 1,
- DAC960_NoticeLevel = 2,
- DAC960_WarningLevel = 3,
- DAC960_ErrorLevel = 4,
- DAC960_ProgressLevel = 5,
- DAC960_CriticalLevel = 6,
- DAC960_UserCriticalLevel = 7
-}
-DAC960_MessageLevel_T;
-
-static char
- *DAC960_MessageLevelMap[] =
- { KERN_NOTICE, KERN_NOTICE, KERN_NOTICE, KERN_WARNING,
- KERN_ERR, KERN_CRIT, KERN_CRIT, KERN_CRIT };
-
-
-/*
- Define Driver Message macros.
-*/
-
-#define DAC960_Announce(Format, Arguments...) \
- DAC960_Message(DAC960_AnnounceLevel, Format, ##Arguments)
-
-#define DAC960_Info(Format, Arguments...) \
- DAC960_Message(DAC960_InfoLevel, Format, ##Arguments)
-
-#define DAC960_Notice(Format, Arguments...) \
- DAC960_Message(DAC960_NoticeLevel, Format, ##Arguments)
-
-#define DAC960_Warning(Format, Arguments...) \
- DAC960_Message(DAC960_WarningLevel, Format, ##Arguments)
-
-#define DAC960_Error(Format, Arguments...) \
- DAC960_Message(DAC960_ErrorLevel, Format, ##Arguments)
-
-#define DAC960_Progress(Format, Arguments...) \
- DAC960_Message(DAC960_ProgressLevel, Format, ##Arguments)
-
-#define DAC960_Critical(Format, Arguments...) \
- DAC960_Message(DAC960_CriticalLevel, Format, ##Arguments)
-
-#define DAC960_UserCritical(Format, Arguments...) \
- DAC960_Message(DAC960_UserCriticalLevel, Format, ##Arguments)
-
-
-struct DAC960_privdata {
- DAC960_HardwareType_T HardwareType;
- DAC960_FirmwareType_T FirmwareType;
- irq_handler_t InterruptHandler;
- unsigned int MemoryWindowSize;
-};
-
-
-/*
- Define the DAC960 V1 Firmware Controller Status Mailbox structure.
-*/
-
-typedef union DAC960_V1_StatusMailbox
-{
- unsigned int Word; /* Word 0 */
- struct {
- DAC960_V1_CommandIdentifier_T CommandIdentifier; /* Byte 0 */
- unsigned char :7; /* Byte 1 Bits 0-6 */
- bool Valid:1; /* Byte 1 Bit 7 */
- DAC960_V1_CommandStatus_T CommandStatus; /* Bytes 2-3 */
- } Fields;
-}
-DAC960_V1_StatusMailbox_T;
-
-
-/*
- Define the DAC960 V2 Firmware Controller Status Mailbox structure.
-*/
-
-typedef union DAC960_V2_StatusMailbox
-{
- unsigned int Words[2]; /* Words 0-1 */
- struct {
- DAC960_V2_CommandIdentifier_T CommandIdentifier; /* Bytes 0-1 */
- DAC960_V2_CommandStatus_T CommandStatus; /* Byte 2 */
- unsigned char RequestSenseLength; /* Byte 3 */
- int DataTransferResidue; /* Bytes 4-7 */
- } Fields;
-}
-DAC960_V2_StatusMailbox_T;
-
-
-/*
- Define the DAC960 Driver Command Types.
-*/
-
-typedef enum
-{
- DAC960_ReadCommand = 1,
- DAC960_WriteCommand = 2,
- DAC960_ReadRetryCommand = 3,
- DAC960_WriteRetryCommand = 4,
- DAC960_MonitoringCommand = 5,
- DAC960_ImmediateCommand = 6,
- DAC960_QueuedCommand = 7
-}
-DAC960_CommandType_T;
-
-
-/*
- Define the DAC960 Driver Command structure.
-*/
-
-typedef struct DAC960_Command
-{
- int CommandIdentifier;
- DAC960_CommandType_T CommandType;
- struct DAC960_Controller *Controller;
- struct DAC960_Command *Next;
- struct completion *Completion;
- unsigned int LogicalDriveNumber;
- unsigned int BlockNumber;
- unsigned int BlockCount;
- unsigned int SegmentCount;
- int DmaDirection;
- struct scatterlist *cmd_sglist;
- struct request *Request;
- union {
- struct {
- DAC960_V1_CommandMailbox_T CommandMailbox;
- DAC960_V1_KernelCommand_T *KernelCommand;
- DAC960_V1_CommandStatus_T CommandStatus;
- DAC960_V1_ScatterGatherSegment_T *ScatterGatherList;
- dma_addr_t ScatterGatherListDMA;
- struct scatterlist ScatterList[DAC960_V1_ScatterGatherLimit];
- unsigned int EndMarker[0];
- } V1;
- struct {
- DAC960_V2_CommandMailbox_T CommandMailbox;
- DAC960_V2_KernelCommand_T *KernelCommand;
- DAC960_V2_CommandStatus_T CommandStatus;
- unsigned char RequestSenseLength;
- int DataTransferResidue;
- DAC960_V2_ScatterGatherSegment_T *ScatterGatherList;
- dma_addr_t ScatterGatherListDMA;
- DAC960_SCSI_RequestSense_T *RequestSense;
- dma_addr_t RequestSenseDMA;
- struct scatterlist ScatterList[DAC960_V2_ScatterGatherLimit];
- unsigned int EndMarker[0];
- } V2;
- } FW;
-}
-DAC960_Command_T;
-
-
-/*
- Define the DAC960 Driver Controller structure.
-*/
-
-typedef struct DAC960_Controller
-{
- void __iomem *BaseAddress;
- void __iomem *MemoryMappedAddress;
- DAC960_FirmwareType_T FirmwareType;
- DAC960_HardwareType_T HardwareType;
- DAC960_IO_Address_T IO_Address;
- DAC960_PCI_Address_T PCI_Address;
- struct pci_dev *PCIDevice;
- unsigned char ControllerNumber;
- unsigned char ControllerName[4];
- unsigned char ModelName[20];
- unsigned char FullModelName[28];
- unsigned char FirmwareVersion[12];
- unsigned char Bus;
- unsigned char Device;
- unsigned char Function;
- unsigned char IRQ_Channel;
- unsigned char Channels;
- unsigned char Targets;
- unsigned char MemorySize;
- unsigned char LogicalDriveCount;
- unsigned short CommandAllocationGroupSize;
- unsigned short ControllerQueueDepth;
- unsigned short DriverQueueDepth;
- unsigned short MaxBlocksPerCommand;
- unsigned short ControllerScatterGatherLimit;
- unsigned short DriverScatterGatherLimit;
- unsigned int CombinedStatusBufferLength;
- unsigned int InitialStatusLength;
- unsigned int CurrentStatusLength;
- unsigned int ProgressBufferLength;
- unsigned int UserStatusLength;
- struct dma_loaf DmaPages;
- unsigned long MonitoringTimerCount;
- unsigned long PrimaryMonitoringTime;
- unsigned long SecondaryMonitoringTime;
- unsigned long ShutdownMonitoringTimer;
- unsigned long LastProgressReportTime;
- unsigned long LastCurrentStatusTime;
- bool ControllerInitialized;
- bool MonitoringCommandDeferred;
- bool EphemeralProgressMessage;
- bool DriveSpinUpMessageDisplayed;
- bool MonitoringAlertMode;
- bool SuppressEnclosureMessages;
- struct timer_list MonitoringTimer;
- struct gendisk *disks[DAC960_MaxLogicalDrives];
- struct dma_pool *ScatterGatherPool;
- DAC960_Command_T *FreeCommands;
- unsigned char *CombinedStatusBuffer;
- unsigned char *CurrentStatusBuffer;
- struct request_queue *RequestQueue[DAC960_MaxLogicalDrives];
- int req_q_index;
- spinlock_t queue_lock;
- wait_queue_head_t CommandWaitQueue;
- wait_queue_head_t HealthStatusWaitQueue;
- DAC960_Command_T InitialCommand;
- DAC960_Command_T *Commands[DAC960_MaxDriverQueueDepth];
- struct proc_dir_entry *ControllerProcEntry;
- bool LogicalDriveInitiallyAccessible[DAC960_MaxLogicalDrives];
- void (*QueueCommand)(DAC960_Command_T *Command);
- bool (*ReadControllerConfiguration)(struct DAC960_Controller *);
- bool (*ReadDeviceConfiguration)(struct DAC960_Controller *);
- bool (*ReportDeviceConfiguration)(struct DAC960_Controller *);
- void (*QueueReadWriteCommand)(DAC960_Command_T *Command);
- union {
- struct {
- unsigned char GeometryTranslationHeads;
- unsigned char GeometryTranslationSectors;
- unsigned char PendingRebuildFlag;
- unsigned short StripeSize;
- unsigned short SegmentSize;
- unsigned short NewEventLogSequenceNumber;
- unsigned short OldEventLogSequenceNumber;
- unsigned short DeviceStateChannel;
- unsigned short DeviceStateTargetID;
- bool DualModeMemoryMailboxInterface;
- bool BackgroundInitializationStatusSupported;
- bool SAFTE_EnclosureManagementEnabled;
- bool NeedLogicalDriveInformation;
- bool NeedErrorTableInformation;
- bool NeedDeviceStateInformation;
- bool NeedDeviceInquiryInformation;
- bool NeedDeviceSerialNumberInformation;
- bool NeedRebuildProgress;
- bool NeedConsistencyCheckProgress;
- bool NeedBackgroundInitializationStatus;
- bool StartDeviceStateScan;
- bool RebuildProgressFirst;
- bool RebuildFlagPending;
- bool RebuildStatusPending;
-
- dma_addr_t FirstCommandMailboxDMA;
- DAC960_V1_CommandMailbox_T *FirstCommandMailbox;
- DAC960_V1_CommandMailbox_T *LastCommandMailbox;
- DAC960_V1_CommandMailbox_T *NextCommandMailbox;
- DAC960_V1_CommandMailbox_T *PreviousCommandMailbox1;
- DAC960_V1_CommandMailbox_T *PreviousCommandMailbox2;
-
- dma_addr_t FirstStatusMailboxDMA;
- DAC960_V1_StatusMailbox_T *FirstStatusMailbox;
- DAC960_V1_StatusMailbox_T *LastStatusMailbox;
- DAC960_V1_StatusMailbox_T *NextStatusMailbox;
-
- DAC960_V1_DCDB_T *MonitoringDCDB;
- dma_addr_t MonitoringDCDB_DMA;
-
- DAC960_V1_Enquiry_T Enquiry;
- DAC960_V1_Enquiry_T *NewEnquiry;
- dma_addr_t NewEnquiryDMA;
-
- DAC960_V1_ErrorTable_T ErrorTable;
- DAC960_V1_ErrorTable_T *NewErrorTable;
- dma_addr_t NewErrorTableDMA;
-
- DAC960_V1_EventLogEntry_T *EventLogEntry;
- dma_addr_t EventLogEntryDMA;
-
- DAC960_V1_RebuildProgress_T *RebuildProgress;
- dma_addr_t RebuildProgressDMA;
- DAC960_V1_CommandStatus_T LastRebuildStatus;
- DAC960_V1_CommandStatus_T PendingRebuildStatus;
-
- DAC960_V1_LogicalDriveInformationArray_T LogicalDriveInformation;
- DAC960_V1_LogicalDriveInformationArray_T *NewLogicalDriveInformation;
- dma_addr_t NewLogicalDriveInformationDMA;
-
- DAC960_V1_BackgroundInitializationStatus_T
- *BackgroundInitializationStatus;
- dma_addr_t BackgroundInitializationStatusDMA;
- DAC960_V1_BackgroundInitializationStatus_T
- LastBackgroundInitializationStatus;
-
- DAC960_V1_DeviceState_T
- DeviceState[DAC960_V1_MaxChannels][DAC960_V1_MaxTargets];
- DAC960_V1_DeviceState_T *NewDeviceState;
- dma_addr_t NewDeviceStateDMA;
-
- DAC960_SCSI_Inquiry_T
- InquiryStandardData[DAC960_V1_MaxChannels][DAC960_V1_MaxTargets];
- DAC960_SCSI_Inquiry_T *NewInquiryStandardData;
- dma_addr_t NewInquiryStandardDataDMA;
-
- DAC960_SCSI_Inquiry_UnitSerialNumber_T
- InquiryUnitSerialNumber[DAC960_V1_MaxChannels][DAC960_V1_MaxTargets];
- DAC960_SCSI_Inquiry_UnitSerialNumber_T *NewInquiryUnitSerialNumber;
- dma_addr_t NewInquiryUnitSerialNumberDMA;
-
- int DeviceResetCount[DAC960_V1_MaxChannels][DAC960_V1_MaxTargets];
- bool DirectCommandActive[DAC960_V1_MaxChannels][DAC960_V1_MaxTargets];
- } V1;
- struct {
- unsigned int StatusChangeCounter;
- unsigned int NextEventSequenceNumber;
- unsigned int PhysicalDeviceIndex;
- bool NeedLogicalDeviceInformation;
- bool NeedPhysicalDeviceInformation;
- bool NeedDeviceSerialNumberInformation;
- bool StartLogicalDeviceInformationScan;
- bool StartPhysicalDeviceInformationScan;
- struct dma_pool *RequestSensePool;
-
- dma_addr_t FirstCommandMailboxDMA;
- DAC960_V2_CommandMailbox_T *FirstCommandMailbox;
- DAC960_V2_CommandMailbox_T *LastCommandMailbox;
- DAC960_V2_CommandMailbox_T *NextCommandMailbox;
- DAC960_V2_CommandMailbox_T *PreviousCommandMailbox1;
- DAC960_V2_CommandMailbox_T *PreviousCommandMailbox2;
-
- dma_addr_t FirstStatusMailboxDMA;
- DAC960_V2_StatusMailbox_T *FirstStatusMailbox;
- DAC960_V2_StatusMailbox_T *LastStatusMailbox;
- DAC960_V2_StatusMailbox_T *NextStatusMailbox;
-
- dma_addr_t HealthStatusBufferDMA;
- DAC960_V2_HealthStatusBuffer_T *HealthStatusBuffer;
-
- DAC960_V2_ControllerInfo_T ControllerInformation;
- DAC960_V2_ControllerInfo_T *NewControllerInformation;
- dma_addr_t NewControllerInformationDMA;
-
- DAC960_V2_LogicalDeviceInfo_T
- *LogicalDeviceInformation[DAC960_MaxLogicalDrives];
- DAC960_V2_LogicalDeviceInfo_T *NewLogicalDeviceInformation;
- dma_addr_t NewLogicalDeviceInformationDMA;
-
- DAC960_V2_PhysicalDeviceInfo_T
- *PhysicalDeviceInformation[DAC960_V2_MaxPhysicalDevices];
- DAC960_V2_PhysicalDeviceInfo_T *NewPhysicalDeviceInformation;
- dma_addr_t NewPhysicalDeviceInformationDMA;
-
- DAC960_SCSI_Inquiry_UnitSerialNumber_T *NewInquiryUnitSerialNumber;
- dma_addr_t NewInquiryUnitSerialNumberDMA;
- DAC960_SCSI_Inquiry_UnitSerialNumber_T
- *InquiryUnitSerialNumber[DAC960_V2_MaxPhysicalDevices];
-
- DAC960_V2_Event_T *Event;
- dma_addr_t EventDMA;
-
- DAC960_V2_PhysicalToLogicalDevice_T *PhysicalToLogicalDevice;
- dma_addr_t PhysicalToLogicalDeviceDMA;
-
- DAC960_V2_PhysicalDevice_T
- LogicalDriveToVirtualDevice[DAC960_MaxLogicalDrives];
- bool LogicalDriveFoundDuringScan[DAC960_MaxLogicalDrives];
- } V2;
- } FW;
- unsigned char ProgressBuffer[DAC960_ProgressBufferSize];
- unsigned char UserStatusBuffer[DAC960_UserMessageSize];
-}
-DAC960_Controller_T;
-
-
-/*
- Simplify access to Firmware Version Dependent Data Structure Components
- and Functions.
-*/
-
-#define V1 FW.V1
-#define V2 FW.V2
-#define DAC960_QueueCommand(Command) \
- (Controller->QueueCommand)(Command)
-#define DAC960_ReadControllerConfiguration(Controller) \
- (Controller->ReadControllerConfiguration)(Controller)
-#define DAC960_ReadDeviceConfiguration(Controller) \
- (Controller->ReadDeviceConfiguration)(Controller)
-#define DAC960_ReportDeviceConfiguration(Controller) \
- (Controller->ReportDeviceConfiguration)(Controller)
-#define DAC960_QueueReadWriteCommand(Command) \
- (Controller->QueueReadWriteCommand)(Command)
-
-/*
- * dma_addr_writeql is provided to write dma_addr_t types
- * to a 64-bit pci address space register. The controller
- * will accept having the register written as two 32-bit
- * values.
- *
- * In HIGHMEM kernels, dma_addr_t is a 64-bit value.
- * without HIGHMEM, dma_addr_t is a 32-bit value.
- *
- * The compiler should always fix up the assignment
- * to u.wq appropriately, depending upon the size of
- * dma_addr_t.
- */
-static inline
-void dma_addr_writeql(dma_addr_t addr, void __iomem *write_address)
-{
- union {
- u64 wq;
- uint wl[2];
- } u;
-
- u.wq = addr;
-
- writel(u.wl[0], write_address);
- writel(u.wl[1], write_address + 4);
-}
-
-/*
- Define the DAC960 GEM Series Controller Interface Register Offsets.
- */
-
-#define DAC960_GEM_RegisterWindowSize 0x600
-
-typedef enum
-{
- DAC960_GEM_InboundDoorBellRegisterReadSetOffset = 0x214,
- DAC960_GEM_InboundDoorBellRegisterClearOffset = 0x218,
- DAC960_GEM_OutboundDoorBellRegisterReadSetOffset = 0x224,
- DAC960_GEM_OutboundDoorBellRegisterClearOffset = 0x228,
- DAC960_GEM_InterruptStatusRegisterOffset = 0x208,
- DAC960_GEM_InterruptMaskRegisterReadSetOffset = 0x22C,
- DAC960_GEM_InterruptMaskRegisterClearOffset = 0x230,
- DAC960_GEM_CommandMailboxBusAddressOffset = 0x510,
- DAC960_GEM_CommandStatusOffset = 0x518,
- DAC960_GEM_ErrorStatusRegisterReadSetOffset = 0x224,
- DAC960_GEM_ErrorStatusRegisterClearOffset = 0x228,
-}
-DAC960_GEM_RegisterOffsets_T;
-
-/*
- Define the structure of the DAC960 GEM Series Inbound Door Bell
- */
-
-typedef union DAC960_GEM_InboundDoorBellRegister
-{
- unsigned int All;
- struct {
- unsigned int :24;
- bool HardwareMailboxNewCommand:1;
- bool AcknowledgeHardwareMailboxStatus:1;
- bool GenerateInterrupt:1;
- bool ControllerReset:1;
- bool MemoryMailboxNewCommand:1;
- unsigned int :3;
- } Write;
- struct {
- unsigned int :24;
- bool HardwareMailboxFull:1;
- bool InitializationInProgress:1;
- unsigned int :6;
- } Read;
-}
-DAC960_GEM_InboundDoorBellRegister_T;
-
-/*
- Define the structure of the DAC960 GEM Series Outbound Door Bell Register.
- */
-typedef union DAC960_GEM_OutboundDoorBellRegister
-{
- unsigned int All;
- struct {
- unsigned int :24;
- bool AcknowledgeHardwareMailboxInterrupt:1;
- bool AcknowledgeMemoryMailboxInterrupt:1;
- unsigned int :6;
- } Write;
- struct {
- unsigned int :24;
- bool HardwareMailboxStatusAvailable:1;
- bool MemoryMailboxStatusAvailable:1;
- unsigned int :6;
- } Read;
-}
-DAC960_GEM_OutboundDoorBellRegister_T;
-
-/*
- Define the structure of the DAC960 GEM Series Interrupt Mask Register.
- */
-typedef union DAC960_GEM_InterruptMaskRegister
-{
- unsigned int All;
- struct {
- unsigned int :16;
- unsigned int :8;
- unsigned int HardwareMailboxInterrupt:1;
- unsigned int MemoryMailboxInterrupt:1;
- unsigned int :6;
- } Bits;
-}
-DAC960_GEM_InterruptMaskRegister_T;
-
-/*
- Define the structure of the DAC960 GEM Series Error Status Register.
- */
-
-typedef union DAC960_GEM_ErrorStatusRegister
-{
- unsigned int All;
- struct {
- unsigned int :24;
- unsigned int :5;
- bool ErrorStatusPending:1;
- unsigned int :2;
- } Bits;
-}
-DAC960_GEM_ErrorStatusRegister_T;
-
-/*
- Define inline functions to provide an abstraction for reading and writing the
- DAC960 GEM Series Controller Interface Registers.
-*/
-
-static inline
-void DAC960_GEM_HardwareMailboxNewCommand(void __iomem *ControllerBaseAddress)
-{
- DAC960_GEM_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.HardwareMailboxNewCommand = true;
- writel(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_GEM_InboundDoorBellRegisterReadSetOffset);
-}
-
-static inline
-void DAC960_GEM_AcknowledgeHardwareMailboxStatus(void __iomem *ControllerBaseAddress)
-{
- DAC960_GEM_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.AcknowledgeHardwareMailboxStatus = true;
- writel(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_GEM_InboundDoorBellRegisterClearOffset);
-}
-
-static inline
-void DAC960_GEM_GenerateInterrupt(void __iomem *ControllerBaseAddress)
-{
- DAC960_GEM_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.GenerateInterrupt = true;
- writel(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_GEM_InboundDoorBellRegisterReadSetOffset);
-}
-
-static inline
-void DAC960_GEM_ControllerReset(void __iomem *ControllerBaseAddress)
-{
- DAC960_GEM_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.ControllerReset = true;
- writel(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_GEM_InboundDoorBellRegisterReadSetOffset);
-}
-
-static inline
-void DAC960_GEM_MemoryMailboxNewCommand(void __iomem *ControllerBaseAddress)
-{
- DAC960_GEM_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.MemoryMailboxNewCommand = true;
- writel(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_GEM_InboundDoorBellRegisterReadSetOffset);
-}
-
-static inline
-bool DAC960_GEM_HardwareMailboxFullP(void __iomem *ControllerBaseAddress)
-{
- DAC960_GEM_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All =
- readl(ControllerBaseAddress +
- DAC960_GEM_InboundDoorBellRegisterReadSetOffset);
- return InboundDoorBellRegister.Read.HardwareMailboxFull;
-}
-
-static inline
-bool DAC960_GEM_InitializationInProgressP(void __iomem *ControllerBaseAddress)
-{
- DAC960_GEM_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All =
- readl(ControllerBaseAddress +
- DAC960_GEM_InboundDoorBellRegisterReadSetOffset);
- return InboundDoorBellRegister.Read.InitializationInProgress;
-}
-
-static inline
-void DAC960_GEM_AcknowledgeHardwareMailboxInterrupt(void __iomem *ControllerBaseAddress)
-{
- DAC960_GEM_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All = 0;
- OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true;
- writel(OutboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_GEM_OutboundDoorBellRegisterClearOffset);
-}
-
-static inline
-void DAC960_GEM_AcknowledgeMemoryMailboxInterrupt(void __iomem *ControllerBaseAddress)
-{
- DAC960_GEM_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All = 0;
- OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true;
- writel(OutboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_GEM_OutboundDoorBellRegisterClearOffset);
-}
-
-static inline
-void DAC960_GEM_AcknowledgeInterrupt(void __iomem *ControllerBaseAddress)
-{
- DAC960_GEM_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All = 0;
- OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true;
- OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true;
- writel(OutboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_GEM_OutboundDoorBellRegisterClearOffset);
-}
-
-static inline
-bool DAC960_GEM_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress)
-{
- DAC960_GEM_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All =
- readl(ControllerBaseAddress +
- DAC960_GEM_OutboundDoorBellRegisterReadSetOffset);
- return OutboundDoorBellRegister.Read.HardwareMailboxStatusAvailable;
-}
-
-static inline
-bool DAC960_GEM_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress)
-{
- DAC960_GEM_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All =
- readl(ControllerBaseAddress +
- DAC960_GEM_OutboundDoorBellRegisterReadSetOffset);
- return OutboundDoorBellRegister.Read.MemoryMailboxStatusAvailable;
-}
-
-static inline
-void DAC960_GEM_EnableInterrupts(void __iomem *ControllerBaseAddress)
-{
- DAC960_GEM_InterruptMaskRegister_T InterruptMaskRegister;
- InterruptMaskRegister.All = 0;
- InterruptMaskRegister.Bits.HardwareMailboxInterrupt = true;
- InterruptMaskRegister.Bits.MemoryMailboxInterrupt = true;
- writel(InterruptMaskRegister.All,
- ControllerBaseAddress + DAC960_GEM_InterruptMaskRegisterClearOffset);
-}
-
-static inline
-void DAC960_GEM_DisableInterrupts(void __iomem *ControllerBaseAddress)
-{
- DAC960_GEM_InterruptMaskRegister_T InterruptMaskRegister;
- InterruptMaskRegister.All = 0;
- InterruptMaskRegister.Bits.HardwareMailboxInterrupt = true;
- InterruptMaskRegister.Bits.MemoryMailboxInterrupt = true;
- writel(InterruptMaskRegister.All,
- ControllerBaseAddress + DAC960_GEM_InterruptMaskRegisterReadSetOffset);
-}
-
-static inline
-bool DAC960_GEM_InterruptsEnabledP(void __iomem *ControllerBaseAddress)
-{
- DAC960_GEM_InterruptMaskRegister_T InterruptMaskRegister;
- InterruptMaskRegister.All =
- readl(ControllerBaseAddress +
- DAC960_GEM_InterruptMaskRegisterReadSetOffset);
- return !(InterruptMaskRegister.Bits.HardwareMailboxInterrupt ||
- InterruptMaskRegister.Bits.MemoryMailboxInterrupt);
-}
-
-static inline
-void DAC960_GEM_WriteCommandMailbox(DAC960_V2_CommandMailbox_T
- *MemoryCommandMailbox,
- DAC960_V2_CommandMailbox_T
- *CommandMailbox)
-{
- memcpy(&MemoryCommandMailbox->Words[1], &CommandMailbox->Words[1],
- sizeof(DAC960_V2_CommandMailbox_T) - sizeof(unsigned int));
- wmb();
- MemoryCommandMailbox->Words[0] = CommandMailbox->Words[0];
- mb();
-}
-
-static inline
-void DAC960_GEM_WriteHardwareMailbox(void __iomem *ControllerBaseAddress,
- dma_addr_t CommandMailboxDMA)
-{
- dma_addr_writeql(CommandMailboxDMA,
- ControllerBaseAddress +
- DAC960_GEM_CommandMailboxBusAddressOffset);
-}
-
-static inline DAC960_V2_CommandIdentifier_T
-DAC960_GEM_ReadCommandIdentifier(void __iomem *ControllerBaseAddress)
-{
- return readw(ControllerBaseAddress + DAC960_GEM_CommandStatusOffset);
-}
-
-static inline DAC960_V2_CommandStatus_T
-DAC960_GEM_ReadCommandStatus(void __iomem *ControllerBaseAddress)
-{
- return readw(ControllerBaseAddress + DAC960_GEM_CommandStatusOffset + 2);
-}
-
-static inline bool
-DAC960_GEM_ReadErrorStatus(void __iomem *ControllerBaseAddress,
- unsigned char *ErrorStatus,
- unsigned char *Parameter0,
- unsigned char *Parameter1)
-{
- DAC960_GEM_ErrorStatusRegister_T ErrorStatusRegister;
- ErrorStatusRegister.All =
- readl(ControllerBaseAddress + DAC960_GEM_ErrorStatusRegisterReadSetOffset);
- if (!ErrorStatusRegister.Bits.ErrorStatusPending) return false;
- ErrorStatusRegister.Bits.ErrorStatusPending = false;
- *ErrorStatus = ErrorStatusRegister.All;
- *Parameter0 =
- readb(ControllerBaseAddress + DAC960_GEM_CommandMailboxBusAddressOffset + 0);
- *Parameter1 =
- readb(ControllerBaseAddress + DAC960_GEM_CommandMailboxBusAddressOffset + 1);
- writel(0x03000000, ControllerBaseAddress +
- DAC960_GEM_ErrorStatusRegisterClearOffset);
- return true;
-}
-
-/*
- Define the DAC960 BA Series Controller Interface Register Offsets.
-*/
-
-#define DAC960_BA_RegisterWindowSize 0x80
-
-typedef enum
-{
- DAC960_BA_InboundDoorBellRegisterOffset = 0x60,
- DAC960_BA_OutboundDoorBellRegisterOffset = 0x61,
- DAC960_BA_InterruptStatusRegisterOffset = 0x30,
- DAC960_BA_InterruptMaskRegisterOffset = 0x34,
- DAC960_BA_CommandMailboxBusAddressOffset = 0x50,
- DAC960_BA_CommandStatusOffset = 0x58,
- DAC960_BA_ErrorStatusRegisterOffset = 0x63
-}
-DAC960_BA_RegisterOffsets_T;
-
-
-/*
- Define the structure of the DAC960 BA Series Inbound Door Bell Register.
-*/
-
-typedef union DAC960_BA_InboundDoorBellRegister
-{
- unsigned char All;
- struct {
- bool HardwareMailboxNewCommand:1; /* Bit 0 */
- bool AcknowledgeHardwareMailboxStatus:1; /* Bit 1 */
- bool GenerateInterrupt:1; /* Bit 2 */
- bool ControllerReset:1; /* Bit 3 */
- bool MemoryMailboxNewCommand:1; /* Bit 4 */
- unsigned char :3; /* Bits 5-7 */
- } Write;
- struct {
- bool HardwareMailboxEmpty:1; /* Bit 0 */
- bool InitializationNotInProgress:1; /* Bit 1 */
- unsigned char :6; /* Bits 2-7 */
- } Read;
-}
-DAC960_BA_InboundDoorBellRegister_T;
-
-
-/*
- Define the structure of the DAC960 BA Series Outbound Door Bell Register.
-*/
-
-typedef union DAC960_BA_OutboundDoorBellRegister
-{
- unsigned char All;
- struct {
- bool AcknowledgeHardwareMailboxInterrupt:1; /* Bit 0 */
- bool AcknowledgeMemoryMailboxInterrupt:1; /* Bit 1 */
- unsigned char :6; /* Bits 2-7 */
- } Write;
- struct {
- bool HardwareMailboxStatusAvailable:1; /* Bit 0 */
- bool MemoryMailboxStatusAvailable:1; /* Bit 1 */
- unsigned char :6; /* Bits 2-7 */
- } Read;
-}
-DAC960_BA_OutboundDoorBellRegister_T;
-
-
-/*
- Define the structure of the DAC960 BA Series Interrupt Mask Register.
-*/
-
-typedef union DAC960_BA_InterruptMaskRegister
-{
- unsigned char All;
- struct {
- unsigned int :2; /* Bits 0-1 */
- bool DisableInterrupts:1; /* Bit 2 */
- bool DisableInterruptsI2O:1; /* Bit 3 */
- unsigned int :4; /* Bits 4-7 */
- } Bits;
-}
-DAC960_BA_InterruptMaskRegister_T;
-
-
-/*
- Define the structure of the DAC960 BA Series Error Status Register.
-*/
-
-typedef union DAC960_BA_ErrorStatusRegister
-{
- unsigned char All;
- struct {
- unsigned int :2; /* Bits 0-1 */
- bool ErrorStatusPending:1; /* Bit 2 */
- unsigned int :5; /* Bits 3-7 */
- } Bits;
-}
-DAC960_BA_ErrorStatusRegister_T;
-
-
-/*
- Define inline functions to provide an abstraction for reading and writing the
- DAC960 BA Series Controller Interface Registers.
-*/
-
-static inline
-void DAC960_BA_HardwareMailboxNewCommand(void __iomem *ControllerBaseAddress)
-{
- DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.HardwareMailboxNewCommand = true;
- writeb(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_BA_InboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_BA_AcknowledgeHardwareMailboxStatus(void __iomem *ControllerBaseAddress)
-{
- DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.AcknowledgeHardwareMailboxStatus = true;
- writeb(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_BA_InboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_BA_GenerateInterrupt(void __iomem *ControllerBaseAddress)
-{
- DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.GenerateInterrupt = true;
- writeb(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_BA_InboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_BA_ControllerReset(void __iomem *ControllerBaseAddress)
-{
- DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.ControllerReset = true;
- writeb(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_BA_InboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_BA_MemoryMailboxNewCommand(void __iomem *ControllerBaseAddress)
-{
- DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.MemoryMailboxNewCommand = true;
- writeb(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_BA_InboundDoorBellRegisterOffset);
-}
-
-static inline
-bool DAC960_BA_HardwareMailboxFullP(void __iomem *ControllerBaseAddress)
-{
- DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All =
- readb(ControllerBaseAddress + DAC960_BA_InboundDoorBellRegisterOffset);
- return !InboundDoorBellRegister.Read.HardwareMailboxEmpty;
-}
-
-static inline
-bool DAC960_BA_InitializationInProgressP(void __iomem *ControllerBaseAddress)
-{
- DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All =
- readb(ControllerBaseAddress + DAC960_BA_InboundDoorBellRegisterOffset);
- return !InboundDoorBellRegister.Read.InitializationNotInProgress;
-}
-
-static inline
-void DAC960_BA_AcknowledgeHardwareMailboxInterrupt(void __iomem *ControllerBaseAddress)
-{
- DAC960_BA_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All = 0;
- OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true;
- writeb(OutboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_BA_OutboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_BA_AcknowledgeMemoryMailboxInterrupt(void __iomem *ControllerBaseAddress)
-{
- DAC960_BA_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All = 0;
- OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true;
- writeb(OutboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_BA_OutboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_BA_AcknowledgeInterrupt(void __iomem *ControllerBaseAddress)
-{
- DAC960_BA_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All = 0;
- OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true;
- OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true;
- writeb(OutboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_BA_OutboundDoorBellRegisterOffset);
-}
-
-static inline
-bool DAC960_BA_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress)
-{
- DAC960_BA_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All =
- readb(ControllerBaseAddress + DAC960_BA_OutboundDoorBellRegisterOffset);
- return OutboundDoorBellRegister.Read.HardwareMailboxStatusAvailable;
-}
-
-static inline
-bool DAC960_BA_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress)
-{
- DAC960_BA_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All =
- readb(ControllerBaseAddress + DAC960_BA_OutboundDoorBellRegisterOffset);
- return OutboundDoorBellRegister.Read.MemoryMailboxStatusAvailable;
-}
-
-static inline
-void DAC960_BA_EnableInterrupts(void __iomem *ControllerBaseAddress)
-{
- DAC960_BA_InterruptMaskRegister_T InterruptMaskRegister;
- InterruptMaskRegister.All = 0xFF;
- InterruptMaskRegister.Bits.DisableInterrupts = false;
- InterruptMaskRegister.Bits.DisableInterruptsI2O = true;
- writeb(InterruptMaskRegister.All,
- ControllerBaseAddress + DAC960_BA_InterruptMaskRegisterOffset);
-}
-
-static inline
-void DAC960_BA_DisableInterrupts(void __iomem *ControllerBaseAddress)
-{
- DAC960_BA_InterruptMaskRegister_T InterruptMaskRegister;
- InterruptMaskRegister.All = 0xFF;
- InterruptMaskRegister.Bits.DisableInterrupts = true;
- InterruptMaskRegister.Bits.DisableInterruptsI2O = true;
- writeb(InterruptMaskRegister.All,
- ControllerBaseAddress + DAC960_BA_InterruptMaskRegisterOffset);
-}
-
-static inline
-bool DAC960_BA_InterruptsEnabledP(void __iomem *ControllerBaseAddress)
-{
- DAC960_BA_InterruptMaskRegister_T InterruptMaskRegister;
- InterruptMaskRegister.All =
- readb(ControllerBaseAddress + DAC960_BA_InterruptMaskRegisterOffset);
- return !InterruptMaskRegister.Bits.DisableInterrupts;
-}
-
-static inline
-void DAC960_BA_WriteCommandMailbox(DAC960_V2_CommandMailbox_T
- *MemoryCommandMailbox,
- DAC960_V2_CommandMailbox_T
- *CommandMailbox)
-{
- memcpy(&MemoryCommandMailbox->Words[1], &CommandMailbox->Words[1],
- sizeof(DAC960_V2_CommandMailbox_T) - sizeof(unsigned int));
- wmb();
- MemoryCommandMailbox->Words[0] = CommandMailbox->Words[0];
- mb();
-}
-
-
-static inline
-void DAC960_BA_WriteHardwareMailbox(void __iomem *ControllerBaseAddress,
- dma_addr_t CommandMailboxDMA)
-{
- dma_addr_writeql(CommandMailboxDMA,
- ControllerBaseAddress +
- DAC960_BA_CommandMailboxBusAddressOffset);
-}
-
-static inline DAC960_V2_CommandIdentifier_T
-DAC960_BA_ReadCommandIdentifier(void __iomem *ControllerBaseAddress)
-{
- return readw(ControllerBaseAddress + DAC960_BA_CommandStatusOffset);
-}
-
-static inline DAC960_V2_CommandStatus_T
-DAC960_BA_ReadCommandStatus(void __iomem *ControllerBaseAddress)
-{
- return readw(ControllerBaseAddress + DAC960_BA_CommandStatusOffset + 2);
-}
-
-static inline bool
-DAC960_BA_ReadErrorStatus(void __iomem *ControllerBaseAddress,
- unsigned char *ErrorStatus,
- unsigned char *Parameter0,
- unsigned char *Parameter1)
-{
- DAC960_BA_ErrorStatusRegister_T ErrorStatusRegister;
- ErrorStatusRegister.All =
- readb(ControllerBaseAddress + DAC960_BA_ErrorStatusRegisterOffset);
- if (!ErrorStatusRegister.Bits.ErrorStatusPending) return false;
- ErrorStatusRegister.Bits.ErrorStatusPending = false;
- *ErrorStatus = ErrorStatusRegister.All;
- *Parameter0 =
- readb(ControllerBaseAddress + DAC960_BA_CommandMailboxBusAddressOffset + 0);
- *Parameter1 =
- readb(ControllerBaseAddress + DAC960_BA_CommandMailboxBusAddressOffset + 1);
- writeb(0xFF, ControllerBaseAddress + DAC960_BA_ErrorStatusRegisterOffset);
- return true;
-}
-
-
-/*
- Define the DAC960 LP Series Controller Interface Register Offsets.
-*/
-
-#define DAC960_LP_RegisterWindowSize 0x80
-
-typedef enum
-{
- DAC960_LP_InboundDoorBellRegisterOffset = 0x20,
- DAC960_LP_OutboundDoorBellRegisterOffset = 0x2C,
- DAC960_LP_InterruptStatusRegisterOffset = 0x30,
- DAC960_LP_InterruptMaskRegisterOffset = 0x34,
- DAC960_LP_CommandMailboxBusAddressOffset = 0x10,
- DAC960_LP_CommandStatusOffset = 0x18,
- DAC960_LP_ErrorStatusRegisterOffset = 0x2E
-}
-DAC960_LP_RegisterOffsets_T;
-
-
-/*
- Define the structure of the DAC960 LP Series Inbound Door Bell Register.
-*/
-
-typedef union DAC960_LP_InboundDoorBellRegister
-{
- unsigned char All;
- struct {
- bool HardwareMailboxNewCommand:1; /* Bit 0 */
- bool AcknowledgeHardwareMailboxStatus:1; /* Bit 1 */
- bool GenerateInterrupt:1; /* Bit 2 */
- bool ControllerReset:1; /* Bit 3 */
- bool MemoryMailboxNewCommand:1; /* Bit 4 */
- unsigned char :3; /* Bits 5-7 */
- } Write;
- struct {
- bool HardwareMailboxFull:1; /* Bit 0 */
- bool InitializationInProgress:1; /* Bit 1 */
- unsigned char :6; /* Bits 2-7 */
- } Read;
-}
-DAC960_LP_InboundDoorBellRegister_T;
-
-
-/*
- Define the structure of the DAC960 LP Series Outbound Door Bell Register.
-*/
-
-typedef union DAC960_LP_OutboundDoorBellRegister
-{
- unsigned char All;
- struct {
- bool AcknowledgeHardwareMailboxInterrupt:1; /* Bit 0 */
- bool AcknowledgeMemoryMailboxInterrupt:1; /* Bit 1 */
- unsigned char :6; /* Bits 2-7 */
- } Write;
- struct {
- bool HardwareMailboxStatusAvailable:1; /* Bit 0 */
- bool MemoryMailboxStatusAvailable:1; /* Bit 1 */
- unsigned char :6; /* Bits 2-7 */
- } Read;
-}
-DAC960_LP_OutboundDoorBellRegister_T;
-
-
-/*
- Define the structure of the DAC960 LP Series Interrupt Mask Register.
-*/
-
-typedef union DAC960_LP_InterruptMaskRegister
-{
- unsigned char All;
- struct {
- unsigned int :2; /* Bits 0-1 */
- bool DisableInterrupts:1; /* Bit 2 */
- unsigned int :5; /* Bits 3-7 */
- } Bits;
-}
-DAC960_LP_InterruptMaskRegister_T;
-
-
-/*
- Define the structure of the DAC960 LP Series Error Status Register.
-*/
-
-typedef union DAC960_LP_ErrorStatusRegister
-{
- unsigned char All;
- struct {
- unsigned int :2; /* Bits 0-1 */
- bool ErrorStatusPending:1; /* Bit 2 */
- unsigned int :5; /* Bits 3-7 */
- } Bits;
-}
-DAC960_LP_ErrorStatusRegister_T;
-
-
-/*
- Define inline functions to provide an abstraction for reading and writing the
- DAC960 LP Series Controller Interface Registers.
-*/
-
-static inline
-void DAC960_LP_HardwareMailboxNewCommand(void __iomem *ControllerBaseAddress)
-{
- DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.HardwareMailboxNewCommand = true;
- writeb(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_LP_InboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_LP_AcknowledgeHardwareMailboxStatus(void __iomem *ControllerBaseAddress)
-{
- DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.AcknowledgeHardwareMailboxStatus = true;
- writeb(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_LP_InboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_LP_GenerateInterrupt(void __iomem *ControllerBaseAddress)
-{
- DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.GenerateInterrupt = true;
- writeb(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_LP_InboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_LP_ControllerReset(void __iomem *ControllerBaseAddress)
-{
- DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.ControllerReset = true;
- writeb(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_LP_InboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_LP_MemoryMailboxNewCommand(void __iomem *ControllerBaseAddress)
-{
- DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.MemoryMailboxNewCommand = true;
- writeb(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_LP_InboundDoorBellRegisterOffset);
-}
-
-static inline
-bool DAC960_LP_HardwareMailboxFullP(void __iomem *ControllerBaseAddress)
-{
- DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All =
- readb(ControllerBaseAddress + DAC960_LP_InboundDoorBellRegisterOffset);
- return InboundDoorBellRegister.Read.HardwareMailboxFull;
-}
-
-static inline
-bool DAC960_LP_InitializationInProgressP(void __iomem *ControllerBaseAddress)
-{
- DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All =
- readb(ControllerBaseAddress + DAC960_LP_InboundDoorBellRegisterOffset);
- return InboundDoorBellRegister.Read.InitializationInProgress;
-}
-
-static inline
-void DAC960_LP_AcknowledgeHardwareMailboxInterrupt(void __iomem *ControllerBaseAddress)
-{
- DAC960_LP_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All = 0;
- OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true;
- writeb(OutboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_LP_OutboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_LP_AcknowledgeMemoryMailboxInterrupt(void __iomem *ControllerBaseAddress)
-{
- DAC960_LP_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All = 0;
- OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true;
- writeb(OutboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_LP_OutboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_LP_AcknowledgeInterrupt(void __iomem *ControllerBaseAddress)
-{
- DAC960_LP_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All = 0;
- OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true;
- OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true;
- writeb(OutboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_LP_OutboundDoorBellRegisterOffset);
-}
-
-static inline
-bool DAC960_LP_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress)
-{
- DAC960_LP_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All =
- readb(ControllerBaseAddress + DAC960_LP_OutboundDoorBellRegisterOffset);
- return OutboundDoorBellRegister.Read.HardwareMailboxStatusAvailable;
-}
-
-static inline
-bool DAC960_LP_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress)
-{
- DAC960_LP_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All =
- readb(ControllerBaseAddress + DAC960_LP_OutboundDoorBellRegisterOffset);
- return OutboundDoorBellRegister.Read.MemoryMailboxStatusAvailable;
-}
-
-static inline
-void DAC960_LP_EnableInterrupts(void __iomem *ControllerBaseAddress)
-{
- DAC960_LP_InterruptMaskRegister_T InterruptMaskRegister;
- InterruptMaskRegister.All = 0xFF;
- InterruptMaskRegister.Bits.DisableInterrupts = false;
- writeb(InterruptMaskRegister.All,
- ControllerBaseAddress + DAC960_LP_InterruptMaskRegisterOffset);
-}
-
-static inline
-void DAC960_LP_DisableInterrupts(void __iomem *ControllerBaseAddress)
-{
- DAC960_LP_InterruptMaskRegister_T InterruptMaskRegister;
- InterruptMaskRegister.All = 0xFF;
- InterruptMaskRegister.Bits.DisableInterrupts = true;
- writeb(InterruptMaskRegister.All,
- ControllerBaseAddress + DAC960_LP_InterruptMaskRegisterOffset);
-}
-
-static inline
-bool DAC960_LP_InterruptsEnabledP(void __iomem *ControllerBaseAddress)
-{
- DAC960_LP_InterruptMaskRegister_T InterruptMaskRegister;
- InterruptMaskRegister.All =
- readb(ControllerBaseAddress + DAC960_LP_InterruptMaskRegisterOffset);
- return !InterruptMaskRegister.Bits.DisableInterrupts;
-}
-
-static inline
-void DAC960_LP_WriteCommandMailbox(DAC960_V2_CommandMailbox_T
- *MemoryCommandMailbox,
- DAC960_V2_CommandMailbox_T
- *CommandMailbox)
-{
- memcpy(&MemoryCommandMailbox->Words[1], &CommandMailbox->Words[1],
- sizeof(DAC960_V2_CommandMailbox_T) - sizeof(unsigned int));
- wmb();
- MemoryCommandMailbox->Words[0] = CommandMailbox->Words[0];
- mb();
-}
-
-static inline
-void DAC960_LP_WriteHardwareMailbox(void __iomem *ControllerBaseAddress,
- dma_addr_t CommandMailboxDMA)
-{
- dma_addr_writeql(CommandMailboxDMA,
- ControllerBaseAddress +
- DAC960_LP_CommandMailboxBusAddressOffset);
-}
-
-static inline DAC960_V2_CommandIdentifier_T
-DAC960_LP_ReadCommandIdentifier(void __iomem *ControllerBaseAddress)
-{
- return readw(ControllerBaseAddress + DAC960_LP_CommandStatusOffset);
-}
-
-static inline DAC960_V2_CommandStatus_T
-DAC960_LP_ReadCommandStatus(void __iomem *ControllerBaseAddress)
-{
- return readw(ControllerBaseAddress + DAC960_LP_CommandStatusOffset + 2);
-}
-
-static inline bool
-DAC960_LP_ReadErrorStatus(void __iomem *ControllerBaseAddress,
- unsigned char *ErrorStatus,
- unsigned char *Parameter0,
- unsigned char *Parameter1)
-{
- DAC960_LP_ErrorStatusRegister_T ErrorStatusRegister;
- ErrorStatusRegister.All =
- readb(ControllerBaseAddress + DAC960_LP_ErrorStatusRegisterOffset);
- if (!ErrorStatusRegister.Bits.ErrorStatusPending) return false;
- ErrorStatusRegister.Bits.ErrorStatusPending = false;
- *ErrorStatus = ErrorStatusRegister.All;
- *Parameter0 =
- readb(ControllerBaseAddress + DAC960_LP_CommandMailboxBusAddressOffset + 0);
- *Parameter1 =
- readb(ControllerBaseAddress + DAC960_LP_CommandMailboxBusAddressOffset + 1);
- writeb(0xFF, ControllerBaseAddress + DAC960_LP_ErrorStatusRegisterOffset);
- return true;
-}
-
-
-/*
- Define the DAC960 LA Series Controller Interface Register Offsets.
-*/
-
-#define DAC960_LA_RegisterWindowSize 0x80
-
-typedef enum
-{
- DAC960_LA_InboundDoorBellRegisterOffset = 0x60,
- DAC960_LA_OutboundDoorBellRegisterOffset = 0x61,
- DAC960_LA_InterruptMaskRegisterOffset = 0x34,
- DAC960_LA_CommandOpcodeRegisterOffset = 0x50,
- DAC960_LA_CommandIdentifierRegisterOffset = 0x51,
- DAC960_LA_MailboxRegister2Offset = 0x52,
- DAC960_LA_MailboxRegister3Offset = 0x53,
- DAC960_LA_MailboxRegister4Offset = 0x54,
- DAC960_LA_MailboxRegister5Offset = 0x55,
- DAC960_LA_MailboxRegister6Offset = 0x56,
- DAC960_LA_MailboxRegister7Offset = 0x57,
- DAC960_LA_MailboxRegister8Offset = 0x58,
- DAC960_LA_MailboxRegister9Offset = 0x59,
- DAC960_LA_MailboxRegister10Offset = 0x5A,
- DAC960_LA_MailboxRegister11Offset = 0x5B,
- DAC960_LA_MailboxRegister12Offset = 0x5C,
- DAC960_LA_StatusCommandIdentifierRegOffset = 0x5D,
- DAC960_LA_StatusRegisterOffset = 0x5E,
- DAC960_LA_ErrorStatusRegisterOffset = 0x63
-}
-DAC960_LA_RegisterOffsets_T;
-
-
-/*
- Define the structure of the DAC960 LA Series Inbound Door Bell Register.
-*/
-
-typedef union DAC960_LA_InboundDoorBellRegister
-{
- unsigned char All;
- struct {
- bool HardwareMailboxNewCommand:1; /* Bit 0 */
- bool AcknowledgeHardwareMailboxStatus:1; /* Bit 1 */
- bool GenerateInterrupt:1; /* Bit 2 */
- bool ControllerReset:1; /* Bit 3 */
- bool MemoryMailboxNewCommand:1; /* Bit 4 */
- unsigned char :3; /* Bits 5-7 */
- } Write;
- struct {
- bool HardwareMailboxEmpty:1; /* Bit 0 */
- bool InitializationNotInProgress:1; /* Bit 1 */
- unsigned char :6; /* Bits 2-7 */
- } Read;
-}
-DAC960_LA_InboundDoorBellRegister_T;
-
-
-/*
- Define the structure of the DAC960 LA Series Outbound Door Bell Register.
-*/
-
-typedef union DAC960_LA_OutboundDoorBellRegister
-{
- unsigned char All;
- struct {
- bool AcknowledgeHardwareMailboxInterrupt:1; /* Bit 0 */
- bool AcknowledgeMemoryMailboxInterrupt:1; /* Bit 1 */
- unsigned char :6; /* Bits 2-7 */
- } Write;
- struct {
- bool HardwareMailboxStatusAvailable:1; /* Bit 0 */
- bool MemoryMailboxStatusAvailable:1; /* Bit 1 */
- unsigned char :6; /* Bits 2-7 */
- } Read;
-}
-DAC960_LA_OutboundDoorBellRegister_T;
-
-
-/*
- Define the structure of the DAC960 LA Series Interrupt Mask Register.
-*/
-
-typedef union DAC960_LA_InterruptMaskRegister
-{
- unsigned char All;
- struct {
- unsigned char :2; /* Bits 0-1 */
- bool DisableInterrupts:1; /* Bit 2 */
- unsigned char :5; /* Bits 3-7 */
- } Bits;
-}
-DAC960_LA_InterruptMaskRegister_T;
-
-
-/*
- Define the structure of the DAC960 LA Series Error Status Register.
-*/
-
-typedef union DAC960_LA_ErrorStatusRegister
-{
- unsigned char All;
- struct {
- unsigned int :2; /* Bits 0-1 */
- bool ErrorStatusPending:1; /* Bit 2 */
- unsigned int :5; /* Bits 3-7 */
- } Bits;
-}
-DAC960_LA_ErrorStatusRegister_T;
-
-
-/*
- Define inline functions to provide an abstraction for reading and writing the
- DAC960 LA Series Controller Interface Registers.
-*/
-
-static inline
-void DAC960_LA_HardwareMailboxNewCommand(void __iomem *ControllerBaseAddress)
-{
- DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.HardwareMailboxNewCommand = true;
- writeb(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_LA_InboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_LA_AcknowledgeHardwareMailboxStatus(void __iomem *ControllerBaseAddress)
-{
- DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.AcknowledgeHardwareMailboxStatus = true;
- writeb(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_LA_InboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_LA_GenerateInterrupt(void __iomem *ControllerBaseAddress)
-{
- DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.GenerateInterrupt = true;
- writeb(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_LA_InboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_LA_ControllerReset(void __iomem *ControllerBaseAddress)
-{
- DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.ControllerReset = true;
- writeb(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_LA_InboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_LA_MemoryMailboxNewCommand(void __iomem *ControllerBaseAddress)
-{
- DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.MemoryMailboxNewCommand = true;
- writeb(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_LA_InboundDoorBellRegisterOffset);
-}
-
-static inline
-bool DAC960_LA_HardwareMailboxFullP(void __iomem *ControllerBaseAddress)
-{
- DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All =
- readb(ControllerBaseAddress + DAC960_LA_InboundDoorBellRegisterOffset);
- return !InboundDoorBellRegister.Read.HardwareMailboxEmpty;
-}
-
-static inline
-bool DAC960_LA_InitializationInProgressP(void __iomem *ControllerBaseAddress)
-{
- DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All =
- readb(ControllerBaseAddress + DAC960_LA_InboundDoorBellRegisterOffset);
- return !InboundDoorBellRegister.Read.InitializationNotInProgress;
-}
-
-static inline
-void DAC960_LA_AcknowledgeHardwareMailboxInterrupt(void __iomem *ControllerBaseAddress)
-{
- DAC960_LA_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All = 0;
- OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true;
- writeb(OutboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_LA_OutboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_LA_AcknowledgeMemoryMailboxInterrupt(void __iomem *ControllerBaseAddress)
-{
- DAC960_LA_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All = 0;
- OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true;
- writeb(OutboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_LA_OutboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_LA_AcknowledgeInterrupt(void __iomem *ControllerBaseAddress)
-{
- DAC960_LA_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All = 0;
- OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true;
- OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true;
- writeb(OutboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_LA_OutboundDoorBellRegisterOffset);
-}
-
-static inline
-bool DAC960_LA_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress)
-{
- DAC960_LA_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All =
- readb(ControllerBaseAddress + DAC960_LA_OutboundDoorBellRegisterOffset);
- return OutboundDoorBellRegister.Read.HardwareMailboxStatusAvailable;
-}
-
-static inline
-bool DAC960_LA_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress)
-{
- DAC960_LA_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All =
- readb(ControllerBaseAddress + DAC960_LA_OutboundDoorBellRegisterOffset);
- return OutboundDoorBellRegister.Read.MemoryMailboxStatusAvailable;
-}
-
-static inline
-void DAC960_LA_EnableInterrupts(void __iomem *ControllerBaseAddress)
-{
- DAC960_LA_InterruptMaskRegister_T InterruptMaskRegister;
- InterruptMaskRegister.All = 0xFF;
- InterruptMaskRegister.Bits.DisableInterrupts = false;
- writeb(InterruptMaskRegister.All,
- ControllerBaseAddress + DAC960_LA_InterruptMaskRegisterOffset);
-}
-
-static inline
-void DAC960_LA_DisableInterrupts(void __iomem *ControllerBaseAddress)
-{
- DAC960_LA_InterruptMaskRegister_T InterruptMaskRegister;
- InterruptMaskRegister.All = 0xFF;
- InterruptMaskRegister.Bits.DisableInterrupts = true;
- writeb(InterruptMaskRegister.All,
- ControllerBaseAddress + DAC960_LA_InterruptMaskRegisterOffset);
-}
-
-static inline
-bool DAC960_LA_InterruptsEnabledP(void __iomem *ControllerBaseAddress)
-{
- DAC960_LA_InterruptMaskRegister_T InterruptMaskRegister;
- InterruptMaskRegister.All =
- readb(ControllerBaseAddress + DAC960_LA_InterruptMaskRegisterOffset);
- return !InterruptMaskRegister.Bits.DisableInterrupts;
-}
-
-static inline
-void DAC960_LA_WriteCommandMailbox(DAC960_V1_CommandMailbox_T
- *MemoryCommandMailbox,
- DAC960_V1_CommandMailbox_T
- *CommandMailbox)
-{
- MemoryCommandMailbox->Words[1] = CommandMailbox->Words[1];
- MemoryCommandMailbox->Words[2] = CommandMailbox->Words[2];
- MemoryCommandMailbox->Words[3] = CommandMailbox->Words[3];
- wmb();
- MemoryCommandMailbox->Words[0] = CommandMailbox->Words[0];
- mb();
-}
-
-static inline
-void DAC960_LA_WriteHardwareMailbox(void __iomem *ControllerBaseAddress,
- DAC960_V1_CommandMailbox_T *CommandMailbox)
-{
- writel(CommandMailbox->Words[0],
- ControllerBaseAddress + DAC960_LA_CommandOpcodeRegisterOffset);
- writel(CommandMailbox->Words[1],
- ControllerBaseAddress + DAC960_LA_MailboxRegister4Offset);
- writel(CommandMailbox->Words[2],
- ControllerBaseAddress + DAC960_LA_MailboxRegister8Offset);
- writeb(CommandMailbox->Bytes[12],
- ControllerBaseAddress + DAC960_LA_MailboxRegister12Offset);
-}
-
-static inline DAC960_V1_CommandIdentifier_T
-DAC960_LA_ReadStatusCommandIdentifier(void __iomem *ControllerBaseAddress)
-{
- return readb(ControllerBaseAddress
- + DAC960_LA_StatusCommandIdentifierRegOffset);
-}
-
-static inline DAC960_V1_CommandStatus_T
-DAC960_LA_ReadStatusRegister(void __iomem *ControllerBaseAddress)
-{
- return readw(ControllerBaseAddress + DAC960_LA_StatusRegisterOffset);
-}
-
-static inline bool
-DAC960_LA_ReadErrorStatus(void __iomem *ControllerBaseAddress,
- unsigned char *ErrorStatus,
- unsigned char *Parameter0,
- unsigned char *Parameter1)
-{
- DAC960_LA_ErrorStatusRegister_T ErrorStatusRegister;
- ErrorStatusRegister.All =
- readb(ControllerBaseAddress + DAC960_LA_ErrorStatusRegisterOffset);
- if (!ErrorStatusRegister.Bits.ErrorStatusPending) return false;
- ErrorStatusRegister.Bits.ErrorStatusPending = false;
- *ErrorStatus = ErrorStatusRegister.All;
- *Parameter0 =
- readb(ControllerBaseAddress + DAC960_LA_CommandOpcodeRegisterOffset);
- *Parameter1 =
- readb(ControllerBaseAddress + DAC960_LA_CommandIdentifierRegisterOffset);
- writeb(0xFF, ControllerBaseAddress + DAC960_LA_ErrorStatusRegisterOffset);
- return true;
-}
-
-/*
- Define the DAC960 PG Series Controller Interface Register Offsets.
-*/
-
-#define DAC960_PG_RegisterWindowSize 0x2000
-
-typedef enum
-{
- DAC960_PG_InboundDoorBellRegisterOffset = 0x0020,
- DAC960_PG_OutboundDoorBellRegisterOffset = 0x002C,
- DAC960_PG_InterruptMaskRegisterOffset = 0x0034,
- DAC960_PG_CommandOpcodeRegisterOffset = 0x1000,
- DAC960_PG_CommandIdentifierRegisterOffset = 0x1001,
- DAC960_PG_MailboxRegister2Offset = 0x1002,
- DAC960_PG_MailboxRegister3Offset = 0x1003,
- DAC960_PG_MailboxRegister4Offset = 0x1004,
- DAC960_PG_MailboxRegister5Offset = 0x1005,
- DAC960_PG_MailboxRegister6Offset = 0x1006,
- DAC960_PG_MailboxRegister7Offset = 0x1007,
- DAC960_PG_MailboxRegister8Offset = 0x1008,
- DAC960_PG_MailboxRegister9Offset = 0x1009,
- DAC960_PG_MailboxRegister10Offset = 0x100A,
- DAC960_PG_MailboxRegister11Offset = 0x100B,
- DAC960_PG_MailboxRegister12Offset = 0x100C,
- DAC960_PG_StatusCommandIdentifierRegOffset = 0x1018,
- DAC960_PG_StatusRegisterOffset = 0x101A,
- DAC960_PG_ErrorStatusRegisterOffset = 0x103F
-}
-DAC960_PG_RegisterOffsets_T;
-
-
-/*
- Define the structure of the DAC960 PG Series Inbound Door Bell Register.
-*/
-
-typedef union DAC960_PG_InboundDoorBellRegister
-{
- unsigned int All;
- struct {
- bool HardwareMailboxNewCommand:1; /* Bit 0 */
- bool AcknowledgeHardwareMailboxStatus:1; /* Bit 1 */
- bool GenerateInterrupt:1; /* Bit 2 */
- bool ControllerReset:1; /* Bit 3 */
- bool MemoryMailboxNewCommand:1; /* Bit 4 */
- unsigned int :27; /* Bits 5-31 */
- } Write;
- struct {
- bool HardwareMailboxFull:1; /* Bit 0 */
- bool InitializationInProgress:1; /* Bit 1 */
- unsigned int :30; /* Bits 2-31 */
- } Read;
-}
-DAC960_PG_InboundDoorBellRegister_T;
-
-
-/*
- Define the structure of the DAC960 PG Series Outbound Door Bell Register.
-*/
-
-typedef union DAC960_PG_OutboundDoorBellRegister
-{
- unsigned int All;
- struct {
- bool AcknowledgeHardwareMailboxInterrupt:1; /* Bit 0 */
- bool AcknowledgeMemoryMailboxInterrupt:1; /* Bit 1 */
- unsigned int :30; /* Bits 2-31 */
- } Write;
- struct {
- bool HardwareMailboxStatusAvailable:1; /* Bit 0 */
- bool MemoryMailboxStatusAvailable:1; /* Bit 1 */
- unsigned int :30; /* Bits 2-31 */
- } Read;
-}
-DAC960_PG_OutboundDoorBellRegister_T;
-
-
-/*
- Define the structure of the DAC960 PG Series Interrupt Mask Register.
-*/
-
-typedef union DAC960_PG_InterruptMaskRegister
-{
- unsigned int All;
- struct {
- unsigned int MessageUnitInterruptMask1:2; /* Bits 0-1 */
- bool DisableInterrupts:1; /* Bit 2 */
- unsigned int MessageUnitInterruptMask2:5; /* Bits 3-7 */
- unsigned int Reserved0:24; /* Bits 8-31 */
- } Bits;
-}
-DAC960_PG_InterruptMaskRegister_T;
-
-
-/*
- Define the structure of the DAC960 PG Series Error Status Register.
-*/
-
-typedef union DAC960_PG_ErrorStatusRegister
-{
- unsigned char All;
- struct {
- unsigned int :2; /* Bits 0-1 */
- bool ErrorStatusPending:1; /* Bit 2 */
- unsigned int :5; /* Bits 3-7 */
- } Bits;
-}
-DAC960_PG_ErrorStatusRegister_T;
-
-
-/*
- Define inline functions to provide an abstraction for reading and writing the
- DAC960 PG Series Controller Interface Registers.
-*/
-
-static inline
-void DAC960_PG_HardwareMailboxNewCommand(void __iomem *ControllerBaseAddress)
-{
- DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.HardwareMailboxNewCommand = true;
- writel(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_PG_InboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_PG_AcknowledgeHardwareMailboxStatus(void __iomem *ControllerBaseAddress)
-{
- DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.AcknowledgeHardwareMailboxStatus = true;
- writel(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_PG_InboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_PG_GenerateInterrupt(void __iomem *ControllerBaseAddress)
-{
- DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.GenerateInterrupt = true;
- writel(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_PG_InboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_PG_ControllerReset(void __iomem *ControllerBaseAddress)
-{
- DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.ControllerReset = true;
- writel(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_PG_InboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_PG_MemoryMailboxNewCommand(void __iomem *ControllerBaseAddress)
-{
- DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.MemoryMailboxNewCommand = true;
- writel(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_PG_InboundDoorBellRegisterOffset);
-}
-
-static inline
-bool DAC960_PG_HardwareMailboxFullP(void __iomem *ControllerBaseAddress)
-{
- DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All =
- readl(ControllerBaseAddress + DAC960_PG_InboundDoorBellRegisterOffset);
- return InboundDoorBellRegister.Read.HardwareMailboxFull;
-}
-
-static inline
-bool DAC960_PG_InitializationInProgressP(void __iomem *ControllerBaseAddress)
-{
- DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All =
- readl(ControllerBaseAddress + DAC960_PG_InboundDoorBellRegisterOffset);
- return InboundDoorBellRegister.Read.InitializationInProgress;
-}
-
-static inline
-void DAC960_PG_AcknowledgeHardwareMailboxInterrupt(void __iomem *ControllerBaseAddress)
-{
- DAC960_PG_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All = 0;
- OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true;
- writel(OutboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_PG_OutboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_PG_AcknowledgeMemoryMailboxInterrupt(void __iomem *ControllerBaseAddress)
-{
- DAC960_PG_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All = 0;
- OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true;
- writel(OutboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_PG_OutboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_PG_AcknowledgeInterrupt(void __iomem *ControllerBaseAddress)
-{
- DAC960_PG_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All = 0;
- OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true;
- OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true;
- writel(OutboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_PG_OutboundDoorBellRegisterOffset);
-}
-
-static inline
-bool DAC960_PG_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress)
-{
- DAC960_PG_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All =
- readl(ControllerBaseAddress + DAC960_PG_OutboundDoorBellRegisterOffset);
- return OutboundDoorBellRegister.Read.HardwareMailboxStatusAvailable;
-}
-
-static inline
-bool DAC960_PG_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress)
-{
- DAC960_PG_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All =
- readl(ControllerBaseAddress + DAC960_PG_OutboundDoorBellRegisterOffset);
- return OutboundDoorBellRegister.Read.MemoryMailboxStatusAvailable;
-}
-
-static inline
-void DAC960_PG_EnableInterrupts(void __iomem *ControllerBaseAddress)
-{
- DAC960_PG_InterruptMaskRegister_T InterruptMaskRegister;
- InterruptMaskRegister.All = 0;
- InterruptMaskRegister.Bits.MessageUnitInterruptMask1 = 0x3;
- InterruptMaskRegister.Bits.DisableInterrupts = false;
- InterruptMaskRegister.Bits.MessageUnitInterruptMask2 = 0x1F;
- writel(InterruptMaskRegister.All,
- ControllerBaseAddress + DAC960_PG_InterruptMaskRegisterOffset);
-}
-
-static inline
-void DAC960_PG_DisableInterrupts(void __iomem *ControllerBaseAddress)
-{
- DAC960_PG_InterruptMaskRegister_T InterruptMaskRegister;
- InterruptMaskRegister.All = 0;
- InterruptMaskRegister.Bits.MessageUnitInterruptMask1 = 0x3;
- InterruptMaskRegister.Bits.DisableInterrupts = true;
- InterruptMaskRegister.Bits.MessageUnitInterruptMask2 = 0x1F;
- writel(InterruptMaskRegister.All,
- ControllerBaseAddress + DAC960_PG_InterruptMaskRegisterOffset);
-}
-
-static inline
-bool DAC960_PG_InterruptsEnabledP(void __iomem *ControllerBaseAddress)
-{
- DAC960_PG_InterruptMaskRegister_T InterruptMaskRegister;
- InterruptMaskRegister.All =
- readl(ControllerBaseAddress + DAC960_PG_InterruptMaskRegisterOffset);
- return !InterruptMaskRegister.Bits.DisableInterrupts;
-}
-
-static inline
-void DAC960_PG_WriteCommandMailbox(DAC960_V1_CommandMailbox_T
- *MemoryCommandMailbox,
- DAC960_V1_CommandMailbox_T
- *CommandMailbox)
-{
- MemoryCommandMailbox->Words[1] = CommandMailbox->Words[1];
- MemoryCommandMailbox->Words[2] = CommandMailbox->Words[2];
- MemoryCommandMailbox->Words[3] = CommandMailbox->Words[3];
- wmb();
- MemoryCommandMailbox->Words[0] = CommandMailbox->Words[0];
- mb();
-}
-
-static inline
-void DAC960_PG_WriteHardwareMailbox(void __iomem *ControllerBaseAddress,
- DAC960_V1_CommandMailbox_T *CommandMailbox)
-{
- writel(CommandMailbox->Words[0],
- ControllerBaseAddress + DAC960_PG_CommandOpcodeRegisterOffset);
- writel(CommandMailbox->Words[1],
- ControllerBaseAddress + DAC960_PG_MailboxRegister4Offset);
- writel(CommandMailbox->Words[2],
- ControllerBaseAddress + DAC960_PG_MailboxRegister8Offset);
- writeb(CommandMailbox->Bytes[12],
- ControllerBaseAddress + DAC960_PG_MailboxRegister12Offset);
-}
-
-static inline DAC960_V1_CommandIdentifier_T
-DAC960_PG_ReadStatusCommandIdentifier(void __iomem *ControllerBaseAddress)
-{
- return readb(ControllerBaseAddress
- + DAC960_PG_StatusCommandIdentifierRegOffset);
-}
-
-static inline DAC960_V1_CommandStatus_T
-DAC960_PG_ReadStatusRegister(void __iomem *ControllerBaseAddress)
-{
- return readw(ControllerBaseAddress + DAC960_PG_StatusRegisterOffset);
-}
-
-static inline bool
-DAC960_PG_ReadErrorStatus(void __iomem *ControllerBaseAddress,
- unsigned char *ErrorStatus,
- unsigned char *Parameter0,
- unsigned char *Parameter1)
-{
- DAC960_PG_ErrorStatusRegister_T ErrorStatusRegister;
- ErrorStatusRegister.All =
- readb(ControllerBaseAddress + DAC960_PG_ErrorStatusRegisterOffset);
- if (!ErrorStatusRegister.Bits.ErrorStatusPending) return false;
- ErrorStatusRegister.Bits.ErrorStatusPending = false;
- *ErrorStatus = ErrorStatusRegister.All;
- *Parameter0 =
- readb(ControllerBaseAddress + DAC960_PG_CommandOpcodeRegisterOffset);
- *Parameter1 =
- readb(ControllerBaseAddress + DAC960_PG_CommandIdentifierRegisterOffset);
- writeb(0, ControllerBaseAddress + DAC960_PG_ErrorStatusRegisterOffset);
- return true;
-}
-
-/*
- Define the DAC960 PD Series Controller Interface Register Offsets.
-*/
-
-#define DAC960_PD_RegisterWindowSize 0x80
-
-typedef enum
-{
- DAC960_PD_CommandOpcodeRegisterOffset = 0x00,
- DAC960_PD_CommandIdentifierRegisterOffset = 0x01,
- DAC960_PD_MailboxRegister2Offset = 0x02,
- DAC960_PD_MailboxRegister3Offset = 0x03,
- DAC960_PD_MailboxRegister4Offset = 0x04,
- DAC960_PD_MailboxRegister5Offset = 0x05,
- DAC960_PD_MailboxRegister6Offset = 0x06,
- DAC960_PD_MailboxRegister7Offset = 0x07,
- DAC960_PD_MailboxRegister8Offset = 0x08,
- DAC960_PD_MailboxRegister9Offset = 0x09,
- DAC960_PD_MailboxRegister10Offset = 0x0A,
- DAC960_PD_MailboxRegister11Offset = 0x0B,
- DAC960_PD_MailboxRegister12Offset = 0x0C,
- DAC960_PD_StatusCommandIdentifierRegOffset = 0x0D,
- DAC960_PD_StatusRegisterOffset = 0x0E,
- DAC960_PD_ErrorStatusRegisterOffset = 0x3F,
- DAC960_PD_InboundDoorBellRegisterOffset = 0x40,
- DAC960_PD_OutboundDoorBellRegisterOffset = 0x41,
- DAC960_PD_InterruptEnableRegisterOffset = 0x43
-}
-DAC960_PD_RegisterOffsets_T;
-
-
-/*
- Define the structure of the DAC960 PD Series Inbound Door Bell Register.
-*/
-
-typedef union DAC960_PD_InboundDoorBellRegister
-{
- unsigned char All;
- struct {
- bool NewCommand:1; /* Bit 0 */
- bool AcknowledgeStatus:1; /* Bit 1 */
- bool GenerateInterrupt:1; /* Bit 2 */
- bool ControllerReset:1; /* Bit 3 */
- unsigned char :4; /* Bits 4-7 */
- } Write;
- struct {
- bool MailboxFull:1; /* Bit 0 */
- bool InitializationInProgress:1; /* Bit 1 */
- unsigned char :6; /* Bits 2-7 */
- } Read;
-}
-DAC960_PD_InboundDoorBellRegister_T;
-
-
-/*
- Define the structure of the DAC960 PD Series Outbound Door Bell Register.
-*/
-
-typedef union DAC960_PD_OutboundDoorBellRegister
-{
- unsigned char All;
- struct {
- bool AcknowledgeInterrupt:1; /* Bit 0 */
- unsigned char :7; /* Bits 1-7 */
- } Write;
- struct {
- bool StatusAvailable:1; /* Bit 0 */
- unsigned char :7; /* Bits 1-7 */
- } Read;
-}
-DAC960_PD_OutboundDoorBellRegister_T;
-
-
-/*
- Define the structure of the DAC960 PD Series Interrupt Enable Register.
-*/
-
-typedef union DAC960_PD_InterruptEnableRegister
-{
- unsigned char All;
- struct {
- bool EnableInterrupts:1; /* Bit 0 */
- unsigned char :7; /* Bits 1-7 */
- } Bits;
-}
-DAC960_PD_InterruptEnableRegister_T;
-
-
-/*
- Define the structure of the DAC960 PD Series Error Status Register.
-*/
-
-typedef union DAC960_PD_ErrorStatusRegister
-{
- unsigned char All;
- struct {
- unsigned int :2; /* Bits 0-1 */
- bool ErrorStatusPending:1; /* Bit 2 */
- unsigned int :5; /* Bits 3-7 */
- } Bits;
-}
-DAC960_PD_ErrorStatusRegister_T;
-
-
-/*
- Define inline functions to provide an abstraction for reading and writing the
- DAC960 PD Series Controller Interface Registers.
-*/
-
-static inline
-void DAC960_PD_NewCommand(void __iomem *ControllerBaseAddress)
-{
- DAC960_PD_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.NewCommand = true;
- writeb(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_PD_InboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_PD_AcknowledgeStatus(void __iomem *ControllerBaseAddress)
-{
- DAC960_PD_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.AcknowledgeStatus = true;
- writeb(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_PD_InboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_PD_GenerateInterrupt(void __iomem *ControllerBaseAddress)
-{
- DAC960_PD_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.GenerateInterrupt = true;
- writeb(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_PD_InboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_PD_ControllerReset(void __iomem *ControllerBaseAddress)
-{
- DAC960_PD_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All = 0;
- InboundDoorBellRegister.Write.ControllerReset = true;
- writeb(InboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_PD_InboundDoorBellRegisterOffset);
-}
-
-static inline
-bool DAC960_PD_MailboxFullP(void __iomem *ControllerBaseAddress)
-{
- DAC960_PD_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All =
- readb(ControllerBaseAddress + DAC960_PD_InboundDoorBellRegisterOffset);
- return InboundDoorBellRegister.Read.MailboxFull;
-}
-
-static inline
-bool DAC960_PD_InitializationInProgressP(void __iomem *ControllerBaseAddress)
-{
- DAC960_PD_InboundDoorBellRegister_T InboundDoorBellRegister;
- InboundDoorBellRegister.All =
- readb(ControllerBaseAddress + DAC960_PD_InboundDoorBellRegisterOffset);
- return InboundDoorBellRegister.Read.InitializationInProgress;
-}
-
-static inline
-void DAC960_PD_AcknowledgeInterrupt(void __iomem *ControllerBaseAddress)
-{
- DAC960_PD_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All = 0;
- OutboundDoorBellRegister.Write.AcknowledgeInterrupt = true;
- writeb(OutboundDoorBellRegister.All,
- ControllerBaseAddress + DAC960_PD_OutboundDoorBellRegisterOffset);
-}
-
-static inline
-bool DAC960_PD_StatusAvailableP(void __iomem *ControllerBaseAddress)
-{
- DAC960_PD_OutboundDoorBellRegister_T OutboundDoorBellRegister;
- OutboundDoorBellRegister.All =
- readb(ControllerBaseAddress + DAC960_PD_OutboundDoorBellRegisterOffset);
- return OutboundDoorBellRegister.Read.StatusAvailable;
-}
-
-static inline
-void DAC960_PD_EnableInterrupts(void __iomem *ControllerBaseAddress)
-{
- DAC960_PD_InterruptEnableRegister_T InterruptEnableRegister;
- InterruptEnableRegister.All = 0;
- InterruptEnableRegister.Bits.EnableInterrupts = true;
- writeb(InterruptEnableRegister.All,
- ControllerBaseAddress + DAC960_PD_InterruptEnableRegisterOffset);
-}
-
-static inline
-void DAC960_PD_DisableInterrupts(void __iomem *ControllerBaseAddress)
-{
- DAC960_PD_InterruptEnableRegister_T InterruptEnableRegister;
- InterruptEnableRegister.All = 0;
- InterruptEnableRegister.Bits.EnableInterrupts = false;
- writeb(InterruptEnableRegister.All,
- ControllerBaseAddress + DAC960_PD_InterruptEnableRegisterOffset);
-}
-
-static inline
-bool DAC960_PD_InterruptsEnabledP(void __iomem *ControllerBaseAddress)
-{
- DAC960_PD_InterruptEnableRegister_T InterruptEnableRegister;
- InterruptEnableRegister.All =
- readb(ControllerBaseAddress + DAC960_PD_InterruptEnableRegisterOffset);
- return InterruptEnableRegister.Bits.EnableInterrupts;
-}
-
-static inline
-void DAC960_PD_WriteCommandMailbox(void __iomem *ControllerBaseAddress,
- DAC960_V1_CommandMailbox_T *CommandMailbox)
-{
- writel(CommandMailbox->Words[0],
- ControllerBaseAddress + DAC960_PD_CommandOpcodeRegisterOffset);
- writel(CommandMailbox->Words[1],
- ControllerBaseAddress + DAC960_PD_MailboxRegister4Offset);
- writel(CommandMailbox->Words[2],
- ControllerBaseAddress + DAC960_PD_MailboxRegister8Offset);
- writeb(CommandMailbox->Bytes[12],
- ControllerBaseAddress + DAC960_PD_MailboxRegister12Offset);
-}
-
-static inline DAC960_V1_CommandIdentifier_T
-DAC960_PD_ReadStatusCommandIdentifier(void __iomem *ControllerBaseAddress)
-{
- return readb(ControllerBaseAddress
- + DAC960_PD_StatusCommandIdentifierRegOffset);
-}
-
-static inline DAC960_V1_CommandStatus_T
-DAC960_PD_ReadStatusRegister(void __iomem *ControllerBaseAddress)
-{
- return readw(ControllerBaseAddress + DAC960_PD_StatusRegisterOffset);
-}
-
-static inline bool
-DAC960_PD_ReadErrorStatus(void __iomem *ControllerBaseAddress,
- unsigned char *ErrorStatus,
- unsigned char *Parameter0,
- unsigned char *Parameter1)
-{
- DAC960_PD_ErrorStatusRegister_T ErrorStatusRegister;
- ErrorStatusRegister.All =
- readb(ControllerBaseAddress + DAC960_PD_ErrorStatusRegisterOffset);
- if (!ErrorStatusRegister.Bits.ErrorStatusPending) return false;
- ErrorStatusRegister.Bits.ErrorStatusPending = false;
- *ErrorStatus = ErrorStatusRegister.All;
- *Parameter0 =
- readb(ControllerBaseAddress + DAC960_PD_CommandOpcodeRegisterOffset);
- *Parameter1 =
- readb(ControllerBaseAddress + DAC960_PD_CommandIdentifierRegisterOffset);
- writeb(0, ControllerBaseAddress + DAC960_PD_ErrorStatusRegisterOffset);
- return true;
-}
-
-static inline void DAC960_P_To_PD_TranslateEnquiry(void *Enquiry)
-{
- memcpy(Enquiry + 132, Enquiry + 36, 64);
- memset(Enquiry + 36, 0, 96);
-}
-
-static inline void DAC960_P_To_PD_TranslateDeviceState(void *DeviceState)
-{
- memcpy(DeviceState + 2, DeviceState + 3, 1);
- memmove(DeviceState + 4, DeviceState + 5, 2);
- memmove(DeviceState + 6, DeviceState + 8, 4);
-}
-
-static inline
-void DAC960_PD_To_P_TranslateReadWriteCommand(DAC960_V1_CommandMailbox_T
- *CommandMailbox)
-{
- int LogicalDriveNumber = CommandMailbox->Type5.LD.LogicalDriveNumber;
- CommandMailbox->Bytes[3] &= 0x7;
- CommandMailbox->Bytes[3] |= CommandMailbox->Bytes[7] << 6;
- CommandMailbox->Bytes[7] = LogicalDriveNumber;
-}
-
-static inline
-void DAC960_P_To_PD_TranslateReadWriteCommand(DAC960_V1_CommandMailbox_T
- *CommandMailbox)
-{
- int LogicalDriveNumber = CommandMailbox->Bytes[7];
- CommandMailbox->Bytes[7] = CommandMailbox->Bytes[3] >> 6;
- CommandMailbox->Bytes[3] &= 0x7;
- CommandMailbox->Bytes[3] |= LogicalDriveNumber << 3;
-}
-
-
-/*
- Define prototypes for the forward referenced DAC960 Driver Internal Functions.
-*/
-
-static void DAC960_FinalizeController(DAC960_Controller_T *);
-static void DAC960_V1_QueueReadWriteCommand(DAC960_Command_T *);
-static void DAC960_V2_QueueReadWriteCommand(DAC960_Command_T *);
-static void DAC960_RequestFunction(struct request_queue *);
-static irqreturn_t DAC960_BA_InterruptHandler(int, void *);
-static irqreturn_t DAC960_LP_InterruptHandler(int, void *);
-static irqreturn_t DAC960_LA_InterruptHandler(int, void *);
-static irqreturn_t DAC960_PG_InterruptHandler(int, void *);
-static irqreturn_t DAC960_PD_InterruptHandler(int, void *);
-static irqreturn_t DAC960_P_InterruptHandler(int, void *);
-static void DAC960_V1_QueueMonitoringCommand(DAC960_Command_T *);
-static void DAC960_V2_QueueMonitoringCommand(DAC960_Command_T *);
-static void DAC960_MonitoringTimerFunction(struct timer_list *);
-static void DAC960_Message(DAC960_MessageLevel_T, unsigned char *,
- DAC960_Controller_T *, ...);
-static void DAC960_CreateProcEntries(DAC960_Controller_T *);
-static void DAC960_DestroyProcEntries(DAC960_Controller_T *);
-
-#endif /* DAC960_DriverVersion */
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index d4913516823f..20bb4bfa4be6 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -121,18 +121,6 @@ source "drivers/block/mtip32xx/Kconfig"
source "drivers/block/zram/Kconfig"
-config BLK_DEV_DAC960
- tristate "Mylex DAC960/DAC1100 PCI RAID Controller support"
- depends on PCI
- help
- This driver adds support for the Mylex DAC960, AcceleRAID, and
- eXtremeRAID PCI RAID controllers. See the file
- <file:Documentation/blockdev/README.DAC960> for further information
- about this driver.
-
- To compile this driver as a module, choose M here: the
- module will be called DAC960.
-
config BLK_DEV_UMEM
tristate "Micro Memory MM5415 Battery Backed RAM support"
depends on PCI
@@ -461,7 +449,6 @@ config BLK_DEV_RBD
select LIBCRC32C
select CRYPTO_AES
select CRYPTO
- default n
help
Say Y here if you want include the Rados block device, which stripes
a block device over objects stored in the Ceph distributed object
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index 8566b188368b..a53cc1e3a2d3 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -16,7 +16,6 @@ obj-$(CONFIG_ATARI_FLOPPY) += ataflop.o
obj-$(CONFIG_AMIGA_Z2RAM) += z2ram.o
obj-$(CONFIG_BLK_DEV_RAM) += brd.o
obj-$(CONFIG_BLK_DEV_LOOP) += loop.o
-obj-$(CONFIG_BLK_DEV_DAC960) += DAC960.o
obj-$(CONFIG_XILINX_SYSACE) += xsysace.o
obj-$(CONFIG_CDROM_PKTCDVD) += pktcdvd.o
obj-$(CONFIG_SUNVDC) += sunvdc.o
diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c
index 3aaf6af3ec23..bf996bd44cfc 100644
--- a/drivers/block/amiflop.c
+++ b/drivers/block/amiflop.c
@@ -61,10 +61,8 @@
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/mutex.h>
-#include <linux/amifdreg.h>
-#include <linux/amifd.h>
#include <linux/fs.h>
-#include <linux/blkdev.h>
+#include <linux/blk-mq.h>
#include <linux/elevator.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
@@ -87,6 +85,126 @@
*/
/*
+ * CIAAPRA bits (read only)
+ */
+
+#define DSKRDY (0x1<<5) /* disk ready when low */
+#define DSKTRACK0 (0x1<<4) /* head at track zero when low */
+#define DSKPROT (0x1<<3) /* disk protected when low */
+#define DSKCHANGE (0x1<<2) /* low when disk removed */
+
+/*
+ * CIAAPRB bits (read/write)
+ */
+
+#define DSKMOTOR (0x1<<7) /* motor on when low */
+#define DSKSEL3 (0x1<<6) /* select drive 3 when low */
+#define DSKSEL2 (0x1<<5) /* select drive 2 when low */
+#define DSKSEL1 (0x1<<4) /* select drive 1 when low */
+#define DSKSEL0 (0x1<<3) /* select drive 0 when low */
+#define DSKSIDE (0x1<<2) /* side selection: 0 = upper, 1 = lower */
+#define DSKDIREC (0x1<<1) /* step direction: 0=in, 1=out (to trk 0) */
+#define DSKSTEP (0x1) /* pulse low to step head 1 track */
+
+/*
+ * DSKBYTR bits (read only)
+ */
+
+#define DSKBYT (1<<15) /* register contains valid byte when set */
+#define DMAON (1<<14) /* disk DMA enabled */
+#define DISKWRITE (1<<13) /* disk write bit in DSKLEN enabled */
+#define WORDEQUAL (1<<12) /* DSKSYNC register match when true */
+/* bits 7-0 are data */
+
+/*
+ * ADKCON/ADKCONR bits
+ */
+
+#ifndef SETCLR
+#define ADK_SETCLR (1<<15) /* control bit */
+#endif
+#define ADK_PRECOMP1 (1<<14) /* precompensation selection */
+#define ADK_PRECOMP0 (1<<13) /* 00=none, 01=140ns, 10=280ns, 11=500ns */
+#define ADK_MFMPREC (1<<12) /* 0=GCR precomp., 1=MFM precomp. */
+#define ADK_WORDSYNC (1<<10) /* enable DSKSYNC auto DMA */
+#define ADK_MSBSYNC (1<<9) /* when 1, enable sync on MSbit (for GCR) */
+#define ADK_FAST (1<<8) /* bit cell: 0=2us (GCR), 1=1us (MFM) */
+
+/*
+ * DSKLEN bits
+ */
+
+#define DSKLEN_DMAEN (1<<15)
+#define DSKLEN_WRITE (1<<14)
+
+/*
+ * INTENA/INTREQ bits
+ */
+
+#define DSKINDEX (0x1<<4) /* DSKINDEX bit */
+
+/*
+ * Misc
+ */
+
+#define MFM_SYNC 0x4489 /* standard MFM sync value */
+
+/* Values for FD_COMMAND */
+#define FD_RECALIBRATE 0x07 /* move to track 0 */
+#define FD_SEEK 0x0F /* seek track */
+#define FD_READ 0xE6 /* read with MT, MFM, SKip deleted */
+#define FD_WRITE 0xC5 /* write with MT, MFM */
+#define FD_SENSEI 0x08 /* Sense Interrupt Status */
+#define FD_SPECIFY 0x03 /* specify HUT etc */
+#define FD_FORMAT 0x4D /* format one track */
+#define FD_VERSION 0x10 /* get version code */
+#define FD_CONFIGURE 0x13 /* configure FIFO operation */
+#define FD_PERPENDICULAR 0x12 /* perpendicular r/w mode */
+
+#define FD_MAX_UNITS 4 /* Max. Number of drives */
+#define FLOPPY_MAX_SECTORS 22 /* Max. Number of sectors per track */
+
+struct fd_data_type {
+ char *name; /* description of data type */
+ int sects; /* sectors per track */
+ int (*read_fkt)(int); /* read whole track */
+ void (*write_fkt)(int); /* write whole track */
+};
+
+struct fd_drive_type {
+ unsigned long code; /* code returned from drive */
+ char *name; /* description of drive */
+ unsigned int tracks; /* number of tracks */
+ unsigned int heads; /* number of heads */
+ unsigned int read_size; /* raw read size for one track */
+ unsigned int write_size; /* raw write size for one track */
+ unsigned int sect_mult; /* sectors and gap multiplier (HD = 2) */
+ unsigned int precomp1; /* start track for precomp 1 */
+ unsigned int precomp2; /* start track for precomp 2 */
+ unsigned int step_delay; /* time (in ms) for delay after step */
+ unsigned int settle_time; /* time to settle after dir change */
+ unsigned int side_time; /* time needed to change sides */
+};
+
+struct amiga_floppy_struct {
+ struct fd_drive_type *type; /* type of floppy for this unit */
+ struct fd_data_type *dtype; /* type of floppy for this unit */
+ int track; /* current track (-1 == unknown) */
+ unsigned char *trackbuf; /* current track (kmaloc()'d */
+
+ int blocks; /* total # blocks on disk */
+
+ int changed; /* true when not known */
+ int disk; /* disk in drive (-1 == unknown) */
+ int motor; /* true when motor is at speed */
+ int busy; /* true when drive is active */
+ int dirty; /* true when trackbuf is not on disk */
+ int status; /* current error code for unit */
+ struct gendisk *gendisk;
+ struct blk_mq_tag_set tag_set;
+};
+
+/*
* Error codes
*/
#define FD_OK 0 /* operation succeeded */
@@ -164,7 +282,6 @@ static volatile int selected = -1; /* currently selected drive */
static int writepending;
static int writefromint;
static char *raw_buf;
-static int fdc_queue;
static DEFINE_SPINLOCK(amiflop_lock);
@@ -1337,76 +1454,20 @@ static int get_track(int drive, int track)
return -1;
}
-/*
- * Round-robin between our available drives, doing one request from each
- */
-static struct request *set_next_request(void)
-{
- struct request_queue *q;
- int cnt = FD_MAX_UNITS;
- struct request *rq = NULL;
-
- /* Find next queue we can dispatch from */
- fdc_queue = fdc_queue + 1;
- if (fdc_queue == FD_MAX_UNITS)
- fdc_queue = 0;
-
- for(cnt = FD_MAX_UNITS; cnt > 0; cnt--) {
-
- if (unit[fdc_queue].type->code == FD_NODRIVE) {
- if (++fdc_queue == FD_MAX_UNITS)
- fdc_queue = 0;
- continue;
- }
-
- q = unit[fdc_queue].gendisk->queue;
- if (q) {
- rq = blk_fetch_request(q);
- if (rq)
- break;
- }
-
- if (++fdc_queue == FD_MAX_UNITS)
- fdc_queue = 0;
- }
-
- return rq;
-}
-
-static void redo_fd_request(void)
+static blk_status_t amiflop_rw_cur_segment(struct amiga_floppy_struct *floppy,
+ struct request *rq)
{
- struct request *rq;
+ int drive = floppy - unit;
unsigned int cnt, block, track, sector;
- int drive;
- struct amiga_floppy_struct *floppy;
char *data;
- unsigned long flags;
- blk_status_t err;
-
-next_req:
- rq = set_next_request();
- if (!rq) {
- /* Nothing left to do */
- return;
- }
-
- floppy = rq->rq_disk->private_data;
- drive = floppy - unit;
-next_segment:
- /* Here someone could investigate to be more efficient */
- for (cnt = 0, err = BLK_STS_OK; cnt < blk_rq_cur_sectors(rq); cnt++) {
+ for (cnt = 0; cnt < blk_rq_cur_sectors(rq); cnt++) {
#ifdef DEBUG
printk("fd: sector %ld + %d requested for %s\n",
blk_rq_pos(rq), cnt,
(rq_data_dir(rq) == READ) ? "read" : "write");
#endif
block = blk_rq_pos(rq) + cnt;
- if ((int)block > floppy->blocks) {
- err = BLK_STS_IOERR;
- break;
- }
-
track = block / (floppy->dtype->sects * floppy->type->sect_mult);
sector = block % (floppy->dtype->sects * floppy->type->sect_mult);
data = bio_data(rq->bio) + 512 * cnt;
@@ -1415,10 +1476,8 @@ next_segment:
"0x%08lx\n", track, sector, data);
#endif
- if (get_track(drive, track) == -1) {
- err = BLK_STS_IOERR;
- break;
- }
+ if (get_track(drive, track) == -1)
+ return BLK_STS_IOERR;
if (rq_data_dir(rq) == READ) {
memcpy(data, floppy->trackbuf + sector * 512, 512);
@@ -1426,31 +1485,40 @@ next_segment:
memcpy(floppy->trackbuf + sector * 512, data, 512);
/* keep the drive spinning while writes are scheduled */
- if (!fd_motor_on(drive)) {
- err = BLK_STS_IOERR;
- break;
- }
+ if (!fd_motor_on(drive))
+ return BLK_STS_IOERR;
/*
* setup a callback to write the track buffer
* after a short (1 tick) delay.
*/
- local_irq_save(flags);
-
floppy->dirty = 1;
/* reset the timer */
mod_timer (flush_track_timer + drive, jiffies + 1);
- local_irq_restore(flags);
}
}
- if (__blk_end_request_cur(rq, err))
- goto next_segment;
- goto next_req;
+ return BLK_STS_OK;
}
-static void do_fd_request(struct request_queue * q)
+static blk_status_t amiflop_queue_rq(struct blk_mq_hw_ctx *hctx,
+ const struct blk_mq_queue_data *bd)
{
- redo_fd_request();
+ struct request *rq = bd->rq;
+ struct amiga_floppy_struct *floppy = rq->rq_disk->private_data;
+ blk_status_t err;
+
+ if (!spin_trylock_irq(&amiflop_lock))
+ return BLK_STS_DEV_RESOURCE;
+
+ blk_mq_start_request(rq);
+
+ do {
+ err = amiflop_rw_cur_segment(floppy, rq);
+ } while (blk_update_request(rq, err, blk_rq_cur_bytes(rq)));
+ blk_mq_end_request(rq, err);
+
+ spin_unlock_irq(&amiflop_lock);
+ return BLK_STS_OK;
}
static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
@@ -1701,11 +1769,47 @@ static const struct block_device_operations floppy_fops = {
.check_events = amiga_check_events,
};
+static const struct blk_mq_ops amiflop_mq_ops = {
+ .queue_rq = amiflop_queue_rq,
+};
+
+static struct gendisk *fd_alloc_disk(int drive)
+{
+ struct gendisk *disk;
+
+ disk = alloc_disk(1);
+ if (!disk)
+ goto out;
+
+ disk->queue = blk_mq_init_sq_queue(&unit[drive].tag_set, &amiflop_mq_ops,
+ 2, BLK_MQ_F_SHOULD_MERGE);
+ if (IS_ERR(disk->queue)) {
+ disk->queue = NULL;
+ goto out_put_disk;
+ }
+
+ unit[drive].trackbuf = kmalloc(FLOPPY_MAX_SECTORS * 512, GFP_KERNEL);
+ if (!unit[drive].trackbuf)
+ goto out_cleanup_queue;
+
+ return disk;
+
+out_cleanup_queue:
+ blk_cleanup_queue(disk->queue);
+ disk->queue = NULL;
+ blk_mq_free_tag_set(&unit[drive].tag_set);
+out_put_disk:
+ put_disk(disk);
+out:
+ unit[drive].type->code = FD_NODRIVE;
+ return NULL;
+}
+
static int __init fd_probe_drives(void)
{
int drive,drives,nomem;
- printk(KERN_INFO "FD: probing units\nfound ");
+ pr_info("FD: probing units\nfound");
drives=0;
nomem=0;
for(drive=0;drive<FD_MAX_UNITS;drive++) {
@@ -1713,27 +1817,17 @@ static int __init fd_probe_drives(void)
fd_probe(drive);
if (unit[drive].type->code == FD_NODRIVE)
continue;
- disk = alloc_disk(1);
+
+ disk = fd_alloc_disk(drive);
if (!disk) {
- unit[drive].type->code = FD_NODRIVE;
+ pr_cont(" no mem for fd%d", drive);
+ nomem = 1;
continue;
}
unit[drive].gendisk = disk;
-
- disk->queue = blk_init_queue(do_fd_request, &amiflop_lock);
- if (!disk->queue) {
- unit[drive].type->code = FD_NODRIVE;
- continue;
- }
-
drives++;
- if ((unit[drive].trackbuf = kmalloc(FLOPPY_MAX_SECTORS * 512, GFP_KERNEL)) == NULL) {
- printk("no mem for ");
- unit[drive].type = &drive_types[num_dr_types - 1]; /* FD_NODRIVE */
- drives--;
- nomem = 1;
- }
- printk("fd%d ",drive);
+
+ pr_cont(" fd%d",drive);
disk->major = FLOPPY_MAJOR;
disk->first_minor = drive;
disk->fops = &floppy_fops;
@@ -1744,11 +1838,11 @@ static int __init fd_probe_drives(void)
}
if ((drives > 0) || (nomem == 0)) {
if (drives == 0)
- printk("no drives");
- printk("\n");
+ pr_cont(" no drives");
+ pr_cont("\n");
return drives;
}
- printk("\n");
+ pr_cont("\n");
return -ENOMEM;
}
@@ -1831,30 +1925,6 @@ out_blkdev:
return ret;
}
-#if 0 /* not safe to unload */
-static int __exit amiga_floppy_remove(struct platform_device *pdev)
-{
- int i;
-
- for( i = 0; i < FD_MAX_UNITS; i++) {
- if (unit[i].type->code != FD_NODRIVE) {
- struct request_queue *q = unit[i].gendisk->queue;
- del_gendisk(unit[i].gendisk);
- put_disk(unit[i].gendisk);
- kfree(unit[i].trackbuf);
- if (q)
- blk_cleanup_queue(q);
- }
- }
- blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
- free_irq(IRQ_AMIGA_CIAA_TB, NULL);
- free_irq(IRQ_AMIGA_DSKBLK, NULL);
- custom.dmacon = DMAF_DISK; /* disable DMA */
- amiga_chip_free(raw_buf);
- unregister_blkdev(FLOPPY_MAJOR, "fd");
-}
-#endif
-
static struct platform_driver amiga_floppy_driver = {
.driver = {
.name = "amiga-floppy",
diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h
index c0ebda1283cc..7ca76ed2e71a 100644
--- a/drivers/block/aoe/aoe.h
+++ b/drivers/block/aoe/aoe.h
@@ -1,4 +1,6 @@
/* Copyright (c) 2013 Coraid, Inc. See COPYING for GPL terms. */
+#include <linux/blk-mq.h>
+
#define VERSION "85"
#define AOE_MAJOR 152
#define DEVICE_NAME "aoe"
@@ -164,6 +166,8 @@ struct aoedev {
struct gendisk *gd;
struct dentry *debugfs;
struct request_queue *blkq;
+ struct list_head rq_list;
+ struct blk_mq_tag_set tag_set;
struct hd_geometry geo;
sector_t ssize;
struct timer_list timer;
@@ -201,7 +205,6 @@ int aoeblk_init(void);
void aoeblk_exit(void);
void aoeblk_gdalloc(void *);
void aoedisk_rm_debugfs(struct aoedev *d);
-void aoedisk_rm_sysfs(struct aoedev *d);
int aoechr_init(void);
void aoechr_exit(void);
diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c
index 429ebb84b592..ed26b7287256 100644
--- a/drivers/block/aoe/aoeblk.c
+++ b/drivers/block/aoe/aoeblk.c
@@ -6,7 +6,7 @@
#include <linux/kernel.h>
#include <linux/hdreg.h>
-#include <linux/blkdev.h>
+#include <linux/blk-mq.h>
#include <linux/backing-dev.h>
#include <linux/fs.h>
#include <linux/ioctl.h>
@@ -177,10 +177,15 @@ static struct attribute *aoe_attrs[] = {
NULL,
};
-static const struct attribute_group attr_group = {
+static const struct attribute_group aoe_attr_group = {
.attrs = aoe_attrs,
};
+static const struct attribute_group *aoe_attr_groups[] = {
+ &aoe_attr_group,
+ NULL,
+};
+
static const struct file_operations aoe_debugfs_fops = {
.open = aoe_debugfs_open,
.read = seq_read,
@@ -220,17 +225,6 @@ aoedisk_rm_debugfs(struct aoedev *d)
}
static int
-aoedisk_add_sysfs(struct aoedev *d)
-{
- return sysfs_create_group(&disk_to_dev(d->gd)->kobj, &attr_group);
-}
-void
-aoedisk_rm_sysfs(struct aoedev *d)
-{
- sysfs_remove_group(&disk_to_dev(d->gd)->kobj, &attr_group);
-}
-
-static int
aoeblk_open(struct block_device *bdev, fmode_t mode)
{
struct aoedev *d = bdev->bd_disk->private_data;
@@ -274,23 +268,25 @@ aoeblk_release(struct gendisk *disk, fmode_t mode)
spin_unlock_irqrestore(&d->lock, flags);
}
-static void
-aoeblk_request(struct request_queue *q)
+static blk_status_t aoeblk_queue_rq(struct blk_mq_hw_ctx *hctx,
+ const struct blk_mq_queue_data *bd)
{
- struct aoedev *d;
- struct request *rq;
+ struct aoedev *d = hctx->queue->queuedata;
+
+ spin_lock_irq(&d->lock);
- d = q->queuedata;
if ((d->flags & DEVFL_UP) == 0) {
pr_info_ratelimited("aoe: device %ld.%d is not up\n",
d->aoemajor, d->aoeminor);
- while ((rq = blk_peek_request(q))) {
- blk_start_request(rq);
- aoe_end_request(d, rq, 1);
- }
- return;
+ spin_unlock_irq(&d->lock);
+ blk_mq_start_request(bd->rq);
+ return BLK_STS_IOERR;
}
+
+ list_add_tail(&bd->rq->queuelist, &d->rq_list);
aoecmd_work(d);
+ spin_unlock_irq(&d->lock);
+ return BLK_STS_OK;
}
static int
@@ -345,6 +341,10 @@ static const struct block_device_operations aoe_bdops = {
.owner = THIS_MODULE,
};
+static const struct blk_mq_ops aoeblk_mq_ops = {
+ .queue_rq = aoeblk_queue_rq,
+};
+
/* alloc_disk and add_disk can sleep */
void
aoeblk_gdalloc(void *vp)
@@ -353,9 +353,11 @@ aoeblk_gdalloc(void *vp)
struct gendisk *gd;
mempool_t *mp;
struct request_queue *q;
+ struct blk_mq_tag_set *set;
enum { KB = 1024, MB = KB * KB, READ_AHEAD = 2 * MB, };
ulong flags;
int late = 0;
+ int err;
spin_lock_irqsave(&d->lock, flags);
if (d->flags & DEVFL_GDALLOC
@@ -382,10 +384,25 @@ aoeblk_gdalloc(void *vp)
d->aoemajor, d->aoeminor);
goto err_disk;
}
- q = blk_init_queue(aoeblk_request, &d->lock);
- if (q == NULL) {
+
+ set = &d->tag_set;
+ set->ops = &aoeblk_mq_ops;
+ set->nr_hw_queues = 1;
+ set->queue_depth = 128;
+ set->numa_node = NUMA_NO_NODE;
+ set->flags = BLK_MQ_F_SHOULD_MERGE;
+ err = blk_mq_alloc_tag_set(set);
+ if (err) {
+ pr_err("aoe: cannot allocate tag set for %ld.%d\n",
+ d->aoemajor, d->aoeminor);
+ goto err_mempool;
+ }
+
+ q = blk_mq_init_queue(set);
+ if (IS_ERR(q)) {
pr_err("aoe: cannot allocate block queue for %ld.%d\n",
d->aoemajor, d->aoeminor);
+ blk_mq_free_tag_set(set);
goto err_mempool;
}
@@ -417,8 +434,7 @@ aoeblk_gdalloc(void *vp)
spin_unlock_irqrestore(&d->lock, flags);
- add_disk(gd);
- aoedisk_add_sysfs(d);
+ device_add_disk(NULL, gd, aoe_attr_groups);
aoedisk_add_debugfs(d);
spin_lock_irqsave(&d->lock, flags);
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
index 136dc507d020..bb2fba651bd2 100644
--- a/drivers/block/aoe/aoecmd.c
+++ b/drivers/block/aoe/aoecmd.c
@@ -7,7 +7,7 @@
#include <linux/ata.h>
#include <linux/slab.h>
#include <linux/hdreg.h>
-#include <linux/blkdev.h>
+#include <linux/blk-mq.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/genhd.h>
@@ -813,7 +813,7 @@ rexmit_timer(struct timer_list *timer)
out:
if ((d->flags & DEVFL_KICKME) && d->blkq) {
d->flags &= ~DEVFL_KICKME;
- d->blkq->request_fn(d->blkq);
+ blk_mq_run_hw_queues(d->blkq, true);
}
d->timer.expires = jiffies + TIMERTICK;
@@ -857,10 +857,12 @@ nextbuf(struct aoedev *d)
return d->ip.buf;
rq = d->ip.rq;
if (rq == NULL) {
- rq = blk_peek_request(q);
+ rq = list_first_entry_or_null(&d->rq_list, struct request,
+ queuelist);
if (rq == NULL)
return NULL;
- blk_start_request(rq);
+ list_del_init(&rq->queuelist);
+ blk_mq_start_request(rq);
d->ip.rq = rq;
d->ip.nxbio = rq->bio;
rq->special = (void *) rqbiocnt(rq);
@@ -1045,6 +1047,7 @@ aoe_end_request(struct aoedev *d, struct request *rq, int fastfail)
struct bio *bio;
int bok;
struct request_queue *q;
+ blk_status_t err = BLK_STS_OK;
q = d->blkq;
if (rq == d->ip.rq)
@@ -1052,11 +1055,15 @@ aoe_end_request(struct aoedev *d, struct request *rq, int fastfail)
do {
bio = rq->bio;
bok = !fastfail && !bio->bi_status;
- } while (__blk_end_request(rq, bok ? BLK_STS_OK : BLK_STS_IOERR, bio->bi_iter.bi_size));
+ if (!bok)
+ err = BLK_STS_IOERR;
+ } while (blk_update_request(rq, bok ? BLK_STS_OK : BLK_STS_IOERR, bio->bi_iter.bi_size));
+
+ __blk_mq_end_request(rq, err);
/* cf. http://lkml.org/lkml/2006/10/31/28 */
if (!fastfail)
- __blk_run_queue(q);
+ blk_mq_run_hw_queues(q, true);
}
static void
diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c
index 41060e9cedf2..9063f8efbd3b 100644
--- a/drivers/block/aoe/aoedev.c
+++ b/drivers/block/aoe/aoedev.c
@@ -5,7 +5,7 @@
*/
#include <linux/hdreg.h>
-#include <linux/blkdev.h>
+#include <linux/blk-mq.h>
#include <linux/netdevice.h>
#include <linux/delay.h>
#include <linux/slab.h>
@@ -197,7 +197,6 @@ aoedev_downdev(struct aoedev *d)
{
struct aoetgt *t, **tt, **te;
struct list_head *head, *pos, *nx;
- struct request *rq;
int i;
d->flags &= ~DEVFL_UP;
@@ -225,10 +224,11 @@ aoedev_downdev(struct aoedev *d)
/* fast fail all pending I/O */
if (d->blkq) {
- while ((rq = blk_peek_request(d->blkq))) {
- blk_start_request(rq);
- aoe_end_request(d, rq, 1);
- }
+ /* UP is cleared, freeze+quiesce to insure all are errored */
+ blk_mq_freeze_queue(d->blkq);
+ blk_mq_quiesce_queue(d->blkq);
+ blk_mq_unquiesce_queue(d->blkq);
+ blk_mq_unfreeze_queue(d->blkq);
}
if (d->gd)
@@ -275,9 +275,9 @@ freedev(struct aoedev *d)
del_timer_sync(&d->timer);
if (d->gd) {
aoedisk_rm_debugfs(d);
- aoedisk_rm_sysfs(d);
del_gendisk(d->gd);
put_disk(d->gd);
+ blk_mq_free_tag_set(&d->tag_set);
blk_cleanup_queue(d->blkq);
}
t = d->targets;
@@ -464,6 +464,7 @@ aoedev_by_aoeaddr(ulong maj, int min, int do_alloc)
d->ntargets = NTARGETS;
INIT_WORK(&d->work, aoecmd_sleepwork);
spin_lock_init(&d->lock);
+ INIT_LIST_HEAD(&d->rq_list);
skb_queue_head_init(&d->skbpool);
timer_setup(&d->timer, dummy_timer, 0);
d->timer.expires = jiffies + HZ;
diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c
index dfb2c2622e5a..f88b4c26d422 100644
--- a/drivers/block/ataflop.c
+++ b/drivers/block/ataflop.c
@@ -66,13 +66,11 @@
#include <linux/fd.h>
#include <linux/delay.h>
#include <linux/init.h>
-#include <linux/blkdev.h>
+#include <linux/blk-mq.h>
#include <linux/mutex.h>
#include <linux/completion.h>
#include <linux/wait.h>
-#include <asm/atafd.h>
-#include <asm/atafdreg.h>
#include <asm/atariints.h>
#include <asm/atari_stdma.h>
#include <asm/atari_stram.h>
@@ -83,7 +81,87 @@
static DEFINE_MUTEX(ataflop_mutex);
static struct request *fd_request;
-static int fdc_queue;
+
+/*
+ * WD1772 stuff
+ */
+
+/* register codes */
+
+#define FDCSELREG_STP (0x80) /* command/status register */
+#define FDCSELREG_TRA (0x82) /* track register */
+#define FDCSELREG_SEC (0x84) /* sector register */
+#define FDCSELREG_DTA (0x86) /* data register */
+
+/* register names for FDC_READ/WRITE macros */
+
+#define FDCREG_CMD 0
+#define FDCREG_STATUS 0
+#define FDCREG_TRACK 2
+#define FDCREG_SECTOR 4
+#define FDCREG_DATA 6
+
+/* command opcodes */
+
+#define FDCCMD_RESTORE (0x00) /* - */
+#define FDCCMD_SEEK (0x10) /* | */
+#define FDCCMD_STEP (0x20) /* | TYP 1 Commands */
+#define FDCCMD_STIN (0x40) /* | */
+#define FDCCMD_STOT (0x60) /* - */
+#define FDCCMD_RDSEC (0x80) /* - TYP 2 Commands */
+#define FDCCMD_WRSEC (0xa0) /* - " */
+#define FDCCMD_RDADR (0xc0) /* - */
+#define FDCCMD_RDTRA (0xe0) /* | TYP 3 Commands */
+#define FDCCMD_WRTRA (0xf0) /* - */
+#define FDCCMD_FORCI (0xd0) /* - TYP 4 Command */
+
+/* command modifier bits */
+
+#define FDCCMDADD_SR6 (0x00) /* step rate settings */
+#define FDCCMDADD_SR12 (0x01)
+#define FDCCMDADD_SR2 (0x02)
+#define FDCCMDADD_SR3 (0x03)
+#define FDCCMDADD_V (0x04) /* verify */
+#define FDCCMDADD_H (0x08) /* wait for spin-up */
+#define FDCCMDADD_U (0x10) /* update track register */
+#define FDCCMDADD_M (0x10) /* multiple sector access */
+#define FDCCMDADD_E (0x04) /* head settling flag */
+#define FDCCMDADD_P (0x02) /* precompensation off */
+#define FDCCMDADD_A0 (0x01) /* DAM flag */
+
+/* status register bits */
+
+#define FDCSTAT_MOTORON (0x80) /* motor on */
+#define FDCSTAT_WPROT (0x40) /* write protected (FDCCMD_WR*) */
+#define FDCSTAT_SPINUP (0x20) /* motor speed stable (Type I) */
+#define FDCSTAT_DELDAM (0x20) /* sector has deleted DAM (Type II+III) */
+#define FDCSTAT_RECNF (0x10) /* record not found */
+#define FDCSTAT_CRC (0x08) /* CRC error */
+#define FDCSTAT_TR00 (0x04) /* Track 00 flag (Type I) */
+#define FDCSTAT_LOST (0x04) /* Lost Data (Type II+III) */
+#define FDCSTAT_IDX (0x02) /* Index status (Type I) */
+#define FDCSTAT_DRQ (0x02) /* DRQ status (Type II+III) */
+#define FDCSTAT_BUSY (0x01) /* FDC is busy */
+
+
+/* PSG Port A Bit Nr 0 .. Side Sel .. 0 -> Side 1 1 -> Side 2 */
+#define DSKSIDE (0x01)
+
+#define DSKDRVNONE (0x06)
+#define DSKDRV0 (0x02)
+#define DSKDRV1 (0x04)
+
+/* step rates */
+#define FDCSTEP_6 0x00
+#define FDCSTEP_12 0x01
+#define FDCSTEP_2 0x02
+#define FDCSTEP_3 0x03
+
+struct atari_format_descr {
+ int track; /* to be formatted */
+ int head; /* "" "" */
+ int sect_offset; /* offset of first sector */
+};
/* Disk types: DD, HD, ED */
static struct atari_disk_type {
@@ -221,6 +299,7 @@ static struct atari_floppy_struct {
struct gendisk *disk;
int ref;
int type;
+ struct blk_mq_tag_set tag_set;
} unit[FD_MAX_UNITS];
#define UD unit[drive]
@@ -300,9 +379,6 @@ static int IsFormatting = 0, FormatError;
static int UserSteprate[FD_MAX_UNITS] = { -1, -1 };
module_param_array(UserSteprate, int, NULL, 0);
-/* Synchronization of FDC access. */
-static volatile int fdc_busy = 0;
-static DECLARE_WAIT_QUEUE_HEAD(fdc_wait);
static DECLARE_COMPLETION(format_wait);
static unsigned long changed_floppies = 0xff, fake_change = 0;
@@ -362,7 +438,6 @@ static void fd_times_out(struct timer_list *unused);
static void finish_fdc( void );
static void finish_fdc_done( int dummy );
static void setup_req_params( int drive );
-static void redo_fd_request( void);
static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
cmd, unsigned long param);
static void fd_probe( int drive );
@@ -380,8 +455,11 @@ static DEFINE_TIMER(fd_timer, check_change);
static void fd_end_request_cur(blk_status_t err)
{
- if (!__blk_end_request_cur(fd_request, err))
+ if (!blk_update_request(fd_request, err,
+ blk_rq_cur_bytes(fd_request))) {
+ __blk_mq_end_request(fd_request, err);
fd_request = NULL;
+ }
}
static inline void start_motor_off_timer(void)
@@ -627,7 +705,6 @@ static void fd_error( void )
if (SelectedDrive != -1)
SUD.track = -1;
}
- redo_fd_request();
}
@@ -645,14 +722,15 @@ static void fd_error( void )
static int do_format(int drive, int type, struct atari_format_descr *desc)
{
+ struct request_queue *q = unit[drive].disk->queue;
unsigned char *p;
int sect, nsect;
unsigned long flags;
+ int ret;
- DPRINT(("do_format( dr=%d tr=%d he=%d offs=%d )\n",
- drive, desc->track, desc->head, desc->sect_offset ));
+ blk_mq_freeze_queue(q);
+ blk_mq_quiesce_queue(q);
- wait_event(fdc_wait, cmpxchg(&fdc_busy, 0, 1) == 0);
local_irq_save(flags);
stdma_lock(floppy_irq, NULL);
atari_turnon_irq( IRQ_MFP_FDC ); /* should be already, just to be sure */
@@ -661,16 +739,16 @@ static int do_format(int drive, int type, struct atari_format_descr *desc)
if (type) {
if (--type >= NUM_DISK_MINORS ||
minor2disktype[type].drive_types > DriveType) {
- redo_fd_request();
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
type = minor2disktype[type].index;
UDT = &atari_disk_type[type];
}
if (!UDT || desc->track >= UDT->blocks/UDT->spt/2 || desc->head >= 2) {
- redo_fd_request();
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
nsect = UDT->spt;
@@ -709,8 +787,11 @@ static int do_format(int drive, int type, struct atari_format_descr *desc)
wait_for_completion(&format_wait);
- redo_fd_request();
- return( FormatError ? -EIO : 0 );
+ ret = FormatError ? -EIO : 0;
+out:
+ blk_mq_unquiesce_queue(q);
+ blk_mq_unfreeze_queue(q);
+ return ret;
}
@@ -740,7 +821,6 @@ static void do_fd_action( int drive )
else {
/* all sectors finished */
fd_end_request_cur(BLK_STS_OK);
- redo_fd_request();
return;
}
}
@@ -1145,7 +1225,6 @@ static void fd_rwsec_done1(int status)
else {
/* all sectors finished */
fd_end_request_cur(BLK_STS_OK);
- redo_fd_request();
}
return;
@@ -1303,8 +1382,6 @@ static void finish_fdc_done( int dummy )
local_irq_save(flags);
stdma_release();
- fdc_busy = 0;
- wake_up( &fdc_wait );
local_irq_restore(flags);
DPRINT(("finish_fdc() finished\n"));
@@ -1394,59 +1471,34 @@ static void setup_req_params( int drive )
ReqTrack, ReqSector, (unsigned long)ReqData ));
}
-/*
- * Round-robin between our available drives, doing one request from each
- */
-static struct request *set_next_request(void)
+static blk_status_t ataflop_queue_rq(struct blk_mq_hw_ctx *hctx,
+ const struct blk_mq_queue_data *bd)
{
- struct request_queue *q;
- int old_pos = fdc_queue;
- struct request *rq = NULL;
-
- do {
- q = unit[fdc_queue].disk->queue;
- if (++fdc_queue == FD_MAX_UNITS)
- fdc_queue = 0;
- if (q) {
- rq = blk_fetch_request(q);
- if (rq) {
- rq->error_count = 0;
- break;
- }
- }
- } while (fdc_queue != old_pos);
-
- return rq;
-}
-
+ struct atari_floppy_struct *floppy = bd->rq->rq_disk->private_data;
+ int drive = floppy - unit;
+ int type = floppy->type;
-static void redo_fd_request(void)
-{
- int drive, type;
- struct atari_floppy_struct *floppy;
+ spin_lock_irq(&ataflop_lock);
+ if (fd_request) {
+ spin_unlock_irq(&ataflop_lock);
+ return BLK_STS_DEV_RESOURCE;
+ }
+ if (!stdma_try_lock(floppy_irq, NULL)) {
+ spin_unlock_irq(&ataflop_lock);
+ return BLK_STS_RESOURCE;
+ }
+ fd_request = bd->rq;
+ blk_mq_start_request(fd_request);
- DPRINT(("redo_fd_request: fd_request=%p dev=%s fd_request->sector=%ld\n",
- fd_request, fd_request ? fd_request->rq_disk->disk_name : "",
- fd_request ? blk_rq_pos(fd_request) : 0 ));
+ atari_disable_irq( IRQ_MFP_FDC );
IsFormatting = 0;
-repeat:
- if (!fd_request) {
- fd_request = set_next_request();
- if (!fd_request)
- goto the_end;
- }
-
- floppy = fd_request->rq_disk->private_data;
- drive = floppy - unit;
- type = floppy->type;
-
if (!UD.connected) {
/* drive not connected */
printk(KERN_ERR "Unknown Device: fd%d\n", drive );
fd_end_request_cur(BLK_STS_IOERR);
- goto repeat;
+ goto out;
}
if (type == 0) {
@@ -1462,23 +1514,18 @@ repeat:
if (--type >= NUM_DISK_MINORS) {
printk(KERN_WARNING "fd%d: invalid disk format", drive );
fd_end_request_cur(BLK_STS_IOERR);
- goto repeat;
+ goto out;
}
if (minor2disktype[type].drive_types > DriveType) {
printk(KERN_WARNING "fd%d: unsupported disk format", drive );
fd_end_request_cur(BLK_STS_IOERR);
- goto repeat;
+ goto out;
}
type = minor2disktype[type].index;
UDT = &atari_disk_type[type];
set_capacity(floppy->disk, UDT->blocks);
UD.autoprobe = 0;
}
-
- if (blk_rq_pos(fd_request) + 1 > UDT->blocks) {
- fd_end_request_cur(BLK_STS_IOERR);
- goto repeat;
- }
/* stop deselect timer */
del_timer( &motor_off_timer );
@@ -1490,22 +1537,13 @@ repeat:
setup_req_params( drive );
do_fd_action( drive );
- return;
-
- the_end:
- finish_fdc();
-}
-
-
-void do_fd_request(struct request_queue * q)
-{
- DPRINT(("do_fd_request for pid %d\n",current->pid));
- wait_event(fdc_wait, cmpxchg(&fdc_busy, 0, 1) == 0);
- stdma_lock(floppy_irq, NULL);
-
- atari_disable_irq( IRQ_MFP_FDC );
- redo_fd_request();
+ if (bd->last)
+ finish_fdc();
atari_enable_irq( IRQ_MFP_FDC );
+
+out:
+ spin_unlock_irq(&ataflop_lock);
+ return BLK_STS_OK;
}
static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode,
@@ -1583,7 +1621,6 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode,
/* what if type > 0 here? Overwrite specified entry ? */
if (type) {
/* refuse to re-set a predefined type for now */
- redo_fd_request();
return -EINVAL;
}
@@ -1651,10 +1688,8 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode,
/* sanity check */
if (setprm.track != dtp->blocks/dtp->spt/2 ||
- setprm.head != 2) {
- redo_fd_request();
+ setprm.head != 2)
return -EINVAL;
- }
UDT = dtp;
set_capacity(floppy->disk, UDT->blocks);
@@ -1910,6 +1945,10 @@ static const struct block_device_operations floppy_fops = {
.revalidate_disk= floppy_revalidate,
};
+static const struct blk_mq_ops ataflop_mq_ops = {
+ .queue_rq = ataflop_queue_rq,
+};
+
static struct kobject *floppy_find(dev_t dev, int *part, void *data)
{
int drive = *part & 3;
@@ -1923,6 +1962,7 @@ static struct kobject *floppy_find(dev_t dev, int *part, void *data)
static int __init atari_floppy_init (void)
{
int i;
+ int ret;
if (!MACH_IS_ATARI)
/* Amiga, Mac, ... don't have Atari-compatible floppy :-) */
@@ -1933,8 +1973,19 @@ static int __init atari_floppy_init (void)
for (i = 0; i < FD_MAX_UNITS; i++) {
unit[i].disk = alloc_disk(1);
- if (!unit[i].disk)
- goto Enomem;
+ if (!unit[i].disk) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ unit[i].disk->queue = blk_mq_init_sq_queue(&unit[i].tag_set,
+ &ataflop_mq_ops, 2,
+ BLK_MQ_F_SHOULD_MERGE);
+ if (IS_ERR(unit[i].disk->queue)) {
+ ret = PTR_ERR(unit[i].disk->queue);
+ unit[i].disk->queue = NULL;
+ goto err;
+ }
}
if (UseTrackbuffer < 0)
@@ -1951,7 +2002,8 @@ static int __init atari_floppy_init (void)
DMABuffer = atari_stram_alloc(BUFFER_SIZE+512, "ataflop");
if (!DMABuffer) {
printk(KERN_ERR "atari_floppy_init: cannot get dma buffer\n");
- goto Enomem;
+ ret = -ENOMEM;
+ goto err;
}
TrackBuffer = DMABuffer + 512;
PhysDMABuffer = atari_stram_to_phys(DMABuffer);
@@ -1966,10 +2018,6 @@ static int __init atari_floppy_init (void)
sprintf(unit[i].disk->disk_name, "fd%d", i);
unit[i].disk->fops = &floppy_fops;
unit[i].disk->private_data = &unit[i];
- unit[i].disk->queue = blk_init_queue(do_fd_request,
- &ataflop_lock);
- if (!unit[i].disk->queue)
- goto Enomem;
set_capacity(unit[i].disk, MAX_DISK_SIZE * 2);
add_disk(unit[i].disk);
}
@@ -1983,17 +2031,23 @@ static int __init atari_floppy_init (void)
config_types();
return 0;
-Enomem:
- while (i--) {
- struct request_queue *q = unit[i].disk->queue;
- put_disk(unit[i].disk);
- if (q)
- blk_cleanup_queue(q);
- }
+err:
+ do {
+ struct gendisk *disk = unit[i].disk;
+
+ if (disk) {
+ if (disk->queue) {
+ blk_cleanup_queue(disk->queue);
+ disk->queue = NULL;
+ }
+ blk_mq_free_tag_set(&unit[i].tag_set);
+ put_disk(unit[i].disk);
+ }
+ } while (i--);
unregister_blkdev(FLOPPY_MAJOR, "fd");
- return -ENOMEM;
+ return ret;
}
#ifndef MODULE
@@ -2040,11 +2094,10 @@ static void __exit atari_floppy_exit(void)
int i;
blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
for (i = 0; i < FD_MAX_UNITS; i++) {
- struct request_queue *q = unit[i].disk->queue;
-
del_gendisk(unit[i].disk);
+ blk_cleanup_queue(unit[i].disk->queue);
+ blk_mq_free_tag_set(&unit[i].tag_set);
put_disk(unit[i].disk);
- blk_cleanup_queue(q);
}
unregister_blkdev(FLOPPY_MAJOR, "fd");
diff --git a/drivers/block/brd.c b/drivers/block/brd.c
index df8103dd40ac..c18586fccb6f 100644
--- a/drivers/block/brd.c
+++ b/drivers/block/brd.c
@@ -396,15 +396,14 @@ static struct brd_device *brd_alloc(int i)
disk->first_minor = i * max_part;
disk->fops = &brd_fops;
disk->private_data = brd;
- disk->queue = brd->brd_queue;
disk->flags = GENHD_FL_EXT_DEVT;
sprintf(disk->disk_name, "ram%d", i);
set_capacity(disk, rd_size * 2);
- disk->queue->backing_dev_info->capabilities |= BDI_CAP_SYNCHRONOUS_IO;
+ brd->brd_queue->backing_dev_info->capabilities |= BDI_CAP_SYNCHRONOUS_IO;
/* Tell the block layer that this is not a rotational device */
- blk_queue_flag_set(QUEUE_FLAG_NONROT, disk->queue);
- blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, disk->queue);
+ blk_queue_flag_set(QUEUE_FLAG_NONROT, brd->brd_queue);
+ blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, brd->brd_queue);
return brd;
@@ -436,6 +435,7 @@ static struct brd_device *brd_init_one(int i, bool *new)
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);
}
@@ -503,8 +503,14 @@ static int __init brd_init(void)
/* point of no return */
- list_for_each_entry(brd, &brd_devices, brd_list)
+ 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);
+ }
blk_register_region(MKDEV(RAMDISK_MAJOR, 0), 1UL << MINORBITS,
THIS_MODULE, brd_probe, NULL, NULL);
diff --git a/drivers/block/cryptoloop.c b/drivers/block/cryptoloop.c
index 7033a4beda66..254ee7d54e91 100644
--- a/drivers/block/cryptoloop.c
+++ b/drivers/block/cryptoloop.c
@@ -45,7 +45,7 @@ cryptoloop_init(struct loop_device *lo, const struct loop_info64 *info)
char cms[LO_NAME_SIZE]; /* cipher-mode string */
char *mode;
char *cmsp = cms; /* c-m string pointer */
- struct crypto_skcipher *tfm;
+ struct crypto_sync_skcipher *tfm;
/* encryption breaks for non sector aligned offsets */
@@ -80,13 +80,13 @@ cryptoloop_init(struct loop_device *lo, const struct loop_info64 *info)
*cmsp++ = ')';
*cmsp = 0;
- tfm = crypto_alloc_skcipher(cms, 0, CRYPTO_ALG_ASYNC);
+ tfm = crypto_alloc_sync_skcipher(cms, 0, 0);
if (IS_ERR(tfm))
return PTR_ERR(tfm);
- err = crypto_skcipher_setkey(tfm, info->lo_encrypt_key,
- info->lo_encrypt_key_size);
-
+ err = crypto_sync_skcipher_setkey(tfm, info->lo_encrypt_key,
+ info->lo_encrypt_key_size);
+
if (err != 0)
goto out_free_tfm;
@@ -94,7 +94,7 @@ cryptoloop_init(struct loop_device *lo, const struct loop_info64 *info)
return 0;
out_free_tfm:
- crypto_free_skcipher(tfm);
+ crypto_free_sync_skcipher(tfm);
out:
return err;
@@ -109,8 +109,8 @@ cryptoloop_transfer(struct loop_device *lo, int cmd,
struct page *loop_page, unsigned loop_off,
int size, sector_t IV)
{
- struct crypto_skcipher *tfm = lo->key_data;
- SKCIPHER_REQUEST_ON_STACK(req, tfm);
+ struct crypto_sync_skcipher *tfm = lo->key_data;
+ SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm);
struct scatterlist sg_out;
struct scatterlist sg_in;
@@ -119,7 +119,7 @@ cryptoloop_transfer(struct loop_device *lo, int cmd,
unsigned in_offs, out_offs;
int err;
- skcipher_request_set_tfm(req, tfm);
+ skcipher_request_set_sync_tfm(req, tfm);
skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP,
NULL, NULL);
@@ -175,9 +175,9 @@ cryptoloop_ioctl(struct loop_device *lo, int cmd, unsigned long arg)
static int
cryptoloop_release(struct loop_device *lo)
{
- struct crypto_skcipher *tfm = lo->key_data;
+ struct crypto_sync_skcipher *tfm = lo->key_data;
if (tfm != NULL) {
- crypto_free_skcipher(tfm);
+ crypto_free_sync_skcipher(tfm);
lo->key_data = NULL;
return 0;
}
diff --git a/drivers/block/drbd/Kconfig b/drivers/block/drbd/Kconfig
index 87aab6910d2d..52d885cdccb5 100644
--- a/drivers/block/drbd/Kconfig
+++ b/drivers/block/drbd/Kconfig
@@ -11,7 +11,6 @@ config BLK_DEV_DRBD
depends on PROC_FS && INET
select LRU_CACHE
select LIBCRC32C
- default n
help
NOTE: In order to authenticate connections you have to select
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h
index e35a234b0a8f..1e47db57b9d2 100644
--- a/drivers/block/drbd/drbd_int.h
+++ b/drivers/block/drbd/drbd_int.h
@@ -429,7 +429,7 @@ enum {
__EE_CALL_AL_COMPLETE_IO,
__EE_MAY_SET_IN_SYNC,
- /* is this a TRIM aka REQ_DISCARD? */
+ /* is this a TRIM aka REQ_OP_DISCARD? */
__EE_IS_TRIM,
/* In case a barrier failed,
@@ -724,10 +724,10 @@ struct drbd_connection {
struct list_head transfer_log; /* all requests not yet fully processed */
struct crypto_shash *cram_hmac_tfm;
- struct crypto_ahash *integrity_tfm; /* checksums we compute, updates protected by connection->data->mutex */
- struct crypto_ahash *peer_integrity_tfm; /* checksums we verify, only accessed from receiver thread */
- struct crypto_ahash *csums_tfm;
- struct crypto_ahash *verify_tfm;
+ struct crypto_shash *integrity_tfm; /* checksums we compute, updates protected by connection->data->mutex */
+ struct crypto_shash *peer_integrity_tfm; /* checksums we verify, only accessed from receiver thread */
+ struct crypto_shash *csums_tfm;
+ struct crypto_shash *verify_tfm;
void *int_dig_in;
void *int_dig_vv;
@@ -1531,8 +1531,9 @@ static inline void ov_out_of_sync_print(struct drbd_device *device)
}
-extern void drbd_csum_bio(struct crypto_ahash *, struct bio *, void *);
-extern void drbd_csum_ee(struct crypto_ahash *, struct drbd_peer_request *, void *);
+extern void drbd_csum_bio(struct crypto_shash *, struct bio *, void *);
+extern void drbd_csum_ee(struct crypto_shash *, struct drbd_peer_request *,
+ void *);
/* worker callbacks */
extern int w_e_end_data_req(struct drbd_work *, int);
extern int w_e_end_rsdata_req(struct drbd_work *, int);
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c
index ef8212a4b73e..fa8204214ac0 100644
--- a/drivers/block/drbd/drbd_main.c
+++ b/drivers/block/drbd/drbd_main.c
@@ -1377,7 +1377,7 @@ void drbd_send_ack_dp(struct drbd_peer_device *peer_device, enum drbd_packet cmd
struct p_data *dp, int data_size)
{
if (peer_device->connection->peer_integrity_tfm)
- data_size -= crypto_ahash_digestsize(peer_device->connection->peer_integrity_tfm);
+ data_size -= crypto_shash_digestsize(peer_device->connection->peer_integrity_tfm);
_drbd_send_ack(peer_device, cmd, dp->sector, cpu_to_be32(data_size),
dp->block_id);
}
@@ -1673,7 +1673,7 @@ static u32 bio_flags_to_wire(struct drbd_connection *connection,
return bio->bi_opf & REQ_SYNC ? DP_RW_SYNC : 0;
}
-/* Used to send write or TRIM aka REQ_DISCARD requests
+/* Used to send write or TRIM aka REQ_OP_DISCARD requests
* R_PRIMARY -> Peer (P_DATA, P_TRIM)
*/
int drbd_send_dblock(struct drbd_peer_device *peer_device, struct drbd_request *req)
@@ -1690,7 +1690,7 @@ int drbd_send_dblock(struct drbd_peer_device *peer_device, struct drbd_request *
sock = &peer_device->connection->data;
p = drbd_prepare_command(peer_device, sock);
digest_size = peer_device->connection->integrity_tfm ?
- crypto_ahash_digestsize(peer_device->connection->integrity_tfm) : 0;
+ crypto_shash_digestsize(peer_device->connection->integrity_tfm) : 0;
if (!p)
return -EIO;
@@ -1796,7 +1796,7 @@ int drbd_send_block(struct drbd_peer_device *peer_device, enum drbd_packet cmd,
p = drbd_prepare_command(peer_device, sock);
digest_size = peer_device->connection->integrity_tfm ?
- crypto_ahash_digestsize(peer_device->connection->integrity_tfm) : 0;
+ crypto_shash_digestsize(peer_device->connection->integrity_tfm) : 0;
if (!p)
return -EIO;
@@ -1856,7 +1856,7 @@ int drbd_send(struct drbd_connection *connection, struct socket *sock,
/* THINK if (signal_pending) return ... ? */
- iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, &iov, 1, size);
+ iov_iter_kvec(&msg.msg_iter, WRITE, &iov, 1, size);
if (sock == connection->data.socket) {
rcu_read_lock();
@@ -2557,11 +2557,11 @@ void conn_free_crypto(struct drbd_connection *connection)
{
drbd_free_sock(connection);
- crypto_free_ahash(connection->csums_tfm);
- crypto_free_ahash(connection->verify_tfm);
+ crypto_free_shash(connection->csums_tfm);
+ crypto_free_shash(connection->verify_tfm);
crypto_free_shash(connection->cram_hmac_tfm);
- crypto_free_ahash(connection->integrity_tfm);
- crypto_free_ahash(connection->peer_integrity_tfm);
+ crypto_free_shash(connection->integrity_tfm);
+ crypto_free_shash(connection->peer_integrity_tfm);
kfree(connection->int_dig_in);
kfree(connection->int_dig_vv);
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index b4f02768ba47..d15703b1ffe8 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -2303,10 +2303,10 @@ check_net_options(struct drbd_connection *connection, struct net_conf *new_net_c
}
struct crypto {
- struct crypto_ahash *verify_tfm;
- struct crypto_ahash *csums_tfm;
+ struct crypto_shash *verify_tfm;
+ struct crypto_shash *csums_tfm;
struct crypto_shash *cram_hmac_tfm;
- struct crypto_ahash *integrity_tfm;
+ struct crypto_shash *integrity_tfm;
};
static int
@@ -2324,36 +2324,21 @@ alloc_shash(struct crypto_shash **tfm, char *tfm_name, int err_alg)
return NO_ERROR;
}
-static int
-alloc_ahash(struct crypto_ahash **tfm, char *tfm_name, int err_alg)
-{
- if (!tfm_name[0])
- return NO_ERROR;
-
- *tfm = crypto_alloc_ahash(tfm_name, 0, CRYPTO_ALG_ASYNC);
- if (IS_ERR(*tfm)) {
- *tfm = NULL;
- return err_alg;
- }
-
- return NO_ERROR;
-}
-
static enum drbd_ret_code
alloc_crypto(struct crypto *crypto, struct net_conf *new_net_conf)
{
char hmac_name[CRYPTO_MAX_ALG_NAME];
enum drbd_ret_code rv;
- rv = alloc_ahash(&crypto->csums_tfm, new_net_conf->csums_alg,
+ rv = alloc_shash(&crypto->csums_tfm, new_net_conf->csums_alg,
ERR_CSUMS_ALG);
if (rv != NO_ERROR)
return rv;
- rv = alloc_ahash(&crypto->verify_tfm, new_net_conf->verify_alg,
+ rv = alloc_shash(&crypto->verify_tfm, new_net_conf->verify_alg,
ERR_VERIFY_ALG);
if (rv != NO_ERROR)
return rv;
- rv = alloc_ahash(&crypto->integrity_tfm, new_net_conf->integrity_alg,
+ rv = alloc_shash(&crypto->integrity_tfm, new_net_conf->integrity_alg,
ERR_INTEGRITY_ALG);
if (rv != NO_ERROR)
return rv;
@@ -2371,9 +2356,9 @@ alloc_crypto(struct crypto *crypto, struct net_conf *new_net_conf)
static void free_crypto(struct crypto *crypto)
{
crypto_free_shash(crypto->cram_hmac_tfm);
- crypto_free_ahash(crypto->integrity_tfm);
- crypto_free_ahash(crypto->csums_tfm);
- crypto_free_ahash(crypto->verify_tfm);
+ crypto_free_shash(crypto->integrity_tfm);
+ crypto_free_shash(crypto->csums_tfm);
+ crypto_free_shash(crypto->verify_tfm);
}
int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info)
@@ -2450,17 +2435,17 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info)
rcu_assign_pointer(connection->net_conf, new_net_conf);
if (!rsr) {
- crypto_free_ahash(connection->csums_tfm);
+ crypto_free_shash(connection->csums_tfm);
connection->csums_tfm = crypto.csums_tfm;
crypto.csums_tfm = NULL;
}
if (!ovr) {
- crypto_free_ahash(connection->verify_tfm);
+ crypto_free_shash(connection->verify_tfm);
connection->verify_tfm = crypto.verify_tfm;
crypto.verify_tfm = NULL;
}
- crypto_free_ahash(connection->integrity_tfm);
+ crypto_free_shash(connection->integrity_tfm);
connection->integrity_tfm = crypto.integrity_tfm;
if (connection->cstate >= C_WF_REPORT_PARAMS && connection->agreed_pro_version >= 100)
/* Do this without trying to take connection->data.mutex again. */
diff --git a/drivers/block/drbd/drbd_protocol.h b/drivers/block/drbd/drbd_protocol.h
index c3081f93051c..48dabbb21e11 100644
--- a/drivers/block/drbd/drbd_protocol.h
+++ b/drivers/block/drbd/drbd_protocol.h
@@ -57,7 +57,7 @@ enum drbd_packet {
P_PROTOCOL_UPDATE = 0x2d, /* data sock: is used in established connections */
/* 0x2e to 0x30 reserved, used in drbd 9 */
- /* REQ_DISCARD. We used "discard" in different contexts before,
+ /* REQ_OP_DISCARD. We used "discard" in different contexts before,
* which is why I chose TRIM here, to disambiguate. */
P_TRIM = 0x31,
@@ -126,7 +126,7 @@ struct p_header100 {
#define DP_UNPLUG 8 /* not used anymore */
#define DP_FUA 16 /* equals REQ_FUA */
#define DP_FLUSH 32 /* equals REQ_PREFLUSH */
-#define DP_DISCARD 64 /* equals REQ_DISCARD */
+#define DP_DISCARD 64 /* equals REQ_OP_DISCARD */
#define DP_SEND_RECEIVE_ACK 128 /* This is a proto B write request */
#define DP_SEND_WRITE_ACK 256 /* This is a proto C write request */
#define DP_WSAME 512 /* equiv. REQ_WRITE_SAME */
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c
index 75f6b47169e6..61c392752fe4 100644
--- a/drivers/block/drbd/drbd_receiver.c
+++ b/drivers/block/drbd/drbd_receiver.c
@@ -516,7 +516,7 @@ static int drbd_recv_short(struct socket *sock, void *buf, size_t size, int flag
struct msghdr msg = {
.msg_flags = (flags ? flags : MSG_WAITALL | MSG_NOSIGNAL)
};
- iov_iter_kvec(&msg.msg_iter, READ | ITER_KVEC, &iov, 1, size);
+ iov_iter_kvec(&msg.msg_iter, READ, &iov, 1, size);
return sock_recvmsg(sock, &msg, msg.msg_flags);
}
@@ -1732,7 +1732,7 @@ static int receive_Barrier(struct drbd_connection *connection, struct packet_inf
}
/* quick wrapper in case payload size != request_size (write same) */
-static void drbd_csum_ee_size(struct crypto_ahash *h,
+static void drbd_csum_ee_size(struct crypto_shash *h,
struct drbd_peer_request *r, void *d,
unsigned int payload_size)
{
@@ -1769,7 +1769,7 @@ read_in_block(struct drbd_peer_device *peer_device, u64 id, sector_t sector,
digest_size = 0;
if (!trim && peer_device->connection->peer_integrity_tfm) {
- digest_size = crypto_ahash_digestsize(peer_device->connection->peer_integrity_tfm);
+ digest_size = crypto_shash_digestsize(peer_device->connection->peer_integrity_tfm);
/*
* FIXME: Receive the incoming digest into the receive buffer
* here, together with its struct p_data?
@@ -1905,7 +1905,7 @@ static int recv_dless_read(struct drbd_peer_device *peer_device, struct drbd_req
digest_size = 0;
if (peer_device->connection->peer_integrity_tfm) {
- digest_size = crypto_ahash_digestsize(peer_device->connection->peer_integrity_tfm);
+ digest_size = crypto_shash_digestsize(peer_device->connection->peer_integrity_tfm);
err = drbd_recv_all_warn(peer_device->connection, dig_in, digest_size);
if (err)
return err;
@@ -3542,7 +3542,7 @@ static int receive_protocol(struct drbd_connection *connection, struct packet_in
int p_proto, p_discard_my_data, p_two_primaries, cf;
struct net_conf *nc, *old_net_conf, *new_net_conf = NULL;
char integrity_alg[SHARED_SECRET_MAX] = "";
- struct crypto_ahash *peer_integrity_tfm = NULL;
+ struct crypto_shash *peer_integrity_tfm = NULL;
void *int_dig_in = NULL, *int_dig_vv = NULL;
p_proto = be32_to_cpu(p->protocol);
@@ -3623,7 +3623,7 @@ static int receive_protocol(struct drbd_connection *connection, struct packet_in
* change.
*/
- peer_integrity_tfm = crypto_alloc_ahash(integrity_alg, 0, CRYPTO_ALG_ASYNC);
+ peer_integrity_tfm = crypto_alloc_shash(integrity_alg, 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(peer_integrity_tfm)) {
peer_integrity_tfm = NULL;
drbd_err(connection, "peer data-integrity-alg %s not supported\n",
@@ -3631,7 +3631,7 @@ static int receive_protocol(struct drbd_connection *connection, struct packet_in
goto disconnect;
}
- hash_size = crypto_ahash_digestsize(peer_integrity_tfm);
+ hash_size = crypto_shash_digestsize(peer_integrity_tfm);
int_dig_in = kmalloc(hash_size, GFP_KERNEL);
int_dig_vv = kmalloc(hash_size, GFP_KERNEL);
if (!(int_dig_in && int_dig_vv)) {
@@ -3661,7 +3661,7 @@ static int receive_protocol(struct drbd_connection *connection, struct packet_in
mutex_unlock(&connection->resource->conf_update);
mutex_unlock(&connection->data.mutex);
- crypto_free_ahash(connection->peer_integrity_tfm);
+ crypto_free_shash(connection->peer_integrity_tfm);
kfree(connection->int_dig_in);
kfree(connection->int_dig_vv);
connection->peer_integrity_tfm = peer_integrity_tfm;
@@ -3679,7 +3679,7 @@ static int receive_protocol(struct drbd_connection *connection, struct packet_in
disconnect_rcu_unlock:
rcu_read_unlock();
disconnect:
- crypto_free_ahash(peer_integrity_tfm);
+ crypto_free_shash(peer_integrity_tfm);
kfree(int_dig_in);
kfree(int_dig_vv);
conn_request_state(connection, NS(conn, C_DISCONNECTING), CS_HARD);
@@ -3691,15 +3691,16 @@ disconnect:
* return: NULL (alg name was "")
* ERR_PTR(error) if something goes wrong
* or the crypto hash ptr, if it worked out ok. */
-static struct crypto_ahash *drbd_crypto_alloc_digest_safe(const struct drbd_device *device,
+static struct crypto_shash *drbd_crypto_alloc_digest_safe(
+ const struct drbd_device *device,
const char *alg, const char *name)
{
- struct crypto_ahash *tfm;
+ struct crypto_shash *tfm;
if (!alg[0])
return NULL;
- tfm = crypto_alloc_ahash(alg, 0, CRYPTO_ALG_ASYNC);
+ tfm = crypto_alloc_shash(alg, 0, 0);
if (IS_ERR(tfm)) {
drbd_err(device, "Can not allocate \"%s\" as %s (reason: %ld)\n",
alg, name, PTR_ERR(tfm));
@@ -3752,8 +3753,8 @@ static int receive_SyncParam(struct drbd_connection *connection, struct packet_i
struct drbd_device *device;
struct p_rs_param_95 *p;
unsigned int header_size, data_size, exp_max_sz;
- struct crypto_ahash *verify_tfm = NULL;
- struct crypto_ahash *csums_tfm = NULL;
+ struct crypto_shash *verify_tfm = NULL;
+ struct crypto_shash *csums_tfm = NULL;
struct net_conf *old_net_conf, *new_net_conf = NULL;
struct disk_conf *old_disk_conf = NULL, *new_disk_conf = NULL;
const int apv = connection->agreed_pro_version;
@@ -3900,14 +3901,14 @@ static int receive_SyncParam(struct drbd_connection *connection, struct packet_i
if (verify_tfm) {
strcpy(new_net_conf->verify_alg, p->verify_alg);
new_net_conf->verify_alg_len = strlen(p->verify_alg) + 1;
- crypto_free_ahash(peer_device->connection->verify_tfm);
+ crypto_free_shash(peer_device->connection->verify_tfm);
peer_device->connection->verify_tfm = verify_tfm;
drbd_info(device, "using verify-alg: \"%s\"\n", p->verify_alg);
}
if (csums_tfm) {
strcpy(new_net_conf->csums_alg, p->csums_alg);
new_net_conf->csums_alg_len = strlen(p->csums_alg) + 1;
- crypto_free_ahash(peer_device->connection->csums_tfm);
+ crypto_free_shash(peer_device->connection->csums_tfm);
peer_device->connection->csums_tfm = csums_tfm;
drbd_info(device, "using csums-alg: \"%s\"\n", p->csums_alg);
}
@@ -3951,9 +3952,9 @@ disconnect:
mutex_unlock(&connection->resource->conf_update);
/* just for completeness: actually not needed,
* as this is not reached if csums_tfm was ok. */
- crypto_free_ahash(csums_tfm);
+ crypto_free_shash(csums_tfm);
/* but free the verify_tfm again, if csums_tfm did not work out */
- crypto_free_ahash(verify_tfm);
+ crypto_free_shash(verify_tfm);
conn_request_state(peer_device->connection, NS(conn, C_DISCONNECTING), CS_HARD);
return -EIO;
}
diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c
index 19cac36e9737..1c4da17e902e 100644
--- a/drivers/block/drbd/drbd_req.c
+++ b/drivers/block/drbd/drbd_req.c
@@ -650,7 +650,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
case DISCARD_COMPLETED_NOTSUPP:
case DISCARD_COMPLETED_WITH_ERROR:
/* I'd rather not detach from local disk just because it
- * failed a REQ_DISCARD. */
+ * failed a REQ_OP_DISCARD. */
mod_rq_state(req, m, RQ_LOCAL_PENDING, RQ_LOCAL_COMPLETED);
break;
diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c
index b8f77e83d456..99255d0c9e2f 100644
--- a/drivers/block/drbd/drbd_worker.c
+++ b/drivers/block/drbd/drbd_worker.c
@@ -152,7 +152,7 @@ void drbd_endio_write_sec_final(struct drbd_peer_request *peer_req) __releases(l
do_wake = list_empty(block_id == ID_SYNCER ? &device->sync_ee : &device->active_ee);
- /* FIXME do we want to detach for failed REQ_DISCARD?
+ /* FIXME do we want to detach for failed REQ_OP_DISCARD?
* ((peer_req->flags & (EE_WAS_ERROR|EE_IS_TRIM)) == EE_WAS_ERROR) */
if (peer_req->flags & EE_WAS_ERROR)
__drbd_chk_io_error(device, DRBD_WRITE_ERROR);
@@ -295,60 +295,61 @@ void drbd_request_endio(struct bio *bio)
complete_master_bio(device, &m);
}
-void drbd_csum_ee(struct crypto_ahash *tfm, struct drbd_peer_request *peer_req, void *digest)
+void drbd_csum_ee(struct crypto_shash *tfm, struct drbd_peer_request *peer_req, void *digest)
{
- AHASH_REQUEST_ON_STACK(req, tfm);
- struct scatterlist sg;
+ SHASH_DESC_ON_STACK(desc, tfm);
struct page *page = peer_req->pages;
struct page *tmp;
unsigned len;
+ void *src;
- ahash_request_set_tfm(req, tfm);
- ahash_request_set_callback(req, 0, NULL, NULL);
+ desc->tfm = tfm;
+ desc->flags = 0;
- sg_init_table(&sg, 1);
- crypto_ahash_init(req);
+ crypto_shash_init(desc);
+ src = kmap_atomic(page);
while ((tmp = page_chain_next(page))) {
/* all but the last page will be fully used */
- sg_set_page(&sg, page, PAGE_SIZE, 0);
- ahash_request_set_crypt(req, &sg, NULL, sg.length);
- crypto_ahash_update(req);
+ crypto_shash_update(desc, src, PAGE_SIZE);
+ kunmap_atomic(src);
page = tmp;
+ src = kmap_atomic(page);
}
/* and now the last, possibly only partially used page */
len = peer_req->i.size & (PAGE_SIZE - 1);
- sg_set_page(&sg, page, len ?: PAGE_SIZE, 0);
- ahash_request_set_crypt(req, &sg, digest, sg.length);
- crypto_ahash_finup(req);
- ahash_request_zero(req);
+ crypto_shash_update(desc, src, len ?: PAGE_SIZE);
+ kunmap_atomic(src);
+
+ crypto_shash_final(desc, digest);
+ shash_desc_zero(desc);
}
-void drbd_csum_bio(struct crypto_ahash *tfm, struct bio *bio, void *digest)
+void drbd_csum_bio(struct crypto_shash *tfm, struct bio *bio, void *digest)
{
- AHASH_REQUEST_ON_STACK(req, tfm);
- struct scatterlist sg;
+ SHASH_DESC_ON_STACK(desc, tfm);
struct bio_vec bvec;
struct bvec_iter iter;
- ahash_request_set_tfm(req, tfm);
- ahash_request_set_callback(req, 0, NULL, NULL);
+ desc->tfm = tfm;
+ desc->flags = 0;
- sg_init_table(&sg, 1);
- crypto_ahash_init(req);
+ crypto_shash_init(desc);
bio_for_each_segment(bvec, bio, iter) {
- sg_set_page(&sg, bvec.bv_page, bvec.bv_len, bvec.bv_offset);
- ahash_request_set_crypt(req, &sg, NULL, sg.length);
- crypto_ahash_update(req);
+ u8 *src;
+
+ src = kmap_atomic(bvec.bv_page);
+ crypto_shash_update(desc, src + bvec.bv_offset, bvec.bv_len);
+ kunmap_atomic(src);
+
/* REQ_OP_WRITE_SAME has only one segment,
* checksum the payload only once. */
if (bio_op(bio) == REQ_OP_WRITE_SAME)
break;
}
- ahash_request_set_crypt(req, NULL, digest, 0);
- crypto_ahash_final(req);
- ahash_request_zero(req);
+ crypto_shash_final(desc, digest);
+ shash_desc_zero(desc);
}
/* MAYBE merge common code with w_e_end_ov_req */
@@ -367,7 +368,7 @@ static int w_e_send_csum(struct drbd_work *w, int cancel)
if (unlikely((peer_req->flags & EE_WAS_ERROR) != 0))
goto out;
- digest_size = crypto_ahash_digestsize(peer_device->connection->csums_tfm);
+ digest_size = crypto_shash_digestsize(peer_device->connection->csums_tfm);
digest = kmalloc(digest_size, GFP_NOIO);
if (digest) {
sector_t sector = peer_req->i.sector;
@@ -1205,7 +1206,7 @@ int w_e_end_csum_rs_req(struct drbd_work *w, int cancel)
* a real fix would be much more involved,
* introducing more locking mechanisms */
if (peer_device->connection->csums_tfm) {
- digest_size = crypto_ahash_digestsize(peer_device->connection->csums_tfm);
+ digest_size = crypto_shash_digestsize(peer_device->connection->csums_tfm);
D_ASSERT(device, digest_size == di->digest_size);
digest = kmalloc(digest_size, GFP_NOIO);
}
@@ -1255,7 +1256,7 @@ int w_e_end_ov_req(struct drbd_work *w, int cancel)
if (unlikely(cancel))
goto out;
- digest_size = crypto_ahash_digestsize(peer_device->connection->verify_tfm);
+ digest_size = crypto_shash_digestsize(peer_device->connection->verify_tfm);
digest = kmalloc(digest_size, GFP_NOIO);
if (!digest) {
err = 1; /* terminate the connection in case the allocation failed */
@@ -1327,7 +1328,7 @@ int w_e_end_ov_reply(struct drbd_work *w, int cancel)
di = peer_req->digest;
if (likely((peer_req->flags & EE_WAS_ERROR) == 0)) {
- digest_size = crypto_ahash_digestsize(peer_device->connection->verify_tfm);
+ digest_size = crypto_shash_digestsize(peer_device->connection->verify_tfm);
digest = kmalloc(digest_size, GFP_NOIO);
if (digest) {
drbd_csum_ee(peer_device->connection->verify_tfm, peer_req, digest);
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index f2b6f4da1034..fb23578e9a41 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -252,13 +252,13 @@ static int allowed_drive_mask = 0x33;
static int irqdma_allocated;
-#include <linux/blkdev.h>
+#include <linux/blk-mq.h>
#include <linux/blkpg.h>
#include <linux/cdrom.h> /* for the compatibility eject ioctl */
#include <linux/completion.h>
+static LIST_HEAD(floppy_reqs);
static struct request *current_req;
-static void do_fd_request(struct request_queue *q);
static int set_next_request(void);
#ifndef fd_get_dma_residue
@@ -414,10 +414,10 @@ static struct floppy_drive_struct drive_state[N_DRIVE];
static struct floppy_write_errors write_errors[N_DRIVE];
static struct timer_list motor_off_timer[N_DRIVE];
static struct gendisk *disks[N_DRIVE];
+static struct blk_mq_tag_set tag_sets[N_DRIVE];
static struct block_device *opened_bdev[N_DRIVE];
static DEFINE_MUTEX(open_lock);
static struct floppy_raw_cmd *raw_cmd, default_raw_cmd;
-static int fdc_queue;
/*
* This struct defines the different floppy types.
@@ -2216,8 +2216,9 @@ static void floppy_end_request(struct request *req, blk_status_t error)
/* current_count_sectors can be zero if transfer failed */
if (error)
nr_sectors = blk_rq_cur_sectors(req);
- if (__blk_end_request(req, error, nr_sectors << 9))
+ if (blk_update_request(req, error, nr_sectors << 9))
return;
+ __blk_mq_end_request(req, error);
/* We're done with the request */
floppy_off(drive);
@@ -2797,27 +2798,14 @@ static int make_raw_rw_request(void)
return 2;
}
-/*
- * Round-robin between our available drives, doing one request from each
- */
static int set_next_request(void)
{
- struct request_queue *q;
- int old_pos = fdc_queue;
-
- do {
- q = disks[fdc_queue]->queue;
- if (++fdc_queue == N_DRIVE)
- fdc_queue = 0;
- if (q) {
- current_req = blk_fetch_request(q);
- if (current_req) {
- current_req->error_count = 0;
- break;
- }
- }
- } while (fdc_queue != old_pos);
-
+ current_req = list_first_entry_or_null(&floppy_reqs, struct request,
+ queuelist);
+ if (current_req) {
+ current_req->error_count = 0;
+ list_del_init(&current_req->queuelist);
+ }
return current_req != NULL;
}
@@ -2901,29 +2889,38 @@ static void process_fd_request(void)
schedule_bh(redo_fd_request);
}
-static void do_fd_request(struct request_queue *q)
+static blk_status_t floppy_queue_rq(struct blk_mq_hw_ctx *hctx,
+ const struct blk_mq_queue_data *bd)
{
+ blk_mq_start_request(bd->rq);
+
if (WARN(max_buffer_sectors == 0,
"VFS: %s called on non-open device\n", __func__))
- return;
+ return BLK_STS_IOERR;
if (WARN(atomic_read(&usage_count) == 0,
"warning: usage count=0, current_req=%p sect=%ld flags=%llx\n",
current_req, (long)blk_rq_pos(current_req),
(unsigned long long) current_req->cmd_flags))
- return;
+ return BLK_STS_IOERR;
+
+ spin_lock_irq(&floppy_lock);
+ list_add_tail(&bd->rq->queuelist, &floppy_reqs);
+ spin_unlock_irq(&floppy_lock);
if (test_and_set_bit(0, &fdc_busy)) {
/* fdc busy, this new request will be treated when the
current one is done */
is_alive(__func__, "old request running");
- return;
+ return BLK_STS_OK;
}
+
command_status = FD_COMMAND_NONE;
__reschedule_timeout(MAXTIMEOUT, "fd_request");
set_fdc(0);
process_fd_request();
is_alive(__func__, "");
+ return BLK_STS_OK;
}
static const struct cont_t poll_cont = {
@@ -4151,10 +4148,11 @@ static int __floppy_read_block_0(struct block_device *bdev, int drive)
bio.bi_end_io = floppy_rb0_cb;
bio_set_op_attrs(&bio, REQ_OP_READ, 0);
+ init_completion(&cbdata.complete);
+
submit_bio(&bio);
process_fd_request();
- init_completion(&cbdata.complete);
wait_for_completion(&cbdata.complete);
__free_page(page);
@@ -4486,6 +4484,10 @@ static struct platform_driver floppy_driver = {
},
};
+static const struct blk_mq_ops floppy_mq_ops = {
+ .queue_rq = floppy_queue_rq,
+};
+
static struct platform_device floppy_device[N_DRIVE];
static bool floppy_available(int drive)
@@ -4533,9 +4535,12 @@ static int __init do_floppy_init(void)
goto out_put_disk;
}
- disks[drive]->queue = blk_init_queue(do_fd_request, &floppy_lock);
- if (!disks[drive]->queue) {
- err = -ENOMEM;
+ disks[drive]->queue = blk_mq_init_sq_queue(&tag_sets[drive],
+ &floppy_mq_ops, 2,
+ BLK_MQ_F_SHOULD_MERGE);
+ if (IS_ERR(disks[drive]->queue)) {
+ err = PTR_ERR(disks[drive]->queue);
+ disks[drive]->queue = NULL;
goto out_put_disk;
}
@@ -4679,7 +4684,7 @@ static int __init do_floppy_init(void)
/* to be cleaned up... */
disks[drive]->private_data = (void *)(long)drive;
disks[drive]->flags |= GENHD_FL_REMOVABLE;
- device_add_disk(&floppy_device[drive].dev, disks[drive]);
+ device_add_disk(&floppy_device[drive].dev, disks[drive], NULL);
}
return 0;
@@ -4708,6 +4713,7 @@ out_put_disk:
del_timer_sync(&motor_off_timer[drive]);
blk_cleanup_queue(disks[drive]->queue);
disks[drive]->queue = NULL;
+ blk_mq_free_tag_set(&tag_sets[drive]);
}
put_disk(disks[drive]);
}
@@ -4935,6 +4941,7 @@ static void __exit floppy_module_exit(void)
platform_device_unregister(&floppy_device[drive]);
}
blk_cleanup_queue(disks[drive]->queue);
+ blk_mq_free_tag_set(&tag_sets[drive]);
/*
* These disks have not called add_disk(). Don't put down
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index ea9debf59b22..cb0cc8685076 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -268,7 +268,7 @@ static int lo_write_bvec(struct file *file, struct bio_vec *bvec, loff_t *ppos)
struct iov_iter i;
ssize_t bw;
- iov_iter_bvec(&i, ITER_BVEC | WRITE, bvec, 1, bvec->bv_len);
+ iov_iter_bvec(&i, WRITE, bvec, 1, bvec->bv_len);
file_start_write(file);
bw = vfs_iter_write(file, &i, ppos, 0);
@@ -346,7 +346,7 @@ static int lo_read_simple(struct loop_device *lo, struct request *rq,
ssize_t len;
rq_for_each_segment(bvec, rq, iter) {
- iov_iter_bvec(&i, ITER_BVEC, &bvec, 1, bvec.bv_len);
+ iov_iter_bvec(&i, READ, &bvec, 1, bvec.bv_len);
len = vfs_iter_read(lo->lo_backing_file, &i, &pos, 0);
if (len < 0)
return len;
@@ -387,7 +387,7 @@ static int lo_read_transfer(struct loop_device *lo, struct request *rq,
b.bv_offset = 0;
b.bv_len = bvec.bv_len;
- iov_iter_bvec(&i, ITER_BVEC, &b, 1, b.bv_len);
+ iov_iter_bvec(&i, READ, &b, 1, b.bv_len);
len = vfs_iter_read(lo->lo_backing_file, &i, &pos, 0);
if (len < 0) {
ret = len;
@@ -554,8 +554,7 @@ static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd,
}
atomic_set(&cmd->ref, 2);
- iov_iter_bvec(&iter, ITER_BVEC | rw, bvec,
- segments, blk_rq_bytes(rq));
+ iov_iter_bvec(&iter, rw, bvec, segments, blk_rq_bytes(rq));
iter.iov_offset = offset;
cmd->iocb.ki_pos = pos;
diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c
index d0666f5ce003..a7daa8acbab3 100644
--- a/drivers/block/mtip32xx/mtip32xx.c
+++ b/drivers/block/mtip32xx/mtip32xx.c
@@ -1862,11 +1862,9 @@ static int exec_drive_taskfile(struct driver_data *dd,
if (IS_ERR(outbuf))
return PTR_ERR(outbuf);
- outbuf_dma = pci_map_single(dd->pdev,
- outbuf,
- taskout,
- DMA_TO_DEVICE);
- if (pci_dma_mapping_error(dd->pdev, outbuf_dma)) {
+ outbuf_dma = dma_map_single(&dd->pdev->dev, outbuf,
+ taskout, DMA_TO_DEVICE);
+ if (dma_mapping_error(&dd->pdev->dev, outbuf_dma)) {
err = -ENOMEM;
goto abort;
}
@@ -1880,10 +1878,9 @@ static int exec_drive_taskfile(struct driver_data *dd,
inbuf = NULL;
goto abort;
}
- inbuf_dma = pci_map_single(dd->pdev,
- inbuf,
- taskin, DMA_FROM_DEVICE);
- if (pci_dma_mapping_error(dd->pdev, inbuf_dma)) {
+ inbuf_dma = dma_map_single(&dd->pdev->dev, inbuf,
+ taskin, DMA_FROM_DEVICE);
+ if (dma_mapping_error(&dd->pdev->dev, inbuf_dma)) {
err = -ENOMEM;
goto abort;
}
@@ -1945,8 +1942,8 @@ static int exec_drive_taskfile(struct driver_data *dd,
dev_warn(&dd->pdev->dev,
"data movement but "
"sect_count is 0\n");
- err = -EINVAL;
- goto abort;
+ err = -EINVAL;
+ goto abort;
}
}
}
@@ -2002,11 +1999,11 @@ static int exec_drive_taskfile(struct driver_data *dd,
/* reclaim the DMA buffers.*/
if (inbuf_dma)
- pci_unmap_single(dd->pdev, inbuf_dma,
- taskin, DMA_FROM_DEVICE);
+ dma_unmap_single(&dd->pdev->dev, inbuf_dma, taskin,
+ DMA_FROM_DEVICE);
if (outbuf_dma)
- pci_unmap_single(dd->pdev, outbuf_dma,
- taskout, DMA_TO_DEVICE);
+ dma_unmap_single(&dd->pdev->dev, outbuf_dma, taskout,
+ DMA_TO_DEVICE);
inbuf_dma = 0;
outbuf_dma = 0;
@@ -2053,11 +2050,11 @@ static int exec_drive_taskfile(struct driver_data *dd,
}
abort:
if (inbuf_dma)
- pci_unmap_single(dd->pdev, inbuf_dma,
- taskin, DMA_FROM_DEVICE);
+ dma_unmap_single(&dd->pdev->dev, inbuf_dma, taskin,
+ DMA_FROM_DEVICE);
if (outbuf_dma)
- pci_unmap_single(dd->pdev, outbuf_dma,
- taskout, DMA_TO_DEVICE);
+ dma_unmap_single(&dd->pdev->dev, outbuf_dma, taskout,
+ DMA_TO_DEVICE);
kfree(outbuf);
kfree(inbuf);
@@ -3861,7 +3858,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);
+ device_add_disk(&dd->pdev->dev, dd->disk, NULL);
dd->bdev = bdget_disk(dd->disk, 0);
/*
@@ -4216,18 +4213,10 @@ static int mtip_pci_probe(struct pci_dev *pdev,
goto iomap_err;
}
- if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
- rv = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
-
- if (rv) {
- rv = pci_set_consistent_dma_mask(pdev,
- DMA_BIT_MASK(32));
- if (rv) {
- dev_warn(&pdev->dev,
- "64-bit DMA enable failed\n");
- goto setmask_err;
- }
- }
+ rv = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+ if (rv) {
+ dev_warn(&pdev->dev, "64-bit DMA enable failed\n");
+ goto setmask_err;
}
/* Copy the info we may need later into the private data structure. */
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 14a51254c3db..4d4d6129ff66 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -473,7 +473,7 @@ static int nbd_send_cmd(struct nbd_device *nbd, struct nbd_cmd *cmd, int index)
u32 nbd_cmd_flags = 0;
int sent = nsock->sent, skip = 0;
- iov_iter_kvec(&from, WRITE | ITER_KVEC, &iov, 1, sizeof(request));
+ iov_iter_kvec(&from, WRITE, &iov, 1, sizeof(request));
switch (req_op(req)) {
case REQ_OP_DISCARD:
@@ -564,8 +564,7 @@ send_pages:
dev_dbg(nbd_to_dev(nbd), "request %p: sending %d bytes data\n",
req, bvec.bv_len);
- iov_iter_bvec(&from, ITER_BVEC | WRITE,
- &bvec, 1, bvec.bv_len);
+ iov_iter_bvec(&from, WRITE, &bvec, 1, bvec.bv_len);
if (skip) {
if (skip >= iov_iter_count(&from)) {
skip -= iov_iter_count(&from);
@@ -624,7 +623,7 @@ static struct nbd_cmd *nbd_read_stat(struct nbd_device *nbd, int index)
int ret = 0;
reply.magic = 0;
- iov_iter_kvec(&to, READ | ITER_KVEC, &iov, 1, sizeof(reply));
+ iov_iter_kvec(&to, READ, &iov, 1, sizeof(reply));
result = sock_xmit(nbd, index, 0, &to, MSG_WAITALL, NULL);
if (result <= 0) {
if (!nbd_disconnected(config))
@@ -678,8 +677,7 @@ static struct nbd_cmd *nbd_read_stat(struct nbd_device *nbd, int index)
struct bio_vec bvec;
rq_for_each_segment(bvec, req, iter) {
- iov_iter_bvec(&to, ITER_BVEC | READ,
- &bvec, 1, bvec.bv_len);
+ iov_iter_bvec(&to, READ, &bvec, 1, bvec.bv_len);
result = sock_xmit(nbd, index, 0, &to, MSG_WAITALL, NULL);
if (result <= 0) {
dev_err(disk_to_dev(nbd->disk), "Receive data failed (result %d)\n",
@@ -1073,7 +1071,7 @@ static void send_disconnects(struct nbd_device *nbd)
for (i = 0; i < config->num_connections; i++) {
struct nbd_sock *nsock = config->socks[i];
- iov_iter_kvec(&from, WRITE | ITER_KVEC, &iov, 1, sizeof(request));
+ iov_iter_kvec(&from, WRITE, &iov, 1, sizeof(request));
mutex_lock(&nsock->tx_lock);
ret = sock_xmit(nbd, i, 1, &from, 0, NULL);
if (ret <= 0)
diff --git a/drivers/block/null_blk.h b/drivers/block/null_blk.h
index 34e0030f0592..7685df43f1ef 100644
--- a/drivers/block/null_blk.h
+++ b/drivers/block/null_blk.h
@@ -87,7 +87,9 @@ struct nullb {
#ifdef CONFIG_BLK_DEV_ZONED
int null_zone_init(struct nullb_device *dev);
void null_zone_exit(struct nullb_device *dev);
-blk_status_t null_zone_report(struct nullb *nullb, struct bio *bio);
+int null_zone_report(struct gendisk *disk, sector_t sector,
+ struct blk_zone *zones, unsigned int *nr_zones,
+ gfp_t gfp_mask);
void null_zone_write(struct nullb_cmd *cmd, sector_t sector,
unsigned int nr_sectors);
void null_zone_reset(struct nullb_cmd *cmd, sector_t sector);
@@ -97,10 +99,11 @@ static inline int null_zone_init(struct nullb_device *dev)
return -EINVAL;
}
static inline void null_zone_exit(struct nullb_device *dev) {}
-static inline blk_status_t null_zone_report(struct nullb *nullb,
- struct bio *bio)
+static inline int null_zone_report(struct gendisk *disk, sector_t sector,
+ struct blk_zone *zones,
+ unsigned int *nr_zones, gfp_t gfp_mask)
{
- return BLK_STS_NOTSUPP;
+ return -EOPNOTSUPP;
}
static inline void null_zone_write(struct nullb_cmd *cmd, sector_t sector,
unsigned int nr_sectors)
diff --git a/drivers/block/null_blk_main.c b/drivers/block/null_blk_main.c
index 093b614d6524..09339203dfba 100644
--- a/drivers/block/null_blk_main.c
+++ b/drivers/block/null_blk_main.c
@@ -606,20 +606,12 @@ static struct nullb_cmd *alloc_cmd(struct nullb_queue *nq, int can_wait)
static void end_cmd(struct nullb_cmd *cmd)
{
- struct request_queue *q = NULL;
int queue_mode = cmd->nq->dev->queue_mode;
- if (cmd->rq)
- q = cmd->rq->q;
-
switch (queue_mode) {
case NULL_Q_MQ:
blk_mq_end_request(cmd->rq, cmd->error);
return;
- case NULL_Q_RQ:
- INIT_LIST_HEAD(&cmd->rq->queuelist);
- blk_end_request_all(cmd->rq, cmd->error);
- break;
case NULL_Q_BIO:
cmd->bio->bi_status = cmd->error;
bio_endio(cmd->bio);
@@ -627,15 +619,6 @@ static void end_cmd(struct nullb_cmd *cmd)
}
free_cmd(cmd);
-
- /* Restart queue if needed, as we are freeing a tag */
- if (queue_mode == NULL_Q_RQ && blk_queue_stopped(q)) {
- unsigned long flags;
-
- spin_lock_irqsave(q->queue_lock, flags);
- blk_start_queue_async(q);
- spin_unlock_irqrestore(q->queue_lock, flags);
- }
}
static enum hrtimer_restart null_cmd_timer_expired(struct hrtimer *timer)
@@ -1136,44 +1119,14 @@ static void null_stop_queue(struct nullb *nullb)
if (nullb->dev->queue_mode == NULL_Q_MQ)
blk_mq_stop_hw_queues(q);
- else {
- spin_lock_irq(q->queue_lock);
- blk_stop_queue(q);
- spin_unlock_irq(q->queue_lock);
- }
}
static void null_restart_queue_async(struct nullb *nullb)
{
struct request_queue *q = nullb->q;
- unsigned long flags;
if (nullb->dev->queue_mode == NULL_Q_MQ)
blk_mq_start_stopped_hw_queues(q, true);
- else {
- spin_lock_irqsave(q->queue_lock, flags);
- blk_start_queue_async(q);
- spin_unlock_irqrestore(q->queue_lock, flags);
- }
-}
-
-static bool cmd_report_zone(struct nullb *nullb, struct nullb_cmd *cmd)
-{
- struct nullb_device *dev = cmd->nq->dev;
-
- if (dev->queue_mode == NULL_Q_BIO) {
- if (bio_op(cmd->bio) == REQ_OP_ZONE_REPORT) {
- cmd->error = null_zone_report(nullb, cmd->bio);
- return true;
- }
- } else {
- if (req_op(cmd->rq) == REQ_OP_ZONE_REPORT) {
- cmd->error = null_zone_report(nullb, cmd->rq->bio);
- return true;
- }
- }
-
- return false;
}
static blk_status_t null_handle_cmd(struct nullb_cmd *cmd)
@@ -1182,9 +1135,6 @@ static blk_status_t null_handle_cmd(struct nullb_cmd *cmd)
struct nullb *nullb = dev->nullb;
int err = 0;
- if (cmd_report_zone(nullb, cmd))
- goto out;
-
if (test_bit(NULLB_DEV_FL_THROTTLED, &dev->flags)) {
struct request *rq = cmd->rq;
@@ -1197,17 +1147,8 @@ static blk_status_t null_handle_cmd(struct nullb_cmd *cmd)
/* race with timer */
if (atomic_long_read(&nullb->cur_bytes) > 0)
null_restart_queue_async(nullb);
- if (dev->queue_mode == NULL_Q_RQ) {
- struct request_queue *q = nullb->q;
-
- spin_lock_irq(q->queue_lock);
- rq->rq_flags |= RQF_DONTPREP;
- blk_requeue_request(q, rq);
- spin_unlock_irq(q->queue_lock);
- return BLK_STS_OK;
- } else
- /* requeue request */
- return BLK_STS_DEV_RESOURCE;
+ /* requeue request */
+ return BLK_STS_DEV_RESOURCE;
}
}
@@ -1278,9 +1219,6 @@ out:
case NULL_Q_MQ:
blk_mq_complete_request(cmd->rq);
break;
- case NULL_Q_RQ:
- blk_complete_request(cmd->rq);
- break;
case NULL_Q_BIO:
/*
* XXX: no proper submitting cpu information available.
@@ -1349,30 +1287,6 @@ static blk_qc_t null_queue_bio(struct request_queue *q, struct bio *bio)
return BLK_QC_T_NONE;
}
-static enum blk_eh_timer_return null_rq_timed_out_fn(struct request *rq)
-{
- pr_info("null: rq %p timed out\n", rq);
- __blk_complete_request(rq);
- return BLK_EH_DONE;
-}
-
-static int null_rq_prep_fn(struct request_queue *q, struct request *req)
-{
- struct nullb *nullb = q->queuedata;
- struct nullb_queue *nq = nullb_to_queue(nullb);
- struct nullb_cmd *cmd;
-
- cmd = alloc_cmd(nq, 0);
- if (cmd) {
- cmd->rq = req;
- req->special = cmd;
- return BLKPREP_OK;
- }
- blk_stop_queue(q);
-
- return BLKPREP_DEFER;
-}
-
static bool should_timeout_request(struct request *rq)
{
#ifdef CONFIG_BLK_DEV_NULL_BLK_FAULT_INJECTION
@@ -1391,27 +1305,6 @@ static bool should_requeue_request(struct request *rq)
return false;
}
-static void null_request_fn(struct request_queue *q)
-{
- struct request *rq;
-
- while ((rq = blk_fetch_request(q)) != NULL) {
- struct nullb_cmd *cmd = rq->special;
-
- /* just ignore the request */
- if (should_timeout_request(rq))
- continue;
- if (should_requeue_request(rq)) {
- blk_requeue_request(q, rq);
- continue;
- }
-
- spin_unlock_irq(q->queue_lock);
- null_handle_cmd(cmd);
- spin_lock_irq(q->queue_lock);
- }
-}
-
static enum blk_eh_timer_return null_timeout_rq(struct request *rq, bool res)
{
pr_info("null: rq %p timed out\n", rq);
@@ -1528,6 +1421,7 @@ static const struct block_device_operations null_fops = {
.owner = THIS_MODULE,
.open = null_open,
.release = null_release,
+ .report_zones = null_zone_report,
};
static void null_init_queue(struct nullb *nullb, struct nullb_queue *nq)
@@ -1634,6 +1528,13 @@ static int null_gendisk_register(struct nullb *nullb)
disk->queue = nullb->q;
strncpy(disk->disk_name, nullb->disk_name, DISK_NAME_LEN);
+ if (nullb->dev->zoned) {
+ int ret = blk_revalidate_disk_zones(disk);
+
+ if (ret != 0)
+ return ret;
+ }
+
add_disk(disk);
return 0;
}
@@ -1766,24 +1667,6 @@ static int null_add_dev(struct nullb_device *dev)
rv = init_driver_queues(nullb);
if (rv)
goto out_cleanup_blk_queue;
- } else {
- nullb->q = blk_init_queue_node(null_request_fn, &nullb->lock,
- dev->home_node);
- if (!nullb->q) {
- rv = -ENOMEM;
- goto out_cleanup_queues;
- }
-
- if (!null_setup_fault())
- goto out_cleanup_blk_queue;
-
- blk_queue_prep_rq(nullb->q, null_rq_prep_fn);
- blk_queue_softirq_done(nullb->q, null_softirq_done_fn);
- blk_queue_rq_timed_out(nullb->q, null_rq_timed_out_fn);
- nullb->q->rq_timeout = 5 * HZ;
- rv = init_driver_queues(nullb);
- if (rv)
- goto out_cleanup_blk_queue;
}
if (dev->mbps) {
@@ -1865,6 +1748,10 @@ static int __init null_init(void)
return -EINVAL;
}
+ if (g_queue_mode == NULL_Q_RQ) {
+ pr_err("null_blk: legacy IO path no longer available\n");
+ return -EINVAL;
+ }
if (g_queue_mode == NULL_Q_MQ && g_use_per_node_hctx) {
if (g_submit_queues != nr_online_nodes) {
pr_warn("null_blk: submit_queues param is set to %u.\n",
diff --git a/drivers/block/null_blk_zoned.c b/drivers/block/null_blk_zoned.c
index 7c6b86d98700..c0b0e4a3fa8f 100644
--- a/drivers/block/null_blk_zoned.c
+++ b/drivers/block/null_blk_zoned.c
@@ -48,54 +48,27 @@ void null_zone_exit(struct nullb_device *dev)
kvfree(dev->zones);
}
-static void null_zone_fill_bio(struct nullb_device *dev, struct bio *bio,
- unsigned int zno, unsigned int nr_zones)
+int null_zone_report(struct gendisk *disk, sector_t sector,
+ struct blk_zone *zones, unsigned int *nr_zones,
+ gfp_t gfp_mask)
{
- struct blk_zone_report_hdr *hdr = NULL;
- struct bio_vec bvec;
- struct bvec_iter iter;
- void *addr;
- unsigned int zones_to_cpy;
-
- bio_for_each_segment(bvec, bio, iter) {
- addr = kmap_atomic(bvec.bv_page);
-
- zones_to_cpy = bvec.bv_len / sizeof(struct blk_zone);
-
- if (!hdr) {
- hdr = (struct blk_zone_report_hdr *)addr;
- hdr->nr_zones = nr_zones;
- zones_to_cpy--;
- addr += sizeof(struct blk_zone_report_hdr);
- }
-
- zones_to_cpy = min_t(unsigned int, zones_to_cpy, nr_zones);
-
- memcpy(addr, &dev->zones[zno],
- zones_to_cpy * sizeof(struct blk_zone));
-
- kunmap_atomic(addr);
+ struct nullb *nullb = disk->private_data;
+ struct nullb_device *dev = nullb->dev;
+ unsigned int zno, nrz = 0;
- nr_zones -= zones_to_cpy;
- zno += zones_to_cpy;
+ if (!dev->zoned)
+ /* Not a zoned null device */
+ return -EOPNOTSUPP;
- if (!nr_zones)
- break;
+ zno = null_zone_no(dev, sector);
+ if (zno < dev->nr_zones) {
+ nrz = min_t(unsigned int, *nr_zones, dev->nr_zones - zno);
+ memcpy(zones, &dev->zones[zno], nrz * sizeof(struct blk_zone));
}
-}
-blk_status_t null_zone_report(struct nullb *nullb, struct bio *bio)
-{
- struct nullb_device *dev = nullb->dev;
- unsigned int zno = null_zone_no(dev, bio->bi_iter.bi_sector);
- unsigned int nr_zones = dev->nr_zones - zno;
- unsigned int max_zones;
+ *nr_zones = nrz;
- max_zones = (bio->bi_iter.bi_size / sizeof(struct blk_zone)) - 1;
- nr_zones = min_t(unsigned int, nr_zones, max_zones);
- null_zone_fill_bio(nullb->dev, bio, zno, nr_zones);
-
- return BLK_STS_OK;
+ return 0;
}
void null_zone_write(struct nullb_cmd *cmd, sector_t sector,
diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c
index a026211afb51..96670eefaeb2 100644
--- a/drivers/block/paride/pcd.c
+++ b/drivers/block/paride/pcd.c
@@ -137,7 +137,7 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV, D_DLY};
#include <linux/delay.h>
#include <linux/cdrom.h>
#include <linux/spinlock.h>
-#include <linux/blkdev.h>
+#include <linux/blk-mq.h>
#include <linux/mutex.h>
#include <linux/uaccess.h>
@@ -186,7 +186,8 @@ static int pcd_packet(struct cdrom_device_info *cdi,
static int pcd_detect(void);
static void pcd_probe_capabilities(void);
static void do_pcd_read_drq(void);
-static void do_pcd_request(struct request_queue * q);
+static blk_status_t pcd_queue_rq(struct blk_mq_hw_ctx *hctx,
+ const struct blk_mq_queue_data *bd);
static void do_pcd_read(void);
struct pcd_unit {
@@ -199,6 +200,8 @@ struct pcd_unit {
char *name; /* pcd0, pcd1, etc */
struct cdrom_device_info info; /* uniform cdrom interface */
struct gendisk *disk;
+ struct blk_mq_tag_set tag_set;
+ struct list_head rq_list;
};
static struct pcd_unit pcd[PCD_UNITS];
@@ -292,6 +295,10 @@ static const struct cdrom_device_ops pcd_dops = {
CDC_CD_RW,
};
+static const struct blk_mq_ops pcd_mq_ops = {
+ .queue_rq = pcd_queue_rq,
+};
+
static void pcd_init_units(void)
{
struct pcd_unit *cd;
@@ -300,13 +307,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);
+
if (!disk)
continue;
- disk->queue = blk_init_queue(do_pcd_request, &pcd_lock);
- if (!disk->queue) {
- put_disk(disk);
+
+ 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;
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;
@@ -748,18 +761,18 @@ static int pcd_queue;
static int set_next_request(void)
{
struct pcd_unit *cd;
- struct request_queue *q;
int old_pos = pcd_queue;
do {
cd = &pcd[pcd_queue];
- q = cd->present ? cd->disk->queue : NULL;
if (++pcd_queue == PCD_UNITS)
pcd_queue = 0;
- if (q) {
- pcd_req = blk_fetch_request(q);
- if (pcd_req)
- break;
+ if (cd->present && !list_empty(&cd->rq_list)) {
+ pcd_req = list_first_entry(&cd->rq_list, struct request,
+ queuelist);
+ list_del_init(&pcd_req->queuelist);
+ blk_mq_start_request(pcd_req);
+ break;
}
} while (pcd_queue != old_pos);
@@ -768,33 +781,41 @@ static int set_next_request(void)
static void pcd_request(void)
{
+ struct pcd_unit *cd;
+
if (pcd_busy)
return;
- while (1) {
- if (!pcd_req && !set_next_request())
- return;
- if (rq_data_dir(pcd_req) == READ) {
- struct pcd_unit *cd = pcd_req->rq_disk->private_data;
- if (cd != pcd_current)
- pcd_bufblk = -1;
- pcd_current = cd;
- pcd_sector = blk_rq_pos(pcd_req);
- pcd_count = blk_rq_cur_sectors(pcd_req);
- pcd_buf = bio_data(pcd_req->bio);
- pcd_busy = 1;
- ps_set_intr(do_pcd_read, NULL, 0, nice);
- return;
- } else {
- __blk_end_request_all(pcd_req, BLK_STS_IOERR);
- pcd_req = NULL;
- }
- }
+ if (!pcd_req && !set_next_request())
+ return;
+
+ cd = pcd_req->rq_disk->private_data;
+ if (cd != pcd_current)
+ pcd_bufblk = -1;
+ pcd_current = cd;
+ pcd_sector = blk_rq_pos(pcd_req);
+ pcd_count = blk_rq_cur_sectors(pcd_req);
+ pcd_buf = bio_data(pcd_req->bio);
+ pcd_busy = 1;
+ ps_set_intr(do_pcd_read, NULL, 0, nice);
}
-static void do_pcd_request(struct request_queue *q)
+static blk_status_t pcd_queue_rq(struct blk_mq_hw_ctx *hctx,
+ const struct blk_mq_queue_data *bd)
{
+ struct pcd_unit *cd = hctx->queue->queuedata;
+
+ if (rq_data_dir(bd->rq) != READ) {
+ blk_mq_start_request(bd->rq);
+ return BLK_STS_IOERR;
+ }
+
+ spin_lock_irq(&pcd_lock);
+ list_add_tail(&bd->rq->queuelist, &cd->rq_list);
pcd_request();
+ spin_unlock_irq(&pcd_lock);
+
+ return BLK_STS_OK;
}
static inline void next_request(blk_status_t err)
@@ -802,8 +823,10 @@ static inline void next_request(blk_status_t err)
unsigned long saved_flags;
spin_lock_irqsave(&pcd_lock, saved_flags);
- if (!__blk_end_request_cur(pcd_req, err))
+ if (!blk_update_request(pcd_req, err, blk_rq_cur_bytes(pcd_req))) {
+ __blk_mq_end_request(pcd_req, err);
pcd_req = NULL;
+ }
pcd_busy = 0;
pcd_request();
spin_unlock_irqrestore(&pcd_lock, saved_flags);
@@ -1011,6 +1034,7 @@ static void __exit pcd_exit(void)
unregister_cdrom(&cd->info);
}
blk_cleanup_queue(cd->disk->queue);
+ blk_mq_free_tag_set(&cd->tag_set);
put_disk(cd->disk);
}
unregister_blkdev(major, name);
diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
index 7cf947586fe4..ae4971e5d9a8 100644
--- a/drivers/block/paride/pd.c
+++ b/drivers/block/paride/pd.c
@@ -151,7 +151,7 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_GEO, D_SBY, D_DLY, D_SLV};
#include <linux/delay.h>
#include <linux/hdreg.h>
#include <linux/cdrom.h> /* for the eject ioctl */
-#include <linux/blkdev.h>
+#include <linux/blk-mq.h>
#include <linux/blkpg.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
@@ -236,6 +236,8 @@ struct pd_unit {
int alt_geom;
char name[PD_NAMELEN]; /* pda, pdb, etc ... */
struct gendisk *gd;
+ struct blk_mq_tag_set tag_set;
+ struct list_head rq_list;
};
static struct pd_unit pd[PD_UNITS];
@@ -399,9 +401,17 @@ static int set_next_request(void)
if (++pd_queue == PD_UNITS)
pd_queue = 0;
if (q) {
- pd_req = blk_fetch_request(q);
- if (pd_req)
- break;
+ struct pd_unit *disk = q->queuedata;
+
+ if (list_empty(&disk->rq_list))
+ continue;
+
+ pd_req = list_first_entry(&disk->rq_list,
+ struct request,
+ queuelist);
+ list_del_init(&pd_req->queuelist);
+ blk_mq_start_request(pd_req);
+ break;
}
} while (pd_queue != old_pos);
@@ -412,7 +422,6 @@ static void run_fsm(void)
{
while (1) {
enum action res;
- unsigned long saved_flags;
int stop = 0;
if (!phase) {
@@ -433,19 +442,24 @@ static void run_fsm(void)
}
switch(res = phase()) {
- case Ok: case Fail:
+ case Ok: case Fail: {
+ blk_status_t err;
+
+ err = res == Ok ? 0 : BLK_STS_IOERR;
pi_disconnect(pi_current);
pd_claimed = 0;
phase = NULL;
- spin_lock_irqsave(&pd_lock, saved_flags);
- if (!__blk_end_request_cur(pd_req,
- res == Ok ? 0 : BLK_STS_IOERR)) {
- if (!set_next_request())
- stop = 1;
+ spin_lock_irq(&pd_lock);
+ if (!blk_update_request(pd_req, err,
+ blk_rq_cur_bytes(pd_req))) {
+ __blk_mq_end_request(pd_req, err);
+ pd_req = NULL;
+ stop = !set_next_request();
}
- spin_unlock_irqrestore(&pd_lock, saved_flags);
+ spin_unlock_irq(&pd_lock);
if (stop)
return;
+ }
/* fall through */
case Hold:
schedule_fsm();
@@ -505,11 +519,17 @@ static int pd_next_buf(void)
if (pd_count)
return 0;
spin_lock_irqsave(&pd_lock, saved_flags);
- __blk_end_request_cur(pd_req, 0);
- pd_count = blk_rq_cur_sectors(pd_req);
- pd_buf = bio_data(pd_req->bio);
+ if (!blk_update_request(pd_req, 0, blk_rq_cur_bytes(pd_req))) {
+ __blk_mq_end_request(pd_req, 0);
+ pd_req = NULL;
+ pd_count = 0;
+ pd_buf = NULL;
+ } else {
+ pd_count = blk_rq_cur_sectors(pd_req);
+ pd_buf = bio_data(pd_req->bio);
+ }
spin_unlock_irqrestore(&pd_lock, saved_flags);
- return 0;
+ return !pd_count;
}
static unsigned long pd_timeout;
@@ -726,15 +746,21 @@ static enum action pd_identify(struct pd_unit *disk)
/* end of io request engine */
-static void do_pd_request(struct request_queue * q)
+static blk_status_t pd_queue_rq(struct blk_mq_hw_ctx *hctx,
+ const struct blk_mq_queue_data *bd)
{
- if (pd_req)
- return;
- pd_req = blk_fetch_request(q);
- if (!pd_req)
- return;
+ struct pd_unit *disk = hctx->queue->queuedata;
+
+ spin_lock_irq(&pd_lock);
+ if (!pd_req) {
+ pd_req = bd->rq;
+ blk_mq_start_request(pd_req);
+ } else
+ list_add_tail(&bd->rq->queuelist, &disk->rq_list);
+ spin_unlock_irq(&pd_lock);
- schedule_fsm();
+ run_fsm();
+ return BLK_STS_OK;
}
static int pd_special_command(struct pd_unit *disk,
@@ -847,23 +873,33 @@ static const struct block_device_operations pd_fops = {
/* probing */
+static const struct blk_mq_ops pd_mq_ops = {
+ .queue_rq = pd_queue_rq,
+};
+
static void pd_probe_drive(struct pd_unit *disk)
{
- struct gendisk *p = alloc_disk(1 << PD_BITS);
+ 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;
disk->gd = p;
p->private_data = disk;
- p->queue = blk_init_queue(do_pd_request, &pd_lock);
- if (!p->queue) {
- disk->gd = NULL;
- put_disk(p);
+
+ p->queue = blk_mq_init_sq_queue(&disk->tag_set, &pd_mq_ops, 2,
+ BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_BLOCKING);
+ if (IS_ERR(p->queue)) {
+ p->queue = NULL;
return;
}
+
+ p->queue->queuedata = disk;
blk_queue_max_hw_sectors(p->queue, cluster);
blk_queue_bounce_limit(p->queue, BLK_BOUNCE_HIGH);
@@ -895,6 +931,7 @@ static int pd_detect(void)
disk->standby = parm[D_SBY];
if (parm[D_PRT])
pd_drive_count++;
+ INIT_LIST_HEAD(&disk->rq_list);
}
par_drv = pi_register_driver(name);
@@ -972,6 +1009,7 @@ static void __exit pd_exit(void)
disk->gd = NULL;
del_gendisk(p);
blk_cleanup_queue(p->queue);
+ 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 eef7a91f667d..e92e7a8eeeb2 100644
--- a/drivers/block/paride/pf.c
+++ b/drivers/block/paride/pf.c
@@ -152,7 +152,7 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV, D_LUN, D_DLY};
#include <linux/hdreg.h>
#include <linux/cdrom.h>
#include <linux/spinlock.h>
-#include <linux/blkdev.h>
+#include <linux/blk-mq.h>
#include <linux/blkpg.h>
#include <linux/mutex.h>
#include <linux/uaccess.h>
@@ -206,7 +206,8 @@ module_param_array(drive3, int, NULL, 0);
#define ATAPI_WRITE_10 0x2a
static int pf_open(struct block_device *bdev, fmode_t mode);
-static void do_pf_request(struct request_queue * q);
+static blk_status_t pf_queue_rq(struct blk_mq_hw_ctx *hctx,
+ const struct blk_mq_queue_data *bd);
static int pf_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg);
static int pf_getgeo(struct block_device *bdev, struct hd_geometry *geo);
@@ -238,6 +239,8 @@ struct pf_unit {
int present; /* device present ? */
char name[PF_NAMELEN]; /* pf0, pf1, ... */
struct gendisk *disk;
+ struct blk_mq_tag_set tag_set;
+ struct list_head rq_list;
};
static struct pf_unit units[PF_UNITS];
@@ -277,6 +280,10 @@ static const struct block_device_operations pf_fops = {
.check_events = pf_check_events,
};
+static const struct blk_mq_ops pf_mq_ops = {
+ .queue_rq = pf_queue_rq,
+};
+
static void __init pf_init_units(void)
{
struct pf_unit *pf;
@@ -284,14 +291,22 @@ static void __init pf_init_units(void)
pf_drive_count = 0;
for (unit = 0, pf = units; unit < PF_UNITS; unit++, pf++) {
- struct gendisk *disk = alloc_disk(1);
+ struct gendisk *disk;
+
+ disk = alloc_disk(1);
if (!disk)
continue;
- disk->queue = blk_init_queue(do_pf_request, &pf_spin_lock);
- if (!disk->queue) {
+
+ disk->queue = blk_mq_init_sq_queue(&pf->tag_set, &pf_mq_ops,
+ 1, BLK_MQ_F_SHOULD_MERGE);
+ if (IS_ERR(disk->queue)) {
put_disk(disk);
- return;
+ disk->queue = NULL;
+ 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;
@@ -784,18 +799,18 @@ static int pf_queue;
static int set_next_request(void)
{
struct pf_unit *pf;
- struct request_queue *q;
int old_pos = pf_queue;
do {
pf = &units[pf_queue];
- q = pf->present ? pf->disk->queue : NULL;
if (++pf_queue == PF_UNITS)
pf_queue = 0;
- if (q) {
- pf_req = blk_fetch_request(q);
- if (pf_req)
- break;
+ if (pf->present && !list_empty(&pf->rq_list)) {
+ pf_req = list_first_entry(&pf->rq_list, struct request,
+ queuelist);
+ list_del_init(&pf_req->queuelist);
+ blk_mq_start_request(pf_req);
+ break;
}
} while (pf_queue != old_pos);
@@ -804,8 +819,12 @@ static int set_next_request(void)
static void pf_end_request(blk_status_t err)
{
- if (pf_req && !__blk_end_request_cur(pf_req, err))
+ if (!pf_req)
+ return;
+ if (!blk_update_request(pf_req, err, blk_rq_cur_bytes(pf_req))) {
+ __blk_mq_end_request(pf_req, err);
pf_req = NULL;
+ }
}
static void pf_request(void)
@@ -842,9 +861,17 @@ repeat:
}
}
-static void do_pf_request(struct request_queue *q)
+static blk_status_t pf_queue_rq(struct blk_mq_hw_ctx *hctx,
+ const struct blk_mq_queue_data *bd)
{
+ struct pf_unit *pf = hctx->queue->queuedata;
+
+ spin_lock_irq(&pf_spin_lock);
+ list_add_tail(&bd->rq->queuelist, &pf->rq_list);
pf_request();
+ spin_unlock_irq(&pf_spin_lock);
+
+ return BLK_STS_OK;
}
static int pf_next_buf(void)
@@ -1024,6 +1051,7 @@ static void __exit pf_exit(void)
continue;
del_gendisk(pf->disk);
blk_cleanup_queue(pf->disk->queue);
+ blk_mq_free_tag_set(&pf->tag_set);
put_disk(pf->disk);
pi_release(pf->pi);
}
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 6f1d25c1eb64..9381f4e3b221 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -2645,7 +2645,7 @@ static int pkt_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
*/
if (pd->refcnt == 1)
pkt_lock_door(pd, 0);
- /* fallthru */
+ /* fall through */
/*
* forward selected CDROM ioctls to CD-ROM, for UDF
*/
diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c
index afe1508d82c6..4e1d9b31f60c 100644
--- a/drivers/block/ps3disk.c
+++ b/drivers/block/ps3disk.c
@@ -19,7 +19,7 @@
*/
#include <linux/ata.h>
-#include <linux/blkdev.h>
+#include <linux/blk-mq.h>
#include <linux/slab.h>
#include <linux/module.h>
@@ -42,6 +42,7 @@
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;
struct request *req;
@@ -118,8 +119,8 @@ static void ps3disk_scatter_gather(struct ps3_storage_device *dev,
}
}
-static int ps3disk_submit_request_sg(struct ps3_storage_device *dev,
- struct request *req)
+static blk_status_t ps3disk_submit_request_sg(struct ps3_storage_device *dev,
+ struct request *req)
{
struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
int write = rq_data_dir(req), res;
@@ -158,16 +159,15 @@ static int ps3disk_submit_request_sg(struct ps3_storage_device *dev,
if (res) {
dev_err(&dev->sbd.core, "%s:%u: %s failed %d\n", __func__,
__LINE__, op, res);
- __blk_end_request_all(req, BLK_STS_IOERR);
- return 0;
+ return BLK_STS_IOERR;
}
priv->req = req;
- return 1;
+ return BLK_STS_OK;
}
-static int ps3disk_submit_flush_request(struct ps3_storage_device *dev,
- struct request *req)
+static blk_status_t ps3disk_submit_flush_request(struct ps3_storage_device *dev,
+ struct request *req)
{
struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
u64 res;
@@ -180,50 +180,45 @@ static int ps3disk_submit_flush_request(struct ps3_storage_device *dev,
if (res) {
dev_err(&dev->sbd.core, "%s:%u: sync cache failed 0x%llx\n",
__func__, __LINE__, res);
- __blk_end_request_all(req, BLK_STS_IOERR);
- return 0;
+ return BLK_STS_IOERR;
}
priv->req = req;
- return 1;
+ return BLK_STS_OK;
}
-static void ps3disk_do_request(struct ps3_storage_device *dev,
- struct request_queue *q)
+static blk_status_t ps3disk_do_request(struct ps3_storage_device *dev,
+ struct request *req)
{
- struct request *req;
-
dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__);
- while ((req = blk_fetch_request(q))) {
- switch (req_op(req)) {
- case REQ_OP_FLUSH:
- if (ps3disk_submit_flush_request(dev, req))
- return;
- break;
- case REQ_OP_READ:
- case REQ_OP_WRITE:
- if (ps3disk_submit_request_sg(dev, req))
- return;
- break;
- default:
- blk_dump_rq_flags(req, DEVICE_NAME " bad request");
- __blk_end_request_all(req, BLK_STS_IOERR);
- }
+ switch (req_op(req)) {
+ case REQ_OP_FLUSH:
+ return ps3disk_submit_flush_request(dev, req);
+ case REQ_OP_READ:
+ case REQ_OP_WRITE:
+ return ps3disk_submit_request_sg(dev, req);
+ default:
+ blk_dump_rq_flags(req, DEVICE_NAME " bad request");
+ return BLK_STS_IOERR;
}
}
-static void ps3disk_request(struct request_queue *q)
+static blk_status_t ps3disk_queue_rq(struct blk_mq_hw_ctx *hctx,
+ const struct blk_mq_queue_data *bd)
{
+ struct request_queue *q = hctx->queue;
struct ps3_storage_device *dev = q->queuedata;
struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
+ blk_status_t ret;
- if (priv->req) {
- dev_dbg(&dev->sbd.core, "%s:%u busy\n", __func__, __LINE__);
- return;
- }
+ blk_mq_start_request(bd->rq);
+
+ spin_lock_irq(&priv->lock);
+ ret = ps3disk_do_request(dev, bd->rq);
+ spin_unlock_irq(&priv->lock);
- ps3disk_do_request(dev, q);
+ return ret;
}
static irqreturn_t ps3disk_interrupt(int irq, void *data)
@@ -280,11 +275,11 @@ static irqreturn_t ps3disk_interrupt(int irq, void *data)
}
spin_lock(&priv->lock);
- __blk_end_request_all(req, error);
priv->req = NULL;
- ps3disk_do_request(dev, priv->queue);
+ blk_mq_end_request(req, error);
spin_unlock(&priv->lock);
+ blk_mq_run_hw_queues(priv->queue, true);
return IRQ_HANDLED;
}
@@ -404,6 +399,10 @@ static unsigned long ps3disk_mask;
static DEFINE_MUTEX(ps3disk_mask_mutex);
+static const struct blk_mq_ops ps3disk_mq_ops = {
+ .queue_rq = ps3disk_queue_rq,
+};
+
static int ps3disk_probe(struct ps3_system_bus_device *_dev)
{
struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
@@ -454,11 +453,12 @@ static int ps3disk_probe(struct ps3_system_bus_device *_dev)
ps3disk_identify(dev);
- queue = blk_init_queue(ps3disk_request, &priv->lock);
- if (!queue) {
- dev_err(&dev->sbd.core, "%s:%u: blk_init_queue failed\n",
+ queue = blk_mq_init_sq_queue(&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 = -ENOMEM;
+ error = PTR_ERR(queue);
goto fail_teardown;
}
@@ -500,11 +500,12 @@ static int ps3disk_probe(struct ps3_system_bus_device *_dev)
gendisk->disk_name, priv->model, priv->raw_capacity >> 11,
get_capacity(gendisk) >> 11);
- device_add_disk(&dev->sbd.core, gendisk);
+ device_add_disk(&dev->sbd.core, gendisk, NULL);
return 0;
fail_cleanup_queue:
blk_cleanup_queue(queue);
+ blk_mq_free_tag_set(&priv->tag_set);
fail_teardown:
ps3stor_teardown(dev);
fail_free_bounce:
@@ -530,6 +531,7 @@ static int ps3disk_remove(struct ps3_system_bus_device *_dev)
mutex_unlock(&ps3disk_mask_mutex);
del_gendisk(priv->gendisk);
blk_cleanup_queue(priv->queue);
+ 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);
diff --git a/drivers/block/ps3vram.c b/drivers/block/ps3vram.c
index 1e3d5de9d838..c0c50816a10b 100644
--- a/drivers/block/ps3vram.c
+++ b/drivers/block/ps3vram.c
@@ -769,7 +769,7 @@ static int ps3vram_probe(struct ps3_system_bus_device *dev)
dev_info(&dev->core, "%s: Using %lu MiB of GPU memory\n",
gendisk->disk_name, get_capacity(gendisk) >> 11);
- device_add_disk(&dev->core, gendisk);
+ device_add_disk(&dev->core, gendisk, NULL);
return 0;
fail_cleanup_queue:
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index 73ed5f3a862d..8e5140bbf241 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -1500,9 +1500,6 @@ rbd_osd_req_create(struct rbd_obj_request *obj_req, unsigned int num_ops)
rbd_dev->header.object_prefix, obj_req->ex.oe_objno))
goto err_req;
- if (ceph_osdc_alloc_messages(req, GFP_NOIO))
- goto err_req;
-
return req;
err_req:
@@ -1945,6 +1942,10 @@ static int __rbd_img_fill_request(struct rbd_img_request *img_req)
}
if (ret)
return ret;
+
+ ret = ceph_osdc_alloc_messages(obj_req->osd_req, GFP_NOIO);
+ if (ret)
+ return ret;
}
return 0;
@@ -2374,8 +2375,7 @@ static int rbd_obj_issue_copyup(struct rbd_obj_request *obj_req, u32 bytes)
if (!obj_req->osd_req)
return -ENOMEM;
- ret = osd_req_op_cls_init(obj_req->osd_req, 0, CEPH_OSD_OP_CALL, "rbd",
- "copyup");
+ ret = osd_req_op_cls_init(obj_req->osd_req, 0, "rbd", "copyup");
if (ret)
return ret;
@@ -2405,6 +2405,10 @@ static int rbd_obj_issue_copyup(struct rbd_obj_request *obj_req, u32 bytes)
rbd_assert(0);
}
+ ret = ceph_osdc_alloc_messages(obj_req->osd_req, GFP_NOIO);
+ if (ret)
+ return ret;
+
rbd_obj_request_submit(obj_req);
return 0;
}
@@ -3784,10 +3788,6 @@ static int rbd_obj_read_sync(struct rbd_device *rbd_dev,
ceph_oloc_copy(&req->r_base_oloc, oloc);
req->r_flags = CEPH_OSD_FLAG_READ;
- ret = ceph_osdc_alloc_messages(req, GFP_KERNEL);
- if (ret)
- goto out_req;
-
pages = ceph_alloc_page_vector(num_pages, GFP_KERNEL);
if (IS_ERR(pages)) {
ret = PTR_ERR(pages);
@@ -3798,6 +3798,10 @@ static int rbd_obj_read_sync(struct rbd_device *rbd_dev,
osd_req_op_extent_osd_data_pages(req, 0, pages, buf_len, 0, false,
true);
+ ret = ceph_osdc_alloc_messages(req, GFP_KERNEL);
+ if (ret)
+ goto out_req;
+
ceph_osdc_start_request(osdc, req, false);
ret = ceph_osdc_wait_request(osdc, req);
if (ret >= 0)
@@ -6067,7 +6071,7 @@ static ssize_t rbd_remove_single_major(struct bus_type *bus,
* create control files in sysfs
* /sys/bus/rbd/...
*/
-static int rbd_sysfs_init(void)
+static int __init rbd_sysfs_init(void)
{
int ret;
@@ -6082,13 +6086,13 @@ static int rbd_sysfs_init(void)
return ret;
}
-static void rbd_sysfs_cleanup(void)
+static void __exit rbd_sysfs_cleanup(void)
{
bus_unregister(&rbd_bus_type);
device_unregister(&rbd_root_dev);
}
-static int rbd_slab_init(void)
+static int __init rbd_slab_init(void)
{
rbd_assert(!rbd_img_request_cache);
rbd_img_request_cache = KMEM_CACHE(rbd_img_request, 0);
diff --git a/drivers/block/rsxx/core.c b/drivers/block/rsxx/core.c
index f2c631ce793c..0cf4509d575c 100644
--- a/drivers/block/rsxx/core.c
+++ b/drivers/block/rsxx/core.c
@@ -780,9 +780,9 @@ static int rsxx_pci_probe(struct pci_dev *dev,
goto failed_enable;
pci_set_master(dev);
- pci_set_dma_max_seg_size(dev, RSXX_HW_BLK_SIZE);
+ dma_set_max_seg_size(&dev->dev, RSXX_HW_BLK_SIZE);
- st = pci_set_dma_mask(dev, DMA_BIT_MASK(64));
+ st = dma_set_mask(&dev->dev, DMA_BIT_MASK(64));
if (st) {
dev_err(CARD_TO_DEV(card),
"No usable DMA configuration,aborting\n");
diff --git a/drivers/block/rsxx/cregs.c b/drivers/block/rsxx/cregs.c
index c148e83e4ed7..d9a8758682c9 100644
--- a/drivers/block/rsxx/cregs.c
+++ b/drivers/block/rsxx/cregs.c
@@ -276,7 +276,7 @@ static void creg_cmd_done(struct work_struct *work)
st = -EIO;
}
- if ((cmd->op == CREG_OP_READ)) {
+ if (cmd->op == CREG_OP_READ) {
unsigned int cnt8 = ioread32(card->regmap + CREG_CNT);
/* Paranoid Sanity Checks */
diff --git a/drivers/block/rsxx/dev.c b/drivers/block/rsxx/dev.c
index 1a92f9e65937..3894aa0f350b 100644
--- a/drivers/block/rsxx/dev.c
+++ b/drivers/block/rsxx/dev.c
@@ -226,7 +226,7 @@ int rsxx_attach_dev(struct rsxx_cardinfo *card)
set_capacity(card->gendisk, card->size8 >> 9);
else
set_capacity(card->gendisk, 0);
- device_add_disk(CARD_TO_DEV(card), card->gendisk);
+ device_add_disk(CARD_TO_DEV(card), card->gendisk, NULL);
card->bdev_attached = 1;
}
diff --git a/drivers/block/rsxx/dma.c b/drivers/block/rsxx/dma.c
index 8fbc1bf6db3d..af9cf0215164 100644
--- a/drivers/block/rsxx/dma.c
+++ b/drivers/block/rsxx/dma.c
@@ -224,12 +224,12 @@ static void dma_intr_coal_auto_tune(struct rsxx_cardinfo *card)
static void rsxx_free_dma(struct rsxx_dma_ctrl *ctrl, struct rsxx_dma *dma)
{
if (dma->cmd != HW_CMD_BLK_DISCARD) {
- if (!pci_dma_mapping_error(ctrl->card->dev, dma->dma_addr)) {
- pci_unmap_page(ctrl->card->dev, dma->dma_addr,
+ if (!dma_mapping_error(&ctrl->card->dev->dev, dma->dma_addr)) {
+ dma_unmap_page(&ctrl->card->dev->dev, dma->dma_addr,
get_dma_size(dma),
dma->cmd == HW_CMD_BLK_WRITE ?
- PCI_DMA_TODEVICE :
- PCI_DMA_FROMDEVICE);
+ DMA_TO_DEVICE :
+ DMA_FROM_DEVICE);
}
}
@@ -438,23 +438,23 @@ static void rsxx_issue_dmas(struct rsxx_dma_ctrl *ctrl)
if (dma->cmd != HW_CMD_BLK_DISCARD) {
if (dma->cmd == HW_CMD_BLK_WRITE)
- dir = PCI_DMA_TODEVICE;
+ dir = DMA_TO_DEVICE;
else
- dir = PCI_DMA_FROMDEVICE;
+ dir = DMA_FROM_DEVICE;
/*
- * The function pci_map_page is placed here because we
+ * The function dma_map_page is placed here because we
* can only, by design, issue up to 255 commands to the
* hardware at one time per DMA channel. So the maximum
* amount of mapped memory would be 255 * 4 channels *
* 4096 Bytes which is less than 2GB, the limit of a x8
- * Non-HWWD PCIe slot. This way the pci_map_page
+ * Non-HWWD PCIe slot. This way the dma_map_page
* function should never fail because of a lack of
* mappable memory.
*/
- dma->dma_addr = pci_map_page(ctrl->card->dev, dma->page,
+ dma->dma_addr = dma_map_page(&ctrl->card->dev->dev, dma->page,
dma->pg_off, dma->sub_page.cnt << 9, dir);
- if (pci_dma_mapping_error(ctrl->card->dev, dma->dma_addr)) {
+ if (dma_mapping_error(&ctrl->card->dev->dev, dma->dma_addr)) {
push_tracker(ctrl->trackers, tag);
rsxx_complete_dma(ctrl, dma, DMA_CANCELLED);
continue;
@@ -776,10 +776,10 @@ bvec_err:
/*----------------- DMA Engine Initialization & Setup -------------------*/
int rsxx_hw_buffers_init(struct pci_dev *dev, struct rsxx_dma_ctrl *ctrl)
{
- ctrl->status.buf = pci_alloc_consistent(dev, STATUS_BUFFER_SIZE8,
- &ctrl->status.dma_addr);
- ctrl->cmd.buf = pci_alloc_consistent(dev, COMMAND_BUFFER_SIZE8,
- &ctrl->cmd.dma_addr);
+ ctrl->status.buf = dma_alloc_coherent(&dev->dev, STATUS_BUFFER_SIZE8,
+ &ctrl->status.dma_addr, GFP_KERNEL);
+ ctrl->cmd.buf = dma_alloc_coherent(&dev->dev, COMMAND_BUFFER_SIZE8,
+ &ctrl->cmd.dma_addr, GFP_KERNEL);
if (ctrl->status.buf == NULL || ctrl->cmd.buf == NULL)
return -ENOMEM;
@@ -962,12 +962,12 @@ failed_dma_setup:
vfree(ctrl->trackers);
if (ctrl->status.buf)
- pci_free_consistent(card->dev, STATUS_BUFFER_SIZE8,
- ctrl->status.buf,
- ctrl->status.dma_addr);
+ dma_free_coherent(&card->dev->dev, STATUS_BUFFER_SIZE8,
+ ctrl->status.buf,
+ ctrl->status.dma_addr);
if (ctrl->cmd.buf)
- pci_free_consistent(card->dev, COMMAND_BUFFER_SIZE8,
- ctrl->cmd.buf, ctrl->cmd.dma_addr);
+ dma_free_coherent(&card->dev->dev, COMMAND_BUFFER_SIZE8,
+ ctrl->cmd.buf, ctrl->cmd.dma_addr);
}
return st;
@@ -1023,10 +1023,10 @@ void rsxx_dma_destroy(struct rsxx_cardinfo *card)
vfree(ctrl->trackers);
- pci_free_consistent(card->dev, STATUS_BUFFER_SIZE8,
- ctrl->status.buf, ctrl->status.dma_addr);
- pci_free_consistent(card->dev, COMMAND_BUFFER_SIZE8,
- ctrl->cmd.buf, ctrl->cmd.dma_addr);
+ dma_free_coherent(&card->dev->dev, STATUS_BUFFER_SIZE8,
+ ctrl->status.buf, ctrl->status.dma_addr);
+ dma_free_coherent(&card->dev->dev, COMMAND_BUFFER_SIZE8,
+ ctrl->cmd.buf, ctrl->cmd.dma_addr);
}
}
@@ -1059,11 +1059,11 @@ int rsxx_eeh_save_issued_dmas(struct rsxx_cardinfo *card)
card->ctrl[i].stats.reads_issued--;
if (dma->cmd != HW_CMD_BLK_DISCARD) {
- pci_unmap_page(card->dev, dma->dma_addr,
+ dma_unmap_page(&card->dev->dev, dma->dma_addr,
get_dma_size(dma),
dma->cmd == HW_CMD_BLK_WRITE ?
- PCI_DMA_TODEVICE :
- PCI_DMA_FROMDEVICE);
+ DMA_TO_DEVICE :
+ DMA_FROM_DEVICE);
}
list_add_tail(&dma->list, &issued_dmas[i]);
diff --git a/drivers/block/skd_main.c b/drivers/block/skd_main.c
index 87b9e7fbf062..2459dcc04b1c 100644
--- a/drivers/block/skd_main.c
+++ b/drivers/block/skd_main.c
@@ -632,7 +632,7 @@ static bool skd_preop_sg_list(struct skd_device *skdev,
* Map scatterlist to PCI bus addresses.
* Note PCI might change the number of entries.
*/
- n_sg = pci_map_sg(skdev->pdev, sgl, n_sg, skreq->data_dir);
+ n_sg = dma_map_sg(&skdev->pdev->dev, sgl, n_sg, skreq->data_dir);
if (n_sg <= 0)
return false;
@@ -682,7 +682,8 @@ static void skd_postop_sg_list(struct skd_device *skdev,
skreq->sksg_list[skreq->n_sg - 1].next_desc_ptr =
skreq->sksg_dma_address +
((skreq->n_sg) * sizeof(struct fit_sg_descriptor));
- pci_unmap_sg(skdev->pdev, &skreq->sg[0], skreq->n_sg, skreq->data_dir);
+ dma_unmap_sg(&skdev->pdev->dev, &skreq->sg[0], skreq->n_sg,
+ skreq->data_dir);
}
/*
@@ -1416,7 +1417,7 @@ static void skd_resolve_req_exception(struct skd_device *skdev,
case SKD_CHECK_STATUS_BUSY_IMMINENT:
skd_log_skreq(skdev, skreq, "retry(busy)");
- blk_requeue_request(skdev->queue, req);
+ blk_mq_requeue_request(req, true);
dev_info(&skdev->pdev->dev, "drive BUSY imminent\n");
skdev->state = SKD_DRVR_STATE_BUSY_IMMINENT;
skdev->timer_countdown = SKD_TIMER_MINUTES(20);
@@ -1426,7 +1427,7 @@ static void skd_resolve_req_exception(struct skd_device *skdev,
case SKD_CHECK_STATUS_REQUEUE_REQUEST:
if ((unsigned long) ++req->special < SKD_MAX_RETRIES) {
skd_log_skreq(skdev, skreq, "retry");
- blk_requeue_request(skdev->queue, req);
+ blk_mq_requeue_request(req, true);
break;
}
/* fall through */
@@ -2632,8 +2633,8 @@ static int skd_cons_skcomp(struct skd_device *skdev)
"comp pci_alloc, total bytes %zd entries %d\n",
SKD_SKCOMP_SIZE, SKD_N_COMPLETION_ENTRY);
- skcomp = pci_zalloc_consistent(skdev->pdev, SKD_SKCOMP_SIZE,
- &skdev->cq_dma_address);
+ skcomp = dma_zalloc_coherent(&skdev->pdev->dev, SKD_SKCOMP_SIZE,
+ &skdev->cq_dma_address, GFP_KERNEL);
if (skcomp == NULL) {
rc = -ENOMEM;
@@ -2674,10 +2675,10 @@ static int skd_cons_skmsg(struct skd_device *skdev)
skmsg->id = i + SKD_ID_FIT_MSG;
- skmsg->msg_buf = pci_alloc_consistent(skdev->pdev,
- SKD_N_FITMSG_BYTES,
- &skmsg->mb_dma_address);
-
+ skmsg->msg_buf = dma_alloc_coherent(&skdev->pdev->dev,
+ SKD_N_FITMSG_BYTES,
+ &skmsg->mb_dma_address,
+ GFP_KERNEL);
if (skmsg->msg_buf == NULL) {
rc = -ENOMEM;
goto err_out;
@@ -2971,8 +2972,8 @@ err_out:
static void skd_free_skcomp(struct skd_device *skdev)
{
if (skdev->skcomp_table)
- pci_free_consistent(skdev->pdev, SKD_SKCOMP_SIZE,
- skdev->skcomp_table, skdev->cq_dma_address);
+ dma_free_coherent(&skdev->pdev->dev, SKD_SKCOMP_SIZE,
+ skdev->skcomp_table, skdev->cq_dma_address);
skdev->skcomp_table = NULL;
skdev->cq_dma_address = 0;
@@ -2991,8 +2992,8 @@ static void skd_free_skmsg(struct skd_device *skdev)
skmsg = &skdev->skmsg_table[i];
if (skmsg->msg_buf != NULL) {
- pci_free_consistent(skdev->pdev, SKD_N_FITMSG_BYTES,
- skmsg->msg_buf,
+ dma_free_coherent(&skdev->pdev->dev, SKD_N_FITMSG_BYTES,
+ skmsg->msg_buf,
skmsg->mb_dma_address);
}
skmsg->msg_buf = NULL;
@@ -3104,7 +3105,7 @@ static int skd_bdev_getgeo(struct block_device *bdev, struct hd_geometry *geo)
static int skd_bdev_attach(struct device *parent, struct skd_device *skdev)
{
dev_dbg(&skdev->pdev->dev, "add_disk\n");
- device_add_disk(parent, skdev->disk);
+ device_add_disk(parent, skdev->disk, NULL);
return 0;
}
@@ -3172,18 +3173,12 @@ static int skd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
rc = pci_request_regions(pdev, DRV_NAME);
if (rc)
goto err_out;
- rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
- if (!rc) {
- if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) {
- dev_err(&pdev->dev, "consistent DMA mask error %d\n",
- rc);
- }
- } else {
- rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
- if (rc) {
- dev_err(&pdev->dev, "DMA mask error %d\n", rc);
- goto err_out_regions;
- }
+ rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+ if (rc)
+ rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+ if (rc) {
+ dev_err(&pdev->dev, "DMA mask error %d\n", rc);
+ goto err_out_regions;
}
if (!skd_major) {
@@ -3367,20 +3362,12 @@ static int skd_pci_resume(struct pci_dev *pdev)
rc = pci_request_regions(pdev, DRV_NAME);
if (rc)
goto err_out;
- rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
- if (!rc) {
- if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) {
-
- dev_err(&pdev->dev, "consistent DMA mask error %d\n",
- rc);
- }
- } else {
- rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
- if (rc) {
-
- dev_err(&pdev->dev, "DMA mask error %d\n", rc);
- goto err_out_regions;
- }
+ rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+ if (rc)
+ rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+ if (rc) {
+ dev_err(&pdev->dev, "DMA mask error %d\n", rc);
+ goto err_out_regions;
}
pci_set_master(pdev);
diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c
index 5ca56bfae63c..b54fa6726303 100644
--- a/drivers/block/sunvdc.c
+++ b/drivers/block/sunvdc.c
@@ -36,6 +36,10 @@ MODULE_VERSION(DRV_MODULE_VERSION);
#define VDC_TX_RING_SIZE 512
#define VDC_DEFAULT_BLK_SIZE 512
+#define MAX_XFER_BLKS (128 * 1024)
+#define MAX_XFER_SIZE (MAX_XFER_BLKS / VDC_DEFAULT_BLK_SIZE)
+#define MAX_RING_COOKIES ((MAX_XFER_BLKS / PAGE_SIZE) + 2)
+
#define WAITING_FOR_LINK_UP 0x01
#define WAITING_FOR_TX_SPACE 0x02
#define WAITING_FOR_GEN_CMD 0x04
@@ -450,7 +454,7 @@ static int __send_request(struct request *req)
{
struct vdc_port *port = req->rq_disk->private_data;
struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING];
- struct scatterlist sg[port->ring_cookies];
+ struct scatterlist sg[MAX_RING_COOKIES];
struct vdc_req_entry *rqe;
struct vio_disk_desc *desc;
unsigned int map_perm;
@@ -458,6 +462,9 @@ static int __send_request(struct request *req)
u64 len;
u8 op;
+ if (WARN_ON(port->ring_cookies > MAX_RING_COOKIES))
+ return -EINVAL;
+
map_perm = LDC_MAP_SHADOW | LDC_MAP_DIRECT | LDC_MAP_IO;
if (rq_data_dir(req) == READ) {
@@ -850,7 +857,7 @@ static int probe_disk(struct vdc_port *port)
port->vdisk_size, (port->vdisk_size >> (20 - 9)),
port->vio.ver.major, port->vio.ver.minor);
- device_add_disk(&port->vio.vdev->dev, g);
+ device_add_disk(&port->vio.vdev->dev, g, NULL);
return 0;
}
@@ -984,9 +991,8 @@ static int vdc_port_probe(struct vio_dev *vdev, const struct vio_device_id *id)
goto err_out_free_port;
port->vdisk_block_size = VDC_DEFAULT_BLK_SIZE;
- port->max_xfer_size = ((128 * 1024) / port->vdisk_block_size);
- port->ring_cookies = ((port->max_xfer_size *
- port->vdisk_block_size) / PAGE_SIZE) + 2;
+ port->max_xfer_size = MAX_XFER_SIZE;
+ port->ring_cookies = MAX_RING_COOKIES;
err = vio_ldc_alloc(&port->vio, &vdc_ldc_cfg, port);
if (err)
diff --git a/drivers/block/swim.c b/drivers/block/swim.c
index 0e31884a9519..3fa6fcc34790 100644
--- a/drivers/block/swim.c
+++ b/drivers/block/swim.c
@@ -19,7 +19,7 @@
#include <linux/module.h>
#include <linux/fd.h>
#include <linux/slab.h>
-#include <linux/blkdev.h>
+#include <linux/blk-mq.h>
#include <linux/mutex.h>
#include <linux/hdreg.h>
#include <linux/kernel.h>
@@ -190,6 +190,7 @@ struct floppy_state {
int ref_count;
struct gendisk *disk;
+ struct blk_mq_tag_set tag_set;
/* parent controller */
@@ -211,7 +212,6 @@ enum head {
struct swim_priv {
struct swim __iomem *base;
spinlock_t lock;
- int fdc_queue;
int floppy_count;
struct floppy_state unit[FD_MAX_UNIT];
};
@@ -525,58 +525,36 @@ static blk_status_t floppy_read_sectors(struct floppy_state *fs,
return 0;
}
-static struct request *swim_next_request(struct swim_priv *swd)
+static blk_status_t swim_queue_rq(struct blk_mq_hw_ctx *hctx,
+ const struct blk_mq_queue_data *bd)
{
- struct request_queue *q;
- struct request *rq;
- int old_pos = swd->fdc_queue;
+ struct floppy_state *fs = hctx->queue->queuedata;
+ struct swim_priv *swd = fs->swd;
+ struct request *req = bd->rq;
+ blk_status_t err;
- do {
- q = swd->unit[swd->fdc_queue].disk->queue;
- if (++swd->fdc_queue == swd->floppy_count)
- swd->fdc_queue = 0;
- if (q) {
- rq = blk_fetch_request(q);
- if (rq)
- return rq;
- }
- } while (swd->fdc_queue != old_pos);
+ if (!spin_trylock_irq(&swd->lock))
+ return BLK_STS_DEV_RESOURCE;
- return NULL;
-}
+ blk_mq_start_request(req);
-static void do_fd_request(struct request_queue *q)
-{
- struct swim_priv *swd = q->queuedata;
- struct request *req;
- struct floppy_state *fs;
+ if (!fs->disk_in || rq_data_dir(req) == WRITE) {
+ err = BLK_STS_IOERR;
+ goto out;
+ }
- req = swim_next_request(swd);
- while (req) {
- blk_status_t err = BLK_STS_IOERR;
+ do {
+ err = floppy_read_sectors(fs, blk_rq_pos(req),
+ blk_rq_cur_sectors(req),
+ bio_data(req->bio));
+ } while (blk_update_request(req, err, blk_rq_cur_bytes(req)));
+ __blk_mq_end_request(req, err);
- fs = req->rq_disk->private_data;
- if (blk_rq_pos(req) >= fs->total_secs)
- goto done;
- if (!fs->disk_in)
- goto done;
- if (rq_data_dir(req) == WRITE && fs->write_protected)
- goto done;
+ err = BLK_STS_OK;
+out:
+ spin_unlock_irq(&swd->lock);
+ return err;
- switch (rq_data_dir(req)) {
- case WRITE:
- /* NOT IMPLEMENTED */
- break;
- case READ:
- err = floppy_read_sectors(fs, blk_rq_pos(req),
- blk_rq_cur_sectors(req),
- bio_data(req->bio));
- break;
- }
- done:
- if (!__blk_end_request_cur(req, err))
- req = swim_next_request(swd);
- }
}
static struct floppy_struct floppy_type[4] = {
@@ -823,6 +801,10 @@ static int swim_add_floppy(struct swim_priv *swd, enum drive_location location)
return 0;
}
+static const struct blk_mq_ops swim_mq_ops = {
+ .queue_rq = swim_queue_rq,
+};
+
static int swim_floppy_init(struct swim_priv *swd)
{
int err;
@@ -852,20 +834,25 @@ 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;
goto exit_put_disks;
}
- swd->unit[drive].disk->queue = blk_init_queue(do_fd_request,
- &swd->lock);
- if (!swd->unit[drive].disk->queue) {
- err = -ENOMEM;
+
+ 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);
goto exit_put_disks;
}
+
+ swd->unit[drive].disk->queue = q;
blk_queue_bounce_limit(swd->unit[drive].disk->queue,
BLK_BOUNCE_HIGH);
- swd->unit[drive].disk->queue->queuedata = swd;
+ swd->unit[drive].disk->queue->queuedata = &swd->unit[drive];
swd->unit[drive].swd = swd;
}
@@ -887,8 +874,18 @@ static int swim_floppy_init(struct swim_priv *swd)
exit_put_disks:
unregister_blkdev(FLOPPY_MAJOR, "fd");
- while (drive--)
- put_disk(swd->unit[drive].disk);
+ 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);
+ }
+ } while (drive--);
return err;
}
@@ -961,6 +958,7 @@ static int swim_remove(struct platform_device *dev)
for (drive = 0; drive < swd->floppy_count; drive++) {
del_gendisk(swd->unit[drive].disk);
blk_cleanup_queue(swd->unit[drive].disk->queue);
+ blk_mq_free_tag_set(&swd->unit[drive].tag_set);
put_disk(swd->unit[drive].disk);
}
diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c
index 469541c1e51e..c1c676a33e4a 100644
--- a/drivers/block/swim3.c
+++ b/drivers/block/swim3.c
@@ -25,7 +25,7 @@
#include <linux/delay.h>
#include <linux/fd.h>
#include <linux/ioctl.h>
-#include <linux/blkdev.h>
+#include <linux/blk-mq.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/module.h>
@@ -206,6 +206,7 @@ struct floppy_state {
char dbdma_cmd_space[5 * sizeof(struct dbdma_cmd)];
int index;
struct request *cur_req;
+ struct blk_mq_tag_set tag_set;
};
#define swim3_err(fmt, arg...) dev_err(&fs->mdev->ofdev.dev, "[fd%d] " fmt, fs->index, arg)
@@ -260,16 +261,15 @@ static int floppy_revalidate(struct gendisk *disk);
static bool swim3_end_request(struct floppy_state *fs, blk_status_t err, unsigned int nr_bytes)
{
struct request *req = fs->cur_req;
- int rc;
swim3_dbg(" end request, err=%d nr_bytes=%d, cur_req=%p\n",
err, nr_bytes, req);
if (err)
nr_bytes = blk_rq_cur_bytes(req);
- rc = __blk_end_request(req, err, nr_bytes);
- if (rc)
+ if (blk_update_request(req, err, nr_bytes))
return true;
+ __blk_mq_end_request(req, err);
fs->cur_req = NULL;
return false;
}
@@ -309,86 +309,58 @@ static int swim3_readbit(struct floppy_state *fs, int bit)
return (stat & DATA) == 0;
}
-static void start_request(struct floppy_state *fs)
+static blk_status_t swim3_queue_rq(struct blk_mq_hw_ctx *hctx,
+ const struct blk_mq_queue_data *bd)
{
- struct request *req;
+ struct floppy_state *fs = hctx->queue->queuedata;
+ struct request *req = bd->rq;
unsigned long x;
- swim3_dbg("start request, initial state=%d\n", fs->state);
-
- if (fs->state == idle && fs->wanted) {
- fs->state = available;
- wake_up(&fs->wait);
- return;
+ spin_lock_irq(&swim3_lock);
+ if (fs->cur_req || fs->state != idle) {
+ spin_unlock_irq(&swim3_lock);
+ return BLK_STS_DEV_RESOURCE;
}
- while (fs->state == idle) {
- swim3_dbg("start request, idle loop, cur_req=%p\n", fs->cur_req);
- if (!fs->cur_req) {
- fs->cur_req = blk_fetch_request(disks[fs->index]->queue);
- swim3_dbg(" fetched request %p\n", fs->cur_req);
- if (!fs->cur_req)
- break;
- }
- req = fs->cur_req;
-
- if (fs->mdev->media_bay &&
- check_media_bay(fs->mdev->media_bay) != MB_FD) {
- swim3_dbg("%s", " media bay absent, dropping req\n");
- swim3_end_request(fs, BLK_STS_IOERR, 0);
- continue;
- }
-
-#if 0 /* This is really too verbose */
- swim3_dbg("do_fd_req: dev=%s cmd=%d sec=%ld nr_sec=%u buf=%p\n",
- req->rq_disk->disk_name, req->cmd,
- (long)blk_rq_pos(req), blk_rq_sectors(req),
- bio_data(req->bio));
- swim3_dbg(" current_nr_sectors=%u\n",
- blk_rq_cur_sectors(req));
-#endif
-
- if (blk_rq_pos(req) >= fs->total_secs) {
- swim3_dbg(" pos out of bounds (%ld, max is %ld)\n",
- (long)blk_rq_pos(req), (long)fs->total_secs);
- swim3_end_request(fs, BLK_STS_IOERR, 0);
- continue;
- }
- if (fs->ejected) {
- swim3_dbg("%s", " disk ejected\n");
+ blk_mq_start_request(req);
+ fs->cur_req = req;
+ if (fs->mdev->media_bay &&
+ check_media_bay(fs->mdev->media_bay) != MB_FD) {
+ swim3_dbg("%s", " media bay absent, dropping req\n");
+ swim3_end_request(fs, BLK_STS_IOERR, 0);
+ goto out;
+ }
+ if (fs->ejected) {
+ swim3_dbg("%s", " disk ejected\n");
+ swim3_end_request(fs, BLK_STS_IOERR, 0);
+ goto out;
+ }
+ if (rq_data_dir(req) == WRITE) {
+ if (fs->write_prot < 0)
+ fs->write_prot = swim3_readbit(fs, WRITE_PROT);
+ if (fs->write_prot) {
+ swim3_dbg("%s", " try to write, disk write protected\n");
swim3_end_request(fs, BLK_STS_IOERR, 0);
- continue;
+ goto out;
}
-
- if (rq_data_dir(req) == WRITE) {
- if (fs->write_prot < 0)
- fs->write_prot = swim3_readbit(fs, WRITE_PROT);
- if (fs->write_prot) {
- swim3_dbg("%s", " try to write, disk write protected\n");
- swim3_end_request(fs, BLK_STS_IOERR, 0);
- continue;
- }
- }
-
- /* Do not remove the cast. blk_rq_pos(req) is now a
- * sector_t and can be 64 bits, but it will never go
- * past 32 bits for this driver anyway, so we can
- * safely cast it down and not have to do a 64/32
- * division
- */
- fs->req_cyl = ((long)blk_rq_pos(req)) / fs->secpercyl;
- x = ((long)blk_rq_pos(req)) % fs->secpercyl;
- fs->head = x / fs->secpertrack;
- fs->req_sector = x % fs->secpertrack + 1;
- fs->state = do_transfer;
- fs->retries = 0;
-
- act(fs);
}
-}
-static void do_fd_request(struct request_queue * q)
-{
- start_request(q->queuedata);
+ /*
+ * Do not remove the cast. blk_rq_pos(req) is now a sector_t and can be
+ * 64 bits, but it will never go past 32 bits for this driver anyway, so
+ * we can safely cast it down and not have to do a 64/32 division
+ */
+ fs->req_cyl = ((long)blk_rq_pos(req)) / fs->secpercyl;
+ x = ((long)blk_rq_pos(req)) % fs->secpercyl;
+ fs->head = x / fs->secpertrack;
+ fs->req_sector = x % fs->secpertrack + 1;
+ fs->state = do_transfer;
+ fs->retries = 0;
+
+ act(fs);
+
+out:
+ spin_unlock_irq(&swim3_lock);
+ return BLK_STS_OK;
}
static void set_timeout(struct floppy_state *fs, int nticks,
@@ -585,7 +557,6 @@ static void scan_timeout(struct timer_list *t)
if (fs->retries > 5) {
swim3_end_request(fs, BLK_STS_IOERR, 0);
fs->state = idle;
- start_request(fs);
} else {
fs->state = jogging;
act(fs);
@@ -609,7 +580,6 @@ static void seek_timeout(struct timer_list *t)
swim3_err("%s", "Seek timeout\n");
swim3_end_request(fs, BLK_STS_IOERR, 0);
fs->state = idle;
- start_request(fs);
spin_unlock_irqrestore(&swim3_lock, flags);
}
@@ -638,7 +608,6 @@ static void settle_timeout(struct timer_list *t)
swim3_err("%s", "Seek settle timeout\n");
swim3_end_request(fs, BLK_STS_IOERR, 0);
fs->state = idle;
- start_request(fs);
unlock:
spin_unlock_irqrestore(&swim3_lock, flags);
}
@@ -667,7 +636,6 @@ static void xfer_timeout(struct timer_list *t)
(long)blk_rq_pos(fs->cur_req));
swim3_end_request(fs, BLK_STS_IOERR, 0);
fs->state = idle;
- start_request(fs);
spin_unlock_irqrestore(&swim3_lock, flags);
}
@@ -704,7 +672,6 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id)
if (fs->retries > 5) {
swim3_end_request(fs, BLK_STS_IOERR, 0);
fs->state = idle;
- start_request(fs);
} else {
fs->state = jogging;
act(fs);
@@ -796,7 +763,6 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id)
fs->state, rq_data_dir(req), intr, err);
swim3_end_request(fs, BLK_STS_IOERR, 0);
fs->state = idle;
- start_request(fs);
break;
}
fs->retries = 0;
@@ -813,8 +779,6 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id)
} else
fs->state = idle;
}
- if (fs->state == idle)
- start_request(fs);
break;
default:
swim3_err("Don't know what to do in state %d\n", fs->state);
@@ -862,14 +826,19 @@ static int grab_drive(struct floppy_state *fs, enum swim_state state,
static void release_drive(struct floppy_state *fs)
{
+ struct request_queue *q = disks[fs->index]->queue;
unsigned long flags;
swim3_dbg("%s", "-> release drive\n");
spin_lock_irqsave(&swim3_lock, flags);
fs->state = idle;
- start_request(fs);
spin_unlock_irqrestore(&swim3_lock, flags);
+
+ blk_mq_freeze_queue(q);
+ blk_mq_quiesce_queue(q);
+ blk_mq_unquiesce_queue(q);
+ blk_mq_unfreeze_queue(q);
}
static int fd_eject(struct floppy_state *fs)
@@ -1089,6 +1058,10 @@ static const struct block_device_operations floppy_fops = {
.revalidate_disk= floppy_revalidate,
};
+static const struct blk_mq_ops swim3_mq_ops = {
+ .queue_rq = swim3_queue_rq,
+};
+
static void swim3_mb_event(struct macio_dev* mdev, int mb_state)
{
struct floppy_state *fs = macio_get_drvdata(mdev);
@@ -1202,47 +1175,63 @@ static int swim3_add_device(struct macio_dev *mdev, int index)
static int swim3_attach(struct macio_dev *mdev,
const struct of_device_id *match)
{
+ struct floppy_state *fs;
struct gendisk *disk;
- int index, rc;
+ int rc;
- index = floppy_count++;
- if (index >= MAX_FLOPPIES)
+ if (floppy_count >= MAX_FLOPPIES)
return -ENXIO;
- /* Add the drive */
- rc = swim3_add_device(mdev, index);
- if (rc)
- return rc;
- /* Now register that disk. Same comment about failure handling */
- disk = disks[index] = alloc_disk(1);
- if (disk == NULL)
- return -ENOMEM;
- disk->queue = blk_init_queue(do_fd_request, &swim3_lock);
- if (disk->queue == NULL) {
- put_disk(disk);
- return -ENOMEM;
+ if (floppy_count == 0) {
+ rc = register_blkdev(FLOPPY_MAJOR, "fd");
+ if (rc)
+ return rc;
}
- blk_queue_bounce_limit(disk->queue, BLK_BOUNCE_HIGH);
- disk->queue->queuedata = &floppy_states[index];
- if (index == 0) {
- /* If we failed, there isn't much we can do as the driver is still
- * too dumb to remove the device, just bail out
- */
- if (register_blkdev(FLOPPY_MAJOR, "fd"))
- return 0;
+ fs = &floppy_states[floppy_count];
+
+ disk = alloc_disk(1);
+ if (disk == NULL) {
+ rc = -ENOMEM;
+ goto out_unregister;
+ }
+
+ 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;
}
+ blk_queue_bounce_limit(disk->queue, BLK_BOUNCE_HIGH);
+ disk->queue->queuedata = fs;
+
+ rc = swim3_add_device(mdev, floppy_count);
+ if (rc)
+ goto out_cleanup_queue;
disk->major = FLOPPY_MAJOR;
- disk->first_minor = index;
+ disk->first_minor = floppy_count;
disk->fops = &floppy_fops;
- disk->private_data = &floppy_states[index];
+ disk->private_data = fs;
disk->flags |= GENHD_FL_REMOVABLE;
- sprintf(disk->disk_name, "fd%d", index);
+ sprintf(disk->disk_name, "fd%d", floppy_count);
set_capacity(disk, 2880);
add_disk(disk);
+ disks[floppy_count++] = disk;
return 0;
+
+out_cleanup_queue:
+ blk_cleanup_queue(disk->queue);
+ disk->queue = NULL;
+ 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");
+ return rc;
}
static const struct of_device_id swim3_match[] =
diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c
index 4d90e5eba2f5..064b8c5c7a32 100644
--- a/drivers/block/sx8.c
+++ b/drivers/block/sx8.c
@@ -16,7 +16,7 @@
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
-#include <linux/blkdev.h>
+#include <linux/blk-mq.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/compiler.h>
@@ -197,7 +197,6 @@ enum {
FL_NON_RAID = FW_VER_NON_RAID,
FL_4PORT = FW_VER_4PORT,
FL_FW_VER_MASK = (FW_VER_NON_RAID | FW_VER_4PORT),
- FL_DAC = (1 << 16),
FL_DYN_MAJOR = (1 << 17),
};
@@ -244,6 +243,7 @@ struct carm_port {
unsigned int port_no;
struct gendisk *disk;
struct carm_host *host;
+ struct blk_mq_tag_set tag_set;
/* attached device characteristics */
u64 capacity;
@@ -279,6 +279,7 @@ struct carm_host {
unsigned int state;
u32 fw_ver;
+ struct blk_mq_tag_set tag_set;
struct request_queue *oob_q;
unsigned int n_oob;
@@ -750,7 +751,7 @@ static inline void carm_end_request_queued(struct carm_host *host,
struct request *req = crq->rq;
int rc;
- __blk_end_request_all(req, error);
+ blk_mq_end_request(req, error);
rc = carm_put_request(host, crq);
assert(rc == 0);
@@ -760,7 +761,7 @@ static inline void carm_push_q (struct carm_host *host, struct request_queue *q)
{
unsigned int idx = host->wait_q_prod % CARM_MAX_WAIT_Q;
- blk_stop_queue(q);
+ blk_mq_stop_hw_queues(q);
VPRINTK("STOPPED QUEUE %p\n", q);
host->wait_q[idx] = q;
@@ -785,7 +786,7 @@ static inline void carm_round_robin(struct carm_host *host)
{
struct request_queue *q = carm_pop_q(host);
if (q) {
- blk_start_queue(q);
+ blk_mq_start_hw_queues(q);
VPRINTK("STARTED QUEUE %p\n", q);
}
}
@@ -802,82 +803,86 @@ static inline void carm_end_rq(struct carm_host *host, struct carm_request *crq,
}
}
-static void carm_oob_rq_fn(struct request_queue *q)
+static blk_status_t carm_oob_queue_rq(struct blk_mq_hw_ctx *hctx,
+ const struct blk_mq_queue_data *bd)
{
+ struct request_queue *q = hctx->queue;
struct carm_host *host = q->queuedata;
struct carm_request *crq;
- struct request *rq;
int rc;
- while (1) {
- DPRINTK("get req\n");
- rq = blk_fetch_request(q);
- if (!rq)
- break;
+ blk_mq_start_request(bd->rq);
- crq = rq->special;
- assert(crq != NULL);
- assert(crq->rq == rq);
+ spin_lock_irq(&host->lock);
- crq->n_elem = 0;
+ crq = bd->rq->special;
+ assert(crq != NULL);
+ assert(crq->rq == bd->rq);
- DPRINTK("send req\n");
- rc = carm_send_msg(host, crq);
- if (rc) {
- blk_requeue_request(q, rq);
- carm_push_q(host, q);
- return; /* call us again later, eventually */
- }
+ crq->n_elem = 0;
+
+ DPRINTK("send req\n");
+ rc = carm_send_msg(host, crq);
+ if (rc) {
+ carm_push_q(host, q);
+ spin_unlock_irq(&host->lock);
+ return BLK_STS_DEV_RESOURCE;
}
+
+ spin_unlock_irq(&host->lock);
+ return BLK_STS_OK;
}
-static void carm_rq_fn(struct request_queue *q)
+static blk_status_t carm_queue_rq(struct blk_mq_hw_ctx *hctx,
+ const struct blk_mq_queue_data *bd)
{
+ struct request_queue *q = hctx->queue;
struct carm_port *port = q->queuedata;
struct carm_host *host = port->host;
struct carm_msg_rw *msg;
struct carm_request *crq;
- struct request *rq;
+ struct request *rq = bd->rq;
struct scatterlist *sg;
int writing = 0, pci_dir, i, n_elem, rc;
u32 tmp;
unsigned int msg_size;
-queue_one_request:
- VPRINTK("get req\n");
- rq = blk_peek_request(q);
- if (!rq)
- return;
+ blk_mq_start_request(rq);
+
+ spin_lock_irq(&host->lock);
crq = carm_get_request(host);
if (!crq) {
carm_push_q(host, q);
- return; /* call us again later, eventually */
+ spin_unlock_irq(&host->lock);
+ return BLK_STS_DEV_RESOURCE;
}
crq->rq = rq;
- blk_start_request(rq);
-
if (rq_data_dir(rq) == WRITE) {
writing = 1;
- pci_dir = PCI_DMA_TODEVICE;
+ pci_dir = DMA_TO_DEVICE;
} else {
- pci_dir = PCI_DMA_FROMDEVICE;
+ pci_dir = DMA_FROM_DEVICE;
}
/* get scatterlist from block layer */
sg = &crq->sg[0];
n_elem = blk_rq_map_sg(q, rq, sg);
if (n_elem <= 0) {
+ /* request with no s/g entries? */
carm_end_rq(host, crq, BLK_STS_IOERR);
- return; /* request with no s/g entries? */
+ spin_unlock_irq(&host->lock);
+ return BLK_STS_IOERR;
}
/* map scatterlist to PCI bus addresses */
- n_elem = pci_map_sg(host->pdev, sg, n_elem, pci_dir);
+ n_elem = dma_map_sg(&host->pdev->dev, sg, n_elem, pci_dir);
if (n_elem <= 0) {
+ /* request with no s/g entries? */
carm_end_rq(host, crq, BLK_STS_IOERR);
- return; /* request with no s/g entries? */
+ spin_unlock_irq(&host->lock);
+ return BLK_STS_IOERR;
}
crq->n_elem = n_elem;
crq->port = port;
@@ -927,12 +932,13 @@ queue_one_request:
rc = carm_send_msg(host, crq);
if (rc) {
carm_put_request(host, crq);
- blk_requeue_request(q, rq);
carm_push_q(host, q);
- return; /* call us again later, eventually */
+ spin_unlock_irq(&host->lock);
+ return BLK_STS_DEV_RESOURCE;
}
- goto queue_one_request;
+ spin_unlock_irq(&host->lock);
+ return BLK_STS_OK;
}
static void carm_handle_array_info(struct carm_host *host,
@@ -1052,11 +1058,11 @@ static inline void carm_handle_rw(struct carm_host *host,
VPRINTK("ENTER\n");
if (rq_data_dir(crq->rq) == WRITE)
- pci_dir = PCI_DMA_TODEVICE;
+ pci_dir = DMA_TO_DEVICE;
else
- pci_dir = PCI_DMA_FROMDEVICE;
+ pci_dir = DMA_FROM_DEVICE;
- pci_unmap_sg(host->pdev, &crq->sg[0], crq->n_elem, pci_dir);
+ dma_unmap_sg(&host->pdev->dev, &crq->sg[0], crq->n_elem, pci_dir);
carm_end_rq(host, crq, error);
}
@@ -1485,6 +1491,14 @@ static int carm_init_host(struct carm_host *host)
return 0;
}
+static const struct blk_mq_ops carm_oob_mq_ops = {
+ .queue_rq = carm_oob_queue_rq,
+};
+
+static const struct blk_mq_ops carm_mq_ops = {
+ .queue_rq = carm_queue_rq,
+};
+
static int carm_init_disks(struct carm_host *host)
{
unsigned int i;
@@ -1513,9 +1527,10 @@ static int carm_init_disks(struct carm_host *host)
disk->fops = &carm_bd_ops;
disk->private_data = port;
- q = blk_init_queue(carm_rq_fn, &host->lock);
- if (!q) {
- rc = -ENOMEM;
+ q = blk_mq_init_sq_queue(&port->tag_set, &carm_mq_ops,
+ max_queue, BLK_MQ_F_SHOULD_MERGE);
+ if (IS_ERR(q)) {
+ rc = PTR_ERR(q);
break;
}
disk->queue = q;
@@ -1533,14 +1548,18 @@ static void carm_free_disks(struct carm_host *host)
unsigned int i;
for (i = 0; i < CARM_MAX_PORTS; i++) {
- struct gendisk *disk = host->port[i].disk;
+ struct carm_port *port = &host->port[i];
+ struct gendisk *disk = port->disk;
+
if (disk) {
struct request_queue *q = disk->queue;
if (disk->flags & GENHD_FL_UP)
del_gendisk(disk);
- if (q)
+ if (q) {
+ blk_mq_free_tag_set(&port->tag_set);
blk_cleanup_queue(q);
+ }
put_disk(disk);
}
}
@@ -1548,8 +1567,8 @@ static void carm_free_disks(struct carm_host *host)
static int carm_init_shm(struct carm_host *host)
{
- host->shm = pci_alloc_consistent(host->pdev, CARM_SHM_SIZE,
- &host->shm_dma);
+ host->shm = dma_alloc_coherent(&host->pdev->dev, CARM_SHM_SIZE,
+ &host->shm_dma, GFP_KERNEL);
if (!host->shm)
return -ENOMEM;
@@ -1565,7 +1584,6 @@ static int carm_init_shm(struct carm_host *host)
static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct carm_host *host;
- unsigned int pci_dac;
int rc;
struct request_queue *q;
unsigned int i;
@@ -1580,28 +1598,12 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc)
goto err_out;
-#ifdef IF_64BIT_DMA_IS_POSSIBLE /* grrrr... */
- rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
- if (!rc) {
- rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
- if (rc) {
- printk(KERN_ERR DRV_NAME "(%s): consistent DMA mask failure\n",
- pci_name(pdev));
- goto err_out_regions;
- }
- pci_dac = 1;
- } else {
-#endif
- rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
- if (rc) {
- printk(KERN_ERR DRV_NAME "(%s): DMA mask failure\n",
- pci_name(pdev));
- goto err_out_regions;
- }
- pci_dac = 0;
-#ifdef IF_64BIT_DMA_IS_POSSIBLE /* grrrr... */
+ rc = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
+ if (rc) {
+ printk(KERN_ERR DRV_NAME "(%s): DMA mask failure\n",
+ pci_name(pdev));
+ goto err_out_regions;
}
-#endif
host = kzalloc(sizeof(*host), GFP_KERNEL);
if (!host) {
@@ -1612,7 +1614,6 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
}
host->pdev = pdev;
- host->flags = pci_dac ? FL_DAC : 0;
spin_lock_init(&host->lock);
INIT_WORK(&host->fsm_task, carm_fsm_task);
init_completion(&host->probe_comp);
@@ -1636,12 +1637,13 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out_iounmap;
}
- q = blk_init_queue(carm_oob_rq_fn, &host->lock);
- if (!q) {
+ q = blk_mq_init_sq_queue(&host->tag_set, &carm_oob_mq_ops, 1,
+ BLK_MQ_F_NO_SCHED);
+ if (IS_ERR(q)) {
printk(KERN_ERR DRV_NAME "(%s): OOB queue alloc failure\n",
pci_name(pdev));
- rc = -ENOMEM;
- goto err_out_pci_free;
+ rc = PTR_ERR(q);
+ goto err_out_dma_free;
}
host->oob_q = q;
q->queuedata = host;
@@ -1705,8 +1707,9 @@ err_out_free_majors:
else if (host->major == 161)
clear_bit(1, &carm_major_alloc);
blk_cleanup_queue(host->oob_q);
-err_out_pci_free:
- pci_free_consistent(pdev, CARM_SHM_SIZE, host->shm, host->shm_dma);
+ blk_mq_free_tag_set(&host->tag_set);
+err_out_dma_free:
+ dma_free_coherent(&pdev->dev, CARM_SHM_SIZE, host->shm, host->shm_dma);
err_out_iounmap:
iounmap(host->mmio);
err_out_kfree:
@@ -1736,7 +1739,8 @@ static void carm_remove_one (struct pci_dev *pdev)
else if (host->major == 161)
clear_bit(1, &carm_major_alloc);
blk_cleanup_queue(host->oob_q);
- pci_free_consistent(pdev, CARM_SHM_SIZE, host->shm, host->shm_dma);
+ blk_mq_free_tag_set(&host->tag_set);
+ dma_free_coherent(&pdev->dev, CARM_SHM_SIZE, host->shm, host->shm_dma);
iounmap(host->mmio);
kfree(host);
pci_release_regions(pdev);
diff --git a/drivers/block/umem.c b/drivers/block/umem.c
index 5c7fb8cc4149..be3e3ab79950 100644
--- a/drivers/block/umem.c
+++ b/drivers/block/umem.c
@@ -363,12 +363,12 @@ static int add_bio(struct cardinfo *card)
vec = bio_iter_iovec(bio, card->current_iter);
- dma_handle = pci_map_page(card->dev,
+ dma_handle = dma_map_page(&card->dev->dev,
vec.bv_page,
vec.bv_offset,
vec.bv_len,
bio_op(bio) == REQ_OP_READ ?
- PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
+ DMA_FROM_DEVICE : DMA_TO_DEVICE);
p = &card->mm_pages[card->Ready];
desc = &p->desc[p->cnt];
@@ -421,7 +421,7 @@ static void process_page(unsigned long data)
struct cardinfo *card = (struct cardinfo *)data;
unsigned int dma_status = card->dma_status;
- spin_lock_bh(&card->lock);
+ spin_lock(&card->lock);
if (card->Active < 0)
goto out_unlock;
page = &card->mm_pages[card->Active];
@@ -448,10 +448,10 @@ static void process_page(unsigned long data)
page->iter = page->bio->bi_iter;
}
- pci_unmap_page(card->dev, desc->data_dma_handle,
+ dma_unmap_page(&card->dev->dev, desc->data_dma_handle,
vec.bv_len,
(control & DMASCR_TRANSFER_READ) ?
- PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+ DMA_TO_DEVICE : DMA_FROM_DEVICE);
if (control & DMASCR_HARD_ERROR) {
/* error */
bio->bi_status = BLK_STS_IOERR;
@@ -496,7 +496,7 @@ static void process_page(unsigned long data)
mm_start_io(card);
}
out_unlock:
- spin_unlock_bh(&card->lock);
+ spin_unlock(&card->lock);
while (return_bio) {
struct bio *bio = return_bio;
@@ -817,8 +817,8 @@ static int mm_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
dev_printk(KERN_INFO, &dev->dev,
"Micro Memory(tm) controller found (PCI Mem Module (Battery Backup))\n");
- if (pci_set_dma_mask(dev, DMA_BIT_MASK(64)) &&
- pci_set_dma_mask(dev, DMA_BIT_MASK(32))) {
+ if (dma_set_mask(&dev->dev, DMA_BIT_MASK(64)) &&
+ dma_set_mask(&dev->dev, DMA_BIT_MASK(32))) {
dev_printk(KERN_WARNING, &dev->dev, "NO suitable DMA found\n");
return -ENOMEM;
}
@@ -871,12 +871,10 @@ static int mm_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
goto failed_magic;
}
- card->mm_pages[0].desc = pci_alloc_consistent(card->dev,
- PAGE_SIZE * 2,
- &card->mm_pages[0].page_dma);
- card->mm_pages[1].desc = pci_alloc_consistent(card->dev,
- PAGE_SIZE * 2,
- &card->mm_pages[1].page_dma);
+ card->mm_pages[0].desc = dma_alloc_coherent(&card->dev->dev,
+ PAGE_SIZE * 2, &card->mm_pages[0].page_dma, GFP_KERNEL);
+ card->mm_pages[1].desc = dma_alloc_coherent(&card->dev->dev,
+ PAGE_SIZE * 2, &card->mm_pages[1].page_dma, GFP_KERNEL);
if (card->mm_pages[0].desc == NULL ||
card->mm_pages[1].desc == NULL) {
dev_printk(KERN_ERR, &card->dev->dev, "alloc failed\n");
@@ -1002,13 +1000,13 @@ static int mm_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
failed_req_irq:
failed_alloc:
if (card->mm_pages[0].desc)
- pci_free_consistent(card->dev, PAGE_SIZE*2,
- card->mm_pages[0].desc,
- card->mm_pages[0].page_dma);
+ dma_free_coherent(&card->dev->dev, PAGE_SIZE * 2,
+ card->mm_pages[0].desc,
+ card->mm_pages[0].page_dma);
if (card->mm_pages[1].desc)
- pci_free_consistent(card->dev, PAGE_SIZE*2,
- card->mm_pages[1].desc,
- card->mm_pages[1].page_dma);
+ dma_free_coherent(&card->dev->dev, PAGE_SIZE * 2,
+ card->mm_pages[1].desc,
+ card->mm_pages[1].page_dma);
failed_magic:
iounmap(card->csr_remap);
failed_remap_csr:
@@ -1027,11 +1025,11 @@ static void mm_pci_remove(struct pci_dev *dev)
iounmap(card->csr_remap);
if (card->mm_pages[0].desc)
- pci_free_consistent(card->dev, PAGE_SIZE*2,
+ dma_free_coherent(&card->dev->dev, PAGE_SIZE * 2,
card->mm_pages[0].desc,
card->mm_pages[0].page_dma);
if (card->mm_pages[1].desc)
- pci_free_consistent(card->dev, PAGE_SIZE*2,
+ dma_free_coherent(&card->dev->dev, PAGE_SIZE * 2,
card->mm_pages[1].desc,
card->mm_pages[1].page_dma);
blk_cleanup_queue(card->queue);
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 23752dc99b00..086c6bb12baa 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -351,8 +351,8 @@ static int minor_to_index(int minor)
return minor >> PART_BITS;
}
-static ssize_t virtblk_serial_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t serial_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct gendisk *disk = dev_to_disk(dev);
int err;
@@ -371,7 +371,7 @@ static ssize_t virtblk_serial_show(struct device *dev,
return err;
}
-static DEVICE_ATTR(serial, 0444, virtblk_serial_show, NULL);
+static DEVICE_ATTR_RO(serial);
/* The queue's logical block size must be set before calling this */
static void virtblk_update_capacity(struct virtio_blk *vblk, bool resize)
@@ -545,8 +545,8 @@ static const char *const virtblk_cache_types[] = {
};
static ssize_t
-virtblk_cache_type_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+cache_type_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct gendisk *disk = dev_to_disk(dev);
struct virtio_blk *vblk = disk->private_data;
@@ -564,8 +564,7 @@ virtblk_cache_type_store(struct device *dev, struct device_attribute *attr,
}
static ssize_t
-virtblk_cache_type_show(struct device *dev, struct device_attribute *attr,
- char *buf)
+cache_type_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct gendisk *disk = dev_to_disk(dev);
struct virtio_blk *vblk = disk->private_data;
@@ -575,12 +574,38 @@ virtblk_cache_type_show(struct device *dev, struct device_attribute *attr,
return snprintf(buf, 40, "%s\n", virtblk_cache_types[writeback]);
}
-static const struct device_attribute dev_attr_cache_type_ro =
- __ATTR(cache_type, 0444,
- virtblk_cache_type_show, NULL);
-static const struct device_attribute dev_attr_cache_type_rw =
- __ATTR(cache_type, 0644,
- virtblk_cache_type_show, virtblk_cache_type_store);
+static DEVICE_ATTR_RW(cache_type);
+
+static struct attribute *virtblk_attrs[] = {
+ &dev_attr_serial.attr,
+ &dev_attr_cache_type.attr,
+ NULL,
+};
+
+static umode_t virtblk_attrs_are_visible(struct kobject *kobj,
+ struct attribute *a, int n)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct gendisk *disk = dev_to_disk(dev);
+ struct virtio_blk *vblk = disk->private_data;
+ struct virtio_device *vdev = vblk->vdev;
+
+ if (a == &dev_attr_cache_type.attr &&
+ !virtio_has_feature(vdev, VIRTIO_BLK_F_CONFIG_WCE))
+ return S_IRUGO;
+
+ return a->mode;
+}
+
+static const struct attribute_group virtblk_attr_group = {
+ .attrs = virtblk_attrs,
+ .is_visible = virtblk_attrs_are_visible,
+};
+
+static const struct attribute_group *virtblk_attr_groups[] = {
+ &virtblk_attr_group,
+ NULL,
+};
static int virtblk_init_request(struct blk_mq_tag_set *set, struct request *rq,
unsigned int hctx_idx, unsigned int numa_node)
@@ -780,24 +805,9 @@ static int virtblk_probe(struct virtio_device *vdev)
virtblk_update_capacity(vblk, false);
virtio_device_ready(vdev);
- device_add_disk(&vdev->dev, vblk->disk);
- err = device_create_file(disk_to_dev(vblk->disk), &dev_attr_serial);
- if (err)
- goto out_del_disk;
-
- if (virtio_has_feature(vdev, VIRTIO_BLK_F_CONFIG_WCE))
- err = device_create_file(disk_to_dev(vblk->disk),
- &dev_attr_cache_type_rw);
- else
- err = device_create_file(disk_to_dev(vblk->disk),
- &dev_attr_cache_type_ro);
- if (err)
- goto out_del_disk;
+ device_add_disk(&vdev->dev, vblk->disk, virtblk_attr_groups);
return 0;
-out_del_disk:
- del_gendisk(vblk->disk);
- blk_cleanup_queue(vblk->disk->queue);
out_free_tags:
blk_mq_free_tag_set(&vblk->tag_set);
out_put_disk:
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index 429d20131c7e..0ed4b200fa58 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -1919,6 +1919,7 @@ static int negotiate_mq(struct blkfront_info *info)
GFP_KERNEL);
if (!info->rinfo) {
xenbus_dev_fatal(info->xbdev, -ENOMEM, "allocating ring_info structure");
+ info->nr_rings = 0;
return -ENOMEM;
}
@@ -2420,7 +2421,7 @@ static void blkfront_connect(struct blkfront_info *info)
for (i = 0; i < info->nr_rings; i++)
kick_pending_request_queues(&info->rinfo[i]);
- device_add_disk(&info->xbdev->dev, info->gd);
+ device_add_disk(&info->xbdev->dev, info->gd, NULL);
info->is_ready = 1;
return;
@@ -2493,6 +2494,9 @@ static int blkfront_remove(struct xenbus_device *xbdev)
dev_dbg(&xbdev->dev, "%s removed", xbdev->nodename);
+ if (!info)
+ return 0;
+
blkif_free(info, 0);
mutex_lock(&info->mutex);
diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c
index c24589414c75..87ccef4bd69e 100644
--- a/drivers/block/xsysace.c
+++ b/drivers/block/xsysace.c
@@ -88,7 +88,7 @@
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/slab.h>
-#include <linux/blkdev.h>
+#include <linux/blk-mq.h>
#include <linux/mutex.h>
#include <linux/ata.h>
#include <linux/hdreg.h>
@@ -209,6 +209,8 @@ struct ace_device {
struct device *dev;
struct request_queue *queue;
struct gendisk *gd;
+ struct blk_mq_tag_set tag_set;
+ struct list_head rq_list;
/* Inserted CF card parameters */
u16 cf_id[ATA_ID_WORDS];
@@ -462,18 +464,26 @@ static inline void ace_fsm_yieldirq(struct ace_device *ace)
ace->fsm_continue_flag = 0;
}
+static bool ace_has_next_request(struct request_queue *q)
+{
+ struct ace_device *ace = q->queuedata;
+
+ return !list_empty(&ace->rq_list);
+}
+
/* Get the next read/write request; ending requests that we don't handle */
static struct request *ace_get_next_request(struct request_queue *q)
{
- struct request *req;
+ struct ace_device *ace = q->queuedata;
+ struct request *rq;
- while ((req = blk_peek_request(q)) != NULL) {
- if (!blk_rq_is_passthrough(req))
- break;
- blk_start_request(req);
- __blk_end_request_all(req, BLK_STS_IOERR);
+ rq = list_first_entry_or_null(&ace->rq_list, struct request, queuelist);
+ if (rq) {
+ list_del_init(&rq->queuelist);
+ blk_mq_start_request(rq);
}
- return req;
+
+ return NULL;
}
static void ace_fsm_dostate(struct ace_device *ace)
@@ -499,11 +509,11 @@ static void ace_fsm_dostate(struct ace_device *ace)
/* Drop all in-flight and pending requests */
if (ace->req) {
- __blk_end_request_all(ace->req, BLK_STS_IOERR);
+ blk_mq_end_request(ace->req, BLK_STS_IOERR);
ace->req = NULL;
}
- while ((req = blk_fetch_request(ace->queue)) != NULL)
- __blk_end_request_all(req, BLK_STS_IOERR);
+ while ((req = ace_get_next_request(ace->queue)) != NULL)
+ blk_mq_end_request(req, BLK_STS_IOERR);
/* Drop back to IDLE state and notify waiters */
ace->fsm_state = ACE_FSM_STATE_IDLE;
@@ -517,7 +527,7 @@ static void ace_fsm_dostate(struct ace_device *ace)
switch (ace->fsm_state) {
case ACE_FSM_STATE_IDLE:
/* See if there is anything to do */
- if (ace->id_req_count || ace_get_next_request(ace->queue)) {
+ if (ace->id_req_count || ace_has_next_request(ace->queue)) {
ace->fsm_iter_num++;
ace->fsm_state = ACE_FSM_STATE_REQ_LOCK;
mod_timer(&ace->stall_timer, jiffies + HZ);
@@ -651,7 +661,6 @@ static void ace_fsm_dostate(struct ace_device *ace)
ace->fsm_state = ACE_FSM_STATE_IDLE;
break;
}
- blk_start_request(req);
/* Okay, it's a data request, set it up for transfer */
dev_dbg(ace->dev,
@@ -728,7 +737,8 @@ static void ace_fsm_dostate(struct ace_device *ace)
}
/* bio finished; is there another one? */
- if (__blk_end_request_cur(ace->req, BLK_STS_OK)) {
+ if (blk_update_request(ace->req, BLK_STS_OK,
+ blk_rq_cur_bytes(ace->req))) {
/* dev_dbg(ace->dev, "next block; h=%u c=%u\n",
* blk_rq_sectors(ace->req),
* blk_rq_cur_sectors(ace->req));
@@ -854,17 +864,23 @@ static irqreturn_t ace_interrupt(int irq, void *dev_id)
/* ---------------------------------------------------------------------
* Block ops
*/
-static void ace_request(struct request_queue * q)
+static blk_status_t ace_queue_rq(struct blk_mq_hw_ctx *hctx,
+ const struct blk_mq_queue_data *bd)
{
- struct request *req;
- struct ace_device *ace;
-
- req = ace_get_next_request(q);
+ struct ace_device *ace = hctx->queue->queuedata;
+ struct request *req = bd->rq;
- if (req) {
- ace = req->rq_disk->private_data;
- tasklet_schedule(&ace->fsm_tasklet);
+ if (blk_rq_is_passthrough(req)) {
+ blk_mq_start_request(req);
+ return BLK_STS_IOERR;
}
+
+ spin_lock_irq(&ace->lock);
+ list_add_tail(&req->queuelist, &ace->rq_list);
+ spin_unlock_irq(&ace->lock);
+
+ tasklet_schedule(&ace->fsm_tasklet);
+ return BLK_STS_OK;
}
static unsigned int ace_check_events(struct gendisk *gd, unsigned int clearing)
@@ -957,6 +973,10 @@ static const struct block_device_operations ace_fops = {
.getgeo = ace_getgeo,
};
+static const struct blk_mq_ops ace_mq_ops = {
+ .queue_rq = ace_queue_rq,
+};
+
/* --------------------------------------------------------------------
* SystemACE device setup/teardown code
*/
@@ -972,6 +992,7 @@ static int ace_setup(struct ace_device *ace)
spin_lock_init(&ace->lock);
init_completion(&ace->id_completion);
+ INIT_LIST_HEAD(&ace->rq_list);
/*
* Map the device
@@ -989,9 +1010,15 @@ static int ace_setup(struct ace_device *ace)
/*
* Initialize the request queue
*/
- ace->queue = blk_init_queue(ace_request, &ace->lock);
- if (ace->queue == NULL)
+ ace->queue = blk_mq_init_sq_queue(&ace->tag_set, &ace_mq_ops, 2,
+ BLK_MQ_F_SHOULD_MERGE);
+ if (IS_ERR(ace->queue)) {
+ rc = PTR_ERR(ace->queue);
+ ace->queue = NULL;
goto err_blk_initq;
+ }
+ ace->queue->queuedata = ace;
+
blk_queue_logical_block_size(ace->queue, 512);
blk_queue_bounce_limit(ace->queue, BLK_BOUNCE_HIGH);
@@ -1066,6 +1093,7 @@ err_read:
put_disk(ace->gd);
err_alloc_disk:
blk_cleanup_queue(ace->queue);
+ blk_mq_free_tag_set(&ace->tag_set);
err_blk_initq:
iounmap(ace->baseaddr);
err_ioremap:
@@ -1081,8 +1109,10 @@ static void ace_teardown(struct ace_device *ace)
put_disk(ace->gd);
}
- if (ace->queue)
+ if (ace->queue) {
blk_cleanup_queue(ace->queue);
+ blk_mq_free_tag_set(&ace->tag_set);
+ }
tasklet_kill(&ace->fsm_tasklet);
diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c
index d0c5bc4e0703..600430685e28 100644
--- a/drivers/block/z2ram.c
+++ b/drivers/block/z2ram.c
@@ -31,7 +31,7 @@
#include <linux/vmalloc.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/blkdev.h>
+#include <linux/blk-mq.h>
#include <linux/bitops.h>
#include <linux/mutex.h>
#include <linux/slab.h>
@@ -66,43 +66,44 @@ static DEFINE_SPINLOCK(z2ram_lock);
static struct gendisk *z2ram_gendisk;
-static void do_z2_request(struct request_queue *q)
+static blk_status_t z2_queue_rq(struct blk_mq_hw_ctx *hctx,
+ const struct blk_mq_queue_data *bd)
{
- struct request *req;
-
- req = blk_fetch_request(q);
- while (req) {
- unsigned long start = blk_rq_pos(req) << 9;
- unsigned long len = blk_rq_cur_bytes(req);
- blk_status_t err = BLK_STS_OK;
-
- if (start + len > z2ram_size) {
- pr_err(DEVICE_NAME ": bad access: block=%llu, "
- "count=%u\n",
- (unsigned long long)blk_rq_pos(req),
- blk_rq_cur_sectors(req));
- err = BLK_STS_IOERR;
- goto done;
- }
- while (len) {
- unsigned long addr = start & Z2RAM_CHUNKMASK;
- unsigned long size = Z2RAM_CHUNKSIZE - addr;
- void *buffer = bio_data(req->bio);
-
- if (len < size)
- size = len;
- addr += z2ram_map[ start >> Z2RAM_CHUNKSHIFT ];
- if (rq_data_dir(req) == READ)
- memcpy(buffer, (char *)addr, size);
- else
- memcpy((char *)addr, buffer, size);
- start += size;
- len -= size;
- }
- done:
- if (!__blk_end_request_cur(req, err))
- req = blk_fetch_request(q);
+ struct request *req = bd->rq;
+ unsigned long start = blk_rq_pos(req) << 9;
+ unsigned long len = blk_rq_cur_bytes(req);
+
+ blk_mq_start_request(req);
+
+ if (start + len > z2ram_size) {
+ pr_err(DEVICE_NAME ": bad access: block=%llu, "
+ "count=%u\n",
+ (unsigned long long)blk_rq_pos(req),
+ blk_rq_cur_sectors(req));
+ return BLK_STS_IOERR;
+ }
+
+ spin_lock_irq(&z2ram_lock);
+
+ while (len) {
+ unsigned long addr = start & Z2RAM_CHUNKMASK;
+ unsigned long size = Z2RAM_CHUNKSIZE - addr;
+ void *buffer = bio_data(req->bio);
+
+ if (len < size)
+ size = len;
+ addr += z2ram_map[ start >> Z2RAM_CHUNKSHIFT ];
+ if (rq_data_dir(req) == READ)
+ memcpy(buffer, (char *)addr, size);
+ else
+ memcpy((char *)addr, buffer, size);
+ start += size;
+ len -= size;
}
+
+ spin_unlock_irq(&z2ram_lock);
+ blk_mq_end_request(req, BLK_STS_OK);
+ return BLK_STS_OK;
}
static void
@@ -190,8 +191,7 @@ static int z2_open(struct block_device *bdev, fmode_t mode)
vfree(vmalloc (size));
}
- vaddr = (unsigned long) __ioremap (paddr, size,
- _PAGE_WRITETHRU);
+ vaddr = (unsigned long)ioremap_wt(paddr, size);
#else
vaddr = (unsigned long)z_remap_nocache_nonser(paddr, size);
@@ -337,6 +337,11 @@ static struct kobject *z2_find(dev_t dev, int *part, void *data)
}
static struct request_queue *z2_queue;
+static struct blk_mq_tag_set tag_set;
+
+static const struct blk_mq_ops z2_mq_ops = {
+ .queue_rq = z2_queue_rq,
+};
static int __init
z2_init(void)
@@ -355,9 +360,13 @@ z2_init(void)
if (!z2ram_gendisk)
goto out_disk;
- z2_queue = blk_init_queue(do_z2_request, &z2ram_lock);
- if (!z2_queue)
+ z2_queue = blk_mq_init_sq_queue(&tag_set, &z2_mq_ops, 16,
+ BLK_MQ_F_SHOULD_MERGE);
+ if (IS_ERR(z2_queue)) {
+ ret = PTR_ERR(z2_queue);
+ z2_queue = NULL;
goto out_queue;
+ }
z2ram_gendisk->major = Z2RAM_MAJOR;
z2ram_gendisk->first_minor = 0;
@@ -387,6 +396,7 @@ static void __exit z2_exit(void)
del_gendisk(z2ram_gendisk);
put_disk(z2ram_gendisk);
blk_cleanup_queue(z2_queue);
+ blk_mq_free_tag_set(&tag_set);
if ( current_device != -1 )
{
diff --git a/drivers/block/zram/Kconfig b/drivers/block/zram/Kconfig
index 635235759a0a..fcd055457364 100644
--- a/drivers/block/zram/Kconfig
+++ b/drivers/block/zram/Kconfig
@@ -3,7 +3,6 @@ config ZRAM
tristate "Compressed RAM block device support"
depends on BLOCK && SYSFS && ZSMALLOC && CRYPTO
select CRYPTO_LZO
- default n
help
Creates virtual block devices called /dev/zramX (X = 0, 1, ...).
Pages written to these disks are compressed and stored in memory
@@ -18,7 +17,6 @@ config ZRAM
config ZRAM_WRITEBACK
bool "Write back incompressible page to backing device"
depends on ZRAM
- default n
help
With incompressible page, there is no memory saving to keep it
in memory. Instead, write it out to backing device.
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index a1d6b5597c17..4879595200e1 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -1636,6 +1636,11 @@ static const struct attribute_group zram_disk_attr_group = {
.attrs = zram_disk_attrs,
};
+static const struct attribute_group *zram_disk_attr_groups[] = {
+ &zram_disk_attr_group,
+ NULL,
+};
+
/*
* Allocate and initialize new zram device. the function returns
* '>= 0' device_id upon success, and negative value otherwise.
@@ -1716,24 +1721,14 @@ static int zram_add(void)
zram->disk->queue->backing_dev_info->capabilities |=
(BDI_CAP_STABLE_WRITES | BDI_CAP_SYNCHRONOUS_IO);
- add_disk(zram->disk);
-
- ret = sysfs_create_group(&disk_to_dev(zram->disk)->kobj,
- &zram_disk_attr_group);
- if (ret < 0) {
- pr_err("Error creating sysfs group for device %d\n",
- device_id);
- goto out_free_disk;
- }
+ device_add_disk(NULL, zram->disk, zram_disk_attr_groups);
+
strlcpy(zram->compressor, default_compressor, sizeof(zram->compressor));
zram_debugfs_register(zram);
pr_info("Added device: %s\n", zram->disk->disk_name);
return device_id;
-out_free_disk:
- del_gendisk(zram->disk);
- put_disk(zram->disk);
out_free_queue:
blk_cleanup_queue(queue);
out_free_idr:
@@ -1762,15 +1757,6 @@ static int zram_remove(struct zram *zram)
mutex_unlock(&bdev->bd_mutex);
zram_debugfs_unregister(zram);
- /*
- * Remove sysfs first, so no one will perform a disksize
- * store while we destroy the devices. This also helps during
- * hot_remove -- zram_reset_device() is the last holder of
- * ->init_lock, no later/concurrent disksize_store() or any
- * other sysfs handlers are possible.
- */
- sysfs_remove_group(&disk_to_dev(zram->disk)->kobj,
- &zram_disk_attr_group);
/* Make sure all the pending I/O are finished */
fsync_bdev(bdev);
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
index 3d7a5c149af3..1ad4991753bb 100644
--- a/drivers/bluetooth/ath3k.c
+++ b/drivers/bluetooth/ath3k.c
@@ -203,10 +203,11 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
{ } /* Terminating entry */
};
-static inline void ath3k_log_failed_loading(int err, int len, int size)
+static inline void ath3k_log_failed_loading(int err, int len, int size,
+ int count)
{
- BT_ERR("Error in firmware loading err = %d, len = %d, size = %d",
- err, len, size);
+ BT_ERR("Firmware loading err = %d, len = %d, size = %d, count = %d",
+ err, len, size, count);
}
#define USB_REQ_DFU_DNLOAD 1
@@ -257,7 +258,7 @@ static int ath3k_load_firmware(struct usb_device *udev,
&len, 3000);
if (err || (len != size)) {
- ath3k_log_failed_loading(err, len, size);
+ ath3k_log_failed_loading(err, len, size, count);
goto error;
}
@@ -356,7 +357,7 @@ static int ath3k_load_fwfile(struct usb_device *udev,
err = usb_bulk_msg(udev, pipe, send_buf, size,
&len, 3000);
if (err || (len != size)) {
- ath3k_log_failed_loading(err, len, size);
+ ath3k_log_failed_loading(err, len, size, count);
kfree(send_buf);
return err;
}
diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
index 25b0cf952b91..54713833951a 100644
--- a/drivers/bluetooth/bt3c_cs.c
+++ b/drivers/bluetooth/bt3c_cs.c
@@ -448,7 +448,7 @@ static int bt3c_load_firmware(struct bt3c_info *info,
{
char *ptr = (char *) firmware;
char b[9];
- unsigned int iobase, tmp;
+ unsigned int iobase, tmp, tn;
unsigned long size, addr, fcs;
int i, err = 0;
@@ -490,7 +490,9 @@ static int bt3c_load_firmware(struct bt3c_info *info,
memset(b, 0, sizeof(b));
for (tmp = 0, i = 0; i < size; i++) {
memcpy(b, ptr + (i * 2) + 2, 2);
- tmp += simple_strtol(b, NULL, 16);
+ if (kstrtouint(b, 16, &tn))
+ return -EINVAL;
+ tmp += tn;
}
if (((tmp + fcs) & 0xff) != 0xff) {
@@ -505,7 +507,8 @@ static int bt3c_load_firmware(struct bt3c_info *info,
memset(b, 0, sizeof(b));
for (i = 0; i < (size - 4) / 2; i++) {
memcpy(b, ptr + (i * 4) + 12, 4);
- tmp = simple_strtoul(b, NULL, 16);
+ if (kstrtouint(b, 16, &tmp))
+ return -EINVAL;
bt3c_put(iobase, tmp);
}
}
diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c
index 99cde1f9467d..e3e4d929e74f 100644
--- a/drivers/bluetooth/btbcm.c
+++ b/drivers/bluetooth/btbcm.c
@@ -324,6 +324,7 @@ static const struct bcm_subver_table bcm_uart_subver_table[] = {
{ 0x4103, "BCM4330B1" }, /* 002.001.003 */
{ 0x410e, "BCM43341B0" }, /* 002.001.014 */
{ 0x4406, "BCM4324B3" }, /* 002.004.006 */
+ { 0x6109, "BCM4335C0" }, /* 003.001.009 */
{ 0x610c, "BCM4354" }, /* 003.001.012 */
{ 0x2122, "BCM4343A0" }, /* 001.001.034 */
{ 0x2209, "BCM43430A1" }, /* 001.002.009 */
diff --git a/drivers/bluetooth/btrsi.c b/drivers/bluetooth/btrsi.c
index 60d1419590ba..3951f7b23840 100644
--- a/drivers/bluetooth/btrsi.c
+++ b/drivers/bluetooth/btrsi.c
@@ -21,8 +21,9 @@
#include <net/rsi_91x.h>
#include <net/genetlink.h>
-#define RSI_HEADROOM_FOR_BT_HAL 16
+#define RSI_DMA_ALIGN 8
#define RSI_FRAME_DESC_SIZE 16
+#define RSI_HEADROOM_FOR_BT_HAL (RSI_FRAME_DESC_SIZE + RSI_DMA_ALIGN)
struct rsi_hci_adapter {
void *priv;
@@ -70,6 +71,16 @@ static int rsi_hci_send_pkt(struct hci_dev *hdev, struct sk_buff *skb)
bt_cb(new_skb)->pkt_type = hci_skb_pkt_type(skb);
kfree_skb(skb);
skb = new_skb;
+ if (!IS_ALIGNED((unsigned long)skb->data, RSI_DMA_ALIGN)) {
+ u8 *skb_data = skb->data;
+ int skb_len = skb->len;
+
+ skb_push(skb, RSI_DMA_ALIGN);
+ skb_pull(skb, PTR_ALIGN(skb->data,
+ RSI_DMA_ALIGN) - skb->data);
+ memmove(skb->data, skb_data, skb_len);
+ skb_trim(skb, skb_len);
+ }
}
return h_adapter->proto_ops->coex_send_pkt(h_adapter->priv, skb,
diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c
index 7f9ea8e4c1b2..41405de27d66 100644
--- a/drivers/bluetooth/btrtl.c
+++ b/drivers/bluetooth/btrtl.c
@@ -138,6 +138,13 @@ static const struct id_table ic_id_table[] = {
.fw_name = "rtl_bt/rtl8761a_fw.bin",
.cfg_name = "rtl_bt/rtl8761a_config" },
+ /* 8822C with USB interface */
+ { IC_INFO(RTL_ROM_LMP_8822B, 0xc),
+ .config_needed = false,
+ .has_rom_version = true,
+ .fw_name = "rtl_bt/rtl8822cu_fw.bin",
+ .cfg_name = "rtl_bt/rtl8822cu_config" },
+
/* 8822B */
{ IC_INFO(RTL_ROM_LMP_8822B, 0xb),
.config_needed = true,
@@ -206,7 +213,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev,
struct btrtl_device_info *btrtl_dev,
unsigned char **_buf)
{
- const u8 extension_sig[] = { 0x51, 0x04, 0xfd, 0x77 };
+ static const u8 extension_sig[] = { 0x51, 0x04, 0xfd, 0x77 };
struct rtl_epatch_header *epatch_info;
unsigned char *buf;
int i, len;
@@ -228,6 +235,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev,
{ RTL_ROM_LMP_8822B, 8 },
{ RTL_ROM_LMP_8723B, 9 }, /* 8723D */
{ RTL_ROM_LMP_8821A, 10 }, /* 8821C */
+ { RTL_ROM_LMP_8822B, 13 }, /* 8822C */
};
min_size = sizeof(struct rtl_epatch_header) + sizeof(extension_sig) + 3;
diff --git a/drivers/bluetooth/btsdio.c b/drivers/bluetooth/btsdio.c
index 20142bc77554..282d1af1d3ba 100644
--- a/drivers/bluetooth/btsdio.c
+++ b/drivers/bluetooth/btsdio.c
@@ -293,13 +293,17 @@ static int btsdio_probe(struct sdio_func *func,
tuple = tuple->next;
}
- /* BCM43341 devices soldered onto the PCB (non-removable) use an
- * uart connection for bluetooth, ignore the BT SDIO interface.
+ /* Broadcom devices soldered onto the PCB (non-removable) use an
+ * UART connection for Bluetooth, ignore the BT SDIO interface.
*/
if (func->vendor == SDIO_VENDOR_ID_BROADCOM &&
- func->device == SDIO_DEVICE_ID_BROADCOM_43341 &&
- !mmc_card_is_removable(func->card->host))
- return -ENODEV;
+ !mmc_card_is_removable(func->card->host)) {
+ switch (func->device) {
+ case SDIO_DEVICE_ID_BROADCOM_43341:
+ case SDIO_DEVICE_ID_BROADCOM_43430:
+ return -ENODEV;
+ }
+ }
data = devm_kzalloc(&func->dev, sizeof(*data), GFP_KERNEL);
if (!data)
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index cd2e5cf14ea5..7439a7eb50ac 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -264,6 +264,7 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 },
/* QCA ROME chipset */
+ { USB_DEVICE(0x0cf3, 0x535b), .driver_info = BTUSB_QCA_ROME },
{ USB_DEVICE(0x0cf3, 0xe007), .driver_info = BTUSB_QCA_ROME },
{ USB_DEVICE(0x0cf3, 0xe009), .driver_info = BTUSB_QCA_ROME },
{ USB_DEVICE(0x0cf3, 0xe010), .driver_info = BTUSB_QCA_ROME },
@@ -3096,6 +3097,7 @@ static int btusb_probe(struct usb_interface *intf,
hdev->set_diag = btintel_set_diag;
hdev->set_bdaddr = btintel_set_bdaddr;
set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
+ set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks);
}
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index ea6238ed5c0e..fbf7b4df23ab 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -823,6 +823,7 @@ static int __init hci_uart_init(void)
hci_uart_ldisc.read = hci_uart_tty_read;
hci_uart_ldisc.write = hci_uart_tty_write;
hci_uart_ldisc.ioctl = hci_uart_tty_ioctl;
+ hci_uart_ldisc.compat_ioctl = hci_uart_tty_ioctl;
hci_uart_ldisc.poll = hci_uart_tty_poll;
hci_uart_ldisc.receive_buf = hci_uart_tty_receive;
hci_uart_ldisc.write_wakeup = hci_uart_tty_wakeup;
diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index e182f6019f68..f036c8f98ea3 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -40,6 +40,7 @@
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/serdev.h>
+#include <asm/unaligned.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
@@ -63,6 +64,9 @@
/* susclk rate */
#define SUSCLK_RATE_32KHZ 32768
+/* Controller debug log header */
+#define QCA_DEBUG_HANDLE 0x2EDC
+
/* HCI_IBS transmit side sleep protocol states */
enum tx_ibs_states {
HCI_IBS_TX_ASLEEP,
@@ -167,7 +171,8 @@ struct qca_serdev {
};
static int qca_power_setup(struct hci_uart *hu, bool on);
-static void qca_power_shutdown(struct hci_dev *hdev);
+static void qca_power_shutdown(struct hci_uart *hu);
+static int qca_power_off(struct hci_dev *hdev);
static void __serial_clock_on(struct tty_struct *tty)
{
@@ -499,7 +504,6 @@ static int qca_open(struct hci_uart *hu)
hu->priv = qca;
if (hu->serdev) {
- serdev_device_open(hu->serdev);
qcadev = serdev_device_get_drvdata(hu->serdev);
if (qcadev->btsoc_type != QCA_WCN3990) {
@@ -609,11 +613,10 @@ static int qca_close(struct hci_uart *hu)
if (hu->serdev) {
qcadev = serdev_device_get_drvdata(hu->serdev);
if (qcadev->btsoc_type == QCA_WCN3990)
- qca_power_shutdown(hu->hdev);
+ qca_power_shutdown(hu);
else
gpiod_set_value_cansleep(qcadev->bt_en, 0);
- serdev_device_close(hu->serdev);
}
kfree_skb(qca->rx_skb);
@@ -850,6 +853,19 @@ static int qca_ibs_wake_ack(struct hci_dev *hdev, struct sk_buff *skb)
return 0;
}
+static int qca_recv_acl_data(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ /* We receive debug logs from chip as an ACL packets.
+ * Instead of sending the data to ACL to decode the
+ * received data, we are pushing them to the above layers
+ * as a diagnostic packet.
+ */
+ if (get_unaligned_le16(skb->data) == QCA_DEBUG_HANDLE)
+ return hci_recv_diag(hdev, skb);
+
+ return hci_recv_frame(hdev, skb);
+}
+
#define QCA_IBS_SLEEP_IND_EVENT \
.type = HCI_IBS_SLEEP_IND, \
.hlen = 0, \
@@ -872,7 +888,7 @@ static int qca_ibs_wake_ack(struct hci_dev *hdev, struct sk_buff *skb)
.maxlen = HCI_MAX_IBS_SIZE
static const struct h4_recv_pkt qca_recv_pkts[] = {
- { H4_RECV_ACL, .recv = hci_recv_frame },
+ { H4_RECV_ACL, .recv = qca_recv_acl_data },
{ H4_RECV_SCO, .recv = hci_recv_frame },
{ H4_RECV_EVENT, .recv = hci_recv_frame },
{ QCA_IBS_WAKE_IND_EVENT, .recv = qca_ibs_wake_ind },
@@ -1101,8 +1117,26 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type)
static int qca_wcn3990_init(struct hci_uart *hu)
{
struct hci_dev *hdev = hu->hdev;
+ struct qca_serdev *qcadev;
int ret;
+ /* Check for vregs status, may be hci down has turned
+ * off the voltage regulator.
+ */
+ qcadev = serdev_device_get_drvdata(hu->serdev);
+ if (!qcadev->bt_power->vregs_on) {
+ serdev_device_close(hu->serdev);
+ ret = qca_power_setup(hu, true);
+ if (ret)
+ return ret;
+
+ ret = serdev_device_open(hu->serdev);
+ if (ret) {
+ bt_dev_err(hu->hdev, "failed to open port");
+ return ret;
+ }
+ }
+
/* Forcefully enable wcn3990 to enter in to boot mode. */
host_set_baudrate(hu, 2400);
ret = qca_send_power_pulse(hdev, QCA_WCN3990_POWEROFF_PULSE);
@@ -1154,6 +1188,12 @@ static int qca_setup(struct hci_uart *hu)
if (qcadev->btsoc_type == QCA_WCN3990) {
bt_dev_info(hdev, "setting up wcn3990");
+
+ /* Enable NON_PERSISTENT_SETUP QUIRK to ensure to execute
+ * setup for every hci up.
+ */
+ set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks);
+ hu->hdev->shutdown = qca_power_off;
ret = qca_wcn3990_init(hu);
if (ret)
return ret;
@@ -1232,15 +1272,26 @@ static const struct qca_vreg_data qca_soc_data = {
.num_vregs = 4,
};
-static void qca_power_shutdown(struct hci_dev *hdev)
+static void qca_power_shutdown(struct hci_uart *hu)
{
- struct hci_uart *hu = hci_get_drvdata(hdev);
+ struct serdev_device *serdev = hu->serdev;
+ unsigned char cmd = QCA_WCN3990_POWEROFF_PULSE;
host_set_baudrate(hu, 2400);
- qca_send_power_pulse(hdev, QCA_WCN3990_POWEROFF_PULSE);
+ hci_uart_set_flow_control(hu, true);
+ serdev_device_write_buf(serdev, &cmd, sizeof(cmd));
+ hci_uart_set_flow_control(hu, false);
qca_power_setup(hu, false);
}
+static int qca_power_off(struct hci_dev *hdev)
+{
+ struct hci_uart *hu = hci_get_drvdata(hdev);
+
+ qca_power_shutdown(hu);
+ return 0;
+}
+
static int qca_enable_regulator(struct qca_vreg vregs,
struct regulator *regulator)
{
@@ -1322,7 +1373,7 @@ static int qca_init_regulators(struct qca_power *qca,
{
int i;
- qca->vreg_bulk = devm_kzalloc(qca->dev, num_vregs *
+ qca->vreg_bulk = devm_kcalloc(qca->dev, num_vregs,
sizeof(struct regulator_bulk_data),
GFP_KERNEL);
if (!qca->vreg_bulk)
@@ -1413,7 +1464,7 @@ static void qca_serdev_remove(struct serdev_device *serdev)
struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev);
if (qcadev->btsoc_type == QCA_WCN3990)
- qca_power_shutdown(qcadev->serdev_hu.hdev);
+ qca_power_shutdown(&qcadev->serdev_hu);
else
clk_disable_unprepare(qcadev->susclk);
diff --git a/drivers/bluetooth/hci_serdev.c b/drivers/bluetooth/hci_serdev.c
index aa2543b3c286..c445aa9ac511 100644
--- a/drivers/bluetooth/hci_serdev.c
+++ b/drivers/bluetooth/hci_serdev.c
@@ -57,9 +57,10 @@ static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu)
{
struct sk_buff *skb = hu->tx_skb;
- if (!skb)
- skb = hu->proto->dequeue(hu);
- else
+ if (!skb) {
+ if (test_bit(HCI_UART_PROTO_READY, &hu->flags))
+ skb = hu->proto->dequeue(hu);
+ } else
hu->tx_skb = NULL;
return skb;
@@ -94,7 +95,7 @@ static void hci_uart_write_work(struct work_struct *work)
hci_uart_tx_complete(hu, hci_skb_pkt_type(skb));
kfree_skb(skb);
}
- } while(test_bit(HCI_UART_TX_WAKEUP, &hu->tx_state));
+ } while (test_bit(HCI_UART_TX_WAKEUP, &hu->tx_state));
clear_bit(HCI_UART_SENDING, &hu->tx_state);
}
@@ -368,6 +369,7 @@ void hci_uart_unregister_device(struct hci_uart *hu)
{
struct hci_dev *hdev = hu->hdev;
+ clear_bit(HCI_UART_PROTO_READY, &hu->flags);
hci_unregister_dev(hdev);
hci_free_dev(hdev);
diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c
index 5d8266c6571f..f0404c6d1ff4 100644
--- a/drivers/bus/fsl-mc/fsl-mc-bus.c
+++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
@@ -127,6 +127,16 @@ static int fsl_mc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
return 0;
}
+static int fsl_mc_dma_configure(struct device *dev)
+{
+ struct device *dma_dev = dev;
+
+ while (dev_is_fsl_mc(dma_dev))
+ dma_dev = dma_dev->parent;
+
+ return of_dma_configure(dev, dma_dev->of_node, 0);
+}
+
static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -148,6 +158,7 @@ struct bus_type fsl_mc_bus_type = {
.name = "fsl-mc",
.match = fsl_mc_bus_match,
.uevent = fsl_mc_bus_uevent,
+ .dma_configure = fsl_mc_dma_configure,
.dev_groups = fsl_mc_dev_groups,
};
EXPORT_SYMBOL_GPL(fsl_mc_bus_type);
@@ -188,6 +199,10 @@ struct device_type fsl_mc_bus_dprtc_type = {
.name = "fsl_mc_bus_dprtc"
};
+struct device_type fsl_mc_bus_dpseci_type = {
+ .name = "fsl_mc_bus_dpseci"
+};
+
static struct device_type *fsl_mc_get_device_type(const char *type)
{
static const struct {
@@ -203,6 +218,7 @@ static struct device_type *fsl_mc_get_device_type(const char *type)
{ &fsl_mc_bus_dpmcp_type, "dpmcp" },
{ &fsl_mc_bus_dpmac_type, "dpmac" },
{ &fsl_mc_bus_dprtc_type, "dprtc" },
+ { &fsl_mc_bus_dpseci_type, "dpseci" },
{ NULL, NULL }
};
int i;
@@ -616,6 +632,7 @@ int fsl_mc_device_add(struct fsl_mc_obj_desc *obj_desc,
mc_dev->icid = parent_mc_dev->icid;
mc_dev->dma_mask = FSL_MC_DEFAULT_DMA_MASK;
mc_dev->dev.dma_mask = &mc_dev->dma_mask;
+ mc_dev->dev.coherent_dma_mask = mc_dev->dma_mask;
dev_set_msi_domain(&mc_dev->dev,
dev_get_msi_domain(&parent_mc_dev->dev));
}
@@ -633,10 +650,6 @@ int fsl_mc_device_add(struct fsl_mc_obj_desc *obj_desc,
goto error_cleanup_dev;
}
- /* Objects are coherent, unless 'no shareability' flag set. */
- if (!(obj_desc->flags & FSL_MC_OBJ_FLAG_NO_MEM_SHAREABILITY))
- arch_setup_dma_ops(&mc_dev->dev, 0, 0, NULL, true);
-
/*
* The device-specific probe callback will get invoked by device_add()
*/
@@ -693,8 +706,8 @@ static int parse_mc_ranges(struct device *dev,
*ranges_start = of_get_property(mc_node, "ranges", &ranges_len);
if (!(*ranges_start) || !ranges_len) {
dev_warn(dev,
- "missing or empty ranges property for device tree node '%s'\n",
- mc_node->name);
+ "missing or empty ranges property for device tree node '%pOFn'\n",
+ mc_node);
return 0;
}
@@ -717,7 +730,7 @@ static int parse_mc_ranges(struct device *dev,
tuple_len = range_tuple_cell_count * sizeof(__be32);
if (ranges_len % tuple_len != 0) {
- dev_err(dev, "malformed ranges property '%s'\n", mc_node->name);
+ dev_err(dev, "malformed ranges property '%pOFn'\n", mc_node);
return -EINVAL;
}
diff --git a/drivers/bus/imx-weim.c b/drivers/bus/imx-weim.c
index 6a94aa6a22c2..d84996a4528e 100644
--- a/drivers/bus/imx-weim.c
+++ b/drivers/bus/imx-weim.c
@@ -156,9 +156,6 @@ static int __init weim_parse_dt(struct platform_device *pdev,
}
for_each_available_child_of_node(pdev->dev.of_node, child) {
- if (!child->name)
- continue;
-
ret = weim_timing_setup(child, base, devtype);
if (ret)
dev_warn(&pdev->dev, "%pOF set timing failed.\n",
diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c
index 70db4d5638a6..5b2a11a88951 100644
--- a/drivers/bus/mvebu-mbus.c
+++ b/drivers/bus/mvebu-mbus.c
@@ -1229,7 +1229,7 @@ mbus_parse_ranges(struct device_node *node,
tuple_len = (*cell_count) * sizeof(__be32);
if (ranges_len % tuple_len) {
- pr_warn("malformed ranges entry '%s'\n", node->name);
+ pr_warn("malformed ranges entry '%pOFn'\n", node);
return -EINVAL;
}
return 0;
diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c
index e4fe954e63a9..a3a2d39280d9 100644
--- a/drivers/bus/ti-sysc.c
+++ b/drivers/bus/ti-sysc.c
@@ -701,69 +701,7 @@ awake:
return error;
}
-#ifdef CONFIG_PM_SLEEP
-static int sysc_suspend(struct device *dev)
-{
- struct sysc *ddata;
- int error;
-
- ddata = dev_get_drvdata(dev);
-
- if (ddata->cfg.quirks & (SYSC_QUIRK_RESOURCE_PROVIDER |
- SYSC_QUIRK_LEGACY_IDLE))
- return 0;
-
- if (!ddata->enabled)
- return 0;
-
- dev_dbg(ddata->dev, "%s %s\n", __func__,
- ddata->name ? ddata->name : "");
-
- error = pm_runtime_put_sync_suspend(dev);
- if (error < 0) {
- dev_warn(ddata->dev, "%s not idle %i %s\n",
- __func__, error,
- ddata->name ? ddata->name : "");
-
- return 0;
- }
-
- ddata->needs_resume = true;
-
- return 0;
-}
-
-static int sysc_resume(struct device *dev)
-{
- struct sysc *ddata;
- int error;
-
- ddata = dev_get_drvdata(dev);
-
- if (ddata->cfg.quirks & (SYSC_QUIRK_RESOURCE_PROVIDER |
- SYSC_QUIRK_LEGACY_IDLE))
- return 0;
-
- if (ddata->needs_resume) {
- dev_dbg(ddata->dev, "%s %s\n", __func__,
- ddata->name ? ddata->name : "");
-
- error = pm_runtime_get_sync(dev);
- if (error < 0) {
- dev_err(ddata->dev, "%s error %i %s\n",
- __func__, error,
- ddata->name ? ddata->name : "");
-
- return error;
- }
-
- ddata->needs_resume = false;
- }
-
- return 0;
-}
-
-static int sysc_noirq_suspend(struct device *dev)
+static int __maybe_unused sysc_noirq_suspend(struct device *dev)
{
struct sysc *ddata;
@@ -772,21 +710,10 @@ static int sysc_noirq_suspend(struct device *dev)
if (ddata->cfg.quirks & SYSC_QUIRK_LEGACY_IDLE)
return 0;
- if (!(ddata->cfg.quirks & SYSC_QUIRK_RESOURCE_PROVIDER))
- return 0;
-
- if (!ddata->enabled)
- return 0;
-
- dev_dbg(ddata->dev, "%s %s\n", __func__,
- ddata->name ? ddata->name : "");
-
- ddata->needs_resume = true;
-
- return sysc_runtime_suspend(dev);
+ return pm_runtime_force_suspend(dev);
}
-static int sysc_noirq_resume(struct device *dev)
+static int __maybe_unused sysc_noirq_resume(struct device *dev)
{
struct sysc *ddata;
@@ -795,24 +722,10 @@ static int sysc_noirq_resume(struct device *dev)
if (ddata->cfg.quirks & SYSC_QUIRK_LEGACY_IDLE)
return 0;
- if (!(ddata->cfg.quirks & SYSC_QUIRK_RESOURCE_PROVIDER))
- return 0;
-
- if (ddata->needs_resume) {
- dev_dbg(ddata->dev, "%s %s\n", __func__,
- ddata->name ? ddata->name : "");
-
- ddata->needs_resume = false;
-
- return sysc_runtime_resume(dev);
- }
-
- return 0;
+ return pm_runtime_force_resume(dev);
}
-#endif
static const struct dev_pm_ops sysc_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(sysc_suspend, sysc_resume)
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(sysc_noirq_suspend, sysc_noirq_resume)
SET_RUNTIME_PM_OPS(sysc_runtime_suspend,
sysc_runtime_resume,
@@ -845,28 +758,8 @@ struct sysc_revision_quirk {
}
static const struct sysc_revision_quirk sysc_revision_quirks[] = {
- /* These need to use noirq_suspend */
- SYSC_QUIRK("control", 0, 0, 0x10, -1, 0x40000900, 0xffffffff,
- SYSC_QUIRK_RESOURCE_PROVIDER),
- SYSC_QUIRK("i2c", 0, 0, 0x10, 0x90, 0x5040000a, 0xffffffff,
- SYSC_QUIRK_RESOURCE_PROVIDER),
- SYSC_QUIRK("mcspi", 0, 0, 0x10, -1, 0x40300a0b, 0xffffffff,
- SYSC_QUIRK_RESOURCE_PROVIDER),
- SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x40000100, 0xffffffff,
- SYSC_QUIRK_RESOURCE_PROVIDER),
- SYSC_QUIRK("ocp2scp", 0, 0, 0x10, 0x14, 0x50060005, 0xffffffff,
- SYSC_QUIRK_RESOURCE_PROVIDER),
- SYSC_QUIRK("padconf", 0, 0, 0x10, -1, 0x4fff0800, 0xffffffff,
- SYSC_QUIRK_RESOURCE_PROVIDER),
- SYSC_QUIRK("scm", 0, 0, 0x10, -1, 0x40000900, 0xffffffff,
- SYSC_QUIRK_RESOURCE_PROVIDER),
- SYSC_QUIRK("scrm", 0, 0, -1, -1, 0x00000010, 0xffffffff,
- SYSC_QUIRK_RESOURCE_PROVIDER),
- SYSC_QUIRK("sdma", 0, 0, 0x2c, 0x28, 0x00010900, 0xffffffff,
- SYSC_QUIRK_RESOURCE_PROVIDER),
-
/* These drivers need to be fixed to not use pm_runtime_irq_safe() */
- SYSC_QUIRK("gpio", 0, 0, 0x10, 0x114, 0x50600801, 0xffffffff,
+ SYSC_QUIRK("gpio", 0, 0, 0x10, 0x114, 0x50600801, 0xffff00ff,
SYSC_QUIRK_LEGACY_IDLE | SYSC_QUIRK_OPT_CLKS_IN_RESET),
SYSC_QUIRK("mmu", 0, 0, 0x10, 0x14, 0x00000020, 0xffffffff,
SYSC_QUIRK_LEGACY_IDLE),
@@ -881,38 +774,70 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
SYSC_QUIRK("timer", 0, 0, 0x10, 0x14, 0x00000015, 0xffffffff,
SYSC_QUIRK_LEGACY_IDLE),
/* Some timers on omap4 and later */
- SYSC_QUIRK("timer", 0, 0, 0x10, -1, 0x4fff1301, 0xffffffff,
+ SYSC_QUIRK("timer", 0, 0, 0x10, -1, 0x50002100, 0xffffffff,
+ SYSC_QUIRK_LEGACY_IDLE),
+ SYSC_QUIRK("timer", 0, 0, 0x10, -1, 0x4fff1301, 0xffff00ff,
SYSC_QUIRK_LEGACY_IDLE),
SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000052, 0xffffffff,
SYSC_QUIRK_LEGACY_IDLE),
/* Uarts on omap4 and later */
- SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x50411e03, 0xffffffff,
+ SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x50411e03, 0xffff00ff,
SYSC_QUIRK_LEGACY_IDLE),
-
- /* These devices don't yet suspend properly without legacy setting */
- SYSC_QUIRK("sdio", 0, 0, 0x10, -1, 0x40202301, 0xffffffff,
- SYSC_QUIRK_LEGACY_IDLE),
- SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0500, 0xffffffff,
- SYSC_QUIRK_LEGACY_IDLE),
- SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0d00, 0xffffffff,
+ SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x47422e03, 0xffffffff,
SYSC_QUIRK_LEGACY_IDLE),
#ifdef DEBUG
+ SYSC_QUIRK("adc", 0, 0, 0x10, -1, 0x47300001, 0xffffffff, 0),
+ SYSC_QUIRK("atl", 0, 0, -1, -1, 0x0a070100, 0xffffffff, 0),
SYSC_QUIRK("aess", 0, 0, 0x10, -1, 0x40000000, 0xffffffff, 0),
+ SYSC_QUIRK("cm", 0, 0, -1, -1, 0x40000301, 0xffffffff, 0),
+ SYSC_QUIRK("control", 0, 0, 0x10, -1, 0x40000900, 0xffffffff, 0),
+ SYSC_QUIRK("cpgmac", 0, 0x1200, 0x1208, 0x1204, 0x4edb1902,
+ 0xffff00f0, 0),
+ SYSC_QUIRK("dcan", 0, 0, -1, -1, 0xffffffff, 0xffffffff, 0),
+ SYSC_QUIRK("dcan", 0, 0, -1, -1, 0x00001401, 0xffffffff, 0),
+ SYSC_QUIRK("dwc3", 0, 0, 0x10, -1, 0x500a0200, 0xffffffff, 0),
+ SYSC_QUIRK("epwmss", 0, 0, 0x4, -1, 0x47400001, 0xffffffff, 0),
SYSC_QUIRK("gpu", 0, 0x1fc00, 0x1fc10, -1, 0, 0, 0),
SYSC_QUIRK("hdq1w", 0, 0, 0x14, 0x18, 0x00000006, 0xffffffff, 0),
+ SYSC_QUIRK("hdq1w", 0, 0, 0x14, 0x18, 0x0000000a, 0xffffffff, 0),
SYSC_QUIRK("hsi", 0, 0, 0x10, 0x14, 0x50043101, 0xffffffff, 0),
SYSC_QUIRK("iss", 0, 0, 0x10, -1, 0x40000101, 0xffffffff, 0),
+ SYSC_QUIRK("i2c", 0, 0, 0x10, 0x90, 0x5040000a, 0xfffff0f0, 0),
+ SYSC_QUIRK("lcdc", 0, 0, 0x54, -1, 0x4f201000, 0xffffffff, 0),
SYSC_QUIRK("mcasp", 0, 0, 0x4, -1, 0x44306302, 0xffffffff, 0),
+ SYSC_QUIRK("mcasp", 0, 0, 0x4, -1, 0x44307b02, 0xffffffff, 0),
SYSC_QUIRK("mcbsp", 0, -1, 0x8c, -1, 0, 0, 0),
+ SYSC_QUIRK("mcspi", 0, 0, 0x10, -1, 0x40300a0b, 0xffff00ff, 0),
+ SYSC_QUIRK("mcspi", 0, 0, 0x110, 0x114, 0x40300a0b, 0xffffffff, 0),
SYSC_QUIRK("mailbox", 0, 0, 0x10, -1, 0x00000400, 0xffffffff, 0),
+ SYSC_QUIRK("m3", 0, 0, -1, -1, 0x5f580105, 0x0fff0f00, 0),
+ SYSC_QUIRK("ocp2scp", 0, 0, 0x10, 0x14, 0x50060005, 0xfffffff0, 0),
+ SYSC_QUIRK("ocp2scp", 0, 0, -1, -1, 0x50060007, 0xffffffff, 0),
+ SYSC_QUIRK("padconf", 0, 0, 0x10, -1, 0x4fff0800, 0xffffffff, 0),
+ SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x40000100, 0xffffffff, 0),
+ SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x00004102, 0xffffffff, 0),
+ SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x40000400, 0xffffffff, 0),
+ SYSC_QUIRK("scm", 0, 0, 0x10, -1, 0x40000900, 0xffffffff, 0),
+ SYSC_QUIRK("scm", 0, 0, -1, -1, 0x4e8b0100, 0xffffffff, 0),
+ SYSC_QUIRK("scm", 0, 0, -1, -1, 0x4f000100, 0xffffffff, 0),
+ SYSC_QUIRK("scm", 0, 0, -1, -1, 0x40000900, 0xffffffff, 0),
+ SYSC_QUIRK("scrm", 0, 0, -1, -1, 0x00000010, 0xffffffff, 0),
+ SYSC_QUIRK("sdio", 0, 0, 0x10, -1, 0x40202301, 0xffff0ff0, 0),
+ SYSC_QUIRK("sdio", 0, 0x2fc, 0x110, 0x114, 0x31010000, 0xffffffff, 0),
+ SYSC_QUIRK("sdma", 0, 0, 0x2c, 0x28, 0x00010900, 0xffffffff, 0),
SYSC_QUIRK("slimbus", 0, 0, 0x10, -1, 0x40000902, 0xffffffff, 0),
SYSC_QUIRK("slimbus", 0, 0, 0x10, -1, 0x40002903, 0xffffffff, 0),
SYSC_QUIRK("spinlock", 0, 0, 0x10, -1, 0x50020000, 0xffffffff, 0),
+ SYSC_QUIRK("rng", 0, 0x1fe0, 0x1fe4, -1, 0x00000020, 0xffffffff, 0),
+ SYSC_QUIRK("rtc", 0, 0x74, 0x78, -1, 0x4eb01908, 0xffff00f0, 0),
+ SYSC_QUIRK("timer32k", 0, 0, 0x4, -1, 0x00000060, 0xffffffff, 0),
SYSC_QUIRK("usbhstll", 0, 0, 0x10, 0x14, 0x00000004, 0xffffffff, 0),
SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, 0x14, 0x50700100, 0xffffffff, 0),
SYSC_QUIRK("usb_otg_hs", 0, 0x400, 0x404, 0x408, 0x00000050,
0xffffffff, 0),
+ SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0500, 0xfffff0f0, 0),
+ SYSC_QUIRK("vfpe", 0, 0, 0x104, -1, 0x4d001200, 0xffffffff, 0),
#endif
};
@@ -1221,8 +1146,8 @@ static int sysc_child_suspend_noirq(struct device *dev)
if (!pm_runtime_status_suspended(dev)) {
error = pm_generic_runtime_suspend(dev);
if (error) {
- dev_warn(dev, "%s busy at %i: %i\n",
- __func__, __LINE__, error);
+ dev_dbg(dev, "%s busy at %i: %i\n",
+ __func__, __LINE__, error);
return 0;
}
diff --git a/drivers/bus/ts-nbus.c b/drivers/bus/ts-nbus.c
index 073fd9011154..9989ce904a37 100644
--- a/drivers/bus/ts-nbus.c
+++ b/drivers/bus/ts-nbus.c
@@ -110,13 +110,12 @@ static void ts_nbus_set_direction(struct ts_nbus *ts_nbus, int direction)
*/
static void ts_nbus_reset_bus(struct ts_nbus *ts_nbus)
{
- int i;
- int values[8];
+ DECLARE_BITMAP(values, 8);
- for (i = 0; i < 8; i++)
- values[i] = 0;
+ values[0] = 0;
- gpiod_set_array_value_cansleep(8, ts_nbus->data->desc, values);
+ gpiod_set_array_value_cansleep(8, ts_nbus->data->desc,
+ ts_nbus->data->info, values);
gpiod_set_value_cansleep(ts_nbus->csn, 0);
gpiod_set_value_cansleep(ts_nbus->strobe, 0);
gpiod_set_value_cansleep(ts_nbus->ale, 0);
@@ -157,16 +156,11 @@ static int ts_nbus_read_byte(struct ts_nbus *ts_nbus, u8 *val)
static void ts_nbus_write_byte(struct ts_nbus *ts_nbus, u8 byte)
{
struct gpio_descs *gpios = ts_nbus->data;
- int i;
- int values[8];
+ DECLARE_BITMAP(values, 8);
- for (i = 0; i < 8; i++)
- if (byte & BIT(i))
- values[i] = 1;
- else
- values[i] = 0;
+ values[0] = byte;
- gpiod_set_array_value_cansleep(8, gpios->desc, values);
+ gpiod_set_array_value_cansleep(8, gpios->desc, gpios->info, values);
}
/*
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index a5d5a96479bf..614ecdbb4ab7 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -410,10 +410,10 @@ static int cdrom_get_disc_info(struct cdrom_device_info *cdi,
* hack to have the capability flags defined const, while we can still
* change it here without gcc complaining at every line.
*/
-#define ENSURE(call, bits) \
-do { \
- if (cdo->call == NULL) \
- *change_capability &= ~(bits); \
+#define ENSURE(cdo, call, bits) \
+do { \
+ if (cdo->call == NULL) \
+ WARN_ON_ONCE((cdo)->capability & (bits)); \
} while (0)
/*
@@ -589,7 +589,6 @@ int register_cdrom(struct cdrom_device_info *cdi)
{
static char banner_printed;
const struct cdrom_device_ops *cdo = cdi->ops;
- int *change_capability = (int *)&cdo->capability; /* hack */
cd_dbg(CD_OPEN, "entering register_cdrom\n");
@@ -601,16 +600,16 @@ int register_cdrom(struct cdrom_device_info *cdi)
cdrom_sysctl_register();
}
- ENSURE(drive_status, CDC_DRIVE_STATUS);
+ ENSURE(cdo, drive_status, CDC_DRIVE_STATUS);
if (cdo->check_events == NULL && cdo->media_changed == NULL)
- *change_capability = ~(CDC_MEDIA_CHANGED | CDC_SELECT_DISC);
- ENSURE(tray_move, CDC_CLOSE_TRAY | CDC_OPEN_TRAY);
- ENSURE(lock_door, CDC_LOCK);
- ENSURE(select_speed, CDC_SELECT_SPEED);
- ENSURE(get_last_session, CDC_MULTI_SESSION);
- ENSURE(get_mcn, CDC_MCN);
- ENSURE(reset, CDC_RESET);
- ENSURE(generic_packet, CDC_GENERIC_PACKET);
+ WARN_ON_ONCE(cdo->capability & (CDC_MEDIA_CHANGED | CDC_SELECT_DISC));
+ ENSURE(cdo, tray_move, CDC_CLOSE_TRAY | CDC_OPEN_TRAY);
+ ENSURE(cdo, lock_door, CDC_LOCK);
+ ENSURE(cdo, select_speed, CDC_SELECT_SPEED);
+ ENSURE(cdo, get_last_session, CDC_MULTI_SESSION);
+ ENSURE(cdo, get_mcn, CDC_MCN);
+ ENSURE(cdo, reset, CDC_RESET);
+ ENSURE(cdo, generic_packet, CDC_GENERIC_PACKET);
cdi->mc_flags = 0;
cdi->options = CDO_USE_FFLAGS;
@@ -2445,7 +2444,7 @@ static int cdrom_ioctl_select_disc(struct cdrom_device_info *cdi,
return -ENOSYS;
if (arg != CDSL_CURRENT && arg != CDSL_NONE) {
- if ((int)arg >= cdi->capacity)
+ if (arg >= cdi->capacity)
return -EINVAL;
}
diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c
index ae3a7537cf0f..a5b8afe3609c 100644
--- a/drivers/cdrom/gdrom.c
+++ b/drivers/cdrom/gdrom.c
@@ -31,12 +31,11 @@
#include <linux/cdrom.h>
#include <linux/genhd.h>
#include <linux/bio.h>
-#include <linux/blkdev.h>
+#include <linux/blk-mq.h>
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/mutex.h>
#include <linux/wait.h>
-#include <linux/workqueue.h>
#include <linux/platform_device.h>
#include <scsi/scsi.h>
#include <asm/io.h>
@@ -102,11 +101,6 @@ static int gdrom_major;
static DECLARE_WAIT_QUEUE_HEAD(command_queue);
static DECLARE_WAIT_QUEUE_HEAD(request_queue);
-static DEFINE_SPINLOCK(gdrom_lock);
-static void gdrom_readdisk_dma(struct work_struct *work);
-static DECLARE_WORK(work, gdrom_readdisk_dma);
-static LIST_HEAD(gdrom_deferred);
-
struct gdromtoc {
unsigned int entry[99];
unsigned int first, last;
@@ -122,6 +116,7 @@ static struct gdrom_unit {
char disk_type;
struct gdromtoc *toc;
struct request_queue *gdrom_rq;
+ struct blk_mq_tag_set tag_set;
} gd;
struct gdrom_id {
@@ -332,15 +327,15 @@ static int get_entry_track(int track)
static int gdrom_get_last_session(struct cdrom_device_info *cd_info,
struct cdrom_multisession *ms_info)
{
- int fentry, lentry, track, data, tocuse, err;
+ int fentry, lentry, track, data, err;
+
if (!gd.toc)
return -ENOMEM;
- tocuse = 1;
+
/* Check if GD-ROM */
err = gdrom_readtoc_cmd(gd.toc, 1);
/* Not a GD-ROM so check if standard CD-ROM */
if (err) {
- tocuse = 0;
err = gdrom_readtoc_cmd(gd.toc, 0);
if (err) {
pr_info("Could not get CD table of contents\n");
@@ -584,103 +579,83 @@ static int gdrom_set_interrupt_handlers(void)
* 9 -> sectors >> 8
* 10 -> sectors
*/
-static void gdrom_readdisk_dma(struct work_struct *work)
+static blk_status_t gdrom_readdisk_dma(struct request *req)
{
int block, block_cnt;
blk_status_t err;
struct packet_command *read_command;
- struct list_head *elem, *next;
- struct request *req;
unsigned long timeout;
- if (list_empty(&gdrom_deferred))
- return;
read_command = kzalloc(sizeof(struct packet_command), GFP_KERNEL);
if (!read_command)
- return; /* get more memory later? */
+ return BLK_STS_RESOURCE;
+
read_command->cmd[0] = 0x30;
read_command->cmd[1] = 0x20;
- spin_lock(&gdrom_lock);
- list_for_each_safe(elem, next, &gdrom_deferred) {
- req = list_entry(elem, struct request, queuelist);
- spin_unlock(&gdrom_lock);
- block = blk_rq_pos(req)/GD_TO_BLK + GD_SESSION_OFFSET;
- block_cnt = blk_rq_sectors(req)/GD_TO_BLK;
- __raw_writel(virt_to_phys(bio_data(req->bio)), GDROM_DMA_STARTADDR_REG);
- __raw_writel(block_cnt * GDROM_HARD_SECTOR, GDROM_DMA_LENGTH_REG);
- __raw_writel(1, GDROM_DMA_DIRECTION_REG);
- __raw_writel(1, GDROM_DMA_ENABLE_REG);
- read_command->cmd[2] = (block >> 16) & 0xFF;
- read_command->cmd[3] = (block >> 8) & 0xFF;
- read_command->cmd[4] = block & 0xFF;
- read_command->cmd[8] = (block_cnt >> 16) & 0xFF;
- read_command->cmd[9] = (block_cnt >> 8) & 0xFF;
- read_command->cmd[10] = block_cnt & 0xFF;
- /* set for DMA */
- __raw_writeb(1, GDROM_ERROR_REG);
- /* other registers */
- __raw_writeb(0, GDROM_SECNUM_REG);
- __raw_writeb(0, GDROM_BCL_REG);
- __raw_writeb(0, GDROM_BCH_REG);
- __raw_writeb(0, GDROM_DSEL_REG);
- __raw_writeb(0, GDROM_INTSEC_REG);
- /* Wait for registers to reset after any previous activity */
- timeout = jiffies + HZ / 2;
- while (gdrom_is_busy() && time_before(jiffies, timeout))
- cpu_relax();
- __raw_writeb(GDROM_COM_PACKET, GDROM_STATUSCOMMAND_REG);
- timeout = jiffies + HZ / 2;
- /* Wait for packet command to finish */
- while (gdrom_is_busy() && time_before(jiffies, timeout))
- cpu_relax();
- gd.pending = 1;
- gd.transfer = 1;
- outsw(GDROM_DATA_REG, &read_command->cmd, 6);
- timeout = jiffies + HZ / 2;
- /* Wait for any pending DMA to finish */
- while (__raw_readb(GDROM_DMA_STATUS_REG) &&
- time_before(jiffies, timeout))
- cpu_relax();
- /* start transfer */
- __raw_writeb(1, GDROM_DMA_STATUS_REG);
- wait_event_interruptible_timeout(request_queue,
- gd.transfer == 0, GDROM_DEFAULT_TIMEOUT);
- err = gd.transfer ? BLK_STS_IOERR : BLK_STS_OK;
- gd.transfer = 0;
- gd.pending = 0;
- /* now seek to take the request spinlock
- * before handling ending the request */
- spin_lock(&gdrom_lock);
- list_del_init(&req->queuelist);
- __blk_end_request_all(req, err);
- }
- spin_unlock(&gdrom_lock);
+ block = blk_rq_pos(req)/GD_TO_BLK + GD_SESSION_OFFSET;
+ block_cnt = blk_rq_sectors(req)/GD_TO_BLK;
+ __raw_writel(virt_to_phys(bio_data(req->bio)), GDROM_DMA_STARTADDR_REG);
+ __raw_writel(block_cnt * GDROM_HARD_SECTOR, GDROM_DMA_LENGTH_REG);
+ __raw_writel(1, GDROM_DMA_DIRECTION_REG);
+ __raw_writel(1, GDROM_DMA_ENABLE_REG);
+ read_command->cmd[2] = (block >> 16) & 0xFF;
+ read_command->cmd[3] = (block >> 8) & 0xFF;
+ read_command->cmd[4] = block & 0xFF;
+ read_command->cmd[8] = (block_cnt >> 16) & 0xFF;
+ read_command->cmd[9] = (block_cnt >> 8) & 0xFF;
+ read_command->cmd[10] = block_cnt & 0xFF;
+ /* set for DMA */
+ __raw_writeb(1, GDROM_ERROR_REG);
+ /* other registers */
+ __raw_writeb(0, GDROM_SECNUM_REG);
+ __raw_writeb(0, GDROM_BCL_REG);
+ __raw_writeb(0, GDROM_BCH_REG);
+ __raw_writeb(0, GDROM_DSEL_REG);
+ __raw_writeb(0, GDROM_INTSEC_REG);
+ /* Wait for registers to reset after any previous activity */
+ timeout = jiffies + HZ / 2;
+ while (gdrom_is_busy() && time_before(jiffies, timeout))
+ cpu_relax();
+ __raw_writeb(GDROM_COM_PACKET, GDROM_STATUSCOMMAND_REG);
+ timeout = jiffies + HZ / 2;
+ /* Wait for packet command to finish */
+ while (gdrom_is_busy() && time_before(jiffies, timeout))
+ cpu_relax();
+ gd.pending = 1;
+ gd.transfer = 1;
+ outsw(GDROM_DATA_REG, &read_command->cmd, 6);
+ timeout = jiffies + HZ / 2;
+ /* Wait for any pending DMA to finish */
+ while (__raw_readb(GDROM_DMA_STATUS_REG) &&
+ time_before(jiffies, timeout))
+ cpu_relax();
+ /* start transfer */
+ __raw_writeb(1, GDROM_DMA_STATUS_REG);
+ wait_event_interruptible_timeout(request_queue,
+ gd.transfer == 0, GDROM_DEFAULT_TIMEOUT);
+ err = gd.transfer ? BLK_STS_IOERR : BLK_STS_OK;
+ gd.transfer = 0;
+ gd.pending = 0;
+
+ blk_mq_end_request(req, err);
kfree(read_command);
+ return BLK_STS_OK;
}
-static void gdrom_request(struct request_queue *rq)
-{
- struct request *req;
-
- while ((req = blk_fetch_request(rq)) != NULL) {
- switch (req_op(req)) {
- case REQ_OP_READ:
- /*
- * Add to list of deferred work and then schedule
- * workqueue.
- */
- list_add_tail(&req->queuelist, &gdrom_deferred);
- schedule_work(&work);
- break;
- case REQ_OP_WRITE:
- pr_notice("Read only device - write request ignored\n");
- __blk_end_request_all(req, BLK_STS_IOERR);
- break;
- default:
- printk(KERN_DEBUG "gdrom: Non-fs request ignored\n");
- __blk_end_request_all(req, BLK_STS_IOERR);
- break;
- }
+static blk_status_t gdrom_queue_rq(struct blk_mq_hw_ctx *hctx,
+ const struct blk_mq_queue_data *bd)
+{
+ blk_mq_start_request(bd->rq);
+
+ switch (req_op(bd->rq)) {
+ case REQ_OP_READ:
+ return gdrom_readdisk_dma(bd->rq);
+ case REQ_OP_WRITE:
+ pr_notice("Read only device - write request ignored\n");
+ return BLK_STS_IOERR;
+ default:
+ printk(KERN_DEBUG "gdrom: Non-fs request ignored\n");
+ return BLK_STS_IOERR;
}
}
@@ -768,6 +743,10 @@ static int probe_gdrom_setupqueue(void)
return gdrom_init_dma_mode();
}
+static const struct blk_mq_ops gdrom_mq_ops = {
+ .queue_rq = gdrom_queue_rq,
+};
+
/*
* register this as a block device and as compliant with the
* universal CD Rom driver interface
@@ -811,11 +790,15 @@ static int probe_gdrom(struct platform_device *devptr)
err = gdrom_set_interrupt_handlers();
if (err)
goto probe_fail_cmdirq_register;
- gd.gdrom_rq = blk_init_queue(gdrom_request, &gdrom_lock);
- if (!gd.gdrom_rq) {
- err = -ENOMEM;
+
+ 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;
}
+
blk_queue_bounce_limit(gd.gdrom_rq, BLK_BOUNCE_HIGH);
err = probe_gdrom_setupqueue();
@@ -832,6 +815,7 @@ static int probe_gdrom(struct platform_device *devptr)
probe_fail_toc:
blk_cleanup_queue(gd.gdrom_rq);
+ blk_mq_free_tag_set(&gd.tag_set);
probe_fail_requestq:
free_irq(HW_EVENT_GDROM_DMA, &gd);
free_irq(HW_EVENT_GDROM_CMD, &gd);
@@ -849,8 +833,8 @@ probe_fail_no_mem:
static int remove_gdrom(struct platform_device *devptr)
{
- flush_work(&work);
blk_cleanup_queue(gd.gdrom_rq);
+ blk_mq_free_tag_set(&gd.tag_set);
free_irq(HW_EVENT_GDROM_CMD, &gd);
free_irq(HW_EVENT_GDROM_DMA, &gd);
del_gendisk(gd.disk);
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 40728491f37b..9d03b2ff5df6 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -268,7 +268,7 @@ if RTC_LIB=n
config RTC
tristate "Enhanced Real Time Clock Support (legacy PC RTC driver)"
- depends on ALPHA || (MIPS && MACH_LOONGSON64)
+ depends on ALPHA
---help---
If you say Y here and create a character special file /dev/rtc with
major number 10 and minor number 135 using mknod ("man mknod"), you
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
index aaf9e5afaad4..95be7228f327 100644
--- a/drivers/char/hw_random/core.c
+++ b/drivers/char/hw_random/core.c
@@ -44,10 +44,10 @@ static unsigned short default_quality; /* = 0; default to "off" */
module_param(current_quality, ushort, 0644);
MODULE_PARM_DESC(current_quality,
- "current hwrng entropy estimation per mill");
+ "current hwrng entropy estimation per 1024 bits of input");
module_param(default_quality, ushort, 0644);
MODULE_PARM_DESC(default_quality,
- "default entropy content of hwrng per mill");
+ "default entropy content of hwrng per 1024 bits of input");
static void drop_current_rng(void);
static int hwrng_init(struct hwrng *rng);
diff --git a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c
index 97d6856c9c0f..f3f216cdf686 100644
--- a/drivers/char/ipmi/ipmi_bt_sm.c
+++ b/drivers/char/ipmi/ipmi_bt_sm.c
@@ -8,6 +8,8 @@
* Author: Rocky Craig <first.last@hp.com>
*/
+#define DEBUG /* So dev_dbg() is always available. */
+
#include <linux/kernel.h> /* For printk. */
#include <linux/string.h>
#include <linux/module.h>
@@ -215,11 +217,11 @@ static int bt_start_transaction(struct si_sm_data *bt,
return IPMI_NOT_IN_MY_STATE_ERR;
if (bt_debug & BT_DEBUG_MSG) {
- printk(KERN_WARNING "BT: +++++++++++++++++ New command\n");
- printk(KERN_WARNING "BT: NetFn/LUN CMD [%d data]:", size - 2);
+ dev_dbg(bt->io->dev, "+++++++++++++++++ New command\n");
+ dev_dbg(bt->io->dev, "NetFn/LUN CMD [%d data]:", size - 2);
for (i = 0; i < size; i ++)
- printk(" %02x", data[i]);
- printk("\n");
+ pr_cont(" %02x", data[i]);
+ pr_cont("\n");
}
bt->write_data[0] = size + 1; /* all data plus seq byte */
bt->write_data[1] = *data; /* NetFn/LUN */
@@ -260,10 +262,10 @@ static int bt_get_result(struct si_sm_data *bt,
memcpy(data + 2, bt->read_data + 4, msg_len - 2);
if (bt_debug & BT_DEBUG_MSG) {
- printk(KERN_WARNING "BT: result %d bytes:", msg_len);
+ dev_dbg(bt->io->dev, "result %d bytes:", msg_len);
for (i = 0; i < msg_len; i++)
- printk(" %02x", data[i]);
- printk("\n");
+ pr_cont(" %02x", data[i]);
+ pr_cont("\n");
}
return msg_len;
}
@@ -274,8 +276,7 @@ static int bt_get_result(struct si_sm_data *bt,
static void reset_flags(struct si_sm_data *bt)
{
if (bt_debug)
- printk(KERN_WARNING "IPMI BT: flag reset %s\n",
- status2txt(BT_STATUS));
+ dev_dbg(bt->io->dev, "flag reset %s\n", status2txt(BT_STATUS));
if (BT_STATUS & BT_H_BUSY)
BT_CONTROL(BT_H_BUSY); /* force clear */
BT_CONTROL(BT_CLR_WR_PTR); /* always reset */
@@ -301,14 +302,14 @@ static void drain_BMC2HOST(struct si_sm_data *bt)
BT_CONTROL(BT_B2H_ATN); /* some BMCs are stubborn */
BT_CONTROL(BT_CLR_RD_PTR); /* always reset */
if (bt_debug)
- printk(KERN_WARNING "IPMI BT: stale response %s; ",
+ dev_dbg(bt->io->dev, "stale response %s; ",
status2txt(BT_STATUS));
size = BMC2HOST;
for (i = 0; i < size ; i++)
BMC2HOST;
BT_CONTROL(BT_H_BUSY); /* now clear */
if (bt_debug)
- printk("drained %d bytes\n", size + 1);
+ pr_cont("drained %d bytes\n", size + 1);
}
static inline void write_all_bytes(struct si_sm_data *bt)
@@ -316,11 +317,11 @@ static inline void write_all_bytes(struct si_sm_data *bt)
int i;
if (bt_debug & BT_DEBUG_MSG) {
- printk(KERN_WARNING "BT: write %d bytes seq=0x%02X",
+ dev_dbg(bt->io->dev, "write %d bytes seq=0x%02X",
bt->write_count, bt->seq);
for (i = 0; i < bt->write_count; i++)
- printk(" %02x", bt->write_data[i]);
- printk("\n");
+ pr_cont(" %02x", bt->write_data[i]);
+ pr_cont("\n");
}
for (i = 0; i < bt->write_count; i++)
HOST2BMC(bt->write_data[i]);
@@ -340,8 +341,8 @@ static inline int read_all_bytes(struct si_sm_data *bt)
if (bt->read_count < 4 || bt->read_count >= IPMI_MAX_MSG_LENGTH) {
if (bt_debug & BT_DEBUG_MSG)
- printk(KERN_WARNING "BT: bad raw rsp len=%d\n",
- bt->read_count);
+ dev_dbg(bt->io->dev,
+ "bad raw rsp len=%d\n", bt->read_count);
bt->truncated = 1;
return 1; /* let next XACTION START clean it up */
}
@@ -352,13 +353,13 @@ static inline int read_all_bytes(struct si_sm_data *bt)
if (bt_debug & BT_DEBUG_MSG) {
int max = bt->read_count;
- printk(KERN_WARNING "BT: got %d bytes seq=0x%02X",
- max, bt->read_data[2]);
+ dev_dbg(bt->io->dev,
+ "got %d bytes seq=0x%02X", max, bt->read_data[2]);
if (max > 16)
max = 16;
for (i = 0; i < max; i++)
- printk(KERN_CONT " %02x", bt->read_data[i]);
- printk(KERN_CONT "%s\n", bt->read_count == max ? "" : " ...");
+ pr_cont(" %02x", bt->read_data[i]);
+ pr_cont("%s\n", bt->read_count == max ? "" : " ...");
}
/* per the spec, the (NetFn[1], Seq[2], Cmd[3]) tuples must match */
@@ -368,10 +369,11 @@ static inline int read_all_bytes(struct si_sm_data *bt)
return 1;
if (bt_debug & BT_DEBUG_MSG)
- printk(KERN_WARNING "IPMI BT: bad packet: "
- "want 0x(%02X, %02X, %02X) got (%02X, %02X, %02X)\n",
- bt->write_data[1] | 0x04, bt->write_data[2], bt->write_data[3],
- bt->read_data[1], bt->read_data[2], bt->read_data[3]);
+ dev_dbg(bt->io->dev,
+ "IPMI BT: bad packet: want 0x(%02X, %02X, %02X) got (%02X, %02X, %02X)\n",
+ bt->write_data[1] | 0x04, bt->write_data[2],
+ bt->write_data[3],
+ bt->read_data[1], bt->read_data[2], bt->read_data[3]);
return 0;
}
@@ -394,8 +396,8 @@ static enum si_sm_result error_recovery(struct si_sm_data *bt,
break;
}
- printk(KERN_WARNING "IPMI BT: %s in %s %s ", /* open-ended line */
- reason, STATE2TXT, STATUS2TXT);
+ dev_warn(bt->io->dev, "IPMI BT: %s in %s %s ", /* open-ended line */
+ reason, STATE2TXT, STATUS2TXT);
/*
* Per the IPMI spec, retries are based on the sequence number
@@ -403,20 +405,20 @@ static enum si_sm_result error_recovery(struct si_sm_data *bt,
*/
(bt->error_retries)++;
if (bt->error_retries < bt->BT_CAP_retries) {
- printk("%d retries left\n",
+ pr_cont("%d retries left\n",
bt->BT_CAP_retries - bt->error_retries);
bt->state = BT_STATE_RESTART;
return SI_SM_CALL_WITHOUT_DELAY;
}
- printk(KERN_WARNING "failed %d retries, sending error response\n",
- bt->BT_CAP_retries);
+ dev_warn(bt->io->dev, "failed %d retries, sending error response\n",
+ bt->BT_CAP_retries);
if (!bt->nonzero_status)
- printk(KERN_ERR "IPMI BT: stuck, try power cycle\n");
+ dev_err(bt->io->dev, "stuck, try power cycle\n");
/* this is most likely during insmod */
else if (bt->seq <= (unsigned char)(bt->BT_CAP_retries & 0xFF)) {
- printk(KERN_WARNING "IPMI: BT reset (takes 5 secs)\n");
+ dev_warn(bt->io->dev, "BT reset (takes 5 secs)\n");
bt->state = BT_STATE_RESET1;
return SI_SM_CALL_WITHOUT_DELAY;
}
@@ -452,7 +454,7 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
status = BT_STATUS;
bt->nonzero_status |= status;
if ((bt_debug & BT_DEBUG_STATES) && (bt->state != last_printed)) {
- printk(KERN_WARNING "BT: %s %s TO=%ld - %ld \n",
+ dev_dbg(bt->io->dev, "BT: %s %s TO=%ld - %ld\n",
STATE2TXT,
STATUS2TXT,
bt->timeout,
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c
index 1a486aec99b6..effab11887ca 100644
--- a/drivers/char/ipmi/ipmi_devintf.c
+++ b/drivers/char/ipmi/ipmi_devintf.c
@@ -818,8 +818,7 @@ static void ipmi_new_smi(int if_num, struct device *device)
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
if (!entry) {
- printk(KERN_ERR "ipmi_devintf: Unable to create the"
- " ipmi class device link\n");
+ pr_err("ipmi_devintf: Unable to create the ipmi class device link\n");
return;
}
entry->dev = dev;
@@ -861,18 +860,18 @@ static int __init init_ipmi_devintf(void)
if (ipmi_major < 0)
return -EINVAL;
- printk(KERN_INFO "ipmi device interface\n");
+ pr_info("ipmi device interface\n");
ipmi_class = class_create(THIS_MODULE, "ipmi");
if (IS_ERR(ipmi_class)) {
- printk(KERN_ERR "ipmi: can't register device class\n");
+ pr_err("ipmi: can't register device class\n");
return PTR_ERR(ipmi_class);
}
rv = register_chrdev(ipmi_major, DEVICE_NAME, &ipmi_fops);
if (rv < 0) {
class_destroy(ipmi_class);
- printk(KERN_ERR "ipmi: can't get major %d\n", ipmi_major);
+ pr_err("ipmi: can't get major %d\n", ipmi_major);
return rv;
}
@@ -884,7 +883,7 @@ static int __init init_ipmi_devintf(void)
if (rv) {
unregister_chrdev(ipmi_major, DEVICE_NAME);
class_destroy(ipmi_class);
- printk(KERN_WARNING "ipmi: can't register smi watcher\n");
+ pr_warn("ipmi: can't register smi watcher\n");
return rv;
}
diff --git a/drivers/char/ipmi/ipmi_dmi.c b/drivers/char/ipmi/ipmi_dmi.c
index e2c143861b1e..249880457b17 100644
--- a/drivers/char/ipmi/ipmi_dmi.c
+++ b/drivers/char/ipmi/ipmi_dmi.c
@@ -4,6 +4,9 @@
* allow autoloading of the IPMI drive based on SMBIOS entries.
*/
+#define pr_fmt(fmt) "%s" fmt, "ipmi:dmi: "
+#define dev_fmt pr_fmt
+
#include <linux/ipmi.h>
#include <linux/init.h>
#include <linux/dmi.h>
@@ -41,7 +44,7 @@ static void __init dmi_add_platform_ipmi(unsigned long base_addr,
unsigned int num_r = 1, size;
struct property_entry p[5];
unsigned int pidx = 0;
- char *name, *override;
+ char *name;
int rv;
enum si_type si_type;
struct ipmi_dmi_info *info;
@@ -49,11 +52,9 @@ static void __init dmi_add_platform_ipmi(unsigned long base_addr,
memset(p, 0, sizeof(p));
name = "dmi-ipmi-si";
- override = "ipmi_si";
switch (type) {
case IPMI_DMI_TYPE_SSIF:
name = "dmi-ipmi-ssif";
- override = "ipmi_ssif";
offset = 1;
size = 1;
si_type = SI_TYPE_INVALID;
@@ -71,7 +72,7 @@ static void __init dmi_add_platform_ipmi(unsigned long base_addr,
si_type = SI_SMIC;
break;
default:
- pr_err("ipmi:dmi: Invalid IPMI type: %d\n", type);
+ pr_err("Invalid IPMI type: %d\n", type);
return;
}
@@ -83,7 +84,7 @@ static void __init dmi_add_platform_ipmi(unsigned long base_addr,
info = kmalloc(sizeof(*info), GFP_KERNEL);
if (!info) {
- pr_warn("ipmi:dmi: Could not allocate dmi info\n");
+ pr_warn("Could not allocate dmi info\n");
} else {
info->si_type = si_type;
info->flags = flags;
@@ -95,13 +96,9 @@ static void __init dmi_add_platform_ipmi(unsigned long base_addr,
pdev = platform_device_alloc(name, ipmi_dmi_nr);
if (!pdev) {
- pr_err("ipmi:dmi: Error allocation IPMI platform device\n");
+ pr_err("Error allocation IPMI platform device\n");
return;
}
- pdev->driver_override = kasprintf(GFP_KERNEL, "%s",
- override);
- if (!pdev->driver_override)
- goto err;
if (type == IPMI_DMI_TYPE_SSIF) {
p[pidx++] = PROPERTY_ENTRY_U16("i2c-addr", base_addr);
@@ -141,22 +138,20 @@ static void __init dmi_add_platform_ipmi(unsigned long base_addr,
rv = platform_device_add_resources(pdev, r, num_r);
if (rv) {
- dev_err(&pdev->dev,
- "ipmi:dmi: Unable to add resources: %d\n", rv);
+ dev_err(&pdev->dev, "Unable to add resources: %d\n", rv);
goto err;
}
add_properties:
rv = platform_device_add_properties(pdev, p);
if (rv) {
- dev_err(&pdev->dev,
- "ipmi:dmi: Unable to add properties: %d\n", rv);
+ dev_err(&pdev->dev, "Unable to add properties: %d\n", rv);
goto err;
}
rv = platform_device_add(pdev);
if (rv) {
- dev_err(&pdev->dev, "ipmi:dmi: Unable to add device: %d\n", rv);
+ dev_err(&pdev->dev, "Unable to add device: %d\n", rv);
goto err;
}
@@ -217,6 +212,10 @@ static void __init dmi_decode_ipmi(const struct dmi_header *dm)
slave_addr = data[DMI_IPMI_SLAVEADDR];
memcpy(&base_addr, data + DMI_IPMI_ADDR, sizeof(unsigned long));
+ if (!base_addr) {
+ pr_err("Base address is zero, assuming no IPMI interface\n");
+ return;
+ }
if (len >= DMI_IPMI_VER2_LENGTH) {
if (type == IPMI_DMI_TYPE_SSIF) {
offset = 0;
@@ -263,7 +262,7 @@ static void __init dmi_decode_ipmi(const struct dmi_header *dm)
offset = 16;
break;
default:
- pr_err("ipmi:dmi: Invalid offset: 0\n");
+ pr_err("Invalid offset: 0\n");
return;
}
}
diff --git a/drivers/char/ipmi/ipmi_kcs_sm.c b/drivers/char/ipmi/ipmi_kcs_sm.c
index f4ea9f47230a..2e7cda08b079 100644
--- a/drivers/char/ipmi/ipmi_kcs_sm.c
+++ b/drivers/char/ipmi/ipmi_kcs_sm.c
@@ -274,8 +274,8 @@ static int start_kcs_transaction(struct si_sm_data *kcs, unsigned char *data,
if (kcs_debug & KCS_DEBUG_MSG) {
printk(KERN_DEBUG "start_kcs_transaction -");
for (i = 0; i < size; i++)
- printk(" %02x", (unsigned char) (data [i]));
- printk("\n");
+ pr_cont(" %02x", data[i]);
+ pr_cont("\n");
}
kcs->error_retries = 0;
memcpy(kcs->write_data, data, size);
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 7fc9612070a1..a74ce885b541 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -11,6 +11,9 @@
* Copyright 2002 MontaVista Software Inc.
*/
+#define pr_fmt(fmt) "%s" fmt, "IPMI message handler: "
+#define dev_fmt pr_fmt
+
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/poll.h>
@@ -30,8 +33,6 @@
#include <linux/workqueue.h>
#include <linux/uuid.h>
-#define PFX "IPMI message handler: "
-
#define IPMI_DRIVER_VERSION "39.2"
static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
@@ -1343,7 +1344,7 @@ int ipmi_set_my_LUN(struct ipmi_user *user,
user->intf->addrinfo[channel].lun = LUN & 0x3;
release_ipmi_user(user, index);
- return 0;
+ return rv;
}
EXPORT_SYMBOL(ipmi_set_my_LUN);
@@ -1474,8 +1475,7 @@ int ipmi_set_gets_events(struct ipmi_user *user, bool val)
list_move_tail(&msg->link, &msgs);
intf->waiting_events_count = 0;
if (intf->event_msg_printed) {
- dev_warn(intf->si_dev,
- PFX "Event queue no longer full\n");
+ dev_warn(intf->si_dev, "Event queue no longer full\n");
intf->event_msg_printed = 0;
}
@@ -2276,16 +2276,15 @@ static void bmc_device_id_handler(struct ipmi_smi *intf,
|| (msg->msg.netfn != IPMI_NETFN_APP_RESPONSE)
|| (msg->msg.cmd != IPMI_GET_DEVICE_ID_CMD)) {
dev_warn(intf->si_dev,
- PFX "invalid device_id msg: addr_type=%d netfn=%x cmd=%x\n",
- msg->addr.addr_type, msg->msg.netfn, msg->msg.cmd);
+ "invalid device_id msg: addr_type=%d netfn=%x cmd=%x\n",
+ msg->addr.addr_type, msg->msg.netfn, msg->msg.cmd);
return;
}
rv = ipmi_demangle_device_id(msg->msg.netfn, msg->msg.cmd,
msg->msg.data, msg->msg.data_len, &intf->bmc->fetch_id);
if (rv) {
- dev_warn(intf->si_dev,
- PFX "device id demangle failed: %d\n", rv);
+ dev_warn(intf->si_dev, "device id demangle failed: %d\n", rv);
intf->bmc->dyn_id_set = 0;
} else {
/*
@@ -2908,8 +2907,7 @@ static int __ipmi_bmc_register(struct ipmi_smi *intf,
mutex_unlock(&bmc->dyn_mutex);
dev_info(intf->si_dev,
- "ipmi: interfacing existing BMC (man_id: 0x%6.6x,"
- " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
+ "interfacing existing BMC (man_id: 0x%6.6x, prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
bmc->id.manufacturer_id,
bmc->id.product_id,
bmc->id.device_id);
@@ -2948,7 +2946,7 @@ static int __ipmi_bmc_register(struct ipmi_smi *intf,
rv = platform_device_register(&bmc->pdev);
if (rv) {
dev_err(intf->si_dev,
- PFX " Unable to register bmc device: %d\n",
+ "Unable to register bmc device: %d\n",
rv);
goto out_list_del;
}
@@ -2966,8 +2964,7 @@ static int __ipmi_bmc_register(struct ipmi_smi *intf,
*/
rv = sysfs_create_link(&intf->si_dev->kobj, &bmc->pdev.dev.kobj, "bmc");
if (rv) {
- dev_err(intf->si_dev,
- PFX "Unable to create bmc symlink: %d\n", rv);
+ dev_err(intf->si_dev, "Unable to create bmc symlink: %d\n", rv);
goto out_put_bmc;
}
@@ -2976,8 +2973,8 @@ static int __ipmi_bmc_register(struct ipmi_smi *intf,
intf->my_dev_name = kasprintf(GFP_KERNEL, "ipmi%d", intf_num);
if (!intf->my_dev_name) {
rv = -ENOMEM;
- dev_err(intf->si_dev,
- PFX "Unable to allocate link from BMC: %d\n", rv);
+ dev_err(intf->si_dev, "Unable to allocate link from BMC: %d\n",
+ rv);
goto out_unlink1;
}
@@ -2986,8 +2983,8 @@ static int __ipmi_bmc_register(struct ipmi_smi *intf,
if (rv) {
kfree(intf->my_dev_name);
intf->my_dev_name = NULL;
- dev_err(intf->si_dev,
- PFX "Unable to create symlink to bmc: %d\n", rv);
+ dev_err(intf->si_dev, "Unable to create symlink to bmc: %d\n",
+ rv);
goto out_free_my_dev_name;
}
@@ -3071,7 +3068,7 @@ static void guid_handler(struct ipmi_smi *intf, struct ipmi_recv_msg *msg)
if (msg->msg.data_len < 17) {
bmc->dyn_guid_set = 0;
dev_warn(intf->si_dev,
- PFX "The GUID response from the BMC was too short, it was %d but should have been 17. Assuming GUID is not available.\n",
+ "The GUID response from the BMC was too short, it was %d but should have been 17. Assuming GUID is not available.\n",
msg->msg.data_len);
goto out;
}
@@ -3195,7 +3192,7 @@ channel_handler(struct ipmi_smi *intf, struct ipmi_recv_msg *msg)
if (rv) {
/* Got an error somehow, just give up. */
dev_warn(intf->si_dev,
- PFX "Error sending channel information for channel %d: %d\n",
+ "Error sending channel information for channel %d: %d\n",
intf->curr_channel, rv);
intf->channel_list = intf->wchannels + set;
@@ -4075,7 +4072,7 @@ static int handle_read_event_rsp(struct ipmi_smi *intf,
* message.
*/
dev_warn(intf->si_dev,
- PFX "Event queue full, discarding incoming events\n");
+ "Event queue full, discarding incoming events\n");
intf->event_msg_printed = 1;
}
@@ -4094,7 +4091,7 @@ static int handle_bmc_rsp(struct ipmi_smi *intf,
recv_msg = (struct ipmi_recv_msg *) msg->user_data;
if (recv_msg == NULL) {
dev_warn(intf->si_dev,
- "IPMI message received with no owner. This could be because of a malformed message, or because of a hardware error. Contact your hardware vender for assistance\n");
+ "IPMI message received with no owner. This could be because of a malformed message, or because of a hardware error. Contact your hardware vendor for assistance.\n");
return 0;
}
@@ -4130,7 +4127,7 @@ static int handle_one_recv_msg(struct ipmi_smi *intf,
if (msg->rsp_size < 2) {
/* Message is too small to be correct. */
dev_warn(intf->si_dev,
- PFX "BMC returned to small a message for netfn %x cmd %x, got %d bytes\n",
+ "BMC returned too small a message for netfn %x cmd %x, got %d bytes\n",
(msg->data[0] >> 2) | 1, msg->data[1], msg->rsp_size);
/* Generate an error response for the message. */
@@ -4145,7 +4142,7 @@ static int handle_one_recv_msg(struct ipmi_smi *intf,
* marginally correct.
*/
dev_warn(intf->si_dev,
- PFX "BMC returned incorrect response, expected netfn %x cmd %x, got netfn %x cmd %x\n",
+ "BMC returned incorrect response, expected netfn %x cmd %x, got netfn %x cmd %x\n",
(msg->data[0] >> 2) | 1, msg->data[1],
msg->rsp[0] >> 2, msg->rsp[1]);
@@ -5035,11 +5032,11 @@ static int ipmi_init_msghandler(void)
rv = driver_register(&ipmidriver.driver);
if (rv) {
- pr_err(PFX "Could not register IPMI driver\n");
+ pr_err("Could not register IPMI driver\n");
return rv;
}
- pr_info("ipmi message handler version " IPMI_DRIVER_VERSION "\n");
+ pr_info("version " IPMI_DRIVER_VERSION "\n");
timer_setup(&ipmi_timer, ipmi_timeout, 0);
mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
@@ -5086,10 +5083,10 @@ static void __exit cleanup_ipmi(void)
/* Check for buffer leaks. */
count = atomic_read(&smi_msg_inuse_count);
if (count != 0)
- pr_warn(PFX "SMI message count %d at exit\n", count);
+ pr_warn("SMI message count %d at exit\n", count);
count = atomic_read(&recv_msg_inuse_count);
if (count != 0)
- pr_warn(PFX "recv message count %d at exit\n", count);
+ pr_warn("recv message count %d at exit\n", count);
}
module_exit(cleanup_ipmi);
diff --git a/drivers/char/ipmi/ipmi_powernv.c b/drivers/char/ipmi/ipmi_powernv.c
index e96500372ce2..da22a8cbe68e 100644
--- a/drivers/char/ipmi/ipmi_powernv.c
+++ b/drivers/char/ipmi/ipmi_powernv.c
@@ -19,7 +19,7 @@
struct ipmi_smi_powernv {
u64 interface_id;
- ipmi_smi_t intf;
+ struct ipmi_smi *intf;
unsigned int irq;
/**
@@ -33,7 +33,7 @@ struct ipmi_smi_powernv {
struct opal_ipmi_msg *opal_msg;
};
-static int ipmi_powernv_start_processing(void *send_info, ipmi_smi_t intf)
+static int ipmi_powernv_start_processing(void *send_info, struct ipmi_smi *intf)
{
struct ipmi_smi_powernv *smi = send_info;
diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c
index f6e19410dc57..bc3a18daf97a 100644
--- a/drivers/char/ipmi/ipmi_poweroff.c
+++ b/drivers/char/ipmi/ipmi_poweroff.c
@@ -11,6 +11,9 @@
*
* Copyright 2002,2004 MontaVista Software Inc.
*/
+
+#define pr_fmt(fmt) "IPMI poweroff: " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/proc_fs.h>
@@ -21,8 +24,6 @@
#include <linux/ipmi.h>
#include <linux/ipmi_smi.h>
-#define PFX "IPMI poweroff: "
-
static void ipmi_po_smi_gone(int if_num);
static void ipmi_po_new_smi(int if_num, struct device *device);
@@ -192,7 +193,7 @@ static void pps_poweroff_atca(struct ipmi_user *user)
smi_addr.channel = IPMI_BMC_CHANNEL;
smi_addr.lun = 0;
- printk(KERN_INFO PFX "PPS powerdown hook used");
+ pr_info("PPS powerdown hook used\n");
send_msg.netfn = IPMI_NETFN_OEM;
send_msg.cmd = IPMI_ATCA_PPS_GRACEFUL_RESTART;
@@ -201,10 +202,9 @@ static void pps_poweroff_atca(struct ipmi_user *user)
rv = ipmi_request_in_rc_mode(user,
(struct ipmi_addr *) &smi_addr,
&send_msg);
- if (rv && rv != IPMI_UNKNOWN_ERR_COMPLETION_CODE) {
- printk(KERN_ERR PFX "Unable to send ATCA ,"
- " IPMI error 0x%x\n", rv);
- }
+ if (rv && rv != IPMI_UNKNOWN_ERR_COMPLETION_CODE)
+ pr_err("Unable to send ATCA, IPMI error 0x%x\n", rv);
+
return;
}
@@ -234,12 +234,10 @@ static int ipmi_atca_detect(struct ipmi_user *user)
(struct ipmi_addr *) &smi_addr,
&send_msg);
- printk(KERN_INFO PFX "ATCA Detect mfg 0x%X prod 0x%X\n",
- mfg_id, prod_id);
+ pr_info("ATCA Detect mfg 0x%X prod 0x%X\n", mfg_id, prod_id);
if ((mfg_id == IPMI_MOTOROLA_MANUFACTURER_ID)
&& (prod_id == IPMI_MOTOROLA_PPS_IPMC_PRODUCT_ID)) {
- printk(KERN_INFO PFX
- "Installing Pigeon Point Systems Poweroff Hook\n");
+ pr_info("Installing Pigeon Point Systems Poweroff Hook\n");
atca_oem_poweroff_hook = pps_poweroff_atca;
}
return !rv;
@@ -259,7 +257,7 @@ static void ipmi_poweroff_atca(struct ipmi_user *user)
smi_addr.channel = IPMI_BMC_CHANNEL;
smi_addr.lun = 0;
- printk(KERN_INFO PFX "Powering down via ATCA power command\n");
+ pr_info("Powering down via ATCA power command\n");
/*
* Power down
@@ -282,8 +280,8 @@ static void ipmi_poweroff_atca(struct ipmi_user *user)
* return code
*/
if (rv && rv != IPMI_UNKNOWN_ERR_COMPLETION_CODE) {
- printk(KERN_ERR PFX "Unable to send ATCA powerdown message,"
- " IPMI error 0x%x\n", rv);
+ pr_err("Unable to send ATCA powerdown message, IPMI error 0x%x\n",
+ rv);
goto out;
}
@@ -334,7 +332,7 @@ static void ipmi_poweroff_cpi1(struct ipmi_user *user)
smi_addr.channel = IPMI_BMC_CHANNEL;
smi_addr.lun = 0;
- printk(KERN_INFO PFX "Powering down via CPI1 power command\n");
+ pr_info("Powering down via CPI1 power command\n");
/*
* Get IPMI ipmb address
@@ -482,7 +480,7 @@ static void ipmi_poweroff_chassis(struct ipmi_user *user)
smi_addr.lun = 0;
powercyclefailed:
- printk(KERN_INFO PFX "Powering %s via IPMI chassis control command\n",
+ pr_info("Powering %s via IPMI chassis control command\n",
(poweroff_powercycle ? "cycle" : "down"));
/*
@@ -502,14 +500,14 @@ static void ipmi_poweroff_chassis(struct ipmi_user *user)
if (rv) {
if (poweroff_powercycle) {
/* power cycle failed, default to power down */
- printk(KERN_ERR PFX "Unable to send chassis power " \
- "cycle message, IPMI error 0x%x\n", rv);
+ pr_err("Unable to send chassis power cycle message, IPMI error 0x%x\n",
+ rv);
poweroff_powercycle = 0;
goto powercyclefailed;
}
- printk(KERN_ERR PFX "Unable to send chassis power " \
- "down message, IPMI error 0x%x\n", rv);
+ pr_err("Unable to send chassis power down message, IPMI error 0x%x\n",
+ rv);
}
}
@@ -571,8 +569,7 @@ static void ipmi_po_new_smi(int if_num, struct device *device)
rv = ipmi_create_user(if_num, &ipmi_poweroff_handler, NULL,
&ipmi_user);
if (rv) {
- printk(KERN_ERR PFX "could not create IPMI user, error %d\n",
- rv);
+ pr_err("could not create IPMI user, error %d\n", rv);
return;
}
@@ -594,14 +591,13 @@ static void ipmi_po_new_smi(int if_num, struct device *device)
(struct ipmi_addr *) &smi_addr,
&send_msg);
if (rv) {
- printk(KERN_ERR PFX "Unable to send IPMI get device id info,"
- " IPMI error 0x%x\n", rv);
+ pr_err("Unable to send IPMI get device id info, IPMI error 0x%x\n",
+ rv);
goto out_err;
}
if (halt_recv_msg.msg.data_len < 12) {
- printk(KERN_ERR PFX "(chassis) IPMI get device id info too,"
- " short, was %d bytes, needed %d bytes\n",
+ pr_err("(chassis) IPMI get device id info too short, was %d bytes, needed %d bytes\n",
halt_recv_msg.msg.data_len, 12);
goto out_err;
}
@@ -622,14 +618,13 @@ static void ipmi_po_new_smi(int if_num, struct device *device)
}
out_err:
- printk(KERN_ERR PFX "Unable to find a poweroff function that"
- " will work, giving up\n");
+ pr_err("Unable to find a poweroff function that will work, giving up\n");
ipmi_destroy_user(ipmi_user);
return;
found:
- printk(KERN_INFO PFX "Found a %s style poweroff function\n",
- poweroff_functions[i].platform_type);
+ pr_info("Found a %s style poweroff function\n",
+ poweroff_functions[i].platform_type);
specific_poweroff_func = poweroff_functions[i].poweroff_func;
old_poweroff_func = pm_power_off;
pm_power_off = ipmi_poweroff_function;
@@ -692,16 +687,15 @@ static int __init ipmi_poweroff_init(void)
{
int rv;
- printk(KERN_INFO "Copyright (C) 2004 MontaVista Software -"
- " IPMI Powerdown via sys_reboot.\n");
+ pr_info("Copyright (C) 2004 MontaVista Software - IPMI Powerdown via sys_reboot\n");
if (poweroff_powercycle)
- printk(KERN_INFO PFX "Power cycle is enabled.\n");
+ pr_info("Power cycle is enabled\n");
#ifdef CONFIG_PROC_FS
ipmi_table_header = register_sysctl_table(ipmi_root_table);
if (!ipmi_table_header) {
- printk(KERN_ERR PFX "Unable to register powercycle sysctl\n");
+ pr_err("Unable to register powercycle sysctl\n");
rv = -ENOMEM;
goto out_err;
}
@@ -712,7 +706,7 @@ static int __init ipmi_poweroff_init(void)
#ifdef CONFIG_PROC_FS
if (rv) {
unregister_sysctl_table(ipmi_table_header);
- printk(KERN_ERR PFX "Unable to register SMI watcher: %d\n", rv);
+ pr_err("Unable to register SMI watcher: %d\n", rv);
goto out_err;
}
@@ -735,8 +729,7 @@ static void __exit ipmi_poweroff_cleanup(void)
if (ready) {
rv = ipmi_destroy_user(ipmi_user);
if (rv)
- printk(KERN_ERR PFX "could not cleanup the IPMI"
- " user: 0x%x\n", rv);
+ pr_err("could not cleanup the IPMI user: 0x%x\n", rv);
pm_power_off = old_poweroff_func;
}
}
diff --git a/drivers/char/ipmi/ipmi_si_hardcode.c b/drivers/char/ipmi/ipmi_si_hardcode.c
index 10219f24546b..487642809c58 100644
--- a/drivers/char/ipmi/ipmi_si_hardcode.c
+++ b/drivers/char/ipmi/ipmi_si_hardcode.c
@@ -1,9 +1,10 @@
// SPDX-License-Identifier: GPL-2.0+
+#define pr_fmt(fmt) "ipmi_hardcode: " fmt
+
#include <linux/moduleparam.h>
#include "ipmi_si.h"
-#define PFX "ipmi_hardcode: "
/*
* There can be 4 IO ports passed in (with or without IRQs), 4 addresses,
* a default IO port, and 1 ACPI/SPMI address. That sets SI_MAX_DRIVERS.
@@ -100,7 +101,7 @@ int ipmi_si_hardcode_find_bmc(void)
continue;
io.addr_source = SI_HARDCODED;
- pr_info(PFX "probing via hardcoded address\n");
+ pr_info("probing via hardcoded address\n");
if (!si_type[i] || strcmp(si_type[i], "kcs") == 0) {
io.si_type = SI_KCS;
@@ -109,7 +110,7 @@ int ipmi_si_hardcode_find_bmc(void)
} else if (strcmp(si_type[i], "bt") == 0) {
io.si_type = SI_BT;
} else {
- pr_warn(PFX "Interface type specified for interface %d, was invalid: %s\n",
+ pr_warn("Interface type specified for interface %d, was invalid: %s\n",
i, si_type[i]);
continue;
}
@@ -123,7 +124,7 @@ int ipmi_si_hardcode_find_bmc(void)
io.addr_data = addrs[i];
io.addr_type = IPMI_MEM_ADDR_SPACE;
} else {
- pr_warn(PFX "Interface type specified for interface %d, but port and address were not set or set to zero.\n",
+ pr_warn("Interface type specified for interface %d, but port and address were not set or set to zero\n",
i);
continue;
}
diff --git a/drivers/char/ipmi/ipmi_si_hotmod.c b/drivers/char/ipmi/ipmi_si_hotmod.c
index a98ca42a50b1..c0067fd0480d 100644
--- a/drivers/char/ipmi/ipmi_si_hotmod.c
+++ b/drivers/char/ipmi/ipmi_si_hotmod.c
@@ -5,12 +5,13 @@
* Handling for dynamically adding/removing IPMI devices through
* a module parameter (and thus sysfs).
*/
+
+#define pr_fmt(fmt) "ipmi_hotmod: " fmt
+
#include <linux/moduleparam.h>
#include <linux/ipmi.h>
#include "ipmi_si.h"
-#define PFX "ipmi_hotmod: "
-
static int hotmod_handler(const char *val, const struct kernel_param *kp);
module_param_call(hotmod, hotmod_handler, NULL, NULL, 0200);
@@ -61,7 +62,7 @@ static int parse_str(const struct hotmod_vals *v, int *val, char *name,
s = strchr(*curr, ',');
if (!s) {
- pr_warn(PFX "No hotmod %s given.\n", name);
+ pr_warn("No hotmod %s given\n", name);
return -EINVAL;
}
*s = '\0';
@@ -74,7 +75,7 @@ static int parse_str(const struct hotmod_vals *v, int *val, char *name,
}
}
- pr_warn(PFX "Invalid hotmod %s '%s'\n", name, *curr);
+ pr_warn("Invalid hotmod %s '%s'\n", name, *curr);
return -EINVAL;
}
@@ -85,12 +86,12 @@ static int check_hotmod_int_op(const char *curr, const char *option,
if (strcmp(curr, name) == 0) {
if (!option) {
- pr_warn(PFX "No option given for '%s'\n", curr);
+ pr_warn("No option given for '%s'\n", curr);
return -EINVAL;
}
*val = simple_strtoul(option, &n, 0);
if ((*n != '\0') || (*option == '\0')) {
- pr_warn(PFX "Bad option given for '%s'\n", curr);
+ pr_warn("Bad option given for '%s'\n", curr);
return -EINVAL;
}
return 1;
@@ -160,7 +161,7 @@ static int hotmod_handler(const char *val, const struct kernel_param *kp)
}
addr = simple_strtoul(curr, &n, 0);
if ((*n != '\0') || (*curr == '\0')) {
- pr_warn(PFX "Invalid hotmod address '%s'\n", curr);
+ pr_warn("Invalid hotmod address '%s'\n", curr);
break;
}
@@ -203,7 +204,7 @@ static int hotmod_handler(const char *val, const struct kernel_param *kp)
continue;
rv = -EINVAL;
- pr_warn(PFX "Invalid hotmod option '%s'\n", curr);
+ pr_warn("Invalid hotmod option '%s'\n", curr);
goto out;
}
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 5faa917df1b6..677618e6f1f7 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -19,6 +19,8 @@
* and drives the real SMI state machine.
*/
+#define pr_fmt(fmt) "ipmi_si: " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/sched.h>
@@ -41,8 +43,6 @@
#include <linux/string.h>
#include <linux/ctype.h>
-#define PFX "ipmi_si: "
-
/* Measure times between events in the driver. */
#undef DEBUG_TIMING
@@ -269,7 +269,7 @@ void debug_timestamp(char *msg)
{
struct timespec64 t;
- getnstimeofday64(&t);
+ ktime_get_ts64(&t);
pr_debug("**%s: %lld.%9.9ld\n", msg, (long long) t.tv_sec, t.tv_nsec);
}
#else
@@ -961,12 +961,12 @@ static inline int ipmi_thread_busy_wait(enum si_sm_result smi_result,
if (max_busy_us == 0 || smi_result != SI_SM_CALL_WITH_DELAY)
ipmi_si_set_not_busy(busy_until);
else if (!ipmi_si_is_busy(busy_until)) {
- getnstimeofday64(busy_until);
+ ktime_get_ts64(busy_until);
timespec64_add_ns(busy_until, max_busy_us*NSEC_PER_USEC);
} else {
struct timespec64 now;
- getnstimeofday64(&now);
+ ktime_get_ts64(&now);
if (unlikely(timespec64_compare(&now, busy_until) > 0)) {
ipmi_si_set_not_busy(busy_until);
return 0;
@@ -1530,7 +1530,7 @@ static int try_enable_event_buffer(struct smi_info *smi_info)
rv = wait_for_msg_done(smi_info);
if (rv) {
- pr_warn(PFX "Error getting response from get global enables command, the event buffer is not enabled.\n");
+ pr_warn("Error getting response from get global enables command, the event buffer is not enabled\n");
goto out;
}
@@ -1541,7 +1541,7 @@ static int try_enable_event_buffer(struct smi_info *smi_info)
resp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 ||
resp[1] != IPMI_GET_BMC_GLOBAL_ENABLES_CMD ||
resp[2] != 0) {
- pr_warn(PFX "Invalid return from get global enables command, cannot enable the event buffer.\n");
+ pr_warn("Invalid return from get global enables command, cannot enable the event buffer\n");
rv = -EINVAL;
goto out;
}
@@ -1559,7 +1559,7 @@ static int try_enable_event_buffer(struct smi_info *smi_info)
rv = wait_for_msg_done(smi_info);
if (rv) {
- pr_warn(PFX "Error getting response from set global, enables command, the event buffer is not enabled.\n");
+ pr_warn("Error getting response from set global, enables command, the event buffer is not enabled\n");
goto out;
}
@@ -1569,7 +1569,7 @@ static int try_enable_event_buffer(struct smi_info *smi_info)
if (resp_len < 3 ||
resp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 ||
resp[1] != IPMI_SET_BMC_GLOBAL_ENABLES_CMD) {
- pr_warn(PFX "Invalid return from get global, enables command, not enable the event buffer.\n");
+ pr_warn("Invalid return from get global, enables command, not enable the event buffer\n");
rv = -EINVAL;
goto out;
}
@@ -1900,7 +1900,7 @@ int ipmi_si_add_smi(struct si_sm_io *io)
}
}
- pr_info(PFX "Adding %s-specified %s state machine\n",
+ pr_info("Adding %s-specified %s state machine\n",
ipmi_addr_src_to_str(new_smi->io.addr_source),
si_to_str[new_smi->io.si_type]);
@@ -1924,7 +1924,7 @@ static int try_smi_init(struct smi_info *new_smi)
int i;
char *init_name = NULL;
- pr_info(PFX "Trying %s-specified %s state machine at %s address 0x%lx, slave address 0x%x, irq %d\n",
+ pr_info("Trying %s-specified %s state machine at %s address 0x%lx, slave address 0x%x, irq %d\n",
ipmi_addr_src_to_str(new_smi->io.addr_source),
si_to_str[new_smi->io.si_type],
addr_space_to_str[new_smi->io.addr_type],
@@ -1964,7 +1964,7 @@ static int try_smi_init(struct smi_info *new_smi)
new_smi->pdev = platform_device_alloc("ipmi_si",
new_smi->si_num);
if (!new_smi->pdev) {
- pr_err(PFX "Unable to allocate platform device\n");
+ pr_err("Unable to allocate platform device\n");
rv = -ENOMEM;
goto out_err;
}
@@ -2097,7 +2097,7 @@ static int init_ipmi_si(void)
if (initialized)
return 0;
- pr_info("IPMI System Interface driver.\n");
+ pr_info("IPMI System Interface driver\n");
/* If the user gave us a device, they presumably want us to use it */
if (!ipmi_si_hardcode_find_bmc())
@@ -2151,7 +2151,7 @@ skip_fallback_noirq:
if (unload_when_empty && list_empty(&smi_infos)) {
mutex_unlock(&smi_infos_lock);
cleanup_ipmi_si();
- pr_warn(PFX "Unable to find any System Interface(s)\n");
+ pr_warn("Unable to find any System Interface(s)\n");
return -ENODEV;
} else {
mutex_unlock(&smi_infos_lock);
diff --git a/drivers/char/ipmi/ipmi_si_mem_io.c b/drivers/char/ipmi/ipmi_si_mem_io.c
index 1b869d530884..fd0ec8d6bf0e 100644
--- a/drivers/char/ipmi/ipmi_si_mem_io.c
+++ b/drivers/char/ipmi/ipmi_si_mem_io.c
@@ -51,7 +51,7 @@ static unsigned char mem_inq(const struct si_sm_io *io, unsigned int offset)
static void mem_outq(const struct si_sm_io *io, unsigned int offset,
unsigned char b)
{
- writeq(b << io->regshift, (io->addr)+(offset * io->regspacing));
+ writeq((u64)b << io->regshift, (io->addr)+(offset * io->regspacing));
}
#endif
diff --git a/drivers/char/ipmi/ipmi_si_pci.c b/drivers/char/ipmi/ipmi_si_pci.c
index f54ca6869ed2..ce00c0da5866 100644
--- a/drivers/char/ipmi/ipmi_si_pci.c
+++ b/drivers/char/ipmi/ipmi_si_pci.c
@@ -4,12 +4,13 @@
*
* Handling for IPMI devices on the PCI bus.
*/
+
+#define pr_fmt(fmt) "ipmi_pci: " fmt
+
#include <linux/module.h>
#include <linux/pci.h>
#include "ipmi_si.h"
-#define PFX "ipmi_pci: "
-
static bool pci_registered;
static bool si_trypci = true;
@@ -18,11 +19,6 @@ module_param_named(trypci, si_trypci, bool, 0);
MODULE_PARM_DESC(trypci, "Setting this to zero will disable the"
" default scan of the interfaces identified via pci");
-#define PCI_CLASS_SERIAL_IPMI 0x0c07
-#define PCI_CLASS_SERIAL_IPMI_SMIC 0x0c0700
-#define PCI_CLASS_SERIAL_IPMI_KCS 0x0c0701
-#define PCI_CLASS_SERIAL_IPMI_BT 0x0c0702
-
#define PCI_DEVICE_ID_HP_MMC 0x121A
static void ipmi_pci_cleanup(struct si_sm_io *io)
@@ -45,8 +41,7 @@ static int ipmi_pci_probe_regspacing(struct si_sm_io *io)
for (regspacing = DEFAULT_REGSPACING; regspacing <= 16;) {
io->regspacing = regspacing;
if (io->io_setup(io)) {
- dev_err(io->dev,
- "Could not setup I/O space\n");
+ dev_err(io->dev, "Could not setup I/O space\n");
return DEFAULT_REGSPACING;
}
/* write invalid cmd */
@@ -120,6 +115,8 @@ static int ipmi_pci_probe(struct pci_dev *pdev,
}
io.addr_data = pci_resource_start(pdev, 0);
+ io.dev = &pdev->dev;
+
io.regspacing = ipmi_pci_probe_regspacing(&io);
io.regsize = DEFAULT_REGSIZE;
io.regshift = 0;
@@ -128,10 +125,8 @@ static int ipmi_pci_probe(struct pci_dev *pdev,
if (io.irq)
io.irq_setup = ipmi_std_irq_setup;
- io.dev = &pdev->dev;
-
dev_info(&pdev->dev, "%pR regsize %d spacing %d irq %d\n",
- &pdev->resource[0], io.regsize, io.regspacing, io.irq);
+ &pdev->resource[0], io.regsize, io.regspacing, io.irq);
rv = ipmi_si_add_smi(&io);
if (rv)
@@ -166,7 +161,7 @@ void ipmi_si_pci_init(void)
if (si_trypci) {
int rv = pci_register_driver(&ipmi_pci_driver);
if (rv)
- pr_err(PFX "Unable to register PCI driver: %d\n", rv);
+ pr_err("Unable to register PCI driver: %d\n", rv);
else
pci_registered = true;
}
diff --git a/drivers/char/ipmi/ipmi_si_platform.c b/drivers/char/ipmi/ipmi_si_platform.c
index bf69927502bd..15cf819f884f 100644
--- a/drivers/char/ipmi/ipmi_si_platform.c
+++ b/drivers/char/ipmi/ipmi_si_platform.c
@@ -5,6 +5,10 @@
* Handling for platform devices in IPMI (ACPI, OF, and things
* coming from the platform.
*/
+
+#define pr_fmt(fmt) "ipmi_platform: " fmt
+#define dev_fmt pr_fmt
+
#include <linux/types.h>
#include <linux/module.h>
#include <linux/of_device.h>
@@ -15,8 +19,6 @@
#include "ipmi_si.h"
#include "ipmi_dmi.h"
-#define PFX "ipmi_platform: "
-
static bool si_tryplatform = true;
#ifdef CONFIG_ACPI
static bool si_tryacpi = true;
@@ -158,7 +160,7 @@ static int platform_ipmi_probe(struct platform_device *pdev)
memset(&io, 0, sizeof(io));
io.addr_source = addr_source;
- dev_info(&pdev->dev, PFX "probing via %s\n",
+ dev_info(&pdev->dev, "probing via %s\n",
ipmi_addr_src_to_str(addr_source));
switch (type) {
@@ -236,25 +238,25 @@ static int of_ipmi_probe(struct platform_device *pdev)
ret = of_address_to_resource(np, 0, &resource);
if (ret) {
- dev_warn(&pdev->dev, PFX "invalid address from OF\n");
+ dev_warn(&pdev->dev, "invalid address from OF\n");
return ret;
}
regsize = of_get_property(np, "reg-size", &proplen);
if (regsize && proplen != 4) {
- dev_warn(&pdev->dev, PFX "invalid regsize from OF\n");
+ dev_warn(&pdev->dev, "invalid regsize from OF\n");
return -EINVAL;
}
regspacing = of_get_property(np, "reg-spacing", &proplen);
if (regspacing && proplen != 4) {
- dev_warn(&pdev->dev, PFX "invalid regspacing from OF\n");
+ dev_warn(&pdev->dev, "invalid regspacing from OF\n");
return -EINVAL;
}
regshift = of_get_property(np, "reg-shift", &proplen);
if (regshift && proplen != 4) {
- dev_warn(&pdev->dev, PFX "invalid regshift from OF\n");
+ dev_warn(&pdev->dev, "invalid regshift from OF\n");
return -EINVAL;
}
@@ -326,7 +328,7 @@ static int acpi_ipmi_probe(struct platform_device *pdev)
memset(&io, 0, sizeof(io));
io.addr_source = SI_ACPI;
- dev_info(&pdev->dev, PFX "probing via ACPI\n");
+ dev_info(&pdev->dev, "probing via ACPI\n");
io.addr_info.acpi_info.acpi_handle = handle;
@@ -417,6 +419,11 @@ static int ipmi_remove(struct platform_device *pdev)
return ipmi_si_remove_by_dev(&pdev->dev);
}
+static const struct platform_device_id si_plat_ids[] = {
+ { "dmi-ipmi-si", 0 },
+ { }
+};
+
struct platform_driver ipmi_platform_driver = {
.driver = {
.name = DEVICE_NAME,
@@ -425,13 +432,14 @@ struct platform_driver ipmi_platform_driver = {
},
.probe = ipmi_probe,
.remove = ipmi_remove,
+ .id_table = si_plat_ids
};
void ipmi_si_platform_init(void)
{
int rv = platform_driver_register(&ipmi_platform_driver);
if (rv)
- pr_err(PFX "Unable to register driver: %d\n", rv);
+ pr_err("Unable to register driver: %d\n", rv);
}
void ipmi_si_platform_shutdown(void)
diff --git a/drivers/char/ipmi/ipmi_smic_sm.c b/drivers/char/ipmi/ipmi_smic_sm.c
index 466a5aac5298..b6225bba2532 100644
--- a/drivers/char/ipmi/ipmi_smic_sm.c
+++ b/drivers/char/ipmi/ipmi_smic_sm.c
@@ -132,8 +132,8 @@ static int start_smic_transaction(struct si_sm_data *smic,
if (smic_debug & SMIC_DEBUG_MSG) {
printk(KERN_DEBUG "start_smic_transaction -");
for (i = 0; i < size; i++)
- printk(" %02x", (unsigned char) data[i]);
- printk("\n");
+ pr_cont(" %02x", data[i]);
+ pr_cont("\n");
}
smic->error_retries = 0;
memcpy(smic->write_data, data, size);
@@ -154,8 +154,8 @@ static int smic_get_result(struct si_sm_data *smic,
if (smic_debug & SMIC_DEBUG_MSG) {
printk(KERN_DEBUG "smic_get result -");
for (i = 0; i < smic->read_pos; i++)
- printk(" %02x", smic->read_data[i]);
- printk("\n");
+ pr_cont(" %02x", smic->read_data[i]);
+ pr_cont("\n");
}
if (length < smic->read_pos) {
smic->read_pos = length;
@@ -212,8 +212,7 @@ static inline void start_error_recovery(struct si_sm_data *smic, char *reason)
(smic->error_retries)++;
if (smic->error_retries > SMIC_MAX_ERROR_RETRIES) {
if (smic_debug & SMIC_DEBUG_ENABLE)
- printk(KERN_WARNING
- "ipmi_smic_drv: smic hosed: %s\n", reason);
+ pr_warn("ipmi_smic_drv: smic hosed: %s\n", reason);
smic->state = SMIC_HOSED;
} else {
smic->write_count = smic->orig_write_count;
@@ -326,8 +325,7 @@ static enum si_sm_result smic_event(struct si_sm_data *smic, long time)
if (smic->state != SMIC_IDLE) {
if (smic_debug & SMIC_DEBUG_STATES)
printk(KERN_DEBUG
- "smic_event - smic->smic_timeout = %ld,"
- " time = %ld\n",
+ "smic_event - smic->smic_timeout = %ld, time = %ld\n",
smic->smic_timeout, time);
/*
* FIXME: smic_event is sometimes called with time >
@@ -347,9 +345,7 @@ static enum si_sm_result smic_event(struct si_sm_data *smic, long time)
status = read_smic_status(smic);
if (smic_debug & SMIC_DEBUG_STATES)
- printk(KERN_DEBUG
- "smic_event - state = %d, flags = 0x%02x,"
- " status = 0x%02x\n",
+ printk(KERN_DEBUG "smic_event - state = %d, flags = 0x%02x, status = 0x%02x\n",
smic->state, flags, status);
switch (smic->state) {
@@ -440,8 +436,8 @@ static enum si_sm_result smic_event(struct si_sm_data *smic, long time)
data = read_smic_data(smic);
if (data != 0) {
if (smic_debug & SMIC_DEBUG_ENABLE)
- printk(KERN_DEBUG
- "SMIC_WRITE_END: data = %02x\n", data);
+ printk(KERN_DEBUG "SMIC_WRITE_END: data = %02x\n",
+ data);
start_error_recovery(smic,
"state = SMIC_WRITE_END, "
"data != SUCCESS");
@@ -520,8 +516,8 @@ static enum si_sm_result smic_event(struct si_sm_data *smic, long time)
/* data register holds an error code */
if (data != 0) {
if (smic_debug & SMIC_DEBUG_ENABLE)
- printk(KERN_DEBUG
- "SMIC_READ_END: data = %02x\n", data);
+ printk(KERN_DEBUG "SMIC_READ_END: data = %02x\n",
+ data);
start_error_recovery(smic,
"state = SMIC_READ_END, "
"data != SUCCESS");
diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
index 29e67a80fb20..ca9528c4f183 100644
--- a/drivers/char/ipmi/ipmi_ssif.c
+++ b/drivers/char/ipmi/ipmi_ssif.c
@@ -27,6 +27,8 @@
* interface into the I2C driver, I believe.
*/
+#define pr_fmt(fmt) "ipmi_ssif: " fmt
+
#if defined(MODVERSIONS)
#include <linux/modversions.h>
#endif
@@ -52,7 +54,6 @@
#include "ipmi_si_sm.h"
#include "ipmi_dmi.h"
-#define PFX "ipmi_ssif: "
#define DEVICE_NAME "ipmi_ssif"
#define IPMI_GET_SYSTEM_INTERFACE_CAPABILITIES_CMD 0x57
@@ -60,6 +61,7 @@
#define SSIF_IPMI_REQUEST 2
#define SSIF_IPMI_MULTI_PART_REQUEST_START 6
#define SSIF_IPMI_MULTI_PART_REQUEST_MIDDLE 7
+#define SSIF_IPMI_MULTI_PART_REQUEST_END 8
#define SSIF_IPMI_RESPONSE 3
#define SSIF_IPMI_MULTI_PART_RESPONSE_MIDDLE 9
@@ -271,6 +273,7 @@ struct ssif_info {
/* Info from SSIF cmd */
unsigned char max_xmit_msg_size;
unsigned char max_recv_msg_size;
+ bool cmd8_works; /* See test_multipart_messages() for details. */
unsigned int multi_support;
int supports_pec;
@@ -316,9 +319,8 @@ static void deliver_recv_msg(struct ssif_info *ssif_info,
{
if (msg->rsp_size < 0) {
return_hosed_msg(ssif_info, msg);
- pr_err(PFX
- "Malformed message in deliver_recv_msg: rsp_size = %d\n",
- msg->rsp_size);
+ pr_err("%s: Malformed message: rsp_size = %d\n",
+ __func__, msg->rsp_size);
} else {
ipmi_smi_msg_received(ssif_info->intf, msg);
}
@@ -606,8 +608,9 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
ssif_info->waiting_alert = true;
ssif_info->rtc_us_timer = SSIF_MSG_USEC;
- mod_timer(&ssif_info->retry_timer,
- jiffies + SSIF_MSG_JIFFIES);
+ if (!ssif_info->stopping)
+ mod_timer(&ssif_info->retry_timer,
+ jiffies + SSIF_MSG_JIFFIES);
ipmi_ssif_unlock_cond(ssif_info, flags);
return;
}
@@ -652,7 +655,7 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
if (len == 0) {
result = -EIO;
if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
- pr_info(PFX "Middle message with no data\n");
+ pr_info("Middle message with no data\n");
goto continue_op;
}
@@ -696,8 +699,7 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
I2C_SMBUS_BLOCK_DATA);
if (rv < 0) {
if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
- pr_info(PFX
- "Error from ssif_i2c_send\n");
+ pr_info("Error from ssif_i2c_send\n");
result = -EIO;
} else
@@ -715,7 +717,7 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
continue_op:
if (ssif_info->ssif_debug & SSIF_DEBUG_STATE)
- pr_info(PFX "DONE 1: state = %d, result=%d.\n",
+ pr_info("DONE 1: state = %d, result=%d\n",
ssif_info->ssif_state, result);
flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
@@ -749,8 +751,8 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
*/
ssif_info->ssif_state = SSIF_NORMAL;
ipmi_ssif_unlock_cond(ssif_info, flags);
- pr_warn(PFX "Error getting flags: %d %d, %x\n",
- result, len, (len >= 3) ? data[2] : 0);
+ pr_warn("Error getting flags: %d %d, %x\n",
+ result, len, (len >= 3) ? data[2] : 0);
} else if (data[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2
|| data[1] != IPMI_GET_MSG_FLAGS_CMD) {
/*
@@ -758,7 +760,7 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
* response to a previous command.
*/
ipmi_ssif_unlock_cond(ssif_info, flags);
- pr_warn(PFX "Invalid response getting flags: %x %x\n",
+ pr_warn("Invalid response getting flags: %x %x\n",
data[0], data[1]);
} else {
ssif_inc_stat(ssif_info, flag_fetches);
@@ -771,11 +773,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
/* We cleared the flags. */
if ((result < 0) || (len < 3) || (data[2] != 0)) {
/* Error clearing flags */
- pr_warn(PFX "Error clearing flags: %d %d, %x\n",
- result, len, (len >= 3) ? data[2] : 0);
+ pr_warn("Error clearing flags: %d %d, %x\n",
+ result, len, (len >= 3) ? data[2] : 0);
} else if (data[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2
|| data[1] != IPMI_CLEAR_MSG_FLAGS_CMD) {
- pr_warn(PFX "Invalid response clearing flags: %x %x\n",
+ pr_warn("Invalid response clearing flags: %x %x\n",
data[0], data[1]);
}
ssif_info->ssif_state = SSIF_NORMAL;
@@ -792,7 +794,7 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
handle_flags(ssif_info, flags);
} else if (msg->rsp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2
|| msg->rsp[1] != IPMI_READ_EVENT_MSG_BUFFER_CMD) {
- pr_warn(PFX "Invalid response getting events: %x %x\n",
+ pr_warn("Invalid response getting events: %x %x\n",
msg->rsp[0], msg->rsp[1]);
msg->done(msg);
/* Take off the event flag. */
@@ -815,7 +817,7 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
handle_flags(ssif_info, flags);
} else if (msg->rsp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2
|| msg->rsp[1] != IPMI_GET_MSG_CMD) {
- pr_warn(PFX "Invalid response clearing flags: %x %x\n",
+ pr_warn("Invalid response clearing flags: %x %x\n",
msg->rsp[0], msg->rsp[1]);
msg->done(msg);
@@ -842,7 +844,7 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
ipmi_ssif_unlock_cond(ssif_info, flags);
if (ssif_info->ssif_debug & SSIF_DEBUG_STATE)
- pr_info(PFX "DONE 2: state = %d.\n", ssif_info->ssif_state);
+ pr_info("DONE 2: state = %d.\n", ssif_info->ssif_state);
}
static void msg_written_handler(struct ssif_info *ssif_info, int result,
@@ -862,8 +864,7 @@ static void msg_written_handler(struct ssif_info *ssif_info, int result,
ssif_inc_stat(ssif_info, send_errors);
if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
- pr_info(PFX
- "Out of retries in msg_written_handler\n");
+ pr_info("%s: Out of retries\n", __func__);
msg_done_handler(ssif_info, -EIO, NULL, 0);
return;
}
@@ -887,32 +888,33 @@ static void msg_written_handler(struct ssif_info *ssif_info, int result,
* in the SSIF_MULTI_n_PART case in the probe function
* for details on the intricacies of this.
*/
- int left;
+ int left, to_write;
unsigned char *data_to_send;
+ unsigned char cmd;
ssif_inc_stat(ssif_info, sent_messages_parts);
left = ssif_info->multi_len - ssif_info->multi_pos;
- if (left > 32)
- left = 32;
+ to_write = left;
+ if (to_write > 32)
+ to_write = 32;
/* Length byte. */
- ssif_info->multi_data[ssif_info->multi_pos] = left;
+ ssif_info->multi_data[ssif_info->multi_pos] = to_write;
data_to_send = ssif_info->multi_data + ssif_info->multi_pos;
- ssif_info->multi_pos += left;
- if (left < 32)
- /*
- * Write is finished. Note that we must end
- * with a write of less than 32 bytes to
- * complete the transaction, even if it is
- * zero bytes.
- */
+ ssif_info->multi_pos += to_write;
+ cmd = SSIF_IPMI_MULTI_PART_REQUEST_MIDDLE;
+ if (ssif_info->cmd8_works) {
+ if (left == to_write) {
+ cmd = SSIF_IPMI_MULTI_PART_REQUEST_END;
+ ssif_info->multi_data = NULL;
+ }
+ } else if (to_write < 32) {
ssif_info->multi_data = NULL;
+ }
rv = ssif_i2c_send(ssif_info, msg_written_handler,
- I2C_SMBUS_WRITE,
- SSIF_IPMI_MULTI_PART_REQUEST_MIDDLE,
- data_to_send,
- I2C_SMBUS_BLOCK_DATA);
+ I2C_SMBUS_WRITE, cmd,
+ data_to_send, I2C_SMBUS_BLOCK_DATA);
if (rv < 0) {
/* request failed, just return the error. */
ssif_inc_stat(ssif_info, send_errors);
@@ -939,8 +941,9 @@ static void msg_written_handler(struct ssif_info *ssif_info, int result,
ssif_info->waiting_alert = true;
ssif_info->retries_left = SSIF_RECV_RETRIES;
ssif_info->rtc_us_timer = SSIF_MSG_PART_USEC;
- mod_timer(&ssif_info->retry_timer,
- jiffies + SSIF_MSG_PART_JIFFIES);
+ if (!ssif_info->stopping)
+ mod_timer(&ssif_info->retry_timer,
+ jiffies + SSIF_MSG_PART_JIFFIES);
ipmi_ssif_unlock_cond(ssif_info, flags);
}
}
@@ -1043,8 +1046,8 @@ static void sender(void *send_info,
ktime_get_real_ts64(&t);
pr_info("**Enqueue %02x %02x: %lld.%6.6ld\n",
- msg->data[0], msg->data[1],
- (long long) t.tv_sec, (long) t.tv_nsec / NSEC_PER_USEC);
+ msg->data[0], msg->data[1],
+ (long long)t.tv_sec, (long)t.tv_nsec / NSEC_PER_USEC);
}
}
@@ -1244,6 +1247,24 @@ static int ssif_remove(struct i2c_client *client)
return 0;
}
+static int read_response(struct i2c_client *client, unsigned char *resp)
+{
+ int ret = -ENODEV, retry_cnt = SSIF_RECV_RETRIES;
+
+ while (retry_cnt > 0) {
+ ret = i2c_smbus_read_block_data(client, SSIF_IPMI_RESPONSE,
+ resp);
+ if (ret > 0)
+ break;
+ msleep(SSIF_MSG_MSEC);
+ retry_cnt--;
+ if (retry_cnt <= 0)
+ break;
+ }
+
+ return ret;
+}
+
static int do_cmd(struct i2c_client *client, int len, unsigned char *msg,
int *resp_len, unsigned char *resp)
{
@@ -1260,26 +1281,16 @@ static int do_cmd(struct i2c_client *client, int len, unsigned char *msg,
return -ENODEV;
}
- ret = -ENODEV;
- retry_cnt = SSIF_RECV_RETRIES;
- while (retry_cnt > 0) {
- ret = i2c_smbus_read_block_data(client, SSIF_IPMI_RESPONSE,
- resp);
- if (ret > 0)
- break;
- msleep(SSIF_MSG_MSEC);
- retry_cnt--;
- if (retry_cnt <= 0)
- break;
- }
-
+ ret = read_response(client, resp);
if (ret > 0) {
/* Validate that the response is correct. */
if (ret < 3 ||
(resp[0] != (msg[0] | (1 << 2))) ||
(resp[1] != msg[1]))
ret = -EINVAL;
- else {
+ else if (ret > IPMI_MAX_MSG_LENGTH) {
+ ret = -E2BIG;
+ } else {
*resp_len = ret;
ret = 0;
}
@@ -1391,6 +1402,121 @@ static int find_slave_address(struct i2c_client *client, int slave_addr)
return slave_addr;
}
+static int start_multipart_test(struct i2c_client *client,
+ unsigned char *msg, bool do_middle)
+{
+ int retry_cnt = SSIF_SEND_RETRIES, ret;
+
+retry_write:
+ ret = i2c_smbus_write_block_data(client,
+ SSIF_IPMI_MULTI_PART_REQUEST_START,
+ 32, msg);
+ if (ret) {
+ retry_cnt--;
+ if (retry_cnt > 0)
+ goto retry_write;
+ dev_err(&client->dev, "Could not write multi-part start, though the BMC said it could handle it. Just limit sends to one part.\n");
+ return ret;
+ }
+
+ if (!do_middle)
+ return 0;
+
+ ret = i2c_smbus_write_block_data(client,
+ SSIF_IPMI_MULTI_PART_REQUEST_MIDDLE,
+ 32, msg + 32);
+ if (ret) {
+ dev_err(&client->dev, "Could not write multi-part middle, though the BMC said it could handle it. Just limit sends to one part.\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void test_multipart_messages(struct i2c_client *client,
+ struct ssif_info *ssif_info,
+ unsigned char *resp)
+{
+ unsigned char msg[65];
+ int ret;
+ bool do_middle;
+
+ if (ssif_info->max_xmit_msg_size <= 32)
+ return;
+
+ do_middle = ssif_info->max_xmit_msg_size > 63;
+
+ memset(msg, 0, sizeof(msg));
+ msg[0] = IPMI_NETFN_APP_REQUEST << 2;
+ msg[1] = IPMI_GET_DEVICE_ID_CMD;
+
+ /*
+ * The specification is all messed up dealing with sending
+ * multi-part messages. Per what the specification says, it
+ * is impossible to send a message that is a multiple of 32
+ * bytes, except for 32 itself. It talks about a "start"
+ * transaction (cmd=6) that must be 32 bytes, "middle"
+ * transaction (cmd=7) that must be 32 bytes, and an "end"
+ * transaction. The "end" transaction is shown as cmd=7 in
+ * the text, but if that's the case there is no way to
+ * differentiate between a middle and end part except the
+ * length being less than 32. But there is a table at the far
+ * end of the section (that I had never noticed until someone
+ * pointed it out to me) that mentions it as cmd=8.
+ *
+ * After some thought, I think the example is wrong and the
+ * end transaction should be cmd=8. But some systems don't
+ * implement cmd=8, they use a zero-length end transaction,
+ * even though that violates the SMBus specification.
+ *
+ * So, to work around this, this code tests if cmd=8 works.
+ * If it does, then we use that. If not, it tests zero-
+ * byte end transactions. If that works, good. If not,
+ * we only allow 63-byte transactions max.
+ */
+
+ ret = start_multipart_test(client, msg, do_middle);
+ if (ret)
+ goto out_no_multi_part;
+
+ ret = i2c_smbus_write_block_data(client,
+ SSIF_IPMI_MULTI_PART_REQUEST_END,
+ 1, msg + 64);
+
+ if (!ret)
+ ret = read_response(client, resp);
+
+ if (ret > 0) {
+ /* End transactions work, we are good. */
+ ssif_info->cmd8_works = true;
+ return;
+ }
+
+ ret = start_multipart_test(client, msg, do_middle);
+ if (ret) {
+ dev_err(&client->dev, "Second multipart test failed.\n");
+ goto out_no_multi_part;
+ }
+
+ ret = i2c_smbus_write_block_data(client,
+ SSIF_IPMI_MULTI_PART_REQUEST_MIDDLE,
+ 0, msg + 64);
+ if (!ret)
+ ret = read_response(client, resp);
+ if (ret > 0)
+ /* Zero-size end parts work, use those. */
+ return;
+
+ /* Limit to 63 bytes and use a short middle command to mark the end. */
+ if (ssif_info->max_xmit_msg_size > 63)
+ ssif_info->max_xmit_msg_size = 63;
+ return;
+
+out_no_multi_part:
+ ssif_info->max_xmit_msg_size = 32;
+ return;
+}
+
/*
* Global enables we care about.
*/
@@ -1435,9 +1561,9 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
slave_addr = find_slave_address(client, slave_addr);
- pr_info(PFX "Trying %s-specified SSIF interface at i2c address 0x%x, adapter %s, slave address 0x%x\n",
- ipmi_addr_src_to_str(ssif_info->addr_source),
- client->addr, client->adapter->name, slave_addr);
+ pr_info("Trying %s-specified SSIF interface at i2c address 0x%x, adapter %s, slave address 0x%x\n",
+ ipmi_addr_src_to_str(ssif_info->addr_source),
+ client->addr, client->adapter->name, slave_addr);
ssif_info->client = client;
i2c_set_clientdata(client, ssif_info);
@@ -1450,7 +1576,7 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
if (!rv && (len >= 3) && (resp[2] == 0)) {
if (len < 7) {
if (ssif_dbg_probe)
- pr_info(PFX "SSIF info too short: %d\n", len);
+ pr_info("SSIF info too short: %d\n", len);
goto no_support;
}
@@ -1477,26 +1603,7 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
break;
case SSIF_MULTI_n_PART:
- /*
- * The specification is rather confusing at
- * this point, but I think I understand what
- * is meant. At least I have a workable
- * solution. With multi-part messages, you
- * cannot send a message that is a multiple of
- * 32-bytes in length, because the start and
- * middle messages are 32-bytes and the end
- * message must be at least one byte. You
- * can't fudge on an extra byte, that would
- * screw up things like fru data writes. So
- * we limit the length to 63 bytes. That way
- * a 32-byte message gets sent as a single
- * part. A larger message will be a 32-byte
- * start and the next message is always going
- * to be 1-31 bytes in length. Not ideal, but
- * it should work.
- */
- if (ssif_info->max_xmit_msg_size > 63)
- ssif_info->max_xmit_msg_size = 63;
+ /* We take whatever size given, but do some testing. */
break;
default:
@@ -1506,8 +1613,8 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
} else {
no_support:
/* Assume no multi-part or PEC support */
- pr_info(PFX "Error fetching SSIF: %d %d %2.2x, your system probably doesn't support this command so using defaults\n",
- rv, len, resp[2]);
+ pr_info("Error fetching SSIF: %d %d %2.2x, your system probably doesn't support this command so using defaults\n",
+ rv, len, resp[2]);
ssif_info->max_xmit_msg_size = 32;
ssif_info->max_recv_msg_size = 32;
@@ -1515,13 +1622,15 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
ssif_info->supports_pec = 0;
}
+ test_multipart_messages(client, ssif_info, resp);
+
/* Make sure the NMI timeout is cleared. */
msg[0] = IPMI_NETFN_APP_REQUEST << 2;
msg[1] = IPMI_CLEAR_MSG_FLAGS_CMD;
msg[2] = WDT_PRE_TIMEOUT_INT;
rv = do_cmd(client, 3, msg, &len, resp);
if (rv || (len < 3) || (resp[2] != 0))
- pr_warn(PFX "Unable to clear message flags: %d %d %2.2x\n",
+ pr_warn("Unable to clear message flags: %d %d %2.2x\n",
rv, len, resp[2]);
/* Attempt to enable the event buffer. */
@@ -1529,7 +1638,7 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;
rv = do_cmd(client, 2, msg, &len, resp);
if (rv || (len < 4) || (resp[2] != 0)) {
- pr_warn(PFX "Error getting global enables: %d %d %2.2x\n",
+ pr_warn("Error getting global enables: %d %d %2.2x\n",
rv, len, resp[2]);
rv = 0; /* Not fatal */
goto found;
@@ -1548,7 +1657,7 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
msg[2] = ssif_info->global_enables | IPMI_BMC_EVT_MSG_BUFF;
rv = do_cmd(client, 3, msg, &len, resp);
if (rv || (len < 2)) {
- pr_warn(PFX "Error setting global enables: %d %d %2.2x\n",
+ pr_warn("Error setting global enables: %d %d %2.2x\n",
rv, len, resp[2]);
rv = 0; /* Not fatal */
goto found;
@@ -1569,7 +1678,7 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
msg[2] = ssif_info->global_enables | IPMI_BMC_RCV_MSG_INTR;
rv = do_cmd(client, 3, msg, &len, resp);
if (rv || (len < 2)) {
- pr_warn(PFX "Error setting global enables: %d %d %2.2x\n",
+ pr_warn("Error setting global enables: %d %d %2.2x\n",
rv, len, resp[2]);
rv = 0; /* Not fatal */
goto found;
@@ -1637,7 +1746,7 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
&ssif_info->client->dev,
slave_addr);
if (rv) {
- pr_err(PFX "Unable to register device: error %d\n", rv);
+ pr_err("Unable to register device: error %d\n", rv);
goto out_remove_attr;
}
@@ -1741,7 +1850,7 @@ static void free_ssif_clients(void)
static unsigned short *ssif_address_list(void)
{
struct ssif_addr_info *info;
- unsigned int count = 0, i;
+ unsigned int count = 0, i = 0;
unsigned short *address_list;
list_for_each_entry(info, &ssif_infos, link)
@@ -1752,18 +1861,17 @@ static unsigned short *ssif_address_list(void)
if (!address_list)
return NULL;
- i = 0;
list_for_each_entry(info, &ssif_infos, link) {
unsigned short addr = info->binfo.addr;
int j;
for (j = 0; j < i; j++) {
if (address_list[j] == addr)
- goto skip_addr;
+ /* Found a dup. */
+ break;
}
- address_list[i] = addr;
-skip_addr:
- i++;
+ if (j == i) /* Didn't find it in the list. */
+ address_list[i++] = addr;
}
address_list[i] = I2C_CLIENT_END;
@@ -1790,7 +1898,7 @@ static int dmi_ipmi_probe(struct platform_device *pdev)
rv = device_property_read_u16(&pdev->dev, "i2c-addr", &i2c_addr);
if (rv) {
- dev_warn(&pdev->dev, PFX "No i2c-addr property\n");
+ dev_warn(&pdev->dev, "No i2c-addr property\n");
return -ENODEV;
}
@@ -1847,12 +1955,18 @@ static int ssif_platform_remove(struct platform_device *dev)
return 0;
}
+static const struct platform_device_id ssif_plat_ids[] = {
+ { "dmi-ipmi-ssif", 0 },
+ { }
+};
+
static struct platform_driver ipmi_driver = {
.driver = {
.name = DEVICE_NAME,
},
.probe = ssif_platform_probe,
.remove = ssif_platform_remove,
+ .id_table = ssif_plat_ids
};
static int init_ipmi_ssif(void)
@@ -1871,8 +1985,7 @@ static int init_ipmi_ssif(void)
dbg[i], slave_addrs[i],
SI_HARDCODED, NULL);
if (rv)
- pr_err(PFX
- "Couldn't add hardcoded device at addr 0x%x\n",
+ pr_err("Couldn't add hardcoded device at addr 0x%x\n",
addr[i]);
}
@@ -1883,7 +1996,7 @@ static int init_ipmi_ssif(void)
if (ssif_trydmi) {
rv = platform_driver_register(&ipmi_driver);
if (rv)
- pr_err(PFX "Unable to register driver: %d\n", rv);
+ pr_err("Unable to register driver: %d\n", rv);
}
ssif_i2c_driver.address_list = ssif_address_list();
@@ -1905,6 +2018,8 @@ static void cleanup_ipmi_ssif(void)
i2c_del_driver(&ssif_i2c_driver);
+ kfree(ssif_i2c_driver.address_list);
+
platform_driver_unregister(&ipmi_driver);
free_ssif_clients();
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c
index ca1c5c5109f0..2924a4bc4a32 100644
--- a/drivers/char/ipmi/ipmi_watchdog.c
+++ b/drivers/char/ipmi/ipmi_watchdog.c
@@ -11,6 +11,8 @@
* Copyright 2002 MontaVista Software Inc.
*/
+#define pr_fmt(fmt) "IPMI Watchdog: " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/ipmi.h>
@@ -50,8 +52,6 @@
#define HAVE_DIE_NMI
#endif
-#define PFX "IPMI Watchdog: "
-
/*
* The IPMI command/response information for the watchdog timer.
*/
@@ -407,7 +407,7 @@ static int __ipmi_set_timeout(struct ipmi_smi_msg *smi_msg,
recv_msg,
1);
if (rv)
- pr_warn(PFX "set timeout error: %d\n", rv);
+ pr_warn("set timeout error: %d\n", rv);
else if (send_heartbeat_now)
*send_heartbeat_now = hbnow;
@@ -530,7 +530,7 @@ static void panic_halt_ipmi_set_timeout(void)
&send_heartbeat_now);
if (rv) {
atomic_sub(1, &panic_done_count);
- pr_warn(PFX "Unable to extend the watchdog timeout.");
+ pr_warn("Unable to extend the watchdog timeout\n");
} else {
if (send_heartbeat_now)
panic_halt_ipmi_heartbeat();
@@ -573,7 +573,7 @@ restart:
&recv_msg,
1);
if (rv) {
- pr_warn(PFX "heartbeat send failure: %d\n", rv);
+ pr_warn("heartbeat send failure: %d\n", rv);
return rv;
}
@@ -583,7 +583,7 @@ restart:
if (recv_msg.msg.data[0] == IPMI_WDOG_TIMER_NOT_INIT_RESP) {
timeout_retries++;
if (timeout_retries > 3) {
- pr_err(PFX ": Unable to restore the IPMI watchdog's settings, giving up.\n");
+ pr_err("Unable to restore the IPMI watchdog's settings, giving up\n");
rv = -EIO;
goto out;
}
@@ -598,7 +598,7 @@ restart:
*/
rv = _ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
if (rv) {
- pr_err(PFX ": Unable to send the command to set the watchdog's settings, giving up.\n");
+ pr_err("Unable to send the command to set the watchdog's settings, giving up\n");
goto out;
}
@@ -876,8 +876,7 @@ static int ipmi_close(struct inode *ino, struct file *filep)
_ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
mutex_unlock(&ipmi_watchdog_mutex);
} else {
- pr_crit(PFX
- "Unexpected close, not stopping watchdog!\n");
+ pr_crit("Unexpected close, not stopping watchdog!\n");
ipmi_heartbeat();
}
clear_bit(0, &ipmi_wdog_open);
@@ -911,9 +910,9 @@ static void ipmi_wdog_msg_handler(struct ipmi_recv_msg *msg,
{
if (msg->msg.cmd == IPMI_WDOG_RESET_TIMER &&
msg->msg.data[0] == IPMI_WDOG_TIMER_NOT_INIT_RESP)
- pr_info(PFX "response: The IPMI controller appears to have been reset, will attempt to reinitialize the watchdog timer\n");
+ pr_info("response: The IPMI controller appears to have been reset, will attempt to reinitialize the watchdog timer\n");
else if (msg->msg.data[0] != 0)
- pr_err(PFX "response: Error %x on cmd %x\n",
+ pr_err("response: Error %x on cmd %x\n",
msg->msg.data[0],
msg->msg.cmd);
@@ -985,7 +984,7 @@ static void ipmi_register_watchdog(int ipmi_intf)
rv = ipmi_create_user(ipmi_intf, &ipmi_hndlrs, NULL, &watchdog_user);
if (rv < 0) {
- pr_crit(PFX "Unable to register with ipmi\n");
+ pr_crit("Unable to register with ipmi\n");
goto out;
}
@@ -993,7 +992,7 @@ static void ipmi_register_watchdog(int ipmi_intf)
&ipmi_version_major,
&ipmi_version_minor);
if (rv) {
- pr_warn(PFX "Unable to get IPMI version, assuming 1.0\n");
+ pr_warn("Unable to get IPMI version, assuming 1.0\n");
ipmi_version_major = 1;
ipmi_version_minor = 0;
}
@@ -1002,7 +1001,7 @@ static void ipmi_register_watchdog(int ipmi_intf)
if (rv < 0) {
ipmi_destroy_user(watchdog_user);
watchdog_user = NULL;
- pr_crit(PFX "Unable to register misc device\n");
+ pr_crit("Unable to register misc device\n");
}
#ifdef HAVE_DIE_NMI
@@ -1024,7 +1023,7 @@ static void ipmi_register_watchdog(int ipmi_intf)
rv = ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB);
if (rv) {
- pr_warn(PFX "Error starting timer to test NMI: 0x%x. The NMI pretimeout will likely not work\n",
+ pr_warn("Error starting timer to test NMI: 0x%x. The NMI pretimeout will likely not work\n",
rv);
rv = 0;
goto out_restore;
@@ -1033,7 +1032,7 @@ static void ipmi_register_watchdog(int ipmi_intf)
msleep(1500);
if (testing_nmi != 2) {
- pr_warn(PFX "IPMI NMI didn't seem to occur. The NMI pretimeout will likely not work\n");
+ pr_warn("IPMI NMI didn't seem to occur. The NMI pretimeout will likely not work\n");
}
out_restore:
testing_nmi = 0;
@@ -1049,7 +1048,7 @@ static void ipmi_register_watchdog(int ipmi_intf)
start_now = 0; /* Disable this function after first startup. */
ipmi_watchdog_state = action_val;
ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB);
- pr_info(PFX "Starting now!\n");
+ pr_info("Starting now!\n");
} else {
/* Stop the timer now. */
ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
@@ -1086,7 +1085,7 @@ static void ipmi_unregister_watchdog(int ipmi_intf)
/* Disconnect from IPMI. */
rv = ipmi_destroy_user(loc_user);
if (rv)
- pr_warn(PFX "error unlinking from IPMI: %d\n", rv);
+ pr_warn("error unlinking from IPMI: %d\n", rv);
/* If it comes back, restart it properly. */
ipmi_start_timer_on_heartbeat = 1;
@@ -1127,7 +1126,7 @@ ipmi_nmi(unsigned int val, struct pt_regs *regs)
the timer. So do so. */
atomic_set(&pretimeout_since_last_heartbeat, 1);
if (atomic_inc_and_test(&preop_panic_excl))
- nmi_panic(regs, PFX "pre-timeout");
+ nmi_panic(regs, "pre-timeout");
}
return NMI_HANDLED;
@@ -1259,7 +1258,7 @@ static void check_parms(void)
if (preaction_val == WDOG_PRETIMEOUT_NMI) {
do_nmi = 1;
if (preop_val == WDOG_PREOP_GIVE_DATA) {
- pr_warn(PFX "Pretimeout op is to give data but NMI pretimeout is enabled, setting pretimeout op to none\n");
+ pr_warn("Pretimeout op is to give data but NMI pretimeout is enabled, setting pretimeout op to none\n");
preop_op("preop_none", NULL);
do_nmi = 0;
}
@@ -1268,7 +1267,7 @@ static void check_parms(void)
rv = register_nmi_handler(NMI_UNKNOWN, ipmi_nmi, 0,
"ipmi");
if (rv) {
- pr_warn(PFX "Can't register nmi handler\n");
+ pr_warn("Can't register nmi handler\n");
return;
} else
nmi_handler_registered = 1;
@@ -1285,19 +1284,18 @@ static int __init ipmi_wdog_init(void)
if (action_op(action, NULL)) {
action_op("reset", NULL);
- pr_info(PFX "Unknown action '%s', defaulting to reset\n",
- action);
+ pr_info("Unknown action '%s', defaulting to reset\n", action);
}
if (preaction_op(preaction, NULL)) {
preaction_op("pre_none", NULL);
- pr_info(PFX "Unknown preaction '%s', defaulting to none\n",
+ pr_info("Unknown preaction '%s', defaulting to none\n",
preaction);
}
if (preop_op(preop, NULL)) {
preop_op("preop_none", NULL);
- pr_info(PFX "Unknown preop '%s', defaulting to none\n", preop);
+ pr_info("Unknown preop '%s', defaulting to none\n", preop);
}
check_parms();
@@ -1311,11 +1309,11 @@ static int __init ipmi_wdog_init(void)
unregister_nmi_handler(NMI_UNKNOWN, "ipmi");
#endif
unregister_reboot_notifier(&wdog_reboot_notifier);
- pr_warn(PFX "can't register smi watcher\n");
+ pr_warn("can't register smi watcher\n");
return rv;
}
- pr_info(PFX "driver initialized\n");
+ pr_info("driver initialized\n");
return 0;
}
diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c
index a219964cb770..809507bf8f1c 100644
--- a/drivers/char/pcmcia/cm4000_cs.c
+++ b/drivers/char/pcmcia/cm4000_cs.c
@@ -530,7 +530,7 @@ static int set_protocol(struct cm4000_dev *dev, struct ptsreq *ptsreq)
DEBUGP(5, dev, "NumRecBytes is valid\n");
break;
}
- mdelay(10);
+ usleep_range(10000, 11000);
}
if (i == 100) {
DEBUGP(5, dev, "Timeout waiting for NumRecBytes getting "
@@ -546,7 +546,7 @@ static int set_protocol(struct cm4000_dev *dev, struct ptsreq *ptsreq)
DEBUGP(2, dev, "NumRecBytes = %i\n", num_bytes_read);
break;
}
- mdelay(10);
+ usleep_range(10000, 11000);
}
/* check whether it is a short PTS reply? */
diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c
index f80965407d3c..d5e43606339c 100644
--- a/drivers/char/pcmcia/cm4040_cs.c
+++ b/drivers/char/pcmcia/cm4040_cs.c
@@ -505,7 +505,7 @@ static void cm4040_reader_release(struct pcmcia_device *link)
DEBUGP(3, dev, "-> cm4040_reader_release\n");
while (link->open) {
- DEBUGP(3, dev, KERN_INFO MODULE_NAME ": delaying release "
+ DEBUGP(3, dev, MODULE_NAME ": delaying release "
"until process has terminated\n");
wait_event(dev->devq, (link->open == 0));
}
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 66b04194aa9f..82f9a6a814ae 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -2237,8 +2237,7 @@ static int mgslpc_ioctl(struct tty_struct *tty,
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_ioctl"))
return -ENODEV;
- if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
- (cmd != TIOCMIWAIT)) {
+ if (cmd != TIOCMIWAIT) {
if (tty_io_error(tty))
return -EIO;
}
diff --git a/drivers/char/random.c b/drivers/char/random.c
index c75b6cdf0053..2eb70e76ed35 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -433,9 +433,9 @@ static int crng_init_cnt = 0;
static unsigned long crng_global_init_time = 0;
#define CRNG_INIT_CNT_THRESH (2*CHACHA20_KEY_SIZE)
static void _extract_crng(struct crng_state *crng,
- __u32 out[CHACHA20_BLOCK_WORDS]);
+ __u8 out[CHACHA20_BLOCK_SIZE]);
static void _crng_backtrack_protect(struct crng_state *crng,
- __u32 tmp[CHACHA20_BLOCK_WORDS], int used);
+ __u8 tmp[CHACHA20_BLOCK_SIZE], int used);
static void process_random_ready_list(void);
static void _get_random_bytes(void *buf, int nbytes);
@@ -926,7 +926,7 @@ static void crng_reseed(struct crng_state *crng, struct entropy_store *r)
unsigned long flags;
int i, num;
union {
- __u32 block[CHACHA20_BLOCK_WORDS];
+ __u8 block[CHACHA20_BLOCK_SIZE];
__u32 key[8];
} buf;
@@ -973,7 +973,7 @@ static void crng_reseed(struct crng_state *crng, struct entropy_store *r)
}
static void _extract_crng(struct crng_state *crng,
- __u32 out[CHACHA20_BLOCK_WORDS])
+ __u8 out[CHACHA20_BLOCK_SIZE])
{
unsigned long v, flags;
@@ -990,7 +990,7 @@ static void _extract_crng(struct crng_state *crng,
spin_unlock_irqrestore(&crng->lock, flags);
}
-static void extract_crng(__u32 out[CHACHA20_BLOCK_WORDS])
+static void extract_crng(__u8 out[CHACHA20_BLOCK_SIZE])
{
struct crng_state *crng = NULL;
@@ -1008,7 +1008,7 @@ static void extract_crng(__u32 out[CHACHA20_BLOCK_WORDS])
* enough) to mutate the CRNG key to provide backtracking protection.
*/
static void _crng_backtrack_protect(struct crng_state *crng,
- __u32 tmp[CHACHA20_BLOCK_WORDS], int used)
+ __u8 tmp[CHACHA20_BLOCK_SIZE], int used)
{
unsigned long flags;
__u32 *s, *d;
@@ -1020,14 +1020,14 @@ static void _crng_backtrack_protect(struct crng_state *crng,
used = 0;
}
spin_lock_irqsave(&crng->lock, flags);
- s = &tmp[used / sizeof(__u32)];
+ s = (__u32 *) &tmp[used];
d = &crng->state[4];
for (i=0; i < 8; i++)
*d++ ^= *s++;
spin_unlock_irqrestore(&crng->lock, flags);
}
-static void crng_backtrack_protect(__u32 tmp[CHACHA20_BLOCK_WORDS], int used)
+static void crng_backtrack_protect(__u8 tmp[CHACHA20_BLOCK_SIZE], int used)
{
struct crng_state *crng = NULL;
@@ -1043,7 +1043,7 @@ static void crng_backtrack_protect(__u32 tmp[CHACHA20_BLOCK_WORDS], int used)
static ssize_t extract_crng_user(void __user *buf, size_t nbytes)
{
ssize_t ret = 0, i = CHACHA20_BLOCK_SIZE;
- __u32 tmp[CHACHA20_BLOCK_WORDS];
+ __u8 tmp[CHACHA20_BLOCK_SIZE] __aligned(4);
int large_request = (nbytes > 256);
while (nbytes) {
@@ -1622,7 +1622,7 @@ static void _warn_unseeded_randomness(const char *func_name, void *caller,
*/
static void _get_random_bytes(void *buf, int nbytes)
{
- __u32 tmp[CHACHA20_BLOCK_WORDS];
+ __u8 tmp[CHACHA20_BLOCK_SIZE] __aligned(4);
trace_get_random_bytes(nbytes, _RET_IP_);
@@ -2248,7 +2248,7 @@ u64 get_random_u64(void)
if (use_lock)
read_lock_irqsave(&batched_entropy_reset_lock, flags);
if (batch->position % ARRAY_SIZE(batch->entropy_u64) == 0) {
- extract_crng((__u32 *)batch->entropy_u64);
+ extract_crng((u8 *)batch->entropy_u64);
batch->position = 0;
}
ret = batch->entropy_u64[batch->position++];
@@ -2278,7 +2278,7 @@ u32 get_random_u32(void)
if (use_lock)
read_lock_irqsave(&batched_entropy_reset_lock, flags);
if (batch->position % ARRAY_SIZE(batch->entropy_u32) == 0) {
- extract_crng(batch->entropy_u32);
+ extract_crng((u8 *)batch->entropy_u32);
batch->position = 0;
}
ret = batch->entropy_u32[batch->position++];
diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
index 18c81cbe4704..536e55d3919f 100644
--- a/drivers/char/tpm/Kconfig
+++ b/drivers/char/tpm/Kconfig
@@ -5,7 +5,7 @@
menuconfig TCG_TPM
tristate "TPM Hardware Support"
depends on HAS_IOMEM
- select SECURITYFS
+ imply SECURITYFS
select CRYPTO
select CRYPTO_HASH_INFO
---help---
diff --git a/drivers/char/tpm/tpm-dev-common.c b/drivers/char/tpm/tpm-dev-common.c
index e4a04b2d3c32..99b5133a9d05 100644
--- a/drivers/char/tpm/tpm-dev-common.c
+++ b/drivers/char/tpm/tpm-dev-common.c
@@ -17,11 +17,36 @@
* License.
*
*/
+#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
+#include <linux/workqueue.h>
#include "tpm.h"
#include "tpm-dev.h"
+static struct workqueue_struct *tpm_dev_wq;
+static DEFINE_MUTEX(tpm_dev_wq_lock);
+
+static void tpm_async_work(struct work_struct *work)
+{
+ struct file_priv *priv =
+ container_of(work, struct file_priv, async_work);
+ ssize_t ret;
+
+ mutex_lock(&priv->buffer_mutex);
+ priv->command_enqueued = false;
+ ret = tpm_transmit(priv->chip, priv->space, priv->data_buffer,
+ sizeof(priv->data_buffer), 0);
+
+ tpm_put_ops(priv->chip);
+ if (ret > 0) {
+ priv->data_pending = ret;
+ mod_timer(&priv->user_read_timer, jiffies + (120 * HZ));
+ }
+ mutex_unlock(&priv->buffer_mutex);
+ wake_up_interruptible(&priv->async_wait);
+}
+
static void user_reader_timeout(struct timer_list *t)
{
struct file_priv *priv = from_timer(priv, t, user_read_timer);
@@ -29,27 +54,32 @@ static void user_reader_timeout(struct timer_list *t)
pr_warn("TPM user space timeout is deprecated (pid=%d)\n",
task_tgid_nr(current));
- schedule_work(&priv->work);
+ schedule_work(&priv->timeout_work);
}
-static void timeout_work(struct work_struct *work)
+static void tpm_timeout_work(struct work_struct *work)
{
- struct file_priv *priv = container_of(work, struct file_priv, work);
+ struct file_priv *priv = container_of(work, struct file_priv,
+ timeout_work);
mutex_lock(&priv->buffer_mutex);
priv->data_pending = 0;
memset(priv->data_buffer, 0, sizeof(priv->data_buffer));
mutex_unlock(&priv->buffer_mutex);
+ wake_up_interruptible(&priv->async_wait);
}
void tpm_common_open(struct file *file, struct tpm_chip *chip,
- struct file_priv *priv)
+ struct file_priv *priv, struct tpm_space *space)
{
priv->chip = chip;
+ priv->space = space;
+
mutex_init(&priv->buffer_mutex);
timer_setup(&priv->user_read_timer, user_reader_timeout, 0);
- INIT_WORK(&priv->work, timeout_work);
-
+ INIT_WORK(&priv->timeout_work, tpm_timeout_work);
+ INIT_WORK(&priv->async_work, tpm_async_work);
+ init_waitqueue_head(&priv->async_wait);
file->private_data = priv;
}
@@ -61,15 +91,17 @@ ssize_t tpm_common_read(struct file *file, char __user *buf,
int rc;
del_singleshot_timer_sync(&priv->user_read_timer);
- flush_work(&priv->work);
+ flush_work(&priv->timeout_work);
mutex_lock(&priv->buffer_mutex);
if (priv->data_pending) {
ret_size = min_t(ssize_t, size, priv->data_pending);
- rc = copy_to_user(buf, priv->data_buffer, ret_size);
- memset(priv->data_buffer, 0, priv->data_pending);
- if (rc)
- ret_size = -EFAULT;
+ if (ret_size > 0) {
+ rc = copy_to_user(buf, priv->data_buffer, ret_size);
+ memset(priv->data_buffer, 0, priv->data_pending);
+ if (rc)
+ ret_size = -EFAULT;
+ }
priv->data_pending = 0;
}
@@ -79,13 +111,12 @@ ssize_t tpm_common_read(struct file *file, char __user *buf,
}
ssize_t tpm_common_write(struct file *file, const char __user *buf,
- size_t size, loff_t *off, struct tpm_space *space)
+ size_t size, loff_t *off)
{
struct file_priv *priv = file->private_data;
- size_t in_size = size;
- ssize_t out_size;
+ int ret = 0;
- if (in_size > TPM_BUFSIZE)
+ if (size > TPM_BUFSIZE)
return -E2BIG;
mutex_lock(&priv->buffer_mutex);
@@ -94,21 +125,20 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf,
* tpm_read or a user_read_timer timeout. This also prevents split
* buffered writes from blocking here.
*/
- if (priv->data_pending != 0) {
- mutex_unlock(&priv->buffer_mutex);
- return -EBUSY;
+ if (priv->data_pending != 0 || priv->command_enqueued) {
+ ret = -EBUSY;
+ goto out;
}
- if (copy_from_user
- (priv->data_buffer, (void __user *) buf, in_size)) {
- mutex_unlock(&priv->buffer_mutex);
- return -EFAULT;
+ if (copy_from_user(priv->data_buffer, buf, size)) {
+ ret = -EFAULT;
+ goto out;
}
- if (in_size < 6 ||
- in_size < be32_to_cpu(*((__be32 *) (priv->data_buffer + 2)))) {
- mutex_unlock(&priv->buffer_mutex);
- return -EINVAL;
+ if (size < 6 ||
+ size < be32_to_cpu(*((__be32 *)(priv->data_buffer + 2)))) {
+ ret = -EINVAL;
+ goto out;
}
/* atomic tpm command send and result receive. We only hold the ops
@@ -116,25 +146,50 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf,
* the char dev is held open.
*/
if (tpm_try_get_ops(priv->chip)) {
- mutex_unlock(&priv->buffer_mutex);
- return -EPIPE;
+ ret = -EPIPE;
+ goto out;
}
- out_size = tpm_transmit(priv->chip, space, priv->data_buffer,
- sizeof(priv->data_buffer), 0);
- tpm_put_ops(priv->chip);
- if (out_size < 0) {
+ /*
+ * If in nonblocking mode schedule an async job to send
+ * the command return the size.
+ * In case of error the err code will be returned in
+ * the subsequent read call.
+ */
+ if (file->f_flags & O_NONBLOCK) {
+ priv->command_enqueued = true;
+ queue_work(tpm_dev_wq, &priv->async_work);
mutex_unlock(&priv->buffer_mutex);
- return out_size;
+ return size;
}
- priv->data_pending = out_size;
+ ret = tpm_transmit(priv->chip, priv->space, priv->data_buffer,
+ sizeof(priv->data_buffer), 0);
+ tpm_put_ops(priv->chip);
+
+ if (ret > 0) {
+ priv->data_pending = ret;
+ mod_timer(&priv->user_read_timer, jiffies + (120 * HZ));
+ ret = size;
+ }
+out:
mutex_unlock(&priv->buffer_mutex);
+ return ret;
+}
+
+__poll_t tpm_common_poll(struct file *file, poll_table *wait)
+{
+ struct file_priv *priv = file->private_data;
+ __poll_t mask = 0;
+
+ poll_wait(file, &priv->async_wait, wait);
- /* Set a timeout by which the reader must come claim the result */
- mod_timer(&priv->user_read_timer, jiffies + (120 * HZ));
+ if (priv->data_pending)
+ mask = EPOLLIN | EPOLLRDNORM;
+ else
+ mask = EPOLLOUT | EPOLLWRNORM;
- return in_size;
+ return mask;
}
/*
@@ -142,8 +197,24 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf,
*/
void tpm_common_release(struct file *file, struct file_priv *priv)
{
+ flush_work(&priv->async_work);
del_singleshot_timer_sync(&priv->user_read_timer);
- flush_work(&priv->work);
+ flush_work(&priv->timeout_work);
file->private_data = NULL;
priv->data_pending = 0;
}
+
+int __init tpm_dev_common_init(void)
+{
+ tpm_dev_wq = alloc_workqueue("tpm_dev_wq", WQ_MEM_RECLAIM, 0);
+
+ return !tpm_dev_wq ? -ENOMEM : 0;
+}
+
+void __exit tpm_dev_common_exit(void)
+{
+ if (tpm_dev_wq) {
+ destroy_workqueue(tpm_dev_wq);
+ tpm_dev_wq = NULL;
+ }
+}
diff --git a/drivers/char/tpm/tpm-dev.c b/drivers/char/tpm/tpm-dev.c
index ebd74ab5abef..32f9738f1cb2 100644
--- a/drivers/char/tpm/tpm-dev.c
+++ b/drivers/char/tpm/tpm-dev.c
@@ -39,7 +39,7 @@ static int tpm_open(struct inode *inode, struct file *file)
if (priv == NULL)
goto out;
- tpm_common_open(file, chip, priv);
+ tpm_common_open(file, chip, priv, NULL);
return 0;
@@ -48,12 +48,6 @@ static int tpm_open(struct inode *inode, struct file *file)
return -ENOMEM;
}
-static ssize_t tpm_write(struct file *file, const char __user *buf,
- size_t size, loff_t *off)
-{
- return tpm_common_write(file, buf, size, off, NULL);
-}
-
/*
* Called on file close
*/
@@ -73,6 +67,7 @@ const struct file_operations tpm_fops = {
.llseek = no_llseek,
.open = tpm_open,
.read = tpm_common_read,
- .write = tpm_write,
+ .write = tpm_common_write,
+ .poll = tpm_common_poll,
.release = tpm_release,
};
diff --git a/drivers/char/tpm/tpm-dev.h b/drivers/char/tpm/tpm-dev.h
index b24cfb4d3ee1..a126b575cb8c 100644
--- a/drivers/char/tpm/tpm-dev.h
+++ b/drivers/char/tpm/tpm-dev.h
@@ -2,27 +2,33 @@
#ifndef _TPM_DEV_H
#define _TPM_DEV_H
+#include <linux/poll.h>
#include "tpm.h"
struct file_priv {
struct tpm_chip *chip;
+ struct tpm_space *space;
- /* Data passed to and from the tpm via the read/write calls */
- size_t data_pending;
+ /* Holds the amount of data passed or an error code from async op */
+ ssize_t data_pending;
struct mutex buffer_mutex;
struct timer_list user_read_timer; /* user needs to claim result */
- struct work_struct work;
+ struct work_struct timeout_work;
+ struct work_struct async_work;
+ wait_queue_head_t async_wait;
+ bool command_enqueued;
u8 data_buffer[TPM_BUFSIZE];
};
void tpm_common_open(struct file *file, struct tpm_chip *chip,
- struct file_priv *priv);
+ struct file_priv *priv, struct tpm_space *space);
ssize_t tpm_common_read(struct file *file, char __user *buf,
size_t size, loff_t *off);
ssize_t tpm_common_write(struct file *file, const char __user *buf,
- size_t size, loff_t *off, struct tpm_space *space);
-void tpm_common_release(struct file *file, struct file_priv *priv);
+ size_t size, loff_t *off);
+__poll_t tpm_common_poll(struct file *file, poll_table *wait);
+void tpm_common_release(struct file *file, struct file_priv *priv);
#endif
diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
index 1a803b0cf980..129f640424b7 100644
--- a/drivers/char/tpm/tpm-interface.c
+++ b/drivers/char/tpm/tpm-interface.c
@@ -663,7 +663,8 @@ ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_space *space,
return len;
err = be32_to_cpu(header->return_code);
- if (err != 0 && desc)
+ if (err != 0 && err != TPM_ERR_DISABLED && err != TPM_ERR_DEACTIVATED
+ && desc)
dev_err(&chip->dev, "A TPM error (%d) occurred %s\n", err,
desc);
if (err)
@@ -1321,7 +1322,8 @@ int tpm_get_random(struct tpm_chip *chip, u8 *out, size_t max)
}
rlength = be32_to_cpu(tpm_cmd.header.out.length);
- if (rlength < offsetof(struct tpm_getrandom_out, rng_data) +
+ if (rlength < TPM_HEADER_SIZE +
+ offsetof(struct tpm_getrandom_out, rng_data) +
recd) {
total = -EFAULT;
break;
@@ -1407,19 +1409,32 @@ static int __init tpm_init(void)
tpmrm_class = class_create(THIS_MODULE, "tpmrm");
if (IS_ERR(tpmrm_class)) {
pr_err("couldn't create tpmrm class\n");
- class_destroy(tpm_class);
- return PTR_ERR(tpmrm_class);
+ rc = PTR_ERR(tpmrm_class);
+ goto out_destroy_tpm_class;
}
rc = alloc_chrdev_region(&tpm_devt, 0, 2*TPM_NUM_DEVICES, "tpm");
if (rc < 0) {
pr_err("tpm: failed to allocate char dev region\n");
- class_destroy(tpmrm_class);
- class_destroy(tpm_class);
- return rc;
+ goto out_destroy_tpmrm_class;
+ }
+
+ rc = tpm_dev_common_init();
+ if (rc) {
+ pr_err("tpm: failed to allocate char dev region\n");
+ goto out_unreg_chrdev;
}
return 0;
+
+out_unreg_chrdev:
+ unregister_chrdev_region(tpm_devt, 2 * TPM_NUM_DEVICES);
+out_destroy_tpmrm_class:
+ class_destroy(tpmrm_class);
+out_destroy_tpm_class:
+ class_destroy(tpm_class);
+
+ return rc;
}
static void __exit tpm_exit(void)
@@ -1428,6 +1443,7 @@ static void __exit tpm_exit(void)
class_destroy(tpm_class);
class_destroy(tpmrm_class);
unregister_chrdev_region(tpm_devt, 2*TPM_NUM_DEVICES);
+ tpm_dev_common_exit();
}
subsys_initcall(tpm_init);
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index f3501d05264f..f20dc8ece348 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -604,4 +604,6 @@ int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space,
int tpm_bios_log_setup(struct tpm_chip *chip);
void tpm_bios_log_teardown(struct tpm_chip *chip);
+int tpm_dev_common_init(void);
+void tpm_dev_common_exit(void);
#endif
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
index c31b490bd41d..3acf4fd4e5a5 100644
--- a/drivers/char/tpm/tpm2-cmd.c
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -329,7 +329,9 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
&buf.data[TPM_HEADER_SIZE];
recd = min_t(u32, be16_to_cpu(out->size), num_bytes);
if (tpm_buf_length(&buf) <
- offsetof(struct tpm2_get_random_out, buffer) + recd) {
+ TPM_HEADER_SIZE +
+ offsetof(struct tpm2_get_random_out, buffer) +
+ recd) {
err = -EFAULT;
goto out;
}
diff --git a/drivers/char/tpm/tpmrm-dev.c b/drivers/char/tpm/tpmrm-dev.c
index 1a0e97a5da5a..0c751a79bbed 100644
--- a/drivers/char/tpm/tpmrm-dev.c
+++ b/drivers/char/tpm/tpmrm-dev.c
@@ -28,7 +28,7 @@ static int tpmrm_open(struct inode *inode, struct file *file)
return -ENOMEM;
}
- tpm_common_open(file, chip, &priv->priv);
+ tpm_common_open(file, chip, &priv->priv, &priv->space);
return 0;
}
@@ -45,21 +45,12 @@ static int tpmrm_release(struct inode *inode, struct file *file)
return 0;
}
-static ssize_t tpmrm_write(struct file *file, const char __user *buf,
- size_t size, loff_t *off)
-{
- struct file_priv *fpriv = file->private_data;
- struct tpmrm_priv *priv = container_of(fpriv, struct tpmrm_priv, priv);
-
- return tpm_common_write(file, buf, size, off, &priv->space);
-}
-
const struct file_operations tpmrm_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.open = tpmrm_open,
.read = tpm_common_read,
- .write = tpmrm_write,
+ .write = tpm_common_write,
+ .poll = tpm_common_poll,
.release = tpmrm_release,
};
-
diff --git a/drivers/char/tpm/xen-tpmfront.c b/drivers/char/tpm/xen-tpmfront.c
index 911475d36800..b150f87f38f5 100644
--- a/drivers/char/tpm/xen-tpmfront.c
+++ b/drivers/char/tpm/xen-tpmfront.c
@@ -264,7 +264,7 @@ static int setup_ring(struct xenbus_device *dev, struct tpm_private *priv)
return -ENOMEM;
}
- rv = xenbus_grant_ring(dev, &priv->shr, 1, &gref);
+ rv = xenbus_grant_ring(dev, priv->shr, 1, &gref);
if (rv < 0)
return rv;
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 292056bbb30e..81cdb4eaca07 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -287,6 +287,7 @@ source "drivers/clk/actions/Kconfig"
source "drivers/clk/bcm/Kconfig"
source "drivers/clk/hisilicon/Kconfig"
source "drivers/clk/imgtec/Kconfig"
+source "drivers/clk/ingenic/Kconfig"
source "drivers/clk/keystone/Kconfig"
source "drivers/clk/mediatek/Kconfig"
source "drivers/clk/meson/Kconfig"
@@ -299,5 +300,6 @@ source "drivers/clk/sunxi-ng/Kconfig"
source "drivers/clk/tegra/Kconfig"
source "drivers/clk/ti/Kconfig"
source "drivers/clk/uniphier/Kconfig"
+source "drivers/clk/zynqmp/Kconfig"
endmenu
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index a84c5573cabe..72be7a38cff1 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -72,7 +72,8 @@ obj-$(CONFIG_H8300) += h8300/
obj-$(CONFIG_ARCH_HISI) += hisilicon/
obj-y += imgtec/
obj-$(CONFIG_ARCH_MXC) += imx/
-obj-$(CONFIG_MACH_INGENIC) += ingenic/
+obj-y += ingenic/
+obj-$(CONFIG_ARCH_K3) += keystone/
obj-$(CONFIG_ARCH_KEYSTONE) += keystone/
obj-$(CONFIG_MACH_LOONGSON32) += loongson1/
obj-y += mediatek/
@@ -108,3 +109,4 @@ obj-$(CONFIG_X86) += x86/
endif
obj-$(CONFIG_ARCH_ZX) += zte/
obj-$(CONFIG_ARCH_ZYNQ) += zynq/
+obj-$(CONFIG_COMMON_CLK_ZYNQMP) += zynqmp/
diff --git a/drivers/clk/actions/Kconfig b/drivers/clk/actions/Kconfig
index dc38c85a4833..04f0a6355726 100644
--- a/drivers/clk/actions/Kconfig
+++ b/drivers/clk/actions/Kconfig
@@ -2,6 +2,7 @@ config CLK_ACTIONS
bool "Clock driver for Actions Semi SoCs"
depends on ARCH_ACTIONS || COMPILE_TEST
select REGMAP_MMIO
+ select RESET_CONTROLLER
default ARCH_ACTIONS
if CLK_ACTIONS
diff --git a/drivers/clk/actions/Makefile b/drivers/clk/actions/Makefile
index 78c17d56f991..ccfdf9781cef 100644
--- a/drivers/clk/actions/Makefile
+++ b/drivers/clk/actions/Makefile
@@ -7,6 +7,7 @@ clk-owl-y += owl-divider.o
clk-owl-y += owl-factor.o
clk-owl-y += owl-composite.o
clk-owl-y += owl-pll.o
+clk-owl-y += owl-reset.o
# SoC support
obj-$(CONFIG_CLK_OWL_S700) += owl-s700.o
diff --git a/drivers/clk/actions/owl-common.c b/drivers/clk/actions/owl-common.c
index 61c1071b5180..32dd29e0a37e 100644
--- a/drivers/clk/actions/owl-common.c
+++ b/drivers/clk/actions/owl-common.c
@@ -39,7 +39,7 @@ static void owl_clk_set_regmap(const struct owl_clk_desc *desc,
}
int owl_clk_regmap_init(struct platform_device *pdev,
- const struct owl_clk_desc *desc)
+ struct owl_clk_desc *desc)
{
void __iomem *base;
struct regmap *regmap;
@@ -57,6 +57,7 @@ int owl_clk_regmap_init(struct platform_device *pdev,
}
owl_clk_set_regmap(desc, regmap);
+ desc->regmap = regmap;
return 0;
}
diff --git a/drivers/clk/actions/owl-common.h b/drivers/clk/actions/owl-common.h
index 4fd726ec54a6..5a866a8b913d 100644
--- a/drivers/clk/actions/owl-common.h
+++ b/drivers/clk/actions/owl-common.h
@@ -26,6 +26,9 @@ struct owl_clk_desc {
struct owl_clk_common **clks;
unsigned long num_clks;
struct clk_hw_onecell_data *hw_clks;
+ const struct owl_reset_map *resets;
+ unsigned long num_resets;
+ struct regmap *regmap;
};
static inline struct owl_clk_common *
@@ -35,7 +38,7 @@ static inline struct owl_clk_common *
}
int owl_clk_regmap_init(struct platform_device *pdev,
- const struct owl_clk_desc *desc);
+ struct owl_clk_desc *desc);
int owl_clk_probe(struct device *dev, struct clk_hw_onecell_data *hw_clks);
#endif /* _OWL_COMMON_H_ */
diff --git a/drivers/clk/actions/owl-reset.c b/drivers/clk/actions/owl-reset.c
new file mode 100644
index 000000000000..203f8f34a8d4
--- /dev/null
+++ b/drivers/clk/actions/owl-reset.c
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// Actions Semi Owl SoCs Reset Management Unit driver
+//
+// Copyright (c) 2018 Linaro Ltd.
+// Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+
+#include <linux/delay.h>
+#include <linux/regmap.h>
+#include <linux/reset-controller.h>
+
+#include "owl-reset.h"
+
+static int owl_reset_assert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct owl_reset *reset = to_owl_reset(rcdev);
+ const struct owl_reset_map *map = &reset->reset_map[id];
+
+ return regmap_update_bits(reset->regmap, map->reg, map->bit, 0);
+}
+
+static int owl_reset_deassert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct owl_reset *reset = to_owl_reset(rcdev);
+ const struct owl_reset_map *map = &reset->reset_map[id];
+
+ return regmap_update_bits(reset->regmap, map->reg, map->bit, map->bit);
+}
+
+static int owl_reset_reset(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ owl_reset_assert(rcdev, id);
+ udelay(1);
+ owl_reset_deassert(rcdev, id);
+
+ return 0;
+}
+
+static int owl_reset_status(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct owl_reset *reset = to_owl_reset(rcdev);
+ const struct owl_reset_map *map = &reset->reset_map[id];
+ u32 reg;
+ int ret;
+
+ ret = regmap_read(reset->regmap, map->reg, &reg);
+ if (ret)
+ return ret;
+
+ /*
+ * The reset control API expects 0 if reset is not asserted,
+ * which is the opposite of what our hardware uses.
+ */
+ return !(map->bit & reg);
+}
+
+const struct reset_control_ops owl_reset_ops = {
+ .assert = owl_reset_assert,
+ .deassert = owl_reset_deassert,
+ .reset = owl_reset_reset,
+ .status = owl_reset_status,
+};
diff --git a/drivers/clk/actions/owl-reset.h b/drivers/clk/actions/owl-reset.h
new file mode 100644
index 000000000000..10f5774979a6
--- /dev/null
+++ b/drivers/clk/actions/owl-reset.h
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// Actions Semi Owl SoCs Reset Management Unit driver
+//
+// Copyright (c) 2018 Linaro Ltd.
+// Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+
+#ifndef _OWL_RESET_H_
+#define _OWL_RESET_H_
+
+#include <linux/reset-controller.h>
+
+struct owl_reset_map {
+ u32 reg;
+ u32 bit;
+};
+
+struct owl_reset {
+ struct reset_controller_dev rcdev;
+ const struct owl_reset_map *reset_map;
+ struct regmap *regmap;
+};
+
+static inline struct owl_reset *to_owl_reset(struct reset_controller_dev *rcdev)
+{
+ return container_of(rcdev, struct owl_reset, rcdev);
+}
+
+extern const struct reset_control_ops owl_reset_ops;
+
+#endif /* _OWL_RESET_H_ */
diff --git a/drivers/clk/actions/owl-s700.c b/drivers/clk/actions/owl-s700.c
index 5e9531392ee5..a2f34d13fb54 100644
--- a/drivers/clk/actions/owl-s700.c
+++ b/drivers/clk/actions/owl-s700.c
@@ -20,8 +20,10 @@
#include "owl-gate.h"
#include "owl-mux.h"
#include "owl-pll.h"
+#include "owl-reset.h"
#include <dt-bindings/clock/actions,s700-cmu.h>
+#include <dt-bindings/reset/actions,s700-reset.h>
#define CMU_COREPLL (0x0000)
#define CMU_DEVPLL (0x0004)
@@ -569,20 +571,69 @@ static struct clk_hw_onecell_data s700_hw_clks = {
.num = CLK_NR_CLKS,
};
-static const struct owl_clk_desc s700_clk_desc = {
+static const struct owl_reset_map s700_resets[] = {
+ [RESET_DE] = { CMU_DEVRST0, BIT(0) },
+ [RESET_LCD0] = { CMU_DEVRST0, BIT(1) },
+ [RESET_DSI] = { CMU_DEVRST0, BIT(2) },
+ [RESET_CSI] = { CMU_DEVRST0, BIT(13) },
+ [RESET_SI] = { CMU_DEVRST0, BIT(14) },
+ [RESET_I2C0] = { CMU_DEVRST1, BIT(0) },
+ [RESET_I2C1] = { CMU_DEVRST1, BIT(1) },
+ [RESET_I2C2] = { CMU_DEVRST1, BIT(2) },
+ [RESET_I2C3] = { CMU_DEVRST1, BIT(3) },
+ [RESET_SPI0] = { CMU_DEVRST1, BIT(4) },
+ [RESET_SPI1] = { CMU_DEVRST1, BIT(5) },
+ [RESET_SPI2] = { CMU_DEVRST1, BIT(6) },
+ [RESET_SPI3] = { CMU_DEVRST1, BIT(7) },
+ [RESET_UART0] = { CMU_DEVRST1, BIT(8) },
+ [RESET_UART1] = { CMU_DEVRST1, BIT(9) },
+ [RESET_UART2] = { CMU_DEVRST1, BIT(10) },
+ [RESET_UART3] = { CMU_DEVRST1, BIT(11) },
+ [RESET_UART4] = { CMU_DEVRST1, BIT(12) },
+ [RESET_UART5] = { CMU_DEVRST1, BIT(13) },
+ [RESET_UART6] = { CMU_DEVRST1, BIT(14) },
+ [RESET_KEY] = { CMU_DEVRST1, BIT(24) },
+ [RESET_GPIO] = { CMU_DEVRST1, BIT(25) },
+ [RESET_AUDIO] = { CMU_DEVRST1, BIT(29) },
+};
+
+static struct owl_clk_desc s700_clk_desc = {
.clks = s700_clks,
.num_clks = ARRAY_SIZE(s700_clks),
.hw_clks = &s700_hw_clks,
+
+ .resets = s700_resets,
+ .num_resets = ARRAY_SIZE(s700_resets),
};
static int s700_clk_probe(struct platform_device *pdev)
{
- const struct owl_clk_desc *desc;
+ struct owl_clk_desc *desc;
+ struct owl_reset *reset;
+ int ret;
desc = &s700_clk_desc;
owl_clk_regmap_init(pdev, desc);
+ /*
+ * FIXME: Reset controller registration should be moved to
+ * common code, once all SoCs of Owl family supports it.
+ */
+ reset = devm_kzalloc(&pdev->dev, sizeof(*reset), GFP_KERNEL);
+ if (!reset)
+ return -ENOMEM;
+
+ reset->rcdev.of_node = pdev->dev.of_node;
+ reset->rcdev.ops = &owl_reset_ops;
+ reset->rcdev.nr_resets = desc->num_resets;
+ reset->reset_map = desc->resets;
+ reset->regmap = desc->regmap;
+
+ ret = devm_reset_controller_register(&pdev->dev, &reset->rcdev);
+ if (ret)
+ dev_err(&pdev->dev, "Failed to register reset controller\n");
+
return owl_clk_probe(&pdev->dev, desc->hw_clks);
}
diff --git a/drivers/clk/actions/owl-s900.c b/drivers/clk/actions/owl-s900.c
index 7f60ed6afe63..790890978424 100644
--- a/drivers/clk/actions/owl-s900.c
+++ b/drivers/clk/actions/owl-s900.c
@@ -19,8 +19,10 @@
#include "owl-gate.h"
#include "owl-mux.h"
#include "owl-pll.h"
+#include "owl-reset.h"
#include <dt-bindings/clock/actions,s900-cmu.h>
+#include <dt-bindings/reset/actions,s900-reset.h>
#define CMU_COREPLL (0x0000)
#define CMU_DEVPLL (0x0004)
@@ -684,20 +686,100 @@ static struct clk_hw_onecell_data s900_hw_clks = {
.num = CLK_NR_CLKS,
};
-static const struct owl_clk_desc s900_clk_desc = {
+static const struct owl_reset_map s900_resets[] = {
+ [RESET_DMAC] = { CMU_DEVRST0, BIT(0) },
+ [RESET_SRAMI] = { CMU_DEVRST0, BIT(1) },
+ [RESET_DDR_CTL_PHY] = { CMU_DEVRST0, BIT(2) },
+ [RESET_NANDC0] = { CMU_DEVRST0, BIT(3) },
+ [RESET_SD0] = { CMU_DEVRST0, BIT(4) },
+ [RESET_SD1] = { CMU_DEVRST0, BIT(5) },
+ [RESET_PCM1] = { CMU_DEVRST0, BIT(6) },
+ [RESET_DE] = { CMU_DEVRST0, BIT(7) },
+ [RESET_LVDS] = { CMU_DEVRST0, BIT(8) },
+ [RESET_SD2] = { CMU_DEVRST0, BIT(9) },
+ [RESET_DSI] = { CMU_DEVRST0, BIT(10) },
+ [RESET_CSI0] = { CMU_DEVRST0, BIT(11) },
+ [RESET_BISP_AXI] = { CMU_DEVRST0, BIT(12) },
+ [RESET_CSI1] = { CMU_DEVRST0, BIT(13) },
+ [RESET_GPIO] = { CMU_DEVRST0, BIT(15) },
+ [RESET_EDP] = { CMU_DEVRST0, BIT(16) },
+ [RESET_AUDIO] = { CMU_DEVRST0, BIT(17) },
+ [RESET_PCM0] = { CMU_DEVRST0, BIT(18) },
+ [RESET_HDE] = { CMU_DEVRST0, BIT(21) },
+ [RESET_GPU3D_PA] = { CMU_DEVRST0, BIT(22) },
+ [RESET_IMX] = { CMU_DEVRST0, BIT(23) },
+ [RESET_SE] = { CMU_DEVRST0, BIT(24) },
+ [RESET_NANDC1] = { CMU_DEVRST0, BIT(25) },
+ [RESET_SD3] = { CMU_DEVRST0, BIT(26) },
+ [RESET_GIC] = { CMU_DEVRST0, BIT(27) },
+ [RESET_GPU3D_PB] = { CMU_DEVRST0, BIT(28) },
+ [RESET_DDR_CTL_PHY_AXI] = { CMU_DEVRST0, BIT(29) },
+ [RESET_CMU_DDR] = { CMU_DEVRST0, BIT(30) },
+ [RESET_DMM] = { CMU_DEVRST0, BIT(31) },
+ [RESET_USB2HUB] = { CMU_DEVRST1, BIT(0) },
+ [RESET_USB2HSIC] = { CMU_DEVRST1, BIT(1) },
+ [RESET_HDMI] = { CMU_DEVRST1, BIT(2) },
+ [RESET_HDCP2TX] = { CMU_DEVRST1, BIT(3) },
+ [RESET_UART6] = { CMU_DEVRST1, BIT(4) },
+ [RESET_UART0] = { CMU_DEVRST1, BIT(5) },
+ [RESET_UART1] = { CMU_DEVRST1, BIT(6) },
+ [RESET_UART2] = { CMU_DEVRST1, BIT(7) },
+ [RESET_SPI0] = { CMU_DEVRST1, BIT(8) },
+ [RESET_SPI1] = { CMU_DEVRST1, BIT(9) },
+ [RESET_SPI2] = { CMU_DEVRST1, BIT(10) },
+ [RESET_SPI3] = { CMU_DEVRST1, BIT(11) },
+ [RESET_I2C0] = { CMU_DEVRST1, BIT(12) },
+ [RESET_I2C1] = { CMU_DEVRST1, BIT(13) },
+ [RESET_USB3] = { CMU_DEVRST1, BIT(14) },
+ [RESET_UART3] = { CMU_DEVRST1, BIT(15) },
+ [RESET_UART4] = { CMU_DEVRST1, BIT(16) },
+ [RESET_UART5] = { CMU_DEVRST1, BIT(17) },
+ [RESET_I2C2] = { CMU_DEVRST1, BIT(18) },
+ [RESET_I2C3] = { CMU_DEVRST1, BIT(19) },
+ [RESET_ETHERNET] = { CMU_DEVRST1, BIT(20) },
+ [RESET_CHIPID] = { CMU_DEVRST1, BIT(21) },
+ [RESET_I2C4] = { CMU_DEVRST1, BIT(22) },
+ [RESET_I2C5] = { CMU_DEVRST1, BIT(23) },
+ [RESET_CPU_SCNT] = { CMU_DEVRST1, BIT(30) }
+};
+
+static struct owl_clk_desc s900_clk_desc = {
.clks = s900_clks,
.num_clks = ARRAY_SIZE(s900_clks),
.hw_clks = &s900_hw_clks,
+
+ .resets = s900_resets,
+ .num_resets = ARRAY_SIZE(s900_resets),
};
static int s900_clk_probe(struct platform_device *pdev)
{
- const struct owl_clk_desc *desc;
+ struct owl_clk_desc *desc;
+ struct owl_reset *reset;
+ int ret;
desc = &s900_clk_desc;
owl_clk_regmap_init(pdev, desc);
+ /*
+ * FIXME: Reset controller registration should be moved to
+ * common code, once all SoCs of Owl family supports it.
+ */
+ reset = devm_kzalloc(&pdev->dev, sizeof(*reset), GFP_KERNEL);
+ if (!reset)
+ return -ENOMEM;
+
+ reset->rcdev.of_node = pdev->dev.of_node;
+ reset->rcdev.ops = &owl_reset_ops;
+ reset->rcdev.nr_resets = desc->num_resets;
+ reset->reset_map = desc->resets;
+ reset->regmap = desc->regmap;
+
+ ret = devm_reset_controller_register(&pdev->dev, &reset->rcdev);
+ if (ret)
+ dev_err(&pdev->dev, "Failed to register reset controller\n");
+
return owl_clk_probe(&pdev->dev, desc->hw_clks);
}
diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile
index facc169ebb68..c75df1cad60e 100644
--- a/drivers/clk/at91/Makefile
+++ b/drivers/clk/at91/Makefile
@@ -3,7 +3,7 @@
# Makefile for at91 specific clk
#
-obj-y += pmc.o sckc.o
+obj-y += pmc.o sckc.o dt-compat.o
obj-y += clk-slow.o clk-main.o clk-pll.o clk-plldiv.o clk-master.o
obj-y += clk-system.o clk-peripheral.o clk-programmable.o
@@ -14,3 +14,6 @@ obj-$(CONFIG_HAVE_AT91_SMD) += clk-smd.o
obj-$(CONFIG_HAVE_AT91_H32MX) += clk-h32mx.o
obj-$(CONFIG_HAVE_AT91_GENERATED_CLK) += clk-generated.o
obj-$(CONFIG_HAVE_AT91_I2S_MUX_CLK) += clk-i2s-mux.o
+obj-$(CONFIG_SOC_AT91SAM9) += at91sam9260.o at91sam9rl.o at91sam9x5.o
+obj-$(CONFIG_SOC_SAMA5D4) += sama5d4.o
+obj-$(CONFIG_SOC_SAMA5D2) += sama5d2.o
diff --git a/drivers/clk/at91/at91sam9260.c b/drivers/clk/at91/at91sam9260.c
new file mode 100644
index 000000000000..b1af5a395423
--- /dev/null
+++ b/drivers/clk/at91/at91sam9260.c
@@ -0,0 +1,494 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/clk-provider.h>
+#include <linux/mfd/syscon.h>
+#include <linux/slab.h>
+
+#include <dt-bindings/clock/at91.h>
+
+#include "pmc.h"
+
+struct sck {
+ char *n;
+ char *p;
+ u8 id;
+};
+
+struct pck {
+ char *n;
+ u8 id;
+};
+
+struct at91sam926x_data {
+ const struct clk_pll_layout *plla_layout;
+ const struct clk_pll_characteristics *plla_characteristics;
+ const struct clk_pll_layout *pllb_layout;
+ const struct clk_pll_characteristics *pllb_characteristics;
+ const struct clk_master_characteristics *mck_characteristics;
+ const struct sck *sck;
+ const struct pck *pck;
+ u8 num_sck;
+ u8 num_pck;
+ u8 num_progck;
+ bool has_slck;
+};
+
+static const struct clk_master_characteristics sam9260_mck_characteristics = {
+ .output = { .min = 0, .max = 105000000 },
+ .divisors = { 1, 2, 4, 0 },
+};
+
+static u8 sam9260_plla_out[] = { 0, 2 };
+
+static u16 sam9260_plla_icpll[] = { 1, 1 };
+
+static struct clk_range sam9260_plla_outputs[] = {
+ { .min = 80000000, .max = 160000000 },
+ { .min = 150000000, .max = 240000000 },
+};
+
+static const struct clk_pll_characteristics sam9260_plla_characteristics = {
+ .input = { .min = 1000000, .max = 32000000 },
+ .num_output = ARRAY_SIZE(sam9260_plla_outputs),
+ .output = sam9260_plla_outputs,
+ .icpll = sam9260_plla_icpll,
+ .out = sam9260_plla_out,
+};
+
+static u8 sam9260_pllb_out[] = { 1 };
+
+static u16 sam9260_pllb_icpll[] = { 1 };
+
+static struct clk_range sam9260_pllb_outputs[] = {
+ { .min = 70000000, .max = 130000000 },
+};
+
+static const struct clk_pll_characteristics sam9260_pllb_characteristics = {
+ .input = { .min = 1000000, .max = 5000000 },
+ .num_output = ARRAY_SIZE(sam9260_pllb_outputs),
+ .output = sam9260_pllb_outputs,
+ .icpll = sam9260_pllb_icpll,
+ .out = sam9260_pllb_out,
+};
+
+static const struct sck at91sam9260_systemck[] = {
+ { .n = "uhpck", .p = "usbck", .id = 6 },
+ { .n = "udpck", .p = "usbck", .id = 7 },
+ { .n = "pck0", .p = "prog0", .id = 8 },
+ { .n = "pck1", .p = "prog1", .id = 9 },
+};
+
+static const struct pck at91sam9260_periphck[] = {
+ { .n = "pioA_clk", .id = 2 },
+ { .n = "pioB_clk", .id = 3 },
+ { .n = "pioC_clk", .id = 4 },
+ { .n = "adc_clk", .id = 5 },
+ { .n = "usart0_clk", .id = 6 },
+ { .n = "usart1_clk", .id = 7 },
+ { .n = "usart2_clk", .id = 8 },
+ { .n = "mci0_clk", .id = 9 },
+ { .n = "udc_clk", .id = 10 },
+ { .n = "twi0_clk", .id = 11 },
+ { .n = "spi0_clk", .id = 12 },
+ { .n = "spi1_clk", .id = 13 },
+ { .n = "ssc0_clk", .id = 14 },
+ { .n = "tc0_clk", .id = 17 },
+ { .n = "tc1_clk", .id = 18 },
+ { .n = "tc2_clk", .id = 19 },
+ { .n = "ohci_clk", .id = 20 },
+ { .n = "macb0_clk", .id = 21 },
+ { .n = "isi_clk", .id = 22 },
+ { .n = "usart3_clk", .id = 23 },
+ { .n = "uart0_clk", .id = 24 },
+ { .n = "uart1_clk", .id = 25 },
+ { .n = "tc3_clk", .id = 26 },
+ { .n = "tc4_clk", .id = 27 },
+ { .n = "tc5_clk", .id = 28 },
+};
+
+static struct at91sam926x_data at91sam9260_data = {
+ .plla_layout = &at91rm9200_pll_layout,
+ .plla_characteristics = &sam9260_plla_characteristics,
+ .pllb_layout = &at91rm9200_pll_layout,
+ .pllb_characteristics = &sam9260_pllb_characteristics,
+ .mck_characteristics = &sam9260_mck_characteristics,
+ .sck = at91sam9260_systemck,
+ .num_sck = ARRAY_SIZE(at91sam9260_systemck),
+ .pck = at91sam9260_periphck,
+ .num_pck = ARRAY_SIZE(at91sam9260_periphck),
+ .num_progck = 2,
+ .has_slck = true,
+};
+
+static const struct clk_master_characteristics sam9g20_mck_characteristics = {
+ .output = { .min = 0, .max = 133000000 },
+ .divisors = { 1, 2, 4, 6 },
+};
+
+static u8 sam9g20_plla_out[] = { 0, 1, 2, 3, 0, 1, 2, 3 };
+
+static u16 sam9g20_plla_icpll[] = { 0, 0, 0, 0, 1, 1, 1, 1 };
+
+static struct clk_range sam9g20_plla_outputs[] = {
+ { .min = 745000000, .max = 800000000 },
+ { .min = 695000000, .max = 750000000 },
+ { .min = 645000000, .max = 700000000 },
+ { .min = 595000000, .max = 650000000 },
+ { .min = 545000000, .max = 600000000 },
+ { .min = 495000000, .max = 550000000 },
+ { .min = 445000000, .max = 500000000 },
+ { .min = 400000000, .max = 450000000 },
+};
+
+static const struct clk_pll_characteristics sam9g20_plla_characteristics = {
+ .input = { .min = 2000000, .max = 32000000 },
+ .num_output = ARRAY_SIZE(sam9g20_plla_outputs),
+ .output = sam9g20_plla_outputs,
+ .icpll = sam9g20_plla_icpll,
+ .out = sam9g20_plla_out,
+};
+
+static u8 sam9g20_pllb_out[] = { 0 };
+
+static u16 sam9g20_pllb_icpll[] = { 0 };
+
+static struct clk_range sam9g20_pllb_outputs[] = {
+ { .min = 30000000, .max = 100000000 },
+};
+
+static const struct clk_pll_characteristics sam9g20_pllb_characteristics = {
+ .input = { .min = 2000000, .max = 32000000 },
+ .num_output = ARRAY_SIZE(sam9g20_pllb_outputs),
+ .output = sam9g20_pllb_outputs,
+ .icpll = sam9g20_pllb_icpll,
+ .out = sam9g20_pllb_out,
+};
+
+static struct at91sam926x_data at91sam9g20_data = {
+ .plla_layout = &at91sam9g45_pll_layout,
+ .plla_characteristics = &sam9g20_plla_characteristics,
+ .pllb_layout = &at91sam9g20_pllb_layout,
+ .pllb_characteristics = &sam9g20_pllb_characteristics,
+ .mck_characteristics = &sam9g20_mck_characteristics,
+ .sck = at91sam9260_systemck,
+ .num_sck = ARRAY_SIZE(at91sam9260_systemck),
+ .pck = at91sam9260_periphck,
+ .num_pck = ARRAY_SIZE(at91sam9260_periphck),
+ .num_progck = 2,
+ .has_slck = true,
+};
+
+static const struct clk_master_characteristics sam9261_mck_characteristics = {
+ .output = { .min = 0, .max = 94000000 },
+ .divisors = { 1, 2, 4, 0 },
+};
+
+static struct clk_range sam9261_plla_outputs[] = {
+ { .min = 80000000, .max = 200000000 },
+ { .min = 190000000, .max = 240000000 },
+};
+
+static const struct clk_pll_characteristics sam9261_plla_characteristics = {
+ .input = { .min = 1000000, .max = 32000000 },
+ .num_output = ARRAY_SIZE(sam9261_plla_outputs),
+ .output = sam9261_plla_outputs,
+ .icpll = sam9260_plla_icpll,
+ .out = sam9260_plla_out,
+};
+
+static u8 sam9261_pllb_out[] = { 1 };
+
+static u16 sam9261_pllb_icpll[] = { 1 };
+
+static struct clk_range sam9261_pllb_outputs[] = {
+ { .min = 70000000, .max = 130000000 },
+};
+
+static const struct clk_pll_characteristics sam9261_pllb_characteristics = {
+ .input = { .min = 1000000, .max = 5000000 },
+ .num_output = ARRAY_SIZE(sam9261_pllb_outputs),
+ .output = sam9261_pllb_outputs,
+ .icpll = sam9261_pllb_icpll,
+ .out = sam9261_pllb_out,
+};
+
+static const struct sck at91sam9261_systemck[] = {
+ { .n = "uhpck", .p = "usbck", .id = 6 },
+ { .n = "udpck", .p = "usbck", .id = 7 },
+ { .n = "pck0", .p = "prog0", .id = 8 },
+ { .n = "pck1", .p = "prog1", .id = 9 },
+ { .n = "pck2", .p = "prog2", .id = 10 },
+ { .n = "pck3", .p = "prog3", .id = 11 },
+ { .n = "hclk0", .p = "masterck", .id = 16 },
+ { .n = "hclk1", .p = "masterck", .id = 17 },
+};
+
+static const struct pck at91sam9261_periphck[] = {
+ { .n = "pioA_clk", .id = 2, },
+ { .n = "pioB_clk", .id = 3, },
+ { .n = "pioC_clk", .id = 4, },
+ { .n = "usart0_clk", .id = 6, },
+ { .n = "usart1_clk", .id = 7, },
+ { .n = "usart2_clk", .id = 8, },
+ { .n = "mci0_clk", .id = 9, },
+ { .n = "udc_clk", .id = 10, },
+ { .n = "twi0_clk", .id = 11, },
+ { .n = "spi0_clk", .id = 12, },
+ { .n = "spi1_clk", .id = 13, },
+ { .n = "ssc0_clk", .id = 14, },
+ { .n = "ssc1_clk", .id = 15, },
+ { .n = "ssc2_clk", .id = 16, },
+ { .n = "tc0_clk", .id = 17, },
+ { .n = "tc1_clk", .id = 18, },
+ { .n = "tc2_clk", .id = 19, },
+ { .n = "ohci_clk", .id = 20, },
+ { .n = "lcd_clk", .id = 21, },
+};
+
+static struct at91sam926x_data at91sam9261_data = {
+ .plla_layout = &at91rm9200_pll_layout,
+ .plla_characteristics = &sam9261_plla_characteristics,
+ .pllb_layout = &at91rm9200_pll_layout,
+ .pllb_characteristics = &sam9261_pllb_characteristics,
+ .mck_characteristics = &sam9261_mck_characteristics,
+ .sck = at91sam9261_systemck,
+ .num_sck = ARRAY_SIZE(at91sam9261_systemck),
+ .pck = at91sam9261_periphck,
+ .num_pck = ARRAY_SIZE(at91sam9261_periphck),
+ .num_progck = 4,
+};
+
+static const struct clk_master_characteristics sam9263_mck_characteristics = {
+ .output = { .min = 0, .max = 120000000 },
+ .divisors = { 1, 2, 4, 0 },
+};
+
+static struct clk_range sam9263_pll_outputs[] = {
+ { .min = 80000000, .max = 200000000 },
+ { .min = 190000000, .max = 240000000 },
+};
+
+static const struct clk_pll_characteristics sam9263_pll_characteristics = {
+ .input = { .min = 1000000, .max = 32000000 },
+ .num_output = ARRAY_SIZE(sam9263_pll_outputs),
+ .output = sam9263_pll_outputs,
+ .icpll = sam9260_plla_icpll,
+ .out = sam9260_plla_out,
+};
+
+static const struct sck at91sam9263_systemck[] = {
+ { .n = "uhpck", .p = "usbck", .id = 6 },
+ { .n = "udpck", .p = "usbck", .id = 7 },
+ { .n = "pck0", .p = "prog0", .id = 8 },
+ { .n = "pck1", .p = "prog1", .id = 9 },
+ { .n = "pck2", .p = "prog2", .id = 10 },
+ { .n = "pck3", .p = "prog3", .id = 11 },
+};
+
+static const struct pck at91sam9263_periphck[] = {
+ { .n = "pioA_clk", .id = 2, },
+ { .n = "pioB_clk", .id = 3, },
+ { .n = "pioCDE_clk", .id = 4, },
+ { .n = "usart0_clk", .id = 7, },
+ { .n = "usart1_clk", .id = 8, },
+ { .n = "usart2_clk", .id = 9, },
+ { .n = "mci0_clk", .id = 10, },
+ { .n = "mci1_clk", .id = 11, },
+ { .n = "can_clk", .id = 12, },
+ { .n = "twi0_clk", .id = 13, },
+ { .n = "spi0_clk", .id = 14, },
+ { .n = "spi1_clk", .id = 15, },
+ { .n = "ssc0_clk", .id = 16, },
+ { .n = "ssc1_clk", .id = 17, },
+ { .n = "ac97_clk", .id = 18, },
+ { .n = "tcb_clk", .id = 19, },
+ { .n = "pwm_clk", .id = 20, },
+ { .n = "macb0_clk", .id = 21, },
+ { .n = "g2de_clk", .id = 23, },
+ { .n = "udc_clk", .id = 24, },
+ { .n = "isi_clk", .id = 25, },
+ { .n = "lcd_clk", .id = 26, },
+ { .n = "dma_clk", .id = 27, },
+ { .n = "ohci_clk", .id = 29, },
+};
+
+static struct at91sam926x_data at91sam9263_data = {
+ .plla_layout = &at91rm9200_pll_layout,
+ .plla_characteristics = &sam9263_pll_characteristics,
+ .pllb_layout = &at91rm9200_pll_layout,
+ .pllb_characteristics = &sam9263_pll_characteristics,
+ .mck_characteristics = &sam9263_mck_characteristics,
+ .sck = at91sam9263_systemck,
+ .num_sck = ARRAY_SIZE(at91sam9263_systemck),
+ .pck = at91sam9263_periphck,
+ .num_pck = ARRAY_SIZE(at91sam9263_periphck),
+ .num_progck = 4,
+};
+
+static void __init at91sam926x_pmc_setup(struct device_node *np,
+ struct at91sam926x_data *data)
+{
+ const char *slowxtal_name, *mainxtal_name;
+ struct pmc_data *at91sam9260_pmc;
+ u32 usb_div[] = { 1, 2, 4, 0 };
+ const char *parent_names[6];
+ const char *slck_name;
+ struct regmap *regmap;
+ struct clk_hw *hw;
+ int i;
+ bool bypass;
+
+ i = of_property_match_string(np, "clock-names", "slow_xtal");
+ if (i < 0)
+ return;
+
+ slowxtal_name = of_clk_get_parent_name(np, i);
+
+ i = of_property_match_string(np, "clock-names", "main_xtal");
+ if (i < 0)
+ return;
+ mainxtal_name = of_clk_get_parent_name(np, i);
+
+ regmap = syscon_node_to_regmap(np);
+ if (IS_ERR(regmap))
+ return;
+
+ at91sam9260_pmc = pmc_data_allocate(PMC_MAIN + 1,
+ ndck(data->sck, data->num_sck),
+ ndck(data->pck, data->num_pck), 0);
+ if (!at91sam9260_pmc)
+ return;
+
+ bypass = of_property_read_bool(np, "atmel,osc-bypass");
+
+ hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name,
+ bypass);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ hw = at91_clk_register_rm9200_main(regmap, "mainck", "main_osc");
+ if (IS_ERR(hw))
+ goto err_free;
+
+ at91sam9260_pmc->chws[PMC_MAIN] = hw;
+
+ if (data->has_slck) {
+ hw = clk_hw_register_fixed_rate_with_accuracy(NULL,
+ "slow_rc_osc",
+ NULL, 0, 32768,
+ 50000000);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ parent_names[0] = "slow_rc_osc";
+ parent_names[1] = "slow_xtal";
+ hw = at91_clk_register_sam9260_slow(regmap, "slck",
+ parent_names, 2);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ at91sam9260_pmc->chws[PMC_SLOW] = hw;
+ slck_name = "slck";
+ } else {
+ slck_name = slowxtal_name;
+ }
+
+ hw = at91_clk_register_pll(regmap, "pllack", "mainck", 0,
+ data->plla_layout,
+ data->plla_characteristics);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ hw = at91_clk_register_pll(regmap, "pllbck", "mainck", 1,
+ data->pllb_layout,
+ data->pllb_characteristics);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ parent_names[0] = slck_name;
+ parent_names[1] = "mainck";
+ parent_names[2] = "pllack";
+ parent_names[3] = "pllbck";
+ hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
+ &at91rm9200_master_layout,
+ data->mck_characteristics);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ at91sam9260_pmc->chws[PMC_MCK] = hw;
+
+ hw = at91rm9200_clk_register_usb(regmap, "usbck", "pllbck", usb_div);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ parent_names[0] = slck_name;
+ parent_names[1] = "mainck";
+ parent_names[2] = "pllack";
+ parent_names[3] = "pllbck";
+ for (i = 0; i < data->num_progck; i++) {
+ char name[6];
+
+ snprintf(name, sizeof(name), "prog%d", i);
+
+ hw = at91_clk_register_programmable(regmap, name,
+ parent_names, 4, i,
+ &at91rm9200_programmable_layout);
+ if (IS_ERR(hw))
+ goto err_free;
+ }
+
+ for (i = 0; i < data->num_sck; i++) {
+ hw = at91_clk_register_system(regmap, data->sck[i].n,
+ data->sck[i].p,
+ data->sck[i].id);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ at91sam9260_pmc->shws[data->sck[i].id] = hw;
+ }
+
+ for (i = 0; i < data->num_pck; i++) {
+ hw = at91_clk_register_peripheral(regmap,
+ data->pck[i].n,
+ "masterck",
+ data->pck[i].id);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ at91sam9260_pmc->phws[data->pck[i].id] = hw;
+ }
+
+ of_clk_add_hw_provider(np, of_clk_hw_pmc_get, at91sam9260_pmc);
+
+ return;
+
+err_free:
+ pmc_data_free(at91sam9260_pmc);
+}
+
+static void __init at91sam9260_pmc_setup(struct device_node *np)
+{
+ at91sam926x_pmc_setup(np, &at91sam9260_data);
+}
+CLK_OF_DECLARE_DRIVER(at91sam9260_pmc, "atmel,at91sam9260-pmc",
+ at91sam9260_pmc_setup);
+
+static void __init at91sam9261_pmc_setup(struct device_node *np)
+{
+ at91sam926x_pmc_setup(np, &at91sam9261_data);
+}
+CLK_OF_DECLARE_DRIVER(at91sam9261_pmc, "atmel,at91sam9261-pmc",
+ at91sam9261_pmc_setup);
+
+static void __init at91sam9263_pmc_setup(struct device_node *np)
+{
+ at91sam926x_pmc_setup(np, &at91sam9263_data);
+}
+CLK_OF_DECLARE_DRIVER(at91sam9263_pmc, "atmel,at91sam9263-pmc",
+ at91sam9263_pmc_setup);
+
+static void __init at91sam9g20_pmc_setup(struct device_node *np)
+{
+ at91sam926x_pmc_setup(np, &at91sam9g20_data);
+}
+CLK_OF_DECLARE_DRIVER(at91sam9g20_pmc, "atmel,at91sam9g20-pmc",
+ at91sam9g20_pmc_setup);
diff --git a/drivers/clk/at91/at91sam9rl.c b/drivers/clk/at91/at91sam9rl.c
new file mode 100644
index 000000000000..5aeef68b4bdd
--- /dev/null
+++ b/drivers/clk/at91/at91sam9rl.c
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/clk-provider.h>
+#include <linux/mfd/syscon.h>
+#include <linux/slab.h>
+
+#include <dt-bindings/clock/at91.h>
+
+#include "pmc.h"
+
+static const struct clk_master_characteristics sam9rl_mck_characteristics = {
+ .output = { .min = 0, .max = 94000000 },
+ .divisors = { 1, 2, 4, 0 },
+};
+
+static u8 sam9rl_plla_out[] = { 0, 2 };
+
+static struct clk_range sam9rl_plla_outputs[] = {
+ { .min = 80000000, .max = 200000000 },
+ { .min = 190000000, .max = 240000000 },
+};
+
+static const struct clk_pll_characteristics sam9rl_plla_characteristics = {
+ .input = { .min = 1000000, .max = 32000000 },
+ .num_output = ARRAY_SIZE(sam9rl_plla_outputs),
+ .output = sam9rl_plla_outputs,
+ .out = sam9rl_plla_out,
+};
+
+static const struct {
+ char *n;
+ char *p;
+ u8 id;
+} at91sam9rl_systemck[] = {
+ { .n = "pck0", .p = "prog0", .id = 8 },
+ { .n = "pck1", .p = "prog1", .id = 9 },
+};
+
+static const struct {
+ char *n;
+ u8 id;
+} at91sam9rl_periphck[] = {
+ { .n = "pioA_clk", .id = 2, },
+ { .n = "pioB_clk", .id = 3, },
+ { .n = "pioC_clk", .id = 4, },
+ { .n = "pioD_clk", .id = 5, },
+ { .n = "usart0_clk", .id = 6, },
+ { .n = "usart1_clk", .id = 7, },
+ { .n = "usart2_clk", .id = 8, },
+ { .n = "usart3_clk", .id = 9, },
+ { .n = "mci0_clk", .id = 10, },
+ { .n = "twi0_clk", .id = 11, },
+ { .n = "twi1_clk", .id = 12, },
+ { .n = "spi0_clk", .id = 13, },
+ { .n = "ssc0_clk", .id = 14, },
+ { .n = "ssc1_clk", .id = 15, },
+ { .n = "tc0_clk", .id = 16, },
+ { .n = "tc1_clk", .id = 17, },
+ { .n = "tc2_clk", .id = 18, },
+ { .n = "pwm_clk", .id = 19, },
+ { .n = "adc_clk", .id = 20, },
+ { .n = "dma0_clk", .id = 21, },
+ { .n = "udphs_clk", .id = 22, },
+ { .n = "lcd_clk", .id = 23, },
+};
+
+static void __init at91sam9rl_pmc_setup(struct device_node *np)
+{
+ const char *slck_name, *mainxtal_name;
+ struct pmc_data *at91sam9rl_pmc;
+ const char *parent_names[6];
+ struct regmap *regmap;
+ struct clk_hw *hw;
+ int i;
+
+ i = of_property_match_string(np, "clock-names", "slow_clk");
+ if (i < 0)
+ return;
+
+ slck_name = of_clk_get_parent_name(np, i);
+
+ i = of_property_match_string(np, "clock-names", "main_xtal");
+ if (i < 0)
+ return;
+ mainxtal_name = of_clk_get_parent_name(np, i);
+
+ regmap = syscon_node_to_regmap(np);
+ if (IS_ERR(regmap))
+ return;
+
+ at91sam9rl_pmc = pmc_data_allocate(PMC_MAIN + 1,
+ nck(at91sam9rl_systemck),
+ nck(at91sam9rl_periphck), 0);
+ if (!at91sam9rl_pmc)
+ return;
+
+ hw = at91_clk_register_rm9200_main(regmap, "mainck", mainxtal_name);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ at91sam9rl_pmc->chws[PMC_MAIN] = hw;
+
+ hw = at91_clk_register_pll(regmap, "pllack", "mainck", 0,
+ &at91rm9200_pll_layout,
+ &sam9rl_plla_characteristics);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ hw = at91_clk_register_utmi(regmap, NULL, "utmick", "mainck");
+ if (IS_ERR(hw))
+ goto err_free;
+
+ at91sam9rl_pmc->chws[PMC_UTMI] = hw;
+
+ parent_names[0] = slck_name;
+ parent_names[1] = "mainck";
+ parent_names[2] = "pllack";
+ parent_names[3] = "utmick";
+ hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
+ &at91rm9200_master_layout,
+ &sam9rl_mck_characteristics);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ at91sam9rl_pmc->chws[PMC_MCK] = hw;
+
+ parent_names[0] = slck_name;
+ parent_names[1] = "mainck";
+ parent_names[2] = "pllack";
+ parent_names[3] = "utmick";
+ parent_names[4] = "masterck";
+ for (i = 0; i < 2; i++) {
+ char name[6];
+
+ snprintf(name, sizeof(name), "prog%d", i);
+
+ hw = at91_clk_register_programmable(regmap, name,
+ parent_names, 5, i,
+ &at91rm9200_programmable_layout);
+ if (IS_ERR(hw))
+ goto err_free;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(at91sam9rl_systemck); i++) {
+ hw = at91_clk_register_system(regmap, at91sam9rl_systemck[i].n,
+ at91sam9rl_systemck[i].p,
+ at91sam9rl_systemck[i].id);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ at91sam9rl_pmc->shws[at91sam9rl_systemck[i].id] = hw;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(at91sam9rl_periphck); i++) {
+ hw = at91_clk_register_peripheral(regmap,
+ at91sam9rl_periphck[i].n,
+ "masterck",
+ at91sam9rl_periphck[i].id);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ at91sam9rl_pmc->phws[at91sam9rl_periphck[i].id] = hw;
+ }
+
+ of_clk_add_hw_provider(np, of_clk_hw_pmc_get, at91sam9rl_pmc);
+
+ return;
+
+err_free:
+ pmc_data_free(at91sam9rl_pmc);
+}
+CLK_OF_DECLARE_DRIVER(at91sam9rl_pmc, "atmel,at91sam9rl-pmc", at91sam9rl_pmc_setup);
diff --git a/drivers/clk/at91/at91sam9x5.c b/drivers/clk/at91/at91sam9x5.c
new file mode 100644
index 000000000000..2fe225a697df
--- /dev/null
+++ b/drivers/clk/at91/at91sam9x5.c
@@ -0,0 +1,309 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/clk-provider.h>
+#include <linux/mfd/syscon.h>
+#include <linux/slab.h>
+
+#include <dt-bindings/clock/at91.h>
+
+#include "pmc.h"
+
+static const struct clk_master_characteristics mck_characteristics = {
+ .output = { .min = 0, .max = 133333333 },
+ .divisors = { 1, 2, 4, 3 },
+ .have_div3_pres = 1,
+};
+
+static u8 plla_out[] = { 0, 1, 2, 3, 0, 1, 2, 3 };
+
+static u16 plla_icpll[] = { 0, 0, 0, 0, 1, 1, 1, 1 };
+
+static struct clk_range plla_outputs[] = {
+ { .min = 745000000, .max = 800000000 },
+ { .min = 695000000, .max = 750000000 },
+ { .min = 645000000, .max = 700000000 },
+ { .min = 595000000, .max = 650000000 },
+ { .min = 545000000, .max = 600000000 },
+ { .min = 495000000, .max = 555000000 },
+ { .min = 445000000, .max = 500000000 },
+ { .min = 400000000, .max = 450000000 },
+};
+
+static const struct clk_pll_characteristics plla_characteristics = {
+ .input = { .min = 2000000, .max = 32000000 },
+ .num_output = ARRAY_SIZE(plla_outputs),
+ .output = plla_outputs,
+ .icpll = plla_icpll,
+ .out = plla_out,
+};
+
+static const struct {
+ char *n;
+ char *p;
+ u8 id;
+} at91sam9x5_systemck[] = {
+ { .n = "ddrck", .p = "masterck", .id = 2 },
+ { .n = "smdck", .p = "smdclk", .id = 4 },
+ { .n = "uhpck", .p = "usbck", .id = 6 },
+ { .n = "udpck", .p = "usbck", .id = 7 },
+ { .n = "pck0", .p = "prog0", .id = 8 },
+ { .n = "pck1", .p = "prog1", .id = 9 },
+};
+
+struct pck {
+ char *n;
+ u8 id;
+};
+
+static const struct pck at91sam9x5_periphck[] = {
+ { .n = "pioAB_clk", .id = 2, },
+ { .n = "pioCD_clk", .id = 3, },
+ { .n = "smd_clk", .id = 4, },
+ { .n = "usart0_clk", .id = 5, },
+ { .n = "usart1_clk", .id = 6, },
+ { .n = "usart2_clk", .id = 7, },
+ { .n = "twi0_clk", .id = 9, },
+ { .n = "twi1_clk", .id = 10, },
+ { .n = "twi2_clk", .id = 11, },
+ { .n = "mci0_clk", .id = 12, },
+ { .n = "spi0_clk", .id = 13, },
+ { .n = "spi1_clk", .id = 14, },
+ { .n = "uart0_clk", .id = 15, },
+ { .n = "uart1_clk", .id = 16, },
+ { .n = "tcb0_clk", .id = 17, },
+ { .n = "pwm_clk", .id = 18, },
+ { .n = "adc_clk", .id = 19, },
+ { .n = "dma0_clk", .id = 20, },
+ { .n = "dma1_clk", .id = 21, },
+ { .n = "uhphs_clk", .id = 22, },
+ { .n = "udphs_clk", .id = 23, },
+ { .n = "mci1_clk", .id = 26, },
+ { .n = "ssc0_clk", .id = 28, },
+};
+
+static const struct pck at91sam9g15_periphck[] = {
+ { .n = "lcdc_clk", .id = 25, },
+ { /* sentinel */}
+};
+
+static const struct pck at91sam9g25_periphck[] = {
+ { .n = "usart3_clk", .id = 8, },
+ { .n = "macb0_clk", .id = 24, },
+ { .n = "isi_clk", .id = 25, },
+ { /* sentinel */}
+};
+
+static const struct pck at91sam9g35_periphck[] = {
+ { .n = "macb0_clk", .id = 24, },
+ { .n = "lcdc_clk", .id = 25, },
+ { /* sentinel */}
+};
+
+static const struct pck at91sam9x25_periphck[] = {
+ { .n = "usart3_clk", .id = 8, },
+ { .n = "macb0_clk", .id = 24, },
+ { .n = "macb1_clk", .id = 27, },
+ { .n = "can0_clk", .id = 29, },
+ { .n = "can1_clk", .id = 30, },
+ { /* sentinel */}
+};
+
+static const struct pck at91sam9x35_periphck[] = {
+ { .n = "macb0_clk", .id = 24, },
+ { .n = "lcdc_clk", .id = 25, },
+ { .n = "can0_clk", .id = 29, },
+ { .n = "can1_clk", .id = 30, },
+ { /* sentinel */}
+};
+
+static void __init at91sam9x5_pmc_setup(struct device_node *np,
+ const struct pck *extra_pcks,
+ bool has_lcdck)
+{
+ struct clk_range range = CLK_RANGE(0, 0);
+ const char *slck_name, *mainxtal_name;
+ struct pmc_data *at91sam9x5_pmc;
+ const char *parent_names[6];
+ struct regmap *regmap;
+ struct clk_hw *hw;
+ int i;
+ bool bypass;
+
+ i = of_property_match_string(np, "clock-names", "slow_clk");
+ if (i < 0)
+ return;
+
+ slck_name = of_clk_get_parent_name(np, i);
+
+ i = of_property_match_string(np, "clock-names", "main_xtal");
+ if (i < 0)
+ return;
+ mainxtal_name = of_clk_get_parent_name(np, i);
+
+ regmap = syscon_node_to_regmap(np);
+ if (IS_ERR(regmap))
+ return;
+
+ at91sam9x5_pmc = pmc_data_allocate(PMC_MAIN + 1,
+ nck(at91sam9x5_systemck),
+ nck(at91sam9x35_periphck), 0);
+ if (!at91sam9x5_pmc)
+ return;
+
+ hw = at91_clk_register_main_rc_osc(regmap, "main_rc_osc", 12000000,
+ 50000000);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ bypass = of_property_read_bool(np, "atmel,osc-bypass");
+
+ hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name,
+ bypass);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ parent_names[0] = "main_rc_osc";
+ parent_names[1] = "main_osc";
+ hw = at91_clk_register_sam9x5_main(regmap, "mainck", parent_names, 2);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ at91sam9x5_pmc->chws[PMC_MAIN] = hw;
+
+ hw = at91_clk_register_pll(regmap, "pllack", "mainck", 0,
+ &at91rm9200_pll_layout, &plla_characteristics);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ hw = at91_clk_register_plldiv(regmap, "plladivck", "pllack");
+ if (IS_ERR(hw))
+ goto err_free;
+
+ hw = at91_clk_register_utmi(regmap, NULL, "utmick", "mainck");
+ if (IS_ERR(hw))
+ goto err_free;
+
+ at91sam9x5_pmc->chws[PMC_UTMI] = hw;
+
+ parent_names[0] = slck_name;
+ parent_names[1] = "mainck";
+ parent_names[2] = "plladivck";
+ parent_names[3] = "utmick";
+ hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
+ &at91sam9x5_master_layout,
+ &mck_characteristics);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ at91sam9x5_pmc->chws[PMC_MCK] = hw;
+
+ parent_names[0] = "plladivck";
+ parent_names[1] = "utmick";
+ hw = at91sam9x5_clk_register_usb(regmap, "usbck", parent_names, 2);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ hw = at91sam9x5_clk_register_smd(regmap, "smdclk", parent_names, 2);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ parent_names[0] = slck_name;
+ parent_names[1] = "mainck";
+ parent_names[2] = "plladivck";
+ parent_names[3] = "utmick";
+ parent_names[4] = "mck";
+ for (i = 0; i < 2; i++) {
+ char name[6];
+
+ snprintf(name, sizeof(name), "prog%d", i);
+
+ hw = at91_clk_register_programmable(regmap, name,
+ parent_names, 5, i,
+ &at91sam9x5_programmable_layout);
+ if (IS_ERR(hw))
+ goto err_free;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(at91sam9x5_systemck); i++) {
+ hw = at91_clk_register_system(regmap, at91sam9x5_systemck[i].n,
+ at91sam9x5_systemck[i].p,
+ at91sam9x5_systemck[i].id);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ at91sam9x5_pmc->shws[at91sam9x5_systemck[i].id] = hw;
+ }
+
+ if (has_lcdck) {
+ hw = at91_clk_register_system(regmap, "lcdck", "masterck", 3);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ at91sam9x5_pmc->shws[3] = hw;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(at91sam9x5_periphck); i++) {
+ hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
+ at91sam9x5_periphck[i].n,
+ "masterck",
+ at91sam9x5_periphck[i].id,
+ &range);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ at91sam9x5_pmc->phws[at91sam9x5_periphck[i].id] = hw;
+ }
+
+ for (i = 0; extra_pcks[i].id; i++) {
+ hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
+ extra_pcks[i].n,
+ "masterck",
+ extra_pcks[i].id,
+ &range);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ at91sam9x5_pmc->phws[extra_pcks[i].id] = hw;
+ }
+
+ of_clk_add_hw_provider(np, of_clk_hw_pmc_get, at91sam9x5_pmc);
+
+ return;
+
+err_free:
+ pmc_data_free(at91sam9x5_pmc);
+}
+
+static void __init at91sam9g15_pmc_setup(struct device_node *np)
+{
+ at91sam9x5_pmc_setup(np, at91sam9g15_periphck, true);
+}
+CLK_OF_DECLARE_DRIVER(at91sam9g15_pmc, "atmel,at91sam9g15-pmc",
+ at91sam9g15_pmc_setup);
+
+static void __init at91sam9g25_pmc_setup(struct device_node *np)
+{
+ at91sam9x5_pmc_setup(np, at91sam9g25_periphck, false);
+}
+CLK_OF_DECLARE_DRIVER(at91sam9g25_pmc, "atmel,at91sam9g25-pmc",
+ at91sam9g25_pmc_setup);
+
+static void __init at91sam9g35_pmc_setup(struct device_node *np)
+{
+ at91sam9x5_pmc_setup(np, at91sam9g35_periphck, true);
+}
+CLK_OF_DECLARE_DRIVER(at91sam9g35_pmc, "atmel,at91sam9g35-pmc",
+ at91sam9g35_pmc_setup);
+
+static void __init at91sam9x25_pmc_setup(struct device_node *np)
+{
+ at91sam9x5_pmc_setup(np, at91sam9x25_periphck, false);
+}
+CLK_OF_DECLARE_DRIVER(at91sam9x25_pmc, "atmel,at91sam9x25-pmc",
+ at91sam9x25_pmc_setup);
+
+static void __init at91sam9x35_pmc_setup(struct device_node *np)
+{
+ at91sam9x5_pmc_setup(np, at91sam9x35_periphck, true);
+}
+CLK_OF_DECLARE_DRIVER(at91sam9x35_pmc, "atmel,at91sam9x35-pmc",
+ at91sam9x35_pmc_setup);
diff --git a/drivers/clk/at91/clk-audio-pll.c b/drivers/clk/at91/clk-audio-pll.c
index da7bafcfbe70..36d77146a3bd 100644
--- a/drivers/clk/at91/clk-audio-pll.c
+++ b/drivers/clk/at91/clk-audio-pll.c
@@ -43,6 +43,8 @@
#include <linux/regmap.h>
#include <linux/slab.h>
+#include "pmc.h"
+
#define AUDIO_PLL_DIV_FRAC BIT(22)
#define AUDIO_PLL_ND_MAX (AT91_PMC_AUDIO_PLL_ND_MASK >> \
AT91_PMC_AUDIO_PLL_ND_OFFSET)
@@ -444,93 +446,94 @@ static const struct clk_ops audio_pll_pmc_ops = {
.set_rate = clk_audio_pll_pmc_set_rate,
};
-static int of_sama5d2_clk_audio_pll_setup(struct device_node *np,
- struct clk_init_data *init,
- struct clk_hw *hw,
- struct regmap **clk_audio_regmap)
-{
- struct regmap *regmap;
- const char *parent_names[1];
- int ret;
-
- regmap = syscon_node_to_regmap(of_get_parent(np));
- if (IS_ERR(regmap))
- return PTR_ERR(regmap);
-
- init->name = np->name;
- of_clk_parent_fill(np, parent_names, 1);
- init->parent_names = parent_names;
- init->num_parents = 1;
-
- hw->init = init;
- *clk_audio_regmap = regmap;
-
- ret = clk_hw_register(NULL, hw);
- if (ret)
- return ret;
-
- return of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
-}
-
-static void __init of_sama5d2_clk_audio_pll_frac_setup(struct device_node *np)
+struct clk_hw * __init
+at91_clk_register_audio_pll_frac(struct regmap *regmap, const char *name,
+ const char *parent_name)
{
struct clk_audio_frac *frac_ck;
struct clk_init_data init = {};
+ int ret;
frac_ck = kzalloc(sizeof(*frac_ck), GFP_KERNEL);
if (!frac_ck)
- return;
+ return ERR_PTR(-ENOMEM);
+ init.name = name;
init.ops = &audio_pll_frac_ops;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
init.flags = CLK_SET_RATE_GATE;
- if (of_sama5d2_clk_audio_pll_setup(np, &init, &frac_ck->hw,
- &frac_ck->regmap))
+ frac_ck->hw.init = &init;
+ frac_ck->regmap = regmap;
+
+ ret = clk_hw_register(NULL, &frac_ck->hw);
+ if (ret) {
kfree(frac_ck);
+ return ERR_PTR(ret);
+ }
+
+ return &frac_ck->hw;
}
-static void __init of_sama5d2_clk_audio_pll_pad_setup(struct device_node *np)
+struct clk_hw * __init
+at91_clk_register_audio_pll_pad(struct regmap *regmap, const char *name,
+ const char *parent_name)
{
struct clk_audio_pad *apad_ck;
- struct clk_init_data init = {};
+ struct clk_init_data init;
+ int ret;
apad_ck = kzalloc(sizeof(*apad_ck), GFP_KERNEL);
if (!apad_ck)
- return;
+ return ERR_PTR(-ENOMEM);
+ init.name = name;
init.ops = &audio_pll_pad_ops;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
CLK_SET_RATE_PARENT;
- if (of_sama5d2_clk_audio_pll_setup(np, &init, &apad_ck->hw,
- &apad_ck->regmap))
+ apad_ck->hw.init = &init;
+ apad_ck->regmap = regmap;
+
+ ret = clk_hw_register(NULL, &apad_ck->hw);
+ if (ret) {
kfree(apad_ck);
+ return ERR_PTR(ret);
+ }
+
+ return &apad_ck->hw;
}
-static void __init of_sama5d2_clk_audio_pll_pmc_setup(struct device_node *np)
+struct clk_hw * __init
+at91_clk_register_audio_pll_pmc(struct regmap *regmap, const char *name,
+ const char *parent_name)
{
- struct clk_audio_pad *apmc_ck;
- struct clk_init_data init = {};
+ struct clk_audio_pmc *apmc_ck;
+ struct clk_init_data init;
+ int ret;
apmc_ck = kzalloc(sizeof(*apmc_ck), GFP_KERNEL);
if (!apmc_ck)
- return;
+ return ERR_PTR(-ENOMEM);
+ init.name = name;
init.ops = &audio_pll_pmc_ops;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
CLK_SET_RATE_PARENT;
- if (of_sama5d2_clk_audio_pll_setup(np, &init, &apmc_ck->hw,
- &apmc_ck->regmap))
+ apmc_ck->hw.init = &init;
+ apmc_ck->regmap = regmap;
+
+ ret = clk_hw_register(NULL, &apmc_ck->hw);
+ if (ret) {
kfree(apmc_ck);
-}
+ return ERR_PTR(ret);
+ }
-CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_frac_setup,
- "atmel,sama5d2-clk-audio-pll-frac",
- of_sama5d2_clk_audio_pll_frac_setup);
-CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_pad_setup,
- "atmel,sama5d2-clk-audio-pll-pad",
- of_sama5d2_clk_audio_pll_pad_setup);
-CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_pmc_setup,
- "atmel,sama5d2-clk-audio-pll-pmc",
- of_sama5d2_clk_audio_pll_pmc_setup);
+ return &apmc_ck->hw;
+}
diff --git a/drivers/clk/at91/clk-generated.c b/drivers/clk/at91/clk-generated.c
index 33481368740e..66e7f7baf958 100644
--- a/drivers/clk/at91/clk-generated.c
+++ b/drivers/clk/at91/clk-generated.c
@@ -20,17 +20,8 @@
#include "pmc.h"
-#define PERIPHERAL_MAX 64
-#define PERIPHERAL_ID_MIN 2
-
-#define GENERATED_SOURCE_MAX 6
#define GENERATED_MAX_DIV 255
-#define GCK_ID_SSC0 43
-#define GCK_ID_SSC1 44
-#define GCK_ID_I2S0 54
-#define GCK_ID_I2S1 55
-#define GCK_ID_CLASSD 59
#define GCK_INDEX_DT_AUDIO_PLL 5
struct clk_generated {
@@ -279,10 +270,10 @@ static void clk_generated_startup(struct clk_generated *gck)
>> AT91_PMC_PCR_GCKDIV_OFFSET;
}
-static struct clk_hw * __init
+struct clk_hw * __init
at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock,
const char *name, const char **parent_names,
- u8 num_parents, u8 id,
+ u8 num_parents, u8 id, bool pll_audio,
const struct clk_range *range)
{
struct clk_generated *gck;
@@ -306,6 +297,7 @@ at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock,
gck->regmap = regmap;
gck->lock = lock;
gck->range = *range;
+ gck->audio_pll_allowed = pll_audio;
clk_generated_startup(gck);
hw = &gck->hw;
@@ -319,70 +311,3 @@ at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock,
return hw;
}
-
-static void __init of_sama5d2_clk_generated_setup(struct device_node *np)
-{
- int num;
- u32 id;
- const char *name;
- struct clk_hw *hw;
- unsigned int num_parents;
- const char *parent_names[GENERATED_SOURCE_MAX];
- struct device_node *gcknp;
- struct clk_range range = CLK_RANGE(0, 0);
- struct regmap *regmap;
- struct clk_generated *gck;
-
- num_parents = of_clk_get_parent_count(np);
- if (num_parents == 0 || num_parents > GENERATED_SOURCE_MAX)
- return;
-
- of_clk_parent_fill(np, parent_names, num_parents);
-
- num = of_get_child_count(np);
- if (!num || num > PERIPHERAL_MAX)
- return;
-
- regmap = syscon_node_to_regmap(of_get_parent(np));
- if (IS_ERR(regmap))
- return;
-
- for_each_child_of_node(np, gcknp) {
- if (of_property_read_u32(gcknp, "reg", &id))
- continue;
-
- if (id < PERIPHERAL_ID_MIN || id >= PERIPHERAL_MAX)
- continue;
-
- if (of_property_read_string(np, "clock-output-names", &name))
- name = gcknp->name;
-
- of_at91_get_clk_range(gcknp, "atmel,clk-output-range",
- &range);
-
- hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, name,
- parent_names, num_parents,
- id, &range);
-
- gck = to_clk_generated(hw);
-
- if (of_device_is_compatible(np,
- "atmel,sama5d2-clk-generated")) {
- if (gck->id == GCK_ID_SSC0 || gck->id == GCK_ID_SSC1 ||
- gck->id == GCK_ID_I2S0 || gck->id == GCK_ID_I2S1 ||
- gck->id == GCK_ID_CLASSD)
- gck->audio_pll_allowed = true;
- else
- gck->audio_pll_allowed = false;
- } else {
- gck->audio_pll_allowed = false;
- }
-
- if (IS_ERR(hw))
- continue;
-
- of_clk_add_hw_provider(gcknp, of_clk_hw_simple_get, hw);
- }
-}
-CLK_OF_DECLARE(of_sama5d2_clk_generated_setup, "atmel,sama5d2-clk-generated",
- of_sama5d2_clk_generated_setup);
diff --git a/drivers/clk/at91/clk-h32mx.c b/drivers/clk/at91/clk-h32mx.c
index e0daa4a31f88..f0a2c6baab37 100644
--- a/drivers/clk/at91/clk-h32mx.c
+++ b/drivers/clk/at91/clk-h32mx.c
@@ -86,25 +86,19 @@ static const struct clk_ops h32mx_ops = {
.set_rate = clk_sama5d4_h32mx_set_rate,
};
-static void __init of_sama5d4_clk_h32mx_setup(struct device_node *np)
+struct clk_hw * __init
+at91_clk_register_h32mx(struct regmap *regmap, const char *name,
+ const char *parent_name)
{
struct clk_sama5d4_h32mx *h32mxclk;
struct clk_init_data init;
- const char *parent_name;
- struct regmap *regmap;
int ret;
- regmap = syscon_node_to_regmap(of_get_parent(np));
- if (IS_ERR(regmap))
- return;
-
h32mxclk = kzalloc(sizeof(*h32mxclk), GFP_KERNEL);
if (!h32mxclk)
- return;
-
- parent_name = of_clk_get_parent_name(np, 0);
+ return ERR_PTR(-ENOMEM);
- init.name = np->name;
+ init.name = name;
init.ops = &h32mx_ops;
init.parent_names = parent_name ? &parent_name : NULL;
init.num_parents = parent_name ? 1 : 0;
@@ -116,10 +110,8 @@ static void __init of_sama5d4_clk_h32mx_setup(struct device_node *np)
ret = clk_hw_register(NULL, &h32mxclk->hw);
if (ret) {
kfree(h32mxclk);
- return;
+ return ERR_PTR(ret);
}
- of_clk_add_hw_provider(np, of_clk_hw_simple_get, &h32mxclk->hw);
+ return &h32mxclk->hw;
}
-CLK_OF_DECLARE(of_sama5d4_clk_h32mx_setup, "atmel,sama5d4-clk-h32mx",
- of_sama5d4_clk_h32mx_setup);
diff --git a/drivers/clk/at91/clk-i2s-mux.c b/drivers/clk/at91/clk-i2s-mux.c
index f0c3c3079f04..fe6ce172b8b0 100644
--- a/drivers/clk/at91/clk-i2s-mux.c
+++ b/drivers/clk/at91/clk-i2s-mux.c
@@ -14,7 +14,7 @@
#include <soc/at91/atmel-sfr.h>
-#define I2S_BUS_NR 2
+#include "pmc.h"
struct clk_i2s_mux {
struct clk_hw hw;
@@ -48,7 +48,7 @@ static const struct clk_ops clk_i2s_mux_ops = {
.determine_rate = __clk_mux_determine_rate,
};
-static struct clk_hw * __init
+struct clk_hw * __init
at91_clk_i2s_mux_register(struct regmap *regmap, const char *name,
const char * const *parent_names,
unsigned int num_parents, u8 bus_id)
@@ -78,39 +78,3 @@ at91_clk_i2s_mux_register(struct regmap *regmap, const char *name,
return &i2s_ck->hw;
}
-
-static void __init of_sama5d2_clk_i2s_mux_setup(struct device_node *np)
-{
- struct regmap *regmap_sfr;
- u8 bus_id;
- const char *parent_names[2];
- struct device_node *i2s_mux_np;
- struct clk_hw *hw;
- int ret;
-
- regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr");
- if (IS_ERR(regmap_sfr))
- return;
-
- for_each_child_of_node(np, i2s_mux_np) {
- if (of_property_read_u8(i2s_mux_np, "reg", &bus_id))
- continue;
-
- if (bus_id > I2S_BUS_NR)
- continue;
-
- ret = of_clk_parent_fill(i2s_mux_np, parent_names, 2);
- if (ret != 2)
- continue;
-
- hw = at91_clk_i2s_mux_register(regmap_sfr, i2s_mux_np->name,
- parent_names, 2, bus_id);
- if (IS_ERR(hw))
- continue;
-
- of_clk_add_hw_provider(i2s_mux_np, of_clk_hw_simple_get, hw);
- }
-}
-
-CLK_OF_DECLARE(sama5d2_clk_i2s_mux, "atmel,sama5d2-clk-i2s-mux",
- of_sama5d2_clk_i2s_mux_setup);
diff --git a/drivers/clk/at91/clk-main.c b/drivers/clk/at91/clk-main.c
index c813c27f2e58..7ac0facdb28b 100644
--- a/drivers/clk/at91/clk-main.c
+++ b/drivers/clk/at91/clk-main.c
@@ -12,7 +12,6 @@
#include <linux/clkdev.h>
#include <linux/clk/at91_pmc.h>
#include <linux/delay.h>
-#include <linux/of.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
@@ -128,7 +127,7 @@ static const struct clk_ops main_osc_ops = {
.is_prepared = clk_main_osc_is_prepared,
};
-static struct clk_hw * __init
+struct clk_hw * __init
at91_clk_register_main_osc(struct regmap *regmap,
const char *name,
const char *parent_name,
@@ -171,31 +170,6 @@ at91_clk_register_main_osc(struct regmap *regmap,
return hw;
}
-static void __init of_at91rm9200_clk_main_osc_setup(struct device_node *np)
-{
- struct clk_hw *hw;
- const char *name = np->name;
- const char *parent_name;
- struct regmap *regmap;
- bool bypass;
-
- of_property_read_string(np, "clock-output-names", &name);
- bypass = of_property_read_bool(np, "atmel,osc-bypass");
- parent_name = of_clk_get_parent_name(np, 0);
-
- regmap = syscon_node_to_regmap(of_get_parent(np));
- if (IS_ERR(regmap))
- return;
-
- hw = at91_clk_register_main_osc(regmap, name, parent_name, bypass);
- if (IS_ERR(hw))
- return;
-
- of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
-}
-CLK_OF_DECLARE(at91rm9200_clk_main_osc, "atmel,at91rm9200-clk-main-osc",
- of_at91rm9200_clk_main_osc_setup);
-
static bool clk_main_rc_osc_ready(struct regmap *regmap)
{
unsigned int status;
@@ -275,7 +249,7 @@ static const struct clk_ops main_rc_osc_ops = {
.recalc_accuracy = clk_main_rc_osc_recalc_accuracy,
};
-static struct clk_hw * __init
+struct clk_hw * __init
at91_clk_register_main_rc_osc(struct regmap *regmap,
const char *name,
u32 frequency, u32 accuracy)
@@ -313,32 +287,6 @@ at91_clk_register_main_rc_osc(struct regmap *regmap,
return hw;
}
-static void __init of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np)
-{
- struct clk_hw *hw;
- u32 frequency = 0;
- u32 accuracy = 0;
- const char *name = np->name;
- struct regmap *regmap;
-
- of_property_read_string(np, "clock-output-names", &name);
- of_property_read_u32(np, "clock-frequency", &frequency);
- of_property_read_u32(np, "clock-accuracy", &accuracy);
-
- regmap = syscon_node_to_regmap(of_get_parent(np));
- if (IS_ERR(regmap))
- return;
-
- hw = at91_clk_register_main_rc_osc(regmap, name, frequency, accuracy);
- if (IS_ERR(hw))
- return;
-
- of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
-}
-CLK_OF_DECLARE(at91sam9x5_clk_main_rc_osc, "atmel,at91sam9x5-clk-main-rc-osc",
- of_at91sam9x5_clk_main_rc_osc_setup);
-
-
static int clk_main_probe_frequency(struct regmap *regmap)
{
unsigned long prep_time, timeout;
@@ -403,7 +351,7 @@ static const struct clk_ops rm9200_main_ops = {
.recalc_rate = clk_rm9200_main_recalc_rate,
};
-static struct clk_hw * __init
+struct clk_hw * __init
at91_clk_register_rm9200_main(struct regmap *regmap,
const char *name,
const char *parent_name)
@@ -442,29 +390,6 @@ at91_clk_register_rm9200_main(struct regmap *regmap,
return hw;
}
-static void __init of_at91rm9200_clk_main_setup(struct device_node *np)
-{
- struct clk_hw *hw;
- const char *parent_name;
- const char *name = np->name;
- struct regmap *regmap;
-
- parent_name = of_clk_get_parent_name(np, 0);
- of_property_read_string(np, "clock-output-names", &name);
-
- regmap = syscon_node_to_regmap(of_get_parent(np));
- if (IS_ERR(regmap))
- return;
-
- hw = at91_clk_register_rm9200_main(regmap, name, parent_name);
- if (IS_ERR(hw))
- return;
-
- of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
-}
-CLK_OF_DECLARE(at91rm9200_clk_main, "atmel,at91rm9200-clk-main",
- of_at91rm9200_clk_main_setup);
-
static inline bool clk_sam9x5_main_ready(struct regmap *regmap)
{
unsigned int status;
@@ -541,7 +466,7 @@ static const struct clk_ops sam9x5_main_ops = {
.get_parent = clk_sam9x5_main_get_parent,
};
-static struct clk_hw * __init
+struct clk_hw * __init
at91_clk_register_sam9x5_main(struct regmap *regmap,
const char *name,
const char **parent_names,
@@ -583,32 +508,3 @@ at91_clk_register_sam9x5_main(struct regmap *regmap,
return hw;
}
-
-static void __init of_at91sam9x5_clk_main_setup(struct device_node *np)
-{
- struct clk_hw *hw;
- const char *parent_names[2];
- unsigned int num_parents;
- const char *name = np->name;
- struct regmap *regmap;
-
- num_parents = of_clk_get_parent_count(np);
- if (num_parents == 0 || num_parents > 2)
- return;
-
- of_clk_parent_fill(np, parent_names, num_parents);
- regmap = syscon_node_to_regmap(of_get_parent(np));
- if (IS_ERR(regmap))
- return;
-
- of_property_read_string(np, "clock-output-names", &name);
-
- hw = at91_clk_register_sam9x5_main(regmap, name, parent_names,
- num_parents);
- if (IS_ERR(hw))
- return;
-
- of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
-}
-CLK_OF_DECLARE(at91sam9x5_clk_main, "atmel,at91sam9x5-clk-main",
- of_at91sam9x5_clk_main_setup);
diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c
index e9cba9fc26d7..eb53b4a8fab6 100644
--- a/drivers/clk/at91/clk-master.c
+++ b/drivers/clk/at91/clk-master.c
@@ -17,24 +17,11 @@
#include "pmc.h"
-#define MASTER_SOURCE_MAX 4
-
#define MASTER_PRES_MASK 0x7
#define MASTER_PRES_MAX MASTER_PRES_MASK
#define MASTER_DIV_SHIFT 8
#define MASTER_DIV_MASK 0x3
-struct clk_master_characteristics {
- struct clk_range output;
- u32 divisors[4];
- u8 have_div3_pres;
-};
-
-struct clk_master_layout {
- u32 mask;
- u8 pres_shift;
-};
-
#define to_clk_master(hw) container_of(hw, struct clk_master, hw)
struct clk_master {
@@ -120,7 +107,7 @@ static const struct clk_ops master_ops = {
.get_parent = clk_master_get_parent,
};
-static struct clk_hw * __init
+struct clk_hw * __init
at91_clk_register_master(struct regmap *regmap,
const char *name, int num_parents,
const char **parent_names,
@@ -161,92 +148,12 @@ at91_clk_register_master(struct regmap *regmap,
}
-static const struct clk_master_layout at91rm9200_master_layout = {
+const struct clk_master_layout at91rm9200_master_layout = {
.mask = 0x31F,
.pres_shift = 2,
};
-static const struct clk_master_layout at91sam9x5_master_layout = {
+const struct clk_master_layout at91sam9x5_master_layout = {
.mask = 0x373,
.pres_shift = 4,
};
-
-
-static struct clk_master_characteristics * __init
-of_at91_clk_master_get_characteristics(struct device_node *np)
-{
- struct clk_master_characteristics *characteristics;
-
- characteristics = kzalloc(sizeof(*characteristics), GFP_KERNEL);
- if (!characteristics)
- return NULL;
-
- if (of_at91_get_clk_range(np, "atmel,clk-output-range", &characteristics->output))
- goto out_free_characteristics;
-
- of_property_read_u32_array(np, "atmel,clk-divisors",
- characteristics->divisors, 4);
-
- characteristics->have_div3_pres =
- of_property_read_bool(np, "atmel,master-clk-have-div3-pres");
-
- return characteristics;
-
-out_free_characteristics:
- kfree(characteristics);
- return NULL;
-}
-
-static void __init
-of_at91_clk_master_setup(struct device_node *np,
- const struct clk_master_layout *layout)
-{
- struct clk_hw *hw;
- unsigned int num_parents;
- const char *parent_names[MASTER_SOURCE_MAX];
- const char *name = np->name;
- struct clk_master_characteristics *characteristics;
- struct regmap *regmap;
-
- num_parents = of_clk_get_parent_count(np);
- if (num_parents == 0 || num_parents > MASTER_SOURCE_MAX)
- return;
-
- of_clk_parent_fill(np, parent_names, num_parents);
-
- of_property_read_string(np, "clock-output-names", &name);
-
- characteristics = of_at91_clk_master_get_characteristics(np);
- if (!characteristics)
- return;
-
- regmap = syscon_node_to_regmap(of_get_parent(np));
- if (IS_ERR(regmap))
- return;
-
- hw = at91_clk_register_master(regmap, name, num_parents,
- parent_names, layout,
- characteristics);
- if (IS_ERR(hw))
- goto out_free_characteristics;
-
- of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
- return;
-
-out_free_characteristics:
- kfree(characteristics);
-}
-
-static void __init of_at91rm9200_clk_master_setup(struct device_node *np)
-{
- of_at91_clk_master_setup(np, &at91rm9200_master_layout);
-}
-CLK_OF_DECLARE(at91rm9200_clk_master, "atmel,at91rm9200-clk-master",
- of_at91rm9200_clk_master_setup);
-
-static void __init of_at91sam9x5_clk_master_setup(struct device_node *np)
-{
- of_at91_clk_master_setup(np, &at91sam9x5_master_layout);
-}
-CLK_OF_DECLARE(at91sam9x5_clk_master, "atmel,at91sam9x5-clk-master",
- of_at91sam9x5_clk_master_setup);
diff --git a/drivers/clk/at91/clk-peripheral.c b/drivers/clk/at91/clk-peripheral.c
index 770118369230..65c1defa78e4 100644
--- a/drivers/clk/at91/clk-peripheral.c
+++ b/drivers/clk/at91/clk-peripheral.c
@@ -19,11 +19,6 @@
DEFINE_SPINLOCK(pmc_pcr_lock);
-#define PERIPHERAL_MAX 64
-
-#define PERIPHERAL_AT91RM9200 0
-#define PERIPHERAL_AT91SAM9X5 1
-
#define PERIPHERAL_ID_MIN 2
#define PERIPHERAL_ID_MAX 31
#define PERIPHERAL_MASK(id) (1 << ((id) & PERIPHERAL_ID_MAX))
@@ -104,7 +99,7 @@ static const struct clk_ops peripheral_ops = {
.is_enabled = clk_peripheral_is_enabled,
};
-static struct clk_hw * __init
+struct clk_hw * __init
at91_clk_register_peripheral(struct regmap *regmap, const char *name,
const char *parent_name, u32 id)
{
@@ -331,7 +326,7 @@ static const struct clk_ops sam9x5_peripheral_ops = {
.set_rate = clk_sam9x5_peripheral_set_rate,
};
-static struct clk_hw * __init
+struct clk_hw * __init
at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
const char *name, const char *parent_name,
u32 id, const struct clk_range *range)
@@ -374,75 +369,3 @@ at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
return hw;
}
-
-static void __init
-of_at91_clk_periph_setup(struct device_node *np, u8 type)
-{
- int num;
- u32 id;
- struct clk_hw *hw;
- const char *parent_name;
- const char *name;
- struct device_node *periphclknp;
- struct regmap *regmap;
-
- parent_name = of_clk_get_parent_name(np, 0);
- if (!parent_name)
- return;
-
- num = of_get_child_count(np);
- if (!num || num > PERIPHERAL_MAX)
- return;
-
- regmap = syscon_node_to_regmap(of_get_parent(np));
- if (IS_ERR(regmap))
- return;
-
- for_each_child_of_node(np, periphclknp) {
- if (of_property_read_u32(periphclknp, "reg", &id))
- continue;
-
- if (id >= PERIPHERAL_MAX)
- continue;
-
- if (of_property_read_string(np, "clock-output-names", &name))
- name = periphclknp->name;
-
- if (type == PERIPHERAL_AT91RM9200) {
- hw = at91_clk_register_peripheral(regmap, name,
- parent_name, id);
- } else {
- struct clk_range range = CLK_RANGE(0, 0);
-
- of_at91_get_clk_range(periphclknp,
- "atmel,clk-output-range",
- &range);
-
- hw = at91_clk_register_sam9x5_peripheral(regmap,
- &pmc_pcr_lock,
- name,
- parent_name,
- id, &range);
- }
-
- if (IS_ERR(hw))
- continue;
-
- of_clk_add_hw_provider(periphclknp, of_clk_hw_simple_get, hw);
- }
-}
-
-static void __init of_at91rm9200_clk_periph_setup(struct device_node *np)
-{
- of_at91_clk_periph_setup(np, PERIPHERAL_AT91RM9200);
-}
-CLK_OF_DECLARE(at91rm9200_clk_periph, "atmel,at91rm9200-clk-peripheral",
- of_at91rm9200_clk_periph_setup);
-
-static void __init of_at91sam9x5_clk_periph_setup(struct device_node *np)
-{
- of_at91_clk_periph_setup(np, PERIPHERAL_AT91SAM9X5);
-}
-CLK_OF_DECLARE(at91sam9x5_clk_periph, "atmel,at91sam9x5-clk-peripheral",
- of_at91sam9x5_clk_periph_setup);
-
diff --git a/drivers/clk/at91/clk-pll.c b/drivers/clk/at91/clk-pll.c
index 72b6091eb7b9..b4138fcacf49 100644
--- a/drivers/clk/at91/clk-pll.c
+++ b/drivers/clk/at91/clk-pll.c
@@ -34,20 +34,6 @@
#define PLL_OUT_SHIFT 14
#define PLL_MAX_ID 1
-struct clk_pll_characteristics {
- struct clk_range input;
- int num_output;
- struct clk_range *output;
- u16 *icpll;
- u8 *out;
-};
-
-struct clk_pll_layout {
- u32 pllr_mask;
- u16 mul_mask;
- u8 mul_shift;
-};
-
#define to_clk_pll(hw) container_of(hw, struct clk_pll, hw)
struct clk_pll {
@@ -133,6 +119,9 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
{
struct clk_pll *pll = to_clk_pll(hw);
+ if (!pll->div || !pll->mul)
+ return 0;
+
return (parent_rate / pll->div) * (pll->mul + 1);
}
@@ -285,7 +274,7 @@ static const struct clk_ops pll_ops = {
.set_rate = clk_pll_set_rate,
};
-static struct clk_hw * __init
+struct clk_hw * __init
at91_clk_register_pll(struct regmap *regmap, const char *name,
const char *parent_name, u8 id,
const struct clk_pll_layout *layout,
@@ -331,189 +320,26 @@ at91_clk_register_pll(struct regmap *regmap, const char *name,
}
-static const struct clk_pll_layout at91rm9200_pll_layout = {
+const struct clk_pll_layout at91rm9200_pll_layout = {
.pllr_mask = 0x7FFFFFF,
.mul_shift = 16,
.mul_mask = 0x7FF,
};
-static const struct clk_pll_layout at91sam9g45_pll_layout = {
+const struct clk_pll_layout at91sam9g45_pll_layout = {
.pllr_mask = 0xFFFFFF,
.mul_shift = 16,
.mul_mask = 0xFF,
};
-static const struct clk_pll_layout at91sam9g20_pllb_layout = {
+const struct clk_pll_layout at91sam9g20_pllb_layout = {
.pllr_mask = 0x3FFFFF,
.mul_shift = 16,
.mul_mask = 0x3F,
};
-static const struct clk_pll_layout sama5d3_pll_layout = {
+const struct clk_pll_layout sama5d3_pll_layout = {
.pllr_mask = 0x1FFFFFF,
.mul_shift = 18,
.mul_mask = 0x7F,
};
-
-
-static struct clk_pll_characteristics * __init
-of_at91_clk_pll_get_characteristics(struct device_node *np)
-{
- int i;
- int offset;
- u32 tmp;
- int num_output;
- u32 num_cells;
- struct clk_range input;
- struct clk_range *output;
- u8 *out = NULL;
- u16 *icpll = NULL;
- struct clk_pll_characteristics *characteristics;
-
- if (of_at91_get_clk_range(np, "atmel,clk-input-range", &input))
- return NULL;
-
- if (of_property_read_u32(np, "#atmel,pll-clk-output-range-cells",
- &num_cells))
- return NULL;
-
- if (num_cells < 2 || num_cells > 4)
- return NULL;
-
- if (!of_get_property(np, "atmel,pll-clk-output-ranges", &tmp))
- return NULL;
- num_output = tmp / (sizeof(u32) * num_cells);
-
- characteristics = kzalloc(sizeof(*characteristics), GFP_KERNEL);
- if (!characteristics)
- return NULL;
-
- output = kcalloc(num_output, sizeof(*output), GFP_KERNEL);
- if (!output)
- goto out_free_characteristics;
-
- if (num_cells > 2) {
- out = kcalloc(num_output, sizeof(*out), GFP_KERNEL);
- if (!out)
- goto out_free_output;
- }
-
- if (num_cells > 3) {
- icpll = kcalloc(num_output, sizeof(*icpll), GFP_KERNEL);
- if (!icpll)
- goto out_free_output;
- }
-
- for (i = 0; i < num_output; i++) {
- offset = i * num_cells;
- if (of_property_read_u32_index(np,
- "atmel,pll-clk-output-ranges",
- offset, &tmp))
- goto out_free_output;
- output[i].min = tmp;
- if (of_property_read_u32_index(np,
- "atmel,pll-clk-output-ranges",
- offset + 1, &tmp))
- goto out_free_output;
- output[i].max = tmp;
-
- if (num_cells == 2)
- continue;
-
- if (of_property_read_u32_index(np,
- "atmel,pll-clk-output-ranges",
- offset + 2, &tmp))
- goto out_free_output;
- out[i] = tmp;
-
- if (num_cells == 3)
- continue;
-
- if (of_property_read_u32_index(np,
- "atmel,pll-clk-output-ranges",
- offset + 3, &tmp))
- goto out_free_output;
- icpll[i] = tmp;
- }
-
- characteristics->input = input;
- characteristics->num_output = num_output;
- characteristics->output = output;
- characteristics->out = out;
- characteristics->icpll = icpll;
- return characteristics;
-
-out_free_output:
- kfree(icpll);
- kfree(out);
- kfree(output);
-out_free_characteristics:
- kfree(characteristics);
- return NULL;
-}
-
-static void __init
-of_at91_clk_pll_setup(struct device_node *np,
- const struct clk_pll_layout *layout)
-{
- u32 id;
- struct clk_hw *hw;
- struct regmap *regmap;
- const char *parent_name;
- const char *name = np->name;
- struct clk_pll_characteristics *characteristics;
-
- if (of_property_read_u32(np, "reg", &id))
- return;
-
- parent_name = of_clk_get_parent_name(np, 0);
-
- of_property_read_string(np, "clock-output-names", &name);
-
- regmap = syscon_node_to_regmap(of_get_parent(np));
- if (IS_ERR(regmap))
- return;
-
- characteristics = of_at91_clk_pll_get_characteristics(np);
- if (!characteristics)
- return;
-
- hw = at91_clk_register_pll(regmap, name, parent_name, id, layout,
- characteristics);
- if (IS_ERR(hw))
- goto out_free_characteristics;
-
- of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
- return;
-
-out_free_characteristics:
- kfree(characteristics);
-}
-
-static void __init of_at91rm9200_clk_pll_setup(struct device_node *np)
-{
- of_at91_clk_pll_setup(np, &at91rm9200_pll_layout);
-}
-CLK_OF_DECLARE(at91rm9200_clk_pll, "atmel,at91rm9200-clk-pll",
- of_at91rm9200_clk_pll_setup);
-
-static void __init of_at91sam9g45_clk_pll_setup(struct device_node *np)
-{
- of_at91_clk_pll_setup(np, &at91sam9g45_pll_layout);
-}
-CLK_OF_DECLARE(at91sam9g45_clk_pll, "atmel,at91sam9g45-clk-pll",
- of_at91sam9g45_clk_pll_setup);
-
-static void __init of_at91sam9g20_clk_pllb_setup(struct device_node *np)
-{
- of_at91_clk_pll_setup(np, &at91sam9g20_pllb_layout);
-}
-CLK_OF_DECLARE(at91sam9g20_clk_pllb, "atmel,at91sam9g20-clk-pllb",
- of_at91sam9g20_clk_pllb_setup);
-
-static void __init of_sama5d3_clk_pll_setup(struct device_node *np)
-{
- of_at91_clk_pll_setup(np, &sama5d3_pll_layout);
-}
-CLK_OF_DECLARE(sama5d3_clk_pll, "atmel,sama5d3-clk-pll",
- of_sama5d3_clk_pll_setup);
diff --git a/drivers/clk/at91/clk-plldiv.c b/drivers/clk/at91/clk-plldiv.c
index b4afaf22f3fd..e8c4f8b02f28 100644
--- a/drivers/clk/at91/clk-plldiv.c
+++ b/drivers/clk/at91/clk-plldiv.c
@@ -75,7 +75,7 @@ static const struct clk_ops plldiv_ops = {
.set_rate = clk_plldiv_set_rate,
};
-static struct clk_hw * __init
+struct clk_hw * __init
at91_clk_register_plldiv(struct regmap *regmap, const char *name,
const char *parent_name)
{
@@ -106,28 +106,3 @@ at91_clk_register_plldiv(struct regmap *regmap, const char *name,
return hw;
}
-
-static void __init
-of_at91sam9x5_clk_plldiv_setup(struct device_node *np)
-{
- struct clk_hw *hw;
- const char *parent_name;
- const char *name = np->name;
- struct regmap *regmap;
-
- parent_name = of_clk_get_parent_name(np, 0);
-
- of_property_read_string(np, "clock-output-names", &name);
-
- regmap = syscon_node_to_regmap(of_get_parent(np));
- if (IS_ERR(regmap))
- return;
-
- hw = at91_clk_register_plldiv(regmap, name, parent_name);
- if (IS_ERR(hw))
- return;
-
- of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
-}
-CLK_OF_DECLARE(at91sam9x5_clk_plldiv, "atmel,at91sam9x5-clk-plldiv",
- of_at91sam9x5_clk_plldiv_setup);
diff --git a/drivers/clk/at91/clk-programmable.c b/drivers/clk/at91/clk-programmable.c
index 0e6aab1252fc..5bc68b9c5498 100644
--- a/drivers/clk/at91/clk-programmable.c
+++ b/drivers/clk/at91/clk-programmable.c
@@ -17,7 +17,6 @@
#include "pmc.h"
-#define PROG_SOURCE_MAX 5
#define PROG_ID_MAX 7
#define PROG_STATUS_MASK(id) (1 << ((id) + 8))
@@ -25,12 +24,6 @@
#define PROG_PRES(layout, pckr) ((pckr >> layout->pres_shift) & PROG_PRES_MASK)
#define PROG_MAX_RM9200_CSS 3
-struct clk_programmable_layout {
- u8 pres_shift;
- u8 css_mask;
- u8 have_slck_mck;
-};
-
struct clk_programmable {
struct clk_hw hw;
struct regmap *regmap;
@@ -170,7 +163,7 @@ static const struct clk_ops programmable_ops = {
.set_rate = clk_programmable_set_rate,
};
-static struct clk_hw * __init
+struct clk_hw * __init
at91_clk_register_programmable(struct regmap *regmap,
const char *name, const char **parent_names,
u8 num_parents, u8 id,
@@ -211,86 +204,20 @@ at91_clk_register_programmable(struct regmap *regmap,
return hw;
}
-static const struct clk_programmable_layout at91rm9200_programmable_layout = {
+const struct clk_programmable_layout at91rm9200_programmable_layout = {
.pres_shift = 2,
.css_mask = 0x3,
.have_slck_mck = 0,
};
-static const struct clk_programmable_layout at91sam9g45_programmable_layout = {
+const struct clk_programmable_layout at91sam9g45_programmable_layout = {
.pres_shift = 2,
.css_mask = 0x3,
.have_slck_mck = 1,
};
-static const struct clk_programmable_layout at91sam9x5_programmable_layout = {
+const struct clk_programmable_layout at91sam9x5_programmable_layout = {
.pres_shift = 4,
.css_mask = 0x7,
.have_slck_mck = 0,
};
-
-static void __init
-of_at91_clk_prog_setup(struct device_node *np,
- const struct clk_programmable_layout *layout)
-{
- int num;
- u32 id;
- struct clk_hw *hw;
- unsigned int num_parents;
- const char *parent_names[PROG_SOURCE_MAX];
- const char *name;
- struct device_node *progclknp;
- struct regmap *regmap;
-
- num_parents = of_clk_get_parent_count(np);
- if (num_parents == 0 || num_parents > PROG_SOURCE_MAX)
- return;
-
- of_clk_parent_fill(np, parent_names, num_parents);
-
- num = of_get_child_count(np);
- if (!num || num > (PROG_ID_MAX + 1))
- return;
-
- regmap = syscon_node_to_regmap(of_get_parent(np));
- if (IS_ERR(regmap))
- return;
-
- for_each_child_of_node(np, progclknp) {
- if (of_property_read_u32(progclknp, "reg", &id))
- continue;
-
- if (of_property_read_string(np, "clock-output-names", &name))
- name = progclknp->name;
-
- hw = at91_clk_register_programmable(regmap, name,
- parent_names, num_parents,
- id, layout);
- if (IS_ERR(hw))
- continue;
-
- of_clk_add_hw_provider(progclknp, of_clk_hw_simple_get, hw);
- }
-}
-
-
-static void __init of_at91rm9200_clk_prog_setup(struct device_node *np)
-{
- of_at91_clk_prog_setup(np, &at91rm9200_programmable_layout);
-}
-CLK_OF_DECLARE(at91rm9200_clk_prog, "atmel,at91rm9200-clk-programmable",
- of_at91rm9200_clk_prog_setup);
-
-static void __init of_at91sam9g45_clk_prog_setup(struct device_node *np)
-{
- of_at91_clk_prog_setup(np, &at91sam9g45_programmable_layout);
-}
-CLK_OF_DECLARE(at91sam9g45_clk_prog, "atmel,at91sam9g45-clk-programmable",
- of_at91sam9g45_clk_prog_setup);
-
-static void __init of_at91sam9x5_clk_prog_setup(struct device_node *np)
-{
- of_at91_clk_prog_setup(np, &at91sam9x5_programmable_layout);
-}
-CLK_OF_DECLARE(at91sam9x5_clk_prog, "atmel,at91sam9x5-clk-programmable",
- of_at91sam9x5_clk_prog_setup);
diff --git a/drivers/clk/at91/clk-slow.c b/drivers/clk/at91/clk-slow.c
index 560a8b9abf93..cbb146912f7a 100644
--- a/drivers/clk/at91/clk-slow.c
+++ b/drivers/clk/at91/clk-slow.c
@@ -40,7 +40,7 @@ static const struct clk_ops sam9260_slow_ops = {
.get_parent = clk_sam9260_slow_get_parent,
};
-static struct clk_hw * __init
+struct clk_hw * __init
at91_clk_register_sam9260_slow(struct regmap *regmap,
const char *name,
const char **parent_names,
@@ -79,33 +79,3 @@ at91_clk_register_sam9260_slow(struct regmap *regmap,
return hw;
}
-
-static void __init of_at91sam9260_clk_slow_setup(struct device_node *np)
-{
- struct clk_hw *hw;
- const char *parent_names[2];
- unsigned int num_parents;
- const char *name = np->name;
- struct regmap *regmap;
-
- num_parents = of_clk_get_parent_count(np);
- if (num_parents != 2)
- return;
-
- of_clk_parent_fill(np, parent_names, num_parents);
- regmap = syscon_node_to_regmap(of_get_parent(np));
- if (IS_ERR(regmap))
- return;
-
- of_property_read_string(np, "clock-output-names", &name);
-
- hw = at91_clk_register_sam9260_slow(regmap, name, parent_names,
- num_parents);
- if (IS_ERR(hw))
- return;
-
- of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
-}
-
-CLK_OF_DECLARE(at91sam9260_clk_slow, "atmel,at91sam9260-clk-slow",
- of_at91sam9260_clk_slow_setup);
diff --git a/drivers/clk/at91/clk-smd.c b/drivers/clk/at91/clk-smd.c
index 965c662b90a5..75679fd8a9c7 100644
--- a/drivers/clk/at91/clk-smd.c
+++ b/drivers/clk/at91/clk-smd.c
@@ -17,8 +17,6 @@
#include "pmc.h"
-#define SMD_SOURCE_MAX 2
-
#define SMD_DIV_SHIFT 8
#define SMD_MAX_DIV 0xf
@@ -111,7 +109,7 @@ static const struct clk_ops at91sam9x5_smd_ops = {
.set_rate = at91sam9x5_clk_smd_set_rate,
};
-static struct clk_hw * __init
+struct clk_hw * __init
at91sam9x5_clk_register_smd(struct regmap *regmap, const char *name,
const char **parent_names, u8 num_parents)
{
@@ -142,33 +140,3 @@ at91sam9x5_clk_register_smd(struct regmap *regmap, const char *name,
return hw;
}
-
-static void __init of_at91sam9x5_clk_smd_setup(struct device_node *np)
-{
- struct clk_hw *hw;
- unsigned int num_parents;
- const char *parent_names[SMD_SOURCE_MAX];
- const char *name = np->name;
- struct regmap *regmap;
-
- num_parents = of_clk_get_parent_count(np);
- if (num_parents == 0 || num_parents > SMD_SOURCE_MAX)
- return;
-
- of_clk_parent_fill(np, parent_names, num_parents);
-
- of_property_read_string(np, "clock-output-names", &name);
-
- regmap = syscon_node_to_regmap(of_get_parent(np));
- if (IS_ERR(regmap))
- return;
-
- hw = at91sam9x5_clk_register_smd(regmap, name, parent_names,
- num_parents);
- if (IS_ERR(hw))
- return;
-
- of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
-}
-CLK_OF_DECLARE(at91sam9x5_clk_smd, "atmel,at91sam9x5-clk-smd",
- of_at91sam9x5_clk_smd_setup);
diff --git a/drivers/clk/at91/clk-system.c b/drivers/clk/at91/clk-system.c
index 86a36809765d..47bfca933403 100644
--- a/drivers/clk/at91/clk-system.c
+++ b/drivers/clk/at91/clk-system.c
@@ -88,7 +88,7 @@ static const struct clk_ops system_ops = {
.is_prepared = clk_system_is_prepared,
};
-static struct clk_hw * __init
+struct clk_hw * __init
at91_clk_register_system(struct regmap *regmap, const char *name,
const char *parent_name, u8 id)
{
@@ -123,40 +123,3 @@ at91_clk_register_system(struct regmap *regmap, const char *name,
return hw;
}
-
-static void __init of_at91rm9200_clk_sys_setup(struct device_node *np)
-{
- int num;
- u32 id;
- struct clk_hw *hw;
- const char *name;
- struct device_node *sysclknp;
- const char *parent_name;
- struct regmap *regmap;
-
- num = of_get_child_count(np);
- if (num > (SYSTEM_MAX_ID + 1))
- return;
-
- regmap = syscon_node_to_regmap(of_get_parent(np));
- if (IS_ERR(regmap))
- return;
-
- for_each_child_of_node(np, sysclknp) {
- if (of_property_read_u32(sysclknp, "reg", &id))
- continue;
-
- if (of_property_read_string(np, "clock-output-names", &name))
- name = sysclknp->name;
-
- parent_name = of_clk_get_parent_name(sysclknp, 0);
-
- hw = at91_clk_register_system(regmap, name, parent_name, id);
- if (IS_ERR(hw))
- continue;
-
- of_clk_add_hw_provider(sysclknp, of_clk_hw_simple_get, hw);
- }
-}
-CLK_OF_DECLARE(at91rm9200_clk_sys, "atmel,at91rm9200-clk-system",
- of_at91rm9200_clk_sys_setup);
diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c
index 791770a563fc..79ee1c760f2a 100644
--- a/drivers/clk/at91/clk-usb.c
+++ b/drivers/clk/at91/clk-usb.c
@@ -17,8 +17,6 @@
#include "pmc.h"
-#define USB_SOURCE_MAX 2
-
#define SAM9X5_USB_DIV_SHIFT 8
#define SAM9X5_USB_MAX_DIV 0xf
@@ -192,7 +190,7 @@ static const struct clk_ops at91sam9n12_usb_ops = {
.set_rate = at91sam9x5_clk_usb_set_rate,
};
-static struct clk_hw * __init
+struct clk_hw * __init
at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name,
const char **parent_names, u8 num_parents)
{
@@ -225,7 +223,7 @@ at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name,
return hw;
}
-static struct clk_hw * __init
+struct clk_hw * __init
at91sam9n12_clk_register_usb(struct regmap *regmap, const char *name,
const char *parent_name)
{
@@ -342,7 +340,7 @@ static const struct clk_ops at91rm9200_usb_ops = {
.set_rate = at91rm9200_clk_usb_set_rate,
};
-static struct clk_hw * __init
+struct clk_hw * __init
at91rm9200_clk_register_usb(struct regmap *regmap, const char *name,
const char *parent_name, const u32 *divisors)
{
@@ -374,89 +372,3 @@ at91rm9200_clk_register_usb(struct regmap *regmap, const char *name,
return hw;
}
-
-static void __init of_at91sam9x5_clk_usb_setup(struct device_node *np)
-{
- struct clk_hw *hw;
- unsigned int num_parents;
- const char *parent_names[USB_SOURCE_MAX];
- const char *name = np->name;
- struct regmap *regmap;
-
- num_parents = of_clk_get_parent_count(np);
- if (num_parents == 0 || num_parents > USB_SOURCE_MAX)
- return;
-
- of_clk_parent_fill(np, parent_names, num_parents);
-
- of_property_read_string(np, "clock-output-names", &name);
-
- regmap = syscon_node_to_regmap(of_get_parent(np));
- if (IS_ERR(regmap))
- return;
-
- hw = at91sam9x5_clk_register_usb(regmap, name, parent_names,
- num_parents);
- if (IS_ERR(hw))
- return;
-
- of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
-}
-CLK_OF_DECLARE(at91sam9x5_clk_usb, "atmel,at91sam9x5-clk-usb",
- of_at91sam9x5_clk_usb_setup);
-
-static void __init of_at91sam9n12_clk_usb_setup(struct device_node *np)
-{
- struct clk_hw *hw;
- const char *parent_name;
- const char *name = np->name;
- struct regmap *regmap;
-
- parent_name = of_clk_get_parent_name(np, 0);
- if (!parent_name)
- return;
-
- of_property_read_string(np, "clock-output-names", &name);
-
- regmap = syscon_node_to_regmap(of_get_parent(np));
- if (IS_ERR(regmap))
- return;
-
- hw = at91sam9n12_clk_register_usb(regmap, name, parent_name);
- if (IS_ERR(hw))
- return;
-
- of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
-}
-CLK_OF_DECLARE(at91sam9n12_clk_usb, "atmel,at91sam9n12-clk-usb",
- of_at91sam9n12_clk_usb_setup);
-
-static void __init of_at91rm9200_clk_usb_setup(struct device_node *np)
-{
- struct clk_hw *hw;
- const char *parent_name;
- const char *name = np->name;
- u32 divisors[4] = {0, 0, 0, 0};
- struct regmap *regmap;
-
- parent_name = of_clk_get_parent_name(np, 0);
- if (!parent_name)
- return;
-
- of_property_read_u32_array(np, "atmel,clk-divisors", divisors, 4);
- if (!divisors[0])
- return;
-
- of_property_read_string(np, "clock-output-names", &name);
-
- regmap = syscon_node_to_regmap(of_get_parent(np));
- if (IS_ERR(regmap))
- return;
- hw = at91rm9200_clk_register_usb(regmap, name, parent_name, divisors);
- if (IS_ERR(hw))
- return;
-
- of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
-}
-CLK_OF_DECLARE(at91rm9200_clk_usb, "atmel,at91rm9200-clk-usb",
- of_at91rm9200_clk_usb_setup);
diff --git a/drivers/clk/at91/clk-utmi.c b/drivers/clk/at91/clk-utmi.c
index cd8d689138ff..9a970abf3489 100644
--- a/drivers/clk/at91/clk-utmi.c
+++ b/drivers/clk/at91/clk-utmi.c
@@ -125,7 +125,7 @@ static const struct clk_ops utmi_ops = {
.recalc_rate = clk_utmi_recalc_rate,
};
-static struct clk_hw * __init
+struct clk_hw * __init
at91_clk_register_utmi(struct regmap *regmap_pmc, struct regmap *regmap_sfr,
const char *name, const char *parent_name)
{
@@ -157,46 +157,3 @@ at91_clk_register_utmi(struct regmap *regmap_pmc, struct regmap *regmap_sfr,
return hw;
}
-
-static void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np)
-{
- struct clk_hw *hw;
- const char *parent_name;
- const char *name = np->name;
- struct regmap *regmap_pmc, *regmap_sfr;
-
- parent_name = of_clk_get_parent_name(np, 0);
-
- of_property_read_string(np, "clock-output-names", &name);
-
- regmap_pmc = syscon_node_to_regmap(of_get_parent(np));
- if (IS_ERR(regmap_pmc))
- return;
-
- /*
- * If the device supports different mainck rates, this value has to be
- * set in the UTMI Clock Trimming register.
- * - 9x5: mainck supports several rates but it is indicated that a
- * 12 MHz is needed in case of USB.
- * - sama5d3 and sama5d2: mainck supports several rates. Configuring
- * the FREQ field of the UTMI Clock Trimming register is mandatory.
- * - sama5d4: mainck is at 12 MHz.
- *
- * We only need to retrieve sama5d3 or sama5d2 sfr regmap.
- */
- regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d3-sfr");
- if (IS_ERR(regmap_sfr)) {
- regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr");
- if (IS_ERR(regmap_sfr))
- regmap_sfr = NULL;
- }
-
- hw = at91_clk_register_utmi(regmap_pmc, regmap_sfr, name, parent_name);
- if (IS_ERR(hw))
- return;
-
- of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
- return;
-}
-CLK_OF_DECLARE(at91sam9x5_clk_utmi, "atmel,at91sam9x5-clk-utmi",
- of_at91sam9x5_clk_utmi_setup);
diff --git a/drivers/clk/at91/dt-compat.c b/drivers/clk/at91/dt-compat.c
new file mode 100644
index 000000000000..b95bb4e2a927
--- /dev/null
+++ b/drivers/clk/at91/dt-compat.c
@@ -0,0 +1,961 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/clk-provider.h>
+#include <linux/clk/at91_pmc.h>
+#include <linux/of.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include "pmc.h"
+
+#define MASTER_SOURCE_MAX 4
+
+#define PERIPHERAL_AT91RM9200 0
+#define PERIPHERAL_AT91SAM9X5 1
+
+#define PERIPHERAL_MAX 64
+
+#define PERIPHERAL_ID_MIN 2
+
+#define PROG_SOURCE_MAX 5
+#define PROG_ID_MAX 7
+
+#define SYSTEM_MAX_ID 31
+
+#ifdef CONFIG_HAVE_AT91_AUDIO_PLL
+static void __init of_sama5d2_clk_audio_pll_frac_setup(struct device_node *np)
+{
+ struct clk_hw *hw;
+ const char *name = np->name;
+ const char *parent_name;
+ struct regmap *regmap;
+
+ regmap = syscon_node_to_regmap(of_get_parent(np));
+ if (IS_ERR(regmap))
+ return;
+
+ parent_name = of_clk_get_parent_name(np, 0);
+
+ hw = at91_clk_register_audio_pll_frac(regmap, name, parent_name);
+ if (IS_ERR(hw))
+ return;
+
+ of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
+}
+CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_frac_setup,
+ "atmel,sama5d2-clk-audio-pll-frac",
+ of_sama5d2_clk_audio_pll_frac_setup);
+
+static void __init of_sama5d2_clk_audio_pll_pad_setup(struct device_node *np)
+{
+ struct clk_hw *hw;
+ const char *name = np->name;
+ const char *parent_name;
+ struct regmap *regmap;
+
+ regmap = syscon_node_to_regmap(of_get_parent(np));
+ if (IS_ERR(regmap))
+ return;
+
+ parent_name = of_clk_get_parent_name(np, 0);
+
+ hw = at91_clk_register_audio_pll_pad(regmap, name, parent_name);
+ if (IS_ERR(hw))
+ return;
+
+ of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
+}
+CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_pad_setup,
+ "atmel,sama5d2-clk-audio-pll-pad",
+ of_sama5d2_clk_audio_pll_pad_setup);
+
+static void __init of_sama5d2_clk_audio_pll_pmc_setup(struct device_node *np)
+{
+ struct clk_hw *hw;
+ const char *name = np->name;
+ const char *parent_name;
+ struct regmap *regmap;
+
+ regmap = syscon_node_to_regmap(of_get_parent(np));
+ if (IS_ERR(regmap))
+ return;
+
+ parent_name = of_clk_get_parent_name(np, 0);
+
+ hw = at91_clk_register_audio_pll_pmc(regmap, name, parent_name);
+ if (IS_ERR(hw))
+ return;
+
+ of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
+}
+CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_pmc_setup,
+ "atmel,sama5d2-clk-audio-pll-pmc",
+ of_sama5d2_clk_audio_pll_pmc_setup);
+#endif /* CONFIG_HAVE_AT91_AUDIO_PLL */
+
+#ifdef CONFIG_HAVE_AT91_GENERATED_CLK
+#define GENERATED_SOURCE_MAX 6
+
+#define GCK_ID_I2S0 54
+#define GCK_ID_I2S1 55
+#define GCK_ID_CLASSD 59
+
+static void __init of_sama5d2_clk_generated_setup(struct device_node *np)
+{
+ int num;
+ u32 id;
+ const char *name;
+ struct clk_hw *hw;
+ unsigned int num_parents;
+ const char *parent_names[GENERATED_SOURCE_MAX];
+ struct device_node *gcknp;
+ struct clk_range range = CLK_RANGE(0, 0);
+ struct regmap *regmap;
+
+ num_parents = of_clk_get_parent_count(np);
+ if (num_parents == 0 || num_parents > GENERATED_SOURCE_MAX)
+ return;
+
+ of_clk_parent_fill(np, parent_names, num_parents);
+
+ num = of_get_child_count(np);
+ if (!num || num > PERIPHERAL_MAX)
+ return;
+
+ regmap = syscon_node_to_regmap(of_get_parent(np));
+ if (IS_ERR(regmap))
+ return;
+
+ for_each_child_of_node(np, gcknp) {
+ bool pll_audio = false;
+
+ if (of_property_read_u32(gcknp, "reg", &id))
+ continue;
+
+ if (id < PERIPHERAL_ID_MIN || id >= PERIPHERAL_MAX)
+ continue;
+
+ if (of_property_read_string(np, "clock-output-names", &name))
+ name = gcknp->name;
+
+ of_at91_get_clk_range(gcknp, "atmel,clk-output-range",
+ &range);
+
+ if (of_device_is_compatible(np, "atmel,sama5d2-clk-generated") &&
+ (id == GCK_ID_I2S0 || id == GCK_ID_I2S1 ||
+ id == GCK_ID_CLASSD))
+ pll_audio = true;
+
+ hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, name,
+ parent_names, num_parents,
+ id, pll_audio, &range);
+ if (IS_ERR(hw))
+ continue;
+
+ of_clk_add_hw_provider(gcknp, of_clk_hw_simple_get, hw);
+ }
+}
+CLK_OF_DECLARE(of_sama5d2_clk_generated_setup, "atmel,sama5d2-clk-generated",
+ of_sama5d2_clk_generated_setup);
+#endif /* CONFIG_HAVE_AT91_GENERATED_CLK */
+
+#ifdef CONFIG_HAVE_AT91_H32MX
+static void __init of_sama5d4_clk_h32mx_setup(struct device_node *np)
+{
+ struct clk_hw *hw;
+ const char *name = np->name;
+ const char *parent_name;
+ struct regmap *regmap;
+
+ regmap = syscon_node_to_regmap(of_get_parent(np));
+ if (IS_ERR(regmap))
+ return;
+
+ parent_name = of_clk_get_parent_name(np, 0);
+
+ hw = at91_clk_register_h32mx(regmap, name, parent_name);
+ if (IS_ERR(hw))
+ return;
+
+ of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
+}
+CLK_OF_DECLARE(of_sama5d4_clk_h32mx_setup, "atmel,sama5d4-clk-h32mx",
+ of_sama5d4_clk_h32mx_setup);
+#endif /* CONFIG_HAVE_AT91_H32MX */
+
+#ifdef CONFIG_HAVE_AT91_I2S_MUX_CLK
+#define I2S_BUS_NR 2
+
+static void __init of_sama5d2_clk_i2s_mux_setup(struct device_node *np)
+{
+ struct regmap *regmap_sfr;
+ u8 bus_id;
+ const char *parent_names[2];
+ struct device_node *i2s_mux_np;
+ struct clk_hw *hw;
+ int ret;
+
+ regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr");
+ if (IS_ERR(regmap_sfr))
+ return;
+
+ for_each_child_of_node(np, i2s_mux_np) {
+ if (of_property_read_u8(i2s_mux_np, "reg", &bus_id))
+ continue;
+
+ if (bus_id > I2S_BUS_NR)
+ continue;
+
+ ret = of_clk_parent_fill(i2s_mux_np, parent_names, 2);
+ if (ret != 2)
+ continue;
+
+ hw = at91_clk_i2s_mux_register(regmap_sfr, i2s_mux_np->name,
+ parent_names, 2, bus_id);
+ if (IS_ERR(hw))
+ continue;
+
+ of_clk_add_hw_provider(i2s_mux_np, of_clk_hw_simple_get, hw);
+ }
+}
+CLK_OF_DECLARE(sama5d2_clk_i2s_mux, "atmel,sama5d2-clk-i2s-mux",
+ of_sama5d2_clk_i2s_mux_setup);
+#endif /* CONFIG_HAVE_AT91_I2S_MUX_CLK */
+
+static void __init of_at91rm9200_clk_main_osc_setup(struct device_node *np)
+{
+ struct clk_hw *hw;
+ const char *name = np->name;
+ const char *parent_name;
+ struct regmap *regmap;
+ bool bypass;
+
+ of_property_read_string(np, "clock-output-names", &name);
+ bypass = of_property_read_bool(np, "atmel,osc-bypass");
+ parent_name = of_clk_get_parent_name(np, 0);
+
+ regmap = syscon_node_to_regmap(of_get_parent(np));
+ if (IS_ERR(regmap))
+ return;
+
+ hw = at91_clk_register_main_osc(regmap, name, parent_name, bypass);
+ if (IS_ERR(hw))
+ return;
+
+ of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
+}
+CLK_OF_DECLARE(at91rm9200_clk_main_osc, "atmel,at91rm9200-clk-main-osc",
+ of_at91rm9200_clk_main_osc_setup);
+
+static void __init of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np)
+{
+ struct clk_hw *hw;
+ u32 frequency = 0;
+ u32 accuracy = 0;
+ const char *name = np->name;
+ struct regmap *regmap;
+
+ of_property_read_string(np, "clock-output-names", &name);
+ of_property_read_u32(np, "clock-frequency", &frequency);
+ of_property_read_u32(np, "clock-accuracy", &accuracy);
+
+ regmap = syscon_node_to_regmap(of_get_parent(np));
+ if (IS_ERR(regmap))
+ return;
+
+ hw = at91_clk_register_main_rc_osc(regmap, name, frequency, accuracy);
+ if (IS_ERR(hw))
+ return;
+
+ of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
+}
+CLK_OF_DECLARE(at91sam9x5_clk_main_rc_osc, "atmel,at91sam9x5-clk-main-rc-osc",
+ of_at91sam9x5_clk_main_rc_osc_setup);
+
+static void __init of_at91rm9200_clk_main_setup(struct device_node *np)
+{
+ struct clk_hw *hw;
+ const char *parent_name;
+ const char *name = np->name;
+ struct regmap *regmap;
+
+ parent_name = of_clk_get_parent_name(np, 0);
+ of_property_read_string(np, "clock-output-names", &name);
+
+ regmap = syscon_node_to_regmap(of_get_parent(np));
+ if (IS_ERR(regmap))
+ return;
+
+ hw = at91_clk_register_rm9200_main(regmap, name, parent_name);
+ if (IS_ERR(hw))
+ return;
+
+ of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
+}
+CLK_OF_DECLARE(at91rm9200_clk_main, "atmel,at91rm9200-clk-main",
+ of_at91rm9200_clk_main_setup);
+
+static void __init of_at91sam9x5_clk_main_setup(struct device_node *np)
+{
+ struct clk_hw *hw;
+ const char *parent_names[2];
+ unsigned int num_parents;
+ const char *name = np->name;
+ struct regmap *regmap;
+
+ num_parents = of_clk_get_parent_count(np);
+ if (num_parents == 0 || num_parents > 2)
+ return;
+
+ of_clk_parent_fill(np, parent_names, num_parents);
+ regmap = syscon_node_to_regmap(of_get_parent(np));
+ if (IS_ERR(regmap))
+ return;
+
+ of_property_read_string(np, "clock-output-names", &name);
+
+ hw = at91_clk_register_sam9x5_main(regmap, name, parent_names,
+ num_parents);
+ if (IS_ERR(hw))
+ return;
+
+ of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
+}
+CLK_OF_DECLARE(at91sam9x5_clk_main, "atmel,at91sam9x5-clk-main",
+ of_at91sam9x5_clk_main_setup);
+
+static struct clk_master_characteristics * __init
+of_at91_clk_master_get_characteristics(struct device_node *np)
+{
+ struct clk_master_characteristics *characteristics;
+
+ characteristics = kzalloc(sizeof(*characteristics), GFP_KERNEL);
+ if (!characteristics)
+ return NULL;
+
+ if (of_at91_get_clk_range(np, "atmel,clk-output-range", &characteristics->output))
+ goto out_free_characteristics;
+
+ of_property_read_u32_array(np, "atmel,clk-divisors",
+ characteristics->divisors, 4);
+
+ characteristics->have_div3_pres =
+ of_property_read_bool(np, "atmel,master-clk-have-div3-pres");
+
+ return characteristics;
+
+out_free_characteristics:
+ kfree(characteristics);
+ return NULL;
+}
+
+static void __init
+of_at91_clk_master_setup(struct device_node *np,
+ const struct clk_master_layout *layout)
+{
+ struct clk_hw *hw;
+ unsigned int num_parents;
+ const char *parent_names[MASTER_SOURCE_MAX];
+ const char *name = np->name;
+ struct clk_master_characteristics *characteristics;
+ struct regmap *regmap;
+
+ num_parents = of_clk_get_parent_count(np);
+ if (num_parents == 0 || num_parents > MASTER_SOURCE_MAX)
+ return;
+
+ of_clk_parent_fill(np, parent_names, num_parents);
+
+ of_property_read_string(np, "clock-output-names", &name);
+
+ characteristics = of_at91_clk_master_get_characteristics(np);
+ if (!characteristics)
+ return;
+
+ regmap = syscon_node_to_regmap(of_get_parent(np));
+ if (IS_ERR(regmap))
+ return;
+
+ hw = at91_clk_register_master(regmap, name, num_parents,
+ parent_names, layout,
+ characteristics);
+ if (IS_ERR(hw))
+ goto out_free_characteristics;
+
+ of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
+ return;
+
+out_free_characteristics:
+ kfree(characteristics);
+}
+
+static void __init of_at91rm9200_clk_master_setup(struct device_node *np)
+{
+ of_at91_clk_master_setup(np, &at91rm9200_master_layout);
+}
+CLK_OF_DECLARE(at91rm9200_clk_master, "atmel,at91rm9200-clk-master",
+ of_at91rm9200_clk_master_setup);
+
+static void __init of_at91sam9x5_clk_master_setup(struct device_node *np)
+{
+ of_at91_clk_master_setup(np, &at91sam9x5_master_layout);
+}
+CLK_OF_DECLARE(at91sam9x5_clk_master, "atmel,at91sam9x5-clk-master",
+ of_at91sam9x5_clk_master_setup);
+
+static void __init
+of_at91_clk_periph_setup(struct device_node *np, u8 type)
+{
+ int num;
+ u32 id;
+ struct clk_hw *hw;
+ const char *parent_name;
+ const char *name;
+ struct device_node *periphclknp;
+ struct regmap *regmap;
+
+ parent_name = of_clk_get_parent_name(np, 0);
+ if (!parent_name)
+ return;
+
+ num = of_get_child_count(np);
+ if (!num || num > PERIPHERAL_MAX)
+ return;
+
+ regmap = syscon_node_to_regmap(of_get_parent(np));
+ if (IS_ERR(regmap))
+ return;
+
+ for_each_child_of_node(np, periphclknp) {
+ if (of_property_read_u32(periphclknp, "reg", &id))
+ continue;
+
+ if (id >= PERIPHERAL_MAX)
+ continue;
+
+ if (of_property_read_string(np, "clock-output-names", &name))
+ name = periphclknp->name;
+
+ if (type == PERIPHERAL_AT91RM9200) {
+ hw = at91_clk_register_peripheral(regmap, name,
+ parent_name, id);
+ } else {
+ struct clk_range range = CLK_RANGE(0, 0);
+
+ of_at91_get_clk_range(periphclknp,
+ "atmel,clk-output-range",
+ &range);
+
+ hw = at91_clk_register_sam9x5_peripheral(regmap,
+ &pmc_pcr_lock,
+ name,
+ parent_name,
+ id, &range);
+ }
+
+ if (IS_ERR(hw))
+ continue;
+
+ of_clk_add_hw_provider(periphclknp, of_clk_hw_simple_get, hw);
+ }
+}
+
+static void __init of_at91rm9200_clk_periph_setup(struct device_node *np)
+{
+ of_at91_clk_periph_setup(np, PERIPHERAL_AT91RM9200);
+}
+CLK_OF_DECLARE(at91rm9200_clk_periph, "atmel,at91rm9200-clk-peripheral",
+ of_at91rm9200_clk_periph_setup);
+
+static void __init of_at91sam9x5_clk_periph_setup(struct device_node *np)
+{
+ of_at91_clk_periph_setup(np, PERIPHERAL_AT91SAM9X5);
+}
+CLK_OF_DECLARE(at91sam9x5_clk_periph, "atmel,at91sam9x5-clk-peripheral",
+ of_at91sam9x5_clk_periph_setup);
+
+static struct clk_pll_characteristics * __init
+of_at91_clk_pll_get_characteristics(struct device_node *np)
+{
+ int i;
+ int offset;
+ u32 tmp;
+ int num_output;
+ u32 num_cells;
+ struct clk_range input;
+ struct clk_range *output;
+ u8 *out = NULL;
+ u16 *icpll = NULL;
+ struct clk_pll_characteristics *characteristics;
+
+ if (of_at91_get_clk_range(np, "atmel,clk-input-range", &input))
+ return NULL;
+
+ if (of_property_read_u32(np, "#atmel,pll-clk-output-range-cells",
+ &num_cells))
+ return NULL;
+
+ if (num_cells < 2 || num_cells > 4)
+ return NULL;
+
+ if (!of_get_property(np, "atmel,pll-clk-output-ranges", &tmp))
+ return NULL;
+ num_output = tmp / (sizeof(u32) * num_cells);
+
+ characteristics = kzalloc(sizeof(*characteristics), GFP_KERNEL);
+ if (!characteristics)
+ return NULL;
+
+ output = kcalloc(num_output, sizeof(*output), GFP_KERNEL);
+ if (!output)
+ goto out_free_characteristics;
+
+ if (num_cells > 2) {
+ out = kcalloc(num_output, sizeof(*out), GFP_KERNEL);
+ if (!out)
+ goto out_free_output;
+ }
+
+ if (num_cells > 3) {
+ icpll = kcalloc(num_output, sizeof(*icpll), GFP_KERNEL);
+ if (!icpll)
+ goto out_free_output;
+ }
+
+ for (i = 0; i < num_output; i++) {
+ offset = i * num_cells;
+ if (of_property_read_u32_index(np,
+ "atmel,pll-clk-output-ranges",
+ offset, &tmp))
+ goto out_free_output;
+ output[i].min = tmp;
+ if (of_property_read_u32_index(np,
+ "atmel,pll-clk-output-ranges",
+ offset + 1, &tmp))
+ goto out_free_output;
+ output[i].max = tmp;
+
+ if (num_cells == 2)
+ continue;
+
+ if (of_property_read_u32_index(np,
+ "atmel,pll-clk-output-ranges",
+ offset + 2, &tmp))
+ goto out_free_output;
+ out[i] = tmp;
+
+ if (num_cells == 3)
+ continue;
+
+ if (of_property_read_u32_index(np,
+ "atmel,pll-clk-output-ranges",
+ offset + 3, &tmp))
+ goto out_free_output;
+ icpll[i] = tmp;
+ }
+
+ characteristics->input = input;
+ characteristics->num_output = num_output;
+ characteristics->output = output;
+ characteristics->out = out;
+ characteristics->icpll = icpll;
+ return characteristics;
+
+out_free_output:
+ kfree(icpll);
+ kfree(out);
+ kfree(output);
+out_free_characteristics:
+ kfree(characteristics);
+ return NULL;
+}
+
+static void __init
+of_at91_clk_pll_setup(struct device_node *np,
+ const struct clk_pll_layout *layout)
+{
+ u32 id;
+ struct clk_hw *hw;
+ struct regmap *regmap;
+ const char *parent_name;
+ const char *name = np->name;
+ struct clk_pll_characteristics *characteristics;
+
+ if (of_property_read_u32(np, "reg", &id))
+ return;
+
+ parent_name = of_clk_get_parent_name(np, 0);
+
+ of_property_read_string(np, "clock-output-names", &name);
+
+ regmap = syscon_node_to_regmap(of_get_parent(np));
+ if (IS_ERR(regmap))
+ return;
+
+ characteristics = of_at91_clk_pll_get_characteristics(np);
+ if (!characteristics)
+ return;
+
+ hw = at91_clk_register_pll(regmap, name, parent_name, id, layout,
+ characteristics);
+ if (IS_ERR(hw))
+ goto out_free_characteristics;
+
+ of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
+ return;
+
+out_free_characteristics:
+ kfree(characteristics);
+}
+
+static void __init of_at91rm9200_clk_pll_setup(struct device_node *np)
+{
+ of_at91_clk_pll_setup(np, &at91rm9200_pll_layout);
+}
+CLK_OF_DECLARE(at91rm9200_clk_pll, "atmel,at91rm9200-clk-pll",
+ of_at91rm9200_clk_pll_setup);
+
+static void __init of_at91sam9g45_clk_pll_setup(struct device_node *np)
+{
+ of_at91_clk_pll_setup(np, &at91sam9g45_pll_layout);
+}
+CLK_OF_DECLARE(at91sam9g45_clk_pll, "atmel,at91sam9g45-clk-pll",
+ of_at91sam9g45_clk_pll_setup);
+
+static void __init of_at91sam9g20_clk_pllb_setup(struct device_node *np)
+{
+ of_at91_clk_pll_setup(np, &at91sam9g20_pllb_layout);
+}
+CLK_OF_DECLARE(at91sam9g20_clk_pllb, "atmel,at91sam9g20-clk-pllb",
+ of_at91sam9g20_clk_pllb_setup);
+
+static void __init of_sama5d3_clk_pll_setup(struct device_node *np)
+{
+ of_at91_clk_pll_setup(np, &sama5d3_pll_layout);
+}
+CLK_OF_DECLARE(sama5d3_clk_pll, "atmel,sama5d3-clk-pll",
+ of_sama5d3_clk_pll_setup);
+
+static void __init
+of_at91sam9x5_clk_plldiv_setup(struct device_node *np)
+{
+ struct clk_hw *hw;
+ const char *parent_name;
+ const char *name = np->name;
+ struct regmap *regmap;
+
+ parent_name = of_clk_get_parent_name(np, 0);
+
+ of_property_read_string(np, "clock-output-names", &name);
+
+ regmap = syscon_node_to_regmap(of_get_parent(np));
+ if (IS_ERR(regmap))
+ return;
+
+ hw = at91_clk_register_plldiv(regmap, name, parent_name);
+ if (IS_ERR(hw))
+ return;
+
+ of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
+}
+CLK_OF_DECLARE(at91sam9x5_clk_plldiv, "atmel,at91sam9x5-clk-plldiv",
+ of_at91sam9x5_clk_plldiv_setup);
+
+static void __init
+of_at91_clk_prog_setup(struct device_node *np,
+ const struct clk_programmable_layout *layout)
+{
+ int num;
+ u32 id;
+ struct clk_hw *hw;
+ unsigned int num_parents;
+ const char *parent_names[PROG_SOURCE_MAX];
+ const char *name;
+ struct device_node *progclknp;
+ struct regmap *regmap;
+
+ num_parents = of_clk_get_parent_count(np);
+ if (num_parents == 0 || num_parents > PROG_SOURCE_MAX)
+ return;
+
+ of_clk_parent_fill(np, parent_names, num_parents);
+
+ num = of_get_child_count(np);
+ if (!num || num > (PROG_ID_MAX + 1))
+ return;
+
+ regmap = syscon_node_to_regmap(of_get_parent(np));
+ if (IS_ERR(regmap))
+ return;
+
+ for_each_child_of_node(np, progclknp) {
+ if (of_property_read_u32(progclknp, "reg", &id))
+ continue;
+
+ if (of_property_read_string(np, "clock-output-names", &name))
+ name = progclknp->name;
+
+ hw = at91_clk_register_programmable(regmap, name,
+ parent_names, num_parents,
+ id, layout);
+ if (IS_ERR(hw))
+ continue;
+
+ of_clk_add_hw_provider(progclknp, of_clk_hw_simple_get, hw);
+ }
+}
+
+static void __init of_at91rm9200_clk_prog_setup(struct device_node *np)
+{
+ of_at91_clk_prog_setup(np, &at91rm9200_programmable_layout);
+}
+CLK_OF_DECLARE(at91rm9200_clk_prog, "atmel,at91rm9200-clk-programmable",
+ of_at91rm9200_clk_prog_setup);
+
+static void __init of_at91sam9g45_clk_prog_setup(struct device_node *np)
+{
+ of_at91_clk_prog_setup(np, &at91sam9g45_programmable_layout);
+}
+CLK_OF_DECLARE(at91sam9g45_clk_prog, "atmel,at91sam9g45-clk-programmable",
+ of_at91sam9g45_clk_prog_setup);
+
+static void __init of_at91sam9x5_clk_prog_setup(struct device_node *np)
+{
+ of_at91_clk_prog_setup(np, &at91sam9x5_programmable_layout);
+}
+CLK_OF_DECLARE(at91sam9x5_clk_prog, "atmel,at91sam9x5-clk-programmable",
+ of_at91sam9x5_clk_prog_setup);
+
+static void __init of_at91sam9260_clk_slow_setup(struct device_node *np)
+{
+ struct clk_hw *hw;
+ const char *parent_names[2];
+ unsigned int num_parents;
+ const char *name = np->name;
+ struct regmap *regmap;
+
+ num_parents = of_clk_get_parent_count(np);
+ if (num_parents != 2)
+ return;
+
+ of_clk_parent_fill(np, parent_names, num_parents);
+ regmap = syscon_node_to_regmap(of_get_parent(np));
+ if (IS_ERR(regmap))
+ return;
+
+ of_property_read_string(np, "clock-output-names", &name);
+
+ hw = at91_clk_register_sam9260_slow(regmap, name, parent_names,
+ num_parents);
+ if (IS_ERR(hw))
+ return;
+
+ of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
+}
+CLK_OF_DECLARE(at91sam9260_clk_slow, "atmel,at91sam9260-clk-slow",
+ of_at91sam9260_clk_slow_setup);
+
+#ifdef CONFIG_HAVE_AT91_SMD
+#define SMD_SOURCE_MAX 2
+
+static void __init of_at91sam9x5_clk_smd_setup(struct device_node *np)
+{
+ struct clk_hw *hw;
+ unsigned int num_parents;
+ const char *parent_names[SMD_SOURCE_MAX];
+ const char *name = np->name;
+ struct regmap *regmap;
+
+ num_parents = of_clk_get_parent_count(np);
+ if (num_parents == 0 || num_parents > SMD_SOURCE_MAX)
+ return;
+
+ of_clk_parent_fill(np, parent_names, num_parents);
+
+ of_property_read_string(np, "clock-output-names", &name);
+
+ regmap = syscon_node_to_regmap(of_get_parent(np));
+ if (IS_ERR(regmap))
+ return;
+
+ hw = at91sam9x5_clk_register_smd(regmap, name, parent_names,
+ num_parents);
+ if (IS_ERR(hw))
+ return;
+
+ of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
+}
+CLK_OF_DECLARE(at91sam9x5_clk_smd, "atmel,at91sam9x5-clk-smd",
+ of_at91sam9x5_clk_smd_setup);
+#endif /* CONFIG_HAVE_AT91_SMD */
+
+static void __init of_at91rm9200_clk_sys_setup(struct device_node *np)
+{
+ int num;
+ u32 id;
+ struct clk_hw *hw;
+ const char *name;
+ struct device_node *sysclknp;
+ const char *parent_name;
+ struct regmap *regmap;
+
+ num = of_get_child_count(np);
+ if (num > (SYSTEM_MAX_ID + 1))
+ return;
+
+ regmap = syscon_node_to_regmap(of_get_parent(np));
+ if (IS_ERR(regmap))
+ return;
+
+ for_each_child_of_node(np, sysclknp) {
+ if (of_property_read_u32(sysclknp, "reg", &id))
+ continue;
+
+ if (of_property_read_string(np, "clock-output-names", &name))
+ name = sysclknp->name;
+
+ parent_name = of_clk_get_parent_name(sysclknp, 0);
+
+ hw = at91_clk_register_system(regmap, name, parent_name, id);
+ if (IS_ERR(hw))
+ continue;
+
+ of_clk_add_hw_provider(sysclknp, of_clk_hw_simple_get, hw);
+ }
+}
+CLK_OF_DECLARE(at91rm9200_clk_sys, "atmel,at91rm9200-clk-system",
+ of_at91rm9200_clk_sys_setup);
+
+#ifdef CONFIG_HAVE_AT91_USB_CLK
+#define USB_SOURCE_MAX 2
+
+static void __init of_at91sam9x5_clk_usb_setup(struct device_node *np)
+{
+ struct clk_hw *hw;
+ unsigned int num_parents;
+ const char *parent_names[USB_SOURCE_MAX];
+ const char *name = np->name;
+ struct regmap *regmap;
+
+ num_parents = of_clk_get_parent_count(np);
+ if (num_parents == 0 || num_parents > USB_SOURCE_MAX)
+ return;
+
+ of_clk_parent_fill(np, parent_names, num_parents);
+
+ of_property_read_string(np, "clock-output-names", &name);
+
+ regmap = syscon_node_to_regmap(of_get_parent(np));
+ if (IS_ERR(regmap))
+ return;
+
+ hw = at91sam9x5_clk_register_usb(regmap, name, parent_names,
+ num_parents);
+ if (IS_ERR(hw))
+ return;
+
+ of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
+}
+CLK_OF_DECLARE(at91sam9x5_clk_usb, "atmel,at91sam9x5-clk-usb",
+ of_at91sam9x5_clk_usb_setup);
+
+static void __init of_at91sam9n12_clk_usb_setup(struct device_node *np)
+{
+ struct clk_hw *hw;
+ const char *parent_name;
+ const char *name = np->name;
+ struct regmap *regmap;
+
+ parent_name = of_clk_get_parent_name(np, 0);
+ if (!parent_name)
+ return;
+
+ of_property_read_string(np, "clock-output-names", &name);
+
+ regmap = syscon_node_to_regmap(of_get_parent(np));
+ if (IS_ERR(regmap))
+ return;
+
+ hw = at91sam9n12_clk_register_usb(regmap, name, parent_name);
+ if (IS_ERR(hw))
+ return;
+
+ of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
+}
+CLK_OF_DECLARE(at91sam9n12_clk_usb, "atmel,at91sam9n12-clk-usb",
+ of_at91sam9n12_clk_usb_setup);
+
+static void __init of_at91rm9200_clk_usb_setup(struct device_node *np)
+{
+ struct clk_hw *hw;
+ const char *parent_name;
+ const char *name = np->name;
+ u32 divisors[4] = {0, 0, 0, 0};
+ struct regmap *regmap;
+
+ parent_name = of_clk_get_parent_name(np, 0);
+ if (!parent_name)
+ return;
+
+ of_property_read_u32_array(np, "atmel,clk-divisors", divisors, 4);
+ if (!divisors[0])
+ return;
+
+ of_property_read_string(np, "clock-output-names", &name);
+
+ regmap = syscon_node_to_regmap(of_get_parent(np));
+ if (IS_ERR(regmap))
+ return;
+ hw = at91rm9200_clk_register_usb(regmap, name, parent_name, divisors);
+ if (IS_ERR(hw))
+ return;
+
+ of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
+}
+CLK_OF_DECLARE(at91rm9200_clk_usb, "atmel,at91rm9200-clk-usb",
+ of_at91rm9200_clk_usb_setup);
+#endif /* CONFIG_HAVE_AT91_USB_CLK */
+
+#ifdef CONFIG_HAVE_AT91_UTMI
+static void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np)
+{
+ struct clk_hw *hw;
+ const char *parent_name;
+ const char *name = np->name;
+ struct regmap *regmap_pmc, *regmap_sfr;
+
+ parent_name = of_clk_get_parent_name(np, 0);
+
+ of_property_read_string(np, "clock-output-names", &name);
+
+ regmap_pmc = syscon_node_to_regmap(of_get_parent(np));
+ if (IS_ERR(regmap_pmc))
+ return;
+
+ /*
+ * If the device supports different mainck rates, this value has to be
+ * set in the UTMI Clock Trimming register.
+ * - 9x5: mainck supports several rates but it is indicated that a
+ * 12 MHz is needed in case of USB.
+ * - sama5d3 and sama5d2: mainck supports several rates. Configuring
+ * the FREQ field of the UTMI Clock Trimming register is mandatory.
+ * - sama5d4: mainck is at 12 MHz.
+ *
+ * We only need to retrieve sama5d3 or sama5d2 sfr regmap.
+ */
+ regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d3-sfr");
+ if (IS_ERR(regmap_sfr)) {
+ regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr");
+ if (IS_ERR(regmap_sfr))
+ regmap_sfr = NULL;
+ }
+
+ hw = at91_clk_register_utmi(regmap_pmc, regmap_sfr, name, parent_name);
+ if (IS_ERR(hw))
+ return;
+
+ of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
+}
+CLK_OF_DECLARE(at91sam9x5_clk_utmi, "atmel,at91sam9x5-clk-utmi",
+ of_at91sam9x5_clk_utmi_setup);
+#endif /* CONFIG_HAVE_AT91_UTMI */
diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
index 1fa27f4ea538..db24539d5740 100644
--- a/drivers/clk/at91/pmc.c
+++ b/drivers/clk/at91/pmc.c
@@ -19,6 +19,8 @@
#include <asm/proc-fns.h>
+#include <dt-bindings/clock/at91.h>
+
#include "pmc.h"
#define PMC_MAX_IDS 128
@@ -47,6 +49,82 @@ int of_at91_get_clk_range(struct device_node *np, const char *propname,
}
EXPORT_SYMBOL_GPL(of_at91_get_clk_range);
+struct clk_hw *of_clk_hw_pmc_get(struct of_phandle_args *clkspec, void *data)
+{
+ unsigned int type = clkspec->args[0];
+ unsigned int idx = clkspec->args[1];
+ struct pmc_data *pmc_data = data;
+
+ switch (type) {
+ case PMC_TYPE_CORE:
+ if (idx < pmc_data->ncore)
+ return pmc_data->chws[idx];
+ break;
+ case PMC_TYPE_SYSTEM:
+ if (idx < pmc_data->nsystem)
+ return pmc_data->shws[idx];
+ break;
+ case PMC_TYPE_PERIPHERAL:
+ if (idx < pmc_data->nperiph)
+ return pmc_data->phws[idx];
+ break;
+ case PMC_TYPE_GCK:
+ if (idx < pmc_data->ngck)
+ return pmc_data->ghws[idx];
+ break;
+ default:
+ break;
+ }
+
+ pr_err("%s: invalid type (%u) or index (%u)\n", __func__, type, idx);
+
+ return ERR_PTR(-EINVAL);
+}
+
+void pmc_data_free(struct pmc_data *pmc_data)
+{
+ kfree(pmc_data->chws);
+ kfree(pmc_data->shws);
+ kfree(pmc_data->phws);
+ kfree(pmc_data->ghws);
+}
+
+struct pmc_data *pmc_data_allocate(unsigned int ncore, unsigned int nsystem,
+ unsigned int nperiph, unsigned int ngck)
+{
+ struct pmc_data *pmc_data = kzalloc(sizeof(*pmc_data), GFP_KERNEL);
+
+ if (!pmc_data)
+ return NULL;
+
+ pmc_data->ncore = ncore;
+ pmc_data->chws = kcalloc(ncore, sizeof(struct clk_hw *), GFP_KERNEL);
+ if (!pmc_data->chws)
+ goto err;
+
+ pmc_data->nsystem = nsystem;
+ pmc_data->shws = kcalloc(nsystem, sizeof(struct clk_hw *), GFP_KERNEL);
+ if (!pmc_data->shws)
+ goto err;
+
+ pmc_data->nperiph = nperiph;
+ pmc_data->phws = kcalloc(nperiph, sizeof(struct clk_hw *), GFP_KERNEL);
+ if (!pmc_data->phws)
+ goto err;
+
+ pmc_data->ngck = ngck;
+ pmc_data->ghws = kcalloc(ngck, sizeof(struct clk_hw *), GFP_KERNEL);
+ if (!pmc_data->ghws)
+ goto err;
+
+ return pmc_data;
+
+err:
+ pmc_data_free(pmc_data);
+
+ return NULL;
+}
+
#ifdef CONFIG_PM
static struct regmap *pmcreg;
diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
index d22b1fa9ecdc..672a79bda88c 100644
--- a/drivers/clk/at91/pmc.h
+++ b/drivers/clk/at91/pmc.h
@@ -19,6 +19,17 @@
extern spinlock_t pmc_pcr_lock;
+struct pmc_data {
+ unsigned int ncore;
+ struct clk_hw **chws;
+ unsigned int nsystem;
+ struct clk_hw **shws;
+ unsigned int nperiph;
+ struct clk_hw **phws;
+ unsigned int ngck;
+ struct clk_hw **ghws;
+};
+
struct clk_range {
unsigned long min;
unsigned long max;
@@ -26,9 +37,157 @@ struct clk_range {
#define CLK_RANGE(MIN, MAX) {.min = MIN, .max = MAX,}
+struct clk_master_layout {
+ u32 mask;
+ u8 pres_shift;
+};
+
+extern const struct clk_master_layout at91rm9200_master_layout;
+extern const struct clk_master_layout at91sam9x5_master_layout;
+
+struct clk_master_characteristics {
+ struct clk_range output;
+ u32 divisors[4];
+ u8 have_div3_pres;
+};
+
+struct clk_pll_layout {
+ u32 pllr_mask;
+ u16 mul_mask;
+ u8 mul_shift;
+};
+
+extern const struct clk_pll_layout at91rm9200_pll_layout;
+extern const struct clk_pll_layout at91sam9g45_pll_layout;
+extern const struct clk_pll_layout at91sam9g20_pllb_layout;
+extern const struct clk_pll_layout sama5d3_pll_layout;
+
+struct clk_pll_characteristics {
+ struct clk_range input;
+ int num_output;
+ struct clk_range *output;
+ u16 *icpll;
+ u8 *out;
+};
+
+struct clk_programmable_layout {
+ u8 pres_shift;
+ u8 css_mask;
+ u8 have_slck_mck;
+};
+
+extern const struct clk_programmable_layout at91rm9200_programmable_layout;
+extern const struct clk_programmable_layout at91sam9g45_programmable_layout;
+extern const struct clk_programmable_layout at91sam9x5_programmable_layout;
+
+#define ndck(a, s) (a[s - 1].id + 1)
+#define nck(a) (a[ARRAY_SIZE(a) - 1].id + 1)
+struct pmc_data *pmc_data_allocate(unsigned int ncore, unsigned int nsystem,
+ unsigned int nperiph, unsigned int ngck);
+void pmc_data_free(struct pmc_data *pmc_data);
+
int of_at91_get_clk_range(struct device_node *np, const char *propname,
struct clk_range *range);
+struct clk_hw *of_clk_hw_pmc_get(struct of_phandle_args *clkspec, void *data);
+
+struct clk_hw * __init
+at91_clk_register_audio_pll_frac(struct regmap *regmap, const char *name,
+ const char *parent_name);
+
+struct clk_hw * __init
+at91_clk_register_audio_pll_pad(struct regmap *regmap, const char *name,
+ const char *parent_name);
+
+struct clk_hw * __init
+at91_clk_register_audio_pll_pmc(struct regmap *regmap, const char *name,
+ const char *parent_name);
+
+struct clk_hw * __init
+at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock,
+ const char *name, const char **parent_names,
+ u8 num_parents, u8 id, bool pll_audio,
+ const struct clk_range *range);
+
+struct clk_hw * __init
+at91_clk_register_h32mx(struct regmap *regmap, const char *name,
+ const char *parent_name);
+
+struct clk_hw * __init
+at91_clk_i2s_mux_register(struct regmap *regmap, const char *name,
+ const char * const *parent_names,
+ unsigned int num_parents, u8 bus_id);
+
+struct clk_hw * __init
+at91_clk_register_main_rc_osc(struct regmap *regmap, const char *name,
+ u32 frequency, u32 accuracy);
+struct clk_hw * __init
+at91_clk_register_main_osc(struct regmap *regmap, const char *name,
+ const char *parent_name, bool bypass);
+struct clk_hw * __init
+at91_clk_register_rm9200_main(struct regmap *regmap,
+ const char *name,
+ const char *parent_name);
+struct clk_hw * __init
+at91_clk_register_sam9x5_main(struct regmap *regmap, const char *name,
+ const char **parent_names, int num_parents);
+
+struct clk_hw * __init
+at91_clk_register_master(struct regmap *regmap, const char *name,
+ int num_parents, const char **parent_names,
+ const struct clk_master_layout *layout,
+ const struct clk_master_characteristics *characteristics);
+
+struct clk_hw * __init
+at91_clk_register_peripheral(struct regmap *regmap, const char *name,
+ const char *parent_name, u32 id);
+struct clk_hw * __init
+at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
+ const char *name, const char *parent_name,
+ u32 id, const struct clk_range *range);
+
+struct clk_hw * __init
+at91_clk_register_pll(struct regmap *regmap, const char *name,
+ const char *parent_name, u8 id,
+ const struct clk_pll_layout *layout,
+ const struct clk_pll_characteristics *characteristics);
+struct clk_hw * __init
+at91_clk_register_plldiv(struct regmap *regmap, const char *name,
+ const char *parent_name);
+
+struct clk_hw * __init
+at91_clk_register_programmable(struct regmap *regmap, const char *name,
+ const char **parent_names, u8 num_parents, u8 id,
+ const struct clk_programmable_layout *layout);
+
+struct clk_hw * __init
+at91_clk_register_sam9260_slow(struct regmap *regmap,
+ const char *name,
+ const char **parent_names,
+ int num_parents);
+
+struct clk_hw * __init
+at91sam9x5_clk_register_smd(struct regmap *regmap, const char *name,
+ const char **parent_names, u8 num_parents);
+
+struct clk_hw * __init
+at91_clk_register_system(struct regmap *regmap, const char *name,
+ const char *parent_name, u8 id);
+
+struct clk_hw * __init
+at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name,
+ const char **parent_names, u8 num_parents);
+struct clk_hw * __init
+at91sam9n12_clk_register_usb(struct regmap *regmap, const char *name,
+ const char *parent_name);
+struct clk_hw * __init
+at91rm9200_clk_register_usb(struct regmap *regmap, const char *name,
+ const char *parent_name, const u32 *divisors);
+
+struct clk_hw * __init
+at91_clk_register_utmi(struct regmap *regmap_pmc, struct regmap *regmap_sfr,
+ const char *name, const char *parent_name);
+
#ifdef CONFIG_PM
void pmc_register_id(u8 id);
void pmc_register_pck(u8 pck);
diff --git a/drivers/clk/at91/sama5d2.c b/drivers/clk/at91/sama5d2.c
new file mode 100644
index 000000000000..d69ad96fe988
--- /dev/null
+++ b/drivers/clk/at91/sama5d2.c
@@ -0,0 +1,336 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/clk-provider.h>
+#include <linux/mfd/syscon.h>
+#include <linux/slab.h>
+
+#include <dt-bindings/clock/at91.h>
+
+#include "pmc.h"
+
+static const struct clk_master_characteristics mck_characteristics = {
+ .output = { .min = 124000000, .max = 166000000 },
+ .divisors = { 1, 2, 4, 3 },
+};
+
+static u8 plla_out[] = { 0 };
+
+static u16 plla_icpll[] = { 0 };
+
+static struct clk_range plla_outputs[] = {
+ { .min = 600000000, .max = 1200000000 },
+};
+
+static const struct clk_pll_characteristics plla_characteristics = {
+ .input = { .min = 12000000, .max = 12000000 },
+ .num_output = ARRAY_SIZE(plla_outputs),
+ .output = plla_outputs,
+ .icpll = plla_icpll,
+ .out = plla_out,
+};
+
+static const struct {
+ char *n;
+ char *p;
+ u8 id;
+} sama5d2_systemck[] = {
+ { .n = "ddrck", .p = "masterck", .id = 2 },
+ { .n = "lcdck", .p = "masterck", .id = 3 },
+ { .n = "uhpck", .p = "usbck", .id = 6 },
+ { .n = "udpck", .p = "usbck", .id = 7 },
+ { .n = "pck0", .p = "prog0", .id = 8 },
+ { .n = "pck1", .p = "prog1", .id = 9 },
+ { .n = "pck2", .p = "prog2", .id = 10 },
+ { .n = "iscck", .p = "masterck", .id = 18 },
+};
+
+static const struct {
+ char *n;
+ u8 id;
+ struct clk_range r;
+} sama5d2_periph32ck[] = {
+ { .n = "macb0_clk", .id = 5, .r = { .min = 0, .max = 83000000 }, },
+ { .n = "tdes_clk", .id = 11, .r = { .min = 0, .max = 83000000 }, },
+ { .n = "matrix1_clk", .id = 14, },
+ { .n = "hsmc_clk", .id = 17, },
+ { .n = "pioA_clk", .id = 18, .r = { .min = 0, .max = 83000000 }, },
+ { .n = "flx0_clk", .id = 19, .r = { .min = 0, .max = 83000000 }, },
+ { .n = "flx1_clk", .id = 20, .r = { .min = 0, .max = 83000000 }, },
+ { .n = "flx2_clk", .id = 21, .r = { .min = 0, .max = 83000000 }, },
+ { .n = "flx3_clk", .id = 22, .r = { .min = 0, .max = 83000000 }, },
+ { .n = "flx4_clk", .id = 23, .r = { .min = 0, .max = 83000000 }, },
+ { .n = "uart0_clk", .id = 24, .r = { .min = 0, .max = 83000000 }, },
+ { .n = "uart1_clk", .id = 25, .r = { .min = 0, .max = 83000000 }, },
+ { .n = "uart2_clk", .id = 26, .r = { .min = 0, .max = 83000000 }, },
+ { .n = "uart3_clk", .id = 27, .r = { .min = 0, .max = 83000000 }, },
+ { .n = "uart4_clk", .id = 28, .r = { .min = 0, .max = 83000000 }, },
+ { .n = "twi0_clk", .id = 29, .r = { .min = 0, .max = 83000000 }, },
+ { .n = "twi1_clk", .id = 30, .r = { .min = 0, .max = 83000000 }, },
+ { .n = "spi0_clk", .id = 33, .r = { .min = 0, .max = 83000000 }, },
+ { .n = "spi1_clk", .id = 34, .r = { .min = 0, .max = 83000000 }, },
+ { .n = "tcb0_clk", .id = 35, .r = { .min = 0, .max = 83000000 }, },
+ { .n = "tcb1_clk", .id = 36, .r = { .min = 0, .max = 83000000 }, },
+ { .n = "pwm_clk", .id = 38, .r = { .min = 0, .max = 83000000 }, },
+ { .n = "adc_clk", .id = 40, .r = { .min = 0, .max = 83000000 }, },
+ { .n = "uhphs_clk", .id = 41, .r = { .min = 0, .max = 83000000 }, },
+ { .n = "udphs_clk", .id = 42, .r = { .min = 0, .max = 83000000 }, },
+ { .n = "ssc0_clk", .id = 43, .r = { .min = 0, .max = 83000000 }, },
+ { .n = "ssc1_clk", .id = 44, .r = { .min = 0, .max = 83000000 }, },
+ { .n = "trng_clk", .id = 47, .r = { .min = 0, .max = 83000000 }, },
+ { .n = "pdmic_clk", .id = 48, .r = { .min = 0, .max = 83000000 }, },
+ { .n = "securam_clk", .id = 51, },
+ { .n = "i2s0_clk", .id = 54, .r = { .min = 0, .max = 83000000 }, },
+ { .n = "i2s1_clk", .id = 55, .r = { .min = 0, .max = 83000000 }, },
+ { .n = "can0_clk", .id = 56, .r = { .min = 0, .max = 83000000 }, },
+ { .n = "can1_clk", .id = 57, .r = { .min = 0, .max = 83000000 }, },
+ { .n = "classd_clk", .id = 59, .r = { .min = 0, .max = 83000000 }, },
+};
+
+static const struct {
+ char *n;
+ u8 id;
+} sama5d2_periphck[] = {
+ { .n = "dma0_clk", .id = 6, },
+ { .n = "dma1_clk", .id = 7, },
+ { .n = "aes_clk", .id = 9, },
+ { .n = "aesb_clk", .id = 10, },
+ { .n = "sha_clk", .id = 12, },
+ { .n = "mpddr_clk", .id = 13, },
+ { .n = "matrix0_clk", .id = 15, },
+ { .n = "sdmmc0_hclk", .id = 31, },
+ { .n = "sdmmc1_hclk", .id = 32, },
+ { .n = "lcdc_clk", .id = 45, },
+ { .n = "isc_clk", .id = 46, },
+ { .n = "qspi0_clk", .id = 52, },
+ { .n = "qspi1_clk", .id = 53, },
+};
+
+static const struct {
+ char *n;
+ u8 id;
+ struct clk_range r;
+ bool pll;
+} sama5d2_gck[] = {
+ { .n = "sdmmc0_gclk", .id = 31, },
+ { .n = "sdmmc1_gclk", .id = 32, },
+ { .n = "tcb0_gclk", .id = 35, .r = { .min = 0, .max = 83000000 }, },
+ { .n = "tcb1_gclk", .id = 36, .r = { .min = 0, .max = 83000000 }, },
+ { .n = "pwm_gclk", .id = 38, .r = { .min = 0, .max = 83000000 }, },
+ { .n = "isc_gclk", .id = 46, },
+ { .n = "pdmic_gclk", .id = 48, },
+ { .n = "i2s0_gclk", .id = 54, .pll = true },
+ { .n = "i2s1_gclk", .id = 55, .pll = true },
+ { .n = "can0_gclk", .id = 56, .r = { .min = 0, .max = 80000000 }, },
+ { .n = "can1_gclk", .id = 57, .r = { .min = 0, .max = 80000000 }, },
+ { .n = "classd_gclk", .id = 59, .r = { .min = 0, .max = 100000000 },
+ .pll = true },
+};
+
+static void __init sama5d2_pmc_setup(struct device_node *np)
+{
+ struct clk_range range = CLK_RANGE(0, 0);
+ const char *slck_name, *mainxtal_name;
+ struct pmc_data *sama5d2_pmc;
+ const char *parent_names[6];
+ struct regmap *regmap, *regmap_sfr;
+ struct clk_hw *hw;
+ int i;
+ bool bypass;
+
+ i = of_property_match_string(np, "clock-names", "slow_clk");
+ if (i < 0)
+ return;
+
+ slck_name = of_clk_get_parent_name(np, i);
+
+ i = of_property_match_string(np, "clock-names", "main_xtal");
+ if (i < 0)
+ return;
+ mainxtal_name = of_clk_get_parent_name(np, i);
+
+ regmap = syscon_node_to_regmap(np);
+ if (IS_ERR(regmap))
+ return;
+
+ sama5d2_pmc = pmc_data_allocate(PMC_I2S1_MUX + 1,
+ nck(sama5d2_systemck),
+ nck(sama5d2_periph32ck),
+ nck(sama5d2_gck));
+ if (!sama5d2_pmc)
+ return;
+
+ hw = at91_clk_register_main_rc_osc(regmap, "main_rc_osc", 12000000,
+ 100000000);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ bypass = of_property_read_bool(np, "atmel,osc-bypass");
+
+ hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name,
+ bypass);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ parent_names[0] = "main_rc_osc";
+ parent_names[1] = "main_osc";
+ hw = at91_clk_register_sam9x5_main(regmap, "mainck", parent_names, 2);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ sama5d2_pmc->chws[PMC_MAIN] = hw;
+
+ hw = at91_clk_register_pll(regmap, "pllack", "mainck", 0,
+ &sama5d3_pll_layout, &plla_characteristics);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ hw = at91_clk_register_plldiv(regmap, "plladivck", "pllack");
+ if (IS_ERR(hw))
+ goto err_free;
+
+ hw = at91_clk_register_audio_pll_frac(regmap, "audiopll_fracck",
+ "mainck");
+ if (IS_ERR(hw))
+ goto err_free;
+
+ hw = at91_clk_register_audio_pll_pad(regmap, "audiopll_padck",
+ "audiopll_fracck");
+ if (IS_ERR(hw))
+ goto err_free;
+
+ hw = at91_clk_register_audio_pll_pmc(regmap, "audiopll_pmcck",
+ "audiopll_fracck");
+ if (IS_ERR(hw))
+ goto err_free;
+
+ regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr");
+ if (IS_ERR(regmap_sfr))
+ regmap_sfr = NULL;
+
+ hw = at91_clk_register_utmi(regmap, regmap_sfr, "utmick", "mainck");
+ if (IS_ERR(hw))
+ goto err_free;
+
+ sama5d2_pmc->chws[PMC_UTMI] = hw;
+
+ parent_names[0] = slck_name;
+ parent_names[1] = "mainck";
+ parent_names[2] = "plladivck";
+ parent_names[3] = "utmick";
+ hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
+ &at91sam9x5_master_layout,
+ &mck_characteristics);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ sama5d2_pmc->chws[PMC_MCK] = hw;
+
+ hw = at91_clk_register_h32mx(regmap, "h32mxck", "masterck");
+ if (IS_ERR(hw))
+ goto err_free;
+
+ sama5d2_pmc->chws[PMC_MCK2] = hw;
+
+ parent_names[0] = "plladivck";
+ parent_names[1] = "utmick";
+ hw = at91sam9x5_clk_register_usb(regmap, "usbck", parent_names, 2);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ parent_names[0] = slck_name;
+ parent_names[1] = "mainck";
+ parent_names[2] = "plladivck";
+ parent_names[3] = "utmick";
+ parent_names[4] = "mck";
+ for (i = 0; i < 3; i++) {
+ char name[6];
+
+ snprintf(name, sizeof(name), "prog%d", i);
+
+ hw = at91_clk_register_programmable(regmap, name,
+ parent_names, 5, i,
+ &at91sam9x5_programmable_layout);
+ if (IS_ERR(hw))
+ goto err_free;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(sama5d2_systemck); i++) {
+ hw = at91_clk_register_system(regmap, sama5d2_systemck[i].n,
+ sama5d2_systemck[i].p,
+ sama5d2_systemck[i].id);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ sama5d2_pmc->shws[sama5d2_systemck[i].id] = hw;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(sama5d2_periphck); i++) {
+ hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
+ sama5d2_periphck[i].n,
+ "masterck",
+ sama5d2_periphck[i].id,
+ &range);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ sama5d2_pmc->phws[sama5d2_periphck[i].id] = hw;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(sama5d2_periph32ck); i++) {
+ hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
+ sama5d2_periph32ck[i].n,
+ "h32mxck",
+ sama5d2_periph32ck[i].id,
+ &sama5d2_periph32ck[i].r);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ sama5d2_pmc->phws[sama5d2_periph32ck[i].id] = hw;
+ }
+
+ parent_names[0] = slck_name;
+ parent_names[1] = "mainck";
+ parent_names[2] = "plladivck";
+ parent_names[3] = "utmick";
+ parent_names[4] = "mck";
+ parent_names[5] = "audiopll_pmcck";
+ for (i = 0; i < ARRAY_SIZE(sama5d2_gck); i++) {
+ hw = at91_clk_register_generated(regmap, &pmc_pcr_lock,
+ sama5d2_gck[i].n,
+ parent_names, 6,
+ sama5d2_gck[i].id,
+ sama5d2_gck[i].pll,
+ &sama5d2_gck[i].r);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ sama5d2_pmc->ghws[sama5d2_gck[i].id] = hw;
+ }
+
+ if (regmap_sfr) {
+ parent_names[0] = "i2s0_clk";
+ parent_names[1] = "i2s0_gclk";
+ hw = at91_clk_i2s_mux_register(regmap_sfr, "i2s0_muxclk",
+ parent_names, 2, 0);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ sama5d2_pmc->chws[PMC_I2S0_MUX] = hw;
+
+ parent_names[0] = "i2s1_clk";
+ parent_names[1] = "i2s1_gclk";
+ hw = at91_clk_i2s_mux_register(regmap_sfr, "i2s1_muxclk",
+ parent_names, 2, 1);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ sama5d2_pmc->chws[PMC_I2S1_MUX] = hw;
+ }
+
+ of_clk_add_hw_provider(np, of_clk_hw_pmc_get, sama5d2_pmc);
+
+ return;
+
+err_free:
+ pmc_data_free(sama5d2_pmc);
+}
+CLK_OF_DECLARE_DRIVER(sama5d2_pmc, "atmel,sama5d2-pmc", sama5d2_pmc_setup);
diff --git a/drivers/clk/at91/sama5d4.c b/drivers/clk/at91/sama5d4.c
new file mode 100644
index 000000000000..e358be7f6c8d
--- /dev/null
+++ b/drivers/clk/at91/sama5d4.c
@@ -0,0 +1,264 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/clk-provider.h>
+#include <linux/mfd/syscon.h>
+#include <linux/slab.h>
+
+#include <dt-bindings/clock/at91.h>
+
+#include "pmc.h"
+
+static const struct clk_master_characteristics mck_characteristics = {
+ .output = { .min = 125000000, .max = 200000000 },
+ .divisors = { 1, 2, 4, 3 },
+};
+
+static u8 plla_out[] = { 0 };
+
+static u16 plla_icpll[] = { 0 };
+
+static struct clk_range plla_outputs[] = {
+ { .min = 600000000, .max = 1200000000 },
+};
+
+static const struct clk_pll_characteristics plla_characteristics = {
+ .input = { .min = 12000000, .max = 12000000 },
+ .num_output = ARRAY_SIZE(plla_outputs),
+ .output = plla_outputs,
+ .icpll = plla_icpll,
+ .out = plla_out,
+};
+
+static const struct {
+ char *n;
+ char *p;
+ u8 id;
+} sama5d4_systemck[] = {
+ { .n = "ddrck", .p = "masterck", .id = 2 },
+ { .n = "lcdck", .p = "masterck", .id = 3 },
+ { .n = "smdck", .p = "smdclk", .id = 4 },
+ { .n = "uhpck", .p = "usbck", .id = 6 },
+ { .n = "udpck", .p = "usbck", .id = 7 },
+ { .n = "pck0", .p = "prog0", .id = 8 },
+ { .n = "pck1", .p = "prog1", .id = 9 },
+ { .n = "pck2", .p = "prog2", .id = 10 },
+};
+
+static const struct {
+ char *n;
+ u8 id;
+} sama5d4_periph32ck[] = {
+ { .n = "pioD_clk", .id = 5 },
+ { .n = "usart0_clk", .id = 6 },
+ { .n = "usart1_clk", .id = 7 },
+ { .n = "icm_clk", .id = 9 },
+ { .n = "aes_clk", .id = 12 },
+ { .n = "tdes_clk", .id = 14 },
+ { .n = "sha_clk", .id = 15 },
+ { .n = "matrix1_clk", .id = 17 },
+ { .n = "hsmc_clk", .id = 22 },
+ { .n = "pioA_clk", .id = 23 },
+ { .n = "pioB_clk", .id = 24 },
+ { .n = "pioC_clk", .id = 25 },
+ { .n = "pioE_clk", .id = 26 },
+ { .n = "uart0_clk", .id = 27 },
+ { .n = "uart1_clk", .id = 28 },
+ { .n = "usart2_clk", .id = 29 },
+ { .n = "usart3_clk", .id = 30 },
+ { .n = "usart4_clk", .id = 31 },
+ { .n = "twi0_clk", .id = 32 },
+ { .n = "twi1_clk", .id = 33 },
+ { .n = "twi2_clk", .id = 34 },
+ { .n = "mci0_clk", .id = 35 },
+ { .n = "mci1_clk", .id = 36 },
+ { .n = "spi0_clk", .id = 37 },
+ { .n = "spi1_clk", .id = 38 },
+ { .n = "spi2_clk", .id = 39 },
+ { .n = "tcb0_clk", .id = 40 },
+ { .n = "tcb1_clk", .id = 41 },
+ { .n = "tcb2_clk", .id = 42 },
+ { .n = "pwm_clk", .id = 43 },
+ { .n = "adc_clk", .id = 44 },
+ { .n = "dbgu_clk", .id = 45 },
+ { .n = "uhphs_clk", .id = 46 },
+ { .n = "udphs_clk", .id = 47 },
+ { .n = "ssc0_clk", .id = 48 },
+ { .n = "ssc1_clk", .id = 49 },
+ { .n = "trng_clk", .id = 53 },
+ { .n = "macb0_clk", .id = 54 },
+ { .n = "macb1_clk", .id = 55 },
+ { .n = "fuse_clk", .id = 57 },
+ { .n = "securam_clk", .id = 59 },
+ { .n = "smd_clk", .id = 61 },
+ { .n = "twi3_clk", .id = 62 },
+ { .n = "catb_clk", .id = 63 },
+};
+
+static const struct {
+ char *n;
+ u8 id;
+} sama5d4_periphck[] = {
+ { .n = "dma0_clk", .id = 8 },
+ { .n = "cpkcc_clk", .id = 10 },
+ { .n = "aesb_clk", .id = 13 },
+ { .n = "mpddr_clk", .id = 16 },
+ { .n = "matrix0_clk", .id = 18 },
+ { .n = "vdec_clk", .id = 19 },
+ { .n = "dma1_clk", .id = 50 },
+ { .n = "lcdc_clk", .id = 51 },
+ { .n = "isi_clk", .id = 52 },
+};
+
+static void __init sama5d4_pmc_setup(struct device_node *np)
+{
+ struct clk_range range = CLK_RANGE(0, 0);
+ const char *slck_name, *mainxtal_name;
+ struct pmc_data *sama5d4_pmc;
+ const char *parent_names[5];
+ struct regmap *regmap;
+ struct clk_hw *hw;
+ int i;
+ bool bypass;
+
+ i = of_property_match_string(np, "clock-names", "slow_clk");
+ if (i < 0)
+ return;
+
+ slck_name = of_clk_get_parent_name(np, i);
+
+ i = of_property_match_string(np, "clock-names", "main_xtal");
+ if (i < 0)
+ return;
+ mainxtal_name = of_clk_get_parent_name(np, i);
+
+ regmap = syscon_node_to_regmap(np);
+ if (IS_ERR(regmap))
+ return;
+
+ sama5d4_pmc = pmc_data_allocate(PMC_MCK2 + 1,
+ nck(sama5d4_systemck),
+ nck(sama5d4_periph32ck), 0);
+ if (!sama5d4_pmc)
+ return;
+
+ hw = at91_clk_register_main_rc_osc(regmap, "main_rc_osc", 12000000,
+ 100000000);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ bypass = of_property_read_bool(np, "atmel,osc-bypass");
+
+ hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name,
+ bypass);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ parent_names[0] = "main_rc_osc";
+ parent_names[1] = "main_osc";
+ hw = at91_clk_register_sam9x5_main(regmap, "mainck", parent_names, 2);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ hw = at91_clk_register_pll(regmap, "pllack", "mainck", 0,
+ &sama5d3_pll_layout, &plla_characteristics);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ hw = at91_clk_register_plldiv(regmap, "plladivck", "pllack");
+ if (IS_ERR(hw))
+ goto err_free;
+
+ hw = at91_clk_register_utmi(regmap, NULL, "utmick", "mainck");
+ if (IS_ERR(hw))
+ goto err_free;
+
+ sama5d4_pmc->chws[PMC_UTMI] = hw;
+
+ parent_names[0] = slck_name;
+ parent_names[1] = "mainck";
+ parent_names[2] = "plladivck";
+ parent_names[3] = "utmick";
+ hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
+ &at91sam9x5_master_layout,
+ &mck_characteristics);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ sama5d4_pmc->chws[PMC_MCK] = hw;
+
+ hw = at91_clk_register_h32mx(regmap, "h32mxck", "masterck");
+ if (IS_ERR(hw))
+ goto err_free;
+
+ sama5d4_pmc->chws[PMC_MCK2] = hw;
+
+ parent_names[0] = "plladivck";
+ parent_names[1] = "utmick";
+ hw = at91sam9x5_clk_register_usb(regmap, "usbck", parent_names, 2);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ parent_names[0] = "plladivck";
+ parent_names[1] = "utmick";
+ hw = at91sam9x5_clk_register_smd(regmap, "smdclk", parent_names, 2);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ parent_names[0] = slck_name;
+ parent_names[1] = "mainck";
+ parent_names[2] = "plladivck";
+ parent_names[3] = "utmick";
+ parent_names[4] = "mck";
+ for (i = 0; i < 3; i++) {
+ char name[6];
+
+ snprintf(name, sizeof(name), "prog%d", i);
+
+ hw = at91_clk_register_programmable(regmap, name,
+ parent_names, 5, i,
+ &at91sam9x5_programmable_layout);
+ if (IS_ERR(hw))
+ goto err_free;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(sama5d4_systemck); i++) {
+ hw = at91_clk_register_system(regmap, sama5d4_systemck[i].n,
+ sama5d4_systemck[i].p,
+ sama5d4_systemck[i].id);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ sama5d4_pmc->shws[sama5d4_systemck[i].id] = hw;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(sama5d4_periphck); i++) {
+ hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
+ sama5d4_periphck[i].n,
+ "masterck",
+ sama5d4_periphck[i].id,
+ &range);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ sama5d4_pmc->phws[sama5d4_periphck[i].id] = hw;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(sama5d4_periph32ck); i++) {
+ hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
+ sama5d4_periph32ck[i].n,
+ "h32mxck",
+ sama5d4_periph32ck[i].id,
+ &range);
+ if (IS_ERR(hw))
+ goto err_free;
+
+ sama5d4_pmc->phws[sama5d4_periph32ck[i].id] = hw;
+ }
+
+ of_clk_add_hw_provider(np, of_clk_hw_pmc_get, sama5d4_pmc);
+
+ return;
+
+err_free:
+ pmc_data_free(sama5d4_pmc);
+}
+CLK_OF_DECLARE_DRIVER(sama5d4_pmc, "atmel,sama5d4-pmc", sama5d4_pmc_setup);
diff --git a/drivers/clk/axs10x/pll_clock.c b/drivers/clk/axs10x/pll_clock.c
index 25d8c240ddfb..c68dada97316 100644
--- a/drivers/clk/axs10x/pll_clock.c
+++ b/drivers/clk/axs10x/pll_clock.c
@@ -301,13 +301,13 @@ static void __init of_axs10x_pll_clk_setup(struct device_node *node)
ret = clk_hw_register(NULL, &pll_clk->hw);
if (ret) {
- pr_err("failed to register %s clock\n", node->name);
+ pr_err("failed to register %pOFn clock\n", node);
goto err_unmap_lock;
}
ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, &pll_clk->hw);
if (ret) {
- pr_err("failed to add hw provider for %s clock\n", node->name);
+ pr_err("failed to add hw provider for %pOFn clock\n", node);
goto err_unregister_clk;
}
diff --git a/drivers/clk/bcm/clk-kona-setup.c b/drivers/clk/bcm/clk-kona-setup.c
index 281f4322355c..e65eeef9cbaf 100644
--- a/drivers/clk/bcm/clk-kona-setup.c
+++ b/drivers/clk/bcm/clk-kona-setup.c
@@ -808,29 +808,29 @@ void __init kona_dt_ccu_setup(struct ccu_data *ccu,
ret = of_address_to_resource(node, 0, &res);
if (ret) {
- pr_err("%s: no valid CCU registers found for %s\n", __func__,
- node->name);
+ pr_err("%s: no valid CCU registers found for %pOFn\n", __func__,
+ node);
goto out_err;
}
range = resource_size(&res);
if (range > (resource_size_t)U32_MAX) {
- pr_err("%s: address range too large for %s\n", __func__,
- node->name);
+ pr_err("%s: address range too large for %pOFn\n", __func__,
+ node);
goto out_err;
}
ccu->range = (u32)range;
if (!ccu_data_valid(ccu)) {
- pr_err("%s: ccu data not valid for %s\n", __func__, node->name);
+ pr_err("%s: ccu data not valid for %pOFn\n", __func__, node);
goto out_err;
}
ccu->base = ioremap(res.start, ccu->range);
if (!ccu->base) {
- pr_err("%s: unable to map CCU registers for %s\n", __func__,
- node->name);
+ pr_err("%s: unable to map CCU registers for %pOFn\n", __func__,
+ node);
goto out_err;
}
ccu->node = of_node_get(node);
@@ -848,16 +848,16 @@ void __init kona_dt_ccu_setup(struct ccu_data *ccu,
ret = of_clk_add_hw_provider(node, of_clk_kona_onecell_get, ccu);
if (ret) {
- pr_err("%s: error adding ccu %s as provider (%d)\n", __func__,
- node->name, ret);
+ pr_err("%s: error adding ccu %pOFn as provider (%d)\n", __func__,
+ node, ret);
goto out_err;
}
if (!kona_ccu_init(ccu))
- pr_err("Broadcom %s initialization had errors\n", node->name);
+ pr_err("Broadcom %pOFn initialization had errors\n", node);
return;
out_err:
kona_ccu_teardown(ccu);
- pr_err("Broadcom %s setup aborted\n", node->name);
+ pr_err("Broadcom %pOFn setup aborted\n", node);
}
diff --git a/drivers/clk/clk-asm9260.c b/drivers/clk/clk-asm9260.c
index 44b544157121..d571a00b5282 100644
--- a/drivers/clk/clk-asm9260.c
+++ b/drivers/clk/clk-asm9260.c
@@ -281,7 +281,7 @@ static void __init asm9260_acc_init(struct device_node *np)
base = of_io_request_and_map(np, 0, np->name);
if (IS_ERR(base))
- panic("%s: unable to map resource", np->name);
+ panic("%pOFn: unable to map resource", np);
/* register pll */
rate = (ioread32(base + HW_SYSPLLCTRL) & 0xffff) * 1000000;
@@ -292,7 +292,7 @@ static void __init asm9260_acc_init(struct device_node *np)
ref_clk, 0, rate, accuracy);
if (IS_ERR(hw))
- panic("%s: can't register REFCLK. Check DT!", np->name);
+ panic("%pOFn: can't register REFCLK. Check DT!", np);
for (n = 0; n < ARRAY_SIZE(asm9260_mux_clks); n++) {
const struct asm9260_mux_clock *mc = &asm9260_mux_clks[n];
diff --git a/drivers/clk/clk-bulk.c b/drivers/clk/clk-bulk.c
index 6904ed6da504..6a7118d4250a 100644
--- a/drivers/clk/clk-bulk.c
+++ b/drivers/clk/clk-bulk.c
@@ -17,8 +17,65 @@
*/
#include <linux/clk.h>
+#include <linux/clk-provider.h>
#include <linux/device.h>
#include <linux/export.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+
+static int __must_check of_clk_bulk_get(struct device_node *np, int num_clks,
+ struct clk_bulk_data *clks)
+{
+ int ret;
+ int i;
+
+ for (i = 0; i < num_clks; i++)
+ clks[i].clk = NULL;
+
+ for (i = 0; i < num_clks; i++) {
+ clks[i].clk = of_clk_get(np, i);
+ if (IS_ERR(clks[i].clk)) {
+ ret = PTR_ERR(clks[i].clk);
+ pr_err("%pOF: Failed to get clk index: %d ret: %d\n",
+ np, i, ret);
+ clks[i].clk = NULL;
+ goto err;
+ }
+ }
+
+ return 0;
+
+err:
+ clk_bulk_put(i, clks);
+
+ return ret;
+}
+
+static int __must_check of_clk_bulk_get_all(struct device_node *np,
+ struct clk_bulk_data **clks)
+{
+ struct clk_bulk_data *clk_bulk;
+ int num_clks;
+ int ret;
+
+ num_clks = of_clk_get_parent_count(np);
+ if (!num_clks)
+ return 0;
+
+ clk_bulk = kmalloc_array(num_clks, sizeof(*clk_bulk), GFP_KERNEL);
+ if (!clk_bulk)
+ return -ENOMEM;
+
+ ret = of_clk_bulk_get(np, num_clks, clk_bulk);
+ if (ret) {
+ kfree(clk_bulk);
+ return ret;
+ }
+
+ *clks = clk_bulk;
+
+ return num_clks;
+}
void clk_bulk_put(int num_clks, struct clk_bulk_data *clks)
{
@@ -59,6 +116,29 @@ err:
}
EXPORT_SYMBOL(clk_bulk_get);
+void clk_bulk_put_all(int num_clks, struct clk_bulk_data *clks)
+{
+ if (IS_ERR_OR_NULL(clks))
+ return;
+
+ clk_bulk_put(num_clks, clks);
+
+ kfree(clks);
+}
+EXPORT_SYMBOL(clk_bulk_put_all);
+
+int __must_check clk_bulk_get_all(struct device *dev,
+ struct clk_bulk_data **clks)
+{
+ struct device_node *np = dev_of_node(dev);
+
+ if (!np)
+ return 0;
+
+ return of_clk_bulk_get_all(np, clks);
+}
+EXPORT_SYMBOL(clk_bulk_get_all);
+
#ifdef CONFIG_HAVE_CLK_PREPARE
/**
diff --git a/drivers/clk/clk-cdce925.c b/drivers/clk/clk-cdce925.c
index 0a7e7d5a7506..23c9326ea48c 100644
--- a/drivers/clk/clk-cdce925.c
+++ b/drivers/clk/clk-cdce925.c
@@ -669,8 +669,8 @@ static int cdce925_probe(struct i2c_client *client,
/* Register PLL clocks */
for (i = 0; i < data->chip_info->num_plls; ++i) {
- pll_clk_name[i] = kasprintf(GFP_KERNEL, "%s.pll%d",
- client->dev.of_node->name, i);
+ pll_clk_name[i] = kasprintf(GFP_KERNEL, "%pOFn.pll%d",
+ client->dev.of_node, i);
init.name = pll_clk_name[i];
data->pll[i].chip = data;
data->pll[i].hw.init = &init;
@@ -703,6 +703,7 @@ static int cdce925_probe(struct i2c_client *client,
0x12 + (i*CDCE925_OFFSET_PLL),
0x07, value & 0x07);
}
+ of_node_put(np_output);
}
/* Register output clock Y1 */
@@ -710,7 +711,7 @@ static int cdce925_probe(struct i2c_client *client,
init.flags = 0;
init.num_parents = 1;
init.parent_names = &parent_name; /* Mux Y1 to input */
- init.name = kasprintf(GFP_KERNEL, "%s.Y1", client->dev.of_node->name);
+ init.name = kasprintf(GFP_KERNEL, "%pOFn.Y1", client->dev.of_node);
data->clk[0].chip = data;
data->clk[0].hw.init = &init;
data->clk[0].index = 0;
@@ -727,8 +728,8 @@ static int cdce925_probe(struct i2c_client *client,
init.flags = CLK_SET_RATE_PARENT;
init.num_parents = 1;
for (i = 1; i < data->chip_info->num_outputs; ++i) {
- init.name = kasprintf(GFP_KERNEL, "%s.Y%d",
- client->dev.of_node->name, i+1);
+ init.name = kasprintf(GFP_KERNEL, "%pOFn.Y%d",
+ client->dev.of_node, i+1);
data->clk[i].chip = data;
data->clk[i].hw.init = &init;
data->clk[i].index = i;
diff --git a/drivers/clk/clk-devres.c b/drivers/clk/clk-devres.c
index d854e26a8ddb..12c87457eca1 100644
--- a/drivers/clk/clk-devres.c
+++ b/drivers/clk/clk-devres.c
@@ -70,6 +70,30 @@ int __must_check devm_clk_bulk_get(struct device *dev, int num_clks,
}
EXPORT_SYMBOL_GPL(devm_clk_bulk_get);
+int __must_check devm_clk_bulk_get_all(struct device *dev,
+ struct clk_bulk_data **clks)
+{
+ struct clk_bulk_devres *devres;
+ int ret;
+
+ devres = devres_alloc(devm_clk_bulk_release,
+ sizeof(*devres), GFP_KERNEL);
+ if (!devres)
+ return -ENOMEM;
+
+ ret = clk_bulk_get_all(dev, &devres->clks);
+ if (ret > 0) {
+ *clks = devres->clks;
+ devres->num_clks = ret;
+ devres_add(dev, devres);
+ } else {
+ devres_free(devres);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all);
+
static int devm_clk_match(struct device *dev, void *res, void *data)
{
struct clk **c = res;
diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c
index 20724abd38bd..ff83e899df71 100644
--- a/drivers/clk/clk-fixed-factor.c
+++ b/drivers/clk/clk-fixed-factor.c
@@ -158,14 +158,14 @@ static struct clk *_of_fixed_factor_clk_setup(struct device_node *node)
int ret;
if (of_property_read_u32(node, "clock-div", &div)) {
- pr_err("%s Fixed factor clock <%s> must have a clock-div property\n",
- __func__, node->name);
+ pr_err("%s Fixed factor clock <%pOFn> must have a clock-div property\n",
+ __func__, node);
return ERR_PTR(-EIO);
}
if (of_property_read_u32(node, "clock-mult", &mult)) {
- pr_err("%s Fixed factor clock <%s> must have a clock-mult property\n",
- __func__, node->name);
+ pr_err("%s Fixed factor clock <%pOFn> must have a clock-mult property\n",
+ __func__, node);
return ERR_PTR(-EIO);
}
@@ -210,6 +210,7 @@ static int of_fixed_factor_clk_remove(struct platform_device *pdev)
{
struct clk *clk = platform_get_drvdata(pdev);
+ of_clk_del_provider(pdev->dev.of_node);
clk_unregister_fixed_factor(clk);
return 0;
diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c
index b5c46b3f8764..6d6475c32ee5 100644
--- a/drivers/clk/clk-fixed-rate.c
+++ b/drivers/clk/clk-fixed-rate.c
@@ -200,6 +200,7 @@ static int of_fixed_clk_remove(struct platform_device *pdev)
{
struct clk *clk = platform_get_drvdata(pdev);
+ of_clk_del_provider(pdev->dev.of_node);
clk_unregister_fixed_rate(clk);
return 0;
diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c
index 40af4fbab4d2..6a43ce420492 100644
--- a/drivers/clk/clk-gpio.c
+++ b/drivers/clk/clk-gpio.c
@@ -233,11 +233,11 @@ static int gpio_clk_driver_probe(struct platform_device *pdev)
if (IS_ERR(gpiod)) {
ret = PTR_ERR(gpiod);
if (ret == -EPROBE_DEFER)
- pr_debug("%s: %s: GPIOs not yet available, retry later\n",
- node->name, __func__);
+ pr_debug("%pOFn: %s: GPIOs not yet available, retry later\n",
+ node, __func__);
else
- pr_err("%s: %s: Can't get '%s' named GPIO property\n",
- node->name, __func__,
+ pr_err("%pOFn: %s: Can't get '%s' named GPIO property\n",
+ node, __func__,
gpio_name);
return ret;
}
diff --git a/drivers/clk/clk-hsdk-pll.c b/drivers/clk/clk-hsdk-pll.c
index c4ee280f454d..a47c2b600f20 100644
--- a/drivers/clk/clk-hsdk-pll.c
+++ b/drivers/clk/clk-hsdk-pll.c
@@ -390,13 +390,13 @@ static void __init of_hsdk_pll_clk_setup(struct device_node *node)
ret = clk_hw_register(NULL, &pll_clk->hw);
if (ret) {
- pr_err("failed to register %s clock\n", node->name);
+ pr_err("failed to register %pOFn clock\n", node);
goto err_unmap_spec_regs;
}
ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, &pll_clk->hw);
if (ret) {
- pr_err("failed to add hw provider for %s clock\n", node->name);
+ pr_err("failed to add hw provider for %pOFn clock\n", node);
goto err_unmap_spec_regs;
}
diff --git a/drivers/clk/clk-max77686.c b/drivers/clk/clk-max77686.c
index eb953d3b0b69..02551fe4b87c 100644
--- a/drivers/clk/clk-max77686.c
+++ b/drivers/clk/clk-max77686.c
@@ -1,24 +1,9 @@
-/*
- * clk-max77686.c - Clock driver for Maxim 77686/MAX77802
- *
- * Copyright (C) 2012 Samsung Electornics
- * Jonghwa Lee <jonghwa3.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// clk-max77686.c - Clock driver for Maxim 77686/MAX77802
+//
+// Copyright (C) 2012 Samsung Electornics
+// Jonghwa Lee <jonghwa3.lee@samsung.com>
#include <linux/kernel.h>
#include <linux/slab.h>
diff --git a/drivers/clk/clk-nomadik.c b/drivers/clk/clk-nomadik.c
index 13ad6d1e5090..84a24875c629 100644
--- a/drivers/clk/clk-nomadik.c
+++ b/drivers/clk/clk-nomadik.c
@@ -97,8 +97,8 @@ static void __init nomadik_src_init(void)
}
src_base = of_iomap(np, 0);
if (!src_base) {
- pr_err("%s: must have src parent node with REGS (%s)\n",
- __func__, np->name);
+ pr_err("%s: must have src parent node with REGS (%pOFn)\n",
+ __func__, np);
return;
}
diff --git a/drivers/clk/clk-npcm7xx.c b/drivers/clk/clk-npcm7xx.c
index c5edf8f2fd19..27a86b7a34db 100644
--- a/drivers/clk/clk-npcm7xx.c
+++ b/drivers/clk/clk-npcm7xx.c
@@ -549,7 +549,7 @@ static void __init npcm7xx_clk_init(struct device_node *clk_np)
ret = of_address_to_resource(clk_np, 0, &res);
if (ret) {
- pr_err("%s: failed to get resource, ret %d\n", clk_np->name,
+ pr_err("%pOFn: failed to get resource, ret %d\n", clk_np,
ret);
return;
}
diff --git a/drivers/clk/clk-palmas.c b/drivers/clk/clk-palmas.c
index 7f51c01085ab..e9612e7068e9 100644
--- a/drivers/clk/clk-palmas.c
+++ b/drivers/clk/clk-palmas.c
@@ -195,8 +195,8 @@ static void palmas_clks_get_clk_data(struct platform_device *pdev,
prop = PALMAS_EXT_CONTROL_NSLEEP;
break;
default:
- dev_warn(&pdev->dev, "%s: Invalid ext control option: %u\n",
- node->name, prop);
+ dev_warn(&pdev->dev, "%pOFn: Invalid ext control option: %u\n",
+ node, prop);
prop = 0;
break;
}
diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c
index 3a1812f65e5d..4c30b6e799ed 100644
--- a/drivers/clk/clk-qoriq.c
+++ b/drivers/clk/clk-qoriq.c
@@ -945,8 +945,8 @@ static void __init core_mux_init(struct device_node *np)
rc = of_clk_add_provider(np, of_clk_src_simple_get, clk);
if (rc) {
- pr_err("%s: Couldn't register clk provider for node %s: %d\n",
- __func__, np->name, rc);
+ pr_err("%s: Couldn't register clk provider for node %pOFn: %d\n",
+ __func__, np, rc);
return;
}
}
@@ -1199,8 +1199,8 @@ static void __init legacy_pll_init(struct device_node *np, int idx)
rc = of_clk_add_provider(np, of_clk_src_onecell_get, onecell_data);
if (rc) {
- pr_err("%s: Couldn't register clk provider for node %s: %d\n",
- __func__, np->name, rc);
+ pr_err("%s: Couldn't register clk provider for node %pOFn: %d\n",
+ __func__, np, rc);
goto err_cell;
}
@@ -1360,7 +1360,7 @@ static void __init clockgen_init(struct device_node *np)
is_old_ls1021a = true;
}
if (!clockgen.regs) {
- pr_err("%s(): %s: of_iomap() failed\n", __func__, np->name);
+ pr_err("%s(): %pOFn: of_iomap() failed\n", __func__, np);
return;
}
@@ -1406,8 +1406,8 @@ static void __init clockgen_init(struct device_node *np)
ret = of_clk_add_provider(np, clockgen_clk_get, &clockgen);
if (ret) {
- pr_err("%s: Couldn't register clk provider for node %s: %d\n",
- __func__, np->name, ret);
+ pr_err("%s: Couldn't register clk provider for node %pOFn: %d\n",
+ __func__, np, ret);
}
return;
diff --git a/drivers/clk/clk-s2mps11.c b/drivers/clk/clk-s2mps11.c
index d44e0eea31ec..5b419b82f7ca 100644
--- a/drivers/clk/clk-s2mps11.c
+++ b/drivers/clk/clk-s2mps11.c
@@ -1,19 +1,8 @@
-/*
- * clk-s2mps11.c - Clock driver for S2MPS11.
- *
- * Copyright (C) 2013,2014 Samsung Electornics
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// clk-s2mps11.c - Clock driver for S2MPS11.
+//
+// Copyright (C) 2013,2014 Samsung Electornics
#include <linux/module.h>
#include <linux/err.h>
@@ -28,12 +17,7 @@
#include <linux/mfd/samsung/s5m8767.h>
#include <linux/mfd/samsung/core.h>
-enum {
- S2MPS11_CLK_AP = 0,
- S2MPS11_CLK_CP,
- S2MPS11_CLK_BT,
- S2MPS11_CLKS_NUM,
-};
+#include <dt-bindings/clock/samsung,s2mps11.h>
struct s2mps11_clk {
struct sec_pmic_dev *iodev;
@@ -245,6 +229,36 @@ static const struct platform_device_id s2mps11_clk_id[] = {
};
MODULE_DEVICE_TABLE(platform, s2mps11_clk_id);
+#ifdef CONFIG_OF
+/*
+ * Device is instantiated through parent MFD device and device matching is done
+ * through platform_device_id.
+ *
+ * However if device's DT node contains proper clock compatible and driver is
+ * built as a module, then the *module* matching will be done trough DT aliases.
+ * This requires of_device_id table. In the same time this will not change the
+ * actual *device* matching so do not add .of_match_table.
+ */
+static const struct of_device_id s2mps11_dt_match[] __used = {
+ {
+ .compatible = "samsung,s2mps11-clk",
+ .data = (void *)S2MPS11X,
+ }, {
+ .compatible = "samsung,s2mps13-clk",
+ .data = (void *)S2MPS13X,
+ }, {
+ .compatible = "samsung,s2mps14-clk",
+ .data = (void *)S2MPS14X,
+ }, {
+ .compatible = "samsung,s5m8767-clk",
+ .data = (void *)S5M8767X,
+ }, {
+ /* Sentinel */
+ },
+};
+MODULE_DEVICE_TABLE(of, s2mps11_dt_match);
+#endif
+
static struct platform_driver s2mps11_clk_driver = {
.driver = {
.name = "s2mps11-clk",
diff --git a/drivers/clk/clk-scmi.c b/drivers/clk/clk-scmi.c
index a985bf5e1ac6..a2287c770d5c 100644
--- a/drivers/clk/clk-scmi.c
+++ b/drivers/clk/clk-scmi.c
@@ -132,7 +132,7 @@ static int scmi_clocks_probe(struct scmi_device *sdev)
count = handle->clk_ops->count_get(handle);
if (count < 0) {
- dev_err(dev, "%s: invalid clock output count\n", np->name);
+ dev_err(dev, "%pOFn: invalid clock output count\n", np);
return -EINVAL;
}
diff --git a/drivers/clk/clk-scpi.c b/drivers/clk/clk-scpi.c
index 25854722810e..d3ccc1cfccd5 100644
--- a/drivers/clk/clk-scpi.c
+++ b/drivers/clk/clk-scpi.c
@@ -207,7 +207,7 @@ static int scpi_clk_add(struct device *dev, struct device_node *np,
count = of_property_count_strings(np, "clock-output-names");
if (count < 0) {
- dev_err(dev, "%s: invalid clock output count\n", np->name);
+ dev_err(dev, "%pOFn: invalid clock output count\n", np);
return -EINVAL;
}
@@ -232,13 +232,13 @@ static int scpi_clk_add(struct device *dev, struct device_node *np,
if (of_property_read_string_index(np, "clock-output-names",
idx, &name)) {
- dev_err(dev, "invalid clock name @ %s\n", np->name);
+ dev_err(dev, "invalid clock name @ %pOFn\n", np);
return -EINVAL;
}
if (of_property_read_u32_index(np, "clock-indices",
idx, &val)) {
- dev_err(dev, "invalid clock index @ %s\n", np->name);
+ dev_err(dev, "invalid clock index @ %pOFn\n", np);
return -EINVAL;
}
diff --git a/drivers/clk/clk-si5351.c b/drivers/clk/clk-si5351.c
index 50e7c341e97e..8bdf91b56012 100644
--- a/drivers/clk/clk-si5351.c
+++ b/drivers/clk/clk-si5351.c
@@ -1215,8 +1215,8 @@ static int si5351_dt_parse(struct i2c_client *client,
/* per clkout properties */
for_each_child_of_node(np, child) {
if (of_property_read_u32(child, "reg", &num)) {
- dev_err(&client->dev, "missing reg property of %s\n",
- child->name);
+ dev_err(&client->dev, "missing reg property of %pOFn\n",
+ child);
goto put_child;
}
diff --git a/drivers/clk/clk-stm32f4.c b/drivers/clk/clk-stm32f4.c
index 294850bdc195..cdaa567c8042 100644
--- a/drivers/clk/clk-stm32f4.c
+++ b/drivers/clk/clk-stm32f4.c
@@ -1433,7 +1433,7 @@ static void __init stm32f4_rcc_init(struct device_node *np)
base = of_iomap(np, 0);
if (!base) {
- pr_err("%s: unable to map resource\n", np->name);
+ pr_err("%pOFn: unable to map resource\n", np);
return;
}
diff --git a/drivers/clk/clk-stm32h7.c b/drivers/clk/clk-stm32h7.c
index d3271eca3779..0ea7261d15e0 100644
--- a/drivers/clk/clk-stm32h7.c
+++ b/drivers/clk/clk-stm32h7.c
@@ -1216,7 +1216,7 @@ static void __init stm32h7_rcc_init(struct device_node *np)
/* get RCC base @ from DT */
base = of_iomap(np, 0);
if (!base) {
- pr_err("%s: unable to map resource", np->name);
+ pr_err("%pOFn: unable to map resource", np);
goto err_free_clks;
}
diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c
index a907555b2a3d..4f48342bc280 100644
--- a/drivers/clk/clk-stm32mp1.c
+++ b/drivers/clk/clk-stm32mp1.c
@@ -2088,7 +2088,7 @@ static void stm32mp1_rcc_init(struct device_node *np)
base = of_iomap(np, 0);
if (!base) {
- pr_err("%s: unable to map resource", np->name);
+ pr_err("%pOFn: unable to map resource", np);
of_node_put(np);
return;
}
diff --git a/drivers/clk/clk-tango4.c b/drivers/clk/clk-tango4.c
index 34b22b7930fb..fe12a43f7a40 100644
--- a/drivers/clk/clk-tango4.c
+++ b/drivers/clk/clk-tango4.c
@@ -54,13 +54,13 @@ static void __init tango4_clkgen_setup(struct device_node *np)
const char *parent = of_clk_get_parent_name(np, 0);
if (!base)
- panic("%s: invalid address\n", np->name);
+ panic("%pOFn: invalid address\n", np);
if (readl(base + CPUCLK_DIV) & DIV_BYPASS)
- panic("%s: unsupported cpuclk setup\n", np->name);
+ panic("%pOFn: unsupported cpuclk setup\n", np);
if (readl(base + SYSCLK_DIV) & DIV_BYPASS)
- panic("%s: unsupported sysclk setup\n", np->name);
+ panic("%pOFn: unsupported sysclk setup\n", np);
writel(0x100, base + CPUCLK_DIV); /* disable frequency ramping */
@@ -77,9 +77,9 @@ static void __init tango4_clkgen_setup(struct device_node *np)
pp[3] = clk_register_fixed_factor(NULL, "sdio_clk", "cd6", 0, 1, 2);
if (IS_ERR(pp[0]) || IS_ERR(pp[1]) || IS_ERR(pp[2]) || IS_ERR(pp[3]))
- panic("%s: clk registration failed\n", np->name);
+ panic("%pOFn: clk registration failed\n", np);
if (of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data))
- panic("%s: clk provider registration failed\n", np->name);
+ panic("%pOFn: clk provider registration failed\n", np);
}
CLK_OF_DECLARE(tango4_clkgen, "sigma,tango4-clkgen", tango4_clkgen_setup);
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index d31055ae6ec6..af011974d4ec 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -924,6 +924,101 @@ static int clk_core_enable_lock(struct clk_core *core)
}
/**
+ * clk_gate_restore_context - restore context for poweroff
+ * @hw: the clk_hw pointer of clock whose state is to be restored
+ *
+ * The clock gate restore context function enables or disables
+ * the gate clocks based on the enable_count. This is done in cases
+ * where the clock context is lost and based on the enable_count
+ * the clock either needs to be enabled/disabled. This
+ * helps restore the state of gate clocks.
+ */
+void clk_gate_restore_context(struct clk_hw *hw)
+{
+ struct clk_core *core = hw->core;
+
+ if (core->enable_count)
+ core->ops->enable(hw);
+ else
+ core->ops->disable(hw);
+}
+EXPORT_SYMBOL_GPL(clk_gate_restore_context);
+
+static int clk_core_save_context(struct clk_core *core)
+{
+ struct clk_core *child;
+ int ret = 0;
+
+ hlist_for_each_entry(child, &core->children, child_node) {
+ ret = clk_core_save_context(child);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (core->ops && core->ops->save_context)
+ ret = core->ops->save_context(core->hw);
+
+ return ret;
+}
+
+static void clk_core_restore_context(struct clk_core *core)
+{
+ struct clk_core *child;
+
+ if (core->ops && core->ops->restore_context)
+ core->ops->restore_context(core->hw);
+
+ hlist_for_each_entry(child, &core->children, child_node)
+ clk_core_restore_context(child);
+}
+
+/**
+ * clk_save_context - save clock context for poweroff
+ *
+ * Saves the context of the clock register for powerstates in which the
+ * contents of the registers will be lost. Occurs deep within the suspend
+ * code. Returns 0 on success.
+ */
+int clk_save_context(void)
+{
+ struct clk_core *clk;
+ int ret;
+
+ hlist_for_each_entry(clk, &clk_root_list, child_node) {
+ ret = clk_core_save_context(clk);
+ if (ret < 0)
+ return ret;
+ }
+
+ hlist_for_each_entry(clk, &clk_orphan_list, child_node) {
+ ret = clk_core_save_context(clk);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(clk_save_context);
+
+/**
+ * clk_restore_context - restore clock context after poweroff
+ *
+ * Restore the saved clock context upon resume.
+ *
+ */
+void clk_restore_context(void)
+{
+ struct clk_core *core;
+
+ hlist_for_each_entry(core, &clk_root_list, child_node)
+ clk_core_restore_context(core);
+
+ hlist_for_each_entry(core, &clk_orphan_list, child_node)
+ clk_core_restore_context(core);
+}
+EXPORT_SYMBOL_GPL(clk_restore_context);
+
+/**
* clk_enable - ungate a clock
* @clk: the clk being ungated
*
diff --git a/drivers/clk/davinci/psc.c b/drivers/clk/davinci/psc.c
index fffbed5e263b..5b69e24a224f 100644
--- a/drivers/clk/davinci/psc.c
+++ b/drivers/clk/davinci/psc.c
@@ -303,24 +303,6 @@ static int davinci_lpsc_clk_reset(struct clk *clk, bool reset)
return 0;
}
-/*
- * REVISIT: These exported functions can be removed after a non-DT lookup is
- * added to the reset controller framework and the davinci-rproc driver is
- * updated to use the generic reset controller framework.
- */
-
-int davinci_clk_reset_assert(struct clk *clk)
-{
- return davinci_lpsc_clk_reset(clk, true);
-}
-EXPORT_SYMBOL(davinci_clk_reset_assert);
-
-int davinci_clk_reset_deassert(struct clk *clk)
-{
- return davinci_lpsc_clk_reset(clk, false);
-}
-EXPORT_SYMBOL(davinci_clk_reset_deassert);
-
static int davinci_psc_reset_assert(struct reset_controller_dev *rcdev,
unsigned long id)
{
diff --git a/drivers/clk/hisilicon/Kconfig b/drivers/clk/hisilicon/Kconfig
index becdb1dd21b5..30fad7ab0d88 100644
--- a/drivers/clk/hisilicon/Kconfig
+++ b/drivers/clk/hisilicon/Kconfig
@@ -21,6 +21,13 @@ config COMMON_CLK_HI3660
help
Build the clock driver for hi3660.
+config COMMON_CLK_HI3670
+ bool "Hi3670 Clock Driver"
+ depends on ARCH_HISI || COMPILE_TEST
+ default ARCH_HISI
+ help
+ Build the clock driver for hi3670.
+
config COMMON_CLK_HI3798CV200
tristate "Hi3798CV200 Clock Driver"
depends on ARCH_HISI || COMPILE_TEST
diff --git a/drivers/clk/hisilicon/Makefile b/drivers/clk/hisilicon/Makefile
index 2a714c0f9657..b2441b99f3d5 100644
--- a/drivers/clk/hisilicon/Makefile
+++ b/drivers/clk/hisilicon/Makefile
@@ -11,6 +11,7 @@ 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_HI3660) += clk-hi3660.o
+obj-$(CONFIG_COMMON_CLK_HI3670) += clk-hi3670.o
obj-$(CONFIG_COMMON_CLK_HI3798CV200) += crg-hi3798cv200.o
obj-$(CONFIG_COMMON_CLK_HI6220) += clk-hi6220.o
obj-$(CONFIG_RESET_HISI) += reset.o
diff --git a/drivers/clk/hisilicon/clk-hi3670.c b/drivers/clk/hisilicon/clk-hi3670.c
new file mode 100644
index 000000000000..fd8c837a6ea3
--- /dev/null
+++ b/drivers/clk/hisilicon/clk-hi3670.c
@@ -0,0 +1,1016 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2001-2021, Huawei Tech. Co., Ltd.
+ * Author: chenjun <chenjun14@huawei.com>
+ *
+ * Copyright (c) 2018, Linaro Ltd.
+ * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+ */
+
+#include <dt-bindings/clock/hi3670-clock.h>
+#include <linux/clk-provider.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include "clk.h"
+
+static const struct hisi_fixed_rate_clock hi3670_fixed_rate_clks[] = {
+ { HI3670_CLKIN_SYS, "clkin_sys", NULL, 0, 19200000, },
+ { HI3670_CLKIN_REF, "clkin_ref", NULL, 0, 32764, },
+ { HI3670_CLK_FLL_SRC, "clk_fll_src", NULL, 0, 134400000, },
+ { HI3670_CLK_PPLL0, "clk_ppll0", NULL, 0, 1660000000, },
+ { HI3670_CLK_PPLL1, "clk_ppll1", NULL, 0, 1866000000, },
+ { HI3670_CLK_PPLL2, "clk_ppll2", NULL, 0, 1920000000, },
+ { HI3670_CLK_PPLL3, "clk_ppll3", NULL, 0, 1200000000, },
+ { HI3670_CLK_PPLL4, "clk_ppll4", NULL, 0, 900000000, },
+ { HI3670_CLK_PPLL6, "clk_ppll6", NULL, 0, 393216000, },
+ { HI3670_CLK_PPLL7, "clk_ppll7", NULL, 0, 1008000000, },
+ { HI3670_CLK_PPLL_PCIE, "clk_ppll_pcie", NULL, 0, 100000000, },
+ { HI3670_CLK_PCIEPLL_REV, "clk_pciepll_rev", NULL, 0, 100000000, },
+ { HI3670_CLK_SCPLL, "clk_scpll", NULL, 0, 245760000, },
+ { HI3670_PCLK, "pclk", NULL, 0, 20000000, },
+ { HI3670_CLK_UART0_DBG, "clk_uart0_dbg", NULL, 0, 19200000, },
+ { HI3670_CLK_UART6, "clk_uart6", NULL, 0, 19200000, },
+ { HI3670_OSC32K, "osc32k", NULL, 0, 32764, },
+ { HI3670_OSC19M, "osc19m", NULL, 0, 19200000, },
+ { HI3670_CLK_480M, "clk_480m", NULL, 0, 480000000, },
+ { HI3670_CLK_INVALID, "clk_invalid", NULL, 0, 10000000, },
+};
+
+/* crgctrl */
+static const struct hisi_fixed_factor_clock hi3670_crg_fixed_factor_clks[] = {
+ { HI3670_CLK_DIV_SYSBUS, "clk_div_sysbus", "clk_mux_sysbus",
+ 1, 7, 0, },
+ { HI3670_CLK_FACTOR_MMC, "clk_factor_mmc", "clkin_sys",
+ 1, 6, 0, },
+ { HI3670_CLK_SD_SYS, "clk_sd_sys", "clk_sd_sys_gt",
+ 1, 6, 0, },
+ { HI3670_CLK_SDIO_SYS, "clk_sdio_sys", "clk_sdio_sys_gt",
+ 1, 6, 0, },
+ { HI3670_CLK_DIV_A53HPM, "clk_div_a53hpm", "clk_a53hpm_andgt",
+ 1, 4, 0, },
+ { HI3670_CLK_DIV_320M, "clk_div_320m", "clk_320m_pll_gt",
+ 1, 5, 0, },
+ { HI3670_PCLK_GATE_UART0, "pclk_gate_uart0", "clk_mux_uartl",
+ 1, 1, 0, },
+ { HI3670_CLK_FACTOR_UART0, "clk_factor_uart0", "clk_mux_uart0",
+ 1, 1, 0, },
+ { HI3670_CLK_FACTOR_USB3PHY_PLL, "clk_factor_usb3phy_pll", "clk_ppll0",
+ 1, 60, 0, },
+ { HI3670_CLK_GATE_ABB_USB, "clk_gate_abb_usb", "clk_gate_usb_tcxo_en",
+ 1, 1, 0, },
+ { HI3670_CLK_GATE_UFSPHY_REF, "clk_gate_ufsphy_ref", "clkin_sys",
+ 1, 1, 0, },
+ { HI3670_ICS_VOLT_HIGH, "ics_volt_high", "peri_volt_hold",
+ 1, 1, 0, },
+ { HI3670_ICS_VOLT_MIDDLE, "ics_volt_middle", "peri_volt_middle",
+ 1, 1, 0, },
+ { HI3670_VENC_VOLT_HOLD, "venc_volt_hold", "peri_volt_hold",
+ 1, 1, 0, },
+ { HI3670_VDEC_VOLT_HOLD, "vdec_volt_hold", "peri_volt_hold",
+ 1, 1, 0, },
+ { HI3670_EDC_VOLT_HOLD, "edc_volt_hold", "peri_volt_hold",
+ 1, 1, 0, },
+ { HI3670_CLK_ISP_SNCLK_FAC, "clk_isp_snclk_fac", "clk_isp_snclk_angt",
+ 1, 10, 0, },
+ { HI3670_CLK_FACTOR_RXDPHY, "clk_factor_rxdphy", "clk_andgt_rxdphy",
+ 1, 6, 0, },
+};
+
+static const struct hisi_gate_clock hi3670_crgctrl_gate_sep_clks[] = {
+ { HI3670_PPLL1_EN_ACPU, "ppll1_en_acpu", "clk_ppll1",
+ CLK_SET_RATE_PARENT, 0x0, 0, 0, },
+ { HI3670_PPLL2_EN_ACPU, "ppll2_en_acpu", "clk_ppll2",
+ CLK_SET_RATE_PARENT, 0x0, 3, 0, },
+ { HI3670_PPLL3_EN_ACPU, "ppll3_en_acpu", "clk_ppll3",
+ CLK_SET_RATE_PARENT, 0x0, 27, 0, },
+ { HI3670_PPLL1_GT_CPU, "ppll1_gt_cpu", "clk_ppll1",
+ CLK_SET_RATE_PARENT, 0x460, 16, 0, },
+ { HI3670_PPLL2_GT_CPU, "ppll2_gt_cpu", "clk_ppll2",
+ CLK_SET_RATE_PARENT, 0x460, 18, 0, },
+ { HI3670_PPLL3_GT_CPU, "ppll3_gt_cpu", "clk_ppll3",
+ CLK_SET_RATE_PARENT, 0x460, 20, 0, },
+ { HI3670_CLK_GATE_PPLL2_MEDIA, "clk_gate_ppll2_media", "clk_ppll2",
+ CLK_SET_RATE_PARENT, 0x410, 27, 0, },
+ { HI3670_CLK_GATE_PPLL3_MEDIA, "clk_gate_ppll3_media", "clk_ppll3",
+ CLK_SET_RATE_PARENT, 0x410, 28, 0, },
+ { HI3670_CLK_GATE_PPLL4_MEDIA, "clk_gate_ppll4_media", "clk_ppll4",
+ CLK_SET_RATE_PARENT, 0x410, 26, 0, },
+ { HI3670_CLK_GATE_PPLL6_MEDIA, "clk_gate_ppll6_media", "clk_ppll6",
+ CLK_SET_RATE_PARENT, 0x410, 30, 0, },
+ { HI3670_CLK_GATE_PPLL7_MEDIA, "clk_gate_ppll7_media", "clk_ppll7",
+ CLK_SET_RATE_PARENT, 0x410, 29, 0, },
+ { HI3670_PCLK_GPIO0, "pclk_gpio0", "clk_div_cfgbus",
+ CLK_SET_RATE_PARENT, 0x10, 0, 0, },
+ { HI3670_PCLK_GPIO1, "pclk_gpio1", "clk_div_cfgbus",
+ CLK_SET_RATE_PARENT, 0x10, 1, 0, },
+ { HI3670_PCLK_GPIO2, "pclk_gpio2", "clk_div_cfgbus",
+ CLK_SET_RATE_PARENT, 0x10, 2, 0, },
+ { HI3670_PCLK_GPIO3, "pclk_gpio3", "clk_div_cfgbus",
+ CLK_SET_RATE_PARENT, 0x10, 3, 0, },
+ { HI3670_PCLK_GPIO4, "pclk_gpio4", "clk_div_cfgbus",
+ CLK_SET_RATE_PARENT, 0x10, 4, 0, },
+ { HI3670_PCLK_GPIO5, "pclk_gpio5", "clk_div_cfgbus",
+ CLK_SET_RATE_PARENT, 0x10, 5, 0, },
+ { HI3670_PCLK_GPIO6, "pclk_gpio6", "clk_div_cfgbus",
+ CLK_SET_RATE_PARENT, 0x10, 6, 0, },
+ { HI3670_PCLK_GPIO7, "pclk_gpio7", "clk_div_cfgbus",
+ CLK_SET_RATE_PARENT, 0x10, 7, 0, },
+ { HI3670_PCLK_GPIO8, "pclk_gpio8", "clk_div_cfgbus",
+ CLK_SET_RATE_PARENT, 0x10, 8, 0, },
+ { HI3670_PCLK_GPIO9, "pclk_gpio9", "clk_div_cfgbus",
+ CLK_SET_RATE_PARENT, 0x10, 9, 0, },
+ { HI3670_PCLK_GPIO10, "pclk_gpio10", "clk_div_cfgbus",
+ CLK_SET_RATE_PARENT, 0x10, 10, 0, },
+ { HI3670_PCLK_GPIO11, "pclk_gpio11", "clk_div_cfgbus",
+ CLK_SET_RATE_PARENT, 0x10, 11, 0, },
+ { HI3670_PCLK_GPIO12, "pclk_gpio12", "clk_div_cfgbus",
+ CLK_SET_RATE_PARENT, 0x10, 12, 0, },
+ { HI3670_PCLK_GPIO13, "pclk_gpio13", "clk_div_cfgbus",
+ CLK_SET_RATE_PARENT, 0x10, 13, 0, },
+ { HI3670_PCLK_GPIO14, "pclk_gpio14", "clk_div_cfgbus",
+ CLK_SET_RATE_PARENT, 0x10, 14, 0, },
+ { HI3670_PCLK_GPIO15, "pclk_gpio15", "clk_div_cfgbus",
+ CLK_SET_RATE_PARENT, 0x10, 15, 0, },
+ { HI3670_PCLK_GPIO16, "pclk_gpio16", "clk_div_cfgbus",
+ CLK_SET_RATE_PARENT, 0x10, 16, 0, },
+ { HI3670_PCLK_GPIO17, "pclk_gpio17", "clk_div_cfgbus",
+ CLK_SET_RATE_PARENT, 0x10, 17, 0, },
+ { HI3670_PCLK_GPIO20, "pclk_gpio20", "clk_div_cfgbus",
+ CLK_SET_RATE_PARENT, 0x10, 20, 0, },
+ { HI3670_PCLK_GPIO21, "pclk_gpio21", "clk_div_cfgbus",
+ CLK_SET_RATE_PARENT, 0x10, 21, 0, },
+ { HI3670_PCLK_GATE_DSI0, "pclk_gate_dsi0", "clk_div_cfgbus",
+ CLK_SET_RATE_PARENT, 0x50, 28, 0, },
+ { HI3670_PCLK_GATE_DSI1, "pclk_gate_dsi1", "clk_div_cfgbus",
+ CLK_SET_RATE_PARENT, 0x50, 29, 0, },
+ { HI3670_HCLK_GATE_USB3OTG, "hclk_gate_usb3otg", "clk_div_sysbus",
+ CLK_SET_RATE_PARENT, 0x0, 25, 0, },
+ { HI3670_ACLK_GATE_USB3DVFS, "aclk_gate_usb3dvfs", "autodiv_emmc0bus",
+ CLK_SET_RATE_PARENT, 0x40, 1, 0, },
+ { HI3670_HCLK_GATE_SDIO, "hclk_gate_sdio", "clk_div_sysbus",
+ CLK_SET_RATE_PARENT, 0x0, 21, 0, },
+ { HI3670_PCLK_GATE_PCIE_SYS, "pclk_gate_pcie_sys", "clk_div_mmc1bus",
+ CLK_SET_RATE_PARENT, 0x420, 7, 0, },
+ { HI3670_PCLK_GATE_PCIE_PHY, "pclk_gate_pcie_phy", "pclk_gate_mmc1_pcie",
+ CLK_SET_RATE_PARENT, 0x420, 9, 0, },
+ { HI3670_PCLK_GATE_MMC1_PCIE, "pclk_gate_mmc1_pcie", "pclk_div_mmc1_pcie",
+ CLK_SET_RATE_PARENT, 0x30, 12, 0, },
+ { HI3670_PCLK_GATE_MMC0_IOC, "pclk_gate_mmc0_ioc", "clk_div_mmc0bus",
+ CLK_SET_RATE_PARENT, 0x40, 13, 0, },
+ { HI3670_PCLK_GATE_MMC1_IOC, "pclk_gate_mmc1_ioc", "clk_div_mmc1bus",
+ CLK_SET_RATE_PARENT, 0x420, 21, 0, },
+ { HI3670_CLK_GATE_DMAC, "clk_gate_dmac", "clk_div_sysbus",
+ CLK_SET_RATE_PARENT, 0x30, 1, 0, },
+ { HI3670_CLK_GATE_VCODECBUS2DDR, "clk_gate_vcodecbus2ddr", "clk_div_vcodecbus",
+ CLK_SET_RATE_PARENT, 0x0, 5, 0, },
+ { HI3670_CLK_CCI400_BYPASS, "clk_cci400_bypass", "clk_ddrc_freq",
+ CLK_SET_RATE_PARENT, 0x22C, 28, 0, },
+ { HI3670_CLK_GATE_CCI400, "clk_gate_cci400", "clk_ddrc_freq",
+ CLK_SET_RATE_PARENT, 0x50, 14, 0, },
+ { HI3670_CLK_GATE_SD, "clk_gate_sd", "clk_mux_sd_sys",
+ CLK_SET_RATE_PARENT, 0x40, 17, 0, },
+ { HI3670_HCLK_GATE_SD, "hclk_gate_sd", "clk_div_sysbus",
+ CLK_SET_RATE_PARENT, 0x0, 30, 0, },
+ { HI3670_CLK_GATE_SDIO, "clk_gate_sdio", "clk_mux_sdio_sys",
+ CLK_SET_RATE_PARENT, 0x40, 19, 0, },
+ { HI3670_CLK_GATE_A57HPM, "clk_gate_a57hpm", "clk_div_a53hpm",
+ CLK_SET_RATE_PARENT, 0x050, 9, 0, },
+ { HI3670_CLK_GATE_A53HPM, "clk_gate_a53hpm", "clk_div_a53hpm",
+ CLK_SET_RATE_PARENT, 0x050, 13, 0, },
+ { HI3670_CLK_GATE_PA_A53, "clk_gate_pa_a53", "clk_div_a53hpm",
+ CLK_SET_RATE_PARENT, 0x480, 10, 0, },
+ { HI3670_CLK_GATE_PA_A57, "clk_gate_pa_a57", "clk_div_a53hpm",
+ CLK_SET_RATE_PARENT, 0x480, 9, 0, },
+ { HI3670_CLK_GATE_PA_G3D, "clk_gate_pa_g3d", "clk_div_a53hpm",
+ CLK_SET_RATE_PARENT, 0x480, 15, 0, },
+ { HI3670_CLK_GATE_GPUHPM, "clk_gate_gpuhpm", "clk_div_a53hpm",
+ CLK_SET_RATE_PARENT, 0x050, 15, 0, },
+ { HI3670_CLK_GATE_PERIHPM, "clk_gate_perihpm", "clk_div_a53hpm",
+ CLK_SET_RATE_PARENT, 0x050, 12, 0, },
+ { HI3670_CLK_GATE_AOHPM, "clk_gate_aohpm", "clk_div_a53hpm",
+ CLK_SET_RATE_PARENT, 0x050, 11, 0, },
+ { HI3670_CLK_GATE_UART1, "clk_gate_uart1", "clk_mux_uarth",
+ CLK_SET_RATE_PARENT, 0x20, 11, 0, },
+ { HI3670_CLK_GATE_UART4, "clk_gate_uart4", "clk_mux_uarth",
+ CLK_SET_RATE_PARENT, 0x20, 14, 0, },
+ { HI3670_PCLK_GATE_UART1, "pclk_gate_uart1", "clk_mux_uarth",
+ CLK_SET_RATE_PARENT, 0x20, 11, 0, },
+ { HI3670_PCLK_GATE_UART4, "pclk_gate_uart4", "clk_mux_uarth",
+ CLK_SET_RATE_PARENT, 0x20, 14, 0, },
+ { HI3670_CLK_GATE_UART2, "clk_gate_uart2", "clk_mux_uartl",
+ CLK_SET_RATE_PARENT, 0x20, 12, 0, },
+ { HI3670_CLK_GATE_UART5, "clk_gate_uart5", "clk_mux_uartl",
+ CLK_SET_RATE_PARENT, 0x20, 15, 0, },
+ { HI3670_PCLK_GATE_UART2, "pclk_gate_uart2", "clk_mux_uartl",
+ CLK_SET_RATE_PARENT, 0x20, 12, 0, },
+ { HI3670_PCLK_GATE_UART5, "pclk_gate_uart5", "clk_mux_uartl",
+ CLK_SET_RATE_PARENT, 0x20, 15, 0, },
+ { HI3670_CLK_GATE_UART0, "clk_gate_uart0", "clk_mux_uart0",
+ CLK_SET_RATE_PARENT, 0x20, 10, 0, },
+ { HI3670_CLK_GATE_I2C3, "clk_gate_i2c3", "clk_mux_i2c",
+ CLK_SET_RATE_PARENT, 0x20, 7, 0, },
+ { HI3670_CLK_GATE_I2C4, "clk_gate_i2c4", "clk_mux_i2c",
+ CLK_SET_RATE_PARENT, 0x20, 27, 0, },
+ { HI3670_CLK_GATE_I2C7, "clk_gate_i2c7", "clk_mux_i2c",
+ CLK_SET_RATE_PARENT, 0x10, 31, 0, },
+ { HI3670_PCLK_GATE_I2C3, "pclk_gate_i2c3", "clk_mux_i2c",
+ CLK_SET_RATE_PARENT, 0x20, 7, 0, },
+ { HI3670_PCLK_GATE_I2C4, "pclk_gate_i2c4", "clk_mux_i2c",
+ CLK_SET_RATE_PARENT, 0x20, 27, 0, },
+ { HI3670_PCLK_GATE_I2C7, "pclk_gate_i2c7", "clk_mux_i2c",
+ CLK_SET_RATE_PARENT, 0x10, 31, 0, },
+ { HI3670_CLK_GATE_SPI1, "clk_gate_spi1", "clk_mux_spi",
+ CLK_SET_RATE_PARENT, 0x20, 9, 0, },
+ { HI3670_CLK_GATE_SPI4, "clk_gate_spi4", "clk_mux_spi",
+ CLK_SET_RATE_PARENT, 0x40, 4, 0, },
+ { HI3670_PCLK_GATE_SPI1, "pclk_gate_spi1", "clk_mux_spi",
+ CLK_SET_RATE_PARENT, 0x20, 9, 0, },
+ { HI3670_PCLK_GATE_SPI4, "pclk_gate_spi4", "clk_mux_spi",
+ CLK_SET_RATE_PARENT, 0x40, 4, 0, },
+ { HI3670_CLK_GATE_USB3OTG_REF, "clk_gate_usb3otg_ref", "clkin_sys",
+ CLK_SET_RATE_PARENT, 0x40, 0, 0, },
+ { HI3670_CLK_GATE_USB2PHY_REF, "clk_gate_usb2phy_ref", "clkin_sys",
+ CLK_SET_RATE_PARENT, 0x410, 19, 0, },
+ { HI3670_CLK_GATE_PCIEAUX, "clk_gate_pcieaux", "clkin_sys",
+ CLK_SET_RATE_PARENT, 0x420, 8, 0, },
+ { HI3670_ACLK_GATE_PCIE, "aclk_gate_pcie", "clk_gate_mmc1_pcieaxi",
+ CLK_SET_RATE_PARENT, 0x420, 5, 0, },
+ { HI3670_CLK_GATE_MMC1_PCIEAXI, "clk_gate_mmc1_pcieaxi", "clk_div_pcieaxi",
+ CLK_SET_RATE_PARENT, 0x050, 4, 0, },
+ { HI3670_CLK_GATE_PCIEPHY_REF, "clk_gate_pciephy_ref", "clk_ppll_pcie",
+ CLK_SET_RATE_PARENT, 0x470, 14, 0, },
+ { HI3670_CLK_GATE_PCIE_DEBOUNCE, "clk_gate_pcie_debounce", "clk_ppll_pcie",
+ CLK_SET_RATE_PARENT, 0x470, 12, 0, },
+ { HI3670_CLK_GATE_PCIEIO, "clk_gate_pcieio", "clk_ppll_pcie",
+ CLK_SET_RATE_PARENT, 0x470, 13, 0, },
+ { HI3670_CLK_GATE_PCIE_HP, "clk_gate_pcie_hp", "clk_ppll_pcie",
+ CLK_SET_RATE_PARENT, 0x470, 15, 0, },
+ { HI3670_CLK_GATE_AO_ASP, "clk_gate_ao_asp", "clk_div_ao_asp",
+ CLK_SET_RATE_PARENT, 0x0, 26, 0, },
+ { HI3670_PCLK_GATE_PCTRL, "pclk_gate_pctrl", "clk_div_ptp",
+ CLK_SET_RATE_PARENT, 0x20, 31, 0, },
+ { HI3670_CLK_CSI_TRANS_GT, "clk_csi_trans_gt", "clk_div_csi_trans",
+ CLK_SET_RATE_PARENT, 0x30, 24, 0, },
+ { HI3670_CLK_DSI_TRANS_GT, "clk_dsi_trans_gt", "clk_div_dsi_trans",
+ CLK_SET_RATE_PARENT, 0x30, 25, 0, },
+ { HI3670_CLK_GATE_PWM, "clk_gate_pwm", "clk_div_ptp",
+ CLK_SET_RATE_PARENT, 0x20, 0, 0, },
+ { HI3670_ABB_AUDIO_EN0, "abb_audio_en0", "clk_gate_abb_192",
+ CLK_SET_RATE_PARENT, 0x30, 8, 0, },
+ { HI3670_ABB_AUDIO_EN1, "abb_audio_en1", "clk_gate_abb_192",
+ CLK_SET_RATE_PARENT, 0x30, 9, 0, },
+ { HI3670_ABB_AUDIO_GT_EN0, "abb_audio_gt_en0", "abb_audio_en0",
+ CLK_SET_RATE_PARENT, 0x30, 19, 0, },
+ { HI3670_ABB_AUDIO_GT_EN1, "abb_audio_gt_en1", "abb_audio_en1",
+ CLK_SET_RATE_PARENT, 0x40, 20, 0, },
+ { HI3670_CLK_GATE_DP_AUDIO_PLL_AO, "clk_gate_dp_audio_pll_ao", "clkdiv_dp_audio_pll_ao",
+ CLK_SET_RATE_PARENT, 0x00, 13, 0, },
+ { HI3670_PERI_VOLT_HOLD, "peri_volt_hold", "clkin_sys",
+ CLK_SET_RATE_PARENT, 0, 1, 0, },
+ { HI3670_PERI_VOLT_MIDDLE, "peri_volt_middle", "clkin_sys",
+ CLK_SET_RATE_PARENT, 0, 1, 0, },
+ { HI3670_CLK_GATE_ISP_SNCLK0, "clk_gate_isp_snclk0", "clk_isp_snclk_mux0",
+ CLK_SET_RATE_PARENT, 0x50, 16, 0, },
+ { HI3670_CLK_GATE_ISP_SNCLK1, "clk_gate_isp_snclk1", "clk_isp_snclk_mux1",
+ CLK_SET_RATE_PARENT, 0x50, 17, 0, },
+ { HI3670_CLK_GATE_ISP_SNCLK2, "clk_gate_isp_snclk2", "clk_isp_snclk_mux2",
+ CLK_SET_RATE_PARENT, 0x50, 18, 0, },
+ { HI3670_CLK_GATE_RXDPHY0_CFG, "clk_gate_rxdphy0_cfg", "clk_mux_rxdphy_cfg",
+ CLK_SET_RATE_PARENT, 0x030, 20, 0, },
+ { HI3670_CLK_GATE_RXDPHY1_CFG, "clk_gate_rxdphy1_cfg", "clk_mux_rxdphy_cfg",
+ CLK_SET_RATE_PARENT, 0x030, 21, 0, },
+ { HI3670_CLK_GATE_RXDPHY2_CFG, "clk_gate_rxdphy2_cfg", "clk_mux_rxdphy_cfg",
+ CLK_SET_RATE_PARENT, 0x030, 22, 0, },
+ { HI3670_CLK_GATE_TXDPHY0_CFG, "clk_gate_txdphy0_cfg", "clkin_sys",
+ CLK_SET_RATE_PARENT, 0x030, 28, 0, },
+ { HI3670_CLK_GATE_TXDPHY0_REF, "clk_gate_txdphy0_ref", "clkin_sys",
+ CLK_SET_RATE_PARENT, 0x030, 29, 0, },
+ { HI3670_CLK_GATE_TXDPHY1_CFG, "clk_gate_txdphy1_cfg", "clkin_sys",
+ CLK_SET_RATE_PARENT, 0x030, 30, 0, },
+ { HI3670_CLK_GATE_TXDPHY1_REF, "clk_gate_txdphy1_ref", "clkin_sys",
+ CLK_SET_RATE_PARENT, 0x030, 31, 0, },
+ { HI3670_CLK_GATE_MEDIA_TCXO, "clk_gate_media_tcxo", "clkin_sys",
+ CLK_SET_RATE_PARENT, 0x40, 6, 0, },
+};
+
+static const struct hisi_gate_clock hi3670_crgctrl_gate_clks[] = {
+ { HI3670_AUTODIV_SYSBUS, "autodiv_sysbus", "clk_div_sysbus",
+ CLK_SET_RATE_PARENT, 0x404, 5, CLK_GATE_HIWORD_MASK, 0, },
+ { HI3670_AUTODIV_EMMC0BUS, "autodiv_emmc0bus", "autodiv_sysbus",
+ CLK_SET_RATE_PARENT, 0x404, 1, CLK_GATE_HIWORD_MASK, 0, },
+ { HI3670_PCLK_ANDGT_MMC1_PCIE, "pclk_andgt_mmc1_pcie", "clk_div_320m",
+ CLK_SET_RATE_PARENT, 0xf8, 13, CLK_GATE_HIWORD_MASK, 0, },
+ { HI3670_CLK_GATE_VCODECBUS_GT, "clk_gate_vcodecbus_gt", "clk_mux_vcodecbus",
+ CLK_SET_RATE_PARENT, 0x0F0, 8, CLK_GATE_HIWORD_MASK, 0, },
+ { HI3670_CLK_ANDGT_SD, "clk_andgt_sd", "clk_mux_sd_pll",
+ CLK_SET_RATE_PARENT, 0xF4, 3, CLK_GATE_HIWORD_MASK, 0, },
+ { HI3670_CLK_SD_SYS_GT, "clk_sd_sys_gt", "clkin_sys",
+ CLK_SET_RATE_PARENT, 0xF4, 5, CLK_GATE_HIWORD_MASK, 0, },
+ { HI3670_CLK_ANDGT_SDIO, "clk_andgt_sdio", "clk_mux_sdio_pll",
+ CLK_SET_RATE_PARENT, 0xF4, 8, CLK_GATE_HIWORD_MASK, 0, },
+ { HI3670_CLK_SDIO_SYS_GT, "clk_sdio_sys_gt", "clkin_sys",
+ CLK_SET_RATE_PARENT, 0xF4, 6, CLK_GATE_HIWORD_MASK, 0, },
+ { HI3670_CLK_A53HPM_ANDGT, "clk_a53hpm_andgt", "clk_mux_a53hpm",
+ CLK_SET_RATE_PARENT, 0x0F4, 7, CLK_GATE_HIWORD_MASK, 0, },
+ { HI3670_CLK_320M_PLL_GT, "clk_320m_pll_gt", "clk_mux_320m",
+ CLK_SET_RATE_PARENT, 0xF8, 10, CLK_GATE_HIWORD_MASK, 0, },
+ { HI3670_CLK_ANDGT_UARTH, "clk_andgt_uarth", "clk_div_320m",
+ CLK_SET_RATE_PARENT, 0xF4, 11, CLK_GATE_HIWORD_MASK, 0, },
+ { HI3670_CLK_ANDGT_UARTL, "clk_andgt_uartl", "clk_div_320m",
+ CLK_SET_RATE_PARENT, 0xF4, 10, CLK_GATE_HIWORD_MASK, 0, },
+ { HI3670_CLK_ANDGT_UART0, "clk_andgt_uart0", "clk_div_320m",
+ CLK_SET_RATE_PARENT, 0xF4, 9, CLK_GATE_HIWORD_MASK, 0, },
+ { HI3670_CLK_ANDGT_SPI, "clk_andgt_spi", "clk_div_320m",
+ CLK_SET_RATE_PARENT, 0xF4, 13, CLK_GATE_HIWORD_MASK, 0, },
+ { HI3670_CLK_ANDGT_PCIEAXI, "clk_andgt_pcieaxi", "clk_mux_pcieaxi",
+ CLK_SET_RATE_PARENT, 0xfc, 15, CLK_GATE_HIWORD_MASK, 0, },
+ { HI3670_CLK_DIV_AO_ASP_GT, "clk_div_ao_asp_gt", "clk_mux_ao_asp",
+ CLK_SET_RATE_PARENT, 0xF4, 4, CLK_GATE_HIWORD_MASK, 0, },
+ { HI3670_CLK_GATE_CSI_TRANS, "clk_gate_csi_trans", "clk_ppll2",
+ CLK_SET_RATE_PARENT, 0xF4, 14, CLK_GATE_HIWORD_MASK, 0, },
+ { HI3670_CLK_GATE_DSI_TRANS, "clk_gate_dsi_trans", "clk_ppll2",
+ CLK_SET_RATE_PARENT, 0xF4, 1, CLK_GATE_HIWORD_MASK, 0, },
+ { HI3670_CLK_ANDGT_PTP, "clk_andgt_ptp", "clk_div_320m",
+ CLK_SET_RATE_PARENT, 0xF8, 5, CLK_GATE_HIWORD_MASK, 0, },
+ { HI3670_CLK_ANDGT_OUT0, "clk_andgt_out0", "clk_ppll0",
+ CLK_SET_RATE_PARENT, 0xF0, 10, CLK_GATE_HIWORD_MASK, 0, },
+ { HI3670_CLK_ANDGT_OUT1, "clk_andgt_out1", "clk_ppll0",
+ CLK_SET_RATE_PARENT, 0xF0, 11, CLK_GATE_HIWORD_MASK, 0, },
+ { HI3670_CLKGT_DP_AUDIO_PLL_AO, "clkgt_dp_audio_pll_ao", "clk_ppll6",
+ CLK_SET_RATE_PARENT, 0xF8, 15, CLK_GATE_HIWORD_MASK, 0, },
+ { HI3670_CLK_ANDGT_VDEC, "clk_andgt_vdec", "clk_mux_vdec",
+ CLK_SET_RATE_PARENT, 0xF0, 13, CLK_GATE_HIWORD_MASK, 0, },
+ { HI3670_CLK_ANDGT_VENC, "clk_andgt_venc", "clk_mux_venc",
+ CLK_SET_RATE_PARENT, 0xF0, 9, CLK_GATE_HIWORD_MASK, 0, },
+ { HI3670_CLK_ISP_SNCLK_ANGT, "clk_isp_snclk_angt", "clk_div_a53hpm",
+ CLK_SET_RATE_PARENT, 0x108, 2, CLK_GATE_HIWORD_MASK, 0, },
+ { HI3670_CLK_ANDGT_RXDPHY, "clk_andgt_rxdphy", "clk_div_a53hpm",
+ CLK_SET_RATE_PARENT, 0x0F0, 12, CLK_GATE_HIWORD_MASK, 0, },
+ { HI3670_CLK_ANDGT_ICS, "clk_andgt_ics", "clk_mux_ics",
+ CLK_SET_RATE_PARENT, 0xf0, 14, CLK_GATE_HIWORD_MASK, 0, },
+ { HI3670_AUTODIV_DMABUS, "autodiv_dmabus", "autodiv_sysbus",
+ CLK_SET_RATE_PARENT, 0x404, 3, CLK_GATE_HIWORD_MASK, 0, },
+};
+
+static const char *const
+clk_mux_sysbus_p[] = { "clk_ppll1", "clk_ppll0", };
+static const char *const
+clk_mux_vcodecbus_p[] = { "clk_invalid", "clk_ppll4", "clk_ppll0",
+ "clk_invalid", "clk_ppll2", "clk_invalid",
+ "clk_invalid", "clk_invalid", "clk_ppll3",
+ "clk_invalid", "clk_invalid", "clk_invalid",
+ "clk_invalid", "clk_invalid", "clk_invalid",
+ "clk_invalid", };
+static const char *const
+clk_mux_sd_sys_p[] = { "clk_sd_sys", "clk_div_sd", };
+static const char *const
+clk_mux_sd_pll_p[] = { "clk_ppll0", "clk_ppll3", "clk_ppll2", "clk_ppll2", };
+static const char *const
+clk_mux_sdio_sys_p[] = { "clk_sdio_sys", "clk_div_sdio", };
+static const char *const
+clk_mux_sdio_pll_p[] = { "clk_ppll0", "clk_ppll3", "clk_ppll2", "clk_ppll2", };
+static const char *const
+clk_mux_a53hpm_p[] = { "clk_ppll0", "clk_ppll2", };
+static const char *const
+clk_mux_320m_p[] = { "clk_ppll2", "clk_ppll0", };
+static const char *const
+clk_mux_uarth_p[] = { "clkin_sys", "clk_div_uarth", };
+static const char *const
+clk_mux_uartl_p[] = { "clkin_sys", "clk_div_uartl", };
+static const char *const
+clk_mux_uart0_p[] = { "clkin_sys", "clk_div_uart0", };
+static const char *const
+clk_mux_i2c_p[] = { "clkin_sys", "clk_div_i2c", };
+static const char *const
+clk_mux_spi_p[] = { "clkin_sys", "clk_div_spi", };
+static const char *const
+clk_mux_pcieaxi_p[] = { "clkin_sys", "clk_ppll0", };
+static const char *const
+clk_mux_ao_asp_p[] = { "clk_ppll2", "clk_ppll3", };
+static const char *const
+clk_mux_vdec_p[] = { "clk_invalid", "clk_ppll4", "clk_ppll0", "clk_invalid",
+ "clk_invalid", "clk_invalid", "clk_invalid", "clk_invalid",
+ "clk_invalid", "clk_invalid", "clk_invalid", "clk_invalid",
+ "clk_invalid", "clk_invalid", "clk_invalid",
+ "clk_invalid", };
+static const char *const
+clk_mux_venc_p[] = { "clk_invalid", "clk_ppll4", "clk_ppll0", "clk_invalid",
+ "clk_invalid", "clk_invalid", "clk_invalid", "clk_invalid",
+ "clk_invalid", "clk_invalid", "clk_invalid", "clk_invalid",
+ "clk_invalid", "clk_invalid", "clk_invalid",
+ "clk_invalid", };
+static const char *const
+clk_isp_snclk_mux0_p[] = { "clkin_sys", "clk_isp_snclk_div0", };
+static const char *const
+clk_isp_snclk_mux1_p[] = { "clkin_sys", "clk_isp_snclk_div1", };
+static const char *const
+clk_isp_snclk_mux2_p[] = { "clkin_sys", "clk_isp_snclk_div2", };
+static const char *const
+clk_mux_rxdphy_cfg_p[] = { "clk_factor_rxdphy", "clkin_sys", };
+static const char *const
+clk_mux_ics_p[] = { "clk_invalid", "clk_ppll4", "clk_ppll0", "clk_invalid",
+ "clk_ppll2", "clk_invalid", "clk_invalid", "clk_invalid",
+ "clk_ppll3", "clk_invalid", "clk_invalid", "clk_invalid",
+ "clk_invalid", "clk_invalid", "clk_invalid",
+ "clk_invalid", };
+
+static const struct hisi_mux_clock hi3670_crgctrl_mux_clks[] = {
+ { HI3670_CLK_MUX_SYSBUS, "clk_mux_sysbus", clk_mux_sysbus_p,
+ ARRAY_SIZE(clk_mux_sysbus_p), CLK_SET_RATE_PARENT,
+ 0xAC, 0, 1, CLK_MUX_HIWORD_MASK, },
+ { HI3670_CLK_MUX_VCODECBUS, "clk_mux_vcodecbus", clk_mux_vcodecbus_p,
+ ARRAY_SIZE(clk_mux_vcodecbus_p), CLK_SET_RATE_PARENT,
+ 0x0C8, 0, 4, CLK_MUX_HIWORD_MASK, },
+ { HI3670_CLK_MUX_SD_SYS, "clk_mux_sd_sys", clk_mux_sd_sys_p,
+ ARRAY_SIZE(clk_mux_sd_sys_p), CLK_SET_RATE_PARENT,
+ 0x0B8, 6, 1, CLK_MUX_HIWORD_MASK, },
+ { HI3670_CLK_MUX_SD_PLL, "clk_mux_sd_pll", clk_mux_sd_pll_p,
+ ARRAY_SIZE(clk_mux_sd_pll_p), CLK_SET_RATE_PARENT,
+ 0x0B8, 4, 2, CLK_MUX_HIWORD_MASK, },
+ { HI3670_CLK_MUX_SDIO_SYS, "clk_mux_sdio_sys", clk_mux_sdio_sys_p,
+ ARRAY_SIZE(clk_mux_sdio_sys_p), CLK_SET_RATE_PARENT,
+ 0x0C0, 6, 1, CLK_MUX_HIWORD_MASK, },
+ { HI3670_CLK_MUX_SDIO_PLL, "clk_mux_sdio_pll", clk_mux_sdio_pll_p,
+ ARRAY_SIZE(clk_mux_sdio_pll_p), CLK_SET_RATE_PARENT,
+ 0x0C0, 4, 2, CLK_MUX_HIWORD_MASK, },
+ { HI3670_CLK_MUX_A53HPM, "clk_mux_a53hpm", clk_mux_a53hpm_p,
+ ARRAY_SIZE(clk_mux_a53hpm_p), CLK_SET_RATE_PARENT,
+ 0x0D4, 9, 1, CLK_MUX_HIWORD_MASK, },
+ { HI3670_CLK_MUX_320M, "clk_mux_320m", clk_mux_320m_p,
+ ARRAY_SIZE(clk_mux_320m_p), CLK_SET_RATE_PARENT,
+ 0x100, 0, 1, CLK_MUX_HIWORD_MASK, },
+ { HI3670_CLK_MUX_UARTH, "clk_mux_uarth", clk_mux_uarth_p,
+ ARRAY_SIZE(clk_mux_uarth_p), CLK_SET_RATE_PARENT,
+ 0xAC, 4, 1, CLK_MUX_HIWORD_MASK, },
+ { HI3670_CLK_MUX_UARTL, "clk_mux_uartl", clk_mux_uartl_p,
+ ARRAY_SIZE(clk_mux_uartl_p), CLK_SET_RATE_PARENT,
+ 0xAC, 3, 1, CLK_MUX_HIWORD_MASK, },
+ { HI3670_CLK_MUX_UART0, "clk_mux_uart0", clk_mux_uart0_p,
+ ARRAY_SIZE(clk_mux_uart0_p), CLK_SET_RATE_PARENT,
+ 0xAC, 2, 1, CLK_MUX_HIWORD_MASK, },
+ { HI3670_CLK_MUX_I2C, "clk_mux_i2c", clk_mux_i2c_p,
+ ARRAY_SIZE(clk_mux_i2c_p), CLK_SET_RATE_PARENT,
+ 0xAC, 13, 1, CLK_MUX_HIWORD_MASK, },
+ { HI3670_CLK_MUX_SPI, "clk_mux_spi", clk_mux_spi_p,
+ ARRAY_SIZE(clk_mux_spi_p), CLK_SET_RATE_PARENT,
+ 0xAC, 8, 1, CLK_MUX_HIWORD_MASK, },
+ { HI3670_CLK_MUX_PCIEAXI, "clk_mux_pcieaxi", clk_mux_pcieaxi_p,
+ ARRAY_SIZE(clk_mux_pcieaxi_p), CLK_SET_RATE_PARENT,
+ 0xb4, 5, 1, CLK_MUX_HIWORD_MASK, },
+ { HI3670_CLK_MUX_AO_ASP, "clk_mux_ao_asp", clk_mux_ao_asp_p,
+ ARRAY_SIZE(clk_mux_ao_asp_p), CLK_SET_RATE_PARENT,
+ 0x100, 6, 1, CLK_MUX_HIWORD_MASK, },
+ { HI3670_CLK_MUX_VDEC, "clk_mux_vdec", clk_mux_vdec_p,
+ ARRAY_SIZE(clk_mux_vdec_p), CLK_SET_RATE_PARENT,
+ 0xC8, 8, 4, CLK_MUX_HIWORD_MASK, },
+ { HI3670_CLK_MUX_VENC, "clk_mux_venc", clk_mux_venc_p,
+ ARRAY_SIZE(clk_mux_venc_p), CLK_SET_RATE_PARENT,
+ 0xC8, 4, 4, CLK_MUX_HIWORD_MASK, },
+ { HI3670_CLK_ISP_SNCLK_MUX0, "clk_isp_snclk_mux0", clk_isp_snclk_mux0_p,
+ ARRAY_SIZE(clk_isp_snclk_mux0_p), CLK_SET_RATE_PARENT,
+ 0x108, 3, 1, CLK_MUX_HIWORD_MASK, },
+ { HI3670_CLK_ISP_SNCLK_MUX1, "clk_isp_snclk_mux1", clk_isp_snclk_mux1_p,
+ ARRAY_SIZE(clk_isp_snclk_mux1_p), CLK_SET_RATE_PARENT,
+ 0x10C, 13, 1, CLK_MUX_HIWORD_MASK, },
+ { HI3670_CLK_ISP_SNCLK_MUX2, "clk_isp_snclk_mux2", clk_isp_snclk_mux2_p,
+ ARRAY_SIZE(clk_isp_snclk_mux2_p), CLK_SET_RATE_PARENT,
+ 0x10C, 10, 1, CLK_MUX_HIWORD_MASK, },
+ { HI3670_CLK_MUX_RXDPHY_CFG, "clk_mux_rxdphy_cfg", clk_mux_rxdphy_cfg_p,
+ ARRAY_SIZE(clk_mux_rxdphy_cfg_p), CLK_SET_RATE_PARENT,
+ 0x0C4, 8, 1, CLK_MUX_HIWORD_MASK, },
+ { HI3670_CLK_MUX_ICS, "clk_mux_ics", clk_mux_ics_p,
+ ARRAY_SIZE(clk_mux_ics_p), CLK_SET_RATE_PARENT,
+ 0xc8, 12, 4, CLK_MUX_HIWORD_MASK, },
+};
+
+static const struct hisi_divider_clock hi3670_crgctrl_divider_clks[] = {
+ { HI3670_CLK_DIV_CFGBUS, "clk_div_cfgbus", "clk_div_sysbus",
+ CLK_SET_RATE_PARENT, 0xEC, 0, 2, CLK_DIVIDER_HIWORD_MASK, 0, },
+ { HI3670_CLK_DIV_MMC0BUS, "clk_div_mmc0bus", "autodiv_emmc0bus",
+ CLK_SET_RATE_PARENT, 0x0EC, 2, 1, CLK_DIVIDER_HIWORD_MASK, 0, },
+ { HI3670_CLK_DIV_MMC1BUS, "clk_div_mmc1bus", "clk_div_sysbus",
+ CLK_SET_RATE_PARENT, 0x0EC, 3, 1, CLK_DIVIDER_HIWORD_MASK, 0, },
+ { HI3670_PCLK_DIV_MMC1_PCIE, "pclk_div_mmc1_pcie", "pclk_andgt_mmc1_pcie",
+ CLK_SET_RATE_PARENT, 0xb4, 6, 4, CLK_DIVIDER_HIWORD_MASK, 0, },
+ { HI3670_CLK_DIV_VCODECBUS, "clk_div_vcodecbus", "clk_gate_vcodecbus_gt",
+ CLK_SET_RATE_PARENT, 0x0BC, 0, 6, CLK_DIVIDER_HIWORD_MASK, 0, },
+ { HI3670_CLK_DIV_SD, "clk_div_sd", "clk_andgt_sd",
+ CLK_SET_RATE_PARENT, 0xB8, 0, 4, CLK_DIVIDER_HIWORD_MASK, 0, },
+ { HI3670_CLK_DIV_SDIO, "clk_div_sdio", "clk_andgt_sdio",
+ CLK_SET_RATE_PARENT, 0xC0, 0, 4, CLK_DIVIDER_HIWORD_MASK, 0, },
+ { HI3670_CLK_DIV_UARTH, "clk_div_uarth", "clk_andgt_uarth",
+ CLK_SET_RATE_PARENT, 0xB0, 12, 4, CLK_DIVIDER_HIWORD_MASK, 0, },
+ { HI3670_CLK_DIV_UARTL, "clk_div_uartl", "clk_andgt_uartl",
+ CLK_SET_RATE_PARENT, 0xB0, 8, 4, CLK_DIVIDER_HIWORD_MASK, 0, },
+ { HI3670_CLK_DIV_UART0, "clk_div_uart0", "clk_andgt_uart0",
+ CLK_SET_RATE_PARENT, 0xB0, 4, 4, CLK_DIVIDER_HIWORD_MASK, 0, },
+ { HI3670_CLK_DIV_I2C, "clk_div_i2c", "clk_div_320m",
+ CLK_SET_RATE_PARENT, 0xE8, 4, 4, CLK_DIVIDER_HIWORD_MASK, 0, },
+ { HI3670_CLK_DIV_SPI, "clk_div_spi", "clk_andgt_spi",
+ CLK_SET_RATE_PARENT, 0xC4, 12, 4, CLK_DIVIDER_HIWORD_MASK, 0, },
+ { HI3670_CLK_DIV_PCIEAXI, "clk_div_pcieaxi", "clk_andgt_pcieaxi",
+ CLK_SET_RATE_PARENT, 0xb4, 0, 5, CLK_DIVIDER_HIWORD_MASK, 0, },
+ { HI3670_CLK_DIV_AO_ASP, "clk_div_ao_asp", "clk_div_ao_asp_gt",
+ CLK_SET_RATE_PARENT, 0x108, 6, 4, CLK_DIVIDER_HIWORD_MASK, 0, },
+ { HI3670_CLK_DIV_CSI_TRANS, "clk_div_csi_trans", "clk_gate_csi_trans",
+ CLK_SET_RATE_PARENT, 0xD4, 0, 5, CLK_DIVIDER_HIWORD_MASK, 0, },
+ { HI3670_CLK_DIV_DSI_TRANS, "clk_div_dsi_trans", "clk_gate_dsi_trans",
+ CLK_SET_RATE_PARENT, 0xD4, 10, 5, CLK_DIVIDER_HIWORD_MASK, 0, },
+ { HI3670_CLK_DIV_PTP, "clk_div_ptp", "clk_andgt_ptp",
+ CLK_SET_RATE_PARENT, 0xD8, 0, 4, CLK_DIVIDER_HIWORD_MASK, 0, },
+ { HI3670_CLK_DIV_CLKOUT0_PLL, "clk_div_clkout0_pll", "clk_andgt_out0",
+ CLK_SET_RATE_PARENT, 0xe0, 4, 6, CLK_DIVIDER_HIWORD_MASK, 0, },
+ { HI3670_CLK_DIV_CLKOUT1_PLL, "clk_div_clkout1_pll", "clk_andgt_out1",
+ CLK_SET_RATE_PARENT, 0xe0, 10, 6, CLK_DIVIDER_HIWORD_MASK, 0, },
+ { HI3670_CLKDIV_DP_AUDIO_PLL_AO, "clkdiv_dp_audio_pll_ao", "clkgt_dp_audio_pll_ao",
+ CLK_SET_RATE_PARENT, 0xBC, 11, 4, CLK_DIVIDER_HIWORD_MASK, 0, },
+ { HI3670_CLK_DIV_VDEC, "clk_div_vdec", "clk_andgt_vdec",
+ CLK_SET_RATE_PARENT, 0xC4, 0, 6, CLK_DIVIDER_HIWORD_MASK, 0, },
+ { HI3670_CLK_DIV_VENC, "clk_div_venc", "clk_andgt_venc",
+ CLK_SET_RATE_PARENT, 0xC0, 8, 6, CLK_DIVIDER_HIWORD_MASK, 0, },
+ { HI3670_CLK_ISP_SNCLK_DIV0, "clk_isp_snclk_div0", "clk_isp_snclk_fac",
+ CLK_SET_RATE_PARENT, 0x108, 0, 2, CLK_DIVIDER_HIWORD_MASK, 0, },
+ { HI3670_CLK_ISP_SNCLK_DIV1, "clk_isp_snclk_div1", "clk_isp_snclk_fac",
+ CLK_SET_RATE_PARENT, 0x10C, 14, 2, CLK_DIVIDER_HIWORD_MASK, 0, },
+ { HI3670_CLK_ISP_SNCLK_DIV2, "clk_isp_snclk_div2", "clk_isp_snclk_fac",
+ CLK_SET_RATE_PARENT, 0x10C, 11, 2, CLK_DIVIDER_HIWORD_MASK, 0, },
+ { HI3670_CLK_DIV_ICS, "clk_div_ics", "clk_andgt_ics",
+ CLK_SET_RATE_PARENT, 0xE4, 9, 6, CLK_DIVIDER_HIWORD_MASK, 0, },
+};
+
+/* clk_pmuctrl */
+static const struct hisi_gate_clock hi3670_pmu_gate_clks[] = {
+ { HI3670_GATE_ABB_192, "clk_gate_abb_192", "clkin_sys",
+ CLK_SET_RATE_PARENT, (0x037 << 2), 0, 0, },
+};
+
+/* clk_pctrl */
+static const struct hisi_gate_clock hi3670_pctrl_gate_clks[] = {
+ { HI3670_GATE_UFS_TCXO_EN, "clk_gate_ufs_tcxo_en", "clk_gate_abb_192",
+ CLK_SET_RATE_PARENT, 0x10, 0, CLK_GATE_HIWORD_MASK, },
+ { HI3670_GATE_USB_TCXO_EN, "clk_gate_usb_tcxo_en", "clk_gate_abb_192",
+ CLK_SET_RATE_PARENT, 0x10, 1, CLK_GATE_HIWORD_MASK, },
+};
+
+/* clk_sctrl */
+static const struct hisi_gate_clock hi3670_sctrl_gate_sep_clks[] = {
+ { HI3670_PPLL0_EN_ACPU, "ppll0_en_acpu", "clk_ppll0",
+ CLK_SET_RATE_PARENT, 0x190, 26, 0, },
+ { HI3670_PPLL0_GT_CPU, "ppll0_gt_cpu", "clk_ppll0",
+ CLK_SET_RATE_PARENT, 0x190, 15, 0, },
+ { HI3670_CLK_GATE_PPLL0_MEDIA, "clk_gate_ppll0_media", "clk_ppll0",
+ CLK_SET_RATE_PARENT, 0x1b0, 6, 0, },
+ { HI3670_PCLK_GPIO18, "pclk_gpio18", "clk_div_aobus",
+ CLK_SET_RATE_PARENT, 0x1B0, 9, 0, },
+ { HI3670_PCLK_GPIO19, "pclk_gpio19", "clk_div_aobus",
+ CLK_SET_RATE_PARENT, 0x1B0, 8, 0, },
+ { HI3670_CLK_GATE_SPI, "clk_gate_spi", "clk_div_ioperi",
+ CLK_SET_RATE_PARENT, 0x1B0, 10, 0, },
+ { HI3670_PCLK_GATE_SPI, "pclk_gate_spi", "clk_div_ioperi",
+ CLK_SET_RATE_PARENT, 0x1B0, 10, 0, },
+ { HI3670_CLK_GATE_UFS_SUBSYS, "clk_gate_ufs_subsys", "clk_div_ufs_subsys",
+ CLK_SET_RATE_PARENT, 0x1B0, 14, 0, },
+ { HI3670_CLK_GATE_UFSIO_REF, "clk_gate_ufsio_ref", "clkin_sys",
+ CLK_SET_RATE_PARENT, 0x1b0, 12, 0, },
+ { HI3670_PCLK_AO_GPIO0, "pclk_ao_gpio0", "clk_div_aobus",
+ CLK_SET_RATE_PARENT, 0x160, 11, 0, },
+ { HI3670_PCLK_AO_GPIO1, "pclk_ao_gpio1", "clk_div_aobus",
+ CLK_SET_RATE_PARENT, 0x160, 12, 0, },
+ { HI3670_PCLK_AO_GPIO2, "pclk_ao_gpio2", "clk_div_aobus",
+ CLK_SET_RATE_PARENT, 0x160, 13, 0, },
+ { HI3670_PCLK_AO_GPIO3, "pclk_ao_gpio3", "clk_div_aobus",
+ CLK_SET_RATE_PARENT, 0x160, 14, 0, },
+ { HI3670_PCLK_AO_GPIO4, "pclk_ao_gpio4", "clk_div_aobus",
+ CLK_SET_RATE_PARENT, 0x160, 21, 0, },
+ { HI3670_PCLK_AO_GPIO5, "pclk_ao_gpio5", "clk_div_aobus",
+ CLK_SET_RATE_PARENT, 0x160, 22, 0, },
+ { HI3670_PCLK_AO_GPIO6, "pclk_ao_gpio6", "clk_div_aobus",
+ CLK_SET_RATE_PARENT, 0x160, 25, 0, },
+ { HI3670_CLK_GATE_OUT0, "clk_gate_out0", "clk_mux_clkout0",
+ CLK_SET_RATE_PARENT, 0x160, 16, 0, },
+ { HI3670_CLK_GATE_OUT1, "clk_gate_out1", "clk_mux_clkout1",
+ CLK_SET_RATE_PARENT, 0x160, 17, 0, },
+ { HI3670_PCLK_GATE_SYSCNT, "pclk_gate_syscnt", "clk_div_aobus",
+ CLK_SET_RATE_PARENT, 0x160, 19, 0, },
+ { HI3670_CLK_GATE_SYSCNT, "clk_gate_syscnt", "clkin_sys",
+ CLK_SET_RATE_PARENT, 0x160, 20, 0, },
+ { HI3670_CLK_GATE_ASP_SUBSYS_PERI, "clk_gate_asp_subsys_peri",
+ "clk_mux_asp_subsys_peri",
+ CLK_SET_RATE_PARENT, 0x170, 6, 0, },
+ { HI3670_CLK_GATE_ASP_SUBSYS, "clk_gate_asp_subsys", "clk_mux_asp_pll",
+ CLK_SET_RATE_PARENT, 0x170, 4, 0, },
+ { HI3670_CLK_GATE_ASP_TCXO, "clk_gate_asp_tcxo", "clkin_sys",
+ CLK_SET_RATE_PARENT, 0x160, 27, 0, },
+ { HI3670_CLK_GATE_DP_AUDIO_PLL, "clk_gate_dp_audio_pll",
+ "clk_gate_dp_audio_pll_ao",
+ CLK_SET_RATE_PARENT, 0x1B0, 7, 0, },
+};
+
+static const struct hisi_gate_clock hi3670_sctrl_gate_clks[] = {
+ { HI3670_CLK_ANDGT_IOPERI, "clk_andgt_ioperi", "clk_ppll0",
+ CLK_SET_RATE_PARENT, 0x270, 6, CLK_GATE_HIWORD_MASK, 0, },
+ { HI3670_CLKANDGT_ASP_SUBSYS_PERI, "clkandgt_asp_subsys_peri",
+ "clk_ppll0",
+ CLK_SET_RATE_PARENT, 0x268, 3, CLK_GATE_HIWORD_MASK, 0, },
+ { HI3670_CLK_ANGT_ASP_SUBSYS, "clk_angt_asp_subsys", "clk_ppll0",
+ CLK_SET_RATE_PARENT, 0x258, 0, CLK_GATE_HIWORD_MASK, 0, },
+};
+
+static const char *const
+clk_mux_ufs_subsys_p[] = { "clkin_sys", "clk_ppll0", };
+static const char *const
+clk_mux_clkout0_p[] = { "clkin_ref", "clk_div_clkout0_tcxo",
+ "clk_div_clkout0_pll", "clk_div_clkout0_pll", };
+static const char *const
+clk_mux_clkout1_p[] = { "clkin_ref", "clk_div_clkout1_tcxo",
+ "clk_div_clkout1_pll", "clk_div_clkout1_pll", };
+static const char *const
+clk_mux_asp_subsys_peri_p[] = { "clk_ppll0", "clk_fll_src", };
+static const char *const
+clk_mux_asp_pll_p[] = { "clk_ppll0", "clk_fll_src", "clk_gate_ao_asp",
+ "clk_pciepll_rev", };
+
+static const struct hisi_mux_clock hi3670_sctrl_mux_clks[] = {
+ { HI3670_CLK_MUX_UFS_SUBSYS, "clk_mux_ufs_subsys", clk_mux_ufs_subsys_p,
+ ARRAY_SIZE(clk_mux_ufs_subsys_p), CLK_SET_RATE_PARENT,
+ 0x274, 8, 1, CLK_MUX_HIWORD_MASK, },
+ { HI3670_CLK_MUX_CLKOUT0, "clk_mux_clkout0", clk_mux_clkout0_p,
+ ARRAY_SIZE(clk_mux_clkout0_p), CLK_SET_RATE_PARENT,
+ 0x254, 12, 2, CLK_MUX_HIWORD_MASK, },
+ { HI3670_CLK_MUX_CLKOUT1, "clk_mux_clkout1", clk_mux_clkout1_p,
+ ARRAY_SIZE(clk_mux_clkout1_p), CLK_SET_RATE_PARENT,
+ 0x254, 14, 2, CLK_MUX_HIWORD_MASK, },
+ { HI3670_CLK_MUX_ASP_SUBSYS_PERI, "clk_mux_asp_subsys_peri",
+ clk_mux_asp_subsys_peri_p, ARRAY_SIZE(clk_mux_asp_subsys_peri_p),
+ CLK_SET_RATE_PARENT, 0x268, 8, 1, CLK_MUX_HIWORD_MASK, },
+ { HI3670_CLK_MUX_ASP_PLL, "clk_mux_asp_pll", clk_mux_asp_pll_p,
+ ARRAY_SIZE(clk_mux_asp_pll_p), CLK_SET_RATE_PARENT,
+ 0x268, 9, 2, CLK_MUX_HIWORD_MASK, },
+};
+
+static const struct hisi_divider_clock hi3670_sctrl_divider_clks[] = {
+ { HI3670_CLK_DIV_AOBUS, "clk_div_aobus", "clk_ppll0",
+ CLK_SET_RATE_PARENT, 0x254, 0, 6, CLK_DIVIDER_HIWORD_MASK, 0, },
+ { HI3670_CLK_DIV_UFS_SUBSYS, "clk_div_ufs_subsys", "clk_mux_ufs_subsys",
+ CLK_SET_RATE_PARENT, 0x274, 0, 6, CLK_DIVIDER_HIWORD_MASK, 0, },
+ { HI3670_CLK_DIV_IOPERI, "clk_div_ioperi", "clk_andgt_ioperi",
+ CLK_SET_RATE_PARENT, 0x270, 0, 6, CLK_DIVIDER_HIWORD_MASK, 0, },
+ { HI3670_CLK_DIV_CLKOUT0_TCXO, "clk_div_clkout0_tcxo", "clkin_sys",
+ CLK_SET_RATE_PARENT, 0x254, 6, 3, CLK_DIVIDER_HIWORD_MASK, 0, },
+ { HI3670_CLK_DIV_CLKOUT1_TCXO, "clk_div_clkout1_tcxo", "clkin_sys",
+ CLK_SET_RATE_PARENT, 0x254, 9, 3, CLK_DIVIDER_HIWORD_MASK, 0, },
+ { HI3670_CLK_ASP_SUBSYS_PERI_DIV, "clk_asp_subsys_peri_div", "clkandgt_asp_subsys_peri",
+ CLK_SET_RATE_PARENT, 0x268, 0, 3, CLK_DIVIDER_HIWORD_MASK, 0, },
+ { HI3670_CLK_DIV_ASP_SUBSYS, "clk_div_asp_subsys", "clk_angt_asp_subsys",
+ CLK_SET_RATE_PARENT, 0x250, 0, 3, CLK_DIVIDER_HIWORD_MASK, 0, },
+};
+
+/* clk_iomcu */
+static const struct hisi_fixed_factor_clock hi3670_iomcu_fixed_factor_clks[] = {
+ { HI3670_CLK_GATE_I2C0, "clk_gate_i2c0", "clk_i2c0_gate_iomcu", 1, 4, 0, },
+ { HI3670_CLK_GATE_I2C1, "clk_gate_i2c1", "clk_i2c1_gate_iomcu", 1, 4, 0, },
+ { HI3670_CLK_GATE_I2C2, "clk_gate_i2c2", "clk_i2c2_gate_iomcu", 1, 4, 0, },
+ { HI3670_CLK_GATE_SPI0, "clk_gate_spi0", "clk_spi0_gate_iomcu", 1, 1, 0, },
+ { HI3670_CLK_GATE_SPI2, "clk_gate_spi2", "clk_spi2_gate_iomcu", 1, 1, 0, },
+ { HI3670_CLK_GATE_UART3, "clk_gate_uart3", "clk_uart3_gate_iomcu", 1, 16, 0, },
+};
+
+static const struct hisi_gate_clock hi3670_iomcu_gate_sep_clks[] = {
+ { HI3670_CLK_I2C0_GATE_IOMCU, "clk_i2c0_gate_iomcu", "clk_fll_src",
+ CLK_SET_RATE_PARENT, 0x10, 3, 0, },
+ { HI3670_CLK_I2C1_GATE_IOMCU, "clk_i2c1_gate_iomcu", "clk_fll_src",
+ CLK_SET_RATE_PARENT, 0x10, 4, 0, },
+ { HI3670_CLK_I2C2_GATE_IOMCU, "clk_i2c2_gate_iomcu", "clk_fll_src",
+ CLK_SET_RATE_PARENT, 0x10, 5, 0, },
+ { HI3670_CLK_SPI0_GATE_IOMCU, "clk_spi0_gate_iomcu", "clk_fll_src",
+ CLK_SET_RATE_PARENT, 0x10, 10, 0, },
+ { HI3670_CLK_SPI2_GATE_IOMCU, "clk_spi2_gate_iomcu", "clk_fll_src",
+ CLK_SET_RATE_PARENT, 0x10, 30, 0, },
+ { HI3670_CLK_UART3_GATE_IOMCU, "clk_uart3_gate_iomcu", "clk_gate_iomcu_peri0",
+ CLK_SET_RATE_PARENT, 0x10, 11, 0, },
+ { HI3670_CLK_GATE_PERI0_IOMCU, "clk_gate_iomcu_peri0", "clk_ppll0",
+ CLK_SET_RATE_PARENT, 0x90, 0, 0, },
+};
+
+/* clk_media1 */
+static const struct hisi_gate_clock hi3670_media1_gate_sep_clks[] = {
+ { HI3670_ACLK_GATE_NOC_DSS, "aclk_gate_noc_dss", "aclk_gate_disp_noc_subsys",
+ CLK_SET_RATE_PARENT, 0x10, 21, 0, },
+ { HI3670_PCLK_GATE_NOC_DSS_CFG, "pclk_gate_noc_dss_cfg", "pclk_gate_disp_noc_subsys",
+ CLK_SET_RATE_PARENT, 0x10, 22, 0, },
+ { HI3670_PCLK_GATE_MMBUF_CFG, "pclk_gate_mmbuf_cfg", "pclk_gate_disp_noc_subsys",
+ CLK_SET_RATE_PARENT, 0x20, 5, 0, },
+ { HI3670_PCLK_GATE_DISP_NOC_SUBSYS, "pclk_gate_disp_noc_subsys", "clk_div_sysbus",
+ CLK_SET_RATE_PARENT, 0x10, 18, 0, },
+ { HI3670_ACLK_GATE_DISP_NOC_SUBSYS, "aclk_gate_disp_noc_subsys", "clk_gate_vivobusfreq",
+ CLK_SET_RATE_PARENT, 0x10, 17, 0, },
+ { HI3670_PCLK_GATE_DSS, "pclk_gate_dss", "pclk_gate_disp_noc_subsys",
+ CLK_SET_RATE_PARENT, 0x00, 14, 0, },
+ { HI3670_ACLK_GATE_DSS, "aclk_gate_dss", "aclk_gate_disp_noc_subsys",
+ CLK_SET_RATE_PARENT, 0x00, 19, 0, },
+ { HI3670_CLK_GATE_VIVOBUSFREQ, "clk_gate_vivobusfreq", "clk_div_vivobus",
+ CLK_SET_RATE_PARENT, 0x00, 18, 0, },
+ { HI3670_CLK_GATE_EDC0, "clk_gate_edc0", "clk_div_edc0",
+ CLK_SET_RATE_PARENT, 0x00, 15, 0, },
+ { HI3670_CLK_GATE_LDI0, "clk_gate_ldi0", "clk_div_ldi0",
+ CLK_SET_RATE_PARENT, 0x00, 16, 0, },
+ { HI3670_CLK_GATE_LDI1FREQ, "clk_gate_ldi1freq", "clk_div_ldi1",
+ CLK_SET_RATE_PARENT, 0x00, 17, 0, },
+ { HI3670_CLK_GATE_BRG, "clk_gate_brg", "clk_media_common_div",
+ CLK_SET_RATE_PARENT, 0x00, 29, 0, },
+ { HI3670_ACLK_GATE_ASC, "aclk_gate_asc", "clk_gate_mmbuf",
+ CLK_SET_RATE_PARENT, 0x20, 3, 0, },
+ { HI3670_CLK_GATE_DSS_AXI_MM, "clk_gate_dss_axi_mm", "clk_gate_mmbuf",
+ CLK_SET_RATE_PARENT, 0x20, 4, 0, },
+ { HI3670_CLK_GATE_MMBUF, "clk_gate_mmbuf", "aclk_div_mmbuf",
+ CLK_SET_RATE_PARENT, 0x20, 0, 0, },
+ { HI3670_PCLK_GATE_MMBUF, "pclk_gate_mmbuf", "pclk_div_mmbuf",
+ CLK_SET_RATE_PARENT, 0x20, 1, 0, },
+ { HI3670_CLK_GATE_ATDIV_VIVO, "clk_gate_atdiv_vivo", "clk_div_vivobus",
+ CLK_SET_RATE_PARENT, 0x010, 1, 0, },
+};
+
+static const struct hisi_gate_clock hi3670_media1_gate_clks[] = {
+ { HI3670_CLK_GATE_VIVOBUS_ANDGT, "clk_gate_vivobus_andgt", "clk_mux_vivobus",
+ CLK_SET_RATE_PARENT, 0x84, 3, CLK_GATE_HIWORD_MASK, 0, },
+ { HI3670_CLK_ANDGT_EDC0, "clk_andgt_edc0", "clk_mux_edc0",
+ CLK_SET_RATE_PARENT, 0x84, 7, CLK_GATE_HIWORD_MASK, 0, },
+ { HI3670_CLK_ANDGT_LDI0, "clk_andgt_ldi0", "clk_mux_ldi0",
+ CLK_SET_RATE_PARENT, 0x84, 9, CLK_GATE_HIWORD_MASK, 0, },
+ { HI3670_CLK_ANDGT_LDI1, "clk_andgt_ldi1", "clk_mux_ldi1",
+ CLK_SET_RATE_PARENT, 0x84, 8, CLK_GATE_HIWORD_MASK, 0, },
+ { HI3670_CLK_MMBUF_PLL_ANDGT, "clk_mmbuf_pll_andgt", "clk_sw_mmbuf",
+ CLK_SET_RATE_PARENT, 0x84, 14, CLK_GATE_HIWORD_MASK, 0, },
+ { HI3670_PCLK_MMBUF_ANDGT, "pclk_mmbuf_andgt", "aclk_div_mmbuf",
+ CLK_SET_RATE_PARENT, 0x84, 15, CLK_GATE_HIWORD_MASK, 0, },
+};
+
+static const char *const
+clk_mux_vivobus_p[] = { "clk_invalid", "clk_invalid", "clk_gate_ppll0_media",
+ "clk_invalid", "clk_gate_ppll2_media", "clk_invalid",
+ "clk_invalid", "clk_invalid", "clk_gate_ppll3_media",
+ "clk_invalid", "clk_invalid", "clk_invalid",
+ "clk_invalid", "clk_invalid", "clk_invalid",
+ "clk_invalid", };
+static const char *const
+clk_mux_edc0_p[] = { "clk_invalid", "clk_invalid", "clk_gate_ppll0_media",
+ "clk_invalid", "clk_gate_ppll2_media", "clk_invalid",
+ "clk_invalid", "clk_invalid", "clk_gate_ppll3_media",
+ "clk_invalid", "clk_invalid", "clk_invalid", "clk_invalid",
+ "clk_invalid", "clk_invalid", "clk_invalid", };
+static const char *const
+clk_mux_ldi0_p[] = { "clk_invalid", "clk_gate_ppll7_media",
+ "clk_gate_ppll0_media", "clk_invalid",
+ "clk_gate_ppll2_media", "clk_invalid", "clk_invalid",
+ "clk_invalid", "clk_gate_ppll3_media", "clk_invalid",
+ "clk_invalid", "clk_invalid", "clk_invalid", "clk_invalid",
+ "clk_invalid", "clk_invalid", };
+static const char *const
+clk_mux_ldi1_p[] = { "clk_invalid", "clk_gate_ppll7_media",
+ "clk_gate_ppll0_media", "clk_invalid",
+ "clk_gate_ppll2_media", "clk_invalid", "clk_invalid",
+ "clk_invalid", "clk_gate_ppll3_media", "clk_invalid",
+ "clk_invalid", "clk_invalid", "clk_invalid", "clk_invalid",
+ "clk_invalid", "clk_invalid", };
+static const char *const
+clk_sw_mmbuf_p[] = { "clk_invalid", "clk_invalid", "clk_gate_ppll0_media",
+ "clk_invalid", "clk_gate_ppll2_media", "clk_invalid",
+ "clk_invalid", "clk_invalid", "clk_gate_ppll3_media",
+ "clk_invalid", "clk_invalid", "clk_invalid", "clk_invalid",
+ "clk_invalid", "clk_invalid", "clk_invalid", };
+
+static const struct hisi_mux_clock hi3670_media1_mux_clks[] = {
+ { HI3670_CLK_MUX_VIVOBUS, "clk_mux_vivobus", clk_mux_vivobus_p,
+ ARRAY_SIZE(clk_mux_vivobus_p), CLK_SET_RATE_PARENT,
+ 0x74, 6, 4, CLK_MUX_HIWORD_MASK, },
+ { HI3670_CLK_MUX_EDC0, "clk_mux_edc0", clk_mux_edc0_p,
+ ARRAY_SIZE(clk_mux_edc0_p), CLK_SET_RATE_PARENT,
+ 0x68, 6, 4, CLK_MUX_HIWORD_MASK, },
+ { HI3670_CLK_MUX_LDI0, "clk_mux_ldi0", clk_mux_ldi0_p,
+ ARRAY_SIZE(clk_mux_ldi0_p), CLK_SET_RATE_PARENT,
+ 0x60, 6, 4, CLK_MUX_HIWORD_MASK, },
+ { HI3670_CLK_MUX_LDI1, "clk_mux_ldi1", clk_mux_ldi1_p,
+ ARRAY_SIZE(clk_mux_ldi1_p), CLK_SET_RATE_PARENT,
+ 0x64, 6, 4, CLK_MUX_HIWORD_MASK, },
+ { HI3670_CLK_SW_MMBUF, "clk_sw_mmbuf", clk_sw_mmbuf_p,
+ ARRAY_SIZE(clk_sw_mmbuf_p), CLK_SET_RATE_PARENT,
+ 0x88, 0, 4, CLK_MUX_HIWORD_MASK, },
+};
+
+static const struct hisi_divider_clock hi3670_media1_divider_clks[] = {
+ { HI3670_CLK_DIV_VIVOBUS, "clk_div_vivobus", "clk_gate_vivobus_andgt",
+ CLK_SET_RATE_PARENT, 0x74, 0, 6, CLK_DIVIDER_HIWORD_MASK, 0, },
+ { HI3670_CLK_DIV_EDC0, "clk_div_edc0", "clk_andgt_edc0",
+ CLK_SET_RATE_PARENT, 0x68, 0, 6, CLK_DIVIDER_HIWORD_MASK, 0, },
+ { HI3670_CLK_DIV_LDI0, "clk_div_ldi0", "clk_andgt_ldi0",
+ CLK_SET_RATE_PARENT, 0x60, 0, 6, CLK_DIVIDER_HIWORD_MASK, 0, },
+ { HI3670_CLK_DIV_LDI1, "clk_div_ldi1", "clk_andgt_ldi1",
+ CLK_SET_RATE_PARENT, 0x64, 0, 6, CLK_DIVIDER_HIWORD_MASK, 0, },
+ { HI3670_ACLK_DIV_MMBUF, "aclk_div_mmbuf", "clk_mmbuf_pll_andgt",
+ CLK_SET_RATE_PARENT, 0x7C, 10, 6, CLK_DIVIDER_HIWORD_MASK, 0, },
+ { HI3670_PCLK_DIV_MMBUF, "pclk_div_mmbuf", "pclk_mmbuf_andgt",
+ CLK_SET_RATE_PARENT, 0x78, 0, 2, CLK_DIVIDER_HIWORD_MASK, 0, },
+};
+
+/* clk_media2 */
+static const struct hisi_gate_clock hi3670_media2_gate_sep_clks[] = {
+ { HI3670_CLK_GATE_VDECFREQ, "clk_gate_vdecfreq", "clk_div_vdec",
+ CLK_SET_RATE_PARENT, 0x00, 8, 0, },
+ { HI3670_CLK_GATE_VENCFREQ, "clk_gate_vencfreq", "clk_div_venc",
+ CLK_SET_RATE_PARENT, 0x00, 5, 0, },
+ { HI3670_CLK_GATE_ICSFREQ, "clk_gate_icsfreq", "clk_div_ics",
+ CLK_SET_RATE_PARENT, 0x00, 2, 0, },
+};
+
+static void hi3670_clk_crgctrl_init(struct device_node *np)
+{
+ struct hisi_clock_data *clk_data;
+
+ int nr = ARRAY_SIZE(hi3670_fixed_rate_clks) +
+ ARRAY_SIZE(hi3670_crgctrl_gate_sep_clks) +
+ ARRAY_SIZE(hi3670_crgctrl_gate_clks) +
+ ARRAY_SIZE(hi3670_crgctrl_mux_clks) +
+ ARRAY_SIZE(hi3670_crg_fixed_factor_clks) +
+ ARRAY_SIZE(hi3670_crgctrl_divider_clks);
+
+ clk_data = hisi_clk_init(np, nr);
+ if (!clk_data)
+ return;
+
+ hisi_clk_register_fixed_rate(hi3670_fixed_rate_clks,
+ ARRAY_SIZE(hi3670_fixed_rate_clks),
+ clk_data);
+ hisi_clk_register_gate_sep(hi3670_crgctrl_gate_sep_clks,
+ ARRAY_SIZE(hi3670_crgctrl_gate_sep_clks),
+ clk_data);
+ hisi_clk_register_gate(hi3670_crgctrl_gate_clks,
+ ARRAY_SIZE(hi3670_crgctrl_gate_clks),
+ clk_data);
+ hisi_clk_register_mux(hi3670_crgctrl_mux_clks,
+ ARRAY_SIZE(hi3670_crgctrl_mux_clks),
+ clk_data);
+ hisi_clk_register_fixed_factor(hi3670_crg_fixed_factor_clks,
+ ARRAY_SIZE(hi3670_crg_fixed_factor_clks),
+ clk_data);
+ hisi_clk_register_divider(hi3670_crgctrl_divider_clks,
+ ARRAY_SIZE(hi3670_crgctrl_divider_clks),
+ clk_data);
+}
+
+static void hi3670_clk_pctrl_init(struct device_node *np)
+{
+ struct hisi_clock_data *clk_data;
+ int nr = ARRAY_SIZE(hi3670_pctrl_gate_clks);
+
+ clk_data = hisi_clk_init(np, nr);
+ if (!clk_data)
+ return;
+ hisi_clk_register_gate(hi3670_pctrl_gate_clks,
+ ARRAY_SIZE(hi3670_pctrl_gate_clks), clk_data);
+}
+
+static void hi3670_clk_pmuctrl_init(struct device_node *np)
+{
+ struct hisi_clock_data *clk_data;
+ int nr = ARRAY_SIZE(hi3670_pmu_gate_clks);
+
+ clk_data = hisi_clk_init(np, nr);
+ if (!clk_data)
+ return;
+
+ hisi_clk_register_gate(hi3670_pmu_gate_clks,
+ ARRAY_SIZE(hi3670_pmu_gate_clks), clk_data);
+}
+
+static void hi3670_clk_sctrl_init(struct device_node *np)
+{
+ struct hisi_clock_data *clk_data;
+ int nr = ARRAY_SIZE(hi3670_sctrl_gate_sep_clks) +
+ ARRAY_SIZE(hi3670_sctrl_gate_clks) +
+ ARRAY_SIZE(hi3670_sctrl_mux_clks) +
+ ARRAY_SIZE(hi3670_sctrl_divider_clks);
+
+ clk_data = hisi_clk_init(np, nr);
+ if (!clk_data)
+ return;
+
+ hisi_clk_register_gate_sep(hi3670_sctrl_gate_sep_clks,
+ ARRAY_SIZE(hi3670_sctrl_gate_sep_clks),
+ clk_data);
+ hisi_clk_register_gate(hi3670_sctrl_gate_clks,
+ ARRAY_SIZE(hi3670_sctrl_gate_clks),
+ clk_data);
+ hisi_clk_register_mux(hi3670_sctrl_mux_clks,
+ ARRAY_SIZE(hi3670_sctrl_mux_clks),
+ clk_data);
+ hisi_clk_register_divider(hi3670_sctrl_divider_clks,
+ ARRAY_SIZE(hi3670_sctrl_divider_clks),
+ clk_data);
+}
+
+static void hi3670_clk_iomcu_init(struct device_node *np)
+{
+ struct hisi_clock_data *clk_data;
+ int nr = ARRAY_SIZE(hi3670_iomcu_gate_sep_clks) +
+ ARRAY_SIZE(hi3670_iomcu_fixed_factor_clks);
+
+ clk_data = hisi_clk_init(np, nr);
+ if (!clk_data)
+ return;
+
+ hisi_clk_register_gate(hi3670_iomcu_gate_sep_clks,
+ ARRAY_SIZE(hi3670_iomcu_gate_sep_clks), clk_data);
+
+ hisi_clk_register_fixed_factor(hi3670_iomcu_fixed_factor_clks,
+ ARRAY_SIZE(hi3670_iomcu_fixed_factor_clks),
+ clk_data);
+}
+
+static void hi3670_clk_media1_init(struct device_node *np)
+{
+ struct hisi_clock_data *clk_data;
+
+ int nr = ARRAY_SIZE(hi3670_media1_gate_sep_clks) +
+ ARRAY_SIZE(hi3670_media1_gate_clks) +
+ ARRAY_SIZE(hi3670_media1_mux_clks) +
+ ARRAY_SIZE(hi3670_media1_divider_clks);
+
+ clk_data = hisi_clk_init(np, nr);
+ if (!clk_data)
+ return;
+
+ hisi_clk_register_gate_sep(hi3670_media1_gate_sep_clks,
+ ARRAY_SIZE(hi3670_media1_gate_sep_clks),
+ clk_data);
+ hisi_clk_register_gate(hi3670_media1_gate_clks,
+ ARRAY_SIZE(hi3670_media1_gate_clks),
+ clk_data);
+ hisi_clk_register_mux(hi3670_media1_mux_clks,
+ ARRAY_SIZE(hi3670_media1_mux_clks),
+ clk_data);
+ hisi_clk_register_divider(hi3670_media1_divider_clks,
+ ARRAY_SIZE(hi3670_media1_divider_clks),
+ clk_data);
+}
+
+static void hi3670_clk_media2_init(struct device_node *np)
+{
+ struct hisi_clock_data *clk_data;
+
+ int nr = ARRAY_SIZE(hi3670_media2_gate_sep_clks);
+
+ clk_data = hisi_clk_init(np, nr);
+ if (!clk_data)
+ return;
+
+ hisi_clk_register_gate_sep(hi3670_media2_gate_sep_clks,
+ ARRAY_SIZE(hi3670_media2_gate_sep_clks),
+ clk_data);
+}
+
+static const struct of_device_id hi3670_clk_match_table[] = {
+ { .compatible = "hisilicon,hi3670-crgctrl",
+ .data = hi3670_clk_crgctrl_init },
+ { .compatible = "hisilicon,hi3670-pctrl",
+ .data = hi3670_clk_pctrl_init },
+ { .compatible = "hisilicon,hi3670-pmuctrl",
+ .data = hi3670_clk_pmuctrl_init },
+ { .compatible = "hisilicon,hi3670-sctrl",
+ .data = hi3670_clk_sctrl_init },
+ { .compatible = "hisilicon,hi3670-iomcu",
+ .data = hi3670_clk_iomcu_init },
+ { .compatible = "hisilicon,hi3670-media1-crg",
+ .data = hi3670_clk_media1_init },
+ { .compatible = "hisilicon,hi3670-media2-crg",
+ .data = hi3670_clk_media2_init },
+ { }
+};
+
+static int hi3670_clk_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = pdev->dev.of_node;
+ void (*init_func)(struct device_node *np);
+
+ init_func = of_device_get_match_data(dev);
+ if (!init_func)
+ return -ENODEV;
+
+ init_func(np);
+
+ return 0;
+}
+
+static struct platform_driver hi3670_clk_driver = {
+ .probe = hi3670_clk_probe,
+ .driver = {
+ .name = "hi3670-clk",
+ .of_match_table = hi3670_clk_match_table,
+ },
+};
+
+static int __init hi3670_clk_init(void)
+{
+ return platform_driver_register(&hi3670_clk_driver);
+}
+core_initcall(hi3670_clk_init);
diff --git a/drivers/clk/hisilicon/reset.c b/drivers/clk/hisilicon/reset.c
index 2a5015c736ce..43e82fa64422 100644
--- a/drivers/clk/hisilicon/reset.c
+++ b/drivers/clk/hisilicon/reset.c
@@ -109,9 +109,8 @@ struct hisi_reset_controller *hisi_reset_init(struct platform_device *pdev)
return NULL;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- rstc->membase = devm_ioremap(&pdev->dev,
- res->start, resource_size(res));
- if (!rstc->membase)
+ rstc->membase = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(rstc->membase))
return NULL;
spin_lock_init(&rstc->lock);
diff --git a/drivers/clk/imx/clk-cpu.c b/drivers/clk/imx/clk-cpu.c
index 9d46eac87f45..ed1b7e97a0d3 100644
--- a/drivers/clk/imx/clk-cpu.c
+++ b/drivers/clk/imx/clk-cpu.c
@@ -94,7 +94,7 @@ struct clk *imx_clk_cpu(const char *name, const char *parent_name,
init.name = name;
init.ops = &clk_cpu_ops;
- init.flags = 0;
+ init.flags = CLK_IS_CRITICAL;
init.parent_names = &parent_name;
init.num_parents = 1;
diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c
index 8c7c2fcb8d94..bbe0c60f4d09 100644
--- a/drivers/clk/imx/clk-imx6q.c
+++ b/drivers/clk/imx/clk-imx6q.c
@@ -789,6 +789,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
clk[IMX6QDL_CLK_MLB] = imx_clk_gate2("mlb", "axi", base + 0x74, 18);
clk[IMX6QDL_CLK_MMDC_CH0_AXI] = imx_clk_gate2_flags("mmdc_ch0_axi", "mmdc_ch0_axi_podf", base + 0x74, 20, CLK_IS_CRITICAL);
clk[IMX6QDL_CLK_MMDC_CH1_AXI] = imx_clk_gate2("mmdc_ch1_axi", "mmdc_ch1_axi_podf", base + 0x74, 22);
+ clk[IMX6QDL_CLK_MMDC_P0_IPG] = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL);
clk[IMX6QDL_CLK_OCRAM] = imx_clk_gate2("ocram", "ahb", base + 0x74, 28);
clk[IMX6QDL_CLK_OPENVG_AXI] = imx_clk_gate2("openvg_axi", "axi", base + 0x74, 30);
clk[IMX6QDL_CLK_PCIE_AXI] = imx_clk_gate2("pcie_axi", "pcie_axi_sel", base + 0x78, 0);
diff --git a/drivers/clk/imx/clk-imx6sl.c b/drivers/clk/imx/clk-imx6sl.c
index eb6bcbf345a3..6fcfbbd907a5 100644
--- a/drivers/clk/imx/clk-imx6sl.c
+++ b/drivers/clk/imx/clk-imx6sl.c
@@ -386,6 +386,8 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
clks[IMX6SL_CLK_LCDIF_AXI] = imx_clk_gate2("lcdif_axi", "lcdif_axi_podf", base + 0x74, 6);
clks[IMX6SL_CLK_LCDIF_PIX] = imx_clk_gate2("lcdif_pix", "lcdif_pix_podf", base + 0x74, 8);
clks[IMX6SL_CLK_EPDC_PIX] = imx_clk_gate2("epdc_pix", "epdc_pix_podf", base + 0x74, 10);
+ clks[IMX6SL_CLK_MMDC_P0_IPG] = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL);
+ clks[IMX6SL_CLK_MMDC_P1_IPG] = imx_clk_gate2("mmdc_p1_ipg", "ipg", base + 0x74, 26);
clks[IMX6SL_CLK_OCRAM] = imx_clk_gate2("ocram", "ocram_podf", base + 0x74, 28);
clks[IMX6SL_CLK_PWM1] = imx_clk_gate2("pwm1", "perclk", base + 0x78, 16);
clks[IMX6SL_CLK_PWM2] = imx_clk_gate2("pwm2", "perclk", base + 0x78, 18);
diff --git a/drivers/clk/imx/clk-imx6sll.c b/drivers/clk/imx/clk-imx6sll.c
index 52379ee49aec..3bd2044cf25c 100644
--- a/drivers/clk/imx/clk-imx6sll.c
+++ b/drivers/clk/imx/clk-imx6sll.c
@@ -293,6 +293,7 @@ static void __init imx6sll_clocks_init(struct device_node *ccm_node)
clks[IMX6SLL_CLK_WDOG1] = imx_clk_gate2("wdog1", "ipg", base + 0x74, 16);
clks[IMX6SLL_CLK_MMDC_P0_FAST] = imx_clk_gate_flags("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20, CLK_IS_CRITICAL);
clks[IMX6SLL_CLK_MMDC_P0_IPG] = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL);
+ clks[IMX6SLL_CLK_MMDC_P1_IPG] = imx_clk_gate2("mmdc_p1_ipg", "ipg", base + 0x74, 26);
clks[IMX6SLL_CLK_OCRAM] = imx_clk_gate_flags("ocram","ahb", base + 0x74, 28, CLK_IS_CRITICAL);
/* CCGR4 */
diff --git a/drivers/clk/imx/clk-imx6sx.c b/drivers/clk/imx/clk-imx6sx.c
index d9f2890ffe62..18527a335ace 100644
--- a/drivers/clk/imx/clk-imx6sx.c
+++ b/drivers/clk/imx/clk-imx6sx.c
@@ -431,6 +431,7 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
clks[IMX6SX_CLK_MLB] = imx_clk_gate2("mlb", "ahb", base + 0x74, 18);
clks[IMX6SX_CLK_MMDC_P0_FAST] = imx_clk_gate2_flags("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20, CLK_IS_CRITICAL);
clks[IMX6SX_CLK_MMDC_P0_IPG] = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL);
+ clks[IMX6SX_CLK_MMDC_P1_IPG] = imx_clk_gate2("mmdc_p1_ipg", "ipg", base + 0x74, 26);
clks[IMX6SX_CLK_OCRAM] = imx_clk_gate2_flags("ocram", "ocram_podf", base + 0x74, 28, CLK_IS_CRITICAL);
/* CCGR4 */
diff --git a/drivers/clk/imx/clk-imx6ul.c b/drivers/clk/imx/clk-imx6ul.c
index 361b43f9742e..fd60d1549f71 100644
--- a/drivers/clk/imx/clk-imx6ul.c
+++ b/drivers/clk/imx/clk-imx6ul.c
@@ -408,6 +408,7 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
clks[IMX6UL_CLK_WDOG1] = imx_clk_gate2("wdog1", "ipg", base + 0x74, 16);
clks[IMX6UL_CLK_MMDC_P0_FAST] = imx_clk_gate_flags("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20, CLK_IS_CRITICAL);
clks[IMX6UL_CLK_MMDC_P0_IPG] = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL);
+ clks[IMX6UL_CLK_MMDC_P1_IPG] = imx_clk_gate2("mmdc_p1_ipg", "ipg", base + 0x74, 26);
clks[IMX6UL_CLK_AXI] = imx_clk_gate_flags("axi", "axi_podf", base + 0x74, 28, CLK_IS_CRITICAL);
/* CCGR4 */
diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c
index 881b772c4ac9..adb08f64c691 100644
--- a/drivers/clk/imx/clk-imx7d.c
+++ b/drivers/clk/imx/clk-imx7d.c
@@ -379,14 +379,6 @@ static const char *pll_enet_bypass_sel[] = { "pll_enet_main", "pll_enet_main_src
static const char *pll_audio_bypass_sel[] = { "pll_audio_main", "pll_audio_main_src", };
static const char *pll_video_bypass_sel[] = { "pll_video_main", "pll_video_main_src", };
-static int const clks_init_on[] __initconst = {
- IMX7D_ARM_A7_ROOT_CLK, IMX7D_MAIN_AXI_ROOT_CLK,
- IMX7D_PLL_SYS_MAIN_480M_CLK, IMX7D_NAND_USDHC_BUS_ROOT_CLK,
- IMX7D_DRAM_PHYM_ROOT_CLK, IMX7D_DRAM_ROOT_CLK,
- IMX7D_DRAM_PHYM_ALT_ROOT_CLK, IMX7D_DRAM_ALT_ROOT_CLK,
- IMX7D_AHB_CHANNEL_ROOT_CLK, IMX7D_IPG_ROOT_CLK,
-};
-
static struct clk_onecell_data clk_data;
static struct clk ** const uart_clks[] __initconst = {
@@ -404,7 +396,6 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
{
struct device_node *np;
void __iomem *base;
- int i;
clks[IMX7D_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
clks[IMX7D_OSC_24M_CLK] = of_clk_get_by_name(ccm_node, "osc");
@@ -467,7 +458,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
clks[IMX7D_PLL_SYS_MAIN_120M] = imx_clk_fixed_factor("pll_sys_main_120m", "pll_sys_main_clk", 1, 4);
clks[IMX7D_PLL_DRAM_MAIN_533M] = imx_clk_fixed_factor("pll_dram_533m", "pll_dram_main_clk", 1, 2);
- clks[IMX7D_PLL_SYS_MAIN_480M_CLK] = imx_clk_gate_dis("pll_sys_main_480m_clk", "pll_sys_main_480m", base + 0xb0, 4);
+ clks[IMX7D_PLL_SYS_MAIN_480M_CLK] = imx_clk_gate_dis_flags("pll_sys_main_480m_clk", "pll_sys_main_480m", base + 0xb0, 4, CLK_IS_CRITICAL);
clks[IMX7D_PLL_SYS_MAIN_240M_CLK] = imx_clk_gate_dis("pll_sys_main_240m_clk", "pll_sys_main_240m", base + 0xb0, 5);
clks[IMX7D_PLL_SYS_MAIN_120M_CLK] = imx_clk_gate_dis("pll_sys_main_120m_clk", "pll_sys_main_120m", base + 0xb0, 6);
clks[IMX7D_PLL_DRAM_MAIN_533M_CLK] = imx_clk_gate("pll_dram_533m_clk", "pll_dram_533m", base + 0x70, 12);
@@ -720,7 +711,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
clks[IMX7D_ENET_AXI_ROOT_DIV] = imx_clk_divider2("enet_axi_post_div", "enet_axi_pre_div", base + 0x8900, 0, 6);
clks[IMX7D_NAND_USDHC_BUS_ROOT_CLK] = imx_clk_divider2("nand_usdhc_root_clk", "nand_usdhc_pre_div", base + 0x8980, 0, 6);
clks[IMX7D_AHB_CHANNEL_ROOT_DIV] = imx_clk_divider2("ahb_root_clk", "ahb_pre_div", base + 0x9000, 0, 6);
- clks[IMX7D_IPG_ROOT_CLK] = imx_clk_divider2("ipg_root_clk", "ahb_root_clk", base + 0x9080, 0, 2);
+ clks[IMX7D_IPG_ROOT_CLK] = imx_clk_divider_flags("ipg_root_clk", "ahb_root_clk", base + 0x9080, 0, 2, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE | CLK_SET_RATE_PARENT);
clks[IMX7D_DRAM_ROOT_DIV] = imx_clk_divider2("dram_post_div", "dram_cg", base + 0x9880, 0, 3);
clks[IMX7D_DRAM_PHYM_ALT_ROOT_DIV] = imx_clk_divider2("dram_phym_alt_post_div", "dram_phym_alt_pre_div", base + 0xa000, 0, 3);
clks[IMX7D_DRAM_ALT_ROOT_DIV] = imx_clk_divider2("dram_alt_post_div", "dram_alt_pre_div", base + 0xa080, 0, 3);
@@ -784,17 +775,17 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
clks[IMX7D_CLKO1_ROOT_DIV] = imx_clk_divider2("clko1_post_div", "clko1_pre_div", base + 0xbd80, 0, 6);
clks[IMX7D_CLKO2_ROOT_DIV] = imx_clk_divider2("clko2_post_div", "clko2_pre_div", base + 0xbe00, 0, 6);
- clks[IMX7D_ARM_A7_ROOT_CLK] = imx_clk_gate4("arm_a7_root_clk", "arm_a7_div", base + 0x4000, 0);
+ clks[IMX7D_ARM_A7_ROOT_CLK] = imx_clk_gate2_flags("arm_a7_root_clk", "arm_a7_div", base + 0x4000, 0, CLK_OPS_PARENT_ENABLE);
clks[IMX7D_ARM_M4_ROOT_CLK] = imx_clk_gate4("arm_m4_root_clk", "arm_m4_div", base + 0x4010, 0);
- clks[IMX7D_MAIN_AXI_ROOT_CLK] = imx_clk_gate4("main_axi_root_clk", "axi_post_div", base + 0x4040, 0);
+ clks[IMX7D_MAIN_AXI_ROOT_CLK] = imx_clk_gate2_flags("main_axi_root_clk", "axi_post_div", base + 0x4040, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
clks[IMX7D_DISP_AXI_ROOT_CLK] = imx_clk_gate4("disp_axi_root_clk", "disp_axi_post_div", base + 0x4050, 0);
clks[IMX7D_ENET_AXI_ROOT_CLK] = imx_clk_gate4("enet_axi_root_clk", "enet_axi_post_div", base + 0x4060, 0);
clks[IMX7D_OCRAM_CLK] = imx_clk_gate4("ocram_clk", "main_axi_root_clk", base + 0x4110, 0);
clks[IMX7D_OCRAM_S_CLK] = imx_clk_gate4("ocram_s_clk", "ahb_root_clk", base + 0x4120, 0);
- clks[IMX7D_DRAM_ROOT_CLK] = imx_clk_gate4("dram_root_clk", "dram_post_div", base + 0x4130, 0);
- clks[IMX7D_DRAM_PHYM_ROOT_CLK] = imx_clk_gate4("dram_phym_root_clk", "dram_phym_cg", base + 0x4130, 0);
- clks[IMX7D_DRAM_PHYM_ALT_ROOT_CLK] = imx_clk_gate4("dram_phym_alt_root_clk", "dram_phym_alt_post_div", base + 0x4130, 0);
- clks[IMX7D_DRAM_ALT_ROOT_CLK] = imx_clk_gate4("dram_alt_root_clk", "dram_alt_post_div", base + 0x4130, 0);
+ clks[IMX7D_DRAM_ROOT_CLK] = imx_clk_gate2_flags("dram_root_clk", "dram_post_div", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
+ clks[IMX7D_DRAM_PHYM_ROOT_CLK] = imx_clk_gate2_flags("dram_phym_root_clk", "dram_phym_cg", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
+ clks[IMX7D_DRAM_PHYM_ALT_ROOT_CLK] = imx_clk_gate2_flags("dram_phym_alt_root_clk", "dram_phym_alt_post_div", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
+ clks[IMX7D_DRAM_ALT_ROOT_CLK] = imx_clk_gate2_flags("dram_alt_root_clk", "dram_alt_post_div", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
clks[IMX7D_OCOTP_CLK] = imx_clk_gate4("ocotp_clk", "ipg_root_clk", base + 0x4230, 0);
clks[IMX7D_SNVS_CLK] = imx_clk_gate4("snvs_clk", "ipg_root_clk", base + 0x4250, 0);
clks[IMX7D_MU_ROOT_CLK] = imx_clk_gate4("mu_root_clk", "ipg_root_clk", base + 0x4270, 0);
@@ -883,9 +874,6 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
clk_data.clk_num = ARRAY_SIZE(clks);
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
- for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
- clk_prepare_enable(clks[clks_init_on[i]]);
-
clk_set_parent(clks[IMX7D_PLL_ARM_MAIN_BYPASS], clks[IMX7D_PLL_ARM_MAIN]);
clk_set_parent(clks[IMX7D_PLL_DRAM_MAIN_BYPASS], clks[IMX7D_PLL_DRAM_MAIN]);
clk_set_parent(clks[IMX7D_PLL_SYS_MAIN_BYPASS], clks[IMX7D_PLL_SYS_MAIN]);
diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h
index 8076ec040f37..5895e2237b6c 100644
--- a/drivers/clk/imx/clk.h
+++ b/drivers/clk/imx/clk.h
@@ -137,6 +137,13 @@ static inline struct clk *imx_clk_gate_dis(const char *name, const char *parent,
shift, CLK_GATE_SET_TO_DISABLE, &imx_ccm_lock);
}
+static inline struct clk *imx_clk_gate_dis_flags(const char *name, const char *parent,
+ void __iomem *reg, u8 shift, unsigned long flags)
+{
+ return clk_register_gate(NULL, name, parent, flags | CLK_SET_RATE_PARENT, reg,
+ shift, CLK_GATE_SET_TO_DISABLE, &imx_ccm_lock);
+}
+
static inline struct clk *imx_clk_gate2(const char *name, const char *parent,
void __iomem *reg, u8 shift)
{
diff --git a/drivers/clk/ingenic/Kconfig b/drivers/clk/ingenic/Kconfig
new file mode 100644
index 000000000000..34dc0da79c39
--- /dev/null
+++ b/drivers/clk/ingenic/Kconfig
@@ -0,0 +1,47 @@
+menu "Ingenic JZ47xx CGU drivers"
+ depends on MIPS
+
+config INGENIC_CGU_COMMON
+ bool
+
+config INGENIC_CGU_JZ4740
+ bool "Ingenic JZ4740 CGU driver"
+ default MACH_JZ4740
+ select INGENIC_CGU_COMMON
+ help
+ Support the clocks provided by the CGU hardware on Ingenic JZ4740
+ and compatible SoCs.
+
+ If building for a JZ4740 SoC, you want to say Y here.
+
+config INGENIC_CGU_JZ4725B
+ bool "Ingenic JZ4725B CGU driver"
+ default MACH_JZ4725B
+ select INGENIC_CGU_COMMON
+ help
+ Support the clocks provided by the CGU hardware on Ingenic JZ4725B
+ and compatible SoCs.
+
+ If building for a JZ4725B SoC, you want to say Y here.
+
+config INGENIC_CGU_JZ4770
+ bool "Ingenic JZ4770 CGU driver"
+ default MACH_JZ4770
+ select INGENIC_CGU_COMMON
+ help
+ Support the clocks provided by the CGU hardware on Ingenic JZ4770
+ and compatible SoCs.
+
+ If building for a JZ4770 SoC, you want to say Y here.
+
+config INGENIC_CGU_JZ4780
+ bool "Ingenic JZ4780 CGU driver"
+ default MACH_JZ4780
+ select INGENIC_CGU_COMMON
+ help
+ Support the clocks provided by the CGU hardware on Ingenic JZ4780
+ and compatible SoCs.
+
+ If building for a JZ4780 SoC, you want to say Y here.
+
+endmenu
diff --git a/drivers/clk/ingenic/Makefile b/drivers/clk/ingenic/Makefile
index 1456e4cdb562..00a79b2fba10 100644
--- a/drivers/clk/ingenic/Makefile
+++ b/drivers/clk/ingenic/Makefile
@@ -1,4 +1,5 @@
-obj-y += cgu.o
-obj-$(CONFIG_MACH_JZ4740) += jz4740-cgu.o
-obj-$(CONFIG_MACH_JZ4770) += jz4770-cgu.o
-obj-$(CONFIG_MACH_JZ4780) += jz4780-cgu.o
+obj-$(CONFIG_INGENIC_CGU_COMMON) += cgu.o
+obj-$(CONFIG_INGENIC_CGU_JZ4740) += jz4740-cgu.o
+obj-$(CONFIG_INGENIC_CGU_JZ4725B) += jz4725b-cgu.o
+obj-$(CONFIG_INGENIC_CGU_JZ4770) += jz4770-cgu.o
+obj-$(CONFIG_INGENIC_CGU_JZ4780) += jz4780-cgu.o
diff --git a/drivers/clk/ingenic/jz4725b-cgu.c b/drivers/clk/ingenic/jz4725b-cgu.c
new file mode 100644
index 000000000000..584ff4ff81c7
--- /dev/null
+++ b/drivers/clk/ingenic/jz4725b-cgu.c
@@ -0,0 +1,225 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Ingenic JZ4725B SoC CGU driver
+ *
+ * Copyright (C) 2018 Paul Cercueil
+ * Author: Paul Cercueil <paul@crapouillou.net>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <dt-bindings/clock/jz4725b-cgu.h>
+#include "cgu.h"
+
+/* CGU register offsets */
+#define CGU_REG_CPCCR 0x00
+#define CGU_REG_LCR 0x04
+#define CGU_REG_CPPCR 0x10
+#define CGU_REG_CLKGR 0x20
+#define CGU_REG_OPCR 0x24
+#define CGU_REG_I2SCDR 0x60
+#define CGU_REG_LPCDR 0x64
+#define CGU_REG_MSCCDR 0x68
+#define CGU_REG_SSICDR 0x74
+#define CGU_REG_CIMCDR 0x78
+
+/* bits within the LCR register */
+#define LCR_SLEEP BIT(0)
+
+static struct ingenic_cgu *cgu;
+
+static const s8 pll_od_encoding[4] = {
+ 0x0, 0x1, -1, 0x3,
+};
+
+static const struct ingenic_cgu_clk_info jz4725b_cgu_clocks[] = {
+
+ /* External clocks */
+
+ [JZ4725B_CLK_EXT] = { "ext", CGU_CLK_EXT },
+ [JZ4725B_CLK_OSC32K] = { "osc32k", CGU_CLK_EXT },
+
+ [JZ4725B_CLK_PLL] = {
+ "pll", CGU_CLK_PLL,
+ .parents = { JZ4725B_CLK_EXT, -1, -1, -1 },
+ .pll = {
+ .reg = CGU_REG_CPPCR,
+ .m_shift = 23,
+ .m_bits = 9,
+ .m_offset = 2,
+ .n_shift = 18,
+ .n_bits = 5,
+ .n_offset = 2,
+ .od_shift = 16,
+ .od_bits = 2,
+ .od_max = 4,
+ .od_encoding = pll_od_encoding,
+ .stable_bit = 10,
+ .bypass_bit = 9,
+ .enable_bit = 8,
+ },
+ },
+
+ /* Muxes & dividers */
+
+ [JZ4725B_CLK_PLL_HALF] = {
+ "pll half", CGU_CLK_DIV,
+ .parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
+ .div = { CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1 },
+ },
+
+ [JZ4725B_CLK_CCLK] = {
+ "cclk", CGU_CLK_DIV,
+ .parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
+ .div = { CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1 },
+ },
+
+ [JZ4725B_CLK_HCLK] = {
+ "hclk", CGU_CLK_DIV,
+ .parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
+ .div = { CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1 },
+ },
+
+ [JZ4725B_CLK_PCLK] = {
+ "pclk", CGU_CLK_DIV,
+ .parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
+ .div = { CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1 },
+ },
+
+ [JZ4725B_CLK_MCLK] = {
+ "mclk", CGU_CLK_DIV,
+ .parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
+ .div = { CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1 },
+ },
+
+ [JZ4725B_CLK_IPU] = {
+ "ipu", CGU_CLK_DIV | CGU_CLK_GATE,
+ .parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
+ .div = { CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1 },
+ .gate = { CGU_REG_CLKGR, 13 },
+ },
+
+ [JZ4725B_CLK_LCD] = {
+ "lcd", CGU_CLK_DIV | CGU_CLK_GATE,
+ .parents = { JZ4725B_CLK_PLL_HALF, -1, -1, -1 },
+ .div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR, 9 },
+ },
+
+ [JZ4725B_CLK_I2S] = {
+ "i2s", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
+ .parents = { JZ4725B_CLK_EXT, JZ4725B_CLK_PLL_HALF, -1, -1 },
+ .mux = { CGU_REG_CPCCR, 31, 1 },
+ .div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR, 6 },
+ },
+
+ [JZ4725B_CLK_SPI] = {
+ "spi", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
+ .parents = { JZ4725B_CLK_EXT, JZ4725B_CLK_PLL, -1, -1 },
+ .mux = { CGU_REG_SSICDR, 31, 1 },
+ .div = { CGU_REG_SSICDR, 0, 1, 4, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR, 4 },
+ },
+
+ [JZ4725B_CLK_MMC_MUX] = {
+ "mmc_mux", CGU_CLK_DIV,
+ .parents = { JZ4725B_CLK_PLL_HALF, -1, -1, -1 },
+ .div = { CGU_REG_MSCCDR, 0, 1, 5, -1, -1, -1 },
+ },
+
+ [JZ4725B_CLK_UDC] = {
+ "udc", CGU_CLK_MUX | CGU_CLK_DIV,
+ .parents = { JZ4725B_CLK_EXT, JZ4725B_CLK_PLL_HALF, -1, -1 },
+ .mux = { CGU_REG_CPCCR, 29, 1 },
+ .div = { CGU_REG_CPCCR, 23, 1, 6, -1, -1, -1 },
+ },
+
+ /* Gate-only clocks */
+
+ [JZ4725B_CLK_UART] = {
+ "uart", CGU_CLK_GATE,
+ .parents = { JZ4725B_CLK_EXT, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR, 0 },
+ },
+
+ [JZ4725B_CLK_DMA] = {
+ "dma", CGU_CLK_GATE,
+ .parents = { JZ4725B_CLK_PCLK, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR, 12 },
+ },
+
+ [JZ4725B_CLK_ADC] = {
+ "adc", CGU_CLK_GATE,
+ .parents = { JZ4725B_CLK_EXT, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR, 7 },
+ },
+
+ [JZ4725B_CLK_I2C] = {
+ "i2c", CGU_CLK_GATE,
+ .parents = { JZ4725B_CLK_EXT, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR, 3 },
+ },
+
+ [JZ4725B_CLK_AIC] = {
+ "aic", CGU_CLK_GATE,
+ .parents = { JZ4725B_CLK_EXT, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR, 5 },
+ },
+
+ [JZ4725B_CLK_MMC0] = {
+ "mmc0", CGU_CLK_GATE,
+ .parents = { JZ4725B_CLK_MMC_MUX, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR, 6 },
+ },
+
+ [JZ4725B_CLK_MMC1] = {
+ "mmc1", CGU_CLK_GATE,
+ .parents = { JZ4725B_CLK_MMC_MUX, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR, 16 },
+ },
+
+ [JZ4725B_CLK_BCH] = {
+ "bch", CGU_CLK_GATE,
+ .parents = { JZ4725B_CLK_MCLK/* not sure */, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR, 11 },
+ },
+
+ [JZ4725B_CLK_TCU] = {
+ "tcu", CGU_CLK_GATE,
+ .parents = { JZ4725B_CLK_EXT/* not sure */, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR, 1 },
+ },
+
+ [JZ4725B_CLK_EXT512] = {
+ "ext/512", CGU_CLK_FIXDIV,
+ .parents = { JZ4725B_CLK_EXT },
+
+ /* Doc calls it EXT512, but it seems to be /256... */
+ .fixdiv = { 256 },
+ },
+
+ [JZ4725B_CLK_RTC] = {
+ "rtc", CGU_CLK_MUX,
+ .parents = { JZ4725B_CLK_EXT512, JZ4725B_CLK_OSC32K, -1, -1 },
+ .mux = { CGU_REG_OPCR, 2, 1},
+ },
+};
+
+static void __init jz4725b_cgu_init(struct device_node *np)
+{
+ int retval;
+
+ cgu = ingenic_cgu_new(jz4725b_cgu_clocks,
+ ARRAY_SIZE(jz4725b_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__);
+}
+CLK_OF_DECLARE(jz4725b_cgu, "ingenic,jz4725b-cgu", jz4725b_cgu_init);
diff --git a/drivers/clk/keystone/Kconfig b/drivers/clk/keystone/Kconfig
index 7e9f0176578a..b04927d06cd1 100644
--- a/drivers/clk/keystone/Kconfig
+++ b/drivers/clk/keystone/Kconfig
@@ -7,7 +7,7 @@ config COMMON_CLK_KEYSTONE
config TI_SCI_CLK
tristate "TI System Control Interface clock drivers"
- depends on (ARCH_KEYSTONE || COMPILE_TEST) && OF
+ depends on (ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST) && OF
depends on TI_SCI_PROTOCOL
default ARCH_KEYSTONE
---help---
diff --git a/drivers/clk/keystone/gate.c b/drivers/clk/keystone/gate.c
index aed5af23895b..4ed9b29ba438 100644
--- a/drivers/clk/keystone/gate.c
+++ b/drivers/clk/keystone/gate.c
@@ -245,7 +245,7 @@ static void __init of_psc_clk_init(struct device_node *node, spinlock_t *lock)
return;
}
- pr_err("%s: error registering clk %s\n", __func__, node->name);
+ pr_err("%s: error registering clk %pOFn\n", __func__, node);
unmap_domain:
iounmap(data->domain_base);
@@ -266,3 +266,8 @@ static void __init of_keystone_psc_clk_init(struct device_node *node)
}
CLK_OF_DECLARE(keystone_gate_clk, "ti,keystone,psc-clock",
of_keystone_psc_clk_init);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Clock driver for Keystone 2 based devices");
+MODULE_AUTHOR("Murali Karicheri <m-karicheri2@ti.com>");
+MODULE_AUTHOR("Santosh Shilimkar <santosh.shilimkar@ti.com>");
diff --git a/drivers/clk/keystone/pll.c b/drivers/clk/keystone/pll.c
index e7e840fb74ea..349540469fc0 100644
--- a/drivers/clk/keystone/pll.c
+++ b/drivers/clk/keystone/pll.c
@@ -219,7 +219,7 @@ static void __init _of_pll_clk_init(struct device_node *node, bool pllctrl)
}
out:
- pr_err("%s: error initializing pll %s\n", __func__, node->name);
+ pr_err("%s: error initializing pll %pOFn\n", __func__, node);
kfree(pll_data);
}
@@ -338,3 +338,8 @@ static void __init of_pll_mux_clk_init(struct device_node *node)
pr_err("%s: error registering mux %s\n", __func__, clk_name);
}
CLK_OF_DECLARE(pll_mux_clock, "ti,keystone,pll-mux-clock", of_pll_mux_clk_init);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PLL clock driver for Keystone devices");
+MODULE_AUTHOR("Murali Karicheri <m-karicheri2@ti.com>");
+MODULE_AUTHOR("Santosh Shilimkar <santosh.shilimkar@ti.com>");
diff --git a/drivers/clk/mediatek/clk-mt2701.c b/drivers/clk/mediatek/clk-mt2701.c
index 4dda8988b2f0..ab6ab07f53e6 100644
--- a/drivers/clk/mediatek/clk-mt2701.c
+++ b/drivers/clk/mediatek/clk-mt2701.c
@@ -249,11 +249,6 @@ static const char * const msdc30_parents[] = {
"univpll2_d4"
};
-static const char * const audio_parents[] = {
- "clk26m",
- "syspll1_d16"
-};
-
static const char * const aud_intbus_parents[] = {
"clk26m",
"syspll1_d4",
diff --git a/drivers/clk/meson/axg-audio.c b/drivers/clk/meson/axg-audio.c
index a0ed41e73bde..5f6c860aa122 100644
--- a/drivers/clk/meson/axg-audio.c
+++ b/drivers/clk/meson/axg-audio.c
@@ -101,10 +101,16 @@ static const char * const mst_mux_parent_names[] = {
"axg_mst_in4", "axg_mst_in5", "axg_mst_in6", "axg_mst_in7",
};
-#define AXG_MST_MCLK_MUX(_name, _reg) \
- AXG_AUD_MUX(_name##_sel, _reg, 0x7, 24, CLK_MUX_ROUND_CLOSEST, \
+#define AXG_MST_MUX(_name, _reg, _flag) \
+ AXG_AUD_MUX(_name##_sel, _reg, 0x7, 24, _flag, \
mst_mux_parent_names, CLK_SET_RATE_PARENT)
+#define AXG_MST_MCLK_MUX(_name, _reg) \
+ AXG_MST_MUX(_name, _reg, CLK_MUX_ROUND_CLOSEST)
+
+#define AXG_MST_SYS_MUX(_name, _reg) \
+ AXG_MST_MUX(_name, _reg, 0)
+
static AXG_MST_MCLK_MUX(mst_a_mclk, AUDIO_MCLK_A_CTRL);
static AXG_MST_MCLK_MUX(mst_b_mclk, AUDIO_MCLK_B_CTRL);
static AXG_MST_MCLK_MUX(mst_c_mclk, AUDIO_MCLK_C_CTRL);
@@ -112,13 +118,19 @@ static AXG_MST_MCLK_MUX(mst_d_mclk, AUDIO_MCLK_D_CTRL);
static AXG_MST_MCLK_MUX(mst_e_mclk, AUDIO_MCLK_E_CTRL);
static AXG_MST_MCLK_MUX(mst_f_mclk, AUDIO_MCLK_F_CTRL);
static AXG_MST_MCLK_MUX(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL);
-static AXG_MST_MCLK_MUX(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL);
static AXG_MST_MCLK_MUX(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0);
-static AXG_MST_MCLK_MUX(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1);
+static AXG_MST_SYS_MUX(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL);
+static AXG_MST_SYS_MUX(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1);
+
+#define AXG_MST_DIV(_name, _reg, _flag) \
+ AXG_AUD_DIV(_name##_div, _reg, 0, 16, _flag, \
+ "axg_"#_name"_sel", CLK_SET_RATE_PARENT) \
+
+#define AXG_MST_MCLK_DIV(_name, _reg) \
+ AXG_MST_DIV(_name, _reg, CLK_DIVIDER_ROUND_CLOSEST)
-#define AXG_MST_MCLK_DIV(_name, _reg) \
- AXG_AUD_DIV(_name##_div, _reg, 0, 16, CLK_DIVIDER_ROUND_CLOSEST, \
- "axg_"#_name"_sel", CLK_SET_RATE_PARENT) \
+#define AXG_MST_SYS_DIV(_name, _reg) \
+ AXG_MST_DIV(_name, _reg, 0)
static AXG_MST_MCLK_DIV(mst_a_mclk, AUDIO_MCLK_A_CTRL);
static AXG_MST_MCLK_DIV(mst_b_mclk, AUDIO_MCLK_B_CTRL);
@@ -127,12 +139,12 @@ static AXG_MST_MCLK_DIV(mst_d_mclk, AUDIO_MCLK_D_CTRL);
static AXG_MST_MCLK_DIV(mst_e_mclk, AUDIO_MCLK_E_CTRL);
static AXG_MST_MCLK_DIV(mst_f_mclk, AUDIO_MCLK_F_CTRL);
static AXG_MST_MCLK_DIV(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL);
-static AXG_MST_MCLK_DIV(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL);
static AXG_MST_MCLK_DIV(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0);
-static AXG_MST_MCLK_DIV(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1);
+static AXG_MST_SYS_DIV(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL);
+static AXG_MST_SYS_DIV(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1);
-#define AXG_MST_MCLK_GATE(_name, _reg) \
- AXG_AUD_GATE(_name, _reg, 31, "axg_"#_name"_div", \
+#define AXG_MST_MCLK_GATE(_name, _reg) \
+ AXG_AUD_GATE(_name, _reg, 31, "axg_"#_name"_div", \
CLK_SET_RATE_PARENT)
static AXG_MST_MCLK_GATE(mst_a_mclk, AUDIO_MCLK_A_CTRL);
diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c
index 00ce62ad6416..792735d7e46e 100644
--- a/drivers/clk/meson/axg.c
+++ b/drivers/clk/meson/axg.c
@@ -22,8 +22,13 @@
static DEFINE_SPINLOCK(meson_clk_lock);
-static struct clk_regmap axg_fixed_pll = {
+static struct clk_regmap axg_fixed_pll_dco = {
.data = &(struct meson_clk_pll_data){
+ .en = {
+ .reg_off = HHI_MPLL_CNTL,
+ .shift = 30,
+ .width = 1,
+ },
.m = {
.reg_off = HHI_MPLL_CNTL,
.shift = 0,
@@ -34,11 +39,6 @@ static struct clk_regmap axg_fixed_pll = {
.shift = 9,
.width = 5,
},
- .od = {
- .reg_off = HHI_MPLL_CNTL,
- .shift = 16,
- .width = 2,
- },
.frac = {
.reg_off = HHI_MPLL_CNTL2,
.shift = 0,
@@ -56,15 +56,39 @@ static struct clk_regmap axg_fixed_pll = {
},
},
.hw.init = &(struct clk_init_data){
- .name = "fixed_pll",
+ .name = "fixed_pll_dco",
.ops = &meson_clk_pll_ro_ops,
.parent_names = (const char *[]){ "xtal" },
.num_parents = 1,
},
};
-static struct clk_regmap axg_sys_pll = {
+static struct clk_regmap axg_fixed_pll = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = HHI_MPLL_CNTL,
+ .shift = 16,
+ .width = 2,
+ .flags = CLK_DIVIDER_POWER_OF_TWO,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "fixed_pll",
+ .ops = &clk_regmap_divider_ro_ops,
+ .parent_names = (const char *[]){ "fixed_pll_dco" },
+ .num_parents = 1,
+ /*
+ * This clock won't ever change at runtime so
+ * CLK_SET_RATE_PARENT is not required
+ */
+ },
+};
+
+static struct clk_regmap axg_sys_pll_dco = {
.data = &(struct meson_clk_pll_data){
+ .en = {
+ .reg_off = HHI_SYS_PLL_CNTL,
+ .shift = 30,
+ .width = 1,
+ },
.m = {
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 0,
@@ -75,11 +99,6 @@ static struct clk_regmap axg_sys_pll = {
.shift = 9,
.width = 5,
},
- .od = {
- .reg_off = HHI_SYS_PLL_CNTL,
- .shift = 16,
- .width = 2,
- },
.l = {
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 31,
@@ -92,102 +111,59 @@ static struct clk_regmap axg_sys_pll = {
},
},
.hw.init = &(struct clk_init_data){
- .name = "sys_pll",
+ .name = "sys_pll_dco",
.ops = &meson_clk_pll_ro_ops,
.parent_names = (const char *[]){ "xtal" },
.num_parents = 1,
- .flags = CLK_GET_RATE_NOCACHE,
},
};
-static const struct pll_rate_table axg_gp0_pll_rate_table[] = {
- PLL_RATE(240000000, 40, 1, 2),
- PLL_RATE(246000000, 41, 1, 2),
- PLL_RATE(252000000, 42, 1, 2),
- PLL_RATE(258000000, 43, 1, 2),
- PLL_RATE(264000000, 44, 1, 2),
- PLL_RATE(270000000, 45, 1, 2),
- PLL_RATE(276000000, 46, 1, 2),
- PLL_RATE(282000000, 47, 1, 2),
- PLL_RATE(288000000, 48, 1, 2),
- PLL_RATE(294000000, 49, 1, 2),
- PLL_RATE(300000000, 50, 1, 2),
- PLL_RATE(306000000, 51, 1, 2),
- PLL_RATE(312000000, 52, 1, 2),
- PLL_RATE(318000000, 53, 1, 2),
- PLL_RATE(324000000, 54, 1, 2),
- PLL_RATE(330000000, 55, 1, 2),
- PLL_RATE(336000000, 56, 1, 2),
- PLL_RATE(342000000, 57, 1, 2),
- PLL_RATE(348000000, 58, 1, 2),
- PLL_RATE(354000000, 59, 1, 2),
- PLL_RATE(360000000, 60, 1, 2),
- PLL_RATE(366000000, 61, 1, 2),
- PLL_RATE(372000000, 62, 1, 2),
- PLL_RATE(378000000, 63, 1, 2),
- PLL_RATE(384000000, 64, 1, 2),
- PLL_RATE(390000000, 65, 1, 3),
- PLL_RATE(396000000, 66, 1, 3),
- PLL_RATE(402000000, 67, 1, 3),
- PLL_RATE(408000000, 68, 1, 3),
- PLL_RATE(480000000, 40, 1, 1),
- PLL_RATE(492000000, 41, 1, 1),
- PLL_RATE(504000000, 42, 1, 1),
- PLL_RATE(516000000, 43, 1, 1),
- PLL_RATE(528000000, 44, 1, 1),
- PLL_RATE(540000000, 45, 1, 1),
- PLL_RATE(552000000, 46, 1, 1),
- PLL_RATE(564000000, 47, 1, 1),
- PLL_RATE(576000000, 48, 1, 1),
- PLL_RATE(588000000, 49, 1, 1),
- PLL_RATE(600000000, 50, 1, 1),
- PLL_RATE(612000000, 51, 1, 1),
- PLL_RATE(624000000, 52, 1, 1),
- PLL_RATE(636000000, 53, 1, 1),
- PLL_RATE(648000000, 54, 1, 1),
- PLL_RATE(660000000, 55, 1, 1),
- PLL_RATE(672000000, 56, 1, 1),
- PLL_RATE(684000000, 57, 1, 1),
- PLL_RATE(696000000, 58, 1, 1),
- PLL_RATE(708000000, 59, 1, 1),
- PLL_RATE(720000000, 60, 1, 1),
- PLL_RATE(732000000, 61, 1, 1),
- PLL_RATE(744000000, 62, 1, 1),
- PLL_RATE(756000000, 63, 1, 1),
- PLL_RATE(768000000, 64, 1, 1),
- PLL_RATE(780000000, 65, 1, 1),
- PLL_RATE(792000000, 66, 1, 1),
- PLL_RATE(804000000, 67, 1, 1),
- PLL_RATE(816000000, 68, 1, 1),
- PLL_RATE(960000000, 40, 1, 0),
- PLL_RATE(984000000, 41, 1, 0),
- PLL_RATE(1008000000, 42, 1, 0),
- PLL_RATE(1032000000, 43, 1, 0),
- PLL_RATE(1056000000, 44, 1, 0),
- PLL_RATE(1080000000, 45, 1, 0),
- PLL_RATE(1104000000, 46, 1, 0),
- PLL_RATE(1128000000, 47, 1, 0),
- PLL_RATE(1152000000, 48, 1, 0),
- PLL_RATE(1176000000, 49, 1, 0),
- PLL_RATE(1200000000, 50, 1, 0),
- PLL_RATE(1224000000, 51, 1, 0),
- PLL_RATE(1248000000, 52, 1, 0),
- PLL_RATE(1272000000, 53, 1, 0),
- PLL_RATE(1296000000, 54, 1, 0),
- PLL_RATE(1320000000, 55, 1, 0),
- PLL_RATE(1344000000, 56, 1, 0),
- PLL_RATE(1368000000, 57, 1, 0),
- PLL_RATE(1392000000, 58, 1, 0),
- PLL_RATE(1416000000, 59, 1, 0),
- PLL_RATE(1440000000, 60, 1, 0),
- PLL_RATE(1464000000, 61, 1, 0),
- PLL_RATE(1488000000, 62, 1, 0),
- PLL_RATE(1512000000, 63, 1, 0),
- PLL_RATE(1536000000, 64, 1, 0),
- PLL_RATE(1560000000, 65, 1, 0),
- PLL_RATE(1584000000, 66, 1, 0),
- PLL_RATE(1608000000, 67, 1, 0),
- PLL_RATE(1632000000, 68, 1, 0),
+static struct clk_regmap axg_sys_pll = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = HHI_SYS_PLL_CNTL,
+ .shift = 16,
+ .width = 2,
+ .flags = CLK_DIVIDER_POWER_OF_TWO,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "sys_pll",
+ .ops = &clk_regmap_divider_ro_ops,
+ .parent_names = (const char *[]){ "sys_pll_dco" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static const struct pll_params_table axg_gp0_pll_params_table[] = {
+ PLL_PARAMS(40, 1),
+ PLL_PARAMS(41, 1),
+ PLL_PARAMS(42, 1),
+ PLL_PARAMS(43, 1),
+ PLL_PARAMS(44, 1),
+ PLL_PARAMS(45, 1),
+ PLL_PARAMS(46, 1),
+ PLL_PARAMS(47, 1),
+ PLL_PARAMS(48, 1),
+ PLL_PARAMS(49, 1),
+ PLL_PARAMS(50, 1),
+ PLL_PARAMS(51, 1),
+ PLL_PARAMS(52, 1),
+ PLL_PARAMS(53, 1),
+ PLL_PARAMS(54, 1),
+ PLL_PARAMS(55, 1),
+ PLL_PARAMS(56, 1),
+ PLL_PARAMS(57, 1),
+ PLL_PARAMS(58, 1),
+ PLL_PARAMS(59, 1),
+ PLL_PARAMS(60, 1),
+ PLL_PARAMS(61, 1),
+ PLL_PARAMS(62, 1),
+ PLL_PARAMS(63, 1),
+ PLL_PARAMS(64, 1),
+ PLL_PARAMS(65, 1),
+ PLL_PARAMS(66, 1),
+ PLL_PARAMS(67, 1),
+ PLL_PARAMS(68, 1),
{ /* sentinel */ },
};
@@ -197,11 +173,15 @@ static const struct reg_sequence axg_gp0_init_regs[] = {
{ .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a59a288 },
{ .reg = HHI_GP0_PLL_CNTL4, .def = 0xc000004d },
{ .reg = HHI_GP0_PLL_CNTL5, .def = 0x00078000 },
- { .reg = HHI_GP0_PLL_CNTL, .def = 0x40010250 },
};
-static struct clk_regmap axg_gp0_pll = {
+static struct clk_regmap axg_gp0_pll_dco = {
.data = &(struct meson_clk_pll_data){
+ .en = {
+ .reg_off = HHI_GP0_PLL_CNTL,
+ .shift = 30,
+ .width = 1,
+ },
.m = {
.reg_off = HHI_GP0_PLL_CNTL,
.shift = 0,
@@ -212,11 +192,6 @@ static struct clk_regmap axg_gp0_pll = {
.shift = 9,
.width = 5,
},
- .od = {
- .reg_off = HHI_GP0_PLL_CNTL,
- .shift = 16,
- .width = 2,
- },
.frac = {
.reg_off = HHI_GP0_PLL_CNTL1,
.shift = 0,
@@ -232,29 +207,49 @@ static struct clk_regmap axg_gp0_pll = {
.shift = 29,
.width = 1,
},
- .table = axg_gp0_pll_rate_table,
+ .table = axg_gp0_pll_params_table,
.init_regs = axg_gp0_init_regs,
.init_count = ARRAY_SIZE(axg_gp0_init_regs),
},
.hw.init = &(struct clk_init_data){
- .name = "gp0_pll",
+ .name = "gp0_pll_dco",
.ops = &meson_clk_pll_ops,
.parent_names = (const char *[]){ "xtal" },
.num_parents = 1,
},
};
+static struct clk_regmap axg_gp0_pll = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = HHI_GP0_PLL_CNTL,
+ .shift = 16,
+ .width = 2,
+ .flags = CLK_DIVIDER_POWER_OF_TWO,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "gp0_pll",
+ .ops = &clk_regmap_divider_ops,
+ .parent_names = (const char *[]){ "gp0_pll_dco" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
static const struct reg_sequence axg_hifi_init_regs[] = {
{ .reg = HHI_HIFI_PLL_CNTL1, .def = 0xc084b000 },
{ .reg = HHI_HIFI_PLL_CNTL2, .def = 0xb75020be },
{ .reg = HHI_HIFI_PLL_CNTL3, .def = 0x0a6a3a88 },
{ .reg = HHI_HIFI_PLL_CNTL4, .def = 0xc000004d },
{ .reg = HHI_HIFI_PLL_CNTL5, .def = 0x00058000 },
- { .reg = HHI_HIFI_PLL_CNTL, .def = 0x40010250 },
};
-static struct clk_regmap axg_hifi_pll = {
+static struct clk_regmap axg_hifi_pll_dco = {
.data = &(struct meson_clk_pll_data){
+ .en = {
+ .reg_off = HHI_HIFI_PLL_CNTL,
+ .shift = 30,
+ .width = 1,
+ },
.m = {
.reg_off = HHI_HIFI_PLL_CNTL,
.shift = 0,
@@ -265,11 +260,6 @@ static struct clk_regmap axg_hifi_pll = {
.shift = 9,
.width = 5,
},
- .od = {
- .reg_off = HHI_HIFI_PLL_CNTL,
- .shift = 16,
- .width = 2,
- },
.frac = {
.reg_off = HHI_HIFI_PLL_CNTL5,
.shift = 0,
@@ -285,19 +275,35 @@ static struct clk_regmap axg_hifi_pll = {
.shift = 29,
.width = 1,
},
- .table = axg_gp0_pll_rate_table,
+ .table = axg_gp0_pll_params_table,
.init_regs = axg_hifi_init_regs,
.init_count = ARRAY_SIZE(axg_hifi_init_regs),
.flags = CLK_MESON_PLL_ROUND_CLOSEST,
},
.hw.init = &(struct clk_init_data){
- .name = "hifi_pll",
+ .name = "hifi_pll_dco",
.ops = &meson_clk_pll_ops,
.parent_names = (const char *[]){ "xtal" },
.num_parents = 1,
},
};
+static struct clk_regmap axg_hifi_pll = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = HHI_HIFI_PLL_CNTL,
+ .shift = 16,
+ .width = 2,
+ .flags = CLK_DIVIDER_POWER_OF_TWO,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "hifi_pll",
+ .ops = &clk_regmap_divider_ops,
+ .parent_names = (const char *[]){ "hifi_pll_dco" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
static struct clk_fixed_factor axg_fclk_div2_div = {
.mult = 1,
.div = 2,
@@ -319,6 +325,7 @@ static struct clk_regmap axg_fclk_div2 = {
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "fclk_div2_div" },
.num_parents = 1,
+ .flags = CLK_IS_CRITICAL,
},
};
@@ -343,6 +350,18 @@ static struct clk_regmap axg_fclk_div3 = {
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "fclk_div3_div" },
.num_parents = 1,
+ /*
+ * FIXME:
+ * This clock, as fdiv2, is used by the SCPI FW and is required
+ * by the platform to operate correctly.
+ * Until the following condition are met, we need this clock to
+ * be marked as critical:
+ * a) The SCPI generic driver claims and enable all the clocks
+ * it needs
+ * b) CCF has a clock hand-off mechanism to make the sure the
+ * clock stays on until the proper driver comes along
+ */
+ .flags = CLK_IS_CRITICAL,
},
};
@@ -625,29 +644,31 @@ static struct clk_regmap axg_mpll3 = {
},
};
-static const struct pll_rate_table axg_pcie_pll_rate_table[] = {
+static const struct pll_params_table axg_pcie_pll_params_table[] = {
{
- .rate = 100000000,
- .m = 200,
- .n = 3,
- .od = 1,
- .od2 = 3,
+ .m = 200,
+ .n = 3,
},
{ /* sentinel */ },
};
static const struct reg_sequence axg_pcie_init_regs[] = {
- { .reg = HHI_PCIE_PLL_CNTL, .def = 0x400106c8 },
{ .reg = HHI_PCIE_PLL_CNTL1, .def = 0x0084a2aa },
{ .reg = HHI_PCIE_PLL_CNTL2, .def = 0xb75020be },
{ .reg = HHI_PCIE_PLL_CNTL3, .def = 0x0a47488e },
{ .reg = HHI_PCIE_PLL_CNTL4, .def = 0xc000004d },
{ .reg = HHI_PCIE_PLL_CNTL5, .def = 0x00078000 },
{ .reg = HHI_PCIE_PLL_CNTL6, .def = 0x002323c6 },
+ { .reg = HHI_PCIE_PLL_CNTL, .def = 0x400106c8 },
};
-static struct clk_regmap axg_pcie_pll = {
+static struct clk_regmap axg_pcie_pll_dco = {
.data = &(struct meson_clk_pll_data){
+ .en = {
+ .reg_off = HHI_PCIE_PLL_CNTL,
+ .shift = 30,
+ .width = 1,
+ },
.m = {
.reg_off = HHI_PCIE_PLL_CNTL,
.shift = 0,
@@ -658,16 +679,6 @@ static struct clk_regmap axg_pcie_pll = {
.shift = 9,
.width = 5,
},
- .od = {
- .reg_off = HHI_PCIE_PLL_CNTL,
- .shift = 16,
- .width = 2,
- },
- .od2 = {
- .reg_off = HHI_PCIE_PLL_CNTL6,
- .shift = 6,
- .width = 2,
- },
.frac = {
.reg_off = HHI_PCIE_PLL_CNTL1,
.shift = 0,
@@ -683,29 +694,63 @@ static struct clk_regmap axg_pcie_pll = {
.shift = 29,
.width = 1,
},
- .table = axg_pcie_pll_rate_table,
+ .table = axg_pcie_pll_params_table,
.init_regs = axg_pcie_init_regs,
.init_count = ARRAY_SIZE(axg_pcie_init_regs),
},
.hw.init = &(struct clk_init_data){
- .name = "pcie_pll",
+ .name = "pcie_pll_dco",
.ops = &meson_clk_pll_ops,
.parent_names = (const char *[]){ "xtal" },
.num_parents = 1,
},
};
+static struct clk_regmap axg_pcie_pll_od = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = HHI_PCIE_PLL_CNTL,
+ .shift = 16,
+ .width = 2,
+ .flags = CLK_DIVIDER_POWER_OF_TWO,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "pcie_pll_od",
+ .ops = &clk_regmap_divider_ops,
+ .parent_names = (const char *[]){ "pcie_pll_dco" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap axg_pcie_pll = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = HHI_PCIE_PLL_CNTL6,
+ .shift = 6,
+ .width = 2,
+ .flags = CLK_DIVIDER_POWER_OF_TWO,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "pcie_pll",
+ .ops = &clk_regmap_divider_ops,
+ .parent_names = (const char *[]){ "pcie_pll_od" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
static struct clk_regmap axg_pcie_mux = {
.data = &(struct clk_regmap_mux_data){
.offset = HHI_PCIE_PLL_CNTL6,
.mask = 0x1,
.shift = 2,
+ /* skip the parent mpll3, reserved for debug */
+ .table = (u32[]){ 1 },
},
.hw.init = &(struct clk_init_data){
.name = "pcie_mux",
.ops = &clk_regmap_mux_ops,
- .parent_names = (const char *[]){ "mpll3", "pcie_pll" },
- .num_parents = 2,
+ .parent_names = (const char *[]){ "pcie_pll" },
+ .num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
@@ -1107,6 +1152,12 @@ static struct clk_hw_onecell_data axg_hw_onecell_data = {
[CLKID_GEN_CLK_SEL] = &axg_gen_clk_sel.hw,
[CLKID_GEN_CLK_DIV] = &axg_gen_clk_div.hw,
[CLKID_GEN_CLK] = &axg_gen_clk.hw,
+ [CLKID_SYS_PLL_DCO] = &axg_sys_pll_dco.hw,
+ [CLKID_FIXED_PLL_DCO] = &axg_fixed_pll_dco.hw,
+ [CLKID_GP0_PLL_DCO] = &axg_gp0_pll_dco.hw,
+ [CLKID_HIFI_PLL_DCO] = &axg_hifi_pll_dco.hw,
+ [CLKID_PCIE_PLL_DCO] = &axg_pcie_pll_dco.hw,
+ [CLKID_PCIE_PLL_OD] = &axg_pcie_pll_od.hw,
[NR_CLKS] = NULL,
},
.num = NR_CLKS,
@@ -1185,6 +1236,8 @@ static struct clk_regmap *const axg_clk_regmaps[] = {
&axg_fclk_div4,
&axg_fclk_div5,
&axg_fclk_div7,
+ &axg_pcie_pll_dco,
+ &axg_pcie_pll_od,
&axg_pcie_pll,
&axg_pcie_mux,
&axg_pcie_ref,
@@ -1194,6 +1247,12 @@ static struct clk_regmap *const axg_clk_regmaps[] = {
&axg_gen_clk_sel,
&axg_gen_clk_div,
&axg_gen_clk,
+ &axg_fixed_pll_dco,
+ &axg_sys_pll_dco,
+ &axg_gp0_pll_dco,
+ &axg_hifi_pll_dco,
+ &axg_pcie_pll_dco,
+ &axg_pcie_pll_od,
};
static const struct of_device_id clkc_match_table[] = {
diff --git a/drivers/clk/meson/axg.h b/drivers/clk/meson/axg.h
index 1d04144a1b2c..0431dabac629 100644
--- a/drivers/clk/meson/axg.h
+++ b/drivers/clk/meson/axg.h
@@ -133,8 +133,14 @@
#define CLKID_PCIE_REF 78
#define CLKID_GEN_CLK_SEL 82
#define CLKID_GEN_CLK_DIV 83
+#define CLKID_SYS_PLL_DCO 85
+#define CLKID_FIXED_PLL_DCO 86
+#define CLKID_GP0_PLL_DCO 87
+#define CLKID_HIFI_PLL_DCO 88
+#define CLKID_PCIE_PLL_DCO 89
+#define CLKID_PCIE_PLL_OD 90
-#define NR_CLKS 85
+#define NR_CLKS 91
/* include the CLKIDs that have been made part of the DT binding */
#include <dt-bindings/clock/axg-clkc.h>
diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c
index 3e04617ac47f..f5b5b3fabe3c 100644
--- a/drivers/clk/meson/clk-pll.c
+++ b/drivers/clk/meson/clk-pll.c
@@ -11,15 +11,19 @@
* In the most basic form, a Meson PLL is composed as follows:
*
* PLL
- * +------------------------------+
- * | |
- * in -----[ /N ]---[ *M ]---[ >>OD ]----->> out
- * | ^ ^ |
- * +------------------------------+
- * | |
- * FREF VCO
+ * +--------------------------------+
+ * | |
+ * | +--+ |
+ * in >>-----[ /N ]--->| | +-----+ |
+ * | | |------| DCO |---->> out
+ * | +--------->| | +--v--+ |
+ * | | +--+ | |
+ * | | | |
+ * | +--[ *(M + (F/Fmax) ]<--+ |
+ * | |
+ * +--------------------------------+
*
- * out = in * (m + frac / frac_max) / (n << sum(ods))
+ * out = in * (m + frac / frac_max) / n
*/
#include <linux/clk-provider.h>
@@ -41,12 +45,11 @@ meson_clk_pll_data(struct clk_regmap *clk)
}
static unsigned long __pll_params_to_rate(unsigned long parent_rate,
- const struct pll_rate_table *pllt,
+ const struct pll_params_table *pllt,
u16 frac,
struct meson_clk_pll_data *pll)
{
u64 rate = (u64)parent_rate * pllt->m;
- unsigned int od = pllt->od + pllt->od2 + pllt->od3;
if (frac && MESON_PARM_APPLICABLE(&pll->frac)) {
u64 frac_rate = (u64)parent_rate * frac;
@@ -55,7 +58,7 @@ static unsigned long __pll_params_to_rate(unsigned long parent_rate,
(1 << pll->frac.width));
}
- return DIV_ROUND_UP_ULL(rate, pllt->n << od);
+ return DIV_ROUND_UP_ULL(rate, pllt->n);
}
static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw,
@@ -63,20 +66,11 @@ static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw,
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
- struct pll_rate_table pllt;
+ struct pll_params_table pllt;
u16 frac;
pllt.n = meson_parm_read(clk->map, &pll->n);
pllt.m = meson_parm_read(clk->map, &pll->m);
- pllt.od = meson_parm_read(clk->map, &pll->od);
-
- pllt.od2 = MESON_PARM_APPLICABLE(&pll->od2) ?
- meson_parm_read(clk->map, &pll->od2) :
- 0;
-
- pllt.od3 = MESON_PARM_APPLICABLE(&pll->od3) ?
- meson_parm_read(clk->map, &pll->od3) :
- 0;
frac = MESON_PARM_APPLICABLE(&pll->frac) ?
meson_parm_read(clk->map, &pll->frac) :
@@ -87,14 +81,12 @@ static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw,
static u16 __pll_params_with_frac(unsigned long rate,
unsigned long parent_rate,
- const struct pll_rate_table *pllt,
+ const struct pll_params_table *pllt,
struct meson_clk_pll_data *pll)
{
u16 frac_max = (1 << pll->frac.width);
u64 val = (u64)rate * pllt->n;
- val <<= pllt->od + pllt->od2 + pllt->od3;
-
if (pll->flags & CLK_MESON_PLL_ROUND_CLOSEST)
val = DIV_ROUND_CLOSEST_ULL(val * frac_max, parent_rate);
else
@@ -105,29 +97,50 @@ static u16 __pll_params_with_frac(unsigned long rate,
return min((u16)val, (u16)(frac_max - 1));
}
-static const struct pll_rate_table *
+static bool meson_clk_pll_is_better(unsigned long rate,
+ unsigned long best,
+ unsigned long now,
+ struct meson_clk_pll_data *pll)
+{
+ if (!(pll->flags & CLK_MESON_PLL_ROUND_CLOSEST) ||
+ MESON_PARM_APPLICABLE(&pll->frac)) {
+ /* Round down */
+ if (now < rate && best < now)
+ return true;
+ } else {
+ /* Round Closest */
+ if (abs(now - rate) < abs(best - rate))
+ return true;
+ }
+
+ return false;
+}
+
+static const struct pll_params_table *
meson_clk_get_pll_settings(unsigned long rate,
+ unsigned long parent_rate,
struct meson_clk_pll_data *pll)
{
- const struct pll_rate_table *table = pll->table;
- unsigned int i = 0;
+ const struct pll_params_table *table = pll->table;
+ unsigned long best = 0, now = 0;
+ unsigned int i, best_i = 0;
if (!table)
return NULL;
- /* Find the first table element exceeding rate */
- while (table[i].rate && table[i].rate <= rate)
- i++;
+ for (i = 0; table[i].n; i++) {
+ now = __pll_params_to_rate(parent_rate, &table[i], 0, pll);
- if (i != 0) {
- if (MESON_PARM_APPLICABLE(&pll->frac) ||
- !(pll->flags & CLK_MESON_PLL_ROUND_CLOSEST) ||
- (abs(rate - table[i - 1].rate) <
- abs(rate - table[i].rate)))
- i--;
+ /* If we get an exact match, don't bother any further */
+ if (now == rate) {
+ return &table[i];
+ } else if (meson_clk_pll_is_better(rate, best, now, pll)) {
+ best = now;
+ best_i = i;
+ }
}
- return (struct pll_rate_table *)&table[i];
+ return (struct pll_params_table *)&table[best_i];
}
static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
@@ -135,16 +148,18 @@ static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
- const struct pll_rate_table *pllt =
- meson_clk_get_pll_settings(rate, pll);
+ const struct pll_params_table *pllt =
+ meson_clk_get_pll_settings(rate, *parent_rate, pll);
+ unsigned long round;
u16 frac;
if (!pllt)
return meson_clk_pll_recalc_rate(hw, *parent_rate);
- if (!MESON_PARM_APPLICABLE(&pll->frac)
- || rate == pllt->rate)
- return pllt->rate;
+ round = __pll_params_to_rate(*parent_rate, pllt, 0, pll);
+
+ if (!MESON_PARM_APPLICABLE(&pll->frac) || rate == round)
+ return round;
/*
* The rate provided by the setting is not an exact match, let's
@@ -185,12 +200,45 @@ static void meson_clk_pll_init(struct clk_hw *hw)
}
}
+static int meson_clk_pll_enable(struct clk_hw *hw)
+{
+ struct clk_regmap *clk = to_clk_regmap(hw);
+ struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
+
+ /* Make sure the pll is in reset */
+ meson_parm_write(clk->map, &pll->rst, 1);
+
+ /* Enable the pll */
+ meson_parm_write(clk->map, &pll->en, 1);
+
+ /* Take the pll out reset */
+ meson_parm_write(clk->map, &pll->rst, 0);
+
+ if (meson_clk_pll_wait_lock(hw))
+ return -EIO;
+
+ return 0;
+}
+
+static void meson_clk_pll_disable(struct clk_hw *hw)
+{
+ struct clk_regmap *clk = to_clk_regmap(hw);
+ struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
+
+ /* Put the pll is in reset */
+ meson_parm_write(clk->map, &pll->rst, 1);
+
+ /* Disable the pll */
+ meson_parm_write(clk->map, &pll->en, 0);
+}
+
static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
- const struct pll_rate_table *pllt;
+ const struct pll_params_table *pllt;
+ unsigned int enabled;
unsigned long old_rate;
u16 frac = 0;
@@ -199,32 +247,28 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
old_rate = rate;
- pllt = meson_clk_get_pll_settings(rate, pll);
+ pllt = meson_clk_get_pll_settings(rate, parent_rate, pll);
if (!pllt)
return -EINVAL;
- /* Put the pll in reset to write the params */
- meson_parm_write(clk->map, &pll->rst, 1);
+ enabled = meson_parm_read(clk->map, &pll->en);
+ if (enabled)
+ meson_clk_pll_disable(hw);
meson_parm_write(clk->map, &pll->n, pllt->n);
meson_parm_write(clk->map, &pll->m, pllt->m);
- meson_parm_write(clk->map, &pll->od, pllt->od);
- if (MESON_PARM_APPLICABLE(&pll->od2))
- meson_parm_write(clk->map, &pll->od2, pllt->od2);
-
- if (MESON_PARM_APPLICABLE(&pll->od3))
- meson_parm_write(clk->map, &pll->od3, pllt->od3);
if (MESON_PARM_APPLICABLE(&pll->frac)) {
frac = __pll_params_with_frac(rate, parent_rate, pllt, pll);
meson_parm_write(clk->map, &pll->frac, frac);
}
- /* make sure the reset is cleared at this point */
- meson_parm_write(clk->map, &pll->rst, 0);
+ /* If the pll is stopped, bail out now */
+ if (!enabled)
+ return 0;
- if (meson_clk_pll_wait_lock(hw)) {
+ if (meson_clk_pll_enable(hw)) {
pr_warn("%s: pll did not lock, trying to restore old rate %lu\n",
__func__, old_rate);
/*
@@ -244,6 +288,8 @@ const struct clk_ops meson_clk_pll_ops = {
.recalc_rate = meson_clk_pll_recalc_rate,
.round_rate = meson_clk_pll_round_rate,
.set_rate = meson_clk_pll_set_rate,
+ .enable = meson_clk_pll_enable,
+ .disable = meson_clk_pll_disable
};
const struct clk_ops meson_clk_pll_ro_ops = {
diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h
index 24cec16b6038..6b96d55c047d 100644
--- a/drivers/clk/meson/clkc.h
+++ b/drivers/clk/meson/clkc.h
@@ -43,37 +43,29 @@ static inline void meson_parm_write(struct regmap *map, struct parm *p,
}
-struct pll_rate_table {
- unsigned long rate;
+struct pll_params_table {
u16 m;
u16 n;
- u16 od;
- u16 od2;
- u16 od3;
};
-#define PLL_RATE(_r, _m, _n, _od) \
+#define PLL_PARAMS(_m, _n) \
{ \
- .rate = (_r), \
.m = (_m), \
.n = (_n), \
- .od = (_od), \
}
#define CLK_MESON_PLL_ROUND_CLOSEST BIT(0)
struct meson_clk_pll_data {
+ struct parm en;
struct parm m;
struct parm n;
struct parm frac;
- struct parm od;
- struct parm od2;
- struct parm od3;
struct parm l;
struct parm rst;
const struct reg_sequence *init_regs;
unsigned int init_count;
- const struct pll_rate_table *table;
+ const struct pll_params_table *table;
u8 flags;
};
diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c
index 86d3ae58e84c..4ada9668fd49 100644
--- a/drivers/clk/meson/gxbb.c
+++ b/drivers/clk/meson/gxbb.c
@@ -18,165 +18,77 @@
static DEFINE_SPINLOCK(meson_clk_lock);
-static const struct pll_rate_table gxbb_gp0_pll_rate_table[] = {
- PLL_RATE(96000000, 32, 1, 3),
- PLL_RATE(99000000, 33, 1, 3),
- PLL_RATE(102000000, 34, 1, 3),
- PLL_RATE(105000000, 35, 1, 3),
- PLL_RATE(108000000, 36, 1, 3),
- PLL_RATE(111000000, 37, 1, 3),
- PLL_RATE(114000000, 38, 1, 3),
- PLL_RATE(117000000, 39, 1, 3),
- PLL_RATE(120000000, 40, 1, 3),
- PLL_RATE(123000000, 41, 1, 3),
- PLL_RATE(126000000, 42, 1, 3),
- PLL_RATE(129000000, 43, 1, 3),
- PLL_RATE(132000000, 44, 1, 3),
- PLL_RATE(135000000, 45, 1, 3),
- PLL_RATE(138000000, 46, 1, 3),
- PLL_RATE(141000000, 47, 1, 3),
- PLL_RATE(144000000, 48, 1, 3),
- PLL_RATE(147000000, 49, 1, 3),
- PLL_RATE(150000000, 50, 1, 3),
- PLL_RATE(153000000, 51, 1, 3),
- PLL_RATE(156000000, 52, 1, 3),
- PLL_RATE(159000000, 53, 1, 3),
- PLL_RATE(162000000, 54, 1, 3),
- PLL_RATE(165000000, 55, 1, 3),
- PLL_RATE(168000000, 56, 1, 3),
- PLL_RATE(171000000, 57, 1, 3),
- PLL_RATE(174000000, 58, 1, 3),
- PLL_RATE(177000000, 59, 1, 3),
- PLL_RATE(180000000, 60, 1, 3),
- PLL_RATE(183000000, 61, 1, 3),
- PLL_RATE(186000000, 62, 1, 3),
- PLL_RATE(192000000, 32, 1, 2),
- PLL_RATE(198000000, 33, 1, 2),
- PLL_RATE(204000000, 34, 1, 2),
- PLL_RATE(210000000, 35, 1, 2),
- PLL_RATE(216000000, 36, 1, 2),
- PLL_RATE(222000000, 37, 1, 2),
- PLL_RATE(228000000, 38, 1, 2),
- PLL_RATE(234000000, 39, 1, 2),
- PLL_RATE(240000000, 40, 1, 2),
- PLL_RATE(246000000, 41, 1, 2),
- PLL_RATE(252000000, 42, 1, 2),
- PLL_RATE(258000000, 43, 1, 2),
- PLL_RATE(264000000, 44, 1, 2),
- PLL_RATE(270000000, 45, 1, 2),
- PLL_RATE(276000000, 46, 1, 2),
- PLL_RATE(282000000, 47, 1, 2),
- PLL_RATE(288000000, 48, 1, 2),
- PLL_RATE(294000000, 49, 1, 2),
- PLL_RATE(300000000, 50, 1, 2),
- PLL_RATE(306000000, 51, 1, 2),
- PLL_RATE(312000000, 52, 1, 2),
- PLL_RATE(318000000, 53, 1, 2),
- PLL_RATE(324000000, 54, 1, 2),
- PLL_RATE(330000000, 55, 1, 2),
- PLL_RATE(336000000, 56, 1, 2),
- PLL_RATE(342000000, 57, 1, 2),
- PLL_RATE(348000000, 58, 1, 2),
- PLL_RATE(354000000, 59, 1, 2),
- PLL_RATE(360000000, 60, 1, 2),
- PLL_RATE(366000000, 61, 1, 2),
- PLL_RATE(372000000, 62, 1, 2),
- PLL_RATE(384000000, 32, 1, 1),
- PLL_RATE(396000000, 33, 1, 1),
- PLL_RATE(408000000, 34, 1, 1),
- PLL_RATE(420000000, 35, 1, 1),
- PLL_RATE(432000000, 36, 1, 1),
- PLL_RATE(444000000, 37, 1, 1),
- PLL_RATE(456000000, 38, 1, 1),
- PLL_RATE(468000000, 39, 1, 1),
- PLL_RATE(480000000, 40, 1, 1),
- PLL_RATE(492000000, 41, 1, 1),
- PLL_RATE(504000000, 42, 1, 1),
- PLL_RATE(516000000, 43, 1, 1),
- PLL_RATE(528000000, 44, 1, 1),
- PLL_RATE(540000000, 45, 1, 1),
- PLL_RATE(552000000, 46, 1, 1),
- PLL_RATE(564000000, 47, 1, 1),
- PLL_RATE(576000000, 48, 1, 1),
- PLL_RATE(588000000, 49, 1, 1),
- PLL_RATE(600000000, 50, 1, 1),
- PLL_RATE(612000000, 51, 1, 1),
- PLL_RATE(624000000, 52, 1, 1),
- PLL_RATE(636000000, 53, 1, 1),
- PLL_RATE(648000000, 54, 1, 1),
- PLL_RATE(660000000, 55, 1, 1),
- PLL_RATE(672000000, 56, 1, 1),
- PLL_RATE(684000000, 57, 1, 1),
- PLL_RATE(696000000, 58, 1, 1),
- PLL_RATE(708000000, 59, 1, 1),
- PLL_RATE(720000000, 60, 1, 1),
- PLL_RATE(732000000, 61, 1, 1),
- PLL_RATE(744000000, 62, 1, 1),
- PLL_RATE(768000000, 32, 1, 0),
- PLL_RATE(792000000, 33, 1, 0),
- PLL_RATE(816000000, 34, 1, 0),
- PLL_RATE(840000000, 35, 1, 0),
- PLL_RATE(864000000, 36, 1, 0),
- PLL_RATE(888000000, 37, 1, 0),
- PLL_RATE(912000000, 38, 1, 0),
- PLL_RATE(936000000, 39, 1, 0),
- PLL_RATE(960000000, 40, 1, 0),
- PLL_RATE(984000000, 41, 1, 0),
- PLL_RATE(1008000000, 42, 1, 0),
- PLL_RATE(1032000000, 43, 1, 0),
- PLL_RATE(1056000000, 44, 1, 0),
- PLL_RATE(1080000000, 45, 1, 0),
- PLL_RATE(1104000000, 46, 1, 0),
- PLL_RATE(1128000000, 47, 1, 0),
- PLL_RATE(1152000000, 48, 1, 0),
- PLL_RATE(1176000000, 49, 1, 0),
- PLL_RATE(1200000000, 50, 1, 0),
- PLL_RATE(1224000000, 51, 1, 0),
- PLL_RATE(1248000000, 52, 1, 0),
- PLL_RATE(1272000000, 53, 1, 0),
- PLL_RATE(1296000000, 54, 1, 0),
- PLL_RATE(1320000000, 55, 1, 0),
- PLL_RATE(1344000000, 56, 1, 0),
- PLL_RATE(1368000000, 57, 1, 0),
- PLL_RATE(1392000000, 58, 1, 0),
- PLL_RATE(1416000000, 59, 1, 0),
- PLL_RATE(1440000000, 60, 1, 0),
- PLL_RATE(1464000000, 61, 1, 0),
- PLL_RATE(1488000000, 62, 1, 0),
+static const struct pll_params_table gxbb_gp0_pll_params_table[] = {
+ PLL_PARAMS(32, 1),
+ PLL_PARAMS(33, 1),
+ PLL_PARAMS(34, 1),
+ PLL_PARAMS(35, 1),
+ PLL_PARAMS(36, 1),
+ PLL_PARAMS(37, 1),
+ PLL_PARAMS(38, 1),
+ PLL_PARAMS(39, 1),
+ PLL_PARAMS(40, 1),
+ PLL_PARAMS(41, 1),
+ PLL_PARAMS(42, 1),
+ PLL_PARAMS(43, 1),
+ PLL_PARAMS(44, 1),
+ PLL_PARAMS(45, 1),
+ PLL_PARAMS(46, 1),
+ PLL_PARAMS(47, 1),
+ PLL_PARAMS(48, 1),
+ PLL_PARAMS(49, 1),
+ PLL_PARAMS(50, 1),
+ PLL_PARAMS(51, 1),
+ PLL_PARAMS(52, 1),
+ PLL_PARAMS(53, 1),
+ PLL_PARAMS(54, 1),
+ PLL_PARAMS(55, 1),
+ PLL_PARAMS(56, 1),
+ PLL_PARAMS(57, 1),
+ PLL_PARAMS(58, 1),
+ PLL_PARAMS(59, 1),
+ PLL_PARAMS(60, 1),
+ PLL_PARAMS(61, 1),
+ PLL_PARAMS(62, 1),
{ /* sentinel */ },
};
-static const struct pll_rate_table gxl_gp0_pll_rate_table[] = {
- PLL_RATE(504000000, 42, 1, 1),
- PLL_RATE(516000000, 43, 1, 1),
- PLL_RATE(528000000, 44, 1, 1),
- PLL_RATE(540000000, 45, 1, 1),
- PLL_RATE(552000000, 46, 1, 1),
- PLL_RATE(564000000, 47, 1, 1),
- PLL_RATE(576000000, 48, 1, 1),
- PLL_RATE(588000000, 49, 1, 1),
- PLL_RATE(600000000, 50, 1, 1),
- PLL_RATE(612000000, 51, 1, 1),
- PLL_RATE(624000000, 52, 1, 1),
- PLL_RATE(636000000, 53, 1, 1),
- PLL_RATE(648000000, 54, 1, 1),
- PLL_RATE(660000000, 55, 1, 1),
- PLL_RATE(672000000, 56, 1, 1),
- PLL_RATE(684000000, 57, 1, 1),
- PLL_RATE(696000000, 58, 1, 1),
- PLL_RATE(708000000, 59, 1, 1),
- PLL_RATE(720000000, 60, 1, 1),
- PLL_RATE(732000000, 61, 1, 1),
- PLL_RATE(744000000, 62, 1, 1),
- PLL_RATE(756000000, 63, 1, 1),
- PLL_RATE(768000000, 64, 1, 1),
- PLL_RATE(780000000, 65, 1, 1),
- PLL_RATE(792000000, 66, 1, 1),
+static const struct pll_params_table gxl_gp0_pll_params_table[] = {
+ PLL_PARAMS(42, 1),
+ PLL_PARAMS(43, 1),
+ PLL_PARAMS(44, 1),
+ PLL_PARAMS(45, 1),
+ PLL_PARAMS(46, 1),
+ PLL_PARAMS(47, 1),
+ PLL_PARAMS(48, 1),
+ PLL_PARAMS(49, 1),
+ PLL_PARAMS(50, 1),
+ PLL_PARAMS(51, 1),
+ PLL_PARAMS(52, 1),
+ PLL_PARAMS(53, 1),
+ PLL_PARAMS(54, 1),
+ PLL_PARAMS(55, 1),
+ PLL_PARAMS(56, 1),
+ PLL_PARAMS(57, 1),
+ PLL_PARAMS(58, 1),
+ PLL_PARAMS(59, 1),
+ PLL_PARAMS(60, 1),
+ PLL_PARAMS(61, 1),
+ PLL_PARAMS(62, 1),
+ PLL_PARAMS(63, 1),
+ PLL_PARAMS(64, 1),
+ PLL_PARAMS(65, 1),
+ PLL_PARAMS(66, 1),
{ /* sentinel */ },
};
-static struct clk_regmap gxbb_fixed_pll = {
+static struct clk_regmap gxbb_fixed_pll_dco = {
.data = &(struct meson_clk_pll_data){
+ .en = {
+ .reg_off = HHI_MPLL_CNTL,
+ .shift = 30,
+ .width = 1,
+ },
.m = {
.reg_off = HHI_MPLL_CNTL,
.shift = 0,
@@ -187,11 +99,6 @@ static struct clk_regmap gxbb_fixed_pll = {
.shift = 9,
.width = 5,
},
- .od = {
- .reg_off = HHI_MPLL_CNTL,
- .shift = 16,
- .width = 2,
- },
.frac = {
.reg_off = HHI_MPLL_CNTL2,
.shift = 0,
@@ -209,11 +116,29 @@ static struct clk_regmap gxbb_fixed_pll = {
},
},
.hw.init = &(struct clk_init_data){
- .name = "fixed_pll",
+ .name = "fixed_pll_dco",
.ops = &meson_clk_pll_ro_ops,
.parent_names = (const char *[]){ "xtal" },
.num_parents = 1,
- .flags = CLK_GET_RATE_NOCACHE,
+ },
+};
+
+static struct clk_regmap gxbb_fixed_pll = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = HHI_MPLL_CNTL,
+ .shift = 16,
+ .width = 2,
+ .flags = CLK_DIVIDER_POWER_OF_TWO,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "fixed_pll",
+ .ops = &clk_regmap_divider_ro_ops,
+ .parent_names = (const char *[]){ "fixed_pll_dco" },
+ .num_parents = 1,
+ /*
+ * This clock won't ever change at runtime so
+ * CLK_SET_RATE_PARENT is not required
+ */
},
};
@@ -228,8 +153,13 @@ static struct clk_fixed_factor gxbb_hdmi_pll_pre_mult = {
},
};
-static struct clk_regmap gxbb_hdmi_pll = {
+static struct clk_regmap gxbb_hdmi_pll_dco = {
.data = &(struct meson_clk_pll_data){
+ .en = {
+ .reg_off = HHI_HDMI_PLL_CNTL,
+ .shift = 30,
+ .width = 1,
+ },
.m = {
.reg_off = HHI_HDMI_PLL_CNTL,
.shift = 0,
@@ -245,21 +175,6 @@ static struct clk_regmap gxbb_hdmi_pll = {
.shift = 0,
.width = 12,
},
- .od = {
- .reg_off = HHI_HDMI_PLL_CNTL2,
- .shift = 16,
- .width = 2,
- },
- .od2 = {
- .reg_off = HHI_HDMI_PLL_CNTL2,
- .shift = 22,
- .width = 2,
- },
- .od3 = {
- .reg_off = HHI_HDMI_PLL_CNTL2,
- .shift = 18,
- .width = 2,
- },
.l = {
.reg_off = HHI_HDMI_PLL_CNTL,
.shift = 31,
@@ -272,74 +187,121 @@ static struct clk_regmap gxbb_hdmi_pll = {
},
},
.hw.init = &(struct clk_init_data){
- .name = "hdmi_pll",
+ .name = "hdmi_pll_dco",
.ops = &meson_clk_pll_ro_ops,
.parent_names = (const char *[]){ "hdmi_pll_pre_mult" },
.num_parents = 1,
+ /*
+ * Display directly handle hdmi pll registers ATM, we need
+ * NOCACHE to keep our view of the clock as accurate as possible
+ */
.flags = CLK_GET_RATE_NOCACHE,
},
};
+static struct clk_regmap gxbb_hdmi_pll_od = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = HHI_HDMI_PLL_CNTL2,
+ .shift = 16,
+ .width = 2,
+ .flags = CLK_DIVIDER_POWER_OF_TWO,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "hdmi_pll_od",
+ .ops = &clk_regmap_divider_ro_ops,
+ .parent_names = (const char *[]){ "hdmi_pll_dco" },
+ .num_parents = 1,
+ .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap gxbb_hdmi_pll_od2 = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = HHI_HDMI_PLL_CNTL2,
+ .shift = 22,
+ .width = 2,
+ .flags = CLK_DIVIDER_POWER_OF_TWO,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "hdmi_pll_od2",
+ .ops = &clk_regmap_divider_ro_ops,
+ .parent_names = (const char *[]){ "hdmi_pll_od" },
+ .num_parents = 1,
+ .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap gxbb_hdmi_pll = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = HHI_HDMI_PLL_CNTL2,
+ .shift = 18,
+ .width = 2,
+ .flags = CLK_DIVIDER_POWER_OF_TWO,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "hdmi_pll",
+ .ops = &clk_regmap_divider_ro_ops,
+ .parent_names = (const char *[]){ "hdmi_pll_od2" },
+ .num_parents = 1,
+ .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap gxl_hdmi_pll_od = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = HHI_HDMI_PLL_CNTL + 8,
+ .shift = 21,
+ .width = 2,
+ .flags = CLK_DIVIDER_POWER_OF_TWO,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "hdmi_pll_od",
+ .ops = &clk_regmap_divider_ro_ops,
+ .parent_names = (const char *[]){ "hdmi_pll_dco" },
+ .num_parents = 1,
+ .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap gxl_hdmi_pll_od2 = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = HHI_HDMI_PLL_CNTL + 8,
+ .shift = 23,
+ .width = 2,
+ .flags = CLK_DIVIDER_POWER_OF_TWO,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "hdmi_pll_od2",
+ .ops = &clk_regmap_divider_ro_ops,
+ .parent_names = (const char *[]){ "hdmi_pll_od" },
+ .num_parents = 1,
+ .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT,
+ },
+};
+
static struct clk_regmap gxl_hdmi_pll = {
- .data = &(struct meson_clk_pll_data){
- .m = {
- .reg_off = HHI_HDMI_PLL_CNTL,
- .shift = 0,
- .width = 9,
- },
- .n = {
- .reg_off = HHI_HDMI_PLL_CNTL,
- .shift = 9,
- .width = 5,
- },
- .frac = {
- /*
- * On gxl, there is a register shift due to
- * HHI_HDMI_PLL_CNTL1 which does not exist on gxbb,
- * so we compute the register offset based on the PLL
- * base to get it right
- */
- .reg_off = HHI_HDMI_PLL_CNTL + 4,
- .shift = 0,
- .width = 12,
- },
- .od = {
- .reg_off = HHI_HDMI_PLL_CNTL + 8,
- .shift = 21,
- .width = 2,
- },
- .od2 = {
- .reg_off = HHI_HDMI_PLL_CNTL + 8,
- .shift = 23,
- .width = 2,
- },
- .od3 = {
- .reg_off = HHI_HDMI_PLL_CNTL + 8,
- .shift = 19,
- .width = 2,
- },
- .l = {
- .reg_off = HHI_HDMI_PLL_CNTL,
- .shift = 31,
- .width = 1,
- },
- .rst = {
- .reg_off = HHI_HDMI_PLL_CNTL,
- .shift = 29,
- .width = 1,
- },
+ .data = &(struct clk_regmap_div_data){
+ .offset = HHI_HDMI_PLL_CNTL + 8,
+ .shift = 19,
+ .width = 2,
+ .flags = CLK_DIVIDER_POWER_OF_TWO,
},
.hw.init = &(struct clk_init_data){
.name = "hdmi_pll",
- .ops = &meson_clk_pll_ro_ops,
- .parent_names = (const char *[]){ "xtal" },
+ .ops = &clk_regmap_divider_ro_ops,
+ .parent_names = (const char *[]){ "hdmi_pll_od2" },
.num_parents = 1,
- .flags = CLK_GET_RATE_NOCACHE,
+ .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT,
},
};
-static struct clk_regmap gxbb_sys_pll = {
+static struct clk_regmap gxbb_sys_pll_dco = {
.data = &(struct meson_clk_pll_data){
+ .en = {
+ .reg_off = HHI_SYS_PLL_CNTL,
+ .shift = 30,
+ .width = 1,
+ },
.m = {
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 0,
@@ -350,11 +312,6 @@ static struct clk_regmap gxbb_sys_pll = {
.shift = 9,
.width = 5,
},
- .od = {
- .reg_off = HHI_SYS_PLL_CNTL,
- .shift = 10,
- .width = 2,
- },
.l = {
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 31,
@@ -367,11 +324,26 @@ static struct clk_regmap gxbb_sys_pll = {
},
},
.hw.init = &(struct clk_init_data){
- .name = "sys_pll",
+ .name = "sys_pll_dco",
.ops = &meson_clk_pll_ro_ops,
.parent_names = (const char *[]){ "xtal" },
.num_parents = 1,
- .flags = CLK_GET_RATE_NOCACHE,
+ },
+};
+
+static struct clk_regmap gxbb_sys_pll = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = HHI_SYS_PLL_CNTL,
+ .shift = 10,
+ .width = 2,
+ .flags = CLK_DIVIDER_POWER_OF_TWO,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "sys_pll",
+ .ops = &clk_regmap_divider_ro_ops,
+ .parent_names = (const char *[]){ "sys_pll_dco" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
},
};
@@ -379,11 +351,15 @@ static const struct reg_sequence gxbb_gp0_init_regs[] = {
{ .reg = HHI_GP0_PLL_CNTL2, .def = 0x69c80000 },
{ .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a5590c4 },
{ .reg = HHI_GP0_PLL_CNTL4, .def = 0x0000500d },
- { .reg = HHI_GP0_PLL_CNTL, .def = 0x4a000228 },
};
-static struct clk_regmap gxbb_gp0_pll = {
+static struct clk_regmap gxbb_gp0_pll_dco = {
.data = &(struct meson_clk_pll_data){
+ .en = {
+ .reg_off = HHI_GP0_PLL_CNTL,
+ .shift = 30,
+ .width = 1,
+ },
.m = {
.reg_off = HHI_GP0_PLL_CNTL,
.shift = 0,
@@ -394,11 +370,6 @@ static struct clk_regmap gxbb_gp0_pll = {
.shift = 9,
.width = 5,
},
- .od = {
- .reg_off = HHI_GP0_PLL_CNTL,
- .shift = 16,
- .width = 2,
- },
.l = {
.reg_off = HHI_GP0_PLL_CNTL,
.shift = 31,
@@ -409,16 +380,15 @@ static struct clk_regmap gxbb_gp0_pll = {
.shift = 29,
.width = 1,
},
- .table = gxbb_gp0_pll_rate_table,
+ .table = gxbb_gp0_pll_params_table,
.init_regs = gxbb_gp0_init_regs,
.init_count = ARRAY_SIZE(gxbb_gp0_init_regs),
},
.hw.init = &(struct clk_init_data){
- .name = "gp0_pll",
+ .name = "gp0_pll_dco",
.ops = &meson_clk_pll_ops,
.parent_names = (const char *[]){ "xtal" },
.num_parents = 1,
- .flags = CLK_GET_RATE_NOCACHE,
},
};
@@ -428,11 +398,15 @@ static const struct reg_sequence gxl_gp0_init_regs[] = {
{ .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a59a288 },
{ .reg = HHI_GP0_PLL_CNTL4, .def = 0xc000004d },
{ .reg = HHI_GP0_PLL_CNTL5, .def = 0x00078000 },
- { .reg = HHI_GP0_PLL_CNTL, .def = 0x40010250 },
};
-static struct clk_regmap gxl_gp0_pll = {
+static struct clk_regmap gxl_gp0_pll_dco = {
.data = &(struct meson_clk_pll_data){
+ .en = {
+ .reg_off = HHI_GP0_PLL_CNTL,
+ .shift = 30,
+ .width = 1,
+ },
.m = {
.reg_off = HHI_GP0_PLL_CNTL,
.shift = 0,
@@ -443,11 +417,6 @@ static struct clk_regmap gxl_gp0_pll = {
.shift = 9,
.width = 5,
},
- .od = {
- .reg_off = HHI_GP0_PLL_CNTL,
- .shift = 16,
- .width = 2,
- },
.frac = {
.reg_off = HHI_GP0_PLL_CNTL1,
.shift = 0,
@@ -463,16 +432,31 @@ static struct clk_regmap gxl_gp0_pll = {
.shift = 29,
.width = 1,
},
- .table = gxl_gp0_pll_rate_table,
+ .table = gxl_gp0_pll_params_table,
.init_regs = gxl_gp0_init_regs,
.init_count = ARRAY_SIZE(gxl_gp0_init_regs),
},
.hw.init = &(struct clk_init_data){
- .name = "gp0_pll",
+ .name = "gp0_pll_dco",
.ops = &meson_clk_pll_ops,
.parent_names = (const char *[]){ "xtal" },
.num_parents = 1,
- .flags = CLK_GET_RATE_NOCACHE,
+ },
+};
+
+static struct clk_regmap gxbb_gp0_pll = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = HHI_GP0_PLL_CNTL,
+ .shift = 16,
+ .width = 2,
+ .flags = CLK_DIVIDER_POWER_OF_TWO,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "gp0_pll",
+ .ops = &clk_regmap_divider_ops,
+ .parent_names = (const char *[]){ "gp0_pll_dco" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
},
};
@@ -522,6 +506,18 @@ static struct clk_regmap gxbb_fclk_div3 = {
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "fclk_div3_div" },
.num_parents = 1,
+ /*
+ * FIXME:
+ * This clock, as fdiv2, is used by the SCPI FW and is required
+ * by the platform to operate correctly.
+ * Until the following condition are met, we need this clock to
+ * be marked as critical:
+ * a) The SCPI generic driver claims and enable all the clocks
+ * it needs
+ * b) CCF has a clock hand-off mechanism to make the sure the
+ * clock stays on until the proper driver comes along
+ */
+ .flags = CLK_IS_CRITICAL,
},
};
@@ -1933,6 +1929,12 @@ static struct clk_hw_onecell_data gxbb_hw_onecell_data = {
[CLKID_GEN_CLK_SEL] = &gxbb_gen_clk_sel.hw,
[CLKID_GEN_CLK_DIV] = &gxbb_gen_clk_div.hw,
[CLKID_GEN_CLK] = &gxbb_gen_clk.hw,
+ [CLKID_FIXED_PLL_DCO] = &gxbb_fixed_pll_dco.hw,
+ [CLKID_HDMI_PLL_DCO] = &gxbb_hdmi_pll_dco.hw,
+ [CLKID_HDMI_PLL_OD] = &gxbb_hdmi_pll_od.hw,
+ [CLKID_HDMI_PLL_OD2] = &gxbb_hdmi_pll_od2.hw,
+ [CLKID_SYS_PLL_DCO] = &gxbb_sys_pll_dco.hw,
+ [CLKID_GP0_PLL_DCO] = &gxbb_gp0_pll_dco.hw,
[NR_CLKS] = NULL,
},
.num = NR_CLKS,
@@ -1948,7 +1950,7 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = {
[CLKID_FCLK_DIV4] = &gxbb_fclk_div4.hw,
[CLKID_FCLK_DIV5] = &gxbb_fclk_div5.hw,
[CLKID_FCLK_DIV7] = &gxbb_fclk_div7.hw,
- [CLKID_GP0_PLL] = &gxl_gp0_pll.hw,
+ [CLKID_GP0_PLL] = &gxbb_gp0_pll.hw,
[CLKID_MPEG_SEL] = &gxbb_mpeg_clk_sel.hw,
[CLKID_MPEG_DIV] = &gxbb_mpeg_clk_div.hw,
[CLKID_CLK81] = &gxbb_clk81.hw,
@@ -2098,19 +2100,29 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = {
[CLKID_GEN_CLK_SEL] = &gxbb_gen_clk_sel.hw,
[CLKID_GEN_CLK_DIV] = &gxbb_gen_clk_div.hw,
[CLKID_GEN_CLK] = &gxbb_gen_clk.hw,
+ [CLKID_FIXED_PLL_DCO] = &gxbb_fixed_pll_dco.hw,
+ [CLKID_HDMI_PLL_DCO] = &gxbb_hdmi_pll_dco.hw,
+ [CLKID_HDMI_PLL_OD] = &gxl_hdmi_pll_od.hw,
+ [CLKID_HDMI_PLL_OD2] = &gxl_hdmi_pll_od2.hw,
+ [CLKID_SYS_PLL_DCO] = &gxbb_sys_pll_dco.hw,
+ [CLKID_GP0_PLL_DCO] = &gxl_gp0_pll_dco.hw,
[NR_CLKS] = NULL,
},
.num = NR_CLKS,
};
static struct clk_regmap *const gxbb_clk_regmaps[] = {
- &gxbb_gp0_pll,
+ &gxbb_gp0_pll_dco,
&gxbb_hdmi_pll,
+ &gxbb_hdmi_pll_od,
+ &gxbb_hdmi_pll_od2,
};
static struct clk_regmap *const gxl_clk_regmaps[] = {
- &gxl_gp0_pll,
+ &gxl_gp0_pll_dco,
&gxl_hdmi_pll,
+ &gxl_hdmi_pll_od,
+ &gxl_hdmi_pll_od2,
};
static struct clk_regmap *const gx_clk_regmaps[] = {
@@ -2265,6 +2277,10 @@ static struct clk_regmap *const gx_clk_regmaps[] = {
&gxbb_gen_clk_sel,
&gxbb_gen_clk_div,
&gxbb_gen_clk,
+ &gxbb_fixed_pll_dco,
+ &gxbb_hdmi_pll_dco,
+ &gxbb_sys_pll_dco,
+ &gxbb_gp0_pll,
};
struct clkc_data {
diff --git a/drivers/clk/meson/gxbb.h b/drivers/clk/meson/gxbb.h
index 20dfb1daf5b8..72bc077d9663 100644
--- a/drivers/clk/meson/gxbb.h
+++ b/drivers/clk/meson/gxbb.h
@@ -159,8 +159,14 @@
#define CLKID_VDEC_HEVC_DIV 155
#define CLKID_GEN_CLK_SEL 157
#define CLKID_GEN_CLK_DIV 158
-
-#define NR_CLKS 160
+#define CLKID_FIXED_PLL_DCO 160
+#define CLKID_HDMI_PLL_DCO 161
+#define CLKID_HDMI_PLL_OD 162
+#define CLKID_HDMI_PLL_OD2 163
+#define CLKID_SYS_PLL_DCO 164
+#define CLKID_GP0_PLL_DCO 165
+
+#define NR_CLKS 166
/* include the CLKIDs that have been made part of the DT binding */
#include <dt-bindings/clock/gxbb-clkc.h>
diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c
index 7447d96a265f..346b9e165b7a 100644
--- a/drivers/clk/meson/meson8b.c
+++ b/drivers/clk/meson/meson8b.c
@@ -11,7 +11,6 @@
#include <linux/clk-provider.h>
#include <linux/init.h>
#include <linux/of_address.h>
-#include <linux/platform_device.h>
#include <linux/reset-controller.h>
#include <linux/slab.h>
#include <linux/regmap.h>
@@ -22,66 +21,27 @@
static DEFINE_SPINLOCK(meson_clk_lock);
-static void __iomem *clk_base;
-
struct meson8b_clk_reset {
struct reset_controller_dev reset;
- void __iomem *base;
+ struct regmap *regmap;
};
-static const struct pll_rate_table sys_pll_rate_table[] = {
- PLL_RATE(312000000, 52, 1, 2),
- PLL_RATE(336000000, 56, 1, 2),
- PLL_RATE(360000000, 60, 1, 2),
- PLL_RATE(384000000, 64, 1, 2),
- PLL_RATE(408000000, 68, 1, 2),
- PLL_RATE(432000000, 72, 1, 2),
- PLL_RATE(456000000, 76, 1, 2),
- PLL_RATE(480000000, 80, 1, 2),
- PLL_RATE(504000000, 84, 1, 2),
- PLL_RATE(528000000, 88, 1, 2),
- PLL_RATE(552000000, 92, 1, 2),
- PLL_RATE(576000000, 96, 1, 2),
- PLL_RATE(600000000, 50, 1, 1),
- PLL_RATE(624000000, 52, 1, 1),
- PLL_RATE(648000000, 54, 1, 1),
- PLL_RATE(672000000, 56, 1, 1),
- PLL_RATE(696000000, 58, 1, 1),
- PLL_RATE(720000000, 60, 1, 1),
- PLL_RATE(744000000, 62, 1, 1),
- PLL_RATE(768000000, 64, 1, 1),
- PLL_RATE(792000000, 66, 1, 1),
- PLL_RATE(816000000, 68, 1, 1),
- PLL_RATE(840000000, 70, 1, 1),
- PLL_RATE(864000000, 72, 1, 1),
- PLL_RATE(888000000, 74, 1, 1),
- PLL_RATE(912000000, 76, 1, 1),
- PLL_RATE(936000000, 78, 1, 1),
- PLL_RATE(960000000, 80, 1, 1),
- PLL_RATE(984000000, 82, 1, 1),
- PLL_RATE(1008000000, 84, 1, 1),
- PLL_RATE(1032000000, 86, 1, 1),
- PLL_RATE(1056000000, 88, 1, 1),
- PLL_RATE(1080000000, 90, 1, 1),
- PLL_RATE(1104000000, 92, 1, 1),
- PLL_RATE(1128000000, 94, 1, 1),
- PLL_RATE(1152000000, 96, 1, 1),
- PLL_RATE(1176000000, 98, 1, 1),
- PLL_RATE(1200000000, 50, 1, 0),
- PLL_RATE(1224000000, 51, 1, 0),
- PLL_RATE(1248000000, 52, 1, 0),
- PLL_RATE(1272000000, 53, 1, 0),
- PLL_RATE(1296000000, 54, 1, 0),
- PLL_RATE(1320000000, 55, 1, 0),
- PLL_RATE(1344000000, 56, 1, 0),
- PLL_RATE(1368000000, 57, 1, 0),
- PLL_RATE(1392000000, 58, 1, 0),
- PLL_RATE(1416000000, 59, 1, 0),
- PLL_RATE(1440000000, 60, 1, 0),
- PLL_RATE(1464000000, 61, 1, 0),
- PLL_RATE(1488000000, 62, 1, 0),
- PLL_RATE(1512000000, 63, 1, 0),
- PLL_RATE(1536000000, 64, 1, 0),
+static const struct pll_params_table sys_pll_params_table[] = {
+ PLL_PARAMS(50, 1),
+ PLL_PARAMS(51, 1),
+ PLL_PARAMS(52, 1),
+ PLL_PARAMS(53, 1),
+ PLL_PARAMS(54, 1),
+ PLL_PARAMS(55, 1),
+ PLL_PARAMS(56, 1),
+ PLL_PARAMS(57, 1),
+ PLL_PARAMS(58, 1),
+ PLL_PARAMS(59, 1),
+ PLL_PARAMS(60, 1),
+ PLL_PARAMS(61, 1),
+ PLL_PARAMS(62, 1),
+ PLL_PARAMS(63, 1),
+ PLL_PARAMS(64, 1),
{ /* sentinel */ },
};
@@ -94,8 +54,13 @@ static struct clk_fixed_rate meson8b_xtal = {
},
};
-static struct clk_regmap meson8b_fixed_pll = {
+static struct clk_regmap meson8b_fixed_pll_dco = {
.data = &(struct meson_clk_pll_data){
+ .en = {
+ .reg_off = HHI_MPLL_CNTL,
+ .shift = 30,
+ .width = 1,
+ },
.m = {
.reg_off = HHI_MPLL_CNTL,
.shift = 0,
@@ -106,11 +71,6 @@ static struct clk_regmap meson8b_fixed_pll = {
.shift = 9,
.width = 5,
},
- .od = {
- .reg_off = HHI_MPLL_CNTL,
- .shift = 16,
- .width = 2,
- },
.frac = {
.reg_off = HHI_MPLL_CNTL2,
.shift = 0,
@@ -128,16 +88,39 @@ static struct clk_regmap meson8b_fixed_pll = {
},
},
.hw.init = &(struct clk_init_data){
- .name = "fixed_pll",
+ .name = "fixed_pll_dco",
.ops = &meson_clk_pll_ro_ops,
.parent_names = (const char *[]){ "xtal" },
.num_parents = 1,
- .flags = CLK_GET_RATE_NOCACHE,
},
};
-static struct clk_regmap meson8b_vid_pll = {
+static struct clk_regmap meson8b_fixed_pll = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = HHI_MPLL_CNTL,
+ .shift = 16,
+ .width = 2,
+ .flags = CLK_DIVIDER_POWER_OF_TWO,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "fixed_pll",
+ .ops = &clk_regmap_divider_ro_ops,
+ .parent_names = (const char *[]){ "fixed_pll_dco" },
+ .num_parents = 1,
+ /*
+ * This clock won't ever change at runtime so
+ * CLK_SET_RATE_PARENT is not required
+ */
+ },
+};
+
+static struct clk_regmap meson8b_vid_pll_dco = {
.data = &(struct meson_clk_pll_data){
+ .en = {
+ .reg_off = HHI_VID_PLL_CNTL,
+ .shift = 30,
+ .width = 1,
+ },
.m = {
.reg_off = HHI_VID_PLL_CNTL,
.shift = 0,
@@ -148,11 +131,6 @@ static struct clk_regmap meson8b_vid_pll = {
.shift = 9,
.width = 5,
},
- .od = {
- .reg_off = HHI_VID_PLL_CNTL,
- .shift = 16,
- .width = 2,
- },
.l = {
.reg_off = HHI_VID_PLL_CNTL,
.shift = 31,
@@ -165,16 +143,36 @@ static struct clk_regmap meson8b_vid_pll = {
},
},
.hw.init = &(struct clk_init_data){
- .name = "vid_pll",
+ .name = "vid_pll_dco",
.ops = &meson_clk_pll_ro_ops,
.parent_names = (const char *[]){ "xtal" },
.num_parents = 1,
- .flags = CLK_GET_RATE_NOCACHE,
},
};
-static struct clk_regmap meson8b_sys_pll = {
+static struct clk_regmap meson8b_vid_pll = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = HHI_VID_PLL_CNTL,
+ .shift = 16,
+ .width = 2,
+ .flags = CLK_DIVIDER_POWER_OF_TWO,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "vid_pll",
+ .ops = &clk_regmap_divider_ro_ops,
+ .parent_names = (const char *[]){ "vid_pll_dco" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap meson8b_sys_pll_dco = {
.data = &(struct meson_clk_pll_data){
+ .en = {
+ .reg_off = HHI_SYS_PLL_CNTL,
+ .shift = 30,
+ .width = 1,
+ },
.m = {
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 0,
@@ -185,11 +183,6 @@ static struct clk_regmap meson8b_sys_pll = {
.shift = 9,
.width = 5,
},
- .od = {
- .reg_off = HHI_SYS_PLL_CNTL,
- .shift = 16,
- .width = 2,
- },
.l = {
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 31,
@@ -200,14 +193,29 @@ static struct clk_regmap meson8b_sys_pll = {
.shift = 29,
.width = 1,
},
- .table = sys_pll_rate_table,
+ .table = sys_pll_params_table,
},
.hw.init = &(struct clk_init_data){
- .name = "sys_pll",
+ .name = "sys_pll_dco",
.ops = &meson_clk_pll_ro_ops,
.parent_names = (const char *[]){ "xtal" },
.num_parents = 1,
- .flags = CLK_GET_RATE_NOCACHE,
+ },
+};
+
+static struct clk_regmap meson8b_sys_pll = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = HHI_SYS_PLL_CNTL,
+ .shift = 16,
+ .width = 2,
+ .flags = CLK_DIVIDER_POWER_OF_TWO,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "sys_pll",
+ .ops = &clk_regmap_divider_ro_ops,
+ .parent_names = (const char *[]){ "sys_pll_dco" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
},
};
@@ -879,6 +887,9 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = {
[CLKID_NAND_SEL] = &meson8b_nand_clk_sel.hw,
[CLKID_NAND_DIV] = &meson8b_nand_clk_div.hw,
[CLKID_NAND_CLK] = &meson8b_nand_clk_gate.hw,
+ [CLKID_PLL_FIXED_DCO] = &meson8b_fixed_pll_dco.hw,
+ [CLKID_PLL_VID_DCO] = &meson8b_vid_pll_dco.hw,
+ [CLKID_PLL_SYS_DCO] = &meson8b_sys_pll_dco.hw,
[CLK_NR_CLKS] = NULL,
},
.num = CLK_NR_CLKS,
@@ -987,6 +998,9 @@ static struct clk_regmap *const meson8b_clk_regmaps[] = {
&meson8b_nand_clk_sel,
&meson8b_nand_clk_div,
&meson8b_nand_clk_gate,
+ &meson8b_fixed_pll_dco,
+ &meson8b_vid_pll_dco,
+ &meson8b_sys_pll_dco,
};
static const struct meson8b_clk_reset_line {
@@ -1050,7 +1064,6 @@ static int meson8b_clk_reset_update(struct reset_controller_dev *rcdev,
container_of(rcdev, struct meson8b_clk_reset, reset);
unsigned long flags;
const struct meson8b_clk_reset_line *reset;
- u32 val;
if (id >= ARRAY_SIZE(meson8b_clk_reset_bits))
return -EINVAL;
@@ -1059,12 +1072,12 @@ static int meson8b_clk_reset_update(struct reset_controller_dev *rcdev,
spin_lock_irqsave(&meson_clk_lock, flags);
- val = readl(meson8b_clk_reset->base + reset->reg);
if (assert)
- val |= BIT(reset->bit_idx);
+ regmap_update_bits(meson8b_clk_reset->regmap, reset->reg,
+ BIT(reset->bit_idx), BIT(reset->bit_idx));
else
- val &= ~BIT(reset->bit_idx);
- writel(val, meson8b_clk_reset->base + reset->reg);
+ regmap_update_bits(meson8b_clk_reset->regmap, reset->reg,
+ BIT(reset->bit_idx), 0);
spin_unlock_irqrestore(&meson_clk_lock, flags);
@@ -1094,62 +1107,12 @@ static const struct regmap_config clkc_regmap_config = {
.reg_stride = 4,
};
-static int meson8b_clkc_probe(struct platform_device *pdev)
-{
- int ret, i;
- struct device *dev = &pdev->dev;
- struct regmap *map;
-
- if (!clk_base)
- return -ENXIO;
-
- map = devm_regmap_init_mmio(dev, clk_base, &clkc_regmap_config);
- if (IS_ERR(map))
- return PTR_ERR(map);
-
- /* Populate regmap for the regmap backed clocks */
- for (i = 0; i < ARRAY_SIZE(meson8b_clk_regmaps); i++)
- meson8b_clk_regmaps[i]->map = map;
-
- /*
- * register all clks
- * CLKID_UNUSED = 0, so skip it and start with CLKID_XTAL = 1
- */
- for (i = CLKID_XTAL; i < CLK_NR_CLKS; i++) {
- /* array might be sparse */
- if (!meson8b_hw_onecell_data.hws[i])
- continue;
-
- ret = devm_clk_hw_register(dev, meson8b_hw_onecell_data.hws[i]);
- if (ret)
- return ret;
- }
-
- return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
- &meson8b_hw_onecell_data);
-}
-
-static const struct of_device_id meson8b_clkc_match_table[] = {
- { .compatible = "amlogic,meson8-clkc" },
- { .compatible = "amlogic,meson8b-clkc" },
- { .compatible = "amlogic,meson8m2-clkc" },
- { }
-};
-
-static struct platform_driver meson8b_driver = {
- .probe = meson8b_clkc_probe,
- .driver = {
- .name = "meson8b-clkc",
- .of_match_table = meson8b_clkc_match_table,
- },
-};
-
-builtin_platform_driver(meson8b_driver);
-
-static void __init meson8b_clkc_reset_init(struct device_node *np)
+static void __init meson8b_clkc_init(struct device_node *np)
{
struct meson8b_clk_reset *rstc;
- int ret;
+ void __iomem *clk_base;
+ struct regmap *map;
+ int i, ret;
/* Generic clocks, PLLs and some of the reset-bits */
clk_base = of_iomap(np, 1);
@@ -1158,12 +1121,16 @@ static void __init meson8b_clkc_reset_init(struct device_node *np)
return;
}
+ map = regmap_init_mmio(NULL, clk_base, &clkc_regmap_config);
+ if (IS_ERR(map))
+ return;
+
rstc = kzalloc(sizeof(*rstc), GFP_KERNEL);
if (!rstc)
return;
/* Reset Controller */
- rstc->base = clk_base;
+ rstc->regmap = map;
rstc->reset.ops = &meson8b_clk_reset_ops;
rstc->reset.nr_resets = ARRAY_SIZE(meson8b_clk_reset_bits);
rstc->reset.of_node = np;
@@ -1173,11 +1140,34 @@ static void __init meson8b_clkc_reset_init(struct device_node *np)
__func__, ret);
return;
}
+
+ /* Populate regmap for the regmap backed clocks */
+ for (i = 0; i < ARRAY_SIZE(meson8b_clk_regmaps); i++)
+ meson8b_clk_regmaps[i]->map = map;
+
+ /*
+ * register all clks
+ * CLKID_UNUSED = 0, so skip it and start with CLKID_XTAL = 1
+ */
+ for (i = CLKID_XTAL; i < CLK_NR_CLKS; i++) {
+ /* array might be sparse */
+ if (!meson8b_hw_onecell_data.hws[i])
+ continue;
+
+ ret = clk_hw_register(NULL, meson8b_hw_onecell_data.hws[i]);
+ if (ret)
+ return;
+ }
+
+ ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get,
+ &meson8b_hw_onecell_data);
+ if (ret)
+ pr_err("%s: failed to register clock provider\n", __func__);
}
CLK_OF_DECLARE_DRIVER(meson8_clkc, "amlogic,meson8-clkc",
- meson8b_clkc_reset_init);
+ meson8b_clkc_init);
CLK_OF_DECLARE_DRIVER(meson8b_clkc, "amlogic,meson8b-clkc",
- meson8b_clkc_reset_init);
+ meson8b_clkc_init);
CLK_OF_DECLARE_DRIVER(meson8m2_clkc, "amlogic,meson8m2-clkc",
- meson8b_clkc_reset_init);
+ meson8b_clkc_init);
diff --git a/drivers/clk/meson/meson8b.h b/drivers/clk/meson/meson8b.h
index 5d09412b5084..1c6fb180e6a2 100644
--- a/drivers/clk/meson/meson8b.h
+++ b/drivers/clk/meson/meson8b.h
@@ -75,8 +75,11 @@
#define CLKID_FCLK_DIV7_DIV 109
#define CLKID_NAND_SEL 110
#define CLKID_NAND_DIV 111
+#define CLKID_PLL_FIXED_DCO 113
+#define CLKID_PLL_VID_DCO 114
+#define CLKID_PLL_SYS_DCO 115
-#define CLK_NR_CLKS 113
+#define CLK_NR_CLKS 116
/*
* include the CLKID and RESETID that have
diff --git a/drivers/clk/mmp/clk-of-mmp2.c b/drivers/clk/mmp/clk-of-mmp2.c
index 0fc75c395957..d083b860f083 100644
--- a/drivers/clk/mmp/clk-of-mmp2.c
+++ b/drivers/clk/mmp/clk-of-mmp2.c
@@ -227,8 +227,8 @@ static struct mmp_param_gate_clk apmu_gate_clks[] = {
/* The gate clocks has mux parent. */
{MMP2_CLK_SDH0, "sdh0_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH0, 0x1b, 0x1b, 0x0, 0, &sdh_lock},
{MMP2_CLK_SDH1, "sdh1_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH1, 0x1b, 0x1b, 0x0, 0, &sdh_lock},
- {MMP2_CLK_SDH1, "sdh2_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH2, 0x1b, 0x1b, 0x0, 0, &sdh_lock},
- {MMP2_CLK_SDH1, "sdh3_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH3, 0x1b, 0x1b, 0x0, 0, &sdh_lock},
+ {MMP2_CLK_SDH2, "sdh2_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH2, 0x1b, 0x1b, 0x0, 0, &sdh_lock},
+ {MMP2_CLK_SDH3, "sdh3_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH3, 0x1b, 0x1b, 0x0, 0, &sdh_lock},
{MMP2_CLK_DISP0, "disp0_clk", "disp0_div", CLK_SET_RATE_PARENT, APMU_DISP0, 0x1b, 0x1b, 0x0, 0, &disp0_lock},
{MMP2_CLK_DISP0_SPHY, "disp0_sphy_clk", "disp0_sphy_div", CLK_SET_RATE_PARENT, APMU_DISP0, 0x1024, 0x1024, 0x0, 0, &disp0_lock},
{MMP2_CLK_DISP1, "disp1_clk", "disp1_div", CLK_SET_RATE_PARENT, APMU_DISP1, 0x1b, 0x1b, 0x0, 0, &disp1_lock},
diff --git a/drivers/clk/mvebu/ap806-system-controller.c b/drivers/clk/mvebu/ap806-system-controller.c
index fa2fbd2cef4a..ea54a874bbda 100644
--- a/drivers/clk/mvebu/ap806-system-controller.c
+++ b/drivers/clk/mvebu/ap806-system-controller.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Marvell Armada AP806 System Controller
*
@@ -5,9 +6,6 @@
*
* Thomas Petazzoni <thomas.petazzoni@free-electrons.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.
*/
#define pr_fmt(fmt) "ap806-system-controller: " fmt
@@ -155,7 +153,6 @@ static int ap806_syscon_common_probe(struct platform_device *pdev,
goto fail4;
}
- of_clk_add_provider(np, of_clk_src_onecell_get, &ap806_clk_data);
ret = of_clk_add_provider(np, of_clk_src_onecell_get, &ap806_clk_data);
if (ret)
goto fail_clk_add;
diff --git a/drivers/clk/mvebu/armada-370.c b/drivers/clk/mvebu/armada-370.c
index 2c7c1085f883..7dedfaa6e152 100644
--- a/drivers/clk/mvebu/armada-370.c
+++ b/drivers/clk/mvebu/armada-370.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Marvell Armada 370 SoC clocks
*
@@ -7,9 +8,6 @@
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
* Andrew Lunn <andrew@lunn.ch>
*
- * 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>
diff --git a/drivers/clk/mvebu/armada-375.c b/drivers/clk/mvebu/armada-375.c
index c7af2242b796..a7157c690238 100644
--- a/drivers/clk/mvebu/armada-375.c
+++ b/drivers/clk/mvebu/armada-375.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Marvell Armada 375 SoC clocks
*
@@ -7,9 +8,6 @@
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
* Andrew Lunn <andrew@lunn.ch>
*
- * 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>
diff --git a/drivers/clk/mvebu/armada-37xx-periph.c b/drivers/clk/mvebu/armada-37xx-periph.c
index 499f5962c8b0..1f1cff428d78 100644
--- a/drivers/clk/mvebu/armada-37xx-periph.c
+++ b/drivers/clk/mvebu/armada-37xx-periph.c
@@ -56,6 +56,15 @@
struct clk_periph_driver_data {
struct clk_hw_onecell_data *hw_data;
spinlock_t lock;
+ void __iomem *reg;
+
+ /* Storage registers for suspend/resume operations */
+ u32 tbg_sel;
+ u32 div_sel0;
+ u32 div_sel1;
+ u32 div_sel2;
+ u32 clk_sel;
+ u32 clk_dis;
};
struct clk_double_div {
@@ -672,6 +681,40 @@ static int armada_3700_add_composite_clk(const struct clk_periph_data *data,
return PTR_ERR_OR_ZERO(*hw);
}
+static int __maybe_unused armada_3700_periph_clock_suspend(struct device *dev)
+{
+ struct clk_periph_driver_data *data = dev_get_drvdata(dev);
+
+ data->tbg_sel = readl(data->reg + TBG_SEL);
+ data->div_sel0 = readl(data->reg + DIV_SEL0);
+ data->div_sel1 = readl(data->reg + DIV_SEL1);
+ data->div_sel2 = readl(data->reg + DIV_SEL2);
+ data->clk_sel = readl(data->reg + CLK_SEL);
+ data->clk_dis = readl(data->reg + CLK_DIS);
+
+ return 0;
+}
+
+static int __maybe_unused armada_3700_periph_clock_resume(struct device *dev)
+{
+ struct clk_periph_driver_data *data = dev_get_drvdata(dev);
+
+ /* Follow the same order than what the Cortex-M3 does (ATF code) */
+ writel(data->clk_dis, data->reg + CLK_DIS);
+ writel(data->div_sel0, data->reg + DIV_SEL0);
+ writel(data->div_sel1, data->reg + DIV_SEL1);
+ writel(data->div_sel2, data->reg + DIV_SEL2);
+ writel(data->tbg_sel, data->reg + TBG_SEL);
+ writel(data->clk_sel, data->reg + CLK_SEL);
+
+ return 0;
+}
+
+static const struct dev_pm_ops armada_3700_periph_clock_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(armada_3700_periph_clock_suspend,
+ armada_3700_periph_clock_resume)
+};
+
static int armada_3700_periph_clock_probe(struct platform_device *pdev)
{
struct clk_periph_driver_data *driver_data;
@@ -680,7 +723,6 @@ static int armada_3700_periph_clock_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
int num_periph = 0, i, ret;
struct resource *res;
- void __iomem *reg;
data = of_device_get_match_data(dev);
if (!data)
@@ -689,11 +731,6 @@ static int armada_3700_periph_clock_probe(struct platform_device *pdev)
while (data[num_periph].name)
num_periph++;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- reg = devm_ioremap_resource(dev, res);
- if (IS_ERR(reg))
- return PTR_ERR(reg);
-
driver_data = devm_kzalloc(dev, sizeof(*driver_data), GFP_KERNEL);
if (!driver_data)
return -ENOMEM;
@@ -706,12 +743,16 @@ static int armada_3700_periph_clock_probe(struct platform_device *pdev)
return -ENOMEM;
driver_data->hw_data->num = num_periph;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ driver_data->reg = devm_ioremap_resource(dev, res);
+ if (IS_ERR(driver_data->reg))
+ return PTR_ERR(driver_data->reg);
+
spin_lock_init(&driver_data->lock);
for (i = 0; i < num_periph; i++) {
struct clk_hw **hw = &driver_data->hw_data->hws[i];
-
- if (armada_3700_add_composite_clk(&data[i], reg,
+ if (armada_3700_add_composite_clk(&data[i], driver_data->reg,
&driver_data->lock, dev, hw))
dev_err(dev, "Can't register periph clock %s\n",
data[i].name);
@@ -749,6 +790,7 @@ static struct platform_driver armada_3700_periph_clock_driver = {
.driver = {
.name = "marvell-armada-3700-periph-clock",
.of_match_table = armada_3700_periph_clock_of_match,
+ .pm = &armada_3700_periph_clock_pm_ops,
},
};
diff --git a/drivers/clk/mvebu/armada-37xx-tbg.c b/drivers/clk/mvebu/armada-37xx-tbg.c
index 7ff041f73b55..ee272d4d8c24 100644
--- a/drivers/clk/mvebu/armada-37xx-tbg.c
+++ b/drivers/clk/mvebu/armada-37xx-tbg.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Marvell Armada 37xx SoC Time Base Generator clocks
*
* Copyright (C) 2016 Marvell
*
* Gregory CLEMENT <gregory.clement@free-electrons.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2 or later. This program is licensed "as is"
- * without any warranty of any kind, whether express or implied.
*/
#include <linux/clk-provider.h>
@@ -99,12 +96,13 @@ static int armada_3700_tbg_clock_probe(struct platform_device *pdev)
hw_tbg_data->num = NUM_TBG;
platform_set_drvdata(pdev, hw_tbg_data);
- parent = devm_clk_get(dev, NULL);
+ parent = clk_get(dev, NULL);
if (IS_ERR(parent)) {
dev_err(dev, "Could get the clock parent\n");
return -EINVAL;
}
parent_name = __clk_get_name(parent);
+ clk_put(parent);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
reg = devm_ioremap_resource(dev, res);
diff --git a/drivers/clk/mvebu/armada-37xx-xtal.c b/drivers/clk/mvebu/armada-37xx-xtal.c
index 612d65ede10a..e9e306d4e9af 100644
--- a/drivers/clk/mvebu/armada-37xx-xtal.c
+++ b/drivers/clk/mvebu/armada-37xx-xtal.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Marvell Armada 37xx SoC xtal clocks
*
@@ -5,9 +6,6 @@
*
* Gregory CLEMENT <gregory.clement@free-electrons.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/clk-provider.h>
diff --git a/drivers/clk/mvebu/armada-38x.c b/drivers/clk/mvebu/armada-38x.c
index 9ff4ea63932d..ef2ab81f087d 100644
--- a/drivers/clk/mvebu/armada-38x.c
+++ b/drivers/clk/mvebu/armada-38x.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Marvell Armada 380/385 SoC clocks
*
@@ -7,9 +8,6 @@
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
* Andrew Lunn <andrew@lunn.ch>
*
- * 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>
diff --git a/drivers/clk/mvebu/armada-39x.c b/drivers/clk/mvebu/armada-39x.c
index 4fdfd32247a9..674ccfd6236e 100644
--- a/drivers/clk/mvebu/armada-39x.c
+++ b/drivers/clk/mvebu/armada-39x.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Marvell Armada 39x SoC clocks
*
@@ -8,9 +9,6 @@
* Andrew Lunn <andrew@lunn.ch>
* Thomas Petazzoni <thomas.petazzoni@free-electrons.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/kernel.h>
diff --git a/drivers/clk/mvebu/armada-xp.c b/drivers/clk/mvebu/armada-xp.c
index 0ec44ae9a2a2..e8f03293ec83 100644
--- a/drivers/clk/mvebu/armada-xp.c
+++ b/drivers/clk/mvebu/armada-xp.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Marvell Armada XP SoC clocks
*
@@ -7,9 +8,6 @@
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
* Andrew Lunn <andrew@lunn.ch>
*
- * 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>
diff --git a/drivers/clk/mvebu/clk-corediv.c b/drivers/clk/mvebu/clk-corediv.c
index 68f05c53d40e..1fc84b0e72ee 100644
--- a/drivers/clk/mvebu/clk-corediv.c
+++ b/drivers/clk/mvebu/clk-corediv.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* MVEBU Core divider clock
*
@@ -5,9 +6,6 @@
*
* Ezequiel Garcia <ezequiel.garcia@free-electrons.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/kernel.h>
diff --git a/drivers/clk/mvebu/clk-cpu.c b/drivers/clk/mvebu/clk-cpu.c
index 072aa38374ce..c2af3395cf13 100644
--- a/drivers/clk/mvebu/clk-cpu.c
+++ b/drivers/clk/mvebu/clk-cpu.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Marvell MVEBU CPU clock handling.
*
@@ -5,9 +6,6 @@
*
* Gregory CLEMENT <gregory.clement@free-electrons.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/kernel.h>
#include <linux/slab.h>
@@ -183,7 +181,7 @@ static void __init of_cpu_clk_setup(struct device_node *node)
pr_warn("%s: pmu-dfs base register not set, dynamic frequency scaling not available\n",
__func__);
- for_each_node_by_type(dn, "cpu")
+ for_each_of_cpu_node(dn)
ncpus++;
cpuclk = kcalloc(ncpus, sizeof(*cpuclk), GFP_KERNEL);
@@ -194,7 +192,7 @@ static void __init of_cpu_clk_setup(struct device_node *node)
if (WARN_ON(!clks))
goto clks_out;
- for_each_node_by_type(dn, "cpu") {
+ for_each_of_cpu_node(dn) {
struct clk_init_data init;
struct clk *clk;
char *clk_name = kzalloc(5, GFP_KERNEL);
diff --git a/drivers/clk/mvebu/common.c b/drivers/clk/mvebu/common.c
index 472c88b90256..6ab3c2e627c7 100644
--- a/drivers/clk/mvebu/common.c
+++ b/drivers/clk/mvebu/common.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Marvell EBU SoC common clock handling
*
@@ -7,9 +8,6 @@
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
* Andrew Lunn <andrew@lunn.ch>
*
- * 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>
diff --git a/drivers/clk/mvebu/common.h b/drivers/clk/mvebu/common.h
index f0de6c8a494a..d1ab79b43105 100644
--- a/drivers/clk/mvebu/common.h
+++ b/drivers/clk/mvebu/common.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Marvell EBU SoC common clock handling
*
@@ -7,9 +8,6 @@
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
* Andrew Lunn <andrew@lunn.ch>
*
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
*/
#ifndef __CLK_MVEBU_COMMON_H_
diff --git a/drivers/clk/mvebu/cp110-system-controller.c b/drivers/clk/mvebu/cp110-system-controller.c
index 75bf7b8f282f..9781b1bf5998 100644
--- a/drivers/clk/mvebu/cp110-system-controller.c
+++ b/drivers/clk/mvebu/cp110-system-controller.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Marvell Armada CP110 System Controller
*
@@ -5,9 +6,6 @@
*
* Thomas Petazzoni <thomas.petazzoni@free-electrons.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.
*/
/*
diff --git a/drivers/clk/mvebu/dove.c b/drivers/clk/mvebu/dove.c
index 59fad9546c84..e0dd99f36bf4 100644
--- a/drivers/clk/mvebu/dove.c
+++ b/drivers/clk/mvebu/dove.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Marvell Dove SoC clocks
*
@@ -7,9 +8,6 @@
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
* Andrew Lunn <andrew@lunn.ch>
*
- * 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>
diff --git a/drivers/clk/mvebu/kirkwood.c b/drivers/clk/mvebu/kirkwood.c
index a2a8d614039d..6f784167bda4 100644
--- a/drivers/clk/mvebu/kirkwood.c
+++ b/drivers/clk/mvebu/kirkwood.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Marvell Kirkwood SoC clocks
*
@@ -7,9 +8,6 @@
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
* Andrew Lunn <andrew@lunn.ch>
*
- * 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>
diff --git a/drivers/clk/mvebu/mv98dx3236.c b/drivers/clk/mvebu/mv98dx3236.c
index 6e203af73cac..0a74cf7a7725 100644
--- a/drivers/clk/mvebu/mv98dx3236.c
+++ b/drivers/clk/mvebu/mv98dx3236.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Marvell MV98DX3236 SoC clocks
*
@@ -7,9 +8,6 @@
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
* Andrew Lunn <andrew@lunn.ch>
*
- * 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>
diff --git a/drivers/clk/mvebu/orion.c b/drivers/clk/mvebu/orion.c
index a6e5bee23385..f681a65be20a 100644
--- a/drivers/clk/mvebu/orion.c
+++ b/drivers/clk/mvebu/orion.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Marvell Orion SoC clocks
*
@@ -5,9 +6,6 @@
*
* Thomas Petazzoni <thomas.petazzoni@free-electrons.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/kernel.h>
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 064768699fe7..a611531df115 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -1,3 +1,7 @@
+config KRAIT_CLOCKS
+ bool
+ select KRAIT_L2_ACCESSORS
+
config QCOM_GDSC
bool
select PM_GENERIC_DOMAINS if PM
@@ -235,6 +239,31 @@ config MSM_GCC_8998
Say Y if you want to use peripheral devices such as UART, SPI,
i2c, USB, UFS, SD/eMMC, PCIe, etc.
+config QCS_GCC_404
+ tristate "QCS404 Global Clock Controller"
+ depends on COMMON_CLK_QCOM
+ help
+ Support for the global clock controller on QCS404 devices.
+ Say Y if you want to use multimedia devices or peripheral
+ devices such as UART, SPI, I2C, USB, SD/eMMC, PCIe etc.
+
+config SDM_CAMCC_845
+ tristate "SDM845 Camera Clock Controller"
+ depends on COMMON_CLK_QCOM
+ select SDM_GCC_845
+ help
+ Support for the camera clock controller on SDM845 devices.
+ Say Y if you want to support camera devices and camera functionality.
+
+config SDM_GCC_660
+ tristate "SDM660 Global Clock Controller"
+ select QCOM_GDSC
+ depends on COMMON_CLK_QCOM
+ help
+ Support for the global clock controller on SDM660 devices.
+ Say Y if you want to use peripheral devices such as UART, SPI,
+ i2C, USB, UFS, SDDC, PCIe, etc.
+
config SDM_GCC_845
tristate "SDM845 Global Clock Controller"
select QCOM_GDSC
@@ -272,3 +301,27 @@ config SPMI_PMIC_CLKDIV
Technologies, Inc. SPMI PMIC. It configures the frequency of
clkdiv outputs of the PMIC. These clocks are typically wired
through alternate functions on GPIO pins.
+
+config QCOM_HFPLL
+ tristate "High-Frequency PLL (HFPLL) Clock Controller"
+ depends on COMMON_CLK_QCOM
+ help
+ Support for the high-frequency PLLs present on Qualcomm devices.
+ Say Y if you want to support CPU frequency scaling on devices
+ such as MSM8974, APQ8084, etc.
+
+config KPSS_XCC
+ tristate "KPSS Clock Controller"
+ depends on COMMON_CLK_QCOM
+ help
+ Support for the Krait ACC and GCC clock controllers. Say Y
+ if you want to support CPU frequency scaling on devices such
+ as MSM8960, APQ8064, etc.
+
+config KRAITCC
+ tristate "Krait Clock Controller"
+ depends on COMMON_CLK_QCOM && ARM
+ select KRAIT_CLOCKS
+ help
+ Support for the Krait CPU clocks on Qualcomm devices.
+ Say Y if you want to support CPU frequency scaling.
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index 21a45035930d..981882e16189 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -11,6 +11,8 @@ clk-qcom-y += clk-branch.o
clk-qcom-y += clk-regmap-divider.o
clk-qcom-y += clk-regmap-mux.o
clk-qcom-y += clk-regmap-mux-div.o
+clk-qcom-$(CONFIG_KRAIT_CLOCKS) += clk-krait.o
+clk-qcom-y += clk-hfpll.o
clk-qcom-y += reset.o
clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o
@@ -39,7 +41,13 @@ obj-$(CONFIG_QCOM_CLK_APCS_MSM8916) += apcs-msm8916.o
obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o
obj-$(CONFIG_QCOM_CLK_RPMH) += clk-rpmh.o
obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o
+obj-$(CONFIG_QCS_GCC_404) += gcc-qcs404.o
+obj-$(CONFIG_SDM_CAMCC_845) += camcc-sdm845.o
obj-$(CONFIG_SDM_DISPCC_845) += dispcc-sdm845.o
+obj-$(CONFIG_SDM_GCC_660) += gcc-sdm660.o
obj-$(CONFIG_SDM_GCC_845) += gcc-sdm845.o
obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o
obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o
+obj-$(CONFIG_KPSS_XCC) += kpss-xcc.o
+obj-$(CONFIG_QCOM_HFPLL) += hfpll.o
+obj-$(CONFIG_KRAITCC) += krait-cc.o
diff --git a/drivers/clk/qcom/camcc-sdm845.c b/drivers/clk/qcom/camcc-sdm845.c
new file mode 100644
index 000000000000..1b2cefef7431
--- /dev/null
+++ b/drivers/clk/qcom/camcc-sdm845.c
@@ -0,0 +1,1745 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, 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 <dt-bindings/clock/qcom,camcc-sdm845.h>
+
+#include "common.h"
+#include "clk-alpha-pll.h"
+#include "clk-branch.h"
+#include "clk-rcg.h"
+#include "clk-regmap.h"
+#include "gdsc.h"
+
+enum {
+ P_BI_TCXO,
+ P_CAM_CC_PLL0_OUT_EVEN,
+ P_CAM_CC_PLL1_OUT_EVEN,
+ P_CAM_CC_PLL2_OUT_EVEN,
+ P_CAM_CC_PLL3_OUT_EVEN,
+ P_CORE_BI_PLL_TEST_SE,
+};
+
+static const struct parent_map cam_cc_parent_map_0[] = {
+ { P_BI_TCXO, 0 },
+ { P_CAM_CC_PLL2_OUT_EVEN, 1 },
+ { P_CAM_CC_PLL1_OUT_EVEN, 2 },
+ { P_CAM_CC_PLL3_OUT_EVEN, 5 },
+ { P_CAM_CC_PLL0_OUT_EVEN, 6 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const cam_cc_parent_names_0[] = {
+ "bi_tcxo",
+ "cam_cc_pll2_out_even",
+ "cam_cc_pll1_out_even",
+ "cam_cc_pll3_out_even",
+ "cam_cc_pll0_out_even",
+ "core_bi_pll_test_se",
+};
+
+static struct clk_alpha_pll cam_cc_pll0 = {
+ .offset = 0x0,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_pll0",
+ .parent_names = (const char *[]){ "bi_tcxo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fabia_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_fabia_even[] = {
+ { 0x0, 1 },
+ { 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_fabia_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_fabia_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_pll0_out_even",
+ .parent_names = (const char *[]){ "cam_cc_pll0" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_fabia_ops,
+ },
+};
+
+static struct clk_alpha_pll cam_cc_pll1 = {
+ .offset = 0x1000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_pll1",
+ .parent_names = (const char *[]){ "bi_tcxo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fabia_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll_postdiv cam_cc_pll1_out_even = {
+ .offset = 0x1000,
+ .post_div_shift = 8,
+ .post_div_table = post_div_table_fabia_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_fabia_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_pll1_out_even",
+ .parent_names = (const char *[]){ "cam_cc_pll1" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_fabia_ops,
+ },
+};
+
+static struct clk_alpha_pll cam_cc_pll2 = {
+ .offset = 0x2000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_pll2",
+ .parent_names = (const char *[]){ "bi_tcxo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fabia_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll_postdiv cam_cc_pll2_out_even = {
+ .offset = 0x2000,
+ .post_div_shift = 8,
+ .post_div_table = post_div_table_fabia_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_fabia_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_pll2_out_even",
+ .parent_names = (const char *[]){ "cam_cc_pll2" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_fabia_ops,
+ },
+};
+
+static struct clk_alpha_pll cam_cc_pll3 = {
+ .offset = 0x3000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_pll3",
+ .parent_names = (const char *[]){ "bi_tcxo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fabia_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll_postdiv cam_cc_pll3_out_even = {
+ .offset = 0x3000,
+ .post_div_shift = 8,
+ .post_div_table = post_div_table_fabia_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_fabia_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_pll3_out_even",
+ .parent_names = (const char *[]){ "cam_cc_pll3" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_fabia_ops,
+ },
+};
+
+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_EVEN, 3, 0, 0),
+ F(404000000, P_CAM_CC_PLL1_OUT_EVEN, 2, 0, 0),
+ F(480000000, P_CAM_CC_PLL2_OUT_EVEN, 1, 0, 0),
+ F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0),
+ { }
+};
+
+/*
+ * As per HW design, some of the CAMCC RCGs needs to
+ * move to XO clock during their clock disable so using
+ * clk_rcg2_shared_ops for such RCGs. This is required
+ * to power down the camera memories gracefully.
+ * Also, use CLK_SET_RATE_PARENT flag for the RCGs which
+ * have CAM_CC_PLL2_OUT_EVEN PLL as parent in frequency
+ * table and requires reconfiguration of the PLL frequency.
+ */
+static struct clk_rcg2 cam_cc_bps_clk_src = {
+ .cmd_rcgr = 0x600c,
+ .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_names = cam_cc_parent_names_0,
+ .num_parents = 6,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_cci_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(37500000, P_CAM_CC_PLL0_OUT_EVEN, 16, 0, 0),
+ F(50000000, P_CAM_CC_PLL0_OUT_EVEN, 12, 0, 0),
+ F(100000000, P_CAM_CC_PLL0_OUT_EVEN, 6, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_cci_clk_src = {
+ .cmd_rcgr = 0xb0d8,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_cci_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_cci_clk_src",
+ .parent_names = cam_cc_parent_names_0,
+ .num_parents = 6,
+ .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(384000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_cphy_rx_clk_src = {
+ .cmd_rcgr = 0x9060,
+ .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_names = cam_cc_parent_names_0,
+ .num_parents = 6,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_csi0phytimer_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(240000000, P_CAM_CC_PLL2_OUT_EVEN, 2, 0, 0),
+ F(269333333, P_CAM_CC_PLL1_OUT_EVEN, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_csi0phytimer_clk_src = {
+ .cmd_rcgr = 0x5004,
+ .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_names = cam_cc_parent_names_0,
+ .num_parents = 6,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_csi1phytimer_clk_src = {
+ .cmd_rcgr = 0x5028,
+ .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_names = cam_cc_parent_names_0,
+ .num_parents = 6,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_csi2phytimer_clk_src = {
+ .cmd_rcgr = 0x504c,
+ .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_names = cam_cc_parent_names_0,
+ .num_parents = 6,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_csi3phytimer_clk_src = {
+ .cmd_rcgr = 0x5070,
+ .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_names = cam_cc_parent_names_0,
+ .num_parents = 6,
+ .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_EVEN, 2, 0, 0),
+ F(400000000, P_CAM_CC_PLL0_OUT_EVEN, 1.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_fast_ahb_clk_src = {
+ .cmd_rcgr = 0x6038,
+ .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_names = cam_cc_parent_names_0,
+ .num_parents = 6,
+ .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(384000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0),
+ F(400000000, P_CAM_CC_PLL0_OUT_EVEN, 1.5, 0, 0),
+ F(538666667, P_CAM_CC_PLL1_OUT_EVEN, 1.5, 0, 0),
+ F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_fd_core_clk_src = {
+ .cmd_rcgr = 0xb0b0,
+ .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_names = cam_cc_parent_names_0,
+ .num_parents = 6,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_icp_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(384000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0),
+ F(400000000, P_CAM_CC_PLL0_OUT_EVEN, 1.5, 0, 0),
+ F(538666667, P_CAM_CC_PLL1_OUT_EVEN, 1.5, 0, 0),
+ F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_icp_clk_src = {
+ .cmd_rcgr = 0xb088,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_icp_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_icp_clk_src",
+ .parent_names = cam_cc_parent_names_0,
+ .num_parents = 6,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_ife_0_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(100000000, P_CAM_CC_PLL0_OUT_EVEN, 6, 0, 0),
+ F(320000000, P_CAM_CC_PLL2_OUT_EVEN, 1.5, 0, 0),
+ F(404000000, P_CAM_CC_PLL1_OUT_EVEN, 2, 0, 0),
+ F(480000000, P_CAM_CC_PLL2_OUT_EVEN, 1, 0, 0),
+ F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_ife_0_clk_src = {
+ .cmd_rcgr = 0x900c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_ife_0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_0_clk_src",
+ .parent_names = cam_cc_parent_names_0,
+ .num_parents = 6,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_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(384000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0),
+ F(538666667, P_CAM_CC_PLL1_OUT_EVEN, 1.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_ife_0_csid_clk_src = {
+ .cmd_rcgr = 0x9038,
+ .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_names = cam_cc_parent_names_0,
+ .num_parents = 6,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_ife_1_clk_src = {
+ .cmd_rcgr = 0xa00c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_ife_0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_1_clk_src",
+ .parent_names = cam_cc_parent_names_0,
+ .num_parents = 6,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_ife_1_csid_clk_src = {
+ .cmd_rcgr = 0xa030,
+ .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_names = cam_cc_parent_names_0,
+ .num_parents = 6,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_ife_lite_clk_src = {
+ .cmd_rcgr = 0xb004,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_ife_0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_lite_clk_src",
+ .parent_names = cam_cc_parent_names_0,
+ .num_parents = 6,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_ife_lite_csid_clk_src = {
+ .cmd_rcgr = 0xb024,
+ .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_lite_csid_clk_src",
+ .parent_names = cam_cc_parent_names_0,
+ .num_parents = 6,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_ipe_0_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(100000000, P_CAM_CC_PLL0_OUT_EVEN, 6, 0, 0),
+ F(240000000, P_CAM_CC_PLL0_OUT_EVEN, 2.5, 0, 0),
+ F(404000000, P_CAM_CC_PLL1_OUT_EVEN, 2, 0, 0),
+ F(480000000, P_CAM_CC_PLL2_OUT_EVEN, 1, 0, 0),
+ F(538666667, P_CAM_CC_PLL1_OUT_EVEN, 1.5, 0, 0),
+ F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_ipe_0_clk_src = {
+ .cmd_rcgr = 0x700c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_ipe_0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ipe_0_clk_src",
+ .parent_names = cam_cc_parent_names_0,
+ .num_parents = 6,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_ipe_1_clk_src = {
+ .cmd_rcgr = 0x800c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_ipe_0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ipe_1_clk_src",
+ .parent_names = cam_cc_parent_names_0,
+ .num_parents = 6,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_jpeg_clk_src = {
+ .cmd_rcgr = 0xb04c,
+ .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_names = cam_cc_parent_names_0,
+ .num_parents = 6,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_lrme_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_EVEN, 3, 0, 0),
+ F(269333333, P_CAM_CC_PLL1_OUT_EVEN, 3, 0, 0),
+ F(320000000, P_CAM_CC_PLL2_OUT_EVEN, 1.5, 0, 0),
+ F(400000000, P_CAM_CC_PLL0_OUT_EVEN, 1.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_lrme_clk_src = {
+ .cmd_rcgr = 0xb0f8,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_lrme_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_lrme_clk_src",
+ .parent_names = cam_cc_parent_names_0,
+ .num_parents = 6,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_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_EVEN, 10, 1, 2),
+ F(33333333, P_CAM_CC_PLL0_OUT_EVEN, 2, 1, 9),
+ F(34285714, P_CAM_CC_PLL2_OUT_EVEN, 14, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_mclk0_clk_src = {
+ .cmd_rcgr = 0x4004,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_mclk0_clk_src",
+ .parent_names = cam_cc_parent_names_0,
+ .num_parents = 6,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_mclk1_clk_src = {
+ .cmd_rcgr = 0x4024,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_mclk1_clk_src",
+ .parent_names = cam_cc_parent_names_0,
+ .num_parents = 6,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_mclk2_clk_src = {
+ .cmd_rcgr = 0x4044,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_mclk2_clk_src",
+ .parent_names = cam_cc_parent_names_0,
+ .num_parents = 6,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_mclk3_clk_src = {
+ .cmd_rcgr = 0x4064,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_mclk3_clk_src",
+ .parent_names = cam_cc_parent_names_0,
+ .num_parents = 6,
+ .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(60000000, P_CAM_CC_PLL0_OUT_EVEN, 10, 0, 0),
+ F(66666667, P_CAM_CC_PLL0_OUT_EVEN, 9, 0, 0),
+ F(73846154, P_CAM_CC_PLL2_OUT_EVEN, 6.5, 0, 0),
+ F(80000000, P_CAM_CC_PLL2_OUT_EVEN, 6, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_slow_ahb_clk_src = {
+ .cmd_rcgr = 0x6054,
+ .mnd_width = 0,
+ .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_names = cam_cc_parent_names_0,
+ .num_parents = 6,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_branch cam_cc_bps_ahb_clk = {
+ .halt_reg = 0x606c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x606c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_bps_ahb_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_slow_ahb_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_bps_areg_clk = {
+ .halt_reg = 0x6050,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x6050,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_bps_areg_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_fast_ahb_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_bps_axi_clk = {
+ .halt_reg = 0x6034,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x6034,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_bps_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_bps_clk = {
+ .halt_reg = 0x6024,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x6024,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_bps_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_bps_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_camnoc_atb_clk = {
+ .halt_reg = 0xb12c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb12c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_camnoc_atb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_camnoc_axi_clk = {
+ .halt_reg = 0xb124,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb124,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_camnoc_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_cci_clk = {
+ .halt_reg = 0xb0f0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb0f0,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_cci_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_cci_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_cpas_ahb_clk = {
+ .halt_reg = 0xb11c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb11c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_cpas_ahb_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_slow_ahb_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csi0phytimer_clk = {
+ .halt_reg = 0x501c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x501c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_csi0phytimer_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_csi0phytimer_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csi1phytimer_clk = {
+ .halt_reg = 0x5040,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5040,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_csi1phytimer_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_csi1phytimer_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csi2phytimer_clk = {
+ .halt_reg = 0x5064,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5064,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_csi2phytimer_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_csi2phytimer_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csi3phytimer_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_csi3phytimer_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_csi3phytimer_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csiphy0_clk = {
+ .halt_reg = 0x5020,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5020,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_csiphy0_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_cphy_rx_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csiphy1_clk = {
+ .halt_reg = 0x5044,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5044,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_csiphy1_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_cphy_rx_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csiphy2_clk = {
+ .halt_reg = 0x5068,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5068,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_csiphy2_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_cphy_rx_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csiphy3_clk = {
+ .halt_reg = 0x508c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x508c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_csiphy3_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_cphy_rx_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_fd_core_clk = {
+ .halt_reg = 0xb0c8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb0c8,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_fd_core_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_fd_core_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_fd_core_uar_clk = {
+ .halt_reg = 0xb0d0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb0d0,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_fd_core_uar_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_fd_core_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_icp_apb_clk = {
+ .halt_reg = 0xb084,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb084,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_icp_apb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_icp_atb_clk = {
+ .halt_reg = 0xb078,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb078,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_icp_atb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_icp_clk = {
+ .halt_reg = 0xb0a0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb0a0,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_icp_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_icp_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_icp_cti_clk = {
+ .halt_reg = 0xb07c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb07c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_icp_cti_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_icp_ts_clk = {
+ .halt_reg = 0xb080,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb080,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_icp_ts_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_0_axi_clk = {
+ .halt_reg = 0x907c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x907c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_0_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_0_clk = {
+ .halt_reg = 0x9024,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x9024,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_0_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_ife_0_clk_src",
+ },
+ .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 = 0x9078,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x9078,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_0_cphy_rx_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_cphy_rx_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_0_csid_clk = {
+ .halt_reg = 0x9050,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x9050,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_0_csid_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_ife_0_csid_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_0_dsp_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_ife_0_dsp_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_ife_0_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_1_axi_clk = {
+ .halt_reg = 0xa054,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa054,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_1_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_1_clk = {
+ .halt_reg = 0xa024,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa024,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_1_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_ife_1_clk_src",
+ },
+ .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 = 0xa050,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa050,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_1_cphy_rx_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_cphy_rx_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_1_csid_clk = {
+ .halt_reg = 0xa048,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa048,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_1_csid_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_ife_1_csid_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_1_dsp_clk = {
+ .halt_reg = 0xa02c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa02c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_1_dsp_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_ife_1_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_lite_clk = {
+ .halt_reg = 0xb01c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb01c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_lite_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_ife_lite_clk_src",
+ },
+ .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 = 0xb044,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb044,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_lite_cphy_rx_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_cphy_rx_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_lite_csid_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_lite_csid_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_ife_lite_csid_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ipe_0_ahb_clk = {
+ .halt_reg = 0x703c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x703c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ipe_0_ahb_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_slow_ahb_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ipe_0_areg_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_ipe_0_areg_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_fast_ahb_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ipe_0_axi_clk = {
+ .halt_reg = 0x7034,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x7034,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ipe_0_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ipe_0_clk = {
+ .halt_reg = 0x7024,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x7024,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ipe_0_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_ipe_0_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ipe_1_ahb_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_1_ahb_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_slow_ahb_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ipe_1_areg_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_1_areg_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_fast_ahb_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ipe_1_axi_clk = {
+ .halt_reg = 0x8034,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8034,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ipe_1_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ipe_1_clk = {
+ .halt_reg = 0x8024,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8024,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ipe_1_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_ipe_1_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_jpeg_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_jpeg_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_jpeg_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_lrme_clk = {
+ .halt_reg = 0xb110,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb110,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_lrme_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_lrme_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_mclk0_clk = {
+ .halt_reg = 0x401c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x401c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_mclk0_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_mclk0_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_mclk1_clk = {
+ .halt_reg = 0x403c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x403c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_mclk1_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_mclk1_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_mclk2_clk = {
+ .halt_reg = 0x405c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x405c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_mclk2_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_mclk2_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_mclk3_clk = {
+ .halt_reg = 0x407c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x407c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_mclk3_clk",
+ .parent_names = (const char *[]){
+ "cam_cc_mclk3_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_soc_ahb_clk = {
+ .halt_reg = 0xb13c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb13c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_soc_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_sys_tmr_clk = {
+ .halt_reg = 0xb0a8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb0a8,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_sys_tmr_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct gdsc bps_gdsc = {
+ .gdscr = 0x6004,
+ .pd = {
+ .name = "bps_gdsc",
+ },
+ .flags = HW_CTRL | POLL_CFG_GDSCR,
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc ipe_0_gdsc = {
+ .gdscr = 0x7004,
+ .pd = {
+ .name = "ipe_0_gdsc",
+ },
+ .flags = HW_CTRL | POLL_CFG_GDSCR,
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc ipe_1_gdsc = {
+ .gdscr = 0x8004,
+ .pd = {
+ .name = "ipe_1_gdsc",
+ },
+ .flags = HW_CTRL | POLL_CFG_GDSCR,
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc ife_0_gdsc = {
+ .gdscr = 0x9004,
+ .pd = {
+ .name = "ife_0_gdsc",
+ },
+ .flags = POLL_CFG_GDSCR,
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc ife_1_gdsc = {
+ .gdscr = 0xa004,
+ .pd = {
+ .name = "ife_1_gdsc",
+ },
+ .flags = POLL_CFG_GDSCR,
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc titan_top_gdsc = {
+ .gdscr = 0xb134,
+ .pd = {
+ .name = "titan_top_gdsc",
+ },
+ .flags = POLL_CFG_GDSCR,
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct clk_regmap *cam_cc_sdm845_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_ATB_CLK] = &cam_cc_camnoc_atb_clk.clkr,
+ [CAM_CC_CAMNOC_AXI_CLK] = &cam_cc_camnoc_axi_clk.clkr,
+ [CAM_CC_CCI_CLK] = &cam_cc_cci_clk.clkr,
+ [CAM_CC_CCI_CLK_SRC] = &cam_cc_cci_clk_src.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_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_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_ICP_APB_CLK] = &cam_cc_icp_apb_clk.clkr,
+ [CAM_CC_ICP_ATB_CLK] = &cam_cc_icp_atb_clk.clkr,
+ [CAM_CC_ICP_CLK] = &cam_cc_icp_clk.clkr,
+ [CAM_CC_ICP_CLK_SRC] = &cam_cc_icp_clk_src.clkr,
+ [CAM_CC_ICP_CTI_CLK] = &cam_cc_icp_cti_clk.clkr,
+ [CAM_CC_ICP_TS_CLK] = &cam_cc_icp_ts_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_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_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_IPE_1_AHB_CLK] = &cam_cc_ipe_1_ahb_clk.clkr,
+ [CAM_CC_IPE_1_AREG_CLK] = &cam_cc_ipe_1_areg_clk.clkr,
+ [CAM_CC_IPE_1_AXI_CLK] = &cam_cc_ipe_1_axi_clk.clkr,
+ [CAM_CC_IPE_1_CLK] = &cam_cc_ipe_1_clk.clkr,
+ [CAM_CC_IPE_1_CLK_SRC] = &cam_cc_ipe_1_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_LRME_CLK] = &cam_cc_lrme_clk.clkr,
+ [CAM_CC_LRME_CLK_SRC] = &cam_cc_lrme_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_PLL0] = &cam_cc_pll0.clkr,
+ [CAM_CC_PLL0_OUT_EVEN] = &cam_cc_pll0_out_even.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_EVEN] = &cam_cc_pll2_out_even.clkr,
+ [CAM_CC_PLL3] = &cam_cc_pll3.clkr,
+ [CAM_CC_PLL3_OUT_EVEN] = &cam_cc_pll3_out_even.clkr,
+ [CAM_CC_SLOW_AHB_CLK_SRC] = &cam_cc_slow_ahb_clk_src.clkr,
+ [CAM_CC_SOC_AHB_CLK] = &cam_cc_soc_ahb_clk.clkr,
+ [CAM_CC_SYS_TMR_CLK] = &cam_cc_sys_tmr_clk.clkr,
+};
+
+static struct gdsc *cam_cc_sdm845_gdscs[] = {
+ [BPS_GDSC] = &bps_gdsc,
+ [IPE_0_GDSC] = &ipe_0_gdsc,
+ [IPE_1_GDSC] = &ipe_1_gdsc,
+ [IFE_0_GDSC] = &ife_0_gdsc,
+ [IFE_1_GDSC] = &ife_1_gdsc,
+ [TITAN_TOP_GDSC] = &titan_top_gdsc,
+};
+
+static const struct regmap_config cam_cc_sdm845_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0xd004,
+ .fast_io = true,
+};
+
+static const struct qcom_cc_desc cam_cc_sdm845_desc = {
+ .config = &cam_cc_sdm845_regmap_config,
+ .clks = cam_cc_sdm845_clocks,
+ .num_clks = ARRAY_SIZE(cam_cc_sdm845_clocks),
+ .gdscs = cam_cc_sdm845_gdscs,
+ .num_gdscs = ARRAY_SIZE(cam_cc_sdm845_gdscs),
+};
+
+static const struct of_device_id cam_cc_sdm845_match_table[] = {
+ { .compatible = "qcom,sdm845-camcc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, cam_cc_sdm845_match_table);
+
+static int cam_cc_sdm845_probe(struct platform_device *pdev)
+{
+ struct regmap *regmap;
+ struct alpha_pll_config cam_cc_pll_config = { };
+
+ regmap = qcom_cc_map(pdev, &cam_cc_sdm845_desc);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ cam_cc_pll_config.l = 0x1f;
+ cam_cc_pll_config.alpha = 0x4000;
+ clk_fabia_pll_configure(&cam_cc_pll0, regmap, &cam_cc_pll_config);
+
+ cam_cc_pll_config.l = 0x2a;
+ cam_cc_pll_config.alpha = 0x1556;
+ clk_fabia_pll_configure(&cam_cc_pll1, regmap, &cam_cc_pll_config);
+
+ cam_cc_pll_config.l = 0x32;
+ cam_cc_pll_config.alpha = 0x0;
+ clk_fabia_pll_configure(&cam_cc_pll2, regmap, &cam_cc_pll_config);
+
+ cam_cc_pll_config.l = 0x14;
+ clk_fabia_pll_configure(&cam_cc_pll3, regmap, &cam_cc_pll_config);
+
+ return qcom_cc_really_probe(pdev, &cam_cc_sdm845_desc, regmap);
+}
+
+static struct platform_driver cam_cc_sdm845_driver = {
+ .probe = cam_cc_sdm845_probe,
+ .driver = {
+ .name = "sdm845-camcc",
+ .of_match_table = cam_cc_sdm845_match_table,
+ },
+};
+
+static int __init cam_cc_sdm845_init(void)
+{
+ return platform_driver_register(&cam_cc_sdm845_driver);
+}
+subsys_initcall(cam_cc_sdm845_init);
+
+static void __exit cam_cc_sdm845_exit(void)
+{
+ platform_driver_unregister(&cam_cc_sdm845_driver);
+}
+module_exit(cam_cc_sdm845_exit);
+
+MODULE_DESCRIPTION("QTI CAM_CC SDM845 Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c
index a91d97cecbad..0ced4a5a9a17 100644
--- a/drivers/clk/qcom/clk-alpha-pll.c
+++ b/drivers/clk/qcom/clk-alpha-pll.c
@@ -220,6 +220,7 @@ void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
if (pll->flags & SUPPORTS_FSM_MODE)
qcom_pll_set_fsm_mode(regmap, PLL_MODE(pll), 6, 0);
}
+EXPORT_SYMBOL_GPL(clk_alpha_pll_configure);
static int clk_alpha_pll_hwfsm_enable(struct clk_hw *hw)
{
diff --git a/drivers/clk/qcom/clk-branch.c b/drivers/clk/qcom/clk-branch.c
index bc2205c450b6..99446bf630aa 100644
--- a/drivers/clk/qcom/clk-branch.c
+++ b/drivers/clk/qcom/clk-branch.c
@@ -18,7 +18,7 @@ static bool clk_branch_in_hwcg_mode(const struct clk_branch *br)
u32 val;
if (!br->hwcg_reg)
- return 0;
+ return false;
regmap_read(br->clkr.regmap, br->hwcg_reg, &val);
diff --git a/drivers/clk/qcom/clk-hfpll.c b/drivers/clk/qcom/clk-hfpll.c
new file mode 100644
index 000000000000..3c04805f2a55
--- /dev/null
+++ b/drivers/clk/qcom/clk-hfpll.c
@@ -0,0 +1,244 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018, The Linux Foundation. All rights reserved.
+
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/clk-provider.h>
+#include <linux/spinlock.h>
+
+#include "clk-regmap.h"
+#include "clk-hfpll.h"
+
+#define PLL_OUTCTRL BIT(0)
+#define PLL_BYPASSNL BIT(1)
+#define PLL_RESET_N BIT(2)
+
+/* Initialize a HFPLL at a given rate and enable it. */
+static void __clk_hfpll_init_once(struct clk_hw *hw)
+{
+ struct clk_hfpll *h = to_clk_hfpll(hw);
+ struct hfpll_data const *hd = h->d;
+ struct regmap *regmap = h->clkr.regmap;
+
+ if (likely(h->init_done))
+ return;
+
+ /* Configure PLL parameters for integer mode. */
+ if (hd->config_val)
+ regmap_write(regmap, hd->config_reg, hd->config_val);
+ regmap_write(regmap, hd->m_reg, 0);
+ regmap_write(regmap, hd->n_reg, 1);
+
+ if (hd->user_reg) {
+ u32 regval = hd->user_val;
+ unsigned long rate;
+
+ rate = clk_hw_get_rate(hw);
+
+ /* Pick the right VCO. */
+ if (hd->user_vco_mask && rate > hd->low_vco_max_rate)
+ regval |= hd->user_vco_mask;
+ regmap_write(regmap, hd->user_reg, regval);
+ }
+
+ if (hd->droop_reg)
+ regmap_write(regmap, hd->droop_reg, hd->droop_val);
+
+ h->init_done = true;
+}
+
+static void __clk_hfpll_enable(struct clk_hw *hw)
+{
+ struct clk_hfpll *h = to_clk_hfpll(hw);
+ struct hfpll_data const *hd = h->d;
+ struct regmap *regmap = h->clkr.regmap;
+ u32 val;
+
+ __clk_hfpll_init_once(hw);
+
+ /* Disable PLL bypass mode. */
+ regmap_update_bits(regmap, hd->mode_reg, PLL_BYPASSNL, PLL_BYPASSNL);
+
+ /*
+ * H/W requires a 5us delay between disabling the bypass and
+ * de-asserting the reset. Delay 10us just to be safe.
+ */
+ udelay(10);
+
+ /* De-assert active-low PLL reset. */
+ regmap_update_bits(regmap, hd->mode_reg, PLL_RESET_N, PLL_RESET_N);
+
+ /* Wait for PLL to lock. */
+ if (hd->status_reg) {
+ do {
+ regmap_read(regmap, hd->status_reg, &val);
+ } while (!(val & BIT(hd->lock_bit)));
+ } else {
+ udelay(60);
+ }
+
+ /* Enable PLL output. */
+ regmap_update_bits(regmap, hd->mode_reg, PLL_OUTCTRL, PLL_OUTCTRL);
+}
+
+/* Enable an already-configured HFPLL. */
+static int clk_hfpll_enable(struct clk_hw *hw)
+{
+ unsigned long flags;
+ struct clk_hfpll *h = to_clk_hfpll(hw);
+ struct hfpll_data const *hd = h->d;
+ struct regmap *regmap = h->clkr.regmap;
+ u32 mode;
+
+ spin_lock_irqsave(&h->lock, flags);
+ regmap_read(regmap, hd->mode_reg, &mode);
+ if (!(mode & (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL)))
+ __clk_hfpll_enable(hw);
+ spin_unlock_irqrestore(&h->lock, flags);
+
+ return 0;
+}
+
+static void __clk_hfpll_disable(struct clk_hfpll *h)
+{
+ struct hfpll_data const *hd = h->d;
+ struct regmap *regmap = h->clkr.regmap;
+
+ /*
+ * Disable the PLL output, disable test mode, enable the bypass mode,
+ * and assert the reset.
+ */
+ regmap_update_bits(regmap, hd->mode_reg,
+ PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL, 0);
+}
+
+static void clk_hfpll_disable(struct clk_hw *hw)
+{
+ struct clk_hfpll *h = to_clk_hfpll(hw);
+ unsigned long flags;
+
+ spin_lock_irqsave(&h->lock, flags);
+ __clk_hfpll_disable(h);
+ spin_unlock_irqrestore(&h->lock, flags);
+}
+
+static long clk_hfpll_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct clk_hfpll *h = to_clk_hfpll(hw);
+ struct hfpll_data const *hd = h->d;
+ unsigned long rrate;
+
+ rate = clamp(rate, hd->min_rate, hd->max_rate);
+
+ rrate = DIV_ROUND_UP(rate, *parent_rate) * *parent_rate;
+ if (rrate > hd->max_rate)
+ rrate -= *parent_rate;
+
+ return rrate;
+}
+
+/*
+ * For optimization reasons, assumes no downstream clocks are actively using
+ * it.
+ */
+static int clk_hfpll_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_hfpll *h = to_clk_hfpll(hw);
+ struct hfpll_data const *hd = h->d;
+ struct regmap *regmap = h->clkr.regmap;
+ unsigned long flags;
+ u32 l_val, val;
+ bool enabled;
+
+ l_val = rate / parent_rate;
+
+ spin_lock_irqsave(&h->lock, flags);
+
+ enabled = __clk_is_enabled(hw->clk);
+ if (enabled)
+ __clk_hfpll_disable(h);
+
+ /* Pick the right VCO. */
+ if (hd->user_reg && hd->user_vco_mask) {
+ regmap_read(regmap, hd->user_reg, &val);
+ if (rate <= hd->low_vco_max_rate)
+ val &= ~hd->user_vco_mask;
+ else
+ val |= hd->user_vco_mask;
+ regmap_write(regmap, hd->user_reg, val);
+ }
+
+ regmap_write(regmap, hd->l_reg, l_val);
+
+ if (enabled)
+ __clk_hfpll_enable(hw);
+
+ spin_unlock_irqrestore(&h->lock, flags);
+
+ return 0;
+}
+
+static unsigned long clk_hfpll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_hfpll *h = to_clk_hfpll(hw);
+ struct hfpll_data const *hd = h->d;
+ struct regmap *regmap = h->clkr.regmap;
+ u32 l_val;
+
+ regmap_read(regmap, hd->l_reg, &l_val);
+
+ return l_val * parent_rate;
+}
+
+static void clk_hfpll_init(struct clk_hw *hw)
+{
+ struct clk_hfpll *h = to_clk_hfpll(hw);
+ struct hfpll_data const *hd = h->d;
+ struct regmap *regmap = h->clkr.regmap;
+ u32 mode, status;
+
+ regmap_read(regmap, hd->mode_reg, &mode);
+ if (mode != (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL)) {
+ __clk_hfpll_init_once(hw);
+ return;
+ }
+
+ if (hd->status_reg) {
+ regmap_read(regmap, hd->status_reg, &status);
+ if (!(status & BIT(hd->lock_bit))) {
+ WARN(1, "HFPLL %s is ON, but not locked!\n",
+ __clk_get_name(hw->clk));
+ clk_hfpll_disable(hw);
+ __clk_hfpll_init_once(hw);
+ }
+ }
+}
+
+static int hfpll_is_enabled(struct clk_hw *hw)
+{
+ struct clk_hfpll *h = to_clk_hfpll(hw);
+ struct hfpll_data const *hd = h->d;
+ struct regmap *regmap = h->clkr.regmap;
+ u32 mode;
+
+ regmap_read(regmap, hd->mode_reg, &mode);
+ mode &= 0x7;
+ return mode == (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL);
+}
+
+const struct clk_ops clk_ops_hfpll = {
+ .enable = clk_hfpll_enable,
+ .disable = clk_hfpll_disable,
+ .is_enabled = hfpll_is_enabled,
+ .round_rate = clk_hfpll_round_rate,
+ .set_rate = clk_hfpll_set_rate,
+ .recalc_rate = clk_hfpll_recalc_rate,
+ .init = clk_hfpll_init,
+};
+EXPORT_SYMBOL_GPL(clk_ops_hfpll);
diff --git a/drivers/clk/qcom/clk-hfpll.h b/drivers/clk/qcom/clk-hfpll.h
new file mode 100644
index 000000000000..2a57b2fb2f2f
--- /dev/null
+++ b/drivers/clk/qcom/clk-hfpll.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __QCOM_CLK_HFPLL_H__
+#define __QCOM_CLK_HFPLL_H__
+
+#include <linux/clk-provider.h>
+#include <linux/spinlock.h>
+#include "clk-regmap.h"
+
+struct hfpll_data {
+ u32 mode_reg;
+ u32 l_reg;
+ u32 m_reg;
+ u32 n_reg;
+ u32 user_reg;
+ u32 droop_reg;
+ u32 config_reg;
+ u32 status_reg;
+ u8 lock_bit;
+
+ u32 droop_val;
+ u32 config_val;
+ u32 user_val;
+ u32 user_vco_mask;
+ unsigned long low_vco_max_rate;
+
+ unsigned long min_rate;
+ unsigned long max_rate;
+};
+
+struct clk_hfpll {
+ struct hfpll_data const *d;
+ int init_done;
+
+ struct clk_regmap clkr;
+ spinlock_t lock;
+};
+
+#define to_clk_hfpll(_hw) \
+ container_of(to_clk_regmap(_hw), struct clk_hfpll, clkr)
+
+extern const struct clk_ops clk_ops_hfpll;
+
+#endif
diff --git a/drivers/clk/qcom/clk-krait.c b/drivers/clk/qcom/clk-krait.c
new file mode 100644
index 000000000000..59f1af415b58
--- /dev/null
+++ b/drivers/clk/qcom/clk-krait.c
@@ -0,0 +1,126 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018, The Linux Foundation. All rights reserved.
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/clk-provider.h>
+#include <linux/spinlock.h>
+
+#include <asm/krait-l2-accessors.h>
+
+#include "clk-krait.h"
+
+/* Secondary and primary muxes share the same cp15 register */
+static DEFINE_SPINLOCK(krait_clock_reg_lock);
+
+#define LPL_SHIFT 8
+static void __krait_mux_set_sel(struct krait_mux_clk *mux, int sel)
+{
+ unsigned long flags;
+ u32 regval;
+
+ spin_lock_irqsave(&krait_clock_reg_lock, flags);
+ regval = krait_get_l2_indirect_reg(mux->offset);
+ regval &= ~(mux->mask << mux->shift);
+ regval |= (sel & mux->mask) << mux->shift;
+ if (mux->lpl) {
+ regval &= ~(mux->mask << (mux->shift + LPL_SHIFT));
+ regval |= (sel & mux->mask) << (mux->shift + LPL_SHIFT);
+ }
+ krait_set_l2_indirect_reg(mux->offset, regval);
+ spin_unlock_irqrestore(&krait_clock_reg_lock, flags);
+
+ /* Wait for switch to complete. */
+ mb();
+ udelay(1);
+}
+
+static int krait_mux_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct krait_mux_clk *mux = to_krait_mux_clk(hw);
+ u32 sel;
+
+ sel = clk_mux_index_to_val(mux->parent_map, 0, index);
+ mux->en_mask = sel;
+ /* Don't touch mux if CPU is off as it won't work */
+ if (__clk_is_enabled(hw->clk))
+ __krait_mux_set_sel(mux, sel);
+
+ mux->reparent = true;
+
+ return 0;
+}
+
+static u8 krait_mux_get_parent(struct clk_hw *hw)
+{
+ struct krait_mux_clk *mux = to_krait_mux_clk(hw);
+ u32 sel;
+
+ sel = krait_get_l2_indirect_reg(mux->offset);
+ sel >>= mux->shift;
+ sel &= mux->mask;
+ mux->en_mask = sel;
+
+ return clk_mux_val_to_index(hw, mux->parent_map, 0, sel);
+}
+
+const struct clk_ops krait_mux_clk_ops = {
+ .set_parent = krait_mux_set_parent,
+ .get_parent = krait_mux_get_parent,
+ .determine_rate = __clk_mux_determine_rate_closest,
+};
+EXPORT_SYMBOL_GPL(krait_mux_clk_ops);
+
+/* The divider can divide by 2, 4, 6 and 8. But we only really need div-2. */
+static long krait_div2_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ *parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), rate * 2);
+ return DIV_ROUND_UP(*parent_rate, 2);
+}
+
+static int krait_div2_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct krait_div2_clk *d = to_krait_div2_clk(hw);
+ unsigned long flags;
+ u32 val;
+ u32 mask = BIT(d->width) - 1;
+
+ if (d->lpl)
+ mask = mask << (d->shift + LPL_SHIFT) | mask << d->shift;
+
+ spin_lock_irqsave(&krait_clock_reg_lock, flags);
+ val = krait_get_l2_indirect_reg(d->offset);
+ val &= ~mask;
+ krait_set_l2_indirect_reg(d->offset, val);
+ spin_unlock_irqrestore(&krait_clock_reg_lock, flags);
+
+ return 0;
+}
+
+static unsigned long
+krait_div2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+ struct krait_div2_clk *d = to_krait_div2_clk(hw);
+ u32 mask = BIT(d->width) - 1;
+ u32 div;
+
+ div = krait_get_l2_indirect_reg(d->offset);
+ div >>= d->shift;
+ div &= mask;
+ div = (div + 1) * 2;
+
+ return DIV_ROUND_UP(parent_rate, div);
+}
+
+const struct clk_ops krait_div2_clk_ops = {
+ .round_rate = krait_div2_round_rate,
+ .set_rate = krait_div2_set_rate,
+ .recalc_rate = krait_div2_recalc_rate,
+};
+EXPORT_SYMBOL_GPL(krait_div2_clk_ops);
diff --git a/drivers/clk/qcom/clk-krait.h b/drivers/clk/qcom/clk-krait.h
new file mode 100644
index 000000000000..9120bd2f5297
--- /dev/null
+++ b/drivers/clk/qcom/clk-krait.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __QCOM_CLK_KRAIT_H
+#define __QCOM_CLK_KRAIT_H
+
+#include <linux/clk-provider.h>
+
+struct krait_mux_clk {
+ unsigned int *parent_map;
+ u32 offset;
+ u32 mask;
+ u32 shift;
+ u32 en_mask;
+ bool lpl;
+ u8 safe_sel;
+ u8 old_index;
+ bool reparent;
+
+ struct clk_hw hw;
+ struct notifier_block clk_nb;
+};
+
+#define to_krait_mux_clk(_hw) container_of(_hw, struct krait_mux_clk, hw)
+
+extern const struct clk_ops krait_mux_clk_ops;
+
+struct krait_div2_clk {
+ u32 offset;
+ u8 width;
+ u32 shift;
+ bool lpl;
+
+ struct clk_hw hw;
+};
+
+#define to_krait_div2_clk(_hw) container_of(_hw, struct krait_div2_clk, hw)
+
+extern const struct clk_ops krait_div2_clk_ops;
+
+#endif
diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h
index dbd5a9e83554..e5eca8a1abe4 100644
--- a/drivers/clk/qcom/clk-rcg.h
+++ b/drivers/clk/qcom/clk-rcg.h
@@ -163,4 +163,15 @@ extern const struct clk_ops clk_pixel_ops;
extern const struct clk_ops clk_gfx3d_ops;
extern const struct clk_ops clk_rcg2_shared_ops;
+struct clk_rcg_dfs_data {
+ struct clk_rcg2 *rcg;
+ struct clk_init_data *init;
+};
+
+#define DEFINE_RCG_DFS(r) \
+ { .rcg = &r##_src, .init = &r##_init }
+
+extern int qcom_cc_register_rcg_dfs(struct regmap *regmap,
+ const struct clk_rcg_dfs_data *rcgs,
+ size_t len);
#endif
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index 52208d4165f4..6e3bd195d012 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -12,6 +12,7 @@
#include <linux/delay.h>
#include <linux/regmap.h>
#include <linux/math64.h>
+#include <linux/slab.h>
#include <asm/div64.h>
@@ -40,6 +41,14 @@
#define N_REG 0xc
#define D_REG 0x10
+/* Dynamic Frequency Scaling */
+#define MAX_PERF_LEVEL 8
+#define SE_CMD_DFSR_OFFSET 0x14
+#define SE_CMD_DFS_EN BIT(0)
+#define SE_PERF_DFSR(level) (0x1c + 0x4 * (level))
+#define SE_PERF_M_DFSR(level) (0x5c + 0x4 * (level))
+#define SE_PERF_N_DFSR(level) (0x9c + 0x4 * (level))
+
enum freq_policy {
FLOOR,
CEIL,
@@ -929,3 +938,189 @@ const struct clk_ops clk_rcg2_shared_ops = {
.set_rate_and_parent = clk_rcg2_shared_set_rate_and_parent,
};
EXPORT_SYMBOL_GPL(clk_rcg2_shared_ops);
+
+/* Common APIs to be used for DFS based RCGR */
+static void clk_rcg2_dfs_populate_freq(struct clk_hw *hw, unsigned int l,
+ struct freq_tbl *f)
+{
+ struct clk_rcg2 *rcg = to_clk_rcg2(hw);
+ struct clk_hw *p;
+ unsigned long prate = 0;
+ u32 val, mask, cfg, mode;
+ int i, num_parents;
+
+ regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + SE_PERF_DFSR(l), &cfg);
+
+ mask = BIT(rcg->hid_width) - 1;
+ f->pre_div = 1;
+ if (cfg & mask)
+ f->pre_div = cfg & mask;
+
+ cfg &= CFG_SRC_SEL_MASK;
+ cfg >>= CFG_SRC_SEL_SHIFT;
+
+ num_parents = clk_hw_get_num_parents(hw);
+ for (i = 0; i < num_parents; i++) {
+ if (cfg == rcg->parent_map[i].cfg) {
+ f->src = rcg->parent_map[i].src;
+ p = clk_hw_get_parent_by_index(&rcg->clkr.hw, i);
+ prate = clk_hw_get_rate(p);
+ }
+ }
+
+ mode = cfg & CFG_MODE_MASK;
+ mode >>= CFG_MODE_SHIFT;
+ if (mode) {
+ mask = BIT(rcg->mnd_width) - 1;
+ regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + SE_PERF_M_DFSR(l),
+ &val);
+ val &= mask;
+ f->m = val;
+
+ regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + SE_PERF_N_DFSR(l),
+ &val);
+ val = ~val;
+ val &= mask;
+ val += f->m;
+ f->n = val;
+ }
+
+ f->freq = calc_rate(prate, f->m, f->n, mode, f->pre_div);
+}
+
+static int clk_rcg2_dfs_populate_freq_table(struct clk_rcg2 *rcg)
+{
+ struct freq_tbl *freq_tbl;
+ int i;
+
+ /* Allocate space for 1 extra since table is NULL terminated */
+ freq_tbl = kcalloc(MAX_PERF_LEVEL + 1, sizeof(*freq_tbl), GFP_KERNEL);
+ if (!freq_tbl)
+ return -ENOMEM;
+ rcg->freq_tbl = freq_tbl;
+
+ for (i = 0; i < MAX_PERF_LEVEL; i++)
+ clk_rcg2_dfs_populate_freq(&rcg->clkr.hw, i, freq_tbl + i);
+
+ return 0;
+}
+
+static int clk_rcg2_dfs_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ struct clk_rcg2 *rcg = to_clk_rcg2(hw);
+ int ret;
+
+ if (!rcg->freq_tbl) {
+ ret = clk_rcg2_dfs_populate_freq_table(rcg);
+ if (ret) {
+ pr_err("Failed to update DFS tables for %s\n",
+ clk_hw_get_name(hw));
+ return ret;
+ }
+ }
+
+ return clk_rcg2_determine_rate(hw, req);
+}
+
+static unsigned long
+clk_rcg2_dfs_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+ struct clk_rcg2 *rcg = to_clk_rcg2(hw);
+ u32 level, mask, cfg, m = 0, n = 0, mode, pre_div;
+
+ regmap_read(rcg->clkr.regmap,
+ rcg->cmd_rcgr + SE_CMD_DFSR_OFFSET, &level);
+ level &= GENMASK(4, 1);
+ level >>= 1;
+
+ if (rcg->freq_tbl)
+ return rcg->freq_tbl[level].freq;
+
+ /*
+ * Assume that parent_rate is actually the parent because
+ * we can't do any better at figuring it out when the table
+ * hasn't been populated yet. We only populate the table
+ * in determine_rate because we can't guarantee the parents
+ * will be registered with the framework until then.
+ */
+ regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + SE_PERF_DFSR(level),
+ &cfg);
+
+ mask = BIT(rcg->hid_width) - 1;
+ pre_div = 1;
+ if (cfg & mask)
+ pre_div = cfg & mask;
+
+ mode = cfg & CFG_MODE_MASK;
+ mode >>= CFG_MODE_SHIFT;
+ if (mode) {
+ mask = BIT(rcg->mnd_width) - 1;
+ regmap_read(rcg->clkr.regmap,
+ rcg->cmd_rcgr + SE_PERF_M_DFSR(level), &m);
+ m &= mask;
+
+ regmap_read(rcg->clkr.regmap,
+ rcg->cmd_rcgr + SE_PERF_N_DFSR(level), &n);
+ n = ~n;
+ n &= mask;
+ n += m;
+ }
+
+ return calc_rate(parent_rate, m, n, mode, pre_div);
+}
+
+static const struct clk_ops clk_rcg2_dfs_ops = {
+ .is_enabled = clk_rcg2_is_enabled,
+ .get_parent = clk_rcg2_get_parent,
+ .determine_rate = clk_rcg2_dfs_determine_rate,
+ .recalc_rate = clk_rcg2_dfs_recalc_rate,
+};
+
+static int clk_rcg2_enable_dfs(const struct clk_rcg_dfs_data *data,
+ struct regmap *regmap)
+{
+ struct clk_rcg2 *rcg = data->rcg;
+ struct clk_init_data *init = data->init;
+ u32 val;
+ int ret;
+
+ ret = regmap_read(regmap, rcg->cmd_rcgr + SE_CMD_DFSR_OFFSET, &val);
+ if (ret)
+ return -EINVAL;
+
+ if (!(val & SE_CMD_DFS_EN))
+ return 0;
+
+ /*
+ * Rate changes with consumer writing a register in
+ * their own I/O region
+ */
+ init->flags |= CLK_GET_RATE_NOCACHE;
+ init->ops = &clk_rcg2_dfs_ops;
+
+ rcg->freq_tbl = NULL;
+
+ pr_debug("DFS registered for clk %s\n", init->name);
+
+ return 0;
+}
+
+int qcom_cc_register_rcg_dfs(struct regmap *regmap,
+ const struct clk_rcg_dfs_data *rcgs, size_t len)
+{
+ int i, ret;
+
+ for (i = 0; i < len; i++) {
+ ret = clk_rcg2_enable_dfs(&rcgs[i], regmap);
+ if (ret) {
+ const char *name = rcgs[i].init->name;
+
+ pr_err("DFS register failed for clk %s\n", name);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(qcom_cc_register_rcg_dfs);
diff --git a/drivers/clk/qcom/gcc-ipq806x.c b/drivers/clk/qcom/gcc-ipq806x.c
index 5f61225657ab..33d1bc5c6a46 100644
--- a/drivers/clk/qcom/gcc-ipq806x.c
+++ b/drivers/clk/qcom/gcc-ipq806x.c
@@ -30,6 +30,7 @@
#include "clk-pll.h"
#include "clk-rcg.h"
#include "clk-branch.h"
+#include "clk-hfpll.h"
#include "reset.h"
static struct clk_pll pll0 = {
@@ -113,6 +114,84 @@ static struct clk_regmap pll8_vote = {
},
};
+static struct hfpll_data hfpll0_data = {
+ .mode_reg = 0x3200,
+ .l_reg = 0x3208,
+ .m_reg = 0x320c,
+ .n_reg = 0x3210,
+ .config_reg = 0x3204,
+ .status_reg = 0x321c,
+ .config_val = 0x7845c665,
+ .droop_reg = 0x3214,
+ .droop_val = 0x0108c000,
+ .min_rate = 600000000UL,
+ .max_rate = 1800000000UL,
+};
+
+static struct clk_hfpll hfpll0 = {
+ .d = &hfpll0_data,
+ .clkr.hw.init = &(struct clk_init_data){
+ .parent_names = (const char *[]){ "pxo" },
+ .num_parents = 1,
+ .name = "hfpll0",
+ .ops = &clk_ops_hfpll,
+ .flags = CLK_IGNORE_UNUSED,
+ },
+ .lock = __SPIN_LOCK_UNLOCKED(hfpll0.lock),
+};
+
+static struct hfpll_data hfpll1_data = {
+ .mode_reg = 0x3240,
+ .l_reg = 0x3248,
+ .m_reg = 0x324c,
+ .n_reg = 0x3250,
+ .config_reg = 0x3244,
+ .status_reg = 0x325c,
+ .config_val = 0x7845c665,
+ .droop_reg = 0x3314,
+ .droop_val = 0x0108c000,
+ .min_rate = 600000000UL,
+ .max_rate = 1800000000UL,
+};
+
+static struct clk_hfpll hfpll1 = {
+ .d = &hfpll1_data,
+ .clkr.hw.init = &(struct clk_init_data){
+ .parent_names = (const char *[]){ "pxo" },
+ .num_parents = 1,
+ .name = "hfpll1",
+ .ops = &clk_ops_hfpll,
+ .flags = CLK_IGNORE_UNUSED,
+ },
+ .lock = __SPIN_LOCK_UNLOCKED(hfpll1.lock),
+};
+
+static struct hfpll_data hfpll_l2_data = {
+ .mode_reg = 0x3300,
+ .l_reg = 0x3308,
+ .m_reg = 0x330c,
+ .n_reg = 0x3310,
+ .config_reg = 0x3304,
+ .status_reg = 0x331c,
+ .config_val = 0x7845c665,
+ .droop_reg = 0x3314,
+ .droop_val = 0x0108c000,
+ .min_rate = 600000000UL,
+ .max_rate = 1800000000UL,
+};
+
+static struct clk_hfpll hfpll_l2 = {
+ .d = &hfpll_l2_data,
+ .clkr.hw.init = &(struct clk_init_data){
+ .parent_names = (const char *[]){ "pxo" },
+ .num_parents = 1,
+ .name = "hfpll_l2",
+ .ops = &clk_ops_hfpll,
+ .flags = CLK_IGNORE_UNUSED,
+ },
+ .lock = __SPIN_LOCK_UNLOCKED(hfpll_l2.lock),
+};
+
static struct clk_pll pll14 = {
.l_reg = 0x31c4,
.m_reg = 0x31c8,
@@ -2797,6 +2876,9 @@ static struct clk_regmap *gcc_ipq806x_clks[] = {
[UBI32_CORE2_CLK_SRC] = &ubi32_core2_src_clk.clkr,
[NSSTCM_CLK_SRC] = &nss_tcm_src.clkr,
[NSSTCM_CLK] = &nss_tcm_clk.clkr,
+ [PLL9] = &hfpll0.clkr,
+ [PLL10] = &hfpll1.clkr,
+ [PLL12] = &hfpll_l2.clkr,
};
static const struct qcom_reset_map gcc_ipq806x_resets[] = {
diff --git a/drivers/clk/qcom/gcc-msm8960.c b/drivers/clk/qcom/gcc-msm8960.c
index fd495e0471bb..399474755654 100644
--- a/drivers/clk/qcom/gcc-msm8960.c
+++ b/drivers/clk/qcom/gcc-msm8960.c
@@ -30,6 +30,7 @@
#include "clk-pll.h"
#include "clk-rcg.h"
#include "clk-branch.h"
+#include "clk-hfpll.h"
#include "reset.h"
static struct clk_pll pll3 = {
@@ -86,6 +87,164 @@ static struct clk_regmap pll8_vote = {
},
};
+static struct hfpll_data hfpll0_data = {
+ .mode_reg = 0x3200,
+ .l_reg = 0x3208,
+ .m_reg = 0x320c,
+ .n_reg = 0x3210,
+ .config_reg = 0x3204,
+ .status_reg = 0x321c,
+ .config_val = 0x7845c665,
+ .droop_reg = 0x3214,
+ .droop_val = 0x0108c000,
+ .min_rate = 600000000UL,
+ .max_rate = 1800000000UL,
+};
+
+static struct clk_hfpll hfpll0 = {
+ .d = &hfpll0_data,
+ .clkr.hw.init = &(struct clk_init_data){
+ .parent_names = (const char *[]){ "pxo" },
+ .num_parents = 1,
+ .name = "hfpll0",
+ .ops = &clk_ops_hfpll,
+ .flags = CLK_IGNORE_UNUSED,
+ },
+ .lock = __SPIN_LOCK_UNLOCKED(hfpll0.lock),
+};
+
+static struct hfpll_data hfpll1_8064_data = {
+ .mode_reg = 0x3240,
+ .l_reg = 0x3248,
+ .m_reg = 0x324c,
+ .n_reg = 0x3250,
+ .config_reg = 0x3244,
+ .status_reg = 0x325c,
+ .config_val = 0x7845c665,
+ .droop_reg = 0x3254,
+ .droop_val = 0x0108c000,
+ .min_rate = 600000000UL,
+ .max_rate = 1800000000UL,
+};
+
+static struct hfpll_data hfpll1_data = {
+ .mode_reg = 0x3300,
+ .l_reg = 0x3308,
+ .m_reg = 0x330c,
+ .n_reg = 0x3310,
+ .config_reg = 0x3304,
+ .status_reg = 0x331c,
+ .config_val = 0x7845c665,
+ .droop_reg = 0x3314,
+ .droop_val = 0x0108c000,
+ .min_rate = 600000000UL,
+ .max_rate = 1800000000UL,
+};
+
+static struct clk_hfpll hfpll1 = {
+ .d = &hfpll1_data,
+ .clkr.hw.init = &(struct clk_init_data){
+ .parent_names = (const char *[]){ "pxo" },
+ .num_parents = 1,
+ .name = "hfpll1",
+ .ops = &clk_ops_hfpll,
+ .flags = CLK_IGNORE_UNUSED,
+ },
+ .lock = __SPIN_LOCK_UNLOCKED(hfpll1.lock),
+};
+
+static struct hfpll_data hfpll2_data = {
+ .mode_reg = 0x3280,
+ .l_reg = 0x3288,
+ .m_reg = 0x328c,
+ .n_reg = 0x3290,
+ .config_reg = 0x3284,
+ .status_reg = 0x329c,
+ .config_val = 0x7845c665,
+ .droop_reg = 0x3294,
+ .droop_val = 0x0108c000,
+ .min_rate = 600000000UL,
+ .max_rate = 1800000000UL,
+};
+
+static struct clk_hfpll hfpll2 = {
+ .d = &hfpll2_data,
+ .clkr.hw.init = &(struct clk_init_data){
+ .parent_names = (const char *[]){ "pxo" },
+ .num_parents = 1,
+ .name = "hfpll2",
+ .ops = &clk_ops_hfpll,
+ .flags = CLK_IGNORE_UNUSED,
+ },
+ .lock = __SPIN_LOCK_UNLOCKED(hfpll2.lock),
+};
+
+static struct hfpll_data hfpll3_data = {
+ .mode_reg = 0x32c0,
+ .l_reg = 0x32c8,
+ .m_reg = 0x32cc,
+ .n_reg = 0x32d0,
+ .config_reg = 0x32c4,
+ .status_reg = 0x32dc,
+ .config_val = 0x7845c665,
+ .droop_reg = 0x32d4,
+ .droop_val = 0x0108c000,
+ .min_rate = 600000000UL,
+ .max_rate = 1800000000UL,
+};
+
+static struct clk_hfpll hfpll3 = {
+ .d = &hfpll3_data,
+ .clkr.hw.init = &(struct clk_init_data){
+ .parent_names = (const char *[]){ "pxo" },
+ .num_parents = 1,
+ .name = "hfpll3",
+ .ops = &clk_ops_hfpll,
+ .flags = CLK_IGNORE_UNUSED,
+ },
+ .lock = __SPIN_LOCK_UNLOCKED(hfpll3.lock),
+};
+
+static struct hfpll_data hfpll_l2_8064_data = {
+ .mode_reg = 0x3300,
+ .l_reg = 0x3308,
+ .m_reg = 0x330c,
+ .n_reg = 0x3310,
+ .config_reg = 0x3304,
+ .status_reg = 0x331c,
+ .config_val = 0x7845c665,
+ .droop_reg = 0x3314,
+ .droop_val = 0x0108c000,
+ .min_rate = 600000000UL,
+ .max_rate = 1800000000UL,
+};
+
+static struct hfpll_data hfpll_l2_data = {
+ .mode_reg = 0x3400,
+ .l_reg = 0x3408,
+ .m_reg = 0x340c,
+ .n_reg = 0x3410,
+ .config_reg = 0x3404,
+ .status_reg = 0x341c,
+ .config_val = 0x7845c665,
+ .droop_reg = 0x3414,
+ .droop_val = 0x0108c000,
+ .min_rate = 600000000UL,
+ .max_rate = 1800000000UL,
+};
+
+static struct clk_hfpll hfpll_l2 = {
+ .d = &hfpll_l2_data,
+ .clkr.hw.init = &(struct clk_init_data){
+ .parent_names = (const char *[]){ "pxo" },
+ .num_parents = 1,
+ .name = "hfpll_l2",
+ .ops = &clk_ops_hfpll,
+ .flags = CLK_IGNORE_UNUSED,
+ },
+ .lock = __SPIN_LOCK_UNLOCKED(hfpll_l2.lock),
+};
+
static struct clk_pll pll14 = {
.l_reg = 0x31c4,
.m_reg = 0x31c8,
@@ -3107,6 +3266,9 @@ static struct clk_regmap *gcc_msm8960_clks[] = {
[PMIC_ARB1_H_CLK] = &pmic_arb1_h_clk.clkr,
[PMIC_SSBI2_CLK] = &pmic_ssbi2_clk.clkr,
[RPM_MSG_RAM_H_CLK] = &rpm_msg_ram_h_clk.clkr,
+ [PLL9] = &hfpll0.clkr,
+ [PLL10] = &hfpll1.clkr,
+ [PLL12] = &hfpll_l2.clkr,
};
static const struct qcom_reset_map gcc_msm8960_resets[] = {
@@ -3318,6 +3480,11 @@ static struct clk_regmap *gcc_apq8064_clks[] = {
[PMIC_ARB1_H_CLK] = &pmic_arb1_h_clk.clkr,
[PMIC_SSBI2_CLK] = &pmic_ssbi2_clk.clkr,
[RPM_MSG_RAM_H_CLK] = &rpm_msg_ram_h_clk.clkr,
+ [PLL9] = &hfpll0.clkr,
+ [PLL10] = &hfpll1.clkr,
+ [PLL12] = &hfpll_l2.clkr,
+ [PLL16] = &hfpll2.clkr,
+ [PLL17] = &hfpll3.clkr,
};
static const struct qcom_reset_map gcc_apq8064_resets[] = {
@@ -3477,6 +3644,11 @@ static int gcc_msm8960_probe(struct platform_device *pdev)
if (ret)
return ret;
+ if (match->data == &gcc_apq8064_desc) {
+ hfpll1.d = &hfpll1_8064_data;
+ hfpll_l2.d = &hfpll_l2_8064_data;
+ }
+
tsens = platform_device_register_data(&pdev->dev, "qcom-tsens", -1,
NULL, 0);
if (IS_ERR(tsens))
diff --git a/drivers/clk/qcom/gcc-msm8996.c b/drivers/clk/qcom/gcc-msm8996.c
index 9a3290fdd01b..9d136172c27c 100644
--- a/drivers/clk/qcom/gcc-msm8996.c
+++ b/drivers/clk/qcom/gcc-msm8996.c
@@ -260,6 +260,36 @@ static struct clk_alpha_pll_postdiv gpll0 = {
},
};
+static struct clk_branch gcc_mmss_gpll0_div_clk = {
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x5200c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_mmss_gpll0_div_clk",
+ .parent_names = (const char *[]){ "gpll0" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_mss_gpll0_div_clk = {
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x5200c,
+ .enable_mask = BIT(2),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_mss_gpll0_div_clk",
+ .parent_names = (const char *[]){ "gpll0" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops
+ },
+ },
+};
+
static struct clk_alpha_pll gpll4_early = {
.offset = 0x77000,
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
@@ -2951,6 +2981,20 @@ static struct clk_branch gcc_smmu_aggre0_ahb_clk = {
},
};
+static struct clk_branch gcc_aggre1_pnoc_ahb_clk = {
+ .halt_reg = 0x82014,
+ .clkr = {
+ .enable_reg = 0x82014,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_aggre1_pnoc_ahb_clk",
+ .parent_names = (const char *[]){ "periph_noc_clk_src" },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
static struct clk_branch gcc_aggre2_ufs_axi_clk = {
.halt_reg = 0x83014,
.clkr = {
@@ -2981,6 +3025,34 @@ static struct clk_branch gcc_aggre2_usb3_axi_clk = {
},
};
+static struct clk_branch gcc_dcc_ahb_clk = {
+ .halt_reg = 0x84004,
+ .clkr = {
+ .enable_reg = 0x84004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_dcc_ahb_clk",
+ .parent_names = (const char *[]){ "config_noc_clk_src" },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_aggre0_noc_mpu_cfg_ahb_clk = {
+ .halt_reg = 0x85000,
+ .clkr = {
+ .enable_reg = 0x85000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_aggre0_noc_mpu_cfg_ahb_clk",
+ .parent_names = (const char *[]){ "config_noc_clk_src" },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
static struct clk_branch gcc_qspi_ahb_clk = {
.halt_reg = 0x8b004,
.clkr = {
@@ -3039,6 +3111,20 @@ static struct clk_branch gcc_hdmi_clkref_clk = {
},
};
+static struct clk_branch gcc_edp_clkref_clk = {
+ .halt_reg = 0x88004,
+ .clkr = {
+ .enable_reg = 0x88004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_edp_clkref_clk",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
static struct clk_branch gcc_ufs_clkref_clk = {
.halt_reg = 0x88008,
.clkr = {
@@ -3095,6 +3181,62 @@ static struct clk_branch gcc_rx1_usb2_clkref_clk = {
},
};
+static struct clk_branch gcc_mss_cfg_ahb_clk = {
+ .halt_reg = 0x8a000,
+ .clkr = {
+ .enable_reg = 0x8a000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_mss_cfg_ahb_clk",
+ .parent_names = (const char *[]){ "config_noc_clk_src" },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_mss_mnoc_bimc_axi_clk = {
+ .halt_reg = 0x8a004,
+ .clkr = {
+ .enable_reg = 0x8a004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_mss_mnoc_bimc_axi_clk",
+ .parent_names = (const char *[]){ "system_noc_clk_src" },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_mss_snoc_axi_clk = {
+ .halt_reg = 0x8a024,
+ .clkr = {
+ .enable_reg = 0x8a024,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_mss_snoc_axi_clk",
+ .parent_names = (const char *[]){ "system_noc_clk_src" },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_mss_q6_bimc_axi_clk = {
+ .halt_reg = 0x8a028,
+ .clkr = {
+ .enable_reg = 0x8a028,
+ .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,
+ },
+ },
+};
+
static struct clk_hw *gcc_msm8996_hws[] = {
&xo.hw,
&gpll0_early_div.hw,
@@ -3355,6 +3497,7 @@ static struct clk_regmap *gcc_msm8996_clocks[] = {
[GCC_AGGRE0_CNOC_AHB_CLK] = &gcc_aggre0_cnoc_ahb_clk.clkr,
[GCC_SMMU_AGGRE0_AXI_CLK] = &gcc_smmu_aggre0_axi_clk.clkr,
[GCC_SMMU_AGGRE0_AHB_CLK] = &gcc_smmu_aggre0_ahb_clk.clkr,
+ [GCC_AGGRE1_PNOC_AHB_CLK] = &gcc_aggre1_pnoc_ahb_clk.clkr,
[GCC_AGGRE2_UFS_AXI_CLK] = &gcc_aggre2_ufs_axi_clk.clkr,
[GCC_AGGRE2_USB3_AXI_CLK] = &gcc_aggre2_usb3_axi_clk.clkr,
[GCC_QSPI_AHB_CLK] = &gcc_qspi_ahb_clk.clkr,
@@ -3365,6 +3508,15 @@ static struct clk_regmap *gcc_msm8996_clocks[] = {
[GCC_PCIE_CLKREF_CLK] = &gcc_pcie_clkref_clk.clkr,
[GCC_RX2_USB2_CLKREF_CLK] = &gcc_rx2_usb2_clkref_clk.clkr,
[GCC_RX1_USB2_CLKREF_CLK] = &gcc_rx1_usb2_clkref_clk.clkr,
+ [GCC_EDP_CLKREF_CLK] = &gcc_edp_clkref_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_MSS_SNOC_AXI_CLK] = &gcc_mss_snoc_axi_clk.clkr,
+ [GCC_MSS_MNOC_BIMC_AXI_CLK] = &gcc_mss_mnoc_bimc_axi_clk.clkr,
+ [GCC_DCC_AHB_CLK] = &gcc_dcc_ahb_clk.clkr,
+ [GCC_AGGRE0_NOC_MPU_CFG_AHB_CLK] = &gcc_aggre0_noc_mpu_cfg_ahb_clk.clkr,
+ [GCC_MMSS_GPLL0_DIV_CLK] = &gcc_mmss_gpll0_div_clk.clkr,
+ [GCC_MSS_GPLL0_DIV_CLK] = &gcc_mss_gpll0_div_clk.clkr,
};
static struct gdsc *gcc_msm8996_gdscs[] = {
diff --git a/drivers/clk/qcom/gcc-qcs404.c b/drivers/clk/qcom/gcc-qcs404.c
new file mode 100644
index 000000000000..ef1b267cb058
--- /dev/null
+++ b/drivers/clk/qcom/gcc-qcs404.c
@@ -0,0 +1,2744 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/clk-provider.h>
+#include <linux/regmap.h>
+#include <linux/reset-controller.h>
+
+#include <dt-bindings/clock/qcom,gcc-qcs404.h>
+
+#include "clk-alpha-pll.h"
+#include "clk-branch.h"
+#include "clk-pll.h"
+#include "clk-rcg.h"
+#include "clk-regmap.h"
+#include "common.h"
+#include "reset.h"
+
+enum {
+ P_CORE_BI_PLL_TEST_SE,
+ P_DSI0_PHY_PLL_OUT_BYTECLK,
+ P_DSI0_PHY_PLL_OUT_DSICLK,
+ P_GPLL0_OUT_AUX,
+ P_GPLL0_OUT_MAIN,
+ P_GPLL1_OUT_MAIN,
+ P_GPLL3_OUT_MAIN,
+ P_GPLL4_OUT_AUX,
+ P_GPLL4_OUT_MAIN,
+ P_GPLL6_OUT_AUX,
+ P_HDMI_PHY_PLL_CLK,
+ P_PCIE_0_PIPE_CLK,
+ P_SLEEP_CLK,
+ P_XO,
+};
+
+static const struct parent_map gcc_parent_map_0[] = {
+ { P_XO, 0 },
+ { P_GPLL0_OUT_MAIN, 1 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gcc_parent_names_0[] = {
+ "cxo",
+ "gpll0_out_main",
+ "core_bi_pll_test_se",
+};
+
+static const char * const gcc_parent_names_ao_0[] = {
+ "cxo",
+ "gpll0_ao_out_main",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map gcc_parent_map_1[] = {
+ { P_XO, 0 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gcc_parent_names_1[] = {
+ "cxo",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map gcc_parent_map_2[] = {
+ { P_XO, 0 },
+ { P_GPLL0_OUT_MAIN, 1 },
+ { P_GPLL6_OUT_AUX, 2 },
+ { P_SLEEP_CLK, 6 },
+};
+
+static const char * const gcc_parent_names_2[] = {
+ "cxo",
+ "gpll0_out_main",
+ "gpll6_out_aux",
+ "sleep_clk",
+};
+
+static const struct parent_map gcc_parent_map_3[] = {
+ { P_XO, 0 },
+ { P_GPLL0_OUT_MAIN, 1 },
+ { P_GPLL6_OUT_AUX, 2 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gcc_parent_names_3[] = {
+ "cxo",
+ "gpll0_out_main",
+ "gpll6_out_aux",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map gcc_parent_map_4[] = {
+ { P_XO, 0 },
+ { P_GPLL1_OUT_MAIN, 1 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gcc_parent_names_4[] = {
+ "cxo",
+ "gpll1_out_main",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map gcc_parent_map_5[] = {
+ { P_XO, 0 },
+ { P_DSI0_PHY_PLL_OUT_BYTECLK, 1 },
+ { P_GPLL0_OUT_AUX, 2 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gcc_parent_names_5[] = {
+ "cxo",
+ "dsi0pll_byteclk_src",
+ "gpll0_out_aux",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map gcc_parent_map_6[] = {
+ { P_XO, 0 },
+ { P_DSI0_PHY_PLL_OUT_BYTECLK, 2 },
+ { P_GPLL0_OUT_AUX, 3 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gcc_parent_names_6[] = {
+ "cxo",
+ "dsi0_phy_pll_out_byteclk",
+ "gpll0_out_aux",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map gcc_parent_map_7[] = {
+ { P_XO, 0 },
+ { P_GPLL0_OUT_MAIN, 1 },
+ { P_GPLL3_OUT_MAIN, 2 },
+ { P_GPLL6_OUT_AUX, 3 },
+ { P_GPLL4_OUT_AUX, 4 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gcc_parent_names_7[] = {
+ "cxo",
+ "gpll0_out_main",
+ "gpll3_out_main",
+ "gpll6_out_aux",
+ "gpll4_out_aux",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map gcc_parent_map_8[] = {
+ { P_XO, 0 },
+ { P_HDMI_PHY_PLL_CLK, 1 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gcc_parent_names_8[] = {
+ "cxo",
+ "hdmi_phy_pll_clk",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map gcc_parent_map_9[] = {
+ { P_XO, 0 },
+ { P_GPLL0_OUT_MAIN, 1 },
+ { P_DSI0_PHY_PLL_OUT_DSICLK, 2 },
+ { P_GPLL6_OUT_AUX, 3 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gcc_parent_names_9[] = {
+ "cxo",
+ "gpll0_out_main",
+ "dsi0_phy_pll_out_dsiclk",
+ "gpll6_out_aux",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map gcc_parent_map_10[] = {
+ { P_XO, 0 },
+ { P_SLEEP_CLK, 1 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gcc_parent_names_10[] = {
+ "cxo",
+ "sleep_clk",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map gcc_parent_map_11[] = {
+ { P_XO, 0 },
+ { P_PCIE_0_PIPE_CLK, 1 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gcc_parent_names_11[] = {
+ "cxo",
+ "pcie_0_pipe_clk",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map gcc_parent_map_12[] = {
+ { P_XO, 0 },
+ { P_DSI0_PHY_PLL_OUT_DSICLK, 1 },
+ { P_GPLL0_OUT_AUX, 2 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gcc_parent_names_12[] = {
+ "cxo",
+ "dsi0pll_pclk_src",
+ "gpll0_out_aux",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map gcc_parent_map_13[] = {
+ { P_XO, 0 },
+ { P_GPLL0_OUT_MAIN, 1 },
+ { P_GPLL4_OUT_MAIN, 2 },
+ { P_GPLL6_OUT_AUX, 3 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gcc_parent_names_13[] = {
+ "cxo",
+ "gpll0_out_main",
+ "gpll4_out_main",
+ "gpll6_out_aux",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map gcc_parent_map_14[] = {
+ { P_XO, 0 },
+ { P_GPLL0_OUT_MAIN, 1 },
+ { P_GPLL4_OUT_AUX, 2 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gcc_parent_names_14[] = {
+ "cxo",
+ "gpll0_out_main",
+ "gpll4_out_aux",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map gcc_parent_map_15[] = {
+ { P_XO, 0 },
+ { P_GPLL0_OUT_AUX, 2 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gcc_parent_names_15[] = {
+ "cxo",
+ "gpll0_out_aux",
+ "core_bi_pll_test_se",
+};
+
+static struct clk_fixed_factor cxo = {
+ .mult = 1,
+ .div = 1,
+ .hw.init = &(struct clk_init_data){
+ .name = "cxo",
+ .parent_names = (const char *[]){ "xo-board" },
+ .num_parents = 1,
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
+static struct clk_alpha_pll gpll0_sleep_clk_src = {
+ .offset = 0x21000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .clkr = {
+ .enable_reg = 0x45008,
+ .enable_mask = BIT(23),
+ .enable_is_inverted = true,
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll0_sleep_clk_src",
+ .parent_names = (const char *[]){ "cxo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll gpll0_out_main = {
+ .offset = 0x21000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .flags = SUPPORTS_FSM_MODE,
+ .clkr = {
+ .enable_reg = 0x45000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll0_out_main",
+ .parent_names = (const char *[])
+ { "gpll0_sleep_clk_src" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll gpll0_ao_out_main = {
+ .offset = 0x21000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .flags = SUPPORTS_FSM_MODE,
+ .clkr = {
+ .enable_reg = 0x45000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll0_ao_out_main",
+ .parent_names = (const char *[]){ "cxo" },
+ .num_parents = 1,
+ .flags = CLK_IS_CRITICAL,
+ .ops = &clk_alpha_pll_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll gpll1_out_main = {
+ .offset = 0x20000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .clkr = {
+ .enable_reg = 0x45000,
+ .enable_mask = BIT(1),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll1_out_main",
+ .parent_names = (const char *[]){ "cxo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ },
+ },
+};
+
+/* 930MHz configuration */
+static const struct alpha_pll_config gpll3_config = {
+ .l = 48,
+ .alpha = 0x0,
+ .alpha_en_mask = BIT(24),
+ .post_div_mask = 0xf << 8,
+ .post_div_val = 0x1 << 8,
+ .vco_mask = 0x3 << 20,
+ .main_output_mask = 0x1,
+ .config_ctl_val = 0x4001055b,
+};
+
+static const struct pll_vco gpll3_vco[] = {
+ { 700000000, 1400000000, 0 },
+};
+
+static struct clk_alpha_pll gpll3_out_main = {
+ .offset = 0x22000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .vco_table = gpll3_vco,
+ .num_vco = ARRAY_SIZE(gpll3_vco),
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll3_out_main",
+ .parent_names = (const char *[]){ "cxo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll gpll4_out_main = {
+ .offset = 0x24000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .clkr = {
+ .enable_reg = 0x45000,
+ .enable_mask = BIT(5),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll4_out_main",
+ .parent_names = (const char *[]){ "cxo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ },
+ },
+};
+
+static struct clk_pll gpll6 = {
+ .l_reg = 0x37004,
+ .m_reg = 0x37008,
+ .n_reg = 0x3700C,
+ .config_reg = 0x37014,
+ .mode_reg = 0x37000,
+ .status_reg = 0x3701C,
+ .status_bit = 17,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gpll6",
+ .parent_names = (const char *[]){ "cxo" },
+ .num_parents = 1,
+ .ops = &clk_pll_ops,
+ },
+};
+
+static struct clk_regmap gpll6_out_aux = {
+ .enable_reg = 0x45000,
+ .enable_mask = BIT(7),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll6_out_aux",
+ .parent_names = (const char *[]){ "gpll6" },
+ .num_parents = 1,
+ .ops = &clk_pll_vote_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_apss_ahb_clk_src[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ F(50000000, P_GPLL0_OUT_MAIN, 16, 0, 0),
+ F(100000000, P_GPLL0_OUT_MAIN, 8, 0, 0),
+ F(133333333, P_GPLL0_OUT_MAIN, 6, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 apss_ahb_clk_src = {
+ .cmd_rcgr = 0x46000,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_apss_ahb_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "apss_ahb_clk_src",
+ .parent_names = gcc_parent_names_ao_0,
+ .num_parents = 3,
+ .flags = CLK_IS_CRITICAL,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_blsp1_qup0_i2c_apps_clk_src[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ F(50000000, P_GPLL0_OUT_MAIN, 16, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 blsp1_qup0_i2c_apps_clk_src = {
+ .cmd_rcgr = 0x602c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_blsp1_qup0_i2c_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup0_i2c_apps_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_blsp1_qup0_spi_apps_clk_src[] = {
+ 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_OUT_MAIN, 10, 1, 5),
+ F(19200000, P_XO, 1, 0, 0),
+ F(25000000, P_GPLL0_OUT_MAIN, 16, 1, 2),
+ F(50000000, P_GPLL0_OUT_MAIN, 16, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 blsp1_qup0_spi_apps_clk_src = {
+ .cmd_rcgr = 0x6034,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_blsp1_qup0_spi_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup0_spi_apps_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_qup1_i2c_apps_clk_src = {
+ .cmd_rcgr = 0x200c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_blsp1_qup0_i2c_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup1_i2c_apps_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_blsp1_qup1_spi_apps_clk_src[] = {
+ F(960000, P_XO, 10, 1, 2),
+ F(4800000, P_XO, 4, 0, 0),
+ F(9600000, P_XO, 2, 0, 0),
+ F(10480000, P_GPLL0_OUT_MAIN, 1, 3, 229),
+ F(16000000, P_GPLL0_OUT_MAIN, 10, 1, 5),
+ F(19200000, P_XO, 1, 0, 0),
+ F(20961000, P_GPLL0_OUT_MAIN, 1, 6, 229),
+ { }
+};
+
+static struct clk_rcg2 blsp1_qup1_spi_apps_clk_src = {
+ .cmd_rcgr = 0x2024,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup1_spi_apps_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_qup2_i2c_apps_clk_src = {
+ .cmd_rcgr = 0x3000,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_blsp1_qup0_i2c_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup2_i2c_apps_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_blsp1_qup2_spi_apps_clk_src[] = {
+ F(960000, P_XO, 10, 1, 2),
+ F(4800000, P_XO, 4, 0, 0),
+ F(9600000, P_XO, 2, 0, 0),
+ F(15000000, P_GPLL0_OUT_MAIN, 1, 3, 160),
+ F(16000000, P_GPLL0_OUT_MAIN, 10, 1, 5),
+ F(19200000, P_XO, 1, 0, 0),
+ F(25000000, P_GPLL0_OUT_MAIN, 16, 1, 2),
+ F(30000000, P_GPLL0_OUT_MAIN, 1, 3, 80),
+ { }
+};
+
+static struct clk_rcg2 blsp1_qup2_spi_apps_clk_src = {
+ .cmd_rcgr = 0x3014,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_blsp1_qup2_spi_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup2_spi_apps_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_qup3_i2c_apps_clk_src = {
+ .cmd_rcgr = 0x4000,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_blsp1_qup0_i2c_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup3_i2c_apps_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 3,
+ .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_parent_map_0,
+ .freq_tbl = ftbl_blsp1_qup0_spi_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup3_spi_apps_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_qup4_i2c_apps_clk_src = {
+ .cmd_rcgr = 0x5000,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_blsp1_qup0_i2c_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup4_i2c_apps_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 3,
+ .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_parent_map_0,
+ .freq_tbl = ftbl_blsp1_qup0_spi_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup4_spi_apps_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_blsp1_uart0_apps_clk_src[] = {
+ F(3686400, P_GPLL0_OUT_MAIN, 1, 72, 15625),
+ F(7372800, P_GPLL0_OUT_MAIN, 1, 144, 15625),
+ F(14745600, P_GPLL0_OUT_MAIN, 1, 288, 15625),
+ F(16000000, P_GPLL0_OUT_MAIN, 10, 1, 5),
+ F(19200000, P_XO, 1, 0, 0),
+ F(24000000, P_GPLL0_OUT_MAIN, 1, 3, 100),
+ F(25000000, P_GPLL0_OUT_MAIN, 16, 1, 2),
+ F(32000000, P_GPLL0_OUT_MAIN, 1, 1, 25),
+ F(40000000, P_GPLL0_OUT_MAIN, 1, 1, 20),
+ F(46400000, P_GPLL0_OUT_MAIN, 1, 29, 500),
+ F(48000000, P_GPLL0_OUT_MAIN, 1, 3, 50),
+ F(51200000, P_GPLL0_OUT_MAIN, 1, 8, 125),
+ F(56000000, P_GPLL0_OUT_MAIN, 1, 7, 100),
+ F(58982400, P_GPLL0_OUT_MAIN, 1, 1152, 15625),
+ F(60000000, P_GPLL0_OUT_MAIN, 1, 3, 40),
+ F(64000000, P_GPLL0_OUT_MAIN, 1, 2, 25),
+ { }
+};
+
+static struct clk_rcg2 blsp1_uart0_apps_clk_src = {
+ .cmd_rcgr = 0x600c,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_blsp1_uart0_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_uart0_apps_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_uart1_apps_clk_src = {
+ .cmd_rcgr = 0x2044,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_blsp1_uart0_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_uart1_apps_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 3,
+ .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_parent_map_0,
+ .freq_tbl = ftbl_blsp1_uart0_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_uart2_apps_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_uart3_apps_clk_src = {
+ .cmd_rcgr = 0x4014,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_blsp1_uart0_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_uart3_apps_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp2_qup0_i2c_apps_clk_src = {
+ .cmd_rcgr = 0xc00c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_blsp1_qup0_i2c_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp2_qup0_i2c_apps_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp2_qup0_spi_apps_clk_src = {
+ .cmd_rcgr = 0xc024,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_blsp1_qup0_spi_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp2_qup0_spi_apps_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp2_uart0_apps_clk_src = {
+ .cmd_rcgr = 0xc044,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_blsp1_uart0_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp2_uart0_apps_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 byte0_clk_src = {
+ .cmd_rcgr = 0x4d044,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_5,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "byte0_clk_src",
+ .parent_names = gcc_parent_names_5,
+ .num_parents = 4,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_byte2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_emac_clk_src[] = {
+ F(5000000, P_GPLL1_OUT_MAIN, 2, 1, 50),
+ F(50000000, P_GPLL1_OUT_MAIN, 10, 0, 0),
+ F(125000000, P_GPLL1_OUT_MAIN, 4, 0, 0),
+ F(250000000, P_GPLL1_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 emac_clk_src = {
+ .cmd_rcgr = 0x4e01c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_4,
+ .freq_tbl = ftbl_emac_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "emac_clk_src",
+ .parent_names = gcc_parent_names_4,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_emac_ptp_clk_src[] = {
+ F(50000000, P_GPLL1_OUT_MAIN, 10, 0, 0),
+ F(125000000, P_GPLL1_OUT_MAIN, 4, 0, 0),
+ F(250000000, P_GPLL1_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 emac_ptp_clk_src = {
+ .cmd_rcgr = 0x4e014,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_4,
+ .freq_tbl = ftbl_emac_ptp_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "emac_ptp_clk_src",
+ .parent_names = gcc_parent_names_4,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_esc0_clk_src[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 esc0_clk_src = {
+ .cmd_rcgr = 0x4d05c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_6,
+ .freq_tbl = ftbl_esc0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "esc0_clk_src",
+ .parent_names = gcc_parent_names_6,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gfx3d_clk_src[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ F(50000000, P_GPLL0_OUT_MAIN, 16, 0, 0),
+ F(80000000, P_GPLL0_OUT_MAIN, 10, 0, 0),
+ F(100000000, P_GPLL0_OUT_MAIN, 8, 0, 0),
+ F(160000000, P_GPLL0_OUT_MAIN, 5, 0, 0),
+ F(200000000, P_GPLL0_OUT_MAIN, 4, 0, 0),
+ F(228571429, P_GPLL0_OUT_MAIN, 3.5, 0, 0),
+ F(240000000, P_GPLL6_OUT_AUX, 4.5, 0, 0),
+ F(266666667, P_GPLL0_OUT_MAIN, 3, 0, 0),
+ F(270000000, P_GPLL6_OUT_AUX, 4, 0, 0),
+ F(320000000, P_GPLL0_OUT_MAIN, 2.5, 0, 0),
+ F(400000000, P_GPLL0_OUT_MAIN, 2, 0, 0),
+ F(484800000, P_GPLL3_OUT_MAIN, 1, 0, 0),
+ F(523200000, P_GPLL3_OUT_MAIN, 1, 0, 0),
+ F(550000000, P_GPLL3_OUT_MAIN, 1, 0, 0),
+ F(598000000, P_GPLL3_OUT_MAIN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gfx3d_clk_src = {
+ .cmd_rcgr = 0x59000,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_7,
+ .freq_tbl = ftbl_gfx3d_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gfx3d_clk_src",
+ .parent_names = gcc_parent_names_7,
+ .num_parents = 6,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gp1_clk_src[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ F(100000000, P_GPLL0_OUT_MAIN, 8, 0, 0),
+ F(200000000, P_GPLL0_OUT_MAIN, 4, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gp1_clk_src = {
+ .cmd_rcgr = 0x8004,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_2,
+ .freq_tbl = ftbl_gp1_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gp1_clk_src",
+ .parent_names = gcc_parent_names_2,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gp2_clk_src = {
+ .cmd_rcgr = 0x9004,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_2,
+ .freq_tbl = ftbl_gp1_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gp2_clk_src",
+ .parent_names = gcc_parent_names_2,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gp3_clk_src = {
+ .cmd_rcgr = 0xa004,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_2,
+ .freq_tbl = ftbl_gp1_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gp3_clk_src",
+ .parent_names = gcc_parent_names_2,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 hdmi_app_clk_src = {
+ .cmd_rcgr = 0x4d0e4,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_esc0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "hdmi_app_clk_src",
+ .parent_names = gcc_parent_names_1,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 hdmi_pclk_clk_src = {
+ .cmd_rcgr = 0x4d0dc,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_8,
+ .freq_tbl = ftbl_esc0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "hdmi_pclk_clk_src",
+ .parent_names = gcc_parent_names_8,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_mdp_clk_src[] = {
+ F(50000000, P_GPLL0_OUT_MAIN, 16, 0, 0),
+ F(80000000, P_GPLL0_OUT_MAIN, 10, 0, 0),
+ F(100000000, P_GPLL0_OUT_MAIN, 8, 0, 0),
+ F(145454545, P_GPLL0_OUT_MAIN, 5.5, 0, 0),
+ F(160000000, P_GPLL0_OUT_MAIN, 5, 0, 0),
+ F(177777778, P_GPLL0_OUT_MAIN, 4.5, 0, 0),
+ F(200000000, P_GPLL0_OUT_MAIN, 4, 0, 0),
+ F(266666667, P_GPLL0_OUT_MAIN, 3, 0, 0),
+ F(320000000, P_GPLL0_OUT_MAIN, 2.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 mdp_clk_src = {
+ .cmd_rcgr = 0x4d014,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_9,
+ .freq_tbl = ftbl_mdp_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "mdp_clk_src",
+ .parent_names = gcc_parent_names_9,
+ .num_parents = 5,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_pcie_0_aux_clk_src[] = {
+ F(1200000, P_XO, 16, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 pcie_0_aux_clk_src = {
+ .cmd_rcgr = 0x3e024,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_10,
+ .freq_tbl = ftbl_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "pcie_0_aux_clk_src",
+ .parent_names = gcc_parent_names_10,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_pcie_0_pipe_clk_src[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ F(125000000, P_PCIE_0_PIPE_CLK, 2, 0, 0),
+ F(250000000, P_PCIE_0_PIPE_CLK, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 pcie_0_pipe_clk_src = {
+ .cmd_rcgr = 0x3e01c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_11,
+ .freq_tbl = ftbl_pcie_0_pipe_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "pcie_0_pipe_clk_src",
+ .parent_names = gcc_parent_names_11,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 pclk0_clk_src = {
+ .cmd_rcgr = 0x4d000,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_12,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "pclk0_clk_src",
+ .parent_names = gcc_parent_names_12,
+ .num_parents = 4,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_pixel_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_pdm2_clk_src[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ F(64000000, P_GPLL0_OUT_MAIN, 12.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 pdm2_clk_src = {
+ .cmd_rcgr = 0x44010,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_pdm2_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "pdm2_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_sdcc1_apps_clk_src[] = {
+ F(144000, P_XO, 16, 3, 25),
+ F(400000, P_XO, 12, 1, 4),
+ F(20000000, P_GPLL0_OUT_MAIN, 10, 1, 4),
+ F(25000000, P_GPLL0_OUT_MAIN, 16, 1, 2),
+ F(50000000, P_GPLL0_OUT_MAIN, 16, 0, 0),
+ F(100000000, P_GPLL0_OUT_MAIN, 8, 0, 0),
+ F(177777778, P_GPLL0_OUT_MAIN, 4.5, 0, 0),
+ F(192000000, P_GPLL4_OUT_MAIN, 6, 0, 0),
+ F(200000000, P_GPLL0_OUT_MAIN, 4, 0, 0),
+ F(384000000, P_GPLL4_OUT_MAIN, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 sdcc1_apps_clk_src = {
+ .cmd_rcgr = 0x42004,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_13,
+ .freq_tbl = ftbl_sdcc1_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "sdcc1_apps_clk_src",
+ .parent_names = gcc_parent_names_13,
+ .num_parents = 5,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_sdcc1_ice_core_clk_src[] = {
+ F(160000000, P_GPLL0_OUT_MAIN, 5, 0, 0),
+ F(266666667, P_GPLL0_OUT_MAIN, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 sdcc1_ice_core_clk_src = {
+ .cmd_rcgr = 0x5d000,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_3,
+ .freq_tbl = ftbl_sdcc1_ice_core_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "sdcc1_ice_core_clk_src",
+ .parent_names = gcc_parent_names_3,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_sdcc2_apps_clk_src[] = {
+ F(144000, P_XO, 16, 3, 25),
+ F(400000, P_XO, 12, 1, 4),
+ F(20000000, P_GPLL0_OUT_MAIN, 10, 1, 4),
+ F(25000000, P_GPLL0_OUT_MAIN, 16, 1, 2),
+ F(50000000, P_GPLL0_OUT_MAIN, 16, 0, 0),
+ F(100000000, P_GPLL0_OUT_MAIN, 8, 0, 0),
+ F(177777778, P_GPLL0_OUT_MAIN, 4.5, 0, 0),
+ F(200000000, P_GPLL0_OUT_MAIN, 4, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 sdcc2_apps_clk_src = {
+ .cmd_rcgr = 0x43004,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_14,
+ .freq_tbl = ftbl_sdcc2_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "sdcc2_apps_clk_src",
+ .parent_names = gcc_parent_names_14,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 usb20_mock_utmi_clk_src = {
+ .cmd_rcgr = 0x41048,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_esc0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "usb20_mock_utmi_clk_src",
+ .parent_names = gcc_parent_names_1,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_usb30_master_clk_src[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ F(100000000, P_GPLL0_OUT_MAIN, 8, 0, 0),
+ F(200000000, P_GPLL0_OUT_MAIN, 4, 0, 0),
+ F(266666667, P_GPLL0_OUT_MAIN, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 usb30_master_clk_src = {
+ .cmd_rcgr = 0x39028,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_usb30_master_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "usb30_master_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 usb30_mock_utmi_clk_src = {
+ .cmd_rcgr = 0x3901c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_esc0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "usb30_mock_utmi_clk_src",
+ .parent_names = gcc_parent_names_1,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 usb3_phy_aux_clk_src = {
+ .cmd_rcgr = 0x3903c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "usb3_phy_aux_clk_src",
+ .parent_names = gcc_parent_names_1,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_usb_hs_system_clk_src[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ F(80000000, P_GPLL0_OUT_MAIN, 10, 0, 0),
+ F(100000000, P_GPLL0_OUT_MAIN, 8, 0, 0),
+ F(133333333, P_GPLL0_OUT_MAIN, 6, 0, 0),
+ F(177777778, P_GPLL0_OUT_MAIN, 4.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 usb_hs_system_clk_src = {
+ .cmd_rcgr = 0x41010,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_3,
+ .freq_tbl = ftbl_usb_hs_system_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "usb_hs_system_clk_src",
+ .parent_names = gcc_parent_names_3,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 vsync_clk_src = {
+ .cmd_rcgr = 0x4d02c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_15,
+ .freq_tbl = ftbl_esc0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "vsync_clk_src",
+ .parent_names = gcc_parent_names_15,
+ .num_parents = 3,
+ .ops = &clk_rcg2_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_names = (const char *[]){
+ "apss_ahb_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_apss_tcu_clk = {
+ .halt_reg = 0x5b004,
+ .halt_check = BRANCH_VOTED,
+ .clkr = {
+ .enable_reg = 0x4500c,
+ .enable_mask = BIT(1),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_apss_tcu_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_bimc_gfx_clk = {
+ .halt_reg = 0x59034,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x59034,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_bimc_gfx_clk",
+ .ops = &clk_branch2_ops,
+ .parent_names = (const char *[]){
+ "gcc_apss_tcu_clk",
+ },
+
+ },
+ },
+};
+
+static struct clk_branch gcc_bimc_gpu_clk = {
+ .halt_reg = 0x59030,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x59030,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_bimc_gpu_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_bimc_mdss_clk = {
+ .halt_reg = 0x31038,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x31038,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_bimc_mdss_clk",
+ .ops = &clk_branch2_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",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_dcc_clk = {
+ .halt_reg = 0x77004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x77004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_dcc_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_dcc_xo_clk = {
+ .halt_reg = 0x77008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x77008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_dcc_xo_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_qup0_i2c_apps_clk = {
+ .halt_reg = 0x6028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x6028,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup0_i2c_apps_clk",
+ .parent_names = (const char *[]){
+ "blsp1_qup0_i2c_apps_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_qup0_spi_apps_clk = {
+ .halt_reg = 0x6024,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x6024,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup0_spi_apps_clk",
+ .parent_names = (const char *[]){
+ "blsp1_qup0_spi_apps_clk_src",
+ },
+ .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,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup1_i2c_apps_clk",
+ .parent_names = (const char *[]){
+ "blsp1_qup1_i2c_apps_clk_src",
+ },
+ .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,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup1_spi_apps_clk",
+ .parent_names = (const char *[]){
+ "blsp1_qup1_spi_apps_clk_src",
+ },
+ .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,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3010,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup2_i2c_apps_clk",
+ .parent_names = (const char *[]){
+ "blsp1_qup2_i2c_apps_clk_src",
+ },
+ .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,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x300c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup2_spi_apps_clk",
+ .parent_names = (const char *[]){
+ "blsp1_qup2_spi_apps_clk_src",
+ },
+ .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,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4020,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup3_i2c_apps_clk",
+ .parent_names = (const char *[]){
+ "blsp1_qup3_i2c_apps_clk_src",
+ },
+ .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,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x401c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup3_spi_apps_clk",
+ .parent_names = (const char *[]){
+ "blsp1_qup3_spi_apps_clk_src",
+ },
+ .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,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5020,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup4_i2c_apps_clk",
+ .parent_names = (const char *[]){
+ "blsp1_qup4_i2c_apps_clk_src",
+ },
+ .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,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x501c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup4_spi_apps_clk",
+ .parent_names = (const char *[]){
+ "blsp1_qup4_spi_apps_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_uart0_apps_clk = {
+ .halt_reg = 0x6004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x6004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_uart0_apps_clk",
+ .parent_names = (const char *[]){
+ "blsp1_uart0_apps_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_uart1_apps_clk = {
+ .halt_reg = 0x203c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x203c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_uart1_apps_clk",
+ .parent_names = (const char *[]){
+ "blsp1_uart1_apps_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_uart2_apps_clk = {
+ .halt_reg = 0x302c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x302c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_uart2_apps_clk",
+ .parent_names = (const char *[]){
+ "blsp1_uart2_apps_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_uart3_apps_clk = {
+ .halt_reg = 0x400c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x400c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_uart3_apps_clk",
+ .parent_names = (const char *[]){
+ "blsp1_uart3_apps_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp2_ahb_clk = {
+ .halt_reg = 0xb008,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x45004,
+ .enable_mask = BIT(20),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp2_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp2_qup0_i2c_apps_clk = {
+ .halt_reg = 0xc008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp2_qup0_i2c_apps_clk",
+ .parent_names = (const char *[]){
+ "blsp2_qup0_i2c_apps_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp2_qup0_spi_apps_clk = {
+ .halt_reg = 0xc004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp2_qup0_spi_apps_clk",
+ .parent_names = (const char *[]){
+ "blsp2_qup0_spi_apps_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp2_uart0_apps_clk = {
+ .halt_reg = 0xc03c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc03c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp2_uart0_apps_clk",
+ .parent_names = (const char *[]){
+ "blsp2_uart0_apps_clk_src",
+ },
+ .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",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_crypto_ahb_clk = {
+ .halt_reg = 0x16024,
+ .halt_check = BRANCH_VOTED,
+ .clkr = {
+ .enable_reg = 0x45004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_crypto_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_crypto_axi_clk = {
+ .halt_reg = 0x16020,
+ .halt_check = BRANCH_VOTED,
+ .clkr = {
+ .enable_reg = 0x45004,
+ .enable_mask = BIT(1),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_crypto_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_crypto_clk = {
+ .halt_reg = 0x1601c,
+ .halt_check = BRANCH_VOTED,
+ .clkr = {
+ .enable_reg = 0x45004,
+ .enable_mask = BIT(2),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_crypto_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_eth_axi_clk = {
+ .halt_reg = 0x4e010,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4e010,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_eth_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_eth_ptp_clk = {
+ .halt_reg = 0x4e004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4e004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_eth_ptp_clk",
+ .parent_names = (const char *[]){
+ "emac_ptp_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_eth_rgmii_clk = {
+ .halt_reg = 0x4e008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4e008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_eth_rgmii_clk",
+ .parent_names = (const char *[]){
+ "emac_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_eth_slave_ahb_clk = {
+ .halt_reg = 0x4e00c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4e00c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_eth_slave_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_geni_ir_s_clk = {
+ .halt_reg = 0xf008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xf008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_geni_ir_s_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_geni_ir_h_clk = {
+ .halt_reg = 0xf004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xf004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_geni_ir_h_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gfx_tcu_clk = {
+ .halt_reg = 0x12020,
+ .halt_check = BRANCH_VOTED,
+ .clkr = {
+ .enable_reg = 0x4500C,
+ .enable_mask = BIT(2),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gfx_tcu_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gfx_tbu_clk = {
+ .halt_reg = 0x12010,
+ .halt_check = BRANCH_VOTED,
+ .clkr = {
+ .enable_reg = 0x4500C,
+ .enable_mask = BIT(3),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gfx_tbu_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp1_clk = {
+ .halt_reg = 0x8000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gp1_clk",
+ .parent_names = (const char *[]){
+ "gp1_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp2_clk = {
+ .halt_reg = 0x9000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x9000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gp2_clk",
+ .parent_names = (const char *[]){
+ "gp2_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp3_clk = {
+ .halt_reg = 0xa000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gp3_clk",
+ .parent_names = (const char *[]){
+ "gp3_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gtcu_ahb_clk = {
+ .halt_reg = 0x12044,
+ .halt_check = BRANCH_VOTED,
+ .clkr = {
+ .enable_reg = 0x4500c,
+ .enable_mask = BIT(13),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gtcu_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_mdp_tbu_clk = {
+ .halt_reg = 0x1201c,
+ .halt_check = BRANCH_VOTED,
+ .clkr = {
+ .enable_reg = 0x4500c,
+ .enable_mask = BIT(4),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_mdp_tbu_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_mdss_ahb_clk = {
+ .halt_reg = 0x4d07c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4d07c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_mdss_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_mdss_axi_clk = {
+ .halt_reg = 0x4d080,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4d080,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_mdss_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_mdss_byte0_clk = {
+ .halt_reg = 0x4d094,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4d094,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_mdss_byte0_clk",
+ .parent_names = (const char *[]){
+ "byte0_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_mdss_esc0_clk = {
+ .halt_reg = 0x4d098,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4d098,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_mdss_esc0_clk",
+ .parent_names = (const char *[]){
+ "esc0_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_mdss_hdmi_app_clk = {
+ .halt_reg = 0x4d0d8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4d0d8,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_mdss_hdmi_app_clk",
+ .parent_names = (const char *[]){
+ "hdmi_app_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_mdss_hdmi_pclk_clk = {
+ .halt_reg = 0x4d0d4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4d0d4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_mdss_hdmi_pclk_clk",
+ .parent_names = (const char *[]){
+ "hdmi_pclk_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_mdss_mdp_clk = {
+ .halt_reg = 0x4d088,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4d088,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_mdss_mdp_clk",
+ .parent_names = (const char *[]){
+ "mdp_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_mdss_pclk0_clk = {
+ .halt_reg = 0x4d084,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4d084,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_mdss_pclk0_clk",
+ .parent_names = (const char *[]){
+ "pclk0_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_mdss_vsync_clk = {
+ .halt_reg = 0x4d090,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4d090,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_mdss_vsync_clk",
+ .parent_names = (const char *[]){
+ "vsync_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_oxili_ahb_clk = {
+ .halt_reg = 0x59028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x59028,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_oxili_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_oxili_gfx3d_clk = {
+ .halt_reg = 0x59020,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x59020,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_oxili_gfx3d_clk",
+ .parent_names = (const char *[]){
+ "gfx3d_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_aux_clk = {
+ .halt_reg = 0x3e014,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x45004,
+ .enable_mask = BIT(27),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pcie_0_aux_clk",
+ .parent_names = (const char *[]){
+ "pcie_0_aux_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_cfg_ahb_clk = {
+ .halt_reg = 0x3e008,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x45004,
+ .enable_mask = BIT(11),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pcie_0_cfg_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_mstr_axi_clk = {
+ .halt_reg = 0x3e018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x45004,
+ .enable_mask = BIT(18),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pcie_0_mstr_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_pipe_clk = {
+ .halt_reg = 0x3e00c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x45004,
+ .enable_mask = BIT(28),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pcie_0_pipe_clk",
+ .parent_names = (const char *[]){
+ "pcie_0_pipe_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_slv_axi_clk = {
+ .halt_reg = 0x3e010,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x45004,
+ .enable_mask = BIT(22),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pcie_0_slv_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcnoc_usb2_clk = {
+ .halt_reg = 0x27008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x27008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pcnoc_usb2_clk",
+ .flags = CLK_IS_CRITICAL,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcnoc_usb3_clk = {
+ .halt_reg = 0x2700c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2700c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pcnoc_usb3_clk",
+ .flags = CLK_IS_CRITICAL,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pdm2_clk = {
+ .halt_reg = 0x4400c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4400c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pdm2_clk",
+ .parent_names = (const char *[]){
+ "pdm2_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pdm_ahb_clk = {
+ .halt_reg = 0x44004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x44004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pdm_ahb_clk",
+ .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",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+/* PWM clks do not have XO as parent as src clk is a balance root */
+static struct clk_branch gcc_pwm0_xo512_clk = {
+ .halt_reg = 0x44018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x44018,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pwm0_xo512_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pwm1_xo512_clk = {
+ .halt_reg = 0x49004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x49004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pwm1_xo512_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pwm2_xo512_clk = {
+ .halt_reg = 0x4a004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4a004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pwm2_xo512_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qdss_dap_clk = {
+ .halt_reg = 0x29084,
+ .halt_check = BRANCH_VOTED,
+ .clkr = {
+ .enable_reg = 0x45004,
+ .enable_mask = BIT(21),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qdss_dap_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc1_ahb_clk = {
+ .halt_reg = 0x4201c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4201c,
+ .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 = 0x42018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x42018,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc1_apps_clk",
+ .parent_names = (const char *[]){
+ "sdcc1_apps_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc1_ice_core_clk = {
+ .halt_reg = 0x5d014,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5d014,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc1_ice_core_clk",
+ .parent_names = (const char *[]){
+ "sdcc1_ice_core_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc2_ahb_clk = {
+ .halt_reg = 0x4301c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4301c,
+ .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 = 0x43018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x43018,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc2_apps_clk",
+ .parent_names = (const char *[]){
+ "sdcc2_apps_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_smmu_cfg_clk = {
+ .halt_reg = 0x12038,
+ .halt_check = BRANCH_VOTED,
+ .clkr = {
+ .enable_reg = 0x3600C,
+ .enable_mask = BIT(12),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_smmu_cfg_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sys_noc_usb3_clk = {
+ .halt_reg = 0x26014,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x26014,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sys_noc_usb3_clk",
+ .parent_names = (const char *[]){
+ "usb30_master_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb_hs_inactivity_timers_clk = {
+ .halt_reg = 0x4100C,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4100C,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb_hs_inactivity_timers_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb20_mock_utmi_clk = {
+ .halt_reg = 0x41044,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x41044,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb20_mock_utmi_clk",
+ .parent_names = (const char *[]){
+ "usb20_mock_utmi_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb2a_phy_sleep_clk = {
+ .halt_reg = 0x4102c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4102c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb2a_phy_sleep_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_master_clk = {
+ .halt_reg = 0x3900c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3900c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb30_master_clk",
+ .parent_names = (const char *[]){
+ "usb30_master_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_mock_utmi_clk = {
+ .halt_reg = 0x39014,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x39014,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb30_mock_utmi_clk",
+ .parent_names = (const char *[]){
+ "usb30_mock_utmi_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_sleep_clk = {
+ .halt_reg = 0x39010,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x39010,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb30_sleep_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_phy_aux_clk = {
+ .halt_reg = 0x39044,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x39044,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb3_phy_aux_clk",
+ .parent_names = (const char *[]){
+ "usb3_phy_aux_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_phy_pipe_clk = {
+ .halt_check = BRANCH_HALT_SKIP,
+ .clkr = {
+ .enable_reg = 0x39018,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb3_phy_pipe_clk",
+ .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",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb_hs_system_clk = {
+ .halt_reg = 0x41004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x41004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb_hs_system_clk",
+ .parent_names = (const char *[]){
+ "usb_hs_system_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_hw *gcc_qcs404_hws[] = {
+ &cxo.hw,
+};
+
+static struct clk_regmap *gcc_qcs404_clocks[] = {
+ [GCC_APSS_AHB_CLK_SRC] = &apss_ahb_clk_src.clkr,
+ [GCC_BLSP1_QUP0_I2C_APPS_CLK_SRC] = &blsp1_qup0_i2c_apps_clk_src.clkr,
+ [GCC_BLSP1_QUP0_SPI_APPS_CLK_SRC] = &blsp1_qup0_spi_apps_clk_src.clkr,
+ [GCC_BLSP1_QUP1_I2C_APPS_CLK_SRC] = &blsp1_qup1_i2c_apps_clk_src.clkr,
+ [GCC_BLSP1_QUP1_SPI_APPS_CLK_SRC] = &blsp1_qup1_spi_apps_clk_src.clkr,
+ [GCC_BLSP1_QUP2_I2C_APPS_CLK_SRC] = &blsp1_qup2_i2c_apps_clk_src.clkr,
+ [GCC_BLSP1_QUP2_SPI_APPS_CLK_SRC] = &blsp1_qup2_spi_apps_clk_src.clkr,
+ [GCC_BLSP1_QUP3_I2C_APPS_CLK_SRC] = &blsp1_qup3_i2c_apps_clk_src.clkr,
+ [GCC_BLSP1_QUP3_SPI_APPS_CLK_SRC] = &blsp1_qup3_spi_apps_clk_src.clkr,
+ [GCC_BLSP1_QUP4_I2C_APPS_CLK_SRC] = &blsp1_qup4_i2c_apps_clk_src.clkr,
+ [GCC_BLSP1_QUP4_SPI_APPS_CLK_SRC] = &blsp1_qup4_spi_apps_clk_src.clkr,
+ [GCC_BLSP1_UART0_APPS_CLK_SRC] = &blsp1_uart0_apps_clk_src.clkr,
+ [GCC_BLSP1_UART1_APPS_CLK_SRC] = &blsp1_uart1_apps_clk_src.clkr,
+ [GCC_BLSP1_UART2_APPS_CLK_SRC] = &blsp1_uart2_apps_clk_src.clkr,
+ [GCC_BLSP1_UART3_APPS_CLK_SRC] = &blsp1_uart3_apps_clk_src.clkr,
+ [GCC_BLSP2_QUP0_I2C_APPS_CLK_SRC] = &blsp2_qup0_i2c_apps_clk_src.clkr,
+ [GCC_BLSP2_QUP0_SPI_APPS_CLK_SRC] = &blsp2_qup0_spi_apps_clk_src.clkr,
+ [GCC_BLSP2_UART0_APPS_CLK_SRC] = &blsp2_uart0_apps_clk_src.clkr,
+ [GCC_BYTE0_CLK_SRC] = &byte0_clk_src.clkr,
+ [GCC_EMAC_CLK_SRC] = &emac_clk_src.clkr,
+ [GCC_EMAC_PTP_CLK_SRC] = &emac_ptp_clk_src.clkr,
+ [GCC_ESC0_CLK_SRC] = &esc0_clk_src.clkr,
+ [GCC_APSS_AHB_CLK] = &gcc_apss_ahb_clk.clkr,
+ [GCC_BIMC_GFX_CLK] = &gcc_bimc_gfx_clk.clkr,
+ [GCC_BIMC_MDSS_CLK] = &gcc_bimc_mdss_clk.clkr,
+ [GCC_BLSP1_AHB_CLK] = &gcc_blsp1_ahb_clk.clkr,
+ [GCC_BLSP1_QUP0_I2C_APPS_CLK] = &gcc_blsp1_qup0_i2c_apps_clk.clkr,
+ [GCC_BLSP1_QUP0_SPI_APPS_CLK] = &gcc_blsp1_qup0_spi_apps_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_UART0_APPS_CLK] = &gcc_blsp1_uart0_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_BLSP2_AHB_CLK] = &gcc_blsp2_ahb_clk.clkr,
+ [GCC_BLSP2_QUP0_I2C_APPS_CLK] = &gcc_blsp2_qup0_i2c_apps_clk.clkr,
+ [GCC_BLSP2_QUP0_SPI_APPS_CLK] = &gcc_blsp2_qup0_spi_apps_clk.clkr,
+ [GCC_BLSP2_UART0_APPS_CLK] = &gcc_blsp2_uart0_apps_clk.clkr,
+ [GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr,
+ [GCC_ETH_AXI_CLK] = &gcc_eth_axi_clk.clkr,
+ [GCC_ETH_PTP_CLK] = &gcc_eth_ptp_clk.clkr,
+ [GCC_ETH_RGMII_CLK] = &gcc_eth_rgmii_clk.clkr,
+ [GCC_ETH_SLAVE_AHB_CLK] = &gcc_eth_slave_ahb_clk.clkr,
+ [GCC_GENI_IR_S_CLK] = &gcc_geni_ir_s_clk.clkr,
+ [GCC_GENI_IR_H_CLK] = &gcc_geni_ir_h_clk.clkr,
+ [GCC_GP1_CLK] = &gcc_gp1_clk.clkr,
+ [GCC_GP2_CLK] = &gcc_gp2_clk.clkr,
+ [GCC_GP3_CLK] = &gcc_gp3_clk.clkr,
+ [GCC_MDSS_AHB_CLK] = &gcc_mdss_ahb_clk.clkr,
+ [GCC_MDSS_AXI_CLK] = &gcc_mdss_axi_clk.clkr,
+ [GCC_MDSS_BYTE0_CLK] = &gcc_mdss_byte0_clk.clkr,
+ [GCC_MDSS_ESC0_CLK] = &gcc_mdss_esc0_clk.clkr,
+ [GCC_MDSS_HDMI_APP_CLK] = &gcc_mdss_hdmi_app_clk.clkr,
+ [GCC_MDSS_HDMI_PCLK_CLK] = &gcc_mdss_hdmi_pclk_clk.clkr,
+ [GCC_MDSS_MDP_CLK] = &gcc_mdss_mdp_clk.clkr,
+ [GCC_MDSS_PCLK0_CLK] = &gcc_mdss_pclk0_clk.clkr,
+ [GCC_MDSS_VSYNC_CLK] = &gcc_mdss_vsync_clk.clkr,
+ [GCC_OXILI_AHB_CLK] = &gcc_oxili_ahb_clk.clkr,
+ [GCC_OXILI_GFX3D_CLK] = &gcc_oxili_gfx3d_clk.clkr,
+ [GCC_PCIE_0_AUX_CLK] = &gcc_pcie_0_aux_clk.clkr,
+ [GCC_PCIE_0_CFG_AHB_CLK] = &gcc_pcie_0_cfg_ahb_clk.clkr,
+ [GCC_PCIE_0_MSTR_AXI_CLK] = &gcc_pcie_0_mstr_axi_clk.clkr,
+ [GCC_PCIE_0_PIPE_CLK] = &gcc_pcie_0_pipe_clk.clkr,
+ [GCC_PCIE_0_SLV_AXI_CLK] = &gcc_pcie_0_slv_axi_clk.clkr,
+ [GCC_PCNOC_USB2_CLK] = &gcc_pcnoc_usb2_clk.clkr,
+ [GCC_PCNOC_USB3_CLK] = &gcc_pcnoc_usb3_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_PWM0_XO512_CLK] = &gcc_pwm0_xo512_clk.clkr,
+ [GCC_PWM1_XO512_CLK] = &gcc_pwm1_xo512_clk.clkr,
+ [GCC_PWM2_XO512_CLK] = &gcc_pwm2_xo512_clk.clkr,
+ [GCC_SDCC1_AHB_CLK] = &gcc_sdcc1_ahb_clk.clkr,
+ [GCC_SDCC1_APPS_CLK] = &gcc_sdcc1_apps_clk.clkr,
+ [GCC_SDCC1_ICE_CORE_CLK] = &gcc_sdcc1_ice_core_clk.clkr,
+ [GCC_SDCC2_AHB_CLK] = &gcc_sdcc2_ahb_clk.clkr,
+ [GCC_SDCC2_APPS_CLK] = &gcc_sdcc2_apps_clk.clkr,
+ [GCC_SYS_NOC_USB3_CLK] = &gcc_sys_noc_usb3_clk.clkr,
+ [GCC_USB20_MOCK_UTMI_CLK] = &gcc_usb20_mock_utmi_clk.clkr,
+ [GCC_USB2A_PHY_SLEEP_CLK] = &gcc_usb2a_phy_sleep_clk.clkr,
+ [GCC_USB30_MASTER_CLK] = &gcc_usb30_master_clk.clkr,
+ [GCC_USB30_MOCK_UTMI_CLK] = &gcc_usb30_mock_utmi_clk.clkr,
+ [GCC_USB30_SLEEP_CLK] = &gcc_usb30_sleep_clk.clkr,
+ [GCC_USB3_PHY_AUX_CLK] = &gcc_usb3_phy_aux_clk.clkr,
+ [GCC_USB3_PHY_PIPE_CLK] = &gcc_usb3_phy_pipe_clk.clkr,
+ [GCC_USB_HS_PHY_CFG_AHB_CLK] = &gcc_usb_hs_phy_cfg_ahb_clk.clkr,
+ [GCC_USB_HS_SYSTEM_CLK] = &gcc_usb_hs_system_clk.clkr,
+ [GCC_GFX3D_CLK_SRC] = &gfx3d_clk_src.clkr,
+ [GCC_GP1_CLK_SRC] = &gp1_clk_src.clkr,
+ [GCC_GP2_CLK_SRC] = &gp2_clk_src.clkr,
+ [GCC_GP3_CLK_SRC] = &gp3_clk_src.clkr,
+ [GCC_GPLL0_OUT_MAIN] = &gpll0_out_main.clkr,
+ [GCC_GPLL0_AO_OUT_MAIN] = &gpll0_ao_out_main.clkr,
+ [GCC_GPLL0_SLEEP_CLK_SRC] = &gpll0_sleep_clk_src.clkr,
+ [GCC_GPLL1_OUT_MAIN] = &gpll1_out_main.clkr,
+ [GCC_GPLL3_OUT_MAIN] = &gpll3_out_main.clkr,
+ [GCC_GPLL4_OUT_MAIN] = &gpll4_out_main.clkr,
+ [GCC_GPLL6] = &gpll6.clkr,
+ [GCC_GPLL6_OUT_AUX] = &gpll6_out_aux,
+ [GCC_HDMI_APP_CLK_SRC] = &hdmi_app_clk_src.clkr,
+ [GCC_HDMI_PCLK_CLK_SRC] = &hdmi_pclk_clk_src.clkr,
+ [GCC_MDP_CLK_SRC] = &mdp_clk_src.clkr,
+ [GCC_PCIE_0_AUX_CLK_SRC] = &pcie_0_aux_clk_src.clkr,
+ [GCC_PCIE_0_PIPE_CLK_SRC] = &pcie_0_pipe_clk_src.clkr,
+ [GCC_PCLK0_CLK_SRC] = &pclk0_clk_src.clkr,
+ [GCC_PDM2_CLK_SRC] = &pdm2_clk_src.clkr,
+ [GCC_SDCC1_APPS_CLK_SRC] = &sdcc1_apps_clk_src.clkr,
+ [GCC_SDCC1_ICE_CORE_CLK_SRC] = &sdcc1_ice_core_clk_src.clkr,
+ [GCC_SDCC2_APPS_CLK_SRC] = &sdcc2_apps_clk_src.clkr,
+ [GCC_USB20_MOCK_UTMI_CLK_SRC] = &usb20_mock_utmi_clk_src.clkr,
+ [GCC_USB30_MASTER_CLK_SRC] = &usb30_master_clk_src.clkr,
+ [GCC_USB30_MOCK_UTMI_CLK_SRC] = &usb30_mock_utmi_clk_src.clkr,
+ [GCC_USB3_PHY_AUX_CLK_SRC] = &usb3_phy_aux_clk_src.clkr,
+ [GCC_USB_HS_SYSTEM_CLK_SRC] = &usb_hs_system_clk_src.clkr,
+ [GCC_VSYNC_CLK_SRC] = &vsync_clk_src.clkr,
+ [GCC_USB_HS_INACTIVITY_TIMERS_CLK] =
+ &gcc_usb_hs_inactivity_timers_clk.clkr,
+ [GCC_BIMC_GPU_CLK] = &gcc_bimc_gpu_clk.clkr,
+ [GCC_GTCU_AHB_CLK] = &gcc_gtcu_ahb_clk.clkr,
+ [GCC_GFX_TCU_CLK] = &gcc_gfx_tcu_clk.clkr,
+ [GCC_GFX_TBU_CLK] = &gcc_gfx_tbu_clk.clkr,
+ [GCC_SMMU_CFG_CLK] = &gcc_smmu_cfg_clk.clkr,
+ [GCC_APSS_TCU_CLK] = &gcc_apss_tcu_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_MDP_TBU_CLK] = &gcc_mdp_tbu_clk.clkr,
+ [GCC_QDSS_DAP_CLK] = &gcc_qdss_dap_clk.clkr,
+ [GCC_DCC_CLK] = &gcc_dcc_clk.clkr,
+ [GCC_DCC_XO_CLK] = &gcc_dcc_xo_clk.clkr,
+};
+
+static const struct qcom_reset_map gcc_qcs404_resets[] = {
+ [GCC_GENI_IR_BCR] = { 0x0F000 },
+ [GCC_USB_HS_BCR] = { 0x41000 },
+ [GCC_USB2_HS_PHY_ONLY_BCR] = { 0x41034 },
+ [GCC_QUSB2_PHY_BCR] = { 0x4103c },
+ [GCC_USB_HS_PHY_CFG_AHB_BCR] = { 0x0000c, 1 },
+ [GCC_USB2A_PHY_BCR] = { 0x0000c, 0 },
+ [GCC_USB3_PHY_BCR] = { 0x39004 },
+ [GCC_USB_30_BCR] = { 0x39000 },
+ [GCC_USB3PHY_PHY_BCR] = { 0x39008 },
+ [GCC_PCIE_0_BCR] = { 0x3e000 },
+ [GCC_PCIE_0_PHY_BCR] = { 0x3e004 },
+ [GCC_PCIE_0_LINK_DOWN_BCR] = { 0x3e038 },
+ [GCC_PCIEPHY_0_PHY_BCR] = { 0x3e03c },
+ [GCC_EMAC_BCR] = { 0x4e000 },
+};
+
+static const struct regmap_config gcc_qcs404_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x7f000,
+ .fast_io = true,
+};
+
+static const struct qcom_cc_desc gcc_qcs404_desc = {
+ .config = &gcc_qcs404_regmap_config,
+ .clks = gcc_qcs404_clocks,
+ .num_clks = ARRAY_SIZE(gcc_qcs404_clocks),
+ .resets = gcc_qcs404_resets,
+ .num_resets = ARRAY_SIZE(gcc_qcs404_resets),
+};
+
+static const struct of_device_id gcc_qcs404_match_table[] = {
+ { .compatible = "qcom,gcc-qcs404" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, gcc_qcs404_match_table);
+
+static int gcc_qcs404_probe(struct platform_device *pdev)
+{
+ struct regmap *regmap;
+ int ret, i;
+
+ regmap = qcom_cc_map(pdev, &gcc_qcs404_desc);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ clk_alpha_pll_configure(&gpll3_out_main, regmap, &gpll3_config);
+
+ for (i = 0; i < ARRAY_SIZE(gcc_qcs404_hws); i++) {
+ ret = devm_clk_hw_register(&pdev->dev, gcc_qcs404_hws[i]);
+ if (ret)
+ return ret;
+ }
+
+ return qcom_cc_really_probe(pdev, &gcc_qcs404_desc, regmap);
+}
+
+static struct platform_driver gcc_qcs404_driver = {
+ .probe = gcc_qcs404_probe,
+ .driver = {
+ .name = "gcc-qcs404",
+ .of_match_table = gcc_qcs404_match_table,
+ },
+};
+
+static int __init gcc_qcs404_init(void)
+{
+ return platform_driver_register(&gcc_qcs404_driver);
+}
+subsys_initcall(gcc_qcs404_init);
+
+static void __exit gcc_qcs404_exit(void)
+{
+ platform_driver_unregister(&gcc_qcs404_driver);
+}
+module_exit(gcc_qcs404_exit);
+
+MODULE_DESCRIPTION("Qualcomm GCC QCS404 Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/qcom/gcc-sdm660.c b/drivers/clk/qcom/gcc-sdm660.c
new file mode 100644
index 000000000000..ba239ea4c842
--- /dev/null
+++ b/drivers/clk/qcom/gcc-sdm660.c
@@ -0,0 +1,2480 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018, Craig Tatlor.
+ */
+
+#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-sdm660.h>
+
+#include "common.h"
+#include "clk-regmap.h"
+#include "clk-alpha-pll.h"
+#include "clk-rcg.h"
+#include "clk-branch.h"
+#include "reset.h"
+#include "gdsc.h"
+
+#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
+
+enum {
+ P_XO,
+ P_SLEEP_CLK,
+ P_GPLL0,
+ P_GPLL1,
+ P_GPLL4,
+ P_GPLL0_EARLY_DIV,
+ P_GPLL1_EARLY_DIV,
+};
+
+static const struct parent_map gcc_parent_map_xo_gpll0_gpll0_early_div[] = {
+ { P_XO, 0 },
+ { P_GPLL0, 1 },
+ { P_GPLL0_EARLY_DIV, 6 },
+};
+
+static const char * const gcc_parent_names_xo_gpll0_gpll0_early_div[] = {
+ "xo",
+ "gpll0",
+ "gpll0_early_div",
+};
+
+static const struct parent_map gcc_parent_map_xo_gpll0[] = {
+ { P_XO, 0 },
+ { P_GPLL0, 1 },
+};
+
+static const char * const gcc_parent_names_xo_gpll0[] = {
+ "xo",
+ "gpll0",
+};
+
+static const struct parent_map gcc_parent_map_xo_gpll0_sleep_clk_gpll0_early_div[] = {
+ { P_XO, 0 },
+ { P_GPLL0, 1 },
+ { P_SLEEP_CLK, 5 },
+ { P_GPLL0_EARLY_DIV, 6 },
+};
+
+static const char * const gcc_parent_names_xo_gpll0_sleep_clk_gpll0_early_div[] = {
+ "xo",
+ "gpll0",
+ "sleep_clk",
+ "gpll0_early_div",
+};
+
+static const struct parent_map gcc_parent_map_xo_sleep_clk[] = {
+ { P_XO, 0 },
+ { P_SLEEP_CLK, 5 },
+};
+
+static const char * const gcc_parent_names_xo_sleep_clk[] = {
+ "xo",
+ "sleep_clk",
+};
+
+static const struct parent_map gcc_parent_map_xo_gpll4[] = {
+ { P_XO, 0 },
+ { P_GPLL4, 5 },
+};
+
+static const char * const gcc_parent_names_xo_gpll4[] = {
+ "xo",
+ "gpll4",
+};
+
+static const struct parent_map gcc_parent_map_xo_gpll0_gpll0_early_div_gpll1_gpll4_gpll1_early_div[] = {
+ { P_XO, 0 },
+ { P_GPLL0, 1 },
+ { P_GPLL0_EARLY_DIV, 3 },
+ { P_GPLL1, 4 },
+ { P_GPLL4, 5 },
+ { P_GPLL1_EARLY_DIV, 6 },
+};
+
+static const char * const gcc_parent_names_xo_gpll0_gpll0_early_div_gpll1_gpll4_gpll1_early_div[] = {
+ "xo",
+ "gpll0",
+ "gpll0_early_div",
+ "gpll1",
+ "gpll4",
+ "gpll1_early_div",
+};
+
+static const struct parent_map gcc_parent_map_xo_gpll0_gpll4_gpll0_early_div[] = {
+ { P_XO, 0 },
+ { P_GPLL0, 1 },
+ { P_GPLL4, 5 },
+ { P_GPLL0_EARLY_DIV, 6 },
+};
+
+static const char * const gcc_parent_names_xo_gpll0_gpll4_gpll0_early_div[] = {
+ "xo",
+ "gpll0",
+ "gpll4",
+ "gpll0_early_div",
+};
+
+static const struct parent_map gcc_parent_map_xo_gpll0_gpll0_early_div_gpll4[] = {
+ { P_XO, 0 },
+ { P_GPLL0, 1 },
+ { P_GPLL0_EARLY_DIV, 2 },
+ { P_GPLL4, 5 },
+};
+
+static const char * const gcc_parent_names_xo_gpll0_gpll0_early_div_gpll4[] = {
+ "xo",
+ "gpll0",
+ "gpll0_early_div",
+ "gpll4",
+};
+
+static struct clk_fixed_factor xo = {
+ .mult = 1,
+ .div = 1,
+ .hw.init = &(struct clk_init_data){
+ .name = "xo",
+ .parent_names = (const char *[]){ "xo_board" },
+ .num_parents = 1,
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
+static struct clk_alpha_pll gpll0_early = {
+ .offset = 0x0,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll0_early",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ },
+ },
+};
+
+static struct clk_fixed_factor gpll0_early_div = {
+ .mult = 1,
+ .div = 2,
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll0_early_div",
+ .parent_names = (const char *[]){ "gpll0_early" },
+ .num_parents = 1,
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
+static struct clk_alpha_pll_postdiv gpll0 = {
+ .offset = 0x00000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gpll0",
+ .parent_names = (const char *[]){ "gpll0_early" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_ops,
+ },
+};
+
+static struct clk_alpha_pll gpll1_early = {
+ .offset = 0x1000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(1),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll1_early",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ },
+ },
+};
+
+static struct clk_fixed_factor gpll1_early_div = {
+ .mult = 1,
+ .div = 2,
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll1_early_div",
+ .parent_names = (const char *[]){ "gpll1_early" },
+ .num_parents = 1,
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
+static struct clk_alpha_pll_postdiv gpll1 = {
+ .offset = 0x1000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gpll1",
+ .parent_names = (const char *[]){ "gpll1_early" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_ops,
+ },
+};
+
+static struct clk_alpha_pll gpll4_early = {
+ .offset = 0x77000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(4),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll4_early",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll_postdiv gpll4 = {
+ .offset = 0x77000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .clkr.hw.init = &(struct clk_init_data)
+ {
+ .name = "gpll4",
+ .parent_names = (const char *[]) { "gpll4_early" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_blsp1_qup1_i2c_apps_clk_src[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ F(50000000, P_GPLL0, 12, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 blsp1_qup1_i2c_apps_clk_src = {
+ .cmd_rcgr = 0x19020,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+ .freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup1_i2c_apps_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_blsp1_qup1_spi_apps_clk_src[] = {
+ F(960000, P_XO, 10, 1, 2),
+ F(4800000, P_XO, 4, 0, 0),
+ F(9600000, P_XO, 2, 0, 0),
+ F(15000000, P_GPLL0, 10, 1, 4),
+ F(19200000, P_XO, 1, 0, 0),
+ F(25000000, P_GPLL0, 12, 1, 2),
+ F(50000000, P_GPLL0, 12, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 blsp1_qup1_spi_apps_clk_src = {
+ .cmd_rcgr = 0x1900c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+ .freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup1_spi_apps_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_qup2_i2c_apps_clk_src = {
+ .cmd_rcgr = 0x1b020,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+ .freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup2_i2c_apps_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_qup2_spi_apps_clk_src = {
+ .cmd_rcgr = 0x1b00c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+ .freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup2_spi_apps_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_qup3_i2c_apps_clk_src = {
+ .cmd_rcgr = 0x1d020,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+ .freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup3_i2c_apps_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_qup3_spi_apps_clk_src = {
+ .cmd_rcgr = 0x1d00c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+ .freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup3_spi_apps_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_qup4_i2c_apps_clk_src = {
+ .cmd_rcgr = 0x1f020,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+ .freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup4_i2c_apps_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_qup4_spi_apps_clk_src = {
+ .cmd_rcgr = 0x1f00c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+ .freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup4_spi_apps_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_blsp1_uart1_apps_clk_src[] = {
+ F(3686400, P_GPLL0, 1, 96, 15625),
+ F(7372800, P_GPLL0, 1, 192, 15625),
+ F(14745600, P_GPLL0, 1, 384, 15625),
+ F(16000000, P_GPLL0, 5, 2, 15),
+ F(19200000, P_XO, 1, 0, 0),
+ F(24000000, P_GPLL0, 5, 1, 5),
+ F(32000000, P_GPLL0, 1, 4, 75),
+ F(40000000, P_GPLL0, 15, 0, 0),
+ F(46400000, P_GPLL0, 1, 29, 375),
+ F(48000000, P_GPLL0, 12.5, 0, 0),
+ F(51200000, P_GPLL0, 1, 32, 375),
+ F(56000000, P_GPLL0, 1, 7, 75),
+ F(58982400, P_GPLL0, 1, 1536, 15625),
+ F(60000000, P_GPLL0, 10, 0, 0),
+ F(63157895, P_GPLL0, 9.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 blsp1_uart1_apps_clk_src = {
+ .cmd_rcgr = 0x1a00c,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+ .freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_uart1_apps_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_uart2_apps_clk_src = {
+ .cmd_rcgr = 0x1c00c,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+ .freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_uart2_apps_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp2_qup1_i2c_apps_clk_src = {
+ .cmd_rcgr = 0x26020,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+ .freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp2_qup1_i2c_apps_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp2_qup1_spi_apps_clk_src = {
+ .cmd_rcgr = 0x2600c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+ .freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp2_qup1_spi_apps_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp2_qup2_i2c_apps_clk_src = {
+ .cmd_rcgr = 0x28020,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+ .freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp2_qup2_i2c_apps_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp2_qup2_spi_apps_clk_src = {
+ .cmd_rcgr = 0x2800c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+ .freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp2_qup2_spi_apps_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp2_qup3_i2c_apps_clk_src = {
+ .cmd_rcgr = 0x2a020,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+ .freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp2_qup3_i2c_apps_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp2_qup3_spi_apps_clk_src = {
+ .cmd_rcgr = 0x2a00c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+ .freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp2_qup3_spi_apps_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp2_qup4_i2c_apps_clk_src = {
+ .cmd_rcgr = 0x2c020,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+ .freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp2_qup4_i2c_apps_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp2_qup4_spi_apps_clk_src = {
+ .cmd_rcgr = 0x2c00c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+ .freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp2_qup4_spi_apps_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp2_uart1_apps_clk_src = {
+ .cmd_rcgr = 0x2700c,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+ .freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp2_uart1_apps_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp2_uart2_apps_clk_src = {
+ .cmd_rcgr = 0x2900c,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+ .freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp2_uart2_apps_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gp1_clk_src[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ F(100000000, P_GPLL0, 6, 0, 0),
+ F(200000000, P_GPLL0, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gp1_clk_src = {
+ .cmd_rcgr = 0x64004,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll0_sleep_clk_gpll0_early_div,
+ .freq_tbl = ftbl_gp1_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gp1_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll0_sleep_clk_gpll0_early_div,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gp2_clk_src = {
+ .cmd_rcgr = 0x65004,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll0_sleep_clk_gpll0_early_div,
+ .freq_tbl = ftbl_gp1_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gp2_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll0_sleep_clk_gpll0_early_div,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gp3_clk_src = {
+ .cmd_rcgr = 0x66004,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll0_sleep_clk_gpll0_early_div,
+ .freq_tbl = ftbl_gp1_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gp3_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll0_sleep_clk_gpll0_early_div,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_hmss_gpll0_clk_src[] = {
+ F(300000000, P_GPLL0, 2, 0, 0),
+ F(600000000, P_GPLL0, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 hmss_gpll0_clk_src = {
+ .cmd_rcgr = 0x4805c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+ .freq_tbl = ftbl_hmss_gpll0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "hmss_gpll0_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_hmss_gpll4_clk_src[] = {
+ F(384000000, P_GPLL4, 4, 0, 0),
+ F(768000000, P_GPLL4, 2, 0, 0),
+ F(1536000000, P_GPLL4, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 hmss_gpll4_clk_src = {
+ .cmd_rcgr = 0x48074,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll4,
+ .freq_tbl = ftbl_hmss_gpll4_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "hmss_gpll4_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll4,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_hmss_rbcpr_clk_src[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 hmss_rbcpr_clk_src = {
+ .cmd_rcgr = 0x48044,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+ .freq_tbl = ftbl_hmss_rbcpr_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "hmss_rbcpr_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_pdm2_clk_src[] = {
+ F(60000000, P_GPLL0, 10, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 pdm2_clk_src = {
+ .cmd_rcgr = 0x33010,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+ .freq_tbl = ftbl_pdm2_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "pdm2_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_qspi_ser_clk_src[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ F(80200000, P_GPLL1_EARLY_DIV, 5, 0, 0),
+ F(160400000, P_GPLL1, 5, 0, 0),
+ F(267333333, P_GPLL1, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 qspi_ser_clk_src = {
+ .cmd_rcgr = 0x4d00c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div_gpll1_gpll4_gpll1_early_div,
+ .freq_tbl = ftbl_qspi_ser_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "qspi_ser_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div_gpll1_gpll4_gpll1_early_div,
+ .num_parents = 6,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_sdcc1_apps_clk_src[] = {
+ F(144000, P_XO, 16, 3, 25),
+ F(400000, P_XO, 12, 1, 4),
+ F(20000000, P_GPLL0_EARLY_DIV, 5, 1, 3),
+ F(25000000, P_GPLL0_EARLY_DIV, 6, 1, 2),
+ F(50000000, P_GPLL0_EARLY_DIV, 6, 0, 0),
+ F(100000000, P_GPLL0, 6, 0, 0),
+ F(192000000, P_GPLL4, 8, 0, 0),
+ F(384000000, P_GPLL4, 4, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 sdcc1_apps_clk_src = {
+ .cmd_rcgr = 0x1602c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll0_gpll4_gpll0_early_div,
+ .freq_tbl = ftbl_sdcc1_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "sdcc1_apps_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll0_gpll4_gpll0_early_div,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_sdcc1_ice_core_clk_src[] = {
+ F(75000000, P_GPLL0_EARLY_DIV, 4, 0, 0),
+ F(150000000, P_GPLL0, 4, 0, 0),
+ F(200000000, P_GPLL0, 3, 0, 0),
+ F(300000000, P_GPLL0, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 sdcc1_ice_core_clk_src = {
+ .cmd_rcgr = 0x16010,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+ .freq_tbl = ftbl_sdcc1_ice_core_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "sdcc1_ice_core_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_sdcc2_apps_clk_src[] = {
+ F(144000, P_XO, 16, 3, 25),
+ F(400000, P_XO, 12, 1, 4),
+ F(20000000, P_GPLL0_EARLY_DIV, 5, 1, 3),
+ F(25000000, P_GPLL0_EARLY_DIV, 6, 1, 2),
+ F(50000000, P_GPLL0_EARLY_DIV, 6, 0, 0),
+ F(100000000, P_GPLL0, 6, 0, 0),
+ F(192000000, P_GPLL4, 8, 0, 0),
+ F(200000000, P_GPLL0, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 sdcc2_apps_clk_src = {
+ .cmd_rcgr = 0x14010,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div_gpll4,
+ .freq_tbl = ftbl_sdcc2_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "sdcc2_apps_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div_gpll4,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_ufs_axi_clk_src[] = {
+ F(50000000, P_GPLL0_EARLY_DIV, 6, 0, 0),
+ F(100000000, P_GPLL0, 6, 0, 0),
+ F(150000000, P_GPLL0, 4, 0, 0),
+ F(200000000, P_GPLL0, 3, 0, 0),
+ F(240000000, P_GPLL0, 2.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 ufs_axi_clk_src = {
+ .cmd_rcgr = 0x75018,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+ .freq_tbl = ftbl_ufs_axi_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "ufs_axi_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_ufs_ice_core_clk_src[] = {
+ F(75000000, P_GPLL0_EARLY_DIV, 4, 0, 0),
+ F(150000000, P_GPLL0, 4, 0, 0),
+ F(300000000, P_GPLL0, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 ufs_ice_core_clk_src = {
+ .cmd_rcgr = 0x76010,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+ .freq_tbl = ftbl_ufs_ice_core_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "ufs_ice_core_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 ufs_phy_aux_clk_src = {
+ .cmd_rcgr = 0x76044,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_sleep_clk,
+ .freq_tbl = ftbl_hmss_rbcpr_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "ufs_phy_aux_clk_src",
+ .parent_names = gcc_parent_names_xo_sleep_clk,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_ufs_unipro_core_clk_src[] = {
+ F(37500000, P_GPLL0_EARLY_DIV, 8, 0, 0),
+ F(75000000, P_GPLL0, 8, 0, 0),
+ F(150000000, P_GPLL0, 4, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 ufs_unipro_core_clk_src = {
+ .cmd_rcgr = 0x76028,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+ .freq_tbl = ftbl_ufs_unipro_core_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "ufs_unipro_core_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_usb20_master_clk_src[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ F(60000000, P_GPLL0, 10, 0, 0),
+ F(120000000, P_GPLL0, 5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 usb20_master_clk_src = {
+ .cmd_rcgr = 0x2f010,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+ .freq_tbl = ftbl_usb20_master_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "usb20_master_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_usb20_mock_utmi_clk_src[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ F(60000000, P_GPLL0, 10, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 usb20_mock_utmi_clk_src = {
+ .cmd_rcgr = 0x2f024,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+ .freq_tbl = ftbl_usb20_mock_utmi_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "usb20_mock_utmi_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_usb30_master_clk_src[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ F(66666667, P_GPLL0_EARLY_DIV, 4.5, 0, 0),
+ F(120000000, P_GPLL0, 5, 0, 0),
+ F(133333333, P_GPLL0, 4.5, 0, 0),
+ F(150000000, P_GPLL0, 4, 0, 0),
+ F(200000000, P_GPLL0, 3, 0, 0),
+ F(240000000, P_GPLL0, 2.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 usb30_master_clk_src = {
+ .cmd_rcgr = 0xf014,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+ .freq_tbl = ftbl_usb30_master_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "usb30_master_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_usb30_mock_utmi_clk_src[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ F(40000000, P_GPLL0_EARLY_DIV, 7.5, 0, 0),
+ F(60000000, P_GPLL0, 10, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 usb30_mock_utmi_clk_src = {
+ .cmd_rcgr = 0xf028,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+ .freq_tbl = ftbl_usb30_mock_utmi_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "usb30_mock_utmi_clk_src",
+ .parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_usb3_phy_aux_clk_src[] = {
+ F(1200000, P_XO, 16, 0, 0),
+ F(19200000, P_XO, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 usb3_phy_aux_clk_src = {
+ .cmd_rcgr = 0x5000c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo_sleep_clk,
+ .freq_tbl = ftbl_usb3_phy_aux_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "usb3_phy_aux_clk_src",
+ .parent_names = gcc_parent_names_xo_sleep_clk,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_branch gcc_aggre2_ufs_axi_clk = {
+ .halt_reg = 0x75034,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x75034,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_aggre2_ufs_axi_clk",
+ .parent_names = (const char *[]){
+ "ufs_axi_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_aggre2_usb3_axi_clk = {
+ .halt_reg = 0xf03c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xf03c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_aggre2_usb3_axi_clk",
+ .parent_names = (const char *[]){
+ "usb30_master_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_bimc_gfx_clk = {
+ .halt_reg = 0x7106c,
+ .halt_check = BRANCH_VOTED,
+ .clkr = {
+ .enable_reg = 0x7106c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_bimc_gfx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_bimc_hmss_axi_clk = {
+ .halt_reg = 0x48004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52004,
+ .enable_mask = BIT(22),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_bimc_hmss_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_bimc_mss_q6_axi_clk = {
+ .halt_reg = 0x4401c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4401c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_bimc_mss_q6_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_ahb_clk = {
+ .halt_reg = 0x17004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52004,
+ .enable_mask = BIT(17),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_qup1_i2c_apps_clk = {
+ .halt_reg = 0x19008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x19008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup1_i2c_apps_clk",
+ .parent_names = (const char *[]){
+ "blsp1_qup1_i2c_apps_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_qup1_spi_apps_clk = {
+ .halt_reg = 0x19004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x19004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup1_spi_apps_clk",
+ .parent_names = (const char *[]){
+ "blsp1_qup1_spi_apps_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_qup2_i2c_apps_clk = {
+ .halt_reg = 0x1b008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1b008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup2_i2c_apps_clk",
+ .parent_names = (const char *[]){
+ "blsp1_qup2_i2c_apps_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_qup2_spi_apps_clk = {
+ .halt_reg = 0x1b004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1b004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup2_spi_apps_clk",
+ .parent_names = (const char *[]){
+ "blsp1_qup2_spi_apps_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_qup3_i2c_apps_clk = {
+ .halt_reg = 0x1d008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1d008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup3_i2c_apps_clk",
+ .parent_names = (const char *[]){
+ "blsp1_qup3_i2c_apps_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_qup3_spi_apps_clk = {
+ .halt_reg = 0x1d004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1d004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup3_spi_apps_clk",
+ .parent_names = (const char *[]){
+ "blsp1_qup3_spi_apps_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_qup4_i2c_apps_clk = {
+ .halt_reg = 0x1f008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1f008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup4_i2c_apps_clk",
+ .parent_names = (const char *[]){
+ "blsp1_qup4_i2c_apps_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_qup4_spi_apps_clk = {
+ .halt_reg = 0x1f004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1f004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup4_spi_apps_clk",
+ .parent_names = (const char *[]){
+ "blsp1_qup4_spi_apps_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_uart1_apps_clk = {
+ .halt_reg = 0x1a004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1a004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_uart1_apps_clk",
+ .parent_names = (const char *[]){
+ "blsp1_uart1_apps_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_uart2_apps_clk = {
+ .halt_reg = 0x1c004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1c004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_uart2_apps_clk",
+ .parent_names = (const char *[]){
+ "blsp1_uart2_apps_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp2_ahb_clk = {
+ .halt_reg = 0x25004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52004,
+ .enable_mask = BIT(15),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp2_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp2_qup1_i2c_apps_clk = {
+ .halt_reg = 0x26008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x26008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp2_qup1_i2c_apps_clk",
+ .parent_names = (const char *[]){
+ "blsp2_qup1_i2c_apps_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp2_qup1_spi_apps_clk = {
+ .halt_reg = 0x26004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x26004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp2_qup1_spi_apps_clk",
+ .parent_names = (const char *[]){
+ "blsp2_qup1_spi_apps_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp2_qup2_i2c_apps_clk = {
+ .halt_reg = 0x28008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x28008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp2_qup2_i2c_apps_clk",
+ .parent_names = (const char *[]){
+ "blsp2_qup2_i2c_apps_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp2_qup2_spi_apps_clk = {
+ .halt_reg = 0x28004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x28004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp2_qup2_spi_apps_clk",
+ .parent_names = (const char *[]){
+ "blsp2_qup2_spi_apps_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp2_qup3_i2c_apps_clk = {
+ .halt_reg = 0x2a008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2a008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp2_qup3_i2c_apps_clk",
+ .parent_names = (const char *[]){
+ "blsp2_qup3_i2c_apps_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp2_qup3_spi_apps_clk = {
+ .halt_reg = 0x2a004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2a004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp2_qup3_spi_apps_clk",
+ .parent_names = (const char *[]){
+ "blsp2_qup3_spi_apps_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp2_qup4_i2c_apps_clk = {
+ .halt_reg = 0x2c008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2c008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp2_qup4_i2c_apps_clk",
+ .parent_names = (const char *[]){
+ "blsp2_qup4_i2c_apps_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp2_qup4_spi_apps_clk = {
+ .halt_reg = 0x2c004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2c004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp2_qup4_spi_apps_clk",
+ .parent_names = (const char *[]){
+ "blsp2_qup4_spi_apps_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp2_uart1_apps_clk = {
+ .halt_reg = 0x27004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x27004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp2_uart1_apps_clk",
+ .parent_names = (const char *[]){
+ "blsp2_uart1_apps_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp2_uart2_apps_clk = {
+ .halt_reg = 0x29004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x29004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp2_uart2_apps_clk",
+ .parent_names = (const char *[]){
+ "blsp2_uart2_apps_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_boot_rom_ahb_clk = {
+ .halt_reg = 0x38004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52004,
+ .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_cfg_noc_usb2_axi_clk = {
+ .halt_reg = 0x5058,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5058,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_cfg_noc_usb2_axi_clk",
+ .parent_names = (const char *[]){
+ "usb20_master_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cfg_noc_usb3_axi_clk = {
+ .halt_reg = 0x5018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5018,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_cfg_noc_usb3_axi_clk",
+ .parent_names = (const char *[]){
+ "usb30_master_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_dcc_ahb_clk = {
+ .halt_reg = 0x84004,
+ .clkr = {
+ .enable_reg = 0x84004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_dcc_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp1_clk = {
+ .halt_reg = 0x64000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x64000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gp1_clk",
+ .parent_names = (const char *[]){
+ "gp1_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp2_clk = {
+ .halt_reg = 0x65000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x65000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gp2_clk",
+ .parent_names = (const char *[]){
+ "gp2_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp3_clk = {
+ .halt_reg = 0x66000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x66000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gp3_clk",
+ .parent_names = (const char *[]){
+ "gp3_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_bimc_gfx_clk = {
+ .halt_reg = 0x71010,
+ .halt_check = BRANCH_VOTED,
+ .clkr = {
+ .enable_reg = 0x71010,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gpu_bimc_gfx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_cfg_ahb_clk = {
+ .halt_reg = 0x71004,
+ .halt_check = BRANCH_VOTED,
+ .clkr = {
+ .enable_reg = 0x71004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gpu_cfg_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_gpll0_clk = {
+ .halt_reg = 0x5200c,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x5200c,
+ .enable_mask = BIT(4),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gpu_gpll0_clk",
+ .parent_names = (const char *[]){
+ "gpll0",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_gpll0_div_clk = {
+ .halt_reg = 0x5200c,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x5200c,
+ .enable_mask = BIT(3),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gpu_gpll0_div_clk",
+ .parent_names = (const char *[]){
+ "gpll0_early_div",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_hmss_dvm_bus_clk = {
+ .halt_reg = 0x4808c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4808c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_hmss_dvm_bus_clk",
+ .ops = &clk_branch2_ops,
+ .flags = CLK_IGNORE_UNUSED,
+ },
+ },
+};
+
+static struct clk_branch gcc_hmss_rbcpr_clk = {
+ .halt_reg = 0x48008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x48008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_hmss_rbcpr_clk",
+ .parent_names = (const char *[]){
+ "hmss_rbcpr_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_mmss_gpll0_clk = {
+ .halt_reg = 0x5200c,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x5200c,
+ .enable_mask = BIT(1),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_mmss_gpll0_clk",
+ .parent_names = (const char *[]){
+ "gpll0",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_mmss_gpll0_div_clk = {
+ .halt_reg = 0x5200c,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x5200c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_mmss_gpll0_div_clk",
+ .parent_names = (const char *[]){
+ "gpll0_early_div",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_mmss_noc_cfg_ahb_clk = {
+ .halt_reg = 0x9004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x9004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_mmss_noc_cfg_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_mmss_sys_noc_axi_clk = {
+ .halt_reg = 0x9000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x9000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_mmss_sys_noc_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_mss_cfg_ahb_clk = {
+ .halt_reg = 0x8a000,
+ .clkr = {
+ .enable_reg = 0x8a000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_mss_cfg_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_mss_mnoc_bimc_axi_clk = {
+ .halt_reg = 0x8a004,
+ .clkr = {
+ .enable_reg = 0x8a004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_mss_mnoc_bimc_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_mss_q6_bimc_axi_clk = {
+ .halt_reg = 0x8a040,
+ .clkr = {
+ .enable_reg = 0x8a040,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_mss_q6_bimc_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_mss_snoc_axi_clk = {
+ .halt_reg = 0x8a03c,
+ .clkr = {
+ .enable_reg = 0x8a03c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_mss_snoc_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pdm2_clk = {
+ .halt_reg = 0x3300c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3300c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pdm2_clk",
+ .parent_names = (const char *[]){
+ "pdm2_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pdm_ahb_clk = {
+ .halt_reg = 0x33004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x33004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pdm_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_prng_ahb_clk = {
+ .halt_reg = 0x34004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52004,
+ .enable_mask = BIT(13),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_prng_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qspi_ahb_clk = {
+ .halt_reg = 0x4d004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4d004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qspi_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qspi_ser_clk = {
+ .halt_reg = 0x4d008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4d008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qspi_ser_clk",
+ .parent_names = (const char *[]){
+ "qspi_ser_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_rx0_usb2_clkref_clk = {
+ .halt_reg = 0x88018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x88018,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_rx0_usb2_clkref_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_rx1_usb2_clkref_clk = {
+ .halt_reg = 0x88014,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x88014,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_rx1_usb2_clkref_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc1_ahb_clk = {
+ .halt_reg = 0x16008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x16008,
+ .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 = 0x16004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x16004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc1_apps_clk",
+ .parent_names = (const char *[]){
+ "sdcc1_apps_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc1_ice_core_clk = {
+ .halt_reg = 0x1600c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1600c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc1_ice_core_clk",
+ .parent_names = (const char *[]){
+ "sdcc1_ice_core_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc2_ahb_clk = {
+ .halt_reg = 0x14008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x14008,
+ .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 = 0x14004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x14004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc2_apps_clk",
+ .parent_names = (const char *[]){
+ "sdcc2_apps_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_ahb_clk = {
+ .halt_reg = 0x7500c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x7500c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_axi_clk = {
+ .halt_reg = 0x75008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x75008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_axi_clk",
+ .parent_names = (const char *[]){
+ "ufs_axi_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_clkref_clk = {
+ .halt_reg = 0x88008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x88008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_clkref_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_ice_core_clk = {
+ .halt_reg = 0x7600c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x7600c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_ice_core_clk",
+ .parent_names = (const char *[]){
+ "ufs_ice_core_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_aux_clk = {
+ .halt_reg = 0x76040,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x76040,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_phy_aux_clk",
+ .parent_names = (const char *[]){
+ "ufs_phy_aux_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_rx_symbol_0_clk = {
+ .halt_reg = 0x75014,
+ .halt_check = BRANCH_HALT_SKIP,
+ .clkr = {
+ .enable_reg = 0x75014,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_rx_symbol_0_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_rx_symbol_1_clk = {
+ .halt_reg = 0x7605c,
+ .halt_check = BRANCH_HALT_SKIP,
+ .clkr = {
+ .enable_reg = 0x7605c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_rx_symbol_1_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_tx_symbol_0_clk = {
+ .halt_reg = 0x75010,
+ .halt_check = BRANCH_HALT_SKIP,
+ .clkr = {
+ .enable_reg = 0x75010,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_tx_symbol_0_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_unipro_core_clk = {
+ .halt_reg = 0x76008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x76008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_unipro_core_clk",
+ .parent_names = (const char *[]){
+ "ufs_unipro_core_clk_src",
+ },
+ .flags = CLK_SET_RATE_PARENT,
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb20_master_clk = {
+ .halt_reg = 0x2f004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2f004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb20_master_clk",
+ .parent_names = (const char *[]){
+ "usb20_master_clk_src"
+ },
+ .flags = CLK_SET_RATE_PARENT,
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb20_mock_utmi_clk = {
+ .halt_reg = 0x2f00c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2f00c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb20_mock_utmi_clk",
+ .parent_names = (const char *[]){
+ "usb20_mock_utmi_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb20_sleep_clk = {
+ .halt_reg = 0x2f008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2f008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb20_sleep_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_master_clk = {
+ .halt_reg = 0xf008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xf008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb30_master_clk",
+ .parent_names = (const char *[]){
+ "usb30_master_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_mock_utmi_clk = {
+ .halt_reg = 0xf010,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xf010,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb30_mock_utmi_clk",
+ .parent_names = (const char *[]){
+ "usb30_mock_utmi_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_sleep_clk = {
+ .halt_reg = 0xf00c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xf00c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb30_sleep_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_clkref_clk = {
+ .halt_reg = 0x8800c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8800c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb3_clkref_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_phy_aux_clk = {
+ .halt_reg = 0x50000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x50000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb3_phy_aux_clk",
+ .parent_names = (const char *[]){
+ "usb3_phy_aux_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_phy_pipe_clk = {
+ .halt_reg = 0x50004,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x50004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb3_phy_pipe_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb_phy_cfg_ahb2phy_clk = {
+ .halt_reg = 0x6a004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x6a004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb_phy_cfg_ahb2phy_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct gdsc ufs_gdsc = {
+ .gdscr = 0x75004,
+ .gds_hw_ctrl = 0x0,
+ .pd = {
+ .name = "ufs_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = VOTABLE,
+};
+
+static struct gdsc usb_30_gdsc = {
+ .gdscr = 0xf004,
+ .gds_hw_ctrl = 0x0,
+ .pd = {
+ .name = "usb_30_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = VOTABLE,
+};
+
+static struct gdsc pcie_0_gdsc = {
+ .gdscr = 0x6b004,
+ .gds_hw_ctrl = 0x0,
+ .pd = {
+ .name = "pcie_0_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = VOTABLE,
+};
+
+static struct clk_hw *gcc_sdm660_hws[] = {
+ &xo.hw,
+ &gpll0_early_div.hw,
+ &gpll1_early_div.hw,
+};
+
+static struct clk_regmap *gcc_sdm660_clocks[] = {
+ [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_UART1_APPS_CLK_SRC] = &blsp1_uart1_apps_clk_src.clkr,
+ [BLSP1_UART2_APPS_CLK_SRC] = &blsp1_uart2_apps_clk_src.clkr,
+ [BLSP2_QUP1_I2C_APPS_CLK_SRC] = &blsp2_qup1_i2c_apps_clk_src.clkr,
+ [BLSP2_QUP1_SPI_APPS_CLK_SRC] = &blsp2_qup1_spi_apps_clk_src.clkr,
+ [BLSP2_QUP2_I2C_APPS_CLK_SRC] = &blsp2_qup2_i2c_apps_clk_src.clkr,
+ [BLSP2_QUP2_SPI_APPS_CLK_SRC] = &blsp2_qup2_spi_apps_clk_src.clkr,
+ [BLSP2_QUP3_I2C_APPS_CLK_SRC] = &blsp2_qup3_i2c_apps_clk_src.clkr,
+ [BLSP2_QUP3_SPI_APPS_CLK_SRC] = &blsp2_qup3_spi_apps_clk_src.clkr,
+ [BLSP2_QUP4_I2C_APPS_CLK_SRC] = &blsp2_qup4_i2c_apps_clk_src.clkr,
+ [BLSP2_QUP4_SPI_APPS_CLK_SRC] = &blsp2_qup4_spi_apps_clk_src.clkr,
+ [BLSP2_UART1_APPS_CLK_SRC] = &blsp2_uart1_apps_clk_src.clkr,
+ [BLSP2_UART2_APPS_CLK_SRC] = &blsp2_uart2_apps_clk_src.clkr,
+ [GCC_AGGRE2_UFS_AXI_CLK] = &gcc_aggre2_ufs_axi_clk.clkr,
+ [GCC_AGGRE2_USB3_AXI_CLK] = &gcc_aggre2_usb3_axi_clk.clkr,
+ [GCC_BIMC_GFX_CLK] = &gcc_bimc_gfx_clk.clkr,
+ [GCC_BIMC_HMSS_AXI_CLK] = &gcc_bimc_hmss_axi_clk.clkr,
+ [GCC_BIMC_MSS_Q6_AXI_CLK] = &gcc_bimc_mss_q6_axi_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_UART1_APPS_CLK] = &gcc_blsp1_uart1_apps_clk.clkr,
+ [GCC_BLSP1_UART2_APPS_CLK] = &gcc_blsp1_uart2_apps_clk.clkr,
+ [GCC_BLSP2_AHB_CLK] = &gcc_blsp2_ahb_clk.clkr,
+ [GCC_BLSP2_QUP1_I2C_APPS_CLK] = &gcc_blsp2_qup1_i2c_apps_clk.clkr,
+ [GCC_BLSP2_QUP1_SPI_APPS_CLK] = &gcc_blsp2_qup1_spi_apps_clk.clkr,
+ [GCC_BLSP2_QUP2_I2C_APPS_CLK] = &gcc_blsp2_qup2_i2c_apps_clk.clkr,
+ [GCC_BLSP2_QUP2_SPI_APPS_CLK] = &gcc_blsp2_qup2_spi_apps_clk.clkr,
+ [GCC_BLSP2_QUP3_I2C_APPS_CLK] = &gcc_blsp2_qup3_i2c_apps_clk.clkr,
+ [GCC_BLSP2_QUP3_SPI_APPS_CLK] = &gcc_blsp2_qup3_spi_apps_clk.clkr,
+ [GCC_BLSP2_QUP4_I2C_APPS_CLK] = &gcc_blsp2_qup4_i2c_apps_clk.clkr,
+ [GCC_BLSP2_QUP4_SPI_APPS_CLK] = &gcc_blsp2_qup4_spi_apps_clk.clkr,
+ [GCC_BLSP2_UART1_APPS_CLK] = &gcc_blsp2_uart1_apps_clk.clkr,
+ [GCC_BLSP2_UART2_APPS_CLK] = &gcc_blsp2_uart2_apps_clk.clkr,
+ [GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr,
+ [GCC_CFG_NOC_USB2_AXI_CLK] = &gcc_cfg_noc_usb2_axi_clk.clkr,
+ [GCC_CFG_NOC_USB3_AXI_CLK] = &gcc_cfg_noc_usb3_axi_clk.clkr,
+ [GCC_DCC_AHB_CLK] = &gcc_dcc_ahb_clk.clkr,
+ [GCC_GP1_CLK] = &gcc_gp1_clk.clkr,
+ [GCC_GP2_CLK] = &gcc_gp2_clk.clkr,
+ [GCC_GP3_CLK] = &gcc_gp3_clk.clkr,
+ [GCC_GPU_BIMC_GFX_CLK] = &gcc_gpu_bimc_gfx_clk.clkr,
+ [GCC_GPU_CFG_AHB_CLK] = &gcc_gpu_cfg_ahb_clk.clkr,
+ [GCC_GPU_GPLL0_CLK] = &gcc_gpu_gpll0_clk.clkr,
+ [GCC_GPU_GPLL0_DIV_CLK] = &gcc_gpu_gpll0_div_clk.clkr,
+ [GCC_HMSS_DVM_BUS_CLK] = &gcc_hmss_dvm_bus_clk.clkr,
+ [GCC_HMSS_RBCPR_CLK] = &gcc_hmss_rbcpr_clk.clkr,
+ [GCC_MMSS_GPLL0_CLK] = &gcc_mmss_gpll0_clk.clkr,
+ [GCC_MMSS_GPLL0_DIV_CLK] = &gcc_mmss_gpll0_div_clk.clkr,
+ [GCC_MMSS_NOC_CFG_AHB_CLK] = &gcc_mmss_noc_cfg_ahb_clk.clkr,
+ [GCC_MMSS_SYS_NOC_AXI_CLK] = &gcc_mmss_sys_noc_axi_clk.clkr,
+ [GCC_MSS_CFG_AHB_CLK] = &gcc_mss_cfg_ahb_clk.clkr,
+ [GCC_MSS_MNOC_BIMC_AXI_CLK] = &gcc_mss_mnoc_bimc_axi_clk.clkr,
+ [GCC_MSS_Q6_BIMC_AXI_CLK] = &gcc_mss_q6_bimc_axi_clk.clkr,
+ [GCC_MSS_SNOC_AXI_CLK] = &gcc_mss_snoc_axi_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_QSPI_AHB_CLK] = &gcc_qspi_ahb_clk.clkr,
+ [GCC_QSPI_SER_CLK] = &gcc_qspi_ser_clk.clkr,
+ [GCC_RX0_USB2_CLKREF_CLK] = &gcc_rx0_usb2_clkref_clk.clkr,
+ [GCC_RX1_USB2_CLKREF_CLK] = &gcc_rx1_usb2_clkref_clk.clkr,
+ [GCC_SDCC1_AHB_CLK] = &gcc_sdcc1_ahb_clk.clkr,
+ [GCC_SDCC1_APPS_CLK] = &gcc_sdcc1_apps_clk.clkr,
+ [GCC_SDCC1_ICE_CORE_CLK] = &gcc_sdcc1_ice_core_clk.clkr,
+ [GCC_SDCC2_AHB_CLK] = &gcc_sdcc2_ahb_clk.clkr,
+ [GCC_SDCC2_APPS_CLK] = &gcc_sdcc2_apps_clk.clkr,
+ [GCC_UFS_AHB_CLK] = &gcc_ufs_ahb_clk.clkr,
+ [GCC_UFS_AXI_CLK] = &gcc_ufs_axi_clk.clkr,
+ [GCC_UFS_CLKREF_CLK] = &gcc_ufs_clkref_clk.clkr,
+ [GCC_UFS_ICE_CORE_CLK] = &gcc_ufs_ice_core_clk.clkr,
+ [GCC_UFS_PHY_AUX_CLK] = &gcc_ufs_phy_aux_clk.clkr,
+ [GCC_UFS_RX_SYMBOL_0_CLK] = &gcc_ufs_rx_symbol_0_clk.clkr,
+ [GCC_UFS_RX_SYMBOL_1_CLK] = &gcc_ufs_rx_symbol_1_clk.clkr,
+ [GCC_UFS_TX_SYMBOL_0_CLK] = &gcc_ufs_tx_symbol_0_clk.clkr,
+ [GCC_UFS_UNIPRO_CORE_CLK] = &gcc_ufs_unipro_core_clk.clkr,
+ [GCC_USB20_MASTER_CLK] = &gcc_usb20_master_clk.clkr,
+ [GCC_USB20_MOCK_UTMI_CLK] = &gcc_usb20_mock_utmi_clk.clkr,
+ [GCC_USB20_SLEEP_CLK] = &gcc_usb20_sleep_clk.clkr,
+ [GCC_USB30_MASTER_CLK] = &gcc_usb30_master_clk.clkr,
+ [GCC_USB30_MOCK_UTMI_CLK] = &gcc_usb30_mock_utmi_clk.clkr,
+ [GCC_USB30_SLEEP_CLK] = &gcc_usb30_sleep_clk.clkr,
+ [GCC_USB3_CLKREF_CLK] = &gcc_usb3_clkref_clk.clkr,
+ [GCC_USB3_PHY_AUX_CLK] = &gcc_usb3_phy_aux_clk.clkr,
+ [GCC_USB3_PHY_PIPE_CLK] = &gcc_usb3_phy_pipe_clk.clkr,
+ [GCC_USB_PHY_CFG_AHB2PHY_CLK] = &gcc_usb_phy_cfg_ahb2phy_clk.clkr,
+ [GP1_CLK_SRC] = &gp1_clk_src.clkr,
+ [GP2_CLK_SRC] = &gp2_clk_src.clkr,
+ [GP3_CLK_SRC] = &gp3_clk_src.clkr,
+ [GPLL0] = &gpll0.clkr,
+ [GPLL0_EARLY] = &gpll0_early.clkr,
+ [GPLL1] = &gpll1.clkr,
+ [GPLL1_EARLY] = &gpll1_early.clkr,
+ [GPLL4] = &gpll4.clkr,
+ [GPLL4_EARLY] = &gpll4_early.clkr,
+ [HMSS_GPLL0_CLK_SRC] = &hmss_gpll0_clk_src.clkr,
+ [HMSS_GPLL4_CLK_SRC] = &hmss_gpll4_clk_src.clkr,
+ [HMSS_RBCPR_CLK_SRC] = &hmss_rbcpr_clk_src.clkr,
+ [PDM2_CLK_SRC] = &pdm2_clk_src.clkr,
+ [QSPI_SER_CLK_SRC] = &qspi_ser_clk_src.clkr,
+ [SDCC1_APPS_CLK_SRC] = &sdcc1_apps_clk_src.clkr,
+ [SDCC1_ICE_CORE_CLK_SRC] = &sdcc1_ice_core_clk_src.clkr,
+ [SDCC2_APPS_CLK_SRC] = &sdcc2_apps_clk_src.clkr,
+ [UFS_AXI_CLK_SRC] = &ufs_axi_clk_src.clkr,
+ [UFS_ICE_CORE_CLK_SRC] = &ufs_ice_core_clk_src.clkr,
+ [UFS_PHY_AUX_CLK_SRC] = &ufs_phy_aux_clk_src.clkr,
+ [UFS_UNIPRO_CORE_CLK_SRC] = &ufs_unipro_core_clk_src.clkr,
+ [USB20_MASTER_CLK_SRC] = &usb20_master_clk_src.clkr,
+ [USB20_MOCK_UTMI_CLK_SRC] = &usb20_mock_utmi_clk_src.clkr,
+ [USB30_MASTER_CLK_SRC] = &usb30_master_clk_src.clkr,
+ [USB30_MOCK_UTMI_CLK_SRC] = &usb30_mock_utmi_clk_src.clkr,
+ [USB3_PHY_AUX_CLK_SRC] = &usb3_phy_aux_clk_src.clkr,
+};
+
+static struct gdsc *gcc_sdm660_gdscs[] = {
+ [UFS_GDSC] = &ufs_gdsc,
+ [USB_30_GDSC] = &usb_30_gdsc,
+ [PCIE_0_GDSC] = &pcie_0_gdsc,
+};
+
+static const struct qcom_reset_map gcc_sdm660_resets[] = {
+ [GCC_QUSB2PHY_PRIM_BCR] = { 0x12000 },
+ [GCC_QUSB2PHY_SEC_BCR] = { 0x12004 },
+ [GCC_UFS_BCR] = { 0x75000 },
+ [GCC_USB3_DP_PHY_BCR] = { 0x50028 },
+ [GCC_USB3_PHY_BCR] = { 0x50020 },
+ [GCC_USB3PHY_PHY_BCR] = { 0x50024 },
+ [GCC_USB_20_BCR] = { 0x2f000 },
+ [GCC_USB_30_BCR] = { 0xf000 },
+ [GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x6a000 },
+};
+
+static const struct regmap_config gcc_sdm660_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x94000,
+ .fast_io = true,
+};
+
+static const struct qcom_cc_desc gcc_sdm660_desc = {
+ .config = &gcc_sdm660_regmap_config,
+ .clks = gcc_sdm660_clocks,
+ .num_clks = ARRAY_SIZE(gcc_sdm660_clocks),
+ .resets = gcc_sdm660_resets,
+ .num_resets = ARRAY_SIZE(gcc_sdm660_resets),
+ .gdscs = gcc_sdm660_gdscs,
+ .num_gdscs = ARRAY_SIZE(gcc_sdm660_gdscs),
+};
+
+static const struct of_device_id gcc_sdm660_match_table[] = {
+ { .compatible = "qcom,gcc-sdm630" },
+ { .compatible = "qcom,gcc-sdm660" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, gcc_sdm660_match_table);
+
+static int gcc_sdm660_probe(struct platform_device *pdev)
+{
+ int i, ret;
+ struct regmap *regmap;
+
+ regmap = qcom_cc_map(pdev, &gcc_sdm660_desc);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ /*
+ * Set the HMSS_AHB_CLK_SLEEP_ENA bit to allow the hmss_ahb_clk to be
+ * turned off by hardware during certain apps low power modes.
+ */
+ ret = regmap_update_bits(regmap, 0x52008, BIT(21), BIT(21));
+ if (ret)
+ return ret;
+
+ /* Register the hws */
+ for (i = 0; i < ARRAY_SIZE(gcc_sdm660_hws); i++) {
+ ret = devm_clk_hw_register(&pdev->dev, gcc_sdm660_hws[i]);
+ if (ret)
+ return ret;
+ }
+
+ return qcom_cc_really_probe(pdev, &gcc_sdm660_desc, regmap);
+}
+
+static struct platform_driver gcc_sdm660_driver = {
+ .probe = gcc_sdm660_probe,
+ .driver = {
+ .name = "gcc-sdm660",
+ .of_match_table = gcc_sdm660_match_table,
+ },
+};
+
+static int __init gcc_sdm660_init(void)
+{
+ return platform_driver_register(&gcc_sdm660_driver);
+}
+core_initcall_sync(gcc_sdm660_init);
+
+static void __exit gcc_sdm660_exit(void)
+{
+ platform_driver_unregister(&gcc_sdm660_driver);
+}
+module_exit(gcc_sdm660_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("QCOM GCC sdm660 Driver");
diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c
index fa1a196350f1..f133b7f5652f 100644
--- a/drivers/clk/qcom/gcc-sdm845.c
+++ b/drivers/clk/qcom/gcc-sdm845.c
@@ -99,22 +99,6 @@ static const char * const gcc_parent_names_4[] = {
"core_bi_pll_test_se",
};
-static const struct parent_map gcc_parent_map_5[] = {
- { P_BI_TCXO, 0 },
- { P_GPLL0_OUT_MAIN, 1 },
- { P_GPLL4_OUT_MAIN, 5 },
- { P_GPLL0_OUT_EVEN, 6 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
-};
-
-static const char * const gcc_parent_names_5[] = {
- "bi_tcxo",
- "gpll0",
- "gpll4",
- "gpll0_out_even",
- "core_bi_pll_test_se",
-};
-
static const struct parent_map gcc_parent_map_6[] = {
{ P_BI_TCXO, 0 },
{ P_GPLL0_OUT_MAIN, 1 },
@@ -356,6 +340,28 @@ static struct clk_rcg2 gcc_pcie_phy_refgen_clk_src = {
},
};
+static const struct freq_tbl ftbl_gcc_qspi_core_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0),
+ F(150000000, P_GPLL0_OUT_MAIN, 4, 0, 0),
+ F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_qspi_core_clk_src = {
+ .cmd_rcgr = 0x4b008,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qspi_core_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_qspi_core_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 4,
+ .ops = &clk_rcg2_floor_ops,
+ },
+};
+
static const struct freq_tbl ftbl_gcc_pdm2_clk_src[] = {
F(9600000, P_BI_TCXO, 2, 0, 0),
F(19200000, P_BI_TCXO, 1, 0, 0),
@@ -396,18 +402,27 @@ static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = {
{ }
};
+static struct clk_init_data gcc_qupv3_wrap0_s0_clk_init = {
+ .name = "gcc_qupv3_wrap0_s0_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 4,
+ .ops = &clk_rcg2_shared_ops,
+};
+
static struct clk_rcg2 gcc_qupv3_wrap0_s0_clk_src = {
.cmd_rcgr = 0x17034,
.mnd_width = 16,
.hid_width = 5,
.parent_map = gcc_parent_map_0,
.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
- .clkr.hw.init = &(struct clk_init_data){
- .name = "gcc_qupv3_wrap0_s0_clk_src",
- .parent_names = gcc_parent_names_0,
- .num_parents = 4,
- .ops = &clk_rcg2_shared_ops,
- },
+ .clkr.hw.init = &gcc_qupv3_wrap0_s0_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s1_clk_init = {
+ .name = "gcc_qupv3_wrap0_s1_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 4,
+ .ops = &clk_rcg2_shared_ops,
};
static struct clk_rcg2 gcc_qupv3_wrap0_s1_clk_src = {
@@ -416,12 +431,14 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s1_clk_src = {
.hid_width = 5,
.parent_map = gcc_parent_map_0,
.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
- .clkr.hw.init = &(struct clk_init_data){
- .name = "gcc_qupv3_wrap0_s1_clk_src",
- .parent_names = gcc_parent_names_0,
- .num_parents = 4,
- .ops = &clk_rcg2_shared_ops,
- },
+ .clkr.hw.init = &gcc_qupv3_wrap0_s1_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s2_clk_init = {
+ .name = "gcc_qupv3_wrap0_s2_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 4,
+ .ops = &clk_rcg2_shared_ops,
};
static struct clk_rcg2 gcc_qupv3_wrap0_s2_clk_src = {
@@ -430,12 +447,14 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s2_clk_src = {
.hid_width = 5,
.parent_map = gcc_parent_map_0,
.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
- .clkr.hw.init = &(struct clk_init_data){
- .name = "gcc_qupv3_wrap0_s2_clk_src",
- .parent_names = gcc_parent_names_0,
- .num_parents = 4,
- .ops = &clk_rcg2_shared_ops,
- },
+ .clkr.hw.init = &gcc_qupv3_wrap0_s2_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s3_clk_init = {
+ .name = "gcc_qupv3_wrap0_s3_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 4,
+ .ops = &clk_rcg2_shared_ops,
};
static struct clk_rcg2 gcc_qupv3_wrap0_s3_clk_src = {
@@ -444,12 +463,14 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s3_clk_src = {
.hid_width = 5,
.parent_map = gcc_parent_map_0,
.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
- .clkr.hw.init = &(struct clk_init_data){
- .name = "gcc_qupv3_wrap0_s3_clk_src",
- .parent_names = gcc_parent_names_0,
- .num_parents = 4,
- .ops = &clk_rcg2_shared_ops,
- },
+ .clkr.hw.init = &gcc_qupv3_wrap0_s3_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s4_clk_init = {
+ .name = "gcc_qupv3_wrap0_s4_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 4,
+ .ops = &clk_rcg2_shared_ops,
};
static struct clk_rcg2 gcc_qupv3_wrap0_s4_clk_src = {
@@ -458,12 +479,14 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s4_clk_src = {
.hid_width = 5,
.parent_map = gcc_parent_map_0,
.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
- .clkr.hw.init = &(struct clk_init_data){
- .name = "gcc_qupv3_wrap0_s4_clk_src",
- .parent_names = gcc_parent_names_0,
- .num_parents = 4,
- .ops = &clk_rcg2_shared_ops,
- },
+ .clkr.hw.init = &gcc_qupv3_wrap0_s4_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s5_clk_init = {
+ .name = "gcc_qupv3_wrap0_s5_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 4,
+ .ops = &clk_rcg2_shared_ops,
};
static struct clk_rcg2 gcc_qupv3_wrap0_s5_clk_src = {
@@ -472,12 +495,14 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s5_clk_src = {
.hid_width = 5,
.parent_map = gcc_parent_map_0,
.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
- .clkr.hw.init = &(struct clk_init_data){
- .name = "gcc_qupv3_wrap0_s5_clk_src",
- .parent_names = gcc_parent_names_0,
- .num_parents = 4,
- .ops = &clk_rcg2_shared_ops,
- },
+ .clkr.hw.init = &gcc_qupv3_wrap0_s5_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s6_clk_init = {
+ .name = "gcc_qupv3_wrap0_s6_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 4,
+ .ops = &clk_rcg2_shared_ops,
};
static struct clk_rcg2 gcc_qupv3_wrap0_s6_clk_src = {
@@ -486,12 +511,14 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s6_clk_src = {
.hid_width = 5,
.parent_map = gcc_parent_map_0,
.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
- .clkr.hw.init = &(struct clk_init_data){
- .name = "gcc_qupv3_wrap0_s6_clk_src",
- .parent_names = gcc_parent_names_0,
- .num_parents = 4,
- .ops = &clk_rcg2_shared_ops,
- },
+ .clkr.hw.init = &gcc_qupv3_wrap0_s6_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s7_clk_init = {
+ .name = "gcc_qupv3_wrap0_s7_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 4,
+ .ops = &clk_rcg2_shared_ops,
};
static struct clk_rcg2 gcc_qupv3_wrap0_s7_clk_src = {
@@ -500,12 +527,14 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s7_clk_src = {
.hid_width = 5,
.parent_map = gcc_parent_map_0,
.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
- .clkr.hw.init = &(struct clk_init_data){
- .name = "gcc_qupv3_wrap0_s7_clk_src",
- .parent_names = gcc_parent_names_0,
- .num_parents = 4,
- .ops = &clk_rcg2_shared_ops,
- },
+ .clkr.hw.init = &gcc_qupv3_wrap0_s7_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s0_clk_init = {
+ .name = "gcc_qupv3_wrap1_s0_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 4,
+ .ops = &clk_rcg2_shared_ops,
};
static struct clk_rcg2 gcc_qupv3_wrap1_s0_clk_src = {
@@ -514,12 +543,14 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s0_clk_src = {
.hid_width = 5,
.parent_map = gcc_parent_map_0,
.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
- .clkr.hw.init = &(struct clk_init_data){
- .name = "gcc_qupv3_wrap1_s0_clk_src",
- .parent_names = gcc_parent_names_0,
- .num_parents = 4,
- .ops = &clk_rcg2_shared_ops,
- },
+ .clkr.hw.init = &gcc_qupv3_wrap1_s0_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s1_clk_init = {
+ .name = "gcc_qupv3_wrap1_s1_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 4,
+ .ops = &clk_rcg2_shared_ops,
};
static struct clk_rcg2 gcc_qupv3_wrap1_s1_clk_src = {
@@ -528,12 +559,14 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s1_clk_src = {
.hid_width = 5,
.parent_map = gcc_parent_map_0,
.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
- .clkr.hw.init = &(struct clk_init_data){
- .name = "gcc_qupv3_wrap1_s1_clk_src",
- .parent_names = gcc_parent_names_0,
- .num_parents = 4,
- .ops = &clk_rcg2_shared_ops,
- },
+ .clkr.hw.init = &gcc_qupv3_wrap1_s1_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s2_clk_init = {
+ .name = "gcc_qupv3_wrap1_s2_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 4,
+ .ops = &clk_rcg2_shared_ops,
};
static struct clk_rcg2 gcc_qupv3_wrap1_s2_clk_src = {
@@ -542,12 +575,14 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s2_clk_src = {
.hid_width = 5,
.parent_map = gcc_parent_map_0,
.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
- .clkr.hw.init = &(struct clk_init_data){
- .name = "gcc_qupv3_wrap1_s2_clk_src",
- .parent_names = gcc_parent_names_0,
- .num_parents = 4,
- .ops = &clk_rcg2_shared_ops,
- },
+ .clkr.hw.init = &gcc_qupv3_wrap1_s2_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s3_clk_init = {
+ .name = "gcc_qupv3_wrap1_s3_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 4,
+ .ops = &clk_rcg2_shared_ops,
};
static struct clk_rcg2 gcc_qupv3_wrap1_s3_clk_src = {
@@ -556,12 +591,14 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s3_clk_src = {
.hid_width = 5,
.parent_map = gcc_parent_map_0,
.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
- .clkr.hw.init = &(struct clk_init_data){
- .name = "gcc_qupv3_wrap1_s3_clk_src",
- .parent_names = gcc_parent_names_0,
- .num_parents = 4,
- .ops = &clk_rcg2_shared_ops,
- },
+ .clkr.hw.init = &gcc_qupv3_wrap1_s3_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s4_clk_init = {
+ .name = "gcc_qupv3_wrap1_s4_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 4,
+ .ops = &clk_rcg2_shared_ops,
};
static struct clk_rcg2 gcc_qupv3_wrap1_s4_clk_src = {
@@ -570,12 +607,14 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s4_clk_src = {
.hid_width = 5,
.parent_map = gcc_parent_map_0,
.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
- .clkr.hw.init = &(struct clk_init_data){
- .name = "gcc_qupv3_wrap1_s4_clk_src",
- .parent_names = gcc_parent_names_0,
- .num_parents = 4,
- .ops = &clk_rcg2_shared_ops,
- },
+ .clkr.hw.init = &gcc_qupv3_wrap1_s4_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s5_clk_init = {
+ .name = "gcc_qupv3_wrap1_s5_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 4,
+ .ops = &clk_rcg2_shared_ops,
};
static struct clk_rcg2 gcc_qupv3_wrap1_s5_clk_src = {
@@ -584,12 +623,14 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s5_clk_src = {
.hid_width = 5,
.parent_map = gcc_parent_map_0,
.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
- .clkr.hw.init = &(struct clk_init_data){
- .name = "gcc_qupv3_wrap1_s5_clk_src",
- .parent_names = gcc_parent_names_0,
- .num_parents = 4,
- .ops = &clk_rcg2_shared_ops,
- },
+ .clkr.hw.init = &gcc_qupv3_wrap1_s5_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s6_clk_init = {
+ .name = "gcc_qupv3_wrap1_s6_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 4,
+ .ops = &clk_rcg2_shared_ops,
};
static struct clk_rcg2 gcc_qupv3_wrap1_s6_clk_src = {
@@ -598,12 +639,14 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s6_clk_src = {
.hid_width = 5,
.parent_map = gcc_parent_map_0,
.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
- .clkr.hw.init = &(struct clk_init_data){
- .name = "gcc_qupv3_wrap1_s6_clk_src",
- .parent_names = gcc_parent_names_0,
- .num_parents = 4,
- .ops = &clk_rcg2_shared_ops,
- },
+ .clkr.hw.init = &gcc_qupv3_wrap1_s6_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s7_clk_init = {
+ .name = "gcc_qupv3_wrap1_s7_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 4,
+ .ops = &clk_rcg2_shared_ops,
};
static struct clk_rcg2 gcc_qupv3_wrap1_s7_clk_src = {
@@ -612,12 +655,7 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s7_clk_src = {
.hid_width = 5,
.parent_map = gcc_parent_map_0,
.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
- .clkr.hw.init = &(struct clk_init_data){
- .name = "gcc_qupv3_wrap1_s7_clk_src",
- .parent_names = gcc_parent_names_0,
- .num_parents = 4,
- .ops = &clk_rcg2_shared_ops,
- },
+ .clkr.hw.init = &gcc_qupv3_wrap1_s7_clk_init,
};
static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = {
@@ -1933,6 +1971,37 @@ static struct clk_branch gcc_qmip_video_ahb_clk = {
},
};
+static struct clk_branch gcc_qspi_cnoc_periph_ahb_clk = {
+ .halt_reg = 0x4b000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4b000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qspi_cnoc_periph_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qspi_core_clk = {
+ .halt_reg = 0x4b004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4b004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qspi_core_clk",
+ .parent_names = (const char *[]){
+ "gcc_qspi_core_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
static struct clk_branch gcc_qupv3_wrap0_s0_clk = {
.halt_reg = 0x17030,
.halt_check = BRANCH_HALT_VOTED,
@@ -3381,6 +3450,9 @@ static struct clk_regmap *gcc_sdm845_clocks[] = {
[GPLL4] = &gpll4.clkr,
[GCC_CPUSS_DVM_BUS_CLK] = &gcc_cpuss_dvm_bus_clk.clkr,
[GCC_CPUSS_GNOC_CLK] = &gcc_cpuss_gnoc_clk.clkr,
+ [GCC_QSPI_CORE_CLK_SRC] = &gcc_qspi_core_clk_src.clkr,
+ [GCC_QSPI_CORE_CLK] = &gcc_qspi_core_clk.clkr,
+ [GCC_QSPI_CNOC_PERIPH_AHB_CLK] = &gcc_qspi_cnoc_periph_ahb_clk.clkr,
};
static const struct qcom_reset_map gcc_sdm845_resets[] = {
@@ -3458,9 +3530,29 @@ static const struct of_device_id gcc_sdm845_match_table[] = {
};
MODULE_DEVICE_TABLE(of, gcc_sdm845_match_table);
+static const struct clk_rcg_dfs_data gcc_dfs_clocks[] = {
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s0_clk),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s1_clk),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s2_clk),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s3_clk),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s4_clk),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s5_clk),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s6_clk),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s7_clk),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s0_clk),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s1_clk),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s2_clk),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s3_clk),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s4_clk),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s5_clk),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s6_clk),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s7_clk),
+};
+
static int gcc_sdm845_probe(struct platform_device *pdev)
{
struct regmap *regmap;
+ int ret;
regmap = qcom_cc_map(pdev, &gcc_sdm845_desc);
if (IS_ERR(regmap))
@@ -3470,6 +3562,11 @@ static int gcc_sdm845_probe(struct platform_device *pdev)
regmap_update_bits(regmap, 0x09ffc, 0x3, 0x3);
regmap_update_bits(regmap, 0x71028, 0x3, 0x3);
+ 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_sdm845_desc, regmap);
}
diff --git a/drivers/clk/qcom/hfpll.c b/drivers/clk/qcom/hfpll.c
new file mode 100644
index 000000000000..a6de7101430c
--- /dev/null
+++ b/drivers/clk/qcom/hfpll.c
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018, The Linux Foundation. All rights reserved.
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/regmap.h>
+
+#include "clk-regmap.h"
+#include "clk-hfpll.h"
+
+static const struct hfpll_data hdata = {
+ .mode_reg = 0x00,
+ .l_reg = 0x04,
+ .m_reg = 0x08,
+ .n_reg = 0x0c,
+ .user_reg = 0x10,
+ .config_reg = 0x14,
+ .config_val = 0x430405d,
+ .status_reg = 0x1c,
+ .lock_bit = 16,
+
+ .user_val = 0x8,
+ .user_vco_mask = 0x100000,
+ .low_vco_max_rate = 1248000000,
+ .min_rate = 537600000UL,
+ .max_rate = 2900000000UL,
+};
+
+static const struct of_device_id qcom_hfpll_match_table[] = {
+ { .compatible = "qcom,hfpll" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, qcom_hfpll_match_table);
+
+static const struct regmap_config hfpll_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x30,
+ .fast_io = true,
+};
+
+static int qcom_hfpll_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct device *dev = &pdev->dev;
+ void __iomem *base;
+ struct regmap *regmap;
+ struct clk_hfpll *h;
+ struct clk_init_data init = {
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_ops_hfpll,
+ };
+
+ h = devm_kzalloc(dev, sizeof(*h), GFP_KERNEL);
+ if (!h)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ regmap = devm_regmap_init_mmio(&pdev->dev, base, &hfpll_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ if (of_property_read_string_index(dev->of_node, "clock-output-names",
+ 0, &init.name))
+ return -ENODEV;
+
+ h->d = &hdata;
+ h->clkr.hw.init = &init;
+ spin_lock_init(&h->lock);
+
+ return devm_clk_register_regmap(&pdev->dev, &h->clkr);
+}
+
+static struct platform_driver qcom_hfpll_driver = {
+ .probe = qcom_hfpll_probe,
+ .driver = {
+ .name = "qcom-hfpll",
+ .of_match_table = qcom_hfpll_match_table,
+ },
+};
+module_platform_driver(qcom_hfpll_driver);
+
+MODULE_DESCRIPTION("QCOM HFPLL Clock Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:qcom-hfpll");
diff --git a/drivers/clk/qcom/kpss-xcc.c b/drivers/clk/qcom/kpss-xcc.c
new file mode 100644
index 000000000000..8590b5edd19d
--- /dev/null
+++ b/drivers/clk/qcom/kpss-xcc.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018, The Linux Foundation. All rights reserved.
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+
+static const char *aux_parents[] = {
+ "pll8_vote",
+ "pxo",
+};
+
+static unsigned int aux_parent_map[] = {
+ 3,
+ 0,
+};
+
+static const struct of_device_id kpss_xcc_match_table[] = {
+ { .compatible = "qcom,kpss-acc-v1", .data = (void *)1UL },
+ { .compatible = "qcom,kpss-gcc" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, kpss_xcc_match_table);
+
+static int kpss_xcc_driver_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *id;
+ struct clk *clk;
+ struct resource *res;
+ void __iomem *base;
+ const char *name;
+
+ id = of_match_device(kpss_xcc_match_table, &pdev->dev);
+ if (!id)
+ return -ENODEV;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ if (id->data) {
+ if (of_property_read_string_index(pdev->dev.of_node,
+ "clock-output-names",
+ 0, &name))
+ return -ENODEV;
+ base += 0x14;
+ } else {
+ name = "acpu_l2_aux";
+ base += 0x28;
+ }
+
+ clk = clk_register_mux_table(&pdev->dev, name, aux_parents,
+ ARRAY_SIZE(aux_parents), 0, base, 0, 0x3,
+ 0, aux_parent_map, NULL);
+
+ platform_set_drvdata(pdev, clk);
+
+ return PTR_ERR_OR_ZERO(clk);
+}
+
+static int kpss_xcc_driver_remove(struct platform_device *pdev)
+{
+ clk_unregister_mux(platform_get_drvdata(pdev));
+ return 0;
+}
+
+static struct platform_driver kpss_xcc_driver = {
+ .probe = kpss_xcc_driver_probe,
+ .remove = kpss_xcc_driver_remove,
+ .driver = {
+ .name = "kpss-xcc",
+ .of_match_table = kpss_xcc_match_table,
+ },
+};
+module_platform_driver(kpss_xcc_driver);
+
+MODULE_DESCRIPTION("Krait Processor Sub System (KPSS) Clock Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:kpss-xcc");
diff --git a/drivers/clk/qcom/krait-cc.c b/drivers/clk/qcom/krait-cc.c
new file mode 100644
index 000000000000..4d4b657d33c3
--- /dev/null
+++ b/drivers/clk/qcom/krait-cc.c
@@ -0,0 +1,397 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018, The Linux Foundation. All rights reserved.
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+
+#include "clk-krait.h"
+
+static unsigned int sec_mux_map[] = {
+ 2,
+ 0,
+};
+
+static unsigned int pri_mux_map[] = {
+ 1,
+ 2,
+ 0,
+};
+
+/*
+ * Notifier function for switching the muxes to safe parent
+ * while the hfpll is getting reprogrammed.
+ */
+static int krait_notifier_cb(struct notifier_block *nb,
+ unsigned long event,
+ void *data)
+{
+ int ret = 0;
+ struct krait_mux_clk *mux = container_of(nb, struct krait_mux_clk,
+ clk_nb);
+ /* Switch to safe parent */
+ if (event == PRE_RATE_CHANGE) {
+ mux->old_index = krait_mux_clk_ops.get_parent(&mux->hw);
+ ret = krait_mux_clk_ops.set_parent(&mux->hw, mux->safe_sel);
+ mux->reparent = false;
+ /*
+ * By the time POST_RATE_CHANGE notifier is called,
+ * clk framework itself would have changed the parent for the new rate.
+ * Only otherwise, put back to the old parent.
+ */
+ } else if (event == POST_RATE_CHANGE) {
+ if (!mux->reparent)
+ ret = krait_mux_clk_ops.set_parent(&mux->hw,
+ mux->old_index);
+ }
+
+ return notifier_from_errno(ret);
+}
+
+static int krait_notifier_register(struct device *dev, struct clk *clk,
+ struct krait_mux_clk *mux)
+{
+ int ret = 0;
+
+ mux->clk_nb.notifier_call = krait_notifier_cb;
+ ret = clk_notifier_register(clk, &mux->clk_nb);
+ if (ret)
+ dev_err(dev, "failed to register clock notifier: %d\n", ret);
+
+ return ret;
+}
+
+static int
+krait_add_div(struct device *dev, int id, const char *s, unsigned int offset)
+{
+ struct krait_div2_clk *div;
+ struct clk_init_data init = {
+ .num_parents = 1,
+ .ops = &krait_div2_clk_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ };
+ const char *p_names[1];
+ struct clk *clk;
+
+ div = devm_kzalloc(dev, sizeof(*div), GFP_KERNEL);
+ if (!div)
+ return -ENOMEM;
+
+ div->width = 2;
+ div->shift = 6;
+ div->lpl = id >= 0;
+ div->offset = offset;
+ div->hw.init = &init;
+
+ init.name = kasprintf(GFP_KERNEL, "hfpll%s_div", s);
+ if (!init.name)
+ return -ENOMEM;
+
+ init.parent_names = p_names;
+ p_names[0] = kasprintf(GFP_KERNEL, "hfpll%s", s);
+ if (!p_names[0]) {
+ kfree(init.name);
+ return -ENOMEM;
+ }
+
+ clk = devm_clk_register(dev, &div->hw);
+ kfree(p_names[0]);
+ kfree(init.name);
+
+ return PTR_ERR_OR_ZERO(clk);
+}
+
+static int
+krait_add_sec_mux(struct device *dev, int id, const char *s,
+ unsigned int offset, bool unique_aux)
+{
+ int ret;
+ struct krait_mux_clk *mux;
+ static const char *sec_mux_list[] = {
+ "acpu_aux",
+ "qsb",
+ };
+ struct clk_init_data init = {
+ .parent_names = sec_mux_list,
+ .num_parents = ARRAY_SIZE(sec_mux_list),
+ .ops = &krait_mux_clk_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ };
+ struct clk *clk;
+
+ mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
+ if (!mux)
+ return -ENOMEM;
+
+ mux->offset = offset;
+ mux->lpl = id >= 0;
+ mux->mask = 0x3;
+ mux->shift = 2;
+ mux->parent_map = sec_mux_map;
+ mux->hw.init = &init;
+ mux->safe_sel = 0;
+
+ init.name = kasprintf(GFP_KERNEL, "krait%s_sec_mux", s);
+ if (!init.name)
+ return -ENOMEM;
+
+ if (unique_aux) {
+ sec_mux_list[0] = kasprintf(GFP_KERNEL, "acpu%s_aux", s);
+ if (!sec_mux_list[0]) {
+ clk = ERR_PTR(-ENOMEM);
+ goto err_aux;
+ }
+ }
+
+ clk = devm_clk_register(dev, &mux->hw);
+
+ ret = krait_notifier_register(dev, clk, mux);
+ if (ret)
+ goto unique_aux;
+
+unique_aux:
+ if (unique_aux)
+ kfree(sec_mux_list[0]);
+err_aux:
+ kfree(init.name);
+ return PTR_ERR_OR_ZERO(clk);
+}
+
+static struct clk *
+krait_add_pri_mux(struct device *dev, int id, const char *s,
+ unsigned int offset)
+{
+ int ret;
+ struct krait_mux_clk *mux;
+ const char *p_names[3];
+ struct clk_init_data init = {
+ .parent_names = p_names,
+ .num_parents = ARRAY_SIZE(p_names),
+ .ops = &krait_mux_clk_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ };
+ struct clk *clk;
+
+ mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
+ if (!mux)
+ return ERR_PTR(-ENOMEM);
+
+ mux->mask = 0x3;
+ mux->shift = 0;
+ mux->offset = offset;
+ mux->lpl = id >= 0;
+ mux->parent_map = pri_mux_map;
+ mux->hw.init = &init;
+ mux->safe_sel = 2;
+
+ init.name = kasprintf(GFP_KERNEL, "krait%s_pri_mux", s);
+ if (!init.name)
+ return ERR_PTR(-ENOMEM);
+
+ p_names[0] = kasprintf(GFP_KERNEL, "hfpll%s", s);
+ if (!p_names[0]) {
+ clk = ERR_PTR(-ENOMEM);
+ goto err_p0;
+ }
+
+ p_names[1] = kasprintf(GFP_KERNEL, "hfpll%s_div", s);
+ if (!p_names[1]) {
+ clk = ERR_PTR(-ENOMEM);
+ goto err_p1;
+ }
+
+ p_names[2] = kasprintf(GFP_KERNEL, "krait%s_sec_mux", s);
+ if (!p_names[2]) {
+ clk = ERR_PTR(-ENOMEM);
+ goto err_p2;
+ }
+
+ clk = devm_clk_register(dev, &mux->hw);
+
+ ret = krait_notifier_register(dev, clk, mux);
+ if (ret)
+ goto err_p3;
+err_p3:
+ kfree(p_names[2]);
+err_p2:
+ kfree(p_names[1]);
+err_p1:
+ kfree(p_names[0]);
+err_p0:
+ kfree(init.name);
+ return clk;
+}
+
+/* id < 0 for L2, otherwise id == physical CPU number */
+static struct clk *krait_add_clks(struct device *dev, int id, bool unique_aux)
+{
+ int ret;
+ unsigned int offset;
+ void *p = NULL;
+ const char *s;
+ struct clk *clk;
+
+ if (id >= 0) {
+ offset = 0x4501 + (0x1000 * id);
+ s = p = kasprintf(GFP_KERNEL, "%d", id);
+ if (!s)
+ return ERR_PTR(-ENOMEM);
+ } else {
+ offset = 0x500;
+ s = "_l2";
+ }
+
+ ret = krait_add_div(dev, id, s, offset);
+ if (ret) {
+ clk = ERR_PTR(ret);
+ goto err;
+ }
+
+ ret = krait_add_sec_mux(dev, id, s, offset, unique_aux);
+ if (ret) {
+ clk = ERR_PTR(ret);
+ goto err;
+ }
+
+ clk = krait_add_pri_mux(dev, id, s, offset);
+err:
+ kfree(p);
+ return clk;
+}
+
+static struct clk *krait_of_get(struct of_phandle_args *clkspec, void *data)
+{
+ unsigned int idx = clkspec->args[0];
+ struct clk **clks = data;
+
+ if (idx >= 5) {
+ pr_err("%s: invalid clock index %d\n", __func__, idx);
+ return ERR_PTR(-EINVAL);
+ }
+
+ return clks[idx] ? : ERR_PTR(-ENODEV);
+}
+
+static const struct of_device_id krait_cc_match_table[] = {
+ { .compatible = "qcom,krait-cc-v1", (void *)1UL },
+ { .compatible = "qcom,krait-cc-v2" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, krait_cc_match_table);
+
+static int krait_cc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ const struct of_device_id *id;
+ unsigned long cur_rate, aux_rate;
+ int cpu;
+ struct clk *clk;
+ struct clk **clks;
+ struct clk *l2_pri_mux_clk;
+
+ id = of_match_device(krait_cc_match_table, dev);
+ if (!id)
+ return -ENODEV;
+
+ /* Rate is 1 because 0 causes problems for __clk_mux_determine_rate */
+ clk = clk_register_fixed_rate(dev, "qsb", NULL, 0, 1);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ if (!id->data) {
+ clk = clk_register_fixed_factor(dev, "acpu_aux",
+ "gpll0_vote", 0, 1, 2);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+ }
+
+ /* Krait configurations have at most 4 CPUs and one L2 */
+ clks = devm_kcalloc(dev, 5, sizeof(*clks), GFP_KERNEL);
+ if (!clks)
+ return -ENOMEM;
+
+ for_each_possible_cpu(cpu) {
+ clk = krait_add_clks(dev, cpu, id->data);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+ clks[cpu] = clk;
+ }
+
+ l2_pri_mux_clk = krait_add_clks(dev, -1, id->data);
+ if (IS_ERR(l2_pri_mux_clk))
+ return PTR_ERR(l2_pri_mux_clk);
+ clks[4] = l2_pri_mux_clk;
+
+ /*
+ * We don't want the CPU or L2 clocks to be turned off at late init
+ * if CPUFREQ or HOTPLUG configs are disabled. So, bump up the
+ * refcount of these clocks. Any cpufreq/hotplug manager can assume
+ * that the clocks have already been prepared and enabled by the time
+ * they take over.
+ */
+ for_each_online_cpu(cpu) {
+ clk_prepare_enable(l2_pri_mux_clk);
+ WARN(clk_prepare_enable(clks[cpu]),
+ "Unable to turn on CPU%d clock", cpu);
+ }
+
+ /*
+ * Force reinit of HFPLLs and muxes to overwrite any potential
+ * incorrect configuration of HFPLLs and muxes by the bootloader.
+ * While at it, also make sure the cores are running at known rates
+ * and print the current rate.
+ *
+ * The clocks are set to aux clock rate first to make sure the
+ * secondary mux is not sourcing off of QSB. The rate is then set to
+ * two different rates to force a HFPLL reinit under all
+ * circumstances.
+ */
+ cur_rate = clk_get_rate(l2_pri_mux_clk);
+ aux_rate = 384000000;
+ if (cur_rate == 1) {
+ pr_info("L2 @ QSB rate. Forcing new rate.\n");
+ cur_rate = aux_rate;
+ }
+ clk_set_rate(l2_pri_mux_clk, aux_rate);
+ clk_set_rate(l2_pri_mux_clk, 2);
+ clk_set_rate(l2_pri_mux_clk, cur_rate);
+ pr_info("L2 @ %lu KHz\n", clk_get_rate(l2_pri_mux_clk) / 1000);
+ for_each_possible_cpu(cpu) {
+ clk = clks[cpu];
+ cur_rate = clk_get_rate(clk);
+ if (cur_rate == 1) {
+ pr_info("CPU%d @ QSB rate. Forcing new rate.\n", cpu);
+ cur_rate = aux_rate;
+ }
+
+ clk_set_rate(clk, aux_rate);
+ clk_set_rate(clk, 2);
+ clk_set_rate(clk, cur_rate);
+ pr_info("CPU%d @ %lu KHz\n", cpu, clk_get_rate(clk) / 1000);
+ }
+
+ of_clk_add_provider(dev->of_node, krait_of_get, clks);
+
+ return 0;
+}
+
+static struct platform_driver krait_cc_driver = {
+ .probe = krait_cc_probe,
+ .driver = {
+ .name = "krait-cc",
+ .of_match_table = krait_cc_match_table,
+ },
+};
+module_platform_driver(krait_cc_driver);
+
+MODULE_DESCRIPTION("Krait CPU Clock Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:krait-cc");
diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig
index 9022bbe1297e..b879e3e3a6b4 100644
--- a/drivers/clk/renesas/Kconfig
+++ b/drivers/clk/renesas/Kconfig
@@ -1,13 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0
+
config CLK_RENESAS
bool "Renesas SoC clock support" if COMPILE_TEST && !ARCH_RENESAS
default y if ARCH_RENESAS
select CLK_EMEV2 if ARCH_EMEV2
select CLK_RZA1 if ARCH_R7S72100
+ select CLK_R7S9210 if ARCH_R7S9210
select CLK_R8A73A4 if ARCH_R8A73A4
select CLK_R8A7740 if ARCH_R8A7740
- select CLK_R8A7743 if ARCH_R8A7743
+ select CLK_R8A7743 if ARCH_R8A7743 || ARCH_R8A7744
select CLK_R8A7745 if ARCH_R8A7745
select CLK_R8A77470 if ARCH_R8A77470
+ select CLK_R8A774A1 if ARCH_R8A774A1
+ select CLK_R8A774C0 if ARCH_R8A774C0
select CLK_R8A7778 if ARCH_R8A7778
select CLK_R8A7779 if ARCH_R8A7779
select CLK_R8A7790 if ARCH_R8A7790
@@ -45,6 +50,10 @@ config CLK_RZA1
bool "RZ/A1H clock support" if COMPILE_TEST
select CLK_RENESAS_CPG_MSTP
+config CLK_R7S9210
+ bool "RZ/A2 clock support" if COMPILE_TEST
+ select CLK_RENESAS_CPG_MSSR
+
config CLK_R8A73A4
bool "R-Mobile APE6 clock support" if COMPILE_TEST
select CLK_RENESAS_CPG_MSTP
@@ -67,6 +76,14 @@ config CLK_R8A77470
bool "RZ/G1C clock support" if COMPILE_TEST
select CLK_RCAR_GEN2_CPG
+config CLK_R8A774A1
+ bool "RZ/G2M clock support" if COMPILE_TEST
+ select CLK_RCAR_GEN3_CPG
+
+config CLK_R8A774C0
+ bool "RZ/G2E clock support" if COMPILE_TEST
+ select CLK_RCAR_GEN3_CPG
+
config CLK_R8A7778
bool "R-Car M1A clock support" if COMPILE_TEST
select CLK_RENESAS_CPG_MSTP
diff --git a/drivers/clk/renesas/Makefile b/drivers/clk/renesas/Makefile
index e4aa3d6143d2..c793e3cc9452 100644
--- a/drivers/clk/renesas/Makefile
+++ b/drivers/clk/renesas/Makefile
@@ -2,11 +2,14 @@
# SoC
obj-$(CONFIG_CLK_EMEV2) += clk-emev2.o
obj-$(CONFIG_CLK_RZA1) += clk-rz.o
+obj-$(CONFIG_CLK_R7S9210) += r7s9210-cpg-mssr.o
obj-$(CONFIG_CLK_R8A73A4) += clk-r8a73a4.o
obj-$(CONFIG_CLK_R8A7740) += clk-r8a7740.o
obj-$(CONFIG_CLK_R8A7743) += r8a7743-cpg-mssr.o
obj-$(CONFIG_CLK_R8A7745) += r8a7745-cpg-mssr.o
obj-$(CONFIG_CLK_R8A77470) += r8a77470-cpg-mssr.o
+obj-$(CONFIG_CLK_R8A774A1) += r8a774a1-cpg-mssr.o
+obj-$(CONFIG_CLK_R8A774C0) += r8a774c0-cpg-mssr.o
obj-$(CONFIG_CLK_R8A7778) += clk-r8a7778.o
obj-$(CONFIG_CLK_R8A7779) += clk-r8a7779.o
obj-$(CONFIG_CLK_R8A7790) += r8a7790-cpg-mssr.o
diff --git a/drivers/clk/renesas/clk-div6.c b/drivers/clk/renesas/clk-div6.c
index 9febbf42c3df..57c934164306 100644
--- a/drivers/clk/renesas/clk-div6.c
+++ b/drivers/clk/renesas/clk-div6.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* r8a7790 Common Clock Framework support
*
* Copyright (C) 2013 Renesas Solutions Corp.
*
* Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
*/
#include <linux/clk-provider.h>
@@ -312,8 +309,8 @@ static void __init cpg_div6_clock_init(struct device_node *np)
num_parents = of_clk_get_parent_count(np);
if (num_parents < 1) {
- pr_err("%s: no parent found for %s DIV6 clock\n",
- __func__, np->name);
+ pr_err("%s: no parent found for %pOFn DIV6 clock\n",
+ __func__, np);
return;
}
@@ -324,8 +321,8 @@ static void __init cpg_div6_clock_init(struct device_node *np)
reg = of_iomap(np, 0);
if (reg == NULL) {
- pr_err("%s: failed to map %s DIV6 clock register\n",
- __func__, np->name);
+ pr_err("%s: failed to map %pOFn DIV6 clock register\n",
+ __func__, np);
goto error;
}
@@ -337,8 +334,8 @@ static void __init cpg_div6_clock_init(struct device_node *np)
clk = cpg_div6_register(clk_name, num_parents, parent_names, reg, NULL);
if (IS_ERR(clk)) {
- pr_err("%s: failed to register %s DIV6 clock (%ld)\n",
- __func__, np->name, PTR_ERR(clk));
+ pr_err("%s: failed to register %pOFn DIV6 clock (%ld)\n",
+ __func__, np, PTR_ERR(clk));
goto error;
}
diff --git a/drivers/clk/renesas/clk-emev2.c b/drivers/clk/renesas/clk-emev2.c
index a91825471c79..7807b30a5bbb 100644
--- a/drivers/clk/renesas/clk-emev2.c
+++ b/drivers/clk/renesas/clk-emev2.c
@@ -1,21 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* EMMA Mobile EV2 common clock framework support
*
* Copyright (C) 2013 Takashi Yoshii <takashi.yoshii.ze@renesas.com>
* Copyright (C) 2012 Magnus Damm
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
@@ -86,8 +74,8 @@ static void __init emev2_smu_clkdiv_init(struct device_node *np)
clk = clk_register_divider(NULL, np->name, parent_name, 0,
smu_base + reg[0], reg[1], 8, 0, &lock);
of_clk_add_provider(np, of_clk_src_simple_get, clk);
- clk_register_clkdev(clk, np->name, NULL);
- pr_debug("## %s %s %p\n", __func__, np->name, clk);
+ clk_register_clkdev(clk, np->full_name, NULL);
+ pr_debug("## %s %pOFn %p\n", __func__, np, clk);
}
CLK_OF_DECLARE(emev2_smu_clkdiv, "renesas,emev2-smu-clkdiv",
emev2_smu_clkdiv_init);
@@ -104,7 +92,7 @@ static void __init emev2_smu_gclk_init(struct device_node *np)
clk = clk_register_gate(NULL, np->name, parent_name, 0,
smu_base + reg[0], reg[1], 0, &lock);
of_clk_add_provider(np, of_clk_src_simple_get, clk);
- clk_register_clkdev(clk, np->name, NULL);
- pr_debug("## %s %s %p\n", __func__, np->name, clk);
+ clk_register_clkdev(clk, np->full_name, NULL);
+ pr_debug("## %s %pOFn %p\n", __func__, np, clk);
}
CLK_OF_DECLARE(emev2_smu_gclk, "renesas,emev2-smu-gclk", emev2_smu_gclk_init);
diff --git a/drivers/clk/renesas/clk-mstp.c b/drivers/clk/renesas/clk-mstp.c
index e82adcb16a52..1c1768c2cc82 100644
--- a/drivers/clk/renesas/clk-mstp.c
+++ b/drivers/clk/renesas/clk-mstp.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* R-Car MSTP clocks
*
@@ -5,10 +6,6 @@
* Copyright (C) 2015 Glider bvba
*
* Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
*/
#include <linux/clk.h>
@@ -239,8 +236,8 @@ static void __init cpg_mstp_clocks_init(struct device_node *np)
break;
if (clkidx >= MSTP_MAX_CLOCKS) {
- pr_err("%s: invalid clock %s %s index %u\n",
- __func__, np->name, name, clkidx);
+ pr_err("%s: invalid clock %pOFn %s index %u\n",
+ __func__, np, name, clkidx);
continue;
}
@@ -259,8 +256,8 @@ static void __init cpg_mstp_clocks_init(struct device_node *np)
*/
clk_register_clkdev(clks[clkidx], name, NULL);
} else {
- pr_err("%s: failed to register %s %s clock (%ld)\n",
- __func__, np->name, name, PTR_ERR(clks[clkidx]));
+ pr_err("%s: failed to register %pOFn %s clock (%ld)\n",
+ __func__, np, name, PTR_ERR(clks[clkidx]));
}
}
diff --git a/drivers/clk/renesas/clk-r8a73a4.c b/drivers/clk/renesas/clk-r8a73a4.c
index 7b903ce4c901..2719c248c67b 100644
--- a/drivers/clk/renesas/clk-r8a73a4.c
+++ b/drivers/clk/renesas/clk-r8a73a4.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* r8a73a4 Core CPG Clocks
*
* Copyright (C) 2014 Ulrich Hecht
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
*/
#include <linux/clk-provider.h>
@@ -228,8 +225,8 @@ static void __init r8a73a4_cpg_clocks_init(struct device_node *np)
clk = r8a73a4_cpg_register_clock(np, cpg, name);
if (IS_ERR(clk))
- pr_err("%s: failed to register %s %s clock (%ld)\n",
- __func__, np->name, name, PTR_ERR(clk));
+ pr_err("%s: failed to register %pOFn %s clock (%ld)\n",
+ __func__, np, name, PTR_ERR(clk));
else
cpg->data.clks[i] = clk;
}
diff --git a/drivers/clk/renesas/clk-r8a7740.c b/drivers/clk/renesas/clk-r8a7740.c
index a7a30d2eca41..5967656c13cc 100644
--- a/drivers/clk/renesas/clk-r8a7740.c
+++ b/drivers/clk/renesas/clk-r8a7740.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* r8a7740 Core CPG Clocks
*
* Copyright (C) 2014 Ulrich Hecht
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
*/
#include <linux/clk-provider.h>
@@ -187,8 +184,8 @@ static void __init r8a7740_cpg_clocks_init(struct device_node *np)
clk = r8a7740_cpg_register_clock(np, cpg, name);
if (IS_ERR(clk))
- pr_err("%s: failed to register %s %s clock (%ld)\n",
- __func__, np->name, name, PTR_ERR(clk));
+ pr_err("%s: failed to register %pOFn %s clock (%ld)\n",
+ __func__, np, name, PTR_ERR(clk));
else
cpg->data.clks[i] = clk;
}
diff --git a/drivers/clk/renesas/clk-r8a7778.c b/drivers/clk/renesas/clk-r8a7778.c
index 886a8380e912..3ccc53685bdd 100644
--- a/drivers/clk/renesas/clk-r8a7778.c
+++ b/drivers/clk/renesas/clk-r8a7778.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* r8a7778 Core CPG Clocks
*
* Copyright (C) 2014 Ulrich Hecht
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
*/
#include <linux/clk-provider.h>
@@ -130,8 +127,8 @@ static void __init r8a7778_cpg_clocks_init(struct device_node *np)
clk = r8a7778_cpg_register_clock(np, cpg, name);
if (IS_ERR(clk))
- pr_err("%s: failed to register %s %s clock (%ld)\n",
- __func__, np->name, name, PTR_ERR(clk));
+ pr_err("%s: failed to register %pOFn %s clock (%ld)\n",
+ __func__, np, name, PTR_ERR(clk));
else
cpg->data.clks[i] = clk;
}
diff --git a/drivers/clk/renesas/clk-r8a7779.c b/drivers/clk/renesas/clk-r8a7779.c
index 5adcca4656c3..9f3b5522eef5 100644
--- a/drivers/clk/renesas/clk-r8a7779.c
+++ b/drivers/clk/renesas/clk-r8a7779.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* r8a7779 Core CPG Clocks
*
* Copyright (C) 2013, 2014 Horms Solutions Ltd.
*
* Contact: Simon Horman <horms@verge.net.au>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
*/
#include <linux/clk-provider.h>
@@ -164,8 +161,8 @@ static void __init r8a7779_cpg_clocks_init(struct device_node *np)
clk = r8a7779_cpg_register_clock(np, cpg, config,
plla_mult, name);
if (IS_ERR(clk))
- pr_err("%s: failed to register %s %s clock (%ld)\n",
- __func__, np->name, name, PTR_ERR(clk));
+ pr_err("%s: failed to register %pOFn %s clock (%ld)\n",
+ __func__, np, name, PTR_ERR(clk));
else
cpg->data.clks[i] = clk;
}
diff --git a/drivers/clk/renesas/clk-rcar-gen2.c b/drivers/clk/renesas/clk-rcar-gen2.c
index bccd62f2cb09..2913b4148157 100644
--- a/drivers/clk/renesas/clk-rcar-gen2.c
+++ b/drivers/clk/renesas/clk-rcar-gen2.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* rcar_gen2 Core CPG Clocks
*
* Copyright (C) 2013 Ideas On Board SPRL
*
* Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
*/
#include <linux/clk-provider.h>
@@ -445,8 +442,8 @@ static void __init rcar_gen2_cpg_clocks_init(struct device_node *np)
clk = rcar_gen2_cpg_register_clock(np, cpg, config, name);
if (IS_ERR(clk))
- pr_err("%s: failed to register %s %s clock (%ld)\n",
- __func__, np->name, name, PTR_ERR(clk));
+ pr_err("%s: failed to register %pOFn %s clock (%ld)\n",
+ __func__, np, name, PTR_ERR(clk));
else
cpg->data.clks[i] = clk;
}
diff --git a/drivers/clk/renesas/clk-rz.c b/drivers/clk/renesas/clk-rz.c
index ac2f86d626b6..3cda53a97f4e 100644
--- a/drivers/clk/renesas/clk-rz.c
+++ b/drivers/clk/renesas/clk-rz.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* RZ/A1 Core CPG Clocks
*
* Copyright (C) 2013 Ideas On Board SPRL
* Copyright (C) 2014 Wolfram Sang, Sang Engineering <wsa@sang-engineering.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 of the License.
*/
#include <linux/clk-provider.h>
@@ -113,8 +110,8 @@ static void __init rz_cpg_clocks_init(struct device_node *np)
clk = rz_cpg_register_clock(np, cpg, name);
if (IS_ERR(clk))
- pr_err("%s: failed to register %s %s clock (%ld)\n",
- __func__, np->name, name, PTR_ERR(clk));
+ pr_err("%s: failed to register %pOFn %s clock (%ld)\n",
+ __func__, np, name, PTR_ERR(clk));
else
cpg->data.clks[i] = clk;
}
diff --git a/drivers/clk/renesas/clk-sh73a0.c b/drivers/clk/renesas/clk-sh73a0.c
index bab33610eb6c..dc8ffc7c727a 100644
--- a/drivers/clk/renesas/clk-sh73a0.c
+++ b/drivers/clk/renesas/clk-sh73a0.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* sh73a0 Core CPG Clocks
*
* Copyright (C) 2014 Ulrich Hecht
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
*/
#include <linux/clk-provider.h>
@@ -206,8 +203,8 @@ static void __init sh73a0_cpg_clocks_init(struct device_node *np)
clk = sh73a0_cpg_register_clock(np, cpg, name);
if (IS_ERR(clk))
- pr_err("%s: failed to register %s %s clock (%ld)\n",
- __func__, np->name, name, PTR_ERR(clk));
+ pr_err("%s: failed to register %pOFn %s clock (%ld)\n",
+ __func__, np, name, PTR_ERR(clk));
else
cpg->data.clks[i] = clk;
}
diff --git a/drivers/clk/renesas/r7s9210-cpg-mssr.c b/drivers/clk/renesas/r7s9210-cpg-mssr.c
new file mode 100644
index 000000000000..5135f13ec628
--- /dev/null
+++ b/drivers/clk/renesas/r7s9210-cpg-mssr.c
@@ -0,0 +1,217 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * R7S9210 Clock Pulse Generator / Module Standby
+ *
+ * Based on r8a7795-cpg-mssr.c
+ *
+ * Copyright (C) 2018 Chris Brandt
+ * Copyright (C) 2018 Renesas Electronics Corp.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <dt-bindings/clock/r7s9210-cpg-mssr.h>
+#include "renesas-cpg-mssr.h"
+
+#define CPG_FRQCR 0x00
+
+static u8 cpg_mode;
+
+/* Internal Clock ratio table */
+static const struct {
+ unsigned int i;
+ unsigned int g;
+ unsigned int b;
+ unsigned int p1;
+ /* p0 is always 32 */;
+} ratio_tab[5] = { /* I, G, B, P1 */
+ { 2, 4, 8, 16}, /* FRQCR = 0x012 */
+ { 4, 4, 8, 16}, /* FRQCR = 0x112 */
+ { 8, 4, 8, 16}, /* FRQCR = 0x212 */
+ { 16, 8, 16, 16}, /* FRQCR = 0x322 */
+ { 16, 16, 32, 32}, /* FRQCR = 0x333 */
+ };
+
+enum rz_clk_types {
+ CLK_TYPE_RZA_MAIN = CLK_TYPE_CUSTOM,
+ CLK_TYPE_RZA_PLL,
+};
+
+enum clk_ids {
+ /* Core Clock Outputs exported to DT */
+ LAST_DT_CORE_CLK = R7S9210_CLK_P0,
+
+ /* External Input Clocks */
+ CLK_EXTAL,
+
+ /* Internal Core Clocks */
+ CLK_MAIN,
+ CLK_PLL,
+
+ /* Module Clocks */
+ MOD_CLK_BASE
+};
+
+static struct cpg_core_clk r7s9210_early_core_clks[] = {
+ /* External Clock Inputs */
+ DEF_INPUT("extal", CLK_EXTAL),
+
+ /* Internal Core Clocks */
+ DEF_BASE(".main", CLK_MAIN, CLK_TYPE_RZA_MAIN, CLK_EXTAL),
+ DEF_BASE(".pll", CLK_PLL, CLK_TYPE_RZA_PLL, CLK_MAIN),
+
+ /* Core Clock Outputs */
+ DEF_FIXED("p1c", R7S9210_CLK_P1C, CLK_PLL, 16, 1),
+};
+
+static const struct mssr_mod_clk r7s9210_early_mod_clks[] __initconst = {
+ DEF_MOD_STB("ostm2", 34, R7S9210_CLK_P1C),
+ DEF_MOD_STB("ostm1", 35, R7S9210_CLK_P1C),
+ DEF_MOD_STB("ostm0", 36, R7S9210_CLK_P1C),
+};
+
+static struct cpg_core_clk r7s9210_core_clks[] = {
+ /* Core Clock Outputs */
+ DEF_FIXED("i", R7S9210_CLK_I, CLK_PLL, 2, 1),
+ DEF_FIXED("g", R7S9210_CLK_G, CLK_PLL, 4, 1),
+ DEF_FIXED("b", R7S9210_CLK_B, CLK_PLL, 8, 1),
+ DEF_FIXED("p1", R7S9210_CLK_P1, CLK_PLL, 16, 1),
+ DEF_FIXED("p0", R7S9210_CLK_P0, CLK_PLL, 32, 1),
+};
+
+static const struct mssr_mod_clk r7s9210_mod_clks[] __initconst = {
+ DEF_MOD_STB("scif4", 43, R7S9210_CLK_P1C),
+ DEF_MOD_STB("scif3", 44, R7S9210_CLK_P1C),
+ DEF_MOD_STB("scif2", 45, R7S9210_CLK_P1C),
+ DEF_MOD_STB("scif1", 46, R7S9210_CLK_P1C),
+ DEF_MOD_STB("scif0", 47, R7S9210_CLK_P1C),
+
+ DEF_MOD_STB("ether1", 64, R7S9210_CLK_B),
+ DEF_MOD_STB("ether0", 65, R7S9210_CLK_B),
+
+ DEF_MOD_STB("i2c3", 84, R7S9210_CLK_P1),
+ DEF_MOD_STB("i2c2", 85, R7S9210_CLK_P1),
+ DEF_MOD_STB("i2c1", 86, R7S9210_CLK_P1),
+ DEF_MOD_STB("i2c0", 87, R7S9210_CLK_P1),
+
+ DEF_MOD_STB("spi2", 95, R7S9210_CLK_P1),
+ DEF_MOD_STB("spi1", 96, R7S9210_CLK_P1),
+ DEF_MOD_STB("spi0", 97, R7S9210_CLK_P1),
+};
+
+/* The clock dividers in the table vary based on DT and register settings */
+static void __init r7s9210_update_clk_table(struct clk *extal_clk,
+ void __iomem *base)
+{
+ int i;
+ u16 frqcr;
+ u8 index;
+
+ /* If EXTAL is above 12MHz, then we know it is Mode 1 */
+ if (clk_get_rate(extal_clk) > 12000000)
+ cpg_mode = 1;
+
+ frqcr = clk_readl(base + CPG_FRQCR) & 0xFFF;
+ if (frqcr == 0x012)
+ index = 0;
+ else if (frqcr == 0x112)
+ index = 1;
+ else if (frqcr == 0x212)
+ index = 2;
+ else if (frqcr == 0x322)
+ index = 3;
+ else if (frqcr == 0x333)
+ index = 4;
+ else
+ BUG_ON(1); /* Illegal FRQCR value */
+
+ for (i = 0; i < ARRAY_SIZE(r7s9210_core_clks); i++) {
+ switch (r7s9210_core_clks[i].id) {
+ case R7S9210_CLK_I:
+ r7s9210_core_clks[i].div = ratio_tab[index].i;
+ break;
+ case R7S9210_CLK_G:
+ r7s9210_core_clks[i].div = ratio_tab[index].g;
+ break;
+ case R7S9210_CLK_B:
+ r7s9210_core_clks[i].div = ratio_tab[index].b;
+ break;
+ case R7S9210_CLK_P1:
+ case R7S9210_CLK_P1C:
+ r7s9210_core_clks[i].div = ratio_tab[index].p1;
+ break;
+ case R7S9210_CLK_P0:
+ r7s9210_core_clks[i].div = 32;
+ break;
+ }
+ }
+}
+
+struct clk * __init rza2_cpg_clk_register(struct device *dev,
+ const struct cpg_core_clk *core, const struct cpg_mssr_info *info,
+ struct clk **clks, void __iomem *base,
+ struct raw_notifier_head *notifiers)
+{
+ struct clk *parent;
+ unsigned int mult = 1;
+ unsigned int div = 1;
+
+ parent = clks[core->parent];
+ if (IS_ERR(parent))
+ return ERR_CAST(parent);
+
+ switch (core->id) {
+ case CLK_MAIN:
+ break;
+
+ case CLK_PLL:
+ if (cpg_mode)
+ mult = 44; /* Divider 1 is 1/2 */
+ else
+ mult = 88; /* Divider 1 is 1 */
+ break;
+
+ default:
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (core->id == CLK_MAIN)
+ r7s9210_update_clk_table(parent, base);
+
+ return clk_register_fixed_factor(NULL, core->name,
+ __clk_get_name(parent), 0, mult, div);
+}
+
+const struct cpg_mssr_info r7s9210_cpg_mssr_info __initconst = {
+ /* Early Clocks */
+ .early_core_clks = r7s9210_early_core_clks,
+ .num_early_core_clks = ARRAY_SIZE(r7s9210_early_core_clks),
+ .early_mod_clks = r7s9210_early_mod_clks,
+ .num_early_mod_clks = ARRAY_SIZE(r7s9210_early_mod_clks),
+
+ /* Core Clocks */
+ .core_clks = r7s9210_core_clks,
+ .num_core_clks = ARRAY_SIZE(r7s9210_core_clks),
+ .last_dt_core_clk = LAST_DT_CORE_CLK,
+ .num_total_core_clks = MOD_CLK_BASE,
+
+ /* Module Clocks */
+ .mod_clks = r7s9210_mod_clks,
+ .num_mod_clks = ARRAY_SIZE(r7s9210_mod_clks),
+ .num_hw_mod_clks = 11 * 32, /* includes STBCR0 which doesn't exist */
+
+ /* Callbacks */
+ .cpg_clk_register = rza2_cpg_clk_register,
+
+ /* RZ/A2 has Standby Control Registers */
+ .stbyctrl = true,
+};
+
+static void __init r7s9210_cpg_mssr_early_init(struct device_node *np)
+{
+ cpg_mssr_early_init(np, &r7s9210_cpg_mssr_info);
+}
+
+CLK_OF_DECLARE_DRIVER(cpg_mstp_clks, "renesas,r7s9210-cpg-mssr",
+ r7s9210_cpg_mssr_early_init);
diff --git a/drivers/clk/renesas/r8a7743-cpg-mssr.c b/drivers/clk/renesas/r8a7743-cpg-mssr.c
index 011c170ec3f9..c01d9af2525a 100644
--- a/drivers/clk/renesas/r8a7743-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a7743-cpg-mssr.c
@@ -1,16 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* r8a7743 Clock Pulse Generator / Module Standby and Software Reset
*
* Copyright (C) 2016 Cogent Embedded Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation; of the License.
*/
#include <linux/device.h>
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/of.h>
#include <linux/soc/renesas/rcar-rst.h>
#include <dt-bindings/clock/r8a7743-cpg-mssr.h>
@@ -37,7 +35,7 @@ enum clk_ids {
MOD_CLK_BASE
};
-static const struct cpg_core_clk r8a7743_core_clks[] __initconst = {
+static struct cpg_core_clk r8a7743_core_clks[] __initdata = {
/* External Clock Inputs */
DEF_INPUT("extal", CLK_EXTAL),
DEF_INPUT("usb_extal", CLK_USB_EXTAL),
@@ -238,6 +236,8 @@ static const struct rcar_gen2_cpg_pll_config cpg_pll_configs[8] __initconst = {
static int __init r8a7743_cpg_mssr_init(struct device *dev)
{
const struct rcar_gen2_cpg_pll_config *cpg_pll_config;
+ struct device_node *np = dev->of_node;
+ unsigned int i;
u32 cpg_mode;
int error;
@@ -247,6 +247,14 @@ static int __init r8a7743_cpg_mssr_init(struct device *dev)
cpg_pll_config = &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(cpg_mode)];
+ if (of_device_is_compatible(np, "renesas,r8a7744-cpg-mssr")) {
+ /* RZ/G1N uses a 1/5 divider for ZG */
+ for (i = 0; i < ARRAY_SIZE(r8a7743_core_clks); i++)
+ if (r8a7743_core_clks[i].id == R8A7743_CLK_ZG) {
+ r8a7743_core_clks[i].div = 5;
+ break;
+ }
+ }
return rcar_gen2_cpg_init(cpg_pll_config, 2, cpg_mode);
}
diff --git a/drivers/clk/renesas/r8a7745-cpg-mssr.c b/drivers/clk/renesas/r8a7745-cpg-mssr.c
index 4b0a9243b748..493874e5ebee 100644
--- a/drivers/clk/renesas/r8a7745-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a7745-cpg-mssr.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* r8a7745 Clock Pulse Generator / Module Standby and Software Reset
*
* Copyright (C) 2016 Cogent Embedded Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation; of the License.
*/
#include <linux/device.h>
diff --git a/drivers/clk/renesas/r8a774a1-cpg-mssr.c b/drivers/clk/renesas/r8a774a1-cpg-mssr.c
new file mode 100644
index 000000000000..b0da34217bdf
--- /dev/null
+++ b/drivers/clk/renesas/r8a774a1-cpg-mssr.c
@@ -0,0 +1,323 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * r8a774a1 Clock Pulse Generator / Module Standby and Software Reset
+ *
+ * Copyright (C) 2018 Renesas Electronics Corp.
+ *
+ * Based on r8a7796-cpg-mssr.c
+ *
+ * Copyright (C) 2016 Glider bvba
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/soc/renesas/rcar-rst.h>
+
+#include <dt-bindings/clock/r8a774a1-cpg-mssr.h>
+
+#include "renesas-cpg-mssr.h"
+#include "rcar-gen3-cpg.h"
+
+enum clk_ids {
+ /* Core Clock Outputs exported to DT */
+ LAST_DT_CORE_CLK = R8A774A1_CLK_OSC,
+
+ /* External Input Clocks */
+ CLK_EXTAL,
+ CLK_EXTALR,
+
+ /* Internal Core Clocks */
+ CLK_MAIN,
+ CLK_PLL0,
+ CLK_PLL1,
+ CLK_PLL2,
+ CLK_PLL3,
+ CLK_PLL4,
+ CLK_PLL1_DIV2,
+ CLK_PLL1_DIV4,
+ CLK_S0,
+ CLK_S1,
+ CLK_S2,
+ CLK_S3,
+ CLK_SDSRC,
+ CLK_RINT,
+
+ /* Module Clocks */
+ MOD_CLK_BASE
+};
+
+static const struct cpg_core_clk r8a774a1_core_clks[] __initconst = {
+ /* External Clock Inputs */
+ DEF_INPUT("extal", CLK_EXTAL),
+ DEF_INPUT("extalr", CLK_EXTALR),
+
+ /* Internal Core Clocks */
+ DEF_BASE(".main", CLK_MAIN, CLK_TYPE_GEN3_MAIN, CLK_EXTAL),
+ DEF_BASE(".pll0", CLK_PLL0, CLK_TYPE_GEN3_PLL0, CLK_MAIN),
+ DEF_BASE(".pll1", CLK_PLL1, CLK_TYPE_GEN3_PLL1, CLK_MAIN),
+ DEF_BASE(".pll2", CLK_PLL2, CLK_TYPE_GEN3_PLL2, CLK_MAIN),
+ DEF_BASE(".pll3", CLK_PLL3, CLK_TYPE_GEN3_PLL3, CLK_MAIN),
+ DEF_BASE(".pll4", CLK_PLL4, CLK_TYPE_GEN3_PLL4, CLK_MAIN),
+
+ DEF_FIXED(".pll1_div2", CLK_PLL1_DIV2, CLK_PLL1, 2, 1),
+ DEF_FIXED(".pll1_div4", CLK_PLL1_DIV4, CLK_PLL1_DIV2, 2, 1),
+ DEF_FIXED(".s0", CLK_S0, CLK_PLL1_DIV2, 2, 1),
+ DEF_FIXED(".s1", CLK_S1, CLK_PLL1_DIV2, 3, 1),
+ DEF_FIXED(".s2", CLK_S2, CLK_PLL1_DIV2, 4, 1),
+ DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 6, 1),
+ DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL1_DIV2, 2, 1),
+
+ DEF_GEN3_OSC(".r", CLK_RINT, CLK_EXTAL, 32),
+
+ /* Core Clock Outputs */
+ DEF_BASE("z", R8A774A1_CLK_Z, CLK_TYPE_GEN3_Z, CLK_PLL0),
+ DEF_BASE("z2", R8A774A1_CLK_Z2, CLK_TYPE_GEN3_Z2, CLK_PLL2),
+ DEF_FIXED("ztr", R8A774A1_CLK_ZTR, CLK_PLL1_DIV2, 6, 1),
+ DEF_FIXED("ztrd2", R8A774A1_CLK_ZTRD2, CLK_PLL1_DIV2, 12, 1),
+ DEF_FIXED("zt", R8A774A1_CLK_ZT, CLK_PLL1_DIV2, 4, 1),
+ DEF_FIXED("zx", R8A774A1_CLK_ZX, CLK_PLL1_DIV2, 2, 1),
+ DEF_FIXED("s0d1", R8A774A1_CLK_S0D1, CLK_S0, 1, 1),
+ DEF_FIXED("s0d2", R8A774A1_CLK_S0D2, CLK_S0, 2, 1),
+ DEF_FIXED("s0d3", R8A774A1_CLK_S0D3, CLK_S0, 3, 1),
+ DEF_FIXED("s0d4", R8A774A1_CLK_S0D4, CLK_S0, 4, 1),
+ DEF_FIXED("s0d6", R8A774A1_CLK_S0D6, CLK_S0, 6, 1),
+ DEF_FIXED("s0d8", R8A774A1_CLK_S0D8, CLK_S0, 8, 1),
+ DEF_FIXED("s0d12", R8A774A1_CLK_S0D12, CLK_S0, 12, 1),
+ DEF_FIXED("s1d2", R8A774A1_CLK_S1D2, CLK_S1, 2, 1),
+ DEF_FIXED("s1d4", R8A774A1_CLK_S1D4, CLK_S1, 4, 1),
+ DEF_FIXED("s2d1", R8A774A1_CLK_S2D1, CLK_S2, 1, 1),
+ DEF_FIXED("s2d2", R8A774A1_CLK_S2D2, CLK_S2, 2, 1),
+ DEF_FIXED("s2d4", R8A774A1_CLK_S2D4, CLK_S2, 4, 1),
+ DEF_FIXED("s3d1", R8A774A1_CLK_S3D1, CLK_S3, 1, 1),
+ DEF_FIXED("s3d2", R8A774A1_CLK_S3D2, CLK_S3, 2, 1),
+ DEF_FIXED("s3d4", R8A774A1_CLK_S3D4, CLK_S3, 4, 1),
+
+ DEF_GEN3_SD("sd0", R8A774A1_CLK_SD0, CLK_SDSRC, 0x074),
+ DEF_GEN3_SD("sd1", R8A774A1_CLK_SD1, CLK_SDSRC, 0x078),
+ DEF_GEN3_SD("sd2", R8A774A1_CLK_SD2, CLK_SDSRC, 0x268),
+ DEF_GEN3_SD("sd3", R8A774A1_CLK_SD3, CLK_SDSRC, 0x26c),
+
+ DEF_FIXED("cl", R8A774A1_CLK_CL, CLK_PLL1_DIV2, 48, 1),
+ DEF_FIXED("cp", R8A774A1_CLK_CP, CLK_EXTAL, 2, 1),
+
+ DEF_DIV6P1("csi0", R8A774A1_CLK_CSI0, CLK_PLL1_DIV4, 0x00c),
+ DEF_DIV6P1("mso", R8A774A1_CLK_MSO, CLK_PLL1_DIV4, 0x014),
+ DEF_DIV6P1("hdmi", R8A774A1_CLK_HDMI, CLK_PLL1_DIV4, 0x250),
+
+ DEF_GEN3_OSC("osc", R8A774A1_CLK_OSC, CLK_EXTAL, 8),
+
+ DEF_BASE("r", R8A774A1_CLK_R, CLK_TYPE_GEN3_R, CLK_RINT),
+};
+
+static const struct mssr_mod_clk r8a774a1_mod_clks[] __initconst = {
+ DEF_MOD("fdp1-0", 119, R8A774A1_CLK_S0D1),
+ DEF_MOD("scif5", 202, R8A774A1_CLK_S3D4),
+ DEF_MOD("scif4", 203, R8A774A1_CLK_S3D4),
+ DEF_MOD("scif3", 204, R8A774A1_CLK_S3D4),
+ DEF_MOD("scif1", 206, R8A774A1_CLK_S3D4),
+ DEF_MOD("scif0", 207, R8A774A1_CLK_S3D4),
+ DEF_MOD("msiof3", 208, R8A774A1_CLK_MSO),
+ DEF_MOD("msiof2", 209, R8A774A1_CLK_MSO),
+ DEF_MOD("msiof1", 210, R8A774A1_CLK_MSO),
+ DEF_MOD("msiof0", 211, R8A774A1_CLK_MSO),
+ DEF_MOD("sys-dmac2", 217, R8A774A1_CLK_S0D3),
+ DEF_MOD("sys-dmac1", 218, R8A774A1_CLK_S0D3),
+ DEF_MOD("sys-dmac0", 219, R8A774A1_CLK_S0D3),
+ DEF_MOD("cmt3", 300, R8A774A1_CLK_R),
+ DEF_MOD("cmt2", 301, R8A774A1_CLK_R),
+ DEF_MOD("cmt1", 302, R8A774A1_CLK_R),
+ DEF_MOD("cmt0", 303, R8A774A1_CLK_R),
+ DEF_MOD("scif2", 310, R8A774A1_CLK_S3D4),
+ DEF_MOD("sdif3", 311, R8A774A1_CLK_SD3),
+ DEF_MOD("sdif2", 312, R8A774A1_CLK_SD2),
+ DEF_MOD("sdif1", 313, R8A774A1_CLK_SD1),
+ DEF_MOD("sdif0", 314, R8A774A1_CLK_SD0),
+ DEF_MOD("pcie1", 318, R8A774A1_CLK_S3D1),
+ DEF_MOD("pcie0", 319, R8A774A1_CLK_S3D1),
+ DEF_MOD("usb3-if0", 328, R8A774A1_CLK_S3D1),
+ DEF_MOD("usb-dmac0", 330, R8A774A1_CLK_S3D1),
+ DEF_MOD("usb-dmac1", 331, R8A774A1_CLK_S3D1),
+ DEF_MOD("rwdt", 402, R8A774A1_CLK_R),
+ DEF_MOD("intc-ex", 407, R8A774A1_CLK_CP),
+ DEF_MOD("intc-ap", 408, R8A774A1_CLK_S0D3),
+ DEF_MOD("audmac1", 501, R8A774A1_CLK_S0D3),
+ DEF_MOD("audmac0", 502, R8A774A1_CLK_S0D3),
+ DEF_MOD("hscif4", 516, R8A774A1_CLK_S3D1),
+ DEF_MOD("hscif3", 517, R8A774A1_CLK_S3D1),
+ DEF_MOD("hscif2", 518, R8A774A1_CLK_S3D1),
+ DEF_MOD("hscif1", 519, R8A774A1_CLK_S3D1),
+ DEF_MOD("hscif0", 520, R8A774A1_CLK_S3D1),
+ DEF_MOD("thermal", 522, R8A774A1_CLK_CP),
+ DEF_MOD("pwm", 523, R8A774A1_CLK_S0D12),
+ DEF_MOD("fcpvd2", 601, R8A774A1_CLK_S0D2),
+ DEF_MOD("fcpvd1", 602, R8A774A1_CLK_S0D2),
+ DEF_MOD("fcpvd0", 603, R8A774A1_CLK_S0D2),
+ DEF_MOD("fcpvb0", 607, R8A774A1_CLK_S0D1),
+ DEF_MOD("fcpvi0", 611, R8A774A1_CLK_S0D1),
+ DEF_MOD("fcpf0", 615, R8A774A1_CLK_S0D1),
+ DEF_MOD("fcpci0", 617, R8A774A1_CLK_S0D2),
+ DEF_MOD("fcpcs", 619, R8A774A1_CLK_S0D2),
+ DEF_MOD("vspd2", 621, R8A774A1_CLK_S0D2),
+ DEF_MOD("vspd1", 622, R8A774A1_CLK_S0D2),
+ DEF_MOD("vspd0", 623, R8A774A1_CLK_S0D2),
+ DEF_MOD("vspb", 626, R8A774A1_CLK_S0D1),
+ DEF_MOD("vspi0", 631, R8A774A1_CLK_S0D1),
+ DEF_MOD("ehci1", 702, R8A774A1_CLK_S3D4),
+ DEF_MOD("ehci0", 703, R8A774A1_CLK_S3D4),
+ DEF_MOD("hsusb", 704, R8A774A1_CLK_S3D4),
+ DEF_MOD("csi20", 714, R8A774A1_CLK_CSI0),
+ DEF_MOD("csi40", 716, R8A774A1_CLK_CSI0),
+ DEF_MOD("du2", 722, R8A774A1_CLK_S2D1),
+ DEF_MOD("du1", 723, R8A774A1_CLK_S2D1),
+ DEF_MOD("du0", 724, R8A774A1_CLK_S2D1),
+ DEF_MOD("lvds", 727, R8A774A1_CLK_S2D1),
+ DEF_MOD("hdmi0", 729, R8A774A1_CLK_HDMI),
+ DEF_MOD("vin7", 804, R8A774A1_CLK_S0D2),
+ DEF_MOD("vin6", 805, R8A774A1_CLK_S0D2),
+ DEF_MOD("vin5", 806, R8A774A1_CLK_S0D2),
+ DEF_MOD("vin4", 807, R8A774A1_CLK_S0D2),
+ DEF_MOD("vin3", 808, R8A774A1_CLK_S0D2),
+ DEF_MOD("vin2", 809, R8A774A1_CLK_S0D2),
+ DEF_MOD("vin1", 810, R8A774A1_CLK_S0D2),
+ DEF_MOD("vin0", 811, R8A774A1_CLK_S0D2),
+ DEF_MOD("etheravb", 812, R8A774A1_CLK_S0D6),
+ DEF_MOD("gpio7", 905, R8A774A1_CLK_S3D4),
+ DEF_MOD("gpio6", 906, R8A774A1_CLK_S3D4),
+ DEF_MOD("gpio5", 907, R8A774A1_CLK_S3D4),
+ DEF_MOD("gpio4", 908, R8A774A1_CLK_S3D4),
+ DEF_MOD("gpio3", 909, R8A774A1_CLK_S3D4),
+ DEF_MOD("gpio2", 910, R8A774A1_CLK_S3D4),
+ DEF_MOD("gpio1", 911, R8A774A1_CLK_S3D4),
+ DEF_MOD("gpio0", 912, R8A774A1_CLK_S3D4),
+ DEF_MOD("can-if1", 915, R8A774A1_CLK_S3D4),
+ DEF_MOD("can-if0", 916, R8A774A1_CLK_S3D4),
+ DEF_MOD("i2c6", 918, R8A774A1_CLK_S0D6),
+ DEF_MOD("i2c5", 919, R8A774A1_CLK_S0D6),
+ DEF_MOD("i2c-dvfs", 926, R8A774A1_CLK_CP),
+ DEF_MOD("i2c4", 927, R8A774A1_CLK_S0D6),
+ DEF_MOD("i2c3", 928, R8A774A1_CLK_S0D6),
+ DEF_MOD("i2c2", 929, R8A774A1_CLK_S3D2),
+ DEF_MOD("i2c1", 930, R8A774A1_CLK_S3D2),
+ DEF_MOD("i2c0", 931, R8A774A1_CLK_S3D2),
+ DEF_MOD("ssi-all", 1005, R8A774A1_CLK_S3D4),
+ DEF_MOD("ssi9", 1006, MOD_CLK_ID(1005)),
+ DEF_MOD("ssi8", 1007, MOD_CLK_ID(1005)),
+ DEF_MOD("ssi7", 1008, MOD_CLK_ID(1005)),
+ DEF_MOD("ssi6", 1009, MOD_CLK_ID(1005)),
+ DEF_MOD("ssi5", 1010, MOD_CLK_ID(1005)),
+ DEF_MOD("ssi4", 1011, MOD_CLK_ID(1005)),
+ DEF_MOD("ssi3", 1012, MOD_CLK_ID(1005)),
+ DEF_MOD("ssi2", 1013, MOD_CLK_ID(1005)),
+ DEF_MOD("ssi1", 1014, MOD_CLK_ID(1005)),
+ DEF_MOD("ssi0", 1015, MOD_CLK_ID(1005)),
+ DEF_MOD("scu-all", 1017, R8A774A1_CLK_S3D4),
+ DEF_MOD("scu-dvc1", 1018, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-dvc0", 1019, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-ctu1-mix1", 1020, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-ctu0-mix0", 1021, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src9", 1022, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src8", 1023, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src7", 1024, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src6", 1025, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src5", 1026, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src4", 1027, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src3", 1028, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src2", 1029, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src1", 1030, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src0", 1031, MOD_CLK_ID(1017)),
+};
+
+static const unsigned int r8a774a1_crit_mod_clks[] __initconst = {
+ MOD_CLK_ID(408), /* INTC-AP (GIC) */
+};
+
+/*
+ * CPG Clock Data
+ */
+
+/*
+ * MD EXTAL PLL0 PLL1 PLL2 PLL3 PLL4 OSC
+ * 14 13 19 17 (MHz)
+ *-------------------------------------------------------------------------
+ * 0 0 0 0 16.66 x 1 x180 x192 x144 x192 x144 /16
+ * 0 0 0 1 16.66 x 1 x180 x192 x144 x128 x144 /16
+ * 0 0 1 0 Prohibited setting
+ * 0 0 1 1 16.66 x 1 x180 x192 x144 x192 x144 /16
+ * 0 1 0 0 20 x 1 x150 x160 x120 x160 x120 /19
+ * 0 1 0 1 20 x 1 x150 x160 x120 x106 x120 /19
+ * 0 1 1 0 Prohibited setting
+ * 0 1 1 1 20 x 1 x150 x160 x120 x160 x120 /19
+ * 1 0 0 0 25 x 1 x120 x128 x96 x128 x96 /24
+ * 1 0 0 1 25 x 1 x120 x128 x96 x84 x96 /24
+ * 1 0 1 0 Prohibited setting
+ * 1 0 1 1 25 x 1 x120 x128 x96 x128 x96 /24
+ * 1 1 0 0 33.33 / 2 x180 x192 x144 x192 x144 /32
+ * 1 1 0 1 33.33 / 2 x180 x192 x144 x128 x144 /32
+ * 1 1 1 0 Prohibited setting
+ * 1 1 1 1 33.33 / 2 x180 x192 x144 x192 x144 /32
+ */
+#define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 11) | \
+ (((md) & BIT(13)) >> 11) | \
+ (((md) & BIT(19)) >> 18) | \
+ (((md) & BIT(17)) >> 17))
+
+static const struct rcar_gen3_cpg_pll_config cpg_pll_configs[16] __initconst = {
+ /* EXTAL div PLL1 mult/div PLL3 mult/div OSC prediv */
+ { 1, 192, 1, 192, 1, 16, },
+ { 1, 192, 1, 128, 1, 16, },
+ { 0, /* Prohibited setting */ },
+ { 1, 192, 1, 192, 1, 16, },
+ { 1, 160, 1, 160, 1, 19, },
+ { 1, 160, 1, 106, 1, 19, },
+ { 0, /* Prohibited setting */ },
+ { 1, 160, 1, 160, 1, 19, },
+ { 1, 128, 1, 128, 1, 24, },
+ { 1, 128, 1, 84, 1, 24, },
+ { 0, /* Prohibited setting */ },
+ { 1, 128, 1, 128, 1, 24, },
+ { 2, 192, 1, 192, 1, 32, },
+ { 2, 192, 1, 128, 1, 32, },
+ { 0, /* Prohibited setting */ },
+ { 2, 192, 1, 192, 1, 32, },
+};
+
+static int __init r8a774a1_cpg_mssr_init(struct device *dev)
+{
+ const struct rcar_gen3_cpg_pll_config *cpg_pll_config;
+ u32 cpg_mode;
+ int error;
+
+ error = rcar_rst_read_mode_pins(&cpg_mode);
+ if (error)
+ return error;
+
+ cpg_pll_config = &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(cpg_mode)];
+ if (!cpg_pll_config->extal_div) {
+ dev_err(dev, "Prohibited setting (cpg_mode=0x%x)\n", cpg_mode);
+ return -EINVAL;
+ }
+
+ return rcar_gen3_cpg_init(cpg_pll_config, CLK_EXTALR, cpg_mode);
+}
+
+const struct cpg_mssr_info r8a774a1_cpg_mssr_info __initconst = {
+ /* Core Clocks */
+ .core_clks = r8a774a1_core_clks,
+ .num_core_clks = ARRAY_SIZE(r8a774a1_core_clks),
+ .last_dt_core_clk = LAST_DT_CORE_CLK,
+ .num_total_core_clks = MOD_CLK_BASE,
+
+ /* Module Clocks */
+ .mod_clks = r8a774a1_mod_clks,
+ .num_mod_clks = ARRAY_SIZE(r8a774a1_mod_clks),
+ .num_hw_mod_clks = 12 * 32,
+
+ /* Critical Module Clocks */
+ .crit_mod_clks = r8a774a1_crit_mod_clks,
+ .num_crit_mod_clks = ARRAY_SIZE(r8a774a1_crit_mod_clks),
+
+ /* Callbacks */
+ .init = r8a774a1_cpg_mssr_init,
+ .cpg_clk_register = rcar_gen3_cpg_clk_register,
+};
diff --git a/drivers/clk/renesas/r8a774c0-cpg-mssr.c b/drivers/clk/renesas/r8a774c0-cpg-mssr.c
new file mode 100644
index 000000000000..10b96895d452
--- /dev/null
+++ b/drivers/clk/renesas/r8a774c0-cpg-mssr.c
@@ -0,0 +1,286 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * r8a774c0 Clock Pulse Generator / Module Standby and Software Reset
+ *
+ * Copyright (C) 2018 Renesas Electronics Corp.
+ *
+ * Based on r8a77990-cpg-mssr.c
+ *
+ * Copyright (C) 2015 Glider bvba
+ * Copyright (C) 2015 Renesas Electronics Corp.
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/soc/renesas/rcar-rst.h>
+
+#include <dt-bindings/clock/r8a774c0-cpg-mssr.h>
+
+#include "renesas-cpg-mssr.h"
+#include "rcar-gen3-cpg.h"
+
+enum clk_ids {
+ /* Core Clock Outputs exported to DT */
+ LAST_DT_CORE_CLK = R8A774C0_CLK_CPEX,
+
+ /* External Input Clocks */
+ CLK_EXTAL,
+
+ /* Internal Core Clocks */
+ CLK_MAIN,
+ CLK_PLL0,
+ CLK_PLL1,
+ CLK_PLL3,
+ CLK_PLL0D4,
+ CLK_PLL0D8,
+ CLK_PLL0D20,
+ CLK_PLL0D24,
+ CLK_PLL1D2,
+ CLK_PE,
+ CLK_S0,
+ CLK_S1,
+ CLK_S2,
+ CLK_S3,
+ CLK_SDSRC,
+ CLK_RINT,
+ CLK_OCO,
+
+ /* Module Clocks */
+ MOD_CLK_BASE
+};
+
+static const struct cpg_core_clk r8a774c0_core_clks[] __initconst = {
+ /* External Clock Inputs */
+ DEF_INPUT("extal", CLK_EXTAL),
+
+ /* Internal Core Clocks */
+ DEF_BASE(".main", CLK_MAIN, CLK_TYPE_GEN3_MAIN, CLK_EXTAL),
+ DEF_BASE(".pll1", CLK_PLL1, CLK_TYPE_GEN3_PLL1, CLK_MAIN),
+ DEF_BASE(".pll3", CLK_PLL3, CLK_TYPE_GEN3_PLL3, CLK_MAIN),
+
+ DEF_FIXED(".pll0", CLK_PLL0, CLK_MAIN, 1, 100),
+ DEF_FIXED(".pll0d4", CLK_PLL0D4, CLK_PLL0, 4, 1),
+ DEF_FIXED(".pll0d8", CLK_PLL0D8, CLK_PLL0, 8, 1),
+ DEF_FIXED(".pll0d20", CLK_PLL0D20, CLK_PLL0, 20, 1),
+ DEF_FIXED(".pll0d24", CLK_PLL0D24, CLK_PLL0, 24, 1),
+ DEF_FIXED(".pll1d2", CLK_PLL1D2, CLK_PLL1, 2, 1),
+ DEF_FIXED(".pe", CLK_PE, CLK_PLL0D20, 1, 1),
+ DEF_FIXED(".s0", CLK_S0, CLK_PLL1, 2, 1),
+ DEF_FIXED(".s1", CLK_S1, CLK_PLL1, 3, 1),
+ DEF_FIXED(".s2", CLK_S2, CLK_PLL1, 4, 1),
+ DEF_FIXED(".s3", CLK_S3, CLK_PLL1, 6, 1),
+ DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL1, 2, 1),
+
+ DEF_DIV6_RO(".r", CLK_RINT, CLK_EXTAL, CPG_RCKCR, 32),
+
+ DEF_RATE(".oco", CLK_OCO, 8 * 1000 * 1000),
+
+ /* Core Clock Outputs */
+ DEF_FIXED("za2", R8A774C0_CLK_ZA2, CLK_PLL0D24, 1, 1),
+ DEF_FIXED("za8", R8A774C0_CLK_ZA8, CLK_PLL0D8, 1, 1),
+ DEF_FIXED("ztr", R8A774C0_CLK_ZTR, CLK_PLL1, 6, 1),
+ DEF_FIXED("zt", R8A774C0_CLK_ZT, CLK_PLL1, 4, 1),
+ DEF_FIXED("zx", R8A774C0_CLK_ZX, CLK_PLL1, 3, 1),
+ DEF_FIXED("s0d1", R8A774C0_CLK_S0D1, CLK_S0, 1, 1),
+ DEF_FIXED("s0d3", R8A774C0_CLK_S0D3, CLK_S0, 3, 1),
+ DEF_FIXED("s0d6", R8A774C0_CLK_S0D6, CLK_S0, 6, 1),
+ DEF_FIXED("s0d12", R8A774C0_CLK_S0D12, CLK_S0, 12, 1),
+ DEF_FIXED("s0d24", R8A774C0_CLK_S0D24, CLK_S0, 24, 1),
+ DEF_FIXED("s1d1", R8A774C0_CLK_S1D1, CLK_S1, 1, 1),
+ DEF_FIXED("s1d2", R8A774C0_CLK_S1D2, CLK_S1, 2, 1),
+ DEF_FIXED("s1d4", R8A774C0_CLK_S1D4, CLK_S1, 4, 1),
+ DEF_FIXED("s2d1", R8A774C0_CLK_S2D1, CLK_S2, 1, 1),
+ DEF_FIXED("s2d2", R8A774C0_CLK_S2D2, CLK_S2, 2, 1),
+ DEF_FIXED("s2d4", R8A774C0_CLK_S2D4, CLK_S2, 4, 1),
+ DEF_FIXED("s3d1", R8A774C0_CLK_S3D1, CLK_S3, 1, 1),
+ DEF_FIXED("s3d2", R8A774C0_CLK_S3D2, CLK_S3, 2, 1),
+ DEF_FIXED("s3d4", R8A774C0_CLK_S3D4, CLK_S3, 4, 1),
+
+ DEF_GEN3_SD("sd0", R8A774C0_CLK_SD0, CLK_SDSRC, 0x0074),
+ DEF_GEN3_SD("sd1", R8A774C0_CLK_SD1, CLK_SDSRC, 0x0078),
+ DEF_GEN3_SD("sd3", R8A774C0_CLK_SD3, CLK_SDSRC, 0x026c),
+
+ DEF_FIXED("cl", R8A774C0_CLK_CL, CLK_PLL1, 48, 1),
+ DEF_FIXED("cp", R8A774C0_CLK_CP, CLK_EXTAL, 2, 1),
+ DEF_FIXED("cpex", R8A774C0_CLK_CPEX, CLK_EXTAL, 4, 1),
+
+ DEF_DIV6_RO("osc", R8A774C0_CLK_OSC, CLK_EXTAL, CPG_RCKCR, 8),
+
+ DEF_GEN3_PE("s0d6c", R8A774C0_CLK_S0D6C, CLK_S0, 6, CLK_PE, 2),
+ DEF_GEN3_PE("s3d1c", R8A774C0_CLK_S3D1C, CLK_S3, 1, CLK_PE, 1),
+ DEF_GEN3_PE("s3d2c", R8A774C0_CLK_S3D2C, CLK_S3, 2, CLK_PE, 2),
+ DEF_GEN3_PE("s3d4c", R8A774C0_CLK_S3D4C, CLK_S3, 4, CLK_PE, 4),
+
+ DEF_DIV6P1("csi0", R8A774C0_CLK_CSI0, CLK_PLL1D2, 0x00c),
+ DEF_DIV6P1("mso", R8A774C0_CLK_MSO, CLK_PLL1D2, 0x014),
+
+ DEF_GEN3_RCKSEL("r", R8A774C0_CLK_R, CLK_RINT, 1, CLK_OCO, 61 * 4),
+};
+
+static const struct mssr_mod_clk r8a774c0_mod_clks[] __initconst = {
+ DEF_MOD("scif5", 202, R8A774C0_CLK_S3D4C),
+ DEF_MOD("scif4", 203, R8A774C0_CLK_S3D4C),
+ DEF_MOD("scif3", 204, R8A774C0_CLK_S3D4C),
+ DEF_MOD("scif1", 206, R8A774C0_CLK_S3D4C),
+ DEF_MOD("scif0", 207, R8A774C0_CLK_S3D4C),
+ DEF_MOD("msiof3", 208, R8A774C0_CLK_MSO),
+ DEF_MOD("msiof2", 209, R8A774C0_CLK_MSO),
+ DEF_MOD("msiof1", 210, R8A774C0_CLK_MSO),
+ DEF_MOD("msiof0", 211, R8A774C0_CLK_MSO),
+ DEF_MOD("sys-dmac2", 217, R8A774C0_CLK_S3D1),
+ DEF_MOD("sys-dmac1", 218, R8A774C0_CLK_S3D1),
+ DEF_MOD("sys-dmac0", 219, R8A774C0_CLK_S3D1),
+
+ DEF_MOD("cmt3", 300, R8A774C0_CLK_R),
+ DEF_MOD("cmt2", 301, R8A774C0_CLK_R),
+ DEF_MOD("cmt1", 302, R8A774C0_CLK_R),
+ DEF_MOD("cmt0", 303, R8A774C0_CLK_R),
+ DEF_MOD("scif2", 310, R8A774C0_CLK_S3D4C),
+ DEF_MOD("sdif3", 311, R8A774C0_CLK_SD3),
+ DEF_MOD("sdif1", 313, R8A774C0_CLK_SD1),
+ DEF_MOD("sdif0", 314, R8A774C0_CLK_SD0),
+ DEF_MOD("pcie0", 319, R8A774C0_CLK_S3D1),
+ DEF_MOD("usb3-if0", 328, R8A774C0_CLK_S3D1),
+ DEF_MOD("usb-dmac0", 330, R8A774C0_CLK_S3D1),
+ DEF_MOD("usb-dmac1", 331, R8A774C0_CLK_S3D1),
+
+ DEF_MOD("rwdt", 402, R8A774C0_CLK_R),
+ DEF_MOD("intc-ex", 407, R8A774C0_CLK_CP),
+ DEF_MOD("intc-ap", 408, R8A774C0_CLK_S0D3),
+
+ DEF_MOD("audmac0", 502, R8A774C0_CLK_S3D4),
+ DEF_MOD("hscif4", 516, R8A774C0_CLK_S3D1C),
+ DEF_MOD("hscif3", 517, R8A774C0_CLK_S3D1C),
+ DEF_MOD("hscif2", 518, R8A774C0_CLK_S3D1C),
+ DEF_MOD("hscif1", 519, R8A774C0_CLK_S3D1C),
+ DEF_MOD("hscif0", 520, R8A774C0_CLK_S3D1C),
+ DEF_MOD("thermal", 522, R8A774C0_CLK_CP),
+ DEF_MOD("pwm", 523, R8A774C0_CLK_S3D4C),
+
+ DEF_MOD("fcpvd1", 602, R8A774C0_CLK_S1D2),
+ DEF_MOD("fcpvd0", 603, R8A774C0_CLK_S1D2),
+ DEF_MOD("fcpvb0", 607, R8A774C0_CLK_S0D1),
+ DEF_MOD("fcpvi0", 611, R8A774C0_CLK_S0D1),
+ DEF_MOD("fcpf0", 615, R8A774C0_CLK_S0D1),
+ DEF_MOD("fcpcs", 619, R8A774C0_CLK_S0D1),
+ DEF_MOD("vspd1", 622, R8A774C0_CLK_S1D2),
+ DEF_MOD("vspd0", 623, R8A774C0_CLK_S1D2),
+ DEF_MOD("vspb", 626, R8A774C0_CLK_S0D1),
+ DEF_MOD("vspi0", 631, R8A774C0_CLK_S0D1),
+
+ DEF_MOD("ehci0", 703, R8A774C0_CLK_S3D4),
+ DEF_MOD("hsusb", 704, R8A774C0_CLK_S3D4),
+ DEF_MOD("csi40", 716, R8A774C0_CLK_CSI0),
+ DEF_MOD("du1", 723, R8A774C0_CLK_S2D1),
+ DEF_MOD("du0", 724, R8A774C0_CLK_S2D1),
+ DEF_MOD("lvds", 727, R8A774C0_CLK_S2D1),
+
+ DEF_MOD("vin5", 806, R8A774C0_CLK_S1D2),
+ DEF_MOD("vin4", 807, R8A774C0_CLK_S1D2),
+ DEF_MOD("etheravb", 812, R8A774C0_CLK_S3D2),
+
+ DEF_MOD("gpio6", 906, R8A774C0_CLK_S3D4),
+ DEF_MOD("gpio5", 907, R8A774C0_CLK_S3D4),
+ DEF_MOD("gpio4", 908, R8A774C0_CLK_S3D4),
+ DEF_MOD("gpio3", 909, R8A774C0_CLK_S3D4),
+ DEF_MOD("gpio2", 910, R8A774C0_CLK_S3D4),
+ DEF_MOD("gpio1", 911, R8A774C0_CLK_S3D4),
+ DEF_MOD("gpio0", 912, R8A774C0_CLK_S3D4),
+ DEF_MOD("can-if1", 915, R8A774C0_CLK_S3D4),
+ DEF_MOD("can-if0", 916, R8A774C0_CLK_S3D4),
+ DEF_MOD("i2c6", 918, R8A774C0_CLK_S3D2),
+ DEF_MOD("i2c5", 919, R8A774C0_CLK_S3D2),
+ DEF_MOD("i2c-dvfs", 926, R8A774C0_CLK_CP),
+ DEF_MOD("i2c4", 927, R8A774C0_CLK_S3D2),
+ DEF_MOD("i2c3", 928, R8A774C0_CLK_S3D2),
+ DEF_MOD("i2c2", 929, R8A774C0_CLK_S3D2),
+ DEF_MOD("i2c1", 930, R8A774C0_CLK_S3D2),
+ DEF_MOD("i2c0", 931, R8A774C0_CLK_S3D2),
+
+ DEF_MOD("i2c7", 1003, R8A774C0_CLK_S3D2),
+ DEF_MOD("ssi-all", 1005, R8A774C0_CLK_S3D4),
+ DEF_MOD("ssi9", 1006, MOD_CLK_ID(1005)),
+ DEF_MOD("ssi8", 1007, MOD_CLK_ID(1005)),
+ DEF_MOD("ssi7", 1008, MOD_CLK_ID(1005)),
+ DEF_MOD("ssi6", 1009, MOD_CLK_ID(1005)),
+ DEF_MOD("ssi5", 1010, MOD_CLK_ID(1005)),
+ DEF_MOD("ssi4", 1011, MOD_CLK_ID(1005)),
+ DEF_MOD("ssi3", 1012, MOD_CLK_ID(1005)),
+ DEF_MOD("ssi2", 1013, MOD_CLK_ID(1005)),
+ DEF_MOD("ssi1", 1014, MOD_CLK_ID(1005)),
+ DEF_MOD("ssi0", 1015, MOD_CLK_ID(1005)),
+ DEF_MOD("scu-all", 1017, R8A774C0_CLK_S3D4),
+ DEF_MOD("scu-dvc1", 1018, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-dvc0", 1019, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-ctu1-mix1", 1020, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-ctu0-mix0", 1021, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src9", 1022, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src8", 1023, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src7", 1024, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src6", 1025, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src5", 1026, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src4", 1027, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src3", 1028, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src2", 1029, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src1", 1030, MOD_CLK_ID(1017)),
+ DEF_MOD("scu-src0", 1031, MOD_CLK_ID(1017)),
+};
+
+static const unsigned int r8a774c0_crit_mod_clks[] __initconst = {
+ MOD_CLK_ID(408), /* INTC-AP (GIC) */
+};
+
+/*
+ * CPG Clock Data
+ */
+
+/*
+ * MD19 EXTAL (MHz) PLL0 PLL1 PLL3
+ *--------------------------------------------------------------------
+ * 0 48 x 1 x100/1 x100/3 x100/3
+ * 1 48 x 1 x100/1 x100/3 x58/3
+ */
+#define CPG_PLL_CONFIG_INDEX(md) (((md) & BIT(19)) >> 19)
+
+static const struct rcar_gen3_cpg_pll_config cpg_pll_configs[2] __initconst = {
+ /* EXTAL div PLL1 mult/div PLL3 mult/div */
+ { 1, 100, 3, 100, 3, },
+ { 1, 100, 3, 58, 3, },
+};
+
+static int __init r8a774c0_cpg_mssr_init(struct device *dev)
+{
+ const struct rcar_gen3_cpg_pll_config *cpg_pll_config;
+ u32 cpg_mode;
+ int error;
+
+ error = rcar_rst_read_mode_pins(&cpg_mode);
+ if (error)
+ return error;
+
+ cpg_pll_config = &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(cpg_mode)];
+
+ return rcar_gen3_cpg_init(cpg_pll_config, 0, cpg_mode);
+}
+
+const struct cpg_mssr_info r8a774c0_cpg_mssr_info __initconst = {
+ /* Core Clocks */
+ .core_clks = r8a774c0_core_clks,
+ .num_core_clks = ARRAY_SIZE(r8a774c0_core_clks),
+ .last_dt_core_clk = LAST_DT_CORE_CLK,
+ .num_total_core_clks = MOD_CLK_BASE,
+
+ /* Module Clocks */
+ .mod_clks = r8a774c0_mod_clks,
+ .num_mod_clks = ARRAY_SIZE(r8a774c0_mod_clks),
+ .num_hw_mod_clks = 12 * 32,
+
+ /* Critical Module Clocks */
+ .crit_mod_clks = r8a774c0_crit_mod_clks,
+ .num_crit_mod_clks = ARRAY_SIZE(r8a774c0_crit_mod_clks),
+
+ /* Callbacks */
+ .init = r8a774c0_cpg_mssr_init,
+ .cpg_clk_register = rcar_gen3_cpg_clk_register,
+};
diff --git a/drivers/clk/renesas/r8a7790-cpg-mssr.c b/drivers/clk/renesas/r8a7790-cpg-mssr.c
index f936cb74b681..c57cb93f8315 100644
--- a/drivers/clk/renesas/r8a7790-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a7790-cpg-mssr.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* r8a7790 Clock Pulse Generator / Module Standby and Software Reset
*
@@ -6,10 +7,6 @@
* Based on clk-rcar-gen2.c
*
* Copyright (C) 2013 Ideas On Board SPRL
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
*/
#include <linux/device.h>
diff --git a/drivers/clk/renesas/r8a7791-cpg-mssr.c b/drivers/clk/renesas/r8a7791-cpg-mssr.c
index 1b91f03b7598..65702debcabb 100644
--- a/drivers/clk/renesas/r8a7791-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a7791-cpg-mssr.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* r8a7791 Clock Pulse Generator / Module Standby and Software Reset
*
@@ -6,10 +7,6 @@
* Based on clk-rcar-gen2.c
*
* Copyright (C) 2013 Ideas On Board SPRL
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
*/
#include <linux/device.h>
diff --git a/drivers/clk/renesas/r8a7792-cpg-mssr.c b/drivers/clk/renesas/r8a7792-cpg-mssr.c
index 493e07859f5f..cf8b84a3a060 100644
--- a/drivers/clk/renesas/r8a7792-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a7792-cpg-mssr.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* r8a7792 Clock Pulse Generator / Module Standby and Software Reset
*
@@ -6,10 +7,6 @@
* Based on clk-rcar-gen2.c
*
* Copyright (C) 2013 Ideas On Board SPRL
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
*/
#include <linux/device.h>
diff --git a/drivers/clk/renesas/r8a7794-cpg-mssr.c b/drivers/clk/renesas/r8a7794-cpg-mssr.c
index 088f4b79fdfc..c1948693c5c1 100644
--- a/drivers/clk/renesas/r8a7794-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a7794-cpg-mssr.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* r8a7794 Clock Pulse Generator / Module Standby and Software Reset
*
@@ -6,10 +7,6 @@
* Based on clk-rcar-gen2.c
*
* Copyright (C) 2013 Ideas On Board SPRL
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
*/
#include <linux/device.h>
diff --git a/drivers/clk/renesas/r8a7795-cpg-mssr.c b/drivers/clk/renesas/r8a7795-cpg-mssr.c
index a85dd50e8911..119c02440726 100644
--- a/drivers/clk/renesas/r8a7795-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a7795-cpg-mssr.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* r8a7795 Clock Pulse Generator / Module Standby and Software Reset
*
@@ -6,10 +7,6 @@
* Based on clk-rcar-gen3.c
*
* Copyright (C) 2015 Renesas Electronics Corp.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
*/
#include <linux/device.h>
@@ -73,6 +70,8 @@ static struct cpg_core_clk r8a7795_core_clks[] __initdata = {
DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 6, 1),
DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL1_DIV2, 2, 1),
+ DEF_GEN3_OSC(".r", CLK_RINT, CLK_EXTAL, 32),
+
/* Core Clock Outputs */
DEF_BASE("z", R8A7795_CLK_Z, CLK_TYPE_GEN3_Z, CLK_PLL0),
DEF_BASE("z2", R8A7795_CLK_Z2, CLK_TYPE_GEN3_Z2, CLK_PLL2),
@@ -111,8 +110,7 @@ static struct cpg_core_clk r8a7795_core_clks[] __initdata = {
DEF_DIV6P1("mso", R8A7795_CLK_MSO, CLK_PLL1_DIV4, 0x014),
DEF_DIV6P1("hdmi", R8A7795_CLK_HDMI, CLK_PLL1_DIV4, 0x250),
- DEF_DIV6_RO("osc", R8A7795_CLK_OSC, CLK_EXTAL, CPG_RCKCR, 8),
- DEF_DIV6_RO("r_int", CLK_RINT, CLK_EXTAL, CPG_RCKCR, 32),
+ DEF_GEN3_OSC("osc", R8A7795_CLK_OSC, CLK_EXTAL, 8),
DEF_BASE("r", R8A7795_CLK_R, CLK_TYPE_GEN3_R, CLK_RINT),
};
@@ -283,25 +281,25 @@ static const unsigned int r8a7795_crit_mod_clks[] __initconst = {
*/
/*
- * MD EXTAL PLL0 PLL1 PLL2 PLL3 PLL4
+ * MD EXTAL PLL0 PLL1 PLL2 PLL3 PLL4 OSC
* 14 13 19 17 (MHz)
- *-------------------------------------------------------------------
- * 0 0 0 0 16.66 x 1 x180 x192 x144 x192 x144
- * 0 0 0 1 16.66 x 1 x180 x192 x144 x128 x144
+ *-------------------------------------------------------------------------
+ * 0 0 0 0 16.66 x 1 x180 x192 x144 x192 x144 /16
+ * 0 0 0 1 16.66 x 1 x180 x192 x144 x128 x144 /16
* 0 0 1 0 Prohibited setting
- * 0 0 1 1 16.66 x 1 x180 x192 x144 x192 x144
- * 0 1 0 0 20 x 1 x150 x160 x120 x160 x120
- * 0 1 0 1 20 x 1 x150 x160 x120 x106 x120
+ * 0 0 1 1 16.66 x 1 x180 x192 x144 x192 x144 /16
+ * 0 1 0 0 20 x 1 x150 x160 x120 x160 x120 /19
+ * 0 1 0 1 20 x 1 x150 x160 x120 x106 x120 /19
* 0 1 1 0 Prohibited setting
- * 0 1 1 1 20 x 1 x150 x160 x120 x160 x120
- * 1 0 0 0 25 x 1 x120 x128 x96 x128 x96
- * 1 0 0 1 25 x 1 x120 x128 x96 x84 x96
+ * 0 1 1 1 20 x 1 x150 x160 x120 x160 x120 /19
+ * 1 0 0 0 25 x 1 x120 x128 x96 x128 x96 /24
+ * 1 0 0 1 25 x 1 x120 x128 x96 x84 x96 /24
* 1 0 1 0 Prohibited setting
- * 1 0 1 1 25 x 1 x120 x128 x96 x128 x96
- * 1 1 0 0 33.33 / 2 x180 x192 x144 x192 x144
- * 1 1 0 1 33.33 / 2 x180 x192 x144 x128 x144
+ * 1 0 1 1 25 x 1 x120 x128 x96 x128 x96 /24
+ * 1 1 0 0 33.33 / 2 x180 x192 x144 x192 x144 /32
+ * 1 1 0 1 33.33 / 2 x180 x192 x144 x128 x144 /32
* 1 1 1 0 Prohibited setting
- * 1 1 1 1 33.33 / 2 x180 x192 x144 x192 x144
+ * 1 1 1 1 33.33 / 2 x180 x192 x144 x192 x144 /32
*/
#define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 11) | \
(((md) & BIT(13)) >> 11) | \
@@ -309,23 +307,23 @@ static const unsigned int r8a7795_crit_mod_clks[] __initconst = {
(((md) & BIT(17)) >> 17))
static const struct rcar_gen3_cpg_pll_config cpg_pll_configs[16] __initconst = {
- /* EXTAL div PLL1 mult/div PLL3 mult/div */
- { 1, 192, 1, 192, 1, },
- { 1, 192, 1, 128, 1, },
- { 0, /* Prohibited setting */ },
- { 1, 192, 1, 192, 1, },
- { 1, 160, 1, 160, 1, },
- { 1, 160, 1, 106, 1, },
- { 0, /* Prohibited setting */ },
- { 1, 160, 1, 160, 1, },
- { 1, 128, 1, 128, 1, },
- { 1, 128, 1, 84, 1, },
- { 0, /* Prohibited setting */ },
- { 1, 128, 1, 128, 1, },
- { 2, 192, 1, 192, 1, },
- { 2, 192, 1, 128, 1, },
- { 0, /* Prohibited setting */ },
- { 2, 192, 1, 192, 1, },
+ /* EXTAL div PLL1 mult/div PLL3 mult/div OSC prediv */
+ { 1, 192, 1, 192, 1, 16, },
+ { 1, 192, 1, 128, 1, 16, },
+ { 0, /* Prohibited setting */ },
+ { 1, 192, 1, 192, 1, 16, },
+ { 1, 160, 1, 160, 1, 19, },
+ { 1, 160, 1, 106, 1, 19, },
+ { 0, /* Prohibited setting */ },
+ { 1, 160, 1, 160, 1, 19, },
+ { 1, 128, 1, 128, 1, 24, },
+ { 1, 128, 1, 84, 1, 24, },
+ { 0, /* Prohibited setting */ },
+ { 1, 128, 1, 128, 1, 24, },
+ { 2, 192, 1, 192, 1, 32, },
+ { 2, 192, 1, 128, 1, 32, },
+ { 0, /* Prohibited setting */ },
+ { 2, 192, 1, 192, 1, 32, },
};
static const struct soc_device_attribute r8a7795es1[] __initconst = {
diff --git a/drivers/clk/renesas/r8a7796-cpg-mssr.c b/drivers/clk/renesas/r8a7796-cpg-mssr.c
index dfb267a92f2a..10567386e6dd 100644
--- a/drivers/clk/renesas/r8a7796-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a7796-cpg-mssr.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* r8a7796 Clock Pulse Generator / Module Standby and Software Reset
*
@@ -7,10 +8,6 @@
*
* Copyright (C) 2015 Glider bvba
* Copyright (C) 2015 Renesas Electronics Corp.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
*/
#include <linux/device.h>
@@ -73,6 +70,8 @@ static const struct cpg_core_clk r8a7796_core_clks[] __initconst = {
DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 6, 1),
DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL1_DIV2, 2, 1),
+ DEF_GEN3_OSC(".r", CLK_RINT, CLK_EXTAL, 32),
+
/* Core Clock Outputs */
DEF_BASE("z", R8A7796_CLK_Z, CLK_TYPE_GEN3_Z, CLK_PLL0),
DEF_BASE("z2", R8A7796_CLK_Z2, CLK_TYPE_GEN3_Z2, CLK_PLL2),
@@ -110,8 +109,7 @@ static const struct cpg_core_clk r8a7796_core_clks[] __initconst = {
DEF_DIV6P1("mso", R8A7796_CLK_MSO, CLK_PLL1_DIV4, 0x014),
DEF_DIV6P1("hdmi", R8A7796_CLK_HDMI, CLK_PLL1_DIV4, 0x250),
- DEF_DIV6_RO("osc", R8A7796_CLK_OSC, CLK_EXTAL, CPG_RCKCR, 8),
- DEF_DIV6_RO("r_int", CLK_RINT, CLK_EXTAL, CPG_RCKCR, 32),
+ DEF_GEN3_OSC("osc", R8A7796_CLK_OSC, CLK_EXTAL, 8),
DEF_BASE("r", R8A7796_CLK_R, CLK_TYPE_GEN3_R, CLK_RINT),
};
@@ -255,25 +253,25 @@ static const unsigned int r8a7796_crit_mod_clks[] __initconst = {
*/
/*
- * MD EXTAL PLL0 PLL1 PLL2 PLL3 PLL4
+ * MD EXTAL PLL0 PLL1 PLL2 PLL3 PLL4 OSC
* 14 13 19 17 (MHz)
- *-------------------------------------------------------------------
- * 0 0 0 0 16.66 x 1 x180 x192 x144 x192 x144
- * 0 0 0 1 16.66 x 1 x180 x192 x144 x128 x144
+ *-------------------------------------------------------------------------
+ * 0 0 0 0 16.66 x 1 x180 x192 x144 x192 x144 /16
+ * 0 0 0 1 16.66 x 1 x180 x192 x144 x128 x144 /16
* 0 0 1 0 Prohibited setting
- * 0 0 1 1 16.66 x 1 x180 x192 x144 x192 x144
- * 0 1 0 0 20 x 1 x150 x160 x120 x160 x120
- * 0 1 0 1 20 x 1 x150 x160 x120 x106 x120
+ * 0 0 1 1 16.66 x 1 x180 x192 x144 x192 x144 /16
+ * 0 1 0 0 20 x 1 x150 x160 x120 x160 x120 /19
+ * 0 1 0 1 20 x 1 x150 x160 x120 x106 x120 /19
* 0 1 1 0 Prohibited setting
- * 0 1 1 1 20 x 1 x150 x160 x120 x160 x120
- * 1 0 0 0 25 x 1 x120 x128 x96 x128 x96
- * 1 0 0 1 25 x 1 x120 x128 x96 x84 x96
+ * 0 1 1 1 20 x 1 x150 x160 x120 x160 x120 /19
+ * 1 0 0 0 25 x 1 x120 x128 x96 x128 x96 /24
+ * 1 0 0 1 25 x 1 x120 x128 x96 x84 x96 /24
* 1 0 1 0 Prohibited setting
- * 1 0 1 1 25 x 1 x120 x128 x96 x128 x96
- * 1 1 0 0 33.33 / 2 x180 x192 x144 x192 x144
- * 1 1 0 1 33.33 / 2 x180 x192 x144 x128 x144
+ * 1 0 1 1 25 x 1 x120 x128 x96 x128 x96 /24
+ * 1 1 0 0 33.33 / 2 x180 x192 x144 x192 x144 /32
+ * 1 1 0 1 33.33 / 2 x180 x192 x144 x128 x144 /32
* 1 1 1 0 Prohibited setting
- * 1 1 1 1 33.33 / 2 x180 x192 x144 x192 x144
+ * 1 1 1 1 33.33 / 2 x180 x192 x144 x192 x144 /32
*/
#define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 11) | \
(((md) & BIT(13)) >> 11) | \
@@ -281,23 +279,23 @@ static const unsigned int r8a7796_crit_mod_clks[] __initconst = {
(((md) & BIT(17)) >> 17))
static const struct rcar_gen3_cpg_pll_config cpg_pll_configs[16] __initconst = {
- /* EXTAL div PLL1 mult/div PLL3 mult/div */
- { 1, 192, 1, 192, 1, },
- { 1, 192, 1, 128, 1, },
- { 0, /* Prohibited setting */ },
- { 1, 192, 1, 192, 1, },
- { 1, 160, 1, 160, 1, },
- { 1, 160, 1, 106, 1, },
- { 0, /* Prohibited setting */ },
- { 1, 160, 1, 160, 1, },
- { 1, 128, 1, 128, 1, },
- { 1, 128, 1, 84, 1, },
- { 0, /* Prohibited setting */ },
- { 1, 128, 1, 128, 1, },
- { 2, 192, 1, 192, 1, },
- { 2, 192, 1, 128, 1, },
- { 0, /* Prohibited setting */ },
- { 2, 192, 1, 192, 1, },
+ /* EXTAL div PLL1 mult/div PLL3 mult/div OSC prediv */
+ { 1, 192, 1, 192, 1, 16, },
+ { 1, 192, 1, 128, 1, 16, },
+ { 0, /* Prohibited setting */ },
+ { 1, 192, 1, 192, 1, 16, },
+ { 1, 160, 1, 160, 1, 19, },
+ { 1, 160, 1, 106, 1, 19, },
+ { 0, /* Prohibited setting */ },
+ { 1, 160, 1, 160, 1, 19, },
+ { 1, 128, 1, 128, 1, 24, },
+ { 1, 128, 1, 84, 1, 24, },
+ { 0, /* Prohibited setting */ },
+ { 1, 128, 1, 128, 1, 24, },
+ { 2, 192, 1, 192, 1, 32, },
+ { 2, 192, 1, 128, 1, 32, },
+ { 0, /* Prohibited setting */ },
+ { 2, 192, 1, 192, 1, 32, },
};
static int __init r8a7796_cpg_mssr_init(struct device *dev)
diff --git a/drivers/clk/renesas/r8a77965-cpg-mssr.c b/drivers/clk/renesas/r8a77965-cpg-mssr.c
index 8fae5e9c4a77..1fcc411502da 100644
--- a/drivers/clk/renesas/r8a77965-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a77965-cpg-mssr.c
@@ -68,6 +68,8 @@ static const struct cpg_core_clk r8a77965_core_clks[] __initconst = {
DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 6, 1),
DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL1_DIV2, 2, 1),
+ DEF_GEN3_OSC(".r", CLK_RINT, CLK_EXTAL, 32),
+
/* Core Clock Outputs */
DEF_BASE("z", R8A77965_CLK_Z, CLK_TYPE_GEN3_Z, CLK_PLL0),
DEF_FIXED("ztr", R8A77965_CLK_ZTR, CLK_PLL1_DIV2, 6, 1),
@@ -104,13 +106,13 @@ static const struct cpg_core_clk r8a77965_core_clks[] __initconst = {
DEF_DIV6P1("mso", R8A77965_CLK_MSO, CLK_PLL1_DIV4, 0x014),
DEF_DIV6P1("hdmi", R8A77965_CLK_HDMI, CLK_PLL1_DIV4, 0x250),
- DEF_DIV6_RO("osc", R8A77965_CLK_OSC, CLK_EXTAL, CPG_RCKCR, 8),
- DEF_DIV6_RO("r_int", CLK_RINT, CLK_EXTAL, CPG_RCKCR, 32),
+ DEF_GEN3_OSC("osc", R8A77965_CLK_OSC, CLK_EXTAL, 8),
DEF_BASE("r", R8A77965_CLK_R, CLK_TYPE_GEN3_R, CLK_RINT),
};
static const struct mssr_mod_clk r8a77965_mod_clks[] __initconst = {
+ DEF_MOD("fdp1-0", 119, R8A77965_CLK_S0D1),
DEF_MOD("scif5", 202, R8A77965_CLK_S3D4),
DEF_MOD("scif4", 203, R8A77965_CLK_S3D4),
DEF_MOD("scif3", 204, R8A77965_CLK_S3D4),
@@ -192,6 +194,7 @@ static const struct mssr_mod_clk r8a77965_mod_clks[] __initconst = {
DEF_MOD("vin1", 810, R8A77965_CLK_S0D2),
DEF_MOD("vin0", 811, R8A77965_CLK_S0D2),
DEF_MOD("etheravb", 812, R8A77965_CLK_S0D6),
+ DEF_MOD("sata0", 815, R8A77965_CLK_S3D2),
DEF_MOD("imr1", 822, R8A77965_CLK_S0D2),
DEF_MOD("imr0", 823, R8A77965_CLK_S0D2),
@@ -252,25 +255,25 @@ static const unsigned int r8a77965_crit_mod_clks[] __initconst = {
*/
/*
- * MD EXTAL PLL0 PLL1 PLL3 PLL4
+ * MD EXTAL PLL0 PLL1 PLL3 PLL4 OSC
* 14 13 19 17 (MHz)
- *-----------------------------------------------------------
- * 0 0 0 0 16.66 x 1 x180 x192 x192 x144
- * 0 0 0 1 16.66 x 1 x180 x192 x128 x144
+ *-----------------------------------------------------------------
+ * 0 0 0 0 16.66 x 1 x180 x192 x192 x144 /16
+ * 0 0 0 1 16.66 x 1 x180 x192 x128 x144 /16
* 0 0 1 0 Prohibited setting
- * 0 0 1 1 16.66 x 1 x180 x192 x192 x144
- * 0 1 0 0 20 x 1 x150 x160 x160 x120
- * 0 1 0 1 20 x 1 x150 x160 x106 x120
+ * 0 0 1 1 16.66 x 1 x180 x192 x192 x144 /16
+ * 0 1 0 0 20 x 1 x150 x160 x160 x120 /19
+ * 0 1 0 1 20 x 1 x150 x160 x106 x120 /19
* 0 1 1 0 Prohibited setting
- * 0 1 1 1 20 x 1 x150 x160 x160 x120
- * 1 0 0 0 25 x 1 x120 x128 x128 x96
- * 1 0 0 1 25 x 1 x120 x128 x84 x96
+ * 0 1 1 1 20 x 1 x150 x160 x160 x120 /19
+ * 1 0 0 0 25 x 1 x120 x128 x128 x96 /24
+ * 1 0 0 1 25 x 1 x120 x128 x84 x96 /24
* 1 0 1 0 Prohibited setting
- * 1 0 1 1 25 x 1 x120 x128 x128 x96
- * 1 1 0 0 33.33 / 2 x180 x192 x192 x144
- * 1 1 0 1 33.33 / 2 x180 x192 x128 x144
+ * 1 0 1 1 25 x 1 x120 x128 x128 x96 /24
+ * 1 1 0 0 33.33 / 2 x180 x192 x192 x144 /32
+ * 1 1 0 1 33.33 / 2 x180 x192 x128 x144 /32
* 1 1 1 0 Prohibited setting
- * 1 1 1 1 33.33 / 2 x180 x192 x192 x144
+ * 1 1 1 1 33.33 / 2 x180 x192 x192 x144 /32
*/
#define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 11) | \
(((md) & BIT(13)) >> 11) | \
@@ -278,23 +281,23 @@ static const unsigned int r8a77965_crit_mod_clks[] __initconst = {
(((md) & BIT(17)) >> 17))
static const struct rcar_gen3_cpg_pll_config cpg_pll_configs[16] __initconst = {
- /* EXTAL div PLL1 mult/div PLL3 mult/div */
- { 1, 192, 1, 192, 1, },
- { 1, 192, 1, 128, 1, },
- { 0, /* Prohibited setting */ },
- { 1, 192, 1, 192, 1, },
- { 1, 160, 1, 160, 1, },
- { 1, 160, 1, 106, 1, },
- { 0, /* Prohibited setting */ },
- { 1, 160, 1, 160, 1, },
- { 1, 128, 1, 128, 1, },
- { 1, 128, 1, 84, 1, },
- { 0, /* Prohibited setting */ },
- { 1, 128, 1, 128, 1, },
- { 2, 192, 1, 192, 1, },
- { 2, 192, 1, 128, 1, },
- { 0, /* Prohibited setting */ },
- { 2, 192, 1, 192, 1, },
+ /* EXTAL div PLL1 mult/div PLL3 mult/div OSC prediv */
+ { 1, 192, 1, 192, 1, 16, },
+ { 1, 192, 1, 128, 1, 16, },
+ { 0, /* Prohibited setting */ },
+ { 1, 192, 1, 192, 1, 16, },
+ { 1, 160, 1, 160, 1, 19, },
+ { 1, 160, 1, 106, 1, 19, },
+ { 0, /* Prohibited setting */ },
+ { 1, 160, 1, 160, 1, 19, },
+ { 1, 128, 1, 128, 1, 24, },
+ { 1, 128, 1, 84, 1, 24, },
+ { 0, /* Prohibited setting */ },
+ { 1, 128, 1, 128, 1, 24, },
+ { 2, 192, 1, 192, 1, 32, },
+ { 2, 192, 1, 128, 1, 32, },
+ { 0, /* Prohibited setting */ },
+ { 2, 192, 1, 192, 1, 32, },
};
static int __init r8a77965_cpg_mssr_init(struct device *dev)
diff --git a/drivers/clk/renesas/r8a77970-cpg-mssr.c b/drivers/clk/renesas/r8a77970-cpg-mssr.c
index f55842917e8d..2015e45543e9 100644
--- a/drivers/clk/renesas/r8a77970-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a77970-cpg-mssr.c
@@ -1,17 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* r8a77970 Clock Pulse Generator / Module Standby and Software Reset
*
- * Copyright (C) 2017 Cogent Embedded Inc.
+ * Copyright (C) 2017-2018 Cogent Embedded Inc.
*
* Based on r8a7795-cpg-mssr.c
*
* Copyright (C) 2015 Glider bvba
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
*/
+#include <linux/clk-provider.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -22,6 +20,13 @@
#include "renesas-cpg-mssr.h"
#include "rcar-gen3-cpg.h"
+#define CPG_SD0CKCR 0x0074
+
+enum r8a77970_clk_types {
+ CLK_TYPE_R8A77970_SD0H = CLK_TYPE_GEN3_SOC_BASE,
+ CLK_TYPE_R8A77970_SD0,
+};
+
enum clk_ids {
/* Core Clock Outputs exported to DT */
LAST_DT_CORE_CLK = R8A77970_CLK_OSC,
@@ -42,6 +47,20 @@ enum clk_ids {
MOD_CLK_BASE
};
+static spinlock_t cpg_lock;
+
+static const struct clk_div_table cpg_sd0h_div_table[] = {
+ { 0, 2 }, { 1, 3 }, { 2, 4 }, { 3, 6 },
+ { 4, 8 }, { 5, 12 }, { 6, 16 }, { 7, 18 },
+ { 8, 24 }, { 10, 36 }, { 11, 48 }, { 0, 0 },
+};
+
+static const struct clk_div_table cpg_sd0_div_table[] = {
+ { 4, 8 }, { 5, 12 }, { 6, 16 }, { 7, 18 },
+ { 8, 24 }, { 10, 36 }, { 11, 48 }, { 12, 10 },
+ { 0, 0 },
+};
+
static const struct cpg_core_clk r8a77970_core_clks[] __initconst = {
/* External Clock Inputs */
DEF_INPUT("extal", CLK_EXTAL),
@@ -68,6 +87,10 @@ static const struct cpg_core_clk r8a77970_core_clks[] __initconst = {
DEF_FIXED("s2d2", R8A77970_CLK_S2D2, CLK_PLL1_DIV2, 12, 1),
DEF_FIXED("s2d4", R8A77970_CLK_S2D4, CLK_PLL1_DIV2, 24, 1),
+ DEF_BASE("sd0h", R8A77970_CLK_SD0H, CLK_TYPE_R8A77970_SD0H,
+ CLK_PLL1_DIV2),
+ DEF_BASE("sd0", R8A77970_CLK_SD0, CLK_TYPE_R8A77970_SD0, CLK_PLL1_DIV2),
+
DEF_FIXED("cl", R8A77970_CLK_CL, CLK_PLL1_DIV2, 48, 1),
DEF_FIXED("cp", R8A77970_CLK_CP, CLK_EXTAL, 2, 1),
@@ -80,6 +103,11 @@ static const struct cpg_core_clk r8a77970_core_clks[] __initconst = {
};
static const struct mssr_mod_clk r8a77970_mod_clks[] __initconst = {
+ DEF_MOD("tmu4", 121, R8A77970_CLK_S2D2),
+ DEF_MOD("tmu3", 122, R8A77970_CLK_S2D2),
+ DEF_MOD("tmu2", 123, R8A77970_CLK_S2D2),
+ DEF_MOD("tmu1", 124, R8A77970_CLK_S2D2),
+ DEF_MOD("tmu0", 125, R8A77970_CLK_CP),
DEF_MOD("ivcp1e", 127, R8A77970_CLK_S2D1),
DEF_MOD("scif4", 203, R8A77970_CLK_S2D4),
DEF_MOD("scif3", 204, R8A77970_CLK_S2D4),
@@ -92,6 +120,12 @@ static const struct mssr_mod_clk r8a77970_mod_clks[] __initconst = {
DEF_MOD("mfis", 213, R8A77970_CLK_S2D2),
DEF_MOD("sys-dmac2", 217, R8A77970_CLK_S2D1),
DEF_MOD("sys-dmac1", 218, R8A77970_CLK_S2D1),
+ DEF_MOD("cmt3", 300, R8A77970_CLK_R),
+ DEF_MOD("cmt2", 301, R8A77970_CLK_R),
+ DEF_MOD("cmt1", 302, R8A77970_CLK_R),
+ DEF_MOD("cmt0", 303, R8A77970_CLK_R),
+ DEF_MOD("tpu0", 304, R8A77970_CLK_S2D4),
+ DEF_MOD("sd-if", 314, R8A77970_CLK_SD0),
DEF_MOD("rwdt", 402, R8A77970_CLK_R),
DEF_MOD("intc-ex", 407, R8A77970_CLK_CP),
DEF_MOD("intc-ap", 408, R8A77970_CLK_S2D1),
@@ -173,11 +207,46 @@ static int __init r8a77970_cpg_mssr_init(struct device *dev)
if (error)
return error;
+ spin_lock_init(&cpg_lock);
+
cpg_pll_config = &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(cpg_mode)];
return rcar_gen3_cpg_init(cpg_pll_config, CLK_EXTALR, cpg_mode);
}
+static struct clk * __init r8a77970_cpg_clk_register(struct device *dev,
+ const struct cpg_core_clk *core, const struct cpg_mssr_info *info,
+ struct clk **clks, void __iomem *base,
+ struct raw_notifier_head *notifiers)
+{
+ const struct clk_div_table *table;
+ const struct clk *parent;
+ unsigned int shift;
+
+ switch (core->type) {
+ case CLK_TYPE_R8A77970_SD0H:
+ table = cpg_sd0h_div_table;
+ shift = 8;
+ break;
+ case CLK_TYPE_R8A77970_SD0:
+ table = cpg_sd0_div_table;
+ shift = 4;
+ break;
+ default:
+ return rcar_gen3_cpg_clk_register(dev, core, info, clks, base,
+ notifiers);
+ }
+
+ parent = clks[core->parent];
+ if (IS_ERR(parent))
+ return ERR_CAST(parent);
+
+ return clk_register_divider_table(NULL, core->name,
+ __clk_get_name(parent), 0,
+ base + CPG_SD0CKCR,
+ shift, 4, 0, table, &cpg_lock);
+}
+
const struct cpg_mssr_info r8a77970_cpg_mssr_info __initconst = {
/* Core Clocks */
.core_clks = r8a77970_core_clks,
@@ -196,5 +265,5 @@ const struct cpg_mssr_info r8a77970_cpg_mssr_info __initconst = {
/* Callbacks */
.init = r8a77970_cpg_mssr_init,
- .cpg_clk_register = rcar_gen3_cpg_clk_register,
+ .cpg_clk_register = r8a77970_cpg_clk_register,
};
diff --git a/drivers/clk/renesas/r8a77980-cpg-mssr.c b/drivers/clk/renesas/r8a77980-cpg-mssr.c
index d7ebd9ec0059..25a3083b6764 100644
--- a/drivers/clk/renesas/r8a77980-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a77980-cpg-mssr.c
@@ -41,6 +41,7 @@ enum clk_ids {
CLK_S2,
CLK_S3,
CLK_SDSRC,
+ CLK_OCO,
/* Module Clocks */
MOD_CLK_BASE
@@ -64,6 +65,7 @@ static const struct cpg_core_clk r8a77980_core_clks[] __initconst = {
DEF_FIXED(".s2", CLK_S2, CLK_PLL1_DIV2, 4, 1),
DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 6, 1),
DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL1_DIV2, 2, 1),
+ DEF_RATE(".oco", CLK_OCO, 32768),
/* Core Clock Outputs */
DEF_FIXED("ztr", R8A77980_CLK_ZTR, CLK_PLL1_DIV2, 6, 1),
@@ -96,6 +98,9 @@ static const struct cpg_core_clk r8a77980_core_clks[] __initconst = {
DEF_DIV6P1("canfd", R8A77980_CLK_CANFD, CLK_PLL1_DIV4, 0x244),
DEF_DIV6P1("csi0", R8A77980_CLK_CSI0, CLK_PLL1_DIV4, 0x00c),
DEF_DIV6P1("mso", R8A77980_CLK_MSO, CLK_PLL1_DIV4, 0x014),
+
+ DEF_GEN3_OSC("osc", R8A77980_CLK_OSC, CLK_EXTAL, 8),
+ DEF_GEN3_MDSEL("r", R8A77980_CLK_R, 29, CLK_EXTALR, 1, CLK_OCO, 1),
};
static const struct mssr_mod_clk r8a77980_mod_clks[] __initconst = {
@@ -114,9 +119,14 @@ static const struct mssr_mod_clk r8a77980_mod_clks[] __initconst = {
DEF_MOD("msiof0", 211, R8A77980_CLK_MSO),
DEF_MOD("sys-dmac2", 217, R8A77980_CLK_S0D3),
DEF_MOD("sys-dmac1", 218, R8A77980_CLK_S0D3),
+ DEF_MOD("cmt3", 300, R8A77980_CLK_R),
+ DEF_MOD("cmt2", 301, R8A77980_CLK_R),
+ DEF_MOD("cmt1", 302, R8A77980_CLK_R),
+ DEF_MOD("cmt0", 303, R8A77980_CLK_R),
DEF_MOD("tpu0", 304, R8A77980_CLK_S3D4),
DEF_MOD("sdif", 314, R8A77980_CLK_SD0),
DEF_MOD("pciec0", 319, R8A77980_CLK_S2D2),
+ DEF_MOD("rwdt", 402, R8A77980_CLK_R),
DEF_MOD("intc-ex", 407, R8A77980_CLK_CP),
DEF_MOD("intc-ap", 408, R8A77980_CLK_S0D3),
DEF_MOD("hscif3", 517, R8A77980_CLK_S3D1),
@@ -171,23 +181,23 @@ static const unsigned int r8a77980_crit_mod_clks[] __initconst = {
*/
/*
- * MD EXTAL PLL2 PLL1 PLL3
+ * MD EXTAL PLL2 PLL1 PLL3 OSC
* 14 13 (MHz)
- * --------------------------------------------------
- * 0 0 16.66 x 1 x240 x192 x192
- * 0 1 20 x 1 x200 x160 x160
- * 1 0 27 x 1 x148 x118 x118
- * 1 1 33.33 / 2 x240 x192 x192
+ * --------------------------------------------------------
+ * 0 0 16.66 x 1 x240 x192 x192 /16
+ * 0 1 20 x 1 x200 x160 x160 /19
+ * 1 0 27 x 1 x148 x118 x118 /26
+ * 1 1 33.33 / 2 x240 x192 x192 /32
*/
#define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 13) | \
(((md) & BIT(13)) >> 13))
static const struct rcar_gen3_cpg_pll_config cpg_pll_configs[4] __initconst = {
- /* EXTAL div PLL1 mult/div PLL3 mult/div */
- { 1, 192, 1, 192, 1, },
- { 1, 160, 1, 160, 1, },
- { 1, 118, 1, 118, 1, },
- { 2, 192, 1, 192, 1, },
+ /* EXTAL div PLL1 mult/div PLL3 mult/div OSC prediv */
+ { 1, 192, 1, 192, 1, 16, },
+ { 1, 160, 1, 160, 1, 19, },
+ { 1, 118, 1, 118, 1, 26, },
+ { 2, 192, 1, 192, 1, 32, },
};
static int __init r8a77980_cpg_mssr_init(struct device *dev)
diff --git a/drivers/clk/renesas/r8a77990-cpg-mssr.c b/drivers/clk/renesas/r8a77990-cpg-mssr.c
index 9e14f1486fbb..9eb80180eea0 100644
--- a/drivers/clk/renesas/r8a77990-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a77990-cpg-mssr.c
@@ -44,6 +44,8 @@ enum clk_ids {
CLK_S2,
CLK_S3,
CLK_SDSRC,
+ CLK_RINT,
+ CLK_OCO,
/* Module Clocks */
MOD_CLK_BASE
@@ -72,6 +74,10 @@ static const struct cpg_core_clk r8a77990_core_clks[] __initconst = {
DEF_FIXED(".s3", CLK_S3, CLK_PLL1, 6, 1),
DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL1, 2, 1),
+ DEF_DIV6_RO(".r", CLK_RINT, CLK_EXTAL, CPG_RCKCR, 32),
+
+ DEF_RATE(".oco", CLK_OCO, 8 * 1000 * 1000),
+
/* Core Clock Outputs */
DEF_FIXED("za2", R8A77990_CLK_ZA2, CLK_PLL0D24, 1, 1),
DEF_FIXED("za8", R8A77990_CLK_ZA8, CLK_PLL0D8, 1, 1),
@@ -100,8 +106,8 @@ static const struct cpg_core_clk r8a77990_core_clks[] __initconst = {
DEF_FIXED("cl", R8A77990_CLK_CL, CLK_PLL1, 48, 1),
DEF_FIXED("cp", R8A77990_CLK_CP, CLK_EXTAL, 2, 1),
DEF_FIXED("cpex", R8A77990_CLK_CPEX, CLK_EXTAL, 4, 1),
- DEF_FIXED("osc", R8A77990_CLK_OSC, CLK_EXTAL, 384, 1),
- DEF_FIXED("r", R8A77990_CLK_R, CLK_EXTAL, 1536, 1),
+
+ DEF_DIV6_RO("osc", R8A77990_CLK_OSC, CLK_EXTAL, CPG_RCKCR, 8),
DEF_GEN3_PE("s0d6c", R8A77990_CLK_S0D6C, CLK_S0, 6, CLK_PE, 2),
DEF_GEN3_PE("s3d1c", R8A77990_CLK_S3D1C, CLK_S3, 1, CLK_PE, 1),
@@ -111,6 +117,8 @@ static const struct cpg_core_clk r8a77990_core_clks[] __initconst = {
DEF_DIV6P1("canfd", R8A77990_CLK_CANFD, CLK_PLL0D6, 0x244),
DEF_DIV6P1("csi0", R8A77990_CLK_CSI0, CLK_PLL1D2, 0x00c),
DEF_DIV6P1("mso", R8A77990_CLK_MSO, CLK_PLL1D2, 0x014),
+
+ DEF_GEN3_RCKSEL("r", R8A77990_CLK_R, CLK_RINT, 1, CLK_OCO, 61 * 4),
};
static const struct mssr_mod_clk r8a77990_mod_clks[] __initconst = {
@@ -202,6 +210,7 @@ static const struct mssr_mod_clk r8a77990_mod_clks[] __initconst = {
DEF_MOD("i2c1", 930, R8A77990_CLK_S3D2),
DEF_MOD("i2c0", 931, R8A77990_CLK_S3D2),
+ DEF_MOD("i2c7", 1003, R8A77990_CLK_S3D2),
DEF_MOD("ssi-all", 1005, R8A77990_CLK_S3D4),
DEF_MOD("ssi9", 1006, MOD_CLK_ID(1005)),
DEF_MOD("ssi8", 1007, MOD_CLK_ID(1005)),
@@ -241,8 +250,8 @@ static const unsigned int r8a77990_crit_mod_clks[] __initconst = {
/*
* MD19 EXTAL (MHz) PLL0 PLL1 PLL3
*--------------------------------------------------------------------
- * 0 48 x 1 x100/4 x100/3 x100/3
- * 1 48 x 1 x100/4 x100/3 x58/3
+ * 0 48 x 1 x100/1 x100/3 x100/3
+ * 1 48 x 1 x100/1 x100/3 x58/3
*/
#define CPG_PLL_CONFIG_INDEX(md) (((md) & BIT(19)) >> 19)
diff --git a/drivers/clk/renesas/r8a77995-cpg-mssr.c b/drivers/clk/renesas/r8a77995-cpg-mssr.c
index ea4cafbe6e85..47e60e3dbe05 100644
--- a/drivers/clk/renesas/r8a77995-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a77995-cpg-mssr.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* r8a77995 Clock Pulse Generator / Module Standby and Software Reset
*
@@ -7,10 +8,6 @@
*
* Copyright (C) 2015 Glider bvba
* Copyright (C) 2015 Renesas Electronics Corp.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
*/
#include <linux/device.h>
@@ -46,6 +43,8 @@ enum clk_ids {
CLK_S3,
CLK_SDSRC,
CLK_SSPSRC,
+ CLK_RINT,
+ CLK_OCO,
/* Module Clocks */
MOD_CLK_BASE
@@ -72,6 +71,10 @@ static const struct cpg_core_clk r8a77995_core_clks[] __initconst = {
DEF_FIXED(".s3", CLK_S3, CLK_PLL1, 6, 1),
DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL1, 2, 1),
+ DEF_DIV6_RO(".r", CLK_RINT, CLK_EXTAL, CPG_RCKCR, 32),
+
+ DEF_RATE(".oco", CLK_OCO, 8 * 1000 * 1000),
+
/* Core Clock Outputs */
DEF_FIXED("z2", R8A77995_CLK_Z2, CLK_PLL0D3, 1, 1),
DEF_FIXED("ztr", R8A77995_CLK_ZTR, CLK_PLL1, 6, 1),
@@ -90,8 +93,8 @@ static const struct cpg_core_clk r8a77995_core_clks[] __initconst = {
DEF_FIXED("cl", R8A77995_CLK_CL, CLK_PLL1, 48, 1),
DEF_FIXED("cp", R8A77995_CLK_CP, CLK_EXTAL, 2, 1),
- DEF_FIXED("osc", R8A77995_CLK_OSC, CLK_EXTAL, 384, 1),
- DEF_FIXED("r", R8A77995_CLK_R, CLK_EXTAL, 1536, 1),
+
+ DEF_DIV6_RO("osc", R8A77995_CLK_OSC, CLK_EXTAL, CPG_RCKCR, 8),
DEF_GEN3_PE("s1d4c", R8A77995_CLK_S1D4C, CLK_S1, 4, CLK_PE, 2),
DEF_GEN3_PE("s3d1c", R8A77995_CLK_S3D1C, CLK_S3, 1, CLK_PE, 1),
@@ -102,6 +105,8 @@ static const struct cpg_core_clk r8a77995_core_clks[] __initconst = {
DEF_DIV6P1("canfd", R8A77995_CLK_CANFD, CLK_PLL0D3, 0x244),
DEF_DIV6P1("mso", R8A77995_CLK_MSO, CLK_PLL1D2, 0x014),
+
+ DEF_GEN3_RCKSEL("r", R8A77995_CLK_R, CLK_RINT, 1, CLK_OCO, 61 * 4),
};
static const struct mssr_mod_clk r8a77995_mod_clks[] __initconst = {
diff --git a/drivers/clk/renesas/r9a06g032-clocks.c b/drivers/clk/renesas/r9a06g032-clocks.c
index a0b6ecdc63dd..6d2b56891559 100644
--- a/drivers/clk/renesas/r9a06g032-clocks.c
+++ b/drivers/clk/renesas/r9a06g032-clocks.c
@@ -539,7 +539,8 @@ r9a06g032_div_round_rate(struct clk_hw *hw,
* several uarts attached to this divider, and changing this impacts
* everyone.
*/
- if (clk->index == R9A06G032_DIV_UART) {
+ 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);
}
diff --git a/drivers/clk/renesas/rcar-gen2-cpg.c b/drivers/clk/renesas/rcar-gen2-cpg.c
index daf88bc2cdae..f596a2dafcf4 100644
--- a/drivers/clk/renesas/rcar-gen2-cpg.c
+++ b/drivers/clk/renesas/rcar-gen2-cpg.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* R-Car Gen2 Clock Pulse Generator
*
* Copyright (C) 2016 Cogent Embedded Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
*/
#include <linux/bug.h>
diff --git a/drivers/clk/renesas/rcar-gen2-cpg.h b/drivers/clk/renesas/rcar-gen2-cpg.h
index 020a3baad015..bff9551c7a38 100644
--- a/drivers/clk/renesas/rcar-gen2-cpg.h
+++ b/drivers/clk/renesas/rcar-gen2-cpg.h
@@ -1,11 +1,8 @@
-/*
+/* SPDX-License-Identifier: GPL-2.0
+ *
* R-Car Gen2 Clock Pulse Generator
*
* Copyright (C) 2016 Cogent Embedded Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation; version 2 of the License.
*/
#ifndef __CLK_RENESAS_RCAR_GEN2_CPG_H__
diff --git a/drivers/clk/renesas/rcar-gen3-cpg.c b/drivers/clk/renesas/rcar-gen3-cpg.c
index 628b63b85d3f..4ba38f98cc7b 100644
--- a/drivers/clk/renesas/rcar-gen3-cpg.c
+++ b/drivers/clk/renesas/rcar-gen3-cpg.c
@@ -1,15 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* R-Car Gen3 Clock Pulse Generator
*
- * Copyright (C) 2015-2016 Glider bvba
+ * Copyright (C) 2015-2018 Glider bvba
*
* Based on clk-rcar-gen3.c
*
* Copyright (C) 2015 Renesas Electronics Corp.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
*/
#include <linux/bug.h>
@@ -31,6 +28,8 @@
#define CPG_PLL2CR 0x002c
#define CPG_PLL4CR 0x01f4
+#define CPG_RCKCR_CKSEL BIT(15) /* RCLK Clock Source Select */
+
struct cpg_simple_notifier {
struct notifier_block nb;
void __iomem *reg;
@@ -444,7 +443,7 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev,
unsigned int div = 1;
u32 value;
- parent = clks[core->parent & 0xffff]; /* CLK_TYPE_PE uses high bits */
+ parent = clks[core->parent & 0xffff]; /* some types use high bits */
if (IS_ERR(parent))
return ERR_CAST(parent);
@@ -524,7 +523,7 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev,
if (clk_get_rate(clks[cpg_clk_extalr])) {
parent = clks[cpg_clk_extalr];
- value |= BIT(15);
+ value |= CPG_RCKCR_CKSEL;
}
writel(value, csn->reg);
@@ -537,16 +536,14 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev,
parent = clks[cpg_clk_extalr];
break;
- case CLK_TYPE_GEN3_PE:
+ case CLK_TYPE_GEN3_MDSEL:
/*
- * Peripheral clock with a fixed divider, selectable between
- * clean and spread spectrum parents using MD12
+ * Clock selectable between two parents and two fixed dividers
+ * using a mode pin
*/
- if (cpg_mode & BIT(12)) {
- /* Clean */
+ if (cpg_mode & BIT(core->offset)) {
div = core->div & 0xffff;
} else {
- /* SCCG */
parent = clks[core->parent >> 16];
if (IS_ERR(parent))
return ERR_CAST(parent);
@@ -563,6 +560,28 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev,
return cpg_z_clk_register(core->name, __clk_get_name(parent),
base, CPG_FRQCRC_Z2FC_MASK);
+ case CLK_TYPE_GEN3_OSC:
+ /*
+ * Clock combining OSC EXTAL predivider and a fixed divider
+ */
+ div = cpg_pll_config->osc_prediv * core->div;
+ break;
+
+ case CLK_TYPE_GEN3_RCKSEL:
+ /*
+ * Clock selectable between two parents and two fixed dividers
+ * using RCKCR.CKSEL
+ */
+ if (readl(base + CPG_RCKCR) & CPG_RCKCR_CKSEL) {
+ div = core->div & 0xffff;
+ } else {
+ parent = clks[core->parent >> 16];
+ if (IS_ERR(parent))
+ return ERR_CAST(parent);
+ div = core->div >> 16;
+ }
+ break;
+
default:
return ERR_PTR(-EINVAL);
}
diff --git a/drivers/clk/renesas/rcar-gen3-cpg.h b/drivers/clk/renesas/rcar-gen3-cpg.h
index ea4f8fc3c4c9..f4fb6cf16688 100644
--- a/drivers/clk/renesas/rcar-gen3-cpg.h
+++ b/drivers/clk/renesas/rcar-gen3-cpg.h
@@ -1,11 +1,9 @@
-/*
+/* SPDX-License-Identifier: GPL-2.0
+ *
* R-Car Gen3 Clock Pulse Generator
*
- * Copyright (C) 2015-2016 Glider bvba
+ * Copyright (C) 2015-2018 Glider bvba
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
*/
#ifndef __CLK_RENESAS_RCAR_GEN3_CPG_H__
@@ -20,19 +18,35 @@ enum rcar_gen3_clk_types {
CLK_TYPE_GEN3_PLL4,
CLK_TYPE_GEN3_SD,
CLK_TYPE_GEN3_R,
- CLK_TYPE_GEN3_PE,
+ CLK_TYPE_GEN3_MDSEL, /* Select parent/divider using mode pin */
CLK_TYPE_GEN3_Z,
CLK_TYPE_GEN3_Z2,
+ CLK_TYPE_GEN3_OSC, /* OSC EXTAL predivider and fixed divider */
+ CLK_TYPE_GEN3_RCKSEL, /* Select parent/divider using RCKCR.CKSEL */
+
+ /* SoC specific definitions start here */
+ CLK_TYPE_GEN3_SOC_BASE,
};
#define DEF_GEN3_SD(_name, _id, _parent, _offset) \
DEF_BASE(_name, _id, CLK_TYPE_GEN3_SD, _parent, .offset = _offset)
+#define DEF_GEN3_MDSEL(_name, _id, _md, _parent0, _div0, _parent1, _div1) \
+ DEF_BASE(_name, _id, CLK_TYPE_GEN3_MDSEL, \
+ (_parent0) << 16 | (_parent1), \
+ .div = (_div0) << 16 | (_div1), .offset = _md)
+
#define DEF_GEN3_PE(_name, _id, _parent_sscg, _div_sscg, _parent_clean, \
_div_clean) \
- DEF_BASE(_name, _id, CLK_TYPE_GEN3_PE, \
- (_parent_sscg) << 16 | (_parent_clean), \
- .div = (_div_sscg) << 16 | (_div_clean))
+ DEF_GEN3_MDSEL(_name, _id, 12, _parent_sscg, _div_sscg, \
+ _parent_clean, _div_clean)
+
+#define DEF_GEN3_OSC(_name, _id, _parent, _div) \
+ DEF_BASE(_name, _id, CLK_TYPE_GEN3_OSC, _parent, .div = _div)
+
+#define DEF_GEN3_RCKSEL(_name, _id, _parent0, _div0, _parent1, _div1) \
+ DEF_BASE(_name, _id, CLK_TYPE_GEN3_RCKSEL, \
+ (_parent0) << 16 | (_parent1), .div = (_div0) << 16 | (_div1))
struct rcar_gen3_cpg_pll_config {
u8 extal_div;
@@ -40,6 +54,7 @@ struct rcar_gen3_cpg_pll_config {
u8 pll1_div;
u8 pll3_mult;
u8 pll3_div;
+ u8 osc_prediv;
};
#define CPG_RCKCR 0x240
diff --git a/drivers/clk/renesas/rcar-usb2-clock-sel.c b/drivers/clk/renesas/rcar-usb2-clock-sel.c
index 6cd030a58964..b241f9ca3d71 100644
--- a/drivers/clk/renesas/rcar-usb2-clock-sel.c
+++ b/drivers/clk/renesas/rcar-usb2-clock-sel.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Renesas R-Car USB2.0 clock selector
*
@@ -6,10 +7,6 @@
* Based on renesas-cpg-mssr.c
*
* Copyright (C) 2015 Glider bvba
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
*/
#include <linux/clk.h>
diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c
index f4b013e9352d..f7bb817420b4 100644
--- a/drivers/clk/renesas/renesas-cpg-mssr.c
+++ b/drivers/clk/renesas/renesas-cpg-mssr.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Renesas Clock Pulse Generator / Module Standby and Software Reset
*
@@ -7,10 +8,6 @@
*
* Copyright (C) 2013 Ideas On Board SPRL
* Copyright (C) 2015 Renesas Electronics Corp.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
*/
#include <linux/clk.h>
@@ -73,6 +70,17 @@ static const u16 smstpcr[] = {
#define SMSTPCR(i) smstpcr[i]
+/*
+ * Standby Control Register offsets (RZ/A)
+ * Base address is FRQCR register
+ */
+
+static const u16 stbcr[] = {
+ 0xFFFF/*dummy*/, 0x010, 0x014, 0x410, 0x414, 0x418, 0x41C, 0x420,
+ 0x424, 0x428, 0x42C,
+};
+
+#define STBCR(i) stbcr[i]
/*
* Software Reset Register offsets
@@ -110,6 +118,7 @@ static const u16 srcr[] = {
* @notifiers: Notifier chain to save/restore clock state for system resume
* @smstpcr_saved[].mask: Mask of SMSTPCR[] bits under our control
* @smstpcr_saved[].val: Saved values of SMSTPCR[]
+ * @stbyctrl: This device has Standby Control Registers
*/
struct cpg_mssr_priv {
#ifdef CONFIG_RESET_CONTROLLER
@@ -118,11 +127,13 @@ struct cpg_mssr_priv {
struct device *dev;
void __iomem *base;
spinlock_t rmw_lock;
+ struct device_node *np;
struct clk **clks;
unsigned int num_core_clks;
unsigned int num_mod_clks;
unsigned int last_dt_core_clk;
+ bool stbyctrl;
struct raw_notifier_head notifiers;
struct {
@@ -131,6 +142,7 @@ struct cpg_mssr_priv {
} smstpcr_saved[ARRAY_SIZE(smstpcr)];
};
+static struct cpg_mssr_priv *cpg_mssr_priv;
/**
* struct mstp_clock - MSTP gating clock
@@ -162,16 +174,29 @@ static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable)
enable ? "ON" : "OFF");
spin_lock_irqsave(&priv->rmw_lock, flags);
- value = readl(priv->base + SMSTPCR(reg));
- if (enable)
- value &= ~bitmask;
- else
- value |= bitmask;
- writel(value, priv->base + SMSTPCR(reg));
+ if (priv->stbyctrl) {
+ value = readb(priv->base + STBCR(reg));
+ if (enable)
+ value &= ~bitmask;
+ else
+ value |= bitmask;
+ writeb(value, priv->base + STBCR(reg));
+
+ /* dummy read to ensure write has completed */
+ readb(priv->base + STBCR(reg));
+ barrier_data(priv->base + STBCR(reg));
+ } else {
+ value = readl(priv->base + SMSTPCR(reg));
+ if (enable)
+ value &= ~bitmask;
+ else
+ value |= bitmask;
+ writel(value, priv->base + SMSTPCR(reg));
+ }
spin_unlock_irqrestore(&priv->rmw_lock, flags);
- if (!enable)
+ if (!enable || priv->stbyctrl)
return 0;
for (i = 1000; i > 0; --i) {
@@ -205,7 +230,10 @@ static int cpg_mstp_clock_is_enabled(struct clk_hw *hw)
struct cpg_mssr_priv *priv = clock->priv;
u32 value;
- value = readl(priv->base + MSTPSR(clock->index / 32));
+ if (priv->stbyctrl)
+ value = readb(priv->base + STBCR(clock->index / 32));
+ else
+ value = readl(priv->base + MSTPSR(clock->index / 32));
return !(value & BIT(clock->index % 32));
}
@@ -226,6 +254,7 @@ struct clk *cpg_mssr_clk_src_twocell_get(struct of_phandle_args *clkspec,
unsigned int idx;
const char *type;
struct clk *clk;
+ int range_check;
switch (clkspec->args[0]) {
case CPG_CORE:
@@ -240,8 +269,14 @@ struct clk *cpg_mssr_clk_src_twocell_get(struct of_phandle_args *clkspec,
case CPG_MOD:
type = "module";
- idx = MOD_CLK_PACK(clkidx);
- if (clkidx % 100 > 31 || idx >= priv->num_mod_clks) {
+ if (priv->stbyctrl) {
+ idx = MOD_CLK_PACK_10(clkidx);
+ range_check = 7 - (clkidx % 10);
+ } else {
+ idx = MOD_CLK_PACK(clkidx);
+ range_check = 31 - (clkidx % 100);
+ }
+ if (range_check < 0 || idx >= priv->num_mod_clks) {
dev_err(dev, "Invalid %s clock index %u\n", type,
clkidx);
return ERR_PTR(-EINVAL);
@@ -283,7 +318,7 @@ static void __init cpg_mssr_register_core_clk(const struct cpg_core_clk *core,
switch (core->type) {
case CLK_TYPE_IN:
- clk = of_clk_get_by_name(priv->dev->of_node, core->name);
+ clk = of_clk_get_by_name(priv->np, core->name);
break;
case CLK_TYPE_FF:
@@ -313,6 +348,11 @@ static void __init cpg_mssr_register_core_clk(const struct cpg_core_clk *core,
}
break;
+ case CLK_TYPE_FR:
+ clk = clk_register_fixed_rate(NULL, core->name, NULL, 0,
+ core->mult);
+ break;
+
default:
if (info->cpg_clk_register)
clk = info->cpg_clk_register(dev, core, info,
@@ -641,11 +681,22 @@ static inline int cpg_mssr_reset_controller_register(struct cpg_mssr_priv *priv)
static const struct of_device_id cpg_mssr_match[] = {
+#ifdef CONFIG_CLK_R7S9210
+ {
+ .compatible = "renesas,r7s9210-cpg-mssr",
+ .data = &r7s9210_cpg_mssr_info,
+ },
+#endif
#ifdef CONFIG_CLK_R8A7743
{
.compatible = "renesas,r8a7743-cpg-mssr",
.data = &r8a7743_cpg_mssr_info,
},
+ /* RZ/G1N is (almost) identical to RZ/G1M w.r.t. clocks. */
+ {
+ .compatible = "renesas,r8a7744-cpg-mssr",
+ .data = &r8a7743_cpg_mssr_info,
+ },
#endif
#ifdef CONFIG_CLK_R8A7745
{
@@ -659,6 +710,18 @@ static const struct of_device_id cpg_mssr_match[] = {
.data = &r8a77470_cpg_mssr_info,
},
#endif
+#ifdef CONFIG_CLK_R8A774A1
+ {
+ .compatible = "renesas,r8a774a1-cpg-mssr",
+ .data = &r8a774a1_cpg_mssr_info,
+ },
+#endif
+#ifdef CONFIG_CLK_R8A774C0
+ {
+ .compatible = "renesas,r8a774c0-cpg-mssr",
+ .data = &r8a774c0_cpg_mssr_info,
+ },
+#endif
#ifdef CONFIG_CLK_R8A7790
{
.compatible = "renesas,r8a7790-cpg-mssr",
@@ -780,13 +843,23 @@ static int cpg_mssr_resume_noirq(struct device *dev)
if (!mask)
continue;
- oldval = readl(priv->base + SMSTPCR(reg));
+ if (priv->stbyctrl)
+ oldval = readb(priv->base + STBCR(reg));
+ else
+ oldval = readl(priv->base + SMSTPCR(reg));
newval = oldval & ~mask;
newval |= priv->smstpcr_saved[reg].val & mask;
if (newval == oldval)
continue;
- writel(newval, priv->base + SMSTPCR(reg));
+ if (priv->stbyctrl) {
+ writeb(newval, priv->base + STBCR(reg));
+ /* dummy read to ensure write has completed */
+ readb(priv->base + STBCR(reg));
+ barrier_data(priv->base + STBCR(reg));
+ continue;
+ } else
+ writel(newval, priv->base + SMSTPCR(reg));
/* Wait until enabled clocks are really enabled */
mask &= ~priv->smstpcr_saved[reg].val;
@@ -817,61 +890,115 @@ static const struct dev_pm_ops cpg_mssr_pm = {
#define DEV_PM_OPS NULL
#endif /* CONFIG_PM_SLEEP && CONFIG_ARM_PSCI_FW */
-static int __init cpg_mssr_probe(struct platform_device *pdev)
+static int __init cpg_mssr_common_init(struct device *dev,
+ struct device_node *np,
+ const struct cpg_mssr_info *info)
{
- struct device *dev = &pdev->dev;
- struct device_node *np = dev->of_node;
- const struct cpg_mssr_info *info;
struct cpg_mssr_priv *priv;
+ struct clk **clks = NULL;
unsigned int nclks, i;
- struct resource *res;
- struct clk **clks;
int error;
- info = of_device_get_match_data(dev);
if (info->init) {
error = info->init(dev);
if (error)
return error;
}
- priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
+ priv->np = np;
priv->dev = dev;
spin_lock_init(&priv->rmw_lock);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- priv->base = devm_ioremap_resource(dev, res);
- if (IS_ERR(priv->base))
- return PTR_ERR(priv->base);
+ priv->base = of_iomap(np, 0);
+ if (!priv->base) {
+ error = -ENOMEM;
+ goto out_err;
+ }
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;
+ clks = kmalloc_array(nclks, sizeof(*clks), GFP_KERNEL);
+ if (!clks) {
+ error = -ENOMEM;
+ goto out_err;
+ }
- dev_set_drvdata(dev, priv);
+ cpg_mssr_priv = priv;
priv->clks = clks;
priv->num_core_clks = info->num_total_core_clks;
priv->num_mod_clks = info->num_hw_mod_clks;
priv->last_dt_core_clk = info->last_dt_core_clk;
RAW_INIT_NOTIFIER_HEAD(&priv->notifiers);
+ priv->stbyctrl = info->stbyctrl;
for (i = 0; i < nclks; i++)
clks[i] = ERR_PTR(-ENOENT);
+ error = of_clk_add_provider(np, cpg_mssr_clk_src_twocell_get, priv);
+ if (error)
+ goto out_err;
+
+ return 0;
+
+out_err:
+ kfree(clks);
+ if (priv->base)
+ iounmap(priv->base);
+ kfree(priv);
+
+ return error;
+}
+
+void __init cpg_mssr_early_init(struct device_node *np,
+ const struct cpg_mssr_info *info)
+{
+ int error;
+ int i;
+
+ error = cpg_mssr_common_init(NULL, np, info);
+ if (error)
+ return;
+
+ for (i = 0; i < info->num_early_core_clks; i++)
+ cpg_mssr_register_core_clk(&info->early_core_clks[i], info,
+ cpg_mssr_priv);
+
+ for (i = 0; i < info->num_early_mod_clks; i++)
+ cpg_mssr_register_mod_clk(&info->early_mod_clks[i], info,
+ cpg_mssr_priv);
+
+}
+
+static int __init cpg_mssr_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ const struct cpg_mssr_info *info;
+ struct cpg_mssr_priv *priv;
+ unsigned int i;
+ int error;
+
+ info = of_device_get_match_data(dev);
+
+ if (!cpg_mssr_priv) {
+ error = cpg_mssr_common_init(dev, dev->of_node, info);
+ if (error)
+ return error;
+ }
+
+ priv = cpg_mssr_priv;
+ priv->dev = dev;
+ dev_set_drvdata(dev, priv);
+
for (i = 0; i < info->num_core_clks; i++)
cpg_mssr_register_core_clk(&info->core_clks[i], info, priv);
for (i = 0; i < info->num_mod_clks; i++)
cpg_mssr_register_mod_clk(&info->mod_clks[i], info, priv);
- error = of_clk_add_provider(np, cpg_mssr_clk_src_twocell_get, priv);
- if (error)
- return error;
-
error = devm_add_action_or_reset(dev,
cpg_mssr_del_clk_provider,
np);
@@ -883,6 +1010,10 @@ static int __init cpg_mssr_probe(struct platform_device *pdev)
if (error)
return error;
+ /* Reset Controller not supported for Standby Control SoCs */
+ if (info->stbyctrl)
+ return 0;
+
error = cpg_mssr_reset_controller_register(priv);
if (error)
return error;
diff --git a/drivers/clk/renesas/renesas-cpg-mssr.h b/drivers/clk/renesas/renesas-cpg-mssr.h
index 642f720b9b05..c4ec9df146fd 100644
--- a/drivers/clk/renesas/renesas-cpg-mssr.h
+++ b/drivers/clk/renesas/renesas-cpg-mssr.h
@@ -1,11 +1,8 @@
-/*
+/* SPDX-License-Identifier: GPL-2.0
+ *
* Renesas Clock Pulse Generator / Module Standby and Software Reset
*
* Copyright (C) 2015 Glider bvba
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
*/
#ifndef __CLK_RENESAS_CPG_MSSR_H__
@@ -38,6 +35,7 @@ enum clk_types {
CLK_TYPE_FF, /* Fixed Factor Clock */
CLK_TYPE_DIV6P1, /* DIV6 Clock with 1 parent clock */
CLK_TYPE_DIV6_RO, /* DIV6 Clock read only with extra divisor */
+ CLK_TYPE_FR, /* Fixed Rate Clock */
/* Custom definitions start here */
CLK_TYPE_CUSTOM,
@@ -56,6 +54,8 @@ enum clk_types {
DEF_BASE(_name, _id, CLK_TYPE_DIV6P1, _parent, .offset = _offset)
#define DEF_DIV6_RO(_name, _id, _parent, _offset, _div) \
DEF_BASE(_name, _id, CLK_TYPE_DIV6_RO, _parent, .offset = _offset, .div = _div, .mult = 1)
+#define DEF_RATE(_name, _id, _rate) \
+ DEF_TYPE(_name, _id, CLK_TYPE_FR, .mult = _rate)
/*
* Definitions of Module Clocks
@@ -75,12 +75,24 @@ struct mssr_mod_clk {
#define DEF_MOD(_name, _mod, _parent...) \
{ .name = _name, .id = MOD_CLK_ID(_mod), .parent = _parent }
+/* Convert from sparse base-10 to packed index space */
+#define MOD_CLK_PACK_10(x) ((x / 10) * 32 + (x % 10))
+
+#define MOD_CLK_ID_10(x) (MOD_CLK_BASE + MOD_CLK_PACK_10(x))
+
+#define DEF_MOD_STB(_name, _mod, _parent...) \
+ { .name = _name, .id = MOD_CLK_ID_10(_mod), .parent = _parent }
struct device_node;
/**
* SoC-specific CPG/MSSR Description
*
+ * @early_core_clks: Array of Early Core Clock definitions
+ * @num_early_core_clks: Number of entries in early_core_clks[]
+ * @early_mod_clks: Array of Early Module Clock definitions
+ * @num_early_mod_clks: Number of entries in early_mod_clks[]
+ *
* @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
@@ -100,14 +112,25 @@ struct device_node;
*
* @init: Optional callback to perform SoC-specific initialization
* @cpg_clk_register: Optional callback to handle special Core Clock types
+ *
+ * @stbyctrl: This device has Standby Control Registers which are 8-bits
+ * wide, no status registers (MSTPSR) and have different address
+ * offsets.
*/
struct cpg_mssr_info {
+ /* Early Clocks */
+ const struct cpg_core_clk *early_core_clks;
+ unsigned int num_early_core_clks;
+ const struct mssr_mod_clk *early_mod_clks;
+ unsigned int num_early_mod_clks;
+
/* 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;
+ bool stbyctrl;
/* Module Clocks */
const struct mssr_mod_clk *mod_clks;
@@ -131,9 +154,12 @@ struct cpg_mssr_info {
struct raw_notifier_head *notifiers);
};
+extern const struct cpg_mssr_info r7s9210_cpg_mssr_info;
extern const struct cpg_mssr_info r8a7743_cpg_mssr_info;
extern const struct cpg_mssr_info r8a7745_cpg_mssr_info;
extern const struct cpg_mssr_info r8a77470_cpg_mssr_info;
+extern const struct cpg_mssr_info r8a774a1_cpg_mssr_info;
+extern const struct cpg_mssr_info r8a774c0_cpg_mssr_info;
extern const struct cpg_mssr_info r8a7790_cpg_mssr_info;
extern const struct cpg_mssr_info r8a7791_cpg_mssr_info;
extern const struct cpg_mssr_info r8a7792_cpg_mssr_info;
@@ -146,6 +172,8 @@ extern const struct cpg_mssr_info r8a77980_cpg_mssr_info;
extern const struct cpg_mssr_info r8a77990_cpg_mssr_info;
extern const struct cpg_mssr_info r8a77995_cpg_mssr_info;
+void __init cpg_mssr_early_init(struct device_node *np,
+ const struct cpg_mssr_info *info);
/*
* Helpers for fixing up clock tables depending on SoC revision
diff --git a/drivers/clk/rockchip/clk-ddr.c b/drivers/clk/rockchip/clk-ddr.c
index e8075359366b..ebce5260068b 100644
--- a/drivers/clk/rockchip/clk-ddr.c
+++ b/drivers/clk/rockchip/clk-ddr.c
@@ -80,16 +80,12 @@ static long rockchip_ddrclk_sip_round_rate(struct clk_hw *hw,
static u8 rockchip_ddrclk_get_parent(struct clk_hw *hw)
{
struct rockchip_ddrclk *ddrclk = to_rockchip_ddrclk_hw(hw);
- int num_parents = clk_hw_get_num_parents(hw);
u32 val;
val = clk_readl(ddrclk->reg_base +
ddrclk->mux_offset) >> ddrclk->mux_shift;
val &= GENMASK(ddrclk->mux_width - 1, 0);
- if (val >= num_parents)
- return -EINVAL;
-
return val;
}
diff --git a/drivers/clk/rockchip/clk-rk3188.c b/drivers/clk/rockchip/clk-rk3188.c
index 67e73fd71f09..fa25e35ce7d5 100644
--- a/drivers/clk/rockchip/clk-rk3188.c
+++ b/drivers/clk/rockchip/clk-rk3188.c
@@ -645,7 +645,7 @@ static struct rockchip_clk_branch rk3066a_clk_branches[] __initdata = {
GATE(HCLK_I2S1, "hclk_i2s1", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 3, GFLAGS),
GATE(HCLK_I2S2, "hclk_i2s2", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 4, GFLAGS),
GATE(HCLK_CIF1, "hclk_cif1", "hclk_cpu", 0, RK2928_CLKGATE_CON(6), 6, GFLAGS),
- GATE(0, "hclk_hdmi", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 14, GFLAGS),
+ GATE(HCLK_HDMI, "hclk_hdmi", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 14, GFLAGS),
GATE(HCLK_OTG1, "hclk_usbotg1", "hclk_peri", CLK_IGNORE_UNUSED,
RK2928_CLKGATE_CON(5), 14, GFLAGS),
diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c
index 450de24a1b42..5a67b7869960 100644
--- a/drivers/clk/rockchip/clk-rk3288.c
+++ b/drivers/clk/rockchip/clk-rk3288.c
@@ -83,22 +83,43 @@ static struct rockchip_pll_rate_table rk3288_pll_rates[] = {
RK3066_PLL_RATE( 768000000, 1, 64, 2),
RK3066_PLL_RATE( 742500000, 8, 495, 2),
RK3066_PLL_RATE( 696000000, 1, 58, 2),
+ RK3066_PLL_RATE_NB(621000000, 1, 207, 8, 1),
RK3066_PLL_RATE( 600000000, 1, 50, 2),
RK3066_PLL_RATE_NB(594000000, 1, 198, 8, 1),
RK3066_PLL_RATE( 552000000, 1, 46, 2),
RK3066_PLL_RATE( 504000000, 1, 84, 4),
RK3066_PLL_RATE( 500000000, 3, 125, 2),
RK3066_PLL_RATE( 456000000, 1, 76, 4),
+ RK3066_PLL_RATE( 428000000, 1, 107, 6),
RK3066_PLL_RATE( 408000000, 1, 68, 4),
RK3066_PLL_RATE( 400000000, 3, 100, 2),
+ RK3066_PLL_RATE_NB( 394000000, 1, 197, 12, 1),
RK3066_PLL_RATE( 384000000, 2, 128, 4),
RK3066_PLL_RATE( 360000000, 1, 60, 4),
+ RK3066_PLL_RATE_NB( 356000000, 1, 178, 12, 1),
+ RK3066_PLL_RATE_NB( 324000000, 1, 189, 14, 1),
RK3066_PLL_RATE( 312000000, 1, 52, 4),
- RK3066_PLL_RATE( 300000000, 1, 50, 4),
- RK3066_PLL_RATE( 297000000, 2, 198, 8),
+ RK3066_PLL_RATE_NB( 308000000, 1, 154, 12, 1),
+ RK3066_PLL_RATE_NB( 303000000, 1, 202, 16, 1),
+ RK3066_PLL_RATE( 300000000, 1, 75, 6),
+ RK3066_PLL_RATE_NB( 297750000, 2, 397, 16, 1),
+ RK3066_PLL_RATE_NB( 293250000, 2, 391, 16, 1),
+ RK3066_PLL_RATE_NB( 292500000, 1, 195, 16, 1),
+ RK3066_PLL_RATE( 273600000, 1, 114, 10),
+ RK3066_PLL_RATE_NB( 273000000, 1, 182, 16, 1),
+ RK3066_PLL_RATE_NB( 270000000, 1, 180, 16, 1),
+ RK3066_PLL_RATE_NB( 266250000, 2, 355, 16, 1),
+ RK3066_PLL_RATE_NB( 256500000, 1, 171, 16, 1),
RK3066_PLL_RATE( 252000000, 1, 84, 8),
- RK3066_PLL_RATE( 216000000, 1, 72, 8),
- RK3066_PLL_RATE( 148500000, 2, 99, 8),
+ RK3066_PLL_RATE_NB( 250500000, 1, 167, 16, 1),
+ RK3066_PLL_RATE_NB( 243428571, 1, 142, 14, 1),
+ RK3066_PLL_RATE( 238000000, 1, 119, 12),
+ RK3066_PLL_RATE_NB( 219750000, 2, 293, 16, 1),
+ RK3066_PLL_RATE_NB( 216000000, 1, 144, 16, 1),
+ RK3066_PLL_RATE_NB( 213000000, 1, 142, 16, 1),
+ RK3066_PLL_RATE( 195428571, 1, 114, 14),
+ RK3066_PLL_RATE( 160000000, 1, 80, 12),
+ RK3066_PLL_RATE( 157500000, 1, 105, 16),
RK3066_PLL_RATE( 126000000, 1, 84, 16),
RK3066_PLL_RATE( 48000000, 1, 64, 32),
{ /* sentinel */ },
diff --git a/drivers/clk/rockchip/clk-rk3328.c b/drivers/clk/rockchip/clk-rk3328.c
index 252366a5231f..2c5426607790 100644
--- a/drivers/clk/rockchip/clk-rk3328.c
+++ b/drivers/clk/rockchip/clk-rk3328.c
@@ -813,22 +813,22 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "clk_sdmmc",
RK3328_SDMMC_CON0, 1),
MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "clk_sdmmc",
- RK3328_SDMMC_CON1, 1),
+ RK3328_SDMMC_CON1, 0),
MMC(SCLK_SDIO_DRV, "sdio_drv", "clk_sdio",
RK3328_SDIO_CON0, 1),
MMC(SCLK_SDIO_SAMPLE, "sdio_sample", "clk_sdio",
- RK3328_SDIO_CON1, 1),
+ RK3328_SDIO_CON1, 0),
MMC(SCLK_EMMC_DRV, "emmc_drv", "clk_emmc",
RK3328_EMMC_CON0, 1),
MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "clk_emmc",
- RK3328_EMMC_CON1, 1),
+ RK3328_EMMC_CON1, 0),
MMC(SCLK_SDMMC_EXT_DRV, "sdmmc_ext_drv", "clk_sdmmc_ext",
RK3328_SDMMC_EXT_CON0, 1),
MMC(SCLK_SDMMC_EXT_SAMPLE, "sdmmc_ext_sample", "clk_sdmmc_ext",
- RK3328_SDMMC_EXT_CON1, 1),
+ RK3328_SDMMC_EXT_CON1, 0),
};
static const char *const rk3328_critical_clocks[] __initconst = {
diff --git a/drivers/clk/samsung/clk-cpu.c b/drivers/clk/samsung/clk-cpu.c
index d2c99d8916b8..a5fddebbe530 100644
--- a/drivers/clk/samsung/clk-cpu.c
+++ b/drivers/clk/samsung/clk-cpu.c
@@ -152,7 +152,7 @@ static int exynos_cpuclk_pre_rate_change(struct clk_notifier_data *ndata,
struct exynos_cpuclk *cpuclk, void __iomem *base)
{
const struct exynos_cpuclk_cfg_data *cfg_data = cpuclk->cfg;
- unsigned long alt_prate = clk_get_rate(cpuclk->alt_parent);
+ unsigned long alt_prate = clk_hw_get_rate(cpuclk->alt_parent);
unsigned long alt_div = 0, alt_div_mask = DIV_MASK;
unsigned long div0, div1 = 0, mux_reg;
unsigned long flags;
@@ -280,7 +280,7 @@ static int exynos5433_cpuclk_pre_rate_change(struct clk_notifier_data *ndata,
struct exynos_cpuclk *cpuclk, void __iomem *base)
{
const struct exynos_cpuclk_cfg_data *cfg_data = cpuclk->cfg;
- unsigned long alt_prate = clk_get_rate(cpuclk->alt_parent);
+ unsigned long alt_prate = clk_hw_get_rate(cpuclk->alt_parent);
unsigned long alt_div = 0, alt_div_mask = DIV_MASK;
unsigned long div0, div1 = 0, mux_reg;
unsigned long flags;
@@ -432,7 +432,7 @@ int __init exynos_register_cpu_clock(struct samsung_clk_provider *ctx,
else
cpuclk->clk_nb.notifier_call = exynos_cpuclk_notifier_cb;
- cpuclk->alt_parent = __clk_lookup(alt_parent);
+ cpuclk->alt_parent = __clk_get_hw(__clk_lookup(alt_parent));
if (!cpuclk->alt_parent) {
pr_err("%s: could not lookup alternate parent %s\n",
__func__, alt_parent);
diff --git a/drivers/clk/samsung/clk-cpu.h b/drivers/clk/samsung/clk-cpu.h
index d4b6b517fe1b..bd38c6aa3897 100644
--- a/drivers/clk/samsung/clk-cpu.h
+++ b/drivers/clk/samsung/clk-cpu.h
@@ -49,7 +49,7 @@ struct exynos_cpuclk_cfg_data {
*/
struct exynos_cpuclk {
struct clk_hw hw;
- struct clk *alt_parent;
+ struct clk_hw *alt_parent;
void __iomem *ctrl_base;
spinlock_t *lock;
const struct exynos_cpuclk_cfg_data *cfg;
diff --git a/drivers/clk/samsung/clk-exynos-audss.c b/drivers/clk/samsung/clk-exynos-audss.c
index f659c5cbf1d5..8f8a0f9fc842 100644
--- a/drivers/clk/samsung/clk-exynos-audss.c
+++ b/drivers/clk/samsung/clk-exynos-audss.c
@@ -15,7 +15,6 @@
#include <linux/clk-provider.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
-#include <linux/syscore_ops.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
diff --git a/drivers/clk/samsung/clk-exynos3250.c b/drivers/clk/samsung/clk-exynos3250.c
index 27c9d23657b3..0e9a41a4cac8 100644
--- a/drivers/clk/samsung/clk-exynos3250.c
+++ b/drivers/clk/samsung/clk-exynos3250.c
@@ -12,7 +12,6 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
-#include <linux/syscore_ops.h>
#include <dt-bindings/clock/exynos3250.h>
diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c
index 0421960eb963..59d4d46667ce 100644
--- a/drivers/clk/samsung/clk-exynos4.c
+++ b/drivers/clk/samsung/clk-exynos4.c
@@ -16,7 +16,6 @@
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/syscore_ops.h>
#include "clk.h"
#include "clk-cpu.h"
@@ -123,10 +122,6 @@
#define CLKOUT_CMU_CPU 0x14a00
#define PWR_CTRL1 0x15020
#define E4X12_PWR_CTRL2 0x15024
-#define E4X12_DIV_ISP0 0x18300
-#define E4X12_DIV_ISP1 0x18304
-#define E4X12_GATE_ISP0 0x18800
-#define E4X12_GATE_ISP1 0x18804
/* Below definitions are used for PWR_CTRL settings */
#define PWR_CTRL1_CORE2_DOWN_RATIO(x) (((x) & 0x7) << 28)
@@ -158,14 +153,6 @@ static void __iomem *reg_base;
static enum exynos4_soc exynos4_soc;
/*
- * Support for CMU save/restore across system suspends
- */
-#ifdef CONFIG_PM_SLEEP
-static struct samsung_clk_reg_dump *exynos4_save_common;
-static struct samsung_clk_reg_dump *exynos4_save_soc;
-static struct samsung_clk_reg_dump *exynos4_save_pll;
-
-/*
* list of controller registers to be saved and restored during a
* suspend/resume cycle.
*/
@@ -192,7 +179,7 @@ static const unsigned long exynos4x12_clk_save[] __initconst = {
E4X12_PWR_CTRL2,
};
-static const unsigned long exynos4_clk_pll_regs[] __initconst = {
+static const unsigned long exynos4_clk_regs[] __initconst = {
EPLL_LOCK,
VPLL_LOCK,
EPLL_CON0,
@@ -201,9 +188,6 @@ static const unsigned long exynos4_clk_pll_regs[] __initconst = {
VPLL_CON0,
VPLL_CON1,
VPLL_CON2,
-};
-
-static const unsigned long exynos4_clk_regs[] __initconst = {
SRC_LEFTBUS,
DIV_LEFTBUS,
GATE_IP_LEFTBUS,
@@ -276,6 +260,8 @@ static const unsigned long exynos4_clk_regs[] __initconst = {
};
static const struct samsung_clk_reg_dump src_mask_suspend[] = {
+ { .offset = VPLL_CON0, .value = 0x80600302, },
+ { .offset = EPLL_CON0, .value = 0x806F0302, },
{ .offset = SRC_MASK_TOP, .value = 0x00000001, },
{ .offset = SRC_MASK_CAM, .value = 0x11111111, },
{ .offset = SRC_MASK_TV, .value = 0x00000111, },
@@ -291,123 +277,6 @@ static const struct samsung_clk_reg_dump src_mask_suspend_e4210[] = {
{ .offset = E4210_SRC_MASK_LCD1, .value = 0x00001111, },
};
-#define PLL_ENABLED (1 << 31)
-#define PLL_LOCKED (1 << 29)
-
-static void exynos4_clk_enable_pll(u32 reg)
-{
- u32 pll_con = readl(reg_base + reg);
- pll_con |= PLL_ENABLED;
- writel(pll_con, reg_base + reg);
-
- while (!(pll_con & PLL_LOCKED)) {
- cpu_relax();
- pll_con = readl(reg_base + reg);
- }
-}
-
-static void exynos4_clk_wait_for_pll(u32 reg)
-{
- u32 pll_con;
-
- pll_con = readl(reg_base + reg);
- if (!(pll_con & PLL_ENABLED))
- return;
-
- while (!(pll_con & PLL_LOCKED)) {
- cpu_relax();
- pll_con = readl(reg_base + reg);
- }
-}
-
-static int exynos4_clk_suspend(void)
-{
- samsung_clk_save(reg_base, exynos4_save_common,
- ARRAY_SIZE(exynos4_clk_regs));
- samsung_clk_save(reg_base, exynos4_save_pll,
- ARRAY_SIZE(exynos4_clk_pll_regs));
-
- exynos4_clk_enable_pll(EPLL_CON0);
- exynos4_clk_enable_pll(VPLL_CON0);
-
- if (exynos4_soc == EXYNOS4210) {
- samsung_clk_save(reg_base, exynos4_save_soc,
- ARRAY_SIZE(exynos4210_clk_save));
- samsung_clk_restore(reg_base, src_mask_suspend_e4210,
- ARRAY_SIZE(src_mask_suspend_e4210));
- } else {
- samsung_clk_save(reg_base, exynos4_save_soc,
- ARRAY_SIZE(exynos4x12_clk_save));
- }
-
- samsung_clk_restore(reg_base, src_mask_suspend,
- ARRAY_SIZE(src_mask_suspend));
-
- return 0;
-}
-
-static void exynos4_clk_resume(void)
-{
- samsung_clk_restore(reg_base, exynos4_save_pll,
- ARRAY_SIZE(exynos4_clk_pll_regs));
-
- exynos4_clk_wait_for_pll(EPLL_CON0);
- exynos4_clk_wait_for_pll(VPLL_CON0);
-
- samsung_clk_restore(reg_base, exynos4_save_common,
- ARRAY_SIZE(exynos4_clk_regs));
-
- if (exynos4_soc == EXYNOS4210)
- samsung_clk_restore(reg_base, exynos4_save_soc,
- ARRAY_SIZE(exynos4210_clk_save));
- else
- samsung_clk_restore(reg_base, exynos4_save_soc,
- ARRAY_SIZE(exynos4x12_clk_save));
-}
-
-static struct syscore_ops exynos4_clk_syscore_ops = {
- .suspend = exynos4_clk_suspend,
- .resume = exynos4_clk_resume,
-};
-
-static void __init exynos4_clk_sleep_init(void)
-{
- exynos4_save_common = samsung_clk_alloc_reg_dump(exynos4_clk_regs,
- ARRAY_SIZE(exynos4_clk_regs));
- if (!exynos4_save_common)
- goto err_warn;
-
- if (exynos4_soc == EXYNOS4210)
- exynos4_save_soc = samsung_clk_alloc_reg_dump(
- exynos4210_clk_save,
- ARRAY_SIZE(exynos4210_clk_save));
- else
- exynos4_save_soc = samsung_clk_alloc_reg_dump(
- exynos4x12_clk_save,
- ARRAY_SIZE(exynos4x12_clk_save));
- if (!exynos4_save_soc)
- goto err_common;
-
- exynos4_save_pll = samsung_clk_alloc_reg_dump(exynos4_clk_pll_regs,
- ARRAY_SIZE(exynos4_clk_pll_regs));
- if (!exynos4_save_pll)
- goto err_soc;
-
- register_syscore_ops(&exynos4_clk_syscore_ops);
- return;
-
-err_soc:
- kfree(exynos4_save_soc);
-err_common:
- kfree(exynos4_save_common);
-err_warn:
- pr_warn("%s: failed to allocate sleep save data, no sleep support!\n",
- __func__);
-}
-#else
-static void __init exynos4_clk_sleep_init(void) {}
-#endif
-
/* list of all parent clock list */
PNAME(mout_apll_p) = { "fin_pll", "fout_apll", };
PNAME(mout_mpll_p) = { "fin_pll", "fout_mpll", };
@@ -841,18 +710,6 @@ static const struct samsung_div_clock exynos4x12_div_clks[] __initconst = {
DIV(0, "div_c2c_aclk", "div_c2c", DIV_DMC1, 12, 3),
};
-static struct samsung_div_clock exynos4x12_isp_div_clks[] = {
- DIV_F(CLK_DIV_ISP0, "div_isp0", "aclk200", E4X12_DIV_ISP0, 0, 3,
- CLK_GET_RATE_NOCACHE, 0),
- DIV_F(CLK_DIV_ISP1, "div_isp1", "aclk200", E4X12_DIV_ISP0, 4, 3,
- CLK_GET_RATE_NOCACHE, 0),
- DIV(0, "div_mpwm", "div_isp1", E4X12_DIV_ISP1, 0, 3),
- DIV_F(CLK_DIV_MCUISP0, "div_mcuisp0", "aclk400_mcuisp", E4X12_DIV_ISP1,
- 4, 3, CLK_GET_RATE_NOCACHE, 0),
- DIV_F(CLK_DIV_MCUISP1, "div_mcuisp1", "div_mcuisp0", E4X12_DIV_ISP1,
- 8, 3, CLK_GET_RATE_NOCACHE, 0),
-};
-
/* list of gate clocks supported in all exynos4 soc's */
static const struct samsung_gate_clock exynos4_gate_clks[] __initconst = {
GATE(CLK_PPMULEFT, "ppmuleft", "aclk200", GATE_IP_LEFTBUS, 1, 0, 0),
@@ -1150,61 +1007,6 @@ static const struct samsung_gate_clock exynos4x12_gate_clks[] __initconst = {
0),
};
-static struct samsung_gate_clock exynos4x12_isp_gate_clks[] = {
- GATE(CLK_FIMC_ISP, "isp", "aclk200", E4X12_GATE_ISP0, 0,
- CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
- GATE(CLK_FIMC_DRC, "drc", "aclk200", E4X12_GATE_ISP0, 1,
- CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
- GATE(CLK_FIMC_FD, "fd", "aclk200", E4X12_GATE_ISP0, 2,
- CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
- GATE(CLK_FIMC_LITE0, "lite0", "aclk200", E4X12_GATE_ISP0, 3,
- CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
- GATE(CLK_FIMC_LITE1, "lite1", "aclk200", E4X12_GATE_ISP0, 4,
- CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
- GATE(CLK_MCUISP, "mcuisp", "aclk200", E4X12_GATE_ISP0, 5,
- CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
- GATE(CLK_GICISP, "gicisp", "aclk200", E4X12_GATE_ISP0, 7,
- CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
- GATE(CLK_SMMU_ISP, "smmu_isp", "aclk200", E4X12_GATE_ISP0, 8,
- CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
- GATE(CLK_SMMU_DRC, "smmu_drc", "aclk200", E4X12_GATE_ISP0, 9,
- CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
- GATE(CLK_SMMU_FD, "smmu_fd", "aclk200", E4X12_GATE_ISP0, 10,
- CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
- GATE(CLK_SMMU_LITE0, "smmu_lite0", "aclk200", E4X12_GATE_ISP0, 11,
- CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
- GATE(CLK_SMMU_LITE1, "smmu_lite1", "aclk200", E4X12_GATE_ISP0, 12,
- CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
- GATE(CLK_PPMUISPMX, "ppmuispmx", "aclk200", E4X12_GATE_ISP0, 20,
- CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
- GATE(CLK_PPMUISPX, "ppmuispx", "aclk200", E4X12_GATE_ISP0, 21,
- CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
- GATE(CLK_MCUCTL_ISP, "mcuctl_isp", "aclk200", E4X12_GATE_ISP0, 23,
- CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
- GATE(CLK_MPWM_ISP, "mpwm_isp", "aclk200", E4X12_GATE_ISP0, 24,
- CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
- GATE(CLK_I2C0_ISP, "i2c0_isp", "aclk200", E4X12_GATE_ISP0, 25,
- CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
- GATE(CLK_I2C1_ISP, "i2c1_isp", "aclk200", E4X12_GATE_ISP0, 26,
- CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
- GATE(CLK_MTCADC_ISP, "mtcadc_isp", "aclk200", E4X12_GATE_ISP0, 27,
- CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
- GATE(CLK_PWM_ISP, "pwm_isp", "aclk200", E4X12_GATE_ISP0, 28,
- CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
- GATE(CLK_WDT_ISP, "wdt_isp", "aclk200", E4X12_GATE_ISP0, 30,
- CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
- GATE(CLK_UART_ISP, "uart_isp", "aclk200", E4X12_GATE_ISP0, 31,
- CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
- GATE(CLK_ASYNCAXIM, "asyncaxim", "aclk200", E4X12_GATE_ISP1, 0,
- CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
- GATE(CLK_SMMU_ISPCX, "smmu_ispcx", "aclk200", E4X12_GATE_ISP1, 4,
- CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
- GATE(CLK_SPI0_ISP, "spi0_isp", "aclk200", E4X12_GATE_ISP1, 12,
- CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
- GATE(CLK_SPI1_ISP, "spi1_isp", "aclk200", E4X12_GATE_ISP1, 13,
- CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
-};
-
/*
* The parent of the fin_pll clock is selected by the XOM[0] bit. This bit
* resides in chipid register space, outside of the clock controller memory
@@ -1504,8 +1306,6 @@ static void __init exynos4_clk_init(struct device_node *np,
e4210_armclk_d, ARRAY_SIZE(e4210_armclk_d),
CLK_CPU_NEEDS_DEBUG_ALT_DIV | CLK_CPU_HAS_DIV1);
} else {
- struct resource res;
-
samsung_clk_register_mux(ctx, exynos4x12_mux_clks,
ARRAY_SIZE(exynos4x12_mux_clks));
samsung_clk_register_div(ctx, exynos4x12_div_clks,
@@ -1516,14 +1316,6 @@ static void __init exynos4_clk_init(struct device_node *np,
exynos4x12_fixed_factor_clks,
ARRAY_SIZE(exynos4x12_fixed_factor_clks));
- of_address_to_resource(np, 0, &res);
- if (resource_size(&res) > 0x18000) {
- samsung_clk_register_div(ctx, exynos4x12_isp_div_clks,
- ARRAY_SIZE(exynos4x12_isp_div_clks));
- samsung_clk_register_gate(ctx, exynos4x12_isp_gate_clks,
- ARRAY_SIZE(exynos4x12_isp_gate_clks));
- }
-
exynos_register_cpu_clock(ctx, CLK_ARM_CLK, "armclk",
mout_core_p4x12[0], mout_core_p4x12[1], 0x14200,
e4412_armclk_d, ARRAY_SIZE(e4412_armclk_d),
@@ -1532,7 +1324,17 @@ static void __init exynos4_clk_init(struct device_node *np,
if (soc == EXYNOS4X12)
exynos4x12_core_down_clock();
- exynos4_clk_sleep_init();
+
+ samsung_clk_extended_sleep_init(reg_base,
+ exynos4_clk_regs, ARRAY_SIZE(exynos4_clk_regs),
+ src_mask_suspend, ARRAY_SIZE(src_mask_suspend));
+ if (exynos4_soc == EXYNOS4210)
+ samsung_clk_extended_sleep_init(reg_base,
+ exynos4210_clk_save, ARRAY_SIZE(exynos4210_clk_save),
+ src_mask_suspend_e4210, ARRAY_SIZE(src_mask_suspend_e4210));
+ else
+ samsung_clk_sleep_init(reg_base, exynos4x12_clk_save,
+ ARRAY_SIZE(exynos4x12_clk_save));
samsung_clk_of_add_provider(np, ctx);
diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c
index 347fd80c351b..f14139bcb0c1 100644
--- a/drivers/clk/samsung/clk-exynos5250.c
+++ b/drivers/clk/samsung/clk-exynos5250.c
@@ -14,7 +14,6 @@
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/syscore_ops.h>
#include "clk.h"
#include "clk-cpu.h"
@@ -111,9 +110,6 @@ enum exynos5250_plls {
static void __iomem *reg_base;
-#ifdef CONFIG_PM_SLEEP
-static struct samsung_clk_reg_dump *exynos5250_save;
-
/*
* list of controller registers to be saved and restored during a
* suspend/resume cycle.
@@ -172,41 +168,6 @@ static const unsigned long exynos5250_clk_regs[] __initconst = {
GATE_IP_ISP1,
};
-static int exynos5250_clk_suspend(void)
-{
- samsung_clk_save(reg_base, exynos5250_save,
- ARRAY_SIZE(exynos5250_clk_regs));
-
- return 0;
-}
-
-static void exynos5250_clk_resume(void)
-{
- samsung_clk_restore(reg_base, exynos5250_save,
- ARRAY_SIZE(exynos5250_clk_regs));
-}
-
-static struct syscore_ops exynos5250_clk_syscore_ops = {
- .suspend = exynos5250_clk_suspend,
- .resume = exynos5250_clk_resume,
-};
-
-static void __init exynos5250_clk_sleep_init(void)
-{
- exynos5250_save = samsung_clk_alloc_reg_dump(exynos5250_clk_regs,
- ARRAY_SIZE(exynos5250_clk_regs));
- if (!exynos5250_save) {
- pr_warn("%s: failed to allocate sleep save data, no sleep support!\n",
- __func__);
- return;
- }
-
- register_syscore_ops(&exynos5250_clk_syscore_ops);
-}
-#else
-static void __init exynos5250_clk_sleep_init(void) {}
-#endif
-
/* list of all parent clock list */
PNAME(mout_apll_p) = { "fin_pll", "fout_apll", };
PNAME(mout_cpu_p) = { "mout_apll", "mout_mpll", };
@@ -882,7 +843,8 @@ static void __init exynos5250_clk_init(struct device_node *np)
PWR_CTRL2_CORE2_UP_RATIO | PWR_CTRL2_CORE1_UP_RATIO);
__raw_writel(tmp, reg_base + PWR_CTRL2);
- exynos5250_clk_sleep_init();
+ samsung_clk_sleep_init(reg_base, exynos5250_clk_regs,
+ ARRAY_SIZE(exynos5250_clk_regs));
exynos5_subcmus_init(ctx, 1, &exynos5250_disp_subcmu);
samsung_clk_of_add_provider(np, ctx);
diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c
index 95e1bf69449b..34cce3c5898f 100644
--- a/drivers/clk/samsung/clk-exynos5420.c
+++ b/drivers/clk/samsung/clk-exynos5420.c
@@ -15,7 +15,6 @@
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/syscore_ops.h>
#include "clk.h"
#include "clk-cpu.h"
@@ -156,10 +155,6 @@ enum exynos5x_plls {
static void __iomem *reg_base;
static enum exynos5x_soc exynos5x_soc;
-#ifdef CONFIG_PM_SLEEP
-static struct samsung_clk_reg_dump *exynos5x_save;
-static struct samsung_clk_reg_dump *exynos5800_save;
-
/*
* list of controller registers to be saved and restored during a
* suspend/resume cycle.
@@ -281,68 +276,9 @@ static const struct samsung_clk_reg_dump exynos5420_set_clksrc[] = {
{ .offset = GATE_BUS_TOP, .value = 0xffffffff, },
{ .offset = GATE_BUS_DISP1, .value = 0xffffffff, },
{ .offset = GATE_IP_PERIC, .value = 0xffffffff, },
+ { .offset = GATE_IP_PERIS, .value = 0xffffffff, },
};
-static int exynos5420_clk_suspend(void)
-{
- samsung_clk_save(reg_base, exynos5x_save,
- ARRAY_SIZE(exynos5x_clk_regs));
-
- if (exynos5x_soc == EXYNOS5800)
- samsung_clk_save(reg_base, exynos5800_save,
- ARRAY_SIZE(exynos5800_clk_regs));
-
- samsung_clk_restore(reg_base, exynos5420_set_clksrc,
- ARRAY_SIZE(exynos5420_set_clksrc));
-
- return 0;
-}
-
-static void exynos5420_clk_resume(void)
-{
- samsung_clk_restore(reg_base, exynos5x_save,
- ARRAY_SIZE(exynos5x_clk_regs));
-
- if (exynos5x_soc == EXYNOS5800)
- samsung_clk_restore(reg_base, exynos5800_save,
- ARRAY_SIZE(exynos5800_clk_regs));
-}
-
-static struct syscore_ops exynos5420_clk_syscore_ops = {
- .suspend = exynos5420_clk_suspend,
- .resume = exynos5420_clk_resume,
-};
-
-static void __init exynos5420_clk_sleep_init(void)
-{
- exynos5x_save = samsung_clk_alloc_reg_dump(exynos5x_clk_regs,
- ARRAY_SIZE(exynos5x_clk_regs));
- if (!exynos5x_save) {
- pr_warn("%s: failed to allocate sleep save data, no sleep support!\n",
- __func__);
- return;
- }
-
- if (exynos5x_soc == EXYNOS5800) {
- exynos5800_save =
- samsung_clk_alloc_reg_dump(exynos5800_clk_regs,
- ARRAY_SIZE(exynos5800_clk_regs));
- if (!exynos5800_save)
- goto err_soc;
- }
-
- register_syscore_ops(&exynos5420_clk_syscore_ops);
- return;
-err_soc:
- kfree(exynos5x_save);
- pr_warn("%s: failed to allocate sleep save data, no sleep support!\n",
- __func__);
- return;
-}
-#else
-static void __init exynos5420_clk_sleep_init(void) {}
-#endif
-
/* list of all parent clocks */
PNAME(mout_mspll_cpu_p) = {"mout_sclk_cpll", "mout_sclk_dpll",
"mout_sclk_mpll", "mout_sclk_spll"};
@@ -633,6 +569,7 @@ static const struct samsung_div_clock exynos5420_div_clks[] __initconst = {
};
static const struct samsung_gate_clock exynos5420_gate_clks[] __initconst = {
+ GATE(CLK_SECKEY, "seckey", "aclk66_psgen", GATE_BUS_PERIS1, 1, 0, 0),
GATE(CLK_MAU_EPLL, "mau_epll", "mout_mau_epll_clk",
SRC_MASK_TOP7, 20, CLK_SET_RATE_PARENT, 0),
};
@@ -1162,8 +1099,6 @@ static const struct samsung_gate_clock exynos5x_gate_clks[] __initconst = {
GATE(CLK_TMU, "tmu", "aclk66_psgen", GATE_IP_PERIS, 21, 0, 0),
GATE(CLK_TMU_GPU, "tmu_gpu", "aclk66_psgen", GATE_IP_PERIS, 22, 0, 0),
- GATE(CLK_SECKEY, "seckey", "aclk66_psgen", GATE_BUS_PERIS1, 1, 0, 0),
-
/* GEN Block */
GATE(CLK_ROTATOR, "rotator", "mout_user_aclk266", GATE_IP_GEN, 1, 0, 0),
GATE(CLK_JPEG, "jpeg", "aclk300_jpeg", GATE_IP_GEN, 2, 0, 0),
@@ -1540,7 +1475,12 @@ static void __init exynos5x_clk_init(struct device_node *np,
mout_kfc_p[0], mout_kfc_p[1], 0x28200,
exynos5420_kfcclk_d, ARRAY_SIZE(exynos5420_kfcclk_d), 0);
- exynos5420_clk_sleep_init();
+ samsung_clk_extended_sleep_init(reg_base,
+ exynos5x_clk_regs, ARRAY_SIZE(exynos5x_clk_regs),
+ exynos5420_set_clksrc, ARRAY_SIZE(exynos5420_set_clksrc));
+ if (soc == EXYNOS5800)
+ samsung_clk_sleep_init(reg_base, exynos5800_clk_regs,
+ ARRAY_SIZE(exynos5800_clk_regs));
exynos5_subcmus_init(ctx, ARRAY_SIZE(exynos5x_subcmus),
exynos5x_subcmus);
diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c
index 162de44df099..751e2c4fb65b 100644
--- a/drivers/clk/samsung/clk-exynos5433.c
+++ b/drivers/clk/samsung/clk-exynos5433.c
@@ -177,6 +177,17 @@ static const unsigned long top_clk_regs[] __initconst = {
ENABLE_CMU_TOP_DIV_STAT,
};
+static const struct samsung_clk_reg_dump top_suspend_regs[] = {
+ /* force all aclk clocks enabled */
+ { ENABLE_ACLK_TOP, 0x67ecffed },
+ /* force all sclk_uart clocks enabled */
+ { ENABLE_SCLK_TOP_PERIC, 0x38 },
+ /* ISP PLL has to be enabled for suspend: reset value + ENABLE bit */
+ { ISP_PLL_CON0, 0x85cc0502 },
+ /* ISP PLL has to be enabled for suspend: reset value + ENABLE bit */
+ { AUD_PLL_CON0, 0x84830202 },
+};
+
/* list of all parent clock list */
PNAME(mout_aud_pll_p) = { "oscclk", "fout_aud_pll", };
PNAME(mout_isp_pll_p) = { "oscclk", "fout_isp_pll", };
@@ -792,6 +803,8 @@ static const struct samsung_cmu_info top_cmu_info __initconst = {
.nr_clk_ids = TOP_NR_CLK,
.clk_regs = top_clk_regs,
.nr_clk_regs = ARRAY_SIZE(top_clk_regs),
+ .suspend_regs = top_suspend_regs,
+ .nr_suspend_regs = ARRAY_SIZE(top_suspend_regs),
};
static void __init exynos5433_cmu_top_init(struct device_node *np)
@@ -822,6 +835,13 @@ static const unsigned long cpif_clk_regs[] __initconst = {
ENABLE_SCLK_CPIF,
};
+static const struct samsung_clk_reg_dump cpif_suspend_regs[] = {
+ /* force all sclk clocks enabled */
+ { ENABLE_SCLK_CPIF, 0x3ff },
+ /* MPHY PLL has to be enabled for suspend: reset value + ENABLE bit */
+ { MPHY_PLL_CON0, 0x81c70601 },
+};
+
/* list of all parent clock list */
PNAME(mout_mphy_pll_p) = { "oscclk", "fout_mphy_pll", };
@@ -862,6 +882,8 @@ static const struct samsung_cmu_info cpif_cmu_info __initconst = {
.nr_clk_ids = CPIF_NR_CLK,
.clk_regs = cpif_clk_regs,
.nr_clk_regs = ARRAY_SIZE(cpif_clk_regs),
+ .suspend_regs = cpif_suspend_regs,
+ .nr_suspend_regs = ARRAY_SIZE(cpif_suspend_regs),
};
static void __init exynos5433_cmu_cpif_init(struct device_node *np)
@@ -1547,6 +1569,13 @@ static const unsigned long peric_clk_regs[] __initconst = {
ENABLE_IP_PERIC2,
};
+static const struct samsung_clk_reg_dump peric_suspend_regs[] = {
+ /* pclk: sci, pmu, sysreg, gpio_{finger, ese, touch, nfc}, uart2-0 */
+ { ENABLE_PCLK_PERIC0, 0xe00ff000 },
+ /* sclk: uart2-0 */
+ { ENABLE_SCLK_PERIC, 0x7 },
+};
+
static const struct samsung_div_clock peric_div_clks[] __initconst = {
/* DIV_PERIC */
DIV(CLK_DIV_SCLK_SCI, "div_sclk_sci", "oscclk", DIV_PERIC, 4, 4),
@@ -1705,6 +1734,8 @@ static const struct samsung_cmu_info peric_cmu_info __initconst = {
.nr_clk_ids = PERIC_NR_CLK,
.clk_regs = peric_clk_regs,
.nr_clk_regs = ARRAY_SIZE(peric_clk_regs),
+ .suspend_regs = peric_suspend_regs,
+ .nr_suspend_regs = ARRAY_SIZE(peric_suspend_regs),
};
static void __init exynos5433_cmu_peric_init(struct device_node *np)
@@ -5630,7 +5661,7 @@ static const struct of_device_id exynos5433_cmu_of_match[] = {
static const struct dev_pm_ops exynos5433_cmu_pm_ops = {
SET_RUNTIME_PM_OPS(exynos5433_cmu_suspend, exynos5433_cmu_resume,
NULL)
- SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
};
diff --git a/drivers/clk/samsung/clk-s3c2410.c b/drivers/clk/samsung/clk-s3c2410.c
index a9c887475054..8cb868f06257 100644
--- a/drivers/clk/samsung/clk-s3c2410.c
+++ b/drivers/clk/samsung/clk-s3c2410.c
@@ -11,7 +11,6 @@
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/syscore_ops.h>
#include <dt-bindings/clock/s3c2410.h>
@@ -40,9 +39,6 @@ enum s3c2410_plls {
static void __iomem *reg_base;
-#ifdef CONFIG_PM_SLEEP
-static struct samsung_clk_reg_dump *s3c2410_save;
-
/*
* list of controller registers to be saved and restored during a
* suspend/resume cycle.
@@ -57,42 +53,6 @@ static unsigned long s3c2410_clk_regs[] __initdata = {
CAMDIVN,
};
-static int s3c2410_clk_suspend(void)
-{
- samsung_clk_save(reg_base, s3c2410_save,
- ARRAY_SIZE(s3c2410_clk_regs));
-
- return 0;
-}
-
-static void s3c2410_clk_resume(void)
-{
- samsung_clk_restore(reg_base, s3c2410_save,
- ARRAY_SIZE(s3c2410_clk_regs));
-}
-
-static struct syscore_ops s3c2410_clk_syscore_ops = {
- .suspend = s3c2410_clk_suspend,
- .resume = s3c2410_clk_resume,
-};
-
-static void __init s3c2410_clk_sleep_init(void)
-{
- s3c2410_save = samsung_clk_alloc_reg_dump(s3c2410_clk_regs,
- ARRAY_SIZE(s3c2410_clk_regs));
- if (!s3c2410_save) {
- pr_warn("%s: failed to allocate sleep save data, no sleep support!\n",
- __func__);
- return;
- }
-
- register_syscore_ops(&s3c2410_clk_syscore_ops);
- return;
-}
-#else
-static void __init s3c2410_clk_sleep_init(void) {}
-#endif
-
PNAME(fclk_p) = { "mpll", "div_slow" };
static struct samsung_mux_clock s3c2410_common_muxes[] __initdata = {
@@ -461,7 +421,8 @@ void __init s3c2410_common_clk_init(struct device_node *np, unsigned long xti_f,
ARRAY_SIZE(s3c244x_common_aliases));
}
- s3c2410_clk_sleep_init();
+ samsung_clk_sleep_init(reg_base, s3c2410_clk_regs,
+ ARRAY_SIZE(s3c2410_clk_regs));
samsung_clk_of_add_provider(np, ctx);
}
diff --git a/drivers/clk/samsung/clk-s3c2412.c b/drivers/clk/samsung/clk-s3c2412.c
index 6bc94d3aff78..dd1159050a5a 100644
--- a/drivers/clk/samsung/clk-s3c2412.c
+++ b/drivers/clk/samsung/clk-s3c2412.c
@@ -11,7 +11,6 @@
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/syscore_ops.h>
#include <linux/reboot.h>
#include <dt-bindings/clock/s3c2412.h>
@@ -29,9 +28,6 @@
static void __iomem *reg_base;
-#ifdef CONFIG_PM_SLEEP
-static struct samsung_clk_reg_dump *s3c2412_save;
-
/*
* list of controller registers to be saved and restored during a
* suspend/resume cycle.
@@ -45,42 +41,6 @@ static unsigned long s3c2412_clk_regs[] __initdata = {
CLKSRC,
};
-static int s3c2412_clk_suspend(void)
-{
- samsung_clk_save(reg_base, s3c2412_save,
- ARRAY_SIZE(s3c2412_clk_regs));
-
- return 0;
-}
-
-static void s3c2412_clk_resume(void)
-{
- samsung_clk_restore(reg_base, s3c2412_save,
- ARRAY_SIZE(s3c2412_clk_regs));
-}
-
-static struct syscore_ops s3c2412_clk_syscore_ops = {
- .suspend = s3c2412_clk_suspend,
- .resume = s3c2412_clk_resume,
-};
-
-static void __init s3c2412_clk_sleep_init(void)
-{
- s3c2412_save = samsung_clk_alloc_reg_dump(s3c2412_clk_regs,
- ARRAY_SIZE(s3c2412_clk_regs));
- if (!s3c2412_save) {
- pr_warn("%s: failed to allocate sleep save data, no sleep support!\n",
- __func__);
- return;
- }
-
- register_syscore_ops(&s3c2412_clk_syscore_ops);
- return;
-}
-#else
-static void __init s3c2412_clk_sleep_init(void) {}
-#endif
-
static struct clk_div_table divxti_d[] = {
{ .val = 0, .div = 1 },
{ .val = 1, .div = 2 },
@@ -278,7 +238,8 @@ void __init s3c2412_common_clk_init(struct device_node *np, unsigned long xti_f,
samsung_clk_register_alias(ctx, s3c2412_aliases,
ARRAY_SIZE(s3c2412_aliases));
- s3c2412_clk_sleep_init();
+ samsung_clk_sleep_init(reg_base, s3c2412_clk_regs,
+ ARRAY_SIZE(s3c2412_clk_regs));
samsung_clk_of_add_provider(np, ctx);
diff --git a/drivers/clk/samsung/clk-s3c2443.c b/drivers/clk/samsung/clk-s3c2443.c
index c46e6d5bc9bc..884067e4f1a1 100644
--- a/drivers/clk/samsung/clk-s3c2443.c
+++ b/drivers/clk/samsung/clk-s3c2443.c
@@ -11,7 +11,6 @@
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/syscore_ops.h>
#include <linux/reboot.h>
#include <dt-bindings/clock/s3c2443.h>
@@ -43,9 +42,6 @@ enum supported_socs {
static void __iomem *reg_base;
-#ifdef CONFIG_PM_SLEEP
-static struct samsung_clk_reg_dump *s3c2443_save;
-
/*
* list of controller registers to be saved and restored during a
* suspend/resume cycle.
@@ -65,42 +61,6 @@ static unsigned long s3c2443_clk_regs[] __initdata = {
SCLKCON,
};
-static int s3c2443_clk_suspend(void)
-{
- samsung_clk_save(reg_base, s3c2443_save,
- ARRAY_SIZE(s3c2443_clk_regs));
-
- return 0;
-}
-
-static void s3c2443_clk_resume(void)
-{
- samsung_clk_restore(reg_base, s3c2443_save,
- ARRAY_SIZE(s3c2443_clk_regs));
-}
-
-static struct syscore_ops s3c2443_clk_syscore_ops = {
- .suspend = s3c2443_clk_suspend,
- .resume = s3c2443_clk_resume,
-};
-
-static void __init s3c2443_clk_sleep_init(void)
-{
- s3c2443_save = samsung_clk_alloc_reg_dump(s3c2443_clk_regs,
- ARRAY_SIZE(s3c2443_clk_regs));
- if (!s3c2443_save) {
- pr_warn("%s: failed to allocate sleep save data, no sleep support!\n",
- __func__);
- return;
- }
-
- register_syscore_ops(&s3c2443_clk_syscore_ops);
- return;
-}
-#else
-static void __init s3c2443_clk_sleep_init(void) {}
-#endif
-
PNAME(epllref_p) = { "mpllref", "mpllref", "xti", "ext" };
PNAME(esysclk_p) = { "epllref", "epll" };
PNAME(mpllref_p) = { "xti", "mdivclk" };
@@ -450,7 +410,8 @@ void __init s3c2443_common_clk_init(struct device_node *np, unsigned long xti_f,
break;
}
- s3c2443_clk_sleep_init();
+ samsung_clk_sleep_init(reg_base, s3c2443_clk_regs,
+ ARRAY_SIZE(s3c2443_clk_regs));
samsung_clk_of_add_provider(np, ctx);
diff --git a/drivers/clk/samsung/clk-s3c64xx.c b/drivers/clk/samsung/clk-s3c64xx.c
index 6db01cf5ab83..54916c7bdb06 100644
--- a/drivers/clk/samsung/clk-s3c64xx.c
+++ b/drivers/clk/samsung/clk-s3c64xx.c
@@ -12,7 +12,6 @@
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/syscore_ops.h>
#include <dt-bindings/clock/samsung,s3c64xx-clock.h>
@@ -59,10 +58,6 @@
static void __iomem *reg_base;
static bool is_s3c6400;
-#ifdef CONFIG_PM_SLEEP
-static struct samsung_clk_reg_dump *s3c64xx_save_common;
-static struct samsung_clk_reg_dump *s3c64xx_save_soc;
-
/*
* List of controller registers to be saved and restored during
* a suspend/resume cycle.
@@ -89,60 +84,6 @@ static unsigned long s3c6410_clk_regs[] __initdata = {
MEM0_GATE,
};
-static int s3c64xx_clk_suspend(void)
-{
- samsung_clk_save(reg_base, s3c64xx_save_common,
- ARRAY_SIZE(s3c64xx_clk_regs));
-
- if (!is_s3c6400)
- samsung_clk_save(reg_base, s3c64xx_save_soc,
- ARRAY_SIZE(s3c6410_clk_regs));
-
- return 0;
-}
-
-static void s3c64xx_clk_resume(void)
-{
- samsung_clk_restore(reg_base, s3c64xx_save_common,
- ARRAY_SIZE(s3c64xx_clk_regs));
-
- if (!is_s3c6400)
- samsung_clk_restore(reg_base, s3c64xx_save_soc,
- ARRAY_SIZE(s3c6410_clk_regs));
-}
-
-static struct syscore_ops s3c64xx_clk_syscore_ops = {
- .suspend = s3c64xx_clk_suspend,
- .resume = s3c64xx_clk_resume,
-};
-
-static void __init s3c64xx_clk_sleep_init(void)
-{
- s3c64xx_save_common = samsung_clk_alloc_reg_dump(s3c64xx_clk_regs,
- ARRAY_SIZE(s3c64xx_clk_regs));
- if (!s3c64xx_save_common)
- goto err_warn;
-
- if (!is_s3c6400) {
- s3c64xx_save_soc = samsung_clk_alloc_reg_dump(s3c6410_clk_regs,
- ARRAY_SIZE(s3c6410_clk_regs));
- if (!s3c64xx_save_soc)
- goto err_soc;
- }
-
- register_syscore_ops(&s3c64xx_clk_syscore_ops);
- return;
-
-err_soc:
- kfree(s3c64xx_save_common);
-err_warn:
- pr_warn("%s: failed to allocate sleep save data, no sleep support!\n",
- __func__);
-}
-#else
-static void __init s3c64xx_clk_sleep_init(void) {}
-#endif
-
/* List of parent clocks common for all S3C64xx SoCs. */
PNAME(spi_mmc_p) = { "mout_epll", "dout_mpll", "fin_pll", "clk27m" };
PNAME(uart_p) = { "mout_epll", "dout_mpll" };
@@ -508,7 +449,12 @@ void __init s3c64xx_clk_init(struct device_node *np, unsigned long xtal_f,
samsung_clk_register_alias(ctx, s3c64xx_clock_aliases,
ARRAY_SIZE(s3c64xx_clock_aliases));
- s3c64xx_clk_sleep_init();
+
+ samsung_clk_sleep_init(reg_base, s3c64xx_clk_regs,
+ ARRAY_SIZE(s3c64xx_clk_regs));
+ if (!is_s3c6400)
+ samsung_clk_sleep_init(reg_base, s3c6410_clk_regs,
+ ARRAY_SIZE(s3c6410_clk_regs));
samsung_clk_of_add_provider(np, ctx);
diff --git a/drivers/clk/samsung/clk-s5pv210.c b/drivers/clk/samsung/clk-s5pv210.c
index fd2725710a6f..41d2337fe030 100644
--- a/drivers/clk/samsung/clk-s5pv210.c
+++ b/drivers/clk/samsung/clk-s5pv210.c
@@ -14,7 +14,6 @@
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/syscore_ops.h>
#include "clk.h"
#include "clk-pll.h"
@@ -83,9 +82,6 @@ enum {
static void __iomem *reg_base;
-#ifdef CONFIG_PM_SLEEP
-static struct samsung_clk_reg_dump *s5pv210_clk_dump;
-
/* List of registers that need to be preserved across suspend/resume. */
static unsigned long s5pv210_clk_regs[] __initdata = {
CLK_SRC0,
@@ -132,40 +128,6 @@ static unsigned long s5pv210_clk_regs[] __initdata = {
CLK_OUT,
};
-static int s5pv210_clk_suspend(void)
-{
- samsung_clk_save(reg_base, s5pv210_clk_dump,
- ARRAY_SIZE(s5pv210_clk_regs));
- return 0;
-}
-
-static void s5pv210_clk_resume(void)
-{
- samsung_clk_restore(reg_base, s5pv210_clk_dump,
- ARRAY_SIZE(s5pv210_clk_regs));
-}
-
-static struct syscore_ops s5pv210_clk_syscore_ops = {
- .suspend = s5pv210_clk_suspend,
- .resume = s5pv210_clk_resume,
-};
-
-static void s5pv210_clk_sleep_init(void)
-{
- s5pv210_clk_dump =
- samsung_clk_alloc_reg_dump(s5pv210_clk_regs,
- ARRAY_SIZE(s5pv210_clk_regs));
- if (!s5pv210_clk_dump) {
- pr_warn("%s: Failed to allocate sleep save data\n", __func__);
- return;
- }
-
- register_syscore_ops(&s5pv210_clk_syscore_ops);
-}
-#else
-static inline void s5pv210_clk_sleep_init(void) { }
-#endif
-
/* Mux parent lists. */
static const char *const fin_pll_p[] __initconst = {
"xxti",
@@ -822,7 +784,8 @@ static void __init __s5pv210_clk_init(struct device_node *np,
samsung_clk_register_alias(ctx, s5pv210_aliases,
ARRAY_SIZE(s5pv210_aliases));
- s5pv210_clk_sleep_init();
+ samsung_clk_sleep_init(reg_base, s5pv210_clk_regs,
+ ARRAY_SIZE(s5pv210_clk_regs));
samsung_clk_of_add_provider(np, ctx);
diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c
index 8634884aa11c..1f6e47cd327d 100644
--- a/drivers/clk/samsung/clk.c
+++ b/drivers/clk/samsung/clk.c
@@ -290,9 +290,12 @@ static int samsung_clk_suspend(void)
{
struct samsung_clock_reg_cache *reg_cache;
- list_for_each_entry(reg_cache, &clock_reg_cache_list, node)
+ list_for_each_entry(reg_cache, &clock_reg_cache_list, node) {
samsung_clk_save(reg_cache->reg_base, reg_cache->rdump,
reg_cache->rd_num);
+ samsung_clk_restore(reg_cache->reg_base, reg_cache->rsuspend,
+ reg_cache->rsuspend_num);
+ }
return 0;
}
@@ -310,9 +313,11 @@ static struct syscore_ops samsung_clk_syscore_ops = {
.resume = samsung_clk_resume,
};
-void samsung_clk_sleep_init(void __iomem *reg_base,
+void samsung_clk_extended_sleep_init(void __iomem *reg_base,
const unsigned long *rdump,
- unsigned long nr_rdump)
+ unsigned long nr_rdump,
+ const struct samsung_clk_reg_dump *rsuspend,
+ unsigned long nr_rsuspend)
{
struct samsung_clock_reg_cache *reg_cache;
@@ -330,13 +335,10 @@ void samsung_clk_sleep_init(void __iomem *reg_base,
reg_cache->reg_base = reg_base;
reg_cache->rd_num = nr_rdump;
+ reg_cache->rsuspend = rsuspend;
+ reg_cache->rsuspend_num = nr_rsuspend;
list_add_tail(&reg_cache->node, &clock_reg_cache_list);
}
-
-#else
-void samsung_clk_sleep_init(void __iomem *reg_base,
- const unsigned long *rdump,
- unsigned long nr_rdump) {}
#endif
/*
@@ -380,8 +382,9 @@ struct samsung_clk_provider * __init samsung_cmu_register_one(
samsung_clk_register_fixed_factor(ctx, cmu->fixed_factor_clks,
cmu->nr_fixed_factor_clks);
if (cmu->clk_regs)
- samsung_clk_sleep_init(reg_base, cmu->clk_regs,
- cmu->nr_clk_regs);
+ samsung_clk_extended_sleep_init(reg_base,
+ cmu->clk_regs, cmu->nr_clk_regs,
+ cmu->suspend_regs, cmu->nr_suspend_regs);
samsung_clk_of_add_provider(np, ctx);
diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h
index 3880d2f9d582..c3f309d7100d 100644
--- a/drivers/clk/samsung/clk.h
+++ b/drivers/clk/samsung/clk.h
@@ -279,6 +279,8 @@ struct samsung_clock_reg_cache {
void __iomem *reg_base;
struct samsung_clk_reg_dump *rdump;
unsigned int rd_num;
+ const struct samsung_clk_reg_dump *rsuspend;
+ unsigned int rsuspend_num;
};
struct samsung_cmu_info {
@@ -358,9 +360,21 @@ extern struct samsung_clk_provider __init *samsung_cmu_register_one(
extern unsigned long _get_rate(const char *clk_name);
-extern void samsung_clk_sleep_init(void __iomem *reg_base,
+#ifdef CONFIG_PM_SLEEP
+extern void samsung_clk_extended_sleep_init(void __iomem *reg_base,
const unsigned long *rdump,
- unsigned long nr_rdump);
+ unsigned long nr_rdump,
+ const struct samsung_clk_reg_dump *rsuspend,
+ unsigned long nr_rsuspend);
+#else
+static inline void samsung_clk_extended_sleep_init(void __iomem *reg_base,
+ const unsigned long *rdump,
+ unsigned long nr_rdump,
+ const struct samsung_clk_reg_dump *rsuspend,
+ unsigned long nr_rsuspend) {}
+#endif
+#define samsung_clk_sleep_init(reg_base, rdump, nr_rdump) \
+ samsung_clk_extended_sleep_init(reg_base, rdump, nr_rdump, NULL, 0)
extern void samsung_clk_save(void __iomem *base,
struct samsung_clk_reg_dump *rd,
diff --git a/drivers/clk/st/clkgen-fsyn.c b/drivers/clk/st/clkgen-fsyn.c
index a79d81985c4e..cfa000007622 100644
--- a/drivers/clk/st/clkgen-fsyn.c
+++ b/drivers/clk/st/clkgen-fsyn.c
@@ -936,7 +936,7 @@ static void __init st_of_quadfs_setup(struct device_node *np,
if (!clk_parent_name)
return;
- pll_name = kasprintf(GFP_KERNEL, "%s.pll", np->name);
+ pll_name = kasprintf(GFP_KERNEL, "%pOFn.pll", np);
if (!pll_name)
return;
diff --git a/drivers/clk/sunxi-ng/ccu-sun4i-a10.c b/drivers/clk/sunxi-ng/ccu-sun4i-a10.c
index ffa5dac221e4..129ebd2588fd 100644
--- a/drivers/clk/sunxi-ng/ccu-sun4i-a10.c
+++ b/drivers/clk/sunxi-ng/ccu-sun4i-a10.c
@@ -1434,8 +1434,16 @@ static void __init sun4i_ccu_init(struct device_node *node,
return;
}
- /* Force the PLL-Audio-1x divider to 1 */
val = readl(reg + SUN4I_PLL_AUDIO_REG);
+
+ /*
+ * Force VCO and PLL bias current to lowest setting. Higher
+ * settings interfere with sigma-delta modulation and result
+ * in audible noise and distortions when using SPDIF or I2S.
+ */
+ val &= ~GENMASK(25, 16);
+
+ /* Force the PLL-Audio-1x divider to 1 */
val &= ~GENMASK(29, 26);
writel(val | (1 << 26), reg + SUN4I_PLL_AUDIO_REG);
diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c
index ee9c12cf3f08..5f80eb018014 100644
--- a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c
+++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c
@@ -64,17 +64,19 @@ static SUNXI_CCU_NM_WITH_GATE_LOCK(pll_audio_base_clk, "pll-audio-base",
BIT(28), /* lock */
CLK_SET_RATE_UNGATE);
-static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_video0_clk, "pll-video0",
- "osc24M", 0x010,
- 8, 7, /* N */
- 0, 4, /* M */
- BIT(24), /* frac enable */
- BIT(25), /* frac select */
- 270000000, /* frac rate 0 */
- 297000000, /* frac rate 1 */
- BIT(31), /* gate */
- BIT(28), /* lock */
- CLK_SET_RATE_UNGATE);
+static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX(pll_video0_clk, "pll-video0",
+ "osc24M", 0x010,
+ 192000000, /* Minimum rate */
+ 1008000000, /* Maximum rate */
+ 8, 7, /* N */
+ 0, 4, /* M */
+ BIT(24), /* frac enable */
+ BIT(25), /* frac select */
+ 270000000, /* frac rate 0 */
+ 297000000, /* frac rate 1 */
+ BIT(31), /* gate */
+ BIT(28), /* lock */
+ CLK_SET_RATE_UNGATE);
static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_ve_clk, "pll-ve",
"osc24M", 0x018,
@@ -125,17 +127,19 @@ static struct ccu_nk pll_periph1_clk = {
},
};
-static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_video1_clk, "pll-video1",
- "osc24M", 0x030,
- 8, 7, /* N */
- 0, 4, /* M */
- BIT(24), /* frac enable */
- BIT(25), /* frac select */
- 270000000, /* frac rate 0 */
- 297000000, /* frac rate 1 */
- BIT(31), /* gate */
- BIT(28), /* lock */
- CLK_SET_RATE_UNGATE);
+static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX(pll_video1_clk, "pll-video1",
+ "osc24M", 0x030,
+ 192000000, /* Minimum rate */
+ 1008000000, /* Maximum rate */
+ 8, 7, /* N */
+ 0, 4, /* M */
+ BIT(24), /* frac enable */
+ BIT(25), /* frac select */
+ 270000000, /* frac rate 0 */
+ 297000000, /* frac rate 1 */
+ BIT(31), /* gate */
+ BIT(28), /* lock */
+ CLK_SET_RATE_UNGATE);
static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_gpu_clk, "pll-gpu",
"osc24M", 0x038,
diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.h b/drivers/clk/sunxi-ng/ccu-sun50i-a64.h
index 061b6fbb4f95..cd415b968e8c 100644
--- a/drivers/clk/sunxi-ng/ccu-sun50i-a64.h
+++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.h
@@ -27,7 +27,9 @@
#define CLK_PLL_AUDIO_2X 4
#define CLK_PLL_AUDIO_4X 5
#define CLK_PLL_AUDIO_8X 6
-#define CLK_PLL_VIDEO0 7
+
+/* PLL_VIDEO0 exported for HDMI PHY */
+
#define CLK_PLL_VIDEO0_2X 8
#define CLK_PLL_VE 9
#define CLK_PLL_DDR0 10
diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c
index bdbfe78fe133..2193e1495086 100644
--- a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c
+++ b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c
@@ -224,7 +224,7 @@ static SUNXI_CCU_MP_WITH_MUX(psi_ahb1_ahb2_clk, "psi-ahb1-ahb2",
psi_ahb1_ahb2_parents,
0x510,
0, 5, /* M */
- 16, 2, /* P */
+ 8, 2, /* P */
24, 2, /* mux */
0);
@@ -233,19 +233,19 @@ static const char * const ahb3_apb1_apb2_parents[] = { "osc24M", "osc32k",
"pll-periph0" };
static SUNXI_CCU_MP_WITH_MUX(ahb3_clk, "ahb3", ahb3_apb1_apb2_parents, 0x51c,
0, 5, /* M */
- 16, 2, /* P */
+ 8, 2, /* P */
24, 2, /* mux */
0);
static SUNXI_CCU_MP_WITH_MUX(apb1_clk, "apb1", ahb3_apb1_apb2_parents, 0x520,
0, 5, /* M */
- 16, 2, /* P */
+ 8, 2, /* P */
24, 2, /* mux */
0);
static SUNXI_CCU_MP_WITH_MUX(apb2_clk, "apb2", ahb3_apb1_apb2_parents, 0x524,
0, 5, /* M */
- 16, 2, /* P */
+ 8, 2, /* P */
24, 2, /* mux */
0);
@@ -352,7 +352,7 @@ static SUNXI_CCU_GATE(bus_dbg_clk, "bus-dbg", "psi-ahb1-ahb2",
static SUNXI_CCU_GATE(bus_psi_clk, "bus-psi", "psi-ahb1-ahb2",
0x79c, BIT(0), 0);
-static SUNXI_CCU_GATE(bus_pwm_clk, "bus-pwm", "apb1", 0x79c, BIT(0), 0);
+static SUNXI_CCU_GATE(bus_pwm_clk, "bus-pwm", "apb1", 0x7ac, BIT(0), 0);
static SUNXI_CCU_GATE(bus_iommu_clk, "bus-iommu", "apb1", 0x7bc, BIT(0), 0);
@@ -408,26 +408,29 @@ static SUNXI_CCU_GATE(bus_nand_clk, "bus-nand", "ahb3", 0x82c, BIT(0), 0);
static const char * const mmc_parents[] = { "osc24M", "pll-periph0-2x",
"pll-periph1-2x" };
-static SUNXI_CCU_MP_WITH_MUX_GATE(mmc0_clk, "mmc0", mmc_parents, 0x830,
- 0, 4, /* M */
- 8, 2, /* N */
- 24, 3, /* mux */
- BIT(31),/* gate */
- 0);
-
-static SUNXI_CCU_MP_WITH_MUX_GATE(mmc1_clk, "mmc1", mmc_parents, 0x834,
- 0, 4, /* M */
- 8, 2, /* N */
- 24, 3, /* mux */
- BIT(31),/* gate */
- 0);
-
-static SUNXI_CCU_MP_WITH_MUX_GATE(mmc2_clk, "mmc2", mmc_parents, 0x838,
- 0, 4, /* M */
- 8, 2, /* N */
- 24, 3, /* mux */
- BIT(31),/* gate */
- 0);
+static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc0_clk, "mmc0", mmc_parents, 0x830,
+ 0, 4, /* M */
+ 8, 2, /* N */
+ 24, 3, /* mux */
+ BIT(31), /* gate */
+ 2, /* post-div */
+ 0);
+
+static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc1_clk, "mmc1", mmc_parents, 0x834,
+ 0, 4, /* M */
+ 8, 2, /* N */
+ 24, 3, /* mux */
+ BIT(31), /* gate */
+ 2, /* post-div */
+ 0);
+
+static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc2_clk, "mmc2", mmc_parents, 0x838,
+ 0, 4, /* M */
+ 8, 2, /* N */
+ 24, 3, /* mux */
+ BIT(31), /* gate */
+ 2, /* post-div */
+ 0);
static SUNXI_CCU_GATE(bus_mmc0_clk, "bus-mmc0", "ahb3", 0x84c, BIT(0), 0);
static SUNXI_CCU_GATE(bus_mmc1_clk, "bus-mmc1", "ahb3", 0x84c, BIT(1), 0);
diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c
index 7d08015b980d..2d6555d73170 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c
@@ -108,6 +108,7 @@ static struct ccu_nkmp pll_video0_clk = {
.n = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 12, 0),
.m = _SUNXI_CCU_DIV(16, 1), /* input divider */
.p = _SUNXI_CCU_DIV(0, 2), /* output divider */
+ .max_rate = 3000000000UL,
.common = {
.reg = 0x010,
.lock_reg = CCU_SUN8I_A83T_LOCK_REG,
@@ -220,6 +221,7 @@ static struct ccu_nkmp pll_video1_clk = {
.n = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 12, 0),
.m = _SUNXI_CCU_DIV(16, 1), /* input divider */
.p = _SUNXI_CCU_DIV(0, 2), /* external divider p */
+ .max_rate = 3000000000UL,
.common = {
.reg = 0x04c,
.lock_reg = CCU_SUN8I_A83T_LOCK_REG,
diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
index 77ed0b0ba681..eb5c608428fa 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
@@ -69,18 +69,19 @@ static SUNXI_CCU_NM_WITH_SDM_GATE_LOCK(pll_audio_base_clk, "pll-audio-base",
BIT(28), /* lock */
CLK_SET_RATE_UNGATE);
-static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN(pll_video_clk, "pll-video",
- "osc24M", 0x0010,
- 192000000, /* Minimum rate */
- 8, 7, /* N */
- 0, 4, /* M */
- BIT(24), /* frac enable */
- BIT(25), /* frac select */
- 270000000, /* frac rate 0 */
- 297000000, /* frac rate 1 */
- BIT(31), /* gate */
- BIT(28), /* lock */
- CLK_SET_RATE_UNGATE);
+static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX(pll_video_clk, "pll-video",
+ "osc24M", 0x0010,
+ 192000000, /* Minimum rate */
+ 912000000, /* Maximum rate */
+ 8, 7, /* N */
+ 0, 4, /* M */
+ BIT(24), /* frac enable */
+ BIT(25), /* frac select */
+ 270000000, /* frac rate 0 */
+ 297000000, /* frac rate 1 */
+ BIT(31), /* gate */
+ BIT(28), /* lock */
+ CLK_SET_RATE_UNGATE);
static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_ve_clk, "pll-ve",
"osc24M", 0x0018,
diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-r40.c b/drivers/clk/sunxi-ng/ccu-sun8i-r40.c
index 0f388f6944d5..582ebd41d20d 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-r40.c
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-r40.c
@@ -65,19 +65,19 @@ static SUNXI_CCU_NM_WITH_GATE_LOCK(pll_audio_base_clk, "pll-audio-base",
BIT(28), /* lock */
CLK_SET_RATE_UNGATE);
-/* TODO: The result of N/M is required to be in [8, 25] range. */
-static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN(pll_video0_clk, "pll-video0",
- "osc24M", 0x0010,
- 192000000, /* Minimum rate */
- 8, 7, /* N */
- 0, 4, /* M */
- BIT(24), /* frac enable */
- BIT(25), /* frac select */
- 270000000, /* frac rate 0 */
- 297000000, /* frac rate 1 */
- BIT(31), /* gate */
- BIT(28), /* lock */
- CLK_SET_RATE_UNGATE);
+static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX(pll_video0_clk, "pll-video0",
+ "osc24M", 0x0010,
+ 192000000, /* Minimum rate */
+ 1008000000, /* Maximum rate */
+ 8, 7, /* N */
+ 0, 4, /* M */
+ BIT(24), /* frac enable */
+ BIT(25), /* frac select */
+ 270000000, /* frac rate 0 */
+ 297000000, /* frac rate 1 */
+ BIT(31), /* gate */
+ BIT(28), /* lock */
+ CLK_SET_RATE_UNGATE);
/* TODO: The result of N/M is required to be in [8, 25] range. */
static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_ve_clk, "pll-ve",
@@ -152,19 +152,19 @@ static struct ccu_nk pll_periph1_clk = {
},
};
-/* TODO: The result of N/M is required to be in [8, 25] range. */
-static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN(pll_video1_clk, "pll-video1",
- "osc24M", 0x030,
- 192000000, /* Minimum rate */
- 8, 7, /* N */
- 0, 4, /* M */
- BIT(24), /* frac enable */
- BIT(25), /* frac select */
- 270000000, /* frac rate 0 */
- 297000000, /* frac rate 1 */
- BIT(31), /* gate */
- BIT(28), /* lock */
- CLK_SET_RATE_UNGATE);
+static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX(pll_video1_clk, "pll-video1",
+ "osc24M", 0x030,
+ 192000000, /* Minimum rate */
+ 1008000000, /* Maximum rate */
+ 8, 7, /* N */
+ 0, 4, /* M */
+ BIT(24), /* frac enable */
+ BIT(25), /* frac select */
+ 270000000, /* frac rate 0 */
+ 297000000, /* frac rate 1 */
+ BIT(31), /* gate */
+ BIT(28), /* lock */
+ CLK_SET_RATE_UNGATE);
static struct ccu_nkm pll_sata_clk = {
.enable = BIT(31),
diff --git a/drivers/clk/sunxi-ng/ccu_nkmp.c b/drivers/clk/sunxi-ng/ccu_nkmp.c
index ebd9436d2c7c..9b49adb20d07 100644
--- a/drivers/clk/sunxi-ng/ccu_nkmp.c
+++ b/drivers/clk/sunxi-ng/ccu_nkmp.c
@@ -137,6 +137,13 @@ static long ccu_nkmp_round_rate(struct clk_hw *hw, unsigned long rate,
if (nkmp->common.features & CCU_FEATURE_FIXED_POSTDIV)
rate *= nkmp->fixed_post_div;
+ if (nkmp->max_rate && rate > nkmp->max_rate) {
+ rate = nkmp->max_rate;
+ if (nkmp->common.features & CCU_FEATURE_FIXED_POSTDIV)
+ rate /= nkmp->fixed_post_div;
+ return rate;
+ }
+
_nkmp.min_n = nkmp->n.min ?: 1;
_nkmp.max_n = nkmp->n.max ?: 1 << nkmp->n.width;
_nkmp.min_k = nkmp->k.min ?: 1;
diff --git a/drivers/clk/sunxi-ng/ccu_nkmp.h b/drivers/clk/sunxi-ng/ccu_nkmp.h
index 6940503e7fc4..a9f8c116a745 100644
--- a/drivers/clk/sunxi-ng/ccu_nkmp.h
+++ b/drivers/clk/sunxi-ng/ccu_nkmp.h
@@ -35,6 +35,7 @@ struct ccu_nkmp {
struct ccu_div_internal p;
unsigned int fixed_post_div;
+ unsigned int max_rate;
struct ccu_common common;
};
diff --git a/drivers/clk/sunxi-ng/ccu_nm.c b/drivers/clk/sunxi-ng/ccu_nm.c
index 4e2073307f34..6fe3c14f7b2d 100644
--- a/drivers/clk/sunxi-ng/ccu_nm.c
+++ b/drivers/clk/sunxi-ng/ccu_nm.c
@@ -124,6 +124,13 @@ static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate,
return rate;
}
+ if (nm->max_rate && rate > nm->max_rate) {
+ rate = nm->max_rate;
+ if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV)
+ rate /= nm->fixed_post_div;
+ return rate;
+ }
+
if (ccu_frac_helper_has_rate(&nm->common, &nm->frac, rate)) {
if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV)
rate /= nm->fixed_post_div;
diff --git a/drivers/clk/sunxi-ng/ccu_nm.h b/drivers/clk/sunxi-ng/ccu_nm.h
index 1d8b459c50b7..de232f2199a6 100644
--- a/drivers/clk/sunxi-ng/ccu_nm.h
+++ b/drivers/clk/sunxi-ng/ccu_nm.h
@@ -38,6 +38,7 @@ struct ccu_nm {
unsigned int fixed_post_div;
unsigned int min_rate;
+ unsigned int max_rate;
struct ccu_common common;
};
@@ -115,6 +116,35 @@ struct ccu_nm {
}, \
}
+#define SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX(_struct, _name, \
+ _parent, _reg, \
+ _min_rate, _max_rate, \
+ _nshift, _nwidth, \
+ _mshift, _mwidth, \
+ _frac_en, _frac_sel, \
+ _frac_rate_0, \
+ _frac_rate_1, \
+ _gate, _lock, _flags) \
+ struct ccu_nm _struct = { \
+ .enable = _gate, \
+ .lock = _lock, \
+ .n = _SUNXI_CCU_MULT(_nshift, _nwidth), \
+ .m = _SUNXI_CCU_DIV(_mshift, _mwidth), \
+ .frac = _SUNXI_CCU_FRAC(_frac_en, _frac_sel, \
+ _frac_rate_0, \
+ _frac_rate_1), \
+ .min_rate = _min_rate, \
+ .max_rate = _max_rate, \
+ .common = { \
+ .reg = _reg, \
+ .features = CCU_FEATURE_FRACTIONAL, \
+ .hw.init = CLK_HW_INIT(_name, \
+ _parent, \
+ &ccu_nm_ops, \
+ _flags), \
+ }, \
+ }
+
#define SUNXI_CCU_NM_WITH_GATE_LOCK(_struct, _name, _parent, _reg, \
_nshift, _nwidth, \
_mshift, _mwidth, \
diff --git a/drivers/clk/sunxi/clk-mod0.c b/drivers/clk/sunxi/clk-mod0.c
index a27c264cc9b4..fc0278a1acc7 100644
--- a/drivers/clk/sunxi/clk-mod0.c
+++ b/drivers/clk/sunxi/clk-mod0.c
@@ -140,8 +140,8 @@ static void __init sun9i_a80_mod0_setup(struct device_node *node)
reg = of_io_request_and_map(node, 0, of_node_full_name(node));
if (IS_ERR(reg)) {
- pr_err("Could not get registers for mod0-clk: %s\n",
- node->name);
+ pr_err("Could not get registers for mod0-clk: %pOFn\n",
+ node);
return;
}
@@ -306,7 +306,7 @@ static void __init sunxi_mmc_setup(struct device_node *node,
reg = of_io_request_and_map(node, 0, of_node_full_name(node));
if (IS_ERR(reg)) {
- pr_err("Couldn't map the %s clock registers\n", node->name);
+ pr_err("Couldn't map the %pOFn clock registers\n", node);
return;
}
diff --git a/drivers/clk/sunxi/clk-sun9i-core.c b/drivers/clk/sunxi/clk-sun9i-core.c
index e9295c286d5d..7e21b2b10c94 100644
--- a/drivers/clk/sunxi/clk-sun9i-core.c
+++ b/drivers/clk/sunxi/clk-sun9i-core.c
@@ -88,8 +88,8 @@ static void __init sun9i_a80_pll4_setup(struct device_node *node)
reg = of_io_request_and_map(node, 0, of_node_full_name(node));
if (IS_ERR(reg)) {
- pr_err("Could not get registers for a80-pll4-clk: %s\n",
- node->name);
+ pr_err("Could not get registers for a80-pll4-clk: %pOFn\n",
+ node);
return;
}
@@ -142,8 +142,8 @@ static void __init sun9i_a80_gt_setup(struct device_node *node)
reg = of_io_request_and_map(node, 0, of_node_full_name(node));
if (IS_ERR(reg)) {
- pr_err("Could not get registers for a80-gt-clk: %s\n",
- node->name);
+ pr_err("Could not get registers for a80-gt-clk: %pOFn\n",
+ node);
return;
}
@@ -197,8 +197,8 @@ static void __init sun9i_a80_ahb_setup(struct device_node *node)
reg = of_io_request_and_map(node, 0, of_node_full_name(node));
if (IS_ERR(reg)) {
- pr_err("Could not get registers for a80-ahb-clk: %s\n",
- node->name);
+ pr_err("Could not get registers for a80-ahb-clk: %pOFn\n",
+ node);
return;
}
@@ -223,8 +223,8 @@ static void __init sun9i_a80_apb0_setup(struct device_node *node)
reg = of_io_request_and_map(node, 0, of_node_full_name(node));
if (IS_ERR(reg)) {
- pr_err("Could not get registers for a80-apb0-clk: %s\n",
- node->name);
+ pr_err("Could not get registers for a80-apb0-clk: %pOFn\n",
+ node);
return;
}
@@ -280,8 +280,8 @@ static void __init sun9i_a80_apb1_setup(struct device_node *node)
reg = of_io_request_and_map(node, 0, of_node_full_name(node));
if (IS_ERR(reg)) {
- pr_err("Could not get registers for a80-apb1-clk: %s\n",
- node->name);
+ pr_err("Could not get registers for a80-apb1-clk: %pOFn\n",
+ node);
return;
}
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index 012714d94b42..892c29030b7b 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -568,8 +568,8 @@ static struct clk * __init sunxi_factors_clk_setup(struct device_node *node,
reg = of_iomap(node, 0);
if (!reg) {
- pr_err("Could not get registers for factors-clk: %s\n",
- node->name);
+ pr_err("Could not get registers for factors-clk: %pOFn\n",
+ node);
return NULL;
}
diff --git a/drivers/clk/tegra/clk-dfll.c b/drivers/clk/tegra/clk-dfll.c
index 48ee43734e05..ebb0e1b6bf01 100644
--- a/drivers/clk/tegra/clk-dfll.c
+++ b/drivers/clk/tegra/clk-dfll.c
@@ -1609,8 +1609,12 @@ int tegra_dfll_register(struct platform_device *pdev,
td->vdd_reg = devm_regulator_get(td->dev, "vdd-cpu");
if (IS_ERR(td->vdd_reg)) {
- dev_err(td->dev, "couldn't get vdd_cpu regulator\n");
- return PTR_ERR(td->vdd_reg);
+ ret = PTR_ERR(td->vdd_reg);
+ if (ret != -EPROBE_DEFER)
+ dev_err(td->dev, "couldn't get vdd_cpu regulator: %d\n",
+ ret);
+
+ return ret;
}
td->dvco_rst = devm_reset_control_get(td->dev, "dvco");
diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
index 9eb1cb14fce1..88f1943bd2b5 100644
--- a/drivers/clk/tegra/clk-tegra210.c
+++ b/drivers/clk/tegra/clk-tegra210.c
@@ -27,6 +27,7 @@
#include <dt-bindings/clock/tegra210-car.h>
#include <dt-bindings/reset/tegra210-car.h>
#include <linux/iopoll.h>
+#include <linux/sizes.h>
#include <soc/tegra/pmc.h>
#include "clk.h"
@@ -2603,7 +2604,7 @@ static struct tegra210_domain_mbist_war tegra210_pg_mbist_war[] = {
[TEGRA_POWERGATE_MPE] = {
.handle_lvl2_ovr = tegra210_generic_mbist_war,
.lvl2_offset = LVL2_CLK_GATE_OVRE,
- .lvl2_mask = BIT(2),
+ .lvl2_mask = BIT(29),
},
[TEGRA_POWERGATE_SOR] = {
.handle_lvl2_ovr = tegra210_generic_mbist_war,
@@ -2654,14 +2655,14 @@ static struct tegra210_domain_mbist_war tegra210_pg_mbist_war[] = {
.num_clks = ARRAY_SIZE(nvdec_slcg_clkids),
.clk_init_data = nvdec_slcg_clkids,
.handle_lvl2_ovr = tegra210_generic_mbist_war,
- .lvl2_offset = LVL2_CLK_GATE_OVRC,
+ .lvl2_offset = LVL2_CLK_GATE_OVRE,
.lvl2_mask = BIT(9) | BIT(31),
},
[TEGRA_POWERGATE_NVJPG] = {
.num_clks = ARRAY_SIZE(nvjpg_slcg_clkids),
.clk_init_data = nvjpg_slcg_clkids,
.handle_lvl2_ovr = tegra210_generic_mbist_war,
- .lvl2_offset = LVL2_CLK_GATE_OVRC,
+ .lvl2_offset = LVL2_CLK_GATE_OVRE,
.lvl2_mask = BIT(9) | BIT(31),
},
[TEGRA_POWERGATE_AUD] = {
diff --git a/drivers/clk/ti/Makefile b/drivers/clk/ti/Makefile
index 5ab295d2a3cb..5ca1e39dd88a 100644
--- a/drivers/clk/ti/Makefile
+++ b/drivers/clk/ti/Makefile
@@ -6,7 +6,8 @@ clk-common = dpll.o composite.o divider.o gate.o \
fixed-factor.o mux.o apll.o \
clkt_dpll.o clkt_iclk.o clkt_dflt.o \
clkctrl.o
-obj-$(CONFIG_SOC_AM33XX) += $(clk-common) clk-33xx.o dpll3xxx.o
+obj-$(CONFIG_SOC_AM33XX) += $(clk-common) clk-33xx.o dpll3xxx.o \
+ clk-33xx-compat.o
obj-$(CONFIG_SOC_TI81XX) += $(clk-common) fapll.o clk-814x.o clk-816x.o
obj-$(CONFIG_ARCH_OMAP2) += $(clk-common) interface.o clk-2xxx.o
obj-$(CONFIG_ARCH_OMAP3) += $(clk-common) interface.o \
@@ -16,8 +17,10 @@ obj-$(CONFIG_ARCH_OMAP4) += $(clk-common) clk-44xx.o \
obj-$(CONFIG_SOC_OMAP5) += $(clk-common) clk-54xx.o \
dpll3xxx.o dpll44xx.o
obj-$(CONFIG_SOC_DRA7XX) += $(clk-common) clk-7xx.o \
- clk-dra7-atl.o dpll3xxx.o dpll44xx.o
-obj-$(CONFIG_SOC_AM43XX) += $(clk-common) dpll3xxx.o clk-43xx.o
+ clk-dra7-atl.o dpll3xxx.o \
+ dpll44xx.o clk-7xx-compat.o
+obj-$(CONFIG_SOC_AM43XX) += $(clk-common) dpll3xxx.o clk-43xx.o \
+ clk-43xx-compat.o
endif # CONFIG_ARCH_OMAP2PLUS
diff --git a/drivers/clk/ti/apll.c b/drivers/clk/ti/apll.c
index 61c126a5d26a..222f68bc3f2a 100644
--- a/drivers/clk/ti/apll.c
+++ b/drivers/clk/ti/apll.c
@@ -143,8 +143,8 @@ static void __init omap_clk_register_apll(void *user,
clk = of_clk_get(node, 0);
if (IS_ERR(clk)) {
- pr_debug("clk-ref for %s not ready, retry\n",
- node->name);
+ pr_debug("clk-ref for %pOFn not ready, retry\n",
+ node);
if (!ti_clk_retry_init(node, hw, omap_clk_register_apll))
return;
@@ -155,8 +155,8 @@ static void __init omap_clk_register_apll(void *user,
clk = of_clk_get(node, 1);
if (IS_ERR(clk)) {
- pr_debug("clk-bypass for %s not ready, retry\n",
- node->name);
+ pr_debug("clk-bypass for %pOFn not ready, retry\n",
+ node);
if (!ti_clk_retry_init(node, hw, omap_clk_register_apll))
return;
@@ -202,7 +202,7 @@ static void __init of_dra7_apll_setup(struct device_node *node)
init->num_parents = of_clk_get_parent_count(node);
if (init->num_parents < 1) {
- pr_err("dra7 apll %s must have parent(s)\n", node->name);
+ pr_err("dra7 apll %pOFn must have parent(s)\n", node);
goto cleanup;
}
@@ -366,7 +366,7 @@ static void __init of_omap2_apll_setup(struct device_node *node)
init->num_parents = of_clk_get_parent_count(node);
if (init->num_parents != 1) {
- pr_err("%s must have one parent\n", node->name);
+ pr_err("%pOFn must have one parent\n", node);
goto cleanup;
}
@@ -374,13 +374,13 @@ static void __init of_omap2_apll_setup(struct device_node *node)
init->parent_names = &parent_name;
if (of_property_read_u32(node, "ti,clock-frequency", &val)) {
- pr_err("%s missing clock-frequency\n", node->name);
+ pr_err("%pOFn missing clock-frequency\n", node);
goto cleanup;
}
clk_hw->fixed_rate = val;
if (of_property_read_u32(node, "ti,bit-shift", &val)) {
- pr_err("%s missing bit-shift\n", node->name);
+ pr_err("%pOFn missing bit-shift\n", node);
goto cleanup;
}
@@ -389,7 +389,7 @@ static void __init of_omap2_apll_setup(struct device_node *node)
ad->autoidle_mask = 0x3 << val;
if (of_property_read_u32(node, "ti,idlest-shift", &val)) {
- pr_err("%s missing idlest-shift\n", node->name);
+ pr_err("%pOFn missing idlest-shift\n", node);
goto cleanup;
}
diff --git a/drivers/clk/ti/clk-33xx-compat.c b/drivers/clk/ti/clk-33xx-compat.c
new file mode 100644
index 000000000000..3e07f127912a
--- /dev/null
+++ b/drivers/clk/ti/clk-33xx-compat.c
@@ -0,0 +1,218 @@
+/*
+ * AM33XX Clock init
+ *
+ * Copyright (C) 2013 Texas Instruments, Inc
+ * Tero Kristo (t-kristo@ti.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clk/ti.h>
+#include <dt-bindings/clock/am3.h>
+
+#include "clock.h"
+
+static const char * const am3_gpio1_dbclk_parents[] __initconst = {
+ "l4_per_cm:clk:0138:0",
+ NULL,
+};
+
+static const struct omap_clkctrl_bit_data am3_gpio2_bit_data[] __initconst = {
+ { 18, TI_CLK_GATE, am3_gpio1_dbclk_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data am3_gpio3_bit_data[] __initconst = {
+ { 18, TI_CLK_GATE, am3_gpio1_dbclk_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data am3_gpio4_bit_data[] __initconst = {
+ { 18, TI_CLK_GATE, am3_gpio1_dbclk_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data am3_l4_per_clkctrl_regs[] __initconst = {
+ { AM3_CPGMAC0_CLKCTRL, NULL, CLKF_SW_SUP, "cpsw_125mhz_gclk", "cpsw_125mhz_clkdm" },
+ { AM3_LCDC_CLKCTRL, NULL, CLKF_SW_SUP | CLKF_SET_RATE_PARENT, "lcd_gclk", "lcdc_clkdm" },
+ { AM3_USB_OTG_HS_CLKCTRL, NULL, CLKF_SW_SUP, "usbotg_fck", "l3s_clkdm" },
+ { AM3_TPTC0_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" },
+ { AM3_EMIF_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_ddr_m2_div2_ck", "l3_clkdm" },
+ { AM3_OCMCRAM_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" },
+ { AM3_GPMC_CLKCTRL, NULL, CLKF_SW_SUP, "l3s_gclk", "l3s_clkdm" },
+ { AM3_MCASP0_CLKCTRL, NULL, CLKF_SW_SUP, "mcasp0_fck", "l3s_clkdm" },
+ { AM3_UART6_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM3_MMC1_CLKCTRL, NULL, CLKF_SW_SUP, "mmc_clk" },
+ { AM3_ELM_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM3_I2C3_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM3_I2C2_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM3_SPI0_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM3_SPI1_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM3_L4_LS_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM3_MCASP1_CLKCTRL, NULL, CLKF_SW_SUP, "mcasp1_fck", "l3s_clkdm" },
+ { AM3_UART2_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM3_UART3_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM3_UART4_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM3_UART5_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM3_TIMER7_CLKCTRL, NULL, CLKF_SW_SUP, "timer7_fck" },
+ { AM3_TIMER2_CLKCTRL, NULL, CLKF_SW_SUP, "timer2_fck" },
+ { AM3_TIMER3_CLKCTRL, NULL, CLKF_SW_SUP, "timer3_fck" },
+ { AM3_TIMER4_CLKCTRL, NULL, CLKF_SW_SUP, "timer4_fck" },
+ { AM3_RNG_CLKCTRL, NULL, CLKF_SW_SUP, "rng_fck" },
+ { AM3_AES_CLKCTRL, NULL, CLKF_SW_SUP, "aes0_fck", "l3_clkdm" },
+ { AM3_SHAM_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" },
+ { AM3_GPIO2_CLKCTRL, am3_gpio2_bit_data, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM3_GPIO3_CLKCTRL, am3_gpio3_bit_data, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM3_GPIO4_CLKCTRL, am3_gpio4_bit_data, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM3_TPCC_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" },
+ { AM3_D_CAN0_CLKCTRL, NULL, CLKF_SW_SUP, "dcan0_fck" },
+ { AM3_D_CAN1_CLKCTRL, NULL, CLKF_SW_SUP, "dcan1_fck" },
+ { AM3_EPWMSS1_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM3_EPWMSS0_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM3_EPWMSS2_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM3_L3_INSTR_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" },
+ { AM3_L3_MAIN_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" },
+ { AM3_PRUSS_CLKCTRL, NULL, CLKF_SW_SUP, "pruss_ocp_gclk", "pruss_ocp_clkdm" },
+ { AM3_TIMER5_CLKCTRL, NULL, CLKF_SW_SUP, "timer5_fck" },
+ { AM3_TIMER6_CLKCTRL, NULL, CLKF_SW_SUP, "timer6_fck" },
+ { AM3_MMC2_CLKCTRL, NULL, CLKF_SW_SUP, "mmc_clk" },
+ { AM3_MMC3_CLKCTRL, NULL, CLKF_SW_SUP, "mmc_clk", "l3s_clkdm" },
+ { AM3_TPTC1_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" },
+ { AM3_TPTC2_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" },
+ { AM3_SPINLOCK_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM3_MAILBOX_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM3_L4_HS_CLKCTRL, NULL, CLKF_SW_SUP, "l4hs_gclk", "l4hs_clkdm" },
+ { AM3_OCPWP_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM3_CLKDIV32K_CLKCTRL, NULL, CLKF_SW_SUP, "clkdiv32k_ck", "clk_24mhz_clkdm" },
+ { 0 },
+};
+
+static const char * const am3_gpio0_dbclk_parents[] __initconst = {
+ "gpio0_dbclk_mux_ck",
+ NULL,
+};
+
+static const struct omap_clkctrl_bit_data am3_gpio1_bit_data[] __initconst = {
+ { 18, TI_CLK_GATE, am3_gpio0_dbclk_parents, NULL },
+ { 0 },
+};
+
+static const char * const am3_dbg_sysclk_ck_parents[] __initconst = {
+ "sys_clkin_ck",
+ NULL,
+};
+
+static const char * const am3_trace_pmd_clk_mux_ck_parents[] __initconst = {
+ "l4_wkup_cm:clk:0010:19",
+ "l4_wkup_cm:clk:0010:30",
+ NULL,
+};
+
+static const char * const am3_trace_clk_div_ck_parents[] __initconst = {
+ "l4_wkup_cm:clk:0010:20",
+ NULL,
+};
+
+static const struct omap_clkctrl_div_data am3_trace_clk_div_ck_data __initconst = {
+ .max_div = 64,
+ .flags = CLK_DIVIDER_POWER_OF_TWO,
+};
+
+static const char * const am3_stm_clk_div_ck_parents[] __initconst = {
+ "l4_wkup_cm:clk:0010:22",
+ NULL,
+};
+
+static const struct omap_clkctrl_div_data am3_stm_clk_div_ck_data __initconst = {
+ .max_div = 64,
+ .flags = CLK_DIVIDER_POWER_OF_TWO,
+};
+
+static const char * const am3_dbg_clka_ck_parents[] __initconst = {
+ "dpll_core_m4_ck",
+ NULL,
+};
+
+static const struct omap_clkctrl_bit_data am3_debugss_bit_data[] __initconst = {
+ { 19, TI_CLK_GATE, am3_dbg_sysclk_ck_parents, NULL },
+ { 20, TI_CLK_MUX, am3_trace_pmd_clk_mux_ck_parents, NULL },
+ { 22, TI_CLK_MUX, am3_trace_pmd_clk_mux_ck_parents, NULL },
+ { 24, TI_CLK_DIVIDER, am3_trace_clk_div_ck_parents, &am3_trace_clk_div_ck_data },
+ { 27, TI_CLK_DIVIDER, am3_stm_clk_div_ck_parents, &am3_stm_clk_div_ck_data },
+ { 30, TI_CLK_GATE, am3_dbg_clka_ck_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data am3_l4_wkup_clkctrl_regs[] __initconst = {
+ { AM3_CONTROL_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_core_m4_div2_ck" },
+ { AM3_GPIO1_CLKCTRL, am3_gpio1_bit_data, CLKF_SW_SUP, "dpll_core_m4_div2_ck" },
+ { AM3_L4_WKUP_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_core_m4_div2_ck" },
+ { AM3_DEBUGSS_CLKCTRL, am3_debugss_bit_data, CLKF_SW_SUP, "l4_wkup_cm:clk:0010:24", "l3_aon_clkdm" },
+ { AM3_WKUP_M3_CLKCTRL, NULL, CLKF_NO_IDLEST, "dpll_core_m4_div2_ck", "l4_wkup_aon_clkdm" },
+ { AM3_UART1_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_wkupdm_ck" },
+ { AM3_I2C1_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_wkupdm_ck" },
+ { AM3_ADC_TSC_CLKCTRL, NULL, CLKF_SW_SUP, "adc_tsc_fck" },
+ { AM3_SMARTREFLEX0_CLKCTRL, NULL, CLKF_SW_SUP, "smartreflex0_fck" },
+ { AM3_TIMER1_CLKCTRL, NULL, CLKF_SW_SUP, "timer1_fck" },
+ { AM3_SMARTREFLEX1_CLKCTRL, NULL, CLKF_SW_SUP, "smartreflex1_fck" },
+ { AM3_WD_TIMER2_CLKCTRL, NULL, CLKF_SW_SUP, "wdt1_fck" },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data am3_mpu_clkctrl_regs[] __initconst = {
+ { AM3_MPU_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_mpu_m2_ck" },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data am3_l4_rtc_clkctrl_regs[] __initconst = {
+ { AM3_RTC_CLKCTRL, NULL, CLKF_SW_SUP, "clk_32768_ck" },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data am3_gfx_l3_clkctrl_regs[] __initconst = {
+ { AM3_GFX_CLKCTRL, NULL, CLKF_SW_SUP, "gfx_fck_div_ck" },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data am3_l4_cefuse_clkctrl_regs[] __initconst = {
+ { AM3_CEFUSE_CLKCTRL, NULL, CLKF_SW_SUP, "sys_clkin_ck" },
+ { 0 },
+};
+
+const struct omap_clkctrl_data am3_clkctrl_compat_data[] __initconst = {
+ { 0x44e00014, am3_l4_per_clkctrl_regs },
+ { 0x44e00404, am3_l4_wkup_clkctrl_regs },
+ { 0x44e00604, am3_mpu_clkctrl_regs },
+ { 0x44e00800, am3_l4_rtc_clkctrl_regs },
+ { 0x44e00904, am3_gfx_l3_clkctrl_regs },
+ { 0x44e00a20, am3_l4_cefuse_clkctrl_regs },
+ { 0 },
+};
+
+struct ti_dt_clk am33xx_compat_clks[] = {
+ DT_CLK(NULL, "timer_32k_ck", "l4_per_cm:0138:0"),
+ DT_CLK(NULL, "timer_sys_ck", "sys_clkin_ck"),
+ DT_CLK(NULL, "clkdiv32k_ick", "l4_per_cm:0138:0"),
+ DT_CLK(NULL, "dbg_clka_ck", "l4_wkup_cm:0010:30"),
+ DT_CLK(NULL, "dbg_sysclk_ck", "l4_wkup_cm:0010:19"),
+ DT_CLK(NULL, "gpio0_dbclk", "l4_wkup_cm:0004:18"),
+ DT_CLK(NULL, "gpio1_dbclk", "l4_per_cm:0098:18"),
+ DT_CLK(NULL, "gpio2_dbclk", "l4_per_cm:009c:18"),
+ DT_CLK(NULL, "gpio3_dbclk", "l4_per_cm:00a0:18"),
+ DT_CLK(NULL, "stm_clk_div_ck", "l4_wkup_cm:0010:27"),
+ DT_CLK(NULL, "stm_pmd_clock_mux_ck", "l4_wkup_cm:0010:22"),
+ DT_CLK(NULL, "trace_clk_div_ck", "l4_wkup_cm:0010:24"),
+ DT_CLK(NULL, "trace_pmd_clk_mux_ck", "l4_wkup_cm:0010:20"),
+ { .node_name = NULL },
+};
diff --git a/drivers/clk/ti/clk-33xx.c b/drivers/clk/ti/clk-33xx.c
index 12e0a2d19911..a360d3109555 100644
--- a/drivers/clk/ti/clk-33xx.c
+++ b/drivers/clk/ti/clk-33xx.c
@@ -24,7 +24,7 @@
#include "clock.h"
static const char * const am3_gpio1_dbclk_parents[] __initconst = {
- "l4_per_cm:clk:0138:0",
+ "clk-24mhz-clkctrl:0000:0",
NULL,
};
@@ -43,58 +43,86 @@ static const struct omap_clkctrl_bit_data am3_gpio4_bit_data[] __initconst = {
{ 0 },
};
-static const struct omap_clkctrl_reg_data am3_l4_per_clkctrl_regs[] __initconst = {
- { AM3_CPGMAC0_CLKCTRL, NULL, CLKF_SW_SUP, "cpsw_125mhz_gclk", "cpsw_125mhz_clkdm" },
- { AM3_LCDC_CLKCTRL, NULL, CLKF_SW_SUP | CLKF_SET_RATE_PARENT, "lcd_gclk", "lcdc_clkdm" },
- { AM3_USB_OTG_HS_CLKCTRL, NULL, CLKF_SW_SUP, "usbotg_fck", "l3s_clkdm" },
- { AM3_TPTC0_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" },
- { AM3_EMIF_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_ddr_m2_div2_ck", "l3_clkdm" },
- { AM3_OCMCRAM_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" },
- { AM3_GPMC_CLKCTRL, NULL, CLKF_SW_SUP, "l3s_gclk", "l3s_clkdm" },
- { AM3_MCASP0_CLKCTRL, NULL, CLKF_SW_SUP, "mcasp0_fck", "l3s_clkdm" },
- { AM3_UART6_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
- { AM3_MMC1_CLKCTRL, NULL, CLKF_SW_SUP, "mmc_clk" },
- { AM3_ELM_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
- { AM3_I2C3_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
- { AM3_I2C2_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
- { AM3_SPI0_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
- { AM3_SPI1_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
- { AM3_L4_LS_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
- { AM3_MCASP1_CLKCTRL, NULL, CLKF_SW_SUP, "mcasp1_fck", "l3s_clkdm" },
- { AM3_UART2_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
- { AM3_UART3_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
- { AM3_UART4_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
- { AM3_UART5_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
- { AM3_TIMER7_CLKCTRL, NULL, CLKF_SW_SUP, "timer7_fck" },
- { AM3_TIMER2_CLKCTRL, NULL, CLKF_SW_SUP, "timer2_fck" },
- { AM3_TIMER3_CLKCTRL, NULL, CLKF_SW_SUP, "timer3_fck" },
- { AM3_TIMER4_CLKCTRL, NULL, CLKF_SW_SUP, "timer4_fck" },
- { AM3_RNG_CLKCTRL, NULL, CLKF_SW_SUP, "rng_fck" },
- { AM3_AES_CLKCTRL, NULL, CLKF_SW_SUP, "aes0_fck", "l3_clkdm" },
- { AM3_SHAM_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" },
- { AM3_GPIO2_CLKCTRL, am3_gpio2_bit_data, CLKF_SW_SUP, "l4ls_gclk" },
- { AM3_GPIO3_CLKCTRL, am3_gpio3_bit_data, CLKF_SW_SUP, "l4ls_gclk" },
- { AM3_GPIO4_CLKCTRL, am3_gpio4_bit_data, CLKF_SW_SUP, "l4ls_gclk" },
- { AM3_TPCC_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" },
- { AM3_D_CAN0_CLKCTRL, NULL, CLKF_SW_SUP, "dcan0_fck" },
- { AM3_D_CAN1_CLKCTRL, NULL, CLKF_SW_SUP, "dcan1_fck" },
- { AM3_EPWMSS1_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
- { AM3_EPWMSS0_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
- { AM3_EPWMSS2_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
- { AM3_L3_INSTR_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" },
- { AM3_L3_MAIN_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" },
- { AM3_PRUSS_CLKCTRL, NULL, CLKF_SW_SUP, "pruss_ocp_gclk", "pruss_ocp_clkdm" },
- { AM3_TIMER5_CLKCTRL, NULL, CLKF_SW_SUP, "timer5_fck" },
- { AM3_TIMER6_CLKCTRL, NULL, CLKF_SW_SUP, "timer6_fck" },
- { AM3_MMC2_CLKCTRL, NULL, CLKF_SW_SUP, "mmc_clk" },
- { AM3_MMC3_CLKCTRL, NULL, CLKF_SW_SUP, "mmc_clk", "l3s_clkdm" },
- { AM3_TPTC1_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" },
- { AM3_TPTC2_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" },
- { AM3_SPINLOCK_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
- { AM3_MAILBOX_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
- { AM3_L4_HS_CLKCTRL, NULL, CLKF_SW_SUP, "l4hs_gclk", "l4hs_clkdm" },
- { AM3_OCPWP_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
- { AM3_CLKDIV32K_CLKCTRL, NULL, CLKF_SW_SUP, "clkdiv32k_ck", "clk_24mhz_clkdm" },
+static const struct omap_clkctrl_reg_data am3_l4ls_clkctrl_regs[] __initconst = {
+ { AM3_L4LS_UART6_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM3_L4LS_MMC1_CLKCTRL, NULL, CLKF_SW_SUP, "mmc_clk" },
+ { AM3_L4LS_ELM_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM3_L4LS_I2C3_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM3_L4LS_I2C2_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM3_L4LS_SPI0_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM3_L4LS_SPI1_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM3_L4LS_L4_LS_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM3_L4LS_UART2_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM3_L4LS_UART3_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM3_L4LS_UART4_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM3_L4LS_UART5_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM3_L4LS_TIMER7_CLKCTRL, NULL, CLKF_SW_SUP, "timer7_fck" },
+ { AM3_L4LS_TIMER2_CLKCTRL, NULL, CLKF_SW_SUP, "timer2_fck" },
+ { AM3_L4LS_TIMER3_CLKCTRL, NULL, CLKF_SW_SUP, "timer3_fck" },
+ { AM3_L4LS_TIMER4_CLKCTRL, NULL, CLKF_SW_SUP, "timer4_fck" },
+ { AM3_L4LS_RNG_CLKCTRL, NULL, CLKF_SW_SUP, "rng_fck" },
+ { AM3_L4LS_GPIO2_CLKCTRL, am3_gpio2_bit_data, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM3_L4LS_GPIO3_CLKCTRL, am3_gpio3_bit_data, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM3_L4LS_GPIO4_CLKCTRL, am3_gpio4_bit_data, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM3_L4LS_D_CAN0_CLKCTRL, NULL, CLKF_SW_SUP, "dcan0_fck" },
+ { AM3_L4LS_D_CAN1_CLKCTRL, NULL, CLKF_SW_SUP, "dcan1_fck" },
+ { AM3_L4LS_EPWMSS1_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM3_L4LS_EPWMSS0_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM3_L4LS_EPWMSS2_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM3_L4LS_TIMER5_CLKCTRL, NULL, CLKF_SW_SUP, "timer5_fck" },
+ { AM3_L4LS_TIMER6_CLKCTRL, NULL, CLKF_SW_SUP, "timer6_fck" },
+ { AM3_L4LS_MMC2_CLKCTRL, NULL, CLKF_SW_SUP, "mmc_clk" },
+ { AM3_L4LS_SPINLOCK_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM3_L4LS_MAILBOX_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM3_L4LS_OCPWP_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data am3_l3s_clkctrl_regs[] __initconst = {
+ { AM3_L3S_USB_OTG_HS_CLKCTRL, NULL, CLKF_SW_SUP, "usbotg_fck" },
+ { AM3_L3S_GPMC_CLKCTRL, NULL, CLKF_SW_SUP, "l3s_gclk" },
+ { AM3_L3S_MCASP0_CLKCTRL, NULL, CLKF_SW_SUP, "mcasp0_fck" },
+ { AM3_L3S_MCASP1_CLKCTRL, NULL, CLKF_SW_SUP, "mcasp1_fck" },
+ { AM3_L3S_MMC3_CLKCTRL, NULL, CLKF_SW_SUP, "mmc_clk" },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data am3_l3_clkctrl_regs[] __initconst = {
+ { AM3_L3_TPTC0_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk" },
+ { AM3_L3_EMIF_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_ddr_m2_div2_ck" },
+ { AM3_L3_OCMCRAM_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk" },
+ { AM3_L3_AES_CLKCTRL, NULL, CLKF_SW_SUP, "aes0_fck" },
+ { AM3_L3_SHAM_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk" },
+ { AM3_L3_TPCC_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk" },
+ { AM3_L3_L3_INSTR_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk" },
+ { AM3_L3_L3_MAIN_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk" },
+ { AM3_L3_TPTC1_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk" },
+ { AM3_L3_TPTC2_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk" },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data am3_l4hs_clkctrl_regs[] __initconst = {
+ { AM3_L4HS_L4_HS_CLKCTRL, NULL, CLKF_SW_SUP, "l4hs_gclk" },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data am3_pruss_ocp_clkctrl_regs[] __initconst = {
+ { AM3_PRUSS_OCP_PRUSS_CLKCTRL, NULL, CLKF_SW_SUP, "pruss_ocp_gclk" },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data am3_cpsw_125mhz_clkctrl_regs[] __initconst = {
+ { AM3_CPSW_125MHZ_CPGMAC0_CLKCTRL, NULL, CLKF_SW_SUP, "cpsw_125mhz_gclk" },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data am3_lcdc_clkctrl_regs[] __initconst = {
+ { AM3_LCDC_LCDC_CLKCTRL, NULL, CLKF_SW_SUP | CLKF_SET_RATE_PARENT, "lcd_gclk" },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data am3_clk_24mhz_clkctrl_regs[] __initconst = {
+ { AM3_CLK_24MHZ_CLKDIV32K_CLKCTRL, NULL, CLKF_SW_SUP, "clkdiv32k_ck" },
{ 0 },
};
@@ -108,19 +136,33 @@ static const struct omap_clkctrl_bit_data am3_gpio1_bit_data[] __initconst = {
{ 0 },
};
+static const struct omap_clkctrl_reg_data am3_l4_wkup_clkctrl_regs[] __initconst = {
+ { AM3_L4_WKUP_CONTROL_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_core_m4_div2_ck" },
+ { AM3_L4_WKUP_GPIO1_CLKCTRL, am3_gpio1_bit_data, CLKF_SW_SUP, "dpll_core_m4_div2_ck" },
+ { AM3_L4_WKUP_L4_WKUP_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_core_m4_div2_ck" },
+ { AM3_L4_WKUP_UART1_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_wkupdm_ck" },
+ { AM3_L4_WKUP_I2C1_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_wkupdm_ck" },
+ { AM3_L4_WKUP_ADC_TSC_CLKCTRL, NULL, CLKF_SW_SUP, "adc_tsc_fck" },
+ { AM3_L4_WKUP_SMARTREFLEX0_CLKCTRL, NULL, CLKF_SW_SUP, "smartreflex0_fck" },
+ { AM3_L4_WKUP_TIMER1_CLKCTRL, NULL, CLKF_SW_SUP, "timer1_fck" },
+ { AM3_L4_WKUP_SMARTREFLEX1_CLKCTRL, NULL, CLKF_SW_SUP, "smartreflex1_fck" },
+ { AM3_L4_WKUP_WD_TIMER2_CLKCTRL, NULL, CLKF_SW_SUP, "wdt1_fck" },
+ { 0 },
+};
+
static const char * const am3_dbg_sysclk_ck_parents[] __initconst = {
"sys_clkin_ck",
NULL,
};
static const char * const am3_trace_pmd_clk_mux_ck_parents[] __initconst = {
- "l4_wkup_cm:clk:0010:19",
- "l4_wkup_cm:clk:0010:30",
+ "l3-aon-clkctrl:0000:19",
+ "l3-aon-clkctrl:0000:30",
NULL,
};
static const char * const am3_trace_clk_div_ck_parents[] __initconst = {
- "l4_wkup_cm:clk:0010:20",
+ "l3-aon-clkctrl:0000:20",
NULL,
};
@@ -130,7 +172,7 @@ static const struct omap_clkctrl_div_data am3_trace_clk_div_ck_data __initconst
};
static const char * const am3_stm_clk_div_ck_parents[] __initconst = {
- "l4_wkup_cm:clk:0010:22",
+ "l3-aon-clkctrl:0000:22",
NULL,
};
@@ -154,66 +196,69 @@ static const struct omap_clkctrl_bit_data am3_debugss_bit_data[] __initconst = {
{ 0 },
};
-static const struct omap_clkctrl_reg_data am3_l4_wkup_clkctrl_regs[] __initconst = {
- { AM3_CONTROL_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_core_m4_div2_ck" },
- { AM3_GPIO1_CLKCTRL, am3_gpio1_bit_data, CLKF_SW_SUP, "dpll_core_m4_div2_ck" },
- { AM3_L4_WKUP_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_core_m4_div2_ck" },
- { AM3_DEBUGSS_CLKCTRL, am3_debugss_bit_data, CLKF_SW_SUP, "l4_wkup_cm:clk:0010:24", "l3_aon_clkdm" },
- { AM3_WKUP_M3_CLKCTRL, NULL, CLKF_NO_IDLEST, "dpll_core_m4_div2_ck", "l4_wkup_aon_clkdm" },
- { AM3_UART1_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_wkupdm_ck" },
- { AM3_I2C1_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_wkupdm_ck" },
- { AM3_ADC_TSC_CLKCTRL, NULL, CLKF_SW_SUP, "adc_tsc_fck" },
- { AM3_SMARTREFLEX0_CLKCTRL, NULL, CLKF_SW_SUP, "smartreflex0_fck" },
- { AM3_TIMER1_CLKCTRL, NULL, CLKF_SW_SUP, "timer1_fck" },
- { AM3_SMARTREFLEX1_CLKCTRL, NULL, CLKF_SW_SUP, "smartreflex1_fck" },
- { AM3_WD_TIMER2_CLKCTRL, NULL, CLKF_SW_SUP, "wdt1_fck" },
+static const struct omap_clkctrl_reg_data am3_l3_aon_clkctrl_regs[] __initconst = {
+ { AM3_L3_AON_DEBUGSS_CLKCTRL, am3_debugss_bit_data, CLKF_SW_SUP, "l3-aon-clkctrl:0000:24" },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data am3_l4_wkup_aon_clkctrl_regs[] __initconst = {
+ { AM3_L4_WKUP_AON_WKUP_M3_CLKCTRL, NULL, CLKF_NO_IDLEST, "dpll_core_m4_div2_ck" },
{ 0 },
};
static const struct omap_clkctrl_reg_data am3_mpu_clkctrl_regs[] __initconst = {
- { AM3_MPU_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_mpu_m2_ck" },
+ { AM3_MPU_MPU_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_mpu_m2_ck" },
{ 0 },
};
static const struct omap_clkctrl_reg_data am3_l4_rtc_clkctrl_regs[] __initconst = {
- { AM3_RTC_CLKCTRL, NULL, CLKF_SW_SUP, "clk_32768_ck" },
+ { AM3_L4_RTC_RTC_CLKCTRL, NULL, CLKF_SW_SUP, "clk_32768_ck" },
{ 0 },
};
static const struct omap_clkctrl_reg_data am3_gfx_l3_clkctrl_regs[] __initconst = {
- { AM3_GFX_CLKCTRL, NULL, CLKF_SW_SUP, "gfx_fck_div_ck" },
+ { AM3_GFX_L3_GFX_CLKCTRL, NULL, CLKF_SW_SUP, "gfx_fck_div_ck" },
{ 0 },
};
static const struct omap_clkctrl_reg_data am3_l4_cefuse_clkctrl_regs[] __initconst = {
- { AM3_CEFUSE_CLKCTRL, NULL, CLKF_SW_SUP, "sys_clkin_ck" },
+ { AM3_L4_CEFUSE_CEFUSE_CLKCTRL, NULL, CLKF_SW_SUP, "sys_clkin_ck" },
{ 0 },
};
const struct omap_clkctrl_data am3_clkctrl_data[] __initconst = {
- { 0x44e00014, am3_l4_per_clkctrl_regs },
- { 0x44e00404, am3_l4_wkup_clkctrl_regs },
- { 0x44e00604, am3_mpu_clkctrl_regs },
+ { 0x44e00038, am3_l4ls_clkctrl_regs },
+ { 0x44e0001c, am3_l3s_clkctrl_regs },
+ { 0x44e00024, am3_l3_clkctrl_regs },
+ { 0x44e00120, am3_l4hs_clkctrl_regs },
+ { 0x44e000e8, am3_pruss_ocp_clkctrl_regs },
+ { 0x44e00000, am3_cpsw_125mhz_clkctrl_regs },
+ { 0x44e00018, am3_lcdc_clkctrl_regs },
+ { 0x44e0014c, am3_clk_24mhz_clkctrl_regs },
+ { 0x44e00400, am3_l4_wkup_clkctrl_regs },
+ { 0x44e00414, am3_l3_aon_clkctrl_regs },
+ { 0x44e004b0, am3_l4_wkup_aon_clkctrl_regs },
+ { 0x44e00600, am3_mpu_clkctrl_regs },
{ 0x44e00800, am3_l4_rtc_clkctrl_regs },
- { 0x44e00904, am3_gfx_l3_clkctrl_regs },
- { 0x44e00a20, am3_l4_cefuse_clkctrl_regs },
+ { 0x44e00900, am3_gfx_l3_clkctrl_regs },
+ { 0x44e00a00, am3_l4_cefuse_clkctrl_regs },
{ 0 },
};
static struct ti_dt_clk am33xx_clks[] = {
- DT_CLK(NULL, "timer_32k_ck", "l4_per_cm:0138:0"),
+ DT_CLK(NULL, "timer_32k_ck", "clk-24mhz-clkctrl:0000:0"),
DT_CLK(NULL, "timer_sys_ck", "sys_clkin_ck"),
- DT_CLK(NULL, "clkdiv32k_ick", "l4_per_cm:0138:0"),
- DT_CLK(NULL, "dbg_clka_ck", "l4_wkup_cm:0010:30"),
- DT_CLK(NULL, "dbg_sysclk_ck", "l4_wkup_cm:0010:19"),
- DT_CLK(NULL, "gpio0_dbclk", "l4_wkup_cm:0004:18"),
- DT_CLK(NULL, "gpio1_dbclk", "l4_per_cm:0098:18"),
- DT_CLK(NULL, "gpio2_dbclk", "l4_per_cm:009c:18"),
- DT_CLK(NULL, "gpio3_dbclk", "l4_per_cm:00a0:18"),
- DT_CLK(NULL, "stm_clk_div_ck", "l4_wkup_cm:0010:27"),
- DT_CLK(NULL, "stm_pmd_clock_mux_ck", "l4_wkup_cm:0010:22"),
- DT_CLK(NULL, "trace_clk_div_ck", "l4_wkup_cm:0010:24"),
- DT_CLK(NULL, "trace_pmd_clk_mux_ck", "l4_wkup_cm:0010:20"),
+ DT_CLK(NULL, "clkdiv32k_ick", "clk-24mhz-clkctrl:0000:0"),
+ DT_CLK(NULL, "dbg_clka_ck", "l3-aon-clkctrl:0000:30"),
+ DT_CLK(NULL, "dbg_sysclk_ck", "l3-aon-clkctrl:0000:19"),
+ DT_CLK(NULL, "gpio0_dbclk", "l4-wkup-clkctrl:0008:18"),
+ DT_CLK(NULL, "gpio1_dbclk", "l4ls-clkctrl:0074:18"),
+ DT_CLK(NULL, "gpio2_dbclk", "l4ls-clkctrl:0078:18"),
+ DT_CLK(NULL, "gpio3_dbclk", "l4ls-clkctrl:007c:18"),
+ DT_CLK(NULL, "stm_clk_div_ck", "l3-aon-clkctrl:0000:27"),
+ DT_CLK(NULL, "stm_pmd_clock_mux_ck", "l3-aon-clkctrl:0000:22"),
+ DT_CLK(NULL, "trace_clk_div_ck", "l3-aon-clkctrl:0000:24"),
+ DT_CLK(NULL, "trace_pmd_clk_mux_ck", "l3-aon-clkctrl:0000:20"),
{ .node_name = NULL },
};
@@ -232,7 +277,10 @@ int __init am33xx_dt_clk_init(void)
{
struct clk *clk1, *clk2;
- ti_dt_clocks_register(am33xx_clks);
+ if (ti_clk_get_features()->flags & TI_CLK_CLKCTRL_COMPAT)
+ ti_dt_clocks_register(am33xx_compat_clks);
+ else
+ ti_dt_clocks_register(am33xx_clks);
omap2_clk_disable_autoidle_all();
diff --git a/drivers/clk/ti/clk-43xx-compat.c b/drivers/clk/ti/clk-43xx-compat.c
new file mode 100644
index 000000000000..513039843392
--- /dev/null
+++ b/drivers/clk/ti/clk-43xx-compat.c
@@ -0,0 +1,225 @@
+/*
+ * AM43XX Clock init
+ *
+ * Copyright (C) 2013 Texas Instruments, Inc
+ * Tero Kristo (t-kristo@ti.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clk/ti.h>
+#include <dt-bindings/clock/am4.h>
+
+#include "clock.h"
+
+static const char * const am4_synctimer_32kclk_parents[] __initconst = {
+ "mux_synctimer32k_ck",
+ NULL,
+};
+
+static const struct omap_clkctrl_bit_data am4_counter_32k_bit_data[] __initconst = {
+ { 8, TI_CLK_GATE, am4_synctimer_32kclk_parents, NULL },
+ { 0 },
+};
+
+static const char * const am4_gpio0_dbclk_parents[] __initconst = {
+ "gpio0_dbclk_mux_ck",
+ NULL,
+};
+
+static const struct omap_clkctrl_bit_data am4_gpio1_bit_data[] __initconst = {
+ { 8, TI_CLK_GATE, am4_gpio0_dbclk_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data am4_l4_wkup_clkctrl_regs[] __initconst = {
+ { AM4_ADC_TSC_CLKCTRL, NULL, CLKF_SW_SUP, "adc_tsc_fck", "l3s_tsc_clkdm" },
+ { AM4_L4_WKUP_CLKCTRL, NULL, CLKF_SW_SUP, "sys_clkin_ck", "l4_wkup_clkdm" },
+ { AM4_WKUP_M3_CLKCTRL, NULL, CLKF_NO_IDLEST, "sys_clkin_ck" },
+ { AM4_COUNTER_32K_CLKCTRL, am4_counter_32k_bit_data, CLKF_SW_SUP, "l4_wkup_cm:clk:0210:8" },
+ { AM4_TIMER1_CLKCTRL, NULL, CLKF_SW_SUP, "timer1_fck", "l4_wkup_clkdm" },
+ { AM4_WD_TIMER2_CLKCTRL, NULL, CLKF_SW_SUP, "wdt1_fck", "l4_wkup_clkdm" },
+ { AM4_I2C1_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_wkupdm_ck", "l4_wkup_clkdm" },
+ { AM4_UART1_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_wkupdm_ck", "l4_wkup_clkdm" },
+ { AM4_SMARTREFLEX0_CLKCTRL, NULL, CLKF_SW_SUP, "smartreflex0_fck", "l4_wkup_clkdm" },
+ { AM4_SMARTREFLEX1_CLKCTRL, NULL, CLKF_SW_SUP, "smartreflex1_fck", "l4_wkup_clkdm" },
+ { AM4_CONTROL_CLKCTRL, NULL, CLKF_SW_SUP, "sys_clkin_ck", "l4_wkup_clkdm" },
+ { AM4_GPIO1_CLKCTRL, am4_gpio1_bit_data, CLKF_SW_SUP, "sys_clkin_ck", "l4_wkup_clkdm" },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data am4_mpu_clkctrl_regs[] __initconst = {
+ { AM4_MPU_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_mpu_m2_ck" },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data am4_gfx_l3_clkctrl_regs[] __initconst = {
+ { AM4_GFX_CLKCTRL, NULL, CLKF_SW_SUP, "gfx_fck_div_ck" },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data am4_l4_rtc_clkctrl_regs[] __initconst = {
+ { AM4_RTC_CLKCTRL, NULL, CLKF_SW_SUP, "clk_32768_ck" },
+ { 0 },
+};
+
+static const char * const am4_usb_otg_ss0_refclk960m_parents[] __initconst = {
+ "dpll_per_clkdcoldo",
+ NULL,
+};
+
+static const struct omap_clkctrl_bit_data am4_usb_otg_ss0_bit_data[] __initconst = {
+ { 8, TI_CLK_GATE, am4_usb_otg_ss0_refclk960m_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data am4_usb_otg_ss1_bit_data[] __initconst = {
+ { 8, TI_CLK_GATE, am4_usb_otg_ss0_refclk960m_parents, NULL },
+ { 0 },
+};
+
+static const char * const am4_gpio1_dbclk_parents[] __initconst = {
+ "clkdiv32k_ick",
+ NULL,
+};
+
+static const struct omap_clkctrl_bit_data am4_gpio2_bit_data[] __initconst = {
+ { 8, TI_CLK_GATE, am4_gpio1_dbclk_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data am4_gpio3_bit_data[] __initconst = {
+ { 8, TI_CLK_GATE, am4_gpio1_dbclk_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data am4_gpio4_bit_data[] __initconst = {
+ { 8, TI_CLK_GATE, am4_gpio1_dbclk_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data am4_gpio5_bit_data[] __initconst = {
+ { 8, TI_CLK_GATE, am4_gpio1_dbclk_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data am4_gpio6_bit_data[] __initconst = {
+ { 8, TI_CLK_GATE, am4_gpio1_dbclk_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data am4_l4_per_clkctrl_regs[] __initconst = {
+ { AM4_L3_MAIN_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" },
+ { AM4_AES_CLKCTRL, NULL, CLKF_SW_SUP, "aes0_fck", "l3_clkdm" },
+ { AM4_DES_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" },
+ { AM4_L3_INSTR_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" },
+ { AM4_OCMCRAM_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" },
+ { AM4_SHAM_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" },
+ { AM4_VPFE0_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3s_clkdm" },
+ { AM4_VPFE1_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3s_clkdm" },
+ { AM4_TPCC_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" },
+ { AM4_TPTC0_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" },
+ { AM4_TPTC1_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" },
+ { AM4_TPTC2_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" },
+ { AM4_L4_HS_CLKCTRL, NULL, CLKF_SW_SUP, "l4hs_gclk", "l3_clkdm" },
+ { AM4_GPMC_CLKCTRL, NULL, CLKF_SW_SUP, "l3s_gclk", "l3s_clkdm" },
+ { AM4_MCASP0_CLKCTRL, NULL, CLKF_SW_SUP, "mcasp0_fck", "l3s_clkdm" },
+ { AM4_MCASP1_CLKCTRL, NULL, CLKF_SW_SUP, "mcasp1_fck", "l3s_clkdm" },
+ { AM4_MMC3_CLKCTRL, NULL, CLKF_SW_SUP, "mmc_clk", "l3s_clkdm" },
+ { AM4_QSPI_CLKCTRL, NULL, CLKF_SW_SUP, "l3s_gclk", "l3s_clkdm" },
+ { AM4_USB_OTG_SS0_CLKCTRL, am4_usb_otg_ss0_bit_data, CLKF_SW_SUP, "l3s_gclk", "l3s_clkdm" },
+ { AM4_USB_OTG_SS1_CLKCTRL, am4_usb_otg_ss1_bit_data, CLKF_SW_SUP, "l3s_gclk", "l3s_clkdm" },
+ { AM4_PRUSS_CLKCTRL, NULL, CLKF_SW_SUP, "pruss_ocp_gclk", "pruss_ocp_clkdm" },
+ { AM4_L4_LS_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM4_D_CAN0_CLKCTRL, NULL, CLKF_SW_SUP, "dcan0_fck" },
+ { AM4_D_CAN1_CLKCTRL, NULL, CLKF_SW_SUP, "dcan1_fck" },
+ { AM4_EPWMSS0_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM4_EPWMSS1_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM4_EPWMSS2_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM4_EPWMSS3_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM4_EPWMSS4_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM4_EPWMSS5_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM4_ELM_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM4_GPIO2_CLKCTRL, am4_gpio2_bit_data, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM4_GPIO3_CLKCTRL, am4_gpio3_bit_data, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM4_GPIO4_CLKCTRL, am4_gpio4_bit_data, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM4_GPIO5_CLKCTRL, am4_gpio5_bit_data, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM4_GPIO6_CLKCTRL, am4_gpio6_bit_data, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM4_HDQ1W_CLKCTRL, NULL, CLKF_SW_SUP, "func_12m_clk" },
+ { AM4_I2C2_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM4_I2C3_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM4_MAILBOX_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM4_MMC1_CLKCTRL, NULL, CLKF_SW_SUP, "mmc_clk" },
+ { AM4_MMC2_CLKCTRL, NULL, CLKF_SW_SUP, "mmc_clk" },
+ { AM4_RNG_CLKCTRL, NULL, CLKF_SW_SUP, "rng_fck" },
+ { AM4_SPI0_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM4_SPI1_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM4_SPI2_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM4_SPI3_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM4_SPI4_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM4_SPINLOCK_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM4_TIMER2_CLKCTRL, NULL, CLKF_SW_SUP, "timer2_fck" },
+ { AM4_TIMER3_CLKCTRL, NULL, CLKF_SW_SUP, "timer3_fck" },
+ { AM4_TIMER4_CLKCTRL, NULL, CLKF_SW_SUP, "timer4_fck" },
+ { AM4_TIMER5_CLKCTRL, NULL, CLKF_SW_SUP, "timer5_fck" },
+ { AM4_TIMER6_CLKCTRL, NULL, CLKF_SW_SUP, "timer6_fck" },
+ { AM4_TIMER7_CLKCTRL, NULL, CLKF_SW_SUP, "timer7_fck" },
+ { AM4_TIMER8_CLKCTRL, NULL, CLKF_SW_SUP, "timer8_fck" },
+ { AM4_TIMER9_CLKCTRL, NULL, CLKF_SW_SUP, "timer9_fck" },
+ { AM4_TIMER10_CLKCTRL, NULL, CLKF_SW_SUP, "timer10_fck" },
+ { AM4_TIMER11_CLKCTRL, NULL, CLKF_SW_SUP, "timer11_fck" },
+ { AM4_UART2_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM4_UART3_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM4_UART4_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM4_UART5_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM4_UART6_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM4_OCP2SCP0_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM4_OCP2SCP1_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM4_EMIF_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_ddr_m2_ck", "emif_clkdm" },
+ { AM4_DSS_CORE_CLKCTRL, NULL, CLKF_SW_SUP | CLKF_SET_RATE_PARENT, "disp_clk", "dss_clkdm" },
+ { AM4_CPGMAC0_CLKCTRL, NULL, CLKF_SW_SUP, "cpsw_125mhz_gclk", "cpsw_125mhz_clkdm" },
+ { 0 },
+};
+
+const struct omap_clkctrl_data am4_clkctrl_compat_data[] __initconst = {
+ { 0x44df2820, am4_l4_wkup_clkctrl_regs },
+ { 0x44df8320, am4_mpu_clkctrl_regs },
+ { 0x44df8420, am4_gfx_l3_clkctrl_regs },
+ { 0x44df8520, am4_l4_rtc_clkctrl_regs },
+ { 0x44df8820, am4_l4_per_clkctrl_regs },
+ { 0 },
+};
+
+const struct omap_clkctrl_data am438x_clkctrl_compat_data[] __initconst = {
+ { 0x44df2820, am4_l4_wkup_clkctrl_regs },
+ { 0x44df8320, am4_mpu_clkctrl_regs },
+ { 0x44df8420, am4_gfx_l3_clkctrl_regs },
+ { 0x44df8820, am4_l4_per_clkctrl_regs },
+ { 0 },
+};
+
+struct ti_dt_clk am43xx_compat_clks[] = {
+ DT_CLK(NULL, "timer_32k_ck", "clkdiv32k_ick"),
+ DT_CLK(NULL, "timer_sys_ck", "sys_clkin_ck"),
+ DT_CLK(NULL, "gpio0_dbclk", "l4_wkup_cm:0348:8"),
+ DT_CLK(NULL, "gpio1_dbclk", "l4_per_cm:0458:8"),
+ DT_CLK(NULL, "gpio2_dbclk", "l4_per_cm:0460:8"),
+ DT_CLK(NULL, "gpio3_dbclk", "l4_per_cm:0468:8"),
+ DT_CLK(NULL, "gpio4_dbclk", "l4_per_cm:0470:8"),
+ DT_CLK(NULL, "gpio5_dbclk", "l4_per_cm:0478:8"),
+ DT_CLK(NULL, "synctimer_32kclk", "l4_wkup_cm:0210:8"),
+ DT_CLK(NULL, "usb_otg_ss0_refclk960m", "l4_per_cm:0240:8"),
+ DT_CLK(NULL, "usb_otg_ss1_refclk960m", "l4_per_cm:0248:8"),
+ { .node_name = NULL },
+};
diff --git a/drivers/clk/ti/clk-43xx.c b/drivers/clk/ti/clk-43xx.c
index 63c5ddb50187..2782d91838ac 100644
--- a/drivers/clk/ti/clk-43xx.c
+++ b/drivers/clk/ti/clk-43xx.c
@@ -23,6 +23,11 @@
#include "clock.h"
+static const struct omap_clkctrl_reg_data am4_l3s_tsc_clkctrl_regs[] __initconst = {
+ { AM4_L3S_TSC_ADC_TSC_CLKCTRL, NULL, CLKF_SW_SUP, "adc_tsc_fck" },
+ { 0 },
+};
+
static const char * const am4_synctimer_32kclk_parents[] __initconst = {
"mux_synctimer32k_ck",
NULL,
@@ -33,6 +38,12 @@ static const struct omap_clkctrl_bit_data am4_counter_32k_bit_data[] __initconst
{ 0 },
};
+static const struct omap_clkctrl_reg_data am4_l4_wkup_aon_clkctrl_regs[] __initconst = {
+ { AM4_L4_WKUP_AON_WKUP_M3_CLKCTRL, NULL, CLKF_SW_SUP | CLKF_NO_IDLEST, "sys_clkin_ck" },
+ { AM4_L4_WKUP_AON_COUNTER_32K_CLKCTRL, am4_counter_32k_bit_data, CLKF_SW_SUP, "l4-wkup-aon-clkctrl:0008:8" },
+ { 0 },
+};
+
static const char * const am4_gpio0_dbclk_parents[] __initconst = {
"gpio0_dbclk_mux_ck",
NULL,
@@ -44,33 +55,45 @@ static const struct omap_clkctrl_bit_data am4_gpio1_bit_data[] __initconst = {
};
static const struct omap_clkctrl_reg_data am4_l4_wkup_clkctrl_regs[] __initconst = {
- { AM4_ADC_TSC_CLKCTRL, NULL, CLKF_SW_SUP, "adc_tsc_fck", "l3s_tsc_clkdm" },
- { AM4_L4_WKUP_CLKCTRL, NULL, CLKF_SW_SUP, "sys_clkin_ck", "l4_wkup_clkdm" },
- { AM4_WKUP_M3_CLKCTRL, NULL, CLKF_NO_IDLEST, "sys_clkin_ck" },
- { AM4_COUNTER_32K_CLKCTRL, am4_counter_32k_bit_data, CLKF_SW_SUP, "l4_wkup_cm:clk:0210:8" },
- { AM4_TIMER1_CLKCTRL, NULL, CLKF_SW_SUP, "timer1_fck", "l4_wkup_clkdm" },
- { AM4_WD_TIMER2_CLKCTRL, NULL, CLKF_SW_SUP, "wdt1_fck", "l4_wkup_clkdm" },
- { AM4_I2C1_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_wkupdm_ck", "l4_wkup_clkdm" },
- { AM4_UART1_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_wkupdm_ck", "l4_wkup_clkdm" },
- { AM4_SMARTREFLEX0_CLKCTRL, NULL, CLKF_SW_SUP, "smartreflex0_fck", "l4_wkup_clkdm" },
- { AM4_SMARTREFLEX1_CLKCTRL, NULL, CLKF_SW_SUP, "smartreflex1_fck", "l4_wkup_clkdm" },
- { AM4_CONTROL_CLKCTRL, NULL, CLKF_SW_SUP, "sys_clkin_ck", "l4_wkup_clkdm" },
- { AM4_GPIO1_CLKCTRL, am4_gpio1_bit_data, CLKF_SW_SUP, "sys_clkin_ck", "l4_wkup_clkdm" },
+ { AM4_L4_WKUP_L4_WKUP_CLKCTRL, NULL, CLKF_SW_SUP, "sys_clkin_ck" },
+ { AM4_L4_WKUP_TIMER1_CLKCTRL, NULL, CLKF_SW_SUP, "timer1_fck" },
+ { AM4_L4_WKUP_WD_TIMER2_CLKCTRL, NULL, CLKF_SW_SUP, "wdt1_fck" },
+ { AM4_L4_WKUP_I2C1_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_wkupdm_ck" },
+ { AM4_L4_WKUP_UART1_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_wkupdm_ck" },
+ { AM4_L4_WKUP_SMARTREFLEX0_CLKCTRL, NULL, CLKF_SW_SUP, "smartreflex0_fck" },
+ { AM4_L4_WKUP_SMARTREFLEX1_CLKCTRL, NULL, CLKF_SW_SUP, "smartreflex1_fck" },
+ { AM4_L4_WKUP_CONTROL_CLKCTRL, NULL, CLKF_SW_SUP, "sys_clkin_ck" },
+ { AM4_L4_WKUP_GPIO1_CLKCTRL, am4_gpio1_bit_data, CLKF_SW_SUP, "sys_clkin_ck" },
{ 0 },
};
static const struct omap_clkctrl_reg_data am4_mpu_clkctrl_regs[] __initconst = {
- { AM4_MPU_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_mpu_m2_ck" },
+ { AM4_MPU_MPU_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_mpu_m2_ck" },
{ 0 },
};
static const struct omap_clkctrl_reg_data am4_gfx_l3_clkctrl_regs[] __initconst = {
- { AM4_GFX_CLKCTRL, NULL, CLKF_SW_SUP, "gfx_fck_div_ck" },
+ { AM4_GFX_L3_GFX_CLKCTRL, NULL, CLKF_SW_SUP, "gfx_fck_div_ck" },
{ 0 },
};
static const struct omap_clkctrl_reg_data am4_l4_rtc_clkctrl_regs[] __initconst = {
- { AM4_RTC_CLKCTRL, NULL, CLKF_SW_SUP, "clk_32768_ck" },
+ { AM4_L4_RTC_RTC_CLKCTRL, NULL, CLKF_SW_SUP, "clk_32768_ck" },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data am4_l3_clkctrl_regs[] __initconst = {
+ { AM4_L3_L3_MAIN_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk" },
+ { AM4_L3_AES_CLKCTRL, NULL, CLKF_SW_SUP, "aes0_fck" },
+ { AM4_L3_DES_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk" },
+ { AM4_L3_L3_INSTR_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk" },
+ { AM4_L3_OCMCRAM_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk" },
+ { AM4_L3_SHAM_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk" },
+ { AM4_L3_TPCC_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk" },
+ { AM4_L3_TPTC0_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk" },
+ { AM4_L3_TPTC1_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk" },
+ { AM4_L3_TPTC2_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk" },
+ { AM4_L3_L4_HS_CLKCTRL, NULL, CLKF_SW_SUP, "l4hs_gclk" },
{ 0 },
};
@@ -89,6 +112,24 @@ static const struct omap_clkctrl_bit_data am4_usb_otg_ss1_bit_data[] __initconst
{ 0 },
};
+static const struct omap_clkctrl_reg_data am4_l3s_clkctrl_regs[] __initconst = {
+ { AM4_L3S_VPFE0_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk" },
+ { AM4_L3S_VPFE1_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk" },
+ { AM4_L3S_GPMC_CLKCTRL, NULL, CLKF_SW_SUP, "l3s_gclk" },
+ { AM4_L3S_MCASP0_CLKCTRL, NULL, CLKF_SW_SUP, "mcasp0_fck" },
+ { AM4_L3S_MCASP1_CLKCTRL, NULL, CLKF_SW_SUP, "mcasp1_fck" },
+ { AM4_L3S_MMC3_CLKCTRL, NULL, CLKF_SW_SUP, "mmc_clk" },
+ { AM4_L3S_QSPI_CLKCTRL, NULL, CLKF_SW_SUP, "l3s_gclk" },
+ { AM4_L3S_USB_OTG_SS0_CLKCTRL, am4_usb_otg_ss0_bit_data, CLKF_SW_SUP, "l3s_gclk" },
+ { AM4_L3S_USB_OTG_SS1_CLKCTRL, am4_usb_otg_ss1_bit_data, CLKF_SW_SUP, "l3s_gclk" },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data am4_pruss_ocp_clkctrl_regs[] __initconst = {
+ { AM4_PRUSS_OCP_PRUSS_CLKCTRL, NULL, CLKF_SW_SUP, "pruss_ocp_gclk" },
+ { 0 },
+};
+
static const char * const am4_gpio1_dbclk_parents[] __initconst = {
"clkdiv32k_ick",
NULL,
@@ -119,108 +160,115 @@ static const struct omap_clkctrl_bit_data am4_gpio6_bit_data[] __initconst = {
{ 0 },
};
-static const struct omap_clkctrl_reg_data am4_l4_per_clkctrl_regs[] __initconst = {
- { AM4_L3_MAIN_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" },
- { AM4_AES_CLKCTRL, NULL, CLKF_SW_SUP, "aes0_fck", "l3_clkdm" },
- { AM4_DES_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" },
- { AM4_L3_INSTR_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" },
- { AM4_OCMCRAM_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" },
- { AM4_SHAM_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" },
- { AM4_VPFE0_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3s_clkdm" },
- { AM4_VPFE1_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3s_clkdm" },
- { AM4_TPCC_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" },
- { AM4_TPTC0_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" },
- { AM4_TPTC1_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" },
- { AM4_TPTC2_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" },
- { AM4_L4_HS_CLKCTRL, NULL, CLKF_SW_SUP, "l4hs_gclk", "l3_clkdm" },
- { AM4_GPMC_CLKCTRL, NULL, CLKF_SW_SUP, "l3s_gclk", "l3s_clkdm" },
- { AM4_MCASP0_CLKCTRL, NULL, CLKF_SW_SUP, "mcasp0_fck", "l3s_clkdm" },
- { AM4_MCASP1_CLKCTRL, NULL, CLKF_SW_SUP, "mcasp1_fck", "l3s_clkdm" },
- { AM4_MMC3_CLKCTRL, NULL, CLKF_SW_SUP, "mmc_clk", "l3s_clkdm" },
- { AM4_QSPI_CLKCTRL, NULL, CLKF_SW_SUP, "l3s_gclk", "l3s_clkdm" },
- { AM4_USB_OTG_SS0_CLKCTRL, am4_usb_otg_ss0_bit_data, CLKF_SW_SUP, "l3s_gclk", "l3s_clkdm" },
- { AM4_USB_OTG_SS1_CLKCTRL, am4_usb_otg_ss1_bit_data, CLKF_SW_SUP, "l3s_gclk", "l3s_clkdm" },
- { AM4_PRUSS_CLKCTRL, NULL, CLKF_SW_SUP, "pruss_ocp_gclk", "pruss_ocp_clkdm" },
- { AM4_L4_LS_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
- { AM4_D_CAN0_CLKCTRL, NULL, CLKF_SW_SUP, "dcan0_fck" },
- { AM4_D_CAN1_CLKCTRL, NULL, CLKF_SW_SUP, "dcan1_fck" },
- { AM4_EPWMSS0_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
- { AM4_EPWMSS1_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
- { AM4_EPWMSS2_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
- { AM4_EPWMSS3_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
- { AM4_EPWMSS4_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
- { AM4_EPWMSS5_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
- { AM4_ELM_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
- { AM4_GPIO2_CLKCTRL, am4_gpio2_bit_data, CLKF_SW_SUP, "l4ls_gclk" },
- { AM4_GPIO3_CLKCTRL, am4_gpio3_bit_data, CLKF_SW_SUP, "l4ls_gclk" },
- { AM4_GPIO4_CLKCTRL, am4_gpio4_bit_data, CLKF_SW_SUP, "l4ls_gclk" },
- { AM4_GPIO5_CLKCTRL, am4_gpio5_bit_data, CLKF_SW_SUP, "l4ls_gclk" },
- { AM4_GPIO6_CLKCTRL, am4_gpio6_bit_data, CLKF_SW_SUP, "l4ls_gclk" },
- { AM4_HDQ1W_CLKCTRL, NULL, CLKF_SW_SUP, "func_12m_clk" },
- { AM4_I2C2_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
- { AM4_I2C3_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
- { AM4_MAILBOX_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
- { AM4_MMC1_CLKCTRL, NULL, CLKF_SW_SUP, "mmc_clk" },
- { AM4_MMC2_CLKCTRL, NULL, CLKF_SW_SUP, "mmc_clk" },
- { AM4_RNG_CLKCTRL, NULL, CLKF_SW_SUP, "rng_fck" },
- { AM4_SPI0_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
- { AM4_SPI1_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
- { AM4_SPI2_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
- { AM4_SPI3_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
- { AM4_SPI4_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
- { AM4_SPINLOCK_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
- { AM4_TIMER2_CLKCTRL, NULL, CLKF_SW_SUP, "timer2_fck" },
- { AM4_TIMER3_CLKCTRL, NULL, CLKF_SW_SUP, "timer3_fck" },
- { AM4_TIMER4_CLKCTRL, NULL, CLKF_SW_SUP, "timer4_fck" },
- { AM4_TIMER5_CLKCTRL, NULL, CLKF_SW_SUP, "timer5_fck" },
- { AM4_TIMER6_CLKCTRL, NULL, CLKF_SW_SUP, "timer6_fck" },
- { AM4_TIMER7_CLKCTRL, NULL, CLKF_SW_SUP, "timer7_fck" },
- { AM4_TIMER8_CLKCTRL, NULL, CLKF_SW_SUP, "timer8_fck" },
- { AM4_TIMER9_CLKCTRL, NULL, CLKF_SW_SUP, "timer9_fck" },
- { AM4_TIMER10_CLKCTRL, NULL, CLKF_SW_SUP, "timer10_fck" },
- { AM4_TIMER11_CLKCTRL, NULL, CLKF_SW_SUP, "timer11_fck" },
- { AM4_UART2_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
- { AM4_UART3_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
- { AM4_UART4_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
- { AM4_UART5_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
- { AM4_UART6_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
- { AM4_OCP2SCP0_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
- { AM4_OCP2SCP1_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
- { AM4_EMIF_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_ddr_m2_ck", "emif_clkdm" },
- { AM4_DSS_CORE_CLKCTRL, NULL, CLKF_SW_SUP | CLKF_SET_RATE_PARENT, "disp_clk", "dss_clkdm" },
- { AM4_CPGMAC0_CLKCTRL, NULL, CLKF_SW_SUP, "cpsw_125mhz_gclk", "cpsw_125mhz_clkdm" },
+static const struct omap_clkctrl_reg_data am4_l4ls_clkctrl_regs[] __initconst = {
+ { AM4_L4LS_L4_LS_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM4_L4LS_D_CAN0_CLKCTRL, NULL, CLKF_SW_SUP, "dcan0_fck" },
+ { AM4_L4LS_D_CAN1_CLKCTRL, NULL, CLKF_SW_SUP, "dcan1_fck" },
+ { AM4_L4LS_EPWMSS0_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM4_L4LS_EPWMSS1_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM4_L4LS_EPWMSS2_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM4_L4LS_EPWMSS3_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM4_L4LS_EPWMSS4_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM4_L4LS_EPWMSS5_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM4_L4LS_ELM_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM4_L4LS_GPIO2_CLKCTRL, am4_gpio2_bit_data, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM4_L4LS_GPIO3_CLKCTRL, am4_gpio3_bit_data, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM4_L4LS_GPIO4_CLKCTRL, am4_gpio4_bit_data, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM4_L4LS_GPIO5_CLKCTRL, am4_gpio5_bit_data, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM4_L4LS_GPIO6_CLKCTRL, am4_gpio6_bit_data, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM4_L4LS_HDQ1W_CLKCTRL, NULL, CLKF_SW_SUP, "func_12m_clk" },
+ { AM4_L4LS_I2C2_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM4_L4LS_I2C3_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM4_L4LS_MAILBOX_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM4_L4LS_MMC1_CLKCTRL, NULL, CLKF_SW_SUP, "mmc_clk" },
+ { AM4_L4LS_MMC2_CLKCTRL, NULL, CLKF_SW_SUP, "mmc_clk" },
+ { AM4_L4LS_RNG_CLKCTRL, NULL, CLKF_SW_SUP, "rng_fck" },
+ { AM4_L4LS_SPI0_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM4_L4LS_SPI1_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM4_L4LS_SPI2_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM4_L4LS_SPI3_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM4_L4LS_SPI4_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM4_L4LS_SPINLOCK_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM4_L4LS_TIMER2_CLKCTRL, NULL, CLKF_SW_SUP, "timer2_fck" },
+ { AM4_L4LS_TIMER3_CLKCTRL, NULL, CLKF_SW_SUP, "timer3_fck" },
+ { AM4_L4LS_TIMER4_CLKCTRL, NULL, CLKF_SW_SUP, "timer4_fck" },
+ { AM4_L4LS_TIMER5_CLKCTRL, NULL, CLKF_SW_SUP, "timer5_fck" },
+ { AM4_L4LS_TIMER6_CLKCTRL, NULL, CLKF_SW_SUP, "timer6_fck" },
+ { AM4_L4LS_TIMER7_CLKCTRL, NULL, CLKF_SW_SUP, "timer7_fck" },
+ { AM4_L4LS_TIMER8_CLKCTRL, NULL, CLKF_SW_SUP, "timer8_fck" },
+ { AM4_L4LS_TIMER9_CLKCTRL, NULL, CLKF_SW_SUP, "timer9_fck" },
+ { AM4_L4LS_TIMER10_CLKCTRL, NULL, CLKF_SW_SUP, "timer10_fck" },
+ { AM4_L4LS_TIMER11_CLKCTRL, NULL, CLKF_SW_SUP, "timer11_fck" },
+ { AM4_L4LS_UART2_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM4_L4LS_UART3_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM4_L4LS_UART4_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM4_L4LS_UART5_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM4_L4LS_UART6_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" },
+ { AM4_L4LS_OCP2SCP0_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { AM4_L4LS_OCP2SCP1_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data am4_emif_clkctrl_regs[] __initconst = {
+ { AM4_EMIF_EMIF_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_ddr_m2_ck" },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data am4_dss_clkctrl_regs[] __initconst = {
+ { AM4_DSS_DSS_CORE_CLKCTRL, NULL, CLKF_SW_SUP | CLKF_SET_RATE_PARENT, "disp_clk" },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data am4_cpsw_125mhz_clkctrl_regs[] __initconst = {
+ { AM4_CPSW_125MHZ_CPGMAC0_CLKCTRL, NULL, CLKF_SW_SUP, "cpsw_125mhz_gclk" },
{ 0 },
};
const struct omap_clkctrl_data am4_clkctrl_data[] __initconst = {
- { 0x44df2820, am4_l4_wkup_clkctrl_regs },
+ { 0x44df2920, am4_l3s_tsc_clkctrl_regs },
+ { 0x44df2a28, am4_l4_wkup_aon_clkctrl_regs },
+ { 0x44df2a20, am4_l4_wkup_clkctrl_regs },
{ 0x44df8320, am4_mpu_clkctrl_regs },
{ 0x44df8420, am4_gfx_l3_clkctrl_regs },
{ 0x44df8520, am4_l4_rtc_clkctrl_regs },
- { 0x44df8820, am4_l4_per_clkctrl_regs },
+ { 0x44df8820, am4_l3_clkctrl_regs },
+ { 0x44df8868, am4_l3s_clkctrl_regs },
+ { 0x44df8b20, am4_pruss_ocp_clkctrl_regs },
+ { 0x44df8c20, am4_l4ls_clkctrl_regs },
+ { 0x44df8f20, am4_emif_clkctrl_regs },
+ { 0x44df9220, am4_dss_clkctrl_regs },
+ { 0x44df9320, am4_cpsw_125mhz_clkctrl_regs },
{ 0 },
};
const struct omap_clkctrl_data am438x_clkctrl_data[] __initconst = {
- { 0x44df2820, am4_l4_wkup_clkctrl_regs },
+ { 0x44df2920, am4_l3s_tsc_clkctrl_regs },
+ { 0x44df2a28, am4_l4_wkup_aon_clkctrl_regs },
+ { 0x44df2a20, am4_l4_wkup_clkctrl_regs },
{ 0x44df8320, am4_mpu_clkctrl_regs },
{ 0x44df8420, am4_gfx_l3_clkctrl_regs },
- { 0x44df8820, am4_l4_per_clkctrl_regs },
+ { 0x44df8820, am4_l3_clkctrl_regs },
+ { 0x44df8868, am4_l3s_clkctrl_regs },
+ { 0x44df8b20, am4_pruss_ocp_clkctrl_regs },
+ { 0x44df8c20, am4_l4ls_clkctrl_regs },
+ { 0x44df8f20, am4_emif_clkctrl_regs },
+ { 0x44df9220, am4_dss_clkctrl_regs },
+ { 0x44df9320, am4_cpsw_125mhz_clkctrl_regs },
{ 0 },
};
static struct ti_dt_clk am43xx_clks[] = {
DT_CLK(NULL, "timer_32k_ck", "clkdiv32k_ick"),
DT_CLK(NULL, "timer_sys_ck", "sys_clkin_ck"),
- DT_CLK(NULL, "gpio0_dbclk", "l4_wkup_cm:0348:8"),
- DT_CLK(NULL, "gpio1_dbclk", "l4_per_cm:0458:8"),
- DT_CLK(NULL, "gpio2_dbclk", "l4_per_cm:0460:8"),
- DT_CLK(NULL, "gpio3_dbclk", "l4_per_cm:0468:8"),
- DT_CLK(NULL, "gpio4_dbclk", "l4_per_cm:0470:8"),
- DT_CLK(NULL, "gpio5_dbclk", "l4_per_cm:0478:8"),
- DT_CLK(NULL, "synctimer_32kclk", "l4_wkup_cm:0210:8"),
- DT_CLK(NULL, "usb_otg_ss0_refclk960m", "l4_per_cm:0240:8"),
- DT_CLK(NULL, "usb_otg_ss1_refclk960m", "l4_per_cm:0248:8"),
+ DT_CLK(NULL, "gpio0_dbclk", "l4-wkup-clkctrl:0148:8"),
+ DT_CLK(NULL, "gpio1_dbclk", "l4ls-clkctrl:0058:8"),
+ DT_CLK(NULL, "gpio2_dbclk", "l4ls-clkctrl:0060:8"),
+ DT_CLK(NULL, "gpio3_dbclk", "l4ls-clkctrl:0068:8"),
+ DT_CLK(NULL, "gpio4_dbclk", "l4ls-clkctrl:0070:8"),
+ DT_CLK(NULL, "gpio5_dbclk", "l4ls-clkctrl:0078:8"),
+ DT_CLK(NULL, "synctimer_32kclk", "l4-wkup-aon-clkctrl:0008:8"),
+ DT_CLK(NULL, "usb_otg_ss0_refclk960m", "l3s-clkctrl:01f8:8"),
+ DT_CLK(NULL, "usb_otg_ss1_refclk960m", "l3s-clkctrl:0200:8"),
{ .node_name = NULL },
};
@@ -228,7 +276,10 @@ int __init am43xx_dt_clk_init(void)
{
struct clk *clk1, *clk2;
- ti_dt_clocks_register(am43xx_clks);
+ if (ti_clk_get_features()->flags & TI_CLK_CLKCTRL_COMPAT)
+ ti_dt_clocks_register(am43xx_compat_clks);
+ else
+ ti_dt_clocks_register(am43xx_clks);
omap2_clk_disable_autoidle_all();
diff --git a/drivers/clk/ti/clk-7xx-compat.c b/drivers/clk/ti/clk-7xx-compat.c
new file mode 100644
index 000000000000..e3cb7f0b03ae
--- /dev/null
+++ b/drivers/clk/ti/clk-7xx-compat.c
@@ -0,0 +1,823 @@
+/*
+ * DRA7 Clock init
+ *
+ * Copyright (C) 2013 Texas Instruments, Inc.
+ *
+ * Tero Kristo (t-kristo@ti.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk/ti.h>
+#include <dt-bindings/clock/dra7.h>
+
+#include "clock.h"
+
+#define DRA7_DPLL_GMAC_DEFFREQ 1000000000
+#define DRA7_DPLL_USB_DEFFREQ 960000000
+
+static const struct omap_clkctrl_reg_data dra7_mpu_clkctrl_regs[] __initconst = {
+ { DRA7_MPU_CLKCTRL, NULL, 0, "dpll_mpu_m2_ck" },
+ { 0 },
+};
+
+static const char * const dra7_mcasp1_aux_gfclk_mux_parents[] __initconst = {
+ "per_abe_x1_gfclk2_div",
+ "video1_clk2_div",
+ "video2_clk2_div",
+ "hdmi_clk2_div",
+ NULL,
+};
+
+static const char * const dra7_mcasp1_ahclkx_mux_parents[] __initconst = {
+ "abe_24m_fclk",
+ "abe_sys_clk_div",
+ "func_24m_clk",
+ "atl_clkin3_ck",
+ "atl_clkin2_ck",
+ "atl_clkin1_ck",
+ "atl_clkin0_ck",
+ "sys_clkin2",
+ "ref_clkin0_ck",
+ "ref_clkin1_ck",
+ "ref_clkin2_ck",
+ "ref_clkin3_ck",
+ "mlb_clk",
+ "mlbp_clk",
+ NULL,
+};
+
+static const struct omap_clkctrl_bit_data dra7_mcasp1_bit_data[] __initconst = {
+ { 22, TI_CLK_MUX, dra7_mcasp1_aux_gfclk_mux_parents, NULL },
+ { 24, TI_CLK_MUX, dra7_mcasp1_ahclkx_mux_parents, NULL },
+ { 28, TI_CLK_MUX, dra7_mcasp1_ahclkx_mux_parents, NULL },
+ { 0 },
+};
+
+static const char * const dra7_timer5_gfclk_mux_parents[] __initconst = {
+ "timer_sys_clk_div",
+ "sys_32k_ck",
+ "sys_clkin2",
+ "ref_clkin0_ck",
+ "ref_clkin1_ck",
+ "ref_clkin2_ck",
+ "ref_clkin3_ck",
+ "abe_giclk_div",
+ "video1_div_clk",
+ "video2_div_clk",
+ "hdmi_div_clk",
+ "clkoutmux0_clk_mux",
+ NULL,
+};
+
+static const struct omap_clkctrl_bit_data dra7_timer5_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_timer5_gfclk_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_timer6_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_timer5_gfclk_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_timer7_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_timer5_gfclk_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_timer8_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_timer5_gfclk_mux_parents, NULL },
+ { 0 },
+};
+
+static const char * const dra7_uart6_gfclk_mux_parents[] __initconst = {
+ "func_48m_fclk",
+ "dpll_per_m2x2_ck",
+ NULL,
+};
+
+static const struct omap_clkctrl_bit_data dra7_uart6_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_uart6_gfclk_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data dra7_ipu_clkctrl_regs[] __initconst = {
+ { DRA7_MCASP1_CLKCTRL, dra7_mcasp1_bit_data, CLKF_SW_SUP, "ipu_cm:clk:0010:22" },
+ { DRA7_TIMER5_CLKCTRL, dra7_timer5_bit_data, CLKF_SW_SUP, "ipu_cm:clk:0018:24" },
+ { DRA7_TIMER6_CLKCTRL, dra7_timer6_bit_data, CLKF_SW_SUP, "ipu_cm:clk:0020:24" },
+ { DRA7_TIMER7_CLKCTRL, dra7_timer7_bit_data, CLKF_SW_SUP, "ipu_cm:clk:0028:24" },
+ { DRA7_TIMER8_CLKCTRL, dra7_timer8_bit_data, CLKF_SW_SUP, "ipu_cm:clk:0030:24" },
+ { DRA7_I2C5_CLKCTRL, NULL, CLKF_SW_SUP, "func_96m_fclk" },
+ { DRA7_UART6_CLKCTRL, dra7_uart6_bit_data, CLKF_SW_SUP, "ipu_cm:clk:0040:24" },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data dra7_rtc_clkctrl_regs[] __initconst = {
+ { DRA7_RTCSS_CLKCTRL, NULL, CLKF_SW_SUP, "sys_32k_ck" },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data dra7_coreaon_clkctrl_regs[] __initconst = {
+ { DRA7_SMARTREFLEX_MPU_CLKCTRL, NULL, CLKF_SW_SUP, "wkupaon_iclk_mux" },
+ { DRA7_SMARTREFLEX_CORE_CLKCTRL, NULL, CLKF_SW_SUP, "wkupaon_iclk_mux" },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data dra7_l3main1_clkctrl_regs[] __initconst = {
+ { DRA7_L3_MAIN_1_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_GPMC_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" },
+ { DRA7_TPCC_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_TPTC0_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" },
+ { DRA7_TPTC1_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" },
+ { DRA7_VCP1_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_VCP2_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data dra7_dma_clkctrl_regs[] __initconst = {
+ { DRA7_DMA_SYSTEM_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data dra7_emif_clkctrl_regs[] __initconst = {
+ { DRA7_DMM_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { 0 },
+};
+
+static const char * const dra7_atl_dpll_clk_mux_parents[] __initconst = {
+ "sys_32k_ck",
+ "video1_clkin_ck",
+ "video2_clkin_ck",
+ "hdmi_clkin_ck",
+ NULL,
+};
+
+static const char * const dra7_atl_gfclk_mux_parents[] __initconst = {
+ "l3_iclk_div",
+ "dpll_abe_m2_ck",
+ "atl_cm:clk:0000:24",
+ NULL,
+};
+
+static const struct omap_clkctrl_bit_data dra7_atl_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_atl_dpll_clk_mux_parents, NULL },
+ { 26, TI_CLK_MUX, dra7_atl_gfclk_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data dra7_atl_clkctrl_regs[] __initconst = {
+ { DRA7_ATL_CLKCTRL, dra7_atl_bit_data, CLKF_SW_SUP, "atl_cm:clk:0000:26" },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data dra7_l4cfg_clkctrl_regs[] __initconst = {
+ { DRA7_L4_CFG_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_SPINLOCK_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_MAILBOX1_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_MAILBOX2_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_MAILBOX3_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_MAILBOX4_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_MAILBOX5_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_MAILBOX6_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_MAILBOX7_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_MAILBOX8_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_MAILBOX9_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_MAILBOX10_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_MAILBOX11_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_MAILBOX12_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_MAILBOX13_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data dra7_l3instr_clkctrl_regs[] __initconst = {
+ { DRA7_L3_MAIN_2_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" },
+ { DRA7_L3_INSTR_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" },
+ { 0 },
+};
+
+static const char * const dra7_dss_dss_clk_parents[] __initconst = {
+ "dpll_per_h12x2_ck",
+ NULL,
+};
+
+static const char * const dra7_dss_48mhz_clk_parents[] __initconst = {
+ "func_48m_fclk",
+ NULL,
+};
+
+static const char * const dra7_dss_hdmi_clk_parents[] __initconst = {
+ "hdmi_dpll_clk_mux",
+ NULL,
+};
+
+static const char * const dra7_dss_32khz_clk_parents[] __initconst = {
+ "sys_32k_ck",
+ NULL,
+};
+
+static const char * const dra7_dss_video1_clk_parents[] __initconst = {
+ "video1_dpll_clk_mux",
+ NULL,
+};
+
+static const char * const dra7_dss_video2_clk_parents[] __initconst = {
+ "video2_dpll_clk_mux",
+ NULL,
+};
+
+static const struct omap_clkctrl_bit_data dra7_dss_core_bit_data[] __initconst = {
+ { 8, TI_CLK_GATE, dra7_dss_dss_clk_parents, NULL },
+ { 9, TI_CLK_GATE, dra7_dss_48mhz_clk_parents, NULL },
+ { 10, TI_CLK_GATE, dra7_dss_hdmi_clk_parents, NULL },
+ { 11, TI_CLK_GATE, dra7_dss_32khz_clk_parents, NULL },
+ { 12, TI_CLK_GATE, dra7_dss_video1_clk_parents, NULL },
+ { 13, TI_CLK_GATE, dra7_dss_video2_clk_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data dra7_dss_clkctrl_regs[] __initconst = {
+ { DRA7_DSS_CORE_CLKCTRL, dra7_dss_core_bit_data, CLKF_SW_SUP, "dss_cm:clk:0000:8" },
+ { DRA7_BB2D_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_core_h24x2_ck" },
+ { 0 },
+};
+
+static const char * const dra7_mmc1_fclk_mux_parents[] __initconst = {
+ "func_128m_clk",
+ "dpll_per_m2x2_ck",
+ NULL,
+};
+
+static const char * const dra7_mmc1_fclk_div_parents[] __initconst = {
+ "l3init_cm:clk:0008:24",
+ NULL,
+};
+
+static const struct omap_clkctrl_div_data dra7_mmc1_fclk_div_data __initconst = {
+ .max_div = 4,
+ .flags = CLK_DIVIDER_POWER_OF_TWO,
+};
+
+static const struct omap_clkctrl_bit_data dra7_mmc1_bit_data[] __initconst = {
+ { 8, TI_CLK_GATE, dra7_dss_32khz_clk_parents, NULL },
+ { 24, TI_CLK_MUX, dra7_mmc1_fclk_mux_parents, NULL },
+ { 25, TI_CLK_DIVIDER, dra7_mmc1_fclk_div_parents, &dra7_mmc1_fclk_div_data },
+ { 0 },
+};
+
+static const char * const dra7_mmc2_fclk_div_parents[] __initconst = {
+ "l3init_cm:clk:0010:24",
+ NULL,
+};
+
+static const struct omap_clkctrl_div_data dra7_mmc2_fclk_div_data __initconst = {
+ .max_div = 4,
+ .flags = CLK_DIVIDER_POWER_OF_TWO,
+};
+
+static const struct omap_clkctrl_bit_data dra7_mmc2_bit_data[] __initconst = {
+ { 8, TI_CLK_GATE, dra7_dss_32khz_clk_parents, NULL },
+ { 24, TI_CLK_MUX, dra7_mmc1_fclk_mux_parents, NULL },
+ { 25, TI_CLK_DIVIDER, dra7_mmc2_fclk_div_parents, &dra7_mmc2_fclk_div_data },
+ { 0 },
+};
+
+static const char * const dra7_usb_otg_ss2_refclk960m_parents[] __initconst = {
+ "l3init_960m_gfclk",
+ NULL,
+};
+
+static const struct omap_clkctrl_bit_data dra7_usb_otg_ss2_bit_data[] __initconst = {
+ { 8, TI_CLK_GATE, dra7_usb_otg_ss2_refclk960m_parents, NULL },
+ { 0 },
+};
+
+static const char * const dra7_sata_ref_clk_parents[] __initconst = {
+ "sys_clkin1",
+ NULL,
+};
+
+static const struct omap_clkctrl_bit_data dra7_sata_bit_data[] __initconst = {
+ { 8, TI_CLK_GATE, dra7_sata_ref_clk_parents, NULL },
+ { 0 },
+};
+
+static const char * const dra7_optfclk_pciephy1_clk_parents[] __initconst = {
+ "apll_pcie_ck",
+ NULL,
+};
+
+static const char * const dra7_optfclk_pciephy1_div_clk_parents[] __initconst = {
+ "optfclk_pciephy_div",
+ NULL,
+};
+
+static const struct omap_clkctrl_bit_data dra7_pcie1_bit_data[] __initconst = {
+ { 8, TI_CLK_GATE, dra7_dss_32khz_clk_parents, NULL },
+ { 9, TI_CLK_GATE, dra7_optfclk_pciephy1_clk_parents, NULL },
+ { 10, TI_CLK_GATE, dra7_optfclk_pciephy1_div_clk_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_pcie2_bit_data[] __initconst = {
+ { 8, TI_CLK_GATE, dra7_dss_32khz_clk_parents, NULL },
+ { 9, TI_CLK_GATE, dra7_optfclk_pciephy1_clk_parents, NULL },
+ { 10, TI_CLK_GATE, dra7_optfclk_pciephy1_div_clk_parents, NULL },
+ { 0 },
+};
+
+static const char * const dra7_rmii_50mhz_clk_mux_parents[] __initconst = {
+ "dpll_gmac_h11x2_ck",
+ "rmii_clk_ck",
+ NULL,
+};
+
+static const char * const dra7_gmac_rft_clk_mux_parents[] __initconst = {
+ "video1_clkin_ck",
+ "video2_clkin_ck",
+ "dpll_abe_m2_ck",
+ "hdmi_clkin_ck",
+ "l3_iclk_div",
+ NULL,
+};
+
+static const struct omap_clkctrl_bit_data dra7_gmac_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_rmii_50mhz_clk_mux_parents, NULL },
+ { 25, TI_CLK_MUX, dra7_gmac_rft_clk_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_usb_otg_ss1_bit_data[] __initconst = {
+ { 8, TI_CLK_GATE, dra7_usb_otg_ss2_refclk960m_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data dra7_l3init_clkctrl_regs[] __initconst = {
+ { DRA7_MMC1_CLKCTRL, dra7_mmc1_bit_data, CLKF_SW_SUP, "l3init_cm:clk:0008:25" },
+ { DRA7_MMC2_CLKCTRL, dra7_mmc2_bit_data, CLKF_SW_SUP, "l3init_cm:clk:0010:25" },
+ { DRA7_USB_OTG_SS2_CLKCTRL, dra7_usb_otg_ss2_bit_data, CLKF_HW_SUP, "dpll_core_h13x2_ck" },
+ { DRA7_USB_OTG_SS3_CLKCTRL, NULL, CLKF_HW_SUP, "dpll_core_h13x2_ck" },
+ { DRA7_USB_OTG_SS4_CLKCTRL, NULL, CLKF_HW_SUP, "dpll_core_h13x2_ck" },
+ { DRA7_SATA_CLKCTRL, dra7_sata_bit_data, CLKF_SW_SUP, "func_48m_fclk" },
+ { DRA7_PCIE1_CLKCTRL, dra7_pcie1_bit_data, CLKF_SW_SUP, "l4_root_clk_div", "pcie_clkdm" },
+ { DRA7_PCIE2_CLKCTRL, dra7_pcie2_bit_data, CLKF_SW_SUP, "l4_root_clk_div", "pcie_clkdm" },
+ { DRA7_GMAC_CLKCTRL, dra7_gmac_bit_data, CLKF_SW_SUP, "dpll_gmac_ck", "gmac_clkdm" },
+ { DRA7_OCP2SCP1_CLKCTRL, NULL, CLKF_HW_SUP, "l4_root_clk_div" },
+ { DRA7_OCP2SCP3_CLKCTRL, NULL, CLKF_HW_SUP, "l4_root_clk_div" },
+ { DRA7_USB_OTG_SS1_CLKCTRL, dra7_usb_otg_ss1_bit_data, CLKF_HW_SUP, "dpll_core_h13x2_ck" },
+ { 0 },
+};
+
+static const char * const dra7_timer10_gfclk_mux_parents[] __initconst = {
+ "timer_sys_clk_div",
+ "sys_32k_ck",
+ "sys_clkin2",
+ "ref_clkin0_ck",
+ "ref_clkin1_ck",
+ "ref_clkin2_ck",
+ "ref_clkin3_ck",
+ "abe_giclk_div",
+ "video1_div_clk",
+ "video2_div_clk",
+ "hdmi_div_clk",
+ NULL,
+};
+
+static const struct omap_clkctrl_bit_data dra7_timer10_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_timer10_gfclk_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_timer11_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_timer10_gfclk_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_timer2_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_timer10_gfclk_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_timer3_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_timer10_gfclk_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_timer4_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_timer10_gfclk_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_timer9_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_timer10_gfclk_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_gpio2_bit_data[] __initconst = {
+ { 8, TI_CLK_GATE, dra7_dss_32khz_clk_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_gpio3_bit_data[] __initconst = {
+ { 8, TI_CLK_GATE, dra7_dss_32khz_clk_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_gpio4_bit_data[] __initconst = {
+ { 8, TI_CLK_GATE, dra7_dss_32khz_clk_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_gpio5_bit_data[] __initconst = {
+ { 8, TI_CLK_GATE, dra7_dss_32khz_clk_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_gpio6_bit_data[] __initconst = {
+ { 8, TI_CLK_GATE, dra7_dss_32khz_clk_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_timer13_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_timer10_gfclk_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_timer14_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_timer10_gfclk_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_timer15_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_timer10_gfclk_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_gpio7_bit_data[] __initconst = {
+ { 8, TI_CLK_GATE, dra7_dss_32khz_clk_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_gpio8_bit_data[] __initconst = {
+ { 8, TI_CLK_GATE, dra7_dss_32khz_clk_parents, NULL },
+ { 0 },
+};
+
+static const char * const dra7_mmc3_gfclk_div_parents[] __initconst = {
+ "l4per_cm:clk:0120:24",
+ NULL,
+};
+
+static const struct omap_clkctrl_div_data dra7_mmc3_gfclk_div_data __initconst = {
+ .max_div = 4,
+ .flags = CLK_DIVIDER_POWER_OF_TWO,
+};
+
+static const struct omap_clkctrl_bit_data dra7_mmc3_bit_data[] __initconst = {
+ { 8, TI_CLK_GATE, dra7_dss_32khz_clk_parents, NULL },
+ { 24, TI_CLK_MUX, dra7_uart6_gfclk_mux_parents, NULL },
+ { 25, TI_CLK_DIVIDER, dra7_mmc3_gfclk_div_parents, &dra7_mmc3_gfclk_div_data },
+ { 0 },
+};
+
+static const char * const dra7_mmc4_gfclk_div_parents[] __initconst = {
+ "l4per_cm:clk:0128:24",
+ NULL,
+};
+
+static const struct omap_clkctrl_div_data dra7_mmc4_gfclk_div_data __initconst = {
+ .max_div = 4,
+ .flags = CLK_DIVIDER_POWER_OF_TWO,
+};
+
+static const struct omap_clkctrl_bit_data dra7_mmc4_bit_data[] __initconst = {
+ { 8, TI_CLK_GATE, dra7_dss_32khz_clk_parents, NULL },
+ { 24, TI_CLK_MUX, dra7_uart6_gfclk_mux_parents, NULL },
+ { 25, TI_CLK_DIVIDER, dra7_mmc4_gfclk_div_parents, &dra7_mmc4_gfclk_div_data },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_timer16_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_timer10_gfclk_mux_parents, NULL },
+ { 0 },
+};
+
+static const char * const dra7_qspi_gfclk_mux_parents[] __initconst = {
+ "func_128m_clk",
+ "dpll_per_h13x2_ck",
+ NULL,
+};
+
+static const char * const dra7_qspi_gfclk_div_parents[] __initconst = {
+ "l4per_cm:clk:0138:24",
+ NULL,
+};
+
+static const struct omap_clkctrl_div_data dra7_qspi_gfclk_div_data __initconst = {
+ .max_div = 4,
+ .flags = CLK_DIVIDER_POWER_OF_TWO,
+};
+
+static const struct omap_clkctrl_bit_data dra7_qspi_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_qspi_gfclk_mux_parents, NULL },
+ { 25, TI_CLK_DIVIDER, dra7_qspi_gfclk_div_parents, &dra7_qspi_gfclk_div_data },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_uart1_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_uart6_gfclk_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_uart2_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_uart6_gfclk_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_uart3_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_uart6_gfclk_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_uart4_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_uart6_gfclk_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_mcasp2_bit_data[] __initconst = {
+ { 22, TI_CLK_MUX, dra7_mcasp1_aux_gfclk_mux_parents, NULL },
+ { 24, TI_CLK_MUX, dra7_mcasp1_ahclkx_mux_parents, NULL },
+ { 28, TI_CLK_MUX, dra7_mcasp1_ahclkx_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_mcasp3_bit_data[] __initconst = {
+ { 22, TI_CLK_MUX, dra7_mcasp1_aux_gfclk_mux_parents, NULL },
+ { 24, TI_CLK_MUX, dra7_mcasp1_ahclkx_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_uart5_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_uart6_gfclk_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_mcasp5_bit_data[] __initconst = {
+ { 22, TI_CLK_MUX, dra7_mcasp1_aux_gfclk_mux_parents, NULL },
+ { 24, TI_CLK_MUX, dra7_mcasp1_ahclkx_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_mcasp8_bit_data[] __initconst = {
+ { 22, TI_CLK_MUX, dra7_mcasp1_aux_gfclk_mux_parents, NULL },
+ { 24, TI_CLK_MUX, dra7_mcasp1_ahclkx_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_mcasp4_bit_data[] __initconst = {
+ { 22, TI_CLK_MUX, dra7_mcasp1_aux_gfclk_mux_parents, NULL },
+ { 24, TI_CLK_MUX, dra7_mcasp1_ahclkx_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_uart7_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_uart6_gfclk_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_uart8_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_uart6_gfclk_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_uart9_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_uart6_gfclk_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_mcasp6_bit_data[] __initconst = {
+ { 22, TI_CLK_MUX, dra7_mcasp1_aux_gfclk_mux_parents, NULL },
+ { 24, TI_CLK_MUX, dra7_mcasp1_ahclkx_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_mcasp7_bit_data[] __initconst = {
+ { 22, TI_CLK_MUX, dra7_mcasp1_aux_gfclk_mux_parents, NULL },
+ { 24, TI_CLK_MUX, dra7_mcasp1_ahclkx_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data dra7_l4per_clkctrl_regs[] __initconst = {
+ { DRA7_L4_PER2_CLKCTRL, NULL, 0, "l3_iclk_div", "l4per2_clkdm" },
+ { DRA7_L4_PER3_CLKCTRL, NULL, 0, "l3_iclk_div", "l4per3_clkdm" },
+ { DRA7_TIMER10_CLKCTRL, dra7_timer10_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0028:24" },
+ { DRA7_TIMER11_CLKCTRL, dra7_timer11_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0030:24" },
+ { DRA7_TIMER2_CLKCTRL, dra7_timer2_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0038:24" },
+ { DRA7_TIMER3_CLKCTRL, dra7_timer3_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0040:24" },
+ { DRA7_TIMER4_CLKCTRL, dra7_timer4_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0048:24" },
+ { DRA7_TIMER9_CLKCTRL, dra7_timer9_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0050:24" },
+ { DRA7_ELM_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_GPIO2_CLKCTRL, dra7_gpio2_bit_data, CLKF_HW_SUP, "l3_iclk_div" },
+ { DRA7_GPIO3_CLKCTRL, dra7_gpio3_bit_data, CLKF_HW_SUP, "l3_iclk_div" },
+ { DRA7_GPIO4_CLKCTRL, dra7_gpio4_bit_data, CLKF_HW_SUP, "l3_iclk_div" },
+ { DRA7_GPIO5_CLKCTRL, dra7_gpio5_bit_data, CLKF_HW_SUP, "l3_iclk_div" },
+ { DRA7_GPIO6_CLKCTRL, dra7_gpio6_bit_data, CLKF_HW_SUP, "l3_iclk_div" },
+ { DRA7_HDQ1W_CLKCTRL, NULL, CLKF_SW_SUP, "func_12m_fclk" },
+ { DRA7_EPWMSS1_CLKCTRL, NULL, CLKF_SW_SUP, "l4_root_clk_div", "l4per2_clkdm" },
+ { DRA7_EPWMSS2_CLKCTRL, NULL, CLKF_SW_SUP, "l4_root_clk_div", "l4per2_clkdm" },
+ { DRA7_I2C1_CLKCTRL, NULL, CLKF_SW_SUP, "func_96m_fclk" },
+ { DRA7_I2C2_CLKCTRL, NULL, CLKF_SW_SUP, "func_96m_fclk" },
+ { DRA7_I2C3_CLKCTRL, NULL, CLKF_SW_SUP, "func_96m_fclk" },
+ { DRA7_I2C4_CLKCTRL, NULL, CLKF_SW_SUP, "func_96m_fclk" },
+ { DRA7_L4_PER1_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_EPWMSS0_CLKCTRL, NULL, CLKF_SW_SUP, "l4_root_clk_div", "l4per2_clkdm" },
+ { DRA7_TIMER13_CLKCTRL, dra7_timer13_bit_data, CLKF_SW_SUP, "l4per_cm:clk:00c8:24", "l4per3_clkdm" },
+ { DRA7_TIMER14_CLKCTRL, dra7_timer14_bit_data, CLKF_SW_SUP, "l4per_cm:clk:00d0:24", "l4per3_clkdm" },
+ { DRA7_TIMER15_CLKCTRL, dra7_timer15_bit_data, CLKF_SW_SUP, "l4per_cm:clk:00d8:24", "l4per3_clkdm" },
+ { DRA7_MCSPI1_CLKCTRL, NULL, CLKF_SW_SUP, "func_48m_fclk" },
+ { DRA7_MCSPI2_CLKCTRL, NULL, CLKF_SW_SUP, "func_48m_fclk" },
+ { DRA7_MCSPI3_CLKCTRL, NULL, CLKF_SW_SUP, "func_48m_fclk" },
+ { DRA7_MCSPI4_CLKCTRL, NULL, CLKF_SW_SUP, "func_48m_fclk" },
+ { DRA7_GPIO7_CLKCTRL, dra7_gpio7_bit_data, CLKF_HW_SUP, "l3_iclk_div" },
+ { DRA7_GPIO8_CLKCTRL, dra7_gpio8_bit_data, CLKF_HW_SUP, "l3_iclk_div" },
+ { DRA7_MMC3_CLKCTRL, dra7_mmc3_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0120:25" },
+ { DRA7_MMC4_CLKCTRL, dra7_mmc4_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0128:25" },
+ { DRA7_TIMER16_CLKCTRL, dra7_timer16_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0130:24", "l4per3_clkdm" },
+ { DRA7_QSPI_CLKCTRL, dra7_qspi_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0138:25", "l4per2_clkdm" },
+ { DRA7_UART1_CLKCTRL, dra7_uart1_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0140:24" },
+ { DRA7_UART2_CLKCTRL, dra7_uart2_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0148:24" },
+ { DRA7_UART3_CLKCTRL, dra7_uart3_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0150:24" },
+ { DRA7_UART4_CLKCTRL, dra7_uart4_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0158:24" },
+ { DRA7_MCASP2_CLKCTRL, dra7_mcasp2_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0160:22", "l4per2_clkdm" },
+ { DRA7_MCASP3_CLKCTRL, dra7_mcasp3_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0168:22", "l4per2_clkdm" },
+ { DRA7_UART5_CLKCTRL, dra7_uart5_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0170:24" },
+ { DRA7_MCASP5_CLKCTRL, dra7_mcasp5_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0178:22", "l4per2_clkdm" },
+ { DRA7_MCASP8_CLKCTRL, dra7_mcasp8_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0190:24", "l4per2_clkdm" },
+ { DRA7_MCASP4_CLKCTRL, dra7_mcasp4_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0198:22", "l4per2_clkdm" },
+ { DRA7_AES1_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div", "l4sec_clkdm" },
+ { DRA7_AES2_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div", "l4sec_clkdm" },
+ { DRA7_DES_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div", "l4sec_clkdm" },
+ { DRA7_RNG_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div", "l4sec_clkdm" },
+ { DRA7_SHAM_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div", "l4sec_clkdm" },
+ { DRA7_UART7_CLKCTRL, dra7_uart7_bit_data, CLKF_SW_SUP, "l4per_cm:clk:01d0:24", "l4per2_clkdm" },
+ { DRA7_UART8_CLKCTRL, dra7_uart8_bit_data, CLKF_SW_SUP, "l4per_cm:clk:01e0:24", "l4per2_clkdm" },
+ { DRA7_UART9_CLKCTRL, dra7_uart9_bit_data, CLKF_SW_SUP, "l4per_cm:clk:01e8:24", "l4per2_clkdm" },
+ { DRA7_DCAN2_CLKCTRL, NULL, CLKF_SW_SUP, "sys_clkin1", "l4per2_clkdm" },
+ { DRA7_MCASP6_CLKCTRL, dra7_mcasp6_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0204:22", "l4per2_clkdm" },
+ { DRA7_MCASP7_CLKCTRL, dra7_mcasp7_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0208:22", "l4per2_clkdm" },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_gpio1_bit_data[] __initconst = {
+ { 8, TI_CLK_GATE, dra7_dss_32khz_clk_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_timer1_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_timer10_gfclk_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_uart10_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_uart6_gfclk_mux_parents, NULL },
+ { 0 },
+};
+
+static const char * const dra7_dcan1_sys_clk_mux_parents[] __initconst = {
+ "sys_clkin1",
+ "sys_clkin2",
+ NULL,
+};
+
+static const struct omap_clkctrl_bit_data dra7_dcan1_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_dcan1_sys_clk_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data dra7_wkupaon_clkctrl_regs[] __initconst = {
+ { DRA7_L4_WKUP_CLKCTRL, NULL, 0, "wkupaon_iclk_mux" },
+ { DRA7_WD_TIMER2_CLKCTRL, NULL, CLKF_SW_SUP, "sys_32k_ck" },
+ { DRA7_GPIO1_CLKCTRL, dra7_gpio1_bit_data, CLKF_HW_SUP, "wkupaon_iclk_mux" },
+ { DRA7_TIMER1_CLKCTRL, dra7_timer1_bit_data, CLKF_SW_SUP, "wkupaon_cm:clk:0020:24" },
+ { DRA7_TIMER12_CLKCTRL, NULL, 0, "secure_32k_clk_src_ck" },
+ { DRA7_COUNTER_32K_CLKCTRL, NULL, 0, "wkupaon_iclk_mux" },
+ { DRA7_UART10_CLKCTRL, dra7_uart10_bit_data, CLKF_SW_SUP, "wkupaon_cm:clk:0060:24" },
+ { DRA7_DCAN1_CLKCTRL, dra7_dcan1_bit_data, CLKF_SW_SUP, "wkupaon_cm:clk:0068:24" },
+ { DRA7_ADC_CLKCTRL, NULL, CLKF_SW_SUP, "mcan_clk"},
+ { 0 },
+};
+
+const struct omap_clkctrl_data dra7_clkctrl_compat_data[] __initconst = {
+ { 0x4a005320, dra7_mpu_clkctrl_regs },
+ { 0x4a005540, dra7_ipu_clkctrl_regs },
+ { 0x4a005740, dra7_rtc_clkctrl_regs },
+ { 0x4a008620, dra7_coreaon_clkctrl_regs },
+ { 0x4a008720, dra7_l3main1_clkctrl_regs },
+ { 0x4a008a20, dra7_dma_clkctrl_regs },
+ { 0x4a008b20, dra7_emif_clkctrl_regs },
+ { 0x4a008c00, dra7_atl_clkctrl_regs },
+ { 0x4a008d20, dra7_l4cfg_clkctrl_regs },
+ { 0x4a008e20, dra7_l3instr_clkctrl_regs },
+ { 0x4a009120, dra7_dss_clkctrl_regs },
+ { 0x4a009320, dra7_l3init_clkctrl_regs },
+ { 0x4a009700, dra7_l4per_clkctrl_regs },
+ { 0x4ae07820, dra7_wkupaon_clkctrl_regs },
+ { 0 },
+};
+
+struct ti_dt_clk dra7xx_compat_clks[] = {
+ DT_CLK(NULL, "timer_32k_ck", "sys_32k_ck"),
+ DT_CLK(NULL, "sys_clkin_ck", "timer_sys_clk_div"),
+ DT_CLK(NULL, "sys_clkin", "sys_clkin1"),
+ DT_CLK(NULL, "atl_dpll_clk_mux", "atl_cm:0000:24"),
+ DT_CLK(NULL, "atl_gfclk_mux", "atl_cm:0000:26"),
+ DT_CLK(NULL, "dcan1_sys_clk_mux", "wkupaon_cm:0068:24"),
+ DT_CLK(NULL, "dss_32khz_clk", "dss_cm:0000:11"),
+ DT_CLK(NULL, "dss_48mhz_clk", "dss_cm:0000:9"),
+ DT_CLK(NULL, "dss_dss_clk", "dss_cm:0000:8"),
+ DT_CLK(NULL, "dss_hdmi_clk", "dss_cm:0000:10"),
+ DT_CLK(NULL, "dss_video1_clk", "dss_cm:0000:12"),
+ DT_CLK(NULL, "dss_video2_clk", "dss_cm:0000:13"),
+ DT_CLK(NULL, "gmac_rft_clk_mux", "l3init_cm:00b0:25"),
+ DT_CLK(NULL, "gpio1_dbclk", "wkupaon_cm:0018:8"),
+ DT_CLK(NULL, "gpio2_dbclk", "l4per_cm:0060:8"),
+ DT_CLK(NULL, "gpio3_dbclk", "l4per_cm:0068:8"),
+ DT_CLK(NULL, "gpio4_dbclk", "l4per_cm:0070:8"),
+ DT_CLK(NULL, "gpio5_dbclk", "l4per_cm:0078:8"),
+ DT_CLK(NULL, "gpio6_dbclk", "l4per_cm:0080:8"),
+ DT_CLK(NULL, "gpio7_dbclk", "l4per_cm:0110:8"),
+ DT_CLK(NULL, "gpio8_dbclk", "l4per_cm:0118:8"),
+ DT_CLK(NULL, "mcasp1_ahclkr_mux", "ipu_cm:0010:28"),
+ DT_CLK(NULL, "mcasp1_ahclkx_mux", "ipu_cm:0010:24"),
+ DT_CLK(NULL, "mcasp1_aux_gfclk_mux", "ipu_cm:0010:22"),
+ DT_CLK(NULL, "mcasp2_ahclkr_mux", "l4per_cm:0160:28"),
+ DT_CLK(NULL, "mcasp2_ahclkx_mux", "l4per_cm:0160:24"),
+ DT_CLK(NULL, "mcasp2_aux_gfclk_mux", "l4per_cm:0160:22"),
+ DT_CLK(NULL, "mcasp3_ahclkx_mux", "l4per_cm:0168:24"),
+ DT_CLK(NULL, "mcasp3_aux_gfclk_mux", "l4per_cm:0168:22"),
+ DT_CLK(NULL, "mcasp4_ahclkx_mux", "l4per_cm:0198:24"),
+ DT_CLK(NULL, "mcasp4_aux_gfclk_mux", "l4per_cm:0198:22"),
+ DT_CLK(NULL, "mcasp5_ahclkx_mux", "l4per_cm:0178:24"),
+ DT_CLK(NULL, "mcasp5_aux_gfclk_mux", "l4per_cm:0178:22"),
+ DT_CLK(NULL, "mcasp6_ahclkx_mux", "l4per_cm:0204:24"),
+ DT_CLK(NULL, "mcasp6_aux_gfclk_mux", "l4per_cm:0204:22"),
+ DT_CLK(NULL, "mcasp7_ahclkx_mux", "l4per_cm:0208:24"),
+ DT_CLK(NULL, "mcasp7_aux_gfclk_mux", "l4per_cm:0208:22"),
+ DT_CLK(NULL, "mcasp8_ahclkx_mux", "l4per_cm:0190:22"),
+ DT_CLK(NULL, "mcasp8_aux_gfclk_mux", "l4per_cm:0190:24"),
+ DT_CLK(NULL, "mmc1_clk32k", "l3init_cm:0008:8"),
+ DT_CLK(NULL, "mmc1_fclk_div", "l3init_cm:0008:25"),
+ DT_CLK(NULL, "mmc1_fclk_mux", "l3init_cm:0008:24"),
+ DT_CLK(NULL, "mmc2_clk32k", "l3init_cm:0010:8"),
+ DT_CLK(NULL, "mmc2_fclk_div", "l3init_cm:0010:25"),
+ DT_CLK(NULL, "mmc2_fclk_mux", "l3init_cm:0010:24"),
+ DT_CLK(NULL, "mmc3_clk32k", "l4per_cm:0120:8"),
+ DT_CLK(NULL, "mmc3_gfclk_div", "l4per_cm:0120:25"),
+ DT_CLK(NULL, "mmc3_gfclk_mux", "l4per_cm:0120:24"),
+ DT_CLK(NULL, "mmc4_clk32k", "l4per_cm:0128:8"),
+ DT_CLK(NULL, "mmc4_gfclk_div", "l4per_cm:0128:25"),
+ DT_CLK(NULL, "mmc4_gfclk_mux", "l4per_cm:0128:24"),
+ DT_CLK(NULL, "optfclk_pciephy1_32khz", "l3init_cm:0090:8"),
+ DT_CLK(NULL, "optfclk_pciephy1_clk", "l3init_cm:0090:9"),
+ DT_CLK(NULL, "optfclk_pciephy1_div_clk", "l3init_cm:0090:10"),
+ DT_CLK(NULL, "optfclk_pciephy2_32khz", "l3init_cm:0098:8"),
+ DT_CLK(NULL, "optfclk_pciephy2_clk", "l3init_cm:0098:9"),
+ DT_CLK(NULL, "optfclk_pciephy2_div_clk", "l3init_cm:0098:10"),
+ DT_CLK(NULL, "qspi_gfclk_div", "l4per_cm:0138:25"),
+ DT_CLK(NULL, "qspi_gfclk_mux", "l4per_cm:0138:24"),
+ DT_CLK(NULL, "rmii_50mhz_clk_mux", "l3init_cm:00b0:24"),
+ DT_CLK(NULL, "sata_ref_clk", "l3init_cm:0068:8"),
+ DT_CLK(NULL, "timer10_gfclk_mux", "l4per_cm:0028:24"),
+ DT_CLK(NULL, "timer11_gfclk_mux", "l4per_cm:0030:24"),
+ DT_CLK(NULL, "timer13_gfclk_mux", "l4per_cm:00c8:24"),
+ DT_CLK(NULL, "timer14_gfclk_mux", "l4per_cm:00d0:24"),
+ DT_CLK(NULL, "timer15_gfclk_mux", "l4per_cm:00d8:24"),
+ DT_CLK(NULL, "timer16_gfclk_mux", "l4per_cm:0130:24"),
+ DT_CLK(NULL, "timer1_gfclk_mux", "wkupaon_cm:0020:24"),
+ DT_CLK(NULL, "timer2_gfclk_mux", "l4per_cm:0038:24"),
+ DT_CLK(NULL, "timer3_gfclk_mux", "l4per_cm:0040:24"),
+ DT_CLK(NULL, "timer4_gfclk_mux", "l4per_cm:0048:24"),
+ DT_CLK(NULL, "timer5_gfclk_mux", "ipu_cm:0018:24"),
+ DT_CLK(NULL, "timer6_gfclk_mux", "ipu_cm:0020:24"),
+ DT_CLK(NULL, "timer7_gfclk_mux", "ipu_cm:0028:24"),
+ DT_CLK(NULL, "timer8_gfclk_mux", "ipu_cm:0030:24"),
+ DT_CLK(NULL, "timer9_gfclk_mux", "l4per_cm:0050:24"),
+ DT_CLK(NULL, "uart10_gfclk_mux", "wkupaon_cm:0060:24"),
+ DT_CLK(NULL, "uart1_gfclk_mux", "l4per_cm:0140:24"),
+ DT_CLK(NULL, "uart2_gfclk_mux", "l4per_cm:0148:24"),
+ DT_CLK(NULL, "uart3_gfclk_mux", "l4per_cm:0150:24"),
+ DT_CLK(NULL, "uart4_gfclk_mux", "l4per_cm:0158:24"),
+ DT_CLK(NULL, "uart5_gfclk_mux", "l4per_cm:0170:24"),
+ DT_CLK(NULL, "uart6_gfclk_mux", "ipu_cm:0040:24"),
+ DT_CLK(NULL, "uart7_gfclk_mux", "l4per_cm:01d0:24"),
+ DT_CLK(NULL, "uart8_gfclk_mux", "l4per_cm:01e0:24"),
+ DT_CLK(NULL, "uart9_gfclk_mux", "l4per_cm:01e8:24"),
+ DT_CLK(NULL, "usb_otg_ss1_refclk960m", "l3init_cm:00d0:8"),
+ DT_CLK(NULL, "usb_otg_ss2_refclk960m", "l3init_cm:0020:8"),
+ { .node_name = NULL },
+};
diff --git a/drivers/clk/ti/clk-7xx.c b/drivers/clk/ti/clk-7xx.c
index 71a122b2dc67..597fb4a59318 100644
--- a/drivers/clk/ti/clk-7xx.c
+++ b/drivers/clk/ti/clk-7xx.c
@@ -23,7 +23,28 @@
#define DRA7_DPLL_USB_DEFFREQ 960000000
static const struct omap_clkctrl_reg_data dra7_mpu_clkctrl_regs[] __initconst = {
- { DRA7_MPU_CLKCTRL, NULL, 0, "dpll_mpu_m2_ck" },
+ { DRA7_MPU_MPU_CLKCTRL, NULL, 0, "dpll_mpu_m2_ck" },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data dra7_dsp1_clkctrl_regs[] __initconst = {
+ { DRA7_DSP1_MMU0_DSP1_CLKCTRL, NULL, CLKF_HW_SUP, "dpll_dsp_m2_ck" },
+ { 0 },
+};
+
+static const char * const dra7_ipu1_gfclk_mux_parents[] __initconst = {
+ "dpll_abe_m2x2_ck",
+ "dpll_core_h22x2_ck",
+ NULL,
+};
+
+static const struct omap_clkctrl_bit_data dra7_mmu_ipu1_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_ipu1_gfclk_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data dra7_ipu1_clkctrl_regs[] __initconst = {
+ { DRA7_IPU1_MMU_IPU1_CLKCTRL, dra7_mmu_ipu1_bit_data, CLKF_HW_SUP, "ipu1-clkctrl:0000:24" },
{ 0 },
};
@@ -108,45 +129,55 @@ static const struct omap_clkctrl_bit_data dra7_uart6_bit_data[] __initconst = {
};
static const struct omap_clkctrl_reg_data dra7_ipu_clkctrl_regs[] __initconst = {
- { DRA7_MCASP1_CLKCTRL, dra7_mcasp1_bit_data, CLKF_SW_SUP, "ipu_cm:clk:0010:22" },
- { DRA7_TIMER5_CLKCTRL, dra7_timer5_bit_data, CLKF_SW_SUP, "ipu_cm:clk:0018:24" },
- { DRA7_TIMER6_CLKCTRL, dra7_timer6_bit_data, CLKF_SW_SUP, "ipu_cm:clk:0020:24" },
- { DRA7_TIMER7_CLKCTRL, dra7_timer7_bit_data, CLKF_SW_SUP, "ipu_cm:clk:0028:24" },
- { DRA7_TIMER8_CLKCTRL, dra7_timer8_bit_data, CLKF_SW_SUP, "ipu_cm:clk:0030:24" },
- { DRA7_I2C5_CLKCTRL, NULL, CLKF_SW_SUP, "func_96m_fclk" },
- { DRA7_UART6_CLKCTRL, dra7_uart6_bit_data, CLKF_SW_SUP, "ipu_cm:clk:0040:24" },
+ { DRA7_IPU_MCASP1_CLKCTRL, dra7_mcasp1_bit_data, CLKF_SW_SUP, "ipu-clkctrl:0000:22" },
+ { DRA7_IPU_TIMER5_CLKCTRL, dra7_timer5_bit_data, CLKF_SW_SUP, "ipu-clkctrl:0008:24" },
+ { DRA7_IPU_TIMER6_CLKCTRL, dra7_timer6_bit_data, CLKF_SW_SUP, "ipu-clkctrl:0010:24" },
+ { DRA7_IPU_TIMER7_CLKCTRL, dra7_timer7_bit_data, CLKF_SW_SUP, "ipu-clkctrl:0018:24" },
+ { DRA7_IPU_TIMER8_CLKCTRL, dra7_timer8_bit_data, CLKF_SW_SUP, "ipu-clkctrl:0020:24" },
+ { DRA7_IPU_I2C5_CLKCTRL, NULL, CLKF_SW_SUP, "func_96m_fclk" },
+ { DRA7_IPU_UART6_CLKCTRL, dra7_uart6_bit_data, CLKF_SW_SUP, "ipu-clkctrl:0030:24" },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data dra7_dsp2_clkctrl_regs[] __initconst = {
+ { DRA7_DSP2_MMU0_DSP2_CLKCTRL, NULL, CLKF_HW_SUP, "dpll_dsp_m2_ck" },
{ 0 },
};
static const struct omap_clkctrl_reg_data dra7_rtc_clkctrl_regs[] __initconst = {
- { DRA7_RTCSS_CLKCTRL, NULL, CLKF_SW_SUP, "sys_32k_ck" },
+ { DRA7_RTC_RTCSS_CLKCTRL, NULL, CLKF_SW_SUP, "sys_32k_ck" },
{ 0 },
};
static const struct omap_clkctrl_reg_data dra7_coreaon_clkctrl_regs[] __initconst = {
- { DRA7_SMARTREFLEX_MPU_CLKCTRL, NULL, CLKF_SW_SUP, "wkupaon_iclk_mux" },
- { DRA7_SMARTREFLEX_CORE_CLKCTRL, NULL, CLKF_SW_SUP, "wkupaon_iclk_mux" },
+ { DRA7_COREAON_SMARTREFLEX_MPU_CLKCTRL, NULL, CLKF_SW_SUP, "wkupaon_iclk_mux" },
+ { DRA7_COREAON_SMARTREFLEX_CORE_CLKCTRL, NULL, CLKF_SW_SUP, "wkupaon_iclk_mux" },
{ 0 },
};
static const struct omap_clkctrl_reg_data dra7_l3main1_clkctrl_regs[] __initconst = {
- { DRA7_L3_MAIN_1_CLKCTRL, NULL, 0, "l3_iclk_div" },
- { DRA7_GPMC_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" },
- { DRA7_TPCC_CLKCTRL, NULL, 0, "l3_iclk_div" },
- { DRA7_TPTC0_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" },
- { DRA7_TPTC1_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" },
- { DRA7_VCP1_CLKCTRL, NULL, 0, "l3_iclk_div" },
- { DRA7_VCP2_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_L3MAIN1_L3_MAIN_1_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_L3MAIN1_GPMC_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" },
+ { DRA7_L3MAIN1_TPCC_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_L3MAIN1_TPTC0_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" },
+ { DRA7_L3MAIN1_TPTC1_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" },
+ { DRA7_L3MAIN1_VCP1_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_L3MAIN1_VCP2_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data dra7_ipu2_clkctrl_regs[] __initconst = {
+ { DRA7_IPU2_MMU_IPU2_CLKCTRL, NULL, CLKF_HW_SUP, "dpll_core_h22x2_ck" },
{ 0 },
};
static const struct omap_clkctrl_reg_data dra7_dma_clkctrl_regs[] __initconst = {
- { DRA7_DMA_SYSTEM_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_DMA_DMA_SYSTEM_CLKCTRL, NULL, 0, "l3_iclk_div" },
{ 0 },
};
static const struct omap_clkctrl_reg_data dra7_emif_clkctrl_regs[] __initconst = {
- { DRA7_DMM_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_EMIF_DMM_CLKCTRL, NULL, 0, "l3_iclk_div" },
{ 0 },
};
@@ -161,7 +192,7 @@ static const char * const dra7_atl_dpll_clk_mux_parents[] __initconst = {
static const char * const dra7_atl_gfclk_mux_parents[] __initconst = {
"l3_iclk_div",
"dpll_abe_m2_ck",
- "atl_cm:clk:0000:24",
+ "atl-clkctrl:0000:24",
NULL,
};
@@ -172,32 +203,32 @@ static const struct omap_clkctrl_bit_data dra7_atl_bit_data[] __initconst = {
};
static const struct omap_clkctrl_reg_data dra7_atl_clkctrl_regs[] __initconst = {
- { DRA7_ATL_CLKCTRL, dra7_atl_bit_data, CLKF_SW_SUP, "atl_cm:clk:0000:26" },
+ { DRA7_ATL_ATL_CLKCTRL, dra7_atl_bit_data, CLKF_SW_SUP, "atl-clkctrl:0000:26" },
{ 0 },
};
static const struct omap_clkctrl_reg_data dra7_l4cfg_clkctrl_regs[] __initconst = {
- { DRA7_L4_CFG_CLKCTRL, NULL, 0, "l3_iclk_div" },
- { DRA7_SPINLOCK_CLKCTRL, NULL, 0, "l3_iclk_div" },
- { DRA7_MAILBOX1_CLKCTRL, NULL, 0, "l3_iclk_div" },
- { DRA7_MAILBOX2_CLKCTRL, NULL, 0, "l3_iclk_div" },
- { DRA7_MAILBOX3_CLKCTRL, NULL, 0, "l3_iclk_div" },
- { DRA7_MAILBOX4_CLKCTRL, NULL, 0, "l3_iclk_div" },
- { DRA7_MAILBOX5_CLKCTRL, NULL, 0, "l3_iclk_div" },
- { DRA7_MAILBOX6_CLKCTRL, NULL, 0, "l3_iclk_div" },
- { DRA7_MAILBOX7_CLKCTRL, NULL, 0, "l3_iclk_div" },
- { DRA7_MAILBOX8_CLKCTRL, NULL, 0, "l3_iclk_div" },
- { DRA7_MAILBOX9_CLKCTRL, NULL, 0, "l3_iclk_div" },
- { DRA7_MAILBOX10_CLKCTRL, NULL, 0, "l3_iclk_div" },
- { DRA7_MAILBOX11_CLKCTRL, NULL, 0, "l3_iclk_div" },
- { DRA7_MAILBOX12_CLKCTRL, NULL, 0, "l3_iclk_div" },
- { DRA7_MAILBOX13_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_L4CFG_L4_CFG_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_L4CFG_SPINLOCK_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_L4CFG_MAILBOX1_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_L4CFG_MAILBOX2_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_L4CFG_MAILBOX3_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_L4CFG_MAILBOX4_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_L4CFG_MAILBOX5_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_L4CFG_MAILBOX6_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_L4CFG_MAILBOX7_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_L4CFG_MAILBOX8_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_L4CFG_MAILBOX9_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_L4CFG_MAILBOX10_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_L4CFG_MAILBOX11_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_L4CFG_MAILBOX12_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_L4CFG_MAILBOX13_CLKCTRL, NULL, 0, "l3_iclk_div" },
{ 0 },
};
static const struct omap_clkctrl_reg_data dra7_l3instr_clkctrl_regs[] __initconst = {
- { DRA7_L3_MAIN_2_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" },
- { DRA7_L3_INSTR_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" },
+ { DRA7_L3INSTR_L3_MAIN_2_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" },
+ { DRA7_L3INSTR_L3_INSTR_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" },
{ 0 },
};
@@ -242,8 +273,8 @@ static const struct omap_clkctrl_bit_data dra7_dss_core_bit_data[] __initconst =
};
static const struct omap_clkctrl_reg_data dra7_dss_clkctrl_regs[] __initconst = {
- { DRA7_DSS_CORE_CLKCTRL, dra7_dss_core_bit_data, CLKF_SW_SUP, "dss_cm:clk:0000:8" },
- { DRA7_BB2D_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_core_h24x2_ck" },
+ { DRA7_DSS_DSS_CORE_CLKCTRL, dra7_dss_core_bit_data, CLKF_SW_SUP, "dss-clkctrl:0000:8" },
+ { DRA7_DSS_BB2D_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_core_h24x2_ck" },
{ 0 },
};
@@ -254,7 +285,7 @@ static const char * const dra7_mmc1_fclk_mux_parents[] __initconst = {
};
static const char * const dra7_mmc1_fclk_div_parents[] __initconst = {
- "l3init_cm:clk:0008:24",
+ "l3init-clkctrl:0008:24",
NULL,
};
@@ -271,7 +302,7 @@ static const struct omap_clkctrl_bit_data dra7_mmc1_bit_data[] __initconst = {
};
static const char * const dra7_mmc2_fclk_div_parents[] __initconst = {
- "l3init_cm:clk:0010:24",
+ "l3init-clkctrl:0010:24",
NULL,
};
@@ -307,6 +338,24 @@ static const struct omap_clkctrl_bit_data dra7_sata_bit_data[] __initconst = {
{ 0 },
};
+static const struct omap_clkctrl_bit_data dra7_usb_otg_ss1_bit_data[] __initconst = {
+ { 8, TI_CLK_GATE, dra7_usb_otg_ss2_refclk960m_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data dra7_l3init_clkctrl_regs[] __initconst = {
+ { DRA7_L3INIT_MMC1_CLKCTRL, dra7_mmc1_bit_data, CLKF_SW_SUP, "l3init-clkctrl:0008:25" },
+ { DRA7_L3INIT_MMC2_CLKCTRL, dra7_mmc2_bit_data, CLKF_SW_SUP, "l3init-clkctrl:0010:25" },
+ { DRA7_L3INIT_USB_OTG_SS2_CLKCTRL, dra7_usb_otg_ss2_bit_data, CLKF_HW_SUP, "dpll_core_h13x2_ck" },
+ { DRA7_L3INIT_USB_OTG_SS3_CLKCTRL, NULL, CLKF_HW_SUP, "dpll_core_h13x2_ck" },
+ { DRA7_L3INIT_USB_OTG_SS4_CLKCTRL, NULL, CLKF_HW_SUP, "dpll_core_h13x2_ck" },
+ { DRA7_L3INIT_SATA_CLKCTRL, dra7_sata_bit_data, CLKF_SW_SUP, "func_48m_fclk" },
+ { DRA7_L3INIT_OCP2SCP1_CLKCTRL, NULL, CLKF_HW_SUP, "l4_root_clk_div" },
+ { DRA7_L3INIT_OCP2SCP3_CLKCTRL, NULL, CLKF_HW_SUP, "l4_root_clk_div" },
+ { DRA7_L3INIT_USB_OTG_SS1_CLKCTRL, dra7_usb_otg_ss1_bit_data, CLKF_HW_SUP, "dpll_core_h13x2_ck" },
+ { 0 },
+};
+
static const char * const dra7_optfclk_pciephy1_clk_parents[] __initconst = {
"apll_pcie_ck",
NULL,
@@ -331,6 +380,12 @@ static const struct omap_clkctrl_bit_data dra7_pcie2_bit_data[] __initconst = {
{ 0 },
};
+static const struct omap_clkctrl_reg_data dra7_pcie_clkctrl_regs[] __initconst = {
+ { DRA7_PCIE_PCIE1_CLKCTRL, dra7_pcie1_bit_data, CLKF_SW_SUP, "l4_root_clk_div" },
+ { DRA7_PCIE_PCIE2_CLKCTRL, dra7_pcie2_bit_data, CLKF_SW_SUP, "l4_root_clk_div" },
+ { 0 },
+};
+
static const char * const dra7_rmii_50mhz_clk_mux_parents[] __initconst = {
"dpll_gmac_h11x2_ck",
"rmii_clk_ck",
@@ -352,24 +407,8 @@ static const struct omap_clkctrl_bit_data dra7_gmac_bit_data[] __initconst = {
{ 0 },
};
-static const struct omap_clkctrl_bit_data dra7_usb_otg_ss1_bit_data[] __initconst = {
- { 8, TI_CLK_GATE, dra7_usb_otg_ss2_refclk960m_parents, NULL },
- { 0 },
-};
-
-static const struct omap_clkctrl_reg_data dra7_l3init_clkctrl_regs[] __initconst = {
- { DRA7_MMC1_CLKCTRL, dra7_mmc1_bit_data, CLKF_SW_SUP, "l3init_cm:clk:0008:25" },
- { DRA7_MMC2_CLKCTRL, dra7_mmc2_bit_data, CLKF_SW_SUP, "l3init_cm:clk:0010:25" },
- { DRA7_USB_OTG_SS2_CLKCTRL, dra7_usb_otg_ss2_bit_data, CLKF_HW_SUP, "dpll_core_h13x2_ck" },
- { DRA7_USB_OTG_SS3_CLKCTRL, NULL, CLKF_HW_SUP, "dpll_core_h13x2_ck" },
- { DRA7_USB_OTG_SS4_CLKCTRL, NULL, CLKF_HW_SUP, "dpll_core_h13x2_ck" },
- { DRA7_SATA_CLKCTRL, dra7_sata_bit_data, CLKF_SW_SUP, "func_48m_fclk" },
- { DRA7_PCIE1_CLKCTRL, dra7_pcie1_bit_data, CLKF_SW_SUP, "l4_root_clk_div", "pcie_clkdm" },
- { DRA7_PCIE2_CLKCTRL, dra7_pcie2_bit_data, CLKF_SW_SUP, "l4_root_clk_div", "pcie_clkdm" },
- { DRA7_GMAC_CLKCTRL, dra7_gmac_bit_data, CLKF_SW_SUP, "dpll_gmac_ck", "gmac_clkdm" },
- { DRA7_OCP2SCP1_CLKCTRL, NULL, CLKF_HW_SUP, "l4_root_clk_div" },
- { DRA7_OCP2SCP3_CLKCTRL, NULL, CLKF_HW_SUP, "l4_root_clk_div" },
- { DRA7_USB_OTG_SS1_CLKCTRL, dra7_usb_otg_ss1_bit_data, CLKF_HW_SUP, "dpll_core_h13x2_ck" },
+static const struct omap_clkctrl_reg_data dra7_gmac_clkctrl_regs[] __initconst = {
+ { DRA7_GMAC_GMAC_CLKCTRL, dra7_gmac_bit_data, CLKF_SW_SUP, "dpll_gmac_ck" },
{ 0 },
};
@@ -443,21 +482,6 @@ static const struct omap_clkctrl_bit_data dra7_gpio6_bit_data[] __initconst = {
{ 0 },
};
-static const struct omap_clkctrl_bit_data dra7_timer13_bit_data[] __initconst = {
- { 24, TI_CLK_MUX, dra7_timer10_gfclk_mux_parents, NULL },
- { 0 },
-};
-
-static const struct omap_clkctrl_bit_data dra7_timer14_bit_data[] __initconst = {
- { 24, TI_CLK_MUX, dra7_timer10_gfclk_mux_parents, NULL },
- { 0 },
-};
-
-static const struct omap_clkctrl_bit_data dra7_timer15_bit_data[] __initconst = {
- { 24, TI_CLK_MUX, dra7_timer10_gfclk_mux_parents, NULL },
- { 0 },
-};
-
static const struct omap_clkctrl_bit_data dra7_gpio7_bit_data[] __initconst = {
{ 8, TI_CLK_GATE, dra7_dss_32khz_clk_parents, NULL },
{ 0 },
@@ -469,7 +493,7 @@ static const struct omap_clkctrl_bit_data dra7_gpio8_bit_data[] __initconst = {
};
static const char * const dra7_mmc3_gfclk_div_parents[] __initconst = {
- "l4per_cm:clk:0120:24",
+ "l4per-clkctrl:00f8:24",
NULL,
};
@@ -486,7 +510,7 @@ static const struct omap_clkctrl_bit_data dra7_mmc3_bit_data[] __initconst = {
};
static const char * const dra7_mmc4_gfclk_div_parents[] __initconst = {
- "l4per_cm:clk:0128:24",
+ "l4per-clkctrl:0100:24",
NULL,
};
@@ -502,8 +526,72 @@ static const struct omap_clkctrl_bit_data dra7_mmc4_bit_data[] __initconst = {
{ 0 },
};
-static const struct omap_clkctrl_bit_data dra7_timer16_bit_data[] __initconst = {
- { 24, TI_CLK_MUX, dra7_timer10_gfclk_mux_parents, NULL },
+static const struct omap_clkctrl_bit_data dra7_uart1_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_uart6_gfclk_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_uart2_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_uart6_gfclk_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_uart3_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_uart6_gfclk_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_uart4_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_uart6_gfclk_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_uart5_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_uart6_gfclk_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data dra7_l4per_clkctrl_regs[] __initconst = {
+ { DRA7_L4PER_TIMER10_CLKCTRL, dra7_timer10_bit_data, CLKF_SW_SUP, "l4per-clkctrl:0000:24" },
+ { DRA7_L4PER_TIMER11_CLKCTRL, dra7_timer11_bit_data, CLKF_SW_SUP, "l4per-clkctrl:0008:24" },
+ { DRA7_L4PER_TIMER2_CLKCTRL, dra7_timer2_bit_data, CLKF_SW_SUP, "l4per-clkctrl:0010:24" },
+ { DRA7_L4PER_TIMER3_CLKCTRL, dra7_timer3_bit_data, CLKF_SW_SUP, "l4per-clkctrl:0018:24" },
+ { DRA7_L4PER_TIMER4_CLKCTRL, dra7_timer4_bit_data, CLKF_SW_SUP, "l4per-clkctrl:0020:24" },
+ { DRA7_L4PER_TIMER9_CLKCTRL, dra7_timer9_bit_data, CLKF_SW_SUP, "l4per-clkctrl:0028:24" },
+ { DRA7_L4PER_ELM_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_L4PER_GPIO2_CLKCTRL, dra7_gpio2_bit_data, CLKF_HW_SUP, "l3_iclk_div" },
+ { DRA7_L4PER_GPIO3_CLKCTRL, dra7_gpio3_bit_data, CLKF_HW_SUP, "l3_iclk_div" },
+ { DRA7_L4PER_GPIO4_CLKCTRL, dra7_gpio4_bit_data, CLKF_HW_SUP, "l3_iclk_div" },
+ { DRA7_L4PER_GPIO5_CLKCTRL, dra7_gpio5_bit_data, CLKF_HW_SUP, "l3_iclk_div" },
+ { DRA7_L4PER_GPIO6_CLKCTRL, dra7_gpio6_bit_data, CLKF_HW_SUP, "l3_iclk_div" },
+ { DRA7_L4PER_HDQ1W_CLKCTRL, NULL, CLKF_SW_SUP, "func_12m_fclk" },
+ { DRA7_L4PER_I2C1_CLKCTRL, NULL, CLKF_SW_SUP, "func_96m_fclk" },
+ { DRA7_L4PER_I2C2_CLKCTRL, NULL, CLKF_SW_SUP, "func_96m_fclk" },
+ { DRA7_L4PER_I2C3_CLKCTRL, NULL, CLKF_SW_SUP, "func_96m_fclk" },
+ { DRA7_L4PER_I2C4_CLKCTRL, NULL, CLKF_SW_SUP, "func_96m_fclk" },
+ { DRA7_L4PER_L4_PER1_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_L4PER_MCSPI1_CLKCTRL, NULL, CLKF_SW_SUP, "func_48m_fclk" },
+ { DRA7_L4PER_MCSPI2_CLKCTRL, NULL, CLKF_SW_SUP, "func_48m_fclk" },
+ { DRA7_L4PER_MCSPI3_CLKCTRL, NULL, CLKF_SW_SUP, "func_48m_fclk" },
+ { DRA7_L4PER_MCSPI4_CLKCTRL, NULL, CLKF_SW_SUP, "func_48m_fclk" },
+ { DRA7_L4PER_GPIO7_CLKCTRL, dra7_gpio7_bit_data, CLKF_HW_SUP, "l3_iclk_div" },
+ { DRA7_L4PER_GPIO8_CLKCTRL, dra7_gpio8_bit_data, CLKF_HW_SUP, "l3_iclk_div" },
+ { DRA7_L4PER_MMC3_CLKCTRL, dra7_mmc3_bit_data, CLKF_SW_SUP, "l4per-clkctrl:00f8:25" },
+ { DRA7_L4PER_MMC4_CLKCTRL, dra7_mmc4_bit_data, CLKF_SW_SUP, "l4per-clkctrl:0100:25" },
+ { DRA7_L4PER_UART1_CLKCTRL, dra7_uart1_bit_data, CLKF_SW_SUP, "l4per-clkctrl:0118:24" },
+ { DRA7_L4PER_UART2_CLKCTRL, dra7_uart2_bit_data, CLKF_SW_SUP, "l4per-clkctrl:0120:24" },
+ { DRA7_L4PER_UART3_CLKCTRL, dra7_uart3_bit_data, CLKF_SW_SUP, "l4per-clkctrl:0128:24" },
+ { DRA7_L4PER_UART4_CLKCTRL, dra7_uart4_bit_data, CLKF_SW_SUP, "l4per-clkctrl:0130:24" },
+ { DRA7_L4PER_UART5_CLKCTRL, dra7_uart5_bit_data, CLKF_SW_SUP, "l4per-clkctrl:0148:24" },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data dra7_l4sec_clkctrl_regs[] __initconst = {
+ { DRA7_L4SEC_AES1_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" },
+ { DRA7_L4SEC_AES2_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" },
+ { DRA7_L4SEC_DES_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" },
+ { DRA7_L4SEC_RNG_CLKCTRL, NULL, CLKF_HW_SUP, "" },
+ { DRA7_L4SEC_SHAM_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" },
{ 0 },
};
@@ -514,7 +602,7 @@ static const char * const dra7_qspi_gfclk_mux_parents[] __initconst = {
};
static const char * const dra7_qspi_gfclk_div_parents[] __initconst = {
- "l4per_cm:clk:0138:24",
+ "l4per2-clkctrl:012c:24",
NULL,
};
@@ -529,26 +617,6 @@ static const struct omap_clkctrl_bit_data dra7_qspi_bit_data[] __initconst = {
{ 0 },
};
-static const struct omap_clkctrl_bit_data dra7_uart1_bit_data[] __initconst = {
- { 24, TI_CLK_MUX, dra7_uart6_gfclk_mux_parents, NULL },
- { 0 },
-};
-
-static const struct omap_clkctrl_bit_data dra7_uart2_bit_data[] __initconst = {
- { 24, TI_CLK_MUX, dra7_uart6_gfclk_mux_parents, NULL },
- { 0 },
-};
-
-static const struct omap_clkctrl_bit_data dra7_uart3_bit_data[] __initconst = {
- { 24, TI_CLK_MUX, dra7_uart6_gfclk_mux_parents, NULL },
- { 0 },
-};
-
-static const struct omap_clkctrl_bit_data dra7_uart4_bit_data[] __initconst = {
- { 24, TI_CLK_MUX, dra7_uart6_gfclk_mux_parents, NULL },
- { 0 },
-};
-
static const struct omap_clkctrl_bit_data dra7_mcasp2_bit_data[] __initconst = {
{ 22, TI_CLK_MUX, dra7_mcasp1_aux_gfclk_mux_parents, NULL },
{ 24, TI_CLK_MUX, dra7_mcasp1_ahclkx_mux_parents, NULL },
@@ -562,11 +630,6 @@ static const struct omap_clkctrl_bit_data dra7_mcasp3_bit_data[] __initconst = {
{ 0 },
};
-static const struct omap_clkctrl_bit_data dra7_uart5_bit_data[] __initconst = {
- { 24, TI_CLK_MUX, dra7_uart6_gfclk_mux_parents, NULL },
- { 0 },
-};
-
static const struct omap_clkctrl_bit_data dra7_mcasp5_bit_data[] __initconst = {
{ 22, TI_CLK_MUX, dra7_mcasp1_aux_gfclk_mux_parents, NULL },
{ 24, TI_CLK_MUX, dra7_mcasp1_ahclkx_mux_parents, NULL },
@@ -612,64 +675,54 @@ static const struct omap_clkctrl_bit_data dra7_mcasp7_bit_data[] __initconst = {
{ 0 },
};
-static const struct omap_clkctrl_reg_data dra7_l4per_clkctrl_regs[] __initconst = {
- { DRA7_L4_PER2_CLKCTRL, NULL, 0, "l3_iclk_div", "l4per2_clkdm" },
- { DRA7_L4_PER3_CLKCTRL, NULL, 0, "l3_iclk_div", "l4per3_clkdm" },
- { DRA7_TIMER10_CLKCTRL, dra7_timer10_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0028:24" },
- { DRA7_TIMER11_CLKCTRL, dra7_timer11_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0030:24" },
- { DRA7_TIMER2_CLKCTRL, dra7_timer2_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0038:24" },
- { DRA7_TIMER3_CLKCTRL, dra7_timer3_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0040:24" },
- { DRA7_TIMER4_CLKCTRL, dra7_timer4_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0048:24" },
- { DRA7_TIMER9_CLKCTRL, dra7_timer9_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0050:24" },
- { DRA7_ELM_CLKCTRL, NULL, 0, "l3_iclk_div" },
- { DRA7_GPIO2_CLKCTRL, dra7_gpio2_bit_data, CLKF_HW_SUP, "l3_iclk_div" },
- { DRA7_GPIO3_CLKCTRL, dra7_gpio3_bit_data, CLKF_HW_SUP, "l3_iclk_div" },
- { DRA7_GPIO4_CLKCTRL, dra7_gpio4_bit_data, CLKF_HW_SUP, "l3_iclk_div" },
- { DRA7_GPIO5_CLKCTRL, dra7_gpio5_bit_data, CLKF_HW_SUP, "l3_iclk_div" },
- { DRA7_GPIO6_CLKCTRL, dra7_gpio6_bit_data, CLKF_HW_SUP, "l3_iclk_div" },
- { DRA7_HDQ1W_CLKCTRL, NULL, CLKF_SW_SUP, "func_12m_fclk" },
- { DRA7_EPWMSS1_CLKCTRL, NULL, CLKF_SW_SUP, "l4_root_clk_div", "l4per2_clkdm" },
- { DRA7_EPWMSS2_CLKCTRL, NULL, CLKF_SW_SUP, "l4_root_clk_div", "l4per2_clkdm" },
- { DRA7_I2C1_CLKCTRL, NULL, CLKF_SW_SUP, "func_96m_fclk" },
- { DRA7_I2C2_CLKCTRL, NULL, CLKF_SW_SUP, "func_96m_fclk" },
- { DRA7_I2C3_CLKCTRL, NULL, CLKF_SW_SUP, "func_96m_fclk" },
- { DRA7_I2C4_CLKCTRL, NULL, CLKF_SW_SUP, "func_96m_fclk" },
- { DRA7_L4_PER1_CLKCTRL, NULL, 0, "l3_iclk_div" },
- { DRA7_EPWMSS0_CLKCTRL, NULL, CLKF_SW_SUP, "l4_root_clk_div", "l4per2_clkdm" },
- { DRA7_TIMER13_CLKCTRL, dra7_timer13_bit_data, CLKF_SW_SUP, "l4per_cm:clk:00c8:24", "l4per3_clkdm" },
- { DRA7_TIMER14_CLKCTRL, dra7_timer14_bit_data, CLKF_SW_SUP, "l4per_cm:clk:00d0:24", "l4per3_clkdm" },
- { DRA7_TIMER15_CLKCTRL, dra7_timer15_bit_data, CLKF_SW_SUP, "l4per_cm:clk:00d8:24", "l4per3_clkdm" },
- { DRA7_MCSPI1_CLKCTRL, NULL, CLKF_SW_SUP, "func_48m_fclk" },
- { DRA7_MCSPI2_CLKCTRL, NULL, CLKF_SW_SUP, "func_48m_fclk" },
- { DRA7_MCSPI3_CLKCTRL, NULL, CLKF_SW_SUP, "func_48m_fclk" },
- { DRA7_MCSPI4_CLKCTRL, NULL, CLKF_SW_SUP, "func_48m_fclk" },
- { DRA7_GPIO7_CLKCTRL, dra7_gpio7_bit_data, CLKF_HW_SUP, "l3_iclk_div" },
- { DRA7_GPIO8_CLKCTRL, dra7_gpio8_bit_data, CLKF_HW_SUP, "l3_iclk_div" },
- { DRA7_MMC3_CLKCTRL, dra7_mmc3_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0120:25" },
- { DRA7_MMC4_CLKCTRL, dra7_mmc4_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0128:25" },
- { DRA7_TIMER16_CLKCTRL, dra7_timer16_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0130:24", "l4per3_clkdm" },
- { DRA7_QSPI_CLKCTRL, dra7_qspi_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0138:25", "l4per2_clkdm" },
- { DRA7_UART1_CLKCTRL, dra7_uart1_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0140:24" },
- { DRA7_UART2_CLKCTRL, dra7_uart2_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0148:24" },
- { DRA7_UART3_CLKCTRL, dra7_uart3_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0150:24" },
- { DRA7_UART4_CLKCTRL, dra7_uart4_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0158:24" },
- { DRA7_MCASP2_CLKCTRL, dra7_mcasp2_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0160:22", "l4per2_clkdm" },
- { DRA7_MCASP3_CLKCTRL, dra7_mcasp3_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0168:22", "l4per2_clkdm" },
- { DRA7_UART5_CLKCTRL, dra7_uart5_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0170:24" },
- { DRA7_MCASP5_CLKCTRL, dra7_mcasp5_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0178:22", "l4per2_clkdm" },
- { DRA7_MCASP8_CLKCTRL, dra7_mcasp8_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0190:24", "l4per2_clkdm" },
- { DRA7_MCASP4_CLKCTRL, dra7_mcasp4_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0198:22", "l4per2_clkdm" },
- { DRA7_AES1_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div", "l4sec_clkdm" },
- { DRA7_AES2_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div", "l4sec_clkdm" },
- { DRA7_DES_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div", "l4sec_clkdm" },
- { DRA7_RNG_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div", "l4sec_clkdm" },
- { DRA7_SHAM_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div", "l4sec_clkdm" },
- { DRA7_UART7_CLKCTRL, dra7_uart7_bit_data, CLKF_SW_SUP, "l4per_cm:clk:01d0:24", "l4per2_clkdm" },
- { DRA7_UART8_CLKCTRL, dra7_uart8_bit_data, CLKF_SW_SUP, "l4per_cm:clk:01e0:24", "l4per2_clkdm" },
- { DRA7_UART9_CLKCTRL, dra7_uart9_bit_data, CLKF_SW_SUP, "l4per_cm:clk:01e8:24", "l4per2_clkdm" },
- { DRA7_DCAN2_CLKCTRL, NULL, CLKF_SW_SUP, "sys_clkin1", "l4per2_clkdm" },
- { DRA7_MCASP6_CLKCTRL, dra7_mcasp6_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0204:22", "l4per2_clkdm" },
- { DRA7_MCASP7_CLKCTRL, dra7_mcasp7_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0208:22", "l4per2_clkdm" },
+static const struct omap_clkctrl_reg_data dra7_l4per2_clkctrl_regs[] __initconst = {
+ { DRA7_L4PER2_L4_PER2_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_L4PER2_PRUSS1_CLKCTRL, NULL, CLKF_SW_SUP, "" },
+ { DRA7_L4PER2_PRUSS2_CLKCTRL, NULL, CLKF_SW_SUP, "" },
+ { DRA7_L4PER2_EPWMSS1_CLKCTRL, NULL, CLKF_SW_SUP, "l4_root_clk_div" },
+ { DRA7_L4PER2_EPWMSS2_CLKCTRL, NULL, CLKF_SW_SUP, "l4_root_clk_div" },
+ { DRA7_L4PER2_EPWMSS0_CLKCTRL, NULL, CLKF_SW_SUP, "l4_root_clk_div" },
+ { DRA7_L4PER2_QSPI_CLKCTRL, dra7_qspi_bit_data, CLKF_SW_SUP, "l4per2-clkctrl:012c:25" },
+ { DRA7_L4PER2_MCASP2_CLKCTRL, dra7_mcasp2_bit_data, CLKF_SW_SUP, "l4per2-clkctrl:0154:22" },
+ { DRA7_L4PER2_MCASP3_CLKCTRL, dra7_mcasp3_bit_data, CLKF_SW_SUP, "l4per2-clkctrl:015c:22" },
+ { DRA7_L4PER2_MCASP5_CLKCTRL, dra7_mcasp5_bit_data, CLKF_SW_SUP, "l4per2-clkctrl:016c:22" },
+ { DRA7_L4PER2_MCASP8_CLKCTRL, dra7_mcasp8_bit_data, CLKF_SW_SUP, "l4per2-clkctrl:0184:24" },
+ { DRA7_L4PER2_MCASP4_CLKCTRL, dra7_mcasp4_bit_data, CLKF_SW_SUP, "l4per2-clkctrl:018c:22" },
+ { DRA7_L4PER2_UART7_CLKCTRL, dra7_uart7_bit_data, CLKF_SW_SUP, "l4per2-clkctrl:01c4:24" },
+ { DRA7_L4PER2_UART8_CLKCTRL, dra7_uart8_bit_data, CLKF_SW_SUP, "l4per2-clkctrl:01d4:24" },
+ { DRA7_L4PER2_UART9_CLKCTRL, dra7_uart9_bit_data, CLKF_SW_SUP, "l4per2-clkctrl:01dc:24" },
+ { DRA7_L4PER2_DCAN2_CLKCTRL, NULL, CLKF_SW_SUP, "sys_clkin1" },
+ { DRA7_L4PER2_MCASP6_CLKCTRL, dra7_mcasp6_bit_data, CLKF_SW_SUP, "l4per2-clkctrl:01f8:22" },
+ { DRA7_L4PER2_MCASP7_CLKCTRL, dra7_mcasp7_bit_data, CLKF_SW_SUP, "l4per2-clkctrl:01fc:22" },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_timer13_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_timer10_gfclk_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_timer14_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_timer10_gfclk_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_timer15_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_timer10_gfclk_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_bit_data dra7_timer16_bit_data[] __initconst = {
+ { 24, TI_CLK_MUX, dra7_timer10_gfclk_mux_parents, NULL },
+ { 0 },
+};
+
+static const struct omap_clkctrl_reg_data dra7_l4per3_clkctrl_regs[] __initconst = {
+ { DRA7_L4PER3_L4_PER3_CLKCTRL, NULL, 0, "l3_iclk_div" },
+ { DRA7_L4PER3_TIMER13_CLKCTRL, dra7_timer13_bit_data, CLKF_SW_SUP, "l4per3-clkctrl:00b4:24" },
+ { DRA7_L4PER3_TIMER14_CLKCTRL, dra7_timer14_bit_data, CLKF_SW_SUP, "l4per3-clkctrl:00bc:24" },
+ { DRA7_L4PER3_TIMER15_CLKCTRL, dra7_timer15_bit_data, CLKF_SW_SUP, "l4per3-clkctrl:00c4:24" },
+ { DRA7_L4PER3_TIMER16_CLKCTRL, dra7_timer16_bit_data, CLKF_SW_SUP, "l4per3-clkctrl:011c:24" },
{ 0 },
};
@@ -700,24 +753,28 @@ static const struct omap_clkctrl_bit_data dra7_dcan1_bit_data[] __initconst = {
};
static const struct omap_clkctrl_reg_data dra7_wkupaon_clkctrl_regs[] __initconst = {
- { DRA7_L4_WKUP_CLKCTRL, NULL, 0, "wkupaon_iclk_mux" },
- { DRA7_WD_TIMER2_CLKCTRL, NULL, CLKF_SW_SUP, "sys_32k_ck" },
- { DRA7_GPIO1_CLKCTRL, dra7_gpio1_bit_data, CLKF_HW_SUP, "wkupaon_iclk_mux" },
- { DRA7_TIMER1_CLKCTRL, dra7_timer1_bit_data, CLKF_SW_SUP, "wkupaon_cm:clk:0020:24" },
- { DRA7_TIMER12_CLKCTRL, NULL, 0, "secure_32k_clk_src_ck" },
- { DRA7_COUNTER_32K_CLKCTRL, NULL, 0, "wkupaon_iclk_mux" },
- { DRA7_UART10_CLKCTRL, dra7_uart10_bit_data, CLKF_SW_SUP, "wkupaon_cm:clk:0060:24" },
- { DRA7_DCAN1_CLKCTRL, dra7_dcan1_bit_data, CLKF_SW_SUP, "wkupaon_cm:clk:0068:24" },
- { DRA7_ADC_CLKCTRL, NULL, CLKF_SW_SUP, "mcan_clk"},
+ { DRA7_WKUPAON_L4_WKUP_CLKCTRL, NULL, 0, "wkupaon_iclk_mux" },
+ { DRA7_WKUPAON_WD_TIMER2_CLKCTRL, NULL, CLKF_SW_SUP, "sys_32k_ck" },
+ { DRA7_WKUPAON_GPIO1_CLKCTRL, dra7_gpio1_bit_data, CLKF_HW_SUP, "wkupaon_iclk_mux" },
+ { DRA7_WKUPAON_TIMER1_CLKCTRL, dra7_timer1_bit_data, CLKF_SW_SUP, "wkupaon-clkctrl:0020:24" },
+ { DRA7_WKUPAON_TIMER12_CLKCTRL, NULL, 0, "secure_32k_clk_src_ck" },
+ { DRA7_WKUPAON_COUNTER_32K_CLKCTRL, NULL, 0, "wkupaon_iclk_mux" },
+ { DRA7_WKUPAON_UART10_CLKCTRL, dra7_uart10_bit_data, CLKF_SW_SUP, "wkupaon-clkctrl:0060:24" },
+ { DRA7_WKUPAON_DCAN1_CLKCTRL, dra7_dcan1_bit_data, CLKF_SW_SUP, "wkupaon-clkctrl:0068:24" },
+ { DRA7_WKUPAON_ADC_CLKCTRL, NULL, CLKF_SW_SUP, "mcan_clk" },
{ 0 },
};
const struct omap_clkctrl_data dra7_clkctrl_data[] __initconst = {
{ 0x4a005320, dra7_mpu_clkctrl_regs },
- { 0x4a005540, dra7_ipu_clkctrl_regs },
- { 0x4a005740, dra7_rtc_clkctrl_regs },
+ { 0x4a005420, dra7_dsp1_clkctrl_regs },
+ { 0x4a005520, dra7_ipu1_clkctrl_regs },
+ { 0x4a005550, dra7_ipu_clkctrl_regs },
+ { 0x4a005620, dra7_dsp2_clkctrl_regs },
+ { 0x4a005720, dra7_rtc_clkctrl_regs },
{ 0x4a008620, dra7_coreaon_clkctrl_regs },
{ 0x4a008720, dra7_l3main1_clkctrl_regs },
+ { 0x4a008920, dra7_ipu2_clkctrl_regs },
{ 0x4a008a20, dra7_dma_clkctrl_regs },
{ 0x4a008b20, dra7_emif_clkctrl_regs },
{ 0x4a008c00, dra7_atl_clkctrl_regs },
@@ -725,7 +782,12 @@ const struct omap_clkctrl_data dra7_clkctrl_data[] __initconst = {
{ 0x4a008e20, dra7_l3instr_clkctrl_regs },
{ 0x4a009120, dra7_dss_clkctrl_regs },
{ 0x4a009320, dra7_l3init_clkctrl_regs },
- { 0x4a009700, dra7_l4per_clkctrl_regs },
+ { 0x4a0093b0, dra7_pcie_clkctrl_regs },
+ { 0x4a0093d0, dra7_gmac_clkctrl_regs },
+ { 0x4a009728, dra7_l4per_clkctrl_regs },
+ { 0x4a0098a0, dra7_l4sec_clkctrl_regs },
+ { 0x4a00970c, dra7_l4per2_clkctrl_regs },
+ { 0x4a009714, dra7_l4per3_clkctrl_regs },
{ 0x4ae07820, dra7_wkupaon_clkctrl_regs },
{ 0 },
};
@@ -734,91 +796,92 @@ static struct ti_dt_clk dra7xx_clks[] = {
DT_CLK(NULL, "timer_32k_ck", "sys_32k_ck"),
DT_CLK(NULL, "sys_clkin_ck", "timer_sys_clk_div"),
DT_CLK(NULL, "sys_clkin", "sys_clkin1"),
- DT_CLK(NULL, "atl_dpll_clk_mux", "atl_cm:0000:24"),
- DT_CLK(NULL, "atl_gfclk_mux", "atl_cm:0000:26"),
- DT_CLK(NULL, "dcan1_sys_clk_mux", "wkupaon_cm:0068:24"),
- DT_CLK(NULL, "dss_32khz_clk", "dss_cm:0000:11"),
- DT_CLK(NULL, "dss_48mhz_clk", "dss_cm:0000:9"),
- DT_CLK(NULL, "dss_dss_clk", "dss_cm:0000:8"),
- DT_CLK(NULL, "dss_hdmi_clk", "dss_cm:0000:10"),
- DT_CLK(NULL, "dss_video1_clk", "dss_cm:0000:12"),
- DT_CLK(NULL, "dss_video2_clk", "dss_cm:0000:13"),
- DT_CLK(NULL, "gmac_rft_clk_mux", "l3init_cm:00b0:25"),
- DT_CLK(NULL, "gpio1_dbclk", "wkupaon_cm:0018:8"),
- DT_CLK(NULL, "gpio2_dbclk", "l4per_cm:0060:8"),
- DT_CLK(NULL, "gpio3_dbclk", "l4per_cm:0068:8"),
- DT_CLK(NULL, "gpio4_dbclk", "l4per_cm:0070:8"),
- DT_CLK(NULL, "gpio5_dbclk", "l4per_cm:0078:8"),
- DT_CLK(NULL, "gpio6_dbclk", "l4per_cm:0080:8"),
- DT_CLK(NULL, "gpio7_dbclk", "l4per_cm:0110:8"),
- DT_CLK(NULL, "gpio8_dbclk", "l4per_cm:0118:8"),
- DT_CLK(NULL, "mcasp1_ahclkr_mux", "ipu_cm:0010:28"),
- DT_CLK(NULL, "mcasp1_ahclkx_mux", "ipu_cm:0010:24"),
- DT_CLK(NULL, "mcasp1_aux_gfclk_mux", "ipu_cm:0010:22"),
- DT_CLK(NULL, "mcasp2_ahclkr_mux", "l4per_cm:0160:28"),
- DT_CLK(NULL, "mcasp2_ahclkx_mux", "l4per_cm:0160:24"),
- DT_CLK(NULL, "mcasp2_aux_gfclk_mux", "l4per_cm:0160:22"),
- DT_CLK(NULL, "mcasp3_ahclkx_mux", "l4per_cm:0168:24"),
- DT_CLK(NULL, "mcasp3_aux_gfclk_mux", "l4per_cm:0168:22"),
- DT_CLK(NULL, "mcasp4_ahclkx_mux", "l4per_cm:0198:24"),
- DT_CLK(NULL, "mcasp4_aux_gfclk_mux", "l4per_cm:0198:22"),
- DT_CLK(NULL, "mcasp5_ahclkx_mux", "l4per_cm:0178:24"),
- DT_CLK(NULL, "mcasp5_aux_gfclk_mux", "l4per_cm:0178:22"),
- DT_CLK(NULL, "mcasp6_ahclkx_mux", "l4per_cm:0204:24"),
- DT_CLK(NULL, "mcasp6_aux_gfclk_mux", "l4per_cm:0204:22"),
- DT_CLK(NULL, "mcasp7_ahclkx_mux", "l4per_cm:0208:24"),
- DT_CLK(NULL, "mcasp7_aux_gfclk_mux", "l4per_cm:0208:22"),
- DT_CLK(NULL, "mcasp8_ahclkx_mux", "l4per_cm:0190:22"),
- DT_CLK(NULL, "mcasp8_aux_gfclk_mux", "l4per_cm:0190:24"),
- DT_CLK(NULL, "mmc1_clk32k", "l3init_cm:0008:8"),
- DT_CLK(NULL, "mmc1_fclk_div", "l3init_cm:0008:25"),
- DT_CLK(NULL, "mmc1_fclk_mux", "l3init_cm:0008:24"),
- DT_CLK(NULL, "mmc2_clk32k", "l3init_cm:0010:8"),
- DT_CLK(NULL, "mmc2_fclk_div", "l3init_cm:0010:25"),
- DT_CLK(NULL, "mmc2_fclk_mux", "l3init_cm:0010:24"),
- DT_CLK(NULL, "mmc3_clk32k", "l4per_cm:0120:8"),
- DT_CLK(NULL, "mmc3_gfclk_div", "l4per_cm:0120:25"),
- DT_CLK(NULL, "mmc3_gfclk_mux", "l4per_cm:0120:24"),
- DT_CLK(NULL, "mmc4_clk32k", "l4per_cm:0128:8"),
- DT_CLK(NULL, "mmc4_gfclk_div", "l4per_cm:0128:25"),
- DT_CLK(NULL, "mmc4_gfclk_mux", "l4per_cm:0128:24"),
- DT_CLK(NULL, "optfclk_pciephy1_32khz", "l3init_cm:0090:8"),
- DT_CLK(NULL, "optfclk_pciephy1_clk", "l3init_cm:0090:9"),
- DT_CLK(NULL, "optfclk_pciephy1_div_clk", "l3init_cm:0090:10"),
- DT_CLK(NULL, "optfclk_pciephy2_32khz", "l3init_cm:0098:8"),
- DT_CLK(NULL, "optfclk_pciephy2_clk", "l3init_cm:0098:9"),
- DT_CLK(NULL, "optfclk_pciephy2_div_clk", "l3init_cm:0098:10"),
- DT_CLK(NULL, "qspi_gfclk_div", "l4per_cm:0138:25"),
- DT_CLK(NULL, "qspi_gfclk_mux", "l4per_cm:0138:24"),
- DT_CLK(NULL, "rmii_50mhz_clk_mux", "l3init_cm:00b0:24"),
- DT_CLK(NULL, "sata_ref_clk", "l3init_cm:0068:8"),
- DT_CLK(NULL, "timer10_gfclk_mux", "l4per_cm:0028:24"),
- DT_CLK(NULL, "timer11_gfclk_mux", "l4per_cm:0030:24"),
- DT_CLK(NULL, "timer13_gfclk_mux", "l4per_cm:00c8:24"),
- DT_CLK(NULL, "timer14_gfclk_mux", "l4per_cm:00d0:24"),
- DT_CLK(NULL, "timer15_gfclk_mux", "l4per_cm:00d8:24"),
- DT_CLK(NULL, "timer16_gfclk_mux", "l4per_cm:0130:24"),
- DT_CLK(NULL, "timer1_gfclk_mux", "wkupaon_cm:0020:24"),
- DT_CLK(NULL, "timer2_gfclk_mux", "l4per_cm:0038:24"),
- DT_CLK(NULL, "timer3_gfclk_mux", "l4per_cm:0040:24"),
- DT_CLK(NULL, "timer4_gfclk_mux", "l4per_cm:0048:24"),
- DT_CLK(NULL, "timer5_gfclk_mux", "ipu_cm:0018:24"),
- DT_CLK(NULL, "timer6_gfclk_mux", "ipu_cm:0020:24"),
- DT_CLK(NULL, "timer7_gfclk_mux", "ipu_cm:0028:24"),
- DT_CLK(NULL, "timer8_gfclk_mux", "ipu_cm:0030:24"),
- DT_CLK(NULL, "timer9_gfclk_mux", "l4per_cm:0050:24"),
- DT_CLK(NULL, "uart10_gfclk_mux", "wkupaon_cm:0060:24"),
- DT_CLK(NULL, "uart1_gfclk_mux", "l4per_cm:0140:24"),
- DT_CLK(NULL, "uart2_gfclk_mux", "l4per_cm:0148:24"),
- DT_CLK(NULL, "uart3_gfclk_mux", "l4per_cm:0150:24"),
- DT_CLK(NULL, "uart4_gfclk_mux", "l4per_cm:0158:24"),
- DT_CLK(NULL, "uart5_gfclk_mux", "l4per_cm:0170:24"),
- DT_CLK(NULL, "uart6_gfclk_mux", "ipu_cm:0040:24"),
- DT_CLK(NULL, "uart7_gfclk_mux", "l4per_cm:01d0:24"),
- DT_CLK(NULL, "uart8_gfclk_mux", "l4per_cm:01e0:24"),
- DT_CLK(NULL, "uart9_gfclk_mux", "l4per_cm:01e8:24"),
- DT_CLK(NULL, "usb_otg_ss1_refclk960m", "l3init_cm:00d0:8"),
- DT_CLK(NULL, "usb_otg_ss2_refclk960m", "l3init_cm:0020:8"),
+ DT_CLK(NULL, "atl_dpll_clk_mux", "atl-clkctrl:0000:24"),
+ DT_CLK(NULL, "atl_gfclk_mux", "atl-clkctrl:0000:26"),
+ DT_CLK(NULL, "dcan1_sys_clk_mux", "wkupaon-clkctrl:0068:24"),
+ DT_CLK(NULL, "dss_32khz_clk", "dss-clkctrl:0000:11"),
+ DT_CLK(NULL, "dss_48mhz_clk", "dss-clkctrl:0000:9"),
+ DT_CLK(NULL, "dss_dss_clk", "dss-clkctrl:0000:8"),
+ DT_CLK(NULL, "dss_hdmi_clk", "dss-clkctrl:0000:10"),
+ DT_CLK(NULL, "dss_video1_clk", "dss-clkctrl:0000:12"),
+ DT_CLK(NULL, "dss_video2_clk", "dss-clkctrl:0000:13"),
+ DT_CLK(NULL, "gmac_rft_clk_mux", "gmac-clkctrl:0000:25"),
+ DT_CLK(NULL, "gpio1_dbclk", "wkupaon-clkctrl:0018:8"),
+ DT_CLK(NULL, "gpio2_dbclk", "l4per-clkctrl:0038:8"),
+ DT_CLK(NULL, "gpio3_dbclk", "l4per-clkctrl:0040:8"),
+ DT_CLK(NULL, "gpio4_dbclk", "l4per-clkctrl:0048:8"),
+ DT_CLK(NULL, "gpio5_dbclk", "l4per-clkctrl:0050:8"),
+ DT_CLK(NULL, "gpio6_dbclk", "l4per-clkctrl:0058:8"),
+ DT_CLK(NULL, "gpio7_dbclk", "l4per-clkctrl:00e8:8"),
+ DT_CLK(NULL, "gpio8_dbclk", "l4per-clkctrl:00f0:8"),
+ DT_CLK(NULL, "ipu1_gfclk_mux", "ipu1-clkctrl:0000:24"),
+ DT_CLK(NULL, "mcasp1_ahclkr_mux", "ipu-clkctrl:0000:28"),
+ DT_CLK(NULL, "mcasp1_ahclkx_mux", "ipu-clkctrl:0000:24"),
+ DT_CLK(NULL, "mcasp1_aux_gfclk_mux", "ipu-clkctrl:0000:22"),
+ DT_CLK(NULL, "mcasp2_ahclkr_mux", "l4per2-clkctrl:0154:28"),
+ DT_CLK(NULL, "mcasp2_ahclkx_mux", "l4per2-clkctrl:0154:24"),
+ DT_CLK(NULL, "mcasp2_aux_gfclk_mux", "l4per2-clkctrl:0154:22"),
+ DT_CLK(NULL, "mcasp3_ahclkx_mux", "l4per2-clkctrl:015c:24"),
+ DT_CLK(NULL, "mcasp3_aux_gfclk_mux", "l4per2-clkctrl:015c:22"),
+ DT_CLK(NULL, "mcasp4_ahclkx_mux", "l4per2-clkctrl:018c:24"),
+ DT_CLK(NULL, "mcasp4_aux_gfclk_mux", "l4per2-clkctrl:018c:22"),
+ DT_CLK(NULL, "mcasp5_ahclkx_mux", "l4per2-clkctrl:016c:24"),
+ DT_CLK(NULL, "mcasp5_aux_gfclk_mux", "l4per2-clkctrl:016c:22"),
+ DT_CLK(NULL, "mcasp6_ahclkx_mux", "l4per2-clkctrl:01f8:24"),
+ DT_CLK(NULL, "mcasp6_aux_gfclk_mux", "l4per2-clkctrl:01f8:22"),
+ DT_CLK(NULL, "mcasp7_ahclkx_mux", "l4per2-clkctrl:01fc:24"),
+ DT_CLK(NULL, "mcasp7_aux_gfclk_mux", "l4per2-clkctrl:01fc:22"),
+ DT_CLK(NULL, "mcasp8_ahclkx_mux", "l4per2-clkctrl:0184:22"),
+ DT_CLK(NULL, "mcasp8_aux_gfclk_mux", "l4per2-clkctrl:0184:24"),
+ DT_CLK(NULL, "mmc1_clk32k", "l3init-clkctrl:0008:8"),
+ DT_CLK(NULL, "mmc1_fclk_div", "l3init-clkctrl:0008:25"),
+ DT_CLK(NULL, "mmc1_fclk_mux", "l3init-clkctrl:0008:24"),
+ DT_CLK(NULL, "mmc2_clk32k", "l3init-clkctrl:0010:8"),
+ DT_CLK(NULL, "mmc2_fclk_div", "l3init-clkctrl:0010:25"),
+ DT_CLK(NULL, "mmc2_fclk_mux", "l3init-clkctrl:0010:24"),
+ DT_CLK(NULL, "mmc3_clk32k", "l4per-clkctrl:00f8:8"),
+ DT_CLK(NULL, "mmc3_gfclk_div", "l4per-clkctrl:00f8:25"),
+ DT_CLK(NULL, "mmc3_gfclk_mux", "l4per-clkctrl:00f8:24"),
+ DT_CLK(NULL, "mmc4_clk32k", "l4per-clkctrl:0100:8"),
+ DT_CLK(NULL, "mmc4_gfclk_div", "l4per-clkctrl:0100:25"),
+ DT_CLK(NULL, "mmc4_gfclk_mux", "l4per-clkctrl:0100:24"),
+ DT_CLK(NULL, "optfclk_pciephy1_32khz", "pcie-clkctrl:0000:8"),
+ DT_CLK(NULL, "optfclk_pciephy1_clk", "pcie-clkctrl:0000:9"),
+ DT_CLK(NULL, "optfclk_pciephy1_div_clk", "pcie-clkctrl:0000:10"),
+ DT_CLK(NULL, "optfclk_pciephy2_32khz", "pcie-clkctrl:0008:8"),
+ DT_CLK(NULL, "optfclk_pciephy2_clk", "pcie-clkctrl:0008:9"),
+ DT_CLK(NULL, "optfclk_pciephy2_div_clk", "pcie-clkctrl:0008:10"),
+ DT_CLK(NULL, "qspi_gfclk_div", "l4per2-clkctrl:012c:25"),
+ DT_CLK(NULL, "qspi_gfclk_mux", "l4per2-clkctrl:012c:24"),
+ DT_CLK(NULL, "rmii_50mhz_clk_mux", "gmac-clkctrl:0000:24"),
+ DT_CLK(NULL, "sata_ref_clk", "l3init-clkctrl:0068:8"),
+ DT_CLK(NULL, "timer10_gfclk_mux", "l4per-clkctrl:0000:24"),
+ DT_CLK(NULL, "timer11_gfclk_mux", "l4per-clkctrl:0008:24"),
+ DT_CLK(NULL, "timer13_gfclk_mux", "l4per3-clkctrl:00b4:24"),
+ DT_CLK(NULL, "timer14_gfclk_mux", "l4per3-clkctrl:00bc:24"),
+ DT_CLK(NULL, "timer15_gfclk_mux", "l4per3-clkctrl:00c4:24"),
+ DT_CLK(NULL, "timer16_gfclk_mux", "l4per3-clkctrl:011c:24"),
+ DT_CLK(NULL, "timer1_gfclk_mux", "wkupaon-clkctrl:0020:24"),
+ DT_CLK(NULL, "timer2_gfclk_mux", "l4per-clkctrl:0010:24"),
+ DT_CLK(NULL, "timer3_gfclk_mux", "l4per-clkctrl:0018:24"),
+ DT_CLK(NULL, "timer4_gfclk_mux", "l4per-clkctrl:0020:24"),
+ DT_CLK(NULL, "timer5_gfclk_mux", "ipu-clkctrl:0008:24"),
+ DT_CLK(NULL, "timer6_gfclk_mux", "ipu-clkctrl:0010:24"),
+ DT_CLK(NULL, "timer7_gfclk_mux", "ipu-clkctrl:0018:24"),
+ DT_CLK(NULL, "timer8_gfclk_mux", "ipu-clkctrl:0020:24"),
+ DT_CLK(NULL, "timer9_gfclk_mux", "l4per-clkctrl:0028:24"),
+ DT_CLK(NULL, "uart10_gfclk_mux", "wkupaon-clkctrl:0060:24"),
+ DT_CLK(NULL, "uart1_gfclk_mux", "l4per-clkctrl:0118:24"),
+ DT_CLK(NULL, "uart2_gfclk_mux", "l4per-clkctrl:0120:24"),
+ DT_CLK(NULL, "uart3_gfclk_mux", "l4per-clkctrl:0128:24"),
+ DT_CLK(NULL, "uart4_gfclk_mux", "l4per-clkctrl:0130:24"),
+ DT_CLK(NULL, "uart5_gfclk_mux", "l4per-clkctrl:0148:24"),
+ DT_CLK(NULL, "uart6_gfclk_mux", "ipu-clkctrl:0030:24"),
+ DT_CLK(NULL, "uart7_gfclk_mux", "l4per2-clkctrl:01c4:24"),
+ DT_CLK(NULL, "uart8_gfclk_mux", "l4per2-clkctrl:01d4:24"),
+ DT_CLK(NULL, "uart9_gfclk_mux", "l4per2-clkctrl:01dc:24"),
+ DT_CLK(NULL, "usb_otg_ss1_refclk960m", "l3init-clkctrl:00d0:8"),
+ DT_CLK(NULL, "usb_otg_ss2_refclk960m", "l3init-clkctrl:0020:8"),
{ .node_name = NULL },
};
@@ -827,7 +890,10 @@ int __init dra7xx_dt_clk_init(void)
int rc;
struct clk *dpll_ck, *hdcp_ck;
- ti_dt_clocks_register(dra7xx_clks);
+ if (ti_clk_get_features()->flags & TI_CLK_CLKCTRL_COMPAT)
+ ti_dt_clocks_register(dra7xx_compat_clks);
+ else
+ ti_dt_clocks_register(dra7xx_clks);
omap2_clk_disable_autoidle_all();
diff --git a/drivers/clk/ti/clk-dra7-atl.c b/drivers/clk/ti/clk-dra7-atl.c
index 148815470431..a01ca9395179 100644
--- a/drivers/clk/ti/clk-dra7-atl.c
+++ b/drivers/clk/ti/clk-dra7-atl.c
@@ -190,8 +190,8 @@ static void __init of_dra7_atl_clock_setup(struct device_node *node)
init.num_parents = of_clk_get_parent_count(node);
if (init.num_parents != 1) {
- pr_err("%s: atl clock %s must have 1 parent\n", __func__,
- node->name);
+ pr_err("%s: atl clock %pOFn must have 1 parent\n", __func__,
+ node);
goto cleanup;
}
diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c
index 7d22e1af2247..d0cd58534781 100644
--- a/drivers/clk/ti/clk.c
+++ b/drivers/clk/ti/clk.c
@@ -23,7 +23,7 @@
#include <linux/of_address.h>
#include <linux/list.h>
#include <linux/regmap.h>
-#include <linux/bootmem.h>
+#include <linux/memblock.h>
#include <linux/device.h>
#include "clock.h"
@@ -34,7 +34,7 @@
struct ti_clk_ll_ops *ti_clk_ll_ops;
static struct device_node *clocks_node_ptr[CLK_MAX_MEMMAPS];
-static struct ti_clk_features ti_clk_features;
+struct ti_clk_features ti_clk_features;
struct clk_iomap {
struct regmap *regmap;
@@ -129,7 +129,7 @@ int ti_clk_setup_ll_ops(struct ti_clk_ll_ops *ops)
void __init ti_dt_clocks_register(struct ti_dt_clk oclks[])
{
struct ti_dt_clk *c;
- struct device_node *node;
+ struct device_node *node, *parent;
struct clk *clk;
struct of_phandle_args clkspec;
char buf[64];
@@ -140,6 +140,9 @@ void __init ti_dt_clocks_register(struct ti_dt_clk oclks[])
int ret;
static bool clkctrl_nodes_missing;
static bool has_clkctrl_data;
+ static bool compat_mode;
+
+ compat_mode = ti_clk_get_features()->flags & TI_CLK_CLKCTRL_COMPAT;
for (c = oclks; c->node_name != NULL; c++) {
strcpy(buf, c->node_name);
@@ -164,8 +167,12 @@ void __init ti_dt_clocks_register(struct ti_dt_clk oclks[])
continue;
node = of_find_node_by_name(NULL, buf);
- if (num_args)
- node = of_find_node_by_name(node, "clk");
+ if (num_args && compat_mode) {
+ parent = node;
+ node = of_get_child_by_name(parent, "clk");
+ of_node_put(parent);
+ }
+
clkspec.np = node;
clkspec.args_count = num_args;
for (i = 0; i < num_args; i++) {
@@ -173,11 +180,12 @@ void __init ti_dt_clocks_register(struct ti_dt_clk oclks[])
if (ret) {
pr_warn("Bad tag in %s at %d: %s\n",
c->node_name, i, tags[i]);
+ of_node_put(node);
return;
}
}
clk = of_clk_get_from_provider(&clkspec);
-
+ of_node_put(node);
if (!IS_ERR(clk)) {
c->lk.clk = clk;
clkdev_add(&c->lk);
@@ -223,7 +231,7 @@ int __init ti_clk_retry_init(struct device_node *node, void *user,
{
struct clk_init_item *retry;
- pr_debug("%s: adding to retry list...\n", node->name);
+ pr_debug("%pOFn: adding to retry list...\n", node);
retry = kzalloc(sizeof(*retry), GFP_KERNEL);
if (!retry)
return -ENOMEM;
@@ -258,14 +266,14 @@ int ti_clk_get_reg_addr(struct device_node *node, int index,
}
if (i == CLK_MAX_MEMMAPS) {
- pr_err("clk-provider not found for %s!\n", node->name);
+ pr_err("clk-provider not found for %pOFn!\n", node);
return -ENOENT;
}
reg->index = i;
if (of_property_read_u32_index(node, "reg", index, &val)) {
- pr_err("%s must have reg[%d]!\n", node->name, index);
+ pr_err("%pOFn must have reg[%d]!\n", node, index);
return -EINVAL;
}
@@ -312,7 +320,7 @@ int __init omap2_clk_provider_init(struct device_node *parent, int index,
/* get clocks for this parent */
clocks = of_get_child_by_name(parent, "clocks");
if (!clocks) {
- pr_err("%s missing 'clocks' child node.\n", parent->name);
+ pr_err("%pOFn missing 'clocks' child node.\n", parent);
return -EINVAL;
}
@@ -342,7 +350,7 @@ void __init omap2_clk_legacy_provider_init(int index, void __iomem *mem)
{
struct clk_iomap *io;
- io = memblock_virt_alloc(sizeof(*io), 0);
+ io = memblock_alloc(sizeof(*io), SMP_CACHE_BYTES);
io->mem = mem;
@@ -365,7 +373,7 @@ void ti_dt_clk_init_retry_clks(void)
while (!list_empty(&retry_list) && retries) {
list_for_each_entry_safe(retry, tmp, &retry_list, link) {
- pr_debug("retry-init: %s\n", retry->node->name);
+ pr_debug("retry-init: %pOFn\n", retry->node);
retry->func(retry->user, retry->node);
list_del(&retry->link);
kfree(retry);
diff --git a/drivers/clk/ti/clkctrl.c b/drivers/clk/ti/clkctrl.c
index 421b05392220..469f560ae1cf 100644
--- a/drivers/clk/ti/clkctrl.c
+++ b/drivers/clk/ti/clkctrl.c
@@ -259,8 +259,13 @@ _ti_clkctrl_clk_register(struct omap_clkctrl_provider *provider,
struct omap_clkctrl_clk *clkctrl_clk;
int ret = 0;
- init.name = kasprintf(GFP_KERNEL, "%s:%s:%04x:%d", node->parent->name,
- node->name, offset, bit);
+ if (ti_clk_get_features()->flags & TI_CLK_CLKCTRL_COMPAT)
+ init.name = kasprintf(GFP_KERNEL, "%pOFn:%pOFn:%04x:%d",
+ node->parent, node, offset,
+ bit);
+ else
+ init.name = kasprintf(GFP_KERNEL, "%pOFn:%04x:%d", node,
+ offset, bit);
clkctrl_clk = kzalloc(sizeof(*clkctrl_clk), GFP_KERNEL);
if (!init.name || !clkctrl_clk) {
ret = -ENOMEM;
@@ -440,6 +445,11 @@ static void __init _ti_omap4_clkctrl_setup(struct device_node *node)
const __be32 *addrp;
u32 addr;
int ret;
+ char *c;
+
+ if (!(ti_clk_get_features()->flags & TI_CLK_CLKCTRL_COMPAT) &&
+ !strcmp(node->name, "clk"))
+ ti_clk_features.flags |= TI_CLK_CLKCTRL_COMPAT;
addrp = of_get_address(node, 0, NULL, NULL);
addr = (u32)of_translate_address(node, addrp);
@@ -453,18 +463,35 @@ static void __init _ti_omap4_clkctrl_setup(struct device_node *node)
data = omap5_clkctrl_data;
#endif
#ifdef CONFIG_SOC_DRA7XX
- if (of_machine_is_compatible("ti,dra7"))
- data = dra7_clkctrl_data;
+ if (of_machine_is_compatible("ti,dra7")) {
+ if (ti_clk_get_features()->flags & TI_CLK_CLKCTRL_COMPAT)
+ data = dra7_clkctrl_compat_data;
+ else
+ data = dra7_clkctrl_data;
+ }
#endif
#ifdef CONFIG_SOC_AM33XX
- if (of_machine_is_compatible("ti,am33xx"))
- data = am3_clkctrl_data;
+ if (of_machine_is_compatible("ti,am33xx")) {
+ if (ti_clk_get_features()->flags & TI_CLK_CLKCTRL_COMPAT)
+ data = am3_clkctrl_compat_data;
+ else
+ data = am3_clkctrl_data;
+ }
#endif
#ifdef CONFIG_SOC_AM43XX
- if (of_machine_is_compatible("ti,am4372"))
- data = am4_clkctrl_data;
- if (of_machine_is_compatible("ti,am438x"))
- data = am438x_clkctrl_data;
+ if (of_machine_is_compatible("ti,am4372")) {
+ if (ti_clk_get_features()->flags & TI_CLK_CLKCTRL_COMPAT)
+ data = am4_clkctrl_compat_data;
+ else
+ data = am4_clkctrl_data;
+ }
+
+ if (of_machine_is_compatible("ti,am438x")) {
+ if (ti_clk_get_features()->flags & TI_CLK_CLKCTRL_COMPAT)
+ data = am438x_clkctrl_compat_data;
+ else
+ data = am438x_clkctrl_data;
+ }
#endif
#ifdef CONFIG_SOC_TI81XX
if (of_machine_is_compatible("ti,dm814"))
@@ -492,21 +519,43 @@ static void __init _ti_omap4_clkctrl_setup(struct device_node *node)
provider->base = of_iomap(node, 0);
- provider->clkdm_name = kmalloc(strlen(node->parent->name) + 3,
- GFP_KERNEL);
- if (!provider->clkdm_name) {
- kfree(provider);
- return;
+ if (ti_clk_get_features()->flags & TI_CLK_CLKCTRL_COMPAT) {
+ provider->clkdm_name = kasprintf(GFP_KERNEL, "%pOFnxxx", node->parent);
+ if (!provider->clkdm_name) {
+ kfree(provider);
+ return;
+ }
+
+ /*
+ * Create default clkdm name, replace _cm from end of parent
+ * node name with _clkdm
+ */
+ provider->clkdm_name[strlen(provider->clkdm_name) - 5] = 0;
+ } else {
+ provider->clkdm_name = kasprintf(GFP_KERNEL, "%pOFn", node);
+ if (!provider->clkdm_name) {
+ kfree(provider);
+ return;
+ }
+
+ /*
+ * Create default clkdm name, replace _clkctrl from end of
+ * node name with _clkdm
+ */
+ provider->clkdm_name[strlen(provider->clkdm_name) - 7] = 0;
}
- /*
- * Create default clkdm name, replace _cm from end of parent node
- * name with _clkdm
- */
- strcpy(provider->clkdm_name, node->parent->name);
- provider->clkdm_name[strlen(provider->clkdm_name) - 2] = 0;
strcat(provider->clkdm_name, "clkdm");
+ /* Replace any dash from the clkdm name with underscore */
+ c = provider->clkdm_name;
+
+ while (*c) {
+ if (*c == '-')
+ *c = '_';
+ c++;
+ }
+
INIT_LIST_HEAD(&provider->clocks);
/* Generate clocks */
@@ -539,9 +588,13 @@ static void __init _ti_omap4_clkctrl_setup(struct device_node *node)
init.flags = 0;
if (reg_data->flags & CLKF_SET_RATE_PARENT)
init.flags |= CLK_SET_RATE_PARENT;
- init.name = kasprintf(GFP_KERNEL, "%s:%s:%04x:%d",
- node->parent->name, node->name,
- reg_data->offset, 0);
+ if (ti_clk_get_features()->flags & TI_CLK_CLKCTRL_COMPAT)
+ init.name = kasprintf(GFP_KERNEL, "%pOFn:%pOFn:%04x:%d",
+ node->parent, node,
+ reg_data->offset, 0);
+ else
+ init.name = kasprintf(GFP_KERNEL, "%pOFn:%04x:%d",
+ node, reg_data->offset, 0);
clkctrl_clk = kzalloc(sizeof(*clkctrl_clk), GFP_KERNEL);
if (!init.name || !clkctrl_clk)
goto cleanup;
diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h
index b58278077226..9f312a219510 100644
--- a/drivers/clk/ti/clock.h
+++ b/drivers/clk/ti/clock.h
@@ -24,6 +24,7 @@ struct clk_omap_divider {
u8 flags;
s8 latch;
const struct clk_div_table *table;
+ u32 context;
};
#define to_clk_omap_divider(_hw) container_of(_hw, struct clk_omap_divider, hw)
@@ -36,6 +37,7 @@ struct clk_omap_mux {
u8 shift;
s8 latch;
u8 flags;
+ u8 saved_parent;
};
#define to_clk_omap_mux(_hw) container_of(_hw, struct clk_omap_mux, hw)
@@ -184,9 +186,16 @@ struct omap_clkctrl_data {
extern const struct omap_clkctrl_data omap4_clkctrl_data[];
extern const struct omap_clkctrl_data omap5_clkctrl_data[];
extern const struct omap_clkctrl_data dra7_clkctrl_data[];
+extern const struct omap_clkctrl_data dra7_clkctrl_compat_data[];
+extern struct ti_dt_clk dra7xx_compat_clks[];
extern const struct omap_clkctrl_data am3_clkctrl_data[];
+extern const struct omap_clkctrl_data am3_clkctrl_compat_data[];
+extern struct ti_dt_clk am33xx_compat_clks[];
extern const struct omap_clkctrl_data am4_clkctrl_data[];
+extern const struct omap_clkctrl_data am4_clkctrl_compat_data[];
+extern struct ti_dt_clk am43xx_compat_clks[];
extern const struct omap_clkctrl_data am438x_clkctrl_data[];
+extern const struct omap_clkctrl_data am438x_clkctrl_compat_data[];
extern const struct omap_clkctrl_data dm814_clkctrl_data[];
extern const struct omap_clkctrl_data dm816_clkctrl_data[];
@@ -233,6 +242,8 @@ extern const struct clk_ops ti_clk_divider_ops;
extern const struct clk_ops ti_clk_mux_ops;
extern const struct clk_ops omap_gate_clk_ops;
+extern struct ti_clk_features ti_clk_features;
+
void omap2_init_clk_clkdm(struct clk_hw *hw);
int omap2_clkops_enable_clkdm(struct clk_hw *hw);
void omap2_clkops_disable_clkdm(struct clk_hw *hw);
diff --git a/drivers/clk/ti/composite.c b/drivers/clk/ti/composite.c
index 030e8b2c1050..6a89936ba03a 100644
--- a/drivers/clk/ti/composite.c
+++ b/drivers/clk/ti/composite.c
@@ -135,8 +135,8 @@ static void __init _register_composite(void *user,
comp = _lookup_component(cclk->comp_nodes[i]);
if (!comp) {
- pr_debug("component %s not ready for %s, retry\n",
- cclk->comp_nodes[i]->name, node->name);
+ pr_debug("component %s not ready for %pOFn, retry\n",
+ cclk->comp_nodes[i]->name, node);
if (!ti_clk_retry_init(node, hw,
_register_composite))
return;
@@ -144,8 +144,8 @@ static void __init _register_composite(void *user,
goto cleanup;
}
if (cclk->comp_clks[comp->type] != NULL) {
- pr_err("duplicate component types for %s (%s)!\n",
- node->name, component_clk_types[comp->type]);
+ pr_err("duplicate component types for %pOFn (%s)!\n",
+ node, component_clk_types[comp->type]);
goto cleanup;
}
@@ -168,7 +168,7 @@ static void __init _register_composite(void *user,
}
if (!num_parents) {
- pr_err("%s: no parents found for %s!\n", __func__, node->name);
+ pr_err("%s: no parents found for %pOFn!\n", __func__, node);
goto cleanup;
}
@@ -212,7 +212,7 @@ static void __init of_ti_composite_clk_setup(struct device_node *node)
num_clks = of_clk_get_parent_count(node);
if (!num_clks) {
- pr_err("composite clk %s must have component(s)\n", node->name);
+ pr_err("composite clk %pOFn must have component(s)\n", node);
return;
}
@@ -248,7 +248,7 @@ int __init ti_clk_add_component(struct device_node *node, struct clk_hw *hw,
num_parents = of_clk_get_parent_count(node);
if (!num_parents) {
- pr_err("component-clock %s must have parent(s)\n", node->name);
+ pr_err("component-clock %pOFn must have parent(s)\n", node);
return -EINVAL;
}
diff --git a/drivers/clk/ti/divider.c b/drivers/clk/ti/divider.c
index ccfb4d9a152a..8d77090ad94a 100644
--- a/drivers/clk/ti/divider.c
+++ b/drivers/clk/ti/divider.c
@@ -268,10 +268,46 @@ static int ti_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
return 0;
}
+/**
+ * clk_divider_save_context - Save the divider value
+ * @hw: pointer struct clk_hw
+ *
+ * Save the divider value
+ */
+static int clk_divider_save_context(struct clk_hw *hw)
+{
+ struct clk_omap_divider *divider = to_clk_omap_divider(hw);
+ u32 val;
+
+ val = ti_clk_ll_ops->clk_readl(&divider->reg) >> divider->shift;
+ divider->context = val & div_mask(divider);
+
+ return 0;
+}
+
+/**
+ * clk_divider_restore_context - restore the saved the divider value
+ * @hw: pointer struct clk_hw
+ *
+ * Restore the saved the divider value
+ */
+static void clk_divider_restore_context(struct clk_hw *hw)
+{
+ struct clk_omap_divider *divider = to_clk_omap_divider(hw);
+ u32 val;
+
+ val = ti_clk_ll_ops->clk_readl(&divider->reg);
+ val &= ~(div_mask(divider) << divider->shift);
+ val |= divider->context << divider->shift;
+ ti_clk_ll_ops->clk_writel(val, &divider->reg);
+}
+
const struct clk_ops ti_clk_divider_ops = {
.recalc_rate = ti_clk_divider_recalc_rate,
.round_rate = ti_clk_divider_round_rate,
.set_rate = ti_clk_divider_set_rate,
+ .save_context = clk_divider_save_context,
+ .restore_context = clk_divider_restore_context,
};
static struct clk *_register_divider(struct device *dev, const char *name,
@@ -492,7 +528,7 @@ __init ti_clk_get_div_table(struct device_node *node)
}
if (!valid_div) {
- pr_err("no valid dividers for %s table\n", node->name);
+ pr_err("no valid dividers for %pOFn table\n", node);
return ERR_PTR(-EINVAL);
}
@@ -530,7 +566,7 @@ static int _get_divider_width(struct device_node *node,
min_div = 1;
if (of_property_read_u32(node, "ti,max-div", &max_div)) {
- pr_err("no max-div for %s!\n", node->name);
+ pr_err("no max-div for %pOFn!\n", node);
return -EINVAL;
}
diff --git a/drivers/clk/ti/dpll.c b/drivers/clk/ti/dpll.c
index dc86d07d0921..92e28af7afba 100644
--- a/drivers/clk/ti/dpll.c
+++ b/drivers/clk/ti/dpll.c
@@ -39,6 +39,8 @@ static const struct clk_ops dpll_m4xen_ck_ops = {
.set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent,
.determine_rate = &omap4_dpll_regm4xen_determine_rate,
.get_parent = &omap2_init_dpll_parent,
+ .save_context = &omap3_core_dpll_save_context,
+ .restore_context = &omap3_core_dpll_restore_context,
};
#else
static const struct clk_ops dpll_m4xen_ck_ops = {};
@@ -62,6 +64,8 @@ static const struct clk_ops dpll_ck_ops = {
.set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent,
.determine_rate = &omap3_noncore_dpll_determine_rate,
.get_parent = &omap2_init_dpll_parent,
+ .save_context = &omap3_noncore_dpll_save_context,
+ .restore_context = &omap3_noncore_dpll_restore_context,
};
static const struct clk_ops dpll_no_gate_ck_ops = {
@@ -72,6 +76,8 @@ static const struct clk_ops dpll_no_gate_ck_ops = {
.set_parent = &omap3_noncore_dpll_set_parent,
.set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent,
.determine_rate = &omap3_noncore_dpll_determine_rate,
+ .save_context = &omap3_noncore_dpll_save_context,
+ .restore_context = &omap3_noncore_dpll_restore_context
};
#else
static const struct clk_ops dpll_core_ck_ops = {};
@@ -162,8 +168,8 @@ static void __init _register_dpll(void *user,
clk = of_clk_get(node, 0);
if (IS_ERR(clk)) {
- pr_debug("clk-ref missing for %s, retry later\n",
- node->name);
+ pr_debug("clk-ref missing for %pOFn, retry later\n",
+ node);
if (!ti_clk_retry_init(node, hw, _register_dpll))
return;
@@ -175,8 +181,8 @@ static void __init _register_dpll(void *user,
clk = of_clk_get(node, 1);
if (IS_ERR(clk)) {
- pr_debug("clk-bypass missing for %s, retry later\n",
- node->name);
+ pr_debug("clk-bypass missing for %pOFn, retry later\n",
+ node);
if (!ti_clk_retry_init(node, hw, _register_dpll))
return;
@@ -226,7 +232,7 @@ static void _register_dpll_x2(struct device_node *node,
parent_name = of_clk_get_parent_name(node, 0);
if (!parent_name) {
- pr_err("%s must have parent\n", node->name);
+ pr_err("%pOFn must have parent\n", node);
return;
}
@@ -305,7 +311,7 @@ static void __init of_ti_dpll_setup(struct device_node *node,
init->num_parents = of_clk_get_parent_count(node);
if (!init->num_parents) {
- pr_err("%s must have parent(s)\n", node->name);
+ pr_err("%pOFn must have parent(s)\n", node);
goto cleanup;
}
diff --git a/drivers/clk/ti/dpll3xxx.c b/drivers/clk/ti/dpll3xxx.c
index 4534de2ef455..44b6b6403753 100644
--- a/drivers/clk/ti/dpll3xxx.c
+++ b/drivers/clk/ti/dpll3xxx.c
@@ -782,6 +782,130 @@ unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw,
return rate;
}
+/**
+ * omap3_core_dpll_save_context - Save the m and n values of the divider
+ * @hw: pointer struct clk_hw
+ *
+ * Before the dpll registers are lost save the last rounded rate m and n
+ * and the enable mask.
+ */
+int omap3_core_dpll_save_context(struct clk_hw *hw)
+{
+ struct clk_hw_omap *clk = to_clk_hw_omap(hw);
+ struct dpll_data *dd;
+ u32 v;
+
+ dd = clk->dpll_data;
+
+ v = ti_clk_ll_ops->clk_readl(&dd->control_reg);
+ clk->context = (v & dd->enable_mask) >> __ffs(dd->enable_mask);
+
+ if (clk->context == DPLL_LOCKED) {
+ v = ti_clk_ll_ops->clk_readl(&dd->mult_div1_reg);
+ dd->last_rounded_m = (v & dd->mult_mask) >>
+ __ffs(dd->mult_mask);
+ dd->last_rounded_n = ((v & dd->div1_mask) >>
+ __ffs(dd->div1_mask)) + 1;
+ }
+
+ return 0;
+}
+
+/**
+ * omap3_core_dpll_restore_context - restore the m and n values of the divider
+ * @hw: pointer struct clk_hw
+ *
+ * Restore the last rounded rate m and n
+ * and the enable mask.
+ */
+void omap3_core_dpll_restore_context(struct clk_hw *hw)
+{
+ struct clk_hw_omap *clk = to_clk_hw_omap(hw);
+ const struct dpll_data *dd;
+ u32 v;
+
+ dd = clk->dpll_data;
+
+ if (clk->context == DPLL_LOCKED) {
+ _omap3_dpll_write_clken(clk, 0x4);
+ _omap3_wait_dpll_status(clk, 0);
+
+ v = ti_clk_ll_ops->clk_readl(&dd->mult_div1_reg);
+ v &= ~(dd->mult_mask | dd->div1_mask);
+ v |= dd->last_rounded_m << __ffs(dd->mult_mask);
+ v |= (dd->last_rounded_n - 1) << __ffs(dd->div1_mask);
+ ti_clk_ll_ops->clk_writel(v, &dd->mult_div1_reg);
+
+ _omap3_dpll_write_clken(clk, DPLL_LOCKED);
+ _omap3_wait_dpll_status(clk, 1);
+ } else {
+ _omap3_dpll_write_clken(clk, clk->context);
+ }
+}
+
+/**
+ * omap3_non_core_dpll_save_context - Save the m and n values of the divider
+ * @hw: pointer struct clk_hw
+ *
+ * Before the dpll registers are lost save the last rounded rate m and n
+ * and the enable mask.
+ */
+int omap3_noncore_dpll_save_context(struct clk_hw *hw)
+{
+ struct clk_hw_omap *clk = to_clk_hw_omap(hw);
+ struct dpll_data *dd;
+ u32 v;
+
+ dd = clk->dpll_data;
+
+ v = ti_clk_ll_ops->clk_readl(&dd->control_reg);
+ clk->context = (v & dd->enable_mask) >> __ffs(dd->enable_mask);
+
+ if (clk->context == DPLL_LOCKED) {
+ v = ti_clk_ll_ops->clk_readl(&dd->mult_div1_reg);
+ dd->last_rounded_m = (v & dd->mult_mask) >>
+ __ffs(dd->mult_mask);
+ dd->last_rounded_n = ((v & dd->div1_mask) >>
+ __ffs(dd->div1_mask)) + 1;
+ }
+
+ return 0;
+}
+
+/**
+ * omap3_core_dpll_restore_context - restore the m and n values of the divider
+ * @hw: pointer struct clk_hw
+ *
+ * Restore the last rounded rate m and n
+ * and the enable mask.
+ */
+void omap3_noncore_dpll_restore_context(struct clk_hw *hw)
+{
+ struct clk_hw_omap *clk = to_clk_hw_omap(hw);
+ const struct dpll_data *dd;
+ u32 ctrl, mult_div1;
+
+ dd = clk->dpll_data;
+
+ ctrl = ti_clk_ll_ops->clk_readl(&dd->control_reg);
+ mult_div1 = ti_clk_ll_ops->clk_readl(&dd->mult_div1_reg);
+
+ if (clk->context == ((ctrl & dd->enable_mask) >>
+ __ffs(dd->enable_mask)) &&
+ dd->last_rounded_m == ((mult_div1 & dd->mult_mask) >>
+ __ffs(dd->mult_mask)) &&
+ dd->last_rounded_n == ((mult_div1 & dd->div1_mask) >>
+ __ffs(dd->div1_mask)) + 1) {
+ /* nothing to be done */
+ return;
+ }
+
+ if (clk->context == DPLL_LOCKED)
+ omap3_noncore_dpll_program(clk, 0);
+ else
+ _omap3_dpll_write_clken(clk, clk->context);
+}
+
/* OMAP3/4 non-CORE DPLL clkops */
const struct clk_hw_omap_ops clkhwops_omap3_dpll = {
.allow_idle = omap3_dpll_allow_idle,
diff --git a/drivers/clk/ti/fapll.c b/drivers/clk/ti/fapll.c
index 071af44b1ba8..ed24f20f63c7 100644
--- a/drivers/clk/ti/fapll.c
+++ b/drivers/clk/ti/fapll.c
@@ -555,7 +555,7 @@ static void __init ti_fapll_setup(struct device_node *node)
init->num_parents = of_clk_get_parent_count(node);
if (init->num_parents != 2) {
- pr_err("%s must have two parents\n", node->name);
+ pr_err("%pOFn must have two parents\n", node);
goto free;
}
@@ -564,19 +564,19 @@ static void __init ti_fapll_setup(struct device_node *node)
fd->clk_ref = of_clk_get(node, 0);
if (IS_ERR(fd->clk_ref)) {
- pr_err("%s could not get clk_ref\n", node->name);
+ pr_err("%pOFn could not get clk_ref\n", node);
goto free;
}
fd->clk_bypass = of_clk_get(node, 1);
if (IS_ERR(fd->clk_bypass)) {
- pr_err("%s could not get clk_bypass\n", node->name);
+ pr_err("%pOFn could not get clk_bypass\n", node);
goto free;
}
fd->base = of_iomap(node, 0);
if (!fd->base) {
- pr_err("%s could not get IO base\n", node->name);
+ pr_err("%pOFn could not get IO base\n", node);
goto free;
}
diff --git a/drivers/clk/ti/fixed-factor.c b/drivers/clk/ti/fixed-factor.c
index 0174a51a4ba6..7cbe896db071 100644
--- a/drivers/clk/ti/fixed-factor.c
+++ b/drivers/clk/ti/fixed-factor.c
@@ -42,12 +42,12 @@ static void __init of_ti_fixed_factor_clk_setup(struct device_node *node)
u32 flags = 0;
if (of_property_read_u32(node, "ti,clock-div", &div)) {
- pr_err("%s must have a clock-div property\n", node->name);
+ pr_err("%pOFn must have a clock-div property\n", node);
return;
}
if (of_property_read_u32(node, "ti,clock-mult", &mult)) {
- pr_err("%s must have a clock-mult property\n", node->name);
+ pr_err("%pOFn must have a clock-mult property\n", node);
return;
}
diff --git a/drivers/clk/ti/gate.c b/drivers/clk/ti/gate.c
index 935b2de5fb88..1c78fff5513c 100644
--- a/drivers/clk/ti/gate.c
+++ b/drivers/clk/ti/gate.c
@@ -33,6 +33,7 @@ static const struct clk_ops omap_gate_clkdm_clk_ops = {
.init = &omap2_init_clk_clkdm,
.enable = &omap2_clkops_enable_clkdm,
.disable = &omap2_clkops_disable_clkdm,
+ .restore_context = clk_gate_restore_context,
};
const struct clk_ops omap_gate_clk_ops = {
@@ -40,6 +41,7 @@ const struct clk_ops omap_gate_clk_ops = {
.enable = &omap2_dflt_clk_enable,
.disable = &omap2_dflt_clk_disable,
.is_enabled = &omap2_dflt_clk_is_enabled,
+ .restore_context = clk_gate_restore_context,
};
static const struct clk_ops omap_gate_clk_hsdiv_restore_ops = {
@@ -47,6 +49,7 @@ static const struct clk_ops omap_gate_clk_hsdiv_restore_ops = {
.enable = &omap36xx_gate_clk_enable_with_hsdiv_restore,
.disable = &omap2_dflt_clk_disable,
.is_enabled = &omap2_dflt_clk_is_enabled,
+ .restore_context = clk_gate_restore_context,
};
/**
@@ -179,7 +182,7 @@ static void __init _of_ti_gate_clk_setup(struct device_node *node,
}
if (of_clk_get_parent_count(node) != 1) {
- pr_err("%s must have 1 parent\n", node->name);
+ pr_err("%pOFn must have 1 parent\n", node);
return;
}
diff --git a/drivers/clk/ti/interface.c b/drivers/clk/ti/interface.c
index 41ae7021670e..87e00c2ee957 100644
--- a/drivers/clk/ti/interface.c
+++ b/drivers/clk/ti/interface.c
@@ -84,7 +84,7 @@ static void __init _of_ti_interface_clk_setup(struct device_node *node,
parent_name = of_clk_get_parent_name(node, 0);
if (!parent_name) {
- pr_err("%s must have a parent\n", node->name);
+ pr_err("%pOFn must have a parent\n", node);
return;
}
diff --git a/drivers/clk/ti/mux.c b/drivers/clk/ti/mux.c
index 69a4308a5a98..883bdde94d04 100644
--- a/drivers/clk/ti/mux.c
+++ b/drivers/clk/ti/mux.c
@@ -91,10 +91,39 @@ static int ti_clk_mux_set_parent(struct clk_hw *hw, u8 index)
return 0;
}
+/**
+ * clk_mux_save_context - Save the parent selcted in the mux
+ * @hw: pointer struct clk_hw
+ *
+ * Save the parent mux value.
+ */
+static int clk_mux_save_context(struct clk_hw *hw)
+{
+ struct clk_omap_mux *mux = to_clk_omap_mux(hw);
+
+ mux->saved_parent = ti_clk_mux_get_parent(hw);
+ return 0;
+}
+
+/**
+ * clk_mux_restore_context - Restore the parent in the mux
+ * @hw: pointer struct clk_hw
+ *
+ * Restore the saved parent mux value.
+ */
+static void clk_mux_restore_context(struct clk_hw *hw)
+{
+ struct clk_omap_mux *mux = to_clk_omap_mux(hw);
+
+ ti_clk_mux_set_parent(hw, mux->saved_parent);
+}
+
const struct clk_ops ti_clk_mux_ops = {
.get_parent = ti_clk_mux_get_parent,
.set_parent = ti_clk_mux_set_parent,
.determine_rate = __clk_mux_determine_rate,
+ .save_context = clk_mux_save_context,
+ .restore_context = clk_mux_restore_context,
};
static struct clk *_register_mux(struct device *dev, const char *name,
@@ -186,7 +215,7 @@ static void of_mux_clk_setup(struct device_node *node)
num_parents = of_clk_get_parent_count(node);
if (num_parents < 2) {
- pr_err("mux-clock %s must have parents\n", node->name);
+ pr_err("mux-clock %pOFn must have parents\n", node);
return;
}
parent_names = kzalloc((sizeof(char *) * num_parents), GFP_KERNEL);
@@ -278,7 +307,7 @@ static void __init of_ti_composite_mux_clk_setup(struct device_node *node)
num_parents = of_clk_get_parent_count(node);
if (num_parents < 2) {
- pr_err("%s must have parents\n", node->name);
+ pr_err("%pOFn must have parents\n", node);
goto cleanup;
}
diff --git a/drivers/clk/zynq/clkc.c b/drivers/clk/zynq/clkc.c
index 88a2cab37f62..d7b53ac8ad11 100644
--- a/drivers/clk/zynq/clkc.c
+++ b/drivers/clk/zynq/clkc.c
@@ -602,7 +602,7 @@ void __init zynq_clock_init(void)
}
if (of_address_to_resource(np, 0, &res)) {
- pr_err("%s: failed to get resource\n", np->name);
+ pr_err("%pOFn: failed to get resource\n", np);
goto np_err;
}
@@ -611,7 +611,7 @@ void __init zynq_clock_init(void)
if (slcr->data) {
zynq_clkc_base = (__force void __iomem *)slcr->data + res.start;
} else {
- pr_err("%s: Unable to get I/O memory\n", np->name);
+ pr_err("%pOFn: Unable to get I/O memory\n", np);
of_node_put(slcr);
goto np_err;
}
diff --git a/drivers/clk/zynqmp/Kconfig b/drivers/clk/zynqmp/Kconfig
new file mode 100644
index 000000000000..17086059be8b
--- /dev/null
+++ b/drivers/clk/zynqmp/Kconfig
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config COMMON_CLK_ZYNQMP
+ bool "Support for Xilinx ZynqMP Ultrascale+ clock controllers"
+ depends on ARCH_ZYNQMP || COMPILE_TEST
+ depends on ZYNQMP_FIRMWARE
+ help
+ Support for the Zynqmp Ultrascale clock controller.
+ It has a dependency on the PMU firmware.
+ Say Y if you want to include clock support.
diff --git a/drivers/clk/zynqmp/Makefile b/drivers/clk/zynqmp/Makefile
new file mode 100644
index 000000000000..0ec24bfe0f18
--- /dev/null
+++ b/drivers/clk/zynqmp/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
+# Zynq Ultrascale+ MPSoC clock specific Makefile
+
+obj-$(CONFIG_ARCH_ZYNQMP) += pll.o clk-gate-zynqmp.o divider.o clk-mux-zynqmp.o clkc.o
diff --git a/drivers/clk/zynqmp/clk-gate-zynqmp.c b/drivers/clk/zynqmp/clk-gate-zynqmp.c
new file mode 100644
index 000000000000..83b236f20fff
--- /dev/null
+++ b/drivers/clk/zynqmp/clk-gate-zynqmp.c
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Zynq UltraScale+ MPSoC clock controller
+ *
+ * Copyright (C) 2016-2018 Xilinx
+ *
+ * Gated clock implementation
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+#include "clk-zynqmp.h"
+
+/**
+ * struct clk_gate - gating clock
+ * @hw: handle between common and hardware-specific interfaces
+ * @flags: hardware-specific flags
+ * @clk_id: Id of clock
+ */
+struct zynqmp_clk_gate {
+ struct clk_hw hw;
+ u8 flags;
+ u32 clk_id;
+};
+
+#define to_zynqmp_clk_gate(_hw) container_of(_hw, struct zynqmp_clk_gate, hw)
+
+/**
+ * zynqmp_clk_gate_enable() - Enable clock
+ * @hw: handle between common and hardware-specific interfaces
+ *
+ * Return: 0 on success else error code
+ */
+static int zynqmp_clk_gate_enable(struct clk_hw *hw)
+{
+ struct zynqmp_clk_gate *gate = to_zynqmp_clk_gate(hw);
+ const char *clk_name = clk_hw_get_name(hw);
+ u32 clk_id = gate->clk_id;
+ int ret;
+ const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
+
+ ret = eemi_ops->clock_enable(clk_id);
+
+ if (ret)
+ pr_warn_once("%s() clock enabled failed for %s, ret = %d\n",
+ __func__, clk_name, ret);
+
+ return ret;
+}
+
+/*
+ * zynqmp_clk_gate_disable() - Disable clock
+ * @hw: handle between common and hardware-specific interfaces
+ */
+static void zynqmp_clk_gate_disable(struct clk_hw *hw)
+{
+ struct zynqmp_clk_gate *gate = to_zynqmp_clk_gate(hw);
+ const char *clk_name = clk_hw_get_name(hw);
+ u32 clk_id = gate->clk_id;
+ int ret;
+ const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
+
+ ret = eemi_ops->clock_disable(clk_id);
+
+ if (ret)
+ pr_warn_once("%s() clock disable failed for %s, ret = %d\n",
+ __func__, clk_name, ret);
+}
+
+/**
+ * zynqmp_clk_gate_is_enable() - Check clock state
+ * @hw: handle between common and hardware-specific interfaces
+ *
+ * Return: 1 if enabled, 0 if disabled else error code
+ */
+static int zynqmp_clk_gate_is_enabled(struct clk_hw *hw)
+{
+ struct zynqmp_clk_gate *gate = to_zynqmp_clk_gate(hw);
+ const char *clk_name = clk_hw_get_name(hw);
+ u32 clk_id = gate->clk_id;
+ int state, ret;
+ const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
+
+ ret = eemi_ops->clock_getstate(clk_id, &state);
+ if (ret) {
+ pr_warn_once("%s() clock get state failed for %s, ret = %d\n",
+ __func__, clk_name, ret);
+ return -EIO;
+ }
+
+ return state ? 1 : 0;
+}
+
+static const struct clk_ops zynqmp_clk_gate_ops = {
+ .enable = zynqmp_clk_gate_enable,
+ .disable = zynqmp_clk_gate_disable,
+ .is_enabled = zynqmp_clk_gate_is_enabled,
+};
+
+/**
+ * zynqmp_clk_register_gate() - Register a gate clock with the clock framework
+ * @name: Name of this clock
+ * @clk_id: Id of this clock
+ * @parents: Name of this clock's parents
+ * @num_parents: Number of parents
+ * @nodes: Clock topology node
+ *
+ * Return: clock hardware of the registered clock gate
+ */
+struct clk_hw *zynqmp_clk_register_gate(const char *name, u32 clk_id,
+ const char * const *parents,
+ u8 num_parents,
+ const struct clock_topology *nodes)
+{
+ struct zynqmp_clk_gate *gate;
+ struct clk_hw *hw;
+ int ret;
+ struct clk_init_data init;
+
+ /* allocate the gate */
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &zynqmp_clk_gate_ops;
+ init.flags = nodes->flag;
+ init.parent_names = parents;
+ init.num_parents = 1;
+
+ /* struct clk_gate assignments */
+ gate->flags = nodes->type_flag;
+ gate->hw.init = &init;
+ gate->clk_id = clk_id;
+
+ hw = &gate->hw;
+ ret = clk_hw_register(NULL, hw);
+ if (ret) {
+ kfree(gate);
+ hw = ERR_PTR(ret);
+ }
+
+ return hw;
+}
diff --git a/drivers/clk/zynqmp/clk-mux-zynqmp.c b/drivers/clk/zynqmp/clk-mux-zynqmp.c
new file mode 100644
index 000000000000..4143f560c28d
--- /dev/null
+++ b/drivers/clk/zynqmp/clk-mux-zynqmp.c
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Zynq UltraScale+ MPSoC mux
+ *
+ * Copyright (C) 2016-2018 Xilinx
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+#include "clk-zynqmp.h"
+
+/*
+ * DOC: basic adjustable multiplexer clock that cannot gate
+ *
+ * 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 only affected by parent switching. No clk_set_rate support
+ * parent - parent is adjustable through clk_set_parent
+ */
+
+/**
+ * struct zynqmp_clk_mux - multiplexer clock
+ *
+ * @hw: handle between common and hardware-specific interfaces
+ * @flags: hardware-specific flags
+ * @clk_id: Id of clock
+ */
+struct zynqmp_clk_mux {
+ struct clk_hw hw;
+ u8 flags;
+ u32 clk_id;
+};
+
+#define to_zynqmp_clk_mux(_hw) container_of(_hw, struct zynqmp_clk_mux, hw)
+
+/**
+ * zynqmp_clk_mux_get_parent() - Get parent of clock
+ * @hw: handle between common and hardware-specific interfaces
+ *
+ * Return: Parent index
+ */
+static u8 zynqmp_clk_mux_get_parent(struct clk_hw *hw)
+{
+ struct zynqmp_clk_mux *mux = to_zynqmp_clk_mux(hw);
+ const char *clk_name = clk_hw_get_name(hw);
+ u32 clk_id = mux->clk_id;
+ u32 val;
+ int ret;
+ const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
+
+ ret = eemi_ops->clock_getparent(clk_id, &val);
+
+ if (ret)
+ pr_warn_once("%s() getparent failed for clock: %s, ret = %d\n",
+ __func__, clk_name, ret);
+
+ return val;
+}
+
+/**
+ * zynqmp_clk_mux_set_parent() - Set parent of clock
+ * @hw: handle between common and hardware-specific interfaces
+ * @index: Parent index
+ *
+ * Return: 0 on success else error+reason
+ */
+static int zynqmp_clk_mux_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct zynqmp_clk_mux *mux = to_zynqmp_clk_mux(hw);
+ const char *clk_name = clk_hw_get_name(hw);
+ u32 clk_id = mux->clk_id;
+ int ret;
+ const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
+
+ ret = eemi_ops->clock_setparent(clk_id, index);
+
+ if (ret)
+ pr_warn_once("%s() set parent failed for clock: %s, ret = %d\n",
+ __func__, clk_name, ret);
+
+ return ret;
+}
+
+static const struct clk_ops zynqmp_clk_mux_ops = {
+ .get_parent = zynqmp_clk_mux_get_parent,
+ .set_parent = zynqmp_clk_mux_set_parent,
+ .determine_rate = __clk_mux_determine_rate,
+};
+
+static const struct clk_ops zynqmp_clk_mux_ro_ops = {
+ .get_parent = zynqmp_clk_mux_get_parent,
+};
+
+/**
+ * zynqmp_clk_register_mux() - Register a mux table with the clock
+ * framework
+ * @name: Name of this clock
+ * @clk_id: Id of this clock
+ * @parents: Name of this clock's parents
+ * @num_parents: Number of parents
+ * @nodes: Clock topology node
+ *
+ * Return: clock hardware of the registered clock mux
+ */
+struct clk_hw *zynqmp_clk_register_mux(const char *name, u32 clk_id,
+ const char * const *parents,
+ u8 num_parents,
+ const struct clock_topology *nodes)
+{
+ struct zynqmp_clk_mux *mux;
+ struct clk_hw *hw;
+ struct clk_init_data init;
+ int ret;
+
+ mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+ if (!mux)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ if (nodes->type_flag & CLK_MUX_READ_ONLY)
+ init.ops = &zynqmp_clk_mux_ro_ops;
+ else
+ init.ops = &zynqmp_clk_mux_ops;
+ init.flags = nodes->flag;
+ init.parent_names = parents;
+ init.num_parents = num_parents;
+ mux->flags = nodes->type_flag;
+ mux->hw.init = &init;
+ mux->clk_id = clk_id;
+
+ hw = &mux->hw;
+ ret = clk_hw_register(NULL, hw);
+ if (ret) {
+ kfree(hw);
+ hw = ERR_PTR(ret);
+ }
+
+ return hw;
+}
+EXPORT_SYMBOL_GPL(zynqmp_clk_register_mux);
diff --git a/drivers/clk/zynqmp/clk-zynqmp.h b/drivers/clk/zynqmp/clk-zynqmp.h
new file mode 100644
index 000000000000..7ab163b67249
--- /dev/null
+++ b/drivers/clk/zynqmp/clk-zynqmp.h
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2016-2018 Xilinx
+ */
+
+#ifndef __LINUX_CLK_ZYNQMP_H_
+#define __LINUX_CLK_ZYNQMP_H_
+
+#include <linux/spinlock.h>
+
+#include <linux/firmware/xlnx-zynqmp.h>
+
+/* Clock APIs payload parameters */
+#define CLK_GET_NAME_RESP_LEN 16
+#define CLK_GET_TOPOLOGY_RESP_WORDS 3
+#define CLK_GET_PARENTS_RESP_WORDS 3
+#define CLK_GET_ATTR_RESP_WORDS 1
+
+enum topology_type {
+ TYPE_INVALID,
+ TYPE_MUX,
+ TYPE_PLL,
+ TYPE_FIXEDFACTOR,
+ TYPE_DIV1,
+ TYPE_DIV2,
+ TYPE_GATE,
+};
+
+/**
+ * struct clock_topology - Clock topology
+ * @type: Type of topology
+ * @flag: Topology flags
+ * @type_flag: Topology type specific flag
+ */
+struct clock_topology {
+ u32 type;
+ u32 flag;
+ u32 type_flag;
+};
+
+struct clk_hw *zynqmp_clk_register_pll(const char *name, u32 clk_id,
+ const char * const *parents,
+ u8 num_parents,
+ const struct clock_topology *nodes);
+
+struct clk_hw *zynqmp_clk_register_gate(const char *name, u32 clk_id,
+ const char * const *parents,
+ u8 num_parents,
+ const struct clock_topology *nodes);
+
+struct clk_hw *zynqmp_clk_register_divider(const char *name,
+ u32 clk_id,
+ const char * const *parents,
+ u8 num_parents,
+ const struct clock_topology *nodes);
+
+struct clk_hw *zynqmp_clk_register_mux(const char *name, u32 clk_id,
+ const char * const *parents,
+ u8 num_parents,
+ const struct clock_topology *nodes);
+
+struct clk_hw *zynqmp_clk_register_fixed_factor(const char *name,
+ u32 clk_id,
+ const char * const *parents,
+ u8 num_parents,
+ const struct clock_topology *nodes);
+
+#endif
diff --git a/drivers/clk/zynqmp/clkc.c b/drivers/clk/zynqmp/clkc.c
new file mode 100644
index 000000000000..9d7d297f0ea8
--- /dev/null
+++ b/drivers/clk/zynqmp/clkc.c
@@ -0,0 +1,716 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Zynq UltraScale+ MPSoC clock controller
+ *
+ * Copyright (C) 2016-2018 Xilinx
+ *
+ * Based on drivers/clk/zynq/clkc.c
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include "clk-zynqmp.h"
+
+#define MAX_PARENT 100
+#define MAX_NODES 6
+#define MAX_NAME_LEN 50
+
+#define CLK_TYPE_SHIFT 2
+
+#define PM_API_PAYLOAD_LEN 3
+
+#define NA_PARENT 0xFFFFFFFF
+#define DUMMY_PARENT 0xFFFFFFFE
+
+#define CLK_TYPE_FIELD_LEN 4
+#define CLK_TOPOLOGY_NODE_OFFSET 16
+#define NODES_PER_RESP 3
+
+#define CLK_TYPE_FIELD_MASK 0xF
+#define CLK_FLAG_FIELD_MASK GENMASK(21, 8)
+#define CLK_TYPE_FLAG_FIELD_MASK GENMASK(31, 24)
+
+#define CLK_PARENTS_ID_LEN 16
+#define CLK_PARENTS_ID_MASK 0xFFFF
+
+/* Flags for parents */
+#define PARENT_CLK_SELF 0
+#define PARENT_CLK_NODE1 1
+#define PARENT_CLK_NODE2 2
+#define PARENT_CLK_NODE3 3
+#define PARENT_CLK_NODE4 4
+#define PARENT_CLK_EXTERNAL 5
+
+#define END_OF_CLK_NAME "END_OF_CLK"
+#define END_OF_TOPOLOGY_NODE 1
+#define END_OF_PARENTS 1
+#define RESERVED_CLK_NAME ""
+
+#define CLK_VALID_MASK 0x1
+
+enum clk_type {
+ CLK_TYPE_OUTPUT,
+ CLK_TYPE_EXTERNAL,
+};
+
+/**
+ * struct clock_parent - Clock parent
+ * @name: Parent name
+ * @id: Parent clock ID
+ * @flag: Parent flags
+ */
+struct clock_parent {
+ char name[MAX_NAME_LEN];
+ int id;
+ u32 flag;
+};
+
+/**
+ * struct zynqmp_clock - Clock
+ * @clk_name: Clock name
+ * @valid: Validity flag of clock
+ * @type: Clock type (Output/External)
+ * @node: Clock topology nodes
+ * @num_nodes: Number of nodes present in topology
+ * @parent: Parent of clock
+ * @num_parents: Number of parents of clock
+ */
+struct zynqmp_clock {
+ char clk_name[MAX_NAME_LEN];
+ u32 valid;
+ enum clk_type type;
+ struct clock_topology node[MAX_NODES];
+ u32 num_nodes;
+ struct clock_parent parent[MAX_PARENT];
+ u32 num_parents;
+};
+
+static const char clk_type_postfix[][10] = {
+ [TYPE_INVALID] = "",
+ [TYPE_MUX] = "_mux",
+ [TYPE_GATE] = "",
+ [TYPE_DIV1] = "_div1",
+ [TYPE_DIV2] = "_div2",
+ [TYPE_FIXEDFACTOR] = "_ff",
+ [TYPE_PLL] = ""
+};
+
+static struct clk_hw *(* const clk_topology[]) (const char *name, u32 clk_id,
+ const char * const *parents,
+ u8 num_parents,
+ const struct clock_topology *nodes)
+ = {
+ [TYPE_INVALID] = NULL,
+ [TYPE_MUX] = zynqmp_clk_register_mux,
+ [TYPE_PLL] = zynqmp_clk_register_pll,
+ [TYPE_FIXEDFACTOR] = zynqmp_clk_register_fixed_factor,
+ [TYPE_DIV1] = zynqmp_clk_register_divider,
+ [TYPE_DIV2] = zynqmp_clk_register_divider,
+ [TYPE_GATE] = zynqmp_clk_register_gate
+};
+
+static struct zynqmp_clock *clock;
+static struct clk_hw_onecell_data *zynqmp_data;
+static unsigned int clock_max_idx;
+static const struct zynqmp_eemi_ops *eemi_ops;
+
+/**
+ * zynqmp_is_valid_clock() - Check whether clock is valid or not
+ * @clk_id: Clock index
+ *
+ * Return: 1 if clock is valid, 0 if clock is invalid else error code
+ */
+static inline int zynqmp_is_valid_clock(u32 clk_id)
+{
+ if (clk_id > clock_max_idx)
+ return -ENODEV;
+
+ return clock[clk_id].valid;
+}
+
+/**
+ * zynqmp_get_clock_name() - Get name of clock from Clock index
+ * @clk_id: Clock index
+ * @clk_name: Name of clock
+ *
+ * Return: 0 on success else error code
+ */
+static int zynqmp_get_clock_name(u32 clk_id, char *clk_name)
+{
+ int ret;
+
+ ret = zynqmp_is_valid_clock(clk_id);
+ if (ret == 1) {
+ strncpy(clk_name, clock[clk_id].clk_name, MAX_NAME_LEN);
+ return 0;
+ }
+
+ return ret == 0 ? -EINVAL : ret;
+}
+
+/**
+ * zynqmp_get_clock_type() - Get type of clock
+ * @clk_id: Clock index
+ * @type: Clock type: CLK_TYPE_OUTPUT or CLK_TYPE_EXTERNAL
+ *
+ * Return: 0 on success else error code
+ */
+static int zynqmp_get_clock_type(u32 clk_id, u32 *type)
+{
+ int ret;
+
+ ret = zynqmp_is_valid_clock(clk_id);
+ if (ret == 1) {
+ *type = clock[clk_id].type;
+ return 0;
+ }
+
+ return ret == 0 ? -EINVAL : ret;
+}
+
+/**
+ * zynqmp_pm_clock_get_num_clocks() - Get number of clocks in system
+ * @nclocks: Number of clocks in system/board.
+ *
+ * Call firmware API to get number of clocks.
+ *
+ * Return: 0 on success else error code.
+ */
+static int zynqmp_pm_clock_get_num_clocks(u32 *nclocks)
+{
+ struct zynqmp_pm_query_data qdata = {0};
+ u32 ret_payload[PAYLOAD_ARG_CNT];
+ int ret;
+
+ qdata.qid = PM_QID_CLOCK_GET_NUM_CLOCKS;
+
+ ret = eemi_ops->query_data(qdata, ret_payload);
+ *nclocks = ret_payload[1];
+
+ return ret;
+}
+
+/**
+ * zynqmp_pm_clock_get_name() - Get the name of clock for given id
+ * @clock_id: ID of the clock to be queried
+ * @name: Name of given clock
+ *
+ * This function is used to get name of clock specified by given
+ * clock ID.
+ *
+ * Return: Returns 0, in case of error name would be 0
+ */
+static int zynqmp_pm_clock_get_name(u32 clock_id, char *name)
+{
+ struct zynqmp_pm_query_data qdata = {0};
+ u32 ret_payload[PAYLOAD_ARG_CNT];
+
+ qdata.qid = PM_QID_CLOCK_GET_NAME;
+ qdata.arg1 = clock_id;
+
+ eemi_ops->query_data(qdata, ret_payload);
+ memcpy(name, ret_payload, CLK_GET_NAME_RESP_LEN);
+
+ return 0;
+}
+
+/**
+ * zynqmp_pm_clock_get_topology() - Get the topology of clock for given id
+ * @clock_id: ID of the clock to be queried
+ * @index: Node index of clock topology
+ * @topology: Buffer to store nodes in topology and flags
+ *
+ * This function is used to get topology information for the clock
+ * specified by given clock ID.
+ *
+ * This API will return 3 node of topology with a single response. To get
+ * other nodes, master should call same API in loop with new
+ * index till error is returned. E.g First call should have
+ * index 0 which will return nodes 0,1 and 2. Next call, index
+ * should be 3 which will return nodes 3,4 and 5 and so on.
+ *
+ * Return: 0 on success else error+reason
+ */
+static int zynqmp_pm_clock_get_topology(u32 clock_id, u32 index, u32 *topology)
+{
+ struct zynqmp_pm_query_data qdata = {0};
+ u32 ret_payload[PAYLOAD_ARG_CNT];
+ int ret;
+
+ qdata.qid = PM_QID_CLOCK_GET_TOPOLOGY;
+ qdata.arg1 = clock_id;
+ qdata.arg2 = index;
+
+ ret = eemi_ops->query_data(qdata, ret_payload);
+ memcpy(topology, &ret_payload[1], CLK_GET_TOPOLOGY_RESP_WORDS * 4);
+
+ return ret;
+}
+
+/**
+ * zynqmp_clk_register_fixed_factor() - Register fixed factor with the
+ * clock framework
+ * @name: Name of this clock
+ * @clk_id: Clock ID
+ * @parents: Name of this clock's parents
+ * @num_parents: Number of parents
+ * @nodes: Clock topology node
+ *
+ * Return: clock hardware to the registered clock
+ */
+struct clk_hw *zynqmp_clk_register_fixed_factor(const char *name, u32 clk_id,
+ const char * const *parents,
+ u8 num_parents,
+ const struct clock_topology *nodes)
+{
+ u32 mult, div;
+ struct clk_hw *hw;
+ struct zynqmp_pm_query_data qdata = {0};
+ u32 ret_payload[PAYLOAD_ARG_CNT];
+ int ret;
+
+ qdata.qid = PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS;
+ qdata.arg1 = clk_id;
+
+ ret = eemi_ops->query_data(qdata, ret_payload);
+ mult = ret_payload[1];
+ div = ret_payload[2];
+
+ hw = clk_hw_register_fixed_factor(NULL, name,
+ parents[0],
+ nodes->flag, mult,
+ div);
+
+ return hw;
+}
+
+/**
+ * zynqmp_pm_clock_get_parents() - Get the first 3 parents of clock for given id
+ * @clock_id: Clock ID
+ * @index: Parent index
+ * @parents: 3 parents of the given clock
+ *
+ * This function is used to get 3 parents for the clock specified by
+ * given clock ID.
+ *
+ * This API will return 3 parents with a single response. To get
+ * other parents, master should call same API in loop with new
+ * parent index till error is returned. E.g First call should have
+ * index 0 which will return parents 0,1 and 2. Next call, index
+ * should be 3 which will return parent 3,4 and 5 and so on.
+ *
+ * Return: 0 on success else error+reason
+ */
+static int zynqmp_pm_clock_get_parents(u32 clock_id, u32 index, u32 *parents)
+{
+ struct zynqmp_pm_query_data qdata = {0};
+ u32 ret_payload[PAYLOAD_ARG_CNT];
+ int ret;
+
+ qdata.qid = PM_QID_CLOCK_GET_PARENTS;
+ qdata.arg1 = clock_id;
+ qdata.arg2 = index;
+
+ ret = eemi_ops->query_data(qdata, ret_payload);
+ memcpy(parents, &ret_payload[1], CLK_GET_PARENTS_RESP_WORDS * 4);
+
+ return ret;
+}
+
+/**
+ * zynqmp_pm_clock_get_attributes() - Get the attributes of clock for given id
+ * @clock_id: Clock ID
+ * @attr: Clock attributes
+ *
+ * This function is used to get clock's attributes(e.g. valid, clock type, etc).
+ *
+ * Return: 0 on success else error+reason
+ */
+static int zynqmp_pm_clock_get_attributes(u32 clock_id, u32 *attr)
+{
+ struct zynqmp_pm_query_data qdata = {0};
+ u32 ret_payload[PAYLOAD_ARG_CNT];
+ int ret;
+
+ qdata.qid = PM_QID_CLOCK_GET_ATTRIBUTES;
+ qdata.arg1 = clock_id;
+
+ ret = eemi_ops->query_data(qdata, ret_payload);
+ memcpy(attr, &ret_payload[1], CLK_GET_ATTR_RESP_WORDS * 4);
+
+ return ret;
+}
+
+/**
+ * __zynqmp_clock_get_topology() - Get topology data of clock from firmware
+ * response data
+ * @topology: Clock topology
+ * @data: Clock topology data received from firmware
+ * @nnodes: Number of nodes
+ *
+ * Return: 0 on success else error+reason
+ */
+static int __zynqmp_clock_get_topology(struct clock_topology *topology,
+ u32 *data, u32 *nnodes)
+{
+ int i;
+
+ for (i = 0; i < PM_API_PAYLOAD_LEN; i++) {
+ if (!(data[i] & CLK_TYPE_FIELD_MASK))
+ return END_OF_TOPOLOGY_NODE;
+ topology[*nnodes].type = data[i] & CLK_TYPE_FIELD_MASK;
+ topology[*nnodes].flag = FIELD_GET(CLK_FLAG_FIELD_MASK,
+ data[i]);
+ topology[*nnodes].type_flag =
+ FIELD_GET(CLK_TYPE_FLAG_FIELD_MASK, data[i]);
+ (*nnodes)++;
+ }
+
+ return 0;
+}
+
+/**
+ * zynqmp_clock_get_topology() - Get topology of clock from firmware using
+ * PM_API
+ * @clk_id: Clock index
+ * @topology: Clock topology
+ * @num_nodes: Number of nodes
+ *
+ * Return: 0 on success else error+reason
+ */
+static int zynqmp_clock_get_topology(u32 clk_id,
+ struct clock_topology *topology,
+ u32 *num_nodes)
+{
+ int j, ret;
+ u32 pm_resp[PM_API_PAYLOAD_LEN] = {0};
+
+ *num_nodes = 0;
+ for (j = 0; j <= MAX_NODES; j += 3) {
+ ret = zynqmp_pm_clock_get_topology(clk_id, j, pm_resp);
+ if (ret)
+ return ret;
+ ret = __zynqmp_clock_get_topology(topology, pm_resp, num_nodes);
+ if (ret == END_OF_TOPOLOGY_NODE)
+ return 0;
+ }
+
+ return 0;
+}
+
+/**
+ * __zynqmp_clock_get_topology() - Get parents info of clock from firmware
+ * response data
+ * @parents: Clock parents
+ * @data: Clock parents data received from firmware
+ * @nparent: Number of parent
+ *
+ * Return: 0 on success else error+reason
+ */
+static int __zynqmp_clock_get_parents(struct clock_parent *parents, u32 *data,
+ u32 *nparent)
+{
+ int i;
+ struct clock_parent *parent;
+
+ for (i = 0; i < PM_API_PAYLOAD_LEN; i++) {
+ if (data[i] == NA_PARENT)
+ return END_OF_PARENTS;
+
+ parent = &parents[i];
+ parent->id = data[i] & CLK_PARENTS_ID_MASK;
+ if (data[i] == DUMMY_PARENT) {
+ strcpy(parent->name, "dummy_name");
+ parent->flag = 0;
+ } else {
+ parent->flag = data[i] >> CLK_PARENTS_ID_LEN;
+ if (zynqmp_get_clock_name(parent->id, parent->name))
+ continue;
+ }
+ *nparent += 1;
+ }
+
+ return 0;
+}
+
+/**
+ * zynqmp_clock_get_parents() - Get parents info from firmware using PM_API
+ * @clk_id: Clock index
+ * @parents: Clock parents
+ * @num_parents: Total number of parents
+ *
+ * Return: 0 on success else error+reason
+ */
+static int zynqmp_clock_get_parents(u32 clk_id, struct clock_parent *parents,
+ u32 *num_parents)
+{
+ int j = 0, ret;
+ u32 pm_resp[PM_API_PAYLOAD_LEN] = {0};
+
+ *num_parents = 0;
+ do {
+ /* Get parents from firmware */
+ ret = zynqmp_pm_clock_get_parents(clk_id, j, pm_resp);
+ if (ret)
+ return ret;
+
+ ret = __zynqmp_clock_get_parents(&parents[j], pm_resp,
+ num_parents);
+ if (ret == END_OF_PARENTS)
+ return 0;
+ j += PM_API_PAYLOAD_LEN;
+ } while (*num_parents <= MAX_PARENT);
+
+ return 0;
+}
+
+/**
+ * zynqmp_get_parent_list() - Create list of parents name
+ * @np: Device node
+ * @clk_id: Clock index
+ * @parent_list: List of parent's name
+ * @num_parents: Total number of parents
+ *
+ * Return: 0 on success else error+reason
+ */
+static int zynqmp_get_parent_list(struct device_node *np, u32 clk_id,
+ const char **parent_list, u32 *num_parents)
+{
+ int i = 0, ret;
+ u32 total_parents = clock[clk_id].num_parents;
+ struct clock_topology *clk_nodes;
+ struct clock_parent *parents;
+
+ clk_nodes = clock[clk_id].node;
+ parents = clock[clk_id].parent;
+
+ for (i = 0; i < total_parents; i++) {
+ if (!parents[i].flag) {
+ parent_list[i] = parents[i].name;
+ } else if (parents[i].flag == PARENT_CLK_EXTERNAL) {
+ ret = of_property_match_string(np, "clock-names",
+ parents[i].name);
+ if (ret < 0)
+ strcpy(parents[i].name, "dummy_name");
+ parent_list[i] = parents[i].name;
+ } else {
+ strcat(parents[i].name,
+ clk_type_postfix[clk_nodes[parents[i].flag - 1].
+ type]);
+ parent_list[i] = parents[i].name;
+ }
+ }
+
+ *num_parents = total_parents;
+ return 0;
+}
+
+/**
+ * zynqmp_register_clk_topology() - Register clock topology
+ * @clk_id: Clock index
+ * @clk_name: Clock Name
+ * @num_parents: Total number of parents
+ * @parent_names: List of parents name
+ *
+ * Return: Returns either clock hardware or error+reason
+ */
+static struct clk_hw *zynqmp_register_clk_topology(int clk_id, char *clk_name,
+ int num_parents,
+ const char **parent_names)
+{
+ int j;
+ u32 num_nodes;
+ char *clk_out = NULL;
+ struct clock_topology *nodes;
+ struct clk_hw *hw = NULL;
+
+ nodes = clock[clk_id].node;
+ num_nodes = clock[clk_id].num_nodes;
+
+ for (j = 0; j < num_nodes; j++) {
+ /*
+ * Clock name received from firmware is output clock name.
+ * Intermediate clock names are postfixed with type of clock.
+ */
+ if (j != (num_nodes - 1)) {
+ clk_out = kasprintf(GFP_KERNEL, "%s%s", clk_name,
+ clk_type_postfix[nodes[j].type]);
+ } else {
+ clk_out = kasprintf(GFP_KERNEL, "%s", clk_name);
+ }
+
+ if (!clk_topology[nodes[j].type])
+ continue;
+
+ hw = (*clk_topology[nodes[j].type])(clk_out, clk_id,
+ parent_names,
+ num_parents,
+ &nodes[j]);
+ if (IS_ERR(hw))
+ pr_warn_once("%s() %s register fail with %ld\n",
+ __func__, clk_name, PTR_ERR(hw));
+
+ parent_names[0] = clk_out;
+ }
+ kfree(clk_out);
+ return hw;
+}
+
+/**
+ * zynqmp_register_clocks() - Register clocks
+ * @np: Device node
+ *
+ * Return: 0 on success else error code
+ */
+static int zynqmp_register_clocks(struct device_node *np)
+{
+ int ret;
+ u32 i, total_parents = 0, type = 0;
+ const char *parent_names[MAX_PARENT];
+
+ for (i = 0; i < clock_max_idx; i++) {
+ char clk_name[MAX_NAME_LEN];
+
+ /* get clock name, continue to next clock if name not found */
+ if (zynqmp_get_clock_name(i, clk_name))
+ continue;
+
+ /* Check if clock is valid and output clock.
+ * Do not register invalid or external clock.
+ */
+ ret = zynqmp_get_clock_type(i, &type);
+ if (ret || type != CLK_TYPE_OUTPUT)
+ continue;
+
+ /* Get parents of clock*/
+ if (zynqmp_get_parent_list(np, i, parent_names,
+ &total_parents)) {
+ WARN_ONCE(1, "No parents found for %s\n",
+ clock[i].clk_name);
+ continue;
+ }
+
+ zynqmp_data->hws[i] =
+ zynqmp_register_clk_topology(i, clk_name,
+ total_parents,
+ parent_names);
+ }
+
+ for (i = 0; i < clock_max_idx; i++) {
+ if (IS_ERR(zynqmp_data->hws[i])) {
+ pr_err("Zynq Ultrascale+ MPSoC clk %s: register failed with %ld\n",
+ clock[i].clk_name, PTR_ERR(zynqmp_data->hws[i]));
+ WARN_ON(1);
+ }
+ }
+ return 0;
+}
+
+/**
+ * zynqmp_get_clock_info() - Get clock information from firmware using PM_API
+ */
+static void zynqmp_get_clock_info(void)
+{
+ int i, ret;
+ u32 attr, type = 0;
+
+ for (i = 0; i < clock_max_idx; i++) {
+ zynqmp_pm_clock_get_name(i, clock[i].clk_name);
+ if (!strcmp(clock[i].clk_name, RESERVED_CLK_NAME))
+ continue;
+
+ ret = zynqmp_pm_clock_get_attributes(i, &attr);
+ if (ret)
+ continue;
+
+ clock[i].valid = attr & CLK_VALID_MASK;
+ clock[i].type = attr >> CLK_TYPE_SHIFT ? CLK_TYPE_EXTERNAL :
+ CLK_TYPE_OUTPUT;
+ }
+
+ /* Get topology of all clock */
+ for (i = 0; i < clock_max_idx; i++) {
+ ret = zynqmp_get_clock_type(i, &type);
+ if (ret || type != CLK_TYPE_OUTPUT)
+ continue;
+
+ ret = zynqmp_clock_get_topology(i, clock[i].node,
+ &clock[i].num_nodes);
+ if (ret)
+ continue;
+
+ ret = zynqmp_clock_get_parents(i, clock[i].parent,
+ &clock[i].num_parents);
+ if (ret)
+ continue;
+ }
+}
+
+/**
+ * zynqmp_clk_setup() - Setup the clock framework and register clocks
+ * @np: Device node
+ *
+ * Return: 0 on success else error code
+ */
+static int zynqmp_clk_setup(struct device_node *np)
+{
+ int ret;
+
+ ret = zynqmp_pm_clock_get_num_clocks(&clock_max_idx);
+ if (ret)
+ return ret;
+
+ zynqmp_data = kzalloc(sizeof(*zynqmp_data) + sizeof(*zynqmp_data) *
+ clock_max_idx, GFP_KERNEL);
+ if (!zynqmp_data)
+ return -ENOMEM;
+
+ clock = kcalloc(clock_max_idx, sizeof(*clock), GFP_KERNEL);
+ if (!clock) {
+ kfree(zynqmp_data);
+ return -ENOMEM;
+ }
+
+ zynqmp_get_clock_info();
+ zynqmp_register_clocks(np);
+
+ zynqmp_data->num = clock_max_idx;
+ of_clk_add_hw_provider(np, of_clk_hw_onecell_get, zynqmp_data);
+
+ return 0;
+}
+
+static int zynqmp_clock_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct device *dev = &pdev->dev;
+
+ eemi_ops = zynqmp_pm_get_eemi_ops();
+ if (!eemi_ops)
+ return -ENXIO;
+
+ ret = zynqmp_clk_setup(dev->of_node);
+
+ return ret;
+}
+
+static const struct of_device_id zynqmp_clock_of_match[] = {
+ {.compatible = "xlnx,zynqmp-clk"},
+ {},
+};
+MODULE_DEVICE_TABLE(of, zynqmp_clock_of_match);
+
+static struct platform_driver zynqmp_clock_driver = {
+ .driver = {
+ .name = "zynqmp_clock",
+ .of_match_table = zynqmp_clock_of_match,
+ },
+ .probe = zynqmp_clock_probe,
+};
+module_platform_driver(zynqmp_clock_driver);
diff --git a/drivers/clk/zynqmp/divider.c b/drivers/clk/zynqmp/divider.c
new file mode 100644
index 000000000000..a371c66e72ef
--- /dev/null
+++ b/drivers/clk/zynqmp/divider.c
@@ -0,0 +1,217 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Zynq UltraScale+ MPSoC Divider support
+ *
+ * Copyright (C) 2016-2018 Xilinx
+ *
+ * Adjustable divider clock implementation
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+#include "clk-zynqmp.h"
+
+/*
+ * DOC: basic adjustable divider clock that cannot gate
+ *
+ * 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 = ceiling(parent->rate / divisor)
+ * parent - fixed parent. No clk_set_parent support
+ */
+
+#define to_zynqmp_clk_divider(_hw) \
+ container_of(_hw, struct zynqmp_clk_divider, hw)
+
+#define CLK_FRAC BIT(13) /* has a fractional parent */
+
+/**
+ * struct zynqmp_clk_divider - adjustable divider clock
+ * @hw: handle between common and hardware-specific interfaces
+ * @flags: Hardware specific flags
+ * @clk_id: Id of clock
+ * @div_type: divisor type (TYPE_DIV1 or TYPE_DIV2)
+ */
+struct zynqmp_clk_divider {
+ struct clk_hw hw;
+ u8 flags;
+ u32 clk_id;
+ u32 div_type;
+};
+
+static inline int zynqmp_divider_get_val(unsigned long parent_rate,
+ unsigned long rate)
+{
+ return DIV_ROUND_CLOSEST(parent_rate, rate);
+}
+
+/**
+ * zynqmp_clk_divider_recalc_rate() - Recalc rate of divider clock
+ * @hw: handle between common and hardware-specific interfaces
+ * @parent_rate: rate of parent clock
+ *
+ * Return: 0 on success else error+reason
+ */
+static unsigned long zynqmp_clk_divider_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct zynqmp_clk_divider *divider = to_zynqmp_clk_divider(hw);
+ const char *clk_name = clk_hw_get_name(hw);
+ u32 clk_id = divider->clk_id;
+ u32 div_type = divider->div_type;
+ u32 div, value;
+ int ret;
+ const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
+
+ ret = eemi_ops->clock_getdivider(clk_id, &div);
+
+ if (ret)
+ pr_warn_once("%s() get divider failed for %s, ret = %d\n",
+ __func__, clk_name, ret);
+
+ if (div_type == TYPE_DIV1)
+ value = div & 0xFFFF;
+ else
+ value = div >> 16;
+
+ return DIV_ROUND_UP_ULL(parent_rate, value);
+}
+
+/**
+ * zynqmp_clk_divider_round_rate() - Round rate of divider clock
+ * @hw: handle between common and hardware-specific interfaces
+ * @rate: rate of clock to be set
+ * @prate: rate of parent clock
+ *
+ * Return: 0 on success else error+reason
+ */
+static long zynqmp_clk_divider_round_rate(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long *prate)
+{
+ struct zynqmp_clk_divider *divider = to_zynqmp_clk_divider(hw);
+ const char *clk_name = clk_hw_get_name(hw);
+ u32 clk_id = divider->clk_id;
+ u32 div_type = divider->div_type;
+ u32 bestdiv;
+ int ret;
+ const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
+
+ /* if read only, just return current value */
+ if (divider->flags & CLK_DIVIDER_READ_ONLY) {
+ ret = eemi_ops->clock_getdivider(clk_id, &bestdiv);
+
+ if (ret)
+ pr_warn_once("%s() get divider failed for %s, ret = %d\n",
+ __func__, clk_name, ret);
+ if (div_type == TYPE_DIV1)
+ bestdiv = bestdiv & 0xFFFF;
+ else
+ bestdiv = bestdiv >> 16;
+
+ return DIV_ROUND_UP_ULL((u64)*prate, bestdiv);
+ }
+
+ bestdiv = zynqmp_divider_get_val(*prate, rate);
+
+ if ((clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) &&
+ (divider->flags & CLK_FRAC))
+ bestdiv = rate % *prate ? 1 : bestdiv;
+ *prate = rate * bestdiv;
+
+ return rate;
+}
+
+/**
+ * zynqmp_clk_divider_set_rate() - Set rate of divider clock
+ * @hw: handle between common and hardware-specific interfaces
+ * @rate: rate of clock to be set
+ * @parent_rate: rate of parent clock
+ *
+ * Return: 0 on success else error+reason
+ */
+static int zynqmp_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct zynqmp_clk_divider *divider = to_zynqmp_clk_divider(hw);
+ const char *clk_name = clk_hw_get_name(hw);
+ u32 clk_id = divider->clk_id;
+ u32 div_type = divider->div_type;
+ u32 value, div;
+ int ret;
+ const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
+
+ value = zynqmp_divider_get_val(parent_rate, rate);
+ if (div_type == TYPE_DIV1) {
+ div = value & 0xFFFF;
+ div |= 0xffff << 16;
+ } else {
+ div = 0xffff;
+ div |= value << 16;
+ }
+
+ ret = eemi_ops->clock_setdivider(clk_id, div);
+
+ if (ret)
+ pr_warn_once("%s() set divider failed for %s, ret = %d\n",
+ __func__, clk_name, ret);
+
+ return ret;
+}
+
+static const struct clk_ops zynqmp_clk_divider_ops = {
+ .recalc_rate = zynqmp_clk_divider_recalc_rate,
+ .round_rate = zynqmp_clk_divider_round_rate,
+ .set_rate = zynqmp_clk_divider_set_rate,
+};
+
+/**
+ * zynqmp_clk_register_divider() - Register a divider clock
+ * @name: Name of this clock
+ * @clk_id: Id of clock
+ * @parents: Name of this clock's parents
+ * @num_parents: Number of parents
+ * @nodes: Clock topology node
+ *
+ * Return: clock hardware to registered clock divider
+ */
+struct clk_hw *zynqmp_clk_register_divider(const char *name,
+ u32 clk_id,
+ const char * const *parents,
+ u8 num_parents,
+ const struct clock_topology *nodes)
+{
+ struct zynqmp_clk_divider *div;
+ struct clk_hw *hw;
+ struct clk_init_data init;
+ int ret;
+
+ /* allocate the divider */
+ div = kzalloc(sizeof(*div), GFP_KERNEL);
+ if (!div)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &zynqmp_clk_divider_ops;
+ init.flags = nodes->flag;
+ init.parent_names = parents;
+ init.num_parents = 1;
+
+ /* struct clk_divider assignments */
+ div->flags = nodes->type_flag;
+ div->hw.init = &init;
+ div->clk_id = clk_id;
+ div->div_type = nodes->type;
+
+ hw = &div->hw;
+ ret = clk_hw_register(NULL, hw);
+ if (ret) {
+ kfree(div);
+ hw = ERR_PTR(ret);
+ }
+
+ return hw;
+}
+EXPORT_SYMBOL_GPL(zynqmp_clk_register_divider);
diff --git a/drivers/clk/zynqmp/pll.c b/drivers/clk/zynqmp/pll.c
new file mode 100644
index 000000000000..a541397a172c
--- /dev/null
+++ b/drivers/clk/zynqmp/pll.c
@@ -0,0 +1,335 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Zynq UltraScale+ MPSoC PLL driver
+ *
+ * Copyright (C) 2016-2018 Xilinx
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+#include "clk-zynqmp.h"
+
+/**
+ * struct zynqmp_pll - PLL clock
+ * @hw: Handle between common and hardware-specific interfaces
+ * @clk_id: PLL clock ID
+ */
+struct zynqmp_pll {
+ struct clk_hw hw;
+ u32 clk_id;
+};
+
+#define to_zynqmp_pll(_hw) container_of(_hw, struct zynqmp_pll, hw)
+
+#define PLL_FBDIV_MIN 25
+#define PLL_FBDIV_MAX 125
+
+#define PS_PLL_VCO_MIN 1500000000
+#define PS_PLL_VCO_MAX 3000000000UL
+
+enum pll_mode {
+ PLL_MODE_INT,
+ PLL_MODE_FRAC,
+};
+
+#define FRAC_OFFSET 0x8
+#define PLLFCFG_FRAC_EN BIT(31)
+#define FRAC_DIV BIT(16) /* 2^16 */
+
+/**
+ * zynqmp_pll_get_mode() - Get mode of PLL
+ * @hw: Handle between common and hardware-specific interfaces
+ *
+ * Return: Mode of PLL
+ */
+static inline enum pll_mode zynqmp_pll_get_mode(struct clk_hw *hw)
+{
+ struct zynqmp_pll *clk = to_zynqmp_pll(hw);
+ u32 clk_id = clk->clk_id;
+ const char *clk_name = clk_hw_get_name(hw);
+ u32 ret_payload[PAYLOAD_ARG_CNT];
+ int ret;
+ const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
+
+ ret = eemi_ops->ioctl(0, IOCTL_GET_PLL_FRAC_MODE, clk_id, 0,
+ ret_payload);
+ if (ret)
+ pr_warn_once("%s() PLL get frac mode failed for %s, ret = %d\n",
+ __func__, clk_name, ret);
+
+ return ret_payload[1];
+}
+
+/**
+ * zynqmp_pll_set_mode() - Set the PLL mode
+ * @hw: Handle between common and hardware-specific interfaces
+ * @on: Flag to determine the mode
+ */
+static inline void zynqmp_pll_set_mode(struct clk_hw *hw, bool on)
+{
+ struct zynqmp_pll *clk = to_zynqmp_pll(hw);
+ u32 clk_id = clk->clk_id;
+ const char *clk_name = clk_hw_get_name(hw);
+ int ret;
+ u32 mode;
+ const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
+
+ if (on)
+ mode = PLL_MODE_FRAC;
+ else
+ mode = PLL_MODE_INT;
+
+ ret = eemi_ops->ioctl(0, IOCTL_SET_PLL_FRAC_MODE, clk_id, mode, NULL);
+ if (ret)
+ pr_warn_once("%s() PLL set frac mode failed for %s, ret = %d\n",
+ __func__, clk_name, ret);
+}
+
+/**
+ * zynqmp_pll_round_rate() - Round a clock frequency
+ * @hw: Handle between common and hardware-specific interfaces
+ * @rate: Desired clock frequency
+ * @prate: Clock frequency of parent clock
+ *
+ * Return: Frequency closest to @rate the hardware can generate
+ */
+static long zynqmp_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ u32 fbdiv;
+ long rate_div, f;
+
+ /* Enable the fractional mode if needed */
+ rate_div = (rate * FRAC_DIV) / *prate;
+ f = rate_div % FRAC_DIV;
+ zynqmp_pll_set_mode(hw, !!f);
+
+ if (zynqmp_pll_get_mode(hw) == PLL_MODE_FRAC) {
+ if (rate > PS_PLL_VCO_MAX) {
+ fbdiv = rate / PS_PLL_VCO_MAX;
+ rate = rate / (fbdiv + 1);
+ }
+ if (rate < PS_PLL_VCO_MIN) {
+ fbdiv = DIV_ROUND_UP(PS_PLL_VCO_MIN, rate);
+ rate = rate * fbdiv;
+ }
+ return rate;
+ }
+
+ fbdiv = DIV_ROUND_CLOSEST(rate, *prate);
+ fbdiv = clamp_t(u32, fbdiv, PLL_FBDIV_MIN, PLL_FBDIV_MAX);
+ return *prate * fbdiv;
+}
+
+/**
+ * zynqmp_pll_recalc_rate() - Recalculate clock frequency
+ * @hw: Handle between common and hardware-specific interfaces
+ * @parent_rate: Clock frequency of parent clock
+ *
+ * Return: Current clock frequency
+ */
+static unsigned long zynqmp_pll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct zynqmp_pll *clk = to_zynqmp_pll(hw);
+ u32 clk_id = clk->clk_id;
+ const char *clk_name = clk_hw_get_name(hw);
+ u32 fbdiv, data;
+ unsigned long rate, frac;
+ u32 ret_payload[PAYLOAD_ARG_CNT];
+ int ret;
+ const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
+
+ ret = eemi_ops->clock_getdivider(clk_id, &fbdiv);
+ if (ret)
+ pr_warn_once("%s() get divider failed for %s, ret = %d\n",
+ __func__, clk_name, ret);
+
+ rate = parent_rate * fbdiv;
+ if (zynqmp_pll_get_mode(hw) == PLL_MODE_FRAC) {
+ eemi_ops->ioctl(0, IOCTL_GET_PLL_FRAC_DATA, clk_id, 0,
+ ret_payload);
+ data = ret_payload[1];
+ frac = (parent_rate * data) / FRAC_DIV;
+ rate = rate + frac;
+ }
+
+ return rate;
+}
+
+/**
+ * zynqmp_pll_set_rate() - Set rate of PLL
+ * @hw: Handle between common and hardware-specific interfaces
+ * @rate: Frequency of clock to be set
+ * @parent_rate: Clock frequency of parent clock
+ *
+ * Set PLL divider to set desired rate.
+ *
+ * Returns: rate which is set on success else error code
+ */
+static int zynqmp_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct zynqmp_pll *clk = to_zynqmp_pll(hw);
+ u32 clk_id = clk->clk_id;
+ const char *clk_name = clk_hw_get_name(hw);
+ u32 fbdiv;
+ long rate_div, frac, m, f;
+ int ret;
+ const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
+
+ if (zynqmp_pll_get_mode(hw) == PLL_MODE_FRAC) {
+ rate_div = (rate * FRAC_DIV) / parent_rate;
+ m = rate_div / FRAC_DIV;
+ f = rate_div % FRAC_DIV;
+ m = clamp_t(u32, m, (PLL_FBDIV_MIN), (PLL_FBDIV_MAX));
+ rate = parent_rate * m;
+ frac = (parent_rate * f) / FRAC_DIV;
+
+ ret = eemi_ops->clock_setdivider(clk_id, m);
+ if (ret)
+ pr_warn_once("%s() set divider failed for %s, ret = %d\n",
+ __func__, clk_name, ret);
+
+ eemi_ops->ioctl(0, IOCTL_SET_PLL_FRAC_DATA, clk_id, f, NULL);
+
+ return rate + frac;
+ }
+
+ fbdiv = DIV_ROUND_CLOSEST(rate, parent_rate);
+ fbdiv = clamp_t(u32, fbdiv, PLL_FBDIV_MIN, PLL_FBDIV_MAX);
+ ret = eemi_ops->clock_setdivider(clk_id, fbdiv);
+ if (ret)
+ pr_warn_once("%s() set divider failed for %s, ret = %d\n",
+ __func__, clk_name, ret);
+
+ return parent_rate * fbdiv;
+}
+
+/**
+ * zynqmp_pll_is_enabled() - Check if a clock is enabled
+ * @hw: Handle between common and hardware-specific interfaces
+ *
+ * Return: 1 if the clock is enabled, 0 otherwise
+ */
+static int zynqmp_pll_is_enabled(struct clk_hw *hw)
+{
+ struct zynqmp_pll *clk = to_zynqmp_pll(hw);
+ const char *clk_name = clk_hw_get_name(hw);
+ u32 clk_id = clk->clk_id;
+ unsigned int state;
+ int ret;
+ const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
+
+ ret = eemi_ops->clock_getstate(clk_id, &state);
+ if (ret) {
+ pr_warn_once("%s() clock get state failed for %s, ret = %d\n",
+ __func__, clk_name, ret);
+ return -EIO;
+ }
+
+ return state ? 1 : 0;
+}
+
+/**
+ * zynqmp_pll_enable() - Enable clock
+ * @hw: Handle between common and hardware-specific interfaces
+ *
+ * Return: 0 on success else error code
+ */
+static int zynqmp_pll_enable(struct clk_hw *hw)
+{
+ struct zynqmp_pll *clk = to_zynqmp_pll(hw);
+ const char *clk_name = clk_hw_get_name(hw);
+ u32 clk_id = clk->clk_id;
+ int ret;
+ const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
+
+ if (zynqmp_pll_is_enabled(hw))
+ return 0;
+
+ ret = eemi_ops->clock_enable(clk_id);
+ if (ret)
+ pr_warn_once("%s() clock enable failed for %s, ret = %d\n",
+ __func__, clk_name, ret);
+
+ return ret;
+}
+
+/**
+ * zynqmp_pll_disable() - Disable clock
+ * @hw: Handle between common and hardware-specific interfaces
+ */
+static void zynqmp_pll_disable(struct clk_hw *hw)
+{
+ struct zynqmp_pll *clk = to_zynqmp_pll(hw);
+ const char *clk_name = clk_hw_get_name(hw);
+ u32 clk_id = clk->clk_id;
+ int ret;
+ const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
+
+ if (!zynqmp_pll_is_enabled(hw))
+ return;
+
+ ret = eemi_ops->clock_disable(clk_id);
+ if (ret)
+ pr_warn_once("%s() clock disable failed for %s, ret = %d\n",
+ __func__, clk_name, ret);
+}
+
+static const struct clk_ops zynqmp_pll_ops = {
+ .enable = zynqmp_pll_enable,
+ .disable = zynqmp_pll_disable,
+ .is_enabled = zynqmp_pll_is_enabled,
+ .round_rate = zynqmp_pll_round_rate,
+ .recalc_rate = zynqmp_pll_recalc_rate,
+ .set_rate = zynqmp_pll_set_rate,
+};
+
+/**
+ * zynqmp_clk_register_pll() - Register PLL with the clock framework
+ * @name: PLL name
+ * @clk_id: Clock ID
+ * @parents: Name of this clock's parents
+ * @num_parents: Number of parents
+ * @nodes: Clock topology node
+ *
+ * Return: clock hardware to the registered clock
+ */
+struct clk_hw *zynqmp_clk_register_pll(const char *name, u32 clk_id,
+ const char * const *parents,
+ u8 num_parents,
+ const struct clock_topology *nodes)
+{
+ struct zynqmp_pll *pll;
+ struct clk_hw *hw;
+ struct clk_init_data init;
+ int ret;
+
+ init.name = name;
+ init.ops = &zynqmp_pll_ops;
+ init.flags = nodes->flag;
+ init.parent_names = parents;
+ init.num_parents = 1;
+
+ pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+ if (!pll)
+ return ERR_PTR(-ENOMEM);
+
+ pll->hw.init = &init;
+ pll->clk_id = clk_id;
+
+ hw = &pll->hw;
+ ret = clk_hw_register(NULL, hw);
+ if (ret) {
+ kfree(pll);
+ return ERR_PTR(ret);
+ }
+
+ 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 a11f4ba98b05..55c77e44bb2d 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -620,4 +620,22 @@ config RISCV_TIMER
is accessed via both the SBI and the rdcycle instruction. This is
required for all RISC-V systems.
+config CSKY_MP_TIMER
+ bool "SMP Timer for the C-SKY platform" if COMPILE_TEST
+ depends on CSKY
+ select TIMER_OF
+ help
+ Say yes here to enable C-SKY SMP timer driver used for C-SKY SMP
+ system.
+ csky,mptimer is not only used in SMP system, it also could be used
+ single core system. It's not a mmio reg and it use mtcr/mfcr instruction.
+
+config GX6605S_TIMER
+ bool "Gx6605s SOC system timer driver" if COMPILE_TEST
+ depends on CSKY
+ select CLKSRC_MMIO
+ select TIMER_OF
+ help
+ This option enables support for gx6605s SOC's timer.
+
endmenu
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index db51b2427e8a..dd9138104568 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -23,8 +23,8 @@ obj-$(CONFIG_FTTMR010_TIMER) += timer-fttmr010.o
obj-$(CONFIG_ROCKCHIP_TIMER) += rockchip_timer.o
obj-$(CONFIG_CLKSRC_NOMADIK_MTU) += nomadik-mtu.o
obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o
-obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o
-obj-$(CONFIG_ORION_TIMER) += time-orion.o
+obj-$(CONFIG_ARMADA_370_XP_TIMER) += timer-armada-370-xp.o
+obj-$(CONFIG_ORION_TIMER) += timer-orion.o
obj-$(CONFIG_BCM2835_TIMER) += bcm2835_timer.o
obj-$(CONFIG_CLPS711X_TIMER) += clps711x-timer.o
obj-$(CONFIG_ATLAS7_TIMER) += timer-atlas7.o
@@ -36,25 +36,25 @@ obj-$(CONFIG_SUN4I_TIMER) += sun4i_timer.o
obj-$(CONFIG_SUN5I_HSTIMER) += timer-sun5i.o
obj-$(CONFIG_MESON6_TIMER) += meson6_timer.o
obj-$(CONFIG_TEGRA_TIMER) += tegra20_timer.o
-obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o
-obj-$(CONFIG_NSPIRE_TIMER) += zevio-timer.o
+obj-$(CONFIG_VT8500_TIMER) += timer-vt8500.o
+obj-$(CONFIG_NSPIRE_TIMER) += timer-zevio.o
obj-$(CONFIG_BCM_KONA_TIMER) += bcm_kona_timer.o
-obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence_ttc_timer.o
-obj-$(CONFIG_CLKSRC_EFM32) += time-efm32.o
+obj-$(CONFIG_CADENCE_TTC_TIMER) += timer-cadence-ttc.o
+obj-$(CONFIG_CLKSRC_EFM32) += timer-efm32.o
obj-$(CONFIG_CLKSRC_STM32) += timer-stm32.o
obj-$(CONFIG_CLKSRC_EXYNOS_MCT) += exynos_mct.o
-obj-$(CONFIG_CLKSRC_LPC32XX) += time-lpc32xx.o
+obj-$(CONFIG_CLKSRC_LPC32XX) += timer-lpc32xx.o
obj-$(CONFIG_CLKSRC_MPS2) += mps2-timer.o
obj-$(CONFIG_CLKSRC_SAMSUNG_PWM) += samsung_pwm_timer.o
-obj-$(CONFIG_FSL_FTM_TIMER) += fsl_ftm_timer.o
-obj-$(CONFIG_VF_PIT_TIMER) += vf_pit_timer.o
-obj-$(CONFIG_CLKSRC_QCOM) += qcom-timer.o
+obj-$(CONFIG_FSL_FTM_TIMER) += timer-fsl-ftm.o
+obj-$(CONFIG_VF_PIT_TIMER) += timer-vf-pit.o
+obj-$(CONFIG_CLKSRC_QCOM) += timer-qcom.o
obj-$(CONFIG_MTK_TIMER) += timer-mediatek.o
-obj-$(CONFIG_CLKSRC_PISTACHIO) += time-pistachio.o
+obj-$(CONFIG_CLKSRC_PISTACHIO) += timer-pistachio.o
obj-$(CONFIG_CLKSRC_TI_32K) += timer-ti-32k.o
obj-$(CONFIG_CLKSRC_NPS) += timer-nps.o
obj-$(CONFIG_OXNAS_RPS_TIMER) += timer-oxnas-rps.o
-obj-$(CONFIG_OWL_TIMER) += owl-timer.o
+obj-$(CONFIG_OWL_TIMER) += timer-owl.o
obj-$(CONFIG_SPRD_TIMER) += timer-sprd.o
obj-$(CONFIG_NPCM7XX_TIMER) += timer-npcm7xx.o
@@ -66,7 +66,7 @@ obj-$(CONFIG_ARM_TIMER_SP804) += timer-sp804.o
obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST) += dummy_timer.o
obj-$(CONFIG_KEYSTONE_TIMER) += timer-keystone.o
obj-$(CONFIG_INTEGRATOR_AP_TIMER) += timer-integrator-ap.o
-obj-$(CONFIG_CLKSRC_VERSATILE) += versatile.o
+obj-$(CONFIG_CLKSRC_VERSATILE) += timer-versatile.o
obj-$(CONFIG_CLKSRC_MIPS_GIC) += mips-gic-timer.o
obj-$(CONFIG_CLKSRC_TANGO_XTAL) += tango_xtal.o
obj-$(CONFIG_CLKSRC_IMX_GPT) += timer-imx-gpt.o
@@ -79,3 +79,5 @@ obj-$(CONFIG_CLKSRC_ST_LPC) += clksrc_st_lpc.o
obj-$(CONFIG_X86_NUMACHIP) += numachip.o
obj-$(CONFIG_ATCPIT100_TIMER) += timer-atcpit100.o
obj-$(CONFIG_RISCV_TIMER) += riscv_timer.o
+obj-$(CONFIG_CSKY_MP_TIMER) += timer-mp-csky.o
+obj-$(CONFIG_GX6605S_TIMER) += timer-gx6605s.o
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index d8c7f5750cdb..9a7d4dc00b6e 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -319,6 +319,13 @@ static u64 notrace arm64_858921_read_cntvct_el0(void)
}
#endif
+#ifdef CONFIG_ARM64_ERRATUM_1188873
+static u64 notrace arm64_1188873_read_cntvct_el0(void)
+{
+ return read_sysreg(cntvct_el0);
+}
+#endif
+
#ifdef CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND
DEFINE_PER_CPU(const struct arch_timer_erratum_workaround *, timer_unstable_counter_workaround);
EXPORT_SYMBOL_GPL(timer_unstable_counter_workaround);
@@ -408,6 +415,14 @@ static const struct arch_timer_erratum_workaround ool_workarounds[] = {
.read_cntvct_el0 = arm64_858921_read_cntvct_el0,
},
#endif
+#ifdef CONFIG_ARM64_ERRATUM_1188873
+ {
+ .match_type = ate_match_local_cap_id,
+ .id = (void *)ARM64_WORKAROUND_1188873,
+ .desc = "ARM erratum 1188873",
+ .read_cntvct_el0 = arm64_1188873_read_cntvct_el0,
+ },
+#endif
};
typedef bool (*ate_match_fn_t)(const struct arch_timer_erratum_workaround *,
diff --git a/drivers/clocksource/asm9260_timer.c b/drivers/clocksource/asm9260_timer.c
index 38cd2feb87c4..fbaee04fd1d9 100644
--- a/drivers/clocksource/asm9260_timer.c
+++ b/drivers/clocksource/asm9260_timer.c
@@ -193,7 +193,7 @@ static int __init asm9260_timer_init(struct device_node *np)
priv.base = of_io_request_and_map(np, 0, np->name);
if (IS_ERR(priv.base)) {
- pr_err("%s: unable to map resource\n", np->name);
+ pr_err("%pOFn: unable to map resource\n", np);
return PTR_ERR(priv.base);
}
diff --git a/drivers/clocksource/dw_apb_timer_of.c b/drivers/clocksource/dw_apb_timer_of.c
index 69866cd8f4bb..db410acd8964 100644
--- a/drivers/clocksource/dw_apb_timer_of.c
+++ b/drivers/clocksource/dw_apb_timer_of.c
@@ -22,6 +22,7 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/clk.h>
+#include <linux/reset.h>
#include <linux/sched_clock.h>
static void __init timer_get_base_and_rate(struct device_node *np,
@@ -29,11 +30,22 @@ static void __init timer_get_base_and_rate(struct device_node *np,
{
struct clk *timer_clk;
struct clk *pclk;
+ struct reset_control *rstc;
*base = of_iomap(np, 0);
if (!*base)
- panic("Unable to map regs for %s", np->name);
+ panic("Unable to map regs for %pOFn", np);
+
+ /*
+ * Reset the timer if the reset control is available, wiping
+ * out the state the firmware may have left it
+ */
+ rstc = of_reset_control_get(np, NULL);
+ if (!IS_ERR(rstc)) {
+ reset_control_assert(rstc);
+ reset_control_deassert(rstc);
+ }
/*
* Not all implementations use a periphal clock, so don't panic
@@ -42,8 +54,8 @@ static void __init timer_get_base_and_rate(struct device_node *np,
pclk = of_clk_get_by_name(np, "pclk");
if (!IS_ERR(pclk))
if (clk_prepare_enable(pclk))
- pr_warn("pclk for %s is present, but could not be activated\n",
- np->name);
+ pr_warn("pclk for %pOFn is present, but could not be activated\n",
+ np);
timer_clk = of_clk_get_by_name(np, "timer");
if (IS_ERR(timer_clk))
@@ -57,7 +69,7 @@ static void __init timer_get_base_and_rate(struct device_node *np,
try_clock_freq:
if (of_property_read_u32(np, "clock-freq", rate) &&
of_property_read_u32(np, "clock-frequency", rate))
- panic("No clock nor clock-frequency property for %s", np->name);
+ panic("No clock nor clock-frequency property for %pOFn", np);
}
static void __init add_clockevent(struct device_node *event_timer)
diff --git a/drivers/clocksource/i8253.c b/drivers/clocksource/i8253.c
index 9c38895542f4..d4350bb10b83 100644
--- a/drivers/clocksource/i8253.c
+++ b/drivers/clocksource/i8253.c
@@ -20,6 +20,13 @@
DEFINE_RAW_SPINLOCK(i8253_lock);
EXPORT_SYMBOL(i8253_lock);
+/*
+ * Handle PIT quirk in pit_shutdown() where zeroing the counter register
+ * restarts the PIT, negating the shutdown. On platforms with the quirk,
+ * platform specific code can set this to false.
+ */
+bool i8253_clear_counter_on_shutdown __ro_after_init = true;
+
#ifdef CONFIG_CLKSRC_I8253
/*
* Since the PIT overflows every tick, its not very useful
@@ -109,8 +116,11 @@ static int pit_shutdown(struct clock_event_device *evt)
raw_spin_lock(&i8253_lock);
outb_p(0x30, PIT_MODE);
- outb_p(0, PIT_CH0);
- outb_p(0, PIT_CH0);
+
+ if (i8253_clear_counter_on_shutdown) {
+ outb_p(0, PIT_CH0);
+ outb_p(0, PIT_CH0);
+ }
raw_spin_unlock(&i8253_lock);
return 0;
diff --git a/drivers/clocksource/pxa_timer.c b/drivers/clocksource/pxa_timer.c
index 08cd6eaf3795..395837938301 100644
--- a/drivers/clocksource/pxa_timer.c
+++ b/drivers/clocksource/pxa_timer.c
@@ -191,13 +191,13 @@ static int __init pxa_timer_dt_init(struct device_node *np)
/* timer registers are shared with watchdog timer */
timer_base = of_iomap(np, 0);
if (!timer_base) {
- pr_err("%s: unable to map resource\n", np->name);
+ pr_err("%pOFn: unable to map resource\n", np);
return -ENXIO;
}
clk = of_clk_get(np, 0);
if (IS_ERR(clk)) {
- pr_crit("%s: unable to get clk\n", np->name);
+ pr_crit("%pOFn: unable to get clk\n", np);
return PTR_ERR(clk);
}
@@ -210,7 +210,7 @@ static int __init pxa_timer_dt_init(struct device_node *np)
/* we are only interested in OS-timer0 irq */
irq = irq_of_parse_and_map(np, 0);
if (irq <= 0) {
- pr_crit("%s: unable to parse OS-timer0 irq\n", np->name);
+ pr_crit("%pOFn: unable to parse OS-timer0 irq\n", np);
return -EINVAL;
}
diff --git a/drivers/clocksource/renesas-ostm.c b/drivers/clocksource/renesas-ostm.c
index 6cffd7c6001a..61d5f3b539ce 100644
--- a/drivers/clocksource/renesas-ostm.c
+++ b/drivers/clocksource/renesas-ostm.c
@@ -1,18 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Renesas Timer Support - OSTM
*
* Copyright (C) 2017 Renesas Electronics America, Inc.
* Copyright (C) 2017 Chris Brandt
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <linux/of_address.h>
diff --git a/drivers/clocksource/riscv_timer.c b/drivers/clocksource/riscv_timer.c
index 4e8b347e43e2..084e97dc10ed 100644
--- a/drivers/clocksource/riscv_timer.c
+++ b/drivers/clocksource/riscv_timer.c
@@ -8,6 +8,7 @@
#include <linux/cpu.h>
#include <linux/delay.h>
#include <linux/irq.h>
+#include <asm/smp.h>
#include <asm/sbi.h>
/*
@@ -84,13 +85,16 @@ void riscv_timer_interrupt(void)
static int __init riscv_timer_init_dt(struct device_node *n)
{
- int cpu_id = riscv_of_processor_hart(n), error;
+ int cpuid, hartid, error;
struct clocksource *cs;
- if (cpu_id != smp_processor_id())
+ hartid = riscv_of_processor_hartid(n);
+ cpuid = riscv_hartid_to_cpuid(hartid);
+
+ if (cpuid != smp_processor_id())
return 0;
- cs = per_cpu_ptr(&riscv_clocksource, cpu_id);
+ cs = per_cpu_ptr(&riscv_clocksource, cpuid);
clocksource_register_hz(cs, riscv_timebase);
error = cpuhp_setup_state(CPUHP_AP_RISCV_TIMER_STARTING,
@@ -98,7 +102,7 @@ static int __init riscv_timer_init_dt(struct device_node *n)
riscv_timer_starting_cpu, riscv_timer_dying_cpu);
if (error)
pr_err("RISCV timer register failed [%d] for cpu = [%d]\n",
- error, cpu_id);
+ error, cpuid);
return error;
}
diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c
index bbbf37c471a3..55d3e03f2cd4 100644
--- a/drivers/clocksource/sh_cmt.c
+++ b/drivers/clocksource/sh_cmt.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* SuperH Timer Support - CMT
*
* Copyright (C) 2008 Magnus Damm
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/clk.h>
@@ -78,18 +70,17 @@ struct sh_cmt_info {
unsigned int channels_mask;
unsigned long width; /* 16 or 32 bit version of hardware block */
- unsigned long overflow_bit;
- unsigned long clear_bits;
+ u32 overflow_bit;
+ u32 clear_bits;
/* callbacks for CMSTR and CMCSR access */
- unsigned long (*read_control)(void __iomem *base, unsigned long offs);
+ u32 (*read_control)(void __iomem *base, unsigned long offs);
void (*write_control)(void __iomem *base, unsigned long offs,
- unsigned long value);
+ u32 value);
/* callbacks for CMCNT and CMCOR access */
- unsigned long (*read_count)(void __iomem *base, unsigned long offs);
- void (*write_count)(void __iomem *base, unsigned long offs,
- unsigned long value);
+ u32 (*read_count)(void __iomem *base, unsigned long offs);
+ void (*write_count)(void __iomem *base, unsigned long offs, u32 value);
};
struct sh_cmt_channel {
@@ -103,13 +94,13 @@ struct sh_cmt_channel {
unsigned int timer_bit;
unsigned long flags;
- unsigned long match_value;
- unsigned long next_match_value;
- unsigned long max_match_value;
+ u32 match_value;
+ u32 next_match_value;
+ u32 max_match_value;
raw_spinlock_t lock;
struct clock_event_device ced;
struct clocksource cs;
- unsigned long total_cycles;
+ u64 total_cycles;
bool cs_enabled;
};
@@ -160,24 +151,22 @@ struct sh_cmt_device {
#define SH_CMT32_CMCSR_CKS_RCLK1 (7 << 0)
#define SH_CMT32_CMCSR_CKS_MASK (7 << 0)
-static unsigned long sh_cmt_read16(void __iomem *base, unsigned long offs)
+static u32 sh_cmt_read16(void __iomem *base, unsigned long offs)
{
return ioread16(base + (offs << 1));
}
-static unsigned long sh_cmt_read32(void __iomem *base, unsigned long offs)
+static u32 sh_cmt_read32(void __iomem *base, unsigned long offs)
{
return ioread32(base + (offs << 2));
}
-static void sh_cmt_write16(void __iomem *base, unsigned long offs,
- unsigned long value)
+static void sh_cmt_write16(void __iomem *base, unsigned long offs, u32 value)
{
iowrite16(value, base + (offs << 1));
}
-static void sh_cmt_write32(void __iomem *base, unsigned long offs,
- unsigned long value)
+static void sh_cmt_write32(void __iomem *base, unsigned long offs, u32 value)
{
iowrite32(value, base + (offs << 2));
}
@@ -242,7 +231,7 @@ static const struct sh_cmt_info sh_cmt_info[] = {
#define CMCNT 1 /* channel register */
#define CMCOR 2 /* channel register */
-static inline unsigned long sh_cmt_read_cmstr(struct sh_cmt_channel *ch)
+static inline u32 sh_cmt_read_cmstr(struct sh_cmt_channel *ch)
{
if (ch->iostart)
return ch->cmt->info->read_control(ch->iostart, 0);
@@ -250,8 +239,7 @@ static inline unsigned long sh_cmt_read_cmstr(struct sh_cmt_channel *ch)
return ch->cmt->info->read_control(ch->cmt->mapbase, 0);
}
-static inline void sh_cmt_write_cmstr(struct sh_cmt_channel *ch,
- unsigned long value)
+static inline void sh_cmt_write_cmstr(struct sh_cmt_channel *ch, u32 value)
{
if (ch->iostart)
ch->cmt->info->write_control(ch->iostart, 0, value);
@@ -259,39 +247,35 @@ static inline void sh_cmt_write_cmstr(struct sh_cmt_channel *ch,
ch->cmt->info->write_control(ch->cmt->mapbase, 0, value);
}
-static inline unsigned long sh_cmt_read_cmcsr(struct sh_cmt_channel *ch)
+static inline u32 sh_cmt_read_cmcsr(struct sh_cmt_channel *ch)
{
return ch->cmt->info->read_control(ch->ioctrl, CMCSR);
}
-static inline void sh_cmt_write_cmcsr(struct sh_cmt_channel *ch,
- unsigned long value)
+static inline void sh_cmt_write_cmcsr(struct sh_cmt_channel *ch, u32 value)
{
ch->cmt->info->write_control(ch->ioctrl, CMCSR, value);
}
-static inline unsigned long sh_cmt_read_cmcnt(struct sh_cmt_channel *ch)
+static inline u32 sh_cmt_read_cmcnt(struct sh_cmt_channel *ch)
{
return ch->cmt->info->read_count(ch->ioctrl, CMCNT);
}
-static inline void sh_cmt_write_cmcnt(struct sh_cmt_channel *ch,
- unsigned long value)
+static inline void sh_cmt_write_cmcnt(struct sh_cmt_channel *ch, u32 value)
{
ch->cmt->info->write_count(ch->ioctrl, CMCNT, value);
}
-static inline void sh_cmt_write_cmcor(struct sh_cmt_channel *ch,
- unsigned long value)
+static inline void sh_cmt_write_cmcor(struct sh_cmt_channel *ch, u32 value)
{
ch->cmt->info->write_count(ch->ioctrl, CMCOR, value);
}
-static unsigned long sh_cmt_get_counter(struct sh_cmt_channel *ch,
- int *has_wrapped)
+static u32 sh_cmt_get_counter(struct sh_cmt_channel *ch, u32 *has_wrapped)
{
- unsigned long v1, v2, v3;
- int o1, o2;
+ u32 v1, v2, v3;
+ u32 o1, o2;
o1 = sh_cmt_read_cmcsr(ch) & ch->cmt->info->overflow_bit;
@@ -311,7 +295,8 @@ static unsigned long sh_cmt_get_counter(struct sh_cmt_channel *ch,
static void sh_cmt_start_stop_ch(struct sh_cmt_channel *ch, int start)
{
- unsigned long flags, value;
+ unsigned long flags;
+ u32 value;
/* start stop register shared by multiple timer channels */
raw_spin_lock_irqsave(&ch->cmt->lock, flags);
@@ -418,11 +403,11 @@ static void sh_cmt_disable(struct sh_cmt_channel *ch)
static void sh_cmt_clock_event_program_verify(struct sh_cmt_channel *ch,
int absolute)
{
- unsigned long new_match;
- unsigned long value = ch->next_match_value;
- unsigned long delay = 0;
- unsigned long now = 0;
- int has_wrapped;
+ u32 value = ch->next_match_value;
+ u32 new_match;
+ u32 delay = 0;
+ u32 now = 0;
+ u32 has_wrapped;
now = sh_cmt_get_counter(ch, &has_wrapped);
ch->flags |= FLAG_REPROGRAM; /* force reprogram */
@@ -619,9 +604,10 @@ static struct sh_cmt_channel *cs_to_sh_cmt(struct clocksource *cs)
static u64 sh_cmt_clocksource_read(struct clocksource *cs)
{
struct sh_cmt_channel *ch = cs_to_sh_cmt(cs);
- unsigned long flags, raw;
- unsigned long value;
- int has_wrapped;
+ unsigned long flags;
+ u32 has_wrapped;
+ u64 value;
+ u32 raw;
raw_spin_lock_irqsave(&ch->lock, flags);
value = ch->total_cycles;
@@ -694,7 +680,7 @@ static int sh_cmt_register_clocksource(struct sh_cmt_channel *ch,
cs->disable = sh_cmt_clocksource_disable;
cs->suspend = sh_cmt_clocksource_suspend;
cs->resume = sh_cmt_clocksource_resume;
- cs->mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8);
+ cs->mask = CLOCKSOURCE_MASK(sizeof(u64) * 8);
cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
dev_info(&ch->cmt->pdev->dev, "ch%u: used as clock source\n",
@@ -941,8 +927,22 @@ static const struct of_device_id sh_cmt_of_table[] __maybe_unused = {
.compatible = "renesas,cmt-48-gen2",
.data = &sh_cmt_info[SH_CMT0_RCAR_GEN2]
},
- { .compatible = "renesas,rcar-gen2-cmt0", .data = &sh_cmt_info[SH_CMT0_RCAR_GEN2] },
- { .compatible = "renesas,rcar-gen2-cmt1", .data = &sh_cmt_info[SH_CMT1_RCAR_GEN2] },
+ {
+ .compatible = "renesas,rcar-gen2-cmt0",
+ .data = &sh_cmt_info[SH_CMT0_RCAR_GEN2]
+ },
+ {
+ .compatible = "renesas,rcar-gen2-cmt1",
+ .data = &sh_cmt_info[SH_CMT1_RCAR_GEN2]
+ },
+ {
+ .compatible = "renesas,rcar-gen3-cmt0",
+ .data = &sh_cmt_info[SH_CMT0_RCAR_GEN2]
+ },
+ {
+ .compatible = "renesas,rcar-gen3-cmt1",
+ .data = &sh_cmt_info[SH_CMT1_RCAR_GEN2]
+ },
{ }
};
MODULE_DEVICE_TABLE(of, sh_cmt_of_table);
diff --git a/drivers/clocksource/sh_mtu2.c b/drivers/clocksource/sh_mtu2.c
index 6812e099b6a3..354b27d14a19 100644
--- a/drivers/clocksource/sh_mtu2.c
+++ b/drivers/clocksource/sh_mtu2.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* SuperH Timer Support - MTU2
*
* Copyright (C) 2009 Magnus Damm
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/clk.h>
diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c
index c74a6c543ca2..49f1c805fc95 100644
--- a/drivers/clocksource/sh_tmu.c
+++ b/drivers/clocksource/sh_tmu.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* SuperH Timer Support - TMU
*
* Copyright (C) 2009 Magnus Damm
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/clk.h>
diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/timer-armada-370-xp.c
index edf1a46269f1..edf1a46269f1 100644
--- a/drivers/clocksource/time-armada-370-xp.c
+++ b/drivers/clocksource/timer-armada-370-xp.c
diff --git a/drivers/clocksource/cadence_ttc_timer.c b/drivers/clocksource/timer-cadence-ttc.c
index 29d51755e18b..b33402980b6f 100644
--- a/drivers/clocksource/cadence_ttc_timer.c
+++ b/drivers/clocksource/timer-cadence-ttc.c
@@ -535,7 +535,7 @@ static int __init ttc_timer_init(struct device_node *timer)
if (ret)
return ret;
- pr_info("%s #0 at %p, irq=%d\n", timer->name, timer_baseaddr, irq);
+ pr_info("%pOFn #0 at %p, irq=%d\n", timer, timer_baseaddr, irq);
return 0;
}
diff --git a/drivers/clocksource/time-efm32.c b/drivers/clocksource/timer-efm32.c
index 257e810ec1ad..257e810ec1ad 100644
--- a/drivers/clocksource/time-efm32.c
+++ b/drivers/clocksource/timer-efm32.c
diff --git a/drivers/clocksource/fsl_ftm_timer.c b/drivers/clocksource/timer-fsl-ftm.c
index 846d18daf893..846d18daf893 100644
--- a/drivers/clocksource/fsl_ftm_timer.c
+++ b/drivers/clocksource/timer-fsl-ftm.c
diff --git a/drivers/clocksource/timer-gx6605s.c b/drivers/clocksource/timer-gx6605s.c
new file mode 100644
index 000000000000..80d0939d040b
--- /dev/null
+++ b/drivers/clocksource/timer-gx6605s.c
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/sched_clock.h>
+
+#include "timer-of.h"
+
+#define CLKSRC_OFFSET 0x40
+
+#define TIMER_STATUS 0x00
+#define TIMER_VALUE 0x04
+#define TIMER_CONTRL 0x10
+#define TIMER_CONFIG 0x20
+#define TIMER_DIV 0x24
+#define TIMER_INI 0x28
+
+#define GX6605S_STATUS_CLR BIT(0)
+#define GX6605S_CONTRL_RST BIT(0)
+#define GX6605S_CONTRL_START BIT(1)
+#define GX6605S_CONFIG_EN BIT(0)
+#define GX6605S_CONFIG_IRQ_EN BIT(1)
+
+static irqreturn_t gx6605s_timer_interrupt(int irq, void *dev)
+{
+ struct clock_event_device *ce = dev;
+ void __iomem *base = timer_of_base(to_timer_of(ce));
+
+ writel_relaxed(GX6605S_STATUS_CLR, base + TIMER_STATUS);
+
+ ce->event_handler(ce);
+
+ return IRQ_HANDLED;
+}
+
+static int gx6605s_timer_set_oneshot(struct clock_event_device *ce)
+{
+ void __iomem *base = timer_of_base(to_timer_of(ce));
+
+ /* reset and stop counter */
+ writel_relaxed(GX6605S_CONTRL_RST, base + TIMER_CONTRL);
+
+ /* enable with irq and start */
+ writel_relaxed(GX6605S_CONFIG_EN | GX6605S_CONFIG_IRQ_EN,
+ base + TIMER_CONFIG);
+
+ return 0;
+}
+
+static int gx6605s_timer_set_next_event(unsigned long delta,
+ struct clock_event_device *ce)
+{
+ void __iomem *base = timer_of_base(to_timer_of(ce));
+
+ /* use reset to pause timer */
+ writel_relaxed(GX6605S_CONTRL_RST, base + TIMER_CONTRL);
+
+ /* config next timeout value */
+ writel_relaxed(ULONG_MAX - delta, base + TIMER_INI);
+ writel_relaxed(GX6605S_CONTRL_START, base + TIMER_CONTRL);
+
+ return 0;
+}
+
+static int gx6605s_timer_shutdown(struct clock_event_device *ce)
+{
+ void __iomem *base = timer_of_base(to_timer_of(ce));
+
+ writel_relaxed(0, base + TIMER_CONTRL);
+ writel_relaxed(0, base + TIMER_CONFIG);
+
+ return 0;
+}
+
+static struct timer_of to = {
+ .flags = TIMER_OF_IRQ | TIMER_OF_BASE | TIMER_OF_CLOCK,
+ .clkevt = {
+ .rating = 300,
+ .features = CLOCK_EVT_FEAT_DYNIRQ |
+ CLOCK_EVT_FEAT_ONESHOT,
+ .set_state_shutdown = gx6605s_timer_shutdown,
+ .set_state_oneshot = gx6605s_timer_set_oneshot,
+ .set_next_event = gx6605s_timer_set_next_event,
+ .cpumask = cpu_possible_mask,
+ },
+ .of_irq = {
+ .handler = gx6605s_timer_interrupt,
+ .flags = IRQF_TIMER | IRQF_IRQPOLL,
+ },
+};
+
+static u64 notrace gx6605s_sched_clock_read(void)
+{
+ void __iomem *base;
+
+ base = timer_of_base(&to) + CLKSRC_OFFSET;
+
+ return (u64)readl_relaxed(base + TIMER_VALUE);
+}
+
+static void gx6605s_clkevt_init(void __iomem *base)
+{
+ writel_relaxed(0, base + TIMER_DIV);
+ writel_relaxed(0, base + TIMER_CONFIG);
+
+ clockevents_config_and_register(&to.clkevt, timer_of_rate(&to), 2,
+ ULONG_MAX);
+}
+
+static int gx6605s_clksrc_init(void __iomem *base)
+{
+ writel_relaxed(0, base + TIMER_DIV);
+ writel_relaxed(0, base + TIMER_INI);
+
+ writel_relaxed(GX6605S_CONTRL_RST, base + TIMER_CONTRL);
+
+ writel_relaxed(GX6605S_CONFIG_EN, base + TIMER_CONFIG);
+
+ writel_relaxed(GX6605S_CONTRL_START, base + TIMER_CONTRL);
+
+ sched_clock_register(gx6605s_sched_clock_read, 32, timer_of_rate(&to));
+
+ return clocksource_mmio_init(base + TIMER_VALUE, "gx6605s",
+ timer_of_rate(&to), 200, 32, clocksource_mmio_readl_up);
+}
+
+static int __init gx6605s_timer_init(struct device_node *np)
+{
+ int ret;
+
+ /*
+ * The timer driver is for nationalchip gx6605s SOC and there are two
+ * same timer in gx6605s. We use one for clkevt and another for clksrc.
+ *
+ * The timer is mmio map to access, so we need give mmio address in dts.
+ *
+ * It provides a 32bit countup timer and interrupt will be caused by
+ * count-overflow.
+ * So we need set-next-event by ULONG_MAX - delta in TIMER_INI reg.
+ *
+ * The counter at 0x0 offset is clock event.
+ * The counter at 0x40 offset is clock source.
+ * They are the same in hardware, just different used by driver.
+ */
+ ret = timer_of_init(np, &to);
+ if (ret)
+ return ret;
+
+ gx6605s_clkevt_init(timer_of_base(&to));
+
+ return gx6605s_clksrc_init(timer_of_base(&to) + CLKSRC_OFFSET);
+}
+TIMER_OF_DECLARE(csky_gx6605s_timer, "csky,gx6605s-timer", gx6605s_timer_init);
diff --git a/drivers/clocksource/timer-integrator-ap.c b/drivers/clocksource/timer-integrator-ap.c
index 62d24690ba02..76e526f58620 100644
--- a/drivers/clocksource/timer-integrator-ap.c
+++ b/drivers/clocksource/timer-integrator-ap.c
@@ -190,7 +190,7 @@ static int __init integrator_ap_timer_init_of(struct device_node *node)
clk = of_clk_get(node, 0);
if (IS_ERR(clk)) {
- pr_err("No clock for %s\n", node->name);
+ pr_err("No clock for %pOFn\n", node);
return PTR_ERR(clk);
}
clk_prepare_enable(clk);
diff --git a/drivers/clocksource/time-lpc32xx.c b/drivers/clocksource/timer-lpc32xx.c
index d51a62a79ef7..d51a62a79ef7 100644
--- a/drivers/clocksource/time-lpc32xx.c
+++ b/drivers/clocksource/timer-lpc32xx.c
diff --git a/drivers/clocksource/timer-mp-csky.c b/drivers/clocksource/timer-mp-csky.c
new file mode 100644
index 000000000000..a8acc431a774
--- /dev/null
+++ b/drivers/clocksource/timer-mp-csky.c
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/sched_clock.h>
+#include <linux/cpu.h>
+#include <linux/of_irq.h>
+#include <asm/reg_ops.h>
+
+#include "timer-of.h"
+
+#define PTIM_CCVR "cr<3, 14>"
+#define PTIM_CTLR "cr<0, 14>"
+#define PTIM_LVR "cr<6, 14>"
+#define PTIM_TSR "cr<1, 14>"
+
+static int csky_mptimer_irq;
+
+static int csky_mptimer_set_next_event(unsigned long delta,
+ struct clock_event_device *ce)
+{
+ mtcr(PTIM_LVR, delta);
+
+ return 0;
+}
+
+static int csky_mptimer_shutdown(struct clock_event_device *ce)
+{
+ mtcr(PTIM_CTLR, 0);
+
+ return 0;
+}
+
+static int csky_mptimer_oneshot(struct clock_event_device *ce)
+{
+ mtcr(PTIM_CTLR, 1);
+
+ return 0;
+}
+
+static int csky_mptimer_oneshot_stopped(struct clock_event_device *ce)
+{
+ mtcr(PTIM_CTLR, 0);
+
+ return 0;
+}
+
+static DEFINE_PER_CPU(struct timer_of, csky_to) = {
+ .flags = TIMER_OF_CLOCK,
+ .clkevt = {
+ .rating = 300,
+ .features = CLOCK_EVT_FEAT_PERCPU |
+ CLOCK_EVT_FEAT_ONESHOT,
+ .set_state_shutdown = csky_mptimer_shutdown,
+ .set_state_oneshot = csky_mptimer_oneshot,
+ .set_state_oneshot_stopped = csky_mptimer_oneshot_stopped,
+ .set_next_event = csky_mptimer_set_next_event,
+ },
+};
+
+static irqreturn_t csky_timer_interrupt(int irq, void *dev)
+{
+ struct timer_of *to = this_cpu_ptr(&csky_to);
+
+ mtcr(PTIM_TSR, 0);
+
+ to->clkevt.event_handler(&to->clkevt);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * clock event for percpu
+ */
+static int csky_mptimer_starting_cpu(unsigned int cpu)
+{
+ struct timer_of *to = per_cpu_ptr(&csky_to, cpu);
+
+ to->clkevt.cpumask = cpumask_of(cpu);
+
+ clockevents_config_and_register(&to->clkevt, timer_of_rate(to),
+ 2, ULONG_MAX);
+
+ enable_percpu_irq(csky_mptimer_irq, 0);
+
+ return 0;
+}
+
+static int csky_mptimer_dying_cpu(unsigned int cpu)
+{
+ disable_percpu_irq(csky_mptimer_irq);
+
+ return 0;
+}
+
+/*
+ * clock source
+ */
+static u64 sched_clock_read(void)
+{
+ return (u64)mfcr(PTIM_CCVR);
+}
+
+static u64 clksrc_read(struct clocksource *c)
+{
+ return (u64)mfcr(PTIM_CCVR);
+}
+
+struct clocksource csky_clocksource = {
+ .name = "csky",
+ .rating = 400,
+ .mask = CLOCKSOURCE_MASK(32),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+ .read = clksrc_read,
+};
+
+static int __init csky_mptimer_init(struct device_node *np)
+{
+ int ret, cpu, cpu_rollback;
+ struct timer_of *to = NULL;
+
+ /*
+ * Csky_mptimer is designed for C-SKY SMP multi-processors and
+ * every core has it's own private irq and regs for clkevt and
+ * clksrc.
+ *
+ * The regs is accessed by cpu instruction: mfcr/mtcr instead of
+ * mmio map style. So we needn't mmio-address in dts, but we still
+ * need to give clk and irq number.
+ *
+ * We use private irq for the mptimer and irq number is the same
+ * for every core. So we use request_percpu_irq() in timer_of_init.
+ */
+ csky_mptimer_irq = irq_of_parse_and_map(np, 0);
+ if (csky_mptimer_irq <= 0)
+ return -EINVAL;
+
+ ret = request_percpu_irq(csky_mptimer_irq, csky_timer_interrupt,
+ "csky_mp_timer", &csky_to);
+ if (ret)
+ return -EINVAL;
+
+ for_each_possible_cpu(cpu) {
+ to = per_cpu_ptr(&csky_to, cpu);
+ ret = timer_of_init(np, to);
+ if (ret)
+ goto rollback;
+ }
+
+ clocksource_register_hz(&csky_clocksource, timer_of_rate(to));
+ sched_clock_register(sched_clock_read, 32, timer_of_rate(to));
+
+ ret = cpuhp_setup_state(CPUHP_AP_CSKY_TIMER_STARTING,
+ "clockevents/csky/timer:starting",
+ csky_mptimer_starting_cpu,
+ csky_mptimer_dying_cpu);
+ if (ret)
+ return -EINVAL;
+
+ return 0;
+
+rollback:
+ for_each_possible_cpu(cpu_rollback) {
+ if (cpu_rollback == cpu)
+ break;
+
+ to = per_cpu_ptr(&csky_to, cpu_rollback);
+ timer_of_cleanup(to);
+ }
+ return -EINVAL;
+}
+TIMER_OF_DECLARE(csky_mptimer, "csky,mptimer", csky_mptimer_init);
diff --git a/drivers/clocksource/time-orion.c b/drivers/clocksource/timer-orion.c
index 12202067fe4b..7d487107e3cd 100644
--- a/drivers/clocksource/time-orion.c
+++ b/drivers/clocksource/timer-orion.c
@@ -129,13 +129,13 @@ static int __init orion_timer_init(struct device_node *np)
/* timer registers are shared with watchdog timer */
timer_base = of_iomap(np, 0);
if (!timer_base) {
- pr_err("%s: unable to map resource\n", np->name);
+ pr_err("%pOFn: unable to map resource\n", np);
return -ENXIO;
}
clk = of_clk_get(np, 0);
if (IS_ERR(clk)) {
- pr_err("%s: unable to get clk\n", np->name);
+ pr_err("%pOFn: unable to get clk\n", np);
return PTR_ERR(clk);
}
@@ -148,7 +148,7 @@ static int __init orion_timer_init(struct device_node *np)
/* we are only interested in timer1 irq */
irq = irq_of_parse_and_map(np, 1);
if (irq <= 0) {
- pr_err("%s: unable to parse timer1 irq\n", np->name);
+ pr_err("%pOFn: unable to parse timer1 irq\n", np);
return -EINVAL;
}
@@ -174,7 +174,7 @@ static int __init orion_timer_init(struct device_node *np)
/* setup timer1 as clockevent timer */
ret = setup_irq(irq, &orion_clkevt_irq);
if (ret) {
- pr_err("%s: unable to setup irq\n", np->name);
+ pr_err("%pOFn: unable to setup irq\n", np);
return ret;
}
diff --git a/drivers/clocksource/owl-timer.c b/drivers/clocksource/timer-owl.c
index ea00a5e8f95d..ea00a5e8f95d 100644
--- a/drivers/clocksource/owl-timer.c
+++ b/drivers/clocksource/timer-owl.c
diff --git a/drivers/clocksource/time-pistachio.c b/drivers/clocksource/timer-pistachio.c
index a2dd85d0c1d7..a2dd85d0c1d7 100644
--- a/drivers/clocksource/time-pistachio.c
+++ b/drivers/clocksource/timer-pistachio.c
diff --git a/drivers/clocksource/qcom-timer.c b/drivers/clocksource/timer-qcom.c
index 89816f89ff3f..89816f89ff3f 100644
--- a/drivers/clocksource/qcom-timer.c
+++ b/drivers/clocksource/timer-qcom.c
diff --git a/drivers/clocksource/timer-sp804.c b/drivers/clocksource/timer-sp804.c
index e01222ea888f..052b230ca312 100644
--- a/drivers/clocksource/timer-sp804.c
+++ b/drivers/clocksource/timer-sp804.c
@@ -249,7 +249,7 @@ static int __init sp804_of_init(struct device_node *np)
if (of_clk_get_parent_count(np) == 3) {
clk2 = of_clk_get(np, 1);
if (IS_ERR(clk2)) {
- pr_err("sp804: %s clock not found: %d\n", np->name,
+ pr_err("sp804: %pOFn clock not found: %d\n", np,
(int)PTR_ERR(clk2));
clk2 = NULL;
}
diff --git a/drivers/clocksource/versatile.c b/drivers/clocksource/timer-versatile.c
index 39725d38aede..39725d38aede 100644
--- a/drivers/clocksource/versatile.c
+++ b/drivers/clocksource/timer-versatile.c
diff --git a/drivers/clocksource/vf_pit_timer.c b/drivers/clocksource/timer-vf-pit.c
index 0f92089ec08c..0f92089ec08c 100644
--- a/drivers/clocksource/vf_pit_timer.c
+++ b/drivers/clocksource/timer-vf-pit.c
diff --git a/drivers/clocksource/vt8500_timer.c b/drivers/clocksource/timer-vt8500.c
index e0f7489cfc8e..e0f7489cfc8e 100644
--- a/drivers/clocksource/vt8500_timer.c
+++ b/drivers/clocksource/timer-vt8500.c
diff --git a/drivers/clocksource/zevio-timer.c b/drivers/clocksource/timer-zevio.c
index f74689334f7c..6127e8062a71 100644
--- a/drivers/clocksource/zevio-timer.c
+++ b/drivers/clocksource/timer-zevio.c
@@ -148,12 +148,12 @@ static int __init zevio_timer_add(struct device_node *node)
of_address_to_resource(node, 0, &res);
scnprintf(timer->clocksource_name, sizeof(timer->clocksource_name),
- "%llx.%s_clocksource",
- (unsigned long long)res.start, node->name);
+ "%llx.%pOFn_clocksource",
+ (unsigned long long)res.start, node);
scnprintf(timer->clockevent_name, sizeof(timer->clockevent_name),
- "%llx.%s_clockevent",
- (unsigned long long)res.start, node->name);
+ "%llx.%pOFn_clockevent",
+ (unsigned long long)res.start, node);
if (timer->interrupt_regs && irqnr) {
timer->clkevt.name = timer->clockevent_name;
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 0cd8eb76ad59..4e1131ef85ae 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -28,20 +28,13 @@ config ARM_ARMADA_37XX_CPUFREQ
# big LITTLE core layer and glue drivers
config ARM_BIG_LITTLE_CPUFREQ
tristate "Generic ARM big LITTLE CPUfreq driver"
- depends on (ARM_CPU_TOPOLOGY || ARM64) && HAVE_CLK
+ depends on ARM_CPU_TOPOLOGY && HAVE_CLK
# if CPU_THERMAL is on and THERMAL=m, ARM_BIT_LITTLE_CPUFREQ cannot be =y
depends on !CPU_THERMAL || THERMAL
select PM_OPP
help
This enables the Generic CPUfreq driver for ARM big.LITTLE platforms.
-config ARM_DT_BL_CPUFREQ
- tristate "Generic probing via DT for ARM big LITTLE CPUfreq driver"
- depends on ARM_BIG_LITTLE_CPUFREQ && OF
- help
- This enables probing via DT for Generic CPUfreq driver for ARM
- big.LITTLE platform. This gets frequency tables from DT.
-
config ARM_SCPI_CPUFREQ
tristate "SCPI based CPUfreq driver"
depends on ARM_SCPI_PROTOCOL && COMMON_CLK_SCPI
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index c1ffeabe4ecf..d5ee4562ed06 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -48,9 +48,6 @@ obj-$(CONFIG_X86_SFI_CPUFREQ) += sfi-cpufreq.o
##################################################################################
# ARM SoC drivers
obj-$(CONFIG_ARM_BIG_LITTLE_CPUFREQ) += arm_big_little.o
-# big LITTLE per platform glues. Keep DT_BL_CPUFREQ as the last entry in all big
-# LITTLE drivers, so that it is probed last.
-obj-$(CONFIG_ARM_DT_BL_CPUFREQ) += arm_big_little_dt.o
obj-$(CONFIG_ARM_ARMADA_37XX_CPUFREQ) += armada-37xx-cpufreq.o
obj-$(CONFIG_ARM_BRCMSTB_AVS_CPUFREQ) += brcmstb-avs-cpufreq.o
diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
index b61f4ec43e06..d62fd374d5c7 100644
--- a/drivers/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/acpi-cpufreq.c
@@ -61,6 +61,7 @@ enum {
#define INTEL_MSR_RANGE (0xffff)
#define AMD_MSR_RANGE (0x7)
+#define HYGON_MSR_RANGE (0x7)
#define MSR_K7_HWCR_CPB_DIS (1ULL << 25)
@@ -95,6 +96,7 @@ static bool boost_state(unsigned int cpu)
rdmsr_on_cpu(cpu, MSR_IA32_MISC_ENABLE, &lo, &hi);
msr = lo | ((u64)hi << 32);
return !(msr & MSR_IA32_MISC_ENABLE_TURBO_DISABLE);
+ case X86_VENDOR_HYGON:
case X86_VENDOR_AMD:
rdmsr_on_cpu(cpu, MSR_K7_HWCR, &lo, &hi);
msr = lo | ((u64)hi << 32);
@@ -113,6 +115,7 @@ static int boost_set_msr(bool enable)
msr_addr = MSR_IA32_MISC_ENABLE;
msr_mask = MSR_IA32_MISC_ENABLE_TURBO_DISABLE;
break;
+ case X86_VENDOR_HYGON:
case X86_VENDOR_AMD:
msr_addr = MSR_K7_HWCR;
msr_mask = MSR_K7_HWCR_CPB_DIS;
@@ -225,6 +228,8 @@ static unsigned extract_msr(struct cpufreq_policy *policy, u32 msr)
if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
msr &= AMD_MSR_RANGE;
+ else if (boot_cpu_data.x86_vendor == X86_VENDOR_HYGON)
+ msr &= HYGON_MSR_RANGE;
else
msr &= INTEL_MSR_RANGE;
diff --git a/drivers/cpufreq/amd_freq_sensitivity.c b/drivers/cpufreq/amd_freq_sensitivity.c
index be926d9a66e5..4ac7c3cf34be 100644
--- a/drivers/cpufreq/amd_freq_sensitivity.c
+++ b/drivers/cpufreq/amd_freq_sensitivity.c
@@ -111,11 +111,16 @@ static int __init amd_freq_sensitivity_init(void)
{
u64 val;
struct pci_dev *pcidev;
+ unsigned int pci_vendor;
- if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
+ if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
+ pci_vendor = PCI_VENDOR_ID_AMD;
+ else if (boot_cpu_data.x86_vendor == X86_VENDOR_HYGON)
+ pci_vendor = PCI_VENDOR_ID_HYGON;
+ else
return -ENODEV;
- pcidev = pci_get_device(PCI_VENDOR_ID_AMD,
+ pcidev = pci_get_device(pci_vendor,
PCI_DEVICE_ID_AMD_KERNCZ_SMBUS, NULL);
if (!pcidev) {
diff --git a/drivers/cpufreq/arm_big_little_dt.c b/drivers/cpufreq/arm_big_little_dt.c
deleted file mode 100644
index b944f290c8a4..000000000000
--- a/drivers/cpufreq/arm_big_little_dt.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Generic big.LITTLE CPUFreq Interface driver
- *
- * It provides necessary ops to arm_big_little cpufreq driver and gets
- * Frequency information from Device Tree. Freq table in DT must be in KHz.
- *
- * Copyright (C) 2013 Linaro.
- * Viresh Kumar <viresh.kumar@linaro.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/cpufreq.h>
-#include <linux/device.h>
-#include <linux/export.h>
-#include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/pm_opp.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-#include "arm_big_little.h"
-
-/* get cpu node with valid operating-points */
-static struct device_node *get_cpu_node_with_valid_op(int cpu)
-{
- struct device_node *np = of_cpu_device_node_get(cpu);
-
- if (!of_get_property(np, "operating-points", NULL)) {
- of_node_put(np);
- np = NULL;
- }
-
- return np;
-}
-
-static int dt_get_transition_latency(struct device *cpu_dev)
-{
- struct device_node *np;
- u32 transition_latency = CPUFREQ_ETERNAL;
-
- np = of_node_get(cpu_dev->of_node);
- if (!np) {
- pr_info("Failed to find cpu node. Use CPUFREQ_ETERNAL transition latency\n");
- return CPUFREQ_ETERNAL;
- }
-
- of_property_read_u32(np, "clock-latency", &transition_latency);
- of_node_put(np);
-
- pr_debug("%s: clock-latency: %d\n", __func__, transition_latency);
- return transition_latency;
-}
-
-static const struct cpufreq_arm_bL_ops dt_bL_ops = {
- .name = "dt-bl",
- .get_transition_latency = dt_get_transition_latency,
- .init_opp_table = dev_pm_opp_of_cpumask_add_table,
- .free_opp_table = dev_pm_opp_of_cpumask_remove_table,
-};
-
-static int generic_bL_probe(struct platform_device *pdev)
-{
- struct device_node *np;
-
- np = get_cpu_node_with_valid_op(0);
- if (!np)
- return -ENODEV;
-
- of_node_put(np);
- return bL_cpufreq_register(&dt_bL_ops);
-}
-
-static int generic_bL_remove(struct platform_device *pdev)
-{
- bL_cpufreq_unregister(&dt_bL_ops);
- return 0;
-}
-
-static struct platform_driver generic_bL_platdrv = {
- .driver = {
- .name = "arm-bL-cpufreq-dt",
- },
- .probe = generic_bL_probe,
- .remove = generic_bL_remove,
-};
-module_platform_driver(generic_bL_platdrv);
-
-MODULE_AUTHOR("Viresh Kumar <viresh.kumar@linaro.org>");
-MODULE_DESCRIPTION("Generic ARM big LITTLE cpufreq driver via DT");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
index 30f302149730..fd25c21cee72 100644
--- a/drivers/cpufreq/cppc_cpufreq.c
+++ b/drivers/cpufreq/cppc_cpufreq.c
@@ -428,7 +428,7 @@ MODULE_LICENSE("GPL");
late_initcall(cppc_cpufreq_init);
-static const struct acpi_device_id cppc_acpi_ids[] = {
+static const struct acpi_device_id cppc_acpi_ids[] __used = {
{ACPI_PROCESSOR_DEVICE_HID, },
{}
};
diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c
index fe14c57de6ca..b1c5468dca16 100644
--- a/drivers/cpufreq/cpufreq-dt-platdev.c
+++ b/drivers/cpufreq/cpufreq-dt-platdev.c
@@ -58,6 +58,7 @@ static const struct of_device_id whitelist[] __initconst = {
{ .compatible = "renesas,r8a73a4", },
{ .compatible = "renesas,r8a7740", },
{ .compatible = "renesas,r8a7743", },
+ { .compatible = "renesas,r8a7744", },
{ .compatible = "renesas,r8a7745", },
{ .compatible = "renesas,r8a7778", },
{ .compatible = "renesas,r8a7779", },
@@ -78,7 +79,10 @@ static const struct of_device_id whitelist[] __initconst = {
{ .compatible = "rockchip,rk3328", },
{ .compatible = "rockchip,rk3366", },
{ .compatible = "rockchip,rk3368", },
- { .compatible = "rockchip,rk3399", },
+ { .compatible = "rockchip,rk3399",
+ .data = &(struct cpufreq_dt_platform_data)
+ { .have_governor_per_policy = true, },
+ },
{ .compatible = "st-ericsson,u8500", },
{ .compatible = "st-ericsson,u8540", },
diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c
index 0a9ebf00be46..e58bfcb1169e 100644
--- a/drivers/cpufreq/cpufreq-dt.c
+++ b/drivers/cpufreq/cpufreq-dt.c
@@ -32,6 +32,7 @@ struct private_data {
struct device *cpu_dev;
struct thermal_cooling_device *cdev;
const char *reg_name;
+ bool have_static_opps;
};
static struct freq_attr *cpufreq_dt_attr[] = {
@@ -204,6 +205,15 @@ static int cpufreq_init(struct cpufreq_policy *policy)
}
}
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ ret = -ENOMEM;
+ goto out_put_regulator;
+ }
+
+ priv->reg_name = name;
+ priv->opp_table = opp_table;
+
/*
* Initialize OPP tables for all policy->cpus. They will be shared by
* all CPUs which have marked their CPUs shared with OPP bindings.
@@ -214,7 +224,8 @@ static int cpufreq_init(struct cpufreq_policy *policy)
*
* OPPs might be populated at runtime, don't check for error here
*/
- dev_pm_opp_of_cpumask_add_table(policy->cpus);
+ if (!dev_pm_opp_of_cpumask_add_table(policy->cpus))
+ priv->have_static_opps = true;
/*
* But we need OPP table to function so if it is not there let's
@@ -240,19 +251,10 @@ static int cpufreq_init(struct cpufreq_policy *policy)
__func__, ret);
}
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (!priv) {
- ret = -ENOMEM;
- goto out_free_opp;
- }
-
- priv->reg_name = name;
- priv->opp_table = opp_table;
-
ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
if (ret) {
dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);
- goto out_free_priv;
+ goto out_free_opp;
}
priv->cpu_dev = cpu_dev;
@@ -282,10 +284,11 @@ static int cpufreq_init(struct cpufreq_policy *policy)
out_free_cpufreq_table:
dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
-out_free_priv:
- kfree(priv);
out_free_opp:
- dev_pm_opp_of_cpumask_remove_table(policy->cpus);
+ if (priv->have_static_opps)
+ dev_pm_opp_of_cpumask_remove_table(policy->cpus);
+ kfree(priv);
+out_put_regulator:
if (name)
dev_pm_opp_put_regulators(opp_table);
out_put_clk:
@@ -300,7 +303,8 @@ static int cpufreq_exit(struct cpufreq_policy *policy)
cpufreq_cooling_unregister(priv->cdev);
dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table);
- dev_pm_opp_of_cpumask_remove_table(policy->related_cpus);
+ if (priv->have_static_opps)
+ dev_pm_opp_of_cpumask_remove_table(policy->related_cpus);
if (priv->reg_name)
dev_pm_opp_put_regulators(priv->opp_table);
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index f53fb41efb7b..7aa3dcad2175 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -403,7 +403,7 @@ EXPORT_SYMBOL_GPL(cpufreq_freq_transition_begin);
void cpufreq_freq_transition_end(struct cpufreq_policy *policy,
struct cpufreq_freqs *freqs, int transition_failed)
{
- if (unlikely(WARN_ON(!policy->transition_ongoing)))
+ if (WARN_ON(!policy->transition_ongoing))
return;
cpufreq_notify_post_transition(policy, freqs, transition_failed);
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index f20f20a77d4d..4268f87e99fc 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -80,8 +80,10 @@ static unsigned int cs_dbs_update(struct cpufreq_policy *policy)
* changed in the meantime, so fall back to current frequency in that
* case.
*/
- if (requested_freq > policy->max || requested_freq < policy->min)
+ if (requested_freq > policy->max || requested_freq < policy->min) {
requested_freq = policy->cur;
+ dbs_info->requested_freq = requested_freq;
+ }
freq_step = get_freq_step(cs_tuners, policy);
@@ -92,7 +94,7 @@ static unsigned int cs_dbs_update(struct cpufreq_policy *policy)
if (policy_dbs->idle_periods < UINT_MAX) {
unsigned int freq_steps = policy_dbs->idle_periods * freq_step;
- if (requested_freq > freq_steps)
+ if (requested_freq > policy->min + freq_steps)
requested_freq -= freq_steps;
else
requested_freq = policy->min;
diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c
index b2ff423ad7f8..d8c3595e9023 100644
--- a/drivers/cpufreq/imx6q-cpufreq.c
+++ b/drivers/cpufreq/imx6q-cpufreq.c
@@ -12,6 +12,7 @@
#include <linux/cpu_cooling.h>
#include <linux/err.h>
#include <linux/module.h>
+#include <linux/nvmem-consumer.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/pm_opp.h>
@@ -159,8 +160,13 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
/* Ensure the arm clock divider is what we expect */
ret = clk_set_rate(clks[ARM].clk, new_freq * 1000);
if (ret) {
+ int ret1;
+
dev_err(cpu_dev, "failed to set clock rate: %d\n", ret);
- regulator_set_voltage_tol(arm_reg, volt_old, 0);
+ ret1 = regulator_set_voltage_tol(arm_reg, volt_old, 0);
+ if (ret1)
+ dev_warn(cpu_dev,
+ "failed to restore vddarm voltage: %d\n", ret1);
return ret;
}
@@ -290,20 +296,32 @@ put_node:
#define OCOTP_CFG3_6ULL_SPEED_792MHZ 0x2
#define OCOTP_CFG3_6ULL_SPEED_900MHZ 0x3
-static void imx6ul_opp_check_speed_grading(struct device *dev)
+static int imx6ul_opp_check_speed_grading(struct device *dev)
{
- struct device_node *np;
- void __iomem *base;
u32 val;
+ int ret = 0;
- np = of_find_compatible_node(NULL, NULL, "fsl,imx6ul-ocotp");
- if (!np)
- return;
+ if (of_find_property(dev->of_node, "nvmem-cells", NULL)) {
+ ret = nvmem_cell_read_u32(dev, "speed_grade", &val);
+ if (ret)
+ return ret;
+ } else {
+ struct device_node *np;
+ void __iomem *base;
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx6ul-ocotp");
+ if (!np)
+ return -ENOENT;
+
+ base = of_iomap(np, 0);
+ of_node_put(np);
+ if (!base) {
+ dev_err(dev, "failed to map ocotp\n");
+ return -EFAULT;
+ }
- base = of_iomap(np, 0);
- if (!base) {
- dev_err(dev, "failed to map ocotp\n");
- goto put_node;
+ val = readl_relaxed(base + OCOTP_CFG3);
+ iounmap(base);
}
/*
@@ -314,7 +332,6 @@ static void imx6ul_opp_check_speed_grading(struct device *dev)
* 2b'11: 900000000Hz on i.MX6ULL only;
* We need to set the max speed of ARM according to fuse map.
*/
- val = readl_relaxed(base + OCOTP_CFG3);
val >>= OCOTP_CFG3_SPEED_SHIFT;
val &= 0x3;
@@ -334,9 +351,7 @@ static void imx6ul_opp_check_speed_grading(struct device *dev)
dev_warn(dev, "failed to disable 900MHz OPP\n");
}
- iounmap(base);
-put_node:
- of_node_put(np);
+ return ret;
}
static int imx6q_cpufreq_probe(struct platform_device *pdev)
@@ -394,10 +409,18 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
}
if (of_machine_is_compatible("fsl,imx6ul") ||
- of_machine_is_compatible("fsl,imx6ull"))
- imx6ul_opp_check_speed_grading(cpu_dev);
- else
+ of_machine_is_compatible("fsl,imx6ull")) {
+ ret = imx6ul_opp_check_speed_grading(cpu_dev);
+ if (ret == -EPROBE_DEFER)
+ return ret;
+ if (ret) {
+ dev_err(cpu_dev, "failed to read ocotp: %d\n",
+ ret);
+ return ret;
+ }
+ } else {
imx6q_opp_check_speed_grading(cpu_dev);
+ }
/* Because we have added the OPPs here, we must free them */
free_opp = true;
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
index b6a1aadaff9f..9578312e43f2 100644
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -373,11 +373,24 @@ static void intel_pstate_set_itmt_prio(int cpu)
}
}
}
-#else
+
+static int intel_pstate_get_cppc_guranteed(int cpu)
+{
+ struct cppc_perf_caps cppc_perf;
+ int ret;
+
+ ret = cppc_get_perf_caps(cpu, &cppc_perf);
+ if (ret)
+ return ret;
+
+ return cppc_perf.guaranteed_perf;
+}
+
+#else /* CONFIG_ACPI_CPPC_LIB */
static void intel_pstate_set_itmt_prio(int cpu)
{
}
-#endif
+#endif /* CONFIG_ACPI_CPPC_LIB */
static void intel_pstate_init_acpi_perf_limits(struct cpufreq_policy *policy)
{
@@ -459,7 +472,7 @@ static void intel_pstate_exit_perf_limits(struct cpufreq_policy *policy)
acpi_processor_unregister_performance(policy->cpu);
}
-#else
+#else /* CONFIG_ACPI */
static inline void intel_pstate_init_acpi_perf_limits(struct cpufreq_policy *policy)
{
}
@@ -472,7 +485,14 @@ static inline bool intel_pstate_acpi_pm_profile_server(void)
{
return false;
}
-#endif
+#endif /* CONFIG_ACPI */
+
+#ifndef CONFIG_ACPI_CPPC_LIB
+static int intel_pstate_get_cppc_guranteed(int cpu)
+{
+ return -ENOTSUPP;
+}
+#endif /* CONFIG_ACPI_CPPC_LIB */
static inline void update_turbo_state(void)
{
@@ -699,9 +719,29 @@ static ssize_t show_energy_performance_preference(
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;
+
+ ratio = intel_pstate_get_cppc_guranteed(policy->cpu);
+ if (ratio <= 0) {
+ rdmsrl_on_cpu(policy->cpu, MSR_HWP_CAPABILITIES, &cap);
+ ratio = HWP_GUARANTEED_PERF(cap);
+ }
+
+ cpu = all_cpu_data[policy->cpu];
+
+ return sprintf(buf, "%d\n", ratio * cpu->pstate.scaling);
+}
+
+cpufreq_freq_attr_ro(base_frequency);
+
static struct freq_attr *hwp_cpufreq_attrs[] = {
&energy_performance_preference,
&energy_performance_available_preferences,
+ &base_frequency,
NULL,
};
@@ -1778,7 +1818,7 @@ static const struct pstate_funcs knl_funcs = {
static const struct x86_cpu_id intel_pstate_cpu_ids[] = {
ICPU(INTEL_FAM6_SANDYBRIDGE, core_funcs),
ICPU(INTEL_FAM6_SANDYBRIDGE_X, core_funcs),
- ICPU(INTEL_FAM6_ATOM_SILVERMONT1, silvermont_funcs),
+ ICPU(INTEL_FAM6_ATOM_SILVERMONT, silvermont_funcs),
ICPU(INTEL_FAM6_IVYBRIDGE, core_funcs),
ICPU(INTEL_FAM6_HASWELL_CORE, core_funcs),
ICPU(INTEL_FAM6_BROADWELL_CORE, core_funcs),
@@ -1795,7 +1835,7 @@ static const struct x86_cpu_id intel_pstate_cpu_ids[] = {
ICPU(INTEL_FAM6_XEON_PHI_KNL, knl_funcs),
ICPU(INTEL_FAM6_XEON_PHI_KNM, knl_funcs),
ICPU(INTEL_FAM6_ATOM_GOLDMONT, core_funcs),
- ICPU(INTEL_FAM6_ATOM_GEMINI_LAKE, core_funcs),
+ ICPU(INTEL_FAM6_ATOM_GOLDMONT_PLUS, core_funcs),
ICPU(INTEL_FAM6_SKYLAKE_X, core_funcs),
{}
};
diff --git a/drivers/cpufreq/mvebu-cpufreq.c b/drivers/cpufreq/mvebu-cpufreq.c
index 31513bd42705..6d33a639f902 100644
--- a/drivers/cpufreq/mvebu-cpufreq.c
+++ b/drivers/cpufreq/mvebu-cpufreq.c
@@ -84,9 +84,10 @@ static int __init armada_xp_pmsu_cpufreq_init(void)
ret = dev_pm_opp_add(cpu_dev, clk_get_rate(clk) / 2, 0);
if (ret) {
+ dev_pm_opp_remove(cpu_dev, clk_get_rate(clk));
clk_put(clk);
dev_err(cpu_dev, "Failed to register OPPs\n");
- goto opp_register_failed;
+ return ret;
}
ret = dev_pm_opp_set_sharing_cpus(cpu_dev,
@@ -99,11 +100,5 @@ static int __init armada_xp_pmsu_cpufreq_init(void)
platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
return 0;
-
-opp_register_failed:
- /* As registering has failed remove all the opp for all cpus */
- dev_pm_opp_cpumask_remove_table(cpu_possible_mask);
-
- return ret;
}
device_initcall(armada_xp_pmsu_cpufreq_init);
diff --git a/drivers/cpufreq/s5pv210-cpufreq.c b/drivers/cpufreq/s5pv210-cpufreq.c
index 5d31c2db12a3..dbecd7667db2 100644
--- a/drivers/cpufreq/s5pv210-cpufreq.c
+++ b/drivers/cpufreq/s5pv210-cpufreq.c
@@ -611,8 +611,8 @@ static int s5pv210_cpufreq_probe(struct platform_device *pdev)
for_each_compatible_node(np, NULL, "samsung,s5pv210-dmc") {
id = of_alias_get_id(np, "dmc");
if (id < 0 || id >= ARRAY_SIZE(dmc_base)) {
- pr_err("%s: failed to get alias of dmc node '%s'\n",
- __func__, np->name);
+ pr_err("%s: failed to get alias of dmc node '%pOFn'\n",
+ __func__, np);
of_node_put(np);
return id;
}
diff --git a/drivers/cpufreq/tegra186-cpufreq.c b/drivers/cpufreq/tegra186-cpufreq.c
index 1f59966573aa..f1e09022b819 100644
--- a/drivers/cpufreq/tegra186-cpufreq.c
+++ b/drivers/cpufreq/tegra186-cpufreq.c
@@ -121,7 +121,7 @@ static struct cpufreq_frequency_table *init_vhint_table(
void *virt;
virt = dma_alloc_coherent(bpmp->dev, sizeof(*data), &phys,
- GFP_KERNEL | GFP_DMA32);
+ GFP_KERNEL);
if (!virt)
return ERR_PTR(-ENOMEM);
diff --git a/drivers/cpuidle/cpuidle-arm.c b/drivers/cpuidle/cpuidle-arm.c
index 073557f433eb..3a407a3ef22b 100644
--- a/drivers/cpuidle/cpuidle-arm.c
+++ b/drivers/cpuidle/cpuidle-arm.c
@@ -82,7 +82,6 @@ static int __init arm_idle_init_cpu(int cpu)
{
int ret;
struct cpuidle_driver *drv;
- struct cpuidle_device *dev;
drv = kmemdup(&arm_idle_driver, sizeof(*drv), GFP_KERNEL);
if (!drv)
@@ -103,13 +102,6 @@ static int __init arm_idle_init_cpu(int cpu)
goto out_kfree_drv;
}
- ret = cpuidle_register_driver(drv);
- if (ret) {
- if (ret != -EBUSY)
- pr_err("Failed to register cpuidle driver\n");
- goto out_kfree_drv;
- }
-
/*
* Call arch CPU operations in order to initialize
* idle states suspend back-end specific data
@@ -117,37 +109,21 @@ static int __init arm_idle_init_cpu(int cpu)
ret = arm_cpuidle_init(cpu);
/*
- * Skip the cpuidle device initialization if the reported
+ * Allow the initialization to continue for other CPUs, if the reported
* failure is a HW misconfiguration/breakage (-ENXIO).
*/
- if (ret == -ENXIO)
- return 0;
-
if (ret) {
pr_err("CPU %d failed to init idle CPU ops\n", cpu);
- goto out_unregister_drv;
- }
-
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev) {
- ret = -ENOMEM;
- goto out_unregister_drv;
+ ret = ret == -ENXIO ? 0 : ret;
+ goto out_kfree_drv;
}
- dev->cpu = cpu;
- ret = cpuidle_register_device(dev);
- if (ret) {
- pr_err("Failed to register cpuidle device for CPU %d\n",
- cpu);
- goto out_kfree_dev;
- }
+ ret = cpuidle_register(drv, NULL);
+ if (ret)
+ goto out_kfree_drv;
return 0;
-out_kfree_dev:
- kfree(dev);
-out_unregister_drv:
- cpuidle_unregister_driver(drv);
out_kfree_drv:
kfree(drv);
return ret;
@@ -178,9 +154,7 @@ out_fail:
while (--cpu >= 0) {
dev = per_cpu(cpuidle_devices, cpu);
drv = cpuidle_get_cpu_driver(dev);
- cpuidle_unregister_device(dev);
- cpuidle_unregister_driver(drv);
- kfree(dev);
+ cpuidle_unregister(drv);
kfree(drv);
}
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 6df894d65d9e..4a97446f66d8 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -247,17 +247,17 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
if (!cpuidle_state_is_coupled(drv, index))
local_irq_enable();
- diff = ktime_us_delta(time_end, time_start);
- if (diff > INT_MAX)
- diff = INT_MAX;
-
- dev->last_residency = (int) diff;
-
if (entered_state >= 0) {
- /* Update cpuidle counters */
- /* This can be moved to within driver enter routine
+ /*
+ * Update cpuidle counters
+ * This can be moved to within driver enter routine,
* but that results in multiple copies of same code.
*/
+ diff = ktime_us_delta(time_end, time_start);
+ if (diff > INT_MAX)
+ diff = INT_MAX;
+
+ dev->last_residency = (int)diff;
dev->states_usage[entered_state].time += dev->last_residency;
dev->states_usage[entered_state].usage++;
} else {
diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c
index 704880a6612a..f0dddc66af26 100644
--- a/drivers/cpuidle/governors/ladder.c
+++ b/drivers/cpuidle/governors/ladder.c
@@ -80,7 +80,7 @@ static int ladder_select_state(struct cpuidle_driver *drv,
last_state = &ldev->states[last_idx];
- last_residency = cpuidle_get_last_residency(dev) - drv->states[last_idx].exit_latency;
+ last_residency = dev->last_residency - drv->states[last_idx].exit_latency;
/* consider promotion */
if (last_idx < drv->state_count - 1 &&
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index e26a40971b26..61316fc51548 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -124,22 +124,12 @@ struct menu_device {
int tick_wakeup;
unsigned int next_timer_us;
- unsigned int predicted_us;
unsigned int bucket;
unsigned int correction_factor[BUCKETS];
unsigned int intervals[INTERVALS];
int interval_ptr;
};
-
-#define LOAD_INT(x) ((x) >> FSHIFT)
-#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
-
-static inline int get_loadavg(unsigned long load)
-{
- return LOAD_INT(load) * 10 + LOAD_FRAC(load) / 10;
-}
-
static inline int which_bucket(unsigned int duration, unsigned long nr_iowaiters)
{
int bucket = 0;
@@ -173,18 +163,10 @@ static inline int which_bucket(unsigned int duration, 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, unsigned long load)
+static inline int performance_multiplier(unsigned long nr_iowaiters)
{
- int mult = 1;
-
- /* for higher loadavg, we are more reluctant */
-
- mult += 2 * get_loadavg(load);
-
- /* for IO wait tasks (per cpu!) we add 5x each */
- mult += 10 * nr_iowaiters;
-
- return mult;
+ /* for IO wait tasks (per cpu!) we add 10x each */
+ return 1 + 10 * nr_iowaiters;
}
static DEFINE_PER_CPU(struct menu_device, menu_devices);
@@ -197,10 +179,11 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev);
* of points is below a threshold. If it is... then use the
* average of these 8 points as the estimated value.
*/
-static unsigned int get_typical_interval(struct menu_device *data)
+static unsigned int get_typical_interval(struct menu_device *data,
+ unsigned int predicted_us)
{
int i, divisor;
- unsigned int max, thresh, avg;
+ unsigned int min, max, thresh, avg;
uint64_t sum, variance;
thresh = UINT_MAX; /* Discard outliers above this value */
@@ -208,6 +191,7 @@ static unsigned int get_typical_interval(struct menu_device *data)
again:
/* First calculate the average of past intervals */
+ min = UINT_MAX;
max = 0;
sum = 0;
divisor = 0;
@@ -218,8 +202,19 @@ again:
divisor++;
if (value > max)
max = value;
+
+ if (value < min)
+ min = value;
}
}
+
+ /*
+ * If the result of the computation is going to be discarded anyway,
+ * avoid the computation altogether.
+ */
+ if (min >= predicted_us)
+ return UINT_MAX;
+
if (divisor == INTERVALS)
avg = sum >> INTERVAL_SHIFT;
else
@@ -286,11 +281,10 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
struct menu_device *data = this_cpu_ptr(&menu_devices);
int latency_req = cpuidle_governor_latency_req(dev->cpu);
int i;
- int first_idx;
int idx;
unsigned int interactivity_req;
- unsigned int expected_interval;
- unsigned long nr_iowaiters, cpu_load;
+ unsigned int predicted_us;
+ unsigned long nr_iowaiters;
ktime_t delta_next;
if (data->needs_update) {
@@ -298,50 +292,36 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
data->needs_update = 0;
}
- /* Special case when user has set very strict latency requirement */
- if (unlikely(latency_req == 0)) {
- *stop_tick = false;
- return 0;
- }
-
/* determine the expected residency time, round up */
data->next_timer_us = ktime_to_us(tick_nohz_get_sleep_length(&delta_next));
- get_iowait_load(&nr_iowaiters, &cpu_load);
+ nr_iowaiters = nr_iowait_cpu(dev->cpu);
data->bucket = which_bucket(data->next_timer_us, nr_iowaiters);
+ if (unlikely(drv->state_count <= 1 || latency_req == 0) ||
+ ((data->next_timer_us < drv->states[1].target_residency ||
+ latency_req < drv->states[1].exit_latency) &&
+ !drv->states[0].disabled && !dev->states_usage[0].disable)) {
+ /*
+ * In this case state[0] will be used no matter what, so return
+ * it right away and keep the tick running.
+ */
+ *stop_tick = false;
+ return 0;
+ }
+
/*
* Force the result of multiplication to be 64 bits even if both
* operands are 32 bits.
* Make sure to round up for half microseconds.
*/
- data->predicted_us = DIV_ROUND_CLOSEST_ULL((uint64_t)data->next_timer_us *
+ predicted_us = DIV_ROUND_CLOSEST_ULL((uint64_t)data->next_timer_us *
data->correction_factor[data->bucket],
RESOLUTION * DECAY);
-
- expected_interval = get_typical_interval(data);
- expected_interval = min(expected_interval, data->next_timer_us);
-
- first_idx = 0;
- if (drv->states[0].flags & CPUIDLE_FLAG_POLLING) {
- struct cpuidle_state *s = &drv->states[1];
- unsigned int polling_threshold;
-
- /*
- * Default to a physical idle state, not to busy polling, unless
- * a timer is going to trigger really really soon.
- */
- polling_threshold = max_t(unsigned int, 20, s->target_residency);
- if (data->next_timer_us > polling_threshold &&
- latency_req > s->exit_latency && !s->disabled &&
- !dev->states_usage[1].disable)
- first_idx = 1;
- }
-
/*
* Use the lowest expected idle interval to pick the idle state.
*/
- data->predicted_us = min(data->predicted_us, expected_interval);
+ predicted_us = min(predicted_us, get_typical_interval(data, predicted_us));
if (tick_nohz_tick_stopped()) {
/*
@@ -352,34 +332,46 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
* the known time till the closest timer event for the idle
* state selection.
*/
- if (data->predicted_us < TICK_USEC)
- data->predicted_us = ktime_to_us(delta_next);
+ if (predicted_us < TICK_USEC)
+ predicted_us = ktime_to_us(delta_next);
} else {
/*
* Use the performance multiplier and the user-configurable
* latency_req to determine the maximum exit latency.
*/
- interactivity_req = data->predicted_us / performance_multiplier(nr_iowaiters, cpu_load);
+ interactivity_req = predicted_us / performance_multiplier(nr_iowaiters);
if (latency_req > interactivity_req)
latency_req = interactivity_req;
}
- expected_interval = data->predicted_us;
/*
* Find the idle state with the lowest power while satisfying
* our constraints.
*/
idx = -1;
- for (i = first_idx; i < drv->state_count; i++) {
+ for (i = 0; i < drv->state_count; i++) {
struct cpuidle_state *s = &drv->states[i];
struct cpuidle_state_usage *su = &dev->states_usage[i];
if (s->disabled || su->disable)
continue;
+
if (idx == -1)
idx = i; /* first enabled state */
- if (s->target_residency > data->predicted_us) {
- if (data->predicted_us < TICK_USEC)
+
+ if (s->target_residency > predicted_us) {
+ /*
+ * Use a physical idle state, not busy polling, unless
+ * a timer is going to trigger soon enough.
+ */
+ if ((drv->states[idx].flags & CPUIDLE_FLAG_POLLING) &&
+ s->exit_latency <= latency_req &&
+ s->target_residency <= data->next_timer_us) {
+ predicted_us = s->target_residency;
+ idx = i;
+ break;
+ }
+ if (predicted_us < TICK_USEC)
break;
if (!tick_nohz_tick_stopped()) {
@@ -389,7 +381,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
* tick in that case and let the governor run
* again in the next iteration of the loop.
*/
- expected_interval = drv->states[idx].target_residency;
+ predicted_us = drv->states[idx].target_residency;
break;
}
@@ -403,7 +395,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
s->target_residency <= ktime_to_us(delta_next))
idx = i;
- goto out;
+ return idx;
}
if (s->exit_latency > latency_req) {
/*
@@ -412,7 +404,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
* expected idle duration so that the tick is retained
* as long as that target residency is low enough.
*/
- expected_interval = drv->states[idx].target_residency;
+ predicted_us = drv->states[idx].target_residency;
break;
}
idx = i;
@@ -426,7 +418,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
* expected idle duration is shorter than the tick period length.
*/
if (((drv->states[idx].flags & CPUIDLE_FLAG_POLLING) ||
- expected_interval < TICK_USEC) && !tick_nohz_tick_stopped()) {
+ predicted_us < TICK_USEC) && !tick_nohz_tick_stopped()) {
unsigned int delta_next_us = ktime_to_us(delta_next);
*stop_tick = false;
@@ -450,10 +442,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
}
}
-out:
- data->last_state_idx = idx;
-
- return data->last_state_idx;
+ return idx;
}
/**
@@ -512,9 +501,19 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
* duration predictor do a better job next time.
*/
measured_us = 9 * MAX_INTERESTING / 10;
+ } else if ((drv->states[last_idx].flags & CPUIDLE_FLAG_POLLING) &&
+ dev->poll_time_limit) {
+ /*
+ * The CPU exited the "polling" state due to a time limit, so
+ * the idle duration prediction leading to the selection of that
+ * state was inaccurate. If a better prediction had been made,
+ * the CPU might have been woken up from idle by the next timer.
+ * Assume that to be the case.
+ */
+ measured_us = data->next_timer_us;
} else {
/* measured value */
- measured_us = cpuidle_get_last_residency(dev);
+ measured_us = dev->last_residency;
/* Deduct exit latency */
if (measured_us > 2 * target->exit_latency)
diff --git a/drivers/cpuidle/poll_state.c b/drivers/cpuidle/poll_state.c
index 3f86d23c592e..85792d371add 100644
--- a/drivers/cpuidle/poll_state.c
+++ b/drivers/cpuidle/poll_state.c
@@ -9,7 +9,6 @@
#include <linux/sched/clock.h>
#include <linux/sched/idle.h>
-#define POLL_IDLE_TIME_LIMIT (TICK_NSEC / 16)
#define POLL_IDLE_RELAX_COUNT 200
static int __cpuidle poll_idle(struct cpuidle_device *dev,
@@ -17,8 +16,11 @@ static int __cpuidle poll_idle(struct cpuidle_device *dev,
{
u64 time_start = local_clock();
+ dev->poll_time_limit = false;
+
local_irq_enable();
if (!current_set_polling_and_test()) {
+ u64 limit = (u64)drv->states[1].target_residency * NSEC_PER_USEC;
unsigned int loop_count = 0;
while (!need_resched()) {
@@ -27,8 +29,10 @@ static int __cpuidle poll_idle(struct cpuidle_device *dev,
continue;
loop_count = 0;
- if (local_clock() - time_start > POLL_IDLE_TIME_LIMIT)
+ if (local_clock() - time_start > limit) {
+ dev->poll_time_limit = true;
break;
+ }
}
}
current_clr_polling();
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index a8c4ce07fc9d..caa98a7fe392 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -73,6 +73,17 @@ config ZCRYPT
+ Crypto Express 2,3,4 or 5 Accelerator (CEXxA)
+ Crypto Express 4 or 5 EP11 Coprocessor (CEXxP)
+config ZCRYPT_MULTIDEVNODES
+ bool "Support for multiple zcrypt device nodes"
+ default y
+ depends on S390
+ depends on ZCRYPT
+ help
+ With this option enabled the zcrypt device driver can
+ provide multiple devices nodes in /dev. Each device
+ node can get customized to limit access and narrow
+ down the use of the available crypto hardware.
+
config PKEY
tristate "Kernel API for protected key handling"
depends on S390
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index c23396f32c8a..8e7e225d2446 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -10,7 +10,7 @@ obj-$(CONFIG_CRYPTO_DEV_CHELSIO) += chelsio/
obj-$(CONFIG_CRYPTO_DEV_CPT) += cavium/cpt/
obj-$(CONFIG_CRYPTO_DEV_NITROX) += cavium/nitrox/
obj-$(CONFIG_CRYPTO_DEV_EXYNOS_RNG) += exynos-rng.o
-obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM) += caam/
+obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_COMMON) += caam/
obj-$(CONFIG_CRYPTO_DEV_GEODE) += geode-aes.o
obj-$(CONFIG_CRYPTO_DEV_HIFN_795X) += hifn_795x.o
obj-$(CONFIG_CRYPTO_DEV_IMGTEC_HASH) += img-hash.o
diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c
index 801aeab5ab1e..2b7af44c7b85 100644
--- a/drivers/crypto/atmel-aes.c
+++ b/drivers/crypto/atmel-aes.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Cryptographic API.
*
@@ -6,10 +7,6 @@
* Copyright (c) 2012 Eukréa Electromatique - ATMEL
* Author: Nicolas Royer <nicolas@eukrea.com>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
- *
* Some ideas are from omap-aes.c driver.
*/
diff --git a/drivers/crypto/atmel-authenc.h b/drivers/crypto/atmel-authenc.h
index 2a60d1224143..cbd37a2edada 100644
--- a/drivers/crypto/atmel-authenc.h
+++ b/drivers/crypto/atmel-authenc.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* API for Atmel Secure Protocol Layers Improved Performances (SPLIP)
*
@@ -5,18 +6,6 @@
*
* Author: Cyrille Pitchen <cyrille.pitchen@atmel.com>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- *
* This driver is based on drivers/mtd/spi-nor/fsl-quadspi.c from Freescale.
*/
diff --git a/drivers/crypto/atmel-ecc.c b/drivers/crypto/atmel-ecc.c
index 74f083f45e97..ba00e4563ca0 100644
--- a/drivers/crypto/atmel-ecc.c
+++ b/drivers/crypto/atmel-ecc.c
@@ -1,18 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Microchip / Atmel ECC (I2C) driver.
*
* Copyright (c) 2017, Microchip Technology Inc.
* Author: Tudor Ambarus <tudor.ambarus@microchip.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <linux/bitrev.h>
diff --git a/drivers/crypto/atmel-ecc.h b/drivers/crypto/atmel-ecc.h
index 25232c8abcc2..643a3b947338 100644
--- a/drivers/crypto/atmel-ecc.h
+++ b/drivers/crypto/atmel-ecc.h
@@ -1,19 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2017, Microchip Technology Inc.
* Author: Tudor Ambarus <tudor.ambarus@microchip.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- *
*/
#ifndef __ATMEL_ECC_H__
diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c
index 8a19df2fba6a..ab0cfe748931 100644
--- a/drivers/crypto/atmel-sha.c
+++ b/drivers/crypto/atmel-sha.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Cryptographic API.
*
@@ -6,10 +7,6 @@
* Copyright (c) 2012 Eukréa Electromatique - ATMEL
* Author: Nicolas Royer <nicolas@eukrea.com>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
- *
* Some ideas are from omap-sham.c drivers.
*/
diff --git a/drivers/crypto/atmel-tdes.c b/drivers/crypto/atmel-tdes.c
index 97b0423efa7f..438e1ffb2ec0 100644
--- a/drivers/crypto/atmel-tdes.c
+++ b/drivers/crypto/atmel-tdes.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Cryptographic API.
*
@@ -6,10 +7,6 @@
* Copyright (c) 2012 Eukréa Electromatique - ATMEL
* Author: Nicolas Royer <nicolas@eukrea.com>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
- *
* Some ideas are from omap-aes.c drivers.
*/
diff --git a/drivers/crypto/axis/artpec6_crypto.c b/drivers/crypto/axis/artpec6_crypto.c
index 7f07a5085e9b..f3442c2bdbdc 100644
--- a/drivers/crypto/axis/artpec6_crypto.c
+++ b/drivers/crypto/axis/artpec6_crypto.c
@@ -330,7 +330,7 @@ struct artpec6_cryptotfm_context {
size_t key_length;
u32 key_md;
int crypto_type;
- struct crypto_skcipher *fallback;
+ struct crypto_sync_skcipher *fallback;
};
struct artpec6_crypto_aead_hw_ctx {
@@ -1199,15 +1199,15 @@ artpec6_crypto_ctr_crypt(struct skcipher_request *req, bool encrypt)
pr_debug("counter %x will overflow (nblks %u), falling back\n",
counter, counter + nblks);
- ret = crypto_skcipher_setkey(ctx->fallback, ctx->aes_key,
- ctx->key_length);
+ ret = crypto_sync_skcipher_setkey(ctx->fallback, ctx->aes_key,
+ ctx->key_length);
if (ret)
return ret;
{
- SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback);
- skcipher_request_set_tfm(subreq, ctx->fallback);
+ skcipher_request_set_sync_tfm(subreq, ctx->fallback);
skcipher_request_set_callback(subreq, req->base.flags,
NULL, NULL);
skcipher_request_set_crypt(subreq, req->src, req->dst,
@@ -1561,10 +1561,9 @@ static int artpec6_crypto_aes_ctr_init(struct crypto_skcipher *tfm)
{
struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(tfm);
- ctx->fallback = crypto_alloc_skcipher(crypto_tfm_alg_name(&tfm->base),
- 0,
- CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_NEED_FALLBACK);
+ ctx->fallback =
+ crypto_alloc_sync_skcipher(crypto_tfm_alg_name(&tfm->base),
+ 0, CRYPTO_ALG_NEED_FALLBACK);
if (IS_ERR(ctx->fallback))
return PTR_ERR(ctx->fallback);
@@ -1605,7 +1604,7 @@ static void artpec6_crypto_aes_ctr_exit(struct crypto_skcipher *tfm)
{
struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(tfm);
- crypto_free_skcipher(ctx->fallback);
+ crypto_free_sync_skcipher(ctx->fallback);
artpec6_crypto_aes_exit(tfm);
}
@@ -3174,7 +3173,6 @@ static struct platform_driver artpec6_crypto_driver = {
.remove = artpec6_crypto_remove,
.driver = {
.name = "artpec6-crypto",
- .owner = THIS_MODULE,
.of_match_table = artpec6_crypto_of_match,
},
};
diff --git a/drivers/crypto/caam/Kconfig b/drivers/crypto/caam/Kconfig
index 1eb852765469..c4b1cade55c1 100644
--- a/drivers/crypto/caam/Kconfig
+++ b/drivers/crypto/caam/Kconfig
@@ -1,7 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0
+config CRYPTO_DEV_FSL_CAAM_COMMON
+ tristate
+
config CRYPTO_DEV_FSL_CAAM
- tristate "Freescale CAAM-Multicore driver backend"
+ tristate "Freescale CAAM-Multicore platform driver backend"
depends on FSL_SOC || ARCH_MXC || ARCH_LAYERSCAPE
select SOC_BUS
+ select CRYPTO_DEV_FSL_CAAM_COMMON
help
Enables the driver module for Freescale's Cryptographic Accelerator
and Assurance Module (CAAM), also known as the SEC version 4 (SEC4).
@@ -12,9 +17,16 @@ config CRYPTO_DEV_FSL_CAAM
To compile this driver as a module, choose M here: the module
will be called caam.
+if CRYPTO_DEV_FSL_CAAM
+
+config CRYPTO_DEV_FSL_CAAM_DEBUG
+ bool "Enable debug output in CAAM driver"
+ help
+ Selecting this will enable printing of various debug
+ information in the CAAM driver.
+
config CRYPTO_DEV_FSL_CAAM_JR
tristate "Freescale CAAM Job Ring driver backend"
- depends on CRYPTO_DEV_FSL_CAAM
default y
help
Enables the driver module for Job Rings which are part of
@@ -25,9 +37,10 @@ config CRYPTO_DEV_FSL_CAAM_JR
To compile this driver as a module, choose M here: the module
will be called caam_jr.
+if CRYPTO_DEV_FSL_CAAM_JR
+
config CRYPTO_DEV_FSL_CAAM_RINGSIZE
int "Job Ring size"
- depends on CRYPTO_DEV_FSL_CAAM_JR
range 2 9
default "9"
help
@@ -45,7 +58,6 @@ config CRYPTO_DEV_FSL_CAAM_RINGSIZE
config CRYPTO_DEV_FSL_CAAM_INTC
bool "Job Ring interrupt coalescing"
- depends on CRYPTO_DEV_FSL_CAAM_JR
help
Enable the Job Ring's interrupt coalescing feature.
@@ -75,7 +87,6 @@ config CRYPTO_DEV_FSL_CAAM_INTC_TIME_THLD
config CRYPTO_DEV_FSL_CAAM_CRYPTO_API
tristate "Register algorithm implementations with the Crypto API"
- depends on CRYPTO_DEV_FSL_CAAM_JR
default y
select CRYPTO_AEAD
select CRYPTO_AUTHENC
@@ -90,7 +101,7 @@ config CRYPTO_DEV_FSL_CAAM_CRYPTO_API
config CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI
tristate "Queue Interface as Crypto API backend"
- depends on CRYPTO_DEV_FSL_CAAM_JR && FSL_DPAA && NET
+ depends on FSL_DPAA && NET
default y
select CRYPTO_AUTHENC
select CRYPTO_BLKCIPHER
@@ -107,7 +118,6 @@ config CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI
config CRYPTO_DEV_FSL_CAAM_AHASH_API
tristate "Register hash algorithm implementations with Crypto API"
- depends on CRYPTO_DEV_FSL_CAAM_JR
default y
select CRYPTO_HASH
help
@@ -119,7 +129,6 @@ config CRYPTO_DEV_FSL_CAAM_AHASH_API
config CRYPTO_DEV_FSL_CAAM_PKC_API
tristate "Register public key cryptography implementations with Crypto API"
- depends on CRYPTO_DEV_FSL_CAAM_JR
default y
select CRYPTO_RSA
help
@@ -131,7 +140,6 @@ config CRYPTO_DEV_FSL_CAAM_PKC_API
config CRYPTO_DEV_FSL_CAAM_RNG_API
tristate "Register caam device for hwrng API"
- depends on CRYPTO_DEV_FSL_CAAM_JR
default y
select CRYPTO_RNG
select HW_RANDOM
@@ -142,13 +150,32 @@ config CRYPTO_DEV_FSL_CAAM_RNG_API
To compile this as a module, choose M here: the module
will be called caamrng.
-config CRYPTO_DEV_FSL_CAAM_DEBUG
- bool "Enable debug output in CAAM driver"
- depends on CRYPTO_DEV_FSL_CAAM
+endif # CRYPTO_DEV_FSL_CAAM_JR
+
+endif # CRYPTO_DEV_FSL_CAAM
+
+config CRYPTO_DEV_FSL_DPAA2_CAAM
+ tristate "QorIQ DPAA2 CAAM (DPSECI) driver"
+ depends on FSL_MC_DPIO
+ depends on NETDEVICES
+ select CRYPTO_DEV_FSL_CAAM_COMMON
+ select CRYPTO_BLKCIPHER
+ select CRYPTO_AUTHENC
+ select CRYPTO_AEAD
+ select CRYPTO_HASH
help
- Selecting this will enable printing of various debug
- information in the CAAM driver.
+ CAAM driver for QorIQ Data Path Acceleration Architecture 2.
+ It handles DPSECI DPAA2 objects that sit on the Management Complex
+ (MC) fsl-mc bus.
+
+ To compile this as a module, choose M here: the module
+ will be called dpaa2_caam.
config CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC
def_tristate (CRYPTO_DEV_FSL_CAAM_CRYPTO_API || \
- CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI)
+ CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI || \
+ CRYPTO_DEV_FSL_DPAA2_CAAM)
+
+config CRYPTO_DEV_FSL_CAAM_AHASH_API_DESC
+ def_tristate (CRYPTO_DEV_FSL_CAAM_AHASH_API || \
+ CRYPTO_DEV_FSL_DPAA2_CAAM)
diff --git a/drivers/crypto/caam/Makefile b/drivers/crypto/caam/Makefile
index cb652ee7dfc8..7bbfd06a11ff 100644
--- a/drivers/crypto/caam/Makefile
+++ b/drivers/crypto/caam/Makefile
@@ -6,19 +6,27 @@ ifeq ($(CONFIG_CRYPTO_DEV_FSL_CAAM_DEBUG), y)
ccflags-y := -DDEBUG
endif
+ccflags-y += -DVERSION=\"\"
+
+obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_COMMON) += error.o
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM) += caam.o
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_JR) += caam_jr.o
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API) += caamalg.o
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI) += caamalg_qi.o
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC) += caamalg_desc.o
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API) += caamhash.o
+obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API_DESC) += caamhash_desc.o
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API) += caamrng.o
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_PKC_API) += caam_pkc.o
caam-objs := ctrl.o
-caam_jr-objs := jr.o key_gen.o error.o
+caam_jr-objs := jr.o key_gen.o
caam_pkc-y := caampkc.o pkc_desc.o
ifneq ($(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI),)
ccflags-y += -DCONFIG_CAAM_QI
caam-objs += qi.o
endif
+
+obj-$(CONFIG_CRYPTO_DEV_FSL_DPAA2_CAAM) += dpaa2_caam.o
+
+dpaa2_caam-y := caamalg_qi2.o dpseci.o
diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c
index d67667970f7e..869f092432de 100644
--- a/drivers/crypto/caam/caamalg.c
+++ b/drivers/crypto/caam/caamalg.c
@@ -1,8 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* caam - Freescale FSL CAAM support for crypto API
*
* Copyright 2008-2011 Freescale Semiconductor, Inc.
- * Copyright 2016 NXP
+ * Copyright 2016-2018 NXP
*
* Based on talitos crypto API driver.
*
@@ -81,8 +82,6 @@
#define debug(format, arg...)
#endif
-static struct list_head alg_list;
-
struct caam_alg_entry {
int class1_alg_type;
int class2_alg_type;
@@ -96,17 +95,21 @@ struct caam_aead_alg {
bool registered;
};
+struct caam_skcipher_alg {
+ struct skcipher_alg skcipher;
+ struct caam_alg_entry caam;
+ bool registered;
+};
+
/*
* per-session context
*/
struct caam_ctx {
u32 sh_desc_enc[DESC_MAX_USED_LEN];
u32 sh_desc_dec[DESC_MAX_USED_LEN];
- u32 sh_desc_givenc[DESC_MAX_USED_LEN];
u8 key[CAAM_MAX_KEY_SIZE];
dma_addr_t sh_desc_enc_dma;
dma_addr_t sh_desc_dec_dma;
- dma_addr_t sh_desc_givenc_dma;
dma_addr_t key_dma;
enum dma_data_direction dir;
struct device *jrdev;
@@ -648,20 +651,20 @@ static int rfc4543_setkey(struct crypto_aead *aead,
return rfc4543_set_sh_desc(aead);
}
-static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher,
- const u8 *key, unsigned int keylen)
+static int skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key,
+ unsigned int keylen)
{
- struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher);
- struct crypto_tfm *tfm = crypto_ablkcipher_tfm(ablkcipher);
- const char *alg_name = crypto_tfm_alg_name(tfm);
+ struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
+ struct caam_skcipher_alg *alg =
+ container_of(crypto_skcipher_alg(skcipher), typeof(*alg),
+ skcipher);
struct device *jrdev = ctx->jrdev;
- unsigned int ivsize = crypto_ablkcipher_ivsize(ablkcipher);
+ unsigned int ivsize = crypto_skcipher_ivsize(skcipher);
u32 *desc;
u32 ctx1_iv_off = 0;
const bool ctr_mode = ((ctx->cdata.algtype & OP_ALG_AAI_MASK) ==
OP_ALG_AAI_CTR_MOD128);
- const bool is_rfc3686 = (ctr_mode &&
- (strstr(alg_name, "rfc3686") != NULL));
+ const bool is_rfc3686 = alg->caam.rfc3686;
#ifdef DEBUG
print_hex_dump(KERN_ERR, "key in @"__stringify(__LINE__)": ",
@@ -689,40 +692,32 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher,
ctx->cdata.key_virt = key;
ctx->cdata.key_inline = true;
- /* ablkcipher_encrypt shared descriptor */
+ /* skcipher_encrypt shared descriptor */
desc = ctx->sh_desc_enc;
- cnstr_shdsc_ablkcipher_encap(desc, &ctx->cdata, ivsize, is_rfc3686,
- ctx1_iv_off);
+ cnstr_shdsc_skcipher_encap(desc, &ctx->cdata, ivsize, is_rfc3686,
+ ctx1_iv_off);
dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma,
desc_bytes(desc), ctx->dir);
- /* ablkcipher_decrypt shared descriptor */
+ /* skcipher_decrypt shared descriptor */
desc = ctx->sh_desc_dec;
- cnstr_shdsc_ablkcipher_decap(desc, &ctx->cdata, ivsize, is_rfc3686,
- ctx1_iv_off);
+ cnstr_shdsc_skcipher_decap(desc, &ctx->cdata, ivsize, is_rfc3686,
+ ctx1_iv_off);
dma_sync_single_for_device(jrdev, ctx->sh_desc_dec_dma,
desc_bytes(desc), ctx->dir);
- /* ablkcipher_givencrypt shared descriptor */
- desc = ctx->sh_desc_givenc;
- cnstr_shdsc_ablkcipher_givencap(desc, &ctx->cdata, ivsize, is_rfc3686,
- ctx1_iv_off);
- dma_sync_single_for_device(jrdev, ctx->sh_desc_givenc_dma,
- desc_bytes(desc), ctx->dir);
-
return 0;
}
-static int xts_ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher,
- const u8 *key, unsigned int keylen)
+static int xts_skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key,
+ unsigned int keylen)
{
- struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher);
+ struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
struct device *jrdev = ctx->jrdev;
u32 *desc;
if (keylen != 2 * AES_MIN_KEY_SIZE && keylen != 2 * AES_MAX_KEY_SIZE) {
- crypto_ablkcipher_set_flags(ablkcipher,
- CRYPTO_TFM_RES_BAD_KEY_LEN);
+ crypto_skcipher_set_flags(skcipher, CRYPTO_TFM_RES_BAD_KEY_LEN);
dev_err(jrdev, "key size mismatch\n");
return -EINVAL;
}
@@ -731,15 +726,15 @@ static int xts_ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher,
ctx->cdata.key_virt = key;
ctx->cdata.key_inline = true;
- /* xts_ablkcipher_encrypt shared descriptor */
+ /* xts_skcipher_encrypt shared descriptor */
desc = ctx->sh_desc_enc;
- cnstr_shdsc_xts_ablkcipher_encap(desc, &ctx->cdata);
+ cnstr_shdsc_xts_skcipher_encap(desc, &ctx->cdata);
dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma,
desc_bytes(desc), ctx->dir);
- /* xts_ablkcipher_decrypt shared descriptor */
+ /* xts_skcipher_decrypt shared descriptor */
desc = ctx->sh_desc_dec;
- cnstr_shdsc_xts_ablkcipher_decap(desc, &ctx->cdata);
+ cnstr_shdsc_xts_skcipher_decap(desc, &ctx->cdata);
dma_sync_single_for_device(jrdev, ctx->sh_desc_dec_dma,
desc_bytes(desc), ctx->dir);
@@ -765,22 +760,20 @@ struct aead_edesc {
};
/*
- * ablkcipher_edesc - s/w-extended ablkcipher descriptor
+ * skcipher_edesc - s/w-extended skcipher descriptor
* @src_nents: number of segments in input s/w scatterlist
* @dst_nents: number of segments in output s/w scatterlist
* @iv_dma: dma address of iv for checking continuity and link table
- * @iv_dir: DMA mapping direction for IV
* @sec4_sg_bytes: length of dma mapped sec4_sg space
* @sec4_sg_dma: bus physical mapped address of h/w link table
* @sec4_sg: pointer to h/w link table
* @hw_desc: the h/w job descriptor followed by any referenced link tables
* and IV
*/
-struct ablkcipher_edesc {
+struct skcipher_edesc {
int src_nents;
int dst_nents;
dma_addr_t iv_dma;
- enum dma_data_direction iv_dir;
int sec4_sg_bytes;
dma_addr_t sec4_sg_dma;
struct sec4_sg_entry *sec4_sg;
@@ -790,8 +783,7 @@ struct ablkcipher_edesc {
static void caam_unmap(struct device *dev, struct scatterlist *src,
struct scatterlist *dst, int src_nents,
int dst_nents,
- dma_addr_t iv_dma, int ivsize,
- enum dma_data_direction iv_dir, dma_addr_t sec4_sg_dma,
+ dma_addr_t iv_dma, int ivsize, dma_addr_t sec4_sg_dma,
int sec4_sg_bytes)
{
if (dst != src) {
@@ -803,7 +795,7 @@ static void caam_unmap(struct device *dev, struct scatterlist *src,
}
if (iv_dma)
- dma_unmap_single(dev, iv_dma, ivsize, iv_dir);
+ dma_unmap_single(dev, iv_dma, ivsize, DMA_TO_DEVICE);
if (sec4_sg_bytes)
dma_unmap_single(dev, sec4_sg_dma, sec4_sg_bytes,
DMA_TO_DEVICE);
@@ -814,20 +806,19 @@ static void aead_unmap(struct device *dev,
struct aead_request *req)
{
caam_unmap(dev, req->src, req->dst,
- edesc->src_nents, edesc->dst_nents, 0, 0, DMA_NONE,
+ edesc->src_nents, edesc->dst_nents, 0, 0,
edesc->sec4_sg_dma, edesc->sec4_sg_bytes);
}
-static void ablkcipher_unmap(struct device *dev,
- struct ablkcipher_edesc *edesc,
- struct ablkcipher_request *req)
+static void skcipher_unmap(struct device *dev, struct skcipher_edesc *edesc,
+ struct skcipher_request *req)
{
- struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req);
- int ivsize = crypto_ablkcipher_ivsize(ablkcipher);
+ struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
+ int ivsize = crypto_skcipher_ivsize(skcipher);
caam_unmap(dev, req->src, req->dst,
edesc->src_nents, edesc->dst_nents,
- edesc->iv_dma, ivsize, edesc->iv_dir,
+ edesc->iv_dma, ivsize,
edesc->sec4_sg_dma, edesc->sec4_sg_bytes);
}
@@ -881,87 +872,74 @@ static void aead_decrypt_done(struct device *jrdev, u32 *desc, u32 err,
aead_request_complete(req, err);
}
-static void ablkcipher_encrypt_done(struct device *jrdev, u32 *desc, u32 err,
- void *context)
+static void skcipher_encrypt_done(struct device *jrdev, u32 *desc, u32 err,
+ void *context)
{
- struct ablkcipher_request *req = context;
- struct ablkcipher_edesc *edesc;
- struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req);
- int ivsize = crypto_ablkcipher_ivsize(ablkcipher);
+ struct skcipher_request *req = context;
+ struct skcipher_edesc *edesc;
+ struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
+ int ivsize = crypto_skcipher_ivsize(skcipher);
#ifdef DEBUG
dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
#endif
- edesc = container_of(desc, struct ablkcipher_edesc, hw_desc[0]);
+ edesc = container_of(desc, struct skcipher_edesc, hw_desc[0]);
if (err)
caam_jr_strstatus(jrdev, err);
#ifdef DEBUG
print_hex_dump(KERN_ERR, "dstiv @"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, req->info,
+ DUMP_PREFIX_ADDRESS, 16, 4, req->iv,
edesc->src_nents > 1 ? 100 : ivsize, 1);
#endif
caam_dump_sg(KERN_ERR, "dst @" __stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, req->dst,
- edesc->dst_nents > 1 ? 100 : req->nbytes, 1);
+ edesc->dst_nents > 1 ? 100 : req->cryptlen, 1);
- ablkcipher_unmap(jrdev, edesc, req);
+ skcipher_unmap(jrdev, edesc, req);
/*
- * The crypto API expects us to set the IV (req->info) to the last
+ * The crypto API expects us to set the IV (req->iv) to the last
* ciphertext block. This is used e.g. by the CTS mode.
*/
- scatterwalk_map_and_copy(req->info, req->dst, req->nbytes - ivsize,
+ scatterwalk_map_and_copy(req->iv, req->dst, req->cryptlen - ivsize,
ivsize, 0);
- /* In case initial IV was generated, copy it in GIVCIPHER request */
- if (edesc->iv_dir == DMA_FROM_DEVICE) {
- u8 *iv;
- struct skcipher_givcrypt_request *greq;
-
- greq = container_of(req, struct skcipher_givcrypt_request,
- creq);
- iv = (u8 *)edesc->hw_desc + desc_bytes(edesc->hw_desc) +
- edesc->sec4_sg_bytes;
- memcpy(greq->giv, iv, ivsize);
- }
-
kfree(edesc);
- ablkcipher_request_complete(req, err);
+ skcipher_request_complete(req, err);
}
-static void ablkcipher_decrypt_done(struct device *jrdev, u32 *desc, u32 err,
- void *context)
+static void skcipher_decrypt_done(struct device *jrdev, u32 *desc, u32 err,
+ void *context)
{
- struct ablkcipher_request *req = context;
- struct ablkcipher_edesc *edesc;
+ struct skcipher_request *req = context;
+ struct skcipher_edesc *edesc;
#ifdef DEBUG
- struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req);
- int ivsize = crypto_ablkcipher_ivsize(ablkcipher);
+ struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
+ int ivsize = crypto_skcipher_ivsize(skcipher);
dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
#endif
- edesc = container_of(desc, struct ablkcipher_edesc, hw_desc[0]);
+ edesc = container_of(desc, struct skcipher_edesc, hw_desc[0]);
if (err)
caam_jr_strstatus(jrdev, err);
#ifdef DEBUG
print_hex_dump(KERN_ERR, "dstiv @"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, req->info,
- ivsize, 1);
+ DUMP_PREFIX_ADDRESS, 16, 4, req->iv, ivsize, 1);
#endif
caam_dump_sg(KERN_ERR, "dst @" __stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, req->dst,
- edesc->dst_nents > 1 ? 100 : req->nbytes, 1);
+ edesc->dst_nents > 1 ? 100 : req->cryptlen, 1);
- ablkcipher_unmap(jrdev, edesc, req);
+ skcipher_unmap(jrdev, edesc, req);
kfree(edesc);
- ablkcipher_request_complete(req, err);
+ skcipher_request_complete(req, err);
}
/*
@@ -1103,34 +1081,38 @@ static void init_authenc_job(struct aead_request *req,
}
/*
- * Fill in ablkcipher job descriptor
+ * Fill in skcipher job descriptor
*/
-static void init_ablkcipher_job(u32 *sh_desc, dma_addr_t ptr,
- struct ablkcipher_edesc *edesc,
- struct ablkcipher_request *req)
+static void init_skcipher_job(struct skcipher_request *req,
+ struct skcipher_edesc *edesc,
+ const bool encrypt)
{
- struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req);
- int ivsize = crypto_ablkcipher_ivsize(ablkcipher);
+ struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
+ struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
+ int ivsize = crypto_skcipher_ivsize(skcipher);
u32 *desc = edesc->hw_desc;
+ u32 *sh_desc;
u32 out_options = 0;
- dma_addr_t dst_dma;
+ dma_addr_t dst_dma, ptr;
int len;
#ifdef DEBUG
print_hex_dump(KERN_ERR, "presciv@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, req->info,
- ivsize, 1);
- pr_err("asked=%d, nbytes%d\n",
- (int)edesc->src_nents > 1 ? 100 : req->nbytes, req->nbytes);
+ DUMP_PREFIX_ADDRESS, 16, 4, req->iv, ivsize, 1);
+ pr_err("asked=%d, cryptlen%d\n",
+ (int)edesc->src_nents > 1 ? 100 : req->cryptlen, req->cryptlen);
#endif
caam_dump_sg(KERN_ERR, "src @" __stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, req->src,
- edesc->src_nents > 1 ? 100 : req->nbytes, 1);
+ edesc->src_nents > 1 ? 100 : req->cryptlen, 1);
+
+ sh_desc = encrypt ? ctx->sh_desc_enc : ctx->sh_desc_dec;
+ ptr = encrypt ? ctx->sh_desc_enc_dma : ctx->sh_desc_dec_dma;
len = desc_len(sh_desc);
init_job_desc_shared(desc, ptr, len, HDR_SHARE_DEFER | HDR_REVERSE);
- append_seq_in_ptr(desc, edesc->sec4_sg_dma, req->nbytes + ivsize,
+ append_seq_in_ptr(desc, edesc->sec4_sg_dma, req->cryptlen + ivsize,
LDST_SGF);
if (likely(req->src == req->dst)) {
@@ -1145,48 +1127,7 @@ static void init_ablkcipher_job(u32 *sh_desc, dma_addr_t ptr,
out_options = LDST_SGF;
}
}
- append_seq_out_ptr(desc, dst_dma, req->nbytes, out_options);
-}
-
-/*
- * Fill in ablkcipher givencrypt job descriptor
- */
-static void init_ablkcipher_giv_job(u32 *sh_desc, dma_addr_t ptr,
- struct ablkcipher_edesc *edesc,
- struct ablkcipher_request *req)
-{
- struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req);
- int ivsize = crypto_ablkcipher_ivsize(ablkcipher);
- u32 *desc = edesc->hw_desc;
- u32 in_options;
- dma_addr_t dst_dma, src_dma;
- int len, sec4_sg_index = 0;
-
-#ifdef DEBUG
- print_hex_dump(KERN_ERR, "presciv@" __stringify(__LINE__) ": ",
- DUMP_PREFIX_ADDRESS, 16, 4, req->info,
- ivsize, 1);
-#endif
- caam_dump_sg(KERN_ERR, "src @" __stringify(__LINE__) ": ",
- DUMP_PREFIX_ADDRESS, 16, 4, req->src,
- edesc->src_nents > 1 ? 100 : req->nbytes, 1);
-
- len = desc_len(sh_desc);
- init_job_desc_shared(desc, ptr, len, HDR_SHARE_DEFER | HDR_REVERSE);
-
- if (edesc->src_nents == 1) {
- src_dma = sg_dma_address(req->src);
- in_options = 0;
- } else {
- src_dma = edesc->sec4_sg_dma;
- sec4_sg_index += edesc->src_nents;
- in_options = LDST_SGF;
- }
- append_seq_in_ptr(desc, src_dma, req->nbytes, in_options);
-
- dst_dma = edesc->sec4_sg_dma + sec4_sg_index *
- sizeof(struct sec4_sg_entry);
- append_seq_out_ptr(desc, dst_dma, req->nbytes + ivsize, LDST_SGF);
+ append_seq_out_ptr(desc, dst_dma, req->cryptlen, out_options);
}
/*
@@ -1275,7 +1216,7 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
GFP_DMA | flags);
if (!edesc) {
caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, 0,
- 0, DMA_NONE, 0, 0);
+ 0, 0, 0);
return ERR_PTR(-ENOMEM);
}
@@ -1476,35 +1417,35 @@ static int aead_decrypt(struct aead_request *req)
}
/*
- * allocate and map the ablkcipher extended descriptor for ablkcipher
+ * allocate and map the skcipher extended descriptor for skcipher
*/
-static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request
- *req, int desc_bytes)
+static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req,
+ int desc_bytes)
{
- struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req);
- struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher);
+ struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
+ struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
struct device *jrdev = ctx->jrdev;
gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
GFP_KERNEL : GFP_ATOMIC;
int src_nents, mapped_src_nents, dst_nents = 0, mapped_dst_nents = 0;
- struct ablkcipher_edesc *edesc;
+ struct skcipher_edesc *edesc;
dma_addr_t iv_dma;
u8 *iv;
- int ivsize = crypto_ablkcipher_ivsize(ablkcipher);
+ int ivsize = crypto_skcipher_ivsize(skcipher);
int dst_sg_idx, sec4_sg_ents, sec4_sg_bytes;
- src_nents = sg_nents_for_len(req->src, req->nbytes);
+ src_nents = sg_nents_for_len(req->src, req->cryptlen);
if (unlikely(src_nents < 0)) {
dev_err(jrdev, "Insufficient bytes (%d) in src S/G\n",
- req->nbytes);
+ req->cryptlen);
return ERR_PTR(src_nents);
}
if (req->dst != req->src) {
- dst_nents = sg_nents_for_len(req->dst, req->nbytes);
+ dst_nents = sg_nents_for_len(req->dst, req->cryptlen);
if (unlikely(dst_nents < 0)) {
dev_err(jrdev, "Insufficient bytes (%d) in dst S/G\n",
- req->nbytes);
+ req->cryptlen);
return ERR_PTR(dst_nents);
}
}
@@ -1546,26 +1487,25 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request
if (!edesc) {
dev_err(jrdev, "could not allocate extended descriptor\n");
caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, 0,
- 0, DMA_NONE, 0, 0);
+ 0, 0, 0);
return ERR_PTR(-ENOMEM);
}
edesc->src_nents = src_nents;
edesc->dst_nents = dst_nents;
edesc->sec4_sg_bytes = sec4_sg_bytes;
- edesc->sec4_sg = (void *)edesc + sizeof(struct ablkcipher_edesc) +
- desc_bytes;
- edesc->iv_dir = DMA_TO_DEVICE;
+ edesc->sec4_sg = (struct sec4_sg_entry *)((u8 *)edesc->hw_desc +
+ desc_bytes);
/* Make sure IV is located in a DMAable area */
iv = (u8 *)edesc->hw_desc + desc_bytes + sec4_sg_bytes;
- memcpy(iv, req->info, ivsize);
+ memcpy(iv, req->iv, ivsize);
iv_dma = dma_map_single(jrdev, iv, ivsize, DMA_TO_DEVICE);
if (dma_mapping_error(jrdev, iv_dma)) {
dev_err(jrdev, "unable to map IV\n");
caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, 0,
- 0, DMA_NONE, 0, 0);
+ 0, 0, 0);
kfree(edesc);
return ERR_PTR(-ENOMEM);
}
@@ -1583,7 +1523,7 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request
if (dma_mapping_error(jrdev, edesc->sec4_sg_dma)) {
dev_err(jrdev, "unable to map S/G table\n");
caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents,
- iv_dma, ivsize, DMA_TO_DEVICE, 0, 0);
+ iv_dma, ivsize, 0, 0);
kfree(edesc);
return ERR_PTR(-ENOMEM);
}
@@ -1591,7 +1531,7 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request
edesc->iv_dma = iv_dma;
#ifdef DEBUG
- print_hex_dump(KERN_ERR, "ablkcipher sec4_sg@"__stringify(__LINE__)": ",
+ print_hex_dump(KERN_ERR, "skcipher sec4_sg@" __stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, edesc->sec4_sg,
sec4_sg_bytes, 1);
#endif
@@ -1599,362 +1539,187 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request
return edesc;
}
-static int ablkcipher_encrypt(struct ablkcipher_request *req)
+static int skcipher_encrypt(struct skcipher_request *req)
{
- struct ablkcipher_edesc *edesc;
- struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req);
- struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher);
+ struct skcipher_edesc *edesc;
+ struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
+ struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
struct device *jrdev = ctx->jrdev;
u32 *desc;
int ret = 0;
/* allocate extended descriptor */
- edesc = ablkcipher_edesc_alloc(req, DESC_JOB_IO_LEN * CAAM_CMD_SZ);
+ edesc = skcipher_edesc_alloc(req, DESC_JOB_IO_LEN * CAAM_CMD_SZ);
if (IS_ERR(edesc))
return PTR_ERR(edesc);
/* Create and submit job descriptor*/
- init_ablkcipher_job(ctx->sh_desc_enc, ctx->sh_desc_enc_dma, edesc, req);
+ init_skcipher_job(req, edesc, true);
#ifdef DEBUG
- print_hex_dump(KERN_ERR, "ablkcipher jobdesc@"__stringify(__LINE__)": ",
+ print_hex_dump(KERN_ERR, "skcipher jobdesc@" __stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc,
desc_bytes(edesc->hw_desc), 1);
#endif
desc = edesc->hw_desc;
- ret = caam_jr_enqueue(jrdev, desc, ablkcipher_encrypt_done, req);
+ ret = caam_jr_enqueue(jrdev, desc, skcipher_encrypt_done, req);
if (!ret) {
ret = -EINPROGRESS;
} else {
- ablkcipher_unmap(jrdev, edesc, req);
+ skcipher_unmap(jrdev, edesc, req);
kfree(edesc);
}
return ret;
}
-static int ablkcipher_decrypt(struct ablkcipher_request *req)
+static int skcipher_decrypt(struct skcipher_request *req)
{
- struct ablkcipher_edesc *edesc;
- struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req);
- struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher);
- int ivsize = crypto_ablkcipher_ivsize(ablkcipher);
+ struct skcipher_edesc *edesc;
+ struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
+ struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
+ int ivsize = crypto_skcipher_ivsize(skcipher);
struct device *jrdev = ctx->jrdev;
u32 *desc;
int ret = 0;
/* allocate extended descriptor */
- edesc = ablkcipher_edesc_alloc(req, DESC_JOB_IO_LEN * CAAM_CMD_SZ);
+ edesc = skcipher_edesc_alloc(req, DESC_JOB_IO_LEN * CAAM_CMD_SZ);
if (IS_ERR(edesc))
return PTR_ERR(edesc);
/*
- * The crypto API expects us to set the IV (req->info) to the last
+ * The crypto API expects us to set the IV (req->iv) to the last
* ciphertext block.
*/
- scatterwalk_map_and_copy(req->info, req->src, req->nbytes - ivsize,
+ scatterwalk_map_and_copy(req->iv, req->src, req->cryptlen - ivsize,
ivsize, 0);
/* Create and submit job descriptor*/
- init_ablkcipher_job(ctx->sh_desc_dec, ctx->sh_desc_dec_dma, edesc, req);
+ init_skcipher_job(req, edesc, false);
desc = edesc->hw_desc;
#ifdef DEBUG
- print_hex_dump(KERN_ERR, "ablkcipher jobdesc@"__stringify(__LINE__)": ",
+ print_hex_dump(KERN_ERR, "skcipher jobdesc@" __stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc,
desc_bytes(edesc->hw_desc), 1);
#endif
- ret = caam_jr_enqueue(jrdev, desc, ablkcipher_decrypt_done, req);
+ ret = caam_jr_enqueue(jrdev, desc, skcipher_decrypt_done, req);
if (!ret) {
ret = -EINPROGRESS;
} else {
- ablkcipher_unmap(jrdev, edesc, req);
+ skcipher_unmap(jrdev, edesc, req);
kfree(edesc);
}
return ret;
}
-/*
- * allocate and map the ablkcipher extended descriptor
- * for ablkcipher givencrypt
- */
-static struct ablkcipher_edesc *ablkcipher_giv_edesc_alloc(
- struct skcipher_givcrypt_request *greq,
- int desc_bytes)
-{
- struct ablkcipher_request *req = &greq->creq;
- struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req);
- struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher);
- struct device *jrdev = ctx->jrdev;
- gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
- GFP_KERNEL : GFP_ATOMIC;
- int src_nents, mapped_src_nents, dst_nents, mapped_dst_nents;
- struct ablkcipher_edesc *edesc;
- dma_addr_t iv_dma;
- u8 *iv;
- int ivsize = crypto_ablkcipher_ivsize(ablkcipher);
- int dst_sg_idx, sec4_sg_ents, sec4_sg_bytes;
-
- src_nents = sg_nents_for_len(req->src, req->nbytes);
- if (unlikely(src_nents < 0)) {
- dev_err(jrdev, "Insufficient bytes (%d) in src S/G\n",
- req->nbytes);
- return ERR_PTR(src_nents);
- }
-
- if (likely(req->src == req->dst)) {
- mapped_src_nents = dma_map_sg(jrdev, req->src, src_nents,
- DMA_BIDIRECTIONAL);
- if (unlikely(!mapped_src_nents)) {
- dev_err(jrdev, "unable to map source\n");
- return ERR_PTR(-ENOMEM);
- }
-
- dst_nents = src_nents;
- mapped_dst_nents = src_nents;
- } else {
- mapped_src_nents = dma_map_sg(jrdev, req->src, src_nents,
- DMA_TO_DEVICE);
- if (unlikely(!mapped_src_nents)) {
- dev_err(jrdev, "unable to map source\n");
- return ERR_PTR(-ENOMEM);
- }
-
- dst_nents = sg_nents_for_len(req->dst, req->nbytes);
- if (unlikely(dst_nents < 0)) {
- dev_err(jrdev, "Insufficient bytes (%d) in dst S/G\n",
- req->nbytes);
- return ERR_PTR(dst_nents);
- }
-
- mapped_dst_nents = dma_map_sg(jrdev, req->dst, dst_nents,
- DMA_FROM_DEVICE);
- if (unlikely(!mapped_dst_nents)) {
- dev_err(jrdev, "unable to map destination\n");
- dma_unmap_sg(jrdev, req->src, src_nents, DMA_TO_DEVICE);
- return ERR_PTR(-ENOMEM);
- }
- }
-
- sec4_sg_ents = mapped_src_nents > 1 ? mapped_src_nents : 0;
- dst_sg_idx = sec4_sg_ents;
- sec4_sg_ents += 1 + mapped_dst_nents;
-
- /*
- * allocate space for base edesc and hw desc commands, link tables, IV
- */
- sec4_sg_bytes = sec4_sg_ents * sizeof(struct sec4_sg_entry);
- edesc = kzalloc(sizeof(*edesc) + desc_bytes + sec4_sg_bytes + ivsize,
- GFP_DMA | flags);
- if (!edesc) {
- dev_err(jrdev, "could not allocate extended descriptor\n");
- caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, 0,
- 0, DMA_NONE, 0, 0);
- return ERR_PTR(-ENOMEM);
- }
-
- edesc->src_nents = src_nents;
- edesc->dst_nents = dst_nents;
- edesc->sec4_sg_bytes = sec4_sg_bytes;
- edesc->sec4_sg = (void *)edesc + sizeof(struct ablkcipher_edesc) +
- desc_bytes;
- edesc->iv_dir = DMA_FROM_DEVICE;
-
- /* Make sure IV is located in a DMAable area */
- iv = (u8 *)edesc->hw_desc + desc_bytes + sec4_sg_bytes;
- iv_dma = dma_map_single(jrdev, iv, ivsize, DMA_FROM_DEVICE);
- if (dma_mapping_error(jrdev, iv_dma)) {
- dev_err(jrdev, "unable to map IV\n");
- caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, 0,
- 0, DMA_NONE, 0, 0);
- kfree(edesc);
- return ERR_PTR(-ENOMEM);
- }
-
- if (mapped_src_nents > 1)
- sg_to_sec4_sg_last(req->src, mapped_src_nents, edesc->sec4_sg,
- 0);
-
- dma_to_sec4_sg_one(edesc->sec4_sg + dst_sg_idx, iv_dma, ivsize, 0);
- sg_to_sec4_sg_last(req->dst, mapped_dst_nents, edesc->sec4_sg +
- dst_sg_idx + 1, 0);
-
- edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg,
- sec4_sg_bytes, DMA_TO_DEVICE);
- if (dma_mapping_error(jrdev, edesc->sec4_sg_dma)) {
- dev_err(jrdev, "unable to map S/G table\n");
- caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents,
- iv_dma, ivsize, DMA_FROM_DEVICE, 0, 0);
- kfree(edesc);
- return ERR_PTR(-ENOMEM);
- }
- edesc->iv_dma = iv_dma;
-
-#ifdef DEBUG
- print_hex_dump(KERN_ERR,
- "ablkcipher sec4_sg@" __stringify(__LINE__) ": ",
- DUMP_PREFIX_ADDRESS, 16, 4, edesc->sec4_sg,
- sec4_sg_bytes, 1);
-#endif
-
- return edesc;
-}
-
-static int ablkcipher_givencrypt(struct skcipher_givcrypt_request *creq)
-{
- struct ablkcipher_request *req = &creq->creq;
- struct ablkcipher_edesc *edesc;
- struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req);
- struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher);
- struct device *jrdev = ctx->jrdev;
- u32 *desc;
- int ret = 0;
-
- /* allocate extended descriptor */
- edesc = ablkcipher_giv_edesc_alloc(creq, DESC_JOB_IO_LEN * CAAM_CMD_SZ);
- if (IS_ERR(edesc))
- return PTR_ERR(edesc);
-
- /* Create and submit job descriptor*/
- init_ablkcipher_giv_job(ctx->sh_desc_givenc, ctx->sh_desc_givenc_dma,
- edesc, req);
-#ifdef DEBUG
- print_hex_dump(KERN_ERR,
- "ablkcipher jobdesc@" __stringify(__LINE__) ": ",
- DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc,
- desc_bytes(edesc->hw_desc), 1);
-#endif
- desc = edesc->hw_desc;
- ret = caam_jr_enqueue(jrdev, desc, ablkcipher_encrypt_done, req);
-
- if (!ret) {
- ret = -EINPROGRESS;
- } else {
- ablkcipher_unmap(jrdev, edesc, req);
- kfree(edesc);
- }
-
- return ret;
-}
-
-#define template_aead template_u.aead
-#define template_ablkcipher template_u.ablkcipher
-struct caam_alg_template {
- char name[CRYPTO_MAX_ALG_NAME];
- char driver_name[CRYPTO_MAX_ALG_NAME];
- unsigned int blocksize;
- u32 type;
- union {
- struct ablkcipher_alg ablkcipher;
- } template_u;
- u32 class1_alg_type;
- u32 class2_alg_type;
-};
-
-static struct caam_alg_template driver_algs[] = {
- /* ablkcipher descriptor */
+static struct caam_skcipher_alg driver_algs[] = {
{
- .name = "cbc(aes)",
- .driver_name = "cbc-aes-caam",
- .blocksize = AES_BLOCK_SIZE,
- .type = CRYPTO_ALG_TYPE_GIVCIPHER,
- .template_ablkcipher = {
- .setkey = ablkcipher_setkey,
- .encrypt = ablkcipher_encrypt,
- .decrypt = ablkcipher_decrypt,
- .givencrypt = ablkcipher_givencrypt,
- .geniv = "<built-in>",
+ .skcipher = {
+ .base = {
+ .cra_name = "cbc(aes)",
+ .cra_driver_name = "cbc-aes-caam",
+ .cra_blocksize = AES_BLOCK_SIZE,
+ },
+ .setkey = skcipher_setkey,
+ .encrypt = skcipher_encrypt,
+ .decrypt = skcipher_decrypt,
.min_keysize = AES_MIN_KEY_SIZE,
.max_keysize = AES_MAX_KEY_SIZE,
.ivsize = AES_BLOCK_SIZE,
- },
- .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
+ },
+ .caam.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
},
{
- .name = "cbc(des3_ede)",
- .driver_name = "cbc-3des-caam",
- .blocksize = DES3_EDE_BLOCK_SIZE,
- .type = CRYPTO_ALG_TYPE_GIVCIPHER,
- .template_ablkcipher = {
- .setkey = ablkcipher_setkey,
- .encrypt = ablkcipher_encrypt,
- .decrypt = ablkcipher_decrypt,
- .givencrypt = ablkcipher_givencrypt,
- .geniv = "<built-in>",
+ .skcipher = {
+ .base = {
+ .cra_name = "cbc(des3_ede)",
+ .cra_driver_name = "cbc-3des-caam",
+ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
+ },
+ .setkey = skcipher_setkey,
+ .encrypt = skcipher_encrypt,
+ .decrypt = skcipher_decrypt,
.min_keysize = DES3_EDE_KEY_SIZE,
.max_keysize = DES3_EDE_KEY_SIZE,
.ivsize = DES3_EDE_BLOCK_SIZE,
- },
- .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
+ },
+ .caam.class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
},
{
- .name = "cbc(des)",
- .driver_name = "cbc-des-caam",
- .blocksize = DES_BLOCK_SIZE,
- .type = CRYPTO_ALG_TYPE_GIVCIPHER,
- .template_ablkcipher = {
- .setkey = ablkcipher_setkey,
- .encrypt = ablkcipher_encrypt,
- .decrypt = ablkcipher_decrypt,
- .givencrypt = ablkcipher_givencrypt,
- .geniv = "<built-in>",
+ .skcipher = {
+ .base = {
+ .cra_name = "cbc(des)",
+ .cra_driver_name = "cbc-des-caam",
+ .cra_blocksize = DES_BLOCK_SIZE,
+ },
+ .setkey = skcipher_setkey,
+ .encrypt = skcipher_encrypt,
+ .decrypt = skcipher_decrypt,
.min_keysize = DES_KEY_SIZE,
.max_keysize = DES_KEY_SIZE,
.ivsize = DES_BLOCK_SIZE,
- },
- .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
+ },
+ .caam.class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
},
{
- .name = "ctr(aes)",
- .driver_name = "ctr-aes-caam",
- .blocksize = 1,
- .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
- .template_ablkcipher = {
- .setkey = ablkcipher_setkey,
- .encrypt = ablkcipher_encrypt,
- .decrypt = ablkcipher_decrypt,
- .geniv = "chainiv",
+ .skcipher = {
+ .base = {
+ .cra_name = "ctr(aes)",
+ .cra_driver_name = "ctr-aes-caam",
+ .cra_blocksize = 1,
+ },
+ .setkey = skcipher_setkey,
+ .encrypt = skcipher_encrypt,
+ .decrypt = skcipher_decrypt,
.min_keysize = AES_MIN_KEY_SIZE,
.max_keysize = AES_MAX_KEY_SIZE,
.ivsize = AES_BLOCK_SIZE,
- },
- .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CTR_MOD128,
+ .chunksize = AES_BLOCK_SIZE,
+ },
+ .caam.class1_alg_type = OP_ALG_ALGSEL_AES |
+ OP_ALG_AAI_CTR_MOD128,
},
{
- .name = "rfc3686(ctr(aes))",
- .driver_name = "rfc3686-ctr-aes-caam",
- .blocksize = 1,
- .type = CRYPTO_ALG_TYPE_GIVCIPHER,
- .template_ablkcipher = {
- .setkey = ablkcipher_setkey,
- .encrypt = ablkcipher_encrypt,
- .decrypt = ablkcipher_decrypt,
- .givencrypt = ablkcipher_givencrypt,
- .geniv = "<built-in>",
+ .skcipher = {
+ .base = {
+ .cra_name = "rfc3686(ctr(aes))",
+ .cra_driver_name = "rfc3686-ctr-aes-caam",
+ .cra_blocksize = 1,
+ },
+ .setkey = skcipher_setkey,
+ .encrypt = skcipher_encrypt,
+ .decrypt = skcipher_decrypt,
.min_keysize = AES_MIN_KEY_SIZE +
CTR_RFC3686_NONCE_SIZE,
.max_keysize = AES_MAX_KEY_SIZE +
CTR_RFC3686_NONCE_SIZE,
.ivsize = CTR_RFC3686_IV_SIZE,
- },
- .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CTR_MOD128,
+ .chunksize = AES_BLOCK_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_AES |
+ OP_ALG_AAI_CTR_MOD128,
+ .rfc3686 = true,
+ },
},
{
- .name = "xts(aes)",
- .driver_name = "xts-aes-caam",
- .blocksize = AES_BLOCK_SIZE,
- .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
- .template_ablkcipher = {
- .setkey = xts_ablkcipher_setkey,
- .encrypt = ablkcipher_encrypt,
- .decrypt = ablkcipher_decrypt,
- .geniv = "eseqiv",
+ .skcipher = {
+ .base = {
+ .cra_name = "xts(aes)",
+ .cra_driver_name = "xts-aes-caam",
+ .cra_blocksize = AES_BLOCK_SIZE,
+ },
+ .setkey = xts_skcipher_setkey,
+ .encrypt = skcipher_encrypt,
+ .decrypt = skcipher_decrypt,
.min_keysize = 2 * AES_MIN_KEY_SIZE,
.max_keysize = 2 * AES_MAX_KEY_SIZE,
.ivsize = AES_BLOCK_SIZE,
- },
- .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_XTS,
+ },
+ .caam.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_XTS,
},
};
@@ -3239,12 +3004,6 @@ static struct caam_aead_alg driver_aeads[] = {
},
};
-struct caam_crypto_alg {
- struct crypto_alg crypto_alg;
- struct list_head entry;
- struct caam_alg_entry caam;
-};
-
static int caam_init_common(struct caam_ctx *ctx, struct caam_alg_entry *caam,
bool uses_dkp)
{
@@ -3276,8 +3035,6 @@ static int caam_init_common(struct caam_ctx *ctx, struct caam_alg_entry *caam,
ctx->sh_desc_enc_dma = dma_addr;
ctx->sh_desc_dec_dma = dma_addr + offsetof(struct caam_ctx,
sh_desc_dec);
- ctx->sh_desc_givenc_dma = dma_addr + offsetof(struct caam_ctx,
- sh_desc_givenc);
ctx->key_dma = dma_addr + offsetof(struct caam_ctx, key);
/* copy descriptor header template value */
@@ -3287,14 +3044,14 @@ static int caam_init_common(struct caam_ctx *ctx, struct caam_alg_entry *caam,
return 0;
}
-static int caam_cra_init(struct crypto_tfm *tfm)
+static int caam_cra_init(struct crypto_skcipher *tfm)
{
- struct crypto_alg *alg = tfm->__crt_alg;
- struct caam_crypto_alg *caam_alg =
- container_of(alg, struct caam_crypto_alg, crypto_alg);
- struct caam_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
+ struct caam_skcipher_alg *caam_alg =
+ container_of(alg, typeof(*caam_alg), skcipher);
- return caam_init_common(ctx, &caam_alg->caam, false);
+ return caam_init_common(crypto_skcipher_ctx(tfm), &caam_alg->caam,
+ false);
}
static int caam_aead_init(struct crypto_aead *tfm)
@@ -3316,9 +3073,9 @@ static void caam_exit_common(struct caam_ctx *ctx)
caam_jr_free(ctx->jrdev);
}
-static void caam_cra_exit(struct crypto_tfm *tfm)
+static void caam_cra_exit(struct crypto_skcipher *tfm)
{
- caam_exit_common(crypto_tfm_ctx(tfm));
+ caam_exit_common(crypto_skcipher_ctx(tfm));
}
static void caam_aead_exit(struct crypto_aead *tfm)
@@ -3328,8 +3085,6 @@ static void caam_aead_exit(struct crypto_aead *tfm)
static void __exit caam_algapi_exit(void)
{
-
- struct caam_crypto_alg *t_alg, *n;
int i;
for (i = 0; i < ARRAY_SIZE(driver_aeads); i++) {
@@ -3339,57 +3094,25 @@ static void __exit caam_algapi_exit(void)
crypto_unregister_aead(&t_alg->aead);
}
- if (!alg_list.next)
- return;
+ for (i = 0; i < ARRAY_SIZE(driver_algs); i++) {
+ struct caam_skcipher_alg *t_alg = driver_algs + i;
- list_for_each_entry_safe(t_alg, n, &alg_list, entry) {
- crypto_unregister_alg(&t_alg->crypto_alg);
- list_del(&t_alg->entry);
- kfree(t_alg);
+ if (t_alg->registered)
+ crypto_unregister_skcipher(&t_alg->skcipher);
}
}
-static struct caam_crypto_alg *caam_alg_alloc(struct caam_alg_template
- *template)
+static void caam_skcipher_alg_init(struct caam_skcipher_alg *t_alg)
{
- struct caam_crypto_alg *t_alg;
- struct crypto_alg *alg;
+ struct skcipher_alg *alg = &t_alg->skcipher;
- t_alg = kzalloc(sizeof(*t_alg), GFP_KERNEL);
- if (!t_alg) {
- pr_err("failed to allocate t_alg\n");
- return ERR_PTR(-ENOMEM);
- }
-
- alg = &t_alg->crypto_alg;
-
- snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s", template->name);
- snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
- template->driver_name);
- alg->cra_module = THIS_MODULE;
- alg->cra_init = caam_cra_init;
- alg->cra_exit = caam_cra_exit;
- alg->cra_priority = CAAM_CRA_PRIORITY;
- alg->cra_blocksize = template->blocksize;
- alg->cra_alignmask = 0;
- alg->cra_ctxsize = sizeof(struct caam_ctx);
- alg->cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY |
- template->type;
- switch (template->type) {
- case CRYPTO_ALG_TYPE_GIVCIPHER:
- alg->cra_type = &crypto_givcipher_type;
- alg->cra_ablkcipher = template->template_ablkcipher;
- break;
- case CRYPTO_ALG_TYPE_ABLKCIPHER:
- alg->cra_type = &crypto_ablkcipher_type;
- alg->cra_ablkcipher = template->template_ablkcipher;
- break;
- }
-
- t_alg->caam.class1_alg_type = template->class1_alg_type;
- t_alg->caam.class2_alg_type = template->class2_alg_type;
+ alg->base.cra_module = THIS_MODULE;
+ alg->base.cra_priority = CAAM_CRA_PRIORITY;
+ alg->base.cra_ctxsize = sizeof(struct caam_ctx);
+ alg->base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY;
- return t_alg;
+ alg->init = caam_cra_init;
+ alg->exit = caam_cra_exit;
}
static void caam_aead_alg_init(struct caam_aead_alg *t_alg)
@@ -3441,8 +3164,6 @@ static int __init caam_algapi_init(void)
return -ENODEV;
- INIT_LIST_HEAD(&alg_list);
-
/*
* Register crypto algorithms the device supports.
* First, detect presence and attributes of DES, AES, and MD blocks.
@@ -3458,9 +3179,8 @@ static int __init caam_algapi_init(void)
md_limit = SHA256_DIGEST_SIZE;
for (i = 0; i < ARRAY_SIZE(driver_algs); i++) {
- struct caam_crypto_alg *t_alg;
- struct caam_alg_template *alg = driver_algs + i;
- u32 alg_sel = alg->class1_alg_type & OP_ALG_ALGSEL_MASK;
+ struct caam_skcipher_alg *t_alg = driver_algs + i;
+ u32 alg_sel = t_alg->caam.class1_alg_type & OP_ALG_ALGSEL_MASK;
/* Skip DES algorithms if not supported by device */
if (!des_inst &&
@@ -3477,26 +3197,20 @@ static int __init caam_algapi_init(void)
* on LP devices.
*/
if ((cha_vid & CHA_ID_LS_AES_MASK) == CHA_ID_LS_AES_LP)
- if ((alg->class1_alg_type & OP_ALG_AAI_MASK) ==
+ if ((t_alg->caam.class1_alg_type & OP_ALG_AAI_MASK) ==
OP_ALG_AAI_XTS)
continue;
- t_alg = caam_alg_alloc(alg);
- if (IS_ERR(t_alg)) {
- err = PTR_ERR(t_alg);
- pr_warn("%s alg allocation failed\n", alg->driver_name);
- continue;
- }
+ caam_skcipher_alg_init(t_alg);
- err = crypto_register_alg(&t_alg->crypto_alg);
+ err = crypto_register_skcipher(&t_alg->skcipher);
if (err) {
pr_warn("%s alg registration failed\n",
- t_alg->crypto_alg.cra_driver_name);
- kfree(t_alg);
+ t_alg->skcipher.base.cra_driver_name);
continue;
}
- list_add_tail(&t_alg->entry, &alg_list);
+ t_alg->registered = true;
registered = true;
}
diff --git a/drivers/crypto/caam/caamalg_desc.c b/drivers/crypto/caam/caamalg_desc.c
index a408edd84f34..1a6f0da14106 100644
--- a/drivers/crypto/caam/caamalg_desc.c
+++ b/drivers/crypto/caam/caamalg_desc.c
@@ -1,7 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
- * Shared descriptors for aead, ablkcipher algorithms
+ * Shared descriptors for aead, skcipher algorithms
*
- * Copyright 2016 NXP
+ * Copyright 2016-2018 NXP
*/
#include "compat.h"
@@ -1212,11 +1213,8 @@ void cnstr_shdsc_rfc4543_decap(u32 * const desc, struct alginfo *cdata,
}
EXPORT_SYMBOL(cnstr_shdsc_rfc4543_decap);
-/*
- * For ablkcipher encrypt and decrypt, read from req->src and
- * write to req->dst
- */
-static inline void ablkcipher_append_src_dst(u32 *desc)
+/* For skcipher encrypt and decrypt, read from req->src and write to req->dst */
+static inline void skcipher_append_src_dst(u32 *desc)
{
append_math_add(desc, VARSEQOUTLEN, SEQINLEN, REG0, CAAM_CMD_SZ);
append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ);
@@ -1226,7 +1224,7 @@ static inline void ablkcipher_append_src_dst(u32 *desc)
}
/**
- * cnstr_shdsc_ablkcipher_encap - ablkcipher encapsulation shared descriptor
+ * cnstr_shdsc_skcipher_encap - skcipher encapsulation shared descriptor
* @desc: pointer to buffer used for descriptor construction
* @cdata: pointer to block cipher transform definitions
* Valid algorithm values - one of OP_ALG_ALGSEL_{AES, DES, 3DES} ANDed
@@ -1235,9 +1233,9 @@ static inline void ablkcipher_append_src_dst(u32 *desc)
* @is_rfc3686: true when ctr(aes) is wrapped by rfc3686 template
* @ctx1_iv_off: IV offset in CONTEXT1 register
*/
-void cnstr_shdsc_ablkcipher_encap(u32 * const desc, struct alginfo *cdata,
- unsigned int ivsize, const bool is_rfc3686,
- const u32 ctx1_iv_off)
+void cnstr_shdsc_skcipher_encap(u32 * const desc, struct alginfo *cdata,
+ unsigned int ivsize, const bool is_rfc3686,
+ const u32 ctx1_iv_off)
{
u32 *key_jump_cmd;
@@ -1280,18 +1278,18 @@ void cnstr_shdsc_ablkcipher_encap(u32 * const desc, struct alginfo *cdata,
OP_ALG_ENCRYPT);
/* Perform operation */
- ablkcipher_append_src_dst(desc);
+ skcipher_append_src_dst(desc);
#ifdef DEBUG
print_hex_dump(KERN_ERR,
- "ablkcipher enc shdesc@" __stringify(__LINE__)": ",
+ "skcipher enc shdesc@" __stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
#endif
}
-EXPORT_SYMBOL(cnstr_shdsc_ablkcipher_encap);
+EXPORT_SYMBOL(cnstr_shdsc_skcipher_encap);
/**
- * cnstr_shdsc_ablkcipher_decap - ablkcipher decapsulation shared descriptor
+ * cnstr_shdsc_skcipher_decap - skcipher decapsulation shared descriptor
* @desc: pointer to buffer used for descriptor construction
* @cdata: pointer to block cipher transform definitions
* Valid algorithm values - one of OP_ALG_ALGSEL_{AES, DES, 3DES} ANDed
@@ -1300,9 +1298,9 @@ EXPORT_SYMBOL(cnstr_shdsc_ablkcipher_encap);
* @is_rfc3686: true when ctr(aes) is wrapped by rfc3686 template
* @ctx1_iv_off: IV offset in CONTEXT1 register
*/
-void cnstr_shdsc_ablkcipher_decap(u32 * const desc, struct alginfo *cdata,
- unsigned int ivsize, const bool is_rfc3686,
- const u32 ctx1_iv_off)
+void cnstr_shdsc_skcipher_decap(u32 * const desc, struct alginfo *cdata,
+ unsigned int ivsize, const bool is_rfc3686,
+ const u32 ctx1_iv_off)
{
u32 *key_jump_cmd;
@@ -1348,105 +1346,23 @@ void cnstr_shdsc_ablkcipher_decap(u32 * const desc, struct alginfo *cdata,
append_dec_op1(desc, cdata->algtype);
/* Perform operation */
- ablkcipher_append_src_dst(desc);
-
-#ifdef DEBUG
- print_hex_dump(KERN_ERR,
- "ablkcipher dec shdesc@" __stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
-#endif
-}
-EXPORT_SYMBOL(cnstr_shdsc_ablkcipher_decap);
-
-/**
- * cnstr_shdsc_ablkcipher_givencap - ablkcipher encapsulation shared descriptor
- * with HW-generated initialization vector.
- * @desc: pointer to buffer used for descriptor construction
- * @cdata: pointer to block cipher transform definitions
- * Valid algorithm values - one of OP_ALG_ALGSEL_{AES, DES, 3DES} ANDed
- * with OP_ALG_AAI_CBC.
- * @ivsize: initialization vector size
- * @is_rfc3686: true when ctr(aes) is wrapped by rfc3686 template
- * @ctx1_iv_off: IV offset in CONTEXT1 register
- */
-void cnstr_shdsc_ablkcipher_givencap(u32 * const desc, struct alginfo *cdata,
- unsigned int ivsize, const bool is_rfc3686,
- const u32 ctx1_iv_off)
-{
- u32 *key_jump_cmd, geniv;
-
- init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX);
- /* Skip if already shared */
- key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
- JUMP_COND_SHRD);
-
- /* Load class1 key only */
- append_key_as_imm(desc, cdata->key_virt, cdata->keylen,
- cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG);
-
- /* Load Nonce into CONTEXT1 reg */
- if (is_rfc3686) {
- const u8 *nonce = cdata->key_virt + cdata->keylen;
-
- append_load_as_imm(desc, nonce, CTR_RFC3686_NONCE_SIZE,
- LDST_CLASS_IND_CCB |
- LDST_SRCDST_BYTE_OUTFIFO | LDST_IMM);
- append_move(desc, MOVE_WAITCOMP | MOVE_SRC_OUTFIFO |
- MOVE_DEST_CLASS1CTX | (16 << MOVE_OFFSET_SHIFT) |
- (CTR_RFC3686_NONCE_SIZE << MOVE_LEN_SHIFT));
- }
- set_jump_tgt_here(desc, key_jump_cmd);
-
- /* Generate IV */
- geniv = NFIFOENTRY_STYPE_PAD | NFIFOENTRY_DEST_DECO |
- NFIFOENTRY_DTYPE_MSG | NFIFOENTRY_LC1 | NFIFOENTRY_PTYPE_RND |
- (ivsize << NFIFOENTRY_DLEN_SHIFT);
- append_load_imm_u32(desc, geniv, LDST_CLASS_IND_CCB |
- LDST_SRCDST_WORD_INFO_FIFO | LDST_IMM);
- append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO);
- append_move(desc, MOVE_WAITCOMP | MOVE_SRC_INFIFO |
- MOVE_DEST_CLASS1CTX | (ivsize << MOVE_LEN_SHIFT) |
- (ctx1_iv_off << MOVE_OFFSET_SHIFT));
- append_cmd(desc, CMD_LOAD | ENABLE_AUTO_INFO_FIFO);
-
- /* Copy generated IV to memory */
- append_seq_store(desc, ivsize, LDST_SRCDST_BYTE_CONTEXT |
- LDST_CLASS_1_CCB | (ctx1_iv_off << LDST_OFFSET_SHIFT));
-
- /* Load Counter into CONTEXT1 reg */
- if (is_rfc3686)
- append_load_imm_be32(desc, 1, LDST_IMM | LDST_CLASS_1_CCB |
- LDST_SRCDST_BYTE_CONTEXT |
- ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) <<
- LDST_OFFSET_SHIFT));
-
- if (ctx1_iv_off)
- append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_NCP |
- (1 << JUMP_OFFSET_SHIFT));
-
- /* Load operation */
- append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL |
- OP_ALG_ENCRYPT);
-
- /* Perform operation */
- ablkcipher_append_src_dst(desc);
+ skcipher_append_src_dst(desc);
#ifdef DEBUG
print_hex_dump(KERN_ERR,
- "ablkcipher givenc shdesc@" __stringify(__LINE__) ": ",
+ "skcipher dec shdesc@" __stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
#endif
}
-EXPORT_SYMBOL(cnstr_shdsc_ablkcipher_givencap);
+EXPORT_SYMBOL(cnstr_shdsc_skcipher_decap);
/**
- * cnstr_shdsc_xts_ablkcipher_encap - xts ablkcipher encapsulation shared
- * descriptor
+ * cnstr_shdsc_xts_skcipher_encap - xts skcipher encapsulation shared descriptor
* @desc: pointer to buffer used for descriptor construction
* @cdata: pointer to block cipher transform definitions
* Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_XTS.
*/
-void cnstr_shdsc_xts_ablkcipher_encap(u32 * const desc, struct alginfo *cdata)
+void cnstr_shdsc_xts_skcipher_encap(u32 * const desc, struct alginfo *cdata)
{
__be64 sector_size = cpu_to_be64(512);
u32 *key_jump_cmd;
@@ -1481,24 +1397,23 @@ void cnstr_shdsc_xts_ablkcipher_encap(u32 * const desc, struct alginfo *cdata)
OP_ALG_ENCRYPT);
/* Perform operation */
- ablkcipher_append_src_dst(desc);
+ skcipher_append_src_dst(desc);
#ifdef DEBUG
print_hex_dump(KERN_ERR,
- "xts ablkcipher enc shdesc@" __stringify(__LINE__) ": ",
+ "xts skcipher enc shdesc@" __stringify(__LINE__) ": ",
DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
#endif
}
-EXPORT_SYMBOL(cnstr_shdsc_xts_ablkcipher_encap);
+EXPORT_SYMBOL(cnstr_shdsc_xts_skcipher_encap);
/**
- * cnstr_shdsc_xts_ablkcipher_decap - xts ablkcipher decapsulation shared
- * descriptor
+ * cnstr_shdsc_xts_skcipher_decap - xts skcipher decapsulation shared descriptor
* @desc: pointer to buffer used for descriptor construction
* @cdata: pointer to block cipher transform definitions
* Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_XTS.
*/
-void cnstr_shdsc_xts_ablkcipher_decap(u32 * const desc, struct alginfo *cdata)
+void cnstr_shdsc_xts_skcipher_decap(u32 * const desc, struct alginfo *cdata)
{
__be64 sector_size = cpu_to_be64(512);
u32 *key_jump_cmd;
@@ -1532,15 +1447,15 @@ void cnstr_shdsc_xts_ablkcipher_decap(u32 * const desc, struct alginfo *cdata)
append_dec_op1(desc, cdata->algtype);
/* Perform operation */
- ablkcipher_append_src_dst(desc);
+ skcipher_append_src_dst(desc);
#ifdef DEBUG
print_hex_dump(KERN_ERR,
- "xts ablkcipher dec shdesc@" __stringify(__LINE__) ": ",
+ "xts skcipher dec shdesc@" __stringify(__LINE__) ": ",
DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
#endif
}
-EXPORT_SYMBOL(cnstr_shdsc_xts_ablkcipher_decap);
+EXPORT_SYMBOL(cnstr_shdsc_xts_skcipher_decap);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("FSL CAAM descriptor support");
diff --git a/drivers/crypto/caam/caamalg_desc.h b/drivers/crypto/caam/caamalg_desc.h
index a917af5776ce..1315c8f6f951 100644
--- a/drivers/crypto/caam/caamalg_desc.h
+++ b/drivers/crypto/caam/caamalg_desc.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
- * Shared descriptors for aead, ablkcipher algorithms
+ * Shared descriptors for aead, skcipher algorithms
*
* Copyright 2016 NXP
*/
@@ -42,10 +42,10 @@
#define DESC_QI_RFC4543_ENC_LEN (DESC_RFC4543_ENC_LEN + 4 * CAAM_CMD_SZ)
#define DESC_QI_RFC4543_DEC_LEN (DESC_RFC4543_DEC_LEN + 4 * CAAM_CMD_SZ)
-#define DESC_ABLKCIPHER_BASE (3 * CAAM_CMD_SZ)
-#define DESC_ABLKCIPHER_ENC_LEN (DESC_ABLKCIPHER_BASE + \
+#define DESC_SKCIPHER_BASE (3 * CAAM_CMD_SZ)
+#define DESC_SKCIPHER_ENC_LEN (DESC_SKCIPHER_BASE + \
20 * CAAM_CMD_SZ)
-#define DESC_ABLKCIPHER_DEC_LEN (DESC_ABLKCIPHER_BASE + \
+#define DESC_SKCIPHER_DEC_LEN (DESC_SKCIPHER_BASE + \
15 * CAAM_CMD_SZ)
void cnstr_shdsc_aead_null_encap(u32 * const desc, struct alginfo *adata,
@@ -96,20 +96,16 @@ void cnstr_shdsc_rfc4543_decap(u32 * const desc, struct alginfo *cdata,
unsigned int ivsize, unsigned int icvsize,
const bool is_qi);
-void cnstr_shdsc_ablkcipher_encap(u32 * const desc, struct alginfo *cdata,
- unsigned int ivsize, const bool is_rfc3686,
- const u32 ctx1_iv_off);
+void cnstr_shdsc_skcipher_encap(u32 * const desc, struct alginfo *cdata,
+ unsigned int ivsize, const bool is_rfc3686,
+ const u32 ctx1_iv_off);
-void cnstr_shdsc_ablkcipher_decap(u32 * const desc, struct alginfo *cdata,
- unsigned int ivsize, const bool is_rfc3686,
- const u32 ctx1_iv_off);
+void cnstr_shdsc_skcipher_decap(u32 * const desc, struct alginfo *cdata,
+ unsigned int ivsize, const bool is_rfc3686,
+ const u32 ctx1_iv_off);
-void cnstr_shdsc_ablkcipher_givencap(u32 * const desc, struct alginfo *cdata,
- unsigned int ivsize, const bool is_rfc3686,
- const u32 ctx1_iv_off);
+void cnstr_shdsc_xts_skcipher_encap(u32 * const desc, struct alginfo *cdata);
-void cnstr_shdsc_xts_ablkcipher_encap(u32 * const desc, struct alginfo *cdata);
-
-void cnstr_shdsc_xts_ablkcipher_decap(u32 * const desc, struct alginfo *cdata);
+void cnstr_shdsc_xts_skcipher_decap(u32 * const desc, struct alginfo *cdata);
#endif /* _CAAMALG_DESC_H_ */
diff --git a/drivers/crypto/caam/caamalg_qi.c b/drivers/crypto/caam/caamalg_qi.c
index d7aa7d7ff102..23c9fc4975f8 100644
--- a/drivers/crypto/caam/caamalg_qi.c
+++ b/drivers/crypto/caam/caamalg_qi.c
@@ -1,9 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Freescale FSL CAAM support for crypto API over QI backend.
* Based on caamalg.c
*
* Copyright 2013-2016 Freescale Semiconductor, Inc.
- * Copyright 2016-2017 NXP
+ * Copyright 2016-2018 NXP
*/
#include "compat.h"
@@ -43,6 +44,12 @@ struct caam_aead_alg {
bool registered;
};
+struct caam_skcipher_alg {
+ struct skcipher_alg skcipher;
+ struct caam_alg_entry caam;
+ bool registered;
+};
+
/*
* per-session context
*/
@@ -50,7 +57,6 @@ struct caam_ctx {
struct device *jrdev;
u32 sh_desc_enc[DESC_MAX_USED_LEN];
u32 sh_desc_dec[DESC_MAX_USED_LEN];
- u32 sh_desc_givenc[DESC_MAX_USED_LEN];
u8 key[CAAM_MAX_KEY_SIZE];
dma_addr_t key_dma;
enum dma_data_direction dir;
@@ -589,18 +595,19 @@ static int rfc4543_setkey(struct crypto_aead *aead,
return 0;
}
-static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher,
- const u8 *key, unsigned int keylen)
+static int skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key,
+ unsigned int keylen)
{
- struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher);
- struct crypto_tfm *tfm = crypto_ablkcipher_tfm(ablkcipher);
- const char *alg_name = crypto_tfm_alg_name(tfm);
+ struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
+ struct caam_skcipher_alg *alg =
+ container_of(crypto_skcipher_alg(skcipher), typeof(*alg),
+ skcipher);
struct device *jrdev = ctx->jrdev;
- unsigned int ivsize = crypto_ablkcipher_ivsize(ablkcipher);
+ unsigned int ivsize = crypto_skcipher_ivsize(skcipher);
u32 ctx1_iv_off = 0;
const bool ctr_mode = ((ctx->cdata.algtype & OP_ALG_AAI_MASK) ==
OP_ALG_AAI_CTR_MOD128);
- const bool is_rfc3686 = (ctr_mode && strstr(alg_name, "rfc3686"));
+ const bool is_rfc3686 = alg->caam.rfc3686;
int ret = 0;
#ifdef DEBUG
@@ -629,13 +636,11 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher,
ctx->cdata.key_virt = key;
ctx->cdata.key_inline = true;
- /* ablkcipher encrypt, decrypt, givencrypt shared descriptors */
- cnstr_shdsc_ablkcipher_encap(ctx->sh_desc_enc, &ctx->cdata, ivsize,
- is_rfc3686, ctx1_iv_off);
- cnstr_shdsc_ablkcipher_decap(ctx->sh_desc_dec, &ctx->cdata, ivsize,
- is_rfc3686, ctx1_iv_off);
- cnstr_shdsc_ablkcipher_givencap(ctx->sh_desc_givenc, &ctx->cdata,
- ivsize, is_rfc3686, ctx1_iv_off);
+ /* skcipher encrypt, decrypt shared descriptors */
+ cnstr_shdsc_skcipher_encap(ctx->sh_desc_enc, &ctx->cdata, ivsize,
+ is_rfc3686, ctx1_iv_off);
+ cnstr_shdsc_skcipher_decap(ctx->sh_desc_dec, &ctx->cdata, ivsize,
+ is_rfc3686, ctx1_iv_off);
/* Now update the driver contexts with the new shared descriptor */
if (ctx->drv_ctx[ENCRYPT]) {
@@ -656,25 +661,16 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher,
}
}
- if (ctx->drv_ctx[GIVENCRYPT]) {
- ret = caam_drv_ctx_update(ctx->drv_ctx[GIVENCRYPT],
- ctx->sh_desc_givenc);
- if (ret) {
- dev_err(jrdev, "driver givenc context update failed\n");
- goto badkey;
- }
- }
-
return ret;
badkey:
- crypto_ablkcipher_set_flags(ablkcipher, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ crypto_skcipher_set_flags(skcipher, CRYPTO_TFM_RES_BAD_KEY_LEN);
return -EINVAL;
}
-static int xts_ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher,
- const u8 *key, unsigned int keylen)
+static int xts_skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key,
+ unsigned int keylen)
{
- struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher);
+ struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
struct device *jrdev = ctx->jrdev;
int ret = 0;
@@ -687,9 +683,9 @@ static int xts_ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher,
ctx->cdata.key_virt = key;
ctx->cdata.key_inline = true;
- /* xts ablkcipher encrypt, decrypt shared descriptors */
- cnstr_shdsc_xts_ablkcipher_encap(ctx->sh_desc_enc, &ctx->cdata);
- cnstr_shdsc_xts_ablkcipher_decap(ctx->sh_desc_dec, &ctx->cdata);
+ /* xts skcipher encrypt, decrypt shared descriptors */
+ cnstr_shdsc_xts_skcipher_encap(ctx->sh_desc_enc, &ctx->cdata);
+ cnstr_shdsc_xts_skcipher_decap(ctx->sh_desc_dec, &ctx->cdata);
/* Now update the driver contexts with the new shared descriptor */
if (ctx->drv_ctx[ENCRYPT]) {
@@ -712,7 +708,7 @@ static int xts_ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher,
return ret;
badkey:
- crypto_ablkcipher_set_flags(ablkcipher, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ crypto_skcipher_set_flags(skcipher, CRYPTO_TFM_RES_BAD_KEY_LEN);
return -EINVAL;
}
@@ -741,7 +737,7 @@ struct aead_edesc {
};
/*
- * ablkcipher_edesc - s/w-extended ablkcipher descriptor
+ * skcipher_edesc - s/w-extended skcipher descriptor
* @src_nents: number of segments in input scatterlist
* @dst_nents: number of segments in output scatterlist
* @iv_dma: dma address of iv for checking continuity and link table
@@ -750,7 +746,7 @@ struct aead_edesc {
* @drv_req: driver-specific request structure
* @sgt: the h/w link table, followed by IV
*/
-struct ablkcipher_edesc {
+struct skcipher_edesc {
int src_nents;
int dst_nents;
dma_addr_t iv_dma;
@@ -781,10 +777,8 @@ static struct caam_drv_ctx *get_drv_ctx(struct caam_ctx *ctx,
if (type == ENCRYPT)
desc = ctx->sh_desc_enc;
- else if (type == DECRYPT)
+ else /* (type == DECRYPT) */
desc = ctx->sh_desc_dec;
- else /* (type == GIVENCRYPT) */
- desc = ctx->sh_desc_givenc;
cpu = smp_processor_id();
drv_ctx = caam_drv_ctx_init(ctx->qidev, &cpu, desc);
@@ -803,8 +797,7 @@ static struct caam_drv_ctx *get_drv_ctx(struct caam_ctx *ctx,
static void caam_unmap(struct device *dev, struct scatterlist *src,
struct scatterlist *dst, int src_nents,
int dst_nents, dma_addr_t iv_dma, int ivsize,
- enum optype op_type, dma_addr_t qm_sg_dma,
- int qm_sg_bytes)
+ dma_addr_t qm_sg_dma, int qm_sg_bytes)
{
if (dst != src) {
if (src_nents)
@@ -815,9 +808,7 @@ static void caam_unmap(struct device *dev, struct scatterlist *src,
}
if (iv_dma)
- dma_unmap_single(dev, iv_dma, ivsize,
- op_type == GIVENCRYPT ? DMA_FROM_DEVICE :
- DMA_TO_DEVICE);
+ dma_unmap_single(dev, iv_dma, ivsize, DMA_TO_DEVICE);
if (qm_sg_bytes)
dma_unmap_single(dev, qm_sg_dma, qm_sg_bytes, DMA_TO_DEVICE);
}
@@ -830,21 +821,18 @@ static void aead_unmap(struct device *dev,
int ivsize = crypto_aead_ivsize(aead);
caam_unmap(dev, req->src, req->dst, edesc->src_nents, edesc->dst_nents,
- edesc->iv_dma, ivsize, edesc->drv_req.drv_ctx->op_type,
- edesc->qm_sg_dma, edesc->qm_sg_bytes);
+ edesc->iv_dma, ivsize, edesc->qm_sg_dma, edesc->qm_sg_bytes);
dma_unmap_single(dev, edesc->assoclen_dma, 4, DMA_TO_DEVICE);
}
-static void ablkcipher_unmap(struct device *dev,
- struct ablkcipher_edesc *edesc,
- struct ablkcipher_request *req)
+static void skcipher_unmap(struct device *dev, struct skcipher_edesc *edesc,
+ struct skcipher_request *req)
{
- struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req);
- int ivsize = crypto_ablkcipher_ivsize(ablkcipher);
+ struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
+ int ivsize = crypto_skcipher_ivsize(skcipher);
caam_unmap(dev, req->src, req->dst, edesc->src_nents, edesc->dst_nents,
- edesc->iv_dma, ivsize, edesc->drv_req.drv_ctx->op_type,
- edesc->qm_sg_dma, edesc->qm_sg_bytes);
+ edesc->iv_dma, ivsize, edesc->qm_sg_dma, edesc->qm_sg_bytes);
}
static void aead_done(struct caam_drv_req *drv_req, u32 status)
@@ -902,9 +890,8 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
int in_len, out_len;
struct qm_sg_entry *sg_table, *fd_sgt;
struct caam_drv_ctx *drv_ctx;
- enum optype op_type = encrypt ? ENCRYPT : DECRYPT;
- drv_ctx = get_drv_ctx(ctx, op_type);
+ drv_ctx = get_drv_ctx(ctx, encrypt ? ENCRYPT : DECRYPT);
if (unlikely(IS_ERR_OR_NULL(drv_ctx)))
return (struct aead_edesc *)drv_ctx;
@@ -994,7 +981,7 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
dev_err(qidev, "No space for %d S/G entries and/or %dB IV\n",
qm_sg_ents, ivsize);
caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0,
- 0, 0, 0, 0);
+ 0, 0, 0);
qi_cache_free(edesc);
return ERR_PTR(-ENOMEM);
}
@@ -1009,7 +996,7 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
if (dma_mapping_error(qidev, iv_dma)) {
dev_err(qidev, "unable to map IV\n");
caam_unmap(qidev, req->src, req->dst, src_nents,
- dst_nents, 0, 0, 0, 0, 0);
+ dst_nents, 0, 0, 0, 0);
qi_cache_free(edesc);
return ERR_PTR(-ENOMEM);
}
@@ -1028,7 +1015,7 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
if (dma_mapping_error(qidev, edesc->assoclen_dma)) {
dev_err(qidev, "unable to map assoclen\n");
caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents,
- iv_dma, ivsize, op_type, 0, 0);
+ iv_dma, ivsize, 0, 0);
qi_cache_free(edesc);
return ERR_PTR(-ENOMEM);
}
@@ -1051,7 +1038,7 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
dev_err(qidev, "unable to map S/G table\n");
dma_unmap_single(qidev, edesc->assoclen_dma, 4, DMA_TO_DEVICE);
caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents,
- iv_dma, ivsize, op_type, 0, 0);
+ iv_dma, ivsize, 0, 0);
qi_cache_free(edesc);
return ERR_PTR(-ENOMEM);
}
@@ -1138,14 +1125,14 @@ static int ipsec_gcm_decrypt(struct aead_request *req)
return aead_crypt(req, false);
}
-static void ablkcipher_done(struct caam_drv_req *drv_req, u32 status)
+static void skcipher_done(struct caam_drv_req *drv_req, u32 status)
{
- struct ablkcipher_edesc *edesc;
- struct ablkcipher_request *req = drv_req->app_ctx;
- struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req);
- struct caam_ctx *caam_ctx = crypto_ablkcipher_ctx(ablkcipher);
+ struct skcipher_edesc *edesc;
+ struct skcipher_request *req = drv_req->app_ctx;
+ struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
+ struct caam_ctx *caam_ctx = crypto_skcipher_ctx(skcipher);
struct device *qidev = caam_ctx->qidev;
- int ivsize = crypto_ablkcipher_ivsize(ablkcipher);
+ int ivsize = crypto_skcipher_ivsize(skcipher);
#ifdef DEBUG
dev_err(qidev, "%s %d: status 0x%x\n", __func__, __LINE__, status);
@@ -1158,72 +1145,60 @@ static void ablkcipher_done(struct caam_drv_req *drv_req, u32 status)
#ifdef DEBUG
print_hex_dump(KERN_ERR, "dstiv @" __stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, req->info,
+ DUMP_PREFIX_ADDRESS, 16, 4, req->iv,
edesc->src_nents > 1 ? 100 : ivsize, 1);
caam_dump_sg(KERN_ERR, "dst @" __stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, req->dst,
- edesc->dst_nents > 1 ? 100 : req->nbytes, 1);
+ edesc->dst_nents > 1 ? 100 : req->cryptlen, 1);
#endif
- ablkcipher_unmap(qidev, edesc, req);
-
- /* In case initial IV was generated, copy it in GIVCIPHER request */
- if (edesc->drv_req.drv_ctx->op_type == GIVENCRYPT) {
- u8 *iv;
- struct skcipher_givcrypt_request *greq;
-
- greq = container_of(req, struct skcipher_givcrypt_request,
- creq);
- iv = (u8 *)edesc->sgt + edesc->qm_sg_bytes;
- memcpy(greq->giv, iv, ivsize);
- }
+ skcipher_unmap(qidev, edesc, req);
/*
- * The crypto API expects us to set the IV (req->info) to the last
+ * The crypto API expects us to set the IV (req->iv) to the last
* ciphertext block. This is used e.g. by the CTS mode.
*/
- if (edesc->drv_req.drv_ctx->op_type != DECRYPT)
- scatterwalk_map_and_copy(req->info, req->dst, req->nbytes -
+ if (edesc->drv_req.drv_ctx->op_type == ENCRYPT)
+ scatterwalk_map_and_copy(req->iv, req->dst, req->cryptlen -
ivsize, ivsize, 0);
qi_cache_free(edesc);
- ablkcipher_request_complete(req, status);
+ skcipher_request_complete(req, status);
}
-static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request
- *req, bool encrypt)
+static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req,
+ bool encrypt)
{
- struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req);
- struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher);
+ struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
+ struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
struct device *qidev = ctx->qidev;
gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
GFP_KERNEL : GFP_ATOMIC;
int src_nents, mapped_src_nents, dst_nents = 0, mapped_dst_nents = 0;
- struct ablkcipher_edesc *edesc;
+ struct skcipher_edesc *edesc;
dma_addr_t iv_dma;
u8 *iv;
- int ivsize = crypto_ablkcipher_ivsize(ablkcipher);
+ int ivsize = crypto_skcipher_ivsize(skcipher);
int dst_sg_idx, qm_sg_ents, qm_sg_bytes;
struct qm_sg_entry *sg_table, *fd_sgt;
struct caam_drv_ctx *drv_ctx;
- enum optype op_type = encrypt ? ENCRYPT : DECRYPT;
- drv_ctx = get_drv_ctx(ctx, op_type);
+ drv_ctx = get_drv_ctx(ctx, encrypt ? ENCRYPT : DECRYPT);
if (unlikely(IS_ERR_OR_NULL(drv_ctx)))
- return (struct ablkcipher_edesc *)drv_ctx;
+ return (struct skcipher_edesc *)drv_ctx;
- src_nents = sg_nents_for_len(req->src, req->nbytes);
+ src_nents = sg_nents_for_len(req->src, req->cryptlen);
if (unlikely(src_nents < 0)) {
dev_err(qidev, "Insufficient bytes (%d) in src S/G\n",
- req->nbytes);
+ req->cryptlen);
return ERR_PTR(src_nents);
}
if (unlikely(req->src != req->dst)) {
- dst_nents = sg_nents_for_len(req->dst, req->nbytes);
+ dst_nents = sg_nents_for_len(req->dst, req->cryptlen);
if (unlikely(dst_nents < 0)) {
dev_err(qidev, "Insufficient bytes (%d) in dst S/G\n",
- req->nbytes);
+ req->cryptlen);
return ERR_PTR(dst_nents);
}
@@ -1255,12 +1230,12 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request
qm_sg_ents += mapped_dst_nents > 1 ? mapped_dst_nents : 0;
qm_sg_bytes = qm_sg_ents * sizeof(struct qm_sg_entry);
- if (unlikely(offsetof(struct ablkcipher_edesc, sgt) + qm_sg_bytes +
+ if (unlikely(offsetof(struct skcipher_edesc, sgt) + qm_sg_bytes +
ivsize > CAAM_QI_MEMCACHE_SIZE)) {
dev_err(qidev, "No space for %d S/G entries and/or %dB IV\n",
qm_sg_ents, ivsize);
caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0,
- 0, 0, 0, 0);
+ 0, 0, 0);
return ERR_PTR(-ENOMEM);
}
@@ -1269,20 +1244,20 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request
if (unlikely(!edesc)) {
dev_err(qidev, "could not allocate extended descriptor\n");
caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0,
- 0, 0, 0, 0);
+ 0, 0, 0);
return ERR_PTR(-ENOMEM);
}
/* Make sure IV is located in a DMAable area */
sg_table = &edesc->sgt[0];
iv = (u8 *)(sg_table + qm_sg_ents);
- memcpy(iv, req->info, ivsize);
+ memcpy(iv, req->iv, ivsize);
iv_dma = dma_map_single(qidev, iv, ivsize, DMA_TO_DEVICE);
if (dma_mapping_error(qidev, iv_dma)) {
dev_err(qidev, "unable to map IV\n");
caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0,
- 0, 0, 0, 0);
+ 0, 0, 0);
qi_cache_free(edesc);
return ERR_PTR(-ENOMEM);
}
@@ -1292,7 +1267,7 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request
edesc->iv_dma = iv_dma;
edesc->qm_sg_bytes = qm_sg_bytes;
edesc->drv_req.app_ctx = req;
- edesc->drv_req.cbk = ablkcipher_done;
+ edesc->drv_req.cbk = skcipher_done;
edesc->drv_req.drv_ctx = drv_ctx;
dma_to_qm_sg_one(sg_table, iv_dma, ivsize, 0);
@@ -1307,7 +1282,7 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request
if (dma_mapping_error(qidev, edesc->qm_sg_dma)) {
dev_err(qidev, "unable to map S/G table\n");
caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents,
- iv_dma, ivsize, op_type, 0, 0);
+ iv_dma, ivsize, 0, 0);
qi_cache_free(edesc);
return ERR_PTR(-ENOMEM);
}
@@ -1315,348 +1290,172 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request
fd_sgt = &edesc->drv_req.fd_sgt[0];
dma_to_qm_sg_one_last_ext(&fd_sgt[1], edesc->qm_sg_dma,
- ivsize + req->nbytes, 0);
+ ivsize + req->cryptlen, 0);
if (req->src == req->dst) {
dma_to_qm_sg_one_ext(&fd_sgt[0], edesc->qm_sg_dma +
- sizeof(*sg_table), req->nbytes, 0);
+ sizeof(*sg_table), req->cryptlen, 0);
} else if (mapped_dst_nents > 1) {
dma_to_qm_sg_one_ext(&fd_sgt[0], edesc->qm_sg_dma + dst_sg_idx *
- sizeof(*sg_table), req->nbytes, 0);
+ sizeof(*sg_table), req->cryptlen, 0);
} else {
dma_to_qm_sg_one(&fd_sgt[0], sg_dma_address(req->dst),
- req->nbytes, 0);
- }
-
- return edesc;
-}
-
-static struct ablkcipher_edesc *ablkcipher_giv_edesc_alloc(
- struct skcipher_givcrypt_request *creq)
-{
- struct ablkcipher_request *req = &creq->creq;
- struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req);
- struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher);
- struct device *qidev = ctx->qidev;
- gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
- GFP_KERNEL : GFP_ATOMIC;
- int src_nents, mapped_src_nents, dst_nents, mapped_dst_nents;
- struct ablkcipher_edesc *edesc;
- dma_addr_t iv_dma;
- u8 *iv;
- int ivsize = crypto_ablkcipher_ivsize(ablkcipher);
- struct qm_sg_entry *sg_table, *fd_sgt;
- int dst_sg_idx, qm_sg_ents, qm_sg_bytes;
- struct caam_drv_ctx *drv_ctx;
-
- drv_ctx = get_drv_ctx(ctx, GIVENCRYPT);
- if (unlikely(IS_ERR_OR_NULL(drv_ctx)))
- return (struct ablkcipher_edesc *)drv_ctx;
-
- src_nents = sg_nents_for_len(req->src, req->nbytes);
- if (unlikely(src_nents < 0)) {
- dev_err(qidev, "Insufficient bytes (%d) in src S/G\n",
- req->nbytes);
- return ERR_PTR(src_nents);
- }
-
- if (unlikely(req->src != req->dst)) {
- dst_nents = sg_nents_for_len(req->dst, req->nbytes);
- if (unlikely(dst_nents < 0)) {
- dev_err(qidev, "Insufficient bytes (%d) in dst S/G\n",
- req->nbytes);
- return ERR_PTR(dst_nents);
- }
-
- mapped_src_nents = dma_map_sg(qidev, req->src, src_nents,
- DMA_TO_DEVICE);
- if (unlikely(!mapped_src_nents)) {
- dev_err(qidev, "unable to map source\n");
- return ERR_PTR(-ENOMEM);
- }
-
- mapped_dst_nents = dma_map_sg(qidev, req->dst, dst_nents,
- DMA_FROM_DEVICE);
- if (unlikely(!mapped_dst_nents)) {
- dev_err(qidev, "unable to map destination\n");
- dma_unmap_sg(qidev, req->src, src_nents, DMA_TO_DEVICE);
- return ERR_PTR(-ENOMEM);
- }
- } else {
- mapped_src_nents = dma_map_sg(qidev, req->src, src_nents,
- DMA_BIDIRECTIONAL);
- if (unlikely(!mapped_src_nents)) {
- dev_err(qidev, "unable to map source\n");
- return ERR_PTR(-ENOMEM);
- }
-
- dst_nents = src_nents;
- mapped_dst_nents = src_nents;
- }
-
- qm_sg_ents = mapped_src_nents > 1 ? mapped_src_nents : 0;
- dst_sg_idx = qm_sg_ents;
-
- qm_sg_ents += 1 + mapped_dst_nents;
- qm_sg_bytes = qm_sg_ents * sizeof(struct qm_sg_entry);
- if (unlikely(offsetof(struct ablkcipher_edesc, sgt) + qm_sg_bytes +
- ivsize > CAAM_QI_MEMCACHE_SIZE)) {
- dev_err(qidev, "No space for %d S/G entries and/or %dB IV\n",
- qm_sg_ents, ivsize);
- caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0,
- 0, 0, 0, 0);
- return ERR_PTR(-ENOMEM);
- }
-
- /* allocate space for base edesc, link tables and IV */
- edesc = qi_cache_alloc(GFP_DMA | flags);
- if (!edesc) {
- dev_err(qidev, "could not allocate extended descriptor\n");
- caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0,
- 0, 0, 0, 0);
- return ERR_PTR(-ENOMEM);
- }
-
- /* Make sure IV is located in a DMAable area */
- sg_table = &edesc->sgt[0];
- iv = (u8 *)(sg_table + qm_sg_ents);
- iv_dma = dma_map_single(qidev, iv, ivsize, DMA_FROM_DEVICE);
- if (dma_mapping_error(qidev, iv_dma)) {
- dev_err(qidev, "unable to map IV\n");
- caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0,
- 0, 0, 0, 0);
- qi_cache_free(edesc);
- return ERR_PTR(-ENOMEM);
- }
-
- edesc->src_nents = src_nents;
- edesc->dst_nents = dst_nents;
- edesc->iv_dma = iv_dma;
- edesc->qm_sg_bytes = qm_sg_bytes;
- edesc->drv_req.app_ctx = req;
- edesc->drv_req.cbk = ablkcipher_done;
- edesc->drv_req.drv_ctx = drv_ctx;
-
- if (mapped_src_nents > 1)
- sg_to_qm_sg_last(req->src, mapped_src_nents, sg_table, 0);
-
- dma_to_qm_sg_one(sg_table + dst_sg_idx, iv_dma, ivsize, 0);
- sg_to_qm_sg_last(req->dst, mapped_dst_nents, sg_table + dst_sg_idx + 1,
- 0);
-
- edesc->qm_sg_dma = dma_map_single(qidev, sg_table, edesc->qm_sg_bytes,
- DMA_TO_DEVICE);
- if (dma_mapping_error(qidev, edesc->qm_sg_dma)) {
- dev_err(qidev, "unable to map S/G table\n");
- caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents,
- iv_dma, ivsize, GIVENCRYPT, 0, 0);
- qi_cache_free(edesc);
- return ERR_PTR(-ENOMEM);
+ req->cryptlen, 0);
}
- fd_sgt = &edesc->drv_req.fd_sgt[0];
-
- if (mapped_src_nents > 1)
- dma_to_qm_sg_one_ext(&fd_sgt[1], edesc->qm_sg_dma, req->nbytes,
- 0);
- else
- dma_to_qm_sg_one(&fd_sgt[1], sg_dma_address(req->src),
- req->nbytes, 0);
-
- dma_to_qm_sg_one_ext(&fd_sgt[0], edesc->qm_sg_dma + dst_sg_idx *
- sizeof(*sg_table), ivsize + req->nbytes, 0);
-
return edesc;
}
-static inline int ablkcipher_crypt(struct ablkcipher_request *req, bool encrypt)
+static inline int skcipher_crypt(struct skcipher_request *req, bool encrypt)
{
- struct ablkcipher_edesc *edesc;
- struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req);
- struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher);
- int ivsize = crypto_ablkcipher_ivsize(ablkcipher);
+ struct skcipher_edesc *edesc;
+ struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
+ struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
+ int ivsize = crypto_skcipher_ivsize(skcipher);
int ret;
if (unlikely(caam_congested))
return -EAGAIN;
/* allocate extended descriptor */
- edesc = ablkcipher_edesc_alloc(req, encrypt);
+ edesc = skcipher_edesc_alloc(req, encrypt);
if (IS_ERR(edesc))
return PTR_ERR(edesc);
/*
- * The crypto API expects us to set the IV (req->info) to the last
+ * The crypto API expects us to set the IV (req->iv) to the last
* ciphertext block.
*/
if (!encrypt)
- scatterwalk_map_and_copy(req->info, req->src, req->nbytes -
+ scatterwalk_map_and_copy(req->iv, req->src, req->cryptlen -
ivsize, ivsize, 0);
ret = caam_qi_enqueue(ctx->qidev, &edesc->drv_req);
if (!ret) {
ret = -EINPROGRESS;
} else {
- ablkcipher_unmap(ctx->qidev, edesc, req);
+ skcipher_unmap(ctx->qidev, edesc, req);
qi_cache_free(edesc);
}
return ret;
}
-static int ablkcipher_encrypt(struct ablkcipher_request *req)
+static int skcipher_encrypt(struct skcipher_request *req)
{
- return ablkcipher_crypt(req, true);
+ return skcipher_crypt(req, true);
}
-static int ablkcipher_decrypt(struct ablkcipher_request *req)
+static int skcipher_decrypt(struct skcipher_request *req)
{
- return ablkcipher_crypt(req, false);
-}
-
-static int ablkcipher_givencrypt(struct skcipher_givcrypt_request *creq)
-{
- struct ablkcipher_request *req = &creq->creq;
- struct ablkcipher_edesc *edesc;
- struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req);
- struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher);
- int ret;
-
- if (unlikely(caam_congested))
- return -EAGAIN;
-
- /* allocate extended descriptor */
- edesc = ablkcipher_giv_edesc_alloc(creq);
- if (IS_ERR(edesc))
- return PTR_ERR(edesc);
-
- ret = caam_qi_enqueue(ctx->qidev, &edesc->drv_req);
- if (!ret) {
- ret = -EINPROGRESS;
- } else {
- ablkcipher_unmap(ctx->qidev, edesc, req);
- qi_cache_free(edesc);
- }
-
- return ret;
+ return skcipher_crypt(req, false);
}
-#define template_ablkcipher template_u.ablkcipher
-struct caam_alg_template {
- char name[CRYPTO_MAX_ALG_NAME];
- char driver_name[CRYPTO_MAX_ALG_NAME];
- unsigned int blocksize;
- u32 type;
- union {
- struct ablkcipher_alg ablkcipher;
- } template_u;
- u32 class1_alg_type;
- u32 class2_alg_type;
-};
-
-static struct caam_alg_template driver_algs[] = {
- /* ablkcipher descriptor */
+static struct caam_skcipher_alg driver_algs[] = {
{
- .name = "cbc(aes)",
- .driver_name = "cbc-aes-caam-qi",
- .blocksize = AES_BLOCK_SIZE,
- .type = CRYPTO_ALG_TYPE_GIVCIPHER,
- .template_ablkcipher = {
- .setkey = ablkcipher_setkey,
- .encrypt = ablkcipher_encrypt,
- .decrypt = ablkcipher_decrypt,
- .givencrypt = ablkcipher_givencrypt,
- .geniv = "<built-in>",
+ .skcipher = {
+ .base = {
+ .cra_name = "cbc(aes)",
+ .cra_driver_name = "cbc-aes-caam-qi",
+ .cra_blocksize = AES_BLOCK_SIZE,
+ },
+ .setkey = skcipher_setkey,
+ .encrypt = skcipher_encrypt,
+ .decrypt = skcipher_decrypt,
.min_keysize = AES_MIN_KEY_SIZE,
.max_keysize = AES_MAX_KEY_SIZE,
.ivsize = AES_BLOCK_SIZE,
},
- .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
+ .caam.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
},
{
- .name = "cbc(des3_ede)",
- .driver_name = "cbc-3des-caam-qi",
- .blocksize = DES3_EDE_BLOCK_SIZE,
- .type = CRYPTO_ALG_TYPE_GIVCIPHER,
- .template_ablkcipher = {
- .setkey = ablkcipher_setkey,
- .encrypt = ablkcipher_encrypt,
- .decrypt = ablkcipher_decrypt,
- .givencrypt = ablkcipher_givencrypt,
- .geniv = "<built-in>",
+ .skcipher = {
+ .base = {
+ .cra_name = "cbc(des3_ede)",
+ .cra_driver_name = "cbc-3des-caam-qi",
+ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
+ },
+ .setkey = skcipher_setkey,
+ .encrypt = skcipher_encrypt,
+ .decrypt = skcipher_decrypt,
.min_keysize = DES3_EDE_KEY_SIZE,
.max_keysize = DES3_EDE_KEY_SIZE,
.ivsize = DES3_EDE_BLOCK_SIZE,
},
- .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
+ .caam.class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
},
{
- .name = "cbc(des)",
- .driver_name = "cbc-des-caam-qi",
- .blocksize = DES_BLOCK_SIZE,
- .type = CRYPTO_ALG_TYPE_GIVCIPHER,
- .template_ablkcipher = {
- .setkey = ablkcipher_setkey,
- .encrypt = ablkcipher_encrypt,
- .decrypt = ablkcipher_decrypt,
- .givencrypt = ablkcipher_givencrypt,
- .geniv = "<built-in>",
+ .skcipher = {
+ .base = {
+ .cra_name = "cbc(des)",
+ .cra_driver_name = "cbc-des-caam-qi",
+ .cra_blocksize = DES_BLOCK_SIZE,
+ },
+ .setkey = skcipher_setkey,
+ .encrypt = skcipher_encrypt,
+ .decrypt = skcipher_decrypt,
.min_keysize = DES_KEY_SIZE,
.max_keysize = DES_KEY_SIZE,
.ivsize = DES_BLOCK_SIZE,
},
- .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
+ .caam.class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
},
{
- .name = "ctr(aes)",
- .driver_name = "ctr-aes-caam-qi",
- .blocksize = 1,
- .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
- .template_ablkcipher = {
- .setkey = ablkcipher_setkey,
- .encrypt = ablkcipher_encrypt,
- .decrypt = ablkcipher_decrypt,
- .geniv = "chainiv",
+ .skcipher = {
+ .base = {
+ .cra_name = "ctr(aes)",
+ .cra_driver_name = "ctr-aes-caam-qi",
+ .cra_blocksize = 1,
+ },
+ .setkey = skcipher_setkey,
+ .encrypt = skcipher_encrypt,
+ .decrypt = skcipher_decrypt,
.min_keysize = AES_MIN_KEY_SIZE,
.max_keysize = AES_MAX_KEY_SIZE,
.ivsize = AES_BLOCK_SIZE,
+ .chunksize = AES_BLOCK_SIZE,
},
- .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CTR_MOD128,
+ .caam.class1_alg_type = OP_ALG_ALGSEL_AES |
+ OP_ALG_AAI_CTR_MOD128,
},
{
- .name = "rfc3686(ctr(aes))",
- .driver_name = "rfc3686-ctr-aes-caam-qi",
- .blocksize = 1,
- .type = CRYPTO_ALG_TYPE_GIVCIPHER,
- .template_ablkcipher = {
- .setkey = ablkcipher_setkey,
- .encrypt = ablkcipher_encrypt,
- .decrypt = ablkcipher_decrypt,
- .givencrypt = ablkcipher_givencrypt,
- .geniv = "<built-in>",
+ .skcipher = {
+ .base = {
+ .cra_name = "rfc3686(ctr(aes))",
+ .cra_driver_name = "rfc3686-ctr-aes-caam-qi",
+ .cra_blocksize = 1,
+ },
+ .setkey = skcipher_setkey,
+ .encrypt = skcipher_encrypt,
+ .decrypt = skcipher_decrypt,
.min_keysize = AES_MIN_KEY_SIZE +
CTR_RFC3686_NONCE_SIZE,
.max_keysize = AES_MAX_KEY_SIZE +
CTR_RFC3686_NONCE_SIZE,
.ivsize = CTR_RFC3686_IV_SIZE,
+ .chunksize = AES_BLOCK_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_AES |
+ OP_ALG_AAI_CTR_MOD128,
+ .rfc3686 = true,
},
- .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CTR_MOD128,
},
{
- .name = "xts(aes)",
- .driver_name = "xts-aes-caam-qi",
- .blocksize = AES_BLOCK_SIZE,
- .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
- .template_ablkcipher = {
- .setkey = xts_ablkcipher_setkey,
- .encrypt = ablkcipher_encrypt,
- .decrypt = ablkcipher_decrypt,
- .geniv = "eseqiv",
+ .skcipher = {
+ .base = {
+ .cra_name = "xts(aes)",
+ .cra_driver_name = "xts-aes-caam-qi",
+ .cra_blocksize = AES_BLOCK_SIZE,
+ },
+ .setkey = xts_skcipher_setkey,
+ .encrypt = skcipher_encrypt,
+ .decrypt = skcipher_decrypt,
.min_keysize = 2 * AES_MIN_KEY_SIZE,
.max_keysize = 2 * AES_MAX_KEY_SIZE,
.ivsize = AES_BLOCK_SIZE,
},
- .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_XTS,
+ .caam.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_XTS,
},
};
@@ -2528,12 +2327,6 @@ static struct caam_aead_alg driver_aeads[] = {
},
};
-struct caam_crypto_alg {
- struct list_head entry;
- struct crypto_alg crypto_alg;
- struct caam_alg_entry caam;
-};
-
static int caam_init_common(struct caam_ctx *ctx, struct caam_alg_entry *caam,
bool uses_dkp)
{
@@ -2572,19 +2365,18 @@ static int caam_init_common(struct caam_ctx *ctx, struct caam_alg_entry *caam,
spin_lock_init(&ctx->lock);
ctx->drv_ctx[ENCRYPT] = NULL;
ctx->drv_ctx[DECRYPT] = NULL;
- ctx->drv_ctx[GIVENCRYPT] = NULL;
return 0;
}
-static int caam_cra_init(struct crypto_tfm *tfm)
+static int caam_cra_init(struct crypto_skcipher *tfm)
{
- struct crypto_alg *alg = tfm->__crt_alg;
- struct caam_crypto_alg *caam_alg = container_of(alg, typeof(*caam_alg),
- crypto_alg);
- struct caam_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
+ struct caam_skcipher_alg *caam_alg =
+ container_of(alg, typeof(*caam_alg), skcipher);
- return caam_init_common(ctx, &caam_alg->caam, false);
+ return caam_init_common(crypto_skcipher_ctx(tfm), &caam_alg->caam,
+ false);
}
static int caam_aead_init(struct crypto_aead *tfm)
@@ -2602,16 +2394,15 @@ static void caam_exit_common(struct caam_ctx *ctx)
{
caam_drv_ctx_rel(ctx->drv_ctx[ENCRYPT]);
caam_drv_ctx_rel(ctx->drv_ctx[DECRYPT]);
- caam_drv_ctx_rel(ctx->drv_ctx[GIVENCRYPT]);
dma_unmap_single(ctx->jrdev, ctx->key_dma, sizeof(ctx->key), ctx->dir);
caam_jr_free(ctx->jrdev);
}
-static void caam_cra_exit(struct crypto_tfm *tfm)
+static void caam_cra_exit(struct crypto_skcipher *tfm)
{
- caam_exit_common(crypto_tfm_ctx(tfm));
+ caam_exit_common(crypto_skcipher_ctx(tfm));
}
static void caam_aead_exit(struct crypto_aead *tfm)
@@ -2619,10 +2410,8 @@ static void caam_aead_exit(struct crypto_aead *tfm)
caam_exit_common(crypto_aead_ctx(tfm));
}
-static struct list_head alg_list;
static void __exit caam_qi_algapi_exit(void)
{
- struct caam_crypto_alg *t_alg, *n;
int i;
for (i = 0; i < ARRAY_SIZE(driver_aeads); i++) {
@@ -2632,55 +2421,25 @@ static void __exit caam_qi_algapi_exit(void)
crypto_unregister_aead(&t_alg->aead);
}
- if (!alg_list.next)
- return;
+ for (i = 0; i < ARRAY_SIZE(driver_algs); i++) {
+ struct caam_skcipher_alg *t_alg = driver_algs + i;
- list_for_each_entry_safe(t_alg, n, &alg_list, entry) {
- crypto_unregister_alg(&t_alg->crypto_alg);
- list_del(&t_alg->entry);
- kfree(t_alg);
+ if (t_alg->registered)
+ crypto_unregister_skcipher(&t_alg->skcipher);
}
}
-static struct caam_crypto_alg *caam_alg_alloc(struct caam_alg_template
- *template)
+static void caam_skcipher_alg_init(struct caam_skcipher_alg *t_alg)
{
- struct caam_crypto_alg *t_alg;
- struct crypto_alg *alg;
-
- t_alg = kzalloc(sizeof(*t_alg), GFP_KERNEL);
- if (!t_alg)
- return ERR_PTR(-ENOMEM);
+ struct skcipher_alg *alg = &t_alg->skcipher;
- alg = &t_alg->crypto_alg;
-
- snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s", template->name);
- snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
- template->driver_name);
- alg->cra_module = THIS_MODULE;
- alg->cra_init = caam_cra_init;
- alg->cra_exit = caam_cra_exit;
- alg->cra_priority = CAAM_CRA_PRIORITY;
- alg->cra_blocksize = template->blocksize;
- alg->cra_alignmask = 0;
- alg->cra_ctxsize = sizeof(struct caam_ctx);
- alg->cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY |
- template->type;
- switch (template->type) {
- case CRYPTO_ALG_TYPE_GIVCIPHER:
- alg->cra_type = &crypto_givcipher_type;
- alg->cra_ablkcipher = template->template_ablkcipher;
- break;
- case CRYPTO_ALG_TYPE_ABLKCIPHER:
- alg->cra_type = &crypto_ablkcipher_type;
- alg->cra_ablkcipher = template->template_ablkcipher;
- break;
- }
-
- t_alg->caam.class1_alg_type = template->class1_alg_type;
- t_alg->caam.class2_alg_type = template->class2_alg_type;
+ alg->base.cra_module = THIS_MODULE;
+ alg->base.cra_priority = CAAM_CRA_PRIORITY;
+ alg->base.cra_ctxsize = sizeof(struct caam_ctx);
+ alg->base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY;
- return t_alg;
+ alg->init = caam_cra_init;
+ alg->exit = caam_cra_exit;
}
static void caam_aead_alg_init(struct caam_aead_alg *t_alg)
@@ -2734,8 +2493,6 @@ static int __init caam_qi_algapi_init(void)
return -ENODEV;
}
- INIT_LIST_HEAD(&alg_list);
-
/*
* Register crypto algorithms the device supports.
* First, detect presence and attributes of DES, AES, and MD blocks.
@@ -2751,9 +2508,8 @@ static int __init caam_qi_algapi_init(void)
md_limit = SHA256_DIGEST_SIZE;
for (i = 0; i < ARRAY_SIZE(driver_algs); i++) {
- struct caam_crypto_alg *t_alg;
- struct caam_alg_template *alg = driver_algs + i;
- u32 alg_sel = alg->class1_alg_type & OP_ALG_ALGSEL_MASK;
+ struct caam_skcipher_alg *t_alg = driver_algs + i;
+ u32 alg_sel = t_alg->caam.class1_alg_type & OP_ALG_ALGSEL_MASK;
/* Skip DES algorithms if not supported by device */
if (!des_inst &&
@@ -2765,23 +2521,16 @@ static int __init caam_qi_algapi_init(void)
if (!aes_inst && (alg_sel == OP_ALG_ALGSEL_AES))
continue;
- t_alg = caam_alg_alloc(alg);
- if (IS_ERR(t_alg)) {
- err = PTR_ERR(t_alg);
- dev_warn(priv->qidev, "%s alg allocation failed\n",
- alg->driver_name);
- continue;
- }
+ caam_skcipher_alg_init(t_alg);
- err = crypto_register_alg(&t_alg->crypto_alg);
+ err = crypto_register_skcipher(&t_alg->skcipher);
if (err) {
dev_warn(priv->qidev, "%s alg registration failed\n",
- t_alg->crypto_alg.cra_driver_name);
- kfree(t_alg);
+ t_alg->skcipher.base.cra_driver_name);
continue;
}
- list_add_tail(&t_alg->entry, &alg_list);
+ t_alg->registered = true;
registered = true;
}
diff --git a/drivers/crypto/caam/caamalg_qi2.c b/drivers/crypto/caam/caamalg_qi2.c
new file mode 100644
index 000000000000..7d8ac0222fa3
--- /dev/null
+++ b/drivers/crypto/caam/caamalg_qi2.c
@@ -0,0 +1,5165 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright 2015-2016 Freescale Semiconductor Inc.
+ * Copyright 2017-2018 NXP
+ */
+
+#include "compat.h"
+#include "regs.h"
+#include "caamalg_qi2.h"
+#include "dpseci_cmd.h"
+#include "desc_constr.h"
+#include "error.h"
+#include "sg_sw_sec4.h"
+#include "sg_sw_qm2.h"
+#include "key_gen.h"
+#include "caamalg_desc.h"
+#include "caamhash_desc.h"
+#include <linux/fsl/mc.h>
+#include <soc/fsl/dpaa2-io.h>
+#include <soc/fsl/dpaa2-fd.h>
+
+#define CAAM_CRA_PRIORITY 2000
+
+/* max key is sum of AES_MAX_KEY_SIZE, max split key size */
+#define CAAM_MAX_KEY_SIZE (AES_MAX_KEY_SIZE + CTR_RFC3686_NONCE_SIZE + \
+ SHA512_DIGEST_SIZE * 2)
+
+#if !IS_ENABLED(CONFIG_CRYPTO_DEV_FSL_CAAM)
+bool caam_little_end;
+EXPORT_SYMBOL(caam_little_end);
+bool caam_imx;
+EXPORT_SYMBOL(caam_imx);
+#endif
+
+/*
+ * This is a a cache of buffers, from which the users of CAAM QI driver
+ * can allocate short buffers. It's speedier than doing kmalloc on the hotpath.
+ * NOTE: A more elegant solution would be to have some headroom in the frames
+ * being processed. This can be added by the dpaa2-eth driver. This would
+ * pose a problem for userspace application processing which cannot
+ * know of this limitation. So for now, this will work.
+ * NOTE: The memcache is SMP-safe. No need to handle spinlocks in-here
+ */
+static struct kmem_cache *qi_cache;
+
+struct caam_alg_entry {
+ struct device *dev;
+ int class1_alg_type;
+ int class2_alg_type;
+ bool rfc3686;
+ bool geniv;
+};
+
+struct caam_aead_alg {
+ struct aead_alg aead;
+ struct caam_alg_entry caam;
+ bool registered;
+};
+
+struct caam_skcipher_alg {
+ struct skcipher_alg skcipher;
+ struct caam_alg_entry caam;
+ bool registered;
+};
+
+/**
+ * caam_ctx - per-session context
+ * @flc: Flow Contexts array
+ * @key: [authentication key], encryption key
+ * @flc_dma: I/O virtual addresses of the Flow Contexts
+ * @key_dma: I/O virtual address of the key
+ * @dir: DMA direction for mapping key and Flow Contexts
+ * @dev: dpseci device
+ * @adata: authentication algorithm details
+ * @cdata: encryption algorithm details
+ * @authsize: authentication tag (a.k.a. ICV / MAC) size
+ */
+struct caam_ctx {
+ struct caam_flc flc[NUM_OP];
+ u8 key[CAAM_MAX_KEY_SIZE];
+ dma_addr_t flc_dma[NUM_OP];
+ dma_addr_t key_dma;
+ enum dma_data_direction dir;
+ struct device *dev;
+ struct alginfo adata;
+ struct alginfo cdata;
+ unsigned int authsize;
+};
+
+static void *dpaa2_caam_iova_to_virt(struct dpaa2_caam_priv *priv,
+ dma_addr_t iova_addr)
+{
+ phys_addr_t phys_addr;
+
+ phys_addr = priv->domain ? iommu_iova_to_phys(priv->domain, iova_addr) :
+ iova_addr;
+
+ return phys_to_virt(phys_addr);
+}
+
+/*
+ * qi_cache_zalloc - Allocate buffers from CAAM-QI cache
+ *
+ * Allocate data on the hotpath. Instead of using kzalloc, one can use the
+ * services of the CAAM QI memory cache (backed by kmem_cache). The buffers
+ * will have a size of CAAM_QI_MEMCACHE_SIZE, which should be sufficient for
+ * hosting 16 SG entries.
+ *
+ * @flags - flags that would be used for the equivalent kmalloc(..) call
+ *
+ * Returns a pointer to a retrieved buffer on success or NULL on failure.
+ */
+static inline void *qi_cache_zalloc(gfp_t flags)
+{
+ return kmem_cache_zalloc(qi_cache, flags);
+}
+
+/*
+ * qi_cache_free - Frees buffers allocated from CAAM-QI cache
+ *
+ * @obj - buffer previously allocated by qi_cache_zalloc
+ *
+ * No checking is being done, the call is a passthrough call to
+ * kmem_cache_free(...)
+ */
+static inline void qi_cache_free(void *obj)
+{
+ kmem_cache_free(qi_cache, obj);
+}
+
+static struct caam_request *to_caam_req(struct crypto_async_request *areq)
+{
+ switch (crypto_tfm_alg_type(areq->tfm)) {
+ case CRYPTO_ALG_TYPE_SKCIPHER:
+ return skcipher_request_ctx(skcipher_request_cast(areq));
+ case CRYPTO_ALG_TYPE_AEAD:
+ return aead_request_ctx(container_of(areq, struct aead_request,
+ base));
+ case CRYPTO_ALG_TYPE_AHASH:
+ return ahash_request_ctx(ahash_request_cast(areq));
+ default:
+ return ERR_PTR(-EINVAL);
+ }
+}
+
+static void caam_unmap(struct device *dev, struct scatterlist *src,
+ struct scatterlist *dst, int src_nents,
+ int dst_nents, dma_addr_t iv_dma, int ivsize,
+ dma_addr_t qm_sg_dma, int qm_sg_bytes)
+{
+ if (dst != src) {
+ if (src_nents)
+ dma_unmap_sg(dev, src, src_nents, DMA_TO_DEVICE);
+ dma_unmap_sg(dev, dst, dst_nents, DMA_FROM_DEVICE);
+ } else {
+ dma_unmap_sg(dev, src, src_nents, DMA_BIDIRECTIONAL);
+ }
+
+ if (iv_dma)
+ dma_unmap_single(dev, iv_dma, ivsize, DMA_TO_DEVICE);
+
+ if (qm_sg_bytes)
+ dma_unmap_single(dev, qm_sg_dma, qm_sg_bytes, DMA_TO_DEVICE);
+}
+
+static int aead_set_sh_desc(struct crypto_aead *aead)
+{
+ struct caam_aead_alg *alg = container_of(crypto_aead_alg(aead),
+ typeof(*alg), aead);
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ unsigned int ivsize = crypto_aead_ivsize(aead);
+ struct device *dev = ctx->dev;
+ struct dpaa2_caam_priv *priv = dev_get_drvdata(dev);
+ struct caam_flc *flc;
+ u32 *desc;
+ u32 ctx1_iv_off = 0;
+ u32 *nonce = NULL;
+ unsigned int data_len[2];
+ u32 inl_mask;
+ const bool ctr_mode = ((ctx->cdata.algtype & OP_ALG_AAI_MASK) ==
+ OP_ALG_AAI_CTR_MOD128);
+ const bool is_rfc3686 = alg->caam.rfc3686;
+
+ if (!ctx->cdata.keylen || !ctx->authsize)
+ return 0;
+
+ /*
+ * AES-CTR needs to load IV in CONTEXT1 reg
+ * at an offset of 128bits (16bytes)
+ * CONTEXT1[255:128] = IV
+ */
+ if (ctr_mode)
+ ctx1_iv_off = 16;
+
+ /*
+ * RFC3686 specific:
+ * CONTEXT1[255:128] = {NONCE, IV, COUNTER}
+ */
+ if (is_rfc3686) {
+ ctx1_iv_off = 16 + CTR_RFC3686_NONCE_SIZE;
+ nonce = (u32 *)((void *)ctx->key + ctx->adata.keylen_pad +
+ ctx->cdata.keylen - CTR_RFC3686_NONCE_SIZE);
+ }
+
+ data_len[0] = ctx->adata.keylen_pad;
+ data_len[1] = ctx->cdata.keylen;
+
+ /* aead_encrypt shared descriptor */
+ if (desc_inline_query((alg->caam.geniv ? DESC_QI_AEAD_GIVENC_LEN :
+ DESC_QI_AEAD_ENC_LEN) +
+ (is_rfc3686 ? DESC_AEAD_CTR_RFC3686_LEN : 0),
+ DESC_JOB_IO_LEN, data_len, &inl_mask,
+ ARRAY_SIZE(data_len)) < 0)
+ return -EINVAL;
+
+ if (inl_mask & 1)
+ ctx->adata.key_virt = ctx->key;
+ else
+ ctx->adata.key_dma = ctx->key_dma;
+
+ if (inl_mask & 2)
+ ctx->cdata.key_virt = ctx->key + ctx->adata.keylen_pad;
+ else
+ ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad;
+
+ ctx->adata.key_inline = !!(inl_mask & 1);
+ ctx->cdata.key_inline = !!(inl_mask & 2);
+
+ flc = &ctx->flc[ENCRYPT];
+ desc = flc->sh_desc;
+
+ if (alg->caam.geniv)
+ cnstr_shdsc_aead_givencap(desc, &ctx->cdata, &ctx->adata,
+ ivsize, ctx->authsize, is_rfc3686,
+ nonce, ctx1_iv_off, true,
+ priv->sec_attr.era);
+ else
+ cnstr_shdsc_aead_encap(desc, &ctx->cdata, &ctx->adata,
+ ivsize, ctx->authsize, is_rfc3686, nonce,
+ ctx1_iv_off, true, priv->sec_attr.era);
+
+ flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
+ dma_sync_single_for_device(dev, ctx->flc_dma[ENCRYPT],
+ sizeof(flc->flc) + desc_bytes(desc),
+ ctx->dir);
+
+ /* aead_decrypt shared descriptor */
+ if (desc_inline_query(DESC_QI_AEAD_DEC_LEN +
+ (is_rfc3686 ? DESC_AEAD_CTR_RFC3686_LEN : 0),
+ DESC_JOB_IO_LEN, data_len, &inl_mask,
+ ARRAY_SIZE(data_len)) < 0)
+ return -EINVAL;
+
+ if (inl_mask & 1)
+ ctx->adata.key_virt = ctx->key;
+ else
+ ctx->adata.key_dma = ctx->key_dma;
+
+ if (inl_mask & 2)
+ ctx->cdata.key_virt = ctx->key + ctx->adata.keylen_pad;
+ else
+ ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad;
+
+ ctx->adata.key_inline = !!(inl_mask & 1);
+ ctx->cdata.key_inline = !!(inl_mask & 2);
+
+ flc = &ctx->flc[DECRYPT];
+ desc = flc->sh_desc;
+ cnstr_shdsc_aead_decap(desc, &ctx->cdata, &ctx->adata,
+ ivsize, ctx->authsize, alg->caam.geniv,
+ is_rfc3686, nonce, ctx1_iv_off, true,
+ priv->sec_attr.era);
+ flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
+ dma_sync_single_for_device(dev, ctx->flc_dma[DECRYPT],
+ sizeof(flc->flc) + desc_bytes(desc),
+ ctx->dir);
+
+ return 0;
+}
+
+static int aead_setauthsize(struct crypto_aead *authenc, unsigned int authsize)
+{
+ struct caam_ctx *ctx = crypto_aead_ctx(authenc);
+
+ ctx->authsize = authsize;
+ aead_set_sh_desc(authenc);
+
+ return 0;
+}
+
+static int aead_setkey(struct crypto_aead *aead, const u8 *key,
+ unsigned int keylen)
+{
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ struct device *dev = ctx->dev;
+ struct crypto_authenc_keys keys;
+
+ if (crypto_authenc_extractkeys(&keys, key, keylen) != 0)
+ goto badkey;
+
+ dev_dbg(dev, "keylen %d enckeylen %d authkeylen %d\n",
+ keys.authkeylen + keys.enckeylen, keys.enckeylen,
+ keys.authkeylen);
+ print_hex_dump_debug("key in @" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
+
+ ctx->adata.keylen = keys.authkeylen;
+ ctx->adata.keylen_pad = split_key_len(ctx->adata.algtype &
+ OP_ALG_ALGSEL_MASK);
+
+ if (ctx->adata.keylen_pad + keys.enckeylen > CAAM_MAX_KEY_SIZE)
+ goto badkey;
+
+ memcpy(ctx->key, keys.authkey, keys.authkeylen);
+ memcpy(ctx->key + ctx->adata.keylen_pad, keys.enckey, keys.enckeylen);
+ dma_sync_single_for_device(dev, ctx->key_dma, ctx->adata.keylen_pad +
+ keys.enckeylen, ctx->dir);
+ print_hex_dump_debug("ctx.key@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, ctx->key,
+ ctx->adata.keylen_pad + keys.enckeylen, 1);
+
+ ctx->cdata.keylen = keys.enckeylen;
+
+ memzero_explicit(&keys, sizeof(keys));
+ return aead_set_sh_desc(aead);
+badkey:
+ crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ memzero_explicit(&keys, sizeof(keys));
+ return -EINVAL;
+}
+
+static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
+ bool encrypt)
+{
+ struct crypto_aead *aead = crypto_aead_reqtfm(req);
+ struct caam_request *req_ctx = aead_request_ctx(req);
+ struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1];
+ struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0];
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ struct caam_aead_alg *alg = container_of(crypto_aead_alg(aead),
+ typeof(*alg), aead);
+ struct device *dev = ctx->dev;
+ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
+ GFP_KERNEL : GFP_ATOMIC;
+ int src_nents, mapped_src_nents, dst_nents = 0, mapped_dst_nents = 0;
+ struct aead_edesc *edesc;
+ dma_addr_t qm_sg_dma, iv_dma = 0;
+ int ivsize = 0;
+ unsigned int authsize = ctx->authsize;
+ int qm_sg_index = 0, qm_sg_nents = 0, qm_sg_bytes;
+ int in_len, out_len;
+ struct dpaa2_sg_entry *sg_table;
+
+ /* allocate space for base edesc, link tables and IV */
+ edesc = qi_cache_zalloc(GFP_DMA | flags);
+ if (unlikely(!edesc)) {
+ dev_err(dev, "could not allocate extended descriptor\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ if (unlikely(req->dst != req->src)) {
+ src_nents = sg_nents_for_len(req->src, req->assoclen +
+ req->cryptlen);
+ if (unlikely(src_nents < 0)) {
+ dev_err(dev, "Insufficient bytes (%d) in src S/G\n",
+ req->assoclen + req->cryptlen);
+ qi_cache_free(edesc);
+ return ERR_PTR(src_nents);
+ }
+
+ dst_nents = sg_nents_for_len(req->dst, req->assoclen +
+ req->cryptlen +
+ (encrypt ? authsize :
+ (-authsize)));
+ if (unlikely(dst_nents < 0)) {
+ dev_err(dev, "Insufficient bytes (%d) in dst S/G\n",
+ req->assoclen + req->cryptlen +
+ (encrypt ? authsize : (-authsize)));
+ qi_cache_free(edesc);
+ return ERR_PTR(dst_nents);
+ }
+
+ if (src_nents) {
+ mapped_src_nents = dma_map_sg(dev, req->src, src_nents,
+ DMA_TO_DEVICE);
+ if (unlikely(!mapped_src_nents)) {
+ dev_err(dev, "unable to map source\n");
+ qi_cache_free(edesc);
+ return ERR_PTR(-ENOMEM);
+ }
+ } else {
+ mapped_src_nents = 0;
+ }
+
+ mapped_dst_nents = dma_map_sg(dev, req->dst, dst_nents,
+ DMA_FROM_DEVICE);
+ if (unlikely(!mapped_dst_nents)) {
+ dev_err(dev, "unable to map destination\n");
+ dma_unmap_sg(dev, req->src, src_nents, DMA_TO_DEVICE);
+ qi_cache_free(edesc);
+ return ERR_PTR(-ENOMEM);
+ }
+ } else {
+ src_nents = sg_nents_for_len(req->src, req->assoclen +
+ req->cryptlen +
+ (encrypt ? authsize : 0));
+ if (unlikely(src_nents < 0)) {
+ dev_err(dev, "Insufficient bytes (%d) in src S/G\n",
+ req->assoclen + req->cryptlen +
+ (encrypt ? authsize : 0));
+ qi_cache_free(edesc);
+ return ERR_PTR(src_nents);
+ }
+
+ mapped_src_nents = dma_map_sg(dev, req->src, src_nents,
+ DMA_BIDIRECTIONAL);
+ if (unlikely(!mapped_src_nents)) {
+ dev_err(dev, "unable to map source\n");
+ qi_cache_free(edesc);
+ return ERR_PTR(-ENOMEM);
+ }
+ }
+
+ if ((alg->caam.rfc3686 && encrypt) || !alg->caam.geniv)
+ ivsize = crypto_aead_ivsize(aead);
+
+ /*
+ * Create S/G table: req->assoclen, [IV,] req->src [, req->dst].
+ * Input is not contiguous.
+ */
+ qm_sg_nents = 1 + !!ivsize + mapped_src_nents +
+ (mapped_dst_nents > 1 ? mapped_dst_nents : 0);
+ sg_table = &edesc->sgt[0];
+ qm_sg_bytes = qm_sg_nents * sizeof(*sg_table);
+ if (unlikely(offsetof(struct aead_edesc, sgt) + qm_sg_bytes + ivsize >
+ CAAM_QI_MEMCACHE_SIZE)) {
+ dev_err(dev, "No space for %d S/G entries and/or %dB IV\n",
+ qm_sg_nents, ivsize);
+ caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, 0,
+ 0, 0, 0);
+ qi_cache_free(edesc);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ if (ivsize) {
+ u8 *iv = (u8 *)(sg_table + qm_sg_nents);
+
+ /* Make sure IV is located in a DMAable area */
+ memcpy(iv, req->iv, ivsize);
+
+ iv_dma = dma_map_single(dev, iv, ivsize, DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, iv_dma)) {
+ dev_err(dev, "unable to map IV\n");
+ caam_unmap(dev, req->src, req->dst, src_nents,
+ dst_nents, 0, 0, 0, 0);
+ qi_cache_free(edesc);
+ return ERR_PTR(-ENOMEM);
+ }
+ }
+
+ edesc->src_nents = src_nents;
+ edesc->dst_nents = dst_nents;
+ edesc->iv_dma = iv_dma;
+
+ edesc->assoclen = cpu_to_caam32(req->assoclen);
+ edesc->assoclen_dma = dma_map_single(dev, &edesc->assoclen, 4,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, edesc->assoclen_dma)) {
+ dev_err(dev, "unable to map assoclen\n");
+ caam_unmap(dev, req->src, req->dst, src_nents, dst_nents,
+ iv_dma, ivsize, 0, 0);
+ qi_cache_free(edesc);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ dma_to_qm_sg_one(sg_table, edesc->assoclen_dma, 4, 0);
+ qm_sg_index++;
+ if (ivsize) {
+ dma_to_qm_sg_one(sg_table + qm_sg_index, iv_dma, ivsize, 0);
+ qm_sg_index++;
+ }
+ sg_to_qm_sg_last(req->src, mapped_src_nents, sg_table + qm_sg_index, 0);
+ qm_sg_index += mapped_src_nents;
+
+ if (mapped_dst_nents > 1)
+ sg_to_qm_sg_last(req->dst, mapped_dst_nents, sg_table +
+ qm_sg_index, 0);
+
+ qm_sg_dma = dma_map_single(dev, sg_table, qm_sg_bytes, DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, qm_sg_dma)) {
+ dev_err(dev, "unable to map S/G table\n");
+ dma_unmap_single(dev, edesc->assoclen_dma, 4, DMA_TO_DEVICE);
+ caam_unmap(dev, req->src, req->dst, src_nents, dst_nents,
+ iv_dma, ivsize, 0, 0);
+ qi_cache_free(edesc);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ edesc->qm_sg_dma = qm_sg_dma;
+ edesc->qm_sg_bytes = qm_sg_bytes;
+
+ out_len = req->assoclen + req->cryptlen +
+ (encrypt ? ctx->authsize : (-ctx->authsize));
+ in_len = 4 + ivsize + req->assoclen + req->cryptlen;
+
+ memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt));
+ dpaa2_fl_set_final(in_fle, true);
+ dpaa2_fl_set_format(in_fle, dpaa2_fl_sg);
+ dpaa2_fl_set_addr(in_fle, qm_sg_dma);
+ dpaa2_fl_set_len(in_fle, in_len);
+
+ if (req->dst == req->src) {
+ if (mapped_src_nents == 1) {
+ dpaa2_fl_set_format(out_fle, dpaa2_fl_single);
+ dpaa2_fl_set_addr(out_fle, sg_dma_address(req->src));
+ } else {
+ dpaa2_fl_set_format(out_fle, dpaa2_fl_sg);
+ dpaa2_fl_set_addr(out_fle, qm_sg_dma +
+ (1 + !!ivsize) * sizeof(*sg_table));
+ }
+ } else if (mapped_dst_nents == 1) {
+ dpaa2_fl_set_format(out_fle, dpaa2_fl_single);
+ dpaa2_fl_set_addr(out_fle, sg_dma_address(req->dst));
+ } else {
+ dpaa2_fl_set_format(out_fle, dpaa2_fl_sg);
+ dpaa2_fl_set_addr(out_fle, qm_sg_dma + qm_sg_index *
+ sizeof(*sg_table));
+ }
+
+ dpaa2_fl_set_len(out_fle, out_len);
+
+ return edesc;
+}
+
+static int gcm_set_sh_desc(struct crypto_aead *aead)
+{
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ struct device *dev = ctx->dev;
+ unsigned int ivsize = crypto_aead_ivsize(aead);
+ struct caam_flc *flc;
+ u32 *desc;
+ int rem_bytes = CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN -
+ ctx->cdata.keylen;
+
+ if (!ctx->cdata.keylen || !ctx->authsize)
+ return 0;
+
+ /*
+ * AES GCM encrypt shared descriptor
+ * Job Descriptor and Shared Descriptor
+ * must fit into the 64-word Descriptor h/w Buffer
+ */
+ if (rem_bytes >= DESC_QI_GCM_ENC_LEN) {
+ ctx->cdata.key_inline = true;
+ ctx->cdata.key_virt = ctx->key;
+ } else {
+ ctx->cdata.key_inline = false;
+ ctx->cdata.key_dma = ctx->key_dma;
+ }
+
+ flc = &ctx->flc[ENCRYPT];
+ desc = flc->sh_desc;
+ cnstr_shdsc_gcm_encap(desc, &ctx->cdata, ivsize, ctx->authsize, true);
+ flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
+ dma_sync_single_for_device(dev, ctx->flc_dma[ENCRYPT],
+ sizeof(flc->flc) + desc_bytes(desc),
+ ctx->dir);
+
+ /*
+ * Job Descriptor and Shared Descriptors
+ * must all fit into the 64-word Descriptor h/w Buffer
+ */
+ if (rem_bytes >= DESC_QI_GCM_DEC_LEN) {
+ ctx->cdata.key_inline = true;
+ ctx->cdata.key_virt = ctx->key;
+ } else {
+ ctx->cdata.key_inline = false;
+ ctx->cdata.key_dma = ctx->key_dma;
+ }
+
+ flc = &ctx->flc[DECRYPT];
+ desc = flc->sh_desc;
+ cnstr_shdsc_gcm_decap(desc, &ctx->cdata, ivsize, ctx->authsize, true);
+ flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
+ dma_sync_single_for_device(dev, ctx->flc_dma[DECRYPT],
+ sizeof(flc->flc) + desc_bytes(desc),
+ ctx->dir);
+
+ return 0;
+}
+
+static int gcm_setauthsize(struct crypto_aead *authenc, unsigned int authsize)
+{
+ struct caam_ctx *ctx = crypto_aead_ctx(authenc);
+
+ ctx->authsize = authsize;
+ gcm_set_sh_desc(authenc);
+
+ return 0;
+}
+
+static int gcm_setkey(struct crypto_aead *aead,
+ const u8 *key, unsigned int keylen)
+{
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ struct device *dev = ctx->dev;
+
+ print_hex_dump_debug("key in @" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
+
+ memcpy(ctx->key, key, keylen);
+ dma_sync_single_for_device(dev, ctx->key_dma, keylen, ctx->dir);
+ ctx->cdata.keylen = keylen;
+
+ return gcm_set_sh_desc(aead);
+}
+
+static int rfc4106_set_sh_desc(struct crypto_aead *aead)
+{
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ struct device *dev = ctx->dev;
+ unsigned int ivsize = crypto_aead_ivsize(aead);
+ struct caam_flc *flc;
+ u32 *desc;
+ int rem_bytes = CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN -
+ ctx->cdata.keylen;
+
+ if (!ctx->cdata.keylen || !ctx->authsize)
+ return 0;
+
+ ctx->cdata.key_virt = ctx->key;
+
+ /*
+ * RFC4106 encrypt shared descriptor
+ * Job Descriptor and Shared Descriptor
+ * must fit into the 64-word Descriptor h/w Buffer
+ */
+ if (rem_bytes >= DESC_QI_RFC4106_ENC_LEN) {
+ ctx->cdata.key_inline = true;
+ } else {
+ ctx->cdata.key_inline = false;
+ ctx->cdata.key_dma = ctx->key_dma;
+ }
+
+ flc = &ctx->flc[ENCRYPT];
+ desc = flc->sh_desc;
+ cnstr_shdsc_rfc4106_encap(desc, &ctx->cdata, ivsize, ctx->authsize,
+ true);
+ flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
+ dma_sync_single_for_device(dev, ctx->flc_dma[ENCRYPT],
+ sizeof(flc->flc) + desc_bytes(desc),
+ ctx->dir);
+
+ /*
+ * Job Descriptor and Shared Descriptors
+ * must all fit into the 64-word Descriptor h/w Buffer
+ */
+ if (rem_bytes >= DESC_QI_RFC4106_DEC_LEN) {
+ ctx->cdata.key_inline = true;
+ } else {
+ ctx->cdata.key_inline = false;
+ ctx->cdata.key_dma = ctx->key_dma;
+ }
+
+ flc = &ctx->flc[DECRYPT];
+ desc = flc->sh_desc;
+ cnstr_shdsc_rfc4106_decap(desc, &ctx->cdata, ivsize, ctx->authsize,
+ true);
+ flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
+ dma_sync_single_for_device(dev, ctx->flc_dma[DECRYPT],
+ sizeof(flc->flc) + desc_bytes(desc),
+ ctx->dir);
+
+ return 0;
+}
+
+static int rfc4106_setauthsize(struct crypto_aead *authenc,
+ unsigned int authsize)
+{
+ struct caam_ctx *ctx = crypto_aead_ctx(authenc);
+
+ ctx->authsize = authsize;
+ rfc4106_set_sh_desc(authenc);
+
+ return 0;
+}
+
+static int rfc4106_setkey(struct crypto_aead *aead,
+ const u8 *key, unsigned int keylen)
+{
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ struct device *dev = ctx->dev;
+
+ if (keylen < 4)
+ return -EINVAL;
+
+ print_hex_dump_debug("key in @" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
+
+ memcpy(ctx->key, key, keylen);
+ /*
+ * The last four bytes of the key material are used as the salt value
+ * in the nonce. Update the AES key length.
+ */
+ ctx->cdata.keylen = keylen - 4;
+ dma_sync_single_for_device(dev, ctx->key_dma, ctx->cdata.keylen,
+ ctx->dir);
+
+ return rfc4106_set_sh_desc(aead);
+}
+
+static int rfc4543_set_sh_desc(struct crypto_aead *aead)
+{
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ struct device *dev = ctx->dev;
+ unsigned int ivsize = crypto_aead_ivsize(aead);
+ struct caam_flc *flc;
+ u32 *desc;
+ int rem_bytes = CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN -
+ ctx->cdata.keylen;
+
+ if (!ctx->cdata.keylen || !ctx->authsize)
+ return 0;
+
+ ctx->cdata.key_virt = ctx->key;
+
+ /*
+ * RFC4543 encrypt shared descriptor
+ * Job Descriptor and Shared Descriptor
+ * must fit into the 64-word Descriptor h/w Buffer
+ */
+ if (rem_bytes >= DESC_QI_RFC4543_ENC_LEN) {
+ ctx->cdata.key_inline = true;
+ } else {
+ ctx->cdata.key_inline = false;
+ ctx->cdata.key_dma = ctx->key_dma;
+ }
+
+ flc = &ctx->flc[ENCRYPT];
+ desc = flc->sh_desc;
+ cnstr_shdsc_rfc4543_encap(desc, &ctx->cdata, ivsize, ctx->authsize,
+ true);
+ flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
+ dma_sync_single_for_device(dev, ctx->flc_dma[ENCRYPT],
+ sizeof(flc->flc) + desc_bytes(desc),
+ ctx->dir);
+
+ /*
+ * Job Descriptor and Shared Descriptors
+ * must all fit into the 64-word Descriptor h/w Buffer
+ */
+ if (rem_bytes >= DESC_QI_RFC4543_DEC_LEN) {
+ ctx->cdata.key_inline = true;
+ } else {
+ ctx->cdata.key_inline = false;
+ ctx->cdata.key_dma = ctx->key_dma;
+ }
+
+ flc = &ctx->flc[DECRYPT];
+ desc = flc->sh_desc;
+ cnstr_shdsc_rfc4543_decap(desc, &ctx->cdata, ivsize, ctx->authsize,
+ true);
+ flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
+ dma_sync_single_for_device(dev, ctx->flc_dma[DECRYPT],
+ sizeof(flc->flc) + desc_bytes(desc),
+ ctx->dir);
+
+ return 0;
+}
+
+static int rfc4543_setauthsize(struct crypto_aead *authenc,
+ unsigned int authsize)
+{
+ struct caam_ctx *ctx = crypto_aead_ctx(authenc);
+
+ ctx->authsize = authsize;
+ rfc4543_set_sh_desc(authenc);
+
+ return 0;
+}
+
+static int rfc4543_setkey(struct crypto_aead *aead,
+ const u8 *key, unsigned int keylen)
+{
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ struct device *dev = ctx->dev;
+
+ if (keylen < 4)
+ return -EINVAL;
+
+ print_hex_dump_debug("key in @" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
+
+ memcpy(ctx->key, key, keylen);
+ /*
+ * The last four bytes of the key material are used as the salt value
+ * in the nonce. Update the AES key length.
+ */
+ ctx->cdata.keylen = keylen - 4;
+ dma_sync_single_for_device(dev, ctx->key_dma, ctx->cdata.keylen,
+ ctx->dir);
+
+ return rfc4543_set_sh_desc(aead);
+}
+
+static int skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key,
+ unsigned int keylen)
+{
+ struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
+ struct caam_skcipher_alg *alg =
+ container_of(crypto_skcipher_alg(skcipher),
+ struct caam_skcipher_alg, skcipher);
+ struct device *dev = ctx->dev;
+ struct caam_flc *flc;
+ unsigned int ivsize = crypto_skcipher_ivsize(skcipher);
+ u32 *desc;
+ u32 ctx1_iv_off = 0;
+ const bool ctr_mode = ((ctx->cdata.algtype & OP_ALG_AAI_MASK) ==
+ OP_ALG_AAI_CTR_MOD128);
+ const bool is_rfc3686 = alg->caam.rfc3686;
+
+ print_hex_dump_debug("key in @" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
+
+ /*
+ * AES-CTR needs to load IV in CONTEXT1 reg
+ * at an offset of 128bits (16bytes)
+ * CONTEXT1[255:128] = IV
+ */
+ if (ctr_mode)
+ ctx1_iv_off = 16;
+
+ /*
+ * RFC3686 specific:
+ * | CONTEXT1[255:128] = {NONCE, IV, COUNTER}
+ * | *key = {KEY, NONCE}
+ */
+ if (is_rfc3686) {
+ ctx1_iv_off = 16 + CTR_RFC3686_NONCE_SIZE;
+ keylen -= CTR_RFC3686_NONCE_SIZE;
+ }
+
+ ctx->cdata.keylen = keylen;
+ ctx->cdata.key_virt = key;
+ ctx->cdata.key_inline = true;
+
+ /* skcipher_encrypt shared descriptor */
+ flc = &ctx->flc[ENCRYPT];
+ desc = flc->sh_desc;
+ cnstr_shdsc_skcipher_encap(desc, &ctx->cdata, ivsize, is_rfc3686,
+ ctx1_iv_off);
+ flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
+ dma_sync_single_for_device(dev, ctx->flc_dma[ENCRYPT],
+ sizeof(flc->flc) + desc_bytes(desc),
+ ctx->dir);
+
+ /* skcipher_decrypt shared descriptor */
+ flc = &ctx->flc[DECRYPT];
+ desc = flc->sh_desc;
+ cnstr_shdsc_skcipher_decap(desc, &ctx->cdata, ivsize, is_rfc3686,
+ ctx1_iv_off);
+ flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
+ dma_sync_single_for_device(dev, ctx->flc_dma[DECRYPT],
+ sizeof(flc->flc) + desc_bytes(desc),
+ ctx->dir);
+
+ return 0;
+}
+
+static int xts_skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key,
+ unsigned int keylen)
+{
+ struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
+ struct device *dev = ctx->dev;
+ struct caam_flc *flc;
+ u32 *desc;
+
+ if (keylen != 2 * AES_MIN_KEY_SIZE && keylen != 2 * AES_MAX_KEY_SIZE) {
+ dev_err(dev, "key size mismatch\n");
+ crypto_skcipher_set_flags(skcipher, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ return -EINVAL;
+ }
+
+ ctx->cdata.keylen = keylen;
+ ctx->cdata.key_virt = key;
+ ctx->cdata.key_inline = true;
+
+ /* xts_skcipher_encrypt shared descriptor */
+ flc = &ctx->flc[ENCRYPT];
+ desc = flc->sh_desc;
+ cnstr_shdsc_xts_skcipher_encap(desc, &ctx->cdata);
+ flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
+ dma_sync_single_for_device(dev, ctx->flc_dma[ENCRYPT],
+ sizeof(flc->flc) + desc_bytes(desc),
+ ctx->dir);
+
+ /* xts_skcipher_decrypt shared descriptor */
+ flc = &ctx->flc[DECRYPT];
+ desc = flc->sh_desc;
+ cnstr_shdsc_xts_skcipher_decap(desc, &ctx->cdata);
+ flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
+ dma_sync_single_for_device(dev, ctx->flc_dma[DECRYPT],
+ sizeof(flc->flc) + desc_bytes(desc),
+ ctx->dir);
+
+ return 0;
+}
+
+static struct skcipher_edesc *skcipher_edesc_alloc(struct skcipher_request *req)
+{
+ struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
+ struct caam_request *req_ctx = skcipher_request_ctx(req);
+ struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1];
+ struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0];
+ struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
+ struct device *dev = ctx->dev;
+ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
+ GFP_KERNEL : GFP_ATOMIC;
+ int src_nents, mapped_src_nents, dst_nents = 0, mapped_dst_nents = 0;
+ struct skcipher_edesc *edesc;
+ dma_addr_t iv_dma;
+ u8 *iv;
+ int ivsize = crypto_skcipher_ivsize(skcipher);
+ int dst_sg_idx, qm_sg_ents, qm_sg_bytes;
+ struct dpaa2_sg_entry *sg_table;
+
+ src_nents = sg_nents_for_len(req->src, req->cryptlen);
+ if (unlikely(src_nents < 0)) {
+ dev_err(dev, "Insufficient bytes (%d) in src S/G\n",
+ req->cryptlen);
+ return ERR_PTR(src_nents);
+ }
+
+ if (unlikely(req->dst != req->src)) {
+ dst_nents = sg_nents_for_len(req->dst, req->cryptlen);
+ if (unlikely(dst_nents < 0)) {
+ dev_err(dev, "Insufficient bytes (%d) in dst S/G\n",
+ req->cryptlen);
+ return ERR_PTR(dst_nents);
+ }
+
+ mapped_src_nents = dma_map_sg(dev, req->src, src_nents,
+ DMA_TO_DEVICE);
+ if (unlikely(!mapped_src_nents)) {
+ dev_err(dev, "unable to map source\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ mapped_dst_nents = dma_map_sg(dev, req->dst, dst_nents,
+ DMA_FROM_DEVICE);
+ if (unlikely(!mapped_dst_nents)) {
+ dev_err(dev, "unable to map destination\n");
+ dma_unmap_sg(dev, req->src, src_nents, DMA_TO_DEVICE);
+ return ERR_PTR(-ENOMEM);
+ }
+ } else {
+ mapped_src_nents = dma_map_sg(dev, req->src, src_nents,
+ DMA_BIDIRECTIONAL);
+ if (unlikely(!mapped_src_nents)) {
+ dev_err(dev, "unable to map source\n");
+ return ERR_PTR(-ENOMEM);
+ }
+ }
+
+ qm_sg_ents = 1 + mapped_src_nents;
+ dst_sg_idx = qm_sg_ents;
+
+ qm_sg_ents += mapped_dst_nents > 1 ? mapped_dst_nents : 0;
+ qm_sg_bytes = qm_sg_ents * sizeof(struct dpaa2_sg_entry);
+ if (unlikely(offsetof(struct skcipher_edesc, sgt) + qm_sg_bytes +
+ ivsize > CAAM_QI_MEMCACHE_SIZE)) {
+ dev_err(dev, "No space for %d S/G entries and/or %dB IV\n",
+ qm_sg_ents, ivsize);
+ caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, 0,
+ 0, 0, 0);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ /* allocate space for base edesc, link tables and IV */
+ edesc = qi_cache_zalloc(GFP_DMA | flags);
+ if (unlikely(!edesc)) {
+ dev_err(dev, "could not allocate extended descriptor\n");
+ caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, 0,
+ 0, 0, 0);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ /* Make sure IV is located in a DMAable area */
+ sg_table = &edesc->sgt[0];
+ iv = (u8 *)(sg_table + qm_sg_ents);
+ memcpy(iv, req->iv, ivsize);
+
+ iv_dma = dma_map_single(dev, iv, ivsize, DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, iv_dma)) {
+ dev_err(dev, "unable to map IV\n");
+ caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, 0,
+ 0, 0, 0);
+ qi_cache_free(edesc);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ edesc->src_nents = src_nents;
+ edesc->dst_nents = dst_nents;
+ edesc->iv_dma = iv_dma;
+ edesc->qm_sg_bytes = qm_sg_bytes;
+
+ dma_to_qm_sg_one(sg_table, iv_dma, ivsize, 0);
+ sg_to_qm_sg_last(req->src, mapped_src_nents, sg_table + 1, 0);
+
+ if (mapped_dst_nents > 1)
+ sg_to_qm_sg_last(req->dst, mapped_dst_nents, sg_table +
+ dst_sg_idx, 0);
+
+ edesc->qm_sg_dma = dma_map_single(dev, sg_table, edesc->qm_sg_bytes,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, edesc->qm_sg_dma)) {
+ dev_err(dev, "unable to map S/G table\n");
+ caam_unmap(dev, req->src, req->dst, src_nents, dst_nents,
+ iv_dma, ivsize, 0, 0);
+ qi_cache_free(edesc);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt));
+ dpaa2_fl_set_final(in_fle, true);
+ dpaa2_fl_set_len(in_fle, req->cryptlen + ivsize);
+ dpaa2_fl_set_len(out_fle, req->cryptlen);
+
+ dpaa2_fl_set_format(in_fle, dpaa2_fl_sg);
+ dpaa2_fl_set_addr(in_fle, edesc->qm_sg_dma);
+
+ if (req->src == req->dst) {
+ dpaa2_fl_set_format(out_fle, dpaa2_fl_sg);
+ dpaa2_fl_set_addr(out_fle, edesc->qm_sg_dma +
+ sizeof(*sg_table));
+ } else if (mapped_dst_nents > 1) {
+ dpaa2_fl_set_format(out_fle, dpaa2_fl_sg);
+ dpaa2_fl_set_addr(out_fle, edesc->qm_sg_dma + dst_sg_idx *
+ sizeof(*sg_table));
+ } else {
+ dpaa2_fl_set_format(out_fle, dpaa2_fl_single);
+ dpaa2_fl_set_addr(out_fle, sg_dma_address(req->dst));
+ }
+
+ return edesc;
+}
+
+static void aead_unmap(struct device *dev, struct aead_edesc *edesc,
+ struct aead_request *req)
+{
+ struct crypto_aead *aead = crypto_aead_reqtfm(req);
+ int ivsize = crypto_aead_ivsize(aead);
+
+ caam_unmap(dev, req->src, req->dst, edesc->src_nents, edesc->dst_nents,
+ edesc->iv_dma, ivsize, edesc->qm_sg_dma, edesc->qm_sg_bytes);
+ dma_unmap_single(dev, edesc->assoclen_dma, 4, DMA_TO_DEVICE);
+}
+
+static void skcipher_unmap(struct device *dev, struct skcipher_edesc *edesc,
+ struct skcipher_request *req)
+{
+ struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
+ int ivsize = crypto_skcipher_ivsize(skcipher);
+
+ caam_unmap(dev, req->src, req->dst, edesc->src_nents, edesc->dst_nents,
+ edesc->iv_dma, ivsize, edesc->qm_sg_dma, edesc->qm_sg_bytes);
+}
+
+static void aead_encrypt_done(void *cbk_ctx, u32 status)
+{
+ struct crypto_async_request *areq = cbk_ctx;
+ struct aead_request *req = container_of(areq, struct aead_request,
+ base);
+ struct caam_request *req_ctx = to_caam_req(areq);
+ struct aead_edesc *edesc = req_ctx->edesc;
+ struct crypto_aead *aead = crypto_aead_reqtfm(req);
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ int ecode = 0;
+
+ dev_dbg(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status);
+
+ if (unlikely(status)) {
+ caam_qi2_strstatus(ctx->dev, status);
+ ecode = -EIO;
+ }
+
+ aead_unmap(ctx->dev, edesc, req);
+ qi_cache_free(edesc);
+ aead_request_complete(req, ecode);
+}
+
+static void aead_decrypt_done(void *cbk_ctx, u32 status)
+{
+ struct crypto_async_request *areq = cbk_ctx;
+ struct aead_request *req = container_of(areq, struct aead_request,
+ base);
+ struct caam_request *req_ctx = to_caam_req(areq);
+ struct aead_edesc *edesc = req_ctx->edesc;
+ struct crypto_aead *aead = crypto_aead_reqtfm(req);
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ int ecode = 0;
+
+ dev_dbg(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status);
+
+ if (unlikely(status)) {
+ caam_qi2_strstatus(ctx->dev, status);
+ /*
+ * verify hw auth check passed else return -EBADMSG
+ */
+ if ((status & JRSTA_CCBERR_ERRID_MASK) ==
+ JRSTA_CCBERR_ERRID_ICVCHK)
+ ecode = -EBADMSG;
+ else
+ ecode = -EIO;
+ }
+
+ aead_unmap(ctx->dev, edesc, req);
+ qi_cache_free(edesc);
+ aead_request_complete(req, ecode);
+}
+
+static int aead_encrypt(struct aead_request *req)
+{
+ struct aead_edesc *edesc;
+ struct crypto_aead *aead = crypto_aead_reqtfm(req);
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ struct caam_request *caam_req = aead_request_ctx(req);
+ int ret;
+
+ /* allocate extended descriptor */
+ edesc = aead_edesc_alloc(req, true);
+ if (IS_ERR(edesc))
+ return PTR_ERR(edesc);
+
+ caam_req->flc = &ctx->flc[ENCRYPT];
+ caam_req->flc_dma = ctx->flc_dma[ENCRYPT];
+ caam_req->cbk = aead_encrypt_done;
+ caam_req->ctx = &req->base;
+ caam_req->edesc = edesc;
+ ret = dpaa2_caam_enqueue(ctx->dev, caam_req);
+ if (ret != -EINPROGRESS &&
+ !(ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) {
+ aead_unmap(ctx->dev, edesc, req);
+ qi_cache_free(edesc);
+ }
+
+ return ret;
+}
+
+static int aead_decrypt(struct aead_request *req)
+{
+ struct aead_edesc *edesc;
+ struct crypto_aead *aead = crypto_aead_reqtfm(req);
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ struct caam_request *caam_req = aead_request_ctx(req);
+ int ret;
+
+ /* allocate extended descriptor */
+ edesc = aead_edesc_alloc(req, false);
+ if (IS_ERR(edesc))
+ return PTR_ERR(edesc);
+
+ caam_req->flc = &ctx->flc[DECRYPT];
+ caam_req->flc_dma = ctx->flc_dma[DECRYPT];
+ caam_req->cbk = aead_decrypt_done;
+ caam_req->ctx = &req->base;
+ caam_req->edesc = edesc;
+ ret = dpaa2_caam_enqueue(ctx->dev, caam_req);
+ if (ret != -EINPROGRESS &&
+ !(ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) {
+ aead_unmap(ctx->dev, edesc, req);
+ qi_cache_free(edesc);
+ }
+
+ return ret;
+}
+
+static int ipsec_gcm_encrypt(struct aead_request *req)
+{
+ if (req->assoclen < 8)
+ return -EINVAL;
+
+ return aead_encrypt(req);
+}
+
+static int ipsec_gcm_decrypt(struct aead_request *req)
+{
+ if (req->assoclen < 8)
+ return -EINVAL;
+
+ return aead_decrypt(req);
+}
+
+static void skcipher_encrypt_done(void *cbk_ctx, u32 status)
+{
+ struct crypto_async_request *areq = cbk_ctx;
+ struct skcipher_request *req = skcipher_request_cast(areq);
+ struct caam_request *req_ctx = to_caam_req(areq);
+ struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
+ struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
+ struct skcipher_edesc *edesc = req_ctx->edesc;
+ int ecode = 0;
+ int ivsize = crypto_skcipher_ivsize(skcipher);
+
+ dev_dbg(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status);
+
+ if (unlikely(status)) {
+ caam_qi2_strstatus(ctx->dev, status);
+ ecode = -EIO;
+ }
+
+ print_hex_dump_debug("dstiv @" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, req->iv,
+ edesc->src_nents > 1 ? 100 : ivsize, 1);
+ caam_dump_sg(KERN_DEBUG, "dst @" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, req->dst,
+ edesc->dst_nents > 1 ? 100 : req->cryptlen, 1);
+
+ skcipher_unmap(ctx->dev, edesc, req);
+
+ /*
+ * The crypto API expects us to set the IV (req->iv) to the last
+ * ciphertext block. This is used e.g. by the CTS mode.
+ */
+ scatterwalk_map_and_copy(req->iv, req->dst, req->cryptlen - ivsize,
+ ivsize, 0);
+
+ qi_cache_free(edesc);
+ skcipher_request_complete(req, ecode);
+}
+
+static void skcipher_decrypt_done(void *cbk_ctx, u32 status)
+{
+ struct crypto_async_request *areq = cbk_ctx;
+ struct skcipher_request *req = skcipher_request_cast(areq);
+ struct caam_request *req_ctx = to_caam_req(areq);
+ struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
+ struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
+ struct skcipher_edesc *edesc = req_ctx->edesc;
+ int ecode = 0;
+ int ivsize = crypto_skcipher_ivsize(skcipher);
+
+ dev_dbg(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status);
+
+ if (unlikely(status)) {
+ caam_qi2_strstatus(ctx->dev, status);
+ ecode = -EIO;
+ }
+
+ print_hex_dump_debug("dstiv @" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, req->iv,
+ edesc->src_nents > 1 ? 100 : ivsize, 1);
+ caam_dump_sg(KERN_DEBUG, "dst @" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, req->dst,
+ edesc->dst_nents > 1 ? 100 : req->cryptlen, 1);
+
+ skcipher_unmap(ctx->dev, edesc, req);
+ qi_cache_free(edesc);
+ skcipher_request_complete(req, ecode);
+}
+
+static int skcipher_encrypt(struct skcipher_request *req)
+{
+ struct skcipher_edesc *edesc;
+ struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
+ struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
+ struct caam_request *caam_req = skcipher_request_ctx(req);
+ int ret;
+
+ /* allocate extended descriptor */
+ edesc = skcipher_edesc_alloc(req);
+ if (IS_ERR(edesc))
+ return PTR_ERR(edesc);
+
+ caam_req->flc = &ctx->flc[ENCRYPT];
+ caam_req->flc_dma = ctx->flc_dma[ENCRYPT];
+ caam_req->cbk = skcipher_encrypt_done;
+ caam_req->ctx = &req->base;
+ caam_req->edesc = edesc;
+ ret = dpaa2_caam_enqueue(ctx->dev, caam_req);
+ if (ret != -EINPROGRESS &&
+ !(ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) {
+ skcipher_unmap(ctx->dev, edesc, req);
+ qi_cache_free(edesc);
+ }
+
+ return ret;
+}
+
+static int skcipher_decrypt(struct skcipher_request *req)
+{
+ struct skcipher_edesc *edesc;
+ struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
+ struct caam_ctx *ctx = crypto_skcipher_ctx(skcipher);
+ struct caam_request *caam_req = skcipher_request_ctx(req);
+ int ivsize = crypto_skcipher_ivsize(skcipher);
+ int ret;
+
+ /* allocate extended descriptor */
+ edesc = skcipher_edesc_alloc(req);
+ if (IS_ERR(edesc))
+ return PTR_ERR(edesc);
+
+ /*
+ * The crypto API expects us to set the IV (req->iv) to the last
+ * ciphertext block.
+ */
+ scatterwalk_map_and_copy(req->iv, req->src, req->cryptlen - ivsize,
+ ivsize, 0);
+
+ caam_req->flc = &ctx->flc[DECRYPT];
+ caam_req->flc_dma = ctx->flc_dma[DECRYPT];
+ caam_req->cbk = skcipher_decrypt_done;
+ caam_req->ctx = &req->base;
+ caam_req->edesc = edesc;
+ ret = dpaa2_caam_enqueue(ctx->dev, caam_req);
+ if (ret != -EINPROGRESS &&
+ !(ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) {
+ skcipher_unmap(ctx->dev, edesc, req);
+ qi_cache_free(edesc);
+ }
+
+ return ret;
+}
+
+static int caam_cra_init(struct caam_ctx *ctx, struct caam_alg_entry *caam,
+ bool uses_dkp)
+{
+ dma_addr_t dma_addr;
+ int i;
+
+ /* copy descriptor header template value */
+ ctx->cdata.algtype = OP_TYPE_CLASS1_ALG | caam->class1_alg_type;
+ ctx->adata.algtype = OP_TYPE_CLASS2_ALG | caam->class2_alg_type;
+
+ ctx->dev = caam->dev;
+ ctx->dir = uses_dkp ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE;
+
+ dma_addr = dma_map_single_attrs(ctx->dev, ctx->flc,
+ offsetof(struct caam_ctx, flc_dma),
+ ctx->dir, DMA_ATTR_SKIP_CPU_SYNC);
+ if (dma_mapping_error(ctx->dev, dma_addr)) {
+ dev_err(ctx->dev, "unable to map key, shared descriptors\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < NUM_OP; i++)
+ ctx->flc_dma[i] = dma_addr + i * sizeof(ctx->flc[i]);
+ ctx->key_dma = dma_addr + NUM_OP * sizeof(ctx->flc[0]);
+
+ return 0;
+}
+
+static int caam_cra_init_skcipher(struct crypto_skcipher *tfm)
+{
+ struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
+ struct caam_skcipher_alg *caam_alg =
+ container_of(alg, typeof(*caam_alg), skcipher);
+
+ crypto_skcipher_set_reqsize(tfm, sizeof(struct caam_request));
+ return caam_cra_init(crypto_skcipher_ctx(tfm), &caam_alg->caam, false);
+}
+
+static int caam_cra_init_aead(struct crypto_aead *tfm)
+{
+ struct aead_alg *alg = crypto_aead_alg(tfm);
+ struct caam_aead_alg *caam_alg = container_of(alg, typeof(*caam_alg),
+ aead);
+
+ crypto_aead_set_reqsize(tfm, sizeof(struct caam_request));
+ return caam_cra_init(crypto_aead_ctx(tfm), &caam_alg->caam,
+ alg->setkey == aead_setkey);
+}
+
+static void caam_exit_common(struct caam_ctx *ctx)
+{
+ dma_unmap_single_attrs(ctx->dev, ctx->flc_dma[0],
+ offsetof(struct caam_ctx, flc_dma), ctx->dir,
+ DMA_ATTR_SKIP_CPU_SYNC);
+}
+
+static void caam_cra_exit(struct crypto_skcipher *tfm)
+{
+ caam_exit_common(crypto_skcipher_ctx(tfm));
+}
+
+static void caam_cra_exit_aead(struct crypto_aead *tfm)
+{
+ caam_exit_common(crypto_aead_ctx(tfm));
+}
+
+static struct caam_skcipher_alg driver_algs[] = {
+ {
+ .skcipher = {
+ .base = {
+ .cra_name = "cbc(aes)",
+ .cra_driver_name = "cbc-aes-caam-qi2",
+ .cra_blocksize = AES_BLOCK_SIZE,
+ },
+ .setkey = skcipher_setkey,
+ .encrypt = skcipher_encrypt,
+ .decrypt = skcipher_decrypt,
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ },
+ .caam.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
+ },
+ {
+ .skcipher = {
+ .base = {
+ .cra_name = "cbc(des3_ede)",
+ .cra_driver_name = "cbc-3des-caam-qi2",
+ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
+ },
+ .setkey = skcipher_setkey,
+ .encrypt = skcipher_encrypt,
+ .decrypt = skcipher_decrypt,
+ .min_keysize = DES3_EDE_KEY_SIZE,
+ .max_keysize = DES3_EDE_KEY_SIZE,
+ .ivsize = DES3_EDE_BLOCK_SIZE,
+ },
+ .caam.class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
+ },
+ {
+ .skcipher = {
+ .base = {
+ .cra_name = "cbc(des)",
+ .cra_driver_name = "cbc-des-caam-qi2",
+ .cra_blocksize = DES_BLOCK_SIZE,
+ },
+ .setkey = skcipher_setkey,
+ .encrypt = skcipher_encrypt,
+ .decrypt = skcipher_decrypt,
+ .min_keysize = DES_KEY_SIZE,
+ .max_keysize = DES_KEY_SIZE,
+ .ivsize = DES_BLOCK_SIZE,
+ },
+ .caam.class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
+ },
+ {
+ .skcipher = {
+ .base = {
+ .cra_name = "ctr(aes)",
+ .cra_driver_name = "ctr-aes-caam-qi2",
+ .cra_blocksize = 1,
+ },
+ .setkey = skcipher_setkey,
+ .encrypt = skcipher_encrypt,
+ .decrypt = skcipher_decrypt,
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .chunksize = AES_BLOCK_SIZE,
+ },
+ .caam.class1_alg_type = OP_ALG_ALGSEL_AES |
+ OP_ALG_AAI_CTR_MOD128,
+ },
+ {
+ .skcipher = {
+ .base = {
+ .cra_name = "rfc3686(ctr(aes))",
+ .cra_driver_name = "rfc3686-ctr-aes-caam-qi2",
+ .cra_blocksize = 1,
+ },
+ .setkey = skcipher_setkey,
+ .encrypt = skcipher_encrypt,
+ .decrypt = skcipher_decrypt,
+ .min_keysize = AES_MIN_KEY_SIZE +
+ CTR_RFC3686_NONCE_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE +
+ CTR_RFC3686_NONCE_SIZE,
+ .ivsize = CTR_RFC3686_IV_SIZE,
+ .chunksize = AES_BLOCK_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_AES |
+ OP_ALG_AAI_CTR_MOD128,
+ .rfc3686 = true,
+ },
+ },
+ {
+ .skcipher = {
+ .base = {
+ .cra_name = "xts(aes)",
+ .cra_driver_name = "xts-aes-caam-qi2",
+ .cra_blocksize = AES_BLOCK_SIZE,
+ },
+ .setkey = xts_skcipher_setkey,
+ .encrypt = skcipher_encrypt,
+ .decrypt = skcipher_decrypt,
+ .min_keysize = 2 * AES_MIN_KEY_SIZE,
+ .max_keysize = 2 * AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ },
+ .caam.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_XTS,
+ }
+};
+
+static struct caam_aead_alg driver_aeads[] = {
+ {
+ .aead = {
+ .base = {
+ .cra_name = "rfc4106(gcm(aes))",
+ .cra_driver_name = "rfc4106-gcm-aes-caam-qi2",
+ .cra_blocksize = 1,
+ },
+ .setkey = rfc4106_setkey,
+ .setauthsize = rfc4106_setauthsize,
+ .encrypt = ipsec_gcm_encrypt,
+ .decrypt = ipsec_gcm_decrypt,
+ .ivsize = 8,
+ .maxauthsize = AES_BLOCK_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM,
+ },
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "rfc4543(gcm(aes))",
+ .cra_driver_name = "rfc4543-gcm-aes-caam-qi2",
+ .cra_blocksize = 1,
+ },
+ .setkey = rfc4543_setkey,
+ .setauthsize = rfc4543_setauthsize,
+ .encrypt = ipsec_gcm_encrypt,
+ .decrypt = ipsec_gcm_decrypt,
+ .ivsize = 8,
+ .maxauthsize = AES_BLOCK_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM,
+ },
+ },
+ /* Galois Counter Mode */
+ {
+ .aead = {
+ .base = {
+ .cra_name = "gcm(aes)",
+ .cra_driver_name = "gcm-aes-caam-qi2",
+ .cra_blocksize = 1,
+ },
+ .setkey = gcm_setkey,
+ .setauthsize = gcm_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = 12,
+ .maxauthsize = AES_BLOCK_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM,
+ }
+ },
+ /* single-pass ipsec_esp descriptor */
+ {
+ .aead = {
+ .base = {
+ .cra_name = "authenc(hmac(md5),cbc(aes))",
+ .cra_driver_name = "authenc-hmac-md5-"
+ "cbc-aes-caam-qi2",
+ .cra_blocksize = AES_BLOCK_SIZE,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = AES_BLOCK_SIZE,
+ .maxauthsize = MD5_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_MD5 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ }
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "echainiv(authenc(hmac(md5),"
+ "cbc(aes)))",
+ .cra_driver_name = "echainiv-authenc-hmac-md5-"
+ "cbc-aes-caam-qi2",
+ .cra_blocksize = AES_BLOCK_SIZE,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = AES_BLOCK_SIZE,
+ .maxauthsize = MD5_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_MD5 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .geniv = true,
+ }
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "authenc(hmac(sha1),cbc(aes))",
+ .cra_driver_name = "authenc-hmac-sha1-"
+ "cbc-aes-caam-qi2",
+ .cra_blocksize = AES_BLOCK_SIZE,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = AES_BLOCK_SIZE,
+ .maxauthsize = SHA1_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA1 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ }
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "echainiv(authenc(hmac(sha1),"
+ "cbc(aes)))",
+ .cra_driver_name = "echainiv-authenc-"
+ "hmac-sha1-cbc-aes-caam-qi2",
+ .cra_blocksize = AES_BLOCK_SIZE,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = AES_BLOCK_SIZE,
+ .maxauthsize = SHA1_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA1 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .geniv = true,
+ },
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "authenc(hmac(sha224),cbc(aes))",
+ .cra_driver_name = "authenc-hmac-sha224-"
+ "cbc-aes-caam-qi2",
+ .cra_blocksize = AES_BLOCK_SIZE,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = AES_BLOCK_SIZE,
+ .maxauthsize = SHA224_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA224 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ }
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "echainiv(authenc(hmac(sha224),"
+ "cbc(aes)))",
+ .cra_driver_name = "echainiv-authenc-"
+ "hmac-sha224-cbc-aes-caam-qi2",
+ .cra_blocksize = AES_BLOCK_SIZE,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = AES_BLOCK_SIZE,
+ .maxauthsize = SHA224_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA224 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .geniv = true,
+ }
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "authenc(hmac(sha256),cbc(aes))",
+ .cra_driver_name = "authenc-hmac-sha256-"
+ "cbc-aes-caam-qi2",
+ .cra_blocksize = AES_BLOCK_SIZE,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = AES_BLOCK_SIZE,
+ .maxauthsize = SHA256_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA256 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ }
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "echainiv(authenc(hmac(sha256),"
+ "cbc(aes)))",
+ .cra_driver_name = "echainiv-authenc-"
+ "hmac-sha256-cbc-aes-"
+ "caam-qi2",
+ .cra_blocksize = AES_BLOCK_SIZE,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = AES_BLOCK_SIZE,
+ .maxauthsize = SHA256_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA256 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .geniv = true,
+ }
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "authenc(hmac(sha384),cbc(aes))",
+ .cra_driver_name = "authenc-hmac-sha384-"
+ "cbc-aes-caam-qi2",
+ .cra_blocksize = AES_BLOCK_SIZE,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = AES_BLOCK_SIZE,
+ .maxauthsize = SHA384_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA384 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ }
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "echainiv(authenc(hmac(sha384),"
+ "cbc(aes)))",
+ .cra_driver_name = "echainiv-authenc-"
+ "hmac-sha384-cbc-aes-"
+ "caam-qi2",
+ .cra_blocksize = AES_BLOCK_SIZE,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = AES_BLOCK_SIZE,
+ .maxauthsize = SHA384_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA384 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .geniv = true,
+ }
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "authenc(hmac(sha512),cbc(aes))",
+ .cra_driver_name = "authenc-hmac-sha512-"
+ "cbc-aes-caam-qi2",
+ .cra_blocksize = AES_BLOCK_SIZE,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = AES_BLOCK_SIZE,
+ .maxauthsize = SHA512_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA512 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ }
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "echainiv(authenc(hmac(sha512),"
+ "cbc(aes)))",
+ .cra_driver_name = "echainiv-authenc-"
+ "hmac-sha512-cbc-aes-"
+ "caam-qi2",
+ .cra_blocksize = AES_BLOCK_SIZE,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = AES_BLOCK_SIZE,
+ .maxauthsize = SHA512_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA512 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .geniv = true,
+ }
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "authenc(hmac(md5),cbc(des3_ede))",
+ .cra_driver_name = "authenc-hmac-md5-"
+ "cbc-des3_ede-caam-qi2",
+ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = DES3_EDE_BLOCK_SIZE,
+ .maxauthsize = MD5_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_MD5 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ }
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "echainiv(authenc(hmac(md5),"
+ "cbc(des3_ede)))",
+ .cra_driver_name = "echainiv-authenc-hmac-md5-"
+ "cbc-des3_ede-caam-qi2",
+ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = DES3_EDE_BLOCK_SIZE,
+ .maxauthsize = MD5_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_MD5 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .geniv = true,
+ }
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "authenc(hmac(sha1),"
+ "cbc(des3_ede))",
+ .cra_driver_name = "authenc-hmac-sha1-"
+ "cbc-des3_ede-caam-qi2",
+ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = DES3_EDE_BLOCK_SIZE,
+ .maxauthsize = SHA1_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA1 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ },
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "echainiv(authenc(hmac(sha1),"
+ "cbc(des3_ede)))",
+ .cra_driver_name = "echainiv-authenc-"
+ "hmac-sha1-"
+ "cbc-des3_ede-caam-qi2",
+ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = DES3_EDE_BLOCK_SIZE,
+ .maxauthsize = SHA1_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA1 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .geniv = true,
+ }
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "authenc(hmac(sha224),"
+ "cbc(des3_ede))",
+ .cra_driver_name = "authenc-hmac-sha224-"
+ "cbc-des3_ede-caam-qi2",
+ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = DES3_EDE_BLOCK_SIZE,
+ .maxauthsize = SHA224_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA224 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ },
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "echainiv(authenc(hmac(sha224),"
+ "cbc(des3_ede)))",
+ .cra_driver_name = "echainiv-authenc-"
+ "hmac-sha224-"
+ "cbc-des3_ede-caam-qi2",
+ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = DES3_EDE_BLOCK_SIZE,
+ .maxauthsize = SHA224_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA224 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .geniv = true,
+ }
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "authenc(hmac(sha256),"
+ "cbc(des3_ede))",
+ .cra_driver_name = "authenc-hmac-sha256-"
+ "cbc-des3_ede-caam-qi2",
+ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = DES3_EDE_BLOCK_SIZE,
+ .maxauthsize = SHA256_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA256 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ },
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "echainiv(authenc(hmac(sha256),"
+ "cbc(des3_ede)))",
+ .cra_driver_name = "echainiv-authenc-"
+ "hmac-sha256-"
+ "cbc-des3_ede-caam-qi2",
+ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = DES3_EDE_BLOCK_SIZE,
+ .maxauthsize = SHA256_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA256 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .geniv = true,
+ }
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "authenc(hmac(sha384),"
+ "cbc(des3_ede))",
+ .cra_driver_name = "authenc-hmac-sha384-"
+ "cbc-des3_ede-caam-qi2",
+ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = DES3_EDE_BLOCK_SIZE,
+ .maxauthsize = SHA384_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA384 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ },
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "echainiv(authenc(hmac(sha384),"
+ "cbc(des3_ede)))",
+ .cra_driver_name = "echainiv-authenc-"
+ "hmac-sha384-"
+ "cbc-des3_ede-caam-qi2",
+ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = DES3_EDE_BLOCK_SIZE,
+ .maxauthsize = SHA384_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA384 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .geniv = true,
+ }
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "authenc(hmac(sha512),"
+ "cbc(des3_ede))",
+ .cra_driver_name = "authenc-hmac-sha512-"
+ "cbc-des3_ede-caam-qi2",
+ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = DES3_EDE_BLOCK_SIZE,
+ .maxauthsize = SHA512_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA512 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ },
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "echainiv(authenc(hmac(sha512),"
+ "cbc(des3_ede)))",
+ .cra_driver_name = "echainiv-authenc-"
+ "hmac-sha512-"
+ "cbc-des3_ede-caam-qi2",
+ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = DES3_EDE_BLOCK_SIZE,
+ .maxauthsize = SHA512_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA512 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .geniv = true,
+ }
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "authenc(hmac(md5),cbc(des))",
+ .cra_driver_name = "authenc-hmac-md5-"
+ "cbc-des-caam-qi2",
+ .cra_blocksize = DES_BLOCK_SIZE,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = DES_BLOCK_SIZE,
+ .maxauthsize = MD5_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_MD5 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ },
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "echainiv(authenc(hmac(md5),"
+ "cbc(des)))",
+ .cra_driver_name = "echainiv-authenc-hmac-md5-"
+ "cbc-des-caam-qi2",
+ .cra_blocksize = DES_BLOCK_SIZE,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = DES_BLOCK_SIZE,
+ .maxauthsize = MD5_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_MD5 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .geniv = true,
+ }
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "authenc(hmac(sha1),cbc(des))",
+ .cra_driver_name = "authenc-hmac-sha1-"
+ "cbc-des-caam-qi2",
+ .cra_blocksize = DES_BLOCK_SIZE,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = DES_BLOCK_SIZE,
+ .maxauthsize = SHA1_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA1 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ },
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "echainiv(authenc(hmac(sha1),"
+ "cbc(des)))",
+ .cra_driver_name = "echainiv-authenc-"
+ "hmac-sha1-cbc-des-caam-qi2",
+ .cra_blocksize = DES_BLOCK_SIZE,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = DES_BLOCK_SIZE,
+ .maxauthsize = SHA1_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA1 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .geniv = true,
+ }
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "authenc(hmac(sha224),cbc(des))",
+ .cra_driver_name = "authenc-hmac-sha224-"
+ "cbc-des-caam-qi2",
+ .cra_blocksize = DES_BLOCK_SIZE,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = DES_BLOCK_SIZE,
+ .maxauthsize = SHA224_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA224 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ },
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "echainiv(authenc(hmac(sha224),"
+ "cbc(des)))",
+ .cra_driver_name = "echainiv-authenc-"
+ "hmac-sha224-cbc-des-"
+ "caam-qi2",
+ .cra_blocksize = DES_BLOCK_SIZE,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = DES_BLOCK_SIZE,
+ .maxauthsize = SHA224_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA224 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .geniv = true,
+ }
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "authenc(hmac(sha256),cbc(des))",
+ .cra_driver_name = "authenc-hmac-sha256-"
+ "cbc-des-caam-qi2",
+ .cra_blocksize = DES_BLOCK_SIZE,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = DES_BLOCK_SIZE,
+ .maxauthsize = SHA256_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA256 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ },
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "echainiv(authenc(hmac(sha256),"
+ "cbc(des)))",
+ .cra_driver_name = "echainiv-authenc-"
+ "hmac-sha256-cbc-desi-"
+ "caam-qi2",
+ .cra_blocksize = DES_BLOCK_SIZE,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = DES_BLOCK_SIZE,
+ .maxauthsize = SHA256_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA256 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .geniv = true,
+ },
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "authenc(hmac(sha384),cbc(des))",
+ .cra_driver_name = "authenc-hmac-sha384-"
+ "cbc-des-caam-qi2",
+ .cra_blocksize = DES_BLOCK_SIZE,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = DES_BLOCK_SIZE,
+ .maxauthsize = SHA384_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA384 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ },
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "echainiv(authenc(hmac(sha384),"
+ "cbc(des)))",
+ .cra_driver_name = "echainiv-authenc-"
+ "hmac-sha384-cbc-des-"
+ "caam-qi2",
+ .cra_blocksize = DES_BLOCK_SIZE,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = DES_BLOCK_SIZE,
+ .maxauthsize = SHA384_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA384 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .geniv = true,
+ }
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "authenc(hmac(sha512),cbc(des))",
+ .cra_driver_name = "authenc-hmac-sha512-"
+ "cbc-des-caam-qi2",
+ .cra_blocksize = DES_BLOCK_SIZE,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = DES_BLOCK_SIZE,
+ .maxauthsize = SHA512_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA512 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ }
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "echainiv(authenc(hmac(sha512),"
+ "cbc(des)))",
+ .cra_driver_name = "echainiv-authenc-"
+ "hmac-sha512-cbc-des-"
+ "caam-qi2",
+ .cra_blocksize = DES_BLOCK_SIZE,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = DES_BLOCK_SIZE,
+ .maxauthsize = SHA512_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA512 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .geniv = true,
+ }
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "authenc(hmac(md5),"
+ "rfc3686(ctr(aes)))",
+ .cra_driver_name = "authenc-hmac-md5-"
+ "rfc3686-ctr-aes-caam-qi2",
+ .cra_blocksize = 1,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = CTR_RFC3686_IV_SIZE,
+ .maxauthsize = MD5_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_AES |
+ OP_ALG_AAI_CTR_MOD128,
+ .class2_alg_type = OP_ALG_ALGSEL_MD5 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .rfc3686 = true,
+ },
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "seqiv(authenc("
+ "hmac(md5),rfc3686(ctr(aes))))",
+ .cra_driver_name = "seqiv-authenc-hmac-md5-"
+ "rfc3686-ctr-aes-caam-qi2",
+ .cra_blocksize = 1,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = CTR_RFC3686_IV_SIZE,
+ .maxauthsize = MD5_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_AES |
+ OP_ALG_AAI_CTR_MOD128,
+ .class2_alg_type = OP_ALG_ALGSEL_MD5 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .rfc3686 = true,
+ .geniv = true,
+ },
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "authenc(hmac(sha1),"
+ "rfc3686(ctr(aes)))",
+ .cra_driver_name = "authenc-hmac-sha1-"
+ "rfc3686-ctr-aes-caam-qi2",
+ .cra_blocksize = 1,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = CTR_RFC3686_IV_SIZE,
+ .maxauthsize = SHA1_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_AES |
+ OP_ALG_AAI_CTR_MOD128,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA1 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .rfc3686 = true,
+ },
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "seqiv(authenc("
+ "hmac(sha1),rfc3686(ctr(aes))))",
+ .cra_driver_name = "seqiv-authenc-hmac-sha1-"
+ "rfc3686-ctr-aes-caam-qi2",
+ .cra_blocksize = 1,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = CTR_RFC3686_IV_SIZE,
+ .maxauthsize = SHA1_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_AES |
+ OP_ALG_AAI_CTR_MOD128,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA1 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .rfc3686 = true,
+ .geniv = true,
+ },
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "authenc(hmac(sha224),"
+ "rfc3686(ctr(aes)))",
+ .cra_driver_name = "authenc-hmac-sha224-"
+ "rfc3686-ctr-aes-caam-qi2",
+ .cra_blocksize = 1,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = CTR_RFC3686_IV_SIZE,
+ .maxauthsize = SHA224_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_AES |
+ OP_ALG_AAI_CTR_MOD128,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA224 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .rfc3686 = true,
+ },
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "seqiv(authenc("
+ "hmac(sha224),rfc3686(ctr(aes))))",
+ .cra_driver_name = "seqiv-authenc-hmac-sha224-"
+ "rfc3686-ctr-aes-caam-qi2",
+ .cra_blocksize = 1,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = CTR_RFC3686_IV_SIZE,
+ .maxauthsize = SHA224_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_AES |
+ OP_ALG_AAI_CTR_MOD128,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA224 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .rfc3686 = true,
+ .geniv = true,
+ },
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "authenc(hmac(sha256),"
+ "rfc3686(ctr(aes)))",
+ .cra_driver_name = "authenc-hmac-sha256-"
+ "rfc3686-ctr-aes-caam-qi2",
+ .cra_blocksize = 1,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = CTR_RFC3686_IV_SIZE,
+ .maxauthsize = SHA256_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_AES |
+ OP_ALG_AAI_CTR_MOD128,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA256 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .rfc3686 = true,
+ },
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "seqiv(authenc(hmac(sha256),"
+ "rfc3686(ctr(aes))))",
+ .cra_driver_name = "seqiv-authenc-hmac-sha256-"
+ "rfc3686-ctr-aes-caam-qi2",
+ .cra_blocksize = 1,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = CTR_RFC3686_IV_SIZE,
+ .maxauthsize = SHA256_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_AES |
+ OP_ALG_AAI_CTR_MOD128,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA256 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .rfc3686 = true,
+ .geniv = true,
+ },
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "authenc(hmac(sha384),"
+ "rfc3686(ctr(aes)))",
+ .cra_driver_name = "authenc-hmac-sha384-"
+ "rfc3686-ctr-aes-caam-qi2",
+ .cra_blocksize = 1,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = CTR_RFC3686_IV_SIZE,
+ .maxauthsize = SHA384_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_AES |
+ OP_ALG_AAI_CTR_MOD128,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA384 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .rfc3686 = true,
+ },
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "seqiv(authenc(hmac(sha384),"
+ "rfc3686(ctr(aes))))",
+ .cra_driver_name = "seqiv-authenc-hmac-sha384-"
+ "rfc3686-ctr-aes-caam-qi2",
+ .cra_blocksize = 1,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = CTR_RFC3686_IV_SIZE,
+ .maxauthsize = SHA384_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_AES |
+ OP_ALG_AAI_CTR_MOD128,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA384 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .rfc3686 = true,
+ .geniv = true,
+ },
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "authenc(hmac(sha512),"
+ "rfc3686(ctr(aes)))",
+ .cra_driver_name = "authenc-hmac-sha512-"
+ "rfc3686-ctr-aes-caam-qi2",
+ .cra_blocksize = 1,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = CTR_RFC3686_IV_SIZE,
+ .maxauthsize = SHA512_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_AES |
+ OP_ALG_AAI_CTR_MOD128,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA512 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .rfc3686 = true,
+ },
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "seqiv(authenc(hmac(sha512),"
+ "rfc3686(ctr(aes))))",
+ .cra_driver_name = "seqiv-authenc-hmac-sha512-"
+ "rfc3686-ctr-aes-caam-qi2",
+ .cra_blocksize = 1,
+ },
+ .setkey = aead_setkey,
+ .setauthsize = aead_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = CTR_RFC3686_IV_SIZE,
+ .maxauthsize = SHA512_DIGEST_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_AES |
+ OP_ALG_AAI_CTR_MOD128,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA512 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .rfc3686 = true,
+ .geniv = true,
+ },
+ },
+};
+
+static void caam_skcipher_alg_init(struct caam_skcipher_alg *t_alg)
+{
+ struct skcipher_alg *alg = &t_alg->skcipher;
+
+ alg->base.cra_module = THIS_MODULE;
+ alg->base.cra_priority = CAAM_CRA_PRIORITY;
+ alg->base.cra_ctxsize = sizeof(struct caam_ctx);
+ alg->base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY;
+
+ alg->init = caam_cra_init_skcipher;
+ alg->exit = caam_cra_exit;
+}
+
+static void caam_aead_alg_init(struct caam_aead_alg *t_alg)
+{
+ struct aead_alg *alg = &t_alg->aead;
+
+ alg->base.cra_module = THIS_MODULE;
+ alg->base.cra_priority = CAAM_CRA_PRIORITY;
+ alg->base.cra_ctxsize = sizeof(struct caam_ctx);
+ alg->base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY;
+
+ alg->init = caam_cra_init_aead;
+ alg->exit = caam_cra_exit_aead;
+}
+
+/* max hash key is max split key size */
+#define CAAM_MAX_HASH_KEY_SIZE (SHA512_DIGEST_SIZE * 2)
+
+#define CAAM_MAX_HASH_BLOCK_SIZE SHA512_BLOCK_SIZE
+
+/* caam context sizes for hashes: running digest + 8 */
+#define HASH_MSG_LEN 8
+#define MAX_CTX_LEN (HASH_MSG_LEN + SHA512_DIGEST_SIZE)
+
+enum hash_optype {
+ UPDATE = 0,
+ UPDATE_FIRST,
+ FINALIZE,
+ DIGEST,
+ HASH_NUM_OP
+};
+
+/**
+ * caam_hash_ctx - ahash per-session context
+ * @flc: Flow Contexts array
+ * @flc_dma: I/O virtual addresses of the Flow Contexts
+ * @dev: dpseci device
+ * @ctx_len: size of Context Register
+ * @adata: hashing algorithm details
+ */
+struct caam_hash_ctx {
+ struct caam_flc flc[HASH_NUM_OP];
+ dma_addr_t flc_dma[HASH_NUM_OP];
+ struct device *dev;
+ int ctx_len;
+ struct alginfo adata;
+};
+
+/* ahash state */
+struct caam_hash_state {
+ struct caam_request caam_req;
+ dma_addr_t buf_dma;
+ dma_addr_t ctx_dma;
+ u8 buf_0[CAAM_MAX_HASH_BLOCK_SIZE] ____cacheline_aligned;
+ int buflen_0;
+ u8 buf_1[CAAM_MAX_HASH_BLOCK_SIZE] ____cacheline_aligned;
+ int buflen_1;
+ u8 caam_ctx[MAX_CTX_LEN] ____cacheline_aligned;
+ int (*update)(struct ahash_request *req);
+ int (*final)(struct ahash_request *req);
+ int (*finup)(struct ahash_request *req);
+ int current_buf;
+};
+
+struct caam_export_state {
+ u8 buf[CAAM_MAX_HASH_BLOCK_SIZE];
+ u8 caam_ctx[MAX_CTX_LEN];
+ int buflen;
+ int (*update)(struct ahash_request *req);
+ int (*final)(struct ahash_request *req);
+ int (*finup)(struct ahash_request *req);
+};
+
+static inline void switch_buf(struct caam_hash_state *state)
+{
+ state->current_buf ^= 1;
+}
+
+static inline u8 *current_buf(struct caam_hash_state *state)
+{
+ return state->current_buf ? state->buf_1 : state->buf_0;
+}
+
+static inline u8 *alt_buf(struct caam_hash_state *state)
+{
+ return state->current_buf ? state->buf_0 : state->buf_1;
+}
+
+static inline int *current_buflen(struct caam_hash_state *state)
+{
+ return state->current_buf ? &state->buflen_1 : &state->buflen_0;
+}
+
+static inline int *alt_buflen(struct caam_hash_state *state)
+{
+ return state->current_buf ? &state->buflen_0 : &state->buflen_1;
+}
+
+/* Map current buffer in state (if length > 0) and put it in link table */
+static inline int buf_map_to_qm_sg(struct device *dev,
+ struct dpaa2_sg_entry *qm_sg,
+ struct caam_hash_state *state)
+{
+ int buflen = *current_buflen(state);
+
+ if (!buflen)
+ return 0;
+
+ state->buf_dma = dma_map_single(dev, current_buf(state), buflen,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, state->buf_dma)) {
+ dev_err(dev, "unable to map buf\n");
+ state->buf_dma = 0;
+ return -ENOMEM;
+ }
+
+ dma_to_qm_sg_one(qm_sg, state->buf_dma, buflen, 0);
+
+ return 0;
+}
+
+/* Map state->caam_ctx, and add it to link table */
+static inline int ctx_map_to_qm_sg(struct device *dev,
+ struct caam_hash_state *state, int ctx_len,
+ struct dpaa2_sg_entry *qm_sg, u32 flag)
+{
+ state->ctx_dma = dma_map_single(dev, state->caam_ctx, ctx_len, flag);
+ if (dma_mapping_error(dev, state->ctx_dma)) {
+ dev_err(dev, "unable to map ctx\n");
+ state->ctx_dma = 0;
+ return -ENOMEM;
+ }
+
+ dma_to_qm_sg_one(qm_sg, state->ctx_dma, ctx_len, 0);
+
+ return 0;
+}
+
+static int ahash_set_sh_desc(struct crypto_ahash *ahash)
+{
+ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
+ int digestsize = crypto_ahash_digestsize(ahash);
+ struct dpaa2_caam_priv *priv = dev_get_drvdata(ctx->dev);
+ struct caam_flc *flc;
+ u32 *desc;
+
+ /* ahash_update shared descriptor */
+ flc = &ctx->flc[UPDATE];
+ desc = flc->sh_desc;
+ cnstr_shdsc_ahash(desc, &ctx->adata, OP_ALG_AS_UPDATE, ctx->ctx_len,
+ ctx->ctx_len, true, priv->sec_attr.era);
+ flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
+ dma_sync_single_for_device(ctx->dev, ctx->flc_dma[UPDATE],
+ desc_bytes(desc), DMA_BIDIRECTIONAL);
+ print_hex_dump_debug("ahash update shdesc@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc),
+ 1);
+
+ /* ahash_update_first shared descriptor */
+ flc = &ctx->flc[UPDATE_FIRST];
+ desc = flc->sh_desc;
+ cnstr_shdsc_ahash(desc, &ctx->adata, OP_ALG_AS_INIT, ctx->ctx_len,
+ ctx->ctx_len, false, priv->sec_attr.era);
+ flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
+ dma_sync_single_for_device(ctx->dev, ctx->flc_dma[UPDATE_FIRST],
+ desc_bytes(desc), DMA_BIDIRECTIONAL);
+ print_hex_dump_debug("ahash update first shdesc@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc),
+ 1);
+
+ /* ahash_final shared descriptor */
+ flc = &ctx->flc[FINALIZE];
+ desc = flc->sh_desc;
+ cnstr_shdsc_ahash(desc, &ctx->adata, OP_ALG_AS_FINALIZE, digestsize,
+ ctx->ctx_len, true, priv->sec_attr.era);
+ flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
+ dma_sync_single_for_device(ctx->dev, ctx->flc_dma[FINALIZE],
+ desc_bytes(desc), DMA_BIDIRECTIONAL);
+ print_hex_dump_debug("ahash final shdesc@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc),
+ 1);
+
+ /* ahash_digest shared descriptor */
+ flc = &ctx->flc[DIGEST];
+ desc = flc->sh_desc;
+ cnstr_shdsc_ahash(desc, &ctx->adata, OP_ALG_AS_INITFINAL, digestsize,
+ ctx->ctx_len, false, priv->sec_attr.era);
+ flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
+ dma_sync_single_for_device(ctx->dev, ctx->flc_dma[DIGEST],
+ desc_bytes(desc), DMA_BIDIRECTIONAL);
+ print_hex_dump_debug("ahash digest shdesc@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc),
+ 1);
+
+ return 0;
+}
+
+struct split_key_sh_result {
+ struct completion completion;
+ int err;
+ struct device *dev;
+};
+
+static void split_key_sh_done(void *cbk_ctx, u32 err)
+{
+ struct split_key_sh_result *res = cbk_ctx;
+
+ dev_dbg(res->dev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
+
+ if (err)
+ caam_qi2_strstatus(res->dev, err);
+
+ res->err = err;
+ complete(&res->completion);
+}
+
+/* Digest hash size if it is too large */
+static int hash_digest_key(struct caam_hash_ctx *ctx, const u8 *key_in,
+ u32 *keylen, u8 *key_out, u32 digestsize)
+{
+ struct caam_request *req_ctx;
+ u32 *desc;
+ struct split_key_sh_result result;
+ dma_addr_t src_dma, dst_dma;
+ struct caam_flc *flc;
+ dma_addr_t flc_dma;
+ int ret = -ENOMEM;
+ struct dpaa2_fl_entry *in_fle, *out_fle;
+
+ req_ctx = kzalloc(sizeof(*req_ctx), GFP_KERNEL | GFP_DMA);
+ if (!req_ctx)
+ return -ENOMEM;
+
+ in_fle = &req_ctx->fd_flt[1];
+ out_fle = &req_ctx->fd_flt[0];
+
+ flc = kzalloc(sizeof(*flc), GFP_KERNEL | GFP_DMA);
+ if (!flc)
+ goto err_flc;
+
+ src_dma = dma_map_single(ctx->dev, (void *)key_in, *keylen,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(ctx->dev, src_dma)) {
+ dev_err(ctx->dev, "unable to map key input memory\n");
+ goto err_src_dma;
+ }
+ dst_dma = dma_map_single(ctx->dev, (void *)key_out, digestsize,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(ctx->dev, dst_dma)) {
+ dev_err(ctx->dev, "unable to map key output memory\n");
+ goto err_dst_dma;
+ }
+
+ desc = flc->sh_desc;
+
+ init_sh_desc(desc, 0);
+
+ /* descriptor to perform unkeyed hash on key_in */
+ append_operation(desc, ctx->adata.algtype | OP_ALG_ENCRYPT |
+ OP_ALG_AS_INITFINAL);
+ append_seq_fifo_load(desc, *keylen, FIFOLD_CLASS_CLASS2 |
+ FIFOLD_TYPE_LAST2 | FIFOLD_TYPE_MSG);
+ append_seq_store(desc, digestsize, LDST_CLASS_2_CCB |
+ LDST_SRCDST_BYTE_CONTEXT);
+
+ flc->flc[1] = cpu_to_caam32(desc_len(desc)); /* SDL */
+ flc_dma = dma_map_single(ctx->dev, flc, sizeof(flc->flc) +
+ desc_bytes(desc), DMA_TO_DEVICE);
+ if (dma_mapping_error(ctx->dev, flc_dma)) {
+ dev_err(ctx->dev, "unable to map shared descriptor\n");
+ goto err_flc_dma;
+ }
+
+ dpaa2_fl_set_final(in_fle, true);
+ dpaa2_fl_set_format(in_fle, dpaa2_fl_single);
+ dpaa2_fl_set_addr(in_fle, src_dma);
+ dpaa2_fl_set_len(in_fle, *keylen);
+ dpaa2_fl_set_format(out_fle, dpaa2_fl_single);
+ dpaa2_fl_set_addr(out_fle, dst_dma);
+ dpaa2_fl_set_len(out_fle, digestsize);
+
+ print_hex_dump_debug("key_in@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, key_in, *keylen, 1);
+ print_hex_dump_debug("shdesc@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc),
+ 1);
+
+ result.err = 0;
+ init_completion(&result.completion);
+ result.dev = ctx->dev;
+
+ req_ctx->flc = flc;
+ req_ctx->flc_dma = flc_dma;
+ req_ctx->cbk = split_key_sh_done;
+ req_ctx->ctx = &result;
+
+ ret = dpaa2_caam_enqueue(ctx->dev, req_ctx);
+ if (ret == -EINPROGRESS) {
+ /* in progress */
+ wait_for_completion(&result.completion);
+ ret = result.err;
+ print_hex_dump_debug("digested key@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, key_in,
+ digestsize, 1);
+ }
+
+ dma_unmap_single(ctx->dev, flc_dma, sizeof(flc->flc) + desc_bytes(desc),
+ DMA_TO_DEVICE);
+err_flc_dma:
+ dma_unmap_single(ctx->dev, dst_dma, digestsize, DMA_FROM_DEVICE);
+err_dst_dma:
+ dma_unmap_single(ctx->dev, src_dma, *keylen, DMA_TO_DEVICE);
+err_src_dma:
+ kfree(flc);
+err_flc:
+ kfree(req_ctx);
+
+ *keylen = digestsize;
+
+ return ret;
+}
+
+static int ahash_setkey(struct crypto_ahash *ahash, const u8 *key,
+ unsigned int keylen)
+{
+ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
+ unsigned int blocksize = crypto_tfm_alg_blocksize(&ahash->base);
+ unsigned int digestsize = crypto_ahash_digestsize(ahash);
+ int ret;
+ u8 *hashed_key = NULL;
+
+ dev_dbg(ctx->dev, "keylen %d blocksize %d\n", keylen, blocksize);
+
+ if (keylen > blocksize) {
+ hashed_key = kmalloc_array(digestsize, sizeof(*hashed_key),
+ GFP_KERNEL | GFP_DMA);
+ if (!hashed_key)
+ return -ENOMEM;
+ ret = hash_digest_key(ctx, key, &keylen, hashed_key,
+ digestsize);
+ if (ret)
+ goto bad_free_key;
+ key = hashed_key;
+ }
+
+ ctx->adata.keylen = keylen;
+ ctx->adata.keylen_pad = split_key_len(ctx->adata.algtype &
+ OP_ALG_ALGSEL_MASK);
+ if (ctx->adata.keylen_pad > CAAM_MAX_HASH_KEY_SIZE)
+ goto bad_free_key;
+
+ ctx->adata.key_virt = key;
+ ctx->adata.key_inline = true;
+
+ ret = ahash_set_sh_desc(ahash);
+ kfree(hashed_key);
+ return ret;
+bad_free_key:
+ kfree(hashed_key);
+ crypto_ahash_set_flags(ahash, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ return -EINVAL;
+}
+
+static inline void ahash_unmap(struct device *dev, struct ahash_edesc *edesc,
+ struct ahash_request *req, int dst_len)
+{
+ struct caam_hash_state *state = ahash_request_ctx(req);
+
+ if (edesc->src_nents)
+ dma_unmap_sg(dev, req->src, edesc->src_nents, DMA_TO_DEVICE);
+ if (edesc->dst_dma)
+ dma_unmap_single(dev, edesc->dst_dma, dst_len, DMA_FROM_DEVICE);
+
+ if (edesc->qm_sg_bytes)
+ dma_unmap_single(dev, edesc->qm_sg_dma, edesc->qm_sg_bytes,
+ DMA_TO_DEVICE);
+
+ if (state->buf_dma) {
+ dma_unmap_single(dev, state->buf_dma, *current_buflen(state),
+ DMA_TO_DEVICE);
+ state->buf_dma = 0;
+ }
+}
+
+static inline void ahash_unmap_ctx(struct device *dev,
+ struct ahash_edesc *edesc,
+ struct ahash_request *req, int dst_len,
+ u32 flag)
+{
+ struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
+ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
+ struct caam_hash_state *state = ahash_request_ctx(req);
+
+ if (state->ctx_dma) {
+ dma_unmap_single(dev, state->ctx_dma, ctx->ctx_len, flag);
+ state->ctx_dma = 0;
+ }
+ ahash_unmap(dev, edesc, req, dst_len);
+}
+
+static void ahash_done(void *cbk_ctx, u32 status)
+{
+ struct crypto_async_request *areq = cbk_ctx;
+ struct ahash_request *req = ahash_request_cast(areq);
+ struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
+ struct caam_hash_state *state = ahash_request_ctx(req);
+ struct ahash_edesc *edesc = state->caam_req.edesc;
+ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
+ int digestsize = crypto_ahash_digestsize(ahash);
+ int ecode = 0;
+
+ dev_dbg(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status);
+
+ if (unlikely(status)) {
+ caam_qi2_strstatus(ctx->dev, status);
+ ecode = -EIO;
+ }
+
+ ahash_unmap(ctx->dev, edesc, req, digestsize);
+ qi_cache_free(edesc);
+
+ print_hex_dump_debug("ctx@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx,
+ ctx->ctx_len, 1);
+ if (req->result)
+ print_hex_dump_debug("result@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, req->result,
+ digestsize, 1);
+
+ req->base.complete(&req->base, ecode);
+}
+
+static void ahash_done_bi(void *cbk_ctx, u32 status)
+{
+ struct crypto_async_request *areq = cbk_ctx;
+ struct ahash_request *req = ahash_request_cast(areq);
+ struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
+ struct caam_hash_state *state = ahash_request_ctx(req);
+ struct ahash_edesc *edesc = state->caam_req.edesc;
+ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
+ int ecode = 0;
+
+ dev_dbg(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status);
+
+ if (unlikely(status)) {
+ caam_qi2_strstatus(ctx->dev, status);
+ ecode = -EIO;
+ }
+
+ ahash_unmap_ctx(ctx->dev, edesc, req, ctx->ctx_len, DMA_BIDIRECTIONAL);
+ switch_buf(state);
+ qi_cache_free(edesc);
+
+ print_hex_dump_debug("ctx@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx,
+ ctx->ctx_len, 1);
+ if (req->result)
+ print_hex_dump_debug("result@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, req->result,
+ crypto_ahash_digestsize(ahash), 1);
+
+ req->base.complete(&req->base, ecode);
+}
+
+static void ahash_done_ctx_src(void *cbk_ctx, u32 status)
+{
+ struct crypto_async_request *areq = cbk_ctx;
+ struct ahash_request *req = ahash_request_cast(areq);
+ struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
+ struct caam_hash_state *state = ahash_request_ctx(req);
+ struct ahash_edesc *edesc = state->caam_req.edesc;
+ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
+ int digestsize = crypto_ahash_digestsize(ahash);
+ int ecode = 0;
+
+ dev_dbg(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status);
+
+ if (unlikely(status)) {
+ caam_qi2_strstatus(ctx->dev, status);
+ ecode = -EIO;
+ }
+
+ ahash_unmap_ctx(ctx->dev, edesc, req, digestsize, DMA_TO_DEVICE);
+ qi_cache_free(edesc);
+
+ print_hex_dump_debug("ctx@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx,
+ ctx->ctx_len, 1);
+ if (req->result)
+ print_hex_dump_debug("result@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, req->result,
+ digestsize, 1);
+
+ req->base.complete(&req->base, ecode);
+}
+
+static void ahash_done_ctx_dst(void *cbk_ctx, u32 status)
+{
+ struct crypto_async_request *areq = cbk_ctx;
+ struct ahash_request *req = ahash_request_cast(areq);
+ struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
+ struct caam_hash_state *state = ahash_request_ctx(req);
+ struct ahash_edesc *edesc = state->caam_req.edesc;
+ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
+ int ecode = 0;
+
+ dev_dbg(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status);
+
+ if (unlikely(status)) {
+ caam_qi2_strstatus(ctx->dev, status);
+ ecode = -EIO;
+ }
+
+ ahash_unmap_ctx(ctx->dev, edesc, req, ctx->ctx_len, DMA_FROM_DEVICE);
+ switch_buf(state);
+ qi_cache_free(edesc);
+
+ print_hex_dump_debug("ctx@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, state->caam_ctx,
+ ctx->ctx_len, 1);
+ if (req->result)
+ print_hex_dump_debug("result@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, req->result,
+ crypto_ahash_digestsize(ahash), 1);
+
+ req->base.complete(&req->base, ecode);
+}
+
+static int ahash_update_ctx(struct ahash_request *req)
+{
+ struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
+ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
+ struct caam_hash_state *state = ahash_request_ctx(req);
+ struct caam_request *req_ctx = &state->caam_req;
+ struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1];
+ struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0];
+ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
+ GFP_KERNEL : GFP_ATOMIC;
+ u8 *buf = current_buf(state);
+ int *buflen = current_buflen(state);
+ u8 *next_buf = alt_buf(state);
+ int *next_buflen = alt_buflen(state), last_buflen;
+ int in_len = *buflen + req->nbytes, to_hash;
+ int src_nents, mapped_nents, qm_sg_bytes, qm_sg_src_index;
+ struct ahash_edesc *edesc;
+ int ret = 0;
+
+ last_buflen = *next_buflen;
+ *next_buflen = in_len & (crypto_tfm_alg_blocksize(&ahash->base) - 1);
+ to_hash = in_len - *next_buflen;
+
+ if (to_hash) {
+ struct dpaa2_sg_entry *sg_table;
+
+ src_nents = sg_nents_for_len(req->src,
+ req->nbytes - (*next_buflen));
+ if (src_nents < 0) {
+ dev_err(ctx->dev, "Invalid number of src SG.\n");
+ return src_nents;
+ }
+
+ if (src_nents) {
+ mapped_nents = dma_map_sg(ctx->dev, req->src, src_nents,
+ DMA_TO_DEVICE);
+ if (!mapped_nents) {
+ dev_err(ctx->dev, "unable to DMA map source\n");
+ return -ENOMEM;
+ }
+ } else {
+ mapped_nents = 0;
+ }
+
+ /* allocate space for base edesc and link tables */
+ edesc = qi_cache_zalloc(GFP_DMA | flags);
+ if (!edesc) {
+ dma_unmap_sg(ctx->dev, req->src, src_nents,
+ DMA_TO_DEVICE);
+ return -ENOMEM;
+ }
+
+ edesc->src_nents = src_nents;
+ qm_sg_src_index = 1 + (*buflen ? 1 : 0);
+ qm_sg_bytes = (qm_sg_src_index + mapped_nents) *
+ sizeof(*sg_table);
+ sg_table = &edesc->sgt[0];
+
+ ret = ctx_map_to_qm_sg(ctx->dev, state, ctx->ctx_len, sg_table,
+ DMA_BIDIRECTIONAL);
+ if (ret)
+ goto unmap_ctx;
+
+ ret = buf_map_to_qm_sg(ctx->dev, sg_table + 1, state);
+ if (ret)
+ goto unmap_ctx;
+
+ if (mapped_nents) {
+ sg_to_qm_sg_last(req->src, mapped_nents,
+ sg_table + qm_sg_src_index, 0);
+ if (*next_buflen)
+ scatterwalk_map_and_copy(next_buf, req->src,
+ to_hash - *buflen,
+ *next_buflen, 0);
+ } else {
+ dpaa2_sg_set_final(sg_table + qm_sg_src_index - 1,
+ true);
+ }
+
+ edesc->qm_sg_dma = dma_map_single(ctx->dev, sg_table,
+ qm_sg_bytes, DMA_TO_DEVICE);
+ if (dma_mapping_error(ctx->dev, edesc->qm_sg_dma)) {
+ dev_err(ctx->dev, "unable to map S/G table\n");
+ ret = -ENOMEM;
+ goto unmap_ctx;
+ }
+ edesc->qm_sg_bytes = qm_sg_bytes;
+
+ memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt));
+ dpaa2_fl_set_final(in_fle, true);
+ dpaa2_fl_set_format(in_fle, dpaa2_fl_sg);
+ dpaa2_fl_set_addr(in_fle, edesc->qm_sg_dma);
+ dpaa2_fl_set_len(in_fle, ctx->ctx_len + to_hash);
+ dpaa2_fl_set_format(out_fle, dpaa2_fl_single);
+ dpaa2_fl_set_addr(out_fle, state->ctx_dma);
+ dpaa2_fl_set_len(out_fle, ctx->ctx_len);
+
+ req_ctx->flc = &ctx->flc[UPDATE];
+ req_ctx->flc_dma = ctx->flc_dma[UPDATE];
+ req_ctx->cbk = ahash_done_bi;
+ req_ctx->ctx = &req->base;
+ req_ctx->edesc = edesc;
+
+ ret = dpaa2_caam_enqueue(ctx->dev, req_ctx);
+ if (ret != -EINPROGRESS &&
+ !(ret == -EBUSY &&
+ req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG))
+ goto unmap_ctx;
+ } else if (*next_buflen) {
+ scatterwalk_map_and_copy(buf + *buflen, req->src, 0,
+ req->nbytes, 0);
+ *buflen = *next_buflen;
+ *next_buflen = last_buflen;
+ }
+
+ print_hex_dump_debug("buf@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, buf, *buflen, 1);
+ print_hex_dump_debug("next buf@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, next_buf, *next_buflen,
+ 1);
+
+ return ret;
+unmap_ctx:
+ ahash_unmap_ctx(ctx->dev, edesc, req, ctx->ctx_len, DMA_BIDIRECTIONAL);
+ qi_cache_free(edesc);
+ return ret;
+}
+
+static int ahash_final_ctx(struct ahash_request *req)
+{
+ struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
+ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
+ struct caam_hash_state *state = ahash_request_ctx(req);
+ struct caam_request *req_ctx = &state->caam_req;
+ struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1];
+ struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0];
+ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
+ GFP_KERNEL : GFP_ATOMIC;
+ int buflen = *current_buflen(state);
+ int qm_sg_bytes, qm_sg_src_index;
+ int digestsize = crypto_ahash_digestsize(ahash);
+ struct ahash_edesc *edesc;
+ struct dpaa2_sg_entry *sg_table;
+ int ret;
+
+ /* allocate space for base edesc and link tables */
+ edesc = qi_cache_zalloc(GFP_DMA | flags);
+ if (!edesc)
+ return -ENOMEM;
+
+ qm_sg_src_index = 1 + (buflen ? 1 : 0);
+ qm_sg_bytes = qm_sg_src_index * sizeof(*sg_table);
+ sg_table = &edesc->sgt[0];
+
+ ret = ctx_map_to_qm_sg(ctx->dev, state, ctx->ctx_len, sg_table,
+ DMA_TO_DEVICE);
+ if (ret)
+ goto unmap_ctx;
+
+ ret = buf_map_to_qm_sg(ctx->dev, sg_table + 1, state);
+ if (ret)
+ goto unmap_ctx;
+
+ dpaa2_sg_set_final(sg_table + qm_sg_src_index - 1, true);
+
+ edesc->qm_sg_dma = dma_map_single(ctx->dev, sg_table, qm_sg_bytes,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(ctx->dev, edesc->qm_sg_dma)) {
+ dev_err(ctx->dev, "unable to map S/G table\n");
+ ret = -ENOMEM;
+ goto unmap_ctx;
+ }
+ edesc->qm_sg_bytes = qm_sg_bytes;
+
+ edesc->dst_dma = dma_map_single(ctx->dev, req->result, digestsize,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(ctx->dev, edesc->dst_dma)) {
+ dev_err(ctx->dev, "unable to map dst\n");
+ edesc->dst_dma = 0;
+ ret = -ENOMEM;
+ goto unmap_ctx;
+ }
+
+ memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt));
+ dpaa2_fl_set_final(in_fle, true);
+ dpaa2_fl_set_format(in_fle, dpaa2_fl_sg);
+ dpaa2_fl_set_addr(in_fle, edesc->qm_sg_dma);
+ dpaa2_fl_set_len(in_fle, ctx->ctx_len + buflen);
+ dpaa2_fl_set_format(out_fle, dpaa2_fl_single);
+ dpaa2_fl_set_addr(out_fle, edesc->dst_dma);
+ dpaa2_fl_set_len(out_fle, digestsize);
+
+ req_ctx->flc = &ctx->flc[FINALIZE];
+ req_ctx->flc_dma = ctx->flc_dma[FINALIZE];
+ req_ctx->cbk = ahash_done_ctx_src;
+ req_ctx->ctx = &req->base;
+ req_ctx->edesc = edesc;
+
+ ret = dpaa2_caam_enqueue(ctx->dev, req_ctx);
+ if (ret == -EINPROGRESS ||
+ (ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG))
+ return ret;
+
+unmap_ctx:
+ ahash_unmap_ctx(ctx->dev, edesc, req, digestsize, DMA_FROM_DEVICE);
+ qi_cache_free(edesc);
+ return ret;
+}
+
+static int ahash_finup_ctx(struct ahash_request *req)
+{
+ struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
+ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
+ struct caam_hash_state *state = ahash_request_ctx(req);
+ struct caam_request *req_ctx = &state->caam_req;
+ struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1];
+ struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0];
+ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
+ GFP_KERNEL : GFP_ATOMIC;
+ int buflen = *current_buflen(state);
+ int qm_sg_bytes, qm_sg_src_index;
+ int src_nents, mapped_nents;
+ int digestsize = crypto_ahash_digestsize(ahash);
+ struct ahash_edesc *edesc;
+ struct dpaa2_sg_entry *sg_table;
+ int ret;
+
+ src_nents = sg_nents_for_len(req->src, req->nbytes);
+ if (src_nents < 0) {
+ dev_err(ctx->dev, "Invalid number of src SG.\n");
+ return src_nents;
+ }
+
+ if (src_nents) {
+ mapped_nents = dma_map_sg(ctx->dev, req->src, src_nents,
+ DMA_TO_DEVICE);
+ if (!mapped_nents) {
+ dev_err(ctx->dev, "unable to DMA map source\n");
+ return -ENOMEM;
+ }
+ } else {
+ mapped_nents = 0;
+ }
+
+ /* allocate space for base edesc and link tables */
+ edesc = qi_cache_zalloc(GFP_DMA | flags);
+ if (!edesc) {
+ dma_unmap_sg(ctx->dev, req->src, src_nents, DMA_TO_DEVICE);
+ return -ENOMEM;
+ }
+
+ edesc->src_nents = src_nents;
+ qm_sg_src_index = 1 + (buflen ? 1 : 0);
+ qm_sg_bytes = (qm_sg_src_index + mapped_nents) * sizeof(*sg_table);
+ sg_table = &edesc->sgt[0];
+
+ ret = ctx_map_to_qm_sg(ctx->dev, state, ctx->ctx_len, sg_table,
+ DMA_TO_DEVICE);
+ if (ret)
+ goto unmap_ctx;
+
+ ret = buf_map_to_qm_sg(ctx->dev, sg_table + 1, state);
+ if (ret)
+ goto unmap_ctx;
+
+ sg_to_qm_sg_last(req->src, mapped_nents, sg_table + qm_sg_src_index, 0);
+
+ edesc->qm_sg_dma = dma_map_single(ctx->dev, sg_table, qm_sg_bytes,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(ctx->dev, edesc->qm_sg_dma)) {
+ dev_err(ctx->dev, "unable to map S/G table\n");
+ ret = -ENOMEM;
+ goto unmap_ctx;
+ }
+ edesc->qm_sg_bytes = qm_sg_bytes;
+
+ edesc->dst_dma = dma_map_single(ctx->dev, req->result, digestsize,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(ctx->dev, edesc->dst_dma)) {
+ dev_err(ctx->dev, "unable to map dst\n");
+ edesc->dst_dma = 0;
+ ret = -ENOMEM;
+ goto unmap_ctx;
+ }
+
+ memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt));
+ dpaa2_fl_set_final(in_fle, true);
+ dpaa2_fl_set_format(in_fle, dpaa2_fl_sg);
+ dpaa2_fl_set_addr(in_fle, edesc->qm_sg_dma);
+ dpaa2_fl_set_len(in_fle, ctx->ctx_len + buflen + req->nbytes);
+ dpaa2_fl_set_format(out_fle, dpaa2_fl_single);
+ dpaa2_fl_set_addr(out_fle, edesc->dst_dma);
+ dpaa2_fl_set_len(out_fle, digestsize);
+
+ req_ctx->flc = &ctx->flc[FINALIZE];
+ req_ctx->flc_dma = ctx->flc_dma[FINALIZE];
+ req_ctx->cbk = ahash_done_ctx_src;
+ req_ctx->ctx = &req->base;
+ req_ctx->edesc = edesc;
+
+ ret = dpaa2_caam_enqueue(ctx->dev, req_ctx);
+ if (ret == -EINPROGRESS ||
+ (ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG))
+ return ret;
+
+unmap_ctx:
+ ahash_unmap_ctx(ctx->dev, edesc, req, digestsize, DMA_FROM_DEVICE);
+ qi_cache_free(edesc);
+ return ret;
+}
+
+static int ahash_digest(struct ahash_request *req)
+{
+ struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
+ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
+ struct caam_hash_state *state = ahash_request_ctx(req);
+ struct caam_request *req_ctx = &state->caam_req;
+ struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1];
+ struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0];
+ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
+ GFP_KERNEL : GFP_ATOMIC;
+ int digestsize = crypto_ahash_digestsize(ahash);
+ int src_nents, mapped_nents;
+ struct ahash_edesc *edesc;
+ int ret = -ENOMEM;
+
+ state->buf_dma = 0;
+
+ src_nents = sg_nents_for_len(req->src, req->nbytes);
+ if (src_nents < 0) {
+ dev_err(ctx->dev, "Invalid number of src SG.\n");
+ return src_nents;
+ }
+
+ if (src_nents) {
+ mapped_nents = dma_map_sg(ctx->dev, req->src, src_nents,
+ DMA_TO_DEVICE);
+ if (!mapped_nents) {
+ dev_err(ctx->dev, "unable to map source for DMA\n");
+ return ret;
+ }
+ } else {
+ mapped_nents = 0;
+ }
+
+ /* allocate space for base edesc and link tables */
+ edesc = qi_cache_zalloc(GFP_DMA | flags);
+ if (!edesc) {
+ dma_unmap_sg(ctx->dev, req->src, src_nents, DMA_TO_DEVICE);
+ return ret;
+ }
+
+ edesc->src_nents = src_nents;
+ memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt));
+
+ if (mapped_nents > 1) {
+ int qm_sg_bytes;
+ struct dpaa2_sg_entry *sg_table = &edesc->sgt[0];
+
+ qm_sg_bytes = mapped_nents * sizeof(*sg_table);
+ sg_to_qm_sg_last(req->src, mapped_nents, sg_table, 0);
+ edesc->qm_sg_dma = dma_map_single(ctx->dev, sg_table,
+ qm_sg_bytes, DMA_TO_DEVICE);
+ if (dma_mapping_error(ctx->dev, edesc->qm_sg_dma)) {
+ dev_err(ctx->dev, "unable to map S/G table\n");
+ goto unmap;
+ }
+ edesc->qm_sg_bytes = qm_sg_bytes;
+ dpaa2_fl_set_format(in_fle, dpaa2_fl_sg);
+ dpaa2_fl_set_addr(in_fle, edesc->qm_sg_dma);
+ } else {
+ dpaa2_fl_set_format(in_fle, dpaa2_fl_single);
+ dpaa2_fl_set_addr(in_fle, sg_dma_address(req->src));
+ }
+
+ edesc->dst_dma = dma_map_single(ctx->dev, req->result, digestsize,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(ctx->dev, edesc->dst_dma)) {
+ dev_err(ctx->dev, "unable to map dst\n");
+ edesc->dst_dma = 0;
+ goto unmap;
+ }
+
+ dpaa2_fl_set_final(in_fle, true);
+ dpaa2_fl_set_len(in_fle, req->nbytes);
+ dpaa2_fl_set_format(out_fle, dpaa2_fl_single);
+ dpaa2_fl_set_addr(out_fle, edesc->dst_dma);
+ dpaa2_fl_set_len(out_fle, digestsize);
+
+ req_ctx->flc = &ctx->flc[DIGEST];
+ req_ctx->flc_dma = ctx->flc_dma[DIGEST];
+ req_ctx->cbk = ahash_done;
+ req_ctx->ctx = &req->base;
+ req_ctx->edesc = edesc;
+ ret = dpaa2_caam_enqueue(ctx->dev, req_ctx);
+ if (ret == -EINPROGRESS ||
+ (ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG))
+ return ret;
+
+unmap:
+ ahash_unmap(ctx->dev, edesc, req, digestsize);
+ qi_cache_free(edesc);
+ return ret;
+}
+
+static int ahash_final_no_ctx(struct ahash_request *req)
+{
+ struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
+ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
+ struct caam_hash_state *state = ahash_request_ctx(req);
+ struct caam_request *req_ctx = &state->caam_req;
+ struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1];
+ struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0];
+ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
+ GFP_KERNEL : GFP_ATOMIC;
+ u8 *buf = current_buf(state);
+ int buflen = *current_buflen(state);
+ int digestsize = crypto_ahash_digestsize(ahash);
+ struct ahash_edesc *edesc;
+ int ret = -ENOMEM;
+
+ /* allocate space for base edesc and link tables */
+ edesc = qi_cache_zalloc(GFP_DMA | flags);
+ if (!edesc)
+ return ret;
+
+ state->buf_dma = dma_map_single(ctx->dev, buf, buflen, DMA_TO_DEVICE);
+ if (dma_mapping_error(ctx->dev, state->buf_dma)) {
+ dev_err(ctx->dev, "unable to map src\n");
+ goto unmap;
+ }
+
+ edesc->dst_dma = dma_map_single(ctx->dev, req->result, digestsize,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(ctx->dev, edesc->dst_dma)) {
+ dev_err(ctx->dev, "unable to map dst\n");
+ edesc->dst_dma = 0;
+ goto unmap;
+ }
+
+ memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt));
+ dpaa2_fl_set_final(in_fle, true);
+ dpaa2_fl_set_format(in_fle, dpaa2_fl_single);
+ dpaa2_fl_set_addr(in_fle, state->buf_dma);
+ dpaa2_fl_set_len(in_fle, buflen);
+ dpaa2_fl_set_format(out_fle, dpaa2_fl_single);
+ dpaa2_fl_set_addr(out_fle, edesc->dst_dma);
+ dpaa2_fl_set_len(out_fle, digestsize);
+
+ req_ctx->flc = &ctx->flc[DIGEST];
+ req_ctx->flc_dma = ctx->flc_dma[DIGEST];
+ req_ctx->cbk = ahash_done;
+ req_ctx->ctx = &req->base;
+ req_ctx->edesc = edesc;
+
+ ret = dpaa2_caam_enqueue(ctx->dev, req_ctx);
+ if (ret == -EINPROGRESS ||
+ (ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG))
+ return ret;
+
+unmap:
+ ahash_unmap(ctx->dev, edesc, req, digestsize);
+ qi_cache_free(edesc);
+ return ret;
+}
+
+static int ahash_update_no_ctx(struct ahash_request *req)
+{
+ struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
+ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
+ struct caam_hash_state *state = ahash_request_ctx(req);
+ struct caam_request *req_ctx = &state->caam_req;
+ struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1];
+ struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0];
+ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
+ GFP_KERNEL : GFP_ATOMIC;
+ u8 *buf = current_buf(state);
+ int *buflen = current_buflen(state);
+ u8 *next_buf = alt_buf(state);
+ int *next_buflen = alt_buflen(state);
+ int in_len = *buflen + req->nbytes, to_hash;
+ int qm_sg_bytes, src_nents, mapped_nents;
+ struct ahash_edesc *edesc;
+ int ret = 0;
+
+ *next_buflen = in_len & (crypto_tfm_alg_blocksize(&ahash->base) - 1);
+ to_hash = in_len - *next_buflen;
+
+ if (to_hash) {
+ struct dpaa2_sg_entry *sg_table;
+
+ src_nents = sg_nents_for_len(req->src,
+ req->nbytes - *next_buflen);
+ if (src_nents < 0) {
+ dev_err(ctx->dev, "Invalid number of src SG.\n");
+ return src_nents;
+ }
+
+ if (src_nents) {
+ mapped_nents = dma_map_sg(ctx->dev, req->src, src_nents,
+ DMA_TO_DEVICE);
+ if (!mapped_nents) {
+ dev_err(ctx->dev, "unable to DMA map source\n");
+ return -ENOMEM;
+ }
+ } else {
+ mapped_nents = 0;
+ }
+
+ /* allocate space for base edesc and link tables */
+ edesc = qi_cache_zalloc(GFP_DMA | flags);
+ if (!edesc) {
+ dma_unmap_sg(ctx->dev, req->src, src_nents,
+ DMA_TO_DEVICE);
+ return -ENOMEM;
+ }
+
+ edesc->src_nents = src_nents;
+ qm_sg_bytes = (1 + mapped_nents) * sizeof(*sg_table);
+ sg_table = &edesc->sgt[0];
+
+ ret = buf_map_to_qm_sg(ctx->dev, sg_table, state);
+ if (ret)
+ goto unmap_ctx;
+
+ sg_to_qm_sg_last(req->src, mapped_nents, sg_table + 1, 0);
+
+ if (*next_buflen)
+ scatterwalk_map_and_copy(next_buf, req->src,
+ to_hash - *buflen,
+ *next_buflen, 0);
+
+ edesc->qm_sg_dma = dma_map_single(ctx->dev, sg_table,
+ qm_sg_bytes, DMA_TO_DEVICE);
+ if (dma_mapping_error(ctx->dev, edesc->qm_sg_dma)) {
+ dev_err(ctx->dev, "unable to map S/G table\n");
+ ret = -ENOMEM;
+ goto unmap_ctx;
+ }
+ edesc->qm_sg_bytes = qm_sg_bytes;
+
+ state->ctx_dma = dma_map_single(ctx->dev, state->caam_ctx,
+ ctx->ctx_len, DMA_FROM_DEVICE);
+ if (dma_mapping_error(ctx->dev, state->ctx_dma)) {
+ dev_err(ctx->dev, "unable to map ctx\n");
+ state->ctx_dma = 0;
+ ret = -ENOMEM;
+ goto unmap_ctx;
+ }
+
+ memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt));
+ dpaa2_fl_set_final(in_fle, true);
+ dpaa2_fl_set_format(in_fle, dpaa2_fl_sg);
+ dpaa2_fl_set_addr(in_fle, edesc->qm_sg_dma);
+ dpaa2_fl_set_len(in_fle, to_hash);
+ dpaa2_fl_set_format(out_fle, dpaa2_fl_single);
+ dpaa2_fl_set_addr(out_fle, state->ctx_dma);
+ dpaa2_fl_set_len(out_fle, ctx->ctx_len);
+
+ req_ctx->flc = &ctx->flc[UPDATE_FIRST];
+ req_ctx->flc_dma = ctx->flc_dma[UPDATE_FIRST];
+ req_ctx->cbk = ahash_done_ctx_dst;
+ req_ctx->ctx = &req->base;
+ req_ctx->edesc = edesc;
+
+ ret = dpaa2_caam_enqueue(ctx->dev, req_ctx);
+ if (ret != -EINPROGRESS &&
+ !(ret == -EBUSY &&
+ req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG))
+ goto unmap_ctx;
+
+ state->update = ahash_update_ctx;
+ state->finup = ahash_finup_ctx;
+ state->final = ahash_final_ctx;
+ } else if (*next_buflen) {
+ scatterwalk_map_and_copy(buf + *buflen, req->src, 0,
+ req->nbytes, 0);
+ *buflen = *next_buflen;
+ *next_buflen = 0;
+ }
+
+ print_hex_dump_debug("buf@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, buf, *buflen, 1);
+ print_hex_dump_debug("next buf@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, next_buf, *next_buflen,
+ 1);
+
+ return ret;
+unmap_ctx:
+ ahash_unmap_ctx(ctx->dev, edesc, req, ctx->ctx_len, DMA_TO_DEVICE);
+ qi_cache_free(edesc);
+ return ret;
+}
+
+static int ahash_finup_no_ctx(struct ahash_request *req)
+{
+ struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
+ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
+ struct caam_hash_state *state = ahash_request_ctx(req);
+ struct caam_request *req_ctx = &state->caam_req;
+ struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1];
+ struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0];
+ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
+ GFP_KERNEL : GFP_ATOMIC;
+ int buflen = *current_buflen(state);
+ int qm_sg_bytes, src_nents, mapped_nents;
+ int digestsize = crypto_ahash_digestsize(ahash);
+ struct ahash_edesc *edesc;
+ struct dpaa2_sg_entry *sg_table;
+ int ret;
+
+ src_nents = sg_nents_for_len(req->src, req->nbytes);
+ if (src_nents < 0) {
+ dev_err(ctx->dev, "Invalid number of src SG.\n");
+ return src_nents;
+ }
+
+ if (src_nents) {
+ mapped_nents = dma_map_sg(ctx->dev, req->src, src_nents,
+ DMA_TO_DEVICE);
+ if (!mapped_nents) {
+ dev_err(ctx->dev, "unable to DMA map source\n");
+ return -ENOMEM;
+ }
+ } else {
+ mapped_nents = 0;
+ }
+
+ /* allocate space for base edesc and link tables */
+ edesc = qi_cache_zalloc(GFP_DMA | flags);
+ if (!edesc) {
+ dma_unmap_sg(ctx->dev, req->src, src_nents, DMA_TO_DEVICE);
+ return -ENOMEM;
+ }
+
+ edesc->src_nents = src_nents;
+ qm_sg_bytes = (2 + mapped_nents) * sizeof(*sg_table);
+ sg_table = &edesc->sgt[0];
+
+ ret = buf_map_to_qm_sg(ctx->dev, sg_table, state);
+ if (ret)
+ goto unmap;
+
+ sg_to_qm_sg_last(req->src, mapped_nents, sg_table + 1, 0);
+
+ edesc->qm_sg_dma = dma_map_single(ctx->dev, sg_table, qm_sg_bytes,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(ctx->dev, edesc->qm_sg_dma)) {
+ dev_err(ctx->dev, "unable to map S/G table\n");
+ ret = -ENOMEM;
+ goto unmap;
+ }
+ edesc->qm_sg_bytes = qm_sg_bytes;
+
+ edesc->dst_dma = dma_map_single(ctx->dev, req->result, digestsize,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(ctx->dev, edesc->dst_dma)) {
+ dev_err(ctx->dev, "unable to map dst\n");
+ edesc->dst_dma = 0;
+ ret = -ENOMEM;
+ goto unmap;
+ }
+
+ memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt));
+ dpaa2_fl_set_final(in_fle, true);
+ dpaa2_fl_set_format(in_fle, dpaa2_fl_sg);
+ dpaa2_fl_set_addr(in_fle, edesc->qm_sg_dma);
+ dpaa2_fl_set_len(in_fle, buflen + req->nbytes);
+ dpaa2_fl_set_format(out_fle, dpaa2_fl_single);
+ dpaa2_fl_set_addr(out_fle, edesc->dst_dma);
+ dpaa2_fl_set_len(out_fle, digestsize);
+
+ req_ctx->flc = &ctx->flc[DIGEST];
+ req_ctx->flc_dma = ctx->flc_dma[DIGEST];
+ req_ctx->cbk = ahash_done;
+ req_ctx->ctx = &req->base;
+ req_ctx->edesc = edesc;
+ ret = dpaa2_caam_enqueue(ctx->dev, req_ctx);
+ if (ret != -EINPROGRESS &&
+ !(ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG))
+ goto unmap;
+
+ return ret;
+unmap:
+ ahash_unmap(ctx->dev, edesc, req, digestsize);
+ qi_cache_free(edesc);
+ return -ENOMEM;
+}
+
+static int ahash_update_first(struct ahash_request *req)
+{
+ struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
+ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
+ struct caam_hash_state *state = ahash_request_ctx(req);
+ struct caam_request *req_ctx = &state->caam_req;
+ struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1];
+ struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0];
+ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
+ GFP_KERNEL : GFP_ATOMIC;
+ u8 *next_buf = alt_buf(state);
+ int *next_buflen = alt_buflen(state);
+ int to_hash;
+ int src_nents, mapped_nents;
+ struct ahash_edesc *edesc;
+ int ret = 0;
+
+ *next_buflen = req->nbytes & (crypto_tfm_alg_blocksize(&ahash->base) -
+ 1);
+ to_hash = req->nbytes - *next_buflen;
+
+ if (to_hash) {
+ struct dpaa2_sg_entry *sg_table;
+
+ src_nents = sg_nents_for_len(req->src,
+ req->nbytes - (*next_buflen));
+ if (src_nents < 0) {
+ dev_err(ctx->dev, "Invalid number of src SG.\n");
+ return src_nents;
+ }
+
+ if (src_nents) {
+ mapped_nents = dma_map_sg(ctx->dev, req->src, src_nents,
+ DMA_TO_DEVICE);
+ if (!mapped_nents) {
+ dev_err(ctx->dev, "unable to map source for DMA\n");
+ return -ENOMEM;
+ }
+ } else {
+ mapped_nents = 0;
+ }
+
+ /* allocate space for base edesc and link tables */
+ edesc = qi_cache_zalloc(GFP_DMA | flags);
+ if (!edesc) {
+ dma_unmap_sg(ctx->dev, req->src, src_nents,
+ DMA_TO_DEVICE);
+ return -ENOMEM;
+ }
+
+ edesc->src_nents = src_nents;
+ sg_table = &edesc->sgt[0];
+
+ memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt));
+ dpaa2_fl_set_final(in_fle, true);
+ dpaa2_fl_set_len(in_fle, to_hash);
+
+ if (mapped_nents > 1) {
+ int qm_sg_bytes;
+
+ sg_to_qm_sg_last(req->src, mapped_nents, sg_table, 0);
+ qm_sg_bytes = mapped_nents * sizeof(*sg_table);
+ edesc->qm_sg_dma = dma_map_single(ctx->dev, sg_table,
+ qm_sg_bytes,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(ctx->dev, edesc->qm_sg_dma)) {
+ dev_err(ctx->dev, "unable to map S/G table\n");
+ ret = -ENOMEM;
+ goto unmap_ctx;
+ }
+ edesc->qm_sg_bytes = qm_sg_bytes;
+ dpaa2_fl_set_format(in_fle, dpaa2_fl_sg);
+ dpaa2_fl_set_addr(in_fle, edesc->qm_sg_dma);
+ } else {
+ dpaa2_fl_set_format(in_fle, dpaa2_fl_single);
+ dpaa2_fl_set_addr(in_fle, sg_dma_address(req->src));
+ }
+
+ if (*next_buflen)
+ scatterwalk_map_and_copy(next_buf, req->src, to_hash,
+ *next_buflen, 0);
+
+ state->ctx_dma = dma_map_single(ctx->dev, state->caam_ctx,
+ ctx->ctx_len, DMA_FROM_DEVICE);
+ if (dma_mapping_error(ctx->dev, state->ctx_dma)) {
+ dev_err(ctx->dev, "unable to map ctx\n");
+ state->ctx_dma = 0;
+ ret = -ENOMEM;
+ goto unmap_ctx;
+ }
+
+ dpaa2_fl_set_format(out_fle, dpaa2_fl_single);
+ dpaa2_fl_set_addr(out_fle, state->ctx_dma);
+ dpaa2_fl_set_len(out_fle, ctx->ctx_len);
+
+ req_ctx->flc = &ctx->flc[UPDATE_FIRST];
+ req_ctx->flc_dma = ctx->flc_dma[UPDATE_FIRST];
+ req_ctx->cbk = ahash_done_ctx_dst;
+ req_ctx->ctx = &req->base;
+ req_ctx->edesc = edesc;
+
+ ret = dpaa2_caam_enqueue(ctx->dev, req_ctx);
+ if (ret != -EINPROGRESS &&
+ !(ret == -EBUSY && req->base.flags &
+ CRYPTO_TFM_REQ_MAY_BACKLOG))
+ goto unmap_ctx;
+
+ state->update = ahash_update_ctx;
+ state->finup = ahash_finup_ctx;
+ state->final = ahash_final_ctx;
+ } else if (*next_buflen) {
+ state->update = ahash_update_no_ctx;
+ state->finup = ahash_finup_no_ctx;
+ state->final = ahash_final_no_ctx;
+ scatterwalk_map_and_copy(next_buf, req->src, 0,
+ req->nbytes, 0);
+ switch_buf(state);
+ }
+
+ print_hex_dump_debug("next buf@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, next_buf, *next_buflen,
+ 1);
+
+ return ret;
+unmap_ctx:
+ ahash_unmap_ctx(ctx->dev, edesc, req, ctx->ctx_len, DMA_TO_DEVICE);
+ qi_cache_free(edesc);
+ return ret;
+}
+
+static int ahash_finup_first(struct ahash_request *req)
+{
+ return ahash_digest(req);
+}
+
+static int ahash_init(struct ahash_request *req)
+{
+ struct caam_hash_state *state = ahash_request_ctx(req);
+
+ state->update = ahash_update_first;
+ state->finup = ahash_finup_first;
+ state->final = ahash_final_no_ctx;
+
+ state->ctx_dma = 0;
+ state->current_buf = 0;
+ state->buf_dma = 0;
+ state->buflen_0 = 0;
+ state->buflen_1 = 0;
+
+ return 0;
+}
+
+static int ahash_update(struct ahash_request *req)
+{
+ struct caam_hash_state *state = ahash_request_ctx(req);
+
+ return state->update(req);
+}
+
+static int ahash_finup(struct ahash_request *req)
+{
+ struct caam_hash_state *state = ahash_request_ctx(req);
+
+ return state->finup(req);
+}
+
+static int ahash_final(struct ahash_request *req)
+{
+ struct caam_hash_state *state = ahash_request_ctx(req);
+
+ return state->final(req);
+}
+
+static int ahash_export(struct ahash_request *req, void *out)
+{
+ struct caam_hash_state *state = ahash_request_ctx(req);
+ struct caam_export_state *export = out;
+ int len;
+ u8 *buf;
+
+ if (state->current_buf) {
+ buf = state->buf_1;
+ len = state->buflen_1;
+ } else {
+ buf = state->buf_0;
+ len = state->buflen_0;
+ }
+
+ memcpy(export->buf, buf, len);
+ memcpy(export->caam_ctx, state->caam_ctx, sizeof(export->caam_ctx));
+ export->buflen = len;
+ export->update = state->update;
+ export->final = state->final;
+ export->finup = state->finup;
+
+ return 0;
+}
+
+static int ahash_import(struct ahash_request *req, const void *in)
+{
+ struct caam_hash_state *state = ahash_request_ctx(req);
+ const struct caam_export_state *export = in;
+
+ memset(state, 0, sizeof(*state));
+ memcpy(state->buf_0, export->buf, export->buflen);
+ memcpy(state->caam_ctx, export->caam_ctx, sizeof(state->caam_ctx));
+ state->buflen_0 = export->buflen;
+ state->update = export->update;
+ state->final = export->final;
+ state->finup = export->finup;
+
+ return 0;
+}
+
+struct caam_hash_template {
+ char name[CRYPTO_MAX_ALG_NAME];
+ char driver_name[CRYPTO_MAX_ALG_NAME];
+ char hmac_name[CRYPTO_MAX_ALG_NAME];
+ char hmac_driver_name[CRYPTO_MAX_ALG_NAME];
+ unsigned int blocksize;
+ struct ahash_alg template_ahash;
+ u32 alg_type;
+};
+
+/* ahash descriptors */
+static struct caam_hash_template driver_hash[] = {
+ {
+ .name = "sha1",
+ .driver_name = "sha1-caam-qi2",
+ .hmac_name = "hmac(sha1)",
+ .hmac_driver_name = "hmac-sha1-caam-qi2",
+ .blocksize = SHA1_BLOCK_SIZE,
+ .template_ahash = {
+ .init = ahash_init,
+ .update = ahash_update,
+ .final = ahash_final,
+ .finup = ahash_finup,
+ .digest = ahash_digest,
+ .export = ahash_export,
+ .import = ahash_import,
+ .setkey = ahash_setkey,
+ .halg = {
+ .digestsize = SHA1_DIGEST_SIZE,
+ .statesize = sizeof(struct caam_export_state),
+ },
+ },
+ .alg_type = OP_ALG_ALGSEL_SHA1,
+ }, {
+ .name = "sha224",
+ .driver_name = "sha224-caam-qi2",
+ .hmac_name = "hmac(sha224)",
+ .hmac_driver_name = "hmac-sha224-caam-qi2",
+ .blocksize = SHA224_BLOCK_SIZE,
+ .template_ahash = {
+ .init = ahash_init,
+ .update = ahash_update,
+ .final = ahash_final,
+ .finup = ahash_finup,
+ .digest = ahash_digest,
+ .export = ahash_export,
+ .import = ahash_import,
+ .setkey = ahash_setkey,
+ .halg = {
+ .digestsize = SHA224_DIGEST_SIZE,
+ .statesize = sizeof(struct caam_export_state),
+ },
+ },
+ .alg_type = OP_ALG_ALGSEL_SHA224,
+ }, {
+ .name = "sha256",
+ .driver_name = "sha256-caam-qi2",
+ .hmac_name = "hmac(sha256)",
+ .hmac_driver_name = "hmac-sha256-caam-qi2",
+ .blocksize = SHA256_BLOCK_SIZE,
+ .template_ahash = {
+ .init = ahash_init,
+ .update = ahash_update,
+ .final = ahash_final,
+ .finup = ahash_finup,
+ .digest = ahash_digest,
+ .export = ahash_export,
+ .import = ahash_import,
+ .setkey = ahash_setkey,
+ .halg = {
+ .digestsize = SHA256_DIGEST_SIZE,
+ .statesize = sizeof(struct caam_export_state),
+ },
+ },
+ .alg_type = OP_ALG_ALGSEL_SHA256,
+ }, {
+ .name = "sha384",
+ .driver_name = "sha384-caam-qi2",
+ .hmac_name = "hmac(sha384)",
+ .hmac_driver_name = "hmac-sha384-caam-qi2",
+ .blocksize = SHA384_BLOCK_SIZE,
+ .template_ahash = {
+ .init = ahash_init,
+ .update = ahash_update,
+ .final = ahash_final,
+ .finup = ahash_finup,
+ .digest = ahash_digest,
+ .export = ahash_export,
+ .import = ahash_import,
+ .setkey = ahash_setkey,
+ .halg = {
+ .digestsize = SHA384_DIGEST_SIZE,
+ .statesize = sizeof(struct caam_export_state),
+ },
+ },
+ .alg_type = OP_ALG_ALGSEL_SHA384,
+ }, {
+ .name = "sha512",
+ .driver_name = "sha512-caam-qi2",
+ .hmac_name = "hmac(sha512)",
+ .hmac_driver_name = "hmac-sha512-caam-qi2",
+ .blocksize = SHA512_BLOCK_SIZE,
+ .template_ahash = {
+ .init = ahash_init,
+ .update = ahash_update,
+ .final = ahash_final,
+ .finup = ahash_finup,
+ .digest = ahash_digest,
+ .export = ahash_export,
+ .import = ahash_import,
+ .setkey = ahash_setkey,
+ .halg = {
+ .digestsize = SHA512_DIGEST_SIZE,
+ .statesize = sizeof(struct caam_export_state),
+ },
+ },
+ .alg_type = OP_ALG_ALGSEL_SHA512,
+ }, {
+ .name = "md5",
+ .driver_name = "md5-caam-qi2",
+ .hmac_name = "hmac(md5)",
+ .hmac_driver_name = "hmac-md5-caam-qi2",
+ .blocksize = MD5_BLOCK_WORDS * 4,
+ .template_ahash = {
+ .init = ahash_init,
+ .update = ahash_update,
+ .final = ahash_final,
+ .finup = ahash_finup,
+ .digest = ahash_digest,
+ .export = ahash_export,
+ .import = ahash_import,
+ .setkey = ahash_setkey,
+ .halg = {
+ .digestsize = MD5_DIGEST_SIZE,
+ .statesize = sizeof(struct caam_export_state),
+ },
+ },
+ .alg_type = OP_ALG_ALGSEL_MD5,
+ }
+};
+
+struct caam_hash_alg {
+ struct list_head entry;
+ struct device *dev;
+ int alg_type;
+ struct ahash_alg ahash_alg;
+};
+
+static int caam_hash_cra_init(struct crypto_tfm *tfm)
+{
+ struct crypto_ahash *ahash = __crypto_ahash_cast(tfm);
+ struct crypto_alg *base = tfm->__crt_alg;
+ struct hash_alg_common *halg =
+ container_of(base, struct hash_alg_common, base);
+ struct ahash_alg *alg =
+ container_of(halg, struct ahash_alg, halg);
+ struct caam_hash_alg *caam_hash =
+ container_of(alg, struct caam_hash_alg, ahash_alg);
+ struct caam_hash_ctx *ctx = crypto_tfm_ctx(tfm);
+ /* Sizes for MDHA running digests: MD5, SHA1, 224, 256, 384, 512 */
+ static const u8 runninglen[] = { HASH_MSG_LEN + MD5_DIGEST_SIZE,
+ HASH_MSG_LEN + SHA1_DIGEST_SIZE,
+ HASH_MSG_LEN + 32,
+ HASH_MSG_LEN + SHA256_DIGEST_SIZE,
+ HASH_MSG_LEN + 64,
+ HASH_MSG_LEN + SHA512_DIGEST_SIZE };
+ dma_addr_t dma_addr;
+ int i;
+
+ ctx->dev = caam_hash->dev;
+
+ dma_addr = dma_map_single_attrs(ctx->dev, ctx->flc, sizeof(ctx->flc),
+ DMA_BIDIRECTIONAL,
+ DMA_ATTR_SKIP_CPU_SYNC);
+ if (dma_mapping_error(ctx->dev, dma_addr)) {
+ dev_err(ctx->dev, "unable to map shared descriptors\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < HASH_NUM_OP; i++)
+ ctx->flc_dma[i] = dma_addr + i * sizeof(ctx->flc[i]);
+
+ /* copy descriptor header template value */
+ ctx->adata.algtype = OP_TYPE_CLASS2_ALG | caam_hash->alg_type;
+
+ ctx->ctx_len = runninglen[(ctx->adata.algtype &
+ OP_ALG_ALGSEL_SUBMASK) >>
+ OP_ALG_ALGSEL_SHIFT];
+
+ crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
+ sizeof(struct caam_hash_state));
+
+ return ahash_set_sh_desc(ahash);
+}
+
+static void caam_hash_cra_exit(struct crypto_tfm *tfm)
+{
+ struct caam_hash_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ dma_unmap_single_attrs(ctx->dev, ctx->flc_dma[0], sizeof(ctx->flc),
+ DMA_BIDIRECTIONAL, DMA_ATTR_SKIP_CPU_SYNC);
+}
+
+static struct caam_hash_alg *caam_hash_alloc(struct device *dev,
+ struct caam_hash_template *template, bool keyed)
+{
+ struct caam_hash_alg *t_alg;
+ struct ahash_alg *halg;
+ struct crypto_alg *alg;
+
+ t_alg = kzalloc(sizeof(*t_alg), GFP_KERNEL);
+ if (!t_alg)
+ return ERR_PTR(-ENOMEM);
+
+ t_alg->ahash_alg = template->template_ahash;
+ halg = &t_alg->ahash_alg;
+ alg = &halg->halg.base;
+
+ if (keyed) {
+ snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s",
+ template->hmac_name);
+ snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
+ template->hmac_driver_name);
+ } else {
+ snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s",
+ template->name);
+ snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
+ template->driver_name);
+ t_alg->ahash_alg.setkey = NULL;
+ }
+ alg->cra_module = THIS_MODULE;
+ alg->cra_init = caam_hash_cra_init;
+ alg->cra_exit = caam_hash_cra_exit;
+ alg->cra_ctxsize = sizeof(struct caam_hash_ctx);
+ alg->cra_priority = CAAM_CRA_PRIORITY;
+ alg->cra_blocksize = template->blocksize;
+ alg->cra_alignmask = 0;
+ alg->cra_flags = CRYPTO_ALG_ASYNC;
+
+ t_alg->alg_type = template->alg_type;
+ t_alg->dev = dev;
+
+ return t_alg;
+}
+
+static void dpaa2_caam_fqdan_cb(struct dpaa2_io_notification_ctx *nctx)
+{
+ struct dpaa2_caam_priv_per_cpu *ppriv;
+
+ ppriv = container_of(nctx, struct dpaa2_caam_priv_per_cpu, nctx);
+ napi_schedule_irqoff(&ppriv->napi);
+}
+
+static int __cold dpaa2_dpseci_dpio_setup(struct dpaa2_caam_priv *priv)
+{
+ struct device *dev = priv->dev;
+ struct dpaa2_io_notification_ctx *nctx;
+ struct dpaa2_caam_priv_per_cpu *ppriv;
+ int err, i = 0, cpu;
+
+ for_each_online_cpu(cpu) {
+ ppriv = per_cpu_ptr(priv->ppriv, cpu);
+ ppriv->priv = priv;
+ nctx = &ppriv->nctx;
+ nctx->is_cdan = 0;
+ nctx->id = ppriv->rsp_fqid;
+ nctx->desired_cpu = cpu;
+ nctx->cb = dpaa2_caam_fqdan_cb;
+
+ /* Register notification callbacks */
+ err = dpaa2_io_service_register(NULL, nctx);
+ if (unlikely(err)) {
+ dev_dbg(dev, "No affine DPIO for cpu %d\n", cpu);
+ nctx->cb = NULL;
+ /*
+ * If no affine DPIO for this core, there's probably
+ * none available for next cores either. Signal we want
+ * to retry later, in case the DPIO devices weren't
+ * probed yet.
+ */
+ err = -EPROBE_DEFER;
+ goto err;
+ }
+
+ ppriv->store = dpaa2_io_store_create(DPAA2_CAAM_STORE_SIZE,
+ dev);
+ if (unlikely(!ppriv->store)) {
+ dev_err(dev, "dpaa2_io_store_create() failed\n");
+ err = -ENOMEM;
+ goto err;
+ }
+
+ if (++i == priv->num_pairs)
+ break;
+ }
+
+ return 0;
+
+err:
+ for_each_online_cpu(cpu) {
+ ppriv = per_cpu_ptr(priv->ppriv, cpu);
+ if (!ppriv->nctx.cb)
+ break;
+ dpaa2_io_service_deregister(NULL, &ppriv->nctx);
+ }
+
+ for_each_online_cpu(cpu) {
+ ppriv = per_cpu_ptr(priv->ppriv, cpu);
+ if (!ppriv->store)
+ break;
+ dpaa2_io_store_destroy(ppriv->store);
+ }
+
+ return err;
+}
+
+static void __cold dpaa2_dpseci_dpio_free(struct dpaa2_caam_priv *priv)
+{
+ struct dpaa2_caam_priv_per_cpu *ppriv;
+ int i = 0, cpu;
+
+ for_each_online_cpu(cpu) {
+ ppriv = per_cpu_ptr(priv->ppriv, cpu);
+ dpaa2_io_service_deregister(NULL, &ppriv->nctx);
+ dpaa2_io_store_destroy(ppriv->store);
+
+ if (++i == priv->num_pairs)
+ return;
+ }
+}
+
+static int dpaa2_dpseci_bind(struct dpaa2_caam_priv *priv)
+{
+ struct dpseci_rx_queue_cfg rx_queue_cfg;
+ struct device *dev = priv->dev;
+ struct fsl_mc_device *ls_dev = to_fsl_mc_device(dev);
+ struct dpaa2_caam_priv_per_cpu *ppriv;
+ int err = 0, i = 0, cpu;
+
+ /* Configure Rx queues */
+ for_each_online_cpu(cpu) {
+ ppriv = per_cpu_ptr(priv->ppriv, cpu);
+
+ rx_queue_cfg.options = DPSECI_QUEUE_OPT_DEST |
+ DPSECI_QUEUE_OPT_USER_CTX;
+ rx_queue_cfg.order_preservation_en = 0;
+ rx_queue_cfg.dest_cfg.dest_type = DPSECI_DEST_DPIO;
+ rx_queue_cfg.dest_cfg.dest_id = ppriv->nctx.dpio_id;
+ /*
+ * Rx priority (WQ) doesn't really matter, since we use
+ * pull mode, i.e. volatile dequeues from specific FQs
+ */
+ rx_queue_cfg.dest_cfg.priority = 0;
+ rx_queue_cfg.user_ctx = ppriv->nctx.qman64;
+
+ err = dpseci_set_rx_queue(priv->mc_io, 0, ls_dev->mc_handle, i,
+ &rx_queue_cfg);
+ if (err) {
+ dev_err(dev, "dpseci_set_rx_queue() failed with err %d\n",
+ err);
+ return err;
+ }
+
+ if (++i == priv->num_pairs)
+ break;
+ }
+
+ return err;
+}
+
+static void dpaa2_dpseci_congestion_free(struct dpaa2_caam_priv *priv)
+{
+ struct device *dev = priv->dev;
+
+ if (!priv->cscn_mem)
+ return;
+
+ dma_unmap_single(dev, priv->cscn_dma, DPAA2_CSCN_SIZE, DMA_FROM_DEVICE);
+ kfree(priv->cscn_mem);
+}
+
+static void dpaa2_dpseci_free(struct dpaa2_caam_priv *priv)
+{
+ struct device *dev = priv->dev;
+ struct fsl_mc_device *ls_dev = to_fsl_mc_device(dev);
+
+ dpaa2_dpseci_congestion_free(priv);
+ dpseci_close(priv->mc_io, 0, ls_dev->mc_handle);
+}
+
+static void dpaa2_caam_process_fd(struct dpaa2_caam_priv *priv,
+ const struct dpaa2_fd *fd)
+{
+ struct caam_request *req;
+ u32 fd_err;
+
+ if (dpaa2_fd_get_format(fd) != dpaa2_fd_list) {
+ dev_err(priv->dev, "Only Frame List FD format is supported!\n");
+ return;
+ }
+
+ fd_err = dpaa2_fd_get_ctrl(fd) & FD_CTRL_ERR_MASK;
+ if (unlikely(fd_err))
+ dev_err(priv->dev, "FD error: %08x\n", fd_err);
+
+ /*
+ * FD[ADDR] is guaranteed to be valid, irrespective of errors reported
+ * in FD[ERR] or FD[FRC].
+ */
+ req = dpaa2_caam_iova_to_virt(priv, dpaa2_fd_get_addr(fd));
+ dma_unmap_single(priv->dev, req->fd_flt_dma, sizeof(req->fd_flt),
+ DMA_BIDIRECTIONAL);
+ req->cbk(req->ctx, dpaa2_fd_get_frc(fd));
+}
+
+static int dpaa2_caam_pull_fq(struct dpaa2_caam_priv_per_cpu *ppriv)
+{
+ int err;
+
+ /* Retry while portal is busy */
+ do {
+ err = dpaa2_io_service_pull_fq(NULL, ppriv->rsp_fqid,
+ ppriv->store);
+ } while (err == -EBUSY);
+
+ if (unlikely(err))
+ dev_err(ppriv->priv->dev, "dpaa2_io_service_pull err %d", err);
+
+ return err;
+}
+
+static int dpaa2_caam_store_consume(struct dpaa2_caam_priv_per_cpu *ppriv)
+{
+ struct dpaa2_dq *dq;
+ int cleaned = 0, is_last;
+
+ do {
+ dq = dpaa2_io_store_next(ppriv->store, &is_last);
+ if (unlikely(!dq)) {
+ if (unlikely(!is_last)) {
+ dev_dbg(ppriv->priv->dev,
+ "FQ %d returned no valid frames\n",
+ ppriv->rsp_fqid);
+ /*
+ * MUST retry until we get some sort of
+ * valid response token (be it "empty dequeue"
+ * or a valid frame).
+ */
+ continue;
+ }
+ break;
+ }
+
+ /* Process FD */
+ dpaa2_caam_process_fd(ppriv->priv, dpaa2_dq_fd(dq));
+ cleaned++;
+ } while (!is_last);
+
+ return cleaned;
+}
+
+static int dpaa2_dpseci_poll(struct napi_struct *napi, int budget)
+{
+ struct dpaa2_caam_priv_per_cpu *ppriv;
+ struct dpaa2_caam_priv *priv;
+ int err, cleaned = 0, store_cleaned;
+
+ ppriv = container_of(napi, struct dpaa2_caam_priv_per_cpu, napi);
+ priv = ppriv->priv;
+
+ if (unlikely(dpaa2_caam_pull_fq(ppriv)))
+ return 0;
+
+ do {
+ store_cleaned = dpaa2_caam_store_consume(ppriv);
+ cleaned += store_cleaned;
+
+ if (store_cleaned == 0 ||
+ cleaned > budget - DPAA2_CAAM_STORE_SIZE)
+ break;
+
+ /* Try to dequeue some more */
+ err = dpaa2_caam_pull_fq(ppriv);
+ if (unlikely(err))
+ break;
+ } while (1);
+
+ if (cleaned < budget) {
+ napi_complete_done(napi, cleaned);
+ err = dpaa2_io_service_rearm(NULL, &ppriv->nctx);
+ if (unlikely(err))
+ dev_err(priv->dev, "Notification rearm failed: %d\n",
+ err);
+ }
+
+ return cleaned;
+}
+
+static int dpaa2_dpseci_congestion_setup(struct dpaa2_caam_priv *priv,
+ u16 token)
+{
+ struct dpseci_congestion_notification_cfg cong_notif_cfg = { 0 };
+ struct device *dev = priv->dev;
+ int err;
+
+ /*
+ * Congestion group feature supported starting with DPSECI API v5.1
+ * and only when object has been created with this capability.
+ */
+ if ((DPSECI_VER(priv->major_ver, priv->minor_ver) < DPSECI_VER(5, 1)) ||
+ !(priv->dpseci_attr.options & DPSECI_OPT_HAS_CG))
+ return 0;
+
+ priv->cscn_mem = kzalloc(DPAA2_CSCN_SIZE + DPAA2_CSCN_ALIGN,
+ GFP_KERNEL | GFP_DMA);
+ if (!priv->cscn_mem)
+ return -ENOMEM;
+
+ priv->cscn_mem_aligned = PTR_ALIGN(priv->cscn_mem, DPAA2_CSCN_ALIGN);
+ priv->cscn_dma = dma_map_single(dev, priv->cscn_mem_aligned,
+ DPAA2_CSCN_SIZE, DMA_FROM_DEVICE);
+ if (dma_mapping_error(dev, priv->cscn_dma)) {
+ dev_err(dev, "Error mapping CSCN memory area\n");
+ err = -ENOMEM;
+ goto err_dma_map;
+ }
+
+ cong_notif_cfg.units = DPSECI_CONGESTION_UNIT_BYTES;
+ cong_notif_cfg.threshold_entry = DPAA2_SEC_CONG_ENTRY_THRESH;
+ cong_notif_cfg.threshold_exit = DPAA2_SEC_CONG_EXIT_THRESH;
+ cong_notif_cfg.message_ctx = (uintptr_t)priv;
+ cong_notif_cfg.message_iova = priv->cscn_dma;
+ cong_notif_cfg.notification_mode = DPSECI_CGN_MODE_WRITE_MEM_ON_ENTER |
+ DPSECI_CGN_MODE_WRITE_MEM_ON_EXIT |
+ DPSECI_CGN_MODE_COHERENT_WRITE;
+
+ err = dpseci_set_congestion_notification(priv->mc_io, 0, token,
+ &cong_notif_cfg);
+ if (err) {
+ dev_err(dev, "dpseci_set_congestion_notification failed\n");
+ goto err_set_cong;
+ }
+
+ return 0;
+
+err_set_cong:
+ dma_unmap_single(dev, priv->cscn_dma, DPAA2_CSCN_SIZE, DMA_FROM_DEVICE);
+err_dma_map:
+ kfree(priv->cscn_mem);
+
+ return err;
+}
+
+static int __cold dpaa2_dpseci_setup(struct fsl_mc_device *ls_dev)
+{
+ struct device *dev = &ls_dev->dev;
+ struct dpaa2_caam_priv *priv;
+ struct dpaa2_caam_priv_per_cpu *ppriv;
+ int err, cpu;
+ u8 i;
+
+ priv = dev_get_drvdata(dev);
+
+ priv->dev = dev;
+ priv->dpsec_id = ls_dev->obj_desc.id;
+
+ /* Get a handle for the DPSECI this interface is associate with */
+ err = dpseci_open(priv->mc_io, 0, priv->dpsec_id, &ls_dev->mc_handle);
+ if (err) {
+ dev_err(dev, "dpseci_open() failed: %d\n", err);
+ goto err_open;
+ }
+
+ err = dpseci_get_api_version(priv->mc_io, 0, &priv->major_ver,
+ &priv->minor_ver);
+ if (err) {
+ dev_err(dev, "dpseci_get_api_version() failed\n");
+ goto err_get_vers;
+ }
+
+ dev_info(dev, "dpseci v%d.%d\n", priv->major_ver, priv->minor_ver);
+
+ err = dpseci_get_attributes(priv->mc_io, 0, ls_dev->mc_handle,
+ &priv->dpseci_attr);
+ if (err) {
+ dev_err(dev, "dpseci_get_attributes() failed\n");
+ goto err_get_vers;
+ }
+
+ err = dpseci_get_sec_attr(priv->mc_io, 0, ls_dev->mc_handle,
+ &priv->sec_attr);
+ if (err) {
+ dev_err(dev, "dpseci_get_sec_attr() failed\n");
+ goto err_get_vers;
+ }
+
+ err = dpaa2_dpseci_congestion_setup(priv, ls_dev->mc_handle);
+ if (err) {
+ dev_err(dev, "setup_congestion() failed\n");
+ goto err_get_vers;
+ }
+
+ priv->num_pairs = min(priv->dpseci_attr.num_rx_queues,
+ priv->dpseci_attr.num_tx_queues);
+ if (priv->num_pairs > num_online_cpus()) {
+ dev_warn(dev, "%d queues won't be used\n",
+ priv->num_pairs - num_online_cpus());
+ priv->num_pairs = num_online_cpus();
+ }
+
+ for (i = 0; i < priv->dpseci_attr.num_rx_queues; i++) {
+ err = dpseci_get_rx_queue(priv->mc_io, 0, ls_dev->mc_handle, i,
+ &priv->rx_queue_attr[i]);
+ if (err) {
+ dev_err(dev, "dpseci_get_rx_queue() failed\n");
+ goto err_get_rx_queue;
+ }
+ }
+
+ for (i = 0; i < priv->dpseci_attr.num_tx_queues; i++) {
+ err = dpseci_get_tx_queue(priv->mc_io, 0, ls_dev->mc_handle, i,
+ &priv->tx_queue_attr[i]);
+ if (err) {
+ dev_err(dev, "dpseci_get_tx_queue() failed\n");
+ goto err_get_rx_queue;
+ }
+ }
+
+ i = 0;
+ for_each_online_cpu(cpu) {
+ dev_dbg(dev, "pair %d: rx queue %d, tx queue %d\n", i,
+ priv->rx_queue_attr[i].fqid,
+ priv->tx_queue_attr[i].fqid);
+
+ ppriv = per_cpu_ptr(priv->ppriv, cpu);
+ ppriv->req_fqid = priv->tx_queue_attr[i].fqid;
+ ppriv->rsp_fqid = priv->rx_queue_attr[i].fqid;
+ ppriv->prio = i;
+
+ ppriv->net_dev.dev = *dev;
+ INIT_LIST_HEAD(&ppriv->net_dev.napi_list);
+ netif_napi_add(&ppriv->net_dev, &ppriv->napi, dpaa2_dpseci_poll,
+ DPAA2_CAAM_NAPI_WEIGHT);
+ if (++i == priv->num_pairs)
+ break;
+ }
+
+ return 0;
+
+err_get_rx_queue:
+ dpaa2_dpseci_congestion_free(priv);
+err_get_vers:
+ dpseci_close(priv->mc_io, 0, ls_dev->mc_handle);
+err_open:
+ return err;
+}
+
+static int dpaa2_dpseci_enable(struct dpaa2_caam_priv *priv)
+{
+ struct device *dev = priv->dev;
+ struct fsl_mc_device *ls_dev = to_fsl_mc_device(dev);
+ struct dpaa2_caam_priv_per_cpu *ppriv;
+ int i;
+
+ for (i = 0; i < priv->num_pairs; i++) {
+ ppriv = per_cpu_ptr(priv->ppriv, i);
+ napi_enable(&ppriv->napi);
+ }
+
+ return dpseci_enable(priv->mc_io, 0, ls_dev->mc_handle);
+}
+
+static int __cold dpaa2_dpseci_disable(struct dpaa2_caam_priv *priv)
+{
+ struct device *dev = priv->dev;
+ struct dpaa2_caam_priv_per_cpu *ppriv;
+ struct fsl_mc_device *ls_dev = to_fsl_mc_device(dev);
+ int i, err = 0, enabled;
+
+ err = dpseci_disable(priv->mc_io, 0, ls_dev->mc_handle);
+ if (err) {
+ dev_err(dev, "dpseci_disable() failed\n");
+ return err;
+ }
+
+ err = dpseci_is_enabled(priv->mc_io, 0, ls_dev->mc_handle, &enabled);
+ if (err) {
+ dev_err(dev, "dpseci_is_enabled() failed\n");
+ return err;
+ }
+
+ dev_dbg(dev, "disable: %s\n", enabled ? "false" : "true");
+
+ for (i = 0; i < priv->num_pairs; i++) {
+ ppriv = per_cpu_ptr(priv->ppriv, i);
+ napi_disable(&ppriv->napi);
+ netif_napi_del(&ppriv->napi);
+ }
+
+ return 0;
+}
+
+static struct list_head hash_list;
+
+static int dpaa2_caam_probe(struct fsl_mc_device *dpseci_dev)
+{
+ struct device *dev;
+ struct dpaa2_caam_priv *priv;
+ int i, err = 0;
+ bool registered = false;
+
+ /*
+ * There is no way to get CAAM endianness - there is no direct register
+ * space access and MC f/w does not provide this attribute.
+ * All DPAA2-based SoCs have little endian CAAM, thus hard-code this
+ * property.
+ */
+ caam_little_end = true;
+
+ caam_imx = false;
+
+ dev = &dpseci_dev->dev;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, priv);
+
+ priv->domain = iommu_get_domain_for_dev(dev);
+
+ qi_cache = kmem_cache_create("dpaa2_caamqicache", CAAM_QI_MEMCACHE_SIZE,
+ 0, SLAB_CACHE_DMA, NULL);
+ if (!qi_cache) {
+ dev_err(dev, "Can't allocate SEC cache\n");
+ return -ENOMEM;
+ }
+
+ err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(49));
+ if (err) {
+ dev_err(dev, "dma_set_mask_and_coherent() failed\n");
+ goto err_dma_mask;
+ }
+
+ /* Obtain a MC portal */
+ err = fsl_mc_portal_allocate(dpseci_dev, 0, &priv->mc_io);
+ if (err) {
+ if (err == -ENXIO)
+ err = -EPROBE_DEFER;
+ else
+ dev_err(dev, "MC portal allocation failed\n");
+
+ goto err_dma_mask;
+ }
+
+ priv->ppriv = alloc_percpu(*priv->ppriv);
+ if (!priv->ppriv) {
+ dev_err(dev, "alloc_percpu() failed\n");
+ err = -ENOMEM;
+ goto err_alloc_ppriv;
+ }
+
+ /* DPSECI initialization */
+ err = dpaa2_dpseci_setup(dpseci_dev);
+ if (err) {
+ dev_err(dev, "dpaa2_dpseci_setup() failed\n");
+ goto err_dpseci_setup;
+ }
+
+ /* DPIO */
+ err = dpaa2_dpseci_dpio_setup(priv);
+ if (err) {
+ if (err != -EPROBE_DEFER)
+ dev_err(dev, "dpaa2_dpseci_dpio_setup() failed\n");
+ goto err_dpio_setup;
+ }
+
+ /* DPSECI binding to DPIO */
+ err = dpaa2_dpseci_bind(priv);
+ if (err) {
+ dev_err(dev, "dpaa2_dpseci_bind() failed\n");
+ goto err_bind;
+ }
+
+ /* DPSECI enable */
+ err = dpaa2_dpseci_enable(priv);
+ if (err) {
+ dev_err(dev, "dpaa2_dpseci_enable() failed\n");
+ goto err_bind;
+ }
+
+ /* register crypto algorithms the device supports */
+ for (i = 0; i < ARRAY_SIZE(driver_algs); i++) {
+ struct caam_skcipher_alg *t_alg = driver_algs + i;
+ u32 alg_sel = t_alg->caam.class1_alg_type & OP_ALG_ALGSEL_MASK;
+
+ /* Skip DES algorithms if not supported by device */
+ if (!priv->sec_attr.des_acc_num &&
+ (alg_sel == OP_ALG_ALGSEL_3DES ||
+ alg_sel == OP_ALG_ALGSEL_DES))
+ continue;
+
+ /* Skip AES algorithms if not supported by device */
+ if (!priv->sec_attr.aes_acc_num &&
+ alg_sel == OP_ALG_ALGSEL_AES)
+ continue;
+
+ t_alg->caam.dev = dev;
+ caam_skcipher_alg_init(t_alg);
+
+ err = crypto_register_skcipher(&t_alg->skcipher);
+ if (err) {
+ dev_warn(dev, "%s alg registration failed: %d\n",
+ t_alg->skcipher.base.cra_driver_name, err);
+ continue;
+ }
+
+ t_alg->registered = true;
+ registered = true;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(driver_aeads); i++) {
+ struct caam_aead_alg *t_alg = driver_aeads + i;
+ u32 c1_alg_sel = t_alg->caam.class1_alg_type &
+ OP_ALG_ALGSEL_MASK;
+ u32 c2_alg_sel = t_alg->caam.class2_alg_type &
+ OP_ALG_ALGSEL_MASK;
+
+ /* Skip DES algorithms if not supported by device */
+ if (!priv->sec_attr.des_acc_num &&
+ (c1_alg_sel == OP_ALG_ALGSEL_3DES ||
+ c1_alg_sel == OP_ALG_ALGSEL_DES))
+ continue;
+
+ /* Skip AES algorithms if not supported by device */
+ if (!priv->sec_attr.aes_acc_num &&
+ c1_alg_sel == OP_ALG_ALGSEL_AES)
+ continue;
+
+ /*
+ * Skip algorithms requiring message digests
+ * if MD not supported by device.
+ */
+ if (!priv->sec_attr.md_acc_num && c2_alg_sel)
+ continue;
+
+ t_alg->caam.dev = dev;
+ caam_aead_alg_init(t_alg);
+
+ err = crypto_register_aead(&t_alg->aead);
+ if (err) {
+ dev_warn(dev, "%s alg registration failed: %d\n",
+ t_alg->aead.base.cra_driver_name, err);
+ continue;
+ }
+
+ t_alg->registered = true;
+ registered = true;
+ }
+ if (registered)
+ dev_info(dev, "algorithms registered in /proc/crypto\n");
+
+ /* register hash algorithms the device supports */
+ INIT_LIST_HEAD(&hash_list);
+
+ /*
+ * Skip registration of any hashing algorithms if MD block
+ * is not present.
+ */
+ if (!priv->sec_attr.md_acc_num)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(driver_hash); i++) {
+ struct caam_hash_alg *t_alg;
+ struct caam_hash_template *alg = driver_hash + i;
+
+ /* register hmac version */
+ t_alg = caam_hash_alloc(dev, alg, true);
+ if (IS_ERR(t_alg)) {
+ err = PTR_ERR(t_alg);
+ dev_warn(dev, "%s hash alg allocation failed: %d\n",
+ alg->driver_name, err);
+ continue;
+ }
+
+ err = crypto_register_ahash(&t_alg->ahash_alg);
+ if (err) {
+ dev_warn(dev, "%s alg registration failed: %d\n",
+ t_alg->ahash_alg.halg.base.cra_driver_name,
+ err);
+ kfree(t_alg);
+ } else {
+ list_add_tail(&t_alg->entry, &hash_list);
+ }
+
+ /* register unkeyed version */
+ t_alg = caam_hash_alloc(dev, alg, false);
+ if (IS_ERR(t_alg)) {
+ err = PTR_ERR(t_alg);
+ dev_warn(dev, "%s alg allocation failed: %d\n",
+ alg->driver_name, err);
+ continue;
+ }
+
+ err = crypto_register_ahash(&t_alg->ahash_alg);
+ if (err) {
+ dev_warn(dev, "%s alg registration failed: %d\n",
+ t_alg->ahash_alg.halg.base.cra_driver_name,
+ err);
+ kfree(t_alg);
+ } else {
+ list_add_tail(&t_alg->entry, &hash_list);
+ }
+ }
+ if (!list_empty(&hash_list))
+ dev_info(dev, "hash algorithms registered in /proc/crypto\n");
+
+ return err;
+
+err_bind:
+ dpaa2_dpseci_dpio_free(priv);
+err_dpio_setup:
+ dpaa2_dpseci_free(priv);
+err_dpseci_setup:
+ free_percpu(priv->ppriv);
+err_alloc_ppriv:
+ fsl_mc_portal_free(priv->mc_io);
+err_dma_mask:
+ kmem_cache_destroy(qi_cache);
+
+ return err;
+}
+
+static int __cold dpaa2_caam_remove(struct fsl_mc_device *ls_dev)
+{
+ struct device *dev;
+ struct dpaa2_caam_priv *priv;
+ int i;
+
+ dev = &ls_dev->dev;
+ priv = dev_get_drvdata(dev);
+
+ for (i = 0; i < ARRAY_SIZE(driver_aeads); i++) {
+ struct caam_aead_alg *t_alg = driver_aeads + i;
+
+ if (t_alg->registered)
+ crypto_unregister_aead(&t_alg->aead);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(driver_algs); i++) {
+ struct caam_skcipher_alg *t_alg = driver_algs + i;
+
+ if (t_alg->registered)
+ crypto_unregister_skcipher(&t_alg->skcipher);
+ }
+
+ if (hash_list.next) {
+ struct caam_hash_alg *t_hash_alg, *p;
+
+ list_for_each_entry_safe(t_hash_alg, p, &hash_list, entry) {
+ crypto_unregister_ahash(&t_hash_alg->ahash_alg);
+ list_del(&t_hash_alg->entry);
+ kfree(t_hash_alg);
+ }
+ }
+
+ dpaa2_dpseci_disable(priv);
+ dpaa2_dpseci_dpio_free(priv);
+ dpaa2_dpseci_free(priv);
+ free_percpu(priv->ppriv);
+ fsl_mc_portal_free(priv->mc_io);
+ kmem_cache_destroy(qi_cache);
+
+ return 0;
+}
+
+int dpaa2_caam_enqueue(struct device *dev, struct caam_request *req)
+{
+ struct dpaa2_fd fd;
+ struct dpaa2_caam_priv *priv = dev_get_drvdata(dev);
+ int err = 0, i, id;
+
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+
+ if (priv->cscn_mem) {
+ dma_sync_single_for_cpu(priv->dev, priv->cscn_dma,
+ DPAA2_CSCN_SIZE,
+ DMA_FROM_DEVICE);
+ if (unlikely(dpaa2_cscn_state_congested(priv->cscn_mem_aligned))) {
+ dev_dbg_ratelimited(dev, "Dropping request\n");
+ return -EBUSY;
+ }
+ }
+
+ dpaa2_fl_set_flc(&req->fd_flt[1], req->flc_dma);
+
+ req->fd_flt_dma = dma_map_single(dev, req->fd_flt, sizeof(req->fd_flt),
+ DMA_BIDIRECTIONAL);
+ if (dma_mapping_error(dev, req->fd_flt_dma)) {
+ dev_err(dev, "DMA mapping error for QI enqueue request\n");
+ goto err_out;
+ }
+
+ memset(&fd, 0, sizeof(fd));
+ dpaa2_fd_set_format(&fd, dpaa2_fd_list);
+ dpaa2_fd_set_addr(&fd, req->fd_flt_dma);
+ dpaa2_fd_set_len(&fd, dpaa2_fl_get_len(&req->fd_flt[1]));
+ dpaa2_fd_set_flc(&fd, req->flc_dma);
+
+ /*
+ * There is no guarantee that preemption is disabled here,
+ * thus take action.
+ */
+ preempt_disable();
+ id = smp_processor_id() % priv->dpseci_attr.num_tx_queues;
+ for (i = 0; i < (priv->dpseci_attr.num_tx_queues << 1); i++) {
+ err = dpaa2_io_service_enqueue_fq(NULL,
+ priv->tx_queue_attr[id].fqid,
+ &fd);
+ if (err != -EBUSY)
+ break;
+ }
+ preempt_enable();
+
+ if (unlikely(err)) {
+ dev_err(dev, "Error enqueuing frame: %d\n", err);
+ goto err_out;
+ }
+
+ return -EINPROGRESS;
+
+err_out:
+ dma_unmap_single(dev, req->fd_flt_dma, sizeof(req->fd_flt),
+ DMA_BIDIRECTIONAL);
+ return -EIO;
+}
+EXPORT_SYMBOL(dpaa2_caam_enqueue);
+
+static const struct fsl_mc_device_id dpaa2_caam_match_id_table[] = {
+ {
+ .vendor = FSL_MC_VENDOR_FREESCALE,
+ .obj_type = "dpseci",
+ },
+ { .vendor = 0x0 }
+};
+
+static struct fsl_mc_driver dpaa2_caam_driver = {
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = dpaa2_caam_probe,
+ .remove = dpaa2_caam_remove,
+ .match_id_table = dpaa2_caam_match_id_table
+};
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Freescale Semiconductor, Inc");
+MODULE_DESCRIPTION("Freescale DPAA2 CAAM Driver");
+
+module_fsl_mc_driver(dpaa2_caam_driver);
diff --git a/drivers/crypto/caam/caamalg_qi2.h b/drivers/crypto/caam/caamalg_qi2.h
new file mode 100644
index 000000000000..9823bdefd029
--- /dev/null
+++ b/drivers/crypto/caam/caamalg_qi2.h
@@ -0,0 +1,223 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+/*
+ * Copyright 2015-2016 Freescale Semiconductor Inc.
+ * Copyright 2017-2018 NXP
+ */
+
+#ifndef _CAAMALG_QI2_H_
+#define _CAAMALG_QI2_H_
+
+#include <soc/fsl/dpaa2-io.h>
+#include <soc/fsl/dpaa2-fd.h>
+#include <linux/threads.h>
+#include "dpseci.h"
+#include "desc_constr.h"
+
+#define DPAA2_CAAM_STORE_SIZE 16
+/* NAPI weight *must* be a multiple of the store size. */
+#define DPAA2_CAAM_NAPI_WEIGHT 64
+
+/* The congestion entrance threshold was chosen so that on LS2088
+ * we support the maximum throughput for the available memory
+ */
+#define DPAA2_SEC_CONG_ENTRY_THRESH (128 * 1024 * 1024)
+#define DPAA2_SEC_CONG_EXIT_THRESH (DPAA2_SEC_CONG_ENTRY_THRESH * 9 / 10)
+
+/**
+ * dpaa2_caam_priv - driver private data
+ * @dpseci_id: DPSECI object unique ID
+ * @major_ver: DPSECI major version
+ * @minor_ver: DPSECI minor version
+ * @dpseci_attr: DPSECI attributes
+ * @sec_attr: SEC engine attributes
+ * @rx_queue_attr: array of Rx queue attributes
+ * @tx_queue_attr: array of Tx queue attributes
+ * @cscn_mem: pointer to memory region containing the congestion SCN
+ * it's size is larger than to accommodate alignment
+ * @cscn_mem_aligned: pointer to congestion SCN; it is computed as
+ * PTR_ALIGN(cscn_mem, DPAA2_CSCN_ALIGN)
+ * @cscn_dma: dma address used by the QMAN to write CSCN messages
+ * @dev: device associated with the DPSECI object
+ * @mc_io: pointer to MC portal's I/O object
+ * @domain: IOMMU domain
+ * @ppriv: per CPU pointers to privata data
+ */
+struct dpaa2_caam_priv {
+ int dpsec_id;
+
+ u16 major_ver;
+ u16 minor_ver;
+
+ struct dpseci_attr dpseci_attr;
+ struct dpseci_sec_attr sec_attr;
+ struct dpseci_rx_queue_attr rx_queue_attr[DPSECI_MAX_QUEUE_NUM];
+ struct dpseci_tx_queue_attr tx_queue_attr[DPSECI_MAX_QUEUE_NUM];
+ int num_pairs;
+
+ /* congestion */
+ void *cscn_mem;
+ void *cscn_mem_aligned;
+ dma_addr_t cscn_dma;
+
+ struct device *dev;
+ struct fsl_mc_io *mc_io;
+ struct iommu_domain *domain;
+
+ struct dpaa2_caam_priv_per_cpu __percpu *ppriv;
+};
+
+/**
+ * dpaa2_caam_priv_per_cpu - per CPU private data
+ * @napi: napi structure
+ * @net_dev: netdev used by napi
+ * @req_fqid: (virtual) request (Tx / enqueue) FQID
+ * @rsp_fqid: (virtual) response (Rx / dequeue) FQID
+ * @prio: internal queue number - index for dpaa2_caam_priv.*_queue_attr
+ * @nctx: notification context of response FQ
+ * @store: where dequeued frames are stored
+ * @priv: backpointer to dpaa2_caam_priv
+ */
+struct dpaa2_caam_priv_per_cpu {
+ struct napi_struct napi;
+ struct net_device net_dev;
+ int req_fqid;
+ int rsp_fqid;
+ int prio;
+ struct dpaa2_io_notification_ctx nctx;
+ struct dpaa2_io_store *store;
+ struct dpaa2_caam_priv *priv;
+};
+
+/*
+ * The CAAM QI hardware constructs a job descriptor which points
+ * to shared descriptor (as pointed by context_a of FQ to CAAM).
+ * When the job descriptor is executed by deco, the whole job
+ * descriptor together with shared descriptor gets loaded in
+ * deco buffer which is 64 words long (each 32-bit).
+ *
+ * The job descriptor constructed by QI hardware has layout:
+ *
+ * HEADER (1 word)
+ * Shdesc ptr (1 or 2 words)
+ * SEQ_OUT_PTR (1 word)
+ * Out ptr (1 or 2 words)
+ * Out length (1 word)
+ * SEQ_IN_PTR (1 word)
+ * In ptr (1 or 2 words)
+ * In length (1 word)
+ *
+ * The shdesc ptr is used to fetch shared descriptor contents
+ * into deco buffer.
+ *
+ * Apart from shdesc contents, the total number of words that
+ * get loaded in deco buffer are '8' or '11'. The remaining words
+ * in deco buffer can be used for storing shared descriptor.
+ */
+#define MAX_SDLEN ((CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN) / CAAM_CMD_SZ)
+
+/* Length of a single buffer in the QI driver memory cache */
+#define CAAM_QI_MEMCACHE_SIZE 512
+
+/*
+ * aead_edesc - s/w-extended aead descriptor
+ * @src_nents: number of segments in input scatterlist
+ * @dst_nents: number of segments in output scatterlist
+ * @iv_dma: dma address of iv for checking continuity and link table
+ * @qm_sg_bytes: length of dma mapped h/w link table
+ * @qm_sg_dma: bus physical mapped address of h/w link table
+ * @assoclen: associated data length, in CAAM endianness
+ * @assoclen_dma: bus physical mapped address of req->assoclen
+ * @sgt: the h/w link table, followed by IV
+ */
+struct aead_edesc {
+ int src_nents;
+ int dst_nents;
+ dma_addr_t iv_dma;
+ int qm_sg_bytes;
+ dma_addr_t qm_sg_dma;
+ unsigned int assoclen;
+ dma_addr_t assoclen_dma;
+ struct dpaa2_sg_entry sgt[0];
+};
+
+/*
+ * skcipher_edesc - s/w-extended skcipher descriptor
+ * @src_nents: number of segments in input scatterlist
+ * @dst_nents: number of segments in output scatterlist
+ * @iv_dma: dma address of iv for checking continuity and link table
+ * @qm_sg_bytes: length of dma mapped qm_sg space
+ * @qm_sg_dma: I/O virtual address of h/w link table
+ * @sgt: the h/w link table, followed by IV
+ */
+struct skcipher_edesc {
+ int src_nents;
+ int dst_nents;
+ dma_addr_t iv_dma;
+ int qm_sg_bytes;
+ dma_addr_t qm_sg_dma;
+ struct dpaa2_sg_entry sgt[0];
+};
+
+/*
+ * ahash_edesc - s/w-extended ahash descriptor
+ * @dst_dma: I/O virtual address of req->result
+ * @qm_sg_dma: I/O virtual address of h/w link table
+ * @src_nents: number of segments in input scatterlist
+ * @qm_sg_bytes: length of dma mapped qm_sg space
+ * @sgt: pointer to h/w link table
+ */
+struct ahash_edesc {
+ dma_addr_t dst_dma;
+ dma_addr_t qm_sg_dma;
+ int src_nents;
+ int qm_sg_bytes;
+ struct dpaa2_sg_entry sgt[0];
+};
+
+/**
+ * caam_flc - Flow Context (FLC)
+ * @flc: Flow Context options
+ * @sh_desc: Shared Descriptor
+ */
+struct caam_flc {
+ u32 flc[16];
+ u32 sh_desc[MAX_SDLEN];
+} ____cacheline_aligned;
+
+enum optype {
+ ENCRYPT = 0,
+ DECRYPT,
+ NUM_OP
+};
+
+/**
+ * caam_request - the request structure the driver application should fill while
+ * submitting a job to driver.
+ * @fd_flt: Frame list table defining input and output
+ * fd_flt[0] - FLE pointing to output buffer
+ * fd_flt[1] - FLE pointing to input buffer
+ * @fd_flt_dma: DMA address for the frame list table
+ * @flc: Flow Context
+ * @flc_dma: I/O virtual address of Flow Context
+ * @cbk: Callback function to invoke when job is completed
+ * @ctx: arbit context attached with request by the application
+ * @edesc: extended descriptor; points to one of {skcipher,aead}_edesc
+ */
+struct caam_request {
+ struct dpaa2_fl_entry fd_flt[2];
+ dma_addr_t fd_flt_dma;
+ struct caam_flc *flc;
+ dma_addr_t flc_dma;
+ void (*cbk)(void *ctx, u32 err);
+ void *ctx;
+ void *edesc;
+};
+
+/**
+ * dpaa2_caam_enqueue() - enqueue a crypto request
+ * @dev: device associated with the DPSECI object
+ * @req: pointer to caam_request
+ */
+int dpaa2_caam_enqueue(struct device *dev, struct caam_request *req);
+
+#endif /* _CAAMALG_QI2_H_ */
diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c
index 43975ab5f09c..46924affa0bd 100644
--- a/drivers/crypto/caam/caamhash.c
+++ b/drivers/crypto/caam/caamhash.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* caam - Freescale FSL CAAM support for ahash functions of crypto API
*
@@ -62,6 +63,7 @@
#include "error.h"
#include "sg_sw_sec4.h"
#include "key_gen.h"
+#include "caamhash_desc.h"
#define CAAM_CRA_PRIORITY 3000
@@ -71,14 +73,6 @@
#define CAAM_MAX_HASH_BLOCK_SIZE SHA512_BLOCK_SIZE
#define CAAM_MAX_HASH_DIGEST_SIZE SHA512_DIGEST_SIZE
-/* length of descriptors text */
-#define DESC_AHASH_BASE (3 * CAAM_CMD_SZ)
-#define DESC_AHASH_UPDATE_LEN (6 * CAAM_CMD_SZ)
-#define DESC_AHASH_UPDATE_FIRST_LEN (DESC_AHASH_BASE + 4 * CAAM_CMD_SZ)
-#define DESC_AHASH_FINAL_LEN (DESC_AHASH_BASE + 5 * CAAM_CMD_SZ)
-#define DESC_AHASH_FINUP_LEN (DESC_AHASH_BASE + 5 * CAAM_CMD_SZ)
-#define DESC_AHASH_DIGEST_LEN (DESC_AHASH_BASE + 4 * CAAM_CMD_SZ)
-
#define DESC_HASH_MAX_USED_BYTES (DESC_AHASH_FINAL_LEN + \
CAAM_MAX_HASH_KEY_SIZE)
#define DESC_HASH_MAX_USED_LEN (DESC_HASH_MAX_USED_BYTES / CAAM_CMD_SZ)
@@ -235,60 +229,6 @@ static inline int ctx_map_to_sec4_sg(struct device *jrdev,
return 0;
}
-/*
- * For ahash update, final and finup (import_ctx = true)
- * import context, read and write to seqout
- * For ahash firsts and digest (import_ctx = false)
- * read and write to seqout
- */
-static inline void ahash_gen_sh_desc(u32 *desc, u32 state, int digestsize,
- struct caam_hash_ctx *ctx, bool import_ctx,
- int era)
-{
- u32 op = ctx->adata.algtype;
- u32 *skip_key_load;
-
- init_sh_desc(desc, HDR_SHARE_SERIAL);
-
- /* Append key if it has been set; ahash update excluded */
- if ((state != OP_ALG_AS_UPDATE) && (ctx->adata.keylen)) {
- /* Skip key loading if already shared */
- skip_key_load = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
- JUMP_COND_SHRD);
-
- if (era < 6)
- append_key_as_imm(desc, ctx->key, ctx->adata.keylen_pad,
- ctx->adata.keylen, CLASS_2 |
- KEY_DEST_MDHA_SPLIT | KEY_ENC);
- else
- append_proto_dkp(desc, &ctx->adata);
-
- set_jump_tgt_here(desc, skip_key_load);
-
- op |= OP_ALG_AAI_HMAC_PRECOMP;
- }
-
- /* If needed, import context from software */
- if (import_ctx)
- append_seq_load(desc, ctx->ctx_len, LDST_CLASS_2_CCB |
- LDST_SRCDST_BYTE_CONTEXT);
-
- /* Class 2 operation */
- append_operation(desc, op | state | OP_ALG_ENCRYPT);
-
- /*
- * Load from buf and/or src and write to req->result or state->context
- * Calculate remaining bytes to read
- */
- append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ);
- /* Read remaining bytes */
- append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_LAST2 |
- FIFOLD_TYPE_MSG | KEY_VLF);
- /* Store class2 context bytes */
- append_seq_store(desc, digestsize, LDST_CLASS_2_CCB |
- LDST_SRCDST_BYTE_CONTEXT);
-}
-
static int ahash_set_sh_desc(struct crypto_ahash *ahash)
{
struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
@@ -301,8 +241,8 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash)
/* ahash_update shared descriptor */
desc = ctx->sh_desc_update;
- ahash_gen_sh_desc(desc, OP_ALG_AS_UPDATE, ctx->ctx_len, ctx, true,
- ctrlpriv->era);
+ cnstr_shdsc_ahash(desc, &ctx->adata, OP_ALG_AS_UPDATE, ctx->ctx_len,
+ ctx->ctx_len, true, ctrlpriv->era);
dma_sync_single_for_device(jrdev, ctx->sh_desc_update_dma,
desc_bytes(desc), ctx->dir);
#ifdef DEBUG
@@ -313,8 +253,8 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash)
/* ahash_update_first shared descriptor */
desc = ctx->sh_desc_update_first;
- ahash_gen_sh_desc(desc, OP_ALG_AS_INIT, ctx->ctx_len, ctx, false,
- ctrlpriv->era);
+ cnstr_shdsc_ahash(desc, &ctx->adata, OP_ALG_AS_INIT, ctx->ctx_len,
+ ctx->ctx_len, false, ctrlpriv->era);
dma_sync_single_for_device(jrdev, ctx->sh_desc_update_first_dma,
desc_bytes(desc), ctx->dir);
#ifdef DEBUG
@@ -325,8 +265,8 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash)
/* ahash_final shared descriptor */
desc = ctx->sh_desc_fin;
- ahash_gen_sh_desc(desc, OP_ALG_AS_FINALIZE, digestsize, ctx, true,
- ctrlpriv->era);
+ cnstr_shdsc_ahash(desc, &ctx->adata, OP_ALG_AS_FINALIZE, digestsize,
+ ctx->ctx_len, true, ctrlpriv->era);
dma_sync_single_for_device(jrdev, ctx->sh_desc_fin_dma,
desc_bytes(desc), ctx->dir);
#ifdef DEBUG
@@ -337,8 +277,8 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash)
/* ahash_digest shared descriptor */
desc = ctx->sh_desc_digest;
- ahash_gen_sh_desc(desc, OP_ALG_AS_INITFINAL, digestsize, ctx, false,
- ctrlpriv->era);
+ cnstr_shdsc_ahash(desc, &ctx->adata, OP_ALG_AS_INITFINAL, digestsize,
+ ctx->ctx_len, false, ctrlpriv->era);
dma_sync_single_for_device(jrdev, ctx->sh_desc_digest_dma,
desc_bytes(desc), ctx->dir);
#ifdef DEBUG
diff --git a/drivers/crypto/caam/caamhash_desc.c b/drivers/crypto/caam/caamhash_desc.c
new file mode 100644
index 000000000000..a12f7959a2c3
--- /dev/null
+++ b/drivers/crypto/caam/caamhash_desc.c
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Shared descriptors for ahash algorithms
+ *
+ * Copyright 2017 NXP
+ */
+
+#include "compat.h"
+#include "desc_constr.h"
+#include "caamhash_desc.h"
+
+/**
+ * cnstr_shdsc_ahash - ahash shared descriptor
+ * @desc: pointer to buffer used for descriptor construction
+ * @adata: pointer to authentication transform definitions.
+ * A split key is required for SEC Era < 6; the size of the split key
+ * is specified in this case.
+ * Valid algorithm values - one of OP_ALG_ALGSEL_{MD5, SHA1, SHA224,
+ * SHA256, SHA384, SHA512}.
+ * @state: algorithm state OP_ALG_AS_{INIT, FINALIZE, INITFINALIZE, UPDATE}
+ * @digestsize: algorithm's digest size
+ * @ctx_len: size of Context Register
+ * @import_ctx: true if previous Context Register needs to be restored
+ * must be true for ahash update and final
+ * must be false for for ahash first and digest
+ * @era: SEC Era
+ */
+void cnstr_shdsc_ahash(u32 * const desc, struct alginfo *adata, u32 state,
+ int digestsize, int ctx_len, bool import_ctx, int era)
+{
+ u32 op = adata->algtype;
+
+ init_sh_desc(desc, HDR_SHARE_SERIAL);
+
+ /* Append key if it has been set; ahash update excluded */
+ if (state != OP_ALG_AS_UPDATE && adata->keylen) {
+ u32 *skip_key_load;
+
+ /* Skip key loading if already shared */
+ skip_key_load = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
+ JUMP_COND_SHRD);
+
+ if (era < 6)
+ append_key_as_imm(desc, adata->key_virt,
+ adata->keylen_pad,
+ adata->keylen, CLASS_2 |
+ KEY_DEST_MDHA_SPLIT | KEY_ENC);
+ else
+ append_proto_dkp(desc, adata);
+
+ set_jump_tgt_here(desc, skip_key_load);
+
+ op |= OP_ALG_AAI_HMAC_PRECOMP;
+ }
+
+ /* If needed, import context from software */
+ if (import_ctx)
+ append_seq_load(desc, ctx_len, LDST_CLASS_2_CCB |
+ LDST_SRCDST_BYTE_CONTEXT);
+
+ /* Class 2 operation */
+ append_operation(desc, op | state | OP_ALG_ENCRYPT);
+
+ /*
+ * Load from buf and/or src and write to req->result or state->context
+ * Calculate remaining bytes to read
+ */
+ append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ);
+ /* Read remaining bytes */
+ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_LAST2 |
+ FIFOLD_TYPE_MSG | KEY_VLF);
+ /* Store class2 context bytes */
+ append_seq_store(desc, digestsize, LDST_CLASS_2_CCB |
+ LDST_SRCDST_BYTE_CONTEXT);
+}
+EXPORT_SYMBOL(cnstr_shdsc_ahash);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("FSL CAAM ahash descriptors support");
+MODULE_AUTHOR("NXP Semiconductors");
diff --git a/drivers/crypto/caam/caamhash_desc.h b/drivers/crypto/caam/caamhash_desc.h
new file mode 100644
index 000000000000..631fc1ac312c
--- /dev/null
+++ b/drivers/crypto/caam/caamhash_desc.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+/*
+ * Shared descriptors for ahash algorithms
+ *
+ * Copyright 2017 NXP
+ */
+
+#ifndef _CAAMHASH_DESC_H_
+#define _CAAMHASH_DESC_H_
+
+/* length of descriptors text */
+#define DESC_AHASH_BASE (3 * CAAM_CMD_SZ)
+#define DESC_AHASH_UPDATE_LEN (6 * CAAM_CMD_SZ)
+#define DESC_AHASH_UPDATE_FIRST_LEN (DESC_AHASH_BASE + 4 * CAAM_CMD_SZ)
+#define DESC_AHASH_FINAL_LEN (DESC_AHASH_BASE + 5 * CAAM_CMD_SZ)
+#define DESC_AHASH_DIGEST_LEN (DESC_AHASH_BASE + 4 * CAAM_CMD_SZ)
+
+void cnstr_shdsc_ahash(u32 * const desc, struct alginfo *adata, u32 state,
+ int digestsize, int ctx_len, bool import_ctx, int era);
+
+#endif /* _CAAMHASH_DESC_H_ */
diff --git a/drivers/crypto/caam/caampkc.c b/drivers/crypto/caam/caampkc.c
index f26d62e5533a..4fc209cbbeab 100644
--- a/drivers/crypto/caam/caampkc.c
+++ b/drivers/crypto/caam/caampkc.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/*
* caam - Freescale FSL CAAM support for Public Key Cryptography
*
diff --git a/drivers/crypto/caam/caamrng.c b/drivers/crypto/caam/caamrng.c
index fde07d4ff019..4318b0aa6fb9 100644
--- a/drivers/crypto/caam/caamrng.c
+++ b/drivers/crypto/caam/caamrng.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* caam - Freescale FSL CAAM support for hw_random
*
diff --git a/drivers/crypto/caam/compat.h b/drivers/crypto/caam/compat.h
index 1c71e0cd5098..9604ff7a335e 100644
--- a/drivers/crypto/caam/compat.h
+++ b/drivers/crypto/caam/compat.h
@@ -17,6 +17,7 @@
#include <linux/of_platform.h>
#include <linux/dma-mapping.h>
#include <linux/io.h>
+#include <linux/iommu.h>
#include <linux/spinlock.h>
#include <linux/rtnetlink.h>
#include <linux/in.h>
@@ -39,6 +40,7 @@
#include <crypto/authenc.h>
#include <crypto/akcipher.h>
#include <crypto/scatterwalk.h>
+#include <crypto/skcipher.h>
#include <crypto/internal/skcipher.h>
#include <crypto/internal/hash.h>
#include <crypto/internal/rsa.h>
diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c
index 538c01f428c1..3fc793193821 100644
--- a/drivers/crypto/caam/ctrl.c
+++ b/drivers/crypto/caam/ctrl.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
/* * CAAM control-plane driver backend
* Controller-level driver, kernel property detection, initialization
*
diff --git a/drivers/crypto/caam/dpseci.c b/drivers/crypto/caam/dpseci.c
new file mode 100644
index 000000000000..8a68531ded0b
--- /dev/null
+++ b/drivers/crypto/caam/dpseci.c
@@ -0,0 +1,426 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright 2013-2016 Freescale Semiconductor Inc.
+ * Copyright 2017-2018 NXP
+ */
+
+#include <linux/fsl/mc.h>
+#include "dpseci.h"
+#include "dpseci_cmd.h"
+
+/**
+ * dpseci_open() - Open a control session for the specified object
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @dpseci_id: DPSECI unique ID
+ * @token: Returned token; use in subsequent API calls
+ *
+ * This function can be used to open a control session for an already created
+ * object; an object may have been declared statically in the DPL
+ * or created dynamically.
+ * This function returns a unique authentication token, associated with the
+ * specific object ID and the specific MC portal; this token must be used in all
+ * subsequent commands for this specific object.
+ *
+ * Return: '0' on success, error code otherwise
+ */
+int dpseci_open(struct fsl_mc_io *mc_io, u32 cmd_flags, int dpseci_id,
+ u16 *token)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpseci_cmd_open *cmd_params;
+ int err;
+
+ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_OPEN,
+ cmd_flags,
+ 0);
+ cmd_params = (struct dpseci_cmd_open *)cmd.params;
+ cmd_params->dpseci_id = cpu_to_le32(dpseci_id);
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ *token = mc_cmd_hdr_read_token(&cmd);
+
+ return 0;
+}
+
+/**
+ * dpseci_close() - Close the control session of the object
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSECI object
+ *
+ * After this function is called, no further operations are allowed on the
+ * object without opening a new control session.
+ *
+ * Return: '0' on success, error code otherwise
+ */
+int dpseci_close(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token)
+{
+ struct fsl_mc_command cmd = { 0 };
+
+ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_CLOSE,
+ cmd_flags,
+ token);
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpseci_enable() - Enable the DPSECI, allow sending and receiving frames
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSECI object
+ *
+ * Return: '0' on success, error code otherwise
+ */
+int dpseci_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token)
+{
+ struct fsl_mc_command cmd = { 0 };
+
+ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_ENABLE,
+ cmd_flags,
+ token);
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpseci_disable() - Disable the DPSECI, stop sending and receiving frames
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSECI object
+ *
+ * Return: '0' on success, error code otherwise
+ */
+int dpseci_disable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token)
+{
+ struct fsl_mc_command cmd = { 0 };
+
+ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_DISABLE,
+ cmd_flags,
+ token);
+
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpseci_is_enabled() - Check if the DPSECI is enabled.
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSECI object
+ * @en: Returns '1' if object is enabled; '0' otherwise
+ *
+ * Return: '0' on success, error code otherwise
+ */
+int dpseci_is_enabled(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+ int *en)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpseci_rsp_is_enabled *rsp_params;
+ int err;
+
+ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_IS_ENABLED,
+ cmd_flags,
+ token);
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ rsp_params = (struct dpseci_rsp_is_enabled *)cmd.params;
+ *en = dpseci_get_field(rsp_params->is_enabled, ENABLE);
+
+ return 0;
+}
+
+/**
+ * dpseci_get_attributes() - Retrieve DPSECI attributes
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSECI object
+ * @attr: Returned object's attributes
+ *
+ * Return: '0' on success, error code otherwise
+ */
+int dpseci_get_attributes(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+ struct dpseci_attr *attr)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpseci_rsp_get_attributes *rsp_params;
+ int err;
+
+ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_GET_ATTR,
+ cmd_flags,
+ token);
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ rsp_params = (struct dpseci_rsp_get_attributes *)cmd.params;
+ attr->id = le32_to_cpu(rsp_params->id);
+ attr->num_tx_queues = rsp_params->num_tx_queues;
+ attr->num_rx_queues = rsp_params->num_rx_queues;
+ attr->options = le32_to_cpu(rsp_params->options);
+
+ return 0;
+}
+
+/**
+ * dpseci_set_rx_queue() - Set Rx queue configuration
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSECI object
+ * @queue: Select the queue relative to number of priorities configured at
+ * DPSECI creation; use DPSECI_ALL_QUEUES to configure all
+ * Rx queues identically.
+ * @cfg: Rx queue configuration
+ *
+ * Return: '0' on success, error code otherwise
+ */
+int dpseci_set_rx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+ u8 queue, const struct dpseci_rx_queue_cfg *cfg)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpseci_cmd_queue *cmd_params;
+
+ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_SET_RX_QUEUE,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpseci_cmd_queue *)cmd.params;
+ cmd_params->dest_id = cpu_to_le32(cfg->dest_cfg.dest_id);
+ cmd_params->priority = cfg->dest_cfg.priority;
+ cmd_params->queue = queue;
+ dpseci_set_field(cmd_params->dest_type, DEST_TYPE,
+ cfg->dest_cfg.dest_type);
+ cmd_params->user_ctx = cpu_to_le64(cfg->user_ctx);
+ cmd_params->options = cpu_to_le32(cfg->options);
+ dpseci_set_field(cmd_params->order_preservation_en, ORDER_PRESERVATION,
+ cfg->order_preservation_en);
+
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpseci_get_rx_queue() - Retrieve Rx queue attributes
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSECI object
+ * @queue: Select the queue relative to number of priorities configured at
+ * DPSECI creation
+ * @attr: Returned Rx queue attributes
+ *
+ * Return: '0' on success, error code otherwise
+ */
+int dpseci_get_rx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+ u8 queue, struct dpseci_rx_queue_attr *attr)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpseci_cmd_queue *cmd_params;
+ int err;
+
+ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_GET_RX_QUEUE,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpseci_cmd_queue *)cmd.params;
+ cmd_params->queue = queue;
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ attr->dest_cfg.dest_id = le32_to_cpu(cmd_params->dest_id);
+ attr->dest_cfg.priority = cmd_params->priority;
+ attr->dest_cfg.dest_type = dpseci_get_field(cmd_params->dest_type,
+ DEST_TYPE);
+ attr->user_ctx = le64_to_cpu(cmd_params->user_ctx);
+ attr->fqid = le32_to_cpu(cmd_params->fqid);
+ attr->order_preservation_en =
+ dpseci_get_field(cmd_params->order_preservation_en,
+ ORDER_PRESERVATION);
+
+ return 0;
+}
+
+/**
+ * dpseci_get_tx_queue() - Retrieve Tx queue attributes
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSECI object
+ * @queue: Select the queue relative to number of priorities configured at
+ * DPSECI creation
+ * @attr: Returned Tx queue attributes
+ *
+ * Return: '0' on success, error code otherwise
+ */
+int dpseci_get_tx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+ u8 queue, struct dpseci_tx_queue_attr *attr)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpseci_cmd_queue *cmd_params;
+ struct dpseci_rsp_get_tx_queue *rsp_params;
+ int err;
+
+ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_GET_TX_QUEUE,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpseci_cmd_queue *)cmd.params;
+ cmd_params->queue = queue;
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ rsp_params = (struct dpseci_rsp_get_tx_queue *)cmd.params;
+ attr->fqid = le32_to_cpu(rsp_params->fqid);
+ attr->priority = rsp_params->priority;
+
+ return 0;
+}
+
+/**
+ * dpseci_get_sec_attr() - Retrieve SEC accelerator attributes
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSECI object
+ * @attr: Returned SEC attributes
+ *
+ * Return: '0' on success, error code otherwise
+ */
+int dpseci_get_sec_attr(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+ struct dpseci_sec_attr *attr)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpseci_rsp_get_sec_attr *rsp_params;
+ int err;
+
+ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_GET_SEC_ATTR,
+ cmd_flags,
+ token);
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ rsp_params = (struct dpseci_rsp_get_sec_attr *)cmd.params;
+ attr->ip_id = le16_to_cpu(rsp_params->ip_id);
+ attr->major_rev = rsp_params->major_rev;
+ attr->minor_rev = rsp_params->minor_rev;
+ attr->era = rsp_params->era;
+ attr->deco_num = rsp_params->deco_num;
+ attr->zuc_auth_acc_num = rsp_params->zuc_auth_acc_num;
+ attr->zuc_enc_acc_num = rsp_params->zuc_enc_acc_num;
+ attr->snow_f8_acc_num = rsp_params->snow_f8_acc_num;
+ attr->snow_f9_acc_num = rsp_params->snow_f9_acc_num;
+ attr->crc_acc_num = rsp_params->crc_acc_num;
+ attr->pk_acc_num = rsp_params->pk_acc_num;
+ attr->kasumi_acc_num = rsp_params->kasumi_acc_num;
+ attr->rng_acc_num = rsp_params->rng_acc_num;
+ attr->md_acc_num = rsp_params->md_acc_num;
+ attr->arc4_acc_num = rsp_params->arc4_acc_num;
+ attr->des_acc_num = rsp_params->des_acc_num;
+ attr->aes_acc_num = rsp_params->aes_acc_num;
+ attr->ccha_acc_num = rsp_params->ccha_acc_num;
+ attr->ptha_acc_num = rsp_params->ptha_acc_num;
+
+ return 0;
+}
+
+/**
+ * dpseci_get_api_version() - Get Data Path SEC Interface API version
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @major_ver: Major version of data path sec API
+ * @minor_ver: Minor version of data path sec API
+ *
+ * Return: '0' on success, error code otherwise
+ */
+int dpseci_get_api_version(struct fsl_mc_io *mc_io, u32 cmd_flags,
+ u16 *major_ver, u16 *minor_ver)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpseci_rsp_get_api_version *rsp_params;
+ int err;
+
+ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_GET_API_VERSION,
+ cmd_flags, 0);
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ rsp_params = (struct dpseci_rsp_get_api_version *)cmd.params;
+ *major_ver = le16_to_cpu(rsp_params->major);
+ *minor_ver = le16_to_cpu(rsp_params->minor);
+
+ return 0;
+}
+
+/**
+ * dpseci_set_congestion_notification() - Set congestion group
+ * notification configuration
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSECI object
+ * @cfg: congestion notification configuration
+ *
+ * Return: '0' on success, error code otherwise
+ */
+int dpseci_set_congestion_notification(struct fsl_mc_io *mc_io, u32 cmd_flags,
+ u16 token, const struct dpseci_congestion_notification_cfg *cfg)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpseci_cmd_congestion_notification *cmd_params;
+
+ cmd.header = mc_encode_cmd_header(
+ DPSECI_CMDID_SET_CONGESTION_NOTIFICATION,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpseci_cmd_congestion_notification *)cmd.params;
+ cmd_params->dest_id = cpu_to_le32(cfg->dest_cfg.dest_id);
+ cmd_params->notification_mode = cpu_to_le16(cfg->notification_mode);
+ cmd_params->priority = cfg->dest_cfg.priority;
+ dpseci_set_field(cmd_params->options, CGN_DEST_TYPE,
+ cfg->dest_cfg.dest_type);
+ dpseci_set_field(cmd_params->options, CGN_UNITS, cfg->units);
+ cmd_params->message_iova = cpu_to_le64(cfg->message_iova);
+ cmd_params->message_ctx = cpu_to_le64(cfg->message_ctx);
+ cmd_params->threshold_entry = cpu_to_le32(cfg->threshold_entry);
+ cmd_params->threshold_exit = cpu_to_le32(cfg->threshold_exit);
+
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpseci_get_congestion_notification() - Get congestion group notification
+ * configuration
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSECI object
+ * @cfg: congestion notification configuration
+ *
+ * Return: '0' on success, error code otherwise
+ */
+int dpseci_get_congestion_notification(struct fsl_mc_io *mc_io, u32 cmd_flags,
+ u16 token, struct dpseci_congestion_notification_cfg *cfg)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpseci_cmd_congestion_notification *rsp_params;
+ int err;
+
+ cmd.header = mc_encode_cmd_header(
+ DPSECI_CMDID_GET_CONGESTION_NOTIFICATION,
+ cmd_flags,
+ token);
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ rsp_params = (struct dpseci_cmd_congestion_notification *)cmd.params;
+ cfg->dest_cfg.dest_id = le32_to_cpu(rsp_params->dest_id);
+ cfg->notification_mode = le16_to_cpu(rsp_params->notification_mode);
+ cfg->dest_cfg.priority = rsp_params->priority;
+ cfg->dest_cfg.dest_type = dpseci_get_field(rsp_params->options,
+ CGN_DEST_TYPE);
+ cfg->units = dpseci_get_field(rsp_params->options, CGN_UNITS);
+ cfg->message_iova = le64_to_cpu(rsp_params->message_iova);
+ cfg->message_ctx = le64_to_cpu(rsp_params->message_ctx);
+ cfg->threshold_entry = le32_to_cpu(rsp_params->threshold_entry);
+ cfg->threshold_exit = le32_to_cpu(rsp_params->threshold_exit);
+
+ return 0;
+}
diff --git a/drivers/crypto/caam/dpseci.h b/drivers/crypto/caam/dpseci.h
new file mode 100644
index 000000000000..4550e134d166
--- /dev/null
+++ b/drivers/crypto/caam/dpseci.h
@@ -0,0 +1,333 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+/*
+ * Copyright 2013-2016 Freescale Semiconductor Inc.
+ * Copyright 2017-2018 NXP
+ */
+#ifndef _DPSECI_H_
+#define _DPSECI_H_
+
+/*
+ * Data Path SEC Interface API
+ * Contains initialization APIs and runtime control APIs for DPSECI
+ */
+
+struct fsl_mc_io;
+
+/**
+ * General DPSECI macros
+ */
+
+/**
+ * Maximum number of Tx/Rx queues per DPSECI object
+ */
+#define DPSECI_MAX_QUEUE_NUM 16
+
+/**
+ * All queues considered; see dpseci_set_rx_queue()
+ */
+#define DPSECI_ALL_QUEUES (u8)(-1)
+
+int dpseci_open(struct fsl_mc_io *mc_io, u32 cmd_flags, int dpseci_id,
+ u16 *token);
+
+int dpseci_close(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token);
+
+/**
+ * Enable the Congestion Group support
+ */
+#define DPSECI_OPT_HAS_CG 0x000020
+
+/**
+ * struct dpseci_cfg - Structure representing DPSECI configuration
+ * @options: Any combination of the following flags:
+ * DPSECI_OPT_HAS_CG
+ * @num_tx_queues: num of queues towards the SEC
+ * @num_rx_queues: num of queues back from the SEC
+ * @priorities: Priorities for the SEC hardware processing;
+ * each place in the array is the priority of the tx queue
+ * towards the SEC;
+ * valid priorities are configured with values 1-8;
+ */
+struct dpseci_cfg {
+ u32 options;
+ u8 num_tx_queues;
+ u8 num_rx_queues;
+ u8 priorities[DPSECI_MAX_QUEUE_NUM];
+};
+
+int dpseci_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token);
+
+int dpseci_disable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token);
+
+int dpseci_is_enabled(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+ int *en);
+
+/**
+ * struct dpseci_attr - Structure representing DPSECI attributes
+ * @id: DPSECI object ID
+ * @num_tx_queues: number of queues towards the SEC
+ * @num_rx_queues: number of queues back from the SEC
+ * @options: any combination of the following flags:
+ * DPSECI_OPT_HAS_CG
+ */
+struct dpseci_attr {
+ int id;
+ u8 num_tx_queues;
+ u8 num_rx_queues;
+ u32 options;
+};
+
+int dpseci_get_attributes(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+ struct dpseci_attr *attr);
+
+/**
+ * enum dpseci_dest - DPSECI destination types
+ * @DPSECI_DEST_NONE: Unassigned destination; The queue is set in parked mode
+ * and does not generate FQDAN notifications; user is expected to dequeue
+ * from the queue based on polling or other user-defined method
+ * @DPSECI_DEST_DPIO: The queue is set in schedule mode and generates FQDAN
+ * notifications to the specified DPIO; user is expected to dequeue from
+ * the queue only after notification is received
+ * @DPSECI_DEST_DPCON: The queue is set in schedule mode and does not generate
+ * FQDAN notifications, but is connected to the specified DPCON object;
+ * user is expected to dequeue from the DPCON channel
+ */
+enum dpseci_dest {
+ DPSECI_DEST_NONE = 0,
+ DPSECI_DEST_DPIO,
+ DPSECI_DEST_DPCON
+};
+
+/**
+ * struct dpseci_dest_cfg - Structure representing DPSECI destination parameters
+ * @dest_type: Destination type
+ * @dest_id: Either DPIO ID or DPCON ID, depending on the destination type
+ * @priority: Priority selection within the DPIO or DPCON channel; valid values
+ * are 0-1 or 0-7, depending on the number of priorities in that channel;
+ * not relevant for 'DPSECI_DEST_NONE' option
+ */
+struct dpseci_dest_cfg {
+ enum dpseci_dest dest_type;
+ int dest_id;
+ u8 priority;
+};
+
+/**
+ * DPSECI queue modification options
+ */
+
+/**
+ * Select to modify the user's context associated with the queue
+ */
+#define DPSECI_QUEUE_OPT_USER_CTX 0x00000001
+
+/**
+ * Select to modify the queue's destination
+ */
+#define DPSECI_QUEUE_OPT_DEST 0x00000002
+
+/**
+ * Select to modify the queue's order preservation
+ */
+#define DPSECI_QUEUE_OPT_ORDER_PRESERVATION 0x00000004
+
+/**
+ * struct dpseci_rx_queue_cfg - DPSECI RX queue configuration
+ * @options: Flags representing the suggested modifications to the queue;
+ * Use any combination of 'DPSECI_QUEUE_OPT_<X>' flags
+ * @order_preservation_en: order preservation configuration for the rx queue
+ * valid only if 'DPSECI_QUEUE_OPT_ORDER_PRESERVATION' is contained in 'options'
+ * @user_ctx: User context value provided in the frame descriptor of each
+ * dequeued frame; valid only if 'DPSECI_QUEUE_OPT_USER_CTX' is contained
+ * in 'options'
+ * @dest_cfg: Queue destination parameters; valid only if
+ * 'DPSECI_QUEUE_OPT_DEST' is contained in 'options'
+ */
+struct dpseci_rx_queue_cfg {
+ u32 options;
+ int order_preservation_en;
+ u64 user_ctx;
+ struct dpseci_dest_cfg dest_cfg;
+};
+
+int dpseci_set_rx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+ u8 queue, const struct dpseci_rx_queue_cfg *cfg);
+
+/**
+ * struct dpseci_rx_queue_attr - Structure representing attributes of Rx queues
+ * @user_ctx: User context value provided in the frame descriptor of each
+ * dequeued frame
+ * @order_preservation_en: Status of the order preservation configuration on the
+ * queue
+ * @dest_cfg: Queue destination configuration
+ * @fqid: Virtual FQID value to be used for dequeue operations
+ */
+struct dpseci_rx_queue_attr {
+ u64 user_ctx;
+ int order_preservation_en;
+ struct dpseci_dest_cfg dest_cfg;
+ u32 fqid;
+};
+
+int dpseci_get_rx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+ u8 queue, struct dpseci_rx_queue_attr *attr);
+
+/**
+ * struct dpseci_tx_queue_attr - Structure representing attributes of Tx queues
+ * @fqid: Virtual FQID to be used for sending frames to SEC hardware
+ * @priority: SEC hardware processing priority for the queue
+ */
+struct dpseci_tx_queue_attr {
+ u32 fqid;
+ u8 priority;
+};
+
+int dpseci_get_tx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+ u8 queue, struct dpseci_tx_queue_attr *attr);
+
+/**
+ * struct dpseci_sec_attr - Structure representing attributes of the SEC
+ * hardware accelerator
+ * @ip_id: ID for SEC
+ * @major_rev: Major revision number for SEC
+ * @minor_rev: Minor revision number for SEC
+ * @era: SEC Era
+ * @deco_num: The number of copies of the DECO that are implemented in this
+ * version of SEC
+ * @zuc_auth_acc_num: The number of copies of ZUCA that are implemented in this
+ * version of SEC
+ * @zuc_enc_acc_num: The number of copies of ZUCE that are implemented in this
+ * version of SEC
+ * @snow_f8_acc_num: The number of copies of the SNOW-f8 module that are
+ * implemented in this version of SEC
+ * @snow_f9_acc_num: The number of copies of the SNOW-f9 module that are
+ * implemented in this version of SEC
+ * @crc_acc_num: The number of copies of the CRC module that are implemented in
+ * this version of SEC
+ * @pk_acc_num: The number of copies of the Public Key module that are
+ * implemented in this version of SEC
+ * @kasumi_acc_num: The number of copies of the Kasumi module that are
+ * implemented in this version of SEC
+ * @rng_acc_num: The number of copies of the Random Number Generator that are
+ * implemented in this version of SEC
+ * @md_acc_num: The number of copies of the MDHA (Hashing module) that are
+ * implemented in this version of SEC
+ * @arc4_acc_num: The number of copies of the ARC4 module that are implemented
+ * in this version of SEC
+ * @des_acc_num: The number of copies of the DES module that are implemented in
+ * this version of SEC
+ * @aes_acc_num: The number of copies of the AES module that are implemented in
+ * this version of SEC
+ * @ccha_acc_num: The number of copies of the ChaCha20 module that are
+ * implemented in this version of SEC.
+ * @ptha_acc_num: The number of copies of the Poly1305 module that are
+ * implemented in this version of SEC.
+ **/
+struct dpseci_sec_attr {
+ u16 ip_id;
+ u8 major_rev;
+ u8 minor_rev;
+ u8 era;
+ u8 deco_num;
+ u8 zuc_auth_acc_num;
+ u8 zuc_enc_acc_num;
+ u8 snow_f8_acc_num;
+ u8 snow_f9_acc_num;
+ u8 crc_acc_num;
+ u8 pk_acc_num;
+ u8 kasumi_acc_num;
+ u8 rng_acc_num;
+ u8 md_acc_num;
+ u8 arc4_acc_num;
+ u8 des_acc_num;
+ u8 aes_acc_num;
+ u8 ccha_acc_num;
+ u8 ptha_acc_num;
+};
+
+int dpseci_get_sec_attr(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+ struct dpseci_sec_attr *attr);
+
+int dpseci_get_api_version(struct fsl_mc_io *mc_io, u32 cmd_flags,
+ u16 *major_ver, u16 *minor_ver);
+
+/**
+ * enum dpseci_congestion_unit - DPSECI congestion units
+ * @DPSECI_CONGESTION_UNIT_BYTES: bytes units
+ * @DPSECI_CONGESTION_UNIT_FRAMES: frames units
+ */
+enum dpseci_congestion_unit {
+ DPSECI_CONGESTION_UNIT_BYTES = 0,
+ DPSECI_CONGESTION_UNIT_FRAMES
+};
+
+/**
+ * CSCN message is written to message_iova once entering a
+ * congestion state (see 'threshold_entry')
+ */
+#define DPSECI_CGN_MODE_WRITE_MEM_ON_ENTER 0x00000001
+
+/**
+ * CSCN message is written to message_iova once exiting a
+ * congestion state (see 'threshold_exit')
+ */
+#define DPSECI_CGN_MODE_WRITE_MEM_ON_EXIT 0x00000002
+
+/**
+ * CSCN write will attempt to allocate into a cache (coherent write);
+ * valid only if 'DPSECI_CGN_MODE_WRITE_MEM_<X>' is selected
+ */
+#define DPSECI_CGN_MODE_COHERENT_WRITE 0x00000004
+
+/**
+ * if 'dpseci_dest_cfg.dest_type != DPSECI_DEST_NONE' CSCN message is sent to
+ * DPIO/DPCON's WQ channel once entering a congestion state
+ * (see 'threshold_entry')
+ */
+#define DPSECI_CGN_MODE_NOTIFY_DEST_ON_ENTER 0x00000008
+
+/**
+ * if 'dpseci_dest_cfg.dest_type != DPSECI_DEST_NONE' CSCN message is sent to
+ * DPIO/DPCON's WQ channel once exiting a congestion state
+ * (see 'threshold_exit')
+ */
+#define DPSECI_CGN_MODE_NOTIFY_DEST_ON_EXIT 0x00000010
+
+/**
+ * if 'dpseci_dest_cfg.dest_type != DPSECI_DEST_NONE' when the CSCN is written
+ * to the sw-portal's DQRR, the DQRI interrupt is asserted immediately
+ * (if enabled)
+ */
+#define DPSECI_CGN_MODE_INTR_COALESCING_DISABLED 0x00000020
+
+/**
+ * struct dpseci_congestion_notification_cfg - congestion notification
+ * configuration
+ * @units: units type
+ * @threshold_entry: above this threshold we enter a congestion state.
+ * set it to '0' to disable it
+ * @threshold_exit: below this threshold we exit the congestion state.
+ * @message_ctx: The context that will be part of the CSCN message
+ * @message_iova: I/O virtual address (must be in DMA-able memory),
+ * must be 16B aligned;
+ * @dest_cfg: CSCN can be send to either DPIO or DPCON WQ channel
+ * @notification_mode: Mask of available options; use 'DPSECI_CGN_MODE_<X>'
+ * values
+ */
+struct dpseci_congestion_notification_cfg {
+ enum dpseci_congestion_unit units;
+ u32 threshold_entry;
+ u32 threshold_exit;
+ u64 message_ctx;
+ u64 message_iova;
+ struct dpseci_dest_cfg dest_cfg;
+ u16 notification_mode;
+};
+
+int dpseci_set_congestion_notification(struct fsl_mc_io *mc_io, u32 cmd_flags,
+ u16 token, const struct dpseci_congestion_notification_cfg *cfg);
+
+int dpseci_get_congestion_notification(struct fsl_mc_io *mc_io, u32 cmd_flags,
+ u16 token, struct dpseci_congestion_notification_cfg *cfg);
+
+#endif /* _DPSECI_H_ */
diff --git a/drivers/crypto/caam/dpseci_cmd.h b/drivers/crypto/caam/dpseci_cmd.h
new file mode 100644
index 000000000000..6ab77ead6e3d
--- /dev/null
+++ b/drivers/crypto/caam/dpseci_cmd.h
@@ -0,0 +1,149 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+/*
+ * Copyright 2013-2016 Freescale Semiconductor Inc.
+ * Copyright 2017-2018 NXP
+ */
+
+#ifndef _DPSECI_CMD_H_
+#define _DPSECI_CMD_H_
+
+/* DPSECI Version */
+#define DPSECI_VER_MAJOR 5
+#define DPSECI_VER_MINOR 3
+
+#define DPSECI_VER(maj, min) (((maj) << 16) | (min))
+#define DPSECI_VERSION DPSECI_VER(DPSECI_VER_MAJOR, DPSECI_VER_MINOR)
+
+/* Command versioning */
+#define DPSECI_CMD_BASE_VERSION 1
+#define DPSECI_CMD_BASE_VERSION_V2 2
+#define DPSECI_CMD_ID_OFFSET 4
+
+#define DPSECI_CMD_V1(id) (((id) << DPSECI_CMD_ID_OFFSET) | \
+ DPSECI_CMD_BASE_VERSION)
+
+#define DPSECI_CMD_V2(id) (((id) << DPSECI_CMD_ID_OFFSET) | \
+ DPSECI_CMD_BASE_VERSION_V2)
+
+/* Command IDs */
+#define DPSECI_CMDID_CLOSE DPSECI_CMD_V1(0x800)
+#define DPSECI_CMDID_OPEN DPSECI_CMD_V1(0x809)
+#define DPSECI_CMDID_GET_API_VERSION DPSECI_CMD_V1(0xa09)
+
+#define DPSECI_CMDID_ENABLE DPSECI_CMD_V1(0x002)
+#define DPSECI_CMDID_DISABLE DPSECI_CMD_V1(0x003)
+#define DPSECI_CMDID_GET_ATTR DPSECI_CMD_V1(0x004)
+#define DPSECI_CMDID_IS_ENABLED DPSECI_CMD_V1(0x006)
+
+#define DPSECI_CMDID_SET_RX_QUEUE DPSECI_CMD_V1(0x194)
+#define DPSECI_CMDID_GET_RX_QUEUE DPSECI_CMD_V1(0x196)
+#define DPSECI_CMDID_GET_TX_QUEUE DPSECI_CMD_V1(0x197)
+#define DPSECI_CMDID_GET_SEC_ATTR DPSECI_CMD_V2(0x198)
+#define DPSECI_CMDID_SET_CONGESTION_NOTIFICATION DPSECI_CMD_V1(0x170)
+#define DPSECI_CMDID_GET_CONGESTION_NOTIFICATION DPSECI_CMD_V1(0x171)
+
+/* Macros for accessing command fields smaller than 1 byte */
+#define DPSECI_MASK(field) \
+ GENMASK(DPSECI_##field##_SHIFT + DPSECI_##field##_SIZE - 1, \
+ DPSECI_##field##_SHIFT)
+
+#define dpseci_set_field(var, field, val) \
+ ((var) |= (((val) << DPSECI_##field##_SHIFT) & DPSECI_MASK(field)))
+
+#define dpseci_get_field(var, field) \
+ (((var) & DPSECI_MASK(field)) >> DPSECI_##field##_SHIFT)
+
+struct dpseci_cmd_open {
+ __le32 dpseci_id;
+};
+
+#define DPSECI_ENABLE_SHIFT 0
+#define DPSECI_ENABLE_SIZE 1
+
+struct dpseci_rsp_is_enabled {
+ u8 is_enabled;
+};
+
+struct dpseci_rsp_get_attributes {
+ __le32 id;
+ __le32 pad0;
+ u8 num_tx_queues;
+ u8 num_rx_queues;
+ u8 pad1[6];
+ __le32 options;
+};
+
+#define DPSECI_DEST_TYPE_SHIFT 0
+#define DPSECI_DEST_TYPE_SIZE 4
+
+#define DPSECI_ORDER_PRESERVATION_SHIFT 0
+#define DPSECI_ORDER_PRESERVATION_SIZE 1
+
+struct dpseci_cmd_queue {
+ __le32 dest_id;
+ u8 priority;
+ u8 queue;
+ u8 dest_type;
+ u8 pad;
+ __le64 user_ctx;
+ union {
+ __le32 options;
+ __le32 fqid;
+ };
+ u8 order_preservation_en;
+};
+
+struct dpseci_rsp_get_tx_queue {
+ __le32 pad;
+ __le32 fqid;
+ u8 priority;
+};
+
+struct dpseci_rsp_get_sec_attr {
+ __le16 ip_id;
+ u8 major_rev;
+ u8 minor_rev;
+ u8 era;
+ u8 pad0[3];
+ u8 deco_num;
+ u8 zuc_auth_acc_num;
+ u8 zuc_enc_acc_num;
+ u8 pad1;
+ u8 snow_f8_acc_num;
+ u8 snow_f9_acc_num;
+ u8 crc_acc_num;
+ u8 pad2;
+ u8 pk_acc_num;
+ u8 kasumi_acc_num;
+ u8 rng_acc_num;
+ u8 pad3;
+ u8 md_acc_num;
+ u8 arc4_acc_num;
+ u8 des_acc_num;
+ u8 aes_acc_num;
+ u8 ccha_acc_num;
+ u8 ptha_acc_num;
+};
+
+struct dpseci_rsp_get_api_version {
+ __le16 major;
+ __le16 minor;
+};
+
+#define DPSECI_CGN_DEST_TYPE_SHIFT 0
+#define DPSECI_CGN_DEST_TYPE_SIZE 4
+#define DPSECI_CGN_UNITS_SHIFT 4
+#define DPSECI_CGN_UNITS_SIZE 2
+
+struct dpseci_cmd_congestion_notification {
+ __le32 dest_id;
+ __le16 notification_mode;
+ u8 priority;
+ u8 options;
+ __le64 message_iova;
+ __le64 message_ctx;
+ __le32 threshold_entry;
+ __le32 threshold_exit;
+};
+
+#endif /* _DPSECI_CMD_H_ */
diff --git a/drivers/crypto/caam/error.c b/drivers/crypto/caam/error.c
index 8da88beb1abb..7e8d690f2827 100644
--- a/drivers/crypto/caam/error.c
+++ b/drivers/crypto/caam/error.c
@@ -108,6 +108,54 @@ static const struct {
{ 0xF1, "3GPP HFN matches or exceeds the Threshold" },
};
+static const struct {
+ u8 value;
+ const char *error_text;
+} qi_error_list[] = {
+ { 0x1F, "Job terminated by FQ or ICID flush" },
+ { 0x20, "FD format error"},
+ { 0x21, "FD command format error"},
+ { 0x23, "FL format error"},
+ { 0x25, "CRJD specified in FD, but not enabled in FLC"},
+ { 0x30, "Max. buffer size too small"},
+ { 0x31, "DHR exceeds max. buffer size (allocate mode, S/G format)"},
+ { 0x32, "SGT exceeds max. buffer size (allocate mode, S/G format"},
+ { 0x33, "Size over/underflow (allocate mode)"},
+ { 0x34, "Size over/underflow (reuse mode)"},
+ { 0x35, "Length exceeds max. short length (allocate mode, S/G/ format)"},
+ { 0x36, "Memory footprint exceeds max. value (allocate mode, S/G/ format)"},
+ { 0x41, "SBC frame format not supported (allocate mode)"},
+ { 0x42, "Pool 0 invalid / pool 1 size < pool 0 size (allocate mode)"},
+ { 0x43, "Annotation output enabled but ASAR = 0 (allocate mode)"},
+ { 0x44, "Unsupported or reserved frame format or SGHR = 1 (reuse mode)"},
+ { 0x45, "DHR correction underflow (reuse mode, single buffer format)"},
+ { 0x46, "Annotation length exceeds offset (reuse mode)"},
+ { 0x48, "Annotation output enabled but ASA limited by ASAR (reuse mode)"},
+ { 0x49, "Data offset correction exceeds input frame data length (reuse mode)"},
+ { 0x4B, "Annotation output enabled but ASA cannote be expanded (frame list)"},
+ { 0x51, "Unsupported IF reuse mode"},
+ { 0x52, "Unsupported FL use mode"},
+ { 0x53, "Unsupported RJD use mode"},
+ { 0x54, "Unsupported inline descriptor use mode"},
+ { 0xC0, "Table buffer pool 0 depletion"},
+ { 0xC1, "Table buffer pool 1 depletion"},
+ { 0xC2, "Data buffer pool 0 depletion, no OF allocated"},
+ { 0xC3, "Data buffer pool 1 depletion, no OF allocated"},
+ { 0xC4, "Data buffer pool 0 depletion, partial OF allocated"},
+ { 0xC5, "Data buffer pool 1 depletion, partial OF allocated"},
+ { 0xD0, "FLC read error"},
+ { 0xD1, "FL read error"},
+ { 0xD2, "FL write error"},
+ { 0xD3, "OF SGT write error"},
+ { 0xD4, "PTA read error"},
+ { 0xD5, "PTA write error"},
+ { 0xD6, "OF SGT F-bit write error"},
+ { 0xD7, "ASA write error"},
+ { 0xE1, "FLC[ICR]=0 ICID error"},
+ { 0xE2, "FLC[ICR]=1 ICID error"},
+ { 0xE4, "source of ICID flush not trusted (BDI = 0)"},
+};
+
static const char * const cha_id_list[] = {
"",
"AES",
@@ -236,6 +284,27 @@ static void report_deco_status(struct device *jrdev, const u32 status,
status, error, idx_str, idx, err_str, err_err_code);
}
+static void report_qi_status(struct device *qidev, const u32 status,
+ const char *error)
+{
+ u8 err_id = status & JRSTA_QIERR_ERROR_MASK;
+ const char *err_str = "unidentified error value 0x";
+ char err_err_code[3] = { 0 };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(qi_error_list); i++)
+ if (qi_error_list[i].value == err_id)
+ break;
+
+ if (i != ARRAY_SIZE(qi_error_list) && qi_error_list[i].error_text)
+ err_str = qi_error_list[i].error_text;
+ else
+ snprintf(err_err_code, sizeof(err_err_code), "%02x", err_id);
+
+ dev_err(qidev, "%08x: %s: %s%s\n",
+ status, error, err_str, err_err_code);
+}
+
static void report_jr_status(struct device *jrdev, const u32 status,
const char *error)
{
@@ -250,7 +319,7 @@ static void report_cond_code_status(struct device *jrdev, const u32 status,
status, error, __func__);
}
-void caam_jr_strstatus(struct device *jrdev, u32 status)
+void caam_strstatus(struct device *jrdev, u32 status, bool qi_v2)
{
static const struct stat_src {
void (*report_ssed)(struct device *jrdev, const u32 status,
@@ -262,7 +331,7 @@ void caam_jr_strstatus(struct device *jrdev, u32 status)
{ report_ccb_status, "CCB" },
{ report_jump_status, "Jump" },
{ report_deco_status, "DECO" },
- { NULL, "Queue Manager Interface" },
+ { report_qi_status, "Queue Manager Interface" },
{ report_jr_status, "Job Ring" },
{ report_cond_code_status, "Condition Code" },
{ NULL, NULL },
@@ -288,4 +357,8 @@ void caam_jr_strstatus(struct device *jrdev, u32 status)
else
dev_err(jrdev, "%d: unknown error source\n", ssrc);
}
-EXPORT_SYMBOL(caam_jr_strstatus);
+EXPORT_SYMBOL(caam_strstatus);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("FSL CAAM error reporting");
+MODULE_AUTHOR("Freescale Semiconductor");
diff --git a/drivers/crypto/caam/error.h b/drivers/crypto/caam/error.h
index 5aa332bac4b0..67ea94079837 100644
--- a/drivers/crypto/caam/error.h
+++ b/drivers/crypto/caam/error.h
@@ -8,7 +8,11 @@
#ifndef CAAM_ERROR_H
#define CAAM_ERROR_H
#define CAAM_ERROR_STR_MAX 302
-void caam_jr_strstatus(struct device *jrdev, u32 status);
+
+void caam_strstatus(struct device *dev, u32 status, bool qi_v2);
+
+#define caam_jr_strstatus(jrdev, status) caam_strstatus(jrdev, status, false)
+#define caam_qi2_strstatus(qidev, status) caam_strstatus(qidev, status, true)
void caam_dump_sg(const char *level, const char *prefix_str, int prefix_type,
int rowsize, int groupsize, struct scatterlist *sg,
diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c
index acdd72016ffe..d50085a03597 100644
--- a/drivers/crypto/caam/jr.c
+++ b/drivers/crypto/caam/jr.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* CAAM/SEC 4.x transport/backend driver
* JobR backend functionality
diff --git a/drivers/crypto/caam/qi.c b/drivers/crypto/caam/qi.c
index 67f7f8c42c93..b84e6c8b1e13 100644
--- a/drivers/crypto/caam/qi.c
+++ b/drivers/crypto/caam/qi.c
@@ -84,13 +84,6 @@ static u64 times_congested;
#endif
/*
- * CPU from where the module initialised. This is required because QMan driver
- * requires CGRs to be removed from same CPU from where they were originally
- * allocated.
- */
-static int mod_init_cpu;
-
-/*
* This is a a cache of buffers, from which the users of CAAM QI driver
* can allocate short (CAAM_QI_MEMCACHE_SIZE) buffers. It's faster than
* doing malloc on the hotpath.
@@ -492,12 +485,11 @@ void caam_drv_ctx_rel(struct caam_drv_ctx *drv_ctx)
}
EXPORT_SYMBOL(caam_drv_ctx_rel);
-int caam_qi_shutdown(struct device *qidev)
+void caam_qi_shutdown(struct device *qidev)
{
- int i, ret;
+ int i;
struct caam_qi_priv *priv = dev_get_drvdata(qidev);
const cpumask_t *cpus = qman_affine_cpus();
- struct cpumask old_cpumask = current->cpus_allowed;
for_each_cpu(i, cpus) {
struct napi_struct *irqtask;
@@ -510,26 +502,12 @@ int caam_qi_shutdown(struct device *qidev)
dev_err(qidev, "Rsp FQ kill failed, cpu: %d\n", i);
}
- /*
- * QMan driver requires CGRs to be deleted from same CPU from where they
- * were instantiated. Hence we get the module removal execute from the
- * same CPU from where it was originally inserted.
- */
- set_cpus_allowed_ptr(current, get_cpu_mask(mod_init_cpu));
-
- ret = qman_delete_cgr(&priv->cgr);
- if (ret)
- dev_err(qidev, "Deletion of CGR failed: %d\n", ret);
- else
- qman_release_cgrid(priv->cgr.cgrid);
+ qman_delete_cgr_safe(&priv->cgr);
+ qman_release_cgrid(priv->cgr.cgrid);
kmem_cache_destroy(qi_cache);
- /* Now that we're done with the CGRs, restore the cpus allowed mask */
- set_cpus_allowed_ptr(current, &old_cpumask);
-
platform_device_unregister(priv->qi_pdev);
- return ret;
}
static void cgr_cb(struct qman_portal *qm, struct qman_cgr *cgr, int congested)
@@ -718,22 +696,11 @@ int caam_qi_init(struct platform_device *caam_pdev)
struct device *ctrldev = &caam_pdev->dev, *qidev;
struct caam_drv_private *ctrlpriv;
const cpumask_t *cpus = qman_affine_cpus();
- struct cpumask old_cpumask = current->cpus_allowed;
static struct platform_device_info qi_pdev_info = {
.name = "caam_qi",
.id = PLATFORM_DEVID_NONE
};
- /*
- * QMAN requires CGRs to be removed from same CPU+portal from where it
- * was originally allocated. Hence we need to note down the
- * initialisation CPU and use the same CPU for module exit.
- * We select the first CPU to from the list of portal owning CPUs.
- * Then we pin module init to this CPU.
- */
- mod_init_cpu = cpumask_first(cpus);
- set_cpus_allowed_ptr(current, get_cpu_mask(mod_init_cpu));
-
qi_pdev_info.parent = ctrldev;
qi_pdev_info.dma_mask = dma_get_mask(ctrldev);
qi_pdev = platform_device_register_full(&qi_pdev_info);
@@ -795,8 +762,6 @@ int caam_qi_init(struct platform_device *caam_pdev)
return -ENOMEM;
}
- /* Done with the CGRs; restore the cpus allowed mask */
- set_cpus_allowed_ptr(current, &old_cpumask);
#ifdef CONFIG_DEBUG_FS
debugfs_create_file("qi_congested", 0444, ctrlpriv->ctl,
&times_congested, &caam_fops_u64_ro);
diff --git a/drivers/crypto/caam/qi.h b/drivers/crypto/caam/qi.h
index 357b69f57072..f93c9c7ed430 100644
--- a/drivers/crypto/caam/qi.h
+++ b/drivers/crypto/caam/qi.h
@@ -62,7 +62,6 @@ typedef void (*caam_qi_cbk)(struct caam_drv_req *drv_req, u32 status);
enum optype {
ENCRYPT,
DECRYPT,
- GIVENCRYPT,
NUM_OP
};
@@ -174,7 +173,7 @@ int caam_drv_ctx_update(struct caam_drv_ctx *drv_ctx, u32 *sh_desc);
void caam_drv_ctx_rel(struct caam_drv_ctx *drv_ctx);
int caam_qi_init(struct platform_device *pdev);
-int caam_qi_shutdown(struct device *dev);
+void caam_qi_shutdown(struct device *dev);
/**
* qi_cache_alloc - Allocate buffers from CAAM-QI cache
diff --git a/drivers/crypto/caam/regs.h b/drivers/crypto/caam/regs.h
index 4fb91ba39c36..457815f965c0 100644
--- a/drivers/crypto/caam/regs.h
+++ b/drivers/crypto/caam/regs.h
@@ -70,22 +70,22 @@
extern bool caam_little_end;
extern bool caam_imx;
-#define caam_to_cpu(len) \
-static inline u##len caam##len ## _to_cpu(u##len val) \
-{ \
- if (caam_little_end) \
- return le##len ## _to_cpu(val); \
- else \
- return be##len ## _to_cpu(val); \
+#define caam_to_cpu(len) \
+static inline u##len caam##len ## _to_cpu(u##len val) \
+{ \
+ if (caam_little_end) \
+ return le##len ## _to_cpu((__force __le##len)val); \
+ else \
+ return be##len ## _to_cpu((__force __be##len)val); \
}
-#define cpu_to_caam(len) \
-static inline u##len cpu_to_caam##len(u##len val) \
-{ \
- if (caam_little_end) \
- return cpu_to_le##len(val); \
- else \
- return cpu_to_be##len(val); \
+#define cpu_to_caam(len) \
+static inline u##len cpu_to_caam##len(u##len val) \
+{ \
+ if (caam_little_end) \
+ return (__force u##len)cpu_to_le##len(val); \
+ else \
+ return (__force u##len)cpu_to_be##len(val); \
}
caam_to_cpu(16)
@@ -633,6 +633,8 @@ struct caam_job_ring {
#define JRSTA_DECOERR_INVSIGN 0x86
#define JRSTA_DECOERR_DSASIGN 0x87
+#define JRSTA_QIERR_ERROR_MASK 0x00ff
+
#define JRSTA_CCBERR_JUMP 0x08000000
#define JRSTA_CCBERR_INDEX_MASK 0xff00
#define JRSTA_CCBERR_INDEX_SHIFT 8
diff --git a/drivers/crypto/caam/sg_sw_qm.h b/drivers/crypto/caam/sg_sw_qm.h
index d000b4df745f..b3e1aaaeffea 100644
--- a/drivers/crypto/caam/sg_sw_qm.h
+++ b/drivers/crypto/caam/sg_sw_qm.h
@@ -1,34 +1,7 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
/*
* Copyright 2013-2016 Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of Freescale Semiconductor nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") as published by the Free Software
- * Foundation, either version 2 of that License or (at your option) any
- * later version.
- *
- * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
*/
#ifndef __SG_SW_QM_H
diff --git a/drivers/crypto/caam/sg_sw_qm2.h b/drivers/crypto/caam/sg_sw_qm2.h
index b5b4c12179df..c9378402a5f8 100644
--- a/drivers/crypto/caam/sg_sw_qm2.h
+++ b/drivers/crypto/caam/sg_sw_qm2.h
@@ -1,35 +1,7 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
/*
* Copyright 2015-2016 Freescale Semiconductor, Inc.
* Copyright 2017 NXP
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the names of the above-listed copyright holders nor the
- * names of any contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") as published by the Free Software
- * Foundation, either version 2 of that License or (at your option) any
- * later version.
- *
- * 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 HOLDERS 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.
*/
#ifndef _SG_SW_QM2_H_
diff --git a/drivers/crypto/cavium/cpt/cptvf_reqmanager.c b/drivers/crypto/cavium/cpt/cptvf_reqmanager.c
index b0ba4331944b..ca549c5dc08e 100644
--- a/drivers/crypto/cavium/cpt/cptvf_reqmanager.c
+++ b/drivers/crypto/cavium/cpt/cptvf_reqmanager.c
@@ -308,21 +308,11 @@ void do_request_cleanup(struct cpt_vf *cptvf,
}
}
- if (info->scatter_components)
- kzfree(info->scatter_components);
-
- if (info->gather_components)
- kzfree(info->gather_components);
-
- if (info->out_buffer)
- kzfree(info->out_buffer);
-
- if (info->in_buffer)
- kzfree(info->in_buffer);
-
- if (info->completion_addr)
- kzfree((void *)info->completion_addr);
-
+ kzfree(info->scatter_components);
+ kzfree(info->gather_components);
+ kzfree(info->out_buffer);
+ kzfree(info->in_buffer);
+ kzfree((void *)info->completion_addr);
kzfree(info);
}
diff --git a/drivers/crypto/cavium/nitrox/Makefile b/drivers/crypto/cavium/nitrox/Makefile
index 45b7379e8e30..e12954791673 100644
--- a/drivers/crypto/cavium/nitrox/Makefile
+++ b/drivers/crypto/cavium/nitrox/Makefile
@@ -7,3 +7,6 @@ n5pf-objs := nitrox_main.o \
nitrox_hal.o \
nitrox_reqmgr.o \
nitrox_algs.o
+
+n5pf-$(CONFIG_PCI_IOV) += nitrox_sriov.o
+n5pf-$(CONFIG_DEBUG_FS) += nitrox_debugfs.o
diff --git a/drivers/crypto/cavium/nitrox/nitrox_common.h b/drivers/crypto/cavium/nitrox/nitrox_common.h
index 312f72801af6..863143a8336b 100644
--- a/drivers/crypto/cavium/nitrox/nitrox_common.h
+++ b/drivers/crypto/cavium/nitrox/nitrox_common.h
@@ -12,32 +12,15 @@ void crypto_free_context(void *ctx);
struct nitrox_device *nitrox_get_first_device(void);
void nitrox_put_device(struct nitrox_device *ndev);
-void nitrox_pf_cleanup_isr(struct nitrox_device *ndev);
-int nitrox_pf_init_isr(struct nitrox_device *ndev);
-
int nitrox_common_sw_init(struct nitrox_device *ndev);
void nitrox_common_sw_cleanup(struct nitrox_device *ndev);
-void pkt_slc_resp_handler(unsigned long data);
+void pkt_slc_resp_tasklet(unsigned long data);
int nitrox_process_se_request(struct nitrox_device *ndev,
struct se_crypto_request *req,
completion_t cb,
struct skcipher_request *skreq);
void backlog_qflush_work(struct work_struct *work);
-void nitrox_config_emu_unit(struct nitrox_device *ndev);
-void nitrox_config_pkt_input_rings(struct nitrox_device *ndev);
-void nitrox_config_pkt_solicit_ports(struct nitrox_device *ndev);
-void nitrox_config_vfmode(struct nitrox_device *ndev, int mode);
-void nitrox_config_nps_unit(struct nitrox_device *ndev);
-void nitrox_config_pom_unit(struct nitrox_device *ndev);
-void nitrox_config_rand_unit(struct nitrox_device *ndev);
-void nitrox_config_efl_unit(struct nitrox_device *ndev);
-void nitrox_config_bmi_unit(struct nitrox_device *ndev);
-void nitrox_config_bmo_unit(struct nitrox_device *ndev);
-void nitrox_config_lbc_unit(struct nitrox_device *ndev);
-void invalidate_lbc(struct nitrox_device *ndev);
-void enable_pkt_input_ring(struct nitrox_device *ndev, int ring);
-void enable_pkt_solicit_port(struct nitrox_device *ndev, int port);
#endif /* __NITROX_COMMON_H */
diff --git a/drivers/crypto/cavium/nitrox/nitrox_csr.h b/drivers/crypto/cavium/nitrox/nitrox_csr.h
index 9dcb7fdbe0a7..1ad27b1a87c5 100644
--- a/drivers/crypto/cavium/nitrox/nitrox_csr.h
+++ b/drivers/crypto/cavium/nitrox/nitrox_csr.h
@@ -7,9 +7,16 @@
/* EMU clusters */
#define NR_CLUSTERS 4
+/* Maximum cores per cluster,
+ * varies based on partname
+ */
#define AE_CORES_PER_CLUSTER 20
#define SE_CORES_PER_CLUSTER 16
+#define AE_MAX_CORES (AE_CORES_PER_CLUSTER * NR_CLUSTERS)
+#define SE_MAX_CORES (SE_CORES_PER_CLUSTER * NR_CLUSTERS)
+#define ZIP_MAX_CORES 5
+
/* BIST registers */
#define EMU_BIST_STATUSX(_i) (0x1402700 + ((_i) * 0x40000))
#define UCD_BIST_STATUS 0x12C0070
@@ -111,6 +118,9 @@
#define LBC_ELM_VF65_128_INT 0x120C000
#define LBC_ELM_VF65_128_INT_ENA_W1S 0x120F000
+#define RST_BOOT 0x10C1600
+#define FUS_DAT1 0x10C1408
+
/* PEM registers */
#define PEM0_INT 0x1080428
@@ -1082,4 +1092,105 @@ union lbc_inval_status {
} s;
};
+/**
+ * struct rst_boot: RST Boot Register
+ * @jtcsrdis: when set, internal CSR access via JTAG TAP controller
+ * is disabled
+ * @jt_tst_mode: JTAG test mode
+ * @io_supply: I/O power supply setting based on IO_VDD_SELECT pin:
+ * 0x1 = 1.8V
+ * 0x2 = 2.5V
+ * 0x4 = 3.3V
+ * All other values are reserved
+ * @pnr_mul: clock multiplier
+ * @lboot: last boot cause mask, resets only with PLL_DC_OK
+ * @rboot: determines whether core 0 remains in reset after
+ * chip cold or warm or soft reset
+ * @rboot_pin: read only access to REMOTE_BOOT pin
+ */
+union rst_boot {
+ u64 value;
+ struct {
+#if (defined(__BIG_ENDIAN_BITFIELD))
+ u64 raz_63 : 1;
+ u64 jtcsrdis : 1;
+ u64 raz_59_61 : 3;
+ u64 jt_tst_mode : 1;
+ u64 raz_40_57 : 18;
+ u64 io_supply : 3;
+ u64 raz_30_36 : 7;
+ u64 pnr_mul : 6;
+ u64 raz_12_23 : 12;
+ u64 lboot : 10;
+ u64 rboot : 1;
+ u64 rboot_pin : 1;
+#else
+ u64 rboot_pin : 1;
+ u64 rboot : 1;
+ u64 lboot : 10;
+ u64 raz_12_23 : 12;
+ u64 pnr_mul : 6;
+ u64 raz_30_36 : 7;
+ u64 io_supply : 3;
+ u64 raz_40_57 : 18;
+ u64 jt_tst_mode : 1;
+ u64 raz_59_61 : 3;
+ u64 jtcsrdis : 1;
+ u64 raz_63 : 1;
+#endif
+ };
+};
+
+/**
+ * struct fus_dat1: Fuse Data 1 Register
+ * @pll_mul: main clock PLL multiplier hardware limit
+ * @pll_half_dis: main clock PLL control
+ * @efus_lck: efuse lockdown
+ * @zip_info: ZIP information
+ * @bar2_sz_conf: when zero, BAR2 size conforms to
+ * PCIe specification
+ * @efus_ign: efuse ignore
+ * @nozip: ZIP disable
+ * @pll_alt_matrix: select alternate PLL matrix
+ * @pll_bwadj_denom: select CLKF denominator for
+ * BWADJ value
+ * @chip_id: chip ID
+ */
+union fus_dat1 {
+ u64 value;
+ struct {
+#if (defined(__BIG_ENDIAN_BITFIELD))
+ u64 raz_57_63 : 7;
+ u64 pll_mul : 3;
+ u64 pll_half_dis : 1;
+ u64 raz_43_52 : 10;
+ u64 efus_lck : 3;
+ u64 raz_26_39 : 14;
+ u64 zip_info : 5;
+ u64 bar2_sz_conf : 1;
+ u64 efus_ign : 1;
+ u64 nozip : 1;
+ u64 raz_11_17 : 7;
+ u64 pll_alt_matrix : 1;
+ u64 pll_bwadj_denom : 2;
+ u64 chip_id : 8;
+#else
+ u64 chip_id : 8;
+ u64 pll_bwadj_denom : 2;
+ u64 pll_alt_matrix : 1;
+ u64 raz_11_17 : 7;
+ u64 nozip : 1;
+ u64 efus_ign : 1;
+ u64 bar2_sz_conf : 1;
+ u64 zip_info : 5;
+ u64 raz_26_39 : 14;
+ u64 efus_lck : 3;
+ u64 raz_43_52 : 10;
+ u64 pll_half_dis : 1;
+ u64 pll_mul : 3;
+ u64 raz_57_63 : 7;
+#endif
+ };
+};
+
#endif /* __NITROX_CSR_H */
diff --git a/drivers/crypto/cavium/nitrox/nitrox_debugfs.c b/drivers/crypto/cavium/nitrox/nitrox_debugfs.c
new file mode 100644
index 000000000000..5f3cd5fafe04
--- /dev/null
+++ b/drivers/crypto/cavium/nitrox/nitrox_debugfs.c
@@ -0,0 +1,115 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+
+#include "nitrox_csr.h"
+#include "nitrox_dev.h"
+
+static int firmware_show(struct seq_file *s, void *v)
+{
+ struct nitrox_device *ndev = s->private;
+
+ seq_printf(s, "Version: %s\n", ndev->hw.fw_name);
+ return 0;
+}
+
+static int firmware_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, firmware_show, inode->i_private);
+}
+
+static const struct file_operations firmware_fops = {
+ .owner = THIS_MODULE,
+ .open = firmware_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int device_show(struct seq_file *s, void *v)
+{
+ struct nitrox_device *ndev = s->private;
+
+ seq_printf(s, "NITROX [%d]\n", ndev->idx);
+ seq_printf(s, " Part Name: %s\n", ndev->hw.partname);
+ seq_printf(s, " Frequency: %d MHz\n", ndev->hw.freq);
+ seq_printf(s, " Device ID: 0x%0x\n", ndev->hw.device_id);
+ seq_printf(s, " Revision ID: 0x%0x\n", ndev->hw.revision_id);
+ seq_printf(s, " Cores: [AE=%u SE=%u ZIP=%u]\n",
+ ndev->hw.ae_cores, ndev->hw.se_cores, ndev->hw.zip_cores);
+
+ return 0;
+}
+
+static int nitrox_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, device_show, inode->i_private);
+}
+
+static const struct file_operations nitrox_fops = {
+ .owner = THIS_MODULE,
+ .open = nitrox_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int stats_show(struct seq_file *s, void *v)
+{
+ struct nitrox_device *ndev = s->private;
+
+ seq_printf(s, "NITROX [%d] Request Statistics\n", ndev->idx);
+ seq_printf(s, " Posted: %llu\n",
+ (u64)atomic64_read(&ndev->stats.posted));
+ seq_printf(s, " Completed: %llu\n",
+ (u64)atomic64_read(&ndev->stats.completed));
+ seq_printf(s, " Dropped: %llu\n",
+ (u64)atomic64_read(&ndev->stats.dropped));
+
+ return 0;
+}
+
+static int nitrox_stats_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, stats_show, inode->i_private);
+}
+
+static const struct file_operations nitrox_stats_fops = {
+ .owner = THIS_MODULE,
+ .open = nitrox_stats_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+void nitrox_debugfs_exit(struct nitrox_device *ndev)
+{
+ debugfs_remove_recursive(ndev->debugfs_dir);
+ ndev->debugfs_dir = NULL;
+}
+
+int nitrox_debugfs_init(struct nitrox_device *ndev)
+{
+ struct dentry *dir, *f;
+
+ dir = debugfs_create_dir(KBUILD_MODNAME, NULL);
+ if (!dir)
+ return -ENOMEM;
+
+ ndev->debugfs_dir = dir;
+ f = debugfs_create_file("firmware", 0400, dir, ndev, &firmware_fops);
+ if (!f)
+ goto err;
+ f = debugfs_create_file("device", 0400, dir, ndev, &nitrox_fops);
+ if (!f)
+ goto err;
+ f = debugfs_create_file("stats", 0400, dir, ndev, &nitrox_stats_fops);
+ if (!f)
+ goto err;
+
+ return 0;
+
+err:
+ nitrox_debugfs_exit(ndev);
+ return -ENODEV;
+}
diff --git a/drivers/crypto/cavium/nitrox/nitrox_dev.h b/drivers/crypto/cavium/nitrox/nitrox_dev.h
index af596455b420..283e252385fb 100644
--- a/drivers/crypto/cavium/nitrox/nitrox_dev.h
+++ b/drivers/crypto/cavium/nitrox/nitrox_dev.h
@@ -5,92 +5,123 @@
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
+#include <linux/if.h>
#define VERSION_LEN 32
+/**
+ * struct nitrox_cmdq - NITROX command queue
+ * @cmd_qlock: command queue lock
+ * @resp_qlock: response queue lock
+ * @backlog_qlock: backlog queue lock
+ * @ndev: NITROX device
+ * @response_head: submitted request list
+ * @backlog_head: backlog queue
+ * @dbell_csr_addr: doorbell register address for this queue
+ * @compl_cnt_csr_addr: completion count register address of the slc port
+ * @base: command queue base address
+ * @dma: dma address of the base
+ * @pending_count: request pending at device
+ * @backlog_count: backlog request count
+ * @write_idx: next write index for the command
+ * @instr_size: command size
+ * @qno: command queue number
+ * @qsize: command queue size
+ * @unalign_base: unaligned base address
+ * @unalign_dma: unaligned dma address
+ */
struct nitrox_cmdq {
- /* command queue lock */
- spinlock_t cmdq_lock;
- /* response list lock */
- spinlock_t response_lock;
- /* backlog list lock */
- spinlock_t backlog_lock;
-
- /* request submitted to chip, in progress */
+ spinlock_t cmd_qlock;
+ spinlock_t resp_qlock;
+ spinlock_t backlog_qlock;
+
+ struct nitrox_device *ndev;
struct list_head response_head;
- /* hw queue full, hold in backlog list */
struct list_head backlog_head;
- /* doorbell address */
u8 __iomem *dbell_csr_addr;
- /* base address of the queue */
- u8 *head;
+ u8 __iomem *compl_cnt_csr_addr;
+ u8 *base;
+ dma_addr_t dma;
- struct nitrox_device *ndev;
- /* flush pending backlog commands */
struct work_struct backlog_qflush;
- /* requests posted waiting for completion */
atomic_t pending_count;
- /* requests in backlog queues */
atomic_t backlog_count;
int write_idx;
- /* command size 32B/64B */
u8 instr_size;
u8 qno;
u32 qsize;
- /* unaligned addresses */
- u8 *head_unaligned;
- dma_addr_t dma_unaligned;
- /* dma address of the base */
- dma_addr_t dma;
+ u8 *unalign_base;
+ dma_addr_t unalign_dma;
};
+/**
+ * struct nitrox_hw - NITROX hardware information
+ * @partname: partname ex: CNN55xxx-xxx
+ * @fw_name: firmware version
+ * @freq: NITROX frequency
+ * @vendor_id: vendor ID
+ * @device_id: device ID
+ * @revision_id: revision ID
+ * @se_cores: number of symmetric cores
+ * @ae_cores: number of asymmetric cores
+ * @zip_cores: number of zip cores
+ */
struct nitrox_hw {
- /* firmware version */
+ char partname[IFNAMSIZ * 2];
char fw_name[VERSION_LEN];
+ int freq;
u16 vendor_id;
u16 device_id;
u8 revision_id;
- /* CNN55XX cores */
u8 se_cores;
u8 ae_cores;
u8 zip_cores;
};
-#define MAX_MSIX_VECTOR_NAME 20
-/**
- * vectors for queues (64 AE, 64 SE and 64 ZIP) and
- * error condition/mailbox.
- */
-#define MAX_MSIX_VECTORS 192
-
-struct nitrox_msix {
- struct msix_entry *entries;
- char **names;
- DECLARE_BITMAP(irqs, MAX_MSIX_VECTORS);
- u32 nr_entries;
+struct nitrox_stats {
+ atomic64_t posted;
+ atomic64_t completed;
+ atomic64_t dropped;
};
-struct bh_data {
- /* slc port completion count address */
- u8 __iomem *completion_cnt_csr_addr;
+#define IRQ_NAMESZ 32
+
+struct nitrox_q_vector {
+ char name[IRQ_NAMESZ];
+ bool valid;
+ int ring;
+ struct tasklet_struct resp_tasklet;
+ union {
+ struct nitrox_cmdq *cmdq;
+ struct nitrox_device *ndev;
+ };
+};
- struct nitrox_cmdq *cmdq;
- struct tasklet_struct resp_handler;
+/*
+ * NITROX Device states
+ */
+enum ndev_state {
+ __NDEV_NOT_READY,
+ __NDEV_READY,
+ __NDEV_IN_RESET,
};
-struct nitrox_bh {
- struct bh_data *slc;
+/* NITROX support modes for VF(s) */
+enum vf_mode {
+ __NDEV_MODE_PF,
+ __NDEV_MODE_VF16,
+ __NDEV_MODE_VF32,
+ __NDEV_MODE_VF64,
+ __NDEV_MODE_VF128,
};
-/* NITROX-V driver state */
-#define NITROX_UCODE_LOADED 0
-#define NITROX_READY 1
+#define __NDEV_SRIOV_BIT 0
/* command queue size */
#define DEFAULT_CMD_QLEN 2048
@@ -98,7 +129,6 @@ struct nitrox_bh {
#define CMD_TIMEOUT 2000
#define DEV(ndev) ((struct device *)(&(ndev)->pdev->dev))
-#define PF_MODE 0
#define NITROX_CSR_ADDR(ndev, offset) \
((ndev)->bar_addr + (offset))
@@ -108,17 +138,18 @@ struct nitrox_bh {
* @list: pointer to linked list of devices
* @bar_addr: iomap address
* @pdev: PCI device information
- * @status: NITROX status
+ * @state: NITROX device state
+ * @flags: flags to indicate device the features
* @timeout: Request timeout in jiffies
* @refcnt: Device usage count
* @idx: device index (0..N)
* @node: NUMA node id attached
* @qlen: Command queue length
* @nr_queues: Number of command queues
+ * @mode: Device mode PF/VF
* @ctx_pool: DMA pool for crypto context
- * @pkt_cmdqs: SE Command queues
- * @msix: MSI-X information
- * @bh: post processing work
+ * @pkt_inq: Packet input rings
+ * @qvec: MSI-X queue vectors information
* @hw: hardware information
* @debugfs_dir: debugfs directory
*/
@@ -128,7 +159,8 @@ struct nitrox_device {
u8 __iomem *bar_addr;
struct pci_dev *pdev;
- unsigned long status;
+ atomic_t state;
+ unsigned long flags;
unsigned long timeout;
refcount_t refcnt;
@@ -136,13 +168,16 @@ struct nitrox_device {
int node;
u16 qlen;
u16 nr_queues;
+ int num_vfs;
+ enum vf_mode mode;
struct dma_pool *ctx_pool;
- struct nitrox_cmdq *pkt_cmdqs;
+ struct nitrox_cmdq *pkt_inq;
- struct nitrox_msix msix;
- struct nitrox_bh bh;
+ struct nitrox_q_vector *qvec;
+ int num_vecs;
+ struct nitrox_stats stats;
struct nitrox_hw hw;
#if IS_ENABLED(CONFIG_DEBUG_FS)
struct dentry *debugfs_dir;
@@ -173,9 +208,22 @@ static inline void nitrox_write_csr(struct nitrox_device *ndev, u64 offset,
writeq(value, (ndev->bar_addr + offset));
}
-static inline int nitrox_ready(struct nitrox_device *ndev)
+static inline bool nitrox_ready(struct nitrox_device *ndev)
{
- return test_bit(NITROX_READY, &ndev->status);
+ return atomic_read(&ndev->state) == __NDEV_READY;
}
+#ifdef CONFIG_DEBUG_FS
+int nitrox_debugfs_init(struct nitrox_device *ndev);
+void nitrox_debugfs_exit(struct nitrox_device *ndev);
+#else
+static inline int nitrox_debugfs_init(struct nitrox_device *ndev)
+{
+ return 0;
+}
+
+static inline void nitrox_debugfs_exit(struct nitrox_device *ndev)
+{ }
+#endif
+
#endif /* __NITROX_DEV_H */
diff --git a/drivers/crypto/cavium/nitrox/nitrox_hal.c b/drivers/crypto/cavium/nitrox/nitrox_hal.c
index ab4ccf2f9e77..a9b82387cf53 100644
--- a/drivers/crypto/cavium/nitrox/nitrox_hal.c
+++ b/drivers/crypto/cavium/nitrox/nitrox_hal.c
@@ -4,6 +4,8 @@
#include "nitrox_dev.h"
#include "nitrox_csr.h"
+#define PLL_REF_CLK 50
+
/**
* emu_enable_cores - Enable EMU cluster cores.
* @ndev: N5 device
@@ -117,7 +119,7 @@ void nitrox_config_pkt_input_rings(struct nitrox_device *ndev)
int i;
for (i = 0; i < ndev->nr_queues; i++) {
- struct nitrox_cmdq *cmdq = &ndev->pkt_cmdqs[i];
+ struct nitrox_cmdq *cmdq = &ndev->pkt_inq[i];
union nps_pkt_in_instr_rsize pkt_in_rsize;
u64 offset;
@@ -256,7 +258,7 @@ void nitrox_config_nps_unit(struct nitrox_device *ndev)
/* disable ILK interface */
core_gbl_vfcfg.value = 0;
core_gbl_vfcfg.s.ilk_disable = 1;
- core_gbl_vfcfg.s.cfg = PF_MODE;
+ core_gbl_vfcfg.s.cfg = __NDEV_MODE_PF;
nitrox_write_csr(ndev, NPS_CORE_GBL_VFCFG, core_gbl_vfcfg.value);
/* config input and solicit ports */
nitrox_config_pkt_input_rings(ndev);
@@ -400,3 +402,68 @@ void nitrox_config_lbc_unit(struct nitrox_device *ndev)
offset = LBC_ELM_VF65_128_INT_ENA_W1S;
nitrox_write_csr(ndev, offset, (~0ULL));
}
+
+void config_nps_core_vfcfg_mode(struct nitrox_device *ndev, enum vf_mode mode)
+{
+ union nps_core_gbl_vfcfg vfcfg;
+
+ vfcfg.value = nitrox_read_csr(ndev, NPS_CORE_GBL_VFCFG);
+ vfcfg.s.cfg = mode & 0x7;
+
+ nitrox_write_csr(ndev, NPS_CORE_GBL_VFCFG, vfcfg.value);
+}
+
+void nitrox_get_hwinfo(struct nitrox_device *ndev)
+{
+ union emu_fuse_map emu_fuse;
+ union rst_boot rst_boot;
+ union fus_dat1 fus_dat1;
+ unsigned char name[IFNAMSIZ * 2] = {};
+ int i, dead_cores;
+ u64 offset;
+
+ /* get core frequency */
+ offset = RST_BOOT;
+ rst_boot.value = nitrox_read_csr(ndev, offset);
+ ndev->hw.freq = (rst_boot.pnr_mul + 3) * PLL_REF_CLK;
+
+ for (i = 0; i < NR_CLUSTERS; i++) {
+ offset = EMU_FUSE_MAPX(i);
+ emu_fuse.value = nitrox_read_csr(ndev, offset);
+ if (emu_fuse.s.valid) {
+ dead_cores = hweight32(emu_fuse.s.ae_fuse);
+ ndev->hw.ae_cores += AE_CORES_PER_CLUSTER - dead_cores;
+ dead_cores = hweight16(emu_fuse.s.se_fuse);
+ ndev->hw.se_cores += SE_CORES_PER_CLUSTER - dead_cores;
+ }
+ }
+ /* find zip hardware availability */
+ offset = FUS_DAT1;
+ fus_dat1.value = nitrox_read_csr(ndev, offset);
+ if (!fus_dat1.nozip) {
+ dead_cores = hweight8(fus_dat1.zip_info);
+ ndev->hw.zip_cores = ZIP_MAX_CORES - dead_cores;
+ }
+
+ /* determine the partname CNN55<cores>-<freq><pincount>-<rev>*/
+ if (ndev->hw.ae_cores == AE_MAX_CORES) {
+ switch (ndev->hw.se_cores) {
+ case SE_MAX_CORES:
+ i = snprintf(name, sizeof(name), "CNN5560");
+ break;
+ case 40:
+ i = snprintf(name, sizeof(name), "CNN5560s");
+ break;
+ }
+ } else if (ndev->hw.ae_cores == (AE_MAX_CORES / 2)) {
+ i = snprintf(name, sizeof(name), "CNN5530");
+ } else {
+ i = snprintf(name, sizeof(name), "CNN5560i");
+ }
+
+ snprintf(name + i, sizeof(name) - i, "-%3dBG676-1.%u",
+ ndev->hw.freq, ndev->hw.revision_id);
+
+ /* copy partname */
+ strncpy(ndev->hw.partname, name, sizeof(ndev->hw.partname));
+}
diff --git a/drivers/crypto/cavium/nitrox/nitrox_hal.h b/drivers/crypto/cavium/nitrox/nitrox_hal.h
new file mode 100644
index 000000000000..489ee64c119e
--- /dev/null
+++ b/drivers/crypto/cavium/nitrox/nitrox_hal.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __NITROX_HAL_H
+#define __NITROX_HAL_H
+
+#include "nitrox_dev.h"
+
+void nitrox_config_emu_unit(struct nitrox_device *ndev);
+void nitrox_config_pkt_input_rings(struct nitrox_device *ndev);
+void nitrox_config_pkt_solicit_ports(struct nitrox_device *ndev);
+void nitrox_config_nps_unit(struct nitrox_device *ndev);
+void nitrox_config_pom_unit(struct nitrox_device *ndev);
+void nitrox_config_rand_unit(struct nitrox_device *ndev);
+void nitrox_config_efl_unit(struct nitrox_device *ndev);
+void nitrox_config_bmi_unit(struct nitrox_device *ndev);
+void nitrox_config_bmo_unit(struct nitrox_device *ndev);
+void nitrox_config_lbc_unit(struct nitrox_device *ndev);
+void invalidate_lbc(struct nitrox_device *ndev);
+void enable_pkt_input_ring(struct nitrox_device *ndev, int ring);
+void enable_pkt_solicit_port(struct nitrox_device *ndev, int port);
+void config_nps_core_vfcfg_mode(struct nitrox_device *ndev, enum vf_mode mode);
+void nitrox_get_hwinfo(struct nitrox_device *ndev);
+
+#endif /* __NITROX_HAL_H */
diff --git a/drivers/crypto/cavium/nitrox/nitrox_isr.c b/drivers/crypto/cavium/nitrox/nitrox_isr.c
index ee0d70ba25d5..88a77b8fb3fb 100644
--- a/drivers/crypto/cavium/nitrox/nitrox_isr.c
+++ b/drivers/crypto/cavium/nitrox/nitrox_isr.c
@@ -6,9 +6,16 @@
#include "nitrox_dev.h"
#include "nitrox_csr.h"
#include "nitrox_common.h"
+#include "nitrox_hal.h"
+/**
+ * One vector for each type of ring
+ * - NPS packet ring, AQMQ ring and ZQMQ ring
+ */
#define NR_RING_VECTORS 3
-#define NPS_CORE_INT_ACTIVE_ENTRY 192
+/* base entry for packet ring/port */
+#define PKT_RING_MSIX_BASE 0
+#define NON_RING_MSIX_BASE 192
/**
* nps_pkt_slc_isr - IRQ handler for NPS solicit port
@@ -17,13 +24,14 @@
*/
static irqreturn_t nps_pkt_slc_isr(int irq, void *data)
{
- struct bh_data *slc = data;
- union nps_pkt_slc_cnts pkt_slc_cnts;
+ struct nitrox_q_vector *qvec = data;
+ union nps_pkt_slc_cnts slc_cnts;
+ struct nitrox_cmdq *cmdq = qvec->cmdq;
- pkt_slc_cnts.value = readq(slc->completion_cnt_csr_addr);
+ slc_cnts.value = readq(cmdq->compl_cnt_csr_addr);
/* New packet on SLC output port */
- if (pkt_slc_cnts.s.slc_int)
- tasklet_hi_schedule(&slc->resp_handler);
+ if (slc_cnts.s.slc_int)
+ tasklet_hi_schedule(&qvec->resp_tasklet);
return IRQ_HANDLED;
}
@@ -190,165 +198,92 @@ static void clear_bmi_err_intr(struct nitrox_device *ndev)
dev_err_ratelimited(DEV(ndev), "BMI_INT 0x%016llx\n", value);
}
+static void nps_core_int_tasklet(unsigned long data)
+{
+ struct nitrox_q_vector *qvec = (void *)(uintptr_t)(data);
+ struct nitrox_device *ndev = qvec->ndev;
+
+ /* if pf mode do queue recovery */
+ if (ndev->mode == __NDEV_MODE_PF) {
+ } else {
+ /**
+ * if VF(s) enabled communicate the error information
+ * to VF(s)
+ */
+ }
+}
+
/**
- * clear_nps_core_int_active - clear NPS_CORE_INT_ACTIVE interrupts
- * @ndev: NITROX device
+ * nps_core_int_isr - interrupt handler for NITROX errors and
+ * mailbox communication
*/
-static void clear_nps_core_int_active(struct nitrox_device *ndev)
+static irqreturn_t nps_core_int_isr(int irq, void *data)
{
- union nps_core_int_active core_int_active;
+ struct nitrox_device *ndev = data;
+ union nps_core_int_active core_int;
- core_int_active.value = nitrox_read_csr(ndev, NPS_CORE_INT_ACTIVE);
+ core_int.value = nitrox_read_csr(ndev, NPS_CORE_INT_ACTIVE);
- if (core_int_active.s.nps_core)
+ if (core_int.s.nps_core)
clear_nps_core_err_intr(ndev);
- if (core_int_active.s.nps_pkt)
+ if (core_int.s.nps_pkt)
clear_nps_pkt_err_intr(ndev);
- if (core_int_active.s.pom)
+ if (core_int.s.pom)
clear_pom_err_intr(ndev);
- if (core_int_active.s.pem)
+ if (core_int.s.pem)
clear_pem_err_intr(ndev);
- if (core_int_active.s.lbc)
+ if (core_int.s.lbc)
clear_lbc_err_intr(ndev);
- if (core_int_active.s.efl)
+ if (core_int.s.efl)
clear_efl_err_intr(ndev);
- if (core_int_active.s.bmi)
+ if (core_int.s.bmi)
clear_bmi_err_intr(ndev);
/* If more work callback the ISR, set resend */
- core_int_active.s.resend = 1;
- nitrox_write_csr(ndev, NPS_CORE_INT_ACTIVE, core_int_active.value);
-}
-
-static irqreturn_t nps_core_int_isr(int irq, void *data)
-{
- struct nitrox_device *ndev = data;
-
- clear_nps_core_int_active(ndev);
+ core_int.s.resend = 1;
+ nitrox_write_csr(ndev, NPS_CORE_INT_ACTIVE, core_int.value);
return IRQ_HANDLED;
}
-static int nitrox_enable_msix(struct nitrox_device *ndev)
+void nitrox_unregister_interrupts(struct nitrox_device *ndev)
{
- struct msix_entry *entries;
- char **names;
- int i, nr_entries, ret;
-
- /*
- * PF MSI-X vectors
- *
- * Entry 0: NPS PKT ring 0
- * Entry 1: AQMQ ring 0
- * Entry 2: ZQM ring 0
- * Entry 3: NPS PKT ring 1
- * Entry 4: AQMQ ring 1
- * Entry 5: ZQM ring 1
- * ....
- * Entry 192: NPS_CORE_INT_ACTIVE
- */
- nr_entries = (ndev->nr_queues * NR_RING_VECTORS) + 1;
- entries = kcalloc_node(nr_entries, sizeof(struct msix_entry),
- GFP_KERNEL, ndev->node);
- if (!entries)
- return -ENOMEM;
-
- names = kcalloc(nr_entries, sizeof(char *), GFP_KERNEL);
- if (!names) {
- kfree(entries);
- return -ENOMEM;
- }
-
- /* fill entires */
- for (i = 0; i < (nr_entries - 1); i++)
- entries[i].entry = i;
-
- entries[i].entry = NPS_CORE_INT_ACTIVE_ENTRY;
-
- for (i = 0; i < nr_entries; i++) {
- *(names + i) = kzalloc(MAX_MSIX_VECTOR_NAME, GFP_KERNEL);
- if (!(*(names + i))) {
- ret = -ENOMEM;
- goto msix_fail;
- }
- }
- ndev->msix.entries = entries;
- ndev->msix.names = names;
- ndev->msix.nr_entries = nr_entries;
-
- ret = pci_enable_msix_exact(ndev->pdev, ndev->msix.entries,
- ndev->msix.nr_entries);
- if (ret) {
- dev_err(&ndev->pdev->dev, "Failed to enable MSI-X IRQ(s) %d\n",
- ret);
- goto msix_fail;
- }
- return 0;
-
-msix_fail:
- for (i = 0; i < nr_entries; i++)
- kfree(*(names + i));
-
- kfree(entries);
- kfree(names);
- return ret;
-}
-
-static void nitrox_cleanup_pkt_slc_bh(struct nitrox_device *ndev)
-{
- int i;
-
- if (!ndev->bh.slc)
- return;
-
- for (i = 0; i < ndev->nr_queues; i++) {
- struct bh_data *bh = &ndev->bh.slc[i];
-
- tasklet_disable(&bh->resp_handler);
- tasklet_kill(&bh->resp_handler);
- }
- kfree(ndev->bh.slc);
- ndev->bh.slc = NULL;
-}
-
-static int nitrox_setup_pkt_slc_bh(struct nitrox_device *ndev)
-{
- u32 size;
+ struct pci_dev *pdev = ndev->pdev;
int i;
- size = ndev->nr_queues * sizeof(struct bh_data);
- ndev->bh.slc = kzalloc(size, GFP_KERNEL);
- if (!ndev->bh.slc)
- return -ENOMEM;
+ for (i = 0; i < ndev->num_vecs; i++) {
+ struct nitrox_q_vector *qvec;
+ int vec;
- for (i = 0; i < ndev->nr_queues; i++) {
- struct bh_data *bh = &ndev->bh.slc[i];
- u64 offset;
+ qvec = ndev->qvec + i;
+ if (!qvec->valid)
+ continue;
- offset = NPS_PKT_SLC_CNTSX(i);
- /* pre calculate completion count address */
- bh->completion_cnt_csr_addr = NITROX_CSR_ADDR(ndev, offset);
- bh->cmdq = &ndev->pkt_cmdqs[i];
+ /* get the vector number */
+ vec = pci_irq_vector(pdev, i);
+ irq_set_affinity_hint(vec, NULL);
+ free_irq(vec, qvec);
- tasklet_init(&bh->resp_handler, pkt_slc_resp_handler,
- (unsigned long)bh);
+ tasklet_disable(&qvec->resp_tasklet);
+ tasklet_kill(&qvec->resp_tasklet);
+ qvec->valid = false;
}
-
- return 0;
+ kfree(ndev->qvec);
+ pci_free_irq_vectors(pdev);
}
-static int nitrox_request_irqs(struct nitrox_device *ndev)
+int nitrox_register_interrupts(struct nitrox_device *ndev)
{
struct pci_dev *pdev = ndev->pdev;
- struct msix_entry *msix_ent = ndev->msix.entries;
- int nr_ring_vectors, i = 0, ring, cpu, ret;
- char *name;
+ struct nitrox_q_vector *qvec;
+ int nr_vecs, vec, cpu;
+ int ret, i;
/*
* PF MSI-X vectors
@@ -357,112 +292,76 @@ static int nitrox_request_irqs(struct nitrox_device *ndev)
* Entry 1: AQMQ ring 0
* Entry 2: ZQM ring 0
* Entry 3: NPS PKT ring 1
+ * Entry 4: AQMQ ring 1
+ * Entry 5: ZQM ring 1
* ....
* Entry 192: NPS_CORE_INT_ACTIVE
*/
- nr_ring_vectors = ndev->nr_queues * NR_RING_VECTORS;
-
- /* request irq for pkt ring/ports only */
- while (i < nr_ring_vectors) {
- name = *(ndev->msix.names + i);
- ring = (i / NR_RING_VECTORS);
- snprintf(name, MAX_MSIX_VECTOR_NAME, "n5(%d)-slc-ring%d",
- ndev->idx, ring);
+ nr_vecs = pci_msix_vec_count(pdev);
- ret = request_irq(msix_ent[i].vector, nps_pkt_slc_isr, 0,
- name, &ndev->bh.slc[ring]);
- if (ret) {
- dev_err(&pdev->dev, "failed to get irq %d for %s\n",
- msix_ent[i].vector, name);
- return ret;
- }
- cpu = ring % num_online_cpus();
- irq_set_affinity_hint(msix_ent[i].vector, get_cpu_mask(cpu));
-
- set_bit(i, ndev->msix.irqs);
- i += NR_RING_VECTORS;
- }
-
- /* Request IRQ for NPS_CORE_INT_ACTIVE */
- name = *(ndev->msix.names + i);
- snprintf(name, MAX_MSIX_VECTOR_NAME, "n5(%d)-nps-core-int", ndev->idx);
- ret = request_irq(msix_ent[i].vector, nps_core_int_isr, 0, name, ndev);
- if (ret) {
- dev_err(&pdev->dev, "failed to get irq %d for %s\n",
- msix_ent[i].vector, name);
+ /* Enable MSI-X */
+ ret = pci_alloc_irq_vectors(pdev, nr_vecs, nr_vecs, PCI_IRQ_MSIX);
+ if (ret < 0) {
+ dev_err(DEV(ndev), "msix vectors %d alloc failed\n", nr_vecs);
return ret;
}
- set_bit(i, ndev->msix.irqs);
+ ndev->num_vecs = nr_vecs;
- return 0;
-}
-
-static void nitrox_disable_msix(struct nitrox_device *ndev)
-{
- struct msix_entry *msix_ent = ndev->msix.entries;
- char **names = ndev->msix.names;
- int i = 0, ring, nr_ring_vectors;
-
- nr_ring_vectors = ndev->msix.nr_entries - 1;
-
- /* clear pkt ring irqs */
- while (i < nr_ring_vectors) {
- if (test_and_clear_bit(i, ndev->msix.irqs)) {
- ring = (i / NR_RING_VECTORS);
- irq_set_affinity_hint(msix_ent[i].vector, NULL);
- free_irq(msix_ent[i].vector, &ndev->bh.slc[ring]);
- }
- i += NR_RING_VECTORS;
+ ndev->qvec = kcalloc(nr_vecs, sizeof(*qvec), GFP_KERNEL);
+ if (!ndev->qvec) {
+ pci_free_irq_vectors(pdev);
+ return -ENOMEM;
}
- irq_set_affinity_hint(msix_ent[i].vector, NULL);
- free_irq(msix_ent[i].vector, ndev);
- clear_bit(i, ndev->msix.irqs);
- kfree(ndev->msix.entries);
- for (i = 0; i < ndev->msix.nr_entries; i++)
- kfree(*(names + i));
+ /* request irqs for packet rings/ports */
+ for (i = PKT_RING_MSIX_BASE; i < (nr_vecs - 1); i += NR_RING_VECTORS) {
+ qvec = &ndev->qvec[i];
- kfree(names);
- pci_disable_msix(ndev->pdev);
-}
-
-/**
- * nitrox_pf_cleanup_isr: Cleanup PF MSI-X and IRQ
- * @ndev: NITROX device
- */
-void nitrox_pf_cleanup_isr(struct nitrox_device *ndev)
-{
- nitrox_disable_msix(ndev);
- nitrox_cleanup_pkt_slc_bh(ndev);
-}
+ qvec->ring = i / NR_RING_VECTORS;
+ if (qvec->ring >= ndev->nr_queues)
+ break;
-/**
- * nitrox_init_isr - Initialize PF MSI-X vectors and IRQ
- * @ndev: NITROX device
- *
- * Return: 0 on success, a negative value on failure.
- */
-int nitrox_pf_init_isr(struct nitrox_device *ndev)
-{
- int err;
+ snprintf(qvec->name, IRQ_NAMESZ, "nitrox-pkt%d", qvec->ring);
+ /* get the vector number */
+ vec = pci_irq_vector(pdev, i);
+ ret = request_irq(vec, nps_pkt_slc_isr, 0, qvec->name, qvec);
+ if (ret) {
+ dev_err(DEV(ndev), "irq failed for pkt ring/port%d\n",
+ qvec->ring);
+ goto irq_fail;
+ }
+ cpu = qvec->ring % num_online_cpus();
+ irq_set_affinity_hint(vec, get_cpu_mask(cpu));
- err = nitrox_setup_pkt_slc_bh(ndev);
- if (err)
- return err;
+ tasklet_init(&qvec->resp_tasklet, pkt_slc_resp_tasklet,
+ (unsigned long)qvec);
+ qvec->cmdq = &ndev->pkt_inq[qvec->ring];
+ qvec->valid = true;
+ }
- err = nitrox_enable_msix(ndev);
- if (err)
- goto msix_fail;
+ /* request irqs for non ring vectors */
+ i = NON_RING_MSIX_BASE;
+ qvec = &ndev->qvec[i];
- err = nitrox_request_irqs(ndev);
- if (err)
+ snprintf(qvec->name, IRQ_NAMESZ, "nitrox-core-int%d", i);
+ /* get the vector number */
+ vec = pci_irq_vector(pdev, i);
+ ret = request_irq(vec, nps_core_int_isr, 0, qvec->name, qvec);
+ if (ret) {
+ dev_err(DEV(ndev), "irq failed for nitrox-core-int%d\n", i);
goto irq_fail;
+ }
+ cpu = num_online_cpus();
+ irq_set_affinity_hint(vec, get_cpu_mask(cpu));
+
+ tasklet_init(&qvec->resp_tasklet, nps_core_int_tasklet,
+ (unsigned long)qvec);
+ qvec->ndev = ndev;
+ qvec->valid = true;
return 0;
irq_fail:
- nitrox_disable_msix(ndev);
-msix_fail:
- nitrox_cleanup_pkt_slc_bh(ndev);
- return err;
+ nitrox_unregister_interrupts(ndev);
+ return ret;
}
diff --git a/drivers/crypto/cavium/nitrox/nitrox_isr.h b/drivers/crypto/cavium/nitrox/nitrox_isr.h
new file mode 100644
index 000000000000..63418a6cc52c
--- /dev/null
+++ b/drivers/crypto/cavium/nitrox/nitrox_isr.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __NITROX_ISR_H
+#define __NITROX_ISR_H
+
+#include "nitrox_dev.h"
+
+int nitrox_register_interrupts(struct nitrox_device *ndev);
+void nitrox_unregister_interrupts(struct nitrox_device *ndev);
+
+#endif /* __NITROX_ISR_H */
diff --git a/drivers/crypto/cavium/nitrox/nitrox_lib.c b/drivers/crypto/cavium/nitrox/nitrox_lib.c
index 4d31df07777f..2260efa42308 100644
--- a/drivers/crypto/cavium/nitrox/nitrox_lib.c
+++ b/drivers/crypto/cavium/nitrox/nitrox_lib.c
@@ -17,30 +17,27 @@
#define CRYPTO_CTX_SIZE 256
-/* command queue alignments */
-#define PKT_IN_ALIGN 16
+/* packet inuput ring alignments */
+#define PKTIN_Q_ALIGN_BYTES 16
-static int cmdq_common_init(struct nitrox_cmdq *cmdq)
+static int nitrox_cmdq_init(struct nitrox_cmdq *cmdq, int align_bytes)
{
struct nitrox_device *ndev = cmdq->ndev;
- u32 qsize;
-
- qsize = (ndev->qlen) * cmdq->instr_size;
- cmdq->head_unaligned = dma_zalloc_coherent(DEV(ndev),
- (qsize + PKT_IN_ALIGN),
- &cmdq->dma_unaligned,
- GFP_KERNEL);
- if (!cmdq->head_unaligned)
+
+ cmdq->qsize = (ndev->qlen * cmdq->instr_size) + align_bytes;
+ cmdq->unalign_base = dma_zalloc_coherent(DEV(ndev), cmdq->qsize,
+ &cmdq->unalign_dma,
+ GFP_KERNEL);
+ if (!cmdq->unalign_base)
return -ENOMEM;
- cmdq->head = PTR_ALIGN(cmdq->head_unaligned, PKT_IN_ALIGN);
- cmdq->dma = PTR_ALIGN(cmdq->dma_unaligned, PKT_IN_ALIGN);
- cmdq->qsize = (qsize + PKT_IN_ALIGN);
+ cmdq->dma = PTR_ALIGN(cmdq->unalign_dma, align_bytes);
+ cmdq->base = cmdq->unalign_base + (cmdq->dma - cmdq->unalign_dma);
cmdq->write_idx = 0;
- spin_lock_init(&cmdq->response_lock);
- spin_lock_init(&cmdq->cmdq_lock);
- spin_lock_init(&cmdq->backlog_lock);
+ spin_lock_init(&cmdq->cmd_qlock);
+ spin_lock_init(&cmdq->resp_qlock);
+ spin_lock_init(&cmdq->backlog_qlock);
INIT_LIST_HEAD(&cmdq->response_head);
INIT_LIST_HEAD(&cmdq->backlog_head);
@@ -51,68 +48,83 @@ static int cmdq_common_init(struct nitrox_cmdq *cmdq)
return 0;
}
-static void cmdq_common_cleanup(struct nitrox_cmdq *cmdq)
+static void nitrox_cmdq_reset(struct nitrox_cmdq *cmdq)
+{
+ cmdq->write_idx = 0;
+ atomic_set(&cmdq->pending_count, 0);
+ atomic_set(&cmdq->backlog_count, 0);
+}
+
+static void nitrox_cmdq_cleanup(struct nitrox_cmdq *cmdq)
{
struct nitrox_device *ndev = cmdq->ndev;
+ if (!cmdq->unalign_base)
+ return;
+
cancel_work_sync(&cmdq->backlog_qflush);
dma_free_coherent(DEV(ndev), cmdq->qsize,
- cmdq->head_unaligned, cmdq->dma_unaligned);
-
- atomic_set(&cmdq->pending_count, 0);
- atomic_set(&cmdq->backlog_count, 0);
+ cmdq->unalign_base, cmdq->unalign_dma);
+ nitrox_cmdq_reset(cmdq);
cmdq->dbell_csr_addr = NULL;
- cmdq->head = NULL;
+ cmdq->compl_cnt_csr_addr = NULL;
+ cmdq->unalign_base = NULL;
+ cmdq->base = NULL;
+ cmdq->unalign_dma = 0;
cmdq->dma = 0;
cmdq->qsize = 0;
cmdq->instr_size = 0;
}
-static void nitrox_cleanup_pkt_cmdqs(struct nitrox_device *ndev)
+static void nitrox_free_pktin_queues(struct nitrox_device *ndev)
{
int i;
for (i = 0; i < ndev->nr_queues; i++) {
- struct nitrox_cmdq *cmdq = &ndev->pkt_cmdqs[i];
+ struct nitrox_cmdq *cmdq = &ndev->pkt_inq[i];
- cmdq_common_cleanup(cmdq);
+ nitrox_cmdq_cleanup(cmdq);
}
- kfree(ndev->pkt_cmdqs);
- ndev->pkt_cmdqs = NULL;
+ kfree(ndev->pkt_inq);
+ ndev->pkt_inq = NULL;
}
-static int nitrox_init_pkt_cmdqs(struct nitrox_device *ndev)
+static int nitrox_alloc_pktin_queues(struct nitrox_device *ndev)
{
- int i, err, size;
+ int i, err;
- size = ndev->nr_queues * sizeof(struct nitrox_cmdq);
- ndev->pkt_cmdqs = kzalloc(size, GFP_KERNEL);
- if (!ndev->pkt_cmdqs)
+ ndev->pkt_inq = kcalloc_node(ndev->nr_queues,
+ sizeof(struct nitrox_cmdq),
+ GFP_KERNEL, ndev->node);
+ if (!ndev->pkt_inq)
return -ENOMEM;
for (i = 0; i < ndev->nr_queues; i++) {
struct nitrox_cmdq *cmdq;
u64 offset;
- cmdq = &ndev->pkt_cmdqs[i];
+ cmdq = &ndev->pkt_inq[i];
cmdq->ndev = ndev;
cmdq->qno = i;
cmdq->instr_size = sizeof(struct nps_pkt_instr);
+ /* packet input ring doorbell address */
offset = NPS_PKT_IN_INSTR_BAOFF_DBELLX(i);
- /* SE ring doorbell address for this queue */
cmdq->dbell_csr_addr = NITROX_CSR_ADDR(ndev, offset);
+ /* packet solicit port completion count address */
+ offset = NPS_PKT_SLC_CNTSX(i);
+ cmdq->compl_cnt_csr_addr = NITROX_CSR_ADDR(ndev, offset);
- err = cmdq_common_init(cmdq);
+ err = nitrox_cmdq_init(cmdq, PKTIN_Q_ALIGN_BYTES);
if (err)
- goto pkt_cmdq_fail;
+ goto pktq_fail;
}
return 0;
-pkt_cmdq_fail:
- nitrox_cleanup_pkt_cmdqs(ndev);
+pktq_fail:
+ nitrox_free_pktin_queues(ndev);
return err;
}
@@ -122,7 +134,7 @@ static int create_crypto_dma_pool(struct nitrox_device *ndev)
/* Crypto context pool, 16 byte aligned */
size = CRYPTO_CTX_SIZE + sizeof(struct ctx_hdr);
- ndev->ctx_pool = dma_pool_create("crypto-context",
+ ndev->ctx_pool = dma_pool_create("nitrox-context",
DEV(ndev), size, 16, 0);
if (!ndev->ctx_pool)
return -ENOMEM;
@@ -149,7 +161,7 @@ void *crypto_alloc_context(struct nitrox_device *ndev)
void *vaddr;
dma_addr_t dma;
- vaddr = dma_pool_alloc(ndev->ctx_pool, (GFP_KERNEL | __GFP_ZERO), &dma);
+ vaddr = dma_pool_zalloc(ndev->ctx_pool, GFP_KERNEL, &dma);
if (!vaddr)
return NULL;
@@ -194,7 +206,7 @@ int nitrox_common_sw_init(struct nitrox_device *ndev)
if (err)
return err;
- err = nitrox_init_pkt_cmdqs(ndev);
+ err = nitrox_alloc_pktin_queues(ndev);
if (err)
destroy_crypto_dma_pool(ndev);
@@ -207,6 +219,6 @@ int nitrox_common_sw_init(struct nitrox_device *ndev)
*/
void nitrox_common_sw_cleanup(struct nitrox_device *ndev)
{
- nitrox_cleanup_pkt_cmdqs(ndev);
+ nitrox_free_pktin_queues(ndev);
destroy_crypto_dma_pool(ndev);
}
diff --git a/drivers/crypto/cavium/nitrox/nitrox_main.c b/drivers/crypto/cavium/nitrox/nitrox_main.c
index fee7cb2ce747..6595c95af9f1 100644
--- a/drivers/crypto/cavium/nitrox/nitrox_main.c
+++ b/drivers/crypto/cavium/nitrox/nitrox_main.c
@@ -11,13 +11,15 @@
#include "nitrox_dev.h"
#include "nitrox_common.h"
#include "nitrox_csr.h"
+#include "nitrox_hal.h"
+#include "nitrox_isr.h"
#define CNN55XX_DEV_ID 0x12
#define MAX_PF_QUEUES 64
#define UCODE_HLEN 48
#define SE_GROUP 0
-#define DRIVER_VERSION "1.0"
+#define DRIVER_VERSION "1.1"
#define FW_DIR "cavium/"
/* SE microcode */
#define SE_FW FW_DIR "cnn55xx_se.fw"
@@ -42,6 +44,15 @@ static unsigned int qlen = DEFAULT_CMD_QLEN;
module_param(qlen, uint, 0644);
MODULE_PARM_DESC(qlen, "Command queue length - default 2048");
+#ifdef CONFIG_PCI_IOV
+int nitrox_sriov_configure(struct pci_dev *pdev, int num_vfs);
+#else
+int nitrox_sriov_configure(struct pci_dev *pdev, int num_vfs)
+{
+ return 0;
+}
+#endif
+
/**
* struct ucode - Firmware Header
* @id: microcode ID
@@ -136,9 +147,6 @@ static int nitrox_load_fw(struct nitrox_device *ndev, const char *fw_name)
write_to_ucd_unit(ndev, ucode);
release_firmware(fw);
- set_bit(NITROX_UCODE_LOADED, &ndev->status);
- /* barrier to sync with other cpus */
- smp_mb__after_atomic();
return 0;
}
@@ -210,7 +218,7 @@ void nitrox_put_device(struct nitrox_device *ndev)
smp_mb__after_atomic();
}
-static int nitrox_reset_device(struct pci_dev *pdev)
+static int nitrox_device_flr(struct pci_dev *pdev)
{
int pos = 0;
@@ -220,15 +228,10 @@ static int nitrox_reset_device(struct pci_dev *pdev)
return -ENOMEM;
}
- pos = pci_pcie_cap(pdev);
- if (!pos)
- return -ENOTTY;
+ /* check flr support */
+ if (pcie_has_flr(pdev))
+ pcie_flr(pdev);
- if (!pci_wait_for_pending_transaction(pdev))
- dev_err(&pdev->dev, "waiting for pending transaction\n");
-
- pcie_capability_set_word(pdev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_BCR_FLR);
- msleep(100);
pci_restore_state(pdev);
return 0;
@@ -242,7 +245,7 @@ static int nitrox_pf_sw_init(struct nitrox_device *ndev)
if (err)
return err;
- err = nitrox_pf_init_isr(ndev);
+ err = nitrox_register_interrupts(ndev);
if (err)
nitrox_common_sw_cleanup(ndev);
@@ -251,7 +254,7 @@ static int nitrox_pf_sw_init(struct nitrox_device *ndev)
static void nitrox_pf_sw_cleanup(struct nitrox_device *ndev)
{
- nitrox_pf_cleanup_isr(ndev);
+ nitrox_unregister_interrupts(ndev);
nitrox_common_sw_cleanup(ndev);
}
@@ -284,26 +287,6 @@ static int nitrox_bist_check(struct nitrox_device *ndev)
return 0;
}
-static void nitrox_get_hwinfo(struct nitrox_device *ndev)
-{
- union emu_fuse_map emu_fuse;
- u64 offset;
- int i;
-
- for (i = 0; i < NR_CLUSTERS; i++) {
- u8 dead_cores;
-
- offset = EMU_FUSE_MAPX(i);
- emu_fuse.value = nitrox_read_csr(ndev, offset);
- if (emu_fuse.s.valid) {
- dead_cores = hweight32(emu_fuse.s.ae_fuse);
- ndev->hw.ae_cores += AE_CORES_PER_CLUSTER - dead_cores;
- dead_cores = hweight16(emu_fuse.s.se_fuse);
- ndev->hw.se_cores += SE_CORES_PER_CLUSTER - dead_cores;
- }
- }
-}
-
static int nitrox_pf_hw_init(struct nitrox_device *ndev)
{
int err;
@@ -336,135 +319,6 @@ static int nitrox_pf_hw_init(struct nitrox_device *ndev)
return 0;
}
-#if IS_ENABLED(CONFIG_DEBUG_FS)
-static int registers_show(struct seq_file *s, void *v)
-{
- struct nitrox_device *ndev = s->private;
- u64 offset;
-
- /* NPS DMA stats */
- offset = NPS_STATS_PKT_DMA_RD_CNT;
- seq_printf(s, "NPS_STATS_PKT_DMA_RD_CNT 0x%016llx\n",
- nitrox_read_csr(ndev, offset));
- offset = NPS_STATS_PKT_DMA_WR_CNT;
- seq_printf(s, "NPS_STATS_PKT_DMA_WR_CNT 0x%016llx\n",
- nitrox_read_csr(ndev, offset));
-
- /* BMI/BMO stats */
- offset = BMI_NPS_PKT_CNT;
- seq_printf(s, "BMI_NPS_PKT_CNT 0x%016llx\n",
- nitrox_read_csr(ndev, offset));
- offset = BMO_NPS_SLC_PKT_CNT;
- seq_printf(s, "BMO_NPS_PKT_CNT 0x%016llx\n",
- nitrox_read_csr(ndev, offset));
-
- return 0;
-}
-
-static int registers_open(struct inode *inode, struct file *file)
-{
- return single_open(file, registers_show, inode->i_private);
-}
-
-static const struct file_operations register_fops = {
- .owner = THIS_MODULE,
- .open = registers_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int firmware_show(struct seq_file *s, void *v)
-{
- struct nitrox_device *ndev = s->private;
-
- seq_printf(s, "Version: %s\n", ndev->hw.fw_name);
- return 0;
-}
-
-static int firmware_open(struct inode *inode, struct file *file)
-{
- return single_open(file, firmware_show, inode->i_private);
-}
-
-static const struct file_operations firmware_fops = {
- .owner = THIS_MODULE,
- .open = firmware_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int nitrox_show(struct seq_file *s, void *v)
-{
- struct nitrox_device *ndev = s->private;
-
- seq_printf(s, "NITROX-5 [idx: %d]\n", ndev->idx);
- seq_printf(s, " Revision ID: 0x%0x\n", ndev->hw.revision_id);
- seq_printf(s, " Cores [AE: %u SE: %u]\n",
- ndev->hw.ae_cores, ndev->hw.se_cores);
- seq_printf(s, " Number of Queues: %u\n", ndev->nr_queues);
- seq_printf(s, " Queue length: %u\n", ndev->qlen);
- seq_printf(s, " Node: %u\n", ndev->node);
-
- return 0;
-}
-
-static int nitrox_open(struct inode *inode, struct file *file)
-{
- return single_open(file, nitrox_show, inode->i_private);
-}
-
-static const struct file_operations nitrox_fops = {
- .owner = THIS_MODULE,
- .open = nitrox_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static void nitrox_debugfs_exit(struct nitrox_device *ndev)
-{
- debugfs_remove_recursive(ndev->debugfs_dir);
- ndev->debugfs_dir = NULL;
-}
-
-static int nitrox_debugfs_init(struct nitrox_device *ndev)
-{
- struct dentry *dir, *f;
-
- dir = debugfs_create_dir(KBUILD_MODNAME, NULL);
- if (!dir)
- return -ENOMEM;
-
- ndev->debugfs_dir = dir;
- f = debugfs_create_file("counters", 0400, dir, ndev, &register_fops);
- if (!f)
- goto err;
- f = debugfs_create_file("firmware", 0400, dir, ndev, &firmware_fops);
- if (!f)
- goto err;
- f = debugfs_create_file("nitrox", 0400, dir, ndev, &nitrox_fops);
- if (!f)
- goto err;
-
- return 0;
-
-err:
- nitrox_debugfs_exit(ndev);
- return -ENODEV;
-}
-#else
-static int nitrox_debugfs_init(struct nitrox_device *ndev)
-{
- return 0;
-}
-
-static void nitrox_debugfs_exit(struct nitrox_device *ndev)
-{
-}
-#endif
-
/**
* nitrox_probe - NITROX Initialization function.
* @pdev: PCI device information struct
@@ -487,7 +341,7 @@ static int nitrox_probe(struct pci_dev *pdev,
return err;
/* do FLR */
- err = nitrox_reset_device(pdev);
+ err = nitrox_device_flr(pdev);
if (err) {
dev_err(&pdev->dev, "FLR failed\n");
pci_disable_device(pdev);
@@ -555,7 +409,12 @@ static int nitrox_probe(struct pci_dev *pdev,
if (err)
goto pf_hw_fail;
- set_bit(NITROX_READY, &ndev->status);
+ /* clear the statistics */
+ atomic64_set(&ndev->stats.posted, 0);
+ atomic64_set(&ndev->stats.completed, 0);
+ atomic64_set(&ndev->stats.dropped, 0);
+
+ atomic_set(&ndev->state, __NDEV_READY);
/* barrier to sync with other cpus */
smp_mb__after_atomic();
@@ -567,7 +426,7 @@ static int nitrox_probe(struct pci_dev *pdev,
crypto_fail:
nitrox_debugfs_exit(ndev);
- clear_bit(NITROX_READY, &ndev->status);
+ atomic_set(&ndev->state, __NDEV_NOT_READY);
/* barrier to sync with other cpus */
smp_mb__after_atomic();
pf_hw_fail:
@@ -602,11 +461,16 @@ static void nitrox_remove(struct pci_dev *pdev)
dev_info(DEV(ndev), "Removing Device %x:%x\n",
ndev->hw.vendor_id, ndev->hw.device_id);
- clear_bit(NITROX_READY, &ndev->status);
+ atomic_set(&ndev->state, __NDEV_NOT_READY);
/* barrier to sync with other cpus */
smp_mb__after_atomic();
nitrox_remove_from_devlist(ndev);
+
+#ifdef CONFIG_PCI_IOV
+ /* disable SR-IOV */
+ nitrox_sriov_configure(pdev, 0);
+#endif
nitrox_crypto_unregister();
nitrox_debugfs_exit(ndev);
nitrox_pf_sw_cleanup(ndev);
@@ -632,6 +496,9 @@ static struct pci_driver nitrox_driver = {
.probe = nitrox_probe,
.remove = nitrox_remove,
.shutdown = nitrox_shutdown,
+#ifdef CONFIG_PCI_IOV
+ .sriov_configure = nitrox_sriov_configure,
+#endif
};
module_pci_driver(nitrox_driver);
diff --git a/drivers/crypto/cavium/nitrox/nitrox_reqmgr.c b/drivers/crypto/cavium/nitrox/nitrox_reqmgr.c
index 4a362fc22f62..3987cd84c033 100644
--- a/drivers/crypto/cavium/nitrox/nitrox_reqmgr.c
+++ b/drivers/crypto/cavium/nitrox/nitrox_reqmgr.c
@@ -382,11 +382,11 @@ static inline void backlog_list_add(struct nitrox_softreq *sr,
{
INIT_LIST_HEAD(&sr->backlog);
- spin_lock_bh(&cmdq->backlog_lock);
+ spin_lock_bh(&cmdq->backlog_qlock);
list_add_tail(&sr->backlog, &cmdq->backlog_head);
atomic_inc(&cmdq->backlog_count);
atomic_set(&sr->status, REQ_BACKLOG);
- spin_unlock_bh(&cmdq->backlog_lock);
+ spin_unlock_bh(&cmdq->backlog_qlock);
}
static inline void response_list_add(struct nitrox_softreq *sr,
@@ -394,17 +394,17 @@ static inline void response_list_add(struct nitrox_softreq *sr,
{
INIT_LIST_HEAD(&sr->response);
- spin_lock_bh(&cmdq->response_lock);
+ spin_lock_bh(&cmdq->resp_qlock);
list_add_tail(&sr->response, &cmdq->response_head);
- spin_unlock_bh(&cmdq->response_lock);
+ spin_unlock_bh(&cmdq->resp_qlock);
}
static inline void response_list_del(struct nitrox_softreq *sr,
struct nitrox_cmdq *cmdq)
{
- spin_lock_bh(&cmdq->response_lock);
+ spin_lock_bh(&cmdq->resp_qlock);
list_del(&sr->response);
- spin_unlock_bh(&cmdq->response_lock);
+ spin_unlock_bh(&cmdq->resp_qlock);
}
static struct nitrox_softreq *
@@ -439,11 +439,11 @@ static void post_se_instr(struct nitrox_softreq *sr,
int idx;
u8 *ent;
- spin_lock_bh(&cmdq->cmdq_lock);
+ spin_lock_bh(&cmdq->cmd_qlock);
idx = cmdq->write_idx;
/* copy the instruction */
- ent = cmdq->head + (idx * cmdq->instr_size);
+ ent = cmdq->base + (idx * cmdq->instr_size);
memcpy(ent, &sr->instr, cmdq->instr_size);
atomic_set(&sr->status, REQ_POSTED);
@@ -459,7 +459,10 @@ static void post_se_instr(struct nitrox_softreq *sr,
cmdq->write_idx = incr_index(idx, 1, ndev->qlen);
- spin_unlock_bh(&cmdq->cmdq_lock);
+ spin_unlock_bh(&cmdq->cmd_qlock);
+
+ /* increment the posted command count */
+ atomic64_inc(&ndev->stats.posted);
}
static int post_backlog_cmds(struct nitrox_cmdq *cmdq)
@@ -471,7 +474,7 @@ static int post_backlog_cmds(struct nitrox_cmdq *cmdq)
if (!atomic_read(&cmdq->backlog_count))
return 0;
- spin_lock_bh(&cmdq->backlog_lock);
+ spin_lock_bh(&cmdq->backlog_qlock);
list_for_each_entry_safe(sr, tmp, &cmdq->backlog_head, backlog) {
struct skcipher_request *skreq;
@@ -494,7 +497,7 @@ static int post_backlog_cmds(struct nitrox_cmdq *cmdq)
/* backlog requests are posted, wakeup with -EINPROGRESS */
skcipher_request_complete(skreq, -EINPROGRESS);
}
- spin_unlock_bh(&cmdq->backlog_lock);
+ spin_unlock_bh(&cmdq->backlog_qlock);
return ret;
}
@@ -508,8 +511,11 @@ static int nitrox_enqueue_request(struct nitrox_softreq *sr)
post_backlog_cmds(cmdq);
if (unlikely(cmdq_full(cmdq, ndev->qlen))) {
- if (!(sr->flags & CRYPTO_TFM_REQ_MAY_BACKLOG))
+ if (!(sr->flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) {
+ /* increment drop count */
+ atomic64_inc(&ndev->stats.dropped);
return -ENOSPC;
+ }
/* add to backlog list */
backlog_list_add(sr, cmdq);
return -EBUSY;
@@ -572,7 +578,7 @@ int nitrox_process_se_request(struct nitrox_device *ndev,
/* select the queue */
qno = smp_processor_id() % ndev->nr_queues;
- sr->cmdq = &ndev->pkt_cmdqs[qno];
+ sr->cmdq = &ndev->pkt_inq[qno];
/*
* 64-Byte Instruction Format
@@ -694,6 +700,7 @@ static void process_response_list(struct nitrox_cmdq *cmdq)
READ_ONCE(sr->resp.orh));
}
atomic_dec(&cmdq->pending_count);
+ atomic64_inc(&ndev->stats.completed);
/* sync with other cpus */
smp_mb__after_atomic();
/* remove from response list */
@@ -714,18 +721,18 @@ static void process_response_list(struct nitrox_cmdq *cmdq)
}
/**
- * pkt_slc_resp_handler - post processing of SE responses
+ * pkt_slc_resp_tasklet - post processing of SE responses
*/
-void pkt_slc_resp_handler(unsigned long data)
+void pkt_slc_resp_tasklet(unsigned long data)
{
- struct bh_data *bh = (void *)(uintptr_t)(data);
- struct nitrox_cmdq *cmdq = bh->cmdq;
- union nps_pkt_slc_cnts pkt_slc_cnts;
+ struct nitrox_q_vector *qvec = (void *)(uintptr_t)(data);
+ struct nitrox_cmdq *cmdq = qvec->cmdq;
+ union nps_pkt_slc_cnts slc_cnts;
/* read completion count */
- pkt_slc_cnts.value = readq(bh->completion_cnt_csr_addr);
+ slc_cnts.value = readq(cmdq->compl_cnt_csr_addr);
/* resend the interrupt if more work to do */
- pkt_slc_cnts.s.resend = 1;
+ slc_cnts.s.resend = 1;
process_response_list(cmdq);
@@ -733,7 +740,7 @@ void pkt_slc_resp_handler(unsigned long data)
* clear the interrupt with resend bit enabled,
* MSI-X interrupt generates if Completion count > Threshold
*/
- writeq(pkt_slc_cnts.value, bh->completion_cnt_csr_addr);
+ writeq(slc_cnts.value, cmdq->compl_cnt_csr_addr);
/* order the writes */
mmiowb();
diff --git a/drivers/crypto/cavium/nitrox/nitrox_sriov.c b/drivers/crypto/cavium/nitrox/nitrox_sriov.c
new file mode 100644
index 000000000000..30c0aa874583
--- /dev/null
+++ b/drivers/crypto/cavium/nitrox/nitrox_sriov.c
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include "nitrox_dev.h"
+#include "nitrox_hal.h"
+#include "nitrox_common.h"
+#include "nitrox_isr.h"
+
+static inline bool num_vfs_valid(int num_vfs)
+{
+ bool valid = false;
+
+ switch (num_vfs) {
+ case 16:
+ case 32:
+ case 64:
+ case 128:
+ valid = true;
+ break;
+ }
+
+ return valid;
+}
+
+static inline enum vf_mode num_vfs_to_mode(int num_vfs)
+{
+ enum vf_mode mode = 0;
+
+ switch (num_vfs) {
+ case 0:
+ mode = __NDEV_MODE_PF;
+ break;
+ case 16:
+ mode = __NDEV_MODE_VF16;
+ break;
+ case 32:
+ mode = __NDEV_MODE_VF32;
+ break;
+ case 64:
+ mode = __NDEV_MODE_VF64;
+ break;
+ case 128:
+ mode = __NDEV_MODE_VF128;
+ break;
+ }
+
+ return mode;
+}
+
+static void pf_sriov_cleanup(struct nitrox_device *ndev)
+{
+ /* PF has no queues in SR-IOV mode */
+ atomic_set(&ndev->state, __NDEV_NOT_READY);
+ /* unregister crypto algorithms */
+ nitrox_crypto_unregister();
+
+ /* cleanup PF resources */
+ nitrox_unregister_interrupts(ndev);
+ nitrox_common_sw_cleanup(ndev);
+}
+
+static int pf_sriov_init(struct nitrox_device *ndev)
+{
+ int err;
+
+ /* allocate resources for PF */
+ err = nitrox_common_sw_init(ndev);
+ if (err)
+ return err;
+
+ err = nitrox_register_interrupts(ndev);
+ if (err) {
+ nitrox_common_sw_cleanup(ndev);
+ return err;
+ }
+
+ /* configure the packet queues */
+ nitrox_config_pkt_input_rings(ndev);
+ nitrox_config_pkt_solicit_ports(ndev);
+
+ /* set device to ready state */
+ atomic_set(&ndev->state, __NDEV_READY);
+
+ /* register crypto algorithms */
+ return nitrox_crypto_register();
+}
+
+static int nitrox_sriov_enable(struct pci_dev *pdev, int num_vfs)
+{
+ struct nitrox_device *ndev = pci_get_drvdata(pdev);
+ int err;
+
+ if (!num_vfs_valid(num_vfs)) {
+ dev_err(DEV(ndev), "Invalid num_vfs %d\n", num_vfs);
+ return -EINVAL;
+ }
+
+ if (pci_num_vf(pdev) == num_vfs)
+ return num_vfs;
+
+ err = pci_enable_sriov(pdev, num_vfs);
+ if (err) {
+ dev_err(DEV(ndev), "failed to enable PCI sriov %d\n", err);
+ return err;
+ }
+ dev_info(DEV(ndev), "Enabled VF(s) %d\n", num_vfs);
+
+ ndev->num_vfs = num_vfs;
+ ndev->mode = num_vfs_to_mode(num_vfs);
+ /* set bit in flags */
+ set_bit(__NDEV_SRIOV_BIT, &ndev->flags);
+
+ /* cleanup PF resources */
+ pf_sriov_cleanup(ndev);
+
+ config_nps_core_vfcfg_mode(ndev, ndev->mode);
+
+ return num_vfs;
+}
+
+static int nitrox_sriov_disable(struct pci_dev *pdev)
+{
+ struct nitrox_device *ndev = pci_get_drvdata(pdev);
+
+ if (!test_bit(__NDEV_SRIOV_BIT, &ndev->flags))
+ return 0;
+
+ if (pci_vfs_assigned(pdev)) {
+ dev_warn(DEV(ndev), "VFs are attached to VM. Can't disable SR-IOV\n");
+ return -EPERM;
+ }
+ pci_disable_sriov(pdev);
+ /* clear bit in flags */
+ clear_bit(__NDEV_SRIOV_BIT, &ndev->flags);
+
+ ndev->num_vfs = 0;
+ ndev->mode = __NDEV_MODE_PF;
+
+ config_nps_core_vfcfg_mode(ndev, ndev->mode);
+
+ return pf_sriov_init(ndev);
+}
+
+int nitrox_sriov_configure(struct pci_dev *pdev, int num_vfs)
+{
+ if (!num_vfs)
+ return nitrox_sriov_disable(pdev);
+
+ return nitrox_sriov_enable(pdev, num_vfs);
+}
diff --git a/drivers/crypto/ccp/ccp-crypto-aes-xts.c b/drivers/crypto/ccp/ccp-crypto-aes-xts.c
index 94b5bcf5b628..ca4630b8395f 100644
--- a/drivers/crypto/ccp/ccp-crypto-aes-xts.c
+++ b/drivers/crypto/ccp/ccp-crypto-aes-xts.c
@@ -102,7 +102,7 @@ static int ccp_aes_xts_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
ctx->u.aes.key_len = key_len / 2;
sg_init_one(&ctx->u.aes.key_sg, ctx->u.aes.key, key_len);
- return crypto_skcipher_setkey(ctx->u.aes.tfm_skcipher, key, key_len);
+ return crypto_sync_skcipher_setkey(ctx->u.aes.tfm_skcipher, key, key_len);
}
static int ccp_aes_xts_crypt(struct ablkcipher_request *req,
@@ -151,12 +151,13 @@ static int ccp_aes_xts_crypt(struct ablkcipher_request *req,
(ctx->u.aes.key_len != AES_KEYSIZE_256))
fallback = 1;
if (fallback) {
- SKCIPHER_REQUEST_ON_STACK(subreq, ctx->u.aes.tfm_skcipher);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(subreq,
+ ctx->u.aes.tfm_skcipher);
/* Use the fallback to process the request for any
* unsupported unit sizes or key sizes
*/
- skcipher_request_set_tfm(subreq, ctx->u.aes.tfm_skcipher);
+ skcipher_request_set_sync_tfm(subreq, ctx->u.aes.tfm_skcipher);
skcipher_request_set_callback(subreq, req->base.flags,
NULL, NULL);
skcipher_request_set_crypt(subreq, req->src, req->dst,
@@ -203,12 +204,12 @@ static int ccp_aes_xts_decrypt(struct ablkcipher_request *req)
static int ccp_aes_xts_cra_init(struct crypto_tfm *tfm)
{
struct ccp_ctx *ctx = crypto_tfm_ctx(tfm);
- struct crypto_skcipher *fallback_tfm;
+ struct crypto_sync_skcipher *fallback_tfm;
ctx->complete = ccp_aes_xts_complete;
ctx->u.aes.key_len = 0;
- fallback_tfm = crypto_alloc_skcipher("xts(aes)", 0,
+ fallback_tfm = crypto_alloc_sync_skcipher("xts(aes)", 0,
CRYPTO_ALG_ASYNC |
CRYPTO_ALG_NEED_FALLBACK);
if (IS_ERR(fallback_tfm)) {
@@ -226,7 +227,7 @@ static void ccp_aes_xts_cra_exit(struct crypto_tfm *tfm)
{
struct ccp_ctx *ctx = crypto_tfm_ctx(tfm);
- crypto_free_skcipher(ctx->u.aes.tfm_skcipher);
+ crypto_free_sync_skcipher(ctx->u.aes.tfm_skcipher);
}
static int ccp_register_aes_xts_alg(struct list_head *head,
diff --git a/drivers/crypto/ccp/ccp-crypto.h b/drivers/crypto/ccp/ccp-crypto.h
index b9fd090c46c2..28819e11db96 100644
--- a/drivers/crypto/ccp/ccp-crypto.h
+++ b/drivers/crypto/ccp/ccp-crypto.h
@@ -88,7 +88,7 @@ static inline struct ccp_crypto_ahash_alg *
/***** AES related defines *****/
struct ccp_aes_ctx {
/* Fallback cipher for XTS with unsupported unit sizes */
- struct crypto_skcipher *tfm_skcipher;
+ struct crypto_sync_skcipher *tfm_skcipher;
/* Cipher used to generate CMAC K1/K2 keys */
struct crypto_cipher *tfm_cipher;
diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c
index 72790d88236d..d64a78ccc03e 100644
--- a/drivers/crypto/ccp/psp-dev.c
+++ b/drivers/crypto/ccp/psp-dev.c
@@ -31,8 +31,9 @@
((psp_master->api_major) >= _maj && \
(psp_master->api_minor) >= _min)
-#define DEVICE_NAME "sev"
-#define SEV_FW_FILE "amd/sev.fw"
+#define DEVICE_NAME "sev"
+#define SEV_FW_FILE "amd/sev.fw"
+#define SEV_FW_NAME_SIZE 64
static DEFINE_MUTEX(sev_cmd_mutex);
static struct sev_misc_dev *misc_dev;
@@ -423,7 +424,7 @@ EXPORT_SYMBOL_GPL(psp_copy_user_blob);
static int sev_get_api_version(void)
{
struct sev_user_data_status *status;
- int error, ret;
+ int error = 0, ret;
status = &psp_master->status_cmd_buf;
ret = sev_platform_status(status, &error);
@@ -440,6 +441,41 @@ static int sev_get_api_version(void)
return 0;
}
+static int sev_get_firmware(struct device *dev,
+ const struct firmware **firmware)
+{
+ char fw_name_specific[SEV_FW_NAME_SIZE];
+ char fw_name_subset[SEV_FW_NAME_SIZE];
+
+ snprintf(fw_name_specific, sizeof(fw_name_specific),
+ "amd/amd_sev_fam%.2xh_model%.2xh.sbin",
+ boot_cpu_data.x86, boot_cpu_data.x86_model);
+
+ snprintf(fw_name_subset, sizeof(fw_name_subset),
+ "amd/amd_sev_fam%.2xh_model%.1xxh.sbin",
+ boot_cpu_data.x86, (boot_cpu_data.x86_model & 0xf0) >> 4);
+
+ /* Check for SEV FW for a particular model.
+ * Ex. amd_sev_fam17h_model00h.sbin for Family 17h Model 00h
+ *
+ * or
+ *
+ * Check for SEV FW common to a subset of models.
+ * Ex. amd_sev_fam17h_model0xh.sbin for
+ * Family 17h Model 00h -- Family 17h Model 0Fh
+ *
+ * or
+ *
+ * Fall-back to using generic name: sev.fw
+ */
+ if ((firmware_request_nowarn(firmware, fw_name_specific, dev) >= 0) ||
+ (firmware_request_nowarn(firmware, fw_name_subset, dev) >= 0) ||
+ (firmware_request_nowarn(firmware, SEV_FW_FILE, dev) >= 0))
+ return 0;
+
+ return -ENOENT;
+}
+
/* Don't fail if SEV FW couldn't be updated. Continue with existing SEV FW */
static int sev_update_firmware(struct device *dev)
{
@@ -449,9 +485,10 @@ static int sev_update_firmware(struct device *dev)
struct page *p;
u64 data_size;
- ret = request_firmware(&firmware, SEV_FW_FILE, dev);
- if (ret < 0)
+ if (sev_get_firmware(dev, &firmware) == -ENOENT) {
+ dev_dbg(dev, "No SEV firmware file present\n");
return -1;
+ }
/*
* SEV FW expects the physical address given to it to be 32
diff --git a/drivers/crypto/ccp/sp-platform.c b/drivers/crypto/ccp/sp-platform.c
index 71734f254fd1..b75dc7db2d4a 100644
--- a/drivers/crypto/ccp/sp-platform.c
+++ b/drivers/crypto/ccp/sp-platform.c
@@ -33,8 +33,31 @@ struct sp_platform {
unsigned int irq_count;
};
-static const struct acpi_device_id sp_acpi_match[];
-static const struct of_device_id sp_of_match[];
+static const struct sp_dev_vdata dev_vdata[] = {
+ {
+ .bar = 0,
+#ifdef CONFIG_CRYPTO_DEV_SP_CCP
+ .ccp_vdata = &ccpv3_platform,
+#endif
+ },
+};
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id sp_acpi_match[] = {
+ { "AMDI0C00", (kernel_ulong_t)&dev_vdata[0] },
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, sp_acpi_match);
+#endif
+
+#ifdef CONFIG_OF
+static const struct of_device_id sp_of_match[] = {
+ { .compatible = "amd,ccp-seattle-v1a",
+ .data = (const void *)&dev_vdata[0] },
+ { },
+};
+MODULE_DEVICE_TABLE(of, sp_of_match);
+#endif
static struct sp_dev_vdata *sp_get_of_version(struct platform_device *pdev)
{
@@ -201,32 +224,6 @@ static int sp_platform_resume(struct platform_device *pdev)
}
#endif
-static const struct sp_dev_vdata dev_vdata[] = {
- {
- .bar = 0,
-#ifdef CONFIG_CRYPTO_DEV_SP_CCP
- .ccp_vdata = &ccpv3_platform,
-#endif
- },
-};
-
-#ifdef CONFIG_ACPI
-static const struct acpi_device_id sp_acpi_match[] = {
- { "AMDI0C00", (kernel_ulong_t)&dev_vdata[0] },
- { },
-};
-MODULE_DEVICE_TABLE(acpi, sp_acpi_match);
-#endif
-
-#ifdef CONFIG_OF
-static const struct of_device_id sp_of_match[] = {
- { .compatible = "amd,ccp-seattle-v1a",
- .data = (const void *)&dev_vdata[0] },
- { },
-};
-MODULE_DEVICE_TABLE(of, sp_of_match);
-#endif
-
static struct platform_driver sp_platform_driver = {
.driver = {
.name = "ccp",
diff --git a/drivers/crypto/ccree/cc_hw_queue_defs.h b/drivers/crypto/ccree/cc_hw_queue_defs.h
index a091ae57f902..45985b955d2c 100644
--- a/drivers/crypto/ccree/cc_hw_queue_defs.h
+++ b/drivers/crypto/ccree/cc_hw_queue_defs.h
@@ -449,8 +449,7 @@ static inline void set_flow_mode(struct cc_hw_desc *pdesc,
* @pdesc: pointer HW descriptor struct
* @mode: Any one of the modes defined in [CC7x-DESC]
*/
-static inline void set_cipher_mode(struct cc_hw_desc *pdesc,
- enum drv_cipher_mode mode)
+static inline void set_cipher_mode(struct cc_hw_desc *pdesc, int mode)
{
pdesc->word[4] |= FIELD_PREP(WORD4_CIPHER_MODE, mode);
}
@@ -461,8 +460,7 @@ static inline void set_cipher_mode(struct cc_hw_desc *pdesc,
* @pdesc: pointer HW descriptor struct
* @mode: Any one of the modes defined in [CC7x-DESC]
*/
-static inline void set_cipher_config0(struct cc_hw_desc *pdesc,
- enum drv_crypto_direction mode)
+static inline void set_cipher_config0(struct cc_hw_desc *pdesc, int mode)
{
pdesc->word[4] |= FIELD_PREP(WORD4_CIPHER_CONF0, mode);
}
diff --git a/drivers/crypto/chelsio/chcr_algo.c b/drivers/crypto/chelsio/chcr_algo.c
index 5c539af8ed60..db203f8be429 100644
--- a/drivers/crypto/chelsio/chcr_algo.c
+++ b/drivers/crypto/chelsio/chcr_algo.c
@@ -367,7 +367,8 @@ static inline void dsgl_walk_init(struct dsgl_walk *walk,
walk->to = (struct phys_sge_pairs *)(dsgl + 1);
}
-static inline void dsgl_walk_end(struct dsgl_walk *walk, unsigned short qid)
+static inline void dsgl_walk_end(struct dsgl_walk *walk, unsigned short qid,
+ int pci_chan_id)
{
struct cpl_rx_phys_dsgl *phys_cpl;
@@ -385,6 +386,7 @@ static inline void dsgl_walk_end(struct dsgl_walk *walk, unsigned short qid)
phys_cpl->rss_hdr_int.opcode = CPL_RX_PHYS_ADDR;
phys_cpl->rss_hdr_int.qid = htons(qid);
phys_cpl->rss_hdr_int.hash_val = 0;
+ phys_cpl->rss_hdr_int.channel = pci_chan_id;
}
static inline void dsgl_walk_add_page(struct dsgl_walk *walk,
@@ -671,7 +673,7 @@ static int chcr_sg_ent_in_wr(struct scatterlist *src,
return min(srclen, dstlen);
}
-static int chcr_cipher_fallback(struct crypto_skcipher *cipher,
+static int chcr_cipher_fallback(struct crypto_sync_skcipher *cipher,
u32 flags,
struct scatterlist *src,
struct scatterlist *dst,
@@ -681,9 +683,9 @@ static int chcr_cipher_fallback(struct crypto_skcipher *cipher,
{
int err;
- SKCIPHER_REQUEST_ON_STACK(subreq, cipher);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, cipher);
- skcipher_request_set_tfm(subreq, cipher);
+ skcipher_request_set_sync_tfm(subreq, cipher);
skcipher_request_set_callback(subreq, flags, NULL, NULL);
skcipher_request_set_crypt(subreq, src, dst,
nbytes, iv);
@@ -718,7 +720,7 @@ static inline void create_wreq(struct chcr_context *ctx,
FILL_WR_RX_Q_ID(ctx->dev->rx_channel_id, qid,
!!lcb, ctx->tx_qidx);
- chcr_req->ulptx.cmd_dest = FILL_ULPTX_CMD_DEST(ctx->dev->tx_channel_id,
+ chcr_req->ulptx.cmd_dest = FILL_ULPTX_CMD_DEST(ctx->tx_chan_id,
qid);
chcr_req->ulptx.len = htonl((DIV_ROUND_UP(len16, 16) -
((sizeof(chcr_req->wreq)) >> 4)));
@@ -854,13 +856,14 @@ static int chcr_cipher_fallback_setkey(struct crypto_ablkcipher *cipher,
struct ablk_ctx *ablkctx = ABLK_CTX(c_ctx(cipher));
int err = 0;
- crypto_skcipher_clear_flags(ablkctx->sw_cipher, CRYPTO_TFM_REQ_MASK);
- crypto_skcipher_set_flags(ablkctx->sw_cipher, cipher->base.crt_flags &
- CRYPTO_TFM_REQ_MASK);
- err = crypto_skcipher_setkey(ablkctx->sw_cipher, key, keylen);
+ crypto_sync_skcipher_clear_flags(ablkctx->sw_cipher,
+ CRYPTO_TFM_REQ_MASK);
+ crypto_sync_skcipher_set_flags(ablkctx->sw_cipher,
+ cipher->base.crt_flags & CRYPTO_TFM_REQ_MASK);
+ err = crypto_sync_skcipher_setkey(ablkctx->sw_cipher, key, keylen);
tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK;
tfm->crt_flags |=
- crypto_skcipher_get_flags(ablkctx->sw_cipher) &
+ crypto_sync_skcipher_get_flags(ablkctx->sw_cipher) &
CRYPTO_TFM_RES_MASK;
return err;
}
@@ -1335,20 +1338,26 @@ static int chcr_device_init(struct chcr_context *ctx)
}
ctx->dev = u_ctx->dev;
adap = padap(ctx->dev);
- ntxq = min_not_zero((unsigned int)u_ctx->lldi.nrxq,
- adap->vres.ncrypto_fc);
+ ntxq = u_ctx->lldi.ntxq;
rxq_perchan = u_ctx->lldi.nrxq / u_ctx->lldi.nchan;
txq_perchan = ntxq / u_ctx->lldi.nchan;
- rxq_idx = ctx->dev->tx_channel_id * rxq_perchan;
- rxq_idx += id % rxq_perchan;
- txq_idx = ctx->dev->tx_channel_id * txq_perchan;
- txq_idx += id % txq_perchan;
spin_lock(&ctx->dev->lock_chcr_dev);
- ctx->rx_qidx = rxq_idx;
- ctx->tx_qidx = txq_idx;
+ ctx->tx_chan_id = ctx->dev->tx_channel_id;
ctx->dev->tx_channel_id = !ctx->dev->tx_channel_id;
ctx->dev->rx_channel_id = 0;
spin_unlock(&ctx->dev->lock_chcr_dev);
+ rxq_idx = ctx->tx_chan_id * rxq_perchan;
+ rxq_idx += id % rxq_perchan;
+ txq_idx = ctx->tx_chan_id * txq_perchan;
+ txq_idx += id % txq_perchan;
+ ctx->rx_qidx = rxq_idx;
+ ctx->tx_qidx = txq_idx;
+ /* Channel Id used by SGE to forward packet to Host.
+ * Same value should be used in cpl_fw6_pld RSS_CH field
+ * by FW. Driver programs PCI channel ID to be used in fw
+ * at the time of queue allocation with value "pi->tx_chan"
+ */
+ ctx->pci_chan_id = txq_idx / txq_perchan;
}
out:
return err;
@@ -1360,8 +1369,8 @@ static int chcr_cra_init(struct crypto_tfm *tfm)
struct chcr_context *ctx = crypto_tfm_ctx(tfm);
struct ablk_ctx *ablkctx = ABLK_CTX(ctx);
- ablkctx->sw_cipher = crypto_alloc_skcipher(alg->cra_name, 0,
- CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK);
+ ablkctx->sw_cipher = crypto_alloc_sync_skcipher(alg->cra_name, 0,
+ CRYPTO_ALG_NEED_FALLBACK);
if (IS_ERR(ablkctx->sw_cipher)) {
pr_err("failed to allocate fallback for %s\n", alg->cra_name);
return PTR_ERR(ablkctx->sw_cipher);
@@ -1390,8 +1399,8 @@ static int chcr_rfc3686_init(struct crypto_tfm *tfm)
/*RFC3686 initialises IV counter value to 1, rfc3686(ctr(aes))
* cannot be used as fallback in chcr_handle_cipher_response
*/
- ablkctx->sw_cipher = crypto_alloc_skcipher("ctr(aes)", 0,
- CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK);
+ ablkctx->sw_cipher = crypto_alloc_sync_skcipher("ctr(aes)", 0,
+ CRYPTO_ALG_NEED_FALLBACK);
if (IS_ERR(ablkctx->sw_cipher)) {
pr_err("failed to allocate fallback for %s\n", alg->cra_name);
return PTR_ERR(ablkctx->sw_cipher);
@@ -1406,7 +1415,7 @@ static void chcr_cra_exit(struct crypto_tfm *tfm)
struct chcr_context *ctx = crypto_tfm_ctx(tfm);
struct ablk_ctx *ablkctx = ABLK_CTX(ctx);
- crypto_free_skcipher(ablkctx->sw_cipher);
+ crypto_free_sync_skcipher(ablkctx->sw_cipher);
if (ablkctx->aes_generic)
crypto_free_cipher(ablkctx->aes_generic);
}
@@ -2503,6 +2512,7 @@ void chcr_add_aead_dst_ent(struct aead_request *req,
struct crypto_aead *tfm = crypto_aead_reqtfm(req);
struct dsgl_walk dsgl_walk;
unsigned int authsize = crypto_aead_authsize(tfm);
+ struct chcr_context *ctx = a_ctx(tfm);
u32 temp;
dsgl_walk_init(&dsgl_walk, phys_cpl);
@@ -2512,7 +2522,7 @@ void chcr_add_aead_dst_ent(struct aead_request *req,
dsgl_walk_add_page(&dsgl_walk, IV, &reqctx->iv_dma);
temp = req->cryptlen + (reqctx->op ? -authsize : authsize);
dsgl_walk_add_sg(&dsgl_walk, req->dst, temp, req->assoclen);
- dsgl_walk_end(&dsgl_walk, qid);
+ dsgl_walk_end(&dsgl_walk, qid, ctx->pci_chan_id);
}
void chcr_add_cipher_src_ent(struct ablkcipher_request *req,
@@ -2544,6 +2554,8 @@ void chcr_add_cipher_dst_ent(struct ablkcipher_request *req,
unsigned short qid)
{
struct chcr_blkcipher_req_ctx *reqctx = ablkcipher_request_ctx(req);
+ struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(wrparam->req);
+ struct chcr_context *ctx = c_ctx(tfm);
struct dsgl_walk dsgl_walk;
dsgl_walk_init(&dsgl_walk, phys_cpl);
@@ -2552,7 +2564,7 @@ void chcr_add_cipher_dst_ent(struct ablkcipher_request *req,
reqctx->dstsg = dsgl_walk.last_sg;
reqctx->dst_ofst = dsgl_walk.last_sg_len;
- dsgl_walk_end(&dsgl_walk, qid);
+ dsgl_walk_end(&dsgl_walk, qid, ctx->pci_chan_id);
}
void chcr_add_hash_src_ent(struct ahash_request *req,
diff --git a/drivers/crypto/chelsio/chcr_core.c b/drivers/crypto/chelsio/chcr_core.c
index 04f277cade7c..2c472e3c6aeb 100644
--- a/drivers/crypto/chelsio/chcr_core.c
+++ b/drivers/crypto/chelsio/chcr_core.c
@@ -43,7 +43,7 @@ static chcr_handler_func work_handlers[NUM_CPL_CMDS] = {
static struct cxgb4_uld_info chcr_uld_info = {
.name = DRV_MODULE_NAME,
.nrxq = MAX_ULD_QSETS,
- .ntxq = MAX_ULD_QSETS,
+ /* Max ntxq will be derived from fw config file*/
.rxq_size = 1024,
.add = chcr_uld_add,
.state_change = chcr_uld_state_change,
@@ -237,9 +237,7 @@ static int chcr_uld_state_change(void *handle, enum cxgb4_state state)
static int __init chcr_crypto_init(void)
{
- if (cxgb4_register_uld(CXGB4_ULD_CRYPTO, &chcr_uld_info))
- pr_err("ULD register fail: No chcr crypto support in cxgb4\n");
-
+ cxgb4_register_uld(CXGB4_ULD_CRYPTO, &chcr_uld_info);
return 0;
}
diff --git a/drivers/crypto/chelsio/chcr_crypto.h b/drivers/crypto/chelsio/chcr_crypto.h
index 54835cb109e5..d37ef41f9ebe 100644
--- a/drivers/crypto/chelsio/chcr_crypto.h
+++ b/drivers/crypto/chelsio/chcr_crypto.h
@@ -170,7 +170,7 @@ static inline struct chcr_context *h_ctx(struct crypto_ahash *tfm)
}
struct ablk_ctx {
- struct crypto_skcipher *sw_cipher;
+ struct crypto_sync_skcipher *sw_cipher;
struct crypto_cipher *aes_generic;
__be32 key_ctx_hdr;
unsigned int enckey_len;
@@ -255,6 +255,8 @@ struct chcr_context {
struct chcr_dev *dev;
unsigned char tx_qidx;
unsigned char rx_qidx;
+ unsigned char tx_chan_id;
+ unsigned char pci_chan_id;
struct __crypto_ctx crypto_ctx[0];
};
diff --git a/drivers/crypto/chelsio/chtls/chtls_cm.c b/drivers/crypto/chelsio/chtls/chtls_cm.c
index 0997e166ea57..20209e29f814 100644
--- a/drivers/crypto/chelsio/chtls/chtls_cm.c
+++ b/drivers/crypto/chelsio/chtls/chtls_cm.c
@@ -234,8 +234,7 @@ static void chtls_send_reset(struct sock *sk, int mode, struct sk_buff *skb)
return;
out:
- if (skb)
- kfree_skb(skb);
+ kfree_skb(skb);
}
static void release_tcp_port(struct sock *sk)
@@ -406,12 +405,10 @@ static int wait_for_states(struct sock *sk, unsigned int states)
int chtls_disconnect(struct sock *sk, int flags)
{
- struct chtls_sock *csk;
struct tcp_sock *tp;
int err;
tp = tcp_sk(sk);
- csk = rcu_dereference_sk_user_data(sk);
chtls_purge_recv_queue(sk);
chtls_purge_receive_queue(sk);
chtls_purge_write_queue(sk);
@@ -1014,7 +1011,6 @@ static struct sock *chtls_recv_sock(struct sock *lsk,
const struct cpl_pass_accept_req *req,
struct chtls_dev *cdev)
{
- const struct tcphdr *tcph;
struct inet_sock *newinet;
const struct iphdr *iph;
struct net_device *ndev;
@@ -1036,7 +1032,6 @@ static struct sock *chtls_recv_sock(struct sock *lsk,
if (!dst)
goto free_sk;
- tcph = (struct tcphdr *)(iph + 1);
n = dst_neigh_lookup(dst, &iph->saddr);
if (!n)
goto free_sk;
diff --git a/drivers/crypto/chelsio/chtls/chtls_main.c b/drivers/crypto/chelsio/chtls/chtls_main.c
index f59b044ebd25..f472c51abe56 100644
--- a/drivers/crypto/chelsio/chtls/chtls_main.c
+++ b/drivers/crypto/chelsio/chtls/chtls_main.c
@@ -272,8 +272,7 @@ static void chtls_free_uld(struct chtls_dev *cdev)
for (i = 0; i < (1 << RSPQ_HASH_BITS); i++)
kfree_skb(cdev->rspq_skb_cache[i]);
kfree(cdev->lldi);
- if (cdev->askb)
- kfree_skb(cdev->askb);
+ kfree_skb(cdev->askb);
kfree(cdev);
}
diff --git a/drivers/crypto/hisilicon/sec/sec_algs.c b/drivers/crypto/hisilicon/sec/sec_algs.c
index f7d6d690116e..cdc4f9a171d9 100644
--- a/drivers/crypto/hisilicon/sec/sec_algs.c
+++ b/drivers/crypto/hisilicon/sec/sec_algs.c
@@ -732,6 +732,7 @@ static int sec_alg_skcipher_crypto(struct skcipher_request *skreq,
int *splits_in_nents;
int *splits_out_nents = NULL;
struct sec_request_el *el, *temp;
+ bool split = skreq->src != skreq->dst;
mutex_init(&sec_req->lock);
sec_req->req_base = &skreq->base;
@@ -750,7 +751,7 @@ static int sec_alg_skcipher_crypto(struct skcipher_request *skreq,
if (ret)
goto err_free_split_sizes;
- if (skreq->src != skreq->dst) {
+ if (split) {
sec_req->len_out = sg_nents(skreq->dst);
ret = sec_map_and_split_sg(skreq->dst, split_sizes, steps,
&splits_out, &splits_out_nents,
@@ -785,8 +786,9 @@ static int sec_alg_skcipher_crypto(struct skcipher_request *skreq,
split_sizes[i],
skreq->src != skreq->dst,
splits_in[i], splits_in_nents[i],
- splits_out[i],
- splits_out_nents[i], info);
+ split ? splits_out[i] : NULL,
+ split ? splits_out_nents[i] : 0,
+ info);
if (IS_ERR(el)) {
ret = PTR_ERR(el);
goto err_free_elements;
@@ -806,13 +808,6 @@ static int sec_alg_skcipher_crypto(struct skcipher_request *skreq,
* more refined but this is unlikely to happen so no need.
*/
- /* Cleanup - all elements in pointer arrays have been coppied */
- kfree(splits_in_nents);
- kfree(splits_in);
- kfree(splits_out_nents);
- kfree(splits_out);
- kfree(split_sizes);
-
/* Grab a big lock for a long time to avoid concurrency issues */
mutex_lock(&queue->queuelock);
@@ -827,13 +822,13 @@ static int sec_alg_skcipher_crypto(struct skcipher_request *skreq,
(!queue->havesoftqueue ||
kfifo_avail(&queue->softqueue) > steps)) ||
!list_empty(&ctx->backlog)) {
+ ret = -EBUSY;
if ((skreq->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) {
list_add_tail(&sec_req->backlog_head, &ctx->backlog);
mutex_unlock(&queue->queuelock);
- return -EBUSY;
+ goto out;
}
- ret = -EBUSY;
mutex_unlock(&queue->queuelock);
goto err_free_elements;
}
@@ -842,7 +837,15 @@ static int sec_alg_skcipher_crypto(struct skcipher_request *skreq,
if (ret)
goto err_free_elements;
- return -EINPROGRESS;
+ ret = -EINPROGRESS;
+out:
+ /* Cleanup - all elements in pointer arrays have been copied */
+ kfree(splits_in_nents);
+ kfree(splits_in);
+ kfree(splits_out_nents);
+ kfree(splits_out);
+ kfree(split_sizes);
+ return ret;
err_free_elements:
list_for_each_entry_safe(el, temp, &sec_req->elements, head) {
@@ -854,7 +857,7 @@ err_free_elements:
crypto_skcipher_ivsize(atfm),
DMA_BIDIRECTIONAL);
err_unmap_out_sg:
- if (skreq->src != skreq->dst)
+ if (split)
sec_unmap_sg_on_err(skreq->dst, steps, splits_out,
splits_out_nents, sec_req->len_out,
info->dev);
diff --git a/drivers/crypto/inside-secure/safexcel.c b/drivers/crypto/inside-secure/safexcel.c
index 7e71043457a6..86c699c14f84 100644
--- a/drivers/crypto/inside-secure/safexcel.c
+++ b/drivers/crypto/inside-secure/safexcel.c
@@ -1044,7 +1044,8 @@ static int safexcel_probe(struct platform_device *pdev)
safexcel_configure(priv);
- priv->ring = devm_kzalloc(dev, priv->config.rings * sizeof(*priv->ring),
+ priv->ring = devm_kcalloc(dev, priv->config.rings,
+ sizeof(*priv->ring),
GFP_KERNEL);
if (!priv->ring) {
ret = -ENOMEM;
@@ -1063,8 +1064,9 @@ static int safexcel_probe(struct platform_device *pdev)
if (ret)
goto err_reg_clk;
- priv->ring[i].rdr_req = devm_kzalloc(dev,
- sizeof(priv->ring[i].rdr_req) * EIP197_DEFAULT_RING_SIZE,
+ priv->ring[i].rdr_req = devm_kcalloc(dev,
+ EIP197_DEFAULT_RING_SIZE,
+ sizeof(priv->ring[i].rdr_req),
GFP_KERNEL);
if (!priv->ring[i].rdr_req) {
ret = -ENOMEM;
diff --git a/drivers/crypto/mxs-dcp.c b/drivers/crypto/mxs-dcp.c
index a10c418d4e5c..4e6ff32f8a7e 100644
--- a/drivers/crypto/mxs-dcp.c
+++ b/drivers/crypto/mxs-dcp.c
@@ -28,9 +28,24 @@
#define DCP_MAX_CHANS 4
#define DCP_BUF_SZ PAGE_SIZE
+#define DCP_SHA_PAY_SZ 64
#define DCP_ALIGNMENT 64
+/*
+ * Null hashes to align with hw behavior on imx6sl and ull
+ * these are flipped for consistency with hw output
+ */
+static const uint8_t sha1_null_hash[] =
+ "\x09\x07\xd8\xaf\x90\x18\x60\x95\xef\xbf"
+ "\x55\x32\x0d\x4b\x6b\x5e\xee\xa3\x39\xda";
+
+static const uint8_t sha256_null_hash[] =
+ "\x55\xb8\x52\x78\x1b\x99\x95\xa4"
+ "\x4c\x93\x9b\x64\xe4\x41\xae\x27"
+ "\x24\xb9\x6f\x99\xc8\xf4\xfb\x9a"
+ "\x14\x1c\xfc\x98\x42\xc4\xb0\xe3";
+
/* DCP DMA descriptor. */
struct dcp_dma_desc {
uint32_t next_cmd_addr;
@@ -48,6 +63,7 @@ struct dcp_coherent_block {
uint8_t aes_in_buf[DCP_BUF_SZ];
uint8_t aes_out_buf[DCP_BUF_SZ];
uint8_t sha_in_buf[DCP_BUF_SZ];
+ uint8_t sha_out_buf[DCP_SHA_PAY_SZ];
uint8_t aes_key[2 * AES_KEYSIZE_128];
@@ -63,7 +79,7 @@ struct dcp {
struct dcp_coherent_block *coh;
struct completion completion[DCP_MAX_CHANS];
- struct mutex mutex[DCP_MAX_CHANS];
+ spinlock_t lock[DCP_MAX_CHANS];
struct task_struct *thread[DCP_MAX_CHANS];
struct crypto_queue queue[DCP_MAX_CHANS];
};
@@ -84,7 +100,7 @@ struct dcp_async_ctx {
unsigned int hot:1;
/* Crypto-specific context */
- struct crypto_skcipher *fallback;
+ struct crypto_sync_skcipher *fallback;
unsigned int key_len;
uint8_t key[AES_KEYSIZE_128];
};
@@ -99,6 +115,11 @@ struct dcp_sha_req_ctx {
unsigned int fini:1;
};
+struct dcp_export_state {
+ struct dcp_sha_req_ctx req_ctx;
+ struct dcp_async_ctx async_ctx;
+};
+
/*
* There can even be only one instance of the MXS DCP due to the
* design of Linux Crypto API.
@@ -209,6 +230,12 @@ static int mxs_dcp_run_aes(struct dcp_async_ctx *actx,
dma_addr_t dst_phys = dma_map_single(sdcp->dev, sdcp->coh->aes_out_buf,
DCP_BUF_SZ, DMA_FROM_DEVICE);
+ if (actx->fill % AES_BLOCK_SIZE) {
+ dev_err(sdcp->dev, "Invalid block size!\n");
+ ret = -EINVAL;
+ goto aes_done_run;
+ }
+
/* Fill in the DMA descriptor. */
desc->control0 = MXS_DCP_CONTROL0_DECR_SEMAPHORE |
MXS_DCP_CONTROL0_INTERRUPT |
@@ -238,6 +265,7 @@ static int mxs_dcp_run_aes(struct dcp_async_ctx *actx,
ret = mxs_dcp_start_dma(actx);
+aes_done_run:
dma_unmap_single(sdcp->dev, key_phys, 2 * AES_KEYSIZE_128,
DMA_TO_DEVICE);
dma_unmap_single(sdcp->dev, src_phys, DCP_BUF_SZ, DMA_TO_DEVICE);
@@ -264,13 +292,15 @@ static int mxs_dcp_aes_block_crypt(struct crypto_async_request *arq)
uint8_t *out_tmp, *src_buf, *dst_buf = NULL;
uint32_t dst_off = 0;
+ uint32_t last_out_len = 0;
uint8_t *key = sdcp->coh->aes_key;
int ret = 0;
int split = 0;
- unsigned int i, len, clen, rem = 0;
+ unsigned int i, len, clen, rem = 0, tlen = 0;
int init = 0;
+ bool limit_hit = false;
actx->fill = 0;
@@ -289,6 +319,11 @@ static int mxs_dcp_aes_block_crypt(struct crypto_async_request *arq)
for_each_sg(req->src, src, nents, i) {
src_buf = sg_virt(src);
len = sg_dma_len(src);
+ tlen += len;
+ limit_hit = tlen > req->nbytes;
+
+ if (limit_hit)
+ len = req->nbytes - (tlen - len);
do {
if (actx->fill + len > out_off)
@@ -305,13 +340,15 @@ static int mxs_dcp_aes_block_crypt(struct crypto_async_request *arq)
* If we filled the buffer or this is the last SG,
* submit the buffer.
*/
- if (actx->fill == out_off || sg_is_last(src)) {
+ if (actx->fill == out_off || sg_is_last(src) ||
+ limit_hit) {
ret = mxs_dcp_run_aes(actx, req, init);
if (ret)
return ret;
init = 0;
out_tmp = out_buf;
+ last_out_len = actx->fill;
while (dst && actx->fill) {
if (!split) {
dst_buf = sg_virt(dst);
@@ -334,6 +371,19 @@ static int mxs_dcp_aes_block_crypt(struct crypto_async_request *arq)
}
}
} while (len);
+
+ if (limit_hit)
+ break;
+ }
+
+ /* Copy the IV for CBC for chaining */
+ if (!rctx->ecb) {
+ if (rctx->enc)
+ memcpy(req->info, out_buf+(last_out_len-AES_BLOCK_SIZE),
+ AES_BLOCK_SIZE);
+ else
+ memcpy(req->info, in_buf+(last_out_len-AES_BLOCK_SIZE),
+ AES_BLOCK_SIZE);
}
return ret;
@@ -349,13 +399,20 @@ static int dcp_chan_thread_aes(void *data)
int ret;
- do {
- __set_current_state(TASK_INTERRUPTIBLE);
+ while (!kthread_should_stop()) {
+ set_current_state(TASK_INTERRUPTIBLE);
- mutex_lock(&sdcp->mutex[chan]);
+ spin_lock(&sdcp->lock[chan]);
backlog = crypto_get_backlog(&sdcp->queue[chan]);
arq = crypto_dequeue_request(&sdcp->queue[chan]);
- mutex_unlock(&sdcp->mutex[chan]);
+ spin_unlock(&sdcp->lock[chan]);
+
+ if (!backlog && !arq) {
+ schedule();
+ continue;
+ }
+
+ set_current_state(TASK_RUNNING);
if (backlog)
backlog->complete(backlog, -EINPROGRESS);
@@ -363,11 +420,8 @@ static int dcp_chan_thread_aes(void *data)
if (arq) {
ret = mxs_dcp_aes_block_crypt(arq);
arq->complete(arq, ret);
- continue;
}
-
- schedule();
- } while (!kthread_should_stop());
+ }
return 0;
}
@@ -376,10 +430,10 @@ static int mxs_dcp_block_fallback(struct ablkcipher_request *req, int enc)
{
struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
struct dcp_async_ctx *ctx = crypto_ablkcipher_ctx(tfm);
- SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback);
int ret;
- skcipher_request_set_tfm(subreq, ctx->fallback);
+ skcipher_request_set_sync_tfm(subreq, ctx->fallback);
skcipher_request_set_callback(subreq, req->base.flags, NULL, NULL);
skcipher_request_set_crypt(subreq, req->src, req->dst,
req->nbytes, req->info);
@@ -409,9 +463,9 @@ static int mxs_dcp_aes_enqueue(struct ablkcipher_request *req, int enc, int ecb)
rctx->ecb = ecb;
actx->chan = DCP_CHAN_CRYPTO;
- mutex_lock(&sdcp->mutex[actx->chan]);
+ spin_lock(&sdcp->lock[actx->chan]);
ret = crypto_enqueue_request(&sdcp->queue[actx->chan], &req->base);
- mutex_unlock(&sdcp->mutex[actx->chan]);
+ spin_unlock(&sdcp->lock[actx->chan]);
wake_up_process(sdcp->thread[actx->chan]);
@@ -460,16 +514,16 @@ static int mxs_dcp_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
* but is supported by in-kernel software implementation, we use
* software fallback.
*/
- crypto_skcipher_clear_flags(actx->fallback, CRYPTO_TFM_REQ_MASK);
- crypto_skcipher_set_flags(actx->fallback,
+ crypto_sync_skcipher_clear_flags(actx->fallback, CRYPTO_TFM_REQ_MASK);
+ crypto_sync_skcipher_set_flags(actx->fallback,
tfm->base.crt_flags & CRYPTO_TFM_REQ_MASK);
- ret = crypto_skcipher_setkey(actx->fallback, key, len);
+ ret = crypto_sync_skcipher_setkey(actx->fallback, key, len);
if (!ret)
return 0;
tfm->base.crt_flags &= ~CRYPTO_TFM_RES_MASK;
- tfm->base.crt_flags |= crypto_skcipher_get_flags(actx->fallback) &
+ tfm->base.crt_flags |= crypto_sync_skcipher_get_flags(actx->fallback) &
CRYPTO_TFM_RES_MASK;
return ret;
@@ -478,11 +532,10 @@ static int mxs_dcp_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
static int mxs_dcp_aes_fallback_init(struct crypto_tfm *tfm)
{
const char *name = crypto_tfm_alg_name(tfm);
- const uint32_t flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK;
struct dcp_async_ctx *actx = crypto_tfm_ctx(tfm);
- struct crypto_skcipher *blk;
+ struct crypto_sync_skcipher *blk;
- blk = crypto_alloc_skcipher(name, 0, flags);
+ blk = crypto_alloc_sync_skcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK);
if (IS_ERR(blk))
return PTR_ERR(blk);
@@ -495,7 +548,7 @@ static void mxs_dcp_aes_fallback_exit(struct crypto_tfm *tfm)
{
struct dcp_async_ctx *actx = crypto_tfm_ctx(tfm);
- crypto_free_skcipher(actx->fallback);
+ crypto_free_sync_skcipher(actx->fallback);
}
/*
@@ -509,8 +562,6 @@ static int mxs_dcp_run_sha(struct ahash_request *req)
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
struct dcp_async_ctx *actx = crypto_ahash_ctx(tfm);
struct dcp_sha_req_ctx *rctx = ahash_request_ctx(req);
- struct hash_alg_common *halg = crypto_hash_alg_common(tfm);
-
struct dcp_dma_desc *desc = &sdcp->coh->desc[actx->chan];
dma_addr_t digest_phys = 0;
@@ -532,10 +583,23 @@ static int mxs_dcp_run_sha(struct ahash_request *req)
desc->payload = 0;
desc->status = 0;
+ /*
+ * Align driver with hw behavior when generating null hashes
+ */
+ if (rctx->init && rctx->fini && desc->size == 0) {
+ struct hash_alg_common *halg = crypto_hash_alg_common(tfm);
+ const uint8_t *sha_buf =
+ (actx->alg == MXS_DCP_CONTROL1_HASH_SELECT_SHA1) ?
+ sha1_null_hash : sha256_null_hash;
+ memcpy(sdcp->coh->sha_out_buf, sha_buf, halg->digestsize);
+ ret = 0;
+ goto done_run;
+ }
+
/* Set HASH_TERM bit for last transfer block. */
if (rctx->fini) {
- digest_phys = dma_map_single(sdcp->dev, req->result,
- halg->digestsize, DMA_FROM_DEVICE);
+ digest_phys = dma_map_single(sdcp->dev, sdcp->coh->sha_out_buf,
+ DCP_SHA_PAY_SZ, DMA_FROM_DEVICE);
desc->control0 |= MXS_DCP_CONTROL0_HASH_TERM;
desc->payload = digest_phys;
}
@@ -543,9 +607,10 @@ static int mxs_dcp_run_sha(struct ahash_request *req)
ret = mxs_dcp_start_dma(actx);
if (rctx->fini)
- dma_unmap_single(sdcp->dev, digest_phys, halg->digestsize,
+ dma_unmap_single(sdcp->dev, digest_phys, DCP_SHA_PAY_SZ,
DMA_FROM_DEVICE);
+done_run:
dma_unmap_single(sdcp->dev, buf_phys, DCP_BUF_SZ, DMA_TO_DEVICE);
return ret;
@@ -563,6 +628,7 @@ static int dcp_sha_req_to_buf(struct crypto_async_request *arq)
const int nents = sg_nents(req->src);
uint8_t *in_buf = sdcp->coh->sha_in_buf;
+ uint8_t *out_buf = sdcp->coh->sha_out_buf;
uint8_t *src_buf;
@@ -617,11 +683,9 @@ static int dcp_sha_req_to_buf(struct crypto_async_request *arq)
actx->fill = 0;
- /* For some reason, the result is flipped. */
- for (i = 0; i < halg->digestsize / 2; i++) {
- swap(req->result[i],
- req->result[halg->digestsize - i - 1]);
- }
+ /* For some reason the result is flipped */
+ for (i = 0; i < halg->digestsize; i++)
+ req->result[i] = out_buf[halg->digestsize - i - 1];
}
return 0;
@@ -640,13 +704,20 @@ static int dcp_chan_thread_sha(void *data)
struct ahash_request *req;
int ret, fini;
- do {
- __set_current_state(TASK_INTERRUPTIBLE);
+ while (!kthread_should_stop()) {
+ set_current_state(TASK_INTERRUPTIBLE);
- mutex_lock(&sdcp->mutex[chan]);
+ spin_lock(&sdcp->lock[chan]);
backlog = crypto_get_backlog(&sdcp->queue[chan]);
arq = crypto_dequeue_request(&sdcp->queue[chan]);
- mutex_unlock(&sdcp->mutex[chan]);
+ spin_unlock(&sdcp->lock[chan]);
+
+ if (!backlog && !arq) {
+ schedule();
+ continue;
+ }
+
+ set_current_state(TASK_RUNNING);
if (backlog)
backlog->complete(backlog, -EINPROGRESS);
@@ -658,12 +729,8 @@ static int dcp_chan_thread_sha(void *data)
ret = dcp_sha_req_to_buf(arq);
fini = rctx->fini;
arq->complete(arq, ret);
- if (!fini)
- continue;
}
-
- schedule();
- } while (!kthread_should_stop());
+ }
return 0;
}
@@ -721,9 +788,9 @@ static int dcp_sha_update_fx(struct ahash_request *req, int fini)
rctx->init = 1;
}
- mutex_lock(&sdcp->mutex[actx->chan]);
+ spin_lock(&sdcp->lock[actx->chan]);
ret = crypto_enqueue_request(&sdcp->queue[actx->chan], &req->base);
- mutex_unlock(&sdcp->mutex[actx->chan]);
+ spin_unlock(&sdcp->lock[actx->chan]);
wake_up_process(sdcp->thread[actx->chan]);
mutex_unlock(&actx->mutex);
@@ -759,14 +826,32 @@ static int dcp_sha_digest(struct ahash_request *req)
return dcp_sha_finup(req);
}
-static int dcp_sha_noimport(struct ahash_request *req, const void *in)
+static int dcp_sha_import(struct ahash_request *req, const void *in)
{
- return -ENOSYS;
+ struct dcp_sha_req_ctx *rctx = ahash_request_ctx(req);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct dcp_async_ctx *actx = crypto_ahash_ctx(tfm);
+ const struct dcp_export_state *export = in;
+
+ memset(rctx, 0, sizeof(struct dcp_sha_req_ctx));
+ memset(actx, 0, sizeof(struct dcp_async_ctx));
+ memcpy(rctx, &export->req_ctx, sizeof(struct dcp_sha_req_ctx));
+ memcpy(actx, &export->async_ctx, sizeof(struct dcp_async_ctx));
+
+ return 0;
}
-static int dcp_sha_noexport(struct ahash_request *req, void *out)
+static int dcp_sha_export(struct ahash_request *req, void *out)
{
- return -ENOSYS;
+ struct dcp_sha_req_ctx *rctx_state = ahash_request_ctx(req);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct dcp_async_ctx *actx_state = crypto_ahash_ctx(tfm);
+ struct dcp_export_state *export = out;
+
+ memcpy(&export->req_ctx, rctx_state, sizeof(struct dcp_sha_req_ctx));
+ memcpy(&export->async_ctx, actx_state, sizeof(struct dcp_async_ctx));
+
+ return 0;
}
static int dcp_sha_cra_init(struct crypto_tfm *tfm)
@@ -839,10 +924,11 @@ static struct ahash_alg dcp_sha1_alg = {
.final = dcp_sha_final,
.finup = dcp_sha_finup,
.digest = dcp_sha_digest,
- .import = dcp_sha_noimport,
- .export = dcp_sha_noexport,
+ .import = dcp_sha_import,
+ .export = dcp_sha_export,
.halg = {
.digestsize = SHA1_DIGEST_SIZE,
+ .statesize = sizeof(struct dcp_export_state),
.base = {
.cra_name = "sha1",
.cra_driver_name = "sha1-dcp",
@@ -865,10 +951,11 @@ static struct ahash_alg dcp_sha256_alg = {
.final = dcp_sha_final,
.finup = dcp_sha_finup,
.digest = dcp_sha_digest,
- .import = dcp_sha_noimport,
- .export = dcp_sha_noexport,
+ .import = dcp_sha_import,
+ .export = dcp_sha_export,
.halg = {
.digestsize = SHA256_DIGEST_SIZE,
+ .statesize = sizeof(struct dcp_export_state),
.base = {
.cra_name = "sha256",
.cra_driver_name = "sha256-dcp",
@@ -997,7 +1084,7 @@ static int mxs_dcp_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, sdcp);
for (i = 0; i < DCP_MAX_CHANS; i++) {
- mutex_init(&sdcp->mutex[i]);
+ spin_lock_init(&sdcp->lock[i]);
init_completion(&sdcp->completion[i]);
crypto_init_queue(&sdcp->queue[i], 50);
}
diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c
index 9019f6b67986..a553ffddb11b 100644
--- a/drivers/crypto/omap-aes.c
+++ b/drivers/crypto/omap-aes.c
@@ -522,9 +522,9 @@ static int omap_aes_crypt(struct ablkcipher_request *req, unsigned long mode)
!!(mode & FLAGS_CBC));
if (req->nbytes < aes_fallback_sz) {
- SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback);
- skcipher_request_set_tfm(subreq, ctx->fallback);
+ skcipher_request_set_sync_tfm(subreq, ctx->fallback);
skcipher_request_set_callback(subreq, req->base.flags, NULL,
NULL);
skcipher_request_set_crypt(subreq, req->src, req->dst,
@@ -564,11 +564,11 @@ static int omap_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
memcpy(ctx->key, key, keylen);
ctx->keylen = keylen;
- crypto_skcipher_clear_flags(ctx->fallback, CRYPTO_TFM_REQ_MASK);
- crypto_skcipher_set_flags(ctx->fallback, tfm->base.crt_flags &
+ crypto_sync_skcipher_clear_flags(ctx->fallback, CRYPTO_TFM_REQ_MASK);
+ crypto_sync_skcipher_set_flags(ctx->fallback, tfm->base.crt_flags &
CRYPTO_TFM_REQ_MASK);
- ret = crypto_skcipher_setkey(ctx->fallback, key, keylen);
+ ret = crypto_sync_skcipher_setkey(ctx->fallback, key, keylen);
if (!ret)
return 0;
@@ -613,11 +613,10 @@ static int omap_aes_crypt_req(struct crypto_engine *engine,
static int omap_aes_cra_init(struct crypto_tfm *tfm)
{
const char *name = crypto_tfm_alg_name(tfm);
- const u32 flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK;
struct omap_aes_ctx *ctx = crypto_tfm_ctx(tfm);
- struct crypto_skcipher *blk;
+ struct crypto_sync_skcipher *blk;
- blk = crypto_alloc_skcipher(name, 0, flags);
+ blk = crypto_alloc_sync_skcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK);
if (IS_ERR(blk))
return PTR_ERR(blk);
@@ -667,7 +666,7 @@ static void omap_aes_cra_exit(struct crypto_tfm *tfm)
struct omap_aes_ctx *ctx = crypto_tfm_ctx(tfm);
if (ctx->fallback)
- crypto_free_skcipher(ctx->fallback);
+ crypto_free_sync_skcipher(ctx->fallback);
ctx->fallback = NULL;
}
diff --git a/drivers/crypto/omap-aes.h b/drivers/crypto/omap-aes.h
index fc3b46a85809..7e02920ef6f8 100644
--- a/drivers/crypto/omap-aes.h
+++ b/drivers/crypto/omap-aes.h
@@ -101,7 +101,7 @@ struct omap_aes_ctx {
int keylen;
u32 key[AES_KEYSIZE_256 / sizeof(u32)];
u8 nonce[4];
- struct crypto_skcipher *fallback;
+ struct crypto_sync_skcipher *fallback;
struct crypto_skcipher *ctr;
};
diff --git a/drivers/crypto/picoxcell_crypto.c b/drivers/crypto/picoxcell_crypto.c
index 321d5e2ac833..a28f1d18fe01 100644
--- a/drivers/crypto/picoxcell_crypto.c
+++ b/drivers/crypto/picoxcell_crypto.c
@@ -171,7 +171,7 @@ struct spacc_ablk_ctx {
* The fallback cipher. If the operation can't be done in hardware,
* fallback to a software version.
*/
- struct crypto_skcipher *sw_cipher;
+ struct crypto_sync_skcipher *sw_cipher;
};
/* AEAD cipher context. */
@@ -799,17 +799,17 @@ static int spacc_aes_setkey(struct crypto_ablkcipher *cipher, const u8 *key,
* Set the fallback transform to use the same request flags as
* the hardware transform.
*/
- crypto_skcipher_clear_flags(ctx->sw_cipher,
+ crypto_sync_skcipher_clear_flags(ctx->sw_cipher,
CRYPTO_TFM_REQ_MASK);
- crypto_skcipher_set_flags(ctx->sw_cipher,
+ crypto_sync_skcipher_set_flags(ctx->sw_cipher,
cipher->base.crt_flags &
CRYPTO_TFM_REQ_MASK);
- err = crypto_skcipher_setkey(ctx->sw_cipher, key, len);
+ err = crypto_sync_skcipher_setkey(ctx->sw_cipher, key, len);
tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK;
tfm->crt_flags |=
- crypto_skcipher_get_flags(ctx->sw_cipher) &
+ crypto_sync_skcipher_get_flags(ctx->sw_cipher) &
CRYPTO_TFM_RES_MASK;
if (err)
@@ -914,7 +914,7 @@ static int spacc_ablk_do_fallback(struct ablkcipher_request *req,
struct crypto_tfm *old_tfm =
crypto_ablkcipher_tfm(crypto_ablkcipher_reqtfm(req));
struct spacc_ablk_ctx *ctx = crypto_tfm_ctx(old_tfm);
- SKCIPHER_REQUEST_ON_STACK(subreq, ctx->sw_cipher);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, ctx->sw_cipher);
int err;
/*
@@ -922,7 +922,7 @@ static int spacc_ablk_do_fallback(struct ablkcipher_request *req,
* the ciphering has completed, put the old transform back into the
* request.
*/
- skcipher_request_set_tfm(subreq, ctx->sw_cipher);
+ skcipher_request_set_sync_tfm(subreq, ctx->sw_cipher);
skcipher_request_set_callback(subreq, req->base.flags, NULL, NULL);
skcipher_request_set_crypt(subreq, req->src, req->dst,
req->nbytes, req->info);
@@ -1020,9 +1020,8 @@ static int spacc_ablk_cra_init(struct crypto_tfm *tfm)
ctx->generic.flags = spacc_alg->type;
ctx->generic.engine = engine;
if (alg->cra_flags & CRYPTO_ALG_NEED_FALLBACK) {
- ctx->sw_cipher = crypto_alloc_skcipher(
- alg->cra_name, 0, CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_NEED_FALLBACK);
+ ctx->sw_cipher = crypto_alloc_sync_skcipher(
+ alg->cra_name, 0, CRYPTO_ALG_NEED_FALLBACK);
if (IS_ERR(ctx->sw_cipher)) {
dev_warn(engine->dev, "failed to allocate fallback for %s\n",
alg->cra_name);
@@ -1041,7 +1040,7 @@ static void spacc_ablk_cra_exit(struct crypto_tfm *tfm)
{
struct spacc_ablk_ctx *ctx = crypto_tfm_ctx(tfm);
- crypto_free_skcipher(ctx->sw_cipher);
+ crypto_free_sync_skcipher(ctx->sw_cipher);
}
static int spacc_ablk_encrypt(struct ablkcipher_request *req)
diff --git a/drivers/crypto/qat/qat_c3xxx/adf_drv.c b/drivers/crypto/qat/qat_c3xxx/adf_drv.c
index ba197f34c252..763c2166ee0e 100644
--- a/drivers/crypto/qat/qat_c3xxx/adf_drv.c
+++ b/drivers/crypto/qat/qat_c3xxx/adf_drv.c
@@ -123,7 +123,8 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
struct adf_hw_device_data *hw_data;
char name[ADF_DEVICE_NAME_LENGTH];
unsigned int i, bar_nr;
- int ret, bar_mask;
+ unsigned long bar_mask;
+ int ret;
switch (ent->device) {
case ADF_C3XXX_PCI_DEVICE_ID:
@@ -235,8 +236,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Find and map all the device's BARS */
i = 0;
bar_mask = pci_select_bars(pdev, IORESOURCE_MEM);
- for_each_set_bit(bar_nr, (const unsigned long *)&bar_mask,
- ADF_PCI_MAX_BARS * 2) {
+ for_each_set_bit(bar_nr, &bar_mask, ADF_PCI_MAX_BARS * 2) {
struct adf_bar *bar = &accel_pci_dev->pci_bars[i++];
bar->base_addr = pci_resource_start(pdev, bar_nr);
diff --git a/drivers/crypto/qat/qat_c3xxxvf/adf_drv.c b/drivers/crypto/qat/qat_c3xxxvf/adf_drv.c
index 24ec908eb26c..613c7d5644ce 100644
--- a/drivers/crypto/qat/qat_c3xxxvf/adf_drv.c
+++ b/drivers/crypto/qat/qat_c3xxxvf/adf_drv.c
@@ -125,7 +125,8 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
struct adf_hw_device_data *hw_data;
char name[ADF_DEVICE_NAME_LENGTH];
unsigned int i, bar_nr;
- int ret, bar_mask;
+ unsigned long bar_mask;
+ int ret;
switch (ent->device) {
case ADF_C3XXXIOV_PCI_DEVICE_ID:
@@ -215,8 +216,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Find and map all the device's BARS */
i = 0;
bar_mask = pci_select_bars(pdev, IORESOURCE_MEM);
- for_each_set_bit(bar_nr, (const unsigned long *)&bar_mask,
- ADF_PCI_MAX_BARS * 2) {
+ for_each_set_bit(bar_nr, &bar_mask, ADF_PCI_MAX_BARS * 2) {
struct adf_bar *bar = &accel_pci_dev->pci_bars[i++];
bar->base_addr = pci_resource_start(pdev, bar_nr);
diff --git a/drivers/crypto/qat/qat_c62x/adf_drv.c b/drivers/crypto/qat/qat_c62x/adf_drv.c
index 59a5a0df50b6..9cb832963357 100644
--- a/drivers/crypto/qat/qat_c62x/adf_drv.c
+++ b/drivers/crypto/qat/qat_c62x/adf_drv.c
@@ -123,7 +123,8 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
struct adf_hw_device_data *hw_data;
char name[ADF_DEVICE_NAME_LENGTH];
unsigned int i, bar_nr;
- int ret, bar_mask;
+ unsigned long bar_mask;
+ int ret;
switch (ent->device) {
case ADF_C62X_PCI_DEVICE_ID:
@@ -235,8 +236,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Find and map all the device's BARS */
i = (hw_data->fuses & ADF_DEVICE_FUSECTL_MASK) ? 1 : 0;
bar_mask = pci_select_bars(pdev, IORESOURCE_MEM);
- for_each_set_bit(bar_nr, (const unsigned long *)&bar_mask,
- ADF_PCI_MAX_BARS * 2) {
+ for_each_set_bit(bar_nr, &bar_mask, ADF_PCI_MAX_BARS * 2) {
struct adf_bar *bar = &accel_pci_dev->pci_bars[i++];
bar->base_addr = pci_resource_start(pdev, bar_nr);
diff --git a/drivers/crypto/qat/qat_c62xvf/adf_drv.c b/drivers/crypto/qat/qat_c62xvf/adf_drv.c
index b9f3e0e4fde9..278452b8ef81 100644
--- a/drivers/crypto/qat/qat_c62xvf/adf_drv.c
+++ b/drivers/crypto/qat/qat_c62xvf/adf_drv.c
@@ -125,7 +125,8 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
struct adf_hw_device_data *hw_data;
char name[ADF_DEVICE_NAME_LENGTH];
unsigned int i, bar_nr;
- int ret, bar_mask;
+ unsigned long bar_mask;
+ int ret;
switch (ent->device) {
case ADF_C62XIOV_PCI_DEVICE_ID:
@@ -215,8 +216,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Find and map all the device's BARS */
i = 0;
bar_mask = pci_select_bars(pdev, IORESOURCE_MEM);
- for_each_set_bit(bar_nr, (const unsigned long *)&bar_mask,
- ADF_PCI_MAX_BARS * 2) {
+ for_each_set_bit(bar_nr, &bar_mask, ADF_PCI_MAX_BARS * 2) {
struct adf_bar *bar = &accel_pci_dev->pci_bars[i++];
bar->base_addr = pci_resource_start(pdev, bar_nr);
diff --git a/drivers/crypto/qat/qat_common/adf_aer.c b/drivers/crypto/qat/qat_common/adf_aer.c
index 9225d060e18f..f5e960d23a7a 100644
--- a/drivers/crypto/qat/qat_common/adf_aer.c
+++ b/drivers/crypto/qat/qat_common/adf_aer.c
@@ -198,7 +198,6 @@ static pci_ers_result_t adf_slot_reset(struct pci_dev *pdev)
pr_err("QAT: Can't find acceleration device\n");
return PCI_ERS_RESULT_DISCONNECT;
}
- pci_cleanup_aer_uncorrect_error_status(pdev);
if (adf_dev_aer_schedule_reset(accel_dev, ADF_DEV_RESET_SYNC))
return PCI_ERS_RESULT_DISCONNECT;
diff --git a/drivers/crypto/qat/qat_common/qat_algs.c b/drivers/crypto/qat/qat_common/qat_algs.c
index 1138e41d6805..d2698299896f 100644
--- a/drivers/crypto/qat/qat_common/qat_algs.c
+++ b/drivers/crypto/qat/qat_common/qat_algs.c
@@ -113,6 +113,13 @@ struct qat_alg_aead_ctx {
struct crypto_shash *hash_tfm;
enum icp_qat_hw_auth_algo qat_hash_alg;
struct qat_crypto_instance *inst;
+ union {
+ struct sha1_state sha1;
+ struct sha256_state sha256;
+ struct sha512_state sha512;
+ };
+ char ipad[SHA512_BLOCK_SIZE]; /* sufficient for SHA-1/SHA-256 as well */
+ char opad[SHA512_BLOCK_SIZE];
};
struct qat_alg_ablkcipher_ctx {
@@ -148,37 +155,32 @@ static int qat_alg_do_precomputes(struct icp_qat_hw_auth_algo_blk *hash,
unsigned int auth_keylen)
{
SHASH_DESC_ON_STACK(shash, ctx->hash_tfm);
- struct sha1_state sha1;
- struct sha256_state sha256;
- struct sha512_state sha512;
int block_size = crypto_shash_blocksize(ctx->hash_tfm);
int digest_size = crypto_shash_digestsize(ctx->hash_tfm);
- char ipad[block_size];
- char opad[block_size];
__be32 *hash_state_out;
__be64 *hash512_state_out;
int i, offset;
- memset(ipad, 0, block_size);
- memset(opad, 0, block_size);
+ memset(ctx->ipad, 0, block_size);
+ memset(ctx->opad, 0, block_size);
shash->tfm = ctx->hash_tfm;
shash->flags = 0x0;
if (auth_keylen > block_size) {
int ret = crypto_shash_digest(shash, auth_key,
- auth_keylen, ipad);
+ auth_keylen, ctx->ipad);
if (ret)
return ret;
- memcpy(opad, ipad, digest_size);
+ memcpy(ctx->opad, ctx->ipad, digest_size);
} else {
- memcpy(ipad, auth_key, auth_keylen);
- memcpy(opad, auth_key, auth_keylen);
+ memcpy(ctx->ipad, auth_key, auth_keylen);
+ memcpy(ctx->opad, auth_key, auth_keylen);
}
for (i = 0; i < block_size; i++) {
- char *ipad_ptr = ipad + i;
- char *opad_ptr = opad + i;
+ char *ipad_ptr = ctx->ipad + i;
+ char *opad_ptr = ctx->opad + i;
*ipad_ptr ^= HMAC_IPAD_VALUE;
*opad_ptr ^= HMAC_OPAD_VALUE;
}
@@ -186,7 +188,7 @@ static int qat_alg_do_precomputes(struct icp_qat_hw_auth_algo_blk *hash,
if (crypto_shash_init(shash))
return -EFAULT;
- if (crypto_shash_update(shash, ipad, block_size))
+ if (crypto_shash_update(shash, ctx->ipad, block_size))
return -EFAULT;
hash_state_out = (__be32 *)hash->sha.state1;
@@ -194,22 +196,22 @@ static int qat_alg_do_precomputes(struct icp_qat_hw_auth_algo_blk *hash,
switch (ctx->qat_hash_alg) {
case ICP_QAT_HW_AUTH_ALGO_SHA1:
- if (crypto_shash_export(shash, &sha1))
+ if (crypto_shash_export(shash, &ctx->sha1))
return -EFAULT;
for (i = 0; i < digest_size >> 2; i++, hash_state_out++)
- *hash_state_out = cpu_to_be32(*(sha1.state + i));
+ *hash_state_out = cpu_to_be32(ctx->sha1.state[i]);
break;
case ICP_QAT_HW_AUTH_ALGO_SHA256:
- if (crypto_shash_export(shash, &sha256))
+ if (crypto_shash_export(shash, &ctx->sha256))
return -EFAULT;
for (i = 0; i < digest_size >> 2; i++, hash_state_out++)
- *hash_state_out = cpu_to_be32(*(sha256.state + i));
+ *hash_state_out = cpu_to_be32(ctx->sha256.state[i]);
break;
case ICP_QAT_HW_AUTH_ALGO_SHA512:
- if (crypto_shash_export(shash, &sha512))
+ if (crypto_shash_export(shash, &ctx->sha512))
return -EFAULT;
for (i = 0; i < digest_size >> 3; i++, hash512_state_out++)
- *hash512_state_out = cpu_to_be64(*(sha512.state + i));
+ *hash512_state_out = cpu_to_be64(ctx->sha512.state[i]);
break;
default:
return -EFAULT;
@@ -218,7 +220,7 @@ static int qat_alg_do_precomputes(struct icp_qat_hw_auth_algo_blk *hash,
if (crypto_shash_init(shash))
return -EFAULT;
- if (crypto_shash_update(shash, opad, block_size))
+ if (crypto_shash_update(shash, ctx->opad, block_size))
return -EFAULT;
offset = round_up(qat_get_inter_state_size(ctx->qat_hash_alg), 8);
@@ -227,28 +229,28 @@ static int qat_alg_do_precomputes(struct icp_qat_hw_auth_algo_blk *hash,
switch (ctx->qat_hash_alg) {
case ICP_QAT_HW_AUTH_ALGO_SHA1:
- if (crypto_shash_export(shash, &sha1))
+ if (crypto_shash_export(shash, &ctx->sha1))
return -EFAULT;
for (i = 0; i < digest_size >> 2; i++, hash_state_out++)
- *hash_state_out = cpu_to_be32(*(sha1.state + i));
+ *hash_state_out = cpu_to_be32(ctx->sha1.state[i]);
break;
case ICP_QAT_HW_AUTH_ALGO_SHA256:
- if (crypto_shash_export(shash, &sha256))
+ if (crypto_shash_export(shash, &ctx->sha256))
return -EFAULT;
for (i = 0; i < digest_size >> 2; i++, hash_state_out++)
- *hash_state_out = cpu_to_be32(*(sha256.state + i));
+ *hash_state_out = cpu_to_be32(ctx->sha256.state[i]);
break;
case ICP_QAT_HW_AUTH_ALGO_SHA512:
- if (crypto_shash_export(shash, &sha512))
+ if (crypto_shash_export(shash, &ctx->sha512))
return -EFAULT;
for (i = 0; i < digest_size >> 3; i++, hash512_state_out++)
- *hash512_state_out = cpu_to_be64(*(sha512.state + i));
+ *hash512_state_out = cpu_to_be64(ctx->sha512.state[i]);
break;
default:
return -EFAULT;
}
- memzero_explicit(ipad, block_size);
- memzero_explicit(opad, block_size);
+ memzero_explicit(ctx->ipad, block_size);
+ memzero_explicit(ctx->opad, block_size);
return 0;
}
diff --git a/drivers/crypto/qat/qat_dh895xcc/adf_drv.c b/drivers/crypto/qat/qat_dh895xcc/adf_drv.c
index be5c5a988ca5..3a9708ef4ce2 100644
--- a/drivers/crypto/qat/qat_dh895xcc/adf_drv.c
+++ b/drivers/crypto/qat/qat_dh895xcc/adf_drv.c
@@ -123,7 +123,8 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
struct adf_hw_device_data *hw_data;
char name[ADF_DEVICE_NAME_LENGTH];
unsigned int i, bar_nr;
- int ret, bar_mask;
+ unsigned long bar_mask;
+ int ret;
switch (ent->device) {
case ADF_DH895XCC_PCI_DEVICE_ID:
@@ -237,8 +238,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Find and map all the device's BARS */
i = 0;
bar_mask = pci_select_bars(pdev, IORESOURCE_MEM);
- for_each_set_bit(bar_nr, (const unsigned long *)&bar_mask,
- ADF_PCI_MAX_BARS * 2) {
+ for_each_set_bit(bar_nr, &bar_mask, ADF_PCI_MAX_BARS * 2) {
struct adf_bar *bar = &accel_pci_dev->pci_bars[i++];
bar->base_addr = pci_resource_start(pdev, bar_nr);
diff --git a/drivers/crypto/qat/qat_dh895xccvf/adf_drv.c b/drivers/crypto/qat/qat_dh895xccvf/adf_drv.c
index 26ab17bfc6da..3da0f951cb59 100644
--- a/drivers/crypto/qat/qat_dh895xccvf/adf_drv.c
+++ b/drivers/crypto/qat/qat_dh895xccvf/adf_drv.c
@@ -125,7 +125,8 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
struct adf_hw_device_data *hw_data;
char name[ADF_DEVICE_NAME_LENGTH];
unsigned int i, bar_nr;
- int ret, bar_mask;
+ unsigned long bar_mask;
+ int ret;
switch (ent->device) {
case ADF_DH895XCCIOV_PCI_DEVICE_ID:
@@ -215,8 +216,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Find and map all the device's BARS */
i = 0;
bar_mask = pci_select_bars(pdev, IORESOURCE_MEM);
- for_each_set_bit(bar_nr, (const unsigned long *)&bar_mask,
- ADF_PCI_MAX_BARS * 2) {
+ for_each_set_bit(bar_nr, &bar_mask, ADF_PCI_MAX_BARS * 2) {
struct adf_bar *bar = &accel_pci_dev->pci_bars[i++];
bar->base_addr = pci_resource_start(pdev, bar_nr);
diff --git a/drivers/crypto/qce/ablkcipher.c b/drivers/crypto/qce/ablkcipher.c
index ea4d96bf47e8..585e1cab9ae3 100644
--- a/drivers/crypto/qce/ablkcipher.c
+++ b/drivers/crypto/qce/ablkcipher.c
@@ -189,7 +189,7 @@ static int qce_ablkcipher_setkey(struct crypto_ablkcipher *ablk, const u8 *key,
memcpy(ctx->enc_key, key, keylen);
return 0;
fallback:
- ret = crypto_skcipher_setkey(ctx->fallback, key, keylen);
+ ret = crypto_sync_skcipher_setkey(ctx->fallback, key, keylen);
if (!ret)
ctx->enc_keylen = keylen;
return ret;
@@ -212,9 +212,9 @@ static int qce_ablkcipher_crypt(struct ablkcipher_request *req, int encrypt)
if (IS_AES(rctx->flags) && ctx->enc_keylen != AES_KEYSIZE_128 &&
ctx->enc_keylen != AES_KEYSIZE_256) {
- SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback);
- skcipher_request_set_tfm(subreq, ctx->fallback);
+ skcipher_request_set_sync_tfm(subreq, ctx->fallback);
skcipher_request_set_callback(subreq, req->base.flags,
NULL, NULL);
skcipher_request_set_crypt(subreq, req->src, req->dst,
@@ -245,9 +245,8 @@ static int qce_ablkcipher_init(struct crypto_tfm *tfm)
memset(ctx, 0, sizeof(*ctx));
tfm->crt_ablkcipher.reqsize = sizeof(struct qce_cipher_reqctx);
- ctx->fallback = crypto_alloc_skcipher(crypto_tfm_alg_name(tfm), 0,
- CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_NEED_FALLBACK);
+ ctx->fallback = crypto_alloc_sync_skcipher(crypto_tfm_alg_name(tfm),
+ 0, CRYPTO_ALG_NEED_FALLBACK);
return PTR_ERR_OR_ZERO(ctx->fallback);
}
@@ -255,7 +254,7 @@ static void qce_ablkcipher_exit(struct crypto_tfm *tfm)
{
struct qce_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
- crypto_free_skcipher(ctx->fallback);
+ crypto_free_sync_skcipher(ctx->fallback);
}
struct qce_ablkcipher_def {
diff --git a/drivers/crypto/qce/cipher.h b/drivers/crypto/qce/cipher.h
index 2b0278bb6e92..ee055bfe98a0 100644
--- a/drivers/crypto/qce/cipher.h
+++ b/drivers/crypto/qce/cipher.h
@@ -22,7 +22,7 @@
struct qce_cipher_ctx {
u8 enc_key[QCE_MAX_KEY_SIZE];
unsigned int enc_keylen;
- struct crypto_skcipher *fallback;
+ struct crypto_sync_skcipher *fallback;
};
/**
diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c
index faa282074e5a..0064be0e3941 100644
--- a/drivers/crypto/s5p-sss.c
+++ b/drivers/crypto/s5p-sss.c
@@ -249,8 +249,8 @@ struct s5p_aes_reqctx {
struct s5p_aes_ctx {
struct s5p_aes_dev *dev;
- uint8_t aes_key[AES_MAX_KEY_SIZE];
- uint8_t nonce[CTR_RFC3686_NONCE_SIZE];
+ u8 aes_key[AES_MAX_KEY_SIZE];
+ u8 nonce[CTR_RFC3686_NONCE_SIZE];
int keylen;
};
@@ -475,9 +475,9 @@ static void s5p_sg_done(struct s5p_aes_dev *dev)
}
/* Calls the completion. Cannot be called with dev->lock hold. */
-static void s5p_aes_complete(struct s5p_aes_dev *dev, int err)
+static void s5p_aes_complete(struct ablkcipher_request *req, int err)
{
- dev->req->base.complete(&dev->req->base, err);
+ req->base.complete(&req->base, err);
}
static void s5p_unset_outdata(struct s5p_aes_dev *dev)
@@ -491,7 +491,7 @@ static void s5p_unset_indata(struct s5p_aes_dev *dev)
}
static int s5p_make_sg_cpy(struct s5p_aes_dev *dev, struct scatterlist *src,
- struct scatterlist **dst)
+ struct scatterlist **dst)
{
void *pages;
int len;
@@ -518,46 +518,28 @@ static int s5p_make_sg_cpy(struct s5p_aes_dev *dev, struct scatterlist *src,
static int s5p_set_outdata(struct s5p_aes_dev *dev, struct scatterlist *sg)
{
- int err;
-
- if (!sg->length) {
- err = -EINVAL;
- goto exit;
- }
+ if (!sg->length)
+ return -EINVAL;
- err = dma_map_sg(dev->dev, sg, 1, DMA_FROM_DEVICE);
- if (!err) {
- err = -ENOMEM;
- goto exit;
- }
+ if (!dma_map_sg(dev->dev, sg, 1, DMA_FROM_DEVICE))
+ return -ENOMEM;
dev->sg_dst = sg;
- err = 0;
-exit:
- return err;
+ return 0;
}
static int s5p_set_indata(struct s5p_aes_dev *dev, struct scatterlist *sg)
{
- int err;
-
- if (!sg->length) {
- err = -EINVAL;
- goto exit;
- }
+ if (!sg->length)
+ return -EINVAL;
- err = dma_map_sg(dev->dev, sg, 1, DMA_TO_DEVICE);
- if (!err) {
- err = -ENOMEM;
- goto exit;
- }
+ if (!dma_map_sg(dev->dev, sg, 1, DMA_TO_DEVICE))
+ return -ENOMEM;
dev->sg_src = sg;
- err = 0;
-exit:
- return err;
+ return 0;
}
/*
@@ -655,14 +637,14 @@ static irqreturn_t s5p_aes_interrupt(int irq, void *dev_id)
{
struct platform_device *pdev = dev_id;
struct s5p_aes_dev *dev = platform_get_drvdata(pdev);
+ struct ablkcipher_request *req;
int err_dma_tx = 0;
int err_dma_rx = 0;
int err_dma_hx = 0;
bool tx_end = false;
bool hx_end = false;
unsigned long flags;
- uint32_t status;
- u32 st_bits;
+ u32 status, st_bits;
int err;
spin_lock_irqsave(&dev->lock, flags);
@@ -727,7 +709,7 @@ static irqreturn_t s5p_aes_interrupt(int irq, void *dev_id)
spin_unlock_irqrestore(&dev->lock, flags);
- s5p_aes_complete(dev, 0);
+ s5p_aes_complete(dev->req, 0);
/* Device is still busy */
tasklet_schedule(&dev->tasklet);
} else {
@@ -752,11 +734,12 @@ static irqreturn_t s5p_aes_interrupt(int irq, void *dev_id)
error:
s5p_sg_done(dev);
dev->busy = false;
+ req = dev->req;
if (err_dma_hx == 1)
s5p_set_dma_hashdata(dev, dev->hash_sg_iter);
spin_unlock_irqrestore(&dev->lock, flags);
- s5p_aes_complete(dev, err);
+ s5p_aes_complete(req, err);
hash_irq_end:
/*
@@ -1830,7 +1813,7 @@ static struct ahash_alg algs_sha1_md5_sha256[] = {
};
static void s5p_set_aes(struct s5p_aes_dev *dev,
- const uint8_t *key, const uint8_t *iv,
+ const u8 *key, const u8 *iv, const u8 *ctr,
unsigned int keylen)
{
void __iomem *keystart;
@@ -1838,6 +1821,9 @@ static void s5p_set_aes(struct s5p_aes_dev *dev,
if (iv)
memcpy_toio(dev->aes_ioaddr + SSS_REG_AES_IV_DATA(0), iv, 0x10);
+ if (ctr)
+ memcpy_toio(dev->aes_ioaddr + SSS_REG_AES_CNT_DATA(0), ctr, 0x10);
+
if (keylen == AES_KEYSIZE_256)
keystart = dev->aes_ioaddr + SSS_REG_AES_KEY_DATA(0);
else if (keylen == AES_KEYSIZE_192)
@@ -1887,7 +1873,7 @@ static int s5p_set_indata_start(struct s5p_aes_dev *dev,
}
static int s5p_set_outdata_start(struct s5p_aes_dev *dev,
- struct ablkcipher_request *req)
+ struct ablkcipher_request *req)
{
struct scatterlist *sg;
int err;
@@ -1916,11 +1902,12 @@ static int s5p_set_outdata_start(struct s5p_aes_dev *dev,
static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode)
{
struct ablkcipher_request *req = dev->req;
- uint32_t aes_control;
+ u32 aes_control;
unsigned long flags;
int err;
- u8 *iv;
+ u8 *iv, *ctr;
+ /* This sets bit [13:12] to 00, which selects 128-bit counter */
aes_control = SSS_AES_KEY_CHANGE_MODE;
if (mode & FLAGS_AES_DECRYPT)
aes_control |= SSS_AES_MODE_DECRYPT;
@@ -1928,11 +1915,14 @@ static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode)
if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CBC) {
aes_control |= SSS_AES_CHAIN_MODE_CBC;
iv = req->info;
+ ctr = NULL;
} else if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CTR) {
aes_control |= SSS_AES_CHAIN_MODE_CTR;
- iv = req->info;
+ iv = NULL;
+ ctr = req->info;
} else {
iv = NULL; /* AES_ECB */
+ ctr = NULL;
}
if (dev->ctx->keylen == AES_KEYSIZE_192)
@@ -1964,7 +1954,7 @@ static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode)
goto outdata_error;
SSS_AES_WRITE(dev, AES_CONTROL, aes_control);
- s5p_set_aes(dev, dev->ctx->aes_key, iv, dev->ctx->keylen);
+ s5p_set_aes(dev, dev->ctx->aes_key, iv, ctr, dev->ctx->keylen);
s5p_set_dma_indata(dev, dev->sg_src);
s5p_set_dma_outdata(dev, dev->sg_dst);
@@ -1983,7 +1973,7 @@ indata_error:
s5p_sg_done(dev);
dev->busy = false;
spin_unlock_irqrestore(&dev->lock, flags);
- s5p_aes_complete(dev, err);
+ s5p_aes_complete(req, err);
}
static void s5p_tasklet_cb(unsigned long data)
@@ -2024,7 +2014,7 @@ static int s5p_aes_handle_req(struct s5p_aes_dev *dev,
err = ablkcipher_enqueue_request(&dev->queue, req);
if (dev->busy) {
spin_unlock_irqrestore(&dev->lock, flags);
- goto exit;
+ return err;
}
dev->busy = true;
@@ -2032,7 +2022,6 @@ static int s5p_aes_handle_req(struct s5p_aes_dev *dev,
tasklet_schedule(&dev->tasklet);
-exit:
return err;
}
@@ -2043,7 +2032,8 @@ static int s5p_aes_crypt(struct ablkcipher_request *req, unsigned long mode)
struct s5p_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm);
struct s5p_aes_dev *dev = ctx->dev;
- if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE)) {
+ if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE) &&
+ ((mode & FLAGS_AES_MODE_MASK) != FLAGS_AES_CTR)) {
dev_err(dev->dev, "request size is not exact amount of AES blocks\n");
return -EINVAL;
}
@@ -2054,7 +2044,7 @@ static int s5p_aes_crypt(struct ablkcipher_request *req, unsigned long mode)
}
static int s5p_aes_setkey(struct crypto_ablkcipher *cipher,
- const uint8_t *key, unsigned int keylen)
+ const u8 *key, unsigned int keylen)
{
struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher);
struct s5p_aes_ctx *ctx = crypto_tfm_ctx(tfm);
@@ -2090,6 +2080,11 @@ static int s5p_aes_cbc_decrypt(struct ablkcipher_request *req)
return s5p_aes_crypt(req, FLAGS_AES_DECRYPT | FLAGS_AES_CBC);
}
+static int s5p_aes_ctr_crypt(struct ablkcipher_request *req)
+{
+ return s5p_aes_crypt(req, FLAGS_AES_CTR);
+}
+
static int s5p_aes_cra_init(struct crypto_tfm *tfm)
{
struct s5p_aes_ctx *ctx = crypto_tfm_ctx(tfm);
@@ -2144,6 +2139,28 @@ static struct crypto_alg algs[] = {
.decrypt = s5p_aes_cbc_decrypt,
}
},
+ {
+ .cra_name = "ctr(aes)",
+ .cra_driver_name = "ctr-aes-s5p",
+ .cra_priority = 100,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+ CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_KERN_DRIVER_ONLY,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct s5p_aes_ctx),
+ .cra_alignmask = 0x0f,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = s5p_aes_cra_init,
+ .cra_u.ablkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .setkey = s5p_aes_setkey,
+ .encrypt = s5p_aes_ctr_crypt,
+ .decrypt = s5p_aes_ctr_crypt,
+ }
+ },
};
static int s5p_aes_probe(struct platform_device *pdev)
diff --git a/drivers/crypto/sahara.c b/drivers/crypto/sahara.c
index e7540a5b8197..bbf166a97ad3 100644
--- a/drivers/crypto/sahara.c
+++ b/drivers/crypto/sahara.c
@@ -149,7 +149,7 @@ struct sahara_ctx {
/* AES-specific context */
int keylen;
u8 key[AES_KEYSIZE_128];
- struct crypto_skcipher *fallback;
+ struct crypto_sync_skcipher *fallback;
};
struct sahara_aes_reqctx {
@@ -621,14 +621,14 @@ static int sahara_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
/*
* The requested key size is not supported by HW, do a fallback.
*/
- crypto_skcipher_clear_flags(ctx->fallback, CRYPTO_TFM_REQ_MASK);
- crypto_skcipher_set_flags(ctx->fallback, tfm->base.crt_flags &
+ crypto_sync_skcipher_clear_flags(ctx->fallback, CRYPTO_TFM_REQ_MASK);
+ crypto_sync_skcipher_set_flags(ctx->fallback, tfm->base.crt_flags &
CRYPTO_TFM_REQ_MASK);
- ret = crypto_skcipher_setkey(ctx->fallback, key, keylen);
+ ret = crypto_sync_skcipher_setkey(ctx->fallback, key, keylen);
tfm->base.crt_flags &= ~CRYPTO_TFM_RES_MASK;
- tfm->base.crt_flags |= crypto_skcipher_get_flags(ctx->fallback) &
+ tfm->base.crt_flags |= crypto_sync_skcipher_get_flags(ctx->fallback) &
CRYPTO_TFM_RES_MASK;
return ret;
}
@@ -666,9 +666,9 @@ static int sahara_aes_ecb_encrypt(struct ablkcipher_request *req)
int err;
if (unlikely(ctx->keylen != AES_KEYSIZE_128)) {
- SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback);
- skcipher_request_set_tfm(subreq, ctx->fallback);
+ skcipher_request_set_sync_tfm(subreq, ctx->fallback);
skcipher_request_set_callback(subreq, req->base.flags,
NULL, NULL);
skcipher_request_set_crypt(subreq, req->src, req->dst,
@@ -688,9 +688,9 @@ static int sahara_aes_ecb_decrypt(struct ablkcipher_request *req)
int err;
if (unlikely(ctx->keylen != AES_KEYSIZE_128)) {
- SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback);
- skcipher_request_set_tfm(subreq, ctx->fallback);
+ skcipher_request_set_sync_tfm(subreq, ctx->fallback);
skcipher_request_set_callback(subreq, req->base.flags,
NULL, NULL);
skcipher_request_set_crypt(subreq, req->src, req->dst,
@@ -710,9 +710,9 @@ static int sahara_aes_cbc_encrypt(struct ablkcipher_request *req)
int err;
if (unlikely(ctx->keylen != AES_KEYSIZE_128)) {
- SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback);
- skcipher_request_set_tfm(subreq, ctx->fallback);
+ skcipher_request_set_sync_tfm(subreq, ctx->fallback);
skcipher_request_set_callback(subreq, req->base.flags,
NULL, NULL);
skcipher_request_set_crypt(subreq, req->src, req->dst,
@@ -732,9 +732,9 @@ static int sahara_aes_cbc_decrypt(struct ablkcipher_request *req)
int err;
if (unlikely(ctx->keylen != AES_KEYSIZE_128)) {
- SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback);
- skcipher_request_set_tfm(subreq, ctx->fallback);
+ skcipher_request_set_sync_tfm(subreq, ctx->fallback);
skcipher_request_set_callback(subreq, req->base.flags,
NULL, NULL);
skcipher_request_set_crypt(subreq, req->src, req->dst,
@@ -752,8 +752,7 @@ static int sahara_aes_cra_init(struct crypto_tfm *tfm)
const char *name = crypto_tfm_alg_name(tfm);
struct sahara_ctx *ctx = crypto_tfm_ctx(tfm);
- ctx->fallback = crypto_alloc_skcipher(name, 0,
- CRYPTO_ALG_ASYNC |
+ ctx->fallback = crypto_alloc_sync_skcipher(name, 0,
CRYPTO_ALG_NEED_FALLBACK);
if (IS_ERR(ctx->fallback)) {
pr_err("Error allocating fallback algo %s\n", name);
@@ -769,7 +768,7 @@ static void sahara_aes_cra_exit(struct crypto_tfm *tfm)
{
struct sahara_ctx *ctx = crypto_tfm_ctx(tfm);
- crypto_free_skcipher(ctx->fallback);
+ crypto_free_sync_skcipher(ctx->fallback);
}
static u32 sahara_sha_init_hdr(struct sahara_dev *dev,
diff --git a/drivers/crypto/vmx/aes_cbc.c b/drivers/crypto/vmx/aes_cbc.c
index b71895871be3..c5c5ff82b52e 100644
--- a/drivers/crypto/vmx/aes_cbc.c
+++ b/drivers/crypto/vmx/aes_cbc.c
@@ -32,7 +32,7 @@
#include "aesp8-ppc.h"
struct p8_aes_cbc_ctx {
- struct crypto_skcipher *fallback;
+ struct crypto_sync_skcipher *fallback;
struct aes_key enc_key;
struct aes_key dec_key;
};
@@ -40,11 +40,11 @@ struct p8_aes_cbc_ctx {
static int p8_aes_cbc_init(struct crypto_tfm *tfm)
{
const char *alg = crypto_tfm_alg_name(tfm);
- struct crypto_skcipher *fallback;
+ struct crypto_sync_skcipher *fallback;
struct p8_aes_cbc_ctx *ctx = crypto_tfm_ctx(tfm);
- fallback = crypto_alloc_skcipher(alg, 0,
- CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK);
+ fallback = crypto_alloc_sync_skcipher(alg, 0,
+ CRYPTO_ALG_NEED_FALLBACK);
if (IS_ERR(fallback)) {
printk(KERN_ERR
@@ -53,7 +53,7 @@ static int p8_aes_cbc_init(struct crypto_tfm *tfm)
return PTR_ERR(fallback);
}
- crypto_skcipher_set_flags(
+ crypto_sync_skcipher_set_flags(
fallback,
crypto_skcipher_get_flags((struct crypto_skcipher *)tfm));
ctx->fallback = fallback;
@@ -66,7 +66,7 @@ static void p8_aes_cbc_exit(struct crypto_tfm *tfm)
struct p8_aes_cbc_ctx *ctx = crypto_tfm_ctx(tfm);
if (ctx->fallback) {
- crypto_free_skcipher(ctx->fallback);
+ crypto_free_sync_skcipher(ctx->fallback);
ctx->fallback = NULL;
}
}
@@ -86,7 +86,7 @@ static int p8_aes_cbc_setkey(struct crypto_tfm *tfm, const u8 *key,
pagefault_enable();
preempt_enable();
- ret += crypto_skcipher_setkey(ctx->fallback, key, keylen);
+ ret += crypto_sync_skcipher_setkey(ctx->fallback, key, keylen);
return ret;
}
@@ -100,8 +100,8 @@ static int p8_aes_cbc_encrypt(struct blkcipher_desc *desc,
crypto_tfm_ctx(crypto_blkcipher_tfm(desc->tfm));
if (in_interrupt()) {
- SKCIPHER_REQUEST_ON_STACK(req, ctx->fallback);
- skcipher_request_set_tfm(req, ctx->fallback);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(req, ctx->fallback);
+ skcipher_request_set_sync_tfm(req, ctx->fallback);
skcipher_request_set_callback(req, desc->flags, NULL, NULL);
skcipher_request_set_crypt(req, src, dst, nbytes, desc->info);
ret = crypto_skcipher_encrypt(req);
@@ -139,8 +139,8 @@ static int p8_aes_cbc_decrypt(struct blkcipher_desc *desc,
crypto_tfm_ctx(crypto_blkcipher_tfm(desc->tfm));
if (in_interrupt()) {
- SKCIPHER_REQUEST_ON_STACK(req, ctx->fallback);
- skcipher_request_set_tfm(req, ctx->fallback);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(req, ctx->fallback);
+ skcipher_request_set_sync_tfm(req, ctx->fallback);
skcipher_request_set_callback(req, desc->flags, NULL, NULL);
skcipher_request_set_crypt(req, src, dst, nbytes, desc->info);
ret = crypto_skcipher_decrypt(req);
diff --git a/drivers/crypto/vmx/aes_ctr.c b/drivers/crypto/vmx/aes_ctr.c
index cd777c75291d..8a2fe092cb8e 100644
--- a/drivers/crypto/vmx/aes_ctr.c
+++ b/drivers/crypto/vmx/aes_ctr.c
@@ -32,18 +32,18 @@
#include "aesp8-ppc.h"
struct p8_aes_ctr_ctx {
- struct crypto_skcipher *fallback;
+ struct crypto_sync_skcipher *fallback;
struct aes_key enc_key;
};
static int p8_aes_ctr_init(struct crypto_tfm *tfm)
{
const char *alg = crypto_tfm_alg_name(tfm);
- struct crypto_skcipher *fallback;
+ struct crypto_sync_skcipher *fallback;
struct p8_aes_ctr_ctx *ctx = crypto_tfm_ctx(tfm);
- fallback = crypto_alloc_skcipher(alg, 0,
- CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK);
+ fallback = crypto_alloc_sync_skcipher(alg, 0,
+ CRYPTO_ALG_NEED_FALLBACK);
if (IS_ERR(fallback)) {
printk(KERN_ERR
"Failed to allocate transformation for '%s': %ld\n",
@@ -51,7 +51,7 @@ static int p8_aes_ctr_init(struct crypto_tfm *tfm)
return PTR_ERR(fallback);
}
- crypto_skcipher_set_flags(
+ crypto_sync_skcipher_set_flags(
fallback,
crypto_skcipher_get_flags((struct crypto_skcipher *)tfm));
ctx->fallback = fallback;
@@ -64,7 +64,7 @@ static void p8_aes_ctr_exit(struct crypto_tfm *tfm)
struct p8_aes_ctr_ctx *ctx = crypto_tfm_ctx(tfm);
if (ctx->fallback) {
- crypto_free_skcipher(ctx->fallback);
+ crypto_free_sync_skcipher(ctx->fallback);
ctx->fallback = NULL;
}
}
@@ -83,7 +83,7 @@ static int p8_aes_ctr_setkey(struct crypto_tfm *tfm, const u8 *key,
pagefault_enable();
preempt_enable();
- ret += crypto_skcipher_setkey(ctx->fallback, key, keylen);
+ ret += crypto_sync_skcipher_setkey(ctx->fallback, key, keylen);
return ret;
}
@@ -119,8 +119,8 @@ static int p8_aes_ctr_crypt(struct blkcipher_desc *desc,
crypto_tfm_ctx(crypto_blkcipher_tfm(desc->tfm));
if (in_interrupt()) {
- SKCIPHER_REQUEST_ON_STACK(req, ctx->fallback);
- skcipher_request_set_tfm(req, ctx->fallback);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(req, ctx->fallback);
+ skcipher_request_set_sync_tfm(req, ctx->fallback);
skcipher_request_set_callback(req, desc->flags, NULL, NULL);
skcipher_request_set_crypt(req, src, dst, nbytes, desc->info);
ret = crypto_skcipher_encrypt(req);
diff --git a/drivers/crypto/vmx/aes_xts.c b/drivers/crypto/vmx/aes_xts.c
index e9954a7d4694..ecd64e5cc5bb 100644
--- a/drivers/crypto/vmx/aes_xts.c
+++ b/drivers/crypto/vmx/aes_xts.c
@@ -33,7 +33,7 @@
#include "aesp8-ppc.h"
struct p8_aes_xts_ctx {
- struct crypto_skcipher *fallback;
+ struct crypto_sync_skcipher *fallback;
struct aes_key enc_key;
struct aes_key dec_key;
struct aes_key tweak_key;
@@ -42,11 +42,11 @@ struct p8_aes_xts_ctx {
static int p8_aes_xts_init(struct crypto_tfm *tfm)
{
const char *alg = crypto_tfm_alg_name(tfm);
- struct crypto_skcipher *fallback;
+ struct crypto_sync_skcipher *fallback;
struct p8_aes_xts_ctx *ctx = crypto_tfm_ctx(tfm);
- fallback = crypto_alloc_skcipher(alg, 0,
- CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK);
+ fallback = crypto_alloc_sync_skcipher(alg, 0,
+ CRYPTO_ALG_NEED_FALLBACK);
if (IS_ERR(fallback)) {
printk(KERN_ERR
"Failed to allocate transformation for '%s': %ld\n",
@@ -54,7 +54,7 @@ static int p8_aes_xts_init(struct crypto_tfm *tfm)
return PTR_ERR(fallback);
}
- crypto_skcipher_set_flags(
+ crypto_sync_skcipher_set_flags(
fallback,
crypto_skcipher_get_flags((struct crypto_skcipher *)tfm));
ctx->fallback = fallback;
@@ -67,7 +67,7 @@ static void p8_aes_xts_exit(struct crypto_tfm *tfm)
struct p8_aes_xts_ctx *ctx = crypto_tfm_ctx(tfm);
if (ctx->fallback) {
- crypto_free_skcipher(ctx->fallback);
+ crypto_free_sync_skcipher(ctx->fallback);
ctx->fallback = NULL;
}
}
@@ -92,7 +92,7 @@ static int p8_aes_xts_setkey(struct crypto_tfm *tfm, const u8 *key,
pagefault_enable();
preempt_enable();
- ret += crypto_skcipher_setkey(ctx->fallback, key, keylen);
+ ret += crypto_sync_skcipher_setkey(ctx->fallback, key, keylen);
return ret;
}
@@ -109,8 +109,8 @@ static int p8_aes_xts_crypt(struct blkcipher_desc *desc,
crypto_tfm_ctx(crypto_blkcipher_tfm(desc->tfm));
if (in_interrupt()) {
- SKCIPHER_REQUEST_ON_STACK(req, ctx->fallback);
- skcipher_request_set_tfm(req, ctx->fallback);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(req, ctx->fallback);
+ skcipher_request_set_sync_tfm(req, ctx->fallback);
skcipher_request_set_callback(req, desc->flags, NULL, NULL);
skcipher_request_set_crypt(req, src, dst, nbytes, desc->info);
ret = enc? crypto_skcipher_encrypt(req) : crypto_skcipher_decrypt(req);
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index 4c49bb1330b5..141413067b5c 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -11,6 +11,7 @@
*/
#include <linux/kernel.h>
+#include <linux/kmod.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/err.h>
@@ -28,9 +29,6 @@
#include <linux/of.h>
#include "governor.h"
-#define MAX(a,b) ((a > b) ? a : b)
-#define MIN(a,b) ((a < b) ? a : b)
-
static struct class *devfreq_class;
/*
@@ -221,6 +219,49 @@ static struct devfreq_governor *find_devfreq_governor(const char *name)
return ERR_PTR(-ENODEV);
}
+/**
+ * try_then_request_governor() - Try to find the governor and request the
+ * module if is not found.
+ * @name: name of the governor
+ *
+ * Search the list of devfreq governors and request the module and try again
+ * if is not found. This can happen when both drivers (the governor driver
+ * and the driver that call devfreq_add_device) are built as modules.
+ * devfreq_list_lock should be held by the caller. Returns the matched
+ * governor's pointer.
+ */
+static struct devfreq_governor *try_then_request_governor(const char *name)
+{
+ struct devfreq_governor *governor;
+ int err = 0;
+
+ if (IS_ERR_OR_NULL(name)) {
+ pr_err("DEVFREQ: %s: Invalid parameters\n", __func__);
+ return ERR_PTR(-EINVAL);
+ }
+ WARN(!mutex_is_locked(&devfreq_list_lock),
+ "devfreq_list_lock must be locked.");
+
+ governor = find_devfreq_governor(name);
+ if (IS_ERR(governor)) {
+ mutex_unlock(&devfreq_list_lock);
+
+ if (!strncmp(name, DEVFREQ_GOV_SIMPLE_ONDEMAND,
+ DEVFREQ_NAME_LEN))
+ err = request_module("governor_%s", "simpleondemand");
+ else
+ err = request_module("governor_%s", name);
+ /* Restore previous state before return */
+ mutex_lock(&devfreq_list_lock);
+ if (err)
+ return NULL;
+
+ governor = find_devfreq_governor(name);
+ }
+
+ return governor;
+}
+
static int devfreq_notify_transition(struct devfreq *devfreq,
struct devfreq_freqs *freqs, unsigned int state)
{
@@ -280,14 +321,14 @@ int update_devfreq(struct devfreq *devfreq)
* max_freq
* min_freq
*/
- max_freq = MIN(devfreq->scaling_max_freq, devfreq->max_freq);
- min_freq = MAX(devfreq->scaling_min_freq, devfreq->min_freq);
+ max_freq = min(devfreq->scaling_max_freq, devfreq->max_freq);
+ min_freq = max(devfreq->scaling_min_freq, devfreq->min_freq);
- if (min_freq && freq < min_freq) {
+ if (freq < min_freq) {
freq = min_freq;
flags &= ~DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use GLB */
}
- if (max_freq && freq > max_freq) {
+ if (freq > max_freq) {
freq = max_freq;
flags |= DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use LUB */
}
@@ -534,10 +575,6 @@ static void devfreq_dev_release(struct device *dev)
list_del(&devfreq->node);
mutex_unlock(&devfreq_list_lock);
- if (devfreq->governor)
- devfreq->governor->event_handler(devfreq,
- DEVFREQ_GOV_STOP, NULL);
-
if (devfreq->profile->exit)
devfreq->profile->exit(devfreq->dev.parent);
@@ -646,9 +683,8 @@ struct devfreq *devfreq_add_device(struct device *dev,
mutex_unlock(&devfreq->lock);
mutex_lock(&devfreq_list_lock);
- list_add(&devfreq->node, &devfreq_list);
- governor = find_devfreq_governor(devfreq->governor_name);
+ governor = try_then_request_governor(devfreq->governor_name);
if (IS_ERR(governor)) {
dev_err(dev, "%s: Unable to find governor for the device\n",
__func__);
@@ -664,19 +700,20 @@ struct devfreq *devfreq_add_device(struct device *dev,
__func__);
goto err_init;
}
+
+ list_add(&devfreq->node, &devfreq_list);
+
mutex_unlock(&devfreq_list_lock);
return devfreq;
err_init:
- list_del(&devfreq->node);
mutex_unlock(&devfreq_list_lock);
- device_unregister(&devfreq->dev);
+ devfreq_remove_device(devfreq);
devfreq = NULL;
err_dev:
- if (devfreq)
- kfree(devfreq);
+ kfree(devfreq);
err_out:
return ERR_PTR(err);
}
@@ -693,6 +730,9 @@ int devfreq_remove_device(struct devfreq *devfreq)
if (!devfreq)
return -EINVAL;
+ if (devfreq->governor)
+ devfreq->governor->event_handler(devfreq,
+ DEVFREQ_GOV_STOP, NULL);
device_unregister(&devfreq->dev);
return 0;
@@ -991,7 +1031,7 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr,
return -EINVAL;
mutex_lock(&devfreq_list_lock);
- governor = find_devfreq_governor(str_governor);
+ governor = try_then_request_governor(str_governor);
if (IS_ERR(governor)) {
ret = PTR_ERR(governor);
goto out;
@@ -1126,17 +1166,26 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
struct devfreq *df = to_devfreq(dev);
unsigned long value;
int ret;
- unsigned long max;
ret = sscanf(buf, "%lu", &value);
if (ret != 1)
return -EINVAL;
mutex_lock(&df->lock);
- max = df->max_freq;
- if (value && max && value > max) {
- ret = -EINVAL;
- goto unlock;
+
+ if (value) {
+ if (value > df->max_freq) {
+ ret = -EINVAL;
+ goto unlock;
+ }
+ } else {
+ unsigned long *freq_table = df->profile->freq_table;
+
+ /* Get minimum frequency according to sorting order */
+ if (freq_table[0] < freq_table[df->profile->max_state - 1])
+ value = freq_table[0];
+ else
+ value = freq_table[df->profile->max_state - 1];
}
df->min_freq = value;
@@ -1152,7 +1201,7 @@ static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
{
struct devfreq *df = to_devfreq(dev);
- return sprintf(buf, "%lu\n", MAX(df->scaling_min_freq, df->min_freq));
+ return sprintf(buf, "%lu\n", max(df->scaling_min_freq, df->min_freq));
}
static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
@@ -1161,17 +1210,26 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
struct devfreq *df = to_devfreq(dev);
unsigned long value;
int ret;
- unsigned long min;
ret = sscanf(buf, "%lu", &value);
if (ret != 1)
return -EINVAL;
mutex_lock(&df->lock);
- min = df->min_freq;
- if (value && min && value < min) {
- ret = -EINVAL;
- goto unlock;
+
+ if (value) {
+ if (value < df->min_freq) {
+ ret = -EINVAL;
+ goto unlock;
+ }
+ } else {
+ unsigned long *freq_table = df->profile->freq_table;
+
+ /* Get maximum frequency according to sorting order */
+ if (freq_table[0] < freq_table[df->profile->max_state - 1])
+ value = freq_table[df->profile->max_state - 1];
+ else
+ value = freq_table[0];
}
df->max_freq = value;
@@ -1188,7 +1246,7 @@ static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr,
{
struct devfreq *df = to_devfreq(dev);
- return sprintf(buf, "%lu\n", MIN(df->scaling_max_freq, df->max_freq));
+ return sprintf(buf, "%lu\n", min(df->scaling_max_freq, df->max_freq));
}
static DEVICE_ATTR_RW(max_freq);
diff --git a/drivers/devfreq/event/exynos-ppmu.c b/drivers/devfreq/event/exynos-ppmu.c
index a9c64f0d3284..c61de0bdf053 100644
--- a/drivers/devfreq/event/exynos-ppmu.c
+++ b/drivers/devfreq/event/exynos-ppmu.c
@@ -535,8 +535,8 @@ static int of_get_devfreq_events(struct device_node *np,
if (i == ARRAY_SIZE(ppmu_events)) {
dev_warn(dev,
- "don't know how to configure events : %s\n",
- node->name);
+ "don't know how to configure events : %pOFn\n",
+ node);
continue;
}
diff --git a/drivers/devfreq/governor.h b/drivers/devfreq/governor.h
index cfc50a61a90d..f53339ca610f 100644
--- a/drivers/devfreq/governor.h
+++ b/drivers/devfreq/governor.h
@@ -25,6 +25,9 @@
#define DEVFREQ_GOV_SUSPEND 0x4
#define DEVFREQ_GOV_RESUME 0x5
+#define DEVFREQ_MIN_FREQ 0
+#define DEVFREQ_MAX_FREQ ULONG_MAX
+
/**
* struct devfreq_governor - Devfreq policy governor
* @node: list node - contains registered devfreq governors
@@ -54,9 +57,6 @@ struct devfreq_governor {
unsigned int event, void *data);
};
-/* Caution: devfreq->lock must be locked before calling update_devfreq */
-extern int update_devfreq(struct devfreq *devfreq);
-
extern void devfreq_monitor_start(struct devfreq *devfreq);
extern void devfreq_monitor_stop(struct devfreq *devfreq);
extern void devfreq_monitor_suspend(struct devfreq *devfreq);
diff --git a/drivers/devfreq/governor_performance.c b/drivers/devfreq/governor_performance.c
index 4d23ecfbd948..ded429fd51be 100644
--- a/drivers/devfreq/governor_performance.c
+++ b/drivers/devfreq/governor_performance.c
@@ -20,10 +20,7 @@ static int devfreq_performance_func(struct devfreq *df,
* target callback should be able to get floor value as
* said in devfreq.h
*/
- if (!df->max_freq)
- *freq = UINT_MAX;
- else
- *freq = df->max_freq;
+ *freq = DEVFREQ_MAX_FREQ;
return 0;
}
diff --git a/drivers/devfreq/governor_powersave.c b/drivers/devfreq/governor_powersave.c
index 0c42f23249ef..9e8897f5ac42 100644
--- a/drivers/devfreq/governor_powersave.c
+++ b/drivers/devfreq/governor_powersave.c
@@ -20,7 +20,7 @@ static int devfreq_powersave_func(struct devfreq *df,
* target callback should be able to get ceiling value as
* said in devfreq.h
*/
- *freq = df->min_freq;
+ *freq = DEVFREQ_MIN_FREQ;
return 0;
}
diff --git a/drivers/devfreq/governor_simpleondemand.c b/drivers/devfreq/governor_simpleondemand.c
index 28e0f2de7100..c0417f0e081e 100644
--- a/drivers/devfreq/governor_simpleondemand.c
+++ b/drivers/devfreq/governor_simpleondemand.c
@@ -27,7 +27,6 @@ static int devfreq_simple_ondemand_func(struct devfreq *df,
unsigned int dfso_upthreshold = DFSO_UPTHRESHOLD;
unsigned int dfso_downdifferential = DFSO_DOWNDIFFERENCTIAL;
struct devfreq_simple_ondemand_data *data = df->data;
- unsigned long max = (df->max_freq) ? df->max_freq : UINT_MAX;
err = devfreq_update_stats(df);
if (err)
@@ -47,7 +46,7 @@ static int devfreq_simple_ondemand_func(struct devfreq *df,
/* Assume MAX if it is going to be divided by zero */
if (stat->total_time == 0) {
- *freq = max;
+ *freq = DEVFREQ_MAX_FREQ;
return 0;
}
@@ -60,13 +59,13 @@ static int devfreq_simple_ondemand_func(struct devfreq *df,
/* Set MAX if it's busy enough */
if (stat->busy_time * 100 >
stat->total_time * dfso_upthreshold) {
- *freq = max;
+ *freq = DEVFREQ_MAX_FREQ;
return 0;
}
/* Set MAX if we do not know the initial frequency */
if (stat->current_frequency == 0) {
- *freq = max;
+ *freq = DEVFREQ_MAX_FREQ;
return 0;
}
@@ -85,11 +84,6 @@ static int devfreq_simple_ondemand_func(struct devfreq *df,
b = div_u64(b, (dfso_upthreshold - dfso_downdifferential / 2));
*freq = (unsigned long) b;
- if (df->min_freq && *freq < df->min_freq)
- *freq = df->min_freq;
- if (df->max_freq && *freq > df->max_freq)
- *freq = df->max_freq;
-
return 0;
}
diff --git a/drivers/devfreq/governor_userspace.c b/drivers/devfreq/governor_userspace.c
index 080607c3f34d..378d84c011df 100644
--- a/drivers/devfreq/governor_userspace.c
+++ b/drivers/devfreq/governor_userspace.c
@@ -26,19 +26,11 @@ static int devfreq_userspace_func(struct devfreq *df, unsigned long *freq)
{
struct userspace_data *data = df->data;
- if (data->valid) {
- unsigned long adjusted_freq = data->user_frequency;
-
- if (df->max_freq && adjusted_freq > df->max_freq)
- adjusted_freq = df->max_freq;
-
- if (df->min_freq && adjusted_freq < df->min_freq)
- adjusted_freq = df->min_freq;
-
- *freq = adjusted_freq;
- } else {
+ if (data->valid)
+ *freq = data->user_frequency;
+ else
*freq = df->previous_freq; /* No user freq specified yet */
- }
+
return 0;
}
diff --git a/drivers/dma-buf/reservation.c b/drivers/dma-buf/reservation.c
index 6c95f61a32e7..c1618335ca99 100644
--- a/drivers/dma-buf/reservation.c
+++ b/drivers/dma-buf/reservation.c
@@ -56,9 +56,10 @@ const char reservation_seqcount_string[] = "reservation_seqcount";
EXPORT_SYMBOL(reservation_seqcount_string);
/**
- * reservation_object_reserve_shared - Reserve space to add a shared
- * fence to a reservation_object.
+ * reservation_object_reserve_shared - Reserve space to add shared fences to
+ * a reservation_object.
* @obj: reservation object
+ * @num_fences: number of fences we want to add
*
* Should be called before reservation_object_add_shared_fence(). Must
* be called with obj->lock held.
@@ -66,107 +67,27 @@ EXPORT_SYMBOL(reservation_seqcount_string);
* RETURNS
* Zero for success, or -errno
*/
-int reservation_object_reserve_shared(struct reservation_object *obj)
+int reservation_object_reserve_shared(struct reservation_object *obj,
+ unsigned int num_fences)
{
- struct reservation_object_list *fobj, *old;
- u32 max;
+ struct reservation_object_list *old, *new;
+ unsigned int i, j, k, max;
old = reservation_object_get_list(obj);
if (old && old->shared_max) {
- if (old->shared_count < old->shared_max) {
- /* perform an in-place update */
- kfree(obj->staged);
- obj->staged = NULL;
+ if ((old->shared_count + num_fences) <= old->shared_max)
return 0;
- } else
- max = old->shared_max * 2;
- } else
- max = 4;
-
- /*
- * resize obj->staged or allocate if it doesn't exist,
- * noop if already correct size
- */
- fobj = krealloc(obj->staged, offsetof(typeof(*fobj), shared[max]),
- GFP_KERNEL);
- if (!fobj)
- return -ENOMEM;
-
- obj->staged = fobj;
- fobj->shared_max = max;
- return 0;
-}
-EXPORT_SYMBOL(reservation_object_reserve_shared);
-
-static void
-reservation_object_add_shared_inplace(struct reservation_object *obj,
- struct reservation_object_list *fobj,
- struct dma_fence *fence)
-{
- struct dma_fence *signaled = NULL;
- u32 i, signaled_idx;
-
- dma_fence_get(fence);
-
- preempt_disable();
- write_seqcount_begin(&obj->seq);
-
- for (i = 0; i < fobj->shared_count; ++i) {
- struct dma_fence *old_fence;
-
- old_fence = rcu_dereference_protected(fobj->shared[i],
- reservation_object_held(obj));
-
- if (old_fence->context == fence->context) {
- /* memory barrier is added by write_seqcount_begin */
- RCU_INIT_POINTER(fobj->shared[i], fence);
- write_seqcount_end(&obj->seq);
- preempt_enable();
-
- dma_fence_put(old_fence);
- return;
- }
-
- if (!signaled && dma_fence_is_signaled(old_fence)) {
- signaled = old_fence;
- signaled_idx = i;
- }
- }
-
- /*
- * memory barrier is added by write_seqcount_begin,
- * fobj->shared_count is protected by this lock too
- */
- if (signaled) {
- RCU_INIT_POINTER(fobj->shared[signaled_idx], fence);
+ else
+ max = max(old->shared_count + num_fences,
+ old->shared_max * 2);
} else {
- BUG_ON(fobj->shared_count >= fobj->shared_max);
- RCU_INIT_POINTER(fobj->shared[fobj->shared_count], fence);
- fobj->shared_count++;
+ max = 4;
}
- write_seqcount_end(&obj->seq);
- preempt_enable();
-
- dma_fence_put(signaled);
-}
-
-static void
-reservation_object_add_shared_replace(struct reservation_object *obj,
- struct reservation_object_list *old,
- struct reservation_object_list *fobj,
- struct dma_fence *fence)
-{
- unsigned i, j, k;
-
- dma_fence_get(fence);
-
- if (!old) {
- RCU_INIT_POINTER(fobj->shared[0], fence);
- fobj->shared_count = 1;
- goto done;
- }
+ new = kmalloc(offsetof(typeof(*new), shared[max]), GFP_KERNEL);
+ if (!new)
+ return -ENOMEM;
/*
* no need to bump fence refcounts, rcu_read access
@@ -174,46 +95,45 @@ reservation_object_add_shared_replace(struct reservation_object *obj,
* references from the old struct are carried over to
* the new.
*/
- for (i = 0, j = 0, k = fobj->shared_max; i < old->shared_count; ++i) {
- struct dma_fence *check;
-
- check = rcu_dereference_protected(old->shared[i],
- reservation_object_held(obj));
+ for (i = 0, j = 0, k = max; i < (old ? old->shared_count : 0); ++i) {
+ struct dma_fence *fence;
- if (check->context == fence->context ||
- dma_fence_is_signaled(check))
- RCU_INIT_POINTER(fobj->shared[--k], check);
+ fence = rcu_dereference_protected(old->shared[i],
+ reservation_object_held(obj));
+ if (dma_fence_is_signaled(fence))
+ RCU_INIT_POINTER(new->shared[--k], fence);
else
- RCU_INIT_POINTER(fobj->shared[j++], check);
+ RCU_INIT_POINTER(new->shared[j++], fence);
}
- fobj->shared_count = j;
- RCU_INIT_POINTER(fobj->shared[fobj->shared_count], fence);
- fobj->shared_count++;
+ new->shared_count = j;
+ new->shared_max = max;
-done:
preempt_disable();
write_seqcount_begin(&obj->seq);
/*
* RCU_INIT_POINTER can be used here,
* seqcount provides the necessary barriers
*/
- RCU_INIT_POINTER(obj->fence, fobj);
+ RCU_INIT_POINTER(obj->fence, new);
write_seqcount_end(&obj->seq);
preempt_enable();
if (!old)
- return;
+ return 0;
/* Drop the references to the signaled fences */
- for (i = k; i < fobj->shared_max; ++i) {
- struct dma_fence *f;
+ for (i = k; i < new->shared_max; ++i) {
+ struct dma_fence *fence;
- f = rcu_dereference_protected(fobj->shared[i],
- reservation_object_held(obj));
- dma_fence_put(f);
+ fence = rcu_dereference_protected(new->shared[i],
+ reservation_object_held(obj));
+ dma_fence_put(fence);
}
kfree_rcu(old, rcu);
+
+ return 0;
}
+EXPORT_SYMBOL(reservation_object_reserve_shared);
/**
* reservation_object_add_shared_fence - Add a fence to a shared slot
@@ -226,15 +146,39 @@ done:
void reservation_object_add_shared_fence(struct reservation_object *obj,
struct dma_fence *fence)
{
- struct reservation_object_list *old, *fobj = obj->staged;
+ struct reservation_object_list *fobj;
+ unsigned int i, count;
- old = reservation_object_get_list(obj);
- obj->staged = NULL;
+ dma_fence_get(fence);
- if (!fobj)
- reservation_object_add_shared_inplace(obj, old, fence);
- else
- reservation_object_add_shared_replace(obj, old, fobj, fence);
+ fobj = reservation_object_get_list(obj);
+ count = fobj->shared_count;
+
+ preempt_disable();
+ write_seqcount_begin(&obj->seq);
+
+ for (i = 0; i < count; ++i) {
+ struct dma_fence *old_fence;
+
+ old_fence = rcu_dereference_protected(fobj->shared[i],
+ reservation_object_held(obj));
+ if (old_fence->context == fence->context ||
+ dma_fence_is_signaled(old_fence)) {
+ dma_fence_put(old_fence);
+ goto replace;
+ }
+ }
+
+ BUG_ON(fobj->shared_count >= fobj->shared_max);
+ count++;
+
+replace:
+ RCU_INIT_POINTER(fobj->shared[i], fence);
+ /* pointer update must be visible before we extend the shared_count */
+ smp_store_mb(fobj->shared_count, count);
+
+ write_seqcount_end(&obj->seq);
+ preempt_enable();
}
EXPORT_SYMBOL(reservation_object_add_shared_fence);
@@ -343,9 +287,6 @@ retry:
new = dma_fence_get_rcu_safe(&src->fence_excl);
rcu_read_unlock();
- kfree(dst->staged);
- dst->staged = NULL;
-
src_list = reservation_object_get_list(dst);
old = reservation_object_get_excl(dst);
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index dacf3f42426d..de511db021cc 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -143,7 +143,7 @@ config DMA_JZ4740
config DMA_JZ4780
tristate "JZ4780 DMA support"
- depends on MACH_JZ4780 || COMPILE_TEST
+ depends on MIPS || COMPILE_TEST
select DMA_ENGINE
select DMA_VIRTUAL_CHANNELS
help
@@ -321,6 +321,17 @@ config LPC18XX_DMAMUX
Enable support for DMA on NXP LPC18xx/43xx platforms
with PL080 and multiplexed DMA request lines.
+config MCF_EDMA
+ tristate "Freescale eDMA engine support, ColdFire mcf5441x SoCs"
+ depends on M5441x || COMPILE_TEST
+ select DMA_ENGINE
+ select DMA_VIRTUAL_CHANNELS
+ help
+ Support the Freescale ColdFire eDMA engine, 64-channel
+ implementation that performs complex data transfers with
+ minimal intervention from a host processor.
+ This module can be found on Freescale ColdFire mcf5441x SoCs.
+
config MMP_PDMA
bool "MMP PDMA support"
depends on ARCH_MMP || ARCH_PXA || COMPILE_TEST
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index c91702d88b95..7fcc4d8e336d 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -31,7 +31,8 @@ obj-$(CONFIG_DW_AXI_DMAC) += dw-axi-dmac/
obj-$(CONFIG_DW_DMAC_CORE) += dw/
obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o
obj-$(CONFIG_FSL_DMA) += fsldma.o
-obj-$(CONFIG_FSL_EDMA) += fsl-edma.o
+obj-$(CONFIG_FSL_EDMA) += fsl-edma.o fsl-edma-common.o
+obj-$(CONFIG_MCF_EDMA) += mcf-edma.o fsl-edma-common.o
obj-$(CONFIG_FSL_RAID) += fsl_raid.o
obj-$(CONFIG_HSU_DMA) += hsu/
obj-$(CONFIG_IMG_MDC_DMA) += img-mdc-dma.o
diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index 75f38d19fcbe..7cbac6e8c113 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -1320,7 +1320,7 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
if (unlikely(!is_slave_direction(direction)))
goto err_out;
- if (sconfig->direction == DMA_MEM_TO_DEV)
+ if (direction == DMA_MEM_TO_DEV)
reg_width = convert_buswidth(sconfig->dst_addr_width);
else
reg_width = convert_buswidth(sconfig->src_addr_width);
diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c
index 4bf72561667c..4e557684f792 100644
--- a/drivers/dma/at_xdmac.c
+++ b/drivers/dma/at_xdmac.c
@@ -1600,7 +1600,7 @@ static void at_xdmac_tasklet(unsigned long data)
if (atchan->status & AT_XDMAC_CIS_ROIS)
dev_err(chan2dev(&atchan->chan), "request overflow error!!!");
- spin_lock_bh(&atchan->lock);
+ spin_lock(&atchan->lock);
desc = list_first_entry(&atchan->xfers_list,
struct at_xdmac_desc,
xfer_node);
@@ -1610,7 +1610,7 @@ static void at_xdmac_tasklet(unsigned long data)
txd = &desc->tx_dma_desc;
at_xdmac_remove_xfer(atchan, desc);
- spin_unlock_bh(&atchan->lock);
+ spin_unlock(&atchan->lock);
if (!at_xdmac_chan_is_cyclic(atchan)) {
dma_cookie_complete(txd);
diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c
index 847f84a41a69..cad55ab80d41 100644
--- a/drivers/dma/bcm2835-dma.c
+++ b/drivers/dma/bcm2835-dma.c
@@ -778,14 +778,6 @@ static int bcm2835_dma_slave_config(struct dma_chan *chan,
{
struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
- if ((cfg->direction == DMA_DEV_TO_MEM &&
- cfg->src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) ||
- (cfg->direction == DMA_MEM_TO_DEV &&
- cfg->dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) ||
- !is_slave_direction(cfg->direction)) {
- return -EINVAL;
- }
-
c->cfg = *cfg;
return 0;
diff --git a/drivers/dma/coh901318.c b/drivers/dma/coh901318.c
index da74fd74636b..eebaba3d9e78 100644
--- a/drivers/dma/coh901318.c
+++ b/drivers/dma/coh901318.c
@@ -1306,6 +1306,7 @@ struct coh901318_chan {
unsigned long nbr_active_done;
unsigned long busy;
+ struct dma_slave_config config;
u32 addr;
u32 ctrl;
@@ -1402,6 +1403,10 @@ static inline struct coh901318_chan *to_coh901318_chan(struct dma_chan *chan)
return container_of(chan, struct coh901318_chan, chan);
}
+static int coh901318_dma_set_runtimeconfig(struct dma_chan *chan,
+ struct dma_slave_config *config,
+ enum dma_transfer_direction direction);
+
static inline const struct coh901318_params *
cohc_chan_param(struct coh901318_chan *cohc)
{
@@ -2360,6 +2365,8 @@ coh901318_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
if (lli == NULL)
goto err_dma_alloc;
+ coh901318_dma_set_runtimeconfig(chan, &cohc->config, direction);
+
/* initiate allocated lli list */
ret = coh901318_lli_fill_sg(&cohc->base->pool, lli, sgl, sg_len,
cohc->addr,
@@ -2499,7 +2506,8 @@ static const struct burst_table burst_sizes[] = {
};
static int coh901318_dma_set_runtimeconfig(struct dma_chan *chan,
- struct dma_slave_config *config)
+ struct dma_slave_config *config,
+ enum dma_transfer_direction direction)
{
struct coh901318_chan *cohc = to_coh901318_chan(chan);
dma_addr_t addr;
@@ -2509,11 +2517,11 @@ static int coh901318_dma_set_runtimeconfig(struct dma_chan *chan,
int i = 0;
/* We only support mem to per or per to mem transfers */
- if (config->direction == DMA_DEV_TO_MEM) {
+ if (direction == DMA_DEV_TO_MEM) {
addr = config->src_addr;
addr_width = config->src_addr_width;
maxburst = config->src_maxburst;
- } else if (config->direction == DMA_MEM_TO_DEV) {
+ } else if (direction == DMA_MEM_TO_DEV) {
addr = config->dst_addr;
addr_width = config->dst_addr_width;
maxburst = config->dst_maxburst;
@@ -2579,6 +2587,16 @@ static int coh901318_dma_set_runtimeconfig(struct dma_chan *chan,
return 0;
}
+static int coh901318_dma_slave_config(struct dma_chan *chan,
+ struct dma_slave_config *config)
+{
+ struct coh901318_chan *cohc = to_coh901318_chan(chan);
+
+ memcpy(&cohc->config, config, sizeof(*config));
+
+ return 0;
+}
+
static void coh901318_base_init(struct dma_device *dma, const int *pick_chans,
struct coh901318_base *base)
{
@@ -2684,7 +2702,7 @@ static int __init coh901318_probe(struct platform_device *pdev)
base->dma_slave.device_prep_slave_sg = coh901318_prep_slave_sg;
base->dma_slave.device_tx_status = coh901318_tx_status;
base->dma_slave.device_issue_pending = coh901318_issue_pending;
- base->dma_slave.device_config = coh901318_dma_set_runtimeconfig;
+ base->dma_slave.device_config = coh901318_dma_slave_config;
base->dma_slave.device_pause = coh901318_pause;
base->dma_slave.device_resume = coh901318_resume;
base->dma_slave.device_terminate_all = coh901318_terminate_all;
@@ -2707,7 +2725,7 @@ static int __init coh901318_probe(struct platform_device *pdev)
base->dma_memcpy.device_prep_dma_memcpy = coh901318_prep_memcpy;
base->dma_memcpy.device_tx_status = coh901318_tx_status;
base->dma_memcpy.device_issue_pending = coh901318_issue_pending;
- base->dma_memcpy.device_config = coh901318_dma_set_runtimeconfig;
+ base->dma_memcpy.device_config = coh901318_dma_slave_config;
base->dma_memcpy.device_pause = coh901318_pause;
base->dma_memcpy.device_resume = coh901318_resume;
base->dma_memcpy.device_terminate_all = coh901318_terminate_all;
diff --git a/drivers/dma/dma-jz4740.c b/drivers/dma/dma-jz4740.c
index afd5e10f8927..5253e3c0dc04 100644
--- a/drivers/dma/dma-jz4740.c
+++ b/drivers/dma/dma-jz4740.c
@@ -113,6 +113,7 @@ struct jz4740_dma_desc {
struct jz4740_dmaengine_chan {
struct virt_dma_chan vchan;
unsigned int id;
+ struct dma_slave_config config;
dma_addr_t fifo_addr;
unsigned int transfer_shift;
@@ -203,8 +204,9 @@ static enum jz4740_dma_transfer_size jz4740_dma_maxburst(u32 maxburst)
return JZ4740_DMA_TRANSFER_SIZE_32BYTE;
}
-static int jz4740_dma_slave_config(struct dma_chan *c,
- struct dma_slave_config *config)
+static int jz4740_dma_slave_config_write(struct dma_chan *c,
+ struct dma_slave_config *config,
+ enum dma_transfer_direction direction)
{
struct jz4740_dmaengine_chan *chan = to_jz4740_dma_chan(c);
struct jz4740_dma_dev *dmadev = jz4740_dma_chan_get_dev(chan);
@@ -214,7 +216,7 @@ static int jz4740_dma_slave_config(struct dma_chan *c,
enum jz4740_dma_flags flags;
uint32_t cmd;
- switch (config->direction) {
+ switch (direction) {
case DMA_MEM_TO_DEV:
flags = JZ4740_DMA_SRC_AUTOINC;
transfer_size = jz4740_dma_maxburst(config->dst_maxburst);
@@ -265,6 +267,15 @@ static int jz4740_dma_slave_config(struct dma_chan *c,
return 0;
}
+static int jz4740_dma_slave_config(struct dma_chan *c,
+ struct dma_slave_config *config)
+{
+ struct jz4740_dmaengine_chan *chan = to_jz4740_dma_chan(c);
+
+ memcpy(&chan->config, config, sizeof(*config));
+ return 0;
+}
+
static int jz4740_dma_terminate_all(struct dma_chan *c)
{
struct jz4740_dmaengine_chan *chan = to_jz4740_dma_chan(c);
@@ -407,6 +418,8 @@ static struct dma_async_tx_descriptor *jz4740_dma_prep_slave_sg(
desc->direction = direction;
desc->cyclic = false;
+ jz4740_dma_slave_config_write(c, &chan->config, direction);
+
return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
}
@@ -438,6 +451,8 @@ static struct dma_async_tx_descriptor *jz4740_dma_prep_dma_cyclic(
desc->direction = direction;
desc->cyclic = true;
+ jz4740_dma_slave_config_write(c, &chan->config, direction);
+
return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
}
diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c
index 85820a2d69d4..a8b6225faa12 100644
--- a/drivers/dma/dma-jz4780.c
+++ b/drivers/dma/dma-jz4780.c
@@ -16,6 +16,7 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/of_dma.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -23,33 +24,35 @@
#include "dmaengine.h"
#include "virt-dma.h"
-#define JZ_DMA_NR_CHANNELS 32
-
/* Global registers. */
-#define JZ_DMA_REG_DMAC 0x1000
-#define JZ_DMA_REG_DIRQP 0x1004
-#define JZ_DMA_REG_DDR 0x1008
-#define JZ_DMA_REG_DDRS 0x100c
-#define JZ_DMA_REG_DMACP 0x101c
-#define JZ_DMA_REG_DSIRQP 0x1020
-#define JZ_DMA_REG_DSIRQM 0x1024
-#define JZ_DMA_REG_DCIRQP 0x1028
-#define JZ_DMA_REG_DCIRQM 0x102c
+#define JZ_DMA_REG_DMAC 0x00
+#define JZ_DMA_REG_DIRQP 0x04
+#define JZ_DMA_REG_DDR 0x08
+#define JZ_DMA_REG_DDRS 0x0c
+#define JZ_DMA_REG_DCKE 0x10
+#define JZ_DMA_REG_DCKES 0x14
+#define JZ_DMA_REG_DCKEC 0x18
+#define JZ_DMA_REG_DMACP 0x1c
+#define JZ_DMA_REG_DSIRQP 0x20
+#define JZ_DMA_REG_DSIRQM 0x24
+#define JZ_DMA_REG_DCIRQP 0x28
+#define JZ_DMA_REG_DCIRQM 0x2c
/* Per-channel registers. */
#define JZ_DMA_REG_CHAN(n) (n * 0x20)
-#define JZ_DMA_REG_DSA(n) (0x00 + JZ_DMA_REG_CHAN(n))
-#define JZ_DMA_REG_DTA(n) (0x04 + JZ_DMA_REG_CHAN(n))
-#define JZ_DMA_REG_DTC(n) (0x08 + JZ_DMA_REG_CHAN(n))
-#define JZ_DMA_REG_DRT(n) (0x0c + JZ_DMA_REG_CHAN(n))
-#define JZ_DMA_REG_DCS(n) (0x10 + JZ_DMA_REG_CHAN(n))
-#define JZ_DMA_REG_DCM(n) (0x14 + JZ_DMA_REG_CHAN(n))
-#define JZ_DMA_REG_DDA(n) (0x18 + JZ_DMA_REG_CHAN(n))
-#define JZ_DMA_REG_DSD(n) (0x1c + JZ_DMA_REG_CHAN(n))
+#define JZ_DMA_REG_DSA 0x00
+#define JZ_DMA_REG_DTA 0x04
+#define JZ_DMA_REG_DTC 0x08
+#define JZ_DMA_REG_DRT 0x0c
+#define JZ_DMA_REG_DCS 0x10
+#define JZ_DMA_REG_DCM 0x14
+#define JZ_DMA_REG_DDA 0x18
+#define JZ_DMA_REG_DSD 0x1c
#define JZ_DMA_DMAC_DMAE BIT(0)
#define JZ_DMA_DMAC_AR BIT(2)
#define JZ_DMA_DMAC_HLT BIT(3)
+#define JZ_DMA_DMAC_FAIC BIT(27)
#define JZ_DMA_DMAC_FMSC BIT(31)
#define JZ_DMA_DRT_AUTO 0x8
@@ -86,6 +89,14 @@
BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES))
+#define JZ4780_DMA_CTRL_OFFSET 0x1000
+
+/* macros for use with jz4780_dma_soc_data.flags */
+#define JZ_SOC_DATA_ALLOW_LEGACY_DT BIT(0)
+#define JZ_SOC_DATA_PROGRAMMABLE_DMA BIT(1)
+#define JZ_SOC_DATA_PER_CHAN_PM BIT(2)
+#define JZ_SOC_DATA_NO_DCKES_DCKEC BIT(3)
+
/**
* struct jz4780_dma_hwdesc - descriptor structure read by the DMA controller.
* @dcm: value for the DCM (channel command) register
@@ -94,17 +105,12 @@
* @dtc: transfer count (number of blocks of the transfer size specified in DCM
* to transfer) in the low 24 bits, offset of the next descriptor from the
* descriptor base address in the upper 8 bits.
- * @sd: target/source stride difference (in stride transfer mode).
- * @drt: request type
*/
struct jz4780_dma_hwdesc {
uint32_t dcm;
uint32_t dsa;
uint32_t dta;
uint32_t dtc;
- uint32_t sd;
- uint32_t drt;
- uint32_t reserved[2];
};
/* Size of allocations for hardware descriptor blocks. */
@@ -135,14 +141,22 @@ struct jz4780_dma_chan {
unsigned int curr_hwdesc;
};
+struct jz4780_dma_soc_data {
+ unsigned int nb_channels;
+ unsigned int transfer_ord_max;
+ unsigned long flags;
+};
+
struct jz4780_dma_dev {
struct dma_device dma_device;
- void __iomem *base;
+ void __iomem *chn_base;
+ void __iomem *ctrl_base;
struct clk *clk;
unsigned int irq;
+ const struct jz4780_dma_soc_data *soc_data;
uint32_t chan_reserved;
- struct jz4780_dma_chan chan[JZ_DMA_NR_CHANNELS];
+ struct jz4780_dma_chan chan[];
};
struct jz4780_dma_filter_data {
@@ -169,16 +183,51 @@ static inline struct jz4780_dma_dev *jz4780_dma_chan_parent(
dma_device);
}
-static inline uint32_t jz4780_dma_readl(struct jz4780_dma_dev *jzdma,
+static inline uint32_t jz4780_dma_chn_readl(struct jz4780_dma_dev *jzdma,
+ unsigned int chn, unsigned int reg)
+{
+ return readl(jzdma->chn_base + reg + JZ_DMA_REG_CHAN(chn));
+}
+
+static inline void jz4780_dma_chn_writel(struct jz4780_dma_dev *jzdma,
+ unsigned int chn, unsigned int reg, uint32_t val)
+{
+ writel(val, jzdma->chn_base + reg + JZ_DMA_REG_CHAN(chn));
+}
+
+static inline uint32_t jz4780_dma_ctrl_readl(struct jz4780_dma_dev *jzdma,
unsigned int reg)
{
- return readl(jzdma->base + reg);
+ return readl(jzdma->ctrl_base + reg);
}
-static inline void jz4780_dma_writel(struct jz4780_dma_dev *jzdma,
+static inline void jz4780_dma_ctrl_writel(struct jz4780_dma_dev *jzdma,
unsigned int reg, uint32_t val)
{
- writel(val, jzdma->base + reg);
+ writel(val, jzdma->ctrl_base + reg);
+}
+
+static inline void jz4780_dma_chan_enable(struct jz4780_dma_dev *jzdma,
+ unsigned int chn)
+{
+ if (jzdma->soc_data->flags & JZ_SOC_DATA_PER_CHAN_PM) {
+ unsigned int reg;
+
+ if (jzdma->soc_data->flags & JZ_SOC_DATA_NO_DCKES_DCKEC)
+ reg = JZ_DMA_REG_DCKE;
+ else
+ reg = JZ_DMA_REG_DCKES;
+
+ jz4780_dma_ctrl_writel(jzdma, reg, BIT(chn));
+ }
+}
+
+static inline void jz4780_dma_chan_disable(struct jz4780_dma_dev *jzdma,
+ unsigned int chn)
+{
+ if ((jzdma->soc_data->flags & JZ_SOC_DATA_PER_CHAN_PM) &&
+ !(jzdma->soc_data->flags & JZ_SOC_DATA_NO_DCKES_DCKEC))
+ jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DCKEC, BIT(chn));
}
static struct jz4780_dma_desc *jz4780_dma_desc_alloc(
@@ -215,8 +264,10 @@ static void jz4780_dma_desc_free(struct virt_dma_desc *vdesc)
kfree(desc);
}
-static uint32_t jz4780_dma_transfer_size(unsigned long val, uint32_t *shift)
+static uint32_t jz4780_dma_transfer_size(struct jz4780_dma_chan *jzchan,
+ unsigned long val, uint32_t *shift)
{
+ struct jz4780_dma_dev *jzdma = jz4780_dma_chan_parent(jzchan);
int ord = ffs(val) - 1;
/*
@@ -228,8 +279,8 @@ static uint32_t jz4780_dma_transfer_size(unsigned long val, uint32_t *shift)
*/
if (ord == 3)
ord = 2;
- else if (ord > 7)
- ord = 7;
+ else if (ord > jzdma->soc_data->transfer_ord_max)
+ ord = jzdma->soc_data->transfer_ord_max;
*shift = ord;
@@ -262,7 +313,6 @@ static int jz4780_dma_setup_hwdesc(struct jz4780_dma_chan *jzchan,
desc->dcm = JZ_DMA_DCM_SAI;
desc->dsa = addr;
desc->dta = config->dst_addr;
- desc->drt = jzchan->transfer_type;
width = config->dst_addr_width;
maxburst = config->dst_maxburst;
@@ -270,7 +320,6 @@ static int jz4780_dma_setup_hwdesc(struct jz4780_dma_chan *jzchan,
desc->dcm = JZ_DMA_DCM_DAI;
desc->dsa = config->src_addr;
desc->dta = addr;
- desc->drt = jzchan->transfer_type;
width = config->src_addr_width;
maxburst = config->src_maxburst;
@@ -283,7 +332,7 @@ static int jz4780_dma_setup_hwdesc(struct jz4780_dma_chan *jzchan,
* divisible by the transfer size, and we must not use more than the
* maximum burst specified by the user.
*/
- tsz = jz4780_dma_transfer_size(addr | len | (width * maxburst),
+ tsz = jz4780_dma_transfer_size(jzchan, addr | len | (width * maxburst),
&jzchan->transfer_shift);
switch (width) {
@@ -412,12 +461,13 @@ static struct dma_async_tx_descriptor *jz4780_dma_prep_dma_memcpy(
if (!desc)
return NULL;
- tsz = jz4780_dma_transfer_size(dest | src | len,
+ tsz = jz4780_dma_transfer_size(jzchan, dest | src | len,
&jzchan->transfer_shift);
+ jzchan->transfer_type = JZ_DMA_DRT_AUTO;
+
desc->desc[0].dsa = src;
desc->desc[0].dta = dest;
- desc->desc[0].drt = JZ_DMA_DRT_AUTO;
desc->desc[0].dcm = JZ_DMA_DCM_TIE | JZ_DMA_DCM_SAI | JZ_DMA_DCM_DAI |
tsz << JZ_DMA_DCM_TSZ_SHIFT |
JZ_DMA_WIDTH_32_BIT << JZ_DMA_DCM_SP_SHIFT |
@@ -472,18 +522,34 @@ static void jz4780_dma_begin(struct jz4780_dma_chan *jzchan)
(jzchan->curr_hwdesc + 1) % jzchan->desc->count;
}
- /* Use 8-word descriptors. */
- jz4780_dma_writel(jzdma, JZ_DMA_REG_DCS(jzchan->id), JZ_DMA_DCS_DES8);
+ /* Enable the channel's clock. */
+ jz4780_dma_chan_enable(jzdma, jzchan->id);
+
+ /* Use 4-word descriptors. */
+ jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DCS, 0);
+
+ /* Set transfer type. */
+ jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DRT,
+ jzchan->transfer_type);
+
+ /*
+ * Set the transfer count. This is redundant for a descriptor-driven
+ * transfer. However, there can be a delay between the transfer start
+ * time and when DTCn reg contains the new transfer count. Setting
+ * it explicitly ensures residue is computed correctly at all times.
+ */
+ jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DTC,
+ jzchan->desc->desc[jzchan->curr_hwdesc].dtc);
/* Write descriptor address and initiate descriptor fetch. */
desc_phys = jzchan->desc->desc_phys +
(jzchan->curr_hwdesc * sizeof(*jzchan->desc->desc));
- jz4780_dma_writel(jzdma, JZ_DMA_REG_DDA(jzchan->id), desc_phys);
- jz4780_dma_writel(jzdma, JZ_DMA_REG_DDRS, BIT(jzchan->id));
+ jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DDA, desc_phys);
+ jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DDRS, BIT(jzchan->id));
/* Enable the channel. */
- jz4780_dma_writel(jzdma, JZ_DMA_REG_DCS(jzchan->id),
- JZ_DMA_DCS_DES8 | JZ_DMA_DCS_CTE);
+ jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DCS,
+ JZ_DMA_DCS_CTE);
}
static void jz4780_dma_issue_pending(struct dma_chan *chan)
@@ -509,12 +575,14 @@ static int jz4780_dma_terminate_all(struct dma_chan *chan)
spin_lock_irqsave(&jzchan->vchan.lock, flags);
/* Clear the DMA status and stop the transfer. */
- jz4780_dma_writel(jzdma, JZ_DMA_REG_DCS(jzchan->id), 0);
+ jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DCS, 0);
if (jzchan->desc) {
vchan_terminate_vdesc(&jzchan->desc->vdesc);
jzchan->desc = NULL;
}
+ jz4780_dma_chan_disable(jzdma, jzchan->id);
+
vchan_get_all_descriptors(&jzchan->vchan, &head);
spin_unlock_irqrestore(&jzchan->vchan.lock, flags);
@@ -526,8 +594,10 @@ static int jz4780_dma_terminate_all(struct dma_chan *chan)
static void jz4780_dma_synchronize(struct dma_chan *chan)
{
struct jz4780_dma_chan *jzchan = to_jz4780_dma_chan(chan);
+ struct jz4780_dma_dev *jzdma = jz4780_dma_chan_parent(jzchan);
vchan_synchronize(&jzchan->vchan);
+ jz4780_dma_chan_disable(jzdma, jzchan->id);
}
static int jz4780_dma_config(struct dma_chan *chan,
@@ -549,21 +619,17 @@ static size_t jz4780_dma_desc_residue(struct jz4780_dma_chan *jzchan,
struct jz4780_dma_desc *desc, unsigned int next_sg)
{
struct jz4780_dma_dev *jzdma = jz4780_dma_chan_parent(jzchan);
- unsigned int residue, count;
+ unsigned int count = 0;
unsigned int i;
- residue = 0;
-
for (i = next_sg; i < desc->count; i++)
- residue += desc->desc[i].dtc << jzchan->transfer_shift;
+ count += desc->desc[i].dtc & GENMASK(23, 0);
- if (next_sg != 0) {
- count = jz4780_dma_readl(jzdma,
- JZ_DMA_REG_DTC(jzchan->id));
- residue += count << jzchan->transfer_shift;
- }
+ if (next_sg != 0)
+ count += jz4780_dma_chn_readl(jzdma, jzchan->id,
+ JZ_DMA_REG_DTC);
- return residue;
+ return count << jzchan->transfer_shift;
}
static enum dma_status jz4780_dma_tx_status(struct dma_chan *chan,
@@ -573,6 +639,7 @@ static enum dma_status jz4780_dma_tx_status(struct dma_chan *chan,
struct virt_dma_desc *vdesc;
enum dma_status status;
unsigned long flags;
+ unsigned long residue = 0;
status = dma_cookie_status(chan, cookie, txstate);
if ((status == DMA_COMPLETE) || (txstate == NULL))
@@ -583,13 +650,13 @@ static enum dma_status jz4780_dma_tx_status(struct dma_chan *chan,
vdesc = vchan_find_desc(&jzchan->vchan, cookie);
if (vdesc) {
/* On the issued list, so hasn't been processed yet */
- txstate->residue = jz4780_dma_desc_residue(jzchan,
+ residue = jz4780_dma_desc_residue(jzchan,
to_jz4780_dma_desc(vdesc), 0);
} else if (cookie == jzchan->desc->vdesc.tx.cookie) {
- txstate->residue = jz4780_dma_desc_residue(jzchan, jzchan->desc,
- (jzchan->curr_hwdesc + 1) % jzchan->desc->count);
- } else
- txstate->residue = 0;
+ residue = jz4780_dma_desc_residue(jzchan, jzchan->desc,
+ jzchan->curr_hwdesc + 1);
+ }
+ dma_set_residue(txstate, residue);
if (vdesc && jzchan->desc && vdesc == &jzchan->desc->vdesc
&& jzchan->desc->status & (JZ_DMA_DCS_AR | JZ_DMA_DCS_HLT))
@@ -606,8 +673,8 @@ static void jz4780_dma_chan_irq(struct jz4780_dma_dev *jzdma,
spin_lock(&jzchan->vchan.lock);
- dcs = jz4780_dma_readl(jzdma, JZ_DMA_REG_DCS(jzchan->id));
- jz4780_dma_writel(jzdma, JZ_DMA_REG_DCS(jzchan->id), 0);
+ dcs = jz4780_dma_chn_readl(jzdma, jzchan->id, JZ_DMA_REG_DCS);
+ jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DCS, 0);
if (dcs & JZ_DMA_DCS_AR) {
dev_warn(&jzchan->vchan.chan.dev->device,
@@ -646,9 +713,9 @@ static irqreturn_t jz4780_dma_irq_handler(int irq, void *data)
uint32_t pending, dmac;
int i;
- pending = jz4780_dma_readl(jzdma, JZ_DMA_REG_DIRQP);
+ pending = jz4780_dma_ctrl_readl(jzdma, JZ_DMA_REG_DIRQP);
- for (i = 0; i < JZ_DMA_NR_CHANNELS; i++) {
+ for (i = 0; i < jzdma->soc_data->nb_channels; i++) {
if (!(pending & (1<<i)))
continue;
@@ -656,12 +723,12 @@ static irqreturn_t jz4780_dma_irq_handler(int irq, void *data)
}
/* Clear halt and address error status of all channels. */
- dmac = jz4780_dma_readl(jzdma, JZ_DMA_REG_DMAC);
+ dmac = jz4780_dma_ctrl_readl(jzdma, JZ_DMA_REG_DMAC);
dmac &= ~(JZ_DMA_DMAC_HLT | JZ_DMA_DMAC_AR);
- jz4780_dma_writel(jzdma, JZ_DMA_REG_DMAC, dmac);
+ jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DMAC, dmac);
/* Clear interrupt pending status. */
- jz4780_dma_writel(jzdma, JZ_DMA_REG_DIRQP, 0);
+ jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DIRQP, 0);
return IRQ_HANDLED;
}
@@ -728,7 +795,7 @@ static struct dma_chan *jz4780_of_dma_xlate(struct of_phandle_args *dma_spec,
data.channel = dma_spec->args[1];
if (data.channel > -1) {
- if (data.channel >= JZ_DMA_NR_CHANNELS) {
+ if (data.channel >= jzdma->soc_data->nb_channels) {
dev_err(jzdma->dma_device.dev,
"device requested non-existent channel %u\n",
data.channel);
@@ -755,16 +822,29 @@ static struct dma_chan *jz4780_of_dma_xlate(struct of_phandle_args *dma_spec,
static int jz4780_dma_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ const struct jz4780_dma_soc_data *soc_data;
struct jz4780_dma_dev *jzdma;
struct jz4780_dma_chan *jzchan;
struct dma_device *dd;
struct resource *res;
int i, ret;
- jzdma = devm_kzalloc(dev, sizeof(*jzdma), GFP_KERNEL);
+ if (!dev->of_node) {
+ dev_err(dev, "This driver must be probed from devicetree\n");
+ return -EINVAL;
+ }
+
+ soc_data = device_get_match_data(dev);
+ if (!soc_data)
+ return -EINVAL;
+
+ jzdma = devm_kzalloc(dev, sizeof(*jzdma)
+ + sizeof(*jzdma->chan) * soc_data->nb_channels,
+ GFP_KERNEL);
if (!jzdma)
return -ENOMEM;
+ jzdma->soc_data = soc_data;
platform_set_drvdata(pdev, jzdma);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -773,9 +853,26 @@ static int jz4780_dma_probe(struct platform_device *pdev)
return -EINVAL;
}
- jzdma->base = devm_ioremap_resource(dev, res);
- if (IS_ERR(jzdma->base))
- return PTR_ERR(jzdma->base);
+ jzdma->chn_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(jzdma->chn_base))
+ return PTR_ERR(jzdma->chn_base);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (res) {
+ jzdma->ctrl_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(jzdma->ctrl_base))
+ return PTR_ERR(jzdma->ctrl_base);
+ } else if (soc_data->flags & JZ_SOC_DATA_ALLOW_LEGACY_DT) {
+ /*
+ * On JZ4780, if the second memory resource was not supplied,
+ * assume we're using an old devicetree, and calculate the
+ * offset to the control registers.
+ */
+ jzdma->ctrl_base = jzdma->chn_base + JZ4780_DMA_CTRL_OFFSET;
+ } else {
+ dev_err(dev, "failed to get I/O memory\n");
+ return -EINVAL;
+ }
ret = platform_get_irq(pdev, 0);
if (ret < 0) {
@@ -833,13 +930,15 @@ static int jz4780_dma_probe(struct platform_device *pdev)
* Also set the FMSC bit - it increases MSC performance, so it makes
* little sense not to enable it.
*/
- jz4780_dma_writel(jzdma, JZ_DMA_REG_DMAC,
- JZ_DMA_DMAC_DMAE | JZ_DMA_DMAC_FMSC);
- jz4780_dma_writel(jzdma, JZ_DMA_REG_DMACP, 0);
+ jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DMAC, JZ_DMA_DMAC_DMAE |
+ JZ_DMA_DMAC_FAIC | JZ_DMA_DMAC_FMSC);
+
+ if (soc_data->flags & JZ_SOC_DATA_PROGRAMMABLE_DMA)
+ jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DMACP, 0);
INIT_LIST_HEAD(&dd->channels);
- for (i = 0; i < JZ_DMA_NR_CHANNELS; i++) {
+ for (i = 0; i < soc_data->nb_channels; i++) {
jzchan = &jzdma->chan[i];
jzchan->id = i;
@@ -847,7 +946,7 @@ static int jz4780_dma_probe(struct platform_device *pdev)
jzchan->vchan.desc_free = jz4780_dma_desc_free;
}
- ret = dma_async_device_register(dd);
+ ret = dmaenginem_async_device_register(dd);
if (ret) {
dev_err(dev, "failed to register device\n");
goto err_disable_clk;
@@ -858,15 +957,12 @@ static int jz4780_dma_probe(struct platform_device *pdev)
jzdma);
if (ret) {
dev_err(dev, "failed to register OF DMA controller\n");
- goto err_unregister_dev;
+ goto err_disable_clk;
}
dev_info(dev, "JZ4780 DMA controller initialised\n");
return 0;
-err_unregister_dev:
- dma_async_device_unregister(dd);
-
err_disable_clk:
clk_disable_unprepare(jzdma->clk);
@@ -884,15 +980,40 @@ static int jz4780_dma_remove(struct platform_device *pdev)
free_irq(jzdma->irq, jzdma);
- for (i = 0; i < JZ_DMA_NR_CHANNELS; i++)
+ for (i = 0; i < jzdma->soc_data->nb_channels; i++)
tasklet_kill(&jzdma->chan[i].vchan.task);
- dma_async_device_unregister(&jzdma->dma_device);
return 0;
}
+static const struct jz4780_dma_soc_data jz4740_dma_soc_data = {
+ .nb_channels = 6,
+ .transfer_ord_max = 5,
+};
+
+static const struct jz4780_dma_soc_data jz4725b_dma_soc_data = {
+ .nb_channels = 6,
+ .transfer_ord_max = 5,
+ .flags = JZ_SOC_DATA_PER_CHAN_PM | JZ_SOC_DATA_NO_DCKES_DCKEC,
+};
+
+static const struct jz4780_dma_soc_data jz4770_dma_soc_data = {
+ .nb_channels = 6,
+ .transfer_ord_max = 6,
+ .flags = JZ_SOC_DATA_PER_CHAN_PM,
+};
+
+static const struct jz4780_dma_soc_data jz4780_dma_soc_data = {
+ .nb_channels = 32,
+ .transfer_ord_max = 7,
+ .flags = JZ_SOC_DATA_ALLOW_LEGACY_DT | JZ_SOC_DATA_PROGRAMMABLE_DMA,
+};
+
static const struct of_device_id jz4780_dma_dt_match[] = {
- { .compatible = "ingenic,jz4780-dma", .data = NULL },
+ { .compatible = "ingenic,jz4740-dma", .data = &jz4740_dma_soc_data },
+ { .compatible = "ingenic,jz4725b-dma", .data = &jz4725b_dma_soc_data },
+ { .compatible = "ingenic,jz4770-dma", .data = &jz4770_dma_soc_data },
+ { .compatible = "ingenic,jz4780-dma", .data = &jz4780_dma_soc_data },
{},
};
MODULE_DEVICE_TABLE(of, jz4780_dma_dt_match);
diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
index c4eb55e3011c..b2ac1d2c5b86 100644
--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
@@ -934,7 +934,7 @@ static int dw_probe(struct platform_device *pdev)
pm_runtime_put(chip->dev);
- ret = dma_async_device_register(&dw->dma);
+ ret = dmaenginem_async_device_register(&dw->dma);
if (ret)
goto err_pm_disable;
@@ -977,8 +977,6 @@ static int dw_remove(struct platform_device *pdev)
tasklet_kill(&chan->vc.task);
}
- dma_async_device_unregister(&dw->dma);
-
return 0;
}
diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c
index f43e6dafe446..d0c3e50b39fb 100644
--- a/drivers/dma/dw/core.c
+++ b/drivers/dma/dw/core.c
@@ -886,12 +886,7 @@ static int dwc_config(struct dma_chan *chan, struct dma_slave_config *sconfig)
*/
u32 s = dw->pdata->is_idma32 ? 1 : 2;
- /* Check if chan will be configured for slave transfers */
- if (!is_slave_direction(sconfig->direction))
- return -EINVAL;
-
memcpy(&dwc->dma_sconfig, sconfig, sizeof(*sconfig));
- dwc->direction = sconfig->direction;
sc->src_maxburst = sc->src_maxburst > 1 ? fls(sc->src_maxburst) - s : 0;
sc->dst_maxburst = sc->dst_maxburst > 1 ? fls(sc->dst_maxburst) - s : 0;
diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c
index f62dd0944908..f01b2c173fa6 100644
--- a/drivers/dma/dw/platform.c
+++ b/drivers/dma/dw/platform.c
@@ -284,6 +284,8 @@ MODULE_DEVICE_TABLE(of, dw_dma_of_id_table);
#ifdef CONFIG_ACPI
static const struct acpi_device_id dw_dma_acpi_id_table[] = {
{ "INTL9C60", 0 },
+ { "80862286", 0 },
+ { "808622C0", 0 },
{ }
};
MODULE_DEVICE_TABLE(acpi, dw_dma_acpi_id_table);
diff --git a/drivers/dma/ep93xx_dma.c b/drivers/dma/ep93xx_dma.c
index a15592383d4e..f674eb5fbbef 100644
--- a/drivers/dma/ep93xx_dma.c
+++ b/drivers/dma/ep93xx_dma.c
@@ -109,6 +109,9 @@
#define DMA_MAX_CHAN_DESCRIPTORS 32
struct ep93xx_dma_engine;
+static int ep93xx_dma_slave_config_write(struct dma_chan *chan,
+ enum dma_transfer_direction dir,
+ struct dma_slave_config *config);
/**
* struct ep93xx_dma_desc - EP93xx specific transaction descriptor
@@ -180,6 +183,7 @@ struct ep93xx_dma_chan {
struct list_head free_list;
u32 runtime_addr;
u32 runtime_ctrl;
+ struct dma_slave_config slave_config;
};
/**
@@ -1051,6 +1055,8 @@ ep93xx_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
return NULL;
}
+ ep93xx_dma_slave_config_write(chan, dir, &edmac->slave_config);
+
first = NULL;
for_each_sg(sgl, sg, sg_len, i) {
size_t len = sg_dma_len(sg);
@@ -1136,6 +1142,8 @@ ep93xx_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t dma_addr,
return NULL;
}
+ ep93xx_dma_slave_config_write(chan, dir, &edmac->slave_config);
+
/* Split the buffer into period size chunks */
first = NULL;
for (offset = 0; offset < buf_len; offset += period_len) {
@@ -1227,6 +1235,17 @@ static int ep93xx_dma_slave_config(struct dma_chan *chan,
struct dma_slave_config *config)
{
struct ep93xx_dma_chan *edmac = to_ep93xx_dma_chan(chan);
+
+ memcpy(&edmac->slave_config, config, sizeof(*config));
+
+ return 0;
+}
+
+static int ep93xx_dma_slave_config_write(struct dma_chan *chan,
+ enum dma_transfer_direction dir,
+ struct dma_slave_config *config)
+{
+ struct ep93xx_dma_chan *edmac = to_ep93xx_dma_chan(chan);
enum dma_slave_buswidth width;
unsigned long flags;
u32 addr, ctrl;
@@ -1234,7 +1253,7 @@ static int ep93xx_dma_slave_config(struct dma_chan *chan,
if (!edmac->edma->m2m)
return -EINVAL;
- switch (config->direction) {
+ switch (dir) {
case DMA_DEV_TO_MEM:
width = config->src_addr_width;
addr = config->src_addr;
diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c
new file mode 100644
index 000000000000..8876c4c1bb2c
--- /dev/null
+++ b/drivers/dma/fsl-edma-common.c
@@ -0,0 +1,626 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Copyright (c) 2013-2014 Freescale Semiconductor, Inc
+// Copyright (c) 2017 Sysam, Angelo Dureghello <angelo@sysam.it>
+
+#include <linux/dmapool.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include "fsl-edma-common.h"
+
+#define EDMA_CR 0x00
+#define EDMA_ES 0x04
+#define EDMA_ERQ 0x0C
+#define EDMA_EEI 0x14
+#define EDMA_SERQ 0x1B
+#define EDMA_CERQ 0x1A
+#define EDMA_SEEI 0x19
+#define EDMA_CEEI 0x18
+#define EDMA_CINT 0x1F
+#define EDMA_CERR 0x1E
+#define EDMA_SSRT 0x1D
+#define EDMA_CDNE 0x1C
+#define EDMA_INTR 0x24
+#define EDMA_ERR 0x2C
+
+#define EDMA64_ERQH 0x08
+#define EDMA64_EEIH 0x10
+#define EDMA64_SERQ 0x18
+#define EDMA64_CERQ 0x19
+#define EDMA64_SEEI 0x1a
+#define EDMA64_CEEI 0x1b
+#define EDMA64_CINT 0x1c
+#define EDMA64_CERR 0x1d
+#define EDMA64_SSRT 0x1e
+#define EDMA64_CDNE 0x1f
+#define EDMA64_INTH 0x20
+#define EDMA64_INTL 0x24
+#define EDMA64_ERRH 0x28
+#define EDMA64_ERRL 0x2c
+
+#define EDMA_TCD 0x1000
+
+static void fsl_edma_enable_request(struct fsl_edma_chan *fsl_chan)
+{
+ struct edma_regs *regs = &fsl_chan->edma->regs;
+ u32 ch = fsl_chan->vchan.chan.chan_id;
+
+ if (fsl_chan->edma->version == v1) {
+ edma_writeb(fsl_chan->edma, EDMA_SEEI_SEEI(ch), regs->seei);
+ edma_writeb(fsl_chan->edma, ch, regs->serq);
+ } else {
+ /* ColdFire is big endian, and accesses natively
+ * big endian I/O peripherals
+ */
+ iowrite8(EDMA_SEEI_SEEI(ch), regs->seei);
+ iowrite8(ch, regs->serq);
+ }
+}
+
+void fsl_edma_disable_request(struct fsl_edma_chan *fsl_chan)
+{
+ struct edma_regs *regs = &fsl_chan->edma->regs;
+ u32 ch = fsl_chan->vchan.chan.chan_id;
+
+ if (fsl_chan->edma->version == v1) {
+ edma_writeb(fsl_chan->edma, ch, regs->cerq);
+ edma_writeb(fsl_chan->edma, EDMA_CEEI_CEEI(ch), regs->ceei);
+ } else {
+ /* ColdFire is big endian, and accesses natively
+ * big endian I/O peripherals
+ */
+ iowrite8(ch, regs->cerq);
+ iowrite8(EDMA_CEEI_CEEI(ch), regs->ceei);
+ }
+}
+EXPORT_SYMBOL_GPL(fsl_edma_disable_request);
+
+void fsl_edma_chan_mux(struct fsl_edma_chan *fsl_chan,
+ unsigned int slot, bool enable)
+{
+ u32 ch = fsl_chan->vchan.chan.chan_id;
+ void __iomem *muxaddr;
+ unsigned int chans_per_mux, ch_off;
+
+ chans_per_mux = fsl_chan->edma->n_chans / DMAMUX_NR;
+ ch_off = fsl_chan->vchan.chan.chan_id % chans_per_mux;
+ muxaddr = fsl_chan->edma->muxbase[ch / chans_per_mux];
+ slot = EDMAMUX_CHCFG_SOURCE(slot);
+
+ if (enable)
+ iowrite8(EDMAMUX_CHCFG_ENBL | slot, muxaddr + ch_off);
+ else
+ iowrite8(EDMAMUX_CHCFG_DIS, muxaddr + ch_off);
+}
+EXPORT_SYMBOL_GPL(fsl_edma_chan_mux);
+
+static unsigned int fsl_edma_get_tcd_attr(enum dma_slave_buswidth addr_width)
+{
+ switch (addr_width) {
+ case 1:
+ return EDMA_TCD_ATTR_SSIZE_8BIT | EDMA_TCD_ATTR_DSIZE_8BIT;
+ case 2:
+ return EDMA_TCD_ATTR_SSIZE_16BIT | EDMA_TCD_ATTR_DSIZE_16BIT;
+ case 4:
+ return EDMA_TCD_ATTR_SSIZE_32BIT | EDMA_TCD_ATTR_DSIZE_32BIT;
+ case 8:
+ return EDMA_TCD_ATTR_SSIZE_64BIT | EDMA_TCD_ATTR_DSIZE_64BIT;
+ default:
+ return EDMA_TCD_ATTR_SSIZE_32BIT | EDMA_TCD_ATTR_DSIZE_32BIT;
+ }
+}
+
+void fsl_edma_free_desc(struct virt_dma_desc *vdesc)
+{
+ struct fsl_edma_desc *fsl_desc;
+ int i;
+
+ fsl_desc = to_fsl_edma_desc(vdesc);
+ for (i = 0; i < fsl_desc->n_tcds; i++)
+ dma_pool_free(fsl_desc->echan->tcd_pool, fsl_desc->tcd[i].vtcd,
+ fsl_desc->tcd[i].ptcd);
+ kfree(fsl_desc);
+}
+EXPORT_SYMBOL_GPL(fsl_edma_free_desc);
+
+int fsl_edma_terminate_all(struct dma_chan *chan)
+{
+ struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+ unsigned long flags;
+ LIST_HEAD(head);
+
+ spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+ fsl_edma_disable_request(fsl_chan);
+ fsl_chan->edesc = NULL;
+ fsl_chan->idle = true;
+ vchan_get_all_descriptors(&fsl_chan->vchan, &head);
+ spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+ vchan_dma_desc_free_list(&fsl_chan->vchan, &head);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(fsl_edma_terminate_all);
+
+int fsl_edma_pause(struct dma_chan *chan)
+{
+ struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+ unsigned long flags;
+
+ spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+ if (fsl_chan->edesc) {
+ fsl_edma_disable_request(fsl_chan);
+ fsl_chan->status = DMA_PAUSED;
+ fsl_chan->idle = true;
+ }
+ spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(fsl_edma_pause);
+
+int fsl_edma_resume(struct dma_chan *chan)
+{
+ struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+ unsigned long flags;
+
+ spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+ if (fsl_chan->edesc) {
+ fsl_edma_enable_request(fsl_chan);
+ fsl_chan->status = DMA_IN_PROGRESS;
+ fsl_chan->idle = false;
+ }
+ spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(fsl_edma_resume);
+
+int fsl_edma_slave_config(struct dma_chan *chan,
+ struct dma_slave_config *cfg)
+{
+ struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+
+ memcpy(&fsl_chan->cfg, cfg, sizeof(*cfg));
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(fsl_edma_slave_config);
+
+static size_t fsl_edma_desc_residue(struct fsl_edma_chan *fsl_chan,
+ struct virt_dma_desc *vdesc, bool in_progress)
+{
+ struct fsl_edma_desc *edesc = fsl_chan->edesc;
+ struct edma_regs *regs = &fsl_chan->edma->regs;
+ u32 ch = fsl_chan->vchan.chan.chan_id;
+ enum dma_transfer_direction dir = edesc->dirn;
+ dma_addr_t cur_addr, dma_addr;
+ size_t len, size;
+ int i;
+
+ /* calculate the total size in this desc */
+ for (len = i = 0; i < fsl_chan->edesc->n_tcds; i++)
+ len += le32_to_cpu(edesc->tcd[i].vtcd->nbytes)
+ * le16_to_cpu(edesc->tcd[i].vtcd->biter);
+
+ if (!in_progress)
+ return len;
+
+ if (dir == DMA_MEM_TO_DEV)
+ cur_addr = edma_readl(fsl_chan->edma, &regs->tcd[ch].saddr);
+ else
+ cur_addr = edma_readl(fsl_chan->edma, &regs->tcd[ch].daddr);
+
+ /* figure out the finished and calculate the residue */
+ for (i = 0; i < fsl_chan->edesc->n_tcds; i++) {
+ size = le32_to_cpu(edesc->tcd[i].vtcd->nbytes)
+ * le16_to_cpu(edesc->tcd[i].vtcd->biter);
+ if (dir == DMA_MEM_TO_DEV)
+ dma_addr = le32_to_cpu(edesc->tcd[i].vtcd->saddr);
+ else
+ dma_addr = le32_to_cpu(edesc->tcd[i].vtcd->daddr);
+
+ len -= size;
+ if (cur_addr >= dma_addr && cur_addr < dma_addr + size) {
+ len += dma_addr + size - cur_addr;
+ break;
+ }
+ }
+
+ return len;
+}
+
+enum dma_status fsl_edma_tx_status(struct dma_chan *chan,
+ dma_cookie_t cookie, struct dma_tx_state *txstate)
+{
+ struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+ struct virt_dma_desc *vdesc;
+ enum dma_status status;
+ unsigned long flags;
+
+ status = dma_cookie_status(chan, cookie, txstate);
+ if (status == DMA_COMPLETE)
+ return status;
+
+ if (!txstate)
+ return fsl_chan->status;
+
+ spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+ vdesc = vchan_find_desc(&fsl_chan->vchan, cookie);
+ if (fsl_chan->edesc && cookie == fsl_chan->edesc->vdesc.tx.cookie)
+ txstate->residue =
+ fsl_edma_desc_residue(fsl_chan, vdesc, true);
+ else if (vdesc)
+ txstate->residue =
+ fsl_edma_desc_residue(fsl_chan, vdesc, false);
+ else
+ txstate->residue = 0;
+
+ spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+
+ return fsl_chan->status;
+}
+EXPORT_SYMBOL_GPL(fsl_edma_tx_status);
+
+static void fsl_edma_set_tcd_regs(struct fsl_edma_chan *fsl_chan,
+ struct fsl_edma_hw_tcd *tcd)
+{
+ struct fsl_edma_engine *edma = fsl_chan->edma;
+ struct edma_regs *regs = &fsl_chan->edma->regs;
+ u32 ch = fsl_chan->vchan.chan.chan_id;
+
+ /*
+ * TCD parameters are stored in struct fsl_edma_hw_tcd in little
+ * endian format. However, we need to load the TCD registers in
+ * big- or little-endian obeying the eDMA engine model endian.
+ */
+ edma_writew(edma, 0, &regs->tcd[ch].csr);
+ edma_writel(edma, le32_to_cpu(tcd->saddr), &regs->tcd[ch].saddr);
+ edma_writel(edma, le32_to_cpu(tcd->daddr), &regs->tcd[ch].daddr);
+
+ edma_writew(edma, le16_to_cpu(tcd->attr), &regs->tcd[ch].attr);
+ edma_writew(edma, le16_to_cpu(tcd->soff), &regs->tcd[ch].soff);
+
+ edma_writel(edma, le32_to_cpu(tcd->nbytes), &regs->tcd[ch].nbytes);
+ edma_writel(edma, le32_to_cpu(tcd->slast), &regs->tcd[ch].slast);
+
+ edma_writew(edma, le16_to_cpu(tcd->citer), &regs->tcd[ch].citer);
+ edma_writew(edma, le16_to_cpu(tcd->biter), &regs->tcd[ch].biter);
+ edma_writew(edma, le16_to_cpu(tcd->doff), &regs->tcd[ch].doff);
+
+ edma_writel(edma, le32_to_cpu(tcd->dlast_sga),
+ &regs->tcd[ch].dlast_sga);
+
+ edma_writew(edma, le16_to_cpu(tcd->csr), &regs->tcd[ch].csr);
+}
+
+static inline
+void fsl_edma_fill_tcd(struct fsl_edma_hw_tcd *tcd, u32 src, u32 dst,
+ u16 attr, u16 soff, u32 nbytes, u32 slast, u16 citer,
+ u16 biter, u16 doff, u32 dlast_sga, bool major_int,
+ bool disable_req, bool enable_sg)
+{
+ u16 csr = 0;
+
+ /*
+ * eDMA hardware SGs require the TCDs to be stored in little
+ * endian format irrespective of the register endian model.
+ * So we put the value in little endian in memory, waiting
+ * for fsl_edma_set_tcd_regs doing the swap.
+ */
+ tcd->saddr = cpu_to_le32(src);
+ tcd->daddr = cpu_to_le32(dst);
+
+ tcd->attr = cpu_to_le16(attr);
+
+ tcd->soff = cpu_to_le16(soff);
+
+ tcd->nbytes = cpu_to_le32(nbytes);
+ tcd->slast = cpu_to_le32(slast);
+
+ tcd->citer = cpu_to_le16(EDMA_TCD_CITER_CITER(citer));
+ tcd->doff = cpu_to_le16(doff);
+
+ tcd->dlast_sga = cpu_to_le32(dlast_sga);
+
+ tcd->biter = cpu_to_le16(EDMA_TCD_BITER_BITER(biter));
+ if (major_int)
+ csr |= EDMA_TCD_CSR_INT_MAJOR;
+
+ if (disable_req)
+ csr |= EDMA_TCD_CSR_D_REQ;
+
+ if (enable_sg)
+ csr |= EDMA_TCD_CSR_E_SG;
+
+ tcd->csr = cpu_to_le16(csr);
+}
+
+static struct fsl_edma_desc *fsl_edma_alloc_desc(struct fsl_edma_chan *fsl_chan,
+ int sg_len)
+{
+ struct fsl_edma_desc *fsl_desc;
+ int i;
+
+ fsl_desc = kzalloc(sizeof(*fsl_desc) +
+ sizeof(struct fsl_edma_sw_tcd) *
+ sg_len, GFP_NOWAIT);
+ if (!fsl_desc)
+ return NULL;
+
+ fsl_desc->echan = fsl_chan;
+ fsl_desc->n_tcds = sg_len;
+ for (i = 0; i < sg_len; i++) {
+ fsl_desc->tcd[i].vtcd = dma_pool_alloc(fsl_chan->tcd_pool,
+ GFP_NOWAIT, &fsl_desc->tcd[i].ptcd);
+ if (!fsl_desc->tcd[i].vtcd)
+ goto err;
+ }
+ return fsl_desc;
+
+err:
+ while (--i >= 0)
+ dma_pool_free(fsl_chan->tcd_pool, fsl_desc->tcd[i].vtcd,
+ fsl_desc->tcd[i].ptcd);
+ kfree(fsl_desc);
+ return NULL;
+}
+
+struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic(
+ struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
+ size_t period_len, enum dma_transfer_direction direction,
+ unsigned long flags)
+{
+ struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+ struct fsl_edma_desc *fsl_desc;
+ dma_addr_t dma_buf_next;
+ int sg_len, i;
+ u32 src_addr, dst_addr, last_sg, nbytes;
+ u16 soff, doff, iter;
+
+ if (!is_slave_direction(direction))
+ return NULL;
+
+ sg_len = buf_len / period_len;
+ fsl_desc = fsl_edma_alloc_desc(fsl_chan, sg_len);
+ if (!fsl_desc)
+ return NULL;
+ fsl_desc->iscyclic = true;
+ fsl_desc->dirn = direction;
+
+ dma_buf_next = dma_addr;
+ if (direction == DMA_MEM_TO_DEV) {
+ fsl_chan->attr =
+ fsl_edma_get_tcd_attr(fsl_chan->cfg.dst_addr_width);
+ nbytes = fsl_chan->cfg.dst_addr_width *
+ fsl_chan->cfg.dst_maxburst;
+ } else {
+ fsl_chan->attr =
+ fsl_edma_get_tcd_attr(fsl_chan->cfg.src_addr_width);
+ nbytes = fsl_chan->cfg.src_addr_width *
+ fsl_chan->cfg.src_maxburst;
+ }
+
+ iter = period_len / nbytes;
+
+ for (i = 0; i < sg_len; i++) {
+ if (dma_buf_next >= dma_addr + buf_len)
+ dma_buf_next = dma_addr;
+
+ /* get next sg's physical address */
+ last_sg = fsl_desc->tcd[(i + 1) % sg_len].ptcd;
+
+ if (direction == DMA_MEM_TO_DEV) {
+ src_addr = dma_buf_next;
+ dst_addr = fsl_chan->cfg.dst_addr;
+ soff = fsl_chan->cfg.dst_addr_width;
+ doff = 0;
+ } else {
+ src_addr = fsl_chan->cfg.src_addr;
+ dst_addr = dma_buf_next;
+ soff = 0;
+ doff = fsl_chan->cfg.src_addr_width;
+ }
+
+ fsl_edma_fill_tcd(fsl_desc->tcd[i].vtcd, src_addr, dst_addr,
+ fsl_chan->attr, soff, nbytes, 0, iter,
+ iter, doff, last_sg, true, false, true);
+ dma_buf_next += period_len;
+ }
+
+ return vchan_tx_prep(&fsl_chan->vchan, &fsl_desc->vdesc, flags);
+}
+EXPORT_SYMBOL_GPL(fsl_edma_prep_dma_cyclic);
+
+struct dma_async_tx_descriptor *fsl_edma_prep_slave_sg(
+ struct dma_chan *chan, struct scatterlist *sgl,
+ unsigned int sg_len, enum dma_transfer_direction direction,
+ unsigned long flags, void *context)
+{
+ struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+ struct fsl_edma_desc *fsl_desc;
+ struct scatterlist *sg;
+ u32 src_addr, dst_addr, last_sg, nbytes;
+ u16 soff, doff, iter;
+ int i;
+
+ if (!is_slave_direction(direction))
+ return NULL;
+
+ fsl_desc = fsl_edma_alloc_desc(fsl_chan, sg_len);
+ if (!fsl_desc)
+ return NULL;
+ fsl_desc->iscyclic = false;
+ fsl_desc->dirn = direction;
+
+ if (direction == DMA_MEM_TO_DEV) {
+ fsl_chan->attr =
+ fsl_edma_get_tcd_attr(fsl_chan->cfg.dst_addr_width);
+ nbytes = fsl_chan->cfg.dst_addr_width *
+ fsl_chan->cfg.dst_maxburst;
+ } else {
+ fsl_chan->attr =
+ fsl_edma_get_tcd_attr(fsl_chan->cfg.src_addr_width);
+ nbytes = fsl_chan->cfg.src_addr_width *
+ fsl_chan->cfg.src_maxburst;
+ }
+
+ for_each_sg(sgl, sg, sg_len, i) {
+ /* get next sg's physical address */
+ last_sg = fsl_desc->tcd[(i + 1) % sg_len].ptcd;
+
+ if (direction == DMA_MEM_TO_DEV) {
+ src_addr = sg_dma_address(sg);
+ dst_addr = fsl_chan->cfg.dst_addr;
+ soff = fsl_chan->cfg.dst_addr_width;
+ doff = 0;
+ } else {
+ src_addr = fsl_chan->cfg.src_addr;
+ dst_addr = sg_dma_address(sg);
+ soff = 0;
+ doff = fsl_chan->cfg.src_addr_width;
+ }
+
+ iter = sg_dma_len(sg) / nbytes;
+ if (i < sg_len - 1) {
+ last_sg = fsl_desc->tcd[(i + 1)].ptcd;
+ fsl_edma_fill_tcd(fsl_desc->tcd[i].vtcd, src_addr,
+ dst_addr, fsl_chan->attr, soff,
+ nbytes, 0, iter, iter, doff, last_sg,
+ false, false, true);
+ } else {
+ last_sg = 0;
+ fsl_edma_fill_tcd(fsl_desc->tcd[i].vtcd, src_addr,
+ dst_addr, fsl_chan->attr, soff,
+ nbytes, 0, iter, iter, doff, last_sg,
+ true, true, false);
+ }
+ }
+
+ return vchan_tx_prep(&fsl_chan->vchan, &fsl_desc->vdesc, flags);
+}
+EXPORT_SYMBOL_GPL(fsl_edma_prep_slave_sg);
+
+void fsl_edma_xfer_desc(struct fsl_edma_chan *fsl_chan)
+{
+ struct virt_dma_desc *vdesc;
+
+ vdesc = vchan_next_desc(&fsl_chan->vchan);
+ if (!vdesc)
+ return;
+ fsl_chan->edesc = to_fsl_edma_desc(vdesc);
+ fsl_edma_set_tcd_regs(fsl_chan, fsl_chan->edesc->tcd[0].vtcd);
+ fsl_edma_enable_request(fsl_chan);
+ fsl_chan->status = DMA_IN_PROGRESS;
+ fsl_chan->idle = false;
+}
+EXPORT_SYMBOL_GPL(fsl_edma_xfer_desc);
+
+void fsl_edma_issue_pending(struct dma_chan *chan)
+{
+ struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+ unsigned long flags;
+
+ spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+
+ if (unlikely(fsl_chan->pm_state != RUNNING)) {
+ spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+ /* cannot submit due to suspend */
+ return;
+ }
+
+ if (vchan_issue_pending(&fsl_chan->vchan) && !fsl_chan->edesc)
+ fsl_edma_xfer_desc(fsl_chan);
+
+ spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+}
+EXPORT_SYMBOL_GPL(fsl_edma_issue_pending);
+
+int fsl_edma_alloc_chan_resources(struct dma_chan *chan)
+{
+ struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+
+ fsl_chan->tcd_pool = dma_pool_create("tcd_pool", chan->device->dev,
+ sizeof(struct fsl_edma_hw_tcd),
+ 32, 0);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(fsl_edma_alloc_chan_resources);
+
+void fsl_edma_free_chan_resources(struct dma_chan *chan)
+{
+ struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+ unsigned long flags;
+ LIST_HEAD(head);
+
+ spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+ fsl_edma_disable_request(fsl_chan);
+ fsl_edma_chan_mux(fsl_chan, 0, false);
+ fsl_chan->edesc = NULL;
+ vchan_get_all_descriptors(&fsl_chan->vchan, &head);
+ spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+
+ vchan_dma_desc_free_list(&fsl_chan->vchan, &head);
+ dma_pool_destroy(fsl_chan->tcd_pool);
+ fsl_chan->tcd_pool = NULL;
+}
+EXPORT_SYMBOL_GPL(fsl_edma_free_chan_resources);
+
+void fsl_edma_cleanup_vchan(struct dma_device *dmadev)
+{
+ struct fsl_edma_chan *chan, *_chan;
+
+ list_for_each_entry_safe(chan, _chan,
+ &dmadev->channels, vchan.chan.device_node) {
+ list_del(&chan->vchan.chan.device_node);
+ tasklet_kill(&chan->vchan.task);
+ }
+}
+EXPORT_SYMBOL_GPL(fsl_edma_cleanup_vchan);
+
+/*
+ * On the 32 channels Vybrid/mpc577x edma version (here called "v1"),
+ * register offsets are different compared to ColdFire mcf5441x 64 channels
+ * edma (here called "v2").
+ *
+ * This function sets up register offsets as per proper declared version
+ * so must be called in xxx_edma_probe() just after setting the
+ * edma "version" and "membase" appropriately.
+ */
+void fsl_edma_setup_regs(struct fsl_edma_engine *edma)
+{
+ edma->regs.cr = edma->membase + EDMA_CR;
+ edma->regs.es = edma->membase + EDMA_ES;
+ edma->regs.erql = edma->membase + EDMA_ERQ;
+ edma->regs.eeil = edma->membase + EDMA_EEI;
+
+ edma->regs.serq = edma->membase + ((edma->version == v1) ?
+ EDMA_SERQ : EDMA64_SERQ);
+ edma->regs.cerq = edma->membase + ((edma->version == v1) ?
+ EDMA_CERQ : EDMA64_CERQ);
+ edma->regs.seei = edma->membase + ((edma->version == v1) ?
+ EDMA_SEEI : EDMA64_SEEI);
+ edma->regs.ceei = edma->membase + ((edma->version == v1) ?
+ EDMA_CEEI : EDMA64_CEEI);
+ edma->regs.cint = edma->membase + ((edma->version == v1) ?
+ EDMA_CINT : EDMA64_CINT);
+ edma->regs.cerr = edma->membase + ((edma->version == v1) ?
+ EDMA_CERR : EDMA64_CERR);
+ edma->regs.ssrt = edma->membase + ((edma->version == v1) ?
+ EDMA_SSRT : EDMA64_SSRT);
+ edma->regs.cdne = edma->membase + ((edma->version == v1) ?
+ EDMA_CDNE : EDMA64_CDNE);
+ edma->regs.intl = edma->membase + ((edma->version == v1) ?
+ EDMA_INTR : EDMA64_INTL);
+ edma->regs.errl = edma->membase + ((edma->version == v1) ?
+ EDMA_ERR : EDMA64_ERRL);
+
+ if (edma->version == v2) {
+ edma->regs.erqh = edma->membase + EDMA64_ERQH;
+ edma->regs.eeih = edma->membase + EDMA64_EEIH;
+ edma->regs.errh = edma->membase + EDMA64_ERRH;
+ edma->regs.inth = edma->membase + EDMA64_INTH;
+ }
+
+ edma->regs.tcd = edma->membase + EDMA_TCD;
+}
+EXPORT_SYMBOL_GPL(fsl_edma_setup_regs);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/dma/fsl-edma-common.h b/drivers/dma/fsl-edma-common.h
new file mode 100644
index 000000000000..8917e8865959
--- /dev/null
+++ b/drivers/dma/fsl-edma-common.h
@@ -0,0 +1,233 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2013-2014 Freescale Semiconductor, Inc.
+ * Copyright 2018 Angelo Dureghello <angelo@sysam.it>
+ */
+#ifndef _FSL_EDMA_COMMON_H_
+#define _FSL_EDMA_COMMON_H_
+
+#include "virt-dma.h"
+
+#define EDMA_CR_EDBG BIT(1)
+#define EDMA_CR_ERCA BIT(2)
+#define EDMA_CR_ERGA BIT(3)
+#define EDMA_CR_HOE BIT(4)
+#define EDMA_CR_HALT BIT(5)
+#define EDMA_CR_CLM BIT(6)
+#define EDMA_CR_EMLM BIT(7)
+#define EDMA_CR_ECX BIT(16)
+#define EDMA_CR_CX BIT(17)
+
+#define EDMA_SEEI_SEEI(x) ((x) & GENMASK(4, 0))
+#define EDMA_CEEI_CEEI(x) ((x) & GENMASK(4, 0))
+#define EDMA_CINT_CINT(x) ((x) & GENMASK(4, 0))
+#define EDMA_CERR_CERR(x) ((x) & GENMASK(4, 0))
+
+#define EDMA_TCD_ATTR_DSIZE(x) (((x) & GENMASK(2, 0)))
+#define EDMA_TCD_ATTR_DMOD(x) (((x) & GENMASK(4, 0)) << 3)
+#define EDMA_TCD_ATTR_SSIZE(x) (((x) & GENMASK(2, 0)) << 8)
+#define EDMA_TCD_ATTR_SMOD(x) (((x) & GENMASK(4, 0)) << 11)
+#define EDMA_TCD_ATTR_DSIZE_8BIT 0
+#define EDMA_TCD_ATTR_DSIZE_16BIT BIT(0)
+#define EDMA_TCD_ATTR_DSIZE_32BIT BIT(1)
+#define EDMA_TCD_ATTR_DSIZE_64BIT (BIT(0) | BIT(1))
+#define EDMA_TCD_ATTR_DSIZE_32BYTE (BIT(3) | BIT(0))
+#define EDMA_TCD_ATTR_SSIZE_8BIT 0
+#define EDMA_TCD_ATTR_SSIZE_16BIT (EDMA_TCD_ATTR_DSIZE_16BIT << 8)
+#define EDMA_TCD_ATTR_SSIZE_32BIT (EDMA_TCD_ATTR_DSIZE_32BIT << 8)
+#define EDMA_TCD_ATTR_SSIZE_64BIT (EDMA_TCD_ATTR_DSIZE_64BIT << 8)
+#define EDMA_TCD_ATTR_SSIZE_32BYTE (EDMA_TCD_ATTR_DSIZE_32BYTE << 8)
+
+#define EDMA_TCD_CITER_CITER(x) ((x) & GENMASK(14, 0))
+#define EDMA_TCD_BITER_BITER(x) ((x) & GENMASK(14, 0))
+
+#define EDMA_TCD_CSR_START BIT(0)
+#define EDMA_TCD_CSR_INT_MAJOR BIT(1)
+#define EDMA_TCD_CSR_INT_HALF BIT(2)
+#define EDMA_TCD_CSR_D_REQ BIT(3)
+#define EDMA_TCD_CSR_E_SG BIT(4)
+#define EDMA_TCD_CSR_E_LINK BIT(5)
+#define EDMA_TCD_CSR_ACTIVE BIT(6)
+#define EDMA_TCD_CSR_DONE BIT(7)
+
+#define EDMAMUX_CHCFG_DIS 0x0
+#define EDMAMUX_CHCFG_ENBL 0x80
+#define EDMAMUX_CHCFG_SOURCE(n) ((n) & 0x3F)
+
+#define DMAMUX_NR 2
+
+#define FSL_EDMA_BUSWIDTHS (BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
+ BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
+ BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \
+ BIT(DMA_SLAVE_BUSWIDTH_8_BYTES))
+enum fsl_edma_pm_state {
+ RUNNING = 0,
+ SUSPENDED,
+};
+
+struct fsl_edma_hw_tcd {
+ __le32 saddr;
+ __le16 soff;
+ __le16 attr;
+ __le32 nbytes;
+ __le32 slast;
+ __le32 daddr;
+ __le16 doff;
+ __le16 citer;
+ __le32 dlast_sga;
+ __le16 csr;
+ __le16 biter;
+};
+
+/*
+ * These are iomem pointers, for both v32 and v64.
+ */
+struct edma_regs {
+ void __iomem *cr;
+ void __iomem *es;
+ void __iomem *erqh;
+ void __iomem *erql; /* aka erq on v32 */
+ void __iomem *eeih;
+ void __iomem *eeil; /* aka eei on v32 */
+ void __iomem *seei;
+ void __iomem *ceei;
+ void __iomem *serq;
+ void __iomem *cerq;
+ void __iomem *cint;
+ void __iomem *cerr;
+ void __iomem *ssrt;
+ void __iomem *cdne;
+ void __iomem *inth;
+ void __iomem *intl;
+ void __iomem *errh;
+ void __iomem *errl;
+ struct fsl_edma_hw_tcd __iomem *tcd;
+};
+
+struct fsl_edma_sw_tcd {
+ dma_addr_t ptcd;
+ struct fsl_edma_hw_tcd *vtcd;
+};
+
+struct fsl_edma_chan {
+ struct virt_dma_chan vchan;
+ enum dma_status status;
+ enum fsl_edma_pm_state pm_state;
+ bool idle;
+ u32 slave_id;
+ struct fsl_edma_engine *edma;
+ struct fsl_edma_desc *edesc;
+ struct dma_slave_config cfg;
+ u32 attr;
+ struct dma_pool *tcd_pool;
+};
+
+struct fsl_edma_desc {
+ struct virt_dma_desc vdesc;
+ struct fsl_edma_chan *echan;
+ bool iscyclic;
+ enum dma_transfer_direction dirn;
+ unsigned int n_tcds;
+ struct fsl_edma_sw_tcd tcd[];
+};
+
+enum edma_version {
+ v1, /* 32ch, Vybdir, mpc57x, etc */
+ v2, /* 64ch Coldfire */
+};
+
+struct fsl_edma_engine {
+ struct dma_device dma_dev;
+ void __iomem *membase;
+ void __iomem *muxbase[DMAMUX_NR];
+ struct clk *muxclk[DMAMUX_NR];
+ struct mutex fsl_edma_mutex;
+ u32 n_chans;
+ int txirq;
+ int errirq;
+ bool big_endian;
+ enum edma_version version;
+ struct edma_regs regs;
+ struct fsl_edma_chan chans[];
+};
+
+/*
+ * R/W functions for big- or little-endian registers:
+ * The eDMA controller's endian is independent of the CPU core's endian.
+ * For the big-endian IP module, the offset for 8-bit or 16-bit registers
+ * should also be swapped opposite to that in little-endian IP.
+ */
+static inline u32 edma_readl(struct fsl_edma_engine *edma, void __iomem *addr)
+{
+ if (edma->big_endian)
+ return ioread32be(addr);
+ else
+ return ioread32(addr);
+}
+
+static inline void edma_writeb(struct fsl_edma_engine *edma,
+ u8 val, void __iomem *addr)
+{
+ /* swap the reg offset for these in big-endian mode */
+ if (edma->big_endian)
+ iowrite8(val, (void __iomem *)((unsigned long)addr ^ 0x3));
+ else
+ iowrite8(val, addr);
+}
+
+static inline void edma_writew(struct fsl_edma_engine *edma,
+ u16 val, void __iomem *addr)
+{
+ /* swap the reg offset for these in big-endian mode */
+ if (edma->big_endian)
+ iowrite16be(val, (void __iomem *)((unsigned long)addr ^ 0x2));
+ else
+ iowrite16(val, addr);
+}
+
+static inline void edma_writel(struct fsl_edma_engine *edma,
+ u32 val, void __iomem *addr)
+{
+ if (edma->big_endian)
+ iowrite32be(val, addr);
+ else
+ iowrite32(val, addr);
+}
+
+static inline struct fsl_edma_chan *to_fsl_edma_chan(struct dma_chan *chan)
+{
+ return container_of(chan, struct fsl_edma_chan, vchan.chan);
+}
+
+static inline struct fsl_edma_desc *to_fsl_edma_desc(struct virt_dma_desc *vd)
+{
+ return container_of(vd, struct fsl_edma_desc, vdesc);
+}
+
+void fsl_edma_disable_request(struct fsl_edma_chan *fsl_chan);
+void fsl_edma_chan_mux(struct fsl_edma_chan *fsl_chan,
+ unsigned int slot, bool enable);
+void fsl_edma_free_desc(struct virt_dma_desc *vdesc);
+int fsl_edma_terminate_all(struct dma_chan *chan);
+int fsl_edma_pause(struct dma_chan *chan);
+int fsl_edma_resume(struct dma_chan *chan);
+int fsl_edma_slave_config(struct dma_chan *chan,
+ struct dma_slave_config *cfg);
+enum dma_status fsl_edma_tx_status(struct dma_chan *chan,
+ dma_cookie_t cookie, struct dma_tx_state *txstate);
+struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic(
+ struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
+ size_t period_len, enum dma_transfer_direction direction,
+ unsigned long flags);
+struct dma_async_tx_descriptor *fsl_edma_prep_slave_sg(
+ struct dma_chan *chan, struct scatterlist *sgl,
+ unsigned int sg_len, enum dma_transfer_direction direction,
+ unsigned long flags, void *context);
+void fsl_edma_xfer_desc(struct fsl_edma_chan *fsl_chan);
+void fsl_edma_issue_pending(struct dma_chan *chan);
+int fsl_edma_alloc_chan_resources(struct dma_chan *chan);
+void fsl_edma_free_chan_resources(struct dma_chan *chan);
+void fsl_edma_cleanup_vchan(struct dma_device *dmadev);
+void fsl_edma_setup_regs(struct fsl_edma_engine *edma);
+
+#endif /* _FSL_EDMA_COMMON_H_ */
diff --git a/drivers/dma/fsl-edma.c b/drivers/dma/fsl-edma.c
index c7568869284e..34d70112fcc9 100644
--- a/drivers/dma/fsl-edma.c
+++ b/drivers/dma/fsl-edma.c
@@ -13,671 +13,31 @@
* option) any later version.
*/
-#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/clk.h>
-#include <linux/dma-mapping.h>
-#include <linux/dmapool.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_dma.h>
-#include "virt-dma.h"
-
-#define EDMA_CR 0x00
-#define EDMA_ES 0x04
-#define EDMA_ERQ 0x0C
-#define EDMA_EEI 0x14
-#define EDMA_SERQ 0x1B
-#define EDMA_CERQ 0x1A
-#define EDMA_SEEI 0x19
-#define EDMA_CEEI 0x18
-#define EDMA_CINT 0x1F
-#define EDMA_CERR 0x1E
-#define EDMA_SSRT 0x1D
-#define EDMA_CDNE 0x1C
-#define EDMA_INTR 0x24
-#define EDMA_ERR 0x2C
-
-#define EDMA_TCD_SADDR(x) (0x1000 + 32 * (x))
-#define EDMA_TCD_SOFF(x) (0x1004 + 32 * (x))
-#define EDMA_TCD_ATTR(x) (0x1006 + 32 * (x))
-#define EDMA_TCD_NBYTES(x) (0x1008 + 32 * (x))
-#define EDMA_TCD_SLAST(x) (0x100C + 32 * (x))
-#define EDMA_TCD_DADDR(x) (0x1010 + 32 * (x))
-#define EDMA_TCD_DOFF(x) (0x1014 + 32 * (x))
-#define EDMA_TCD_CITER_ELINK(x) (0x1016 + 32 * (x))
-#define EDMA_TCD_CITER(x) (0x1016 + 32 * (x))
-#define EDMA_TCD_DLAST_SGA(x) (0x1018 + 32 * (x))
-#define EDMA_TCD_CSR(x) (0x101C + 32 * (x))
-#define EDMA_TCD_BITER_ELINK(x) (0x101E + 32 * (x))
-#define EDMA_TCD_BITER(x) (0x101E + 32 * (x))
-
-#define EDMA_CR_EDBG BIT(1)
-#define EDMA_CR_ERCA BIT(2)
-#define EDMA_CR_ERGA BIT(3)
-#define EDMA_CR_HOE BIT(4)
-#define EDMA_CR_HALT BIT(5)
-#define EDMA_CR_CLM BIT(6)
-#define EDMA_CR_EMLM BIT(7)
-#define EDMA_CR_ECX BIT(16)
-#define EDMA_CR_CX BIT(17)
-
-#define EDMA_SEEI_SEEI(x) ((x) & 0x1F)
-#define EDMA_CEEI_CEEI(x) ((x) & 0x1F)
-#define EDMA_CINT_CINT(x) ((x) & 0x1F)
-#define EDMA_CERR_CERR(x) ((x) & 0x1F)
-
-#define EDMA_TCD_ATTR_DSIZE(x) (((x) & 0x0007))
-#define EDMA_TCD_ATTR_DMOD(x) (((x) & 0x001F) << 3)
-#define EDMA_TCD_ATTR_SSIZE(x) (((x) & 0x0007) << 8)
-#define EDMA_TCD_ATTR_SMOD(x) (((x) & 0x001F) << 11)
-#define EDMA_TCD_ATTR_SSIZE_8BIT (0x0000)
-#define EDMA_TCD_ATTR_SSIZE_16BIT (0x0100)
-#define EDMA_TCD_ATTR_SSIZE_32BIT (0x0200)
-#define EDMA_TCD_ATTR_SSIZE_64BIT (0x0300)
-#define EDMA_TCD_ATTR_SSIZE_32BYTE (0x0500)
-#define EDMA_TCD_ATTR_DSIZE_8BIT (0x0000)
-#define EDMA_TCD_ATTR_DSIZE_16BIT (0x0001)
-#define EDMA_TCD_ATTR_DSIZE_32BIT (0x0002)
-#define EDMA_TCD_ATTR_DSIZE_64BIT (0x0003)
-#define EDMA_TCD_ATTR_DSIZE_32BYTE (0x0005)
-
-#define EDMA_TCD_SOFF_SOFF(x) (x)
-#define EDMA_TCD_NBYTES_NBYTES(x) (x)
-#define EDMA_TCD_SLAST_SLAST(x) (x)
-#define EDMA_TCD_DADDR_DADDR(x) (x)
-#define EDMA_TCD_CITER_CITER(x) ((x) & 0x7FFF)
-#define EDMA_TCD_DOFF_DOFF(x) (x)
-#define EDMA_TCD_DLAST_SGA_DLAST_SGA(x) (x)
-#define EDMA_TCD_BITER_BITER(x) ((x) & 0x7FFF)
-
-#define EDMA_TCD_CSR_START BIT(0)
-#define EDMA_TCD_CSR_INT_MAJOR BIT(1)
-#define EDMA_TCD_CSR_INT_HALF BIT(2)
-#define EDMA_TCD_CSR_D_REQ BIT(3)
-#define EDMA_TCD_CSR_E_SG BIT(4)
-#define EDMA_TCD_CSR_E_LINK BIT(5)
-#define EDMA_TCD_CSR_ACTIVE BIT(6)
-#define EDMA_TCD_CSR_DONE BIT(7)
-
-#define EDMAMUX_CHCFG_DIS 0x0
-#define EDMAMUX_CHCFG_ENBL 0x80
-#define EDMAMUX_CHCFG_SOURCE(n) ((n) & 0x3F)
-
-#define DMAMUX_NR 2
-
-#define FSL_EDMA_BUSWIDTHS BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
- BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
- BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \
- BIT(DMA_SLAVE_BUSWIDTH_8_BYTES)
-enum fsl_edma_pm_state {
- RUNNING = 0,
- SUSPENDED,
-};
-
-struct fsl_edma_hw_tcd {
- __le32 saddr;
- __le16 soff;
- __le16 attr;
- __le32 nbytes;
- __le32 slast;
- __le32 daddr;
- __le16 doff;
- __le16 citer;
- __le32 dlast_sga;
- __le16 csr;
- __le16 biter;
-};
-
-struct fsl_edma_sw_tcd {
- dma_addr_t ptcd;
- struct fsl_edma_hw_tcd *vtcd;
-};
-
-struct fsl_edma_slave_config {
- enum dma_transfer_direction dir;
- enum dma_slave_buswidth addr_width;
- u32 dev_addr;
- u32 burst;
- u32 attr;
-};
-
-struct fsl_edma_chan {
- struct virt_dma_chan vchan;
- enum dma_status status;
- enum fsl_edma_pm_state pm_state;
- bool idle;
- u32 slave_id;
- struct fsl_edma_engine *edma;
- struct fsl_edma_desc *edesc;
- struct fsl_edma_slave_config fsc;
- struct dma_pool *tcd_pool;
-};
-
-struct fsl_edma_desc {
- struct virt_dma_desc vdesc;
- struct fsl_edma_chan *echan;
- bool iscyclic;
- unsigned int n_tcds;
- struct fsl_edma_sw_tcd tcd[];
-};
-
-struct fsl_edma_engine {
- struct dma_device dma_dev;
- void __iomem *membase;
- void __iomem *muxbase[DMAMUX_NR];
- struct clk *muxclk[DMAMUX_NR];
- struct mutex fsl_edma_mutex;
- u32 n_chans;
- int txirq;
- int errirq;
- bool big_endian;
- struct fsl_edma_chan chans[];
-};
-
-/*
- * R/W functions for big- or little-endian registers:
- * The eDMA controller's endian is independent of the CPU core's endian.
- * For the big-endian IP module, the offset for 8-bit or 16-bit registers
- * should also be swapped opposite to that in little-endian IP.
- */
-
-static u32 edma_readl(struct fsl_edma_engine *edma, void __iomem *addr)
-{
- if (edma->big_endian)
- return ioread32be(addr);
- else
- return ioread32(addr);
-}
-
-static void edma_writeb(struct fsl_edma_engine *edma, u8 val, void __iomem *addr)
-{
- /* swap the reg offset for these in big-endian mode */
- if (edma->big_endian)
- iowrite8(val, (void __iomem *)((unsigned long)addr ^ 0x3));
- else
- iowrite8(val, addr);
-}
-
-static void edma_writew(struct fsl_edma_engine *edma, u16 val, void __iomem *addr)
-{
- /* swap the reg offset for these in big-endian mode */
- if (edma->big_endian)
- iowrite16be(val, (void __iomem *)((unsigned long)addr ^ 0x2));
- else
- iowrite16(val, addr);
-}
-
-static void edma_writel(struct fsl_edma_engine *edma, u32 val, void __iomem *addr)
-{
- if (edma->big_endian)
- iowrite32be(val, addr);
- else
- iowrite32(val, addr);
-}
-
-static struct fsl_edma_chan *to_fsl_edma_chan(struct dma_chan *chan)
-{
- return container_of(chan, struct fsl_edma_chan, vchan.chan);
-}
-
-static struct fsl_edma_desc *to_fsl_edma_desc(struct virt_dma_desc *vd)
-{
- return container_of(vd, struct fsl_edma_desc, vdesc);
-}
-
-static void fsl_edma_enable_request(struct fsl_edma_chan *fsl_chan)
-{
- void __iomem *addr = fsl_chan->edma->membase;
- u32 ch = fsl_chan->vchan.chan.chan_id;
-
- edma_writeb(fsl_chan->edma, EDMA_SEEI_SEEI(ch), addr + EDMA_SEEI);
- edma_writeb(fsl_chan->edma, ch, addr + EDMA_SERQ);
-}
-
-static void fsl_edma_disable_request(struct fsl_edma_chan *fsl_chan)
-{
- void __iomem *addr = fsl_chan->edma->membase;
- u32 ch = fsl_chan->vchan.chan.chan_id;
-
- edma_writeb(fsl_chan->edma, ch, addr + EDMA_CERQ);
- edma_writeb(fsl_chan->edma, EDMA_CEEI_CEEI(ch), addr + EDMA_CEEI);
-}
-
-static void fsl_edma_chan_mux(struct fsl_edma_chan *fsl_chan,
- unsigned int slot, bool enable)
-{
- u32 ch = fsl_chan->vchan.chan.chan_id;
- void __iomem *muxaddr;
- unsigned chans_per_mux, ch_off;
-
- chans_per_mux = fsl_chan->edma->n_chans / DMAMUX_NR;
- ch_off = fsl_chan->vchan.chan.chan_id % chans_per_mux;
- muxaddr = fsl_chan->edma->muxbase[ch / chans_per_mux];
- slot = EDMAMUX_CHCFG_SOURCE(slot);
-
- if (enable)
- iowrite8(EDMAMUX_CHCFG_ENBL | slot, muxaddr + ch_off);
- else
- iowrite8(EDMAMUX_CHCFG_DIS, muxaddr + ch_off);
-}
-
-static unsigned int fsl_edma_get_tcd_attr(enum dma_slave_buswidth addr_width)
-{
- switch (addr_width) {
- case 1:
- return EDMA_TCD_ATTR_SSIZE_8BIT | EDMA_TCD_ATTR_DSIZE_8BIT;
- case 2:
- return EDMA_TCD_ATTR_SSIZE_16BIT | EDMA_TCD_ATTR_DSIZE_16BIT;
- case 4:
- return EDMA_TCD_ATTR_SSIZE_32BIT | EDMA_TCD_ATTR_DSIZE_32BIT;
- case 8:
- return EDMA_TCD_ATTR_SSIZE_64BIT | EDMA_TCD_ATTR_DSIZE_64BIT;
- default:
- return EDMA_TCD_ATTR_SSIZE_32BIT | EDMA_TCD_ATTR_DSIZE_32BIT;
- }
-}
-
-static void fsl_edma_free_desc(struct virt_dma_desc *vdesc)
-{
- struct fsl_edma_desc *fsl_desc;
- int i;
-
- fsl_desc = to_fsl_edma_desc(vdesc);
- for (i = 0; i < fsl_desc->n_tcds; i++)
- dma_pool_free(fsl_desc->echan->tcd_pool, fsl_desc->tcd[i].vtcd,
- fsl_desc->tcd[i].ptcd);
- kfree(fsl_desc);
-}
-
-static int fsl_edma_terminate_all(struct dma_chan *chan)
-{
- struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
- unsigned long flags;
- LIST_HEAD(head);
-
- spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
- fsl_edma_disable_request(fsl_chan);
- fsl_chan->edesc = NULL;
- fsl_chan->idle = true;
- vchan_get_all_descriptors(&fsl_chan->vchan, &head);
- spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
- vchan_dma_desc_free_list(&fsl_chan->vchan, &head);
- return 0;
-}
-
-static int fsl_edma_pause(struct dma_chan *chan)
-{
- struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
- unsigned long flags;
-
- spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
- if (fsl_chan->edesc) {
- fsl_edma_disable_request(fsl_chan);
- fsl_chan->status = DMA_PAUSED;
- fsl_chan->idle = true;
- }
- spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
- return 0;
-}
-
-static int fsl_edma_resume(struct dma_chan *chan)
-{
- struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
- unsigned long flags;
-
- spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
- if (fsl_chan->edesc) {
- fsl_edma_enable_request(fsl_chan);
- fsl_chan->status = DMA_IN_PROGRESS;
- fsl_chan->idle = false;
- }
- spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
- return 0;
-}
-
-static int fsl_edma_slave_config(struct dma_chan *chan,
- struct dma_slave_config *cfg)
-{
- struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
-
- fsl_chan->fsc.dir = cfg->direction;
- if (cfg->direction == DMA_DEV_TO_MEM) {
- fsl_chan->fsc.dev_addr = cfg->src_addr;
- fsl_chan->fsc.addr_width = cfg->src_addr_width;
- fsl_chan->fsc.burst = cfg->src_maxburst;
- fsl_chan->fsc.attr = fsl_edma_get_tcd_attr(cfg->src_addr_width);
- } else if (cfg->direction == DMA_MEM_TO_DEV) {
- fsl_chan->fsc.dev_addr = cfg->dst_addr;
- fsl_chan->fsc.addr_width = cfg->dst_addr_width;
- fsl_chan->fsc.burst = cfg->dst_maxburst;
- fsl_chan->fsc.attr = fsl_edma_get_tcd_attr(cfg->dst_addr_width);
- } else {
- return -EINVAL;
- }
- return 0;
-}
-
-static size_t fsl_edma_desc_residue(struct fsl_edma_chan *fsl_chan,
- struct virt_dma_desc *vdesc, bool in_progress)
-{
- struct fsl_edma_desc *edesc = fsl_chan->edesc;
- void __iomem *addr = fsl_chan->edma->membase;
- u32 ch = fsl_chan->vchan.chan.chan_id;
- enum dma_transfer_direction dir = fsl_chan->fsc.dir;
- dma_addr_t cur_addr, dma_addr;
- size_t len, size;
- int i;
-
- /* calculate the total size in this desc */
- for (len = i = 0; i < fsl_chan->edesc->n_tcds; i++)
- len += le32_to_cpu(edesc->tcd[i].vtcd->nbytes)
- * le16_to_cpu(edesc->tcd[i].vtcd->biter);
-
- if (!in_progress)
- return len;
-
- if (dir == DMA_MEM_TO_DEV)
- cur_addr = edma_readl(fsl_chan->edma, addr + EDMA_TCD_SADDR(ch));
- else
- cur_addr = edma_readl(fsl_chan->edma, addr + EDMA_TCD_DADDR(ch));
-
- /* figure out the finished and calculate the residue */
- for (i = 0; i < fsl_chan->edesc->n_tcds; i++) {
- size = le32_to_cpu(edesc->tcd[i].vtcd->nbytes)
- * le16_to_cpu(edesc->tcd[i].vtcd->biter);
- if (dir == DMA_MEM_TO_DEV)
- dma_addr = le32_to_cpu(edesc->tcd[i].vtcd->saddr);
- else
- dma_addr = le32_to_cpu(edesc->tcd[i].vtcd->daddr);
-
- len -= size;
- if (cur_addr >= dma_addr && cur_addr < dma_addr + size) {
- len += dma_addr + size - cur_addr;
- break;
- }
- }
-
- return len;
-}
-
-static enum dma_status fsl_edma_tx_status(struct dma_chan *chan,
- dma_cookie_t cookie, struct dma_tx_state *txstate)
-{
- struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
- struct virt_dma_desc *vdesc;
- enum dma_status status;
- unsigned long flags;
-
- status = dma_cookie_status(chan, cookie, txstate);
- if (status == DMA_COMPLETE)
- return status;
-
- if (!txstate)
- return fsl_chan->status;
-
- spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
- vdesc = vchan_find_desc(&fsl_chan->vchan, cookie);
- if (fsl_chan->edesc && cookie == fsl_chan->edesc->vdesc.tx.cookie)
- txstate->residue = fsl_edma_desc_residue(fsl_chan, vdesc, true);
- else if (vdesc)
- txstate->residue = fsl_edma_desc_residue(fsl_chan, vdesc, false);
- else
- txstate->residue = 0;
-
- spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
-
- return fsl_chan->status;
-}
-
-static void fsl_edma_set_tcd_regs(struct fsl_edma_chan *fsl_chan,
- struct fsl_edma_hw_tcd *tcd)
-{
- struct fsl_edma_engine *edma = fsl_chan->edma;
- void __iomem *addr = fsl_chan->edma->membase;
- u32 ch = fsl_chan->vchan.chan.chan_id;
-
- /*
- * TCD parameters are stored in struct fsl_edma_hw_tcd in little
- * endian format. However, we need to load the TCD registers in
- * big- or little-endian obeying the eDMA engine model endian.
- */
- edma_writew(edma, 0, addr + EDMA_TCD_CSR(ch));
- edma_writel(edma, le32_to_cpu(tcd->saddr), addr + EDMA_TCD_SADDR(ch));
- edma_writel(edma, le32_to_cpu(tcd->daddr), addr + EDMA_TCD_DADDR(ch));
-
- edma_writew(edma, le16_to_cpu(tcd->attr), addr + EDMA_TCD_ATTR(ch));
- edma_writew(edma, le16_to_cpu(tcd->soff), addr + EDMA_TCD_SOFF(ch));
-
- edma_writel(edma, le32_to_cpu(tcd->nbytes), addr + EDMA_TCD_NBYTES(ch));
- edma_writel(edma, le32_to_cpu(tcd->slast), addr + EDMA_TCD_SLAST(ch));
-
- edma_writew(edma, le16_to_cpu(tcd->citer), addr + EDMA_TCD_CITER(ch));
- edma_writew(edma, le16_to_cpu(tcd->biter), addr + EDMA_TCD_BITER(ch));
- edma_writew(edma, le16_to_cpu(tcd->doff), addr + EDMA_TCD_DOFF(ch));
-
- edma_writel(edma, le32_to_cpu(tcd->dlast_sga), addr + EDMA_TCD_DLAST_SGA(ch));
-
- edma_writew(edma, le16_to_cpu(tcd->csr), addr + EDMA_TCD_CSR(ch));
-}
-
-static inline
-void fsl_edma_fill_tcd(struct fsl_edma_hw_tcd *tcd, u32 src, u32 dst,
- u16 attr, u16 soff, u32 nbytes, u32 slast, u16 citer,
- u16 biter, u16 doff, u32 dlast_sga, bool major_int,
- bool disable_req, bool enable_sg)
-{
- u16 csr = 0;
-
- /*
- * eDMA hardware SGs require the TCDs to be stored in little
- * endian format irrespective of the register endian model.
- * So we put the value in little endian in memory, waiting
- * for fsl_edma_set_tcd_regs doing the swap.
- */
- tcd->saddr = cpu_to_le32(src);
- tcd->daddr = cpu_to_le32(dst);
-
- tcd->attr = cpu_to_le16(attr);
-
- tcd->soff = cpu_to_le16(EDMA_TCD_SOFF_SOFF(soff));
-
- tcd->nbytes = cpu_to_le32(EDMA_TCD_NBYTES_NBYTES(nbytes));
- tcd->slast = cpu_to_le32(EDMA_TCD_SLAST_SLAST(slast));
-
- tcd->citer = cpu_to_le16(EDMA_TCD_CITER_CITER(citer));
- tcd->doff = cpu_to_le16(EDMA_TCD_DOFF_DOFF(doff));
-
- tcd->dlast_sga = cpu_to_le32(EDMA_TCD_DLAST_SGA_DLAST_SGA(dlast_sga));
-
- tcd->biter = cpu_to_le16(EDMA_TCD_BITER_BITER(biter));
- if (major_int)
- csr |= EDMA_TCD_CSR_INT_MAJOR;
-
- if (disable_req)
- csr |= EDMA_TCD_CSR_D_REQ;
-
- if (enable_sg)
- csr |= EDMA_TCD_CSR_E_SG;
-
- tcd->csr = cpu_to_le16(csr);
-}
-
-static struct fsl_edma_desc *fsl_edma_alloc_desc(struct fsl_edma_chan *fsl_chan,
- int sg_len)
-{
- struct fsl_edma_desc *fsl_desc;
- int i;
-
- fsl_desc = kzalloc(sizeof(*fsl_desc) + sizeof(struct fsl_edma_sw_tcd) * sg_len,
- GFP_NOWAIT);
- if (!fsl_desc)
- return NULL;
-
- fsl_desc->echan = fsl_chan;
- fsl_desc->n_tcds = sg_len;
- for (i = 0; i < sg_len; i++) {
- fsl_desc->tcd[i].vtcd = dma_pool_alloc(fsl_chan->tcd_pool,
- GFP_NOWAIT, &fsl_desc->tcd[i].ptcd);
- if (!fsl_desc->tcd[i].vtcd)
- goto err;
- }
- return fsl_desc;
-
-err:
- while (--i >= 0)
- dma_pool_free(fsl_chan->tcd_pool, fsl_desc->tcd[i].vtcd,
- fsl_desc->tcd[i].ptcd);
- kfree(fsl_desc);
- return NULL;
-}
-
-static struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic(
- struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
- size_t period_len, enum dma_transfer_direction direction,
- unsigned long flags)
-{
- struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
- struct fsl_edma_desc *fsl_desc;
- dma_addr_t dma_buf_next;
- int sg_len, i;
- u32 src_addr, dst_addr, last_sg, nbytes;
- u16 soff, doff, iter;
-
- if (!is_slave_direction(fsl_chan->fsc.dir))
- return NULL;
-
- sg_len = buf_len / period_len;
- fsl_desc = fsl_edma_alloc_desc(fsl_chan, sg_len);
- if (!fsl_desc)
- return NULL;
- fsl_desc->iscyclic = true;
-
- dma_buf_next = dma_addr;
- nbytes = fsl_chan->fsc.addr_width * fsl_chan->fsc.burst;
- iter = period_len / nbytes;
-
- for (i = 0; i < sg_len; i++) {
- if (dma_buf_next >= dma_addr + buf_len)
- dma_buf_next = dma_addr;
-
- /* get next sg's physical address */
- last_sg = fsl_desc->tcd[(i + 1) % sg_len].ptcd;
-
- if (fsl_chan->fsc.dir == DMA_MEM_TO_DEV) {
- src_addr = dma_buf_next;
- dst_addr = fsl_chan->fsc.dev_addr;
- soff = fsl_chan->fsc.addr_width;
- doff = 0;
- } else {
- src_addr = fsl_chan->fsc.dev_addr;
- dst_addr = dma_buf_next;
- soff = 0;
- doff = fsl_chan->fsc.addr_width;
- }
-
- fsl_edma_fill_tcd(fsl_desc->tcd[i].vtcd, src_addr, dst_addr,
- fsl_chan->fsc.attr, soff, nbytes, 0, iter,
- iter, doff, last_sg, true, false, true);
- dma_buf_next += period_len;
- }
-
- return vchan_tx_prep(&fsl_chan->vchan, &fsl_desc->vdesc, flags);
-}
-
-static struct dma_async_tx_descriptor *fsl_edma_prep_slave_sg(
- struct dma_chan *chan, struct scatterlist *sgl,
- unsigned int sg_len, enum dma_transfer_direction direction,
- unsigned long flags, void *context)
-{
- struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
- struct fsl_edma_desc *fsl_desc;
- struct scatterlist *sg;
- u32 src_addr, dst_addr, last_sg, nbytes;
- u16 soff, doff, iter;
- int i;
-
- if (!is_slave_direction(fsl_chan->fsc.dir))
- return NULL;
-
- fsl_desc = fsl_edma_alloc_desc(fsl_chan, sg_len);
- if (!fsl_desc)
- return NULL;
- fsl_desc->iscyclic = false;
-
- nbytes = fsl_chan->fsc.addr_width * fsl_chan->fsc.burst;
- for_each_sg(sgl, sg, sg_len, i) {
- /* get next sg's physical address */
- last_sg = fsl_desc->tcd[(i + 1) % sg_len].ptcd;
-
- if (fsl_chan->fsc.dir == DMA_MEM_TO_DEV) {
- src_addr = sg_dma_address(sg);
- dst_addr = fsl_chan->fsc.dev_addr;
- soff = fsl_chan->fsc.addr_width;
- doff = 0;
- } else {
- src_addr = fsl_chan->fsc.dev_addr;
- dst_addr = sg_dma_address(sg);
- soff = 0;
- doff = fsl_chan->fsc.addr_width;
- }
-
- iter = sg_dma_len(sg) / nbytes;
- if (i < sg_len - 1) {
- last_sg = fsl_desc->tcd[(i + 1)].ptcd;
- fsl_edma_fill_tcd(fsl_desc->tcd[i].vtcd, src_addr,
- dst_addr, fsl_chan->fsc.attr, soff,
- nbytes, 0, iter, iter, doff, last_sg,
- false, false, true);
- } else {
- last_sg = 0;
- fsl_edma_fill_tcd(fsl_desc->tcd[i].vtcd, src_addr,
- dst_addr, fsl_chan->fsc.attr, soff,
- nbytes, 0, iter, iter, doff, last_sg,
- true, true, false);
- }
- }
-
- return vchan_tx_prep(&fsl_chan->vchan, &fsl_desc->vdesc, flags);
-}
-
-static void fsl_edma_xfer_desc(struct fsl_edma_chan *fsl_chan)
-{
- struct virt_dma_desc *vdesc;
-
- vdesc = vchan_next_desc(&fsl_chan->vchan);
- if (!vdesc)
- return;
- fsl_chan->edesc = to_fsl_edma_desc(vdesc);
- fsl_edma_set_tcd_regs(fsl_chan, fsl_chan->edesc->tcd[0].vtcd);
- fsl_edma_enable_request(fsl_chan);
- fsl_chan->status = DMA_IN_PROGRESS;
- fsl_chan->idle = false;
-}
+#include "fsl-edma-common.h"
static irqreturn_t fsl_edma_tx_handler(int irq, void *dev_id)
{
struct fsl_edma_engine *fsl_edma = dev_id;
unsigned int intr, ch;
- void __iomem *base_addr;
+ struct edma_regs *regs = &fsl_edma->regs;
struct fsl_edma_chan *fsl_chan;
- base_addr = fsl_edma->membase;
-
- intr = edma_readl(fsl_edma, base_addr + EDMA_INTR);
+ intr = edma_readl(fsl_edma, regs->intl);
if (!intr)
return IRQ_NONE;
for (ch = 0; ch < fsl_edma->n_chans; ch++) {
if (intr & (0x1 << ch)) {
- edma_writeb(fsl_edma, EDMA_CINT_CINT(ch),
- base_addr + EDMA_CINT);
+ edma_writeb(fsl_edma, EDMA_CINT_CINT(ch), regs->cint);
fsl_chan = &fsl_edma->chans[ch];
@@ -705,16 +65,16 @@ static irqreturn_t fsl_edma_err_handler(int irq, void *dev_id)
{
struct fsl_edma_engine *fsl_edma = dev_id;
unsigned int err, ch;
+ struct edma_regs *regs = &fsl_edma->regs;
- err = edma_readl(fsl_edma, fsl_edma->membase + EDMA_ERR);
+ err = edma_readl(fsl_edma, regs->errl);
if (!err)
return IRQ_NONE;
for (ch = 0; ch < fsl_edma->n_chans; ch++) {
if (err & (0x1 << ch)) {
fsl_edma_disable_request(&fsl_edma->chans[ch]);
- edma_writeb(fsl_edma, EDMA_CERR_CERR(ch),
- fsl_edma->membase + EDMA_CERR);
+ edma_writeb(fsl_edma, EDMA_CERR_CERR(ch), regs->cerr);
fsl_edma->chans[ch].status = DMA_ERROR;
fsl_edma->chans[ch].idle = true;
}
@@ -730,25 +90,6 @@ static irqreturn_t fsl_edma_irq_handler(int irq, void *dev_id)
return fsl_edma_err_handler(irq, dev_id);
}
-static void fsl_edma_issue_pending(struct dma_chan *chan)
-{
- struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
- unsigned long flags;
-
- spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
-
- if (unlikely(fsl_chan->pm_state != RUNNING)) {
- spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
- /* cannot submit due to suspend */
- return;
- }
-
- if (vchan_issue_pending(&fsl_chan->vchan) && !fsl_chan->edesc)
- fsl_edma_xfer_desc(fsl_chan);
-
- spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
-}
-
static struct dma_chan *fsl_edma_xlate(struct of_phandle_args *dma_spec,
struct of_dma *ofdma)
{
@@ -781,34 +122,6 @@ static struct dma_chan *fsl_edma_xlate(struct of_phandle_args *dma_spec,
return NULL;
}
-static int fsl_edma_alloc_chan_resources(struct dma_chan *chan)
-{
- struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
-
- fsl_chan->tcd_pool = dma_pool_create("tcd_pool", chan->device->dev,
- sizeof(struct fsl_edma_hw_tcd),
- 32, 0);
- return 0;
-}
-
-static void fsl_edma_free_chan_resources(struct dma_chan *chan)
-{
- struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
- unsigned long flags;
- LIST_HEAD(head);
-
- spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
- fsl_edma_disable_request(fsl_chan);
- fsl_edma_chan_mux(fsl_chan, 0, false);
- fsl_chan->edesc = NULL;
- vchan_get_all_descriptors(&fsl_chan->vchan, &head);
- spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
-
- vchan_dma_desc_free_list(&fsl_chan->vchan, &head);
- dma_pool_destroy(fsl_chan->tcd_pool);
- fsl_chan->tcd_pool = NULL;
-}
-
static int
fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma)
{
@@ -876,6 +189,7 @@ static int fsl_edma_probe(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
struct fsl_edma_engine *fsl_edma;
struct fsl_edma_chan *fsl_chan;
+ struct edma_regs *regs;
struct resource *res;
int len, chans;
int ret, i;
@@ -891,6 +205,7 @@ static int fsl_edma_probe(struct platform_device *pdev)
if (!fsl_edma)
return -ENOMEM;
+ fsl_edma->version = v1;
fsl_edma->n_chans = chans;
mutex_init(&fsl_edma->fsl_edma_mutex);
@@ -899,6 +214,9 @@ static int fsl_edma_probe(struct platform_device *pdev)
if (IS_ERR(fsl_edma->membase))
return PTR_ERR(fsl_edma->membase);
+ fsl_edma_setup_regs(fsl_edma);
+ regs = &fsl_edma->regs;
+
for (i = 0; i < DMAMUX_NR; i++) {
char clkname[32];
@@ -939,11 +257,11 @@ static int fsl_edma_probe(struct platform_device *pdev)
fsl_chan->vchan.desc_free = fsl_edma_free_desc;
vchan_init(&fsl_chan->vchan, &fsl_edma->dma_dev);
- edma_writew(fsl_edma, 0x0, fsl_edma->membase + EDMA_TCD_CSR(i));
+ edma_writew(fsl_edma, 0x0, &regs->tcd[i].csr);
fsl_edma_chan_mux(fsl_chan, 0, false);
}
- edma_writel(fsl_edma, ~0, fsl_edma->membase + EDMA_INTR);
+ edma_writel(fsl_edma, ~0, regs->intl);
ret = fsl_edma_irq_init(pdev, fsl_edma);
if (ret)
return ret;
@@ -990,22 +308,11 @@ static int fsl_edma_probe(struct platform_device *pdev)
}
/* enable round robin arbitration */
- edma_writel(fsl_edma, EDMA_CR_ERGA | EDMA_CR_ERCA, fsl_edma->membase + EDMA_CR);
+ edma_writel(fsl_edma, EDMA_CR_ERGA | EDMA_CR_ERCA, regs->cr);
return 0;
}
-static void fsl_edma_cleanup_vchan(struct dma_device *dmadev)
-{
- struct fsl_edma_chan *chan, *_chan;
-
- list_for_each_entry_safe(chan, _chan,
- &dmadev->channels, vchan.chan.device_node) {
- list_del(&chan->vchan.chan.device_node);
- tasklet_kill(&chan->vchan.task);
- }
-}
-
static int fsl_edma_remove(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -1048,18 +355,18 @@ static int fsl_edma_resume_early(struct device *dev)
{
struct fsl_edma_engine *fsl_edma = dev_get_drvdata(dev);
struct fsl_edma_chan *fsl_chan;
+ struct edma_regs *regs = &fsl_edma->regs;
int i;
for (i = 0; i < fsl_edma->n_chans; i++) {
fsl_chan = &fsl_edma->chans[i];
fsl_chan->pm_state = RUNNING;
- edma_writew(fsl_edma, 0x0, fsl_edma->membase + EDMA_TCD_CSR(i));
+ edma_writew(fsl_edma, 0x0, &regs->tcd[i].csr);
if (fsl_chan->slave_id != 0)
fsl_edma_chan_mux(fsl_chan, fsl_chan->slave_id, true);
}
- edma_writel(fsl_edma, EDMA_CR_ERGA | EDMA_CR_ERCA,
- fsl_edma->membase + EDMA_CR);
+ edma_writel(fsl_edma, EDMA_CR_ERGA | EDMA_CR_ERCA, regs->cr);
return 0;
}
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 1117b5123a6f..9d360a3fbae3 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -987,7 +987,7 @@ static void dma_do_tasklet(unsigned long data)
chan_dbg(chan, "tasklet entry\n");
- spin_lock_bh(&chan->desc_lock);
+ spin_lock(&chan->desc_lock);
/* the hardware is now idle and ready for more */
chan->idle = true;
@@ -995,7 +995,7 @@ static void dma_do_tasklet(unsigned long data)
/* Run all cleanup for descriptors which have been completed */
fsldma_cleanup_descriptors(chan);
- spin_unlock_bh(&chan->desc_lock);
+ spin_unlock(&chan->desc_lock);
chan_dbg(chan, "tasklet exit\n");
}
diff --git a/drivers/dma/hsu/hsu.c b/drivers/dma/hsu/hsu.c
index 202ffa9f7611..e06f20272fd7 100644
--- a/drivers/dma/hsu/hsu.c
+++ b/drivers/dma/hsu/hsu.c
@@ -348,10 +348,6 @@ static int hsu_dma_slave_config(struct dma_chan *chan,
{
struct hsu_dma_chan *hsuc = to_hsu_dma_chan(chan);
- /* Check if chan will be configured for slave transfers */
- if (!is_slave_direction(config->direction))
- return -EINVAL;
-
memcpy(&hsuc->config, config, sizeof(hsuc->config));
return 0;
diff --git a/drivers/dma/idma64.c b/drivers/dma/idma64.c
index 1fbf9cb9b742..0baf9797cc09 100644
--- a/drivers/dma/idma64.c
+++ b/drivers/dma/idma64.c
@@ -142,9 +142,8 @@ static void idma64_chan_irq(struct idma64 *idma64, unsigned short c,
{
struct idma64_chan *idma64c = &idma64->chan[c];
struct idma64_desc *desc;
- unsigned long flags;
- spin_lock_irqsave(&idma64c->vchan.lock, flags);
+ spin_lock(&idma64c->vchan.lock);
desc = idma64c->desc;
if (desc) {
if (status_err & (1 << c)) {
@@ -161,7 +160,7 @@ static void idma64_chan_irq(struct idma64 *idma64, unsigned short c,
if (idma64c->desc == NULL || desc->status == DMA_ERROR)
idma64_stop_transfer(idma64c);
}
- spin_unlock_irqrestore(&idma64c->vchan.lock, flags);
+ spin_unlock(&idma64c->vchan.lock);
}
static irqreturn_t idma64_irq(int irq, void *dev)
@@ -408,10 +407,6 @@ static int idma64_slave_config(struct dma_chan *chan,
{
struct idma64_chan *idma64c = to_idma64_chan(chan);
- /* Check if chan will be configured for slave transfers */
- if (!is_slave_direction(config->direction))
- return -EINVAL;
-
memcpy(&idma64c->config, config, sizeof(idma64c->config));
convert_burst(&idma64c->config.src_maxburst);
diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c
index 75b6ff0415ee..c2fff3f6c9ca 100644
--- a/drivers/dma/imx-dma.c
+++ b/drivers/dma/imx-dma.c
@@ -162,6 +162,7 @@ struct imxdma_channel {
bool enabled_2d;
int slot_2d;
unsigned int irq;
+ struct dma_slave_config config;
};
enum imx_dma_type {
@@ -675,14 +676,15 @@ static int imxdma_terminate_all(struct dma_chan *chan)
return 0;
}
-static int imxdma_config(struct dma_chan *chan,
- struct dma_slave_config *dmaengine_cfg)
+static int imxdma_config_write(struct dma_chan *chan,
+ struct dma_slave_config *dmaengine_cfg,
+ enum dma_transfer_direction direction)
{
struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
struct imxdma_engine *imxdma = imxdmac->imxdma;
unsigned int mode = 0;
- if (dmaengine_cfg->direction == DMA_DEV_TO_MEM) {
+ if (direction == DMA_DEV_TO_MEM) {
imxdmac->per_address = dmaengine_cfg->src_addr;
imxdmac->watermark_level = dmaengine_cfg->src_maxburst;
imxdmac->word_size = dmaengine_cfg->src_addr_width;
@@ -723,6 +725,16 @@ static int imxdma_config(struct dma_chan *chan,
return 0;
}
+static int imxdma_config(struct dma_chan *chan,
+ struct dma_slave_config *dmaengine_cfg)
+{
+ struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
+
+ memcpy(&imxdmac->config, dmaengine_cfg, sizeof(*dmaengine_cfg));
+
+ return 0;
+}
+
static enum dma_status imxdma_tx_status(struct dma_chan *chan,
dma_cookie_t cookie,
struct dma_tx_state *txstate)
@@ -905,6 +917,8 @@ static struct dma_async_tx_descriptor *imxdma_prep_dma_cyclic(
desc->desc.callback = NULL;
desc->desc.callback_param = NULL;
+ imxdma_config_write(chan, &imxdmac->config, direction);
+
return &desc->desc;
}
diff --git a/drivers/dma/ioat/init.c b/drivers/dma/ioat/init.c
index 4fa4c06c9edb..2d810dfcdc48 100644
--- a/drivers/dma/ioat/init.c
+++ b/drivers/dma/ioat/init.c
@@ -129,7 +129,7 @@ static void
ioat_init_channel(struct ioatdma_device *ioat_dma,
struct ioatdma_chan *ioat_chan, int idx);
static void ioat_intr_quirk(struct ioatdma_device *ioat_dma);
-static int ioat_enumerate_channels(struct ioatdma_device *ioat_dma);
+static void ioat_enumerate_channels(struct ioatdma_device *ioat_dma);
static int ioat3_dma_self_test(struct ioatdma_device *ioat_dma);
static int ioat_dca_enabled = 1;
@@ -575,7 +575,7 @@ static void ioat_dma_remove(struct ioatdma_device *ioat_dma)
* ioat_enumerate_channels - find and initialize the device's channels
* @ioat_dma: the ioat dma device to be enumerated
*/
-static int ioat_enumerate_channels(struct ioatdma_device *ioat_dma)
+static void ioat_enumerate_channels(struct ioatdma_device *ioat_dma)
{
struct ioatdma_chan *ioat_chan;
struct device *dev = &ioat_dma->pdev->dev;
@@ -594,7 +594,7 @@ static int ioat_enumerate_channels(struct ioatdma_device *ioat_dma)
xfercap_log = readb(ioat_dma->reg_base + IOAT_XFERCAP_OFFSET);
xfercap_log &= 0x1f; /* bits [4:0] valid */
if (xfercap_log == 0)
- return 0;
+ return;
dev_dbg(dev, "%s: xfercap = %d\n", __func__, 1 << xfercap_log);
for (i = 0; i < dma->chancnt; i++) {
@@ -611,7 +611,6 @@ static int ioat_enumerate_channels(struct ioatdma_device *ioat_dma)
}
}
dma->chancnt = i;
- return i;
}
/**
@@ -1205,8 +1204,15 @@ static void ioat_shutdown(struct pci_dev *pdev)
spin_lock_bh(&ioat_chan->prep_lock);
set_bit(IOAT_CHAN_DOWN, &ioat_chan->state);
- del_timer_sync(&ioat_chan->timer);
spin_unlock_bh(&ioat_chan->prep_lock);
+ /*
+ * Synchronization rule for del_timer_sync():
+ * - The caller must not hold locks which would prevent
+ * completion of the timer's handler.
+ * So prep_lock cannot be held before calling it.
+ */
+ del_timer_sync(&ioat_chan->timer);
+
/* this should quiesce then reset */
ioat_reset_hw(ioat_chan);
}
@@ -1252,7 +1258,6 @@ static pci_ers_result_t ioat_pcie_error_detected(struct pci_dev *pdev,
static pci_ers_result_t ioat_pcie_error_slot_reset(struct pci_dev *pdev)
{
pci_ers_result_t result = PCI_ERS_RESULT_RECOVERED;
- int err;
dev_dbg(&pdev->dev, "%s post reset handling\n", DRV_NAME);
@@ -1267,12 +1272,6 @@ static pci_ers_result_t ioat_pcie_error_slot_reset(struct pci_dev *pdev)
pci_wake_from_d3(pdev, false);
}
- err = pci_cleanup_aer_uncorrect_error_status(pdev);
- if (err) {
- dev_err(&pdev->dev,
- "AER uncorrect error status clear failed: %#x\n", err);
- }
-
return result;
}
diff --git a/drivers/dma/k3dma.c b/drivers/dma/k3dma.c
index 6bfa217ed6d0..fdec2b6cfbb0 100644
--- a/drivers/dma/k3dma.c
+++ b/drivers/dma/k3dma.c
@@ -87,10 +87,10 @@ struct k3_dma_chan {
struct virt_dma_chan vc;
struct k3_dma_phy *phy;
struct list_head node;
- enum dma_transfer_direction dir;
dma_addr_t dev_addr;
enum dma_status status;
bool cyclic;
+ struct dma_slave_config slave_config;
};
struct k3_dma_phy {
@@ -118,6 +118,10 @@ struct k3_dma_dev {
#define to_k3_dma(dmadev) container_of(dmadev, struct k3_dma_dev, slave)
+static int k3_dma_config_write(struct dma_chan *chan,
+ enum dma_transfer_direction dir,
+ struct dma_slave_config *cfg);
+
static struct k3_dma_chan *to_k3_chan(struct dma_chan *chan)
{
return container_of(chan, struct k3_dma_chan, vc.chan);
@@ -501,14 +505,8 @@ static struct dma_async_tx_descriptor *k3_dma_prep_memcpy(
copy = min_t(size_t, len, DMA_MAX_SIZE);
k3_dma_fill_desc(ds, dst, src, copy, num++, c->ccfg);
- if (c->dir == DMA_MEM_TO_DEV) {
- src += copy;
- } else if (c->dir == DMA_DEV_TO_MEM) {
- dst += copy;
- } else {
- src += copy;
- dst += copy;
- }
+ src += copy;
+ dst += copy;
len -= copy;
} while (len);
@@ -542,6 +540,7 @@ static struct dma_async_tx_descriptor *k3_dma_prep_slave_sg(
if (!ds)
return NULL;
num = 0;
+ k3_dma_config_write(chan, dir, &c->slave_config);
for_each_sg(sgl, sg, sglen, i) {
addr = sg_dma_address(sg);
@@ -602,6 +601,7 @@ k3_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr,
avail = buf_len;
total = avail;
num = 0;
+ k3_dma_config_write(chan, dir, &c->slave_config);
if (period_len < modulo)
modulo = period_len;
@@ -642,18 +642,26 @@ static int k3_dma_config(struct dma_chan *chan,
struct dma_slave_config *cfg)
{
struct k3_dma_chan *c = to_k3_chan(chan);
+
+ memcpy(&c->slave_config, cfg, sizeof(*cfg));
+
+ return 0;
+}
+
+static int k3_dma_config_write(struct dma_chan *chan,
+ enum dma_transfer_direction dir,
+ struct dma_slave_config *cfg)
+{
+ struct k3_dma_chan *c = to_k3_chan(chan);
u32 maxburst = 0, val = 0;
enum dma_slave_buswidth width = DMA_SLAVE_BUSWIDTH_UNDEFINED;
- if (cfg == NULL)
- return -EINVAL;
- c->dir = cfg->direction;
- if (c->dir == DMA_DEV_TO_MEM) {
+ if (dir == DMA_DEV_TO_MEM) {
c->ccfg = CX_CFG_DSTINCR;
c->dev_addr = cfg->src_addr;
maxburst = cfg->src_maxburst;
width = cfg->src_addr_width;
- } else if (c->dir == DMA_MEM_TO_DEV) {
+ } else if (dir == DMA_MEM_TO_DEV) {
c->ccfg = CX_CFG_SRCINCR;
c->dev_addr = cfg->dst_addr;
maxburst = cfg->dst_maxburst;
diff --git a/drivers/dma/mcf-edma.c b/drivers/dma/mcf-edma.c
new file mode 100644
index 000000000000..5de1b07eddff
--- /dev/null
+++ b/drivers/dma/mcf-edma.c
@@ -0,0 +1,317 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Copyright (c) 2013-2014 Freescale Semiconductor, Inc
+// Copyright (c) 2017 Sysam, Angelo Dureghello <angelo@sysam.it>
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/dmaengine.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/dma-mcf-edma.h>
+
+#include "fsl-edma-common.h"
+
+#define EDMA_CHANNELS 64
+#define EDMA_MASK_CH(x) ((x) & GENMASK(5, 0))
+
+static irqreturn_t mcf_edma_tx_handler(int irq, void *dev_id)
+{
+ struct fsl_edma_engine *mcf_edma = dev_id;
+ struct edma_regs *regs = &mcf_edma->regs;
+ unsigned int ch;
+ struct fsl_edma_chan *mcf_chan;
+ u64 intmap;
+
+ intmap = ioread32(regs->inth);
+ intmap <<= 32;
+ intmap |= ioread32(regs->intl);
+ if (!intmap)
+ return IRQ_NONE;
+
+ for (ch = 0; ch < mcf_edma->n_chans; ch++) {
+ if (intmap & BIT(ch)) {
+ iowrite8(EDMA_MASK_CH(ch), regs->cint);
+
+ mcf_chan = &mcf_edma->chans[ch];
+
+ spin_lock(&mcf_chan->vchan.lock);
+ if (!mcf_chan->edesc->iscyclic) {
+ list_del(&mcf_chan->edesc->vdesc.node);
+ vchan_cookie_complete(&mcf_chan->edesc->vdesc);
+ mcf_chan->edesc = NULL;
+ mcf_chan->status = DMA_COMPLETE;
+ mcf_chan->idle = true;
+ } else {
+ vchan_cyclic_callback(&mcf_chan->edesc->vdesc);
+ }
+
+ if (!mcf_chan->edesc)
+ fsl_edma_xfer_desc(mcf_chan);
+
+ spin_unlock(&mcf_chan->vchan.lock);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t mcf_edma_err_handler(int irq, void *dev_id)
+{
+ struct fsl_edma_engine *mcf_edma = dev_id;
+ struct edma_regs *regs = &mcf_edma->regs;
+ unsigned int err, ch;
+
+ err = ioread32(regs->errl);
+ if (!err)
+ return IRQ_NONE;
+
+ for (ch = 0; ch < (EDMA_CHANNELS / 2); ch++) {
+ if (err & BIT(ch)) {
+ fsl_edma_disable_request(&mcf_edma->chans[ch]);
+ iowrite8(EDMA_CERR_CERR(ch), regs->cerr);
+ mcf_edma->chans[ch].status = DMA_ERROR;
+ mcf_edma->chans[ch].idle = true;
+ }
+ }
+
+ err = ioread32(regs->errh);
+ if (!err)
+ return IRQ_NONE;
+
+ for (ch = (EDMA_CHANNELS / 2); ch < EDMA_CHANNELS; ch++) {
+ if (err & (BIT(ch - (EDMA_CHANNELS / 2)))) {
+ fsl_edma_disable_request(&mcf_edma->chans[ch]);
+ iowrite8(EDMA_CERR_CERR(ch), regs->cerr);
+ mcf_edma->chans[ch].status = DMA_ERROR;
+ mcf_edma->chans[ch].idle = true;
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int mcf_edma_irq_init(struct platform_device *pdev,
+ struct fsl_edma_engine *mcf_edma)
+{
+ int ret = 0, i;
+ struct resource *res;
+
+ res = platform_get_resource_byname(pdev,
+ IORESOURCE_IRQ, "edma-tx-00-15");
+ if (!res)
+ return -1;
+
+ for (ret = 0, i = res->start; i <= res->end; ++i)
+ ret |= request_irq(i, mcf_edma_tx_handler, 0, "eDMA", mcf_edma);
+ if (ret)
+ return ret;
+
+ res = platform_get_resource_byname(pdev,
+ IORESOURCE_IRQ, "edma-tx-16-55");
+ if (!res)
+ return -1;
+
+ for (ret = 0, i = res->start; i <= res->end; ++i)
+ ret |= request_irq(i, mcf_edma_tx_handler, 0, "eDMA", mcf_edma);
+ if (ret)
+ return ret;
+
+ ret = platform_get_irq_byname(pdev, "edma-tx-56-63");
+ if (ret != -ENXIO) {
+ ret = request_irq(ret, mcf_edma_tx_handler,
+ 0, "eDMA", mcf_edma);
+ if (ret)
+ return ret;
+ }
+
+ ret = platform_get_irq_byname(pdev, "edma-err");
+ if (ret != -ENXIO) {
+ ret = request_irq(ret, mcf_edma_err_handler,
+ 0, "eDMA", mcf_edma);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void mcf_edma_irq_free(struct platform_device *pdev,
+ struct fsl_edma_engine *mcf_edma)
+{
+ int irq;
+ struct resource *res;
+
+ res = platform_get_resource_byname(pdev,
+ IORESOURCE_IRQ, "edma-tx-00-15");
+ if (res) {
+ for (irq = res->start; irq <= res->end; irq++)
+ free_irq(irq, mcf_edma);
+ }
+
+ res = platform_get_resource_byname(pdev,
+ IORESOURCE_IRQ, "edma-tx-16-55");
+ if (res) {
+ for (irq = res->start; irq <= res->end; irq++)
+ free_irq(irq, mcf_edma);
+ }
+
+ irq = platform_get_irq_byname(pdev, "edma-tx-56-63");
+ if (irq != -ENXIO)
+ free_irq(irq, mcf_edma);
+
+ irq = platform_get_irq_byname(pdev, "edma-err");
+ if (irq != -ENXIO)
+ free_irq(irq, mcf_edma);
+}
+
+static int mcf_edma_probe(struct platform_device *pdev)
+{
+ struct mcf_edma_platform_data *pdata;
+ struct fsl_edma_engine *mcf_edma;
+ struct fsl_edma_chan *mcf_chan;
+ struct edma_regs *regs;
+ struct resource *res;
+ int ret, i, len, chans;
+
+ pdata = dev_get_platdata(&pdev->dev);
+ if (!pdata) {
+ dev_err(&pdev->dev, "no platform data supplied\n");
+ return -EINVAL;
+ }
+
+ chans = pdata->dma_channels;
+ len = sizeof(*mcf_edma) + sizeof(*mcf_chan) * chans;
+ mcf_edma = devm_kzalloc(&pdev->dev, len, GFP_KERNEL);
+ if (!mcf_edma)
+ return -ENOMEM;
+
+ mcf_edma->n_chans = chans;
+
+ /* Set up version for ColdFire edma */
+ mcf_edma->version = v2;
+ mcf_edma->big_endian = 1;
+
+ if (!mcf_edma->n_chans) {
+ dev_info(&pdev->dev, "setting default channel number to 64");
+ mcf_edma->n_chans = 64;
+ }
+
+ mutex_init(&mcf_edma->fsl_edma_mutex);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ mcf_edma->membase = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mcf_edma->membase))
+ return PTR_ERR(mcf_edma->membase);
+
+ fsl_edma_setup_regs(mcf_edma);
+ regs = &mcf_edma->regs;
+
+ INIT_LIST_HEAD(&mcf_edma->dma_dev.channels);
+ for (i = 0; i < mcf_edma->n_chans; i++) {
+ struct fsl_edma_chan *mcf_chan = &mcf_edma->chans[i];
+
+ mcf_chan->edma = mcf_edma;
+ mcf_chan->slave_id = i;
+ mcf_chan->idle = true;
+ mcf_chan->vchan.desc_free = fsl_edma_free_desc;
+ vchan_init(&mcf_chan->vchan, &mcf_edma->dma_dev);
+ iowrite32(0x0, &regs->tcd[i].csr);
+ }
+
+ iowrite32(~0, regs->inth);
+ iowrite32(~0, regs->intl);
+
+ ret = mcf_edma_irq_init(pdev, mcf_edma);
+ if (ret)
+ return ret;
+
+ dma_cap_set(DMA_PRIVATE, mcf_edma->dma_dev.cap_mask);
+ dma_cap_set(DMA_SLAVE, mcf_edma->dma_dev.cap_mask);
+ dma_cap_set(DMA_CYCLIC, mcf_edma->dma_dev.cap_mask);
+
+ mcf_edma->dma_dev.dev = &pdev->dev;
+ mcf_edma->dma_dev.device_alloc_chan_resources =
+ fsl_edma_alloc_chan_resources;
+ mcf_edma->dma_dev.device_free_chan_resources =
+ fsl_edma_free_chan_resources;
+ mcf_edma->dma_dev.device_config = fsl_edma_slave_config;
+ mcf_edma->dma_dev.device_prep_dma_cyclic =
+ fsl_edma_prep_dma_cyclic;
+ mcf_edma->dma_dev.device_prep_slave_sg = fsl_edma_prep_slave_sg;
+ mcf_edma->dma_dev.device_tx_status = fsl_edma_tx_status;
+ mcf_edma->dma_dev.device_pause = fsl_edma_pause;
+ mcf_edma->dma_dev.device_resume = fsl_edma_resume;
+ mcf_edma->dma_dev.device_terminate_all = fsl_edma_terminate_all;
+ mcf_edma->dma_dev.device_issue_pending = fsl_edma_issue_pending;
+
+ mcf_edma->dma_dev.src_addr_widths = FSL_EDMA_BUSWIDTHS;
+ mcf_edma->dma_dev.dst_addr_widths = FSL_EDMA_BUSWIDTHS;
+ mcf_edma->dma_dev.directions =
+ BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+
+ mcf_edma->dma_dev.filter.fn = mcf_edma_filter_fn;
+ mcf_edma->dma_dev.filter.map = pdata->slave_map;
+ mcf_edma->dma_dev.filter.mapcnt = pdata->slavecnt;
+
+ platform_set_drvdata(pdev, mcf_edma);
+
+ ret = dma_async_device_register(&mcf_edma->dma_dev);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Can't register Freescale eDMA engine. (%d)\n", ret);
+ return ret;
+ }
+
+ /* Enable round robin arbitration */
+ iowrite32(EDMA_CR_ERGA | EDMA_CR_ERCA, regs->cr);
+
+ return 0;
+}
+
+static int mcf_edma_remove(struct platform_device *pdev)
+{
+ struct fsl_edma_engine *mcf_edma = platform_get_drvdata(pdev);
+
+ mcf_edma_irq_free(pdev, mcf_edma);
+ fsl_edma_cleanup_vchan(&mcf_edma->dma_dev);
+ dma_async_device_unregister(&mcf_edma->dma_dev);
+
+ return 0;
+}
+
+static struct platform_driver mcf_edma_driver = {
+ .driver = {
+ .name = "mcf-edma",
+ },
+ .probe = mcf_edma_probe,
+ .remove = mcf_edma_remove,
+};
+
+bool mcf_edma_filter_fn(struct dma_chan *chan, void *param)
+{
+ if (chan->device->dev->driver == &mcf_edma_driver.driver) {
+ struct fsl_edma_chan *mcf_chan = to_fsl_edma_chan(chan);
+
+ return (mcf_chan->slave_id == (uintptr_t)param);
+ }
+
+ return false;
+}
+EXPORT_SYMBOL(mcf_edma_filter_fn);
+
+static int __init mcf_edma_init(void)
+{
+ return platform_driver_register(&mcf_edma_driver);
+}
+subsys_initcall(mcf_edma_init);
+
+static void __exit mcf_edma_exit(void)
+{
+ platform_driver_unregister(&mcf_edma_driver);
+}
+module_exit(mcf_edma_exit);
+
+MODULE_ALIAS("platform:mcf-edma");
+MODULE_DESCRIPTION("Freescale eDMA engine driver, ColdFire family");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/dma/mmp_tdma.c b/drivers/dma/mmp_tdma.c
index 13c68b6434ce..0c56faa03e9a 100644
--- a/drivers/dma/mmp_tdma.c
+++ b/drivers/dma/mmp_tdma.c
@@ -116,6 +116,7 @@ struct mmp_tdma_chan {
u32 burst_sz;
enum dma_slave_buswidth buswidth;
enum dma_status status;
+ struct dma_slave_config slave_config;
int idx;
enum mmp_tdma_type type;
@@ -139,6 +140,10 @@ struct mmp_tdma_device {
#define to_mmp_tdma_chan(dchan) container_of(dchan, struct mmp_tdma_chan, chan)
+static int mmp_tdma_config_write(struct dma_chan *chan,
+ enum dma_transfer_direction dir,
+ struct dma_slave_config *dmaengine_cfg);
+
static void mmp_tdma_chan_set_desc(struct mmp_tdma_chan *tdmac, dma_addr_t phys)
{
writel(phys, tdmac->reg_base + TDNDPR);
@@ -442,6 +447,8 @@ static struct dma_async_tx_descriptor *mmp_tdma_prep_dma_cyclic(
if (!desc)
goto err_out;
+ mmp_tdma_config_write(chan, direction, &tdmac->slave_config);
+
while (buf < buf_len) {
desc = &tdmac->desc_arr[i];
@@ -495,7 +502,18 @@ static int mmp_tdma_config(struct dma_chan *chan,
{
struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
- if (dmaengine_cfg->direction == DMA_DEV_TO_MEM) {
+ memcpy(&tdmac->slave_config, dmaengine_cfg, sizeof(*dmaengine_cfg));
+
+ return 0;
+}
+
+static int mmp_tdma_config_write(struct dma_chan *chan,
+ enum dma_transfer_direction dir,
+ struct dma_slave_config *dmaengine_cfg)
+{
+ struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
+
+ if (dir == DMA_DEV_TO_MEM) {
tdmac->dev_addr = dmaengine_cfg->src_addr;
tdmac->burst_sz = dmaengine_cfg->src_maxburst;
tdmac->buswidth = dmaengine_cfg->src_addr_width;
@@ -504,7 +522,7 @@ static int mmp_tdma_config(struct dma_chan *chan,
tdmac->burst_sz = dmaengine_cfg->dst_maxburst;
tdmac->buswidth = dmaengine_cfg->dst_addr_width;
}
- tdmac->dir = dmaengine_cfg->direction;
+ tdmac->dir = dir;
return mmp_tdma_config_chan(chan);
}
@@ -530,9 +548,6 @@ static void mmp_tdma_issue_pending(struct dma_chan *chan)
static int mmp_tdma_remove(struct platform_device *pdev)
{
- struct mmp_tdma_device *tdev = platform_get_drvdata(pdev);
-
- dma_async_device_unregister(&tdev->device);
return 0;
}
@@ -696,7 +711,7 @@ static int mmp_tdma_probe(struct platform_device *pdev)
dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
platform_set_drvdata(pdev, tdev);
- ret = dma_async_device_register(&tdev->device);
+ ret = dmaenginem_async_device_register(&tdev->device);
if (ret) {
dev_err(tdev->device.dev, "unable to register\n");
return ret;
@@ -708,7 +723,7 @@ static int mmp_tdma_probe(struct platform_device *pdev)
if (ret) {
dev_err(tdev->device.dev,
"failed to register controller\n");
- dma_async_device_unregister(&tdev->device);
+ return ret;
}
}
diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c
index 969534c1a6c6..7f595355fb79 100644
--- a/drivers/dma/mv_xor.c
+++ b/drivers/dma/mv_xor.c
@@ -348,9 +348,9 @@ static void mv_xor_tasklet(unsigned long data)
{
struct mv_xor_chan *chan = (struct mv_xor_chan *) data;
- spin_lock_bh(&chan->lock);
+ spin_lock(&chan->lock);
mv_chan_slot_cleanup(chan);
- spin_unlock_bh(&chan->lock);
+ spin_unlock(&chan->lock);
}
static struct mv_xor_desc_slot *
diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c
index ae5182ff0128..35193b31a9e0 100644
--- a/drivers/dma/mxs-dma.c
+++ b/drivers/dma/mxs-dma.c
@@ -847,7 +847,7 @@ static int __init mxs_dma_probe(struct platform_device *pdev)
mxs_dma->dma_device.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
mxs_dma->dma_device.device_issue_pending = mxs_dma_enable_chan;
- ret = dma_async_device_register(&mxs_dma->dma_device);
+ ret = dmaenginem_async_device_register(&mxs_dma->dma_device);
if (ret) {
dev_err(mxs_dma->dma_device.dev, "unable to register\n");
return ret;
@@ -857,7 +857,6 @@ static int __init mxs_dma_probe(struct platform_device *pdev)
if (ret) {
dev_err(mxs_dma->dma_device.dev,
"failed to register controller\n");
- dma_async_device_unregister(&mxs_dma->dma_device);
}
dev_info(mxs_dma->dma_device.dev, "initialized\n");
diff --git a/drivers/dma/nbpfaxi.c b/drivers/dma/nbpfaxi.c
index 8c7b2e8703da..a67b292190f4 100644
--- a/drivers/dma/nbpfaxi.c
+++ b/drivers/dma/nbpfaxi.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2013-2014 Renesas Electronics Europe Ltd.
* Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
*/
#include <linux/bitmap.h>
@@ -1095,8 +1092,8 @@ static struct dma_chan *nbpf_of_xlate(struct of_phandle_args *dma_spec,
if (!dchan)
return NULL;
- dev_dbg(dchan->device->dev, "Entry %s(%s)\n", __func__,
- dma_spec->np->name);
+ dev_dbg(dchan->device->dev, "Entry %s(%pOFn)\n", __func__,
+ dma_spec->np);
chan = nbpf_to_chan(dchan);
diff --git a/drivers/dma/owl-dma.c b/drivers/dma/owl-dma.c
index 7812a6338acd..90bbcef99ef8 100644
--- a/drivers/dma/owl-dma.c
+++ b/drivers/dma/owl-dma.c
@@ -21,6 +21,7 @@
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/of_device.h>
+#include <linux/of_dma.h>
#include <linux/slab.h>
#include "virt-dma.h"
@@ -161,10 +162,12 @@ struct owl_dma_lli {
* struct owl_dma_txd - Wrapper for struct dma_async_tx_descriptor
* @vd: virtual DMA descriptor
* @lli_list: link list of lli nodes
+ * @cyclic: flag to indicate cyclic transfers
*/
struct owl_dma_txd {
struct virt_dma_desc vd;
struct list_head lli_list;
+ bool cyclic;
};
/**
@@ -186,11 +189,15 @@ struct owl_dma_pchan {
* @vc: wrappped virtual channel
* @pchan: the physical channel utilized by this channel
* @txd: active transaction on this channel
+ * @cfg: slave configuration for this channel
+ * @drq: physical DMA request ID for this channel
*/
struct owl_dma_vchan {
struct virt_dma_chan vc;
struct owl_dma_pchan *pchan;
struct owl_dma_txd *txd;
+ struct dma_slave_config cfg;
+ u8 drq;
};
/**
@@ -200,6 +207,7 @@ struct owl_dma_vchan {
* @clk: clock for the DMA controller
* @lock: a lock to use when change DMA controller global register
* @lli_pool: a pool for the LLI descriptors
+ * @irq: interrupt ID for the DMA controller
* @nr_pchans: the number of physical channels
* @pchans: array of data for the physical channels
* @nr_vchans: the number of physical channels
@@ -336,9 +344,11 @@ static struct owl_dma_lli *owl_dma_alloc_lli(struct owl_dma *od)
static struct owl_dma_lli *owl_dma_add_lli(struct owl_dma_txd *txd,
struct owl_dma_lli *prev,
- struct owl_dma_lli *next)
+ struct owl_dma_lli *next,
+ bool is_cyclic)
{
- list_add_tail(&next->node, &txd->lli_list);
+ if (!is_cyclic)
+ list_add_tail(&next->node, &txd->lli_list);
if (prev) {
prev->hw.next_lli = next->phys;
@@ -351,7 +361,9 @@ static struct owl_dma_lli *owl_dma_add_lli(struct owl_dma_txd *txd,
static inline int owl_dma_cfg_lli(struct owl_dma_vchan *vchan,
struct owl_dma_lli *lli,
dma_addr_t src, dma_addr_t dst,
- u32 len, enum dma_transfer_direction dir)
+ u32 len, enum dma_transfer_direction dir,
+ struct dma_slave_config *sconfig,
+ bool is_cyclic)
{
struct owl_dma_lli_hw *hw = &lli->hw;
u32 mode;
@@ -365,6 +377,32 @@ static inline int owl_dma_cfg_lli(struct owl_dma_vchan *vchan,
OWL_DMA_MODE_DAM_INC;
break;
+ case DMA_MEM_TO_DEV:
+ mode |= OWL_DMA_MODE_TS(vchan->drq)
+ | OWL_DMA_MODE_ST_DCU | OWL_DMA_MODE_DT_DEV
+ | OWL_DMA_MODE_SAM_INC | OWL_DMA_MODE_DAM_CONST;
+
+ /*
+ * Hardware only supports 32bit and 8bit buswidth. Since the
+ * default is 32bit, select 8bit only when requested.
+ */
+ if (sconfig->dst_addr_width == DMA_SLAVE_BUSWIDTH_1_BYTE)
+ mode |= OWL_DMA_MODE_NDDBW_8BIT;
+
+ break;
+ case DMA_DEV_TO_MEM:
+ mode |= OWL_DMA_MODE_TS(vchan->drq)
+ | OWL_DMA_MODE_ST_DEV | OWL_DMA_MODE_DT_DCU
+ | OWL_DMA_MODE_SAM_CONST | OWL_DMA_MODE_DAM_INC;
+
+ /*
+ * Hardware only supports 32bit and 8bit buswidth. Since the
+ * default is 32bit, select 8bit only when requested.
+ */
+ if (sconfig->src_addr_width == DMA_SLAVE_BUSWIDTH_1_BYTE)
+ mode |= OWL_DMA_MODE_NDDBW_8BIT;
+
+ break;
default:
return -EINVAL;
}
@@ -381,7 +419,10 @@ static inline int owl_dma_cfg_lli(struct owl_dma_vchan *vchan,
OWL_DMA_LLC_SAV_LOAD_NEXT |
OWL_DMA_LLC_DAV_LOAD_NEXT);
- hw->ctrlb = llc_hw_ctrlb(OWL_DMA_INTCTL_SUPER_BLOCK);
+ if (is_cyclic)
+ hw->ctrlb = llc_hw_ctrlb(OWL_DMA_INTCTL_BLOCK);
+ else
+ hw->ctrlb = llc_hw_ctrlb(OWL_DMA_INTCTL_SUPER_BLOCK);
return 0;
}
@@ -443,6 +484,16 @@ static void owl_dma_terminate_pchan(struct owl_dma *od,
spin_unlock_irqrestore(&od->lock, flags);
}
+static void owl_dma_pause_pchan(struct owl_dma_pchan *pchan)
+{
+ pchan_writel(pchan, 1, OWL_DMAX_PAUSE);
+}
+
+static void owl_dma_resume_pchan(struct owl_dma_pchan *pchan)
+{
+ pchan_writel(pchan, 0, OWL_DMAX_PAUSE);
+}
+
static int owl_dma_start_next_txd(struct owl_dma_vchan *vchan)
{
struct owl_dma *od = to_owl_dma(vchan->vc.chan.device);
@@ -464,7 +515,10 @@ static int owl_dma_start_next_txd(struct owl_dma_vchan *vchan)
lli = list_first_entry(&txd->lli_list,
struct owl_dma_lli, node);
- int_ctl = OWL_DMA_INTCTL_SUPER_BLOCK;
+ if (txd->cyclic)
+ int_ctl = OWL_DMA_INTCTL_BLOCK;
+ else
+ int_ctl = OWL_DMA_INTCTL_SUPER_BLOCK;
pchan_writel(pchan, OWL_DMAX_MODE, OWL_DMA_MODE_LME);
pchan_writel(pchan, OWL_DMAX_LINKLIST_CTL,
@@ -627,6 +681,54 @@ static int owl_dma_terminate_all(struct dma_chan *chan)
return 0;
}
+static int owl_dma_config(struct dma_chan *chan,
+ struct dma_slave_config *config)
+{
+ struct owl_dma_vchan *vchan = to_owl_vchan(chan);
+
+ /* Reject definitely invalid configurations */
+ if (config->src_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES ||
+ config->dst_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES)
+ return -EINVAL;
+
+ memcpy(&vchan->cfg, config, sizeof(struct dma_slave_config));
+
+ return 0;
+}
+
+static int owl_dma_pause(struct dma_chan *chan)
+{
+ struct owl_dma_vchan *vchan = to_owl_vchan(chan);
+ unsigned long flags;
+
+ spin_lock_irqsave(&vchan->vc.lock, flags);
+
+ owl_dma_pause_pchan(vchan->pchan);
+
+ spin_unlock_irqrestore(&vchan->vc.lock, flags);
+
+ return 0;
+}
+
+static int owl_dma_resume(struct dma_chan *chan)
+{
+ struct owl_dma_vchan *vchan = to_owl_vchan(chan);
+ unsigned long flags;
+
+ if (!vchan->pchan && !vchan->txd)
+ return 0;
+
+ dev_dbg(chan2dev(chan), "vchan %p: resume\n", &vchan->vc);
+
+ spin_lock_irqsave(&vchan->vc.lock, flags);
+
+ owl_dma_resume_pchan(vchan->pchan);
+
+ spin_unlock_irqrestore(&vchan->vc.lock, flags);
+
+ return 0;
+}
+
static u32 owl_dma_getbytes_chan(struct owl_dma_vchan *vchan)
{
struct owl_dma_pchan *pchan;
@@ -754,13 +856,14 @@ static struct dma_async_tx_descriptor
bytes = min_t(size_t, (len - offset), OWL_DMA_FRAME_MAX_LENGTH);
ret = owl_dma_cfg_lli(vchan, lli, src + offset, dst + offset,
- bytes, DMA_MEM_TO_MEM);
+ bytes, DMA_MEM_TO_MEM,
+ &vchan->cfg, txd->cyclic);
if (ret) {
dev_warn(chan2dev(chan), "failed to config lli\n");
goto err_txd_free;
}
- prev = owl_dma_add_lli(txd, prev, lli);
+ prev = owl_dma_add_lli(txd, prev, lli, false);
}
return vchan_tx_prep(&vchan->vc, &txd->vd, flags);
@@ -770,6 +873,133 @@ err_txd_free:
return NULL;
}
+static struct dma_async_tx_descriptor
+ *owl_dma_prep_slave_sg(struct dma_chan *chan,
+ struct scatterlist *sgl,
+ unsigned int sg_len,
+ enum dma_transfer_direction dir,
+ unsigned long flags, void *context)
+{
+ struct owl_dma *od = to_owl_dma(chan->device);
+ struct owl_dma_vchan *vchan = to_owl_vchan(chan);
+ struct dma_slave_config *sconfig = &vchan->cfg;
+ struct owl_dma_txd *txd;
+ struct owl_dma_lli *lli, *prev = NULL;
+ struct scatterlist *sg;
+ dma_addr_t addr, src = 0, dst = 0;
+ size_t len;
+ int ret, i;
+
+ txd = kzalloc(sizeof(*txd), GFP_NOWAIT);
+ if (!txd)
+ return NULL;
+
+ INIT_LIST_HEAD(&txd->lli_list);
+
+ for_each_sg(sgl, sg, sg_len, i) {
+ addr = sg_dma_address(sg);
+ len = sg_dma_len(sg);
+
+ if (len > OWL_DMA_FRAME_MAX_LENGTH) {
+ dev_err(od->dma.dev,
+ "frame length exceeds max supported length");
+ goto err_txd_free;
+ }
+
+ lli = owl_dma_alloc_lli(od);
+ if (!lli) {
+ dev_err(chan2dev(chan), "failed to allocate lli");
+ goto err_txd_free;
+ }
+
+ if (dir == DMA_MEM_TO_DEV) {
+ src = addr;
+ dst = sconfig->dst_addr;
+ } else {
+ src = sconfig->src_addr;
+ dst = addr;
+ }
+
+ ret = owl_dma_cfg_lli(vchan, lli, src, dst, len, dir, sconfig,
+ txd->cyclic);
+ if (ret) {
+ dev_warn(chan2dev(chan), "failed to config lli");
+ goto err_txd_free;
+ }
+
+ prev = owl_dma_add_lli(txd, prev, lli, false);
+ }
+
+ return vchan_tx_prep(&vchan->vc, &txd->vd, flags);
+
+err_txd_free:
+ owl_dma_free_txd(od, txd);
+
+ return NULL;
+}
+
+static struct dma_async_tx_descriptor
+ *owl_prep_dma_cyclic(struct dma_chan *chan,
+ dma_addr_t buf_addr, size_t buf_len,
+ size_t period_len,
+ enum dma_transfer_direction dir,
+ unsigned long flags)
+{
+ struct owl_dma *od = to_owl_dma(chan->device);
+ struct owl_dma_vchan *vchan = to_owl_vchan(chan);
+ struct dma_slave_config *sconfig = &vchan->cfg;
+ struct owl_dma_txd *txd;
+ struct owl_dma_lli *lli, *prev = NULL, *first = NULL;
+ dma_addr_t src = 0, dst = 0;
+ unsigned int periods = buf_len / period_len;
+ int ret, i;
+
+ txd = kzalloc(sizeof(*txd), GFP_NOWAIT);
+ if (!txd)
+ return NULL;
+
+ INIT_LIST_HEAD(&txd->lli_list);
+ txd->cyclic = true;
+
+ for (i = 0; i < periods; i++) {
+ lli = owl_dma_alloc_lli(od);
+ if (!lli) {
+ dev_warn(chan2dev(chan), "failed to allocate lli");
+ goto err_txd_free;
+ }
+
+ if (dir == DMA_MEM_TO_DEV) {
+ src = buf_addr + (period_len * i);
+ dst = sconfig->dst_addr;
+ } else if (dir == DMA_DEV_TO_MEM) {
+ src = sconfig->src_addr;
+ dst = buf_addr + (period_len * i);
+ }
+
+ ret = owl_dma_cfg_lli(vchan, lli, src, dst, period_len,
+ dir, sconfig, txd->cyclic);
+ if (ret) {
+ dev_warn(chan2dev(chan), "failed to config lli");
+ goto err_txd_free;
+ }
+
+ if (!first)
+ first = lli;
+
+ prev = owl_dma_add_lli(txd, prev, lli, false);
+ }
+
+ /* close the cyclic list */
+ owl_dma_add_lli(txd, prev, first, true);
+
+ return vchan_tx_prep(&vchan->vc, &txd->vd, flags);
+
+err_txd_free:
+ owl_dma_free_txd(od, txd);
+
+ return NULL;
+}
+
static void owl_dma_free_chan_resources(struct dma_chan *chan)
{
struct owl_dma_vchan *vchan = to_owl_vchan(chan);
@@ -790,6 +1020,27 @@ static inline void owl_dma_free(struct owl_dma *od)
}
}
+static struct dma_chan *owl_dma_of_xlate(struct of_phandle_args *dma_spec,
+ struct of_dma *ofdma)
+{
+ struct owl_dma *od = ofdma->of_dma_data;
+ struct owl_dma_vchan *vchan;
+ struct dma_chan *chan;
+ u8 drq = dma_spec->args[0];
+
+ if (drq > od->nr_vchans)
+ return NULL;
+
+ chan = dma_get_any_slave_channel(&od->dma);
+ if (!chan)
+ return NULL;
+
+ vchan = to_owl_vchan(chan);
+ vchan->drq = drq;
+
+ return chan;
+}
+
static int owl_dma_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -833,12 +1084,19 @@ static int owl_dma_probe(struct platform_device *pdev)
spin_lock_init(&od->lock);
dma_cap_set(DMA_MEMCPY, od->dma.cap_mask);
+ dma_cap_set(DMA_SLAVE, od->dma.cap_mask);
+ dma_cap_set(DMA_CYCLIC, od->dma.cap_mask);
od->dma.dev = &pdev->dev;
od->dma.device_free_chan_resources = owl_dma_free_chan_resources;
od->dma.device_tx_status = owl_dma_tx_status;
od->dma.device_issue_pending = owl_dma_issue_pending;
od->dma.device_prep_dma_memcpy = owl_dma_prep_memcpy;
+ od->dma.device_prep_slave_sg = owl_dma_prep_slave_sg;
+ od->dma.device_prep_dma_cyclic = owl_prep_dma_cyclic;
+ od->dma.device_config = owl_dma_config;
+ od->dma.device_pause = owl_dma_pause;
+ od->dma.device_resume = owl_dma_resume;
od->dma.device_terminate_all = owl_dma_terminate_all;
od->dma.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
od->dma.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
@@ -910,8 +1168,18 @@ static int owl_dma_probe(struct platform_device *pdev)
goto err_pool_free;
}
+ /* Device-tree DMA controller registration */
+ ret = of_dma_controller_register(pdev->dev.of_node,
+ owl_dma_of_xlate, od);
+ if (ret) {
+ dev_err(&pdev->dev, "of_dma_controller_register failed\n");
+ goto err_dma_unregister;
+ }
+
return 0;
+err_dma_unregister:
+ dma_async_device_unregister(&od->dma);
err_pool_free:
clk_disable_unprepare(od->clk);
dma_pool_destroy(od->lli_pool);
@@ -923,6 +1191,7 @@ static int owl_dma_remove(struct platform_device *pdev)
{
struct owl_dma *od = platform_get_drvdata(pdev);
+ of_dma_controller_free(pdev->dev.of_node);
dma_async_device_unregister(&od->dma);
/* Mask all interrupts for this execution environment */
diff --git a/drivers/dma/ppc4xx/adma.c b/drivers/dma/ppc4xx/adma.c
index 4cf0d4d0cecf..25610286979f 100644
--- a/drivers/dma/ppc4xx/adma.c
+++ b/drivers/dma/ppc4xx/adma.c
@@ -4360,7 +4360,7 @@ static ssize_t enable_store(struct device_driver *dev, const char *buf,
}
static DRIVER_ATTR_RW(enable);
-static ssize_t poly_store(struct device_driver *dev, char *buf)
+static ssize_t poly_show(struct device_driver *dev, char *buf)
{
ssize_t size = 0;
u32 reg;
diff --git a/drivers/dma/pxa_dma.c b/drivers/dma/pxa_dma.c
index b31c28b67ad3..825725057e00 100644
--- a/drivers/dma/pxa_dma.c
+++ b/drivers/dma/pxa_dma.c
@@ -1285,7 +1285,6 @@ static int pxad_remove(struct platform_device *op)
pxad_cleanup_debugfs(pdev);
pxad_free_channels(&pdev->slave);
- dma_async_device_unregister(&pdev->slave);
return 0;
}
@@ -1396,7 +1395,7 @@ static int pxad_init_dmadev(struct platform_device *op,
init_waitqueue_head(&c->wq_state);
}
- return dma_async_device_register(&pdev->slave);
+ return dmaenginem_async_device_register(&pdev->slave);
}
static int pxad_probe(struct platform_device *op)
@@ -1433,7 +1432,7 @@ static int pxad_probe(struct platform_device *op)
"#dma-requests set to default 32 as missing in OF: %d",
ret);
nb_requestors = 32;
- };
+ }
} else if (pdata && pdata->dma_channels) {
dma_channels = pdata->dma_channels;
nb_requestors = pdata->nb_requestors;
diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c
index 48ee35e2bce6..74fa2b1a6a86 100644
--- a/drivers/dma/sh/rcar-dmac.c
+++ b/drivers/dma/sh/rcar-dmac.c
@@ -198,6 +198,7 @@ struct rcar_dmac {
struct dma_device engine;
struct device *dev;
void __iomem *iomem;
+ struct device_dma_parameters parms;
unsigned int n_channels;
struct rcar_dmac_chan *channels;
@@ -1792,6 +1793,8 @@ static int rcar_dmac_probe(struct platform_device *pdev)
dmac->dev = &pdev->dev;
platform_set_drvdata(pdev, dmac);
+ dmac->dev->dma_parms = &dmac->parms;
+ dma_set_max_seg_size(dmac->dev, RCAR_DMATCR_MASK);
dma_set_mask_and_coherent(dmac->dev, DMA_BIT_MASK(40));
ret = rcar_dmac_parse_of(&pdev->dev, dmac);
diff --git a/drivers/dma/sh/shdma-arm.h b/drivers/dma/sh/shdma-arm.h
index a1b0ef45d6a2..7459f9a13b5b 100644
--- a/drivers/dma/sh/shdma-arm.h
+++ b/drivers/dma/sh/shdma-arm.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Renesas SuperH DMA Engine support
*
* Copyright (C) 2013 Renesas Electronics, Inc.
- *
- * This is free software; you can redistribute it and/or modify it under the
- * terms of version 2 the GNU General Public License as published by the Free
- * Software Foundation.
*/
#ifndef SHDMA_ARM_H
diff --git a/drivers/dma/sh/shdma-base.c b/drivers/dma/sh/shdma-base.c
index 6b5626e299b2..c51de498b5b4 100644
--- a/drivers/dma/sh/shdma-base.c
+++ b/drivers/dma/sh/shdma-base.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Dmaengine driver base library for DMA controllers, found on SH-based SoCs
*
@@ -7,10 +8,6 @@
* Copyright (C) 2009 Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
* Copyright (C) 2009 Renesas Solutions, Inc. All rights reserved.
* Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
- *
- * This is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
*/
#include <linux/delay.h>
diff --git a/drivers/dma/sh/shdma-of.c b/drivers/dma/sh/shdma-of.c
index f999f9b0d314..be89dd894328 100644
--- a/drivers/dma/sh/shdma-of.c
+++ b/drivers/dma/sh/shdma-of.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* SHDMA Device Tree glue
*
* Copyright (C) 2013 Renesas Electronics Inc.
* Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- *
- * This is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
*/
#include <linux/dmaengine.h>
diff --git a/drivers/dma/sh/shdma-r8a73a4.c b/drivers/dma/sh/shdma-r8a73a4.c
index 96ea3828c3eb..ddc9a3578353 100644
--- a/drivers/dma/sh/shdma-r8a73a4.c
+++ b/drivers/dma/sh/shdma-r8a73a4.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Renesas SuperH DMA Engine support for r8a73a4 (APE6) SoCs
*
* Copyright (C) 2013 Renesas Electronics, Inc.
- *
- * This is free software; you can redistribute it and/or modify it under the
- * terms of version 2 the GNU General Public License as published by the Free
- * Software Foundation.
*/
#include <linux/sh_dma.h>
diff --git a/drivers/dma/sh/shdma.h b/drivers/dma/sh/shdma.h
index 2c0a969adc9f..bfb69909bd19 100644
--- a/drivers/dma/sh/shdma.h
+++ b/drivers/dma/sh/shdma.h
@@ -1,14 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Renesas SuperH DMA Engine support
*
* Copyright (C) 2009 Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
* Copyright (C) 2009 Renesas Solutions, Inc. All rights reserved.
*
- * This 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.
- *
*/
#ifndef __DMA_SHDMA_H
#define __DMA_SHDMA_H
diff --git a/drivers/dma/sh/shdmac.c b/drivers/dma/sh/shdmac.c
index 04a74e0a95b7..7971ea275387 100644
--- a/drivers/dma/sh/shdmac.c
+++ b/drivers/dma/sh/shdmac.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Renesas SuperH DMA Engine support
*
@@ -8,11 +9,6 @@
* Copyright (C) 2009 Renesas Solutions, Inc. All rights reserved.
* Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
*
- * This 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.
- *
* - DMA of SuperH does not have Hardware DMA chain mode.
* - MAX DMA size is 16MB.
*
diff --git a/drivers/dma/sh/sudmac.c b/drivers/dma/sh/sudmac.c
index 69b9564dc9d9..30cc3553cb8b 100644
--- a/drivers/dma/sh/sudmac.c
+++ b/drivers/dma/sh/sudmac.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Renesas SUDMAC support
*
@@ -8,10 +9,6 @@
* Copyright (C) 2009 Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
* Copyright (C) 2009 Renesas Solutions, Inc. All rights reserved.
* Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
- *
- * This is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
*/
#include <linux/dmaengine.h>
diff --git a/drivers/dma/sh/usb-dmac.c b/drivers/dma/sh/usb-dmac.c
index 1bb1a8e09025..7f7184c3cf95 100644
--- a/drivers/dma/sh/usb-dmac.c
+++ b/drivers/dma/sh/usb-dmac.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Renesas USB DMA Controller Driver
*
@@ -6,10 +7,6 @@
* based on rcar-dmac.c
* Copyright (C) 2014 Renesas Electronics Inc.
* Author: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- *
- * This is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
*/
#include <linux/delay.h>
diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c
index 55df0d41355b..38d4e4f07c66 100644
--- a/drivers/dma/sprd-dma.c
+++ b/drivers/dma/sprd-dma.c
@@ -68,6 +68,7 @@
/* SPRD_DMA_CHN_CFG register definition */
#define SPRD_DMA_CHN_EN BIT(0)
+#define SPRD_DMA_LINKLIST_EN BIT(4)
#define SPRD_DMA_WAIT_BDONE_OFFSET 24
#define SPRD_DMA_DONOT_WAIT_BDONE 1
@@ -103,7 +104,7 @@
#define SPRD_DMA_REQ_MODE_MASK GENMASK(1, 0)
#define SPRD_DMA_FIX_SEL_OFFSET 21
#define SPRD_DMA_FIX_EN_OFFSET 20
-#define SPRD_DMA_LLIST_END_OFFSET 19
+#define SPRD_DMA_LLIST_END BIT(19)
#define SPRD_DMA_FRG_LEN_MASK GENMASK(16, 0)
/* SPRD_DMA_CHN_BLK_LEN register definition */
@@ -164,6 +165,7 @@ struct sprd_dma_desc {
struct sprd_dma_chn {
struct virt_dma_chan vc;
void __iomem *chn_base;
+ struct sprd_dma_linklist linklist;
struct dma_slave_config slave_cfg;
u32 chn_num;
u32 dev_id;
@@ -582,7 +584,8 @@ static int sprd_dma_get_step(enum dma_slave_buswidth buswidth)
}
static int sprd_dma_fill_desc(struct dma_chan *chan,
- struct sprd_dma_desc *sdesc,
+ struct sprd_dma_chn_hw *hw,
+ unsigned int sglen, int sg_index,
dma_addr_t src, dma_addr_t dst, u32 len,
enum dma_transfer_direction dir,
unsigned long flags,
@@ -590,7 +593,6 @@ static int sprd_dma_fill_desc(struct dma_chan *chan,
{
struct sprd_dma_dev *sdev = to_sprd_dma_dev(chan);
struct sprd_dma_chn *schan = to_sprd_dma_chan(chan);
- struct sprd_dma_chn_hw *hw = &sdesc->chn_hw;
u32 req_mode = (flags >> SPRD_DMA_REQ_SHIFT) & SPRD_DMA_REQ_MODE_MASK;
u32 int_mode = flags & SPRD_DMA_INT_MASK;
int src_datawidth, dst_datawidth, src_step, dst_step;
@@ -670,12 +672,52 @@ static int sprd_dma_fill_desc(struct dma_chan *chan,
temp |= (src_step & SPRD_DMA_TRSF_STEP_MASK) << SPRD_DMA_SRC_TRSF_STEP_OFFSET;
hw->trsf_step = temp;
+ /* link-list configuration */
+ if (schan->linklist.phy_addr) {
+ if (sg_index == sglen - 1)
+ hw->frg_len |= SPRD_DMA_LLIST_END;
+
+ hw->cfg |= SPRD_DMA_LINKLIST_EN;
+
+ /* link-list index */
+ temp = (sg_index + 1) % sglen;
+ /* Next link-list configuration's physical address offset */
+ temp = temp * sizeof(*hw) + SPRD_DMA_CHN_SRC_ADDR;
+ /*
+ * Set the link-list pointer point to next link-list
+ * configuration's physical address.
+ */
+ hw->llist_ptr = schan->linklist.phy_addr + temp;
+ } else {
+ hw->llist_ptr = 0;
+ }
+
hw->frg_step = 0;
hw->src_blk_step = 0;
hw->des_blk_step = 0;
return 0;
}
+static int sprd_dma_fill_linklist_desc(struct dma_chan *chan,
+ unsigned int sglen, int sg_index,
+ dma_addr_t src, dma_addr_t dst, u32 len,
+ enum dma_transfer_direction dir,
+ unsigned long flags,
+ struct dma_slave_config *slave_cfg)
+{
+ struct sprd_dma_chn *schan = to_sprd_dma_chan(chan);
+ struct sprd_dma_chn_hw *hw;
+
+ if (!schan->linklist.virt_addr)
+ return -EINVAL;
+
+ hw = (struct sprd_dma_chn_hw *)(schan->linklist.virt_addr +
+ sg_index * sizeof(*hw));
+
+ return sprd_dma_fill_desc(chan, hw, sglen, sg_index, src, dst, len,
+ dir, flags, slave_cfg);
+}
+
static struct dma_async_tx_descriptor *
sprd_dma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
size_t len, unsigned long flags)
@@ -744,10 +786,20 @@ sprd_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
u32 len = 0;
int ret, i;
- /* TODO: now we only support one sg for each DMA configuration. */
- if (!is_slave_direction(dir) || sglen > 1)
+ if (!is_slave_direction(dir))
return NULL;
+ if (context) {
+ struct sprd_dma_linklist *ll_cfg =
+ (struct sprd_dma_linklist *)context;
+
+ schan->linklist.phy_addr = ll_cfg->phy_addr;
+ schan->linklist.virt_addr = ll_cfg->virt_addr;
+ } else {
+ schan->linklist.phy_addr = 0;
+ schan->linklist.virt_addr = 0;
+ }
+
sdesc = kzalloc(sizeof(*sdesc), GFP_NOWAIT);
if (!sdesc)
return NULL;
@@ -762,10 +814,25 @@ sprd_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
src = slave_cfg->src_addr;
dst = sg_dma_address(sg);
}
+
+ /*
+ * The link-list mode needs at least 2 link-list
+ * configurations. If there is only one sg, it doesn't
+ * need to fill the link-list configuration.
+ */
+ if (sglen < 2)
+ break;
+
+ ret = sprd_dma_fill_linklist_desc(chan, sglen, i, src, dst, len,
+ dir, flags, slave_cfg);
+ if (ret) {
+ kfree(sdesc);
+ return NULL;
+ }
}
- ret = sprd_dma_fill_desc(chan, sdesc, src, dst, len, dir, flags,
- slave_cfg);
+ ret = sprd_dma_fill_desc(chan, &sdesc->chn_hw, 0, 0, src, dst, len,
+ dir, flags, slave_cfg);
if (ret) {
kfree(sdesc);
return NULL;
diff --git a/drivers/dma/st_fdma.c b/drivers/dma/st_fdma.c
index bfb79bd0c6de..07c20aa2e955 100644
--- a/drivers/dma/st_fdma.c
+++ b/drivers/dma/st_fdma.c
@@ -833,7 +833,7 @@ static int st_fdma_probe(struct platform_device *pdev)
fdev->dma_device.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
fdev->dma_device.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
- ret = dma_async_device_register(&fdev->dma_device);
+ ret = dmaenginem_async_device_register(&fdev->dma_device);
if (ret) {
dev_err(&pdev->dev,
"Failed to register DMA device (%d)\n", ret);
@@ -844,15 +844,13 @@ static int st_fdma_probe(struct platform_device *pdev)
if (ret) {
dev_err(&pdev->dev,
"Failed to register controller (%d)\n", ret);
- goto err_dma_dev;
+ goto err_rproc;
}
dev_info(&pdev->dev, "ST FDMA engine driver, irq:%d\n", fdev->irq);
return 0;
-err_dma_dev:
- dma_async_device_unregister(&fdev->dma_device);
err_rproc:
st_fdma_free(fdev);
st_slim_rproc_put(fdev->slim_rproc);
@@ -867,7 +865,6 @@ static int st_fdma_remove(struct platform_device *pdev)
devm_free_irq(&pdev->dev, fdev->irq, fdev);
st_slim_rproc_put(fdev->slim_rproc);
of_dma_controller_free(pdev->dev.of_node);
- dma_async_device_unregister(&fdev->dma_device);
return 0;
}
diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c
index f4edfc56f34e..5e328bd10c27 100644
--- a/drivers/dma/ste_dma40.c
+++ b/drivers/dma/ste_dma40.c
@@ -2839,7 +2839,7 @@ static int __init d40_dmaengine_init(struct d40_base *base,
d40_ops_init(base, &base->dma_slave);
- err = dma_async_device_register(&base->dma_slave);
+ err = dmaenginem_async_device_register(&base->dma_slave);
if (err) {
d40_err(base->dev, "Failed to register slave channels\n");
@@ -2854,12 +2854,12 @@ static int __init d40_dmaengine_init(struct d40_base *base,
d40_ops_init(base, &base->dma_memcpy);
- err = dma_async_device_register(&base->dma_memcpy);
+ err = dmaenginem_async_device_register(&base->dma_memcpy);
if (err) {
d40_err(base->dev,
"Failed to register memcpy only channels\n");
- goto unregister_slave;
+ goto exit;
}
d40_chan_init(base, &base->dma_both, base->phy_chans,
@@ -2871,18 +2871,14 @@ static int __init d40_dmaengine_init(struct d40_base *base,
dma_cap_set(DMA_CYCLIC, base->dma_slave.cap_mask);
d40_ops_init(base, &base->dma_both);
- err = dma_async_device_register(&base->dma_both);
+ err = dmaenginem_async_device_register(&base->dma_both);
if (err) {
d40_err(base->dev,
"Failed to register logical and physical capable channels\n");
- goto unregister_memcpy;
+ goto exit;
}
return 0;
- unregister_memcpy:
- dma_async_device_unregister(&base->dma_memcpy);
- unregister_slave:
- dma_async_device_unregister(&base->dma_slave);
exit:
return err;
}
diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c
index 379e8d534e61..4903a408fc14 100644
--- a/drivers/dma/stm32-dma.c
+++ b/drivers/dma/stm32-dma.c
@@ -308,20 +308,12 @@ static bool stm32_dma_fifo_threshold_is_allowed(u32 burst, u32 threshold,
static bool stm32_dma_is_burst_possible(u32 buf_len, u32 threshold)
{
- switch (threshold) {
- case STM32_DMA_FIFO_THRESHOLD_FULL:
- if (buf_len >= STM32_DMA_MAX_BURST)
- return true;
- else
- return false;
- case STM32_DMA_FIFO_THRESHOLD_HALFFULL:
- if (buf_len >= STM32_DMA_MAX_BURST / 2)
- return true;
- else
- return false;
- default:
- return false;
- }
+ /*
+ * Buffer or period length has to be aligned on FIFO depth.
+ * Otherwise bytes may be stuck within FIFO at buffer or period
+ * length.
+ */
+ return ((buf_len % ((threshold + 1) * 4)) == 0);
}
static u32 stm32_dma_get_best_burst(u32 buf_len, u32 max_burst, u32 threshold,
diff --git a/drivers/dma/stm32-mdma.c b/drivers/dma/stm32-mdma.c
index 06dd1725375e..390e4cae0e1a 100644
--- a/drivers/dma/stm32-mdma.c
+++ b/drivers/dma/stm32-mdma.c
@@ -1656,7 +1656,7 @@ static int stm32_mdma_probe(struct platform_device *pdev)
return ret;
}
- ret = dma_async_device_register(dd);
+ ret = dmaenginem_async_device_register(dd);
if (ret)
return ret;
@@ -1674,8 +1674,6 @@ static int stm32_mdma_probe(struct platform_device *pdev)
return 0;
err_unregister:
- dma_async_device_unregister(dd);
-
return ret;
}
diff --git a/drivers/dma/timb_dma.c b/drivers/dma/timb_dma.c
index 395c698edb4d..fc0f9c8766a8 100644
--- a/drivers/dma/timb_dma.c
+++ b/drivers/dma/timb_dma.c
@@ -545,7 +545,7 @@ static struct dma_async_tx_descriptor *td_prep_slave_sg(struct dma_chan *chan,
}
dma_sync_single_for_device(chan2dmadev(chan), td_desc->txd.phys,
- td_desc->desc_list_len, DMA_MEM_TO_DEV);
+ td_desc->desc_list_len, DMA_TO_DEVICE);
return &td_desc->txd;
}
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 57304b2e989f..41c9ccdd20d6 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -234,6 +234,7 @@ config EDAC_SKX
depends on PCI && X86_64 && X86_MCE_INTEL && PCI_MMCONFIG
depends on ACPI_NFIT || !ACPI_NFIT # if ACPI_NFIT=m, EDAC_SKX can't be y
select DMI
+ select ACPI_ADXL if ACPI
help
Support for error detection and correction the Intel
Skylake server Integrated Memory Controllers. If your
@@ -460,4 +461,18 @@ config EDAC_TI
Support for error detection and correction on the
TI SoCs.
+config EDAC_QCOM
+ tristate "QCOM EDAC Controller"
+ depends on ARCH_QCOM && QCOM_LLCC
+ help
+ Support for error detection and correction on the
+ Qualcomm Technologies, Inc. SoCs.
+
+ This driver reports Single Bit Errors (SBEs) and Double Bit Errors (DBEs).
+ As of now, it supports error reporting for Last Level Cache Controller (LLCC)
+ of Tag RAM and Data RAM.
+
+ For debugging issues having to do with stability and overall system
+ health, you should probably say 'Y' here.
+
endif # EDAC
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
index 02b43a7d8c3e..716096d08ea0 100644
--- a/drivers/edac/Makefile
+++ b/drivers/edac/Makefile
@@ -77,3 +77,4 @@ obj-$(CONFIG_EDAC_ALTERA) += altera_edac.o
obj-$(CONFIG_EDAC_SYNOPSYS) += synopsys_edac.o
obj-$(CONFIG_EDAC_XGENE) += xgene_edac.o
obj-$(CONFIG_EDAC_TI) += ti_edac.o
+obj-$(CONFIG_EDAC_QCOM) += qcom_edac.o
diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c
index 5762c3c383f2..c89d82aa2776 100644
--- a/drivers/edac/altera_edac.c
+++ b/drivers/edac/altera_edac.c
@@ -69,25 +69,6 @@ static const struct altr_sdram_prv_data a10_data = {
.ue_set_mask = A10_DIAGINT_TDERRA_MASK,
};
-static const struct altr_sdram_prv_data s10_data = {
- .ecc_ctrl_offset = S10_ECCCTRL1_OFST,
- .ecc_ctl_en_mask = A10_ECCCTRL1_ECC_EN,
- .ecc_stat_offset = S10_INTSTAT_OFST,
- .ecc_stat_ce_mask = A10_INTSTAT_SBEERR,
- .ecc_stat_ue_mask = A10_INTSTAT_DBEERR,
- .ecc_saddr_offset = S10_SERRADDR_OFST,
- .ecc_daddr_offset = S10_DERRADDR_OFST,
- .ecc_irq_en_offset = S10_ERRINTEN_OFST,
- .ecc_irq_en_mask = A10_ECC_IRQ_EN_MASK,
- .ecc_irq_clr_offset = S10_INTSTAT_OFST,
- .ecc_irq_clr_mask = (A10_INTSTAT_SBEERR | A10_INTSTAT_DBEERR),
- .ecc_cnt_rst_offset = S10_ECCCTRL1_OFST,
- .ecc_cnt_rst_mask = A10_ECC_CNT_RESET_MASK,
- .ce_ue_trgr_offset = S10_DIAGINTTEST_OFST,
- .ce_set_mask = A10_DIAGINT_TSERRA_MASK,
- .ue_set_mask = A10_DIAGINT_TDERRA_MASK,
-};
-
/*********************** EDAC Memory Controller Functions ****************/
/* The SDRAM controller uses the EDAC Memory Controller framework. */
@@ -239,7 +220,7 @@ static unsigned long get_total_mem(void)
static const struct of_device_id altr_sdram_ctrl_of_match[] = {
{ .compatible = "altr,sdram-edac", .data = &c5_data},
{ .compatible = "altr,sdram-edac-a10", .data = &a10_data},
- { .compatible = "altr,sdram-edac-s10", .data = &s10_data},
+ { .compatible = "altr,sdram-edac-s10", .data = &a10_data},
{},
};
MODULE_DEVICE_TABLE(of, altr_sdram_ctrl_of_match);
@@ -293,6 +274,7 @@ release:
return ret;
}
+static int socfpga_is_a10(void);
static int altr_sdram_probe(struct platform_device *pdev)
{
const struct of_device_id *id;
@@ -416,7 +398,7 @@ static int altr_sdram_probe(struct platform_device *pdev)
goto err;
/* Only the Arria10 has separate IRQs */
- if (irq2 > 0) {
+ if (socfpga_is_a10()) {
/* Arria10 specific initialization */
res = a10_init(mc_vbase);
if (res < 0)
@@ -502,8 +484,9 @@ static int s10_protected_reg_write(void *context, unsigned int reg,
unsigned int val)
{
struct arm_smccc_res result;
+ unsigned long offset = (unsigned long)context;
- arm_smccc_smc(INTEL_SIP_SMC_REG_WRITE, reg, val, 0, 0,
+ arm_smccc_smc(INTEL_SIP_SMC_REG_WRITE, offset + reg, val, 0, 0,
0, 0, 0, &result);
return (int)result.a0;
@@ -523,8 +506,9 @@ static int s10_protected_reg_read(void *context, unsigned int reg,
unsigned int *val)
{
struct arm_smccc_res result;
+ unsigned long offset = (unsigned long)context;
- arm_smccc_smc(INTEL_SIP_SMC_REG_READ, reg, 0, 0, 0,
+ arm_smccc_smc(INTEL_SIP_SMC_REG_READ, offset + reg, 0, 0, 0,
0, 0, 0, &result);
*val = (unsigned int)result.a1;
@@ -532,245 +516,18 @@ static int s10_protected_reg_read(void *context, unsigned int reg,
return (int)result.a0;
}
-static bool s10_sdram_writeable_reg(struct device *dev, unsigned int reg)
-{
- switch (reg) {
- case S10_ECCCTRL1_OFST:
- case S10_ERRINTEN_OFST:
- case S10_INTMODE_OFST:
- case S10_INTSTAT_OFST:
- case S10_DIAGINTTEST_OFST:
- case S10_SYSMGR_ECC_INTMASK_VAL_OFST:
- case S10_SYSMGR_ECC_INTMASK_SET_OFST:
- case S10_SYSMGR_ECC_INTMASK_CLR_OFST:
- return true;
- }
- return false;
-}
-
-static bool s10_sdram_readable_reg(struct device *dev, unsigned int reg)
-{
- switch (reg) {
- case S10_ECCCTRL1_OFST:
- case S10_ERRINTEN_OFST:
- case S10_INTMODE_OFST:
- case S10_INTSTAT_OFST:
- case S10_DERRADDR_OFST:
- case S10_SERRADDR_OFST:
- case S10_DIAGINTTEST_OFST:
- case S10_SYSMGR_ECC_INTMASK_VAL_OFST:
- case S10_SYSMGR_ECC_INTMASK_SET_OFST:
- case S10_SYSMGR_ECC_INTMASK_CLR_OFST:
- case S10_SYSMGR_ECC_INTSTAT_SERR_OFST:
- case S10_SYSMGR_ECC_INTSTAT_DERR_OFST:
- return true;
- }
- return false;
-}
-
-static bool s10_sdram_volatile_reg(struct device *dev, unsigned int reg)
-{
- switch (reg) {
- case S10_ECCCTRL1_OFST:
- case S10_ERRINTEN_OFST:
- case S10_INTMODE_OFST:
- case S10_INTSTAT_OFST:
- case S10_DERRADDR_OFST:
- case S10_SERRADDR_OFST:
- case S10_DIAGINTTEST_OFST:
- case S10_SYSMGR_ECC_INTMASK_VAL_OFST:
- case S10_SYSMGR_ECC_INTMASK_SET_OFST:
- case S10_SYSMGR_ECC_INTMASK_CLR_OFST:
- case S10_SYSMGR_ECC_INTSTAT_SERR_OFST:
- case S10_SYSMGR_ECC_INTSTAT_DERR_OFST:
- return true;
- }
- return false;
-}
-
static const struct regmap_config s10_sdram_regmap_cfg = {
.name = "s10_ddr",
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
- .max_register = 0xffffffff,
- .writeable_reg = s10_sdram_writeable_reg,
- .readable_reg = s10_sdram_readable_reg,
- .volatile_reg = s10_sdram_volatile_reg,
+ .max_register = 0xffd12228,
.reg_read = s10_protected_reg_read,
.reg_write = s10_protected_reg_write,
- .use_single_rw = true,
+ .use_single_read = true,
+ .use_single_write = true,
};
-static int altr_s10_sdram_probe(struct platform_device *pdev)
-{
- const struct of_device_id *id;
- struct edac_mc_layer layers[2];
- struct mem_ctl_info *mci;
- struct altr_sdram_mc_data *drvdata;
- const struct altr_sdram_prv_data *priv;
- struct regmap *regmap;
- struct dimm_info *dimm;
- u32 read_reg;
- int irq, ret = 0;
- unsigned long mem_size;
-
- id = of_match_device(altr_sdram_ctrl_of_match, &pdev->dev);
- if (!id)
- return -ENODEV;
-
- /* Grab specific offsets and masks for Stratix10 */
- priv = of_match_node(altr_sdram_ctrl_of_match,
- pdev->dev.of_node)->data;
-
- regmap = devm_regmap_init(&pdev->dev, NULL, (void *)priv,
- &s10_sdram_regmap_cfg);
- if (IS_ERR(regmap))
- return PTR_ERR(regmap);
-
- /* Validate the SDRAM controller has ECC enabled */
- if (regmap_read(regmap, priv->ecc_ctrl_offset, &read_reg) ||
- ((read_reg & priv->ecc_ctl_en_mask) != priv->ecc_ctl_en_mask)) {
- edac_printk(KERN_ERR, EDAC_MC,
- "No ECC/ECC disabled [0x%08X]\n", read_reg);
- return -ENODEV;
- }
-
- /* Grab memory size from device tree. */
- mem_size = get_total_mem();
- if (!mem_size) {
- edac_printk(KERN_ERR, EDAC_MC, "Unable to calculate memory size\n");
- return -ENODEV;
- }
-
- /* Ensure the SDRAM Interrupt is disabled */
- if (regmap_update_bits(regmap, priv->ecc_irq_en_offset,
- priv->ecc_irq_en_mask, 0)) {
- edac_printk(KERN_ERR, EDAC_MC,
- "Error disabling SDRAM ECC IRQ\n");
- return -ENODEV;
- }
-
- /* Toggle to clear the SDRAM Error count */
- if (regmap_update_bits(regmap, priv->ecc_cnt_rst_offset,
- priv->ecc_cnt_rst_mask,
- priv->ecc_cnt_rst_mask)) {
- edac_printk(KERN_ERR, EDAC_MC,
- "Error clearing SDRAM ECC count\n");
- return -ENODEV;
- }
-
- if (regmap_update_bits(regmap, priv->ecc_cnt_rst_offset,
- priv->ecc_cnt_rst_mask, 0)) {
- edac_printk(KERN_ERR, EDAC_MC,
- "Error clearing SDRAM ECC count\n");
- return -ENODEV;
- }
-
- irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- edac_printk(KERN_ERR, EDAC_MC,
- "No irq %d in DT\n", irq);
- return -ENODEV;
- }
-
- layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
- layers[0].size = 1;
- layers[0].is_virt_csrow = true;
- layers[1].type = EDAC_MC_LAYER_CHANNEL;
- layers[1].size = 1;
- layers[1].is_virt_csrow = false;
- mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers,
- sizeof(struct altr_sdram_mc_data));
- if (!mci)
- return -ENOMEM;
-
- mci->pdev = &pdev->dev;
- drvdata = mci->pvt_info;
- drvdata->mc_vbase = regmap;
- drvdata->data = priv;
- platform_set_drvdata(pdev, mci);
-
- if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL)) {
- edac_printk(KERN_ERR, EDAC_MC,
- "Unable to get managed device resource\n");
- ret = -ENOMEM;
- goto free;
- }
-
- mci->mtype_cap = MEM_FLAG_DDR3;
- mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
- mci->edac_cap = EDAC_FLAG_SECDED;
- mci->mod_name = EDAC_MOD_STR;
- mci->ctl_name = dev_name(&pdev->dev);
- mci->scrub_mode = SCRUB_SW_SRC;
- mci->dev_name = dev_name(&pdev->dev);
-
- dimm = *mci->dimms;
- dimm->nr_pages = ((mem_size - 1) >> PAGE_SHIFT) + 1;
- dimm->grain = 8;
- dimm->dtype = DEV_X8;
- dimm->mtype = MEM_DDR3;
- dimm->edac_mode = EDAC_SECDED;
-
- ret = edac_mc_add_mc(mci);
- if (ret < 0)
- goto err;
-
- ret = devm_request_irq(&pdev->dev, irq, altr_sdram_mc_err_handler,
- IRQF_SHARED, dev_name(&pdev->dev), mci);
- if (ret < 0) {
- edac_mc_printk(mci, KERN_ERR,
- "Unable to request irq %d\n", irq);
- ret = -ENODEV;
- goto err2;
- }
-
- if (regmap_write(regmap, S10_SYSMGR_ECC_INTMASK_CLR_OFST,
- S10_DDR0_IRQ_MASK)) {
- edac_printk(KERN_ERR, EDAC_MC,
- "Error clearing SDRAM ECC count\n");
- ret = -ENODEV;
- goto err2;
- }
-
- if (regmap_update_bits(drvdata->mc_vbase, priv->ecc_irq_en_offset,
- priv->ecc_irq_en_mask, priv->ecc_irq_en_mask)) {
- edac_mc_printk(mci, KERN_ERR,
- "Error enabling SDRAM ECC IRQ\n");
- ret = -ENODEV;
- goto err2;
- }
-
- altr_sdr_mc_create_debugfs_nodes(mci);
-
- devres_close_group(&pdev->dev, NULL);
-
- return 0;
-
-err2:
- edac_mc_del_mc(&pdev->dev);
-err:
- devres_release_group(&pdev->dev, NULL);
-free:
- edac_mc_free(mci);
- edac_printk(KERN_ERR, EDAC_MC,
- "EDAC Probe Failed; Error %d\n", ret);
-
- return ret;
-}
-
-static int altr_s10_sdram_remove(struct platform_device *pdev)
-{
- struct mem_ctl_info *mci = platform_get_drvdata(pdev);
-
- edac_mc_del_mc(&pdev->dev);
- edac_mc_free(mci);
- platform_set_drvdata(pdev, NULL);
-
- return 0;
-}
-
/************** </Stratix10 EDAC Memory Controller Functions> ***********/
/*
@@ -804,20 +561,6 @@ static struct platform_driver altr_sdram_edac_driver = {
module_platform_driver(altr_sdram_edac_driver);
-static struct platform_driver altr_s10_sdram_edac_driver = {
- .probe = altr_s10_sdram_probe,
- .remove = altr_s10_sdram_remove,
- .driver = {
- .name = "altr_s10_sdram_edac",
-#ifdef CONFIG_PM
- .pm = &altr_sdram_pm_ops,
-#endif
- .of_match_table = altr_sdram_ctrl_of_match,
- },
-};
-
-module_platform_driver(altr_s10_sdram_edac_driver);
-
/************************* EDAC Parent Probe *************************/
static const struct of_device_id altr_edac_device_of_match[];
@@ -971,6 +714,16 @@ static const struct file_operations altr_edac_a10_device_inject_fops = {
.llseek = generic_file_llseek,
};
+static ssize_t altr_edac_a10_device_trig2(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos);
+
+static const struct file_operations altr_edac_a10_device_inject2_fops = {
+ .open = simple_open,
+ .write = altr_edac_a10_device_trig2,
+ .llseek = generic_file_llseek,
+};
+
static void altr_create_edacdev_dbgfs(struct edac_device_ctl_info *edac_dci,
const struct edac_device_prv_data *priv)
{
@@ -1252,6 +1005,16 @@ static int __maybe_unused altr_init_memory_port(void __iomem *ioaddr, int port)
return ret;
}
+static int socfpga_is_a10(void)
+{
+ return of_machine_is_compatible("altr,socfpga-arria10");
+}
+
+static int socfpga_is_s10(void)
+{
+ return of_machine_is_compatible("altr,socfpga-stratix10");
+}
+
static __init int __maybe_unused
altr_init_a10_ecc_block(struct device_node *np, u32 irq_mask,
u32 ecc_ctrl_en_mask, bool dual_port)
@@ -1266,8 +1029,32 @@ altr_init_a10_ecc_block(struct device_node *np, u32 irq_mask,
/* Get the ECC Manager - parent of the device EDACs */
np_eccmgr = of_get_parent(np);
- ecc_mgr_map = syscon_regmap_lookup_by_phandle(np_eccmgr,
- "altr,sysmgr-syscon");
+
+ if (socfpga_is_a10()) {
+ ecc_mgr_map = syscon_regmap_lookup_by_phandle(np_eccmgr,
+ "altr,sysmgr-syscon");
+ } else {
+ struct device_node *sysmgr_np;
+ struct resource res;
+ uintptr_t base;
+
+ sysmgr_np = of_parse_phandle(np_eccmgr,
+ "altr,sysmgr-syscon", 0);
+ if (!sysmgr_np) {
+ edac_printk(KERN_ERR, EDAC_DEVICE,
+ "Unable to find altr,sysmgr-syscon\n");
+ return -ENODEV;
+ }
+
+ if (of_address_to_resource(sysmgr_np, 0, &res))
+ return -ENOMEM;
+
+ /* Need physical address for SMCC call */
+ base = res.start;
+
+ ecc_mgr_map = regmap_init(NULL, NULL, (void *)base,
+ &s10_sdram_regmap_cfg);
+ }
of_node_put(np_eccmgr);
if (IS_ERR(ecc_mgr_map)) {
edac_printk(KERN_ERR, EDAC_DEVICE,
@@ -1325,11 +1112,6 @@ out:
return ret;
}
-static int socfpga_is_a10(void)
-{
- return of_machine_is_compatible("altr,socfpga-arria10");
-}
-
static int validate_parent_available(struct device_node *np);
static const struct of_device_id altr_edac_a10_device_of_match[];
static int __init __maybe_unused altr_init_a10_ecc_device_type(char *compat)
@@ -1337,7 +1119,7 @@ static int __init __maybe_unused altr_init_a10_ecc_device_type(char *compat)
int irq;
struct device_node *child, *np;
- if (!socfpga_is_a10())
+ if (!socfpga_is_a10() && !socfpga_is_s10())
return -ENODEV;
np = of_find_compatible_node(NULL, NULL,
@@ -1583,7 +1365,7 @@ static const struct edac_device_prv_data a10_enetecc_data = {
.ue_set_mask = ALTR_A10_ECC_TDERRA,
.set_err_ofst = ALTR_A10_ECC_INTTEST_OFST,
.ecc_irq_handler = altr_edac_a10_ecc_irq,
- .inject_fops = &altr_edac_a10_device_inject_fops,
+ .inject_fops = &altr_edac_a10_device_inject2_fops,
};
static int __init socfpga_init_ethernet_ecc(void)
@@ -1661,7 +1443,7 @@ static const struct edac_device_prv_data a10_usbecc_data = {
.ue_set_mask = ALTR_A10_ECC_TDERRA,
.set_err_ofst = ALTR_A10_ECC_INTTEST_OFST,
.ecc_irq_handler = altr_edac_a10_ecc_irq,
- .inject_fops = &altr_edac_a10_device_inject_fops,
+ .inject_fops = &altr_edac_a10_device_inject2_fops,
};
static int __init socfpga_init_usb_ecc(void)
@@ -1859,7 +1641,7 @@ static int __init socfpga_init_sdmmc_ecc(void)
int rc = -ENODEV;
struct device_node *child;
- if (!socfpga_is_a10())
+ if (!socfpga_is_a10() && !socfpga_is_s10())
return -ENODEV;
child = of_find_compatible_node(NULL, NULL, "altr,socfpga-sdmmc-ecc");
@@ -1943,6 +1725,74 @@ static ssize_t altr_edac_a10_device_trig(struct file *file,
writel(priv->ue_set_mask, set_addr);
else
writel(priv->ce_set_mask, set_addr);
+
+ /* Ensure the interrupt test bits are set */
+ wmb();
+ local_irq_restore(flags);
+
+ return count;
+}
+
+/*
+ * The Stratix10 EDAC Error Injection Functions differ from Arria10
+ * slightly. A few Arria10 peripherals can use this injection function.
+ * Inject the error into the memory and then readback to trigger the IRQ.
+ */
+static ssize_t altr_edac_a10_device_trig2(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct edac_device_ctl_info *edac_dci = file->private_data;
+ struct altr_edac_device_dev *drvdata = edac_dci->pvt_info;
+ const struct edac_device_prv_data *priv = drvdata->data;
+ void __iomem *set_addr = (drvdata->base + priv->set_err_ofst);
+ unsigned long flags;
+ u8 trig_type;
+
+ if (!user_buf || get_user(trig_type, user_buf))
+ return -EFAULT;
+
+ local_irq_save(flags);
+ if (trig_type == ALTR_UE_TRIGGER_CHAR) {
+ writel(priv->ue_set_mask, set_addr);
+ } else {
+ /* Setup write of 0 to first 4 bytes */
+ writel(0x0, drvdata->base + ECC_BLK_WDATA0_OFST);
+ writel(0x0, drvdata->base + ECC_BLK_WDATA1_OFST);
+ writel(0x0, drvdata->base + ECC_BLK_WDATA2_OFST);
+ writel(0x0, drvdata->base + ECC_BLK_WDATA3_OFST);
+ /* Setup write of 4 bytes */
+ writel(ECC_WORD_WRITE, drvdata->base + ECC_BLK_DBYTECTRL_OFST);
+ /* Setup Address to 0 */
+ writel(0x0, drvdata->base + ECC_BLK_ADDRESS_OFST);
+ /* Setup accctrl to write & data override */
+ writel(ECC_WRITE_DOVR, drvdata->base + ECC_BLK_ACCCTRL_OFST);
+ /* Kick it. */
+ writel(ECC_XACT_KICK, drvdata->base + ECC_BLK_STARTACC_OFST);
+ /* Setup accctrl to read & ecc override */
+ writel(ECC_READ_EOVR, drvdata->base + ECC_BLK_ACCCTRL_OFST);
+ /* Kick it. */
+ writel(ECC_XACT_KICK, drvdata->base + ECC_BLK_STARTACC_OFST);
+ /* Setup write for single bit change */
+ writel(0x1, drvdata->base + ECC_BLK_WDATA0_OFST);
+ writel(0x0, drvdata->base + ECC_BLK_WDATA1_OFST);
+ writel(0x0, drvdata->base + ECC_BLK_WDATA2_OFST);
+ writel(0x0, drvdata->base + ECC_BLK_WDATA3_OFST);
+ /* Copy Read ECC to Write ECC */
+ writel(readl(drvdata->base + ECC_BLK_RECC0_OFST),
+ drvdata->base + ECC_BLK_WECC0_OFST);
+ writel(readl(drvdata->base + ECC_BLK_RECC1_OFST),
+ drvdata->base + ECC_BLK_WECC1_OFST);
+ /* Setup accctrl to write & ecc override & data override */
+ writel(ECC_WRITE_EDOVR, drvdata->base + ECC_BLK_ACCCTRL_OFST);
+ /* Kick it. */
+ writel(ECC_XACT_KICK, drvdata->base + ECC_BLK_STARTACC_OFST);
+ /* Setup accctrl to read & ecc overwrite & data overwrite */
+ writel(ECC_READ_EDOVR, drvdata->base + ECC_BLK_ACCCTRL_OFST);
+ /* Kick it. */
+ writel(ECC_XACT_KICK, drvdata->base + ECC_BLK_STARTACC_OFST);
+ }
+
/* Ensure the interrupt test bits are set */
wmb();
local_irq_restore(flags);
@@ -2146,6 +1996,35 @@ static const struct irq_domain_ops a10_eccmgr_ic_ops = {
.xlate = irq_domain_xlate_twocell,
};
+/************** Stratix 10 EDAC Double Bit Error Handler ************/
+#define to_a10edac(p, m) container_of(p, struct altr_arria10_edac, m)
+
+/*
+ * The double bit error is handled through SError which is fatal. This is
+ * called as a panic notifier to printout ECC error info as part of the panic.
+ */
+static int s10_edac_dberr_handler(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ struct altr_arria10_edac *edac = to_a10edac(this, panic_notifier);
+ int err_addr, dberror;
+
+ regmap_read(edac->ecc_mgr_map, S10_SYSMGR_ECC_INTSTAT_DERR_OFST,
+ &dberror);
+ regmap_write(edac->ecc_mgr_map, S10_SYSMGR_UE_VAL_OFST, dberror);
+ if (dberror & S10_DDR0_IRQ_MASK) {
+ regmap_read(edac->ecc_mgr_map, A10_DERRADDR_OFST, &err_addr);
+ regmap_write(edac->ecc_mgr_map, S10_SYSMGR_UE_ADDR_OFST,
+ err_addr);
+ edac_printk(KERN_ERR, EDAC_MC,
+ "EDAC: [Uncorrectable errors @ 0x%08X]\n\n",
+ err_addr);
+ }
+
+ return NOTIFY_DONE;
+}
+
+/****************** Arria 10 EDAC Probe Function *********************/
static int altr_edac_a10_probe(struct platform_device *pdev)
{
struct altr_arria10_edac *edac;
@@ -2159,8 +2038,34 @@ static int altr_edac_a10_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, edac);
INIT_LIST_HEAD(&edac->a10_ecc_devices);
- edac->ecc_mgr_map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+ if (socfpga_is_a10()) {
+ edac->ecc_mgr_map =
+ syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
"altr,sysmgr-syscon");
+ } else {
+ struct device_node *sysmgr_np;
+ struct resource res;
+ uintptr_t base;
+
+ sysmgr_np = of_parse_phandle(pdev->dev.of_node,
+ "altr,sysmgr-syscon", 0);
+ if (!sysmgr_np) {
+ edac_printk(KERN_ERR, EDAC_DEVICE,
+ "Unable to find altr,sysmgr-syscon\n");
+ return -ENODEV;
+ }
+
+ if (of_address_to_resource(sysmgr_np, 0, &res))
+ return -ENOMEM;
+
+ /* Need physical address for SMCC call */
+ base = res.start;
+
+ edac->ecc_mgr_map = devm_regmap_init(&pdev->dev, NULL,
+ (void *)base,
+ &s10_sdram_regmap_cfg);
+ }
+
if (IS_ERR(edac->ecc_mgr_map)) {
edac_printk(KERN_ERR, EDAC_DEVICE,
"Unable to get syscon altr,sysmgr-syscon\n");
@@ -2187,14 +2092,38 @@ static int altr_edac_a10_probe(struct platform_device *pdev)
altr_edac_a10_irq_handler,
edac);
- edac->db_irq = platform_get_irq(pdev, 1);
- if (edac->db_irq < 0) {
- dev_err(&pdev->dev, "No DBERR IRQ resource\n");
- return edac->db_irq;
+ if (socfpga_is_a10()) {
+ edac->db_irq = platform_get_irq(pdev, 1);
+ if (edac->db_irq < 0) {
+ dev_err(&pdev->dev, "No DBERR IRQ resource\n");
+ return edac->db_irq;
+ }
+ irq_set_chained_handler_and_data(edac->db_irq,
+ altr_edac_a10_irq_handler,
+ edac);
+ } else {
+ int dberror, err_addr;
+
+ edac->panic_notifier.notifier_call = s10_edac_dberr_handler;
+ atomic_notifier_chain_register(&panic_notifier_list,
+ &edac->panic_notifier);
+
+ /* Printout a message if uncorrectable error previously. */
+ regmap_read(edac->ecc_mgr_map, S10_SYSMGR_UE_VAL_OFST,
+ &dberror);
+ if (dberror) {
+ regmap_read(edac->ecc_mgr_map, S10_SYSMGR_UE_ADDR_OFST,
+ &err_addr);
+ edac_printk(KERN_ERR, EDAC_DEVICE,
+ "Previous Boot UE detected[0x%X] @ 0x%X\n",
+ dberror, err_addr);
+ /* Reset the sticky registers */
+ regmap_write(edac->ecc_mgr_map,
+ S10_SYSMGR_UE_VAL_OFST, 0);
+ regmap_write(edac->ecc_mgr_map,
+ S10_SYSMGR_UE_ADDR_OFST, 0);
+ }
}
- irq_set_chained_handler_and_data(edac->db_irq,
- altr_edac_a10_irq_handler,
- edac);
for_each_child_of_node(pdev->dev.of_node, child) {
if (!of_device_is_available(child))
@@ -2211,7 +2140,8 @@ static int altr_edac_a10_probe(struct platform_device *pdev)
altr_edac_a10_device_add(edac, child);
- else if (of_device_is_compatible(child, "altr,sdram-edac-a10"))
+ else if ((of_device_is_compatible(child, "altr,sdram-edac-a10")) ||
+ (of_device_is_compatible(child, "altr,sdram-edac-s10")))
of_platform_populate(pdev->dev.of_node,
altr_sdram_ctrl_of_match,
NULL, &pdev->dev);
@@ -2222,6 +2152,7 @@ static int altr_edac_a10_probe(struct platform_device *pdev)
static const struct of_device_id altr_edac_a10_of_match[] = {
{ .compatible = "altr,socfpga-a10-ecc-manager" },
+ { .compatible = "altr,socfpga-s10-ecc-manager" },
{},
};
MODULE_DEVICE_TABLE(of, altr_edac_a10_of_match);
@@ -2235,171 +2166,6 @@ static struct platform_driver altr_edac_a10_driver = {
};
module_platform_driver(altr_edac_a10_driver);
-/************** Stratix 10 EDAC Device Controller Functions> ************/
-
-#define to_s10edac(p, m) container_of(p, struct altr_stratix10_edac, m)
-
-/*
- * The double bit error is handled through SError which is fatal. This is
- * called as a panic notifier to printout ECC error info as part of the panic.
- */
-static int s10_edac_dberr_handler(struct notifier_block *this,
- unsigned long event, void *ptr)
-{
- struct altr_stratix10_edac *edac = to_s10edac(this, panic_notifier);
- int err_addr, dberror;
-
- s10_protected_reg_read(edac, S10_SYSMGR_ECC_INTSTAT_DERR_OFST,
- &dberror);
- /* Remember the UE Errors for a reboot */
- s10_protected_reg_write(edac, S10_SYSMGR_UE_VAL_OFST, dberror);
- if (dberror & S10_DDR0_IRQ_MASK) {
- s10_protected_reg_read(edac, S10_DERRADDR_OFST, &err_addr);
- /* Remember the UE Error address */
- s10_protected_reg_write(edac, S10_SYSMGR_UE_ADDR_OFST,
- err_addr);
- edac_printk(KERN_ERR, EDAC_MC,
- "EDAC: [Uncorrectable errors @ 0x%08X]\n\n",
- err_addr);
- }
-
- return NOTIFY_DONE;
-}
-
-static void altr_edac_s10_irq_handler(struct irq_desc *desc)
-{
- struct altr_stratix10_edac *edac = irq_desc_get_handler_data(desc);
- struct irq_chip *chip = irq_desc_get_chip(desc);
- int irq = irq_desc_get_irq(desc);
- int bit, sm_offset, irq_status;
-
- sm_offset = S10_SYSMGR_ECC_INTSTAT_SERR_OFST;
-
- chained_irq_enter(chip, desc);
-
- s10_protected_reg_read(NULL, sm_offset, &irq_status);
-
- for_each_set_bit(bit, (unsigned long *)&irq_status, 32) {
- irq = irq_linear_revmap(edac->domain, bit);
- if (irq)
- generic_handle_irq(irq);
- }
-
- chained_irq_exit(chip, desc);
-}
-
-static void s10_eccmgr_irq_mask(struct irq_data *d)
-{
- struct altr_stratix10_edac *edac = irq_data_get_irq_chip_data(d);
-
- s10_protected_reg_write(edac, S10_SYSMGR_ECC_INTMASK_SET_OFST,
- BIT(d->hwirq));
-}
-
-static void s10_eccmgr_irq_unmask(struct irq_data *d)
-{
- struct altr_stratix10_edac *edac = irq_data_get_irq_chip_data(d);
-
- s10_protected_reg_write(edac, S10_SYSMGR_ECC_INTMASK_CLR_OFST,
- BIT(d->hwirq));
-}
-
-static int s10_eccmgr_irqdomain_map(struct irq_domain *d, unsigned int irq,
- irq_hw_number_t hwirq)
-{
- struct altr_stratix10_edac *edac = d->host_data;
-
- irq_set_chip_and_handler(irq, &edac->irq_chip, handle_simple_irq);
- irq_set_chip_data(irq, edac);
- irq_set_noprobe(irq);
-
- return 0;
-}
-
-static const struct irq_domain_ops s10_eccmgr_ic_ops = {
- .map = s10_eccmgr_irqdomain_map,
- .xlate = irq_domain_xlate_twocell,
-};
-
-static int altr_edac_s10_probe(struct platform_device *pdev)
-{
- struct altr_stratix10_edac *edac;
- struct device_node *child;
- int dberror, err_addr;
-
- edac = devm_kzalloc(&pdev->dev, sizeof(*edac), GFP_KERNEL);
- if (!edac)
- return -ENOMEM;
-
- edac->dev = &pdev->dev;
- platform_set_drvdata(pdev, edac);
- INIT_LIST_HEAD(&edac->s10_ecc_devices);
-
- edac->irq_chip.name = pdev->dev.of_node->name;
- edac->irq_chip.irq_mask = s10_eccmgr_irq_mask;
- edac->irq_chip.irq_unmask = s10_eccmgr_irq_unmask;
- edac->domain = irq_domain_add_linear(pdev->dev.of_node, 64,
- &s10_eccmgr_ic_ops, edac);
- if (!edac->domain) {
- dev_err(&pdev->dev, "Error adding IRQ domain\n");
- return -ENOMEM;
- }
-
- edac->sb_irq = platform_get_irq(pdev, 0);
- if (edac->sb_irq < 0) {
- dev_err(&pdev->dev, "No SBERR IRQ resource\n");
- return edac->sb_irq;
- }
-
- irq_set_chained_handler_and_data(edac->sb_irq,
- altr_edac_s10_irq_handler,
- edac);
-
- edac->panic_notifier.notifier_call = s10_edac_dberr_handler;
- atomic_notifier_chain_register(&panic_notifier_list,
- &edac->panic_notifier);
-
- /* Printout a message if uncorrectable error previously. */
- s10_protected_reg_read(edac, S10_SYSMGR_UE_VAL_OFST, &dberror);
- if (dberror) {
- s10_protected_reg_read(edac, S10_SYSMGR_UE_ADDR_OFST,
- &err_addr);
- edac_printk(KERN_ERR, EDAC_DEVICE,
- "Previous Boot UE detected[0x%X] @ 0x%X\n",
- dberror, err_addr);
- /* Reset the sticky registers */
- s10_protected_reg_write(edac, S10_SYSMGR_UE_VAL_OFST, 0);
- s10_protected_reg_write(edac, S10_SYSMGR_UE_ADDR_OFST, 0);
- }
-
- for_each_child_of_node(pdev->dev.of_node, child) {
- if (!of_device_is_available(child))
- continue;
-
- if (of_device_is_compatible(child, "altr,sdram-edac-s10"))
- of_platform_populate(pdev->dev.of_node,
- altr_sdram_ctrl_of_match,
- NULL, &pdev->dev);
- }
-
- return 0;
-}
-
-static const struct of_device_id altr_edac_s10_of_match[] = {
- { .compatible = "altr,socfpga-s10-ecc-manager" },
- {},
-};
-MODULE_DEVICE_TABLE(of, altr_edac_s10_of_match);
-
-static struct platform_driver altr_edac_s10_driver = {
- .probe = altr_edac_s10_probe,
- .driver = {
- .name = "socfpga_s10_ecc_manager",
- .of_match_table = altr_edac_s10_of_match,
- },
-};
-module_platform_driver(altr_edac_s10_driver);
-
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Thor Thayer");
MODULE_DESCRIPTION("EDAC Driver for Altera Memories");
diff --git a/drivers/edac/altera_edac.h b/drivers/edac/altera_edac.h
index 81f0554e09de..4213cb0bb2a7 100644
--- a/drivers/edac/altera_edac.h
+++ b/drivers/edac/altera_edac.h
@@ -156,34 +156,6 @@
#define A10_INTMASK_CLR_OFST 0x10
#define A10_DDR0_IRQ_MASK BIT(17)
-/************* Stratix10 Defines **************/
-
-/* SDRAM Controller EccCtrl Register */
-#define S10_ECCCTRL1_OFST 0xF8011100
-
-/* SDRAM Controller DRAM IRQ Register */
-#define S10_ERRINTEN_OFST 0xF8011110
-
-/* SDRAM Interrupt Mode Register */
-#define S10_INTMODE_OFST 0xF801111C
-
-/* SDRAM Controller Error Status Register */
-#define S10_INTSTAT_OFST 0xF8011120
-
-/* SDRAM Controller ECC Error Address Register */
-#define S10_DERRADDR_OFST 0xF801112C
-#define S10_SERRADDR_OFST 0xF8011130
-
-/* SDRAM Controller ECC Diagnostic Register */
-#define S10_DIAGINTTEST_OFST 0xF8011124
-
-/* SDRAM Single Bit Error Count Compare Set Register */
-#define S10_SERRCNTREG_OFST 0xF801113C
-
-/* Sticky registers for Uncorrected Errors */
-#define S10_SYSMGR_UE_VAL_OFST 0xFFD12220
-#define S10_SYSMGR_UE_ADDR_OFST 0xFFD12224
-
struct altr_sdram_prv_data {
int ecc_ctrl_offset;
int ecc_ctl_en_mask;
@@ -319,15 +291,40 @@ struct altr_sdram_mc_data {
/************* Stratix10 Defines **************/
/* Stratix10 ECC Manager Defines */
-#define S10_SYSMGR_ECC_INTMASK_VAL_OFST 0xFFD12090
-#define S10_SYSMGR_ECC_INTMASK_SET_OFST 0xFFD12094
-#define S10_SYSMGR_ECC_INTMASK_CLR_OFST 0xFFD12098
+#define S10_SYSMGR_ECC_INTMASK_CLR_OFST 0x98
+#define S10_SYSMGR_ECC_INTSTAT_DERR_OFST 0xA0
-#define S10_SYSMGR_ECC_INTSTAT_SERR_OFST 0xFFD1209C
-#define S10_SYSMGR_ECC_INTSTAT_DERR_OFST 0xFFD120A0
+/* Sticky registers for Uncorrected Errors */
+#define S10_SYSMGR_UE_VAL_OFST 0x120
+#define S10_SYSMGR_UE_ADDR_OFST 0x124
#define S10_DDR0_IRQ_MASK BIT(16)
+/* Define ECC Block Offsets for peripherals */
+#define ECC_BLK_ADDRESS_OFST 0x40
+#define ECC_BLK_RDATA0_OFST 0x44
+#define ECC_BLK_RDATA1_OFST 0x48
+#define ECC_BLK_RDATA2_OFST 0x4C
+#define ECC_BLK_RDATA3_OFST 0x50
+#define ECC_BLK_WDATA0_OFST 0x54
+#define ECC_BLK_WDATA1_OFST 0x58
+#define ECC_BLK_WDATA2_OFST 0x5C
+#define ECC_BLK_WDATA3_OFST 0x60
+#define ECC_BLK_RECC0_OFST 0x64
+#define ECC_BLK_RECC1_OFST 0x68
+#define ECC_BLK_WECC0_OFST 0x6C
+#define ECC_BLK_WECC1_OFST 0x70
+#define ECC_BLK_DBYTECTRL_OFST 0x74
+#define ECC_BLK_ACCCTRL_OFST 0x78
+#define ECC_BLK_STARTACC_OFST 0x7C
+
+#define ECC_XACT_KICK 0x10000
+#define ECC_WORD_WRITE 0xF
+#define ECC_WRITE_DOVR 0x101
+#define ECC_WRITE_EDOVR 0x103
+#define ECC_READ_EOVR 0x2
+#define ECC_READ_EDOVR 0x3
+
struct altr_edac_device_dev;
struct edac_device_prv_data {
@@ -370,6 +367,7 @@ struct altr_arria10_edac {
struct irq_domain *domain;
struct irq_chip irq_chip;
struct list_head a10_ecc_devices;
+ struct notifier_block panic_notifier;
};
/*
@@ -437,13 +435,4 @@ struct altr_arria10_edac {
#define INTEL_SIP_SMC_REG_WRITE \
INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_REG_WRITE)
-struct altr_stratix10_edac {
- struct device *dev;
- int sb_irq;
- struct irq_domain *domain;
- struct irq_chip irq_chip;
- struct list_head s10_ecc_devices;
- struct notifier_block panic_notifier;
-};
-
#endif /* #ifndef _ALTERA_EDAC_H */
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index 18aeabb1d5ee..6ea98575a402 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -211,7 +211,7 @@ static int __set_scrub_rate(struct amd64_pvt *pvt, u32 new_bw, u32 min_rate)
scrubval = scrubrates[i].scrubval;
- if (pvt->fam == 0x17) {
+ if (pvt->fam == 0x17 || pvt->fam == 0x18) {
__f17h_set_scrubval(pvt, scrubval);
} else if (pvt->fam == 0x15 && pvt->model == 0x60) {
f15h_select_dct(pvt, 0);
@@ -264,6 +264,7 @@ static int get_scrub_rate(struct mem_ctl_info *mci)
break;
case 0x17:
+ case 0x18:
amd64_read_pci_cfg(pvt->F6, F17H_SCR_BASE_ADDR, &scrubval);
if (scrubval & BIT(0)) {
amd64_read_pci_cfg(pvt->F6, F17H_SCR_LIMIT_ADDR, &scrubval);
@@ -1044,6 +1045,7 @@ static void determine_memory_type(struct amd64_pvt *pvt)
goto ddr3;
case 0x17:
+ case 0x18:
if ((pvt->umc[0].dimm_cfg | pvt->umc[1].dimm_cfg) & BIT(5))
pvt->dram_type = MEM_LRDDR4;
else if ((pvt->umc[0].dimm_cfg | pvt->umc[1].dimm_cfg) & BIT(4))
@@ -2200,6 +2202,15 @@ static struct amd64_family_type family_types[] = {
.dbam_to_cs = f17_base_addr_to_cs_size,
}
},
+ [F17_M10H_CPUS] = {
+ .ctl_name = "F17h_M10h",
+ .f0_id = PCI_DEVICE_ID_AMD_17H_M10H_DF_F0,
+ .f6_id = PCI_DEVICE_ID_AMD_17H_M10H_DF_F6,
+ .ops = {
+ .early_channel_count = f17_early_channel_count,
+ .dbam_to_cs = f17_base_addr_to_cs_size,
+ }
+ },
};
/*
@@ -3188,8 +3199,18 @@ static struct amd64_family_type *per_family_init(struct amd64_pvt *pvt)
break;
case 0x17:
+ if (pvt->model >= 0x10 && pvt->model <= 0x2f) {
+ fam_type = &family_types[F17_M10H_CPUS];
+ pvt->ops = &family_types[F17_M10H_CPUS].ops;
+ break;
+ }
+ /* fall through */
+ case 0x18:
fam_type = &family_types[F17_CPUS];
pvt->ops = &family_types[F17_CPUS].ops;
+
+ if (pvt->fam == 0x18)
+ family_types[F17_CPUS].ctl_name = "F18h";
break;
default:
@@ -3428,6 +3449,7 @@ static const struct x86_cpu_id amd64_cpuids[] = {
{ X86_VENDOR_AMD, 0x15, X86_MODEL_ANY, X86_FEATURE_ANY, 0 },
{ X86_VENDOR_AMD, 0x16, X86_MODEL_ANY, X86_FEATURE_ANY, 0 },
{ X86_VENDOR_AMD, 0x17, X86_MODEL_ANY, X86_FEATURE_ANY, 0 },
+ { X86_VENDOR_HYGON, 0x18, X86_MODEL_ANY, X86_FEATURE_ANY, 0 },
{ }
};
MODULE_DEVICE_TABLE(x86cpu, amd64_cpuids);
diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h
index 1d4b74e9a037..4242f8e39c18 100644
--- a/drivers/edac/amd64_edac.h
+++ b/drivers/edac/amd64_edac.h
@@ -115,6 +115,8 @@
#define PCI_DEVICE_ID_AMD_16H_M30H_NB_F2 0x1582
#define PCI_DEVICE_ID_AMD_17H_DF_F0 0x1460
#define PCI_DEVICE_ID_AMD_17H_DF_F6 0x1466
+#define PCI_DEVICE_ID_AMD_17H_M10H_DF_F0 0x15e8
+#define PCI_DEVICE_ID_AMD_17H_M10H_DF_F6 0x15ee
/*
* Function 1 - Address Map
@@ -281,6 +283,7 @@ enum amd_families {
F16_CPUS,
F16_M30H_CPUS,
F17_CPUS,
+ F17_M10H_CPUS,
NUM_FAMILIES,
};
diff --git a/drivers/edac/cpc925_edac.c b/drivers/edac/cpc925_edac.c
index 2c98e020df05..3c0881ac9880 100644
--- a/drivers/edac/cpc925_edac.c
+++ b/drivers/edac/cpc925_edac.c
@@ -593,8 +593,7 @@ static void cpc925_mc_check(struct mem_ctl_info *mci)
/******************** CPU err device********************************/
static u32 cpc925_cpu_mask_disabled(void)
{
- struct device_node *cpus;
- struct device_node *cpunode = NULL;
+ struct device_node *cpunode;
static u32 mask = 0;
/* use cached value if available */
@@ -603,20 +602,8 @@ static u32 cpc925_cpu_mask_disabled(void)
mask = APIMASK_ADI0 | APIMASK_ADI1;
- cpus = of_find_node_by_path("/cpus");
- if (cpus == NULL) {
- cpc925_printk(KERN_DEBUG, "No /cpus node !\n");
- return 0;
- }
-
- while ((cpunode = of_get_next_child(cpus, cpunode)) != NULL) {
+ for_each_of_cpu_node(cpunode) {
const u32 *reg = of_get_property(cpunode, "reg", NULL);
-
- if (strcmp(cpunode->type, "cpu")) {
- cpc925_printk(KERN_ERR, "Not a cpu node in /cpus: %s\n", cpunode->name);
- continue;
- }
-
if (reg == NULL || *reg > 2) {
cpc925_printk(KERN_ERR, "Bad reg value at %pOF\n", cpunode);
continue;
@@ -633,9 +620,6 @@ static u32 cpc925_cpu_mask_disabled(void)
"Assuming PI id is equal to CPU MPIC id!\n");
}
- of_node_put(cpunode);
- of_node_put(cpus);
-
return mask;
}
diff --git a/drivers/edac/ghes_edac.c b/drivers/edac/ghes_edac.c
index 473aeec4b1da..49396bf6ad88 100644
--- a/drivers/edac/ghes_edac.c
+++ b/drivers/edac/ghes_edac.c
@@ -81,6 +81,18 @@ static void ghes_edac_count_dimms(const struct dmi_header *dh, void *arg)
(*num_dimm)++;
}
+static int get_dimm_smbios_index(u16 handle)
+{
+ struct mem_ctl_info *mci = ghes_pvt->mci;
+ int i;
+
+ for (i = 0; i < mci->tot_dimms; i++) {
+ if (mci->dimms[i]->smbios_handle == handle)
+ return i;
+ }
+ return -1;
+}
+
static void ghes_edac_dmidecode(const struct dmi_header *dh, void *arg)
{
struct ghes_edac_dimm_fill *dimm_fill = arg;
@@ -177,6 +189,8 @@ static void ghes_edac_dmidecode(const struct dmi_header *dh, void *arg)
entry->total_width, entry->data_width);
}
+ dimm->smbios_handle = entry->handle;
+
dimm_fill->count++;
}
}
@@ -327,12 +341,21 @@ void ghes_edac_report_mem_error(int sev, struct cper_sec_mem_err *mem_err)
p += sprintf(p, "bit_pos:%d ", mem_err->bit_pos);
if (mem_err->validation_bits & CPER_MEM_VALID_MODULE_HANDLE) {
const char *bank = NULL, *device = NULL;
+ int index = -1;
+
dmi_memdev_name(mem_err->mem_dev_handle, &bank, &device);
if (bank != NULL && device != NULL)
p += sprintf(p, "DIMM location:%s %s ", bank, device);
else
p += sprintf(p, "DIMM DMI handle: 0x%.4x ",
mem_err->mem_dev_handle);
+
+ index = get_dimm_smbios_index(mem_err->mem_dev_handle);
+ if (index >= 0) {
+ e->top_layer = index;
+ e->enable_per_layer_report = true;
+ }
+
}
if (p > e->location)
*(p - 1) = '\0';
diff --git a/drivers/edac/i3200_edac.c b/drivers/edac/i3200_edac.c
index d92d56cee101..299b441647cd 100644
--- a/drivers/edac/i3200_edac.c
+++ b/drivers/edac/i3200_edac.c
@@ -399,7 +399,7 @@ static int i3200_probe1(struct pci_dev *pdev, int dev_idx)
if (nr_pages == 0)
continue;
- edac_dbg(0, "csrow %d, channel %d%s, size = %ld Mb\n", i, j,
+ edac_dbg(0, "csrow %d, channel %d%s, size = %ld MiB\n", i, j,
stacked ? " (stacked)" : "", PAGES_TO_MiB(nr_pages));
dimm->nr_pages = nr_pages;
diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c
index 8e120bf60624..9ef448fef12f 100644
--- a/drivers/edac/i7core_edac.c
+++ b/drivers/edac/i7core_edac.c
@@ -597,7 +597,7 @@ static int get_dimm_config(struct mem_ctl_info *mci)
/* DDR3 has 8 I/O banks */
size = (rows * cols * banks * ranks) >> (20 - 3);
- edac_dbg(0, "\tdimm %d %d Mb offset: %x, bank: %d, rank: %d, row: %#x, col: %#x\n",
+ edac_dbg(0, "\tdimm %d %d MiB offset: %x, bank: %d, rank: %d, row: %#x, col: %#x\n",
j, size,
RANKOFFSET(dimm_dod[j]),
banks, ranks, rows, cols);
@@ -1711,6 +1711,7 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci,
u32 errnum = find_first_bit(&error, 32);
if (uncorrected_error) {
+ core_err_cnt = 1;
if (ripv)
tp_event = HW_EVENT_ERR_FATAL;
else
@@ -1815,14 +1816,12 @@ static int i7core_mce_check_error(struct notifier_block *nb, unsigned long val,
struct mce *mce = (struct mce *)data;
struct i7core_dev *i7_dev;
struct mem_ctl_info *mci;
- struct i7core_pvt *pvt;
i7_dev = get_i7core_dev(mce->socketid);
if (!i7_dev)
return NOTIFY_DONE;
mci = i7_dev->mci;
- pvt = mci->pvt_info;
/*
* Just let mcelog handle it if the error is
diff --git a/drivers/edac/mce_amd.c b/drivers/edac/mce_amd.c
index 2ab4d61ee47e..c605089d899f 100644
--- a/drivers/edac/mce_amd.c
+++ b/drivers/edac/mce_amd.c
@@ -1059,7 +1059,8 @@ static int __init mce_amd_init(void)
{
struct cpuinfo_x86 *c = &boot_cpu_data;
- if (c->x86_vendor != X86_VENDOR_AMD)
+ if (c->x86_vendor != X86_VENDOR_AMD &&
+ c->x86_vendor != X86_VENDOR_HYGON)
return -ENODEV;
fam_ops = kzalloc(sizeof(struct amd_decoder_ops), GFP_KERNEL);
@@ -1113,6 +1114,7 @@ static int __init mce_amd_init(void)
break;
case 0x17:
+ case 0x18:
xec_mask = 0x3f;
if (!boot_cpu_has(X86_FEATURE_SMCA)) {
printk(KERN_WARNING "Decoding supported only on Scalable MCA processors.\n");
diff --git a/drivers/edac/pnd2_edac.c b/drivers/edac/pnd2_edac.c
index df28b65358d2..903a4f1fadcc 100644
--- a/drivers/edac/pnd2_edac.c
+++ b/drivers/edac/pnd2_edac.c
@@ -1541,7 +1541,7 @@ static struct dunit_ops dnv_ops = {
static const struct x86_cpu_id pnd2_cpuids[] = {
{ X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_GOLDMONT, 0, (kernel_ulong_t)&apl_ops },
- { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_DENVERTON, 0, (kernel_ulong_t)&dnv_ops },
+ { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_GOLDMONT_X, 0, (kernel_ulong_t)&dnv_ops },
{ }
};
MODULE_DEVICE_TABLE(x86cpu, pnd2_cpuids);
diff --git a/drivers/edac/qcom_edac.c b/drivers/edac/qcom_edac.c
new file mode 100644
index 000000000000..82bd775124f2
--- /dev/null
+++ b/drivers/edac/qcom_edac.c
@@ -0,0 +1,414 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/edac.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/soc/qcom/llcc-qcom.h>
+
+#include "edac_mc.h"
+#include "edac_device.h"
+
+#define EDAC_LLCC "qcom_llcc"
+
+#define LLCC_ERP_PANIC_ON_UE 1
+
+#define TRP_SYN_REG_CNT 6
+#define DRP_SYN_REG_CNT 8
+
+#define LLCC_COMMON_STATUS0 0x0003000c
+#define LLCC_LB_CNT_MASK GENMASK(31, 28)
+#define LLCC_LB_CNT_SHIFT 28
+
+/* Single & double bit syndrome register offsets */
+#define TRP_ECC_SB_ERR_SYN0 0x0002304c
+#define TRP_ECC_DB_ERR_SYN0 0x00020370
+#define DRP_ECC_SB_ERR_SYN0 0x0004204c
+#define DRP_ECC_DB_ERR_SYN0 0x00042070
+
+/* Error register offsets */
+#define TRP_ECC_ERROR_STATUS1 0x00020348
+#define TRP_ECC_ERROR_STATUS0 0x00020344
+#define DRP_ECC_ERROR_STATUS1 0x00042048
+#define DRP_ECC_ERROR_STATUS0 0x00042044
+
+/* TRP, DRP interrupt register offsets */
+#define DRP_INTERRUPT_STATUS 0x00041000
+#define TRP_INTERRUPT_0_STATUS 0x00020480
+#define DRP_INTERRUPT_CLEAR 0x00041008
+#define DRP_ECC_ERROR_CNTR_CLEAR 0x00040004
+#define TRP_INTERRUPT_0_CLEAR 0x00020484
+#define TRP_ECC_ERROR_CNTR_CLEAR 0x00020440
+
+/* Mask and shift macros */
+#define ECC_DB_ERR_COUNT_MASK GENMASK(4, 0)
+#define ECC_DB_ERR_WAYS_MASK GENMASK(31, 16)
+#define ECC_DB_ERR_WAYS_SHIFT BIT(4)
+
+#define ECC_SB_ERR_COUNT_MASK GENMASK(23, 16)
+#define ECC_SB_ERR_COUNT_SHIFT BIT(4)
+#define ECC_SB_ERR_WAYS_MASK GENMASK(15, 0)
+
+#define SB_ECC_ERROR BIT(0)
+#define DB_ECC_ERROR BIT(1)
+
+#define DRP_TRP_INT_CLEAR GENMASK(1, 0)
+#define DRP_TRP_CNT_CLEAR GENMASK(1, 0)
+
+/* Config registers offsets*/
+#define DRP_ECC_ERROR_CFG 0x00040000
+
+/* Tag RAM, Data RAM interrupt register offsets */
+#define CMN_INTERRUPT_0_ENABLE 0x0003001c
+#define CMN_INTERRUPT_2_ENABLE 0x0003003c
+#define TRP_INTERRUPT_0_ENABLE 0x00020488
+#define DRP_INTERRUPT_ENABLE 0x0004100c
+
+#define SB_ERROR_THRESHOLD 0x1
+#define SB_ERROR_THRESHOLD_SHIFT 24
+#define SB_DB_TRP_INTERRUPT_ENABLE 0x3
+#define TRP0_INTERRUPT_ENABLE 0x1
+#define DRP0_INTERRUPT_ENABLE BIT(6)
+#define SB_DB_DRP_INTERRUPT_ENABLE 0x3
+
+enum {
+ LLCC_DRAM_CE = 0,
+ LLCC_DRAM_UE,
+ LLCC_TRAM_CE,
+ LLCC_TRAM_UE,
+};
+
+static const struct llcc_edac_reg_data edac_reg_data[] = {
+ [LLCC_DRAM_CE] = {
+ .name = "DRAM Single-bit",
+ .synd_reg = DRP_ECC_SB_ERR_SYN0,
+ .count_status_reg = DRP_ECC_ERROR_STATUS1,
+ .ways_status_reg = DRP_ECC_ERROR_STATUS0,
+ .reg_cnt = DRP_SYN_REG_CNT,
+ .count_mask = ECC_SB_ERR_COUNT_MASK,
+ .ways_mask = ECC_SB_ERR_WAYS_MASK,
+ .count_shift = ECC_SB_ERR_COUNT_SHIFT,
+ },
+ [LLCC_DRAM_UE] = {
+ .name = "DRAM Double-bit",
+ .synd_reg = DRP_ECC_DB_ERR_SYN0,
+ .count_status_reg = DRP_ECC_ERROR_STATUS1,
+ .ways_status_reg = DRP_ECC_ERROR_STATUS0,
+ .reg_cnt = DRP_SYN_REG_CNT,
+ .count_mask = ECC_DB_ERR_COUNT_MASK,
+ .ways_mask = ECC_DB_ERR_WAYS_MASK,
+ .ways_shift = ECC_DB_ERR_WAYS_SHIFT,
+ },
+ [LLCC_TRAM_CE] = {
+ .name = "TRAM Single-bit",
+ .synd_reg = TRP_ECC_SB_ERR_SYN0,
+ .count_status_reg = TRP_ECC_ERROR_STATUS1,
+ .ways_status_reg = TRP_ECC_ERROR_STATUS0,
+ .reg_cnt = TRP_SYN_REG_CNT,
+ .count_mask = ECC_SB_ERR_COUNT_MASK,
+ .ways_mask = ECC_SB_ERR_WAYS_MASK,
+ .count_shift = ECC_SB_ERR_COUNT_SHIFT,
+ },
+ [LLCC_TRAM_UE] = {
+ .name = "TRAM Double-bit",
+ .synd_reg = TRP_ECC_DB_ERR_SYN0,
+ .count_status_reg = TRP_ECC_ERROR_STATUS1,
+ .ways_status_reg = TRP_ECC_ERROR_STATUS0,
+ .reg_cnt = TRP_SYN_REG_CNT,
+ .count_mask = ECC_DB_ERR_COUNT_MASK,
+ .ways_mask = ECC_DB_ERR_WAYS_MASK,
+ .ways_shift = ECC_DB_ERR_WAYS_SHIFT,
+ },
+};
+
+static int qcom_llcc_core_setup(struct regmap *llcc_bcast_regmap)
+{
+ u32 sb_err_threshold;
+ int ret;
+
+ /*
+ * Configure interrupt enable registers such that Tag, Data RAM related
+ * interrupts are propagated to interrupt controller for servicing
+ */
+ ret = regmap_update_bits(llcc_bcast_regmap, CMN_INTERRUPT_2_ENABLE,
+ TRP0_INTERRUPT_ENABLE,
+ TRP0_INTERRUPT_ENABLE);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(llcc_bcast_regmap, TRP_INTERRUPT_0_ENABLE,
+ SB_DB_TRP_INTERRUPT_ENABLE,
+ SB_DB_TRP_INTERRUPT_ENABLE);
+ if (ret)
+ return ret;
+
+ sb_err_threshold = (SB_ERROR_THRESHOLD << SB_ERROR_THRESHOLD_SHIFT);
+ ret = regmap_write(llcc_bcast_regmap, DRP_ECC_ERROR_CFG,
+ sb_err_threshold);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(llcc_bcast_regmap, CMN_INTERRUPT_2_ENABLE,
+ DRP0_INTERRUPT_ENABLE,
+ DRP0_INTERRUPT_ENABLE);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(llcc_bcast_regmap, DRP_INTERRUPT_ENABLE,
+ SB_DB_DRP_INTERRUPT_ENABLE);
+ return ret;
+}
+
+/* Clear the error interrupt and counter registers */
+static int
+qcom_llcc_clear_error_status(int err_type, struct llcc_drv_data *drv)
+{
+ int ret = 0;
+
+ switch (err_type) {
+ case LLCC_DRAM_CE:
+ case LLCC_DRAM_UE:
+ ret = regmap_write(drv->bcast_regmap, DRP_INTERRUPT_CLEAR,
+ DRP_TRP_INT_CLEAR);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(drv->bcast_regmap, DRP_ECC_ERROR_CNTR_CLEAR,
+ DRP_TRP_CNT_CLEAR);
+ if (ret)
+ return ret;
+ break;
+ case LLCC_TRAM_CE:
+ case LLCC_TRAM_UE:
+ ret = regmap_write(drv->bcast_regmap, TRP_INTERRUPT_0_CLEAR,
+ DRP_TRP_INT_CLEAR);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(drv->bcast_regmap, TRP_ECC_ERROR_CNTR_CLEAR,
+ DRP_TRP_CNT_CLEAR);
+ if (ret)
+ return ret;
+ break;
+ default:
+ ret = -EINVAL;
+ edac_printk(KERN_CRIT, EDAC_LLCC, "Unexpected error type: %d\n",
+ err_type);
+ }
+ return ret;
+}
+
+/* Dump Syndrome registers data for Tag RAM, Data RAM bit errors*/
+static int
+dump_syn_reg_values(struct llcc_drv_data *drv, u32 bank, int err_type)
+{
+ struct llcc_edac_reg_data reg_data = edac_reg_data[err_type];
+ int err_cnt, err_ways, ret, i;
+ u32 synd_reg, synd_val;
+
+ for (i = 0; i < reg_data.reg_cnt; i++) {
+ synd_reg = reg_data.synd_reg + (i * 4);
+ ret = regmap_read(drv->regmap, drv->offsets[bank] + synd_reg,
+ &synd_val);
+ if (ret)
+ goto clear;
+
+ edac_printk(KERN_CRIT, EDAC_LLCC, "%s: ECC_SYN%d: 0x%8x\n",
+ reg_data.name, i, synd_val);
+ }
+
+ ret = regmap_read(drv->regmap,
+ drv->offsets[bank] + reg_data.count_status_reg,
+ &err_cnt);
+ if (ret)
+ goto clear;
+
+ err_cnt &= reg_data.count_mask;
+ err_cnt >>= reg_data.count_shift;
+ edac_printk(KERN_CRIT, EDAC_LLCC, "%s: Error count: 0x%4x\n",
+ reg_data.name, err_cnt);
+
+ ret = regmap_read(drv->regmap,
+ drv->offsets[bank] + reg_data.ways_status_reg,
+ &err_ways);
+ if (ret)
+ goto clear;
+
+ err_ways &= reg_data.ways_mask;
+ err_ways >>= reg_data.ways_shift;
+
+ edac_printk(KERN_CRIT, EDAC_LLCC, "%s: Error ways: 0x%4x\n",
+ reg_data.name, err_ways);
+
+clear:
+ return qcom_llcc_clear_error_status(err_type, drv);
+}
+
+static int
+dump_syn_reg(struct edac_device_ctl_info *edev_ctl, int err_type, u32 bank)
+{
+ struct llcc_drv_data *drv = edev_ctl->pvt_info;
+ int ret;
+
+ ret = dump_syn_reg_values(drv, bank, err_type);
+ if (ret)
+ return ret;
+
+ switch (err_type) {
+ case LLCC_DRAM_CE:
+ edac_device_handle_ce(edev_ctl, 0, bank,
+ "LLCC Data RAM correctable Error");
+ break;
+ case LLCC_DRAM_UE:
+ edac_device_handle_ue(edev_ctl, 0, bank,
+ "LLCC Data RAM uncorrectable Error");
+ break;
+ case LLCC_TRAM_CE:
+ edac_device_handle_ce(edev_ctl, 0, bank,
+ "LLCC Tag RAM correctable Error");
+ break;
+ case LLCC_TRAM_UE:
+ edac_device_handle_ue(edev_ctl, 0, bank,
+ "LLCC Tag RAM uncorrectable Error");
+ break;
+ default:
+ ret = -EINVAL;
+ edac_printk(KERN_CRIT, EDAC_LLCC, "Unexpected error type: %d\n",
+ err_type);
+ }
+
+ return ret;
+}
+
+static irqreturn_t
+llcc_ecc_irq_handler(int irq, void *edev_ctl)
+{
+ struct edac_device_ctl_info *edac_dev_ctl = edev_ctl;
+ struct llcc_drv_data *drv = edac_dev_ctl->pvt_info;
+ irqreturn_t irq_rc = IRQ_NONE;
+ u32 drp_error, trp_error, i;
+ bool irq_handled;
+ int ret;
+
+ /* Iterate over the banks and look for Tag RAM or Data RAM errors */
+ for (i = 0; i < drv->num_banks; i++) {
+ ret = regmap_read(drv->regmap,
+ drv->offsets[i] + DRP_INTERRUPT_STATUS,
+ &drp_error);
+
+ if (!ret && (drp_error & SB_ECC_ERROR)) {
+ edac_printk(KERN_CRIT, EDAC_LLCC,
+ "Single Bit Error detected in Data RAM\n");
+ ret = dump_syn_reg(edev_ctl, LLCC_DRAM_CE, i);
+ } else if (!ret && (drp_error & DB_ECC_ERROR)) {
+ edac_printk(KERN_CRIT, EDAC_LLCC,
+ "Double Bit Error detected in Data RAM\n");
+ ret = dump_syn_reg(edev_ctl, LLCC_DRAM_UE, i);
+ }
+ if (!ret)
+ irq_handled = true;
+
+ ret = regmap_read(drv->regmap,
+ drv->offsets[i] + TRP_INTERRUPT_0_STATUS,
+ &trp_error);
+
+ if (!ret && (trp_error & SB_ECC_ERROR)) {
+ edac_printk(KERN_CRIT, EDAC_LLCC,
+ "Single Bit Error detected in Tag RAM\n");
+ ret = dump_syn_reg(edev_ctl, LLCC_TRAM_CE, i);
+ } else if (!ret && (trp_error & DB_ECC_ERROR)) {
+ edac_printk(KERN_CRIT, EDAC_LLCC,
+ "Double Bit Error detected in Tag RAM\n");
+ ret = dump_syn_reg(edev_ctl, LLCC_TRAM_UE, i);
+ }
+ if (!ret)
+ irq_handled = true;
+ }
+
+ if (irq_handled)
+ irq_rc = IRQ_HANDLED;
+
+ return irq_rc;
+}
+
+static int qcom_llcc_edac_probe(struct platform_device *pdev)
+{
+ struct llcc_drv_data *llcc_driv_data = pdev->dev.platform_data;
+ struct edac_device_ctl_info *edev_ctl;
+ struct device *dev = &pdev->dev;
+ int ecc_irq;
+ int rc;
+
+ rc = qcom_llcc_core_setup(llcc_driv_data->bcast_regmap);
+ if (rc)
+ return rc;
+
+ /* Allocate edac control info */
+ edev_ctl = edac_device_alloc_ctl_info(0, "qcom-llcc", 1, "bank",
+ llcc_driv_data->num_banks, 1,
+ NULL, 0,
+ edac_device_alloc_index());
+
+ if (!edev_ctl)
+ return -ENOMEM;
+
+ edev_ctl->dev = dev;
+ edev_ctl->mod_name = dev_name(dev);
+ edev_ctl->dev_name = dev_name(dev);
+ edev_ctl->ctl_name = "llcc";
+ edev_ctl->panic_on_ue = LLCC_ERP_PANIC_ON_UE;
+ edev_ctl->pvt_info = llcc_driv_data;
+
+ rc = edac_device_add_device(edev_ctl);
+ if (rc)
+ goto out_mem;
+
+ platform_set_drvdata(pdev, edev_ctl);
+
+ /* Request for ecc irq */
+ ecc_irq = llcc_driv_data->ecc_irq;
+ if (ecc_irq < 0) {
+ rc = -ENODEV;
+ goto out_dev;
+ }
+ rc = devm_request_irq(dev, ecc_irq, llcc_ecc_irq_handler,
+ IRQF_TRIGGER_HIGH, "llcc_ecc", edev_ctl);
+ if (rc)
+ goto out_dev;
+
+ return rc;
+
+out_dev:
+ edac_device_del_device(edev_ctl->dev);
+out_mem:
+ edac_device_free_ctl_info(edev_ctl);
+
+ return rc;
+}
+
+static int qcom_llcc_edac_remove(struct platform_device *pdev)
+{
+ struct edac_device_ctl_info *edev_ctl = dev_get_drvdata(&pdev->dev);
+
+ edac_device_del_device(edev_ctl->dev);
+ edac_device_free_ctl_info(edev_ctl);
+
+ return 0;
+}
+
+static struct platform_driver qcom_llcc_edac_driver = {
+ .probe = qcom_llcc_edac_probe,
+ .remove = qcom_llcc_edac_remove,
+ .driver = {
+ .name = "qcom_llcc_edac",
+ },
+};
+module_platform_driver(qcom_llcc_edac_driver);
+
+MODULE_DESCRIPTION("QCOM EDAC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index 07726fb00321..9353c3fc7c05 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
@@ -326,6 +326,7 @@ struct sbridge_info {
const struct interleave_pkg *interleave_pkg;
u8 max_sad;
u8 (*get_node_id)(struct sbridge_pvt *pvt);
+ u8 (*get_ha)(u8 bank);
enum mem_type (*get_memory_type)(struct sbridge_pvt *pvt);
enum dev_type (*get_width)(struct sbridge_pvt *pvt, u32 mtr);
struct pci_dev *pci_vtd;
@@ -1002,6 +1003,39 @@ static u8 knl_get_node_id(struct sbridge_pvt *pvt)
return GET_BITFIELD(reg, 0, 2);
}
+/*
+ * Use the reporting bank number to determine which memory
+ * controller (also known as "ha" for "home agent"). Sandy
+ * Bridge only has one memory controller per socket, so the
+ * answer is always zero.
+ */
+static u8 sbridge_get_ha(u8 bank)
+{
+ return 0;
+}
+
+/*
+ * On Ivy Bridge, Haswell and Broadwell the error may be in a
+ * home agent bank (7, 8), or one of the per-channel memory
+ * controller banks (9 .. 16).
+ */
+static u8 ibridge_get_ha(u8 bank)
+{
+ switch (bank) {
+ case 7 ... 8:
+ return bank - 7;
+ case 9 ... 16:
+ return (bank - 9) / 4;
+ default:
+ return 0xff;
+ }
+}
+
+/* Not used, but included for safety/symmetry */
+static u8 knl_get_ha(u8 bank)
+{
+ return 0xff;
+}
static u64 haswell_get_tolm(struct sbridge_pvt *pvt)
{
@@ -1622,7 +1656,7 @@ static int __populate_dimms(struct mem_ctl_info *mci,
size = ((u64)rows * cols * banks * ranks) >> (20 - 3);
npages = MiB_TO_PAGES(size);
- edac_dbg(0, "mc#%d: ha %d channel %d, dimm %d, %lld Mb (%d pages) bank: %d, rank: %d, row: %#x, col: %#x\n",
+ edac_dbg(0, "mc#%d: ha %d channel %d, dimm %d, %lld MiB (%d pages) bank: %d, rank: %d, row: %#x, col: %#x\n",
pvt->sbridge_dev->mc, pvt->sbridge_dev->dom, i, j,
size, npages,
banks, ranks, rows, cols);
@@ -2207,6 +2241,60 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
return 0;
}
+static int get_memory_error_data_from_mce(struct mem_ctl_info *mci,
+ const struct mce *m, u8 *socket,
+ u8 *ha, long *channel_mask,
+ char *msg)
+{
+ u32 reg, channel = GET_BITFIELD(m->status, 0, 3);
+ struct mem_ctl_info *new_mci;
+ struct sbridge_pvt *pvt;
+ struct pci_dev *pci_ha;
+ bool tad0;
+
+ if (channel >= NUM_CHANNELS) {
+ sprintf(msg, "Invalid channel 0x%x", channel);
+ return -EINVAL;
+ }
+
+ pvt = mci->pvt_info;
+ if (!pvt->info.get_ha) {
+ sprintf(msg, "No get_ha()");
+ return -EINVAL;
+ }
+ *ha = pvt->info.get_ha(m->bank);
+ if (*ha != 0 && *ha != 1) {
+ sprintf(msg, "Impossible bank %d", m->bank);
+ return -EINVAL;
+ }
+
+ *socket = m->socketid;
+ new_mci = get_mci_for_node_id(*socket, *ha);
+ if (!new_mci) {
+ strcpy(msg, "mci socket got corrupted!");
+ return -EINVAL;
+ }
+
+ pvt = new_mci->pvt_info;
+ pci_ha = pvt->pci_ha;
+ pci_read_config_dword(pci_ha, tad_dram_rule[0], &reg);
+ tad0 = m->addr <= TAD_LIMIT(reg);
+
+ *channel_mask = 1 << channel;
+ if (pvt->mirror_mode == FULL_MIRRORING ||
+ (pvt->mirror_mode == ADDR_RANGE_MIRRORING && tad0)) {
+ *channel_mask |= 1 << ((channel + 2) % 4);
+ pvt->is_cur_addr_mirrored = true;
+ } else {
+ pvt->is_cur_addr_mirrored = false;
+ }
+
+ if (pvt->is_lockstep)
+ *channel_mask |= 1 << ((channel + 1) % 4);
+
+ return 0;
+}
+
/****************************************************************************
Device initialization routines: put/get, init/exit
****************************************************************************/
@@ -2877,10 +2965,16 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
u32 errcode = GET_BITFIELD(m->status, 0, 15);
u32 channel = GET_BITFIELD(m->status, 0, 3);
u32 optypenum = GET_BITFIELD(m->status, 4, 6);
+ /*
+ * Bits 5-0 of MCi_MISC give the least significant bit that is valid.
+ * A value 6 is for cache line aligned address, a value 12 is for page
+ * aligned address reported by patrol scrubber.
+ */
+ u32 lsb = GET_BITFIELD(m->misc, 0, 5);
long channel_mask, first_channel;
- u8 rank, socket, ha;
+ u8 rank = 0xff, socket, ha;
int rc, dimm;
- char *area_type = NULL;
+ char *area_type = "DRAM";
if (pvt->info.type != SANDY_BRIDGE)
recoverable = true;
@@ -2888,6 +2982,7 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
recoverable = GET_BITFIELD(m->status, 56, 56);
if (uncorrected_error) {
+ core_err_cnt = 1;
if (ripv) {
type = "FATAL";
tp_event = HW_EVENT_ERR_FATAL;
@@ -2911,35 +3006,27 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
* cccc = channel
* If the mask doesn't match, report an error to the parsing logic
*/
- if (! ((errcode & 0xef80) == 0x80)) {
- optype = "Can't parse: it is not a mem";
- } else {
- switch (optypenum) {
- case 0:
- optype = "generic undef request error";
- break;
- case 1:
- optype = "memory read error";
- break;
- case 2:
- optype = "memory write error";
- break;
- case 3:
- optype = "addr/cmd error";
- break;
- case 4:
- optype = "memory scrubbing error";
- break;
- default:
- optype = "reserved";
- break;
- }
+ switch (optypenum) {
+ case 0:
+ optype = "generic undef request error";
+ break;
+ case 1:
+ optype = "memory read error";
+ break;
+ case 2:
+ optype = "memory write error";
+ break;
+ case 3:
+ optype = "addr/cmd error";
+ break;
+ case 4:
+ optype = "memory scrubbing error";
+ break;
+ default:
+ optype = "reserved";
+ break;
}
- /* Only decode errors with an valid address (ADDRV) */
- if (!GET_BITFIELD(m->status, 58, 58))
- return;
-
if (pvt->info.type == KNIGHTS_LANDING) {
if (channel == 14) {
edac_dbg(0, "%s%s err_code:%04x:%04x EDRAM bank %d\n",
@@ -2972,9 +3059,13 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
optype, msg);
}
return;
- } else {
+ } else if (lsb < 12) {
rc = get_memory_error_data(mci, m->addr, &socket, &ha,
- &channel_mask, &rank, &area_type, msg);
+ &channel_mask, &rank,
+ &area_type, msg);
+ } else {
+ rc = get_memory_error_data_from_mce(mci, m, &socket, &ha,
+ &channel_mask, msg);
}
if (rc < 0)
@@ -2989,14 +3080,15 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
first_channel = find_first_bit(&channel_mask, NUM_CHANNELS);
- if (rank < 4)
+ if (rank == 0xff)
+ dimm = -1;
+ else if (rank < 4)
dimm = 0;
else if (rank < 8)
dimm = 1;
else
dimm = 2;
-
/*
* FIXME: On some memory configurations (mirror, lockstep), the
* Memory Controller can't point the error to a single DIMM. The
@@ -3045,17 +3137,11 @@ static int sbridge_mce_check_error(struct notifier_block *nb, unsigned long val,
{
struct mce *mce = (struct mce *)data;
struct mem_ctl_info *mci;
- struct sbridge_pvt *pvt;
char *type;
if (edac_get_report_status() == EDAC_REPORTING_DISABLED)
return NOTIFY_DONE;
- mci = get_mci_for_node_id(mce->socketid, IMC0);
- if (!mci)
- return NOTIFY_DONE;
- pvt = mci->pvt_info;
-
/*
* Just let mcelog handle it if the error is
* outside the memory controller. A memory error
@@ -3065,6 +3151,22 @@ static int sbridge_mce_check_error(struct notifier_block *nb, unsigned long val,
if ((mce->status & 0xefff) >> 7 != 1)
return NOTIFY_DONE;
+ /* Check ADDRV bit in STATUS */
+ if (!GET_BITFIELD(mce->status, 58, 58))
+ return NOTIFY_DONE;
+
+ /* Check MISCV bit in STATUS */
+ if (!GET_BITFIELD(mce->status, 59, 59))
+ return NOTIFY_DONE;
+
+ /* Check address type in MISC (physical address only) */
+ if (GET_BITFIELD(mce->misc, 6, 8) != 2)
+ return NOTIFY_DONE;
+
+ mci = get_mci_for_node_id(mce->socketid, IMC0);
+ if (!mci)
+ return NOTIFY_DONE;
+
if (mce->mcgstatus & MCG_STATUS_MCIP)
type = "Exception";
else
@@ -3173,6 +3275,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
pvt->info.dram_rule = ibridge_dram_rule;
pvt->info.get_memory_type = get_memory_type;
pvt->info.get_node_id = get_node_id;
+ pvt->info.get_ha = ibridge_get_ha;
pvt->info.rir_limit = rir_limit;
pvt->info.sad_limit = sad_limit;
pvt->info.interleave_mode = interleave_mode;
@@ -3197,6 +3300,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
pvt->info.dram_rule = sbridge_dram_rule;
pvt->info.get_memory_type = get_memory_type;
pvt->info.get_node_id = get_node_id;
+ pvt->info.get_ha = sbridge_get_ha;
pvt->info.rir_limit = rir_limit;
pvt->info.sad_limit = sad_limit;
pvt->info.interleave_mode = interleave_mode;
@@ -3221,6 +3325,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
pvt->info.dram_rule = ibridge_dram_rule;
pvt->info.get_memory_type = haswell_get_memory_type;
pvt->info.get_node_id = haswell_get_node_id;
+ pvt->info.get_ha = ibridge_get_ha;
pvt->info.rir_limit = haswell_rir_limit;
pvt->info.sad_limit = sad_limit;
pvt->info.interleave_mode = interleave_mode;
@@ -3245,6 +3350,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
pvt->info.dram_rule = ibridge_dram_rule;
pvt->info.get_memory_type = haswell_get_memory_type;
pvt->info.get_node_id = haswell_get_node_id;
+ pvt->info.get_ha = ibridge_get_ha;
pvt->info.rir_limit = haswell_rir_limit;
pvt->info.sad_limit = sad_limit;
pvt->info.interleave_mode = interleave_mode;
@@ -3269,6 +3375,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
pvt->info.dram_rule = knl_dram_rule;
pvt->info.get_memory_type = knl_get_memory_type;
pvt->info.get_node_id = knl_get_node_id;
+ pvt->info.get_ha = knl_get_ha;
pvt->info.rir_limit = NULL;
pvt->info.sad_limit = knl_sad_limit;
pvt->info.interleave_mode = knl_interleave_mode;
@@ -3320,17 +3427,14 @@ fail0:
return rc;
}
-#define ICPU(model, table) \
- { X86_VENDOR_INTEL, 6, model, 0, (unsigned long)&table }
-
static const struct x86_cpu_id sbridge_cpuids[] = {
- ICPU(INTEL_FAM6_SANDYBRIDGE_X, pci_dev_descr_sbridge_table),
- ICPU(INTEL_FAM6_IVYBRIDGE_X, pci_dev_descr_ibridge_table),
- ICPU(INTEL_FAM6_HASWELL_X, pci_dev_descr_haswell_table),
- ICPU(INTEL_FAM6_BROADWELL_X, pci_dev_descr_broadwell_table),
- ICPU(INTEL_FAM6_BROADWELL_XEON_D, pci_dev_descr_broadwell_table),
- ICPU(INTEL_FAM6_XEON_PHI_KNL, pci_dev_descr_knl_table),
- ICPU(INTEL_FAM6_XEON_PHI_KNM, pci_dev_descr_knl_table),
+ INTEL_CPU_FAM6(SANDYBRIDGE_X, pci_dev_descr_sbridge_table),
+ INTEL_CPU_FAM6(IVYBRIDGE_X, pci_dev_descr_ibridge_table),
+ INTEL_CPU_FAM6(HASWELL_X, pci_dev_descr_haswell_table),
+ INTEL_CPU_FAM6(BROADWELL_X, pci_dev_descr_broadwell_table),
+ INTEL_CPU_FAM6(BROADWELL_XEON_D, pci_dev_descr_broadwell_table),
+ INTEL_CPU_FAM6(XEON_PHI_KNL, pci_dev_descr_knl_table),
+ INTEL_CPU_FAM6(XEON_PHI_KNM, pci_dev_descr_knl_table),
{ }
};
MODULE_DEVICE_TABLE(x86cpu, sbridge_cpuids);
diff --git a/drivers/edac/skx_edac.c b/drivers/edac/skx_edac.c
index fae095162c01..a99ea61dad32 100644
--- a/drivers/edac/skx_edac.c
+++ b/drivers/edac/skx_edac.c
@@ -26,6 +26,7 @@
#include <linux/bitmap.h>
#include <linux/math64.h>
#include <linux/mod_devicetable.h>
+#include <linux/adxl.h>
#include <acpi/nfit.h>
#include <asm/cpu_device_id.h>
#include <asm/intel-family.h>
@@ -35,6 +36,7 @@
#include "edac_module.h"
#define EDAC_MOD_STR "skx_edac"
+#define MSG_SIZE 1024
/*
* Debug macros
@@ -54,6 +56,29 @@
static LIST_HEAD(skx_edac_list);
static u64 skx_tolm, skx_tohm;
+static char *skx_msg;
+static unsigned int nvdimm_count;
+
+enum {
+ INDEX_SOCKET,
+ INDEX_MEMCTRL,
+ INDEX_CHANNEL,
+ INDEX_DIMM,
+ INDEX_MAX
+};
+
+static const char * const component_names[] = {
+ [INDEX_SOCKET] = "ProcessorSocketId",
+ [INDEX_MEMCTRL] = "MemoryControllerId",
+ [INDEX_CHANNEL] = "ChannelId",
+ [INDEX_DIMM] = "DimmSlotId",
+};
+
+static int component_indices[ARRAY_SIZE(component_names)];
+static int adxl_component_count;
+static const char * const *adxl_component_names;
+static u64 *adxl_values;
+static char *adxl_msg;
#define NUM_IMC 2 /* memory controllers per socket */
#define NUM_CHANNELS 3 /* channels per memory controller */
@@ -364,7 +389,7 @@ static int get_dimm_info(u32 mtr, u32 amap, struct dimm_info *dimm,
size = ((1ull << (rows + cols + ranks)) * banks) >> (20 - 3);
npages = MiB_TO_PAGES(size);
- edac_dbg(0, "mc#%d: channel %d, dimm %d, %lld Mb (%d pages) bank: %d, rank: %d, row: %#x, col: %#x\n",
+ edac_dbg(0, "mc#%d: channel %d, dimm %d, %lld MiB (%d pages) bank: %d, rank: %d, row: %#x, col: %#x\n",
imc->mc, chan, dimmno, size, npages,
banks, 1 << ranks, rows, cols);
@@ -393,6 +418,8 @@ static int get_nvdimm_info(struct dimm_info *dimm, struct skx_imc *imc,
u16 flags;
u64 size = 0;
+ nvdimm_count++;
+
dev_handle = ACPI_NFIT_BUILD_DEVICE_HANDLE(dimmno, chan, imc->lmc,
imc->src_id, 0);
@@ -424,7 +451,7 @@ unknown_size:
dimm->mtype = MEM_NVDIMM;
dimm->edac_mode = EDAC_SECDED; /* likely better than this */
- edac_dbg(0, "mc#%d: channel %d, dimm %d, %llu Mb (%u pages)\n",
+ edac_dbg(0, "mc#%d: channel %d, dimm %d, %llu MiB (%u pages)\n",
imc->mc, chan, dimmno, size >> 20, dimm->nr_pages);
snprintf(dimm->label, sizeof(dimm->label), "CPU_SrcID#%u_MC#%u_Chan#%u_DIMM#%u",
@@ -668,7 +695,7 @@ sad_found:
break;
case 2:
lchan = (addr >> shift) % 2;
- lchan = (lchan << 1) | ~lchan;
+ lchan = (lchan << 1) | !lchan;
break;
case 3:
lchan = ((addr >> shift) % 2) << 1;
@@ -941,12 +968,46 @@ static void teardown_skx_debug(void)
}
#endif /*CONFIG_EDAC_DEBUG*/
+static bool skx_adxl_decode(struct decoded_addr *res)
+
+{
+ int i, len = 0;
+
+ if (res->addr >= skx_tohm || (res->addr >= skx_tolm &&
+ res->addr < BIT_ULL(32))) {
+ edac_dbg(0, "Address 0x%llx out of range\n", res->addr);
+ return false;
+ }
+
+ if (adxl_decode(res->addr, adxl_values)) {
+ edac_dbg(0, "Failed to decode 0x%llx\n", res->addr);
+ return false;
+ }
+
+ 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]];
+
+ for (i = 0; i < adxl_component_count; i++) {
+ if (adxl_values[i] == ~0x0ull)
+ continue;
+
+ len += snprintf(adxl_msg + len, MSG_SIZE - len, " %s:0x%llx",
+ adxl_component_names[i], adxl_values[i]);
+ if (MSG_SIZE - len <= 0)
+ break;
+ }
+
+ return true;
+}
+
static void skx_mce_output_error(struct mem_ctl_info *mci,
const struct mce *m,
struct decoded_addr *res)
{
enum hw_event_mc_err_type tp_event;
- char *type, *optype, msg[256];
+ char *type, *optype;
bool ripv = GET_BITFIELD(m->mcgstatus, 0, 0);
bool overflow = GET_BITFIELD(m->status, 62, 62);
bool uncorrected_error = GET_BITFIELD(m->status, 61, 61);
@@ -959,6 +1020,7 @@ static void skx_mce_output_error(struct mem_ctl_info *mci,
recoverable = GET_BITFIELD(m->status, 56, 56);
if (uncorrected_error) {
+ core_err_cnt = 1;
if (ripv) {
type = "FATAL";
tp_event = HW_EVENT_ERR_FATAL;
@@ -1006,22 +1068,47 @@ static void skx_mce_output_error(struct mem_ctl_info *mci,
break;
}
}
+ if (adxl_component_count) {
+ snprintf(skx_msg, MSG_SIZE, "%s%s err_code:%04x:%04x %s",
+ overflow ? " OVERFLOW" : "",
+ (uncorrected_error && recoverable) ? " recoverable" : "",
+ mscod, errcode, adxl_msg);
+ } else {
+ snprintf(skx_msg, MSG_SIZE,
+ "%s%s err_code:%04x:%04x socket:%d imc:%d rank:%d bg:%d ba:%d row:%x col:%x",
+ overflow ? " OVERFLOW" : "",
+ (uncorrected_error && recoverable) ? " recoverable" : "",
+ mscod, errcode,
+ res->socket, res->imc, res->rank,
+ res->bank_group, res->bank_address, res->row, res->column);
+ }
- snprintf(msg, sizeof(msg),
- "%s%s err_code:%04x:%04x socket:%d imc:%d rank:%d bg:%d ba:%d row:%x col:%x",
- overflow ? " OVERFLOW" : "",
- (uncorrected_error && recoverable) ? " recoverable" : "",
- mscod, errcode,
- res->socket, res->imc, res->rank,
- res->bank_group, res->bank_address, res->row, res->column);
-
- edac_dbg(0, "%s\n", msg);
+ edac_dbg(0, "%s\n", skx_msg);
/* Call the helper to output message */
edac_mc_handle_error(tp_event, mci, core_err_cnt,
m->addr >> PAGE_SHIFT, m->addr & ~PAGE_MASK, 0,
res->channel, res->dimm, -1,
- optype, msg);
+ optype, skx_msg);
+}
+
+static struct mem_ctl_info *get_mci(int src_id, int lmc)
+{
+ struct skx_dev *d;
+
+ if (lmc > NUM_IMC - 1) {
+ skx_printk(KERN_ERR, "Bad lmc %d\n", lmc);
+ return NULL;
+ }
+
+ list_for_each_entry(d, &skx_edac_list, list) {
+ if (d->imc[0].src_id == src_id)
+ return d->imc[lmc].mci;
+ }
+
+ skx_printk(KERN_ERR, "No mci for src_id %d lmc %d\n", src_id, lmc);
+
+ return NULL;
}
static int skx_mce_check_error(struct notifier_block *nb, unsigned long val,
@@ -1039,10 +1126,23 @@ static int skx_mce_check_error(struct notifier_block *nb, unsigned long val,
if ((mce->status & 0xefff) >> 7 != 1 || !(mce->status & MCI_STATUS_ADDRV))
return NOTIFY_DONE;
+ memset(&res, 0, sizeof(res));
res.addr = mce->addr;
- if (!skx_decode(&res))
+
+ if (adxl_component_count) {
+ if (!skx_adxl_decode(&res))
+ return NOTIFY_DONE;
+
+ mci = get_mci(res.socket, res.imc);
+ } else {
+ if (!skx_decode(&res))
+ return NOTIFY_DONE;
+
+ mci = res.dev->imc[res.imc].mci;
+ }
+
+ if (!mci)
return NOTIFY_DONE;
- mci = res.dev->imc[res.imc].mci;
if (mce->mcgstatus & MCG_STATUS_MCIP)
type = "Exception";
@@ -1093,6 +1193,62 @@ static void skx_remove(void)
}
}
+static void __init skx_adxl_get(void)
+{
+ const char * const *names;
+ int i, j;
+
+ names = adxl_get_component_names();
+ if (!names) {
+ skx_printk(KERN_NOTICE, "No firmware support for address translation.");
+ skx_printk(KERN_CONT, " Only decoding DDR4 address!\n");
+ return;
+ }
+
+ for (i = 0; i < INDEX_MAX; i++) {
+ for (j = 0; names[j]; j++) {
+ if (!strcmp(component_names[i], names[j])) {
+ component_indices[i] = j;
+ break;
+ }
+ }
+
+ if (!names[j])
+ goto err;
+ }
+
+ adxl_component_names = names;
+ while (*names++)
+ adxl_component_count++;
+
+ adxl_values = kcalloc(adxl_component_count, sizeof(*adxl_values),
+ GFP_KERNEL);
+ if (!adxl_values) {
+ adxl_component_count = 0;
+ return;
+ }
+
+ adxl_msg = kzalloc(MSG_SIZE, GFP_KERNEL);
+ if (!adxl_msg) {
+ adxl_component_count = 0;
+ kfree(adxl_values);
+ }
+
+ return;
+err:
+ skx_printk(KERN_ERR, "'%s' is not matched from DSM parameters: ",
+ component_names[i]);
+ for (j = 0; names[j]; j++)
+ skx_printk(KERN_CONT, "%s ", names[j]);
+ skx_printk(KERN_CONT, "\n");
+}
+
+static void __exit skx_adxl_put(void)
+{
+ kfree(adxl_values);
+ kfree(adxl_msg);
+}
+
/*
* skx_init:
* make sure we are running on the correct cpu model
@@ -1157,6 +1313,15 @@ static int __init skx_init(void)
}
}
+ skx_msg = kzalloc(MSG_SIZE, GFP_KERNEL);
+ if (!skx_msg) {
+ rc = -ENOMEM;
+ goto fail;
+ }
+
+ if (nvdimm_count)
+ skx_adxl_get();
+
/* Ensure that the OPSTATE is set correctly for POLL or NMI */
opstate_init();
@@ -1175,6 +1340,9 @@ static void __exit skx_exit(void)
edac_dbg(2, "\n");
mce_unregister_decode_chain(&skx_mce_dec);
skx_remove();
+ if (nvdimm_count)
+ skx_adxl_put();
+ kfree(skx_msg);
teardown_skx_debug();
}
diff --git a/drivers/edac/thunderx_edac.c b/drivers/edac/thunderx_edac.c
index c009d94f40c5..34be60fe6892 100644
--- a/drivers/edac/thunderx_edac.c
+++ b/drivers/edac/thunderx_edac.c
@@ -1884,7 +1884,7 @@ static irqreturn_t thunderx_l2c_threaded_isr(int irq, void *irq_id)
default:
dev_err(&l2c->pdev->dev, "Unsupported device: %04x\n",
l2c->pdev->device);
- return IRQ_NONE;
+ goto err_free;
}
while (CIRC_CNT(l2c->ring_head, l2c->ring_tail,
@@ -1906,7 +1906,7 @@ static irqreturn_t thunderx_l2c_threaded_isr(int irq, void *irq_id)
l2c->ring_tail++;
}
- return IRQ_HANDLED;
+ ret = IRQ_HANDLED;
err_free:
kfree(other);
diff --git a/drivers/extcon/extcon-intel-cht-wc.c b/drivers/extcon/extcon-intel-cht-wc.c
index 5e1dd2772278..5ef215297101 100644
--- a/drivers/extcon/extcon-intel-cht-wc.c
+++ b/drivers/extcon/extcon-intel-cht-wc.c
@@ -1,18 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Extcon charger detection driver for Intel Cherrytrail Whiskey Cove PMIC
* Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
*
* Based on various non upstream patches to support the CHT Whiskey Cove PMIC:
* Copyright (C) 2013-2015 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
*/
#include <linux/extcon-provider.h>
@@ -32,10 +24,10 @@
#define CHT_WC_CHGRCTRL0_EMRGCHREN BIT(1)
#define CHT_WC_CHGRCTRL0_EXTCHRDIS BIT(2)
#define CHT_WC_CHGRCTRL0_SWCONTROL BIT(3)
-#define CHT_WC_CHGRCTRL0_TTLCK_MASK BIT(4)
-#define CHT_WC_CHGRCTRL0_CCSM_OFF_MASK BIT(5)
-#define CHT_WC_CHGRCTRL0_DBPOFF_MASK BIT(6)
-#define CHT_WC_CHGRCTRL0_WDT_NOKICK BIT(7)
+#define CHT_WC_CHGRCTRL0_TTLCK BIT(4)
+#define CHT_WC_CHGRCTRL0_CCSM_OFF BIT(5)
+#define CHT_WC_CHGRCTRL0_DBPOFF BIT(6)
+#define CHT_WC_CHGRCTRL0_CHR_WDT_NOKICK BIT(7)
#define CHT_WC_CHGRCTRL1 0x5e17
@@ -52,7 +44,7 @@
#define CHT_WC_USBSRC_TYPE_ACA 4
#define CHT_WC_USBSRC_TYPE_SE1 5
#define CHT_WC_USBSRC_TYPE_MHL 6
-#define CHT_WC_USBSRC_TYPE_FLOAT_DP_DN 7
+#define CHT_WC_USBSRC_TYPE_FLOATING 7
#define CHT_WC_USBSRC_TYPE_OTHER 8
#define CHT_WC_USBSRC_TYPE_DCP_EXTPHY 9
@@ -61,9 +53,12 @@
#define CHT_WC_PWRSRC_STS 0x6e1e
#define CHT_WC_PWRSRC_VBUS BIT(0)
#define CHT_WC_PWRSRC_DC BIT(1)
-#define CHT_WC_PWRSRC_BAT BIT(2)
-#define CHT_WC_PWRSRC_ID_GND BIT(3)
-#define CHT_WC_PWRSRC_ID_FLOAT BIT(4)
+#define CHT_WC_PWRSRC_BATT BIT(2)
+#define CHT_WC_PWRSRC_USBID_MASK GENMASK(4, 3)
+#define CHT_WC_PWRSRC_USBID_SHIFT 3
+#define CHT_WC_PWRSRC_RID_ACA 0
+#define CHT_WC_PWRSRC_RID_GND 1
+#define CHT_WC_PWRSRC_RID_FLOAT 2
#define CHT_WC_VBUS_GPIO_CTLO 0x6e2d
#define CHT_WC_VBUS_GPIO_CTLO_OUTPUT BIT(0)
@@ -104,16 +99,20 @@ struct cht_wc_extcon_data {
static int cht_wc_extcon_get_id(struct cht_wc_extcon_data *ext, int pwrsrc_sts)
{
- if (pwrsrc_sts & CHT_WC_PWRSRC_ID_GND)
+ switch ((pwrsrc_sts & CHT_WC_PWRSRC_USBID_MASK) >> CHT_WC_PWRSRC_USBID_SHIFT) {
+ case CHT_WC_PWRSRC_RID_GND:
return USB_ID_GND;
- if (pwrsrc_sts & CHT_WC_PWRSRC_ID_FLOAT)
+ case CHT_WC_PWRSRC_RID_FLOAT:
return USB_ID_FLOAT;
-
- /*
- * Once we have iio support for the gpadc we should read the USBID
- * gpadc channel here and determine ACA role based on that.
- */
- return USB_ID_FLOAT;
+ case CHT_WC_PWRSRC_RID_ACA:
+ default:
+ /*
+ * Once we have IIO support for the GPADC we should read
+ * the USBID GPADC channel here and determine ACA role
+ * based on that.
+ */
+ return USB_ID_FLOAT;
+ }
}
static int cht_wc_extcon_get_charger(struct cht_wc_extcon_data *ext,
@@ -156,9 +155,9 @@ static int cht_wc_extcon_get_charger(struct cht_wc_extcon_data *ext,
dev_warn(ext->dev,
"Unhandled charger type %d, defaulting to SDP\n",
ret);
- /* Fall through, treat as SDP */
+ return EXTCON_CHG_USB_SDP;
case CHT_WC_USBSRC_TYPE_SDP:
- case CHT_WC_USBSRC_TYPE_FLOAT_DP_DN:
+ case CHT_WC_USBSRC_TYPE_FLOATING:
case CHT_WC_USBSRC_TYPE_OTHER:
return EXTCON_CHG_USB_SDP;
case CHT_WC_USBSRC_TYPE_CDP:
@@ -279,7 +278,7 @@ static int cht_wc_extcon_sw_control(struct cht_wc_extcon_data *ext, bool enable)
{
int ret, mask, val;
- mask = CHT_WC_CHGRCTRL0_SWCONTROL | CHT_WC_CHGRCTRL0_CCSM_OFF_MASK;
+ mask = CHT_WC_CHGRCTRL0_SWCONTROL | CHT_WC_CHGRCTRL0_CCSM_OFF;
val = enable ? mask : 0;
ret = regmap_update_bits(ext->regmap, CHT_WC_CHGRCTRL0, mask, val);
if (ret)
@@ -292,6 +291,7 @@ static int cht_wc_extcon_probe(struct platform_device *pdev)
{
struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
struct cht_wc_extcon_data *ext;
+ unsigned long mask = ~(CHT_WC_PWRSRC_VBUS | CHT_WC_PWRSRC_USBID_MASK);
int irq, ret;
irq = platform_get_irq(pdev, 0);
@@ -352,9 +352,7 @@ static int cht_wc_extcon_probe(struct platform_device *pdev)
}
/* Unmask irqs */
- ret = regmap_write(ext->regmap, CHT_WC_PWRSRC_IRQ_MASK,
- (int)~(CHT_WC_PWRSRC_VBUS | CHT_WC_PWRSRC_ID_GND |
- CHT_WC_PWRSRC_ID_FLOAT));
+ ret = regmap_write(ext->regmap, CHT_WC_PWRSRC_IRQ_MASK, mask);
if (ret) {
dev_err(ext->dev, "Error writing irq-mask: %d\n", ret);
goto disable_sw_control;
diff --git a/drivers/extcon/extcon-intel-int3496.c b/drivers/extcon/extcon-intel-int3496.c
index fd24debe58a3..80c9abcc3f97 100644
--- a/drivers/extcon/extcon-intel-int3496.c
+++ b/drivers/extcon/extcon-intel-int3496.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Intel INT3496 ACPI device extcon driver
*
@@ -7,15 +8,6 @@
*
* Copyright (c) 2014, Intel Corporation.
* Author: David Cohen <david.a.cohen@linux.intel.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/acpi.h>
@@ -192,4 +184,4 @@ module_platform_driver(int3496_driver);
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
MODULE_DESCRIPTION("Intel INT3496 ACPI device extcon driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/extcon/extcon-max14577.c b/drivers/extcon/extcon-max14577.c
index b871836da8a4..22d2feb1f8bc 100644
--- a/drivers/extcon/extcon-max14577.c
+++ b/drivers/extcon/extcon-max14577.c
@@ -1,20 +1,10 @@
-/*
- * extcon-max14577.c - MAX14577/77836 extcon driver to support MUIC
- *
- * Copyright (C) 2013,2014 Samsung Electronics
- * Chanwoo Choi <cw00.choi@samsung.com>
- * Krzysztof Kozlowski <krzk@kernel.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 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.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// extcon-max14577.c - MAX14577/77836 extcon driver to support MUIC
+//
+// Copyright (C) 2013,2014 Samsung Electronics
+// Chanwoo Choi <cw00.choi@samsung.com>
+// Krzysztof Kozlowski <krzk@kernel.org>
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c
index 227651ff9666..a79537ebb671 100644
--- a/drivers/extcon/extcon-max77693.c
+++ b/drivers/extcon/extcon-max77693.c
@@ -1,19 +1,9 @@
-/*
- * extcon-max77693.c - MAX77693 extcon driver to support MAX77693 MUIC
- *
- * Copyright (C) 2012 Samsung Electrnoics
- * Chanwoo Choi <cw00.choi@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// extcon-max77693.c - MAX77693 extcon driver to support MAX77693 MUIC
+//
+// Copyright (C) 2012 Samsung Electrnoics
+// Chanwoo Choi <cw00.choi@samsung.com>
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/extcon/extcon-max77843.c b/drivers/extcon/extcon-max77843.c
index c9fcd6cd41cb..b98cbd0362f5 100644
--- a/drivers/extcon/extcon-max77843.c
+++ b/drivers/extcon/extcon-max77843.c
@@ -1,15 +1,10 @@
-/*
- * extcon-max77843.c - Maxim MAX77843 extcon driver to support
- * MUIC(Micro USB Interface Controller)
- *
- * Copyright (C) 2015 Samsung Electronics
- * Author: Jaewon Kim <jaewon02.kim@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// extcon-max77843.c - Maxim MAX77843 extcon driver to support
+// MUIC(Micro USB Interface Controller)
+//
+// Copyright (C) 2015 Samsung Electronics
+// Author: Jaewon Kim <jaewon02.kim@samsung.com>
#include <linux/extcon-provider.h>
#include <linux/i2c.h>
diff --git a/drivers/extcon/extcon-max8997.c b/drivers/extcon/extcon-max8997.c
index 9f30f4929b72..bdabb2479e0d 100644
--- a/drivers/extcon/extcon-max8997.c
+++ b/drivers/extcon/extcon-max8997.c
@@ -1,19 +1,9 @@
-/*
- * extcon-max8997.c - MAX8997 extcon driver to support MAX8997 MUIC
- *
- * Copyright (C) 2012 Samsung Electronics
- * Donggeun Kim <dg77.kim@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// extcon-max8997.c - MAX8997 extcon driver to support MAX8997 MUIC
+//
+// Copyright (C) 2012 Samsung Electronics
+// Donggeun Kim <dg77.kim@samsung.com>
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c
index b9d27c8fe57e..5ab0498be652 100644
--- a/drivers/extcon/extcon.c
+++ b/drivers/extcon/extcon.c
@@ -628,7 +628,7 @@ int extcon_get_property(struct extcon_dev *edev, unsigned int id,
unsigned long flags;
int index, ret = 0;
- *prop_val = (union extcon_property_value)(0);
+ *prop_val = (union extcon_property_value){0};
if (!edev)
return -EINVAL;
@@ -1123,7 +1123,6 @@ int extcon_dev_register(struct extcon_dev *edev)
(unsigned long)atomic_inc_return(&edev_no));
if (edev->max_supported) {
- char buf[10];
char *str;
struct extcon_cable *cable;
@@ -1137,9 +1136,7 @@ int extcon_dev_register(struct extcon_dev *edev)
for (index = 0; index < edev->max_supported; index++) {
cable = &edev->cables[index];
- snprintf(buf, 10, "cable.%d", index);
- str = kzalloc(strlen(buf) + 1,
- GFP_KERNEL);
+ str = kasprintf(GFP_KERNEL, "cable.%d", index);
if (!str) {
for (index--; index >= 0; index--) {
cable = &edev->cables[index];
@@ -1149,7 +1146,6 @@ int extcon_dev_register(struct extcon_dev *edev)
goto err_alloc_cables;
}
- strcpy(str, buf);
cable->edev = edev;
cable->cable_index = index;
@@ -1172,7 +1168,6 @@ int extcon_dev_register(struct extcon_dev *edev)
}
if (edev->max_supported && edev->mutually_exclusive) {
- char buf[80];
char *name;
/* Count the size of mutually_exclusive array */
@@ -1197,9 +1192,8 @@ int extcon_dev_register(struct extcon_dev *edev)
}
for (index = 0; edev->mutually_exclusive[index]; index++) {
- sprintf(buf, "0x%x", edev->mutually_exclusive[index]);
- name = kzalloc(strlen(buf) + 1,
- GFP_KERNEL);
+ name = kasprintf(GFP_KERNEL, "0x%x",
+ edev->mutually_exclusive[index]);
if (!name) {
for (index--; index >= 0; index--) {
kfree(edev->d_attrs_muex[index].attr.
@@ -1210,7 +1204,6 @@ int extcon_dev_register(struct extcon_dev *edev)
ret = -ENOMEM;
goto err_muex;
}
- strcpy(name, buf);
sysfs_attr_init(&edev->d_attrs_muex[index].attr);
edev->d_attrs_muex[index].attr.name = name;
edev->d_attrs_muex[index].attr.mode = 0000;
diff --git a/drivers/firewire/core-iso.c b/drivers/firewire/core-iso.c
index 051327a951b1..35e784cffc23 100644
--- a/drivers/firewire/core-iso.c
+++ b/drivers/firewire/core-iso.c
@@ -337,9 +337,16 @@ static void deallocate_channel(struct fw_card *card, int irm_id,
/**
* fw_iso_resource_manage() - Allocate or deallocate a channel and/or bandwidth
+ * @card: card interface for this action
+ * @generation: bus generation
+ * @channels_mask: bitmask for channel allocation
+ * @channel: pointer for returning channel allocation result
+ * @bandwidth: pointer for returning bandwidth allocation result
+ * @allocate: whether to allocate (true) or deallocate (false)
*
* In parameters: card, generation, channels_mask, bandwidth, allocate
* Out parameters: channel, bandwidth
+ *
* This function blocks (sleeps) during communication with the IRM.
*
* Allocates or deallocates at most one channel out of channels_mask.
diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c
index 4372f9e4b0da..50bf1fe1775f 100644
--- a/drivers/firewire/core-transaction.c
+++ b/drivers/firewire/core-transaction.c
@@ -410,6 +410,14 @@ static void transaction_callback(struct fw_card *card, int rcode,
/**
* fw_run_transaction() - send request and sleep until transaction is completed
+ * @card: card interface for this request
+ * @tcode: transaction code
+ * @destination_id: destination node ID, consisting of bus_ID and phy_ID
+ * @generation: bus generation in which request and response are valid
+ * @speed: transmission speed
+ * @offset: 48bit wide offset into destination's address space
+ * @payload: data payload for the request subaction
+ * @length: length of the payload, in bytes
*
* Returns the RCODE. See fw_send_request() for parameter documentation.
* Unlike fw_send_request(), @data points to the payload of the request or/and
@@ -604,6 +612,7 @@ EXPORT_SYMBOL(fw_core_add_address_handler);
/**
* fw_core_remove_address_handler() - unregister an address handler
+ * @handler: callback
*
* To be called in process context.
*
@@ -828,6 +837,7 @@ EXPORT_SYMBOL(fw_send_response);
/**
* fw_get_request_speed() - returns speed at which the @request was received
+ * @request: firewire request data
*/
int fw_get_request_speed(struct fw_request *request)
{
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index 6e83880046d7..7273e5082b41 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -145,34 +145,6 @@ config EFI_PCDP
See DIG64_HCDPv20_042804.pdf available from
<http://www.dig64.org/specifications/>
-config DELL_RBU
- tristate "BIOS update support for DELL systems via sysfs"
- depends on X86
- select FW_LOADER
- select FW_LOADER_USER_HELPER
- help
- Say m if you want to have the option of updating the BIOS for your
- DELL system. Note you need a Dell OpenManage or Dell Update package (DUP)
- supporting application to communicate with the BIOS regarding the new
- image for the image update to take effect.
- See <file:Documentation/dell_rbu.txt> for more details on the driver.
-
-config DCDBAS
- tristate "Dell Systems Management Base Driver"
- depends on X86
- help
- The Dell Systems Management Base Driver provides a sysfs interface
- for systems management software to perform System Management
- Interrupts (SMIs) and Host Control Actions (system power cycle or
- power off after OS shutdown) on certain Dell systems.
-
- See <file:Documentation/dcdbas.txt> for more details on the driver
- and the Dell systems on which Dell systems management software makes
- use of this driver.
-
- Say Y or M here to enable the driver for use by Dell systems
- management software such as Dell OpenManage.
-
config DMIID
bool "Export DMI identification via sysfs to userspace"
depends on DMI
@@ -289,7 +261,9 @@ config HAVE_ARM_SMCCC
source "drivers/firmware/broadcom/Kconfig"
source "drivers/firmware/google/Kconfig"
source "drivers/firmware/efi/Kconfig"
+source "drivers/firmware/imx/Kconfig"
source "drivers/firmware/meson/Kconfig"
source "drivers/firmware/tegra/Kconfig"
+source "drivers/firmware/xilinx/Kconfig"
endmenu
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index e18a041cfc53..3158dffd9914 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -11,8 +11,6 @@ obj-$(CONFIG_DMI) += dmi_scan.o
obj-$(CONFIG_DMI_SYSFS) += dmi-sysfs.o
obj-$(CONFIG_EDD) += edd.o
obj-$(CONFIG_EFI_PCDP) += pcdp.o
-obj-$(CONFIG_DELL_RBU) += dell_rbu.o
-obj-$(CONFIG_DCDBAS) += dcdbas.o
obj-$(CONFIG_DMIID) += dmi-id.o
obj-$(CONFIG_ISCSI_IBFT_FIND) += iscsi_ibft_find.o
obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o
@@ -31,4 +29,6 @@ obj-y += meson/
obj-$(CONFIG_GOOGLE_FIRMWARE) += google/
obj-$(CONFIG_EFI) += efi/
obj-$(CONFIG_UEFI_CPER) += efi/
+obj-y += imx/
obj-y += tegra/
+obj-y += xilinx/
diff --git a/drivers/firmware/arm_scmi/base.c b/drivers/firmware/arm_scmi/base.c
index 9dff33ea6416..204390297f4b 100644
--- a/drivers/firmware/arm_scmi/base.c
+++ b/drivers/firmware/arm_scmi/base.c
@@ -208,7 +208,7 @@ static int scmi_base_discover_agent_get(const struct scmi_handle *handle,
ret = scmi_do_xfer(handle, t);
if (!ret)
- memcpy(name, t->rx.buf, SCMI_MAX_STR_SIZE);
+ strlcpy(name, t->rx.buf, SCMI_MAX_STR_SIZE);
scmi_xfer_put(handle, t);
diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/clock.c
index e4119eb34986..30fc04e28431 100644
--- a/drivers/firmware/arm_scmi/clock.c
+++ b/drivers/firmware/arm_scmi/clock.c
@@ -111,7 +111,7 @@ static int scmi_clock_attributes_get(const struct scmi_handle *handle,
ret = scmi_do_xfer(handle, t);
if (!ret)
- memcpy(clk->name, attr->name, SCMI_MAX_STR_SIZE);
+ strlcpy(clk->name, attr->name, SCMI_MAX_STR_SIZE);
else
clk->name[0] = '\0';
diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c
index 64342944d917..3c8ae7cc35de 100644
--- a/drivers/firmware/arm_scmi/perf.c
+++ b/drivers/firmware/arm_scmi/perf.c
@@ -174,7 +174,7 @@ scmi_perf_domain_attributes_get(const struct scmi_handle *handle, u32 domain,
dom_info->mult_factor =
(dom_info->sustained_freq_khz * 1000) /
dom_info->sustained_perf_level;
- memcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE);
+ strlcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE);
}
scmi_xfer_put(handle, t);
@@ -427,6 +427,33 @@ static int scmi_dvfs_freq_get(const struct scmi_handle *handle, u32 domain,
return ret;
}
+static int scmi_dvfs_est_power_get(const struct scmi_handle *handle, u32 domain,
+ unsigned long *freq, unsigned long *power)
+{
+ struct scmi_perf_info *pi = handle->perf_priv;
+ struct perf_dom_info *dom;
+ unsigned long opp_freq;
+ int idx, ret = -EINVAL;
+ struct scmi_opp *opp;
+
+ dom = pi->dom_info + domain;
+ if (!dom)
+ return -EIO;
+
+ for (opp = dom->opp, idx = 0; idx < dom->opp_count; idx++, opp++) {
+ opp_freq = opp->perf * dom->mult_factor;
+ if (opp_freq < *freq)
+ continue;
+
+ *freq = opp_freq;
+ *power = opp->power;
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
static struct scmi_perf_ops perf_ops = {
.limits_set = scmi_perf_limits_set,
.limits_get = scmi_perf_limits_get,
@@ -437,6 +464,7 @@ static struct scmi_perf_ops perf_ops = {
.device_opps_add = scmi_dvfs_device_opps_add,
.freq_set = scmi_dvfs_freq_set,
.freq_get = scmi_dvfs_freq_get,
+ .est_power_get = scmi_dvfs_est_power_get,
};
static int scmi_perf_protocol_init(struct scmi_handle *handle)
diff --git a/drivers/firmware/arm_scmi/power.c b/drivers/firmware/arm_scmi/power.c
index cfa033b05aed..62f3401a1f01 100644
--- a/drivers/firmware/arm_scmi/power.c
+++ b/drivers/firmware/arm_scmi/power.c
@@ -106,7 +106,7 @@ scmi_power_domain_attributes_get(const struct scmi_handle *handle, u32 domain,
dom_info->state_set_notify = SUPPORTS_STATE_SET_NOTIFY(flags);
dom_info->state_set_async = SUPPORTS_STATE_SET_ASYNC(flags);
dom_info->state_set_sync = SUPPORTS_STATE_SET_SYNC(flags);
- memcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE);
+ strlcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE);
}
scmi_xfer_put(handle, t);
diff --git a/drivers/firmware/arm_scmi/sensors.c b/drivers/firmware/arm_scmi/sensors.c
index 27f2092b9882..b53d5cc9c9f6 100644
--- a/drivers/firmware/arm_scmi/sensors.c
+++ b/drivers/firmware/arm_scmi/sensors.c
@@ -140,7 +140,7 @@ static int scmi_sensor_description_get(const struct scmi_handle *handle,
s = &si->sensors[desc_index + cnt];
s->id = le32_to_cpu(buf->desc[cnt].id);
s->type = SENSOR_TYPE(attrh);
- memcpy(s->name, buf->desc[cnt].name, SCMI_MAX_STR_SIZE);
+ strlcpy(s->name, buf->desc[cnt].name, SCMI_MAX_STR_SIZE);
}
desc_index += num_returned;
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index f2483548cde9..099d83e4e910 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -5,7 +5,7 @@
#include <linux/ctype.h>
#include <linux/dmi.h>
#include <linux/efi.h>
-#include <linux/bootmem.h>
+#include <linux/memblock.h>
#include <linux/random.h>
#include <asm/dmi.h>
#include <asm/unaligned.h>
diff --git a/drivers/firmware/efi/apple-properties.c b/drivers/firmware/efi/apple-properties.c
index 60a95719ecb8..ac1654f74dc7 100644
--- a/drivers/firmware/efi/apple-properties.c
+++ b/drivers/firmware/efi/apple-properties.c
@@ -20,7 +20,7 @@
#define pr_fmt(fmt) "apple-properties: " fmt
-#include <linux/bootmem.h>
+#include <linux/memblock.h>
#include <linux/efi.h>
#include <linux/io.h>
#include <linux/platform_data/x86/apple.h>
@@ -235,7 +235,7 @@ static int __init map_properties(void)
*/
data->len = 0;
memunmap(data);
- free_bootmem_late(pa_data + sizeof(*data), data_len);
+ memblock_free_late(pa_data + sizeof(*data), data_len);
return ret;
}
diff --git a/drivers/firmware/efi/arm-init.c b/drivers/firmware/efi/arm-init.c
index 388a929baf95..1a6a77df8a5e 100644
--- a/drivers/firmware/efi/arm-init.c
+++ b/drivers/firmware/efi/arm-init.c
@@ -265,6 +265,10 @@ void __init efi_init(void)
(params.mmap & ~PAGE_MASK)));
init_screen_info();
+
+ /* ARM does not permit early mappings to persist across paging_init() */
+ if (IS_ENABLED(CONFIG_ARM))
+ efi_memmap_unmap();
}
static int __init register_gop_device(void)
diff --git a/drivers/firmware/efi/arm-runtime.c b/drivers/firmware/efi/arm-runtime.c
index 922cfb813109..a00934d263c5 100644
--- a/drivers/firmware/efi/arm-runtime.c
+++ b/drivers/firmware/efi/arm-runtime.c
@@ -110,7 +110,7 @@ static int __init arm_enable_runtime_services(void)
{
u64 mapsize;
- if (!efi_enabled(EFI_BOOT) || !efi_enabled(EFI_MEMMAP)) {
+ if (!efi_enabled(EFI_BOOT)) {
pr_info("EFI services will not be available.\n");
return 0;
}
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index 2a29dd9c986d..fad7c62cfc0e 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -52,7 +52,8 @@ struct efi __read_mostly efi = {
.properties_table = EFI_INVALID_TABLE_ADDR,
.mem_attr_table = EFI_INVALID_TABLE_ADDR,
.rng_seed = EFI_INVALID_TABLE_ADDR,
- .tpm_log = EFI_INVALID_TABLE_ADDR
+ .tpm_log = EFI_INVALID_TABLE_ADDR,
+ .mem_reserve = EFI_INVALID_TABLE_ADDR,
};
EXPORT_SYMBOL(efi);
@@ -484,6 +485,7 @@ static __initdata efi_config_table_type_t common_tables[] = {
{EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMATTR", &efi.mem_attr_table},
{LINUX_EFI_RANDOM_SEED_TABLE_GUID, "RNG", &efi.rng_seed},
{LINUX_EFI_TPM_EVENT_LOG_GUID, "TPMEventLog", &efi.tpm_log},
+ {LINUX_EFI_MEMRESERVE_TABLE_GUID, "MEMRESERVE", &efi.mem_reserve},
{NULL_GUID, NULL, NULL},
};
@@ -590,6 +592,33 @@ int __init efi_config_parse_tables(void *config_tables, int count, int sz,
early_memunmap(tbl, sizeof(*tbl));
}
+ return 0;
+}
+
+int __init efi_apply_persistent_mem_reservations(void)
+{
+ if (efi.mem_reserve != EFI_INVALID_TABLE_ADDR) {
+ unsigned long prsv = efi.mem_reserve;
+
+ while (prsv) {
+ struct linux_efi_memreserve *rsv;
+
+ /* reserve the entry itself */
+ memblock_reserve(prsv, sizeof(*rsv));
+
+ rsv = early_memremap(prsv, sizeof(*rsv));
+ if (rsv == NULL) {
+ pr_err("Could not map UEFI memreserve entry!\n");
+ return -ENOMEM;
+ }
+
+ if (rsv->size)
+ memblock_reserve(rsv->base, rsv->size);
+
+ prsv = rsv->next;
+ early_memunmap(rsv, sizeof(*rsv));
+ }
+ }
return 0;
}
@@ -937,6 +966,45 @@ bool efi_is_table_address(unsigned long phys_addr)
return false;
}
+static DEFINE_SPINLOCK(efi_mem_reserve_persistent_lock);
+static struct linux_efi_memreserve *efi_memreserve_root __ro_after_init;
+
+int efi_mem_reserve_persistent(phys_addr_t addr, u64 size)
+{
+ struct linux_efi_memreserve *rsv;
+
+ if (!efi_memreserve_root)
+ return -ENODEV;
+
+ rsv = kmalloc(sizeof(*rsv), GFP_ATOMIC);
+ if (!rsv)
+ return -ENOMEM;
+
+ rsv->base = addr;
+ rsv->size = size;
+
+ spin_lock(&efi_mem_reserve_persistent_lock);
+ rsv->next = efi_memreserve_root->next;
+ efi_memreserve_root->next = __pa(rsv);
+ spin_unlock(&efi_mem_reserve_persistent_lock);
+
+ return 0;
+}
+
+static int __init efi_memreserve_root_init(void)
+{
+ if (efi.mem_reserve == EFI_INVALID_TABLE_ADDR)
+ return -ENODEV;
+
+ efi_memreserve_root = memremap(efi.mem_reserve,
+ sizeof(*efi_memreserve_root),
+ MEMREMAP_WB);
+ if (!efi_memreserve_root)
+ return -ENOMEM;
+ return 0;
+}
+early_initcall(efi_memreserve_root_init);
+
#ifdef CONFIG_KEXEC
static int update_efi_random_seed(struct notifier_block *nb,
unsigned long code, void *unused)
diff --git a/drivers/firmware/efi/efivars.c b/drivers/firmware/efi/efivars.c
index 3e626fd9bd4e..8061667a6765 100644
--- a/drivers/firmware/efi/efivars.c
+++ b/drivers/firmware/efi/efivars.c
@@ -229,14 +229,6 @@ sanity_check(struct efi_variable *var, efi_char16_t *name, efi_guid_t vendor,
return 0;
}
-static inline bool is_compat(void)
-{
- if (IS_ENABLED(CONFIG_COMPAT) && in_compat_syscall())
- return true;
-
- return false;
-}
-
static void
copy_out_compat(struct efi_variable *dst, struct compat_efi_variable *src)
{
@@ -263,7 +255,7 @@ efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count)
u8 *data;
int err;
- if (is_compat()) {
+ if (in_compat_syscall()) {
struct compat_efi_variable *compat;
if (count != sizeof(*compat))
@@ -324,7 +316,7 @@ efivar_show_raw(struct efivar_entry *entry, char *buf)
&entry->var.DataSize, entry->var.Data))
return -EIO;
- if (is_compat()) {
+ if (in_compat_syscall()) {
compat = (struct compat_efi_variable *)buf;
size = sizeof(*compat);
@@ -418,7 +410,7 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
struct compat_efi_variable *compat = (struct compat_efi_variable *)buf;
struct efi_variable *new_var = (struct efi_variable *)buf;
struct efivar_entry *new_entry;
- bool need_compat = is_compat();
+ bool need_compat = in_compat_syscall();
efi_char16_t *name;
unsigned long size;
u32 attributes;
@@ -495,7 +487,7 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
- if (is_compat()) {
+ if (in_compat_syscall()) {
if (count != sizeof(*compat))
return -EINVAL;
diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
index 14c40a7750d1..c51627660dbb 100644
--- a/drivers/firmware/efi/libstub/Makefile
+++ b/drivers/firmware/efi/libstub/Makefile
@@ -16,7 +16,8 @@ cflags-$(CONFIG_X86) += -m$(BITS) -D__KERNEL__ -O2 \
cflags-$(CONFIG_ARM64) := $(subst -pg,,$(KBUILD_CFLAGS)) -fpie \
$(DISABLE_STACKLEAK_PLUGIN)
cflags-$(CONFIG_ARM) := $(subst -pg,,$(KBUILD_CFLAGS)) \
- -fno-builtin -fpic -mno-single-pic-base
+ -fno-builtin -fpic \
+ $(call cc-option,-mno-single-pic-base)
cflags-$(CONFIG_EFI_ARMSTUB) += -I$(srctree)/scripts/dtc/libfdt
diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c
index 6920033de6d4..3d36142cf812 100644
--- a/drivers/firmware/efi/libstub/arm-stub.c
+++ b/drivers/firmware/efi/libstub/arm-stub.c
@@ -69,6 +69,34 @@ static struct screen_info *setup_graphics(efi_system_table_t *sys_table_arg)
return si;
}
+void install_memreserve_table(efi_system_table_t *sys_table_arg)
+{
+ struct linux_efi_memreserve *rsv;
+ efi_guid_t memreserve_table_guid = LINUX_EFI_MEMRESERVE_TABLE_GUID;
+ efi_status_t status;
+
+ if (IS_ENABLED(CONFIG_ARM))
+ return;
+
+ status = efi_call_early(allocate_pool, EFI_LOADER_DATA, sizeof(*rsv),
+ (void **)&rsv);
+ if (status != EFI_SUCCESS) {
+ pr_efi_err(sys_table_arg, "Failed to allocate memreserve entry!\n");
+ return;
+ }
+
+ rsv->next = 0;
+ rsv->base = 0;
+ rsv->size = 0;
+
+ status = efi_call_early(install_configuration_table,
+ &memreserve_table_guid,
+ rsv);
+ if (status != EFI_SUCCESS)
+ pr_efi_err(sys_table_arg, "Failed to install memreserve config table!\n");
+}
+
+
/*
* This function handles the architcture specific differences between arm and
* arm64 regarding where the kernel image must be loaded and any memory that
@@ -235,6 +263,8 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table,
}
}
+ install_memreserve_table(sys_table);
+
new_fdt_addr = fdt_addr;
status = allocate_new_fdt_and_exit_boot(sys_table, handle,
&new_fdt_addr, efi_get_max_fdt_addr(dram_base),
diff --git a/drivers/firmware/efi/libstub/fdt.c b/drivers/firmware/efi/libstub/fdt.c
index 8830fa601e45..0c0d2312f4a8 100644
--- a/drivers/firmware/efi/libstub/fdt.c
+++ b/drivers/firmware/efi/libstub/fdt.c
@@ -158,6 +158,10 @@ static efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,
return efi_status;
}
}
+
+ /* shrink the FDT back to its minimum size */
+ fdt_pack(fdt);
+
return EFI_SUCCESS;
fdt_set_fail:
diff --git a/drivers/firmware/efi/memmap.c b/drivers/firmware/efi/memmap.c
index 5fc70520e04c..38b686c67b17 100644
--- a/drivers/firmware/efi/memmap.c
+++ b/drivers/firmware/efi/memmap.c
@@ -15,7 +15,7 @@
static phys_addr_t __init __efi_memmap_alloc_early(unsigned long size)
{
- return memblock_alloc(size, 0);
+ return memblock_phys_alloc(size, SMP_CACHE_BYTES);
}
static phys_addr_t __init __efi_memmap_alloc_late(unsigned long size)
@@ -118,6 +118,9 @@ int __init efi_memmap_init_early(struct efi_memory_map_data *data)
void __init efi_memmap_unmap(void)
{
+ if (!efi_enabled(EFI_MEMMAP))
+ return;
+
if (!efi.memmap.late) {
unsigned long size;
diff --git a/drivers/firmware/efi/runtime-wrappers.c b/drivers/firmware/efi/runtime-wrappers.c
index aa66cbf23512..8903b9ccfc2b 100644
--- a/drivers/firmware/efi/runtime-wrappers.c
+++ b/drivers/firmware/efi/runtime-wrappers.c
@@ -45,39 +45,7 @@
#define __efi_call_virt(f, args...) \
__efi_call_virt_pointer(efi.systab->runtime, f, args)
-/* efi_runtime_service() function identifiers */
-enum efi_rts_ids {
- GET_TIME,
- SET_TIME,
- GET_WAKEUP_TIME,
- SET_WAKEUP_TIME,
- GET_VARIABLE,
- GET_NEXT_VARIABLE,
- SET_VARIABLE,
- QUERY_VARIABLE_INFO,
- GET_NEXT_HIGH_MONO_COUNT,
- UPDATE_CAPSULE,
- QUERY_CAPSULE_CAPS,
-};
-
-/*
- * efi_runtime_work: Details of EFI Runtime Service work
- * @arg<1-5>: EFI Runtime Service function arguments
- * @status: Status of executing EFI Runtime Service
- * @efi_rts_id: EFI Runtime Service function identifier
- * @efi_rts_comp: Struct used for handling completions
- */
-struct efi_runtime_work {
- void *arg1;
- void *arg2;
- void *arg3;
- void *arg4;
- void *arg5;
- efi_status_t status;
- struct work_struct work;
- enum efi_rts_ids efi_rts_id;
- struct completion efi_rts_comp;
-};
+struct efi_runtime_work efi_rts_work;
/*
* efi_queue_work: Queue efi_runtime_service() and wait until it's done
@@ -91,11 +59,15 @@ struct efi_runtime_work {
*/
#define efi_queue_work(_rts, _arg1, _arg2, _arg3, _arg4, _arg5) \
({ \
- struct efi_runtime_work efi_rts_work; \
efi_rts_work.status = EFI_ABORTED; \
\
+ if (!efi_enabled(EFI_RUNTIME_SERVICES)) { \
+ pr_warn_once("EFI Runtime Services are disabled!\n"); \
+ goto exit; \
+ } \
+ \
init_completion(&efi_rts_work.efi_rts_comp); \
- INIT_WORK_ONSTACK(&efi_rts_work.work, efi_call_rts); \
+ INIT_WORK(&efi_rts_work.work, efi_call_rts); \
efi_rts_work.arg1 = _arg1; \
efi_rts_work.arg2 = _arg2; \
efi_rts_work.arg3 = _arg3; \
@@ -112,6 +84,8 @@ struct efi_runtime_work {
else \
pr_err("Failed to queue work to efi_rts_wq.\n"); \
\
+exit: \
+ efi_rts_work.efi_rts_id = NONE; \
efi_rts_work.status; \
})
@@ -184,18 +158,16 @@ static DEFINE_SEMAPHORE(efi_runtime_lock);
*/
static void efi_call_rts(struct work_struct *work)
{
- struct efi_runtime_work *efi_rts_work;
void *arg1, *arg2, *arg3, *arg4, *arg5;
efi_status_t status = EFI_NOT_FOUND;
- efi_rts_work = container_of(work, struct efi_runtime_work, work);
- arg1 = efi_rts_work->arg1;
- arg2 = efi_rts_work->arg2;
- arg3 = efi_rts_work->arg3;
- arg4 = efi_rts_work->arg4;
- arg5 = efi_rts_work->arg5;
+ arg1 = efi_rts_work.arg1;
+ arg2 = efi_rts_work.arg2;
+ arg3 = efi_rts_work.arg3;
+ arg4 = efi_rts_work.arg4;
+ arg5 = efi_rts_work.arg5;
- switch (efi_rts_work->efi_rts_id) {
+ switch (efi_rts_work.efi_rts_id) {
case GET_TIME:
status = efi_call_virt(get_time, (efi_time_t *)arg1,
(efi_time_cap_t *)arg2);
@@ -253,8 +225,8 @@ static void efi_call_rts(struct work_struct *work)
*/
pr_err("Requested executing invalid EFI Runtime Service.\n");
}
- efi_rts_work->status = status;
- complete(&efi_rts_work->efi_rts_comp);
+ efi_rts_work.status = status;
+ complete(&efi_rts_work.efi_rts_comp);
}
static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
@@ -428,6 +400,7 @@ static void virt_efi_reset_system(int reset_type,
"could not get exclusive access to the firmware\n");
return;
}
+ efi_rts_work.efi_rts_id = RESET_SYSTEM;
__efi_call_virt(reset_system, reset_type, status, data_size, data);
up(&efi_runtime_lock);
}
diff --git a/drivers/firmware/efi/test/efi_test.c b/drivers/firmware/efi/test/efi_test.c
index 41c48a1e8baa..769640940c9f 100644
--- a/drivers/firmware/efi/test/efi_test.c
+++ b/drivers/firmware/efi/test/efi_test.c
@@ -542,6 +542,30 @@ static long efi_runtime_get_nexthighmonocount(unsigned long arg)
return 0;
}
+static long efi_runtime_reset_system(unsigned long arg)
+{
+ struct efi_resetsystem __user *resetsystem_user;
+ struct efi_resetsystem resetsystem;
+ void *data = NULL;
+
+ resetsystem_user = (struct efi_resetsystem __user *)arg;
+ if (copy_from_user(&resetsystem, resetsystem_user,
+ sizeof(resetsystem)))
+ return -EFAULT;
+ if (resetsystem.data_size != 0) {
+ data = memdup_user((void *)resetsystem.data,
+ resetsystem.data_size);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+ }
+
+ efi.reset_system(resetsystem.reset_type, resetsystem.status,
+ resetsystem.data_size, (efi_char16_t *)data);
+
+ kfree(data);
+ return 0;
+}
+
static long efi_runtime_query_variableinfo(unsigned long arg)
{
struct efi_queryvariableinfo __user *queryvariableinfo_user;
@@ -682,6 +706,9 @@ static long efi_test_ioctl(struct file *file, unsigned int cmd,
case EFI_RUNTIME_QUERY_CAPSULECAPABILITIES:
return efi_runtime_query_capsulecaps(arg);
+
+ case EFI_RUNTIME_RESET_SYSTEM:
+ return efi_runtime_reset_system(arg);
}
return -ENOTTY;
diff --git a/drivers/firmware/efi/test/efi_test.h b/drivers/firmware/efi/test/efi_test.h
index 9812c6a02b40..5f4818bf112f 100644
--- a/drivers/firmware/efi/test/efi_test.h
+++ b/drivers/firmware/efi/test/efi_test.h
@@ -81,6 +81,13 @@ struct efi_querycapsulecapabilities {
efi_status_t *status;
} __packed;
+struct efi_resetsystem {
+ int reset_type;
+ efi_status_t status;
+ unsigned long data_size;
+ efi_char16_t *data;
+} __packed;
+
#define EFI_RUNTIME_GET_VARIABLE \
_IOWR('p', 0x01, struct efi_getvariable)
#define EFI_RUNTIME_SET_VARIABLE \
@@ -108,4 +115,7 @@ struct efi_querycapsulecapabilities {
#define EFI_RUNTIME_QUERY_CAPSULECAPABILITIES \
_IOR('p', 0x0A, struct efi_querycapsulecapabilities)
+#define EFI_RUNTIME_RESET_SYSTEM \
+ _IOW('p', 0x0B, struct efi_resetsystem)
+
#endif /* _DRIVERS_FIRMWARE_EFI_TEST_H_ */
diff --git a/drivers/firmware/google/Kconfig b/drivers/firmware/google/Kconfig
index a456a000048b..91a0404affe2 100644
--- a/drivers/firmware/google/Kconfig
+++ b/drivers/firmware/google/Kconfig
@@ -10,37 +10,31 @@ if GOOGLE_FIRMWARE
config GOOGLE_SMI
tristate "SMI interface for Google platforms"
- depends on X86 && ACPI && DMI && EFI
- select EFI_VARS
+ depends on X86 && ACPI && DMI
help
Say Y here if you want to enable SMI callbacks for Google
platforms. This provides an interface for writing to and
- clearing the EFI event log and reading and writing NVRAM
+ clearing the event log. If EFI_VARS is also enabled this
+ driver provides an interface for reading and writing NVRAM
variables.
config GOOGLE_COREBOOT_TABLE
- tristate
- depends on GOOGLE_COREBOOT_TABLE_ACPI || GOOGLE_COREBOOT_TABLE_OF
-
-config GOOGLE_COREBOOT_TABLE_ACPI
- tristate "Coreboot Table Access - ACPI"
- depends on ACPI
- select GOOGLE_COREBOOT_TABLE
+ tristate "Coreboot Table Access"
+ depends on ACPI || OF
help
This option enables the coreboot_table module, which provides other
- firmware modules to access to the coreboot table. The coreboot table
- pointer is accessed through the ACPI "GOOGCB00" object.
+ firmware modules access to the coreboot table. The coreboot table
+ pointer is accessed through the ACPI "GOOGCB00" object or the
+ device tree node /firmware/coreboot.
If unsure say N.
+config GOOGLE_COREBOOT_TABLE_ACPI
+ tristate
+ select GOOGLE_COREBOOT_TABLE
+
config GOOGLE_COREBOOT_TABLE_OF
- tristate "Coreboot Table Access - Device Tree"
- depends on OF
+ tristate
select GOOGLE_COREBOOT_TABLE
- help
- This option enable the coreboot_table module, which provide other
- firmware modules to access coreboot table. The coreboot table pointer
- is accessed through the device tree node /firmware/coreboot.
- If unsure say N.
config GOOGLE_MEMCONSOLE
tristate
diff --git a/drivers/firmware/google/Makefile b/drivers/firmware/google/Makefile
index d0b3fba96194..d17caded5d88 100644
--- a/drivers/firmware/google/Makefile
+++ b/drivers/firmware/google/Makefile
@@ -2,8 +2,6 @@
obj-$(CONFIG_GOOGLE_SMI) += gsmi.o
obj-$(CONFIG_GOOGLE_COREBOOT_TABLE) += coreboot_table.o
-obj-$(CONFIG_GOOGLE_COREBOOT_TABLE_ACPI) += coreboot_table-acpi.o
-obj-$(CONFIG_GOOGLE_COREBOOT_TABLE_OF) += coreboot_table-of.o
obj-$(CONFIG_GOOGLE_FRAMEBUFFER_COREBOOT) += framebuffer-coreboot.o
obj-$(CONFIG_GOOGLE_MEMCONSOLE) += memconsole.o
obj-$(CONFIG_GOOGLE_MEMCONSOLE_COREBOOT) += memconsole-coreboot.o
diff --git a/drivers/firmware/google/coreboot_table-acpi.c b/drivers/firmware/google/coreboot_table-acpi.c
deleted file mode 100644
index 77197fe3d42f..000000000000
--- a/drivers/firmware/google/coreboot_table-acpi.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * coreboot_table-acpi.c
- *
- * Using ACPI to locate Coreboot table and provide coreboot table access.
- *
- * Copyright 2017 Google Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License v2.0 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/acpi.h>
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-
-#include "coreboot_table.h"
-
-static int coreboot_table_acpi_probe(struct platform_device *pdev)
-{
- phys_addr_t phyaddr;
- resource_size_t len;
- struct coreboot_table_header __iomem *header = NULL;
- struct resource *res;
- void __iomem *ptr = NULL;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -EINVAL;
-
- len = resource_size(res);
- if (!res->start || !len)
- return -EINVAL;
-
- phyaddr = res->start;
- header = ioremap_cache(phyaddr, sizeof(*header));
- if (header == NULL)
- return -ENOMEM;
-
- ptr = ioremap_cache(phyaddr,
- header->header_bytes + header->table_bytes);
- iounmap(header);
- if (!ptr)
- return -ENOMEM;
-
- return coreboot_table_init(&pdev->dev, ptr);
-}
-
-static int coreboot_table_acpi_remove(struct platform_device *pdev)
-{
- return coreboot_table_exit();
-}
-
-static const struct acpi_device_id cros_coreboot_acpi_match[] = {
- { "GOOGCB00", 0 },
- { "BOOT0000", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(acpi, cros_coreboot_acpi_match);
-
-static struct platform_driver coreboot_table_acpi_driver = {
- .probe = coreboot_table_acpi_probe,
- .remove = coreboot_table_acpi_remove,
- .driver = {
- .name = "coreboot_table_acpi",
- .acpi_match_table = ACPI_PTR(cros_coreboot_acpi_match),
- },
-};
-
-static int __init coreboot_table_acpi_init(void)
-{
- return platform_driver_register(&coreboot_table_acpi_driver);
-}
-
-module_init(coreboot_table_acpi_init);
-
-MODULE_AUTHOR("Google, Inc.");
-MODULE_LICENSE("GPL");
diff --git a/drivers/firmware/google/coreboot_table-of.c b/drivers/firmware/google/coreboot_table-of.c
deleted file mode 100644
index f15bf404c579..000000000000
--- a/drivers/firmware/google/coreboot_table-of.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * coreboot_table-of.c
- *
- * Coreboot table access through open firmware.
- *
- * Copyright 2017 Google Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License v2.0 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/device.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/of_address.h>
-#include <linux/of_platform.h>
-#include <linux/platform_device.h>
-
-#include "coreboot_table.h"
-
-static int coreboot_table_of_probe(struct platform_device *pdev)
-{
- struct device_node *fw_dn = pdev->dev.of_node;
- void __iomem *ptr;
-
- ptr = of_iomap(fw_dn, 0);
- of_node_put(fw_dn);
- if (!ptr)
- return -ENOMEM;
-
- return coreboot_table_init(&pdev->dev, ptr);
-}
-
-static int coreboot_table_of_remove(struct platform_device *pdev)
-{
- return coreboot_table_exit();
-}
-
-static const struct of_device_id coreboot_of_match[] = {
- { .compatible = "coreboot" },
- {},
-};
-
-static struct platform_driver coreboot_table_of_driver = {
- .probe = coreboot_table_of_probe,
- .remove = coreboot_table_of_remove,
- .driver = {
- .name = "coreboot_table_of",
- .of_match_table = coreboot_of_match,
- },
-};
-
-static int __init platform_coreboot_table_of_init(void)
-{
- struct platform_device *pdev;
- struct device_node *of_node;
-
- /* Limit device creation to the presence of /firmware/coreboot node */
- of_node = of_find_node_by_path("/firmware/coreboot");
- if (!of_node)
- return -ENODEV;
-
- if (!of_match_node(coreboot_of_match, of_node))
- return -ENODEV;
-
- pdev = of_platform_device_create(of_node, "coreboot_table_of", NULL);
- if (!pdev)
- return -ENODEV;
-
- return platform_driver_register(&coreboot_table_of_driver);
-}
-
-module_init(platform_coreboot_table_of_init);
-
-MODULE_AUTHOR("Google, Inc.");
-MODULE_LICENSE("GPL");
diff --git a/drivers/firmware/google/coreboot_table.c b/drivers/firmware/google/coreboot_table.c
index 19db5709ae28..078d3bbe632f 100644
--- a/drivers/firmware/google/coreboot_table.c
+++ b/drivers/firmware/google/coreboot_table.c
@@ -16,12 +16,15 @@
* GNU General Public License for more details.
*/
+#include <linux/acpi.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
#include <linux/slab.h>
#include "coreboot_table.h"
@@ -29,8 +32,6 @@
#define CB_DEV(d) container_of(d, struct coreboot_device, dev)
#define CB_DRV(d) container_of(d, struct coreboot_driver, drv)
-static struct coreboot_table_header __iomem *ptr_header;
-
static int coreboot_bus_match(struct device *dev, struct device_driver *drv)
{
struct coreboot_device *device = CB_DEV(dev);
@@ -70,12 +71,6 @@ static struct bus_type coreboot_bus_type = {
.remove = coreboot_bus_remove,
};
-static int __init coreboot_bus_init(void)
-{
- return bus_register(&coreboot_bus_type);
-}
-module_init(coreboot_bus_init);
-
static void coreboot_device_release(struct device *dev)
{
struct coreboot_device *device = CB_DEV(dev);
@@ -97,62 +92,117 @@ void coreboot_driver_unregister(struct coreboot_driver *driver)
}
EXPORT_SYMBOL(coreboot_driver_unregister);
-int coreboot_table_init(struct device *dev, void __iomem *ptr)
+static int coreboot_table_populate(struct device *dev, void *ptr)
{
int i, ret;
void *ptr_entry;
struct coreboot_device *device;
- struct coreboot_table_entry entry;
- struct coreboot_table_header header;
-
- ptr_header = ptr;
- memcpy_fromio(&header, ptr_header, sizeof(header));
-
- if (strncmp(header.signature, "LBIO", sizeof(header.signature))) {
- pr_warn("coreboot_table: coreboot table missing or corrupt!\n");
- return -ENODEV;
- }
+ struct coreboot_table_entry *entry;
+ struct coreboot_table_header *header = ptr;
- ptr_entry = (void *)ptr_header + header.header_bytes;
- for (i = 0; i < header.table_entries; i++) {
- memcpy_fromio(&entry, ptr_entry, sizeof(entry));
+ ptr_entry = ptr + header->header_bytes;
+ for (i = 0; i < header->table_entries; i++) {
+ entry = ptr_entry;
- device = kzalloc(sizeof(struct device) + entry.size, GFP_KERNEL);
- if (!device) {
- ret = -ENOMEM;
- break;
- }
+ device = kzalloc(sizeof(struct device) + entry->size, GFP_KERNEL);
+ if (!device)
+ return -ENOMEM;
dev_set_name(&device->dev, "coreboot%d", i);
device->dev.parent = dev;
device->dev.bus = &coreboot_bus_type;
device->dev.release = coreboot_device_release;
- memcpy_fromio(&device->entry, ptr_entry, entry.size);
+ memcpy(&device->entry, ptr_entry, entry->size);
ret = device_register(&device->dev);
if (ret) {
put_device(&device->dev);
- break;
+ return ret;
}
- ptr_entry += entry.size;
+ ptr_entry += entry->size;
}
- return ret;
+ return 0;
}
-EXPORT_SYMBOL(coreboot_table_init);
-int coreboot_table_exit(void)
+static int coreboot_table_probe(struct platform_device *pdev)
{
- if (ptr_header) {
- bus_unregister(&coreboot_bus_type);
- iounmap(ptr_header);
- ptr_header = NULL;
+ resource_size_t len;
+ struct coreboot_table_header *header;
+ struct resource *res;
+ struct device *dev = &pdev->dev;
+ void *ptr;
+ int ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -EINVAL;
+
+ len = resource_size(res);
+ if (!res->start || !len)
+ return -EINVAL;
+
+ /* Check just the header first to make sure things are sane */
+ header = memremap(res->start, sizeof(*header), MEMREMAP_WB);
+ if (!header)
+ return -ENOMEM;
+
+ len = header->header_bytes + header->table_bytes;
+ ret = strncmp(header->signature, "LBIO", sizeof(header->signature));
+ memunmap(header);
+ if (ret) {
+ dev_warn(dev, "coreboot table missing or corrupt!\n");
+ return -ENODEV;
}
+ ptr = memremap(res->start, len, MEMREMAP_WB);
+ if (!ptr)
+ return -ENOMEM;
+
+ ret = bus_register(&coreboot_bus_type);
+ if (!ret) {
+ ret = coreboot_table_populate(dev, ptr);
+ if (ret)
+ bus_unregister(&coreboot_bus_type);
+ }
+ memunmap(ptr);
+
+ return ret;
+}
+
+static int coreboot_table_remove(struct platform_device *pdev)
+{
+ bus_unregister(&coreboot_bus_type);
return 0;
}
-EXPORT_SYMBOL(coreboot_table_exit);
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id cros_coreboot_acpi_match[] = {
+ { "GOOGCB00", 0 },
+ { "BOOT0000", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, cros_coreboot_acpi_match);
+#endif
+
+#ifdef CONFIG_OF
+static const struct of_device_id coreboot_of_match[] = {
+ { .compatible = "coreboot" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, coreboot_of_match);
+#endif
+
+static struct platform_driver coreboot_table_driver = {
+ .probe = coreboot_table_probe,
+ .remove = coreboot_table_remove,
+ .driver = {
+ .name = "coreboot_table",
+ .acpi_match_table = ACPI_PTR(cros_coreboot_acpi_match),
+ .of_match_table = of_match_ptr(coreboot_of_match),
+ },
+};
+module_platform_driver(coreboot_table_driver);
MODULE_AUTHOR("Google, Inc.");
MODULE_LICENSE("GPL");
diff --git a/drivers/firmware/google/coreboot_table.h b/drivers/firmware/google/coreboot_table.h
index 8ad95a94481b..71a9de6b15fa 100644
--- a/drivers/firmware/google/coreboot_table.h
+++ b/drivers/firmware/google/coreboot_table.h
@@ -91,10 +91,4 @@ int coreboot_driver_register(struct coreboot_driver *driver);
/* Unregister a driver that uses the data from a coreboot table. */
void coreboot_driver_unregister(struct coreboot_driver *driver);
-/* Initialize coreboot table module given a pointer to iomem */
-int coreboot_table_init(struct device *dev, void __iomem *ptr);
-
-/* Cleanup coreboot table module */
-int coreboot_table_exit(void);
-
#endif /* __COREBOOT_TABLE_H */
diff --git a/drivers/firmware/google/gsmi.c b/drivers/firmware/google/gsmi.c
index c8f169bf2e27..82ce1e6d261e 100644
--- a/drivers/firmware/google/gsmi.c
+++ b/drivers/firmware/google/gsmi.c
@@ -29,6 +29,7 @@
#include <linux/efi.h>
#include <linux/module.h>
#include <linux/ucs2_string.h>
+#include <linux/suspend.h>
#define GSMI_SHUTDOWN_CLEAN 0 /* Clean Shutdown */
/* TODO(mikew@google.com): Tie in HARDLOCKUP_DETECTOR with NMIWDT */
@@ -70,6 +71,8 @@
#define GSMI_CMD_SET_NVRAM_VAR 0x03
#define GSMI_CMD_SET_EVENT_LOG 0x08
#define GSMI_CMD_CLEAR_EVENT_LOG 0x09
+#define GSMI_CMD_LOG_S0IX_SUSPEND 0x0a
+#define GSMI_CMD_LOG_S0IX_RESUME 0x0b
#define GSMI_CMD_CLEAR_CONFIG 0x20
#define GSMI_CMD_HANDSHAKE_TYPE 0xC1
@@ -84,7 +87,7 @@ struct gsmi_buf {
u32 address; /* physical address of buffer */
};
-struct gsmi_device {
+static struct gsmi_device {
struct platform_device *pdev; /* platform device */
struct gsmi_buf *name_buf; /* variable name buffer */
struct gsmi_buf *data_buf; /* generic data buffer */
@@ -122,7 +125,6 @@ struct gsmi_log_entry_type_1 {
u32 instance;
} __packed;
-
/*
* Some platforms don't have explicit SMI handshake
* and need to wait for SMI to complete.
@@ -133,6 +135,15 @@ module_param(spincount, uint, 0600);
MODULE_PARM_DESC(spincount,
"The number of loop iterations to use when using the spin handshake.");
+/*
+ * Platforms might not support S0ix logging in their GSMI handlers. In order to
+ * avoid any side-effects of generating an SMI for S0ix logging, use the S0ix
+ * related GSMI commands only for those platforms that explicitly enable this
+ * option.
+ */
+static bool s0ix_logging_enable;
+module_param(s0ix_logging_enable, bool, 0600);
+
static struct gsmi_buf *gsmi_buf_alloc(void)
{
struct gsmi_buf *smibuf;
@@ -289,6 +300,10 @@ static int gsmi_exec(u8 func, u8 sub)
return rc;
}
+#ifdef CONFIG_EFI_VARS
+
+static struct efivars efivars;
+
static efi_status_t gsmi_get_variable(efi_char16_t *name,
efi_guid_t *vendor, u32 *attr,
unsigned long *data_size,
@@ -466,6 +481,8 @@ static const struct efivar_operations efivar_ops = {
.get_next_variable = gsmi_get_next_variable,
};
+#endif /* CONFIG_EFI_VARS */
+
static ssize_t eventlog_write(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t pos, size_t count)
@@ -480,11 +497,10 @@ static ssize_t eventlog_write(struct file *filp, struct kobject *kobj,
if (count < sizeof(u32))
return -EINVAL;
param.type = *(u32 *)buf;
- count -= sizeof(u32);
buf += sizeof(u32);
/* The remaining buffer is the data payload */
- if (count > gsmi_dev.data_buf->length)
+ if ((count - sizeof(u32)) > gsmi_dev.data_buf->length)
return -EINVAL;
param.data_len = count - sizeof(u32);
@@ -504,7 +520,7 @@ static ssize_t eventlog_write(struct file *filp, struct kobject *kobj,
spin_unlock_irqrestore(&gsmi_dev.lock, flags);
- return rc;
+ return (rc == 0) ? count : rc;
}
@@ -716,6 +732,12 @@ static const struct dmi_system_id gsmi_dmi_table[] __initconst = {
DMI_MATCH(DMI_BOARD_VENDOR, "Google, Inc."),
},
},
+ {
+ .ident = "Coreboot Firmware",
+ .matches = {
+ DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"),
+ },
+ },
{}
};
MODULE_DEVICE_TABLE(dmi, gsmi_dmi_table);
@@ -762,7 +784,6 @@ static __init int gsmi_system_valid(void)
}
static struct kobject *gsmi_kobj;
-static struct efivars efivars;
static const struct platform_device_info gsmi_dev_info = {
.name = "gsmi",
@@ -771,6 +792,78 @@ static const struct platform_device_info gsmi_dev_info = {
.dma_mask = DMA_BIT_MASK(32),
};
+#ifdef CONFIG_PM
+static void gsmi_log_s0ix_info(u8 cmd)
+{
+ unsigned long flags;
+
+ /*
+ * If platform has not enabled S0ix logging, then no action is
+ * necessary.
+ */
+ if (!s0ix_logging_enable)
+ return;
+
+ spin_lock_irqsave(&gsmi_dev.lock, flags);
+
+ memset(gsmi_dev.param_buf->start, 0, gsmi_dev.param_buf->length);
+
+ gsmi_exec(GSMI_CALLBACK, cmd);
+
+ spin_unlock_irqrestore(&gsmi_dev.lock, flags);
+}
+
+static int gsmi_log_s0ix_suspend(struct device *dev)
+{
+ /*
+ * If system is not suspending via firmware using the standard ACPI Sx
+ * types, then make a GSMI call to log the suspend info.
+ */
+ if (!pm_suspend_via_firmware())
+ gsmi_log_s0ix_info(GSMI_CMD_LOG_S0IX_SUSPEND);
+
+ /*
+ * Always return success, since we do not want suspend
+ * to fail just because of logging failure.
+ */
+ return 0;
+}
+
+static int gsmi_log_s0ix_resume(struct device *dev)
+{
+ /*
+ * If system did not resume via firmware, then make a GSMI call to log
+ * the resume info and wake source.
+ */
+ if (!pm_resume_via_firmware())
+ gsmi_log_s0ix_info(GSMI_CMD_LOG_S0IX_RESUME);
+
+ /*
+ * Always return success, since we do not want resume
+ * to fail just because of logging failure.
+ */
+ return 0;
+}
+
+static const struct dev_pm_ops gsmi_pm_ops = {
+ .suspend_noirq = gsmi_log_s0ix_suspend,
+ .resume_noirq = gsmi_log_s0ix_resume,
+};
+
+static int gsmi_platform_driver_probe(struct platform_device *dev)
+{
+ return 0;
+}
+
+static struct platform_driver gsmi_driver_info = {
+ .driver = {
+ .name = "gsmi",
+ .pm = &gsmi_pm_ops,
+ },
+ .probe = gsmi_platform_driver_probe,
+};
+#endif
+
static __init int gsmi_init(void)
{
unsigned long flags;
@@ -782,6 +875,14 @@ static __init int gsmi_init(void)
gsmi_dev.smi_cmd = acpi_gbl_FADT.smi_command;
+#ifdef CONFIG_PM
+ ret = platform_driver_register(&gsmi_driver_info);
+ if (unlikely(ret)) {
+ printk(KERN_ERR "gsmi: unable to register platform driver\n");
+ return ret;
+ }
+#endif
+
/* register device */
gsmi_dev.pdev = platform_device_register_full(&gsmi_dev_info);
if (IS_ERR(gsmi_dev.pdev)) {
@@ -886,11 +987,14 @@ static __init int gsmi_init(void)
goto out_remove_bin_file;
}
+#ifdef CONFIG_EFI_VARS
ret = efivars_register(&efivars, &efivar_ops, gsmi_kobj);
if (ret) {
printk(KERN_INFO "gsmi: Failed to register efivars\n");
- goto out_remove_sysfs_files;
+ sysfs_remove_files(gsmi_kobj, gsmi_attrs);
+ goto out_remove_bin_file;
}
+#endif
register_reboot_notifier(&gsmi_reboot_notifier);
register_die_notifier(&gsmi_die_notifier);
@@ -901,8 +1005,6 @@ static __init int gsmi_init(void)
return 0;
-out_remove_sysfs_files:
- sysfs_remove_files(gsmi_kobj, gsmi_attrs);
out_remove_bin_file:
sysfs_remove_bin_file(gsmi_kobj, &eventlog_bin_attr);
out_err:
@@ -922,7 +1024,9 @@ static void __exit gsmi_exit(void)
unregister_die_notifier(&gsmi_die_notifier);
atomic_notifier_chain_unregister(&panic_notifier_list,
&gsmi_panic_notifier);
+#ifdef CONFIG_EFI_VARS
efivars_unregister(&efivars);
+#endif
sysfs_remove_files(gsmi_kobj, gsmi_attrs);
sysfs_remove_bin_file(gsmi_kobj, &eventlog_bin_attr);
diff --git a/drivers/firmware/google/vpd.c b/drivers/firmware/google/vpd.c
index 1aa67bb5d8c0..c0c0b4e4e281 100644
--- a/drivers/firmware/google/vpd.c
+++ b/drivers/firmware/google/vpd.c
@@ -198,7 +198,7 @@ static int vpd_section_init(const char *name, struct vpd_section *sec,
sec->name = name;
- /* We want to export the raw partion with name ${name}_raw */
+ /* We want to export the raw partition with name ${name}_raw */
sec->raw_name = kasprintf(GFP_KERNEL, "%s_raw", name);
if (!sec->raw_name) {
err = -ENOMEM;
diff --git a/drivers/firmware/imx/Kconfig b/drivers/firmware/imx/Kconfig
new file mode 100644
index 000000000000..b170c2851e48
--- /dev/null
+++ b/drivers/firmware/imx/Kconfig
@@ -0,0 +1,11 @@
+config IMX_SCU
+ bool "IMX SCU Protocol driver"
+ depends on IMX_MBOX
+ help
+ The System Controller Firmware (SCFW) is a low-level system function
+ which runs on a dedicated Cortex-M core to provide power, clock, and
+ resource management. It exists on some i.MX8 processors. e.g. i.MX8QM
+ (QM, QP), and i.MX8QX (QXP, DX).
+
+ This driver manages the IPC interface between host CPU and the
+ SCU firmware running on M4.
diff --git a/drivers/firmware/imx/Makefile b/drivers/firmware/imx/Makefile
new file mode 100644
index 000000000000..0ac04dfda8d4
--- /dev/null
+++ b/drivers/firmware/imx/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_IMX_SCU) += imx-scu.o misc.o
diff --git a/drivers/firmware/imx/imx-scu.c b/drivers/firmware/imx/imx-scu.c
new file mode 100644
index 000000000000..2bb1a19c413f
--- /dev/null
+++ b/drivers/firmware/imx/imx-scu.c
@@ -0,0 +1,270 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 NXP
+ * Author: Dong Aisheng <aisheng.dong@nxp.com>
+ *
+ * Implementation of the SCU IPC functions using MUs (client side).
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/firmware/imx/types.h>
+#include <linux/firmware/imx/ipc.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/mailbox_client.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+
+#define SCU_MU_CHAN_NUM 8
+#define MAX_RX_TIMEOUT (msecs_to_jiffies(30))
+
+struct imx_sc_chan {
+ struct imx_sc_ipc *sc_ipc;
+
+ struct mbox_client cl;
+ struct mbox_chan *ch;
+ int idx;
+};
+
+struct imx_sc_ipc {
+ /* SCU uses 4 Tx and 4 Rx channels */
+ struct imx_sc_chan chans[SCU_MU_CHAN_NUM];
+ struct device *dev;
+ struct mutex lock;
+ struct completion done;
+
+ /* temporarily store the SCU msg */
+ u32 *msg;
+ u8 rx_size;
+ u8 count;
+};
+
+/*
+ * This type is used to indicate error response for most functions.
+ */
+enum imx_sc_error_codes {
+ IMX_SC_ERR_NONE = 0, /* Success */
+ IMX_SC_ERR_VERSION = 1, /* Incompatible API version */
+ IMX_SC_ERR_CONFIG = 2, /* Configuration error */
+ IMX_SC_ERR_PARM = 3, /* Bad parameter */
+ IMX_SC_ERR_NOACCESS = 4, /* Permission error (no access) */
+ IMX_SC_ERR_LOCKED = 5, /* Permission error (locked) */
+ IMX_SC_ERR_UNAVAILABLE = 6, /* Unavailable (out of resources) */
+ IMX_SC_ERR_NOTFOUND = 7, /* Not found */
+ IMX_SC_ERR_NOPOWER = 8, /* No power */
+ IMX_SC_ERR_IPC = 9, /* Generic IPC error */
+ IMX_SC_ERR_BUSY = 10, /* Resource is currently busy/active */
+ IMX_SC_ERR_FAIL = 11, /* General I/O failure */
+ IMX_SC_ERR_LAST
+};
+
+static int imx_sc_linux_errmap[IMX_SC_ERR_LAST] = {
+ 0, /* IMX_SC_ERR_NONE */
+ -EINVAL, /* IMX_SC_ERR_VERSION */
+ -EINVAL, /* IMX_SC_ERR_CONFIG */
+ -EINVAL, /* IMX_SC_ERR_PARM */
+ -EACCES, /* IMX_SC_ERR_NOACCESS */
+ -EACCES, /* IMX_SC_ERR_LOCKED */
+ -ERANGE, /* IMX_SC_ERR_UNAVAILABLE */
+ -EEXIST, /* IMX_SC_ERR_NOTFOUND */
+ -EPERM, /* IMX_SC_ERR_NOPOWER */
+ -EPIPE, /* IMX_SC_ERR_IPC */
+ -EBUSY, /* IMX_SC_ERR_BUSY */
+ -EIO, /* IMX_SC_ERR_FAIL */
+};
+
+static struct imx_sc_ipc *imx_sc_ipc_handle;
+
+static inline int imx_sc_to_linux_errno(int errno)
+{
+ if (errno >= IMX_SC_ERR_NONE && errno < IMX_SC_ERR_LAST)
+ return imx_sc_linux_errmap[errno];
+ return -EIO;
+}
+
+/*
+ * Get the default handle used by SCU
+ */
+int imx_scu_get_handle(struct imx_sc_ipc **ipc)
+{
+ if (!imx_sc_ipc_handle)
+ return -EPROBE_DEFER;
+
+ *ipc = imx_sc_ipc_handle;
+ return 0;
+}
+EXPORT_SYMBOL(imx_scu_get_handle);
+
+static void imx_scu_rx_callback(struct mbox_client *c, void *msg)
+{
+ struct imx_sc_chan *sc_chan = container_of(c, struct imx_sc_chan, cl);
+ struct imx_sc_ipc *sc_ipc = sc_chan->sc_ipc;
+ struct imx_sc_rpc_msg *hdr;
+ u32 *data = msg;
+
+ if (sc_chan->idx == 0) {
+ hdr = msg;
+ sc_ipc->rx_size = hdr->size;
+ dev_dbg(sc_ipc->dev, "msg rx size %u\n", sc_ipc->rx_size);
+ if (sc_ipc->rx_size > 4)
+ dev_warn(sc_ipc->dev, "RPC does not support receiving over 4 words: %u\n",
+ sc_ipc->rx_size);
+ }
+
+ sc_ipc->msg[sc_chan->idx] = *data;
+ sc_ipc->count++;
+
+ dev_dbg(sc_ipc->dev, "mu %u msg %u 0x%x\n", sc_chan->idx,
+ sc_ipc->count, *data);
+
+ if ((sc_ipc->rx_size != 0) && (sc_ipc->count == sc_ipc->rx_size))
+ complete(&sc_ipc->done);
+}
+
+static int imx_scu_ipc_write(struct imx_sc_ipc *sc_ipc, void *msg)
+{
+ struct imx_sc_rpc_msg *hdr = msg;
+ struct imx_sc_chan *sc_chan;
+ u32 *data = msg;
+ int ret;
+ int i;
+
+ /* Check size */
+ if (hdr->size > IMX_SC_RPC_MAX_MSG)
+ return -EINVAL;
+
+ dev_dbg(sc_ipc->dev, "RPC SVC %u FUNC %u SIZE %u\n", hdr->svc,
+ hdr->func, hdr->size);
+
+ for (i = 0; i < hdr->size; i++) {
+ sc_chan = &sc_ipc->chans[i % 4];
+ ret = mbox_send_message(sc_chan->ch, &data[i]);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+/*
+ * RPC command/response
+ */
+int imx_scu_call_rpc(struct imx_sc_ipc *sc_ipc, void *msg, bool have_resp)
+{
+ struct imx_sc_rpc_msg *hdr;
+ int ret;
+
+ if (WARN_ON(!sc_ipc || !msg))
+ return -EINVAL;
+
+ mutex_lock(&sc_ipc->lock);
+ reinit_completion(&sc_ipc->done);
+
+ sc_ipc->msg = msg;
+ sc_ipc->count = 0;
+ ret = imx_scu_ipc_write(sc_ipc, msg);
+ if (ret < 0) {
+ dev_err(sc_ipc->dev, "RPC send msg failed: %d\n", ret);
+ goto out;
+ }
+
+ if (have_resp) {
+ if (!wait_for_completion_timeout(&sc_ipc->done,
+ MAX_RX_TIMEOUT)) {
+ dev_err(sc_ipc->dev, "RPC send msg timeout\n");
+ mutex_unlock(&sc_ipc->lock);
+ return -ETIMEDOUT;
+ }
+
+ /* response status is stored in hdr->func field */
+ hdr = msg;
+ ret = hdr->func;
+ }
+
+out:
+ mutex_unlock(&sc_ipc->lock);
+
+ dev_dbg(sc_ipc->dev, "RPC SVC done\n");
+
+ return imx_sc_to_linux_errno(ret);
+}
+EXPORT_SYMBOL(imx_scu_call_rpc);
+
+static int imx_scu_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct imx_sc_ipc *sc_ipc;
+ struct imx_sc_chan *sc_chan;
+ struct mbox_client *cl;
+ char *chan_name;
+ int ret;
+ int i;
+
+ sc_ipc = devm_kzalloc(dev, sizeof(*sc_ipc), GFP_KERNEL);
+ if (!sc_ipc)
+ return -ENOMEM;
+
+ for (i = 0; i < SCU_MU_CHAN_NUM; i++) {
+ if (i < 4)
+ chan_name = kasprintf(GFP_KERNEL, "tx%d", i);
+ else
+ chan_name = kasprintf(GFP_KERNEL, "rx%d", i - 4);
+
+ if (!chan_name)
+ return -ENOMEM;
+
+ sc_chan = &sc_ipc->chans[i];
+ cl = &sc_chan->cl;
+ cl->dev = dev;
+ cl->tx_block = false;
+ cl->knows_txdone = true;
+ cl->rx_callback = imx_scu_rx_callback;
+
+ sc_chan->sc_ipc = sc_ipc;
+ sc_chan->idx = i % 4;
+ sc_chan->ch = mbox_request_channel_byname(cl, chan_name);
+ if (IS_ERR(sc_chan->ch)) {
+ ret = PTR_ERR(sc_chan->ch);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Failed to request mbox chan %s ret %d\n",
+ chan_name, ret);
+ return ret;
+ }
+
+ dev_dbg(dev, "request mbox chan %s\n", chan_name);
+ /* chan_name is not used anymore by framework */
+ kfree(chan_name);
+ }
+
+ sc_ipc->dev = dev;
+ mutex_init(&sc_ipc->lock);
+ init_completion(&sc_ipc->done);
+
+ imx_sc_ipc_handle = sc_ipc;
+
+ dev_info(dev, "NXP i.MX SCU Initialized\n");
+
+ return devm_of_platform_populate(dev);
+}
+
+static const struct of_device_id imx_scu_match[] = {
+ { .compatible = "fsl,imx-scu", },
+ { /* Sentinel */ }
+};
+
+static struct platform_driver imx_scu_driver = {
+ .driver = {
+ .name = "imx-scu",
+ .of_match_table = imx_scu_match,
+ },
+ .probe = imx_scu_probe,
+};
+builtin_platform_driver(imx_scu_driver);
+
+MODULE_AUTHOR("Dong Aisheng <aisheng.dong@nxp.com>");
+MODULE_DESCRIPTION("IMX SCU firmware protocol driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/firmware/imx/misc.c b/drivers/firmware/imx/misc.c
new file mode 100644
index 000000000000..97f5424dbac9
--- /dev/null
+++ b/drivers/firmware/imx/misc.c
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017~2018 NXP
+ * Author: Dong Aisheng <aisheng.dong@nxp.com>
+ *
+ * File containing client-side RPC functions for the MISC service. These
+ * function are ported to clients that communicate to the SC.
+ *
+ */
+
+#include <linux/firmware/imx/svc/misc.h>
+
+struct imx_sc_msg_req_misc_set_ctrl {
+ struct imx_sc_rpc_msg hdr;
+ u32 ctrl;
+ u32 val;
+ u16 resource;
+} __packed;
+
+struct imx_sc_msg_req_misc_get_ctrl {
+ struct imx_sc_rpc_msg hdr;
+ u32 ctrl;
+ u16 resource;
+} __packed;
+
+struct imx_sc_msg_resp_misc_get_ctrl {
+ struct imx_sc_rpc_msg hdr;
+ u32 val;
+} __packed;
+
+/*
+ * This function sets a miscellaneous control value.
+ *
+ * @param[in] ipc IPC handle
+ * @param[in] resource resource the control is associated with
+ * @param[in] ctrl control to change
+ * @param[in] val value to apply to the control
+ *
+ * @return Returns 0 for success and < 0 for errors.
+ */
+
+int imx_sc_misc_set_control(struct imx_sc_ipc *ipc, u32 resource,
+ u8 ctrl, u32 val)
+{
+ struct imx_sc_msg_req_misc_set_ctrl msg;
+ struct imx_sc_rpc_msg *hdr = &msg.hdr;
+
+ hdr->ver = IMX_SC_RPC_VERSION;
+ hdr->svc = (uint8_t)IMX_SC_RPC_SVC_MISC;
+ hdr->func = (uint8_t)IMX_SC_MISC_FUNC_SET_CONTROL;
+ hdr->size = 4;
+
+ msg.ctrl = ctrl;
+ msg.val = val;
+ msg.resource = resource;
+
+ return imx_scu_call_rpc(ipc, &msg, true);
+}
+EXPORT_SYMBOL(imx_sc_misc_set_control);
+
+/*
+ * This function gets a miscellaneous control value.
+ *
+ * @param[in] ipc IPC handle
+ * @param[in] resource resource the control is associated with
+ * @param[in] ctrl control to get
+ * @param[out] val pointer to return the control value
+ *
+ * @return Returns 0 for success and < 0 for errors.
+ */
+
+int imx_sc_misc_get_control(struct imx_sc_ipc *ipc, u32 resource,
+ u8 ctrl, u32 *val)
+{
+ struct imx_sc_msg_req_misc_get_ctrl msg;
+ struct imx_sc_msg_resp_misc_get_ctrl *resp;
+ struct imx_sc_rpc_msg *hdr = &msg.hdr;
+ int ret;
+
+ hdr->ver = IMX_SC_RPC_VERSION;
+ hdr->svc = (uint8_t)IMX_SC_RPC_SVC_MISC;
+ hdr->func = (uint8_t)IMX_SC_MISC_FUNC_GET_CONTROL;
+ hdr->size = 3;
+
+ msg.ctrl = ctrl;
+ msg.resource = resource;
+
+ ret = imx_scu_call_rpc(ipc, &msg, true);
+ if (ret)
+ return ret;
+
+ resp = (struct imx_sc_msg_resp_misc_get_ctrl *)&msg;
+ if (val != NULL)
+ *val = resp->val;
+
+ return 0;
+}
+EXPORT_SYMBOL(imx_sc_misc_get_control);
diff --git a/drivers/firmware/iscsi_ibft_find.c b/drivers/firmware/iscsi_ibft_find.c
index 2224f1dc074b..72d9ea18270b 100644
--- a/drivers/firmware/iscsi_ibft_find.c
+++ b/drivers/firmware/iscsi_ibft_find.c
@@ -18,7 +18,7 @@
* GNU General Public License for more details.
*/
-#include <linux/bootmem.h>
+#include <linux/memblock.h>
#include <linux/blkdev.h>
#include <linux/ctype.h>
#include <linux/device.h>
diff --git a/drivers/firmware/memmap.c b/drivers/firmware/memmap.c
index 5de3ed29282c..d168c87c7d30 100644
--- a/drivers/firmware/memmap.c
+++ b/drivers/firmware/memmap.c
@@ -19,7 +19,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
-#include <linux/bootmem.h>
+#include <linux/memblock.h>
#include <linux/slab.h>
#include <linux/mm.h>
@@ -333,7 +333,8 @@ int __init firmware_map_add_early(u64 start, u64 end, const char *type)
{
struct firmware_map_entry *entry;
- entry = memblock_virt_alloc(sizeof(struct firmware_map_entry), 0);
+ entry = memblock_alloc(sizeof(struct firmware_map_entry),
+ SMP_CACHE_BYTES);
if (WARN_ON(!entry))
return -ENOMEM;
diff --git a/drivers/firmware/meson/meson_sm.c b/drivers/firmware/meson/meson_sm.c
index 0ec2ca87318c..29fbc818a573 100644
--- a/drivers/firmware/meson/meson_sm.c
+++ b/drivers/firmware/meson/meson_sm.c
@@ -24,6 +24,7 @@
#include <linux/printk.h>
#include <linux/types.h>
#include <linux/sizes.h>
+ #include <linux/slab.h>
#include <linux/firmware/meson/meson_sm.h>
@@ -48,6 +49,7 @@ struct meson_sm_chip gxbb_chip = {
CMD(SM_EFUSE_READ, 0x82000030),
CMD(SM_EFUSE_WRITE, 0x82000031),
CMD(SM_EFUSE_USER_MAX, 0x82000033),
+ CMD(SM_GET_CHIP_ID, 0x82000044),
{ /* sentinel */ },
},
};
@@ -214,6 +216,57 @@ int meson_sm_call_write(void *buffer, unsigned int size, unsigned int cmd_index,
}
EXPORT_SYMBOL(meson_sm_call_write);
+#define SM_CHIP_ID_LENGTH 119
+#define SM_CHIP_ID_OFFSET 4
+#define SM_CHIP_ID_SIZE 12
+
+static ssize_t serial_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ uint8_t *id_buf;
+ int ret;
+
+ id_buf = kmalloc(SM_CHIP_ID_LENGTH, GFP_KERNEL);
+ if (!id_buf)
+ return -ENOMEM;
+
+ ret = meson_sm_call_read(id_buf, SM_CHIP_ID_LENGTH, SM_GET_CHIP_ID,
+ 0, 0, 0, 0, 0);
+ if (ret < 0) {
+ kfree(id_buf);
+ return ret;
+ }
+
+ ret = sprintf(buf, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ id_buf[SM_CHIP_ID_OFFSET + 0],
+ id_buf[SM_CHIP_ID_OFFSET + 1],
+ id_buf[SM_CHIP_ID_OFFSET + 2],
+ id_buf[SM_CHIP_ID_OFFSET + 3],
+ id_buf[SM_CHIP_ID_OFFSET + 4],
+ id_buf[SM_CHIP_ID_OFFSET + 5],
+ id_buf[SM_CHIP_ID_OFFSET + 6],
+ id_buf[SM_CHIP_ID_OFFSET + 7],
+ id_buf[SM_CHIP_ID_OFFSET + 8],
+ id_buf[SM_CHIP_ID_OFFSET + 9],
+ id_buf[SM_CHIP_ID_OFFSET + 10],
+ id_buf[SM_CHIP_ID_OFFSET + 11]);
+
+ kfree(id_buf);
+
+ return ret;
+}
+
+static DEVICE_ATTR_RO(serial);
+
+static struct attribute *meson_sm_sysfs_attributes[] = {
+ &dev_attr_serial.attr,
+ NULL,
+};
+
+static const struct attribute_group meson_sm_sysfs_attr_group = {
+ .attrs = meson_sm_sysfs_attributes,
+};
+
static const struct of_device_id meson_sm_ids[] = {
{ .compatible = "amlogic,meson-gxbb-sm", .data = &gxbb_chip },
{ /* sentinel */ },
@@ -242,6 +295,9 @@ static int __init meson_sm_probe(struct platform_device *pdev)
fw.chip = chip;
pr_info("secure-monitor enabled\n");
+ if (sysfs_create_group(&pdev->dev.kobj, &meson_sm_sysfs_attr_group))
+ goto out_in_base;
+
return 0;
out_in_base:
diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c
index e778af766fae..af4eee86919d 100644
--- a/drivers/firmware/qcom_scm.c
+++ b/drivers/firmware/qcom_scm.c
@@ -525,34 +525,44 @@ static int qcom_scm_probe(struct platform_device *pdev)
return ret;
clks = (unsigned long)of_device_get_match_data(&pdev->dev);
- if (clks & SCM_HAS_CORE_CLK) {
- scm->core_clk = devm_clk_get(&pdev->dev, "core");
- if (IS_ERR(scm->core_clk)) {
- if (PTR_ERR(scm->core_clk) != -EPROBE_DEFER)
- dev_err(&pdev->dev,
- "failed to acquire core clk\n");
+
+ scm->core_clk = devm_clk_get(&pdev->dev, "core");
+ if (IS_ERR(scm->core_clk)) {
+ if (PTR_ERR(scm->core_clk) == -EPROBE_DEFER)
+ return PTR_ERR(scm->core_clk);
+
+ if (clks & SCM_HAS_CORE_CLK) {
+ dev_err(&pdev->dev, "failed to acquire core clk\n");
return PTR_ERR(scm->core_clk);
}
+
+ scm->core_clk = NULL;
}
- if (clks & SCM_HAS_IFACE_CLK) {
- scm->iface_clk = devm_clk_get(&pdev->dev, "iface");
- if (IS_ERR(scm->iface_clk)) {
- if (PTR_ERR(scm->iface_clk) != -EPROBE_DEFER)
- dev_err(&pdev->dev,
- "failed to acquire iface clk\n");
+ scm->iface_clk = devm_clk_get(&pdev->dev, "iface");
+ if (IS_ERR(scm->iface_clk)) {
+ if (PTR_ERR(scm->iface_clk) == -EPROBE_DEFER)
+ return PTR_ERR(scm->iface_clk);
+
+ if (clks & SCM_HAS_IFACE_CLK) {
+ dev_err(&pdev->dev, "failed to acquire iface clk\n");
return PTR_ERR(scm->iface_clk);
}
+
+ scm->iface_clk = NULL;
}
- if (clks & SCM_HAS_BUS_CLK) {
- scm->bus_clk = devm_clk_get(&pdev->dev, "bus");
- if (IS_ERR(scm->bus_clk)) {
- if (PTR_ERR(scm->bus_clk) != -EPROBE_DEFER)
- dev_err(&pdev->dev,
- "failed to acquire bus clk\n");
+ scm->bus_clk = devm_clk_get(&pdev->dev, "bus");
+ if (IS_ERR(scm->bus_clk)) {
+ if (PTR_ERR(scm->bus_clk) == -EPROBE_DEFER)
+ return PTR_ERR(scm->bus_clk);
+
+ if (clks & SCM_HAS_BUS_CLK) {
+ dev_err(&pdev->dev, "failed to acquire bus clk\n");
return PTR_ERR(scm->bus_clk);
}
+
+ scm->bus_clk = NULL;
}
scm->reset.ops = &qcom_scm_pas_reset_ops;
@@ -594,23 +604,23 @@ static const struct of_device_id qcom_scm_dt_match[] = {
{ .compatible = "qcom,scm-apq8064",
/* FIXME: This should have .data = (void *) SCM_HAS_CORE_CLK */
},
- { .compatible = "qcom,scm-msm8660",
- .data = (void *) SCM_HAS_CORE_CLK,
- },
- { .compatible = "qcom,scm-msm8960",
- .data = (void *) SCM_HAS_CORE_CLK,
- },
- { .compatible = "qcom,scm-msm8996",
- .data = NULL, /* no clocks */
+ { .compatible = "qcom,scm-apq8084", .data = (void *)(SCM_HAS_CORE_CLK |
+ SCM_HAS_IFACE_CLK |
+ SCM_HAS_BUS_CLK)
},
- { .compatible = "qcom,scm-ipq4019",
- .data = NULL, /* no clocks */
+ { .compatible = "qcom,scm-ipq4019" },
+ { .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 |
+ SCM_HAS_IFACE_CLK |
+ SCM_HAS_BUS_CLK)
},
- { .compatible = "qcom,scm",
- .data = (void *)(SCM_HAS_CORE_CLK
- | SCM_HAS_IFACE_CLK
- | SCM_HAS_BUS_CLK),
+ { .compatible = "qcom,scm-msm8974", .data = (void *)(SCM_HAS_CORE_CLK |
+ SCM_HAS_IFACE_CLK |
+ SCM_HAS_BUS_CLK)
},
+ { .compatible = "qcom,scm-msm8996" },
+ { .compatible = "qcom,scm" },
{}
};
diff --git a/drivers/firmware/scpi_pm_domain.c b/drivers/firmware/scpi_pm_domain.c
index f395dec27113..390aa13391e4 100644
--- a/drivers/firmware/scpi_pm_domain.c
+++ b/drivers/firmware/scpi_pm_domain.c
@@ -121,7 +121,7 @@ static int scpi_pm_domain_probe(struct platform_device *pdev)
scpi_pd->domain = i;
scpi_pd->ops = scpi_ops;
- sprintf(scpi_pd->name, "%s.%d", np->name, i);
+ sprintf(scpi_pd->name, "%pOFn.%d", np, i);
scpi_pd->genpd.name = scpi_pd->name;
scpi_pd->genpd.power_off = scpi_pd_power_off;
scpi_pd->genpd.power_on = scpi_pd_power_on;
diff --git a/drivers/firmware/tegra/bpmp.c b/drivers/firmware/tegra/bpmp.c
index 14a456afa379..a3d5b518c10e 100644
--- a/drivers/firmware/tegra/bpmp.c
+++ b/drivers/firmware/tegra/bpmp.c
@@ -18,6 +18,7 @@
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
+#include <linux/pm.h>
#include <linux/semaphore.h>
#include <linux/sched/clock.h>
@@ -843,6 +844,23 @@ free_tx:
return err;
}
+static int __maybe_unused tegra_bpmp_resume(struct device *dev)
+{
+ struct tegra_bpmp *bpmp = dev_get_drvdata(dev);
+ unsigned int i;
+
+ /* reset message channels */
+ tegra_bpmp_channel_reset(bpmp->tx_channel);
+ tegra_bpmp_channel_reset(bpmp->rx_channel);
+
+ for (i = 0; i < bpmp->threaded.count; i++)
+ tegra_bpmp_channel_reset(&bpmp->threaded_channels[i]);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(tegra_bpmp_pm_ops, NULL, tegra_bpmp_resume);
+
static const struct tegra_bpmp_soc tegra186_soc = {
.channels = {
.cpu_tx = {
@@ -871,6 +889,7 @@ static struct platform_driver tegra_bpmp_driver = {
.driver = {
.name = "tegra-bpmp",
.of_match_table = tegra_bpmp_match,
+ .pm = &tegra_bpmp_pm_ops,
},
.probe = tegra_bpmp_probe,
};
diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
index 7fa744793bc5..69ed1464175c 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -66,14 +66,14 @@ struct ti_sci_xfers_info {
/**
* struct ti_sci_desc - Description of SoC integration
- * @host_id: Host identifier representing the compute entity
+ * @default_host_id: Host identifier representing the compute entity
* @max_rx_timeout_ms: Timeout for communication with SoC (in Milliseconds)
* @max_msgs: Maximum number of messages that can be pending
* simultaneously in the system
* @max_msg_size: Maximum size of data per message that can be handled.
*/
struct ti_sci_desc {
- u8 host_id;
+ u8 default_host_id;
int max_rx_timeout_ms;
int max_msgs;
int max_msg_size;
@@ -94,6 +94,7 @@ struct ti_sci_desc {
* @chan_rx: Receive mailbox channel
* @minfo: Message info
* @node: list head
+ * @host_id: Host ID
* @users: Number of users of this instance
*/
struct ti_sci_info {
@@ -110,6 +111,7 @@ struct ti_sci_info {
struct mbox_chan *chan_rx;
struct ti_sci_xfers_info minfo;
struct list_head node;
+ u8 host_id;
/* protected by ti_sci_list_mutex */
int users;
@@ -370,7 +372,7 @@ static struct ti_sci_xfer *ti_sci_get_one_xfer(struct ti_sci_info *info,
hdr->seq = xfer_id;
hdr->type = msg_type;
- hdr->host = info->desc->host_id;
+ hdr->host = info->host_id;
hdr->flags = msg_flags;
return xfer;
@@ -1793,7 +1795,7 @@ static int tisci_reboot_handler(struct notifier_block *nb, unsigned long mode,
/* Description for K2G */
static const struct ti_sci_desc ti_sci_pmmc_k2g_desc = {
- .host_id = 2,
+ .default_host_id = 2,
/* Conservative duration */
.max_rx_timeout_ms = 1000,
/* Limited by MBOX_TX_QUEUE_LEN. K2G can handle upto 128 messages! */
@@ -1819,6 +1821,7 @@ static int ti_sci_probe(struct platform_device *pdev)
int ret = -EINVAL;
int i;
int reboot = 0;
+ u32 h_id;
of_id = of_match_device(ti_sci_of_match, dev);
if (!of_id) {
@@ -1833,6 +1836,19 @@ static int ti_sci_probe(struct platform_device *pdev)
info->dev = dev;
info->desc = desc;
+ ret = of_property_read_u32(dev->of_node, "ti,host-id", &h_id);
+ /* if the property is not present in DT, use a default from desc */
+ if (ret < 0) {
+ info->host_id = info->desc->default_host_id;
+ } else {
+ if (!h_id) {
+ dev_warn(dev, "Host ID 0 is reserved for firmware\n");
+ info->host_id = info->desc->default_host_id;
+ } else {
+ info->host_id = h_id;
+ }
+ }
+
reboot = of_property_read_bool(dev->of_node,
"ti,system-reboot-controller");
INIT_LIST_HEAD(&info->node);
diff --git a/drivers/firmware/xilinx/Kconfig b/drivers/firmware/xilinx/Kconfig
new file mode 100644
index 000000000000..8f44b9cd295a
--- /dev/null
+++ b/drivers/firmware/xilinx/Kconfig
@@ -0,0 +1,23 @@
+# SPDX-License-Identifier: GPL-2.0
+# Kconfig for Xilinx firmwares
+
+menu "Zynq MPSoC Firmware Drivers"
+ depends on ARCH_ZYNQMP
+
+config ZYNQMP_FIRMWARE
+ bool "Enable Xilinx Zynq MPSoC firmware interface"
+ help
+ Firmware interface driver is used by different
+ drivers to communicate with the firmware for
+ various platform management services.
+ Say yes to enable ZynqMP firmware interface driver.
+ If in doubt, say N.
+
+config ZYNQMP_FIRMWARE_DEBUG
+ bool "Enable Xilinx Zynq MPSoC firmware debug APIs"
+ depends on ZYNQMP_FIRMWARE && DEBUG_FS
+ help
+ Say yes to enable ZynqMP firmware interface debug APIs.
+ If in doubt, say N.
+
+endmenu
diff --git a/drivers/firmware/xilinx/Makefile b/drivers/firmware/xilinx/Makefile
new file mode 100644
index 000000000000..875a53703c82
--- /dev/null
+++ b/drivers/firmware/xilinx/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+# Makefile for Xilinx firmwares
+
+obj-$(CONFIG_ZYNQMP_FIRMWARE) += zynqmp.o
+obj-$(CONFIG_ZYNQMP_FIRMWARE_DEBUG) += zynqmp-debug.o
diff --git a/drivers/firmware/xilinx/zynqmp-debug.c b/drivers/firmware/xilinx/zynqmp-debug.c
new file mode 100644
index 000000000000..2771df6df379
--- /dev/null
+++ b/drivers/firmware/xilinx/zynqmp-debug.c
@@ -0,0 +1,250 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Xilinx Zynq MPSoC Firmware layer for debugfs APIs
+ *
+ * Copyright (C) 2014-2018 Xilinx, Inc.
+ *
+ * Michal Simek <michal.simek@xilinx.com>
+ * Davorin Mista <davorin.mista@aggios.com>
+ * Jolly Shah <jollys@xilinx.com>
+ * Rajan Vaja <rajanv@xilinx.com>
+ */
+
+#include <linux/compiler.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+
+#include <linux/firmware/xlnx-zynqmp.h>
+#include "zynqmp-debug.h"
+
+#define PM_API_NAME_LEN 50
+
+struct pm_api_info {
+ u32 api_id;
+ char api_name[PM_API_NAME_LEN];
+ char api_name_len;
+};
+
+static char debugfs_buf[PAGE_SIZE];
+
+#define PM_API(id) {id, #id, strlen(#id)}
+static struct pm_api_info pm_api_list[] = {
+ PM_API(PM_GET_API_VERSION),
+ PM_API(PM_QUERY_DATA),
+};
+
+struct dentry *firmware_debugfs_root;
+
+/**
+ * zynqmp_pm_argument_value() - Extract argument value from a PM-API request
+ * @arg: Entered PM-API argument in string format
+ *
+ * Return: Argument value in unsigned integer format on success
+ * 0 otherwise
+ */
+static u64 zynqmp_pm_argument_value(char *arg)
+{
+ u64 value;
+
+ if (!arg)
+ return 0;
+
+ if (!kstrtou64(arg, 0, &value))
+ return value;
+
+ return 0;
+}
+
+/**
+ * get_pm_api_id() - Extract API-ID from a PM-API request
+ * @pm_api_req: Entered PM-API argument in string format
+ * @pm_id: API-ID
+ *
+ * Return: 0 on success else error code
+ */
+static int get_pm_api_id(char *pm_api_req, u32 *pm_id)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pm_api_list) ; i++) {
+ if (!strncasecmp(pm_api_req, pm_api_list[i].api_name,
+ pm_api_list[i].api_name_len)) {
+ *pm_id = pm_api_list[i].api_id;
+ break;
+ }
+ }
+
+ /* If no name was entered look for PM-API ID instead */
+ if (i == ARRAY_SIZE(pm_api_list) && kstrtouint(pm_api_req, 10, pm_id))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int process_api_request(u32 pm_id, u64 *pm_api_arg, u32 *pm_api_ret)
+{
+ const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
+ u32 pm_api_version;
+ int ret;
+ struct zynqmp_pm_query_data qdata = {0};
+
+ if (!eemi_ops)
+ return -ENXIO;
+
+ switch (pm_id) {
+ case PM_GET_API_VERSION:
+ ret = eemi_ops->get_api_version(&pm_api_version);
+ sprintf(debugfs_buf, "PM-API Version = %d.%d\n",
+ pm_api_version >> 16, pm_api_version & 0xffff);
+ break;
+ case PM_QUERY_DATA:
+ qdata.qid = pm_api_arg[0];
+ qdata.arg1 = pm_api_arg[1];
+ qdata.arg2 = pm_api_arg[2];
+ qdata.arg3 = pm_api_arg[3];
+
+ ret = eemi_ops->query_data(qdata, pm_api_ret);
+ if (ret)
+ break;
+
+ switch (qdata.qid) {
+ case PM_QID_CLOCK_GET_NAME:
+ sprintf(debugfs_buf, "Clock name = %s\n",
+ (char *)pm_api_ret);
+ break;
+ case PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS:
+ sprintf(debugfs_buf, "Multiplier = %d, Divider = %d\n",
+ pm_api_ret[1], pm_api_ret[2]);
+ break;
+ default:
+ sprintf(debugfs_buf,
+ "data[0] = 0x%08x\ndata[1] = 0x%08x\n data[2] = 0x%08x\ndata[3] = 0x%08x\n",
+ pm_api_ret[0], pm_api_ret[1],
+ pm_api_ret[2], pm_api_ret[3]);
+ }
+ break;
+ default:
+ sprintf(debugfs_buf, "Unsupported PM-API request\n");
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+/**
+ * zynqmp_pm_debugfs_api_write() - debugfs write function
+ * @file: User file
+ * @ptr: User entered PM-API string
+ * @len: Length of the userspace buffer
+ * @off: Offset within the file
+ *
+ * Used for triggering pm api functions by writing
+ * echo <pm_api_id> > /sys/kernel/debug/zynqmp_pm/power or
+ * echo <pm_api_name> > /sys/kernel/debug/zynqmp_pm/power
+ *
+ * Return: Number of bytes copied if PM-API request succeeds,
+ * the corresponding error code otherwise
+ */
+static ssize_t zynqmp_pm_debugfs_api_write(struct file *file,
+ const char __user *ptr, size_t len,
+ loff_t *off)
+{
+ char *kern_buff, *tmp_buff;
+ char *pm_api_req;
+ u32 pm_id = 0;
+ u64 pm_api_arg[4] = {0, 0, 0, 0};
+ /* Return values from PM APIs calls */
+ u32 pm_api_ret[4] = {0, 0, 0, 0};
+
+ int ret;
+ int i = 0;
+
+ strcpy(debugfs_buf, "");
+
+ if (*off != 0 || len == 0)
+ return -EINVAL;
+
+ kern_buff = kzalloc(len, GFP_KERNEL);
+ if (!kern_buff)
+ return -ENOMEM;
+
+ tmp_buff = kern_buff;
+
+ ret = strncpy_from_user(kern_buff, ptr, len);
+ if (ret < 0) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ /* Read the API name from a user request */
+ pm_api_req = strsep(&kern_buff, " ");
+
+ ret = get_pm_api_id(pm_api_req, &pm_id);
+ if (ret < 0)
+ goto err;
+
+ /* Read node_id and arguments from the PM-API request */
+ pm_api_req = strsep(&kern_buff, " ");
+ while ((i < ARRAY_SIZE(pm_api_arg)) && pm_api_req) {
+ pm_api_arg[i++] = zynqmp_pm_argument_value(pm_api_req);
+ pm_api_req = strsep(&kern_buff, " ");
+ }
+
+ ret = process_api_request(pm_id, pm_api_arg, pm_api_ret);
+
+err:
+ kfree(tmp_buff);
+ if (ret)
+ return ret;
+
+ return len;
+}
+
+/**
+ * zynqmp_pm_debugfs_api_read() - debugfs read function
+ * @file: User file
+ * @ptr: Requested pm_api_version string
+ * @len: Length of the userspace buffer
+ * @off: Offset within the file
+ *
+ * Return: Length of the version string on success
+ * else error code
+ */
+static ssize_t zynqmp_pm_debugfs_api_read(struct file *file, char __user *ptr,
+ size_t len, loff_t *off)
+{
+ return simple_read_from_buffer(ptr, len, off, debugfs_buf,
+ strlen(debugfs_buf));
+}
+
+/* Setup debugfs fops */
+static const struct file_operations fops_zynqmp_pm_dbgfs = {
+ .owner = THIS_MODULE,
+ .write = zynqmp_pm_debugfs_api_write,
+ .read = zynqmp_pm_debugfs_api_read,
+};
+
+/**
+ * zynqmp_pm_api_debugfs_init - Initialize debugfs interface
+ *
+ * Return: None
+ */
+void zynqmp_pm_api_debugfs_init(void)
+{
+ /* Initialize debugfs interface */
+ firmware_debugfs_root = debugfs_create_dir("zynqmp-firmware", NULL);
+ debugfs_create_file("pm", 0660, firmware_debugfs_root, NULL,
+ &fops_zynqmp_pm_dbgfs);
+}
+
+/**
+ * zynqmp_pm_api_debugfs_exit - Remove debugfs interface
+ *
+ * Return: None
+ */
+void zynqmp_pm_api_debugfs_exit(void)
+{
+ debugfs_remove_recursive(firmware_debugfs_root);
+}
diff --git a/drivers/firmware/xilinx/zynqmp-debug.h b/drivers/firmware/xilinx/zynqmp-debug.h
new file mode 100644
index 000000000000..9929f8b433f5
--- /dev/null
+++ b/drivers/firmware/xilinx/zynqmp-debug.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Xilinx Zynq MPSoC Firmware layer
+ *
+ * Copyright (C) 2014-2018 Xilinx
+ *
+ * Michal Simek <michal.simek@xilinx.com>
+ * Davorin Mista <davorin.mista@aggios.com>
+ * Jolly Shah <jollys@xilinx.com>
+ * Rajan Vaja <rajanv@xilinx.com>
+ */
+
+#ifndef __FIRMWARE_ZYNQMP_DEBUG_H__
+#define __FIRMWARE_ZYNQMP_DEBUG_H__
+
+#if IS_REACHABLE(CONFIG_ZYNQMP_FIRMWARE_DEBUG)
+void zynqmp_pm_api_debugfs_init(void);
+void zynqmp_pm_api_debugfs_exit(void);
+#else
+static inline void zynqmp_pm_api_debugfs_init(void) { }
+static inline void zynqmp_pm_api_debugfs_exit(void) { }
+#endif
+
+#endif /* __FIRMWARE_ZYNQMP_DEBUG_H__ */
diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c
new file mode 100644
index 000000000000..9a1c72a9280f
--- /dev/null
+++ b/drivers/firmware/xilinx/zynqmp.c
@@ -0,0 +1,565 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Xilinx Zynq MPSoC Firmware layer
+ *
+ * Copyright (C) 2014-2018 Xilinx, Inc.
+ *
+ * Michal Simek <michal.simek@xilinx.com>
+ * Davorin Mista <davorin.mista@aggios.com>
+ * Jolly Shah <jollys@xilinx.com>
+ * Rajan Vaja <rajanv@xilinx.com>
+ */
+
+#include <linux/arm-smccc.h>
+#include <linux/compiler.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+#include <linux/firmware/xlnx-zynqmp.h>
+#include "zynqmp-debug.h"
+
+/**
+ * zynqmp_pm_ret_code() - Convert PMU-FW error codes to Linux error codes
+ * @ret_status: PMUFW return code
+ *
+ * Return: corresponding Linux error code
+ */
+static int zynqmp_pm_ret_code(u32 ret_status)
+{
+ switch (ret_status) {
+ case XST_PM_SUCCESS:
+ case XST_PM_DOUBLE_REQ:
+ return 0;
+ case XST_PM_NO_ACCESS:
+ return -EACCES;
+ case XST_PM_ABORT_SUSPEND:
+ return -ECANCELED;
+ case XST_PM_INTERNAL:
+ case XST_PM_CONFLICT:
+ case XST_PM_INVALID_NODE:
+ default:
+ return -EINVAL;
+ }
+}
+
+static noinline int do_fw_call_fail(u64 arg0, u64 arg1, u64 arg2,
+ u32 *ret_payload)
+{
+ return -ENODEV;
+}
+
+/*
+ * PM function call wrapper
+ * Invoke do_fw_call_smc or do_fw_call_hvc, depending on the configuration
+ */
+static int (*do_fw_call)(u64, u64, u64, u32 *ret_payload) = do_fw_call_fail;
+
+/**
+ * do_fw_call_smc() - Call system-level platform management layer (SMC)
+ * @arg0: Argument 0 to SMC call
+ * @arg1: Argument 1 to SMC call
+ * @arg2: Argument 2 to SMC call
+ * @ret_payload: Returned value array
+ *
+ * Invoke platform management function via SMC call (no hypervisor present).
+ *
+ * Return: Returns status, either success or error+reason
+ */
+static noinline int do_fw_call_smc(u64 arg0, u64 arg1, u64 arg2,
+ u32 *ret_payload)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_smc(arg0, arg1, arg2, 0, 0, 0, 0, 0, &res);
+
+ if (ret_payload) {
+ ret_payload[0] = lower_32_bits(res.a0);
+ ret_payload[1] = upper_32_bits(res.a0);
+ ret_payload[2] = lower_32_bits(res.a1);
+ ret_payload[3] = upper_32_bits(res.a1);
+ }
+
+ return zynqmp_pm_ret_code((enum pm_ret_status)res.a0);
+}
+
+/**
+ * do_fw_call_hvc() - Call system-level platform management layer (HVC)
+ * @arg0: Argument 0 to HVC call
+ * @arg1: Argument 1 to HVC call
+ * @arg2: Argument 2 to HVC call
+ * @ret_payload: Returned value array
+ *
+ * Invoke platform management function via HVC
+ * HVC-based for communication through hypervisor
+ * (no direct communication with ATF).
+ *
+ * Return: Returns status, either success or error+reason
+ */
+static noinline int do_fw_call_hvc(u64 arg0, u64 arg1, u64 arg2,
+ u32 *ret_payload)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_hvc(arg0, arg1, arg2, 0, 0, 0, 0, 0, &res);
+
+ if (ret_payload) {
+ ret_payload[0] = lower_32_bits(res.a0);
+ ret_payload[1] = upper_32_bits(res.a0);
+ ret_payload[2] = lower_32_bits(res.a1);
+ ret_payload[3] = upper_32_bits(res.a1);
+ }
+
+ return zynqmp_pm_ret_code((enum pm_ret_status)res.a0);
+}
+
+/**
+ * zynqmp_pm_invoke_fn() - Invoke the system-level platform management layer
+ * caller function depending on the configuration
+ * @pm_api_id: Requested PM-API call
+ * @arg0: Argument 0 to requested PM-API call
+ * @arg1: Argument 1 to requested PM-API call
+ * @arg2: Argument 2 to requested PM-API call
+ * @arg3: Argument 3 to requested PM-API call
+ * @ret_payload: Returned value array
+ *
+ * Invoke platform management function for SMC or HVC call, depending on
+ * configuration.
+ * Following SMC Calling Convention (SMCCC) for SMC64:
+ * Pm Function Identifier,
+ * PM_SIP_SVC + PM_API_ID =
+ * ((SMC_TYPE_FAST << FUNCID_TYPE_SHIFT)
+ * ((SMC_64) << FUNCID_CC_SHIFT)
+ * ((SIP_START) << FUNCID_OEN_SHIFT)
+ * ((PM_API_ID) & FUNCID_NUM_MASK))
+ *
+ * PM_SIP_SVC - Registered ZynqMP SIP Service Call.
+ * PM_API_ID - Platform Management API ID.
+ *
+ * Return: Returns status, either success or error+reason
+ */
+int zynqmp_pm_invoke_fn(u32 pm_api_id, u32 arg0, u32 arg1,
+ u32 arg2, u32 arg3, u32 *ret_payload)
+{
+ /*
+ * Added SIP service call Function Identifier
+ * Make sure to stay in x0 register
+ */
+ u64 smc_arg[4];
+
+ smc_arg[0] = PM_SIP_SVC | pm_api_id;
+ smc_arg[1] = ((u64)arg1 << 32) | arg0;
+ smc_arg[2] = ((u64)arg3 << 32) | arg2;
+
+ return do_fw_call(smc_arg[0], smc_arg[1], smc_arg[2], ret_payload);
+}
+
+static u32 pm_api_version;
+static u32 pm_tz_version;
+
+/**
+ * zynqmp_pm_get_api_version() - Get version number of PMU PM firmware
+ * @version: Returned version value
+ *
+ * Return: Returns status, either success or error+reason
+ */
+static int zynqmp_pm_get_api_version(u32 *version)
+{
+ u32 ret_payload[PAYLOAD_ARG_CNT];
+ int ret;
+
+ if (!version)
+ return -EINVAL;
+
+ /* Check is PM API version already verified */
+ if (pm_api_version > 0) {
+ *version = pm_api_version;
+ return 0;
+ }
+ ret = zynqmp_pm_invoke_fn(PM_GET_API_VERSION, 0, 0, 0, 0, ret_payload);
+ *version = ret_payload[1];
+
+ return ret;
+}
+
+/**
+ * zynqmp_pm_get_trustzone_version() - Get secure trustzone firmware version
+ * @version: Returned version value
+ *
+ * Return: Returns status, either success or error+reason
+ */
+static int zynqmp_pm_get_trustzone_version(u32 *version)
+{
+ u32 ret_payload[PAYLOAD_ARG_CNT];
+ int ret;
+
+ if (!version)
+ return -EINVAL;
+
+ /* Check is PM trustzone version already verified */
+ if (pm_tz_version > 0) {
+ *version = pm_tz_version;
+ return 0;
+ }
+ ret = zynqmp_pm_invoke_fn(PM_GET_TRUSTZONE_VERSION, 0, 0,
+ 0, 0, ret_payload);
+ *version = ret_payload[1];
+
+ return ret;
+}
+
+/**
+ * get_set_conduit_method() - Choose SMC or HVC based communication
+ * @np: Pointer to the device_node structure
+ *
+ * Use SMC or HVC-based functions to communicate with EL2/EL3.
+ *
+ * Return: Returns 0 on success or error code
+ */
+static int get_set_conduit_method(struct device_node *np)
+{
+ const char *method;
+
+ if (of_property_read_string(np, "method", &method)) {
+ pr_warn("%s missing \"method\" property\n", __func__);
+ return -ENXIO;
+ }
+
+ if (!strcmp("hvc", method)) {
+ do_fw_call = do_fw_call_hvc;
+ } else if (!strcmp("smc", method)) {
+ do_fw_call = do_fw_call_smc;
+ } else {
+ pr_warn("%s Invalid \"method\" property: %s\n",
+ __func__, method);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * zynqmp_pm_query_data() - Get query data from firmware
+ * @qdata: Variable to the zynqmp_pm_query_data structure
+ * @out: Returned output value
+ *
+ * Return: Returns status, either success or error+reason
+ */
+static int zynqmp_pm_query_data(struct zynqmp_pm_query_data qdata, u32 *out)
+{
+ int ret;
+
+ ret = zynqmp_pm_invoke_fn(PM_QUERY_DATA, qdata.qid, qdata.arg1,
+ qdata.arg2, qdata.arg3, out);
+
+ /*
+ * For clock name query, all bytes in SMC response are clock name
+ * characters and return code is always success. For invalid clocks,
+ * clock name bytes would be zeros.
+ */
+ return qdata.qid == PM_QID_CLOCK_GET_NAME ? 0 : ret;
+}
+
+/**
+ * zynqmp_pm_clock_enable() - Enable the clock for given id
+ * @clock_id: ID of the clock to be enabled
+ *
+ * This function is used by master to enable the clock
+ * including peripherals and PLL clocks.
+ *
+ * Return: Returns status, either success or error+reason
+ */
+static int zynqmp_pm_clock_enable(u32 clock_id)
+{
+ return zynqmp_pm_invoke_fn(PM_CLOCK_ENABLE, clock_id, 0, 0, 0, NULL);
+}
+
+/**
+ * zynqmp_pm_clock_disable() - Disable the clock for given id
+ * @clock_id: ID of the clock to be disable
+ *
+ * This function is used by master to disable the clock
+ * including peripherals and PLL clocks.
+ *
+ * Return: Returns status, either success or error+reason
+ */
+static int zynqmp_pm_clock_disable(u32 clock_id)
+{
+ return zynqmp_pm_invoke_fn(PM_CLOCK_DISABLE, clock_id, 0, 0, 0, NULL);
+}
+
+/**
+ * zynqmp_pm_clock_getstate() - Get the clock state for given id
+ * @clock_id: ID of the clock to be queried
+ * @state: 1/0 (Enabled/Disabled)
+ *
+ * This function is used by master to get the state of clock
+ * including peripherals and PLL clocks.
+ *
+ * Return: Returns status, either success or error+reason
+ */
+static int zynqmp_pm_clock_getstate(u32 clock_id, u32 *state)
+{
+ u32 ret_payload[PAYLOAD_ARG_CNT];
+ int ret;
+
+ ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETSTATE, clock_id, 0,
+ 0, 0, ret_payload);
+ *state = ret_payload[1];
+
+ return ret;
+}
+
+/**
+ * zynqmp_pm_clock_setdivider() - Set the clock divider for given id
+ * @clock_id: ID of the clock
+ * @divider: divider value
+ *
+ * This function is used by master to set divider for any clock
+ * to achieve desired rate.
+ *
+ * Return: Returns status, either success or error+reason
+ */
+static int zynqmp_pm_clock_setdivider(u32 clock_id, u32 divider)
+{
+ return zynqmp_pm_invoke_fn(PM_CLOCK_SETDIVIDER, clock_id, divider,
+ 0, 0, NULL);
+}
+
+/**
+ * zynqmp_pm_clock_getdivider() - Get the clock divider for given id
+ * @clock_id: ID of the clock
+ * @divider: divider value
+ *
+ * This function is used by master to get divider values
+ * for any clock.
+ *
+ * Return: Returns status, either success or error+reason
+ */
+static int zynqmp_pm_clock_getdivider(u32 clock_id, u32 *divider)
+{
+ u32 ret_payload[PAYLOAD_ARG_CNT];
+ int ret;
+
+ ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETDIVIDER, clock_id, 0,
+ 0, 0, ret_payload);
+ *divider = ret_payload[1];
+
+ return ret;
+}
+
+/**
+ * zynqmp_pm_clock_setrate() - Set the clock rate for given id
+ * @clock_id: ID of the clock
+ * @rate: rate value in hz
+ *
+ * This function is used by master to set rate for any clock.
+ *
+ * Return: Returns status, either success or error+reason
+ */
+static int zynqmp_pm_clock_setrate(u32 clock_id, u64 rate)
+{
+ return zynqmp_pm_invoke_fn(PM_CLOCK_SETRATE, clock_id,
+ lower_32_bits(rate),
+ upper_32_bits(rate),
+ 0, NULL);
+}
+
+/**
+ * zynqmp_pm_clock_getrate() - Get the clock rate for given id
+ * @clock_id: ID of the clock
+ * @rate: rate value in hz
+ *
+ * This function is used by master to get rate
+ * for any clock.
+ *
+ * Return: Returns status, either success or error+reason
+ */
+static int zynqmp_pm_clock_getrate(u32 clock_id, u64 *rate)
+{
+ u32 ret_payload[PAYLOAD_ARG_CNT];
+ int ret;
+
+ ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETRATE, clock_id, 0,
+ 0, 0, ret_payload);
+ *rate = ((u64)ret_payload[2] << 32) | ret_payload[1];
+
+ return ret;
+}
+
+/**
+ * zynqmp_pm_clock_setparent() - Set the clock parent for given id
+ * @clock_id: ID of the clock
+ * @parent_id: parent id
+ *
+ * This function is used by master to set parent for any clock.
+ *
+ * Return: Returns status, either success or error+reason
+ */
+static int zynqmp_pm_clock_setparent(u32 clock_id, u32 parent_id)
+{
+ return zynqmp_pm_invoke_fn(PM_CLOCK_SETPARENT, clock_id,
+ parent_id, 0, 0, NULL);
+}
+
+/**
+ * zynqmp_pm_clock_getparent() - Get the clock parent for given id
+ * @clock_id: ID of the clock
+ * @parent_id: parent id
+ *
+ * This function is used by master to get parent index
+ * for any clock.
+ *
+ * Return: Returns status, either success or error+reason
+ */
+static int zynqmp_pm_clock_getparent(u32 clock_id, u32 *parent_id)
+{
+ u32 ret_payload[PAYLOAD_ARG_CNT];
+ int ret;
+
+ ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETPARENT, clock_id, 0,
+ 0, 0, ret_payload);
+ *parent_id = ret_payload[1];
+
+ return ret;
+}
+
+/**
+ * zynqmp_is_valid_ioctl() - Check whether IOCTL ID is valid or not
+ * @ioctl_id: IOCTL ID
+ *
+ * Return: 1 if IOCTL is valid else 0
+ */
+static inline int zynqmp_is_valid_ioctl(u32 ioctl_id)
+{
+ switch (ioctl_id) {
+ case IOCTL_SET_PLL_FRAC_MODE:
+ case IOCTL_GET_PLL_FRAC_MODE:
+ case IOCTL_SET_PLL_FRAC_DATA:
+ case IOCTL_GET_PLL_FRAC_DATA:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/**
+ * zynqmp_pm_ioctl() - PM IOCTL API for device control and configs
+ * @node_id: Node ID of the device
+ * @ioctl_id: ID of the requested IOCTL
+ * @arg1: Argument 1 to requested IOCTL call
+ * @arg2: Argument 2 to requested IOCTL call
+ * @out: Returned output value
+ *
+ * This function calls IOCTL to firmware for device control and configuration.
+ *
+ * Return: Returns status, either success or error+reason
+ */
+static int zynqmp_pm_ioctl(u32 node_id, u32 ioctl_id, u32 arg1, u32 arg2,
+ u32 *out)
+{
+ if (!zynqmp_is_valid_ioctl(ioctl_id))
+ return -EINVAL;
+
+ return zynqmp_pm_invoke_fn(PM_IOCTL, node_id, ioctl_id,
+ arg1, arg2, out);
+}
+
+static const struct zynqmp_eemi_ops eemi_ops = {
+ .get_api_version = zynqmp_pm_get_api_version,
+ .query_data = zynqmp_pm_query_data,
+ .clock_enable = zynqmp_pm_clock_enable,
+ .clock_disable = zynqmp_pm_clock_disable,
+ .clock_getstate = zynqmp_pm_clock_getstate,
+ .clock_setdivider = zynqmp_pm_clock_setdivider,
+ .clock_getdivider = zynqmp_pm_clock_getdivider,
+ .clock_setrate = zynqmp_pm_clock_setrate,
+ .clock_getrate = zynqmp_pm_clock_getrate,
+ .clock_setparent = zynqmp_pm_clock_setparent,
+ .clock_getparent = zynqmp_pm_clock_getparent,
+ .ioctl = zynqmp_pm_ioctl,
+};
+
+/**
+ * zynqmp_pm_get_eemi_ops - Get eemi ops functions
+ *
+ * Return: Pointer of eemi_ops structure
+ */
+const struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void)
+{
+ return &eemi_ops;
+}
+EXPORT_SYMBOL_GPL(zynqmp_pm_get_eemi_ops);
+
+static int zynqmp_firmware_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np;
+ int ret;
+
+ np = of_find_compatible_node(NULL, NULL, "xlnx,zynqmp");
+ if (!np)
+ return 0;
+ of_node_put(np);
+
+ ret = get_set_conduit_method(dev->of_node);
+ if (ret)
+ return ret;
+
+ /* Check PM API version number */
+ zynqmp_pm_get_api_version(&pm_api_version);
+ if (pm_api_version < ZYNQMP_PM_VERSION) {
+ panic("%s Platform Management API version error. Expected: v%d.%d - Found: v%d.%d\n",
+ __func__,
+ ZYNQMP_PM_VERSION_MAJOR, ZYNQMP_PM_VERSION_MINOR,
+ pm_api_version >> 16, pm_api_version & 0xFFFF);
+ }
+
+ pr_info("%s Platform Management API v%d.%d\n", __func__,
+ pm_api_version >> 16, pm_api_version & 0xFFFF);
+
+ /* Check trustzone version number */
+ ret = zynqmp_pm_get_trustzone_version(&pm_tz_version);
+ if (ret)
+ panic("Legacy trustzone found without version support\n");
+
+ if (pm_tz_version < ZYNQMP_TZ_VERSION)
+ panic("%s Trustzone version error. Expected: v%d.%d - Found: v%d.%d\n",
+ __func__,
+ ZYNQMP_TZ_VERSION_MAJOR, ZYNQMP_TZ_VERSION_MINOR,
+ pm_tz_version >> 16, pm_tz_version & 0xFFFF);
+
+ pr_info("%s Trustzone version v%d.%d\n", __func__,
+ pm_tz_version >> 16, pm_tz_version & 0xFFFF);
+
+ zynqmp_pm_api_debugfs_init();
+
+ return of_platform_populate(dev->of_node, NULL, NULL, dev);
+}
+
+static int zynqmp_firmware_remove(struct platform_device *pdev)
+{
+ zynqmp_pm_api_debugfs_exit();
+
+ return 0;
+}
+
+static const struct of_device_id zynqmp_firmware_of_match[] = {
+ {.compatible = "xlnx,zynqmp-firmware"},
+ {},
+};
+MODULE_DEVICE_TABLE(of, zynqmp_firmware_of_match);
+
+static struct platform_driver zynqmp_firmware_driver = {
+ .driver = {
+ .name = "zynqmp_firmware",
+ .of_match_table = zynqmp_firmware_of_match,
+ },
+ .probe = zynqmp_firmware_probe,
+ .remove = zynqmp_firmware_remove,
+};
+module_platform_driver(zynqmp_firmware_driver);
diff --git a/drivers/fpga/altera-cvp.c b/drivers/fpga/altera-cvp.c
index 7fa793672a7a..610a1558e0ed 100644
--- a/drivers/fpga/altera-cvp.c
+++ b/drivers/fpga/altera-cvp.c
@@ -453,8 +453,8 @@ static int altera_cvp_probe(struct pci_dev *pdev,
snprintf(conf->mgr_name, sizeof(conf->mgr_name), "%s @%s",
ALTERA_CVP_MGR_NAME, pci_name(pdev));
- mgr = fpga_mgr_create(&pdev->dev, conf->mgr_name,
- &altera_cvp_ops, conf);
+ mgr = devm_fpga_mgr_create(&pdev->dev, conf->mgr_name,
+ &altera_cvp_ops, conf);
if (!mgr) {
ret = -ENOMEM;
goto err_unmap;
@@ -463,10 +463,8 @@ static int altera_cvp_probe(struct pci_dev *pdev,
pci_set_drvdata(pdev, mgr);
ret = fpga_mgr_register(mgr);
- if (ret) {
- fpga_mgr_free(mgr);
+ if (ret)
goto err_unmap;
- }
ret = driver_create_file(&altera_cvp_driver.driver,
&driver_attr_chkcfg);
diff --git a/drivers/fpga/altera-fpga2sdram.c b/drivers/fpga/altera-fpga2sdram.c
index 23660ccd634b..a78e49c63c64 100644
--- a/drivers/fpga/altera-fpga2sdram.c
+++ b/drivers/fpga/altera-fpga2sdram.c
@@ -121,18 +121,16 @@ static int alt_fpga_bridge_probe(struct platform_device *pdev)
/* Get f2s bridge configuration saved in handoff register */
regmap_read(sysmgr, SYSMGR_ISWGRP_HANDOFF3, &priv->mask);
- br = fpga_bridge_create(dev, F2S_BRIDGE_NAME,
- &altera_fpga2sdram_br_ops, priv);
+ br = devm_fpga_bridge_create(dev, F2S_BRIDGE_NAME,
+ &altera_fpga2sdram_br_ops, priv);
if (!br)
return -ENOMEM;
platform_set_drvdata(pdev, br);
ret = fpga_bridge_register(br);
- if (ret) {
- fpga_bridge_free(br);
+ if (ret)
return ret;
- }
dev_info(dev, "driver initialized with handoff %08x\n", priv->mask);
diff --git a/drivers/fpga/altera-freeze-bridge.c b/drivers/fpga/altera-freeze-bridge.c
index ffd586c48ecf..dd58c4aea92e 100644
--- a/drivers/fpga/altera-freeze-bridge.c
+++ b/drivers/fpga/altera-freeze-bridge.c
@@ -213,7 +213,6 @@ static int altera_freeze_br_probe(struct platform_device *pdev)
struct fpga_bridge *br;
struct resource *res;
u32 status, revision;
- int ret;
if (!np)
return -ENODEV;
@@ -245,20 +244,14 @@ static int altera_freeze_br_probe(struct platform_device *pdev)
priv->base_addr = base_addr;
- br = fpga_bridge_create(dev, FREEZE_BRIDGE_NAME,
- &altera_freeze_br_br_ops, priv);
+ br = devm_fpga_bridge_create(dev, FREEZE_BRIDGE_NAME,
+ &altera_freeze_br_br_ops, priv);
if (!br)
return -ENOMEM;
platform_set_drvdata(pdev, br);
- ret = fpga_bridge_register(br);
- if (ret) {
- fpga_bridge_free(br);
- return ret;
- }
-
- return 0;
+ return fpga_bridge_register(br);
}
static int altera_freeze_br_remove(struct platform_device *pdev)
diff --git a/drivers/fpga/altera-hps2fpga.c b/drivers/fpga/altera-hps2fpga.c
index a974d3f60321..77b95f251821 100644
--- a/drivers/fpga/altera-hps2fpga.c
+++ b/drivers/fpga/altera-hps2fpga.c
@@ -180,7 +180,8 @@ static int alt_fpga_bridge_probe(struct platform_device *pdev)
}
}
- br = fpga_bridge_create(dev, priv->name, &altera_hps2fpga_br_ops, priv);
+ br = devm_fpga_bridge_create(dev, priv->name,
+ &altera_hps2fpga_br_ops, priv);
if (!br) {
ret = -ENOMEM;
goto err;
@@ -190,12 +191,10 @@ static int alt_fpga_bridge_probe(struct platform_device *pdev)
ret = fpga_bridge_register(br);
if (ret)
- goto err_free;
+ goto err;
return 0;
-err_free:
- fpga_bridge_free(br);
err:
clk_disable_unprepare(priv->clk);
diff --git a/drivers/fpga/altera-pr-ip-core.c b/drivers/fpga/altera-pr-ip-core.c
index 65e0b6a2c031..a7a3bf0b5202 100644
--- a/drivers/fpga/altera-pr-ip-core.c
+++ b/drivers/fpga/altera-pr-ip-core.c
@@ -177,7 +177,6 @@ int alt_pr_register(struct device *dev, void __iomem *reg_base)
{
struct alt_pr_priv *priv;
struct fpga_manager *mgr;
- int ret;
u32 val;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -192,17 +191,13 @@ int alt_pr_register(struct device *dev, void __iomem *reg_base)
(val & ALT_PR_CSR_STATUS_MSK) >> ALT_PR_CSR_STATUS_SFT,
(int)(val & ALT_PR_CSR_PR_START));
- mgr = fpga_mgr_create(dev, dev_name(dev), &alt_pr_ops, priv);
+ mgr = devm_fpga_mgr_create(dev, dev_name(dev), &alt_pr_ops, priv);
if (!mgr)
return -ENOMEM;
dev_set_drvdata(dev, mgr);
- ret = fpga_mgr_register(mgr);
- if (ret)
- fpga_mgr_free(mgr);
-
- return ret;
+ return fpga_mgr_register(mgr);
}
EXPORT_SYMBOL_GPL(alt_pr_register);
diff --git a/drivers/fpga/altera-ps-spi.c b/drivers/fpga/altera-ps-spi.c
index 24b25c626036..33aafda50af5 100644
--- a/drivers/fpga/altera-ps-spi.c
+++ b/drivers/fpga/altera-ps-spi.c
@@ -239,7 +239,6 @@ static int altera_ps_probe(struct spi_device *spi)
struct altera_ps_conf *conf;
const struct of_device_id *of_id;
struct fpga_manager *mgr;
- int ret;
conf = devm_kzalloc(&spi->dev, sizeof(*conf), GFP_KERNEL);
if (!conf)
@@ -275,18 +274,14 @@ static int altera_ps_probe(struct spi_device *spi)
snprintf(conf->mgr_name, sizeof(conf->mgr_name), "%s %s",
dev_driver_string(&spi->dev), dev_name(&spi->dev));
- mgr = fpga_mgr_create(&spi->dev, conf->mgr_name,
- &altera_ps_ops, conf);
+ mgr = devm_fpga_mgr_create(&spi->dev, conf->mgr_name,
+ &altera_ps_ops, conf);
if (!mgr)
return -ENOMEM;
spi_set_drvdata(spi, mgr);
- ret = fpga_mgr_register(mgr);
- if (ret)
- fpga_mgr_free(mgr);
-
- return ret;
+ return fpga_mgr_register(mgr);
}
static int altera_ps_remove(struct spi_device *spi)
diff --git a/drivers/fpga/dfl-afu-dma-region.c b/drivers/fpga/dfl-afu-dma-region.c
index 0e81d33af856..025aba3ea76c 100644
--- a/drivers/fpga/dfl-afu-dma-region.c
+++ b/drivers/fpga/dfl-afu-dma-region.c
@@ -70,7 +70,7 @@ static int afu_dma_adjust_locked_vm(struct device *dev, long npages, bool incr)
dev_dbg(dev, "[%d] RLIMIT_MEMLOCK %c%ld %ld/%ld%s\n", current->pid,
incr ? '+' : '-', npages << PAGE_SHIFT,
current->mm->locked_vm << PAGE_SHIFT, rlimit(RLIMIT_MEMLOCK),
- ret ? "- execeeded" : "");
+ ret ? "- exceeded" : "");
up_write(&current->mm->mmap_sem);
diff --git a/drivers/fpga/dfl-fme-br.c b/drivers/fpga/dfl-fme-br.c
index 7cc041def8b3..3ff9f3a687ce 100644
--- a/drivers/fpga/dfl-fme-br.c
+++ b/drivers/fpga/dfl-fme-br.c
@@ -61,7 +61,6 @@ static int fme_br_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct fme_br_priv *priv;
struct fpga_bridge *br;
- int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -69,18 +68,14 @@ static int fme_br_probe(struct platform_device *pdev)
priv->pdata = dev_get_platdata(dev);
- br = fpga_bridge_create(dev, "DFL FPGA FME Bridge",
- &fme_bridge_ops, priv);
+ br = devm_fpga_bridge_create(dev, "DFL FPGA FME Bridge",
+ &fme_bridge_ops, priv);
if (!br)
return -ENOMEM;
platform_set_drvdata(pdev, br);
- ret = fpga_bridge_register(br);
- if (ret)
- fpga_bridge_free(br);
-
- return ret;
+ return fpga_bridge_register(br);
}
static int fme_br_remove(struct platform_device *pdev)
diff --git a/drivers/fpga/dfl-fme-mgr.c b/drivers/fpga/dfl-fme-mgr.c
index b5ef405b6d88..76f37709dd1a 100644
--- a/drivers/fpga/dfl-fme-mgr.c
+++ b/drivers/fpga/dfl-fme-mgr.c
@@ -201,7 +201,7 @@ static int fme_mgr_write(struct fpga_manager *mgr,
}
if (count < 4) {
- dev_err(dev, "Invaild PR bitstream size\n");
+ dev_err(dev, "Invalid PR bitstream size\n");
return -EINVAL;
}
@@ -287,7 +287,6 @@ static int fme_mgr_probe(struct platform_device *pdev)
struct fme_mgr_priv *priv;
struct fpga_manager *mgr;
struct resource *res;
- int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -309,19 +308,15 @@ static int fme_mgr_probe(struct platform_device *pdev)
fme_mgr_get_compat_id(priv->ioaddr, compat_id);
- mgr = fpga_mgr_create(dev, "DFL FME FPGA Manager",
- &fme_mgr_ops, priv);
+ mgr = devm_fpga_mgr_create(dev, "DFL FME FPGA Manager",
+ &fme_mgr_ops, priv);
if (!mgr)
return -ENOMEM;
mgr->compat_id = compat_id;
platform_set_drvdata(pdev, mgr);
- ret = fpga_mgr_register(mgr);
- if (ret)
- fpga_mgr_free(mgr);
-
- return ret;
+ return fpga_mgr_register(mgr);
}
static int fme_mgr_remove(struct platform_device *pdev)
diff --git a/drivers/fpga/dfl-fme-region.c b/drivers/fpga/dfl-fme-region.c
index 0b7e19c27c6d..ec134ec93f08 100644
--- a/drivers/fpga/dfl-fme-region.c
+++ b/drivers/fpga/dfl-fme-region.c
@@ -14,6 +14,7 @@
*/
#include <linux/module.h>
+#include <linux/fpga/fpga-mgr.h>
#include <linux/fpga/fpga-region.h>
#include "dfl-fme-pr.h"
@@ -38,7 +39,7 @@ static int fme_region_probe(struct platform_device *pdev)
if (IS_ERR(mgr))
return -EPROBE_DEFER;
- region = fpga_region_create(dev, mgr, fme_region_get_bridges);
+ region = devm_fpga_region_create(dev, mgr, fme_region_get_bridges);
if (!region) {
ret = -ENOMEM;
goto eprobe_mgr_put;
@@ -50,14 +51,12 @@ static int fme_region_probe(struct platform_device *pdev)
ret = fpga_region_register(region);
if (ret)
- goto region_free;
+ goto eprobe_mgr_put;
dev_dbg(dev, "DFL FME FPGA Region probed\n");
return 0;
-region_free:
- fpga_region_free(region);
eprobe_mgr_put:
fpga_mgr_put(mgr);
return ret;
@@ -66,9 +65,10 @@ eprobe_mgr_put:
static int fme_region_remove(struct platform_device *pdev)
{
struct fpga_region *region = dev_get_drvdata(&pdev->dev);
+ struct fpga_manager *mgr = region->mgr;
fpga_region_unregister(region);
- fpga_mgr_put(region->mgr);
+ fpga_mgr_put(mgr);
return 0;
}
diff --git a/drivers/fpga/dfl.c b/drivers/fpga/dfl.c
index a9b521bccb06..2c09e502e721 100644
--- a/drivers/fpga/dfl.c
+++ b/drivers/fpga/dfl.c
@@ -899,7 +899,7 @@ dfl_fpga_feature_devs_enumerate(struct dfl_fpga_enum_info *info)
if (!cdev)
return ERR_PTR(-ENOMEM);
- cdev->region = fpga_region_create(info->dev, NULL, NULL);
+ cdev->region = devm_fpga_region_create(info->dev, NULL, NULL);
if (!cdev->region) {
ret = -ENOMEM;
goto free_cdev_exit;
@@ -911,7 +911,7 @@ dfl_fpga_feature_devs_enumerate(struct dfl_fpga_enum_info *info)
ret = fpga_region_register(cdev->region);
if (ret)
- goto free_region_exit;
+ goto free_cdev_exit;
/* create and init build info for enumeration */
binfo = devm_kzalloc(info->dev, sizeof(*binfo), GFP_KERNEL);
@@ -942,8 +942,6 @@ dfl_fpga_feature_devs_enumerate(struct dfl_fpga_enum_info *info)
unregister_region_exit:
fpga_region_unregister(cdev->region);
-free_region_exit:
- fpga_region_free(cdev->region);
free_cdev_exit:
devm_kfree(info->dev, cdev);
return ERR_PTR(ret);
diff --git a/drivers/fpga/fpga-bridge.c b/drivers/fpga/fpga-bridge.c
index 24b8f98b73ec..80bd8f1b2aa6 100644
--- a/drivers/fpga/fpga-bridge.c
+++ b/drivers/fpga/fpga-bridge.c
@@ -125,7 +125,7 @@ static int fpga_bridge_dev_match(struct device *dev, const void *data)
*
* Given a device, get an exclusive reference to a fpga bridge.
*
- * Return: fpga manager struct or IS_ERR() condition containing error code.
+ * Return: fpga bridge struct or IS_ERR() condition containing error code.
*/
struct fpga_bridge *fpga_bridge_get(struct device *dev,
struct fpga_image_info *info)
@@ -324,6 +324,9 @@ ATTRIBUTE_GROUPS(fpga_bridge);
* @br_ops: pointer to structure of fpga bridge ops
* @priv: FPGA bridge private data
*
+ * The caller of this function is responsible for freeing the bridge with
+ * fpga_bridge_free(). Using devm_fpga_bridge_create() instead is recommended.
+ *
* Return: struct fpga_bridge or NULL
*/
struct fpga_bridge *fpga_bridge_create(struct device *dev, const char *name,
@@ -378,8 +381,8 @@ error_kfree:
EXPORT_SYMBOL_GPL(fpga_bridge_create);
/**
- * fpga_bridge_free - free a fpga bridge and its id
- * @bridge: FPGA bridge struct created by fpga_bridge_create
+ * fpga_bridge_free - free a fpga bridge created by fpga_bridge_create()
+ * @bridge: FPGA bridge struct
*/
void fpga_bridge_free(struct fpga_bridge *bridge)
{
@@ -388,9 +391,56 @@ void fpga_bridge_free(struct fpga_bridge *bridge)
}
EXPORT_SYMBOL_GPL(fpga_bridge_free);
+static void devm_fpga_bridge_release(struct device *dev, void *res)
+{
+ struct fpga_bridge *bridge = *(struct fpga_bridge **)res;
+
+ fpga_bridge_free(bridge);
+}
+
/**
- * fpga_bridge_register - register a fpga bridge
- * @bridge: FPGA bridge struct created by fpga_bridge_create
+ * devm_fpga_bridge_create - create and init a managed struct fpga_bridge
+ * @dev: 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.
+ * 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
+ * allocated with this function will be freed automatically on driver detach.
+ * This includes the case of a probe function returning error before calling
+ * fpga_bridge_register(), the struct will still get cleaned up.
+ *
+ * Return: struct fpga_bridge or NULL
+ */
+struct fpga_bridge
+*devm_fpga_bridge_create(struct device *dev, const char *name,
+ const struct fpga_bridge_ops *br_ops, void *priv)
+{
+ struct fpga_bridge **ptr, *bridge;
+
+ ptr = devres_alloc(devm_fpga_bridge_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return NULL;
+
+ bridge = fpga_bridge_create(dev, name, br_ops, priv);
+ if (!bridge) {
+ devres_free(ptr);
+ } else {
+ *ptr = bridge;
+ devres_add(dev, ptr);
+ }
+
+ return bridge;
+}
+EXPORT_SYMBOL_GPL(devm_fpga_bridge_create);
+
+/**
+ * fpga_bridge_register - register a FPGA bridge
+ *
+ * @bridge: FPGA bridge struct
*
* Return: 0 for success, error code otherwise.
*/
@@ -412,8 +462,11 @@ int fpga_bridge_register(struct fpga_bridge *bridge)
EXPORT_SYMBOL_GPL(fpga_bridge_register);
/**
- * fpga_bridge_unregister - unregister and free a fpga bridge
- * @bridge: FPGA bridge struct created by fpga_bridge_create
+ * fpga_bridge_unregister - unregister a FPGA bridge
+ *
+ * @bridge: FPGA bridge struct
+ *
+ * This function is intended for use in a FPGA bridge driver's remove function.
*/
void fpga_bridge_unregister(struct fpga_bridge *bridge)
{
@@ -430,9 +483,6 @@ EXPORT_SYMBOL_GPL(fpga_bridge_unregister);
static void fpga_bridge_dev_release(struct device *dev)
{
- struct fpga_bridge *bridge = to_fpga_bridge(dev);
-
- fpga_bridge_free(bridge);
}
static int __init fpga_bridge_dev_init(void)
diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c
index a41b07e37884..c3866816456a 100644
--- a/drivers/fpga/fpga-mgr.c
+++ b/drivers/fpga/fpga-mgr.c
@@ -558,6 +558,9 @@ EXPORT_SYMBOL_GPL(fpga_mgr_unlock);
* @mops: pointer to structure of fpga manager ops
* @priv: fpga manager private data
*
+ * The caller of this function is responsible for freeing the struct with
+ * fpga_mgr_free(). Using devm_fpga_mgr_create() instead is recommended.
+ *
* Return: pointer to struct fpga_manager or NULL
*/
struct fpga_manager *fpga_mgr_create(struct device *dev, const char *name,
@@ -618,8 +621,8 @@ error_kfree:
EXPORT_SYMBOL_GPL(fpga_mgr_create);
/**
- * fpga_mgr_free - deallocate a FPGA manager
- * @mgr: fpga manager struct created by fpga_mgr_create
+ * fpga_mgr_free - free a FPGA manager created with fpga_mgr_create()
+ * @mgr: fpga manager struct
*/
void fpga_mgr_free(struct fpga_manager *mgr)
{
@@ -628,9 +631,55 @@ void fpga_mgr_free(struct fpga_manager *mgr)
}
EXPORT_SYMBOL_GPL(fpga_mgr_free);
+static void devm_fpga_mgr_release(struct device *dev, void *res)
+{
+ struct fpga_manager *mgr = *(struct fpga_manager **)res;
+
+ fpga_mgr_free(mgr);
+}
+
+/**
+ * devm_fpga_mgr_create - create and initialize a managed FPGA manager struct
+ * @dev: 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.
+ * 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
+ * manager struct allocated with this function will be freed automatically on
+ * driver detach. This includes the case of a probe function returning error
+ * before calling fpga_mgr_register(), the struct will still get cleaned up.
+ *
+ * Return: pointer to struct fpga_manager or NULL
+ */
+struct fpga_manager *devm_fpga_mgr_create(struct device *dev, const char *name,
+ const struct fpga_manager_ops *mops,
+ void *priv)
+{
+ struct fpga_manager **ptr, *mgr;
+
+ ptr = devres_alloc(devm_fpga_mgr_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return NULL;
+
+ mgr = fpga_mgr_create(dev, name, mops, priv);
+ if (!mgr) {
+ devres_free(ptr);
+ } else {
+ *ptr = mgr;
+ devres_add(dev, ptr);
+ }
+
+ return mgr;
+}
+EXPORT_SYMBOL_GPL(devm_fpga_mgr_create);
+
/**
* fpga_mgr_register - register a FPGA manager
- * @mgr: fpga manager struct created by fpga_mgr_create
+ * @mgr: fpga manager struct
*
* Return: 0 on success, negative error code otherwise.
*/
@@ -661,8 +710,10 @@ error_device:
EXPORT_SYMBOL_GPL(fpga_mgr_register);
/**
- * fpga_mgr_unregister - unregister and free a FPGA manager
- * @mgr: fpga manager struct
+ * fpga_mgr_unregister - unregister a FPGA manager
+ * @mgr: fpga manager struct
+ *
+ * This function is intended for use in a FPGA manager driver's remove function.
*/
void fpga_mgr_unregister(struct fpga_manager *mgr)
{
@@ -681,9 +732,6 @@ EXPORT_SYMBOL_GPL(fpga_mgr_unregister);
static void fpga_mgr_dev_release(struct device *dev)
{
- struct fpga_manager *mgr = to_fpga_manager(dev);
-
- fpga_mgr_free(mgr);
}
static int __init fpga_mgr_class_init(void)
diff --git a/drivers/fpga/fpga-region.c b/drivers/fpga/fpga-region.c
index 0d65220d5ec5..bde5a9d460c5 100644
--- a/drivers/fpga/fpga-region.c
+++ b/drivers/fpga/fpga-region.c
@@ -185,6 +185,10 @@ ATTRIBUTE_GROUPS(fpga_region);
* @mgr: manager that programs this region
* @get_bridges: optional function to get bridges to a list
*
+ * The caller of this function is responsible for freeing the resulting region
+ * struct with fpga_region_free(). Using devm_fpga_region_create() instead is
+ * recommended.
+ *
* Return: struct fpga_region or NULL
*/
struct fpga_region
@@ -230,8 +234,8 @@ err_free:
EXPORT_SYMBOL_GPL(fpga_region_create);
/**
- * fpga_region_free - free a struct fpga_region
- * @region: FPGA region created by fpga_region_create
+ * fpga_region_free - free a FPGA region created by fpga_region_create()
+ * @region: FPGA region
*/
void fpga_region_free(struct fpga_region *region)
{
@@ -240,21 +244,69 @@ void fpga_region_free(struct fpga_region *region)
}
EXPORT_SYMBOL_GPL(fpga_region_free);
+static void devm_fpga_region_release(struct device *dev, void *res)
+{
+ struct fpga_region *region = *(struct fpga_region **)res;
+
+ fpga_region_free(region);
+}
+
+/**
+ * devm_fpga_region_create - create and initialize a managed FPGA region struct
+ * @dev: 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.
+ * 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().
+ * The region struct allocated with this function will be freed automatically on
+ * driver detach. This includes the case of a probe function returning error
+ * before calling fpga_region_register(), the struct will still get cleaned up.
+ *
+ * Return: struct fpga_region or NULL
+ */
+struct fpga_region
+*devm_fpga_region_create(struct device *dev,
+ struct fpga_manager *mgr,
+ int (*get_bridges)(struct fpga_region *))
+{
+ struct fpga_region **ptr, *region;
+
+ ptr = devres_alloc(devm_fpga_region_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return NULL;
+
+ region = fpga_region_create(dev, mgr, get_bridges);
+ if (!region) {
+ devres_free(ptr);
+ } else {
+ *ptr = region;
+ devres_add(dev, ptr);
+ }
+
+ return region;
+}
+EXPORT_SYMBOL_GPL(devm_fpga_region_create);
+
/**
* fpga_region_register - register a FPGA region
- * @region: FPGA region created by fpga_region_create
+ * @region: FPGA region
+ *
* Return: 0 or -errno
*/
int fpga_region_register(struct fpga_region *region)
{
return device_add(&region->dev);
-
}
EXPORT_SYMBOL_GPL(fpga_region_register);
/**
- * fpga_region_unregister - unregister and free a FPGA region
+ * fpga_region_unregister - unregister a FPGA region
* @region: FPGA region
+ *
+ * This function is intended for use in a FPGA region driver's remove function.
*/
void fpga_region_unregister(struct fpga_region *region)
{
@@ -264,9 +316,6 @@ EXPORT_SYMBOL_GPL(fpga_region_unregister);
static void fpga_region_dev_release(struct device *dev)
{
- struct fpga_region *region = to_fpga_region(dev);
-
- fpga_region_free(region);
}
/**
diff --git a/drivers/fpga/ice40-spi.c b/drivers/fpga/ice40-spi.c
index 5981c7ee7a7d..6154661b8f76 100644
--- a/drivers/fpga/ice40-spi.c
+++ b/drivers/fpga/ice40-spi.c
@@ -175,18 +175,14 @@ static int ice40_fpga_probe(struct spi_device *spi)
return ret;
}
- mgr = fpga_mgr_create(dev, "Lattice iCE40 FPGA Manager",
- &ice40_fpga_ops, priv);
+ mgr = devm_fpga_mgr_create(dev, "Lattice iCE40 FPGA Manager",
+ &ice40_fpga_ops, priv);
if (!mgr)
return -ENOMEM;
spi_set_drvdata(spi, mgr);
- ret = fpga_mgr_register(mgr);
- if (ret)
- fpga_mgr_free(mgr);
-
- return ret;
+ return fpga_mgr_register(mgr);
}
static int ice40_fpga_remove(struct spi_device *spi)
diff --git a/drivers/fpga/machxo2-spi.c b/drivers/fpga/machxo2-spi.c
index a582e0000c97..4d8a87641587 100644
--- a/drivers/fpga/machxo2-spi.c
+++ b/drivers/fpga/machxo2-spi.c
@@ -356,25 +356,20 @@ static int machxo2_spi_probe(struct spi_device *spi)
{
struct device *dev = &spi->dev;
struct fpga_manager *mgr;
- int ret;
if (spi->max_speed_hz > MACHXO2_MAX_SPEED) {
dev_err(dev, "Speed is too high\n");
return -EINVAL;
}
- mgr = fpga_mgr_create(dev, "Lattice MachXO2 SPI FPGA Manager",
- &machxo2_ops, spi);
+ mgr = devm_fpga_mgr_create(dev, "Lattice MachXO2 SPI FPGA Manager",
+ &machxo2_ops, spi);
if (!mgr)
return -ENOMEM;
spi_set_drvdata(spi, mgr);
- ret = fpga_mgr_register(mgr);
- if (ret)
- fpga_mgr_free(mgr);
-
- return ret;
+ return fpga_mgr_register(mgr);
}
static int machxo2_spi_remove(struct spi_device *spi)
diff --git a/drivers/fpga/of-fpga-region.c b/drivers/fpga/of-fpga-region.c
index 35fabb8083fb..122286fd255a 100644
--- a/drivers/fpga/of-fpga-region.c
+++ b/drivers/fpga/of-fpga-region.c
@@ -410,7 +410,7 @@ static int of_fpga_region_probe(struct platform_device *pdev)
if (IS_ERR(mgr))
return -EPROBE_DEFER;
- region = fpga_region_create(dev, mgr, of_fpga_region_get_bridges);
+ region = devm_fpga_region_create(dev, mgr, of_fpga_region_get_bridges);
if (!region) {
ret = -ENOMEM;
goto eprobe_mgr_put;
@@ -418,7 +418,7 @@ static int of_fpga_region_probe(struct platform_device *pdev)
ret = fpga_region_register(region);
if (ret)
- goto eprobe_free;
+ goto eprobe_mgr_put;
of_platform_populate(np, fpga_region_of_match, NULL, &region->dev);
dev_set_drvdata(dev, region);
@@ -427,8 +427,6 @@ static int of_fpga_region_probe(struct platform_device *pdev)
return 0;
-eprobe_free:
- fpga_region_free(region);
eprobe_mgr_put:
fpga_mgr_put(mgr);
return ret;
@@ -437,9 +435,10 @@ eprobe_mgr_put:
static int of_fpga_region_remove(struct platform_device *pdev)
{
struct fpga_region *region = platform_get_drvdata(pdev);
+ struct fpga_manager *mgr = region->mgr;
fpga_region_unregister(region);
- fpga_mgr_put(region->mgr);
+ fpga_mgr_put(mgr);
return 0;
}
diff --git a/drivers/fpga/socfpga-a10.c b/drivers/fpga/socfpga-a10.c
index be30c48eb6e4..573d88bdf730 100644
--- a/drivers/fpga/socfpga-a10.c
+++ b/drivers/fpga/socfpga-a10.c
@@ -508,8 +508,8 @@ static int socfpga_a10_fpga_probe(struct platform_device *pdev)
return -EBUSY;
}
- mgr = fpga_mgr_create(dev, "SoCFPGA Arria10 FPGA Manager",
- &socfpga_a10_fpga_mgr_ops, priv);
+ mgr = devm_fpga_mgr_create(dev, "SoCFPGA Arria10 FPGA Manager",
+ &socfpga_a10_fpga_mgr_ops, priv);
if (!mgr)
return -ENOMEM;
@@ -517,7 +517,6 @@ static int socfpga_a10_fpga_probe(struct platform_device *pdev)
ret = fpga_mgr_register(mgr);
if (ret) {
- fpga_mgr_free(mgr);
clk_disable_unprepare(priv->clk);
return ret;
}
diff --git a/drivers/fpga/socfpga.c b/drivers/fpga/socfpga.c
index 959d71f26896..4a8a2fcd4e6c 100644
--- a/drivers/fpga/socfpga.c
+++ b/drivers/fpga/socfpga.c
@@ -571,18 +571,14 @@ static int socfpga_fpga_probe(struct platform_device *pdev)
if (ret)
return ret;
- mgr = fpga_mgr_create(dev, "Altera SOCFPGA FPGA Manager",
- &socfpga_fpga_ops, priv);
+ mgr = devm_fpga_mgr_create(dev, "Altera SOCFPGA FPGA Manager",
+ &socfpga_fpga_ops, priv);
if (!mgr)
return -ENOMEM;
platform_set_drvdata(pdev, mgr);
- ret = fpga_mgr_register(mgr);
- if (ret)
- fpga_mgr_free(mgr);
-
- return ret;
+ return fpga_mgr_register(mgr);
}
static int socfpga_fpga_remove(struct platform_device *pdev)
diff --git a/drivers/fpga/ts73xx-fpga.c b/drivers/fpga/ts73xx-fpga.c
index 08efd1895b1b..dc22a5842609 100644
--- a/drivers/fpga/ts73xx-fpga.c
+++ b/drivers/fpga/ts73xx-fpga.c
@@ -118,7 +118,6 @@ static int ts73xx_fpga_probe(struct platform_device *pdev)
struct ts73xx_fpga_priv *priv;
struct fpga_manager *mgr;
struct resource *res;
- int ret;
priv = devm_kzalloc(kdev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -133,18 +132,14 @@ static int ts73xx_fpga_probe(struct platform_device *pdev)
return PTR_ERR(priv->io_base);
}
- mgr = fpga_mgr_create(kdev, "TS-73xx FPGA Manager",
- &ts73xx_fpga_ops, priv);
+ mgr = devm_fpga_mgr_create(kdev, "TS-73xx FPGA Manager",
+ &ts73xx_fpga_ops, priv);
if (!mgr)
return -ENOMEM;
platform_set_drvdata(pdev, mgr);
- ret = fpga_mgr_register(mgr);
- if (ret)
- fpga_mgr_free(mgr);
-
- return ret;
+ return fpga_mgr_register(mgr);
}
static int ts73xx_fpga_remove(struct platform_device *pdev)
diff --git a/drivers/fpga/xilinx-pr-decoupler.c b/drivers/fpga/xilinx-pr-decoupler.c
index 07ba1539e82c..641036135207 100644
--- a/drivers/fpga/xilinx-pr-decoupler.c
+++ b/drivers/fpga/xilinx-pr-decoupler.c
@@ -121,8 +121,8 @@ static int xlnx_pr_decoupler_probe(struct platform_device *pdev)
clk_disable(priv->clk);
- br = fpga_bridge_create(&pdev->dev, "Xilinx PR Decoupler",
- &xlnx_pr_decoupler_br_ops, priv);
+ br = devm_fpga_bridge_create(&pdev->dev, "Xilinx PR Decoupler",
+ &xlnx_pr_decoupler_br_ops, priv);
if (!br) {
err = -ENOMEM;
goto err_clk;
diff --git a/drivers/fpga/xilinx-spi.c b/drivers/fpga/xilinx-spi.c
index 8d1945966533..469486be20c4 100644
--- a/drivers/fpga/xilinx-spi.c
+++ b/drivers/fpga/xilinx-spi.c
@@ -144,7 +144,6 @@ static int xilinx_spi_probe(struct spi_device *spi)
{
struct xilinx_spi_conf *conf;
struct fpga_manager *mgr;
- int ret;
conf = devm_kzalloc(&spi->dev, sizeof(*conf), GFP_KERNEL);
if (!conf)
@@ -167,18 +166,15 @@ static int xilinx_spi_probe(struct spi_device *spi)
return PTR_ERR(conf->done);
}
- mgr = fpga_mgr_create(&spi->dev, "Xilinx Slave Serial FPGA Manager",
- &xilinx_spi_ops, conf);
+ mgr = devm_fpga_mgr_create(&spi->dev,
+ "Xilinx Slave Serial FPGA Manager",
+ &xilinx_spi_ops, conf);
if (!mgr)
return -ENOMEM;
spi_set_drvdata(spi, mgr);
- ret = fpga_mgr_register(mgr);
- if (ret)
- fpga_mgr_free(mgr);
-
- return ret;
+ return fpga_mgr_register(mgr);
}
static int xilinx_spi_remove(struct spi_device *spi)
diff --git a/drivers/fpga/zynq-fpga.c b/drivers/fpga/zynq-fpga.c
index 3110e00121ca..bb82efeebb9d 100644
--- a/drivers/fpga/zynq-fpga.c
+++ b/drivers/fpga/zynq-fpga.c
@@ -614,8 +614,8 @@ static int zynq_fpga_probe(struct platform_device *pdev)
clk_disable(priv->clk);
- mgr = fpga_mgr_create(dev, "Xilinx Zynq FPGA Manager",
- &zynq_fpga_ops, priv);
+ mgr = devm_fpga_mgr_create(dev, "Xilinx Zynq FPGA Manager",
+ &zynq_fpga_ops, priv);
if (!mgr)
return -ENOMEM;
@@ -624,7 +624,6 @@ static int zynq_fpga_probe(struct platform_device *pdev)
err = fpga_mgr_register(mgr);
if (err) {
dev_err(dev, "unable to register FPGA manager\n");
- fpga_mgr_free(mgr);
clk_unprepare(priv->clk);
return err;
}
diff --git a/drivers/fsi/fsi-sbefifo.c b/drivers/fsi/fsi-sbefifo.c
index ae861342626e..d92f5b87c251 100644
--- a/drivers/fsi/fsi-sbefifo.c
+++ b/drivers/fsi/fsi-sbefifo.c
@@ -638,7 +638,7 @@ static void sbefifo_collect_async_ffdc(struct sbefifo *sbefifo)
}
ffdc_iov.iov_base = ffdc;
ffdc_iov.iov_len = SBEFIFO_MAX_FFDC_SIZE;
- iov_iter_kvec(&ffdc_iter, WRITE | ITER_KVEC, &ffdc_iov, 1, SBEFIFO_MAX_FFDC_SIZE);
+ iov_iter_kvec(&ffdc_iter, WRITE, &ffdc_iov, 1, SBEFIFO_MAX_FFDC_SIZE);
cmd[0] = cpu_to_be32(2);
cmd[1] = cpu_to_be32(SBEFIFO_CMD_GET_SBE_FFDC);
rc = sbefifo_do_command(sbefifo, cmd, 2, &ffdc_iter);
@@ -735,7 +735,7 @@ int sbefifo_submit(struct device *dev, const __be32 *command, size_t cmd_len,
rbytes = (*resp_len) * sizeof(__be32);
resp_iov.iov_base = response;
resp_iov.iov_len = rbytes;
- iov_iter_kvec(&resp_iter, WRITE | ITER_KVEC, &resp_iov, 1, rbytes);
+ iov_iter_kvec(&resp_iter, WRITE, &resp_iov, 1, rbytes);
/* Perform the command */
mutex_lock(&sbefifo->lock);
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 4f52c3a8ec99..833a1b51c948 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -200,6 +200,7 @@ config GPIO_EP93XX
def_bool y
depends on ARCH_EP93XX
select GPIO_GENERIC
+ select GPIOLIB_IRQCHIP
config GPIO_EXAR
tristate "Support for GPIO pins on XR17V352/354/358"
@@ -267,17 +268,6 @@ config GPIO_ICH
If unsure, say N.
-config GPIO_INGENIC
- tristate "Ingenic JZ47xx SoCs GPIO support"
- depends on OF
- depends on MACH_INGENIC || COMPILE_TEST
- select GPIOLIB_IRQCHIP
- help
- Say yes here to support the GPIO functionality present on the
- JZ4740 and JZ4780 SoCs from Ingenic.
-
- If unsure, say N.
-
config GPIO_IOP
tristate "Intel IOP GPIO"
depends on ARCH_IOP32X || ARCH_IOP33X || COMPILE_TEST
@@ -439,6 +429,24 @@ config GPIO_REG
A 32-bit single register GPIO fixed in/out implementation. This
can be used to represent any register as a set of GPIO signals.
+config GPIO_SIOX
+ tristate "SIOX GPIO support"
+ depends on SIOX
+ select GPIOLIB_IRQCHIP
+ help
+ Say yes here to support SIOX I/O devices. These are units connected
+ via a SIOX bus and have a number of fixed-direction I/O lines.
+
+config GPIO_SNPS_CREG
+ bool "Synopsys GPIO via CREG (Control REGisters) driver"
+ depends on ARC || COMPILE_TEST
+ depends on OF_GPIO
+ help
+ This driver supports GPIOs via CREG on various Synopsys SoCs.
+ This is a single-register MMIO GPIO driver for complex cases
+ where only several fields in register belong to GPIO lines and
+ each GPIO line owns a field with different length and on/off value.
+
config GPIO_SPEAR_SPICS
bool "ST SPEAr13xx SPI Chip Select as GPIO support"
depends on PLAT_SPEAR
@@ -480,6 +488,7 @@ config GPIO_SYSCON
config GPIO_TB10X
bool
+ select GPIO_GENERIC
select GENERIC_IRQ_CHIP
select OF_GPIO
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index c256aff66a65..671c4477c951 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -3,8 +3,8 @@
ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG
-obj-$(CONFIG_GPIOLIB) += devres.o
obj-$(CONFIG_GPIOLIB) += gpiolib.o
+obj-$(CONFIG_GPIOLIB) += gpiolib-devres.o
obj-$(CONFIG_GPIOLIB) += gpiolib-legacy.o
obj-$(CONFIG_GPIOLIB) += gpiolib-devprop.o
obj-$(CONFIG_OF_GPIO) += gpiolib-of.o
@@ -57,7 +57,6 @@ obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.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_INGENIC) += gpio-ingenic.o
obj-$(CONFIG_GPIO_IOP) += gpio-iop.o
obj-$(CONFIG_GPIO_IT87) += gpio-it87.o
obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o
@@ -111,6 +110,7 @@ obj-$(CONFIG_GPIO_REG) += gpio-reg.o
obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o
obj-$(CONFIG_GPIO_SCH) += gpio-sch.o
obj-$(CONFIG_GPIO_SCH311X) += gpio-sch311x.o
+obj-$(CONFIG_GPIO_SNPS_CREG) += gpio-creg-snps.o
obj-$(CONFIG_GPIO_SODAVILLE) += gpio-sodaville.o
obj-$(CONFIG_GPIO_SPEAR_SPICS) += gpio-spear-spics.o
obj-$(CONFIG_GPIO_SPRD) += gpio-sprd.o
@@ -125,6 +125,7 @@ obj-$(CONFIG_GPIO_TEGRA186) += gpio-tegra186.o
obj-$(CONFIG_GPIO_THUNDERX) += gpio-thunderx.o
obj-$(CONFIG_GPIO_TIMBERDALE) += gpio-timberdale.o
obj-$(CONFIG_GPIO_PALMAS) += gpio-palmas.o
+obj-$(CONFIG_GPIO_SIOX) += gpio-siox.o
obj-$(CONFIG_GPIO_TPIC2810) += gpio-tpic2810.o
obj-$(CONFIG_GPIO_TPS65086) += gpio-tps65086.o
obj-$(CONFIG_GPIO_TPS65218) += gpio-tps65218.o
diff --git a/drivers/gpio/gpio-adp5520.c b/drivers/gpio/gpio-adp5520.c
index 21452622d954..e321955782a1 100644
--- a/drivers/gpio/gpio-adp5520.c
+++ b/drivers/gpio/gpio-adp5520.c
@@ -172,7 +172,7 @@ static struct platform_driver adp5520_gpio_driver = {
module_platform_driver(adp5520_gpio_driver);
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("GPIO ADP5520 Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:adp5520-gpio");
diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/gpio-adp5588.c
index da9781a2ef4a..cc33d8986ad3 100644
--- a/drivers/gpio/gpio-adp5588.c
+++ b/drivers/gpio/gpio-adp5588.c
@@ -494,6 +494,6 @@ static struct i2c_driver adp5588_gpio_driver = {
module_i2c_driver(adp5588_gpio_driver);
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("GPIO ADP5588 Driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c
index d0707fc23afd..c5536a509b59 100644
--- a/drivers/gpio/gpio-bcm-kona.c
+++ b/drivers/gpio/gpio-bcm-kona.c
@@ -373,6 +373,7 @@ static void bcm_kona_gpio_irq_mask(struct irq_data *d)
val = readl(reg_base + GPIO_INT_MASK(bank_id));
val |= BIT(bit);
writel(val, reg_base + GPIO_INT_MASK(bank_id));
+ gpiochip_disable_irq(&kona_gpio->gpio_chip, gpio);
raw_spin_unlock_irqrestore(&kona_gpio->lock, flags);
}
@@ -394,6 +395,7 @@ static void bcm_kona_gpio_irq_unmask(struct irq_data *d)
val = readl(reg_base + GPIO_INT_MSKCLR(bank_id));
val |= BIT(bit);
writel(val, reg_base + GPIO_INT_MSKCLR(bank_id));
+ gpiochip_enable_irq(&kona_gpio->gpio_chip, gpio);
raw_spin_unlock_irqrestore(&kona_gpio->lock, flags);
}
@@ -485,23 +487,15 @@ static void bcm_kona_gpio_irq_handler(struct irq_desc *desc)
static int bcm_kona_gpio_irq_reqres(struct irq_data *d)
{
struct bcm_kona_gpio *kona_gpio = irq_data_get_irq_chip_data(d);
- int ret;
- ret = gpiochip_lock_as_irq(&kona_gpio->gpio_chip, d->hwirq);
- if (ret) {
- dev_err(kona_gpio->gpio_chip.parent,
- "unable to lock HW IRQ %lu for IRQ\n",
- d->hwirq);
- return ret;
- }
- return 0;
+ return gpiochip_reqres_irq(&kona_gpio->gpio_chip, d->hwirq);
}
static void bcm_kona_gpio_irq_relres(struct irq_data *d)
{
struct bcm_kona_gpio *kona_gpio = irq_data_get_irq_chip_data(d);
- gpiochip_unlock_as_irq(&kona_gpio->gpio_chip, d->hwirq);
+ gpiochip_relres_irq(&kona_gpio->gpio_chip, d->hwirq);
}
static struct irq_chip bcm_gpio_irq_chip = {
diff --git a/drivers/gpio/gpio-brcmstb.c b/drivers/gpio/gpio-brcmstb.c
index 16c7f9f49416..af936dcca659 100644
--- a/drivers/gpio/gpio-brcmstb.c
+++ b/drivers/gpio/gpio-brcmstb.c
@@ -664,6 +664,18 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
struct brcmstb_gpio_bank *bank;
struct gpio_chip *gc;
+ /*
+ * If bank_width is 0, then there is an empty bank in the
+ * register block. Special handling for this case.
+ */
+ if (bank_width == 0) {
+ dev_dbg(dev, "Width 0 found: Empty bank @ %d\n",
+ num_banks);
+ num_banks++;
+ gpio_base += MAX_GPIO_PER_BANK;
+ continue;
+ }
+
bank = devm_kzalloc(dev, sizeof(*bank), GFP_KERNEL);
if (!bank) {
err = -ENOMEM;
@@ -740,9 +752,6 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
goto fail;
}
- dev_info(dev, "Registered %d banks (GPIO(s): %d-%d)\n",
- num_banks, priv->gpio_base, gpio_base - 1);
-
if (priv->parent_wake_irq && need_wakeup_event)
pm_wakeup_event(dev, 0);
diff --git a/drivers/gpio/gpio-creg-snps.c b/drivers/gpio/gpio-creg-snps.c
new file mode 100644
index 000000000000..8cbc94d0d424
--- /dev/null
+++ b/drivers/gpio/gpio-creg-snps.c
@@ -0,0 +1,191 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Synopsys CREG (Control REGisters) GPIO driver
+//
+// Copyright (C) 2018 Synopsys
+// Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
+
+#include <linux/gpio/driver.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+
+#define MAX_GPIO 32
+
+struct creg_layout {
+ u8 ngpio;
+ u8 shift[MAX_GPIO];
+ u8 on[MAX_GPIO];
+ u8 off[MAX_GPIO];
+ u8 bit_per_gpio[MAX_GPIO];
+};
+
+struct creg_gpio {
+ struct gpio_chip gc;
+ void __iomem *regs;
+ spinlock_t lock;
+ const struct creg_layout *layout;
+};
+
+static void creg_gpio_set(struct gpio_chip *gc, unsigned int offset, int val)
+{
+ struct creg_gpio *hcg = gpiochip_get_data(gc);
+ const struct creg_layout *layout = hcg->layout;
+ u32 reg, reg_shift, value;
+ unsigned long flags;
+ int i;
+
+ value = val ? hcg->layout->on[offset] : hcg->layout->off[offset];
+
+ reg_shift = layout->shift[offset];
+ for (i = 0; i < offset; i++)
+ reg_shift += layout->bit_per_gpio[i] + layout->shift[i];
+
+ spin_lock_irqsave(&hcg->lock, flags);
+ reg = readl(hcg->regs);
+ reg &= ~(GENMASK(layout->bit_per_gpio[i] - 1, 0) << reg_shift);
+ reg |= (value << reg_shift);
+ writel(reg, hcg->regs);
+ spin_unlock_irqrestore(&hcg->lock, flags);
+}
+
+static int creg_gpio_dir_out(struct gpio_chip *gc, unsigned int offset, int val)
+{
+ creg_gpio_set(gc, offset, val);
+
+ return 0;
+}
+
+static int creg_gpio_validate_pg(struct device *dev, struct creg_gpio *hcg,
+ int i)
+{
+ const struct creg_layout *layout = hcg->layout;
+
+ if (layout->bit_per_gpio[i] < 1 || layout->bit_per_gpio[i] > 8)
+ return -EINVAL;
+
+ /* Check that on valiue fits it's placeholder */
+ if (GENMASK(31, layout->bit_per_gpio[i]) & layout->on[i])
+ return -EINVAL;
+
+ /* Check that off valiue fits it's placeholder */
+ if (GENMASK(31, layout->bit_per_gpio[i]) & layout->off[i])
+ return -EINVAL;
+
+ if (layout->on[i] == layout->off[i])
+ return -EINVAL;
+
+ return 0;
+}
+
+static int creg_gpio_validate(struct device *dev, struct creg_gpio *hcg,
+ u32 ngpios)
+{
+ u32 reg_len = 0;
+ int i;
+
+ if (hcg->layout->ngpio < 1 || hcg->layout->ngpio > MAX_GPIO)
+ return -EINVAL;
+
+ if (ngpios < 1 || ngpios > hcg->layout->ngpio) {
+ dev_err(dev, "ngpios must be in [1:%u]\n", hcg->layout->ngpio);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < hcg->layout->ngpio; i++) {
+ if (creg_gpio_validate_pg(dev, hcg, i))
+ return -EINVAL;
+
+ reg_len += hcg->layout->shift[i] + hcg->layout->bit_per_gpio[i];
+ }
+
+ /* Check that we fit in 32 bit register */
+ if (reg_len > 32)
+ return -EINVAL;
+
+ return 0;
+}
+
+static const struct creg_layout hsdk_cs_ctl = {
+ .ngpio = 10,
+ .shift = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ .off = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
+ .on = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
+ .bit_per_gpio = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }
+};
+
+static const struct creg_layout axs10x_flsh_cs_ctl = {
+ .ngpio = 1,
+ .shift = { 0 },
+ .off = { 1 },
+ .on = { 3 },
+ .bit_per_gpio = { 2 }
+};
+
+static const struct of_device_id creg_gpio_ids[] = {
+ {
+ .compatible = "snps,creg-gpio-axs10x",
+ .data = &axs10x_flsh_cs_ctl
+ }, {
+ .compatible = "snps,creg-gpio-hsdk",
+ .data = &hsdk_cs_ctl
+ }, { /* sentinel */ }
+};
+
+static int creg_gpio_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *match;
+ struct device *dev = &pdev->dev;
+ struct creg_gpio *hcg;
+ struct resource *mem;
+ u32 ngpios;
+ int ret;
+
+ hcg = devm_kzalloc(dev, sizeof(struct creg_gpio), GFP_KERNEL);
+ if (!hcg)
+ return -ENOMEM;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ hcg->regs = devm_ioremap_resource(dev, mem);
+ if (IS_ERR(hcg->regs))
+ return PTR_ERR(hcg->regs);
+
+ match = of_match_node(creg_gpio_ids, pdev->dev.of_node);
+ hcg->layout = match->data;
+ if (!hcg->layout)
+ return -EINVAL;
+
+ ret = of_property_read_u32(dev->of_node, "ngpios", &ngpios);
+ if (ret)
+ return ret;
+
+ ret = creg_gpio_validate(dev, hcg, ngpios);
+ if (ret)
+ return ret;
+
+ spin_lock_init(&hcg->lock);
+
+ hcg->gc.label = dev_name(dev);
+ hcg->gc.base = -1;
+ hcg->gc.ngpio = ngpios;
+ hcg->gc.set = creg_gpio_set;
+ hcg->gc.direction_output = creg_gpio_dir_out;
+ hcg->gc.of_node = dev->of_node;
+
+ ret = devm_gpiochip_add_data(dev, &hcg->gc, hcg);
+ if (ret)
+ return ret;
+
+ dev_info(dev, "GPIO controller with %d gpios probed\n", ngpios);
+
+ return 0;
+}
+
+static struct platform_driver creg_gpio_snps_driver = {
+ .driver = {
+ .name = "snps-creg-gpio",
+ .of_match_table = creg_gpio_ids,
+ },
+ .probe = creg_gpio_probe,
+};
+builtin_platform_driver(creg_gpio_snps_driver);
diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c
index a5ece8ea79bc..5c1564fcc24e 100644
--- a/drivers/gpio/gpio-davinci.c
+++ b/drivers/gpio/gpio-davinci.c
@@ -9,6 +9,7 @@
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
+
#include <linux/gpio/driver.h>
#include <linux/errno.h>
#include <linux/kernel.h>
@@ -24,6 +25,12 @@
#include <linux/platform_device.h>
#include <linux/platform_data/gpio-davinci.h>
#include <linux/irqchip/chained_irq.h>
+#include <linux/spinlock.h>
+
+#include <asm-generic/gpio.h>
+
+#define MAX_REGS_BANKS 5
+#define MAX_INT_PER_BANK 32
struct davinci_gpio_regs {
u32 dir;
@@ -41,11 +48,31 @@ struct davinci_gpio_regs {
typedef struct irq_chip *(*gpio_get_irq_chip_cb_t)(unsigned int irq);
#define BINTEN 0x8 /* GPIO Interrupt Per-Bank Enable Register */
-#define MAX_LABEL_SIZE 20
static void __iomem *gpio_base;
static unsigned int offset_array[5] = {0x10, 0x38, 0x60, 0x88, 0xb0};
+struct davinci_gpio_irq_data {
+ void __iomem *regs;
+ struct davinci_gpio_controller *chip;
+ int bank_num;
+};
+
+struct davinci_gpio_controller {
+ struct gpio_chip chip;
+ struct irq_domain *irq_domain;
+ /* Serialize access to GPIO registers */
+ spinlock_t lock;
+ void __iomem *regs[MAX_REGS_BANKS];
+ int gpio_unbanked;
+ int irqs[MAX_INT_PER_BANK];
+};
+
+static inline u32 __gpio_mask(unsigned gpio)
+{
+ return 1 << (gpio % 32);
+}
+
static inline struct davinci_gpio_regs __iomem *irq2regs(struct irq_data *d)
{
struct davinci_gpio_regs __iomem *g;
@@ -166,14 +193,12 @@ of_err:
static int davinci_gpio_probe(struct platform_device *pdev)
{
- static int ctrl_num, bank_base;
- int gpio, bank, i, ret = 0;
+ int bank, i, ret = 0;
unsigned int ngpio, nbank, nirq;
struct davinci_gpio_controller *chips;
struct davinci_gpio_platform_data *pdata;
struct device *dev = &pdev->dev;
struct resource *res;
- char label[MAX_LABEL_SIZE];
pdata = davinci_gpio_get_pdata(pdev);
if (!pdata) {
@@ -207,10 +232,7 @@ static int davinci_gpio_probe(struct platform_device *pdev)
else
nirq = DIV_ROUND_UP(ngpio, 16);
- nbank = DIV_ROUND_UP(ngpio, 32);
- chips = devm_kcalloc(dev,
- nbank, sizeof(struct davinci_gpio_controller),
- GFP_KERNEL);
+ chips = devm_kzalloc(dev, sizeof(*chips), GFP_KERNEL);
if (!chips)
return -ENOMEM;
@@ -228,10 +250,7 @@ static int davinci_gpio_probe(struct platform_device *pdev)
}
}
- snprintf(label, MAX_LABEL_SIZE, "davinci_gpio.%d", ctrl_num++);
- chips->chip.label = devm_kstrdup(dev, label, GFP_KERNEL);
- if (!chips->chip.label)
- return -ENOMEM;
+ chips->chip.label = dev_name(dev);
chips->chip.direction_input = davinci_direction_in;
chips->chip.get = davinci_gpio_get;
@@ -239,7 +258,7 @@ static int davinci_gpio_probe(struct platform_device *pdev)
chips->chip.set = davinci_gpio_set;
chips->chip.ngpio = ngpio;
- chips->chip.base = bank_base;
+ chips->chip.base = -1;
#ifdef CONFIG_OF_GPIO
chips->chip.of_gpio_n_cells = 2;
@@ -252,28 +271,21 @@ static int davinci_gpio_probe(struct platform_device *pdev)
}
#endif
spin_lock_init(&chips->lock);
- bank_base += ngpio;
- for (gpio = 0, bank = 0; gpio < ngpio; gpio += 32, bank++)
+ nbank = DIV_ROUND_UP(ngpio, 32);
+ for (bank = 0; bank < nbank; bank++)
chips->regs[bank] = gpio_base + offset_array[bank];
ret = devm_gpiochip_add_data(dev, &chips->chip, chips);
if (ret)
- goto err;
+ return ret;
platform_set_drvdata(pdev, chips);
ret = davinci_gpio_irq_setup(pdev);
if (ret)
- goto err;
+ return ret;
return 0;
-
-err:
- /* Revert the static variable increments */
- ctrl_num--;
- bank_base -= ngpio;
-
- return ret;
}
/*--------------------------------------------------------------------------*/
diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c
index 45d384039e9b..71728d6e0bca 100644
--- a/drivers/gpio/gpio-ep93xx.c
+++ b/drivers/gpio/gpio-ep93xx.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Generic EP93xx GPIO handling
*
@@ -6,10 +7,6 @@
*
* Based on code originally from:
* linux/arch/arm/mach-ep93xx/core.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/init.h>
@@ -19,16 +16,26 @@
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/gpio/driver.h>
-/* FIXME: this is here for gpio_to_irq() - get rid of this! */
-#include <linux/gpio.h>
+#include <linux/bitops.h>
+
+#define EP93XX_GPIO_F_INT_STATUS 0x5c
+#define EP93XX_GPIO_A_INT_STATUS 0xa0
+#define EP93XX_GPIO_B_INT_STATUS 0xbc
+
+/* Maximum value for gpio line identifiers */
+#define EP93XX_GPIO_LINE_MAX 63
-#include <mach/hardware.h>
-#include <mach/gpio-ep93xx.h>
+/* Maximum value for irq capable line identifiers */
+#define EP93XX_GPIO_LINE_MAX_IRQ 23
-#define irq_to_gpio(irq) ((irq) - gpio_to_irq(0))
+/*
+ * Static mapping of GPIO bank F IRQS:
+ * F0..F7 (16..24) to irq 80..87.
+ */
+#define EP93XX_GPIO_F_IRQ_BASE 80
struct ep93xx_gpio {
- void __iomem *mmio_base;
+ void __iomem *base;
struct gpio_chip gc[8];
};
@@ -48,27 +55,45 @@ static const u8 eoi_register_offset[3] = { 0x98, 0xb4, 0x54 };
static const u8 int_en_register_offset[3] = { 0x9c, 0xb8, 0x58 };
static const u8 int_debounce_register_offset[3] = { 0xa8, 0xc4, 0x64 };
-static void ep93xx_gpio_update_int_params(unsigned port)
+static void ep93xx_gpio_update_int_params(struct ep93xx_gpio *epg, unsigned port)
{
BUG_ON(port > 2);
- writeb_relaxed(0, EP93XX_GPIO_REG(int_en_register_offset[port]));
+ writeb_relaxed(0, epg->base + int_en_register_offset[port]);
writeb_relaxed(gpio_int_type2[port],
- EP93XX_GPIO_REG(int_type2_register_offset[port]));
+ epg->base + int_type2_register_offset[port]);
writeb_relaxed(gpio_int_type1[port],
- EP93XX_GPIO_REG(int_type1_register_offset[port]));
+ epg->base + int_type1_register_offset[port]);
writeb(gpio_int_unmasked[port] & gpio_int_enabled[port],
- EP93XX_GPIO_REG(int_en_register_offset[port]));
+ epg->base + int_en_register_offset[port]);
+}
+
+static int ep93xx_gpio_port(struct gpio_chip *gc)
+{
+ struct ep93xx_gpio *epg = gpiochip_get_data(gc);
+ int port = 0;
+
+ while (port < ARRAY_SIZE(epg->gc) && gc != &epg->gc[port])
+ port++;
+
+ /* This should not happen but is there as a last safeguard */
+ if (port == ARRAY_SIZE(epg->gc)) {
+ pr_crit("can't find the GPIO port\n");
+ return 0;
+ }
+
+ return port;
}
-static void ep93xx_gpio_int_debounce(unsigned int irq, bool enable)
+static void ep93xx_gpio_int_debounce(struct gpio_chip *gc,
+ unsigned int offset, bool enable)
{
- int line = irq_to_gpio(irq);
- int port = line >> 3;
- int port_mask = 1 << (line & 7);
+ struct ep93xx_gpio *epg = gpiochip_get_data(gc);
+ int port = ep93xx_gpio_port(gc);
+ int port_mask = BIT(offset);
if (enable)
gpio_int_debounce[port] |= port_mask;
@@ -76,29 +101,36 @@ static void ep93xx_gpio_int_debounce(unsigned int irq, bool enable)
gpio_int_debounce[port] &= ~port_mask;
writeb(gpio_int_debounce[port],
- EP93XX_GPIO_REG(int_debounce_register_offset[port]));
+ epg->base + int_debounce_register_offset[port]);
}
static void ep93xx_gpio_ab_irq_handler(struct irq_desc *desc)
{
- unsigned char status;
- int i;
+ struct gpio_chip *gc = irq_desc_get_handler_data(desc);
+ struct ep93xx_gpio *epg = gpiochip_get_data(gc);
+ struct irq_chip *irqchip = irq_desc_get_chip(desc);
+ unsigned long stat;
+ int offset;
- status = readb(EP93XX_GPIO_A_INT_STATUS);
- for (i = 0; i < 8; i++) {
- if (status & (1 << i)) {
- int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_A(0)) + i;
- generic_handle_irq(gpio_irq);
- }
- }
+ chained_irq_enter(irqchip, desc);
- status = readb(EP93XX_GPIO_B_INT_STATUS);
- for (i = 0; i < 8; i++) {
- if (status & (1 << i)) {
- int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_B(0)) + i;
- generic_handle_irq(gpio_irq);
- }
- }
+ /*
+ * Dispatch the IRQs to the irqdomain of each A and B
+ * gpiochip irqdomains depending on what has fired.
+ * The tricky part is that the IRQ line is shared
+ * between bank A and B and each has their own gpiochip.
+ */
+ stat = readb(epg->base + EP93XX_GPIO_A_INT_STATUS);
+ for_each_set_bit(offset, &stat, 8)
+ generic_handle_irq(irq_find_mapping(epg->gc[0].irq.domain,
+ offset));
+
+ stat = readb(epg->base + EP93XX_GPIO_B_INT_STATUS);
+ for_each_set_bit(offset, &stat, 8)
+ generic_handle_irq(irq_find_mapping(epg->gc[1].irq.domain,
+ offset));
+
+ chained_irq_exit(irqchip, desc);
}
static void ep93xx_gpio_f_irq_handler(struct irq_desc *desc)
@@ -106,60 +138,67 @@ static void ep93xx_gpio_f_irq_handler(struct irq_desc *desc)
/*
* map discontiguous hw irq range to continuous sw irq range:
*
- * IRQ_EP93XX_GPIO{0..7}MUX -> gpio_to_irq(EP93XX_GPIO_LINE_F({0..7})
+ * IRQ_EP93XX_GPIO{0..7}MUX -> EP93XX_GPIO_LINE_F{0..7}
*/
+ struct irq_chip *irqchip = irq_desc_get_chip(desc);
unsigned int irq = irq_desc_get_irq(desc);
int port_f_idx = ((irq + 1) & 7) ^ 4; /* {19..22,47..50} -> {0..7} */
- int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_F(0)) + port_f_idx;
+ int gpio_irq = EP93XX_GPIO_F_IRQ_BASE + port_f_idx;
+ chained_irq_enter(irqchip, desc);
generic_handle_irq(gpio_irq);
+ chained_irq_exit(irqchip, desc);
}
static void ep93xx_gpio_irq_ack(struct irq_data *d)
{
- int line = irq_to_gpio(d->irq);
- int port = line >> 3;
- int port_mask = 1 << (line & 7);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct ep93xx_gpio *epg = gpiochip_get_data(gc);
+ int port = ep93xx_gpio_port(gc);
+ int port_mask = BIT(d->irq & 7);
if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH) {
gpio_int_type2[port] ^= port_mask; /* switch edge direction */
- ep93xx_gpio_update_int_params(port);
+ ep93xx_gpio_update_int_params(epg, port);
}
- writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port]));
+ writeb(port_mask, epg->base + eoi_register_offset[port]);
}
static void ep93xx_gpio_irq_mask_ack(struct irq_data *d)
{
- int line = irq_to_gpio(d->irq);
- int port = line >> 3;
- int port_mask = 1 << (line & 7);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct ep93xx_gpio *epg = gpiochip_get_data(gc);
+ int port = ep93xx_gpio_port(gc);
+ int port_mask = BIT(d->irq & 7);
if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH)
gpio_int_type2[port] ^= port_mask; /* switch edge direction */
gpio_int_unmasked[port] &= ~port_mask;
- ep93xx_gpio_update_int_params(port);
+ ep93xx_gpio_update_int_params(epg, port);
- writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port]));
+ writeb(port_mask, epg->base + eoi_register_offset[port]);
}
static void ep93xx_gpio_irq_mask(struct irq_data *d)
{
- int line = irq_to_gpio(d->irq);
- int port = line >> 3;
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct ep93xx_gpio *epg = gpiochip_get_data(gc);
+ int port = ep93xx_gpio_port(gc);
- gpio_int_unmasked[port] &= ~(1 << (line & 7));
- ep93xx_gpio_update_int_params(port);
+ gpio_int_unmasked[port] &= ~BIT(d->irq & 7);
+ ep93xx_gpio_update_int_params(epg, port);
}
static void ep93xx_gpio_irq_unmask(struct irq_data *d)
{
- int line = irq_to_gpio(d->irq);
- int port = line >> 3;
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct ep93xx_gpio *epg = gpiochip_get_data(gc);
+ int port = ep93xx_gpio_port(gc);
- gpio_int_unmasked[port] |= 1 << (line & 7);
- ep93xx_gpio_update_int_params(port);
+ gpio_int_unmasked[port] |= BIT(d->irq & 7);
+ ep93xx_gpio_update_int_params(epg, port);
}
/*
@@ -169,12 +208,14 @@ static void ep93xx_gpio_irq_unmask(struct irq_data *d)
*/
static int ep93xx_gpio_irq_type(struct irq_data *d, unsigned int type)
{
- const int gpio = irq_to_gpio(d->irq);
- const int port = gpio >> 3;
- const int port_mask = 1 << (gpio & 7);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct ep93xx_gpio *epg = gpiochip_get_data(gc);
+ int port = ep93xx_gpio_port(gc);
+ int offset = d->irq & 7;
+ int port_mask = BIT(offset);
irq_flow_handler_t handler;
- gpio_direction_input(gpio);
+ gc->direction_input(gc, offset);
switch (type) {
case IRQ_TYPE_EDGE_RISING:
@@ -200,7 +241,7 @@ static int ep93xx_gpio_irq_type(struct irq_data *d, unsigned int type)
case IRQ_TYPE_EDGE_BOTH:
gpio_int_type1[port] |= port_mask;
/* set initial polarity based on current input level */
- if (gpio_get_value(gpio))
+ if (gc->get(gc, offset))
gpio_int_type2[port] &= ~port_mask; /* falling */
else
gpio_int_type2[port] |= port_mask; /* rising */
@@ -214,7 +255,7 @@ static int ep93xx_gpio_irq_type(struct irq_data *d, unsigned int type)
gpio_int_enabled[port] |= port_mask;
- ep93xx_gpio_update_int_params(port);
+ ep93xx_gpio_update_int_params(epg, port);
return 0;
}
@@ -228,35 +269,53 @@ static struct irq_chip ep93xx_gpio_irq_chip = {
.irq_set_type = ep93xx_gpio_irq_type,
};
-static void ep93xx_gpio_init_irq(void)
+static int ep93xx_gpio_init_irq(struct platform_device *pdev,
+ struct ep93xx_gpio *epg)
{
+ int ab_parent_irq = platform_get_irq(pdev, 0);
+ struct device *dev = &pdev->dev;
int gpio_irq;
+ int ret;
+ int i;
- for (gpio_irq = gpio_to_irq(0);
- gpio_irq <= gpio_to_irq(EP93XX_GPIO_LINE_MAX_IRQ); ++gpio_irq) {
+ /* The A bank */
+ ret = gpiochip_irqchip_add(&epg->gc[0], &ep93xx_gpio_irq_chip,
+ 64, handle_level_irq,
+ IRQ_TYPE_NONE);
+ if (ret) {
+ dev_err(dev, "Could not add irqchip 0\n");
+ return ret;
+ }
+ gpiochip_set_chained_irqchip(&epg->gc[0], &ep93xx_gpio_irq_chip,
+ ab_parent_irq,
+ ep93xx_gpio_ab_irq_handler);
+
+ /* The B bank */
+ ret = gpiochip_irqchip_add(&epg->gc[1], &ep93xx_gpio_irq_chip,
+ 72, handle_level_irq,
+ IRQ_TYPE_NONE);
+ if (ret) {
+ dev_err(dev, "Could not add irqchip 1\n");
+ return ret;
+ }
+ gpiochip_set_chained_irqchip(&epg->gc[1], &ep93xx_gpio_irq_chip,
+ ab_parent_irq,
+ ep93xx_gpio_ab_irq_handler);
+
+ /* The F bank */
+ for (i = 0; i < 8; i++) {
+ gpio_irq = EP93XX_GPIO_F_IRQ_BASE + i;
+ irq_set_chip_data(gpio_irq, &epg->gc[5]);
irq_set_chip_and_handler(gpio_irq, &ep93xx_gpio_irq_chip,
handle_level_irq);
irq_clear_status_flags(gpio_irq, IRQ_NOREQUEST);
}
- irq_set_chained_handler(IRQ_EP93XX_GPIO_AB,
- ep93xx_gpio_ab_irq_handler);
- irq_set_chained_handler(IRQ_EP93XX_GPIO0MUX,
- ep93xx_gpio_f_irq_handler);
- irq_set_chained_handler(IRQ_EP93XX_GPIO1MUX,
- ep93xx_gpio_f_irq_handler);
- irq_set_chained_handler(IRQ_EP93XX_GPIO2MUX,
- ep93xx_gpio_f_irq_handler);
- irq_set_chained_handler(IRQ_EP93XX_GPIO3MUX,
- ep93xx_gpio_f_irq_handler);
- irq_set_chained_handler(IRQ_EP93XX_GPIO4MUX,
- ep93xx_gpio_f_irq_handler);
- irq_set_chained_handler(IRQ_EP93XX_GPIO5MUX,
- ep93xx_gpio_f_irq_handler);
- irq_set_chained_handler(IRQ_EP93XX_GPIO6MUX,
- ep93xx_gpio_f_irq_handler);
- irq_set_chained_handler(IRQ_EP93XX_GPIO7MUX,
- ep93xx_gpio_f_irq_handler);
+ for (i = 1; i <= 8; i++)
+ irq_set_chained_handler_and_data(platform_get_irq(pdev, i),
+ ep93xx_gpio_f_irq_handler,
+ &epg->gc[i]);
+ return 0;
}
@@ -268,68 +327,54 @@ struct ep93xx_gpio_bank {
int data;
int dir;
int base;
- bool has_debounce;
+ bool has_irq;
};
-#define EP93XX_GPIO_BANK(_label, _data, _dir, _base, _debounce) \
+#define EP93XX_GPIO_BANK(_label, _data, _dir, _base, _has_irq) \
{ \
.label = _label, \
.data = _data, \
.dir = _dir, \
.base = _base, \
- .has_debounce = _debounce, \
+ .has_irq = _has_irq, \
}
static struct ep93xx_gpio_bank ep93xx_gpio_banks[] = {
- EP93XX_GPIO_BANK("A", 0x00, 0x10, 0, true),
- EP93XX_GPIO_BANK("B", 0x04, 0x14, 8, true),
+ EP93XX_GPIO_BANK("A", 0x00, 0x10, 0, true), /* Bank A has 8 IRQs */
+ EP93XX_GPIO_BANK("B", 0x04, 0x14, 8, true), /* Bank B has 8 IRQs */
EP93XX_GPIO_BANK("C", 0x08, 0x18, 40, false),
EP93XX_GPIO_BANK("D", 0x0c, 0x1c, 24, false),
EP93XX_GPIO_BANK("E", 0x20, 0x24, 32, false),
- EP93XX_GPIO_BANK("F", 0x30, 0x34, 16, true),
+ EP93XX_GPIO_BANK("F", 0x30, 0x34, 16, true), /* Bank F has 8 IRQs */
EP93XX_GPIO_BANK("G", 0x38, 0x3c, 48, false),
EP93XX_GPIO_BANK("H", 0x40, 0x44, 56, false),
};
-static int ep93xx_gpio_set_config(struct gpio_chip *chip, unsigned offset,
+static int ep93xx_gpio_set_config(struct gpio_chip *gc, unsigned offset,
unsigned long config)
{
- int gpio = chip->base + offset;
- int irq = gpio_to_irq(gpio);
u32 debounce;
if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
return -ENOTSUPP;
- if (irq < 0)
- return -EINVAL;
-
debounce = pinconf_to_config_argument(config);
- ep93xx_gpio_int_debounce(irq, debounce ? true : false);
+ ep93xx_gpio_int_debounce(gc, offset, debounce ? true : false);
return 0;
}
-/*
- * Map GPIO A0..A7 (0..7) to irq 64..71,
- * B0..B7 (7..15) to irq 72..79, and
- * F0..F7 (16..24) to irq 80..87.
- */
-static int ep93xx_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+static int ep93xx_gpio_f_to_irq(struct gpio_chip *gc, unsigned offset)
{
- int gpio = chip->base + offset;
-
- if (gpio > EP93XX_GPIO_LINE_MAX_IRQ)
- return -EINVAL;
-
- return 64 + gpio;
+ return EP93XX_GPIO_F_IRQ_BASE + offset;
}
static int ep93xx_gpio_add_bank(struct gpio_chip *gc, struct device *dev,
- void __iomem *mmio_base, struct ep93xx_gpio_bank *bank)
+ struct ep93xx_gpio *epg,
+ struct ep93xx_gpio_bank *bank)
{
- void __iomem *data = mmio_base + bank->data;
- void __iomem *dir = mmio_base + bank->dir;
+ void __iomem *data = epg->base + bank->data;
+ void __iomem *dir = epg->base + bank->dir;
int err;
err = bgpio_init(gc, dev, 1, data, NULL, NULL, dir, NULL, 0);
@@ -339,41 +384,41 @@ static int ep93xx_gpio_add_bank(struct gpio_chip *gc, struct device *dev,
gc->label = bank->label;
gc->base = bank->base;
- if (bank->has_debounce) {
+ if (bank->has_irq)
gc->set_config = ep93xx_gpio_set_config;
- gc->to_irq = ep93xx_gpio_to_irq;
- }
- return devm_gpiochip_add_data(dev, gc, NULL);
+ return devm_gpiochip_add_data(dev, gc, epg);
}
static int ep93xx_gpio_probe(struct platform_device *pdev)
{
- struct ep93xx_gpio *ep93xx_gpio;
+ struct ep93xx_gpio *epg;
struct resource *res;
int i;
struct device *dev = &pdev->dev;
- ep93xx_gpio = devm_kzalloc(dev, sizeof(struct ep93xx_gpio), GFP_KERNEL);
- if (!ep93xx_gpio)
+ epg = devm_kzalloc(dev, sizeof(*epg), GFP_KERNEL);
+ if (!epg)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- ep93xx_gpio->mmio_base = devm_ioremap_resource(dev, res);
- if (IS_ERR(ep93xx_gpio->mmio_base))
- return PTR_ERR(ep93xx_gpio->mmio_base);
+ epg->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(epg->base))
+ return PTR_ERR(epg->base);
for (i = 0; i < ARRAY_SIZE(ep93xx_gpio_banks); i++) {
- struct gpio_chip *gc = &ep93xx_gpio->gc[i];
+ struct gpio_chip *gc = &epg->gc[i];
struct ep93xx_gpio_bank *bank = &ep93xx_gpio_banks[i];
- if (ep93xx_gpio_add_bank(gc, &pdev->dev,
- ep93xx_gpio->mmio_base, bank))
+ if (ep93xx_gpio_add_bank(gc, &pdev->dev, epg, bank))
dev_warn(&pdev->dev, "Unable to add gpio bank %s\n",
- bank->label);
+ bank->label);
+ /* Only bank F has especially funky IRQ handling */
+ if (i == 5)
+ gc->to_irq = ep93xx_gpio_f_to_irq;
}
- ep93xx_gpio_init_irq();
+ ep93xx_gpio_init_irq(pdev, epg);
return 0;
}
diff --git a/drivers/gpio/gpio-ftgpio010.c b/drivers/gpio/gpio-ftgpio010.c
index 868bf8501560..95f578804b0e 100644
--- a/drivers/gpio/gpio-ftgpio010.c
+++ b/drivers/gpio/gpio-ftgpio010.c
@@ -15,6 +15,7 @@
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/bitops.h>
+#include <linux/clk.h>
/* GPIO registers definition */
#define GPIO_DATA_OUT 0x00
@@ -40,11 +41,14 @@
* struct ftgpio_gpio - Gemini GPIO state container
* @dev: containing device for this instance
* @gc: gpiochip for this instance
+ * @base: remapped I/O-memory base
+ * @clk: silicon clock
*/
struct ftgpio_gpio {
struct device *dev;
struct gpio_chip gc;
void __iomem *base;
+ struct clk *clk;
};
static void ftgpio_gpio_ack_irq(struct irq_data *d)
@@ -157,6 +161,73 @@ static void ftgpio_gpio_irq_handler(struct irq_desc *desc)
chained_irq_exit(irqchip, desc);
}
+static int ftgpio_gpio_set_config(struct gpio_chip *gc, unsigned int offset,
+ unsigned long config)
+{
+ enum pin_config_param param = pinconf_to_config_param(config);
+ u32 arg = pinconf_to_config_argument(config);
+ struct ftgpio_gpio *g = gpiochip_get_data(gc);
+ unsigned long pclk_freq;
+ u32 deb_div;
+ u32 val;
+
+ if (param != PIN_CONFIG_INPUT_DEBOUNCE)
+ return -ENOTSUPP;
+
+ /*
+ * Debounce only works if interrupts are enabled. The manual
+ * states that if PCLK is 66 MHz, and this is set to 0x7D0, then
+ * PCLK is divided down to 33 kHz for the debounce timer. 0x7D0 is
+ * 2000 decimal, so what they mean is simply that the PCLK is
+ * divided by this value.
+ *
+ * As we get a debounce setting in microseconds, we calculate the
+ * desired period time and see if we can get a suitable debounce
+ * time.
+ */
+ pclk_freq = clk_get_rate(g->clk);
+ deb_div = DIV_ROUND_CLOSEST(pclk_freq, arg);
+
+ /* This register is only 24 bits wide */
+ if (deb_div > (1 << 24))
+ return -ENOTSUPP;
+
+ dev_dbg(g->dev, "prescale divisor: %08x, resulting frequency %lu Hz\n",
+ deb_div, (pclk_freq/deb_div));
+
+ val = readl(g->base + GPIO_DEBOUNCE_PRESCALE);
+ if (val == deb_div) {
+ /*
+ * The debounce timer happens to already be set to the
+ * desireable value, what a coincidence! We can just enable
+ * debounce on this GPIO line and return. This happens more
+ * often than you think, for example when all GPIO keys
+ * on a system are requesting the same debounce interval.
+ */
+ val = readl(g->base + GPIO_DEBOUNCE_EN);
+ val |= BIT(offset);
+ writel(val, g->base + GPIO_DEBOUNCE_EN);
+ return 0;
+ }
+
+ val = readl(g->base + GPIO_DEBOUNCE_EN);
+ if (val) {
+ /*
+ * Oh no! Someone is already using the debounce with
+ * another setting than what we need. Bummer.
+ */
+ return -ENOTSUPP;
+ }
+
+ /* First come, first serve */
+ writel(deb_div, g->base + GPIO_DEBOUNCE_PRESCALE);
+ /* Enable debounce */
+ val |= BIT(offset);
+ writel(val, g->base + GPIO_DEBOUNCE_EN);
+
+ return 0;
+}
+
static int ftgpio_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -180,6 +251,19 @@ static int ftgpio_gpio_probe(struct platform_device *pdev)
if (irq <= 0)
return irq ? irq : -EINVAL;
+ g->clk = devm_clk_get(dev, NULL);
+ if (!IS_ERR(g->clk)) {
+ ret = clk_prepare_enable(g->clk);
+ if (ret)
+ return ret;
+ } else if (PTR_ERR(g->clk) == -EPROBE_DEFER) {
+ /*
+ * Percolate deferrals, for anything else,
+ * just live without the clocking.
+ */
+ return PTR_ERR(g->clk);
+ }
+
ret = bgpio_init(&g->gc, dev, 4,
g->base + GPIO_DATA_IN,
g->base + GPIO_DATA_SET,
@@ -189,7 +273,7 @@ static int ftgpio_gpio_probe(struct platform_device *pdev)
0);
if (ret) {
dev_err(dev, "unable to init generic GPIO\n");
- return ret;
+ goto dis_clk;
}
g->gc.label = "FTGPIO010";
g->gc.base = -1;
@@ -197,28 +281,50 @@ static int ftgpio_gpio_probe(struct platform_device *pdev)
g->gc.owner = THIS_MODULE;
/* ngpio is set by bgpio_init() */
+ /* We need a silicon clock to do debounce */
+ if (!IS_ERR(g->clk))
+ g->gc.set_config = ftgpio_gpio_set_config;
+
ret = devm_gpiochip_add_data(dev, &g->gc, g);
if (ret)
- return ret;
+ goto dis_clk;
/* Disable, unmask and clear all interrupts */
writel(0x0, g->base + GPIO_INT_EN);
writel(0x0, g->base + GPIO_INT_MASK);
writel(~0x0, g->base + GPIO_INT_CLR);
+ /* Clear any use of debounce */
+ writel(0x0, g->base + GPIO_DEBOUNCE_EN);
+
ret = gpiochip_irqchip_add(&g->gc, &ftgpio_gpio_irqchip,
0, handle_bad_irq,
IRQ_TYPE_NONE);
if (ret) {
dev_info(dev, "could not add irqchip\n");
- return ret;
+ goto dis_clk;
}
gpiochip_set_chained_irqchip(&g->gc, &ftgpio_gpio_irqchip,
irq, ftgpio_gpio_irq_handler);
+ platform_set_drvdata(pdev, g);
dev_info(dev, "FTGPIO010 @%p registered\n", g->base);
return 0;
+
+dis_clk:
+ if (!IS_ERR(g->clk))
+ clk_disable_unprepare(g->clk);
+ return ret;
+}
+
+static int ftgpio_gpio_remove(struct platform_device *pdev)
+{
+ struct ftgpio_gpio *g = platform_get_drvdata(pdev);
+
+ if (!IS_ERR(g->clk))
+ clk_disable_unprepare(g->clk);
+ return 0;
}
static const struct of_device_id ftgpio_gpio_of_match[] = {
@@ -239,6 +345,7 @@ static struct platform_driver ftgpio_gpio_driver = {
.name = "ftgpio010-gpio",
.of_match_table = of_match_ptr(ftgpio_gpio_of_match),
},
- .probe = ftgpio_gpio_probe,
+ .probe = ftgpio_gpio_probe,
+ .remove = ftgpio_gpio_remove,
};
builtin_platform_driver(ftgpio_gpio_driver);
diff --git a/drivers/gpio/gpio-htc-egpio.c b/drivers/gpio/gpio-htc-egpio.c
index ad6e5b518669..9d3ac51a765c 100644
--- a/drivers/gpio/gpio-htc-egpio.c
+++ b/drivers/gpio/gpio-htc-egpio.c
@@ -189,7 +189,6 @@ static void egpio_set(struct gpio_chip *chip, unsigned offset, int value)
unsigned long flag;
struct egpio_chip *egpio;
struct egpio_info *ei;
- unsigned bit;
int pos;
int reg;
int shift;
@@ -199,7 +198,6 @@ static void egpio_set(struct gpio_chip *chip, unsigned offset, int value)
egpio = gpiochip_get_data(chip);
ei = dev_get_drvdata(egpio->dev);
- bit = egpio_bit(ei, offset);
pos = egpio_pos(ei, offset);
reg = egpio->reg_start + pos;
shift = pos << ei->reg_shift;
@@ -334,7 +332,13 @@ static int __init egpio_probe(struct platform_device *pdev)
ei->chip[i].is_out = pdata->chip[i].direction;
ei->chip[i].dev = &(pdev->dev);
chip = &(ei->chip[i].chip);
- chip->label = "htc-egpio";
+ chip->label = devm_kasprintf(&pdev->dev, GFP_KERNEL,
+ "htc-egpio-%d",
+ i);
+ if (!chip->label) {
+ ret = -ENOMEM;
+ goto fail;
+ }
chip->parent = &pdev->dev;
chip->owner = THIS_MODULE;
chip->get = egpio_get;
diff --git a/drivers/gpio/gpio-ingenic.c b/drivers/gpio/gpio-ingenic.c
deleted file mode 100644
index e738e384a5ca..000000000000
--- a/drivers/gpio/gpio-ingenic.c
+++ /dev/null
@@ -1,392 +0,0 @@
-/*
- * Ingenic JZ47xx GPIO driver
- *
- * Copyright (c) 2017 Paul Cercueil <paul@crapouillou.net>
- *
- * License terms: GNU General Public License (GPL) version 2
- */
-
-#include <linux/gpio/driver.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
-#include <linux/of_irq.h>
-#include <linux/pinctrl/consumer.h>
-#include <linux/regmap.h>
-
-#define GPIO_PIN 0x00
-#define GPIO_MSK 0x20
-
-#define JZ4740_GPIO_DATA 0x10
-#define JZ4740_GPIO_SELECT 0x50
-#define JZ4740_GPIO_DIR 0x60
-#define JZ4740_GPIO_TRIG 0x70
-#define JZ4740_GPIO_FLAG 0x80
-
-#define JZ4770_GPIO_INT 0x10
-#define JZ4770_GPIO_PAT1 0x30
-#define JZ4770_GPIO_PAT0 0x40
-#define JZ4770_GPIO_FLAG 0x50
-
-#define REG_SET(x) ((x) + 0x4)
-#define REG_CLEAR(x) ((x) + 0x8)
-
-enum jz_version {
- ID_JZ4740,
- ID_JZ4770,
- ID_JZ4780,
-};
-
-struct ingenic_gpio_chip {
- struct regmap *map;
- struct gpio_chip gc;
- struct irq_chip irq_chip;
- unsigned int irq, reg_base;
- enum jz_version version;
-};
-
-static u32 gpio_ingenic_read_reg(struct ingenic_gpio_chip *jzgc, u8 reg)
-{
- unsigned int val;
-
- regmap_read(jzgc->map, jzgc->reg_base + reg, &val);
-
- return (u32) val;
-}
-
-static void gpio_ingenic_set_bit(struct ingenic_gpio_chip *jzgc,
- u8 reg, u8 offset, bool set)
-{
- if (set)
- reg = REG_SET(reg);
- else
- reg = REG_CLEAR(reg);
-
- regmap_write(jzgc->map, jzgc->reg_base + reg, BIT(offset));
-}
-
-static inline bool gpio_get_value(struct ingenic_gpio_chip *jzgc, u8 offset)
-{
- unsigned int val = gpio_ingenic_read_reg(jzgc, GPIO_PIN);
-
- return !!(val & BIT(offset));
-}
-
-static void gpio_set_value(struct ingenic_gpio_chip *jzgc, u8 offset, int value)
-{
- if (jzgc->version >= ID_JZ4770)
- gpio_ingenic_set_bit(jzgc, JZ4770_GPIO_PAT0, offset, !!value);
- else
- gpio_ingenic_set_bit(jzgc, JZ4740_GPIO_DATA, offset, !!value);
-}
-
-static void irq_set_type(struct ingenic_gpio_chip *jzgc,
- u8 offset, unsigned int type)
-{
- u8 reg1, reg2;
-
- if (jzgc->version >= ID_JZ4770) {
- reg1 = JZ4770_GPIO_PAT1;
- reg2 = JZ4770_GPIO_PAT0;
- } else {
- reg1 = JZ4740_GPIO_TRIG;
- reg2 = JZ4740_GPIO_DIR;
- }
-
- switch (type) {
- case IRQ_TYPE_EDGE_RISING:
- gpio_ingenic_set_bit(jzgc, reg2, offset, true);
- gpio_ingenic_set_bit(jzgc, reg1, offset, true);
- break;
- case IRQ_TYPE_EDGE_FALLING:
- gpio_ingenic_set_bit(jzgc, reg2, offset, false);
- gpio_ingenic_set_bit(jzgc, reg1, offset, true);
- break;
- case IRQ_TYPE_LEVEL_HIGH:
- gpio_ingenic_set_bit(jzgc, reg2, offset, true);
- gpio_ingenic_set_bit(jzgc, reg1, offset, false);
- break;
- case IRQ_TYPE_LEVEL_LOW:
- default:
- gpio_ingenic_set_bit(jzgc, reg2, offset, false);
- gpio_ingenic_set_bit(jzgc, reg1, offset, false);
- break;
- }
-}
-
-static void ingenic_gpio_irq_mask(struct irq_data *irqd)
-{
- struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
- struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
-
- gpio_ingenic_set_bit(jzgc, GPIO_MSK, irqd->hwirq, true);
-}
-
-static void ingenic_gpio_irq_unmask(struct irq_data *irqd)
-{
- struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
- struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
-
- gpio_ingenic_set_bit(jzgc, GPIO_MSK, irqd->hwirq, false);
-}
-
-static void ingenic_gpio_irq_enable(struct irq_data *irqd)
-{
- struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
- struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
- int irq = irqd->hwirq;
-
- if (jzgc->version >= ID_JZ4770)
- gpio_ingenic_set_bit(jzgc, JZ4770_GPIO_INT, irq, true);
- else
- gpio_ingenic_set_bit(jzgc, JZ4740_GPIO_SELECT, irq, true);
-
- ingenic_gpio_irq_unmask(irqd);
-}
-
-static void ingenic_gpio_irq_disable(struct irq_data *irqd)
-{
- struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
- struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
- int irq = irqd->hwirq;
-
- ingenic_gpio_irq_mask(irqd);
-
- if (jzgc->version >= ID_JZ4770)
- gpio_ingenic_set_bit(jzgc, JZ4770_GPIO_INT, irq, false);
- else
- gpio_ingenic_set_bit(jzgc, JZ4740_GPIO_SELECT, irq, false);
-}
-
-static void ingenic_gpio_irq_ack(struct irq_data *irqd)
-{
- struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
- struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
- int irq = irqd->hwirq;
- bool high;
-
- if (irqd_get_trigger_type(irqd) == IRQ_TYPE_EDGE_BOTH) {
- /*
- * Switch to an interrupt for the opposite edge to the one that
- * triggered the interrupt being ACKed.
- */
- high = gpio_get_value(jzgc, irq);
- if (high)
- irq_set_type(jzgc, irq, IRQ_TYPE_EDGE_FALLING);
- else
- irq_set_type(jzgc, irq, IRQ_TYPE_EDGE_RISING);
- }
-
- if (jzgc->version >= ID_JZ4770)
- gpio_ingenic_set_bit(jzgc, JZ4770_GPIO_FLAG, irq, false);
- else
- gpio_ingenic_set_bit(jzgc, JZ4740_GPIO_DATA, irq, true);
-}
-
-static int ingenic_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
-{
- struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
- struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
-
- switch (type) {
- case IRQ_TYPE_EDGE_BOTH:
- case IRQ_TYPE_EDGE_RISING:
- case IRQ_TYPE_EDGE_FALLING:
- irq_set_handler_locked(irqd, handle_edge_irq);
- break;
- case IRQ_TYPE_LEVEL_HIGH:
- case IRQ_TYPE_LEVEL_LOW:
- irq_set_handler_locked(irqd, handle_level_irq);
- break;
- default:
- irq_set_handler_locked(irqd, handle_bad_irq);
- }
-
- if (type == IRQ_TYPE_EDGE_BOTH) {
- /*
- * The hardware does not support interrupts on both edges. The
- * best we can do is to set up a single-edge interrupt and then
- * switch to the opposing edge when ACKing the interrupt.
- */
- bool high = gpio_get_value(jzgc, irqd->hwirq);
-
- type = high ? IRQ_TYPE_EDGE_FALLING : IRQ_TYPE_EDGE_RISING;
- }
-
- irq_set_type(jzgc, irqd->hwirq, type);
- return 0;
-}
-
-static int ingenic_gpio_irq_set_wake(struct irq_data *irqd, unsigned int on)
-{
- struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
- struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
-
- return irq_set_irq_wake(jzgc->irq, on);
-}
-
-static void ingenic_gpio_irq_handler(struct irq_desc *desc)
-{
- struct gpio_chip *gc = irq_desc_get_handler_data(desc);
- struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
- struct irq_chip *irq_chip = irq_data_get_irq_chip(&desc->irq_data);
- unsigned long flag, i;
-
- chained_irq_enter(irq_chip, desc);
-
- if (jzgc->version >= ID_JZ4770)
- flag = gpio_ingenic_read_reg(jzgc, JZ4770_GPIO_FLAG);
- else
- flag = gpio_ingenic_read_reg(jzgc, JZ4740_GPIO_FLAG);
-
- for_each_set_bit(i, &flag, 32)
- generic_handle_irq(irq_linear_revmap(gc->irq.domain, i));
- chained_irq_exit(irq_chip, desc);
-}
-
-static void ingenic_gpio_set(struct gpio_chip *gc,
- unsigned int offset, int value)
-{
- struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
-
- gpio_set_value(jzgc, offset, value);
-}
-
-static int ingenic_gpio_get(struct gpio_chip *gc, unsigned int offset)
-{
- struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
-
- return (int) gpio_get_value(jzgc, offset);
-}
-
-static int ingenic_gpio_direction_input(struct gpio_chip *gc,
- unsigned int offset)
-{
- return pinctrl_gpio_direction_input(gc->base + offset);
-}
-
-static int ingenic_gpio_direction_output(struct gpio_chip *gc,
- unsigned int offset, int value)
-{
- ingenic_gpio_set(gc, offset, value);
- return pinctrl_gpio_direction_output(gc->base + offset);
-}
-
-static const struct of_device_id ingenic_gpio_of_match[] = {
- { .compatible = "ingenic,jz4740-gpio", .data = (void *)ID_JZ4740 },
- { .compatible = "ingenic,jz4770-gpio", .data = (void *)ID_JZ4770 },
- { .compatible = "ingenic,jz4780-gpio", .data = (void *)ID_JZ4780 },
- {},
-};
-MODULE_DEVICE_TABLE(of, ingenic_gpio_of_match);
-
-static int ingenic_gpio_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct ingenic_gpio_chip *jzgc;
- u32 bank;
- int err;
-
- jzgc = devm_kzalloc(dev, sizeof(*jzgc), GFP_KERNEL);
- if (!jzgc)
- return -ENOMEM;
-
- jzgc->map = dev_get_drvdata(dev->parent);
- if (!jzgc->map) {
- dev_err(dev, "Cannot get parent regmap\n");
- return -ENXIO;
- }
-
- err = of_property_read_u32(dev->of_node, "reg", &bank);
- if (err) {
- dev_err(dev, "Cannot read \"reg\" property: %i\n", err);
- return err;
- }
-
- jzgc->reg_base = bank * 0x100;
-
- jzgc->gc.label = devm_kasprintf(dev, GFP_KERNEL, "GPIO%c", 'A' + bank);
- if (!jzgc->gc.label)
- return -ENOMEM;
-
- /* DO NOT EXPAND THIS: FOR BACKWARD GPIO NUMBERSPACE COMPATIBIBILITY
- * ONLY: WORK TO TRANSITION CONSUMERS TO USE THE GPIO DESCRIPTOR API IN
- * <linux/gpio/consumer.h> INSTEAD.
- */
- jzgc->gc.base = bank * 32;
-
- jzgc->gc.ngpio = 32;
- jzgc->gc.parent = dev;
- jzgc->gc.of_node = dev->of_node;
- jzgc->gc.owner = THIS_MODULE;
- jzgc->version = (enum jz_version)of_device_get_match_data(dev);
-
- jzgc->gc.set = ingenic_gpio_set;
- jzgc->gc.get = ingenic_gpio_get;
- jzgc->gc.direction_input = ingenic_gpio_direction_input;
- jzgc->gc.direction_output = ingenic_gpio_direction_output;
-
- if (of_property_read_bool(dev->of_node, "gpio-ranges")) {
- jzgc->gc.request = gpiochip_generic_request;
- jzgc->gc.free = gpiochip_generic_free;
- }
-
- err = devm_gpiochip_add_data(dev, &jzgc->gc, jzgc);
- if (err)
- return err;
-
- jzgc->irq = irq_of_parse_and_map(dev->of_node, 0);
- if (!jzgc->irq)
- return -EINVAL;
-
- jzgc->irq_chip.name = jzgc->gc.label;
- jzgc->irq_chip.irq_enable = ingenic_gpio_irq_enable;
- jzgc->irq_chip.irq_disable = ingenic_gpio_irq_disable;
- jzgc->irq_chip.irq_unmask = ingenic_gpio_irq_unmask;
- jzgc->irq_chip.irq_mask = ingenic_gpio_irq_mask;
- jzgc->irq_chip.irq_ack = ingenic_gpio_irq_ack;
- jzgc->irq_chip.irq_set_type = ingenic_gpio_irq_set_type;
- jzgc->irq_chip.irq_set_wake = ingenic_gpio_irq_set_wake;
- jzgc->irq_chip.flags = IRQCHIP_MASK_ON_SUSPEND;
-
- err = gpiochip_irqchip_add(&jzgc->gc, &jzgc->irq_chip, 0,
- handle_level_irq, IRQ_TYPE_NONE);
- if (err)
- return err;
-
- gpiochip_set_chained_irqchip(&jzgc->gc, &jzgc->irq_chip,
- jzgc->irq, ingenic_gpio_irq_handler);
- return 0;
-}
-
-static int ingenic_gpio_remove(struct platform_device *pdev)
-{
- return 0;
-}
-
-static struct platform_driver ingenic_gpio_driver = {
- .driver = {
- .name = "gpio-ingenic",
- .of_match_table = of_match_ptr(ingenic_gpio_of_match),
- },
- .probe = ingenic_gpio_probe,
- .remove = ingenic_gpio_remove,
-};
-
-static int __init ingenic_gpio_drv_register(void)
-{
- return platform_driver_register(&ingenic_gpio_driver);
-}
-subsys_initcall(ingenic_gpio_drv_register);
-
-static void __exit ingenic_gpio_drv_unregister(void)
-{
- platform_driver_unregister(&ingenic_gpio_driver);
-}
-module_exit(ingenic_gpio_drv_unregister);
-
-MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");
-MODULE_DESCRIPTION("Ingenic JZ47xx GPIO driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-max3191x.c b/drivers/gpio/gpio-max3191x.c
index b5b9cb1fda50..9a8876abeb57 100644
--- a/drivers/gpio/gpio-max3191x.c
+++ b/drivers/gpio/gpio-max3191x.c
@@ -313,18 +313,21 @@ static int max3191x_set_config(struct gpio_chip *gpio, unsigned int offset,
static void gpiod_set_array_single_value_cansleep(unsigned int ndescs,
struct gpio_desc **desc,
+ struct gpio_array *info,
int value)
{
- int i, *values;
+ unsigned long *values;
- values = kmalloc_array(ndescs, sizeof(*values), GFP_KERNEL);
+ values = bitmap_alloc(ndescs, GFP_KERNEL);
if (!values)
return;
- for (i = 0; i < ndescs; i++)
- values[i] = value;
+ if (value)
+ bitmap_fill(values, ndescs);
+ else
+ bitmap_zero(values, ndescs);
- gpiod_set_array_value_cansleep(ndescs, desc, values);
+ gpiod_set_array_value_cansleep(ndescs, desc, info, values);
kfree(values);
}
@@ -397,7 +400,8 @@ static int max3191x_probe(struct spi_device *spi)
if (max3191x->modesel_pins)
gpiod_set_array_single_value_cansleep(
max3191x->modesel_pins->ndescs,
- max3191x->modesel_pins->desc, max3191x->mode);
+ max3191x->modesel_pins->desc,
+ max3191x->modesel_pins->info, max3191x->mode);
max3191x->ignore_uv = device_property_read_bool(dev,
"maxim,ignore-undervoltage");
diff --git a/drivers/gpio/gpio-mmio.c b/drivers/gpio/gpio-mmio.c
index 935292a30c99..50bdc29591c0 100644
--- a/drivers/gpio/gpio-mmio.c
+++ b/drivers/gpio/gpio-mmio.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Generic driver for memory-mapped GPIO controllers.
*
* Copyright 2008 MontaVista Software, Inc.
* Copyright 2008,2010 Anton Vorontsov <cbouatmailru@gmail.com>
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
* ....``.```~~~~````.`.`.`.`.```````'',,,.........`````......`.......
* ...`` ```````..
* ..The simplest form of a GPIO controller that the driver supports is``
diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c
index d66b7a768ecd..8269cffc2967 100644
--- a/drivers/gpio/gpio-mockup.c
+++ b/drivers/gpio/gpio-mockup.c
@@ -18,6 +18,7 @@
#include <linux/irq_sim.h>
#include <linux/debugfs.h>
#include <linux/uaccess.h>
+#include <linux/property.h>
#include "gpiolib.h"
@@ -28,6 +29,8 @@
* of GPIO lines.
*/
#define GPIO_MOCKUP_MAX_RANGES (GPIO_MOCKUP_MAX_GC * 2)
+/* Maximum of three properties + the sentinel. */
+#define GPIO_MOCKUP_MAX_PROP 4
#define gpio_mockup_err(...) pr_err(GPIO_MOCKUP_NAME ": " __VA_ARGS__)
@@ -59,13 +62,6 @@ struct gpio_mockup_dbgfs_private {
int offset;
};
-struct gpio_mockup_platform_data {
- int base;
- int ngpio;
- int index;
- bool named_lines;
-};
-
static int gpio_mockup_ranges[GPIO_MOCKUP_MAX_RANGES];
static int gpio_mockup_num_ranges;
module_param_array(gpio_mockup_ranges, int, &gpio_mockup_num_ranges, 0400);
@@ -255,26 +251,37 @@ static int gpio_mockup_name_lines(struct device *dev,
static int gpio_mockup_probe(struct platform_device *pdev)
{
- struct gpio_mockup_platform_data *pdata;
struct gpio_mockup_chip *chip;
struct gpio_chip *gc;
- int rv, base, ngpio;
struct device *dev;
- char *name;
+ const char *name;
+ int rv, base;
+ u16 ngpio;
dev = &pdev->dev;
- pdata = dev_get_platdata(dev);
- base = pdata->base;
- ngpio = pdata->ngpio;
+
+ rv = device_property_read_u32(dev, "gpio-base", &base);
+ if (rv)
+ base = -1;
+
+ rv = device_property_read_u16(dev, "nr-gpios", &ngpio);
+ if (rv)
+ return rv;
+
+ rv = device_property_read_string(dev, "chip-name", &name);
+ if (rv)
+ name = NULL;
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
- name = devm_kasprintf(dev, GFP_KERNEL, "%s-%c",
- pdev->name, pdata->index);
- if (!name)
- return -ENOMEM;
+ if (!name) {
+ name = devm_kasprintf(dev, GFP_KERNEL,
+ "%s-%c", pdev->name, pdev->id + 'A');
+ if (!name)
+ return -ENOMEM;
+ }
gc = &chip->gc;
gc->base = base;
@@ -295,7 +302,7 @@ static int gpio_mockup_probe(struct platform_device *pdev)
if (!chip->lines)
return -ENOMEM;
- if (pdata->named_lines) {
+ if (device_property_read_bool(dev, "named-gpio-lines")) {
rv = gpio_mockup_name_lines(dev, chip);
if (rv)
return rv;
@@ -339,9 +346,11 @@ static void gpio_mockup_unregister_pdevs(void)
static int __init gpio_mockup_init(void)
{
- int i, num_chips, err = 0, index = 'A';
- struct gpio_mockup_platform_data pdata;
+ struct property_entry properties[GPIO_MOCKUP_MAX_PROP];
+ int i, prop, num_chips, err = 0, base;
+ struct platform_device_info pdevinfo;
struct platform_device *pdev;
+ u16 ngpio;
if ((gpio_mockup_num_ranges < 2) ||
(gpio_mockup_num_ranges % 2) ||
@@ -371,17 +380,28 @@ static int __init gpio_mockup_init(void)
}
for (i = 0; i < num_chips; i++) {
- pdata.index = index++;
- pdata.base = gpio_mockup_range_base(i);
- pdata.ngpio = pdata.base < 0
- ? gpio_mockup_range_ngpio(i)
- : gpio_mockup_range_ngpio(i) - pdata.base;
- pdata.named_lines = gpio_mockup_named_lines;
-
- pdev = platform_device_register_resndata(NULL,
- GPIO_MOCKUP_NAME,
- i, NULL, 0, &pdata,
- sizeof(pdata));
+ memset(properties, 0, sizeof(properties));
+ memset(&pdevinfo, 0, sizeof(pdevinfo));
+ prop = 0;
+
+ base = gpio_mockup_range_base(i);
+ if (base >= 0)
+ properties[prop++] = PROPERTY_ENTRY_U32("gpio-base",
+ base);
+
+ ngpio = base < 0 ? gpio_mockup_range_ngpio(i)
+ : gpio_mockup_range_ngpio(i) - base;
+ properties[prop++] = PROPERTY_ENTRY_U16("nr-gpios", ngpio);
+
+ if (gpio_mockup_named_lines)
+ properties[prop++] = PROPERTY_ENTRY_BOOL(
+ "named-gpio-lines");
+
+ pdevinfo.name = GPIO_MOCKUP_NAME;
+ pdevinfo.id = i;
+ pdevinfo.properties = properties;
+
+ pdev = platform_device_register_full(&pdevinfo);
if (IS_ERR(pdev)) {
gpio_mockup_err("error registering device");
platform_driver_unregister(&gpio_mockup_driver);
diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c
index df30490da820..ea874fd033a5 100644
--- a/drivers/gpio/gpio-mxs.c
+++ b/drivers/gpio/gpio-mxs.c
@@ -18,8 +18,6 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/gpio/driver.h>
-/* FIXME: for gpio_get_value(), replace this by direct register read */
-#include <linux/gpio.h>
#include <linux/module.h>
#define MXS_SET 0x4
@@ -86,7 +84,7 @@ static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type)
port->both_edges &= ~pin_mask;
switch (type) {
case IRQ_TYPE_EDGE_BOTH:
- val = gpio_get_value(port->gc.base + d->hwirq);
+ val = port->gc.get(&port->gc, d->hwirq);
if (val)
edge = GPIO_INT_FALL_EDGE;
else
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index e81008678a38..9887c3db6e16 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -19,6 +19,7 @@
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/io.h>
+#include <linux/cpu_pm.h>
#include <linux/device.h>
#include <linux/pm_runtime.h>
#include <linux/pm.h>
@@ -28,10 +29,10 @@
#include <linux/bitops.h>
#include <linux/platform_data/gpio-omap.h>
-#define OFF_MODE 1
#define OMAP4_GPIO_DEBOUNCINGTIME_MASK 0xFF
-static LIST_HEAD(omap_gpio_list);
+#define OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER BIT(2)
+#define OMAP_GPIO_QUIRK_DEFERRED_WKUP_EN BIT(1)
struct gpio_regs {
u32 irqenable1;
@@ -48,6 +49,13 @@ struct gpio_regs {
u32 debounce_en;
};
+struct gpio_bank;
+
+struct gpio_omap_funcs {
+ void (*idle_enable_level_quirk)(struct gpio_bank *bank);
+ void (*idle_disable_level_quirk)(struct gpio_bank *bank);
+};
+
struct gpio_bank {
struct list_head node;
void __iomem *base;
@@ -55,6 +63,7 @@ struct gpio_bank {
u32 non_wakeup_gpios;
u32 enabled_non_wakeup_gpios;
struct gpio_regs context;
+ struct gpio_omap_funcs funcs;
u32 saved_datain;
u32 level_mask;
u32 toggle_mask;
@@ -62,6 +71,8 @@ struct gpio_bank {
raw_spinlock_t wa_lock;
struct gpio_chip chip;
struct clk *dbck;
+ struct notifier_block nb;
+ unsigned int is_suspended:1;
u32 mod_usage;
u32 irq_usage;
u32 dbck_enable_mask;
@@ -73,8 +84,8 @@ struct gpio_bank {
int stride;
u32 width;
int context_loss_count;
- int power_mode;
bool workaround_enabled;
+ u32 quirks;
void (*set_dataout)(struct gpio_bank *bank, unsigned gpio, int enable);
void (*set_dataout_multiple)(struct gpio_bank *bank,
@@ -368,9 +379,18 @@ static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio,
readl_relaxed(bank->base + bank->regs->fallingdetect);
if (likely(!(bank->non_wakeup_gpios & gpio_bit))) {
- omap_gpio_rmw(base, bank->regs->wkup_en, gpio_bit, trigger != 0);
- bank->context.wake_en =
- readl_relaxed(bank->base + bank->regs->wkup_en);
+ /* Defer wkup_en register update until we idle? */
+ if (bank->quirks & OMAP_GPIO_QUIRK_DEFERRED_WKUP_EN) {
+ if (trigger)
+ bank->context.wake_en |= gpio_bit;
+ else
+ bank->context.wake_en &= ~gpio_bit;
+ } else {
+ omap_gpio_rmw(base, bank->regs->wkup_en, gpio_bit,
+ trigger != 0);
+ bank->context.wake_en =
+ readl_relaxed(bank->base + bank->regs->wkup_en);
+ }
}
/* This part needs to be executed always for OMAP{34xx, 44xx} */
@@ -682,12 +702,7 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
struct gpio_bank *bank = gpiochip_get_data(chip);
unsigned long flags;
- /*
- * If this is the first gpio_request for the bank,
- * enable the bank module.
- */
- if (!BANK_USED(bank))
- pm_runtime_get_sync(chip->parent);
+ pm_runtime_get_sync(chip->parent);
raw_spin_lock_irqsave(&bank->lock, flags);
omap_enable_gpio_module(bank, offset);
@@ -711,12 +726,7 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
omap_disable_gpio_module(bank, offset);
raw_spin_unlock_irqrestore(&bank->lock, flags);
- /*
- * If this is the last gpio to be freed in the bank,
- * disable the bank module.
- */
- if (!BANK_USED(bank))
- pm_runtime_put(chip->parent);
+ pm_runtime_put(chip->parent);
}
/*
@@ -741,7 +751,9 @@ static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
if (WARN_ON(!isr_reg))
goto exit;
- pm_runtime_get_sync(bank->chip.parent);
+ if (WARN_ONCE(!pm_runtime_active(bank->chip.parent),
+ "gpio irq%i while runtime suspended?\n", irq))
+ return IRQ_NONE;
while (1) {
raw_spin_lock_irqsave(&bank->lock, lock_flags);
@@ -792,7 +804,6 @@ static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
}
}
exit:
- pm_runtime_put(bank->chip.parent);
return IRQ_HANDLED;
}
@@ -841,20 +852,14 @@ static void omap_gpio_irq_bus_lock(struct irq_data *data)
{
struct gpio_bank *bank = omap_irq_data_get_bank(data);
- if (!BANK_USED(bank))
- pm_runtime_get_sync(bank->chip.parent);
+ pm_runtime_get_sync(bank->chip.parent);
}
static void gpio_irq_bus_sync_unlock(struct irq_data *data)
{
struct gpio_bank *bank = omap_irq_data_get_bank(data);
- /*
- * If this is the last IRQ to be freed in the bank,
- * disable the bank module.
- */
- if (!BANK_USED(bank))
- pm_runtime_put(bank->chip.parent);
+ pm_runtime_put(bank->chip.parent);
}
static void omap_gpio_ack_irq(struct irq_data *d)
@@ -899,6 +904,82 @@ static void omap_gpio_unmask_irq(struct irq_data *d)
raw_spin_unlock_irqrestore(&bank->lock, flags);
}
+/*
+ * Only edges can generate a wakeup event to the PRCM.
+ *
+ * Therefore, ensure any wake-up capable GPIOs have
+ * edge-detection enabled before going idle to ensure a wakeup
+ * to the PRCM is generated on a GPIO transition. (c.f. 34xx
+ * NDA TRM 25.5.3.1)
+ *
+ * The normal values will be restored upon ->runtime_resume()
+ * by writing back the values saved in bank->context.
+ */
+static void __maybe_unused
+omap2_gpio_enable_level_quirk(struct gpio_bank *bank)
+{
+ u32 wake_low, wake_hi;
+
+ /* Enable additional edge detection for level gpios for idle */
+ wake_low = bank->context.leveldetect0 & bank->context.wake_en;
+ if (wake_low)
+ writel_relaxed(wake_low | bank->context.fallingdetect,
+ bank->base + bank->regs->fallingdetect);
+
+ wake_hi = bank->context.leveldetect1 & bank->context.wake_en;
+ if (wake_hi)
+ writel_relaxed(wake_hi | bank->context.risingdetect,
+ bank->base + bank->regs->risingdetect);
+}
+
+static void __maybe_unused
+omap2_gpio_disable_level_quirk(struct gpio_bank *bank)
+{
+ /* Disable edge detection for level gpios after idle */
+ writel_relaxed(bank->context.fallingdetect,
+ bank->base + bank->regs->fallingdetect);
+ writel_relaxed(bank->context.risingdetect,
+ bank->base + bank->regs->risingdetect);
+}
+
+/*
+ * On omap4 and later SoC variants a level interrupt with wkup_en
+ * enabled blocks the GPIO functional clock from idling until the GPIO
+ * instance has been reset. To avoid that, we must set wkup_en only for
+ * idle for level interrupts, and clear level registers for the duration
+ * of idle. The level interrupts will be still there on wakeup by their
+ * nature.
+ */
+static void __maybe_unused
+omap4_gpio_enable_level_quirk(struct gpio_bank *bank)
+{
+ /* Update wake register for idle, edge bits might be already set */
+ writel_relaxed(bank->context.wake_en,
+ bank->base + bank->regs->wkup_en);
+
+ /* Clear level registers for idle */
+ writel_relaxed(0, bank->base + bank->regs->leveldetect0);
+ writel_relaxed(0, bank->base + bank->regs->leveldetect1);
+}
+
+static void __maybe_unused
+omap4_gpio_disable_level_quirk(struct gpio_bank *bank)
+{
+ /* Restore level registers after idle */
+ writel_relaxed(bank->context.leveldetect0,
+ bank->base + bank->regs->leveldetect0);
+ writel_relaxed(bank->context.leveldetect1,
+ bank->base + bank->regs->leveldetect1);
+
+ /* Clear saved wkup_en for level, it will be set for next idle again */
+ bank->context.wake_en &= ~(bank->context.leveldetect0 |
+ bank->context.leveldetect1);
+
+ /* Update wake with only edge configuration */
+ writel_relaxed(bank->context.wake_en,
+ bank->base + bank->regs->wkup_en);
+}
+
/*---------------------------------------------------------------------*/
static int omap_mpuio_suspend_noirq(struct device *dev)
@@ -1218,6 +1299,36 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
return ret;
}
+static void omap_gpio_idle(struct gpio_bank *bank, bool may_lose_context);
+static void omap_gpio_unidle(struct gpio_bank *bank);
+
+static int gpio_omap_cpu_notifier(struct notifier_block *nb,
+ unsigned long cmd, void *v)
+{
+ struct gpio_bank *bank;
+ unsigned long flags;
+
+ bank = container_of(nb, struct gpio_bank, nb);
+
+ raw_spin_lock_irqsave(&bank->lock, flags);
+ switch (cmd) {
+ case CPU_CLUSTER_PM_ENTER:
+ if (bank->is_suspended)
+ break;
+ omap_gpio_idle(bank, true);
+ break;
+ case CPU_CLUSTER_PM_ENTER_FAILED:
+ case CPU_CLUSTER_PM_EXIT:
+ if (bank->is_suspended)
+ break;
+ omap_gpio_unidle(bank);
+ break;
+ }
+ raw_spin_unlock_irqrestore(&bank->lock, flags);
+
+ return NOTIFY_OK;
+}
+
static const struct of_device_id omap_gpio_match[];
static int omap_gpio_probe(struct platform_device *pdev)
@@ -1256,6 +1367,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
irqc->irq_bus_sync_unlock = gpio_irq_bus_sync_unlock,
irqc->name = dev_name(&pdev->dev);
irqc->flags = IRQCHIP_MASK_ON_SUSPEND;
+ irqc->parent_device = dev;
bank->irq = platform_get_irq(pdev, 0);
if (bank->irq <= 0) {
@@ -1270,6 +1382,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
bank->chip.parent = dev;
bank->chip.owner = THIS_MODULE;
bank->dbck_flag = pdata->dbck_flag;
+ bank->quirks = pdata->quirks;
bank->stride = pdata->bank_stride;
bank->width = pdata->bank_width;
bank->is_mpuio = pdata->is_mpuio;
@@ -1278,6 +1391,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
#ifdef CONFIG_OF_GPIO
bank->chip.of_node = of_node_get(node);
#endif
+
if (node) {
if (!of_property_read_bool(node, "ti,gpio-always-on"))
bank->loses_context = true;
@@ -1298,6 +1412,18 @@ static int omap_gpio_probe(struct platform_device *pdev)
omap_set_gpio_dataout_mask_multiple;
}
+ if (bank->quirks & OMAP_GPIO_QUIRK_DEFERRED_WKUP_EN) {
+ bank->funcs.idle_enable_level_quirk =
+ omap4_gpio_enable_level_quirk;
+ bank->funcs.idle_disable_level_quirk =
+ omap4_gpio_disable_level_quirk;
+ } else if (bank->quirks & OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER) {
+ bank->funcs.idle_enable_level_quirk =
+ omap2_gpio_enable_level_quirk;
+ bank->funcs.idle_disable_level_quirk =
+ omap2_gpio_disable_level_quirk;
+ }
+
raw_spin_lock_init(&bank->lock);
raw_spin_lock_init(&bank->wa_lock);
@@ -1322,7 +1448,6 @@ static int omap_gpio_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, bank);
pm_runtime_enable(dev);
- pm_runtime_irq_safe(dev);
pm_runtime_get_sync(dev);
if (bank->is_mpuio)
@@ -1341,9 +1466,13 @@ static int omap_gpio_probe(struct platform_device *pdev)
omap_gpio_show_rev(bank);
- pm_runtime_put(dev);
+ if (bank->funcs.idle_enable_level_quirk &&
+ bank->funcs.idle_disable_level_quirk) {
+ bank->nb.notifier_call = gpio_omap_cpu_notifier;
+ cpu_pm_register_notifier(&bank->nb);
+ }
- list_add_tail(&bank->node, &omap_gpio_list);
+ pm_runtime_put(dev);
return 0;
}
@@ -1352,6 +1481,8 @@ static int omap_gpio_remove(struct platform_device *pdev)
{
struct gpio_bank *bank = platform_get_drvdata(pdev);
+ if (bank->nb.notifier_call)
+ cpu_pm_unregister_notifier(&bank->nb);
list_del(&bank->node);
gpiochip_remove(&bank->chip);
pm_runtime_disable(&pdev->dev);
@@ -1361,48 +1492,22 @@ static int omap_gpio_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_ARCH_OMAP2PLUS
-
-#if defined(CONFIG_PM)
static void omap_gpio_restore_context(struct gpio_bank *bank);
-static int omap_gpio_runtime_suspend(struct device *dev)
+static void omap_gpio_idle(struct gpio_bank *bank, bool may_lose_context)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct gpio_bank *bank = platform_get_drvdata(pdev);
+ struct device *dev = bank->chip.parent;
u32 l1 = 0, l2 = 0;
- unsigned long flags;
- u32 wake_low, wake_hi;
- raw_spin_lock_irqsave(&bank->lock, flags);
-
- /*
- * Only edges can generate a wakeup event to the PRCM.
- *
- * Therefore, ensure any wake-up capable GPIOs have
- * edge-detection enabled before going idle to ensure a wakeup
- * to the PRCM is generated on a GPIO transition. (c.f. 34xx
- * NDA TRM 25.5.3.1)
- *
- * The normal values will be restored upon ->runtime_resume()
- * by writing back the values saved in bank->context.
- */
- wake_low = bank->context.leveldetect0 & bank->context.wake_en;
- if (wake_low)
- writel_relaxed(wake_low | bank->context.fallingdetect,
- bank->base + bank->regs->fallingdetect);
- wake_hi = bank->context.leveldetect1 & bank->context.wake_en;
- if (wake_hi)
- writel_relaxed(wake_hi | bank->context.risingdetect,
- bank->base + bank->regs->risingdetect);
+ if (bank->funcs.idle_enable_level_quirk)
+ bank->funcs.idle_enable_level_quirk(bank);
if (!bank->enabled_non_wakeup_gpios)
goto update_gpio_context_count;
- if (bank->power_mode != OFF_MODE) {
- bank->power_mode = 0;
+ if (!may_lose_context)
goto update_gpio_context_count;
- }
+
/*
* If going to OFF, remove triggering for all
* non-wakeup GPIOs. Otherwise spurious IRQs will be
@@ -1427,23 +1532,16 @@ update_gpio_context_count:
bank->get_context_loss_count(dev);
omap_gpio_dbck_disable(bank);
- raw_spin_unlock_irqrestore(&bank->lock, flags);
-
- return 0;
}
static void omap_gpio_init_context(struct gpio_bank *p);
-static int omap_gpio_runtime_resume(struct device *dev)
+static void omap_gpio_unidle(struct gpio_bank *bank)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct gpio_bank *bank = platform_get_drvdata(pdev);
+ struct device *dev = bank->chip.parent;
u32 l = 0, gen, gen0, gen1;
- unsigned long flags;
int c;
- raw_spin_lock_irqsave(&bank->lock, flags);
-
/*
* On the first resume during the probe, the context has not
* been initialised and so initialise it now. Also initialise
@@ -1459,16 +1557,8 @@ static int omap_gpio_runtime_resume(struct device *dev)
omap_gpio_dbck_enable(bank);
- /*
- * In ->runtime_suspend(), level-triggered, wakeup-enabled
- * GPIOs were set to edge trigger also in order to be able to
- * generate a PRCM wakeup. Here we restore the
- * pre-runtime_suspend() values for edge triggering.
- */
- writel_relaxed(bank->context.fallingdetect,
- bank->base + bank->regs->fallingdetect);
- writel_relaxed(bank->context.risingdetect,
- bank->base + bank->regs->risingdetect);
+ if (bank->funcs.idle_disable_level_quirk)
+ bank->funcs.idle_disable_level_quirk(bank);
if (bank->loses_context) {
if (!bank->get_context_loss_count) {
@@ -1478,16 +1568,13 @@ static int omap_gpio_runtime_resume(struct device *dev)
if (c != bank->context_loss_count) {
omap_gpio_restore_context(bank);
} else {
- raw_spin_unlock_irqrestore(&bank->lock, flags);
- return 0;
+ return;
}
}
}
- if (!bank->workaround_enabled) {
- raw_spin_unlock_irqrestore(&bank->lock, flags);
- return 0;
- }
+ if (!bank->workaround_enabled)
+ return;
l = readl_relaxed(bank->base + bank->regs->datain);
@@ -1540,41 +1627,8 @@ static int omap_gpio_runtime_resume(struct device *dev)
}
bank->workaround_enabled = false;
- raw_spin_unlock_irqrestore(&bank->lock, flags);
-
- return 0;
-}
-#endif /* CONFIG_PM */
-
-#if IS_BUILTIN(CONFIG_GPIO_OMAP)
-void omap2_gpio_prepare_for_idle(int pwr_mode)
-{
- struct gpio_bank *bank;
-
- list_for_each_entry(bank, &omap_gpio_list, node) {
- if (!BANK_USED(bank) || !bank->loses_context)
- continue;
-
- bank->power_mode = pwr_mode;
-
- pm_runtime_put_sync_suspend(bank->chip.parent);
- }
-}
-
-void omap2_gpio_resume_after_idle(void)
-{
- struct gpio_bank *bank;
-
- list_for_each_entry(bank, &omap_gpio_list, node) {
- if (!BANK_USED(bank) || !bank->loses_context)
- continue;
-
- pm_runtime_get_sync(bank->chip.parent);
- }
}
-#endif
-#if defined(CONFIG_PM)
static void omap_gpio_init_context(struct gpio_bank *p)
{
struct omap_gpio_reg_offs *regs = p->regs;
@@ -1631,17 +1685,57 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
writel_relaxed(bank->context.irqenable2,
bank->base + bank->regs->irqenable2);
}
-#endif /* CONFIG_PM */
-#else
-#define omap_gpio_runtime_suspend NULL
-#define omap_gpio_runtime_resume NULL
-static inline void omap_gpio_init_context(struct gpio_bank *p) {}
-#endif
+static int __maybe_unused omap_gpio_runtime_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct gpio_bank *bank = platform_get_drvdata(pdev);
+ unsigned long flags;
+ int error = 0;
+
+ raw_spin_lock_irqsave(&bank->lock, flags);
+ /* Must be idled only by CPU_CLUSTER_PM_ENTER? */
+ if (bank->irq_usage) {
+ error = -EBUSY;
+ goto unlock;
+ }
+ omap_gpio_idle(bank, true);
+ bank->is_suspended = true;
+unlock:
+ raw_spin_unlock_irqrestore(&bank->lock, flags);
+
+ return error;
+}
+
+static int __maybe_unused omap_gpio_runtime_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct gpio_bank *bank = platform_get_drvdata(pdev);
+ unsigned long flags;
+ int error = 0;
+
+ raw_spin_lock_irqsave(&bank->lock, flags);
+ /* Must be unidled only by CPU_CLUSTER_PM_ENTER? */
+ if (bank->irq_usage) {
+ error = -EBUSY;
+ goto unlock;
+ }
+ omap_gpio_unidle(bank);
+ bank->is_suspended = false;
+unlock:
+ raw_spin_unlock_irqrestore(&bank->lock, flags);
+
+ return error;
+}
+
+#ifdef CONFIG_ARCH_OMAP2PLUS
static const struct dev_pm_ops gpio_pm_ops = {
SET_RUNTIME_PM_OPS(omap_gpio_runtime_suspend, omap_gpio_runtime_resume,
NULL)
};
+#else
+static const struct dev_pm_ops gpio_pm_ops;
+#endif /* CONFIG_ARCH_OMAP2PLUS */
#if defined(CONFIG_OF)
static struct omap_gpio_reg_offs omap2_gpio_regs = {
@@ -1690,6 +1784,11 @@ static struct omap_gpio_reg_offs omap4_gpio_regs = {
.fallingdetect = OMAP4_GPIO_FALLINGDETECT,
};
+/*
+ * Note that omap2 does not currently support idle modes with context loss so
+ * no need to add OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER quirk flag to save
+ * and restore context.
+ */
static const struct omap_gpio_platform_data omap2_pdata = {
.regs = &omap2_gpio_regs,
.bank_width = 32,
@@ -1700,12 +1799,15 @@ static const struct omap_gpio_platform_data omap3_pdata = {
.regs = &omap2_gpio_regs,
.bank_width = 32,
.dbck_flag = true,
+ .quirks = OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER,
};
static const struct omap_gpio_platform_data omap4_pdata = {
.regs = &omap4_gpio_regs,
.bank_width = 32,
.dbck_flag = true,
+ .quirks = OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER |
+ OMAP_GPIO_QUIRK_DEFERRED_WKUP_EN,
};
static const struct of_device_id omap_gpio_match[] = {
diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c
index c18712dabf93..bfe4c5c9f41c 100644
--- a/drivers/gpio/gpio-pxa.c
+++ b/drivers/gpio/gpio-pxa.c
@@ -776,6 +776,9 @@ static int pxa_gpio_suspend(void)
struct pxa_gpio_bank *c;
int gpio;
+ if (!pchip)
+ return 0;
+
for_each_gpio_bank(gpio, c, pchip) {
c->saved_gplr = readl_relaxed(c->regbase + GPLR_OFFSET);
c->saved_gpdr = readl_relaxed(c->regbase + GPDR_OFFSET);
@@ -794,6 +797,9 @@ static void pxa_gpio_resume(void)
struct pxa_gpio_bank *c;
int gpio;
+ if (!pchip)
+ return;
+
for_each_gpio_bank(gpio, c, pchip) {
/* restore level with set/clear */
writel_relaxed(c->saved_gplr, c->regbase + GPSR_OFFSET);
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
index 55cc61086d99..3c82bb3c2030 100644
--- a/drivers/gpio/gpio-rcar.c
+++ b/drivers/gpio/gpio-rcar.c
@@ -321,6 +321,9 @@ static void gpio_rcar_set_multiple(struct gpio_chip *chip, unsigned long *mask,
u32 val, bankmask;
bankmask = mask[0] & GENMASK(chip->ngpio - 1, 0);
+ if (chip->valid_mask)
+ bankmask &= chip->valid_mask[0];
+
if (!bankmask)
return;
@@ -558,6 +561,9 @@ static int gpio_rcar_resume(struct device *dev)
u32 mask;
for (offset = 0; offset < p->gpio_chip.ngpio; offset++) {
+ if (!gpiochip_line_is_valid(&p->gpio_chip, offset))
+ continue;
+
mask = BIT(offset);
/* I/O pin */
if (!(p->bank_info.iointsel & mask)) {
diff --git a/drivers/gpio/gpio-siox.c b/drivers/gpio/gpio-siox.c
new file mode 100644
index 000000000000..571b2a81c6de
--- /dev/null
+++ b/drivers/gpio/gpio-siox.c
@@ -0,0 +1,293 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2015-2018 Pengutronix, Uwe Kleine-König <kernel@pengutronix.de>
+ */
+
+#include <linux/module.h>
+#include <linux/siox.h>
+#include <linux/gpio/driver.h>
+#include <linux/of.h>
+
+struct gpio_siox_ddata {
+ struct gpio_chip gchip;
+ struct irq_chip ichip;
+ struct mutex lock;
+ u8 setdata[1];
+ u8 getdata[3];
+
+ spinlock_t irqlock;
+ u32 irq_enable;
+ u32 irq_status;
+ u32 irq_type[20];
+};
+
+/*
+ * Note that this callback only sets the value that is clocked out in the next
+ * cycle.
+ */
+static int gpio_siox_set_data(struct siox_device *sdevice, u8 status, u8 buf[])
+{
+ struct gpio_siox_ddata *ddata = dev_get_drvdata(&sdevice->dev);
+
+ mutex_lock(&ddata->lock);
+ buf[0] = ddata->setdata[0];
+ mutex_unlock(&ddata->lock);
+
+ return 0;
+}
+
+static int gpio_siox_get_data(struct siox_device *sdevice, const u8 buf[])
+{
+ struct gpio_siox_ddata *ddata = dev_get_drvdata(&sdevice->dev);
+ size_t offset;
+ u32 trigger;
+
+ mutex_lock(&ddata->lock);
+
+ spin_lock_irq(&ddata->irqlock);
+
+ for (offset = 0; offset < 12; ++offset) {
+ unsigned int bitpos = 11 - offset;
+ unsigned int gpiolevel = buf[bitpos / 8] & (1 << bitpos % 8);
+ unsigned int prev_level =
+ ddata->getdata[bitpos / 8] & (1 << (bitpos % 8));
+ u32 irq_type = ddata->irq_type[offset];
+
+ if (gpiolevel) {
+ if ((irq_type & IRQ_TYPE_LEVEL_HIGH) ||
+ ((irq_type & IRQ_TYPE_EDGE_RISING) && !prev_level))
+ ddata->irq_status |= 1 << offset;
+ } else {
+ if ((irq_type & IRQ_TYPE_LEVEL_LOW) ||
+ ((irq_type & IRQ_TYPE_EDGE_FALLING) && prev_level))
+ ddata->irq_status |= 1 << offset;
+ }
+ }
+
+ trigger = ddata->irq_status & ddata->irq_enable;
+
+ spin_unlock_irq(&ddata->irqlock);
+
+ ddata->getdata[0] = buf[0];
+ ddata->getdata[1] = buf[1];
+ ddata->getdata[2] = buf[2];
+
+ mutex_unlock(&ddata->lock);
+
+ for (offset = 0; offset < 12; ++offset) {
+ if (trigger & (1 << offset)) {
+ struct irq_domain *irqdomain = ddata->gchip.irq.domain;
+ unsigned int irq = irq_find_mapping(irqdomain, offset);
+
+ /*
+ * Conceptually handle_nested_irq should call the flow
+ * handler of the irq chip. But it doesn't, so we have
+ * to clean the irq_status here.
+ */
+ spin_lock_irq(&ddata->irqlock);
+ ddata->irq_status &= ~(1 << offset);
+ spin_unlock_irq(&ddata->irqlock);
+
+ handle_nested_irq(irq);
+ }
+ }
+
+ return 0;
+}
+
+static void gpio_siox_irq_ack(struct irq_data *d)
+{
+ struct irq_chip *ic = irq_data_get_irq_chip(d);
+ struct gpio_siox_ddata *ddata =
+ container_of(ic, struct gpio_siox_ddata, ichip);
+
+ spin_lock_irq(&ddata->irqlock);
+ ddata->irq_status &= ~(1 << d->hwirq);
+ spin_unlock_irq(&ddata->irqlock);
+}
+
+static void gpio_siox_irq_mask(struct irq_data *d)
+{
+ struct irq_chip *ic = irq_data_get_irq_chip(d);
+ struct gpio_siox_ddata *ddata =
+ container_of(ic, struct gpio_siox_ddata, ichip);
+
+ spin_lock_irq(&ddata->irqlock);
+ ddata->irq_enable &= ~(1 << d->hwirq);
+ spin_unlock_irq(&ddata->irqlock);
+}
+
+static void gpio_siox_irq_unmask(struct irq_data *d)
+{
+ struct irq_chip *ic = irq_data_get_irq_chip(d);
+ struct gpio_siox_ddata *ddata =
+ container_of(ic, struct gpio_siox_ddata, ichip);
+
+ spin_lock_irq(&ddata->irqlock);
+ ddata->irq_enable |= 1 << d->hwirq;
+ spin_unlock_irq(&ddata->irqlock);
+}
+
+static int gpio_siox_irq_set_type(struct irq_data *d, u32 type)
+{
+ struct irq_chip *ic = irq_data_get_irq_chip(d);
+ struct gpio_siox_ddata *ddata =
+ container_of(ic, struct gpio_siox_ddata, ichip);
+
+ spin_lock_irq(&ddata->irqlock);
+ ddata->irq_type[d->hwirq] = type;
+ spin_unlock_irq(&ddata->irqlock);
+
+ return 0;
+}
+
+static int gpio_siox_get(struct gpio_chip *chip, unsigned int offset)
+{
+ struct gpio_siox_ddata *ddata =
+ container_of(chip, struct gpio_siox_ddata, gchip);
+ int ret;
+
+ mutex_lock(&ddata->lock);
+
+ if (offset >= 12) {
+ unsigned int bitpos = 19 - offset;
+
+ ret = ddata->setdata[0] & (1 << bitpos);
+ } else {
+ unsigned int bitpos = 11 - offset;
+
+ ret = ddata->getdata[bitpos / 8] & (1 << (bitpos % 8));
+ }
+
+ mutex_unlock(&ddata->lock);
+
+ return ret;
+}
+
+static void gpio_siox_set(struct gpio_chip *chip,
+ unsigned int offset, int value)
+{
+ struct gpio_siox_ddata *ddata =
+ container_of(chip, struct gpio_siox_ddata, gchip);
+ u8 mask = 1 << (19 - offset);
+
+ mutex_lock(&ddata->lock);
+
+ if (value)
+ ddata->setdata[0] |= mask;
+ else
+ ddata->setdata[0] &= ~mask;
+
+ mutex_unlock(&ddata->lock);
+}
+
+static int gpio_siox_direction_input(struct gpio_chip *chip,
+ unsigned int offset)
+{
+ if (offset >= 12)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int gpio_siox_direction_output(struct gpio_chip *chip,
+ unsigned int offset, int value)
+{
+ if (offset < 12)
+ return -EINVAL;
+
+ gpio_siox_set(chip, offset, value);
+ return 0;
+}
+
+static int gpio_siox_get_direction(struct gpio_chip *chip, unsigned int offset)
+{
+ if (offset < 12)
+ return 1; /* input */
+ else
+ return 0; /* output */
+}
+
+static int gpio_siox_probe(struct siox_device *sdevice)
+{
+ struct gpio_siox_ddata *ddata;
+ int ret;
+
+ ddata = devm_kzalloc(&sdevice->dev, sizeof(*ddata), GFP_KERNEL);
+ if (!ddata)
+ return -ENOMEM;
+
+ dev_set_drvdata(&sdevice->dev, ddata);
+
+ mutex_init(&ddata->lock);
+ spin_lock_init(&ddata->irqlock);
+
+ ddata->gchip.base = -1;
+ ddata->gchip.can_sleep = 1;
+ ddata->gchip.parent = &sdevice->dev;
+ ddata->gchip.owner = THIS_MODULE;
+ ddata->gchip.get = gpio_siox_get;
+ ddata->gchip.set = gpio_siox_set;
+ ddata->gchip.direction_input = gpio_siox_direction_input;
+ ddata->gchip.direction_output = gpio_siox_direction_output;
+ ddata->gchip.get_direction = gpio_siox_get_direction;
+ ddata->gchip.ngpio = 20;
+
+ ddata->ichip.name = "siox-gpio";
+ ddata->ichip.irq_ack = gpio_siox_irq_ack;
+ ddata->ichip.irq_mask = gpio_siox_irq_mask;
+ ddata->ichip.irq_unmask = gpio_siox_irq_unmask;
+ ddata->ichip.irq_set_type = gpio_siox_irq_set_type;
+
+ ret = gpiochip_add(&ddata->gchip);
+ if (ret) {
+ dev_err(&sdevice->dev,
+ "Failed to register gpio chip (%d)\n", ret);
+ goto err_gpiochip;
+ }
+
+ ret = gpiochip_irqchip_add(&ddata->gchip, &ddata->ichip,
+ 0, handle_level_irq, IRQ_TYPE_EDGE_RISING);
+ if (ret) {
+ dev_err(&sdevice->dev,
+ "Failed to register irq chip (%d)\n", ret);
+err_gpiochip:
+ gpiochip_remove(&ddata->gchip);
+ }
+
+ return ret;
+}
+
+static int gpio_siox_remove(struct siox_device *sdevice)
+{
+ struct gpio_siox_ddata *ddata = dev_get_drvdata(&sdevice->dev);
+
+ gpiochip_remove(&ddata->gchip);
+ return 0;
+}
+
+static struct siox_driver gpio_siox_driver = {
+ .probe = gpio_siox_probe,
+ .remove = gpio_siox_remove,
+ .set_data = gpio_siox_set_data,
+ .get_data = gpio_siox_get_data,
+ .driver = {
+ .name = "gpio-siox",
+ },
+};
+
+static int __init gpio_siox_init(void)
+{
+ return siox_driver_register(&gpio_siox_driver);
+}
+module_init(gpio_siox_init);
+
+static void __exit gpio_siox_exit(void)
+{
+ siox_driver_unregister(&gpio_siox_driver);
+}
+module_exit(gpio_siox_exit);
+
+MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
+MODULE_DESCRIPTION("SIOX gpio driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-syscon.c b/drivers/gpio/gpio-syscon.c
index 87c18a544513..7f3da34c7874 100644
--- a/drivers/gpio/gpio-syscon.c
+++ b/drivers/gpio/gpio-syscon.c
@@ -122,7 +122,7 @@ static int syscon_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int val)
BIT(offs % SYSCON_REG_BITS));
}
- priv->data->set(chip, offset, val);
+ chip->set(chip, offset, val);
return 0;
}
diff --git a/drivers/gpio/gpio-tb10x.c b/drivers/gpio/gpio-tb10x.c
index a12cd0b5c972..d5e5d19f4c0a 100644
--- a/drivers/gpio/gpio-tb10x.c
+++ b/drivers/gpio/gpio-tb10x.c
@@ -45,14 +45,12 @@
/**
- * @spinlock: used for atomic read/modify/write of registers
* @base: register base address
* @domain: IRQ domain of GPIO generated interrupts managed by this controller
* @irq: Interrupt line of parent interrupt controller
* @gc: gpio_chip structure associated to this GPIO controller
*/
struct tb10x_gpio {
- spinlock_t spinlock;
void __iomem *base;
struct irq_domain *domain;
int irq;
@@ -76,60 +74,14 @@ static inline void tb10x_set_bits(struct tb10x_gpio *gpio, unsigned int offs,
u32 r;
unsigned long flags;
- spin_lock_irqsave(&gpio->spinlock, flags);
+ spin_lock_irqsave(&gpio->gc.bgpio_lock, flags);
r = tb10x_reg_read(gpio, offs);
r = (r & ~mask) | (val & mask);
tb10x_reg_write(gpio, offs, r);
- spin_unlock_irqrestore(&gpio->spinlock, flags);
-}
-
-static int tb10x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
-{
- struct tb10x_gpio *tb10x_gpio = gpiochip_get_data(chip);
- int mask = BIT(offset);
- int val = TB10X_GPIO_DIR_IN << offset;
-
- tb10x_set_bits(tb10x_gpio, OFFSET_TO_REG_DDR, mask, val);
-
- return 0;
-}
-
-static int tb10x_gpio_get(struct gpio_chip *chip, unsigned offset)
-{
- struct tb10x_gpio *tb10x_gpio = gpiochip_get_data(chip);
- int val;
-
- val = tb10x_reg_read(tb10x_gpio, OFFSET_TO_REG_DATA);
-
- if (val & BIT(offset))
- return 1;
- else
- return 0;
-}
-
-static void tb10x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
-{
- struct tb10x_gpio *tb10x_gpio = gpiochip_get_data(chip);
- int mask = BIT(offset);
- int val = value << offset;
-
- tb10x_set_bits(tb10x_gpio, OFFSET_TO_REG_DATA, mask, val);
-}
-
-static int tb10x_gpio_direction_out(struct gpio_chip *chip,
- unsigned offset, int value)
-{
- struct tb10x_gpio *tb10x_gpio = gpiochip_get_data(chip);
- int mask = BIT(offset);
- int val = TB10X_GPIO_DIR_OUT << offset;
-
- tb10x_gpio_set(chip, offset, value);
- tb10x_set_bits(tb10x_gpio, OFFSET_TO_REG_DDR, mask, val);
-
- return 0;
+ spin_unlock_irqrestore(&gpio->gc.bgpio_lock, flags);
}
static int tb10x_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
@@ -169,72 +121,85 @@ static int tb10x_gpio_probe(struct platform_device *pdev)
{
struct tb10x_gpio *tb10x_gpio;
struct resource *mem;
- struct device_node *dn = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
int ret = -EBUSY;
u32 ngpio;
- if (!dn)
+ if (!np)
return -EINVAL;
- if (of_property_read_u32(dn, "abilis,ngpio", &ngpio))
+ if (of_property_read_u32(np, "abilis,ngpio", &ngpio))
return -EINVAL;
- tb10x_gpio = devm_kzalloc(&pdev->dev, sizeof(*tb10x_gpio), GFP_KERNEL);
+ tb10x_gpio = devm_kzalloc(dev, sizeof(*tb10x_gpio), GFP_KERNEL);
if (tb10x_gpio == NULL)
return -ENOMEM;
- spin_lock_init(&tb10x_gpio->spinlock);
-
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- tb10x_gpio->base = devm_ioremap_resource(&pdev->dev, mem);
+ tb10x_gpio->base = devm_ioremap_resource(dev, mem);
if (IS_ERR(tb10x_gpio->base))
return PTR_ERR(tb10x_gpio->base);
- tb10x_gpio->gc.label =
- devm_kasprintf(&pdev->dev, GFP_KERNEL, "%pOF", pdev->dev.of_node);
+ tb10x_gpio->gc.label =
+ devm_kasprintf(dev, GFP_KERNEL, "%pOF", pdev->dev.of_node);
if (!tb10x_gpio->gc.label)
return -ENOMEM;
- tb10x_gpio->gc.parent = &pdev->dev;
- tb10x_gpio->gc.owner = THIS_MODULE;
- tb10x_gpio->gc.direction_input = tb10x_gpio_direction_in;
- tb10x_gpio->gc.get = tb10x_gpio_get;
- tb10x_gpio->gc.direction_output = tb10x_gpio_direction_out;
- tb10x_gpio->gc.set = tb10x_gpio_set;
- tb10x_gpio->gc.request = gpiochip_generic_request;
- tb10x_gpio->gc.free = gpiochip_generic_free;
- tb10x_gpio->gc.base = -1;
- tb10x_gpio->gc.ngpio = ngpio;
- tb10x_gpio->gc.can_sleep = false;
-
-
- ret = devm_gpiochip_add_data(&pdev->dev, &tb10x_gpio->gc, tb10x_gpio);
+ /*
+ * Initialize generic GPIO with one single register for reading and setting
+ * the lines, no special set or clear registers and a data direction register
+ * wher 1 means "output".
+ */
+ ret = bgpio_init(&tb10x_gpio->gc, dev, 4,
+ tb10x_gpio->base + OFFSET_TO_REG_DATA,
+ NULL,
+ NULL,
+ tb10x_gpio->base + OFFSET_TO_REG_DDR,
+ NULL,
+ 0);
+ if (ret) {
+ dev_err(dev, "unable to init generic GPIO\n");
+ return ret;
+ }
+ tb10x_gpio->gc.base = -1;
+ tb10x_gpio->gc.parent = dev;
+ tb10x_gpio->gc.owner = THIS_MODULE;
+ /*
+ * ngpio is set by bgpio_init() but we override it, this .request()
+ * callback also overrides the one set up by generic GPIO.
+ */
+ tb10x_gpio->gc.ngpio = ngpio;
+ tb10x_gpio->gc.request = gpiochip_generic_request;
+ tb10x_gpio->gc.free = gpiochip_generic_free;
+
+ ret = devm_gpiochip_add_data(dev, &tb10x_gpio->gc, tb10x_gpio);
if (ret < 0) {
- dev_err(&pdev->dev, "Could not add gpiochip.\n");
+ dev_err(dev, "Could not add gpiochip.\n");
return ret;
}
platform_set_drvdata(pdev, tb10x_gpio);
- if (of_find_property(dn, "interrupt-controller", NULL)) {
+ if (of_find_property(np, "interrupt-controller", NULL)) {
struct irq_chip_generic *gc;
ret = platform_get_irq(pdev, 0);
if (ret < 0) {
- dev_err(&pdev->dev, "No interrupt specified.\n");
+ dev_err(dev, "No interrupt specified.\n");
return ret;
}
tb10x_gpio->gc.to_irq = tb10x_gpio_to_irq;
tb10x_gpio->irq = ret;
- ret = devm_request_irq(&pdev->dev, ret, tb10x_gpio_irq_cascade,
+ ret = devm_request_irq(dev, ret, tb10x_gpio_irq_cascade,
IRQF_TRIGGER_NONE | IRQF_SHARED,
- dev_name(&pdev->dev), tb10x_gpio);
+ dev_name(dev), tb10x_gpio);
if (ret != 0)
return ret;
- tb10x_gpio->domain = irq_domain_add_linear(dn,
+ tb10x_gpio->domain = irq_domain_add_linear(np,
tb10x_gpio->gc.ngpio,
&irq_generic_chip_ops, NULL);
if (!tb10x_gpio->domain) {
diff --git a/drivers/gpio/gpio-tps65086.c b/drivers/gpio/gpio-tps65086.c
index b23c4d2429be..2eea98ff4ea3 100644
--- a/drivers/gpio/gpio-tps65086.c
+++ b/drivers/gpio/gpio-tps65086.c
@@ -1,20 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
* Andrew F. Davis <afd@ti.com>
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
- * kind, whether expressed or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License version 2 for more details.
- *
* Based on the TPS65912 driver
*/
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/module.h>
#include <linux/platform_device.h>
diff --git a/drivers/gpio/gpio-tps6586x.c b/drivers/gpio/gpio-tps6586x.c
index 042b9a20781a..9b6cc74f47c8 100644
--- a/drivers/gpio/gpio-tps6586x.c
+++ b/drivers/gpio/gpio-tps6586x.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* TI TPS6586x GPIO driver
*
@@ -7,22 +8,10 @@
* Based on tps6586x.c
* Copyright (c) 2010 CompuLab Ltd.
* Mike Rapoport <mike@compulab.co.il>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/errno.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/mfd/tps6586x.h>
diff --git a/drivers/gpio/gpio-tps65910.c b/drivers/gpio/gpio-tps65910.c
index e63d7dabf78b..0c785b0fd161 100644
--- a/drivers/gpio/gpio-tps65910.c
+++ b/drivers/gpio/gpio-tps65910.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* TI TPS6591x GPIO driver
*
@@ -5,18 +6,12 @@
*
* Author: Graeme Gregory <gg@slimlogic.co.uk>
* Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/errno.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/mfd/tps65910.h>
diff --git a/drivers/gpio/gpio-tps65912.c b/drivers/gpio/gpio-tps65912.c
index abc0798ef843..3ad68bd78282 100644
--- a/drivers/gpio/gpio-tps65912.c
+++ b/drivers/gpio/gpio-tps65912.c
@@ -1,23 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* GPIO driver for TI TPS65912x PMICs
*
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
* Andrew F. Davis <afd@ti.com>
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
- * kind, whether expressed or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License version 2 for more details.
- *
* Based on the Arizona GPIO driver and the previous TPS65912 driver by
* Margarita Olaya Cabrera <magi@slimlogic.co.uk>
*/
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/module.h>
#include <linux/platform_device.h>
@@ -40,9 +32,9 @@ static int tps65912_gpio_get_direction(struct gpio_chip *gc,
return ret;
if (val & GPIO_CFG_MASK)
- return GPIOF_DIR_OUT;
+ return 0;
else
- return GPIOF_DIR_IN;
+ return 1;
}
static int tps65912_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
diff --git a/drivers/gpio/gpio-ts5500.c b/drivers/gpio/gpio-ts5500.c
index 6cfeba07f882..c91890488402 100644
--- a/drivers/gpio/gpio-ts5500.c
+++ b/drivers/gpio/gpio-ts5500.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Digital I/O driver for Technologic Systems TS-5500
*
@@ -16,17 +17,12 @@
* TS-5600:
* Documentation: http://wiki.embeddedarm.com/wiki/TS-5600
* Blocks: LCD port (identical to TS-5500 LCD).
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/bitops.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/io.h>
#include <linux/module.h>
-#include <linux/platform_data/gpio-ts5500.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -318,7 +314,6 @@ static void ts5500_disable_irq(struct ts5500_priv *priv)
static int ts5500_dio_probe(struct platform_device *pdev)
{
enum ts5500_blocks block = platform_get_device_id(pdev)->driver_data;
- struct ts5500_dio_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct device *dev = &pdev->dev;
const char *name = dev_name(dev);
struct ts5500_priv *priv;
@@ -349,10 +344,6 @@ static int ts5500_dio_probe(struct platform_device *pdev)
priv->gpio_chip.set = ts5500_gpio_set;
priv->gpio_chip.to_irq = ts5500_gpio_to_irq;
priv->gpio_chip.base = -1;
- if (pdata) {
- priv->gpio_chip.base = pdata->base;
- priv->strap = pdata->strap;
- }
switch (block) {
case TS5500_DIO1:
diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c
index 9b511df5450e..fbfb648d3502 100644
--- a/drivers/gpio/gpio-twl4030.c
+++ b/drivers/gpio/gpio-twl4030.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Access to GPIOs on TWL4030/TPS659x0 chips
*
@@ -9,20 +10,6 @@
*
* Initial Code:
* Andy Lowe / Nishanth Menon
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
@@ -30,7 +17,7 @@
#include <linux/interrupt.h>
#include <linux/kthread.h>
#include <linux/irq.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/irqdomain.h>
@@ -167,6 +154,23 @@ static int twl4030_set_gpio_direction(int gpio, int is_input)
return ret;
}
+static int twl4030_get_gpio_direction(int gpio)
+{
+ u8 d_bnk = gpio >> 3;
+ u8 d_msk = BIT(gpio & 0x7);
+ u8 base = REG_GPIODATADIR1 + d_bnk;
+ int ret = 0;
+
+ ret = gpio_twl4030_read(base);
+ if (ret < 0)
+ return ret;
+
+ /* 1 = output, but gpiolib semantics are inverse so invert */
+ ret = !(ret & d_msk);
+
+ return ret;
+}
+
static int twl4030_set_gpio_dataout(int gpio, int enable)
{
u8 d_bnk = gpio >> 3;
@@ -372,6 +376,28 @@ static int twl_direction_out(struct gpio_chip *chip, unsigned offset, int value)
return ret;
}
+static int twl_get_direction(struct gpio_chip *chip, unsigned offset)
+{
+ struct gpio_twl4030_priv *priv = gpiochip_get_data(chip);
+ /*
+ * Default 0 = output
+ * LED GPIOs >= TWL4030_GPIO_MAX are always output
+ */
+ int ret = 0;
+
+ mutex_lock(&priv->mutex);
+ if (offset < TWL4030_GPIO_MAX) {
+ ret = twl4030_get_gpio_direction(offset);
+ if (ret) {
+ mutex_unlock(&priv->mutex);
+ return ret;
+ }
+ }
+ mutex_unlock(&priv->mutex);
+
+ return ret;
+}
+
static int twl_to_irq(struct gpio_chip *chip, unsigned offset)
{
struct gpio_twl4030_priv *priv = gpiochip_get_data(chip);
@@ -387,8 +413,9 @@ static const struct gpio_chip template_chip = {
.request = twl_request,
.free = twl_free,
.direction_input = twl_direction_in,
- .get = twl_get,
.direction_output = twl_direction_out,
+ .get_direction = twl_get_direction,
+ .get = twl_get,
.set = twl_set,
.to_irq = twl_to_irq,
.can_sleep = true,
diff --git a/drivers/gpio/gpio-twl6040.c b/drivers/gpio/gpio-twl6040.c
index dadeacf43e0c..c845b2ff1f43 100644
--- a/drivers/gpio/gpio-twl6040.c
+++ b/drivers/gpio/gpio-twl6040.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Access to GPOs on TWL6040 chip
*
@@ -6,28 +7,15 @@
* Authors:
* Sergio Aguirre <saaguirre@ti.com>
* Peter Ujfalusi <peter.ujfalusi@ti.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kthread.h>
#include <linux/irq.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/platform_device.h>
+#include <linux/bitops.h>
#include <linux/of.h>
#include <linux/mfd/twl6040.h>
@@ -41,7 +29,13 @@ static int twl6040gpo_get(struct gpio_chip *chip, unsigned offset)
if (ret < 0)
return ret;
- return (ret >> offset) & 1;
+ return !!(ret & BIT(offset));
+}
+
+static int twl6040gpo_get_direction(struct gpio_chip *chip, unsigned offset)
+{
+ /* This means "out" */
+ return 0;
}
static int twl6040gpo_direction_out(struct gpio_chip *chip, unsigned offset,
@@ -62,9 +56,9 @@ static void twl6040gpo_set(struct gpio_chip *chip, unsigned offset, int value)
return;
if (value)
- gpoctl = ret | (1 << offset);
+ gpoctl = ret | BIT(offset);
else
- gpoctl = ret & ~(1 << offset);
+ gpoctl = ret & ~BIT(offset);
twl6040_reg_write(twl6040, TWL6040_REG_GPOCTL, gpoctl);
}
@@ -74,6 +68,7 @@ static struct gpio_chip twl6040gpo_chip = {
.owner = THIS_MODULE,
.get = twl6040gpo_get,
.direction_output = twl6040gpo_direction_out,
+ .get_direction = twl6040gpo_get_direction,
.set = twl6040gpo_set,
.can_sleep = true,
};
diff --git a/drivers/gpio/gpio-uniphier.c b/drivers/gpio/gpio-uniphier.c
index 7fdac9060979..74551cbdb2e8 100644
--- a/drivers/gpio/gpio-uniphier.c
+++ b/drivers/gpio/gpio-uniphier.c
@@ -12,7 +12,7 @@
* GNU General Public License for more details.
*/
-#include <linux/bitops.h>
+#include <linux/bits.h>
#include <linux/gpio/driver.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c
index d4ad6d0e02a2..5960396c8d9a 100644
--- a/drivers/gpio/gpio-vf610.c
+++ b/drivers/gpio/gpio-vf610.c
@@ -1,23 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Freescale vf610 GPIO support through PORT and GPIO
*
* Copyright (c) 2014 Toradex AG.
*
* Author: Stefan Agner <stefan@agner.ch>.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
-
#include <linux/bitops.h>
#include <linux/err.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
diff --git a/drivers/gpio/gpio-viperboard.c b/drivers/gpio/gpio-viperboard.c
index e6d1328dddfa..9b604f13e302 100644
--- a/drivers/gpio/gpio-viperboard.c
+++ b/drivers/gpio/gpio-viperboard.c
@@ -1,15 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Nano River Technologies viperboard GPIO lib driver
*
* (C) 2012 by Lemonage GmbH
* Author: Lars Poeschel <poeschel@lemonage.de>
* All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
*/
#include <linux/kernel.h>
@@ -19,9 +14,8 @@
#include <linux/types.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
-
#include <linux/usb.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/mfd/viperboard.h>
diff --git a/drivers/gpio/gpio-vr41xx.c b/drivers/gpio/gpio-vr41xx.c
index 027699cec911..b13a49c89cc1 100644
--- a/drivers/gpio/gpio-vr41xx.c
+++ b/drivers/gpio/gpio-vr41xx.c
@@ -1,27 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Driver for NEC VR4100 series General-purpose I/O Unit.
*
* Copyright (C) 2002 MontaVista Software Inc.
* Author: Yoichi Yuasa <source@mvista.com>
* Copyright (C) 2003-2009 Yoichi Yuasa <yuasa@linux-mips.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/errno.h>
#include <linux/fs.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@@ -384,44 +371,6 @@ static int giu_set_direction(struct gpio_chip *chip, unsigned pin, int dir)
return 0;
}
-int vr41xx_gpio_pullupdown(unsigned int pin, gpio_pull_t pull)
-{
- u16 reg, mask;
- unsigned long flags;
-
- if ((giu_flags & GPIO_HAS_PULLUPDOWN_IO) != GPIO_HAS_PULLUPDOWN_IO)
- return -EPERM;
-
- if (pin >= 15)
- return -EINVAL;
-
- mask = 1 << pin;
-
- spin_lock_irqsave(&giu_lock, flags);
-
- if (pull == GPIO_PULL_UP || pull == GPIO_PULL_DOWN) {
- reg = giu_read(GIUTERMUPDN);
- if (pull == GPIO_PULL_UP)
- reg |= mask;
- else
- reg &= ~mask;
- giu_write(GIUTERMUPDN, reg);
-
- reg = giu_read(GIUUSEUPDN);
- reg |= mask;
- giu_write(GIUUSEUPDN, reg);
- } else {
- reg = giu_read(GIUUSEUPDN);
- reg &= ~mask;
- giu_write(GIUUSEUPDN, reg);
- }
-
- spin_unlock_irqrestore(&giu_lock, flags);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(vr41xx_gpio_pullupdown);
-
static int vr41xx_gpio_get(struct gpio_chip *chip, unsigned pin)
{
u16 reg, mask;
diff --git a/drivers/gpio/gpio-vx855.c b/drivers/gpio/gpio-vx855.c
index 98a6f1fcc561..4ff146ca32fe 100644
--- a/drivers/gpio/gpio-vx855.c
+++ b/drivers/gpio/gpio-vx855.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Linux GPIOlib driver for the VIA VX855 integrated southbridge GPIO
*
@@ -5,27 +6,10 @@
* Copyright (C) 2010 One Laptop per Child
* Author: Harald Welte <HaraldWelte@viatech.com>
* All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU 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/kernel.h>
#include <linux/module.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/platform_device.h>
diff --git a/drivers/gpio/gpio-wm831x.c b/drivers/gpio/gpio-wm831x.c
index 324813e8304e..a3a32a77041f 100644
--- a/drivers/gpio/gpio-wm831x.c
+++ b/drivers/gpio/gpio-wm831x.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* gpiolib support for Wolfson WM831x PMICs
*
@@ -5,17 +6,12 @@
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/mfd/core.h>
#include <linux/platform_device.h>
#include <linux/seq_file.h>
diff --git a/drivers/gpio/gpio-wm8350.c b/drivers/gpio/gpio-wm8350.c
index e46752e73dd9..460f0a4b04bd 100644
--- a/drivers/gpio/gpio-wm8350.c
+++ b/drivers/gpio/gpio-wm8350.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* gpiolib support for Wolfson WM835x PMICs
*
@@ -5,17 +6,12 @@
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/mfd/core.h>
#include <linux/platform_device.h>
#include <linux/seq_file.h>
diff --git a/drivers/gpio/gpio-wm8994.c b/drivers/gpio/gpio-wm8994.c
index 1e35756ac55b..9af89cf7f6bc 100644
--- a/drivers/gpio/gpio-wm8994.c
+++ b/drivers/gpio/gpio-wm8994.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* gpiolib support for Wolfson WM8994
*
@@ -5,17 +6,12 @@
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/mfd/core.h>
#include <linux/platform_device.h>
#include <linux/seq_file.h>
diff --git a/drivers/gpio/gpio-xlp.c b/drivers/gpio/gpio-xlp.c
index 8e4275eaa7d7..0a3607fd21af 100644
--- a/drivers/gpio/gpio-xlp.c
+++ b/drivers/gpio/gpio-xlp.c
@@ -1,18 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2003-2015 Broadcom Corporation
* All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/platform_device.h>
#include <linux/of_device.h>
#include <linux/module.h>
diff --git a/drivers/gpio/gpio-xtensa.c b/drivers/gpio/gpio-xtensa.c
index f16c0427952e..43d3fa5f511a 100644
--- a/drivers/gpio/gpio-xtensa.c
+++ b/drivers/gpio/gpio-xtensa.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2013 TangoTec Ltd.
* Author: Baruch Siach <baruch@tkos.co.il>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
* Driver for the Xtensa LX4 GPIO32 Option
*
* Documentation: Xtensa LX4 Microprocessor Data Book, Section 2.22
@@ -30,7 +27,7 @@
#include <linux/err.h>
#include <linux/module.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/bitops.h>
#include <linux/platform_device.h>
diff --git a/drivers/gpio/gpio-zevio.c b/drivers/gpio/gpio-zevio.c
index 3926ce9c2840..57432397e5e5 100644
--- a/drivers/gpio/gpio-zevio.c
+++ b/drivers/gpio/gpio-zevio.c
@@ -16,7 +16,7 @@
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/slab.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
/*
* Memory layout:
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index 8b9d7e42c600..55b72fbe1631 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -1,17 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* ACPI helpers for GPIO API
*
* Copyright (C) 2012, Intel Corporation
* Authors: Mathias Nyman <mathias.nyman@linux.intel.com>
* Mika Westerberg <mika.westerberg@linux.intel.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/errno.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
#include <linux/gpio/machine.h>
@@ -1198,7 +1194,7 @@ int acpi_gpio_count(struct device *dev, const char *con_id)
bool acpi_can_fallback_to_crs(struct acpi_device *adev, const char *con_id)
{
/* Never allow fallback if the device has properties */
- if (adev->data.properties || adev->driver_gpios)
+ if (acpi_dev_has_props(adev) || adev->driver_gpios)
return false;
return con_id == NULL;
diff --git a/drivers/gpio/gpiolib-devprop.c b/drivers/gpio/gpiolib-devprop.c
index f748aa3e77f7..dd517098ab95 100644
--- a/drivers/gpio/gpiolib-devprop.c
+++ b/drivers/gpio/gpiolib-devprop.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Device property helpers for GPIO chips.
*
* Copyright (C) 2016, Intel Corporation
* Author: Mika Westerberg <mika.westerberg@linux.intel.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/property.h>
@@ -32,32 +29,29 @@ void devprop_gpiochip_set_names(struct gpio_chip *chip,
struct gpio_device *gdev = chip->gpiodev;
const char **names;
int ret, i;
+ int count;
- ret = fwnode_property_read_string_array(fwnode, "gpio-line-names",
- NULL, 0);
- if (ret < 0)
+ count = fwnode_property_read_string_array(fwnode, "gpio-line-names",
+ NULL, 0);
+ if (count < 0)
return;
- if (ret != gdev->ngpio) {
- dev_warn(&gdev->dev,
- "names %d do not match number of GPIOs %d\n", ret,
- gdev->ngpio);
- return;
- }
+ if (count > gdev->ngpio)
+ count = gdev->ngpio;
- names = kcalloc(gdev->ngpio, sizeof(*names), GFP_KERNEL);
+ names = kcalloc(count, sizeof(*names), GFP_KERNEL);
if (!names)
return;
ret = fwnode_property_read_string_array(fwnode, "gpio-line-names",
- names, gdev->ngpio);
+ names, count);
if (ret < 0) {
dev_warn(&gdev->dev, "failed to read GPIO line names\n");
kfree(names);
return;
}
- for (i = 0; i < gdev->ngpio; i++)
+ for (i = 0; i < count; i++)
gdev->descs[i].name = names[i];
kfree(names);
diff --git a/drivers/gpio/devres.c b/drivers/gpio/gpiolib-devres.c
index e82cc763633c..01959369360b 100644
--- a/drivers/gpio/devres.c
+++ b/drivers/gpio/gpiolib-devres.c
@@ -1,14 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
- * drivers/gpio/devres.c - managed gpio resources
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * You 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
- *
+ * devres.c - managed gpio resources
* This file is based on kernel/irq/devres.c
*
* Copyright (c) 2011 John Crispin <john@phrozen.org>
diff --git a/drivers/gpio/gpiolib-legacy.c b/drivers/gpio/gpiolib-legacy.c
index 8b830996fe02..30e2476a6dc4 100644
--- a/drivers/gpio/gpiolib-legacy.c
+++ b/drivers/gpio/gpiolib-legacy.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index d4e7a09598fa..7f1260c78270 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* OF helpers for the GPIO API
*
* Copyright (c) 2007-2008 MontaVista Software, Inc.
*
* Author: Anton Vorontsov <avorontsov@ru.mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include <linux/device.h>
@@ -58,7 +54,8 @@ static struct gpio_desc *of_xlate_and_get_gpiod_flags(struct gpio_chip *chip,
}
static void of_gpio_flags_quirks(struct device_node *np,
- enum of_gpio_flags *flags)
+ enum of_gpio_flags *flags,
+ int index)
{
/*
* Some GPIO fixed regulator quirks.
@@ -92,6 +89,51 @@ static void of_gpio_flags_quirks(struct device_node *np,
pr_info("%s uses legacy open drain flag - update the DTS if you can\n",
of_node_full_name(np));
}
+
+ /*
+ * Legacy handling of SPI active high chip select. If we have a
+ * property named "cs-gpios" we need to inspect the child node
+ * to determine if the flags should have inverted semantics.
+ */
+ if (IS_ENABLED(CONFIG_SPI_MASTER) &&
+ of_property_read_bool(np, "cs-gpios")) {
+ struct device_node *child;
+ u32 cs;
+ int ret;
+
+ for_each_child_of_node(np, child) {
+ ret = of_property_read_u32(child, "reg", &cs);
+ if (!ret)
+ continue;
+ if (cs == index) {
+ /*
+ * SPI children have active low chip selects
+ * by default. This can be specified negatively
+ * by just omitting "spi-cs-high" in the
+ * device node, or actively by tagging on
+ * GPIO_ACTIVE_LOW as flag in the device
+ * tree. If the line is simultaneously
+ * tagged as active low in the device tree
+ * and has the "spi-cs-high" set, we get a
+ * conflict and the "spi-cs-high" flag will
+ * take precedence.
+ */
+ if (of_property_read_bool(np, "spi-cs-high")) {
+ if (*flags & OF_GPIO_ACTIVE_LOW) {
+ pr_warn("%s GPIO handle specifies active low - ignored\n",
+ of_node_full_name(np));
+ *flags &= ~OF_GPIO_ACTIVE_LOW;
+ }
+ } else {
+ if (!(*flags & OF_GPIO_ACTIVE_LOW))
+ pr_info("%s enforce active low on chipselect handle\n",
+ of_node_full_name(np));
+ *flags |= OF_GPIO_ACTIVE_LOW;
+ }
+ break;
+ }
+ }
+ }
}
/**
@@ -132,7 +174,7 @@ struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
goto out;
if (flags)
- of_gpio_flags_quirks(np, flags);
+ of_gpio_flags_quirks(np, flags, index);
pr_debug("%s: parsed '%s' property of node '%pOF[%d]' - status (%d)\n",
__func__, propname, np, index,
@@ -349,8 +391,8 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np,
else if (of_property_read_bool(np, "output-high"))
*dflags |= GPIOD_OUT_HIGH;
else {
- pr_warn("GPIO line %d (%s): no hogging state specified, bailing out\n",
- desc_to_gpio(desc), np->name);
+ pr_warn("GPIO line %d (%pOFn): no hogging state specified, bailing out\n",
+ desc_to_gpio(desc), np);
return ERR_PTR(-EINVAL);
}
diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index 3dbaf489a8a5..fbf6b1a0a4fa 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -1,8 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
#include <linux/idr.h>
#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/sysfs.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
#include <linux/interrupt.h>
@@ -444,11 +444,6 @@ static struct attribute *gpiochip_attrs[] = {
};
ATTRIBUTE_GROUPS(gpiochip);
-static struct gpio_desc *gpio_to_valid_desc(int gpio)
-{
- return gpio_is_valid(gpio) ? gpio_to_desc(gpio) : NULL;
-}
-
/*
* /sys/class/gpio/export ... write-only
* integer N ... number of GPIO to export (full access)
@@ -467,7 +462,7 @@ static ssize_t export_store(struct class *class,
if (status < 0)
goto done;
- desc = gpio_to_valid_desc(gpio);
+ desc = gpio_to_desc(gpio);
/* reject invalid GPIOs */
if (!desc) {
pr_warn("%s: invalid GPIO %ld\n", __func__, gpio);
@@ -514,7 +509,7 @@ static ssize_t unexport_store(struct class *class,
if (status < 0)
goto done;
- desc = gpio_to_valid_desc(gpio);
+ desc = gpio_to_desc(gpio);
/* reject bogus commands (gpio_unexport ignores them) */
if (!desc) {
pr_warn("%s: invalid GPIO %ld\n", __func__, gpio);
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index e8f8a1999393..230e41562462 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
#include <linux/bitmap.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -210,15 +211,15 @@ static int gpiochip_find_base(int ngpio)
*/
int gpiod_get_direction(struct gpio_desc *desc)
{
- struct gpio_chip *chip;
- unsigned offset;
- int status = -EINVAL;
+ struct gpio_chip *chip;
+ unsigned offset;
+ int status;
chip = gpiod_to_chip(desc);
offset = gpio_chip_hwgpio(desc);
if (!chip->get_direction)
- return status;
+ return -ENOTSUPP;
status = chip->get_direction(chip, offset);
if (status > 0) {
@@ -359,7 +360,7 @@ static unsigned long *gpiochip_allocate_mask(struct gpio_chip *chip)
return p;
}
-static int gpiochip_init_valid_mask(struct gpio_chip *gpiochip)
+static int gpiochip_alloc_valid_mask(struct gpio_chip *gpiochip)
{
#ifdef CONFIG_OF_GPIO
int size;
@@ -380,6 +381,14 @@ static int gpiochip_init_valid_mask(struct gpio_chip *gpiochip)
return 0;
}
+static int gpiochip_init_valid_mask(struct gpio_chip *gpiochip)
+{
+ if (gpiochip->init_valid_mask)
+ return gpiochip->init_valid_mask(gpiochip);
+
+ return 0;
+}
+
static void gpiochip_free_valid_mask(struct gpio_chip *gpiochip)
{
kfree(gpiochip->valid_mask);
@@ -427,7 +436,7 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd,
struct linehandle_state *lh = filep->private_data;
void __user *ip = (void __user *)arg;
struct gpiohandle_data ghd;
- int vals[GPIOHANDLES_MAX];
+ DECLARE_BITMAP(vals, GPIOHANDLES_MAX);
int i;
if (cmd == GPIOHANDLE_GET_LINE_VALUES_IOCTL) {
@@ -436,13 +445,14 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd,
true,
lh->numdescs,
lh->descs,
+ NULL,
vals);
if (ret)
return ret;
memset(&ghd, 0, sizeof(ghd));
for (i = 0; i < lh->numdescs; i++)
- ghd.values[i] = vals[i];
+ ghd.values[i] = test_bit(i, vals);
if (copy_to_user(ip, &ghd, sizeof(ghd)))
return -EFAULT;
@@ -461,13 +471,14 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd,
/* Clamp all values to [0,1] */
for (i = 0; i < lh->numdescs; i++)
- vals[i] = !!ghd.values[i];
+ __assign_bit(i, vals, ghd.values[i]);
/* Reuse the array setting function */
return gpiod_set_array_value_complex(false,
true,
lh->numdescs,
lh->descs,
+ NULL,
vals);
}
return -EINVAL;
@@ -571,7 +582,7 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
if (ret)
goto out_free_descs;
lh->descs[i] = desc;
- count = i;
+ count = i + 1;
if (lflags & GPIOHANDLE_REQUEST_ACTIVE_LOW)
set_bit(FLAG_ACTIVE_LOW, &desc->flags);
@@ -812,26 +823,26 @@ static irqreturn_t lineevent_irq_thread(int irq, void *p)
{
struct lineevent_state *le = p;
struct gpioevent_data ge;
- int ret, level;
+ int ret;
/* Do not leak kernel stack to userspace */
memset(&ge, 0, sizeof(ge));
ge.timestamp = le->timestamp;
- level = gpiod_get_value_cansleep(le->desc);
if (le->eflags & GPIOEVENT_REQUEST_RISING_EDGE
&& le->eflags & GPIOEVENT_REQUEST_FALLING_EDGE) {
+ int level = gpiod_get_value_cansleep(le->desc);
if (level)
/* Emit low-to-high event */
ge.id = GPIOEVENT_EVENT_RISING_EDGE;
else
/* Emit high-to-low event */
ge.id = GPIOEVENT_EVENT_FALLING_EDGE;
- } else if (le->eflags & GPIOEVENT_REQUEST_RISING_EDGE && level) {
+ } else if (le->eflags & GPIOEVENT_REQUEST_RISING_EDGE) {
/* Emit low-to-high event */
ge.id = GPIOEVENT_EVENT_RISING_EDGE;
- } else if (le->eflags & GPIOEVENT_REQUEST_FALLING_EDGE && !level) {
+ } else if (le->eflags & GPIOEVENT_REQUEST_FALLING_EDGE) {
/* Emit high-to-low event */
ge.id = GPIOEVENT_EVENT_FALLING_EDGE;
} else {
@@ -942,7 +953,6 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
if (eflags & GPIOEVENT_REQUEST_FALLING_EDGE)
irqflags |= IRQF_TRIGGER_FALLING;
irqflags |= IRQF_ONESHOT;
- irqflags |= IRQF_SHARED;
INIT_KFIFO(le->events);
init_waitqueue_head(&le->wait);
@@ -1341,19 +1351,8 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
spin_unlock_irqrestore(&gpio_lock, flags);
- for (i = 0; i < chip->ngpio; i++) {
- struct gpio_desc *desc = &gdev->descs[i];
-
- desc->gdev = gdev;
-
- /* REVISIT: most hardware initializes GPIOs as inputs (often
- * with pullups enabled) so power usage is minimized. Linux
- * code should set the gpio direction first thing; but until
- * it does, and in case chip->get_direction is not set, we may
- * expose the wrong direction in sysfs.
- */
- desc->flags = !chip->direction_input ? (1 << FLAG_IS_OUT) : 0;
- }
+ for (i = 0; i < chip->ngpio; i++)
+ gdev->descs[i].gdev = gdev;
#ifdef CONFIG_PINCTRL
INIT_LIST_HEAD(&gdev->pin_ranges);
@@ -1367,7 +1366,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
if (status)
goto err_remove_from_list;
- status = gpiochip_init_valid_mask(chip);
+ status = gpiochip_alloc_valid_mask(chip);
if (status)
goto err_remove_irqchip_mask;
@@ -1379,6 +1378,21 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
if (status)
goto err_remove_chip;
+ status = gpiochip_init_valid_mask(chip);
+ if (status)
+ goto err_remove_chip;
+
+ for (i = 0; i < chip->ngpio; i++) {
+ struct gpio_desc *desc = &gdev->descs[i];
+
+ if (chip->get_direction && gpiochip_line_is_valid(chip, i))
+ desc->flags = !chip->get_direction(chip, i) ?
+ (1 << FLAG_IS_OUT) : 0;
+ else
+ desc->flags = !chip->direction_input ?
+ (1 << FLAG_IS_OUT) : 0;
+ }
+
acpi_gpiochip_add(chip);
machine_gpiochip_add(chip);
@@ -1512,7 +1526,7 @@ static int devm_gpio_chip_match(struct device *dev, void *res, void *data)
/**
* devm_gpiochip_add_data() - Resource manager gpiochip_add_data()
- * @dev: the device pointer on which irq_chip belongs to.
+ * @dev: pointer to the device that gpio_chip belongs to.
* @chip: the chip to register, with chip->base initialized
* @data: driver-private data associated with this chip
*
@@ -1649,7 +1663,6 @@ EXPORT_SYMBOL_GPL(gpiochip_irqchip_irq_valid);
/**
* gpiochip_set_cascaded_irqchip() - connects a cascaded irqchip to a gpiochip
* @gpiochip: the gpiochip to set the irqchip chain to
- * @irqchip: the irqchip to chain to the gpiochip
* @parent_irq: the irq number corresponding to the parent IRQ for this
* chained irqchip
* @parent_handler: the parent interrupt handler for the accumulated IRQ
@@ -1657,12 +1670,9 @@ EXPORT_SYMBOL_GPL(gpiochip_irqchip_irq_valid);
* cascaded, pass NULL in this handler argument
*/
static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gpiochip,
- struct irq_chip *irqchip,
unsigned int parent_irq,
irq_flow_handler_t parent_handler)
{
- unsigned int offset;
-
if (!gpiochip->irq.domain) {
chip_err(gpiochip, "called %s before setting up irqchip\n",
__func__);
@@ -1682,17 +1692,10 @@ static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gpiochip,
irq_set_chained_handler_and_data(parent_irq, parent_handler,
gpiochip);
- gpiochip->irq.parents = &parent_irq;
+ gpiochip->irq.parent_irq = parent_irq;
+ gpiochip->irq.parents = &gpiochip->irq.parent_irq;
gpiochip->irq.num_parents = 1;
}
-
- /* Set the parent IRQ for all affected IRQs */
- for (offset = 0; offset < gpiochip->ngpio; offset++) {
- if (!gpiochip_irqchip_irq_valid(gpiochip, offset))
- continue;
- irq_set_parent(irq_find_mapping(gpiochip->irq.domain, offset),
- parent_irq);
- }
}
/**
@@ -1702,8 +1705,7 @@ static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gpiochip,
* @parent_irq: the irq number corresponding to the parent IRQ for this
* chained irqchip
* @parent_handler: the parent interrupt handler for the accumulated IRQ
- * coming out of the gpiochip. If the interrupt is nested rather than
- * cascaded, pass NULL in this handler argument
+ * coming out of the gpiochip.
*/
void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
struct irq_chip *irqchip,
@@ -1715,8 +1717,7 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
return;
}
- gpiochip_set_cascaded_irqchip(gpiochip, irqchip, parent_irq,
- parent_handler);
+ gpiochip_set_cascaded_irqchip(gpiochip, parent_irq, parent_handler);
}
EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip);
@@ -1731,8 +1732,7 @@ void gpiochip_set_nested_irqchip(struct gpio_chip *gpiochip,
struct irq_chip *irqchip,
unsigned int parent_irq)
{
- gpiochip_set_cascaded_irqchip(gpiochip, irqchip, parent_irq,
- NULL);
+ gpiochip_set_cascaded_irqchip(gpiochip, parent_irq, NULL);
}
EXPORT_SYMBOL_GPL(gpiochip_set_nested_irqchip);
@@ -1804,39 +1804,75 @@ static const struct irq_domain_ops gpiochip_domain_ops = {
.xlate = irq_domain_xlate_twocell,
};
+static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ if (!gpiochip_irqchip_irq_valid(chip, offset))
+ return -ENXIO;
+
+ return irq_create_mapping(chip->irq.domain, offset);
+}
+
static int gpiochip_irq_reqres(struct irq_data *d)
{
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
- int ret;
-
- if (!try_module_get(chip->gpiodev->owner))
- return -ENODEV;
- ret = gpiochip_lock_as_irq(chip, d->hwirq);
- if (ret) {
- chip_err(chip,
- "unable to lock HW IRQ %lu for IRQ\n",
- d->hwirq);
- module_put(chip->gpiodev->owner);
- return ret;
- }
- return 0;
+ return gpiochip_reqres_irq(chip, d->hwirq);
}
static void gpiochip_irq_relres(struct irq_data *d)
{
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
- gpiochip_unlock_as_irq(chip, d->hwirq);
- module_put(chip->gpiodev->owner);
+ gpiochip_relres_irq(chip, d->hwirq);
}
-static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
+static void gpiochip_irq_enable(struct irq_data *d)
{
- if (!gpiochip_irqchip_irq_valid(chip, offset))
- return -ENXIO;
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
- return irq_create_mapping(chip->irq.domain, offset);
+ gpiochip_enable_irq(chip, d->hwirq);
+ if (chip->irq.irq_enable)
+ chip->irq.irq_enable(d);
+ else
+ chip->irq.chip->irq_unmask(d);
+}
+
+static void gpiochip_irq_disable(struct irq_data *d)
+{
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+
+ if (chip->irq.irq_disable)
+ chip->irq.irq_disable(d);
+ else
+ chip->irq.chip->irq_mask(d);
+ gpiochip_disable_irq(chip, d->hwirq);
+}
+
+static void gpiochip_set_irq_hooks(struct gpio_chip *gpiochip)
+{
+ struct irq_chip *irqchip = gpiochip->irq.chip;
+
+ if (!irqchip->irq_request_resources &&
+ !irqchip->irq_release_resources) {
+ irqchip->irq_request_resources = gpiochip_irq_reqres;
+ irqchip->irq_release_resources = gpiochip_irq_relres;
+ }
+ if (WARN_ON(gpiochip->irq.irq_enable))
+ return;
+ /* Check if the irqchip already has this hook... */
+ if (irqchip->irq_enable == gpiochip_irq_enable) {
+ /*
+ * ...and if so, give a gentle warning that this is bad
+ * practice.
+ */
+ chip_info(gpiochip,
+ "detected irqchip that is shared with multiple gpiochips: please fix the driver.\n");
+ return;
+ }
+ gpiochip->irq.irq_enable = irqchip->irq_enable;
+ gpiochip->irq.irq_disable = irqchip->irq_disable;
+ irqchip->irq_enable = gpiochip_irq_enable;
+ irqchip->irq_disable = gpiochip_irq_disable;
}
/**
@@ -1897,16 +1933,6 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip,
if (!gpiochip->irq.domain)
return -EINVAL;
- /*
- * It is possible for a driver to override this, but only if the
- * alternative functions are both implemented.
- */
- if (!irqchip->irq_request_resources &&
- !irqchip->irq_release_resources) {
- irqchip->irq_request_resources = gpiochip_irq_reqres;
- irqchip->irq_release_resources = gpiochip_irq_relres;
- }
-
if (gpiochip->irq.parent_handler) {
void *data = gpiochip->irq.parent_handler_data ?: gpiochip;
@@ -1922,6 +1948,8 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip,
}
}
+ gpiochip_set_irq_hooks(gpiochip);
+
acpi_gpiochip_request_interrupts(gpiochip);
return 0;
@@ -1935,11 +1963,12 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip,
*/
static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
{
+ struct irq_chip *irqchip = gpiochip->irq.chip;
unsigned int offset;
acpi_gpiochip_free_interrupts(gpiochip);
- if (gpiochip->irq.chip && gpiochip->irq.parent_handler) {
+ if (irqchip && gpiochip->irq.parent_handler) {
struct gpio_irq_chip *irq = &gpiochip->irq;
unsigned int i;
@@ -1963,11 +1992,19 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
irq_domain_remove(gpiochip->irq.domain);
}
- if (gpiochip->irq.chip) {
- gpiochip->irq.chip->irq_request_resources = NULL;
- gpiochip->irq.chip->irq_release_resources = NULL;
- gpiochip->irq.chip = NULL;
+ if (irqchip) {
+ if (irqchip->irq_request_resources == gpiochip_irq_reqres) {
+ irqchip->irq_request_resources = NULL;
+ irqchip->irq_release_resources = NULL;
+ }
+ if (irqchip->irq_enable == gpiochip_irq_enable) {
+ irqchip->irq_enable = gpiochip->irq.irq_enable;
+ irqchip->irq_disable = gpiochip->irq.irq_disable;
+ }
}
+ gpiochip->irq.irq_enable = NULL;
+ gpiochip->irq.irq_disable = NULL;
+ gpiochip->irq.chip = NULL;
gpiochip_irqchip_free_valid_mask(gpiochip);
}
@@ -2056,15 +2093,7 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
return -EINVAL;
}
- /*
- * It is possible for a driver to override this, but only if the
- * alternative functions are both implemented.
- */
- if (!irqchip->irq_request_resources &&
- !irqchip->irq_release_resources) {
- irqchip->irq_request_resources = gpiochip_irq_reqres;
- irqchip->irq_release_resources = gpiochip_irq_relres;
- }
+ gpiochip_set_irq_hooks(gpiochip);
acpi_gpiochip_request_interrupts(gpiochip);
@@ -2512,19 +2541,38 @@ EXPORT_SYMBOL_GPL(gpiochip_free_own_desc);
int gpiod_direction_input(struct gpio_desc *desc)
{
struct gpio_chip *chip;
- int status = -EINVAL;
+ int status = 0;
VALIDATE_DESC(desc);
chip = desc->gdev->chip;
- if (!chip->get || !chip->direction_input) {
+ /*
+ * It is legal to have no .get() and .direction_input() specified if
+ * the chip is output-only, but you can't specify .direction_input()
+ * and not support the .get() operation, that doesn't make sense.
+ */
+ if (!chip->get && chip->direction_input) {
gpiod_warn(desc,
- "%s: missing get() or direction_input() operations\n",
- __func__);
+ "%s: missing get() but have direction_input()\n",
+ __func__);
return -EIO;
}
- status = chip->direction_input(chip, gpio_chip_hwgpio(desc));
+ /*
+ * If we have a .direction_input() callback, things are simple,
+ * just call it. Else we are some input-only chip so try to check the
+ * direction (if .get_direction() is supported) else we silently
+ * assume we are in input mode after this.
+ */
+ if (chip->direction_input) {
+ status = chip->direction_input(chip, gpio_chip_hwgpio(desc));
+ } else if (chip->get_direction &&
+ (chip->get_direction(chip, gpio_chip_hwgpio(desc)) != 1)) {
+ gpiod_warn(desc,
+ "%s: missing direction_input() operation and line is output\n",
+ __func__);
+ return -EIO;
+ }
if (status == 0)
clear_bit(FLAG_IS_OUT, &desc->flags);
@@ -2546,16 +2594,38 @@ static int gpiod_direction_output_raw_commit(struct gpio_desc *desc, int value)
{
struct gpio_chip *gc = desc->gdev->chip;
int val = !!value;
- int ret;
+ int ret = 0;
- if (!gc->set || !gc->direction_output) {
+ /*
+ * It's OK not to specify .direction_output() if the gpiochip is
+ * output-only, but if there is then not even a .set() operation it
+ * is pretty tricky to drive the output line.
+ */
+ if (!gc->set && !gc->direction_output) {
gpiod_warn(desc,
- "%s: missing set() or direction_output() operations\n",
- __func__);
+ "%s: missing set() and direction_output() operations\n",
+ __func__);
return -EIO;
}
- ret = gc->direction_output(gc, gpio_chip_hwgpio(desc), val);
+ if (gc->direction_output) {
+ ret = gc->direction_output(gc, gpio_chip_hwgpio(desc), val);
+ } else {
+ /* Check that we are in output mode if we can */
+ if (gc->get_direction &&
+ gc->get_direction(gc, gpio_chip_hwgpio(desc))) {
+ gpiod_warn(desc,
+ "%s: missing direction_output() operation\n",
+ __func__);
+ return -EIO;
+ }
+ /*
+ * If we can't actively set the direction, we are some
+ * output-only chip, so just drive the output as desired.
+ */
+ gc->set(gc, gpio_chip_hwgpio(desc), val);
+ }
+
if (!ret)
set_bit(FLAG_IS_OUT, &desc->flags);
trace_gpio_value(desc_to_gpio(desc), 0, val);
@@ -2604,8 +2674,9 @@ int gpiod_direction_output(struct gpio_desc *desc, int value)
else
value = !!value;
- /* GPIOs used for IRQs shall not be set as output */
- if (test_bit(FLAG_USED_AS_IRQ, &desc->flags)) {
+ /* GPIOs used for enabled IRQs shall not be set as output */
+ if (test_bit(FLAG_USED_AS_IRQ, &desc->flags) &&
+ test_bit(FLAG_IRQ_IS_ENABLED, &desc->flags)) {
gpiod_err(desc,
"%s: tried to set a GPIO tied to an IRQ as output\n",
__func__);
@@ -2784,9 +2855,39 @@ static int gpio_chip_get_multiple(struct gpio_chip *chip,
int gpiod_get_array_value_complex(bool raw, bool can_sleep,
unsigned int array_size,
struct gpio_desc **desc_array,
- int *value_array)
+ struct gpio_array *array_info,
+ unsigned long *value_bitmap)
{
- int i = 0;
+ int err, i = 0;
+
+ /*
+ * Validate array_info against desc_array and its size.
+ * It should immediately follow desc_array if both
+ * have been obtained from the same gpiod_get_array() call.
+ */
+ if (array_info && array_info->desc == desc_array &&
+ array_size <= array_info->size &&
+ (void *)array_info == desc_array + array_info->size) {
+ if (!can_sleep)
+ WARN_ON(array_info->chip->can_sleep);
+
+ err = gpio_chip_get_multiple(array_info->chip,
+ array_info->get_mask,
+ value_bitmap);
+ if (err)
+ return err;
+
+ if (!raw && !bitmap_empty(array_info->invert_mask, array_size))
+ bitmap_xor(value_bitmap, value_bitmap,
+ array_info->invert_mask, array_size);
+
+ if (bitmap_full(array_info->get_mask, array_size))
+ return 0;
+
+ i = find_first_zero_bit(array_info->get_mask, array_size);
+ } else {
+ array_info = NULL;
+ }
while (i < array_size) {
struct gpio_chip *chip = desc_array[i]->gdev->chip;
@@ -2818,6 +2919,10 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
__set_bit(hwgpio, mask);
i++;
+
+ if (array_info)
+ i = find_next_zero_bit(array_info->get_mask,
+ array_size, i);
} while ((i < array_size) &&
(desc_array[i]->gdev->chip == chip));
@@ -2828,15 +2933,20 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
return ret;
}
- for (j = first; j < i; j++) {
+ for (j = first; j < i; ) {
const struct gpio_desc *desc = desc_array[j];
int hwgpio = gpio_chip_hwgpio(desc);
int value = test_bit(hwgpio, bits);
if (!raw && test_bit(FLAG_ACTIVE_LOW, &desc->flags))
value = !value;
- value_array[j] = value;
+ __assign_bit(j, value_bitmap, value);
trace_gpio_value(desc_to_gpio(desc), 1, value);
+ j++;
+
+ if (array_info)
+ j = find_next_zero_bit(array_info->get_mask, i,
+ j);
}
if (mask != fastpath)
@@ -2895,9 +3005,10 @@ EXPORT_SYMBOL_GPL(gpiod_get_value);
/**
* gpiod_get_raw_array_value() - read raw values from an array of GPIOs
- * @array_size: number of elements in the descriptor / value arrays
+ * @array_size: number of elements in the descriptor array / value bitmap
* @desc_array: array of GPIO descriptors whose values will be read
- * @value_array: array to store the read values
+ * @array_info: information on applicability of fast bitmap processing path
+ * @value_bitmap: bitmap to store the read values
*
* Read the raw values of the GPIOs, i.e. the values of the physical lines
* without regard for their ACTIVE_LOW status. Return 0 in case of success,
@@ -2907,20 +3018,24 @@ EXPORT_SYMBOL_GPL(gpiod_get_value);
* and it will complain if the GPIO chip functions potentially sleep.
*/
int gpiod_get_raw_array_value(unsigned int array_size,
- struct gpio_desc **desc_array, int *value_array)
+ struct gpio_desc **desc_array,
+ struct gpio_array *array_info,
+ unsigned long *value_bitmap)
{
if (!desc_array)
return -EINVAL;
return gpiod_get_array_value_complex(true, false, array_size,
- desc_array, value_array);
+ desc_array, array_info,
+ value_bitmap);
}
EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value);
/**
* gpiod_get_array_value() - read values from an array of GPIOs
- * @array_size: number of elements in the descriptor / value arrays
+ * @array_size: number of elements in the descriptor array / value bitmap
* @desc_array: array of GPIO descriptors whose values will be read
- * @value_array: array to store the read values
+ * @array_info: information on applicability of fast bitmap processing path
+ * @value_bitmap: bitmap to store the read values
*
* Read the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status
* into account. Return 0 in case of success, else an error code.
@@ -2929,12 +3044,15 @@ EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value);
* and it will complain if the GPIO chip functions potentially sleep.
*/
int gpiod_get_array_value(unsigned int array_size,
- struct gpio_desc **desc_array, int *value_array)
+ struct gpio_desc **desc_array,
+ struct gpio_array *array_info,
+ unsigned long *value_bitmap)
{
if (!desc_array)
return -EINVAL;
return gpiod_get_array_value_complex(false, false, array_size,
- desc_array, value_array);
+ desc_array, array_info,
+ value_bitmap);
}
EXPORT_SYMBOL_GPL(gpiod_get_array_value);
@@ -3025,12 +3143,39 @@ static void gpio_chip_set_multiple(struct gpio_chip *chip,
}
int gpiod_set_array_value_complex(bool raw, bool can_sleep,
- unsigned int array_size,
- struct gpio_desc **desc_array,
- int *value_array)
+ unsigned int array_size,
+ struct gpio_desc **desc_array,
+ struct gpio_array *array_info,
+ unsigned long *value_bitmap)
{
int i = 0;
+ /*
+ * Validate array_info against desc_array and its size.
+ * It should immediately follow desc_array if both
+ * have been obtained from the same gpiod_get_array() call.
+ */
+ if (array_info && array_info->desc == desc_array &&
+ array_size <= array_info->size &&
+ (void *)array_info == desc_array + array_info->size) {
+ if (!can_sleep)
+ WARN_ON(array_info->chip->can_sleep);
+
+ if (!raw && !bitmap_empty(array_info->invert_mask, array_size))
+ bitmap_xor(value_bitmap, value_bitmap,
+ array_info->invert_mask, array_size);
+
+ gpio_chip_set_multiple(array_info->chip, array_info->set_mask,
+ value_bitmap);
+
+ if (bitmap_full(array_info->set_mask, array_size))
+ return 0;
+
+ i = find_first_zero_bit(array_info->set_mask, array_size);
+ } else {
+ array_info = NULL;
+ }
+
while (i < array_size) {
struct gpio_chip *chip = desc_array[i]->gdev->chip;
unsigned long fastpath[2 * BITS_TO_LONGS(FASTPATH_NGPIO)];
@@ -3056,9 +3201,16 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
do {
struct gpio_desc *desc = desc_array[i];
int hwgpio = gpio_chip_hwgpio(desc);
- int value = value_array[i];
+ int value = test_bit(i, value_bitmap);
- if (!raw && test_bit(FLAG_ACTIVE_LOW, &desc->flags))
+ /*
+ * Pins applicable for fast input but not for
+ * fast output processing may have been already
+ * inverted inside the fast path, skip them.
+ */
+ if (!raw && !(array_info &&
+ test_bit(i, array_info->invert_mask)) &&
+ test_bit(FLAG_ACTIVE_LOW, &desc->flags))
value = !value;
trace_gpio_value(desc_to_gpio(desc), 0, value);
/*
@@ -3078,6 +3230,10 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
count++;
}
i++;
+
+ if (array_info)
+ i = find_next_zero_bit(array_info->set_mask,
+ array_size, i);
} while ((i < array_size) &&
(desc_array[i]->gdev->chip == chip));
/* push collected bits to outputs */
@@ -3152,9 +3308,10 @@ EXPORT_SYMBOL_GPL(gpiod_set_value);
/**
* gpiod_set_raw_array_value() - assign values to an array of GPIOs
- * @array_size: number of elements in the descriptor / value arrays
+ * @array_size: number of elements in the descriptor array / value bitmap
* @desc_array: array of GPIO descriptors whose values will be assigned
- * @value_array: array of values to assign
+ * @array_info: information on applicability of fast bitmap processing path
+ * @value_bitmap: bitmap of values to assign
*
* Set the raw values of the GPIOs, i.e. the values of the physical lines
* without regard for their ACTIVE_LOW status.
@@ -3163,20 +3320,23 @@ EXPORT_SYMBOL_GPL(gpiod_set_value);
* complain if the GPIO chip functions potentially sleep.
*/
int gpiod_set_raw_array_value(unsigned int array_size,
- struct gpio_desc **desc_array, int *value_array)
+ struct gpio_desc **desc_array,
+ struct gpio_array *array_info,
+ unsigned long *value_bitmap)
{
if (!desc_array)
return -EINVAL;
return gpiod_set_array_value_complex(true, false, array_size,
- desc_array, value_array);
+ desc_array, array_info, value_bitmap);
}
EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value);
/**
* gpiod_set_array_value() - assign values to an array of GPIOs
- * @array_size: number of elements in the descriptor / value arrays
+ * @array_size: number of elements in the descriptor array / value bitmap
* @desc_array: array of GPIO descriptors whose values will be assigned
- * @value_array: array of values to assign
+ * @array_info: information on applicability of fast bitmap processing path
+ * @value_bitmap: bitmap of values to assign
*
* Set the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status
* into account.
@@ -3184,13 +3344,16 @@ EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value);
* This function should be called from contexts where we cannot sleep, and will
* complain if the GPIO chip functions potentially sleep.
*/
-void gpiod_set_array_value(unsigned int array_size,
- struct gpio_desc **desc_array, int *value_array)
+int gpiod_set_array_value(unsigned int array_size,
+ struct gpio_desc **desc_array,
+ struct gpio_array *array_info,
+ unsigned long *value_bitmap)
{
if (!desc_array)
- return;
- gpiod_set_array_value_complex(false, false, array_size, desc_array,
- value_array);
+ return -EINVAL;
+ return gpiod_set_array_value_complex(false, false, array_size,
+ desc_array, array_info,
+ value_bitmap);
}
EXPORT_SYMBOL_GPL(gpiod_set_array_value);
@@ -3292,6 +3455,7 @@ int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset)
}
set_bit(FLAG_USED_AS_IRQ, &desc->flags);
+ set_bit(FLAG_IRQ_IS_ENABLED, &desc->flags);
/*
* If the consumer has not set up a label (such as when the
@@ -3322,6 +3486,7 @@ void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset)
return;
clear_bit(FLAG_USED_AS_IRQ, &desc->flags);
+ clear_bit(FLAG_IRQ_IS_ENABLED, &desc->flags);
/* If we only had this marking, erase it */
if (desc->label && !strcmp(desc->label, "interrupt"))
@@ -3329,6 +3494,28 @@ void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset)
}
EXPORT_SYMBOL_GPL(gpiochip_unlock_as_irq);
+void gpiochip_disable_irq(struct gpio_chip *chip, unsigned int offset)
+{
+ struct gpio_desc *desc = gpiochip_get_desc(chip, offset);
+
+ if (!IS_ERR(desc) &&
+ !WARN_ON(!test_bit(FLAG_USED_AS_IRQ, &desc->flags)))
+ clear_bit(FLAG_IRQ_IS_ENABLED, &desc->flags);
+}
+EXPORT_SYMBOL_GPL(gpiochip_disable_irq);
+
+void gpiochip_enable_irq(struct gpio_chip *chip, unsigned int offset)
+{
+ struct gpio_desc *desc = gpiochip_get_desc(chip, offset);
+
+ if (!IS_ERR(desc) &&
+ !WARN_ON(!test_bit(FLAG_USED_AS_IRQ, &desc->flags))) {
+ WARN_ON(test_bit(FLAG_IS_OUT, &desc->flags));
+ set_bit(FLAG_IRQ_IS_ENABLED, &desc->flags);
+ }
+}
+EXPORT_SYMBOL_GPL(gpiochip_enable_irq);
+
bool gpiochip_line_is_irq(struct gpio_chip *chip, unsigned int offset)
{
if (offset >= chip->ngpio)
@@ -3338,6 +3525,30 @@ bool gpiochip_line_is_irq(struct gpio_chip *chip, unsigned int offset)
}
EXPORT_SYMBOL_GPL(gpiochip_line_is_irq);
+int gpiochip_reqres_irq(struct gpio_chip *chip, unsigned int offset)
+{
+ int ret;
+
+ if (!try_module_get(chip->gpiodev->owner))
+ return -ENODEV;
+
+ ret = gpiochip_lock_as_irq(chip, offset);
+ if (ret) {
+ chip_err(chip, "unable to lock HW IRQ %u for IRQ\n", offset);
+ module_put(chip->gpiodev->owner);
+ return ret;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(gpiochip_reqres_irq);
+
+void gpiochip_relres_irq(struct gpio_chip *chip, unsigned int offset)
+{
+ gpiochip_unlock_as_irq(chip, offset);
+ module_put(chip->gpiodev->owner);
+}
+EXPORT_SYMBOL_GPL(gpiochip_relres_irq);
+
bool gpiochip_line_is_open_drain(struct gpio_chip *chip, unsigned int offset)
{
if (offset >= chip->ngpio)
@@ -3410,9 +3621,10 @@ EXPORT_SYMBOL_GPL(gpiod_get_value_cansleep);
/**
* gpiod_get_raw_array_value_cansleep() - read raw values from an array of GPIOs
- * @array_size: number of elements in the descriptor / value arrays
+ * @array_size: number of elements in the descriptor array / value bitmap
* @desc_array: array of GPIO descriptors whose values will be read
- * @value_array: array to store the read values
+ * @array_info: information on applicability of fast bitmap processing path
+ * @value_bitmap: bitmap to store the read values
*
* Read the raw values of the GPIOs, i.e. the values of the physical lines
* without regard for their ACTIVE_LOW status. Return 0 in case of success,
@@ -3422,21 +3634,24 @@ EXPORT_SYMBOL_GPL(gpiod_get_value_cansleep);
*/
int gpiod_get_raw_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array,
- int *value_array)
+ struct gpio_array *array_info,
+ unsigned long *value_bitmap)
{
might_sleep_if(extra_checks);
if (!desc_array)
return -EINVAL;
return gpiod_get_array_value_complex(true, true, array_size,
- desc_array, value_array);
+ desc_array, array_info,
+ value_bitmap);
}
EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value_cansleep);
/**
* gpiod_get_array_value_cansleep() - read values from an array of GPIOs
- * @array_size: number of elements in the descriptor / value arrays
+ * @array_size: number of elements in the descriptor array / value bitmap
* @desc_array: array of GPIO descriptors whose values will be read
- * @value_array: array to store the read values
+ * @array_info: information on applicability of fast bitmap processing path
+ * @value_bitmap: bitmap to store the read values
*
* Read the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status
* into account. Return 0 in case of success, else an error code.
@@ -3445,13 +3660,15 @@ EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value_cansleep);
*/
int gpiod_get_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array,
- int *value_array)
+ struct gpio_array *array_info,
+ unsigned long *value_bitmap)
{
might_sleep_if(extra_checks);
if (!desc_array)
return -EINVAL;
return gpiod_get_array_value_complex(false, true, array_size,
- desc_array, value_array);
+ desc_array, array_info,
+ value_bitmap);
}
EXPORT_SYMBOL_GPL(gpiod_get_array_value_cansleep);
@@ -3493,9 +3710,10 @@ EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep);
/**
* gpiod_set_raw_array_value_cansleep() - assign values to an array of GPIOs
- * @array_size: number of elements in the descriptor / value arrays
+ * @array_size: number of elements in the descriptor array / value bitmap
* @desc_array: array of GPIO descriptors whose values will be assigned
- * @value_array: array of values to assign
+ * @array_info: information on applicability of fast bitmap processing path
+ * @value_bitmap: bitmap of values to assign
*
* Set the raw values of the GPIOs, i.e. the values of the physical lines
* without regard for their ACTIVE_LOW status.
@@ -3503,14 +3721,15 @@ EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep);
* This function is to be called from contexts that can sleep.
*/
int gpiod_set_raw_array_value_cansleep(unsigned int array_size,
- struct gpio_desc **desc_array,
- int *value_array)
+ struct gpio_desc **desc_array,
+ struct gpio_array *array_info,
+ unsigned long *value_bitmap)
{
might_sleep_if(extra_checks);
if (!desc_array)
return -EINVAL;
return gpiod_set_array_value_complex(true, true, array_size, desc_array,
- value_array);
+ array_info, value_bitmap);
}
EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value_cansleep);
@@ -3533,24 +3752,27 @@ void gpiod_add_lookup_tables(struct gpiod_lookup_table **tables, size_t n)
/**
* gpiod_set_array_value_cansleep() - assign values to an array of GPIOs
- * @array_size: number of elements in the descriptor / value arrays
+ * @array_size: number of elements in the descriptor array / value bitmap
* @desc_array: array of GPIO descriptors whose values will be assigned
- * @value_array: array of values to assign
+ * @array_info: information on applicability of fast bitmap processing path
+ * @value_bitmap: bitmap of values to assign
*
* Set the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status
* into account.
*
* This function is to be called from contexts that can sleep.
*/
-void gpiod_set_array_value_cansleep(unsigned int array_size,
- struct gpio_desc **desc_array,
- int *value_array)
+int gpiod_set_array_value_cansleep(unsigned int array_size,
+ struct gpio_desc **desc_array,
+ struct gpio_array *array_info,
+ unsigned long *value_bitmap)
{
might_sleep_if(extra_checks);
if (!desc_array)
- return;
- gpiod_set_array_value_complex(false, true, array_size, desc_array,
- value_array);
+ return -EINVAL;
+ return gpiod_set_array_value_complex(false, true, array_size,
+ desc_array, array_info,
+ value_bitmap);
}
EXPORT_SYMBOL_GPL(gpiod_set_array_value_cansleep);
@@ -3908,8 +4130,23 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
* the device name as label
*/
status = gpiod_request(desc, con_id ? con_id : devname);
- if (status < 0)
- return ERR_PTR(status);
+ if (status < 0) {
+ if (status == -EBUSY && flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE) {
+ /*
+ * This happens when there are several consumers for
+ * the same GPIO line: we just return here without
+ * further initialization. It is a bit if a hack.
+ * This is necessary to support fixed regulators.
+ *
+ * FIXME: Make this more sane and safe.
+ */
+ dev_info(dev, "nonexclusive access to GPIO for %s\n",
+ con_id ? con_id : devname);
+ return desc;
+ } else {
+ return ERR_PTR(status);
+ }
+ }
status = gpiod_configure_flags(desc, con_id, lookupflags, flags);
if (status < 0) {
@@ -4170,7 +4407,9 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
{
struct gpio_desc *desc;
struct gpio_descs *descs;
- int count;
+ struct gpio_array *array_info = NULL;
+ struct gpio_chip *chip;
+ int count, bitmap_size;
count = gpiod_count(dev, con_id);
if (count < 0)
@@ -4186,9 +4425,92 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
gpiod_put_array(descs);
return ERR_CAST(desc);
}
+
descs->desc[descs->ndescs] = desc;
+
+ chip = gpiod_to_chip(desc);
+ /*
+ * If pin hardware number of array member 0 is also 0, select
+ * its chip as a candidate for fast bitmap processing path.
+ */
+ if (descs->ndescs == 0 && gpio_chip_hwgpio(desc) == 0) {
+ struct gpio_descs *array;
+
+ bitmap_size = BITS_TO_LONGS(chip->ngpio > count ?
+ chip->ngpio : count);
+
+ array = kzalloc(struct_size(descs, desc, count) +
+ struct_size(array_info, invert_mask,
+ 3 * bitmap_size), GFP_KERNEL);
+ if (!array) {
+ gpiod_put_array(descs);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ memcpy(array, descs,
+ struct_size(descs, desc, descs->ndescs + 1));
+ kfree(descs);
+
+ descs = array;
+ array_info = (void *)(descs->desc + count);
+ array_info->get_mask = array_info->invert_mask +
+ bitmap_size;
+ array_info->set_mask = array_info->get_mask +
+ bitmap_size;
+
+ array_info->desc = descs->desc;
+ array_info->size = count;
+ array_info->chip = chip;
+ bitmap_set(array_info->get_mask, descs->ndescs,
+ count - descs->ndescs);
+ bitmap_set(array_info->set_mask, descs->ndescs,
+ count - descs->ndescs);
+ descs->info = array_info;
+ }
+ /* Unmark array members which don't belong to the 'fast' chip */
+ if (array_info && array_info->chip != chip) {
+ __clear_bit(descs->ndescs, array_info->get_mask);
+ __clear_bit(descs->ndescs, array_info->set_mask);
+ }
+ /*
+ * Detect array members which belong to the 'fast' chip
+ * but their pins are not in hardware order.
+ */
+ else if (array_info &&
+ gpio_chip_hwgpio(desc) != descs->ndescs) {
+ /*
+ * Don't use fast path if all array members processed so
+ * far belong to the same chip as this one but its pin
+ * hardware number is different from its array index.
+ */
+ if (bitmap_full(array_info->get_mask, descs->ndescs)) {
+ array_info = NULL;
+ } else {
+ __clear_bit(descs->ndescs,
+ array_info->get_mask);
+ __clear_bit(descs->ndescs,
+ array_info->set_mask);
+ }
+ } else if (array_info) {
+ /* Exclude open drain or open source from fast output */
+ if (gpiochip_line_is_open_drain(chip, descs->ndescs) ||
+ gpiochip_line_is_open_source(chip, descs->ndescs))
+ __clear_bit(descs->ndescs,
+ array_info->set_mask);
+ /* Identify 'fast' pins which require invertion */
+ if (gpiod_is_active_low(desc))
+ __set_bit(descs->ndescs,
+ array_info->invert_mask);
+ }
+
descs->ndescs++;
}
+ if (array_info)
+ dev_dbg(dev,
+ "GPIO array info: chip=%s, size=%d, get_mask=%lx, set_mask=%lx, invert_mask=%lx\n",
+ array_info->chip->label, array_info->size,
+ *array_info->get_mask, *array_info->set_mask,
+ *array_info->invert_mask);
return descs;
}
EXPORT_SYMBOL_GPL(gpiod_get_array);
@@ -4275,8 +4597,9 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_device *gdev)
struct gpio_chip *chip = gdev->chip;
unsigned gpio = gdev->base;
struct gpio_desc *gdesc = &gdev->descs[0];
- int is_out;
- int is_irq;
+ bool is_out;
+ bool is_irq;
+ bool active_low;
for (i = 0; i < gdev->ngpio; i++, gpio++, gdesc++) {
if (!test_bit(FLAG_REQUESTED, &gdesc->flags)) {
@@ -4290,11 +4613,13 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_device *gdev)
gpiod_get_direction(gdesc);
is_out = test_bit(FLAG_IS_OUT, &gdesc->flags);
is_irq = test_bit(FLAG_USED_AS_IRQ, &gdesc->flags);
- seq_printf(s, " gpio-%-3d (%-20.20s|%-20.20s) %s %s %s",
+ active_low = test_bit(FLAG_ACTIVE_LOW, &gdesc->flags);
+ seq_printf(s, " gpio-%-3d (%-20.20s|%-20.20s) %s %s %s%s",
gpio, gdesc->name ? gdesc->name : "", gdesc->label,
is_out ? "out" : "in ",
chip->get ? (chip->get(chip, i) ? "hi" : "lo") : "? ",
- is_irq ? "IRQ" : " ");
+ is_irq ? "IRQ " : "",
+ active_low ? "ACTIVE LOW" : "");
seq_printf(s, "\n");
}
}
diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
index a7e49fef73d4..087d865286a0 100644
--- a/drivers/gpio/gpiolib.h
+++ b/drivers/gpio/gpiolib.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Internal GPIO functions.
*
* Copyright (C) 2013, Intel Corporation
* Author: Mika Westerberg <mika.westerberg@linux.intel.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#ifndef GPIOLIB_H
@@ -183,15 +180,26 @@ static inline bool acpi_can_fallback_to_crs(struct acpi_device *adev,
}
#endif
+struct gpio_array {
+ struct gpio_desc **desc;
+ unsigned int size;
+ struct gpio_chip *chip;
+ unsigned long *get_mask;
+ unsigned long *set_mask;
+ unsigned long invert_mask[];
+};
+
struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, u16 hwnum);
int gpiod_get_array_value_complex(bool raw, bool can_sleep,
unsigned int array_size,
struct gpio_desc **desc_array,
- int *value_array);
+ struct gpio_array *array_info,
+ unsigned long *value_bitmap);
int gpiod_set_array_value_complex(bool raw, bool can_sleep,
- unsigned int array_size,
- struct gpio_desc **desc_array,
- int *value_array);
+ unsigned int array_size,
+ struct gpio_desc **desc_array,
+ struct gpio_array *array_info,
+ unsigned long *value_bitmap);
/* This is just passed between gpiolib and devres */
struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
@@ -214,6 +222,7 @@ struct gpio_desc {
#define FLAG_OPEN_DRAIN 7 /* Gpio is open drain type */
#define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */
#define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */
+#define FLAG_IRQ_IS_ENABLED 10 /* GPIO is connected to an enabled IRQ */
#define FLAG_IS_HOGGED 11 /* GPIO is hogged */
#define FLAG_TRANSITORY 12 /* GPIO may lose value in sleep or reset */
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index bc6a16a3c36e..7f3be3506057 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -11,7 +11,7 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \
drm_sysfs.o drm_hashtab.o drm_mm.o \
drm_crtc.o drm_fourcc.o drm_modes.o drm_edid.o \
drm_info.o drm_encoder_slave.o \
- drm_trace_points.o drm_global.o drm_prime.o \
+ drm_trace_points.o drm_prime.o \
drm_rect.o drm_vma_manager.o drm_flip_work.o \
drm_modeset_lock.o drm_atomic.o drm_bridge.o \
drm_framebuffer.o drm_connector.o drm_blend.o \
@@ -36,7 +36,8 @@ drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \
drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \
drm_kms_helper_common.o drm_dp_dual_mode_helper.o \
drm_simple_kms_helper.o drm_modeset_helper.o \
- drm_scdc_helper.o drm_gem_framebuffer_helper.o
+ drm_scdc_helper.o drm_gem_framebuffer_helper.o \
+ drm_atomic_state_helper.o
drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o
drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile
index 138cb787d27e..f76bcb9c45e4 100644
--- a/drivers/gpu/drm/amd/amdgpu/Makefile
+++ b/drivers/gpu/drm/amd/amdgpu/Makefile
@@ -53,7 +53,7 @@ amdgpu-y += amdgpu_device.o amdgpu_kms.o \
amdgpu_ucode.o amdgpu_bo_list.o amdgpu_ctx.o amdgpu_sync.o \
amdgpu_gtt_mgr.o amdgpu_vram_mgr.o amdgpu_virt.o amdgpu_atomfirmware.o \
amdgpu_vf_error.o amdgpu_sched.o amdgpu_debugfs.o amdgpu_ids.o \
- amdgpu_gmc.o amdgpu_xgmi.o
+ amdgpu_gmc.o amdgpu_xgmi.o amdgpu_csa.o
# add asic specific block
amdgpu-$(CONFIG_DRM_AMDGPU_CIK)+= cik.o cik_ih.o kv_smc.o kv_dpm.o \
@@ -105,6 +105,7 @@ amdgpu-y += \
# add GFX block
amdgpu-y += \
amdgpu_gfx.o \
+ amdgpu_rlc.o \
gfx_v8_0.o \
gfx_v9_0.o
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index d0102cfc8efb..42f882c633ee 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -75,6 +75,7 @@
#include "amdgpu_sdma.h"
#include "amdgpu_dm.h"
#include "amdgpu_virt.h"
+#include "amdgpu_csa.h"
#include "amdgpu_gart.h"
#include "amdgpu_debugfs.h"
#include "amdgpu_job.h"
@@ -151,6 +152,7 @@ extern int amdgpu_compute_multipipe;
extern int amdgpu_gpu_recovery;
extern int amdgpu_emu_mode;
extern uint amdgpu_smu_memory_pool_size;
+extern uint amdgpu_dc_feature_mask;
extern struct amdgpu_mgpu_info mgpu_info;
#ifdef CONFIG_DRM_AMDGPU_SI
@@ -432,7 +434,7 @@ typedef enum _AMDGPU_DOORBELL64_ASSIGNMENT
* default non-graphics QWORD index is 0xe0 - 0xFF inclusive
*/
- /* sDMA engines reserved from 0xe0 -oxef */
+ /* sDMA engines reserved from 0xe0 -0xef */
AMDGPU_DOORBELL64_sDMA_ENGINE0 = 0xE0,
AMDGPU_DOORBELL64_sDMA_HI_PRI_ENGINE0 = 0xE1,
AMDGPU_DOORBELL64_sDMA_ENGINE1 = 0xE8,
@@ -830,7 +832,6 @@ struct amdgpu_device {
bool need_dma32;
bool need_swiotlb;
bool accel_working;
- struct work_struct reset_work;
struct notifier_block acpi_nb;
struct amdgpu_i2c_chan *i2c_bus[AMDGPU_MAX_I2C_BUS];
struct amdgpu_debugfs debugfs[AMDGPU_DEBUGFS_MAX_COMPONENTS];
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
index c31a8849e9f8..60f9a87e9c74 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
@@ -144,7 +144,7 @@ void amdgpu_amdkfd_device_init(struct amdgpu_device *adev)
KGD_MAX_QUEUES);
/* remove the KIQ bit as well */
- if (adev->gfx.kiq.ring.ready)
+ if (adev->gfx.kiq.ring.sched.ready)
clear_bit(amdgpu_gfx_queue_to_bit(adev,
adev->gfx.kiq.ring.me - 1,
adev->gfx.kiq.ring.pipe,
@@ -268,9 +268,9 @@ void amdgpu_amdkfd_gpu_reset(struct kgd_dev *kgd)
amdgpu_device_gpu_recover(adev, NULL);
}
-int alloc_gtt_mem(struct kgd_dev *kgd, size_t size,
- void **mem_obj, uint64_t *gpu_addr,
- void **cpu_ptr, bool mqd_gfx9)
+int amdgpu_amdkfd_alloc_gtt_mem(struct kgd_dev *kgd, size_t size,
+ void **mem_obj, uint64_t *gpu_addr,
+ void **cpu_ptr, bool mqd_gfx9)
{
struct amdgpu_device *adev = (struct amdgpu_device *)kgd;
struct amdgpu_bo *bo = NULL;
@@ -340,7 +340,7 @@ allocate_mem_reserve_bo_failed:
return r;
}
-void free_gtt_mem(struct kgd_dev *kgd, void *mem_obj)
+void amdgpu_amdkfd_free_gtt_mem(struct kgd_dev *kgd, void *mem_obj)
{
struct amdgpu_bo *bo = (struct amdgpu_bo *) mem_obj;
@@ -351,8 +351,8 @@ void free_gtt_mem(struct kgd_dev *kgd, void *mem_obj)
amdgpu_bo_unref(&(bo));
}
-void get_local_mem_info(struct kgd_dev *kgd,
- struct kfd_local_mem_info *mem_info)
+void amdgpu_amdkfd_get_local_mem_info(struct kgd_dev *kgd,
+ struct kfd_local_mem_info *mem_info)
{
struct amdgpu_device *adev = (struct amdgpu_device *)kgd;
uint64_t address_mask = adev->dev->dma_mask ? ~*adev->dev->dma_mask :
@@ -383,7 +383,7 @@ void get_local_mem_info(struct kgd_dev *kgd,
mem_info->mem_clk_max = 100;
}
-uint64_t get_gpu_clock_counter(struct kgd_dev *kgd)
+uint64_t amdgpu_amdkfd_get_gpu_clock_counter(struct kgd_dev *kgd)
{
struct amdgpu_device *adev = (struct amdgpu_device *)kgd;
@@ -392,7 +392,7 @@ uint64_t get_gpu_clock_counter(struct kgd_dev *kgd)
return 0;
}
-uint32_t get_max_engine_clock_in_mhz(struct kgd_dev *kgd)
+uint32_t amdgpu_amdkfd_get_max_engine_clock_in_mhz(struct kgd_dev *kgd)
{
struct amdgpu_device *adev = (struct amdgpu_device *)kgd;
@@ -405,7 +405,7 @@ uint32_t get_max_engine_clock_in_mhz(struct kgd_dev *kgd)
return 100;
}
-void get_cu_info(struct kgd_dev *kgd, struct kfd_cu_info *cu_info)
+void amdgpu_amdkfd_get_cu_info(struct kgd_dev *kgd, struct kfd_cu_info *cu_info)
{
struct amdgpu_device *adev = (struct amdgpu_device *)kgd;
struct amdgpu_cu_info acu_info = adev->gfx.cu_info;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
index 8e0d4f7196b4..bcf587b4ba98 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
@@ -134,16 +134,16 @@ int amdgpu_amdkfd_post_reset(struct amdgpu_device *adev);
void amdgpu_amdkfd_gpu_reset(struct kgd_dev *kgd);
/* Shared API */
-int alloc_gtt_mem(struct kgd_dev *kgd, size_t size,
- void **mem_obj, uint64_t *gpu_addr,
- void **cpu_ptr, bool mqd_gfx9);
-void free_gtt_mem(struct kgd_dev *kgd, void *mem_obj);
-void get_local_mem_info(struct kgd_dev *kgd,
- struct kfd_local_mem_info *mem_info);
-uint64_t get_gpu_clock_counter(struct kgd_dev *kgd);
-
-uint32_t get_max_engine_clock_in_mhz(struct kgd_dev *kgd);
-void get_cu_info(struct kgd_dev *kgd, struct kfd_cu_info *cu_info);
+int amdgpu_amdkfd_alloc_gtt_mem(struct kgd_dev *kgd, size_t size,
+ void **mem_obj, uint64_t *gpu_addr,
+ void **cpu_ptr, bool mqd_gfx9);
+void amdgpu_amdkfd_free_gtt_mem(struct kgd_dev *kgd, void *mem_obj);
+void amdgpu_amdkfd_get_local_mem_info(struct kgd_dev *kgd,
+ struct kfd_local_mem_info *mem_info);
+uint64_t amdgpu_amdkfd_get_gpu_clock_counter(struct kgd_dev *kgd);
+
+uint32_t amdgpu_amdkfd_get_max_engine_clock_in_mhz(struct kgd_dev *kgd);
+void amdgpu_amdkfd_get_cu_info(struct kgd_dev *kgd, struct kfd_cu_info *cu_info);
uint64_t amdgpu_amdkfd_get_vram_usage(struct kgd_dev *kgd);
uint64_t amdgpu_amdkfd_get_hive_id(struct kgd_dev *kgd);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c
index 244d9834a381..72a357dae070 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c
@@ -173,13 +173,6 @@ static int get_tile_config(struct kgd_dev *kgd,
}
static const struct kfd2kgd_calls kfd2kgd = {
- .init_gtt_mem_allocation = alloc_gtt_mem,
- .free_gtt_mem = free_gtt_mem,
- .get_local_mem_info = get_local_mem_info,
- .get_gpu_clock_counter = get_gpu_clock_counter,
- .get_max_engine_clock_in_mhz = get_max_engine_clock_in_mhz,
- .alloc_pasid = amdgpu_pasid_alloc,
- .free_pasid = amdgpu_pasid_free,
.program_sh_mem_settings = kgd_program_sh_mem_settings,
.set_pasid_vmid_mapping = kgd_set_pasid_vmid_mapping,
.init_interrupts = kgd_init_interrupts,
@@ -200,28 +193,10 @@ static const struct kfd2kgd_calls kfd2kgd = {
.get_fw_version = get_fw_version,
.set_scratch_backing_va = set_scratch_backing_va,
.get_tile_config = get_tile_config,
- .get_cu_info = get_cu_info,
- .get_vram_usage = amdgpu_amdkfd_get_vram_usage,
- .create_process_vm = amdgpu_amdkfd_gpuvm_create_process_vm,
- .acquire_process_vm = amdgpu_amdkfd_gpuvm_acquire_process_vm,
- .destroy_process_vm = amdgpu_amdkfd_gpuvm_destroy_process_vm,
- .release_process_vm = amdgpu_amdkfd_gpuvm_release_process_vm,
- .get_process_page_dir = amdgpu_amdkfd_gpuvm_get_process_page_dir,
.set_vm_context_page_table_base = set_vm_context_page_table_base,
- .alloc_memory_of_gpu = amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu,
- .free_memory_of_gpu = amdgpu_amdkfd_gpuvm_free_memory_of_gpu,
- .map_memory_to_gpu = amdgpu_amdkfd_gpuvm_map_memory_to_gpu,
- .unmap_memory_to_gpu = amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu,
- .sync_memory = amdgpu_amdkfd_gpuvm_sync_memory,
- .map_gtt_bo_to_kernel = amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel,
- .restore_process_bos = amdgpu_amdkfd_gpuvm_restore_process_bos,
.invalidate_tlbs = invalidate_tlbs,
.invalidate_tlbs_vmid = invalidate_tlbs_vmid,
- .submit_ib = amdgpu_amdkfd_submit_ib,
- .get_vm_fault_info = amdgpu_amdkfd_gpuvm_get_vm_fault_info,
.read_vmid_from_vmfault_reg = read_vmid_from_vmfault_reg,
- .gpu_recover = amdgpu_amdkfd_gpu_reset,
- .set_compute_idle = amdgpu_amdkfd_set_compute_idle
};
struct kfd2kgd_calls *amdgpu_amdkfd_gfx_7_get_functions(void)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c
index 9f149914ad6c..0e2a56b6a9b6 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c
@@ -128,13 +128,6 @@ static int get_tile_config(struct kgd_dev *kgd,
}
static const struct kfd2kgd_calls kfd2kgd = {
- .init_gtt_mem_allocation = alloc_gtt_mem,
- .free_gtt_mem = free_gtt_mem,
- .get_local_mem_info = get_local_mem_info,
- .get_gpu_clock_counter = get_gpu_clock_counter,
- .get_max_engine_clock_in_mhz = get_max_engine_clock_in_mhz,
- .alloc_pasid = amdgpu_pasid_alloc,
- .free_pasid = amdgpu_pasid_free,
.program_sh_mem_settings = kgd_program_sh_mem_settings,
.set_pasid_vmid_mapping = kgd_set_pasid_vmid_mapping,
.init_interrupts = kgd_init_interrupts,
@@ -157,27 +150,9 @@ static const struct kfd2kgd_calls kfd2kgd = {
.get_fw_version = get_fw_version,
.set_scratch_backing_va = set_scratch_backing_va,
.get_tile_config = get_tile_config,
- .get_cu_info = get_cu_info,
- .get_vram_usage = amdgpu_amdkfd_get_vram_usage,
- .create_process_vm = amdgpu_amdkfd_gpuvm_create_process_vm,
- .acquire_process_vm = amdgpu_amdkfd_gpuvm_acquire_process_vm,
- .destroy_process_vm = amdgpu_amdkfd_gpuvm_destroy_process_vm,
- .release_process_vm = amdgpu_amdkfd_gpuvm_release_process_vm,
- .get_process_page_dir = amdgpu_amdkfd_gpuvm_get_process_page_dir,
.set_vm_context_page_table_base = set_vm_context_page_table_base,
- .alloc_memory_of_gpu = amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu,
- .free_memory_of_gpu = amdgpu_amdkfd_gpuvm_free_memory_of_gpu,
- .map_memory_to_gpu = amdgpu_amdkfd_gpuvm_map_memory_to_gpu,
- .unmap_memory_to_gpu = amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu,
- .sync_memory = amdgpu_amdkfd_gpuvm_sync_memory,
- .map_gtt_bo_to_kernel = amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel,
- .restore_process_bos = amdgpu_amdkfd_gpuvm_restore_process_bos,
.invalidate_tlbs = invalidate_tlbs,
.invalidate_tlbs_vmid = invalidate_tlbs_vmid,
- .submit_ib = amdgpu_amdkfd_submit_ib,
- .get_vm_fault_info = amdgpu_amdkfd_gpuvm_get_vm_fault_info,
- .gpu_recover = amdgpu_amdkfd_gpu_reset,
- .set_compute_idle = amdgpu_amdkfd_set_compute_idle
};
struct kfd2kgd_calls *amdgpu_amdkfd_gfx_8_0_get_functions(void)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c
index 42cb4c4e0929..03b604c96d94 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c
@@ -46,38 +46,9 @@
#include "v9_structs.h"
#include "soc15.h"
#include "soc15d.h"
+#include "mmhub_v1_0.h"
+#include "gfxhub_v1_0.h"
-/* HACK: MMHUB and GC both have VM-related register with the same
- * names but different offsets. Define the MMHUB register we need here
- * with a prefix. A proper solution would be to move the functions
- * programming these registers into gfx_v9_0.c and mmhub_v1_0.c
- * respectively.
- */
-#define mmMMHUB_VM_INVALIDATE_ENG16_REQ 0x06f3
-#define mmMMHUB_VM_INVALIDATE_ENG16_REQ_BASE_IDX 0
-
-#define mmMMHUB_VM_INVALIDATE_ENG16_ACK 0x0705
-#define mmMMHUB_VM_INVALIDATE_ENG16_ACK_BASE_IDX 0
-
-#define mmMMHUB_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32 0x072b
-#define mmMMHUB_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32_BASE_IDX 0
-#define mmMMHUB_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32 0x072c
-#define mmMMHUB_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32_BASE_IDX 0
-
-#define mmMMHUB_VM_CONTEXT0_PAGE_TABLE_START_ADDR_LO32 0x074b
-#define mmMMHUB_VM_CONTEXT0_PAGE_TABLE_START_ADDR_LO32_BASE_IDX 0
-#define mmMMHUB_VM_CONTEXT0_PAGE_TABLE_START_ADDR_HI32 0x074c
-#define mmMMHUB_VM_CONTEXT0_PAGE_TABLE_START_ADDR_HI32_BASE_IDX 0
-
-#define mmMMHUB_VM_CONTEXT0_PAGE_TABLE_END_ADDR_LO32 0x076b
-#define mmMMHUB_VM_CONTEXT0_PAGE_TABLE_END_ADDR_LO32_BASE_IDX 0
-#define mmMMHUB_VM_CONTEXT0_PAGE_TABLE_END_ADDR_HI32 0x076c
-#define mmMMHUB_VM_CONTEXT0_PAGE_TABLE_END_ADDR_HI32_BASE_IDX 0
-
-#define mmMMHUB_VM_INVALIDATE_ENG16_ADDR_RANGE_LO32 0x0727
-#define mmMMHUB_VM_INVALIDATE_ENG16_ADDR_RANGE_LO32_BASE_IDX 0
-#define mmMMHUB_VM_INVALIDATE_ENG16_ADDR_RANGE_HI32 0x0728
-#define mmMMHUB_VM_INVALIDATE_ENG16_ADDR_RANGE_HI32_BASE_IDX 0
#define V9_PIPE_PER_MEC (4)
#define V9_QUEUES_PER_PIPE_MEC (8)
@@ -167,13 +138,6 @@ static int amdgpu_amdkfd_get_tile_config(struct kgd_dev *kgd,
}
static const struct kfd2kgd_calls kfd2kgd = {
- .init_gtt_mem_allocation = alloc_gtt_mem,
- .free_gtt_mem = free_gtt_mem,
- .get_local_mem_info = get_local_mem_info,
- .get_gpu_clock_counter = get_gpu_clock_counter,
- .get_max_engine_clock_in_mhz = get_max_engine_clock_in_mhz,
- .alloc_pasid = amdgpu_pasid_alloc,
- .free_pasid = amdgpu_pasid_free,
.program_sh_mem_settings = kgd_program_sh_mem_settings,
.set_pasid_vmid_mapping = kgd_set_pasid_vmid_mapping,
.init_interrupts = kgd_init_interrupts,
@@ -196,26 +160,9 @@ static const struct kfd2kgd_calls kfd2kgd = {
.get_fw_version = get_fw_version,
.set_scratch_backing_va = set_scratch_backing_va,
.get_tile_config = amdgpu_amdkfd_get_tile_config,
- .get_cu_info = get_cu_info,
- .get_vram_usage = amdgpu_amdkfd_get_vram_usage,
- .create_process_vm = amdgpu_amdkfd_gpuvm_create_process_vm,
- .acquire_process_vm = amdgpu_amdkfd_gpuvm_acquire_process_vm,
- .destroy_process_vm = amdgpu_amdkfd_gpuvm_destroy_process_vm,
- .release_process_vm = amdgpu_amdkfd_gpuvm_release_process_vm,
- .get_process_page_dir = amdgpu_amdkfd_gpuvm_get_process_page_dir,
.set_vm_context_page_table_base = set_vm_context_page_table_base,
- .alloc_memory_of_gpu = amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu,
- .free_memory_of_gpu = amdgpu_amdkfd_gpuvm_free_memory_of_gpu,
- .map_memory_to_gpu = amdgpu_amdkfd_gpuvm_map_memory_to_gpu,
- .unmap_memory_to_gpu = amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu,
- .sync_memory = amdgpu_amdkfd_gpuvm_sync_memory,
- .map_gtt_bo_to_kernel = amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel,
- .restore_process_bos = amdgpu_amdkfd_gpuvm_restore_process_bos,
.invalidate_tlbs = invalidate_tlbs,
.invalidate_tlbs_vmid = invalidate_tlbs_vmid,
- .submit_ib = amdgpu_amdkfd_submit_ib,
- .gpu_recover = amdgpu_amdkfd_gpu_reset,
- .set_compute_idle = amdgpu_amdkfd_set_compute_idle,
.get_hive_id = amdgpu_amdkfd_get_hive_id,
};
@@ -785,15 +732,6 @@ static uint16_t get_atc_vmid_pasid_mapping_pasid(struct kgd_dev *kgd,
static void write_vmid_invalidate_request(struct kgd_dev *kgd, uint8_t vmid)
{
struct amdgpu_device *adev = (struct amdgpu_device *) kgd;
- uint32_t req = (1 << vmid) |
- (0 << VM_INVALIDATE_ENG16_REQ__FLUSH_TYPE__SHIFT) | /* legacy */
- VM_INVALIDATE_ENG16_REQ__INVALIDATE_L2_PTES_MASK |
- VM_INVALIDATE_ENG16_REQ__INVALIDATE_L2_PDE0_MASK |
- VM_INVALIDATE_ENG16_REQ__INVALIDATE_L2_PDE1_MASK |
- VM_INVALIDATE_ENG16_REQ__INVALIDATE_L2_PDE2_MASK |
- VM_INVALIDATE_ENG16_REQ__INVALIDATE_L1_PTES_MASK;
-
- mutex_lock(&adev->srbm_mutex);
/* Use legacy mode tlb invalidation.
*
@@ -810,34 +748,7 @@ static void write_vmid_invalidate_request(struct kgd_dev *kgd, uint8_t vmid)
* TODO 2: support range-based invalidation, requires kfg2kgd
* interface change
*/
- WREG32(SOC15_REG_OFFSET(GC, 0, mmVM_INVALIDATE_ENG16_ADDR_RANGE_LO32),
- 0xffffffff);
- WREG32(SOC15_REG_OFFSET(GC, 0, mmVM_INVALIDATE_ENG16_ADDR_RANGE_HI32),
- 0x0000001f);
-
- WREG32(SOC15_REG_OFFSET(MMHUB, 0,
- mmMMHUB_VM_INVALIDATE_ENG16_ADDR_RANGE_LO32),
- 0xffffffff);
- WREG32(SOC15_REG_OFFSET(MMHUB, 0,
- mmMMHUB_VM_INVALIDATE_ENG16_ADDR_RANGE_HI32),
- 0x0000001f);
-
- WREG32(SOC15_REG_OFFSET(GC, 0, mmVM_INVALIDATE_ENG16_REQ), req);
-
- WREG32(SOC15_REG_OFFSET(MMHUB, 0, mmMMHUB_VM_INVALIDATE_ENG16_REQ),
- req);
-
- while (!(RREG32(SOC15_REG_OFFSET(GC, 0, mmVM_INVALIDATE_ENG16_ACK)) &
- (1 << vmid)))
- cpu_relax();
-
- while (!(RREG32(SOC15_REG_OFFSET(MMHUB, 0,
- mmMMHUB_VM_INVALIDATE_ENG16_ACK)) &
- (1 << vmid)))
- cpu_relax();
-
- mutex_unlock(&adev->srbm_mutex);
-
+ amdgpu_gmc_flush_gpu_tlb(adev, vmid, 0);
}
static int invalidate_tlbs_with_kiq(struct amdgpu_device *adev, uint16_t pasid)
@@ -876,7 +787,7 @@ static int invalidate_tlbs(struct kgd_dev *kgd, uint16_t pasid)
if (adev->in_gpu_reset)
return -EIO;
- if (ring->ready)
+ if (ring->sched.ready)
return invalidate_tlbs_with_kiq(adev, pasid);
for (vmid = 0; vmid < 16; vmid++) {
@@ -1016,7 +927,6 @@ static void set_vm_context_page_table_base(struct kgd_dev *kgd, uint32_t vmid,
uint64_t page_table_base)
{
struct amdgpu_device *adev = get_amdgpu_device(kgd);
- uint64_t base = page_table_base | AMDGPU_PTE_VALID;
if (!amdgpu_amdkfd_is_kfd_vmid(adev, vmid)) {
pr_err("trying to set page table base for wrong VMID %u\n",
@@ -1028,25 +938,7 @@ static void set_vm_context_page_table_base(struct kgd_dev *kgd, uint32_t vmid,
* now, all processes share the same address space size, like
* on GFX8 and older.
*/
- WREG32(SOC15_REG_OFFSET(MMHUB, 0, mmMMHUB_VM_CONTEXT0_PAGE_TABLE_START_ADDR_LO32) + (vmid*2), 0);
- WREG32(SOC15_REG_OFFSET(MMHUB, 0, mmMMHUB_VM_CONTEXT0_PAGE_TABLE_START_ADDR_HI32) + (vmid*2), 0);
-
- WREG32(SOC15_REG_OFFSET(MMHUB, 0, mmMMHUB_VM_CONTEXT0_PAGE_TABLE_END_ADDR_LO32) + (vmid*2),
- lower_32_bits(adev->vm_manager.max_pfn - 1));
- WREG32(SOC15_REG_OFFSET(MMHUB, 0, mmMMHUB_VM_CONTEXT0_PAGE_TABLE_END_ADDR_HI32) + (vmid*2),
- upper_32_bits(adev->vm_manager.max_pfn - 1));
-
- WREG32(SOC15_REG_OFFSET(MMHUB, 0, mmMMHUB_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32) + (vmid*2), lower_32_bits(base));
- WREG32(SOC15_REG_OFFSET(MMHUB, 0, mmMMHUB_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32) + (vmid*2), upper_32_bits(base));
-
- WREG32(SOC15_REG_OFFSET(GC, 0, mmVM_CONTEXT0_PAGE_TABLE_START_ADDR_LO32) + (vmid*2), 0);
- WREG32(SOC15_REG_OFFSET(GC, 0, mmVM_CONTEXT0_PAGE_TABLE_START_ADDR_HI32) + (vmid*2), 0);
-
- WREG32(SOC15_REG_OFFSET(GC, 0, mmVM_CONTEXT0_PAGE_TABLE_END_ADDR_LO32) + (vmid*2),
- lower_32_bits(adev->vm_manager.max_pfn - 1));
- WREG32(SOC15_REG_OFFSET(GC, 0, mmVM_CONTEXT0_PAGE_TABLE_END_ADDR_HI32) + (vmid*2),
- upper_32_bits(adev->vm_manager.max_pfn - 1));
+ mmhub_v1_0_setup_vm_pt_regs(adev, vmid, page_table_base);
- WREG32(SOC15_REG_OFFSET(GC, 0, mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32) + (vmid*2), lower_32_bits(base));
- WREG32(SOC15_REG_OFFSET(GC, 0, mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32) + (vmid*2), upper_32_bits(base));
+ gfxhub_v1_0_setup_vm_pt_regs(adev, vmid, page_table_base);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c
index 8816c697b205..ceadeeadfa56 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c
@@ -330,7 +330,9 @@ static int amdgpu_cgs_get_firmware_info(struct cgs_device *cgs_device,
case CHIP_TOPAZ:
if (((adev->pdev->device == 0x6900) && (adev->pdev->revision == 0x81)) ||
((adev->pdev->device == 0x6900) && (adev->pdev->revision == 0x83)) ||
- ((adev->pdev->device == 0x6907) && (adev->pdev->revision == 0x87))) {
+ ((adev->pdev->device == 0x6907) && (adev->pdev->revision == 0x87)) ||
+ ((adev->pdev->device == 0x6900) && (adev->pdev->revision == 0xD1)) ||
+ ((adev->pdev->device == 0x6900) && (adev->pdev->revision == 0xD3))) {
info->is_kicker = true;
strcpy(fw_name, "amdgpu/topaz_k_smc.bin");
} else
@@ -351,7 +353,6 @@ static int amdgpu_cgs_get_firmware_info(struct cgs_device *cgs_device,
if (type == CGS_UCODE_ID_SMU) {
if (((adev->pdev->device == 0x67ef) &&
((adev->pdev->revision == 0xe0) ||
- (adev->pdev->revision == 0xe2) ||
(adev->pdev->revision == 0xe5))) ||
((adev->pdev->device == 0x67ff) &&
((adev->pdev->revision == 0xcf) ||
@@ -359,8 +360,13 @@ static int amdgpu_cgs_get_firmware_info(struct cgs_device *cgs_device,
(adev->pdev->revision == 0xff)))) {
info->is_kicker = true;
strcpy(fw_name, "amdgpu/polaris11_k_smc.bin");
- } else
+ } else if ((adev->pdev->device == 0x67ef) &&
+ (adev->pdev->revision == 0xe2)) {
+ info->is_kicker = true;
+ strcpy(fw_name, "amdgpu/polaris11_k2_smc.bin");
+ } else {
strcpy(fw_name, "amdgpu/polaris11_smc.bin");
+ }
} else if (type == CGS_UCODE_ID_SMU_SK) {
strcpy(fw_name, "amdgpu/polaris11_smc_sk.bin");
}
@@ -378,14 +384,31 @@ static int amdgpu_cgs_get_firmware_info(struct cgs_device *cgs_device,
(adev->pdev->revision == 0xef))) {
info->is_kicker = true;
strcpy(fw_name, "amdgpu/polaris10_k_smc.bin");
- } else
+ } else if ((adev->pdev->device == 0x67df) &&
+ ((adev->pdev->revision == 0xe1) ||
+ (adev->pdev->revision == 0xf7))) {
+ info->is_kicker = true;
+ strcpy(fw_name, "amdgpu/polaris10_k2_smc.bin");
+ } else {
strcpy(fw_name, "amdgpu/polaris10_smc.bin");
+ }
} else if (type == CGS_UCODE_ID_SMU_SK) {
strcpy(fw_name, "amdgpu/polaris10_smc_sk.bin");
}
break;
case CHIP_POLARIS12:
- strcpy(fw_name, "amdgpu/polaris12_smc.bin");
+ if (((adev->pdev->device == 0x6987) &&
+ ((adev->pdev->revision == 0xc0) ||
+ (adev->pdev->revision == 0xc3))) ||
+ ((adev->pdev->device == 0x6981) &&
+ ((adev->pdev->revision == 0x00) ||
+ (adev->pdev->revision == 0x01) ||
+ (adev->pdev->revision == 0x10)))) {
+ info->is_kicker = true;
+ strcpy(fw_name, "amdgpu/polaris12_k_smc.bin");
+ } else {
+ strcpy(fw_name, "amdgpu/polaris12_smc.bin");
+ }
break;
case CHIP_VEGAM:
strcpy(fw_name, "amdgpu/vegam_smc.bin");
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
index 663043c8f0f5..024dfbd87f11 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
@@ -955,7 +955,7 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p)
if (r)
return r;
- r = reservation_object_reserve_shared(vm->root.base.bo->tbo.resv);
+ r = reservation_object_reserve_shared(vm->root.base.bo->tbo.resv, 1);
if (r)
return r;
@@ -1104,7 +1104,7 @@ static int amdgpu_syncobj_lookup_and_add_to_sync(struct amdgpu_cs_parser *p,
{
int r;
struct dma_fence *fence;
- r = drm_syncobj_find_fence(p->filp, handle, 0, &fence);
+ r = drm_syncobj_find_fence(p->filp, handle, 0, 0, &fence);
if (r)
return r;
@@ -1260,8 +1260,7 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p,
return 0;
error_abort:
- dma_fence_put(&job->base.s_fence->finished);
- job->base.s_fence = NULL;
+ drm_sched_job_cleanup(&job->base);
amdgpu_mn_unlock(p->mn);
error_unlock:
@@ -1285,7 +1284,7 @@ int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
r = amdgpu_cs_parser_init(&parser, data);
if (r) {
- DRM_ERROR("Failed to initialize parser !\n");
+ DRM_ERROR("Failed to initialize parser %d!\n", r);
goto out;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_csa.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_csa.c
new file mode 100644
index 000000000000..0c590ddf250a
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_csa.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2016 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.
+
+ * * Author: Monk.liu@amd.com
+ */
+
+#include "amdgpu.h"
+
+uint64_t amdgpu_csa_vaddr(struct amdgpu_device *adev)
+{
+ uint64_t addr = adev->vm_manager.max_pfn << AMDGPU_GPU_PAGE_SHIFT;
+
+ addr -= AMDGPU_VA_RESERVED_SIZE;
+ addr = amdgpu_gmc_sign_extend(addr);
+
+ return addr;
+}
+
+int amdgpu_allocate_static_csa(struct amdgpu_device *adev, struct amdgpu_bo **bo,
+ u32 domain, uint32_t size)
+{
+ int r;
+ void *ptr;
+
+ r = amdgpu_bo_create_kernel(adev, size, PAGE_SIZE,
+ domain, bo,
+ NULL, &ptr);
+ if (!bo)
+ return -ENOMEM;
+
+ memset(ptr, 0, size);
+ return 0;
+}
+
+void amdgpu_free_static_csa(struct amdgpu_bo **bo)
+{
+ amdgpu_bo_free_kernel(bo, NULL, NULL);
+}
+
+/*
+ * amdgpu_map_static_csa should be called during amdgpu_vm_init
+ * it maps virtual address amdgpu_csa_vaddr() to this VM, and each command
+ * submission of GFX should use this virtual address within META_DATA init
+ * package to support SRIOV gfx preemption.
+ */
+int amdgpu_map_static_csa(struct amdgpu_device *adev, struct amdgpu_vm *vm,
+ struct amdgpu_bo *bo, struct amdgpu_bo_va **bo_va,
+ uint64_t csa_addr, uint32_t size)
+{
+ struct ww_acquire_ctx ticket;
+ struct list_head list;
+ struct amdgpu_bo_list_entry pd;
+ struct ttm_validate_buffer csa_tv;
+ int r;
+
+ INIT_LIST_HEAD(&list);
+ INIT_LIST_HEAD(&csa_tv.head);
+ csa_tv.bo = &bo->tbo;
+ csa_tv.shared = true;
+
+ list_add(&csa_tv.head, &list);
+ amdgpu_vm_get_pd_bo(vm, &list, &pd);
+
+ r = ttm_eu_reserve_buffers(&ticket, &list, true, NULL);
+ if (r) {
+ DRM_ERROR("failed to reserve CSA,PD BOs: err=%d\n", r);
+ return r;
+ }
+
+ *bo_va = amdgpu_vm_bo_add(adev, vm, bo);
+ if (!*bo_va) {
+ ttm_eu_backoff_reservation(&ticket, &list);
+ DRM_ERROR("failed to create bo_va for static CSA\n");
+ return -ENOMEM;
+ }
+
+ r = amdgpu_vm_alloc_pts(adev, (*bo_va)->base.vm, csa_addr,
+ size);
+ if (r) {
+ DRM_ERROR("failed to allocate pts for static CSA, err=%d\n", r);
+ amdgpu_vm_bo_rmv(adev, *bo_va);
+ ttm_eu_backoff_reservation(&ticket, &list);
+ return r;
+ }
+
+ r = amdgpu_vm_bo_map(adev, *bo_va, csa_addr, 0, size,
+ AMDGPU_PTE_READABLE | AMDGPU_PTE_WRITEABLE |
+ AMDGPU_PTE_EXECUTABLE);
+
+ if (r) {
+ DRM_ERROR("failed to do bo_map on static CSA, err=%d\n", r);
+ amdgpu_vm_bo_rmv(adev, *bo_va);
+ ttm_eu_backoff_reservation(&ticket, &list);
+ return r;
+ }
+
+ ttm_eu_backoff_reservation(&ticket, &list);
+ return 0;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_csa.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_csa.h
new file mode 100644
index 000000000000..524b4437a021
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_csa.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2016 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.
+ *
+ * Author: Monk.liu@amd.com
+ */
+
+#ifndef AMDGPU_CSA_MANAGER_H
+#define AMDGPU_CSA_MANAGER_H
+
+#define AMDGPU_CSA_SIZE (128 * 1024)
+
+uint32_t amdgpu_get_total_csa_size(struct amdgpu_device *adev);
+uint64_t amdgpu_csa_vaddr(struct amdgpu_device *adev);
+int amdgpu_allocate_static_csa(struct amdgpu_device *adev, struct amdgpu_bo **bo,
+ u32 domain, uint32_t size);
+int amdgpu_map_static_csa(struct amdgpu_device *adev, struct amdgpu_vm *vm,
+ struct amdgpu_bo *bo, struct amdgpu_bo_va **bo_va,
+ uint64_t csa_addr, uint32_t size);
+void amdgpu_free_static_csa(struct amdgpu_bo **bo);
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index 30bc345d6fdf..590588a82471 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -1656,7 +1656,9 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev)
/* right after GMC hw init, we create CSA */
if (amdgpu_sriov_vf(adev)) {
- r = amdgpu_allocate_static_csa(adev);
+ r = amdgpu_allocate_static_csa(adev, &adev->virt.csa_obj,
+ AMDGPU_GEM_DOMAIN_VRAM,
+ AMDGPU_CSA_SIZE);
if (r) {
DRM_ERROR("allocate CSA failed %d\n", r);
return r;
@@ -1681,7 +1683,8 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev)
if (r)
return r;
- amdgpu_xgmi_add_device(adev);
+ if (adev->gmc.xgmi.num_physical_nodes > 1)
+ amdgpu_xgmi_add_device(adev);
amdgpu_amdkfd_device_init(adev);
if (amdgpu_sriov_vf(adev))
@@ -1890,7 +1893,7 @@ static int amdgpu_device_ip_fini(struct amdgpu_device *adev)
if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC) {
amdgpu_ucode_free_bo(adev);
- amdgpu_free_static_csa(adev);
+ amdgpu_free_static_csa(&adev->virt.csa_obj);
amdgpu_device_wb_fini(adev);
amdgpu_device_vram_scratch_fini(adev);
}
@@ -3295,13 +3298,35 @@ bool amdgpu_device_should_recover_gpu(struct amdgpu_device *adev)
return false;
}
- if (amdgpu_gpu_recovery == 0 || (amdgpu_gpu_recovery == -1 &&
- !amdgpu_sriov_vf(adev))) {
- DRM_INFO("GPU recovery disabled.\n");
- return false;
+ if (amdgpu_gpu_recovery == 0)
+ goto disabled;
+
+ if (amdgpu_sriov_vf(adev))
+ return true;
+
+ if (amdgpu_gpu_recovery == -1) {
+ switch (adev->asic_type) {
+ case CHIP_TOPAZ:
+ case CHIP_TONGA:
+ case CHIP_FIJI:
+ case CHIP_POLARIS10:
+ case CHIP_POLARIS11:
+ case CHIP_POLARIS12:
+ case CHIP_VEGAM:
+ case CHIP_VEGA20:
+ case CHIP_VEGA10:
+ case CHIP_VEGA12:
+ break;
+ default:
+ goto disabled;
+ }
}
return true;
+
+disabled:
+ DRM_INFO("GPU recovery disabled.\n");
+ return false;
}
/**
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index 943dbf3c5da1..8de55f7f1a3a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -127,6 +127,9 @@ int amdgpu_compute_multipipe = -1;
int amdgpu_gpu_recovery = -1; /* auto */
int amdgpu_emu_mode = 0;
uint amdgpu_smu_memory_pool_size = 0;
+/* FBC (bit 0) disabled by default*/
+uint amdgpu_dc_feature_mask = 0;
+
struct amdgpu_mgpu_info mgpu_info = {
.mutex = __MUTEX_INITIALIZER(mgpu_info.mutex),
};
@@ -631,6 +634,14 @@ module_param(halt_if_hws_hang, int, 0644);
MODULE_PARM_DESC(halt_if_hws_hang, "Halt if HWS hang is detected (0 = off (default), 1 = on)");
#endif
+/**
+ * DOC: dcfeaturemask (uint)
+ * Override display features enabled. See enum DC_FEATURE_MASK in drivers/gpu/drm/amd/include/amd_shared.h.
+ * The default is the current set of stable display features.
+ */
+MODULE_PARM_DESC(dcfeaturemask, "all stable DC features enabled (default))");
+module_param_named(dcfeaturemask, amdgpu_dc_feature_mask, uint, 0444);
+
static const struct pci_device_id pciidlist[] = {
#ifdef CONFIG_DRM_AMDGPU_SI
{0x1002, 0x6780, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI},
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
index 5448cf27654e..ee47c11e92ce 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
@@ -398,9 +398,9 @@ int amdgpu_fence_driver_start_ring(struct amdgpu_ring *ring,
ring->fence_drv.irq_type = irq_type;
ring->fence_drv.initialized = true;
- dev_dbg(adev->dev, "fence driver on ring %d use gpu addr 0x%016llx, "
- "cpu addr 0x%p\n", ring->idx,
- ring->fence_drv.gpu_addr, ring->fence_drv.cpu_addr);
+ DRM_DEV_DEBUG(adev->dev, "fence driver on ring %s use gpu addr "
+ "0x%016llx, cpu addr 0x%p\n", ring->name,
+ ring->fence_drv.gpu_addr, ring->fence_drv.cpu_addr);
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c
index 11fea28f8ad3..6d11e1721147 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c
@@ -248,7 +248,7 @@ int amdgpu_gart_unbind(struct amdgpu_device *adev, uint64_t offset,
}
mb();
amdgpu_asic_flush_hdp(adev, NULL);
- amdgpu_gmc_flush_gpu_tlb(adev, 0);
+ amdgpu_gmc_flush_gpu_tlb(adev, 0, 0);
return 0;
}
@@ -259,6 +259,8 @@ int amdgpu_gart_unbind(struct amdgpu_device *adev, uint64_t offset,
* @offset: offset into the GPU's gart aperture
* @pages: number of pages to bind
* @dma_addr: DMA addresses of pages
+ * @flags: page table entry flags
+ * @dst: CPU address of the gart table
*
* Map the dma_addresses into GART entries (all asics).
* Returns 0 for success, -EINVAL for failure.
@@ -331,7 +333,7 @@ int amdgpu_gart_bind(struct amdgpu_device *adev, uint64_t offset,
mb();
amdgpu_asic_flush_hdp(adev, NULL);
- amdgpu_gmc_flush_gpu_tlb(adev, 0);
+ amdgpu_gmc_flush_gpu_tlb(adev, 0, 0);
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.h
index 9ff62887e4e3..afa2e2877d87 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.h
@@ -41,6 +41,7 @@ struct amdgpu_bo;
struct amdgpu_gart {
struct amdgpu_bo *bo;
+ /* CPU kmapped address of gart table */
void *ptr;
unsigned num_gpu_pages;
unsigned num_cpu_pages;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
index 1a656b8657f7..6a70c0b7105f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
@@ -25,6 +25,7 @@
#include <drm/drmP.h>
#include "amdgpu.h"
#include "amdgpu_gfx.h"
+#include "amdgpu_rlc.h"
/* delay 0.1 second to enable gfx off feature */
#define GFX_OFF_DELAY_ENABLE msecs_to_jiffies(100)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h
index b61b5c11aead..f790e15bcd08 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h
@@ -29,6 +29,7 @@
*/
#include "clearstate_defs.h"
#include "amdgpu_ring.h"
+#include "amdgpu_rlc.h"
/* GFX current status */
#define AMDGPU_GFX_NORMAL_MODE 0x00000000L
@@ -37,59 +38,6 @@
#define AMDGPU_GFX_CG_DISABLED_MODE 0x00000004L
#define AMDGPU_GFX_LBPW_DISABLED_MODE 0x00000008L
-
-struct amdgpu_rlc_funcs {
- void (*enter_safe_mode)(struct amdgpu_device *adev);
- void (*exit_safe_mode)(struct amdgpu_device *adev);
-};
-
-struct amdgpu_rlc {
- /* for power gating */
- struct amdgpu_bo *save_restore_obj;
- uint64_t save_restore_gpu_addr;
- volatile uint32_t *sr_ptr;
- const u32 *reg_list;
- u32 reg_list_size;
- /* for clear state */
- struct amdgpu_bo *clear_state_obj;
- uint64_t clear_state_gpu_addr;
- volatile uint32_t *cs_ptr;
- const struct cs_section_def *cs_data;
- u32 clear_state_size;
- /* for cp tables */
- struct amdgpu_bo *cp_table_obj;
- uint64_t cp_table_gpu_addr;
- volatile uint32_t *cp_table_ptr;
- u32 cp_table_size;
-
- /* safe mode for updating CG/PG state */
- bool in_safe_mode;
- const struct amdgpu_rlc_funcs *funcs;
-
- /* for firmware data */
- u32 save_and_restore_offset;
- u32 clear_state_descriptor_offset;
- u32 avail_scratch_ram_locations;
- u32 reg_restore_list_size;
- u32 reg_list_format_start;
- u32 reg_list_format_separate_start;
- u32 starting_offsets_start;
- u32 reg_list_format_size_bytes;
- u32 reg_list_size_bytes;
- u32 reg_list_format_direct_reg_list_length;
- u32 save_restore_list_cntl_size_bytes;
- u32 save_restore_list_gpm_size_bytes;
- u32 save_restore_list_srm_size_bytes;
-
- u32 *register_list_format;
- u32 *register_restore;
- u8 *save_restore_list_cntl;
- u8 *save_restore_list_gpm;
- u8 *save_restore_list_srm;
-
- bool is_rlc_v2_1;
-};
-
#define AMDGPU_MAX_COMPUTE_QUEUES KGD_MAX_QUEUES
struct amdgpu_mec {
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h
index 6fa7ef446e46..8c57924c075f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h
@@ -64,7 +64,7 @@ struct amdgpu_vmhub {
struct amdgpu_gmc_funcs {
/* flush the vm tlb via mmio */
void (*flush_gpu_tlb)(struct amdgpu_device *adev,
- uint32_t vmid);
+ uint32_t vmid, uint32_t flush_type);
/* flush the vm tlb via ring */
uint64_t (*emit_flush_gpu_tlb)(struct amdgpu_ring *ring, unsigned vmid,
uint64_t pd_addr);
@@ -89,7 +89,7 @@ struct amdgpu_gmc_funcs {
struct amdgpu_xgmi {
/* from psp */
- u64 device_id;
+ u64 node_id;
u64 hive_id;
/* fixed per family */
u64 node_segment_size;
@@ -151,7 +151,7 @@ struct amdgpu_gmc {
struct amdgpu_xgmi xgmi;
};
-#define amdgpu_gmc_flush_gpu_tlb(adev, vmid) (adev)->gmc.gmc_funcs->flush_gpu_tlb((adev), (vmid))
+#define amdgpu_gmc_flush_gpu_tlb(adev, vmid, type) (adev)->gmc.gmc_funcs->flush_gpu_tlb((adev), (vmid), (type))
#define amdgpu_gmc_emit_flush_gpu_tlb(r, vmid, addr) (r)->adev->gmc.gmc_funcs->emit_flush_gpu_tlb((r), (vmid), (addr))
#define amdgpu_gmc_emit_pasid_mapping(r, vmid, pasid) (r)->adev->gmc.gmc_funcs->emit_pasid_mapping((r), (vmid), (pasid))
#define amdgpu_gmc_set_pte_pde(adev, pt, idx, addr, flags) (adev)->gmc.gmc_funcs->set_pte_pde((adev), (pt), (idx), (addr), (flags))
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
index b8963b725dfa..c48207b377bc 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
@@ -146,7 +146,7 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs,
fence_ctx = 0;
}
- if (!ring->ready) {
+ if (!ring->sched.ready) {
dev_err(adev->dev, "couldn't schedule ib on ring <%s>\n", ring->name);
return -EINVAL;
}
@@ -221,8 +221,7 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs,
!amdgpu_sriov_vf(adev)) /* for SRIOV preemption, Preamble CE ib must be inserted anyway */
continue;
- amdgpu_ring_emit_ib(ring, ib, job ? job->vmid : 0,
- need_ctx_switch);
+ amdgpu_ring_emit_ib(ring, job, ib, need_ctx_switch);
need_ctx_switch = false;
}
@@ -347,19 +346,14 @@ int amdgpu_ib_ring_tests(struct amdgpu_device *adev)
tmo_gfx = 8 * AMDGPU_IB_TEST_TIMEOUT;
}
- for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
+ for (i = 0; i < adev->num_rings; ++i) {
struct amdgpu_ring *ring = adev->rings[i];
long tmo;
- if (!ring || !ring->ready)
- continue;
-
- /* skip IB tests for KIQ in general for the below reasons:
- * 1. We never submit IBs to the KIQ
- * 2. KIQ doesn't use the EOP interrupts,
- * we use some other CP interrupt.
+ /* KIQ rings don't have an IB test because we never submit IBs
+ * to them and they have no interrupt support.
*/
- if (ring->funcs->type == AMDGPU_RING_TYPE_KIQ)
+ if (!ring->sched.ready || !ring->funcs->test_ib)
continue;
/* MM engine need more time */
@@ -374,20 +368,23 @@ int amdgpu_ib_ring_tests(struct amdgpu_device *adev)
tmo = tmo_gfx;
r = amdgpu_ring_test_ib(ring, tmo);
- if (r) {
- ring->ready = false;
-
- if (ring == &adev->gfx.gfx_ring[0]) {
- /* oh, oh, that's really bad */
- DRM_ERROR("amdgpu: failed testing IB on GFX ring (%d).\n", r);
- adev->accel_working = false;
- return r;
-
- } else {
- /* still not good, but we can live with it */
- DRM_ERROR("amdgpu: failed testing IB on ring %d (%d).\n", i, r);
- ret = r;
- }
+ if (!r) {
+ DRM_DEV_DEBUG(adev->dev, "ib test on %s succeeded\n",
+ ring->name);
+ continue;
+ }
+
+ ring->sched.ready = false;
+ DRM_DEV_ERROR(adev->dev, "IB test failed on %s (%d).\n",
+ ring->name, r);
+
+ if (ring == &adev->gfx.gfx_ring[0]) {
+ /* oh, oh, that's really bad */
+ adev->accel_working = false;
+ return r;
+
+ } else {
+ ret = r;
}
}
return ret;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
index 52c17f6219a7..6b6524f04ce0 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
@@ -94,23 +94,6 @@ static void amdgpu_hotplug_work_func(struct work_struct *work)
}
/**
- * amdgpu_irq_reset_work_func - execute GPU reset
- *
- * @work: work struct pointer
- *
- * Execute scheduled GPU reset (Cayman+).
- * This function is called when the IRQ handler thinks we need a GPU reset.
- */
-static void amdgpu_irq_reset_work_func(struct work_struct *work)
-{
- struct amdgpu_device *adev = container_of(work, struct amdgpu_device,
- reset_work);
-
- if (!amdgpu_sriov_vf(adev) && amdgpu_device_should_recover_gpu(adev))
- amdgpu_device_gpu_recover(adev, NULL);
-}
-
-/**
* amdgpu_irq_disable_all - disable *all* interrupts
*
* @adev: amdgpu device pointer
@@ -262,15 +245,12 @@ int amdgpu_irq_init(struct amdgpu_device *adev)
amdgpu_hotplug_work_func);
}
- INIT_WORK(&adev->reset_work, amdgpu_irq_reset_work_func);
-
adev->irq.installed = true;
r = drm_irq_install(adev->ddev, adev->ddev->pdev->irq);
if (r) {
adev->irq.installed = false;
if (!amdgpu_device_has_dc_support(adev))
flush_work(&adev->hotplug_work);
- cancel_work_sync(&adev->reset_work);
return r;
}
adev->ddev->max_vblank_count = 0x00ffffff;
@@ -299,7 +279,6 @@ void amdgpu_irq_fini(struct amdgpu_device *adev)
pci_disable_msi(adev->pdev);
if (!amdgpu_device_has_dc_support(adev))
flush_work(&adev->hotplug_work);
- cancel_work_sync(&adev->reset_work);
}
for (i = 0; i < AMDGPU_IRQ_CLIENTID_MAX; ++i) {
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
index 755f733bf0d9..e0af44fd6a0c 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
@@ -112,6 +112,8 @@ static void amdgpu_job_free_cb(struct drm_sched_job *s_job)
struct amdgpu_ring *ring = to_amdgpu_ring(s_job->sched);
struct amdgpu_job *job = to_amdgpu_job(s_job);
+ drm_sched_job_cleanup(s_job);
+
amdgpu_ring_priority_put(ring, s_job->s_priority);
dma_fence_put(job->fence);
amdgpu_sync_free(&job->sync);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h
index 57cfe78a262b..e1b46a6703de 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h
@@ -33,6 +33,8 @@
#define to_amdgpu_job(sched_job) \
container_of((sched_job), struct amdgpu_job, base)
+#define AMDGPU_JOB_GET_VMID(job) ((job) ? (job)->vmid : 0)
+
struct amdgpu_fence;
struct amdgpu_job {
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
index 81732a84c2ab..9b3164c0f861 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
@@ -336,7 +336,7 @@ static int amdgpu_hw_ip_info(struct amdgpu_device *adev,
case AMDGPU_HW_IP_GFX:
type = AMD_IP_BLOCK_TYPE_GFX;
for (i = 0; i < adev->gfx.num_gfx_rings; i++)
- if (adev->gfx.gfx_ring[i].ready)
+ if (adev->gfx.gfx_ring[i].sched.ready)
++num_rings;
ib_start_alignment = 32;
ib_size_alignment = 32;
@@ -344,7 +344,7 @@ static int amdgpu_hw_ip_info(struct amdgpu_device *adev,
case AMDGPU_HW_IP_COMPUTE:
type = AMD_IP_BLOCK_TYPE_GFX;
for (i = 0; i < adev->gfx.num_compute_rings; i++)
- if (adev->gfx.compute_ring[i].ready)
+ if (adev->gfx.compute_ring[i].sched.ready)
++num_rings;
ib_start_alignment = 32;
ib_size_alignment = 32;
@@ -352,7 +352,7 @@ static int amdgpu_hw_ip_info(struct amdgpu_device *adev,
case AMDGPU_HW_IP_DMA:
type = AMD_IP_BLOCK_TYPE_SDMA;
for (i = 0; i < adev->sdma.num_instances; i++)
- if (adev->sdma.instance[i].ring.ready)
+ if (adev->sdma.instance[i].ring.sched.ready)
++num_rings;
ib_start_alignment = 256;
ib_size_alignment = 4;
@@ -363,7 +363,7 @@ static int amdgpu_hw_ip_info(struct amdgpu_device *adev,
if (adev->uvd.harvest_config & (1 << i))
continue;
- if (adev->uvd.inst[i].ring.ready)
+ if (adev->uvd.inst[i].ring.sched.ready)
++num_rings;
}
ib_start_alignment = 64;
@@ -372,7 +372,7 @@ static int amdgpu_hw_ip_info(struct amdgpu_device *adev,
case AMDGPU_HW_IP_VCE:
type = AMD_IP_BLOCK_TYPE_VCE;
for (i = 0; i < adev->vce.num_rings; i++)
- if (adev->vce.ring[i].ready)
+ if (adev->vce.ring[i].sched.ready)
++num_rings;
ib_start_alignment = 4;
ib_size_alignment = 1;
@@ -384,7 +384,7 @@ static int amdgpu_hw_ip_info(struct amdgpu_device *adev,
continue;
for (j = 0; j < adev->uvd.num_enc_rings; j++)
- if (adev->uvd.inst[i].ring_enc[j].ready)
+ if (adev->uvd.inst[i].ring_enc[j].sched.ready)
++num_rings;
}
ib_start_alignment = 64;
@@ -392,7 +392,7 @@ static int amdgpu_hw_ip_info(struct amdgpu_device *adev,
break;
case AMDGPU_HW_IP_VCN_DEC:
type = AMD_IP_BLOCK_TYPE_VCN;
- if (adev->vcn.ring_dec.ready)
+ if (adev->vcn.ring_dec.sched.ready)
++num_rings;
ib_start_alignment = 16;
ib_size_alignment = 16;
@@ -400,14 +400,14 @@ static int amdgpu_hw_ip_info(struct amdgpu_device *adev,
case AMDGPU_HW_IP_VCN_ENC:
type = AMD_IP_BLOCK_TYPE_VCN;
for (i = 0; i < adev->vcn.num_enc_rings; i++)
- if (adev->vcn.ring_enc[i].ready)
+ if (adev->vcn.ring_enc[i].sched.ready)
++num_rings;
ib_start_alignment = 64;
ib_size_alignment = 1;
break;
case AMDGPU_HW_IP_VCN_JPEG:
type = AMD_IP_BLOCK_TYPE_VCN;
- if (adev->vcn.ring_jpeg.ready)
+ if (adev->vcn.ring_jpeg.sched.ready)
++num_rings;
ib_start_alignment = 16;
ib_size_alignment = 16;
@@ -978,7 +978,10 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)
}
if (amdgpu_sriov_vf(adev)) {
- r = amdgpu_map_static_csa(adev, &fpriv->vm, &fpriv->csa_va);
+ uint64_t csa_addr = amdgpu_csa_vaddr(adev) & AMDGPU_GMC_HOLE_MASK;
+
+ r = amdgpu_map_static_csa(adev, &fpriv->vm, adev->virt.csa_obj,
+ &fpriv->csa_va, csa_addr, AMDGPU_CSA_SIZE);
if (r)
goto error_vm;
}
@@ -1048,8 +1051,8 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev,
pasid = fpriv->vm.pasid;
pd = amdgpu_bo_ref(fpriv->vm.root.base.bo);
- amdgpu_vm_fini(adev, &fpriv->vm);
amdgpu_ctx_mgr_fini(&fpriv->ctx_mgr);
+ amdgpu_vm_fini(adev, &fpriv->vm);
if (pasid)
amdgpu_pasid_free_delayed(pd->tbo.resv, pasid);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
index b9e9e8b02fb7..11723d8fffbd 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
@@ -57,7 +57,6 @@ struct amdgpu_hpd;
#define to_amdgpu_connector(x) container_of(x, struct amdgpu_connector, base)
#define to_amdgpu_encoder(x) container_of(x, struct amdgpu_encoder, base)
#define to_amdgpu_framebuffer(x) container_of(x, struct amdgpu_framebuffer, base)
-#define to_amdgpu_plane(x) container_of(x, struct amdgpu_plane, base)
#define to_dm_plane_state(x) container_of(x, struct dm_plane_state, base);
@@ -325,7 +324,7 @@ struct amdgpu_mode_info {
struct card_info *atom_card_info;
bool mode_config_initialized;
struct amdgpu_crtc *crtcs[AMDGPU_MAX_CRTCS];
- struct amdgpu_plane *planes[AMDGPU_MAX_PLANES];
+ struct drm_plane *planes[AMDGPU_MAX_PLANES];
struct amdgpu_afmt *afmt[AMDGPU_MAX_AFMT_BLOCKS];
/* DVI-I properties */
struct drm_property *coherent_mode_property;
@@ -434,11 +433,6 @@ struct amdgpu_crtc {
struct drm_pending_vblank_event *event;
};
-struct amdgpu_plane {
- struct drm_plane base;
- enum drm_plane_type plane_type;
-};
-
struct amdgpu_encoder_atom_dig {
bool linkb;
/* atom dig */
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
index 904014dc5915..cf768acb51dc 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
@@ -640,7 +640,7 @@ int amdgpu_bo_backup_to_shadow(struct amdgpu_device *adev,
bo_addr = amdgpu_bo_gpu_offset(bo);
shadow_addr = amdgpu_bo_gpu_offset(bo->shadow);
- r = reservation_object_reserve_shared(bo->tbo.resv);
+ r = reservation_object_reserve_shared(bo->tbo.resv, 1);
if (r)
goto err;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
index 59cc678de8c1..7235cd0b0fa9 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
@@ -2129,7 +2129,7 @@ void amdgpu_pm_compute_clocks(struct amdgpu_device *adev)
for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
struct amdgpu_ring *ring = adev->rings[i];
- if (ring && ring->ready)
+ if (ring && ring->sched.ready)
amdgpu_fence_wait_empty(ring);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c
index e45e929aaab5..3e44d889f7af 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c
@@ -339,8 +339,6 @@ static const struct dma_buf_ops amdgpu_dmabuf_ops = {
.unmap_dma_buf = drm_gem_unmap_dma_buf,
.release = drm_gem_dmabuf_release,
.begin_cpu_access = amdgpu_gem_begin_cpu_access,
- .map = drm_gem_dmabuf_kmap,
- .unmap = drm_gem_dmabuf_kunmap,
.mmap = drm_gem_dmabuf_mmap,
.vmap = drm_gem_dmabuf_vmap,
.vunmap = drm_gem_dmabuf_vunmap,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
index 25d2f3e757f1..e05dc66b1090 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
@@ -90,6 +90,8 @@ static int psp_sw_fini(void *handle)
adev->psp.sos_fw = NULL;
release_firmware(adev->psp.asd_fw);
adev->psp.asd_fw = NULL;
+ release_firmware(adev->psp.ta_fw);
+ adev->psp.ta_fw = NULL;
return 0;
}
@@ -118,21 +120,25 @@ int psp_wait_for(struct psp_context *psp, uint32_t reg_index,
static int
psp_cmd_submit_buf(struct psp_context *psp,
struct amdgpu_firmware_info *ucode,
- struct psp_gfx_cmd_resp *cmd, uint64_t fence_mc_addr,
- int index)
+ struct psp_gfx_cmd_resp *cmd, uint64_t fence_mc_addr)
{
int ret;
+ int index;
memset(psp->cmd_buf_mem, 0, PSP_CMD_BUFFER_SIZE);
memcpy(psp->cmd_buf_mem, cmd, sizeof(struct psp_gfx_cmd_resp));
+ index = atomic_inc_return(&psp->fence_value);
ret = psp_cmd_submit(psp, ucode, psp->cmd_buf_mc_addr,
fence_mc_addr, index);
+ if (ret) {
+ atomic_dec(&psp->fence_value);
+ return ret;
+ }
- while (*((unsigned int *)psp->fence_buf) != index) {
+ while (*((unsigned int *)psp->fence_buf) != index)
msleep(1);
- }
/* the status field must be 0 after FW is loaded */
if (ucode && psp->cmd_buf_mem->resp.status) {
@@ -191,7 +197,7 @@ static int psp_tmr_load(struct psp_context *psp)
PSP_TMR_SIZE, psp->tmr_mc_addr);
ret = psp_cmd_submit_buf(psp, NULL, cmd,
- psp->fence_buf_mc_addr, 1);
+ psp->fence_buf_mc_addr);
if (ret)
goto failed;
@@ -258,13 +264,194 @@ static int psp_asd_load(struct psp_context *psp)
psp->asd_ucode_size, PSP_ASD_SHARED_MEM_SIZE);
ret = psp_cmd_submit_buf(psp, NULL, cmd,
- psp->fence_buf_mc_addr, 2);
+ psp->fence_buf_mc_addr);
+
+ kfree(cmd);
+
+ return ret;
+}
+
+static void psp_prep_xgmi_ta_load_cmd_buf(struct psp_gfx_cmd_resp *cmd,
+ uint64_t xgmi_ta_mc, uint64_t xgmi_mc_shared,
+ uint32_t xgmi_ta_size, uint32_t shared_size)
+{
+ cmd->cmd_id = GFX_CMD_ID_LOAD_TA;
+ cmd->cmd.cmd_load_ta.app_phy_addr_lo = lower_32_bits(xgmi_ta_mc);
+ cmd->cmd.cmd_load_ta.app_phy_addr_hi = upper_32_bits(xgmi_ta_mc);
+ cmd->cmd.cmd_load_ta.app_len = xgmi_ta_size;
+
+ cmd->cmd.cmd_load_ta.cmd_buf_phy_addr_lo = lower_32_bits(xgmi_mc_shared);
+ cmd->cmd.cmd_load_ta.cmd_buf_phy_addr_hi = upper_32_bits(xgmi_mc_shared);
+ cmd->cmd.cmd_load_ta.cmd_buf_len = shared_size;
+}
+
+static int psp_xgmi_init_shared_buf(struct psp_context *psp)
+{
+ int ret;
+
+ /*
+ * Allocate 16k memory aligned to 4k from Frame Buffer (local
+ * physical) for xgmi ta <-> Driver
+ */
+ ret = amdgpu_bo_create_kernel(psp->adev, PSP_XGMI_SHARED_MEM_SIZE,
+ PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM,
+ &psp->xgmi_context.xgmi_shared_bo,
+ &psp->xgmi_context.xgmi_shared_mc_addr,
+ &psp->xgmi_context.xgmi_shared_buf);
+
+ return ret;
+}
+
+static int psp_xgmi_load(struct psp_context *psp)
+{
+ int ret;
+ struct psp_gfx_cmd_resp *cmd;
+
+ /*
+ * TODO: bypass the loading in sriov for now
+ */
+ if (amdgpu_sriov_vf(psp->adev))
+ return 0;
+
+ cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+
+ memset(psp->fw_pri_buf, 0, PSP_1_MEG);
+ memcpy(psp->fw_pri_buf, psp->ta_xgmi_start_addr, psp->ta_xgmi_ucode_size);
+
+ psp_prep_xgmi_ta_load_cmd_buf(cmd, psp->fw_pri_mc_addr,
+ psp->xgmi_context.xgmi_shared_mc_addr,
+ psp->ta_xgmi_ucode_size, PSP_XGMI_SHARED_MEM_SIZE);
+
+ ret = psp_cmd_submit_buf(psp, NULL, cmd,
+ psp->fence_buf_mc_addr);
+
+ if (!ret) {
+ psp->xgmi_context.initialized = 1;
+ psp->xgmi_context.session_id = cmd->resp.session_id;
+ }
+
+ kfree(cmd);
+
+ return ret;
+}
+
+static void psp_prep_xgmi_ta_unload_cmd_buf(struct psp_gfx_cmd_resp *cmd,
+ uint32_t xgmi_session_id)
+{
+ cmd->cmd_id = GFX_CMD_ID_UNLOAD_TA;
+ cmd->cmd.cmd_unload_ta.session_id = xgmi_session_id;
+}
+
+static int psp_xgmi_unload(struct psp_context *psp)
+{
+ int ret;
+ struct psp_gfx_cmd_resp *cmd;
+
+ /*
+ * TODO: bypass the unloading in sriov for now
+ */
+ if (amdgpu_sriov_vf(psp->adev))
+ return 0;
+
+ cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+
+ psp_prep_xgmi_ta_unload_cmd_buf(cmd, psp->xgmi_context.session_id);
+
+ ret = psp_cmd_submit_buf(psp, NULL, cmd,
+ psp->fence_buf_mc_addr);
kfree(cmd);
return ret;
}
+static void psp_prep_xgmi_ta_invoke_cmd_buf(struct psp_gfx_cmd_resp *cmd,
+ uint32_t ta_cmd_id,
+ uint32_t xgmi_session_id)
+{
+ cmd->cmd_id = GFX_CMD_ID_INVOKE_CMD;
+ cmd->cmd.cmd_invoke_cmd.session_id = xgmi_session_id;
+ cmd->cmd.cmd_invoke_cmd.ta_cmd_id = ta_cmd_id;
+ /* Note: cmd_invoke_cmd.buf is not used for now */
+}
+
+int psp_xgmi_invoke(struct psp_context *psp, uint32_t ta_cmd_id)
+{
+ int ret;
+ struct psp_gfx_cmd_resp *cmd;
+
+ /*
+ * TODO: bypass the loading in sriov for now
+ */
+ if (amdgpu_sriov_vf(psp->adev))
+ return 0;
+
+ cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+
+ psp_prep_xgmi_ta_invoke_cmd_buf(cmd, ta_cmd_id,
+ psp->xgmi_context.session_id);
+
+ ret = psp_cmd_submit_buf(psp, NULL, cmd,
+ psp->fence_buf_mc_addr);
+
+ kfree(cmd);
+
+ return ret;
+}
+
+static int psp_xgmi_terminate(struct psp_context *psp)
+{
+ int ret;
+
+ if (!psp->xgmi_context.initialized)
+ return 0;
+
+ ret = psp_xgmi_unload(psp);
+ if (ret)
+ return ret;
+
+ psp->xgmi_context.initialized = 0;
+
+ /* free xgmi shared memory */
+ amdgpu_bo_free_kernel(&psp->xgmi_context.xgmi_shared_bo,
+ &psp->xgmi_context.xgmi_shared_mc_addr,
+ &psp->xgmi_context.xgmi_shared_buf);
+
+ return 0;
+}
+
+static int psp_xgmi_initialize(struct psp_context *psp)
+{
+ struct ta_xgmi_shared_memory *xgmi_cmd;
+ int ret;
+
+ if (!psp->xgmi_context.initialized) {
+ ret = psp_xgmi_init_shared_buf(psp);
+ if (ret)
+ return ret;
+ }
+
+ /* Load XGMI TA */
+ ret = psp_xgmi_load(psp);
+ if (ret)
+ return ret;
+
+ /* Initialize XGMI session */
+ xgmi_cmd = (struct ta_xgmi_shared_memory *)(psp->xgmi_context.xgmi_shared_buf);
+ memset(xgmi_cmd, 0, sizeof(struct ta_xgmi_shared_memory));
+ xgmi_cmd->cmd_id = TA_COMMAND_XGMI__INITIALIZE;
+
+ ret = psp_xgmi_invoke(psp, xgmi_cmd->cmd_id);
+
+ return ret;
+}
+
static int psp_hw_start(struct psp_context *psp)
{
struct amdgpu_device *adev = psp->adev;
@@ -292,6 +479,15 @@ static int psp_hw_start(struct psp_context *psp)
if (ret)
return ret;
+ if (adev->gmc.xgmi.num_physical_nodes > 1) {
+ ret = psp_xgmi_initialize(psp);
+ /* Warning the XGMI seesion initialize failure
+ * Instead of stop driver initialization
+ */
+ if (ret)
+ dev_err(psp->adev->dev,
+ "XGMI: Failed to initialize XGMI session\n");
+ }
return 0;
}
@@ -321,7 +517,7 @@ static int psp_np_fw_load(struct psp_context *psp)
return ret;
ret = psp_cmd_submit_buf(psp, ucode, psp->cmd,
- psp->fence_buf_mc_addr, i + 3);
+ psp->fence_buf_mc_addr);
if (ret)
return ret;
@@ -452,6 +648,10 @@ static int psp_hw_fini(void *handle)
if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP)
return 0;
+ if (adev->gmc.xgmi.num_physical_nodes > 1 &&
+ psp->xgmi_context.initialized == 1)
+ psp_xgmi_terminate(psp);
+
psp_ring_destroy(psp, PSP_RING_TYPE__KM);
amdgpu_bo_free_kernel(&psp->tmr_bo, &psp->tmr_mc_addr, &psp->tmr_buf);
@@ -479,6 +679,15 @@ static int psp_suspend(void *handle)
if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP)
return 0;
+ if (adev->gmc.xgmi.num_physical_nodes > 1 &&
+ psp->xgmi_context.initialized == 1) {
+ ret = psp_xgmi_terminate(psp);
+ if (ret) {
+ DRM_ERROR("Failed to terminate xgmi ta\n");
+ return ret;
+ }
+ }
+
ret = psp_ring_stop(psp, PSP_RING_TYPE__KM);
if (ret) {
DRM_ERROR("PSP ring stop failed\n");
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
index 8b8720e9c3f0..9ec5d1a666a6 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
@@ -27,14 +27,17 @@
#include "amdgpu.h"
#include "psp_gfx_if.h"
+#include "ta_xgmi_if.h"
#define PSP_FENCE_BUFFER_SIZE 0x1000
#define PSP_CMD_BUFFER_SIZE 0x1000
-#define PSP_ASD_SHARED_MEM_SIZE 0x4000
+#define PSP_ASD_SHARED_MEM_SIZE 0x4000
+#define PSP_XGMI_SHARED_MEM_SIZE 0x4000
#define PSP_1_MEG 0x100000
#define PSP_TMR_SIZE 0x400000
struct psp_context;
+struct psp_xgmi_node_info;
struct psp_xgmi_topology_info;
enum psp_ring_type
@@ -80,12 +83,20 @@ struct psp_funcs
enum AMDGPU_UCODE_ID ucode_type);
bool (*smu_reload_quirk)(struct psp_context *psp);
int (*mode1_reset)(struct psp_context *psp);
- uint64_t (*xgmi_get_device_id)(struct psp_context *psp);
+ uint64_t (*xgmi_get_node_id)(struct psp_context *psp);
uint64_t (*xgmi_get_hive_id)(struct psp_context *psp);
int (*xgmi_get_topology_info)(struct psp_context *psp, int number_devices,
- struct psp_xgmi_topology_info *topology);
+ struct psp_xgmi_topology_info *topology);
int (*xgmi_set_topology_info)(struct psp_context *psp, int number_devices,
- struct psp_xgmi_topology_info *topology);
+ struct psp_xgmi_topology_info *topology);
+};
+
+struct psp_xgmi_context {
+ uint8_t initialized;
+ uint32_t session_id;
+ struct amdgpu_bo *xgmi_shared_bo;
+ uint64_t xgmi_shared_mc_addr;
+ void *xgmi_shared_buf;
};
struct psp_context
@@ -96,7 +107,7 @@ struct psp_context
const struct psp_funcs *funcs;
- /* fence buffer */
+ /* firmware buffer */
struct amdgpu_bo *fw_pri_bo;
uint64_t fw_pri_mc_addr;
void *fw_pri_buf;
@@ -134,6 +145,16 @@ struct psp_context
struct amdgpu_bo *cmd_buf_bo;
uint64_t cmd_buf_mc_addr;
struct psp_gfx_cmd_resp *cmd_buf_mem;
+
+ /* fence value associated with cmd buffer */
+ atomic_t fence_value;
+
+ /* xgmi ta firmware and buffer */
+ const struct firmware *ta_fw;
+ uint32_t ta_xgmi_ucode_version;
+ uint32_t ta_xgmi_ucode_size;
+ uint8_t *ta_xgmi_start_addr;
+ struct psp_xgmi_context xgmi_context;
};
struct amdgpu_psp_funcs {
@@ -141,21 +162,17 @@ struct amdgpu_psp_funcs {
enum AMDGPU_UCODE_ID);
};
+#define AMDGPU_XGMI_MAX_CONNECTED_NODES 64
+struct psp_xgmi_node_info {
+ uint64_t node_id;
+ uint8_t num_hops;
+ uint8_t is_sharing_enabled;
+ enum ta_xgmi_assigned_sdma_engine sdma_engine;
+};
+
struct psp_xgmi_topology_info {
- /* Generated by PSP to identify the GPU instance within xgmi connection */
- uint64_t device_id;
- /*
- * If all bits set to 0 , driver indicates it wants to retrieve the xgmi
- * connection vector topology, but not access enable the connections
- * if some or all bits are set to 1, driver indicates it want to retrieve the
- * current xgmi topology and access enable the link to GPU[i] associated
- * with the bit position in the vector.
- * On return,: bits indicated which xgmi links are present/active depending
- * on the value passed in. The relative bit offset for the relative GPU index
- * within the hive is always marked active.
- */
- uint32_t connection_mask;
- uint32_t reserved; /* must be 0 */
+ uint32_t num_nodes;
+ struct psp_xgmi_node_info nodes[AMDGPU_XGMI_MAX_CONNECTED_NODES];
};
#define psp_prep_cmd_buf(ucode, type) (psp)->funcs->prep_cmd_buf((ucode), (type))
@@ -177,8 +194,8 @@ struct psp_xgmi_topology_info {
((psp)->funcs->smu_reload_quirk ? (psp)->funcs->smu_reload_quirk((psp)) : false)
#define psp_mode1_reset(psp) \
((psp)->funcs->mode1_reset ? (psp)->funcs->mode1_reset((psp)) : false)
-#define psp_xgmi_get_device_id(psp) \
- ((psp)->funcs->xgmi_get_device_id ? (psp)->funcs->xgmi_get_device_id((psp)) : 0)
+#define psp_xgmi_get_node_id(psp) \
+ ((psp)->funcs->xgmi_get_node_id ? (psp)->funcs->xgmi_get_node_id((psp)) : 0)
#define psp_xgmi_get_hive_id(psp) \
((psp)->funcs->xgmi_get_hive_id ? (psp)->funcs->xgmi_get_hive_id((psp)) : 0)
#define psp_xgmi_get_topology_info(psp, num_device, topology) \
@@ -199,6 +216,8 @@ extern int psp_wait_for(struct psp_context *psp, uint32_t reg_index,
extern const struct amdgpu_ip_block_version psp_v10_0_ip_block;
int psp_gpu_reset(struct amdgpu_device *adev);
+int psp_xgmi_invoke(struct psp_context *psp, uint32_t ta_cmd_id);
+
extern const struct amdgpu_ip_block_version psp_v11_0_ip_block;
#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
index b70e85ec147d..5b75bdc8dc28 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
@@ -338,7 +338,7 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring,
*/
void amdgpu_ring_fini(struct amdgpu_ring *ring)
{
- ring->ready = false;
+ ring->sched.ready = false;
/* Not to finish a ring which is not initialized */
if (!(ring->adev) || !(ring->adev->rings[ring->idx]))
@@ -500,3 +500,29 @@ static void amdgpu_debugfs_ring_fini(struct amdgpu_ring *ring)
debugfs_remove(ring->ent);
#endif
}
+
+/**
+ * amdgpu_ring_test_helper - tests ring and set sched readiness status
+ *
+ * @ring: ring to try the recovery on
+ *
+ * Tests ring and set sched readiness status
+ *
+ * Returns 0 on success, error on failure.
+ */
+int amdgpu_ring_test_helper(struct amdgpu_ring *ring)
+{
+ struct amdgpu_device *adev = ring->adev;
+ int r;
+
+ r = amdgpu_ring_test_ring(ring);
+ if (r)
+ DRM_DEV_ERROR(adev->dev, "ring %s test failed (%d)\n",
+ ring->name, r);
+ else
+ DRM_DEV_DEBUG(adev->dev, "ring test on %s succeeded\n",
+ ring->name);
+
+ ring->sched.ready = !r;
+ return r;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
index 4caa301ce454..0beb01fef83f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
@@ -129,8 +129,9 @@ struct amdgpu_ring_funcs {
unsigned emit_ib_size;
/* command emit functions */
void (*emit_ib)(struct amdgpu_ring *ring,
+ struct amdgpu_job *job,
struct amdgpu_ib *ib,
- unsigned vmid, bool ctx_switch);
+ bool ctx_switch);
void (*emit_fence)(struct amdgpu_ring *ring, uint64_t addr,
uint64_t seq, unsigned flags);
void (*emit_pipeline_sync)(struct amdgpu_ring *ring);
@@ -189,7 +190,6 @@ struct amdgpu_ring {
uint64_t gpu_addr;
uint64_t ptr_mask;
uint32_t buf_mask;
- bool ready;
u32 idx;
u32 me;
u32 pipe;
@@ -229,7 +229,7 @@ struct amdgpu_ring {
#define amdgpu_ring_get_rptr(r) (r)->funcs->get_rptr((r))
#define amdgpu_ring_get_wptr(r) (r)->funcs->get_wptr((r))
#define amdgpu_ring_set_wptr(r) (r)->funcs->set_wptr((r))
-#define amdgpu_ring_emit_ib(r, ib, vmid, c) (r)->funcs->emit_ib((r), (ib), (vmid), (c))
+#define amdgpu_ring_emit_ib(r, job, ib, c) ((r)->funcs->emit_ib((r), (job), (ib), (c)))
#define amdgpu_ring_emit_pipeline_sync(r) (r)->funcs->emit_pipeline_sync((r))
#define amdgpu_ring_emit_vm_flush(r, vmid, addr) (r)->funcs->emit_vm_flush((r), (vmid), (addr))
#define amdgpu_ring_emit_fence(r, addr, seq, flags) (r)->funcs->emit_fence((r), (addr), (seq), (flags))
@@ -313,4 +313,6 @@ static inline void amdgpu_ring_write_multiple(struct amdgpu_ring *ring,
ring->count_dw -= count_dw;
}
+int amdgpu_ring_test_helper(struct amdgpu_ring *ring);
+
#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c
new file mode 100644
index 000000000000..c8793e6cc3c5
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * 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/firmware.h>
+#include "amdgpu.h"
+#include "amdgpu_gfx.h"
+#include "amdgpu_rlc.h"
+
+/**
+ * amdgpu_gfx_rlc_enter_safe_mode - Set RLC into safe mode
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Set RLC enter into safe mode if RLC is enabled and haven't in safe mode.
+ */
+void amdgpu_gfx_rlc_enter_safe_mode(struct amdgpu_device *adev)
+{
+ if (adev->gfx.rlc.in_safe_mode)
+ return;
+
+ /* if RLC is not enabled, do nothing */
+ if (!adev->gfx.rlc.funcs->is_rlc_enabled(adev))
+ return;
+
+ if (adev->cg_flags &
+ (AMD_CG_SUPPORT_GFX_CGCG | AMD_CG_SUPPORT_GFX_MGCG |
+ AMD_CG_SUPPORT_GFX_3D_CGCG)) {
+ adev->gfx.rlc.funcs->set_safe_mode(adev);
+ adev->gfx.rlc.in_safe_mode = true;
+ }
+}
+
+/**
+ * amdgpu_gfx_rlc_exit_safe_mode - Set RLC out of safe mode
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Set RLC exit safe mode if RLC is enabled and have entered into safe mode.
+ */
+void amdgpu_gfx_rlc_exit_safe_mode(struct amdgpu_device *adev)
+{
+ if (!(adev->gfx.rlc.in_safe_mode))
+ return;
+
+ /* if RLC is not enabled, do nothing */
+ if (!adev->gfx.rlc.funcs->is_rlc_enabled(adev))
+ return;
+
+ if (adev->cg_flags &
+ (AMD_CG_SUPPORT_GFX_CGCG | AMD_CG_SUPPORT_GFX_MGCG |
+ AMD_CG_SUPPORT_GFX_3D_CGCG)) {
+ adev->gfx.rlc.funcs->unset_safe_mode(adev);
+ adev->gfx.rlc.in_safe_mode = false;
+ }
+}
+
+/**
+ * amdgpu_gfx_rlc_init_sr - Init save restore block
+ *
+ * @adev: amdgpu_device pointer
+ * @dws: the size of save restore block
+ *
+ * Allocate and setup value to save restore block of rlc.
+ * Returns 0 on succeess or negative error code if allocate failed.
+ */
+int amdgpu_gfx_rlc_init_sr(struct amdgpu_device *adev, u32 dws)
+{
+ const u32 *src_ptr;
+ volatile u32 *dst_ptr;
+ u32 i;
+ int r;
+
+ /* allocate save restore block */
+ r = amdgpu_bo_create_reserved(adev, dws * 4, PAGE_SIZE,
+ AMDGPU_GEM_DOMAIN_VRAM,
+ &adev->gfx.rlc.save_restore_obj,
+ &adev->gfx.rlc.save_restore_gpu_addr,
+ (void **)&adev->gfx.rlc.sr_ptr);
+ if (r) {
+ dev_warn(adev->dev, "(%d) create RLC sr bo failed\n", r);
+ amdgpu_gfx_rlc_fini(adev);
+ return r;
+ }
+
+ /* write the sr buffer */
+ src_ptr = adev->gfx.rlc.reg_list;
+ dst_ptr = adev->gfx.rlc.sr_ptr;
+ for (i = 0; i < adev->gfx.rlc.reg_list_size; i++)
+ dst_ptr[i] = cpu_to_le32(src_ptr[i]);
+ amdgpu_bo_kunmap(adev->gfx.rlc.save_restore_obj);
+ amdgpu_bo_unreserve(adev->gfx.rlc.save_restore_obj);
+
+ return 0;
+}
+
+/**
+ * amdgpu_gfx_rlc_init_csb - Init clear state block
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Allocate and setup value to clear state block of rlc.
+ * Returns 0 on succeess or negative error code if allocate failed.
+ */
+int amdgpu_gfx_rlc_init_csb(struct amdgpu_device *adev)
+{
+ volatile u32 *dst_ptr;
+ u32 dws;
+ int r;
+
+ /* allocate clear state block */
+ adev->gfx.rlc.clear_state_size = dws = adev->gfx.rlc.funcs->get_csb_size(adev);
+ r = amdgpu_bo_create_reserved(adev, dws * 4, PAGE_SIZE,
+ AMDGPU_GEM_DOMAIN_VRAM,
+ &adev->gfx.rlc.clear_state_obj,
+ &adev->gfx.rlc.clear_state_gpu_addr,
+ (void **)&adev->gfx.rlc.cs_ptr);
+ if (r) {
+ dev_err(adev->dev, "(%d) failed to create rlc csb bo\n", r);
+ amdgpu_gfx_rlc_fini(adev);
+ return r;
+ }
+
+ /* set up the cs buffer */
+ dst_ptr = adev->gfx.rlc.cs_ptr;
+ adev->gfx.rlc.funcs->get_csb_buffer(adev, dst_ptr);
+ amdgpu_bo_kunmap(adev->gfx.rlc.clear_state_obj);
+ amdgpu_bo_unpin(adev->gfx.rlc.clear_state_obj);
+ amdgpu_bo_unreserve(adev->gfx.rlc.clear_state_obj);
+
+ return 0;
+}
+
+/**
+ * amdgpu_gfx_rlc_init_cpt - Init cp table
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Allocate and setup value to cp table of rlc.
+ * Returns 0 on succeess or negative error code if allocate failed.
+ */
+int amdgpu_gfx_rlc_init_cpt(struct amdgpu_device *adev)
+{
+ int r;
+
+ r = amdgpu_bo_create_reserved(adev, adev->gfx.rlc.cp_table_size,
+ PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM,
+ &adev->gfx.rlc.cp_table_obj,
+ &adev->gfx.rlc.cp_table_gpu_addr,
+ (void **)&adev->gfx.rlc.cp_table_ptr);
+ if (r) {
+ dev_err(adev->dev, "(%d) failed to create cp table bo\n", r);
+ amdgpu_gfx_rlc_fini(adev);
+ return r;
+ }
+
+ /* set up the cp table */
+ amdgpu_gfx_rlc_setup_cp_table(adev);
+ amdgpu_bo_kunmap(adev->gfx.rlc.cp_table_obj);
+ amdgpu_bo_unreserve(adev->gfx.rlc.cp_table_obj);
+
+ return 0;
+}
+
+/**
+ * amdgpu_gfx_rlc_setup_cp_table - setup cp the buffer of cp table
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Write cp firmware data into cp table.
+ */
+void amdgpu_gfx_rlc_setup_cp_table(struct amdgpu_device *adev)
+{
+ const __le32 *fw_data;
+ volatile u32 *dst_ptr;
+ int me, i, max_me;
+ u32 bo_offset = 0;
+ u32 table_offset, table_size;
+
+ max_me = adev->gfx.rlc.funcs->get_cp_table_num(adev);
+
+ /* write the cp table buffer */
+ dst_ptr = adev->gfx.rlc.cp_table_ptr;
+ for (me = 0; me < max_me; me++) {
+ if (me == 0) {
+ const struct gfx_firmware_header_v1_0 *hdr =
+ (const struct gfx_firmware_header_v1_0 *)adev->gfx.ce_fw->data;
+ fw_data = (const __le32 *)
+ (adev->gfx.ce_fw->data +
+ le32_to_cpu(hdr->header.ucode_array_offset_bytes));
+ table_offset = le32_to_cpu(hdr->jt_offset);
+ table_size = le32_to_cpu(hdr->jt_size);
+ } else if (me == 1) {
+ const struct gfx_firmware_header_v1_0 *hdr =
+ (const struct gfx_firmware_header_v1_0 *)adev->gfx.pfp_fw->data;
+ fw_data = (const __le32 *)
+ (adev->gfx.pfp_fw->data +
+ le32_to_cpu(hdr->header.ucode_array_offset_bytes));
+ table_offset = le32_to_cpu(hdr->jt_offset);
+ table_size = le32_to_cpu(hdr->jt_size);
+ } else if (me == 2) {
+ const struct gfx_firmware_header_v1_0 *hdr =
+ (const struct gfx_firmware_header_v1_0 *)adev->gfx.me_fw->data;
+ fw_data = (const __le32 *)
+ (adev->gfx.me_fw->data +
+ le32_to_cpu(hdr->header.ucode_array_offset_bytes));
+ table_offset = le32_to_cpu(hdr->jt_offset);
+ table_size = le32_to_cpu(hdr->jt_size);
+ } else if (me == 3) {
+ const struct gfx_firmware_header_v1_0 *hdr =
+ (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data;
+ fw_data = (const __le32 *)
+ (adev->gfx.mec_fw->data +
+ le32_to_cpu(hdr->header.ucode_array_offset_bytes));
+ table_offset = le32_to_cpu(hdr->jt_offset);
+ table_size = le32_to_cpu(hdr->jt_size);
+ } else if (me == 4) {
+ const struct gfx_firmware_header_v1_0 *hdr =
+ (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec2_fw->data;
+ fw_data = (const __le32 *)
+ (adev->gfx.mec2_fw->data +
+ le32_to_cpu(hdr->header.ucode_array_offset_bytes));
+ table_offset = le32_to_cpu(hdr->jt_offset);
+ table_size = le32_to_cpu(hdr->jt_size);
+ }
+
+ for (i = 0; i < table_size; i ++) {
+ dst_ptr[bo_offset + i] =
+ cpu_to_le32(le32_to_cpu(fw_data[table_offset + i]));
+ }
+
+ bo_offset += table_size;
+ }
+}
+
+/**
+ * amdgpu_gfx_rlc_fini - Free BO which used for RLC
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Free three BO which is used for rlc_save_restore_block, rlc_clear_state_block
+ * and rlc_jump_table_block.
+ */
+void amdgpu_gfx_rlc_fini(struct amdgpu_device *adev)
+{
+ /* save restore block */
+ if (adev->gfx.rlc.save_restore_obj) {
+ amdgpu_bo_free_kernel(&adev->gfx.rlc.save_restore_obj,
+ &adev->gfx.rlc.save_restore_gpu_addr,
+ (void **)&adev->gfx.rlc.sr_ptr);
+ }
+
+ /* clear state block */
+ amdgpu_bo_free_kernel(&adev->gfx.rlc.clear_state_obj,
+ &adev->gfx.rlc.clear_state_gpu_addr,
+ (void **)&adev->gfx.rlc.cs_ptr);
+
+ /* jump table block */
+ amdgpu_bo_free_kernel(&adev->gfx.rlc.cp_table_obj,
+ &adev->gfx.rlc.cp_table_gpu_addr,
+ (void **)&adev->gfx.rlc.cp_table_ptr);
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.h
new file mode 100644
index 000000000000..49a8ab52113b
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2014 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 __AMDGPU_RLC_H__
+#define __AMDGPU_RLC_H__
+
+#include "clearstate_defs.h"
+
+struct amdgpu_rlc_funcs {
+ bool (*is_rlc_enabled)(struct amdgpu_device *adev);
+ void (*set_safe_mode)(struct amdgpu_device *adev);
+ void (*unset_safe_mode)(struct amdgpu_device *adev);
+ int (*init)(struct amdgpu_device *adev);
+ u32 (*get_csb_size)(struct amdgpu_device *adev);
+ void (*get_csb_buffer)(struct amdgpu_device *adev, volatile u32 *buffer);
+ int (*get_cp_table_num)(struct amdgpu_device *adev);
+ int (*resume)(struct amdgpu_device *adev);
+ void (*stop)(struct amdgpu_device *adev);
+ void (*reset)(struct amdgpu_device *adev);
+ void (*start)(struct amdgpu_device *adev);
+};
+
+struct amdgpu_rlc {
+ /* for power gating */
+ struct amdgpu_bo *save_restore_obj;
+ uint64_t save_restore_gpu_addr;
+ volatile uint32_t *sr_ptr;
+ const u32 *reg_list;
+ u32 reg_list_size;
+ /* for clear state */
+ struct amdgpu_bo *clear_state_obj;
+ uint64_t clear_state_gpu_addr;
+ volatile uint32_t *cs_ptr;
+ const struct cs_section_def *cs_data;
+ u32 clear_state_size;
+ /* for cp tables */
+ struct amdgpu_bo *cp_table_obj;
+ uint64_t cp_table_gpu_addr;
+ volatile uint32_t *cp_table_ptr;
+ u32 cp_table_size;
+
+ /* safe mode for updating CG/PG state */
+ bool in_safe_mode;
+ const struct amdgpu_rlc_funcs *funcs;
+
+ /* for firmware data */
+ u32 save_and_restore_offset;
+ u32 clear_state_descriptor_offset;
+ u32 avail_scratch_ram_locations;
+ u32 reg_restore_list_size;
+ u32 reg_list_format_start;
+ u32 reg_list_format_separate_start;
+ u32 starting_offsets_start;
+ u32 reg_list_format_size_bytes;
+ u32 reg_list_size_bytes;
+ u32 reg_list_format_direct_reg_list_length;
+ u32 save_restore_list_cntl_size_bytes;
+ u32 save_restore_list_gpm_size_bytes;
+ u32 save_restore_list_srm_size_bytes;
+
+ u32 *register_list_format;
+ u32 *register_restore;
+ u8 *save_restore_list_cntl;
+ u8 *save_restore_list_gpm;
+ u8 *save_restore_list_srm;
+
+ bool is_rlc_v2_1;
+};
+
+void amdgpu_gfx_rlc_enter_safe_mode(struct amdgpu_device *adev);
+void amdgpu_gfx_rlc_exit_safe_mode(struct amdgpu_device *adev);
+int amdgpu_gfx_rlc_init_sr(struct amdgpu_device *adev, u32 dws);
+int amdgpu_gfx_rlc_init_csb(struct amdgpu_device *adev);
+int amdgpu_gfx_rlc_init_cpt(struct amdgpu_device *adev);
+void amdgpu_gfx_rlc_setup_cp_table(struct amdgpu_device *adev);
+void amdgpu_gfx_rlc_fini(struct amdgpu_device *adev);
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c
index bc9244b429ef..115bb0c99b0f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c
@@ -28,17 +28,31 @@
* GPU SDMA IP block helpers function.
*/
-struct amdgpu_sdma_instance * amdgpu_get_sdma_instance(struct amdgpu_ring *ring)
+struct amdgpu_sdma_instance *amdgpu_sdma_get_instance_from_ring(struct amdgpu_ring *ring)
{
struct amdgpu_device *adev = ring->adev;
int i;
for (i = 0; i < adev->sdma.num_instances; i++)
- if (&adev->sdma.instance[i].ring == ring)
- break;
+ if (ring == &adev->sdma.instance[i].ring ||
+ ring == &adev->sdma.instance[i].page)
+ return &adev->sdma.instance[i];
- if (i < AMDGPU_MAX_SDMA_INSTANCES)
- return &adev->sdma.instance[i];
- else
- return NULL;
+ return NULL;
+}
+
+int amdgpu_sdma_get_index_from_ring(struct amdgpu_ring *ring, uint32_t *index)
+{
+ struct amdgpu_device *adev = ring->adev;
+ int i;
+
+ for (i = 0; i < adev->sdma.num_instances; i++) {
+ if (ring == &adev->sdma.instance[i].ring ||
+ ring == &adev->sdma.instance[i].page) {
+ *index = i;
+ return 0;
+ }
+ }
+
+ return -EINVAL;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h
index 500113ec65ca..16b1a6ae5ba6 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h
@@ -41,6 +41,7 @@ struct amdgpu_sdma_instance {
uint32_t feature_version;
struct amdgpu_ring ring;
+ struct amdgpu_ring page;
bool burst_nop;
};
@@ -50,6 +51,7 @@ struct amdgpu_sdma {
struct amdgpu_irq_src illegal_inst_irq;
int num_instances;
uint32_t srbm_soft_reset;
+ bool has_page_queue;
};
/*
@@ -92,6 +94,7 @@ struct amdgpu_buffer_funcs {
#define amdgpu_emit_fill_buffer(adev, ib, s, d, b) (adev)->mman.buffer_funcs->emit_fill_buffer((ib), (s), (d), (b))
struct amdgpu_sdma_instance *
-amdgpu_get_sdma_instance(struct amdgpu_ring *ring);
+amdgpu_sdma_get_instance_from_ring(struct amdgpu_ring *ring);
+int amdgpu_sdma_get_index_from_ring(struct amdgpu_ring *ring, uint32_t *index);
#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h
index e9bf70e2ac51..626abca770a0 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h
@@ -218,6 +218,7 @@ TRACE_EVENT(amdgpu_vm_grab_id,
TP_ARGS(vm, ring, job),
TP_STRUCT__entry(
__field(u32, pasid)
+ __string(ring, ring->name)
__field(u32, ring)
__field(u32, vmid)
__field(u32, vm_hub)
@@ -227,14 +228,14 @@ TRACE_EVENT(amdgpu_vm_grab_id,
TP_fast_assign(
__entry->pasid = vm->pasid;
- __entry->ring = ring->idx;
+ __assign_str(ring, ring->name)
__entry->vmid = job->vmid;
__entry->vm_hub = ring->funcs->vmhub,
__entry->pd_addr = job->vm_pd_addr;
__entry->needs_flush = job->vm_needs_flush;
),
- TP_printk("pasid=%d, ring=%u, id=%u, hub=%u, pd_addr=%010Lx needs_flush=%u",
- __entry->pasid, __entry->ring, __entry->vmid,
+ TP_printk("pasid=%d, ring=%s, id=%u, hub=%u, pd_addr=%010Lx needs_flush=%u",
+ __entry->pasid, __get_str(ring), __entry->vmid,
__entry->vm_hub, __entry->pd_addr, __entry->needs_flush)
);
@@ -366,20 +367,20 @@ TRACE_EVENT(amdgpu_vm_flush,
uint64_t pd_addr),
TP_ARGS(ring, vmid, pd_addr),
TP_STRUCT__entry(
- __field(u32, ring)
+ __string(ring, ring->name)
__field(u32, vmid)
__field(u32, vm_hub)
__field(u64, pd_addr)
),
TP_fast_assign(
- __entry->ring = ring->idx;
+ __assign_str(ring, ring->name)
__entry->vmid = vmid;
__entry->vm_hub = ring->funcs->vmhub;
__entry->pd_addr = pd_addr;
),
- TP_printk("ring=%u, id=%u, hub=%u, pd_addr=%010Lx",
- __entry->ring, __entry->vmid,
+ TP_printk("ring=%s, id=%u, hub=%u, pd_addr=%010Lx",
+ __get_str(ring), __entry->vmid,
__entry->vm_hub,__entry->pd_addr)
);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
index a44fc12ae1f9..c91ec3101d00 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
@@ -61,100 +61,6 @@ static int amdgpu_map_buffer(struct ttm_buffer_object *bo,
static int amdgpu_ttm_debugfs_init(struct amdgpu_device *adev);
static void amdgpu_ttm_debugfs_fini(struct amdgpu_device *adev);
-/*
- * Global memory.
- */
-
-/**
- * amdgpu_ttm_mem_global_init - Initialize and acquire reference to
- * memory object
- *
- * @ref: Object for initialization.
- *
- * This is called by drm_global_item_ref() when an object is being
- * initialized.
- */
-static int amdgpu_ttm_mem_global_init(struct drm_global_reference *ref)
-{
- return ttm_mem_global_init(ref->object);
-}
-
-/**
- * amdgpu_ttm_mem_global_release - Drop reference to a memory object
- *
- * @ref: Object being removed
- *
- * This is called by drm_global_item_unref() when an object is being
- * released.
- */
-static void amdgpu_ttm_mem_global_release(struct drm_global_reference *ref)
-{
- ttm_mem_global_release(ref->object);
-}
-
-/**
- * amdgpu_ttm_global_init - Initialize global TTM memory reference structures.
- *
- * @adev: AMDGPU device for which the global structures need to be registered.
- *
- * This is called as part of the AMDGPU ttm init from amdgpu_ttm_init()
- * during bring up.
- */
-static int amdgpu_ttm_global_init(struct amdgpu_device *adev)
-{
- struct drm_global_reference *global_ref;
- int r;
-
- /* ensure reference is false in case init fails */
- adev->mman.mem_global_referenced = false;
-
- global_ref = &adev->mman.mem_global_ref;
- global_ref->global_type = DRM_GLOBAL_TTM_MEM;
- global_ref->size = sizeof(struct ttm_mem_global);
- global_ref->init = &amdgpu_ttm_mem_global_init;
- global_ref->release = &amdgpu_ttm_mem_global_release;
- r = drm_global_item_ref(global_ref);
- if (r) {
- DRM_ERROR("Failed setting up TTM memory accounting "
- "subsystem.\n");
- goto error_mem;
- }
-
- adev->mman.bo_global_ref.mem_glob =
- adev->mman.mem_global_ref.object;
- global_ref = &adev->mman.bo_global_ref.ref;
- global_ref->global_type = DRM_GLOBAL_TTM_BO;
- global_ref->size = sizeof(struct ttm_bo_global);
- global_ref->init = &ttm_bo_global_init;
- global_ref->release = &ttm_bo_global_release;
- r = drm_global_item_ref(global_ref);
- if (r) {
- DRM_ERROR("Failed setting up TTM BO subsystem.\n");
- goto error_bo;
- }
-
- mutex_init(&adev->mman.gtt_window_lock);
-
- adev->mman.mem_global_referenced = true;
-
- return 0;
-
-error_bo:
- drm_global_item_unref(&adev->mman.mem_global_ref);
-error_mem:
- return r;
-}
-
-static void amdgpu_ttm_global_fini(struct amdgpu_device *adev)
-{
- if (adev->mman.mem_global_referenced) {
- mutex_destroy(&adev->mman.gtt_window_lock);
- drm_global_item_unref(&adev->mman.bo_global_ref.ref);
- drm_global_item_unref(&adev->mman.mem_global_ref);
- adev->mman.mem_global_referenced = false;
- }
-}
-
static int amdgpu_invalidate_caches(struct ttm_bo_device *bdev, uint32_t flags)
{
return 0;
@@ -1758,14 +1664,10 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
int r;
u64 vis_vram_limit;
- /* initialize global references for vram/gtt */
- r = amdgpu_ttm_global_init(adev);
- if (r) {
- return r;
- }
+ mutex_init(&adev->mman.gtt_window_lock);
+
/* No others user of address space so set it to 0 */
r = ttm_bo_device_init(&adev->mman.bdev,
- adev->mman.bo_global_ref.ref.object,
&amdgpu_bo_driver,
adev->ddev->anon_inode->i_mapping,
DRM_FILE_PAGE_OFFSET,
@@ -1922,7 +1824,6 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev)
ttm_bo_clean_mm(&adev->mman.bdev, AMDGPU_PL_GWS);
ttm_bo_clean_mm(&adev->mman.bdev, AMDGPU_PL_OA);
ttm_bo_device_release(&adev->mman.bdev);
- amdgpu_ttm_global_fini(adev);
adev->mman.initialized = false;
DRM_INFO("amdgpu: ttm finalized\n");
}
@@ -2069,7 +1970,7 @@ int amdgpu_copy_buffer(struct amdgpu_ring *ring, uint64_t src_offset,
unsigned i;
int r;
- if (direct_submit && !ring->ready) {
+ if (direct_submit && !ring->sched.ready) {
DRM_ERROR("Trying to move memory with ring turned off.\n");
return -EINVAL;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
index fe8f276e9811..b5b2d101f7db 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
@@ -39,8 +39,6 @@
#define AMDGPU_GTT_NUM_TRANSFER_WINDOWS 2
struct amdgpu_mman {
- struct ttm_bo_global_ref bo_global_ref;
- struct drm_global_reference mem_global_ref;
struct ttm_bo_device bdev;
bool mem_global_referenced;
bool initialized;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h
index aa6641b944a0..7ac25a1c7853 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h
@@ -58,6 +58,17 @@ struct psp_firmware_header_v1_0 {
};
/* version_major=1, version_minor=0 */
+struct ta_firmware_header_v1_0 {
+ struct common_firmware_header header;
+ uint32_t ta_xgmi_ucode_version;
+ uint32_t ta_xgmi_offset_bytes;
+ uint32_t ta_xgmi_size_bytes;
+ uint32_t ta_ras_ucode_version;
+ uint32_t ta_ras_offset_bytes;
+ uint32_t ta_ras_size_bytes;
+};
+
+/* version_major=1, version_minor=0 */
struct gfx_firmware_header_v1_0 {
struct common_firmware_header header;
uint32_t ucode_feature_version;
@@ -170,6 +181,7 @@ union amdgpu_firmware_header {
struct mc_firmware_header_v1_0 mc;
struct smc_firmware_header_v1_0 smc;
struct psp_firmware_header_v1_0 psp;
+ struct ta_firmware_header_v1_0 ta;
struct gfx_firmware_header_v1_0 gfx;
struct rlc_firmware_header_v1_0 rlc;
struct rlc_firmware_header_v2_0 rlc_v2_0;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
index e5a6db6beab7..69896f451e8a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
@@ -1243,30 +1243,20 @@ int amdgpu_uvd_ring_test_ib(struct amdgpu_ring *ring, long timeout)
{
struct dma_fence *fence;
long r;
- uint32_t ip_instance = ring->me;
r = amdgpu_uvd_get_create_msg(ring, 1, NULL);
- if (r) {
- DRM_ERROR("amdgpu: (%d)failed to get create msg (%ld).\n", ip_instance, r);
+ if (r)
goto error;
- }
r = amdgpu_uvd_get_destroy_msg(ring, 1, true, &fence);
- if (r) {
- DRM_ERROR("amdgpu: (%d)failed to get destroy ib (%ld).\n", ip_instance, r);
+ if (r)
goto error;
- }
r = dma_fence_wait_timeout(fence, false, timeout);
- if (r == 0) {
- DRM_ERROR("amdgpu: (%d)IB test timed out.\n", ip_instance);
+ if (r == 0)
r = -ETIMEDOUT;
- } else if (r < 0) {
- DRM_ERROR("amdgpu: (%d)fence wait failed (%ld).\n", ip_instance, r);
- } else {
- DRM_DEBUG("ib test on (%d)ring %d succeeded\n", ip_instance, ring->idx);
+ else if (r > 0)
r = 0;
- }
dma_fence_put(fence);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
index 5f3f54073818..98a1b2ce2b9d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
@@ -1032,8 +1032,10 @@ out:
* @ib: the IB to execute
*
*/
-void amdgpu_vce_ring_emit_ib(struct amdgpu_ring *ring, struct amdgpu_ib *ib,
- unsigned vmid, bool ctx_switch)
+void amdgpu_vce_ring_emit_ib(struct amdgpu_ring *ring,
+ struct amdgpu_job *job,
+ struct amdgpu_ib *ib,
+ bool ctx_switch)
{
amdgpu_ring_write(ring, VCE_CMD_IB);
amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr));
@@ -1079,11 +1081,9 @@ int amdgpu_vce_ring_test_ring(struct amdgpu_ring *ring)
return 0;
r = amdgpu_ring_alloc(ring, 16);
- if (r) {
- DRM_ERROR("amdgpu: vce failed to lock ring %d (%d).\n",
- ring->idx, r);
+ if (r)
return r;
- }
+
amdgpu_ring_write(ring, VCE_CMD_END);
amdgpu_ring_commit(ring);
@@ -1093,14 +1093,8 @@ int amdgpu_vce_ring_test_ring(struct amdgpu_ring *ring)
DRM_UDELAY(1);
}
- if (i < timeout) {
- DRM_DEBUG("ring test on %d succeeded in %d usecs\n",
- ring->idx, i);
- } else {
- DRM_ERROR("amdgpu: ring %d test failed\n",
- ring->idx);
+ if (i >= timeout)
r = -ETIMEDOUT;
- }
return r;
}
@@ -1121,27 +1115,19 @@ int amdgpu_vce_ring_test_ib(struct amdgpu_ring *ring, long timeout)
return 0;
r = amdgpu_vce_get_create_msg(ring, 1, NULL);
- if (r) {
- DRM_ERROR("amdgpu: failed to get create msg (%ld).\n", r);
+ if (r)
goto error;
- }
r = amdgpu_vce_get_destroy_msg(ring, 1, true, &fence);
- if (r) {
- DRM_ERROR("amdgpu: failed to get destroy ib (%ld).\n", r);
+ if (r)
goto error;
- }
r = dma_fence_wait_timeout(fence, false, timeout);
- if (r == 0) {
- DRM_ERROR("amdgpu: IB test timed out.\n");
+ if (r == 0)
r = -ETIMEDOUT;
- } else if (r < 0) {
- DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r);
- } else {
- DRM_DEBUG("ib test on ring %d succeeded\n", ring->idx);
+ else if (r > 0)
r = 0;
- }
+
error:
dma_fence_put(fence);
return r;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h
index a1f209eed4c4..50293652af14 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h
@@ -65,8 +65,8 @@ int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle,
void amdgpu_vce_free_handles(struct amdgpu_device *adev, struct drm_file *filp);
int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx);
int amdgpu_vce_ring_parse_cs_vm(struct amdgpu_cs_parser *p, uint32_t ib_idx);
-void amdgpu_vce_ring_emit_ib(struct amdgpu_ring *ring, struct amdgpu_ib *ib,
- unsigned vmid, bool ctx_switch);
+void amdgpu_vce_ring_emit_ib(struct amdgpu_ring *ring, struct amdgpu_job *job,
+ struct amdgpu_ib *ib, bool ctx_switch);
void amdgpu_vce_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq,
unsigned flags);
int amdgpu_vce_ring_test_ring(struct amdgpu_ring *ring);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c
index 27da13df2f11..e2e42e3fbcf3 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c
@@ -425,11 +425,9 @@ int amdgpu_vcn_dec_ring_test_ring(struct amdgpu_ring *ring)
WREG32(SOC15_REG_OFFSET(UVD, 0, mmUVD_SCRATCH9), 0xCAFEDEAD);
r = amdgpu_ring_alloc(ring, 3);
- if (r) {
- DRM_ERROR("amdgpu: cp failed to lock ring %d (%d).\n",
- ring->idx, r);
+ if (r)
return r;
- }
+
amdgpu_ring_write(ring,
PACKET0(SOC15_REG_OFFSET(UVD, 0, mmUVD_SCRATCH9), 0));
amdgpu_ring_write(ring, 0xDEADBEEF);
@@ -441,14 +439,9 @@ int amdgpu_vcn_dec_ring_test_ring(struct amdgpu_ring *ring)
DRM_UDELAY(1);
}
- if (i < adev->usec_timeout) {
- DRM_DEBUG("ring test on %d succeeded in %d usecs\n",
- ring->idx, i);
- } else {
- DRM_ERROR("amdgpu: ring %d test failed (0x%08X)\n",
- ring->idx, tmp);
- r = -EINVAL;
- }
+ if (i >= adev->usec_timeout)
+ r = -ETIMEDOUT;
+
return r;
}
@@ -570,30 +563,20 @@ int amdgpu_vcn_dec_ring_test_ib(struct amdgpu_ring *ring, long timeout)
long r;
r = amdgpu_vcn_dec_get_create_msg(ring, 1, NULL);
- if (r) {
- DRM_ERROR("amdgpu: failed to get create msg (%ld).\n", r);
+ if (r)
goto error;
- }
r = amdgpu_vcn_dec_get_destroy_msg(ring, 1, &fence);
- if (r) {
- DRM_ERROR("amdgpu: failed to get destroy ib (%ld).\n", r);
+ if (r)
goto error;
- }
r = dma_fence_wait_timeout(fence, false, timeout);
- if (r == 0) {
- DRM_ERROR("amdgpu: IB test timed out.\n");
+ if (r == 0)
r = -ETIMEDOUT;
- } else if (r < 0) {
- DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r);
- } else {
- DRM_DEBUG("ib test on ring %d succeeded\n", ring->idx);
+ else if (r > 0)
r = 0;
- }
dma_fence_put(fence);
-
error:
return r;
}
@@ -606,11 +589,9 @@ int amdgpu_vcn_enc_ring_test_ring(struct amdgpu_ring *ring)
int r;
r = amdgpu_ring_alloc(ring, 16);
- if (r) {
- DRM_ERROR("amdgpu: vcn enc failed to lock ring %d (%d).\n",
- ring->idx, r);
+ if (r)
return r;
- }
+
amdgpu_ring_write(ring, VCN_ENC_CMD_END);
amdgpu_ring_commit(ring);
@@ -620,14 +601,8 @@ int amdgpu_vcn_enc_ring_test_ring(struct amdgpu_ring *ring)
DRM_UDELAY(1);
}
- if (i < adev->usec_timeout) {
- DRM_DEBUG("ring test on %d succeeded in %d usecs\n",
- ring->idx, i);
- } else {
- DRM_ERROR("amdgpu: ring %d test failed\n",
- ring->idx);
+ if (i >= adev->usec_timeout)
r = -ETIMEDOUT;
- }
return r;
}
@@ -742,27 +717,19 @@ int amdgpu_vcn_enc_ring_test_ib(struct amdgpu_ring *ring, long timeout)
long r;
r = amdgpu_vcn_enc_get_create_msg(ring, 1, NULL);
- if (r) {
- DRM_ERROR("amdgpu: failed to get create msg (%ld).\n", r);
+ if (r)
goto error;
- }
r = amdgpu_vcn_enc_get_destroy_msg(ring, 1, &fence);
- if (r) {
- DRM_ERROR("amdgpu: failed to get destroy ib (%ld).\n", r);
+ if (r)
goto error;
- }
r = dma_fence_wait_timeout(fence, false, timeout);
- if (r == 0) {
- DRM_ERROR("amdgpu: IB test timed out.\n");
+ if (r == 0)
r = -ETIMEDOUT;
- } else if (r < 0) {
- DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r);
- } else {
- DRM_DEBUG("ib test on ring %d succeeded\n", ring->idx);
+ else if (r > 0)
r = 0;
- }
+
error:
dma_fence_put(fence);
return r;
@@ -778,11 +745,8 @@ int amdgpu_vcn_jpeg_ring_test_ring(struct amdgpu_ring *ring)
WREG32(SOC15_REG_OFFSET(UVD, 0, mmUVD_SCRATCH9), 0xCAFEDEAD);
r = amdgpu_ring_alloc(ring, 3);
- if (r) {
- DRM_ERROR("amdgpu: cp failed to lock ring %d (%d).\n",
- ring->idx, r);
+ if (r)
return r;
- }
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_SCRATCH9), 0, 0, 0));
@@ -796,14 +760,8 @@ int amdgpu_vcn_jpeg_ring_test_ring(struct amdgpu_ring *ring)
DRM_UDELAY(1);
}
- if (i < adev->usec_timeout) {
- DRM_DEBUG("ring test on %d succeeded in %d usecs\n",
- ring->idx, i);
- } else {
- DRM_ERROR("amdgpu: ring %d test failed (0x%08X)\n",
- ring->idx, tmp);
- r = -EINVAL;
- }
+ if (i >= adev->usec_timeout)
+ r = -ETIMEDOUT;
return r;
}
@@ -856,21 +814,18 @@ int amdgpu_vcn_jpeg_ring_test_ib(struct amdgpu_ring *ring, long timeout)
long r = 0;
r = amdgpu_vcn_jpeg_set_reg(ring, 1, &fence);
- if (r) {
- DRM_ERROR("amdgpu: failed to set jpeg register (%ld).\n", r);
+ if (r)
goto error;
- }
r = dma_fence_wait_timeout(fence, false, timeout);
if (r == 0) {
- DRM_ERROR("amdgpu: IB test timed out.\n");
r = -ETIMEDOUT;
goto error;
} else if (r < 0) {
- DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r);
goto error;
- } else
+ } else {
r = 0;
+ }
for (i = 0; i < adev->usec_timeout; i++) {
tmp = RREG32(SOC15_REG_OFFSET(UVD, 0, mmUVD_SCRATCH9));
@@ -879,15 +834,10 @@ int amdgpu_vcn_jpeg_ring_test_ib(struct amdgpu_ring *ring, long timeout)
DRM_UDELAY(1);
}
- if (i < adev->usec_timeout)
- DRM_DEBUG("ib test on ring %d succeeded\n", ring->idx);
- else {
- DRM_ERROR("ib test failed (0x%08X)\n", tmp);
- r = -EINVAL;
- }
+ if (i >= adev->usec_timeout)
+ r = -ETIMEDOUT;
dma_fence_put(fence);
-
error:
return r;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c
index f2f358aa0597..cfee74732edb 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c
@@ -23,16 +23,6 @@
#include "amdgpu.h"
-uint64_t amdgpu_csa_vaddr(struct amdgpu_device *adev)
-{
- uint64_t addr = adev->vm_manager.max_pfn << AMDGPU_GPU_PAGE_SHIFT;
-
- addr -= AMDGPU_VA_RESERVED_SIZE;
- addr = amdgpu_gmc_sign_extend(addr);
-
- return addr;
-}
-
bool amdgpu_virt_mmio_blocked(struct amdgpu_device *adev)
{
/* By now all MMIO pages except mailbox are blocked */
@@ -41,88 +31,6 @@ bool amdgpu_virt_mmio_blocked(struct amdgpu_device *adev)
return RREG32_NO_KIQ(0xc040) == 0xffffffff;
}
-int amdgpu_allocate_static_csa(struct amdgpu_device *adev)
-{
- int r;
- void *ptr;
-
- r = amdgpu_bo_create_kernel(adev, AMDGPU_CSA_SIZE, PAGE_SIZE,
- AMDGPU_GEM_DOMAIN_VRAM, &adev->virt.csa_obj,
- &adev->virt.csa_vmid0_addr, &ptr);
- if (r)
- return r;
-
- memset(ptr, 0, AMDGPU_CSA_SIZE);
- return 0;
-}
-
-void amdgpu_free_static_csa(struct amdgpu_device *adev) {
- amdgpu_bo_free_kernel(&adev->virt.csa_obj,
- &adev->virt.csa_vmid0_addr,
- NULL);
-}
-
-/*
- * amdgpu_map_static_csa should be called during amdgpu_vm_init
- * it maps virtual address amdgpu_csa_vaddr() to this VM, and each command
- * submission of GFX should use this virtual address within META_DATA init
- * package to support SRIOV gfx preemption.
- */
-int amdgpu_map_static_csa(struct amdgpu_device *adev, struct amdgpu_vm *vm,
- struct amdgpu_bo_va **bo_va)
-{
- uint64_t csa_addr = amdgpu_csa_vaddr(adev) & AMDGPU_GMC_HOLE_MASK;
- struct ww_acquire_ctx ticket;
- struct list_head list;
- struct amdgpu_bo_list_entry pd;
- struct ttm_validate_buffer csa_tv;
- int r;
-
- INIT_LIST_HEAD(&list);
- INIT_LIST_HEAD(&csa_tv.head);
- csa_tv.bo = &adev->virt.csa_obj->tbo;
- csa_tv.shared = true;
-
- list_add(&csa_tv.head, &list);
- amdgpu_vm_get_pd_bo(vm, &list, &pd);
-
- r = ttm_eu_reserve_buffers(&ticket, &list, true, NULL);
- if (r) {
- DRM_ERROR("failed to reserve CSA,PD BOs: err=%d\n", r);
- return r;
- }
-
- *bo_va = amdgpu_vm_bo_add(adev, vm, adev->virt.csa_obj);
- if (!*bo_va) {
- ttm_eu_backoff_reservation(&ticket, &list);
- DRM_ERROR("failed to create bo_va for static CSA\n");
- return -ENOMEM;
- }
-
- r = amdgpu_vm_alloc_pts(adev, (*bo_va)->base.vm, csa_addr,
- AMDGPU_CSA_SIZE);
- if (r) {
- DRM_ERROR("failed to allocate pts for static CSA, err=%d\n", r);
- amdgpu_vm_bo_rmv(adev, *bo_va);
- ttm_eu_backoff_reservation(&ticket, &list);
- return r;
- }
-
- r = amdgpu_vm_bo_map(adev, *bo_va, csa_addr, 0, AMDGPU_CSA_SIZE,
- AMDGPU_PTE_READABLE | AMDGPU_PTE_WRITEABLE |
- AMDGPU_PTE_EXECUTABLE);
-
- if (r) {
- DRM_ERROR("failed to do bo_map on static CSA, err=%d\n", r);
- amdgpu_vm_bo_rmv(adev, *bo_va);
- ttm_eu_backoff_reservation(&ticket, &list);
- return r;
- }
-
- ttm_eu_backoff_reservation(&ticket, &list);
- return 0;
-}
-
void amdgpu_virt_init_setting(struct amdgpu_device *adev)
{
/* enable virtual display */
@@ -162,9 +70,7 @@ uint32_t amdgpu_virt_kiq_rreg(struct amdgpu_device *adev, uint32_t reg)
if (r < 1 && (adev->in_gpu_reset || in_interrupt()))
goto failed_kiq_read;
- if (in_interrupt())
- might_sleep();
-
+ might_sleep();
while (r < 1 && cnt++ < MAX_KIQ_REG_TRY) {
msleep(MAX_KIQ_REG_BAILOUT_INTERVAL);
r = amdgpu_fence_wait_polling(ring, seq, MAX_KIQ_REG_WAIT);
@@ -210,9 +116,7 @@ void amdgpu_virt_kiq_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v)
if (r < 1 && (adev->in_gpu_reset || in_interrupt()))
goto failed_kiq_write;
- if (in_interrupt())
- might_sleep();
-
+ might_sleep();
while (r < 1 && cnt++ < MAX_KIQ_REG_TRY) {
msleep(MAX_KIQ_REG_BAILOUT_INTERVAL);
@@ -228,6 +132,46 @@ failed_kiq_write:
pr_err("failed to write reg:%x\n", reg);
}
+void amdgpu_virt_kiq_reg_write_reg_wait(struct amdgpu_device *adev,
+ uint32_t reg0, uint32_t reg1,
+ uint32_t ref, uint32_t mask)
+{
+ struct amdgpu_kiq *kiq = &adev->gfx.kiq;
+ struct amdgpu_ring *ring = &kiq->ring;
+ signed long r, cnt = 0;
+ unsigned long flags;
+ uint32_t seq;
+
+ spin_lock_irqsave(&kiq->ring_lock, flags);
+ amdgpu_ring_alloc(ring, 32);
+ amdgpu_ring_emit_reg_write_reg_wait(ring, reg0, reg1,
+ ref, mask);
+ amdgpu_fence_emit_polling(ring, &seq);
+ amdgpu_ring_commit(ring);
+ spin_unlock_irqrestore(&kiq->ring_lock, flags);
+
+ r = amdgpu_fence_wait_polling(ring, seq, MAX_KIQ_REG_WAIT);
+
+ /* don't wait anymore for IRQ context */
+ if (r < 1 && in_interrupt())
+ goto failed_kiq;
+
+ might_sleep();
+ while (r < 1 && cnt++ < MAX_KIQ_REG_TRY) {
+
+ msleep(MAX_KIQ_REG_BAILOUT_INTERVAL);
+ r = amdgpu_fence_wait_polling(ring, seq, MAX_KIQ_REG_WAIT);
+ }
+
+ if (cnt > MAX_KIQ_REG_TRY)
+ goto failed_kiq;
+
+ return;
+
+failed_kiq:
+ pr_err("failed to write reg %x wait reg %x\n", reg0, reg1);
+}
+
/**
* amdgpu_virt_request_full_gpu() - request full gpu access
* @amdgpu: amdgpu device.
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h
index 880ac113a3a9..0728fbc9a692 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h
@@ -238,7 +238,6 @@ typedef struct amdgim_vf2pf_info_v2 amdgim_vf2pf_info ;
struct amdgpu_virt {
uint32_t caps;
struct amdgpu_bo *csa_obj;
- uint64_t csa_vmid0_addr;
bool chained_ib_support;
uint32_t reg_val_offs;
struct amdgpu_irq_src ack_irq;
@@ -251,8 +250,6 @@ struct amdgpu_virt {
uint32_t gim_feature;
};
-#define AMDGPU_CSA_SIZE (8 * 1024)
-
#define amdgpu_sriov_enabled(adev) \
((adev)->virt.caps & AMDGPU_SRIOV_CAPS_ENABLE_IOV)
@@ -277,17 +274,13 @@ static inline bool is_virtual_machine(void)
#endif
}
-struct amdgpu_vm;
-
-uint64_t amdgpu_csa_vaddr(struct amdgpu_device *adev);
bool amdgpu_virt_mmio_blocked(struct amdgpu_device *adev);
-int amdgpu_allocate_static_csa(struct amdgpu_device *adev);
-int amdgpu_map_static_csa(struct amdgpu_device *adev, struct amdgpu_vm *vm,
- struct amdgpu_bo_va **bo_va);
-void amdgpu_free_static_csa(struct amdgpu_device *adev);
void amdgpu_virt_init_setting(struct amdgpu_device *adev);
uint32_t amdgpu_virt_kiq_rreg(struct amdgpu_device *adev, uint32_t reg);
void amdgpu_virt_kiq_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v);
+void amdgpu_virt_kiq_reg_write_reg_wait(struct amdgpu_device *adev,
+ uint32_t reg0, uint32_t rreg1,
+ uint32_t ref, uint32_t mask);
int amdgpu_virt_request_full_gpu(struct amdgpu_device *adev, bool init);
int amdgpu_virt_release_full_gpu(struct amdgpu_device *adev, bool init);
int amdgpu_virt_reset_gpu(struct amdgpu_device *adev);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
index 352b30409060..58a2363040dd 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
@@ -773,7 +773,7 @@ static int amdgpu_vm_clear_bo(struct amdgpu_device *adev,
ring = container_of(vm->entity.rq->sched, struct amdgpu_ring, sched);
- r = reservation_object_reserve_shared(bo->tbo.resv);
+ r = reservation_object_reserve_shared(bo->tbo.resv, 1);
if (r)
return r;
@@ -1632,13 +1632,6 @@ static int amdgpu_vm_update_ptes(struct amdgpu_pte_update_params *params,
continue;
}
- /* First check if the entry is already handled */
- if (cursor.pfn < frag_start) {
- cursor.entry->huge = true;
- amdgpu_vm_pt_next(adev, &cursor);
- continue;
- }
-
/* If it isn't already handled it can't be a huge page */
if (cursor.entry->huge) {
/* Add the entry to the relocated list to update it. */
@@ -1701,8 +1694,17 @@ static int amdgpu_vm_update_ptes(struct amdgpu_pte_update_params *params,
}
} while (frag_start < entry_end);
- if (frag >= shift)
+ if (amdgpu_vm_pt_descendant(adev, &cursor)) {
+ /* Mark all child entries as huge */
+ while (cursor.pfn < frag_start) {
+ cursor.entry->huge = true;
+ amdgpu_vm_pt_next(adev, &cursor);
+ }
+
+ } else if (frag >= shift) {
+ /* or just move on to the next on the same level. */
amdgpu_vm_pt_next(adev, &cursor);
+ }
}
return 0;
@@ -1840,7 +1842,7 @@ static int amdgpu_vm_bo_update_mapping(struct amdgpu_device *adev,
if (r)
goto error_free;
- r = reservation_object_reserve_shared(vm->root.base.bo->tbo.resv);
+ r = reservation_object_reserve_shared(vm->root.base.bo->tbo.resv, 1);
if (r)
goto error_free;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c
index 897afbb348c1..909216a9b447 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c
@@ -63,7 +63,7 @@ static struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev)
int amdgpu_xgmi_add_device(struct amdgpu_device *adev)
{
- struct psp_xgmi_topology_info tmp_topology[AMDGPU_MAX_XGMI_DEVICE_PER_HIVE];
+ struct psp_xgmi_topology_info *tmp_topology;
struct amdgpu_hive_info *hive;
struct amdgpu_xgmi *entry;
struct amdgpu_device *tmp_adev;
@@ -73,10 +73,12 @@ int amdgpu_xgmi_add_device(struct amdgpu_device *adev)
if ((adev->asic_type < CHIP_VEGA20) ||
(adev->flags & AMD_IS_APU) )
return 0;
- adev->gmc.xgmi.device_id = psp_xgmi_get_device_id(&adev->psp);
+ adev->gmc.xgmi.node_id = psp_xgmi_get_node_id(&adev->psp);
adev->gmc.xgmi.hive_id = psp_xgmi_get_hive_id(&adev->psp);
- memset(&tmp_topology[0], 0, sizeof(tmp_topology));
+ tmp_topology = kzalloc(sizeof(struct psp_xgmi_topology_info), GFP_KERNEL);
+ if (!tmp_topology)
+ return -ENOMEM;
mutex_lock(&xgmi_mutex);
hive = amdgpu_get_xgmi_hive(adev);
if (!hive)
@@ -84,23 +86,28 @@ int amdgpu_xgmi_add_device(struct amdgpu_device *adev)
list_add_tail(&adev->gmc.xgmi.head, &hive->device_list);
list_for_each_entry(entry, &hive->device_list, head)
- tmp_topology[count++].device_id = entry->device_id;
-
- ret = psp_xgmi_get_topology_info(&adev->psp, count, tmp_topology);
- if (ret) {
- dev_err(adev->dev,
- "XGMI: Get topology failure on device %llx, hive %llx, ret %d",
- adev->gmc.xgmi.device_id,
- adev->gmc.xgmi.hive_id, ret);
- goto exit;
+ tmp_topology->nodes[count++].node_id = entry->node_id;
+
+ /* Each psp need to get the latest topology */
+ list_for_each_entry(tmp_adev, &hive->device_list, gmc.xgmi.head) {
+ ret = psp_xgmi_get_topology_info(&tmp_adev->psp, count, tmp_topology);
+ if (ret) {
+ dev_err(tmp_adev->dev,
+ "XGMI: Get topology failure on device %llx, hive %llx, ret %d",
+ tmp_adev->gmc.xgmi.node_id,
+ tmp_adev->gmc.xgmi.hive_id, ret);
+ /* To do : continue with some node failed or disable the whole hive */
+ break;
+ }
}
+
/* Each psp need to set the latest topology */
list_for_each_entry(tmp_adev, &hive->device_list, gmc.xgmi.head) {
ret = psp_xgmi_set_topology_info(&tmp_adev->psp, count, tmp_topology);
if (ret) {
dev_err(tmp_adev->dev,
"XGMI: Set topology failure on device %llx, hive %llx, ret %d",
- tmp_adev->gmc.xgmi.device_id,
+ tmp_adev->gmc.xgmi.node_id,
tmp_adev->gmc.xgmi.hive_id, ret);
/* To do : continue with some node failed or disable the whole hive */
break;
@@ -113,7 +120,6 @@ int amdgpu_xgmi_add_device(struct amdgpu_device *adev)
exit:
mutex_unlock(&xgmi_mutex);
+ kfree(tmp_topology);
return ret;
}
-
-
diff --git a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c
index 79220a91abe3..86e14c754dd4 100644
--- a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c
+++ b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c
@@ -743,19 +743,19 @@ static int ci_enable_didt(struct amdgpu_device *adev, bool enable)
if (pi->caps_sq_ramping || pi->caps_db_ramping ||
pi->caps_td_ramping || pi->caps_tcp_ramping) {
- adev->gfx.rlc.funcs->enter_safe_mode(adev);
+ amdgpu_gfx_rlc_enter_safe_mode(adev);
if (enable) {
ret = ci_program_pt_config_registers(adev, didt_config_ci);
if (ret) {
- adev->gfx.rlc.funcs->exit_safe_mode(adev);
+ amdgpu_gfx_rlc_exit_safe_mode(adev);
return ret;
}
}
ci_do_enable_didt(adev, enable);
- adev->gfx.rlc.funcs->exit_safe_mode(adev);
+ amdgpu_gfx_rlc_exit_safe_mode(adev);
}
return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c
index b918c8886b75..45795191de1f 100644
--- a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c
+++ b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c
@@ -198,7 +198,7 @@ static void cik_sdma_ring_set_wptr(struct amdgpu_ring *ring)
static void cik_sdma_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count)
{
- struct amdgpu_sdma_instance *sdma = amdgpu_get_sdma_instance(ring);
+ struct amdgpu_sdma_instance *sdma = amdgpu_sdma_get_instance_from_ring(ring);
int i;
for (i = 0; i < count; i++)
@@ -218,9 +218,11 @@ static void cik_sdma_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count)
* Schedule an IB in the DMA ring (CIK).
*/
static void cik_sdma_ring_emit_ib(struct amdgpu_ring *ring,
+ struct amdgpu_job *job,
struct amdgpu_ib *ib,
- unsigned vmid, bool ctx_switch)
+ bool ctx_switch)
{
+ unsigned vmid = AMDGPU_JOB_GET_VMID(job);
u32 extra_bits = vmid & 0xf;
/* IB packet must end on a 8 DW boundary */
@@ -316,8 +318,8 @@ static void cik_sdma_gfx_stop(struct amdgpu_device *adev)
WREG32(mmSDMA0_GFX_RB_CNTL + sdma_offsets[i], rb_cntl);
WREG32(mmSDMA0_GFX_IB_CNTL + sdma_offsets[i], 0);
}
- sdma0->ready = false;
- sdma1->ready = false;
+ sdma0->sched.ready = false;
+ sdma1->sched.ready = false;
}
/**
@@ -494,18 +496,16 @@ static int cik_sdma_gfx_resume(struct amdgpu_device *adev)
/* enable DMA IBs */
WREG32(mmSDMA0_GFX_IB_CNTL + sdma_offsets[i], ib_cntl);
- ring->ready = true;
+ ring->sched.ready = true;
}
cik_sdma_enable(adev, true);
for (i = 0; i < adev->sdma.num_instances; i++) {
ring = &adev->sdma.instance[i].ring;
- r = amdgpu_ring_test_ring(ring);
- if (r) {
- ring->ready = false;
+ r = amdgpu_ring_test_helper(ring);
+ if (r)
return r;
- }
if (adev->mman.buffer_funcs_ring == ring)
amdgpu_ttm_set_buffer_funcs_status(adev, true);
@@ -618,21 +618,17 @@ static int cik_sdma_ring_test_ring(struct amdgpu_ring *ring)
u64 gpu_addr;
r = amdgpu_device_wb_get(adev, &index);
- if (r) {
- dev_err(adev->dev, "(%d) failed to allocate wb slot\n", r);
+ if (r)
return r;
- }
gpu_addr = adev->wb.gpu_addr + (index * 4);
tmp = 0xCAFEDEAD;
adev->wb.wb[index] = cpu_to_le32(tmp);
r = amdgpu_ring_alloc(ring, 5);
- if (r) {
- DRM_ERROR("amdgpu: dma failed to lock ring %d (%d).\n", ring->idx, r);
- amdgpu_device_wb_free(adev, index);
- return r;
- }
+ if (r)
+ goto error_free_wb;
+
amdgpu_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_WRITE, SDMA_WRITE_SUB_OPCODE_LINEAR, 0));
amdgpu_ring_write(ring, lower_32_bits(gpu_addr));
amdgpu_ring_write(ring, upper_32_bits(gpu_addr));
@@ -647,15 +643,11 @@ static int cik_sdma_ring_test_ring(struct amdgpu_ring *ring)
DRM_UDELAY(1);
}
- if (i < adev->usec_timeout) {
- DRM_DEBUG("ring test on %d succeeded in %d usecs\n", ring->idx, i);
- } else {
- DRM_ERROR("amdgpu: ring %d test failed (0x%08X)\n",
- ring->idx, tmp);
- r = -EINVAL;
- }
- amdgpu_device_wb_free(adev, index);
+ if (i >= adev->usec_timeout)
+ r = -ETIMEDOUT;
+error_free_wb:
+ amdgpu_device_wb_free(adev, index);
return r;
}
@@ -678,20 +670,16 @@ static int cik_sdma_ring_test_ib(struct amdgpu_ring *ring, long timeout)
long r;
r = amdgpu_device_wb_get(adev, &index);
- if (r) {
- dev_err(adev->dev, "(%ld) failed to allocate wb slot\n", r);
+ if (r)
return r;
- }
gpu_addr = adev->wb.gpu_addr + (index * 4);
tmp = 0xCAFEDEAD;
adev->wb.wb[index] = cpu_to_le32(tmp);
memset(&ib, 0, sizeof(ib));
r = amdgpu_ib_get(adev, NULL, 256, &ib);
- if (r) {
- DRM_ERROR("amdgpu: failed to get ib (%ld).\n", r);
+ if (r)
goto err0;
- }
ib.ptr[0] = SDMA_PACKET(SDMA_OPCODE_WRITE,
SDMA_WRITE_SUB_OPCODE_LINEAR, 0);
@@ -706,21 +694,16 @@ static int cik_sdma_ring_test_ib(struct amdgpu_ring *ring, long timeout)
r = dma_fence_wait_timeout(f, false, timeout);
if (r == 0) {
- DRM_ERROR("amdgpu: IB test timed out\n");
r = -ETIMEDOUT;
goto err1;
} else if (r < 0) {
- DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r);
goto err1;
}
tmp = le32_to_cpu(adev->wb.wb[index]);
- if (tmp == 0xDEADBEEF) {
- DRM_DEBUG("ib test on ring %d succeeded\n", ring->idx);
+ if (tmp == 0xDEADBEEF)
r = 0;
- } else {
- DRM_ERROR("amdgpu: ib test failed (0x%08X)\n", tmp);
+ else
r = -EINVAL;
- }
err1:
amdgpu_ib_free(adev, &ib, NULL);
@@ -822,7 +805,7 @@ static void cik_sdma_vm_set_pte_pde(struct amdgpu_ib *ib, uint64_t pe,
*/
static void cik_sdma_ring_pad_ib(struct amdgpu_ring *ring, struct amdgpu_ib *ib)
{
- struct amdgpu_sdma_instance *sdma = amdgpu_get_sdma_instance(ring);
+ struct amdgpu_sdma_instance *sdma = amdgpu_sdma_get_instance_from_ring(ring);
u32 pad_count;
int i;
@@ -1214,8 +1197,11 @@ static int cik_sdma_process_illegal_inst_irq(struct amdgpu_device *adev,
struct amdgpu_irq_src *source,
struct amdgpu_iv_entry *entry)
{
+ u8 instance_id;
+
DRM_ERROR("Illegal instruction in SDMA command stream\n");
- schedule_work(&adev->reset_work);
+ instance_id = (entry->ring_id & 0x3) >> 0;
+ drm_sched_fault(&adev->sdma.instance[instance_id].ring.sched);
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
index d76eb27945dc..1dc3013ea1d5 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
@@ -1775,18 +1775,15 @@ static int gfx_v6_0_ring_test_ring(struct amdgpu_ring *ring)
int r;
r = amdgpu_gfx_scratch_get(adev, &scratch);
- if (r) {
- DRM_ERROR("amdgpu: cp failed to get scratch reg (%d).\n", r);
+ if (r)
return r;
- }
+
WREG32(scratch, 0xCAFEDEAD);
r = amdgpu_ring_alloc(ring, 3);
- if (r) {
- DRM_ERROR("amdgpu: cp failed to lock ring %d (%d).\n", ring->idx, r);
- amdgpu_gfx_scratch_free(adev, scratch);
- return r;
- }
+ if (r)
+ goto error_free_scratch;
+
amdgpu_ring_write(ring, PACKET3(PACKET3_SET_CONFIG_REG, 1));
amdgpu_ring_write(ring, (scratch - PACKET3_SET_CONFIG_REG_START));
amdgpu_ring_write(ring, 0xDEADBEEF);
@@ -1798,13 +1795,11 @@ static int gfx_v6_0_ring_test_ring(struct amdgpu_ring *ring)
break;
DRM_UDELAY(1);
}
- if (i < adev->usec_timeout) {
- DRM_DEBUG("ring test on %d succeeded in %d usecs\n", ring->idx, i);
- } else {
- DRM_ERROR("amdgpu: ring %d test failed (scratch(0x%04X)=0x%08X)\n",
- ring->idx, scratch, tmp);
- r = -EINVAL;
- }
+
+ if (i >= adev->usec_timeout)
+ r = -ETIMEDOUT;
+
+error_free_scratch:
amdgpu_gfx_scratch_free(adev, scratch);
return r;
}
@@ -1845,9 +1840,11 @@ static void gfx_v6_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr,
}
static void gfx_v6_0_ring_emit_ib(struct amdgpu_ring *ring,
+ struct amdgpu_job *job,
struct amdgpu_ib *ib,
- unsigned vmid, bool ctx_switch)
+ bool ctx_switch)
{
+ unsigned vmid = AMDGPU_JOB_GET_VMID(job);
u32 header, control = 0;
/* insert SWITCH_BUFFER packet before first IB in the ring frame */
@@ -1892,17 +1889,15 @@ static int gfx_v6_0_ring_test_ib(struct amdgpu_ring *ring, long timeout)
long r;
r = amdgpu_gfx_scratch_get(adev, &scratch);
- if (r) {
- DRM_ERROR("amdgpu: failed to get scratch reg (%ld).\n", r);
+ if (r)
return r;
- }
+
WREG32(scratch, 0xCAFEDEAD);
memset(&ib, 0, sizeof(ib));
r = amdgpu_ib_get(adev, NULL, 256, &ib);
- if (r) {
- DRM_ERROR("amdgpu: failed to get ib (%ld).\n", r);
+ if (r)
goto err1;
- }
+
ib.ptr[0] = PACKET3(PACKET3_SET_CONFIG_REG, 1);
ib.ptr[1] = ((scratch - PACKET3_SET_CONFIG_REG_START));
ib.ptr[2] = 0xDEADBEEF;
@@ -1914,22 +1909,16 @@ static int gfx_v6_0_ring_test_ib(struct amdgpu_ring *ring, long timeout)
r = dma_fence_wait_timeout(f, false, timeout);
if (r == 0) {
- DRM_ERROR("amdgpu: IB test timed out\n");
r = -ETIMEDOUT;
goto err2;
} else if (r < 0) {
- DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r);
goto err2;
}
tmp = RREG32(scratch);
- if (tmp == 0xDEADBEEF) {
- DRM_DEBUG("ib test on ring %d succeeded\n", ring->idx);
+ if (tmp == 0xDEADBEEF)
r = 0;
- } else {
- DRM_ERROR("amdgpu: ib test failed (scratch(0x%04X)=0x%08X)\n",
- scratch, tmp);
+ else
r = -EINVAL;
- }
err2:
amdgpu_ib_free(adev, &ib, NULL);
@@ -1950,9 +1939,9 @@ static void gfx_v6_0_cp_gfx_enable(struct amdgpu_device *adev, bool enable)
CP_ME_CNTL__CE_HALT_MASK));
WREG32(mmSCRATCH_UMSK, 0);
for (i = 0; i < adev->gfx.num_gfx_rings; i++)
- adev->gfx.gfx_ring[i].ready = false;
+ adev->gfx.gfx_ring[i].sched.ready = false;
for (i = 0; i < adev->gfx.num_compute_rings; i++)
- adev->gfx.compute_ring[i].ready = false;
+ adev->gfx.compute_ring[i].sched.ready = false;
}
udelay(50);
}
@@ -2124,12 +2113,9 @@ static int gfx_v6_0_cp_gfx_resume(struct amdgpu_device *adev)
/* start the rings */
gfx_v6_0_cp_gfx_start(adev);
- ring->ready = true;
- r = amdgpu_ring_test_ring(ring);
- if (r) {
- ring->ready = false;
+ r = amdgpu_ring_test_helper(ring);
+ if (r)
return r;
- }
return 0;
}
@@ -2227,14 +2213,11 @@ static int gfx_v6_0_cp_compute_resume(struct amdgpu_device *adev)
WREG32(mmCP_RB2_CNTL, tmp);
WREG32(mmCP_RB2_BASE, ring->gpu_addr >> 8);
- adev->gfx.compute_ring[0].ready = false;
- adev->gfx.compute_ring[1].ready = false;
for (i = 0; i < 2; i++) {
- r = amdgpu_ring_test_ring(&adev->gfx.compute_ring[i]);
+ r = amdgpu_ring_test_helper(&adev->gfx.compute_ring[i]);
if (r)
return r;
- adev->gfx.compute_ring[i].ready = true;
}
return 0;
@@ -2368,18 +2351,11 @@ static void gfx_v6_0_ring_emit_wreg(struct amdgpu_ring *ring,
amdgpu_ring_write(ring, val);
}
-static void gfx_v6_0_rlc_fini(struct amdgpu_device *adev)
-{
- amdgpu_bo_free_kernel(&adev->gfx.rlc.save_restore_obj, NULL, NULL);
- amdgpu_bo_free_kernel(&adev->gfx.rlc.clear_state_obj, NULL, NULL);
- amdgpu_bo_free_kernel(&adev->gfx.rlc.cp_table_obj, NULL, NULL);
-}
-
static int gfx_v6_0_rlc_init(struct amdgpu_device *adev)
{
const u32 *src_ptr;
volatile u32 *dst_ptr;
- u32 dws, i;
+ u32 dws;
u64 reg_list_mc_addr;
const struct cs_section_def *cs_data;
int r;
@@ -2394,26 +2370,10 @@ static int gfx_v6_0_rlc_init(struct amdgpu_device *adev)
cs_data = adev->gfx.rlc.cs_data;
if (src_ptr) {
- /* save restore block */
- r = amdgpu_bo_create_reserved(adev, dws * 4, PAGE_SIZE,
- AMDGPU_GEM_DOMAIN_VRAM,
- &adev->gfx.rlc.save_restore_obj,
- &adev->gfx.rlc.save_restore_gpu_addr,
- (void **)&adev->gfx.rlc.sr_ptr);
- if (r) {
- dev_warn(adev->dev, "(%d) create RLC sr bo failed\n",
- r);
- gfx_v6_0_rlc_fini(adev);
+ /* init save restore block */
+ r = amdgpu_gfx_rlc_init_sr(adev, dws);
+ if (r)
return r;
- }
-
- /* write the sr buffer */
- dst_ptr = adev->gfx.rlc.sr_ptr;
- for (i = 0; i < adev->gfx.rlc.reg_list_size; i++)
- dst_ptr[i] = cpu_to_le32(src_ptr[i]);
-
- amdgpu_bo_kunmap(adev->gfx.rlc.save_restore_obj);
- amdgpu_bo_unreserve(adev->gfx.rlc.save_restore_obj);
}
if (cs_data) {
@@ -2428,7 +2388,7 @@ static int gfx_v6_0_rlc_init(struct amdgpu_device *adev)
(void **)&adev->gfx.rlc.cs_ptr);
if (r) {
dev_warn(adev->dev, "(%d) create RLC c bo failed\n", r);
- gfx_v6_0_rlc_fini(adev);
+ amdgpu_gfx_rlc_fini(adev);
return r;
}
@@ -2549,8 +2509,8 @@ static int gfx_v6_0_rlc_resume(struct amdgpu_device *adev)
if (!adev->gfx.rlc_fw)
return -EINVAL;
- gfx_v6_0_rlc_stop(adev);
- gfx_v6_0_rlc_reset(adev);
+ adev->gfx.rlc.funcs->stop(adev);
+ adev->gfx.rlc.funcs->reset(adev);
gfx_v6_0_init_pg(adev);
gfx_v6_0_init_cg(adev);
@@ -2578,7 +2538,7 @@ static int gfx_v6_0_rlc_resume(struct amdgpu_device *adev)
WREG32(mmRLC_UCODE_ADDR, 0);
gfx_v6_0_enable_lbpw(adev, gfx_v6_0_lbpw_supported(adev));
- gfx_v6_0_rlc_start(adev);
+ adev->gfx.rlc.funcs->start(adev);
return 0;
}
@@ -3075,6 +3035,14 @@ static const struct amdgpu_gfx_funcs gfx_v6_0_gfx_funcs = {
.select_me_pipe_q = &gfx_v6_0_select_me_pipe_q
};
+static const struct amdgpu_rlc_funcs gfx_v6_0_rlc_funcs = {
+ .init = gfx_v6_0_rlc_init,
+ .resume = gfx_v6_0_rlc_resume,
+ .stop = gfx_v6_0_rlc_stop,
+ .reset = gfx_v6_0_rlc_reset,
+ .start = gfx_v6_0_rlc_start
+};
+
static int gfx_v6_0_early_init(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
@@ -3082,6 +3050,7 @@ static int gfx_v6_0_early_init(void *handle)
adev->gfx.num_gfx_rings = GFX6_NUM_GFX_RINGS;
adev->gfx.num_compute_rings = GFX6_NUM_COMPUTE_RINGS;
adev->gfx.funcs = &gfx_v6_0_gfx_funcs;
+ adev->gfx.rlc.funcs = &gfx_v6_0_rlc_funcs;
gfx_v6_0_set_ring_funcs(adev);
gfx_v6_0_set_irq_funcs(adev);
@@ -3114,7 +3083,7 @@ static int gfx_v6_0_sw_init(void *handle)
return r;
}
- r = gfx_v6_0_rlc_init(adev);
+ r = adev->gfx.rlc.funcs->init(adev);
if (r) {
DRM_ERROR("Failed to init rlc BOs!\n");
return r;
@@ -3165,7 +3134,7 @@ static int gfx_v6_0_sw_fini(void *handle)
for (i = 0; i < adev->gfx.num_compute_rings; i++)
amdgpu_ring_fini(&adev->gfx.compute_ring[i]);
- gfx_v6_0_rlc_fini(adev);
+ amdgpu_gfx_rlc_fini(adev);
return 0;
}
@@ -3177,7 +3146,7 @@ static int gfx_v6_0_hw_init(void *handle)
gfx_v6_0_constants_init(adev);
- r = gfx_v6_0_rlc_resume(adev);
+ r = adev->gfx.rlc.funcs->resume(adev);
if (r)
return r;
@@ -3195,7 +3164,7 @@ static int gfx_v6_0_hw_fini(void *handle)
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
gfx_v6_0_cp_enable(adev, false);
- gfx_v6_0_rlc_stop(adev);
+ adev->gfx.rlc.funcs->stop(adev);
gfx_v6_0_fini_pg(adev);
return 0;
@@ -3393,12 +3362,31 @@ static int gfx_v6_0_eop_irq(struct amdgpu_device *adev,
return 0;
}
+static void gfx_v6_0_fault(struct amdgpu_device *adev,
+ struct amdgpu_iv_entry *entry)
+{
+ struct amdgpu_ring *ring;
+
+ switch (entry->ring_id) {
+ case 0:
+ ring = &adev->gfx.gfx_ring[0];
+ break;
+ case 1:
+ case 2:
+ ring = &adev->gfx.compute_ring[entry->ring_id - 1];
+ break;
+ default:
+ return;
+ }
+ drm_sched_fault(&ring->sched);
+}
+
static int gfx_v6_0_priv_reg_irq(struct amdgpu_device *adev,
struct amdgpu_irq_src *source,
struct amdgpu_iv_entry *entry)
{
DRM_ERROR("Illegal register access in command stream\n");
- schedule_work(&adev->reset_work);
+ gfx_v6_0_fault(adev, entry);
return 0;
}
@@ -3407,7 +3395,7 @@ static int gfx_v6_0_priv_inst_irq(struct amdgpu_device *adev,
struct amdgpu_iv_entry *entry)
{
DRM_ERROR("Illegal instruction in command stream\n");
- schedule_work(&adev->reset_work);
+ gfx_v6_0_fault(adev, entry);
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
index 0e72bc09939a..f467b9bd090d 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
@@ -882,7 +882,6 @@ static const u32 kalindi_rlc_save_restore_register_list[] =
static u32 gfx_v7_0_get_csb_size(struct amdgpu_device *adev);
static void gfx_v7_0_get_csb_buffer(struct amdgpu_device *adev, volatile u32 *buffer);
-static void gfx_v7_0_init_cp_pg_table(struct amdgpu_device *adev);
static void gfx_v7_0_init_pg(struct amdgpu_device *adev);
static void gfx_v7_0_get_cu_info(struct amdgpu_device *adev);
@@ -2064,17 +2063,14 @@ static int gfx_v7_0_ring_test_ring(struct amdgpu_ring *ring)
int r;
r = amdgpu_gfx_scratch_get(adev, &scratch);
- if (r) {
- DRM_ERROR("amdgpu: cp failed to get scratch reg (%d).\n", r);
+ if (r)
return r;
- }
+
WREG32(scratch, 0xCAFEDEAD);
r = amdgpu_ring_alloc(ring, 3);
- if (r) {
- DRM_ERROR("amdgpu: cp failed to lock ring %d (%d).\n", ring->idx, r);
- amdgpu_gfx_scratch_free(adev, scratch);
- return r;
- }
+ if (r)
+ goto error_free_scratch;
+
amdgpu_ring_write(ring, PACKET3(PACKET3_SET_UCONFIG_REG, 1));
amdgpu_ring_write(ring, (scratch - PACKET3_SET_UCONFIG_REG_START));
amdgpu_ring_write(ring, 0xDEADBEEF);
@@ -2086,13 +2082,10 @@ static int gfx_v7_0_ring_test_ring(struct amdgpu_ring *ring)
break;
DRM_UDELAY(1);
}
- if (i < adev->usec_timeout) {
- DRM_DEBUG("ring test on %d succeeded in %d usecs\n", ring->idx, i);
- } else {
- DRM_ERROR("amdgpu: ring %d test failed (scratch(0x%04X)=0x%08X)\n",
- ring->idx, scratch, tmp);
- r = -EINVAL;
- }
+ if (i >= adev->usec_timeout)
+ r = -ETIMEDOUT;
+
+error_free_scratch:
amdgpu_gfx_scratch_free(adev, scratch);
return r;
}
@@ -2233,9 +2226,11 @@ static void gfx_v7_0_ring_emit_fence_compute(struct amdgpu_ring *ring,
* on the gfx ring for execution by the GPU.
*/
static void gfx_v7_0_ring_emit_ib_gfx(struct amdgpu_ring *ring,
- struct amdgpu_ib *ib,
- unsigned vmid, bool ctx_switch)
+ struct amdgpu_job *job,
+ struct amdgpu_ib *ib,
+ bool ctx_switch)
{
+ unsigned vmid = AMDGPU_JOB_GET_VMID(job);
u32 header, control = 0;
/* insert SWITCH_BUFFER packet before first IB in the ring frame */
@@ -2262,9 +2257,11 @@ static void gfx_v7_0_ring_emit_ib_gfx(struct amdgpu_ring *ring,
}
static void gfx_v7_0_ring_emit_ib_compute(struct amdgpu_ring *ring,
+ struct amdgpu_job *job,
struct amdgpu_ib *ib,
- unsigned vmid, bool ctx_switch)
+ bool ctx_switch)
{
+ unsigned vmid = AMDGPU_JOB_GET_VMID(job);
u32 control = INDIRECT_BUFFER_VALID | ib->length_dw | (vmid << 24);
amdgpu_ring_write(ring, PACKET3(PACKET3_INDIRECT_BUFFER, 2));
@@ -2316,17 +2313,15 @@ static int gfx_v7_0_ring_test_ib(struct amdgpu_ring *ring, long timeout)
long r;
r = amdgpu_gfx_scratch_get(adev, &scratch);
- if (r) {
- DRM_ERROR("amdgpu: failed to get scratch reg (%ld).\n", r);
+ if (r)
return r;
- }
+
WREG32(scratch, 0xCAFEDEAD);
memset(&ib, 0, sizeof(ib));
r = amdgpu_ib_get(adev, NULL, 256, &ib);
- if (r) {
- DRM_ERROR("amdgpu: failed to get ib (%ld).\n", r);
+ if (r)
goto err1;
- }
+
ib.ptr[0] = PACKET3(PACKET3_SET_UCONFIG_REG, 1);
ib.ptr[1] = ((scratch - PACKET3_SET_UCONFIG_REG_START));
ib.ptr[2] = 0xDEADBEEF;
@@ -2338,22 +2333,16 @@ static int gfx_v7_0_ring_test_ib(struct amdgpu_ring *ring, long timeout)
r = dma_fence_wait_timeout(f, false, timeout);
if (r == 0) {
- DRM_ERROR("amdgpu: IB test timed out\n");
r = -ETIMEDOUT;
goto err2;
} else if (r < 0) {
- DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r);
goto err2;
}
tmp = RREG32(scratch);
- if (tmp == 0xDEADBEEF) {
- DRM_DEBUG("ib test on ring %d succeeded\n", ring->idx);
+ if (tmp == 0xDEADBEEF)
r = 0;
- } else {
- DRM_ERROR("amdgpu: ib test failed (scratch(0x%04X)=0x%08X)\n",
- scratch, tmp);
+ else
r = -EINVAL;
- }
err2:
amdgpu_ib_free(adev, &ib, NULL);
@@ -2403,7 +2392,7 @@ static void gfx_v7_0_cp_gfx_enable(struct amdgpu_device *adev, bool enable)
} else {
WREG32(mmCP_ME_CNTL, (CP_ME_CNTL__ME_HALT_MASK | CP_ME_CNTL__PFP_HALT_MASK | CP_ME_CNTL__CE_HALT_MASK));
for (i = 0; i < adev->gfx.num_gfx_rings; i++)
- adev->gfx.gfx_ring[i].ready = false;
+ adev->gfx.gfx_ring[i].sched.ready = false;
}
udelay(50);
}
@@ -2613,12 +2602,9 @@ static int gfx_v7_0_cp_gfx_resume(struct amdgpu_device *adev)
/* start the ring */
gfx_v7_0_cp_gfx_start(adev);
- ring->ready = true;
- r = amdgpu_ring_test_ring(ring);
- if (r) {
- ring->ready = false;
+ r = amdgpu_ring_test_helper(ring);
+ if (r)
return r;
- }
return 0;
}
@@ -2675,7 +2661,7 @@ static void gfx_v7_0_cp_compute_enable(struct amdgpu_device *adev, bool enable)
} else {
WREG32(mmCP_MEC_CNTL, (CP_MEC_CNTL__MEC_ME1_HALT_MASK | CP_MEC_CNTL__MEC_ME2_HALT_MASK));
for (i = 0; i < adev->gfx.num_compute_rings; i++)
- adev->gfx.compute_ring[i].ready = false;
+ adev->gfx.compute_ring[i].sched.ready = false;
}
udelay(50);
}
@@ -2781,7 +2767,7 @@ static int gfx_v7_0_mec_init(struct amdgpu_device *adev)
* GFX7_MEC_HPD_SIZE * 2;
r = amdgpu_bo_create_reserved(adev, mec_hpd_size, PAGE_SIZE,
- AMDGPU_GEM_DOMAIN_GTT,
+ AMDGPU_GEM_DOMAIN_VRAM,
&adev->gfx.mec.hpd_eop_obj,
&adev->gfx.mec.hpd_eop_gpu_addr,
(void **)&hpd);
@@ -3106,10 +3092,7 @@ static int gfx_v7_0_cp_compute_resume(struct amdgpu_device *adev)
for (i = 0; i < adev->gfx.num_compute_rings; i++) {
ring = &adev->gfx.compute_ring[i];
- ring->ready = true;
- r = amdgpu_ring_test_ring(ring);
- if (r)
- ring->ready = false;
+ amdgpu_ring_test_helper(ring);
}
return 0;
@@ -3268,18 +3251,10 @@ static void gfx_v7_0_ring_emit_wreg(struct amdgpu_ring *ring,
* The RLC is a multi-purpose microengine that handles a
* variety of functions.
*/
-static void gfx_v7_0_rlc_fini(struct amdgpu_device *adev)
-{
- amdgpu_bo_free_kernel(&adev->gfx.rlc.save_restore_obj, NULL, NULL);
- amdgpu_bo_free_kernel(&adev->gfx.rlc.clear_state_obj, NULL, NULL);
- amdgpu_bo_free_kernel(&adev->gfx.rlc.cp_table_obj, NULL, NULL);
-}
-
static int gfx_v7_0_rlc_init(struct amdgpu_device *adev)
{
const u32 *src_ptr;
- volatile u32 *dst_ptr;
- u32 dws, i;
+ u32 dws;
const struct cs_section_def *cs_data;
int r;
@@ -3306,66 +3281,23 @@ static int gfx_v7_0_rlc_init(struct amdgpu_device *adev)
cs_data = adev->gfx.rlc.cs_data;
if (src_ptr) {
- /* save restore block */
- r = amdgpu_bo_create_reserved(adev, dws * 4, PAGE_SIZE,
- AMDGPU_GEM_DOMAIN_VRAM,
- &adev->gfx.rlc.save_restore_obj,
- &adev->gfx.rlc.save_restore_gpu_addr,
- (void **)&adev->gfx.rlc.sr_ptr);
- if (r) {
- dev_warn(adev->dev, "(%d) create, pin or map of RLC sr bo failed\n", r);
- gfx_v7_0_rlc_fini(adev);
+ /* init save restore block */
+ r = amdgpu_gfx_rlc_init_sr(adev, dws);
+ if (r)
return r;
- }
-
- /* write the sr buffer */
- dst_ptr = adev->gfx.rlc.sr_ptr;
- for (i = 0; i < adev->gfx.rlc.reg_list_size; i++)
- dst_ptr[i] = cpu_to_le32(src_ptr[i]);
- amdgpu_bo_kunmap(adev->gfx.rlc.save_restore_obj);
- amdgpu_bo_unreserve(adev->gfx.rlc.save_restore_obj);
}
if (cs_data) {
- /* clear state block */
- adev->gfx.rlc.clear_state_size = dws = gfx_v7_0_get_csb_size(adev);
-
- r = amdgpu_bo_create_reserved(adev, dws * 4, PAGE_SIZE,
- AMDGPU_GEM_DOMAIN_VRAM,
- &adev->gfx.rlc.clear_state_obj,
- &adev->gfx.rlc.clear_state_gpu_addr,
- (void **)&adev->gfx.rlc.cs_ptr);
- if (r) {
- dev_warn(adev->dev, "(%d) create RLC c bo failed\n", r);
- gfx_v7_0_rlc_fini(adev);
+ /* init clear state block */
+ r = amdgpu_gfx_rlc_init_csb(adev);
+ if (r)
return r;
- }
-
- /* set up the cs buffer */
- dst_ptr = adev->gfx.rlc.cs_ptr;
- gfx_v7_0_get_csb_buffer(adev, dst_ptr);
- amdgpu_bo_kunmap(adev->gfx.rlc.clear_state_obj);
- amdgpu_bo_unreserve(adev->gfx.rlc.clear_state_obj);
}
if (adev->gfx.rlc.cp_table_size) {
-
- r = amdgpu_bo_create_reserved(adev, adev->gfx.rlc.cp_table_size,
- PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM,
- &adev->gfx.rlc.cp_table_obj,
- &adev->gfx.rlc.cp_table_gpu_addr,
- (void **)&adev->gfx.rlc.cp_table_ptr);
- if (r) {
- dev_warn(adev->dev, "(%d) create RLC cp table bo failed\n", r);
- gfx_v7_0_rlc_fini(adev);
+ r = amdgpu_gfx_rlc_init_cpt(adev);
+ if (r)
return r;
- }
-
- gfx_v7_0_init_cp_pg_table(adev);
-
- amdgpu_bo_kunmap(adev->gfx.rlc.cp_table_obj);
- amdgpu_bo_unreserve(adev->gfx.rlc.cp_table_obj);
-
}
return 0;
@@ -3446,7 +3378,12 @@ static u32 gfx_v7_0_halt_rlc(struct amdgpu_device *adev)
return orig;
}
-static void gfx_v7_0_enter_rlc_safe_mode(struct amdgpu_device *adev)
+static bool gfx_v7_0_is_rlc_enabled(struct amdgpu_device *adev)
+{
+ return true;
+}
+
+static void gfx_v7_0_set_safe_mode(struct amdgpu_device *adev)
{
u32 tmp, i, mask;
@@ -3468,7 +3405,7 @@ static void gfx_v7_0_enter_rlc_safe_mode(struct amdgpu_device *adev)
}
}
-static void gfx_v7_0_exit_rlc_safe_mode(struct amdgpu_device *adev)
+static void gfx_v7_0_unset_safe_mode(struct amdgpu_device *adev)
{
u32 tmp;
@@ -3545,13 +3482,13 @@ static int gfx_v7_0_rlc_resume(struct amdgpu_device *adev)
adev->gfx.rlc_feature_version = le32_to_cpu(
hdr->ucode_feature_version);
- gfx_v7_0_rlc_stop(adev);
+ adev->gfx.rlc.funcs->stop(adev);
/* disable CG */
tmp = RREG32(mmRLC_CGCG_CGLS_CTRL) & 0xfffffffc;
WREG32(mmRLC_CGCG_CGLS_CTRL, tmp);
- gfx_v7_0_rlc_reset(adev);
+ adev->gfx.rlc.funcs->reset(adev);
gfx_v7_0_init_pg(adev);
@@ -3582,7 +3519,7 @@ static int gfx_v7_0_rlc_resume(struct amdgpu_device *adev)
if (adev->asic_type == CHIP_BONAIRE)
WREG32(mmRLC_DRIVER_CPDMA_STATUS, 0);
- gfx_v7_0_rlc_start(adev);
+ adev->gfx.rlc.funcs->start(adev);
return 0;
}
@@ -3784,72 +3721,12 @@ static void gfx_v7_0_enable_gds_pg(struct amdgpu_device *adev, bool enable)
WREG32(mmRLC_PG_CNTL, data);
}
-static void gfx_v7_0_init_cp_pg_table(struct amdgpu_device *adev)
+static int gfx_v7_0_cp_pg_table_num(struct amdgpu_device *adev)
{
- const __le32 *fw_data;
- volatile u32 *dst_ptr;
- int me, i, max_me = 4;
- u32 bo_offset = 0;
- u32 table_offset, table_size;
-
if (adev->asic_type == CHIP_KAVERI)
- max_me = 5;
-
- if (adev->gfx.rlc.cp_table_ptr == NULL)
- return;
-
- /* write the cp table buffer */
- dst_ptr = adev->gfx.rlc.cp_table_ptr;
- for (me = 0; me < max_me; me++) {
- if (me == 0) {
- const struct gfx_firmware_header_v1_0 *hdr =
- (const struct gfx_firmware_header_v1_0 *)adev->gfx.ce_fw->data;
- fw_data = (const __le32 *)
- (adev->gfx.ce_fw->data +
- le32_to_cpu(hdr->header.ucode_array_offset_bytes));
- table_offset = le32_to_cpu(hdr->jt_offset);
- table_size = le32_to_cpu(hdr->jt_size);
- } else if (me == 1) {
- const struct gfx_firmware_header_v1_0 *hdr =
- (const struct gfx_firmware_header_v1_0 *)adev->gfx.pfp_fw->data;
- fw_data = (const __le32 *)
- (adev->gfx.pfp_fw->data +
- le32_to_cpu(hdr->header.ucode_array_offset_bytes));
- table_offset = le32_to_cpu(hdr->jt_offset);
- table_size = le32_to_cpu(hdr->jt_size);
- } else if (me == 2) {
- const struct gfx_firmware_header_v1_0 *hdr =
- (const struct gfx_firmware_header_v1_0 *)adev->gfx.me_fw->data;
- fw_data = (const __le32 *)
- (adev->gfx.me_fw->data +
- le32_to_cpu(hdr->header.ucode_array_offset_bytes));
- table_offset = le32_to_cpu(hdr->jt_offset);
- table_size = le32_to_cpu(hdr->jt_size);
- } else if (me == 3) {
- const struct gfx_firmware_header_v1_0 *hdr =
- (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data;
- fw_data = (const __le32 *)
- (adev->gfx.mec_fw->data +
- le32_to_cpu(hdr->header.ucode_array_offset_bytes));
- table_offset = le32_to_cpu(hdr->jt_offset);
- table_size = le32_to_cpu(hdr->jt_size);
- } else {
- const struct gfx_firmware_header_v1_0 *hdr =
- (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec2_fw->data;
- fw_data = (const __le32 *)
- (adev->gfx.mec2_fw->data +
- le32_to_cpu(hdr->header.ucode_array_offset_bytes));
- table_offset = le32_to_cpu(hdr->jt_offset);
- table_size = le32_to_cpu(hdr->jt_size);
- }
-
- for (i = 0; i < table_size; i ++) {
- dst_ptr[bo_offset + i] =
- cpu_to_le32(le32_to_cpu(fw_data[table_offset + i]));
- }
-
- bo_offset += table_size;
- }
+ return 5;
+ else
+ return 4;
}
static void gfx_v7_0_enable_gfx_cgpg(struct amdgpu_device *adev,
@@ -4288,8 +4165,17 @@ static const struct amdgpu_gfx_funcs gfx_v7_0_gfx_funcs = {
};
static const struct amdgpu_rlc_funcs gfx_v7_0_rlc_funcs = {
- .enter_safe_mode = gfx_v7_0_enter_rlc_safe_mode,
- .exit_safe_mode = gfx_v7_0_exit_rlc_safe_mode
+ .is_rlc_enabled = gfx_v7_0_is_rlc_enabled,
+ .set_safe_mode = gfx_v7_0_set_safe_mode,
+ .unset_safe_mode = gfx_v7_0_unset_safe_mode,
+ .init = gfx_v7_0_rlc_init,
+ .get_csb_size = gfx_v7_0_get_csb_size,
+ .get_csb_buffer = gfx_v7_0_get_csb_buffer,
+ .get_cp_table_num = gfx_v7_0_cp_pg_table_num,
+ .resume = gfx_v7_0_rlc_resume,
+ .stop = gfx_v7_0_rlc_stop,
+ .reset = gfx_v7_0_rlc_reset,
+ .start = gfx_v7_0_rlc_start
};
static int gfx_v7_0_early_init(void *handle)
@@ -4540,7 +4426,7 @@ static int gfx_v7_0_sw_init(void *handle)
return r;
}
- r = gfx_v7_0_rlc_init(adev);
+ r = adev->gfx.rlc.funcs->init(adev);
if (r) {
DRM_ERROR("Failed to init rlc BOs!\n");
return r;
@@ -4604,7 +4490,7 @@ static int gfx_v7_0_sw_fini(void *handle)
amdgpu_ring_fini(&adev->gfx.compute_ring[i]);
gfx_v7_0_cp_compute_fini(adev);
- gfx_v7_0_rlc_fini(adev);
+ amdgpu_gfx_rlc_fini(adev);
gfx_v7_0_mec_fini(adev);
amdgpu_bo_free_kernel(&adev->gfx.rlc.clear_state_obj,
&adev->gfx.rlc.clear_state_gpu_addr,
@@ -4627,7 +4513,7 @@ static int gfx_v7_0_hw_init(void *handle)
gfx_v7_0_constants_init(adev);
/* init rlc */
- r = gfx_v7_0_rlc_resume(adev);
+ r = adev->gfx.rlc.funcs->resume(adev);
if (r)
return r;
@@ -4645,7 +4531,7 @@ static int gfx_v7_0_hw_fini(void *handle)
amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0);
amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0);
gfx_v7_0_cp_enable(adev, false);
- gfx_v7_0_rlc_stop(adev);
+ adev->gfx.rlc.funcs->stop(adev);
gfx_v7_0_fini_pg(adev);
return 0;
@@ -4730,7 +4616,7 @@ static int gfx_v7_0_soft_reset(void *handle)
gfx_v7_0_update_cg(adev, false);
/* stop the rlc */
- gfx_v7_0_rlc_stop(adev);
+ adev->gfx.rlc.funcs->stop(adev);
/* Disable GFX parsing/prefetching */
WREG32(mmCP_ME_CNTL, CP_ME_CNTL__ME_HALT_MASK | CP_ME_CNTL__PFP_HALT_MASK | CP_ME_CNTL__CE_HALT_MASK);
@@ -4959,12 +4845,36 @@ static int gfx_v7_0_eop_irq(struct amdgpu_device *adev,
return 0;
}
+static void gfx_v7_0_fault(struct amdgpu_device *adev,
+ struct amdgpu_iv_entry *entry)
+{
+ struct amdgpu_ring *ring;
+ u8 me_id, pipe_id;
+ int i;
+
+ me_id = (entry->ring_id & 0x0c) >> 2;
+ pipe_id = (entry->ring_id & 0x03) >> 0;
+ switch (me_id) {
+ case 0:
+ drm_sched_fault(&adev->gfx.gfx_ring[0].sched);
+ break;
+ case 1:
+ case 2:
+ for (i = 0; i < adev->gfx.num_compute_rings; i++) {
+ ring = &adev->gfx.compute_ring[i];
+ if ((ring->me == me_id) && (ring->pipe == pipe_id))
+ drm_sched_fault(&ring->sched);
+ }
+ break;
+ }
+}
+
static int gfx_v7_0_priv_reg_irq(struct amdgpu_device *adev,
struct amdgpu_irq_src *source,
struct amdgpu_iv_entry *entry)
{
DRM_ERROR("Illegal register access in command stream\n");
- schedule_work(&adev->reset_work);
+ gfx_v7_0_fault(adev, entry);
return 0;
}
@@ -4974,7 +4884,7 @@ static int gfx_v7_0_priv_inst_irq(struct amdgpu_device *adev,
{
DRM_ERROR("Illegal instruction in command stream\n");
// XXX soft reset the gfx block only
- schedule_work(&adev->reset_work);
+ gfx_v7_0_fault(adev, entry);
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
index 617b0c8908a3..cb066a8dccd7 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
@@ -54,7 +54,7 @@
#include "ivsrcid/ivsrcid_vislands30.h"
#define GFX8_NUM_GFX_RINGS 1
-#define GFX8_MEC_HPD_SIZE 2048
+#define GFX8_MEC_HPD_SIZE 4096
#define TOPAZ_GB_ADDR_CONFIG_GOLDEN 0x22010001
#define CARRIZO_GB_ADDR_CONFIG_GOLDEN 0x22010001
@@ -839,18 +839,14 @@ static int gfx_v8_0_ring_test_ring(struct amdgpu_ring *ring)
int r;
r = amdgpu_gfx_scratch_get(adev, &scratch);
- if (r) {
- DRM_ERROR("amdgpu: cp failed to get scratch reg (%d).\n", r);
+ if (r)
return r;
- }
+
WREG32(scratch, 0xCAFEDEAD);
r = amdgpu_ring_alloc(ring, 3);
- if (r) {
- DRM_ERROR("amdgpu: cp failed to lock ring %d (%d).\n",
- ring->idx, r);
- amdgpu_gfx_scratch_free(adev, scratch);
- return r;
- }
+ if (r)
+ goto error_free_scratch;
+
amdgpu_ring_write(ring, PACKET3(PACKET3_SET_UCONFIG_REG, 1));
amdgpu_ring_write(ring, (scratch - PACKET3_SET_UCONFIG_REG_START));
amdgpu_ring_write(ring, 0xDEADBEEF);
@@ -862,14 +858,11 @@ static int gfx_v8_0_ring_test_ring(struct amdgpu_ring *ring)
break;
DRM_UDELAY(1);
}
- if (i < adev->usec_timeout) {
- DRM_DEBUG("ring test on %d succeeded in %d usecs\n",
- ring->idx, i);
- } else {
- DRM_ERROR("amdgpu: ring %d test failed (scratch(0x%04X)=0x%08X)\n",
- ring->idx, scratch, tmp);
- r = -EINVAL;
- }
+
+ if (i >= adev->usec_timeout)
+ r = -ETIMEDOUT;
+
+error_free_scratch:
amdgpu_gfx_scratch_free(adev, scratch);
return r;
}
@@ -886,19 +879,16 @@ static int gfx_v8_0_ring_test_ib(struct amdgpu_ring *ring, long timeout)
long r;
r = amdgpu_device_wb_get(adev, &index);
- if (r) {
- dev_err(adev->dev, "(%ld) failed to allocate wb slot\n", r);
+ if (r)
return r;
- }
gpu_addr = adev->wb.gpu_addr + (index * 4);
adev->wb.wb[index] = cpu_to_le32(0xCAFEDEAD);
memset(&ib, 0, sizeof(ib));
r = amdgpu_ib_get(adev, NULL, 16, &ib);
- if (r) {
- DRM_ERROR("amdgpu: failed to get ib (%ld).\n", r);
+ if (r)
goto err1;
- }
+
ib.ptr[0] = PACKET3(PACKET3_WRITE_DATA, 3);
ib.ptr[1] = WRITE_DATA_DST_SEL(5) | WR_CONFIRM;
ib.ptr[2] = lower_32_bits(gpu_addr);
@@ -912,22 +902,17 @@ static int gfx_v8_0_ring_test_ib(struct amdgpu_ring *ring, long timeout)
r = dma_fence_wait_timeout(f, false, timeout);
if (r == 0) {
- DRM_ERROR("amdgpu: IB test timed out.\n");
r = -ETIMEDOUT;
goto err2;
} else if (r < 0) {
- DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r);
goto err2;
}
tmp = adev->wb.wb[index];
- if (tmp == 0xDEADBEEF) {
- DRM_DEBUG("ib test on ring %d succeeded\n", ring->idx);
+ if (tmp == 0xDEADBEEF)
r = 0;
- } else {
- DRM_ERROR("ib test on ring %d failed\n", ring->idx);
+ else
r = -EINVAL;
- }
err2:
amdgpu_ib_free(adev, &ib, NULL);
@@ -1298,81 +1283,16 @@ static void gfx_v8_0_get_csb_buffer(struct amdgpu_device *adev,
buffer[count++] = cpu_to_le32(0);
}
-static void cz_init_cp_jump_table(struct amdgpu_device *adev)
+static int gfx_v8_0_cp_jump_table_num(struct amdgpu_device *adev)
{
- const __le32 *fw_data;
- volatile u32 *dst_ptr;
- int me, i, max_me = 4;
- u32 bo_offset = 0;
- u32 table_offset, table_size;
-
if (adev->asic_type == CHIP_CARRIZO)
- max_me = 5;
-
- /* write the cp table buffer */
- dst_ptr = adev->gfx.rlc.cp_table_ptr;
- for (me = 0; me < max_me; me++) {
- if (me == 0) {
- const struct gfx_firmware_header_v1_0 *hdr =
- (const struct gfx_firmware_header_v1_0 *)adev->gfx.ce_fw->data;
- fw_data = (const __le32 *)
- (adev->gfx.ce_fw->data +
- le32_to_cpu(hdr->header.ucode_array_offset_bytes));
- table_offset = le32_to_cpu(hdr->jt_offset);
- table_size = le32_to_cpu(hdr->jt_size);
- } else if (me == 1) {
- const struct gfx_firmware_header_v1_0 *hdr =
- (const struct gfx_firmware_header_v1_0 *)adev->gfx.pfp_fw->data;
- fw_data = (const __le32 *)
- (adev->gfx.pfp_fw->data +
- le32_to_cpu(hdr->header.ucode_array_offset_bytes));
- table_offset = le32_to_cpu(hdr->jt_offset);
- table_size = le32_to_cpu(hdr->jt_size);
- } else if (me == 2) {
- const struct gfx_firmware_header_v1_0 *hdr =
- (const struct gfx_firmware_header_v1_0 *)adev->gfx.me_fw->data;
- fw_data = (const __le32 *)
- (adev->gfx.me_fw->data +
- le32_to_cpu(hdr->header.ucode_array_offset_bytes));
- table_offset = le32_to_cpu(hdr->jt_offset);
- table_size = le32_to_cpu(hdr->jt_size);
- } else if (me == 3) {
- const struct gfx_firmware_header_v1_0 *hdr =
- (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data;
- fw_data = (const __le32 *)
- (adev->gfx.mec_fw->data +
- le32_to_cpu(hdr->header.ucode_array_offset_bytes));
- table_offset = le32_to_cpu(hdr->jt_offset);
- table_size = le32_to_cpu(hdr->jt_size);
- } else if (me == 4) {
- const struct gfx_firmware_header_v1_0 *hdr =
- (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec2_fw->data;
- fw_data = (const __le32 *)
- (adev->gfx.mec2_fw->data +
- le32_to_cpu(hdr->header.ucode_array_offset_bytes));
- table_offset = le32_to_cpu(hdr->jt_offset);
- table_size = le32_to_cpu(hdr->jt_size);
- }
-
- for (i = 0; i < table_size; i ++) {
- dst_ptr[bo_offset + i] =
- cpu_to_le32(le32_to_cpu(fw_data[table_offset + i]));
- }
-
- bo_offset += table_size;
- }
-}
-
-static void gfx_v8_0_rlc_fini(struct amdgpu_device *adev)
-{
- amdgpu_bo_free_kernel(&adev->gfx.rlc.clear_state_obj, NULL, NULL);
- amdgpu_bo_free_kernel(&adev->gfx.rlc.cp_table_obj, NULL, NULL);
+ return 5;
+ else
+ return 4;
}
static int gfx_v8_0_rlc_init(struct amdgpu_device *adev)
{
- volatile u32 *dst_ptr;
- u32 dws;
const struct cs_section_def *cs_data;
int r;
@@ -1381,44 +1301,18 @@ static int gfx_v8_0_rlc_init(struct amdgpu_device *adev)
cs_data = adev->gfx.rlc.cs_data;
if (cs_data) {
- /* clear state block */
- adev->gfx.rlc.clear_state_size = dws = gfx_v8_0_get_csb_size(adev);
-
- r = amdgpu_bo_create_reserved(adev, dws * 4, PAGE_SIZE,
- AMDGPU_GEM_DOMAIN_VRAM,
- &adev->gfx.rlc.clear_state_obj,
- &adev->gfx.rlc.clear_state_gpu_addr,
- (void **)&adev->gfx.rlc.cs_ptr);
- if (r) {
- dev_warn(adev->dev, "(%d) create RLC c bo failed\n", r);
- gfx_v8_0_rlc_fini(adev);
+ /* init clear state block */
+ r = amdgpu_gfx_rlc_init_csb(adev);
+ if (r)
return r;
- }
-
- /* set up the cs buffer */
- dst_ptr = adev->gfx.rlc.cs_ptr;
- gfx_v8_0_get_csb_buffer(adev, dst_ptr);
- amdgpu_bo_kunmap(adev->gfx.rlc.clear_state_obj);
- amdgpu_bo_unreserve(adev->gfx.rlc.clear_state_obj);
}
if ((adev->asic_type == CHIP_CARRIZO) ||
(adev->asic_type == CHIP_STONEY)) {
adev->gfx.rlc.cp_table_size = ALIGN(96 * 5 * 4, 2048) + (64 * 1024); /* JT + GDS */
- r = amdgpu_bo_create_reserved(adev, adev->gfx.rlc.cp_table_size,
- PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM,
- &adev->gfx.rlc.cp_table_obj,
- &adev->gfx.rlc.cp_table_gpu_addr,
- (void **)&adev->gfx.rlc.cp_table_ptr);
- if (r) {
- dev_warn(adev->dev, "(%d) create RLC cp table bo failed\n", r);
+ r = amdgpu_gfx_rlc_init_cpt(adev);
+ if (r)
return r;
- }
-
- cz_init_cp_jump_table(adev);
-
- amdgpu_bo_kunmap(adev->gfx.rlc.cp_table_obj);
- amdgpu_bo_unreserve(adev->gfx.rlc.cp_table_obj);
}
return 0;
@@ -1443,7 +1337,7 @@ static int gfx_v8_0_mec_init(struct amdgpu_device *adev)
mec_hpd_size = adev->gfx.num_compute_rings * GFX8_MEC_HPD_SIZE;
r = amdgpu_bo_create_reserved(adev, mec_hpd_size, PAGE_SIZE,
- AMDGPU_GEM_DOMAIN_GTT,
+ AMDGPU_GEM_DOMAIN_VRAM,
&adev->gfx.mec.hpd_eop_obj,
&adev->gfx.mec.hpd_eop_gpu_addr,
(void **)&hpd);
@@ -1629,7 +1523,7 @@ static int gfx_v8_0_do_edc_gpr_workarounds(struct amdgpu_device *adev)
return 0;
/* bail if the compute ring is not ready */
- if (!ring->ready)
+ if (!ring->sched.ready)
return 0;
tmp = RREG32(mmGB_EDC_MODE);
@@ -2088,7 +1982,7 @@ static int gfx_v8_0_sw_init(void *handle)
return r;
}
- r = gfx_v8_0_rlc_init(adev);
+ r = adev->gfx.rlc.funcs->init(adev);
if (r) {
DRM_ERROR("Failed to init rlc BOs!\n");
return r;
@@ -2181,7 +2075,7 @@ static int gfx_v8_0_sw_fini(void *handle)
amdgpu_gfx_kiq_fini(adev);
gfx_v8_0_mec_fini(adev);
- gfx_v8_0_rlc_fini(adev);
+ amdgpu_gfx_rlc_fini(adev);
amdgpu_bo_free_kernel(&adev->gfx.rlc.clear_state_obj,
&adev->gfx.rlc.clear_state_gpu_addr,
(void **)&adev->gfx.rlc.cs_ptr);
@@ -4175,10 +4069,10 @@ static void gfx_v8_0_rlc_start(struct amdgpu_device *adev)
static int gfx_v8_0_rlc_resume(struct amdgpu_device *adev)
{
- gfx_v8_0_rlc_stop(adev);
- gfx_v8_0_rlc_reset(adev);
+ adev->gfx.rlc.funcs->stop(adev);
+ adev->gfx.rlc.funcs->reset(adev);
gfx_v8_0_init_pg(adev);
- gfx_v8_0_rlc_start(adev);
+ adev->gfx.rlc.funcs->start(adev);
return 0;
}
@@ -4197,7 +4091,7 @@ static void gfx_v8_0_cp_gfx_enable(struct amdgpu_device *adev, bool enable)
tmp = REG_SET_FIELD(tmp, CP_ME_CNTL, PFP_HALT, 1);
tmp = REG_SET_FIELD(tmp, CP_ME_CNTL, CE_HALT, 1);
for (i = 0; i < adev->gfx.num_gfx_rings; i++)
- adev->gfx.gfx_ring[i].ready = false;
+ adev->gfx.gfx_ring[i].sched.ready = false;
}
WREG32(mmCP_ME_CNTL, tmp);
udelay(50);
@@ -4379,10 +4273,8 @@ static int gfx_v8_0_cp_gfx_resume(struct amdgpu_device *adev)
/* start the ring */
amdgpu_ring_clear_ring(ring);
gfx_v8_0_cp_gfx_start(adev);
- ring->ready = true;
- r = amdgpu_ring_test_ring(ring);
- if (r)
- ring->ready = false;
+ ring->sched.ready = true;
+ r = amdgpu_ring_test_helper(ring);
return r;
}
@@ -4396,8 +4288,8 @@ static void gfx_v8_0_cp_compute_enable(struct amdgpu_device *adev, bool enable)
} else {
WREG32(mmCP_MEC_CNTL, (CP_MEC_CNTL__MEC_ME1_HALT_MASK | CP_MEC_CNTL__MEC_ME2_HALT_MASK));
for (i = 0; i < adev->gfx.num_compute_rings; i++)
- adev->gfx.compute_ring[i].ready = false;
- adev->gfx.kiq.ring.ready = false;
+ adev->gfx.compute_ring[i].sched.ready = false;
+ adev->gfx.kiq.ring.sched.ready = false;
}
udelay(50);
}
@@ -4473,11 +4365,9 @@ static int gfx_v8_0_kiq_kcq_enable(struct amdgpu_device *adev)
amdgpu_ring_write(kiq_ring, upper_32_bits(wptr_addr));
}
- r = amdgpu_ring_test_ring(kiq_ring);
- if (r) {
+ r = amdgpu_ring_test_helper(kiq_ring);
+ if (r)
DRM_ERROR("KCQ enable failed\n");
- kiq_ring->ready = false;
- }
return r;
}
@@ -4781,7 +4671,7 @@ static int gfx_v8_0_kiq_resume(struct amdgpu_device *adev)
amdgpu_bo_kunmap(ring->mqd_obj);
ring->mqd_ptr = NULL;
amdgpu_bo_unreserve(ring->mqd_obj);
- ring->ready = true;
+ ring->sched.ready = true;
return 0;
}
@@ -4820,10 +4710,7 @@ static int gfx_v8_0_kcq_resume(struct amdgpu_device *adev)
*/
for (i = adev->gfx.num_compute_rings - 1; i >= 0; i--) {
ring = &adev->gfx.compute_ring[i];
- ring->ready = true;
- r = amdgpu_ring_test_ring(ring);
- if (r)
- ring->ready = false;
+ r = amdgpu_ring_test_helper(ring);
}
done:
@@ -4867,7 +4754,7 @@ static int gfx_v8_0_hw_init(void *handle)
gfx_v8_0_init_golden_registers(adev);
gfx_v8_0_constants_init(adev);
- r = gfx_v8_0_rlc_resume(adev);
+ r = adev->gfx.rlc.funcs->resume(adev);
if (r)
return r;
@@ -4899,7 +4786,7 @@ static int gfx_v8_0_kcq_disable(struct amdgpu_device *adev)
amdgpu_ring_write(kiq_ring, 0);
amdgpu_ring_write(kiq_ring, 0);
}
- r = amdgpu_ring_test_ring(kiq_ring);
+ r = amdgpu_ring_test_helper(kiq_ring);
if (r)
DRM_ERROR("KCQ disable failed\n");
@@ -4973,16 +4860,16 @@ static int gfx_v8_0_hw_fini(void *handle)
pr_debug("For SRIOV client, shouldn't do anything.\n");
return 0;
}
- adev->gfx.rlc.funcs->enter_safe_mode(adev);
+ amdgpu_gfx_rlc_enter_safe_mode(adev);
if (!gfx_v8_0_wait_for_idle(adev))
gfx_v8_0_cp_enable(adev, false);
else
pr_err("cp is busy, skip halt cp\n");
if (!gfx_v8_0_wait_for_rlc_idle(adev))
- gfx_v8_0_rlc_stop(adev);
+ adev->gfx.rlc.funcs->stop(adev);
else
pr_err("rlc is busy, skip halt rlc\n");
- adev->gfx.rlc.funcs->exit_safe_mode(adev);
+ amdgpu_gfx_rlc_exit_safe_mode(adev);
return 0;
}
@@ -5071,7 +4958,7 @@ static int gfx_v8_0_pre_soft_reset(void *handle)
srbm_soft_reset = adev->gfx.srbm_soft_reset;
/* stop the rlc */
- gfx_v8_0_rlc_stop(adev);
+ adev->gfx.rlc.funcs->stop(adev);
if (REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CP) ||
REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_GFX))
@@ -5197,7 +5084,7 @@ static int gfx_v8_0_post_soft_reset(void *handle)
REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_GFX))
gfx_v8_0_cp_gfx_resume(adev);
- gfx_v8_0_rlc_start(adev);
+ adev->gfx.rlc.funcs->start(adev);
return 0;
}
@@ -5445,7 +5332,7 @@ static int gfx_v8_0_set_powergating_state(void *handle,
AMD_PG_SUPPORT_RLC_SMU_HS |
AMD_PG_SUPPORT_CP |
AMD_PG_SUPPORT_GFX_DMG))
- adev->gfx.rlc.funcs->enter_safe_mode(adev);
+ amdgpu_gfx_rlc_enter_safe_mode(adev);
switch (adev->asic_type) {
case CHIP_CARRIZO:
case CHIP_STONEY:
@@ -5499,7 +5386,7 @@ static int gfx_v8_0_set_powergating_state(void *handle,
AMD_PG_SUPPORT_RLC_SMU_HS |
AMD_PG_SUPPORT_CP |
AMD_PG_SUPPORT_GFX_DMG))
- adev->gfx.rlc.funcs->exit_safe_mode(adev);
+ amdgpu_gfx_rlc_exit_safe_mode(adev);
return 0;
}
@@ -5593,57 +5480,53 @@ static void gfx_v8_0_send_serdes_cmd(struct amdgpu_device *adev,
#define RLC_GPR_REG2__MESSAGE__SHIFT 0x00000001
#define RLC_GPR_REG2__MESSAGE_MASK 0x0000001e
-static void iceland_enter_rlc_safe_mode(struct amdgpu_device *adev)
+static bool gfx_v8_0_is_rlc_enabled(struct amdgpu_device *adev)
{
- u32 data;
- unsigned i;
+ uint32_t rlc_setting;
- data = RREG32(mmRLC_CNTL);
- if (!(data & RLC_CNTL__RLC_ENABLE_F32_MASK))
- return;
+ rlc_setting = RREG32(mmRLC_CNTL);
+ if (!(rlc_setting & RLC_CNTL__RLC_ENABLE_F32_MASK))
+ return false;
- if (adev->cg_flags & (AMD_CG_SUPPORT_GFX_CGCG | AMD_CG_SUPPORT_GFX_MGCG)) {
- data |= RLC_SAFE_MODE__CMD_MASK;
- data &= ~RLC_SAFE_MODE__MESSAGE_MASK;
- data |= (1 << RLC_SAFE_MODE__MESSAGE__SHIFT);
- WREG32(mmRLC_SAFE_MODE, data);
+ return true;
+}
- for (i = 0; i < adev->usec_timeout; i++) {
- if ((RREG32(mmRLC_GPM_STAT) &
- (RLC_GPM_STAT__GFX_CLOCK_STATUS_MASK |
- RLC_GPM_STAT__GFX_POWER_STATUS_MASK)) ==
- (RLC_GPM_STAT__GFX_CLOCK_STATUS_MASK |
- RLC_GPM_STAT__GFX_POWER_STATUS_MASK))
- break;
- udelay(1);
- }
+static void gfx_v8_0_set_safe_mode(struct amdgpu_device *adev)
+{
+ uint32_t data;
+ unsigned i;
+ data = RREG32(mmRLC_CNTL);
+ data |= RLC_SAFE_MODE__CMD_MASK;
+ data &= ~RLC_SAFE_MODE__MESSAGE_MASK;
+ data |= (1 << RLC_SAFE_MODE__MESSAGE__SHIFT);
+ WREG32(mmRLC_SAFE_MODE, data);
- for (i = 0; i < adev->usec_timeout; i++) {
- if (!REG_GET_FIELD(RREG32(mmRLC_SAFE_MODE), RLC_SAFE_MODE, CMD))
- break;
- udelay(1);
- }
- adev->gfx.rlc.in_safe_mode = true;
+ /* wait for RLC_SAFE_MODE */
+ for (i = 0; i < adev->usec_timeout; i++) {
+ if ((RREG32(mmRLC_GPM_STAT) &
+ (RLC_GPM_STAT__GFX_CLOCK_STATUS_MASK |
+ RLC_GPM_STAT__GFX_POWER_STATUS_MASK)) ==
+ (RLC_GPM_STAT__GFX_CLOCK_STATUS_MASK |
+ RLC_GPM_STAT__GFX_POWER_STATUS_MASK))
+ break;
+ udelay(1);
+ }
+ for (i = 0; i < adev->usec_timeout; i++) {
+ if (!REG_GET_FIELD(RREG32(mmRLC_SAFE_MODE), RLC_SAFE_MODE, CMD))
+ break;
+ udelay(1);
}
}
-static void iceland_exit_rlc_safe_mode(struct amdgpu_device *adev)
+static void gfx_v8_0_unset_safe_mode(struct amdgpu_device *adev)
{
- u32 data = 0;
+ uint32_t data;
unsigned i;
data = RREG32(mmRLC_CNTL);
- if (!(data & RLC_CNTL__RLC_ENABLE_F32_MASK))
- return;
-
- if (adev->cg_flags & (AMD_CG_SUPPORT_GFX_CGCG | AMD_CG_SUPPORT_GFX_MGCG)) {
- if (adev->gfx.rlc.in_safe_mode) {
- data |= RLC_SAFE_MODE__CMD_MASK;
- data &= ~RLC_SAFE_MODE__MESSAGE_MASK;
- WREG32(mmRLC_SAFE_MODE, data);
- adev->gfx.rlc.in_safe_mode = false;
- }
- }
+ data |= RLC_SAFE_MODE__CMD_MASK;
+ data &= ~RLC_SAFE_MODE__MESSAGE_MASK;
+ WREG32(mmRLC_SAFE_MODE, data);
for (i = 0; i < adev->usec_timeout; i++) {
if (!REG_GET_FIELD(RREG32(mmRLC_SAFE_MODE), RLC_SAFE_MODE, CMD))
@@ -5653,8 +5536,17 @@ static void iceland_exit_rlc_safe_mode(struct amdgpu_device *adev)
}
static const struct amdgpu_rlc_funcs iceland_rlc_funcs = {
- .enter_safe_mode = iceland_enter_rlc_safe_mode,
- .exit_safe_mode = iceland_exit_rlc_safe_mode
+ .is_rlc_enabled = gfx_v8_0_is_rlc_enabled,
+ .set_safe_mode = gfx_v8_0_set_safe_mode,
+ .unset_safe_mode = gfx_v8_0_unset_safe_mode,
+ .init = gfx_v8_0_rlc_init,
+ .get_csb_size = gfx_v8_0_get_csb_size,
+ .get_csb_buffer = gfx_v8_0_get_csb_buffer,
+ .get_cp_table_num = gfx_v8_0_cp_jump_table_num,
+ .resume = gfx_v8_0_rlc_resume,
+ .stop = gfx_v8_0_rlc_stop,
+ .reset = gfx_v8_0_rlc_reset,
+ .start = gfx_v8_0_rlc_start
};
static void gfx_v8_0_update_medium_grain_clock_gating(struct amdgpu_device *adev,
@@ -5662,7 +5554,7 @@ static void gfx_v8_0_update_medium_grain_clock_gating(struct amdgpu_device *adev
{
uint32_t temp, data;
- adev->gfx.rlc.funcs->enter_safe_mode(adev);
+ amdgpu_gfx_rlc_enter_safe_mode(adev);
/* It is disabled by HW by default */
if (enable && (adev->cg_flags & AMD_CG_SUPPORT_GFX_MGCG)) {
@@ -5758,7 +5650,7 @@ static void gfx_v8_0_update_medium_grain_clock_gating(struct amdgpu_device *adev
gfx_v8_0_wait_for_rlc_serdes(adev);
}
- adev->gfx.rlc.funcs->exit_safe_mode(adev);
+ amdgpu_gfx_rlc_exit_safe_mode(adev);
}
static void gfx_v8_0_update_coarse_grain_clock_gating(struct amdgpu_device *adev,
@@ -5768,7 +5660,7 @@ static void gfx_v8_0_update_coarse_grain_clock_gating(struct amdgpu_device *adev
temp = data = RREG32(mmRLC_CGCG_CGLS_CTRL);
- adev->gfx.rlc.funcs->enter_safe_mode(adev);
+ amdgpu_gfx_rlc_enter_safe_mode(adev);
if (enable && (adev->cg_flags & AMD_CG_SUPPORT_GFX_CGCG)) {
temp1 = data1 = RREG32(mmRLC_CGTT_MGCG_OVERRIDE);
@@ -5851,7 +5743,7 @@ static void gfx_v8_0_update_coarse_grain_clock_gating(struct amdgpu_device *adev
gfx_v8_0_wait_for_rlc_serdes(adev);
- adev->gfx.rlc.funcs->exit_safe_mode(adev);
+ amdgpu_gfx_rlc_exit_safe_mode(adev);
}
static int gfx_v8_0_update_gfx_clock_gating(struct amdgpu_device *adev,
bool enable)
@@ -6131,9 +6023,11 @@ static void gfx_v8_0_ring_emit_vgt_flush(struct amdgpu_ring *ring)
}
static void gfx_v8_0_ring_emit_ib_gfx(struct amdgpu_ring *ring,
- struct amdgpu_ib *ib,
- unsigned vmid, bool ctx_switch)
+ struct amdgpu_job *job,
+ struct amdgpu_ib *ib,
+ bool ctx_switch)
{
+ unsigned vmid = AMDGPU_JOB_GET_VMID(job);
u32 header, control = 0;
if (ib->flags & AMDGPU_IB_FLAG_CE)
@@ -6161,9 +6055,11 @@ static void gfx_v8_0_ring_emit_ib_gfx(struct amdgpu_ring *ring,
}
static void gfx_v8_0_ring_emit_ib_compute(struct amdgpu_ring *ring,
+ struct amdgpu_job *job,
struct amdgpu_ib *ib,
- unsigned vmid, bool ctx_switch)
+ bool ctx_switch)
{
+ unsigned vmid = AMDGPU_JOB_GET_VMID(job);
u32 control = INDIRECT_BUFFER_VALID | ib->length_dw | (vmid << 24);
amdgpu_ring_write(ring, PACKET3(PACKET3_INDIRECT_BUFFER, 2));
@@ -6738,12 +6634,39 @@ static int gfx_v8_0_eop_irq(struct amdgpu_device *adev,
return 0;
}
+static void gfx_v8_0_fault(struct amdgpu_device *adev,
+ struct amdgpu_iv_entry *entry)
+{
+ u8 me_id, pipe_id, queue_id;
+ struct amdgpu_ring *ring;
+ int i;
+
+ me_id = (entry->ring_id & 0x0c) >> 2;
+ pipe_id = (entry->ring_id & 0x03) >> 0;
+ queue_id = (entry->ring_id & 0x70) >> 4;
+
+ switch (me_id) {
+ case 0:
+ drm_sched_fault(&adev->gfx.gfx_ring[0].sched);
+ break;
+ case 1:
+ case 2:
+ for (i = 0; i < adev->gfx.num_compute_rings; i++) {
+ ring = &adev->gfx.compute_ring[i];
+ if (ring->me == me_id && ring->pipe == pipe_id &&
+ ring->queue == queue_id)
+ drm_sched_fault(&ring->sched);
+ }
+ break;
+ }
+}
+
static int gfx_v8_0_priv_reg_irq(struct amdgpu_device *adev,
struct amdgpu_irq_src *source,
struct amdgpu_iv_entry *entry)
{
DRM_ERROR("Illegal register access in command stream\n");
- schedule_work(&adev->reset_work);
+ gfx_v8_0_fault(adev, entry);
return 0;
}
@@ -6752,7 +6675,7 @@ static int gfx_v8_0_priv_inst_irq(struct amdgpu_device *adev,
struct amdgpu_iv_entry *entry)
{
DRM_ERROR("Illegal instruction in command stream\n");
- schedule_work(&adev->reset_work);
+ gfx_v8_0_fault(adev, entry);
return 0;
}
@@ -6976,10 +6899,8 @@ static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_kiq = {
17 + /* gfx_v8_0_ring_emit_vm_flush */
7 + 7 + 7, /* gfx_v8_0_ring_emit_fence_kiq x3 for user fence, vm fence */
.emit_ib_size = 4, /* gfx_v8_0_ring_emit_ib_compute */
- .emit_ib = gfx_v8_0_ring_emit_ib_compute,
.emit_fence = gfx_v8_0_ring_emit_fence_kiq,
.test_ring = gfx_v8_0_ring_test_ring,
- .test_ib = gfx_v8_0_ring_test_ib,
.insert_nop = amdgpu_ring_insert_nop,
.pad_ib = amdgpu_ring_generic_pad_ib,
.emit_rreg = gfx_v8_0_ring_emit_rreg,
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
index 6d7baf59d6e1..c27caa144c57 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
@@ -41,7 +41,7 @@
#include "ivsrcid/gfx/irqsrcs_gfx_9_0.h"
#define GFX9_NUM_GFX_RINGS 1
-#define GFX9_MEC_HPD_SIZE 2048
+#define GFX9_MEC_HPD_SIZE 4096
#define RLCG_UCODE_LOADING_START_ADDRESS 0x00002000L
#define RLC_SAVE_RESTORE_ADDR_STARTING_OFFSET 0x00000000L
@@ -396,18 +396,14 @@ static int gfx_v9_0_ring_test_ring(struct amdgpu_ring *ring)
int r;
r = amdgpu_gfx_scratch_get(adev, &scratch);
- if (r) {
- DRM_ERROR("amdgpu: cp failed to get scratch reg (%d).\n", r);
+ if (r)
return r;
- }
+
WREG32(scratch, 0xCAFEDEAD);
r = amdgpu_ring_alloc(ring, 3);
- if (r) {
- DRM_ERROR("amdgpu: cp failed to lock ring %d (%d).\n",
- ring->idx, r);
- amdgpu_gfx_scratch_free(adev, scratch);
- return r;
- }
+ if (r)
+ goto error_free_scratch;
+
amdgpu_ring_write(ring, PACKET3(PACKET3_SET_UCONFIG_REG, 1));
amdgpu_ring_write(ring, (scratch - PACKET3_SET_UCONFIG_REG_START));
amdgpu_ring_write(ring, 0xDEADBEEF);
@@ -419,14 +415,11 @@ static int gfx_v9_0_ring_test_ring(struct amdgpu_ring *ring)
break;
DRM_UDELAY(1);
}
- if (i < adev->usec_timeout) {
- DRM_DEBUG("ring test on %d succeeded in %d usecs\n",
- ring->idx, i);
- } else {
- DRM_ERROR("amdgpu: ring %d test failed (scratch(0x%04X)=0x%08X)\n",
- ring->idx, scratch, tmp);
- r = -EINVAL;
- }
+
+ if (i >= adev->usec_timeout)
+ r = -ETIMEDOUT;
+
+error_free_scratch:
amdgpu_gfx_scratch_free(adev, scratch);
return r;
}
@@ -443,19 +436,16 @@ static int gfx_v9_0_ring_test_ib(struct amdgpu_ring *ring, long timeout)
long r;
r = amdgpu_device_wb_get(adev, &index);
- if (r) {
- dev_err(adev->dev, "(%ld) failed to allocate wb slot\n", r);
+ if (r)
return r;
- }
gpu_addr = adev->wb.gpu_addr + (index * 4);
adev->wb.wb[index] = cpu_to_le32(0xCAFEDEAD);
memset(&ib, 0, sizeof(ib));
r = amdgpu_ib_get(adev, NULL, 16, &ib);
- if (r) {
- DRM_ERROR("amdgpu: failed to get ib (%ld).\n", r);
+ if (r)
goto err1;
- }
+
ib.ptr[0] = PACKET3(PACKET3_WRITE_DATA, 3);
ib.ptr[1] = WRITE_DATA_DST_SEL(5) | WR_CONFIRM;
ib.ptr[2] = lower_32_bits(gpu_addr);
@@ -469,22 +459,17 @@ static int gfx_v9_0_ring_test_ib(struct amdgpu_ring *ring, long timeout)
r = dma_fence_wait_timeout(f, false, timeout);
if (r == 0) {
- DRM_ERROR("amdgpu: IB test timed out.\n");
- r = -ETIMEDOUT;
- goto err2;
+ r = -ETIMEDOUT;
+ goto err2;
} else if (r < 0) {
- DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r);
- goto err2;
+ goto err2;
}
tmp = adev->wb.wb[index];
- if (tmp == 0xDEADBEEF) {
- DRM_DEBUG("ib test on ring %d succeeded\n", ring->idx);
- r = 0;
- } else {
- DRM_ERROR("ib test on ring %d failed\n", ring->idx);
- r = -EINVAL;
- }
+ if (tmp == 0xDEADBEEF)
+ r = 0;
+ else
+ r = -EINVAL;
err2:
amdgpu_ib_free(adev, &ib, NULL);
@@ -1065,85 +1050,13 @@ static void gfx_v9_0_enable_lbpw(struct amdgpu_device *adev, bool enable)
WREG32_FIELD15(GC, 0, RLC_LB_CNTL, LOAD_BALANCE_ENABLE, enable ? 1 : 0);
}
-static void rv_init_cp_jump_table(struct amdgpu_device *adev)
-{
- const __le32 *fw_data;
- volatile u32 *dst_ptr;
- int me, i, max_me = 5;
- u32 bo_offset = 0;
- u32 table_offset, table_size;
-
- /* write the cp table buffer */
- dst_ptr = adev->gfx.rlc.cp_table_ptr;
- for (me = 0; me < max_me; me++) {
- if (me == 0) {
- const struct gfx_firmware_header_v1_0 *hdr =
- (const struct gfx_firmware_header_v1_0 *)adev->gfx.ce_fw->data;
- fw_data = (const __le32 *)
- (adev->gfx.ce_fw->data +
- le32_to_cpu(hdr->header.ucode_array_offset_bytes));
- table_offset = le32_to_cpu(hdr->jt_offset);
- table_size = le32_to_cpu(hdr->jt_size);
- } else if (me == 1) {
- const struct gfx_firmware_header_v1_0 *hdr =
- (const struct gfx_firmware_header_v1_0 *)adev->gfx.pfp_fw->data;
- fw_data = (const __le32 *)
- (adev->gfx.pfp_fw->data +
- le32_to_cpu(hdr->header.ucode_array_offset_bytes));
- table_offset = le32_to_cpu(hdr->jt_offset);
- table_size = le32_to_cpu(hdr->jt_size);
- } else if (me == 2) {
- const struct gfx_firmware_header_v1_0 *hdr =
- (const struct gfx_firmware_header_v1_0 *)adev->gfx.me_fw->data;
- fw_data = (const __le32 *)
- (adev->gfx.me_fw->data +
- le32_to_cpu(hdr->header.ucode_array_offset_bytes));
- table_offset = le32_to_cpu(hdr->jt_offset);
- table_size = le32_to_cpu(hdr->jt_size);
- } else if (me == 3) {
- const struct gfx_firmware_header_v1_0 *hdr =
- (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data;
- fw_data = (const __le32 *)
- (adev->gfx.mec_fw->data +
- le32_to_cpu(hdr->header.ucode_array_offset_bytes));
- table_offset = le32_to_cpu(hdr->jt_offset);
- table_size = le32_to_cpu(hdr->jt_size);
- } else if (me == 4) {
- const struct gfx_firmware_header_v1_0 *hdr =
- (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec2_fw->data;
- fw_data = (const __le32 *)
- (adev->gfx.mec2_fw->data +
- le32_to_cpu(hdr->header.ucode_array_offset_bytes));
- table_offset = le32_to_cpu(hdr->jt_offset);
- table_size = le32_to_cpu(hdr->jt_size);
- }
-
- for (i = 0; i < table_size; i ++) {
- dst_ptr[bo_offset + i] =
- cpu_to_le32(le32_to_cpu(fw_data[table_offset + i]));
- }
-
- bo_offset += table_size;
- }
-}
-
-static void gfx_v9_0_rlc_fini(struct amdgpu_device *adev)
+static int gfx_v9_0_cp_jump_table_num(struct amdgpu_device *adev)
{
- /* clear state block */
- amdgpu_bo_free_kernel(&adev->gfx.rlc.clear_state_obj,
- &adev->gfx.rlc.clear_state_gpu_addr,
- (void **)&adev->gfx.rlc.cs_ptr);
-
- /* jump table block */
- amdgpu_bo_free_kernel(&adev->gfx.rlc.cp_table_obj,
- &adev->gfx.rlc.cp_table_gpu_addr,
- (void **)&adev->gfx.rlc.cp_table_ptr);
+ return 5;
}
static int gfx_v9_0_rlc_init(struct amdgpu_device *adev)
{
- volatile u32 *dst_ptr;
- u32 dws;
const struct cs_section_def *cs_data;
int r;
@@ -1152,45 +1065,18 @@ static int gfx_v9_0_rlc_init(struct amdgpu_device *adev)
cs_data = adev->gfx.rlc.cs_data;
if (cs_data) {
- /* clear state block */
- adev->gfx.rlc.clear_state_size = dws = gfx_v9_0_get_csb_size(adev);
- r = amdgpu_bo_create_reserved(adev, dws * 4, PAGE_SIZE,
- AMDGPU_GEM_DOMAIN_VRAM,
- &adev->gfx.rlc.clear_state_obj,
- &adev->gfx.rlc.clear_state_gpu_addr,
- (void **)&adev->gfx.rlc.cs_ptr);
- if (r) {
- dev_err(adev->dev, "(%d) failed to create rlc csb bo\n",
- r);
- gfx_v9_0_rlc_fini(adev);
+ /* init clear state block */
+ r = amdgpu_gfx_rlc_init_csb(adev);
+ if (r)
return r;
- }
- /* set up the cs buffer */
- dst_ptr = adev->gfx.rlc.cs_ptr;
- gfx_v9_0_get_csb_buffer(adev, dst_ptr);
- amdgpu_bo_kunmap(adev->gfx.rlc.clear_state_obj);
- amdgpu_bo_unpin(adev->gfx.rlc.clear_state_obj);
- amdgpu_bo_unreserve(adev->gfx.rlc.clear_state_obj);
}
if (adev->asic_type == CHIP_RAVEN) {
/* TODO: double check the cp_table_size for RV */
adev->gfx.rlc.cp_table_size = ALIGN(96 * 5 * 4, 2048) + (64 * 1024); /* JT + GDS */
- r = amdgpu_bo_create_reserved(adev, adev->gfx.rlc.cp_table_size,
- PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM,
- &adev->gfx.rlc.cp_table_obj,
- &adev->gfx.rlc.cp_table_gpu_addr,
- (void **)&adev->gfx.rlc.cp_table_ptr);
- if (r) {
- dev_err(adev->dev,
- "(%d) failed to create cp table bo\n", r);
- gfx_v9_0_rlc_fini(adev);
+ r = amdgpu_gfx_rlc_init_cpt(adev);
+ if (r)
return r;
- }
-
- rv_init_cp_jump_table(adev);
- amdgpu_bo_kunmap(adev->gfx.rlc.cp_table_obj);
- amdgpu_bo_unreserve(adev->gfx.rlc.cp_table_obj);
}
switch (adev->asic_type) {
@@ -1264,7 +1150,7 @@ static int gfx_v9_0_mec_init(struct amdgpu_device *adev)
mec_hpd_size = adev->gfx.num_compute_rings * GFX9_MEC_HPD_SIZE;
r = amdgpu_bo_create_reserved(adev, mec_hpd_size, PAGE_SIZE,
- AMDGPU_GEM_DOMAIN_GTT,
+ AMDGPU_GEM_DOMAIN_VRAM,
&adev->gfx.mec.hpd_eop_obj,
&adev->gfx.mec.hpd_eop_gpu_addr,
(void **)&hpd);
@@ -1635,8 +1521,8 @@ static int gfx_v9_0_ngg_en(struct amdgpu_device *adev)
/* Clear GDS reserved memory */
r = amdgpu_ring_alloc(ring, 17);
if (r) {
- DRM_ERROR("amdgpu: NGG failed to lock ring %d (%d).\n",
- ring->idx, r);
+ DRM_ERROR("amdgpu: NGG failed to lock ring %s (%d).\n",
+ ring->name, r);
return r;
}
@@ -1748,7 +1634,7 @@ static int gfx_v9_0_sw_init(void *handle)
return r;
}
- r = gfx_v9_0_rlc_init(adev);
+ r = adev->gfx.rlc.funcs->init(adev);
if (r) {
DRM_ERROR("Failed to init rlc BOs!\n");
return r;
@@ -2498,12 +2384,12 @@ static int gfx_v9_0_rlc_resume(struct amdgpu_device *adev)
return 0;
}
- gfx_v9_0_rlc_stop(adev);
+ adev->gfx.rlc.funcs->stop(adev);
/* disable CG */
WREG32_SOC15(GC, 0, mmRLC_CGCG_CGLS_CTRL, 0);
- gfx_v9_0_rlc_reset(adev);
+ adev->gfx.rlc.funcs->reset(adev);
gfx_v9_0_init_pg(adev);
@@ -2514,15 +2400,24 @@ static int gfx_v9_0_rlc_resume(struct amdgpu_device *adev)
return r;
}
- if (adev->asic_type == CHIP_RAVEN ||
- adev->asic_type == CHIP_VEGA20) {
- if (amdgpu_lbpw != 0)
+ switch (adev->asic_type) {
+ case CHIP_RAVEN:
+ if (amdgpu_lbpw == 0)
+ gfx_v9_0_enable_lbpw(adev, false);
+ else
+ gfx_v9_0_enable_lbpw(adev, true);
+ break;
+ case CHIP_VEGA20:
+ if (amdgpu_lbpw > 0)
gfx_v9_0_enable_lbpw(adev, true);
else
gfx_v9_0_enable_lbpw(adev, false);
+ break;
+ default:
+ break;
}
- gfx_v9_0_rlc_start(adev);
+ adev->gfx.rlc.funcs->start(adev);
return 0;
}
@@ -2537,7 +2432,7 @@ static void gfx_v9_0_cp_gfx_enable(struct amdgpu_device *adev, bool enable)
tmp = REG_SET_FIELD(tmp, CP_ME_CNTL, CE_HALT, enable ? 0 : 1);
if (!enable) {
for (i = 0; i < adev->gfx.num_gfx_rings; i++)
- adev->gfx.gfx_ring[i].ready = false;
+ adev->gfx.gfx_ring[i].sched.ready = false;
}
WREG32_SOC15(GC, 0, mmCP_ME_CNTL, tmp);
udelay(50);
@@ -2727,7 +2622,7 @@ static int gfx_v9_0_cp_gfx_resume(struct amdgpu_device *adev)
/* start the ring */
gfx_v9_0_cp_gfx_start(adev);
- ring->ready = true;
+ ring->sched.ready = true;
return 0;
}
@@ -2742,8 +2637,8 @@ static void gfx_v9_0_cp_compute_enable(struct amdgpu_device *adev, bool enable)
WREG32_SOC15(GC, 0, mmCP_MEC_CNTL,
(CP_MEC_CNTL__MEC_ME1_HALT_MASK | CP_MEC_CNTL__MEC_ME2_HALT_MASK));
for (i = 0; i < adev->gfx.num_compute_rings; i++)
- adev->gfx.compute_ring[i].ready = false;
- adev->gfx.kiq.ring.ready = false;
+ adev->gfx.compute_ring[i].sched.ready = false;
+ adev->gfx.kiq.ring.sched.ready = false;
}
udelay(50);
}
@@ -2866,11 +2761,9 @@ static int gfx_v9_0_kiq_kcq_enable(struct amdgpu_device *adev)
amdgpu_ring_write(kiq_ring, upper_32_bits(wptr_addr));
}
- r = amdgpu_ring_test_ring(kiq_ring);
- if (r) {
+ r = amdgpu_ring_test_helper(kiq_ring);
+ if (r)
DRM_ERROR("KCQ enable failed\n");
- kiq_ring->ready = false;
- }
return r;
}
@@ -3249,7 +3142,7 @@ static int gfx_v9_0_kiq_resume(struct amdgpu_device *adev)
amdgpu_bo_kunmap(ring->mqd_obj);
ring->mqd_ptr = NULL;
amdgpu_bo_unreserve(ring->mqd_obj);
- ring->ready = true;
+ ring->sched.ready = true;
return 0;
}
@@ -3314,19 +3207,13 @@ static int gfx_v9_0_cp_resume(struct amdgpu_device *adev)
return r;
ring = &adev->gfx.gfx_ring[0];
- r = amdgpu_ring_test_ring(ring);
- if (r) {
- ring->ready = false;
+ r = amdgpu_ring_test_helper(ring);
+ if (r)
return r;
- }
for (i = 0; i < adev->gfx.num_compute_rings; i++) {
ring = &adev->gfx.compute_ring[i];
-
- ring->ready = true;
- r = amdgpu_ring_test_ring(ring);
- if (r)
- ring->ready = false;
+ amdgpu_ring_test_helper(ring);
}
gfx_v9_0_enable_gui_idle_interrupt(adev, true);
@@ -3353,7 +3240,7 @@ static int gfx_v9_0_hw_init(void *handle)
if (r)
return r;
- r = gfx_v9_0_rlc_resume(adev);
+ r = adev->gfx.rlc.funcs->resume(adev);
if (r)
return r;
@@ -3391,7 +3278,7 @@ static int gfx_v9_0_kcq_disable(struct amdgpu_device *adev)
amdgpu_ring_write(kiq_ring, 0);
amdgpu_ring_write(kiq_ring, 0);
}
- r = amdgpu_ring_test_ring(kiq_ring);
+ r = amdgpu_ring_test_helper(kiq_ring);
if (r)
DRM_ERROR("KCQ disable failed\n");
@@ -3433,7 +3320,7 @@ static int gfx_v9_0_hw_fini(void *handle)
}
gfx_v9_0_cp_enable(adev, false);
- gfx_v9_0_rlc_stop(adev);
+ adev->gfx.rlc.funcs->stop(adev);
gfx_v9_0_csb_vram_unpin(adev);
@@ -3508,7 +3395,7 @@ static int gfx_v9_0_soft_reset(void *handle)
if (grbm_soft_reset) {
/* stop the rlc */
- gfx_v9_0_rlc_stop(adev);
+ adev->gfx.rlc.funcs->stop(adev);
/* Disable GFX parsing/prefetching */
gfx_v9_0_cp_gfx_enable(adev, false);
@@ -3607,64 +3494,47 @@ static int gfx_v9_0_late_init(void *handle)
return 0;
}
-static void gfx_v9_0_enter_rlc_safe_mode(struct amdgpu_device *adev)
+static bool gfx_v9_0_is_rlc_enabled(struct amdgpu_device *adev)
{
- uint32_t rlc_setting, data;
- unsigned i;
-
- if (adev->gfx.rlc.in_safe_mode)
- return;
+ uint32_t rlc_setting;
/* if RLC is not enabled, do nothing */
rlc_setting = RREG32_SOC15(GC, 0, mmRLC_CNTL);
if (!(rlc_setting & RLC_CNTL__RLC_ENABLE_F32_MASK))
- return;
-
- if (adev->cg_flags &
- (AMD_CG_SUPPORT_GFX_CGCG | AMD_CG_SUPPORT_GFX_MGCG |
- AMD_CG_SUPPORT_GFX_3D_CGCG)) {
- data = RLC_SAFE_MODE__CMD_MASK;
- data |= (1 << RLC_SAFE_MODE__MESSAGE__SHIFT);
- WREG32_SOC15(GC, 0, mmRLC_SAFE_MODE, data);
+ return false;
- /* wait for RLC_SAFE_MODE */
- for (i = 0; i < adev->usec_timeout; i++) {
- if (!REG_GET_FIELD(RREG32_SOC15(GC, 0, mmRLC_SAFE_MODE), RLC_SAFE_MODE, CMD))
- break;
- udelay(1);
- }
- adev->gfx.rlc.in_safe_mode = true;
- }
+ return true;
}
-static void gfx_v9_0_exit_rlc_safe_mode(struct amdgpu_device *adev)
+static void gfx_v9_0_set_safe_mode(struct amdgpu_device *adev)
{
- uint32_t rlc_setting, data;
-
- if (!adev->gfx.rlc.in_safe_mode)
- return;
+ uint32_t data;
+ unsigned i;
- /* if RLC is not enabled, do nothing */
- rlc_setting = RREG32_SOC15(GC, 0, mmRLC_CNTL);
- if (!(rlc_setting & RLC_CNTL__RLC_ENABLE_F32_MASK))
- return;
+ data = RLC_SAFE_MODE__CMD_MASK;
+ data |= (1 << RLC_SAFE_MODE__MESSAGE__SHIFT);
+ WREG32_SOC15(GC, 0, mmRLC_SAFE_MODE, data);
- if (adev->cg_flags &
- (AMD_CG_SUPPORT_GFX_CGCG | AMD_CG_SUPPORT_GFX_MGCG)) {
- /*
- * Try to exit safe mode only if it is already in safe
- * mode.
- */
- data = RLC_SAFE_MODE__CMD_MASK;
- WREG32_SOC15(GC, 0, mmRLC_SAFE_MODE, data);
- adev->gfx.rlc.in_safe_mode = false;
+ /* wait for RLC_SAFE_MODE */
+ for (i = 0; i < adev->usec_timeout; i++) {
+ if (!REG_GET_FIELD(RREG32_SOC15(GC, 0, mmRLC_SAFE_MODE), RLC_SAFE_MODE, CMD))
+ break;
+ udelay(1);
}
}
+static void gfx_v9_0_unset_safe_mode(struct amdgpu_device *adev)
+{
+ uint32_t data;
+
+ data = RLC_SAFE_MODE__CMD_MASK;
+ WREG32_SOC15(GC, 0, mmRLC_SAFE_MODE, data);
+}
+
static void gfx_v9_0_update_gfx_cg_power_gating(struct amdgpu_device *adev,
bool enable)
{
- gfx_v9_0_enter_rlc_safe_mode(adev);
+ amdgpu_gfx_rlc_enter_safe_mode(adev);
if ((adev->pg_flags & AMD_PG_SUPPORT_GFX_PG) && enable) {
gfx_v9_0_enable_gfx_cg_power_gating(adev, true);
@@ -3675,7 +3545,7 @@ static void gfx_v9_0_update_gfx_cg_power_gating(struct amdgpu_device *adev,
gfx_v9_0_enable_gfx_pipeline_powergating(adev, false);
}
- gfx_v9_0_exit_rlc_safe_mode(adev);
+ amdgpu_gfx_rlc_exit_safe_mode(adev);
}
static void gfx_v9_0_update_gfx_mg_power_gating(struct amdgpu_device *adev,
@@ -3773,7 +3643,7 @@ static void gfx_v9_0_update_3d_clock_gating(struct amdgpu_device *adev,
{
uint32_t data, def;
- adev->gfx.rlc.funcs->enter_safe_mode(adev);
+ amdgpu_gfx_rlc_enter_safe_mode(adev);
/* Enable 3D CGCG/CGLS */
if (enable && (adev->cg_flags & AMD_CG_SUPPORT_GFX_3D_CGCG)) {
@@ -3813,7 +3683,7 @@ static void gfx_v9_0_update_3d_clock_gating(struct amdgpu_device *adev,
WREG32_SOC15(GC, 0, mmRLC_CGCG_CGLS_CTRL_3D, data);
}
- adev->gfx.rlc.funcs->exit_safe_mode(adev);
+ amdgpu_gfx_rlc_exit_safe_mode(adev);
}
static void gfx_v9_0_update_coarse_grain_clock_gating(struct amdgpu_device *adev,
@@ -3821,7 +3691,7 @@ static void gfx_v9_0_update_coarse_grain_clock_gating(struct amdgpu_device *adev
{
uint32_t def, data;
- adev->gfx.rlc.funcs->enter_safe_mode(adev);
+ amdgpu_gfx_rlc_enter_safe_mode(adev);
if (enable && (adev->cg_flags & AMD_CG_SUPPORT_GFX_CGCG)) {
def = data = RREG32_SOC15(GC, 0, mmRLC_CGTT_MGCG_OVERRIDE);
@@ -3861,7 +3731,7 @@ static void gfx_v9_0_update_coarse_grain_clock_gating(struct amdgpu_device *adev
WREG32_SOC15(GC, 0, mmRLC_CGCG_CGLS_CTRL, data);
}
- adev->gfx.rlc.funcs->exit_safe_mode(adev);
+ amdgpu_gfx_rlc_exit_safe_mode(adev);
}
static int gfx_v9_0_update_gfx_clock_gating(struct amdgpu_device *adev,
@@ -3890,8 +3760,17 @@ static int gfx_v9_0_update_gfx_clock_gating(struct amdgpu_device *adev,
}
static const struct amdgpu_rlc_funcs gfx_v9_0_rlc_funcs = {
- .enter_safe_mode = gfx_v9_0_enter_rlc_safe_mode,
- .exit_safe_mode = gfx_v9_0_exit_rlc_safe_mode
+ .is_rlc_enabled = gfx_v9_0_is_rlc_enabled,
+ .set_safe_mode = gfx_v9_0_set_safe_mode,
+ .unset_safe_mode = gfx_v9_0_unset_safe_mode,
+ .init = gfx_v9_0_rlc_init,
+ .get_csb_size = gfx_v9_0_get_csb_size,
+ .get_csb_buffer = gfx_v9_0_get_csb_buffer,
+ .get_cp_table_num = gfx_v9_0_cp_jump_table_num,
+ .resume = gfx_v9_0_rlc_resume,
+ .stop = gfx_v9_0_rlc_stop,
+ .reset = gfx_v9_0_rlc_reset,
+ .start = gfx_v9_0_rlc_start
};
static int gfx_v9_0_set_powergating_state(void *handle,
@@ -4072,9 +3951,11 @@ static void gfx_v9_0_ring_emit_hdp_flush(struct amdgpu_ring *ring)
}
static void gfx_v9_0_ring_emit_ib_gfx(struct amdgpu_ring *ring,
- struct amdgpu_ib *ib,
- unsigned vmid, bool ctx_switch)
+ struct amdgpu_job *job,
+ struct amdgpu_ib *ib,
+ bool ctx_switch)
{
+ unsigned vmid = AMDGPU_JOB_GET_VMID(job);
u32 header, control = 0;
if (ib->flags & AMDGPU_IB_FLAG_CE)
@@ -4103,20 +3984,22 @@ static void gfx_v9_0_ring_emit_ib_gfx(struct amdgpu_ring *ring,
}
static void gfx_v9_0_ring_emit_ib_compute(struct amdgpu_ring *ring,
- struct amdgpu_ib *ib,
- unsigned vmid, bool ctx_switch)
+ struct amdgpu_job *job,
+ struct amdgpu_ib *ib,
+ bool ctx_switch)
{
- u32 control = INDIRECT_BUFFER_VALID | ib->length_dw | (vmid << 24);
+ unsigned vmid = AMDGPU_JOB_GET_VMID(job);
+ u32 control = INDIRECT_BUFFER_VALID | ib->length_dw | (vmid << 24);
- amdgpu_ring_write(ring, PACKET3(PACKET3_INDIRECT_BUFFER, 2));
+ amdgpu_ring_write(ring, PACKET3(PACKET3_INDIRECT_BUFFER, 2));
BUG_ON(ib->gpu_addr & 0x3); /* Dword align */
- amdgpu_ring_write(ring,
+ amdgpu_ring_write(ring,
#ifdef __BIG_ENDIAN
- (2 << 0) |
+ (2 << 0) |
#endif
- lower_32_bits(ib->gpu_addr));
- amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr));
- amdgpu_ring_write(ring, control);
+ lower_32_bits(ib->gpu_addr));
+ amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr));
+ amdgpu_ring_write(ring, control);
}
static void gfx_v9_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr,
@@ -4695,12 +4578,39 @@ static int gfx_v9_0_eop_irq(struct amdgpu_device *adev,
return 0;
}
+static void gfx_v9_0_fault(struct amdgpu_device *adev,
+ struct amdgpu_iv_entry *entry)
+{
+ u8 me_id, pipe_id, queue_id;
+ struct amdgpu_ring *ring;
+ int i;
+
+ me_id = (entry->ring_id & 0x0c) >> 2;
+ pipe_id = (entry->ring_id & 0x03) >> 0;
+ queue_id = (entry->ring_id & 0x70) >> 4;
+
+ switch (me_id) {
+ case 0:
+ drm_sched_fault(&adev->gfx.gfx_ring[0].sched);
+ break;
+ case 1:
+ case 2:
+ for (i = 0; i < adev->gfx.num_compute_rings; i++) {
+ ring = &adev->gfx.compute_ring[i];
+ if (ring->me == me_id && ring->pipe == pipe_id &&
+ ring->queue == queue_id)
+ drm_sched_fault(&ring->sched);
+ }
+ break;
+ }
+}
+
static int gfx_v9_0_priv_reg_irq(struct amdgpu_device *adev,
struct amdgpu_irq_src *source,
struct amdgpu_iv_entry *entry)
{
DRM_ERROR("Illegal register access in command stream\n");
- schedule_work(&adev->reset_work);
+ gfx_v9_0_fault(adev, entry);
return 0;
}
@@ -4709,7 +4619,7 @@ static int gfx_v9_0_priv_inst_irq(struct amdgpu_device *adev,
struct amdgpu_iv_entry *entry)
{
DRM_ERROR("Illegal instruction in command stream\n");
- schedule_work(&adev->reset_work);
+ gfx_v9_0_fault(adev, entry);
return 0;
}
@@ -4836,10 +4746,8 @@ static const struct amdgpu_ring_funcs gfx_v9_0_ring_funcs_kiq = {
2 + /* gfx_v9_0_ring_emit_vm_flush */
8 + 8 + 8, /* gfx_v9_0_ring_emit_fence_kiq x3 for user fence, vm fence */
.emit_ib_size = 4, /* gfx_v9_0_ring_emit_ib_compute */
- .emit_ib = gfx_v9_0_ring_emit_ib_compute,
.emit_fence = gfx_v9_0_ring_emit_fence_kiq,
.test_ring = gfx_v9_0_ring_test_ring,
- .test_ib = gfx_v9_0_ring_test_ib,
.insert_nop = amdgpu_ring_insert_nop,
.pad_ib = amdgpu_ring_generic_pad_ib,
.emit_rreg = gfx_v9_0_ring_emit_rreg,
diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c
index ceb7847b504f..f5edddf3b29d 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c
@@ -35,20 +35,25 @@ u64 gfxhub_v1_0_get_mc_fb_offset(struct amdgpu_device *adev)
return (u64)RREG32_SOC15(GC, 0, mmMC_VM_FB_OFFSET) << 24;
}
-static void gfxhub_v1_0_init_gart_pt_regs(struct amdgpu_device *adev)
+void gfxhub_v1_0_setup_vm_pt_regs(struct amdgpu_device *adev, uint32_t vmid,
+ uint64_t page_table_base)
{
- uint64_t value = amdgpu_gmc_pd_addr(adev->gart.bo);
+ /* two registers distance between mmVM_CONTEXT0_* to mmVM_CONTEXT1_* */
+ int offset = mmVM_CONTEXT1_PAGE_TABLE_BASE_ADDR_LO32
+ - mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32;
- WREG32_SOC15(GC, 0, mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32,
- lower_32_bits(value));
+ WREG32_SOC15_OFFSET(GC, 0, mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32,
+ offset * vmid, lower_32_bits(page_table_base));
- WREG32_SOC15(GC, 0, mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32,
- upper_32_bits(value));
+ WREG32_SOC15_OFFSET(GC, 0, mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32,
+ offset * vmid, upper_32_bits(page_table_base));
}
static void gfxhub_v1_0_init_gart_aperture_regs(struct amdgpu_device *adev)
{
- gfxhub_v1_0_init_gart_pt_regs(adev);
+ uint64_t pt_base = amdgpu_gmc_pd_addr(adev->gart.bo);
+
+ gfxhub_v1_0_setup_vm_pt_regs(adev, 0, pt_base);
WREG32_SOC15(GC, 0, mmVM_CONTEXT0_PAGE_TABLE_START_ADDR_LO32,
(u32)(adev->gmc.gart_start >> 12));
@@ -72,7 +77,7 @@ static void gfxhub_v1_0_init_system_aperture_regs(struct amdgpu_device *adev)
/* Program the system aperture low logical page number. */
WREG32_SOC15(GC, 0, mmMC_VM_SYSTEM_APERTURE_LOW_ADDR,
- min(adev->gmc.vram_start, adev->gmc.agp_start) >> 18);
+ min(adev->gmc.fb_start, adev->gmc.agp_start) >> 18);
if (adev->asic_type == CHIP_RAVEN && adev->rev_id >= 0x8)
/*
@@ -82,11 +87,11 @@ static void gfxhub_v1_0_init_system_aperture_regs(struct amdgpu_device *adev)
* to get rid of the VM fault and hardware hang.
*/
WREG32_SOC15(GC, 0, mmMC_VM_SYSTEM_APERTURE_HIGH_ADDR,
- max((adev->gmc.vram_end >> 18) + 0x1,
+ max((adev->gmc.fb_end >> 18) + 0x1,
adev->gmc.agp_end >> 18));
else
WREG32_SOC15(GC, 0, mmMC_VM_SYSTEM_APERTURE_HIGH_ADDR,
- max(adev->gmc.vram_end, adev->gmc.agp_end) >> 18);
+ max(adev->gmc.fb_end, adev->gmc.agp_end) >> 18);
/* Set default page address. */
value = adev->vram_scratch.gpu_addr - adev->gmc.vram_start
diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.h b/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.h
index 206e29cad753..92d3a70cd9b1 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.h
+++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.h
@@ -30,5 +30,7 @@ void gfxhub_v1_0_set_fault_enable_default(struct amdgpu_device *adev,
bool value);
void gfxhub_v1_0_init(struct amdgpu_device *adev);
u64 gfxhub_v1_0_get_mc_fb_offset(struct amdgpu_device *adev);
+void gfxhub_v1_0_setup_vm_pt_regs(struct amdgpu_device *adev, uint32_t vmid,
+ uint64_t page_table_base);
#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
index e1c2b4e9c7b2..2821d1d846e4 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
@@ -358,7 +358,8 @@ static int gmc_v6_0_mc_init(struct amdgpu_device *adev)
return 0;
}
-static void gmc_v6_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid)
+static void gmc_v6_0_flush_gpu_tlb(struct amdgpu_device *adev,
+ uint32_t vmid, uint32_t flush_type)
{
WREG32(mmVM_INVALIDATE_REQUEST, 1 << vmid);
}
@@ -580,7 +581,7 @@ static int gmc_v6_0_gart_enable(struct amdgpu_device *adev)
else
gmc_v6_0_set_fault_enable_default(adev, true);
- gmc_v6_0_flush_gpu_tlb(adev, 0);
+ gmc_v6_0_flush_gpu_tlb(adev, 0, 0);
dev_info(adev->dev, "PCIE GART of %uM enabled (table at 0x%016llX).\n",
(unsigned)(adev->gmc.gart_size >> 20),
(unsigned long long)table_addr);
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
index 910c4ce19cb3..761dcfb2fec0 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
@@ -430,7 +430,8 @@ static int gmc_v7_0_mc_init(struct amdgpu_device *adev)
*
* Flush the TLB for the requested page table (CIK).
*/
-static void gmc_v7_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid)
+static void gmc_v7_0_flush_gpu_tlb(struct amdgpu_device *adev,
+ uint32_t vmid, uint32_t flush_type)
{
/* bits 0-15 are the VM contexts0-15 */
WREG32(mmVM_INVALIDATE_REQUEST, 1 << vmid);
@@ -698,7 +699,7 @@ static int gmc_v7_0_gart_enable(struct amdgpu_device *adev)
WREG32(mmCHUB_CONTROL, tmp);
}
- gmc_v7_0_flush_gpu_tlb(adev, 0);
+ gmc_v7_0_flush_gpu_tlb(adev, 0, 0);
DRM_INFO("PCIE GART of %uM enabled (table at 0x%016llX).\n",
(unsigned)(adev->gmc.gart_size >> 20),
(unsigned long long)table_addr);
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
index 1d3265c97b70..531aaf377592 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
@@ -611,7 +611,7 @@ static int gmc_v8_0_mc_init(struct amdgpu_device *adev)
* Flush the TLB for the requested page table (CIK).
*/
static void gmc_v8_0_flush_gpu_tlb(struct amdgpu_device *adev,
- uint32_t vmid)
+ uint32_t vmid, uint32_t flush_type)
{
/* bits 0-15 are the VM contexts0-15 */
WREG32(mmVM_INVALIDATE_REQUEST, 1 << vmid);
@@ -920,7 +920,7 @@ static int gmc_v8_0_gart_enable(struct amdgpu_device *adev)
else
gmc_v8_0_set_fault_enable_default(adev, true);
- gmc_v8_0_flush_gpu_tlb(adev, 0);
+ gmc_v8_0_flush_gpu_tlb(adev, 0, 0);
DRM_INFO("PCIE GART of %uM enabled (table at 0x%016llX).\n",
(unsigned)(adev->gmc.gart_size >> 20),
(unsigned long long)table_addr);
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
index f35d7a554ad5..811231e4ec53 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
@@ -293,14 +293,14 @@ static void gmc_v9_0_set_irq_funcs(struct amdgpu_device *adev)
adev->gmc.vm_fault.funcs = &gmc_v9_0_irq_funcs;
}
-static uint32_t gmc_v9_0_get_invalidate_req(unsigned int vmid)
+static uint32_t gmc_v9_0_get_invalidate_req(unsigned int vmid,
+ uint32_t flush_type)
{
u32 req = 0;
- /* invalidate using legacy mode on vmid*/
req = REG_SET_FIELD(req, VM_INVALIDATE_ENG0_REQ,
PER_VMID_INVALIDATE_REQ, 1 << vmid);
- req = REG_SET_FIELD(req, VM_INVALIDATE_ENG0_REQ, FLUSH_TYPE, 0);
+ req = REG_SET_FIELD(req, VM_INVALIDATE_ENG0_REQ, FLUSH_TYPE, flush_type);
req = REG_SET_FIELD(req, VM_INVALIDATE_ENG0_REQ, INVALIDATE_L2_PTES, 1);
req = REG_SET_FIELD(req, VM_INVALIDATE_ENG0_REQ, INVALIDATE_L2_PDE0, 1);
req = REG_SET_FIELD(req, VM_INVALIDATE_ENG0_REQ, INVALIDATE_L2_PDE1, 1);
@@ -312,48 +312,6 @@ static uint32_t gmc_v9_0_get_invalidate_req(unsigned int vmid)
return req;
}
-static signed long amdgpu_kiq_reg_write_reg_wait(struct amdgpu_device *adev,
- uint32_t reg0, uint32_t reg1,
- uint32_t ref, uint32_t mask)
-{
- signed long r, cnt = 0;
- unsigned long flags;
- uint32_t seq;
- struct amdgpu_kiq *kiq = &adev->gfx.kiq;
- struct amdgpu_ring *ring = &kiq->ring;
-
- spin_lock_irqsave(&kiq->ring_lock, flags);
-
- amdgpu_ring_alloc(ring, 32);
- amdgpu_ring_emit_reg_write_reg_wait(ring, reg0, reg1,
- ref, mask);
- amdgpu_fence_emit_polling(ring, &seq);
- amdgpu_ring_commit(ring);
- spin_unlock_irqrestore(&kiq->ring_lock, flags);
-
- r = amdgpu_fence_wait_polling(ring, seq, MAX_KIQ_REG_WAIT);
-
- /* don't wait anymore for IRQ context */
- if (r < 1 && in_interrupt())
- goto failed_kiq;
-
- might_sleep();
-
- while (r < 1 && cnt++ < MAX_KIQ_REG_TRY) {
- msleep(MAX_KIQ_REG_BAILOUT_INTERVAL);
- r = amdgpu_fence_wait_polling(ring, seq, MAX_KIQ_REG_WAIT);
- }
-
- if (cnt > MAX_KIQ_REG_TRY)
- goto failed_kiq;
-
- return 0;
-
-failed_kiq:
- pr_err("failed to invalidate tlb with kiq\n");
- return r;
-}
-
/*
* GART
* VMID 0 is the physical GPU addresses as used by the kernel.
@@ -362,64 +320,47 @@ failed_kiq:
*/
/**
- * gmc_v9_0_flush_gpu_tlb - gart tlb flush callback
+ * gmc_v9_0_flush_gpu_tlb - tlb flush with certain type
*
* @adev: amdgpu_device pointer
* @vmid: vm instance to flush
+ * @flush_type: the flush type
*
- * Flush the TLB for the requested page table.
+ * Flush the TLB for the requested page table using certain type.
*/
static void gmc_v9_0_flush_gpu_tlb(struct amdgpu_device *adev,
- uint32_t vmid)
+ uint32_t vmid, uint32_t flush_type)
{
- /* Use register 17 for GART */
const unsigned eng = 17;
unsigned i, j;
- int r;
for (i = 0; i < AMDGPU_MAX_VMHUBS; ++i) {
struct amdgpu_vmhub *hub = &adev->vmhub[i];
- u32 tmp = gmc_v9_0_get_invalidate_req(vmid);
-
- if (adev->gfx.kiq.ring.ready &&
- (amdgpu_sriov_runtime(adev) || !amdgpu_sriov_vf(adev)) &&
- !adev->in_gpu_reset) {
- r = amdgpu_kiq_reg_write_reg_wait(adev, hub->vm_inv_eng0_req + eng,
- hub->vm_inv_eng0_ack + eng, tmp, 1 << vmid);
- if (!r)
- continue;
- }
+ u32 tmp = gmc_v9_0_get_invalidate_req(vmid, flush_type);
- spin_lock(&adev->gmc.invalidate_lock);
+ if (i == AMDGPU_GFXHUB && !adev->in_gpu_reset &&
+ adev->gfx.kiq.ring.sched.ready &&
+ (amdgpu_sriov_runtime(adev) || !amdgpu_sriov_vf(adev))) {
+ uint32_t req = hub->vm_inv_eng0_req + eng;
+ uint32_t ack = hub->vm_inv_eng0_ack + eng;
- WREG32_NO_KIQ(hub->vm_inv_eng0_req + eng, tmp);
-
- /* Busy wait for ACK.*/
- for (j = 0; j < 100; j++) {
- tmp = RREG32_NO_KIQ(hub->vm_inv_eng0_ack + eng);
- tmp &= 1 << vmid;
- if (tmp)
- break;
- cpu_relax();
- }
- if (j < 100) {
- spin_unlock(&adev->gmc.invalidate_lock);
+ amdgpu_virt_kiq_reg_write_reg_wait(adev, req, ack, tmp,
+ 1 << vmid);
continue;
}
- /* Wait for ACK with a delay.*/
+ spin_lock(&adev->gmc.invalidate_lock);
+ WREG32_NO_KIQ(hub->vm_inv_eng0_req + eng, tmp);
for (j = 0; j < adev->usec_timeout; j++) {
tmp = RREG32_NO_KIQ(hub->vm_inv_eng0_ack + eng);
- tmp &= 1 << vmid;
- if (tmp)
+ if (tmp & (1 << vmid))
break;
udelay(1);
}
- if (j < adev->usec_timeout) {
- spin_unlock(&adev->gmc.invalidate_lock);
- continue;
- }
spin_unlock(&adev->gmc.invalidate_lock);
+ if (j < adev->usec_timeout)
+ continue;
+
DRM_ERROR("Timeout waiting for VM flush ACK!\n");
}
}
@@ -429,7 +370,7 @@ static uint64_t gmc_v9_0_emit_flush_gpu_tlb(struct amdgpu_ring *ring,
{
struct amdgpu_device *adev = ring->adev;
struct amdgpu_vmhub *hub = &adev->vmhub[ring->funcs->vmhub];
- uint32_t req = gmc_v9_0_get_invalidate_req(vmid);
+ uint32_t req = gmc_v9_0_get_invalidate_req(vmid, 0);
unsigned eng = ring->vm_inv_eng;
amdgpu_ring_emit_wreg(ring, hub->ctx0_ptb_addr_lo32 + (2 * vmid),
@@ -739,9 +680,8 @@ static int gmc_v9_0_late_init(void *handle)
unsigned vmhub = ring->funcs->vmhub;
ring->vm_inv_eng = vm_inv_eng[vmhub]++;
- dev_info(adev->dev, "ring %u(%s) uses VM inv eng %u on hub %u\n",
- ring->idx, ring->name, ring->vm_inv_eng,
- ring->funcs->vmhub);
+ dev_info(adev->dev, "ring %s uses VM inv eng %u on hub %u\n",
+ ring->name, ring->vm_inv_eng, ring->funcs->vmhub);
}
/* Engine 16 is used for KFD and 17 for GART flushes */
@@ -1122,7 +1062,7 @@ static int gmc_v9_0_gart_enable(struct amdgpu_device *adev)
gfxhub_v1_0_set_fault_enable_default(adev, value);
mmhub_v1_0_set_fault_enable_default(adev, value);
- gmc_v9_0_flush_gpu_tlb(adev, 0);
+ gmc_v9_0_flush_gpu_tlb(adev, 0, 0);
DRM_INFO("PCIE GART of %uM enabled (table at 0x%016llX).\n",
(unsigned)(adev->gmc.gart_size >> 20),
diff --git a/drivers/gpu/drm/amd/amdgpu/kv_dpm.c b/drivers/gpu/drm/amd/amdgpu/kv_dpm.c
index d0e478f43443..0c9a2c03504e 100644
--- a/drivers/gpu/drm/amd/amdgpu/kv_dpm.c
+++ b/drivers/gpu/drm/amd/amdgpu/kv_dpm.c
@@ -508,19 +508,19 @@ static int kv_enable_didt(struct amdgpu_device *adev, bool enable)
pi->caps_db_ramping ||
pi->caps_td_ramping ||
pi->caps_tcp_ramping) {
- adev->gfx.rlc.funcs->enter_safe_mode(adev);
+ amdgpu_gfx_rlc_enter_safe_mode(adev);
if (enable) {
ret = kv_program_pt_config_registers(adev, didt_config_kv);
if (ret) {
- adev->gfx.rlc.funcs->exit_safe_mode(adev);
+ amdgpu_gfx_rlc_exit_safe_mode(adev);
return ret;
}
}
kv_do_enable_didt(adev, enable);
- adev->gfx.rlc.funcs->exit_safe_mode(adev);
+ amdgpu_gfx_rlc_exit_safe_mode(adev);
}
return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c
index fd23ba1226a5..d0d966d6080a 100644
--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c
@@ -52,20 +52,25 @@ u64 mmhub_v1_0_get_fb_location(struct amdgpu_device *adev)
return base;
}
-static void mmhub_v1_0_init_gart_pt_regs(struct amdgpu_device *adev)
+void mmhub_v1_0_setup_vm_pt_regs(struct amdgpu_device *adev, uint32_t vmid,
+ uint64_t page_table_base)
{
- uint64_t value = amdgpu_gmc_pd_addr(adev->gart.bo);
+ /* two registers distance between mmVM_CONTEXT0_* to mmVM_CONTEXT1_* */
+ int offset = mmVM_CONTEXT1_PAGE_TABLE_BASE_ADDR_LO32
+ - mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32;
- WREG32_SOC15(MMHUB, 0, mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32,
- lower_32_bits(value));
+ WREG32_SOC15_OFFSET(MMHUB, 0, mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32,
+ offset * vmid, lower_32_bits(page_table_base));
- WREG32_SOC15(MMHUB, 0, mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32,
- upper_32_bits(value));
+ WREG32_SOC15_OFFSET(MMHUB, 0, mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32,
+ offset * vmid, upper_32_bits(page_table_base));
}
static void mmhub_v1_0_init_gart_aperture_regs(struct amdgpu_device *adev)
{
- mmhub_v1_0_init_gart_pt_regs(adev);
+ uint64_t pt_base = amdgpu_gmc_pd_addr(adev->gart.bo);
+
+ mmhub_v1_0_setup_vm_pt_regs(adev, 0, pt_base);
WREG32_SOC15(MMHUB, 0, mmVM_CONTEXT0_PAGE_TABLE_START_ADDR_LO32,
(u32)(adev->gmc.gart_start >> 12));
@@ -90,7 +95,7 @@ static void mmhub_v1_0_init_system_aperture_regs(struct amdgpu_device *adev)
/* Program the system aperture low logical page number. */
WREG32_SOC15(MMHUB, 0, mmMC_VM_SYSTEM_APERTURE_LOW_ADDR,
- min(adev->gmc.vram_start, adev->gmc.agp_start) >> 18);
+ min(adev->gmc.fb_start, adev->gmc.agp_start) >> 18);
if (adev->asic_type == CHIP_RAVEN && adev->rev_id >= 0x8)
/*
@@ -100,11 +105,11 @@ static void mmhub_v1_0_init_system_aperture_regs(struct amdgpu_device *adev)
* to get rid of the VM fault and hardware hang.
*/
WREG32_SOC15(MMHUB, 0, mmMC_VM_SYSTEM_APERTURE_HIGH_ADDR,
- max((adev->gmc.vram_end >> 18) + 0x1,
+ max((adev->gmc.fb_end >> 18) + 0x1,
adev->gmc.agp_end >> 18));
else
WREG32_SOC15(MMHUB, 0, mmMC_VM_SYSTEM_APERTURE_HIGH_ADDR,
- max(adev->gmc.vram_end, adev->gmc.agp_end) >> 18);
+ max(adev->gmc.fb_end, adev->gmc.agp_end) >> 18);
/* Set default page address. */
value = adev->vram_scratch.gpu_addr - adev->gmc.vram_start +
diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.h b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.h
index bef3d0c0c117..0de0fdf98c00 100644
--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.h
+++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.h
@@ -34,5 +34,7 @@ int mmhub_v1_0_set_clockgating(struct amdgpu_device *adev,
void mmhub_v1_0_get_clockgating(struct amdgpu_device *adev, u32 *flags);
void mmhub_v1_0_update_power_gating(struct amdgpu_device *adev,
bool enable);
+void mmhub_v1_0_setup_vm_pt_regs(struct amdgpu_device *adev, uint32_t vmid,
+ uint64_t page_table_base);
#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
index 3f3fac2d50cd..e5dd052d9e06 100644
--- a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
@@ -34,6 +34,7 @@
#include "nbio/nbio_7_4_offset.h"
MODULE_FIRMWARE("amdgpu/vega20_sos.bin");
+MODULE_FIRMWARE("amdgpu/vega20_ta.bin");
/* address block */
#define smnMP1_FIRMWARE_FLAGS 0x3010024
@@ -98,7 +99,8 @@ static int psp_v11_0_init_microcode(struct psp_context *psp)
const char *chip_name;
char fw_name[30];
int err = 0;
- const struct psp_firmware_header_v1_0 *hdr;
+ const struct psp_firmware_header_v1_0 *sos_hdr;
+ const struct ta_firmware_header_v1_0 *ta_hdr;
DRM_DEBUG("\n");
@@ -119,16 +121,32 @@ static int psp_v11_0_init_microcode(struct psp_context *psp)
if (err)
goto out;
- hdr = (const struct psp_firmware_header_v1_0 *)adev->psp.sos_fw->data;
- adev->psp.sos_fw_version = le32_to_cpu(hdr->header.ucode_version);
- adev->psp.sos_feature_version = le32_to_cpu(hdr->ucode_feature_version);
- adev->psp.sos_bin_size = le32_to_cpu(hdr->sos_size_bytes);
- adev->psp.sys_bin_size = le32_to_cpu(hdr->header.ucode_size_bytes) -
- le32_to_cpu(hdr->sos_size_bytes);
- adev->psp.sys_start_addr = (uint8_t *)hdr +
- le32_to_cpu(hdr->header.ucode_array_offset_bytes);
+ sos_hdr = (const struct psp_firmware_header_v1_0 *)adev->psp.sos_fw->data;
+ adev->psp.sos_fw_version = le32_to_cpu(sos_hdr->header.ucode_version);
+ adev->psp.sos_feature_version = le32_to_cpu(sos_hdr->ucode_feature_version);
+ adev->psp.sos_bin_size = le32_to_cpu(sos_hdr->sos_size_bytes);
+ adev->psp.sys_bin_size = le32_to_cpu(sos_hdr->header.ucode_size_bytes) -
+ le32_to_cpu(sos_hdr->sos_size_bytes);
+ adev->psp.sys_start_addr = (uint8_t *)sos_hdr +
+ le32_to_cpu(sos_hdr->header.ucode_array_offset_bytes);
adev->psp.sos_start_addr = (uint8_t *)adev->psp.sys_start_addr +
- le32_to_cpu(hdr->sos_offset_bytes);
+ le32_to_cpu(sos_hdr->sos_offset_bytes);
+
+ snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ta.bin", chip_name);
+ err = request_firmware(&adev->psp.ta_fw, fw_name, adev->dev);
+ if (err)
+ goto out;
+
+ err = amdgpu_ucode_validate(adev->psp.ta_fw);
+ if (err)
+ goto out;
+
+ ta_hdr = (const struct ta_firmware_header_v1_0 *)adev->psp.ta_fw->data;
+ adev->psp.ta_xgmi_ucode_version = le32_to_cpu(ta_hdr->ta_xgmi_ucode_version);
+ adev->psp.ta_xgmi_ucode_size = le32_to_cpu(ta_hdr->ta_xgmi_size_bytes);
+ adev->psp.ta_xgmi_start_addr = (uint8_t *)ta_hdr +
+ le32_to_cpu(ta_hdr->header.ucode_array_offset_bytes);
+
return 0;
out:
if (err) {
@@ -167,7 +185,7 @@ static int psp_v11_0_bootloader_load_sysdrv(struct psp_context *psp)
/* Copy PSP System Driver binary to memory */
memcpy(psp->fw_pri_buf, psp->sys_start_addr, psp->sys_bin_size);
- /* Provide the sys driver to bootrom */
+ /* Provide the sys driver to bootloader */
WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
(uint32_t)(psp->fw_pri_mc_addr >> 20));
psp_gfxdrv_command_reg = 1 << 16;
@@ -208,7 +226,7 @@ static int psp_v11_0_bootloader_load_sos(struct psp_context *psp)
/* Copy Secure OS binary to PSP memory */
memcpy(psp->fw_pri_buf, psp->sos_start_addr, psp->sos_bin_size);
- /* Provide the PSP secure OS to bootrom */
+ /* Provide the PSP secure OS to bootloader */
WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
(uint32_t)(psp->fw_pri_mc_addr >> 20));
psp_gfxdrv_command_reg = 2 << 16;
@@ -552,24 +570,110 @@ static int psp_v11_0_mode1_reset(struct psp_context *psp)
static int psp_v11_0_xgmi_get_topology_info(struct psp_context *psp,
int number_devices, struct psp_xgmi_topology_info *topology)
{
+ struct ta_xgmi_shared_memory *xgmi_cmd;
+ struct ta_xgmi_cmd_get_topology_info_input *topology_info_input;
+ struct ta_xgmi_cmd_get_topology_info_output *topology_info_output;
+ int i;
+ int ret;
+
+ if (!topology || topology->num_nodes > TA_XGMI__MAX_CONNECTED_NODES)
+ return -EINVAL;
+
+ xgmi_cmd = (struct ta_xgmi_shared_memory*)psp->xgmi_context.xgmi_shared_buf;
+ memset(xgmi_cmd, 0, sizeof(struct ta_xgmi_shared_memory));
+
+ /* Fill in the shared memory with topology information as input */
+ topology_info_input = &xgmi_cmd->xgmi_in_message.get_topology_info;
+ xgmi_cmd->cmd_id = TA_COMMAND_XGMI__GET_GET_TOPOLOGY_INFO;
+ topology_info_input->num_nodes = number_devices;
+
+ for (i = 0; i < topology_info_input->num_nodes; i++) {
+ topology_info_input->nodes[i].node_id = topology->nodes[i].node_id;
+ topology_info_input->nodes[i].num_hops = topology->nodes[i].num_hops;
+ topology_info_input->nodes[i].is_sharing_enabled = topology->nodes[i].is_sharing_enabled;
+ topology_info_input->nodes[i].sdma_engine = topology->nodes[i].sdma_engine;
+ }
+
+ /* Invoke xgmi ta to get the topology information */
+ ret = psp_xgmi_invoke(psp, TA_COMMAND_XGMI__GET_GET_TOPOLOGY_INFO);
+ if (ret)
+ return ret;
+
+ /* Read the output topology information from the shared memory */
+ topology_info_output = &xgmi_cmd->xgmi_out_message.get_topology_info;
+ topology->num_nodes = xgmi_cmd->xgmi_out_message.get_topology_info.num_nodes;
+ for (i = 0; i < topology->num_nodes; i++) {
+ topology->nodes[i].node_id = topology_info_output->nodes[i].node_id;
+ topology->nodes[i].num_hops = topology_info_output->nodes[i].num_hops;
+ topology->nodes[i].is_sharing_enabled = topology_info_output->nodes[i].is_sharing_enabled;
+ topology->nodes[i].sdma_engine = topology_info_output->nodes[i].sdma_engine;
+ }
+
return 0;
}
static int psp_v11_0_xgmi_set_topology_info(struct psp_context *psp,
int number_devices, struct psp_xgmi_topology_info *topology)
{
- return 0;
+ struct ta_xgmi_shared_memory *xgmi_cmd;
+ struct ta_xgmi_cmd_get_topology_info_input *topology_info_input;
+ int i;
+
+ if (!topology || topology->num_nodes > TA_XGMI__MAX_CONNECTED_NODES)
+ return -EINVAL;
+
+ xgmi_cmd = (struct ta_xgmi_shared_memory*)psp->xgmi_context.xgmi_shared_buf;
+ memset(xgmi_cmd, 0, sizeof(struct ta_xgmi_shared_memory));
+
+ topology_info_input = &xgmi_cmd->xgmi_in_message.get_topology_info;
+ xgmi_cmd->cmd_id = TA_COMMAND_XGMI__SET_TOPOLOGY_INFO;
+ topology_info_input->num_nodes = number_devices;
+
+ for (i = 0; i < topology_info_input->num_nodes; i++) {
+ topology_info_input->nodes[i].node_id = topology->nodes[i].node_id;
+ topology_info_input->nodes[i].num_hops = topology->nodes[i].num_hops;
+ topology_info_input->nodes[i].is_sharing_enabled = topology->nodes[i].is_sharing_enabled;
+ topology_info_input->nodes[i].sdma_engine = topology->nodes[i].sdma_engine;
+ }
+
+ /* Invoke xgmi ta to set topology information */
+ return psp_xgmi_invoke(psp, TA_COMMAND_XGMI__SET_TOPOLOGY_INFO);
}
static u64 psp_v11_0_xgmi_get_hive_id(struct psp_context *psp)
{
- u64 hive_id = 0;
+ struct ta_xgmi_shared_memory *xgmi_cmd;
+ int ret;
+
+ xgmi_cmd = (struct ta_xgmi_shared_memory*)psp->xgmi_context.xgmi_shared_buf;
+ memset(xgmi_cmd, 0, sizeof(struct ta_xgmi_shared_memory));
+
+ xgmi_cmd->cmd_id = TA_COMMAND_XGMI__GET_HIVE_ID;
+
+ /* Invoke xgmi ta to get hive id */
+ ret = psp_xgmi_invoke(psp, xgmi_cmd->cmd_id);
+ if (ret)
+ return 0;
+ else
+ return xgmi_cmd->xgmi_out_message.get_hive_id.hive_id;
+}
+
+static u64 psp_v11_0_xgmi_get_node_id(struct psp_context *psp)
+{
+ struct ta_xgmi_shared_memory *xgmi_cmd;
+ int ret;
+
+ xgmi_cmd = (struct ta_xgmi_shared_memory*)psp->xgmi_context.xgmi_shared_buf;
+ memset(xgmi_cmd, 0, sizeof(struct ta_xgmi_shared_memory));
- /* Remove me when we can get correct hive_id through PSP */
- if (psp->adev->gmc.xgmi.num_physical_nodes)
- hive_id = 0x123456789abcdef;
+ xgmi_cmd->cmd_id = TA_COMMAND_XGMI__GET_NODE_ID;
- return hive_id;
+ /* Invoke xgmi ta to get the node id */
+ ret = psp_xgmi_invoke(psp, xgmi_cmd->cmd_id);
+ if (ret)
+ return 0;
+ else
+ return xgmi_cmd->xgmi_out_message.get_node_id.node_id;
}
static const struct psp_funcs psp_v11_0_funcs = {
@@ -587,6 +691,7 @@ static const struct psp_funcs psp_v11_0_funcs = {
.xgmi_get_topology_info = psp_v11_0_xgmi_get_topology_info,
.xgmi_set_topology_info = psp_v11_0_xgmi_set_topology_info,
.xgmi_get_hive_id = psp_v11_0_xgmi_get_hive_id,
+ .xgmi_get_node_id = psp_v11_0_xgmi_get_node_id,
};
void psp_v11_0_set_psp_funcs(struct psp_context *psp)
diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
index e1ebf770c303..9cea0bbe4525 100644
--- a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
@@ -194,7 +194,7 @@ static int psp_v3_1_bootloader_load_sysdrv(struct psp_context *psp)
/* Copy PSP System Driver binary to memory */
memcpy(psp->fw_pri_buf, psp->sys_start_addr, psp->sys_bin_size);
- /* Provide the sys driver to bootrom */
+ /* Provide the sys driver to bootloader */
WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
(uint32_t)(psp->fw_pri_mc_addr >> 20));
psp_gfxdrv_command_reg = 1 << 16;
@@ -254,7 +254,7 @@ static int psp_v3_1_bootloader_load_sos(struct psp_context *psp)
/* Copy Secure OS binary to PSP memory */
memcpy(psp->fw_pri_buf, psp->sos_start_addr, psp->sos_bin_size);
- /* Provide the PSP secure OS to bootrom */
+ /* Provide the PSP secure OS to bootloader */
WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36,
(uint32_t)(psp->fw_pri_mc_addr >> 20));
psp_gfxdrv_command_reg = 2 << 16;
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c
index 2d4770e173dd..9f3cb2aec7c2 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c
@@ -225,7 +225,7 @@ static void sdma_v2_4_ring_set_wptr(struct amdgpu_ring *ring)
static void sdma_v2_4_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count)
{
- struct amdgpu_sdma_instance *sdma = amdgpu_get_sdma_instance(ring);
+ struct amdgpu_sdma_instance *sdma = amdgpu_sdma_get_instance_from_ring(ring);
int i;
for (i = 0; i < count; i++)
@@ -245,9 +245,12 @@ static void sdma_v2_4_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count)
* Schedule an IB in the DMA ring (VI).
*/
static void sdma_v2_4_ring_emit_ib(struct amdgpu_ring *ring,
+ struct amdgpu_job *job,
struct amdgpu_ib *ib,
- unsigned vmid, bool ctx_switch)
+ bool ctx_switch)
{
+ unsigned vmid = AMDGPU_JOB_GET_VMID(job);
+
/* IB packet must end on a 8 DW boundary */
sdma_v2_4_ring_insert_nop(ring, (10 - (lower_32_bits(ring->wptr) & 7)) % 8);
@@ -349,8 +352,8 @@ static void sdma_v2_4_gfx_stop(struct amdgpu_device *adev)
ib_cntl = REG_SET_FIELD(ib_cntl, SDMA0_GFX_IB_CNTL, IB_ENABLE, 0);
WREG32(mmSDMA0_GFX_IB_CNTL + sdma_offsets[i], ib_cntl);
}
- sdma0->ready = false;
- sdma1->ready = false;
+ sdma0->sched.ready = false;
+ sdma1->sched.ready = false;
}
/**
@@ -471,17 +474,15 @@ static int sdma_v2_4_gfx_resume(struct amdgpu_device *adev)
/* enable DMA IBs */
WREG32(mmSDMA0_GFX_IB_CNTL + sdma_offsets[i], ib_cntl);
- ring->ready = true;
+ ring->sched.ready = true;
}
sdma_v2_4_enable(adev, true);
for (i = 0; i < adev->sdma.num_instances; i++) {
ring = &adev->sdma.instance[i].ring;
- r = amdgpu_ring_test_ring(ring);
- if (r) {
- ring->ready = false;
+ r = amdgpu_ring_test_helper(ring);
+ if (r)
return r;
- }
if (adev->mman.buffer_funcs_ring == ring)
amdgpu_ttm_set_buffer_funcs_status(adev, true);
@@ -550,21 +551,16 @@ static int sdma_v2_4_ring_test_ring(struct amdgpu_ring *ring)
u64 gpu_addr;
r = amdgpu_device_wb_get(adev, &index);
- if (r) {
- dev_err(adev->dev, "(%d) failed to allocate wb slot\n", r);
+ if (r)
return r;
- }
gpu_addr = adev->wb.gpu_addr + (index * 4);
tmp = 0xCAFEDEAD;
adev->wb.wb[index] = cpu_to_le32(tmp);
r = amdgpu_ring_alloc(ring, 5);
- if (r) {
- DRM_ERROR("amdgpu: dma failed to lock ring %d (%d).\n", ring->idx, r);
- amdgpu_device_wb_free(adev, index);
- return r;
- }
+ if (r)
+ goto error_free_wb;
amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_WRITE) |
SDMA_PKT_HEADER_SUB_OP(SDMA_SUBOP_WRITE_LINEAR));
@@ -581,15 +577,11 @@ static int sdma_v2_4_ring_test_ring(struct amdgpu_ring *ring)
DRM_UDELAY(1);
}
- if (i < adev->usec_timeout) {
- DRM_DEBUG("ring test on %d succeeded in %d usecs\n", ring->idx, i);
- } else {
- DRM_ERROR("amdgpu: ring %d test failed (0x%08X)\n",
- ring->idx, tmp);
- r = -EINVAL;
- }
- amdgpu_device_wb_free(adev, index);
+ if (i >= adev->usec_timeout)
+ r = -ETIMEDOUT;
+error_free_wb:
+ amdgpu_device_wb_free(adev, index);
return r;
}
@@ -612,20 +604,16 @@ static int sdma_v2_4_ring_test_ib(struct amdgpu_ring *ring, long timeout)
long r;
r = amdgpu_device_wb_get(adev, &index);
- if (r) {
- dev_err(adev->dev, "(%ld) failed to allocate wb slot\n", r);
+ if (r)
return r;
- }
gpu_addr = adev->wb.gpu_addr + (index * 4);
tmp = 0xCAFEDEAD;
adev->wb.wb[index] = cpu_to_le32(tmp);
memset(&ib, 0, sizeof(ib));
r = amdgpu_ib_get(adev, NULL, 256, &ib);
- if (r) {
- DRM_ERROR("amdgpu: failed to get ib (%ld).\n", r);
+ if (r)
goto err0;
- }
ib.ptr[0] = SDMA_PKT_HEADER_OP(SDMA_OP_WRITE) |
SDMA_PKT_HEADER_SUB_OP(SDMA_SUBOP_WRITE_LINEAR);
@@ -644,21 +632,16 @@ static int sdma_v2_4_ring_test_ib(struct amdgpu_ring *ring, long timeout)
r = dma_fence_wait_timeout(f, false, timeout);
if (r == 0) {
- DRM_ERROR("amdgpu: IB test timed out\n");
r = -ETIMEDOUT;
goto err1;
} else if (r < 0) {
- DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r);
goto err1;
}
tmp = le32_to_cpu(adev->wb.wb[index]);
- if (tmp == 0xDEADBEEF) {
- DRM_DEBUG("ib test on ring %d succeeded\n", ring->idx);
+ if (tmp == 0xDEADBEEF)
r = 0;
- } else {
- DRM_ERROR("amdgpu: ib test failed (0x%08X)\n", tmp);
+ else
r = -EINVAL;
- }
err1:
amdgpu_ib_free(adev, &ib, NULL);
@@ -760,7 +743,7 @@ static void sdma_v2_4_vm_set_pte_pde(struct amdgpu_ib *ib, uint64_t pe,
*/
static void sdma_v2_4_ring_pad_ib(struct amdgpu_ring *ring, struct amdgpu_ib *ib)
{
- struct amdgpu_sdma_instance *sdma = amdgpu_get_sdma_instance(ring);
+ struct amdgpu_sdma_instance *sdma = amdgpu_sdma_get_instance_from_ring(ring);
u32 pad_count;
int i;
@@ -1105,8 +1088,14 @@ static int sdma_v2_4_process_illegal_inst_irq(struct amdgpu_device *adev,
struct amdgpu_irq_src *source,
struct amdgpu_iv_entry *entry)
{
+ u8 instance_id, queue_id;
+
DRM_ERROR("Illegal instruction in SDMA command stream\n");
- schedule_work(&adev->reset_work);
+ instance_id = (entry->ring_id & 0x3) >> 0;
+ queue_id = (entry->ring_id & 0xc) >> 2;
+
+ if (instance_id <= 1 && queue_id == 0)
+ drm_sched_fault(&adev->sdma.instance[instance_id].ring.sched);
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
index 6fb3edaba0ec..b6a25f92d566 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
@@ -399,7 +399,7 @@ static void sdma_v3_0_ring_set_wptr(struct amdgpu_ring *ring)
static void sdma_v3_0_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count)
{
- struct amdgpu_sdma_instance *sdma = amdgpu_get_sdma_instance(ring);
+ struct amdgpu_sdma_instance *sdma = amdgpu_sdma_get_instance_from_ring(ring);
int i;
for (i = 0; i < count; i++)
@@ -419,9 +419,12 @@ static void sdma_v3_0_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count)
* Schedule an IB in the DMA ring (VI).
*/
static void sdma_v3_0_ring_emit_ib(struct amdgpu_ring *ring,
+ struct amdgpu_job *job,
struct amdgpu_ib *ib,
- unsigned vmid, bool ctx_switch)
+ bool ctx_switch)
{
+ unsigned vmid = AMDGPU_JOB_GET_VMID(job);
+
/* IB packet must end on a 8 DW boundary */
sdma_v3_0_ring_insert_nop(ring, (10 - (lower_32_bits(ring->wptr) & 7)) % 8);
@@ -523,8 +526,8 @@ static void sdma_v3_0_gfx_stop(struct amdgpu_device *adev)
ib_cntl = REG_SET_FIELD(ib_cntl, SDMA0_GFX_IB_CNTL, IB_ENABLE, 0);
WREG32(mmSDMA0_GFX_IB_CNTL + sdma_offsets[i], ib_cntl);
}
- sdma0->ready = false;
- sdma1->ready = false;
+ sdma0->sched.ready = false;
+ sdma1->sched.ready = false;
}
/**
@@ -739,7 +742,7 @@ static int sdma_v3_0_gfx_resume(struct amdgpu_device *adev)
/* enable DMA IBs */
WREG32(mmSDMA0_GFX_IB_CNTL + sdma_offsets[i], ib_cntl);
- ring->ready = true;
+ ring->sched.ready = true;
}
/* unhalt the MEs */
@@ -749,11 +752,9 @@ static int sdma_v3_0_gfx_resume(struct amdgpu_device *adev)
for (i = 0; i < adev->sdma.num_instances; i++) {
ring = &adev->sdma.instance[i].ring;
- r = amdgpu_ring_test_ring(ring);
- if (r) {
- ring->ready = false;
+ r = amdgpu_ring_test_helper(ring);
+ if (r)
return r;
- }
if (adev->mman.buffer_funcs_ring == ring)
amdgpu_ttm_set_buffer_funcs_status(adev, true);
@@ -822,21 +823,16 @@ static int sdma_v3_0_ring_test_ring(struct amdgpu_ring *ring)
u64 gpu_addr;
r = amdgpu_device_wb_get(adev, &index);
- if (r) {
- dev_err(adev->dev, "(%d) failed to allocate wb slot\n", r);
+ if (r)
return r;
- }
gpu_addr = adev->wb.gpu_addr + (index * 4);
tmp = 0xCAFEDEAD;
adev->wb.wb[index] = cpu_to_le32(tmp);
r = amdgpu_ring_alloc(ring, 5);
- if (r) {
- DRM_ERROR("amdgpu: dma failed to lock ring %d (%d).\n", ring->idx, r);
- amdgpu_device_wb_free(adev, index);
- return r;
- }
+ if (r)
+ goto error_free_wb;
amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_WRITE) |
SDMA_PKT_HEADER_SUB_OP(SDMA_SUBOP_WRITE_LINEAR));
@@ -853,15 +849,11 @@ static int sdma_v3_0_ring_test_ring(struct amdgpu_ring *ring)
DRM_UDELAY(1);
}
- if (i < adev->usec_timeout) {
- DRM_DEBUG("ring test on %d succeeded in %d usecs\n", ring->idx, i);
- } else {
- DRM_ERROR("amdgpu: ring %d test failed (0x%08X)\n",
- ring->idx, tmp);
- r = -EINVAL;
- }
- amdgpu_device_wb_free(adev, index);
+ if (i >= adev->usec_timeout)
+ r = -ETIMEDOUT;
+error_free_wb:
+ amdgpu_device_wb_free(adev, index);
return r;
}
@@ -884,20 +876,16 @@ static int sdma_v3_0_ring_test_ib(struct amdgpu_ring *ring, long timeout)
long r;
r = amdgpu_device_wb_get(adev, &index);
- if (r) {
- dev_err(adev->dev, "(%ld) failed to allocate wb slot\n", r);
+ if (r)
return r;
- }
gpu_addr = adev->wb.gpu_addr + (index * 4);
tmp = 0xCAFEDEAD;
adev->wb.wb[index] = cpu_to_le32(tmp);
memset(&ib, 0, sizeof(ib));
r = amdgpu_ib_get(adev, NULL, 256, &ib);
- if (r) {
- DRM_ERROR("amdgpu: failed to get ib (%ld).\n", r);
+ if (r)
goto err0;
- }
ib.ptr[0] = SDMA_PKT_HEADER_OP(SDMA_OP_WRITE) |
SDMA_PKT_HEADER_SUB_OP(SDMA_SUBOP_WRITE_LINEAR);
@@ -916,21 +904,16 @@ static int sdma_v3_0_ring_test_ib(struct amdgpu_ring *ring, long timeout)
r = dma_fence_wait_timeout(f, false, timeout);
if (r == 0) {
- DRM_ERROR("amdgpu: IB test timed out\n");
r = -ETIMEDOUT;
goto err1;
} else if (r < 0) {
- DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r);
goto err1;
}
tmp = le32_to_cpu(adev->wb.wb[index]);
- if (tmp == 0xDEADBEEF) {
- DRM_DEBUG("ib test on ring %d succeeded\n", ring->idx);
+ if (tmp == 0xDEADBEEF)
r = 0;
- } else {
- DRM_ERROR("amdgpu: ib test failed (0x%08X)\n", tmp);
+ else
r = -EINVAL;
- }
err1:
amdgpu_ib_free(adev, &ib, NULL);
dma_fence_put(f);
@@ -1031,7 +1014,7 @@ static void sdma_v3_0_vm_set_pte_pde(struct amdgpu_ib *ib, uint64_t pe,
*/
static void sdma_v3_0_ring_pad_ib(struct amdgpu_ring *ring, struct amdgpu_ib *ib)
{
- struct amdgpu_sdma_instance *sdma = amdgpu_get_sdma_instance(ring);
+ struct amdgpu_sdma_instance *sdma = amdgpu_sdma_get_instance_from_ring(ring);
u32 pad_count;
int i;
@@ -1440,8 +1423,14 @@ static int sdma_v3_0_process_illegal_inst_irq(struct amdgpu_device *adev,
struct amdgpu_irq_src *source,
struct amdgpu_iv_entry *entry)
{
+ u8 instance_id, queue_id;
+
DRM_ERROR("Illegal instruction in SDMA command stream\n");
- schedule_work(&adev->reset_work);
+ instance_id = (entry->ring_id & 0x3) >> 0;
+ queue_id = (entry->ring_id & 0xc) >> 2;
+
+ if (instance_id <= 1 && queue_id == 0)
+ drm_sched_fault(&adev->sdma.instance[instance_id].ring.sched);
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
index 7a8c9172d30a..f4490cdd9804 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
@@ -54,6 +54,11 @@ MODULE_FIRMWARE("amdgpu/raven2_sdma.bin");
#define SDMA0_POWER_CNTL__ON_OFF_CONDITION_HOLD_TIME_MASK 0x000000F8L
#define SDMA0_POWER_CNTL__ON_OFF_STATUS_DURATION_TIME_MASK 0xFC000000L
+#define WREG32_SDMA(instance, offset, value) \
+ WREG32(sdma_v4_0_get_reg_offset(adev, (instance), (offset)), value)
+#define RREG32_SDMA(instance, offset) \
+ RREG32(sdma_v4_0_get_reg_offset(adev, (instance), (offset)))
+
static void sdma_v4_0_set_ring_funcs(struct amdgpu_device *adev);
static void sdma_v4_0_set_buffer_funcs(struct amdgpu_device *adev);
static void sdma_v4_0_set_vm_pte_funcs(struct amdgpu_device *adev);
@@ -367,16 +372,11 @@ static uint64_t sdma_v4_0_ring_get_wptr(struct amdgpu_ring *ring)
wptr = READ_ONCE(*((u64 *)&adev->wb.wb[ring->wptr_offs]));
DRM_DEBUG("wptr/doorbell before shift == 0x%016llx\n", wptr);
} else {
- u32 lowbit, highbit;
-
- lowbit = RREG32(sdma_v4_0_get_reg_offset(adev, ring->me, mmSDMA0_GFX_RB_WPTR)) >> 2;
- highbit = RREG32(sdma_v4_0_get_reg_offset(adev, ring->me, mmSDMA0_GFX_RB_WPTR_HI)) >> 2;
-
- DRM_DEBUG("wptr [%i]high== 0x%08x low==0x%08x\n",
- ring->me, highbit, lowbit);
- wptr = highbit;
+ wptr = RREG32_SDMA(ring->me, mmSDMA0_GFX_RB_WPTR_HI);
wptr = wptr << 32;
- wptr |= lowbit;
+ wptr |= RREG32_SDMA(ring->me, mmSDMA0_GFX_RB_WPTR);
+ DRM_DEBUG("wptr before shift [%i] wptr == 0x%016llx\n",
+ ring->me, wptr);
}
return wptr >> 2;
@@ -417,14 +417,67 @@ static void sdma_v4_0_ring_set_wptr(struct amdgpu_ring *ring)
lower_32_bits(ring->wptr << 2),
ring->me,
upper_32_bits(ring->wptr << 2));
- WREG32(sdma_v4_0_get_reg_offset(adev, ring->me, mmSDMA0_GFX_RB_WPTR), lower_32_bits(ring->wptr << 2));
- WREG32(sdma_v4_0_get_reg_offset(adev, ring->me, mmSDMA0_GFX_RB_WPTR_HI), upper_32_bits(ring->wptr << 2));
+ WREG32_SDMA(ring->me, mmSDMA0_GFX_RB_WPTR,
+ lower_32_bits(ring->wptr << 2));
+ WREG32_SDMA(ring->me, mmSDMA0_GFX_RB_WPTR_HI,
+ upper_32_bits(ring->wptr << 2));
+ }
+}
+
+/**
+ * sdma_v4_0_page_ring_get_wptr - get the current write pointer
+ *
+ * @ring: amdgpu ring pointer
+ *
+ * Get the current wptr from the hardware (VEGA10+).
+ */
+static uint64_t sdma_v4_0_page_ring_get_wptr(struct amdgpu_ring *ring)
+{
+ struct amdgpu_device *adev = ring->adev;
+ u64 wptr;
+
+ if (ring->use_doorbell) {
+ /* XXX check if swapping is necessary on BE */
+ wptr = READ_ONCE(*((u64 *)&adev->wb.wb[ring->wptr_offs]));
+ } else {
+ wptr = RREG32_SDMA(ring->me, mmSDMA0_PAGE_RB_WPTR_HI);
+ wptr = wptr << 32;
+ wptr |= RREG32_SDMA(ring->me, mmSDMA0_PAGE_RB_WPTR);
+ }
+
+ return wptr >> 2;
+}
+
+/**
+ * sdma_v4_0_ring_set_wptr - commit the write pointer
+ *
+ * @ring: amdgpu ring pointer
+ *
+ * Write the wptr back to the hardware (VEGA10+).
+ */
+static void sdma_v4_0_page_ring_set_wptr(struct amdgpu_ring *ring)
+{
+ struct amdgpu_device *adev = ring->adev;
+
+ if (ring->use_doorbell) {
+ u64 *wb = (u64 *)&adev->wb.wb[ring->wptr_offs];
+
+ /* XXX check if swapping is necessary on BE */
+ WRITE_ONCE(*wb, (ring->wptr << 2));
+ WDOORBELL64(ring->doorbell_index, ring->wptr << 2);
+ } else {
+ uint64_t wptr = ring->wptr << 2;
+
+ WREG32_SDMA(ring->me, mmSDMA0_PAGE_RB_WPTR,
+ lower_32_bits(wptr));
+ WREG32_SDMA(ring->me, mmSDMA0_PAGE_RB_WPTR_HI,
+ upper_32_bits(wptr));
}
}
static void sdma_v4_0_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count)
{
- struct amdgpu_sdma_instance *sdma = amdgpu_get_sdma_instance(ring);
+ struct amdgpu_sdma_instance *sdma = amdgpu_sdma_get_instance_from_ring(ring);
int i;
for (i = 0; i < count; i++)
@@ -444,9 +497,12 @@ static void sdma_v4_0_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count)
* Schedule an IB in the DMA ring (VEGA10).
*/
static void sdma_v4_0_ring_emit_ib(struct amdgpu_ring *ring,
- struct amdgpu_ib *ib,
- unsigned vmid, bool ctx_switch)
+ struct amdgpu_job *job,
+ struct amdgpu_ib *ib,
+ bool ctx_switch)
{
+ unsigned vmid = AMDGPU_JOB_GET_VMID(job);
+
/* IB packet must end on a 8 DW boundary */
sdma_v4_0_ring_insert_nop(ring, (10 - (lower_32_bits(ring->wptr) & 7)) % 8);
@@ -568,16 +624,16 @@ static void sdma_v4_0_gfx_stop(struct amdgpu_device *adev)
amdgpu_ttm_set_buffer_funcs_status(adev, false);
for (i = 0; i < adev->sdma.num_instances; i++) {
- rb_cntl = RREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_CNTL));
+ rb_cntl = RREG32_SDMA(i, mmSDMA0_GFX_RB_CNTL);
rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RB_ENABLE, 0);
- WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_CNTL), rb_cntl);
- ib_cntl = RREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_IB_CNTL));
+ WREG32_SDMA(i, mmSDMA0_GFX_RB_CNTL, rb_cntl);
+ ib_cntl = RREG32_SDMA(i, mmSDMA0_GFX_IB_CNTL);
ib_cntl = REG_SET_FIELD(ib_cntl, SDMA0_GFX_IB_CNTL, IB_ENABLE, 0);
- WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_IB_CNTL), ib_cntl);
+ WREG32_SDMA(i, mmSDMA0_GFX_IB_CNTL, ib_cntl);
}
- sdma0->ready = false;
- sdma1->ready = false;
+ sdma0->sched.ready = false;
+ sdma1->sched.ready = false;
}
/**
@@ -593,6 +649,39 @@ static void sdma_v4_0_rlc_stop(struct amdgpu_device *adev)
}
/**
+ * sdma_v4_0_page_stop - stop the page async dma engines
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Stop the page async dma ring buffers (VEGA10).
+ */
+static void sdma_v4_0_page_stop(struct amdgpu_device *adev)
+{
+ struct amdgpu_ring *sdma0 = &adev->sdma.instance[0].page;
+ struct amdgpu_ring *sdma1 = &adev->sdma.instance[1].page;
+ u32 rb_cntl, ib_cntl;
+ int i;
+
+ if ((adev->mman.buffer_funcs_ring == sdma0) ||
+ (adev->mman.buffer_funcs_ring == sdma1))
+ amdgpu_ttm_set_buffer_funcs_status(adev, false);
+
+ for (i = 0; i < adev->sdma.num_instances; i++) {
+ rb_cntl = RREG32_SDMA(i, mmSDMA0_PAGE_RB_CNTL);
+ rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_PAGE_RB_CNTL,
+ RB_ENABLE, 0);
+ WREG32_SDMA(i, mmSDMA0_PAGE_RB_CNTL, rb_cntl);
+ ib_cntl = RREG32_SDMA(i, mmSDMA0_PAGE_IB_CNTL);
+ ib_cntl = REG_SET_FIELD(ib_cntl, SDMA0_PAGE_IB_CNTL,
+ IB_ENABLE, 0);
+ WREG32_SDMA(i, mmSDMA0_PAGE_IB_CNTL, ib_cntl);
+ }
+
+ sdma0->sched.ready = false;
+ sdma1->sched.ready = false;
+}
+
+/**
* sdma_v_0_ctx_switch_enable - stop the async dma engines context switch
*
* @adev: amdgpu_device pointer
@@ -630,18 +719,15 @@ static void sdma_v4_0_ctx_switch_enable(struct amdgpu_device *adev, bool enable)
}
for (i = 0; i < adev->sdma.num_instances; i++) {
- f32_cntl = RREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_CNTL));
+ f32_cntl = RREG32_SDMA(i, mmSDMA0_CNTL);
f32_cntl = REG_SET_FIELD(f32_cntl, SDMA0_CNTL,
AUTO_CTXSW_ENABLE, enable ? 1 : 0);
if (enable && amdgpu_sdma_phase_quantum) {
- WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_PHASE0_QUANTUM),
- phase_quantum);
- WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_PHASE1_QUANTUM),
- phase_quantum);
- WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_PHASE2_QUANTUM),
- phase_quantum);
+ WREG32_SDMA(i, mmSDMA0_PHASE0_QUANTUM, phase_quantum);
+ WREG32_SDMA(i, mmSDMA0_PHASE1_QUANTUM, phase_quantum);
+ WREG32_SDMA(i, mmSDMA0_PHASE2_QUANTUM, phase_quantum);
}
- WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_CNTL), f32_cntl);
+ WREG32_SDMA(i, mmSDMA0_CNTL, f32_cntl);
}
}
@@ -662,156 +748,217 @@ static void sdma_v4_0_enable(struct amdgpu_device *adev, bool enable)
if (enable == false) {
sdma_v4_0_gfx_stop(adev);
sdma_v4_0_rlc_stop(adev);
+ if (adev->sdma.has_page_queue)
+ sdma_v4_0_page_stop(adev);
}
for (i = 0; i < adev->sdma.num_instances; i++) {
- f32_cntl = RREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_F32_CNTL));
+ f32_cntl = RREG32_SDMA(i, mmSDMA0_F32_CNTL);
f32_cntl = REG_SET_FIELD(f32_cntl, SDMA0_F32_CNTL, HALT, enable ? 0 : 1);
- WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_F32_CNTL), f32_cntl);
+ WREG32_SDMA(i, mmSDMA0_F32_CNTL, f32_cntl);
}
}
/**
+ * sdma_v4_0_rb_cntl - get parameters for rb_cntl
+ */
+static uint32_t sdma_v4_0_rb_cntl(struct amdgpu_ring *ring, uint32_t rb_cntl)
+{
+ /* Set ring buffer size in dwords */
+ uint32_t rb_bufsz = order_base_2(ring->ring_size / 4);
+
+ rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RB_SIZE, rb_bufsz);
+#ifdef __BIG_ENDIAN
+ rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RB_SWAP_ENABLE, 1);
+ rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL,
+ RPTR_WRITEBACK_SWAP_ENABLE, 1);
+#endif
+ return rb_cntl;
+}
+
+/**
* sdma_v4_0_gfx_resume - setup and start the async dma engines
*
* @adev: amdgpu_device pointer
+ * @i: instance to resume
*
* Set up the gfx DMA ring buffers and enable them (VEGA10).
* Returns 0 for success, error for failure.
*/
-static int sdma_v4_0_gfx_resume(struct amdgpu_device *adev)
+static void sdma_v4_0_gfx_resume(struct amdgpu_device *adev, unsigned int i)
{
- struct amdgpu_ring *ring;
+ struct amdgpu_ring *ring = &adev->sdma.instance[i].ring;
u32 rb_cntl, ib_cntl, wptr_poll_cntl;
- u32 rb_bufsz;
u32 wb_offset;
u32 doorbell;
u32 doorbell_offset;
- u32 temp;
u64 wptr_gpu_addr;
- int i, r;
-
- for (i = 0; i < adev->sdma.num_instances; i++) {
- ring = &adev->sdma.instance[i].ring;
- wb_offset = (ring->rptr_offs * 4);
- WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_SEM_WAIT_FAIL_TIMER_CNTL), 0);
+ wb_offset = (ring->rptr_offs * 4);
- /* Set ring buffer size in dwords */
- rb_bufsz = order_base_2(ring->ring_size / 4);
- rb_cntl = RREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_CNTL));
- rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RB_SIZE, rb_bufsz);
-#ifdef __BIG_ENDIAN
- rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RB_SWAP_ENABLE, 1);
- rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL,
- RPTR_WRITEBACK_SWAP_ENABLE, 1);
-#endif
- WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_CNTL), rb_cntl);
+ rb_cntl = RREG32_SDMA(i, mmSDMA0_GFX_RB_CNTL);
+ rb_cntl = sdma_v4_0_rb_cntl(ring, rb_cntl);
+ WREG32_SDMA(i, mmSDMA0_GFX_RB_CNTL, rb_cntl);
- /* Initialize the ring buffer's read and write pointers */
- WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_RPTR), 0);
- WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_RPTR_HI), 0);
- WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR), 0);
- WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR_HI), 0);
+ /* Initialize the ring buffer's read and write pointers */
+ WREG32_SDMA(i, mmSDMA0_GFX_RB_RPTR, 0);
+ WREG32_SDMA(i, mmSDMA0_GFX_RB_RPTR_HI, 0);
+ WREG32_SDMA(i, mmSDMA0_GFX_RB_WPTR, 0);
+ WREG32_SDMA(i, mmSDMA0_GFX_RB_WPTR_HI, 0);
- /* set the wb address whether it's enabled or not */
- WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_RPTR_ADDR_HI),
- upper_32_bits(adev->wb.gpu_addr + wb_offset) & 0xFFFFFFFF);
- WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_RPTR_ADDR_LO),
- lower_32_bits(adev->wb.gpu_addr + wb_offset) & 0xFFFFFFFC);
+ /* set the wb address whether it's enabled or not */
+ WREG32_SDMA(i, mmSDMA0_GFX_RB_RPTR_ADDR_HI,
+ upper_32_bits(adev->wb.gpu_addr + wb_offset) & 0xFFFFFFFF);
+ WREG32_SDMA(i, mmSDMA0_GFX_RB_RPTR_ADDR_LO,
+ lower_32_bits(adev->wb.gpu_addr + wb_offset) & 0xFFFFFFFC);
- rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RPTR_WRITEBACK_ENABLE, 1);
+ rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL,
+ RPTR_WRITEBACK_ENABLE, 1);
- WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_BASE), ring->gpu_addr >> 8);
- WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_BASE_HI), ring->gpu_addr >> 40);
+ WREG32_SDMA(i, mmSDMA0_GFX_RB_BASE, ring->gpu_addr >> 8);
+ WREG32_SDMA(i, mmSDMA0_GFX_RB_BASE_HI, ring->gpu_addr >> 40);
- ring->wptr = 0;
+ ring->wptr = 0;
- /* before programing wptr to a less value, need set minor_ptr_update first */
- WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_MINOR_PTR_UPDATE), 1);
+ /* before programing wptr to a less value, need set minor_ptr_update first */
+ WREG32_SDMA(i, mmSDMA0_GFX_MINOR_PTR_UPDATE, 1);
- if (!amdgpu_sriov_vf(adev)) { /* only bare-metal use register write for wptr */
- WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR), lower_32_bits(ring->wptr) << 2);
- WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR_HI), upper_32_bits(ring->wptr) << 2);
- }
+ doorbell = RREG32_SDMA(i, mmSDMA0_GFX_DOORBELL);
+ doorbell_offset = RREG32_SDMA(i, mmSDMA0_GFX_DOORBELL_OFFSET);
- doorbell = RREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_DOORBELL));
- doorbell_offset = RREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_DOORBELL_OFFSET));
-
- if (ring->use_doorbell) {
- doorbell = REG_SET_FIELD(doorbell, SDMA0_GFX_DOORBELL, ENABLE, 1);
- doorbell_offset = REG_SET_FIELD(doorbell_offset, SDMA0_GFX_DOORBELL_OFFSET,
+ doorbell = REG_SET_FIELD(doorbell, SDMA0_GFX_DOORBELL, ENABLE,
+ ring->use_doorbell);
+ doorbell_offset = REG_SET_FIELD(doorbell_offset,
+ SDMA0_GFX_DOORBELL_OFFSET,
OFFSET, ring->doorbell_index);
- } else {
- doorbell = REG_SET_FIELD(doorbell, SDMA0_GFX_DOORBELL, ENABLE, 0);
- }
- WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_DOORBELL), doorbell);
- WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_DOORBELL_OFFSET), doorbell_offset);
- adev->nbio_funcs->sdma_doorbell_range(adev, i, ring->use_doorbell,
- ring->doorbell_index);
+ WREG32_SDMA(i, mmSDMA0_GFX_DOORBELL, doorbell);
+ WREG32_SDMA(i, mmSDMA0_GFX_DOORBELL_OFFSET, doorbell_offset);
+ adev->nbio_funcs->sdma_doorbell_range(adev, i, ring->use_doorbell,
+ ring->doorbell_index);
+
+ sdma_v4_0_ring_set_wptr(ring);
+
+ /* set minor_ptr_update to 0 after wptr programed */
+ WREG32_SDMA(i, mmSDMA0_GFX_MINOR_PTR_UPDATE, 0);
+
+ /* setup the wptr shadow polling */
+ wptr_gpu_addr = adev->wb.gpu_addr + (ring->wptr_offs * 4);
+ WREG32_SDMA(i, mmSDMA0_GFX_RB_WPTR_POLL_ADDR_LO,
+ lower_32_bits(wptr_gpu_addr));
+ WREG32_SDMA(i, mmSDMA0_GFX_RB_WPTR_POLL_ADDR_HI,
+ upper_32_bits(wptr_gpu_addr));
+ wptr_poll_cntl = RREG32_SDMA(i, mmSDMA0_GFX_RB_WPTR_POLL_CNTL);
+ wptr_poll_cntl = REG_SET_FIELD(wptr_poll_cntl,
+ SDMA0_GFX_RB_WPTR_POLL_CNTL,
+ F32_POLL_ENABLE, amdgpu_sriov_vf(adev));
+ WREG32_SDMA(i, mmSDMA0_GFX_RB_WPTR_POLL_CNTL, wptr_poll_cntl);
+
+ /* enable DMA RB */
+ rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RB_ENABLE, 1);
+ WREG32_SDMA(i, mmSDMA0_GFX_RB_CNTL, rb_cntl);
+
+ ib_cntl = RREG32_SDMA(i, mmSDMA0_GFX_IB_CNTL);
+ ib_cntl = REG_SET_FIELD(ib_cntl, SDMA0_GFX_IB_CNTL, IB_ENABLE, 1);
+#ifdef __BIG_ENDIAN
+ ib_cntl = REG_SET_FIELD(ib_cntl, SDMA0_GFX_IB_CNTL, IB_SWAP_ENABLE, 1);
+#endif
+ /* enable DMA IBs */
+ WREG32_SDMA(i, mmSDMA0_GFX_IB_CNTL, ib_cntl);
- if (amdgpu_sriov_vf(adev))
- sdma_v4_0_ring_set_wptr(ring);
+ ring->sched.ready = true;
+}
- /* set minor_ptr_update to 0 after wptr programed */
- WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_MINOR_PTR_UPDATE), 0);
+/**
+ * sdma_v4_0_page_resume - setup and start the async dma engines
+ *
+ * @adev: amdgpu_device pointer
+ * @i: instance to resume
+ *
+ * Set up the page DMA ring buffers and enable them (VEGA10).
+ * Returns 0 for success, error for failure.
+ */
+static void sdma_v4_0_page_resume(struct amdgpu_device *adev, unsigned int i)
+{
+ struct amdgpu_ring *ring = &adev->sdma.instance[i].page;
+ u32 rb_cntl, ib_cntl, wptr_poll_cntl;
+ u32 wb_offset;
+ u32 doorbell;
+ u32 doorbell_offset;
+ u64 wptr_gpu_addr;
- /* set utc l1 enable flag always to 1 */
- temp = RREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_CNTL));
- temp = REG_SET_FIELD(temp, SDMA0_CNTL, UTC_L1_ENABLE, 1);
- WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_CNTL), temp);
+ wb_offset = (ring->rptr_offs * 4);
- if (!amdgpu_sriov_vf(adev)) {
- /* unhalt engine */
- temp = RREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_F32_CNTL));
- temp = REG_SET_FIELD(temp, SDMA0_F32_CNTL, HALT, 0);
- WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_F32_CNTL), temp);
- }
+ rb_cntl = RREG32_SDMA(i, mmSDMA0_PAGE_RB_CNTL);
+ rb_cntl = sdma_v4_0_rb_cntl(ring, rb_cntl);
+ WREG32_SDMA(i, mmSDMA0_PAGE_RB_CNTL, rb_cntl);
- /* setup the wptr shadow polling */
- wptr_gpu_addr = adev->wb.gpu_addr + (ring->wptr_offs * 4);
- WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR_POLL_ADDR_LO),
- lower_32_bits(wptr_gpu_addr));
- WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR_POLL_ADDR_HI),
- upper_32_bits(wptr_gpu_addr));
- wptr_poll_cntl = RREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR_POLL_CNTL));
- if (amdgpu_sriov_vf(adev))
- wptr_poll_cntl = REG_SET_FIELD(wptr_poll_cntl, SDMA0_GFX_RB_WPTR_POLL_CNTL, F32_POLL_ENABLE, 1);
- else
- wptr_poll_cntl = REG_SET_FIELD(wptr_poll_cntl, SDMA0_GFX_RB_WPTR_POLL_CNTL, F32_POLL_ENABLE, 0);
- WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR_POLL_CNTL), wptr_poll_cntl);
+ /* Initialize the ring buffer's read and write pointers */
+ WREG32_SDMA(i, mmSDMA0_PAGE_RB_RPTR, 0);
+ WREG32_SDMA(i, mmSDMA0_PAGE_RB_RPTR_HI, 0);
+ WREG32_SDMA(i, mmSDMA0_PAGE_RB_WPTR, 0);
+ WREG32_SDMA(i, mmSDMA0_PAGE_RB_WPTR_HI, 0);
- /* enable DMA RB */
- rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RB_ENABLE, 1);
- WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_CNTL), rb_cntl);
+ /* set the wb address whether it's enabled or not */
+ WREG32_SDMA(i, mmSDMA0_PAGE_RB_RPTR_ADDR_HI,
+ upper_32_bits(adev->wb.gpu_addr + wb_offset) & 0xFFFFFFFF);
+ WREG32_SDMA(i, mmSDMA0_PAGE_RB_RPTR_ADDR_LO,
+ lower_32_bits(adev->wb.gpu_addr + wb_offset) & 0xFFFFFFFC);
- ib_cntl = RREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_IB_CNTL));
- ib_cntl = REG_SET_FIELD(ib_cntl, SDMA0_GFX_IB_CNTL, IB_ENABLE, 1);
-#ifdef __BIG_ENDIAN
- ib_cntl = REG_SET_FIELD(ib_cntl, SDMA0_GFX_IB_CNTL, IB_SWAP_ENABLE, 1);
-#endif
- /* enable DMA IBs */
- WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_IB_CNTL), ib_cntl);
+ rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_PAGE_RB_CNTL,
+ RPTR_WRITEBACK_ENABLE, 1);
- ring->ready = true;
+ WREG32_SDMA(i, mmSDMA0_PAGE_RB_BASE, ring->gpu_addr >> 8);
+ WREG32_SDMA(i, mmSDMA0_PAGE_RB_BASE_HI, ring->gpu_addr >> 40);
- if (amdgpu_sriov_vf(adev)) { /* bare-metal sequence doesn't need below to lines */
- sdma_v4_0_ctx_switch_enable(adev, true);
- sdma_v4_0_enable(adev, true);
- }
+ ring->wptr = 0;
- r = amdgpu_ring_test_ring(ring);
- if (r) {
- ring->ready = false;
- return r;
- }
+ /* before programing wptr to a less value, need set minor_ptr_update first */
+ WREG32_SDMA(i, mmSDMA0_PAGE_MINOR_PTR_UPDATE, 1);
- if (adev->mman.buffer_funcs_ring == ring)
- amdgpu_ttm_set_buffer_funcs_status(adev, true);
+ doorbell = RREG32_SDMA(i, mmSDMA0_PAGE_DOORBELL);
+ doorbell_offset = RREG32_SDMA(i, mmSDMA0_PAGE_DOORBELL_OFFSET);
- }
+ doorbell = REG_SET_FIELD(doorbell, SDMA0_PAGE_DOORBELL, ENABLE,
+ ring->use_doorbell);
+ doorbell_offset = REG_SET_FIELD(doorbell_offset,
+ SDMA0_PAGE_DOORBELL_OFFSET,
+ OFFSET, ring->doorbell_index);
+ WREG32_SDMA(i, mmSDMA0_PAGE_DOORBELL, doorbell);
+ WREG32_SDMA(i, mmSDMA0_PAGE_DOORBELL_OFFSET, doorbell_offset);
+ /* TODO: enable doorbell support */
+ /*adev->nbio_funcs->sdma_doorbell_range(adev, i, ring->use_doorbell,
+ ring->doorbell_index);*/
+
+ sdma_v4_0_ring_set_wptr(ring);
+
+ /* set minor_ptr_update to 0 after wptr programed */
+ WREG32_SDMA(i, mmSDMA0_PAGE_MINOR_PTR_UPDATE, 0);
+
+ /* setup the wptr shadow polling */
+ wptr_gpu_addr = adev->wb.gpu_addr + (ring->wptr_offs * 4);
+ WREG32_SDMA(i, mmSDMA0_PAGE_RB_WPTR_POLL_ADDR_LO,
+ lower_32_bits(wptr_gpu_addr));
+ WREG32_SDMA(i, mmSDMA0_PAGE_RB_WPTR_POLL_ADDR_HI,
+ upper_32_bits(wptr_gpu_addr));
+ wptr_poll_cntl = RREG32_SDMA(i, mmSDMA0_PAGE_RB_WPTR_POLL_CNTL);
+ wptr_poll_cntl = REG_SET_FIELD(wptr_poll_cntl,
+ SDMA0_PAGE_RB_WPTR_POLL_CNTL,
+ F32_POLL_ENABLE, amdgpu_sriov_vf(adev));
+ WREG32_SDMA(i, mmSDMA0_PAGE_RB_WPTR_POLL_CNTL, wptr_poll_cntl);
+
+ /* enable DMA RB */
+ rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_PAGE_RB_CNTL, RB_ENABLE, 1);
+ WREG32_SDMA(i, mmSDMA0_PAGE_RB_CNTL, rb_cntl);
+
+ ib_cntl = RREG32_SDMA(i, mmSDMA0_PAGE_IB_CNTL);
+ ib_cntl = REG_SET_FIELD(ib_cntl, SDMA0_PAGE_IB_CNTL, IB_ENABLE, 1);
+#ifdef __BIG_ENDIAN
+ ib_cntl = REG_SET_FIELD(ib_cntl, SDMA0_PAGE_IB_CNTL, IB_SWAP_ENABLE, 1);
+#endif
+ /* enable DMA IBs */
+ WREG32_SDMA(i, mmSDMA0_PAGE_IB_CNTL, ib_cntl);
- return 0;
+ ring->sched.ready = true;
}
static void
@@ -922,12 +1069,14 @@ static int sdma_v4_0_load_microcode(struct amdgpu_device *adev)
(adev->sdma.instance[i].fw->data +
le32_to_cpu(hdr->header.ucode_array_offset_bytes));
- WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_UCODE_ADDR), 0);
+ WREG32_SDMA(i, mmSDMA0_UCODE_ADDR, 0);
for (j = 0; j < fw_size; j++)
- WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_UCODE_DATA), le32_to_cpup(fw_data++));
+ WREG32_SDMA(i, mmSDMA0_UCODE_DATA,
+ le32_to_cpup(fw_data++));
- WREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_UCODE_ADDR), adev->sdma.instance[i].fw_version);
+ WREG32_SDMA(i, mmSDMA0_UCODE_ADDR,
+ adev->sdma.instance[i].fw_version);
}
return 0;
@@ -943,33 +1092,78 @@ static int sdma_v4_0_load_microcode(struct amdgpu_device *adev)
*/
static int sdma_v4_0_start(struct amdgpu_device *adev)
{
- int r = 0;
+ struct amdgpu_ring *ring;
+ int i, r;
if (amdgpu_sriov_vf(adev)) {
sdma_v4_0_ctx_switch_enable(adev, false);
sdma_v4_0_enable(adev, false);
+ } else {
- /* set RB registers */
- r = sdma_v4_0_gfx_resume(adev);
- return r;
+ if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) {
+ r = sdma_v4_0_load_microcode(adev);
+ if (r)
+ return r;
+ }
+
+ /* unhalt the MEs */
+ sdma_v4_0_enable(adev, true);
+ /* enable sdma ring preemption */
+ sdma_v4_0_ctx_switch_enable(adev, true);
+ }
+
+ /* start the gfx rings and rlc compute queues */
+ for (i = 0; i < adev->sdma.num_instances; i++) {
+ uint32_t temp;
+
+ WREG32_SDMA(i, mmSDMA0_SEM_WAIT_FAIL_TIMER_CNTL, 0);
+ sdma_v4_0_gfx_resume(adev, i);
+ if (adev->sdma.has_page_queue)
+ sdma_v4_0_page_resume(adev, i);
+
+ /* set utc l1 enable flag always to 1 */
+ temp = RREG32_SDMA(i, mmSDMA0_CNTL);
+ temp = REG_SET_FIELD(temp, SDMA0_CNTL, UTC_L1_ENABLE, 1);
+ WREG32_SDMA(i, mmSDMA0_CNTL, temp);
+
+ if (!amdgpu_sriov_vf(adev)) {
+ /* unhalt engine */
+ temp = RREG32_SDMA(i, mmSDMA0_F32_CNTL);
+ temp = REG_SET_FIELD(temp, SDMA0_F32_CNTL, HALT, 0);
+ WREG32_SDMA(i, mmSDMA0_F32_CNTL, temp);
+ }
}
- if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) {
- r = sdma_v4_0_load_microcode(adev);
+ if (amdgpu_sriov_vf(adev)) {
+ sdma_v4_0_ctx_switch_enable(adev, true);
+ sdma_v4_0_enable(adev, true);
+ } else {
+ r = sdma_v4_0_rlc_resume(adev);
if (r)
return r;
}
- /* unhalt the MEs */
- sdma_v4_0_enable(adev, true);
- /* enable sdma ring preemption */
- sdma_v4_0_ctx_switch_enable(adev, true);
+ for (i = 0; i < adev->sdma.num_instances; i++) {
+ ring = &adev->sdma.instance[i].ring;
- /* start the gfx rings and rlc compute queues */
- r = sdma_v4_0_gfx_resume(adev);
- if (r)
- return r;
- r = sdma_v4_0_rlc_resume(adev);
+ r = amdgpu_ring_test_helper(ring);
+ if (r)
+ return r;
+
+ if (adev->sdma.has_page_queue) {
+ struct amdgpu_ring *page = &adev->sdma.instance[i].page;
+
+ r = amdgpu_ring_test_helper(page);
+ if (r)
+ return r;
+
+ if (adev->mman.buffer_funcs_ring == page)
+ amdgpu_ttm_set_buffer_funcs_status(adev, true);
+ }
+
+ if (adev->mman.buffer_funcs_ring == ring)
+ amdgpu_ttm_set_buffer_funcs_status(adev, true);
+ }
return r;
}
@@ -993,21 +1187,16 @@ static int sdma_v4_0_ring_test_ring(struct amdgpu_ring *ring)
u64 gpu_addr;
r = amdgpu_device_wb_get(adev, &index);
- if (r) {
- dev_err(adev->dev, "(%d) failed to allocate wb slot\n", r);
+ if (r)
return r;
- }
gpu_addr = adev->wb.gpu_addr + (index * 4);
tmp = 0xCAFEDEAD;
adev->wb.wb[index] = cpu_to_le32(tmp);
r = amdgpu_ring_alloc(ring, 5);
- if (r) {
- DRM_ERROR("amdgpu: dma failed to lock ring %d (%d).\n", ring->idx, r);
- amdgpu_device_wb_free(adev, index);
- return r;
- }
+ if (r)
+ goto error_free_wb;
amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_WRITE) |
SDMA_PKT_HEADER_SUB_OP(SDMA_SUBOP_WRITE_LINEAR));
@@ -1024,15 +1213,11 @@ static int sdma_v4_0_ring_test_ring(struct amdgpu_ring *ring)
DRM_UDELAY(1);
}
- if (i < adev->usec_timeout) {
- DRM_DEBUG("ring test on %d succeeded in %d usecs\n", ring->idx, i);
- } else {
- DRM_ERROR("amdgpu: ring %d test failed (0x%08X)\n",
- ring->idx, tmp);
- r = -EINVAL;
- }
- amdgpu_device_wb_free(adev, index);
+ if (i >= adev->usec_timeout)
+ r = -ETIMEDOUT;
+error_free_wb:
+ amdgpu_device_wb_free(adev, index);
return r;
}
@@ -1055,20 +1240,16 @@ static int sdma_v4_0_ring_test_ib(struct amdgpu_ring *ring, long timeout)
u64 gpu_addr;
r = amdgpu_device_wb_get(adev, &index);
- if (r) {
- dev_err(adev->dev, "(%ld) failed to allocate wb slot\n", r);
+ if (r)
return r;
- }
gpu_addr = adev->wb.gpu_addr + (index * 4);
tmp = 0xCAFEDEAD;
adev->wb.wb[index] = cpu_to_le32(tmp);
memset(&ib, 0, sizeof(ib));
r = amdgpu_ib_get(adev, NULL, 256, &ib);
- if (r) {
- DRM_ERROR("amdgpu: failed to get ib (%ld).\n", r);
+ if (r)
goto err0;
- }
ib.ptr[0] = SDMA_PKT_HEADER_OP(SDMA_OP_WRITE) |
SDMA_PKT_HEADER_SUB_OP(SDMA_SUBOP_WRITE_LINEAR);
@@ -1087,21 +1268,17 @@ static int sdma_v4_0_ring_test_ib(struct amdgpu_ring *ring, long timeout)
r = dma_fence_wait_timeout(f, false, timeout);
if (r == 0) {
- DRM_ERROR("amdgpu: IB test timed out\n");
r = -ETIMEDOUT;
goto err1;
} else if (r < 0) {
- DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r);
goto err1;
}
tmp = le32_to_cpu(adev->wb.wb[index]);
- if (tmp == 0xDEADBEEF) {
- DRM_DEBUG("ib test on ring %d succeeded\n", ring->idx);
+ if (tmp == 0xDEADBEEF)
r = 0;
- } else {
- DRM_ERROR("amdgpu: ib test failed (0x%08X)\n", tmp);
+ else
r = -EINVAL;
- }
+
err1:
amdgpu_ib_free(adev, &ib, NULL);
dma_fence_put(f);
@@ -1206,7 +1383,7 @@ static void sdma_v4_0_vm_set_pte_pde(struct amdgpu_ib *ib,
*/
static void sdma_v4_0_ring_pad_ib(struct amdgpu_ring *ring, struct amdgpu_ib *ib)
{
- struct amdgpu_sdma_instance *sdma = amdgpu_get_sdma_instance(ring);
+ struct amdgpu_sdma_instance *sdma = amdgpu_sdma_get_instance_from_ring(ring);
u32 pad_count;
int i;
@@ -1276,10 +1453,18 @@ static int sdma_v4_0_early_init(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
- if (adev->asic_type == CHIP_RAVEN)
+ if (adev->asic_type == CHIP_RAVEN) {
adev->sdma.num_instances = 1;
- else
+ adev->sdma.has_page_queue = false;
+ } else {
adev->sdma.num_instances = 2;
+ /* TODO: Page queue breaks driver reload under SRIOV */
+ if ((adev->asic_type == CHIP_VEGA10) && amdgpu_sriov_vf((adev)))
+ adev->sdma.has_page_queue = false;
+ else if (adev->asic_type != CHIP_VEGA20 &&
+ adev->asic_type != CHIP_VEGA12)
+ adev->sdma.has_page_queue = true;
+ }
sdma_v4_0_set_ring_funcs(adev);
sdma_v4_0_set_buffer_funcs(adev);
@@ -1340,6 +1525,21 @@ static int sdma_v4_0_sw_init(void *handle)
AMDGPU_SDMA_IRQ_TRAP1);
if (r)
return r;
+
+ if (adev->sdma.has_page_queue) {
+ ring = &adev->sdma.instance[i].page;
+ ring->ring_obj = NULL;
+ ring->use_doorbell = false;
+
+ sprintf(ring->name, "page%d", i);
+ r = amdgpu_ring_init(adev, ring, 1024,
+ &adev->sdma.trap_irq,
+ (i == 0) ?
+ AMDGPU_SDMA_IRQ_TRAP0 :
+ AMDGPU_SDMA_IRQ_TRAP1);
+ if (r)
+ return r;
+ }
}
return r;
@@ -1350,8 +1550,11 @@ static int sdma_v4_0_sw_fini(void *handle)
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
int i;
- for (i = 0; i < adev->sdma.num_instances; i++)
+ for (i = 0; i < adev->sdma.num_instances; i++) {
amdgpu_ring_fini(&adev->sdma.instance[i].ring);
+ if (adev->sdma.has_page_queue)
+ amdgpu_ring_fini(&adev->sdma.instance[i].page);
+ }
for (i = 0; i < adev->sdma.num_instances; i++) {
release_firmware(adev->sdma.instance[i].fw);
@@ -1414,7 +1617,7 @@ static bool sdma_v4_0_is_idle(void *handle)
u32 i;
for (i = 0; i < adev->sdma.num_instances; i++) {
- u32 tmp = RREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_STATUS_REG));
+ u32 tmp = RREG32_SDMA(i, mmSDMA0_STATUS_REG);
if (!(tmp & SDMA0_STATUS_REG__IDLE_MASK))
return false;
@@ -1430,8 +1633,8 @@ static int sdma_v4_0_wait_for_idle(void *handle)
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
for (i = 0; i < adev->usec_timeout; i++) {
- sdma0 = RREG32(sdma_v4_0_get_reg_offset(adev, 0, mmSDMA0_STATUS_REG));
- sdma1 = RREG32(sdma_v4_0_get_reg_offset(adev, 1, mmSDMA0_STATUS_REG));
+ sdma0 = RREG32_SDMA(0, mmSDMA0_STATUS_REG);
+ sdma1 = RREG32_SDMA(1, mmSDMA0_STATUS_REG);
if (sdma0 & sdma1 & SDMA0_STATUS_REG__IDLE_MASK)
return 0;
@@ -1452,16 +1655,13 @@ static int sdma_v4_0_set_trap_irq_state(struct amdgpu_device *adev,
unsigned type,
enum amdgpu_interrupt_state state)
{
+ unsigned int instance = (type == AMDGPU_SDMA_IRQ_TRAP0) ? 0 : 1;
u32 sdma_cntl;
- u32 reg_offset = (type == AMDGPU_SDMA_IRQ_TRAP0) ?
- sdma_v4_0_get_reg_offset(adev, 0, mmSDMA0_CNTL) :
- sdma_v4_0_get_reg_offset(adev, 1, mmSDMA0_CNTL);
-
- sdma_cntl = RREG32(reg_offset);
+ sdma_cntl = RREG32_SDMA(instance, mmSDMA0_CNTL);
sdma_cntl = REG_SET_FIELD(sdma_cntl, SDMA0_CNTL, TRAP_ENABLE,
state == AMDGPU_IRQ_STATE_ENABLE ? 1 : 0);
- WREG32(reg_offset, sdma_cntl);
+ WREG32_SDMA(instance, mmSDMA0_CNTL, sdma_cntl);
return 0;
}
@@ -1470,39 +1670,32 @@ static int sdma_v4_0_process_trap_irq(struct amdgpu_device *adev,
struct amdgpu_irq_src *source,
struct amdgpu_iv_entry *entry)
{
+ uint32_t instance;
+
DRM_DEBUG("IH: SDMA trap\n");
switch (entry->client_id) {
case SOC15_IH_CLIENTID_SDMA0:
- switch (entry->ring_id) {
- case 0:
- amdgpu_fence_process(&adev->sdma.instance[0].ring);
- break;
- case 1:
- /* XXX compute */
- break;
- case 2:
- /* XXX compute */
- break;
- case 3:
- /* XXX page queue*/
- break;
- }
+ instance = 0;
break;
case SOC15_IH_CLIENTID_SDMA1:
- switch (entry->ring_id) {
- case 0:
- amdgpu_fence_process(&adev->sdma.instance[1].ring);
- break;
- case 1:
- /* XXX compute */
- break;
- case 2:
- /* XXX compute */
- break;
- case 3:
- /* XXX page queue*/
- break;
- }
+ instance = 1;
+ break;
+ default:
+ return 0;
+ }
+
+ switch (entry->ring_id) {
+ case 0:
+ amdgpu_fence_process(&adev->sdma.instance[instance].ring);
+ break;
+ case 1:
+ /* XXX compute */
+ break;
+ case 2:
+ /* XXX compute */
+ break;
+ case 3:
+ amdgpu_fence_process(&adev->sdma.instance[instance].page);
break;
}
return 0;
@@ -1512,12 +1705,29 @@ static int sdma_v4_0_process_illegal_inst_irq(struct amdgpu_device *adev,
struct amdgpu_irq_src *source,
struct amdgpu_iv_entry *entry)
{
+ int instance;
+
DRM_ERROR("Illegal instruction in SDMA command stream\n");
- schedule_work(&adev->reset_work);
+
+ switch (entry->client_id) {
+ case SOC15_IH_CLIENTID_SDMA0:
+ instance = 0;
+ break;
+ case SOC15_IH_CLIENTID_SDMA1:
+ instance = 1;
+ break;
+ default:
+ return 0;
+ }
+
+ switch (entry->ring_id) {
+ case 0:
+ drm_sched_fault(&adev->sdma.instance[instance].ring.sched);
+ break;
+ }
return 0;
}
-
static void sdma_v4_0_update_medium_grain_clock_gating(
struct amdgpu_device *adev,
bool enable)
@@ -1730,6 +1940,38 @@ static const struct amdgpu_ring_funcs sdma_v4_0_ring_funcs = {
.emit_reg_write_reg_wait = amdgpu_ring_emit_reg_write_reg_wait_helper,
};
+static const struct amdgpu_ring_funcs sdma_v4_0_page_ring_funcs = {
+ .type = AMDGPU_RING_TYPE_SDMA,
+ .align_mask = 0xf,
+ .nop = SDMA_PKT_NOP_HEADER_OP(SDMA_OP_NOP),
+ .support_64bit_ptrs = true,
+ .vmhub = AMDGPU_MMHUB,
+ .get_rptr = sdma_v4_0_ring_get_rptr,
+ .get_wptr = sdma_v4_0_page_ring_get_wptr,
+ .set_wptr = sdma_v4_0_page_ring_set_wptr,
+ .emit_frame_size =
+ 6 + /* sdma_v4_0_ring_emit_hdp_flush */
+ 3 + /* hdp invalidate */
+ 6 + /* sdma_v4_0_ring_emit_pipeline_sync */
+ /* sdma_v4_0_ring_emit_vm_flush */
+ SOC15_FLUSH_GPU_TLB_NUM_WREG * 3 +
+ SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 6 +
+ 10 + 10 + 10, /* sdma_v4_0_ring_emit_fence x3 for user fence, vm fence */
+ .emit_ib_size = 7 + 6, /* sdma_v4_0_ring_emit_ib */
+ .emit_ib = sdma_v4_0_ring_emit_ib,
+ .emit_fence = sdma_v4_0_ring_emit_fence,
+ .emit_pipeline_sync = sdma_v4_0_ring_emit_pipeline_sync,
+ .emit_vm_flush = sdma_v4_0_ring_emit_vm_flush,
+ .emit_hdp_flush = sdma_v4_0_ring_emit_hdp_flush,
+ .test_ring = sdma_v4_0_ring_test_ring,
+ .test_ib = sdma_v4_0_ring_test_ib,
+ .insert_nop = sdma_v4_0_ring_insert_nop,
+ .pad_ib = sdma_v4_0_ring_pad_ib,
+ .emit_wreg = sdma_v4_0_ring_emit_wreg,
+ .emit_reg_wait = sdma_v4_0_ring_emit_reg_wait,
+ .emit_reg_write_reg_wait = amdgpu_ring_emit_reg_write_reg_wait_helper,
+};
+
static void sdma_v4_0_set_ring_funcs(struct amdgpu_device *adev)
{
int i;
@@ -1737,6 +1979,10 @@ static void sdma_v4_0_set_ring_funcs(struct amdgpu_device *adev)
for (i = 0; i < adev->sdma.num_instances; i++) {
adev->sdma.instance[i].ring.funcs = &sdma_v4_0_ring_funcs;
adev->sdma.instance[i].ring.me = i;
+ if (adev->sdma.has_page_queue) {
+ adev->sdma.instance[i].page.funcs = &sdma_v4_0_page_ring_funcs;
+ adev->sdma.instance[i].page.me = i;
+ }
}
}
@@ -1818,7 +2064,10 @@ static const struct amdgpu_buffer_funcs sdma_v4_0_buffer_funcs = {
static void sdma_v4_0_set_buffer_funcs(struct amdgpu_device *adev)
{
adev->mman.buffer_funcs = &sdma_v4_0_buffer_funcs;
- adev->mman.buffer_funcs_ring = &adev->sdma.instance[0].ring;
+ if (adev->sdma.has_page_queue)
+ adev->mman.buffer_funcs_ring = &adev->sdma.instance[0].page;
+ else
+ adev->mman.buffer_funcs_ring = &adev->sdma.instance[0].ring;
}
static const struct amdgpu_vm_pte_funcs sdma_v4_0_vm_pte_funcs = {
@@ -1836,7 +2085,10 @@ static void sdma_v4_0_set_vm_pte_funcs(struct amdgpu_device *adev)
adev->vm_manager.vm_pte_funcs = &sdma_v4_0_vm_pte_funcs;
for (i = 0; i < adev->sdma.num_instances; i++) {
- sched = &adev->sdma.instance[i].ring.sched;
+ if (adev->sdma.has_page_queue)
+ sched = &adev->sdma.instance[i].page.sched;
+ else
+ sched = &adev->sdma.instance[i].ring.sched;
adev->vm_manager.vm_pte_rqs[i] =
&sched->sched_rq[DRM_SCHED_PRIORITY_KERNEL];
}
diff --git a/drivers/gpu/drm/amd/amdgpu/si_dma.c b/drivers/gpu/drm/amd/amdgpu/si_dma.c
index adbaea6da0d7..b6e473134e19 100644
--- a/drivers/gpu/drm/amd/amdgpu/si_dma.c
+++ b/drivers/gpu/drm/amd/amdgpu/si_dma.c
@@ -61,9 +61,11 @@ static void si_dma_ring_set_wptr(struct amdgpu_ring *ring)
}
static void si_dma_ring_emit_ib(struct amdgpu_ring *ring,
+ struct amdgpu_job *job,
struct amdgpu_ib *ib,
- unsigned vmid, bool ctx_switch)
+ bool ctx_switch)
{
+ unsigned vmid = AMDGPU_JOB_GET_VMID(job);
/* The indirect buffer packet must end on an 8 DW boundary in the DMA ring.
* Pad as necessary with NOPs.
*/
@@ -122,7 +124,7 @@ static void si_dma_stop(struct amdgpu_device *adev)
if (adev->mman.buffer_funcs_ring == ring)
amdgpu_ttm_set_buffer_funcs_status(adev, false);
- ring->ready = false;
+ ring->sched.ready = false;
}
}
@@ -175,13 +177,11 @@ static int si_dma_start(struct amdgpu_device *adev)
WREG32(DMA_RB_WPTR + sdma_offsets[i], lower_32_bits(ring->wptr) << 2);
WREG32(DMA_RB_CNTL + sdma_offsets[i], rb_cntl | DMA_RB_ENABLE);
- ring->ready = true;
+ ring->sched.ready = true;
- r = amdgpu_ring_test_ring(ring);
- if (r) {
- ring->ready = false;
+ r = amdgpu_ring_test_helper(ring);
+ if (r)
return r;
- }
if (adev->mman.buffer_funcs_ring == ring)
amdgpu_ttm_set_buffer_funcs_status(adev, true);
@@ -209,21 +209,16 @@ static int si_dma_ring_test_ring(struct amdgpu_ring *ring)
u64 gpu_addr;
r = amdgpu_device_wb_get(adev, &index);
- if (r) {
- dev_err(adev->dev, "(%d) failed to allocate wb slot\n", r);
+ if (r)
return r;
- }
gpu_addr = adev->wb.gpu_addr + (index * 4);
tmp = 0xCAFEDEAD;
adev->wb.wb[index] = cpu_to_le32(tmp);
r = amdgpu_ring_alloc(ring, 4);
- if (r) {
- DRM_ERROR("amdgpu: dma failed to lock ring %d (%d).\n", ring->idx, r);
- amdgpu_device_wb_free(adev, index);
- return r;
- }
+ if (r)
+ goto error_free_wb;
amdgpu_ring_write(ring, DMA_PACKET(DMA_PACKET_WRITE, 0, 0, 0, 1));
amdgpu_ring_write(ring, lower_32_bits(gpu_addr));
@@ -238,15 +233,11 @@ static int si_dma_ring_test_ring(struct amdgpu_ring *ring)
DRM_UDELAY(1);
}
- if (i < adev->usec_timeout) {
- DRM_DEBUG("ring test on %d succeeded in %d usecs\n", ring->idx, i);
- } else {
- DRM_ERROR("amdgpu: ring %d test failed (0x%08X)\n",
- ring->idx, tmp);
- r = -EINVAL;
- }
- amdgpu_device_wb_free(adev, index);
+ if (i >= adev->usec_timeout)
+ r = -ETIMEDOUT;
+error_free_wb:
+ amdgpu_device_wb_free(adev, index);
return r;
}
@@ -269,20 +260,16 @@ static int si_dma_ring_test_ib(struct amdgpu_ring *ring, long timeout)
long r;
r = amdgpu_device_wb_get(adev, &index);
- if (r) {
- dev_err(adev->dev, "(%ld) failed to allocate wb slot\n", r);
+ if (r)
return r;
- }
gpu_addr = adev->wb.gpu_addr + (index * 4);
tmp = 0xCAFEDEAD;
adev->wb.wb[index] = cpu_to_le32(tmp);
memset(&ib, 0, sizeof(ib));
r = amdgpu_ib_get(adev, NULL, 256, &ib);
- if (r) {
- DRM_ERROR("amdgpu: failed to get ib (%ld).\n", r);
+ if (r)
goto err0;
- }
ib.ptr[0] = DMA_PACKET(DMA_PACKET_WRITE, 0, 0, 0, 1);
ib.ptr[1] = lower_32_bits(gpu_addr);
@@ -295,21 +282,16 @@ static int si_dma_ring_test_ib(struct amdgpu_ring *ring, long timeout)
r = dma_fence_wait_timeout(f, false, timeout);
if (r == 0) {
- DRM_ERROR("amdgpu: IB test timed out\n");
r = -ETIMEDOUT;
goto err1;
} else if (r < 0) {
- DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r);
goto err1;
}
tmp = le32_to_cpu(adev->wb.wb[index]);
- if (tmp == 0xDEADBEEF) {
- DRM_DEBUG("ib test on ring %d succeeded\n", ring->idx);
+ if (tmp == 0xDEADBEEF)
r = 0;
- } else {
- DRM_ERROR("amdgpu: ib test failed (0x%08X)\n", tmp);
+ else
r = -EINVAL;
- }
err1:
amdgpu_ib_free(adev, &ib, NULL);
@@ -658,15 +640,6 @@ static int si_dma_process_trap_irq(struct amdgpu_device *adev,
return 0;
}
-static int si_dma_process_illegal_inst_irq(struct amdgpu_device *adev,
- struct amdgpu_irq_src *source,
- struct amdgpu_iv_entry *entry)
-{
- DRM_ERROR("Illegal instruction in SDMA command stream\n");
- schedule_work(&adev->reset_work);
- return 0;
-}
-
static int si_dma_set_clockgating_state(void *handle,
enum amd_clockgating_state state)
{
@@ -781,15 +754,10 @@ static const struct amdgpu_irq_src_funcs si_dma_trap_irq_funcs = {
.process = si_dma_process_trap_irq,
};
-static const struct amdgpu_irq_src_funcs si_dma_illegal_inst_irq_funcs = {
- .process = si_dma_process_illegal_inst_irq,
-};
-
static void si_dma_set_irq_funcs(struct amdgpu_device *adev)
{
adev->sdma.trap_irq.num_types = AMDGPU_SDMA_IRQ_LAST;
adev->sdma.trap_irq.funcs = &si_dma_trap_irq_funcs;
- adev->sdma.illegal_inst_irq.funcs = &si_dma_illegal_inst_irq_funcs;
}
/**
diff --git a/drivers/gpu/drm/amd/amdgpu/ta_xgmi_if.h b/drivers/gpu/drm/amd/amdgpu/ta_xgmi_if.h
new file mode 100644
index 000000000000..ac2c27b7630c
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/ta_xgmi_if.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2018 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 _TA_XGMI_IF_H
+#define _TA_XGMI_IF_H
+
+/* Responses have bit 31 set */
+#define RSP_ID_MASK (1U << 31)
+#define RSP_ID(cmdId) (((uint32_t)(cmdId)) | RSP_ID_MASK)
+
+enum ta_command_xgmi {
+ TA_COMMAND_XGMI__INITIALIZE = 0x00,
+ TA_COMMAND_XGMI__GET_NODE_ID = 0x01,
+ TA_COMMAND_XGMI__GET_HIVE_ID = 0x02,
+ TA_COMMAND_XGMI__GET_GET_TOPOLOGY_INFO = 0x03,
+ TA_COMMAND_XGMI__SET_TOPOLOGY_INFO = 0x04
+};
+
+/* XGMI related enumerations */
+/**********************************************************/;
+enum ta_xgmi_connected_nodes {
+ TA_XGMI__MAX_CONNECTED_NODES = 64
+};
+
+enum ta_xgmi_status {
+ TA_XGMI_STATUS__SUCCESS = 0x00,
+ TA_XGMI_STATUS__GENERIC_FAILURE = 0x01,
+ TA_XGMI_STATUS__NULL_POINTER = 0x02,
+ TA_XGMI_STATUS__INVALID_PARAMETER = 0x03,
+ TA_XGMI_STATUS__NOT_INITIALIZED = 0x04,
+ TA_XGMI_STATUS__INVALID_NODE_NUM = 0x05,
+ TA_XGMI_STATUS__INVALID_NODE_ID = 0x06,
+ TA_XGMI_STATUS__INVALID_TOPOLOGY = 0x07,
+ TA_XGMI_STATUS__FAILED_ID_GEN = 0x08,
+ TA_XGMI_STATUS__FAILED_TOPOLOGY_INIT = 0x09,
+ TA_XGMI_STATUS__SET_SHARING_ERROR = 0x0A
+};
+
+enum ta_xgmi_assigned_sdma_engine {
+ TA_XGMI_ASSIGNED_SDMA_ENGINE__NOT_ASSIGNED = -1,
+ TA_XGMI_ASSIGNED_SDMA_ENGINE__SDMA0 = 0,
+ TA_XGMI_ASSIGNED_SDMA_ENGINE__SDMA1 = 1,
+ TA_XGMI_ASSIGNED_SDMA_ENGINE__SDMA2 = 2,
+ TA_XGMI_ASSIGNED_SDMA_ENGINE__SDMA3 = 3,
+ TA_XGMI_ASSIGNED_SDMA_ENGINE__SDMA4 = 4,
+ TA_XGMI_ASSIGNED_SDMA_ENGINE__SDMA5 = 5
+};
+
+/* input/output structures for XGMI commands */
+/**********************************************************/
+struct ta_xgmi_node_info {
+ uint64_t node_id;
+ uint8_t num_hops;
+ uint8_t is_sharing_enabled;
+ enum ta_xgmi_assigned_sdma_engine sdma_engine;
+};
+
+struct ta_xgmi_cmd_initialize_output {
+ uint32_t status;
+};
+
+struct ta_xgmi_cmd_get_node_id_output {
+ uint64_t node_id;
+};
+
+struct ta_xgmi_cmd_get_hive_id_output {
+ uint64_t hive_id;
+};
+
+struct ta_xgmi_cmd_get_topology_info_input {
+ uint32_t num_nodes;
+ struct ta_xgmi_node_info nodes[TA_XGMI__MAX_CONNECTED_NODES];
+};
+
+struct ta_xgmi_cmd_get_topology_info_output {
+ uint32_t num_nodes;
+ struct ta_xgmi_node_info nodes[TA_XGMI__MAX_CONNECTED_NODES];
+};
+
+struct ta_xgmi_cmd_set_topology_info_input {
+ uint32_t num_nodes;
+ struct ta_xgmi_node_info nodes[TA_XGMI__MAX_CONNECTED_NODES];
+};
+
+/**********************************************************/
+/* Common input structure for XGMI callbacks */
+union ta_xgmi_cmd_input {
+ struct ta_xgmi_cmd_get_topology_info_input get_topology_info;
+ struct ta_xgmi_cmd_set_topology_info_input set_topology_info;
+};
+
+/* Common output structure for XGMI callbacks */
+union ta_xgmi_cmd_output {
+ struct ta_xgmi_cmd_initialize_output initialize;
+ struct ta_xgmi_cmd_get_node_id_output get_node_id;
+ struct ta_xgmi_cmd_get_hive_id_output get_hive_id;
+ struct ta_xgmi_cmd_get_topology_info_output get_topology_info;
+};
+/**********************************************************/
+
+struct ta_xgmi_shared_memory {
+ uint32_t cmd_id;
+ uint32_t resp_id;
+ enum ta_xgmi_status xgmi_status;
+ uint32_t reserved;
+ union ta_xgmi_cmd_input xgmi_in_message;
+ union ta_xgmi_cmd_output xgmi_out_message;
+};
+
+#endif //_TA_XGMI_IF_H
diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c
index 1fc17bf39fed..90bbcee00f28 100644
--- a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c
+++ b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c
@@ -162,12 +162,9 @@ static int uvd_v4_2_hw_init(void *handle)
uvd_v4_2_enable_mgcg(adev, true);
amdgpu_asic_set_uvd_clocks(adev, 10000, 10000);
- ring->ready = true;
- r = amdgpu_ring_test_ring(ring);
- if (r) {
- ring->ready = false;
+ r = amdgpu_ring_test_helper(ring);
+ if (r)
goto done;
- }
r = amdgpu_ring_alloc(ring, 10);
if (r) {
@@ -218,7 +215,7 @@ static int uvd_v4_2_hw_fini(void *handle)
if (RREG32(mmUVD_STATUS) != 0)
uvd_v4_2_stop(adev);
- ring->ready = false;
+ ring->sched.ready = false;
return 0;
}
@@ -484,11 +481,9 @@ static int uvd_v4_2_ring_test_ring(struct amdgpu_ring *ring)
WREG32(mmUVD_CONTEXT_ID, 0xCAFEDEAD);
r = amdgpu_ring_alloc(ring, 3);
- if (r) {
- DRM_ERROR("amdgpu: cp failed to lock ring %d (%d).\n",
- ring->idx, r);
+ if (r)
return r;
- }
+
amdgpu_ring_write(ring, PACKET0(mmUVD_CONTEXT_ID, 0));
amdgpu_ring_write(ring, 0xDEADBEEF);
amdgpu_ring_commit(ring);
@@ -499,14 +494,9 @@ static int uvd_v4_2_ring_test_ring(struct amdgpu_ring *ring)
DRM_UDELAY(1);
}
- if (i < adev->usec_timeout) {
- DRM_DEBUG("ring test on %d succeeded in %d usecs\n",
- ring->idx, i);
- } else {
- DRM_ERROR("amdgpu: ring %d test failed (0x%08X)\n",
- ring->idx, tmp);
- r = -EINVAL;
- }
+ if (i >= adev->usec_timeout)
+ r = -ETIMEDOUT;
+
return r;
}
@@ -519,8 +509,9 @@ static int uvd_v4_2_ring_test_ring(struct amdgpu_ring *ring)
* Write ring commands to execute the indirect buffer
*/
static void uvd_v4_2_ring_emit_ib(struct amdgpu_ring *ring,
+ struct amdgpu_job *job,
struct amdgpu_ib *ib,
- unsigned vmid, bool ctx_switch)
+ bool ctx_switch)
{
amdgpu_ring_write(ring, PACKET0(mmUVD_RBC_IB_BASE, 0));
amdgpu_ring_write(ring, ib->gpu_addr);
diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c
index fde6ad5ac9ab..1c5e12703103 100644
--- a/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c
@@ -158,12 +158,9 @@ static int uvd_v5_0_hw_init(void *handle)
uvd_v5_0_set_clockgating_state(adev, AMD_CG_STATE_UNGATE);
uvd_v5_0_enable_mgcg(adev, true);
- ring->ready = true;
- r = amdgpu_ring_test_ring(ring);
- if (r) {
- ring->ready = false;
+ r = amdgpu_ring_test_helper(ring);
+ if (r)
goto done;
- }
r = amdgpu_ring_alloc(ring, 10);
if (r) {
@@ -215,7 +212,7 @@ static int uvd_v5_0_hw_fini(void *handle)
if (RREG32(mmUVD_STATUS) != 0)
uvd_v5_0_stop(adev);
- ring->ready = false;
+ ring->sched.ready = false;
return 0;
}
@@ -500,11 +497,8 @@ static int uvd_v5_0_ring_test_ring(struct amdgpu_ring *ring)
WREG32(mmUVD_CONTEXT_ID, 0xCAFEDEAD);
r = amdgpu_ring_alloc(ring, 3);
- if (r) {
- DRM_ERROR("amdgpu: cp failed to lock ring %d (%d).\n",
- ring->idx, r);
+ if (r)
return r;
- }
amdgpu_ring_write(ring, PACKET0(mmUVD_CONTEXT_ID, 0));
amdgpu_ring_write(ring, 0xDEADBEEF);
amdgpu_ring_commit(ring);
@@ -515,14 +509,9 @@ static int uvd_v5_0_ring_test_ring(struct amdgpu_ring *ring)
DRM_UDELAY(1);
}
- if (i < adev->usec_timeout) {
- DRM_DEBUG("ring test on %d succeeded in %d usecs\n",
- ring->idx, i);
- } else {
- DRM_ERROR("amdgpu: ring %d test failed (0x%08X)\n",
- ring->idx, tmp);
- r = -EINVAL;
- }
+ if (i >= adev->usec_timeout)
+ r = -ETIMEDOUT;
+
return r;
}
@@ -535,8 +524,9 @@ static int uvd_v5_0_ring_test_ring(struct amdgpu_ring *ring)
* Write ring commands to execute the indirect buffer
*/
static void uvd_v5_0_ring_emit_ib(struct amdgpu_ring *ring,
+ struct amdgpu_job *job,
struct amdgpu_ib *ib,
- unsigned vmid, bool ctx_switch)
+ bool ctx_switch)
{
amdgpu_ring_write(ring, PACKET0(mmUVD_LMI_RBC_IB_64BIT_BAR_LOW, 0));
amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr));
diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c
index 7a5b40275e8e..f184842ef2a2 100644
--- a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c
@@ -175,11 +175,8 @@ static int uvd_v6_0_enc_ring_test_ring(struct amdgpu_ring *ring)
int r;
r = amdgpu_ring_alloc(ring, 16);
- if (r) {
- DRM_ERROR("amdgpu: uvd enc failed to lock ring %d (%d).\n",
- ring->idx, r);
+ if (r)
return r;
- }
amdgpu_ring_write(ring, HEVC_ENC_CMD_END);
amdgpu_ring_commit(ring);
@@ -189,14 +186,8 @@ static int uvd_v6_0_enc_ring_test_ring(struct amdgpu_ring *ring)
DRM_UDELAY(1);
}
- if (i < adev->usec_timeout) {
- DRM_DEBUG("ring test on %d succeeded in %d usecs\n",
- ring->idx, i);
- } else {
- DRM_ERROR("amdgpu: ring %d test failed\n",
- ring->idx);
+ if (i >= adev->usec_timeout)
r = -ETIMEDOUT;
- }
return r;
}
@@ -336,31 +327,24 @@ static int uvd_v6_0_enc_ring_test_ib(struct amdgpu_ring *ring, long timeout)
long r;
r = uvd_v6_0_enc_get_create_msg(ring, 1, NULL);
- if (r) {
- DRM_ERROR("amdgpu: failed to get create msg (%ld).\n", r);
+ if (r)
goto error;
- }
r = uvd_v6_0_enc_get_destroy_msg(ring, 1, &fence);
- if (r) {
- DRM_ERROR("amdgpu: failed to get destroy ib (%ld).\n", r);
+ if (r)
goto error;
- }
r = dma_fence_wait_timeout(fence, false, timeout);
- if (r == 0) {
- DRM_ERROR("amdgpu: IB test timed out.\n");
+ if (r == 0)
r = -ETIMEDOUT;
- } else if (r < 0) {
- DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r);
- } else {
- DRM_DEBUG("ib test on ring %d succeeded\n", ring->idx);
+ else if (r > 0)
r = 0;
- }
+
error:
dma_fence_put(fence);
return r;
}
+
static int uvd_v6_0_early_init(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
@@ -476,12 +460,9 @@ static int uvd_v6_0_hw_init(void *handle)
uvd_v6_0_set_clockgating_state(adev, AMD_CG_STATE_UNGATE);
uvd_v6_0_enable_mgcg(adev, true);
- ring->ready = true;
- r = amdgpu_ring_test_ring(ring);
- if (r) {
- ring->ready = false;
+ r = amdgpu_ring_test_helper(ring);
+ if (r)
goto done;
- }
r = amdgpu_ring_alloc(ring, 10);
if (r) {
@@ -513,12 +494,9 @@ static int uvd_v6_0_hw_init(void *handle)
if (uvd_v6_0_enc_support(adev)) {
for (i = 0; i < adev->uvd.num_enc_rings; ++i) {
ring = &adev->uvd.inst->ring_enc[i];
- ring->ready = true;
- r = amdgpu_ring_test_ring(ring);
- if (r) {
- ring->ready = false;
+ r = amdgpu_ring_test_helper(ring);
+ if (r)
goto done;
- }
}
}
@@ -548,7 +526,7 @@ static int uvd_v6_0_hw_fini(void *handle)
if (RREG32(mmUVD_STATUS) != 0)
uvd_v6_0_stop(adev);
- ring->ready = false;
+ ring->sched.ready = false;
return 0;
}
@@ -969,11 +947,9 @@ static int uvd_v6_0_ring_test_ring(struct amdgpu_ring *ring)
WREG32(mmUVD_CONTEXT_ID, 0xCAFEDEAD);
r = amdgpu_ring_alloc(ring, 3);
- if (r) {
- DRM_ERROR("amdgpu: cp failed to lock ring %d (%d).\n",
- ring->idx, r);
+ if (r)
return r;
- }
+
amdgpu_ring_write(ring, PACKET0(mmUVD_CONTEXT_ID, 0));
amdgpu_ring_write(ring, 0xDEADBEEF);
amdgpu_ring_commit(ring);
@@ -984,14 +960,9 @@ static int uvd_v6_0_ring_test_ring(struct amdgpu_ring *ring)
DRM_UDELAY(1);
}
- if (i < adev->usec_timeout) {
- DRM_DEBUG("ring test on %d succeeded in %d usecs\n",
- ring->idx, i);
- } else {
- DRM_ERROR("amdgpu: ring %d test failed (0x%08X)\n",
- ring->idx, tmp);
- r = -EINVAL;
- }
+ if (i >= adev->usec_timeout)
+ r = -ETIMEDOUT;
+
return r;
}
@@ -1004,9 +975,12 @@ static int uvd_v6_0_ring_test_ring(struct amdgpu_ring *ring)
* Write ring commands to execute the indirect buffer
*/
static void uvd_v6_0_ring_emit_ib(struct amdgpu_ring *ring,
+ struct amdgpu_job *job,
struct amdgpu_ib *ib,
- unsigned vmid, bool ctx_switch)
+ bool ctx_switch)
{
+ unsigned vmid = AMDGPU_JOB_GET_VMID(job);
+
amdgpu_ring_write(ring, PACKET0(mmUVD_LMI_RBC_IB_VMID, 0));
amdgpu_ring_write(ring, vmid);
@@ -1027,8 +1001,12 @@ static void uvd_v6_0_ring_emit_ib(struct amdgpu_ring *ring,
* Write enc ring commands to execute the indirect buffer
*/
static void uvd_v6_0_enc_ring_emit_ib(struct amdgpu_ring *ring,
- struct amdgpu_ib *ib, unsigned int vmid, bool ctx_switch)
+ struct amdgpu_job *job,
+ struct amdgpu_ib *ib,
+ bool ctx_switch)
{
+ unsigned vmid = AMDGPU_JOB_GET_VMID(job);
+
amdgpu_ring_write(ring, HEVC_ENC_CMD_IB_VM);
amdgpu_ring_write(ring, vmid);
amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr));
diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c
index 58b39afcfb86..8a4595968d98 100644
--- a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c
@@ -183,11 +183,8 @@ static int uvd_v7_0_enc_ring_test_ring(struct amdgpu_ring *ring)
return 0;
r = amdgpu_ring_alloc(ring, 16);
- if (r) {
- DRM_ERROR("amdgpu: uvd enc failed to lock (%d)ring %d (%d).\n",
- ring->me, ring->idx, r);
+ if (r)
return r;
- }
amdgpu_ring_write(ring, HEVC_ENC_CMD_END);
amdgpu_ring_commit(ring);
@@ -197,14 +194,8 @@ static int uvd_v7_0_enc_ring_test_ring(struct amdgpu_ring *ring)
DRM_UDELAY(1);
}
- if (i < adev->usec_timeout) {
- DRM_DEBUG("(%d)ring test on %d succeeded in %d usecs\n",
- ring->me, ring->idx, i);
- } else {
- DRM_ERROR("amdgpu: (%d)ring %d test failed\n",
- ring->me, ring->idx);
+ if (i >= adev->usec_timeout)
r = -ETIMEDOUT;
- }
return r;
}
@@ -343,27 +334,19 @@ static int uvd_v7_0_enc_ring_test_ib(struct amdgpu_ring *ring, long timeout)
long r;
r = uvd_v7_0_enc_get_create_msg(ring, 1, NULL);
- if (r) {
- DRM_ERROR("amdgpu: (%d)failed to get create msg (%ld).\n", ring->me, r);
+ if (r)
goto error;
- }
r = uvd_v7_0_enc_get_destroy_msg(ring, 1, &fence);
- if (r) {
- DRM_ERROR("amdgpu: (%d)failed to get destroy ib (%ld).\n", ring->me, r);
+ if (r)
goto error;
- }
r = dma_fence_wait_timeout(fence, false, timeout);
- if (r == 0) {
- DRM_ERROR("amdgpu: (%d)IB test timed out.\n", ring->me);
+ if (r == 0)
r = -ETIMEDOUT;
- } else if (r < 0) {
- DRM_ERROR("amdgpu: (%d)fence wait failed (%ld).\n", ring->me, r);
- } else {
- DRM_DEBUG("ib test on (%d)ring %d succeeded\n", ring->me, ring->idx);
+ else if (r > 0)
r = 0;
- }
+
error:
dma_fence_put(fence);
return r;
@@ -540,12 +523,9 @@ static int uvd_v7_0_hw_init(void *handle)
ring = &adev->uvd.inst[j].ring;
if (!amdgpu_sriov_vf(adev)) {
- ring->ready = true;
- r = amdgpu_ring_test_ring(ring);
- if (r) {
- ring->ready = false;
+ r = amdgpu_ring_test_helper(ring);
+ if (r)
goto done;
- }
r = amdgpu_ring_alloc(ring, 10);
if (r) {
@@ -582,12 +562,9 @@ static int uvd_v7_0_hw_init(void *handle)
for (i = 0; i < adev->uvd.num_enc_rings; ++i) {
ring = &adev->uvd.inst[j].ring_enc[i];
- ring->ready = true;
- r = amdgpu_ring_test_ring(ring);
- if (r) {
- ring->ready = false;
+ r = amdgpu_ring_test_helper(ring);
+ if (r)
goto done;
- }
}
}
done:
@@ -619,7 +596,7 @@ static int uvd_v7_0_hw_fini(void *handle)
for (i = 0; i < adev->uvd.num_uvd_inst; ++i) {
if (adev->uvd.harvest_config & (1 << i))
continue;
- adev->uvd.inst[i].ring.ready = false;
+ adev->uvd.inst[i].ring.sched.ready = false;
}
return 0;
@@ -1235,11 +1212,9 @@ static int uvd_v7_0_ring_test_ring(struct amdgpu_ring *ring)
WREG32_SOC15(UVD, ring->me, mmUVD_CONTEXT_ID, 0xCAFEDEAD);
r = amdgpu_ring_alloc(ring, 3);
- if (r) {
- DRM_ERROR("amdgpu: (%d)cp failed to lock ring %d (%d).\n",
- ring->me, ring->idx, r);
+ if (r)
return r;
- }
+
amdgpu_ring_write(ring,
PACKET0(SOC15_REG_OFFSET(UVD, ring->me, mmUVD_CONTEXT_ID), 0));
amdgpu_ring_write(ring, 0xDEADBEEF);
@@ -1251,14 +1226,9 @@ static int uvd_v7_0_ring_test_ring(struct amdgpu_ring *ring)
DRM_UDELAY(1);
}
- if (i < adev->usec_timeout) {
- DRM_DEBUG("(%d)ring test on %d succeeded in %d usecs\n",
- ring->me, ring->idx, i);
- } else {
- DRM_ERROR("(%d)amdgpu: ring %d test failed (0x%08X)\n",
- ring->me, ring->idx, tmp);
- r = -EINVAL;
- }
+ if (i >= adev->usec_timeout)
+ r = -ETIMEDOUT;
+
return r;
}
@@ -1300,10 +1270,12 @@ static int uvd_v7_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p,
* Write ring commands to execute the indirect buffer
*/
static void uvd_v7_0_ring_emit_ib(struct amdgpu_ring *ring,
+ struct amdgpu_job *job,
struct amdgpu_ib *ib,
- unsigned vmid, bool ctx_switch)
+ bool ctx_switch)
{
struct amdgpu_device *adev = ring->adev;
+ unsigned vmid = AMDGPU_JOB_GET_VMID(job);
amdgpu_ring_write(ring,
PACKET0(SOC15_REG_OFFSET(UVD, ring->me, mmUVD_LMI_RBC_IB_VMID), 0));
@@ -1329,8 +1301,12 @@ static void uvd_v7_0_ring_emit_ib(struct amdgpu_ring *ring,
* Write enc ring commands to execute the indirect buffer
*/
static void uvd_v7_0_enc_ring_emit_ib(struct amdgpu_ring *ring,
- struct amdgpu_ib *ib, unsigned int vmid, bool ctx_switch)
+ struct amdgpu_job *job,
+ struct amdgpu_ib *ib,
+ bool ctx_switch)
{
+ unsigned vmid = AMDGPU_JOB_GET_VMID(job);
+
amdgpu_ring_write(ring, HEVC_ENC_CMD_IB_VM);
amdgpu_ring_write(ring, vmid);
amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr));
diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c
index ea28828360d3..bed78a778e3f 100644
--- a/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c
@@ -463,15 +463,11 @@ static int vce_v2_0_hw_init(void *handle)
amdgpu_asic_set_vce_clocks(adev, 10000, 10000);
vce_v2_0_enable_mgcg(adev, true, false);
- for (i = 0; i < adev->vce.num_rings; i++)
- adev->vce.ring[i].ready = false;
for (i = 0; i < adev->vce.num_rings; i++) {
- r = amdgpu_ring_test_ring(&adev->vce.ring[i]);
+ r = amdgpu_ring_test_helper(&adev->vce.ring[i]);
if (r)
return r;
- else
- adev->vce.ring[i].ready = true;
}
DRM_INFO("VCE initialized successfully.\n");
diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
index 6dbd39730070..3e84840859a7 100644
--- a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
@@ -474,15 +474,10 @@ static int vce_v3_0_hw_init(void *handle)
amdgpu_asic_set_vce_clocks(adev, 10000, 10000);
- for (i = 0; i < adev->vce.num_rings; i++)
- adev->vce.ring[i].ready = false;
-
for (i = 0; i < adev->vce.num_rings; i++) {
- r = amdgpu_ring_test_ring(&adev->vce.ring[i]);
+ r = amdgpu_ring_test_helper(&adev->vce.ring[i]);
if (r)
return r;
- else
- adev->vce.ring[i].ready = true;
}
DRM_INFO("VCE initialized successfully.\n");
@@ -838,8 +833,12 @@ out:
}
static void vce_v3_0_ring_emit_ib(struct amdgpu_ring *ring,
- struct amdgpu_ib *ib, unsigned int vmid, bool ctx_switch)
+ struct amdgpu_job *job,
+ struct amdgpu_ib *ib,
+ bool ctx_switch)
{
+ unsigned vmid = AMDGPU_JOB_GET_VMID(job);
+
amdgpu_ring_write(ring, VCE_CMD_IB_VM);
amdgpu_ring_write(ring, vmid);
amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr));
diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c
index 1c9471890bf7..0054ba1b9a68 100644
--- a/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c
@@ -519,15 +519,10 @@ static int vce_v4_0_hw_init(void *handle)
if (r)
return r;
- for (i = 0; i < adev->vce.num_rings; i++)
- adev->vce.ring[i].ready = false;
-
for (i = 0; i < adev->vce.num_rings; i++) {
- r = amdgpu_ring_test_ring(&adev->vce.ring[i]);
+ r = amdgpu_ring_test_helper(&adev->vce.ring[i]);
if (r)
return r;
- else
- adev->vce.ring[i].ready = true;
}
DRM_INFO("VCE initialized successfully.\n");
@@ -549,7 +544,7 @@ static int vce_v4_0_hw_fini(void *handle)
}
for (i = 0; i < adev->vce.num_rings; i++)
- adev->vce.ring[i].ready = false;
+ adev->vce.ring[i].sched.ready = false;
return 0;
}
@@ -951,9 +946,11 @@ static int vce_v4_0_set_powergating_state(void *handle,
}
#endif
-static void vce_v4_0_ring_emit_ib(struct amdgpu_ring *ring,
- struct amdgpu_ib *ib, unsigned int vmid, bool ctx_switch)
+static void vce_v4_0_ring_emit_ib(struct amdgpu_ring *ring, struct amdgpu_job *job,
+ struct amdgpu_ib *ib, bool ctx_switch)
{
+ unsigned vmid = AMDGPU_JOB_GET_VMID(job);
+
amdgpu_ring_write(ring, VCE_CMD_IB_VM);
amdgpu_ring_write(ring, vmid);
amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr));
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c
index eae90922fdbe..c1a03505f956 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c
@@ -176,30 +176,22 @@ static int vcn_v1_0_hw_init(void *handle)
struct amdgpu_ring *ring = &adev->vcn.ring_dec;
int i, r;
- ring->ready = true;
- r = amdgpu_ring_test_ring(ring);
- if (r) {
- ring->ready = false;
+ r = amdgpu_ring_test_helper(ring);
+ if (r)
goto done;
- }
for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
ring = &adev->vcn.ring_enc[i];
- ring->ready = true;
- r = amdgpu_ring_test_ring(ring);
- if (r) {
- ring->ready = false;
+ ring->sched.ready = true;
+ r = amdgpu_ring_test_helper(ring);
+ if (r)
goto done;
- }
}
ring = &adev->vcn.ring_jpeg;
- ring->ready = true;
- r = amdgpu_ring_test_ring(ring);
- if (r) {
- ring->ready = false;
+ r = amdgpu_ring_test_helper(ring);
+ if (r)
goto done;
- }
done:
if (!r)
@@ -224,7 +216,7 @@ static int vcn_v1_0_hw_fini(void *handle)
if (RREG32_SOC15(VCN, 0, mmUVD_STATUS))
vcn_v1_0_stop(adev);
- ring->ready = false;
+ ring->sched.ready = false;
return 0;
}
@@ -1366,10 +1358,12 @@ static void vcn_v1_0_dec_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64
* Write ring commands to execute the indirect buffer
*/
static void vcn_v1_0_dec_ring_emit_ib(struct amdgpu_ring *ring,
- struct amdgpu_ib *ib,
- unsigned vmid, bool ctx_switch)
+ struct amdgpu_job *job,
+ struct amdgpu_ib *ib,
+ bool ctx_switch)
{
struct amdgpu_device *adev = ring->adev;
+ unsigned vmid = AMDGPU_JOB_GET_VMID(job);
amdgpu_ring_write(ring,
PACKET0(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_RBC_IB_VMID), 0));
@@ -1524,8 +1518,12 @@ static void vcn_v1_0_enc_ring_insert_end(struct amdgpu_ring *ring)
* Write enc ring commands to execute the indirect buffer
*/
static void vcn_v1_0_enc_ring_emit_ib(struct amdgpu_ring *ring,
- struct amdgpu_ib *ib, unsigned int vmid, bool ctx_switch)
+ struct amdgpu_job *job,
+ struct amdgpu_ib *ib,
+ bool ctx_switch)
{
+ unsigned vmid = AMDGPU_JOB_GET_VMID(job);
+
amdgpu_ring_write(ring, VCN_ENC_CMD_IB);
amdgpu_ring_write(ring, vmid);
amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr));
@@ -1725,10 +1723,12 @@ static void vcn_v1_0_jpeg_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u6
* Write ring commands to execute the indirect buffer.
*/
static void vcn_v1_0_jpeg_ring_emit_ib(struct amdgpu_ring *ring,
- struct amdgpu_ib *ib,
- unsigned vmid, bool ctx_switch)
+ struct amdgpu_job *job,
+ struct amdgpu_ib *ib,
+ bool ctx_switch)
{
struct amdgpu_device *adev = ring->adev;
+ unsigned vmid = AMDGPU_JOB_GET_VMID(job);
amdgpu_ring_write(ring,
PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_IB_VMID), 0, 0, PACKETJ_TYPE0));
diff --git a/drivers/gpu/drm/amd/amdgpu/vega10_ih.c b/drivers/gpu/drm/amd/amdgpu/vega10_ih.c
index a99f71797aa3..a0fda6f9252a 100644
--- a/drivers/gpu/drm/amd/amdgpu/vega10_ih.c
+++ b/drivers/gpu/drm/amd/amdgpu/vega10_ih.c
@@ -129,7 +129,7 @@ static int vega10_ih_irq_init(struct amdgpu_device *adev)
else
wptr_off = adev->wb.gpu_addr + (adev->irq.ih.wptr_offs * 4);
WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_ADDR_LO, lower_32_bits(wptr_off));
- WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_ADDR_HI, upper_32_bits(wptr_off) & 0xFF);
+ WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_ADDR_HI, upper_32_bits(wptr_off) & 0xFFFF);
/* set rptr, wptr to 0 */
WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR, 0);
diff --git a/drivers/gpu/drm/amd/amdgpu/vega20_reg_init.c b/drivers/gpu/drm/amd/amdgpu/vega20_reg_init.c
index 2d4473557b0d..d13fc4fcb517 100644
--- a/drivers/gpu/drm/amd/amdgpu/vega20_reg_init.c
+++ b/drivers/gpu/drm/amd/amdgpu/vega20_reg_init.c
@@ -49,6 +49,7 @@ int vega20_reg_base_init(struct amdgpu_device *adev)
adev->reg_offset[SMUIO_HWIP][i] = (uint32_t *)(&(SMUIO_BASE.instance[i]));
adev->reg_offset[NBIF_HWIP][i] = (uint32_t *)(&(NBIO_BASE.instance[i]));
adev->reg_offset[THM_HWIP][i] = (uint32_t *)(&(THM_BASE.instance[i]));
+ adev->reg_offset[CLK_HWIP][i] = (uint32_t *)(&(CLK_BASE.instance[i]));
}
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c b/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c
index 5d2475d5392c..177d1e5329a5 100644
--- a/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c
+++ b/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c
@@ -23,6 +23,7 @@
#include "kfd_priv.h"
#include "kfd_events.h"
#include "cik_int.h"
+#include "amdgpu_amdkfd.h"
static bool cik_event_interrupt_isr(struct kfd_dev *dev,
const uint32_t *ih_ring_entry,
@@ -107,7 +108,7 @@ static void cik_event_interrupt_wq(struct kfd_dev *dev,
kfd_process_vm_fault(dev->dqm, pasid);
memset(&info, 0, sizeof(info));
- dev->kfd2kgd->get_vm_fault_info(dev->kgd, &info);
+ amdgpu_amdkfd_gpuvm_get_vm_fault_info(dev->kgd, &info);
if (!info.page_addr && !info.status)
return;
diff --git a/drivers/gpu/drm/amd/amdkfd/cik_regs.h b/drivers/gpu/drm/amd/amdkfd/cik_regs.h
index 37ce6dd65391..8e2a1663c4db 100644
--- a/drivers/gpu/drm/amd/amdkfd/cik_regs.h
+++ b/drivers/gpu/drm/amd/amdkfd/cik_regs.h
@@ -68,6 +68,4 @@
#define GRBM_GFX_INDEX 0x30800
-#define ATC_VMID_PASID_MAPPING_VALID (1U << 31)
-
#endif
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
index 14d5b5fa822d..5f4062b41add 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
@@ -37,6 +37,7 @@
#include "kfd_priv.h"
#include "kfd_device_queue_manager.h"
#include "kfd_dbgmgr.h"
+#include "amdgpu_amdkfd.h"
static long kfd_ioctl(struct file *, unsigned int, unsigned long);
static int kfd_open(struct inode *, struct file *);
@@ -834,8 +835,7 @@ static int kfd_ioctl_get_clock_counters(struct file *filep,
dev = kfd_device_by_id(args->gpu_id);
if (dev)
/* Reading GPU clock counter from KGD */
- args->gpu_clock_counter =
- dev->kfd2kgd->get_gpu_clock_counter(dev->kgd);
+ args->gpu_clock_counter = amdgpu_amdkfd_get_gpu_clock_counter(dev->kgd);
else
/* Node without GPU resource */
args->gpu_clock_counter = 0;
@@ -1042,7 +1042,7 @@ static int kfd_ioctl_create_event(struct file *filp, struct kfd_process *p,
}
mutex_unlock(&p->mutex);
- err = kfd->kfd2kgd->map_gtt_bo_to_kernel(kfd->kgd,
+ err = amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel(kfd->kgd,
mem, &kern_addr, &size);
if (err) {
pr_err("Failed to map event page to kernel\n");
@@ -1240,7 +1240,7 @@ bool kfd_dev_is_large_bar(struct kfd_dev *dev)
if (dev->device_info->needs_iommu_device)
return false;
- dev->kfd2kgd->get_local_mem_info(dev->kgd, &mem_info);
+ amdgpu_amdkfd_get_local_mem_info(dev->kgd, &mem_info);
if (mem_info.local_mem_size_private == 0 &&
mem_info.local_mem_size_public > 0)
return true;
@@ -1281,7 +1281,7 @@ static int kfd_ioctl_alloc_memory_of_gpu(struct file *filep,
goto err_unlock;
}
- err = dev->kfd2kgd->alloc_memory_of_gpu(
+ err = amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu(
dev->kgd, args->va_addr, args->size,
pdd->vm, (struct kgd_mem **) &mem, &offset,
flags);
@@ -1303,7 +1303,7 @@ static int kfd_ioctl_alloc_memory_of_gpu(struct file *filep,
return 0;
err_free:
- dev->kfd2kgd->free_memory_of_gpu(dev->kgd, (struct kgd_mem *)mem);
+ amdgpu_amdkfd_gpuvm_free_memory_of_gpu(dev->kgd, (struct kgd_mem *)mem);
err_unlock:
mutex_unlock(&p->mutex);
return err;
@@ -1338,7 +1338,8 @@ static int kfd_ioctl_free_memory_of_gpu(struct file *filep,
goto err_unlock;
}
- ret = dev->kfd2kgd->free_memory_of_gpu(dev->kgd, (struct kgd_mem *)mem);
+ ret = amdgpu_amdkfd_gpuvm_free_memory_of_gpu(dev->kgd,
+ (struct kgd_mem *)mem);
/* If freeing the buffer failed, leave the handle in place for
* clean-up during process tear-down.
@@ -1418,7 +1419,7 @@ static int kfd_ioctl_map_memory_to_gpu(struct file *filep,
err = PTR_ERR(peer_pdd);
goto get_mem_obj_from_handle_failed;
}
- err = peer->kfd2kgd->map_memory_to_gpu(
+ err = amdgpu_amdkfd_gpuvm_map_memory_to_gpu(
peer->kgd, (struct kgd_mem *)mem, peer_pdd->vm);
if (err) {
pr_err("Failed to map to gpu %d/%d\n",
@@ -1430,7 +1431,7 @@ static int kfd_ioctl_map_memory_to_gpu(struct file *filep,
mutex_unlock(&p->mutex);
- err = dev->kfd2kgd->sync_memory(dev->kgd, (struct kgd_mem *) mem, true);
+ 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;
@@ -1525,7 +1526,7 @@ static int kfd_ioctl_unmap_memory_from_gpu(struct file *filep,
err = -ENODEV;
goto get_mem_obj_from_handle_failed;
}
- err = dev->kfd2kgd->unmap_memory_to_gpu(
+ err = amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu(
peer->kgd, (struct kgd_mem *)mem, peer_pdd->vm);
if (err) {
pr_err("Failed to unmap from gpu %d/%d\n",
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c
index 56412b0e7e1c..3783d122f283 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c
@@ -26,6 +26,7 @@
#include "kfd_priv.h"
#include "kfd_topology.h"
#include "kfd_iommu.h"
+#include "amdgpu_amdkfd.h"
/* GPU Processor ID base for dGPUs for which VCRAT needs to be created.
* GPU processor ID are expressed with Bit[31]=1.
@@ -753,12 +754,10 @@ int kfd_create_crat_image_acpi(void **crat_image, size_t *size)
return -ENODATA;
}
- pcrat_image = kmalloc(crat_table->length, GFP_KERNEL);
+ pcrat_image = kmemdup(crat_table, crat_table->length, GFP_KERNEL);
if (!pcrat_image)
return -ENOMEM;
- memcpy(pcrat_image, crat_table, crat_table->length);
-
*crat_image = pcrat_image;
*size = crat_table->length;
@@ -1161,7 +1160,7 @@ static int kfd_create_vcrat_image_gpu(void *pcrat_image,
cu->flags |= CRAT_CU_FLAGS_GPU_PRESENT;
cu->proximity_domain = proximity_domain;
- kdev->kfd2kgd->get_cu_info(kdev->kgd, &cu_info);
+ amdgpu_amdkfd_get_cu_info(kdev->kgd, &cu_info);
cu->num_simd_per_cu = cu_info.simd_per_cu;
cu->num_simd_cores = cu_info.simd_per_cu * cu_info.cu_active_number;
cu->max_waves_simd = cu_info.max_waves_per_simd;
@@ -1192,7 +1191,7 @@ static int kfd_create_vcrat_image_gpu(void *pcrat_image,
* report the total FB size (public+private) as a single
* private heap.
*/
- kdev->kfd2kgd->get_local_mem_info(kdev->kgd, &local_mem_info);
+ amdgpu_amdkfd_get_local_mem_info(kdev->kgd, &local_mem_info);
sub_type_hdr = (typeof(sub_type_hdr))((char *)sub_type_hdr +
sub_type_hdr->length);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
index a9f18ea7e354..c004647c8cb4 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
@@ -28,6 +28,7 @@
#include "kfd_pm4_headers_vi.h"
#include "cwsr_trap_handler.h"
#include "kfd_iommu.h"
+#include "amdgpu_amdkfd.h"
#define MQD_SIZE_ALIGNED 768
@@ -478,7 +479,7 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd,
/* add another 512KB for all other allocations on gart (HPD, fences) */
size += 512 * 1024;
- if (kfd->kfd2kgd->init_gtt_mem_allocation(
+ if (amdgpu_amdkfd_alloc_gtt_mem(
kfd->kgd, size, &kfd->gtt_mem,
&kfd->gtt_start_gpu_addr, &kfd->gtt_start_cpu_ptr,
false)) {
@@ -552,7 +553,7 @@ kfd_topology_add_device_error:
kfd_doorbell_error:
kfd_gtt_sa_fini(kfd);
kfd_gtt_sa_init_error:
- kfd->kfd2kgd->free_gtt_mem(kfd->kgd, kfd->gtt_mem);
+ amdgpu_amdkfd_free_gtt_mem(kfd->kgd, kfd->gtt_mem);
dev_err(kfd_device,
"device %x:%x NOT added due to errors\n",
kfd->pdev->vendor, kfd->pdev->device);
@@ -569,7 +570,7 @@ void kgd2kfd_device_exit(struct kfd_dev *kfd)
kfd_topology_remove_device(kfd);
kfd_doorbell_fini(kfd);
kfd_gtt_sa_fini(kfd);
- kfd->kfd2kgd->free_gtt_mem(kfd->kgd, kfd->gtt_mem);
+ amdgpu_amdkfd_free_gtt_mem(kfd->kgd, kfd->gtt_mem);
}
kfree(kfd);
@@ -681,6 +682,7 @@ void kgd2kfd_interrupt(struct kfd_dev *kfd, const void *ih_ring_entry)
{
uint32_t patched_ihre[KFD_MAX_RING_ENTRY_SIZE];
bool is_patched = false;
+ unsigned long flags;
if (!kfd->init_complete)
return;
@@ -690,7 +692,7 @@ void kgd2kfd_interrupt(struct kfd_dev *kfd, const void *ih_ring_entry)
return;
}
- spin_lock(&kfd->interrupt_lock);
+ spin_lock_irqsave(&kfd->interrupt_lock, flags);
if (kfd->interrupts_active
&& interrupt_is_wanted(kfd, ih_ring_entry,
@@ -699,7 +701,7 @@ void kgd2kfd_interrupt(struct kfd_dev *kfd, const void *ih_ring_entry)
is_patched ? patched_ihre : ih_ring_entry))
queue_work(kfd->ih_wq, &kfd->interrupt_work);
- spin_unlock(&kfd->interrupt_lock);
+ spin_unlock_irqrestore(&kfd->interrupt_lock, flags);
}
int kgd2kfd_quiesce_mm(struct mm_struct *mm)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
index a3b933967171..fb9d66ea13b7 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
@@ -33,6 +33,7 @@
#include "kfd_mqd_manager.h"
#include "cik_regs.h"
#include "kfd_kernel_queue.h"
+#include "amdgpu_amdkfd.h"
/* Size of the per-pipe EOP queue */
#define CIK_HPD_EOP_BYTES_LOG2 11
@@ -219,7 +220,7 @@ static int flush_texture_cache_nocpsch(struct kfd_dev *kdev,
if (ret)
return ret;
- return kdev->kfd2kgd->submit_ib(kdev->kgd, KGD_ENGINE_MEC1, qpd->vmid,
+ return amdgpu_amdkfd_submit_ib(kdev->kgd, KGD_ENGINE_MEC1, qpd->vmid,
qpd->ib_base, (uint32_t *)qpd->ib_kaddr,
pmf->release_mem_size / sizeof(uint32_t));
}
@@ -672,7 +673,7 @@ static int restore_process_queues_nocpsch(struct device_queue_manager *dqm,
pdd = qpd_to_pdd(qpd);
/* Retrieve PD base */
- pd_base = dqm->dev->kfd2kgd->get_process_page_dir(pdd->vm);
+ pd_base = amdgpu_amdkfd_gpuvm_get_process_page_dir(pdd->vm);
dqm_lock(dqm);
if (WARN_ON_ONCE(!qpd->evicted)) /* already restored, do nothing */
@@ -743,7 +744,7 @@ static int restore_process_queues_cpsch(struct device_queue_manager *dqm,
pdd = qpd_to_pdd(qpd);
/* Retrieve PD base */
- pd_base = dqm->dev->kfd2kgd->get_process_page_dir(pdd->vm);
+ pd_base = amdgpu_amdkfd_gpuvm_get_process_page_dir(pdd->vm);
dqm_lock(dqm);
if (WARN_ON_ONCE(!qpd->evicted)) /* already restored, do nothing */
@@ -793,7 +794,7 @@ static int register_process(struct device_queue_manager *dqm,
pdd = qpd_to_pdd(qpd);
/* Retrieve PD base */
- pd_base = dqm->dev->kfd2kgd->get_process_page_dir(pdd->vm);
+ pd_base = amdgpu_amdkfd_gpuvm_get_process_page_dir(pdd->vm);
dqm_lock(dqm);
list_add(&n->list, &dqm->queues);
@@ -805,7 +806,7 @@ static int register_process(struct device_queue_manager *dqm,
retval = dqm->asic_ops.update_qpd(dqm, qpd);
if (dqm->processes_count++ == 0)
- dqm->dev->kfd2kgd->set_compute_idle(dqm->dev->kgd, false);
+ amdgpu_amdkfd_set_compute_idle(dqm->dev->kgd, false);
dqm_unlock(dqm);
@@ -829,7 +830,7 @@ static int unregister_process(struct device_queue_manager *dqm,
list_del(&cur->list);
kfree(cur);
if (--dqm->processes_count == 0)
- dqm->dev->kfd2kgd->set_compute_idle(
+ amdgpu_amdkfd_set_compute_idle(
dqm->dev->kgd, true);
goto out;
}
@@ -845,15 +846,8 @@ static int
set_pasid_vmid_mapping(struct device_queue_manager *dqm, unsigned int pasid,
unsigned int vmid)
{
- uint32_t pasid_mapping;
-
- pasid_mapping = (pasid == 0) ? 0 :
- (uint32_t)pasid |
- ATC_VMID_PASID_MAPPING_VALID;
-
return dqm->dev->kfd2kgd->set_pasid_vmid_mapping(
- dqm->dev->kgd, pasid_mapping,
- vmid);
+ dqm->dev->kgd, pasid, vmid);
}
static void init_interrupts(struct device_queue_manager *dqm)
@@ -1796,7 +1790,7 @@ static void kfd_process_hw_exception(struct work_struct *work)
{
struct device_queue_manager *dqm = container_of(work,
struct device_queue_manager, hw_exception_work);
- dqm->dev->kfd2kgd->gpu_recover(dqm->dev->kgd);
+ amdgpu_amdkfd_gpu_reset(dqm->dev->kgd);
}
#if defined(CONFIG_DEBUG_FS)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c
index e33019a7a883..6910028010d6 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c
@@ -22,6 +22,7 @@
*/
#include "kfd_mqd_manager.h"
+#include "amdgpu_amdkfd.h"
struct mqd_manager *mqd_manager_init(enum KFD_MQD_TYPE type,
struct kfd_dev *dev)
@@ -58,7 +59,7 @@ void mqd_symmetrically_map_cu_mask(struct mqd_manager *mm,
uint32_t cu_per_sh[4] = {0};
int i, se, cu = 0;
- mm->dev->kfd2kgd->get_cu_info(mm->dev->kgd, &cu_info);
+ amdgpu_amdkfd_get_cu_info(mm->dev->kgd, &cu_info);
if (cu_mask_count > cu_info.cu_active_number)
cu_mask_count = cu_info.cu_active_number;
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c
index f381c1cb27bd..9dbba609450e 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c
@@ -30,6 +30,7 @@
#include "gc/gc_9_0_offset.h"
#include "gc/gc_9_0_sh_mask.h"
#include "sdma0/sdma0_4_0_sh_mask.h"
+#include "amdgpu_amdkfd.h"
static inline struct v9_mqd *get_mqd(void *mqd)
{
@@ -83,7 +84,7 @@ static int init_mqd(struct mqd_manager *mm, void **mqd,
*mqd_mem_obj = kzalloc(sizeof(struct kfd_mem_obj), GFP_KERNEL);
if (!*mqd_mem_obj)
return -ENOMEM;
- retval = kfd->kfd2kgd->init_gtt_mem_allocation(kfd->kgd,
+ retval = amdgpu_amdkfd_alloc_gtt_mem(kfd->kgd,
ALIGN(q->ctl_stack_size, PAGE_SIZE) +
ALIGN(sizeof(struct v9_mqd), PAGE_SIZE),
&((*mqd_mem_obj)->gtt_mem),
@@ -250,7 +251,7 @@ static void uninit_mqd(struct mqd_manager *mm, void *mqd,
struct kfd_dev *kfd = mm->dev;
if (mqd_mem_obj->gtt_mem) {
- kfd->kfd2kgd->free_gtt_mem(kfd->kgd, mqd_mem_obj->gtt_mem);
+ amdgpu_amdkfd_free_gtt_mem(kfd->kgd, mqd_mem_obj->gtt_mem);
kfree(mqd_mem_obj);
} else {
kfd_gtt_sa_free(mm->dev, mqd_mem_obj);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_pasid.c b/drivers/gpu/drm/amd/amdkfd/kfd_pasid.c
index 15fff4420e53..33b08ff00b50 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_pasid.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_pasid.c
@@ -22,6 +22,7 @@
#include <linux/types.h>
#include "kfd_priv.h"
+#include "amdgpu_ids.h"
static unsigned int pasid_bits = 16;
static const struct kfd2kgd_calls *kfd2kgd;
@@ -71,7 +72,7 @@ unsigned int kfd_pasid_alloc(void)
return false;
}
- r = kfd2kgd->alloc_pasid(pasid_bits);
+ r = amdgpu_pasid_alloc(pasid_bits);
return r > 0 ? r : 0;
}
@@ -79,5 +80,5 @@ unsigned int kfd_pasid_alloc(void)
void kfd_pasid_free(unsigned int pasid)
{
if (kfd2kgd)
- kfd2kgd->free_pasid(pasid);
+ amdgpu_pasid_free(pasid);
}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
index 53ff86d45d91..dec8e64f36bd 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
@@ -507,6 +507,7 @@ struct qcm_process_device {
* All the memory management data should be here too
*/
uint64_t gds_context_area;
+ /* Contains page table flags such as AMDGPU_PTE_VALID since gfx9 */
uint64_t page_table_base;
uint32_t sh_mem_config;
uint32_t sh_mem_bases;
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
index 0039e451d9af..80b36e860a0a 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
@@ -31,6 +31,7 @@
#include <linux/compat.h>
#include <linux/mman.h>
#include <linux/file.h>
+#include "amdgpu_amdkfd.h"
struct mm_struct;
@@ -100,8 +101,8 @@ static void kfd_process_free_gpuvm(struct kgd_mem *mem,
{
struct kfd_dev *dev = pdd->dev;
- dev->kfd2kgd->unmap_memory_to_gpu(dev->kgd, mem, pdd->vm);
- dev->kfd2kgd->free_memory_of_gpu(dev->kgd, mem);
+ amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu(dev->kgd, mem, pdd->vm);
+ amdgpu_amdkfd_gpuvm_free_memory_of_gpu(dev->kgd, mem);
}
/* kfd_process_alloc_gpuvm - Allocate GPU VM for the KFD process
@@ -119,16 +120,16 @@ static int kfd_process_alloc_gpuvm(struct kfd_process_device *pdd,
int handle;
int err;
- err = kdev->kfd2kgd->alloc_memory_of_gpu(kdev->kgd, gpu_va, size,
+ err = amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu(kdev->kgd, gpu_va, size,
pdd->vm, &mem, NULL, flags);
if (err)
goto err_alloc_mem;
- err = kdev->kfd2kgd->map_memory_to_gpu(kdev->kgd, mem, pdd->vm);
+ err = amdgpu_amdkfd_gpuvm_map_memory_to_gpu(kdev->kgd, mem, pdd->vm);
if (err)
goto err_map_mem;
- err = kdev->kfd2kgd->sync_memory(kdev->kgd, mem, true);
+ err = amdgpu_amdkfd_gpuvm_sync_memory(kdev->kgd, mem, true);
if (err) {
pr_debug("Sync memory failed, wait interrupted by user signal\n");
goto sync_memory_failed;
@@ -147,7 +148,7 @@ static int kfd_process_alloc_gpuvm(struct kfd_process_device *pdd,
}
if (kptr) {
- err = kdev->kfd2kgd->map_gtt_bo_to_kernel(kdev->kgd,
+ err = amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel(kdev->kgd,
(struct kgd_mem *)mem, kptr, NULL);
if (err) {
pr_debug("Map GTT BO to kernel failed\n");
@@ -165,7 +166,7 @@ sync_memory_failed:
return err;
err_map_mem:
- kdev->kfd2kgd->free_memory_of_gpu(kdev->kgd, mem);
+ amdgpu_amdkfd_gpuvm_free_memory_of_gpu(kdev->kgd, mem);
err_alloc_mem:
*kptr = NULL;
return err;
@@ -296,11 +297,11 @@ static void kfd_process_device_free_bos(struct kfd_process_device *pdd)
per_device_list) {
if (!peer_pdd->vm)
continue;
- peer_pdd->dev->kfd2kgd->unmap_memory_to_gpu(
+ amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu(
peer_pdd->dev->kgd, mem, peer_pdd->vm);
}
- pdd->dev->kfd2kgd->free_memory_of_gpu(pdd->dev->kgd, mem);
+ amdgpu_amdkfd_gpuvm_free_memory_of_gpu(pdd->dev->kgd, mem);
kfd_process_device_remove_obj_handle(pdd, id);
}
}
@@ -323,11 +324,12 @@ static void kfd_process_destroy_pdds(struct kfd_process *p)
pdd->dev->id, p->pasid);
if (pdd->drm_file) {
- pdd->dev->kfd2kgd->release_process_vm(pdd->dev->kgd, pdd->vm);
+ amdgpu_amdkfd_gpuvm_release_process_vm(
+ pdd->dev->kgd, pdd->vm);
fput(pdd->drm_file);
}
else if (pdd->vm)
- pdd->dev->kfd2kgd->destroy_process_vm(
+ amdgpu_amdkfd_gpuvm_destroy_process_vm(
pdd->dev->kgd, pdd->vm);
list_del(&pdd->per_device_list);
@@ -688,12 +690,12 @@ int kfd_process_device_init_vm(struct kfd_process_device *pdd,
dev = pdd->dev;
if (drm_file)
- ret = dev->kfd2kgd->acquire_process_vm(
+ ret = amdgpu_amdkfd_gpuvm_acquire_process_vm(
dev->kgd, drm_file, p->pasid,
&pdd->vm, &p->kgd_process_info, &p->ef);
else
- ret = dev->kfd2kgd->create_process_vm(
- dev->kgd, p->pasid, &pdd->vm, &p->kgd_process_info, &p->ef);
+ ret = amdgpu_amdkfd_gpuvm_create_process_vm(dev->kgd, p->pasid,
+ &pdd->vm, &p->kgd_process_info, &p->ef);
if (ret) {
pr_err("Failed to create process VM object\n");
return ret;
@@ -714,7 +716,7 @@ err_init_cwsr:
err_reserve_ib_mem:
kfd_process_device_free_bos(pdd);
if (!drm_file)
- dev->kfd2kgd->destroy_process_vm(dev->kgd, pdd->vm);
+ amdgpu_amdkfd_gpuvm_destroy_process_vm(dev->kgd, pdd->vm);
pdd->vm = NULL;
return ret;
@@ -972,7 +974,7 @@ static void restore_process_worker(struct work_struct *work)
*/
p->last_restore_timestamp = get_jiffies_64();
- ret = pdd->dev->kfd2kgd->restore_process_bos(p->kgd_process_info,
+ ret = amdgpu_amdkfd_gpuvm_restore_process_bos(p->kgd_process_info,
&p->ef);
if (ret) {
pr_debug("Failed to restore BOs of pasid %d, retry after %d ms\n",
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
index e3843c5929ed..c73b4ff61f99 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
@@ -36,6 +36,7 @@
#include "kfd_topology.h"
#include "kfd_device_queue_manager.h"
#include "kfd_iommu.h"
+#include "amdgpu_amdkfd.h"
/* topology_device_list - Master list of all topology devices */
static struct list_head topology_device_list;
@@ -1052,7 +1053,7 @@ static uint32_t kfd_generate_gpu_id(struct kfd_dev *gpu)
if (!gpu)
return 0;
- gpu->kfd2kgd->get_local_mem_info(gpu->kgd, &local_mem_info);
+ amdgpu_amdkfd_get_local_mem_info(gpu->kgd, &local_mem_info);
local_mem_size = local_mem_info.local_mem_size_private +
local_mem_info.local_mem_size_public;
@@ -1118,8 +1119,7 @@ static void kfd_fill_mem_clk_max_info(struct kfd_topology_device *dev)
* for APUs - If CRAT from ACPI reports more than one bank, then
* all the banks will report the same mem_clk_max information
*/
- dev->gpu->kfd2kgd->get_local_mem_info(dev->gpu->kgd,
- &local_mem_info);
+ amdgpu_amdkfd_get_local_mem_info(dev->gpu->kgd, &local_mem_info);
list_for_each_entry(mem, &dev->mem_props, list)
mem->mem_clk_max = local_mem_info.mem_clk_max;
@@ -1240,7 +1240,7 @@ int kfd_topology_add_device(struct kfd_dev *gpu)
* needed for the topology
*/
- dev->gpu->kfd2kgd->get_cu_info(dev->gpu->kgd, &cu_info);
+ amdgpu_amdkfd_get_cu_info(dev->gpu->kgd, &cu_info);
dev->node_props.simd_arrays_per_engine =
cu_info.num_shader_arrays_per_engine;
@@ -1249,7 +1249,7 @@ int kfd_topology_add_device(struct kfd_dev *gpu)
dev->node_props.location_id = PCI_DEVID(gpu->pdev->bus->number,
gpu->pdev->devfn);
dev->node_props.max_engine_clk_fcompute =
- dev->gpu->kfd2kgd->get_max_engine_clock_in_mhz(dev->gpu->kgd);
+ amdgpu_amdkfd_get_max_engine_clock_in_mhz(dev->gpu->kgd);
dev->node_props.max_engine_clk_ccompute =
cpufreq_quick_get_max(0) / 1000;
dev->node_props.drm_render_minor =
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 b0df6dc9a775..aa43bb253ea2 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -76,6 +76,16 @@
#define FIRMWARE_RAVEN_DMCU "amdgpu/raven_dmcu.bin"
MODULE_FIRMWARE(FIRMWARE_RAVEN_DMCU);
+/**
+ * DOC: overview
+ *
+ * The AMDgpu display manager, **amdgpu_dm** (or even simpler,
+ * **dm**) sits between DRM and DC. It acts as a liason, converting DRM
+ * requests into DC requests, and DC responses into DRM responses.
+ *
+ * The root control structure is &struct amdgpu_display_manager.
+ */
+
/* basic init/fini API */
static int amdgpu_dm_init(struct amdgpu_device *adev);
static void amdgpu_dm_fini(struct amdgpu_device *adev);
@@ -95,7 +105,7 @@ static void
amdgpu_dm_update_connector_after_detect(struct amdgpu_dm_connector *aconnector);
static int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
- struct amdgpu_plane *aplane,
+ struct drm_plane *plane,
unsigned long possible_crtcs);
static int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm,
struct drm_plane *plane,
@@ -379,11 +389,6 @@ static void amdgpu_dm_fbc_init(struct drm_connector *connector)
}
-/*
- * Init display KMS
- *
- * Returns 0 on success
- */
static int amdgpu_dm_init(struct amdgpu_device *adev)
{
struct dc_init_data init_data;
@@ -429,6 +434,9 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
adev->asic_type < CHIP_RAVEN)
init_data.flags.gpu_vm_support = true;
+ if (amdgpu_dc_feature_mask & DC_FBC_MASK)
+ init_data.flags.fbc_support = true;
+
/* Display Core create. */
adev->dm.dc = dc_create(&init_data);
@@ -660,6 +668,26 @@ static void s3_handle_mst(struct drm_device *dev, bool suspend)
drm_modeset_unlock(&dev->mode_config.connection_mutex);
}
+/**
+ * dm_hw_init() - Initialize DC device
+ * @handle: The base driver device containing the amdpgu_dm device.
+ *
+ * Initialize the &struct amdgpu_display_manager device. This involves calling
+ * the initializers of each DM component, then populating the struct with them.
+ *
+ * Although the function implies hardware initialization, both hardware and
+ * software are initialized here. Splitting them out to their relevant init
+ * hooks is a future TODO item.
+ *
+ * Some notable things that are initialized here:
+ *
+ * - Display Core, both software and hardware
+ * - DC modules that we need (freesync and color management)
+ * - DRM software states
+ * - Interrupt sources and handlers
+ * - Vblank support
+ * - Debug FS entries, if enabled
+ */
static int dm_hw_init(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
@@ -670,6 +698,14 @@ static int dm_hw_init(void *handle)
return 0;
}
+/**
+ * dm_hw_fini() - Teardown DC device
+ * @handle: The base driver device containing the amdpgu_dm device.
+ *
+ * Teardown components within &struct amdgpu_display_manager that require
+ * cleanup. This involves cleaning up the DRM device, DC, and any modules that
+ * were loaded. Also flush IRQ workqueues and disable them.
+ */
static int dm_hw_fini(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
@@ -895,6 +931,16 @@ static int dm_resume(void *handle)
return ret;
}
+/**
+ * DOC: DM Lifecycle
+ *
+ * DM (and consequently DC) is registered in the amdgpu base driver as a IP
+ * block. When CONFIG_DRM_AMD_DC is enabled, the DM device IP block is added to
+ * the base driver's device list to be initialized and torn down accordingly.
+ *
+ * The functions to do so are provided as hooks in &struct amd_ip_funcs.
+ */
+
static const struct amd_ip_funcs amdgpu_dm_funcs = {
.name = "dm",
.early_init = dm_early_init,
@@ -962,6 +1008,12 @@ dm_atomic_state_alloc_free(struct drm_atomic_state *state)
kfree(dm_state);
}
+/**
+ * DOC: atomic
+ *
+ * *WIP*
+ */
+
static const struct drm_mode_config_funcs amdgpu_dm_mode_funcs = {
.fb_create = amdgpu_display_user_framebuffer_create,
.output_poll_changed = drm_fb_helper_output_poll_changed,
@@ -1524,15 +1576,23 @@ static int amdgpu_dm_backlight_update_status(struct backlight_device *bd)
{
struct amdgpu_display_manager *dm = bl_get_data(bd);
+ /* backlight_pwm_u16_16 parameter is in unsigned 32 bit, 16 bit integer
+ * and 16 bit fractional, where 1.0 is max backlight value.
+ * bd->props.brightness is 8 bit format and needs to be converted by
+ * scaling via copy lower byte to upper byte of 16 bit value.
+ */
+ uint32_t brightness = bd->props.brightness * 0x101;
+
/*
* PWM interperts 0 as 100% rather than 0% because of HW
- * limitation for level 0.So limiting minimum brightness level
+ * limitation for level 0. So limiting minimum brightness level
* to 1.
*/
if (bd->props.brightness < 1)
- return 1;
+ brightness = 0x101;
+
if (dc_link_set_backlight_level(dm->backlight_link,
- bd->props.brightness, 0, 0))
+ brightness, 0, 0))
return 0;
else
return 1;
@@ -1584,18 +1644,18 @@ static int initialize_plane(struct amdgpu_display_manager *dm,
struct amdgpu_mode_info *mode_info,
int plane_id)
{
- struct amdgpu_plane *plane;
+ struct drm_plane *plane;
unsigned long possible_crtcs;
int ret = 0;
- plane = kzalloc(sizeof(struct amdgpu_plane), GFP_KERNEL);
+ plane = kzalloc(sizeof(struct drm_plane), GFP_KERNEL);
mode_info->planes[plane_id] = plane;
if (!plane) {
DRM_ERROR("KMS: Failed to allocate plane\n");
return -ENOMEM;
}
- plane->base.type = mode_info->plane_type[plane_id];
+ plane->type = mode_info->plane_type[plane_id];
/*
* HACK: IGT tests expect that each plane can only have
@@ -1686,7 +1746,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
}
for (i = 0; i < dm->dc->caps.max_streams; i++)
- if (amdgpu_dm_crtc_init(dm, &mode_info->planes[i]->base, i)) {
+ if (amdgpu_dm_crtc_init(dm, mode_info->planes[i], i)) {
DRM_ERROR("KMS: Failed to initialize crtc\n");
goto fail;
}
@@ -2707,18 +2767,11 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
drm_connector = &aconnector->base;
if (!aconnector->dc_sink) {
- /*
- * Create dc_sink when necessary to MST
- * Don't apply fake_sink to MST
- */
- if (aconnector->mst_port) {
- dm_dp_mst_dc_sink_create(drm_connector);
- return stream;
+ if (!aconnector->mst_port) {
+ sink = create_fake_sink(aconnector);
+ if (!sink)
+ return stream;
}
-
- sink = create_fake_sink(aconnector);
- if (!sink)
- return stream;
} else {
sink = aconnector->dc_sink;
}
@@ -3196,7 +3249,6 @@ amdgpu_dm_connector_helper_funcs = {
*/
.get_modes = get_modes,
.mode_valid = amdgpu_dm_connector_mode_valid,
- .best_encoder = drm_atomic_helper_best_encoder
};
static void dm_crtc_helper_disable(struct drm_crtc *crtc)
@@ -3308,7 +3360,7 @@ void dm_drm_plane_destroy_state(struct drm_plane *plane,
static const struct drm_plane_funcs dm_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
- .destroy = drm_plane_cleanup,
+ .destroy = drm_primary_helper_destroy,
.reset = dm_drm_plane_reset,
.atomic_duplicate_state = dm_drm_plane_duplicate_state,
.atomic_destroy_state = dm_drm_plane_destroy_state,
@@ -3469,49 +3521,49 @@ static const u32 cursor_formats[] = {
};
static int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
- struct amdgpu_plane *aplane,
+ struct drm_plane *plane,
unsigned long possible_crtcs)
{
int res = -EPERM;
- switch (aplane->base.type) {
+ switch (plane->type) {
case DRM_PLANE_TYPE_PRIMARY:
res = drm_universal_plane_init(
dm->adev->ddev,
- &aplane->base,
+ plane,
possible_crtcs,
&dm_plane_funcs,
rgb_formats,
ARRAY_SIZE(rgb_formats),
- NULL, aplane->base.type, NULL);
+ NULL, plane->type, NULL);
break;
case DRM_PLANE_TYPE_OVERLAY:
res = drm_universal_plane_init(
dm->adev->ddev,
- &aplane->base,
+ plane,
possible_crtcs,
&dm_plane_funcs,
yuv_formats,
ARRAY_SIZE(yuv_formats),
- NULL, aplane->base.type, NULL);
+ NULL, plane->type, NULL);
break;
case DRM_PLANE_TYPE_CURSOR:
res = drm_universal_plane_init(
dm->adev->ddev,
- &aplane->base,
+ plane,
possible_crtcs,
&dm_plane_funcs,
cursor_formats,
ARRAY_SIZE(cursor_formats),
- NULL, aplane->base.type, NULL);
+ NULL, plane->type, NULL);
break;
}
- drm_plane_helper_add(&aplane->base, &dm_plane_helper_funcs);
+ drm_plane_helper_add(plane, &dm_plane_helper_funcs);
/* Create (reset) the plane state */
- if (aplane->base.funcs->reset)
- aplane->base.funcs->reset(&aplane->base);
+ if (plane->funcs->reset)
+ plane->funcs->reset(plane);
return res;
@@ -3522,7 +3574,7 @@ static int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm,
uint32_t crtc_index)
{
struct amdgpu_crtc *acrtc = NULL;
- struct amdgpu_plane *cursor_plane;
+ struct drm_plane *cursor_plane;
int res = -ENOMEM;
@@ -3530,7 +3582,7 @@ static int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm,
if (!cursor_plane)
goto fail;
- cursor_plane->base.type = DRM_PLANE_TYPE_CURSOR;
+ cursor_plane->type = DRM_PLANE_TYPE_CURSOR;
res = amdgpu_dm_plane_init(dm, cursor_plane, 0);
acrtc = kzalloc(sizeof(struct amdgpu_crtc), GFP_KERNEL);
@@ -3541,7 +3593,7 @@ static int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm,
dm->ddev,
&acrtc->base,
plane,
- &cursor_plane->base,
+ cursor_plane,
&amdgpu_dm_crtc_funcs, NULL);
if (res)
@@ -3599,14 +3651,17 @@ static int to_drm_connector_type(enum signal_type st)
}
}
+static struct drm_encoder *amdgpu_dm_connector_to_encoder(struct drm_connector *connector)
+{
+ return drm_encoder_find(connector->dev, NULL, connector->encoder_ids[0]);
+}
+
static void amdgpu_dm_get_native_mode(struct drm_connector *connector)
{
- const struct drm_connector_helper_funcs *helper =
- connector->helper_private;
struct drm_encoder *encoder;
struct amdgpu_encoder *amdgpu_encoder;
- encoder = helper->best_encoder(connector);
+ encoder = amdgpu_dm_connector_to_encoder(connector);
if (encoder == NULL)
return;
@@ -3733,14 +3788,12 @@ static void amdgpu_dm_connector_ddc_get_modes(struct drm_connector *connector,
static int amdgpu_dm_connector_get_modes(struct drm_connector *connector)
{
- const struct drm_connector_helper_funcs *helper =
- connector->helper_private;
struct amdgpu_dm_connector *amdgpu_dm_connector =
to_amdgpu_dm_connector(connector);
struct drm_encoder *encoder;
struct edid *edid = amdgpu_dm_connector->edid;
- encoder = helper->best_encoder(connector);
+ encoder = amdgpu_dm_connector_to_encoder(connector);
if (!edid || !drm_edid_is_valid(edid)) {
amdgpu_dm_connector->num_modes =
@@ -3779,12 +3832,12 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
case DRM_MODE_CONNECTOR_HDMIA:
aconnector->base.polled = DRM_CONNECTOR_POLL_HPD;
aconnector->base.ycbcr_420_allowed =
- link->link_enc->features.ycbcr420_supported ? true : false;
+ link->link_enc->features.hdmi_ycbcr420_supported ? true : false;
break;
case DRM_MODE_CONNECTOR_DisplayPort:
aconnector->base.polled = DRM_CONNECTOR_POLL_HPD;
aconnector->base.ycbcr_420_allowed =
- link->link_enc->features.ycbcr420_supported ? true : false;
+ link->link_enc->features.dp_ycbcr420_supported ? true : false;
break;
case DRM_MODE_CONNECTOR_DVID:
aconnector->base.polled = DRM_CONNECTOR_POLL_HPD;
@@ -4542,6 +4595,14 @@ static int amdgpu_dm_atomic_commit(struct drm_device *dev,
/*TODO Handle EINTR, reenable IRQ*/
}
+/**
+ * amdgpu_dm_atomic_commit_tail() - AMDgpu DM's commit tail implementation.
+ * @state: The atomic state to commit
+ *
+ * This will tell DC to commit the constructed DC state from atomic_check,
+ * programming the hardware. Any failures here implies a hardware failure, since
+ * atomic check should have filtered anything non-kosher.
+ */
static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
{
struct drm_device *dev = state->dev;
@@ -5313,6 +5374,12 @@ enum surface_update_type dm_determine_update_type_for_commit(struct dc *dc, stru
struct dc_stream_update stream_update;
enum surface_update_type update_type = UPDATE_TYPE_FAST;
+ if (!updates || !surface) {
+ DRM_ERROR("Plane or surface update failed to allocate");
+ /* Set type to FULL to avoid crashing in DC*/
+ update_type = UPDATE_TYPE_FULL;
+ goto ret;
+ }
for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
new_dm_crtc_state = to_dm_crtc_state(new_crtc_state);
@@ -5388,6 +5455,31 @@ ret:
return update_type;
}
+/**
+ * amdgpu_dm_atomic_check() - Atomic check implementation for AMDgpu DM.
+ * @dev: The DRM device
+ * @state: The atomic state to commit
+ *
+ * Validate that the given atomic state is programmable by DC into hardware.
+ * This involves constructing a &struct dc_state reflecting the new hardware
+ * state we wish to commit, then querying DC to see if it is programmable. It's
+ * important not to modify the existing DC state. Otherwise, atomic_check
+ * may unexpectedly commit hardware changes.
+ *
+ * When validating the DC state, it's important that the right locks are
+ * acquired. For full updates case which removes/adds/updates streams on one
+ * CRTC while flipping on another CRTC, acquiring global lock will guarantee
+ * that any such full update commit will wait for completion of any outstanding
+ * flip using DRMs synchronization events. See
+ * dm_determine_update_type_for_commit()
+ *
+ * Note that DM adds the affected connectors for all CRTCs in state, when that
+ * might not seem necessary. This is because DC stream creation requires the
+ * DC sink, which is tied to the DRM connector state. Cleaning this up should
+ * be possible but non-trivial - a possible TODO item.
+ *
+ * Return: -Error code if validation failed.
+ */
static int amdgpu_dm_atomic_check(struct drm_device *dev,
struct drm_atomic_state *state)
{
@@ -5490,15 +5582,6 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
lock_and_validation_needed = true;
}
- /*
- * For full updates case when
- * removing/adding/updating streams on one CRTC while flipping
- * on another CRTC,
- * acquiring global lock will guarantee that any such full
- * update commit
- * will wait for completion of any outstanding flip using DRMs
- * synchronization events.
- */
update_type = dm_determine_update_type_for_commit(dc, state);
if (overall_update_type < update_type)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index 978b34a5011c..d6960644d714 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -59,49 +59,100 @@ struct common_irq_params {
enum dc_irq_source irq_src;
};
+/**
+ * struct irq_list_head - Linked-list for low context IRQ handlers.
+ *
+ * @head: The list_head within &struct handler_data
+ * @work: A work_struct containing the deferred handler work
+ */
struct irq_list_head {
struct list_head head;
/* In case this interrupt needs post-processing, 'work' will be queued*/
struct work_struct work;
};
+/**
+ * struct dm_compressor_info - Buffer info used by frame buffer compression
+ * @cpu_addr: MMIO cpu addr
+ * @bo_ptr: Pointer to the buffer object
+ * @gpu_addr: MMIO gpu addr
+ */
struct dm_comressor_info {
void *cpu_addr;
struct amdgpu_bo *bo_ptr;
uint64_t gpu_addr;
};
+/**
+ * struct amdgpu_display_manager - Central amdgpu display manager device
+ *
+ * @dc: Display Core control structure
+ * @adev: AMDGPU base driver structure
+ * @ddev: DRM base driver structure
+ * @display_indexes_num: Max number of display streams supported
+ * @irq_handler_list_table_lock: Synchronizes access to IRQ tables
+ * @backlight_dev: Backlight control device
+ * @cached_state: Caches device atomic state for suspend/resume
+ * @compressor: Frame buffer compression buffer. See &struct dm_comressor_info
+ */
struct amdgpu_display_manager {
+
struct dc *dc;
+
+ /**
+ * @cgs_device:
+ *
+ * The Common Graphics Services device. It provides an interface for
+ * accessing registers.
+ */
struct cgs_device *cgs_device;
- struct amdgpu_device *adev; /*AMD base driver*/
- struct drm_device *ddev; /*DRM base driver*/
+ struct amdgpu_device *adev;
+ struct drm_device *ddev;
u16 display_indexes_num;
- /*
- * 'irq_source_handler_table' holds a list of handlers
- * per (DAL) IRQ source.
+ /**
+ * @irq_handler_list_low_tab:
+ *
+ * Low priority IRQ handler table.
*
- * Each IRQ source may need to be handled at different contexts.
- * By 'context' we mean, for example:
- * - The ISR context, which is the direct interrupt handler.
- * - The 'deferred' context - this is the post-processing of the
- * interrupt, but at a lower priority.
+ * It is a n*m table consisting of n IRQ sources, and m handlers per IRQ
+ * source. Low priority IRQ handlers are deferred to a workqueue to be
+ * processed. Hence, they can sleep.
*
* Note that handlers are called in the same order as they were
* registered (FIFO).
*/
struct irq_list_head irq_handler_list_low_tab[DAL_IRQ_SOURCES_NUMBER];
+
+ /**
+ * @irq_handler_list_high_tab:
+ *
+ * High priority IRQ handler table.
+ *
+ * It is a n*m table, same as &irq_handler_list_low_tab. However,
+ * handlers in this table are not deferred and are called immediately.
+ */
struct list_head irq_handler_list_high_tab[DAL_IRQ_SOURCES_NUMBER];
+ /**
+ * @pflip_params:
+ *
+ * Page flip IRQ parameters, passed to registered handlers when
+ * triggered.
+ */
struct common_irq_params
pflip_params[DC_IRQ_SOURCE_PFLIP_LAST - DC_IRQ_SOURCE_PFLIP_FIRST + 1];
+ /**
+ * @vblank_params:
+ *
+ * Vertical blanking IRQ parameters, passed to registered handlers when
+ * triggered.
+ */
struct common_irq_params
vblank_params[DC_IRQ_SOURCE_VBLANK6 - DC_IRQ_SOURCE_VBLANK1 + 1];
- /* this spin lock synchronizes access to 'irq_handler_list_table' */
spinlock_t irq_handler_list_table_lock;
struct backlight_device *backlight_dev;
@@ -110,9 +161,6 @@ struct amdgpu_display_manager {
struct mod_freesync *freesync_module;
- /**
- * Caches device atomic state for suspend/resume
- */
struct drm_atomic_state *cached_state;
struct dm_comressor_info compressor;
@@ -160,8 +208,6 @@ struct amdgpu_dm_connector {
struct mutex hpd_lock;
bool fake_enable;
-
- bool mst_connected;
};
#define to_amdgpu_dm_connector(x) container_of(x, struct amdgpu_dm_connector, base)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index be19e6861189..216e48cec716 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -164,7 +164,7 @@ int amdgpu_dm_set_regamma_lut(struct dm_crtc_state *crtc)
*/
stream->out_transfer_func->type = TF_TYPE_DISTRIBUTED_POINTS;
ret = mod_color_calculate_regamma_params(stream->out_transfer_func,
- gamma, true, adev->asic_type <= CHIP_RAVEN);
+ gamma, true, adev->asic_type <= CHIP_RAVEN, NULL);
dc_gamma_release(&gamma);
if (!ret) {
stream->out_transfer_func->type = old_type;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
index 01fc5717b657..f088ac585978 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
@@ -75,6 +75,11 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name)
return -EINVAL;
}
+ if (!stream_state) {
+ DRM_ERROR("No stream state for CRTC%d\n", crtc->index);
+ return -EINVAL;
+ }
+
/* When enabling CRC, we should also disable dithering. */
if (source == AMDGPU_DM_PIPE_CRC_SOURCE_AUTO) {
if (dc_stream_configure_crc(stream_state->ctx->dc,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
index a212178f2edc..cd10f77cdeb0 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
@@ -32,16 +32,55 @@
#include "amdgpu_dm.h"
#include "amdgpu_dm_irq.h"
+/**
+ * DOC: overview
+ *
+ * DM provides another layer of IRQ management on top of what the base driver
+ * already provides. This is something that could be cleaned up, and is a
+ * future TODO item.
+ *
+ * The base driver provides IRQ source registration with DRM, handler
+ * registration into the base driver's IRQ table, and a handler callback
+ * amdgpu_irq_handler(), with which DRM calls on interrupts. This generic
+ * handler looks up the IRQ table, and calls the respective
+ * &amdgpu_irq_src_funcs.process hookups.
+ *
+ * What DM provides on top are two IRQ tables specifically for top-half and
+ * bottom-half IRQ handling, with the bottom-half implementing workqueues:
+ *
+ * - &amdgpu_display_manager.irq_handler_list_high_tab
+ * - &amdgpu_display_manager.irq_handler_list_low_tab
+ *
+ * They override the base driver's IRQ table, and the effect can be seen
+ * in the hooks that DM provides for &amdgpu_irq_src_funcs.process. They
+ * are all set to the DM generic handler amdgpu_dm_irq_handler(), which looks up
+ * DM's IRQ tables. However, in order for base driver to recognize this hook, DM
+ * still needs to register the IRQ with the base driver. See
+ * dce110_register_irq_handlers() and dcn10_register_irq_handlers().
+ *
+ * To expose DC's hardware interrupt toggle to the base driver, DM implements
+ * &amdgpu_irq_src_funcs.set hooks. Base driver calls it through
+ * amdgpu_irq_update() to enable or disable the interrupt.
+ */
+
/******************************************************************************
* Private declarations.
*****************************************************************************/
+/**
+ * struct amdgpu_dm_irq_handler_data - Data for DM interrupt handlers.
+ *
+ * @list: Linked list entry referencing the next/previous handler
+ * @handler: Handler function
+ * @handler_arg: Argument passed to the handler when triggered
+ * @dm: DM which this handler belongs to
+ * @irq_source: DC interrupt source that this handler is registered for
+ */
struct amdgpu_dm_irq_handler_data {
struct list_head list;
interrupt_handler handler;
void *handler_arg;
- /* DM which this handler belongs to */
struct amdgpu_display_manager *dm;
/* DAL irq source which registered for this interrupt. */
enum dc_irq_source irq_source;
@@ -68,7 +107,7 @@ static void init_handler_common_data(struct amdgpu_dm_irq_handler_data *hcd,
}
/**
- * dm_irq_work_func - Handle an IRQ outside of the interrupt handler proper.
+ * dm_irq_work_func() - Handle an IRQ outside of the interrupt handler proper.
*
* @work: work struct
*/
@@ -99,8 +138,8 @@ static void dm_irq_work_func(struct work_struct *work)
* (The most common use is HPD interrupt) */
}
-/**
- * Remove a handler and return a pointer to hander list from which the
+/*
+ * Remove a handler and return a pointer to handler list from which the
* handler was removed.
*/
static struct list_head *remove_irq_handler(struct amdgpu_device *adev,
@@ -203,6 +242,24 @@ static bool validate_irq_unregistration_params(enum dc_irq_source irq_source,
* Note: caller is responsible for input validation.
*****************************************************************************/
+/**
+ * amdgpu_dm_irq_register_interrupt() - Register a handler within DM.
+ * @adev: The base driver device containing the DM device.
+ * @int_params: Interrupt parameters containing the source, and handler context
+ * @ih: Function pointer to the interrupt handler to register
+ * @handler_args: Arguments passed to the handler when the interrupt occurs
+ *
+ * Register an interrupt handler for the given IRQ source, under the given
+ * context. The context can either be high or low. High context handlers are
+ * executed directly within ISR context, while low context is executed within a
+ * workqueue, thereby allowing operations that sleep.
+ *
+ * Registered handlers are called in a FIFO manner, i.e. the most recently
+ * registered handler will be called first.
+ *
+ * Return: Handler data &struct amdgpu_dm_irq_handler_data containing the IRQ
+ * source, handler function, and args
+ */
void *amdgpu_dm_irq_register_interrupt(struct amdgpu_device *adev,
struct dc_interrupt_params *int_params,
void (*ih)(void *),
@@ -261,6 +318,15 @@ void *amdgpu_dm_irq_register_interrupt(struct amdgpu_device *adev,
return handler_data;
}
+/**
+ * amdgpu_dm_irq_unregister_interrupt() - Remove a handler from the DM IRQ table
+ * @adev: The base driver device containing the DM device
+ * @irq_source: IRQ source to remove the given handler from
+ * @ih: Function pointer to the interrupt handler to unregister
+ *
+ * Go through both low and high context IRQ tables, and find the given handler
+ * for the given irq source. If found, remove it. Otherwise, do nothing.
+ */
void amdgpu_dm_irq_unregister_interrupt(struct amdgpu_device *adev,
enum dc_irq_source irq_source,
void *ih)
@@ -295,6 +361,20 @@ void amdgpu_dm_irq_unregister_interrupt(struct amdgpu_device *adev,
}
}
+/**
+ * amdgpu_dm_irq_init() - Initialize DM IRQ management
+ * @adev: The base driver device containing the DM device
+ *
+ * Initialize DM's high and low context IRQ tables.
+ *
+ * The N by M table contains N IRQ sources, with M
+ * &struct amdgpu_dm_irq_handler_data hooked together in a linked list. The
+ * list_heads are initialized here. When an interrupt n is triggered, all m
+ * handlers are called in sequence, FIFO according to registration order.
+ *
+ * The low context table requires special steps to initialize, since handlers
+ * will be deferred to a workqueue. See &struct irq_list_head.
+ */
int amdgpu_dm_irq_init(struct amdgpu_device *adev)
{
int src;
@@ -317,7 +397,12 @@ int amdgpu_dm_irq_init(struct amdgpu_device *adev)
return 0;
}
-/* DM IRQ and timer resource release */
+/**
+ * amdgpu_dm_irq_fini() - Tear down DM IRQ management
+ * @adev: The base driver device containing the DM device
+ *
+ * Flush all work within the low context IRQ table.
+ */
void amdgpu_dm_irq_fini(struct amdgpu_device *adev)
{
int src;
@@ -414,7 +499,7 @@ int amdgpu_dm_irq_resume_late(struct amdgpu_device *adev)
return 0;
}
-/**
+/*
* amdgpu_dm_irq_schedule_work - schedule all work items registered for the
* "irq_source".
*/
@@ -439,8 +524,9 @@ static void amdgpu_dm_irq_schedule_work(struct amdgpu_device *adev,
}
-/** amdgpu_dm_irq_immediate_work
- * Callback high irq work immediately, don't send to work queue
+/*
+ * amdgpu_dm_irq_immediate_work
+ * Callback high irq work immediately, don't send to work queue
*/
static void amdgpu_dm_irq_immediate_work(struct amdgpu_device *adev,
enum dc_irq_source irq_source)
@@ -467,11 +553,14 @@ static void amdgpu_dm_irq_immediate_work(struct amdgpu_device *adev,
DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags);
}
-/*
- * amdgpu_dm_irq_handler
+/**
+ * amdgpu_dm_irq_handler - Generic DM IRQ handler
+ * @adev: amdgpu base driver device containing the DM device
+ * @source: Unused
+ * @entry: Data about the triggered interrupt
*
- * Generic IRQ handler, calls all registered high irq work immediately, and
- * schedules work for low irq
+ * Calls all registered high irq work immediately, and schedules work for low
+ * irq. The DM IRQ table is used to find the corresponding handlers.
*/
static int amdgpu_dm_irq_handler(struct amdgpu_device *adev,
struct amdgpu_irq_src *source,
@@ -613,7 +702,7 @@ void amdgpu_dm_set_irq_funcs(struct amdgpu_device *adev)
adev->hpd_irq.funcs = &dm_hpd_irq_funcs;
}
-/*
+/**
* amdgpu_dm_hpd_init - hpd setup callback.
*
* @adev: amdgpu_device pointer
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
index 03601d717fed..d02c32a1039c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
@@ -205,40 +205,6 @@ static const struct drm_connector_funcs dm_dp_mst_connector_funcs = {
.atomic_get_property = amdgpu_dm_connector_atomic_get_property
};
-void dm_dp_mst_dc_sink_create(struct drm_connector *connector)
-{
- struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
- struct dc_sink *dc_sink;
- struct dc_sink_init_data init_params = {
- .link = aconnector->dc_link,
- .sink_signal = SIGNAL_TYPE_DISPLAY_PORT_MST };
-
- /* FIXME none of this is safe. we shouldn't touch aconnector here in
- * atomic_check
- */
-
- /*
- * TODO: Need to further figure out why ddc.algo is NULL while MST port exists
- */
- if (!aconnector->port || !aconnector->port->aux.ddc.algo)
- return;
-
- ASSERT(aconnector->edid);
-
- dc_sink = dc_link_add_remote_sink(
- aconnector->dc_link,
- (uint8_t *)aconnector->edid,
- (aconnector->edid->extensions + 1) * EDID_LENGTH,
- &init_params);
-
- dc_sink->priv = aconnector;
- aconnector->dc_sink = dc_sink;
-
- if (aconnector->dc_sink)
- amdgpu_dm_update_freesync_caps(
- connector, aconnector->edid);
-}
-
static int dm_dp_mst_get_modes(struct drm_connector *connector)
{
struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
@@ -319,12 +285,7 @@ dm_dp_create_fake_mst_encoder(struct amdgpu_dm_connector *connector)
struct amdgpu_device *adev = dev->dev_private;
struct amdgpu_encoder *amdgpu_encoder;
struct drm_encoder *encoder;
- const struct drm_connector_helper_funcs *connector_funcs =
- connector->base.helper_private;
- struct drm_encoder *enc_master =
- connector_funcs->best_encoder(&connector->base);
- DRM_DEBUG_KMS("enc master is %p\n", enc_master);
amdgpu_encoder = kzalloc(sizeof(*amdgpu_encoder), GFP_KERNEL);
if (!amdgpu_encoder)
return NULL;
@@ -354,25 +315,6 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
struct amdgpu_device *adev = dev->dev_private;
struct amdgpu_dm_connector *aconnector;
struct drm_connector *connector;
- struct drm_connector_list_iter conn_iter;
-
- drm_connector_list_iter_begin(dev, &conn_iter);
- drm_for_each_connector_iter(connector, &conn_iter) {
- aconnector = to_amdgpu_dm_connector(connector);
- if (aconnector->mst_port == master
- && !aconnector->port) {
- DRM_INFO("DM_MST: reusing connector: %p [id: %d] [master: %p]\n",
- aconnector, connector->base.id, aconnector->mst_port);
-
- aconnector->port = port;
- drm_connector_set_path_property(connector, pathprop);
-
- drm_connector_list_iter_end(&conn_iter);
- aconnector->mst_connected = true;
- return &aconnector->base;
- }
- }
- drm_connector_list_iter_end(&conn_iter);
aconnector = kzalloc(sizeof(*aconnector), GFP_KERNEL);
if (!aconnector)
@@ -421,8 +363,6 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
*/
amdgpu_dm_connector_funcs_reset(connector);
- aconnector->mst_connected = true;
-
DRM_INFO("DM_MST: added connector: %p [id: %d] [master: %p]\n",
aconnector, connector->base.id, aconnector->mst_port);
@@ -434,6 +374,9 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
static void dm_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
struct drm_connector *connector)
{
+ struct amdgpu_dm_connector *master = container_of(mgr, struct amdgpu_dm_connector, mst_mgr);
+ struct drm_device *dev = master->base.dev;
+ struct amdgpu_device *adev = dev->dev_private;
struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
DRM_INFO("DM_MST: Disabling connector: %p [id: %d] [master: %p]\n",
@@ -447,7 +390,10 @@ static void dm_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
aconnector->dc_sink = NULL;
}
- aconnector->mst_connected = false;
+ drm_connector_unregister(connector);
+ if (adev->mode_info.rfbdev)
+ drm_fb_helper_remove_one_connector(&adev->mode_info.rfbdev->helper, connector);
+ drm_connector_put(connector);
}
static void dm_dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr)
@@ -458,18 +404,10 @@ static void dm_dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr)
drm_kms_helper_hotplug_event(dev);
}
-static void dm_dp_mst_link_status_reset(struct drm_connector *connector)
-{
- mutex_lock(&connector->dev->mode_config.mutex);
- drm_connector_set_link_status_property(connector, DRM_MODE_LINK_STATUS_BAD);
- mutex_unlock(&connector->dev->mode_config.mutex);
-}
-
static void dm_dp_mst_register_connector(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
struct amdgpu_device *adev = dev->dev_private;
- struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
if (adev->mode_info.rfbdev)
drm_fb_helper_add_one_connector(&adev->mode_info.rfbdev->helper, connector);
@@ -477,9 +415,6 @@ static void dm_dp_mst_register_connector(struct drm_connector *connector)
DRM_ERROR("adev->mode_info.rfbdev is NULL\n");
drm_connector_register(connector);
-
- if (aconnector->mst_connected)
- dm_dp_mst_link_status_reset(connector);
}
static const struct drm_dp_mst_topology_cbs dm_mst_cbs = {
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
index 8cf51da26657..2da851b40042 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
@@ -31,6 +31,5 @@ struct amdgpu_dm_connector;
void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm,
struct amdgpu_dm_connector *aconnector);
-void dm_dp_mst_dc_sink_create(struct drm_connector *connector);
#endif
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c
index 12001a006b2d..9d2d6986b983 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c
@@ -485,11 +485,11 @@ void pp_rv_set_display_requirement(struct pp_smu *pp,
return;
clock.clock_type = amd_pp_dcf_clock;
- clock.clock_freq_in_khz = req->hard_min_dcefclk_khz;
+ clock.clock_freq_in_khz = req->hard_min_dcefclk_mhz * 1000;
pp_funcs->display_clock_voltage_request(pp_handle, &clock);
clock.clock_type = amd_pp_f_clock;
- clock.clock_freq_in_khz = req->hard_min_fclk_khz;
+ clock.clock_freq_in_khz = req->hard_min_fclk_mhz * 1000;
pp_funcs->display_clock_voltage_request(pp_handle, &clock);
}
@@ -518,13 +518,13 @@ void pp_rv_set_wm_ranges(struct pp_smu *pp,
wm_dce_clocks[i].wm_set_id =
ranges->reader_wm_sets[i].wm_inst;
wm_dce_clocks[i].wm_max_dcfclk_clk_in_khz =
- ranges->reader_wm_sets[i].max_drain_clk_khz;
+ ranges->reader_wm_sets[i].max_drain_clk_mhz * 1000;
wm_dce_clocks[i].wm_min_dcfclk_clk_in_khz =
- ranges->reader_wm_sets[i].min_drain_clk_khz;
+ ranges->reader_wm_sets[i].min_drain_clk_mhz * 1000;
wm_dce_clocks[i].wm_max_mem_clk_in_khz =
- ranges->reader_wm_sets[i].max_fill_clk_khz;
+ ranges->reader_wm_sets[i].max_fill_clk_mhz * 1000;
wm_dce_clocks[i].wm_min_mem_clk_in_khz =
- ranges->reader_wm_sets[i].min_fill_clk_khz;
+ ranges->reader_wm_sets[i].min_fill_clk_mhz * 1000;
}
for (i = 0; i < wm_with_clock_ranges.num_wm_mcif_sets; i++) {
@@ -534,13 +534,13 @@ void pp_rv_set_wm_ranges(struct pp_smu *pp,
wm_soc_clocks[i].wm_set_id =
ranges->writer_wm_sets[i].wm_inst;
wm_soc_clocks[i].wm_max_socclk_clk_in_khz =
- ranges->writer_wm_sets[i].max_fill_clk_khz;
+ ranges->writer_wm_sets[i].max_fill_clk_mhz * 1000;
wm_soc_clocks[i].wm_min_socclk_clk_in_khz =
- ranges->writer_wm_sets[i].min_fill_clk_khz;
+ ranges->writer_wm_sets[i].min_fill_clk_mhz * 1000;
wm_soc_clocks[i].wm_max_mem_clk_in_khz =
- ranges->writer_wm_sets[i].max_drain_clk_khz;
+ ranges->writer_wm_sets[i].max_drain_clk_mhz * 1000;
wm_soc_clocks[i].wm_min_mem_clk_in_khz =
- ranges->writer_wm_sets[i].min_drain_clk_khz;
+ ranges->writer_wm_sets[i].min_drain_clk_mhz * 1000;
}
pp_funcs->set_watermarks_for_clocks_ranges(pp_handle, &wm_with_clock_ranges);
diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c
index 0e1dc1b1a48d..c2ab026aee91 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c
+++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c
@@ -2030,7 +2030,7 @@ static uint32_t get_src_obj_list(struct bios_parser *bp, ATOM_OBJECT *object,
static struct device_id device_type_from_device_id(uint16_t device_id)
{
- struct device_id result_device_id;
+ struct device_id result_device_id = {0};
switch (device_id) {
case ATOM_DEVICE_LCD1_SUPPORT:
diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c
index ff764da21b6f..751bb614fc0e 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c
+++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c
@@ -1884,6 +1884,8 @@ static const struct dc_vbios_funcs vbios_funcs = {
.is_accelerated_mode = bios_parser_is_accelerated_mode,
+ .is_active_display = bios_is_active_display,
+
.set_scratch_critical_state = bios_parser_set_scratch_critical_state,
diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c
index d4589470985c..fdda8aa8e303 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c
+++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c
@@ -88,3 +88,96 @@ uint32_t bios_get_vga_enabled_displays(
return active_disp;
}
+bool bios_is_active_display(
+ struct dc_bios *bios,
+ enum signal_type signal,
+ const struct connector_device_tag_info *device_tag)
+{
+ uint32_t active = 0;
+ uint32_t connected = 0;
+ uint32_t bios_scratch_0 = 0;
+ uint32_t bios_scratch_3 = 0;
+
+ switch (signal) {
+ case SIGNAL_TYPE_DVI_SINGLE_LINK:
+ case SIGNAL_TYPE_DVI_DUAL_LINK:
+ case SIGNAL_TYPE_HDMI_TYPE_A:
+ case SIGNAL_TYPE_DISPLAY_PORT:
+ case SIGNAL_TYPE_DISPLAY_PORT_MST:
+ {
+ if (device_tag->dev_id.device_type == DEVICE_TYPE_DFP) {
+ switch (device_tag->dev_id.enum_id) {
+ case 1:
+ {
+ active = ATOM_S3_DFP1_ACTIVE;
+ connected = 0x0008; //ATOM_DISPLAY_DFP1_CONNECT
+ }
+ break;
+
+ case 2:
+ {
+ active = ATOM_S3_DFP2_ACTIVE;
+ connected = 0x0080; //ATOM_DISPLAY_DFP2_CONNECT
+ }
+ break;
+
+ case 3:
+ {
+ active = ATOM_S3_DFP3_ACTIVE;
+ connected = 0x0200; //ATOM_DISPLAY_DFP3_CONNECT
+ }
+ break;
+
+ case 4:
+ {
+ active = ATOM_S3_DFP4_ACTIVE;
+ connected = 0x0400; //ATOM_DISPLAY_DFP4_CONNECT
+ }
+ break;
+
+ case 5:
+ {
+ active = ATOM_S3_DFP5_ACTIVE;
+ connected = 0x0800; //ATOM_DISPLAY_DFP5_CONNECT
+ }
+ break;
+
+ case 6:
+ {
+ active = ATOM_S3_DFP6_ACTIVE;
+ connected = 0x0040; //ATOM_DISPLAY_DFP6_CONNECT
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ break;
+
+ case SIGNAL_TYPE_LVDS:
+ case SIGNAL_TYPE_EDP:
+ {
+ active = ATOM_S3_LCD1_ACTIVE;
+ connected = 0x0002; //ATOM_DISPLAY_LCD1_CONNECT
+ }
+ break;
+
+ default:
+ break;
+ }
+
+
+ if (bios->regs->BIOS_SCRATCH_0) /*follow up with other asic, todo*/
+ bios_scratch_0 = REG_READ(BIOS_SCRATCH_0);
+ if (bios->regs->BIOS_SCRATCH_3) /*follow up with other asic, todo*/
+ bios_scratch_3 = REG_READ(BIOS_SCRATCH_3);
+
+ bios_scratch_3 &= ATOM_S3_DEVICE_ACTIVE_MASK;
+ if ((active & bios_scratch_3) && (connected & bios_scratch_0))
+ return true;
+
+ return false;
+}
+
diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h
index 75a29e68fb27..f33cac2147e3 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h
+++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h
@@ -35,6 +35,10 @@ bool bios_is_accelerated_mode(struct dc_bios *bios);
void bios_set_scratch_acc_mode_change(struct dc_bios *bios);
void bios_set_scratch_critical_state(struct dc_bios *bios, bool state);
uint32_t bios_get_vga_enabled_displays(struct dc_bios *bios);
+bool bios_is_active_display(
+ struct dc_bios *bios,
+ enum signal_type signal,
+ const struct connector_device_tag_info *device_tag);
#define GET_IMAGE(type, offset) ((type *) bios_get_image(&bp->base, offset, sizeof(type)))
diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c
index 3208188b7ed4..43e4a2be0fa6 100644
--- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c
+++ b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c
@@ -1423,27 +1423,27 @@ void dcn_bw_notify_pplib_of_wm_ranges(struct dc *dc)
ranges.num_reader_wm_sets = WM_SET_COUNT;
ranges.num_writer_wm_sets = WM_SET_COUNT;
ranges.reader_wm_sets[0].wm_inst = WM_A;
- ranges.reader_wm_sets[0].min_drain_clk_khz = min_dcfclk_khz;
- ranges.reader_wm_sets[0].max_drain_clk_khz = overdrive;
- ranges.reader_wm_sets[0].min_fill_clk_khz = min_fclk_khz;
- ranges.reader_wm_sets[0].max_fill_clk_khz = overdrive;
+ ranges.reader_wm_sets[0].min_drain_clk_mhz = min_dcfclk_khz / 1000;
+ ranges.reader_wm_sets[0].max_drain_clk_mhz = overdrive / 1000;
+ ranges.reader_wm_sets[0].min_fill_clk_mhz = min_fclk_khz / 1000;
+ ranges.reader_wm_sets[0].max_fill_clk_mhz = overdrive / 1000;
ranges.writer_wm_sets[0].wm_inst = WM_A;
- ranges.writer_wm_sets[0].min_fill_clk_khz = socclk_khz;
- ranges.writer_wm_sets[0].max_fill_clk_khz = overdrive;
- ranges.writer_wm_sets[0].min_drain_clk_khz = min_fclk_khz;
- ranges.writer_wm_sets[0].max_drain_clk_khz = overdrive;
+ ranges.writer_wm_sets[0].min_fill_clk_mhz = socclk_khz / 1000;
+ ranges.writer_wm_sets[0].max_fill_clk_mhz = overdrive / 1000;
+ ranges.writer_wm_sets[0].min_drain_clk_mhz = min_fclk_khz / 1000;
+ ranges.writer_wm_sets[0].max_drain_clk_mhz = overdrive / 1000;
if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE) {
ranges.reader_wm_sets[0].wm_inst = WM_A;
- ranges.reader_wm_sets[0].min_drain_clk_khz = 300000;
- ranges.reader_wm_sets[0].max_drain_clk_khz = 5000000;
- ranges.reader_wm_sets[0].min_fill_clk_khz = 800000;
- ranges.reader_wm_sets[0].max_fill_clk_khz = 5000000;
+ ranges.reader_wm_sets[0].min_drain_clk_mhz = 300;
+ ranges.reader_wm_sets[0].max_drain_clk_mhz = 5000;
+ ranges.reader_wm_sets[0].min_fill_clk_mhz = 800;
+ ranges.reader_wm_sets[0].max_fill_clk_mhz = 5000;
ranges.writer_wm_sets[0].wm_inst = WM_A;
- ranges.writer_wm_sets[0].min_fill_clk_khz = 200000;
- ranges.writer_wm_sets[0].max_fill_clk_khz = 5000000;
- ranges.writer_wm_sets[0].min_drain_clk_khz = 800000;
- ranges.writer_wm_sets[0].max_drain_clk_khz = 5000000;
+ ranges.writer_wm_sets[0].min_fill_clk_mhz = 200;
+ ranges.writer_wm_sets[0].max_fill_clk_mhz = 5000;
+ ranges.writer_wm_sets[0].min_drain_clk_mhz = 800;
+ ranges.writer_wm_sets[0].max_drain_clk_mhz = 5000;
}
ranges.reader_wm_sets[1] = ranges.writer_wm_sets[0];
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index 7c491c91465f..3279e26c3440 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -391,9 +391,11 @@ bool dc_stream_program_csc_matrix(struct dc *dc, struct dc_stream_state *stream)
== stream) {
pipes = &dc->current_state->res_ctx.pipe_ctx[i];
- dc->hwss.program_csc_matrix(pipes,
- stream->output_color_space,
- stream->csc_color_matrix.matrix);
+ dc->hwss.program_output_csc(dc,
+ pipes,
+ stream->output_color_space,
+ stream->csc_color_matrix.matrix,
+ pipes->plane_res.hubp->opp_id);
ret = true;
}
}
@@ -941,7 +943,7 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
if (!dcb->funcs->is_accelerated_mode(dcb))
dc->hwss.enable_accelerated_mode(dc, context);
- dc->hwss.set_bandwidth(dc, context, false);
+ dc->hwss.prepare_bandwidth(dc, context);
/* re-program planes for existing stream, in case we need to
* free up plane resource for later use
@@ -957,8 +959,6 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
}
/* Program hardware */
- dc->hwss.ready_shared_resources(dc, context);
-
for (i = 0; i < dc->res_pool->pipe_count; i++) {
pipe = &context->res_ctx.pipe_ctx[i];
dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe);
@@ -1012,7 +1012,7 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
dc_enable_stereo(dc, context, dc_streams, context->stream_count);
/* pplib is notified if disp_num changed */
- dc->hwss.set_bandwidth(dc, context, true);
+ dc->hwss.optimize_bandwidth(dc, context);
dc_release_state(dc->current_state);
@@ -1020,8 +1020,6 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
dc_retain_state(dc->current_state);
- dc->hwss.optimize_shared_resources(dc);
-
return result;
}
@@ -1063,7 +1061,7 @@ bool dc_post_update_surfaces_to_stream(struct dc *dc)
dc->optimized_required = false;
- dc->hwss.set_bandwidth(dc, context, true);
+ dc->hwss.optimize_bandwidth(dc, context);
return true;
}
@@ -1369,35 +1367,6 @@ static struct dc_stream_status *stream_get_status(
static const enum surface_update_type update_surface_trace_level = UPDATE_TYPE_FULL;
-static void notify_display_count_to_smu(
- struct dc *dc,
- struct dc_state *context)
-{
- int i, display_count;
- struct pp_smu_funcs_rv *pp_smu = dc->res_pool->pp_smu;
-
- /*
- * if function pointer not set up, this message is
- * sent as part of pplib_apply_display_requirements.
- * So just return.
- */
- if (!pp_smu || !pp_smu->set_display_count)
- return;
-
- display_count = 0;
- for (i = 0; i < context->stream_count; i++) {
- const struct dc_stream_state *stream = context->streams[i];
-
- /* only notify active stream */
- if (stream->dpms_off)
- continue;
-
- display_count++;
- }
-
- pp_smu->set_display_count(&pp_smu->pp_smu, display_count);
-}
-
static void commit_planes_do_stream_update(struct dc *dc,
struct dc_stream_state *stream,
struct dc_stream_update *stream_update,
@@ -1422,7 +1391,6 @@ static void commit_planes_do_stream_update(struct dc *dc,
stream_update->adjust->v_total_max);
if (stream_update->periodic_fn_vsync_delta &&
- pipe_ctx->stream_res.tg &&
pipe_ctx->stream_res.tg->funcs->program_vline_interrupt)
pipe_ctx->stream_res.tg->funcs->program_vline_interrupt(
pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing,
@@ -1448,19 +1416,13 @@ static void commit_planes_do_stream_update(struct dc *dc,
if (stream_update->dpms_off) {
if (*stream_update->dpms_off) {
core_link_disable_stream(pipe_ctx, KEEP_ACQUIRED_RESOURCE);
- dc->hwss.pplib_apply_display_requirements(
- dc, dc->current_state);
- notify_display_count_to_smu(dc, dc->current_state);
+ dc->hwss.optimize_bandwidth(dc, dc->current_state);
} else {
- dc->hwss.pplib_apply_display_requirements(
- dc, dc->current_state);
- notify_display_count_to_smu(dc, dc->current_state);
+ dc->hwss.prepare_bandwidth(dc, dc->current_state);
core_link_enable_stream(dc->current_state, pipe_ctx);
}
}
-
-
if (stream_update->abm_level && pipe_ctx->stream_res.abm) {
if (pipe_ctx->stream_res.tg->funcs->is_blanked) {
// if otg funcs defined check if blanked before programming
@@ -1487,7 +1449,7 @@ static void commit_planes_for_stream(struct dc *dc,
struct pipe_ctx *top_pipe_to_program = NULL;
if (update_type == UPDATE_TYPE_FULL) {
- dc->hwss.set_bandwidth(dc, context, false);
+ dc->hwss.prepare_bandwidth(dc, context);
context_clock_trace(dc, context);
}
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c
index e1ebdf7b5eaf..73d049506618 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c
@@ -311,7 +311,7 @@ void context_timing_trace(
{
int i;
struct dc *core_dc = dc;
- int h_pos[MAX_PIPES], v_pos[MAX_PIPES];
+ int h_pos[MAX_PIPES] = {0}, v_pos[MAX_PIPES] = {0};
struct crtc_position position;
unsigned int underlay_idx = core_dc->res_pool->underlay_pipe_index;
DC_LOGGER_INIT(dc->ctx->logger);
@@ -322,8 +322,7 @@ void context_timing_trace(
/* get_position() returns CRTC vertical/horizontal counter
* hence not applicable for underlay pipe
*/
- if (pipe_ctx->stream == NULL
- || pipe_ctx->pipe_idx == underlay_idx)
+ if (pipe_ctx->stream == NULL || pipe_ctx->pipe_idx == underlay_idx)
continue;
pipe_ctx->stream_res.tg->funcs->get_position(pipe_ctx->stream_res.tg, &position);
@@ -333,7 +332,7 @@ void context_timing_trace(
for (i = 0; i < core_dc->res_pool->pipe_count; i++) {
struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i];
- if (pipe_ctx->stream == NULL)
+ if (pipe_ctx->stream == NULL || pipe_ctx->pipe_idx == underlay_idx)
continue;
TIMING_TRACE("OTG_%d H_tot:%d V_tot:%d H_pos:%d V_pos:%d\n",
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
index fb04a4ad141f..7ee9c033acbd 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
@@ -1357,28 +1357,13 @@ static enum dc_status enable_link_dp(
struct dc_link *link = stream->sink->link;
struct dc_link_settings link_settings = {0};
enum dp_panel_mode panel_mode;
- enum dc_link_rate max_link_rate = LINK_RATE_HIGH2;
/* get link settings for video mode timing */
decide_link_settings(stream, &link_settings);
- /* raise clock state for HBR3 if required. Confirmed with HW DCE/DPCS
- * logic for HBR3 still needs Nominal (0.8V) on VDDC rail
- */
- if (link->link_enc->features.flags.bits.IS_HBR3_CAPABLE)
- max_link_rate = LINK_RATE_HIGH3;
-
- if (link_settings.link_rate == max_link_rate) {
- struct dc_clocks clocks = state->bw.dcn.clk;
-
- /* dce/dcn compat, do not update dispclk */
- clocks.dispclk_khz = 0;
- /* 27mhz = 27000000hz= 27000khz */
- clocks.phyclk_khz = link_settings.link_rate * 27000;
-
- state->dis_clk->funcs->update_clocks(
- state->dis_clk, &clocks, false);
- }
+ pipe_ctx->stream_res.pix_clk_params.requested_sym_clk =
+ link_settings.link_rate * LINK_RATE_REF_FREQ_IN_KHZ;
+ state->dccg->funcs->update_clocks(state->dccg, state, false);
dp_enable_link_phy(
link,
@@ -1722,7 +1707,7 @@ static void write_i2c_retimer_setting(
i2c_success = i2c_write(pipe_ctx, slave_address,
buffer, sizeof(buffer));
RETIMER_REDRIVER_INFO("retimer write to slave_address = 0x%x,\
- offset = 0x%d, reg_val = 0x%d, i2c_success = %d\n",
+ offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
slave_address, buffer[0], buffer[1], i2c_success?1:0);
if (!i2c_success)
/* Write failure */
@@ -1734,7 +1719,7 @@ static void write_i2c_retimer_setting(
i2c_success = i2c_write(pipe_ctx, slave_address,
buffer, sizeof(buffer));
RETIMER_REDRIVER_INFO("retimer write to slave_address = 0x%x,\
- offset = 0x%d, reg_val = 0x%d, i2c_success = %d\n",
+ offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
slave_address, buffer[0], buffer[1], i2c_success?1:0);
if (!i2c_success)
/* Write failure */
@@ -2156,14 +2141,16 @@ int dc_link_get_backlight_level(const struct dc_link *link)
{
struct abm *abm = link->ctx->dc->res_pool->abm;
- if (abm == NULL || abm->funcs->get_current_backlight_8_bit == NULL)
+ if (abm == NULL || abm->funcs->get_current_backlight == NULL)
return DC_ERROR_UNEXPECTED;
- return (int) abm->funcs->get_current_backlight_8_bit(abm);
+ return (int) abm->funcs->get_current_backlight(abm);
}
-bool dc_link_set_backlight_level(const struct dc_link *link, uint32_t level,
- uint32_t frame_ramp, const struct dc_stream_state *stream)
+bool dc_link_set_backlight_level(const struct dc_link *link,
+ uint32_t backlight_pwm_u16_16,
+ uint32_t frame_ramp,
+ const struct dc_stream_state *stream)
{
struct dc *core_dc = link->ctx->dc;
struct abm *abm = core_dc->res_pool->abm;
@@ -2175,19 +2162,17 @@ bool dc_link_set_backlight_level(const struct dc_link *link, uint32_t level,
if ((dmcu == NULL) ||
(abm == NULL) ||
- (abm->funcs->set_backlight_level == NULL))
+ (abm->funcs->set_backlight_level_pwm == NULL))
return false;
- if (stream) {
- if (stream->bl_pwm_level == EDP_BACKLIGHT_RAMP_DISABLE_LEVEL)
- frame_ramp = 0;
-
- ((struct dc_stream_state *)stream)->bl_pwm_level = level;
- }
+ if (stream)
+ ((struct dc_stream_state *)stream)->bl_pwm_level =
+ backlight_pwm_u16_16;
use_smooth_brightness = dmcu->funcs->is_dmcu_initialized(dmcu);
- DC_LOG_BACKLIGHT("New Backlight level: %d (0x%X)\n", level, level);
+ DC_LOG_BACKLIGHT("New Backlight level: %d (0x%X)\n",
+ backlight_pwm_u16_16, backlight_pwm_u16_16);
if (dc_is_embedded_signal(link->connector_signal)) {
if (stream != NULL) {
@@ -2204,9 +2189,9 @@ bool dc_link_set_backlight_level(const struct dc_link *link, uint32_t level,
1;
}
}
- abm->funcs->set_backlight_level(
+ abm->funcs->set_backlight_level_pwm(
abm,
- level,
+ backlight_pwm_u16_16,
frame_ramp,
controller_id,
use_smooth_brightness);
@@ -2220,7 +2205,7 @@ bool dc_link_set_abm_disable(const struct dc_link *link)
struct dc *core_dc = link->ctx->dc;
struct abm *abm = core_dc->res_pool->abm;
- if ((abm == NULL) || (abm->funcs->set_backlight_level == NULL))
+ if ((abm == NULL) || (abm->funcs->set_backlight_level_pwm == NULL))
return false;
abm->funcs->set_abm_immediate_disable(abm);
@@ -2609,6 +2594,10 @@ void core_link_enable_stream(
core_dc->hwss.unblank_stream(pipe_ctx,
&pipe_ctx->stream->sink->link->cur_link_settings);
+ dc_link_set_backlight_level(pipe_ctx->stream->sink->link,
+ pipe_ctx->stream->bl_pwm_level,
+ 0,
+ pipe_ctx->stream);
}
}
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
index b6fe29b9fb65..fc65b0055167 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
@@ -499,8 +499,13 @@ static void calculate_viewport(struct pipe_ctx *pipe_ctx)
pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state;
bool flip_vert_scan_dir = false, flip_horz_scan_dir = false;
+
/*
- * Need to calculate the scan direction for viewport to properly determine offset
+ * We need take horizontal mirror into account. On an unrotated surface this means
+ * that the viewport offset is actually the offset from the other side of source
+ * image so we have to subtract the right edge of the viewport from the right edge of
+ * the source window. Similar to mirror we need to take into account how offset is
+ * affected for 270/180 rotations
*/
if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_180) {
flip_vert_scan_dir = true;
@@ -510,6 +515,9 @@ static void calculate_viewport(struct pipe_ctx *pipe_ctx)
else if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270)
flip_horz_scan_dir = true;
+ if (pipe_ctx->plane_state->horizontal_mirror)
+ flip_horz_scan_dir = !flip_horz_scan_dir;
+
if (stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE ||
stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM) {
pri_split = false;
@@ -540,45 +548,27 @@ static void calculate_viewport(struct pipe_ctx *pipe_ctx)
plane_state->clip_rect.y + plane_state->clip_rect.height - clip.y ;
/* offset = surf_src.ofs + (clip.ofs - surface->dst_rect.ofs) * scl_ratio
+ * note: surf_src.ofs should be added after rotation/mirror offset direction
+ * adjustment since it is already in viewport space
* num_pixels = clip.num_pix * scl_ratio
*/
- data->viewport.x = surf_src.x + (clip.x - plane_state->dst_rect.x) *
+ data->viewport.x = (clip.x - plane_state->dst_rect.x) *
surf_src.width / plane_state->dst_rect.width;
data->viewport.width = clip.width *
surf_src.width / plane_state->dst_rect.width;
- data->viewport.y = surf_src.y + (clip.y - plane_state->dst_rect.y) *
+ data->viewport.y = (clip.y - plane_state->dst_rect.y) *
surf_src.height / plane_state->dst_rect.height;
data->viewport.height = clip.height *
surf_src.height / plane_state->dst_rect.height;
- /* To transfer the x, y to correct coordinate on mirror image (camera).
- * deg 0 : transfer x,
- * deg 90 : don't need to transfer,
- * deg180 : transfer y,
- * deg270 : transfer x and y.
- * To transfer the x, y to correct coordinate on non-mirror image (video).
- * deg 0 : don't need to transfer,
- * deg 90 : transfer y,
- * deg180 : transfer x and y,
- * deg270 : transfer x.
- */
- if (pipe_ctx->plane_state->horizontal_mirror) {
- if (flip_horz_scan_dir && !flip_vert_scan_dir) {
- data->viewport.y = surf_src.height - data->viewport.y - data->viewport.height;
- data->viewport.x = surf_src.width - data->viewport.x - data->viewport.width;
- } else if (flip_horz_scan_dir && flip_vert_scan_dir)
- data->viewport.y = surf_src.height - data->viewport.y - data->viewport.height;
- else {
- if (!flip_horz_scan_dir && !flip_vert_scan_dir)
- data->viewport.x = surf_src.width - data->viewport.x - data->viewport.width;
- }
- } else {
- if (flip_horz_scan_dir)
- data->viewport.x = surf_src.width - data->viewport.x - data->viewport.width;
- if (flip_vert_scan_dir)
- data->viewport.y = surf_src.height - data->viewport.y - data->viewport.height;
- }
+ if (flip_vert_scan_dir)
+ data->viewport.y = surf_src.height - data->viewport.y - data->viewport.height;
+ if (flip_horz_scan_dir)
+ data->viewport.x = surf_src.width - data->viewport.x - data->viewport.width;
+
+ data->viewport.x += surf_src.x;
+ data->viewport.y += surf_src.y;
/* Round down, compensate in init */
data->viewport_c.x = data->viewport.x / vpc_div;
@@ -773,22 +763,15 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct rect *r
else if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270)
flip_horz_scan_dir = true;
+ if (pipe_ctx->plane_state->horizontal_mirror)
+ flip_horz_scan_dir = !flip_horz_scan_dir;
+
if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 ||
pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270) {
rect_swap_helper(&src);
rect_swap_helper(&data->viewport_c);
rect_swap_helper(&data->viewport);
-
- if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270 &&
- pipe_ctx->plane_state->horizontal_mirror) {
- flip_vert_scan_dir = true;
- }
- if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 &&
- pipe_ctx->plane_state->horizontal_mirror) {
- flip_vert_scan_dir = false;
- }
- } else if (pipe_ctx->plane_state->horizontal_mirror)
- flip_horz_scan_dir = !flip_horz_scan_dir;
+ }
/*
* Init calculated according to formula:
@@ -1115,9 +1098,6 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
pipe_ctx->plane_res.scl_data.format = convert_pixel_format_to_dalsurface(
pipe_ctx->plane_state->format);
- if (pipe_ctx->stream->timing.flags.INTERLACE)
- pipe_ctx->stream->dst.height *= 2;
-
calculate_scaling_ratios(pipe_ctx);
calculate_viewport(pipe_ctx);
@@ -1138,9 +1118,6 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
pipe_ctx->plane_res.scl_data.h_active = timing->h_addressable + timing->h_border_left + timing->h_border_right;
pipe_ctx->plane_res.scl_data.v_active = timing->v_addressable + timing->v_border_top + timing->v_border_bottom;
- if (pipe_ctx->stream->timing.flags.INTERLACE)
- pipe_ctx->plane_res.scl_data.v_active *= 2;
-
/* Taps calculations */
if (pipe_ctx->plane_res.xfm != NULL)
@@ -1185,9 +1162,6 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
plane_state->dst_rect.x,
plane_state->dst_rect.y);
- if (pipe_ctx->stream->timing.flags.INTERLACE)
- pipe_ctx->stream->dst.height /= 2;
-
return res;
}
@@ -2071,7 +2045,7 @@ void dc_resource_state_construct(
const struct dc *dc,
struct dc_state *dst_ctx)
{
- dst_ctx->dis_clk = dc->res_pool->dccg;
+ dst_ctx->dccg = dc->res_pool->clk_mgr;
}
enum dc_status dc_validate_global_state(
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
index 2ac848a106ba..e113439aaa86 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
@@ -106,6 +106,7 @@ static void construct(struct dc_stream_state *stream,
stream->out_transfer_func = dc_create_transfer_func();
stream->out_transfer_func->type = TF_TYPE_BYPASS;
+ stream->out_transfer_func->ctx = stream->ctx;
}
static void destruct(struct dc_stream_state *stream)
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c
index 8fb3aefd195c..c60c9b4c3075 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c
@@ -44,6 +44,7 @@ static void construct(struct dc_context *ctx, struct dc_plane_state *plane_state
plane_state->in_transfer_func = dc_create_transfer_func();
plane_state->in_transfer_func->type = TF_TYPE_BYPASS;
+ plane_state->in_transfer_func->ctx = ctx;
}
static void destruct(struct dc_plane_state *plane_state)
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index 199527171100..d16a20c84792 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -38,7 +38,7 @@
#include "inc/compressor.h"
#include "dml/display_mode_lib.h"
-#define DC_VER "3.1.68"
+#define DC_VER "3.2.04"
#define MAX_SURFACES 3
#define MAX_STREAMS 6
@@ -169,6 +169,7 @@ struct link_training_settings;
struct dc_config {
bool gpu_vm_support;
bool disable_disp_pll_sharing;
+ bool fbc_support;
};
enum visual_confirm {
@@ -249,8 +250,6 @@ struct dc_debug_options {
bool disable_dmcu;
bool disable_psr;
bool force_abm_enable;
- bool disable_hbup_pg;
- bool disable_dpp_pg;
bool disable_stereo_support;
bool vsr_support;
bool performance_trace;
@@ -304,11 +303,6 @@ struct dc {
struct hw_sequencer_funcs hwss;
struct dce_hwseq *hwseq;
- /* temp store of dm_pp_display_configuration
- * to compare to see if display config changed
- */
- struct dm_pp_display_configuration prev_display_config;
-
bool optimized_required;
/* FBC compressor */
diff --git a/drivers/gpu/drm/amd/display/dc/dc_bios_types.h b/drivers/gpu/drm/amd/display/dc/dc_bios_types.h
index 8130b95ccc53..a8b3cedf9431 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_bios_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_bios_types.h
@@ -86,6 +86,10 @@ struct dc_vbios_funcs {
bool (*is_accelerated_mode)(
struct dc_bios *bios);
+ bool (*is_active_display)(
+ struct dc_bios *bios,
+ enum signal_type signal,
+ const struct connector_device_tag_info *device_tag);
void (*set_scratch_critical_state)(
struct dc_bios *bios,
bool state);
@@ -141,6 +145,7 @@ struct dc_vbios_funcs {
};
struct bios_registers {
+ uint32_t BIOS_SCRATCH_0;
uint32_t BIOS_SCRATCH_3;
uint32_t BIOS_SCRATCH_6;
};
diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h
index 3bfdccceb524..8738f27a8708 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_link.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_link.h
@@ -138,9 +138,14 @@ static inline struct dc_link *dc_get_link_at_index(struct dc *dc, uint32_t link_
return dc->links[link_index];
}
-/* Set backlight level of an embedded panel (eDP, LVDS). */
-bool dc_link_set_backlight_level(const struct dc_link *dc_link, uint32_t level,
- uint32_t frame_ramp, const struct dc_stream_state *stream);
+/* Set backlight level of an embedded panel (eDP, LVDS).
+ * backlight_pwm_u16_16 is unsigned 32 bit with 16 bit integer
+ * and 16 bit fractional, where 1.0 is max backlight value.
+ */
+bool dc_link_set_backlight_level(const struct dc_link *dc_link,
+ uint32_t backlight_pwm_u16_16,
+ uint32_t frame_ramp,
+ const struct dc_stream_state *stream);
int dc_link_get_backlight_level(const struct dc_link *dc_link);
diff --git a/drivers/gpu/drm/amd/display/dc/dce/Makefile b/drivers/gpu/drm/amd/display/dc/dce/Makefile
index 8f7f0e8b341f..6d7b64a743ca 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/dce/Makefile
@@ -28,7 +28,7 @@
DCE = dce_audio.o dce_stream_encoder.o dce_link_encoder.o dce_hwseq.o \
dce_mem_input.o dce_clock_source.o dce_scl_filters.o dce_transform.o \
-dce_clocks.o dce_opp.o dce_dmcu.o dce_abm.o dce_ipp.o dce_aux.o \
+dce_clk_mgr.o dce_opp.o dce_dmcu.o dce_abm.o dce_ipp.o dce_aux.o \
dce_i2c.o dce_i2c_hw.o dce_i2c_sw.o
AMD_DAL_DCE = $(addprefix $(AMDDALPATH)/dc/dce/,$(DCE))
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c b/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c
index 29294db1a96b..2a342eae80fd 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c
@@ -54,7 +54,7 @@
#define MCP_DISABLE_ABM_IMMEDIATELY 255
-static unsigned int get_current_backlight_16_bit(struct dce_abm *abm_dce)
+static unsigned int calculate_16_bit_backlight_from_pwm(struct dce_abm *abm_dce)
{
uint64_t current_backlight;
uint32_t round_result;
@@ -103,45 +103,21 @@ static unsigned int get_current_backlight_16_bit(struct dce_abm *abm_dce)
return (uint32_t)(current_backlight);
}
-static void driver_set_backlight_level(struct dce_abm *abm_dce, uint32_t level)
+static void driver_set_backlight_level(struct dce_abm *abm_dce,
+ uint32_t backlight_pwm_u16_16)
{
- uint32_t backlight_24bit;
- uint32_t backlight_17bit;
uint32_t backlight_16bit;
uint32_t masked_pwm_period;
- uint8_t rounding_bit;
uint8_t bit_count;
uint64_t active_duty_cycle;
uint32_t pwm_period_bitcnt;
/*
- * 1. Convert 8-bit value to 17 bit U1.16 format
- * (1 integer, 16 fractional bits)
- */
-
- /* 1.1 multiply 8 bit value by 0x10101 to get a 24 bit value,
- * effectively multiplying value by 256/255
- * eg. for a level of 0xEF, backlight_24bit = 0xEF * 0x10101 = 0xEFEFEF
- */
- backlight_24bit = level * 0x10101;
-
- /* 1.2 The upper 16 bits of the 24 bit value is the fraction, lower 8
- * used for rounding, take most significant bit of fraction for
- * rounding, e.g. for 0xEFEFEF, rounding bit is 1
- */
- rounding_bit = (backlight_24bit >> 7) & 1;
-
- /* 1.3 Add the upper 16 bits of the 24 bit value with the rounding bit
- * resulting in a 17 bit value e.g. 0xEFF0 = (0xEFEFEF >> 8) + 1
- */
- backlight_17bit = (backlight_24bit >> 8) + rounding_bit;
-
- /*
- * 2. Find 16 bit backlight active duty cycle, where 0 <= backlight
+ * 1. Find 16 bit backlight active duty cycle, where 0 <= backlight
* active duty cycle <= backlight period
*/
- /* 2.1 Apply bitmask for backlight period value based on value of BITCNT
+ /* 1.1 Apply bitmask for backlight period value based on value of BITCNT
*/
REG_GET_2(BL_PWM_PERIOD_CNTL,
BL_PWM_PERIOD_BITCNT, &pwm_period_bitcnt,
@@ -155,13 +131,13 @@ static void driver_set_backlight_level(struct dce_abm *abm_dce, uint32_t level)
/* e.g. maskedPwmPeriod = 0x24 when bitCount is 6 */
masked_pwm_period = masked_pwm_period & ((1 << bit_count) - 1);
- /* 2.2 Calculate integer active duty cycle required upper 16 bits
+ /* 1.2 Calculate integer active duty cycle required upper 16 bits
* contain integer component, lower 16 bits contain fractional component
* of active duty cycle e.g. 0x21BDC0 = 0xEFF0 * 0x24
*/
- active_duty_cycle = backlight_17bit * masked_pwm_period;
+ active_duty_cycle = backlight_pwm_u16_16 * masked_pwm_period;
- /* 2.3 Calculate 16 bit active duty cycle from integer and fractional
+ /* 1.3 Calculate 16 bit active duty cycle from integer and fractional
* components shift by bitCount then mask 16 bits and add rounding bit
* from MSB of fraction e.g. 0x86F7 = ((0x21BDC0 >> 6) & 0xFFF) + 0
*/
@@ -170,23 +146,23 @@ static void driver_set_backlight_level(struct dce_abm *abm_dce, uint32_t level)
backlight_16bit += (active_duty_cycle >> (bit_count - 1)) & 0x1;
/*
- * 3. Program register with updated value
+ * 2. Program register with updated value
*/
- /* 3.1 Lock group 2 backlight registers */
+ /* 2.1 Lock group 2 backlight registers */
REG_UPDATE_2(BL_PWM_GRP1_REG_LOCK,
BL_PWM_GRP1_IGNORE_MASTER_LOCK_EN, 1,
BL_PWM_GRP1_REG_LOCK, 1);
- // 3.2 Write new active duty cycle
+ // 2.2 Write new active duty cycle
REG_UPDATE(BL_PWM_CNTL, BL_ACTIVE_INT_FRAC_CNT, backlight_16bit);
- /* 3.3 Unlock group 2 backlight registers */
+ /* 2.3 Unlock group 2 backlight registers */
REG_UPDATE(BL_PWM_GRP1_REG_LOCK,
BL_PWM_GRP1_REG_LOCK, 0);
- /* 5.4.4 Wait for pending bit to be cleared */
+ /* 3 Wait for pending bit to be cleared */
REG_WAIT(BL_PWM_GRP1_REG_LOCK,
BL_PWM_GRP1_REG_UPDATE_PENDING, 0,
1, 10000);
@@ -194,16 +170,21 @@ static void driver_set_backlight_level(struct dce_abm *abm_dce, uint32_t level)
static void dmcu_set_backlight_level(
struct dce_abm *abm_dce,
- uint32_t level,
+ uint32_t backlight_pwm_u16_16,
uint32_t frame_ramp,
uint32_t controller_id)
{
- unsigned int backlight_16_bit = (level * 0x10101) >> 8;
- unsigned int backlight_17_bit = backlight_16_bit +
- (((backlight_16_bit & 0x80) >> 7) & 1);
+ unsigned int backlight_8_bit = 0;
uint32_t rampingBoundary = 0xFFFF;
uint32_t s2;
+ if (backlight_pwm_u16_16 & 0x10000)
+ // Check for max backlight condition
+ backlight_8_bit = 0xFF;
+ else
+ // Take MSB of fractional part since backlight is not max
+ backlight_8_bit = (backlight_pwm_u16_16 >> 8) & 0xFF;
+
/* set ramping boundary */
REG_WRITE(MASTER_COMM_DATA_REG1, rampingBoundary);
@@ -220,7 +201,7 @@ static void dmcu_set_backlight_level(
0, 1, 80000);
/* setDMCUParam_BL */
- REG_UPDATE(BL1_PWM_USER_LEVEL, BL1_PWM_USER_LEVEL, backlight_17_bit);
+ REG_UPDATE(BL1_PWM_USER_LEVEL, BL1_PWM_USER_LEVEL, backlight_pwm_u16_16);
/* write ramp */
if (controller_id == 0)
@@ -237,9 +218,9 @@ static void dmcu_set_backlight_level(
s2 = REG_READ(BIOS_SCRATCH_2);
s2 &= ~ATOM_S2_CURRENT_BL_LEVEL_MASK;
- level &= (ATOM_S2_CURRENT_BL_LEVEL_MASK >>
+ backlight_8_bit &= (ATOM_S2_CURRENT_BL_LEVEL_MASK >>
ATOM_S2_CURRENT_BL_LEVEL_SHIFT);
- s2 |= (level << ATOM_S2_CURRENT_BL_LEVEL_SHIFT);
+ s2 |= (backlight_8_bit << ATOM_S2_CURRENT_BL_LEVEL_SHIFT);
REG_WRITE(BIOS_SCRATCH_2, s2);
}
@@ -247,7 +228,7 @@ static void dmcu_set_backlight_level(
static void dce_abm_init(struct abm *abm)
{
struct dce_abm *abm_dce = TO_DCE_ABM(abm);
- unsigned int backlight = get_current_backlight_16_bit(abm_dce);
+ unsigned int backlight = calculate_16_bit_backlight_from_pwm(abm_dce);
REG_WRITE(DC_ABM1_HG_SAMPLE_RATE, 0x103);
REG_WRITE(DC_ABM1_HG_SAMPLE_RATE, 0x101);
@@ -284,12 +265,26 @@ static void dce_abm_init(struct abm *abm)
ABM1_BL_REG_READ_MISSED_FRAME_CLEAR, 1);
}
-static unsigned int dce_abm_get_current_backlight_8_bit(struct abm *abm)
+static unsigned int dce_abm_get_current_backlight(struct abm *abm)
{
struct dce_abm *abm_dce = TO_DCE_ABM(abm);
unsigned int backlight = REG_READ(BL1_PWM_CURRENT_ABM_LEVEL);
- return (backlight >> 8);
+ /* return backlight in hardware format which is unsigned 17 bits, with
+ * 1 bit integer and 16 bit fractional
+ */
+ return backlight;
+}
+
+static unsigned int dce_abm_get_target_backlight(struct abm *abm)
+{
+ struct dce_abm *abm_dce = TO_DCE_ABM(abm);
+ unsigned int backlight = REG_READ(BL1_PWM_TARGET_ABM_LEVEL);
+
+ /* return backlight in hardware format which is unsigned 17 bits, with
+ * 1 bit integer and 16 bit fractional
+ */
+ return backlight;
}
static bool dce_abm_set_level(struct abm *abm, uint32_t level)
@@ -396,9 +391,9 @@ static bool dce_abm_init_backlight(struct abm *abm)
return true;
}
-static bool dce_abm_set_backlight_level(
+static bool dce_abm_set_backlight_level_pwm(
struct abm *abm,
- unsigned int backlight_level,
+ unsigned int backlight_pwm_u16_16,
unsigned int frame_ramp,
unsigned int controller_id,
bool use_smooth_brightness)
@@ -406,16 +401,16 @@ static bool dce_abm_set_backlight_level(
struct dce_abm *abm_dce = TO_DCE_ABM(abm);
DC_LOG_BACKLIGHT("New Backlight level: %d (0x%X)\n",
- backlight_level, backlight_level);
+ backlight_pwm_u16_16, backlight_pwm_u16_16);
/* If DMCU is in reset state, DMCU is uninitialized */
if (use_smooth_brightness)
dmcu_set_backlight_level(abm_dce,
- backlight_level,
+ backlight_pwm_u16_16,
frame_ramp,
controller_id);
else
- driver_set_backlight_level(abm_dce, backlight_level);
+ driver_set_backlight_level(abm_dce, backlight_pwm_u16_16);
return true;
}
@@ -424,8 +419,9 @@ static const struct abm_funcs dce_funcs = {
.abm_init = dce_abm_init,
.set_abm_level = dce_abm_set_level,
.init_backlight = dce_abm_init_backlight,
- .set_backlight_level = dce_abm_set_backlight_level,
- .get_current_backlight_8_bit = dce_abm_get_current_backlight_8_bit,
+ .set_backlight_level_pwm = dce_abm_set_backlight_level_pwm,
+ .get_current_backlight = dce_abm_get_current_backlight,
+ .get_target_backlight = dce_abm_get_target_backlight,
.set_abm_immediate_disable = dce_abm_immediate_disable
};
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c
new file mode 100644
index 000000000000..9a28a04417d1
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c
@@ -0,0 +1,879 @@
+/*
+ * Copyright 2012-16 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.
+ *
+ * Authors: AMD
+ *
+ */
+
+#include "dce_clk_mgr.h"
+
+#include "reg_helper.h"
+#include "dmcu.h"
+#include "core_types.h"
+#include "dal_asic_id.h"
+
+#define TO_DCE_CLK_MGR(clocks)\
+ container_of(clocks, struct dce_clk_mgr, base)
+
+#define REG(reg) \
+ (clk_mgr_dce->regs->reg)
+
+#undef FN
+#define FN(reg_name, field_name) \
+ clk_mgr_dce->clk_mgr_shift->field_name, clk_mgr_dce->clk_mgr_mask->field_name
+
+#define CTX \
+ clk_mgr_dce->base.ctx
+#define DC_LOGGER \
+ clk_mgr->ctx->logger
+
+/* Max clock values for each state indexed by "enum clocks_state": */
+static const struct state_dependent_clocks dce80_max_clks_by_state[] = {
+/* ClocksStateInvalid - should not be used */
+{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
+/* ClocksStateUltraLow - not expected to be used for DCE 8.0 */
+{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
+/* ClocksStateLow */
+{ .display_clk_khz = 352000, .pixel_clk_khz = 330000},
+/* ClocksStateNominal */
+{ .display_clk_khz = 600000, .pixel_clk_khz = 400000 },
+/* ClocksStatePerformance */
+{ .display_clk_khz = 600000, .pixel_clk_khz = 400000 } };
+
+static const struct state_dependent_clocks dce110_max_clks_by_state[] = {
+/*ClocksStateInvalid - should not be used*/
+{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
+/*ClocksStateUltraLow - currently by HW design team not supposed to be used*/
+{ .display_clk_khz = 352000, .pixel_clk_khz = 330000 },
+/*ClocksStateLow*/
+{ .display_clk_khz = 352000, .pixel_clk_khz = 330000 },
+/*ClocksStateNominal*/
+{ .display_clk_khz = 467000, .pixel_clk_khz = 400000 },
+/*ClocksStatePerformance*/
+{ .display_clk_khz = 643000, .pixel_clk_khz = 400000 } };
+
+static const struct state_dependent_clocks dce112_max_clks_by_state[] = {
+/*ClocksStateInvalid - should not be used*/
+{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
+/*ClocksStateUltraLow - currently by HW design team not supposed to be used*/
+{ .display_clk_khz = 389189, .pixel_clk_khz = 346672 },
+/*ClocksStateLow*/
+{ .display_clk_khz = 459000, .pixel_clk_khz = 400000 },
+/*ClocksStateNominal*/
+{ .display_clk_khz = 667000, .pixel_clk_khz = 600000 },
+/*ClocksStatePerformance*/
+{ .display_clk_khz = 1132000, .pixel_clk_khz = 600000 } };
+
+static const struct state_dependent_clocks dce120_max_clks_by_state[] = {
+/*ClocksStateInvalid - should not be used*/
+{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
+/*ClocksStateUltraLow - currently by HW design team not supposed to be used*/
+{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
+/*ClocksStateLow*/
+{ .display_clk_khz = 460000, .pixel_clk_khz = 400000 },
+/*ClocksStateNominal*/
+{ .display_clk_khz = 670000, .pixel_clk_khz = 600000 },
+/*ClocksStatePerformance*/
+{ .display_clk_khz = 1133000, .pixel_clk_khz = 600000 } };
+
+static int dentist_get_divider_from_did(int did)
+{
+ if (did < DENTIST_BASE_DID_1)
+ did = DENTIST_BASE_DID_1;
+ if (did > DENTIST_MAX_DID)
+ did = DENTIST_MAX_DID;
+
+ if (did < DENTIST_BASE_DID_2) {
+ return DENTIST_DIVIDER_RANGE_1_START + DENTIST_DIVIDER_RANGE_1_STEP
+ * (did - DENTIST_BASE_DID_1);
+ } else if (did < DENTIST_BASE_DID_3) {
+ return DENTIST_DIVIDER_RANGE_2_START + DENTIST_DIVIDER_RANGE_2_STEP
+ * (did - DENTIST_BASE_DID_2);
+ } else if (did < DENTIST_BASE_DID_4) {
+ return DENTIST_DIVIDER_RANGE_3_START + DENTIST_DIVIDER_RANGE_3_STEP
+ * (did - DENTIST_BASE_DID_3);
+ } else {
+ return DENTIST_DIVIDER_RANGE_4_START + DENTIST_DIVIDER_RANGE_4_STEP
+ * (did - DENTIST_BASE_DID_4);
+ }
+}
+
+/* SW will adjust DP REF Clock average value for all purposes
+ * (DP DTO / DP Audio DTO and DP GTC)
+ if clock is spread for all cases:
+ -if SS enabled on DP Ref clock and HW de-spreading enabled with SW
+ calculations for DS_INCR/DS_MODULO (this is planned to be default case)
+ -if SS enabled on DP Ref clock and HW de-spreading enabled with HW
+ calculations (not planned to be used, but average clock should still
+ be valid)
+ -if SS enabled on DP Ref clock and HW de-spreading disabled
+ (should not be case with CIK) then SW should program all rates
+ generated according to average value (case as with previous ASICs)
+ */
+static int clk_mgr_adjust_dp_ref_freq_for_ss(struct dce_clk_mgr *clk_mgr_dce, int dp_ref_clk_khz)
+{
+ if (clk_mgr_dce->ss_on_dprefclk && clk_mgr_dce->dprefclk_ss_divider != 0) {
+ struct fixed31_32 ss_percentage = dc_fixpt_div_int(
+ dc_fixpt_from_fraction(clk_mgr_dce->dprefclk_ss_percentage,
+ clk_mgr_dce->dprefclk_ss_divider), 200);
+ struct fixed31_32 adj_dp_ref_clk_khz;
+
+ ss_percentage = dc_fixpt_sub(dc_fixpt_one, ss_percentage);
+ adj_dp_ref_clk_khz = dc_fixpt_mul_int(ss_percentage, dp_ref_clk_khz);
+ dp_ref_clk_khz = dc_fixpt_floor(adj_dp_ref_clk_khz);
+ }
+ return dp_ref_clk_khz;
+}
+
+static int dce_get_dp_ref_freq_khz(struct clk_mgr *clk_mgr)
+{
+ struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr);
+ int dprefclk_wdivider;
+ int dprefclk_src_sel;
+ int dp_ref_clk_khz = 600000;
+ int target_div;
+
+ /* ASSERT DP Reference Clock source is from DFS*/
+ REG_GET(DPREFCLK_CNTL, DPREFCLK_SRC_SEL, &dprefclk_src_sel);
+ ASSERT(dprefclk_src_sel == 0);
+
+ /* Read the mmDENTIST_DISPCLK_CNTL to get the currently
+ * programmed DID DENTIST_DPREFCLK_WDIVIDER*/
+ REG_GET(DENTIST_DISPCLK_CNTL, DENTIST_DPREFCLK_WDIVIDER, &dprefclk_wdivider);
+
+ /* Convert DENTIST_DPREFCLK_WDIVIDERto actual divider*/
+ target_div = dentist_get_divider_from_did(dprefclk_wdivider);
+
+ /* Calculate the current DFS clock, in kHz.*/
+ dp_ref_clk_khz = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR
+ * clk_mgr_dce->dentist_vco_freq_khz) / target_div;
+
+ return clk_mgr_adjust_dp_ref_freq_for_ss(clk_mgr_dce, dp_ref_clk_khz);
+}
+
+int dce12_get_dp_ref_freq_khz(struct clk_mgr *clk_mgr)
+{
+ struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr);
+
+ return clk_mgr_adjust_dp_ref_freq_for_ss(clk_mgr_dce, clk_mgr_dce->dprefclk_khz);
+}
+
+/* unit: in_khz before mode set, get pixel clock from context. ASIC register
+ * may not be programmed yet
+ */
+static uint32_t get_max_pixel_clock_for_all_paths(struct dc_state *context)
+{
+ uint32_t max_pix_clk = 0;
+ int i;
+
+ for (i = 0; i < MAX_PIPES; i++) {
+ struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
+
+ if (pipe_ctx->stream == NULL)
+ continue;
+
+ /* do not check under lay */
+ if (pipe_ctx->top_pipe)
+ continue;
+
+ if (pipe_ctx->stream_res.pix_clk_params.requested_pix_clk > max_pix_clk)
+ max_pix_clk = pipe_ctx->stream_res.pix_clk_params.requested_pix_clk;
+
+ /* raise clock state for HBR3/2 if required. Confirmed with HW DCE/DPCS
+ * logic for HBR3 still needs Nominal (0.8V) on VDDC rail
+ */
+ if (dc_is_dp_signal(pipe_ctx->stream->signal) &&
+ pipe_ctx->stream_res.pix_clk_params.requested_sym_clk > max_pix_clk)
+ max_pix_clk = pipe_ctx->stream_res.pix_clk_params.requested_sym_clk;
+ }
+
+ return max_pix_clk;
+}
+
+static enum dm_pp_clocks_state dce_get_required_clocks_state(
+ struct clk_mgr *clk_mgr,
+ struct dc_state *context)
+{
+ struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr);
+ int i;
+ enum dm_pp_clocks_state low_req_clk;
+ int max_pix_clk = get_max_pixel_clock_for_all_paths(context);
+
+ /* Iterate from highest supported to lowest valid state, and update
+ * lowest RequiredState with the lowest state that satisfies
+ * all required clocks
+ */
+ for (i = clk_mgr_dce->max_clks_state; i >= DM_PP_CLOCKS_STATE_ULTRA_LOW; i--)
+ if (context->bw.dce.dispclk_khz >
+ clk_mgr_dce->max_clks_by_state[i].display_clk_khz
+ || max_pix_clk >
+ clk_mgr_dce->max_clks_by_state[i].pixel_clk_khz)
+ break;
+
+ low_req_clk = i + 1;
+ if (low_req_clk > clk_mgr_dce->max_clks_state) {
+ /* set max clock state for high phyclock, invalid on exceeding display clock */
+ if (clk_mgr_dce->max_clks_by_state[clk_mgr_dce->max_clks_state].display_clk_khz
+ < context->bw.dce.dispclk_khz)
+ low_req_clk = DM_PP_CLOCKS_STATE_INVALID;
+ else
+ low_req_clk = clk_mgr_dce->max_clks_state;
+ }
+
+ return low_req_clk;
+}
+
+static int dce_set_clock(
+ struct clk_mgr *clk_mgr,
+ int requested_clk_khz)
+{
+ struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr);
+ struct bp_pixel_clock_parameters pxl_clk_params = { 0 };
+ struct dc_bios *bp = clk_mgr->ctx->dc_bios;
+ int actual_clock = requested_clk_khz;
+ struct dmcu *dmcu = clk_mgr_dce->base.ctx->dc->res_pool->dmcu;
+
+ /* Make sure requested clock isn't lower than minimum threshold*/
+ if (requested_clk_khz > 0)
+ requested_clk_khz = max(requested_clk_khz,
+ clk_mgr_dce->dentist_vco_freq_khz / 64);
+
+ /* Prepare to program display clock*/
+ pxl_clk_params.target_pixel_clock = requested_clk_khz;
+ pxl_clk_params.pll_id = CLOCK_SOURCE_ID_DFS;
+
+ if (clk_mgr_dce->dfs_bypass_active)
+ pxl_clk_params.flags.SET_DISPCLK_DFS_BYPASS = true;
+
+ bp->funcs->program_display_engine_pll(bp, &pxl_clk_params);
+
+ if (clk_mgr_dce->dfs_bypass_active) {
+ /* Cache the fixed display clock*/
+ clk_mgr_dce->dfs_bypass_disp_clk =
+ pxl_clk_params.dfs_bypass_display_clock;
+ actual_clock = pxl_clk_params.dfs_bypass_display_clock;
+ }
+
+ /* from power down, we need mark the clock state as ClocksStateNominal
+ * from HWReset, so when resume we will call pplib voltage regulator.*/
+ if (requested_clk_khz == 0)
+ clk_mgr_dce->cur_min_clks_state = DM_PP_CLOCKS_STATE_NOMINAL;
+
+ dmcu->funcs->set_psr_wait_loop(dmcu, actual_clock / 1000 / 7);
+
+ return actual_clock;
+}
+
+int dce112_set_clock(struct clk_mgr *clk_mgr, int requested_clk_khz)
+{
+ struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr);
+ struct bp_set_dce_clock_parameters dce_clk_params;
+ struct dc_bios *bp = clk_mgr->ctx->dc_bios;
+ struct dc *core_dc = clk_mgr->ctx->dc;
+ struct dmcu *dmcu = core_dc->res_pool->dmcu;
+ int actual_clock = requested_clk_khz;
+ /* Prepare to program display clock*/
+ memset(&dce_clk_params, 0, sizeof(dce_clk_params));
+
+ /* Make sure requested clock isn't lower than minimum threshold*/
+ if (requested_clk_khz > 0)
+ requested_clk_khz = max(requested_clk_khz,
+ clk_mgr_dce->dentist_vco_freq_khz / 62);
+
+ dce_clk_params.target_clock_frequency = requested_clk_khz;
+ dce_clk_params.pll_id = CLOCK_SOURCE_ID_DFS;
+ dce_clk_params.clock_type = DCECLOCK_TYPE_DISPLAY_CLOCK;
+
+ bp->funcs->set_dce_clock(bp, &dce_clk_params);
+ actual_clock = dce_clk_params.target_clock_frequency;
+
+ /* from power down, we need mark the clock state as ClocksStateNominal
+ * from HWReset, so when resume we will call pplib voltage regulator.*/
+ if (requested_clk_khz == 0)
+ clk_mgr_dce->cur_min_clks_state = DM_PP_CLOCKS_STATE_NOMINAL;
+
+ /*Program DP ref Clock*/
+ /*VBIOS will determine DPREFCLK frequency, so we don't set it*/
+ dce_clk_params.target_clock_frequency = 0;
+ dce_clk_params.clock_type = DCECLOCK_TYPE_DPREFCLK;
+ if (!ASICREV_IS_VEGA20_P(clk_mgr->ctx->asic_id.hw_internal_rev))
+ dce_clk_params.flags.USE_GENLOCK_AS_SOURCE_FOR_DPREFCLK =
+ (dce_clk_params.pll_id ==
+ CLOCK_SOURCE_COMBO_DISPLAY_PLL0);
+ else
+ dce_clk_params.flags.USE_GENLOCK_AS_SOURCE_FOR_DPREFCLK = false;
+
+ bp->funcs->set_dce_clock(bp, &dce_clk_params);
+
+ if (!IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) {
+ if (clk_mgr_dce->dfs_bypass_disp_clk != actual_clock)
+ dmcu->funcs->set_psr_wait_loop(dmcu,
+ actual_clock / 1000 / 7);
+ }
+
+ clk_mgr_dce->dfs_bypass_disp_clk = actual_clock;
+ return actual_clock;
+}
+
+static void dce_clock_read_integrated_info(struct dce_clk_mgr *clk_mgr_dce)
+{
+ struct dc_debug_options *debug = &clk_mgr_dce->base.ctx->dc->debug;
+ struct dc_bios *bp = clk_mgr_dce->base.ctx->dc_bios;
+ struct integrated_info info = { { { 0 } } };
+ struct dc_firmware_info fw_info = { { 0 } };
+ int i;
+
+ if (bp->integrated_info)
+ info = *bp->integrated_info;
+
+ clk_mgr_dce->dentist_vco_freq_khz = info.dentist_vco_freq;
+ if (clk_mgr_dce->dentist_vco_freq_khz == 0) {
+ bp->funcs->get_firmware_info(bp, &fw_info);
+ clk_mgr_dce->dentist_vco_freq_khz =
+ fw_info.smu_gpu_pll_output_freq;
+ if (clk_mgr_dce->dentist_vco_freq_khz == 0)
+ clk_mgr_dce->dentist_vco_freq_khz = 3600000;
+ }
+
+ /*update the maximum display clock for each power state*/
+ for (i = 0; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
+ enum dm_pp_clocks_state clk_state = DM_PP_CLOCKS_STATE_INVALID;
+
+ switch (i) {
+ case 0:
+ clk_state = DM_PP_CLOCKS_STATE_ULTRA_LOW;
+ break;
+
+ case 1:
+ clk_state = DM_PP_CLOCKS_STATE_LOW;
+ break;
+
+ case 2:
+ clk_state = DM_PP_CLOCKS_STATE_NOMINAL;
+ break;
+
+ case 3:
+ clk_state = DM_PP_CLOCKS_STATE_PERFORMANCE;
+ break;
+
+ default:
+ clk_state = DM_PP_CLOCKS_STATE_INVALID;
+ break;
+ }
+
+ /*Do not allow bad VBIOS/SBIOS to override with invalid values,
+ * check for > 100MHz*/
+ if (info.disp_clk_voltage[i].max_supported_clk >= 100000)
+ clk_mgr_dce->max_clks_by_state[clk_state].display_clk_khz =
+ info.disp_clk_voltage[i].max_supported_clk;
+ }
+
+ if (!debug->disable_dfs_bypass && bp->integrated_info)
+ if (bp->integrated_info->gpu_cap_info & DFS_BYPASS_ENABLE)
+ clk_mgr_dce->dfs_bypass_enabled = true;
+}
+
+void dce_clock_read_ss_info(struct dce_clk_mgr *clk_mgr_dce)
+{
+ struct dc_bios *bp = clk_mgr_dce->base.ctx->dc_bios;
+ int ss_info_num = bp->funcs->get_ss_entry_number(
+ bp, AS_SIGNAL_TYPE_GPU_PLL);
+
+ if (ss_info_num) {
+ struct spread_spectrum_info info = { { 0 } };
+ enum bp_result result = bp->funcs->get_spread_spectrum_info(
+ bp, AS_SIGNAL_TYPE_GPU_PLL, 0, &info);
+
+ /* Based on VBIOS, VBIOS will keep entry for GPU PLL SS
+ * even if SS not enabled and in that case
+ * SSInfo.spreadSpectrumPercentage !=0 would be sign
+ * that SS is enabled
+ */
+ if (result == BP_RESULT_OK &&
+ info.spread_spectrum_percentage != 0) {
+ clk_mgr_dce->ss_on_dprefclk = true;
+ clk_mgr_dce->dprefclk_ss_divider = info.spread_percentage_divider;
+
+ if (info.type.CENTER_MODE == 0) {
+ /* TODO: Currently for DP Reference clock we
+ * need only SS percentage for
+ * downspread */
+ clk_mgr_dce->dprefclk_ss_percentage =
+ info.spread_spectrum_percentage;
+ }
+
+ return;
+ }
+
+ result = bp->funcs->get_spread_spectrum_info(
+ bp, AS_SIGNAL_TYPE_DISPLAY_PORT, 0, &info);
+
+ /* Based on VBIOS, VBIOS will keep entry for DPREFCLK SS
+ * even if SS not enabled and in that case
+ * SSInfo.spreadSpectrumPercentage !=0 would be sign
+ * that SS is enabled
+ */
+ if (result == BP_RESULT_OK &&
+ info.spread_spectrum_percentage != 0) {
+ clk_mgr_dce->ss_on_dprefclk = true;
+ clk_mgr_dce->dprefclk_ss_divider = info.spread_percentage_divider;
+
+ if (info.type.CENTER_MODE == 0) {
+ /* Currently for DP Reference clock we
+ * need only SS percentage for
+ * downspread */
+ clk_mgr_dce->dprefclk_ss_percentage =
+ info.spread_spectrum_percentage;
+ }
+ }
+ }
+}
+
+void dce110_fill_display_configs(
+ const struct dc_state *context,
+ struct dm_pp_display_configuration *pp_display_cfg)
+{
+ int j;
+ int num_cfgs = 0;
+
+ for (j = 0; j < context->stream_count; j++) {
+ int k;
+
+ const struct dc_stream_state *stream = context->streams[j];
+ struct dm_pp_single_disp_config *cfg =
+ &pp_display_cfg->disp_configs[num_cfgs];
+ const struct pipe_ctx *pipe_ctx = NULL;
+
+ for (k = 0; k < MAX_PIPES; k++)
+ if (stream == context->res_ctx.pipe_ctx[k].stream) {
+ pipe_ctx = &context->res_ctx.pipe_ctx[k];
+ break;
+ }
+
+ ASSERT(pipe_ctx != NULL);
+
+ /* only notify active stream */
+ if (stream->dpms_off)
+ continue;
+
+ num_cfgs++;
+ cfg->signal = pipe_ctx->stream->signal;
+ cfg->pipe_idx = pipe_ctx->stream_res.tg->inst;
+ cfg->src_height = stream->src.height;
+ cfg->src_width = stream->src.width;
+ cfg->ddi_channel_mapping =
+ stream->sink->link->ddi_channel_mapping.raw;
+ cfg->transmitter =
+ stream->sink->link->link_enc->transmitter;
+ cfg->link_settings.lane_count =
+ stream->sink->link->cur_link_settings.lane_count;
+ cfg->link_settings.link_rate =
+ stream->sink->link->cur_link_settings.link_rate;
+ cfg->link_settings.link_spread =
+ stream->sink->link->cur_link_settings.link_spread;
+ cfg->sym_clock = stream->phy_pix_clk;
+ /* Round v_refresh*/
+ cfg->v_refresh = stream->timing.pix_clk_khz * 1000;
+ cfg->v_refresh /= stream->timing.h_total;
+ cfg->v_refresh = (cfg->v_refresh + stream->timing.v_total / 2)
+ / stream->timing.v_total;
+ }
+
+ pp_display_cfg->display_count = num_cfgs;
+}
+
+static uint32_t dce110_get_min_vblank_time_us(const struct dc_state *context)
+{
+ uint8_t j;
+ uint32_t min_vertical_blank_time = -1;
+
+ for (j = 0; j < context->stream_count; j++) {
+ struct dc_stream_state *stream = context->streams[j];
+ uint32_t vertical_blank_in_pixels = 0;
+ uint32_t vertical_blank_time = 0;
+
+ vertical_blank_in_pixels = stream->timing.h_total *
+ (stream->timing.v_total
+ - stream->timing.v_addressable);
+
+ vertical_blank_time = vertical_blank_in_pixels
+ * 1000 / stream->timing.pix_clk_khz;
+
+ if (min_vertical_blank_time > vertical_blank_time)
+ min_vertical_blank_time = vertical_blank_time;
+ }
+
+ return min_vertical_blank_time;
+}
+
+static int determine_sclk_from_bounding_box(
+ const struct dc *dc,
+ int required_sclk)
+{
+ int i;
+
+ /*
+ * Some asics do not give us sclk levels, so we just report the actual
+ * required sclk
+ */
+ if (dc->sclk_lvls.num_levels == 0)
+ return required_sclk;
+
+ for (i = 0; i < dc->sclk_lvls.num_levels; i++) {
+ if (dc->sclk_lvls.clocks_in_khz[i] >= required_sclk)
+ return dc->sclk_lvls.clocks_in_khz[i];
+ }
+ /*
+ * even maximum level could not satisfy requirement, this
+ * is unexpected at this stage, should have been caught at
+ * validation time
+ */
+ ASSERT(0);
+ return dc->sclk_lvls.clocks_in_khz[dc->sclk_lvls.num_levels - 1];
+}
+
+static void dce_pplib_apply_display_requirements(
+ struct dc *dc,
+ struct dc_state *context)
+{
+ struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg;
+
+ pp_display_cfg->avail_mclk_switch_time_us = dce110_get_min_vblank_time_us(context);
+
+ dce110_fill_display_configs(context, pp_display_cfg);
+
+ if (memcmp(&dc->current_state->pp_display_cfg, pp_display_cfg, sizeof(*pp_display_cfg)) != 0)
+ dm_pp_apply_display_requirements(dc->ctx, pp_display_cfg);
+}
+
+static void dce11_pplib_apply_display_requirements(
+ struct dc *dc,
+ struct dc_state *context)
+{
+ struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg;
+
+ pp_display_cfg->all_displays_in_sync =
+ context->bw.dce.all_displays_in_sync;
+ pp_display_cfg->nb_pstate_switch_disable =
+ context->bw.dce.nbp_state_change_enable == false;
+ pp_display_cfg->cpu_cc6_disable =
+ context->bw.dce.cpuc_state_change_enable == false;
+ pp_display_cfg->cpu_pstate_disable =
+ context->bw.dce.cpup_state_change_enable == false;
+ pp_display_cfg->cpu_pstate_separation_time =
+ context->bw.dce.blackout_recovery_time_us;
+
+ pp_display_cfg->min_memory_clock_khz = context->bw.dce.yclk_khz
+ / MEMORY_TYPE_MULTIPLIER_CZ;
+
+ pp_display_cfg->min_engine_clock_khz = determine_sclk_from_bounding_box(
+ dc,
+ context->bw.dce.sclk_khz);
+
+ pp_display_cfg->min_engine_clock_deep_sleep_khz
+ = context->bw.dce.sclk_deep_sleep_khz;
+
+ pp_display_cfg->avail_mclk_switch_time_us =
+ dce110_get_min_vblank_time_us(context);
+ /* TODO: dce11.2*/
+ pp_display_cfg->avail_mclk_switch_time_in_disp_active_us = 0;
+
+ pp_display_cfg->disp_clk_khz = dc->res_pool->clk_mgr->clks.dispclk_khz;
+
+ dce110_fill_display_configs(context, pp_display_cfg);
+
+ /* TODO: is this still applicable?*/
+ if (pp_display_cfg->display_count == 1) {
+ const struct dc_crtc_timing *timing =
+ &context->streams[0]->timing;
+
+ pp_display_cfg->crtc_index =
+ pp_display_cfg->disp_configs[0].pipe_idx;
+ pp_display_cfg->line_time_in_us = timing->h_total * 1000 / timing->pix_clk_khz;
+ }
+
+ if (memcmp(&dc->current_state->pp_display_cfg, pp_display_cfg, sizeof(*pp_display_cfg)) != 0)
+ dm_pp_apply_display_requirements(dc->ctx, pp_display_cfg);
+}
+
+static void dce_update_clocks(struct clk_mgr *clk_mgr,
+ struct dc_state *context,
+ bool safe_to_lower)
+{
+ struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr);
+ struct dm_pp_power_level_change_request level_change_req;
+ int unpatched_disp_clk = context->bw.dce.dispclk_khz;
+
+ /*TODO: W/A for dal3 linux, investigate why this works */
+ if (!clk_mgr_dce->dfs_bypass_active)
+ context->bw.dce.dispclk_khz = context->bw.dce.dispclk_khz * 115 / 100;
+
+ level_change_req.power_level = dce_get_required_clocks_state(clk_mgr, context);
+ /* get max clock state from PPLIB */
+ if ((level_change_req.power_level < clk_mgr_dce->cur_min_clks_state && safe_to_lower)
+ || level_change_req.power_level > clk_mgr_dce->cur_min_clks_state) {
+ if (dm_pp_apply_power_level_change_request(clk_mgr->ctx, &level_change_req))
+ clk_mgr_dce->cur_min_clks_state = level_change_req.power_level;
+ }
+
+ if (should_set_clock(safe_to_lower, context->bw.dce.dispclk_khz, clk_mgr->clks.dispclk_khz)) {
+ context->bw.dce.dispclk_khz = dce_set_clock(clk_mgr, context->bw.dce.dispclk_khz);
+ clk_mgr->clks.dispclk_khz = context->bw.dce.dispclk_khz;
+ }
+ dce_pplib_apply_display_requirements(clk_mgr->ctx->dc, context);
+
+ context->bw.dce.dispclk_khz = unpatched_disp_clk;
+}
+
+static void dce11_update_clocks(struct clk_mgr *clk_mgr,
+ struct dc_state *context,
+ bool safe_to_lower)
+{
+ struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr);
+ struct dm_pp_power_level_change_request level_change_req;
+
+ level_change_req.power_level = dce_get_required_clocks_state(clk_mgr, context);
+ /* get max clock state from PPLIB */
+ if ((level_change_req.power_level < clk_mgr_dce->cur_min_clks_state && safe_to_lower)
+ || level_change_req.power_level > clk_mgr_dce->cur_min_clks_state) {
+ if (dm_pp_apply_power_level_change_request(clk_mgr->ctx, &level_change_req))
+ clk_mgr_dce->cur_min_clks_state = level_change_req.power_level;
+ }
+
+ if (should_set_clock(safe_to_lower, context->bw.dce.dispclk_khz, clk_mgr->clks.dispclk_khz)) {
+ context->bw.dce.dispclk_khz = dce_set_clock(clk_mgr, context->bw.dce.dispclk_khz);
+ clk_mgr->clks.dispclk_khz = context->bw.dce.dispclk_khz;
+ }
+ dce11_pplib_apply_display_requirements(clk_mgr->ctx->dc, context);
+}
+
+static void dce112_update_clocks(struct clk_mgr *clk_mgr,
+ struct dc_state *context,
+ bool safe_to_lower)
+{
+ struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr);
+ struct dm_pp_power_level_change_request level_change_req;
+
+ level_change_req.power_level = dce_get_required_clocks_state(clk_mgr, context);
+ /* get max clock state from PPLIB */
+ if ((level_change_req.power_level < clk_mgr_dce->cur_min_clks_state && safe_to_lower)
+ || level_change_req.power_level > clk_mgr_dce->cur_min_clks_state) {
+ if (dm_pp_apply_power_level_change_request(clk_mgr->ctx, &level_change_req))
+ clk_mgr_dce->cur_min_clks_state = level_change_req.power_level;
+ }
+
+ if (should_set_clock(safe_to_lower, context->bw.dce.dispclk_khz, clk_mgr->clks.dispclk_khz)) {
+ context->bw.dce.dispclk_khz = dce112_set_clock(clk_mgr, context->bw.dce.dispclk_khz);
+ clk_mgr->clks.dispclk_khz = context->bw.dce.dispclk_khz;
+ }
+ dce11_pplib_apply_display_requirements(clk_mgr->ctx->dc, context);
+}
+
+static void dce12_update_clocks(struct clk_mgr *clk_mgr,
+ struct dc_state *context,
+ bool safe_to_lower)
+{
+ struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr);
+ struct dm_pp_clock_for_voltage_req clock_voltage_req = {0};
+ int max_pix_clk = get_max_pixel_clock_for_all_paths(context);
+ int unpatched_disp_clk = context->bw.dce.dispclk_khz;
+
+ /*TODO: W/A for dal3 linux, investigate why this works */
+ if (!clk_mgr_dce->dfs_bypass_active)
+ context->bw.dce.dispclk_khz = context->bw.dce.dispclk_khz * 115 / 100;
+
+ if (should_set_clock(safe_to_lower, context->bw.dce.dispclk_khz, clk_mgr->clks.dispclk_khz)) {
+ clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DISPLAY_CLK;
+ clock_voltage_req.clocks_in_khz = context->bw.dce.dispclk_khz;
+ context->bw.dce.dispclk_khz = dce112_set_clock(clk_mgr, context->bw.dce.dispclk_khz);
+ clk_mgr->clks.dispclk_khz = context->bw.dce.dispclk_khz;
+
+ dm_pp_apply_clock_for_voltage_request(clk_mgr->ctx, &clock_voltage_req);
+ }
+
+ if (should_set_clock(safe_to_lower, max_pix_clk, clk_mgr->clks.phyclk_khz)) {
+ clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DISPLAYPHYCLK;
+ clock_voltage_req.clocks_in_khz = max_pix_clk;
+ clk_mgr->clks.phyclk_khz = max_pix_clk;
+
+ dm_pp_apply_clock_for_voltage_request(clk_mgr->ctx, &clock_voltage_req);
+ }
+ dce11_pplib_apply_display_requirements(clk_mgr->ctx->dc, context);
+
+ context->bw.dce.dispclk_khz = unpatched_disp_clk;
+}
+
+static const struct clk_mgr_funcs dce120_funcs = {
+ .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
+ .update_clocks = dce12_update_clocks
+};
+
+static const struct clk_mgr_funcs dce112_funcs = {
+ .get_dp_ref_clk_frequency = dce_get_dp_ref_freq_khz,
+ .update_clocks = dce112_update_clocks
+};
+
+static const struct clk_mgr_funcs dce110_funcs = {
+ .get_dp_ref_clk_frequency = dce_get_dp_ref_freq_khz,
+ .update_clocks = dce11_update_clocks,
+};
+
+static const struct clk_mgr_funcs dce_funcs = {
+ .get_dp_ref_clk_frequency = dce_get_dp_ref_freq_khz,
+ .update_clocks = dce_update_clocks
+};
+
+static void dce_clk_mgr_construct(
+ struct dce_clk_mgr *clk_mgr_dce,
+ struct dc_context *ctx,
+ const struct clk_mgr_registers *regs,
+ const struct clk_mgr_shift *clk_shift,
+ const struct clk_mgr_mask *clk_mask)
+{
+ struct clk_mgr *base = &clk_mgr_dce->base;
+ struct dm_pp_static_clock_info static_clk_info = {0};
+
+ base->ctx = ctx;
+ base->funcs = &dce_funcs;
+
+ clk_mgr_dce->regs = regs;
+ clk_mgr_dce->clk_mgr_shift = clk_shift;
+ clk_mgr_dce->clk_mgr_mask = clk_mask;
+
+ clk_mgr_dce->dfs_bypass_disp_clk = 0;
+
+ clk_mgr_dce->dprefclk_ss_percentage = 0;
+ clk_mgr_dce->dprefclk_ss_divider = 1000;
+ clk_mgr_dce->ss_on_dprefclk = false;
+
+
+ if (dm_pp_get_static_clocks(ctx, &static_clk_info))
+ clk_mgr_dce->max_clks_state = static_clk_info.max_clocks_state;
+ else
+ clk_mgr_dce->max_clks_state = DM_PP_CLOCKS_STATE_NOMINAL;
+ clk_mgr_dce->cur_min_clks_state = DM_PP_CLOCKS_STATE_INVALID;
+
+ dce_clock_read_integrated_info(clk_mgr_dce);
+ dce_clock_read_ss_info(clk_mgr_dce);
+}
+
+struct clk_mgr *dce_clk_mgr_create(
+ struct dc_context *ctx,
+ const struct clk_mgr_registers *regs,
+ const struct clk_mgr_shift *clk_shift,
+ const struct clk_mgr_mask *clk_mask)
+{
+ struct dce_clk_mgr *clk_mgr_dce = kzalloc(sizeof(*clk_mgr_dce), GFP_KERNEL);
+
+ if (clk_mgr_dce == NULL) {
+ BREAK_TO_DEBUGGER();
+ return NULL;
+ }
+
+ memcpy(clk_mgr_dce->max_clks_by_state,
+ dce80_max_clks_by_state,
+ sizeof(dce80_max_clks_by_state));
+
+ dce_clk_mgr_construct(
+ clk_mgr_dce, ctx, regs, clk_shift, clk_mask);
+
+ return &clk_mgr_dce->base;
+}
+
+struct clk_mgr *dce110_clk_mgr_create(
+ struct dc_context *ctx,
+ const struct clk_mgr_registers *regs,
+ const struct clk_mgr_shift *clk_shift,
+ const struct clk_mgr_mask *clk_mask)
+{
+ struct dce_clk_mgr *clk_mgr_dce = kzalloc(sizeof(*clk_mgr_dce), GFP_KERNEL);
+
+ if (clk_mgr_dce == NULL) {
+ BREAK_TO_DEBUGGER();
+ return NULL;
+ }
+
+ memcpy(clk_mgr_dce->max_clks_by_state,
+ dce110_max_clks_by_state,
+ sizeof(dce110_max_clks_by_state));
+
+ dce_clk_mgr_construct(
+ clk_mgr_dce, ctx, regs, clk_shift, clk_mask);
+
+ clk_mgr_dce->base.funcs = &dce110_funcs;
+
+ return &clk_mgr_dce->base;
+}
+
+struct clk_mgr *dce112_clk_mgr_create(
+ struct dc_context *ctx,
+ const struct clk_mgr_registers *regs,
+ const struct clk_mgr_shift *clk_shift,
+ const struct clk_mgr_mask *clk_mask)
+{
+ struct dce_clk_mgr *clk_mgr_dce = kzalloc(sizeof(*clk_mgr_dce), GFP_KERNEL);
+
+ if (clk_mgr_dce == NULL) {
+ BREAK_TO_DEBUGGER();
+ return NULL;
+ }
+
+ memcpy(clk_mgr_dce->max_clks_by_state,
+ dce112_max_clks_by_state,
+ sizeof(dce112_max_clks_by_state));
+
+ dce_clk_mgr_construct(
+ clk_mgr_dce, ctx, regs, clk_shift, clk_mask);
+
+ clk_mgr_dce->base.funcs = &dce112_funcs;
+
+ return &clk_mgr_dce->base;
+}
+
+struct clk_mgr *dce120_clk_mgr_create(struct dc_context *ctx)
+{
+ struct dce_clk_mgr *clk_mgr_dce = kzalloc(sizeof(*clk_mgr_dce), GFP_KERNEL);
+
+ if (clk_mgr_dce == NULL) {
+ BREAK_TO_DEBUGGER();
+ return NULL;
+ }
+
+ memcpy(clk_mgr_dce->max_clks_by_state,
+ dce120_max_clks_by_state,
+ sizeof(dce120_max_clks_by_state));
+
+ dce_clk_mgr_construct(
+ clk_mgr_dce, ctx, NULL, NULL, NULL);
+
+ clk_mgr_dce->dprefclk_khz = 600000;
+ clk_mgr_dce->base.funcs = &dce120_funcs;
+
+ return &clk_mgr_dce->base;
+}
+
+void dce_clk_mgr_destroy(struct clk_mgr **clk_mgr)
+{
+ struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(*clk_mgr);
+
+ kfree(clk_mgr_dce);
+ *clk_mgr = NULL;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h b/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.h
index 34fdb386c884..046077797416 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.h
@@ -24,10 +24,13 @@
*/
-#ifndef _DCE_CLOCKS_H_
-#define _DCE_CLOCKS_H_
+#ifndef _DCE_CLK_MGR_H_
+#define _DCE_CLK_MGR_H_
-#include "display_clock.h"
+#include "clk_mgr.h"
+#include "dccg.h"
+
+#define MEMORY_TYPE_MULTIPLIER_CZ 4
#define CLK_COMMON_REG_LIST_DCE_BASE() \
.DPREFCLK_CNTL = mmDPREFCLK_CNTL, \
@@ -53,24 +56,31 @@
type DENTIST_DISPCLK_WDIVIDER; \
type DENTIST_DISPCLK_CHG_DONE;
-struct dccg_shift {
+struct clk_mgr_shift {
CLK_REG_FIELD_LIST(uint8_t)
};
-struct dccg_mask {
+struct clk_mgr_mask {
CLK_REG_FIELD_LIST(uint32_t)
};
-struct dccg_registers {
+struct clk_mgr_registers {
uint32_t DPREFCLK_CNTL;
uint32_t DENTIST_DISPCLK_CNTL;
};
-struct dce_dccg {
- struct dccg base;
- const struct dccg_registers *regs;
- const struct dccg_shift *clk_shift;
- const struct dccg_mask *clk_mask;
+struct state_dependent_clocks {
+ int display_clk_khz;
+ int pixel_clk_khz;
+};
+
+struct dce_clk_mgr {
+ struct clk_mgr base;
+ const struct clk_mgr_registers *regs;
+ const struct clk_mgr_shift *clk_mgr_shift;
+ const struct clk_mgr_mask *clk_mgr_mask;
+
+ struct dccg *dccg;
struct state_dependent_clocks max_clks_by_state[DM_PP_CLOCKS_MAX_STATES];
@@ -91,33 +101,68 @@ struct dce_dccg {
/* DPREFCLK SS percentage Divider (100 or 1000) */
int dprefclk_ss_divider;
int dprefclk_khz;
+
+ enum dm_pp_clocks_state max_clks_state;
+ enum dm_pp_clocks_state cur_min_clks_state;
};
+/* Starting DID for each range */
+enum dentist_base_divider_id {
+ DENTIST_BASE_DID_1 = 0x08,
+ DENTIST_BASE_DID_2 = 0x40,
+ DENTIST_BASE_DID_3 = 0x60,
+ DENTIST_BASE_DID_4 = 0x7e,
+ DENTIST_MAX_DID = 0x7f
+};
-struct dccg *dce_dccg_create(
- struct dc_context *ctx,
- const struct dccg_registers *regs,
- const struct dccg_shift *clk_shift,
- const struct dccg_mask *clk_mask);
+/* Starting point and step size for each divider range.*/
+enum dentist_divider_range {
+ DENTIST_DIVIDER_RANGE_1_START = 8, /* 2.00 */
+ DENTIST_DIVIDER_RANGE_1_STEP = 1, /* 0.25 */
+ DENTIST_DIVIDER_RANGE_2_START = 64, /* 16.00 */
+ DENTIST_DIVIDER_RANGE_2_STEP = 2, /* 0.50 */
+ DENTIST_DIVIDER_RANGE_3_START = 128, /* 32.00 */
+ DENTIST_DIVIDER_RANGE_3_STEP = 4, /* 1.00 */
+ DENTIST_DIVIDER_RANGE_4_START = 248, /* 62.00 */
+ DENTIST_DIVIDER_RANGE_4_STEP = 264, /* 66.00 */
+ DENTIST_DIVIDER_RANGE_SCALE_FACTOR = 4
+};
+
+static inline bool should_set_clock(bool safe_to_lower, int calc_clk, int cur_clk)
+{
+ return ((safe_to_lower && calc_clk < cur_clk) || calc_clk > cur_clk);
+}
+
+void dce_clock_read_ss_info(struct dce_clk_mgr *dccg_dce);
+
+int dce12_get_dp_ref_freq_khz(struct clk_mgr *dccg);
-struct dccg *dce110_dccg_create(
+void dce110_fill_display_configs(
+ const struct dc_state *context,
+ struct dm_pp_display_configuration *pp_display_cfg);
+
+int dce112_set_clock(struct clk_mgr *dccg, int requested_clk_khz);
+
+struct clk_mgr *dce_clk_mgr_create(
struct dc_context *ctx,
- const struct dccg_registers *regs,
- const struct dccg_shift *clk_shift,
- const struct dccg_mask *clk_mask);
+ const struct clk_mgr_registers *regs,
+ const struct clk_mgr_shift *clk_shift,
+ const struct clk_mgr_mask *clk_mask);
-struct dccg *dce112_dccg_create(
+struct clk_mgr *dce110_clk_mgr_create(
struct dc_context *ctx,
- const struct dccg_registers *regs,
- const struct dccg_shift *clk_shift,
- const struct dccg_mask *clk_mask);
+ const struct clk_mgr_registers *regs,
+ const struct clk_mgr_shift *clk_shift,
+ const struct clk_mgr_mask *clk_mask);
-struct dccg *dce120_dccg_create(struct dc_context *ctx);
+struct clk_mgr *dce112_clk_mgr_create(
+ struct dc_context *ctx,
+ const struct clk_mgr_registers *regs,
+ const struct clk_mgr_shift *clk_shift,
+ const struct clk_mgr_mask *clk_mask);
-#ifdef CONFIG_DRM_AMD_DC_DCN1_0
-struct dccg *dcn1_dccg_create(struct dc_context *ctx);
-#endif
+struct clk_mgr *dce120_clk_mgr_create(struct dc_context *ctx);
-void dce_dccg_destroy(struct dccg **dccg);
+void dce_clk_mgr_destroy(struct clk_mgr **clk_mgr);
-#endif /* _DCE_CLOCKS_H_ */
+#endif /* _DCE_CLK_MGR_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c
deleted file mode 100644
index d89a097ba936..000000000000
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c
+++ /dev/null
@@ -1,947 +0,0 @@
-/*
- * Copyright 2012-16 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.
- *
- * Authors: AMD
- *
- */
-
-#include "dce_clocks.h"
-#include "dm_services.h"
-#include "reg_helper.h"
-#include "fixed31_32.h"
-#include "bios_parser_interface.h"
-#include "dc.h"
-#include "dmcu.h"
-#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
-#include "dcn_calcs.h"
-#endif
-#include "core_types.h"
-#include "dc_types.h"
-#include "dal_asic_id.h"
-
-#define TO_DCE_CLOCKS(clocks)\
- container_of(clocks, struct dce_dccg, base)
-
-#define REG(reg) \
- (clk_dce->regs->reg)
-
-#undef FN
-#define FN(reg_name, field_name) \
- clk_dce->clk_shift->field_name, clk_dce->clk_mask->field_name
-
-#define CTX \
- clk_dce->base.ctx
-#define DC_LOGGER \
- clk->ctx->logger
-
-/* Max clock values for each state indexed by "enum clocks_state": */
-static const struct state_dependent_clocks dce80_max_clks_by_state[] = {
-/* ClocksStateInvalid - should not be used */
-{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
-/* ClocksStateUltraLow - not expected to be used for DCE 8.0 */
-{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
-/* ClocksStateLow */
-{ .display_clk_khz = 352000, .pixel_clk_khz = 330000},
-/* ClocksStateNominal */
-{ .display_clk_khz = 600000, .pixel_clk_khz = 400000 },
-/* ClocksStatePerformance */
-{ .display_clk_khz = 600000, .pixel_clk_khz = 400000 } };
-
-static const struct state_dependent_clocks dce110_max_clks_by_state[] = {
-/*ClocksStateInvalid - should not be used*/
-{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
-/*ClocksStateUltraLow - currently by HW design team not supposed to be used*/
-{ .display_clk_khz = 352000, .pixel_clk_khz = 330000 },
-/*ClocksStateLow*/
-{ .display_clk_khz = 352000, .pixel_clk_khz = 330000 },
-/*ClocksStateNominal*/
-{ .display_clk_khz = 467000, .pixel_clk_khz = 400000 },
-/*ClocksStatePerformance*/
-{ .display_clk_khz = 643000, .pixel_clk_khz = 400000 } };
-
-static const struct state_dependent_clocks dce112_max_clks_by_state[] = {
-/*ClocksStateInvalid - should not be used*/
-{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
-/*ClocksStateUltraLow - currently by HW design team not supposed to be used*/
-{ .display_clk_khz = 389189, .pixel_clk_khz = 346672 },
-/*ClocksStateLow*/
-{ .display_clk_khz = 459000, .pixel_clk_khz = 400000 },
-/*ClocksStateNominal*/
-{ .display_clk_khz = 667000, .pixel_clk_khz = 600000 },
-/*ClocksStatePerformance*/
-{ .display_clk_khz = 1132000, .pixel_clk_khz = 600000 } };
-
-static const struct state_dependent_clocks dce120_max_clks_by_state[] = {
-/*ClocksStateInvalid - should not be used*/
-{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
-/*ClocksStateUltraLow - currently by HW design team not supposed to be used*/
-{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
-/*ClocksStateLow*/
-{ .display_clk_khz = 460000, .pixel_clk_khz = 400000 },
-/*ClocksStateNominal*/
-{ .display_clk_khz = 670000, .pixel_clk_khz = 600000 },
-/*ClocksStatePerformance*/
-{ .display_clk_khz = 1133000, .pixel_clk_khz = 600000 } };
-
-/* Starting DID for each range */
-enum dentist_base_divider_id {
- DENTIST_BASE_DID_1 = 0x08,
- DENTIST_BASE_DID_2 = 0x40,
- DENTIST_BASE_DID_3 = 0x60,
- DENTIST_BASE_DID_4 = 0x7e,
- DENTIST_MAX_DID = 0x7f
-};
-
-/* Starting point and step size for each divider range.*/
-enum dentist_divider_range {
- DENTIST_DIVIDER_RANGE_1_START = 8, /* 2.00 */
- DENTIST_DIVIDER_RANGE_1_STEP = 1, /* 0.25 */
- DENTIST_DIVIDER_RANGE_2_START = 64, /* 16.00 */
- DENTIST_DIVIDER_RANGE_2_STEP = 2, /* 0.50 */
- DENTIST_DIVIDER_RANGE_3_START = 128, /* 32.00 */
- DENTIST_DIVIDER_RANGE_3_STEP = 4, /* 1.00 */
- DENTIST_DIVIDER_RANGE_4_START = 248, /* 62.00 */
- DENTIST_DIVIDER_RANGE_4_STEP = 264, /* 66.00 */
- DENTIST_DIVIDER_RANGE_SCALE_FACTOR = 4
-};
-
-static int dentist_get_divider_from_did(int did)
-{
- if (did < DENTIST_BASE_DID_1)
- did = DENTIST_BASE_DID_1;
- if (did > DENTIST_MAX_DID)
- did = DENTIST_MAX_DID;
-
- if (did < DENTIST_BASE_DID_2) {
- return DENTIST_DIVIDER_RANGE_1_START + DENTIST_DIVIDER_RANGE_1_STEP
- * (did - DENTIST_BASE_DID_1);
- } else if (did < DENTIST_BASE_DID_3) {
- return DENTIST_DIVIDER_RANGE_2_START + DENTIST_DIVIDER_RANGE_2_STEP
- * (did - DENTIST_BASE_DID_2);
- } else if (did < DENTIST_BASE_DID_4) {
- return DENTIST_DIVIDER_RANGE_3_START + DENTIST_DIVIDER_RANGE_3_STEP
- * (did - DENTIST_BASE_DID_3);
- } else {
- return DENTIST_DIVIDER_RANGE_4_START + DENTIST_DIVIDER_RANGE_4_STEP
- * (did - DENTIST_BASE_DID_4);
- }
-}
-
-/* SW will adjust DP REF Clock average value for all purposes
- * (DP DTO / DP Audio DTO and DP GTC)
- if clock is spread for all cases:
- -if SS enabled on DP Ref clock and HW de-spreading enabled with SW
- calculations for DS_INCR/DS_MODULO (this is planned to be default case)
- -if SS enabled on DP Ref clock and HW de-spreading enabled with HW
- calculations (not planned to be used, but average clock should still
- be valid)
- -if SS enabled on DP Ref clock and HW de-spreading disabled
- (should not be case with CIK) then SW should program all rates
- generated according to average value (case as with previous ASICs)
- */
-static int dccg_adjust_dp_ref_freq_for_ss(struct dce_dccg *clk_dce, int dp_ref_clk_khz)
-{
- if (clk_dce->ss_on_dprefclk && clk_dce->dprefclk_ss_divider != 0) {
- struct fixed31_32 ss_percentage = dc_fixpt_div_int(
- dc_fixpt_from_fraction(clk_dce->dprefclk_ss_percentage,
- clk_dce->dprefclk_ss_divider), 200);
- struct fixed31_32 adj_dp_ref_clk_khz;
-
- ss_percentage = dc_fixpt_sub(dc_fixpt_one, ss_percentage);
- adj_dp_ref_clk_khz = dc_fixpt_mul_int(ss_percentage, dp_ref_clk_khz);
- dp_ref_clk_khz = dc_fixpt_floor(adj_dp_ref_clk_khz);
- }
- return dp_ref_clk_khz;
-}
-
-static int dce_get_dp_ref_freq_khz(struct dccg *clk)
-{
- struct dce_dccg *clk_dce = TO_DCE_CLOCKS(clk);
- int dprefclk_wdivider;
- int dprefclk_src_sel;
- int dp_ref_clk_khz = 600000;
- int target_div;
-
- /* ASSERT DP Reference Clock source is from DFS*/
- REG_GET(DPREFCLK_CNTL, DPREFCLK_SRC_SEL, &dprefclk_src_sel);
- ASSERT(dprefclk_src_sel == 0);
-
- /* Read the mmDENTIST_DISPCLK_CNTL to get the currently
- * programmed DID DENTIST_DPREFCLK_WDIVIDER*/
- REG_GET(DENTIST_DISPCLK_CNTL, DENTIST_DPREFCLK_WDIVIDER, &dprefclk_wdivider);
-
- /* Convert DENTIST_DPREFCLK_WDIVIDERto actual divider*/
- target_div = dentist_get_divider_from_did(dprefclk_wdivider);
-
- /* Calculate the current DFS clock, in kHz.*/
- dp_ref_clk_khz = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR
- * clk_dce->dentist_vco_freq_khz) / target_div;
-
- return dccg_adjust_dp_ref_freq_for_ss(clk_dce, dp_ref_clk_khz);
-}
-
-static int dce12_get_dp_ref_freq_khz(struct dccg *clk)
-{
- struct dce_dccg *clk_dce = TO_DCE_CLOCKS(clk);
-
- return dccg_adjust_dp_ref_freq_for_ss(clk_dce, clk_dce->dprefclk_khz);
-}
-
-static enum dm_pp_clocks_state dce_get_required_clocks_state(
- struct dccg *clk,
- struct dc_clocks *req_clocks)
-{
- struct dce_dccg *clk_dce = TO_DCE_CLOCKS(clk);
- int i;
- enum dm_pp_clocks_state low_req_clk;
-
- /* Iterate from highest supported to lowest valid state, and update
- * lowest RequiredState with the lowest state that satisfies
- * all required clocks
- */
- for (i = clk->max_clks_state; i >= DM_PP_CLOCKS_STATE_ULTRA_LOW; i--)
- if (req_clocks->dispclk_khz >
- clk_dce->max_clks_by_state[i].display_clk_khz
- || req_clocks->phyclk_khz >
- clk_dce->max_clks_by_state[i].pixel_clk_khz)
- break;
-
- low_req_clk = i + 1;
- if (low_req_clk > clk->max_clks_state) {
- /* set max clock state for high phyclock, invalid on exceeding display clock */
- if (clk_dce->max_clks_by_state[clk->max_clks_state].display_clk_khz
- < req_clocks->dispclk_khz)
- low_req_clk = DM_PP_CLOCKS_STATE_INVALID;
- else
- low_req_clk = clk->max_clks_state;
- }
-
- return low_req_clk;
-}
-
-static int dce_set_clock(
- struct dccg *clk,
- int requested_clk_khz)
-{
- struct dce_dccg *clk_dce = TO_DCE_CLOCKS(clk);
- struct bp_pixel_clock_parameters pxl_clk_params = { 0 };
- struct dc_bios *bp = clk->ctx->dc_bios;
- int actual_clock = requested_clk_khz;
-
- /* Make sure requested clock isn't lower than minimum threshold*/
- if (requested_clk_khz > 0)
- requested_clk_khz = max(requested_clk_khz,
- clk_dce->dentist_vco_freq_khz / 64);
-
- /* Prepare to program display clock*/
- pxl_clk_params.target_pixel_clock = requested_clk_khz;
- pxl_clk_params.pll_id = CLOCK_SOURCE_ID_DFS;
-
- if (clk_dce->dfs_bypass_active)
- pxl_clk_params.flags.SET_DISPCLK_DFS_BYPASS = true;
-
- bp->funcs->program_display_engine_pll(bp, &pxl_clk_params);
-
- if (clk_dce->dfs_bypass_active) {
- /* Cache the fixed display clock*/
- clk_dce->dfs_bypass_disp_clk =
- pxl_clk_params.dfs_bypass_display_clock;
- actual_clock = pxl_clk_params.dfs_bypass_display_clock;
- }
-
- /* from power down, we need mark the clock state as ClocksStateNominal
- * from HWReset, so when resume we will call pplib voltage regulator.*/
- if (requested_clk_khz == 0)
- clk->cur_min_clks_state = DM_PP_CLOCKS_STATE_NOMINAL;
- return actual_clock;
-}
-
-static int dce_psr_set_clock(
- struct dccg *clk,
- int requested_clk_khz)
-{
- struct dce_dccg *clk_dce = TO_DCE_CLOCKS(clk);
- struct dc_context *ctx = clk_dce->base.ctx;
- struct dc *core_dc = ctx->dc;
- struct dmcu *dmcu = core_dc->res_pool->dmcu;
- int actual_clk_khz = requested_clk_khz;
-
- actual_clk_khz = dce_set_clock(clk, requested_clk_khz);
-
- dmcu->funcs->set_psr_wait_loop(dmcu, actual_clk_khz / 1000 / 7);
- return actual_clk_khz;
-}
-
-static int dce112_set_clock(
- struct dccg *clk,
- int requested_clk_khz)
-{
- struct dce_dccg *clk_dce = TO_DCE_CLOCKS(clk);
- struct bp_set_dce_clock_parameters dce_clk_params;
- struct dc_bios *bp = clk->ctx->dc_bios;
- struct dc *core_dc = clk->ctx->dc;
- struct dmcu *dmcu = core_dc->res_pool->dmcu;
- int actual_clock = requested_clk_khz;
- /* Prepare to program display clock*/
- memset(&dce_clk_params, 0, sizeof(dce_clk_params));
-
- /* Make sure requested clock isn't lower than minimum threshold*/
- if (requested_clk_khz > 0)
- requested_clk_khz = max(requested_clk_khz,
- clk_dce->dentist_vco_freq_khz / 62);
-
- dce_clk_params.target_clock_frequency = requested_clk_khz;
- dce_clk_params.pll_id = CLOCK_SOURCE_ID_DFS;
- dce_clk_params.clock_type = DCECLOCK_TYPE_DISPLAY_CLOCK;
-
- bp->funcs->set_dce_clock(bp, &dce_clk_params);
- actual_clock = dce_clk_params.target_clock_frequency;
-
- /* from power down, we need mark the clock state as ClocksStateNominal
- * from HWReset, so when resume we will call pplib voltage regulator.*/
- if (requested_clk_khz == 0)
- clk->cur_min_clks_state = DM_PP_CLOCKS_STATE_NOMINAL;
-
- /*Program DP ref Clock*/
- /*VBIOS will determine DPREFCLK frequency, so we don't set it*/
- dce_clk_params.target_clock_frequency = 0;
- dce_clk_params.clock_type = DCECLOCK_TYPE_DPREFCLK;
- if (!ASICREV_IS_VEGA20_P(clk->ctx->asic_id.hw_internal_rev))
- dce_clk_params.flags.USE_GENLOCK_AS_SOURCE_FOR_DPREFCLK =
- (dce_clk_params.pll_id ==
- CLOCK_SOURCE_COMBO_DISPLAY_PLL0);
- else
- dce_clk_params.flags.USE_GENLOCK_AS_SOURCE_FOR_DPREFCLK = false;
-
- bp->funcs->set_dce_clock(bp, &dce_clk_params);
-
- if (!IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) {
- if (clk_dce->dfs_bypass_disp_clk != actual_clock)
- dmcu->funcs->set_psr_wait_loop(dmcu,
- actual_clock / 1000 / 7);
- }
-
- clk_dce->dfs_bypass_disp_clk = actual_clock;
- return actual_clock;
-}
-
-static void dce_clock_read_integrated_info(struct dce_dccg *clk_dce)
-{
- struct dc_debug_options *debug = &clk_dce->base.ctx->dc->debug;
- struct dc_bios *bp = clk_dce->base.ctx->dc_bios;
- struct integrated_info info = { { { 0 } } };
- struct dc_firmware_info fw_info = { { 0 } };
- int i;
-
- if (bp->integrated_info)
- info = *bp->integrated_info;
-
- clk_dce->dentist_vco_freq_khz = info.dentist_vco_freq;
- if (clk_dce->dentist_vco_freq_khz == 0) {
- bp->funcs->get_firmware_info(bp, &fw_info);
- clk_dce->dentist_vco_freq_khz =
- fw_info.smu_gpu_pll_output_freq;
- if (clk_dce->dentist_vco_freq_khz == 0)
- clk_dce->dentist_vco_freq_khz = 3600000;
- }
-
- /*update the maximum display clock for each power state*/
- for (i = 0; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
- enum dm_pp_clocks_state clk_state = DM_PP_CLOCKS_STATE_INVALID;
-
- switch (i) {
- case 0:
- clk_state = DM_PP_CLOCKS_STATE_ULTRA_LOW;
- break;
-
- case 1:
- clk_state = DM_PP_CLOCKS_STATE_LOW;
- break;
-
- case 2:
- clk_state = DM_PP_CLOCKS_STATE_NOMINAL;
- break;
-
- case 3:
- clk_state = DM_PP_CLOCKS_STATE_PERFORMANCE;
- break;
-
- default:
- clk_state = DM_PP_CLOCKS_STATE_INVALID;
- break;
- }
-
- /*Do not allow bad VBIOS/SBIOS to override with invalid values,
- * check for > 100MHz*/
- if (info.disp_clk_voltage[i].max_supported_clk >= 100000)
- clk_dce->max_clks_by_state[clk_state].display_clk_khz =
- info.disp_clk_voltage[i].max_supported_clk;
- }
-
- if (!debug->disable_dfs_bypass && bp->integrated_info)
- if (bp->integrated_info->gpu_cap_info & DFS_BYPASS_ENABLE)
- clk_dce->dfs_bypass_enabled = true;
-}
-
-static void dce_clock_read_ss_info(struct dce_dccg *clk_dce)
-{
- struct dc_bios *bp = clk_dce->base.ctx->dc_bios;
- int ss_info_num = bp->funcs->get_ss_entry_number(
- bp, AS_SIGNAL_TYPE_GPU_PLL);
-
- if (ss_info_num) {
- struct spread_spectrum_info info = { { 0 } };
- enum bp_result result = bp->funcs->get_spread_spectrum_info(
- bp, AS_SIGNAL_TYPE_GPU_PLL, 0, &info);
-
- /* Based on VBIOS, VBIOS will keep entry for GPU PLL SS
- * even if SS not enabled and in that case
- * SSInfo.spreadSpectrumPercentage !=0 would be sign
- * that SS is enabled
- */
- if (result == BP_RESULT_OK &&
- info.spread_spectrum_percentage != 0) {
- clk_dce->ss_on_dprefclk = true;
- clk_dce->dprefclk_ss_divider = info.spread_percentage_divider;
-
- if (info.type.CENTER_MODE == 0) {
- /* TODO: Currently for DP Reference clock we
- * need only SS percentage for
- * downspread */
- clk_dce->dprefclk_ss_percentage =
- info.spread_spectrum_percentage;
- }
-
- return;
- }
-
- result = bp->funcs->get_spread_spectrum_info(
- bp, AS_SIGNAL_TYPE_DISPLAY_PORT, 0, &info);
-
- /* Based on VBIOS, VBIOS will keep entry for DPREFCLK SS
- * even if SS not enabled and in that case
- * SSInfo.spreadSpectrumPercentage !=0 would be sign
- * that SS is enabled
- */
- if (result == BP_RESULT_OK &&
- info.spread_spectrum_percentage != 0) {
- clk_dce->ss_on_dprefclk = true;
- clk_dce->dprefclk_ss_divider = info.spread_percentage_divider;
-
- if (info.type.CENTER_MODE == 0) {
- /* Currently for DP Reference clock we
- * need only SS percentage for
- * downspread */
- clk_dce->dprefclk_ss_percentage =
- info.spread_spectrum_percentage;
- }
- }
- }
-}
-
-static inline bool should_set_clock(bool safe_to_lower, int calc_clk, int cur_clk)
-{
- return ((safe_to_lower && calc_clk < cur_clk) || calc_clk > cur_clk);
-}
-
-static void dce12_update_clocks(struct dccg *dccg,
- struct dc_clocks *new_clocks,
- bool safe_to_lower)
-{
- struct dm_pp_clock_for_voltage_req clock_voltage_req = {0};
-
- /* TODO: Investigate why this is needed to fix display corruption. */
- new_clocks->dispclk_khz = new_clocks->dispclk_khz * 115 / 100;
-
- if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, dccg->clks.dispclk_khz)) {
- clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DISPLAY_CLK;
- clock_voltage_req.clocks_in_khz = new_clocks->dispclk_khz;
- new_clocks->dispclk_khz = dccg->funcs->set_dispclk(dccg, new_clocks->dispclk_khz);
- dccg->clks.dispclk_khz = new_clocks->dispclk_khz;
-
- dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req);
- }
-
- if (should_set_clock(safe_to_lower, new_clocks->phyclk_khz, dccg->clks.phyclk_khz)) {
- clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DISPLAYPHYCLK;
- clock_voltage_req.clocks_in_khz = new_clocks->phyclk_khz;
- dccg->clks.phyclk_khz = new_clocks->phyclk_khz;
-
- dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req);
- }
-}
-
-#ifdef CONFIG_DRM_AMD_DC_DCN1_0
-static int dcn1_determine_dppclk_threshold(struct dccg *dccg, struct dc_clocks *new_clocks)
-{
- bool request_dpp_div = new_clocks->dispclk_khz > new_clocks->dppclk_khz;
- bool dispclk_increase = new_clocks->dispclk_khz > dccg->clks.dispclk_khz;
- int disp_clk_threshold = new_clocks->max_supported_dppclk_khz;
- bool cur_dpp_div = dccg->clks.dispclk_khz > dccg->clks.dppclk_khz;
-
- /* increase clock, looking for div is 0 for current, request div is 1*/
- if (dispclk_increase) {
- /* already divided by 2, no need to reach target clk with 2 steps*/
- if (cur_dpp_div)
- return new_clocks->dispclk_khz;
-
- /* request disp clk is lower than maximum supported dpp clk,
- * no need to reach target clk with two steps.
- */
- if (new_clocks->dispclk_khz <= disp_clk_threshold)
- return new_clocks->dispclk_khz;
-
- /* target dpp clk not request divided by 2, still within threshold */
- if (!request_dpp_div)
- return new_clocks->dispclk_khz;
-
- } else {
- /* decrease clock, looking for current dppclk divided by 2,
- * request dppclk not divided by 2.
- */
-
- /* current dpp clk not divided by 2, no need to ramp*/
- if (!cur_dpp_div)
- return new_clocks->dispclk_khz;
-
- /* current disp clk is lower than current maximum dpp clk,
- * no need to ramp
- */
- if (dccg->clks.dispclk_khz <= disp_clk_threshold)
- return new_clocks->dispclk_khz;
-
- /* request dpp clk need to be divided by 2 */
- if (request_dpp_div)
- return new_clocks->dispclk_khz;
- }
-
- return disp_clk_threshold;
-}
-
-static void dcn1_ramp_up_dispclk_with_dpp(struct dccg *dccg, struct dc_clocks *new_clocks)
-{
- struct dc *dc = dccg->ctx->dc;
- int dispclk_to_dpp_threshold = dcn1_determine_dppclk_threshold(dccg, new_clocks);
- bool request_dpp_div = new_clocks->dispclk_khz > new_clocks->dppclk_khz;
- int i;
-
- /* set disp clk to dpp clk threshold */
- dccg->funcs->set_dispclk(dccg, dispclk_to_dpp_threshold);
-
- /* update request dpp clk division option */
- for (i = 0; i < dc->res_pool->pipe_count; i++) {
- struct pipe_ctx *pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
-
- if (!pipe_ctx->plane_state)
- continue;
-
- pipe_ctx->plane_res.dpp->funcs->dpp_dppclk_control(
- pipe_ctx->plane_res.dpp,
- request_dpp_div,
- true);
- }
-
- /* If target clk not same as dppclk threshold, set to target clock */
- if (dispclk_to_dpp_threshold != new_clocks->dispclk_khz)
- dccg->funcs->set_dispclk(dccg, new_clocks->dispclk_khz);
-
- dccg->clks.dispclk_khz = new_clocks->dispclk_khz;
- dccg->clks.dppclk_khz = new_clocks->dppclk_khz;
- dccg->clks.max_supported_dppclk_khz = new_clocks->max_supported_dppclk_khz;
-}
-
-static void dcn1_update_clocks(struct dccg *dccg,
- struct dc_clocks *new_clocks,
- bool safe_to_lower)
-{
- struct dc *dc = dccg->ctx->dc;
- struct pp_smu_display_requirement_rv *smu_req_cur =
- &dc->res_pool->pp_smu_req;
- struct pp_smu_display_requirement_rv smu_req = *smu_req_cur;
- struct pp_smu_funcs_rv *pp_smu = dc->res_pool->pp_smu;
- struct dm_pp_clock_for_voltage_req clock_voltage_req = {0};
- bool send_request_to_increase = false;
- bool send_request_to_lower = false;
-
- if (new_clocks->phyclk_khz)
- smu_req.display_count = 1;
- else
- smu_req.display_count = 0;
-
- if (new_clocks->dispclk_khz > dccg->clks.dispclk_khz
- || new_clocks->phyclk_khz > dccg->clks.phyclk_khz
- || new_clocks->fclk_khz > dccg->clks.fclk_khz
- || new_clocks->dcfclk_khz > dccg->clks.dcfclk_khz)
- send_request_to_increase = true;
-
- if (should_set_clock(safe_to_lower, new_clocks->phyclk_khz, dccg->clks.phyclk_khz)) {
- dccg->clks.phyclk_khz = new_clocks->phyclk_khz;
-
- send_request_to_lower = true;
- }
-
- if (should_set_clock(safe_to_lower, new_clocks->fclk_khz, dccg->clks.fclk_khz)) {
- dccg->clks.fclk_khz = new_clocks->fclk_khz;
- clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_FCLK;
- clock_voltage_req.clocks_in_khz = new_clocks->fclk_khz;
- smu_req.hard_min_fclk_khz = new_clocks->fclk_khz;
-
- dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req);
- send_request_to_lower = true;
- }
-
- if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, dccg->clks.dcfclk_khz)) {
- dccg->clks.dcfclk_khz = new_clocks->dcfclk_khz;
- smu_req.hard_min_dcefclk_khz = new_clocks->dcfclk_khz;
-
- send_request_to_lower = true;
- }
-
- if (should_set_clock(safe_to_lower,
- new_clocks->dcfclk_deep_sleep_khz, dccg->clks.dcfclk_deep_sleep_khz)) {
- dccg->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz;
- smu_req.min_deep_sleep_dcefclk_mhz = new_clocks->dcfclk_deep_sleep_khz;
-
- send_request_to_lower = true;
- }
-
- /* make sure dcf clk is before dpp clk to
- * make sure we have enough voltage to run dpp clk
- */
- if (send_request_to_increase) {
- /*use dcfclk to request voltage*/
- clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DCFCLK;
- clock_voltage_req.clocks_in_khz = dcn_find_dcfclk_suits_all(dc, new_clocks);
- dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req);
- if (pp_smu->set_display_requirement)
- pp_smu->set_display_requirement(&pp_smu->pp_smu, &smu_req);
- }
-
- /* dcn1 dppclk is tied to dispclk */
- /* program dispclk on = as a w/a for sleep resume clock ramping issues */
- if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, dccg->clks.dispclk_khz)
- || new_clocks->dispclk_khz == dccg->clks.dispclk_khz) {
- dcn1_ramp_up_dispclk_with_dpp(dccg, new_clocks);
- dccg->clks.dispclk_khz = new_clocks->dispclk_khz;
-
- send_request_to_lower = true;
- }
-
- if (!send_request_to_increase && send_request_to_lower) {
- /*use dcfclk to request voltage*/
- clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DCFCLK;
- clock_voltage_req.clocks_in_khz = dcn_find_dcfclk_suits_all(dc, new_clocks);
- dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req);
- if (pp_smu->set_display_requirement)
- pp_smu->set_display_requirement(&pp_smu->pp_smu, &smu_req);
- }
-
-
- *smu_req_cur = smu_req;
-}
-#endif
-
-static void dce_update_clocks(struct dccg *dccg,
- struct dc_clocks *new_clocks,
- bool safe_to_lower)
-{
- struct dm_pp_power_level_change_request level_change_req;
- struct dce_dccg *clk_dce = TO_DCE_CLOCKS(dccg);
-
- /* TODO: Investigate why this is needed to fix display corruption. */
- if (!clk_dce->dfs_bypass_active)
- new_clocks->dispclk_khz = new_clocks->dispclk_khz * 115 / 100;
-
- level_change_req.power_level = dce_get_required_clocks_state(dccg, new_clocks);
- /* get max clock state from PPLIB */
- if ((level_change_req.power_level < dccg->cur_min_clks_state && safe_to_lower)
- || level_change_req.power_level > dccg->cur_min_clks_state) {
- if (dm_pp_apply_power_level_change_request(dccg->ctx, &level_change_req))
- dccg->cur_min_clks_state = level_change_req.power_level;
- }
-
- if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, dccg->clks.dispclk_khz)) {
- new_clocks->dispclk_khz = dccg->funcs->set_dispclk(dccg, new_clocks->dispclk_khz);
- dccg->clks.dispclk_khz = new_clocks->dispclk_khz;
- }
-}
-
-static bool dce_update_dfs_bypass(
- struct dccg *dccg,
- struct dc *dc,
- struct dc_state *context,
- int requested_clock_khz)
-{
- struct dce_dccg *clk_dce = TO_DCE_CLOCKS(dccg);
- struct resource_context *res_ctx = &context->res_ctx;
- enum signal_type signal_type = SIGNAL_TYPE_NONE;
- bool was_active = clk_dce->dfs_bypass_active;
- int i;
-
- /* Disable DFS bypass by default. */
- clk_dce->dfs_bypass_active = false;
-
- /* Check that DFS bypass is available. */
- if (!clk_dce->dfs_bypass_enabled)
- goto update;
-
- /* Check if the requested display clock is below the threshold. */
- if (requested_clock_khz >= 400000)
- goto update;
-
- /* DFS-bypass should only be enabled on single stream setups */
- if (context->stream_count != 1)
- goto update;
-
- /* Check that the stream's signal type is an embedded panel */
- for (i = 0; i < dc->res_pool->pipe_count; i++) {
- if (res_ctx->pipe_ctx[i].stream) {
- struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i];
-
- signal_type = pipe_ctx->stream->sink->link->connector_signal;
- break;
- }
- }
-
- if (signal_type == SIGNAL_TYPE_EDP ||
- signal_type == SIGNAL_TYPE_LVDS)
- clk_dce->dfs_bypass_active = true;
-
-update:
- /* Update the clock state. We don't need to respect safe_to_lower
- * because DFS bypass should always be greater than the current
- * display clock frequency.
- */
- if (was_active != clk_dce->dfs_bypass_active) {
- dccg->clks.dispclk_khz =
- dccg->funcs->set_dispclk(dccg, dccg->clks.dispclk_khz);
- return true;
- }
-
- return false;
-}
-
-#ifdef CONFIG_DRM_AMD_DC_DCN1_0
-static const struct display_clock_funcs dcn1_funcs = {
- .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
- .set_dispclk = dce112_set_clock,
- .update_clocks = dcn1_update_clocks
-};
-#endif
-
-static const struct display_clock_funcs dce120_funcs = {
- .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
- .set_dispclk = dce112_set_clock,
- .update_clocks = dce12_update_clocks
-};
-
-static const struct display_clock_funcs dce112_funcs = {
- .get_dp_ref_clk_frequency = dce_get_dp_ref_freq_khz,
- .set_dispclk = dce112_set_clock,
- .update_clocks = dce_update_clocks
-};
-
-static const struct display_clock_funcs dce110_funcs = {
- .get_dp_ref_clk_frequency = dce_get_dp_ref_freq_khz,
- .set_dispclk = dce_psr_set_clock,
- .update_clocks = dce_update_clocks,
- .update_dfs_bypass = dce_update_dfs_bypass
-};
-
-static const struct display_clock_funcs dce_funcs = {
- .get_dp_ref_clk_frequency = dce_get_dp_ref_freq_khz,
- .set_dispclk = dce_set_clock,
- .update_clocks = dce_update_clocks
-};
-
-static void dce_dccg_construct(
- struct dce_dccg *clk_dce,
- struct dc_context *ctx,
- const struct dccg_registers *regs,
- const struct dccg_shift *clk_shift,
- const struct dccg_mask *clk_mask)
-{
- struct dccg *base = &clk_dce->base;
-
- base->ctx = ctx;
- base->funcs = &dce_funcs;
-
- clk_dce->regs = regs;
- clk_dce->clk_shift = clk_shift;
- clk_dce->clk_mask = clk_mask;
-
- clk_dce->dfs_bypass_disp_clk = 0;
-
- clk_dce->dprefclk_ss_percentage = 0;
- clk_dce->dprefclk_ss_divider = 1000;
- clk_dce->ss_on_dprefclk = false;
-
- base->max_clks_state = DM_PP_CLOCKS_STATE_NOMINAL;
- base->cur_min_clks_state = DM_PP_CLOCKS_STATE_INVALID;
-
- dce_clock_read_integrated_info(clk_dce);
- dce_clock_read_ss_info(clk_dce);
-}
-
-struct dccg *dce_dccg_create(
- struct dc_context *ctx,
- const struct dccg_registers *regs,
- const struct dccg_shift *clk_shift,
- const struct dccg_mask *clk_mask)
-{
- struct dce_dccg *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL);
-
- if (clk_dce == NULL) {
- BREAK_TO_DEBUGGER();
- return NULL;
- }
-
- memcpy(clk_dce->max_clks_by_state,
- dce80_max_clks_by_state,
- sizeof(dce80_max_clks_by_state));
-
- dce_dccg_construct(
- clk_dce, ctx, regs, clk_shift, clk_mask);
-
- return &clk_dce->base;
-}
-
-struct dccg *dce110_dccg_create(
- struct dc_context *ctx,
- const struct dccg_registers *regs,
- const struct dccg_shift *clk_shift,
- const struct dccg_mask *clk_mask)
-{
- struct dce_dccg *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL);
-
- if (clk_dce == NULL) {
- BREAK_TO_DEBUGGER();
- return NULL;
- }
-
- memcpy(clk_dce->max_clks_by_state,
- dce110_max_clks_by_state,
- sizeof(dce110_max_clks_by_state));
-
- dce_dccg_construct(
- clk_dce, ctx, regs, clk_shift, clk_mask);
-
- clk_dce->base.funcs = &dce110_funcs;
-
- return &clk_dce->base;
-}
-
-struct dccg *dce112_dccg_create(
- struct dc_context *ctx,
- const struct dccg_registers *regs,
- const struct dccg_shift *clk_shift,
- const struct dccg_mask *clk_mask)
-{
- struct dce_dccg *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL);
-
- if (clk_dce == NULL) {
- BREAK_TO_DEBUGGER();
- return NULL;
- }
-
- memcpy(clk_dce->max_clks_by_state,
- dce112_max_clks_by_state,
- sizeof(dce112_max_clks_by_state));
-
- dce_dccg_construct(
- clk_dce, ctx, regs, clk_shift, clk_mask);
-
- clk_dce->base.funcs = &dce112_funcs;
-
- return &clk_dce->base;
-}
-
-struct dccg *dce120_dccg_create(struct dc_context *ctx)
-{
- struct dce_dccg *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL);
-
- if (clk_dce == NULL) {
- BREAK_TO_DEBUGGER();
- return NULL;
- }
-
- memcpy(clk_dce->max_clks_by_state,
- dce120_max_clks_by_state,
- sizeof(dce120_max_clks_by_state));
-
- dce_dccg_construct(
- clk_dce, ctx, NULL, NULL, NULL);
-
- clk_dce->dprefclk_khz = 600000;
- clk_dce->base.funcs = &dce120_funcs;
-
- return &clk_dce->base;
-}
-
-#ifdef CONFIG_DRM_AMD_DC_DCN1_0
-struct dccg *dcn1_dccg_create(struct dc_context *ctx)
-{
- struct dc_debug_options *debug = &ctx->dc->debug;
- struct dc_bios *bp = ctx->dc_bios;
- struct dc_firmware_info fw_info = { { 0 } };
- struct dce_dccg *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL);
-
- if (clk_dce == NULL) {
- BREAK_TO_DEBUGGER();
- return NULL;
- }
-
- clk_dce->base.ctx = ctx;
- clk_dce->base.funcs = &dcn1_funcs;
-
- clk_dce->dfs_bypass_disp_clk = 0;
-
- clk_dce->dprefclk_ss_percentage = 0;
- clk_dce->dprefclk_ss_divider = 1000;
- clk_dce->ss_on_dprefclk = false;
-
- clk_dce->dprefclk_khz = 600000;
- if (bp->integrated_info)
- clk_dce->dentist_vco_freq_khz = bp->integrated_info->dentist_vco_freq;
- if (clk_dce->dentist_vco_freq_khz == 0) {
- bp->funcs->get_firmware_info(bp, &fw_info);
- clk_dce->dentist_vco_freq_khz = fw_info.smu_gpu_pll_output_freq;
- if (clk_dce->dentist_vco_freq_khz == 0)
- clk_dce->dentist_vco_freq_khz = 3600000;
- }
-
- if (!debug->disable_dfs_bypass && bp->integrated_info)
- if (bp->integrated_info->gpu_cap_info & DFS_BYPASS_ENABLE)
- clk_dce->dfs_bypass_enabled = true;
-
- dce_clock_read_ss_info(clk_dce);
-
- return &clk_dce->base;
-}
-#endif
-
-void dce_dccg_destroy(struct dccg **dccg)
-{
- struct dce_dccg *clk_dce = TO_DCE_CLOCKS(*dccg);
-
- kfree(clk_dce);
- *dccg = NULL;
-}
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h
index 64dc75378541..c83a7f05f14c 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h
@@ -233,6 +233,16 @@ struct dce_hwseq_registers {
uint32_t DOMAIN5_PG_CONFIG;
uint32_t DOMAIN6_PG_CONFIG;
uint32_t DOMAIN7_PG_CONFIG;
+ uint32_t DOMAIN8_PG_CONFIG;
+ uint32_t DOMAIN9_PG_CONFIG;
+ uint32_t DOMAIN10_PG_CONFIG;
+ uint32_t DOMAIN11_PG_CONFIG;
+ uint32_t DOMAIN16_PG_CONFIG;
+ uint32_t DOMAIN17_PG_CONFIG;
+ uint32_t DOMAIN18_PG_CONFIG;
+ uint32_t DOMAIN19_PG_CONFIG;
+ uint32_t DOMAIN20_PG_CONFIG;
+ uint32_t DOMAIN21_PG_CONFIG;
uint32_t DOMAIN0_PG_STATUS;
uint32_t DOMAIN1_PG_STATUS;
uint32_t DOMAIN2_PG_STATUS;
@@ -241,6 +251,16 @@ struct dce_hwseq_registers {
uint32_t DOMAIN5_PG_STATUS;
uint32_t DOMAIN6_PG_STATUS;
uint32_t DOMAIN7_PG_STATUS;
+ uint32_t DOMAIN8_PG_STATUS;
+ uint32_t DOMAIN9_PG_STATUS;
+ uint32_t DOMAIN10_PG_STATUS;
+ uint32_t DOMAIN11_PG_STATUS;
+ uint32_t DOMAIN16_PG_STATUS;
+ uint32_t DOMAIN17_PG_STATUS;
+ uint32_t DOMAIN18_PG_STATUS;
+ uint32_t DOMAIN19_PG_STATUS;
+ uint32_t DOMAIN20_PG_STATUS;
+ uint32_t DOMAIN21_PG_STATUS;
uint32_t DIO_MEM_PWR_CTRL;
uint32_t DCCG_GATE_DISABLE_CNTL;
uint32_t DCCG_GATE_DISABLE_CNTL2;
@@ -262,6 +282,8 @@ struct dce_hwseq_registers {
uint32_t D2VGA_CONTROL;
uint32_t D3VGA_CONTROL;
uint32_t D4VGA_CONTROL;
+ uint32_t D5VGA_CONTROL;
+ uint32_t D6VGA_CONTROL;
uint32_t VGA_TEST_CONTROL;
/* MMHUB registers. read only. temporary hack */
uint32_t VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32;
@@ -489,6 +511,26 @@ struct dce_hwseq_registers {
type DOMAIN6_POWER_GATE; \
type DOMAIN7_POWER_FORCEON; \
type DOMAIN7_POWER_GATE; \
+ type DOMAIN8_POWER_FORCEON; \
+ type DOMAIN8_POWER_GATE; \
+ type DOMAIN9_POWER_FORCEON; \
+ type DOMAIN9_POWER_GATE; \
+ type DOMAIN10_POWER_FORCEON; \
+ type DOMAIN10_POWER_GATE; \
+ type DOMAIN11_POWER_FORCEON; \
+ type DOMAIN11_POWER_GATE; \
+ type DOMAIN16_POWER_FORCEON; \
+ type DOMAIN16_POWER_GATE; \
+ type DOMAIN17_POWER_FORCEON; \
+ type DOMAIN17_POWER_GATE; \
+ type DOMAIN18_POWER_FORCEON; \
+ type DOMAIN18_POWER_GATE; \
+ type DOMAIN19_POWER_FORCEON; \
+ type DOMAIN19_POWER_GATE; \
+ type DOMAIN20_POWER_FORCEON; \
+ type DOMAIN20_POWER_GATE; \
+ type DOMAIN21_POWER_FORCEON; \
+ type DOMAIN21_POWER_GATE; \
type DOMAIN0_PGFSM_PWR_STATUS; \
type DOMAIN1_PGFSM_PWR_STATUS; \
type DOMAIN2_PGFSM_PWR_STATUS; \
@@ -497,6 +539,16 @@ struct dce_hwseq_registers {
type DOMAIN5_PGFSM_PWR_STATUS; \
type DOMAIN6_PGFSM_PWR_STATUS; \
type DOMAIN7_PGFSM_PWR_STATUS; \
+ type DOMAIN8_PGFSM_PWR_STATUS; \
+ type DOMAIN9_PGFSM_PWR_STATUS; \
+ type DOMAIN10_PGFSM_PWR_STATUS; \
+ type DOMAIN11_PGFSM_PWR_STATUS; \
+ type DOMAIN16_PGFSM_PWR_STATUS; \
+ type DOMAIN17_PGFSM_PWR_STATUS; \
+ type DOMAIN18_PGFSM_PWR_STATUS; \
+ type DOMAIN19_PGFSM_PWR_STATUS; \
+ type DOMAIN20_PGFSM_PWR_STATUS; \
+ type DOMAIN21_PGFSM_PWR_STATUS; \
type DCFCLK_GATE_DIS; \
type DCHUBBUB_GLOBAL_TIMER_REFDIV; \
type VGA_TEST_ENABLE; \
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c
index 366bc8c2c643..3e18ea84b1f9 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c
@@ -645,7 +645,7 @@ static bool dce110_link_encoder_validate_hdmi_output(
return false;
/* DCE11 HW does not support 420 */
- if (!enc110->base.features.ycbcr420_supported &&
+ if (!enc110->base.features.hdmi_ycbcr420_supported &&
crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR420)
return false;
diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c
index 74c05e878807..bc50a8e25f4f 100644
--- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c
+++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c
@@ -105,74 +105,18 @@ bool dce100_enable_display_power_gating(
return false;
}
-static void dce100_pplib_apply_display_requirements(
- struct dc *dc,
- struct dc_state *context)
-{
- struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg;
-
- pp_display_cfg->avail_mclk_switch_time_us =
- dce110_get_min_vblank_time_us(context);
- /*pp_display_cfg->min_memory_clock_khz = context->bw.dce.yclk_khz
- / MEMORY_TYPE_MULTIPLIER;*/
-
- dce110_fill_display_configs(context, pp_display_cfg);
-
- if (memcmp(&dc->prev_display_config, pp_display_cfg, sizeof(
- struct dm_pp_display_configuration)) != 0)
- dm_pp_apply_display_requirements(dc->ctx, pp_display_cfg);
-
- dc->prev_display_config = *pp_display_cfg;
-}
-
-/* unit: in_khz before mode set, get pixel clock from context. ASIC register
- * may not be programmed yet
- */
-static uint32_t get_max_pixel_clock_for_all_paths(
- struct dc *dc,
- struct dc_state *context)
-{
- uint32_t max_pix_clk = 0;
- int i;
-
- for (i = 0; i < MAX_PIPES; i++) {
- struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
-
- if (pipe_ctx->stream == NULL)
- continue;
-
- /* do not check under lay */
- if (pipe_ctx->top_pipe)
- continue;
-
- if (pipe_ctx->stream_res.pix_clk_params.requested_pix_clk > max_pix_clk)
- max_pix_clk =
- pipe_ctx->stream_res.pix_clk_params.requested_pix_clk;
- }
- return max_pix_clk;
-}
-
-void dce100_set_bandwidth(
+void dce100_prepare_bandwidth(
struct dc *dc,
- struct dc_state *context,
- bool decrease_allowed)
+ struct dc_state *context)
{
- struct dc_clocks req_clks;
-
- req_clks.dispclk_khz = context->bw.dce.dispclk_khz * 115 / 100;
- req_clks.phyclk_khz = get_max_pixel_clock_for_all_paths(dc, context);
-
dce110_set_safe_displaymarks(&context->res_ctx, dc->res_pool);
- dc->res_pool->dccg->funcs->update_clocks(
- dc->res_pool->dccg,
- &req_clks,
- decrease_allowed);
-
- dce100_pplib_apply_display_requirements(dc, context);
+ dc->res_pool->clk_mgr->funcs->update_clocks(
+ dc->res_pool->clk_mgr,
+ context,
+ false);
}
-
/**************************************************************************/
void dce100_hw_sequencer_construct(struct dc *dc)
@@ -180,8 +124,7 @@ void dce100_hw_sequencer_construct(struct dc *dc)
dce110_hw_sequencer_construct(dc);
dc->hwss.enable_display_power_gating = dce100_enable_display_power_gating;
- dc->hwss.set_bandwidth = dce100_set_bandwidth;
- dc->hwss.pplib_apply_display_requirements =
- dce100_pplib_apply_display_requirements;
+ dc->hwss.prepare_bandwidth = dce100_prepare_bandwidth;
+ dc->hwss.optimize_bandwidth = dce100_prepare_bandwidth;
}
diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.h
index c6ec0ed6ec3d..acd418515346 100644
--- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.h
+++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.h
@@ -33,10 +33,9 @@ struct dc_state;
void dce100_hw_sequencer_construct(struct dc *dc);
-void dce100_set_bandwidth(
+void dce100_prepare_bandwidth(
struct dc *dc,
- struct dc_state *context,
- bool decrease_allowed);
+ struct dc_state *context);
bool dce100_enable_display_power_gating(struct dc *dc, uint8_t controller_id,
struct dc_bios *dcb,
diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c
index 14754a87156c..6ae51a5dfc04 100644
--- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c
@@ -36,11 +36,11 @@
#include "dce/dce_link_encoder.h"
#include "dce/dce_stream_encoder.h"
+#include "dce/dce_clk_mgr.h"
#include "dce/dce_mem_input.h"
#include "dce/dce_ipp.h"
#include "dce/dce_transform.h"
#include "dce/dce_opp.h"
-#include "dce/dce_clocks.h"
#include "dce/dce_clock_source.h"
#include "dce/dce_audio.h"
#include "dce/dce_hwseq.h"
@@ -137,15 +137,15 @@ static const struct dce110_timing_generator_offsets dce100_tg_offsets[] = {
.reg_name = mm ## block ## id ## _ ## reg_name
-static const struct dccg_registers disp_clk_regs = {
+static const struct clk_mgr_registers disp_clk_regs = {
CLK_COMMON_REG_LIST_DCE_BASE()
};
-static const struct dccg_shift disp_clk_shift = {
+static const struct clk_mgr_shift disp_clk_shift = {
CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT)
};
-static const struct dccg_mask disp_clk_mask = {
+static const struct clk_mgr_mask disp_clk_mask = {
CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK)
};
@@ -722,8 +722,8 @@ static void destruct(struct dce110_resource_pool *pool)
dce_aud_destroy(&pool->base.audios[i]);
}
- if (pool->base.dccg != NULL)
- dce_dccg_destroy(&pool->base.dccg);
+ if (pool->base.clk_mgr != NULL)
+ dce_clk_mgr_destroy(&pool->base.clk_mgr);
if (pool->base.abm != NULL)
dce_abm_destroy(&pool->base.abm);
@@ -767,7 +767,7 @@ bool dce100_validate_bandwidth(
if (at_least_one_pipe) {
/* TODO implement when needed but for now hardcode max value*/
context->bw.dce.dispclk_khz = 681000;
- context->bw.dce.yclk_khz = 250000 * MEMORY_TYPE_MULTIPLIER;
+ context->bw.dce.yclk_khz = 250000 * MEMORY_TYPE_MULTIPLIER_CZ;
} else {
context->bw.dce.dispclk_khz = 0;
context->bw.dce.yclk_khz = 0;
@@ -860,7 +860,6 @@ static bool construct(
struct dc_context *ctx = dc->ctx;
struct dc_firmware_info info;
struct dc_bios *bp;
- struct dm_pp_static_clock_info static_clk_info = {0};
ctx->dc_bios->regs = &bios_regs;
@@ -908,11 +907,11 @@ static bool construct(
}
}
- pool->base.dccg = dce_dccg_create(ctx,
+ pool->base.clk_mgr = dce_clk_mgr_create(ctx,
&disp_clk_regs,
&disp_clk_shift,
&disp_clk_mask);
- if (pool->base.dccg == NULL) {
+ if (pool->base.clk_mgr == NULL) {
dm_error("DC: failed to create display clock!\n");
BREAK_TO_DEBUGGER();
goto res_create_fail;
@@ -938,12 +937,6 @@ static bool construct(
goto res_create_fail;
}
- /* get static clock information for PPLIB or firmware, save
- * max_clock_state
- */
- if (dm_pp_get_static_clocks(ctx, &static_clk_info))
- pool->base.dccg->max_clks_state =
- static_clk_info.max_clocks_state;
{
struct irq_service_init_data init_data;
init_data.ctx = dc->ctx;
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 b75ede5f84f7..9724a17e352b 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
@@ -548,14 +548,14 @@ dce110_translate_regamma_to_hw_format(const struct dc_transfer_func *output_tf,
regamma_params->hw_points_num = hw_points;
- i = 1;
- for (k = 0; k < 16 && i < 16; k++) {
+ k = 0;
+ for (i = 1; i < 16; i++) {
if (seg_distr[k] != -1) {
regamma_params->arr_curve_points[k].segments_num = seg_distr[k];
regamma_params->arr_curve_points[i].offset =
regamma_params->arr_curve_points[k].offset + (1 << seg_distr[k]);
}
- i++;
+ k++;
}
if (seg_distr[k] != -1)
@@ -1085,7 +1085,6 @@ void dce110_unblank_stream(struct pipe_ctx *pipe_ctx,
if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) {
link->dc->hwss.edp_backlight_control(link, true);
- stream->bl_pwm_level = EDP_BACKLIGHT_RAMP_DISABLE_LEVEL;
}
}
void dce110_blank_stream(struct pipe_ctx *pipe_ctx)
@@ -1192,8 +1191,8 @@ static void build_audio_output(
if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT ||
pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
audio_output->pll_info.dp_dto_source_clock_in_khz =
- state->dis_clk->funcs->get_dp_ref_clk_frequency(
- state->dis_clk);
+ state->dccg->funcs->get_dp_ref_clk_frequency(
+ state->dccg);
}
audio_output->pll_info.feed_back_divider =
@@ -1547,6 +1546,7 @@ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context)
int i;
struct dc_link *edp_link_to_turnoff = NULL;
struct dc_link *edp_link = get_link_for_edp(dc);
+ struct dc_bios *bios = dc->ctx->dc_bios;
bool can_edp_fast_boot_optimize = false;
bool apply_edp_fast_boot_optimization = false;
@@ -1573,6 +1573,20 @@ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context)
if (context->streams[i]->signal == SIGNAL_TYPE_EDP) {
context->streams[i]->apply_edp_fast_boot_optimization = true;
apply_edp_fast_boot_optimization = true;
+
+ /* When after S4 and S5, vbios may post edp and previous dpms_off
+ * doesn't make sense.
+ * Update dpms_off state to align hw and sw state via check
+ * vBios scratch register.
+ */
+ if (bios->funcs->is_active_display) {
+ const struct connector_device_tag_info *device_tag = &(edp_link->device_tag);
+
+ if (bios->funcs->is_active_display(bios,
+ context->streams[i]->signal,
+ device_tag))
+ context->streams[i]->dpms_off = false;
+ }
}
}
}
@@ -1736,41 +1750,18 @@ static void set_static_screen_control(struct pipe_ctx **pipe_ctx,
if (events->force_trigger)
value |= 0x1;
- value |= 0x84;
+ if (num_pipes) {
+ struct dc *dc = pipe_ctx[0]->stream->ctx->dc;
+
+ if (dc->fbc_compressor)
+ value |= 0x84;
+ }
for (i = 0; i < num_pipes; i++)
pipe_ctx[i]->stream_res.tg->funcs->
set_static_screen_control(pipe_ctx[i]->stream_res.tg, value);
}
-/* unit: in_khz before mode set, get pixel clock from context. ASIC register
- * may not be programmed yet
- */
-static uint32_t get_max_pixel_clock_for_all_paths(
- struct dc *dc,
- struct dc_state *context)
-{
- uint32_t max_pix_clk = 0;
- int i;
-
- for (i = 0; i < MAX_PIPES; i++) {
- struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
-
- if (pipe_ctx->stream == NULL)
- continue;
-
- /* do not check under lay */
- if (pipe_ctx->top_pipe)
- continue;
-
- if (pipe_ctx->stream_res.pix_clk_params.requested_pix_clk > max_pix_clk)
- max_pix_clk =
- pipe_ctx->stream_res.pix_clk_params.requested_pix_clk;
- }
-
- return max_pix_clk;
-}
-
/*
* Check if FBC can be enabled
*/
@@ -2380,191 +2371,33 @@ static void init_hw(struct dc *dc)
}
-void dce110_fill_display_configs(
- const struct dc_state *context,
- struct dm_pp_display_configuration *pp_display_cfg)
-{
- int j;
- int num_cfgs = 0;
-
- for (j = 0; j < context->stream_count; j++) {
- int k;
-
- const struct dc_stream_state *stream = context->streams[j];
- struct dm_pp_single_disp_config *cfg =
- &pp_display_cfg->disp_configs[num_cfgs];
- const struct pipe_ctx *pipe_ctx = NULL;
-
- for (k = 0; k < MAX_PIPES; k++)
- if (stream == context->res_ctx.pipe_ctx[k].stream) {
- pipe_ctx = &context->res_ctx.pipe_ctx[k];
- break;
- }
-
- ASSERT(pipe_ctx != NULL);
-
- /* only notify active stream */
- if (stream->dpms_off)
- continue;
-
- num_cfgs++;
- cfg->signal = pipe_ctx->stream->signal;
- cfg->pipe_idx = pipe_ctx->stream_res.tg->inst;
- cfg->src_height = stream->src.height;
- cfg->src_width = stream->src.width;
- cfg->ddi_channel_mapping =
- stream->sink->link->ddi_channel_mapping.raw;
- cfg->transmitter =
- stream->sink->link->link_enc->transmitter;
- cfg->link_settings.lane_count =
- stream->sink->link->cur_link_settings.lane_count;
- cfg->link_settings.link_rate =
- stream->sink->link->cur_link_settings.link_rate;
- cfg->link_settings.link_spread =
- stream->sink->link->cur_link_settings.link_spread;
- cfg->sym_clock = stream->phy_pix_clk;
- /* Round v_refresh*/
- cfg->v_refresh = stream->timing.pix_clk_khz * 1000;
- cfg->v_refresh /= stream->timing.h_total;
- cfg->v_refresh = (cfg->v_refresh + stream->timing.v_total / 2)
- / stream->timing.v_total;
- }
-
- pp_display_cfg->display_count = num_cfgs;
-}
-
-uint32_t dce110_get_min_vblank_time_us(const struct dc_state *context)
-{
- uint8_t j;
- uint32_t min_vertical_blank_time = -1;
-
- for (j = 0; j < context->stream_count; j++) {
- struct dc_stream_state *stream = context->streams[j];
- uint32_t vertical_blank_in_pixels = 0;
- uint32_t vertical_blank_time = 0;
-
- vertical_blank_in_pixels = stream->timing.h_total *
- (stream->timing.v_total
- - stream->timing.v_addressable);
-
- vertical_blank_time = vertical_blank_in_pixels
- * 1000 / stream->timing.pix_clk_khz;
-
- if (min_vertical_blank_time > vertical_blank_time)
- min_vertical_blank_time = vertical_blank_time;
- }
-
- return min_vertical_blank_time;
-}
-
-static int determine_sclk_from_bounding_box(
- const struct dc *dc,
- int required_sclk)
-{
- int i;
- /*
- * Some asics do not give us sclk levels, so we just report the actual
- * required sclk
- */
- if (dc->sclk_lvls.num_levels == 0)
- return required_sclk;
-
- for (i = 0; i < dc->sclk_lvls.num_levels; i++) {
- if (dc->sclk_lvls.clocks_in_khz[i] >= required_sclk)
- return dc->sclk_lvls.clocks_in_khz[i];
- }
- /*
- * even maximum level could not satisfy requirement, this
- * is unexpected at this stage, should have been caught at
- * validation time
- */
- ASSERT(0);
- return dc->sclk_lvls.clocks_in_khz[dc->sclk_lvls.num_levels - 1];
-}
-
-static void pplib_apply_display_requirements(
- struct dc *dc,
- struct dc_state *context)
+void dce110_prepare_bandwidth(
+ struct dc *dc,
+ struct dc_state *context)
{
- struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg;
+ struct clk_mgr *dccg = dc->res_pool->clk_mgr;
- pp_display_cfg->all_displays_in_sync =
- context->bw.dce.all_displays_in_sync;
- pp_display_cfg->nb_pstate_switch_disable =
- context->bw.dce.nbp_state_change_enable == false;
- pp_display_cfg->cpu_cc6_disable =
- context->bw.dce.cpuc_state_change_enable == false;
- pp_display_cfg->cpu_pstate_disable =
- context->bw.dce.cpup_state_change_enable == false;
- pp_display_cfg->cpu_pstate_separation_time =
- context->bw.dce.blackout_recovery_time_us;
+ dce110_set_safe_displaymarks(&context->res_ctx, dc->res_pool);
- pp_display_cfg->min_memory_clock_khz = context->bw.dce.yclk_khz
- / MEMORY_TYPE_MULTIPLIER;
-
- pp_display_cfg->min_engine_clock_khz = determine_sclk_from_bounding_box(
- dc,
- context->bw.dce.sclk_khz);
-
- pp_display_cfg->min_engine_clock_deep_sleep_khz
- = context->bw.dce.sclk_deep_sleep_khz;
-
- pp_display_cfg->avail_mclk_switch_time_us =
- dce110_get_min_vblank_time_us(context);
- /* TODO: dce11.2*/
- pp_display_cfg->avail_mclk_switch_time_in_disp_active_us = 0;
-
- pp_display_cfg->disp_clk_khz = dc->res_pool->dccg->clks.dispclk_khz;
-
- dce110_fill_display_configs(context, pp_display_cfg);
-
- /* TODO: is this still applicable?*/
- if (pp_display_cfg->display_count == 1) {
- const struct dc_crtc_timing *timing =
- &context->streams[0]->timing;
-
- pp_display_cfg->crtc_index =
- pp_display_cfg->disp_configs[0].pipe_idx;
- pp_display_cfg->line_time_in_us = timing->h_total * 1000
- / timing->pix_clk_khz;
- }
-
- if (memcmp(&dc->prev_display_config, pp_display_cfg, sizeof(
- struct dm_pp_display_configuration)) != 0)
- dm_pp_apply_display_requirements(dc->ctx, pp_display_cfg);
-
- dc->prev_display_config = *pp_display_cfg;
+ dccg->funcs->update_clocks(
+ dccg,
+ context,
+ false);
}
-static void dce110_set_bandwidth(
+void dce110_optimize_bandwidth(
struct dc *dc,
- struct dc_state *context,
- bool decrease_allowed)
+ struct dc_state *context)
{
- struct dc_clocks req_clks;
- struct dccg *dccg = dc->res_pool->dccg;
-
- req_clks.dispclk_khz = context->bw.dce.dispclk_khz;
- req_clks.phyclk_khz = get_max_pixel_clock_for_all_paths(dc, context);
-
- if (decrease_allowed)
- dce110_set_displaymarks(dc, context);
- else
- dce110_set_safe_displaymarks(&context->res_ctx, dc->res_pool);
+ struct clk_mgr *dccg = dc->res_pool->clk_mgr;
- if (dccg->funcs->update_dfs_bypass)
- dccg->funcs->update_dfs_bypass(
- dccg,
- dc,
- context,
- req_clks.dispclk_khz);
+ dce110_set_displaymarks(dc, context);
dccg->funcs->update_clocks(
dccg,
- &req_clks,
- decrease_allowed);
- pplib_apply_display_requirements(dc, context);
+ context,
+ true);
}
static void dce110_program_front_end_for_pipe(
@@ -2769,28 +2602,6 @@ static void dce110_wait_for_mpcc_disconnect(
/* do nothing*/
}
-static void program_csc_matrix(struct pipe_ctx *pipe_ctx,
- enum dc_color_space colorspace,
- uint16_t *matrix)
-{
- int i;
- struct out_csc_color_matrix tbl_entry;
-
- if (pipe_ctx->stream->csc_color_matrix.enable_adjustment
- == true) {
- enum dc_color_space color_space =
- pipe_ctx->stream->output_color_space;
-
- //uint16_t matrix[12];
- for (i = 0; i < 12; i++)
- tbl_entry.regval[i] = pipe_ctx->stream->csc_color_matrix.matrix[i];
-
- tbl_entry.color_space = color_space;
- //tbl_entry.regval = matrix;
- pipe_ctx->plane_res.xfm->funcs->opp_set_csc_adjustment(pipe_ctx->plane_res.xfm, &tbl_entry);
- }
-}
-
void dce110_set_cursor_position(struct pipe_ctx *pipe_ctx)
{
struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position;
@@ -2839,13 +2650,8 @@ void dce110_set_cursor_attribute(struct pipe_ctx *pipe_ctx)
pipe_ctx->plane_res.xfm, attributes);
}
-static void ready_shared_resources(struct dc *dc, struct dc_state *context) {}
-
-static void optimize_shared_resources(struct dc *dc) {}
-
static const struct hw_sequencer_funcs dce110_funcs = {
.program_gamut_remap = program_gamut_remap,
- .program_csc_matrix = program_csc_matrix,
.init_hw = init_hw,
.apply_ctx_to_hw = dce110_apply_ctx_to_hw,
.apply_ctx_for_surface = dce110_apply_ctx_for_surface,
@@ -2868,7 +2674,8 @@ static const struct hw_sequencer_funcs dce110_funcs = {
.enable_display_power_gating = dce110_enable_display_power_gating,
.disable_plane = dce110_power_down_fe,
.pipe_control_lock = dce_pipe_control_lock,
- .set_bandwidth = dce110_set_bandwidth,
+ .prepare_bandwidth = dce110_prepare_bandwidth,
+ .optimize_bandwidth = dce110_optimize_bandwidth,
.set_drr = set_drr,
.get_position = get_position,
.set_static_screen_control = set_static_screen_control,
@@ -2877,9 +2684,6 @@ static const struct hw_sequencer_funcs dce110_funcs = {
.setup_stereo = NULL,
.set_avmute = dce110_set_avmute,
.wait_for_mpcc_disconnect = dce110_wait_for_mpcc_disconnect,
- .ready_shared_resources = ready_shared_resources,
- .optimize_shared_resources = optimize_shared_resources,
- .pplib_apply_display_requirements = pplib_apply_display_requirements,
.edp_backlight_control = hwss_edp_backlight_control,
.edp_power_control = hwss_edp_power_control,
.edp_wait_for_hpd_ready = hwss_edp_wait_for_hpd_ready,
diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h
index d6db3dbd9015..cd3e36d52a52 100644
--- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h
+++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h
@@ -40,7 +40,6 @@ enum dc_status dce110_apply_ctx_to_hw(
struct dc_state *context);
-
void dce110_enable_stream(struct pipe_ctx *pipe_ctx);
void dce110_disable_stream(struct pipe_ctx *pipe_ctx, int option);
@@ -64,11 +63,13 @@ void dce110_set_safe_displaymarks(
struct resource_context *res_ctx,
const struct resource_pool *pool);
-void dce110_fill_display_configs(
- const struct dc_state *context,
- struct dm_pp_display_configuration *pp_display_cfg);
+void dce110_prepare_bandwidth(
+ struct dc *dc,
+ struct dc_state *context);
-uint32_t dce110_get_min_vblank_time_us(const struct dc_state *context);
+void dce110_optimize_bandwidth(
+ struct dc *dc,
+ struct dc_state *context);
void dp_receiver_power_ctrl(struct dc_link *link, bool on);
diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c
index e3624ca24574..e33d11785b1f 100644
--- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c
@@ -31,6 +31,7 @@
#include "resource.h"
#include "dce110/dce110_resource.h"
+#include "dce/dce_clk_mgr.h"
#include "include/irq_service_interface.h"
#include "dce/dce_audio.h"
#include "dce110/dce110_timing_generator.h"
@@ -45,7 +46,6 @@
#include "dce110/dce110_transform_v.h"
#include "dce/dce_opp.h"
#include "dce110/dce110_opp_v.h"
-#include "dce/dce_clocks.h"
#include "dce/dce_clock_source.h"
#include "dce/dce_hwseq.h"
#include "dce110/dce110_hw_sequencer.h"
@@ -148,15 +148,15 @@ static const struct dce110_timing_generator_offsets dce110_tg_offsets[] = {
#define SRI(reg_name, block, id)\
.reg_name = mm ## block ## id ## _ ## reg_name
-static const struct dccg_registers disp_clk_regs = {
+static const struct clk_mgr_registers disp_clk_regs = {
CLK_COMMON_REG_LIST_DCE_BASE()
};
-static const struct dccg_shift disp_clk_shift = {
+static const struct clk_mgr_shift disp_clk_shift = {
CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT)
};
-static const struct dccg_mask disp_clk_mask = {
+static const struct clk_mgr_mask disp_clk_mask = {
CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK)
};
@@ -760,8 +760,8 @@ static void destruct(struct dce110_resource_pool *pool)
if (pool->base.dmcu != NULL)
dce_dmcu_destroy(&pool->base.dmcu);
- if (pool->base.dccg != NULL)
- dce_dccg_destroy(&pool->base.dccg);
+ if (pool->base.clk_mgr != NULL)
+ dce_clk_mgr_destroy(&pool->base.clk_mgr);
if (pool->base.irqs != NULL) {
dal_irq_service_destroy(&pool->base.irqs);
@@ -1173,12 +1173,12 @@ static void bw_calcs_data_update_from_pplib(struct dc *dc)
&clks);
dc->bw_vbios->low_yclk = bw_frc_to_fixed(
- clks.clocks_in_khz[0] * MEMORY_TYPE_MULTIPLIER, 1000);
+ clks.clocks_in_khz[0] * MEMORY_TYPE_MULTIPLIER_CZ, 1000);
dc->bw_vbios->mid_yclk = bw_frc_to_fixed(
- clks.clocks_in_khz[clks.num_levels>>1] * MEMORY_TYPE_MULTIPLIER,
+ clks.clocks_in_khz[clks.num_levels>>1] * MEMORY_TYPE_MULTIPLIER_CZ,
1000);
dc->bw_vbios->high_yclk = bw_frc_to_fixed(
- clks.clocks_in_khz[clks.num_levels-1] * MEMORY_TYPE_MULTIPLIER,
+ clks.clocks_in_khz[clks.num_levels-1] * MEMORY_TYPE_MULTIPLIER_CZ,
1000);
}
@@ -1201,7 +1201,6 @@ static bool construct(
struct dc_context *ctx = dc->ctx;
struct dc_firmware_info info;
struct dc_bios *bp;
- struct dm_pp_static_clock_info static_clk_info = {0};
ctx->dc_bios->regs = &bios_regs;
@@ -1257,11 +1256,11 @@ static bool construct(
}
}
- pool->base.dccg = dce110_dccg_create(ctx,
+ pool->base.clk_mgr = dce110_clk_mgr_create(ctx,
&disp_clk_regs,
&disp_clk_shift,
&disp_clk_mask);
- if (pool->base.dccg == NULL) {
+ if (pool->base.clk_mgr == NULL) {
dm_error("DC: failed to create display clock!\n");
BREAK_TO_DEBUGGER();
goto res_create_fail;
@@ -1287,13 +1286,6 @@ static bool construct(
goto res_create_fail;
}
- /* get static clock information for PPLIB or firmware, save
- * max_clock_state
- */
- if (dm_pp_get_static_clocks(ctx, &static_clk_info))
- pool->base.dccg->max_clks_state =
- static_clk_info.max_clocks_state;
-
{
struct irq_service_init_data init_data;
init_data.ctx = dc->ctx;
@@ -1362,7 +1354,8 @@ static bool construct(
pool->base.sw_i2cs[i] = NULL;
}
- dc->fbc_compressor = dce110_compressor_create(ctx);
+ if (dc->config.fbc_support)
+ dc->fbc_compressor = dce110_compressor_create(ctx);
if (!underlay_create(ctx, &pool->base))
goto res_create_fail;
diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c
index 3ce79c208ddf..969d4e72dc94 100644
--- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c
@@ -35,6 +35,7 @@
#include "irq/dce110/irq_service_dce110.h"
+#include "dce/dce_clk_mgr.h"
#include "dce/dce_mem_input.h"
#include "dce/dce_transform.h"
#include "dce/dce_link_encoder.h"
@@ -42,7 +43,6 @@
#include "dce/dce_audio.h"
#include "dce/dce_opp.h"
#include "dce/dce_ipp.h"
-#include "dce/dce_clocks.h"
#include "dce/dce_clock_source.h"
#include "dce/dce_hwseq.h"
@@ -148,15 +148,15 @@ static const struct dce110_timing_generator_offsets dce112_tg_offsets[] = {
.reg_name = mm ## block ## id ## _ ## reg_name
-static const struct dccg_registers disp_clk_regs = {
+static const struct clk_mgr_registers disp_clk_regs = {
CLK_COMMON_REG_LIST_DCE_BASE()
};
-static const struct dccg_shift disp_clk_shift = {
+static const struct clk_mgr_shift disp_clk_shift = {
CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT)
};
-static const struct dccg_mask disp_clk_mask = {
+static const struct clk_mgr_mask disp_clk_mask = {
CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK)
};
@@ -551,7 +551,8 @@ static struct transform *dce112_transform_create(
static const struct encoder_feature_support link_enc_feature = {
.max_hdmi_deep_color = COLOR_DEPTH_121212,
.max_hdmi_pixel_clock = 600000,
- .ycbcr420_supported = true,
+ .hdmi_ycbcr420_supported = true,
+ .dp_ycbcr420_supported = false,
.flags.bits.IS_HBR2_CAPABLE = true,
.flags.bits.IS_HBR3_CAPABLE = true,
.flags.bits.IS_TPS3_CAPABLE = true,
@@ -749,8 +750,8 @@ static void destruct(struct dce110_resource_pool *pool)
if (pool->base.dmcu != NULL)
dce_dmcu_destroy(&pool->base.dmcu);
- if (pool->base.dccg != NULL)
- dce_dccg_destroy(&pool->base.dccg);
+ if (pool->base.clk_mgr != NULL)
+ dce_clk_mgr_destroy(&pool->base.clk_mgr);
if (pool->base.irqs != NULL) {
dal_irq_service_destroy(&pool->base.irqs);
@@ -1015,12 +1016,12 @@ static void bw_calcs_data_update_from_pplib(struct dc *dc)
&clks);
dc->bw_vbios->low_yclk = bw_frc_to_fixed(
- clks.clocks_in_khz[0] * MEMORY_TYPE_MULTIPLIER, 1000);
+ clks.clocks_in_khz[0] * MEMORY_TYPE_MULTIPLIER_CZ, 1000);
dc->bw_vbios->mid_yclk = bw_frc_to_fixed(
- clks.clocks_in_khz[clks.num_levels>>1] * MEMORY_TYPE_MULTIPLIER,
+ clks.clocks_in_khz[clks.num_levels>>1] * MEMORY_TYPE_MULTIPLIER_CZ,
1000);
dc->bw_vbios->high_yclk = bw_frc_to_fixed(
- clks.clocks_in_khz[clks.num_levels-1] * MEMORY_TYPE_MULTIPLIER,
+ clks.clocks_in_khz[clks.num_levels-1] * MEMORY_TYPE_MULTIPLIER_CZ,
1000);
return;
@@ -1056,12 +1057,12 @@ static void bw_calcs_data_update_from_pplib(struct dc *dc)
* YCLK = UMACLK*m_memoryTypeMultiplier
*/
dc->bw_vbios->low_yclk = bw_frc_to_fixed(
- mem_clks.data[0].clocks_in_khz * MEMORY_TYPE_MULTIPLIER, 1000);
+ mem_clks.data[0].clocks_in_khz * MEMORY_TYPE_MULTIPLIER_CZ, 1000);
dc->bw_vbios->mid_yclk = bw_frc_to_fixed(
- mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz * MEMORY_TYPE_MULTIPLIER,
+ mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz * MEMORY_TYPE_MULTIPLIER_CZ,
1000);
dc->bw_vbios->high_yclk = bw_frc_to_fixed(
- mem_clks.data[mem_clks.num_levels-1].clocks_in_khz * MEMORY_TYPE_MULTIPLIER,
+ mem_clks.data[mem_clks.num_levels-1].clocks_in_khz * MEMORY_TYPE_MULTIPLIER_CZ,
1000);
/* Now notify PPLib/SMU about which Watermarks sets they should select
@@ -1131,7 +1132,6 @@ static bool construct(
{
unsigned int i;
struct dc_context *ctx = dc->ctx;
- struct dm_pp_static_clock_info static_clk_info = {0};
ctx->dc_bios->regs = &bios_regs;
@@ -1199,11 +1199,11 @@ static bool construct(
}
}
- pool->base.dccg = dce112_dccg_create(ctx,
+ pool->base.clk_mgr = dce112_clk_mgr_create(ctx,
&disp_clk_regs,
&disp_clk_shift,
&disp_clk_mask);
- if (pool->base.dccg == NULL) {
+ if (pool->base.clk_mgr == NULL) {
dm_error("DC: failed to create display clock!\n");
BREAK_TO_DEBUGGER();
goto res_create_fail;
@@ -1229,13 +1229,6 @@ static bool construct(
goto res_create_fail;
}
- /* get static clock information for PPLIB or firmware, save
- * max_clock_state
- */
- if (dm_pp_get_static_clocks(ctx, &static_clk_info))
- pool->base.dccg->max_clks_state =
- static_clk_info.max_clocks_state;
-
{
struct irq_service_init_data init_data;
init_data.ctx = dc->ctx;
diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c
index 79ab5f9f9115..f12696674eb0 100644
--- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c
@@ -31,6 +31,7 @@
#include "resource.h"
#include "include/irq_service_interface.h"
#include "dce120_resource.h"
+
#include "dce112/dce112_resource.h"
#include "dce110/dce110_resource.h"
@@ -39,7 +40,6 @@
#include "irq/dce120/irq_service_dce120.h"
#include "dce/dce_opp.h"
#include "dce/dce_clock_source.h"
-#include "dce/dce_clocks.h"
#include "dce/dce_ipp.h"
#include "dce/dce_mem_input.h"
@@ -47,6 +47,7 @@
#include "dce120/dce120_hw_sequencer.h"
#include "dce/dce_transform.h"
+#include "dce/dce_clk_mgr.h"
#include "dce/dce_audio.h"
#include "dce/dce_link_encoder.h"
#include "dce/dce_stream_encoder.h"
@@ -573,8 +574,8 @@ static void destruct(struct dce110_resource_pool *pool)
if (pool->base.dmcu != NULL)
dce_dmcu_destroy(&pool->base.dmcu);
- if (pool->base.dccg != NULL)
- dce_dccg_destroy(&pool->base.dccg);
+ if (pool->base.clk_mgr != NULL)
+ dce_clk_mgr_destroy(&pool->base.clk_mgr);
}
static void read_dce_straps(
@@ -606,7 +607,8 @@ static struct audio *create_audio(
static const struct encoder_feature_support link_enc_feature = {
.max_hdmi_deep_color = COLOR_DEPTH_121212,
.max_hdmi_pixel_clock = 600000,
- .ycbcr420_supported = true,
+ .hdmi_ycbcr420_supported = true,
+ .dp_ycbcr420_supported = false,
.flags.bits.IS_HBR2_CAPABLE = true,
.flags.bits.IS_HBR3_CAPABLE = true,
.flags.bits.IS_TPS3_CAPABLE = true,
@@ -834,12 +836,12 @@ static void bw_calcs_data_update_from_pplib(struct dc *dc)
* YCLK = UMACLK*m_memoryTypeMultiplier
*/
dc->bw_vbios->low_yclk = bw_frc_to_fixed(
- mem_clks.data[0].clocks_in_khz * MEMORY_TYPE_MULTIPLIER, 1000);
+ mem_clks.data[0].clocks_in_khz * MEMORY_TYPE_MULTIPLIER_CZ, 1000);
dc->bw_vbios->mid_yclk = bw_frc_to_fixed(
- mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz * MEMORY_TYPE_MULTIPLIER,
+ mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz * MEMORY_TYPE_MULTIPLIER_CZ,
1000);
dc->bw_vbios->high_yclk = bw_frc_to_fixed(
- mem_clks.data[mem_clks.num_levels-1].clocks_in_khz * MEMORY_TYPE_MULTIPLIER,
+ mem_clks.data[mem_clks.num_levels-1].clocks_in_khz * MEMORY_TYPE_MULTIPLIER_CZ,
1000);
/* Now notify PPLib/SMU about which Watermarks sets they should select
@@ -973,8 +975,8 @@ static bool construct(
}
}
- pool->base.dccg = dce120_dccg_create(ctx);
- if (pool->base.dccg == NULL) {
+ pool->base.clk_mgr = dce120_clk_mgr_create(ctx);
+ if (pool->base.clk_mgr == NULL) {
dm_error("DC: failed to create display clock!\n");
BREAK_TO_DEBUGGER();
goto dccg_create_fail;
diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_hw_sequencer.c
index 6c6a1a16af19..a60a90e68d91 100644
--- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_hw_sequencer.c
+++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_hw_sequencer.c
@@ -76,6 +76,7 @@ void dce80_hw_sequencer_construct(struct dc *dc)
dc->hwss.enable_display_power_gating = dce100_enable_display_power_gating;
dc->hwss.pipe_control_lock = dce_pipe_control_lock;
- dc->hwss.set_bandwidth = dce100_set_bandwidth;
+ dc->hwss.prepare_bandwidth = dce100_prepare_bandwidth;
+ dc->hwss.optimize_bandwidth = dce100_prepare_bandwidth;
}
diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c
index d68f951f9869..6d40b3d54ac1 100644
--- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c
@@ -37,6 +37,7 @@
#include "dce110/dce110_timing_generator.h"
#include "dce110/dce110_resource.h"
#include "dce80/dce80_timing_generator.h"
+#include "dce/dce_clk_mgr.h"
#include "dce/dce_mem_input.h"
#include "dce/dce_link_encoder.h"
#include "dce/dce_stream_encoder.h"
@@ -44,7 +45,6 @@
#include "dce/dce_ipp.h"
#include "dce/dce_transform.h"
#include "dce/dce_opp.h"
-#include "dce/dce_clocks.h"
#include "dce/dce_clock_source.h"
#include "dce/dce_audio.h"
#include "dce/dce_hwseq.h"
@@ -155,15 +155,15 @@ static const struct dce110_timing_generator_offsets dce80_tg_offsets[] = {
.reg_name = mm ## block ## id ## _ ## reg_name
-static const struct dccg_registers disp_clk_regs = {
+static const struct clk_mgr_registers disp_clk_regs = {
CLK_COMMON_REG_LIST_DCE_BASE()
};
-static const struct dccg_shift disp_clk_shift = {
+static const struct clk_mgr_shift disp_clk_shift = {
CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT)
};
-static const struct dccg_mask disp_clk_mask = {
+static const struct clk_mgr_mask disp_clk_mask = {
CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK)
};
@@ -779,8 +779,8 @@ static void destruct(struct dce110_resource_pool *pool)
}
}
- if (pool->base.dccg != NULL)
- dce_dccg_destroy(&pool->base.dccg);
+ if (pool->base.clk_mgr != NULL)
+ dce_clk_mgr_destroy(&pool->base.clk_mgr);
if (pool->base.irqs != NULL) {
dal_irq_service_destroy(&pool->base.irqs);
@@ -793,7 +793,7 @@ bool dce80_validate_bandwidth(
{
/* TODO implement when needed but for now hardcode max value*/
context->bw.dce.dispclk_khz = 681000;
- context->bw.dce.yclk_khz = 250000 * MEMORY_TYPE_MULTIPLIER;
+ context->bw.dce.yclk_khz = 250000 * MEMORY_TYPE_MULTIPLIER_CZ;
return true;
}
@@ -855,7 +855,6 @@ static bool dce80_construct(
struct dc_context *ctx = dc->ctx;
struct dc_firmware_info info;
struct dc_bios *bp;
- struct dm_pp_static_clock_info static_clk_info = {0};
ctx->dc_bios->regs = &bios_regs;
@@ -918,11 +917,11 @@ static bool dce80_construct(
}
}
- pool->base.dccg = dce_dccg_create(ctx,
+ pool->base.clk_mgr = dce_clk_mgr_create(ctx,
&disp_clk_regs,
&disp_clk_shift,
&disp_clk_mask);
- if (pool->base.dccg == NULL) {
+ if (pool->base.clk_mgr == NULL) {
dm_error("DC: failed to create display clock!\n");
BREAK_TO_DEBUGGER();
goto res_create_fail;
@@ -948,10 +947,6 @@ static bool dce80_construct(
goto res_create_fail;
}
- if (dm_pp_get_static_clocks(ctx, &static_clk_info))
- pool->base.dccg->max_clks_state =
- static_clk_info.max_clocks_state;
-
{
struct irq_service_init_data init_data;
init_data.ctx = dc->ctx;
@@ -1065,7 +1060,6 @@ static bool dce81_construct(
struct dc_context *ctx = dc->ctx;
struct dc_firmware_info info;
struct dc_bios *bp;
- struct dm_pp_static_clock_info static_clk_info = {0};
ctx->dc_bios->regs = &bios_regs;
@@ -1128,11 +1122,11 @@ static bool dce81_construct(
}
}
- pool->base.dccg = dce_dccg_create(ctx,
+ pool->base.clk_mgr = dce_clk_mgr_create(ctx,
&disp_clk_regs,
&disp_clk_shift,
&disp_clk_mask);
- if (pool->base.dccg == NULL) {
+ if (pool->base.clk_mgr == NULL) {
dm_error("DC: failed to create display clock!\n");
BREAK_TO_DEBUGGER();
goto res_create_fail;
@@ -1158,10 +1152,6 @@ static bool dce81_construct(
goto res_create_fail;
}
- if (dm_pp_get_static_clocks(ctx, &static_clk_info))
- pool->base.dccg->max_clks_state =
- static_clk_info.max_clocks_state;
-
{
struct irq_service_init_data init_data;
init_data.ctx = dc->ctx;
@@ -1275,7 +1265,6 @@ static bool dce83_construct(
struct dc_context *ctx = dc->ctx;
struct dc_firmware_info info;
struct dc_bios *bp;
- struct dm_pp_static_clock_info static_clk_info = {0};
ctx->dc_bios->regs = &bios_regs;
@@ -1334,11 +1323,11 @@ static bool dce83_construct(
}
}
- pool->base.dccg = dce_dccg_create(ctx,
+ pool->base.clk_mgr = dce_clk_mgr_create(ctx,
&disp_clk_regs,
&disp_clk_shift,
&disp_clk_mask);
- if (pool->base.dccg == NULL) {
+ if (pool->base.clk_mgr == NULL) {
dm_error("DC: failed to create display clock!\n");
BREAK_TO_DEBUGGER();
goto res_create_fail;
@@ -1364,10 +1353,6 @@ static bool dce83_construct(
goto res_create_fail;
}
- if (dm_pp_get_static_clocks(ctx, &static_clk_info))
- pool->base.dccg->max_clks_state =
- static_clk_info.max_clocks_state;
-
{
struct irq_service_init_data init_data;
init_data.ctx = dc->ctx;
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/Makefile b/drivers/gpu/drm/amd/display/dc/dcn10/Makefile
index 032f872be89c..55f293c8a3c0 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/Makefile
@@ -24,7 +24,7 @@
DCN10 = dcn10_resource.o dcn10_ipp.o dcn10_hw_sequencer.o dcn10_hw_sequencer_debug.o \
dcn10_dpp.o dcn10_opp.o dcn10_optc.o \
- dcn10_hubp.o dcn10_mpc.o \
+ dcn10_hubp.o dcn10_mpc.o dcn10_clk_mgr.o \
dcn10_dpp_dscl.o dcn10_dpp_cm.o dcn10_cm_common.o \
dcn10_hubbub.o dcn10_stream_encoder.o dcn10_link_encoder.o
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.c
new file mode 100644
index 000000000000..20f531d27e2b
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.c
@@ -0,0 +1,379 @@
+/*
+ * Copyright 2018 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.
+ *
+ * Authors: AMD
+ *
+ */
+
+#include "dcn10_clk_mgr.h"
+
+#include "reg_helper.h"
+#include "core_types.h"
+
+#define TO_DCE_CLK_MGR(clocks)\
+ container_of(clocks, struct dce_clk_mgr, base)
+
+#define REG(reg) \
+ (clk_mgr_dce->regs->reg)
+
+#undef FN
+#define FN(reg_name, field_name) \
+ clk_mgr_dce->clk_mgr_shift->field_name, clk_mgr_dce->clk_mgr_mask->field_name
+
+#define CTX \
+ clk_mgr_dce->base.ctx
+#define DC_LOGGER \
+ clk_mgr->ctx->logger
+
+void dcn1_pplib_apply_display_requirements(
+ struct dc *dc,
+ struct dc_state *context)
+{
+ struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg;
+
+ pp_display_cfg->min_engine_clock_khz = dc->res_pool->clk_mgr->clks.dcfclk_khz;
+ pp_display_cfg->min_memory_clock_khz = dc->res_pool->clk_mgr->clks.fclk_khz;
+ pp_display_cfg->min_engine_clock_deep_sleep_khz = dc->res_pool->clk_mgr->clks.dcfclk_deep_sleep_khz;
+ pp_display_cfg->min_dcfc_deep_sleep_clock_khz = dc->res_pool->clk_mgr->clks.dcfclk_deep_sleep_khz;
+ pp_display_cfg->min_dcfclock_khz = dc->res_pool->clk_mgr->clks.dcfclk_khz;
+ pp_display_cfg->disp_clk_khz = dc->res_pool->clk_mgr->clks.dispclk_khz;
+ dce110_fill_display_configs(context, pp_display_cfg);
+
+ dm_pp_apply_display_requirements(dc->ctx, pp_display_cfg);
+}
+
+static int dcn1_determine_dppclk_threshold(struct clk_mgr *clk_mgr, struct dc_clocks *new_clocks)
+{
+ bool request_dpp_div = new_clocks->dispclk_khz > new_clocks->dppclk_khz;
+ bool dispclk_increase = new_clocks->dispclk_khz > clk_mgr->clks.dispclk_khz;
+ int disp_clk_threshold = new_clocks->max_supported_dppclk_khz;
+ bool cur_dpp_div = clk_mgr->clks.dispclk_khz > clk_mgr->clks.dppclk_khz;
+
+ /* increase clock, looking for div is 0 for current, request div is 1*/
+ if (dispclk_increase) {
+ /* already divided by 2, no need to reach target clk with 2 steps*/
+ if (cur_dpp_div)
+ return new_clocks->dispclk_khz;
+
+ /* request disp clk is lower than maximum supported dpp clk,
+ * no need to reach target clk with two steps.
+ */
+ if (new_clocks->dispclk_khz <= disp_clk_threshold)
+ return new_clocks->dispclk_khz;
+
+ /* target dpp clk not request divided by 2, still within threshold */
+ if (!request_dpp_div)
+ return new_clocks->dispclk_khz;
+
+ } else {
+ /* decrease clock, looking for current dppclk divided by 2,
+ * request dppclk not divided by 2.
+ */
+
+ /* current dpp clk not divided by 2, no need to ramp*/
+ if (!cur_dpp_div)
+ return new_clocks->dispclk_khz;
+
+ /* current disp clk is lower than current maximum dpp clk,
+ * no need to ramp
+ */
+ if (clk_mgr->clks.dispclk_khz <= disp_clk_threshold)
+ return new_clocks->dispclk_khz;
+
+ /* request dpp clk need to be divided by 2 */
+ if (request_dpp_div)
+ return new_clocks->dispclk_khz;
+ }
+
+ return disp_clk_threshold;
+}
+
+static void dcn1_ramp_up_dispclk_with_dpp(struct clk_mgr *clk_mgr, struct dc_clocks *new_clocks)
+{
+ struct dc *dc = clk_mgr->ctx->dc;
+ int dispclk_to_dpp_threshold = dcn1_determine_dppclk_threshold(clk_mgr, new_clocks);
+ bool request_dpp_div = new_clocks->dispclk_khz > new_clocks->dppclk_khz;
+ int i;
+
+ /* set disp clk to dpp clk threshold */
+ dce112_set_clock(clk_mgr, dispclk_to_dpp_threshold);
+
+ /* update request dpp clk division option */
+ for (i = 0; i < dc->res_pool->pipe_count; i++) {
+ struct pipe_ctx *pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
+
+ if (!pipe_ctx->plane_state)
+ continue;
+
+ pipe_ctx->plane_res.dpp->funcs->dpp_dppclk_control(
+ pipe_ctx->plane_res.dpp,
+ request_dpp_div,
+ true);
+ }
+
+ /* If target clk not same as dppclk threshold, set to target clock */
+ if (dispclk_to_dpp_threshold != new_clocks->dispclk_khz)
+ dce112_set_clock(clk_mgr, new_clocks->dispclk_khz);
+
+ clk_mgr->clks.dispclk_khz = new_clocks->dispclk_khz;
+ clk_mgr->clks.dppclk_khz = new_clocks->dppclk_khz;
+ clk_mgr->clks.max_supported_dppclk_khz = new_clocks->max_supported_dppclk_khz;
+}
+
+static int get_active_display_cnt(
+ struct dc *dc,
+ struct dc_state *context)
+{
+ int i, display_count;
+
+ display_count = 0;
+ for (i = 0; i < context->stream_count; i++) {
+ const struct dc_stream_state *stream = context->streams[i];
+
+ /*
+ * Only notify active stream or virtual stream.
+ * Need to notify virtual stream to work around
+ * headless case. HPD does not fire when system is in
+ * S0i2.
+ */
+ if (!stream->dpms_off || stream->signal == SIGNAL_TYPE_VIRTUAL)
+ display_count++;
+ }
+
+ return display_count;
+}
+
+static void notify_deep_sleep_dcfclk_to_smu(
+ struct pp_smu_funcs_rv *pp_smu, int min_dcef_deep_sleep_clk_khz)
+{
+ int min_dcef_deep_sleep_clk_mhz; //minimum required DCEF Deep Sleep clock in mhz
+ /*
+ * if function pointer not set up, this message is
+ * sent as part of pplib_apply_display_requirements.
+ * So just return.
+ */
+ if (!pp_smu || !pp_smu->set_min_deep_sleep_dcfclk)
+ return;
+
+ min_dcef_deep_sleep_clk_mhz = (min_dcef_deep_sleep_clk_khz + 999) / 1000; //Round up
+ pp_smu->set_min_deep_sleep_dcfclk(&pp_smu->pp_smu, min_dcef_deep_sleep_clk_mhz);
+}
+
+static void notify_hard_min_dcfclk_to_smu(
+ struct pp_smu_funcs_rv *pp_smu, int min_dcf_clk_khz)
+{
+ int min_dcf_clk_mhz; //minimum required DCF clock in mhz
+
+ /*
+ * if function pointer not set up, this message is
+ * sent as part of pplib_apply_display_requirements.
+ * So just return.
+ */
+ if (!pp_smu || !pp_smu->set_hard_min_dcfclk_by_freq)
+ return;
+
+ min_dcf_clk_mhz = min_dcf_clk_khz / 1000;
+
+ pp_smu->set_hard_min_dcfclk_by_freq(&pp_smu->pp_smu, min_dcf_clk_mhz);
+}
+
+static void notify_hard_min_fclk_to_smu(
+ struct pp_smu_funcs_rv *pp_smu, int min_f_clk_khz)
+{
+ int min_f_clk_mhz; //minimum required F clock in mhz
+
+ /*
+ * if function pointer not set up, this message is
+ * sent as part of pplib_apply_display_requirements.
+ * So just return.
+ */
+ if (!pp_smu || !pp_smu->set_hard_min_fclk_by_freq)
+ return;
+
+ min_f_clk_mhz = min_f_clk_khz / 1000;
+
+ pp_smu->set_hard_min_fclk_by_freq(&pp_smu->pp_smu, min_f_clk_mhz);
+}
+
+static void dcn1_update_clocks(struct clk_mgr *clk_mgr,
+ struct dc_state *context,
+ bool safe_to_lower)
+{
+ struct dc *dc = clk_mgr->ctx->dc;
+ struct dc_clocks *new_clocks = &context->bw.dcn.clk;
+ struct pp_smu_display_requirement_rv *smu_req_cur =
+ &dc->res_pool->pp_smu_req;
+ struct pp_smu_display_requirement_rv smu_req = *smu_req_cur;
+ struct pp_smu_funcs_rv *pp_smu = dc->res_pool->pp_smu;
+ struct dm_pp_clock_for_voltage_req clock_voltage_req = {0};
+ bool send_request_to_increase = false;
+ bool send_request_to_lower = false;
+ int display_count;
+
+ bool enter_display_off = false;
+
+ display_count = get_active_display_cnt(dc, context);
+
+ if (display_count == 0)
+ enter_display_off = true;
+
+ if (enter_display_off == safe_to_lower) {
+ /*
+ * Notify SMU active displays
+ * if function pointer not set up, this message is
+ * sent as part of pplib_apply_display_requirements.
+ */
+ if (pp_smu->set_display_count)
+ pp_smu->set_display_count(&pp_smu->pp_smu, display_count);
+ else
+ smu_req.display_count = display_count;
+
+ }
+
+ if (new_clocks->dispclk_khz > clk_mgr->clks.dispclk_khz
+ || new_clocks->phyclk_khz > clk_mgr->clks.phyclk_khz
+ || new_clocks->fclk_khz > clk_mgr->clks.fclk_khz
+ || new_clocks->dcfclk_khz > clk_mgr->clks.dcfclk_khz)
+ send_request_to_increase = true;
+
+ if (should_set_clock(safe_to_lower, new_clocks->phyclk_khz, clk_mgr->clks.phyclk_khz)) {
+ clk_mgr->clks.phyclk_khz = new_clocks->phyclk_khz;
+
+ send_request_to_lower = true;
+ }
+
+ // F Clock
+ if (should_set_clock(safe_to_lower, new_clocks->fclk_khz, clk_mgr->clks.fclk_khz)) {
+ clk_mgr->clks.fclk_khz = new_clocks->fclk_khz;
+ clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_FCLK;
+ clock_voltage_req.clocks_in_khz = new_clocks->fclk_khz;
+ smu_req.hard_min_fclk_mhz = new_clocks->fclk_khz / 1000;
+
+ notify_hard_min_fclk_to_smu(pp_smu, new_clocks->fclk_khz);
+
+ send_request_to_lower = true;
+ }
+
+ //DCF Clock
+ if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, clk_mgr->clks.dcfclk_khz)) {
+ clk_mgr->clks.dcfclk_khz = new_clocks->dcfclk_khz;
+ smu_req.hard_min_dcefclk_mhz = new_clocks->dcfclk_khz / 1000;
+
+ send_request_to_lower = true;
+ }
+
+ if (should_set_clock(safe_to_lower,
+ new_clocks->dcfclk_deep_sleep_khz, clk_mgr->clks.dcfclk_deep_sleep_khz)) {
+ clk_mgr->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz;
+ smu_req.min_deep_sleep_dcefclk_mhz = new_clocks->dcfclk_deep_sleep_khz / 1000;
+
+ send_request_to_lower = true;
+ }
+
+ /* make sure dcf clk is before dpp clk to
+ * make sure we have enough voltage to run dpp clk
+ */
+ if (send_request_to_increase) {
+ /*use dcfclk to request voltage*/
+ clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DCFCLK;
+ clock_voltage_req.clocks_in_khz = dcn_find_dcfclk_suits_all(dc, new_clocks);
+
+ notify_hard_min_dcfclk_to_smu(pp_smu, clock_voltage_req.clocks_in_khz);
+
+ if (pp_smu->set_display_requirement)
+ pp_smu->set_display_requirement(&pp_smu->pp_smu, &smu_req);
+
+ notify_deep_sleep_dcfclk_to_smu(pp_smu, clk_mgr->clks.dcfclk_deep_sleep_khz);
+ dcn1_pplib_apply_display_requirements(dc, context);
+ }
+
+ /* dcn1 dppclk is tied to dispclk */
+ /* program dispclk on = as a w/a for sleep resume clock ramping issues */
+ if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr->clks.dispclk_khz)
+ || new_clocks->dispclk_khz == clk_mgr->clks.dispclk_khz) {
+ dcn1_ramp_up_dispclk_with_dpp(clk_mgr, new_clocks);
+ clk_mgr->clks.dispclk_khz = new_clocks->dispclk_khz;
+
+ send_request_to_lower = true;
+ }
+
+ if (!send_request_to_increase && send_request_to_lower) {
+ /*use dcfclk to request voltage*/
+ clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DCFCLK;
+ clock_voltage_req.clocks_in_khz = dcn_find_dcfclk_suits_all(dc, new_clocks);
+
+ notify_hard_min_dcfclk_to_smu(pp_smu, clock_voltage_req.clocks_in_khz);
+
+ if (pp_smu->set_display_requirement)
+ pp_smu->set_display_requirement(&pp_smu->pp_smu, &smu_req);
+
+ notify_deep_sleep_dcfclk_to_smu(pp_smu, clk_mgr->clks.dcfclk_deep_sleep_khz);
+ dcn1_pplib_apply_display_requirements(dc, context);
+ }
+
+
+ *smu_req_cur = smu_req;
+}
+
+static const struct clk_mgr_funcs dcn1_funcs = {
+ .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
+ .update_clocks = dcn1_update_clocks
+};
+
+struct clk_mgr *dcn1_clk_mgr_create(struct dc_context *ctx)
+{
+ struct dc_debug_options *debug = &ctx->dc->debug;
+ struct dc_bios *bp = ctx->dc_bios;
+ struct dc_firmware_info fw_info = { { 0 } };
+ struct dce_clk_mgr *clk_mgr_dce = kzalloc(sizeof(*clk_mgr_dce), GFP_KERNEL);
+
+ if (clk_mgr_dce == NULL) {
+ BREAK_TO_DEBUGGER();
+ return NULL;
+ }
+
+ clk_mgr_dce->base.ctx = ctx;
+ clk_mgr_dce->base.funcs = &dcn1_funcs;
+
+ clk_mgr_dce->dfs_bypass_disp_clk = 0;
+
+ clk_mgr_dce->dprefclk_ss_percentage = 0;
+ clk_mgr_dce->dprefclk_ss_divider = 1000;
+ clk_mgr_dce->ss_on_dprefclk = false;
+
+ clk_mgr_dce->dprefclk_khz = 600000;
+ if (bp->integrated_info)
+ clk_mgr_dce->dentist_vco_freq_khz = bp->integrated_info->dentist_vco_freq;
+ if (clk_mgr_dce->dentist_vco_freq_khz == 0) {
+ bp->funcs->get_firmware_info(bp, &fw_info);
+ clk_mgr_dce->dentist_vco_freq_khz = fw_info.smu_gpu_pll_output_freq;
+ if (clk_mgr_dce->dentist_vco_freq_khz == 0)
+ clk_mgr_dce->dentist_vco_freq_khz = 3600000;
+ }
+
+ if (!debug->disable_dfs_bypass && bp->integrated_info)
+ if (bp->integrated_info->gpu_cap_info & DFS_BYPASS_ENABLE)
+ clk_mgr_dce->dfs_bypass_enabled = true;
+
+ dce_clock_read_ss_info(clk_mgr_dce);
+
+ return &clk_mgr_dce->base;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.h
new file mode 100644
index 000000000000..9dbaf6578006
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2018 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.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DCN10_CLK_MGR_H__
+#define __DCN10_CLK_MGR_H__
+
+#include "../dce/dce_clk_mgr.h"
+
+void dcn1_pplib_apply_display_requirements(
+ struct dc *dc,
+ struct dc_state *context);
+
+struct clk_mgr *dcn1_clk_mgr_create(struct dc_context *ctx);
+
+#endif //__DCN10_CLK_MGR_H__
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c
index 5d95a997fd9f..3eea44092a04 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c
@@ -71,39 +71,39 @@ void cm_helper_program_xfer_func(
unsigned int i = 0;
REG_SET_2(reg->start_cntl_b, 0,
- exp_region_start, params->arr_points[0].custom_float_x,
+ exp_region_start, params->corner_points[0].blue.custom_float_x,
exp_resion_start_segment, 0);
REG_SET_2(reg->start_cntl_g, 0,
- exp_region_start, params->arr_points[0].custom_float_x,
+ exp_region_start, params->corner_points[0].green.custom_float_x,
exp_resion_start_segment, 0);
REG_SET_2(reg->start_cntl_r, 0,
- exp_region_start, params->arr_points[0].custom_float_x,
+ exp_region_start, params->corner_points[0].red.custom_float_x,
exp_resion_start_segment, 0);
REG_SET(reg->start_slope_cntl_b, 0,
- field_region_linear_slope, params->arr_points[0].custom_float_slope);
+ field_region_linear_slope, params->corner_points[0].blue.custom_float_slope);
REG_SET(reg->start_slope_cntl_g, 0,
- field_region_linear_slope, params->arr_points[0].custom_float_slope);
+ field_region_linear_slope, params->corner_points[0].green.custom_float_slope);
REG_SET(reg->start_slope_cntl_r, 0,
- field_region_linear_slope, params->arr_points[0].custom_float_slope);
+ field_region_linear_slope, params->corner_points[0].red.custom_float_slope);
REG_SET(reg->start_end_cntl1_b, 0,
- field_region_end, params->arr_points[1].custom_float_x);
+ field_region_end, params->corner_points[1].blue.custom_float_x);
REG_SET_2(reg->start_end_cntl2_b, 0,
- field_region_end_slope, params->arr_points[1].custom_float_slope,
- field_region_end_base, params->arr_points[1].custom_float_y);
+ field_region_end_slope, params->corner_points[1].blue.custom_float_slope,
+ field_region_end_base, params->corner_points[1].blue.custom_float_y);
REG_SET(reg->start_end_cntl1_g, 0,
- field_region_end, params->arr_points[1].custom_float_x);
+ field_region_end, params->corner_points[1].green.custom_float_x);
REG_SET_2(reg->start_end_cntl2_g, 0,
- field_region_end_slope, params->arr_points[1].custom_float_slope,
- field_region_end_base, params->arr_points[1].custom_float_y);
+ field_region_end_slope, params->corner_points[1].green.custom_float_slope,
+ field_region_end_base, params->corner_points[1].green.custom_float_y);
REG_SET(reg->start_end_cntl1_r, 0,
- field_region_end, params->arr_points[1].custom_float_x);
+ field_region_end, params->corner_points[1].red.custom_float_x);
REG_SET_2(reg->start_end_cntl2_r, 0,
- field_region_end_slope, params->arr_points[1].custom_float_slope,
- field_region_end_base, params->arr_points[1].custom_float_y);
+ field_region_end_slope, params->corner_points[1].red.custom_float_slope,
+ field_region_end_base, params->corner_points[1].red.custom_float_y);
for (reg_region_cur = reg->region_start;
reg_region_cur <= reg->region_end;
@@ -127,7 +127,7 @@ void cm_helper_program_xfer_func(
bool cm_helper_convert_to_custom_float(
struct pwl_result_data *rgb_resulted,
- struct curve_points *arr_points,
+ struct curve_points3 *corner_points,
uint32_t hw_points_num,
bool fixpoint)
{
@@ -141,20 +141,53 @@ bool cm_helper_convert_to_custom_float(
fmt.mantissa_bits = 12;
fmt.sign = false;
- if (!convert_to_custom_float_format(arr_points[0].x, &fmt,
- &arr_points[0].custom_float_x)) {
+ /* corner_points[0] - beginning base, slope offset for R,G,B
+ * corner_points[1] - end base, slope offset for R,G,B
+ */
+ if (!convert_to_custom_float_format(corner_points[0].red.x, &fmt,
+ &corner_points[0].red.custom_float_x)) {
+ BREAK_TO_DEBUGGER();
+ return false;
+ }
+ if (!convert_to_custom_float_format(corner_points[0].green.x, &fmt,
+ &corner_points[0].green.custom_float_x)) {
+ BREAK_TO_DEBUGGER();
+ return false;
+ }
+ if (!convert_to_custom_float_format(corner_points[0].blue.x, &fmt,
+ &corner_points[0].blue.custom_float_x)) {
BREAK_TO_DEBUGGER();
return false;
}
- if (!convert_to_custom_float_format(arr_points[0].offset, &fmt,
- &arr_points[0].custom_float_offset)) {
+ if (!convert_to_custom_float_format(corner_points[0].red.offset, &fmt,
+ &corner_points[0].red.custom_float_offset)) {
+ BREAK_TO_DEBUGGER();
+ return false;
+ }
+ if (!convert_to_custom_float_format(corner_points[0].green.offset, &fmt,
+ &corner_points[0].green.custom_float_offset)) {
+ BREAK_TO_DEBUGGER();
+ return false;
+ }
+ if (!convert_to_custom_float_format(corner_points[0].blue.offset, &fmt,
+ &corner_points[0].blue.custom_float_offset)) {
BREAK_TO_DEBUGGER();
return false;
}
- if (!convert_to_custom_float_format(arr_points[0].slope, &fmt,
- &arr_points[0].custom_float_slope)) {
+ if (!convert_to_custom_float_format(corner_points[0].red.slope, &fmt,
+ &corner_points[0].red.custom_float_slope)) {
+ BREAK_TO_DEBUGGER();
+ return false;
+ }
+ if (!convert_to_custom_float_format(corner_points[0].green.slope, &fmt,
+ &corner_points[0].green.custom_float_slope)) {
+ BREAK_TO_DEBUGGER();
+ return false;
+ }
+ if (!convert_to_custom_float_format(corner_points[0].blue.slope, &fmt,
+ &corner_points[0].blue.custom_float_slope)) {
BREAK_TO_DEBUGGER();
return false;
}
@@ -162,22 +195,59 @@ bool cm_helper_convert_to_custom_float(
fmt.mantissa_bits = 10;
fmt.sign = false;
- if (!convert_to_custom_float_format(arr_points[1].x, &fmt,
- &arr_points[1].custom_float_x)) {
+ if (!convert_to_custom_float_format(corner_points[1].red.x, &fmt,
+ &corner_points[1].red.custom_float_x)) {
BREAK_TO_DEBUGGER();
return false;
}
-
- if (fixpoint == true)
- arr_points[1].custom_float_y = dc_fixpt_clamp_u0d14(arr_points[1].y);
- else if (!convert_to_custom_float_format(arr_points[1].y, &fmt,
- &arr_points[1].custom_float_y)) {
+ if (!convert_to_custom_float_format(corner_points[1].green.x, &fmt,
+ &corner_points[1].green.custom_float_x)) {
+ BREAK_TO_DEBUGGER();
+ return false;
+ }
+ if (!convert_to_custom_float_format(corner_points[1].blue.x, &fmt,
+ &corner_points[1].blue.custom_float_x)) {
BREAK_TO_DEBUGGER();
return false;
}
- if (!convert_to_custom_float_format(arr_points[1].slope, &fmt,
- &arr_points[1].custom_float_slope)) {
+ if (fixpoint == true) {
+ corner_points[1].red.custom_float_y =
+ dc_fixpt_clamp_u0d14(corner_points[1].red.y);
+ corner_points[1].green.custom_float_y =
+ dc_fixpt_clamp_u0d14(corner_points[1].green.y);
+ corner_points[1].blue.custom_float_y =
+ dc_fixpt_clamp_u0d14(corner_points[1].blue.y);
+ } else {
+ if (!convert_to_custom_float_format(corner_points[1].red.y,
+ &fmt, &corner_points[1].red.custom_float_y)) {
+ BREAK_TO_DEBUGGER();
+ return false;
+ }
+ if (!convert_to_custom_float_format(corner_points[1].green.y,
+ &fmt, &corner_points[1].green.custom_float_y)) {
+ BREAK_TO_DEBUGGER();
+ return false;
+ }
+ if (!convert_to_custom_float_format(corner_points[1].blue.y,
+ &fmt, &corner_points[1].blue.custom_float_y)) {
+ BREAK_TO_DEBUGGER();
+ return false;
+ }
+ }
+
+ if (!convert_to_custom_float_format(corner_points[1].red.slope, &fmt,
+ &corner_points[1].red.custom_float_slope)) {
+ BREAK_TO_DEBUGGER();
+ return false;
+ }
+ if (!convert_to_custom_float_format(corner_points[1].green.slope, &fmt,
+ &corner_points[1].green.custom_float_slope)) {
+ BREAK_TO_DEBUGGER();
+ return false;
+ }
+ if (!convert_to_custom_float_format(corner_points[1].blue.slope, &fmt,
+ &corner_points[1].blue.custom_float_slope)) {
BREAK_TO_DEBUGGER();
return false;
}
@@ -242,15 +312,10 @@ bool cm_helper_translate_curve_to_hw_format(
const struct dc_transfer_func *output_tf,
struct pwl_params *lut_params, bool fixpoint)
{
- struct curve_points *arr_points;
+ struct curve_points3 *corner_points;
struct pwl_result_data *rgb_resulted;
struct pwl_result_data *rgb;
struct pwl_result_data *rgb_plus_1;
- struct fixed31_32 y_r;
- struct fixed31_32 y_g;
- struct fixed31_32 y_b;
- struct fixed31_32 y1_min;
- struct fixed31_32 y3_max;
int32_t region_start, region_end;
int32_t i;
@@ -261,14 +326,14 @@ bool cm_helper_translate_curve_to_hw_format(
PERF_TRACE();
- arr_points = lut_params->arr_points;
+ corner_points = lut_params->corner_points;
rgb_resulted = lut_params->rgb_resulted;
hw_points = 0;
memset(lut_params, 0, sizeof(struct pwl_params));
memset(seg_distr, 0, sizeof(seg_distr));
- if (output_tf->tf == TRANSFER_FUNCTION_PQ) {
+ if (output_tf->tf == TRANSFER_FUNCTION_PQ || output_tf->tf == TRANSFER_FUNCTION_GAMMA22) {
/* 32 segments
* segments are from 2^-25 to 2^7
*/
@@ -327,31 +392,37 @@ bool cm_helper_translate_curve_to_hw_format(
rgb_resulted[hw_points - 1].green = output_tf->tf_pts.green[start_index];
rgb_resulted[hw_points - 1].blue = output_tf->tf_pts.blue[start_index];
- arr_points[0].x = dc_fixpt_pow(dc_fixpt_from_int(2),
+ // All 3 color channels have same x
+ corner_points[0].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),
dc_fixpt_from_int(region_start));
- arr_points[1].x = dc_fixpt_pow(dc_fixpt_from_int(2),
- dc_fixpt_from_int(region_end));
+ corner_points[0].green.x = corner_points[0].red.x;
+ corner_points[0].blue.x = corner_points[0].red.x;
- y_r = rgb_resulted[0].red;
- y_g = rgb_resulted[0].green;
- y_b = rgb_resulted[0].blue;
+ corner_points[1].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),
+ dc_fixpt_from_int(region_end));
+ corner_points[1].green.x = corner_points[1].red.x;
+ corner_points[1].blue.x = corner_points[1].red.x;
- y1_min = dc_fixpt_min(y_r, dc_fixpt_min(y_g, y_b));
+ corner_points[0].red.y = rgb_resulted[0].red;
+ corner_points[0].green.y = rgb_resulted[0].green;
+ corner_points[0].blue.y = rgb_resulted[0].blue;
- arr_points[0].y = y1_min;
- arr_points[0].slope = dc_fixpt_div(arr_points[0].y, arr_points[0].x);
- y_r = rgb_resulted[hw_points - 1].red;
- y_g = rgb_resulted[hw_points - 1].green;
- y_b = rgb_resulted[hw_points - 1].blue;
+ corner_points[0].red.slope = dc_fixpt_div(corner_points[0].red.y,
+ corner_points[0].red.x);
+ corner_points[0].green.slope = dc_fixpt_div(corner_points[0].green.y,
+ corner_points[0].green.x);
+ corner_points[0].blue.slope = dc_fixpt_div(corner_points[0].blue.y,
+ corner_points[0].blue.x);
/* see comment above, m_arrPoints[1].y should be the Y value for the
* region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1)
*/
- y3_max = dc_fixpt_max(y_r, dc_fixpt_max(y_g, y_b));
-
- arr_points[1].y = y3_max;
-
- arr_points[1].slope = dc_fixpt_zero;
+ corner_points[1].red.y = rgb_resulted[hw_points - 1].red;
+ corner_points[1].green.y = rgb_resulted[hw_points - 1].green;
+ corner_points[1].blue.y = rgb_resulted[hw_points - 1].blue;
+ corner_points[1].red.slope = dc_fixpt_zero;
+ corner_points[1].green.slope = dc_fixpt_zero;
+ corner_points[1].blue.slope = dc_fixpt_zero;
if (output_tf->tf == TRANSFER_FUNCTION_PQ) {
/* for PQ, we want to have a straight line from last HW X point,
@@ -360,9 +431,15 @@ bool cm_helper_translate_curve_to_hw_format(
const struct fixed31_32 end_value =
dc_fixpt_from_int(125);
- arr_points[1].slope = dc_fixpt_div(
- dc_fixpt_sub(dc_fixpt_one, arr_points[1].y),
- dc_fixpt_sub(end_value, arr_points[1].x));
+ corner_points[1].red.slope = dc_fixpt_div(
+ dc_fixpt_sub(dc_fixpt_one, corner_points[1].red.y),
+ dc_fixpt_sub(end_value, corner_points[1].red.x));
+ corner_points[1].green.slope = dc_fixpt_div(
+ dc_fixpt_sub(dc_fixpt_one, corner_points[1].green.y),
+ dc_fixpt_sub(end_value, corner_points[1].green.x));
+ corner_points[1].blue.slope = dc_fixpt_div(
+ dc_fixpt_sub(dc_fixpt_one, corner_points[1].blue.y),
+ dc_fixpt_sub(end_value, corner_points[1].blue.x));
}
lut_params->hw_points_num = hw_points;
@@ -411,7 +488,7 @@ bool cm_helper_translate_curve_to_hw_format(
++i;
}
cm_helper_convert_to_custom_float(rgb_resulted,
- lut_params->arr_points,
+ lut_params->corner_points,
hw_points, fixpoint);
return true;
@@ -424,15 +501,10 @@ bool cm_helper_translate_curve_to_degamma_hw_format(
const struct dc_transfer_func *output_tf,
struct pwl_params *lut_params)
{
- struct curve_points *arr_points;
+ struct curve_points3 *corner_points;
struct pwl_result_data *rgb_resulted;
struct pwl_result_data *rgb;
struct pwl_result_data *rgb_plus_1;
- struct fixed31_32 y_r;
- struct fixed31_32 y_g;
- struct fixed31_32 y_b;
- struct fixed31_32 y1_min;
- struct fixed31_32 y3_max;
int32_t region_start, region_end;
int32_t i;
@@ -443,7 +515,7 @@ bool cm_helper_translate_curve_to_degamma_hw_format(
PERF_TRACE();
- arr_points = lut_params->arr_points;
+ corner_points = lut_params->corner_points;
rgb_resulted = lut_params->rgb_resulted;
hw_points = 0;
@@ -489,31 +561,28 @@ bool cm_helper_translate_curve_to_degamma_hw_format(
rgb_resulted[hw_points - 1].green = output_tf->tf_pts.green[start_index];
rgb_resulted[hw_points - 1].blue = output_tf->tf_pts.blue[start_index];
- arr_points[0].x = dc_fixpt_pow(dc_fixpt_from_int(2),
+ corner_points[0].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),
dc_fixpt_from_int(region_start));
- arr_points[1].x = dc_fixpt_pow(dc_fixpt_from_int(2),
+ corner_points[0].green.x = corner_points[0].red.x;
+ corner_points[0].blue.x = corner_points[0].red.x;
+ corner_points[1].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),
dc_fixpt_from_int(region_end));
+ corner_points[1].green.x = corner_points[1].red.x;
+ corner_points[1].blue.x = corner_points[1].red.x;
- y_r = rgb_resulted[0].red;
- y_g = rgb_resulted[0].green;
- y_b = rgb_resulted[0].blue;
-
- y1_min = dc_fixpt_min(y_r, dc_fixpt_min(y_g, y_b));
-
- arr_points[0].y = y1_min;
- arr_points[0].slope = dc_fixpt_div(arr_points[0].y, arr_points[0].x);
- y_r = rgb_resulted[hw_points - 1].red;
- y_g = rgb_resulted[hw_points - 1].green;
- y_b = rgb_resulted[hw_points - 1].blue;
+ corner_points[0].red.y = rgb_resulted[0].red;
+ corner_points[0].green.y = rgb_resulted[0].green;
+ corner_points[0].blue.y = rgb_resulted[0].blue;
/* see comment above, m_arrPoints[1].y should be the Y value for the
* region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1)
*/
- y3_max = dc_fixpt_max(y_r, dc_fixpt_max(y_g, y_b));
-
- arr_points[1].y = y3_max;
-
- arr_points[1].slope = dc_fixpt_zero;
+ corner_points[1].red.y = rgb_resulted[hw_points - 1].red;
+ corner_points[1].green.y = rgb_resulted[hw_points - 1].green;
+ corner_points[1].blue.y = rgb_resulted[hw_points - 1].blue;
+ corner_points[1].red.slope = dc_fixpt_zero;
+ corner_points[1].green.slope = dc_fixpt_zero;
+ corner_points[1].blue.slope = dc_fixpt_zero;
if (output_tf->tf == TRANSFER_FUNCTION_PQ) {
/* for PQ, we want to have a straight line from last HW X point,
@@ -522,9 +591,15 @@ bool cm_helper_translate_curve_to_degamma_hw_format(
const struct fixed31_32 end_value =
dc_fixpt_from_int(125);
- arr_points[1].slope = dc_fixpt_div(
- dc_fixpt_sub(dc_fixpt_one, arr_points[1].y),
- dc_fixpt_sub(end_value, arr_points[1].x));
+ corner_points[1].red.slope = dc_fixpt_div(
+ dc_fixpt_sub(dc_fixpt_one, corner_points[1].red.y),
+ dc_fixpt_sub(end_value, corner_points[1].red.x));
+ corner_points[1].green.slope = dc_fixpt_div(
+ dc_fixpt_sub(dc_fixpt_one, corner_points[1].green.y),
+ dc_fixpt_sub(end_value, corner_points[1].green.x));
+ corner_points[1].blue.slope = dc_fixpt_div(
+ dc_fixpt_sub(dc_fixpt_one, corner_points[1].blue.y),
+ dc_fixpt_sub(end_value, corner_points[1].blue.x));
}
lut_params->hw_points_num = hw_points;
@@ -564,7 +639,7 @@ bool cm_helper_translate_curve_to_degamma_hw_format(
++i;
}
cm_helper_convert_to_custom_float(rgb_resulted,
- lut_params->arr_points,
+ lut_params->corner_points,
hw_points, false);
return true;
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.h
index 7a531b02871f..5ae4d69391a5 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.h
@@ -98,7 +98,7 @@ void cm_helper_program_xfer_func(
bool cm_helper_convert_to_custom_float(
struct pwl_result_data *rgb_resulted,
- struct curve_points *arr_points,
+ struct curve_points3 *corner_points,
uint32_t hw_points_num,
bool fixpoint);
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
index 193184affefb..87495dea45ec 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
@@ -45,6 +45,7 @@
#include "dcn10_hubbub.h"
#include "dcn10_cm_common.h"
#include "dc_link_dp.h"
+#include "dccg.h"
#define DC_LOGGER_INIT(logger)
@@ -786,7 +787,7 @@ static bool dcn10_hw_wa_force_recovery(struct dc *dc)
&dc->current_state->res_ctx.pipe_ctx[i];
if (pipe_ctx != NULL) {
hubp = pipe_ctx->plane_res.hubp;
- if (hubp != NULL) {
+ if (hubp != NULL && hubp->funcs->hubp_get_underflow_status) {
if (hubp->funcs->hubp_get_underflow_status(hubp) != 0) {
/* one pipe underflow, we will reset all the pipes*/
need_recover = true;
@@ -812,7 +813,7 @@ static bool dcn10_hw_wa_force_recovery(struct dc *dc)
if (pipe_ctx != NULL) {
hubp = pipe_ctx->plane_res.hubp;
/*DCHUBP_CNTL:HUBP_BLANK_EN=1*/
- if (hubp != NULL)
+ if (hubp != NULL && hubp->funcs->set_hubp_blank_en)
hubp->funcs->set_hubp_blank_en(hubp, true);
}
}
@@ -825,7 +826,7 @@ static bool dcn10_hw_wa_force_recovery(struct dc *dc)
if (pipe_ctx != NULL) {
hubp = pipe_ctx->plane_res.hubp;
/*DCHUBP_CNTL:HUBP_DISABLE=1*/
- if (hubp != NULL)
+ if (hubp != NULL && hubp->funcs->hubp_disable_control)
hubp->funcs->hubp_disable_control(hubp, true);
}
}
@@ -835,7 +836,7 @@ static bool dcn10_hw_wa_force_recovery(struct dc *dc)
if (pipe_ctx != NULL) {
hubp = pipe_ctx->plane_res.hubp;
/*DCHUBP_CNTL:HUBP_DISABLE=0*/
- if (hubp != NULL)
+ if (hubp != NULL && hubp->funcs->hubp_disable_control)
hubp->funcs->hubp_disable_control(hubp, true);
}
}
@@ -847,7 +848,7 @@ static bool dcn10_hw_wa_force_recovery(struct dc *dc)
if (pipe_ctx != NULL) {
hubp = pipe_ctx->plane_res.hubp;
/*DCHUBP_CNTL:HUBP_BLANK_EN=0*/
- if (hubp != NULL)
+ if (hubp != NULL && hubp->funcs->set_hubp_blank_en)
hubp->funcs->set_hubp_blank_en(hubp, true);
}
}
@@ -1126,7 +1127,7 @@ static void dcn10_init_hw(struct dc *dc)
enable_power_gating_plane(dc->hwseq, true);
- memset(&dc->res_pool->dccg->clks, 0, sizeof(dc->res_pool->dccg->clks));
+ memset(&dc->res_pool->clk_mgr->clks, 0, sizeof(dc->res_pool->clk_mgr->clks));
}
static void reset_hw_ctx_wrap(
@@ -1603,7 +1604,7 @@ static void mmhub_read_vm_context0_settings(struct dcn10_hubp *hubp1,
}
-static void dcn10_program_pte_vm(struct dce_hwseq *hws, struct hubp *hubp)
+void dcn10_program_pte_vm(struct dce_hwseq *hws, struct hubp *hubp)
{
struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp);
struct vm_system_aperture_param apt = { {{ 0 } } };
@@ -1703,33 +1704,22 @@ static void program_gamut_remap(struct pipe_ctx *pipe_ctx)
pipe_ctx->plane_res.dpp->funcs->dpp_set_gamut_remap(pipe_ctx->plane_res.dpp, &adjust);
}
-
-static void program_csc_matrix(struct pipe_ctx *pipe_ctx,
+static void dcn10_program_output_csc(struct dc *dc,
+ struct pipe_ctx *pipe_ctx,
enum dc_color_space colorspace,
- uint16_t *matrix)
+ uint16_t *matrix,
+ int opp_id)
{
if (pipe_ctx->stream->csc_color_matrix.enable_adjustment == true) {
- if (pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment != NULL)
- pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment(pipe_ctx->plane_res.dpp, matrix);
+ if (pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment != NULL)
+ pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment(pipe_ctx->plane_res.dpp, matrix);
} else {
if (pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_default != NULL)
pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_default(pipe_ctx->plane_res.dpp, colorspace);
}
}
-static void dcn10_program_output_csc(struct dc *dc,
- struct pipe_ctx *pipe_ctx,
- enum dc_color_space colorspace,
- uint16_t *matrix,
- int opp_id)
-{
- if (pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment != NULL)
- program_csc_matrix(pipe_ctx,
- colorspace,
- matrix);
-}
-
-static bool is_lower_pipe_tree_visible(struct pipe_ctx *pipe_ctx)
+bool is_lower_pipe_tree_visible(struct pipe_ctx *pipe_ctx)
{
if (pipe_ctx->plane_state->visible)
return true;
@@ -1738,7 +1728,7 @@ static bool is_lower_pipe_tree_visible(struct pipe_ctx *pipe_ctx)
return false;
}
-static bool is_upper_pipe_tree_visible(struct pipe_ctx *pipe_ctx)
+bool is_upper_pipe_tree_visible(struct pipe_ctx *pipe_ctx)
{
if (pipe_ctx->plane_state->visible)
return true;
@@ -1747,7 +1737,7 @@ static bool is_upper_pipe_tree_visible(struct pipe_ctx *pipe_ctx)
return false;
}
-static bool is_pipe_tree_visible(struct pipe_ctx *pipe_ctx)
+bool is_pipe_tree_visible(struct pipe_ctx *pipe_ctx)
{
if (pipe_ctx->plane_state->visible)
return true;
@@ -1943,10 +1933,6 @@ static void dcn10_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx)
struct mpc *mpc = dc->res_pool->mpc;
struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params);
-
-
- /* TODO: proper fix once fpga works */
-
if (dc->debug.visual_confirm == VISUAL_CONFIRM_HDR) {
dcn10_get_hdr_visual_confirm_color(
pipe_ctx, &blnd_cfg.black_color);
@@ -2026,8 +2012,6 @@ static void update_scaler(struct pipe_ctx *pipe_ctx)
bool per_pixel_alpha =
pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe;
- /* TODO: proper fix once fpga works */
-
pipe_ctx->plane_res.scl_data.lb_params.alpha_en = per_pixel_alpha;
pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP;
/* scaler configuration */
@@ -2035,7 +2019,7 @@ static void update_scaler(struct pipe_ctx *pipe_ctx)
pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data);
}
-static void update_dchubp_dpp(
+void update_dchubp_dpp(
struct dc *dc,
struct pipe_ctx *pipe_ctx,
struct dc_state *context)
@@ -2052,16 +2036,22 @@ static void update_dchubp_dpp(
*/
if (plane_state->update_flags.bits.full_update) {
bool should_divided_by_2 = context->bw.dcn.clk.dppclk_khz <=
- dc->res_pool->dccg->clks.dispclk_khz / 2;
+ dc->res_pool->clk_mgr->clks.dispclk_khz / 2;
dpp->funcs->dpp_dppclk_control(
dpp,
should_divided_by_2,
true);
- dc->res_pool->dccg->clks.dppclk_khz = should_divided_by_2 ?
- dc->res_pool->dccg->clks.dispclk_khz / 2 :
- dc->res_pool->dccg->clks.dispclk_khz;
+ if (dc->res_pool->dccg)
+ dc->res_pool->dccg->funcs->update_dpp_dto(
+ dc->res_pool->dccg,
+ dpp->inst,
+ pipe_ctx->plane_res.bw.calc.dppclk_khz);
+ else
+ dc->res_pool->clk_mgr->clks.dppclk_khz = should_divided_by_2 ?
+ dc->res_pool->clk_mgr->clks.dispclk_khz / 2 :
+ dc->res_pool->clk_mgr->clks.dispclk_khz;
}
/* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG
@@ -2182,7 +2172,7 @@ static void dcn10_blank_pixel_data(
}
}
-static void set_hdr_multiplier(struct pipe_ctx *pipe_ctx)
+void set_hdr_multiplier(struct pipe_ctx *pipe_ctx)
{
struct fixed31_32 multiplier = dc_fixpt_from_fraction(
pipe_ctx->plane_state->sdr_white_level, 80);
@@ -2257,47 +2247,7 @@ static void program_all_pipe_in_tree(
}
}
-static void dcn10_pplib_apply_display_requirements(
- struct dc *dc,
- struct dc_state *context)
-{
- struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg;
-
- pp_display_cfg->min_engine_clock_khz = dc->res_pool->dccg->clks.dcfclk_khz;
- pp_display_cfg->min_memory_clock_khz = dc->res_pool->dccg->clks.fclk_khz;
- pp_display_cfg->min_engine_clock_deep_sleep_khz = dc->res_pool->dccg->clks.dcfclk_deep_sleep_khz;
- pp_display_cfg->min_dcfc_deep_sleep_clock_khz = dc->res_pool->dccg->clks.dcfclk_deep_sleep_khz;
- pp_display_cfg->min_dcfclock_khz = dc->res_pool->dccg->clks.dcfclk_khz;
- pp_display_cfg->disp_clk_khz = dc->res_pool->dccg->clks.dispclk_khz;
- dce110_fill_display_configs(context, pp_display_cfg);
-
- if (memcmp(&dc->prev_display_config, pp_display_cfg, sizeof(
- struct dm_pp_display_configuration)) != 0)
- dm_pp_apply_display_requirements(dc->ctx, pp_display_cfg);
-
- dc->prev_display_config = *pp_display_cfg;
-}
-
-static void optimize_shared_resources(struct dc *dc)
-{
- if (dc->current_state->stream_count == 0) {
- /* S0i2 message */
- dcn10_pplib_apply_display_requirements(dc, dc->current_state);
- }
-
- if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE)
- dcn_bw_notify_pplib_of_wm_ranges(dc);
-}
-
-static void ready_shared_resources(struct dc *dc, struct dc_state *context)
-{
- /* S0i2 message */
- if (dc->current_state->stream_count == 0 &&
- context->stream_count != 0)
- dcn10_pplib_apply_display_requirements(dc, context);
-}
-
-static struct pipe_ctx *find_top_pipe_for_stream(
+struct pipe_ctx *find_top_pipe_for_stream(
struct dc *dc,
struct dc_state *context,
const struct dc_stream_state *stream)
@@ -2398,10 +2348,9 @@ static void dcn10_apply_ctx_for_surface(
hubbub1_wm_change_req_wa(dc->res_pool->hubbub);
}
-static void dcn10_set_bandwidth(
+static void dcn10_prepare_bandwidth(
struct dc *dc,
- struct dc_state *context,
- bool safe_to_lower)
+ struct dc_state *context)
{
if (dc->debug.sanity_checks)
dcn10_verify_allow_pstate_change_high(dc);
@@ -2410,12 +2359,39 @@ static void dcn10_set_bandwidth(
if (context->stream_count == 0)
context->bw.dcn.clk.phyclk_khz = 0;
- dc->res_pool->dccg->funcs->update_clocks(
- dc->res_pool->dccg,
- &context->bw.dcn.clk,
- safe_to_lower);
+ dc->res_pool->clk_mgr->funcs->update_clocks(
+ dc->res_pool->clk_mgr,
+ context,
+ false);
+ }
- dcn10_pplib_apply_display_requirements(dc, context);
+ hubbub1_program_watermarks(dc->res_pool->hubbub,
+ &context->bw.dcn.watermarks,
+ dc->res_pool->ref_clock_inKhz / 1000,
+ true);
+
+ if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE)
+ dcn_bw_notify_pplib_of_wm_ranges(dc);
+
+ if (dc->debug.sanity_checks)
+ dcn10_verify_allow_pstate_change_high(dc);
+}
+
+static void dcn10_optimize_bandwidth(
+ struct dc *dc,
+ struct dc_state *context)
+{
+ if (dc->debug.sanity_checks)
+ dcn10_verify_allow_pstate_change_high(dc);
+
+ if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
+ if (context->stream_count == 0)
+ context->bw.dcn.clk.phyclk_khz = 0;
+
+ dc->res_pool->clk_mgr->funcs->update_clocks(
+ dc->res_pool->clk_mgr,
+ context,
+ true);
}
hubbub1_program_watermarks(dc->res_pool->hubbub,
@@ -2423,6 +2399,9 @@ static void dcn10_set_bandwidth(
dc->res_pool->ref_clock_inKhz / 1000,
true);
+ if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE)
+ dcn_bw_notify_pplib_of_wm_ranges(dc);
+
if (dc->debug.sanity_checks)
dcn10_verify_allow_pstate_change_high(dc);
}
@@ -2694,7 +2673,6 @@ static void dcn10_set_cursor_sdr_white_level(struct pipe_ctx *pipe_ctx)
static const struct hw_sequencer_funcs dcn10_funcs = {
.program_gamut_remap = program_gamut_remap,
- .program_csc_matrix = program_csc_matrix,
.init_hw = dcn10_init_hw,
.apply_ctx_to_hw = dce110_apply_ctx_to_hw,
.apply_ctx_for_surface = dcn10_apply_ctx_for_surface,
@@ -2721,7 +2699,8 @@ static const struct hw_sequencer_funcs dcn10_funcs = {
.disable_plane = dcn10_disable_plane,
.blank_pixel_data = dcn10_blank_pixel_data,
.pipe_control_lock = dcn10_pipe_control_lock,
- .set_bandwidth = dcn10_set_bandwidth,
+ .prepare_bandwidth = dcn10_prepare_bandwidth,
+ .optimize_bandwidth = dcn10_optimize_bandwidth,
.reset_hw_ctx_wrap = reset_hw_ctx_wrap,
.enable_stream_timing = dcn10_enable_stream_timing,
.set_drr = set_drr,
@@ -2732,10 +2711,6 @@ static const struct hw_sequencer_funcs dcn10_funcs = {
.log_hw_state = dcn10_log_hw_state,
.get_hw_state = dcn10_get_hw_state,
.wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect,
- .ready_shared_resources = ready_shared_resources,
- .optimize_shared_resources = optimize_shared_resources,
- .pplib_apply_display_requirements =
- dcn10_pplib_apply_display_requirements,
.edp_backlight_control = hwss_edp_backlight_control,
.edp_power_control = hwss_edp_power_control,
.edp_wait_for_hpd_ready = hwss_edp_wait_for_hpd_ready,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h
index 84d461e0ed3e..5e5610c9e600 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h
@@ -51,4 +51,24 @@ void dcn10_get_hw_state(
char *pBuf, unsigned int bufSize,
unsigned int mask);
+bool is_lower_pipe_tree_visible(struct pipe_ctx *pipe_ctx);
+
+bool is_upper_pipe_tree_visible(struct pipe_ctx *pipe_ctx);
+
+bool is_pipe_tree_visible(struct pipe_ctx *pipe_ctx);
+
+void dcn10_program_pte_vm(struct dce_hwseq *hws, struct hubp *hubp);
+
+void set_hdr_multiplier(struct pipe_ctx *pipe_ctx);
+
+void update_dchubp_dpp(
+ struct dc *dc,
+ struct pipe_ctx *pipe_ctx,
+ struct dc_state *context);
+
+struct pipe_ctx *find_top_pipe_for_stream(
+ struct dc *dc,
+ struct dc_state *context,
+ const struct dc_stream_state *stream);
+
#endif /* __DC_HWSS_DCN10_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c
index ba6a8686062f..477ab9222216 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c
@@ -589,7 +589,7 @@ static bool dcn10_link_encoder_validate_hdmi_output(
return false;
/* DCE11 HW does not support 420 */
- if (!enc10->base.features.ycbcr420_supported &&
+ if (!enc10->base.features.hdmi_ycbcr420_supported &&
crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR420)
return false;
@@ -606,8 +606,10 @@ bool dcn10_link_encoder_validate_dp_output(
const struct dcn10_link_encoder *enc10,
const struct dc_crtc_timing *crtc_timing)
{
- if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR420)
- return false;
+ if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) {
+ if (!enc10->base.features.dp_ycbcr420_supported)
+ return false;
+ }
return true;
}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c
index 54626682bab2..7d1f66797cb3 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c
@@ -87,9 +87,8 @@ static void optc1_disable_stereo(struct timing_generator *optc)
REG_SET(OTG_STEREO_CONTROL, 0,
OTG_STEREO_EN, 0);
- REG_SET_3(OTG_3D_STRUCTURE_CONTROL, 0,
+ REG_SET_2(OTG_3D_STRUCTURE_CONTROL, 0,
OTG_3D_STRUCTURE_EN, 0,
- OTG_3D_STRUCTURE_V_UPDATE_MODE, 0,
OTG_3D_STRUCTURE_STEREO_SEL_OVR, 0);
}
@@ -274,10 +273,12 @@ void optc1_program_timing(
* program the reg for interrupt postition.
*/
vertical_line_start = asic_blank_end - optc->dlg_otg_param.vstartup_start + 1;
- if (vertical_line_start < 0) {
- ASSERT(0);
+ v_fp2 = 0;
+ if (vertical_line_start < 0)
+ v_fp2 = -vertical_line_start;
+ if (vertical_line_start < 0)
vertical_line_start = 0;
- }
+
REG_SET(OTG_VERTICAL_INTERRUPT2_POSITION, 0,
OTG_VERTICAL_INTERRUPT2_LINE_START, vertical_line_start);
@@ -296,9 +297,6 @@ void optc1_program_timing(
if (patched_crtc_timing.flags.INTERLACE == 1)
field_num = 1;
}
- v_fp2 = 0;
- if (optc->dlg_otg_param.vstartup_start > asic_blank_end)
- v_fp2 = optc->dlg_otg_param.vstartup_start > asic_blank_end;
/* Interlace */
if (patched_crtc_timing.flags.INTERLACE == 1) {
@@ -1155,9 +1153,8 @@ static void optc1_enable_stereo(struct timing_generator *optc,
OTG_DISABLE_STEREOSYNC_OUTPUT_FOR_DP, 1);
if (flags->PROGRAM_STEREO)
- REG_UPDATE_3(OTG_3D_STRUCTURE_CONTROL,
+ REG_UPDATE_2(OTG_3D_STRUCTURE_CONTROL,
OTG_3D_STRUCTURE_EN, flags->FRAME_PACKED,
- OTG_3D_STRUCTURE_V_UPDATE_MODE, flags->FRAME_PACKED,
OTG_3D_STRUCTURE_STEREO_SEL_OVR, flags->FRAME_PACKED);
}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c
index a71453a15ae3..47dbe4bb294a 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c
@@ -28,23 +28,23 @@
#include "resource.h"
#include "include/irq_service_interface.h"
-#include "dcn10/dcn10_resource.h"
+#include "dcn10_resource.h"
-#include "dcn10/dcn10_ipp.h"
-#include "dcn10/dcn10_mpc.h"
+#include "dcn10_ipp.h"
+#include "dcn10_mpc.h"
#include "irq/dcn10/irq_service_dcn10.h"
-#include "dcn10/dcn10_dpp.h"
+#include "dcn10_dpp.h"
#include "dcn10_optc.h"
-#include "dcn10/dcn10_hw_sequencer.h"
+#include "dcn10_hw_sequencer.h"
#include "dce110/dce110_hw_sequencer.h"
-#include "dcn10/dcn10_opp.h"
-#include "dcn10/dcn10_link_encoder.h"
-#include "dcn10/dcn10_stream_encoder.h"
-#include "dce/dce_clocks.h"
+#include "dcn10_opp.h"
+#include "dcn10_link_encoder.h"
+#include "dcn10_stream_encoder.h"
+#include "dcn10_clk_mgr.h"
#include "dce/dce_clock_source.h"
#include "dce/dce_audio.h"
#include "dce/dce_hwseq.h"
-#include "../virtual/virtual_stream_encoder.h"
+#include "virtual/virtual_stream_encoder.h"
#include "dce110/dce110_resource.h"
#include "dce112/dce112_resource.h"
#include "dcn10_hubp.h"
@@ -438,6 +438,7 @@ static const struct dcn_optc_mask tg_mask = {
static const struct bios_registers bios_regs = {
+ NBIO_SR(BIOS_SCRATCH_0),
NBIO_SR(BIOS_SCRATCH_3),
NBIO_SR(BIOS_SCRATCH_6)
};
@@ -719,7 +720,8 @@ static struct timing_generator *dcn10_timing_generator_create(
static const struct encoder_feature_support link_enc_feature = {
.max_hdmi_deep_color = COLOR_DEPTH_121212,
.max_hdmi_pixel_clock = 600000,
- .ycbcr420_supported = true,
+ .hdmi_ycbcr420_supported = true,
+ .dp_ycbcr420_supported = false,
.flags.bits.IS_HBR2_CAPABLE = true,
.flags.bits.IS_HBR3_CAPABLE = true,
.flags.bits.IS_TPS3_CAPABLE = true,
@@ -949,8 +951,8 @@ static void destruct(struct dcn10_resource_pool *pool)
if (pool->base.dmcu != NULL)
dce_dmcu_destroy(&pool->base.dmcu);
- if (pool->base.dccg != NULL)
- dce_dccg_destroy(&pool->base.dccg);
+ if (pool->base.clk_mgr != NULL)
+ dce_clk_mgr_destroy(&pool->base.clk_mgr);
kfree(pool->base.pp_smu);
}
@@ -1276,8 +1278,8 @@ static bool construct(
}
}
- pool->base.dccg = dcn1_dccg_create(ctx);
- if (pool->base.dccg == NULL) {
+ pool->base.clk_mgr = dcn1_clk_mgr_create(ctx);
+ if (pool->base.clk_mgr == NULL) {
dm_error("DC: failed to create display clock!\n");
BREAK_TO_DEBUGGER();
goto fail;
diff --git a/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h b/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h
index f2ea8452d48f..beb08fd12b1d 100644
--- a/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h
+++ b/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h
@@ -55,10 +55,10 @@ struct pp_smu {
struct pp_smu_wm_set_range {
unsigned int wm_inst;
- uint32_t min_fill_clk_khz;
- uint32_t max_fill_clk_khz;
- uint32_t min_drain_clk_khz;
- uint32_t max_drain_clk_khz;
+ uint32_t min_fill_clk_mhz;
+ uint32_t max_fill_clk_mhz;
+ uint32_t min_drain_clk_mhz;
+ uint32_t max_drain_clk_mhz;
};
#define MAX_WATERMARK_SETS 4
@@ -77,15 +77,15 @@ struct pp_smu_display_requirement_rv {
*/
unsigned int display_count;
- /* PPSMC_MSG_SetHardMinFclkByFreq: khz
+ /* PPSMC_MSG_SetHardMinFclkByFreq: mhz
* FCLK will vary with DPM, but never below requested hard min
*/
- unsigned int hard_min_fclk_khz;
+ unsigned int hard_min_fclk_mhz;
- /* PPSMC_MSG_SetHardMinDcefclkByFreq: khz
+ /* PPSMC_MSG_SetHardMinDcefclkByFreq: mhz
* fixed clock at requested freq, either from FCH bypass or DFS
*/
- unsigned int hard_min_dcefclk_khz;
+ unsigned int hard_min_dcefclk_mhz;
/* PPSMC_MSG_SetMinDeepSleepDcefclk: mhz
* when DF is in cstate, dcf clock is further divided down
@@ -103,13 +103,19 @@ struct pp_smu_funcs_rv {
void (*set_display_count)(struct pp_smu *pp, int count);
/* which SMU message? are reader and writer WM separate SMU msg? */
+ /*
+ * PPSMC_MSG_SetDriverDramAddrHigh
+ * PPSMC_MSG_SetDriverDramAddrLow
+ * PPSMC_MSG_TransferTableDram2Smu
+ *
+ * */
void (*set_wm_ranges)(struct pp_smu *pp,
struct pp_smu_wm_range_sets *ranges);
/* PPSMC_MSG_SetHardMinDcfclkByFreq
* fixed clock at requested freq, either from FCH bypass or DFS
*/
- void (*set_hard_min_dcfclk_by_freq)(struct pp_smu *pp, int khz);
+ void (*set_hard_min_dcfclk_by_freq)(struct pp_smu *pp, int mhz);
/* PPSMC_MSG_SetMinDeepSleepDcfclk
* when DF is in cstate, dcf clock is further divided down
@@ -120,12 +126,12 @@ struct pp_smu_funcs_rv {
/* PPSMC_MSG_SetHardMinFclkByFreq
* FCLK will vary with DPM, but never below requested hard min
*/
- void (*set_hard_min_fclk_by_freq)(struct pp_smu *pp, int khz);
+ void (*set_hard_min_fclk_by_freq)(struct pp_smu *pp, int mhz);
/* PPSMC_MSG_SetHardMinSocclkByFreq
* Needed for DWB support
*/
- void (*set_hard_min_socclk_by_freq)(struct pp_smu *pp, int khz);
+ void (*set_hard_min_socclk_by_freq)(struct pp_smu *pp, int mhz);
/* PME w/a */
void (*set_pme_wa_enable)(struct pp_smu *pp);
diff --git a/drivers/gpu/drm/amd/display/dc/dm_services_types.h b/drivers/gpu/drm/amd/display/dc/dm_services_types.h
index 2b83f922ac02..1af8c777b3ac 100644
--- a/drivers/gpu/drm/amd/display/dc/dm_services_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dm_services_types.h
@@ -208,22 +208,20 @@ struct dm_bl_data_point {
/* Brightness level as effective value in range 0-255,
* corresponding to above percentage
*/
- uint8_t signalLevel;
+ uint8_t signal_level;
};
/* Total size of the structure should not exceed 256 bytes */
struct dm_acpi_atif_backlight_caps {
-
-
uint16_t size; /* Bytes 0-1 (2 bytes) */
uint16_t flags; /* Byted 2-3 (2 bytes) */
- uint8_t errorCode; /* Byte 4 */
- uint8_t acLevelPercentage; /* Byte 5 */
- uint8_t dcLevelPercentage; /* Byte 6 */
- uint8_t minInputSignal; /* Byte 7 */
- uint8_t maxInputSignal; /* Byte 8 */
- uint8_t numOfDataPoints; /* Byte 9 */
- struct dm_bl_data_point dataPoints[99]; /* Bytes 10-207 (198 bytes)*/
+ uint8_t error_code; /* Byte 4 */
+ uint8_t ac_level_percentage; /* Byte 5 */
+ uint8_t dc_level_percentage; /* Byte 6 */
+ uint8_t min_input_signal; /* Byte 7 */
+ uint8_t max_input_signal; /* Byte 8 */
+ uint8_t num_data_points; /* Byte 9 */
+ struct dm_bl_data_point data_points[99]; /* Bytes 10-207 (198 bytes)*/
};
enum dm_acpi_display_type {
diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h
index cbafce649e33..5dd04520ceca 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h
@@ -113,7 +113,8 @@ struct _vcs_dpi_soc_bounding_box_st {
int use_urgent_burst_bw;
double max_hscl_ratio;
double max_vscl_ratio;
- struct _vcs_dpi_voltage_scaling_st clock_limits[7];
+ unsigned int num_states;
+ struct _vcs_dpi_voltage_scaling_st clock_limits[8];
};
struct _vcs_dpi_ip_params_st {
diff --git a/drivers/gpu/drm/amd/display/dc/inc/bw_fixed.h b/drivers/gpu/drm/amd/display/dc/inc/bw_fixed.h
index 39ee8eba3c31..d1656c9d50df 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/bw_fixed.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/bw_fixed.h
@@ -126,7 +126,7 @@ static inline struct bw_fixed bw_div(const struct bw_fixed arg1, const struct bw
static inline struct bw_fixed bw_mod(const struct bw_fixed arg1, const struct bw_fixed arg2)
{
struct bw_fixed res;
- div64_u64_rem(arg1.value, arg2.value, &res.value);
+ div64_u64_rem(arg1.value, arg2.value, (uint64_t *)&res.value);
return res;
}
diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h
index c1976c175b57..e3ee96afa60e 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h
@@ -82,7 +82,7 @@ void core_link_disable_stream(struct pipe_ctx *pipe_ctx, int option);
void core_link_set_avmute(struct pipe_ctx *pipe_ctx, bool enable);
/********** DAL Core*********************/
-#include "display_clock.h"
+#include "hw/clk_mgr.h"
#include "transform.h"
#include "dpp.h"
@@ -169,6 +169,7 @@ struct resource_pool {
unsigned int audio_count;
struct audio_support audio_support;
+ struct clk_mgr *clk_mgr;
struct dccg *dccg;
struct irq_service *irqs;
@@ -287,7 +288,7 @@ struct dc_state {
struct dcn_bw_internal_vars dcn_bw_vars;
#endif
- struct dccg *dis_clk;
+ struct clk_mgr *dccg;
struct kref refcount;
};
diff --git a/drivers/gpu/drm/amd/display/dc/inc/dcn_calcs.h b/drivers/gpu/drm/amd/display/dc/inc/dcn_calcs.h
index e688eb9b975c..ece954a40a8e 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/dcn_calcs.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/dcn_calcs.h
@@ -31,8 +31,8 @@
#define __DCN_CALCS_H__
#include "bw_fixed.h"
-#include "display_clock.h"
#include "../dml/display_mode_lib.h"
+#include "hw/clk_mgr.h"
struct dc;
struct dc_state;
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/abm.h b/drivers/gpu/drm/amd/display/dc/inc/hw/abm.h
index a83a48494613..abc961c0906e 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/abm.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/abm.h
@@ -47,12 +47,18 @@ struct abm_funcs {
bool (*set_abm_level)(struct abm *abm, unsigned int abm_level);
bool (*set_abm_immediate_disable)(struct abm *abm);
bool (*init_backlight)(struct abm *abm);
- bool (*set_backlight_level)(struct abm *abm,
- unsigned int backlight_level,
+
+ /* backlight_pwm_u16_16 is unsigned 32 bit,
+ * 16 bit integer + 16 fractional, where 1.0 is max backlight value.
+ */
+ bool (*set_backlight_level_pwm)(struct abm *abm,
+ unsigned int backlight_pwm_u16_16,
unsigned int frame_ramp,
unsigned int controller_id,
bool use_smooth_brightness);
- unsigned int (*get_current_backlight_8_bit)(struct abm *abm);
+
+ unsigned int (*get_current_backlight)(struct abm *abm);
+ unsigned int (*get_target_backlight)(struct abm *abm);
};
#endif
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/display_clock.h b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h
index 689faa16c0ae..23a4b18e5fee 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/display_clock.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h
@@ -23,41 +23,25 @@
*
*/
-#ifndef __DISPLAY_CLOCK_H__
-#define __DISPLAY_CLOCK_H__
+#ifndef __DAL_CLK_MGR_H__
+#define __DAL_CLK_MGR_H__
#include "dm_services_types.h"
#include "dc.h"
-/* Structure containing all state-dependent clocks
- * (dependent on "enum clocks_state") */
-struct state_dependent_clocks {
- int display_clk_khz;
- int pixel_clk_khz;
-};
-
-struct dccg {
+struct clk_mgr {
struct dc_context *ctx;
- const struct display_clock_funcs *funcs;
+ const struct clk_mgr_funcs *funcs;
- enum dm_pp_clocks_state max_clks_state;
- enum dm_pp_clocks_state cur_min_clks_state;
struct dc_clocks clks;
};
-struct display_clock_funcs {
- void (*update_clocks)(struct dccg *dccg,
- struct dc_clocks *new_clocks,
+struct clk_mgr_funcs {
+ void (*update_clocks)(struct clk_mgr *clk_mgr,
+ struct dc_state *context,
bool safe_to_lower);
- int (*set_dispclk)(struct dccg *dccg,
- int requested_clock_khz);
-
- int (*get_dp_ref_clk_frequency)(struct dccg *dccg);
- bool (*update_dfs_bypass)(struct dccg *dccg,
- struct dc *dc,
- struct dc_state *context,
- int requested_clock_khz);
+ int (*get_dp_ref_clk_frequency)(struct clk_mgr *clk_mgr);
};
-#endif /* __DISPLAY_CLOCK_H__ */
+#endif /* __DAL_CLK_MGR_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h
new file mode 100644
index 000000000000..95a56d012626
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2018 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.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DAL_DCCG_H__
+#define __DAL_DCCG_H__
+
+#include "dc_types.h"
+
+struct dccg {
+ struct dc_context *ctx;
+ const struct dccg_funcs *funcs;
+
+ int ref_dppclk;
+};
+
+struct dccg_funcs {
+ void (*update_dpp_dto)(struct dccg *dccg,
+ int dpp_inst,
+ int req_dppclk);
+};
+
+#endif //__DAL_DCCG_H__
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h b/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h
index cf7433ebf91a..da85537a4488 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h
@@ -53,6 +53,12 @@ struct curve_points {
uint32_t custom_float_slope;
};
+struct curve_points3 {
+ struct curve_points red;
+ struct curve_points green;
+ struct curve_points blue;
+};
+
struct pwl_result_data {
struct fixed31_32 red;
struct fixed31_32 green;
@@ -71,9 +77,17 @@ struct pwl_result_data {
uint32_t delta_blue_reg;
};
+/* arr_curve_points - regamma regions/segments specification
+ * arr_points - beginning and end point specified separately (only one on DCE)
+ * corner_points - beginning and end point for all 3 colors (DCN)
+ * rgb_resulted - final curve
+ */
struct pwl_params {
struct gamma_curve arr_curve_points[34];
- struct curve_points arr_points[2];
+ union {
+ struct curve_points arr_points[2];
+ struct curve_points3 corner_points[2];
+ };
struct pwl_result_data rgb_resulted[256 + 3];
uint32_t hw_points_num;
};
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h
index e28e9770e0a3..c20fdcaac53b 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h
@@ -65,7 +65,8 @@ struct encoder_feature_support {
enum dc_color_depth max_hdmi_deep_color;
unsigned int max_hdmi_pixel_clock;
- bool ycbcr420_supported;
+ bool hdmi_ycbcr420_supported;
+ bool dp_ycbcr420_supported;
};
union dpcd_psr_configuration {
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/mem_input.h b/drivers/gpu/drm/amd/display/dc/inc/hw/mem_input.h
index da89c2edb07c..06df02ddff6a 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/mem_input.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/mem_input.h
@@ -31,7 +31,7 @@
#include "dml/display_mode_structs.h"
struct dchub_init_data;
-struct cstate_pstate_watermarks_st {
+struct cstate_pstate_watermarks_st1 {
uint32_t cstate_exit_ns;
uint32_t cstate_enter_plus_exit_ns;
uint32_t pstate_change_ns;
@@ -40,7 +40,7 @@ struct cstate_pstate_watermarks_st {
struct dcn_watermarks {
uint32_t pte_meta_urgent_ns;
uint32_t urgent_ns;
- struct cstate_pstate_watermarks_st cstate_pstate;
+ struct cstate_pstate_watermarks_st1 cstate_pstate;
};
struct dcn_watermark_set {
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h
index 26f29d5da3d8..e9b702ce02dd 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h
@@ -32,8 +32,6 @@
#include "inc/hw/link_encoder.h"
#include "core_status.h"
-#define EDP_BACKLIGHT_RAMP_DISABLE_LEVEL 0xFFFFFFFF
-
enum pipe_gating_control {
PIPE_GATING_CONTROL_DISABLE = 0,
PIPE_GATING_CONTROL_ENABLE,
@@ -87,11 +85,6 @@ struct hw_sequencer_funcs {
void (*program_gamut_remap)(
struct pipe_ctx *pipe_ctx);
- void (*program_csc_matrix)(
- struct pipe_ctx *pipe_ctx,
- enum dc_color_space colorspace,
- uint16_t *matrix);
-
void (*program_output_csc)(struct dc *dc,
struct pipe_ctx *pipe_ctx,
enum dc_color_space colorspace,
@@ -177,10 +170,12 @@ struct hw_sequencer_funcs {
struct pipe_ctx *pipe_ctx,
bool blank);
- void (*set_bandwidth)(
+ void (*prepare_bandwidth)(
struct dc *dc,
- struct dc_state *context,
- bool safe_to_lower);
+ struct dc_state *context);
+ void (*optimize_bandwidth)(
+ struct dc *dc,
+ struct dc_state *context);
void (*set_drr)(struct pipe_ctx **pipe_ctx, int num_pipes,
int vmin, int vmax);
@@ -210,11 +205,6 @@ struct hw_sequencer_funcs {
struct resource_pool *res_pool,
struct pipe_ctx *pipe_ctx);
- void (*ready_shared_resources)(struct dc *dc, struct dc_state *context);
- void (*optimize_shared_resources)(struct dc *dc);
- void (*pplib_apply_display_requirements)(
- struct dc *dc,
- struct dc_state *context);
void (*edp_power_control)(
struct dc_link *link,
bool enable);
diff --git a/drivers/gpu/drm/amd/display/dc/inc/resource.h b/drivers/gpu/drm/amd/display/dc/inc/resource.h
index 33b99e3ab10d..0086a2f1d21a 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/resource.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/resource.h
@@ -30,9 +30,6 @@
#include "dal_asic_id.h"
#include "dm_pp_smu.h"
-/* TODO unhardcode, 4 for CZ*/
-#define MEMORY_TYPE_MULTIPLIER 4
-
enum dce_version resource_parse_asic_id(
struct hw_asic_id asic_id);
diff --git a/drivers/gpu/drm/amd/display/dc/os_types.h b/drivers/gpu/drm/amd/display/dc/os_types.h
index a407892905af..c0d9f332baed 100644
--- a/drivers/gpu/drm/amd/display/dc/os_types.h
+++ b/drivers/gpu/drm/amd/display/dc/os_types.h
@@ -40,8 +40,6 @@
#define LITTLEENDIAN_CPU
#endif
-#undef READ
-#undef WRITE
#undef FRAME_SIZE
#define dm_output_to_console(fmt, ...) DRM_DEBUG_KMS(fmt, ##__VA_ARGS__)
diff --git a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c
index cdcefd087487..7480f072c375 100644
--- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c
+++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c
@@ -306,6 +306,18 @@ static struct fixed31_32 translate_from_linear_space(
a1);
}
+static struct fixed31_32 calculate_gamma22(struct fixed31_32 arg)
+{
+ struct fixed31_32 gamma = dc_fixpt_from_fraction(22, 10);
+
+ return translate_from_linear_space(arg,
+ dc_fixpt_zero,
+ dc_fixpt_zero,
+ dc_fixpt_zero,
+ dc_fixpt_zero,
+ gamma);
+}
+
static struct fixed31_32 translate_to_linear_space(
struct fixed31_32 arg,
struct fixed31_32 a0,
@@ -709,6 +721,169 @@ static void build_regamma(struct pwl_float_data_ex *rgb_regamma,
}
}
+static void hermite_spline_eetf(struct fixed31_32 input_x,
+ struct fixed31_32 max_display,
+ struct fixed31_32 min_display,
+ struct fixed31_32 max_content,
+ struct fixed31_32 *out_x)
+{
+ struct fixed31_32 min_lum_pq;
+ struct fixed31_32 max_lum_pq;
+ struct fixed31_32 max_content_pq;
+ struct fixed31_32 ks;
+ struct fixed31_32 E1;
+ struct fixed31_32 E2;
+ struct fixed31_32 E3;
+ struct fixed31_32 t;
+ struct fixed31_32 t2;
+ struct fixed31_32 t3;
+ struct fixed31_32 two;
+ struct fixed31_32 three;
+ struct fixed31_32 temp1;
+ struct fixed31_32 temp2;
+ struct fixed31_32 a = dc_fixpt_from_fraction(15, 10);
+ struct fixed31_32 b = dc_fixpt_from_fraction(5, 10);
+ struct fixed31_32 epsilon = dc_fixpt_from_fraction(1, 1000000); // dc_fixpt_epsilon is a bit too small
+
+ if (dc_fixpt_eq(max_content, dc_fixpt_zero)) {
+ *out_x = dc_fixpt_zero;
+ return;
+ }
+
+ compute_pq(input_x, &E1);
+ compute_pq(dc_fixpt_div(min_display, max_content), &min_lum_pq);
+ compute_pq(dc_fixpt_div(max_display, max_content), &max_lum_pq);
+ compute_pq(dc_fixpt_one, &max_content_pq); // always 1? DAL2 code is weird
+ a = dc_fixpt_div(dc_fixpt_add(dc_fixpt_one, b), max_content_pq); // (1+b)/maxContent
+ ks = dc_fixpt_sub(dc_fixpt_mul(a, max_lum_pq), b); // a * max_lum_pq - b
+
+ if (dc_fixpt_lt(E1, ks))
+ E2 = E1;
+ else if (dc_fixpt_le(ks, E1) && dc_fixpt_le(E1, dc_fixpt_one)) {
+ if (dc_fixpt_lt(epsilon, dc_fixpt_sub(dc_fixpt_one, ks)))
+ // t = (E1 - ks) / (1 - ks)
+ t = dc_fixpt_div(dc_fixpt_sub(E1, ks),
+ dc_fixpt_sub(dc_fixpt_one, ks));
+ else
+ t = dc_fixpt_zero;
+
+ two = dc_fixpt_from_int(2);
+ three = dc_fixpt_from_int(3);
+
+ t2 = dc_fixpt_mul(t, t);
+ t3 = dc_fixpt_mul(t2, t);
+ temp1 = dc_fixpt_mul(two, t3);
+ temp2 = dc_fixpt_mul(three, t2);
+
+ // (2t^3 - 3t^2 + 1) * ks
+ E2 = dc_fixpt_mul(ks, dc_fixpt_add(dc_fixpt_one,
+ dc_fixpt_sub(temp1, temp2)));
+
+ // (-2t^3 + 3t^2) * max_lum_pq
+ E2 = dc_fixpt_add(E2, dc_fixpt_mul(max_lum_pq,
+ dc_fixpt_sub(temp2, temp1)));
+
+ temp1 = dc_fixpt_mul(two, t2);
+ temp2 = dc_fixpt_sub(dc_fixpt_one, ks);
+
+ // (t^3 - 2t^2 + t) * (1-ks)
+ E2 = dc_fixpt_add(E2, dc_fixpt_mul(temp2,
+ dc_fixpt_add(t, dc_fixpt_sub(t3, temp1))));
+ } else
+ E2 = dc_fixpt_one;
+
+ temp1 = dc_fixpt_sub(dc_fixpt_one, E2);
+ temp2 = dc_fixpt_mul(temp1, temp1);
+ temp2 = dc_fixpt_mul(temp2, temp2);
+ // temp2 = (1-E2)^4
+
+ E3 = dc_fixpt_add(E2, dc_fixpt_mul(min_lum_pq, temp2));
+ compute_de_pq(E3, out_x);
+
+ *out_x = dc_fixpt_div(*out_x, dc_fixpt_div(max_display, max_content));
+}
+
+static bool build_freesync_hdr(struct pwl_float_data_ex *rgb_regamma,
+ uint32_t hw_points_num,
+ const struct hw_x_point *coordinate_x,
+ const struct freesync_hdr_tf_params *fs_params)
+{
+ uint32_t i;
+ struct pwl_float_data_ex *rgb = rgb_regamma;
+ const struct hw_x_point *coord_x = coordinate_x;
+ struct fixed31_32 scaledX = dc_fixpt_zero;
+ struct fixed31_32 scaledX1 = dc_fixpt_zero;
+ struct fixed31_32 max_display = dc_fixpt_from_int(fs_params->max_display);
+ struct fixed31_32 min_display = dc_fixpt_from_fraction(fs_params->min_display, 10000);
+ struct fixed31_32 max_content = dc_fixpt_from_int(fs_params->max_content);
+ struct fixed31_32 min_content = dc_fixpt_from_fraction(fs_params->min_content, 10000);
+ struct fixed31_32 clip = dc_fixpt_one;
+ struct fixed31_32 output;
+ bool use_eetf = false;
+ bool is_clipped = false;
+ struct fixed31_32 sdr_white_level = dc_fixpt_from_int(fs_params->sdr_white_level);
+
+ if (fs_params == NULL || fs_params->max_content == 0 ||
+ fs_params->max_display == 0)
+ return false;
+
+ if (fs_params->min_display > 1000) // cap at 0.1 at the bottom
+ min_display = dc_fixpt_from_fraction(1, 10);
+ if (fs_params->max_display < 100) // cap at 100 at the top
+ max_display = dc_fixpt_from_int(100);
+
+ if (fs_params->min_content < fs_params->min_display)
+ use_eetf = true;
+ else
+ min_content = min_display;
+
+ if (fs_params->max_content > fs_params->max_display)
+ use_eetf = true;
+ else
+ max_content = max_display;
+
+ rgb += 32; // first 32 points have problems with fixed point, too small
+ coord_x += 32;
+ for (i = 32; i <= hw_points_num; i++) {
+ if (!is_clipped) {
+ if (use_eetf) {
+ /*max content is equal 1 */
+ scaledX1 = dc_fixpt_div(coord_x->x,
+ dc_fixpt_div(max_content, sdr_white_level));
+ hermite_spline_eetf(scaledX1, max_display, min_display,
+ max_content, &scaledX);
+ } else
+ scaledX = dc_fixpt_div(coord_x->x,
+ dc_fixpt_div(max_display, sdr_white_level));
+
+ if (dc_fixpt_lt(scaledX, clip)) {
+ if (dc_fixpt_lt(scaledX, dc_fixpt_zero))
+ output = dc_fixpt_zero;
+ else
+ output = calculate_gamma22(scaledX);
+
+ rgb->r = output;
+ rgb->g = output;
+ rgb->b = output;
+ } else {
+ is_clipped = true;
+ rgb->r = clip;
+ rgb->g = clip;
+ rgb->b = clip;
+ }
+ } else {
+ rgb->r = clip;
+ rgb->g = clip;
+ rgb->b = clip;
+ }
+
+ ++coord_x;
+ ++rgb;
+ }
+
+ return true;
+}
+
static void build_degamma(struct pwl_float_data_ex *curve,
uint32_t hw_points_num,
const struct hw_x_point *coordinate_x, bool is_2_4)
@@ -1356,7 +1531,8 @@ static bool map_regamma_hw_to_x_user(
#define _EXTRA_POINTS 3
bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf,
- const struct dc_gamma *ramp, bool mapUserRamp, bool canRomBeUsed)
+ const struct dc_gamma *ramp, bool mapUserRamp, bool canRomBeUsed,
+ const struct freesync_hdr_tf_params *fs_params)
{
struct dc_transfer_func_distributed_points *tf_pts = &output_tf->tf_pts;
struct dividers dividers;
@@ -1374,7 +1550,7 @@ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf,
/* we can use hardcoded curve for plain SRGB TF */
if (output_tf->type == TF_TYPE_PREDEFINED && canRomBeUsed == true &&
output_tf->tf == TRANSFER_FUNCTION_SRGB &&
- (!mapUserRamp && ramp->type == GAMMA_RGB_256))
+ (ramp->is_identity || (!mapUserRamp && ramp->type == GAMMA_RGB_256)))
return true;
output_tf->type = TF_TYPE_DISTRIBUTED_POINTS;
@@ -1424,6 +1600,12 @@ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf,
MAX_HW_POINTS,
coordinates_x,
output_tf->sdr_ref_white_level);
+ } else if (tf == TRANSFER_FUNCTION_GAMMA22 &&
+ fs_params != NULL) {
+ build_freesync_hdr(rgb_regamma,
+ MAX_HW_POINTS,
+ coordinates_x,
+ fs_params);
} else {
tf_pts->end_exponent = 0;
tf_pts->x_point_at_y1_red = 1;
diff --git a/drivers/gpu/drm/amd/display/modules/color/color_gamma.h b/drivers/gpu/drm/amd/display/modules/color/color_gamma.h
index 63ccb9c91224..a6e164df090a 100644
--- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.h
+++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.h
@@ -73,12 +73,21 @@ struct regamma_lut {
};
};
+struct freesync_hdr_tf_params {
+ unsigned int sdr_white_level;
+ unsigned int min_content; // luminance in 1/10000 nits
+ unsigned int max_content; // luminance in nits
+ unsigned int min_display; // luminance in 1/10000 nits
+ unsigned int max_display; // luminance in nits
+};
+
void setup_x_points_distribution(void);
void precompute_pq(void);
void precompute_de_pq(void);
bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf,
- const struct dc_gamma *ramp, bool mapUserRamp, bool canRomBeUsed);
+ const struct dc_gamma *ramp, bool mapUserRamp, bool canRomBeUsed,
+ const struct freesync_hdr_tf_params *fs_params);
bool mod_color_calculate_degamma_params(struct dc_transfer_func *output_tf,
const struct dc_gamma *ramp, bool mapUserRamp);
diff --git a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c
index 4018c7180d00..620a171620ee 100644
--- a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c
+++ b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c
@@ -37,6 +37,8 @@
#define RENDER_TIMES_MAX_COUNT 10
/* Threshold to exit BTR (to avoid frequent enter-exits at the lower limit) */
#define BTR_EXIT_MARGIN 2000
+/*Threshold to exit fixed refresh rate*/
+#define FIXED_REFRESH_EXIT_MARGIN_IN_HZ 4
/* Number of consecutive frames to check before entering/exiting fixed refresh*/
#define FIXED_REFRESH_ENTER_FRAME_COUNT 5
#define FIXED_REFRESH_EXIT_FRAME_COUNT 5
@@ -257,40 +259,14 @@ static void apply_below_the_range(struct core_freesync *core_freesync,
if (in_out_vrr->btr.btr_active) {
in_out_vrr->btr.frame_counter = 0;
in_out_vrr->btr.btr_active = false;
-
- /* Exit Fixed Refresh mode */
- } else if (in_out_vrr->fixed.fixed_active) {
-
- in_out_vrr->fixed.frame_counter++;
-
- if (in_out_vrr->fixed.frame_counter >
- FIXED_REFRESH_EXIT_FRAME_COUNT) {
- in_out_vrr->fixed.frame_counter = 0;
- in_out_vrr->fixed.fixed_active = false;
- }
}
} else if (last_render_time_in_us > max_render_time_in_us) {
/* Enter Below the Range */
- if (!in_out_vrr->btr.btr_active &&
- in_out_vrr->btr.btr_enabled) {
- in_out_vrr->btr.btr_active = true;
-
- /* Enter Fixed Refresh mode */
- } else if (!in_out_vrr->fixed.fixed_active &&
- !in_out_vrr->btr.btr_enabled) {
- in_out_vrr->fixed.frame_counter++;
-
- if (in_out_vrr->fixed.frame_counter >
- FIXED_REFRESH_ENTER_FRAME_COUNT) {
- in_out_vrr->fixed.frame_counter = 0;
- in_out_vrr->fixed.fixed_active = true;
- }
- }
+ in_out_vrr->btr.btr_active = true;
}
/* BTR set to "not active" so disengage */
if (!in_out_vrr->btr.btr_active) {
- in_out_vrr->btr.btr_active = false;
in_out_vrr->btr.inserted_duration_in_us = 0;
in_out_vrr->btr.frames_to_insert = 0;
in_out_vrr->btr.frame_counter = 0;
@@ -375,7 +351,12 @@ static void apply_fixed_refresh(struct core_freesync *core_freesync,
bool update = false;
unsigned int max_render_time_in_us = in_out_vrr->max_duration_in_us;
- if (last_render_time_in_us + BTR_EXIT_MARGIN < max_render_time_in_us) {
+ //Compute the exit refresh rate and exit frame duration
+ unsigned int exit_refresh_rate_in_milli_hz = ((1000000000/max_render_time_in_us)
+ + (1000*FIXED_REFRESH_EXIT_MARGIN_IN_HZ));
+ unsigned int exit_frame_duration_in_us = 1000000000/exit_refresh_rate_in_milli_hz;
+
+ if (last_render_time_in_us < exit_frame_duration_in_us) {
/* Exit Fixed Refresh mode */
if (in_out_vrr->fixed.fixed_active) {
in_out_vrr->fixed.frame_counter++;
diff --git a/drivers/gpu/drm/amd/include/amd_shared.h b/drivers/gpu/drm/amd/include/amd_shared.h
index 2083c308007c..470d7b89071a 100644
--- a/drivers/gpu/drm/amd/include/amd_shared.h
+++ b/drivers/gpu/drm/amd/include/amd_shared.h
@@ -133,6 +133,10 @@ enum PP_FEATURE_MASK {
PP_AVFS_MASK = 0x40000,
};
+enum DC_FEATURE_MASK {
+ DC_FBC_MASK = 0x1,
+};
+
/**
* struct amd_ip_funcs - general hooks for managing amdgpu IP Blocks
*/
diff --git a/drivers/gpu/drm/amd/include/atomfirmware.h b/drivers/gpu/drm/amd/include/atomfirmware.h
index d2e7c0fa96c2..8eb0bb241210 100644
--- a/drivers/gpu/drm/amd/include/atomfirmware.h
+++ b/drivers/gpu/drm/amd/include/atomfirmware.h
@@ -1325,7 +1325,7 @@ struct atom_smu_info_v3_3 {
struct atom_common_table_header table_header;
uint8_t smuip_min_ver;
uint8_t smuip_max_ver;
- uint8_t smu_rsd1;
+ uint8_t waflclk_ss_mode;
uint8_t gpuclk_ss_mode;
uint16_t sclk_ss_percentage;
uint16_t sclk_ss_rate_10hz;
@@ -1355,7 +1355,10 @@ struct atom_smu_info_v3_3 {
uint32_t syspll3_1_vco_freq_10khz;
uint32_t bootup_fclk_10khz;
uint32_t bootup_waflclk_10khz;
- uint32_t reserved[3];
+ uint32_t smu_info_caps;
+ uint16_t waflclk_ss_percentage; // in unit of 0.001%
+ uint16_t smuinitoffset;
+ uint32_t reserved;
};
/*
diff --git a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h
index 64ecffd52126..58ac0b90c310 100644
--- a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h
+++ b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h
@@ -205,20 +205,6 @@ struct tile_config {
/**
* struct kfd2kgd_calls
*
- * @init_gtt_mem_allocation: Allocate a buffer on the gart aperture.
- * The buffer can be used for mqds, hpds, kernel queue, fence and runlists
- *
- * @free_gtt_mem: Frees a buffer that was allocated on the gart aperture
- *
- * @get_local_mem_info: Retrieves information about GPU local memory
- *
- * @get_gpu_clock_counter: Retrieves GPU clock counter
- *
- * @get_max_engine_clock_in_mhz: Retrieves maximum GPU clock in MHz
- *
- * @alloc_pasid: Allocate a PASID
- * @free_pasid: Free a PASID
- *
* @program_sh_mem_settings: A function that should initiate the memory
* properties such as main aperture memory type (cache / non cached) and
* secondary aperture base address, size and memory type.
@@ -255,64 +241,16 @@ struct tile_config {
*
* @get_tile_config: Returns GPU-specific tiling mode information
*
- * @get_cu_info: Retrieves activated cu info
- *
- * @get_vram_usage: Returns current VRAM usage
- *
- * @create_process_vm: Create a VM address space for a given process and GPU
- *
- * @destroy_process_vm: Destroy a VM
- *
- * @get_process_page_dir: Get physical address of a VM page directory
- *
* @set_vm_context_page_table_base: Program page table base for a VMID
*
- * @alloc_memory_of_gpu: Allocate GPUVM memory
- *
- * @free_memory_of_gpu: Free GPUVM memory
- *
- * @map_memory_to_gpu: Map GPUVM memory into a specific VM address
- * space. Allocates and updates page tables and page directories as
- * needed. This function may return before all page table updates have
- * completed. This allows multiple map operations (on multiple GPUs)
- * to happen concurrently. Use sync_memory to synchronize with all
- * pending updates.
- *
- * @unmap_memor_to_gpu: Unmap GPUVM memory from a specific VM address space
- *
- * @sync_memory: Wait for pending page table updates to complete
- *
- * @map_gtt_bo_to_kernel: Map a GTT BO for kernel access
- * Pins the BO, maps it to kernel address space. Such BOs are never evicted.
- * The kernel virtual address remains valid until the BO is freed.
- *
- * @restore_process_bos: Restore all BOs that belong to the
- * process. This is intended for restoring memory mappings after a TTM
- * eviction.
- *
* @invalidate_tlbs: Invalidate TLBs for a specific PASID
*
* @invalidate_tlbs_vmid: Invalidate TLBs for a specific VMID
*
- * @submit_ib: Submits an IB to the engine specified by inserting the
- * IB to the corresponding ring (ring type). The IB is executed with the
- * specified VMID in a user mode context.
- *
- * @get_vm_fault_info: Return information about a recent VM fault on
- * GFXv7 and v8. If multiple VM faults occurred since the last call of
- * this function, it will return information about the first of those
- * faults. On GFXv9 VM fault information is fully contained in the IH
- * packet and this function is not needed.
- *
* @read_vmid_from_vmfault_reg: On Hawaii the VMID is not set in the
* IH ring entry. This function allows the KFD ISR to get the VMID
* from the fault status register as early as possible.
*
- * @gpu_recover: let kgd reset gpu after kfd detect CPC hang
- *
- * @set_compute_idle: Indicates that compute is idle on a device. This
- * can be used to change power profiles depending on compute activity.
- *
* @get_hive_id: Returns hive id of current device, 0 if xgmi is not enabled
*
* This structure contains function pointers to services that the kgd driver
@@ -320,21 +258,6 @@ struct tile_config {
*
*/
struct kfd2kgd_calls {
- int (*init_gtt_mem_allocation)(struct kgd_dev *kgd, size_t size,
- void **mem_obj, uint64_t *gpu_addr,
- void **cpu_ptr, bool mqd_gfx9);
-
- void (*free_gtt_mem)(struct kgd_dev *kgd, void *mem_obj);
-
- void (*get_local_mem_info)(struct kgd_dev *kgd,
- struct kfd_local_mem_info *mem_info);
- uint64_t (*get_gpu_clock_counter)(struct kgd_dev *kgd);
-
- uint32_t (*get_max_engine_clock_in_mhz)(struct kgd_dev *kgd);
-
- int (*alloc_pasid)(unsigned int bits);
- void (*free_pasid)(unsigned int pasid);
-
/* Register access functions */
void (*program_sh_mem_settings)(struct kgd_dev *kgd, uint32_t vmid,
uint32_t sh_mem_config, uint32_t sh_mem_ape1_base,
@@ -398,49 +321,11 @@ struct kfd2kgd_calls {
uint64_t va, uint32_t vmid);
int (*get_tile_config)(struct kgd_dev *kgd, struct tile_config *config);
- void (*get_cu_info)(struct kgd_dev *kgd,
- struct kfd_cu_info *cu_info);
- uint64_t (*get_vram_usage)(struct kgd_dev *kgd);
-
- int (*create_process_vm)(struct kgd_dev *kgd, unsigned int pasid, void **vm,
- void **process_info, struct dma_fence **ef);
- int (*acquire_process_vm)(struct kgd_dev *kgd, struct file *filp,
- unsigned int pasid, void **vm, void **process_info,
- struct dma_fence **ef);
- void (*destroy_process_vm)(struct kgd_dev *kgd, void *vm);
- void (*release_process_vm)(struct kgd_dev *kgd, void *vm);
- uint64_t (*get_process_page_dir)(void *vm);
void (*set_vm_context_page_table_base)(struct kgd_dev *kgd,
uint32_t vmid, uint64_t page_table_base);
- int (*alloc_memory_of_gpu)(struct kgd_dev *kgd, uint64_t va,
- uint64_t size, void *vm,
- struct kgd_mem **mem, uint64_t *offset,
- uint32_t flags);
- int (*free_memory_of_gpu)(struct kgd_dev *kgd, struct kgd_mem *mem);
- int (*map_memory_to_gpu)(struct kgd_dev *kgd, struct kgd_mem *mem,
- void *vm);
- int (*unmap_memory_to_gpu)(struct kgd_dev *kgd, struct kgd_mem *mem,
- void *vm);
- int (*sync_memory)(struct kgd_dev *kgd, struct kgd_mem *mem, bool intr);
- int (*map_gtt_bo_to_kernel)(struct kgd_dev *kgd, struct kgd_mem *mem,
- void **kptr, uint64_t *size);
- int (*restore_process_bos)(void *process_info, struct dma_fence **ef);
-
int (*invalidate_tlbs)(struct kgd_dev *kgd, uint16_t pasid);
int (*invalidate_tlbs_vmid)(struct kgd_dev *kgd, uint16_t vmid);
-
- int (*submit_ib)(struct kgd_dev *kgd, enum kgd_engine_type engine,
- uint32_t vmid, uint64_t gpu_addr,
- uint32_t *ib_cmd, uint32_t ib_len);
-
- int (*get_vm_fault_info)(struct kgd_dev *kgd,
- struct kfd_vm_fault_info *info);
uint32_t (*read_vmid_from_vmfault_reg)(struct kgd_dev *kgd);
-
- void (*gpu_recover)(struct kgd_dev *kgd);
-
- void (*set_compute_idle)(struct kgd_dev *kgd, bool idle);
-
uint64_t (*get_hive_id)(struct kgd_dev *kgd);
};
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c
index 5e19f5977eb1..d138ddae563d 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c
@@ -967,7 +967,7 @@ int smu7_enable_didt_config(struct pp_hwmgr *hwmgr)
PP_CAP(PHM_PlatformCaps_TDRamping) ||
PP_CAP(PHM_PlatformCaps_TCPRamping)) {
- adev->gfx.rlc.funcs->enter_safe_mode(adev);
+ amdgpu_gfx_rlc_enter_safe_mode(adev);
mutex_lock(&adev->grbm_idx_mutex);
value = 0;
value2 = cgs_read_register(hwmgr->device, mmGRBM_GFX_INDEX);
@@ -1014,13 +1014,13 @@ int smu7_enable_didt_config(struct pp_hwmgr *hwmgr)
"Failed to enable DPM DIDT.", goto error);
}
mutex_unlock(&adev->grbm_idx_mutex);
- adev->gfx.rlc.funcs->exit_safe_mode(adev);
+ amdgpu_gfx_rlc_exit_safe_mode(adev);
}
return 0;
error:
mutex_unlock(&adev->grbm_idx_mutex);
- adev->gfx.rlc.funcs->exit_safe_mode(adev);
+ amdgpu_gfx_rlc_exit_safe_mode(adev);
return result;
}
@@ -1034,7 +1034,7 @@ int smu7_disable_didt_config(struct pp_hwmgr *hwmgr)
PP_CAP(PHM_PlatformCaps_TDRamping) ||
PP_CAP(PHM_PlatformCaps_TCPRamping)) {
- adev->gfx.rlc.funcs->enter_safe_mode(adev);
+ amdgpu_gfx_rlc_enter_safe_mode(adev);
result = smu7_enable_didt(hwmgr, false);
PP_ASSERT_WITH_CODE((result == 0),
@@ -1046,12 +1046,12 @@ int smu7_disable_didt_config(struct pp_hwmgr *hwmgr)
PP_ASSERT_WITH_CODE((0 == result),
"Failed to disable DPM DIDT.", goto error);
}
- adev->gfx.rlc.funcs->exit_safe_mode(adev);
+ amdgpu_gfx_rlc_exit_safe_mode(adev);
}
return 0;
error:
- adev->gfx.rlc.funcs->exit_safe_mode(adev);
+ amdgpu_gfx_rlc_exit_safe_mode(adev);
return result;
}
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.c
index 99a33c33a32c..101c09b212ad 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.c
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.c
@@ -713,20 +713,20 @@ int smu_set_watermarks_for_clocks_ranges(void *wt_table,
for (i = 0; i < wm_with_clock_ranges->num_wm_dmif_sets; i++) {
table->WatermarkRow[1][i].MinClock =
cpu_to_le16((uint16_t)
- (wm_with_clock_ranges->wm_dmif_clocks_ranges[i].wm_min_dcfclk_clk_in_khz) /
- 1000);
+ (wm_with_clock_ranges->wm_dmif_clocks_ranges[i].wm_min_dcfclk_clk_in_khz /
+ 1000));
table->WatermarkRow[1][i].MaxClock =
cpu_to_le16((uint16_t)
- (wm_with_clock_ranges->wm_dmif_clocks_ranges[i].wm_max_dcfclk_clk_in_khz) /
- 1000);
+ (wm_with_clock_ranges->wm_dmif_clocks_ranges[i].wm_max_dcfclk_clk_in_khz /
+ 1000));
table->WatermarkRow[1][i].MinUclk =
cpu_to_le16((uint16_t)
- (wm_with_clock_ranges->wm_dmif_clocks_ranges[i].wm_min_mem_clk_in_khz) /
- 1000);
+ (wm_with_clock_ranges->wm_dmif_clocks_ranges[i].wm_min_mem_clk_in_khz /
+ 1000));
table->WatermarkRow[1][i].MaxUclk =
cpu_to_le16((uint16_t)
- (wm_with_clock_ranges->wm_dmif_clocks_ranges[i].wm_max_mem_clk_in_khz) /
- 1000);
+ (wm_with_clock_ranges->wm_dmif_clocks_ranges[i].wm_max_mem_clk_in_khz /
+ 1000));
table->WatermarkRow[1][i].WmSetting = (uint8_t)
wm_with_clock_ranges->wm_dmif_clocks_ranges[i].wm_set_id;
}
@@ -734,20 +734,20 @@ int smu_set_watermarks_for_clocks_ranges(void *wt_table,
for (i = 0; i < wm_with_clock_ranges->num_wm_mcif_sets; i++) {
table->WatermarkRow[0][i].MinClock =
cpu_to_le16((uint16_t)
- (wm_with_clock_ranges->wm_mcif_clocks_ranges[i].wm_min_socclk_clk_in_khz) /
- 1000);
+ (wm_with_clock_ranges->wm_mcif_clocks_ranges[i].wm_min_socclk_clk_in_khz /
+ 1000));
table->WatermarkRow[0][i].MaxClock =
cpu_to_le16((uint16_t)
- (wm_with_clock_ranges->wm_mcif_clocks_ranges[i].wm_max_socclk_clk_in_khz) /
- 1000);
+ (wm_with_clock_ranges->wm_mcif_clocks_ranges[i].wm_max_socclk_clk_in_khz /
+ 1000));
table->WatermarkRow[0][i].MinUclk =
cpu_to_le16((uint16_t)
- (wm_with_clock_ranges->wm_mcif_clocks_ranges[i].wm_min_mem_clk_in_khz) /
- 1000);
+ (wm_with_clock_ranges->wm_mcif_clocks_ranges[i].wm_min_mem_clk_in_khz /
+ 1000));
table->WatermarkRow[0][i].MaxUclk =
cpu_to_le16((uint16_t)
- (wm_with_clock_ranges->wm_mcif_clocks_ranges[i].wm_max_mem_clk_in_khz) /
- 1000);
+ (wm_with_clock_ranges->wm_mcif_clocks_ranges[i].wm_max_mem_clk_in_khz /
+ 1000));
table->WatermarkRow[0][i].WmSetting = (uint8_t)
wm_with_clock_ranges->wm_mcif_clocks_ranges[i].wm_set_id;
}
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c
index 2d88abf97e7b..6f26cb241ecc 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c
@@ -937,7 +937,7 @@ static int vega10_enable_cac_driving_se_didt_config(struct pp_hwmgr *hwmgr)
num_se = adev->gfx.config.max_shader_engines;
- adev->gfx.rlc.funcs->enter_safe_mode(adev);
+ amdgpu_gfx_rlc_enter_safe_mode(adev);
mutex_lock(&adev->grbm_idx_mutex);
for (count = 0; count < num_se; count++) {
@@ -962,7 +962,7 @@ static int vega10_enable_cac_driving_se_didt_config(struct pp_hwmgr *hwmgr)
vega10_didt_set_mask(hwmgr, true);
- adev->gfx.rlc.funcs->exit_safe_mode(adev);
+ amdgpu_gfx_rlc_exit_safe_mode(adev);
return 0;
}
@@ -971,11 +971,11 @@ static int vega10_disable_cac_driving_se_didt_config(struct pp_hwmgr *hwmgr)
{
struct amdgpu_device *adev = hwmgr->adev;
- adev->gfx.rlc.funcs->enter_safe_mode(adev);
+ amdgpu_gfx_rlc_enter_safe_mode(adev);
vega10_didt_set_mask(hwmgr, false);
- adev->gfx.rlc.funcs->exit_safe_mode(adev);
+ amdgpu_gfx_rlc_exit_safe_mode(adev);
return 0;
}
@@ -988,7 +988,7 @@ static int vega10_enable_psm_gc_didt_config(struct pp_hwmgr *hwmgr)
num_se = adev->gfx.config.max_shader_engines;
- adev->gfx.rlc.funcs->enter_safe_mode(adev);
+ amdgpu_gfx_rlc_enter_safe_mode(adev);
mutex_lock(&adev->grbm_idx_mutex);
for (count = 0; count < num_se; count++) {
@@ -1007,7 +1007,7 @@ static int vega10_enable_psm_gc_didt_config(struct pp_hwmgr *hwmgr)
vega10_didt_set_mask(hwmgr, true);
- adev->gfx.rlc.funcs->exit_safe_mode(adev);
+ amdgpu_gfx_rlc_exit_safe_mode(adev);
vega10_program_gc_didt_config_registers(hwmgr, GCDiDtDroopCtrlConfig_vega10);
if (PP_CAP(PHM_PlatformCaps_GCEDC))
@@ -1024,11 +1024,11 @@ static int vega10_disable_psm_gc_didt_config(struct pp_hwmgr *hwmgr)
struct amdgpu_device *adev = hwmgr->adev;
uint32_t data;
- adev->gfx.rlc.funcs->enter_safe_mode(adev);
+ amdgpu_gfx_rlc_enter_safe_mode(adev);
vega10_didt_set_mask(hwmgr, false);
- adev->gfx.rlc.funcs->exit_safe_mode(adev);
+ amdgpu_gfx_rlc_exit_safe_mode(adev);
if (PP_CAP(PHM_PlatformCaps_GCEDC)) {
data = 0x00000000;
@@ -1049,7 +1049,7 @@ static int vega10_enable_se_edc_config(struct pp_hwmgr *hwmgr)
num_se = adev->gfx.config.max_shader_engines;
- adev->gfx.rlc.funcs->enter_safe_mode(adev);
+ amdgpu_gfx_rlc_enter_safe_mode(adev);
mutex_lock(&adev->grbm_idx_mutex);
for (count = 0; count < num_se; count++) {
@@ -1070,7 +1070,7 @@ static int vega10_enable_se_edc_config(struct pp_hwmgr *hwmgr)
vega10_didt_set_mask(hwmgr, true);
- adev->gfx.rlc.funcs->exit_safe_mode(adev);
+ amdgpu_gfx_rlc_exit_safe_mode(adev);
return 0;
}
@@ -1079,11 +1079,11 @@ static int vega10_disable_se_edc_config(struct pp_hwmgr *hwmgr)
{
struct amdgpu_device *adev = hwmgr->adev;
- adev->gfx.rlc.funcs->enter_safe_mode(adev);
+ amdgpu_gfx_rlc_enter_safe_mode(adev);
vega10_didt_set_mask(hwmgr, false);
- adev->gfx.rlc.funcs->exit_safe_mode(adev);
+ amdgpu_gfx_rlc_exit_safe_mode(adev);
return 0;
}
@@ -1097,7 +1097,7 @@ static int vega10_enable_psm_gc_edc_config(struct pp_hwmgr *hwmgr)
num_se = adev->gfx.config.max_shader_engines;
- adev->gfx.rlc.funcs->enter_safe_mode(adev);
+ amdgpu_gfx_rlc_enter_safe_mode(adev);
vega10_program_gc_didt_config_registers(hwmgr, AvfsPSMResetConfig_vega10);
@@ -1118,7 +1118,7 @@ static int vega10_enable_psm_gc_edc_config(struct pp_hwmgr *hwmgr)
vega10_didt_set_mask(hwmgr, true);
- adev->gfx.rlc.funcs->exit_safe_mode(adev);
+ amdgpu_gfx_rlc_exit_safe_mode(adev);
vega10_program_gc_didt_config_registers(hwmgr, PSMGCEDCDroopCtrlConfig_vega10);
@@ -1138,11 +1138,11 @@ static int vega10_disable_psm_gc_edc_config(struct pp_hwmgr *hwmgr)
struct amdgpu_device *adev = hwmgr->adev;
uint32_t data;
- adev->gfx.rlc.funcs->enter_safe_mode(adev);
+ amdgpu_gfx_rlc_enter_safe_mode(adev);
vega10_didt_set_mask(hwmgr, false);
- adev->gfx.rlc.funcs->exit_safe_mode(adev);
+ amdgpu_gfx_rlc_exit_safe_mode(adev);
if (PP_CAP(PHM_PlatformCaps_GCEDC)) {
data = 0x00000000;
@@ -1160,7 +1160,7 @@ static int vega10_enable_se_edc_force_stall_config(struct pp_hwmgr *hwmgr)
struct amdgpu_device *adev = hwmgr->adev;
int result;
- adev->gfx.rlc.funcs->enter_safe_mode(adev);
+ amdgpu_gfx_rlc_enter_safe_mode(adev);
mutex_lock(&adev->grbm_idx_mutex);
WREG32_SOC15(GC, 0, mmGRBM_GFX_INDEX, 0xE0000000);
@@ -1173,7 +1173,7 @@ static int vega10_enable_se_edc_force_stall_config(struct pp_hwmgr *hwmgr)
vega10_didt_set_mask(hwmgr, false);
- adev->gfx.rlc.funcs->exit_safe_mode(adev);
+ amdgpu_gfx_rlc_exit_safe_mode(adev);
return 0;
}
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c
index 57143d51e3ee..f2daf00cc911 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c
@@ -120,6 +120,7 @@ static void vega20_set_default_registry_data(struct pp_hwmgr *hwmgr)
data->registry_data.disable_auto_wattman = 1;
data->registry_data.auto_wattman_debug = 0;
data->registry_data.auto_wattman_sample_period = 100;
+ data->registry_data.fclk_gfxclk_ratio = 0x3F6CCCCD;
data->registry_data.auto_wattman_threshold = 50;
data->registry_data.gfxoff_controlled_by_driver = 1;
data->gfxoff_allowed = false;
@@ -829,6 +830,28 @@ static int vega20_enable_all_smu_features(struct pp_hwmgr *hwmgr)
return 0;
}
+static int vega20_notify_smc_display_change(struct pp_hwmgr *hwmgr)
+{
+ struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
+
+ if (data->smu_features[GNLD_DPM_UCLK].enabled)
+ return smum_send_msg_to_smc_with_parameter(hwmgr,
+ PPSMC_MSG_SetUclkFastSwitch,
+ 1);
+
+ return 0;
+}
+
+static int vega20_send_clock_ratio(struct pp_hwmgr *hwmgr)
+{
+ struct vega20_hwmgr *data =
+ (struct vega20_hwmgr *)(hwmgr->backend);
+
+ return smum_send_msg_to_smc_with_parameter(hwmgr,
+ PPSMC_MSG_SetFclkGfxClkRatio,
+ data->registry_data.fclk_gfxclk_ratio);
+}
+
static int vega20_disable_all_smu_features(struct pp_hwmgr *hwmgr)
{
struct vega20_hwmgr *data =
@@ -1532,6 +1555,16 @@ static int vega20_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
"[EnableDPMTasks] Failed to enable all smu features!",
return result);
+ result = vega20_notify_smc_display_change(hwmgr);
+ PP_ASSERT_WITH_CODE(!result,
+ "[EnableDPMTasks] Failed to notify smc display change!",
+ return result);
+
+ result = vega20_send_clock_ratio(hwmgr);
+ PP_ASSERT_WITH_CODE(!result,
+ "[EnableDPMTasks] Failed to send clock ratio!",
+ return result);
+
/* Initialize UVD/VCE powergating state */
vega20_init_powergate_state(hwmgr);
@@ -1972,19 +2005,6 @@ static int vega20_read_sensor(struct pp_hwmgr *hwmgr, int idx,
return ret;
}
-static int vega20_notify_smc_display_change(struct pp_hwmgr *hwmgr,
- bool has_disp)
-{
- struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
-
- if (data->smu_features[GNLD_DPM_UCLK].enabled)
- return smum_send_msg_to_smc_with_parameter(hwmgr,
- PPSMC_MSG_SetUclkFastSwitch,
- has_disp ? 1 : 0);
-
- return 0;
-}
-
int vega20_display_clock_voltage_request(struct pp_hwmgr *hwmgr,
struct pp_display_clock_request *clock_req)
{
@@ -2044,13 +2064,6 @@ static int vega20_notify_smc_display_config_after_ps_adjustment(
struct pp_display_clock_request clock_req;
int ret = 0;
- if ((hwmgr->display_config->num_display > 1) &&
- !hwmgr->display_config->multi_monitor_in_sync &&
- !hwmgr->display_config->nb_pstate_switch_disable)
- vega20_notify_smc_display_change(hwmgr, false);
- else
- vega20_notify_smc_display_change(hwmgr, true);
-
min_clocks.dcefClock = hwmgr->display_config->min_dcef_set_clk;
min_clocks.dcefClockInSR = hwmgr->display_config->min_dcef_deep_sleep_set_clk;
min_clocks.memoryClock = hwmgr->display_config->min_mem_set_clock;
@@ -2742,7 +2755,7 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
for (i = 0; i < clocks.num_levels; i++)
size += sprintf(buf + size, "%d: %uMhz %s\n",
i, clocks.data[i].clocks_in_khz / 1000,
- (clocks.data[i].clocks_in_khz == now) ? "*" : "");
+ (clocks.data[i].clocks_in_khz == now * 10) ? "*" : "");
break;
case PP_MCLK:
@@ -2759,7 +2772,7 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
for (i = 0; i < clocks.num_levels; i++)
size += sprintf(buf + size, "%d: %uMhz %s\n",
i, clocks.data[i].clocks_in_khz / 1000,
- (clocks.data[i].clocks_in_khz == now) ? "*" : "");
+ (clocks.data[i].clocks_in_khz == now * 10) ? "*" : "");
break;
case PP_PCIE:
@@ -3441,109 +3454,64 @@ static int vega20_get_thermal_temperature_range(struct pp_hwmgr *hwmgr,
static const struct pp_hwmgr_func vega20_hwmgr_funcs = {
/* init/fini related */
- .backend_init =
- vega20_hwmgr_backend_init,
- .backend_fini =
- vega20_hwmgr_backend_fini,
- .asic_setup =
- vega20_setup_asic_task,
- .power_off_asic =
- vega20_power_off_asic,
- .dynamic_state_management_enable =
- vega20_enable_dpm_tasks,
- .dynamic_state_management_disable =
- vega20_disable_dpm_tasks,
+ .backend_init = vega20_hwmgr_backend_init,
+ .backend_fini = vega20_hwmgr_backend_fini,
+ .asic_setup = vega20_setup_asic_task,
+ .power_off_asic = vega20_power_off_asic,
+ .dynamic_state_management_enable = vega20_enable_dpm_tasks,
+ .dynamic_state_management_disable = vega20_disable_dpm_tasks,
/* power state related */
- .apply_clocks_adjust_rules =
- vega20_apply_clocks_adjust_rules,
- .pre_display_config_changed =
- vega20_pre_display_configuration_changed_task,
- .display_config_changed =
- vega20_display_configuration_changed_task,
+ .apply_clocks_adjust_rules = vega20_apply_clocks_adjust_rules,
+ .pre_display_config_changed = vega20_pre_display_configuration_changed_task,
+ .display_config_changed = vega20_display_configuration_changed_task,
.check_smc_update_required_for_display_configuration =
vega20_check_smc_update_required_for_display_configuration,
.notify_smc_display_config_after_ps_adjustment =
vega20_notify_smc_display_config_after_ps_adjustment,
/* export to DAL */
- .get_sclk =
- vega20_dpm_get_sclk,
- .get_mclk =
- vega20_dpm_get_mclk,
- .get_dal_power_level =
- vega20_get_dal_power_level,
- .get_clock_by_type_with_latency =
- vega20_get_clock_by_type_with_latency,
- .get_clock_by_type_with_voltage =
- vega20_get_clock_by_type_with_voltage,
- .set_watermarks_for_clocks_ranges =
- vega20_set_watermarks_for_clocks_ranges,
- .display_clock_voltage_request =
- vega20_display_clock_voltage_request,
- .get_performance_level =
- vega20_get_performance_level,
+ .get_sclk = vega20_dpm_get_sclk,
+ .get_mclk = vega20_dpm_get_mclk,
+ .get_dal_power_level = vega20_get_dal_power_level,
+ .get_clock_by_type_with_latency = vega20_get_clock_by_type_with_latency,
+ .get_clock_by_type_with_voltage = vega20_get_clock_by_type_with_voltage,
+ .set_watermarks_for_clocks_ranges = vega20_set_watermarks_for_clocks_ranges,
+ .display_clock_voltage_request = vega20_display_clock_voltage_request,
+ .get_performance_level = vega20_get_performance_level,
/* UMD pstate, profile related */
- .force_dpm_level =
- vega20_dpm_force_dpm_level,
- .get_power_profile_mode =
- vega20_get_power_profile_mode,
- .set_power_profile_mode =
- vega20_set_power_profile_mode,
+ .force_dpm_level = vega20_dpm_force_dpm_level,
+ .get_power_profile_mode = vega20_get_power_profile_mode,
+ .set_power_profile_mode = vega20_set_power_profile_mode,
/* od related */
- .set_power_limit =
- vega20_set_power_limit,
- .get_sclk_od =
- vega20_get_sclk_od,
- .set_sclk_od =
- vega20_set_sclk_od,
- .get_mclk_od =
- vega20_get_mclk_od,
- .set_mclk_od =
- vega20_set_mclk_od,
- .odn_edit_dpm_table =
- vega20_odn_edit_dpm_table,
+ .set_power_limit = vega20_set_power_limit,
+ .get_sclk_od = vega20_get_sclk_od,
+ .set_sclk_od = vega20_set_sclk_od,
+ .get_mclk_od = vega20_get_mclk_od,
+ .set_mclk_od = vega20_set_mclk_od,
+ .odn_edit_dpm_table = vega20_odn_edit_dpm_table,
/* for sysfs to retrive/set gfxclk/memclk */
- .force_clock_level =
- vega20_force_clock_level,
- .print_clock_levels =
- vega20_print_clock_levels,
- .read_sensor =
- vega20_read_sensor,
+ .force_clock_level = vega20_force_clock_level,
+ .print_clock_levels = vega20_print_clock_levels,
+ .read_sensor = vega20_read_sensor,
/* powergate related */
- .powergate_uvd =
- vega20_power_gate_uvd,
- .powergate_vce =
- vega20_power_gate_vce,
+ .powergate_uvd = vega20_power_gate_uvd,
+ .powergate_vce = vega20_power_gate_vce,
/* thermal related */
- .start_thermal_controller =
- vega20_start_thermal_controller,
- .stop_thermal_controller =
- vega20_thermal_stop_thermal_controller,
- .get_thermal_temperature_range =
- vega20_get_thermal_temperature_range,
- .register_irq_handlers =
- smu9_register_irq_handlers,
- .disable_smc_firmware_ctf =
- vega20_thermal_disable_alert,
+ .start_thermal_controller = vega20_start_thermal_controller,
+ .stop_thermal_controller = vega20_thermal_stop_thermal_controller,
+ .get_thermal_temperature_range = vega20_get_thermal_temperature_range,
+ .register_irq_handlers = smu9_register_irq_handlers,
+ .disable_smc_firmware_ctf = vega20_thermal_disable_alert,
/* fan control related */
- .get_fan_speed_percent =
- vega20_fan_ctrl_get_fan_speed_percent,
- .set_fan_speed_percent =
- vega20_fan_ctrl_set_fan_speed_percent,
- .get_fan_speed_info =
- vega20_fan_ctrl_get_fan_speed_info,
- .get_fan_speed_rpm =
- vega20_fan_ctrl_get_fan_speed_rpm,
- .set_fan_speed_rpm =
- vega20_fan_ctrl_set_fan_speed_rpm,
- .get_fan_control_mode =
- vega20_get_fan_control_mode,
- .set_fan_control_mode =
- vega20_set_fan_control_mode,
+ .get_fan_speed_percent = vega20_fan_ctrl_get_fan_speed_percent,
+ .set_fan_speed_percent = vega20_fan_ctrl_set_fan_speed_percent,
+ .get_fan_speed_info = vega20_fan_ctrl_get_fan_speed_info,
+ .get_fan_speed_rpm = vega20_fan_ctrl_get_fan_speed_rpm,
+ .set_fan_speed_rpm = vega20_fan_ctrl_set_fan_speed_rpm,
+ .get_fan_control_mode = vega20_get_fan_control_mode,
+ .set_fan_control_mode = vega20_set_fan_control_mode,
/* smu memory related */
- .notify_cac_buffer_info =
- vega20_notify_cac_buffer_info,
- .enable_mgpu_fan_boost =
- vega20_enable_mgpu_fan_boost,
+ .notify_cac_buffer_info = vega20_notify_cac_buffer_info,
+ .enable_mgpu_fan_boost = vega20_enable_mgpu_fan_boost,
};
int vega20_hwmgr_init(struct pp_hwmgr *hwmgr)
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.h b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.h
index 56fe6a0d42e8..25faaa5c5b10 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.h
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.h
@@ -328,6 +328,7 @@ struct vega20_registry_data {
uint8_t disable_auto_wattman;
uint32_t auto_wattman_debug;
uint32_t auto_wattman_sample_period;
+ uint32_t fclk_gfxclk_ratio;
uint8_t auto_wattman_threshold;
uint8_t log_avfs_param;
uint8_t enable_enginess;
diff --git a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h
index e5a60aa44b5d..07d180ce4d18 100644
--- a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h
+++ b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h
@@ -28,7 +28,6 @@
#include "hardwaremanager.h"
#include "hwmgr_ppt.h"
#include "ppatomctrl.h"
-#include "hwmgr_ppt.h"
#include "power_state.h"
#include "smu_helper.h"
diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu7_common.h b/drivers/gpu/drm/amd/powerplay/inc/smu7_common.h
index 65eb630bfea3..94bf7b649c20 100644
--- a/drivers/gpu/drm/amd/powerplay/inc/smu7_common.h
+++ b/drivers/gpu/drm/amd/powerplay/inc/smu7_common.h
@@ -40,10 +40,6 @@
#include "bif/bif_5_0_d.h"
#include "bif/bif_5_0_sh_mask.h"
-
-#include "bif/bif_5_0_d.h"
-#include "bif/bif_5_0_sh_mask.h"
-
#include "dce/dce_10_0_d.h"
#include "dce/dce_10_0_sh_mask.h"
diff --git a/drivers/gpu/drm/amd/powerplay/inc/vega20_ppsmc.h b/drivers/gpu/drm/amd/powerplay/inc/vega20_ppsmc.h
index 45d64a81e945..4f63a736ea0e 100644
--- a/drivers/gpu/drm/amd/powerplay/inc/vega20_ppsmc.h
+++ b/drivers/gpu/drm/amd/powerplay/inc/vega20_ppsmc.h
@@ -105,7 +105,8 @@
#define PPSMC_MSG_SetSystemVirtualDramAddrHigh 0x4B
#define PPSMC_MSG_SetSystemVirtualDramAddrLow 0x4C
#define PPSMC_MSG_WaflTest 0x4D
-// Unused ID 0x4E to 0x50
+#define PPSMC_MSG_SetFclkGfxClkRatio 0x4E
+// Unused ID 0x4F to 0x50
#define PPSMC_MSG_AllowGfxOff 0x51
#define PPSMC_MSG_DisallowGfxOff 0x52
#define PPSMC_MSG_GetPptLimit 0x53
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c
index 872d3824337b..2b2c26616902 100644
--- a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c
+++ b/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c
@@ -44,7 +44,6 @@
#include "smu7_hwmgr.h"
#include "hardwaremanager.h"
-#include "ppatomctrl.h"
#include "atombios.h"
#include "pppcielanes.h"
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu10_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smu10_smumgr.c
index d0eb8ab50148..d111dd4e03d7 100644
--- a/drivers/gpu/drm/amd/powerplay/smumgr/smu10_smumgr.c
+++ b/drivers/gpu/drm/amd/powerplay/smumgr/smu10_smumgr.c
@@ -29,7 +29,6 @@
#include "rv_ppsmc.h"
#include "smu10_driver_if.h"
#include "smu10.h"
-#include "ppatomctrl.h"
#include "pp_debug.h"
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c
index 09b844ec3eab..e2787e14a500 100644
--- a/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c
+++ b/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c
@@ -24,6 +24,7 @@
#include <linux/delay.h>
#include <linux/gfp.h>
#include <linux/kernel.h>
+#include <linux/ktime.h>
#include <linux/slab.h>
#include <linux/types.h>
@@ -61,9 +62,13 @@ static uint32_t smu8_get_argument(struct pp_hwmgr *hwmgr)
mmSMU_MP1_SRBM2P_ARG_0);
}
-static int smu8_send_msg_to_smc_async(struct pp_hwmgr *hwmgr, uint16_t msg)
+/* Send a message to the SMC, and wait for its response.*/
+static int smu8_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr,
+ uint16_t msg, uint32_t parameter)
{
int result = 0;
+ ktime_t t_start;
+ s64 elapsed_us;
if (hwmgr == NULL || hwmgr->device == NULL)
return -EINVAL;
@@ -74,28 +79,31 @@ static int smu8_send_msg_to_smc_async(struct pp_hwmgr *hwmgr, uint16_t msg)
/* Read the last message to SMU, to report actual cause */
uint32_t val = cgs_read_register(hwmgr->device,
mmSMU_MP1_SRBM2P_MSG_0);
- pr_err("smu8_send_msg_to_smc_async (0x%04x) failed\n", msg);
- pr_err("SMU still servicing msg (0x%04x)\n", val);
+ pr_err("%s(0x%04x) aborted; SMU still servicing msg (0x%04x)\n",
+ __func__, msg, val);
return result;
}
+ t_start = ktime_get();
+
+ cgs_write_register(hwmgr->device, mmSMU_MP1_SRBM2P_ARG_0, parameter);
cgs_write_register(hwmgr->device, mmSMU_MP1_SRBM2P_RESP_0, 0);
cgs_write_register(hwmgr->device, mmSMU_MP1_SRBM2P_MSG_0, msg);
- return 0;
+ result = PHM_WAIT_FIELD_UNEQUAL(hwmgr,
+ SMU_MP1_SRBM2P_RESP_0, CONTENT, 0);
+
+ elapsed_us = ktime_us_delta(ktime_get(), t_start);
+
+ WARN(result, "%s(0x%04x, %#x) timed out after %lld us\n",
+ __func__, msg, parameter, elapsed_us);
+
+ return result;
}
-/* Send a message to the SMC, and wait for its response.*/
static int smu8_send_msg_to_smc(struct pp_hwmgr *hwmgr, uint16_t msg)
{
- int result = 0;
-
- result = smu8_send_msg_to_smc_async(hwmgr, msg);
- if (result != 0)
- return result;
-
- return PHM_WAIT_FIELD_UNEQUAL(hwmgr,
- SMU_MP1_SRBM2P_RESP_0, CONTENT, 0);
+ return smu8_send_msg_to_smc_with_parameter(hwmgr, msg, 0);
}
static int smu8_set_smc_sram_address(struct pp_hwmgr *hwmgr,
@@ -135,17 +143,6 @@ static int smu8_write_smc_sram_dword(struct pp_hwmgr *hwmgr,
return result;
}
-static int smu8_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr,
- uint16_t msg, uint32_t parameter)
-{
- if (hwmgr == NULL || hwmgr->device == NULL)
- return -EINVAL;
-
- cgs_write_register(hwmgr->device, mmSMU_MP1_SRBM2P_ARG_0, parameter);
-
- return smu8_send_msg_to_smc(hwmgr, msg);
-}
-
static int smu8_check_fw_load_finish(struct pp_hwmgr *hwmgr,
uint32_t firmware)
{
@@ -737,6 +734,10 @@ static int smu8_start_smu(struct pp_hwmgr *hwmgr)
cgs_write_register(hwmgr->device, mmMP0PUB_IND_INDEX, index);
hwmgr->smu_version = cgs_read_register(hwmgr->device, mmMP0PUB_IND_DATA);
+ pr_info("smu version %02d.%02d.%02d\n",
+ ((hwmgr->smu_version >> 16) & 0xFF),
+ ((hwmgr->smu_version >> 8) & 0xFF),
+ (hwmgr->smu_version & 0xFF));
adev->pm.fw_version = hwmgr->smu_version >> 8;
return smu8_request_smu_load_fw(hwmgr);
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c
index 99d5e4f98f49..a6edd5df33b0 100644
--- a/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c
+++ b/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c
@@ -37,10 +37,13 @@ MODULE_FIRMWARE("amdgpu/fiji_smc.bin");
MODULE_FIRMWARE("amdgpu/polaris10_smc.bin");
MODULE_FIRMWARE("amdgpu/polaris10_smc_sk.bin");
MODULE_FIRMWARE("amdgpu/polaris10_k_smc.bin");
+MODULE_FIRMWARE("amdgpu/polaris10_k2_smc.bin");
MODULE_FIRMWARE("amdgpu/polaris11_smc.bin");
MODULE_FIRMWARE("amdgpu/polaris11_smc_sk.bin");
MODULE_FIRMWARE("amdgpu/polaris11_k_smc.bin");
+MODULE_FIRMWARE("amdgpu/polaris11_k2_smc.bin");
MODULE_FIRMWARE("amdgpu/polaris12_smc.bin");
+MODULE_FIRMWARE("amdgpu/polaris12_k_smc.bin");
MODULE_FIRMWARE("amdgpu/vegam_smc.bin");
MODULE_FIRMWARE("amdgpu/vega10_smc.bin");
MODULE_FIRMWARE("amdgpu/vega10_acg_smc.bin");
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vegam_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/vegam_smumgr.c
index 9f71512b2510..1e69300f6175 100644
--- a/drivers/gpu/drm/amd/powerplay/smumgr/vegam_smumgr.c
+++ b/drivers/gpu/drm/amd/powerplay/smumgr/vegam_smumgr.c
@@ -40,7 +40,6 @@
#include "smu7_hwmgr.h"
#include "hardwaremanager.h"
-#include "ppatomctrl.h"
#include "atombios.h"
#include "pppcielanes.h"
diff --git a/drivers/gpu/drm/arc/arcpgu.h b/drivers/gpu/drm/arc/arcpgu.h
index e8fcf3ab1d9a..90ef76b19f8a 100644
--- a/drivers/gpu/drm/arc/arcpgu.h
+++ b/drivers/gpu/drm/arc/arcpgu.h
@@ -20,7 +20,6 @@
struct arcpgu_drm_private {
void __iomem *regs;
struct clk *clk;
- struct drm_fbdev_cma *fbdev;
struct drm_framebuffer *fb;
struct drm_crtc crtc;
struct drm_plane *plane;
@@ -43,8 +42,5 @@ static inline u32 arc_pgu_read(struct arcpgu_drm_private *arcpgu,
int arc_pgu_setup_crtc(struct drm_device *dev);
int arcpgu_drm_hdmi_init(struct drm_device *drm, struct device_node *np);
int arcpgu_drm_sim_init(struct drm_device *drm, struct device_node *np);
-struct drm_fbdev_cma *arcpgu_fbdev_cma_init(struct drm_device *dev,
- unsigned int preferred_bpp, unsigned int num_crtc,
- unsigned int max_conn_count);
#endif
diff --git a/drivers/gpu/drm/arc/arcpgu_crtc.c b/drivers/gpu/drm/arc/arcpgu_crtc.c
index 965cda48dc13..62f51f70606d 100644
--- a/drivers/gpu/drm/arc/arcpgu_crtc.c
+++ b/drivers/gpu/drm/arc/arcpgu_crtc.c
@@ -158,8 +158,6 @@ static void arc_pgu_crtc_atomic_begin(struct drm_crtc *crtc,
static const struct drm_crtc_helper_funcs arc_pgu_crtc_helper_funcs = {
.mode_valid = arc_pgu_crtc_mode_valid,
- .mode_set = drm_helper_crtc_mode_set,
- .mode_set_base = drm_helper_crtc_mode_set_base,
.mode_set_nofb = arc_pgu_crtc_mode_set_nofb,
.atomic_begin = arc_pgu_crtc_atomic_begin,
.atomic_enable = arc_pgu_crtc_atomic_enable,
@@ -186,7 +184,6 @@ static const struct drm_plane_helper_funcs arc_pgu_plane_helper_funcs = {
static void arc_pgu_plane_destroy(struct drm_plane *plane)
{
- drm_plane_helper_disable(plane, NULL);
drm_plane_cleanup(plane);
}
diff --git a/drivers/gpu/drm/arc/arcpgu_drv.c b/drivers/gpu/drm/arc/arcpgu_drv.c
index f067de4e1e82..2af847ebca34 100644
--- a/drivers/gpu/drm/arc/arcpgu_drv.c
+++ b/drivers/gpu/drm/arc/arcpgu_drv.c
@@ -17,6 +17,7 @@
#include <linux/clk.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_fb_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_atomic_helper.h>
@@ -25,16 +26,8 @@
#include "arcpgu.h"
#include "arcpgu_regs.h"
-static void arcpgu_fb_output_poll_changed(struct drm_device *dev)
-{
- struct arcpgu_drm_private *arcpgu = dev->dev_private;
-
- drm_fbdev_cma_hotplug_event(arcpgu->fbdev);
-}
-
static const struct drm_mode_config_funcs arcpgu_drm_modecfg_funcs = {
.fb_create = drm_gem_fb_create,
- .output_poll_changed = arcpgu_fb_output_poll_changed,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = drm_atomic_helper_commit,
};
@@ -51,13 +44,6 @@ static void arcpgu_setup_mode_config(struct drm_device *drm)
DEFINE_DRM_GEM_CMA_FOPS(arcpgu_drm_ops);
-static void arcpgu_lastclose(struct drm_device *drm)
-{
- struct arcpgu_drm_private *arcpgu = drm->dev_private;
-
- drm_fbdev_cma_restore_mode(arcpgu->fbdev);
-}
-
static int arcpgu_load(struct drm_device *drm)
{
struct platform_device *pdev = to_platform_device(drm->dev);
@@ -113,27 +99,14 @@ static int arcpgu_load(struct drm_device *drm)
drm_mode_config_reset(drm);
drm_kms_helper_poll_init(drm);
- arcpgu->fbdev = drm_fbdev_cma_init(drm, 16,
- drm->mode_config.num_connector);
- if (IS_ERR(arcpgu->fbdev)) {
- ret = PTR_ERR(arcpgu->fbdev);
- arcpgu->fbdev = NULL;
- return -ENODEV;
- }
-
platform_set_drvdata(pdev, drm);
return 0;
}
static int arcpgu_unload(struct drm_device *drm)
{
- struct arcpgu_drm_private *arcpgu = drm->dev_private;
-
- if (arcpgu->fbdev) {
- drm_fbdev_cma_fini(arcpgu->fbdev);
- arcpgu->fbdev = NULL;
- }
drm_kms_helper_poll_fini(drm);
+ drm_atomic_helper_shutdown(drm);
drm_mode_config_cleanup(drm);
return 0;
@@ -167,7 +140,6 @@ static int arcpgu_debugfs_init(struct drm_minor *minor)
static struct drm_driver arcpgu_drm_driver = {
.driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME |
DRIVER_ATOMIC,
- .lastclose = arcpgu_lastclose,
.name = "arcpgu",
.desc = "ARC PGU Controller",
.date = "20160219",
@@ -210,6 +182,8 @@ static int arcpgu_probe(struct platform_device *pdev)
if (ret)
goto err_unload;
+ drm_fbdev_generic_setup(drm, 16);
+
return 0;
err_unload:
diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c
index 7aad7dd80d8c..b9bed1138fa3 100644
--- a/drivers/gpu/drm/arm/malidp_hw.c
+++ b/drivers/gpu/drm/arm/malidp_hw.c
@@ -77,12 +77,18 @@ static const struct malidp_format_id malidp500_de_formats[] = {
{ DRM_FORMAT_YUYV, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 2) }, \
{ DRM_FORMAT_UYVY, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 3) }, \
{ DRM_FORMAT_NV12, DE_VIDEO1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(5, 6) }, \
- { DRM_FORMAT_YUV420, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 7) }
+ { DRM_FORMAT_YUV420, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 7) }, \
+ { DRM_FORMAT_X0L2, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(6, 6)}
static const struct malidp_format_id malidp550_de_formats[] = {
MALIDP_COMMON_FORMATS,
};
+static const struct malidp_format_id malidp650_de_formats[] = {
+ MALIDP_COMMON_FORMATS,
+ { DRM_FORMAT_X0L0, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 4)},
+};
+
static const struct malidp_layer malidp500_layers[] = {
/* id, base address, fb pointer address base, stride offset,
* yuv2rgb matrix offset, mmu control register offset, rotation_features
@@ -630,6 +636,8 @@ static int malidp550_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16
case DRM_FORMAT_BGR565:
case DRM_FORMAT_UYVY:
case DRM_FORMAT_YUYV:
+ case DRM_FORMAT_X0L0:
+ case DRM_FORMAT_X0L2:
bytes_per_col = 32;
break;
/* 16 lines at 1.5 bytes per pixel */
@@ -905,8 +913,8 @@ const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = {
MALIDP550_DC_IRQ_SE,
.vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
},
- .pixel_formats = malidp550_de_formats,
- .n_pixel_formats = ARRAY_SIZE(malidp550_de_formats),
+ .pixel_formats = malidp650_de_formats,
+ .n_pixel_formats = ARRAY_SIZE(malidp650_de_formats),
.bus_align_bytes = 16,
},
.query_hw = malidp650_query_hw,
diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c
index 837a24d56675..c9a6d3e0cada 100644
--- a/drivers/gpu/drm/arm/malidp_planes.c
+++ b/drivers/gpu/drm/arm/malidp_planes.c
@@ -398,6 +398,7 @@ static int malidp_de_plane_check(struct drm_plane *plane,
struct drm_framebuffer *fb;
u16 pixel_alpha = state->pixel_blend_mode;
int i, ret;
+ unsigned int block_w, block_h;
if (!state->crtc || !state->fb)
return 0;
@@ -413,13 +414,26 @@ static int malidp_de_plane_check(struct drm_plane *plane,
ms->n_planes = fb->format->num_planes;
for (i = 0; i < ms->n_planes; i++) {
u8 alignment = malidp_hw_get_pitch_align(mp->hwdev, rotated);
- if (fb->pitches[i] & (alignment - 1)) {
+
+ if ((fb->pitches[i] * drm_format_info_block_height(fb->format, i))
+ & (alignment - 1)) {
DRM_DEBUG_KMS("Invalid pitch %u for plane %d\n",
fb->pitches[i], i);
return -EINVAL;
}
}
+ block_w = drm_format_info_block_width(fb->format, 0);
+ block_h = drm_format_info_block_height(fb->format, 0);
+ if (fb->width % block_w || fb->height % block_h) {
+ DRM_DEBUG_KMS("Buffer width/height needs to be a multiple of tile sizes");
+ return -EINVAL;
+ }
+ if ((state->src_x >> 16) % block_w || (state->src_y >> 16) % block_h) {
+ DRM_DEBUG_KMS("Plane src_x/src_y needs to be a multiple of tile sizes");
+ return -EINVAL;
+ }
+
if ((state->crtc_w > mp->hwdev->max_line_size) ||
(state->crtc_h > mp->hwdev->max_line_size) ||
(state->crtc_w < mp->hwdev->min_line_size) ||
@@ -492,10 +506,18 @@ static void malidp_de_set_plane_pitches(struct malidp_plane *mp,
num_strides = (mp->hwdev->hw->features &
MALIDP_DEVICE_LV_HAS_3_STRIDES) ? 3 : 2;
- for (i = 0; i < num_strides; ++i)
- malidp_hw_write(mp->hwdev, pitches[i],
+ /*
+ * The drm convention for pitch is that it needs to cover width * cpp,
+ * but our hardware wants the pitch/stride to cover all rows included
+ * in a tile.
+ */
+ for (i = 0; i < num_strides; ++i) {
+ unsigned int block_h = drm_format_info_block_height(mp->base.state->fb->format, i);
+
+ malidp_hw_write(mp->hwdev, pitches[i] * block_h,
mp->layer->base +
mp->layer->stride_offset + i * 4);
+ }
}
static const s16
diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h
index e6c4cd3dc50e..bfc65040dfcb 100644
--- a/drivers/gpu/drm/ast/ast_drv.h
+++ b/drivers/gpu/drm/ast/ast_drv.h
@@ -104,8 +104,6 @@ struct ast_private {
int fb_mtrr;
struct {
- struct drm_global_reference mem_global_ref;
- struct ttm_bo_global_ref bo_global_ref;
struct ttm_bo_device bdev;
} ttm;
diff --git a/drivers/gpu/drm/ast/ast_ttm.c b/drivers/gpu/drm/ast/ast_ttm.c
index fe354ebf374d..c168d62fe8f9 100644
--- a/drivers/gpu/drm/ast/ast_ttm.c
+++ b/drivers/gpu/drm/ast/ast_ttm.c
@@ -36,63 +36,6 @@ ast_bdev(struct ttm_bo_device *bd)
return container_of(bd, struct ast_private, ttm.bdev);
}
-static int
-ast_ttm_mem_global_init(struct drm_global_reference *ref)
-{
- return ttm_mem_global_init(ref->object);
-}
-
-static void
-ast_ttm_mem_global_release(struct drm_global_reference *ref)
-{
- ttm_mem_global_release(ref->object);
-}
-
-static int ast_ttm_global_init(struct ast_private *ast)
-{
- struct drm_global_reference *global_ref;
- int r;
-
- global_ref = &ast->ttm.mem_global_ref;
- global_ref->global_type = DRM_GLOBAL_TTM_MEM;
- global_ref->size = sizeof(struct ttm_mem_global);
- global_ref->init = &ast_ttm_mem_global_init;
- global_ref->release = &ast_ttm_mem_global_release;
- r = drm_global_item_ref(global_ref);
- if (r != 0) {
- DRM_ERROR("Failed setting up TTM memory accounting "
- "subsystem.\n");
- return r;
- }
-
- ast->ttm.bo_global_ref.mem_glob =
- ast->ttm.mem_global_ref.object;
- global_ref = &ast->ttm.bo_global_ref.ref;
- global_ref->global_type = DRM_GLOBAL_TTM_BO;
- global_ref->size = sizeof(struct ttm_bo_global);
- global_ref->init = &ttm_bo_global_init;
- global_ref->release = &ttm_bo_global_release;
- r = drm_global_item_ref(global_ref);
- if (r != 0) {
- DRM_ERROR("Failed setting up TTM BO subsystem.\n");
- drm_global_item_unref(&ast->ttm.mem_global_ref);
- return r;
- }
- return 0;
-}
-
-static void
-ast_ttm_global_release(struct ast_private *ast)
-{
- if (ast->ttm.mem_global_ref.release == NULL)
- return;
-
- drm_global_item_unref(&ast->ttm.bo_global_ref.ref);
- drm_global_item_unref(&ast->ttm.mem_global_ref);
- ast->ttm.mem_global_ref.release = NULL;
-}
-
-
static void ast_bo_ttm_destroy(struct ttm_buffer_object *tbo)
{
struct ast_bo *bo;
@@ -232,12 +175,7 @@ int ast_mm_init(struct ast_private *ast)
struct drm_device *dev = ast->dev;
struct ttm_bo_device *bdev = &ast->ttm.bdev;
- ret = ast_ttm_global_init(ast);
- if (ret)
- return ret;
-
ret = ttm_bo_device_init(&ast->ttm.bdev,
- ast->ttm.bo_global_ref.ref.object,
&ast_bo_driver,
dev->anon_inode->i_mapping,
DRM_FILE_PAGE_OFFSET,
@@ -268,8 +206,6 @@ void ast_mm_fini(struct ast_private *ast)
ttm_bo_device_release(&ast->ttm.bdev);
- ast_ttm_global_release(ast);
-
arch_phys_wc_del(ast->fb_mtrr);
arch_io_free_memtype_wc(pci_resource_start(dev->pdev, 0),
pci_resource_len(dev->pdev, 0));
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
index 9e34bce089d0..96f4082671fe 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
@@ -364,9 +364,7 @@ static void atmel_hlcdc_crtc_atomic_flush(struct drm_crtc *crtc,
static const struct drm_crtc_helper_funcs lcdc_crtc_helper_funcs = {
.mode_valid = atmel_hlcdc_crtc_mode_valid,
- .mode_set = drm_helper_crtc_mode_set,
.mode_set_nofb = atmel_hlcdc_crtc_mode_set_nofb,
- .mode_set_base = drm_helper_crtc_mode_set_base,
.atomic_check = atmel_hlcdc_crtc_atomic_check,
.atomic_begin = atmel_hlcdc_crtc_atomic_begin,
.atomic_flush = atmel_hlcdc_crtc_atomic_flush,
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
index 843cac222e60..034a91112098 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
@@ -556,7 +556,6 @@ error:
static const struct drm_mode_config_funcs mode_config_funcs = {
.fb_create = atmel_hlcdc_fb_create,
- .output_poll_changed = drm_fb_helper_output_poll_changed,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = atmel_hlcdc_dc_atomic_commit,
};
@@ -658,8 +657,6 @@ static int atmel_hlcdc_dc_load(struct drm_device *dev)
platform_set_drvdata(pdev, dev);
- drm_fb_cma_fbdev_init(dev, 24, 0);
-
drm_kms_helper_poll_init(dev);
return 0;
@@ -678,7 +675,6 @@ static void atmel_hlcdc_dc_unload(struct drm_device *dev)
{
struct atmel_hlcdc_dc *dc = dev->dev_private;
- drm_fb_cma_fbdev_fini(dev);
flush_workqueue(dc->wq);
drm_kms_helper_poll_fini(dev);
drm_atomic_helper_shutdown(dev);
@@ -727,7 +723,6 @@ static struct drm_driver atmel_hlcdc_dc_driver = {
.driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM |
DRIVER_MODESET | DRIVER_PRIME |
DRIVER_ATOMIC,
- .lastclose = drm_fb_helper_lastclose,
.irq_handler = atmel_hlcdc_dc_irq_handler,
.irq_preinstall = atmel_hlcdc_dc_irq_uninstall,
.irq_postinstall = atmel_hlcdc_dc_irq_postinstall,
@@ -763,19 +758,21 @@ static int atmel_hlcdc_dc_drm_probe(struct platform_device *pdev)
ret = atmel_hlcdc_dc_load(ddev);
if (ret)
- goto err_unref;
+ goto err_put;
ret = drm_dev_register(ddev, 0);
if (ret)
goto err_unload;
+ drm_fbdev_generic_setup(ddev, 24);
+
return 0;
err_unload:
atmel_hlcdc_dc_unload(ddev);
-err_unref:
- drm_dev_unref(ddev);
+err_put:
+ drm_dev_put(ddev);
return ret;
}
@@ -786,7 +783,7 @@ static int atmel_hlcdc_dc_drm_remove(struct platform_device *pdev)
drm_dev_unregister(ddev);
atmel_hlcdc_dc_unload(ddev);
- drm_dev_unref(ddev);
+ drm_dev_put(ddev);
return 0;
}
diff --git a/drivers/gpu/drm/bochs/bochs.h b/drivers/gpu/drm/bochs/bochs.h
index e7a69077e45a..fb38c8b857b5 100644
--- a/drivers/gpu/drm/bochs/bochs.h
+++ b/drivers/gpu/drm/bochs/bochs.h
@@ -66,6 +66,7 @@ struct bochs_device {
u16 yres_virtual;
u32 stride;
u32 bpp;
+ struct edid *edid;
/* drm */
struct drm_device *dev;
@@ -76,8 +77,6 @@ struct bochs_device {
/* ttm */
struct {
- struct drm_global_reference mem_global_ref;
- struct ttm_bo_global_ref bo_global_ref;
struct ttm_bo_device bdev;
bool initialized;
} ttm;
@@ -126,6 +125,7 @@ void bochs_hw_setmode(struct bochs_device *bochs,
const struct drm_format_info *format);
void bochs_hw_setbase(struct bochs_device *bochs,
int x, int y, u64 addr);
+int bochs_hw_load_edid(struct bochs_device *bochs);
/* bochs_mm.c */
int bochs_mm_init(struct bochs_device *bochs);
diff --git a/drivers/gpu/drm/bochs/bochs_hw.c b/drivers/gpu/drm/bochs/bochs_hw.c
index cacff73a64ab..c90a0d492fd5 100644
--- a/drivers/gpu/drm/bochs/bochs_hw.c
+++ b/drivers/gpu/drm/bochs/bochs_hw.c
@@ -69,6 +69,35 @@ static void bochs_hw_set_little_endian(struct bochs_device *bochs)
#define bochs_hw_set_native_endian(_b) bochs_hw_set_little_endian(_b)
#endif
+static int bochs_get_edid_block(void *data, u8 *buf,
+ unsigned int block, size_t len)
+{
+ struct bochs_device *bochs = data;
+ size_t i, start = block * EDID_LENGTH;
+
+ if (start + len > 0x400 /* vga register offset */)
+ return -1;
+
+ for (i = 0; i < len; i++) {
+ buf[i] = readb(bochs->mmio + start + i);
+ }
+ return 0;
+}
+
+int bochs_hw_load_edid(struct bochs_device *bochs)
+{
+ if (!bochs->mmio)
+ return -1;
+
+ kfree(bochs->edid);
+ bochs->edid = drm_do_get_edid(&bochs->connector,
+ bochs_get_edid_block, bochs);
+ if (bochs->edid == NULL)
+ return -1;
+
+ return 0;
+}
+
int bochs_hw_init(struct drm_device *dev)
{
struct bochs_device *bochs = dev->dev_private;
@@ -164,6 +193,7 @@ void bochs_hw_fini(struct drm_device *dev)
if (bochs->fb_map)
iounmap(bochs->fb_map);
pci_release_regions(dev->pdev);
+ kfree(bochs->edid);
}
void bochs_hw_setmode(struct bochs_device *bochs,
diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c
index 9bc5b438aefd..f87c284dd93d 100644
--- a/drivers/gpu/drm/bochs/bochs_kms.c
+++ b/drivers/gpu/drm/bochs/bochs_kms.c
@@ -213,10 +213,17 @@ static void bochs_encoder_init(struct drm_device *dev)
static int bochs_connector_get_modes(struct drm_connector *connector)
{
- int count;
+ struct bochs_device *bochs =
+ container_of(connector, struct bochs_device, connector);
+ int count = 0;
+
+ if (bochs->edid)
+ count = drm_add_edid_modes(connector, bochs->edid);
- count = drm_add_modes_noedid(connector, 8192, 8192);
- drm_set_preferred_mode(connector, defx, defy);
+ if (!count) {
+ count = drm_add_modes_noedid(connector, 8192, 8192);
+ drm_set_preferred_mode(connector, defx, defy);
+ }
return count;
}
@@ -271,6 +278,13 @@ static void bochs_connector_init(struct drm_device *dev)
drm_connector_helper_add(connector,
&bochs_connector_connector_helper_funcs);
drm_connector_register(connector);
+
+ bochs_hw_load_edid(bochs);
+ if (bochs->edid) {
+ DRM_INFO("Found EDID data blob.\n");
+ drm_connector_attach_edid_property(connector);
+ drm_connector_update_edid_property(connector, bochs->edid);
+ }
}
diff --git a/drivers/gpu/drm/bochs/bochs_mm.c b/drivers/gpu/drm/bochs/bochs_mm.c
index a61c1ecb2bdc..0980411e41bf 100644
--- a/drivers/gpu/drm/bochs/bochs_mm.c
+++ b/drivers/gpu/drm/bochs/bochs_mm.c
@@ -16,61 +16,6 @@ static inline struct bochs_device *bochs_bdev(struct ttm_bo_device *bd)
return container_of(bd, struct bochs_device, ttm.bdev);
}
-static int bochs_ttm_mem_global_init(struct drm_global_reference *ref)
-{
- return ttm_mem_global_init(ref->object);
-}
-
-static void bochs_ttm_mem_global_release(struct drm_global_reference *ref)
-{
- ttm_mem_global_release(ref->object);
-}
-
-static int bochs_ttm_global_init(struct bochs_device *bochs)
-{
- struct drm_global_reference *global_ref;
- int r;
-
- global_ref = &bochs->ttm.mem_global_ref;
- global_ref->global_type = DRM_GLOBAL_TTM_MEM;
- global_ref->size = sizeof(struct ttm_mem_global);
- global_ref->init = &bochs_ttm_mem_global_init;
- global_ref->release = &bochs_ttm_mem_global_release;
- r = drm_global_item_ref(global_ref);
- if (r != 0) {
- DRM_ERROR("Failed setting up TTM memory accounting "
- "subsystem.\n");
- return r;
- }
-
- bochs->ttm.bo_global_ref.mem_glob =
- bochs->ttm.mem_global_ref.object;
- global_ref = &bochs->ttm.bo_global_ref.ref;
- global_ref->global_type = DRM_GLOBAL_TTM_BO;
- global_ref->size = sizeof(struct ttm_bo_global);
- global_ref->init = &ttm_bo_global_init;
- global_ref->release = &ttm_bo_global_release;
- r = drm_global_item_ref(global_ref);
- if (r != 0) {
- DRM_ERROR("Failed setting up TTM BO subsystem.\n");
- drm_global_item_unref(&bochs->ttm.mem_global_ref);
- return r;
- }
-
- return 0;
-}
-
-static void bochs_ttm_global_release(struct bochs_device *bochs)
-{
- if (bochs->ttm.mem_global_ref.release == NULL)
- return;
-
- drm_global_item_unref(&bochs->ttm.bo_global_ref.ref);
- drm_global_item_unref(&bochs->ttm.mem_global_ref);
- bochs->ttm.mem_global_ref.release = NULL;
-}
-
-
static void bochs_bo_ttm_destroy(struct ttm_buffer_object *tbo)
{
struct bochs_bo *bo;
@@ -208,12 +153,7 @@ int bochs_mm_init(struct bochs_device *bochs)
struct ttm_bo_device *bdev = &bochs->ttm.bdev;
int ret;
- ret = bochs_ttm_global_init(bochs);
- if (ret)
- return ret;
-
ret = ttm_bo_device_init(&bochs->ttm.bdev,
- bochs->ttm.bo_global_ref.ref.object,
&bochs_bo_driver,
bochs->dev->anon_inode->i_mapping,
DRM_FILE_PAGE_OFFSET,
@@ -240,7 +180,6 @@ void bochs_mm_fini(struct bochs_device *bochs)
return;
ttm_bo_device_release(&bochs->ttm.bdev);
- bochs_ttm_global_release(bochs);
bochs->ttm.initialized = false;
}
@@ -414,7 +353,7 @@ int bochs_dumb_create(struct drm_file *file, struct drm_device *dev,
return ret;
ret = drm_gem_handle_create(file, gobj, &handle);
- drm_gem_object_unreference_unlocked(gobj);
+ drm_gem_object_put_unlocked(gobj);
if (ret)
return ret;
@@ -454,6 +393,6 @@ int bochs_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
bo = gem_to_bochs_bo(obj);
*offset = bochs_bo_mmap_offset(bo);
- drm_gem_object_unreference_unlocked(obj);
+ drm_gem_object_put_unlocked(obj);
return 0;
}
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 2f21d3b6850b..753e96129ab7 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -1219,12 +1219,12 @@ static int analogix_dp_bridge_attach(struct drm_bridge *bridge)
* plat_data->attch return, that's why we record the connector
* point after plat attached.
*/
- if (dp->plat_data->attach) {
- ret = dp->plat_data->attach(dp->plat_data, bridge, connector);
- if (ret) {
- DRM_ERROR("Failed at platform attch func\n");
- return ret;
- }
+ if (dp->plat_data->attach) {
+ ret = dp->plat_data->attach(dp->plat_data, bridge, connector);
+ if (ret) {
+ DRM_ERROR("Failed at platform attach func\n");
+ return ret;
+ }
}
if (dp->plat_data->panel) {
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index 5971976284bf..64c3cf027518 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -1664,6 +1664,7 @@ static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
case 0x131a:
case 0x132a:
case 0x201a:
+ case 0x212a:
count = 1;
break;
default:
@@ -1957,7 +1958,6 @@ static const struct drm_connector_funcs dw_hdmi_connector_funcs = {
static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = {
.get_modes = dw_hdmi_connector_get_modes,
- .best_encoder = drm_atomic_helper_best_encoder,
};
static int dw_hdmi_bridge_attach(struct drm_bridge *bridge)
@@ -2205,7 +2205,9 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
unsigned int i;
u8 phy_type;
- phy_type = hdmi_readb(hdmi, HDMI_CONFIG2_ID);
+ phy_type = hdmi->plat_data->phy_force_vendor ?
+ DW_HDMI_PHY_VENDOR_PHY :
+ hdmi_readb(hdmi, HDMI_CONFIG2_ID);
if (phy_type == DW_HDMI_PHY_VENDOR_PHY) {
/* Vendor PHYs require support from the glue layer. */
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
index fd7999642cf8..2f4b145b73af 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
@@ -230,10 +230,21 @@ struct dw_mipi_dsi {
u32 format;
unsigned long mode_flags;
+ struct dw_mipi_dsi *master; /* dual-dsi master ptr */
+ struct dw_mipi_dsi *slave; /* dual-dsi slave ptr */
+
const struct dw_mipi_dsi_plat_data *plat_data;
};
/*
+ * Check if either a link to a master or slave is present
+ */
+static inline bool dw_mipi_is_dual_mode(struct dw_mipi_dsi *dsi)
+{
+ return dsi->slave || dsi->master;
+}
+
+/*
* The controller should generate 2 frames before
* preparing the peripheral.
*/
@@ -270,6 +281,7 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
struct mipi_dsi_device *device)
{
struct dw_mipi_dsi *dsi = host_to_dsi(host);
+ const struct dw_mipi_dsi_plat_data *pdata = dsi->plat_data;
struct drm_bridge *bridge;
struct drm_panel *panel;
int ret;
@@ -300,6 +312,12 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
drm_bridge_add(&dsi->bridge);
+ if (pdata->host_ops && pdata->host_ops->attach) {
+ ret = pdata->host_ops->attach(pdata->priv_data, device);
+ if (ret < 0)
+ return ret;
+ }
+
return 0;
}
@@ -307,6 +325,14 @@ static int dw_mipi_dsi_host_detach(struct mipi_dsi_host *host,
struct mipi_dsi_device *device)
{
struct dw_mipi_dsi *dsi = host_to_dsi(host);
+ const struct dw_mipi_dsi_plat_data *pdata = dsi->plat_data;
+ int ret;
+
+ if (pdata->host_ops && pdata->host_ops->detach) {
+ ret = pdata->host_ops->detach(pdata->priv_data, device);
+ if (ret < 0)
+ return ret;
+ }
drm_of_panel_bridge_remove(host->dev->of_node, 1, 0);
@@ -441,10 +467,17 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host,
}
dw_mipi_message_config(dsi, msg);
+ if (dsi->slave)
+ dw_mipi_message_config(dsi->slave, msg);
ret = dw_mipi_dsi_write(dsi, &packet);
if (ret)
return ret;
+ if (dsi->slave) {
+ ret = dw_mipi_dsi_write(dsi->slave, &packet);
+ if (ret)
+ return ret;
+ }
if (msg->rx_buf && msg->rx_len) {
ret = dw_mipi_dsi_read(dsi, msg);
@@ -583,7 +616,11 @@ static void dw_mipi_dsi_video_packet_config(struct dw_mipi_dsi *dsi,
* DSI_VNPCR.NPSIZE... especially because this driver supports
* non-burst video modes, see dw_mipi_dsi_video_mode_config()...
*/
- dsi_write(dsi, DSI_VID_PKT_SIZE, VID_PKT_SIZE(mode->hdisplay));
+
+ dsi_write(dsi, DSI_VID_PKT_SIZE,
+ dw_mipi_is_dual_mode(dsi) ?
+ VID_PKT_SIZE(mode->hdisplay / 2) :
+ VID_PKT_SIZE(mode->hdisplay));
}
static void dw_mipi_dsi_command_mode_config(struct dw_mipi_dsi *dsi)
@@ -755,24 +792,43 @@ static void dw_mipi_dsi_bridge_post_disable(struct drm_bridge *bridge)
*/
dsi->panel_bridge->funcs->post_disable(dsi->panel_bridge);
+ if (dsi->slave) {
+ dw_mipi_dsi_disable(dsi->slave);
+ clk_disable_unprepare(dsi->slave->pclk);
+ pm_runtime_put(dsi->slave->dev);
+ }
dw_mipi_dsi_disable(dsi);
+
clk_disable_unprepare(dsi->pclk);
pm_runtime_put(dsi->dev);
}
-static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
+static unsigned int dw_mipi_dsi_get_lanes(struct dw_mipi_dsi *dsi)
+{
+ /* this instance is the slave, so add the master's lanes */
+ if (dsi->master)
+ return dsi->master->lanes + dsi->lanes;
+
+ /* this instance is the master, so add the slave's lanes */
+ if (dsi->slave)
+ return dsi->lanes + dsi->slave->lanes;
+
+ /* single-dsi, so no other instance to consider */
+ return dsi->lanes;
+}
+
+static void dw_mipi_dsi_mode_set(struct dw_mipi_dsi *dsi,
+ struct drm_display_mode *adjusted_mode)
{
- struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops;
void *priv_data = dsi->plat_data->priv_data;
int ret;
+ u32 lanes = dw_mipi_dsi_get_lanes(dsi);
clk_prepare_enable(dsi->pclk);
ret = phy_ops->get_lane_mbps(priv_data, adjusted_mode, dsi->mode_flags,
- dsi->lanes, dsi->format, &dsi->lane_mbps);
+ lanes, dsi->format, &dsi->lane_mbps);
if (ret)
DRM_DEBUG_DRIVER("Phy get_lane_mbps() failed\n");
@@ -804,12 +860,25 @@ static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge,
dw_mipi_dsi_set_mode(dsi, 0);
}
+static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
+
+ dw_mipi_dsi_mode_set(dsi, adjusted_mode);
+ if (dsi->slave)
+ dw_mipi_dsi_mode_set(dsi->slave, adjusted_mode);
+}
+
static void dw_mipi_dsi_bridge_enable(struct drm_bridge *bridge)
{
struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
/* Switch to video mode for panel-bridge enable & panel enable */
dw_mipi_dsi_set_mode(dsi, MIPI_DSI_MODE_VIDEO);
+ if (dsi->slave)
+ dw_mipi_dsi_set_mode(dsi->slave, MIPI_DSI_MODE_VIDEO);
}
static enum drm_mode_status
@@ -941,9 +1010,25 @@ __dw_mipi_dsi_probe(struct platform_device *pdev,
static void __dw_mipi_dsi_remove(struct dw_mipi_dsi *dsi)
{
+ mipi_dsi_host_unregister(&dsi->dsi_host);
+
pm_runtime_disable(dsi->dev);
}
+void dw_mipi_dsi_set_slave(struct dw_mipi_dsi *dsi, struct dw_mipi_dsi *slave)
+{
+ /* introduce controllers to each other */
+ dsi->slave = slave;
+ dsi->slave->master = dsi;
+
+ /* migrate settings for already attached displays */
+ dsi->slave->lanes = dsi->lanes;
+ dsi->slave->channel = dsi->channel;
+ dsi->slave->format = dsi->format;
+ dsi->slave->mode_flags = dsi->mode_flags;
+}
+EXPORT_SYMBOL_GPL(dw_mipi_dsi_set_slave);
+
/*
* Probe/remove API, used from platforms based on the DRM bridge API.
*/
@@ -957,8 +1042,6 @@ EXPORT_SYMBOL_GPL(dw_mipi_dsi_probe);
void dw_mipi_dsi_remove(struct dw_mipi_dsi *dsi)
{
- mipi_dsi_host_unregister(&dsi->dsi_host);
-
__dw_mipi_dsi_remove(dsi);
}
EXPORT_SYMBOL_GPL(dw_mipi_dsi_remove);
@@ -966,31 +1049,22 @@ EXPORT_SYMBOL_GPL(dw_mipi_dsi_remove);
/*
* Bind/unbind API, used from platforms based on the component framework.
*/
-struct dw_mipi_dsi *
-dw_mipi_dsi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
- const struct dw_mipi_dsi_plat_data *plat_data)
+int dw_mipi_dsi_bind(struct dw_mipi_dsi *dsi, struct drm_encoder *encoder)
{
- struct dw_mipi_dsi *dsi;
int ret;
- dsi = __dw_mipi_dsi_probe(pdev, plat_data);
- if (IS_ERR(dsi))
- return dsi;
-
ret = drm_bridge_attach(encoder, &dsi->bridge, NULL);
if (ret) {
- dw_mipi_dsi_remove(dsi);
DRM_ERROR("Failed to initialize bridge with drm\n");
- return ERR_PTR(ret);
+ return ret;
}
- return dsi;
+ return ret;
}
EXPORT_SYMBOL_GPL(dw_mipi_dsi_bind);
void dw_mipi_dsi_unbind(struct dw_mipi_dsi *dsi)
{
- __dw_mipi_dsi_remove(dsi);
}
EXPORT_SYMBOL_GPL(dw_mipi_dsi_unbind);
diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.h b/drivers/gpu/drm/cirrus/cirrus_drv.h
index a29f87e98d9d..f2b2e0d169fa 100644
--- a/drivers/gpu/drm/cirrus/cirrus_drv.h
+++ b/drivers/gpu/drm/cirrus/cirrus_drv.h
@@ -136,8 +136,6 @@ struct cirrus_device {
int fb_mtrr;
struct {
- struct drm_global_reference mem_global_ref;
- struct ttm_bo_global_ref bo_global_ref;
struct ttm_bo_device bdev;
} ttm;
bool mm_inited;
diff --git a/drivers/gpu/drm/cirrus/cirrus_ttm.c b/drivers/gpu/drm/cirrus/cirrus_ttm.c
index f21953243790..e075810b4bd4 100644
--- a/drivers/gpu/drm/cirrus/cirrus_ttm.c
+++ b/drivers/gpu/drm/cirrus/cirrus_ttm.c
@@ -36,63 +36,6 @@ cirrus_bdev(struct ttm_bo_device *bd)
return container_of(bd, struct cirrus_device, ttm.bdev);
}
-static int
-cirrus_ttm_mem_global_init(struct drm_global_reference *ref)
-{
- return ttm_mem_global_init(ref->object);
-}
-
-static void
-cirrus_ttm_mem_global_release(struct drm_global_reference *ref)
-{
- ttm_mem_global_release(ref->object);
-}
-
-static int cirrus_ttm_global_init(struct cirrus_device *cirrus)
-{
- struct drm_global_reference *global_ref;
- int r;
-
- global_ref = &cirrus->ttm.mem_global_ref;
- global_ref->global_type = DRM_GLOBAL_TTM_MEM;
- global_ref->size = sizeof(struct ttm_mem_global);
- global_ref->init = &cirrus_ttm_mem_global_init;
- global_ref->release = &cirrus_ttm_mem_global_release;
- r = drm_global_item_ref(global_ref);
- if (r != 0) {
- DRM_ERROR("Failed setting up TTM memory accounting "
- "subsystem.\n");
- return r;
- }
-
- cirrus->ttm.bo_global_ref.mem_glob =
- cirrus->ttm.mem_global_ref.object;
- global_ref = &cirrus->ttm.bo_global_ref.ref;
- global_ref->global_type = DRM_GLOBAL_TTM_BO;
- global_ref->size = sizeof(struct ttm_bo_global);
- global_ref->init = &ttm_bo_global_init;
- global_ref->release = &ttm_bo_global_release;
- r = drm_global_item_ref(global_ref);
- if (r != 0) {
- DRM_ERROR("Failed setting up TTM BO subsystem.\n");
- drm_global_item_unref(&cirrus->ttm.mem_global_ref);
- return r;
- }
- return 0;
-}
-
-static void
-cirrus_ttm_global_release(struct cirrus_device *cirrus)
-{
- if (cirrus->ttm.mem_global_ref.release == NULL)
- return;
-
- drm_global_item_unref(&cirrus->ttm.bo_global_ref.ref);
- drm_global_item_unref(&cirrus->ttm.mem_global_ref);
- cirrus->ttm.mem_global_ref.release = NULL;
-}
-
-
static void cirrus_bo_ttm_destroy(struct ttm_buffer_object *tbo)
{
struct cirrus_bo *bo;
@@ -232,12 +175,7 @@ int cirrus_mm_init(struct cirrus_device *cirrus)
struct drm_device *dev = cirrus->dev;
struct ttm_bo_device *bdev = &cirrus->ttm.bdev;
- ret = cirrus_ttm_global_init(cirrus);
- if (ret)
- return ret;
-
ret = ttm_bo_device_init(&cirrus->ttm.bdev,
- cirrus->ttm.bo_global_ref.ref.object,
&cirrus_bo_driver,
dev->anon_inode->i_mapping,
DRM_FILE_PAGE_OFFSET,
@@ -273,8 +211,6 @@ void cirrus_mm_fini(struct cirrus_device *cirrus)
ttm_bo_device_release(&cirrus->ttm.bdev);
- cirrus_ttm_global_release(cirrus);
-
arch_phys_wc_del(cirrus->fb_mtrr);
cirrus->fb_mtrr = 0;
arch_io_free_memtype_wc(pci_resource_start(dev->pdev, 0),
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index cd8362dc4f74..1706ed1100d5 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -175,6 +175,11 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
state->crtcs[i].state = NULL;
state->crtcs[i].old_state = NULL;
state->crtcs[i].new_state = NULL;
+
+ if (state->crtcs[i].commit) {
+ drm_crtc_commit_put(state->crtcs[i].commit);
+ state->crtcs[i].commit = NULL;
+ }
}
for (i = 0; i < config->num_total_plane; i++) {
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 86ac6b5b36ea..fa95f9974f6d 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -92,6 +92,17 @@ drm_atomic_helper_plane_changed(struct drm_atomic_state *state,
}
}
+/*
+ * For connectors that support multiple encoders, either the
+ * .atomic_best_encoder() or .best_encoder() operation must be implemented.
+ */
+static struct drm_encoder *
+pick_single_encoder_for_connector(struct drm_connector *connector)
+{
+ WARN_ON(connector->encoder_ids[1]);
+ return drm_encoder_find(connector->dev, NULL, connector->encoder_ids[0]);
+}
+
static int handle_conflicting_encoders(struct drm_atomic_state *state,
bool disable_conflicting_encoders)
{
@@ -119,7 +130,7 @@ static int handle_conflicting_encoders(struct drm_atomic_state *state,
else if (funcs->best_encoder)
new_encoder = funcs->best_encoder(connector);
else
- new_encoder = drm_atomic_helper_best_encoder(connector);
+ new_encoder = pick_single_encoder_for_connector(connector);
if (new_encoder) {
if (encoder_mask & drm_encoder_mask(new_encoder)) {
@@ -336,7 +347,7 @@ update_connector_routing(struct drm_atomic_state *state,
else if (funcs->best_encoder)
new_encoder = funcs->best_encoder(connector);
else
- new_encoder = drm_atomic_helper_best_encoder(connector);
+ new_encoder = pick_single_encoder_for_connector(connector);
if (!new_encoder) {
DRM_DEBUG_ATOMIC("No suitable encoder found for [CONNECTOR:%d:%s]\n",
@@ -1432,15 +1443,16 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_vblanks);
void drm_atomic_helper_wait_for_flip_done(struct drm_device *dev,
struct drm_atomic_state *old_state)
{
- struct drm_crtc_state *new_crtc_state;
struct drm_crtc *crtc;
int i;
- for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) {
- struct drm_crtc_commit *commit = new_crtc_state->commit;
+ for (i = 0; i < dev->mode_config.num_crtc; i++) {
+ struct drm_crtc_commit *commit = old_state->crtcs[i].commit;
int ret;
- if (!commit)
+ crtc = old_state->crtcs[i].ptr;
+
+ if (!crtc || !commit)
continue;
ret = wait_for_completion_timeout(&commit->flip_done, 10 * HZ);
@@ -1958,6 +1970,9 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state,
drm_crtc_commit_get(commit);
commit->abort_completion = true;
+
+ state->crtcs[i].commit = commit;
+ drm_crtc_commit_get(commit);
}
for_each_oldnew_connector_in_state(state, conn, old_conn_state, new_conn_state, i) {
@@ -3411,586 +3426,3 @@ fail:
return ret;
}
EXPORT_SYMBOL(drm_atomic_helper_page_flip_target);
-
-/**
- * drm_atomic_helper_best_encoder - Helper for
- * &drm_connector_helper_funcs.best_encoder callback
- * @connector: Connector control structure
- *
- * This is a &drm_connector_helper_funcs.best_encoder callback helper for
- * connectors that support exactly 1 encoder, statically determined at driver
- * init time.
- */
-struct drm_encoder *
-drm_atomic_helper_best_encoder(struct drm_connector *connector)
-{
- WARN_ON(connector->encoder_ids[1]);
- return drm_encoder_find(connector->dev, NULL, connector->encoder_ids[0]);
-}
-EXPORT_SYMBOL(drm_atomic_helper_best_encoder);
-
-/**
- * DOC: atomic state reset and initialization
- *
- * Both the drm core and the atomic helpers assume that there is always the full
- * and correct atomic software state for all connectors, CRTCs and planes
- * available. Which is a bit a problem on driver load and also after system
- * suspend. One way to solve this is to have a hardware state read-out
- * infrastructure which reconstructs the full software state (e.g. the i915
- * driver).
- *
- * The simpler solution is to just reset the software state to everything off,
- * which is easiest to do by calling drm_mode_config_reset(). To facilitate this
- * the atomic helpers provide default reset implementations for all hooks.
- *
- * On the upside the precise state tracking of atomic simplifies system suspend
- * and resume a lot. For drivers using drm_mode_config_reset() a complete recipe
- * is implemented in drm_atomic_helper_suspend() and drm_atomic_helper_resume().
- * For other drivers the building blocks are split out, see the documentation
- * for these functions.
- */
-
-/**
- * drm_atomic_helper_crtc_reset - default &drm_crtc_funcs.reset hook for CRTCs
- * @crtc: drm CRTC
- *
- * Resets the atomic state for @crtc by freeing the state pointer (which might
- * be NULL, e.g. at driver load time) and allocating a new empty state object.
- */
-void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc)
-{
- if (crtc->state)
- __drm_atomic_helper_crtc_destroy_state(crtc->state);
-
- kfree(crtc->state);
- crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL);
-
- if (crtc->state)
- crtc->state->crtc = crtc;
-}
-EXPORT_SYMBOL(drm_atomic_helper_crtc_reset);
-
-/**
- * __drm_atomic_helper_crtc_duplicate_state - copy atomic CRTC state
- * @crtc: CRTC object
- * @state: atomic CRTC state
- *
- * Copies atomic state from a CRTC's current state and resets inferred values.
- * This is useful for drivers that subclass the CRTC state.
- */
-void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,
- struct drm_crtc_state *state)
-{
- memcpy(state, crtc->state, sizeof(*state));
-
- if (state->mode_blob)
- drm_property_blob_get(state->mode_blob);
- if (state->degamma_lut)
- drm_property_blob_get(state->degamma_lut);
- if (state->ctm)
- drm_property_blob_get(state->ctm);
- if (state->gamma_lut)
- drm_property_blob_get(state->gamma_lut);
- state->mode_changed = false;
- state->active_changed = false;
- state->planes_changed = false;
- state->connectors_changed = false;
- state->color_mgmt_changed = false;
- state->zpos_changed = false;
- state->commit = NULL;
- state->event = NULL;
- state->pageflip_flags = 0;
-}
-EXPORT_SYMBOL(__drm_atomic_helper_crtc_duplicate_state);
-
-/**
- * drm_atomic_helper_crtc_duplicate_state - default state duplicate hook
- * @crtc: drm CRTC
- *
- * Default CRTC state duplicate hook for drivers which don't have their own
- * subclassed CRTC state structure.
- */
-struct drm_crtc_state *
-drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc)
-{
- struct drm_crtc_state *state;
-
- if (WARN_ON(!crtc->state))
- return NULL;
-
- state = kmalloc(sizeof(*state), GFP_KERNEL);
- if (state)
- __drm_atomic_helper_crtc_duplicate_state(crtc, state);
-
- return state;
-}
-EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state);
-
-/**
- * __drm_atomic_helper_crtc_destroy_state - release CRTC state
- * @state: CRTC state object to release
- *
- * Releases all resources stored in the CRTC state without actually freeing
- * the memory of the CRTC state. This is useful for drivers that subclass the
- * CRTC state.
- */
-void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state)
-{
- if (state->commit) {
- /*
- * In the event that a non-blocking commit returns
- * -ERESTARTSYS before the commit_tail work is queued, we will
- * have an extra reference to the commit object. Release it, if
- * the event has not been consumed by the worker.
- *
- * state->event may be freed, so we can't directly look at
- * state->event->base.completion.
- */
- if (state->event && state->commit->abort_completion)
- drm_crtc_commit_put(state->commit);
-
- kfree(state->commit->event);
- state->commit->event = NULL;
-
- drm_crtc_commit_put(state->commit);
- }
-
- drm_property_blob_put(state->mode_blob);
- drm_property_blob_put(state->degamma_lut);
- drm_property_blob_put(state->ctm);
- drm_property_blob_put(state->gamma_lut);
-}
-EXPORT_SYMBOL(__drm_atomic_helper_crtc_destroy_state);
-
-/**
- * drm_atomic_helper_crtc_destroy_state - default state destroy hook
- * @crtc: drm CRTC
- * @state: CRTC state object to release
- *
- * Default CRTC state destroy hook for drivers which don't have their own
- * subclassed CRTC state structure.
- */
-void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
- struct drm_crtc_state *state)
-{
- __drm_atomic_helper_crtc_destroy_state(state);
- kfree(state);
-}
-EXPORT_SYMBOL(drm_atomic_helper_crtc_destroy_state);
-
-/**
- * __drm_atomic_helper_plane_reset - resets planes state to default values
- * @plane: plane object, must not be NULL
- * @state: atomic plane state, must not be NULL
- *
- * Initializes plane state to default. This is useful for drivers that subclass
- * the plane state.
- */
-void __drm_atomic_helper_plane_reset(struct drm_plane *plane,
- struct drm_plane_state *state)
-{
- state->plane = plane;
- state->rotation = DRM_MODE_ROTATE_0;
-
- state->alpha = DRM_BLEND_ALPHA_OPAQUE;
- state->pixel_blend_mode = DRM_MODE_BLEND_PREMULTI;
-
- plane->state = state;
-}
-EXPORT_SYMBOL(__drm_atomic_helper_plane_reset);
-
-/**
- * drm_atomic_helper_plane_reset - default &drm_plane_funcs.reset hook for planes
- * @plane: drm plane
- *
- * Resets the atomic state for @plane by freeing the state pointer (which might
- * be NULL, e.g. at driver load time) and allocating a new empty state object.
- */
-void drm_atomic_helper_plane_reset(struct drm_plane *plane)
-{
- if (plane->state)
- __drm_atomic_helper_plane_destroy_state(plane->state);
-
- kfree(plane->state);
- plane->state = kzalloc(sizeof(*plane->state), GFP_KERNEL);
- if (plane->state)
- __drm_atomic_helper_plane_reset(plane, plane->state);
-}
-EXPORT_SYMBOL(drm_atomic_helper_plane_reset);
-
-/**
- * __drm_atomic_helper_plane_duplicate_state - copy atomic plane state
- * @plane: plane object
- * @state: atomic plane state
- *
- * Copies atomic state from a plane's current state. This is useful for
- * drivers that subclass the plane state.
- */
-void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane,
- struct drm_plane_state *state)
-{
- memcpy(state, plane->state, sizeof(*state));
-
- if (state->fb)
- drm_framebuffer_get(state->fb);
-
- state->fence = NULL;
- state->commit = NULL;
-}
-EXPORT_SYMBOL(__drm_atomic_helper_plane_duplicate_state);
-
-/**
- * drm_atomic_helper_plane_duplicate_state - default state duplicate hook
- * @plane: drm plane
- *
- * Default plane state duplicate hook for drivers which don't have their own
- * subclassed plane state structure.
- */
-struct drm_plane_state *
-drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane)
-{
- struct drm_plane_state *state;
-
- if (WARN_ON(!plane->state))
- return NULL;
-
- state = kmalloc(sizeof(*state), GFP_KERNEL);
- if (state)
- __drm_atomic_helper_plane_duplicate_state(plane, state);
-
- return state;
-}
-EXPORT_SYMBOL(drm_atomic_helper_plane_duplicate_state);
-
-/**
- * __drm_atomic_helper_plane_destroy_state - release plane state
- * @state: plane state object to release
- *
- * Releases all resources stored in the plane state without actually freeing
- * the memory of the plane state. This is useful for drivers that subclass the
- * plane state.
- */
-void __drm_atomic_helper_plane_destroy_state(struct drm_plane_state *state)
-{
- if (state->fb)
- drm_framebuffer_put(state->fb);
-
- if (state->fence)
- dma_fence_put(state->fence);
-
- if (state->commit)
- drm_crtc_commit_put(state->commit);
-}
-EXPORT_SYMBOL(__drm_atomic_helper_plane_destroy_state);
-
-/**
- * drm_atomic_helper_plane_destroy_state - default state destroy hook
- * @plane: drm plane
- * @state: plane state object to release
- *
- * Default plane state destroy hook for drivers which don't have their own
- * subclassed plane state structure.
- */
-void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
- struct drm_plane_state *state)
-{
- __drm_atomic_helper_plane_destroy_state(state);
- kfree(state);
-}
-EXPORT_SYMBOL(drm_atomic_helper_plane_destroy_state);
-
-/**
- * __drm_atomic_helper_connector_reset - reset state on connector
- * @connector: drm connector
- * @conn_state: connector state to assign
- *
- * Initializes the newly allocated @conn_state and assigns it to
- * the &drm_conector->state pointer of @connector, usually required when
- * initializing the drivers or when called from the &drm_connector_funcs.reset
- * hook.
- *
- * This is useful for drivers that subclass the connector state.
- */
-void
-__drm_atomic_helper_connector_reset(struct drm_connector *connector,
- struct drm_connector_state *conn_state)
-{
- if (conn_state)
- conn_state->connector = connector;
-
- connector->state = conn_state;
-}
-EXPORT_SYMBOL(__drm_atomic_helper_connector_reset);
-
-/**
- * drm_atomic_helper_connector_reset - default &drm_connector_funcs.reset hook for connectors
- * @connector: drm connector
- *
- * Resets the atomic state for @connector by freeing the state pointer (which
- * might be NULL, e.g. at driver load time) and allocating a new empty state
- * object.
- */
-void drm_atomic_helper_connector_reset(struct drm_connector *connector)
-{
- struct drm_connector_state *conn_state =
- kzalloc(sizeof(*conn_state), GFP_KERNEL);
-
- if (connector->state)
- __drm_atomic_helper_connector_destroy_state(connector->state);
-
- kfree(connector->state);
- __drm_atomic_helper_connector_reset(connector, conn_state);
-}
-EXPORT_SYMBOL(drm_atomic_helper_connector_reset);
-
-/**
- * __drm_atomic_helper_connector_duplicate_state - copy atomic connector state
- * @connector: connector object
- * @state: atomic connector state
- *
- * Copies atomic state from a connector's current state. This is useful for
- * drivers that subclass the connector state.
- */
-void
-__drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
- struct drm_connector_state *state)
-{
- memcpy(state, connector->state, sizeof(*state));
- if (state->crtc)
- drm_connector_get(connector);
- state->commit = NULL;
-
- /* Don't copy over a writeback job, they are used only once */
- state->writeback_job = NULL;
-}
-EXPORT_SYMBOL(__drm_atomic_helper_connector_duplicate_state);
-
-/**
- * drm_atomic_helper_connector_duplicate_state - default state duplicate hook
- * @connector: drm connector
- *
- * Default connector state duplicate hook for drivers which don't have their own
- * subclassed connector state structure.
- */
-struct drm_connector_state *
-drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector)
-{
- struct drm_connector_state *state;
-
- if (WARN_ON(!connector->state))
- return NULL;
-
- state = kmalloc(sizeof(*state), GFP_KERNEL);
- if (state)
- __drm_atomic_helper_connector_duplicate_state(connector, state);
-
- return state;
-}
-EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state);
-
-/**
- * drm_atomic_helper_duplicate_state - duplicate an atomic state object
- * @dev: DRM device
- * @ctx: lock acquisition context
- *
- * Makes a copy of the current atomic state by looping over all objects and
- * duplicating their respective states. This is used for example by suspend/
- * resume support code to save the state prior to suspend such that it can
- * be restored upon resume.
- *
- * Note that this treats atomic state as persistent between save and restore.
- * Drivers must make sure that this is possible and won't result in confusion
- * or erroneous behaviour.
- *
- * Note that if callers haven't already acquired all modeset locks this might
- * return -EDEADLK, which must be handled by calling drm_modeset_backoff().
- *
- * Returns:
- * A pointer to the copy of the atomic state object on success or an
- * ERR_PTR()-encoded error code on failure.
- *
- * See also:
- * drm_atomic_helper_suspend(), drm_atomic_helper_resume()
- */
-struct drm_atomic_state *
-drm_atomic_helper_duplicate_state(struct drm_device *dev,
- struct drm_modeset_acquire_ctx *ctx)
-{
- struct drm_atomic_state *state;
- struct drm_connector *conn;
- struct drm_connector_list_iter conn_iter;
- struct drm_plane *plane;
- struct drm_crtc *crtc;
- int err = 0;
-
- state = drm_atomic_state_alloc(dev);
- if (!state)
- return ERR_PTR(-ENOMEM);
-
- state->acquire_ctx = ctx;
-
- drm_for_each_crtc(crtc, dev) {
- struct drm_crtc_state *crtc_state;
-
- crtc_state = drm_atomic_get_crtc_state(state, crtc);
- if (IS_ERR(crtc_state)) {
- err = PTR_ERR(crtc_state);
- goto free;
- }
- }
-
- drm_for_each_plane(plane, dev) {
- struct drm_plane_state *plane_state;
-
- plane_state = drm_atomic_get_plane_state(state, plane);
- if (IS_ERR(plane_state)) {
- err = PTR_ERR(plane_state);
- goto free;
- }
- }
-
- drm_connector_list_iter_begin(dev, &conn_iter);
- drm_for_each_connector_iter(conn, &conn_iter) {
- struct drm_connector_state *conn_state;
-
- conn_state = drm_atomic_get_connector_state(state, conn);
- if (IS_ERR(conn_state)) {
- err = PTR_ERR(conn_state);
- drm_connector_list_iter_end(&conn_iter);
- goto free;
- }
- }
- drm_connector_list_iter_end(&conn_iter);
-
- /* clear the acquire context so that it isn't accidentally reused */
- state->acquire_ctx = NULL;
-
-free:
- if (err < 0) {
- drm_atomic_state_put(state);
- state = ERR_PTR(err);
- }
-
- return state;
-}
-EXPORT_SYMBOL(drm_atomic_helper_duplicate_state);
-
-/**
- * __drm_atomic_helper_connector_destroy_state - release connector state
- * @state: connector state object to release
- *
- * Releases all resources stored in the connector state without actually
- * freeing the memory of the connector state. This is useful for drivers that
- * subclass the connector state.
- */
-void
-__drm_atomic_helper_connector_destroy_state(struct drm_connector_state *state)
-{
- if (state->crtc)
- drm_connector_put(state->connector);
-
- if (state->commit)
- drm_crtc_commit_put(state->commit);
-}
-EXPORT_SYMBOL(__drm_atomic_helper_connector_destroy_state);
-
-/**
- * drm_atomic_helper_connector_destroy_state - default state destroy hook
- * @connector: drm connector
- * @state: connector state object to release
- *
- * Default connector state destroy hook for drivers which don't have their own
- * subclassed connector state structure.
- */
-void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
- struct drm_connector_state *state)
-{
- __drm_atomic_helper_connector_destroy_state(state);
- kfree(state);
-}
-EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state);
-
-/**
- * drm_atomic_helper_legacy_gamma_set - set the legacy gamma correction table
- * @crtc: CRTC object
- * @red: red correction table
- * @green: green correction table
- * @blue: green correction table
- * @size: size of the tables
- * @ctx: lock acquire context
- *
- * Implements support for legacy gamma correction table for drivers
- * that support color management through the DEGAMMA_LUT/GAMMA_LUT
- * properties. See drm_crtc_enable_color_mgmt() and the containing chapter for
- * how the atomic color management and gamma tables work.
- */
-int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
- u16 *red, u16 *green, u16 *blue,
- uint32_t size,
- struct drm_modeset_acquire_ctx *ctx)
-{
- struct drm_device *dev = crtc->dev;
- struct drm_atomic_state *state;
- struct drm_crtc_state *crtc_state;
- struct drm_property_blob *blob = NULL;
- struct drm_color_lut *blob_data;
- int i, ret = 0;
- bool replaced;
-
- state = drm_atomic_state_alloc(crtc->dev);
- if (!state)
- return -ENOMEM;
-
- blob = drm_property_create_blob(dev,
- sizeof(struct drm_color_lut) * size,
- NULL);
- if (IS_ERR(blob)) {
- ret = PTR_ERR(blob);
- blob = NULL;
- goto fail;
- }
-
- /* Prepare GAMMA_LUT with the legacy values. */
- blob_data = blob->data;
- for (i = 0; i < size; i++) {
- blob_data[i].red = red[i];
- blob_data[i].green = green[i];
- blob_data[i].blue = blue[i];
- }
-
- state->acquire_ctx = ctx;
- crtc_state = drm_atomic_get_crtc_state(state, crtc);
- if (IS_ERR(crtc_state)) {
- ret = PTR_ERR(crtc_state);
- goto fail;
- }
-
- /* Reset DEGAMMA_LUT and CTM properties. */
- replaced = drm_property_replace_blob(&crtc_state->degamma_lut, NULL);
- replaced |= drm_property_replace_blob(&crtc_state->ctm, NULL);
- replaced |= drm_property_replace_blob(&crtc_state->gamma_lut, blob);
- crtc_state->color_mgmt_changed |= replaced;
-
- ret = drm_atomic_commit(state);
-
-fail:
- drm_atomic_state_put(state);
- drm_property_blob_put(blob);
- return ret;
-}
-EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set);
-
-/**
- * __drm_atomic_helper_private_duplicate_state - copy atomic private state
- * @obj: CRTC object
- * @state: new private object state
- *
- * Copies atomic state from a private objects's current state and resets inferred values.
- * This is useful for drivers that subclass the private state.
- */
-void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj,
- struct drm_private_state *state)
-{
- memcpy(state, obj->state, sizeof(*state));
-}
-EXPORT_SYMBOL(__drm_atomic_helper_private_obj_duplicate_state);
diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
new file mode 100644
index 000000000000..3ba996069d69
--- /dev/null
+++ b/drivers/gpu/drm/drm_atomic_state_helper.c
@@ -0,0 +1,601 @@
+/*
+ * Copyright (C) 2018 Intel Corp.
+ *
+ * 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.
+ *
+ * Authors:
+ * Rob Clark <robdclark@gmail.com>
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ */
+
+#include <drm/drm_atomic_state_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_plane.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_device.h>
+
+#include <linux/slab.h>
+#include <linux/dma-fence.h>
+
+/**
+ * DOC: atomic state reset and initialization
+ *
+ * Both the drm core and the atomic helpers assume that there is always the full
+ * and correct atomic software state for all connectors, CRTCs and planes
+ * available. Which is a bit a problem on driver load and also after system
+ * suspend. One way to solve this is to have a hardware state read-out
+ * infrastructure which reconstructs the full software state (e.g. the i915
+ * driver).
+ *
+ * The simpler solution is to just reset the software state to everything off,
+ * which is easiest to do by calling drm_mode_config_reset(). To facilitate this
+ * the atomic helpers provide default reset implementations for all hooks.
+ *
+ * On the upside the precise state tracking of atomic simplifies system suspend
+ * and resume a lot. For drivers using drm_mode_config_reset() a complete recipe
+ * is implemented in drm_atomic_helper_suspend() and drm_atomic_helper_resume().
+ * For other drivers the building blocks are split out, see the documentation
+ * for these functions.
+ */
+
+/**
+ * drm_atomic_helper_crtc_reset - default &drm_crtc_funcs.reset hook for CRTCs
+ * @crtc: drm CRTC
+ *
+ * Resets the atomic state for @crtc by freeing the state pointer (which might
+ * be NULL, e.g. at driver load time) and allocating a new empty state object.
+ */
+void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc)
+{
+ if (crtc->state)
+ __drm_atomic_helper_crtc_destroy_state(crtc->state);
+
+ kfree(crtc->state);
+ crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL);
+
+ if (crtc->state)
+ crtc->state->crtc = crtc;
+}
+EXPORT_SYMBOL(drm_atomic_helper_crtc_reset);
+
+/**
+ * __drm_atomic_helper_crtc_duplicate_state - copy atomic CRTC state
+ * @crtc: CRTC object
+ * @state: atomic CRTC state
+ *
+ * Copies atomic state from a CRTC's current state and resets inferred values.
+ * This is useful for drivers that subclass the CRTC state.
+ */
+void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+{
+ memcpy(state, crtc->state, sizeof(*state));
+
+ if (state->mode_blob)
+ drm_property_blob_get(state->mode_blob);
+ if (state->degamma_lut)
+ drm_property_blob_get(state->degamma_lut);
+ if (state->ctm)
+ drm_property_blob_get(state->ctm);
+ if (state->gamma_lut)
+ drm_property_blob_get(state->gamma_lut);
+ state->mode_changed = false;
+ state->active_changed = false;
+ state->planes_changed = false;
+ state->connectors_changed = false;
+ state->color_mgmt_changed = false;
+ state->zpos_changed = false;
+ state->commit = NULL;
+ state->event = NULL;
+ state->pageflip_flags = 0;
+}
+EXPORT_SYMBOL(__drm_atomic_helper_crtc_duplicate_state);
+
+/**
+ * drm_atomic_helper_crtc_duplicate_state - default state duplicate hook
+ * @crtc: drm CRTC
+ *
+ * Default CRTC state duplicate hook for drivers which don't have their own
+ * subclassed CRTC state structure.
+ */
+struct drm_crtc_state *
+drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc)
+{
+ struct drm_crtc_state *state;
+
+ if (WARN_ON(!crtc->state))
+ return NULL;
+
+ state = kmalloc(sizeof(*state), GFP_KERNEL);
+ if (state)
+ __drm_atomic_helper_crtc_duplicate_state(crtc, state);
+
+ return state;
+}
+EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state);
+
+/**
+ * __drm_atomic_helper_crtc_destroy_state - release CRTC state
+ * @state: CRTC state object to release
+ *
+ * Releases all resources stored in the CRTC state without actually freeing
+ * the memory of the CRTC state. This is useful for drivers that subclass the
+ * CRTC state.
+ */
+void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state)
+{
+ if (state->commit) {
+ /*
+ * In the event that a non-blocking commit returns
+ * -ERESTARTSYS before the commit_tail work is queued, we will
+ * have an extra reference to the commit object. Release it, if
+ * the event has not been consumed by the worker.
+ *
+ * state->event may be freed, so we can't directly look at
+ * state->event->base.completion.
+ */
+ if (state->event && state->commit->abort_completion)
+ drm_crtc_commit_put(state->commit);
+
+ kfree(state->commit->event);
+ state->commit->event = NULL;
+
+ drm_crtc_commit_put(state->commit);
+ }
+
+ drm_property_blob_put(state->mode_blob);
+ drm_property_blob_put(state->degamma_lut);
+ drm_property_blob_put(state->ctm);
+ drm_property_blob_put(state->gamma_lut);
+}
+EXPORT_SYMBOL(__drm_atomic_helper_crtc_destroy_state);
+
+/**
+ * drm_atomic_helper_crtc_destroy_state - default state destroy hook
+ * @crtc: drm CRTC
+ * @state: CRTC state object to release
+ *
+ * Default CRTC state destroy hook for drivers which don't have their own
+ * subclassed CRTC state structure.
+ */
+void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+{
+ __drm_atomic_helper_crtc_destroy_state(state);
+ kfree(state);
+}
+EXPORT_SYMBOL(drm_atomic_helper_crtc_destroy_state);
+
+/**
+ * __drm_atomic_helper_plane_reset - resets planes state to default values
+ * @plane: plane object, must not be NULL
+ * @state: atomic plane state, must not be NULL
+ *
+ * Initializes plane state to default. This is useful for drivers that subclass
+ * the plane state.
+ */
+void __drm_atomic_helper_plane_reset(struct drm_plane *plane,
+ struct drm_plane_state *state)
+{
+ state->plane = plane;
+ state->rotation = DRM_MODE_ROTATE_0;
+
+ state->alpha = DRM_BLEND_ALPHA_OPAQUE;
+ state->pixel_blend_mode = DRM_MODE_BLEND_PREMULTI;
+
+ plane->state = state;
+}
+EXPORT_SYMBOL(__drm_atomic_helper_plane_reset);
+
+/**
+ * drm_atomic_helper_plane_reset - default &drm_plane_funcs.reset hook for planes
+ * @plane: drm plane
+ *
+ * Resets the atomic state for @plane by freeing the state pointer (which might
+ * be NULL, e.g. at driver load time) and allocating a new empty state object.
+ */
+void drm_atomic_helper_plane_reset(struct drm_plane *plane)
+{
+ if (plane->state)
+ __drm_atomic_helper_plane_destroy_state(plane->state);
+
+ kfree(plane->state);
+ plane->state = kzalloc(sizeof(*plane->state), GFP_KERNEL);
+ if (plane->state)
+ __drm_atomic_helper_plane_reset(plane, plane->state);
+}
+EXPORT_SYMBOL(drm_atomic_helper_plane_reset);
+
+/**
+ * __drm_atomic_helper_plane_duplicate_state - copy atomic plane state
+ * @plane: plane object
+ * @state: atomic plane state
+ *
+ * Copies atomic state from a plane's current state. This is useful for
+ * drivers that subclass the plane state.
+ */
+void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane,
+ struct drm_plane_state *state)
+{
+ memcpy(state, plane->state, sizeof(*state));
+
+ if (state->fb)
+ drm_framebuffer_get(state->fb);
+
+ state->fence = NULL;
+ state->commit = NULL;
+}
+EXPORT_SYMBOL(__drm_atomic_helper_plane_duplicate_state);
+
+/**
+ * drm_atomic_helper_plane_duplicate_state - default state duplicate hook
+ * @plane: drm plane
+ *
+ * Default plane state duplicate hook for drivers which don't have their own
+ * subclassed plane state structure.
+ */
+struct drm_plane_state *
+drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane)
+{
+ struct drm_plane_state *state;
+
+ if (WARN_ON(!plane->state))
+ return NULL;
+
+ state = kmalloc(sizeof(*state), GFP_KERNEL);
+ if (state)
+ __drm_atomic_helper_plane_duplicate_state(plane, state);
+
+ return state;
+}
+EXPORT_SYMBOL(drm_atomic_helper_plane_duplicate_state);
+
+/**
+ * __drm_atomic_helper_plane_destroy_state - release plane state
+ * @state: plane state object to release
+ *
+ * Releases all resources stored in the plane state without actually freeing
+ * the memory of the plane state. This is useful for drivers that subclass the
+ * plane state.
+ */
+void __drm_atomic_helper_plane_destroy_state(struct drm_plane_state *state)
+{
+ if (state->fb)
+ drm_framebuffer_put(state->fb);
+
+ if (state->fence)
+ dma_fence_put(state->fence);
+
+ if (state->commit)
+ drm_crtc_commit_put(state->commit);
+}
+EXPORT_SYMBOL(__drm_atomic_helper_plane_destroy_state);
+
+/**
+ * drm_atomic_helper_plane_destroy_state - default state destroy hook
+ * @plane: drm plane
+ * @state: plane state object to release
+ *
+ * Default plane state destroy hook for drivers which don't have their own
+ * subclassed plane state structure.
+ */
+void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
+ struct drm_plane_state *state)
+{
+ __drm_atomic_helper_plane_destroy_state(state);
+ kfree(state);
+}
+EXPORT_SYMBOL(drm_atomic_helper_plane_destroy_state);
+
+/**
+ * __drm_atomic_helper_connector_reset - reset state on connector
+ * @connector: drm connector
+ * @conn_state: connector state to assign
+ *
+ * Initializes the newly allocated @conn_state and assigns it to
+ * the &drm_conector->state pointer of @connector, usually required when
+ * initializing the drivers or when called from the &drm_connector_funcs.reset
+ * hook.
+ *
+ * This is useful for drivers that subclass the connector state.
+ */
+void
+__drm_atomic_helper_connector_reset(struct drm_connector *connector,
+ struct drm_connector_state *conn_state)
+{
+ if (conn_state)
+ conn_state->connector = connector;
+
+ connector->state = conn_state;
+}
+EXPORT_SYMBOL(__drm_atomic_helper_connector_reset);
+
+/**
+ * drm_atomic_helper_connector_reset - default &drm_connector_funcs.reset hook for connectors
+ * @connector: drm connector
+ *
+ * Resets the atomic state for @connector by freeing the state pointer (which
+ * might be NULL, e.g. at driver load time) and allocating a new empty state
+ * object.
+ */
+void drm_atomic_helper_connector_reset(struct drm_connector *connector)
+{
+ struct drm_connector_state *conn_state =
+ kzalloc(sizeof(*conn_state), GFP_KERNEL);
+
+ if (connector->state)
+ __drm_atomic_helper_connector_destroy_state(connector->state);
+
+ kfree(connector->state);
+ __drm_atomic_helper_connector_reset(connector, conn_state);
+}
+EXPORT_SYMBOL(drm_atomic_helper_connector_reset);
+
+/**
+ * __drm_atomic_helper_connector_duplicate_state - copy atomic connector state
+ * @connector: connector object
+ * @state: atomic connector state
+ *
+ * Copies atomic state from a connector's current state. This is useful for
+ * drivers that subclass the connector state.
+ */
+void
+__drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
+ struct drm_connector_state *state)
+{
+ memcpy(state, connector->state, sizeof(*state));
+ if (state->crtc)
+ drm_connector_get(connector);
+ state->commit = NULL;
+
+ /* Don't copy over a writeback job, they are used only once */
+ state->writeback_job = NULL;
+}
+EXPORT_SYMBOL(__drm_atomic_helper_connector_duplicate_state);
+
+/**
+ * drm_atomic_helper_connector_duplicate_state - default state duplicate hook
+ * @connector: drm connector
+ *
+ * Default connector state duplicate hook for drivers which don't have their own
+ * subclassed connector state structure.
+ */
+struct drm_connector_state *
+drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector)
+{
+ struct drm_connector_state *state;
+
+ if (WARN_ON(!connector->state))
+ return NULL;
+
+ state = kmalloc(sizeof(*state), GFP_KERNEL);
+ if (state)
+ __drm_atomic_helper_connector_duplicate_state(connector, state);
+
+ return state;
+}
+EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state);
+
+/**
+ * drm_atomic_helper_duplicate_state - duplicate an atomic state object
+ * @dev: DRM device
+ * @ctx: lock acquisition context
+ *
+ * Makes a copy of the current atomic state by looping over all objects and
+ * duplicating their respective states. This is used for example by suspend/
+ * resume support code to save the state prior to suspend such that it can
+ * be restored upon resume.
+ *
+ * Note that this treats atomic state as persistent between save and restore.
+ * Drivers must make sure that this is possible and won't result in confusion
+ * or erroneous behaviour.
+ *
+ * Note that if callers haven't already acquired all modeset locks this might
+ * return -EDEADLK, which must be handled by calling drm_modeset_backoff().
+ *
+ * Returns:
+ * A pointer to the copy of the atomic state object on success or an
+ * ERR_PTR()-encoded error code on failure.
+ *
+ * See also:
+ * drm_atomic_helper_suspend(), drm_atomic_helper_resume()
+ */
+struct drm_atomic_state *
+drm_atomic_helper_duplicate_state(struct drm_device *dev,
+ struct drm_modeset_acquire_ctx *ctx)
+{
+ struct drm_atomic_state *state;
+ struct drm_connector *conn;
+ struct drm_connector_list_iter conn_iter;
+ struct drm_plane *plane;
+ struct drm_crtc *crtc;
+ int err = 0;
+
+ state = drm_atomic_state_alloc(dev);
+ if (!state)
+ return ERR_PTR(-ENOMEM);
+
+ state->acquire_ctx = ctx;
+
+ drm_for_each_crtc(crtc, dev) {
+ struct drm_crtc_state *crtc_state;
+
+ crtc_state = drm_atomic_get_crtc_state(state, crtc);
+ if (IS_ERR(crtc_state)) {
+ err = PTR_ERR(crtc_state);
+ goto free;
+ }
+ }
+
+ drm_for_each_plane(plane, dev) {
+ struct drm_plane_state *plane_state;
+
+ plane_state = drm_atomic_get_plane_state(state, plane);
+ if (IS_ERR(plane_state)) {
+ err = PTR_ERR(plane_state);
+ goto free;
+ }
+ }
+
+ drm_connector_list_iter_begin(dev, &conn_iter);
+ drm_for_each_connector_iter(conn, &conn_iter) {
+ struct drm_connector_state *conn_state;
+
+ conn_state = drm_atomic_get_connector_state(state, conn);
+ if (IS_ERR(conn_state)) {
+ err = PTR_ERR(conn_state);
+ drm_connector_list_iter_end(&conn_iter);
+ goto free;
+ }
+ }
+ drm_connector_list_iter_end(&conn_iter);
+
+ /* clear the acquire context so that it isn't accidentally reused */
+ state->acquire_ctx = NULL;
+
+free:
+ if (err < 0) {
+ drm_atomic_state_put(state);
+ state = ERR_PTR(err);
+ }
+
+ return state;
+}
+EXPORT_SYMBOL(drm_atomic_helper_duplicate_state);
+
+/**
+ * __drm_atomic_helper_connector_destroy_state - release connector state
+ * @state: connector state object to release
+ *
+ * Releases all resources stored in the connector state without actually
+ * freeing the memory of the connector state. This is useful for drivers that
+ * subclass the connector state.
+ */
+void
+__drm_atomic_helper_connector_destroy_state(struct drm_connector_state *state)
+{
+ if (state->crtc)
+ drm_connector_put(state->connector);
+
+ if (state->commit)
+ drm_crtc_commit_put(state->commit);
+}
+EXPORT_SYMBOL(__drm_atomic_helper_connector_destroy_state);
+
+/**
+ * drm_atomic_helper_connector_destroy_state - default state destroy hook
+ * @connector: drm connector
+ * @state: connector state object to release
+ *
+ * Default connector state destroy hook for drivers which don't have their own
+ * subclassed connector state structure.
+ */
+void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
+ struct drm_connector_state *state)
+{
+ __drm_atomic_helper_connector_destroy_state(state);
+ kfree(state);
+}
+EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state);
+
+/**
+ * drm_atomic_helper_legacy_gamma_set - set the legacy gamma correction table
+ * @crtc: CRTC object
+ * @red: red correction table
+ * @green: green correction table
+ * @blue: green correction table
+ * @size: size of the tables
+ * @ctx: lock acquire context
+ *
+ * Implements support for legacy gamma correction table for drivers
+ * that support color management through the DEGAMMA_LUT/GAMMA_LUT
+ * properties. See drm_crtc_enable_color_mgmt() and the containing chapter for
+ * how the atomic color management and gamma tables work.
+ */
+int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
+ u16 *red, u16 *green, u16 *blue,
+ uint32_t size,
+ struct drm_modeset_acquire_ctx *ctx)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_atomic_state *state;
+ struct drm_crtc_state *crtc_state;
+ struct drm_property_blob *blob = NULL;
+ struct drm_color_lut *blob_data;
+ int i, ret = 0;
+ bool replaced;
+
+ state = drm_atomic_state_alloc(crtc->dev);
+ if (!state)
+ return -ENOMEM;
+
+ blob = drm_property_create_blob(dev,
+ sizeof(struct drm_color_lut) * size,
+ NULL);
+ if (IS_ERR(blob)) {
+ ret = PTR_ERR(blob);
+ blob = NULL;
+ goto fail;
+ }
+
+ /* Prepare GAMMA_LUT with the legacy values. */
+ blob_data = blob->data;
+ for (i = 0; i < size; i++) {
+ blob_data[i].red = red[i];
+ blob_data[i].green = green[i];
+ blob_data[i].blue = blue[i];
+ }
+
+ state->acquire_ctx = ctx;
+ crtc_state = drm_atomic_get_crtc_state(state, crtc);
+ if (IS_ERR(crtc_state)) {
+ ret = PTR_ERR(crtc_state);
+ goto fail;
+ }
+
+ /* Reset DEGAMMA_LUT and CTM properties. */
+ replaced = drm_property_replace_blob(&crtc_state->degamma_lut, NULL);
+ replaced |= drm_property_replace_blob(&crtc_state->ctm, NULL);
+ replaced |= drm_property_replace_blob(&crtc_state->gamma_lut, blob);
+ crtc_state->color_mgmt_changed |= replaced;
+
+ ret = drm_atomic_commit(state);
+
+fail:
+ drm_atomic_state_put(state);
+ drm_property_blob_put(blob);
+ return ret;
+}
+EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set);
+
+/**
+ * __drm_atomic_helper_private_duplicate_state - copy atomic private state
+ * @obj: CRTC object
+ * @state: new private object state
+ *
+ * Copies atomic state from a private objects's current state and resets inferred values.
+ * This is useful for drivers that subclass the private state.
+ */
+void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj,
+ struct drm_private_state *state)
+{
+ memcpy(state, obj->state, sizeof(*state));
+}
+EXPORT_SYMBOL(__drm_atomic_helper_private_obj_duplicate_state);
diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c
index 7412acaf3cde..d7d10cabb9bb 100644
--- a/drivers/gpu/drm/drm_bufs.c
+++ b/drivers/gpu/drm/drm_bufs.c
@@ -36,6 +36,8 @@
#include <drm/drmP.h>
#include "drm_legacy.h"
+#include <linux/nospec.h>
+
static struct drm_map_list *drm_find_matching_map(struct drm_device *dev,
struct drm_local_map *map)
{
@@ -1417,6 +1419,7 @@ int drm_legacy_freebufs(struct drm_device *dev, void *data,
idx, dma->buf_count - 1);
return -EINVAL;
}
+ idx = array_index_nospec(idx, dma->buf_count);
buf = dma->buflist[idx];
if (buf->file_priv != file_priv) {
DRM_ERROR("Process %d freeing buffer not owned\n",
diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
index 17d9a64e885e..fc03d26fcacc 100644
--- a/drivers/gpu/drm/drm_client.c
+++ b/drivers/gpu/drm/drm_client.c
@@ -63,20 +63,21 @@ static void drm_client_close(struct drm_client_dev *client)
EXPORT_SYMBOL(drm_client_close);
/**
- * drm_client_new - Create a DRM client
+ * drm_client_init - Initialise a DRM client
* @dev: DRM device
* @client: DRM client
* @name: Client name
* @funcs: DRM client functions (optional)
*
+ * This initialises the client and opens a &drm_file. Use drm_client_add() to complete the process.
* The caller needs to hold a reference on @dev before calling this function.
* The client is freed when the &drm_device is unregistered. See drm_client_release().
*
* Returns:
* Zero on success or negative error code on failure.
*/
-int drm_client_new(struct drm_device *dev, struct drm_client_dev *client,
- const char *name, const struct drm_client_funcs *funcs)
+int drm_client_init(struct drm_device *dev, struct drm_client_dev *client,
+ const char *name, const struct drm_client_funcs *funcs)
{
int ret;
@@ -95,10 +96,6 @@ int drm_client_new(struct drm_device *dev, struct drm_client_dev *client,
if (ret)
goto err_put_module;
- mutex_lock(&dev->clientlist_mutex);
- list_add(&client->list, &dev->clientlist);
- mutex_unlock(&dev->clientlist_mutex);
-
drm_dev_get(dev);
return 0;
@@ -109,13 +106,33 @@ err_put_module:
return ret;
}
-EXPORT_SYMBOL(drm_client_new);
+EXPORT_SYMBOL(drm_client_init);
+
+/**
+ * drm_client_add - Add client to the device list
+ * @client: DRM client
+ *
+ * Add the client to the &drm_device client list to activate its callbacks.
+ * @client must be initialized by a call to drm_client_init(). After
+ * drm_client_add() it is no longer permissible to call drm_client_release()
+ * directly (outside the unregister callback), instead cleanup will happen
+ * automatically on driver unload.
+ */
+void drm_client_add(struct drm_client_dev *client)
+{
+ struct drm_device *dev = client->dev;
+
+ mutex_lock(&dev->clientlist_mutex);
+ list_add(&client->list, &dev->clientlist);
+ mutex_unlock(&dev->clientlist_mutex);
+}
+EXPORT_SYMBOL(drm_client_add);
/**
* drm_client_release - Release DRM client resources
* @client: DRM client
*
- * Releases resources by closing the &drm_file that was opened by drm_client_new().
+ * Releases resources by closing the &drm_file that was opened by drm_client_init().
* It is called automatically if the &drm_client_funcs.unregister callback is _not_ set.
*
* This function should only be called from the unregister callback. An exception
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 375cdce7df94..fa9baacc863b 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -260,9 +260,7 @@ int drm_connector_init(struct drm_device *dev,
if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL &&
connector_type != DRM_MODE_CONNECTOR_WRITEBACK)
- drm_object_attach_property(&connector->base,
- config->edid_property,
- 0);
+ drm_connector_attach_edid_property(connector);
drm_object_attach_property(&connector->base,
config->dpms_property, 0);
@@ -295,6 +293,24 @@ out_put:
EXPORT_SYMBOL(drm_connector_init);
/**
+ * drm_connector_attach_edid_property - attach edid property.
+ * @connector: the connector
+ *
+ * Some connector types like DRM_MODE_CONNECTOR_VIRTUAL do not get a
+ * edid property attached by default. This function can be used to
+ * explicitly enable the edid property in these cases.
+ */
+void drm_connector_attach_edid_property(struct drm_connector *connector)
+{
+ struct drm_mode_config *config = &connector->dev->mode_config;
+
+ drm_object_attach_property(&connector->base,
+ config->edid_property,
+ 0);
+}
+EXPORT_SYMBOL(drm_connector_attach_edid_property);
+
+/**
* drm_connector_attach_encoder - attach a connector to an encoder
* @connector: connector to attach
* @encoder: encoder to attach @connector to
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 5f488aa80bcd..268a182ae189 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -570,9 +570,9 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
struct drm_mode_crtc *crtc_req = data;
struct drm_crtc *crtc;
struct drm_plane *plane;
- struct drm_connector **connector_set = NULL, *connector;
- struct drm_framebuffer *fb = NULL;
- struct drm_display_mode *mode = NULL;
+ struct drm_connector **connector_set, *connector;
+ struct drm_framebuffer *fb;
+ struct drm_display_mode *mode;
struct drm_mode_set set;
uint32_t __user *set_connectors_ptr;
struct drm_modeset_acquire_ctx ctx;
@@ -601,6 +601,10 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
mutex_lock(&crtc->dev->mode_config.mutex);
drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE);
retry:
+ connector_set = NULL;
+ fb = NULL;
+ mode = NULL;
+
ret = drm_modeset_lock_all_ctx(crtc->dev, &ctx);
if (ret)
goto out;
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index ce75e9506e85..a3c81850e755 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -984,118 +984,3 @@ void drm_helper_resume_force_mode(struct drm_device *dev)
drm_modeset_unlock_all(dev);
}
EXPORT_SYMBOL(drm_helper_resume_force_mode);
-
-/**
- * drm_helper_crtc_mode_set - mode_set implementation for atomic plane helpers
- * @crtc: DRM CRTC
- * @mode: DRM display mode which userspace requested
- * @adjusted_mode: DRM display mode adjusted by ->mode_fixup callbacks
- * @x: x offset of the CRTC scanout area on the underlying framebuffer
- * @y: y offset of the CRTC scanout area on the underlying framebuffer
- * @old_fb: previous framebuffer
- *
- * This function implements a callback useable as the ->mode_set callback
- * required by the CRTC helpers. Besides the atomic plane helper functions for
- * the primary plane the driver must also provide the ->mode_set_nofb callback
- * to set up the CRTC.
- *
- * This is a transitional helper useful for converting drivers to the atomic
- * interfaces.
- */
-int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode, int x, int y,
- struct drm_framebuffer *old_fb)
-{
- struct drm_crtc_state *crtc_state;
- const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
- int ret;
-
- if (crtc->funcs->atomic_duplicate_state)
- crtc_state = crtc->funcs->atomic_duplicate_state(crtc);
- else {
- if (!crtc->state)
- drm_atomic_helper_crtc_reset(crtc);
-
- crtc_state = drm_atomic_helper_crtc_duplicate_state(crtc);
- }
-
- if (!crtc_state)
- return -ENOMEM;
-
- crtc_state->planes_changed = true;
- crtc_state->mode_changed = true;
- ret = drm_atomic_set_mode_for_crtc(crtc_state, mode);
- if (ret)
- goto out;
- drm_mode_copy(&crtc_state->adjusted_mode, adjusted_mode);
-
- if (crtc_funcs->atomic_check) {
- ret = crtc_funcs->atomic_check(crtc, crtc_state);
- if (ret)
- goto out;
- }
-
- swap(crtc->state, crtc_state);
-
- crtc_funcs->mode_set_nofb(crtc);
-
- ret = drm_helper_crtc_mode_set_base(crtc, x, y, old_fb);
-
-out:
- if (crtc_state) {
- if (crtc->funcs->atomic_destroy_state)
- crtc->funcs->atomic_destroy_state(crtc, crtc_state);
- else
- drm_atomic_helper_crtc_destroy_state(crtc, crtc_state);
- }
-
- return ret;
-}
-EXPORT_SYMBOL(drm_helper_crtc_mode_set);
-
-/**
- * drm_helper_crtc_mode_set_base - mode_set_base implementation for atomic plane helpers
- * @crtc: DRM CRTC
- * @x: x offset of the CRTC scanout area on the underlying framebuffer
- * @y: y offset of the CRTC scanout area on the underlying framebuffer
- * @old_fb: previous framebuffer
- *
- * This function implements a callback useable as the ->mode_set_base used
- * required by the CRTC helpers. The driver must provide the atomic plane helper
- * functions for the primary plane.
- *
- * This is a transitional helper useful for converting drivers to the atomic
- * interfaces.
- */
-int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
- struct drm_framebuffer *old_fb)
-{
- struct drm_plane_state *plane_state;
- struct drm_plane *plane = crtc->primary;
-
- if (plane->funcs->atomic_duplicate_state)
- plane_state = plane->funcs->atomic_duplicate_state(plane);
- else {
- if (!plane->state)
- drm_atomic_helper_plane_reset(plane);
-
- plane_state = drm_atomic_helper_plane_duplicate_state(plane);
- }
- if (!plane_state)
- return -ENOMEM;
- plane_state->plane = plane;
-
- plane_state->crtc = crtc;
- drm_atomic_set_fb_for_plane(plane_state, crtc->primary->fb);
- plane_state->crtc_x = 0;
- plane_state->crtc_y = 0;
- plane_state->crtc_h = crtc->mode.vdisplay;
- plane_state->crtc_w = crtc->mode.hdisplay;
- plane_state->src_x = x << 16;
- plane_state->src_y = y << 16;
- plane_state->src_h = crtc->mode.vdisplay << 16;
- plane_state->src_w = crtc->mode.hdisplay << 16;
-
- return drm_plane_helper_commit(plane, plane_state, old_fb);
-}
-EXPORT_SYMBOL(drm_helper_crtc_mode_set_base);
diff --git a/drivers/gpu/drm/drm_dp_cec.c b/drivers/gpu/drm/drm_dp_cec.c
index 8a718f85079a..b15cee85b702 100644
--- a/drivers/gpu/drm/drm_dp_cec.c
+++ b/drivers/gpu/drm/drm_dp_cec.c
@@ -424,8 +424,6 @@ void drm_dp_cec_register_connector(struct drm_dp_aux *aux, const char *name,
aux->cec.parent = parent;
INIT_DELAYED_WORK(&aux->cec.unregister_work,
drm_dp_cec_unregister_work);
-
- drm_dp_cec_set_edid(aux, NULL);
}
EXPORT_SYMBOL(drm_dp_cec_register_connector);
diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c
index 5ff1d79b86c4..529414556962 100644
--- a/drivers/gpu/drm/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/drm_dp_mst_topology.c
@@ -1275,6 +1275,9 @@ static struct drm_dp_mst_branch *drm_dp_get_mst_branch_device(struct drm_dp_mst_
mutex_lock(&mgr->lock);
mstb = mgr->mst_primary;
+ if (!mstb)
+ goto out;
+
for (i = 0; i < lct - 1; i++) {
int shift = (i % 2) ? 0 : 4;
int port_num = (rad[i / 2] >> shift) & 0xf;
@@ -2569,9 +2572,16 @@ struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_
EXPORT_SYMBOL(drm_dp_mst_get_edid);
/**
- * drm_dp_find_vcpi_slots() - find slots for this PBN value
+ * drm_dp_find_vcpi_slots() - Find VCPI slots for this PBN value
* @mgr: manager to use
* @pbn: payload bandwidth to convert into slots.
+ *
+ * Calculate the number of VCPI slots that will be required for the given PBN
+ * value. This function is deprecated, and should not be used in atomic
+ * drivers.
+ *
+ * RETURNS:
+ * The total slots required for this port, or error.
*/
int drm_dp_find_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr,
int pbn)
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 36e8e9cbec52..e2ffecd5e453 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -476,8 +476,6 @@ static void drm_fs_inode_free(struct inode *inode)
* The initial ref-count of the object is 1. Use drm_dev_get() and
* drm_dev_put() to take and drop further ref-counts.
*
- * Note that for purely virtual devices @parent can be NULL.
- *
* Drivers that do not want to allocate their own device struct
* embedding &struct drm_device can call drm_dev_alloc() instead. For drivers
* that do embed &struct drm_device it must be placed first in the overall
@@ -502,6 +500,8 @@ int drm_dev_init(struct drm_device *dev,
return -ENODEV;
}
+ BUG_ON(!parent);
+
kref_init(&dev->ref);
dev->dev = parent;
dev->driver = driver;
@@ -556,9 +556,7 @@ int drm_dev_init(struct drm_device *dev,
}
}
- /* Use the parent device name as DRM device unique identifier, but fall
- * back to the driver name for virtual devices like vgem. */
- ret = drm_dev_set_unique(dev, parent ? dev_name(parent) : driver->name);
+ ret = drm_dev_set_unique(dev, dev_name(parent));
if (ret)
goto err_setunique;
@@ -975,14 +973,12 @@ static void drm_core_exit(void)
drm_sysfs_destroy();
idr_destroy(&drm_minors_idr);
drm_connector_ida_destroy();
- drm_global_release();
}
static int __init drm_core_init(void)
{
int ret;
- drm_global_init();
drm_connector_ida_init();
idr_init(&drm_minors_idr);
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 08821dfa3327..b506e3622b08 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -113,6 +113,9 @@ static const struct edid_quirk {
/* AEO model 0 reports 8 bpc, but is a 6 bpc panel */
{ "AEO", 0, EDID_QUIRK_FORCE_6BPC },
+ /* BOE model on HP Pavilion 15-n233sl reports 8 bpc, but is a 6 bpc panel */
+ { "BOE", 0x78b, EDID_QUIRK_FORCE_6BPC },
+
/* CPT panel of Asus UX303LA reports 8 bpc, but is a 6 bpc panel */
{ "CPT", 0x17df, EDID_QUIRK_FORCE_6BPC },
@@ -4282,7 +4285,7 @@ static void drm_parse_ycbcr420_deep_color_info(struct drm_connector *connector,
struct drm_hdmi_info *hdmi = &connector->display_info.hdmi;
dc_mask = db[7] & DRM_EDID_YCBCR420_DC_MASK;
- hdmi->y420_dc_modes |= dc_mask;
+ hdmi->y420_dc_modes = dc_mask;
}
static void drm_parse_hdmi_forum_vsdb(struct drm_connector *connector,
diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c
index 47e0e2f6642d..5b516615881a 100644
--- a/drivers/gpu/drm/drm_fb_cma_helper.c
+++ b/drivers/gpu/drm/drm_fb_cma_helper.c
@@ -72,7 +72,9 @@ struct drm_gem_cma_object *drm_fb_cma_get_gem_obj(struct drm_framebuffer *fb,
EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_obj);
/**
- * drm_fb_cma_get_gem_addr() - Get physical address for framebuffer
+ * drm_fb_cma_get_gem_addr() - Get physical address for framebuffer, for pixel
+ * formats where values are grouped in blocks this will get you the beginning of
+ * the block
* @fb: The framebuffer
* @state: Which state of drm plane
* @plane: Which plane
@@ -87,6 +89,13 @@ dma_addr_t drm_fb_cma_get_gem_addr(struct drm_framebuffer *fb,
struct drm_gem_cma_object *obj;
dma_addr_t paddr;
u8 h_div = 1, v_div = 1;
+ u32 block_w = drm_format_info_block_width(fb->format, plane);
+ u32 block_h = drm_format_info_block_height(fb->format, plane);
+ u32 block_size = fb->format->char_per_block[plane];
+ u32 sample_x;
+ u32 sample_y;
+ u32 block_start_y;
+ u32 num_hblocks;
obj = drm_fb_cma_get_gem_obj(fb, plane);
if (!obj)
@@ -99,8 +108,13 @@ dma_addr_t drm_fb_cma_get_gem_addr(struct drm_framebuffer *fb,
v_div = fb->format->vsub;
}
- paddr += (fb->format->cpp[plane] * (state->src_x >> 16)) / h_div;
- paddr += (fb->pitches[plane] * (state->src_y >> 16)) / v_div;
+ sample_x = (state->src_x >> 16) / h_div;
+ sample_y = (state->src_y >> 16) / v_div;
+ block_start_y = (sample_y / block_h) * block_h;
+ num_hblocks = sample_x / block_w;
+
+ paddr += fb->pitches[plane] * block_start_y;
+ paddr += block_size * num_hblocks;
return paddr;
}
@@ -124,10 +138,7 @@ int drm_fb_cma_fbdev_init(struct drm_device *dev, unsigned int preferred_bpp,
/* dev->fb_helper will indirectly point to fbdev_cma after this call */
fbdev_cma = drm_fbdev_cma_init(dev, preferred_bpp, max_conn_count);
- if (IS_ERR(fbdev_cma))
- return PTR_ERR(fbdev_cma);
-
- return 0;
+ return PTR_ERR_OR_ZERO(fbdev_cma);
}
EXPORT_SYMBOL_GPL(drm_fb_cma_fbdev_init);
@@ -167,7 +178,7 @@ struct drm_fbdev_cma *drm_fbdev_cma_init(struct drm_device *dev,
fb_helper = &fbdev_cma->fb_helper;
- ret = drm_client_new(dev, &fb_helper->client, "fbdev", NULL);
+ ret = drm_client_init(dev, &fb_helper->client, "fbdev", NULL);
if (ret)
goto err_free;
@@ -176,6 +187,8 @@ struct drm_fbdev_cma *drm_fbdev_cma_init(struct drm_device *dev,
if (ret)
goto err_client_put;
+ drm_client_add(&fb_helper->client);
+
return fbdev_cma;
err_client_put:
@@ -224,21 +237,3 @@ void drm_fbdev_cma_hotplug_event(struct drm_fbdev_cma *fbdev_cma)
drm_fb_helper_hotplug_event(&fbdev_cma->fb_helper);
}
EXPORT_SYMBOL_GPL(drm_fbdev_cma_hotplug_event);
-
-/**
- * drm_fbdev_cma_set_suspend_unlocked - wrapper around
- * drm_fb_helper_set_suspend_unlocked
- * @fbdev_cma: The drm_fbdev_cma struct, may be NULL
- * @state: desired state, zero to resume, non-zero to suspend
- *
- * Calls drm_fb_helper_set_suspend, which is a wrapper around
- * fb_set_suspend implemented by fbdev core.
- */
-void drm_fbdev_cma_set_suspend_unlocked(struct drm_fbdev_cma *fbdev_cma,
- bool state)
-{
- if (fbdev_cma)
- drm_fb_helper_set_suspend_unlocked(&fbdev_cma->fb_helper,
- state);
-}
-EXPORT_SYMBOL(drm_fbdev_cma_set_suspend_unlocked);
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 9b111e846847..9a69ad7e9f3b 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1599,6 +1599,25 @@ unlock:
}
EXPORT_SYMBOL(drm_fb_helper_ioctl);
+static bool drm_fb_pixel_format_equal(const struct fb_var_screeninfo *var_1,
+ const struct fb_var_screeninfo *var_2)
+{
+ return var_1->bits_per_pixel == var_2->bits_per_pixel &&
+ var_1->grayscale == var_2->grayscale &&
+ var_1->red.offset == var_2->red.offset &&
+ var_1->red.length == var_2->red.length &&
+ var_1->red.msb_right == var_2->red.msb_right &&
+ var_1->green.offset == var_2->green.offset &&
+ var_1->green.length == var_2->green.length &&
+ var_1->green.msb_right == var_2->green.msb_right &&
+ var_1->blue.offset == var_2->blue.offset &&
+ var_1->blue.length == var_2->blue.length &&
+ var_1->blue.msb_right == var_2->blue.msb_right &&
+ var_1->transp.offset == var_2->transp.offset &&
+ var_1->transp.length == var_2->transp.length &&
+ var_1->transp.msb_right == var_2->transp.msb_right;
+}
+
/**
* drm_fb_helper_check_var - implementation for &fb_ops.fb_check_var
* @var: screeninfo to check
@@ -1609,11 +1628,14 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
{
struct drm_fb_helper *fb_helper = info->par;
struct drm_framebuffer *fb = fb_helper->fb;
- int depth;
if (var->pixclock != 0 || in_dbg_master())
return -EINVAL;
+ if ((drm_format_info_block_width(fb->format, 0) > 1) ||
+ (drm_format_info_block_height(fb->format, 0) > 1))
+ return -EINVAL;
+
/*
* Changes struct fb_var_screeninfo are currently not pushed back
* to KMS, hence fail if different settings are requested.
@@ -1629,72 +1651,15 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
return -EINVAL;
}
- switch (var->bits_per_pixel) {
- case 16:
- depth = (var->green.length == 6) ? 16 : 15;
- break;
- case 32:
- depth = (var->transp.length > 0) ? 32 : 24;
- break;
- default:
- depth = var->bits_per_pixel;
- break;
- }
-
- switch (depth) {
- case 8:
- var->red.offset = 0;
- var->green.offset = 0;
- var->blue.offset = 0;
- var->red.length = 8;
- var->green.length = 8;
- var->blue.length = 8;
- var->transp.length = 0;
- var->transp.offset = 0;
- break;
- case 15:
- var->red.offset = 10;
- var->green.offset = 5;
- var->blue.offset = 0;
- var->red.length = 5;
- var->green.length = 5;
- var->blue.length = 5;
- var->transp.length = 1;
- var->transp.offset = 15;
- break;
- case 16:
- var->red.offset = 11;
- var->green.offset = 5;
- var->blue.offset = 0;
- var->red.length = 5;
- var->green.length = 6;
- var->blue.length = 5;
- var->transp.length = 0;
- var->transp.offset = 0;
- break;
- case 24:
- var->red.offset = 16;
- var->green.offset = 8;
- var->blue.offset = 0;
- var->red.length = 8;
- var->green.length = 8;
- var->blue.length = 8;
- var->transp.length = 0;
- var->transp.offset = 0;
- break;
- case 32:
- var->red.offset = 16;
- var->green.offset = 8;
- var->blue.offset = 0;
- var->red.length = 8;
- var->green.length = 8;
- var->blue.length = 8;
- var->transp.length = 8;
- var->transp.offset = 24;
- break;
- default:
+ /*
+ * drm fbdev emulation doesn't support changing the pixel format at all,
+ * so reject all pixel format changing requests.
+ */
+ if (!drm_fb_pixel_format_equal(var, &info->var)) {
+ DRM_DEBUG("fbdev emulation doesn't support changing the pixel format\n");
return -EINVAL;
}
+
return 0;
}
EXPORT_SYMBOL(drm_fb_helper_check_var);
@@ -1988,6 +1953,8 @@ void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helpe
{
struct drm_framebuffer *fb = fb_helper->fb;
+ WARN_ON((drm_format_info_block_width(fb->format, 0) > 1) ||
+ (drm_format_info_block_height(fb->format, 0) > 1));
info->pseudo_palette = fb_helper->pseudo_palette;
info->var.xres_virtual = fb->width;
info->var.yres_virtual = fb->height;
@@ -3258,13 +3225,15 @@ int drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp)
if (!fb_helper)
return -ENOMEM;
- ret = drm_client_new(dev, &fb_helper->client, "fbdev", &drm_fbdev_client_funcs);
+ ret = drm_client_init(dev, &fb_helper->client, "fbdev", &drm_fbdev_client_funcs);
if (ret) {
kfree(fb_helper);
DRM_DEV_ERROR(dev->dev, "Failed to register client: %d\n", ret);
return ret;
}
+ drm_client_add(&fb_helper->client);
+
fb_helper->preferred_bpp = preferred_bpp;
ret = drm_fbdev_client_hotplug(&fb_helper->client);
diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c
index 90a1c846fc25..f523948c82b1 100644
--- a/drivers/gpu/drm/drm_fourcc.c
+++ b/drivers/gpu/drm/drm_fourcc.c
@@ -97,14 +97,14 @@ EXPORT_SYMBOL(drm_mode_legacy_fb_format);
/**
* drm_driver_legacy_fb_format - compute drm fourcc code from legacy description
+ * @dev: DRM device
* @bpp: bits per pixels
* @depth: bit depth per pixel
- * @native: use host native byte order
*
* Computes a drm fourcc pixel format code for the given @bpp/@depth values.
* Unlike drm_mode_legacy_fb_format() this looks at the drivers mode_config,
- * and depending on the quirk_addfb_prefer_host_byte_order flag it returns
- * little endian byte order or host byte order framebuffer formats.
+ * and depending on the &drm_mode_config.quirk_addfb_prefer_host_byte_order flag
+ * it returns little endian byte order or host byte order framebuffer formats.
*/
uint32_t drm_driver_legacy_fb_format(struct drm_device *dev,
uint32_t bpp, uint32_t depth)
@@ -225,6 +225,18 @@ const struct drm_format_info *__drm_format_info(u32 format)
{ .format = DRM_FORMAT_UYVY, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true },
{ .format = DRM_FORMAT_VYUY, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true },
{ .format = DRM_FORMAT_AYUV, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true, .is_yuv = true },
+ { .format = DRM_FORMAT_Y0L0, .depth = 0, .num_planes = 1,
+ .char_per_block = { 8, 0, 0 }, .block_w = { 2, 0, 0 }, .block_h = { 2, 0, 0 },
+ .hsub = 2, .vsub = 2, .has_alpha = true, .is_yuv = true },
+ { .format = DRM_FORMAT_X0L0, .depth = 0, .num_planes = 1,
+ .char_per_block = { 8, 0, 0 }, .block_w = { 2, 0, 0 }, .block_h = { 2, 0, 0 },
+ .hsub = 2, .vsub = 2, .is_yuv = true },
+ { .format = DRM_FORMAT_Y0L2, .depth = 0, .num_planes = 1,
+ .char_per_block = { 8, 0, 0 }, .block_w = { 2, 0, 0 }, .block_h = { 2, 0, 0 },
+ .hsub = 2, .vsub = 2, .has_alpha = true, .is_yuv = true },
+ { .format = DRM_FORMAT_X0L2, .depth = 0, .num_planes = 1,
+ .char_per_block = { 8, 0, 0 }, .block_w = { 2, 0, 0 }, .block_h = { 2, 0, 0 },
+ .hsub = 2, .vsub = 2, .is_yuv = true },
};
unsigned int i;
@@ -400,3 +412,65 @@ int drm_format_plane_height(int height, uint32_t format, int plane)
return height / info->vsub;
}
EXPORT_SYMBOL(drm_format_plane_height);
+
+/**
+ * drm_format_info_block_width - width in pixels of block.
+ * @info: pixel format info
+ * @plane: plane index
+ *
+ * Returns:
+ * The width in pixels of a block, depending on the plane index.
+ */
+unsigned int drm_format_info_block_width(const struct drm_format_info *info,
+ int plane)
+{
+ if (!info || plane < 0 || plane >= info->num_planes)
+ return 0;
+
+ if (!info->block_w[plane])
+ return 1;
+ return info->block_w[plane];
+}
+EXPORT_SYMBOL(drm_format_info_block_width);
+
+/**
+ * drm_format_info_block_height - height in pixels of a block
+ * @info: pixel format info
+ * @plane: plane index
+ *
+ * Returns:
+ * The height in pixels of a block, depending on the plane index.
+ */
+unsigned int drm_format_info_block_height(const struct drm_format_info *info,
+ int plane)
+{
+ if (!info || plane < 0 || plane >= info->num_planes)
+ return 0;
+
+ if (!info->block_h[plane])
+ return 1;
+ return info->block_h[plane];
+}
+EXPORT_SYMBOL(drm_format_info_block_height);
+
+/**
+ * drm_format_info_min_pitch - computes the minimum required pitch in bytes
+ * @info: pixel format info
+ * @plane: plane index
+ * @buffer_width: buffer width in pixels
+ *
+ * Returns:
+ * The minimum required pitch in bytes for a buffer by taking into consideration
+ * the pixel format information and the buffer width.
+ */
+uint64_t drm_format_info_min_pitch(const struct drm_format_info *info,
+ int plane, unsigned int buffer_width)
+{
+ if (!info || plane < 0 || plane >= info->num_planes)
+ return 0;
+
+ return DIV_ROUND_UP_ULL((u64)buffer_width * info->char_per_block[plane],
+ drm_format_info_block_width(info, plane) *
+ drm_format_info_block_height(info, plane));
+}
+EXPORT_SYMBOL(drm_format_info_min_pitch);
diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c
index 3bf729d0aae5..fcaea8f50513 100644
--- a/drivers/gpu/drm/drm_framebuffer.c
+++ b/drivers/gpu/drm/drm_framebuffer.c
@@ -195,20 +195,26 @@ static int framebuffer_check(struct drm_device *dev,
for (i = 0; i < info->num_planes; i++) {
unsigned int width = fb_plane_width(r->width, info, i);
unsigned int height = fb_plane_height(r->height, info, i);
- unsigned int cpp = info->cpp[i];
+ unsigned int block_size = info->char_per_block[i];
+ u64 min_pitch = drm_format_info_min_pitch(info, i, width);
+
+ if (!block_size && (r->modifier[i] == DRM_FORMAT_MOD_LINEAR)) {
+ DRM_DEBUG_KMS("Format requires non-linear modifier for plane %d\n", i);
+ return -EINVAL;
+ }
if (!r->handles[i]) {
DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i);
return -EINVAL;
}
- if ((uint64_t) width * cpp > UINT_MAX)
+ if (min_pitch > UINT_MAX)
return -ERANGE;
if ((uint64_t) height * r->pitches[i] + r->offsets[i] > UINT_MAX)
return -ERANGE;
- if (r->pitches[i] < width * cpp) {
+ if (block_size && r->pitches[i] < min_pitch) {
DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i);
return -EINVAL;
}
@@ -317,6 +323,7 @@ drm_internal_framebuffer_create(struct drm_device *dev,
return fb;
}
+EXPORT_SYMBOL_FOR_TESTS_ONLY(drm_internal_framebuffer_create);
/**
* drm_mode_addfb2 - add an FB to the graphics configuration
diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c
index ded7a379ac35..acb466d25afc 100644
--- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c
+++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c
@@ -171,7 +171,7 @@ drm_gem_fb_create_with_funcs(struct drm_device *dev, struct drm_file *file,
}
min_size = (height - 1) * mode_cmd->pitches[i]
- + width * info->cpp[i]
+ + drm_format_info_min_pitch(info, i, width)
+ mode_cmd->offsets[i];
if (objs[i]->size < min_size) {
diff --git a/drivers/gpu/drm/drm_global.c b/drivers/gpu/drm/drm_global.c
deleted file mode 100644
index 5799e2782dd1..000000000000
--- a/drivers/gpu/drm/drm_global.c
+++ /dev/null
@@ -1,137 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0 OR MIT
-/**************************************************************************
- *
- * Copyright 2008-2009 VMware, Inc., Palo Alto, CA., USA
- *
- * 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, sub license, 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 (including the
- * next paragraph) 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 NON-INFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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.
- *
- **************************************************************************/
-/*
- * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
- */
-
-#include <linux/mutex.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <drm/drm_global.h>
-
-struct drm_global_item {
- struct mutex mutex;
- void *object;
- int refcount;
-};
-
-static struct drm_global_item glob[DRM_GLOBAL_NUM];
-
-void drm_global_init(void)
-{
- int i;
-
- for (i = 0; i < DRM_GLOBAL_NUM; ++i) {
- struct drm_global_item *item = &glob[i];
- mutex_init(&item->mutex);
- item->object = NULL;
- item->refcount = 0;
- }
-}
-
-void drm_global_release(void)
-{
- int i;
- for (i = 0; i < DRM_GLOBAL_NUM; ++i) {
- struct drm_global_item *item = &glob[i];
- BUG_ON(item->object != NULL);
- BUG_ON(item->refcount != 0);
- }
-}
-
-/**
- * drm_global_item_ref - Initialize and acquire reference to memory
- * object
- * @ref: Object for initialization
- *
- * This initializes a memory object, allocating memory and calling the
- * .init() hook. Further calls will increase the reference count for
- * that item.
- *
- * Returns:
- * Zero on success, non-zero otherwise.
- */
-int drm_global_item_ref(struct drm_global_reference *ref)
-{
- int ret = 0;
- struct drm_global_item *item = &glob[ref->global_type];
-
- mutex_lock(&item->mutex);
- if (item->refcount == 0) {
- ref->object = kzalloc(ref->size, GFP_KERNEL);
- if (unlikely(ref->object == NULL)) {
- ret = -ENOMEM;
- goto error_unlock;
- }
- ret = ref->init(ref);
- if (unlikely(ret != 0))
- goto error_free;
-
- item->object = ref->object;
- } else {
- ref->object = item->object;
- }
-
- ++item->refcount;
- mutex_unlock(&item->mutex);
- return 0;
-
-error_free:
- kfree(ref->object);
- ref->object = NULL;
-error_unlock:
- mutex_unlock(&item->mutex);
- return ret;
-}
-EXPORT_SYMBOL(drm_global_item_ref);
-
-/**
- * drm_global_item_unref - Drop reference to memory
- * object
- * @ref: Object being removed
- *
- * Drop a reference to the memory object and eventually call the
- * release() hook. The allocated object should be dropped in the
- * release() hook or before calling this function
- *
- */
-
-void drm_global_item_unref(struct drm_global_reference *ref)
-{
- struct drm_global_item *item = &glob[ref->global_type];
-
- mutex_lock(&item->mutex);
- BUG_ON(item->refcount == 0);
- BUG_ON(ref->object != item->object);
- if (--item->refcount == 0) {
- ref->release(ref);
- item->object = NULL;
- }
- mutex_unlock(&item->mutex);
-}
-EXPORT_SYMBOL(drm_global_item_unref);
-
diff --git a/drivers/gpu/drm/drm_lease.c b/drivers/gpu/drm/drm_lease.c
index 5894b4e144d7..3650d3c46718 100644
--- a/drivers/gpu/drm/drm_lease.c
+++ b/drivers/gpu/drm/drm_lease.c
@@ -39,7 +39,6 @@ struct drm_master *drm_lease_owner(struct drm_master *master)
master = master->lessor;
return master;
}
-EXPORT_SYMBOL(drm_lease_owner);
/**
* _drm_find_lessee - find lessee by id (idr_mutex held)
@@ -117,7 +116,6 @@ bool _drm_lease_held(struct drm_file *file_priv, int id)
return _drm_lease_held_master(file_priv->master, id);
}
-EXPORT_SYMBOL(_drm_lease_held);
/**
* drm_lease_held - check drm_mode_object lease status (idr_mutex not held)
@@ -144,7 +142,6 @@ bool drm_lease_held(struct drm_file *file_priv, int id)
mutex_unlock(&master->dev->mode_config.idr_mutex);
return ret;
}
-EXPORT_SYMBOL(drm_lease_held);
/**
* drm_lease_filter_crtcs - restricted crtc set to leased values (idr_mutex not held)
@@ -184,7 +181,6 @@ uint32_t drm_lease_filter_crtcs(struct drm_file *file_priv, uint32_t crtcs_in)
mutex_unlock(&master->dev->mode_config.idr_mutex);
return crtcs_out;
}
-EXPORT_SYMBOL(drm_lease_filter_crtcs);
/*
* drm_lease_create - create a new drm_master with leased objects (idr_mutex not held)
@@ -195,7 +191,7 @@ EXPORT_SYMBOL(drm_lease_filter_crtcs);
* make sure all of the desired objects can be leased, atomically
* leasing them to the new drmmaster.
*
- * ERR_PTR(-EACCESS) some other master holds the title to any object
+ * ERR_PTR(-EACCES) some other master holds the title to any object
* ERR_PTR(-ENOENT) some object is not a valid DRM object for this device
* ERR_PTR(-EBUSY) some other lessee holds title to this object
* ERR_PTR(-EEXIST) same object specified more than once in the provided list
@@ -357,9 +353,9 @@ void drm_lease_revoke(struct drm_master *top)
}
static int validate_lease(struct drm_device *dev,
- struct drm_file *lessor_priv,
int object_count,
- struct drm_mode_object **objects)
+ struct drm_mode_object **objects,
+ bool universal_planes)
{
int o;
int has_crtc = -1;
@@ -376,14 +372,14 @@ static int validate_lease(struct drm_device *dev,
if (objects[o]->type == DRM_MODE_OBJECT_CONNECTOR && has_connector == -1)
has_connector = o;
- if (lessor_priv->universal_planes) {
+ if (universal_planes) {
if (objects[o]->type == DRM_MODE_OBJECT_PLANE && has_plane == -1)
has_plane = o;
}
}
if (has_crtc == -1 || has_connector == -1)
return -EINVAL;
- if (lessor_priv->universal_planes && has_plane == -1)
+ if (universal_planes && has_plane == -1)
return -EINVAL;
return 0;
}
@@ -397,6 +393,8 @@ static int fill_object_idr(struct drm_device *dev,
struct drm_mode_object **objects;
u32 o;
int ret;
+ bool universal_planes = READ_ONCE(lessor_priv->universal_planes);
+
objects = kcalloc(object_count, sizeof(struct drm_mode_object *),
GFP_KERNEL);
if (!objects)
@@ -419,14 +417,17 @@ static int fill_object_idr(struct drm_device *dev,
}
if (!drm_mode_object_lease_required(objects[o]->type)) {
+ DRM_DEBUG_KMS("invalid object for lease\n");
ret = -EINVAL;
goto out_free_objects;
}
}
- ret = validate_lease(dev, lessor_priv, object_count, objects);
- if (ret)
+ ret = validate_lease(dev, object_count, objects, universal_planes);
+ if (ret) {
+ DRM_DEBUG_LEASE("lease validation failed\n");
goto out_free_objects;
+ }
/* add their IDs to the lease request - taking into account
universal planes */
@@ -449,7 +450,7 @@ static int fill_object_idr(struct drm_device *dev,
object_id, ret);
goto out_free_objects;
}
- if (obj->type == DRM_MODE_OBJECT_CRTC && !lessor_priv->universal_planes) {
+ if (obj->type == DRM_MODE_OBJECT_CRTC && !universal_planes) {
struct drm_crtc *crtc = obj_to_crtc(obj);
ret = idr_alloc(leases, &drm_lease_idr_object, crtc->primary->base.id, crtc->primary->base.id + 1, GFP_KERNEL);
if (ret < 0) {
@@ -509,15 +510,21 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev,
return -EOPNOTSUPP;
/* Do not allow sub-leases */
- if (lessor->lessor)
+ if (lessor->lessor) {
+ DRM_DEBUG_LEASE("recursive leasing not allowed\n");
return -EINVAL;
+ }
/* need some objects */
- if (cl->object_count == 0)
+ if (cl->object_count == 0) {
+ DRM_DEBUG_LEASE("no objects in lease\n");
return -EINVAL;
+ }
- if (cl->flags && (cl->flags & ~(O_CLOEXEC | O_NONBLOCK)))
+ if (cl->flags && (cl->flags & ~(O_CLOEXEC | O_NONBLOCK))) {
+ DRM_DEBUG_LEASE("invalid flags\n");
return -EINVAL;
+ }
object_count = cl->object_count;
@@ -532,6 +539,7 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev,
object_count, object_ids);
kfree(object_ids);
if (ret) {
+ DRM_DEBUG_LEASE("lease object lookup failed: %i\n", ret);
idr_destroy(&leases);
return ret;
}
@@ -566,14 +574,14 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev,
lessee_priv->is_master = 1;
lessee_priv->authenticated = 1;
- /* Hook up the fd */
- fd_install(fd, lessee_file);
-
/* Pass fd back to userspace */
DRM_DEBUG_LEASE("Returning fd %d id %d\n", fd, lessee->lessee_id);
cl->fd = fd;
cl->lessee_id = lessee->lessee_id;
+ /* Hook up the fd */
+ fd_install(fd, lessee_file);
+
DRM_DEBUG_LEASE("drm_mode_create_lease_ioctl succeeded\n");
return 0;
diff --git a/drivers/gpu/drm/drm_memory.c b/drivers/gpu/drm/drm_memory.c
index d69e4fc1ee77..40c4349cb939 100644
--- a/drivers/gpu/drm/drm_memory.c
+++ b/drivers/gpu/drm/drm_memory.c
@@ -51,7 +51,7 @@
#endif
static void *agp_remap(unsigned long offset, unsigned long size,
- struct drm_device * dev)
+ struct drm_device *dev)
{
unsigned long i, num_pages =
PAGE_ALIGN(size) / PAGE_SIZE;
@@ -94,26 +94,26 @@ static void *agp_remap(unsigned long offset, unsigned long size,
}
/** Wrapper around agp_free_memory() */
-void drm_free_agp(struct agp_memory * handle, int pages)
+void drm_free_agp(struct agp_memory *handle, int pages)
{
agp_free_memory(handle);
}
/** Wrapper around agp_bind_memory() */
-int drm_bind_agp(struct agp_memory * handle, unsigned int start)
+int drm_bind_agp(struct agp_memory *handle, unsigned int start)
{
return agp_bind_memory(handle, start);
}
/** Wrapper around agp_unbind_memory() */
-int drm_unbind_agp(struct agp_memory * handle)
+int drm_unbind_agp(struct agp_memory *handle)
{
return agp_unbind_memory(handle);
}
#else /* CONFIG_AGP */
static inline void *agp_remap(unsigned long offset, unsigned long size,
- struct drm_device * dev)
+ struct drm_device *dev)
{
return NULL;
}
diff --git a/drivers/gpu/drm/drm_mode_object.c b/drivers/gpu/drm/drm_mode_object.c
index be8b754eaf60..cd9bc0ce9be0 100644
--- a/drivers/gpu/drm/drm_mode_object.c
+++ b/drivers/gpu/drm/drm_mode_object.c
@@ -38,7 +38,8 @@ int __drm_mode_object_add(struct drm_device *dev, struct drm_mode_object *obj,
int ret;
mutex_lock(&dev->mode_config.idr_mutex);
- ret = idr_alloc(&dev->mode_config.crtc_idr, register_obj ? obj : NULL, 1, 0, GFP_KERNEL);
+ ret = idr_alloc(&dev->mode_config.crtc_idr, register_obj ? obj : NULL,
+ 1, 0, GFP_KERNEL);
if (ret >= 0) {
/*
* Set up the object linking under the protection of the idr
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 02db9ac82d7a..24a750436559 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -716,8 +716,8 @@ int of_get_drm_display_mode(struct device_node *np,
if (bus_flags)
drm_bus_flags_from_videomode(&vm, bus_flags);
- pr_debug("%pOF: got %dx%d display mode from %s\n",
- np, vm.hactive, vm.vactive, np->name);
+ pr_debug("%pOF: got %dx%d display mode\n",
+ np, vm.hactive, vm.vactive);
drm_mode_debug_printmodeline(dmode);
return 0;
diff --git a/drivers/gpu/drm/drm_modeset_helper.c b/drivers/gpu/drm/drm_modeset_helper.c
index f1c24ab0ef09..9150fa385bba 100644
--- a/drivers/gpu/drm/drm_modeset_helper.c
+++ b/drivers/gpu/drm/drm_modeset_helper.c
@@ -146,6 +146,21 @@ static struct drm_plane *create_primary_plane(struct drm_device *dev)
* Initialize a CRTC object with a default helper-provided primary plane and no
* cursor plane.
*
+ * Note that we make some assumptions about hardware limitations that may not be
+ * true for all hardware:
+ *
+ * 1. Primary plane cannot be repositioned.
+ * 2. Primary plane cannot be scaled.
+ * 3. Primary plane must cover the entire CRTC.
+ * 4. Subpixel positioning is not supported.
+ * 5. The primary plane must always be on if the CRTC is enabled.
+ *
+ * This is purely a backwards compatibility helper for old drivers. Drivers
+ * should instead implement their own primary plane. Atomic drivers must do so.
+ * Drivers with the above hardware restriction can look into using &struct
+ * drm_simple_display_pipe, which encapsulates the above limitations into a nice
+ * interface.
+ *
* Returns:
* Zero on success, error code on failure.
*/
diff --git a/drivers/gpu/drm/drm_panel_orientation_quirks.c b/drivers/gpu/drm/drm_panel_orientation_quirks.c
index ee4a5e1221f1..ab4e70e63f6e 100644
--- a/drivers/gpu/drm/drm_panel_orientation_quirks.c
+++ b/drivers/gpu/drm/drm_panel_orientation_quirks.c
@@ -59,6 +59,14 @@ static const struct drm_dmi_panel_orientation_data gpd_win = {
.orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
};
+static const struct drm_dmi_panel_orientation_data gpd_win2 = {
+ .width = 720,
+ .height = 1280,
+ .bios_dates = (const char * const []){
+ "12/07/2017", "05/24/2018", NULL },
+ .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
+};
+
static const struct drm_dmi_panel_orientation_data itworks_tw891 = {
.width = 800,
.height = 1280,
@@ -106,6 +114,14 @@ static const struct dmi_system_id orientation_data[] = {
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Default string"),
},
.driver_data = (void *)&gpd_win,
+ }, { /* GPD Win 2 (too generic strings, also match on bios date) */
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Default string"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Default string"),
+ DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Default string"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "Default string"),
+ },
+ .driver_data = (void *)&gpd_win2,
}, { /* I.T.Works TW891 */
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "To be filled by O.E.M."),
diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c
index 48f615d38931..a9d9df6c85ad 100644
--- a/drivers/gpu/drm/drm_pci.c
+++ b/drivers/gpu/drm/drm_pci.c
@@ -61,15 +61,14 @@ drm_dma_handle_t *drm_pci_alloc(struct drm_device * dev, size_t size, size_t ali
return NULL;
dmah->size = size;
- dmah->vaddr = dma_alloc_coherent(&dev->pdev->dev, size, &dmah->busaddr, GFP_KERNEL | __GFP_COMP);
+ dmah->vaddr = dma_zalloc_coherent(&dev->pdev->dev, size, &dmah->busaddr,
+ GFP_KERNEL | __GFP_COMP);
if (dmah->vaddr == NULL) {
kfree(dmah);
return NULL;
}
- memset(dmah->vaddr, 0, size);
-
/* XXX - Is virt_to_page() legal for consistent mem? */
/* Reserve */
for (addr = (unsigned long)dmah->vaddr, sz = size;
diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c
index 1fa98bd12003..679455e36829 100644
--- a/drivers/gpu/drm/drm_plane.c
+++ b/drivers/gpu/drm/drm_plane.c
@@ -636,6 +636,29 @@ static int __setplane_check(struct drm_plane *plane,
return 0;
}
+/**
+ * drm_any_plane_has_format - Check whether any plane supports this format and modifier combination
+ * @dev: DRM device
+ * @format: pixel format (DRM_FORMAT_*)
+ * @modifier: data layout modifier
+ *
+ * Returns:
+ * Whether at least one plane supports the specified format and modifier combination.
+ */
+bool drm_any_plane_has_format(struct drm_device *dev,
+ u32 format, u64 modifier)
+{
+ struct drm_plane *plane;
+
+ drm_for_each_plane(plane, dev) {
+ if (drm_plane_check_pixel_format(plane, format, modifier) == 0)
+ return true;
+ }
+
+ return false;
+}
+EXPORT_SYMBOL(drm_any_plane_has_format);
+
/*
* __setplane_internal - setplane handler for internal callers
*
diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c
index a393756b664e..0fff72dcd06d 100644
--- a/drivers/gpu/drm/drm_plane_helper.c
+++ b/drivers/gpu/drm/drm_plane_helper.c
@@ -42,11 +42,8 @@
* primary plane support on top of the normal CRTC configuration interface.
* Since the legacy &drm_mode_config_funcs.set_config interface ties the primary
* plane together with the CRTC state this does not allow userspace to disable
- * the primary plane itself. To avoid too much duplicated code use
- * drm_plane_helper_check_update() which can be used to enforce the same
- * restrictions as primary planes had thus. The default primary plane only
- * expose XRBG8888 and ARGB8888 as valid pixel formats for the attached
- * framebuffer.
+ * the primary plane itself. The default primary plane only expose XRBG8888 and
+ * ARGB8888 as valid pixel formats for the attached framebuffer.
*
* Drivers are highly recommended to implement proper support for primary
* planes, and newly merged drivers must not rely upon these transitional
@@ -100,43 +97,17 @@ static int get_connectors_for_crtc(struct drm_crtc *crtc,
return count;
}
-/**
- * drm_plane_helper_check_update() - Check plane update for validity
- * @plane: plane object to update
- * @crtc: owning CRTC of owning plane
- * @fb: framebuffer to flip onto plane
- * @src: source coordinates in 16.16 fixed point
- * @dst: integer destination coordinates
- * @rotation: plane rotation
- * @min_scale: minimum @src:@dest scaling factor in 16.16 fixed point
- * @max_scale: maximum @src:@dest scaling factor in 16.16 fixed point
- * @can_position: is it legal to position the plane such that it
- * doesn't cover the entire crtc? This will generally
- * only be false for primary planes.
- * @can_update_disabled: can the plane be updated while the crtc
- * is disabled?
- * @visible: output parameter indicating whether plane is still visible after
- * clipping
- *
- * Checks that a desired plane update is valid. Drivers that provide
- * their own plane handling rather than helper-provided implementations may
- * still wish to call this function to avoid duplication of error checking
- * code.
- *
- * RETURNS:
- * Zero if update appears valid, error code on failure
- */
-int drm_plane_helper_check_update(struct drm_plane *plane,
- struct drm_crtc *crtc,
- struct drm_framebuffer *fb,
- struct drm_rect *src,
- struct drm_rect *dst,
- unsigned int rotation,
- int min_scale,
- int max_scale,
- bool can_position,
- bool can_update_disabled,
- bool *visible)
+static int drm_plane_helper_check_update(struct drm_plane *plane,
+ struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ struct drm_rect *src,
+ struct drm_rect *dst,
+ unsigned int rotation,
+ int min_scale,
+ int max_scale,
+ bool can_position,
+ bool can_update_disabled,
+ bool *visible)
{
struct drm_plane_state plane_state = {
.plane = plane,
@@ -173,52 +144,14 @@ int drm_plane_helper_check_update(struct drm_plane *plane,
return 0;
}
-EXPORT_SYMBOL(drm_plane_helper_check_update);
-/**
- * drm_primary_helper_update() - Helper for primary plane update
- * @plane: plane object to update
- * @crtc: owning CRTC of owning plane
- * @fb: framebuffer to flip onto plane
- * @crtc_x: x offset of primary plane on crtc
- * @crtc_y: y offset of primary plane on crtc
- * @crtc_w: width of primary plane rectangle on crtc
- * @crtc_h: height of primary plane rectangle on crtc
- * @src_x: x offset of @fb for panning
- * @src_y: y offset of @fb for panning
- * @src_w: width of source rectangle in @fb
- * @src_h: height of source rectangle in @fb
- * @ctx: lock acquire context, not used here
- *
- * Provides a default plane update handler for primary planes. This is handler
- * is called in response to a userspace SetPlane operation on the plane with a
- * non-NULL framebuffer. We call the driver's modeset handler to update the
- * framebuffer.
- *
- * SetPlane() on a primary plane of a disabled CRTC is not supported, and will
- * return an error.
- *
- * Note that we make some assumptions about hardware limitations that may not be
- * true for all hardware --
- *
- * 1. Primary plane cannot be repositioned.
- * 2. Primary plane cannot be scaled.
- * 3. Primary plane must cover the entire CRTC.
- * 4. Subpixel positioning is not supported.
- *
- * Drivers for hardware that don't have these restrictions can provide their
- * own implementation rather than using this helper.
- *
- * RETURNS:
- * Zero on success, error code on failure
- */
-int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
- struct drm_framebuffer *fb,
- int crtc_x, int crtc_y,
- unsigned int crtc_w, unsigned int crtc_h,
- uint32_t src_x, uint32_t src_y,
- uint32_t src_w, uint32_t src_h,
- struct drm_modeset_acquire_ctx *ctx)
+static int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ int crtc_x, int crtc_y,
+ unsigned int crtc_w, unsigned int crtc_h,
+ uint32_t src_x, uint32_t src_y,
+ uint32_t src_w, uint32_t src_h,
+ struct drm_modeset_acquire_ctx *ctx)
{
struct drm_mode_set set = {
.crtc = crtc,
@@ -285,35 +218,12 @@ int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
kfree(connector_list);
return ret;
}
-EXPORT_SYMBOL(drm_primary_helper_update);
-/**
- * drm_primary_helper_disable() - Helper for primary plane disable
- * @plane: plane to disable
- * @ctx: lock acquire context, not used here
- *
- * Provides a default plane disable handler for primary planes. This is handler
- * is called in response to a userspace SetPlane operation on the plane with a
- * NULL framebuffer parameter. It unconditionally fails the disable call with
- * -EINVAL the only way to disable the primary plane without driver support is
- * to disable the entire CRTC. Which does not match the plane
- * &drm_plane_funcs.disable_plane hook.
- *
- * Note that some hardware may be able to disable the primary plane without
- * disabling the whole CRTC. Drivers for such hardware should provide their
- * own disable handler that disables just the primary plane (and they'll likely
- * need to provide their own update handler as well to properly re-enable a
- * disabled primary plane).
- *
- * RETURNS:
- * Unconditionally returns -EINVAL.
- */
-int drm_primary_helper_disable(struct drm_plane *plane,
- struct drm_modeset_acquire_ctx *ctx)
+static int drm_primary_helper_disable(struct drm_plane *plane,
+ struct drm_modeset_acquire_ctx *ctx)
{
return -EINVAL;
}
-EXPORT_SYMBOL(drm_primary_helper_disable);
/**
* drm_primary_helper_destroy() - Helper for primary plane destruction
@@ -336,200 +246,3 @@ const struct drm_plane_funcs drm_primary_helper_funcs = {
.destroy = drm_primary_helper_destroy,
};
EXPORT_SYMBOL(drm_primary_helper_funcs);
-
-int drm_plane_helper_commit(struct drm_plane *plane,
- struct drm_plane_state *plane_state,
- struct drm_framebuffer *old_fb)
-{
- const struct drm_plane_helper_funcs *plane_funcs;
- struct drm_crtc *crtc[2];
- const struct drm_crtc_helper_funcs *crtc_funcs[2];
- int i, ret = 0;
-
- plane_funcs = plane->helper_private;
-
- /* Since this is a transitional helper we can't assume that plane->state
- * is always valid. Hence we need to use plane->crtc instead of
- * plane->state->crtc as the old crtc. */
- crtc[0] = plane->crtc;
- crtc[1] = crtc[0] != plane_state->crtc ? plane_state->crtc : NULL;
-
- for (i = 0; i < 2; i++)
- crtc_funcs[i] = crtc[i] ? crtc[i]->helper_private : NULL;
-
- if (plane_funcs->atomic_check) {
- ret = plane_funcs->atomic_check(plane, plane_state);
- if (ret)
- goto out;
- }
-
- if (plane_funcs->prepare_fb && plane_state->fb != old_fb) {
- ret = plane_funcs->prepare_fb(plane,
- plane_state);
- if (ret)
- goto out;
- }
-
- /* Point of no return, commit sw state. */
- swap(plane->state, plane_state);
-
- for (i = 0; i < 2; i++) {
- if (crtc_funcs[i] && crtc_funcs[i]->atomic_begin)
- crtc_funcs[i]->atomic_begin(crtc[i], crtc[i]->state);
- }
-
- /*
- * Drivers may optionally implement the ->atomic_disable callback, so
- * special-case that here.
- */
- if (drm_atomic_plane_disabling(plane_state, plane->state) &&
- plane_funcs->atomic_disable)
- plane_funcs->atomic_disable(plane, plane_state);
- else
- plane_funcs->atomic_update(plane, plane_state);
-
- for (i = 0; i < 2; i++) {
- if (crtc_funcs[i] && crtc_funcs[i]->atomic_flush)
- crtc_funcs[i]->atomic_flush(crtc[i], crtc[i]->state);
- }
-
- /*
- * If we only moved the plane and didn't change fb's, there's no need to
- * wait for vblank.
- */
- if (plane->state->fb == old_fb)
- goto out;
-
- for (i = 0; i < 2; i++) {
- if (!crtc[i])
- continue;
-
- if (crtc[i]->cursor == plane)
- continue;
-
- /* There's no other way to figure out whether the crtc is running. */
- ret = drm_crtc_vblank_get(crtc[i]);
- if (ret == 0) {
- drm_crtc_wait_one_vblank(crtc[i]);
- drm_crtc_vblank_put(crtc[i]);
- }
-
- ret = 0;
- }
-
- if (plane_funcs->cleanup_fb)
- plane_funcs->cleanup_fb(plane, plane_state);
-out:
- if (plane->funcs->atomic_destroy_state)
- plane->funcs->atomic_destroy_state(plane, plane_state);
- else
- drm_atomic_helper_plane_destroy_state(plane, plane_state);
-
- return ret;
-}
-
-/**
- * drm_plane_helper_update() - Transitional helper for plane update
- * @plane: plane object to update
- * @crtc: owning CRTC of owning plane
- * @fb: framebuffer to flip onto plane
- * @crtc_x: x offset of primary plane on crtc
- * @crtc_y: y offset of primary plane on crtc
- * @crtc_w: width of primary plane rectangle on crtc
- * @crtc_h: height of primary plane rectangle on crtc
- * @src_x: x offset of @fb for panning
- * @src_y: y offset of @fb for panning
- * @src_w: width of source rectangle in @fb
- * @src_h: height of source rectangle in @fb
- * @ctx: lock acquire context, not used here
- *
- * Provides a default plane update handler using the atomic plane update
- * functions. It is fully left to the driver to check plane constraints and
- * handle corner-cases like a fully occluded or otherwise invisible plane.
- *
- * This is useful for piecewise transitioning of a driver to the atomic helpers.
- *
- * RETURNS:
- * Zero on success, error code on failure
- */
-int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
- struct drm_framebuffer *fb,
- int crtc_x, int crtc_y,
- unsigned int crtc_w, unsigned int crtc_h,
- uint32_t src_x, uint32_t src_y,
- uint32_t src_w, uint32_t src_h,
- struct drm_modeset_acquire_ctx *ctx)
-{
- struct drm_plane_state *plane_state;
-
- if (plane->funcs->atomic_duplicate_state)
- plane_state = plane->funcs->atomic_duplicate_state(plane);
- else {
- if (!plane->state)
- drm_atomic_helper_plane_reset(plane);
-
- plane_state = drm_atomic_helper_plane_duplicate_state(plane);
- }
- if (!plane_state)
- return -ENOMEM;
- plane_state->plane = plane;
-
- plane_state->crtc = crtc;
- drm_atomic_set_fb_for_plane(plane_state, fb);
- plane_state->crtc_x = crtc_x;
- plane_state->crtc_y = crtc_y;
- plane_state->crtc_h = crtc_h;
- plane_state->crtc_w = crtc_w;
- plane_state->src_x = src_x;
- plane_state->src_y = src_y;
- plane_state->src_h = src_h;
- plane_state->src_w = src_w;
-
- return drm_plane_helper_commit(plane, plane_state, plane->fb);
-}
-EXPORT_SYMBOL(drm_plane_helper_update);
-
-/**
- * drm_plane_helper_disable() - Transitional helper for plane disable
- * @plane: plane to disable
- * @ctx: lock acquire context, not used here
- *
- * Provides a default plane disable handler using the atomic plane update
- * functions. It is fully left to the driver to check plane constraints and
- * handle corner-cases like a fully occluded or otherwise invisible plane.
- *
- * This is useful for piecewise transitioning of a driver to the atomic helpers.
- *
- * RETURNS:
- * Zero on success, error code on failure
- */
-int drm_plane_helper_disable(struct drm_plane *plane,
- struct drm_modeset_acquire_ctx *ctx)
-{
- struct drm_plane_state *plane_state;
- struct drm_framebuffer *old_fb;
-
- /* crtc helpers love to call disable functions for already disabled hw
- * functions. So cope with that. */
- if (!plane->crtc)
- return 0;
-
- if (plane->funcs->atomic_duplicate_state)
- plane_state = plane->funcs->atomic_duplicate_state(plane);
- else {
- if (!plane->state)
- drm_atomic_helper_plane_reset(plane);
-
- plane_state = drm_atomic_helper_plane_duplicate_state(plane);
- }
- if (!plane_state)
- return -ENOMEM;
- plane_state->plane = plane;
-
- plane_state->crtc = NULL;
- old_fb = plane_state->fb;
- drm_atomic_set_fb_for_plane(plane_state, NULL);
-
- return drm_plane_helper_commit(plane, plane_state, old_fb);
-}
-EXPORT_SYMBOL(drm_plane_helper_disable);
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
index 3f0205fc0a1a..8d54d51a6b6b 100644
--- a/drivers/gpu/drm/drm_prime.c
+++ b/drivers/gpu/drm/drm_prime.c
@@ -434,34 +434,6 @@ void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr)
EXPORT_SYMBOL(drm_gem_dmabuf_vunmap);
/**
- * drm_gem_dmabuf_kmap - map implementation for GEM
- * @dma_buf: buffer to be mapped
- * @page_num: page number within the buffer
- *
- * Not implemented. This can be used as the &dma_buf_ops.map callback.
- */
-void *drm_gem_dmabuf_kmap(struct dma_buf *dma_buf, unsigned long page_num)
-{
- return NULL;
-}
-EXPORT_SYMBOL(drm_gem_dmabuf_kmap);
-
-/**
- * drm_gem_dmabuf_kunmap - unmap implementation for GEM
- * @dma_buf: buffer to be unmapped
- * @page_num: page number within the buffer
- * @addr: virtual address of the buffer
- *
- * Not implemented. This can be used as the &dma_buf_ops.unmap callback.
- */
-void drm_gem_dmabuf_kunmap(struct dma_buf *dma_buf, unsigned long page_num,
- void *addr)
-{
-
-}
-EXPORT_SYMBOL(drm_gem_dmabuf_kunmap);
-
-/**
* drm_gem_dmabuf_mmap - dma_buf mmap implementation for GEM
* @dma_buf: buffer to be mapped
* @vma: virtual address range
@@ -489,8 +461,6 @@ static const struct dma_buf_ops drm_gem_prime_dmabuf_ops = {
.map_dma_buf = drm_gem_map_dma_buf,
.unmap_dma_buf = drm_gem_unmap_dma_buf,
.release = drm_gem_dmabuf_release,
- .map = drm_gem_dmabuf_kmap,
- .unmap = drm_gem_dmabuf_kunmap,
.mmap = drm_gem_dmabuf_mmap,
.vmap = drm_gem_dmabuf_vmap,
.vunmap = drm_gem_dmabuf_vunmap,
diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c
index 51fa978f0d23..917812448d1b 100644
--- a/drivers/gpu/drm/drm_simple_kms_helper.c
+++ b/drivers/gpu/drm/drm_simple_kms_helper.c
@@ -190,6 +190,13 @@ static void drm_simple_kms_plane_cleanup_fb(struct drm_plane *plane,
pipe->funcs->cleanup_fb(pipe, state);
}
+static bool drm_simple_kms_format_mod_supported(struct drm_plane *plane,
+ uint32_t format,
+ uint64_t modifier)
+{
+ return modifier == DRM_FORMAT_MOD_LINEAR;
+}
+
static const struct drm_plane_helper_funcs drm_simple_kms_plane_helper_funcs = {
.prepare_fb = drm_simple_kms_plane_prepare_fb,
.cleanup_fb = drm_simple_kms_plane_cleanup_fb,
@@ -204,6 +211,7 @@ static const struct drm_plane_funcs drm_simple_kms_plane_funcs = {
.reset = drm_atomic_helper_plane_reset,
.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+ .format_mod_supported = drm_simple_kms_format_mod_supported,
};
/**
diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c
index 5c2091dbd230..da8175d9c6ff 100644
--- a/drivers/gpu/drm/drm_syncobj.c
+++ b/drivers/gpu/drm/drm_syncobj.c
@@ -56,6 +56,9 @@
#include "drm_internal.h"
#include <drm/drm_syncobj.h>
+/* merge normal syncobj to timeline syncobj, the point interval is 1 */
+#define DRM_SYNCOBJ_BINARY_POINT 1
+
struct drm_syncobj_stub_fence {
struct dma_fence base;
spinlock_t lock;
@@ -71,7 +74,29 @@ static const struct dma_fence_ops drm_syncobj_stub_fence_ops = {
.get_timeline_name = drm_syncobj_stub_fence_get_name,
};
+struct drm_syncobj_signal_pt {
+ struct dma_fence_array *fence_array;
+ u64 value;
+ struct list_head list;
+};
+
+static DEFINE_SPINLOCK(signaled_fence_lock);
+static struct dma_fence signaled_fence;
+static struct dma_fence *drm_syncobj_get_stub_fence(void)
+{
+ spin_lock(&signaled_fence_lock);
+ if (!signaled_fence.ops) {
+ dma_fence_init(&signaled_fence,
+ &drm_syncobj_stub_fence_ops,
+ &signaled_fence_lock,
+ 0, 0);
+ dma_fence_signal_locked(&signaled_fence);
+ }
+ spin_unlock(&signaled_fence_lock);
+
+ return dma_fence_get(&signaled_fence);
+}
/**
* drm_syncobj_find - lookup and reference a sync object.
* @file_private: drm file private pointer
@@ -98,6 +123,27 @@ struct drm_syncobj *drm_syncobj_find(struct drm_file *file_private,
}
EXPORT_SYMBOL(drm_syncobj_find);
+static struct dma_fence *
+drm_syncobj_find_signal_pt_for_point(struct drm_syncobj *syncobj,
+ uint64_t point)
+{
+ struct drm_syncobj_signal_pt *signal_pt;
+
+ if ((syncobj->type == DRM_SYNCOBJ_TYPE_TIMELINE) &&
+ (point <= syncobj->timeline))
+ return drm_syncobj_get_stub_fence();
+
+ list_for_each_entry(signal_pt, &syncobj->signal_pt_list, list) {
+ if (point > signal_pt->value)
+ continue;
+ if ((syncobj->type == DRM_SYNCOBJ_TYPE_BINARY) &&
+ (point != signal_pt->value))
+ continue;
+ return dma_fence_get(&signal_pt->fence_array->base);
+ }
+ return NULL;
+}
+
static void drm_syncobj_add_callback_locked(struct drm_syncobj *syncobj,
struct drm_syncobj_cb *cb,
drm_syncobj_func_t func)
@@ -106,55 +152,158 @@ static void drm_syncobj_add_callback_locked(struct drm_syncobj *syncobj,
list_add_tail(&cb->node, &syncobj->cb_list);
}
-static int drm_syncobj_fence_get_or_add_callback(struct drm_syncobj *syncobj,
- struct dma_fence **fence,
- struct drm_syncobj_cb *cb,
- drm_syncobj_func_t func)
+static void drm_syncobj_fence_get_or_add_callback(struct drm_syncobj *syncobj,
+ struct dma_fence **fence,
+ struct drm_syncobj_cb *cb,
+ drm_syncobj_func_t func)
{
- int ret;
+ u64 pt_value = 0;
WARN_ON(*fence);
- *fence = drm_syncobj_fence_get(syncobj);
- if (*fence)
- return 1;
+ if (syncobj->type == DRM_SYNCOBJ_TYPE_BINARY) {
+ /*BINARY syncobj always wait on last pt */
+ pt_value = syncobj->signal_point;
- spin_lock(&syncobj->lock);
- /* We've already tried once to get a fence and failed. Now that we
- * have the lock, try one more time just to be sure we don't add a
- * callback when a fence has already been set.
- */
- if (syncobj->fence) {
- *fence = dma_fence_get(rcu_dereference_protected(syncobj->fence,
- lockdep_is_held(&syncobj->lock)));
- ret = 1;
- } else {
- *fence = NULL;
- drm_syncobj_add_callback_locked(syncobj, cb, func);
- ret = 0;
+ if (pt_value == 0)
+ pt_value += DRM_SYNCOBJ_BINARY_POINT;
}
- spin_unlock(&syncobj->lock);
- return ret;
+ mutex_lock(&syncobj->cb_mutex);
+ spin_lock(&syncobj->pt_lock);
+ *fence = drm_syncobj_find_signal_pt_for_point(syncobj, pt_value);
+ spin_unlock(&syncobj->pt_lock);
+ if (!*fence)
+ drm_syncobj_add_callback_locked(syncobj, cb, func);
+ mutex_unlock(&syncobj->cb_mutex);
}
-void drm_syncobj_add_callback(struct drm_syncobj *syncobj,
- struct drm_syncobj_cb *cb,
- drm_syncobj_func_t func)
+static void drm_syncobj_remove_callback(struct drm_syncobj *syncobj,
+ struct drm_syncobj_cb *cb)
{
- spin_lock(&syncobj->lock);
- drm_syncobj_add_callback_locked(syncobj, cb, func);
- spin_unlock(&syncobj->lock);
+ mutex_lock(&syncobj->cb_mutex);
+ list_del_init(&cb->node);
+ mutex_unlock(&syncobj->cb_mutex);
}
-void drm_syncobj_remove_callback(struct drm_syncobj *syncobj,
- struct drm_syncobj_cb *cb)
+static void drm_syncobj_init(struct drm_syncobj *syncobj)
{
- spin_lock(&syncobj->lock);
- list_del_init(&cb->node);
- spin_unlock(&syncobj->lock);
+ spin_lock(&syncobj->pt_lock);
+ syncobj->timeline_context = dma_fence_context_alloc(1);
+ syncobj->timeline = 0;
+ syncobj->signal_point = 0;
+ init_waitqueue_head(&syncobj->wq);
+
+ INIT_LIST_HEAD(&syncobj->signal_pt_list);
+ spin_unlock(&syncobj->pt_lock);
+}
+
+static void drm_syncobj_fini(struct drm_syncobj *syncobj)
+{
+ struct drm_syncobj_signal_pt *signal_pt = NULL, *tmp;
+
+ spin_lock(&syncobj->pt_lock);
+ list_for_each_entry_safe(signal_pt, tmp,
+ &syncobj->signal_pt_list, list) {
+ list_del(&signal_pt->list);
+ dma_fence_put(&signal_pt->fence_array->base);
+ kfree(signal_pt);
+ }
+ spin_unlock(&syncobj->pt_lock);
+}
+
+static int drm_syncobj_create_signal_pt(struct drm_syncobj *syncobj,
+ struct dma_fence *fence,
+ u64 point)
+{
+ struct drm_syncobj_signal_pt *signal_pt =
+ kzalloc(sizeof(struct drm_syncobj_signal_pt), GFP_KERNEL);
+ struct drm_syncobj_signal_pt *tail_pt;
+ struct dma_fence **fences;
+ int num_fences = 0;
+ int ret = 0, i;
+
+ if (!signal_pt)
+ return -ENOMEM;
+ if (!fence)
+ goto out;
+
+ fences = kmalloc_array(sizeof(void *), 2, GFP_KERNEL);
+ if (!fences) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ fences[num_fences++] = dma_fence_get(fence);
+ /* timeline syncobj must take this dependency */
+ if (syncobj->type == DRM_SYNCOBJ_TYPE_TIMELINE) {
+ spin_lock(&syncobj->pt_lock);
+ if (!list_empty(&syncobj->signal_pt_list)) {
+ tail_pt = list_last_entry(&syncobj->signal_pt_list,
+ struct drm_syncobj_signal_pt, list);
+ fences[num_fences++] =
+ dma_fence_get(&tail_pt->fence_array->base);
+ }
+ spin_unlock(&syncobj->pt_lock);
+ }
+ signal_pt->fence_array = dma_fence_array_create(num_fences, fences,
+ syncobj->timeline_context,
+ point, false);
+ if (!signal_pt->fence_array) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ spin_lock(&syncobj->pt_lock);
+ if (syncobj->signal_point >= point) {
+ DRM_WARN("A later signal is ready!");
+ spin_unlock(&syncobj->pt_lock);
+ goto exist;
+ }
+ signal_pt->value = point;
+ list_add_tail(&signal_pt->list, &syncobj->signal_pt_list);
+ syncobj->signal_point = point;
+ spin_unlock(&syncobj->pt_lock);
+ wake_up_all(&syncobj->wq);
+
+ return 0;
+exist:
+ dma_fence_put(&signal_pt->fence_array->base);
+fail:
+ for (i = 0; i < num_fences; i++)
+ dma_fence_put(fences[i]);
+ kfree(fences);
+out:
+ kfree(signal_pt);
+ return ret;
}
+static void drm_syncobj_garbage_collection(struct drm_syncobj *syncobj)
+{
+ struct drm_syncobj_signal_pt *signal_pt, *tmp, *tail_pt;
+
+ spin_lock(&syncobj->pt_lock);
+ tail_pt = list_last_entry(&syncobj->signal_pt_list,
+ struct drm_syncobj_signal_pt,
+ list);
+ list_for_each_entry_safe(signal_pt, tmp,
+ &syncobj->signal_pt_list, list) {
+ if (syncobj->type == DRM_SYNCOBJ_TYPE_BINARY &&
+ signal_pt == tail_pt)
+ continue;
+ if (dma_fence_is_signaled(&signal_pt->fence_array->base)) {
+ syncobj->timeline = signal_pt->value;
+ list_del(&signal_pt->list);
+ dma_fence_put(&signal_pt->fence_array->base);
+ kfree(signal_pt);
+ } else {
+ /*signal_pt is in order in list, from small to big, so
+ * the later must not be signal either */
+ break;
+ }
+ }
+
+ spin_unlock(&syncobj->pt_lock);
+}
/**
* drm_syncobj_replace_fence - replace fence in a sync object.
* @syncobj: Sync object to replace fence in
@@ -167,28 +316,30 @@ void drm_syncobj_replace_fence(struct drm_syncobj *syncobj,
u64 point,
struct dma_fence *fence)
{
- struct dma_fence *old_fence;
- struct drm_syncobj_cb *cur, *tmp;
-
- if (fence)
- dma_fence_get(fence);
-
- spin_lock(&syncobj->lock);
-
- old_fence = rcu_dereference_protected(syncobj->fence,
- lockdep_is_held(&syncobj->lock));
- rcu_assign_pointer(syncobj->fence, fence);
+ u64 pt_value = point;
+
+ drm_syncobj_garbage_collection(syncobj);
+ if (syncobj->type == DRM_SYNCOBJ_TYPE_BINARY) {
+ if (!fence) {
+ drm_syncobj_fini(syncobj);
+ drm_syncobj_init(syncobj);
+ return;
+ }
+ pt_value = syncobj->signal_point +
+ DRM_SYNCOBJ_BINARY_POINT;
+ }
+ drm_syncobj_create_signal_pt(syncobj, fence, pt_value);
+ if (fence) {
+ struct drm_syncobj_cb *cur, *tmp;
+ LIST_HEAD(cb_list);
- if (fence != old_fence) {
+ mutex_lock(&syncobj->cb_mutex);
list_for_each_entry_safe(cur, tmp, &syncobj->cb_list, node) {
list_del_init(&cur->node);
cur->func(syncobj, cur);
}
+ mutex_unlock(&syncobj->cb_mutex);
}
-
- spin_unlock(&syncobj->lock);
-
- dma_fence_put(old_fence);
}
EXPORT_SYMBOL(drm_syncobj_replace_fence);
@@ -211,35 +362,89 @@ static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj)
return 0;
}
+static int
+drm_syncobj_point_get(struct drm_syncobj *syncobj, u64 point, u64 flags,
+ struct dma_fence **fence)
+{
+ int ret = 0;
+
+ if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) {
+ ret = wait_event_interruptible(syncobj->wq,
+ point <= syncobj->signal_point);
+ if (ret < 0)
+ return ret;
+ }
+ spin_lock(&syncobj->pt_lock);
+ *fence = drm_syncobj_find_signal_pt_for_point(syncobj, point);
+ if (!*fence)
+ ret = -EINVAL;
+ spin_unlock(&syncobj->pt_lock);
+ return ret;
+}
+
+/**
+ * drm_syncobj_search_fence - lookup and reference the fence in a sync object or
+ * in a timeline point
+ * @syncobj: sync object pointer
+ * @point: timeline point
+ * @flags: DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT or not
+ * @fence: out parameter for the fence
+ *
+ * if flags is DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT, the function will block
+ * here until specific timeline points is reached.
+ * if not, you need a submit thread and block in userspace until all future
+ * timeline points have materialized, only then you can submit to the kernel,
+ * otherwise, function will fail to return fence.
+ *
+ * Returns 0 on success or a negative error value on failure. On success @fence
+ * contains a reference to the fence, which must be released by calling
+ * dma_fence_put().
+ */
+int drm_syncobj_search_fence(struct drm_syncobj *syncobj, u64 point,
+ u64 flags, struct dma_fence **fence)
+{
+ u64 pt_value = point;
+
+ if (!syncobj)
+ return -ENOENT;
+
+ drm_syncobj_garbage_collection(syncobj);
+ if (syncobj->type == DRM_SYNCOBJ_TYPE_BINARY) {
+ /*BINARY syncobj always wait on last pt */
+ pt_value = syncobj->signal_point;
+
+ if (pt_value == 0)
+ pt_value += DRM_SYNCOBJ_BINARY_POINT;
+ }
+ return drm_syncobj_point_get(syncobj, pt_value, flags, fence);
+}
+EXPORT_SYMBOL(drm_syncobj_search_fence);
+
/**
* drm_syncobj_find_fence - lookup and reference the fence in a sync object
* @file_private: drm file private pointer
* @handle: sync object handle to lookup.
* @point: timeline point
+ * @flags: DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT or not
* @fence: out parameter for the fence
*
* This is just a convenience function that combines drm_syncobj_find() and
- * drm_syncobj_fence_get().
+ * drm_syncobj_lookup_fence().
*
* Returns 0 on success or a negative error value on failure. On success @fence
* contains a reference to the fence, which must be released by calling
* dma_fence_put().
*/
int drm_syncobj_find_fence(struct drm_file *file_private,
- u32 handle, u64 point,
+ u32 handle, u64 point, u64 flags,
struct dma_fence **fence)
{
struct drm_syncobj *syncobj = drm_syncobj_find(file_private, handle);
- int ret = 0;
-
- if (!syncobj)
- return -ENOENT;
+ int ret;
- *fence = drm_syncobj_fence_get(syncobj);
- if (!*fence) {
- ret = -EINVAL;
- }
- drm_syncobj_put(syncobj);
+ ret = drm_syncobj_search_fence(syncobj, point, flags, fence);
+ if (syncobj)
+ drm_syncobj_put(syncobj);
return ret;
}
EXPORT_SYMBOL(drm_syncobj_find_fence);
@@ -255,7 +460,7 @@ void drm_syncobj_free(struct kref *kref)
struct drm_syncobj *syncobj = container_of(kref,
struct drm_syncobj,
refcount);
- drm_syncobj_replace_fence(syncobj, 0, NULL);
+ drm_syncobj_fini(syncobj);
kfree(syncobj);
}
EXPORT_SYMBOL(drm_syncobj_free);
@@ -284,7 +489,13 @@ int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags,
kref_init(&syncobj->refcount);
INIT_LIST_HEAD(&syncobj->cb_list);
- spin_lock_init(&syncobj->lock);
+ spin_lock_init(&syncobj->pt_lock);
+ mutex_init(&syncobj->cb_mutex);
+ if (flags & DRM_SYNCOBJ_CREATE_TYPE_TIMELINE)
+ syncobj->type = DRM_SYNCOBJ_TYPE_TIMELINE;
+ else
+ syncobj->type = DRM_SYNCOBJ_TYPE_BINARY;
+ drm_syncobj_init(syncobj);
if (flags & DRM_SYNCOBJ_CREATE_SIGNALED) {
ret = drm_syncobj_assign_null_handle(syncobj);
@@ -497,7 +708,7 @@ static int drm_syncobj_export_sync_file(struct drm_file *file_private,
if (fd < 0)
return fd;
- ret = drm_syncobj_find_fence(file_private, handle, 0, &fence);
+ ret = drm_syncobj_find_fence(file_private, handle, 0, 0, &fence);
if (ret)
goto err_put_fd;
@@ -567,7 +778,8 @@ drm_syncobj_create_ioctl(struct drm_device *dev, void *data,
return -EOPNOTSUPP;
/* no valid flags yet */
- if (args->flags & ~DRM_SYNCOBJ_CREATE_SIGNALED)
+ if (args->flags & ~(DRM_SYNCOBJ_CREATE_SIGNALED |
+ DRM_SYNCOBJ_CREATE_TYPE_TIMELINE))
return -EINVAL;
return drm_syncobj_create_as_handle(file_private,
@@ -660,9 +872,8 @@ static void syncobj_wait_syncobj_func(struct drm_syncobj *syncobj,
struct syncobj_wait_entry *wait =
container_of(cb, struct syncobj_wait_entry, syncobj_cb);
- /* This happens inside the syncobj lock */
- wait->fence = dma_fence_get(rcu_dereference_protected(syncobj->fence,
- lockdep_is_held(&syncobj->lock)));
+ drm_syncobj_search_fence(syncobj, 0, 0, &wait->fence);
+
wake_up_process(wait->task);
}
@@ -688,7 +899,8 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs,
signaled_count = 0;
for (i = 0; i < count; ++i) {
entries[i].task = current;
- entries[i].fence = drm_syncobj_fence_get(syncobjs[i]);
+ drm_syncobj_search_fence(syncobjs[i], 0, 0,
+ &entries[i].fence);
if (!entries[i].fence) {
if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) {
continue;
@@ -953,12 +1165,13 @@ drm_syncobj_reset_ioctl(struct drm_device *dev, void *data,
if (ret < 0)
return ret;
- for (i = 0; i < args->count_handles; i++)
- drm_syncobj_replace_fence(syncobjs[i], 0, NULL);
-
+ for (i = 0; i < args->count_handles; i++) {
+ drm_syncobj_fini(syncobjs[i]);
+ drm_syncobj_init(syncobjs[i]);
+ }
drm_syncobj_array_free(syncobjs, args->count_handles);
- return 0;
+ return ret;
}
int
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
index 983e67f19e45..30875f8f2933 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
@@ -179,7 +179,7 @@ static int submit_fence_sync(struct etnaviv_gem_submit *submit)
struct reservation_object *robj = bo->obj->resv;
if (!(bo->flags & ETNA_SUBMIT_BO_WRITE)) {
- ret = reservation_object_reserve_shared(robj);
+ ret = reservation_object_reserve_shared(robj, 1);
if (ret)
return ret;
}
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_sched.c b/drivers/gpu/drm/etnaviv/etnaviv_sched.c
index e7c3ed6c9a2e..49a6763693f1 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_sched.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_sched.c
@@ -93,7 +93,7 @@ static void etnaviv_sched_timedout_job(struct drm_sched_job *sched_job)
* If the GPU managed to complete this jobs fence, the timout is
* spurious. Bail out.
*/
- if (fence_completed(gpu, submit->out_fence->seqno))
+ if (dma_fence_is_signaled(submit->out_fence))
return;
/*
@@ -105,8 +105,6 @@ static void etnaviv_sched_timedout_job(struct drm_sched_job *sched_job)
change = dma_addr - gpu->hangcheck_dma_addr;
if (change < 0 || change > 16) {
gpu->hangcheck_dma_addr = dma_addr;
- schedule_delayed_work(&sched_job->sched->work_tdr,
- sched_job->sched->timeout);
return;
}
@@ -127,6 +125,8 @@ static void etnaviv_sched_free_job(struct drm_sched_job *sched_job)
{
struct etnaviv_gem_submit *submit = to_etnaviv_submit(sched_job);
+ drm_sched_job_cleanup(sched_job);
+
etnaviv_submit_put(submit);
}
@@ -159,6 +159,7 @@ int etnaviv_sched_push_job(struct drm_sched_entity *sched_entity,
submit->out_fence, 0,
INT_MAX, GFP_KERNEL);
if (submit->out_fence_id < 0) {
+ drm_sched_job_cleanup(&submit->sched_job);
ret = -ENOMEM;
goto out_unlock;
}
diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c
index 94529aa82339..aef487dd8731 100644
--- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c
+++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c
@@ -164,13 +164,6 @@ static u32 decon_get_frame_count(struct decon_context *ctx, bool end)
return frm;
}
-static u32 decon_get_vblank_counter(struct exynos_drm_crtc *crtc)
-{
- struct decon_context *ctx = crtc->ctx;
-
- return decon_get_frame_count(ctx, false);
-}
-
static void decon_setup_trigger(struct decon_context *ctx)
{
if (!ctx->crtc->i80_mode && !(ctx->out_type & I80_HW_TRG))
@@ -536,7 +529,6 @@ static const struct exynos_drm_crtc_ops decon_crtc_ops = {
.disable = decon_disable,
.enable_vblank = decon_enable_vblank,
.disable_vblank = decon_disable_vblank,
- .get_vblank_counter = decon_get_vblank_counter,
.atomic_begin = decon_atomic_begin,
.update_plane = decon_update_plane,
.disable_plane = decon_disable_plane,
@@ -554,7 +546,6 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
int ret;
ctx->drm_dev = drm_dev;
- drm_dev->max_vblank_count = 0xffffffff;
for (win = ctx->first_win; win < WINDOWS_NR; win++) {
ctx->configs[win].pixel_formats = decon_formats;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index eea90251808f..2696289ecc78 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -162,16 +162,6 @@ static void exynos_drm_crtc_disable_vblank(struct drm_crtc *crtc)
exynos_crtc->ops->disable_vblank(exynos_crtc);
}
-static u32 exynos_drm_crtc_get_vblank_counter(struct drm_crtc *crtc)
-{
- struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
-
- if (exynos_crtc->ops->get_vblank_counter)
- return exynos_crtc->ops->get_vblank_counter(exynos_crtc);
-
- return 0;
-}
-
static const struct drm_crtc_funcs exynos_crtc_funcs = {
.set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip,
@@ -181,7 +171,6 @@ static const struct drm_crtc_funcs exynos_crtc_funcs = {
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
.enable_vblank = exynos_drm_crtc_enable_vblank,
.disable_vblank = exynos_drm_crtc_disable_vblank,
- .get_vblank_counter = exynos_drm_crtc_get_vblank_counter,
};
struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index ec9604f1272b..5e61e707f955 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -135,7 +135,6 @@ struct exynos_drm_crtc_ops {
void (*disable)(struct exynos_drm_crtc *crtc);
int (*enable_vblank)(struct exynos_drm_crtc *crtc);
void (*disable_vblank)(struct exynos_drm_crtc *crtc);
- u32 (*get_vblank_counter)(struct exynos_drm_crtc *crtc);
enum drm_mode_status (*mode_valid)(struct exynos_drm_crtc *crtc,
const struct drm_display_mode *mode);
bool (*mode_fixup)(struct exynos_drm_crtc *crtc,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index 07af7758066d..d81e62ae286a 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -14,6 +14,7 @@
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_panel.h>
#include <drm/drm_atomic_helper.h>
@@ -1474,12 +1475,12 @@ static int exynos_dsi_create_connector(struct drm_encoder *encoder)
{
struct exynos_dsi *dsi = encoder_to_dsi(encoder);
struct drm_connector *connector = &dsi->connector;
+ struct drm_device *drm = encoder->dev;
int ret;
connector->polled = DRM_CONNECTOR_POLL_HPD;
- ret = drm_connector_init(encoder->dev, connector,
- &exynos_dsi_connector_funcs,
+ ret = drm_connector_init(drm, connector, &exynos_dsi_connector_funcs,
DRM_MODE_CONNECTOR_DSI);
if (ret) {
DRM_ERROR("Failed to initialize connector with drm\n");
@@ -1489,7 +1490,12 @@ static int exynos_dsi_create_connector(struct drm_encoder *encoder)
connector->status = connector_status_disconnected;
drm_connector_helper_add(connector, &exynos_dsi_connector_helper_funcs);
drm_connector_attach_encoder(connector, encoder);
+ if (!drm->registered)
+ return 0;
+ connector->funcs->reset(connector);
+ drm_fb_helper_add_one_connector(drm->fb_helper, connector);
+ drm_connector_register(connector);
return 0;
}
@@ -1527,7 +1533,9 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
}
dsi->panel = of_drm_find_panel(device->dev.of_node);
- if (dsi->panel) {
+ if (IS_ERR(dsi->panel)) {
+ dsi->panel = NULL;
+ } else {
drm_panel_attach(dsi->panel, &dsi->connector);
dsi->connector.status = connector_status_connected;
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
index 918dd2c82209..01d182289efa 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -192,7 +192,7 @@ int exynos_drm_fbdev_init(struct drm_device *dev)
struct drm_fb_helper *helper;
int ret;
- if (!dev->mode_config.num_crtc || !dev->mode_config.num_connector)
+ if (!dev->mode_config.num_crtc)
return 0;
fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_iommu.h b/drivers/gpu/drm/exynos/exynos_drm_iommu.h
index 87f6b5672e11..797d9ee5f15a 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_iommu.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_iommu.h
@@ -55,37 +55,12 @@ static inline void __exynos_iommu_detach(struct exynos_drm_private *priv,
static inline int __exynos_iommu_create_mapping(struct exynos_drm_private *priv,
unsigned long start, unsigned long size)
{
- struct iommu_domain *domain;
- int ret;
-
- domain = iommu_domain_alloc(priv->dma_dev->bus);
- if (!domain)
- return -ENOMEM;
-
- ret = iommu_get_dma_cookie(domain);
- if (ret)
- goto free_domain;
-
- ret = iommu_dma_init_domain(domain, start, size, NULL);
- if (ret)
- goto put_cookie;
-
- priv->mapping = domain;
+ priv->mapping = iommu_get_domain_for_dev(priv->dma_dev);
return 0;
-
-put_cookie:
- iommu_put_dma_cookie(domain);
-free_domain:
- iommu_domain_free(domain);
- return ret;
}
static inline void __exynos_iommu_release_mapping(struct exynos_drm_private *priv)
{
- struct iommu_domain *domain = priv->mapping;
-
- iommu_put_dma_cookie(domain);
- iommu_domain_free(domain);
priv->mapping = NULL;
}
@@ -94,7 +69,9 @@ static inline int __exynos_iommu_attach(struct exynos_drm_private *priv,
{
struct iommu_domain *domain = priv->mapping;
- return iommu_attach_device(domain, dev);
+ if (dev != priv->dma_dev)
+ return iommu_attach_device(domain, dev);
+ return 0;
}
static inline void __exynos_iommu_detach(struct exynos_drm_private *priv,
@@ -102,7 +79,8 @@ static inline void __exynos_iommu_detach(struct exynos_drm_private *priv,
{
struct iommu_domain *domain = priv->mapping;
- iommu_detach_device(domain, dev);
+ if (dev != priv->dma_dev)
+ iommu_detach_device(domain, dev);
}
#else
#error Unsupported architecture and IOMMU/DMA-mapping glue code
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c
index 0e3752437e44..18afc94e4dff 100644
--- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c
+++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c
@@ -17,6 +17,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
+#include <video/videomode.h>
#include "fsl_dcu_drm_crtc.h"
#include "fsl_dcu_drm_drv.h"
@@ -85,40 +86,34 @@ static void fsl_dcu_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
struct drm_connector *con = &fsl_dev->connector.base;
struct drm_display_mode *mode = &crtc->state->mode;
- unsigned int hbp, hfp, hsw, vbp, vfp, vsw, index, pol = 0;
+ unsigned int pol = 0;
+ struct videomode vm;
- index = drm_crtc_index(crtc);
clk_set_rate(fsl_dev->pix_clk, mode->clock * 1000);
- /* Configure timings: */
- hbp = mode->htotal - mode->hsync_end;
- hfp = mode->hsync_start - mode->hdisplay;
- hsw = mode->hsync_end - mode->hsync_start;
- vbp = mode->vtotal - mode->vsync_end;
- vfp = mode->vsync_start - mode->vdisplay;
- vsw = mode->vsync_end - mode->vsync_start;
+ drm_display_mode_to_videomode(mode, &vm);
/* INV_PXCK as default (most display sample data on rising edge) */
if (!(con->display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_POSEDGE))
pol |= DCU_SYN_POL_INV_PXCK;
- if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+ if (vm.flags & DISPLAY_FLAGS_HSYNC_LOW)
pol |= DCU_SYN_POL_INV_HS_LOW;
- if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+ if (vm.flags & DISPLAY_FLAGS_VSYNC_LOW)
pol |= DCU_SYN_POL_INV_VS_LOW;
regmap_write(fsl_dev->regmap, DCU_HSYN_PARA,
- DCU_HSYN_PARA_BP(hbp) |
- DCU_HSYN_PARA_PW(hsw) |
- DCU_HSYN_PARA_FP(hfp));
+ DCU_HSYN_PARA_BP(vm.hback_porch) |
+ DCU_HSYN_PARA_PW(vm.hsync_len) |
+ DCU_HSYN_PARA_FP(vm.hfront_porch));
regmap_write(fsl_dev->regmap, DCU_VSYN_PARA,
- DCU_VSYN_PARA_BP(vbp) |
- DCU_VSYN_PARA_PW(vsw) |
- DCU_VSYN_PARA_FP(vfp));
+ DCU_VSYN_PARA_BP(vm.vback_porch) |
+ DCU_VSYN_PARA_PW(vm.vsync_len) |
+ DCU_VSYN_PARA_FP(vm.vfront_porch));
regmap_write(fsl_dev->regmap, DCU_DISP_SIZE,
- DCU_DISP_SIZE_DELTA_Y(mode->vdisplay) |
- DCU_DISP_SIZE_DELTA_X(mode->hdisplay));
+ DCU_DISP_SIZE_DELTA_Y(vm.vactive) |
+ DCU_DISP_SIZE_DELTA_X(vm.hactive));
regmap_write(fsl_dev->regmap, DCU_SYN_POL, pol);
regmap_write(fsl_dev->regmap, DCU_BGND, DCU_BGND_R(0) |
DCU_BGND_G(0) | DCU_BGND_B(0));
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c
index 0496be5212e1..ceddc3e29258 100644
--- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c
+++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c
@@ -26,6 +26,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_fb_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_modeset_helper.h>
@@ -89,20 +90,11 @@ static int fsl_dcu_load(struct drm_device *dev, unsigned long flags)
"Invalid legacyfb_depth. Defaulting to 24bpp\n");
legacyfb_depth = 24;
}
- fsl_dev->fbdev = drm_fbdev_cma_init(dev, legacyfb_depth, 1);
- if (IS_ERR(fsl_dev->fbdev)) {
- ret = PTR_ERR(fsl_dev->fbdev);
- fsl_dev->fbdev = NULL;
- goto done;
- }
return 0;
done:
drm_kms_helper_poll_fini(dev);
- if (fsl_dev->fbdev)
- drm_fbdev_cma_fini(fsl_dev->fbdev);
-
drm_mode_config_cleanup(dev);
drm_irq_uninstall(dev);
dev->dev_private = NULL;
@@ -112,14 +104,9 @@ done:
static void fsl_dcu_unload(struct drm_device *dev)
{
- struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
-
drm_atomic_helper_shutdown(dev);
drm_kms_helper_poll_fini(dev);
- if (fsl_dev->fbdev)
- drm_fbdev_cma_fini(fsl_dev->fbdev);
-
drm_mode_config_cleanup(dev);
drm_irq_uninstall(dev);
@@ -147,19 +134,11 @@ static irqreturn_t fsl_dcu_drm_irq(int irq, void *arg)
return IRQ_HANDLED;
}
-static void fsl_dcu_drm_lastclose(struct drm_device *dev)
-{
- struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
-
- drm_fbdev_cma_restore_mode(fsl_dev->fbdev);
-}
-
DEFINE_DRM_GEM_CMA_FOPS(fsl_dcu_drm_fops);
static struct drm_driver fsl_dcu_drm_driver = {
.driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET
| DRIVER_PRIME | DRIVER_ATOMIC,
- .lastclose = fsl_dcu_drm_lastclose,
.load = fsl_dcu_load,
.unload = fsl_dcu_unload,
.irq_handler = fsl_dcu_drm_irq,
@@ -355,6 +334,8 @@ static int fsl_dcu_drm_probe(struct platform_device *pdev)
if (ret < 0)
goto put;
+ drm_fbdev_generic_setup(drm, legacyfb_depth);
+
return 0;
put:
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h
index 93bfb98012d4..cb87bb74cb87 100644
--- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h
+++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h
@@ -191,7 +191,6 @@ struct fsl_dcu_drm_device {
/*protects hardware register*/
spinlock_t irq_lock;
struct drm_device *drm;
- struct drm_fbdev_cma *fbdev;
struct drm_crtc crtc;
struct drm_encoder encoder;
struct fsl_dcu_drm_connector connector;
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
index 45c25a488f42..3c168ae77b0c 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -49,8 +49,6 @@ struct hibmc_drm_private {
bool mode_config_initialized;
/* ttm */
- struct drm_global_reference mem_global_ref;
- struct ttm_bo_global_ref bo_global_ref;
struct ttm_bo_device bdev;
bool initialized;
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
index 2e3e0bdb8932..dd383267884c 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
@@ -29,55 +29,6 @@ hibmc_bdev(struct ttm_bo_device *bd)
return container_of(bd, struct hibmc_drm_private, bdev);
}
-static int
-hibmc_ttm_mem_global_init(struct drm_global_reference *ref)
-{
- return ttm_mem_global_init(ref->object);
-}
-
-static void
-hibmc_ttm_mem_global_release(struct drm_global_reference *ref)
-{
- ttm_mem_global_release(ref->object);
-}
-
-static int hibmc_ttm_global_init(struct hibmc_drm_private *hibmc)
-{
- int ret;
-
- hibmc->mem_global_ref.global_type = DRM_GLOBAL_TTM_MEM;
- hibmc->mem_global_ref.size = sizeof(struct ttm_mem_global);
- hibmc->mem_global_ref.init = &hibmc_ttm_mem_global_init;
- hibmc->mem_global_ref.release = &hibmc_ttm_mem_global_release;
- ret = drm_global_item_ref(&hibmc->mem_global_ref);
- if (ret) {
- DRM_ERROR("could not get ref on ttm global: %d\n", ret);
- return ret;
- }
-
- hibmc->bo_global_ref.mem_glob =
- hibmc->mem_global_ref.object;
- hibmc->bo_global_ref.ref.global_type = DRM_GLOBAL_TTM_BO;
- hibmc->bo_global_ref.ref.size = sizeof(struct ttm_bo_global);
- hibmc->bo_global_ref.ref.init = &ttm_bo_global_init;
- hibmc->bo_global_ref.ref.release = &ttm_bo_global_release;
- ret = drm_global_item_ref(&hibmc->bo_global_ref.ref);
- if (ret) {
- DRM_ERROR("failed setting up TTM BO subsystem: %d\n", ret);
- drm_global_item_unref(&hibmc->mem_global_ref);
- return ret;
- }
- return 0;
-}
-
-static void
-hibmc_ttm_global_release(struct hibmc_drm_private *hibmc)
-{
- drm_global_item_unref(&hibmc->bo_global_ref.ref);
- drm_global_item_unref(&hibmc->mem_global_ref);
- hibmc->mem_global_ref.release = NULL;
-}
-
static void hibmc_bo_ttm_destroy(struct ttm_buffer_object *tbo)
{
struct hibmc_bo *bo = container_of(tbo, struct hibmc_bo, bo);
@@ -237,18 +188,12 @@ int hibmc_mm_init(struct hibmc_drm_private *hibmc)
struct drm_device *dev = hibmc->dev;
struct ttm_bo_device *bdev = &hibmc->bdev;
- ret = hibmc_ttm_global_init(hibmc);
- if (ret)
- return ret;
-
ret = ttm_bo_device_init(&hibmc->bdev,
- hibmc->bo_global_ref.ref.object,
&hibmc_bo_driver,
dev->anon_inode->i_mapping,
DRM_FILE_PAGE_OFFSET,
true);
if (ret) {
- hibmc_ttm_global_release(hibmc);
DRM_ERROR("error initializing bo driver: %d\n", ret);
return ret;
}
@@ -256,7 +201,6 @@ int hibmc_mm_init(struct hibmc_drm_private *hibmc)
ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM,
hibmc->fb_size >> PAGE_SHIFT);
if (ret) {
- hibmc_ttm_global_release(hibmc);
DRM_ERROR("failed ttm VRAM init: %d\n", ret);
return ret;
}
@@ -271,7 +215,6 @@ void hibmc_mm_fini(struct hibmc_drm_private *hibmc)
return;
ttm_bo_device_release(&hibmc->bdev);
- hibmc_ttm_global_release(hibmc);
hibmc->mm_inited = false;
}
diff --git a/drivers/gpu/drm/i2c/tda9950.c b/drivers/gpu/drm/i2c/tda9950.c
index 5d2f0d548469..250b5e02a314 100644
--- a/drivers/gpu/drm/i2c/tda9950.c
+++ b/drivers/gpu/drm/i2c/tda9950.c
@@ -191,7 +191,8 @@ static irqreturn_t tda9950_irq(int irq, void *data)
break;
}
/* TDA9950 executes all retries for us */
- tx_status |= CEC_TX_STATUS_MAX_RETRIES;
+ if (tx_status != CEC_TX_STATUS_OK)
+ tx_status |= CEC_TX_STATUS_MAX_RETRIES;
cec_transmit_done(priv->adap, tx_status, arb_lost_cnt,
nack_cnt, 0, err_cnt);
break;
@@ -310,7 +311,7 @@ static void tda9950_release(struct tda9950_priv *priv)
/* Wait up to .5s for it to signal non-busy */
do {
csr = tda9950_read(client, REG_CSR);
- if (!(csr & CSR_BUSY) || --timeout)
+ if (!(csr & CSR_BUSY) || !--timeout)
break;
msleep(10);
} while (1);
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 1e7e9513bb10..0ff878c994e2 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -12,7 +12,7 @@
# Note the danger in using -Wall -Wextra is that when CI updates gcc we
# will most likely get a sudden build breakage... Hopefully we will fix
# new warnings before CI updates!
-subdir-ccflags-y := -Wall -Wextra -Wvla
+subdir-ccflags-y := -Wall -Wextra
subdir-ccflags-y += $(call cc-disable-warning, unused-parameter)
subdir-ccflags-y += $(call cc-disable-warning, type-limits)
subdir-ccflags-y += $(call cc-disable-warning, missing-field-initializers)
diff --git a/drivers/gpu/drm/i915/gvt/gtt.c b/drivers/gpu/drm/i915/gvt/gtt.c
index 2402395a068d..58e166effa45 100644
--- a/drivers/gpu/drm/i915/gvt/gtt.c
+++ b/drivers/gpu/drm/i915/gvt/gtt.c
@@ -1905,7 +1905,6 @@ static struct intel_vgpu_mm *intel_vgpu_create_ggtt_mm(struct intel_vgpu *vgpu)
vgpu_free_mm(mm);
return ERR_PTR(-ENOMEM);
}
- mm->ggtt_mm.last_partial_off = -1UL;
return mm;
}
@@ -1930,7 +1929,6 @@ void _intel_vgpu_mm_release(struct kref *mm_ref)
invalidate_ppgtt_mm(mm);
} else {
vfree(mm->ggtt_mm.virtual_ggtt);
- mm->ggtt_mm.last_partial_off = -1UL;
}
vgpu_free_mm(mm);
@@ -2168,6 +2166,8 @@ static int emulate_ggtt_mmio_write(struct intel_vgpu *vgpu, unsigned int off,
struct intel_gvt_gtt_entry e, m;
dma_addr_t dma_addr;
int ret;
+ struct intel_gvt_partial_pte *partial_pte, *pos, *n;
+ bool partial_update = false;
if (bytes != 4 && bytes != 8)
return -EINVAL;
@@ -2178,68 +2178,57 @@ static int emulate_ggtt_mmio_write(struct intel_vgpu *vgpu, unsigned int off,
if (!vgpu_gmadr_is_valid(vgpu, gma))
return 0;
- ggtt_get_guest_entry(ggtt_mm, &e, g_gtt_index);
-
+ e.type = GTT_TYPE_GGTT_PTE;
memcpy((void *)&e.val64 + (off & (info->gtt_entry_size - 1)), p_data,
bytes);
/* If ggtt entry size is 8 bytes, and it's split into two 4 bytes
- * write, we assume the two 4 bytes writes are consecutive.
- * Otherwise, we abort and report error
+ * write, save the first 4 bytes in a list and update virtual
+ * PTE. Only update shadow PTE when the second 4 bytes comes.
*/
if (bytes < info->gtt_entry_size) {
- if (ggtt_mm->ggtt_mm.last_partial_off == -1UL) {
- /* the first partial part*/
- ggtt_mm->ggtt_mm.last_partial_off = off;
- ggtt_mm->ggtt_mm.last_partial_data = e.val64;
- return 0;
- } else if ((g_gtt_index ==
- (ggtt_mm->ggtt_mm.last_partial_off >>
- info->gtt_entry_size_shift)) &&
- (off != ggtt_mm->ggtt_mm.last_partial_off)) {
- /* the second partial part */
-
- int last_off = ggtt_mm->ggtt_mm.last_partial_off &
- (info->gtt_entry_size - 1);
-
- memcpy((void *)&e.val64 + last_off,
- (void *)&ggtt_mm->ggtt_mm.last_partial_data +
- last_off, bytes);
-
- ggtt_mm->ggtt_mm.last_partial_off = -1UL;
- } else {
- int last_offset;
-
- gvt_vgpu_err("failed to populate guest ggtt entry: abnormal ggtt entry write sequence, last_partial_off=%lx, offset=%x, bytes=%d, ggtt entry size=%d\n",
- ggtt_mm->ggtt_mm.last_partial_off, off,
- bytes, info->gtt_entry_size);
-
- /* set host ggtt entry to scratch page and clear
- * virtual ggtt entry as not present for last
- * partially write offset
- */
- last_offset = ggtt_mm->ggtt_mm.last_partial_off &
- (~(info->gtt_entry_size - 1));
-
- ggtt_get_host_entry(ggtt_mm, &m, last_offset);
- ggtt_invalidate_pte(vgpu, &m);
- ops->set_pfn(&m, gvt->gtt.scratch_mfn);
- ops->clear_present(&m);
- ggtt_set_host_entry(ggtt_mm, &m, last_offset);
- ggtt_invalidate(gvt->dev_priv);
-
- ggtt_get_guest_entry(ggtt_mm, &e, last_offset);
- ops->clear_present(&e);
- ggtt_set_guest_entry(ggtt_mm, &e, last_offset);
-
- ggtt_mm->ggtt_mm.last_partial_off = off;
- ggtt_mm->ggtt_mm.last_partial_data = e.val64;
+ bool found = false;
+
+ list_for_each_entry_safe(pos, n,
+ &ggtt_mm->ggtt_mm.partial_pte_list, list) {
+ if (g_gtt_index == pos->offset >>
+ info->gtt_entry_size_shift) {
+ if (off != pos->offset) {
+ /* the second partial part*/
+ int last_off = pos->offset &
+ (info->gtt_entry_size - 1);
+
+ memcpy((void *)&e.val64 + last_off,
+ (void *)&pos->data + last_off,
+ bytes);
+
+ list_del(&pos->list);
+ kfree(pos);
+ found = true;
+ break;
+ }
+
+ /* update of the first partial part */
+ pos->data = e.val64;
+ ggtt_set_guest_entry(ggtt_mm, &e, g_gtt_index);
+ return 0;
+ }
+ }
- return 0;
+ if (!found) {
+ /* the first partial part */
+ partial_pte = kzalloc(sizeof(*partial_pte), GFP_KERNEL);
+ if (!partial_pte)
+ return -ENOMEM;
+ partial_pte->offset = off;
+ partial_pte->data = e.val64;
+ list_add_tail(&partial_pte->list,
+ &ggtt_mm->ggtt_mm.partial_pte_list);
+ partial_update = true;
}
}
- if (ops->test_present(&e)) {
+ if (!partial_update && (ops->test_present(&e))) {
gfn = ops->get_pfn(&e);
m = e;
@@ -2263,16 +2252,18 @@ static int emulate_ggtt_mmio_write(struct intel_vgpu *vgpu, unsigned int off,
} else
ops->set_pfn(&m, dma_addr >> PAGE_SHIFT);
} else {
- ggtt_get_host_entry(ggtt_mm, &m, g_gtt_index);
- ggtt_invalidate_pte(vgpu, &m);
ops->set_pfn(&m, gvt->gtt.scratch_mfn);
ops->clear_present(&m);
}
out:
+ ggtt_set_guest_entry(ggtt_mm, &e, g_gtt_index);
+
+ ggtt_get_host_entry(ggtt_mm, &e, g_gtt_index);
+ ggtt_invalidate_pte(vgpu, &e);
+
ggtt_set_host_entry(ggtt_mm, &m, g_gtt_index);
ggtt_invalidate(gvt->dev_priv);
- ggtt_set_guest_entry(ggtt_mm, &e, g_gtt_index);
return 0;
}
@@ -2430,6 +2421,8 @@ int intel_vgpu_init_gtt(struct intel_vgpu *vgpu)
intel_vgpu_reset_ggtt(vgpu, false);
+ INIT_LIST_HEAD(&gtt->ggtt_mm->ggtt_mm.partial_pte_list);
+
return create_scratch_page_tree(vgpu);
}
@@ -2454,6 +2447,14 @@ static void intel_vgpu_destroy_all_ppgtt_mm(struct intel_vgpu *vgpu)
static void intel_vgpu_destroy_ggtt_mm(struct intel_vgpu *vgpu)
{
+ struct intel_gvt_partial_pte *pos;
+
+ list_for_each_entry(pos,
+ &vgpu->gtt.ggtt_mm->ggtt_mm.partial_pte_list, list) {
+ gvt_dbg_mm("partial PTE update on hold 0x%lx : 0x%llx\n",
+ pos->offset, pos->data);
+ kfree(pos);
+ }
intel_vgpu_destroy_mm(vgpu->gtt.ggtt_mm);
vgpu->gtt.ggtt_mm = NULL;
}
diff --git a/drivers/gpu/drm/i915/gvt/gtt.h b/drivers/gpu/drm/i915/gvt/gtt.h
index bfb6f652b09f..d8cb04cc946d 100644
--- a/drivers/gpu/drm/i915/gvt/gtt.h
+++ b/drivers/gpu/drm/i915/gvt/gtt.h
@@ -132,6 +132,12 @@ enum intel_gvt_mm_type {
#define GVT_RING_CTX_NR_PDPS GEN8_3LVL_PDPES
+struct intel_gvt_partial_pte {
+ unsigned long offset;
+ u64 data;
+ struct list_head list;
+};
+
struct intel_vgpu_mm {
enum intel_gvt_mm_type type;
struct intel_vgpu *vgpu;
@@ -156,8 +162,7 @@ struct intel_vgpu_mm {
} ppgtt_mm;
struct {
void *virtual_ggtt;
- unsigned long last_partial_off;
- u64 last_partial_data;
+ struct list_head partial_pte_list;
} ggtt_mm;
};
};
diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c
index 90f50f67909a..aa280bb07125 100644
--- a/drivers/gpu/drm/i915/gvt/handlers.c
+++ b/drivers/gpu/drm/i915/gvt/handlers.c
@@ -1609,7 +1609,7 @@ static int bxt_gt_disp_pwron_write(struct intel_vgpu *vgpu,
return 0;
}
-static int bxt_edp_psr_imr_iir_write(struct intel_vgpu *vgpu,
+static int edp_psr_imr_iir_write(struct intel_vgpu *vgpu,
unsigned int offset, void *p_data, unsigned int bytes)
{
vgpu_vreg(vgpu, offset) = 0;
@@ -2607,6 +2607,9 @@ static int init_generic_mmio_info(struct intel_gvt *gvt)
MMIO_DFH(_MMIO(0x1a178), D_BDW_PLUS, F_CMD_ACCESS, NULL, NULL);
MMIO_DFH(_MMIO(0x1a17c), D_BDW_PLUS, F_CMD_ACCESS, NULL, NULL);
MMIO_DFH(_MMIO(0x2217c), D_BDW_PLUS, F_CMD_ACCESS, NULL, NULL);
+
+ MMIO_DH(EDP_PSR_IMR, D_BDW_PLUS, NULL, edp_psr_imr_iir_write);
+ MMIO_DH(EDP_PSR_IIR, D_BDW_PLUS, NULL, edp_psr_imr_iir_write);
return 0;
}
@@ -3205,9 +3208,6 @@ static int init_bxt_mmio_info(struct intel_gvt *gvt)
MMIO_D(HSW_TVIDEO_DIP_GCP(TRANSCODER_B), D_BXT);
MMIO_D(HSW_TVIDEO_DIP_GCP(TRANSCODER_C), D_BXT);
- MMIO_DH(EDP_PSR_IMR, D_BXT, NULL, bxt_edp_psr_imr_iir_write);
- MMIO_DH(EDP_PSR_IIR, D_BXT, NULL, bxt_edp_psr_imr_iir_write);
-
MMIO_D(RC6_CTX_BASE, D_BXT);
MMIO_D(GEN8_PUSHBUS_CONTROL, D_BXT);
diff --git a/drivers/gpu/drm/i915/gvt/mmio_context.c b/drivers/gpu/drm/i915/gvt/mmio_context.c
index 10e63eea5492..36a5147cd01e 100644
--- a/drivers/gpu/drm/i915/gvt/mmio_context.c
+++ b/drivers/gpu/drm/i915/gvt/mmio_context.c
@@ -131,7 +131,7 @@ static struct engine_mmio gen9_engine_mmio_list[] __cacheline_aligned = {
{RCS, GAMT_CHKN_BIT_REG, 0x0, false}, /* 0x4ab8 */
{RCS, GEN9_GAMT_ECO_REG_RW_IA, 0x0, false}, /* 0x4ab0 */
- {RCS, GEN9_CSFE_CHICKEN1_RCS, 0x0, false}, /* 0x20d4 */
+ {RCS, GEN9_CSFE_CHICKEN1_RCS, 0xffff, false}, /* 0x20d4 */
{RCS, GEN8_GARBCNTL, 0x0, false}, /* 0xb004 */
{RCS, GEN7_FF_THREAD_MODE, 0x0, false}, /* 0x20a0 */
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 7d9457915704..c55b1f75c980 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -6081,7 +6081,8 @@ i915_gem_object_get_sg(struct drm_i915_gem_object *obj,
count = __sg_page_count(sg);
while (idx + count <= n) {
- unsigned long exception, i;
+ void *entry;
+ unsigned long i;
int ret;
/* If we cannot allocate and insert this entry, or the
@@ -6096,12 +6097,9 @@ i915_gem_object_get_sg(struct drm_i915_gem_object *obj,
if (ret && ret != -EEXIST)
goto scan;
- exception =
- RADIX_TREE_EXCEPTIONAL_ENTRY |
- idx << RADIX_TREE_EXCEPTIONAL_SHIFT;
+ entry = xa_mk_value(idx);
for (i = 1; i < count; i++) {
- ret = radix_tree_insert(&iter->radix, idx + i,
- (void *)exception);
+ ret = radix_tree_insert(&iter->radix, idx + i, entry);
if (ret && ret != -EEXIST)
goto scan;
}
@@ -6139,15 +6137,14 @@ lookup:
GEM_BUG_ON(!sg);
/* If this index is in the middle of multi-page sg entry,
- * the radixtree will contain an exceptional entry that points
+ * the radix tree will contain a value entry that points
* to the start of that range. We will return the pointer to
* the base page and the offset of this page within the
* sg entry's range.
*/
*offset = 0;
- if (unlikely(radix_tree_exception(sg))) {
- unsigned long base =
- (unsigned long)sg >> RADIX_TREE_EXCEPTIONAL_SHIFT;
+ if (unlikely(xa_is_value(sg))) {
+ unsigned long base = xa_to_value(sg);
sg = radix_tree_lookup(&iter->radix, base);
GEM_BUG_ON(!sg);
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index d4fac09095f8..7b3ae2333dbf 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -2162,7 +2162,7 @@ await_fence_array(struct i915_execbuffer *eb,
if (!(flags & I915_EXEC_FENCE_WAIT))
continue;
- fence = drm_syncobj_fence_get(syncobj);
+ drm_syncobj_search_fence(syncobj, 0, 0, &fence);
if (!fence)
return -EINVAL;
diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c
index 82652c3d1bed..5b4d78cdb4ca 100644
--- a/drivers/gpu/drm/i915/i915_vma.c
+++ b/drivers/gpu/drm/i915/i915_vma.c
@@ -892,7 +892,7 @@ static void export_fence(struct i915_vma *vma,
reservation_object_lock(resv, NULL);
if (flags & EXEC_OBJECT_WRITE)
reservation_object_add_excl_fence(resv, &rq->fence);
- else if (reservation_object_reserve_shared(resv) == 0)
+ else if (reservation_object_reserve_shared(resv, 1) == 0)
reservation_object_add_shared_fence(resv, &rq->fence);
reservation_object_unlock(resv);
}
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 314ec14fc952..e2c6a2b3e8f2 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -466,7 +466,8 @@ static void intel_hdmi_set_avi_infoframe(struct intel_encoder *encoder,
const struct drm_display_mode *adjusted_mode =
&crtc_state->base.adjusted_mode;
struct drm_connector *connector = &intel_hdmi->attached_connector->base;
- bool is_hdmi2_sink = connector->display_info.hdmi.scdc.supported;
+ bool is_hdmi2_sink = connector->display_info.hdmi.scdc.supported ||
+ connector->display_info.color_formats & DRM_COLOR_FORMAT_YCRCB420;
union hdmi_infoframe frame;
int ret;
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
index 0b976dfd04df..92ecb9bf982c 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
@@ -600,7 +600,7 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
}
mtk_crtc->layer_nr = mtk_ddp_comp_layer_nr(mtk_crtc->ddp_comp[0]);
- mtk_crtc->planes = devm_kzalloc(dev, mtk_crtc->layer_nr *
+ mtk_crtc->planes = devm_kcalloc(dev, mtk_crtc->layer_nr,
sizeof(struct drm_plane),
GFP_KERNEL);
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c
index 11e3644da79a..862f3ec22131 100644
--- a/drivers/gpu/drm/mediatek/mtk_hdmi.c
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c
@@ -1452,8 +1452,7 @@ static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi,
}
/* The CEC module handles HDMI hotplug detection */
- cec_np = of_find_compatible_node(np->parent, NULL,
- "mediatek,mt8173-cec");
+ cec_np = of_get_compatible_child(np->parent, "mediatek,mt8173-cec");
if (!cec_np) {
dev_err(dev, "Failed to find CEC node\n");
return -EINVAL;
@@ -1463,8 +1462,10 @@ static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi,
if (!cec_pdev) {
dev_err(hdmi->dev, "Waiting for CEC device %pOF\n",
cec_np);
+ of_node_put(cec_np);
return -EPROBE_DEFER;
}
+ of_node_put(cec_np);
hdmi->cec_dev = &cec_pdev->dev;
/*
diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
index d3443125e661..348b5a198b9d 100644
--- a/drivers/gpu/drm/meson/meson_drv.c
+++ b/drivers/gpu/drm/meson/meson_drv.c
@@ -68,15 +68,7 @@
* - Powering Up HDMI controller and PHY
*/
-static void meson_fb_output_poll_changed(struct drm_device *dev)
-{
- struct meson_drm *priv = dev->dev_private;
-
- drm_fbdev_cma_hotplug_event(priv->fbdev);
-}
-
static const struct drm_mode_config_funcs meson_mode_config_funcs = {
- .output_poll_changed = meson_fb_output_poll_changed,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = drm_atomic_helper_commit,
.fb_create = drm_gem_fb_create,
@@ -282,13 +274,6 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
drm_mode_config_reset(drm);
- priv->fbdev = drm_fbdev_cma_init(drm, 32,
- drm->mode_config.num_connector);
- if (IS_ERR(priv->fbdev)) {
- ret = PTR_ERR(priv->fbdev);
- goto free_drm;
- }
-
drm_kms_helper_poll_init(drm);
platform_set_drvdata(pdev, priv);
@@ -297,6 +282,8 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
if (ret)
goto free_drm;
+ drm_fbdev_generic_setup(drm, 32);
+
return 0;
free_drm:
@@ -313,11 +300,9 @@ static int meson_drv_bind(struct device *dev)
static void meson_drv_unbind(struct device *dev)
{
struct drm_device *drm = dev_get_drvdata(dev);
- struct meson_drm *priv = drm->dev_private;
drm_dev_unregister(drm);
drm_kms_helper_poll_fini(drm);
- drm_fbdev_cma_fini(priv->fbdev);
drm_mode_config_cleanup(drm);
drm_dev_put(drm);
diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h
index 8450d6ac8c9b..aab96260da9f 100644
--- a/drivers/gpu/drm/meson/meson_drv.h
+++ b/drivers/gpu/drm/meson/meson_drv.h
@@ -33,7 +33,6 @@ struct meson_drm {
struct drm_device *drm;
struct drm_crtc *crtc;
- struct drm_fbdev_cma *fbdev;
struct drm_plane *primary_plane;
/* Components Data */
diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c
index 514245e69b38..acbbad3e322c 100644
--- a/drivers/gpu/drm/meson/meson_venc.c
+++ b/drivers/gpu/drm/meson/meson_venc.c
@@ -854,6 +854,13 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic,
unsigned int sof_lines;
unsigned int vsync_lines;
+ /* Use VENCI for 480i and 576i and double HDMI pixels */
+ if (mode->flags & DRM_MODE_FLAG_DBLCLK) {
+ hdmi_repeat = true;
+ use_enci = true;
+ venc_hdmi_latency = 1;
+ }
+
if (meson_venc_hdmi_supported_vic(vic)) {
vmode = meson_venc_hdmi_get_vic_vmode(vic);
if (!vmode) {
@@ -865,13 +872,7 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic,
} else {
meson_venc_hdmi_get_dmt_vmode(mode, &vmode_dmt);
vmode = &vmode_dmt;
- }
-
- /* Use VENCI for 480i and 576i and double HDMI pixels */
- if (mode->flags & DRM_MODE_FLAG_DBLCLK) {
- hdmi_repeat = true;
- use_enci = true;
- venc_hdmi_latency = 1;
+ use_enci = false;
}
/* Repeat VENC pixels for 480/576i/p, 720p50/60 and 1080p50/60 */
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h
index 04f1dfba12e5..0aaedc554879 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.h
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.h
@@ -212,8 +212,6 @@ struct mga_device {
int fb_mtrr;
struct {
- struct drm_global_reference mem_global_ref;
- struct ttm_bo_global_ref bo_global_ref;
struct ttm_bo_device bdev;
} ttm;
diff --git a/drivers/gpu/drm/mgag200/mgag200_ttm.c b/drivers/gpu/drm/mgag200/mgag200_ttm.c
index 05570f0de4d7..d96a9b32455e 100644
--- a/drivers/gpu/drm/mgag200/mgag200_ttm.c
+++ b/drivers/gpu/drm/mgag200/mgag200_ttm.c
@@ -36,63 +36,6 @@ mgag200_bdev(struct ttm_bo_device *bd)
return container_of(bd, struct mga_device, ttm.bdev);
}
-static int
-mgag200_ttm_mem_global_init(struct drm_global_reference *ref)
-{
- return ttm_mem_global_init(ref->object);
-}
-
-static void
-mgag200_ttm_mem_global_release(struct drm_global_reference *ref)
-{
- ttm_mem_global_release(ref->object);
-}
-
-static int mgag200_ttm_global_init(struct mga_device *ast)
-{
- struct drm_global_reference *global_ref;
- int r;
-
- global_ref = &ast->ttm.mem_global_ref;
- global_ref->global_type = DRM_GLOBAL_TTM_MEM;
- global_ref->size = sizeof(struct ttm_mem_global);
- global_ref->init = &mgag200_ttm_mem_global_init;
- global_ref->release = &mgag200_ttm_mem_global_release;
- r = drm_global_item_ref(global_ref);
- if (r != 0) {
- DRM_ERROR("Failed setting up TTM memory accounting "
- "subsystem.\n");
- return r;
- }
-
- ast->ttm.bo_global_ref.mem_glob =
- ast->ttm.mem_global_ref.object;
- global_ref = &ast->ttm.bo_global_ref.ref;
- global_ref->global_type = DRM_GLOBAL_TTM_BO;
- global_ref->size = sizeof(struct ttm_bo_global);
- global_ref->init = &ttm_bo_global_init;
- global_ref->release = &ttm_bo_global_release;
- r = drm_global_item_ref(global_ref);
- if (r != 0) {
- DRM_ERROR("Failed setting up TTM BO subsystem.\n");
- drm_global_item_unref(&ast->ttm.mem_global_ref);
- return r;
- }
- return 0;
-}
-
-static void
-mgag200_ttm_global_release(struct mga_device *ast)
-{
- if (ast->ttm.mem_global_ref.release == NULL)
- return;
-
- drm_global_item_unref(&ast->ttm.bo_global_ref.ref);
- drm_global_item_unref(&ast->ttm.mem_global_ref);
- ast->ttm.mem_global_ref.release = NULL;
-}
-
-
static void mgag200_bo_ttm_destroy(struct ttm_buffer_object *tbo)
{
struct mgag200_bo *bo;
@@ -232,12 +175,7 @@ int mgag200_mm_init(struct mga_device *mdev)
struct drm_device *dev = mdev->dev;
struct ttm_bo_device *bdev = &mdev->ttm.bdev;
- ret = mgag200_ttm_global_init(mdev);
- if (ret)
- return ret;
-
ret = ttm_bo_device_init(&mdev->ttm.bdev,
- mdev->ttm.bo_global_ref.ref.object,
&mgag200_bo_driver,
dev->anon_inode->i_mapping,
DRM_FILE_PAGE_OFFSET,
@@ -268,8 +206,6 @@ void mgag200_mm_fini(struct mga_device *mdev)
ttm_bo_device_release(&mdev->ttm.bdev);
- mgag200_ttm_global_release(mdev);
-
arch_io_free_memtype_wc(pci_resource_start(dev->pdev, 0),
pci_resource_len(dev->pdev, 0));
arch_phys_wc_del(mdev->fb_mtrr);
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
index 48b5304f460c..8edd80bb0428 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
@@ -1222,10 +1222,7 @@ static int a5xx_crashdumper_init(struct msm_gpu *gpu,
SZ_1M, MSM_BO_UNCACHED, gpu->aspace,
&dumper->bo, &dumper->iova);
- if (IS_ERR(dumper->ptr))
- return PTR_ERR(dumper->ptr);
-
- return 0;
+ return PTR_ERR_OR_ZERO(dumper->ptr);
}
static void a5xx_crashdumper_free(struct msm_gpu *gpu,
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
index da1363a0c54d..93d70f4a2154 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
@@ -633,8 +633,7 @@ static int adreno_get_legacy_pwrlevels(struct device *dev)
struct device_node *child, *node;
int ret;
- node = of_find_compatible_node(dev->of_node, NULL,
- "qcom,gpu-pwrlevels");
+ node = of_get_compatible_child(dev->of_node, "qcom,gpu-pwrlevels");
if (!node) {
dev_err(dev, "Could not find the GPU powerlevels\n");
return -ENXIO;
@@ -655,6 +654,8 @@ static int adreno_get_legacy_pwrlevels(struct device *dev)
dev_pm_opp_add(dev, val, 0);
}
+ of_node_put(node);
+
return 0;
}
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c
index 790d39f816dc..b557687b1964 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c
@@ -153,8 +153,8 @@ int msm_dss_parse_clock(struct platform_device *pdev,
return 0;
}
- mp->clk_config = devm_kzalloc(&pdev->dev,
- sizeof(struct dss_clk) * num_clk,
+ mp->clk_config = devm_kcalloc(&pdev->dev,
+ num_clk, sizeof(struct dss_clk),
GFP_KERNEL);
if (!mp->clk_config)
return -ENOMEM;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
index f549daf30fe6..d77a8cb15404 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
@@ -1179,8 +1179,6 @@ static void dpu_plane_destroy(struct drm_plane *plane)
mutex_destroy(&pdpu->lock);
- drm_plane_helper_disable(plane, NULL);
-
/* this will destroy the states as well */
drm_plane_cleanup(plane);
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c
index 79ff653d8081..7a499731ce93 100644
--- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c
@@ -68,7 +68,6 @@ static void mdp4_plane_destroy(struct drm_plane *plane)
{
struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
- drm_plane_helper_disable(plane, NULL);
drm_plane_cleanup(plane);
kfree(mdp4_plane);
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c
index 7f42c3e68a53..310459541e48 100644
--- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c
@@ -46,7 +46,6 @@ static void mdp5_plane_destroy(struct drm_plane *plane)
{
struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
- drm_plane_helper_disable(plane, NULL);
drm_plane_cleanup(plane);
kfree(mdp5_plane);
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
index c79659ca5706..23670907a29d 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
@@ -579,7 +579,7 @@ static int msm_hdmi_bind(struct device *dev, struct device *master, void *data)
hdmi_cfg = (struct hdmi_platform_config *)
of_device_get_match_data(dev);
if (!hdmi_cfg) {
- dev_err(dev, "unknown hdmi_cfg: %s\n", of_node->name);
+ dev_err(dev, "unknown hdmi_cfg: %pOFn\n", of_node);
return -ENXIO;
}
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index 4904d0d41409..5e758d95751a 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -312,6 +312,7 @@ static int msm_drm_uninit(struct device *dev)
if (fbdev && priv->fbdev)
msm_fbdev_free(ddev);
#endif
+ drm_atomic_helper_shutdown(ddev);
drm_mode_config_cleanup(ddev);
pm_runtime_get_sync(dev);
diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c
index 7a7923e6220d..a90aedd6883a 100644
--- a/drivers/gpu/drm/msm/msm_gem_submit.c
+++ b/drivers/gpu/drm/msm/msm_gem_submit.c
@@ -241,7 +241,8 @@ static int submit_fence_sync(struct msm_gem_submit *submit, bool no_implicit)
* strange place to call it. OTOH this is a
* convenient can-fail point to hook it in.
*/
- ret = reservation_object_reserve_shared(msm_obj->resv);
+ ret = reservation_object_reserve_shared(msm_obj->resv,
+ 1);
if (ret)
return ret;
}
diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c
index 9d9a18ab95ec..6cbbae3f438b 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/disp.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c
@@ -932,9 +932,22 @@ static enum drm_connector_status
nv50_mstc_detect(struct drm_connector *connector, bool force)
{
struct nv50_mstc *mstc = nv50_mstc(connector);
+ enum drm_connector_status conn_status;
+ int ret;
+
if (!mstc->port)
return connector_status_disconnected;
- return drm_dp_mst_detect_port(connector, mstc->port->mgr, mstc->port);
+
+ ret = pm_runtime_get_sync(connector->dev->dev);
+ if (ret < 0 && ret != -EACCES)
+ return connector_status_disconnected;
+
+ conn_status = drm_dp_mst_detect_port(connector, mstc->port->mgr,
+ mstc->port);
+
+ pm_runtime_mark_last_busy(connector->dev->dev);
+ pm_runtime_put_autosuspend(connector->dev->dev);
+ return conn_status;
}
static void
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index 0b2191fa96f7..d20b9ba4b1c1 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -146,8 +146,6 @@ struct nouveau_drm {
/* TTM interface support */
struct {
- struct drm_global_reference mem_global_ref;
- struct ttm_bo_global_ref bo_global_ref;
struct ttm_bo_device bdev;
atomic_t validate_sequence;
int (*move)(struct nouveau_channel *,
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c
index 99be61ddeb75..d4964f3397a1 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c
@@ -341,7 +341,7 @@ nouveau_fence_sync(struct nouveau_bo *nvbo, struct nouveau_channel *chan, bool e
int ret = 0, i;
if (!exclusive) {
- ret = reservation_object_reserve_shared(resv);
+ ret = reservation_object_reserve_shared(resv, 1);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c
index 8edb9f2a4269..1543c2f8d3d3 100644
--- a/drivers/gpu/drm/nouveau/nouveau_ttm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c
@@ -175,66 +175,6 @@ nouveau_ttm_mmap(struct file *filp, struct vm_area_struct *vma)
}
static int
-nouveau_ttm_mem_global_init(struct drm_global_reference *ref)
-{
- return ttm_mem_global_init(ref->object);
-}
-
-static void
-nouveau_ttm_mem_global_release(struct drm_global_reference *ref)
-{
- ttm_mem_global_release(ref->object);
-}
-
-int
-nouveau_ttm_global_init(struct nouveau_drm *drm)
-{
- struct drm_global_reference *global_ref;
- int ret;
-
- global_ref = &drm->ttm.mem_global_ref;
- global_ref->global_type = DRM_GLOBAL_TTM_MEM;
- global_ref->size = sizeof(struct ttm_mem_global);
- global_ref->init = &nouveau_ttm_mem_global_init;
- global_ref->release = &nouveau_ttm_mem_global_release;
-
- ret = drm_global_item_ref(global_ref);
- if (unlikely(ret != 0)) {
- DRM_ERROR("Failed setting up TTM memory accounting\n");
- drm->ttm.mem_global_ref.release = NULL;
- return ret;
- }
-
- drm->ttm.bo_global_ref.mem_glob = global_ref->object;
- global_ref = &drm->ttm.bo_global_ref.ref;
- global_ref->global_type = DRM_GLOBAL_TTM_BO;
- global_ref->size = sizeof(struct ttm_bo_global);
- global_ref->init = &ttm_bo_global_init;
- global_ref->release = &ttm_bo_global_release;
-
- ret = drm_global_item_ref(global_ref);
- if (unlikely(ret != 0)) {
- DRM_ERROR("Failed setting up TTM BO subsystem\n");
- drm_global_item_unref(&drm->ttm.mem_global_ref);
- drm->ttm.mem_global_ref.release = NULL;
- return ret;
- }
-
- return 0;
-}
-
-void
-nouveau_ttm_global_release(struct nouveau_drm *drm)
-{
- if (drm->ttm.mem_global_ref.release == NULL)
- return;
-
- drm_global_item_unref(&drm->ttm.bo_global_ref.ref);
- drm_global_item_unref(&drm->ttm.mem_global_ref);
- drm->ttm.mem_global_ref.release = NULL;
-}
-
-static int
nouveau_ttm_init_host(struct nouveau_drm *drm, u8 kind)
{
struct nvif_mmu *mmu = &drm->client.mmu;
@@ -296,12 +236,7 @@ nouveau_ttm_init(struct nouveau_drm *drm)
drm->agp.cma = pci->agp.cma;
}
- ret = nouveau_ttm_global_init(drm);
- if (ret)
- return ret;
-
ret = ttm_bo_device_init(&drm->ttm.bdev,
- drm->ttm.bo_global_ref.ref.object,
&nouveau_bo_driver,
dev->anon_inode->i_mapping,
DRM_FILE_PAGE_OFFSET,
@@ -356,8 +291,6 @@ nouveau_ttm_fini(struct nouveau_drm *drm)
ttm_bo_device_release(&drm->ttm.bdev);
- nouveau_ttm_global_release(drm);
-
arch_phys_wc_del(drm->ttm.mtrr);
drm->ttm.mtrr = 0;
arch_io_free_memtype_wc(device->func->resource_addr(device, 1),
diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c
index 394c129cfb3b..0a485c5b982e 100644
--- a/drivers/gpu/drm/omapdrm/dss/dsi.c
+++ b/drivers/gpu/drm/omapdrm/dss/dsi.c
@@ -5409,11 +5409,14 @@ static int dsi_probe(struct platform_device *pdev)
/* DSI on OMAP3 doesn't have register DSI_GNQ, set number
* of data to 3 by default */
- if (dsi->data->quirks & DSI_QUIRK_GNQ)
+ if (dsi->data->quirks & DSI_QUIRK_GNQ) {
+ dsi_runtime_get(dsi);
/* NB_DATA_LANES */
dsi->num_lanes_supported = 1 + REG_GET(dsi, DSI_GNQ, 11, 9);
- else
+ dsi_runtime_put(dsi);
+ } else {
dsi->num_lanes_supported = 3;
+ }
r = dsi_init_output(dsi);
if (r)
@@ -5426,15 +5429,19 @@ static int dsi_probe(struct platform_device *pdev)
}
r = of_platform_populate(dev->of_node, NULL, NULL, dev);
- if (r)
+ if (r) {
DSSERR("Failed to populate DSI child devices: %d\n", r);
+ goto err_uninit_output;
+ }
r = component_add(&pdev->dev, &dsi_component_ops);
if (r)
- goto err_uninit_output;
+ goto err_of_depopulate;
return 0;
+err_of_depopulate:
+ of_platform_depopulate(dev);
err_uninit_output:
dsi_uninit_output(dsi);
err_pm_disable:
@@ -5470,19 +5477,12 @@ static int dsi_runtime_suspend(struct device *dev)
/* wait for current handler to finish before turning the DSI off */
synchronize_irq(dsi->irq);
- dispc_runtime_put(dsi->dss->dispc);
-
return 0;
}
static int dsi_runtime_resume(struct device *dev)
{
struct dsi_data *dsi = dev_get_drvdata(dev);
- int r;
-
- r = dispc_runtime_get(dsi->dss->dispc);
- if (r)
- return r;
dsi->is_enabled = true;
/* ensure the irq handler sees the is_enabled value */
diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c
index 1aaf260aa9b8..7553c7fc1c45 100644
--- a/drivers/gpu/drm/omapdrm/dss/dss.c
+++ b/drivers/gpu/drm/omapdrm/dss/dss.c
@@ -1484,16 +1484,23 @@ static int dss_probe(struct platform_device *pdev)
dss);
/* Add all the child devices as components. */
+ r = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+ if (r)
+ goto err_uninit_debugfs;
+
omapdss_gather_components(&pdev->dev);
device_for_each_child(&pdev->dev, &match, dss_add_child_component);
r = component_master_add_with_match(&pdev->dev, &dss_component_ops, match);
if (r)
- goto err_uninit_debugfs;
+ goto err_of_depopulate;
return 0;
+err_of_depopulate:
+ of_platform_depopulate(&pdev->dev);
+
err_uninit_debugfs:
dss_debugfs_remove_file(dss->debugfs.clk);
dss_debugfs_remove_file(dss->debugfs.dss);
@@ -1522,6 +1529,8 @@ static int dss_remove(struct platform_device *pdev)
{
struct dss_device *dss = platform_get_drvdata(pdev);
+ of_platform_depopulate(&pdev->dev);
+
component_master_del(&pdev->dev, &dss_component_ops);
dss_debugfs_remove_file(dss->debugfs.clk);
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c
index cf6230eac31a..aabdda394c9c 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c
@@ -635,10 +635,14 @@ static int hdmi4_bind(struct device *dev, struct device *master, void *data)
hdmi->dss = dss;
- r = hdmi_pll_init(dss, hdmi->pdev, &hdmi->pll, &hdmi->wp);
+ r = hdmi_runtime_get(hdmi);
if (r)
return r;
+ r = hdmi_pll_init(dss, hdmi->pdev, &hdmi->pll, &hdmi->wp);
+ if (r)
+ goto err_runtime_put;
+
r = hdmi4_cec_init(hdmi->pdev, &hdmi->core, &hdmi->wp);
if (r)
goto err_pll_uninit;
@@ -652,12 +656,16 @@ static int hdmi4_bind(struct device *dev, struct device *master, void *data)
hdmi->debugfs = dss_debugfs_create_file(dss, "hdmi", hdmi_dump_regs,
hdmi);
+ hdmi_runtime_put(hdmi);
+
return 0;
err_cec_uninit:
hdmi4_cec_uninit(&hdmi->core);
err_pll_uninit:
hdmi_pll_uninit(&hdmi->pll);
+err_runtime_put:
+ hdmi_runtime_put(hdmi);
return r;
}
@@ -833,32 +841,6 @@ static int hdmi4_remove(struct platform_device *pdev)
return 0;
}
-static int hdmi_runtime_suspend(struct device *dev)
-{
- struct omap_hdmi *hdmi = dev_get_drvdata(dev);
-
- dispc_runtime_put(hdmi->dss->dispc);
-
- return 0;
-}
-
-static int hdmi_runtime_resume(struct device *dev)
-{
- struct omap_hdmi *hdmi = dev_get_drvdata(dev);
- int r;
-
- r = dispc_runtime_get(hdmi->dss->dispc);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-static const struct dev_pm_ops hdmi_pm_ops = {
- .runtime_suspend = hdmi_runtime_suspend,
- .runtime_resume = hdmi_runtime_resume,
-};
-
static const struct of_device_id hdmi_of_match[] = {
{ .compatible = "ti,omap4-hdmi", },
{},
@@ -869,7 +851,6 @@ struct platform_driver omapdss_hdmi4hw_driver = {
.remove = hdmi4_remove,
.driver = {
.name = "omapdss_hdmi",
- .pm = &hdmi_pm_ops,
.of_match_table = hdmi_of_match,
.suppress_bind_attrs = true,
},
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c
index b0e4a7463f8c..9e8556f67a29 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c
@@ -825,32 +825,6 @@ static int hdmi5_remove(struct platform_device *pdev)
return 0;
}
-static int hdmi_runtime_suspend(struct device *dev)
-{
- struct omap_hdmi *hdmi = dev_get_drvdata(dev);
-
- dispc_runtime_put(hdmi->dss->dispc);
-
- return 0;
-}
-
-static int hdmi_runtime_resume(struct device *dev)
-{
- struct omap_hdmi *hdmi = dev_get_drvdata(dev);
- int r;
-
- r = dispc_runtime_get(hdmi->dss->dispc);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-static const struct dev_pm_ops hdmi_pm_ops = {
- .runtime_suspend = hdmi_runtime_suspend,
- .runtime_resume = hdmi_runtime_resume,
-};
-
static const struct of_device_id hdmi_of_match[] = {
{ .compatible = "ti,omap5-hdmi", },
{ .compatible = "ti,dra7-hdmi", },
@@ -862,7 +836,6 @@ struct platform_driver omapdss_hdmi5hw_driver = {
.remove = hdmi5_remove,
.driver = {
.name = "omapdss_hdmi5",
- .pm = &hdmi_pm_ops,
.of_match_table = hdmi_of_match,
.suppress_bind_attrs = true,
},
diff --git a/drivers/gpu/drm/omapdrm/dss/venc.c b/drivers/gpu/drm/omapdrm/dss/venc.c
index ff0b18c8e4ac..b5f52727f8b1 100644
--- a/drivers/gpu/drm/omapdrm/dss/venc.c
+++ b/drivers/gpu/drm/omapdrm/dss/venc.c
@@ -946,19 +946,12 @@ static int venc_runtime_suspend(struct device *dev)
if (venc->tv_dac_clk)
clk_disable_unprepare(venc->tv_dac_clk);
- dispc_runtime_put(venc->dss->dispc);
-
return 0;
}
static int venc_runtime_resume(struct device *dev)
{
struct venc_device *venc = dev_get_drvdata(dev);
- int r;
-
- r = dispc_runtime_get(venc->dss->dispc);
- if (r < 0)
- return r;
if (venc->tv_dac_clk)
clk_prepare_enable(venc->tv_dac_clk);
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c
index 62928ec0e7db..caffc547ef97 100644
--- a/drivers/gpu/drm/omapdrm/omap_crtc.c
+++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
@@ -350,11 +350,14 @@ static void omap_crtc_arm_event(struct drm_crtc *crtc)
static void omap_crtc_atomic_enable(struct drm_crtc *crtc,
struct drm_crtc_state *old_state)
{
+ struct omap_drm_private *priv = crtc->dev->dev_private;
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
int ret;
DBG("%s", omap_crtc->name);
+ priv->dispc_ops->runtime_get(priv->dispc);
+
spin_lock_irq(&crtc->dev->event_lock);
drm_crtc_vblank_on(crtc);
ret = drm_crtc_vblank_get(crtc);
@@ -367,6 +370,7 @@ static void omap_crtc_atomic_enable(struct drm_crtc *crtc,
static void omap_crtc_atomic_disable(struct drm_crtc *crtc,
struct drm_crtc_state *old_state)
{
+ struct omap_drm_private *priv = crtc->dev->dev_private;
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
DBG("%s", omap_crtc->name);
@@ -379,6 +383,8 @@ static void omap_crtc_atomic_disable(struct drm_crtc *crtc,
spin_unlock_irq(&crtc->dev->event_lock);
drm_crtc_vblank_off(crtc);
+
+ priv->dispc_ops->runtime_put(priv->dispc);
}
static enum drm_mode_status omap_crtc_mode_valid(struct drm_crtc *crtc,
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index 6020c30a33b3..3f3537719beb 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -90,6 +90,18 @@ config DRM_PANEL_LG_LG4573
Say Y here if you want to enable support for LG4573 RGB panel.
To compile this driver as a module, choose M here.
+config DRM_PANEL_OLIMEX_LCD_OLINUXINO
+ tristate "Olimex LCD-OLinuXino panel"
+ depends on OF
+ depends on I2C
+ depends on BACKLIGHT_CLASS_DEVICE
+ help
+ The panel is used with different sizes LCDs, from 480x272 to
+ 1280x800, and 24 bit per pixel.
+
+ Say Y here if you want to enable support for Olimex Ltd.
+ LCD-OLinuXino panel.
+
config DRM_PANEL_ORISETECH_OTM8009A
tristate "Orise Technology otm8009a 480x800 dsi 2dl panel"
depends on OF
@@ -126,6 +138,12 @@ config DRM_PANEL_RAYDIUM_RM68200
Say Y here if you want to enable support for Raydium RM68200
720x1280 DSI video mode panel.
+config DRM_PANEL_SAMSUNG_S6D16D0
+ tristate "Samsung S6D16D0 DSI video mode panel"
+ depends on OF
+ depends on DRM_MIPI_DSI
+ select VIDEOMODE_HELPERS
+
config DRM_PANEL_SAMSUNG_S6E3HA2
tristate "Samsung S6E3HA2 DSI video mode panel"
depends on OF
@@ -186,4 +204,11 @@ config DRM_PANEL_SITRONIX_ST7789V
Say Y here if you want to enable support for the Sitronix
ST7789V controller for 240x320 LCD panels
+config DRM_PANEL_TRULY_NT35597_WQXGA
+ tristate "Truly WQXGA"
+ depends on OF
+ depends on DRM_MIPI_DSI
+ help
+ Say Y here if you want to enable support for Truly NT35597 WQXGA Dual DSI
+ Video Mode panel
endmenu
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index 5ccaaa9d13af..4396658a7996 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -7,11 +7,13 @@ obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9881C) += panel-ilitek-ili9881c.o
obj-$(CONFIG_DRM_PANEL_INNOLUX_P079ZCA) += panel-innolux-p079zca.o
obj-$(CONFIG_DRM_PANEL_JDI_LT070ME05000) += panel-jdi-lt070me05000.o
obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o
+obj-$(CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO) += panel-olimex-lcd-olinuxino.o
obj-$(CONFIG_DRM_PANEL_ORISETECH_OTM8009A) += panel-orisetech-otm8009a.o
obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.o
obj-$(CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN) += panel-raspberrypi-touchscreen.o
obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM68200) += panel-raydium-rm68200.o
obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o
+obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6D16D0) += panel-samsung-s6d16d0.o
obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2) += panel-samsung-s6e3ha2.o
obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03) += panel-samsung-s6e63j0x03.o
obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o
@@ -19,3 +21,4 @@ obj-$(CONFIG_DRM_PANEL_SEIKO_43WVF1G) += panel-seiko-43wvf1g.o
obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o
obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o
obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7789V) += panel-sitronix-st7789v.o
+obj-$(CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA) += panel-truly-nt35597.o
diff --git a/drivers/gpu/drm/panel/panel-innolux-p079zca.c b/drivers/gpu/drm/panel/panel-innolux-p079zca.c
index 72edb334d997..ca4ae45dd307 100644
--- a/drivers/gpu/drm/panel/panel-innolux-p079zca.c
+++ b/drivers/gpu/drm/panel/panel-innolux-p079zca.c
@@ -506,8 +506,7 @@ static int innolux_panel_add(struct mipi_dsi_device *dsi,
static void innolux_panel_del(struct innolux_panel *innolux)
{
- if (innolux->base.dev)
- drm_panel_remove(&innolux->base);
+ drm_panel_remove(&innolux->base);
}
static int innolux_panel_probe(struct mipi_dsi_device *dsi)
diff --git a/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c b/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c
new file mode 100644
index 000000000000..5e8d4523e9ed
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c
@@ -0,0 +1,330 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * LCD-OLinuXino support for panel driver
+ *
+ * Copyright (C) 2018 Olimex Ltd.
+ * Author: Stefan Mavrodiev <stefan@olimex.com>
+ */
+
+#include <linux/backlight.h>
+#include <linux/crc32.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+
+#include <drm/drm_modes.h>
+#include <drm/drm_panel.h>
+#include <drm/drmP.h>
+
+#include <video/videomode.h>
+#include <video/display_timing.h>
+
+#define LCD_OLINUXINO_HEADER_MAGIC 0x4F4CB727
+#define LCD_OLINUXINO_DATA_LEN 256
+
+struct lcd_olinuxino_mode {
+ u32 pixelclock;
+ u32 hactive;
+ u32 hfp;
+ u32 hbp;
+ u32 hpw;
+ u32 vactive;
+ u32 vfp;
+ u32 vbp;
+ u32 vpw;
+ u32 refresh;
+ u32 flags;
+};
+
+struct lcd_olinuxino_info {
+ char name[32];
+ u32 width_mm;
+ u32 height_mm;
+ u32 bpc;
+ u32 bus_format;
+ u32 bus_flag;
+} __attribute__((__packed__));
+
+struct lcd_olinuxino_eeprom {
+ u32 header;
+ u32 id;
+ char revision[4];
+ u32 serial;
+ struct lcd_olinuxino_info info;
+ u32 num_modes;
+ u8 reserved[180];
+ u32 checksum;
+} __attribute__((__packed__));
+
+struct lcd_olinuxino {
+ struct drm_panel panel;
+ struct device *dev;
+ struct i2c_client *client;
+ struct mutex mutex;
+
+ bool prepared;
+ bool enabled;
+
+ struct backlight_device *backlight;
+ struct regulator *supply;
+ struct gpio_desc *enable_gpio;
+
+ struct lcd_olinuxino_eeprom eeprom;
+};
+
+static inline struct lcd_olinuxino *to_lcd_olinuxino(struct drm_panel *panel)
+{
+ return container_of(panel, struct lcd_olinuxino, panel);
+}
+
+static int lcd_olinuxino_disable(struct drm_panel *panel)
+{
+ struct lcd_olinuxino *lcd = to_lcd_olinuxino(panel);
+
+ if (!lcd->enabled)
+ return 0;
+
+ backlight_disable(lcd->backlight);
+
+ lcd->enabled = false;
+
+ return 0;
+}
+
+static int lcd_olinuxino_unprepare(struct drm_panel *panel)
+{
+ struct lcd_olinuxino *lcd = to_lcd_olinuxino(panel);
+
+ if (!lcd->prepared)
+ return 0;
+
+ gpiod_set_value_cansleep(lcd->enable_gpio, 0);
+ regulator_disable(lcd->supply);
+
+ lcd->prepared = false;
+
+ return 0;
+}
+
+static int lcd_olinuxino_prepare(struct drm_panel *panel)
+{
+ struct lcd_olinuxino *lcd = to_lcd_olinuxino(panel);
+ int ret;
+
+ if (lcd->prepared)
+ return 0;
+
+ ret = regulator_enable(lcd->supply);
+ if (ret < 0)
+ return ret;
+
+ gpiod_set_value_cansleep(lcd->enable_gpio, 1);
+ lcd->prepared = true;
+
+ return 0;
+}
+
+static int lcd_olinuxino_enable(struct drm_panel *panel)
+{
+ struct lcd_olinuxino *lcd = to_lcd_olinuxino(panel);
+
+ if (lcd->enabled)
+ return 0;
+
+ backlight_enable(lcd->backlight);
+
+ lcd->enabled = true;
+
+ return 0;
+}
+
+static int lcd_olinuxino_get_modes(struct drm_panel *panel)
+{
+ struct lcd_olinuxino *lcd = to_lcd_olinuxino(panel);
+ struct drm_connector *connector = lcd->panel.connector;
+ struct lcd_olinuxino_info *lcd_info = &lcd->eeprom.info;
+ struct drm_device *drm = lcd->panel.drm;
+ struct lcd_olinuxino_mode *lcd_mode;
+ struct drm_display_mode *mode;
+ u32 i, num = 0;
+
+ for (i = 0; i < lcd->eeprom.num_modes; i++) {
+ lcd_mode = (struct lcd_olinuxino_mode *)
+ &lcd->eeprom.reserved[i * sizeof(*lcd_mode)];
+
+ mode = drm_mode_create(drm);
+ if (!mode) {
+ dev_err(drm->dev, "failed to add mode %ux%u@%u\n",
+ lcd_mode->hactive,
+ lcd_mode->vactive,
+ lcd_mode->refresh);
+ continue;
+ }
+
+ mode->clock = lcd_mode->pixelclock;
+ mode->hdisplay = lcd_mode->hactive;
+ mode->hsync_start = lcd_mode->hactive + lcd_mode->hfp;
+ mode->hsync_end = lcd_mode->hactive + lcd_mode->hfp +
+ lcd_mode->hpw;
+ mode->htotal = lcd_mode->hactive + lcd_mode->hfp +
+ lcd_mode->hpw + lcd_mode->hbp;
+ mode->vdisplay = lcd_mode->vactive;
+ mode->vsync_start = lcd_mode->vactive + lcd_mode->vfp;
+ mode->vsync_end = lcd_mode->vactive + lcd_mode->vfp +
+ lcd_mode->vpw;
+ mode->vtotal = lcd_mode->vactive + lcd_mode->vfp +
+ lcd_mode->vpw + lcd_mode->vbp;
+ mode->vrefresh = lcd_mode->refresh;
+
+ /* Always make the first mode preferred */
+ if (i == 0)
+ mode->type |= DRM_MODE_TYPE_PREFERRED;
+ mode->type |= DRM_MODE_TYPE_DRIVER;
+
+ drm_mode_set_name(mode);
+ drm_mode_probed_add(connector, mode);
+
+ num++;
+ }
+
+ memcpy(connector->display_info.name, lcd_info->name, 32);
+ connector->display_info.width_mm = lcd_info->width_mm;
+ connector->display_info.height_mm = lcd_info->height_mm;
+ connector->display_info.bpc = lcd_info->bpc;
+
+ if (lcd_info->bus_format)
+ drm_display_info_set_bus_formats(&connector->display_info,
+ &lcd_info->bus_format, 1);
+ connector->display_info.bus_flags = lcd_info->bus_flag;
+
+ return num;
+}
+
+static const struct drm_panel_funcs lcd_olinuxino_funcs = {
+ .disable = lcd_olinuxino_disable,
+ .unprepare = lcd_olinuxino_unprepare,
+ .prepare = lcd_olinuxino_prepare,
+ .enable = lcd_olinuxino_enable,
+ .get_modes = lcd_olinuxino_get_modes,
+};
+
+static int lcd_olinuxino_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct lcd_olinuxino *lcd;
+ u32 checksum, i;
+ int ret = 0;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
+ I2C_FUNC_SMBUS_READ_I2C_BLOCK))
+ return -ENODEV;
+
+ lcd = devm_kzalloc(dev, sizeof(*lcd), GFP_KERNEL);
+ if (!lcd)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, lcd);
+ lcd->dev = dev;
+ lcd->client = client;
+
+ mutex_init(&lcd->mutex);
+
+ /* Copy data into buffer */
+ for (i = 0; i < LCD_OLINUXINO_DATA_LEN; i += I2C_SMBUS_BLOCK_MAX) {
+ mutex_lock(&lcd->mutex);
+ ret = i2c_smbus_read_i2c_block_data(client,
+ i,
+ I2C_SMBUS_BLOCK_MAX,
+ (u8 *)&lcd->eeprom + i);
+ mutex_unlock(&lcd->mutex);
+ if (ret < 0) {
+ dev_err(dev, "error reading from device at %02x\n", i);
+ return ret;
+ }
+ }
+
+ /* Check configuration checksum */
+ checksum = ~crc32(~0, (u8 *)&lcd->eeprom, 252);
+ if (checksum != lcd->eeprom.checksum) {
+ dev_err(dev, "configuration checksum does not match!\n");
+ return -EINVAL;
+ }
+
+ /* Check magic header */
+ if (lcd->eeprom.header != LCD_OLINUXINO_HEADER_MAGIC) {
+ dev_err(dev, "magic header does not match\n");
+ return -EINVAL;
+ }
+
+ dev_info(dev, "Detected %s, Rev. %s, Serial: %08x\n",
+ lcd->eeprom.info.name,
+ lcd->eeprom.revision,
+ lcd->eeprom.serial);
+
+ /*
+ * The eeprom can hold up to 4 modes.
+ * If the stored value is bigger, overwrite it.
+ */
+ if (lcd->eeprom.num_modes > 4) {
+ dev_warn(dev, "invalid number of modes, falling back to 4\n");
+ lcd->eeprom.num_modes = 4;
+ }
+
+ lcd->enabled = false;
+ lcd->prepared = false;
+
+ lcd->supply = devm_regulator_get(dev, "power");
+ if (IS_ERR(lcd->supply))
+ return PTR_ERR(lcd->supply);
+
+ lcd->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
+ if (IS_ERR(lcd->enable_gpio))
+ return PTR_ERR(lcd->enable_gpio);
+
+ lcd->backlight = devm_of_find_backlight(dev);
+ if (IS_ERR(lcd->backlight))
+ return PTR_ERR(lcd->backlight);
+
+ drm_panel_init(&lcd->panel);
+ lcd->panel.dev = dev;
+ lcd->panel.funcs = &lcd_olinuxino_funcs;
+
+ return drm_panel_add(&lcd->panel);
+}
+
+static int lcd_olinuxino_remove(struct i2c_client *client)
+{
+ struct lcd_olinuxino *panel = i2c_get_clientdata(client);
+
+ drm_panel_remove(&panel->panel);
+
+ lcd_olinuxino_disable(&panel->panel);
+ lcd_olinuxino_unprepare(&panel->panel);
+
+ return 0;
+}
+
+static const struct of_device_id lcd_olinuxino_of_ids[] = {
+ { .compatible = "olimex,lcd-olinuxino" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, lcd_olinuxino_of_ids);
+
+static struct i2c_driver lcd_olinuxino_driver = {
+ .driver = {
+ .name = "lcd_olinuxino",
+ .of_match_table = lcd_olinuxino_of_ids,
+ },
+ .probe = lcd_olinuxino_probe,
+ .remove = lcd_olinuxino_remove,
+};
+
+module_i2c_driver(lcd_olinuxino_driver);
+
+MODULE_AUTHOR("Stefan Mavrodiev <stefan@olimex.com>");
+MODULE_DESCRIPTION("LCD-OLinuXino driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c b/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c
new file mode 100644
index 000000000000..fa8bfa7c492d
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c
@@ -0,0 +1,264 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * MIPI-DSI Samsung s6d16d0 panel driver. This is a 864x480
+ * AMOLED panel with a command-only DSI interface.
+ */
+
+#include <drm/drm_modes.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_print.h>
+
+#include <linux/gpio/consumer.h>
+#include <linux/regulator/consumer.h>
+#include <linux/delay.h>
+#include <linux/of_device.h>
+#include <linux/module.h>
+
+struct s6d16d0 {
+ struct device *dev;
+ struct drm_panel panel;
+ struct regulator *supply;
+ struct gpio_desc *reset_gpio;
+};
+
+/*
+ * The timings are not very helpful as the display is used in
+ * command mode.
+ */
+static const struct drm_display_mode samsung_s6d16d0_mode = {
+ /* HS clock, (htotal*vtotal*vrefresh)/1000 */
+ .clock = 420160,
+ .hdisplay = 864,
+ .hsync_start = 864 + 154,
+ .hsync_end = 864 + 154 + 16,
+ .htotal = 864 + 154 + 16 + 32,
+ .vdisplay = 480,
+ .vsync_start = 480 + 1,
+ .vsync_end = 480 + 1 + 1,
+ .vtotal = 480 + 1 + 1 + 1,
+ /*
+ * This depends on the clocking HS vs LP rate, this value
+ * is calculated as:
+ * vrefresh = (clock * 1000) / (htotal*vtotal)
+ */
+ .vrefresh = 816,
+ .width_mm = 84,
+ .height_mm = 48,
+};
+
+static inline struct s6d16d0 *panel_to_s6d16d0(struct drm_panel *panel)
+{
+ return container_of(panel, struct s6d16d0, panel);
+}
+
+static int s6d16d0_unprepare(struct drm_panel *panel)
+{
+ struct s6d16d0 *s6 = panel_to_s6d16d0(panel);
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(s6->dev);
+ int ret;
+
+ /* Enter sleep mode */
+ ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
+ if (ret) {
+ DRM_DEV_ERROR(s6->dev, "failed to enter sleep mode (%d)\n",
+ ret);
+ return ret;
+ }
+
+ /* Assert RESET */
+ gpiod_set_value_cansleep(s6->reset_gpio, 1);
+ regulator_disable(s6->supply);
+
+ return 0;
+}
+
+static int s6d16d0_prepare(struct drm_panel *panel)
+{
+ struct s6d16d0 *s6 = panel_to_s6d16d0(panel);
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(s6->dev);
+ int ret;
+
+ ret = regulator_enable(s6->supply);
+ if (ret) {
+ DRM_DEV_ERROR(s6->dev, "failed to enable supply (%d)\n", ret);
+ return ret;
+ }
+
+ /* Assert RESET */
+ gpiod_set_value_cansleep(s6->reset_gpio, 1);
+ udelay(10);
+ /* De-assert RESET */
+ gpiod_set_value_cansleep(s6->reset_gpio, 0);
+ msleep(120);
+
+ /* Enabe tearing mode: send TE (tearing effect) at VBLANK */
+ ret = mipi_dsi_dcs_set_tear_on(dsi,
+ MIPI_DSI_DCS_TEAR_MODE_VBLANK);
+ if (ret) {
+ DRM_DEV_ERROR(s6->dev, "failed to enble vblank TE (%d)\n",
+ ret);
+ return ret;
+ }
+ /* Exit sleep mode and power on */
+ ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
+ if (ret) {
+ DRM_DEV_ERROR(s6->dev, "failed to exit sleep mode (%d)\n",
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int s6d16d0_enable(struct drm_panel *panel)
+{
+ struct s6d16d0 *s6 = panel_to_s6d16d0(panel);
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(s6->dev);
+ int ret;
+
+ ret = mipi_dsi_dcs_set_display_on(dsi);
+ if (ret) {
+ DRM_DEV_ERROR(s6->dev, "failed to turn display on (%d)\n",
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int s6d16d0_disable(struct drm_panel *panel)
+{
+ struct s6d16d0 *s6 = panel_to_s6d16d0(panel);
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(s6->dev);
+ int ret;
+
+ ret = mipi_dsi_dcs_set_display_off(dsi);
+ if (ret) {
+ DRM_DEV_ERROR(s6->dev, "failed to turn display off (%d)\n",
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int s6d16d0_get_modes(struct drm_panel *panel)
+{
+ struct drm_connector *connector = panel->connector;
+ struct drm_display_mode *mode;
+
+ strncpy(connector->display_info.name, "Samsung S6D16D0\0",
+ DRM_DISPLAY_INFO_LEN);
+
+ mode = drm_mode_duplicate(panel->drm, &samsung_s6d16d0_mode);
+ if (!mode) {
+ DRM_ERROR("bad mode or failed to add mode\n");
+ return -EINVAL;
+ }
+ drm_mode_set_name(mode);
+ mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+
+ connector->display_info.width_mm = mode->width_mm;
+ connector->display_info.height_mm = mode->height_mm;
+
+ drm_mode_probed_add(connector, mode);
+
+ return 1; /* Number of modes */
+}
+
+static const struct drm_panel_funcs s6d16d0_drm_funcs = {
+ .disable = s6d16d0_disable,
+ .unprepare = s6d16d0_unprepare,
+ .prepare = s6d16d0_prepare,
+ .enable = s6d16d0_enable,
+ .get_modes = s6d16d0_get_modes,
+};
+
+static int s6d16d0_probe(struct mipi_dsi_device *dsi)
+{
+ struct device *dev = &dsi->dev;
+ struct s6d16d0 *s6;
+ int ret;
+
+ s6 = devm_kzalloc(dev, sizeof(struct s6d16d0), GFP_KERNEL);
+ if (!s6)
+ return -ENOMEM;
+
+ mipi_dsi_set_drvdata(dsi, s6);
+ s6->dev = dev;
+
+ dsi->lanes = 2;
+ dsi->format = MIPI_DSI_FMT_RGB888;
+ dsi->hs_rate = 420160000;
+ dsi->lp_rate = 19200000;
+ /*
+ * This display uses command mode so no MIPI_DSI_MODE_VIDEO
+ * or MIPI_DSI_MODE_VIDEO_SYNC_PULSE
+ *
+ * As we only send commands we do not need to be continuously
+ * clocked.
+ */
+ dsi->mode_flags =
+ MIPI_DSI_CLOCK_NON_CONTINUOUS |
+ MIPI_DSI_MODE_EOT_PACKET;
+
+ s6->supply = devm_regulator_get(dev, "vdd1");
+ if (IS_ERR(s6->supply))
+ return PTR_ERR(s6->supply);
+
+ /* This asserts RESET by default */
+ s6->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(s6->reset_gpio)) {
+ ret = PTR_ERR(s6->reset_gpio);
+ if (ret != -EPROBE_DEFER)
+ DRM_DEV_ERROR(dev, "failed to request GPIO (%d)\n",
+ ret);
+ return ret;
+ }
+
+ drm_panel_init(&s6->panel);
+ s6->panel.dev = dev;
+ s6->panel.funcs = &s6d16d0_drm_funcs;
+
+ ret = drm_panel_add(&s6->panel);
+ if (ret < 0)
+ return ret;
+
+ ret = mipi_dsi_attach(dsi);
+ if (ret < 0)
+ drm_panel_remove(&s6->panel);
+
+ return ret;
+}
+
+static int s6d16d0_remove(struct mipi_dsi_device *dsi)
+{
+ struct s6d16d0 *s6 = mipi_dsi_get_drvdata(dsi);
+
+ mipi_dsi_detach(dsi);
+ drm_panel_remove(&s6->panel);
+
+ return 0;
+}
+
+static const struct of_device_id s6d16d0_of_match[] = {
+ { .compatible = "samsung,s6d16d0" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, s6d16d0_of_match);
+
+static struct mipi_dsi_driver s6d16d0_driver = {
+ .probe = s6d16d0_probe,
+ .remove = s6d16d0_remove,
+ .driver = {
+ .name = "panel-samsung-s6d16d0",
+ .of_match_table = s6d16d0_of_match,
+ },
+};
+module_mipi_dsi_driver(s6d16d0_driver);
+
+MODULE_AUTHOR("Linus Wallei <linus.walleij@linaro.org>");
+MODULE_DESCRIPTION("MIPI-DSI s6d16d0 Panel Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/panel/panel-seiko-43wvf1g.c b/drivers/gpu/drm/panel/panel-seiko-43wvf1g.c
index 75f925390551..2d99e28ff117 100644
--- a/drivers/gpu/drm/panel/panel-seiko-43wvf1g.c
+++ b/drivers/gpu/drm/panel/panel-seiko-43wvf1g.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2017 NXP Semiconductors.
* Author: Marco Franchi <marco.franchi@nxp.com>
*
* Based on Panel Simple driver by Thierry Reding <treding@nvidia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
*/
#include <linux/backlight.h>
@@ -366,6 +363,6 @@ static struct platform_driver seiko_panel_platform_driver = {
};
module_platform_driver(seiko_panel_platform_driver);
-MODULE_AUTHOR("Marco Franchi <marco.franchi@nxp.com");
+MODULE_AUTHOR("Marco Franchi <marco.franchi@nxp.com>");
MODULE_DESCRIPTION("Seiko 43WVF1G panel driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
index a04ffb3b2174..5fbee837b0db 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -782,16 +782,38 @@ static const struct panel_desc avic_tm070ddh03 = {
},
};
+static const struct drm_display_mode bananapi_s070wv20_ct16_mode = {
+ .clock = 30000,
+ .hdisplay = 800,
+ .hsync_start = 800 + 40,
+ .hsync_end = 800 + 40 + 48,
+ .htotal = 800 + 40 + 48 + 40,
+ .vdisplay = 480,
+ .vsync_start = 480 + 13,
+ .vsync_end = 480 + 13 + 3,
+ .vtotal = 480 + 13 + 3 + 29,
+};
+
+static const struct panel_desc bananapi_s070wv20_ct16 = {
+ .modes = &bananapi_s070wv20_ct16_mode,
+ .num_modes = 1,
+ .bpc = 6,
+ .size = {
+ .width = 154,
+ .height = 86,
+ },
+};
+
static const struct drm_display_mode boe_hv070wsa_mode = {
- .clock = 40800,
+ .clock = 42105,
.hdisplay = 1024,
- .hsync_start = 1024 + 90,
- .hsync_end = 1024 + 90 + 90,
- .htotal = 1024 + 90 + 90 + 90,
+ .hsync_start = 1024 + 30,
+ .hsync_end = 1024 + 30 + 30,
+ .htotal = 1024 + 30 + 30 + 30,
.vdisplay = 600,
- .vsync_start = 600 + 3,
- .vsync_end = 600 + 3 + 4,
- .vtotal = 600 + 3 + 4 + 3,
+ .vsync_start = 600 + 10,
+ .vsync_end = 600 + 10 + 10,
+ .vtotal = 600 + 10 + 10 + 10,
.vrefresh = 60,
};
@@ -846,6 +868,55 @@ static const struct panel_desc boe_nv101wxmn51 = {
},
};
+static const struct drm_display_mode cdtech_s043wq26h_ct7_mode = {
+ .clock = 9000,
+ .hdisplay = 480,
+ .hsync_start = 480 + 5,
+ .hsync_end = 480 + 5 + 5,
+ .htotal = 480 + 5 + 5 + 40,
+ .vdisplay = 272,
+ .vsync_start = 272 + 8,
+ .vsync_end = 272 + 8 + 8,
+ .vtotal = 272 + 8 + 8 + 8,
+ .vrefresh = 60,
+ .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+};
+
+static const struct panel_desc cdtech_s043wq26h_ct7 = {
+ .modes = &cdtech_s043wq26h_ct7_mode,
+ .num_modes = 1,
+ .bpc = 8,
+ .size = {
+ .width = 95,
+ .height = 54,
+ },
+ .bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE,
+};
+
+static const struct drm_display_mode cdtech_s070wv95_ct16_mode = {
+ .clock = 35000,
+ .hdisplay = 800,
+ .hsync_start = 800 + 40,
+ .hsync_end = 800 + 40 + 40,
+ .htotal = 800 + 40 + 40 + 48,
+ .vdisplay = 480,
+ .vsync_start = 480 + 29,
+ .vsync_end = 480 + 29 + 13,
+ .vtotal = 480 + 29 + 13 + 3,
+ .vrefresh = 60,
+ .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+};
+
+static const struct panel_desc cdtech_s070wv95_ct16 = {
+ .modes = &cdtech_s070wv95_ct16_mode,
+ .num_modes = 1,
+ .bpc = 8,
+ .size = {
+ .width = 154,
+ .height = 85,
+ },
+};
+
static const struct drm_display_mode chunghwa_claa070wp03xg_mode = {
.clock = 66770,
.hdisplay = 800,
@@ -971,6 +1042,36 @@ static const struct panel_desc dlc_dlc0700yzg_1 = {
.bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG,
};
+static const struct display_timing dlc_dlc1010gig_timing = {
+ .pixelclock = { 68900000, 71100000, 73400000 },
+ .hactive = { 1280, 1280, 1280 },
+ .hfront_porch = { 43, 53, 63 },
+ .hback_porch = { 43, 53, 63 },
+ .hsync_len = { 44, 54, 64 },
+ .vactive = { 800, 800, 800 },
+ .vfront_porch = { 5, 8, 11 },
+ .vback_porch = { 5, 8, 11 },
+ .vsync_len = { 5, 7, 11 },
+ .flags = DISPLAY_FLAGS_DE_HIGH,
+};
+
+static const struct panel_desc dlc_dlc1010gig = {
+ .timings = &dlc_dlc1010gig_timing,
+ .num_timings = 1,
+ .bpc = 8,
+ .size = {
+ .width = 216,
+ .height = 135,
+ },
+ .delay = {
+ .prepare = 60,
+ .enable = 150,
+ .disable = 100,
+ .unprepare = 60,
+ },
+ .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
+};
+
static const struct drm_display_mode edt_et057090dhu_mode = {
.clock = 25175,
.hdisplay = 640,
@@ -2334,6 +2435,33 @@ static const struct panel_desc winstar_wf35ltiacd = {
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
};
+static const struct drm_display_mode arm_rtsm_mode[] = {
+ {
+ .clock = 65000,
+ .hdisplay = 1024,
+ .hsync_start = 1024 + 24,
+ .hsync_end = 1024 + 24 + 136,
+ .htotal = 1024 + 24 + 136 + 160,
+ .vdisplay = 768,
+ .vsync_start = 768 + 3,
+ .vsync_end = 768 + 3 + 6,
+ .vtotal = 768 + 3 + 6 + 29,
+ .vrefresh = 60,
+ .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
+ },
+};
+
+static const struct panel_desc arm_rtsm = {
+ .modes = arm_rtsm_mode,
+ .num_modes = 1,
+ .bpc = 8,
+ .size = {
+ .width = 400,
+ .height = 300,
+ },
+ .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
+};
+
static const struct of_device_id platform_of_match[] = {
{
.compatible = "ampire,am-480272h3tmqw-t01h",
@@ -2342,6 +2470,9 @@ static const struct of_device_id platform_of_match[] = {
.compatible = "ampire,am800480r3tmqwa1h",
.data = &ampire_am800480r3tmqwa1h,
}, {
+ .compatible = "arm,rtsm-display",
+ .data = &arm_rtsm,
+ }, {
.compatible = "auo,b101aw03",
.data = &auo_b101aw03,
}, {
@@ -2381,12 +2512,21 @@ static const struct of_device_id platform_of_match[] = {
.compatible = "avic,tm070ddh03",
.data = &avic_tm070ddh03,
}, {
+ .compatible = "bananapi,s070wv20-ct16",
+ .data = &bananapi_s070wv20_ct16,
+ }, {
.compatible = "boe,hv070wsa-100",
.data = &boe_hv070wsa
}, {
.compatible = "boe,nv101wxmn51",
.data = &boe_nv101wxmn51,
}, {
+ .compatible = "cdtech,s043wq26h-ct7",
+ .data = &cdtech_s043wq26h_ct7,
+ }, {
+ .compatible = "cdtech,s070wv95-ct16",
+ .data = &cdtech_s070wv95_ct16,
+ }, {
.compatible = "chunghwa,claa070wp03xg",
.data = &chunghwa_claa070wp03xg,
}, {
@@ -2402,6 +2542,9 @@ static const struct of_device_id platform_of_match[] = {
.compatible = "dlc,dlc0700yzg-1",
.data = &dlc_dlc0700yzg_1,
}, {
+ .compatible = "dlc,dlc1010gig",
+ .data = &dlc_dlc1010gig,
+ }, {
.compatible = "edt,et057090dhu",
.data = &edt_et057090dhu,
}, {
diff --git a/drivers/gpu/drm/panel/panel-truly-nt35597.c b/drivers/gpu/drm/panel/panel-truly-nt35597.c
new file mode 100644
index 000000000000..fc2a66c53db4
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-truly-nt35597.c
@@ -0,0 +1,675 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_mipi_dsi.h>
+
+#include <linux/gpio/consumer.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/regulator/consumer.h>
+
+#include <video/mipi_display.h>
+
+static const char * const regulator_names[] = {
+ "vdda",
+ "vdispp",
+ "vdispn",
+};
+
+static unsigned long const regulator_enable_loads[] = {
+ 62000,
+ 100000,
+ 100000,
+};
+
+static unsigned long const regulator_disable_loads[] = {
+ 80,
+ 100,
+ 100,
+};
+
+struct cmd_set {
+ u8 commands[4];
+ u8 size;
+};
+
+struct nt35597_config {
+ u32 width_mm;
+ u32 height_mm;
+ const char *panel_name;
+ const struct cmd_set *panel_on_cmds;
+ u32 num_on_cmds;
+ const struct drm_display_mode *dm;
+};
+
+struct truly_nt35597 {
+ struct device *dev;
+ struct drm_panel panel;
+
+ struct regulator_bulk_data supplies[ARRAY_SIZE(regulator_names)];
+
+ struct gpio_desc *reset_gpio;
+ struct gpio_desc *mode_gpio;
+
+ struct backlight_device *backlight;
+
+ struct mipi_dsi_device *dsi[2];
+
+ const struct nt35597_config *config;
+ bool prepared;
+ bool enabled;
+};
+
+static inline struct truly_nt35597 *panel_to_ctx(struct drm_panel *panel)
+{
+ return container_of(panel, struct truly_nt35597, panel);
+}
+
+static const struct cmd_set qcom_2k_panel_magic_cmds[] = {
+ /* CMD2_P0 */
+ { { 0xff, 0x20 }, 2 },
+ { { 0xfb, 0x01 }, 2 },
+ { { 0x00, 0x01 }, 2 },
+ { { 0x01, 0x55 }, 2 },
+ { { 0x02, 0x45 }, 2 },
+ { { 0x05, 0x40 }, 2 },
+ { { 0x06, 0x19 }, 2 },
+ { { 0x07, 0x1e }, 2 },
+ { { 0x0b, 0x73 }, 2 },
+ { { 0x0c, 0x73 }, 2 },
+ { { 0x0e, 0xb0 }, 2 },
+ { { 0x0f, 0xae }, 2 },
+ { { 0x11, 0xb8 }, 2 },
+ { { 0x13, 0x00 }, 2 },
+ { { 0x58, 0x80 }, 2 },
+ { { 0x59, 0x01 }, 2 },
+ { { 0x5a, 0x00 }, 2 },
+ { { 0x5b, 0x01 }, 2 },
+ { { 0x5c, 0x80 }, 2 },
+ { { 0x5d, 0x81 }, 2 },
+ { { 0x5e, 0x00 }, 2 },
+ { { 0x5f, 0x01 }, 2 },
+ { { 0x72, 0x11 }, 2 },
+ { { 0x68, 0x03 }, 2 },
+ /* CMD2_P4 */
+ { { 0xFF, 0x24 }, 2 },
+ { { 0xFB, 0x01 }, 2 },
+ { { 0x00, 0x1C }, 2 },
+ { { 0x01, 0x0B }, 2 },
+ { { 0x02, 0x0C }, 2 },
+ { { 0x03, 0x01 }, 2 },
+ { { 0x04, 0x0F }, 2 },
+ { { 0x05, 0x10 }, 2 },
+ { { 0x06, 0x10 }, 2 },
+ { { 0x07, 0x10 }, 2 },
+ { { 0x08, 0x89 }, 2 },
+ { { 0x09, 0x8A }, 2 },
+ { { 0x0A, 0x13 }, 2 },
+ { { 0x0B, 0x13 }, 2 },
+ { { 0x0C, 0x15 }, 2 },
+ { { 0x0D, 0x15 }, 2 },
+ { { 0x0E, 0x17 }, 2 },
+ { { 0x0F, 0x17 }, 2 },
+ { { 0x10, 0x1C }, 2 },
+ { { 0x11, 0x0B }, 2 },
+ { { 0x12, 0x0C }, 2 },
+ { { 0x13, 0x01 }, 2 },
+ { { 0x14, 0x0F }, 2 },
+ { { 0x15, 0x10 }, 2 },
+ { { 0x16, 0x10 }, 2 },
+ { { 0x17, 0x10 }, 2 },
+ { { 0x18, 0x89 }, 2 },
+ { { 0x19, 0x8A }, 2 },
+ { { 0x1A, 0x13 }, 2 },
+ { { 0x1B, 0x13 }, 2 },
+ { { 0x1C, 0x15 }, 2 },
+ { { 0x1D, 0x15 }, 2 },
+ { { 0x1E, 0x17 }, 2 },
+ { { 0x1F, 0x17 }, 2 },
+ /* STV */
+ { { 0x20, 0x40 }, 2 },
+ { { 0x21, 0x01 }, 2 },
+ { { 0x22, 0x00 }, 2 },
+ { { 0x23, 0x40 }, 2 },
+ { { 0x24, 0x40 }, 2 },
+ { { 0x25, 0x6D }, 2 },
+ { { 0x26, 0x40 }, 2 },
+ { { 0x27, 0x40 }, 2 },
+ /* Vend */
+ { { 0xE0, 0x00 }, 2 },
+ { { 0xDC, 0x21 }, 2 },
+ { { 0xDD, 0x22 }, 2 },
+ { { 0xDE, 0x07 }, 2 },
+ { { 0xDF, 0x07 }, 2 },
+ { { 0xE3, 0x6D }, 2 },
+ { { 0xE1, 0x07 }, 2 },
+ { { 0xE2, 0x07 }, 2 },
+ /* UD */
+ { { 0x29, 0xD8 }, 2 },
+ { { 0x2A, 0x2A }, 2 },
+ /* CLK */
+ { { 0x4B, 0x03 }, 2 },
+ { { 0x4C, 0x11 }, 2 },
+ { { 0x4D, 0x10 }, 2 },
+ { { 0x4E, 0x01 }, 2 },
+ { { 0x4F, 0x01 }, 2 },
+ { { 0x50, 0x10 }, 2 },
+ { { 0x51, 0x00 }, 2 },
+ { { 0x52, 0x80 }, 2 },
+ { { 0x53, 0x00 }, 2 },
+ { { 0x56, 0x00 }, 2 },
+ { { 0x54, 0x07 }, 2 },
+ { { 0x58, 0x07 }, 2 },
+ { { 0x55, 0x25 }, 2 },
+ /* Reset XDONB */
+ { { 0x5B, 0x43 }, 2 },
+ { { 0x5C, 0x00 }, 2 },
+ { { 0x5F, 0x73 }, 2 },
+ { { 0x60, 0x73 }, 2 },
+ { { 0x63, 0x22 }, 2 },
+ { { 0x64, 0x00 }, 2 },
+ { { 0x67, 0x08 }, 2 },
+ { { 0x68, 0x04 }, 2 },
+ /* Resolution:1440x2560 */
+ { { 0x72, 0x02 }, 2 },
+ /* mux */
+ { { 0x7A, 0x80 }, 2 },
+ { { 0x7B, 0x91 }, 2 },
+ { { 0x7C, 0xD8 }, 2 },
+ { { 0x7D, 0x60 }, 2 },
+ { { 0x7F, 0x15 }, 2 },
+ { { 0x75, 0x15 }, 2 },
+ /* ABOFF */
+ { { 0xB3, 0xC0 }, 2 },
+ { { 0xB4, 0x00 }, 2 },
+ { { 0xB5, 0x00 }, 2 },
+ /* Source EQ */
+ { { 0x78, 0x00 }, 2 },
+ { { 0x79, 0x00 }, 2 },
+ { { 0x80, 0x00 }, 2 },
+ { { 0x83, 0x00 }, 2 },
+ /* FP BP */
+ { { 0x93, 0x0A }, 2 },
+ { { 0x94, 0x0A }, 2 },
+ /* Inversion Type */
+ { { 0x8A, 0x00 }, 2 },
+ { { 0x9B, 0xFF }, 2 },
+ /* IMGSWAP =1 @PortSwap=1 */
+ { { 0x9D, 0xB0 }, 2 },
+ { { 0x9F, 0x63 }, 2 },
+ { { 0x98, 0x10 }, 2 },
+ /* FRM */
+ { { 0xEC, 0x00 }, 2 },
+ /* CMD1 */
+ { { 0xFF, 0x10 }, 2 },
+ /* VBP+VSA=,VFP = 10H */
+ { { 0x3B, 0x03, 0x0A, 0x0A }, 4 },
+ /* FTE on */
+ { { 0x35, 0x00 }, 2 },
+ /* EN_BK =1(auto black) */
+ { { 0xE5, 0x01 }, 2 },
+ /* CMD mode(10) VDO mode(03) */
+ { { 0xBB, 0x03 }, 2 },
+ /* Non Reload MTP */
+ { { 0xFB, 0x01 }, 2 },
+};
+
+static int truly_dcs_write(struct drm_panel *panel, u32 command)
+{
+ struct truly_nt35597 *ctx = panel_to_ctx(panel);
+ int i, ret;
+
+ for (i = 0; i < ARRAY_SIZE(ctx->dsi); i++) {
+ ret = mipi_dsi_dcs_write(ctx->dsi[i], command, NULL, 0);
+ if (ret < 0) {
+ DRM_DEV_ERROR(ctx->dev,
+ "cmd 0x%x failed for dsi = %d\n",
+ command, i);
+ }
+ }
+
+ return ret;
+}
+
+static int truly_dcs_write_buf(struct drm_panel *panel,
+ u32 size, const u8 *buf)
+{
+ struct truly_nt35597 *ctx = panel_to_ctx(panel);
+ int ret = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ctx->dsi); i++) {
+ ret = mipi_dsi_dcs_write_buffer(ctx->dsi[i], buf, size);
+ if (ret < 0) {
+ DRM_DEV_ERROR(ctx->dev,
+ "failed to tx cmd [%d], err: %d\n", i, ret);
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+static int truly_35597_power_on(struct truly_nt35597 *ctx)
+{
+ int ret, i;
+
+ for (i = 0; i < ARRAY_SIZE(ctx->supplies); i++) {
+ ret = regulator_set_load(ctx->supplies[i].consumer,
+ regulator_enable_loads[i]);
+ if (ret)
+ return ret;
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Reset sequence of truly panel requires the panel to be
+ * out of reset for 10ms, followed by being held in reset
+ * for 10ms and then out again
+ */
+ gpiod_set_value(ctx->reset_gpio, 0);
+ usleep_range(10000, 20000);
+ gpiod_set_value(ctx->reset_gpio, 1);
+ usleep_range(10000, 20000);
+ gpiod_set_value(ctx->reset_gpio, 0);
+
+ return 0;
+}
+
+static int truly_nt35597_power_off(struct truly_nt35597 *ctx)
+{
+ int ret = 0;
+ int i;
+
+ gpiod_set_value(ctx->reset_gpio, 1);
+
+ for (i = 0; i < ARRAY_SIZE(ctx->supplies); i++) {
+ ret = regulator_set_load(ctx->supplies[i].consumer,
+ regulator_disable_loads[i]);
+ if (ret) {
+ DRM_DEV_ERROR(ctx->dev,
+ "regulator_set_load failed %d\n", ret);
+ return ret;
+ }
+ }
+
+ ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
+ if (ret) {
+ DRM_DEV_ERROR(ctx->dev,
+ "regulator_bulk_disable failed %d\n", ret);
+ }
+ return ret;
+}
+
+static int truly_nt35597_disable(struct drm_panel *panel)
+{
+ struct truly_nt35597 *ctx = panel_to_ctx(panel);
+ int ret;
+
+ if (!ctx->enabled)
+ return 0;
+
+ if (ctx->backlight) {
+ ret = backlight_disable(ctx->backlight);
+ if (ret < 0)
+ DRM_DEV_ERROR(ctx->dev, "backlight disable failed %d\n",
+ ret);
+ }
+
+ ctx->enabled = false;
+ return 0;
+}
+
+static int truly_nt35597_unprepare(struct drm_panel *panel)
+{
+ struct truly_nt35597 *ctx = panel_to_ctx(panel);
+ int ret = 0;
+
+ if (!ctx->prepared)
+ return 0;
+
+ ctx->dsi[0]->mode_flags = 0;
+ ctx->dsi[1]->mode_flags = 0;
+
+ ret = truly_dcs_write(panel, MIPI_DCS_SET_DISPLAY_OFF);
+ if (ret < 0) {
+ DRM_DEV_ERROR(ctx->dev,
+ "set_display_off cmd failed ret = %d\n",
+ ret);
+ }
+
+ /* 120ms delay required here as per DCS spec */
+ msleep(120);
+
+ ret = truly_dcs_write(panel, MIPI_DCS_ENTER_SLEEP_MODE);
+ if (ret < 0) {
+ DRM_DEV_ERROR(ctx->dev,
+ "enter_sleep cmd failed ret = %d\n", ret);
+ }
+
+ ret = truly_nt35597_power_off(ctx);
+ if (ret < 0)
+ DRM_DEV_ERROR(ctx->dev, "power_off failed ret = %d\n", ret);
+
+ ctx->prepared = false;
+ return ret;
+}
+
+static int truly_nt35597_prepare(struct drm_panel *panel)
+{
+ struct truly_nt35597 *ctx = panel_to_ctx(panel);
+ int ret;
+ int i;
+ const struct cmd_set *panel_on_cmds;
+ const struct nt35597_config *config;
+ u32 num_cmds;
+
+ if (ctx->prepared)
+ return 0;
+
+ ret = truly_35597_power_on(ctx);
+ if (ret < 0)
+ return ret;
+
+ ctx->dsi[0]->mode_flags |= MIPI_DSI_MODE_LPM;
+ ctx->dsi[1]->mode_flags |= MIPI_DSI_MODE_LPM;
+
+ config = ctx->config;
+ panel_on_cmds = config->panel_on_cmds;
+ num_cmds = config->num_on_cmds;
+
+ for (i = 0; i < num_cmds; i++) {
+ ret = truly_dcs_write_buf(panel,
+ panel_on_cmds[i].size,
+ panel_on_cmds[i].commands);
+ if (ret < 0) {
+ DRM_DEV_ERROR(ctx->dev,
+ "cmd set tx failed i = %d ret = %d\n",
+ i, ret);
+ goto power_off;
+ }
+ }
+
+ ret = truly_dcs_write(panel, MIPI_DCS_EXIT_SLEEP_MODE);
+ if (ret < 0) {
+ DRM_DEV_ERROR(ctx->dev,
+ "exit_sleep_mode cmd failed ret = %d\n",
+ ret);
+ goto power_off;
+ }
+
+ /* Per DSI spec wait 120ms after sending exit sleep DCS command */
+ msleep(120);
+
+ ret = truly_dcs_write(panel, MIPI_DCS_SET_DISPLAY_ON);
+ if (ret < 0) {
+ DRM_DEV_ERROR(ctx->dev,
+ "set_display_on cmd failed ret = %d\n", ret);
+ goto power_off;
+ }
+
+ /* Per DSI spec wait 120ms after sending set_display_on DCS command */
+ msleep(120);
+
+ ctx->prepared = true;
+
+ return 0;
+
+power_off:
+ if (truly_nt35597_power_off(ctx))
+ DRM_DEV_ERROR(ctx->dev, "power_off failed\n");
+ return ret;
+}
+
+static int truly_nt35597_enable(struct drm_panel *panel)
+{
+ struct truly_nt35597 *ctx = panel_to_ctx(panel);
+ int ret;
+
+ if (ctx->enabled)
+ return 0;
+
+ if (ctx->backlight) {
+ ret = backlight_enable(ctx->backlight);
+ if (ret < 0)
+ DRM_DEV_ERROR(ctx->dev, "backlight enable failed %d\n",
+ ret);
+ }
+
+ ctx->enabled = true;
+
+ return 0;
+}
+
+static int truly_nt35597_get_modes(struct drm_panel *panel)
+{
+ struct drm_connector *connector = panel->connector;
+ struct truly_nt35597 *ctx = panel_to_ctx(panel);
+ struct drm_display_mode *mode;
+ const struct nt35597_config *config;
+
+ config = ctx->config;
+ mode = drm_mode_create(connector->dev);
+ if (!mode) {
+ DRM_DEV_ERROR(ctx->dev,
+ "failed to create a new display mode\n");
+ return 0;
+ }
+
+ connector->display_info.width_mm = config->width_mm;
+ connector->display_info.height_mm = config->height_mm;
+ drm_mode_copy(mode, config->dm);
+ mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+ drm_mode_probed_add(connector, mode);
+
+ return 1;
+}
+
+static const struct drm_panel_funcs truly_nt35597_drm_funcs = {
+ .disable = truly_nt35597_disable,
+ .unprepare = truly_nt35597_unprepare,
+ .prepare = truly_nt35597_prepare,
+ .enable = truly_nt35597_enable,
+ .get_modes = truly_nt35597_get_modes,
+};
+
+static int truly_nt35597_panel_add(struct truly_nt35597 *ctx)
+{
+ struct device *dev = ctx->dev;
+ int ret, i;
+ const struct nt35597_config *config;
+
+ config = ctx->config;
+ for (i = 0; i < ARRAY_SIZE(ctx->supplies); i++)
+ ctx->supplies[i].supply = regulator_names[i];
+
+ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
+ ctx->supplies);
+ if (ret < 0)
+ return ret;
+
+ ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(ctx->reset_gpio)) {
+ DRM_DEV_ERROR(dev, "cannot get reset gpio %ld\n",
+ PTR_ERR(ctx->reset_gpio));
+ return PTR_ERR(ctx->reset_gpio);
+ }
+
+ ctx->mode_gpio = devm_gpiod_get(dev, "mode", GPIOD_OUT_LOW);
+ if (IS_ERR(ctx->mode_gpio)) {
+ DRM_DEV_ERROR(dev, "cannot get mode gpio %ld\n",
+ PTR_ERR(ctx->mode_gpio));
+ return PTR_ERR(ctx->mode_gpio);
+ }
+
+ /* dual port */
+ gpiod_set_value(ctx->mode_gpio, 0);
+
+ drm_panel_init(&ctx->panel);
+ ctx->panel.dev = dev;
+ ctx->panel.funcs = &truly_nt35597_drm_funcs;
+ drm_panel_add(&ctx->panel);
+
+ return 0;
+}
+
+static const struct drm_display_mode qcom_sdm845_mtp_2k_mode = {
+ .name = "1440x2560",
+ .clock = 268316,
+ .hdisplay = 1440,
+ .hsync_start = 1440 + 200,
+ .hsync_end = 1440 + 200 + 32,
+ .htotal = 1440 + 200 + 32 + 64,
+ .vdisplay = 2560,
+ .vsync_start = 2560 + 8,
+ .vsync_end = 2560 + 8 + 1,
+ .vtotal = 2560 + 8 + 1 + 7,
+ .vrefresh = 60,
+ .flags = 0,
+};
+
+static const struct nt35597_config nt35597_dir = {
+ .width_mm = 74,
+ .height_mm = 131,
+ .panel_name = "qcom_sdm845_mtp_2k_panel",
+ .dm = &qcom_sdm845_mtp_2k_mode,
+ .panel_on_cmds = qcom_2k_panel_magic_cmds,
+ .num_on_cmds = ARRAY_SIZE(qcom_2k_panel_magic_cmds),
+};
+
+static int truly_nt35597_probe(struct mipi_dsi_device *dsi)
+{
+ struct device *dev = &dsi->dev;
+ struct truly_nt35597 *ctx;
+ struct mipi_dsi_device *dsi1_device;
+ struct device_node *dsi1;
+ struct mipi_dsi_host *dsi1_host;
+ struct mipi_dsi_device *dsi_dev;
+ int ret = 0;
+ int i;
+
+ const struct mipi_dsi_device_info info = {
+ .type = "trulynt35597",
+ .channel = 0,
+ .node = NULL,
+ };
+
+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+
+ if (!ctx)
+ return -ENOMEM;
+
+ /*
+ * This device represents itself as one with two input ports which are
+ * fed by the output ports of the two DSI controllers . The DSI0 is
+ * the master controller and has most of the panel related info in its
+ * child node.
+ */
+
+ ctx->config = of_device_get_match_data(dev);
+
+ if (!ctx->config) {
+ dev_err(dev, "missing device configuration\n");
+ return -ENODEV;
+ }
+
+ dsi1 = of_graph_get_remote_node(dsi->dev.of_node, 1, -1);
+ if (!dsi1) {
+ DRM_DEV_ERROR(dev,
+ "failed to get remote node for dsi1_device\n");
+ return -ENODEV;
+ }
+
+ dsi1_host = of_find_mipi_dsi_host_by_node(dsi1);
+ of_node_put(dsi1);
+ if (!dsi1_host) {
+ DRM_DEV_ERROR(dev, "failed to find dsi host\n");
+ return -EPROBE_DEFER;
+ }
+
+ /* register the second DSI device */
+ dsi1_device = mipi_dsi_device_register_full(dsi1_host, &info);
+ if (IS_ERR(dsi1_device)) {
+ DRM_DEV_ERROR(dev, "failed to create dsi device\n");
+ return PTR_ERR(dsi1_device);
+ }
+
+ mipi_dsi_set_drvdata(dsi, ctx);
+
+ ctx->dev = dev;
+ ctx->dsi[0] = dsi;
+ ctx->dsi[1] = dsi1_device;
+
+ ret = truly_nt35597_panel_add(ctx);
+ if (ret) {
+ DRM_DEV_ERROR(dev, "failed to add panel\n");
+ goto err_panel_add;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(ctx->dsi); i++) {
+ dsi_dev = ctx->dsi[i];
+ dsi_dev->lanes = 4;
+ dsi_dev->format = MIPI_DSI_FMT_RGB888;
+ dsi_dev->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM |
+ MIPI_DSI_CLOCK_NON_CONTINUOUS;
+ ret = mipi_dsi_attach(dsi_dev);
+ if (ret < 0) {
+ DRM_DEV_ERROR(dev,
+ "dsi attach failed i = %d\n", i);
+ goto err_dsi_attach;
+ }
+ }
+
+ return 0;
+
+err_dsi_attach:
+ drm_panel_remove(&ctx->panel);
+err_panel_add:
+ mipi_dsi_device_unregister(dsi1_device);
+ return ret;
+}
+
+static int truly_nt35597_remove(struct mipi_dsi_device *dsi)
+{
+ struct truly_nt35597 *ctx = mipi_dsi_get_drvdata(dsi);
+
+ if (ctx->dsi[0])
+ mipi_dsi_detach(ctx->dsi[0]);
+ if (ctx->dsi[1]) {
+ mipi_dsi_detach(ctx->dsi[1]);
+ mipi_dsi_device_unregister(ctx->dsi[1]);
+ }
+
+ drm_panel_remove(&ctx->panel);
+ return 0;
+}
+
+static const struct of_device_id truly_nt35597_of_match[] = {
+ {
+ .compatible = "truly,nt35597-2K-display",
+ .data = &nt35597_dir,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, truly_nt35597_of_match);
+
+static struct mipi_dsi_driver truly_nt35597_driver = {
+ .driver = {
+ .name = "panel-truly-nt35597",
+ .of_match_table = truly_nt35597_of_match,
+ },
+ .probe = truly_nt35597_probe,
+ .remove = truly_nt35597_remove,
+};
+module_mipi_dsi_driver(truly_nt35597_driver);
+
+MODULE_DESCRIPTION("Truly NT35597 DSI Panel Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/qxl/qxl_cmd.c b/drivers/gpu/drm/qxl/qxl_cmd.c
index 208af9f37914..dffc5093ff16 100644
--- a/drivers/gpu/drm/qxl/qxl_cmd.c
+++ b/drivers/gpu/drm/qxl/qxl_cmd.c
@@ -84,6 +84,7 @@ static int qxl_check_header(struct qxl_ring *ring)
int ret;
struct qxl_ring_header *header = &(ring->ring->header);
unsigned long flags;
+
spin_lock_irqsave(&ring->lock, flags);
ret = header->prod - header->cons < header->num_items;
if (ret == 0)
@@ -97,6 +98,7 @@ int qxl_check_idle(struct qxl_ring *ring)
int ret;
struct qxl_ring_header *header = &(ring->ring->header);
unsigned long flags;
+
spin_lock_irqsave(&ring->lock, flags);
ret = header->prod == header->cons;
spin_unlock_irqrestore(&ring->lock, flags);
@@ -110,6 +112,7 @@ int qxl_ring_push(struct qxl_ring *ring,
uint8_t *elt;
int idx, ret;
unsigned long flags;
+
spin_lock_irqsave(&ring->lock, flags);
if (header->prod - header->cons == header->num_items) {
header->notify_on_cons = header->cons + 1;
@@ -156,6 +159,7 @@ static bool qxl_ring_pop(struct qxl_ring *ring,
volatile uint8_t *ring_elt;
int idx;
unsigned long flags;
+
spin_lock_irqsave(&ring->lock, flags);
if (header->cons == header->prod) {
header->notify_on_prod = header->cons + 1;
@@ -365,7 +369,6 @@ void qxl_io_flush_surfaces(struct qxl_device *qdev)
wait_for_io_cmd(qdev, 0, QXL_IO_FLUSH_SURFACES_ASYNC);
}
-
void qxl_io_destroy_primary(struct qxl_device *qdev)
{
wait_for_io_cmd(qdev, 0, QXL_IO_DESTROY_PRIMARY_ASYNC);
@@ -373,7 +376,7 @@ void qxl_io_destroy_primary(struct qxl_device *qdev)
}
void qxl_io_create_primary(struct qxl_device *qdev,
- unsigned offset, struct qxl_bo *bo)
+ unsigned int offset, struct qxl_bo *bo)
{
struct qxl_surface_create *create;
diff --git a/drivers/gpu/drm/qxl/qxl_debugfs.c b/drivers/gpu/drm/qxl/qxl_debugfs.c
index 15c84068d3fb..118422549828 100644
--- a/drivers/gpu/drm/qxl/qxl_debugfs.c
+++ b/drivers/gpu/drm/qxl/qxl_debugfs.c
@@ -34,7 +34,6 @@
#include "qxl_drv.h"
#include "qxl_object.h"
-
#if defined(CONFIG_DEBUG_FS)
static int
qxl_debugfs_irq_received(struct seq_file *m, void *data)
@@ -102,9 +101,9 @@ qxl_debugfs_init(struct drm_minor *minor)
int qxl_debugfs_add_files(struct qxl_device *qdev,
struct drm_info_list *files,
- unsigned nfiles)
+ unsigned int nfiles)
{
- unsigned i;
+ unsigned int i;
for (i = 0; i < qdev->debugfs_count; i++) {
if (qdev->debugfs[i].files == files) {
diff --git a/drivers/gpu/drm/qxl/qxl_dev.h b/drivers/gpu/drm/qxl/qxl_dev.h
index 94c5aec71920..a0ee41632d7e 100644
--- a/drivers/gpu/drm/qxl/qxl_dev.h
+++ b/drivers/gpu/drm/qxl/qxl_dev.h
@@ -28,7 +28,6 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-
#ifndef H_QXL_DEV
#define H_QXL_DEV
diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
index 87d16a0ce01e..2ce9a8dcec84 100644
--- a/drivers/gpu/drm/qxl/qxl_display.c
+++ b/drivers/gpu/drm/qxl/qxl_display.c
@@ -253,12 +253,13 @@ static struct mode_size {
};
static int qxl_add_common_modes(struct drm_connector *connector,
- unsigned pwidth,
- unsigned pheight)
+ unsigned int pwidth,
+ unsigned int pheight)
{
struct drm_device *dev = connector->dev;
struct drm_display_mode *mode = NULL;
int i;
+
for (i = 0; i < ARRAY_SIZE(common_modes); i++) {
mode = drm_cvt_mode(dev, common_modes[i].w, common_modes[i].h,
60, false, false, false);
@@ -315,6 +316,7 @@ static void qxl_crtc_update_monitors_config(struct drm_crtc *crtc,
oldcount = qdev->monitors_config->count;
if (crtc->state->active) {
struct drm_display_mode *mode = &crtc->mode;
+
head.width = mode->hdisplay;
head.height = mode->vdisplay;
head.x = crtc->x;
@@ -391,9 +393,9 @@ static const struct drm_crtc_funcs qxl_crtc_funcs = {
static int qxl_framebuffer_surface_dirty(struct drm_framebuffer *fb,
struct drm_file *file_priv,
- unsigned flags, unsigned color,
+ unsigned int flags, unsigned int color,
struct drm_clip_rect *clips,
- unsigned num_clips)
+ unsigned int num_clips)
{
/* TODO: vmwgfx where this was cribbed from had locking. Why? */
struct qxl_device *qdev = fb->dev->dev_private;
@@ -917,8 +919,8 @@ free_mem:
static int qxl_conn_get_modes(struct drm_connector *connector)
{
- unsigned pwidth = 1024;
- unsigned pheight = 768;
+ unsigned int pwidth = 1024;
+ unsigned int pheight = 768;
int ret = 0;
ret = qxl_add_monitors_config_modes(connector, &pwidth, &pheight);
@@ -938,8 +940,8 @@ static enum drm_mode_status qxl_conn_mode_valid(struct drm_connector *connector,
/* TODO: is this called for user defined modes? (xrandr --add-mode)
* TODO: check that the mode fits in the framebuffer */
- if(qdev->monitors_config_width == mode->hdisplay &&
- qdev->monitors_config_height == mode->vdisplay)
+ if (qdev->monitors_config_width == mode->hdisplay &&
+ qdev->monitors_config_height == mode->vdisplay)
return MODE_OK;
for (i = 0; i < ARRAY_SIZE(common_modes); i++) {
@@ -958,7 +960,6 @@ static struct drm_encoder *qxl_best_encoder(struct drm_connector *connector)
return &qxl_output->enc;
}
-
static const struct drm_encoder_helper_funcs qxl_enc_helper_funcs = {
};
diff --git a/drivers/gpu/drm/qxl/qxl_draw.c b/drivers/gpu/drm/qxl/qxl_draw.c
index cc5b32e749ce..c34e45662965 100644
--- a/drivers/gpu/drm/qxl/qxl_draw.c
+++ b/drivers/gpu/drm/qxl/qxl_draw.c
@@ -25,7 +25,7 @@
static int alloc_clips(struct qxl_device *qdev,
struct qxl_release *release,
- unsigned num_clips,
+ unsigned int num_clips,
struct qxl_bo **clips_bo)
{
int size = sizeof(struct qxl_clip_rects) + sizeof(struct qxl_rect) * num_clips;
@@ -37,7 +37,7 @@ static int alloc_clips(struct qxl_device *qdev,
* the qxl_clip_rects. This is *not* the same as the memory allocated
* on the device, it is offset to qxl_clip_rects.chunk.data */
static struct qxl_rect *drawable_set_clipping(struct qxl_device *qdev,
- unsigned num_clips,
+ unsigned int num_clips,
struct qxl_bo *clips_bo)
{
struct qxl_clip_rects *dev_clips;
@@ -168,6 +168,7 @@ void qxl_draw_opaque_fb(const struct qxl_fb_image *qxl_fb_image,
int ret;
struct qxl_drm_image *dimage;
struct qxl_bo *palette_bo = NULL;
+
if (stride == 0)
stride = depth * width / 8;
@@ -214,6 +215,7 @@ void qxl_draw_opaque_fb(const struct qxl_fb_image *qxl_fb_image,
if (depth == 1) {
void *ptr;
+
ret = qxl_palette_create_1bit(palette_bo, release, qxl_fb_image);
ptr = qxl_bo_kmap_atomic_page(qdev, dimage->bo, 0);
@@ -264,9 +266,9 @@ out_free_drawable:
void qxl_draw_dirty_fb(struct qxl_device *qdev,
struct drm_framebuffer *fb,
struct qxl_bo *bo,
- unsigned flags, unsigned color,
+ unsigned int flags, unsigned int color,
struct drm_clip_rect *clips,
- unsigned num_clips, int inc)
+ unsigned int num_clips, int inc)
{
/*
* TODO: if flags & DRM_MODE_FB_DIRTY_ANNOTATE_FILL then we should
@@ -340,7 +342,6 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev,
if (ret)
goto out_release_backoff;
-
ret = qxl_image_init(qdev, release, dimage, surface_base,
left, top, width, height, depth, stride);
qxl_bo_kunmap(bo);
diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h
index 8ff70a7281a7..13a0254b59a1 100644
--- a/drivers/gpu/drm/qxl/qxl_drv.h
+++ b/drivers/gpu/drm/qxl/qxl_drv.h
@@ -23,7 +23,6 @@
* Alon Levy
*/
-
#ifndef QXL_DRV_H
#define QXL_DRV_H
@@ -83,16 +82,16 @@ struct qxl_bo {
struct ttm_placement placement;
struct ttm_buffer_object tbo;
struct ttm_bo_kmap_obj kmap;
- unsigned pin_count;
+ unsigned int pin_count;
void *kptr;
int type;
/* Constant after initialization */
struct drm_gem_object gem_base;
- bool is_primary; /* is this now a primary surface */
- bool is_dumb;
+ unsigned int is_primary:1; /* is this now a primary surface */
+ unsigned int is_dumb:1;
struct qxl_bo *shadow;
- bool hw_surf_alloc;
+ unsigned int hw_surf_alloc:1;
struct qxl_surface surf;
uint32_t surface_id;
struct qxl_release *surf_create;
@@ -127,13 +126,9 @@ struct qxl_output {
#define drm_encoder_to_qxl_output(x) container_of(x, struct qxl_output, enc)
struct qxl_mman {
- struct ttm_bo_global_ref bo_global_ref;
- struct drm_global_reference mem_global_ref;
- bool mem_global_referenced;
struct ttm_bo_device bdev;
};
-
struct qxl_memslot {
uint8_t generation;
uint64_t start_phys_addr;
@@ -191,12 +186,12 @@ struct qxl_draw_fill {
*/
struct qxl_debugfs {
struct drm_info_list *files;
- unsigned num_files;
+ unsigned int num_files;
};
int qxl_debugfs_add_files(struct qxl_device *rdev,
struct drm_info_list *files,
- unsigned nfiles);
+ unsigned int nfiles);
int qxl_debugfs_fence_init(struct qxl_device *rdev);
struct qxl_device;
@@ -231,7 +226,7 @@ struct qxl_device {
struct qxl_ram_header *ram_header;
- bool primary_created;
+ unsigned int primary_created:1;
struct qxl_memslot *mem_slots;
uint8_t n_mem_slots;
@@ -254,7 +249,7 @@ struct qxl_device {
atomic_t irq_received_display;
atomic_t irq_received_cursor;
atomic_t irq_received_io_cmd;
- unsigned irq_received_error;
+ unsigned int irq_received_error;
wait_queue_head_t display_event;
wait_queue_head_t cursor_event;
wait_queue_head_t io_cmd_event;
@@ -262,7 +257,7 @@ struct qxl_device {
/* debugfs */
struct qxl_debugfs debugfs[QXL_DEBUGFS_MAX_COMPONENTS];
- unsigned debugfs_count;
+ unsigned int debugfs_count;
struct mutex update_area_mutex;
@@ -372,7 +367,6 @@ int qxl_mode_dumb_mmap(struct drm_file *filp,
struct drm_device *dev,
uint32_t handle, uint64_t *offset_p);
-
/* qxl ttm */
int qxl_ttm_init(struct qxl_device *qdev);
void qxl_ttm_fini(struct qxl_device *qdev);
@@ -398,7 +392,7 @@ void qxl_update_screen(struct qxl_device *qxl);
/* qxl io operations (qxl_cmd.c) */
void qxl_io_create_primary(struct qxl_device *qdev,
- unsigned offset,
+ unsigned int offset,
struct qxl_bo *bo);
void qxl_io_destroy_primary(struct qxl_device *qdev);
void qxl_io_memslot_add(struct qxl_device *qdev, uint8_t id);
@@ -449,9 +443,9 @@ void qxl_draw_opaque_fb(const struct qxl_fb_image *qxl_fb_image,
void qxl_draw_dirty_fb(struct qxl_device *qdev,
struct drm_framebuffer *fb,
struct qxl_bo *bo,
- unsigned flags, unsigned color,
+ unsigned int flags, unsigned int color,
struct drm_clip_rect *clips,
- unsigned num_clips, int inc);
+ unsigned int num_clips, int inc);
void qxl_draw_fill(struct qxl_draw_fill *qxl_draw_fill_rec);
@@ -496,7 +490,7 @@ bool qxl_fbdev_qobj_is_fb(struct qxl_device *qdev, struct qxl_bo *qobj);
int qxl_debugfs_add_files(struct qxl_device *qdev,
struct drm_info_list *files,
- unsigned nfiles);
+ unsigned int nfiles);
int qxl_surface_id_alloc(struct qxl_device *qdev,
struct qxl_bo *surf);
diff --git a/drivers/gpu/drm/qxl/qxl_dumb.c b/drivers/gpu/drm/qxl/qxl_dumb.c
index c666b89eed5d..e3765739c396 100644
--- a/drivers/gpu/drm/qxl/qxl_dumb.c
+++ b/drivers/gpu/drm/qxl/qxl_dumb.c
@@ -38,6 +38,7 @@ int qxl_mode_dumb_create(struct drm_file *file_priv,
int r;
struct qxl_surface surf;
uint32_t pitch, format;
+
pitch = args->width * ((args->bpp + 1) / 8);
args->size = pitch * args->height;
args->size = ALIGN(args->size, PAGE_SIZE);
@@ -52,7 +53,7 @@ int qxl_mode_dumb_create(struct drm_file *file_priv,
default:
return -EINVAL;
}
-
+
surf.width = args->width;
surf.height = args->height;
surf.stride = pitch;
diff --git a/drivers/gpu/drm/qxl/qxl_fb.c b/drivers/gpu/drm/qxl/qxl_fb.c
index 2294b7f14fdf..7e047c985ea6 100644
--- a/drivers/gpu/drm/qxl/qxl_fb.c
+++ b/drivers/gpu/drm/qxl/qxl_fb.c
@@ -134,9 +134,9 @@ out_unref:
*/
static int qxlfb_framebuffer_dirty(struct drm_framebuffer *fb,
struct drm_file *file_priv,
- unsigned flags, unsigned color,
+ unsigned int flags, unsigned int color,
struct drm_clip_rect *clips,
- unsigned num_clips)
+ unsigned int num_clips)
{
struct qxl_device *qdev = fb->dev->dev_private;
struct fb_info *info = qdev->fb_helper.fbdev;
diff --git a/drivers/gpu/drm/qxl/qxl_image.c b/drivers/gpu/drm/qxl/qxl_image.c
index 7fbcc35e8ad3..43688ecdd8a0 100644
--- a/drivers/gpu/drm/qxl/qxl_image.c
+++ b/drivers/gpu/drm/qxl/qxl_image.c
@@ -136,6 +136,7 @@ qxl_image_init_helper(struct qxl_device *qdev,
int remain;
int page;
int size;
+
if (stride == linesize && chunk_stride == stride) {
remain = linesize * height;
page = 0;
@@ -162,7 +163,8 @@ qxl_image_init_helper(struct qxl_device *qdev,
page++;
}
} else {
- unsigned page_base, page_offset, out_offset;
+ unsigned int page_base, page_offset, out_offset;
+
for (i = 0 ; i < height ; ++i) {
i_data = (void *)data + i * stride;
remain = linesize;
diff --git a/drivers/gpu/drm/qxl/qxl_ioctl.c b/drivers/gpu/drm/qxl/qxl_ioctl.c
index 6cc9f3367fa0..6e828158bcb0 100644
--- a/drivers/gpu/drm/qxl/qxl_ioctl.c
+++ b/drivers/gpu/drm/qxl/qxl_ioctl.c
@@ -85,6 +85,7 @@ static void
apply_reloc(struct qxl_device *qdev, struct qxl_reloc_info *info)
{
void *reloc_page;
+
reloc_page = qxl_bo_kmap_atomic_page(qdev, info->dst_bo, info->dst_offset & PAGE_MASK);
*(uint64_t *)(reloc_page + (info->dst_offset & ~PAGE_MASK)) = qxl_bo_physical_address(qdev,
info->src_bo,
@@ -189,6 +190,7 @@ static int qxl_process_single_command(struct qxl_device *qdev,
{
struct qxl_drawable *draw = fb_cmd;
+
draw->mm_time = qdev->rom->mm_clock;
}
diff --git a/drivers/gpu/drm/qxl/qxl_kms.c b/drivers/gpu/drm/qxl/qxl_kms.c
index e25c589d5f50..f6975d7c7d10 100644
--- a/drivers/gpu/drm/qxl/qxl_kms.c
+++ b/drivers/gpu/drm/qxl/qxl_kms.c
@@ -92,6 +92,7 @@ void qxl_reinit_memslots(struct qxl_device *qdev)
static void qxl_gc_work(struct work_struct *work)
{
struct qxl_device *qdev = container_of(work, struct qxl_device, gc_work);
+
qxl_garbage_collect(qdev);
}
@@ -284,7 +285,6 @@ int qxl_device_init(struct qxl_device *qdev,
(unsigned long)qdev->surfaceram_base,
(unsigned long)qdev->surfaceram_size);
-
INIT_WORK(&qdev->gc_work, qxl_gc_work);
return 0;
diff --git a/drivers/gpu/drm/qxl/qxl_object.c b/drivers/gpu/drm/qxl/qxl_object.c
index 6a30196e9d6c..f67a3c535afb 100644
--- a/drivers/gpu/drm/qxl/qxl_object.c
+++ b/drivers/gpu/drm/qxl/qxl_object.c
@@ -54,7 +54,7 @@ void qxl_ttm_placement_from_domain(struct qxl_bo *qbo, u32 domain, bool pinned)
{
u32 c = 0;
u32 pflag = pinned ? TTM_PL_FLAG_NO_EVICT : 0;
- unsigned i;
+ unsigned int i;
qbo->placement.placement = qbo->placements;
qbo->placement.busy_placement = qbo->placements;
@@ -74,7 +74,6 @@ void qxl_ttm_placement_from_domain(struct qxl_bo *qbo, u32 domain, bool pinned)
}
}
-
int qxl_bo_create(struct qxl_device *qdev,
unsigned long size, bool kernel, bool pinned, u32 domain,
struct qxl_surface *surf,
@@ -266,7 +265,6 @@ static int __qxl_bo_unpin(struct qxl_bo *bo)
return r;
}
-
/*
* Reserve the BO before pinning the object. If the BO was reserved
* beforehand, use the internal version directly __qxl_bo_pin.
@@ -335,6 +333,7 @@ void qxl_bo_fini(struct qxl_device *qdev)
int qxl_bo_check_id(struct qxl_device *qdev, struct qxl_bo *bo)
{
int ret;
+
if (bo->type == QXL_GEM_DOMAIN_SURFACE && bo->surface_id == 0) {
/* allocate a surface id for this surface now */
ret = qxl_surface_id_alloc(qdev, bo);
diff --git a/drivers/gpu/drm/qxl/qxl_object.h b/drivers/gpu/drm/qxl/qxl_object.h
index 0374fd93f4d6..b40fc9a10406 100644
--- a/drivers/gpu/drm/qxl/qxl_object.h
+++ b/drivers/gpu/drm/qxl/qxl_object.h
@@ -35,6 +35,7 @@ static inline int qxl_bo_reserve(struct qxl_bo *bo, bool no_wait)
if (unlikely(r != 0)) {
if (r != -ERESTARTSYS) {
struct drm_device *ddev = bo->gem_base.dev;
+
dev_err(ddev->dev, "%p reserve failed\n", bo);
}
return r;
@@ -71,6 +72,7 @@ static inline int qxl_bo_wait(struct qxl_bo *bo, u32 *mem_type,
if (unlikely(r != 0)) {
if (r != -ERESTARTSYS) {
struct drm_device *ddev = bo->gem_base.dev;
+
dev_err(ddev->dev, "%p reserve failed for wait\n",
bo);
}
diff --git a/drivers/gpu/drm/qxl/qxl_prime.c b/drivers/gpu/drm/qxl/qxl_prime.c
index 9f029dda1f07..a55dece118b2 100644
--- a/drivers/gpu/drm/qxl/qxl_prime.c
+++ b/drivers/gpu/drm/qxl/qxl_prime.c
@@ -38,7 +38,6 @@ void qxl_gem_prime_unpin(struct drm_gem_object *obj)
WARN_ONCE(1, "not implemented");
}
-
struct sg_table *qxl_gem_prime_get_sg_table(struct drm_gem_object *obj)
{
WARN_ONCE(1, "not implemented");
diff --git a/drivers/gpu/drm/qxl/qxl_release.c b/drivers/gpu/drm/qxl/qxl_release.c
index e37f0097f744..3813ec198900 100644
--- a/drivers/gpu/drm/qxl/qxl_release.c
+++ b/drivers/gpu/drm/qxl/qxl_release.c
@@ -234,7 +234,7 @@ static int qxl_release_validate_bo(struct qxl_bo *bo)
return ret;
}
- ret = reservation_object_reserve_shared(bo->tbo.resv);
+ ret = reservation_object_reserve_shared(bo->tbo.resv, 1);
if (ret)
return ret;
@@ -282,7 +282,6 @@ void qxl_release_backoff_reserve_list(struct qxl_release *release)
ttm_eu_backoff_reservation(&release->ticket, &release->bos);
}
-
int qxl_alloc_surface_release_reserved(struct qxl_device *qdev,
enum qxl_surface_cmd_type surface_cmd_type,
struct qxl_release *create_rel,
diff --git a/drivers/gpu/drm/qxl/qxl_ttm.c b/drivers/gpu/drm/qxl/qxl_ttm.c
index 86a1fb32f6db..886f61e94f24 100644
--- a/drivers/gpu/drm/qxl/qxl_ttm.c
+++ b/drivers/gpu/drm/qxl/qxl_ttm.c
@@ -46,62 +46,6 @@ static struct qxl_device *qxl_get_qdev(struct ttm_bo_device *bdev)
return qdev;
}
-static int qxl_ttm_mem_global_init(struct drm_global_reference *ref)
-{
- return ttm_mem_global_init(ref->object);
-}
-
-static void qxl_ttm_mem_global_release(struct drm_global_reference *ref)
-{
- ttm_mem_global_release(ref->object);
-}
-
-static int qxl_ttm_global_init(struct qxl_device *qdev)
-{
- struct drm_global_reference *global_ref;
- int r;
-
- qdev->mman.mem_global_referenced = false;
- global_ref = &qdev->mman.mem_global_ref;
- global_ref->global_type = DRM_GLOBAL_TTM_MEM;
- global_ref->size = sizeof(struct ttm_mem_global);
- global_ref->init = &qxl_ttm_mem_global_init;
- global_ref->release = &qxl_ttm_mem_global_release;
-
- r = drm_global_item_ref(global_ref);
- if (r != 0) {
- DRM_ERROR("Failed setting up TTM memory accounting "
- "subsystem.\n");
- return r;
- }
-
- qdev->mman.bo_global_ref.mem_glob =
- qdev->mman.mem_global_ref.object;
- global_ref = &qdev->mman.bo_global_ref.ref;
- global_ref->global_type = DRM_GLOBAL_TTM_BO;
- global_ref->size = sizeof(struct ttm_bo_global);
- global_ref->init = &ttm_bo_global_init;
- global_ref->release = &ttm_bo_global_release;
- r = drm_global_item_ref(global_ref);
- if (r != 0) {
- DRM_ERROR("Failed setting up TTM BO subsystem.\n");
- drm_global_item_unref(&qdev->mman.mem_global_ref);
- return r;
- }
-
- qdev->mman.mem_global_referenced = true;
- return 0;
-}
-
-static void qxl_ttm_global_fini(struct qxl_device *qdev)
-{
- if (qdev->mman.mem_global_referenced) {
- drm_global_item_unref(&qdev->mman.bo_global_ref.ref);
- drm_global_item_unref(&qdev->mman.mem_global_ref);
- qdev->mman.mem_global_referenced = false;
- }
-}
-
static struct vm_operations_struct qxl_ttm_vm_ops;
static const struct vm_operations_struct *ttm_vm_ops;
@@ -174,7 +118,7 @@ static int qxl_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
man->default_caching = TTM_PL_FLAG_CACHED;
break;
default:
- DRM_ERROR("Unsupported memory type %u\n", (unsigned)type);
+ DRM_ERROR("Unsupported memory type %u\n", (unsigned int)type);
return -EINVAL;
}
return 0;
@@ -331,7 +275,6 @@ static int qxl_bo_move(struct ttm_buffer_object *bo, bool evict,
if (ret)
return ret;
-
if (old_mem->mem_type == TTM_PL_SYSTEM && bo->ttm == NULL) {
qxl_move_null(bo, new_mem);
return 0;
@@ -373,12 +316,8 @@ int qxl_ttm_init(struct qxl_device *qdev)
int r;
int num_io_pages; /* != rom->num_io_pages, we include surface0 */
- r = qxl_ttm_global_init(qdev);
- if (r)
- return r;
/* No others user of address space so set it to 0 */
r = ttm_bo_device_init(&qdev->mman.bdev,
- qdev->mman.bo_global_ref.ref.object,
&qxl_bo_driver,
qdev->ddev.anon_inode->i_mapping,
DRM_FILE_PAGE_OFFSET, 0);
@@ -401,11 +340,11 @@ int qxl_ttm_init(struct qxl_device *qdev)
return r;
}
DRM_INFO("qxl: %uM of VRAM memory size\n",
- (unsigned)qdev->vram_size / (1024 * 1024));
+ (unsigned int)qdev->vram_size / (1024 * 1024));
DRM_INFO("qxl: %luM of IO pages memory ready (VRAM domain)\n",
- ((unsigned)num_io_pages * PAGE_SIZE) / (1024 * 1024));
+ ((unsigned int)num_io_pages * PAGE_SIZE) / (1024 * 1024));
DRM_INFO("qxl: %uM of Surface memory size\n",
- (unsigned)qdev->surfaceram_size / (1024 * 1024));
+ (unsigned int)qdev->surfaceram_size / (1024 * 1024));
return 0;
}
@@ -414,11 +353,9 @@ void qxl_ttm_fini(struct qxl_device *qdev)
ttm_bo_clean_mm(&qdev->mman.bdev, TTM_PL_VRAM);
ttm_bo_clean_mm(&qdev->mman.bdev, TTM_PL_PRIV);
ttm_bo_device_release(&qdev->mman.bdev);
- qxl_ttm_global_fini(qdev);
DRM_INFO("qxl: ttm finalized\n");
}
-
#define QXL_DEBUGFS_MEM_TYPES 2
#if defined(CONFIG_DEBUG_FS)
@@ -443,7 +380,7 @@ int qxl_ttm_debugfs_init(struct qxl_device *qdev)
#if defined(CONFIG_DEBUG_FS)
static struct drm_info_list qxl_mem_types_list[QXL_DEBUGFS_MEM_TYPES];
static char qxl_mem_types_names[QXL_DEBUGFS_MEM_TYPES][32];
- unsigned i;
+ unsigned int i;
for (i = 0; i < QXL_DEBUGFS_MEM_TYPES; i++) {
if (i == 0)
diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c
index 21161aa8acbf..652126fd6dd4 100644
--- a/drivers/gpu/drm/radeon/r300.c
+++ b/drivers/gpu/drm/radeon/r300.c
@@ -814,7 +814,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
((idx_value >> 21) & 0xF));
return -EINVAL;
}
- /* Pass through. */
+ /* Fall through. */
case 6:
track->cb[i].cpp = 4;
break;
@@ -965,7 +965,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
return -EINVAL;
}
/* The same rules apply as for DXT3/5. */
- /* Pass through. */
+ /* Fall through. */
case R300_TX_FORMAT_DXT3:
case R300_TX_FORMAT_DXT5:
track->textures[i].cpp = 1;
diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c
index 45e1d4e60759..2318d9e3ed96 100644
--- a/drivers/gpu/drm/radeon/r420.c
+++ b/drivers/gpu/drm/radeon/r420.c
@@ -109,6 +109,7 @@ void r420_pipes_init(struct radeon_device *rdev)
default:
/* force to 1 pipe */
num_pipes = 1;
+ /* fall through */
case 1:
tmp = (0 << 1);
break;
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 1a6f6edb3515..32808e50be12 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -448,10 +448,7 @@ struct radeon_surface_reg {
* TTM.
*/
struct radeon_mman {
- struct ttm_bo_global_ref bo_global_ref;
- struct drm_global_reference mem_global_ref;
struct ttm_bo_device bdev;
- bool mem_global_referenced;
bool initialized;
#if defined(CONFIG_DEBUG_FS)
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_tv.c b/drivers/gpu/drm/radeon/radeon_legacy_tv.c
index 4278272e3191..3dae2c4dec71 100644
--- a/drivers/gpu/drm/radeon/radeon_legacy_tv.c
+++ b/drivers/gpu/drm/radeon/radeon_legacy_tv.c
@@ -421,24 +421,14 @@ static void radeon_legacy_write_tv_restarts(struct radeon_encoder *radeon_encode
static bool radeon_legacy_tv_init_restarts(struct drm_encoder *encoder)
{
- struct drm_device *dev = encoder->dev;
- struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv;
- struct radeon_crtc *radeon_crtc;
int restart;
unsigned int h_total, v_total, f_total;
int v_offset, h_offset;
u16 p1, p2, h_inc;
bool h_changed;
const struct radeon_tv_mode_constants *const_ptr;
- struct radeon_pll *pll;
-
- radeon_crtc = to_radeon_crtc(radeon_encoder->base.crtc);
- if (radeon_crtc->crtc_id == 1)
- pll = &rdev->clock.p2pll;
- else
- pll = &rdev->clock.p1pll;
const_ptr = radeon_legacy_tv_get_std_mode(radeon_encoder, NULL);
if (!const_ptr)
diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c
index 92f6d4002eea..833e909706a9 100644
--- a/drivers/gpu/drm/radeon/radeon_object.c
+++ b/drivers/gpu/drm/radeon/radeon_object.c
@@ -314,11 +314,9 @@ struct radeon_bo *radeon_bo_ref(struct radeon_bo *bo)
void radeon_bo_unref(struct radeon_bo **bo)
{
struct ttm_buffer_object *tbo;
- struct radeon_device *rdev;
if ((*bo) == NULL)
return;
- rdev = (*bo)->rdev;
tbo = &((*bo)->tbo);
ttm_bo_put(tbo);
*bo = NULL;
diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
index cbb67e9ffb3a..9920a6fc11bf 100644
--- a/drivers/gpu/drm/radeon/radeon_ttm.c
+++ b/drivers/gpu/drm/radeon/radeon_ttm.c
@@ -60,65 +60,6 @@ static struct radeon_device *radeon_get_rdev(struct ttm_bo_device *bdev)
return rdev;
}
-
-/*
- * Global memory.
- */
-static int radeon_ttm_mem_global_init(struct drm_global_reference *ref)
-{
- return ttm_mem_global_init(ref->object);
-}
-
-static void radeon_ttm_mem_global_release(struct drm_global_reference *ref)
-{
- ttm_mem_global_release(ref->object);
-}
-
-static int radeon_ttm_global_init(struct radeon_device *rdev)
-{
- struct drm_global_reference *global_ref;
- int r;
-
- rdev->mman.mem_global_referenced = false;
- global_ref = &rdev->mman.mem_global_ref;
- global_ref->global_type = DRM_GLOBAL_TTM_MEM;
- global_ref->size = sizeof(struct ttm_mem_global);
- global_ref->init = &radeon_ttm_mem_global_init;
- global_ref->release = &radeon_ttm_mem_global_release;
- r = drm_global_item_ref(global_ref);
- if (r != 0) {
- DRM_ERROR("Failed setting up TTM memory accounting "
- "subsystem.\n");
- return r;
- }
-
- rdev->mman.bo_global_ref.mem_glob =
- rdev->mman.mem_global_ref.object;
- global_ref = &rdev->mman.bo_global_ref.ref;
- global_ref->global_type = DRM_GLOBAL_TTM_BO;
- global_ref->size = sizeof(struct ttm_bo_global);
- global_ref->init = &ttm_bo_global_init;
- global_ref->release = &ttm_bo_global_release;
- r = drm_global_item_ref(global_ref);
- if (r != 0) {
- DRM_ERROR("Failed setting up TTM BO subsystem.\n");
- drm_global_item_unref(&rdev->mman.mem_global_ref);
- return r;
- }
-
- rdev->mman.mem_global_referenced = true;
- return 0;
-}
-
-static void radeon_ttm_global_fini(struct radeon_device *rdev)
-{
- if (rdev->mman.mem_global_referenced) {
- drm_global_item_unref(&rdev->mman.bo_global_ref.ref);
- drm_global_item_unref(&rdev->mman.mem_global_ref);
- rdev->mman.mem_global_referenced = false;
- }
-}
-
static int radeon_invalidate_caches(struct ttm_bo_device *bdev, uint32_t flags)
{
return 0;
@@ -847,13 +788,8 @@ int radeon_ttm_init(struct radeon_device *rdev)
{
int r;
- r = radeon_ttm_global_init(rdev);
- if (r) {
- return r;
- }
/* No others user of address space so set it to 0 */
r = ttm_bo_device_init(&rdev->mman.bdev,
- rdev->mman.bo_global_ref.ref.object,
&radeon_bo_driver,
rdev->ddev->anon_inode->i_mapping,
DRM_FILE_PAGE_OFFSET,
@@ -925,7 +861,6 @@ void radeon_ttm_fini(struct radeon_device *rdev)
ttm_bo_clean_mm(&rdev->mman.bdev, TTM_PL_TT);
ttm_bo_device_release(&rdev->mman.bdev);
radeon_gart_fini(rdev);
- radeon_ttm_global_fini(rdev);
rdev->mman.initialized = false;
DRM_INFO("radeon: ttm finalized\n");
}
diff --git a/drivers/gpu/drm/radeon/radeon_vm.c b/drivers/gpu/drm/radeon/radeon_vm.c
index 7f1a9c787bd1..fed11ece0de6 100644
--- a/drivers/gpu/drm/radeon/radeon_vm.c
+++ b/drivers/gpu/drm/radeon/radeon_vm.c
@@ -831,7 +831,7 @@ static int radeon_vm_update_ptes(struct radeon_device *rdev,
int r;
radeon_sync_resv(rdev, &ib->sync, pt->tbo.resv, true);
- r = reservation_object_reserve_shared(pt->tbo.resv);
+ r = reservation_object_reserve_shared(pt->tbo.resv, 1);
if (r)
return r;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
index 084f58df4a8c..7015974c247a 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
@@ -404,32 +404,15 @@ static struct drm_driver rcar_du_driver = {
static int rcar_du_pm_suspend(struct device *dev)
{
struct rcar_du_device *rcdu = dev_get_drvdata(dev);
- struct drm_atomic_state *state;
- drm_kms_helper_poll_disable(rcdu->ddev);
- drm_fbdev_cma_set_suspend_unlocked(rcdu->fbdev, true);
-
- state = drm_atomic_helper_suspend(rcdu->ddev);
- if (IS_ERR(state)) {
- drm_fbdev_cma_set_suspend_unlocked(rcdu->fbdev, false);
- drm_kms_helper_poll_enable(rcdu->ddev);
- return PTR_ERR(state);
- }
-
- rcdu->suspend_state = state;
-
- return 0;
+ return drm_mode_config_helper_suspend(rcdu->ddev);
}
static int rcar_du_pm_resume(struct device *dev)
{
struct rcar_du_device *rcdu = dev_get_drvdata(dev);
- drm_atomic_helper_resume(rcdu->ddev, rcdu->suspend_state);
- drm_fbdev_cma_set_suspend_unlocked(rcdu->fbdev, false);
- drm_kms_helper_poll_enable(rcdu->ddev);
-
- return 0;
+ return drm_mode_config_helper_resume(rcdu->ddev);
}
#endif
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
index 143c037e2c0f..9f5563296c5a 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
@@ -79,7 +79,6 @@ struct rcar_du_device {
struct drm_device *ddev;
struct drm_fbdev_cma *fbdev;
- struct drm_atomic_state *suspend_state;
struct rcar_du_crtc crtcs[RCAR_DU_MAX_CRTCS];
unsigned int num_crtcs;
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index 26438d45732b..1e75196f9659 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -7,7 +7,7 @@ config DRM_ROCKCHIP
select VIDEOMODE_HELPERS
select DRM_ANALOGIX_DP if ROCKCHIP_ANALOGIX_DP
select DRM_DW_HDMI if ROCKCHIP_DW_HDMI
- select DRM_MIPI_DSI if ROCKCHIP_DW_MIPI_DSI
+ select DRM_DW_MIPI_DSI if ROCKCHIP_DW_MIPI_DSI
select DRM_RGB if ROCKCHIP_RGB
select SND_SOC_HDMI_CODEC if ROCKCHIP_CDN_DP && SND_SOC
help
diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile
index 868263ff0302..f6fc9d5dd0ad 100644
--- a/drivers/gpu/drm/rockchip/Makefile
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -11,7 +11,7 @@ rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o
rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o
rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o
rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
-rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o
+rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi-rockchip.o
rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o
rockchipdrm-$(CONFIG_ROCKCHIP_LVDS) += rockchip_lvds.o
rockchipdrm-$(CONFIG_ROCKCHIP_RGB) += rockchip_rgb.o
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
new file mode 100644
index 000000000000..7ee359bcee62
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
@@ -0,0 +1,1076 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:
+ * Chris Zhong <zyw@rock-chips.com>
+ * Nickey Yang <nickey.yang@rock-chips.com>
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/bridge/dw_mipi_dsi.h>
+#include <drm/drm_of.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/math64.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <video/mipi_display.h>
+
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_vop.h"
+
+#define DSI_PHY_RSTZ 0xa0
+#define PHY_DISFORCEPLL 0
+#define PHY_ENFORCEPLL BIT(3)
+#define PHY_DISABLECLK 0
+#define PHY_ENABLECLK BIT(2)
+#define PHY_RSTZ 0
+#define PHY_UNRSTZ BIT(1)
+#define PHY_SHUTDOWNZ 0
+#define PHY_UNSHUTDOWNZ BIT(0)
+
+#define DSI_PHY_IF_CFG 0xa4
+#define N_LANES(n) ((((n) - 1) & 0x3) << 0)
+#define PHY_STOP_WAIT_TIME(cycle) (((cycle) & 0xff) << 8)
+
+#define DSI_PHY_STATUS 0xb0
+#define LOCK BIT(0)
+#define STOP_STATE_CLK_LANE BIT(2)
+
+#define DSI_PHY_TST_CTRL0 0xb4
+#define PHY_TESTCLK BIT(1)
+#define PHY_UNTESTCLK 0
+#define PHY_TESTCLR BIT(0)
+#define PHY_UNTESTCLR 0
+
+#define DSI_PHY_TST_CTRL1 0xb8
+#define PHY_TESTEN BIT(16)
+#define PHY_UNTESTEN 0
+#define PHY_TESTDOUT(n) (((n) & 0xff) << 8)
+#define PHY_TESTDIN(n) (((n) & 0xff) << 0)
+
+#define DSI_INT_ST0 0xbc
+#define DSI_INT_ST1 0xc0
+#define DSI_INT_MSK0 0xc4
+#define DSI_INT_MSK1 0xc8
+
+#define PHY_STATUS_TIMEOUT_US 10000
+#define CMD_PKT_STATUS_TIMEOUT_US 20000
+
+#define BYPASS_VCO_RANGE BIT(7)
+#define VCO_RANGE_CON_SEL(val) (((val) & 0x7) << 3)
+#define VCO_IN_CAP_CON_DEFAULT (0x0 << 1)
+#define VCO_IN_CAP_CON_LOW (0x1 << 1)
+#define VCO_IN_CAP_CON_HIGH (0x2 << 1)
+#define REF_BIAS_CUR_SEL BIT(0)
+
+#define CP_CURRENT_3UA 0x1
+#define CP_CURRENT_4_5UA 0x2
+#define CP_CURRENT_7_5UA 0x6
+#define CP_CURRENT_6UA 0x9
+#define CP_CURRENT_12UA 0xb
+#define CP_CURRENT_SEL(val) ((val) & 0xf)
+#define CP_PROGRAM_EN BIT(7)
+
+#define LPF_RESISTORS_15_5KOHM 0x1
+#define LPF_RESISTORS_13KOHM 0x2
+#define LPF_RESISTORS_11_5KOHM 0x4
+#define LPF_RESISTORS_10_5KOHM 0x8
+#define LPF_RESISTORS_8KOHM 0x10
+#define LPF_PROGRAM_EN BIT(6)
+#define LPF_RESISTORS_SEL(val) ((val) & 0x3f)
+
+#define HSFREQRANGE_SEL(val) (((val) & 0x3f) << 1)
+
+#define INPUT_DIVIDER(val) (((val) - 1) & 0x7f)
+#define LOW_PROGRAM_EN 0
+#define HIGH_PROGRAM_EN BIT(7)
+#define LOOP_DIV_LOW_SEL(val) (((val) - 1) & 0x1f)
+#define LOOP_DIV_HIGH_SEL(val) ((((val) - 1) >> 5) & 0xf)
+#define PLL_LOOP_DIV_EN BIT(5)
+#define PLL_INPUT_DIV_EN BIT(4)
+
+#define POWER_CONTROL BIT(6)
+#define INTERNAL_REG_CURRENT BIT(3)
+#define BIAS_BLOCK_ON BIT(2)
+#define BANDGAP_ON BIT(0)
+
+#define TER_RESISTOR_HIGH BIT(7)
+#define TER_RESISTOR_LOW 0
+#define LEVEL_SHIFTERS_ON BIT(6)
+#define TER_CAL_DONE BIT(5)
+#define SETRD_MAX (0x7 << 2)
+#define POWER_MANAGE BIT(1)
+#define TER_RESISTORS_ON BIT(0)
+
+#define BIASEXTR_SEL(val) ((val) & 0x7)
+#define BANDGAP_SEL(val) ((val) & 0x7)
+#define TLP_PROGRAM_EN BIT(7)
+#define THS_PRE_PROGRAM_EN BIT(7)
+#define THS_ZERO_PROGRAM_EN BIT(6)
+
+#define PLL_BIAS_CUR_SEL_CAP_VCO_CONTROL 0x10
+#define PLL_CP_CONTROL_PLL_LOCK_BYPASS 0x11
+#define PLL_LPF_AND_CP_CONTROL 0x12
+#define PLL_INPUT_DIVIDER_RATIO 0x17
+#define PLL_LOOP_DIVIDER_RATIO 0x18
+#define PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL 0x19
+#define BANDGAP_AND_BIAS_CONTROL 0x20
+#define TERMINATION_RESISTER_CONTROL 0x21
+#define AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY 0x22
+#define HS_RX_CONTROL_OF_LANE_0 0x44
+#define HS_TX_CLOCK_LANE_REQUEST_STATE_TIME_CONTROL 0x60
+#define HS_TX_CLOCK_LANE_PREPARE_STATE_TIME_CONTROL 0x61
+#define HS_TX_CLOCK_LANE_HS_ZERO_STATE_TIME_CONTROL 0x62
+#define HS_TX_CLOCK_LANE_TRAIL_STATE_TIME_CONTROL 0x63
+#define HS_TX_CLOCK_LANE_EXIT_STATE_TIME_CONTROL 0x64
+#define HS_TX_CLOCK_LANE_POST_TIME_CONTROL 0x65
+#define HS_TX_DATA_LANE_REQUEST_STATE_TIME_CONTROL 0x70
+#define HS_TX_DATA_LANE_PREPARE_STATE_TIME_CONTROL 0x71
+#define HS_TX_DATA_LANE_HS_ZERO_STATE_TIME_CONTROL 0x72
+#define HS_TX_DATA_LANE_TRAIL_STATE_TIME_CONTROL 0x73
+#define HS_TX_DATA_LANE_EXIT_STATE_TIME_CONTROL 0x74
+
+#define DW_MIPI_NEEDS_PHY_CFG_CLK BIT(0)
+#define DW_MIPI_NEEDS_GRF_CLK BIT(1)
+
+#define RK3288_GRF_SOC_CON6 0x025c
+#define RK3288_DSI0_LCDC_SEL BIT(6)
+#define RK3288_DSI1_LCDC_SEL BIT(9)
+
+#define RK3399_GRF_SOC_CON20 0x6250
+#define RK3399_DSI0_LCDC_SEL BIT(0)
+#define RK3399_DSI1_LCDC_SEL BIT(4)
+
+#define RK3399_GRF_SOC_CON22 0x6258
+#define RK3399_DSI0_TURNREQUEST (0xf << 12)
+#define RK3399_DSI0_TURNDISABLE (0xf << 8)
+#define RK3399_DSI0_FORCETXSTOPMODE (0xf << 4)
+#define RK3399_DSI0_FORCERXMODE (0xf << 0)
+
+#define RK3399_GRF_SOC_CON23 0x625c
+#define RK3399_DSI1_TURNDISABLE (0xf << 12)
+#define RK3399_DSI1_FORCETXSTOPMODE (0xf << 8)
+#define RK3399_DSI1_FORCERXMODE (0xf << 4)
+#define RK3399_DSI1_ENABLE (0xf << 0)
+
+#define RK3399_GRF_SOC_CON24 0x6260
+#define RK3399_TXRX_MASTERSLAVEZ BIT(7)
+#define RK3399_TXRX_ENABLECLK BIT(6)
+#define RK3399_TXRX_BASEDIR BIT(5)
+
+#define HIWORD_UPDATE(val, mask) (val | (mask) << 16)
+
+#define to_dsi(nm) container_of(nm, struct dw_mipi_dsi_rockchip, nm)
+
+enum {
+ BANDGAP_97_07,
+ BANDGAP_98_05,
+ BANDGAP_99_02,
+ BANDGAP_100_00,
+ BANDGAP_93_17,
+ BANDGAP_94_15,
+ BANDGAP_95_12,
+ BANDGAP_96_10,
+};
+
+enum {
+ BIASEXTR_87_1,
+ BIASEXTR_91_5,
+ BIASEXTR_95_9,
+ BIASEXTR_100,
+ BIASEXTR_105_94,
+ BIASEXTR_111_88,
+ BIASEXTR_118_8,
+ BIASEXTR_127_7,
+};
+
+struct rockchip_dw_dsi_chip_data {
+ u32 reg;
+
+ u32 lcdsel_grf_reg;
+ u32 lcdsel_big;
+ u32 lcdsel_lit;
+
+ u32 enable_grf_reg;
+ u32 enable;
+
+ u32 lanecfg1_grf_reg;
+ u32 lanecfg1;
+ u32 lanecfg2_grf_reg;
+ u32 lanecfg2;
+
+ unsigned int flags;
+ unsigned int max_data_lanes;
+};
+
+struct dw_mipi_dsi_rockchip {
+ struct device *dev;
+ struct drm_encoder encoder;
+ void __iomem *base;
+
+ struct regmap *grf_regmap;
+ struct clk *pllref_clk;
+ struct clk *grf_clk;
+ struct clk *phy_cfg_clk;
+
+ /* dual-channel */
+ bool is_slave;
+ struct dw_mipi_dsi_rockchip *slave;
+
+ unsigned int lane_mbps; /* per lane */
+ u16 input_div;
+ u16 feedback_div;
+ u32 format;
+
+ struct dw_mipi_dsi *dmd;
+ const struct rockchip_dw_dsi_chip_data *cdata;
+ struct dw_mipi_dsi_plat_data pdata;
+ int devcnt;
+};
+
+struct dphy_pll_parameter_map {
+ unsigned int max_mbps;
+ u8 hsfreqrange;
+ u8 icpctrl;
+ u8 lpfctrl;
+};
+
+/* The table is based on 27MHz DPHY pll reference clock. */
+static const struct dphy_pll_parameter_map dppa_map[] = {
+ { 89, 0x00, CP_CURRENT_3UA, LPF_RESISTORS_13KOHM },
+ { 99, 0x10, CP_CURRENT_3UA, LPF_RESISTORS_13KOHM },
+ { 109, 0x20, CP_CURRENT_3UA, LPF_RESISTORS_13KOHM },
+ { 129, 0x01, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM },
+ { 139, 0x11, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM },
+ { 149, 0x21, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM },
+ { 169, 0x02, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM },
+ { 179, 0x12, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM },
+ { 199, 0x22, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM },
+ { 219, 0x03, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM },
+ { 239, 0x13, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM },
+ { 249, 0x23, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM },
+ { 269, 0x04, CP_CURRENT_6UA, LPF_RESISTORS_11_5KOHM },
+ { 299, 0x14, CP_CURRENT_6UA, LPF_RESISTORS_11_5KOHM },
+ { 329, 0x05, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM },
+ { 359, 0x15, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM },
+ { 399, 0x25, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM },
+ { 449, 0x06, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM },
+ { 499, 0x16, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM },
+ { 549, 0x07, CP_CURRENT_7_5UA, LPF_RESISTORS_10_5KOHM },
+ { 599, 0x17, CP_CURRENT_7_5UA, LPF_RESISTORS_10_5KOHM },
+ { 649, 0x08, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM },
+ { 699, 0x18, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM },
+ { 749, 0x09, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM },
+ { 799, 0x19, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM },
+ { 849, 0x29, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM },
+ { 899, 0x39, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM },
+ { 949, 0x0a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM },
+ { 999, 0x1a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM },
+ {1049, 0x2a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM },
+ {1099, 0x3a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM },
+ {1149, 0x0b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM },
+ {1199, 0x1b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM },
+ {1249, 0x2b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM },
+ {1299, 0x3b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM },
+ {1349, 0x0c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM },
+ {1399, 0x1c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM },
+ {1449, 0x2c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM },
+ {1500, 0x3c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM }
+};
+
+static int max_mbps_to_parameter(unsigned int max_mbps)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dppa_map); i++)
+ if (dppa_map[i].max_mbps >= max_mbps)
+ return i;
+
+ return -EINVAL;
+}
+
+static inline void dsi_write(struct dw_mipi_dsi_rockchip *dsi, u32 reg, u32 val)
+{
+ writel(val, dsi->base + reg);
+}
+
+static inline u32 dsi_read(struct dw_mipi_dsi_rockchip *dsi, u32 reg)
+{
+ return readl(dsi->base + reg);
+}
+
+static inline void dsi_set(struct dw_mipi_dsi_rockchip *dsi, u32 reg, u32 mask)
+{
+ dsi_write(dsi, reg, dsi_read(dsi, reg) | mask);
+}
+
+static inline void dsi_update_bits(struct dw_mipi_dsi_rockchip *dsi, u32 reg,
+ u32 mask, u32 val)
+{
+ dsi_write(dsi, reg, (dsi_read(dsi, reg) & ~mask) | val);
+}
+
+static void dw_mipi_dsi_phy_write(struct dw_mipi_dsi_rockchip *dsi,
+ u8 test_code,
+ u8 test_data)
+{
+ /*
+ * With the falling edge on TESTCLK, the TESTDIN[7:0] signal content
+ * is latched internally as the current test code. Test data is
+ * programmed internally by rising edge on TESTCLK.
+ */
+ dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLK | PHY_UNTESTCLR);
+
+ dsi_write(dsi, DSI_PHY_TST_CTRL1, PHY_TESTEN | PHY_TESTDOUT(0) |
+ PHY_TESTDIN(test_code));
+
+ dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_UNTESTCLK | PHY_UNTESTCLR);
+
+ dsi_write(dsi, DSI_PHY_TST_CTRL1, PHY_UNTESTEN | PHY_TESTDOUT(0) |
+ PHY_TESTDIN(test_data));
+
+ dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLK | PHY_UNTESTCLR);
+}
+
+/**
+ * ns2bc - Nanoseconds to byte clock cycles
+ */
+static inline unsigned int ns2bc(struct dw_mipi_dsi_rockchip *dsi, int ns)
+{
+ return DIV_ROUND_UP(ns * dsi->lane_mbps / 8, 1000);
+}
+
+/**
+ * ns2ui - Nanoseconds to UI time periods
+ */
+static inline unsigned int ns2ui(struct dw_mipi_dsi_rockchip *dsi, int ns)
+{
+ return DIV_ROUND_UP(ns * dsi->lane_mbps, 1000);
+}
+
+static int dw_mipi_dsi_phy_init(void *priv_data)
+{
+ struct dw_mipi_dsi_rockchip *dsi = priv_data;
+ int ret, i, vco;
+
+ /*
+ * Get vco from frequency(lane_mbps)
+ * vco frequency table
+ * 000 - between 80 and 200 MHz
+ * 001 - between 200 and 300 MHz
+ * 010 - between 300 and 500 MHz
+ * 011 - between 500 and 700 MHz
+ * 100 - between 700 and 900 MHz
+ * 101 - between 900 and 1100 MHz
+ * 110 - between 1100 and 1300 MHz
+ * 111 - between 1300 and 1500 MHz
+ */
+ vco = (dsi->lane_mbps < 200) ? 0 : (dsi->lane_mbps + 100) / 200;
+
+ i = max_mbps_to_parameter(dsi->lane_mbps);
+ if (i < 0) {
+ DRM_DEV_ERROR(dsi->dev,
+ "failed to get parameter for %dmbps clock\n",
+ dsi->lane_mbps);
+ return i;
+ }
+
+ ret = clk_prepare_enable(dsi->phy_cfg_clk);
+ if (ret) {
+ DRM_DEV_ERROR(dsi->dev, "Failed to enable phy_cfg_clk\n");
+ return ret;
+ }
+
+ dw_mipi_dsi_phy_write(dsi, PLL_BIAS_CUR_SEL_CAP_VCO_CONTROL,
+ BYPASS_VCO_RANGE |
+ VCO_RANGE_CON_SEL(vco) |
+ VCO_IN_CAP_CON_LOW |
+ REF_BIAS_CUR_SEL);
+
+ dw_mipi_dsi_phy_write(dsi, PLL_CP_CONTROL_PLL_LOCK_BYPASS,
+ CP_CURRENT_SEL(dppa_map[i].icpctrl));
+ dw_mipi_dsi_phy_write(dsi, PLL_LPF_AND_CP_CONTROL,
+ CP_PROGRAM_EN | LPF_PROGRAM_EN |
+ LPF_RESISTORS_SEL(dppa_map[i].lpfctrl));
+
+ dw_mipi_dsi_phy_write(dsi, HS_RX_CONTROL_OF_LANE_0,
+ HSFREQRANGE_SEL(dppa_map[i].hsfreqrange));
+
+ dw_mipi_dsi_phy_write(dsi, PLL_INPUT_DIVIDER_RATIO,
+ INPUT_DIVIDER(dsi->input_div));
+ dw_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO,
+ LOOP_DIV_LOW_SEL(dsi->feedback_div) |
+ LOW_PROGRAM_EN);
+ /*
+ * We need set PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL immediately
+ * to make the configured LSB effective according to IP simulation
+ * and lab test results.
+ * Only in this way can we get correct mipi phy pll frequency.
+ */
+ dw_mipi_dsi_phy_write(dsi, PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL,
+ PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
+ dw_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO,
+ LOOP_DIV_HIGH_SEL(dsi->feedback_div) |
+ HIGH_PROGRAM_EN);
+ dw_mipi_dsi_phy_write(dsi, PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL,
+ PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
+
+ dw_mipi_dsi_phy_write(dsi, AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY,
+ LOW_PROGRAM_EN | BIASEXTR_SEL(BIASEXTR_127_7));
+ dw_mipi_dsi_phy_write(dsi, AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY,
+ HIGH_PROGRAM_EN | BANDGAP_SEL(BANDGAP_96_10));
+
+ dw_mipi_dsi_phy_write(dsi, BANDGAP_AND_BIAS_CONTROL,
+ POWER_CONTROL | INTERNAL_REG_CURRENT |
+ BIAS_BLOCK_ON | BANDGAP_ON);
+
+ dw_mipi_dsi_phy_write(dsi, TERMINATION_RESISTER_CONTROL,
+ TER_RESISTOR_LOW | TER_CAL_DONE |
+ SETRD_MAX | TER_RESISTORS_ON);
+ dw_mipi_dsi_phy_write(dsi, TERMINATION_RESISTER_CONTROL,
+ TER_RESISTOR_HIGH | LEVEL_SHIFTERS_ON |
+ SETRD_MAX | POWER_MANAGE |
+ TER_RESISTORS_ON);
+
+ dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_REQUEST_STATE_TIME_CONTROL,
+ TLP_PROGRAM_EN | ns2bc(dsi, 500));
+ dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_PREPARE_STATE_TIME_CONTROL,
+ THS_PRE_PROGRAM_EN | ns2ui(dsi, 40));
+ dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_HS_ZERO_STATE_TIME_CONTROL,
+ THS_ZERO_PROGRAM_EN | ns2bc(dsi, 300));
+ dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_TRAIL_STATE_TIME_CONTROL,
+ THS_PRE_PROGRAM_EN | ns2ui(dsi, 100));
+ dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_EXIT_STATE_TIME_CONTROL,
+ BIT(5) | ns2bc(dsi, 100));
+ dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_POST_TIME_CONTROL,
+ BIT(5) | (ns2bc(dsi, 60) + 7));
+
+ dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_REQUEST_STATE_TIME_CONTROL,
+ TLP_PROGRAM_EN | ns2bc(dsi, 500));
+ dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_PREPARE_STATE_TIME_CONTROL,
+ THS_PRE_PROGRAM_EN | (ns2ui(dsi, 50) + 20));
+ dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_HS_ZERO_STATE_TIME_CONTROL,
+ THS_ZERO_PROGRAM_EN | (ns2bc(dsi, 140) + 2));
+ dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_TRAIL_STATE_TIME_CONTROL,
+ THS_PRE_PROGRAM_EN | (ns2ui(dsi, 60) + 8));
+ dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_EXIT_STATE_TIME_CONTROL,
+ BIT(5) | ns2bc(dsi, 100));
+
+ clk_disable_unprepare(dsi->phy_cfg_clk);
+
+ return ret;
+}
+
+static int
+dw_mipi_dsi_get_lane_mbps(void *priv_data, struct drm_display_mode *mode,
+ unsigned long mode_flags, u32 lanes, u32 format,
+ unsigned int *lane_mbps)
+{
+ struct dw_mipi_dsi_rockchip *dsi = priv_data;
+ int bpp;
+ unsigned long mpclk, tmp;
+ unsigned int target_mbps = 1000;
+ unsigned int max_mbps = dppa_map[ARRAY_SIZE(dppa_map) - 1].max_mbps;
+ unsigned long best_freq = 0;
+ unsigned long fvco_min, fvco_max, fin, fout;
+ unsigned int min_prediv, max_prediv;
+ unsigned int _prediv, uninitialized_var(best_prediv);
+ unsigned long _fbdiv, uninitialized_var(best_fbdiv);
+ unsigned long min_delta = ULONG_MAX;
+
+ dsi->format = format;
+ bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
+ if (bpp < 0) {
+ DRM_DEV_ERROR(dsi->dev,
+ "failed to get bpp for pixel format %d\n",
+ dsi->format);
+ return bpp;
+ }
+
+ mpclk = DIV_ROUND_UP(mode->clock, MSEC_PER_SEC);
+ if (mpclk) {
+ /* take 1 / 0.8, since mbps must big than bandwidth of RGB */
+ tmp = mpclk * (bpp / lanes) * 10 / 8;
+ if (tmp < max_mbps)
+ target_mbps = tmp;
+ else
+ DRM_DEV_ERROR(dsi->dev,
+ "DPHY clock frequency is out of range\n");
+ }
+
+ fin = clk_get_rate(dsi->pllref_clk);
+ fout = target_mbps * USEC_PER_SEC;
+
+ /* constraint: 5Mhz <= Fref / N <= 40MHz */
+ min_prediv = DIV_ROUND_UP(fin, 40 * USEC_PER_SEC);
+ max_prediv = fin / (5 * USEC_PER_SEC);
+
+ /* constraint: 80MHz <= Fvco <= 1500Mhz */
+ fvco_min = 80 * USEC_PER_SEC;
+ fvco_max = 1500 * USEC_PER_SEC;
+
+ for (_prediv = min_prediv; _prediv <= max_prediv; _prediv++) {
+ u64 tmp;
+ u32 delta;
+ /* Fvco = Fref * M / N */
+ tmp = (u64)fout * _prediv;
+ do_div(tmp, fin);
+ _fbdiv = tmp;
+ /*
+ * Due to the use of a "by 2 pre-scaler," the range of the
+ * feedback multiplication value M is limited to even division
+ * numbers, and m must be greater than 6, not bigger than 512.
+ */
+ if (_fbdiv < 6 || _fbdiv > 512)
+ continue;
+
+ _fbdiv += _fbdiv % 2;
+
+ tmp = (u64)_fbdiv * fin;
+ do_div(tmp, _prediv);
+ if (tmp < fvco_min || tmp > fvco_max)
+ continue;
+
+ delta = abs(fout - tmp);
+ if (delta < min_delta) {
+ best_prediv = _prediv;
+ best_fbdiv = _fbdiv;
+ min_delta = delta;
+ best_freq = tmp;
+ }
+ }
+
+ if (best_freq) {
+ dsi->lane_mbps = DIV_ROUND_UP(best_freq, USEC_PER_SEC);
+ *lane_mbps = dsi->lane_mbps;
+ dsi->input_div = best_prediv;
+ dsi->feedback_div = best_fbdiv;
+ } else {
+ DRM_DEV_ERROR(dsi->dev, "Can not find best_freq for DPHY\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct dw_mipi_dsi_phy_ops dw_mipi_dsi_rockchip_phy_ops = {
+ .init = dw_mipi_dsi_phy_init,
+ .get_lane_mbps = dw_mipi_dsi_get_lane_mbps,
+};
+
+static void dw_mipi_dsi_rockchip_config(struct dw_mipi_dsi_rockchip *dsi,
+ int mux)
+{
+ if (dsi->cdata->lcdsel_grf_reg)
+ regmap_write(dsi->grf_regmap, dsi->cdata->lcdsel_grf_reg,
+ mux ? dsi->cdata->lcdsel_lit : dsi->cdata->lcdsel_big);
+
+ if (dsi->cdata->lanecfg1_grf_reg)
+ regmap_write(dsi->grf_regmap, dsi->cdata->lanecfg1_grf_reg,
+ dsi->cdata->lanecfg1);
+
+ if (dsi->cdata->lanecfg2_grf_reg)
+ regmap_write(dsi->grf_regmap, dsi->cdata->lanecfg2_grf_reg,
+ dsi->cdata->lanecfg2);
+
+ if (dsi->cdata->enable_grf_reg)
+ regmap_write(dsi->grf_regmap, dsi->cdata->enable_grf_reg,
+ dsi->cdata->enable);
+}
+
+static int
+dw_mipi_dsi_encoder_atomic_check(struct drm_encoder *encoder,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
+{
+ struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
+ struct dw_mipi_dsi_rockchip *dsi = to_dsi(encoder);
+
+ switch (dsi->format) {
+ case MIPI_DSI_FMT_RGB888:
+ s->output_mode = ROCKCHIP_OUT_MODE_P888;
+ break;
+ case MIPI_DSI_FMT_RGB666:
+ s->output_mode = ROCKCHIP_OUT_MODE_P666;
+ break;
+ case MIPI_DSI_FMT_RGB565:
+ s->output_mode = ROCKCHIP_OUT_MODE_P565;
+ break;
+ default:
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ s->output_type = DRM_MODE_CONNECTOR_DSI;
+ if (dsi->slave)
+ s->output_flags = ROCKCHIP_OUTPUT_DSI_DUAL;
+
+ return 0;
+}
+
+static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
+{
+ struct dw_mipi_dsi_rockchip *dsi = to_dsi(encoder);
+ int ret, mux;
+
+ mux = drm_of_encoder_active_endpoint_id(dsi->dev->of_node,
+ &dsi->encoder);
+ if (mux < 0)
+ return;
+
+ pm_runtime_get_sync(dsi->dev);
+ if (dsi->slave)
+ pm_runtime_get_sync(dsi->slave->dev);
+
+ /*
+ * For the RK3399, the clk of grf must be enabled before writing grf
+ * register. And for RK3288 or other soc, this grf_clk must be NULL,
+ * the clk_prepare_enable return true directly.
+ */
+ ret = clk_prepare_enable(dsi->grf_clk);
+ if (ret) {
+ DRM_DEV_ERROR(dsi->dev, "Failed to enable grf_clk: %d\n", ret);
+ return;
+ }
+
+ dw_mipi_dsi_rockchip_config(dsi, mux);
+ if (dsi->slave)
+ dw_mipi_dsi_rockchip_config(dsi->slave, mux);
+
+ clk_disable_unprepare(dsi->grf_clk);
+}
+
+static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder)
+{
+ struct dw_mipi_dsi_rockchip *dsi = to_dsi(encoder);
+
+ if (dsi->slave)
+ pm_runtime_put(dsi->slave->dev);
+ pm_runtime_put(dsi->dev);
+}
+
+static const struct drm_encoder_helper_funcs
+dw_mipi_dsi_encoder_helper_funcs = {
+ .atomic_check = dw_mipi_dsi_encoder_atomic_check,
+ .enable = dw_mipi_dsi_encoder_enable,
+ .disable = dw_mipi_dsi_encoder_disable,
+};
+
+static const struct drm_encoder_funcs dw_mipi_dsi_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
+static int rockchip_dsi_drm_create_encoder(struct dw_mipi_dsi_rockchip *dsi,
+ struct drm_device *drm_dev)
+{
+ struct drm_encoder *encoder = &dsi->encoder;
+ int ret;
+
+ encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev,
+ dsi->dev->of_node);
+
+ ret = drm_encoder_init(drm_dev, encoder, &dw_mipi_dsi_encoder_funcs,
+ DRM_MODE_ENCODER_DSI, NULL);
+ if (ret) {
+ DRM_ERROR("Failed to initialize encoder with drm\n");
+ return ret;
+ }
+
+ drm_encoder_helper_add(encoder, &dw_mipi_dsi_encoder_helper_funcs);
+
+ return 0;
+}
+
+static struct device
+*dw_mipi_dsi_rockchip_find_second(struct dw_mipi_dsi_rockchip *dsi)
+{
+ const struct of_device_id *match;
+ struct device_node *node = NULL, *local;
+
+ match = of_match_device(dsi->dev->driver->of_match_table, dsi->dev);
+
+ local = of_graph_get_remote_node(dsi->dev->of_node, 1, 0);
+ if (!local)
+ return NULL;
+
+ while ((node = of_find_compatible_node(node, NULL,
+ match->compatible))) {
+ struct device_node *remote;
+
+ /* found ourself */
+ if (node == dsi->dev->of_node)
+ continue;
+
+ remote = of_graph_get_remote_node(node, 1, 0);
+ if (!remote)
+ continue;
+
+ /* same display device in port1-ep0 for both */
+ if (remote == local) {
+ struct dw_mipi_dsi_rockchip *dsi2;
+ struct platform_device *pdev;
+
+ pdev = of_find_device_by_node(node);
+
+ /*
+ * we have found the second, so will either return it
+ * or return with an error. In any case won't need the
+ * nodes anymore nor continue the loop.
+ */
+ of_node_put(remote);
+ of_node_put(node);
+ of_node_put(local);
+
+ if (!pdev)
+ return ERR_PTR(-EPROBE_DEFER);
+
+ dsi2 = platform_get_drvdata(pdev);
+ if (!dsi2) {
+ platform_device_put(pdev);
+ return ERR_PTR(-EPROBE_DEFER);
+ }
+
+ return &pdev->dev;
+ }
+
+ of_node_put(remote);
+ }
+
+ of_node_put(local);
+
+ return NULL;
+}
+
+static int dw_mipi_dsi_rockchip_bind(struct device *dev,
+ struct device *master,
+ void *data)
+{
+ struct dw_mipi_dsi_rockchip *dsi = dev_get_drvdata(dev);
+ struct drm_device *drm_dev = data;
+ struct device *second;
+ bool master1, master2;
+ int ret;
+
+ second = dw_mipi_dsi_rockchip_find_second(dsi);
+ if (IS_ERR(second))
+ return PTR_ERR(second);
+
+ if (second) {
+ master1 = of_property_read_bool(dsi->dev->of_node,
+ "clock-master");
+ master2 = of_property_read_bool(second->of_node,
+ "clock-master");
+
+ if (master1 && master2) {
+ DRM_DEV_ERROR(dsi->dev, "only one clock-master allowed\n");
+ return -EINVAL;
+ }
+
+ if (!master1 && !master2) {
+ DRM_DEV_ERROR(dsi->dev, "no clock-master defined\n");
+ return -EINVAL;
+ }
+
+ /* we are the slave in dual-DSI */
+ if (!master1) {
+ dsi->is_slave = true;
+ return 0;
+ }
+
+ dsi->slave = dev_get_drvdata(second);
+ if (!dsi->slave) {
+ DRM_DEV_ERROR(dev, "could not get slaves data\n");
+ return -ENODEV;
+ }
+
+ dsi->slave->is_slave = true;
+ dw_mipi_dsi_set_slave(dsi->dmd, dsi->slave->dmd);
+ put_device(second);
+ }
+
+ ret = clk_prepare_enable(dsi->pllref_clk);
+ if (ret) {
+ DRM_DEV_ERROR(dev, "Failed to enable pllref_clk: %d\n", ret);
+ return ret;
+ }
+
+ ret = rockchip_dsi_drm_create_encoder(dsi, drm_dev);
+ if (ret) {
+ DRM_DEV_ERROR(dev, "Failed to create drm encoder\n");
+ return ret;
+ }
+
+ ret = dw_mipi_dsi_bind(dsi->dmd, &dsi->encoder);
+ if (ret) {
+ DRM_DEV_ERROR(dev, "Failed to bind: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void dw_mipi_dsi_rockchip_unbind(struct device *dev,
+ struct device *master,
+ void *data)
+{
+ struct dw_mipi_dsi_rockchip *dsi = dev_get_drvdata(dev);
+
+ if (dsi->is_slave)
+ return;
+
+ dw_mipi_dsi_unbind(dsi->dmd);
+
+ clk_disable_unprepare(dsi->pllref_clk);
+}
+
+static const struct component_ops dw_mipi_dsi_rockchip_ops = {
+ .bind = dw_mipi_dsi_rockchip_bind,
+ .unbind = dw_mipi_dsi_rockchip_unbind,
+};
+
+static int dw_mipi_dsi_rockchip_host_attach(void *priv_data,
+ struct mipi_dsi_device *device)
+{
+ struct dw_mipi_dsi_rockchip *dsi = priv_data;
+ struct device *second;
+ int ret;
+
+ ret = component_add(dsi->dev, &dw_mipi_dsi_rockchip_ops);
+ if (ret) {
+ DRM_DEV_ERROR(dsi->dev, "Failed to register component: %d\n",
+ ret);
+ return ret;
+ }
+
+ second = dw_mipi_dsi_rockchip_find_second(dsi);
+ if (IS_ERR(second))
+ return PTR_ERR(second);
+ if (second) {
+ ret = component_add(second, &dw_mipi_dsi_rockchip_ops);
+ if (ret) {
+ DRM_DEV_ERROR(second,
+ "Failed to register component: %d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int dw_mipi_dsi_rockchip_host_detach(void *priv_data,
+ struct mipi_dsi_device *device)
+{
+ struct dw_mipi_dsi_rockchip *dsi = priv_data;
+ struct device *second;
+
+ second = dw_mipi_dsi_rockchip_find_second(dsi);
+ if (second && !IS_ERR(second))
+ component_del(second, &dw_mipi_dsi_rockchip_ops);
+
+ component_del(dsi->dev, &dw_mipi_dsi_rockchip_ops);
+
+ return 0;
+}
+
+static const struct dw_mipi_dsi_host_ops dw_mipi_dsi_rockchip_host_ops = {
+ .attach = dw_mipi_dsi_rockchip_host_attach,
+ .detach = dw_mipi_dsi_rockchip_host_detach,
+};
+
+static int dw_mipi_dsi_rockchip_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct dw_mipi_dsi_rockchip *dsi;
+ struct resource *res;
+ const struct rockchip_dw_dsi_chip_data *cdata =
+ of_device_get_match_data(dev);
+ int ret, i;
+
+ dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
+ if (!dsi)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ dsi->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(dsi->base)) {
+ DRM_DEV_ERROR(dev, "Unable to get dsi registers\n");
+ return PTR_ERR(dsi->base);
+ }
+
+ i = 0;
+ while (cdata[i].reg) {
+ if (cdata[i].reg == res->start) {
+ dsi->cdata = &cdata[i];
+ break;
+ }
+
+ i++;
+ }
+
+ if (!dsi->cdata) {
+ dev_err(dev, "no dsi-config for %s node\n", np->name);
+ return -EINVAL;
+ }
+
+ dsi->pllref_clk = devm_clk_get(dev, "ref");
+ if (IS_ERR(dsi->pllref_clk)) {
+ ret = PTR_ERR(dsi->pllref_clk);
+ DRM_DEV_ERROR(dev,
+ "Unable to get pll reference clock: %d\n", ret);
+ return ret;
+ }
+
+ if (dsi->cdata->flags & DW_MIPI_NEEDS_PHY_CFG_CLK) {
+ dsi->phy_cfg_clk = devm_clk_get(dev, "phy_cfg");
+ if (IS_ERR(dsi->phy_cfg_clk)) {
+ ret = PTR_ERR(dsi->phy_cfg_clk);
+ DRM_DEV_ERROR(dev,
+ "Unable to get phy_cfg_clk: %d\n", ret);
+ return ret;
+ }
+ }
+
+ if (dsi->cdata->flags & DW_MIPI_NEEDS_GRF_CLK) {
+ dsi->grf_clk = devm_clk_get(dev, "grf");
+ if (IS_ERR(dsi->grf_clk)) {
+ ret = PTR_ERR(dsi->grf_clk);
+ DRM_DEV_ERROR(dev, "Unable to get grf_clk: %d\n", ret);
+ return ret;
+ }
+ }
+
+ dsi->grf_regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
+ if (IS_ERR(dsi->grf_regmap)) {
+ DRM_DEV_ERROR(dsi->dev, "Unable to get rockchip,grf\n");
+ return PTR_ERR(dsi->grf_regmap);
+ }
+
+ dsi->dev = dev;
+ dsi->pdata.base = dsi->base;
+ dsi->pdata.max_data_lanes = dsi->cdata->max_data_lanes;
+ dsi->pdata.phy_ops = &dw_mipi_dsi_rockchip_phy_ops;
+ dsi->pdata.host_ops = &dw_mipi_dsi_rockchip_host_ops;
+ dsi->pdata.priv_data = dsi;
+ platform_set_drvdata(pdev, dsi);
+
+ dsi->dmd = dw_mipi_dsi_probe(pdev, &dsi->pdata);
+ if (IS_ERR(dsi->dmd)) {
+ ret = PTR_ERR(dsi->dmd);
+ if (ret != -EPROBE_DEFER)
+ DRM_DEV_ERROR(dev,
+ "Failed to probe dw_mipi_dsi: %d\n", ret);
+ goto err_clkdisable;
+ }
+
+ return 0;
+
+err_clkdisable:
+ clk_disable_unprepare(dsi->pllref_clk);
+ return ret;
+}
+
+static int dw_mipi_dsi_rockchip_remove(struct platform_device *pdev)
+{
+ struct dw_mipi_dsi_rockchip *dsi = platform_get_drvdata(pdev);
+
+ if (dsi->devcnt == 0)
+ component_del(dsi->dev, &dw_mipi_dsi_rockchip_ops);
+
+ dw_mipi_dsi_remove(dsi->dmd);
+
+ return 0;
+}
+
+static const struct rockchip_dw_dsi_chip_data rk3288_chip_data[] = {
+ {
+ .reg = 0xff960000,
+ .lcdsel_grf_reg = RK3288_GRF_SOC_CON6,
+ .lcdsel_big = HIWORD_UPDATE(0, RK3288_DSI0_LCDC_SEL),
+ .lcdsel_lit = HIWORD_UPDATE(RK3288_DSI0_LCDC_SEL, RK3288_DSI0_LCDC_SEL),
+
+ .max_data_lanes = 4,
+ },
+ {
+ .reg = 0xff964000,
+ .lcdsel_grf_reg = RK3288_GRF_SOC_CON6,
+ .lcdsel_big = HIWORD_UPDATE(0, RK3288_DSI1_LCDC_SEL),
+ .lcdsel_lit = HIWORD_UPDATE(RK3288_DSI1_LCDC_SEL, RK3288_DSI1_LCDC_SEL),
+
+ .max_data_lanes = 4,
+ },
+ { /* sentinel */ }
+};
+
+static const struct rockchip_dw_dsi_chip_data rk3399_chip_data[] = {
+ {
+ .reg = 0xff960000,
+ .lcdsel_grf_reg = RK3399_GRF_SOC_CON20,
+ .lcdsel_big = HIWORD_UPDATE(0, RK3399_DSI0_LCDC_SEL),
+ .lcdsel_lit = HIWORD_UPDATE(RK3399_DSI0_LCDC_SEL,
+ RK3399_DSI0_LCDC_SEL),
+
+ .lanecfg1_grf_reg = RK3399_GRF_SOC_CON22,
+ .lanecfg1 = HIWORD_UPDATE(0, RK3399_DSI0_TURNREQUEST |
+ RK3399_DSI0_TURNDISABLE |
+ RK3399_DSI0_FORCETXSTOPMODE |
+ RK3399_DSI0_FORCERXMODE),
+
+ .flags = DW_MIPI_NEEDS_PHY_CFG_CLK | DW_MIPI_NEEDS_GRF_CLK,
+ .max_data_lanes = 4,
+ },
+ {
+ .reg = 0xff968000,
+ .lcdsel_grf_reg = RK3399_GRF_SOC_CON20,
+ .lcdsel_big = HIWORD_UPDATE(0, RK3399_DSI1_LCDC_SEL),
+ .lcdsel_lit = HIWORD_UPDATE(RK3399_DSI1_LCDC_SEL,
+ RK3399_DSI1_LCDC_SEL),
+
+ .lanecfg1_grf_reg = RK3399_GRF_SOC_CON23,
+ .lanecfg1 = HIWORD_UPDATE(0, RK3399_DSI1_TURNDISABLE |
+ RK3399_DSI1_FORCETXSTOPMODE |
+ RK3399_DSI1_FORCERXMODE |
+ RK3399_DSI1_ENABLE),
+
+ .lanecfg2_grf_reg = RK3399_GRF_SOC_CON24,
+ .lanecfg2 = HIWORD_UPDATE(RK3399_TXRX_MASTERSLAVEZ |
+ RK3399_TXRX_ENABLECLK,
+ RK3399_TXRX_MASTERSLAVEZ |
+ RK3399_TXRX_ENABLECLK |
+ RK3399_TXRX_BASEDIR),
+
+ .enable_grf_reg = RK3399_GRF_SOC_CON23,
+ .enable = HIWORD_UPDATE(RK3399_DSI1_ENABLE, RK3399_DSI1_ENABLE),
+
+ .flags = DW_MIPI_NEEDS_PHY_CFG_CLK | DW_MIPI_NEEDS_GRF_CLK,
+ .max_data_lanes = 4,
+ },
+ { /* sentinel */ }
+};
+
+static const struct of_device_id dw_mipi_dsi_rockchip_dt_ids[] = {
+ {
+ .compatible = "rockchip,rk3288-mipi-dsi",
+ .data = &rk3288_chip_data,
+ }, {
+ .compatible = "rockchip,rk3399-mipi-dsi",
+ .data = &rk3399_chip_data,
+ },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, dw_mipi_dsi_rockchip_dt_ids);
+
+struct platform_driver dw_mipi_dsi_rockchip_driver = {
+ .probe = dw_mipi_dsi_rockchip_probe,
+ .remove = dw_mipi_dsi_rockchip_remove,
+ .driver = {
+ .of_match_table = dw_mipi_dsi_rockchip_dt_ids,
+ .name = "dw-mipi-dsi-rockchip",
+ },
+};
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
deleted file mode 100644
index 662b6cb5d3f0..000000000000
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
+++ /dev/null
@@ -1,1349 +0,0 @@
-/*
- * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-#include <linux/clk.h>
-#include <linux/component.h>
-#include <linux/iopoll.h>
-#include <linux/math64.h>
-#include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/pm_runtime.h>
-#include <linux/regmap.h>
-#include <linux/reset.h>
-#include <linux/mfd/syscon.h>
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_mipi_dsi.h>
-#include <drm/drm_of.h>
-#include <drm/drm_panel.h>
-#include <drm/drmP.h>
-#include <video/mipi_display.h>
-
-#include "rockchip_drm_drv.h"
-#include "rockchip_drm_vop.h"
-
-#define DRIVER_NAME "dw-mipi-dsi"
-
-#define RK3288_GRF_SOC_CON6 0x025c
-#define RK3288_DSI0_SEL_VOP_LIT BIT(6)
-#define RK3288_DSI1_SEL_VOP_LIT BIT(9)
-
-#define RK3399_GRF_SOC_CON20 0x6250
-#define RK3399_DSI0_SEL_VOP_LIT BIT(0)
-#define RK3399_DSI1_SEL_VOP_LIT BIT(4)
-
-/* disable turnrequest, turndisable, forcetxstopmode, forcerxmode */
-#define RK3399_GRF_SOC_CON22 0x6258
-#define RK3399_GRF_DSI_MODE 0xffff0000
-
-#define DSI_VERSION 0x00
-#define DSI_PWR_UP 0x04
-#define RESET 0
-#define POWERUP BIT(0)
-
-#define DSI_CLKMGR_CFG 0x08
-#define TO_CLK_DIVIDSION(div) (((div) & 0xff) << 8)
-#define TX_ESC_CLK_DIVIDSION(div) (((div) & 0xff) << 0)
-
-#define DSI_DPI_VCID 0x0c
-#define DPI_VID(vid) (((vid) & 0x3) << 0)
-
-#define DSI_DPI_COLOR_CODING 0x10
-#define EN18_LOOSELY BIT(8)
-#define DPI_COLOR_CODING_16BIT_1 0x0
-#define DPI_COLOR_CODING_16BIT_2 0x1
-#define DPI_COLOR_CODING_16BIT_3 0x2
-#define DPI_COLOR_CODING_18BIT_1 0x3
-#define DPI_COLOR_CODING_18BIT_2 0x4
-#define DPI_COLOR_CODING_24BIT 0x5
-
-#define DSI_DPI_CFG_POL 0x14
-#define COLORM_ACTIVE_LOW BIT(4)
-#define SHUTD_ACTIVE_LOW BIT(3)
-#define HSYNC_ACTIVE_LOW BIT(2)
-#define VSYNC_ACTIVE_LOW BIT(1)
-#define DATAEN_ACTIVE_LOW BIT(0)
-
-#define DSI_DPI_LP_CMD_TIM 0x18
-#define OUTVACT_LPCMD_TIME(p) (((p) & 0xff) << 16)
-#define INVACT_LPCMD_TIME(p) ((p) & 0xff)
-
-#define DSI_DBI_CFG 0x20
-#define DSI_DBI_CMDSIZE 0x28
-
-#define DSI_PCKHDL_CFG 0x2c
-#define EN_CRC_RX BIT(4)
-#define EN_ECC_RX BIT(3)
-#define EN_BTA BIT(2)
-#define EN_EOTP_RX BIT(1)
-#define EN_EOTP_TX BIT(0)
-
-#define DSI_MODE_CFG 0x34
-#define ENABLE_VIDEO_MODE 0
-#define ENABLE_CMD_MODE BIT(0)
-
-#define DSI_VID_MODE_CFG 0x38
-#define FRAME_BTA_ACK BIT(14)
-#define ENABLE_LOW_POWER (0x3f << 8)
-#define ENABLE_LOW_POWER_MASK (0x3f << 8)
-#define VID_MODE_TYPE_NON_BURST_SYNC_PULSES 0x0
-#define VID_MODE_TYPE_NON_BURST_SYNC_EVENTS 0x1
-#define VID_MODE_TYPE_BURST 0x2
-#define VID_MODE_TYPE_MASK 0x3
-
-#define DSI_VID_PKT_SIZE 0x3c
-#define VID_PKT_SIZE(p) (((p) & 0x3fff) << 0)
-#define VID_PKT_MAX_SIZE 0x3fff
-
-#define DSI_VID_HSA_TIME 0x48
-#define DSI_VID_HBP_TIME 0x4c
-#define DSI_VID_HLINE_TIME 0x50
-#define DSI_VID_VSA_LINES 0x54
-#define DSI_VID_VBP_LINES 0x58
-#define DSI_VID_VFP_LINES 0x5c
-#define DSI_VID_VACTIVE_LINES 0x60
-#define DSI_CMD_MODE_CFG 0x68
-#define MAX_RD_PKT_SIZE_LP BIT(24)
-#define DCS_LW_TX_LP BIT(19)
-#define DCS_SR_0P_TX_LP BIT(18)
-#define DCS_SW_1P_TX_LP BIT(17)
-#define DCS_SW_0P_TX_LP BIT(16)
-#define GEN_LW_TX_LP BIT(14)
-#define GEN_SR_2P_TX_LP BIT(13)
-#define GEN_SR_1P_TX_LP BIT(12)
-#define GEN_SR_0P_TX_LP BIT(11)
-#define GEN_SW_2P_TX_LP BIT(10)
-#define GEN_SW_1P_TX_LP BIT(9)
-#define GEN_SW_0P_TX_LP BIT(8)
-#define EN_ACK_RQST BIT(1)
-#define EN_TEAR_FX BIT(0)
-
-#define CMD_MODE_ALL_LP (MAX_RD_PKT_SIZE_LP | \
- DCS_LW_TX_LP | \
- DCS_SR_0P_TX_LP | \
- DCS_SW_1P_TX_LP | \
- DCS_SW_0P_TX_LP | \
- GEN_LW_TX_LP | \
- GEN_SR_2P_TX_LP | \
- GEN_SR_1P_TX_LP | \
- GEN_SR_0P_TX_LP | \
- GEN_SW_2P_TX_LP | \
- GEN_SW_1P_TX_LP | \
- GEN_SW_0P_TX_LP)
-
-#define DSI_GEN_HDR 0x6c
-#define GEN_HDATA(data) (((data) & 0xffff) << 8)
-#define GEN_HDATA_MASK (0xffff << 8)
-#define GEN_HTYPE(type) (((type) & 0xff) << 0)
-#define GEN_HTYPE_MASK 0xff
-
-#define DSI_GEN_PLD_DATA 0x70
-
-#define DSI_CMD_PKT_STATUS 0x74
-#define GEN_CMD_EMPTY BIT(0)
-#define GEN_CMD_FULL BIT(1)
-#define GEN_PLD_W_EMPTY BIT(2)
-#define GEN_PLD_W_FULL BIT(3)
-#define GEN_PLD_R_EMPTY BIT(4)
-#define GEN_PLD_R_FULL BIT(5)
-#define GEN_RD_CMD_BUSY BIT(6)
-
-#define DSI_TO_CNT_CFG 0x78
-#define HSTX_TO_CNT(p) (((p) & 0xffff) << 16)
-#define LPRX_TO_CNT(p) ((p) & 0xffff)
-
-#define DSI_BTA_TO_CNT 0x8c
-#define DSI_LPCLK_CTRL 0x94
-#define AUTO_CLKLANE_CTRL BIT(1)
-#define PHY_TXREQUESTCLKHS BIT(0)
-
-#define DSI_PHY_TMR_LPCLK_CFG 0x98
-#define PHY_CLKHS2LP_TIME(lbcc) (((lbcc) & 0x3ff) << 16)
-#define PHY_CLKLP2HS_TIME(lbcc) ((lbcc) & 0x3ff)
-
-#define DSI_PHY_TMR_CFG 0x9c
-#define PHY_HS2LP_TIME(lbcc) (((lbcc) & 0xff) << 24)
-#define PHY_LP2HS_TIME(lbcc) (((lbcc) & 0xff) << 16)
-#define MAX_RD_TIME(lbcc) ((lbcc) & 0x7fff)
-
-#define DSI_PHY_RSTZ 0xa0
-#define PHY_DISFORCEPLL 0
-#define PHY_ENFORCEPLL BIT(3)
-#define PHY_DISABLECLK 0
-#define PHY_ENABLECLK BIT(2)
-#define PHY_RSTZ 0
-#define PHY_UNRSTZ BIT(1)
-#define PHY_SHUTDOWNZ 0
-#define PHY_UNSHUTDOWNZ BIT(0)
-
-#define DSI_PHY_IF_CFG 0xa4
-#define N_LANES(n) ((((n) - 1) & 0x3) << 0)
-#define PHY_STOP_WAIT_TIME(cycle) (((cycle) & 0xff) << 8)
-
-#define DSI_PHY_STATUS 0xb0
-#define LOCK BIT(0)
-#define STOP_STATE_CLK_LANE BIT(2)
-
-#define DSI_PHY_TST_CTRL0 0xb4
-#define PHY_TESTCLK BIT(1)
-#define PHY_UNTESTCLK 0
-#define PHY_TESTCLR BIT(0)
-#define PHY_UNTESTCLR 0
-
-#define DSI_PHY_TST_CTRL1 0xb8
-#define PHY_TESTEN BIT(16)
-#define PHY_UNTESTEN 0
-#define PHY_TESTDOUT(n) (((n) & 0xff) << 8)
-#define PHY_TESTDIN(n) (((n) & 0xff) << 0)
-
-#define DSI_INT_ST0 0xbc
-#define DSI_INT_ST1 0xc0
-#define DSI_INT_MSK0 0xc4
-#define DSI_INT_MSK1 0xc8
-
-#define PHY_STATUS_TIMEOUT_US 10000
-#define CMD_PKT_STATUS_TIMEOUT_US 20000
-
-#define BYPASS_VCO_RANGE BIT(7)
-#define VCO_RANGE_CON_SEL(val) (((val) & 0x7) << 3)
-#define VCO_IN_CAP_CON_DEFAULT (0x0 << 1)
-#define VCO_IN_CAP_CON_LOW (0x1 << 1)
-#define VCO_IN_CAP_CON_HIGH (0x2 << 1)
-#define REF_BIAS_CUR_SEL BIT(0)
-
-#define CP_CURRENT_3MA BIT(3)
-#define CP_PROGRAM_EN BIT(7)
-#define LPF_PROGRAM_EN BIT(6)
-#define LPF_RESISTORS_20_KOHM 0
-
-#define HSFREQRANGE_SEL(val) (((val) & 0x3f) << 1)
-
-#define INPUT_DIVIDER(val) (((val) - 1) & 0x7f)
-#define LOW_PROGRAM_EN 0
-#define HIGH_PROGRAM_EN BIT(7)
-#define LOOP_DIV_LOW_SEL(val) (((val) - 1) & 0x1f)
-#define LOOP_DIV_HIGH_SEL(val) ((((val) - 1) >> 5) & 0x1f)
-#define PLL_LOOP_DIV_EN BIT(5)
-#define PLL_INPUT_DIV_EN BIT(4)
-
-#define POWER_CONTROL BIT(6)
-#define INTERNAL_REG_CURRENT BIT(3)
-#define BIAS_BLOCK_ON BIT(2)
-#define BANDGAP_ON BIT(0)
-
-#define TER_RESISTOR_HIGH BIT(7)
-#define TER_RESISTOR_LOW 0
-#define LEVEL_SHIFTERS_ON BIT(6)
-#define TER_CAL_DONE BIT(5)
-#define SETRD_MAX (0x7 << 2)
-#define POWER_MANAGE BIT(1)
-#define TER_RESISTORS_ON BIT(0)
-
-#define BIASEXTR_SEL(val) ((val) & 0x7)
-#define BANDGAP_SEL(val) ((val) & 0x7)
-#define TLP_PROGRAM_EN BIT(7)
-#define THS_PRE_PROGRAM_EN BIT(7)
-#define THS_ZERO_PROGRAM_EN BIT(6)
-
-#define DW_MIPI_NEEDS_PHY_CFG_CLK BIT(0)
-#define DW_MIPI_NEEDS_GRF_CLK BIT(1)
-
-enum {
- BANDGAP_97_07,
- BANDGAP_98_05,
- BANDGAP_99_02,
- BANDGAP_100_00,
- BANDGAP_93_17,
- BANDGAP_94_15,
- BANDGAP_95_12,
- BANDGAP_96_10,
-};
-
-enum {
- BIASEXTR_87_1,
- BIASEXTR_91_5,
- BIASEXTR_95_9,
- BIASEXTR_100,
- BIASEXTR_105_94,
- BIASEXTR_111_88,
- BIASEXTR_118_8,
- BIASEXTR_127_7,
-};
-
-struct dw_mipi_dsi_plat_data {
- u32 dsi0_en_bit;
- u32 dsi1_en_bit;
- u32 grf_switch_reg;
- u32 grf_dsi0_mode;
- u32 grf_dsi0_mode_reg;
- unsigned int flags;
- unsigned int max_data_lanes;
-};
-
-struct dw_mipi_dsi {
- struct drm_encoder encoder;
- struct drm_connector connector;
- struct mipi_dsi_host dsi_host;
- struct drm_panel *panel;
- struct device *dev;
- struct regmap *grf_regmap;
- void __iomem *base;
-
- struct clk *grf_clk;
- struct clk *pllref_clk;
- struct clk *pclk;
- struct clk *phy_cfg_clk;
-
- int dpms_mode;
- unsigned int lane_mbps; /* per lane */
- u32 channel;
- u32 lanes;
- u32 format;
- u16 input_div;
- u16 feedback_div;
- unsigned long mode_flags;
-
- const struct dw_mipi_dsi_plat_data *pdata;
-};
-
-enum dw_mipi_dsi_mode {
- DW_MIPI_DSI_CMD_MODE,
- DW_MIPI_DSI_VID_MODE,
-};
-
-struct dphy_pll_testdin_map {
- unsigned int max_mbps;
- u8 testdin;
-};
-
-/* The table is based on 27MHz DPHY pll reference clock. */
-static const struct dphy_pll_testdin_map dptdin_map[] = {
- { 90, 0x00}, { 100, 0x10}, { 110, 0x20}, { 130, 0x01},
- { 140, 0x11}, { 150, 0x21}, { 170, 0x02}, { 180, 0x12},
- { 200, 0x22}, { 220, 0x03}, { 240, 0x13}, { 250, 0x23},
- { 270, 0x04}, { 300, 0x14}, { 330, 0x05}, { 360, 0x15},
- { 400, 0x25}, { 450, 0x06}, { 500, 0x16}, { 550, 0x07},
- { 600, 0x17}, { 650, 0x08}, { 700, 0x18}, { 750, 0x09},
- { 800, 0x19}, { 850, 0x29}, { 900, 0x39}, { 950, 0x0a},
- {1000, 0x1a}, {1050, 0x2a}, {1100, 0x3a}, {1150, 0x0b},
- {1200, 0x1b}, {1250, 0x2b}, {1300, 0x3b}, {1350, 0x0c},
- {1400, 0x1c}, {1450, 0x2c}, {1500, 0x3c}
-};
-
-static int max_mbps_to_testdin(unsigned int max_mbps)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(dptdin_map); i++)
- if (dptdin_map[i].max_mbps > max_mbps)
- return dptdin_map[i].testdin;
-
- return -EINVAL;
-}
-
-/*
- * The controller should generate 2 frames before
- * preparing the peripheral.
- */
-static void dw_mipi_dsi_wait_for_two_frames(struct drm_display_mode *mode)
-{
- int refresh, two_frames;
-
- refresh = drm_mode_vrefresh(mode);
- two_frames = DIV_ROUND_UP(MSEC_PER_SEC, refresh) * 2;
- msleep(two_frames);
-}
-
-static inline struct dw_mipi_dsi *host_to_dsi(struct mipi_dsi_host *host)
-{
- return container_of(host, struct dw_mipi_dsi, dsi_host);
-}
-
-static inline struct dw_mipi_dsi *con_to_dsi(struct drm_connector *con)
-{
- return container_of(con, struct dw_mipi_dsi, connector);
-}
-
-static inline struct dw_mipi_dsi *encoder_to_dsi(struct drm_encoder *encoder)
-{
- return container_of(encoder, struct dw_mipi_dsi, encoder);
-}
-
-static inline void dsi_write(struct dw_mipi_dsi *dsi, u32 reg, u32 val)
-{
- writel(val, dsi->base + reg);
-}
-
-static inline u32 dsi_read(struct dw_mipi_dsi *dsi, u32 reg)
-{
- return readl(dsi->base + reg);
-}
-
-static void dw_mipi_dsi_phy_write(struct dw_mipi_dsi *dsi, u8 test_code,
- u8 test_data)
-{
- /*
- * With the falling edge on TESTCLK, the TESTDIN[7:0] signal content
- * is latched internally as the current test code. Test data is
- * programmed internally by rising edge on TESTCLK.
- */
- dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLK | PHY_UNTESTCLR);
-
- dsi_write(dsi, DSI_PHY_TST_CTRL1, PHY_TESTEN | PHY_TESTDOUT(0) |
- PHY_TESTDIN(test_code));
-
- dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_UNTESTCLK | PHY_UNTESTCLR);
-
- dsi_write(dsi, DSI_PHY_TST_CTRL1, PHY_UNTESTEN | PHY_TESTDOUT(0) |
- PHY_TESTDIN(test_data));
-
- dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLK | PHY_UNTESTCLR);
-}
-
-/**
- * ns2bc - Nanoseconds to byte clock cycles
- */
-static inline unsigned int ns2bc(struct dw_mipi_dsi *dsi, int ns)
-{
- return DIV_ROUND_UP(ns * dsi->lane_mbps / 8, 1000);
-}
-
-/**
- * ns2ui - Nanoseconds to UI time periods
- */
-static inline unsigned int ns2ui(struct dw_mipi_dsi *dsi, int ns)
-{
- return DIV_ROUND_UP(ns * dsi->lane_mbps, 1000);
-}
-
-static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
-{
- int ret, testdin, vco, val;
-
- vco = (dsi->lane_mbps < 200) ? 0 : (dsi->lane_mbps + 100) / 200;
-
- testdin = max_mbps_to_testdin(dsi->lane_mbps);
- if (testdin < 0) {
- DRM_DEV_ERROR(dsi->dev,
- "failed to get testdin for %dmbps lane clock\n",
- dsi->lane_mbps);
- return testdin;
- }
-
- /* Start by clearing PHY state */
- dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_UNTESTCLR);
- dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLR);
- dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_UNTESTCLR);
-
- ret = clk_prepare_enable(dsi->phy_cfg_clk);
- if (ret) {
- DRM_DEV_ERROR(dsi->dev, "Failed to enable phy_cfg_clk\n");
- return ret;
- }
-
- dw_mipi_dsi_phy_write(dsi, 0x10, BYPASS_VCO_RANGE |
- VCO_RANGE_CON_SEL(vco) |
- VCO_IN_CAP_CON_LOW |
- REF_BIAS_CUR_SEL);
-
- dw_mipi_dsi_phy_write(dsi, 0x11, CP_CURRENT_3MA);
- dw_mipi_dsi_phy_write(dsi, 0x12, CP_PROGRAM_EN | LPF_PROGRAM_EN |
- LPF_RESISTORS_20_KOHM);
-
- dw_mipi_dsi_phy_write(dsi, 0x44, HSFREQRANGE_SEL(testdin));
-
- dw_mipi_dsi_phy_write(dsi, 0x17, INPUT_DIVIDER(dsi->input_div));
- dw_mipi_dsi_phy_write(dsi, 0x18, LOOP_DIV_LOW_SEL(dsi->feedback_div) |
- LOW_PROGRAM_EN);
- dw_mipi_dsi_phy_write(dsi, 0x18, LOOP_DIV_HIGH_SEL(dsi->feedback_div) |
- HIGH_PROGRAM_EN);
- dw_mipi_dsi_phy_write(dsi, 0x19, PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
-
- dw_mipi_dsi_phy_write(dsi, 0x22, LOW_PROGRAM_EN |
- BIASEXTR_SEL(BIASEXTR_127_7));
- dw_mipi_dsi_phy_write(dsi, 0x22, HIGH_PROGRAM_EN |
- BANDGAP_SEL(BANDGAP_96_10));
-
- dw_mipi_dsi_phy_write(dsi, 0x20, POWER_CONTROL | INTERNAL_REG_CURRENT |
- BIAS_BLOCK_ON | BANDGAP_ON);
-
- dw_mipi_dsi_phy_write(dsi, 0x21, TER_RESISTOR_LOW | TER_CAL_DONE |
- SETRD_MAX | TER_RESISTORS_ON);
- dw_mipi_dsi_phy_write(dsi, 0x21, TER_RESISTOR_HIGH | LEVEL_SHIFTERS_ON |
- SETRD_MAX | POWER_MANAGE |
- TER_RESISTORS_ON);
-
- dw_mipi_dsi_phy_write(dsi, 0x60, TLP_PROGRAM_EN | ns2bc(dsi, 500));
- dw_mipi_dsi_phy_write(dsi, 0x61, THS_PRE_PROGRAM_EN | ns2ui(dsi, 40));
- dw_mipi_dsi_phy_write(dsi, 0x62, THS_ZERO_PROGRAM_EN | ns2bc(dsi, 300));
- dw_mipi_dsi_phy_write(dsi, 0x63, THS_PRE_PROGRAM_EN | ns2ui(dsi, 100));
- dw_mipi_dsi_phy_write(dsi, 0x64, BIT(5) | ns2bc(dsi, 100));
- dw_mipi_dsi_phy_write(dsi, 0x65, BIT(5) | (ns2bc(dsi, 60) + 7));
-
- dw_mipi_dsi_phy_write(dsi, 0x70, TLP_PROGRAM_EN | ns2bc(dsi, 500));
- dw_mipi_dsi_phy_write(dsi, 0x71,
- THS_PRE_PROGRAM_EN | (ns2ui(dsi, 50) + 5));
- dw_mipi_dsi_phy_write(dsi, 0x72,
- THS_ZERO_PROGRAM_EN | (ns2bc(dsi, 140) + 2));
- dw_mipi_dsi_phy_write(dsi, 0x73,
- THS_PRE_PROGRAM_EN | (ns2ui(dsi, 60) + 8));
- dw_mipi_dsi_phy_write(dsi, 0x74, BIT(5) | ns2bc(dsi, 100));
-
- dsi_write(dsi, DSI_PHY_RSTZ, PHY_ENFORCEPLL | PHY_ENABLECLK |
- PHY_UNRSTZ | PHY_UNSHUTDOWNZ);
-
- ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS,
- val, val & LOCK, 1000, PHY_STATUS_TIMEOUT_US);
- if (ret < 0) {
- DRM_DEV_ERROR(dsi->dev, "failed to wait for phy lock state\n");
- goto phy_init_end;
- }
-
- ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS,
- val, val & STOP_STATE_CLK_LANE, 1000,
- PHY_STATUS_TIMEOUT_US);
- if (ret < 0)
- DRM_DEV_ERROR(dsi->dev,
- "failed to wait for phy clk lane stop state\n");
-
-phy_init_end:
- clk_disable_unprepare(dsi->phy_cfg_clk);
-
- return ret;
-}
-
-static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
- struct drm_display_mode *mode)
-{
- unsigned int i, pre;
- unsigned long mpclk, pllref, tmp;
- unsigned int m = 1, n = 1, target_mbps = 1000;
- unsigned int max_mbps = dptdin_map[ARRAY_SIZE(dptdin_map) - 1].max_mbps;
- int bpp;
-
- bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
- if (bpp < 0) {
- DRM_DEV_ERROR(dsi->dev,
- "failed to get bpp for pixel format %d\n",
- dsi->format);
- return bpp;
- }
-
- mpclk = DIV_ROUND_UP(mode->clock, MSEC_PER_SEC);
- if (mpclk) {
- /* take 1 / 0.8, since mbps must big than bandwidth of RGB */
- tmp = mpclk * (bpp / dsi->lanes) * 10 / 8;
- if (tmp < max_mbps)
- target_mbps = tmp;
- else
- DRM_DEV_ERROR(dsi->dev,
- "DPHY clock frequency is out of range\n");
- }
-
- pllref = DIV_ROUND_UP(clk_get_rate(dsi->pllref_clk), USEC_PER_SEC);
- tmp = pllref;
-
- /*
- * The limits on the PLL divisor are:
- *
- * 5MHz <= (pllref / n) <= 40MHz
- *
- * we walk over these values in descreasing order so that if we hit
- * an exact match for target_mbps it is more likely that "m" will be
- * even.
- *
- * TODO: ensure that "m" is even after this loop.
- */
- for (i = pllref / 5; i > (pllref / 40); i--) {
- pre = pllref / i;
- if ((tmp > (target_mbps % pre)) && (target_mbps / pre < 512)) {
- tmp = target_mbps % pre;
- n = i;
- m = target_mbps / pre;
- }
- if (tmp == 0)
- break;
- }
-
- dsi->lane_mbps = pllref / n * m;
- dsi->input_div = n;
- dsi->feedback_div = m;
-
- return 0;
-}
-
-static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
- struct mipi_dsi_device *device)
-{
- struct dw_mipi_dsi *dsi = host_to_dsi(host);
-
- if (device->lanes > dsi->pdata->max_data_lanes) {
- DRM_DEV_ERROR(dsi->dev,
- "the number of data lanes(%u) is too many\n",
- device->lanes);
- return -EINVAL;
- }
-
- dsi->lanes = device->lanes;
- dsi->channel = device->channel;
- dsi->format = device->format;
- dsi->mode_flags = device->mode_flags;
- dsi->panel = of_drm_find_panel(device->dev.of_node);
- if (!IS_ERR(dsi->panel))
- return drm_panel_attach(dsi->panel, &dsi->connector);
-
- return -EINVAL;
-}
-
-static int dw_mipi_dsi_host_detach(struct mipi_dsi_host *host,
- struct mipi_dsi_device *device)
-{
- struct dw_mipi_dsi *dsi = host_to_dsi(host);
-
- drm_panel_detach(dsi->panel);
-
- return 0;
-}
-
-static void dw_mipi_message_config(struct dw_mipi_dsi *dsi,
- const struct mipi_dsi_msg *msg)
-{
- bool lpm = msg->flags & MIPI_DSI_MSG_USE_LPM;
- u32 val = 0;
-
- if (msg->flags & MIPI_DSI_MSG_REQ_ACK)
- val |= EN_ACK_RQST;
- if (lpm)
- val |= CMD_MODE_ALL_LP;
-
- dsi_write(dsi, DSI_LPCLK_CTRL, lpm ? 0 : PHY_TXREQUESTCLKHS);
- dsi_write(dsi, DSI_CMD_MODE_CFG, val);
-}
-
-static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val)
-{
- int ret;
- u32 val, mask;
-
- ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS,
- val, !(val & GEN_CMD_FULL), 1000,
- CMD_PKT_STATUS_TIMEOUT_US);
- if (ret < 0) {
- DRM_DEV_ERROR(dsi->dev,
- "failed to get available command FIFO\n");
- return ret;
- }
-
- dsi_write(dsi, DSI_GEN_HDR, hdr_val);
-
- mask = GEN_CMD_EMPTY | GEN_PLD_W_EMPTY;
- ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS,
- val, (val & mask) == mask,
- 1000, CMD_PKT_STATUS_TIMEOUT_US);
- if (ret < 0) {
- DRM_DEV_ERROR(dsi->dev, "failed to write command FIFO\n");
- return ret;
- }
-
- return 0;
-}
-
-static int dw_mipi_dsi_dcs_short_write(struct dw_mipi_dsi *dsi,
- const struct mipi_dsi_msg *msg)
-{
- const u8 *tx_buf = msg->tx_buf;
- u16 data = 0;
- u32 val;
-
- if (msg->tx_len > 0)
- data |= tx_buf[0];
- if (msg->tx_len > 1)
- data |= tx_buf[1] << 8;
-
- if (msg->tx_len > 2) {
- DRM_DEV_ERROR(dsi->dev,
- "too long tx buf length %zu for short write\n",
- msg->tx_len);
- return -EINVAL;
- }
-
- val = GEN_HDATA(data) | GEN_HTYPE(msg->type);
- return dw_mipi_dsi_gen_pkt_hdr_write(dsi, val);
-}
-
-static int dw_mipi_dsi_dcs_long_write(struct dw_mipi_dsi *dsi,
- const struct mipi_dsi_msg *msg)
-{
- const u8 *tx_buf = msg->tx_buf;
- int len = msg->tx_len, pld_data_bytes = sizeof(u32), ret;
- u32 hdr_val = GEN_HDATA(msg->tx_len) | GEN_HTYPE(msg->type);
- u32 remainder;
- u32 val;
-
- if (msg->tx_len < 3) {
- DRM_DEV_ERROR(dsi->dev,
- "wrong tx buf length %zu for long write\n",
- msg->tx_len);
- return -EINVAL;
- }
-
- while (DIV_ROUND_UP(len, pld_data_bytes)) {
- if (len < pld_data_bytes) {
- remainder = 0;
- memcpy(&remainder, tx_buf, len);
- dsi_write(dsi, DSI_GEN_PLD_DATA, remainder);
- len = 0;
- } else {
- memcpy(&remainder, tx_buf, pld_data_bytes);
- dsi_write(dsi, DSI_GEN_PLD_DATA, remainder);
- tx_buf += pld_data_bytes;
- len -= pld_data_bytes;
- }
-
- ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS,
- val, !(val & GEN_PLD_W_FULL), 1000,
- CMD_PKT_STATUS_TIMEOUT_US);
- if (ret < 0) {
- DRM_DEV_ERROR(dsi->dev,
- "failed to get available write payload FIFO\n");
- return ret;
- }
- }
-
- return dw_mipi_dsi_gen_pkt_hdr_write(dsi, hdr_val);
-}
-
-static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host,
- const struct mipi_dsi_msg *msg)
-{
- struct dw_mipi_dsi *dsi = host_to_dsi(host);
- int ret;
-
- dw_mipi_message_config(dsi, msg);
-
- switch (msg->type) {
- case MIPI_DSI_DCS_SHORT_WRITE:
- case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
- case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE:
- ret = dw_mipi_dsi_dcs_short_write(dsi, msg);
- break;
- case MIPI_DSI_DCS_LONG_WRITE:
- ret = dw_mipi_dsi_dcs_long_write(dsi, msg);
- break;
- default:
- DRM_DEV_ERROR(dsi->dev, "unsupported message type 0x%02x\n",
- msg->type);
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-static const struct mipi_dsi_host_ops dw_mipi_dsi_host_ops = {
- .attach = dw_mipi_dsi_host_attach,
- .detach = dw_mipi_dsi_host_detach,
- .transfer = dw_mipi_dsi_host_transfer,
-};
-
-static void dw_mipi_dsi_video_mode_config(struct dw_mipi_dsi *dsi)
-{
- u32 val;
-
- val = ENABLE_LOW_POWER;
-
- if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
- val |= VID_MODE_TYPE_BURST;
- else if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
- val |= VID_MODE_TYPE_NON_BURST_SYNC_PULSES;
- else
- val |= VID_MODE_TYPE_NON_BURST_SYNC_EVENTS;
-
- dsi_write(dsi, DSI_VID_MODE_CFG, val);
-}
-
-static void dw_mipi_dsi_set_mode(struct dw_mipi_dsi *dsi,
- enum dw_mipi_dsi_mode mode)
-{
- if (mode == DW_MIPI_DSI_CMD_MODE) {
- dsi_write(dsi, DSI_PWR_UP, RESET);
- dsi_write(dsi, DSI_MODE_CFG, ENABLE_CMD_MODE);
- dsi_write(dsi, DSI_PWR_UP, POWERUP);
- } else {
- dsi_write(dsi, DSI_PWR_UP, RESET);
- dsi_write(dsi, DSI_MODE_CFG, ENABLE_VIDEO_MODE);
- dw_mipi_dsi_video_mode_config(dsi);
- dsi_write(dsi, DSI_LPCLK_CTRL, PHY_TXREQUESTCLKHS);
- dsi_write(dsi, DSI_PWR_UP, POWERUP);
- }
-}
-
-static void dw_mipi_dsi_disable(struct dw_mipi_dsi *dsi)
-{
- dsi_write(dsi, DSI_PWR_UP, RESET);
- dsi_write(dsi, DSI_PHY_RSTZ, PHY_RSTZ);
-}
-
-static void dw_mipi_dsi_init(struct dw_mipi_dsi *dsi)
-{
- /*
- * The maximum permitted escape clock is 20MHz and it is derived from
- * lanebyteclk, which is running at "lane_mbps / 8". Thus we want:
- *
- * (lane_mbps >> 3) / esc_clk_division < 20
- * which is:
- * (lane_mbps >> 3) / 20 > esc_clk_division
- */
- u32 esc_clk_division = (dsi->lane_mbps >> 3) / 20 + 1;
-
- dsi_write(dsi, DSI_PWR_UP, RESET);
- dsi_write(dsi, DSI_PHY_RSTZ, PHY_DISFORCEPLL | PHY_DISABLECLK
- | PHY_RSTZ | PHY_SHUTDOWNZ);
- dsi_write(dsi, DSI_CLKMGR_CFG, TO_CLK_DIVIDSION(10) |
- TX_ESC_CLK_DIVIDSION(esc_clk_division));
-}
-
-static void dw_mipi_dsi_dpi_config(struct dw_mipi_dsi *dsi,
- struct drm_display_mode *mode)
-{
- u32 val = 0, color = 0;
-
- switch (dsi->format) {
- case MIPI_DSI_FMT_RGB888:
- color = DPI_COLOR_CODING_24BIT;
- break;
- case MIPI_DSI_FMT_RGB666:
- color = DPI_COLOR_CODING_18BIT_2 | EN18_LOOSELY;
- break;
- case MIPI_DSI_FMT_RGB666_PACKED:
- color = DPI_COLOR_CODING_18BIT_1;
- break;
- case MIPI_DSI_FMT_RGB565:
- color = DPI_COLOR_CODING_16BIT_1;
- break;
- }
-
- if (mode->flags & DRM_MODE_FLAG_NVSYNC)
- val |= VSYNC_ACTIVE_LOW;
- if (mode->flags & DRM_MODE_FLAG_NHSYNC)
- val |= HSYNC_ACTIVE_LOW;
-
- dsi_write(dsi, DSI_DPI_VCID, DPI_VID(dsi->channel));
- dsi_write(dsi, DSI_DPI_COLOR_CODING, color);
- dsi_write(dsi, DSI_DPI_CFG_POL, val);
- dsi_write(dsi, DSI_DPI_LP_CMD_TIM, OUTVACT_LPCMD_TIME(4)
- | INVACT_LPCMD_TIME(4));
-}
-
-static void dw_mipi_dsi_packet_handler_config(struct dw_mipi_dsi *dsi)
-{
- dsi_write(dsi, DSI_PCKHDL_CFG, EN_CRC_RX | EN_ECC_RX | EN_BTA);
-}
-
-static void dw_mipi_dsi_video_packet_config(struct dw_mipi_dsi *dsi,
- struct drm_display_mode *mode)
-{
- dsi_write(dsi, DSI_VID_PKT_SIZE, VID_PKT_SIZE(mode->hdisplay));
-}
-
-static void dw_mipi_dsi_command_mode_config(struct dw_mipi_dsi *dsi)
-{
- dsi_write(dsi, DSI_TO_CNT_CFG, HSTX_TO_CNT(1000) | LPRX_TO_CNT(1000));
- dsi_write(dsi, DSI_BTA_TO_CNT, 0xd00);
- dsi_write(dsi, DSI_MODE_CFG, ENABLE_CMD_MODE);
-}
-
-/* Get lane byte clock cycles. */
-static u32 dw_mipi_dsi_get_hcomponent_lbcc(struct dw_mipi_dsi *dsi,
- struct drm_display_mode *mode,
- u32 hcomponent)
-{
- u32 frac, lbcc;
-
- lbcc = hcomponent * dsi->lane_mbps * MSEC_PER_SEC / 8;
-
- frac = lbcc % mode->clock;
- lbcc = lbcc / mode->clock;
- if (frac)
- lbcc++;
-
- return lbcc;
-}
-
-static void dw_mipi_dsi_line_timer_config(struct dw_mipi_dsi *dsi,
- struct drm_display_mode *mode)
-{
- u32 htotal, hsa, hbp, lbcc;
-
- htotal = mode->htotal;
- hsa = mode->hsync_end - mode->hsync_start;
- hbp = mode->htotal - mode->hsync_end;
-
- lbcc = dw_mipi_dsi_get_hcomponent_lbcc(dsi, mode, htotal);
- dsi_write(dsi, DSI_VID_HLINE_TIME, lbcc);
-
- lbcc = dw_mipi_dsi_get_hcomponent_lbcc(dsi, mode, hsa);
- dsi_write(dsi, DSI_VID_HSA_TIME, lbcc);
-
- lbcc = dw_mipi_dsi_get_hcomponent_lbcc(dsi, mode, hbp);
- dsi_write(dsi, DSI_VID_HBP_TIME, lbcc);
-}
-
-static void dw_mipi_dsi_vertical_timing_config(struct dw_mipi_dsi *dsi,
- struct drm_display_mode *mode)
-{
- u32 vactive, vsa, vfp, vbp;
-
- vactive = mode->vdisplay;
- vsa = mode->vsync_end - mode->vsync_start;
- vfp = mode->vsync_start - mode->vdisplay;
- vbp = mode->vtotal - mode->vsync_end;
-
- dsi_write(dsi, DSI_VID_VACTIVE_LINES, vactive);
- dsi_write(dsi, DSI_VID_VSA_LINES, vsa);
- dsi_write(dsi, DSI_VID_VFP_LINES, vfp);
- dsi_write(dsi, DSI_VID_VBP_LINES, vbp);
-}
-
-static void dw_mipi_dsi_dphy_timing_config(struct dw_mipi_dsi *dsi)
-{
- dsi_write(dsi, DSI_PHY_TMR_CFG, PHY_HS2LP_TIME(0x40)
- | PHY_LP2HS_TIME(0x40) | MAX_RD_TIME(10000));
-
- dsi_write(dsi, DSI_PHY_TMR_LPCLK_CFG, PHY_CLKHS2LP_TIME(0x40)
- | PHY_CLKLP2HS_TIME(0x40));
-}
-
-static void dw_mipi_dsi_dphy_interface_config(struct dw_mipi_dsi *dsi)
-{
- dsi_write(dsi, DSI_PHY_IF_CFG, PHY_STOP_WAIT_TIME(0x20) |
- N_LANES(dsi->lanes));
-}
-
-static void dw_mipi_dsi_clear_err(struct dw_mipi_dsi *dsi)
-{
- dsi_read(dsi, DSI_INT_ST0);
- dsi_read(dsi, DSI_INT_ST1);
- dsi_write(dsi, DSI_INT_MSK0, 0);
- dsi_write(dsi, DSI_INT_MSK1, 0);
-}
-
-static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder)
-{
- struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
-
- if (dsi->dpms_mode != DRM_MODE_DPMS_ON)
- return;
-
- if (clk_prepare_enable(dsi->pclk)) {
- DRM_DEV_ERROR(dsi->dev, "Failed to enable pclk\n");
- return;
- }
-
- drm_panel_disable(dsi->panel);
-
- dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_CMD_MODE);
- drm_panel_unprepare(dsi->panel);
-
- dw_mipi_dsi_disable(dsi);
- pm_runtime_put(dsi->dev);
- clk_disable_unprepare(dsi->pclk);
- dsi->dpms_mode = DRM_MODE_DPMS_OFF;
-}
-
-static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
-{
- struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
- struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
- const struct dw_mipi_dsi_plat_data *pdata = dsi->pdata;
- int mux = drm_of_encoder_active_endpoint_id(dsi->dev->of_node, encoder);
- u32 val;
- int ret;
-
- ret = dw_mipi_dsi_get_lane_bps(dsi, mode);
- if (ret < 0)
- return;
-
- if (dsi->dpms_mode == DRM_MODE_DPMS_ON)
- return;
-
- if (clk_prepare_enable(dsi->pclk)) {
- DRM_DEV_ERROR(dsi->dev, "Failed to enable pclk\n");
- return;
- }
-
- pm_runtime_get_sync(dsi->dev);
- dw_mipi_dsi_init(dsi);
- dw_mipi_dsi_dpi_config(dsi, mode);
- dw_mipi_dsi_packet_handler_config(dsi);
- dw_mipi_dsi_video_mode_config(dsi);
- dw_mipi_dsi_video_packet_config(dsi, mode);
- dw_mipi_dsi_command_mode_config(dsi);
- dw_mipi_dsi_line_timer_config(dsi, mode);
- dw_mipi_dsi_vertical_timing_config(dsi, mode);
- dw_mipi_dsi_dphy_timing_config(dsi);
- dw_mipi_dsi_dphy_interface_config(dsi);
- dw_mipi_dsi_clear_err(dsi);
-
- /*
- * For the RK3399, the clk of grf must be enabled before writing grf
- * register. And for RK3288 or other soc, this grf_clk must be NULL,
- * the clk_prepare_enable return true directly.
- */
- ret = clk_prepare_enable(dsi->grf_clk);
- if (ret) {
- DRM_DEV_ERROR(dsi->dev, "Failed to enable grf_clk: %d\n", ret);
- return;
- }
-
- if (pdata->grf_dsi0_mode_reg)
- regmap_write(dsi->grf_regmap, pdata->grf_dsi0_mode_reg,
- pdata->grf_dsi0_mode);
-
- dw_mipi_dsi_phy_init(dsi);
- dw_mipi_dsi_wait_for_two_frames(mode);
-
- dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_CMD_MODE);
- if (drm_panel_prepare(dsi->panel))
- DRM_DEV_ERROR(dsi->dev, "failed to prepare panel\n");
-
- dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_VID_MODE);
- drm_panel_enable(dsi->panel);
-
- clk_disable_unprepare(dsi->pclk);
-
- if (mux)
- val = pdata->dsi0_en_bit | (pdata->dsi0_en_bit << 16);
- else
- val = pdata->dsi0_en_bit << 16;
-
- regmap_write(dsi->grf_regmap, pdata->grf_switch_reg, val);
- DRM_DEV_DEBUG(dsi->dev,
- "vop %s output to dsi0\n", (mux) ? "LIT" : "BIG");
- dsi->dpms_mode = DRM_MODE_DPMS_ON;
-
- clk_disable_unprepare(dsi->grf_clk);
-}
-
-static int
-dw_mipi_dsi_encoder_atomic_check(struct drm_encoder *encoder,
- struct drm_crtc_state *crtc_state,
- struct drm_connector_state *conn_state)
-{
- struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
- struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
-
- switch (dsi->format) {
- case MIPI_DSI_FMT_RGB888:
- s->output_mode = ROCKCHIP_OUT_MODE_P888;
- break;
- case MIPI_DSI_FMT_RGB666:
- s->output_mode = ROCKCHIP_OUT_MODE_P666;
- break;
- case MIPI_DSI_FMT_RGB565:
- s->output_mode = ROCKCHIP_OUT_MODE_P565;
- break;
- default:
- WARN_ON(1);
- return -EINVAL;
- }
-
- s->output_type = DRM_MODE_CONNECTOR_DSI;
-
- return 0;
-}
-
-static const struct drm_encoder_helper_funcs
-dw_mipi_dsi_encoder_helper_funcs = {
- .enable = dw_mipi_dsi_encoder_enable,
- .disable = dw_mipi_dsi_encoder_disable,
- .atomic_check = dw_mipi_dsi_encoder_atomic_check,
-};
-
-static const struct drm_encoder_funcs dw_mipi_dsi_encoder_funcs = {
- .destroy = drm_encoder_cleanup,
-};
-
-static int dw_mipi_dsi_connector_get_modes(struct drm_connector *connector)
-{
- struct dw_mipi_dsi *dsi = con_to_dsi(connector);
-
- return drm_panel_get_modes(dsi->panel);
-}
-
-static struct drm_connector_helper_funcs dw_mipi_dsi_connector_helper_funcs = {
- .get_modes = dw_mipi_dsi_connector_get_modes,
-};
-
-static void dw_mipi_dsi_drm_connector_destroy(struct drm_connector *connector)
-{
- drm_connector_unregister(connector);
- drm_connector_cleanup(connector);
-}
-
-static const struct drm_connector_funcs dw_mipi_dsi_atomic_connector_funcs = {
- .fill_modes = drm_helper_probe_single_connector_modes,
- .destroy = dw_mipi_dsi_drm_connector_destroy,
- .reset = drm_atomic_helper_connector_reset,
- .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-};
-
-static int dw_mipi_dsi_register(struct drm_device *drm,
- struct dw_mipi_dsi *dsi)
-{
- struct drm_encoder *encoder = &dsi->encoder;
- struct drm_connector *connector = &dsi->connector;
- struct device *dev = dsi->dev;
- int ret;
-
- encoder->possible_crtcs = drm_of_find_possible_crtcs(drm,
- dev->of_node);
- /*
- * If we failed to find the CRTC(s) which this encoder is
- * supposed to be connected to, it's because the CRTC has
- * not been registered yet. Defer probing, and hope that
- * the required CRTC is added later.
- */
- if (encoder->possible_crtcs == 0)
- return -EPROBE_DEFER;
-
- drm_encoder_helper_add(&dsi->encoder,
- &dw_mipi_dsi_encoder_helper_funcs);
- ret = drm_encoder_init(drm, &dsi->encoder, &dw_mipi_dsi_encoder_funcs,
- DRM_MODE_ENCODER_DSI, NULL);
- if (ret) {
- DRM_DEV_ERROR(dev, "Failed to initialize encoder with drm\n");
- return ret;
- }
-
- drm_connector_helper_add(connector,
- &dw_mipi_dsi_connector_helper_funcs);
-
- drm_connector_init(drm, &dsi->connector,
- &dw_mipi_dsi_atomic_connector_funcs,
- DRM_MODE_CONNECTOR_DSI);
-
- drm_connector_attach_encoder(connector, encoder);
-
- return 0;
-}
-
-static int rockchip_mipi_parse_dt(struct dw_mipi_dsi *dsi)
-{
- struct device_node *np = dsi->dev->of_node;
-
- dsi->grf_regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
- if (IS_ERR(dsi->grf_regmap)) {
- DRM_DEV_ERROR(dsi->dev, "Unable to get rockchip,grf\n");
- return PTR_ERR(dsi->grf_regmap);
- }
-
- return 0;
-}
-
-static struct dw_mipi_dsi_plat_data rk3288_mipi_dsi_drv_data = {
- .dsi0_en_bit = RK3288_DSI0_SEL_VOP_LIT,
- .dsi1_en_bit = RK3288_DSI1_SEL_VOP_LIT,
- .grf_switch_reg = RK3288_GRF_SOC_CON6,
- .max_data_lanes = 4,
-};
-
-static struct dw_mipi_dsi_plat_data rk3399_mipi_dsi_drv_data = {
- .dsi0_en_bit = RK3399_DSI0_SEL_VOP_LIT,
- .dsi1_en_bit = RK3399_DSI1_SEL_VOP_LIT,
- .grf_switch_reg = RK3399_GRF_SOC_CON20,
- .grf_dsi0_mode = RK3399_GRF_DSI_MODE,
- .grf_dsi0_mode_reg = RK3399_GRF_SOC_CON22,
- .flags = DW_MIPI_NEEDS_PHY_CFG_CLK | DW_MIPI_NEEDS_GRF_CLK,
- .max_data_lanes = 4,
-};
-
-static const struct of_device_id dw_mipi_dsi_dt_ids[] = {
- {
- .compatible = "rockchip,rk3288-mipi-dsi",
- .data = &rk3288_mipi_dsi_drv_data,
- }, {
- .compatible = "rockchip,rk3399-mipi-dsi",
- .data = &rk3399_mipi_dsi_drv_data,
- },
- { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, dw_mipi_dsi_dt_ids);
-
-static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
- void *data)
-{
- const struct of_device_id *of_id =
- of_match_device(dw_mipi_dsi_dt_ids, dev);
- const struct dw_mipi_dsi_plat_data *pdata = of_id->data;
- struct platform_device *pdev = to_platform_device(dev);
- struct reset_control *apb_rst;
- struct drm_device *drm = data;
- struct dw_mipi_dsi *dsi;
- struct resource *res;
- int ret;
-
- dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
- if (!dsi)
- return -ENOMEM;
-
- dsi->dev = dev;
- dsi->pdata = pdata;
- dsi->dpms_mode = DRM_MODE_DPMS_OFF;
-
- ret = rockchip_mipi_parse_dt(dsi);
- if (ret)
- return ret;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- dsi->base = devm_ioremap_resource(dev, res);
- if (IS_ERR(dsi->base))
- return PTR_ERR(dsi->base);
-
- dsi->pllref_clk = devm_clk_get(dev, "ref");
- if (IS_ERR(dsi->pllref_clk)) {
- ret = PTR_ERR(dsi->pllref_clk);
- DRM_DEV_ERROR(dev,
- "Unable to get pll reference clock: %d\n", ret);
- return ret;
- }
-
- dsi->pclk = devm_clk_get(dev, "pclk");
- if (IS_ERR(dsi->pclk)) {
- ret = PTR_ERR(dsi->pclk);
- DRM_DEV_ERROR(dev, "Unable to get pclk: %d\n", ret);
- return ret;
- }
-
- /*
- * Note that the reset was not defined in the initial device tree, so
- * we have to be prepared for it not being found.
- */
- apb_rst = devm_reset_control_get(dev, "apb");
- if (IS_ERR(apb_rst)) {
- ret = PTR_ERR(apb_rst);
- if (ret == -ENOENT) {
- apb_rst = NULL;
- } else {
- DRM_DEV_ERROR(dev,
- "Unable to get reset control: %d\n", ret);
- return ret;
- }
- }
-
- if (apb_rst) {
- ret = clk_prepare_enable(dsi->pclk);
- if (ret) {
- DRM_DEV_ERROR(dev, "Failed to enable pclk\n");
- return ret;
- }
-
- reset_control_assert(apb_rst);
- usleep_range(10, 20);
- reset_control_deassert(apb_rst);
-
- clk_disable_unprepare(dsi->pclk);
- }
-
- if (pdata->flags & DW_MIPI_NEEDS_PHY_CFG_CLK) {
- dsi->phy_cfg_clk = devm_clk_get(dev, "phy_cfg");
- if (IS_ERR(dsi->phy_cfg_clk)) {
- ret = PTR_ERR(dsi->phy_cfg_clk);
- DRM_DEV_ERROR(dev,
- "Unable to get phy_cfg_clk: %d\n", ret);
- return ret;
- }
- }
-
- if (pdata->flags & DW_MIPI_NEEDS_GRF_CLK) {
- dsi->grf_clk = devm_clk_get(dev, "grf");
- if (IS_ERR(dsi->grf_clk)) {
- ret = PTR_ERR(dsi->grf_clk);
- DRM_DEV_ERROR(dev, "Unable to get grf_clk: %d\n", ret);
- return ret;
- }
- }
-
- ret = clk_prepare_enable(dsi->pllref_clk);
- if (ret) {
- DRM_DEV_ERROR(dev, "Failed to enable pllref_clk\n");
- return ret;
- }
-
- ret = dw_mipi_dsi_register(drm, dsi);
- if (ret) {
- DRM_DEV_ERROR(dev, "Failed to register mipi_dsi: %d\n", ret);
- goto err_pllref;
- }
-
- dsi->dsi_host.ops = &dw_mipi_dsi_host_ops;
- dsi->dsi_host.dev = dev;
- ret = mipi_dsi_host_register(&dsi->dsi_host);
- if (ret) {
- DRM_DEV_ERROR(dev, "Failed to register MIPI host: %d\n", ret);
- goto err_cleanup;
- }
-
- if (!dsi->panel) {
- ret = -EPROBE_DEFER;
- goto err_mipi_dsi_host;
- }
-
- dev_set_drvdata(dev, dsi);
- pm_runtime_enable(dev);
- return 0;
-
-err_mipi_dsi_host:
- mipi_dsi_host_unregister(&dsi->dsi_host);
-err_cleanup:
- dsi->connector.funcs->destroy(&dsi->connector);
- dsi->encoder.funcs->destroy(&dsi->encoder);
-err_pllref:
- clk_disable_unprepare(dsi->pllref_clk);
- return ret;
-}
-
-static void dw_mipi_dsi_unbind(struct device *dev, struct device *master,
- void *data)
-{
- struct dw_mipi_dsi *dsi = dev_get_drvdata(dev);
-
- mipi_dsi_host_unregister(&dsi->dsi_host);
- pm_runtime_disable(dev);
-
- dsi->connector.funcs->destroy(&dsi->connector);
- dsi->encoder.funcs->destroy(&dsi->encoder);
-
- clk_disable_unprepare(dsi->pllref_clk);
-}
-
-static const struct component_ops dw_mipi_dsi_ops = {
- .bind = dw_mipi_dsi_bind,
- .unbind = dw_mipi_dsi_unbind,
-};
-
-static int dw_mipi_dsi_probe(struct platform_device *pdev)
-{
- return component_add(&pdev->dev, &dw_mipi_dsi_ops);
-}
-
-static int dw_mipi_dsi_remove(struct platform_device *pdev)
-{
- component_del(&pdev->dev, &dw_mipi_dsi_ops);
- return 0;
-}
-
-struct platform_driver dw_mipi_dsi_driver = {
- .probe = dw_mipi_dsi_probe,
- .remove = dw_mipi_dsi_remove,
- .driver = {
- .of_match_table = dw_mipi_dsi_dt_ids,
- .name = DRIVER_NAME,
- },
-};
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index 11309a2a4e43..89c63cfde5c8 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -11,6 +11,7 @@
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/phy/phy.h>
#include <linux/regmap.h>
#include <drm/drm_of.h>
@@ -24,6 +25,24 @@
#define RK3288_GRF_SOC_CON6 0x025C
#define RK3288_HDMI_LCDC_SEL BIT(4)
+#define RK3328_GRF_SOC_CON2 0x0408
+
+#define RK3328_HDMI_SDAIN_MSK BIT(11)
+#define RK3328_HDMI_SCLIN_MSK BIT(10)
+#define RK3328_HDMI_HPD_IOE BIT(2)
+#define RK3328_GRF_SOC_CON3 0x040c
+/* need to be unset if hdmi or i2c should control voltage */
+#define RK3328_HDMI_SDA5V_GRF BIT(15)
+#define RK3328_HDMI_SCL5V_GRF BIT(14)
+#define RK3328_HDMI_HPD5V_GRF BIT(13)
+#define RK3328_HDMI_CEC5V_GRF BIT(12)
+#define RK3328_GRF_SOC_CON4 0x0410
+#define RK3328_HDMI_HPD_SARADC BIT(13)
+#define RK3328_HDMI_CEC_5V BIT(11)
+#define RK3328_HDMI_SDA_5V BIT(10)
+#define RK3328_HDMI_SCL_5V BIT(9)
+#define RK3328_HDMI_HPD_5V BIT(8)
+
#define RK3399_GRF_SOC_CON20 0x6250
#define RK3399_HDMI_LCDC_SEL BIT(6)
@@ -36,7 +55,7 @@
* @lcdsel_lit: reg value of selecting vop little for HDMI
*/
struct rockchip_hdmi_chip_data {
- u32 lcdsel_grf_reg;
+ int lcdsel_grf_reg;
u32 lcdsel_big;
u32 lcdsel_lit;
};
@@ -49,6 +68,7 @@ struct rockchip_hdmi {
struct clk *vpll_clk;
struct clk *grf_clk;
struct dw_hdmi *hdmi;
+ struct phy *phy;
};
#define to_rockchip_hdmi(x) container_of(x, struct rockchip_hdmi, x)
@@ -245,6 +265,9 @@ static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder)
u32 val;
int ret;
+ if (hdmi->chip_data->lcdsel_grf_reg < 0)
+ return;
+
ret = drm_of_encoder_active_endpoint_id(hdmi->dev->of_node, encoder);
if (ret)
val = hdmi->chip_data->lcdsel_lit;
@@ -287,6 +310,66 @@ static const struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_fun
.atomic_check = dw_hdmi_rockchip_encoder_atomic_check,
};
+static int dw_hdmi_rockchip_genphy_init(struct dw_hdmi *dw_hdmi, void *data,
+ struct drm_display_mode *mode)
+{
+ struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
+
+ return phy_power_on(hdmi->phy);
+}
+
+static void dw_hdmi_rockchip_genphy_disable(struct dw_hdmi *dw_hdmi, void *data)
+{
+ struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
+
+ phy_power_off(hdmi->phy);
+}
+
+static enum drm_connector_status
+dw_hdmi_rk3328_read_hpd(struct dw_hdmi *dw_hdmi, void *data)
+{
+ struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
+ enum drm_connector_status status;
+
+ status = dw_hdmi_phy_read_hpd(dw_hdmi, data);
+
+ if (status == connector_status_connected)
+ regmap_write(hdmi->regmap,
+ RK3328_GRF_SOC_CON4,
+ HIWORD_UPDATE(RK3328_HDMI_SDA_5V | RK3328_HDMI_SCL_5V,
+ RK3328_HDMI_SDA_5V | RK3328_HDMI_SCL_5V));
+ else
+ regmap_write(hdmi->regmap,
+ RK3328_GRF_SOC_CON4,
+ HIWORD_UPDATE(0, RK3328_HDMI_SDA_5V |
+ RK3328_HDMI_SCL_5V));
+ return status;
+}
+
+static void dw_hdmi_rk3328_setup_hpd(struct dw_hdmi *dw_hdmi, void *data)
+{
+ struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
+
+ dw_hdmi_phy_setup_hpd(dw_hdmi, data);
+
+ /* Enable and map pins to 3V grf-controlled io-voltage */
+ regmap_write(hdmi->regmap,
+ RK3328_GRF_SOC_CON4,
+ HIWORD_UPDATE(0, RK3328_HDMI_HPD_SARADC | RK3328_HDMI_CEC_5V |
+ RK3328_HDMI_SDA_5V | RK3328_HDMI_SCL_5V |
+ RK3328_HDMI_HPD_5V));
+ regmap_write(hdmi->regmap,
+ RK3328_GRF_SOC_CON3,
+ HIWORD_UPDATE(0, RK3328_HDMI_SDA5V_GRF | RK3328_HDMI_SCL5V_GRF |
+ RK3328_HDMI_HPD5V_GRF |
+ RK3328_HDMI_CEC5V_GRF));
+ regmap_write(hdmi->regmap,
+ RK3328_GRF_SOC_CON2,
+ HIWORD_UPDATE(RK3328_HDMI_SDAIN_MSK | RK3328_HDMI_SCLIN_MSK,
+ RK3328_HDMI_SDAIN_MSK | RK3328_HDMI_SCLIN_MSK |
+ RK3328_HDMI_HPD_IOE));
+}
+
static struct rockchip_hdmi_chip_data rk3288_chip_data = {
.lcdsel_grf_reg = RK3288_GRF_SOC_CON6,
.lcdsel_big = HIWORD_UPDATE(0, RK3288_HDMI_LCDC_SEL),
@@ -301,6 +384,29 @@ static const struct dw_hdmi_plat_data rk3288_hdmi_drv_data = {
.phy_data = &rk3288_chip_data,
};
+static const struct dw_hdmi_phy_ops rk3328_hdmi_phy_ops = {
+ .init = dw_hdmi_rockchip_genphy_init,
+ .disable = dw_hdmi_rockchip_genphy_disable,
+ .read_hpd = dw_hdmi_rk3328_read_hpd,
+ .update_hpd = dw_hdmi_phy_update_hpd,
+ .setup_hpd = dw_hdmi_rk3328_setup_hpd,
+};
+
+static struct rockchip_hdmi_chip_data rk3328_chip_data = {
+ .lcdsel_grf_reg = -1,
+};
+
+static const struct dw_hdmi_plat_data rk3328_hdmi_drv_data = {
+ .mode_valid = dw_hdmi_rockchip_mode_valid,
+ .mpll_cfg = rockchip_mpll_cfg,
+ .cur_ctr = rockchip_cur_ctr,
+ .phy_config = rockchip_phy_config,
+ .phy_data = &rk3328_chip_data,
+ .phy_ops = &rk3328_hdmi_phy_ops,
+ .phy_name = "inno_dw_hdmi_phy2",
+ .phy_force_vendor = true,
+};
+
static struct rockchip_hdmi_chip_data rk3399_chip_data = {
.lcdsel_grf_reg = RK3399_GRF_SOC_CON20,
.lcdsel_big = HIWORD_UPDATE(0, RK3399_HDMI_LCDC_SEL),
@@ -319,6 +425,9 @@ static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = {
{ .compatible = "rockchip,rk3288-dw-hdmi",
.data = &rk3288_hdmi_drv_data
},
+ { .compatible = "rockchip,rk3328-dw-hdmi",
+ .data = &rk3328_hdmi_drv_data
+ },
{ .compatible = "rockchip,rk3399-dw-hdmi",
.data = &rk3399_hdmi_drv_data
},
@@ -330,7 +439,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
void *data)
{
struct platform_device *pdev = to_platform_device(dev);
- const struct dw_hdmi_plat_data *plat_data;
+ struct dw_hdmi_plat_data *plat_data;
const struct of_device_id *match;
struct drm_device *drm = data;
struct drm_encoder *encoder;
@@ -345,9 +454,14 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
return -ENOMEM;
match = of_match_node(dw_hdmi_rockchip_dt_ids, pdev->dev.of_node);
- plat_data = match->data;
+ plat_data = devm_kmemdup(&pdev->dev, match->data,
+ sizeof(*plat_data), GFP_KERNEL);
+ if (!plat_data)
+ return -ENOMEM;
+
hdmi->dev = &pdev->dev;
hdmi->chip_data = plat_data->phy_data;
+ plat_data->phy_data = hdmi;
encoder = &hdmi->encoder;
encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
@@ -373,6 +487,14 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
return ret;
}
+ hdmi->phy = devm_phy_optional_get(dev, "hdmi");
+ if (IS_ERR(hdmi->phy)) {
+ ret = PTR_ERR(hdmi->phy);
+ if (ret != -EPROBE_DEFER)
+ DRM_DEV_ERROR(hdmi->dev, "failed to get phy\n");
+ return ret;
+ }
+
drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs);
drm_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs,
DRM_MODE_ENCODER_TMDS, NULL);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index 941f35233b1f..37f9a3b651ab 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -489,7 +489,7 @@ static int __init rockchip_drm_init(void)
ADD_ROCKCHIP_SUB_DRIVER(cdn_dp_driver, CONFIG_ROCKCHIP_CDN_DP);
ADD_ROCKCHIP_SUB_DRIVER(dw_hdmi_rockchip_pltfm_driver,
CONFIG_ROCKCHIP_DW_HDMI);
- ADD_ROCKCHIP_SUB_DRIVER(dw_mipi_dsi_driver,
+ ADD_ROCKCHIP_SUB_DRIVER(dw_mipi_dsi_rockchip_driver,
CONFIG_ROCKCHIP_DW_MIPI_DSI);
ADD_ROCKCHIP_SUB_DRIVER(inno_hdmi_driver, CONFIG_ROCKCHIP_INNO_HDMI);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index 21a023a97bb8..ce48568ec8a0 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -37,6 +37,7 @@ struct rockchip_crtc_state {
int output_type;
int output_mode;
int output_bpc;
+ int output_flags;
};
#define to_rockchip_crtc_state(s) \
container_of(s, struct rockchip_crtc_state, base)
@@ -67,7 +68,7 @@ int rockchip_drm_wait_vact_end(struct drm_crtc *crtc, unsigned int mstimeout);
int rockchip_drm_endpoint_is_subdriver(struct device_node *ep);
extern struct platform_driver cdn_dp_driver;
extern struct platform_driver dw_hdmi_rockchip_pltfm_driver;
-extern struct platform_driver dw_mipi_dsi_driver;
+extern struct platform_driver dw_mipi_dsi_rockchip_driver;
extern struct platform_driver inno_hdmi_driver;
extern struct platform_driver rockchip_dp_driver;
extern struct platform_driver rockchip_lvds_driver;
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c
index 79d00d861a31..01ff3c858875 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c
@@ -189,12 +189,14 @@ EXPORT_SYMBOL(rockchip_drm_psr_flush_all);
int rockchip_drm_psr_register(struct drm_encoder *encoder,
int (*psr_set)(struct drm_encoder *, bool enable))
{
- struct rockchip_drm_private *drm_drv = encoder->dev->dev_private;
+ struct rockchip_drm_private *drm_drv;
struct psr_drv *psr;
if (!encoder || !psr_set)
return -EINVAL;
+ drm_drv = encoder->dev->dev_private;
+
psr = kzalloc(sizeof(struct psr_drv), GFP_KERNEL);
if (!psr)
return -ENOMEM;
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index 0c35a88e33dd..fb70fb486fbf 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -916,6 +916,7 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc,
pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) ?
BIT(VSYNC_POSITIVE) : 0;
VOP_REG_SET(vop, output, pin_pol, pin_pol);
+ VOP_REG_SET(vop, output, mipi_dual_channel_en, 0);
switch (s->output_type) {
case DRM_MODE_CONNECTOR_LVDS:
@@ -933,6 +934,8 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc,
case DRM_MODE_CONNECTOR_DSI:
VOP_REG_SET(vop, output, mipi_pin_pol, pin_pol);
VOP_REG_SET(vop, output, mipi_en, 1);
+ VOP_REG_SET(vop, output, mipi_dual_channel_en,
+ !!(s->output_flags & ROCKCHIP_OUTPUT_DSI_DUAL));
break;
case DRM_MODE_CONNECTOR_DisplayPort:
pin_pol &= ~BIT(DCLK_INVERT);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
index fd5765dfd637..0fe40e1983d9 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
@@ -60,6 +60,7 @@ struct vop_output {
struct vop_reg edp_en;
struct vop_reg hdmi_en;
struct vop_reg mipi_en;
+ struct vop_reg mipi_dual_channel_en;
struct vop_reg rgb_en;
};
@@ -214,6 +215,9 @@ struct vop_data {
/* for use special outface */
#define ROCKCHIP_OUT_MODE_AAAA 15
+/* output flags */
+#define ROCKCHIP_OUTPUT_DSI_DUAL BIT(0)
+
enum alpha_mode {
ALPHA_STRAIGHT,
ALPHA_INVERSE,
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
index a6db3cd5544b..08fc40af52c8 100644
--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
+++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
@@ -361,7 +361,11 @@ static const struct vop_win_data rk3188_vop_win_data[] = {
};
static const int rk3188_vop_intrs[] = {
- 0,
+ /*
+ * hs_start interrupt fires at frame-start, so serves
+ * the same purpose as dsp_hold in the driver.
+ */
+ DSP_HOLD_VALID_INTR,
FS_INTR,
LINE_FLAG_INTR,
BUS_ERROR_INTR,
@@ -630,6 +634,7 @@ static const struct vop_output rk3399_output = {
.hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13),
.edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14),
.mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15),
+ .mipi_dual_channel_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 3),
};
static const struct vop_data rk3399_vop_big = {
diff --git a/drivers/gpu/drm/scheduler/sched_entity.c b/drivers/gpu/drm/scheduler/sched_entity.c
index 3e22a54a99c2..4463d3826ecb 100644
--- a/drivers/gpu/drm/scheduler/sched_entity.c
+++ b/drivers/gpu/drm/scheduler/sched_entity.c
@@ -130,7 +130,14 @@ drm_sched_entity_get_free_sched(struct drm_sched_entity *entity)
int i;
for (i = 0; i < entity->num_rq_list; ++i) {
- num_jobs = atomic_read(&entity->rq_list[i]->sched->num_jobs);
+ struct drm_gpu_scheduler *sched = entity->rq_list[i]->sched;
+
+ if (!entity->rq_list[i]->sched->ready) {
+ DRM_WARN("sched%s is not ready, skipping", sched->name);
+ continue;
+ }
+
+ num_jobs = atomic_read(&sched->num_jobs);
if (num_jobs < min_jobs) {
min_jobs = num_jobs;
rq = entity->rq_list[i];
@@ -204,7 +211,6 @@ static void drm_sched_entity_kill_jobs_cb(struct dma_fence *f,
drm_sched_fence_finished(job->s_fence);
WARN_ON(job->s_fence->parent);
- dma_fence_put(&job->s_fence->finished);
job->sched->ops->free_job(job);
}
diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c
index 44fe587aaef9..18ebbb05762e 100644
--- a/drivers/gpu/drm/scheduler/sched_main.c
+++ b/drivers/gpu/drm/scheduler/sched_main.c
@@ -196,6 +196,19 @@ static void drm_sched_start_timeout(struct drm_gpu_scheduler *sched)
schedule_delayed_work(&sched->work_tdr, sched->timeout);
}
+/**
+ * drm_sched_fault - immediately start timeout handler
+ *
+ * @sched: scheduler where the timeout handling should be started.
+ *
+ * Start timeout handling immediately when the driver detects a hardware fault.
+ */
+void drm_sched_fault(struct drm_gpu_scheduler *sched)
+{
+ mod_delayed_work(system_wq, &sched->work_tdr, 0);
+}
+EXPORT_SYMBOL(drm_sched_fault);
+
/* job_finish is called after hw fence signaled
*/
static void drm_sched_job_finish(struct work_struct *work)
@@ -220,7 +233,6 @@ static void drm_sched_job_finish(struct work_struct *work)
drm_sched_start_timeout(sched);
spin_unlock(&sched->job_list_lock);
- dma_fence_put(&s_job->s_fence->finished);
sched->ops->free_job(s_job);
}
@@ -283,6 +295,7 @@ static void drm_sched_job_timedout(struct work_struct *work)
already_signaled:
;
}
+ drm_sched_start_timeout(sched);
spin_unlock(&sched->job_list_lock);
}
@@ -406,6 +419,9 @@ int drm_sched_job_init(struct drm_sched_job *job,
struct drm_gpu_scheduler *sched;
drm_sched_entity_select_rq(entity);
+ if (!entity->rq)
+ return -ENOENT;
+
sched = entity->rq->sched;
job->sched = sched;
@@ -424,6 +440,18 @@ int drm_sched_job_init(struct drm_sched_job *job,
EXPORT_SYMBOL(drm_sched_job_init);
/**
+ * drm_sched_job_cleanup - clean up scheduler job resources
+ *
+ * @job: scheduler job to clean up
+ */
+void drm_sched_job_cleanup(struct drm_sched_job *job)
+{
+ dma_fence_put(&job->s_fence->finished);
+ job->s_fence = NULL;
+}
+EXPORT_SYMBOL(drm_sched_job_cleanup);
+
+/**
* drm_sched_ready - is the scheduler ready
*
* @sched: scheduler instance
@@ -619,6 +647,7 @@ int drm_sched_init(struct drm_gpu_scheduler *sched,
return PTR_ERR(sched->thread);
}
+ sched->ready = true;
return 0;
}
EXPORT_SYMBOL(drm_sched_init);
@@ -634,5 +663,7 @@ void drm_sched_fini(struct drm_gpu_scheduler *sched)
{
if (sched->thread)
kthread_stop(sched->thread);
+
+ sched->ready = false;
}
EXPORT_SYMBOL(drm_sched_fini);
diff --git a/drivers/gpu/drm/selftests/Makefile b/drivers/gpu/drm/selftests/Makefile
index 9fc349fa18e9..383d8d6c5847 100644
--- a/drivers/gpu/drm/selftests/Makefile
+++ b/drivers/gpu/drm/selftests/Makefile
@@ -1 +1,4 @@
-obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm-helper.o
+test-drm_modeset-y := test-drm_modeset_common.o test-drm_plane_helper.o \
+ test-drm_format.o test-drm_framebuffer.o
+
+obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o
diff --git a/drivers/gpu/drm/selftests/drm_helper_selftests.h b/drivers/gpu/drm/selftests/drm_modeset_selftests.h
index 9771290ed228..92601defd8f6 100644
--- a/drivers/gpu/drm/selftests/drm_helper_selftests.h
+++ b/drivers/gpu/drm/selftests/drm_modeset_selftests.h
@@ -7,3 +7,7 @@
* Tests are executed in order by igt/drm_selftests_helper
*/
selftest(check_plane_state, igt_check_plane_state)
+selftest(check_drm_format_block_width, igt_check_drm_format_block_width)
+selftest(check_drm_format_block_height, igt_check_drm_format_block_height)
+selftest(check_drm_format_min_pitch, igt_check_drm_format_min_pitch)
+selftest(check_drm_framebuffer_create, igt_check_drm_framebuffer_create)
diff --git a/drivers/gpu/drm/selftests/test-drm_format.c b/drivers/gpu/drm/selftests/test-drm_format.c
new file mode 100644
index 000000000000..c5e212afa27a
--- /dev/null
+++ b/drivers/gpu/drm/selftests/test-drm_format.c
@@ -0,0 +1,280 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Test cases for the drm_format functions
+ */
+
+#define pr_fmt(fmt) "drm_format: " fmt
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+
+#include <drm/drm_fourcc.h>
+
+#include "test-drm_modeset_common.h"
+
+int igt_check_drm_format_block_width(void *ignored)
+{
+ const struct drm_format_info *info = NULL;
+
+ /* Test invalid arguments */
+ FAIL_ON(drm_format_info_block_width(info, 0) != 0);
+ FAIL_ON(drm_format_info_block_width(info, -1) != 0);
+ FAIL_ON(drm_format_info_block_width(info, 1) != 0);
+
+ /* Test 1 plane format */
+ info = drm_format_info(DRM_FORMAT_XRGB4444);
+ FAIL_ON(!info);
+ FAIL_ON(drm_format_info_block_width(info, 0) != 1);
+ FAIL_ON(drm_format_info_block_width(info, 1) != 0);
+ FAIL_ON(drm_format_info_block_width(info, -1) != 0);
+
+ /* Test 2 planes format */
+ info = drm_format_info(DRM_FORMAT_NV12);
+ FAIL_ON(!info);
+ FAIL_ON(drm_format_info_block_width(info, 0) != 1);
+ FAIL_ON(drm_format_info_block_width(info, 1) != 1);
+ FAIL_ON(drm_format_info_block_width(info, 2) != 0);
+ FAIL_ON(drm_format_info_block_width(info, -1) != 0);
+
+ /* Test 3 planes format */
+ info = drm_format_info(DRM_FORMAT_YUV422);
+ FAIL_ON(!info);
+ FAIL_ON(drm_format_info_block_width(info, 0) != 1);
+ FAIL_ON(drm_format_info_block_width(info, 1) != 1);
+ FAIL_ON(drm_format_info_block_width(info, 2) != 1);
+ FAIL_ON(drm_format_info_block_width(info, 3) != 0);
+ FAIL_ON(drm_format_info_block_width(info, -1) != 0);
+
+ /* Test a tiled format */
+ info = drm_format_info(DRM_FORMAT_X0L0);
+ FAIL_ON(!info);
+ FAIL_ON(drm_format_info_block_width(info, 0) != 2);
+ FAIL_ON(drm_format_info_block_width(info, 1) != 0);
+ FAIL_ON(drm_format_info_block_width(info, -1) != 0);
+
+ return 0;
+}
+
+int igt_check_drm_format_block_height(void *ignored)
+{
+ const struct drm_format_info *info = NULL;
+
+ /* Test invalid arguments */
+ FAIL_ON(drm_format_info_block_height(info, 0) != 0);
+ FAIL_ON(drm_format_info_block_height(info, -1) != 0);
+ FAIL_ON(drm_format_info_block_height(info, 1) != 0);
+
+ /* Test 1 plane format */
+ info = drm_format_info(DRM_FORMAT_XRGB4444);
+ FAIL_ON(!info);
+ FAIL_ON(drm_format_info_block_height(info, 0) != 1);
+ FAIL_ON(drm_format_info_block_height(info, 1) != 0);
+ FAIL_ON(drm_format_info_block_height(info, -1) != 0);
+
+ /* Test 2 planes format */
+ info = drm_format_info(DRM_FORMAT_NV12);
+ FAIL_ON(!info);
+ FAIL_ON(drm_format_info_block_height(info, 0) != 1);
+ FAIL_ON(drm_format_info_block_height(info, 1) != 1);
+ FAIL_ON(drm_format_info_block_height(info, 2) != 0);
+ FAIL_ON(drm_format_info_block_height(info, -1) != 0);
+
+ /* Test 3 planes format */
+ info = drm_format_info(DRM_FORMAT_YUV422);
+ FAIL_ON(!info);
+ FAIL_ON(drm_format_info_block_height(info, 0) != 1);
+ FAIL_ON(drm_format_info_block_height(info, 1) != 1);
+ FAIL_ON(drm_format_info_block_height(info, 2) != 1);
+ FAIL_ON(drm_format_info_block_height(info, 3) != 0);
+ FAIL_ON(drm_format_info_block_height(info, -1) != 0);
+
+ /* Test a tiled format */
+ info = drm_format_info(DRM_FORMAT_X0L0);
+ FAIL_ON(!info);
+ FAIL_ON(drm_format_info_block_height(info, 0) != 2);
+ FAIL_ON(drm_format_info_block_height(info, 1) != 0);
+ FAIL_ON(drm_format_info_block_height(info, -1) != 0);
+
+ return 0;
+}
+
+int igt_check_drm_format_min_pitch(void *ignored)
+{
+ const struct drm_format_info *info = NULL;
+
+ /* Test invalid arguments */
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
+ FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
+ FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
+
+ /* Test 1 plane 8 bits per pixel format */
+ info = drm_format_info(DRM_FORMAT_RGB332);
+ FAIL_ON(!info);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
+ FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
+ FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
+
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 1);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 2);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 640);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 1024);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 1920);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 4096);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 671);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) !=
+ (uint64_t)UINT_MAX);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, (UINT_MAX - 1)) !=
+ (uint64_t)(UINT_MAX - 1));
+
+ /* Test 1 plane 16 bits per pixel format */
+ info = drm_format_info(DRM_FORMAT_XRGB4444);
+ FAIL_ON(!info);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
+ FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
+ FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
+
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 2);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 4);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 1280);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 2048);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 3840);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 8192);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 1342);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) !=
+ (uint64_t)UINT_MAX * 2);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, (UINT_MAX - 1)) !=
+ (uint64_t)(UINT_MAX - 1) * 2);
+
+ /* Test 1 plane 24 bits per pixel format */
+ info = drm_format_info(DRM_FORMAT_RGB888);
+ FAIL_ON(!info);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
+ FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
+ FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
+
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 3);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 6);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 1920);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 3072);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 5760);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 12288);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 2013);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) !=
+ (uint64_t)UINT_MAX * 3);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX - 1) !=
+ (uint64_t)(UINT_MAX - 1) * 3);
+
+ /* Test 1 plane 32 bits per pixel format */
+ info = drm_format_info(DRM_FORMAT_ABGR8888);
+ FAIL_ON(!info);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
+ FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
+ FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
+
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 4);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 8);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 2560);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 4096);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 7680);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 16384);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 2684);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) !=
+ (uint64_t)UINT_MAX * 4);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX - 1) !=
+ (uint64_t)(UINT_MAX - 1) * 4);
+
+ /* Test 2 planes format */
+ info = drm_format_info(DRM_FORMAT_NV12);
+ FAIL_ON(!info);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
+ FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
+ FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
+ FAIL_ON(drm_format_info_min_pitch(info, 2, 0) != 0);
+
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 1);
+ FAIL_ON(drm_format_info_min_pitch(info, 1, 1) != 2);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 2);
+ FAIL_ON(drm_format_info_min_pitch(info, 1, 1) != 2);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 640);
+ FAIL_ON(drm_format_info_min_pitch(info, 1, 320) != 640);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 1024);
+ FAIL_ON(drm_format_info_min_pitch(info, 1, 512) != 1024);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 1920);
+ FAIL_ON(drm_format_info_min_pitch(info, 1, 960) != 1920);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 4096);
+ FAIL_ON(drm_format_info_min_pitch(info, 1, 2048) != 4096);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 671);
+ FAIL_ON(drm_format_info_min_pitch(info, 1, 336) != 672);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) !=
+ (uint64_t)UINT_MAX);
+ FAIL_ON(drm_format_info_min_pitch(info, 1, UINT_MAX / 2 + 1) !=
+ (uint64_t)UINT_MAX + 1);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, (UINT_MAX - 1)) !=
+ (uint64_t)(UINT_MAX - 1));
+ FAIL_ON(drm_format_info_min_pitch(info, 1, (UINT_MAX - 1) / 2) !=
+ (uint64_t)(UINT_MAX - 1));
+
+ /* Test 3 planes 8 bits per pixel format */
+ info = drm_format_info(DRM_FORMAT_YUV422);
+ FAIL_ON(!info);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
+ FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
+ FAIL_ON(drm_format_info_min_pitch(info, 2, 0) != 0);
+ FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
+ FAIL_ON(drm_format_info_min_pitch(info, 3, 0) != 0);
+
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 1);
+ FAIL_ON(drm_format_info_min_pitch(info, 1, 1) != 1);
+ FAIL_ON(drm_format_info_min_pitch(info, 2, 1) != 1);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 2);
+ FAIL_ON(drm_format_info_min_pitch(info, 1, 2) != 2);
+ FAIL_ON(drm_format_info_min_pitch(info, 2, 2) != 2);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 640);
+ FAIL_ON(drm_format_info_min_pitch(info, 1, 320) != 320);
+ FAIL_ON(drm_format_info_min_pitch(info, 2, 320) != 320);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 1024);
+ FAIL_ON(drm_format_info_min_pitch(info, 1, 512) != 512);
+ FAIL_ON(drm_format_info_min_pitch(info, 2, 512) != 512);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 1920);
+ FAIL_ON(drm_format_info_min_pitch(info, 1, 960) != 960);
+ FAIL_ON(drm_format_info_min_pitch(info, 2, 960) != 960);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 4096);
+ FAIL_ON(drm_format_info_min_pitch(info, 1, 2048) != 2048);
+ FAIL_ON(drm_format_info_min_pitch(info, 2, 2048) != 2048);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 671);
+ FAIL_ON(drm_format_info_min_pitch(info, 1, 336) != 336);
+ FAIL_ON(drm_format_info_min_pitch(info, 2, 336) != 336);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) !=
+ (uint64_t)UINT_MAX);
+ FAIL_ON(drm_format_info_min_pitch(info, 1, UINT_MAX / 2 + 1) !=
+ (uint64_t)UINT_MAX / 2 + 1);
+ FAIL_ON(drm_format_info_min_pitch(info, 2, UINT_MAX / 2 + 1) !=
+ (uint64_t)UINT_MAX / 2 + 1);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, (UINT_MAX - 1) / 2) !=
+ (uint64_t)(UINT_MAX - 1) / 2);
+ FAIL_ON(drm_format_info_min_pitch(info, 1, (UINT_MAX - 1) / 2) !=
+ (uint64_t)(UINT_MAX - 1) / 2);
+ FAIL_ON(drm_format_info_min_pitch(info, 2, (UINT_MAX - 1) / 2) !=
+ (uint64_t)(UINT_MAX - 1) / 2);
+
+ /* Test tiled format */
+ info = drm_format_info(DRM_FORMAT_X0L2);
+ FAIL_ON(!info);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
+ FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
+ FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
+
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 2);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 4);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 1280);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 2048);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 3840);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 8192);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 1342);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) !=
+ (uint64_t)UINT_MAX * 2);
+ FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX - 1) !=
+ (uint64_t)(UINT_MAX - 1) * 2);
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/selftests/test-drm_framebuffer.c b/drivers/gpu/drm/selftests/test-drm_framebuffer.c
new file mode 100644
index 000000000000..a04d02dacce2
--- /dev/null
+++ b/drivers/gpu/drm/selftests/test-drm_framebuffer.c
@@ -0,0 +1,346 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Test cases for the drm_framebuffer functions
+ */
+
+#include <drm/drmP.h>
+#include "../drm_crtc_internal.h"
+
+#include "test-drm_modeset_common.h"
+
+#define MIN_WIDTH 4
+#define MAX_WIDTH 4096
+#define MIN_HEIGHT 4
+#define MAX_HEIGHT 4096
+
+struct drm_framebuffer_test {
+ int buffer_created;
+ struct drm_mode_fb_cmd2 cmd;
+ const char *name;
+};
+
+static struct drm_framebuffer_test createbuffer_tests[] = {
+{ .buffer_created = 1, .name = "ABGR8888 normal sizes",
+ .cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_ABGR8888,
+ .handles = { 1, 0, 0 }, .pitches = { 4 * 600, 0, 0 },
+ }
+},
+{ .buffer_created = 1, .name = "ABGR8888 max sizes",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
+ .handles = { 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
+ }
+},
+{ .buffer_created = 1, .name = "ABGR8888 pitch greater than min required",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
+ .handles = { 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH + 1, 0, 0 },
+ }
+},
+{ .buffer_created = 0, .name = "ABGR8888 pitch less than min required",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
+ .handles = { 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH - 1, 0, 0 },
+ }
+},
+{ .buffer_created = 0, .name = "ABGR8888 Invalid width",
+ .cmd = { .width = MAX_WIDTH + 1, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
+ .handles = { 1, 0, 0 }, .pitches = { 4 * (MAX_WIDTH + 1), 0, 0 },
+ }
+},
+{ .buffer_created = 0, .name = "ABGR8888 Invalid buffer handle",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
+ .handles = { 0, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
+ }
+},
+{ .buffer_created = 0, .name = "No pixel format",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = 0,
+ .handles = { 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
+ }
+},
+{ .buffer_created = 0, .name = "ABGR8888 Width 0",
+ .cmd = { .width = 0, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
+ .handles = { 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
+ }
+},
+{ .buffer_created = 0, .name = "ABGR8888 Height 0",
+ .cmd = { .width = MAX_WIDTH, .height = 0, .pixel_format = DRM_FORMAT_ABGR8888,
+ .handles = { 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
+ }
+},
+{ .buffer_created = 0, .name = "ABGR8888 Out of bound height * pitch combination",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
+ .handles = { 1, 0, 0 }, .offsets = { UINT_MAX - 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
+ }
+},
+{ .buffer_created = 1, .name = "ABGR8888 Large buffer offset",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
+ .handles = { 1, 0, 0 }, .offsets = { UINT_MAX / 2, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
+ }
+},
+{ .buffer_created = 1, .name = "ABGR8888 Set DRM_MODE_FB_MODIFIERS without modifiers",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
+ .handles = { 1, 0, 0 }, .offsets = { UINT_MAX / 2, 0, 0 },
+ .pitches = { 4 * MAX_WIDTH, 0, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
+ }
+},
+{ .buffer_created = 1, .name = "ABGR8888 Valid buffer modifier",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
+ .handles = { 1, 0, 0 }, .offsets = { UINT_MAX / 2, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
+ .flags = DRM_MODE_FB_MODIFIERS, .modifier = { AFBC_FORMAT_MOD_YTR, 0, 0 },
+ }
+},
+{ .buffer_created = 0, .name = "ABGR8888 Invalid buffer modifier(DRM_FORMAT_MOD_SAMSUNG_64_32_TILE)",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
+ .handles = { 1, 0, 0 }, .offsets = { UINT_MAX / 2, 0, 0 },
+ .pitches = { 4 * MAX_WIDTH, 0, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
+ .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, 0, 0 },
+ }
+},
+{ .buffer_created = 1, .name = "ABGR8888 Extra pitches without DRM_MODE_FB_MODIFIERS",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
+ .handles = { 1, 0, 0 }, .offsets = { UINT_MAX / 2, 0, 0 },
+ .pitches = { 4 * MAX_WIDTH, 4 * MAX_WIDTH, 0 },
+ }
+},
+{ .buffer_created = 0, .name = "ABGR8888 Extra pitches with DRM_MODE_FB_MODIFIERS",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
+ .handles = { 1, 0, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
+ .pitches = { 4 * MAX_WIDTH, 4 * MAX_WIDTH, 0 },
+ }
+},
+{ .buffer_created = 1, .name = "NV12 Normal sizes",
+ .cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_NV12,
+ .handles = { 1, 1, 0 }, .pitches = { 600, 600, 0 },
+ }
+},
+{ .buffer_created = 1, .name = "NV12 Max sizes",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
+ .handles = { 1, 1, 0 }, .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
+ }
+},
+{ .buffer_created = 0, .name = "NV12 Invalid pitch",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
+ .handles = { 1, 1, 0 }, .pitches = { MAX_WIDTH, MAX_WIDTH - 1, 0 },
+ }
+},
+{ .buffer_created = 0, .name = "NV12 Invalid modifier/misssing DRM_MODE_FB_MODIFIERS flag",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
+ .handles = { 1, 1, 0 }, .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, 0, 0 },
+ .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
+ }
+},
+{ .buffer_created = 0, .name = "NV12 different modifier per-plane",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
+ .handles = { 1, 1, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
+ .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, 0, 0 },
+ .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
+ }
+},
+{ .buffer_created = 1, .name = "NV12 with DRM_FORMAT_MOD_SAMSUNG_64_32_TILE",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
+ .handles = { 1, 1, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
+ .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, 0 },
+ .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
+ }
+},
+{ .buffer_created = 0, .name = "NV12 Valid modifiers without DRM_MODE_FB_MODIFIERS",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
+ .handles = { 1, 1, 0 }, .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE,
+ DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, 0 },
+ .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
+ }
+},
+{ .buffer_created = 0, .name = "NV12 Modifier for inexistent plane",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
+ .handles = { 1, 1, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
+ .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, DRM_FORMAT_MOD_SAMSUNG_64_32_TILE,
+ DRM_FORMAT_MOD_SAMSUNG_64_32_TILE },
+ .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
+ }
+},
+{ .buffer_created = 0, .name = "NV12 Handle for inexistent plane",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
+ .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS, .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
+ }
+},
+{ .buffer_created = 1, .name = "NV12 Handle for inexistent plane without DRM_MODE_FB_MODIFIERS",
+ .cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_NV12,
+ .handles = { 1, 1, 1 }, .pitches = { 600, 600, 600 },
+ }
+},
+{ .buffer_created = 1, .name = "YVU420 Normal sizes",
+ .cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_YVU420,
+ .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS,
+ .pitches = { 600, 300, 300 },
+ }
+},
+{ .buffer_created = 1, .name = "YVU420 DRM_MODE_FB_MODIFIERS set without modifier",
+ .cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_YVU420,
+ .handles = { 1, 1, 1 }, .pitches = { 600, 300, 300 },
+ }
+},
+{ .buffer_created = 1, .name = "YVU420 Max sizes",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
+ .handles = { 1, 1, 1 }, .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2),
+ DIV_ROUND_UP(MAX_WIDTH, 2) },
+ }
+},
+{ .buffer_created = 0, .name = "YVU420 Invalid pitch",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
+ .handles = { 1, 1, 1 }, .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2) - 1,
+ DIV_ROUND_UP(MAX_WIDTH, 2) },
+ }
+},
+{ .buffer_created = 1, .name = "YVU420 Different pitches",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
+ .handles = { 1, 1, 1 }, .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2) + 1,
+ DIV_ROUND_UP(MAX_WIDTH, 2) + 7 },
+ }
+},
+{ .buffer_created = 1, .name = "YVU420 Different buffer offsets/pitches",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
+ .handles = { 1, 1, 1 }, .offsets = { MAX_WIDTH, MAX_WIDTH + MAX_WIDTH * MAX_HEIGHT,
+ MAX_WIDTH + 2 * MAX_WIDTH * MAX_HEIGHT },
+ .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2) + 1, DIV_ROUND_UP(MAX_WIDTH, 2) + 7 },
+ }
+},
+{ .buffer_created = 0, .name = "YVU420 Modifier set just for plane 0, without DRM_MODE_FB_MODIFIERS",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
+ .handles = { 1, 1, 1 }, .modifier = { AFBC_FORMAT_MOD_SPARSE, 0, 0 },
+ .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) },
+ }
+},
+{ .buffer_created = 0, .name = "YVU420 Modifier set just for planes 0, 1, without DRM_MODE_FB_MODIFIERS",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
+ .handles = { 1, 1, 1 }, .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, 0 },
+ .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) },
+ }
+},
+{ .buffer_created = 0, .name = "YVU420 Modifier set just for plane 0, 1, with DRM_MODE_FB_MODIFIERS",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
+ .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS,
+ .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, 0 },
+ .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) },
+ }
+},
+{ .buffer_created = 1, .name = "YVU420 Valid modifier",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
+ .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS,
+ .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE },
+ .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) },
+ }
+},
+{ .buffer_created = 0, .name = "YVU420 Different modifiers per plane",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
+ .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS,
+ .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE | AFBC_FORMAT_MOD_YTR,
+ AFBC_FORMAT_MOD_SPARSE },
+ .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) },
+ }
+},
+{ .buffer_created = 0, .name = "YVU420 Modifier for inexistent plane",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
+ .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS,
+ .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE,
+ AFBC_FORMAT_MOD_SPARSE },
+ .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) },
+ }
+},
+{ .buffer_created = 1, .name = "X0L2 Normal sizes",
+ .cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_X0L2,
+ .handles = { 1, 0, 0 }, .pitches = { 1200, 0, 0 }
+ }
+},
+{ .buffer_created = 1, .name = "X0L2 Max sizes",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
+ .handles = { 1, 0, 0 }, .pitches = { 2 * MAX_WIDTH, 0, 0 }
+ }
+},
+{ .buffer_created = 0, .name = "X0L2 Invalid pitch",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
+ .handles = { 1, 0, 0 }, .pitches = { 2 * MAX_WIDTH - 1, 0, 0 }
+ }
+},
+{ .buffer_created = 1, .name = "X0L2 Pitch greater than minimum required",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
+ .handles = { 1, 0, 0 }, .pitches = { 2 * MAX_WIDTH + 1, 0, 0 }
+ }
+},
+{ .buffer_created = 0, .name = "X0L2 Handle for inexistent plane",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
+ .handles = { 1, 1, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
+ .pitches = { 2 * MAX_WIDTH + 1, 0, 0 }
+ }
+},
+{ .buffer_created = 1, .name = "X0L2 Offset for inexistent plane, without DRM_MODE_FB_MODIFIERS set",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
+ .handles = { 1, 0, 0 }, .offsets = { 0, 0, 3 },
+ .pitches = { 2 * MAX_WIDTH + 1, 0, 0 }
+ }
+},
+{ .buffer_created = 0, .name = "X0L2 Modifier without DRM_MODE_FB_MODIFIERS set",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
+ .handles = { 1, 0, 0 }, .pitches = { 2 * MAX_WIDTH + 1, 0, 0 },
+ .modifier = { AFBC_FORMAT_MOD_SPARSE, 0, 0 },
+ }
+},
+{ .buffer_created = 1, .name = "X0L2 Valid modifier",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
+ .handles = { 1, 0, 0 }, .pitches = { 2 * MAX_WIDTH + 1, 0, 0 },
+ .modifier = { AFBC_FORMAT_MOD_SPARSE, 0, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
+ }
+},
+{ .buffer_created = 0, .name = "X0L2 Modifier for inexistent plane",
+ .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT,
+ .pixel_format = DRM_FORMAT_X0L2, .handles = { 1, 0, 0 },
+ .pitches = { 2 * MAX_WIDTH + 1, 0, 0 },
+ .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, 0 },
+ .flags = DRM_MODE_FB_MODIFIERS,
+ }
+},
+};
+
+static struct drm_framebuffer *fb_create_mock(struct drm_device *dev,
+ struct drm_file *file_priv,
+ const struct drm_mode_fb_cmd2 *mode_cmd)
+{
+ int *buffer_created = dev->dev_private;
+ *buffer_created = 1;
+ return ERR_PTR(-EINVAL);
+}
+
+static struct drm_mode_config_funcs mock_config_funcs = {
+ .fb_create = fb_create_mock,
+};
+
+static struct drm_device mock_drm_device = {
+ .mode_config = {
+ .min_width = MIN_WIDTH,
+ .max_width = MAX_WIDTH,
+ .min_height = MIN_HEIGHT,
+ .max_height = MAX_HEIGHT,
+ .allow_fb_modifiers = true,
+ .funcs = &mock_config_funcs,
+ },
+};
+
+static int execute_drm_mode_fb_cmd2(struct drm_mode_fb_cmd2 *r)
+{
+ int buffer_created = 0;
+ struct drm_framebuffer *fb;
+
+ mock_drm_device.dev_private = &buffer_created;
+ fb = drm_internal_framebuffer_create(&mock_drm_device, r, NULL);
+ return buffer_created;
+}
+
+int igt_check_drm_framebuffer_create(void *ignored)
+{
+ int i = 0;
+
+ for (i = 0; i < ARRAY_SIZE(createbuffer_tests); i++) {
+ FAIL(createbuffer_tests[i].buffer_created !=
+ execute_drm_mode_fb_cmd2(&createbuffer_tests[i].cmd),
+ "Test %d: \"%s\" failed\n", i, createbuffer_tests[i].name);
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/selftests/test-drm_modeset_common.c b/drivers/gpu/drm/selftests/test-drm_modeset_common.c
new file mode 100644
index 000000000000..2a7f93774006
--- /dev/null
+++ b/drivers/gpu/drm/selftests/test-drm_modeset_common.c
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Common file for modeset selftests.
+ */
+
+#include <linux/module.h>
+
+#include "test-drm_modeset_common.h"
+
+#define TESTS "drm_modeset_selftests.h"
+#include "drm_selftest.h"
+
+#include "drm_selftest.c"
+
+static int __init test_drm_modeset_init(void)
+{
+ int err;
+
+ err = run_selftests(selftests, ARRAY_SIZE(selftests), NULL);
+
+ return err > 0 ? 0 : err;
+}
+
+static void __exit test_drm_modeset_exit(void)
+{
+}
+
+module_init(test_drm_modeset_init);
+module_exit(test_drm_modeset_exit);
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/selftests/test-drm_modeset_common.h b/drivers/gpu/drm/selftests/test-drm_modeset_common.h
new file mode 100644
index 000000000000..d5df5bd51b05
--- /dev/null
+++ b/drivers/gpu/drm/selftests/test-drm_modeset_common.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __TEST_DRM_MODESET_COMMON_H__
+#define __TEST_DRM_MODESET_COMMON_H__
+
+#define FAIL(test, msg, ...) \
+ do { \
+ if (test) { \
+ pr_err("%s/%u: " msg, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
+ return -EINVAL; \
+ } \
+ } while (0)
+
+#define FAIL_ON(x) FAIL((x), "%s", "FAIL_ON(" __stringify(x) ")\n")
+
+int igt_check_plane_state(void *ignored);
+int igt_check_drm_format_block_width(void *ignored);
+int igt_check_drm_format_block_height(void *ignored);
+int igt_check_drm_format_min_pitch(void *ignored);
+int igt_check_drm_framebuffer_create(void *ignored);
+
+#endif
diff --git a/drivers/gpu/drm/selftests/test-drm-helper.c b/drivers/gpu/drm/selftests/test-drm_plane_helper.c
index a015712b43e8..0a9553f51796 100644
--- a/drivers/gpu/drm/selftests/test-drm-helper.c
+++ b/drivers/gpu/drm/selftests/test-drm_plane_helper.c
@@ -1,27 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
/*
- * Test cases for the drm_kms_helper functions
+ * Test cases for the drm_plane_helper functions
*/
-#define pr_fmt(fmt) "drm_kms_helper: " fmt
-
-#include <linux/module.h>
+#define pr_fmt(fmt) "drm_plane_helper: " fmt
#include <drm/drm_atomic_helper.h>
#include <drm/drm_plane_helper.h>
#include <drm/drm_modes.h>
-#define TESTS "drm_helper_selftests.h"
-#include "drm_selftest.h"
-
-#define FAIL(test, msg, ...) \
- do { \
- if (test) { \
- pr_err("%s/%u: " msg, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
- return -EINVAL; \
- } \
- } while (0)
-
-#define FAIL_ON(x) FAIL((x), "%s", "FAIL_ON(" __stringify(x) ")\n")
+#include "test-drm_modeset_common.h"
static void set_src(struct drm_plane_state *plane_state,
unsigned src_x, unsigned src_y,
@@ -85,7 +73,7 @@ static bool check_crtc_eq(struct drm_plane_state *plane_state,
return true;
}
-static int igt_check_plane_state(void *ignored)
+int igt_check_plane_state(void *ignored)
{
int ret;
@@ -229,19 +217,3 @@ static int igt_check_plane_state(void *ignored)
return 0;
}
-
-#include "drm_selftest.c"
-
-static int __init test_drm_helper_init(void)
-{
- int err;
-
- err = run_selftests(selftests, ARRAY_SIZE(selftests), NULL);
-
- return err > 0 ? 0 : err;
-}
-
-module_init(test_drm_helper_init);
-
-MODULE_AUTHOR("Intel Corporation");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/sti/sti_crtc.c b/drivers/gpu/drm/sti/sti_crtc.c
index 5824e6aca8f4..61c2379fba87 100644
--- a/drivers/gpu/drm/sti/sti_crtc.c
+++ b/drivers/gpu/drm/sti/sti_crtc.c
@@ -40,6 +40,8 @@ static void sti_crtc_atomic_disable(struct drm_crtc *crtc,
DRM_DEBUG_DRIVER("\n");
mixer->status = STI_MIXER_DISABLING;
+
+ drm_crtc_wait_one_vblank(crtc);
}
static int
diff --git a/drivers/gpu/drm/sti/sti_cursor.c b/drivers/gpu/drm/sti/sti_cursor.c
index 57b870e1e696..bc908453ffb3 100644
--- a/drivers/gpu/drm/sti/sti_cursor.c
+++ b/drivers/gpu/drm/sti/sti_cursor.c
@@ -332,7 +332,6 @@ static void sti_cursor_destroy(struct drm_plane *drm_plane)
{
DRM_DEBUG_DRIVER("\n");
- drm_plane_helper_disable(drm_plane, NULL);
drm_plane_cleanup(drm_plane);
}
diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c
index 6dced8abcf16..ac54e0f9caea 100644
--- a/drivers/gpu/drm/sti/sti_drv.c
+++ b/drivers/gpu/drm/sti/sti_drv.c
@@ -206,6 +206,8 @@ static void sti_cleanup(struct drm_device *ddev)
struct sti_private *private = ddev->dev_private;
drm_kms_helper_poll_fini(ddev);
+ drm_atomic_helper_shutdown(ddev);
+ drm_mode_config_cleanup(ddev);
component_unbind_all(ddev->dev, ddev);
kfree(private);
ddev->dev_private = NULL;
@@ -230,7 +232,7 @@ static int sti_bind(struct device *dev)
ret = drm_dev_register(ddev, 0);
if (ret)
- goto err_register;
+ goto err_cleanup;
drm_mode_config_reset(ddev);
@@ -238,8 +240,6 @@ static int sti_bind(struct device *dev)
return 0;
-err_register:
- drm_mode_config_cleanup(ddev);
err_cleanup:
sti_cleanup(ddev);
err_drm_dev_put:
diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c
index c32de6cbf061..cff7b2b5ee9e 100644
--- a/drivers/gpu/drm/sti/sti_gdp.c
+++ b/drivers/gpu/drm/sti/sti_gdp.c
@@ -517,7 +517,7 @@ static void sti_gdp_init(struct sti_gdp *gdp)
/* Allocate all the nodes within a single memory page */
size = sizeof(struct sti_gdp_node) *
GDP_NODE_PER_FIELD * GDP_NODE_NB_BANK;
- base = dma_alloc_wc(gdp->dev, size, &dma_addr, GFP_KERNEL | GFP_DMA);
+ base = dma_alloc_wc(gdp->dev, size, &dma_addr, GFP_KERNEL);
if (!base) {
DRM_ERROR("Failed to allocate memory for GDP node\n");
@@ -883,7 +883,6 @@ static void sti_gdp_destroy(struct drm_plane *drm_plane)
{
DRM_DEBUG_DRIVER("\n");
- drm_plane_helper_disable(drm_plane, NULL);
drm_plane_cleanup(drm_plane);
}
diff --git a/drivers/gpu/drm/sti/sti_hqvdp.c b/drivers/gpu/drm/sti/sti_hqvdp.c
index 03ac3b4a4469..23565f52dd71 100644
--- a/drivers/gpu/drm/sti/sti_hqvdp.c
+++ b/drivers/gpu/drm/sti/sti_hqvdp.c
@@ -1260,7 +1260,6 @@ static void sti_hqvdp_destroy(struct drm_plane *drm_plane)
{
DRM_DEBUG_DRIVER("\n");
- drm_plane_helper_disable(drm_plane, NULL);
drm_plane_cleanup(drm_plane);
}
diff --git a/drivers/gpu/drm/stm/drv.c b/drivers/gpu/drm/stm/drv.c
index f2021b23554d..8dec001b9d37 100644
--- a/drivers/gpu/drm/stm/drv.c
+++ b/drivers/gpu/drm/stm/drv.c
@@ -26,7 +26,6 @@
static const struct drm_mode_config_funcs drv_mode_config_funcs = {
.fb_create = drm_gem_fb_create,
- .output_poll_changed = drm_fb_helper_output_poll_changed,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = drm_atomic_helper_commit,
};
@@ -52,7 +51,6 @@ DEFINE_DRM_GEM_CMA_FOPS(drv_driver_fops);
static struct drm_driver drv_driver = {
.driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME |
DRIVER_ATOMIC,
- .lastclose = drm_fb_helper_lastclose,
.name = "stm",
.desc = "STMicroelectronics SoC DRM",
.date = "20170330",
@@ -72,6 +70,8 @@ static struct drm_driver drv_driver = {
.gem_prime_vmap = drm_gem_cma_prime_vmap,
.gem_prime_vunmap = drm_gem_cma_prime_vunmap,
.gem_prime_mmap = drm_gem_cma_prime_mmap,
+ .get_scanout_position = ltdc_crtc_scanoutpos,
+ .get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos,
};
static int drv_load(struct drm_device *ddev)
@@ -108,12 +108,6 @@ static int drv_load(struct drm_device *ddev)
drm_mode_config_reset(ddev);
drm_kms_helper_poll_init(ddev);
- if (ddev->mode_config.num_connector) {
- ret = drm_fb_cma_fbdev_init(ddev, 16, 0);
- if (ret)
- DRM_DEBUG("Warning: fails to create fbdev\n");
- }
-
platform_set_drvdata(pdev, ddev);
return 0;
@@ -126,7 +120,6 @@ static void drv_unload(struct drm_device *ddev)
{
DRM_DEBUG("%s\n", __func__);
- drm_fb_cma_fbdev_fini(ddev);
drm_kms_helper_poll_fini(ddev);
ltdc_unload(ddev);
drm_mode_config_cleanup(ddev);
@@ -154,6 +147,8 @@ static int stm_drm_platform_probe(struct platform_device *pdev)
if (ret)
goto err_put;
+ drm_fbdev_generic_setup(ddev, 16);
+
return 0;
err_put:
diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c
index 808d9fb627e9..61dd661aa0ac 100644
--- a/drivers/gpu/drm/stm/ltdc.c
+++ b/drivers/gpu/drm/stm/ltdc.c
@@ -148,6 +148,8 @@
#define IER_TERRIE BIT(2) /* Transfer ERRor Interrupt Enable */
#define IER_RRIE BIT(3) /* Register Reload Interrupt enable */
+#define CPSR_CYPOS GENMASK(15, 0) /* Current Y position */
+
#define ISR_LIF BIT(0) /* Line Interrupt Flag */
#define ISR_FUIF BIT(1) /* Fifo Underrun Interrupt Flag */
#define ISR_TERRIF BIT(2) /* Transfer ERRor Interrupt Flag */
@@ -626,6 +628,49 @@ static void ltdc_crtc_disable_vblank(struct drm_crtc *crtc)
reg_clear(ldev->regs, LTDC_IER, IER_LIE);
}
+bool ltdc_crtc_scanoutpos(struct drm_device *ddev, unsigned int pipe,
+ bool in_vblank_irq, int *vpos, int *hpos,
+ ktime_t *stime, ktime_t *etime,
+ const struct drm_display_mode *mode)
+{
+ struct ltdc_device *ldev = ddev->dev_private;
+ int line, vactive_start, vactive_end, vtotal;
+
+ if (stime)
+ *stime = ktime_get();
+
+ /* The active area starts after vsync + front porch and ends
+ * at vsync + front porc + display size.
+ * The total height also include back porch.
+ * We have 3 possible cases to handle:
+ * - line < vactive_start: vpos = line - vactive_start and will be
+ * negative
+ * - vactive_start < line < vactive_end: vpos = line - vactive_start
+ * and will be positive
+ * - line > vactive_end: vpos = line - vtotal - vactive_start
+ * and will negative
+ *
+ * Computation for the two first cases are identical so we can
+ * simplify the code and only test if line > vactive_end
+ */
+ line = reg_read(ldev->regs, LTDC_CPSR) & CPSR_CYPOS;
+ vactive_start = reg_read(ldev->regs, LTDC_BPCR) & BPCR_AVBP;
+ vactive_end = reg_read(ldev->regs, LTDC_AWCR) & AWCR_AAH;
+ vtotal = reg_read(ldev->regs, LTDC_TWCR) & TWCR_TOTALH;
+
+ if (line > vactive_end)
+ *vpos = line - vtotal - vactive_start;
+ else
+ *vpos = line - vactive_start;
+
+ *hpos = 0;
+
+ if (etime)
+ *etime = ktime_get();
+
+ return true;
+}
+
static const struct drm_crtc_funcs ltdc_crtc_funcs = {
.destroy = drm_crtc_cleanup,
.set_config = drm_atomic_helper_set_config,
diff --git a/drivers/gpu/drm/stm/ltdc.h b/drivers/gpu/drm/stm/ltdc.h
index d5afb8960867..e46f477a8494 100644
--- a/drivers/gpu/drm/stm/ltdc.h
+++ b/drivers/gpu/drm/stm/ltdc.h
@@ -38,6 +38,11 @@ struct ltdc_device {
struct fps_info plane_fpsi[LTDC_MAX_LAYER];
};
+bool ltdc_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe,
+ bool in_vblank_irq, int *vpos, int *hpos,
+ ktime_t *stime, ktime_t *etime,
+ const struct drm_display_mode *mode);
+
int ltdc_load(struct drm_device *ddev);
void ltdc_unload(struct drm_device *ddev);
diff --git a/drivers/gpu/drm/sun4i/sun4i_dotclock.c b/drivers/gpu/drm/sun4i/sun4i_dotclock.c
index e36004fbe453..2a15f2f9271e 100644
--- a/drivers/gpu/drm/sun4i/sun4i_dotclock.c
+++ b/drivers/gpu/drm/sun4i/sun4i_dotclock.c
@@ -81,9 +81,19 @@ static long sun4i_dclk_round_rate(struct clk_hw *hw, unsigned long rate,
int i;
for (i = tcon->dclk_min_div; i <= tcon->dclk_max_div; i++) {
- unsigned long ideal = rate * i;
+ u64 ideal = (u64)rate * i;
unsigned long rounded;
+ /*
+ * ideal has overflowed the max value that can be stored in an
+ * unsigned long, and every clk operation we might do on a
+ * truncated u64 value will give us incorrect results.
+ * Let's just stop there since bigger dividers will result in
+ * the same overflow issue.
+ */
+ if (ideal > ULONG_MAX)
+ goto out;
+
rounded = clk_hw_round_rate(clk_hw_get_parent(hw),
ideal);
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
index 1e41c3f5fd6d..ef773d36baf0 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -34,7 +34,6 @@ static struct drm_driver sun4i_drv_driver = {
.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_ATOMIC,
/* Generic Operations */
- .lastclose = drm_fb_helper_lastclose,
.fops = &sun4i_drv_fops,
.name = "sun4i-drm",
.desc = "Allwinner sun4i Display Engine",
@@ -105,12 +104,7 @@ static int sun4i_drv_bind(struct device *dev)
/* Remove early framebuffers (ie. simplefb) */
drm_fb_helper_remove_conflicting_framebuffers(NULL, "sun4i-drm-fb", false);
- /* Create our framebuffer */
- ret = sun4i_framebuffer_init(drm);
- if (ret) {
- dev_err(drm->dev, "Couldn't create our framebuffer\n");
- goto cleanup_mode_config;
- }
+ sun4i_framebuffer_init(drm);
/* Enable connectors polling */
drm_kms_helper_poll_init(drm);
@@ -119,11 +113,12 @@ static int sun4i_drv_bind(struct device *dev)
if (ret)
goto finish_poll;
+ drm_fbdev_generic_setup(drm, 32);
+
return 0;
finish_poll:
drm_kms_helper_poll_fini(drm);
- sun4i_framebuffer_free(drm);
cleanup_mode_config:
drm_mode_config_cleanup(drm);
of_reserved_mem_device_release(dev);
@@ -138,7 +133,6 @@ static void sun4i_drv_unbind(struct device *dev)
drm_dev_unregister(drm);
drm_kms_helper_poll_fini(drm);
- sun4i_framebuffer_free(drm);
drm_mode_config_cleanup(drm);
of_reserved_mem_device_release(dev);
drm_dev_put(drm);
diff --git a/drivers/gpu/drm/sun4i/sun4i_framebuffer.c b/drivers/gpu/drm/sun4i/sun4i_framebuffer.c
index 5f29850ef8ac..cb828028ae06 100644
--- a/drivers/gpu/drm/sun4i/sun4i_framebuffer.c
+++ b/drivers/gpu/drm/sun4i/sun4i_framebuffer.c
@@ -12,8 +12,6 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_fb_helper.h>
-#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drmP.h>
@@ -37,7 +35,6 @@ static int sun4i_de_atomic_check(struct drm_device *dev,
}
static const struct drm_mode_config_funcs sun4i_de_mode_config_funcs = {
- .output_poll_changed = drm_fb_helper_output_poll_changed,
.atomic_check = sun4i_de_atomic_check,
.atomic_commit = drm_atomic_helper_commit,
.fb_create = drm_gem_fb_create,
@@ -47,7 +44,7 @@ static struct drm_mode_config_helper_funcs sun4i_de_mode_config_helpers = {
.atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
};
-int sun4i_framebuffer_init(struct drm_device *drm)
+void sun4i_framebuffer_init(struct drm_device *drm)
{
drm_mode_config_reset(drm);
@@ -56,11 +53,4 @@ int sun4i_framebuffer_init(struct drm_device *drm)
drm->mode_config.funcs = &sun4i_de_mode_config_funcs;
drm->mode_config.helper_private = &sun4i_de_mode_config_helpers;
-
- return drm_fb_cma_fbdev_init(drm, 32, 0);
-}
-
-void sun4i_framebuffer_free(struct drm_device *drm)
-{
- drm_fb_cma_fbdev_fini(drm);
}
diff --git a/drivers/gpu/drm/sun4i/sun4i_framebuffer.h b/drivers/gpu/drm/sun4i/sun4i_framebuffer.h
index 7ef0aed8384c..6fe5bd8c4026 100644
--- a/drivers/gpu/drm/sun4i/sun4i_framebuffer.h
+++ b/drivers/gpu/drm/sun4i/sun4i_framebuffer.h
@@ -13,7 +13,6 @@
#ifndef _SUN4I_FRAMEBUFFER_H_
#define _SUN4I_FRAMEBUFFER_H_
-int sun4i_framebuffer_init(struct drm_device *drm);
-void sun4i_framebuffer_free(struct drm_device *drm);
+void sun4i_framebuffer_init(struct drm_device *drm);
#endif /* _SUN4I_FRAMEBUFFER_H_ */
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c
index 3ecffa52c814..fb985ba1a176 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c
@@ -35,7 +35,7 @@ static unsigned long sun4i_tmds_calc_divider(unsigned long rate,
{
unsigned long best_rate = 0;
u8 best_m = 0, m;
- bool is_double;
+ bool is_double = false;
for (m = div_offset ?: 1; m < (16 + div_offset); m++) {
u8 d;
@@ -52,7 +52,7 @@ static unsigned long sun4i_tmds_calc_divider(unsigned long rate,
(rate - tmp_rate) < (rate - best_rate)) {
best_rate = tmp_rate;
best_m = m;
- is_double = d;
+ is_double = (d == 2) ? true : false;
}
}
}
diff --git a/drivers/gpu/drm/sun4i/sun4i_lvds.c b/drivers/gpu/drm/sun4i/sun4i_lvds.c
index af7dcb6da351..e7eb0d1e17be 100644
--- a/drivers/gpu/drm/sun4i/sun4i_lvds.c
+++ b/drivers/gpu/drm/sun4i/sun4i_lvds.c
@@ -75,7 +75,7 @@ static void sun4i_lvds_encoder_enable(struct drm_encoder *encoder)
DRM_DEBUG_DRIVER("Enabling LVDS output\n");
- if (!IS_ERR(tcon->panel)) {
+ if (tcon->panel) {
drm_panel_prepare(tcon->panel);
drm_panel_enable(tcon->panel);
}
@@ -88,7 +88,7 @@ static void sun4i_lvds_encoder_disable(struct drm_encoder *encoder)
DRM_DEBUG_DRIVER("Disabling LVDS output\n");
- if (!IS_ERR(tcon->panel)) {
+ if (tcon->panel) {
drm_panel_disable(tcon->panel);
drm_panel_unprepare(tcon->panel);
}
diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c
index bf068da6b12e..f4a22689eb54 100644
--- a/drivers/gpu/drm/sun4i/sun4i_rgb.c
+++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c
@@ -135,7 +135,7 @@ static void sun4i_rgb_encoder_enable(struct drm_encoder *encoder)
DRM_DEBUG_DRIVER("Enabling RGB output\n");
- if (!IS_ERR(tcon->panel)) {
+ if (tcon->panel) {
drm_panel_prepare(tcon->panel);
drm_panel_enable(tcon->panel);
}
@@ -148,7 +148,7 @@ static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder)
DRM_DEBUG_DRIVER("Disabling RGB output\n");
- if (!IS_ERR(tcon->panel)) {
+ if (tcon->panel) {
drm_panel_disable(tcon->panel);
drm_panel_unprepare(tcon->panel);
}
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index c78cd35a1294..f949287d926c 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -491,7 +491,8 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon,
sun4i_tcon0_mode_set_common(tcon, mode);
/* Set dithering if needed */
- sun4i_tcon0_mode_set_dithering(tcon, tcon->panel->connector);
+ if (tcon->panel)
+ sun4i_tcon0_mode_set_dithering(tcon, tcon->panel->connector);
/* Adjust clock delay */
clk_delay = sun4i_tcon_get_clk_delay(mode, 0);
@@ -555,7 +556,7 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon,
* Following code is a way to avoid quirks all around TCON
* and DOTCLOCK drivers.
*/
- if (!IS_ERR(tcon->panel)) {
+ if (tcon->panel) {
struct drm_panel *panel = tcon->panel;
struct drm_connector *connector = panel->connector;
struct drm_display_info display_info = connector->display_info;
diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c b/drivers/gpu/drm/sun4i/sun8i_csc.c
index b14925b40ccf..e7608a72f26f 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -34,6 +34,41 @@ static const u32 yvu2rgb[] = {
0x000004A8, 0x00000000, 0x00000813, 0xFFFBAC4A,
};
+/*
+ * DE3 has a bit different CSC units. Factors are in two's complement format.
+ * First three factors in a row are multiplication factors which have 17 bits
+ * for fractional part. Fourth value in a row is comprised of two factors.
+ * Upper 16 bits represents difference, which is subtracted from the input
+ * value before multiplication and lower 16 bits represents constant, which
+ * is addes at the end.
+ *
+ * x' = c00 * (x + d0) + c01 * (y + d1) + c02 * (z + d2) + const0
+ * y' = c10 * (x + d0) + c11 * (y + d1) + c12 * (z + d2) + const1
+ * z' = c20 * (x + d0) + c21 * (y + d1) + c22 * (z + d2) + const2
+ *
+ * Please note that above formula is true only for Blender CSC. Other DE3 CSC
+ * units takes only positive value for difference. From what can be deducted
+ * from BSP driver code, those units probably automatically assume that
+ * difference has to be subtracted.
+ *
+ * Layout of factors in table:
+ * c00 c01 c02 [d0 const0]
+ * c10 c11 c12 [d1 const1]
+ * c20 c21 c22 [d2 const2]
+ */
+
+static const u32 yuv2rgb_de3[] = {
+ 0x0002542a, 0x00000000, 0x0003312a, 0xffc00000,
+ 0x0002542a, 0xffff376b, 0xfffe5fc3, 0xfe000000,
+ 0x0002542a, 0x000408d3, 0x00000000, 0xfe000000,
+};
+
+static const u32 yvu2rgb_de3[] = {
+ 0x0002542a, 0x0003312a, 0x00000000, 0xffc00000,
+ 0x0002542a, 0xfffe5fc3, 0xffff376b, 0xfe000000,
+ 0x0002542a, 0x00000000, 0x000408d3, 0xfe000000,
+};
+
static void sun8i_csc_set_coefficients(struct regmap *map, u32 base,
enum sun8i_csc_mode mode)
{
@@ -61,6 +96,28 @@ static void sun8i_csc_set_coefficients(struct regmap *map, u32 base,
}
}
+static void sun8i_de3_ccsc_set_coefficients(struct regmap *map, int layer,
+ enum sun8i_csc_mode mode)
+{
+ const u32 *table;
+ u32 base_reg;
+
+ switch (mode) {
+ case SUN8I_CSC_MODE_YUV2RGB:
+ table = yuv2rgb_de3;
+ break;
+ case SUN8I_CSC_MODE_YVU2RGB:
+ table = yvu2rgb_de3;
+ break;
+ default:
+ DRM_WARN("Wrong CSC mode specified.\n");
+ return;
+ }
+
+ base_reg = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE, layer, 0, 0);
+ regmap_bulk_write(map, base_reg, table, 12);
+}
+
static void sun8i_csc_enable(struct regmap *map, u32 base, bool enable)
{
u32 val;
@@ -73,11 +130,32 @@ static void sun8i_csc_enable(struct regmap *map, u32 base, bool enable)
regmap_update_bits(map, SUN8I_CSC_CTRL(base), SUN8I_CSC_CTRL_EN, val);
}
+static void sun8i_de3_ccsc_enable(struct regmap *map, int layer, bool enable)
+{
+ u32 val, mask;
+
+ mask = SUN50I_MIXER_BLEND_CSC_CTL_EN(layer);
+
+ if (enable)
+ val = mask;
+ else
+ val = 0;
+
+ regmap_update_bits(map, SUN50I_MIXER_BLEND_CSC_CTL(DE3_BLD_BASE),
+ mask, val);
+}
+
void sun8i_csc_set_ccsc_coefficients(struct sun8i_mixer *mixer, int layer,
enum sun8i_csc_mode mode)
{
u32 base;
+ if (mixer->cfg->is_de3) {
+ sun8i_de3_ccsc_set_coefficients(mixer->engine.regs,
+ layer, mode);
+ return;
+ }
+
base = ccsc_base[mixer->cfg->ccsc][layer];
sun8i_csc_set_coefficients(mixer->engine.regs, base, mode);
@@ -87,6 +165,11 @@ void sun8i_csc_enable_ccsc(struct sun8i_mixer *mixer, int layer, bool enable)
{
u32 base;
+ if (mixer->cfg->is_de3) {
+ sun8i_de3_ccsc_enable(mixer->engine.regs, layer, enable);
+ return;
+ }
+
base = ccsc_base[mixer->cfg->ccsc][layer];
sun8i_csc_enable(mixer->engine.regs, base, enable);
diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
index ed2983770e9c..dc47720c99ba 100644
--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
+++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
@@ -5,6 +5,7 @@
#include <linux/component.h>
#include <linux/module.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <drm/drm_of.h>
@@ -20,7 +21,8 @@ static void sun8i_dw_hdmi_encoder_mode_set(struct drm_encoder *encoder,
{
struct sun8i_dw_hdmi *hdmi = encoder_to_sun8i_dw_hdmi(encoder);
- clk_set_rate(hdmi->clk_tmds, mode->crtc_clock * 1000);
+ if (hdmi->quirks->set_rate)
+ clk_set_rate(hdmi->clk_tmds, mode->crtc_clock * 1000);
}
static const struct drm_encoder_helper_funcs
@@ -33,8 +35,8 @@ static const struct drm_encoder_funcs sun8i_dw_hdmi_encoder_funcs = {
};
static enum drm_mode_status
-sun8i_dw_hdmi_mode_valid(struct drm_connector *connector,
- const struct drm_display_mode *mode)
+sun8i_dw_hdmi_mode_valid_a83t(struct drm_connector *connector,
+ const struct drm_display_mode *mode)
{
if (mode->clock > 297000)
return MODE_CLOCK_HIGH;
@@ -42,6 +44,17 @@ sun8i_dw_hdmi_mode_valid(struct drm_connector *connector,
return MODE_OK;
}
+static enum drm_mode_status
+sun8i_dw_hdmi_mode_valid_h6(struct drm_connector *connector,
+ const struct drm_display_mode *mode)
+{
+ /* This is max for HDMI 2.0b (4K@60Hz) */
+ if (mode->clock > 594000)
+ return MODE_CLOCK_HIGH;
+
+ return MODE_OK;
+}
+
static bool sun8i_dw_hdmi_node_is_tcon_top(struct device_node *node)
{
return IS_ENABLED(CONFIG_DRM_SUN8I_TCON_TOP) &&
@@ -102,6 +115,8 @@ static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master,
hdmi->dev = &pdev->dev;
encoder = &hdmi->encoder;
+ hdmi->quirks = of_device_get_match_data(dev);
+
encoder->possible_crtcs =
sun8i_dw_hdmi_find_possible_crtcs(drm, dev->of_node);
/*
@@ -168,10 +183,8 @@ static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master,
sun8i_hdmi_phy_init(hdmi->phy);
- plat_data->mode_valid = &sun8i_dw_hdmi_mode_valid;
- plat_data->phy_ops = sun8i_hdmi_phy_get_ops();
- plat_data->phy_name = "sun8i_dw_hdmi_phy";
- plat_data->phy_data = hdmi->phy;
+ plat_data->mode_valid = hdmi->quirks->mode_valid;
+ sun8i_hdmi_phy_set_ops(hdmi->phy, plat_data);
platform_set_drvdata(pdev, hdmi);
@@ -230,8 +243,24 @@ static int sun8i_dw_hdmi_remove(struct platform_device *pdev)
return 0;
}
+static const struct sun8i_dw_hdmi_quirks sun8i_a83t_quirks = {
+ .mode_valid = sun8i_dw_hdmi_mode_valid_a83t,
+ .set_rate = true,
+};
+
+static const struct sun8i_dw_hdmi_quirks sun50i_h6_quirks = {
+ .mode_valid = sun8i_dw_hdmi_mode_valid_h6,
+};
+
static const struct of_device_id sun8i_dw_hdmi_dt_ids[] = {
- { .compatible = "allwinner,sun8i-a83t-dw-hdmi" },
+ {
+ .compatible = "allwinner,sun8i-a83t-dw-hdmi",
+ .data = &sun8i_a83t_quirks,
+ },
+ {
+ .compatible = "allwinner,sun50i-h6-dw-hdmi",
+ .data = &sun50i_h6_quirks,
+ },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, sun8i_dw_hdmi_dt_ids);
diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
index 7fdc1ecd2892..720c5aa8adc1 100644
--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
+++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
@@ -150,6 +150,10 @@ struct sun8i_hdmi_phy;
struct sun8i_hdmi_phy_variant {
bool has_phy_clk;
bool has_second_pll;
+ unsigned int is_custom_phy : 1;
+ const struct dw_hdmi_curr_ctrl *cur_ctr;
+ const struct dw_hdmi_mpll_config *mpll_cfg;
+ const struct dw_hdmi_phy_config *phy_cfg;
void (*phy_init)(struct sun8i_hdmi_phy *phy);
void (*phy_disable)(struct dw_hdmi *hdmi,
struct sun8i_hdmi_phy *phy);
@@ -170,6 +174,12 @@ struct sun8i_hdmi_phy {
struct sun8i_hdmi_phy_variant *variant;
};
+struct sun8i_dw_hdmi_quirks {
+ enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
+ const struct drm_display_mode *mode);
+ unsigned int set_rate : 1;
+};
+
struct sun8i_dw_hdmi {
struct clk *clk_tmds;
struct device *dev;
@@ -178,6 +188,7 @@ struct sun8i_dw_hdmi {
struct sun8i_hdmi_phy *phy;
struct dw_hdmi_plat_data plat_data;
struct regulator *regulator;
+ const struct sun8i_dw_hdmi_quirks *quirks;
struct reset_control *rst_ctrl;
};
@@ -191,7 +202,8 @@ int sun8i_hdmi_phy_probe(struct sun8i_dw_hdmi *hdmi, struct device_node *node);
void sun8i_hdmi_phy_remove(struct sun8i_dw_hdmi *hdmi);
void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy);
-const struct dw_hdmi_phy_ops *sun8i_hdmi_phy_get_ops(void);
+void sun8i_hdmi_phy_set_ops(struct sun8i_hdmi_phy *phy,
+ struct dw_hdmi_plat_data *plat_data);
int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device *dev,
bool second_parent);
diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
index 471993097ced..66ea3a902e36 100644
--- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
+++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
@@ -14,6 +14,122 @@
*/
#define I2C_ADDR 0x69
+static const struct dw_hdmi_mpll_config sun50i_h6_mpll_cfg[] = {
+ {
+ 30666000, {
+ { 0x00b3, 0x0000 },
+ { 0x2153, 0x0000 },
+ { 0x40f3, 0x0000 },
+ },
+ }, {
+ 36800000, {
+ { 0x00b3, 0x0000 },
+ { 0x2153, 0x0000 },
+ { 0x40a2, 0x0001 },
+ },
+ }, {
+ 46000000, {
+ { 0x00b3, 0x0000 },
+ { 0x2142, 0x0001 },
+ { 0x40a2, 0x0001 },
+ },
+ }, {
+ 61333000, {
+ { 0x0072, 0x0001 },
+ { 0x2142, 0x0001 },
+ { 0x40a2, 0x0001 },
+ },
+ }, {
+ 73600000, {
+ { 0x0072, 0x0001 },
+ { 0x2142, 0x0001 },
+ { 0x4061, 0x0002 },
+ },
+ }, {
+ 92000000, {
+ { 0x0072, 0x0001 },
+ { 0x2145, 0x0002 },
+ { 0x4061, 0x0002 },
+ },
+ }, {
+ 122666000, {
+ { 0x0051, 0x0002 },
+ { 0x2145, 0x0002 },
+ { 0x4061, 0x0002 },
+ },
+ }, {
+ 147200000, {
+ { 0x0051, 0x0002 },
+ { 0x2145, 0x0002 },
+ { 0x4064, 0x0003 },
+ },
+ }, {
+ 184000000, {
+ { 0x0051, 0x0002 },
+ { 0x214c, 0x0003 },
+ { 0x4064, 0x0003 },
+ },
+ }, {
+ 226666000, {
+ { 0x0040, 0x0003 },
+ { 0x214c, 0x0003 },
+ { 0x4064, 0x0003 },
+ },
+ }, {
+ 272000000, {
+ { 0x0040, 0x0003 },
+ { 0x214c, 0x0003 },
+ { 0x5a64, 0x0003 },
+ },
+ }, {
+ 340000000, {
+ { 0x0040, 0x0003 },
+ { 0x3b4c, 0x0003 },
+ { 0x5a64, 0x0003 },
+ },
+ }, {
+ 594000000, {
+ { 0x1a40, 0x0003 },
+ { 0x3b4c, 0x0003 },
+ { 0x5a64, 0x0003 },
+ },
+ }, {
+ ~0UL, {
+ { 0x0000, 0x0000 },
+ { 0x0000, 0x0000 },
+ { 0x0000, 0x0000 },
+ },
+ }
+};
+
+static const struct dw_hdmi_curr_ctrl sun50i_h6_cur_ctr[] = {
+ /* pixelclk bpp8 bpp10 bpp12 */
+ { 25175000, { 0x0000, 0x0000, 0x0000 }, },
+ { 27000000, { 0x0012, 0x0000, 0x0000 }, },
+ { 59400000, { 0x0008, 0x0008, 0x0008 }, },
+ { 72000000, { 0x0008, 0x0008, 0x001b }, },
+ { 74250000, { 0x0013, 0x0013, 0x0013 }, },
+ { 90000000, { 0x0008, 0x001a, 0x001b }, },
+ { 118800000, { 0x001b, 0x001a, 0x001b }, },
+ { 144000000, { 0x001b, 0x001a, 0x0034 }, },
+ { 180000000, { 0x001b, 0x0033, 0x0034 }, },
+ { 216000000, { 0x0036, 0x0033, 0x0034 }, },
+ { 237600000, { 0x0036, 0x0033, 0x001b }, },
+ { 288000000, { 0x0036, 0x001b, 0x001b }, },
+ { 297000000, { 0x0019, 0x001b, 0x0019 }, },
+ { 330000000, { 0x0036, 0x001b, 0x001b }, },
+ { 594000000, { 0x003f, 0x001b, 0x001b }, },
+ { ~0UL, { 0x0000, 0x0000, 0x0000 }, }
+};
+
+static const struct dw_hdmi_phy_config sun50i_h6_phy_config[] = {
+ /*pixelclk symbol term vlev*/
+ { 74250000, 0x8009, 0x0004, 0x0232},
+ { 148500000, 0x8029, 0x0004, 0x0273},
+ { 594000000, 0x8039, 0x0004, 0x014a},
+ { ~0UL, 0x0000, 0x0000, 0x0000}
+};
+
static int sun8i_hdmi_phy_config_a83t(struct dw_hdmi *hdmi,
struct sun8i_hdmi_phy *phy,
unsigned int clk_rate)
@@ -279,8 +395,31 @@ static const struct dw_hdmi_phy_ops sun8i_hdmi_phy_ops = {
.setup_hpd = &dw_hdmi_phy_setup_hpd,
};
+static void sun8i_hdmi_phy_unlock(struct sun8i_hdmi_phy *phy)
+{
+ /* enable read access to HDMI controller */
+ regmap_write(phy->regs, SUN8I_HDMI_PHY_READ_EN_REG,
+ SUN8I_HDMI_PHY_READ_EN_MAGIC);
+
+ /* unscramble register offsets */
+ regmap_write(phy->regs, SUN8I_HDMI_PHY_UNSCRAMBLE_REG,
+ SUN8I_HDMI_PHY_UNSCRAMBLE_MAGIC);
+}
+
+static void sun50i_hdmi_phy_init_h6(struct sun8i_hdmi_phy *phy)
+{
+ regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG,
+ SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN,
+ SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN);
+
+ regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG,
+ 0xffff0000, 0x80c00000);
+}
+
static void sun8i_hdmi_phy_init_a83t(struct sun8i_hdmi_phy *phy)
{
+ sun8i_hdmi_phy_unlock(phy);
+
regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG,
SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK,
SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK);
@@ -298,6 +437,8 @@ static void sun8i_hdmi_phy_init_h3(struct sun8i_hdmi_phy *phy)
{
unsigned int val;
+ sun8i_hdmi_phy_unlock(phy);
+
regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 0);
regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
SUN8I_HDMI_PHY_ANA_CFG1_ENBI,
@@ -372,20 +513,23 @@ static void sun8i_hdmi_phy_init_h3(struct sun8i_hdmi_phy *phy)
void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy)
{
- /* enable read access to HDMI controller */
- regmap_write(phy->regs, SUN8I_HDMI_PHY_READ_EN_REG,
- SUN8I_HDMI_PHY_READ_EN_MAGIC);
-
- /* unscramble register offsets */
- regmap_write(phy->regs, SUN8I_HDMI_PHY_UNSCRAMBLE_REG,
- SUN8I_HDMI_PHY_UNSCRAMBLE_MAGIC);
-
phy->variant->phy_init(phy);
}
-const struct dw_hdmi_phy_ops *sun8i_hdmi_phy_get_ops(void)
+void sun8i_hdmi_phy_set_ops(struct sun8i_hdmi_phy *phy,
+ struct dw_hdmi_plat_data *plat_data)
{
- return &sun8i_hdmi_phy_ops;
+ struct sun8i_hdmi_phy_variant *variant = phy->variant;
+
+ if (variant->is_custom_phy) {
+ plat_data->phy_ops = &sun8i_hdmi_phy_ops;
+ plat_data->phy_name = "sun8i_dw_hdmi_phy";
+ plat_data->phy_data = phy;
+ } else {
+ plat_data->mpll_cfg = variant->mpll_cfg;
+ plat_data->cur_ctr = variant->cur_ctr;
+ plat_data->phy_config = variant->phy_cfg;
+ }
}
static struct regmap_config sun8i_hdmi_phy_regmap_config = {
@@ -396,14 +540,8 @@ static struct regmap_config sun8i_hdmi_phy_regmap_config = {
.name = "phy"
};
-static const struct sun8i_hdmi_phy_variant sun50i_a64_hdmi_phy = {
- .has_phy_clk = true,
- .phy_init = &sun8i_hdmi_phy_init_h3,
- .phy_disable = &sun8i_hdmi_phy_disable_h3,
- .phy_config = &sun8i_hdmi_phy_config_h3,
-};
-
static const struct sun8i_hdmi_phy_variant sun8i_a83t_hdmi_phy = {
+ .is_custom_phy = true,
.phy_init = &sun8i_hdmi_phy_init_a83t,
.phy_disable = &sun8i_hdmi_phy_disable_a83t,
.phy_config = &sun8i_hdmi_phy_config_a83t,
@@ -411,6 +549,7 @@ static const struct sun8i_hdmi_phy_variant sun8i_a83t_hdmi_phy = {
static const struct sun8i_hdmi_phy_variant sun8i_h3_hdmi_phy = {
.has_phy_clk = true,
+ .is_custom_phy = true,
.phy_init = &sun8i_hdmi_phy_init_h3,
.phy_disable = &sun8i_hdmi_phy_disable_h3,
.phy_config = &sun8i_hdmi_phy_config_h3,
@@ -419,17 +558,29 @@ static const struct sun8i_hdmi_phy_variant sun8i_h3_hdmi_phy = {
static const struct sun8i_hdmi_phy_variant sun8i_r40_hdmi_phy = {
.has_phy_clk = true,
.has_second_pll = true,
+ .is_custom_phy = true,
+ .phy_init = &sun8i_hdmi_phy_init_h3,
+ .phy_disable = &sun8i_hdmi_phy_disable_h3,
+ .phy_config = &sun8i_hdmi_phy_config_h3,
+};
+
+static const struct sun8i_hdmi_phy_variant sun50i_a64_hdmi_phy = {
+ .has_phy_clk = true,
+ .is_custom_phy = true,
.phy_init = &sun8i_hdmi_phy_init_h3,
.phy_disable = &sun8i_hdmi_phy_disable_h3,
.phy_config = &sun8i_hdmi_phy_config_h3,
};
+static const struct sun8i_hdmi_phy_variant sun50i_h6_hdmi_phy = {
+ .cur_ctr = sun50i_h6_cur_ctr,
+ .mpll_cfg = sun50i_h6_mpll_cfg,
+ .phy_cfg = sun50i_h6_phy_config,
+ .phy_init = &sun50i_hdmi_phy_init_h6,
+};
+
static const struct of_device_id sun8i_hdmi_phy_of_table[] = {
{
- .compatible = "allwinner,sun50i-a64-hdmi-phy",
- .data = &sun50i_a64_hdmi_phy,
- },
- {
.compatible = "allwinner,sun8i-a83t-hdmi-phy",
.data = &sun8i_a83t_hdmi_phy,
},
@@ -441,6 +592,14 @@ static const struct of_device_id sun8i_hdmi_phy_of_table[] = {
.compatible = "allwinner,sun8i-r40-hdmi-phy",
.data = &sun8i_r40_hdmi_phy,
},
+ {
+ .compatible = "allwinner,sun50i-a64-hdmi-phy",
+ .data = &sun50i_a64_hdmi_phy,
+ },
+ {
+ .compatible = "allwinner,sun50i-h6-hdmi-phy",
+ .data = &sun50i_h6_hdmi_phy,
+ },
{ /* sentinel */ }
};
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index 8b3d02b146b7..44a9ba7d8433 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -368,6 +368,7 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
struct sun8i_mixer *mixer;
struct resource *res;
void __iomem *regs;
+ unsigned int base;
int plane_cnt;
int i, ret;
@@ -456,33 +457,60 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
list_add_tail(&mixer->engine.list, &drv->engine_list);
- /* Reset the registers */
- for (i = 0x0; i < 0x20000; i += 4)
- regmap_write(mixer->engine.regs, i, 0);
+ base = sun8i_blender_base(mixer);
+
+ /* Reset registers and disable unused sub-engines */
+ if (mixer->cfg->is_de3) {
+ for (i = 0; i < DE3_MIXER_UNIT_SIZE; i += 4)
+ regmap_write(mixer->engine.regs, i, 0);
+
+ regmap_write(mixer->engine.regs, SUN50I_MIXER_FCE_EN, 0);
+ regmap_write(mixer->engine.regs, SUN50I_MIXER_PEAK_EN, 0);
+ regmap_write(mixer->engine.regs, SUN50I_MIXER_LCTI_EN, 0);
+ regmap_write(mixer->engine.regs, SUN50I_MIXER_BLS_EN, 0);
+ regmap_write(mixer->engine.regs, SUN50I_MIXER_FCC_EN, 0);
+ regmap_write(mixer->engine.regs, SUN50I_MIXER_DNS_EN, 0);
+ regmap_write(mixer->engine.regs, SUN50I_MIXER_DRC_EN, 0);
+ regmap_write(mixer->engine.regs, SUN50I_MIXER_FMT_EN, 0);
+ regmap_write(mixer->engine.regs, SUN50I_MIXER_CDC0_EN, 0);
+ regmap_write(mixer->engine.regs, SUN50I_MIXER_CDC1_EN, 0);
+ } else {
+ for (i = 0; i < DE2_MIXER_UNIT_SIZE; i += 4)
+ regmap_write(mixer->engine.regs, i, 0);
+
+ regmap_write(mixer->engine.regs, SUN8I_MIXER_FCE_EN, 0);
+ regmap_write(mixer->engine.regs, SUN8I_MIXER_BWS_EN, 0);
+ regmap_write(mixer->engine.regs, SUN8I_MIXER_LTI_EN, 0);
+ regmap_write(mixer->engine.regs, SUN8I_MIXER_PEAK_EN, 0);
+ regmap_write(mixer->engine.regs, SUN8I_MIXER_ASE_EN, 0);
+ regmap_write(mixer->engine.regs, SUN8I_MIXER_FCC_EN, 0);
+ regmap_write(mixer->engine.regs, SUN8I_MIXER_DCSC_EN, 0);
+ }
/* Enable the mixer */
regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_CTL,
SUN8I_MIXER_GLOBAL_CTL_RT_EN);
/* Set background color to black */
- regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_BKCOLOR,
+ regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_BKCOLOR(base),
SUN8I_MIXER_BLEND_COLOR_BLACK);
/*
* Set fill color of bottom plane to black. Generally not needed
* except when VI plane is at bottom (zpos = 0) and enabled.
*/
- regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL,
+ regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0));
- regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ATTR_FCOLOR(0),
+ regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ATTR_FCOLOR(base, 0),
SUN8I_MIXER_BLEND_COLOR_BLACK);
plane_cnt = mixer->cfg->vi_num + mixer->cfg->ui_num;
for (i = 0; i < plane_cnt; i++)
- regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_MODE(i),
+ regmap_write(mixer->engine.regs,
+ SUN8I_MIXER_BLEND_MODE(base, i),
SUN8I_MIXER_BLEND_MODE_DEF);
- regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL,
+ regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK, 0);
return 0;
@@ -585,6 +613,15 @@ static const struct sun8i_mixer_cfg sun50i_a64_mixer1_cfg = {
.vi_num = 1,
};
+static const struct sun8i_mixer_cfg sun50i_h6_mixer0_cfg = {
+ .ccsc = 0,
+ .is_de3 = true,
+ .mod_rate = 600000000,
+ .scaler_mask = 0xf,
+ .ui_num = 3,
+ .vi_num = 1,
+};
+
static const struct of_device_id sun8i_mixer_of_table[] = {
{
.compatible = "allwinner,sun8i-a83t-de2-mixer-0",
@@ -618,6 +655,10 @@ static const struct of_device_id sun8i_mixer_of_table[] = {
.compatible = "allwinner,sun50i-a64-de2-mixer-1",
.data = &sun50i_a64_mixer1_cfg,
},
+ {
+ .compatible = "allwinner,sun50i-h6-de3-mixer-0",
+ .data = &sun50i_h6_mixer0_cfg,
+ },
{ }
};
MODULE_DEVICE_TABLE(of, sun8i_mixer_of_table);
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.h b/drivers/gpu/drm/sun4i/sun8i_mixer.h
index 406c42e752d7..913d14ce68b0 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.h
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.h
@@ -29,24 +29,41 @@
#define SUN8I_MIXER_GLOBAL_DBUFF_ENABLE BIT(0)
-#define SUN8I_MIXER_BLEND_PIPE_CTL 0x1000
-#define SUN8I_MIXER_BLEND_ATTR_FCOLOR(x) (0x1004 + 0x10 * (x) + 0x0)
-#define SUN8I_MIXER_BLEND_ATTR_INSIZE(x) (0x1004 + 0x10 * (x) + 0x4)
-#define SUN8I_MIXER_BLEND_ATTR_COORD(x) (0x1004 + 0x10 * (x) + 0x8)
-#define SUN8I_MIXER_BLEND_ROUTE 0x1080
-#define SUN8I_MIXER_BLEND_PREMULTIPLY 0x1084
-#define SUN8I_MIXER_BLEND_BKCOLOR 0x1088
-#define SUN8I_MIXER_BLEND_OUTSIZE 0x108c
-#define SUN8I_MIXER_BLEND_MODE(x) (0x1090 + 0x04 * (x))
-#define SUN8I_MIXER_BLEND_CK_CTL 0x10b0
-#define SUN8I_MIXER_BLEND_CK_CFG 0x10b4
-#define SUN8I_MIXER_BLEND_CK_MAX(x) (0x10c0 + 0x04 * (x))
-#define SUN8I_MIXER_BLEND_CK_MIN(x) (0x10e0 + 0x04 * (x))
-#define SUN8I_MIXER_BLEND_OUTCTL 0x10fc
+#define DE2_MIXER_UNIT_SIZE 0x6000
+#define DE3_MIXER_UNIT_SIZE 0x3000
+
+#define DE2_BLD_BASE 0x1000
+#define DE2_CH_BASE 0x2000
+#define DE2_CH_SIZE 0x1000
+
+#define DE3_BLD_BASE 0x0800
+#define DE3_CH_BASE 0x1000
+#define DE3_CH_SIZE 0x0800
+
+#define SUN8I_MIXER_BLEND_PIPE_CTL(base) ((base) + 0)
+#define SUN8I_MIXER_BLEND_ATTR_FCOLOR(base, x) ((base) + 0x4 + 0x10 * (x))
+#define SUN8I_MIXER_BLEND_ATTR_INSIZE(base, x) ((base) + 0x8 + 0x10 * (x))
+#define SUN8I_MIXER_BLEND_ATTR_COORD(base, x) ((base) + 0xc + 0x10 * (x))
+#define SUN8I_MIXER_BLEND_ROUTE(base) ((base) + 0x80)
+#define SUN8I_MIXER_BLEND_PREMULTIPLY(base) ((base) + 0x84)
+#define SUN8I_MIXER_BLEND_BKCOLOR(base) ((base) + 0x88)
+#define SUN8I_MIXER_BLEND_OUTSIZE(base) ((base) + 0x8c)
+#define SUN8I_MIXER_BLEND_MODE(base, x) ((base) + 0x90 + 0x04 * (x))
+#define SUN8I_MIXER_BLEND_CK_CTL(base) ((base) + 0xb0)
+#define SUN8I_MIXER_BLEND_CK_CFG(base) ((base) + 0xb4)
+#define SUN8I_MIXER_BLEND_CK_MAX(base, x) ((base) + 0xc0 + 0x04 * (x))
+#define SUN8I_MIXER_BLEND_CK_MIN(base, x) ((base) + 0xe0 + 0x04 * (x))
+#define SUN8I_MIXER_BLEND_OUTCTL(base) ((base) + 0xfc)
+#define SUN50I_MIXER_BLEND_CSC_CTL(base) ((base) + 0x100)
+#define SUN50I_MIXER_BLEND_CSC_COEFF(base, layer, x, y) \
+ ((base) + 0x110 + (layer) * 0x30 + (x) * 0x10 + 4 * (y))
+#define SUN50I_MIXER_BLEND_CSC_CONST(base, layer, i) \
+ ((base) + 0x110 + (layer) * 0x30 + (i) * 0x10 + 0x0c)
#define SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK GENMASK(12, 8)
#define SUN8I_MIXER_BLEND_PIPE_CTL_EN(pipe) BIT(8 + pipe)
#define SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(pipe) BIT(pipe)
+
/* colors are always in AARRGGBB format */
#define SUN8I_MIXER_BLEND_COLOR_BLACK 0xff000000
/* The following numbers are some still unknown magic numbers */
@@ -57,6 +74,9 @@
#define SUN8I_MIXER_BLEND_OUTCTL_INTERLACED BIT(1)
+#define SUN50I_MIXER_BLEND_CSC_CTL_EN(ch) BIT(ch)
+#define SUN50I_MIXER_BLEND_CSC_CONST_VAL(d, c) (((d) << 16) | ((c) & 0xffff))
+
#define SUN8I_MIXER_FBFMT_ARGB8888 0
#define SUN8I_MIXER_FBFMT_ABGR8888 1
#define SUN8I_MIXER_FBFMT_RGBA8888 2
@@ -95,8 +115,8 @@
#define SUN8I_MIXER_FBFMT_YUV411 14
/*
- * These sub-engines are still unknown now, the EN registers are here only to
- * be used to disable these sub-engines.
+ * Sub-engines listed bellow are unused for now. The EN registers are here only
+ * to be used to disable these sub-engines.
*/
#define SUN8I_MIXER_FCE_EN 0xa0000
#define SUN8I_MIXER_BWS_EN 0xa2000
@@ -106,6 +126,17 @@
#define SUN8I_MIXER_FCC_EN 0xaa000
#define SUN8I_MIXER_DCSC_EN 0xb0000
+#define SUN50I_MIXER_FCE_EN 0x70000
+#define SUN50I_MIXER_PEAK_EN 0x70800
+#define SUN50I_MIXER_LCTI_EN 0x71000
+#define SUN50I_MIXER_BLS_EN 0x71800
+#define SUN50I_MIXER_FCC_EN 0x72000
+#define SUN50I_MIXER_DNS_EN 0x80000
+#define SUN50I_MIXER_DRC_EN 0xa0000
+#define SUN50I_MIXER_FMT_EN 0xa8000
+#define SUN50I_MIXER_CDC0_EN 0xd0000
+#define SUN50I_MIXER_CDC1_EN 0xd8000
+
struct de2_fmt_info {
u32 drm_fmt;
u32 de2_fmt;
@@ -127,6 +158,7 @@ struct de2_fmt_info {
* are invalid.
* @mod_rate: module clock rate that needs to be set in order to have
* a functional block.
+ * @is_de3: true, if this is next gen display engine 3.0, false otherwise.
*/
struct sun8i_mixer_cfg {
int vi_num;
@@ -134,6 +166,7 @@ struct sun8i_mixer_cfg {
int scaler_mask;
int ccsc;
unsigned long mod_rate;
+ unsigned int is_de3 : 1;
};
struct sun8i_mixer {
@@ -153,5 +186,20 @@ engine_to_sun8i_mixer(struct sunxi_engine *engine)
return container_of(engine, struct sun8i_mixer, engine);
}
+static inline u32
+sun8i_blender_base(struct sun8i_mixer *mixer)
+{
+ return mixer->cfg->is_de3 ? DE3_BLD_BASE : DE2_BLD_BASE;
+}
+
+static inline u32
+sun8i_channel_base(struct sun8i_mixer *mixer, int channel)
+{
+ if (mixer->cfg->is_de3)
+ return DE3_CH_BASE + channel * DE3_CH_SIZE;
+ else
+ return DE2_CH_BASE + channel * DE2_CH_SIZE;
+}
+
const struct de2_fmt_info *sun8i_mixer_format_info(u32 format);
#endif /* _SUN8I_MIXER_H_ */
diff --git a/drivers/gpu/drm/sun4i/sun8i_tcon_top.c b/drivers/gpu/drm/sun4i/sun8i_tcon_top.c
index 3040a79f298f..fc36e0c10a37 100644
--- a/drivers/gpu/drm/sun4i/sun8i_tcon_top.c
+++ b/drivers/gpu/drm/sun4i/sun8i_tcon_top.c
@@ -9,11 +9,17 @@
#include <linux/component.h>
#include <linux/device.h>
#include <linux/module.h>
+#include <linux/of_device.h>
#include <linux/of_graph.h>
#include <linux/platform_device.h>
#include "sun8i_tcon_top.h"
+struct sun8i_tcon_top_quirks {
+ bool has_tcon_tv1;
+ bool has_dsi;
+};
+
static bool sun8i_tcon_top_node_is_tcon_top(struct device_node *node)
{
return !!of_match_node(sun8i_tcon_top_of_table, node);
@@ -121,10 +127,13 @@ static int sun8i_tcon_top_bind(struct device *dev, struct device *master,
struct platform_device *pdev = to_platform_device(dev);
struct clk_hw_onecell_data *clk_data;
struct sun8i_tcon_top *tcon_top;
+ const struct sun8i_tcon_top_quirks *quirks;
struct resource *res;
void __iomem *regs;
int ret, i;
+ quirks = of_device_get_match_data(&pdev->dev);
+
tcon_top = devm_kzalloc(dev, sizeof(*tcon_top), GFP_KERNEL);
if (!tcon_top)
return -ENOMEM;
@@ -168,6 +177,13 @@ static int sun8i_tcon_top_bind(struct device *dev, struct device *master,
}
/*
+ * At least on H6, some registers have some bits set by default
+ * which may cause issues. Clear them here.
+ */
+ writel(0, regs + TCON_TOP_PORT_SEL_REG);
+ writel(0, regs + TCON_TOP_GATE_SRC_REG);
+
+ /*
* TCON TOP has two muxes, which select parent clock for each TCON TV
* channel clock. Parent could be either TCON TV or TVE clock. For now
* we leave this fixed to TCON TV, since TVE driver for R40 is not yet
@@ -180,15 +196,17 @@ static int sun8i_tcon_top_bind(struct device *dev, struct device *master,
&tcon_top->reg_lock,
TCON_TOP_TCON_TV0_GATE, 0);
- clk_data->hws[CLK_TCON_TOP_TV1] =
- sun8i_tcon_top_register_gate(dev, "tcon-tv1", regs,
- &tcon_top->reg_lock,
- TCON_TOP_TCON_TV1_GATE, 1);
+ if (quirks->has_tcon_tv1)
+ clk_data->hws[CLK_TCON_TOP_TV1] =
+ sun8i_tcon_top_register_gate(dev, "tcon-tv1", regs,
+ &tcon_top->reg_lock,
+ TCON_TOP_TCON_TV1_GATE, 1);
- clk_data->hws[CLK_TCON_TOP_DSI] =
- sun8i_tcon_top_register_gate(dev, "dsi", regs,
- &tcon_top->reg_lock,
- TCON_TOP_TCON_DSI_GATE, 2);
+ if (quirks->has_dsi)
+ clk_data->hws[CLK_TCON_TOP_DSI] =
+ sun8i_tcon_top_register_gate(dev, "dsi", regs,
+ &tcon_top->reg_lock,
+ TCON_TOP_TCON_DSI_GATE, 2);
for (i = 0; i < CLK_NUM; i++)
if (IS_ERR(clk_data->hws[i])) {
@@ -250,9 +268,25 @@ static int sun8i_tcon_top_remove(struct platform_device *pdev)
return 0;
}
+const struct sun8i_tcon_top_quirks sun8i_r40_tcon_top_quirks = {
+ .has_tcon_tv1 = true,
+ .has_dsi = true,
+};
+
+const struct sun8i_tcon_top_quirks sun50i_h6_tcon_top_quirks = {
+ /* Nothing special */
+};
+
/* sun4i_drv uses this list to check if a device node is a TCON TOP */
const struct of_device_id sun8i_tcon_top_of_table[] = {
- { .compatible = "allwinner,sun8i-r40-tcon-top" },
+ {
+ .compatible = "allwinner,sun8i-r40-tcon-top",
+ .data = &sun8i_r40_tcon_top_quirks
+ },
+ {
+ .compatible = "allwinner,sun50i-h6-tcon-top",
+ .data = &sun50i_h6_tcon_top_quirks
+ },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sun8i_tcon_top_of_table);
diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
index 28c15c6ef1ef..e3fc8fa920fb 100644
--- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
@@ -30,7 +30,10 @@ static void sun8i_ui_layer_enable(struct sun8i_mixer *mixer, int channel,
int overlay, bool enable, unsigned int zpos,
unsigned int old_zpos)
{
- u32 val;
+ u32 val, bld_base, ch_base;
+
+ bld_base = sun8i_blender_base(mixer);
+ ch_base = sun8i_channel_base(mixer, channel);
DRM_DEBUG_DRIVER("%sabling channel %d overlay %d\n",
enable ? "En" : "Dis", channel, overlay);
@@ -41,17 +44,17 @@ static void sun8i_ui_layer_enable(struct sun8i_mixer *mixer, int channel,
val = 0;
regmap_update_bits(mixer->engine.regs,
- SUN8I_MIXER_CHAN_UI_LAYER_ATTR(channel, overlay),
+ SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch_base, overlay),
SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN, val);
if (!enable || zpos != old_zpos) {
regmap_update_bits(mixer->engine.regs,
- SUN8I_MIXER_BLEND_PIPE_CTL,
+ SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
SUN8I_MIXER_BLEND_PIPE_CTL_EN(old_zpos),
0);
regmap_update_bits(mixer->engine.regs,
- SUN8I_MIXER_BLEND_ROUTE,
+ SUN8I_MIXER_BLEND_ROUTE(bld_base),
SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(old_zpos),
0);
}
@@ -60,12 +63,13 @@ static void sun8i_ui_layer_enable(struct sun8i_mixer *mixer, int channel,
val = SUN8I_MIXER_BLEND_PIPE_CTL_EN(zpos);
regmap_update_bits(mixer->engine.regs,
- SUN8I_MIXER_BLEND_PIPE_CTL, val, val);
+ SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
+ val, val);
val = channel << SUN8I_MIXER_BLEND_ROUTE_PIPE_SHIFT(zpos);
regmap_update_bits(mixer->engine.regs,
- SUN8I_MIXER_BLEND_ROUTE,
+ SUN8I_MIXER_BLEND_ROUTE(bld_base),
SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(zpos),
val);
}
@@ -77,12 +81,16 @@ static int sun8i_ui_layer_update_coord(struct sun8i_mixer *mixer, int channel,
{
struct drm_plane_state *state = plane->state;
u32 src_w, src_h, dst_w, dst_h;
+ u32 bld_base, ch_base;
u32 outsize, insize;
u32 hphase, vphase;
DRM_DEBUG_DRIVER("Updating UI channel %d overlay %d\n",
channel, overlay);
+ bld_base = sun8i_blender_base(mixer);
+ ch_base = sun8i_channel_base(mixer, channel);
+
src_w = drm_rect_width(&state->src) >> 16;
src_h = drm_rect_height(&state->src) >> 16;
dst_w = drm_rect_width(&state->dst);
@@ -103,8 +111,8 @@ static int sun8i_ui_layer_update_coord(struct sun8i_mixer *mixer, int channel,
regmap_write(mixer->engine.regs,
SUN8I_MIXER_GLOBAL_SIZE,
outsize);
- regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_OUTSIZE,
- outsize);
+ regmap_write(mixer->engine.regs,
+ SUN8I_MIXER_BLEND_OUTSIZE(bld_base), outsize);
if (state->crtc)
interlaced = state->crtc->state->adjusted_mode.flags
@@ -116,7 +124,7 @@ static int sun8i_ui_layer_update_coord(struct sun8i_mixer *mixer, int channel,
val = 0;
regmap_update_bits(mixer->engine.regs,
- SUN8I_MIXER_BLEND_OUTCTL,
+ SUN8I_MIXER_BLEND_OUTCTL(bld_base),
SUN8I_MIXER_BLEND_OUTCTL_INTERLACED,
val);
@@ -129,10 +137,10 @@ static int sun8i_ui_layer_update_coord(struct sun8i_mixer *mixer, int channel,
state->src.x1 >> 16, state->src.y1 >> 16);
DRM_DEBUG_DRIVER("Layer source size W: %d H: %d\n", src_w, src_h);
regmap_write(mixer->engine.regs,
- SUN8I_MIXER_CHAN_UI_LAYER_SIZE(channel, overlay),
+ SUN8I_MIXER_CHAN_UI_LAYER_SIZE(ch_base, overlay),
insize);
regmap_write(mixer->engine.regs,
- SUN8I_MIXER_CHAN_UI_OVL_SIZE(channel),
+ SUN8I_MIXER_CHAN_UI_OVL_SIZE(ch_base),
insize);
if (insize != outsize || hphase || vphase) {
@@ -156,10 +164,10 @@ static int sun8i_ui_layer_update_coord(struct sun8i_mixer *mixer, int channel,
state->dst.x1, state->dst.y1);
DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h);
regmap_write(mixer->engine.regs,
- SUN8I_MIXER_BLEND_ATTR_COORD(zpos),
+ SUN8I_MIXER_BLEND_ATTR_COORD(bld_base, zpos),
SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1));
regmap_write(mixer->engine.regs,
- SUN8I_MIXER_BLEND_ATTR_INSIZE(zpos),
+ SUN8I_MIXER_BLEND_ATTR_INSIZE(bld_base, zpos),
outsize);
return 0;
@@ -170,7 +178,9 @@ static int sun8i_ui_layer_update_formats(struct sun8i_mixer *mixer, int channel,
{
struct drm_plane_state *state = plane->state;
const struct de2_fmt_info *fmt_info;
- u32 val;
+ u32 val, ch_base;
+
+ ch_base = sun8i_channel_base(mixer, channel);
fmt_info = sun8i_mixer_format_info(state->fb->format->format);
if (!fmt_info || !fmt_info->rgb) {
@@ -180,7 +190,7 @@ static int sun8i_ui_layer_update_formats(struct sun8i_mixer *mixer, int channel,
val = fmt_info->de2_fmt << SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_OFFSET;
regmap_update_bits(mixer->engine.regs,
- SUN8I_MIXER_CHAN_UI_LAYER_ATTR(channel, overlay),
+ SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch_base, overlay),
SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK, val);
return 0;
@@ -193,8 +203,11 @@ static int sun8i_ui_layer_update_buffer(struct sun8i_mixer *mixer, int channel,
struct drm_framebuffer *fb = state->fb;
struct drm_gem_cma_object *gem;
dma_addr_t paddr;
+ u32 ch_base;
int bpp;
+ ch_base = sun8i_channel_base(mixer, channel);
+
/* Get the physical address of the buffer in memory */
gem = drm_fb_cma_get_gem_obj(fb, 0);
@@ -211,13 +224,13 @@ static int sun8i_ui_layer_update_buffer(struct sun8i_mixer *mixer, int channel,
/* Set the line width */
DRM_DEBUG_DRIVER("Layer line width: %d bytes\n", fb->pitches[0]);
regmap_write(mixer->engine.regs,
- SUN8I_MIXER_CHAN_UI_LAYER_PITCH(channel, overlay),
+ SUN8I_MIXER_CHAN_UI_LAYER_PITCH(ch_base, overlay),
fb->pitches[0]);
DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
regmap_write(mixer->engine.regs,
- SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(channel, overlay),
+ SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(ch_base, overlay),
lower_32_bits(paddr));
return 0;
diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.h b/drivers/gpu/drm/sun4i/sun8i_ui_layer.h
index 123b15ea9918..f4389cf0ba20 100644
--- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.h
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.h
@@ -18,23 +18,26 @@
#include <drm/drm_plane.h>
-#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch, layer) \
- (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x0)
-#define SUN8I_MIXER_CHAN_UI_LAYER_SIZE(ch, layer) \
- (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x4)
-#define SUN8I_MIXER_CHAN_UI_LAYER_COORD(ch, layer) \
- (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x8)
-#define SUN8I_MIXER_CHAN_UI_LAYER_PITCH(ch, layer) \
- (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0xc)
-#define SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(ch, layer) \
- (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x10)
-#define SUN8I_MIXER_CHAN_UI_LAYER_BOT_LADDR(ch, layer) \
- (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x14)
-#define SUN8I_MIXER_CHAN_UI_LAYER_FCOLOR(ch, layer) \
- (0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x18)
-#define SUN8I_MIXER_CHAN_UI_TOP_HADDR(ch) (0x2000 + 0x1000 * (ch) + 0x80)
-#define SUN8I_MIXER_CHAN_UI_BOT_HADDR(ch) (0x2000 + 0x1000 * (ch) + 0x84)
-#define SUN8I_MIXER_CHAN_UI_OVL_SIZE(ch) (0x2000 + 0x1000 * (ch) + 0x88)
+#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR(base, layer) \
+ ((base) + 0x20 * (layer) + 0x0)
+#define SUN8I_MIXER_CHAN_UI_LAYER_SIZE(base, layer) \
+ ((base) + 0x20 * (layer) + 0x4)
+#define SUN8I_MIXER_CHAN_UI_LAYER_COORD(base, layer) \
+ ((base) + 0x20 * (layer) + 0x8)
+#define SUN8I_MIXER_CHAN_UI_LAYER_PITCH(base, layer) \
+ ((base) + 0x20 * (layer) + 0xc)
+#define SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(base, layer) \
+ ((base) + 0x20 * (layer) + 0x10)
+#define SUN8I_MIXER_CHAN_UI_LAYER_BOT_LADDR(base, layer) \
+ ((base) + 0x20 * (layer) + 0x14)
+#define SUN8I_MIXER_CHAN_UI_LAYER_FCOLOR(base, layer) \
+ ((base) + 0x20 * (layer) + 0x18)
+#define SUN8I_MIXER_CHAN_UI_TOP_HADDR(base) \
+ ((base) + 0x80)
+#define SUN8I_MIXER_CHAN_UI_BOT_HADDR(base) \
+ ((base) + 0x84)
+#define SUN8I_MIXER_CHAN_UI_OVL_SIZE(base) \
+ ((base) + 0x88)
#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN BIT(0)
#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_MASK GENMASK(2, 1)
diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_scaler.c b/drivers/gpu/drm/sun4i/sun8i_ui_scaler.c
index 6bb2aa164c8e..ae0806bccac7 100644
--- a/drivers/gpu/drm/sun4i/sun8i_ui_scaler.c
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_scaler.c
@@ -10,6 +10,7 @@
*/
#include "sun8i_ui_scaler.h"
+#include "sun8i_vi_scaler.h"
static const u32 lan2coefftab16[240] = {
0x00004000, 0x00033ffe, 0x00063efc, 0x000a3bfb,
@@ -88,6 +89,20 @@ static const u32 lan2coefftab16[240] = {
0x0b1c1603, 0x0d1c1502, 0x0e1d1401, 0x0f1d1301,
};
+static u32 sun8i_ui_scaler_base(struct sun8i_mixer *mixer, int channel)
+{
+ int vi_num = mixer->cfg->vi_num;
+
+ if (mixer->cfg->is_de3)
+ return DE3_VI_SCALER_UNIT_BASE +
+ DE3_VI_SCALER_UNIT_SIZE * vi_num +
+ DE3_UI_SCALER_UNIT_SIZE * (channel - vi_num);
+ else
+ return DE2_VI_SCALER_UNIT_BASE +
+ DE2_VI_SCALER_UNIT_SIZE * vi_num +
+ DE2_UI_SCALER_UNIT_SIZE * (channel - vi_num);
+}
+
static int sun8i_ui_scaler_coef_index(unsigned int step)
{
unsigned int scale, int_part, float_part;
@@ -114,33 +129,35 @@ static int sun8i_ui_scaler_coef_index(unsigned int step)
void sun8i_ui_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable)
{
- int vi_cnt = mixer->cfg->vi_num;
- u32 val;
+ u32 val, base;
- if (WARN_ON(layer < vi_cnt))
+ if (WARN_ON(layer < mixer->cfg->vi_num))
return;
+ base = sun8i_ui_scaler_base(mixer, layer);
+
if (enable)
val = SUN8I_SCALER_GSU_CTRL_EN |
SUN8I_SCALER_GSU_CTRL_COEFF_RDY;
else
val = 0;
- regmap_write(mixer->engine.regs,
- SUN8I_SCALER_GSU_CTRL(vi_cnt, layer - vi_cnt), val);
+ regmap_write(mixer->engine.regs, SUN8I_SCALER_GSU_CTRL(base), val);
}
void sun8i_ui_scaler_setup(struct sun8i_mixer *mixer, int layer,
u32 src_w, u32 src_h, u32 dst_w, u32 dst_h,
u32 hscale, u32 vscale, u32 hphase, u32 vphase)
{
- int vi_cnt = mixer->cfg->vi_num;
u32 insize, outsize;
int i, offset;
+ u32 base;
- if (WARN_ON(layer < vi_cnt))
+ if (WARN_ON(layer < mixer->cfg->vi_num))
return;
+ base = sun8i_ui_scaler_base(mixer, layer);
+
hphase <<= SUN8I_UI_SCALER_PHASE_FRAC - 16;
vphase <<= SUN8I_UI_SCALER_PHASE_FRAC - 16;
hscale <<= SUN8I_UI_SCALER_SCALE_FRAC - 16;
@@ -149,24 +166,22 @@ void sun8i_ui_scaler_setup(struct sun8i_mixer *mixer, int layer,
insize = SUN8I_UI_SCALER_SIZE(src_w, src_h);
outsize = SUN8I_UI_SCALER_SIZE(dst_w, dst_h);
- layer -= vi_cnt;
-
regmap_write(mixer->engine.regs,
- SUN8I_SCALER_GSU_OUTSIZE(vi_cnt, layer), outsize);
+ SUN8I_SCALER_GSU_OUTSIZE(base), outsize);
regmap_write(mixer->engine.regs,
- SUN8I_SCALER_GSU_INSIZE(vi_cnt, layer), insize);
+ SUN8I_SCALER_GSU_INSIZE(base), insize);
regmap_write(mixer->engine.regs,
- SUN8I_SCALER_GSU_HSTEP(vi_cnt, layer), hscale);
+ SUN8I_SCALER_GSU_HSTEP(base), hscale);
regmap_write(mixer->engine.regs,
- SUN8I_SCALER_GSU_VSTEP(vi_cnt, layer), vscale);
+ SUN8I_SCALER_GSU_VSTEP(base), vscale);
regmap_write(mixer->engine.regs,
- SUN8I_SCALER_GSU_HPHASE(vi_cnt, layer), hphase);
+ SUN8I_SCALER_GSU_HPHASE(base), hphase);
regmap_write(mixer->engine.regs,
- SUN8I_SCALER_GSU_VPHASE(vi_cnt, layer), vphase);
+ SUN8I_SCALER_GSU_VPHASE(base), vphase);
offset = sun8i_ui_scaler_coef_index(hscale) *
SUN8I_UI_SCALER_COEFF_COUNT;
for (i = 0; i < SUN8I_UI_SCALER_COEFF_COUNT; i++)
regmap_write(mixer->engine.regs,
- SUN8I_SCALER_GSU_HCOEFF(vi_cnt, layer, i),
+ SUN8I_SCALER_GSU_HCOEFF(base, i),
lan2coefftab16[offset + i]);
}
diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_scaler.h b/drivers/gpu/drm/sun4i/sun8i_ui_scaler.h
index 86295be8be78..1ef4bd6f2718 100644
--- a/drivers/gpu/drm/sun4i/sun8i_ui_scaler.h
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_scaler.h
@@ -11,6 +11,9 @@
#include "sun8i_mixer.h"
+#define DE2_UI_SCALER_UNIT_SIZE 0x10000
+#define DE3_UI_SCALER_UNIT_SIZE 0x08000
+
/* this two macros assumes 16 fractional bits which is standard in DRM */
#define SUN8I_UI_SCALER_SCALE_MIN 1
#define SUN8I_UI_SCALER_SCALE_MAX ((1UL << 20) - 1)
@@ -20,23 +23,14 @@
#define SUN8I_UI_SCALER_COEFF_COUNT 16
#define SUN8I_UI_SCALER_SIZE(w, h) (((h) - 1) << 16 | ((w) - 1))
-#define SUN8I_SCALER_GSU_CTRL(vi_cnt, ui_idx) \
- (0x20000 + 0x20000 * (vi_cnt) + 0x10000 * (ui_idx) + 0x0)
-#define SUN8I_SCALER_GSU_OUTSIZE(vi_cnt, ui_idx) \
- (0x20000 + 0x20000 * (vi_cnt) + 0x10000 * (ui_idx) + 0x40)
-#define SUN8I_SCALER_GSU_INSIZE(vi_cnt, ui_idx) \
- (0x20000 + 0x20000 * (vi_cnt) + 0x10000 * (ui_idx) + 0x80)
-#define SUN8I_SCALER_GSU_HSTEP(vi_cnt, ui_idx) \
- (0x20000 + 0x20000 * (vi_cnt) + 0x10000 * (ui_idx) + 0x88)
-#define SUN8I_SCALER_GSU_VSTEP(vi_cnt, ui_idx) \
- (0x20000 + 0x20000 * (vi_cnt) + 0x10000 * (ui_idx) + 0x8c)
-#define SUN8I_SCALER_GSU_HPHASE(vi_cnt, ui_idx) \
- (0x20000 + 0x20000 * (vi_cnt) + 0x10000 * (ui_idx) + 0x90)
-#define SUN8I_SCALER_GSU_VPHASE(vi_cnt, ui_idx) \
- (0x20000 + 0x20000 * (vi_cnt) + 0x10000 * (ui_idx) + 0x98)
-#define SUN8I_SCALER_GSU_HCOEFF(vi_cnt, ui_idx, index) \
- (0x20000 + 0x20000 * (vi_cnt) + 0x10000 * (ui_idx) + 0x200 + \
- 0x4 * (index))
+#define SUN8I_SCALER_GSU_CTRL(base) ((base) + 0x0)
+#define SUN8I_SCALER_GSU_OUTSIZE(base) ((base) + 0x40)
+#define SUN8I_SCALER_GSU_INSIZE(base) ((base) + 0x80)
+#define SUN8I_SCALER_GSU_HSTEP(base) ((base) + 0x88)
+#define SUN8I_SCALER_GSU_VSTEP(base) ((base) + 0x8c)
+#define SUN8I_SCALER_GSU_HPHASE(base) ((base) + 0x90)
+#define SUN8I_SCALER_GSU_VPHASE(base) ((base) + 0x98)
+#define SUN8I_SCALER_GSU_HCOEFF(base, index) ((base) + 0x200 + 0x4 * (index))
#define SUN8I_SCALER_GSU_CTRL_EN BIT(0)
#define SUN8I_SCALER_GSU_CTRL_COEFF_RDY BIT(4)
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
index f4fe97813f94..4249edfb47ed 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
@@ -24,7 +24,10 @@ static void sun8i_vi_layer_enable(struct sun8i_mixer *mixer, int channel,
int overlay, bool enable, unsigned int zpos,
unsigned int old_zpos)
{
- u32 val;
+ u32 val, bld_base, ch_base;
+
+ bld_base = sun8i_blender_base(mixer);
+ ch_base = sun8i_channel_base(mixer, channel);
DRM_DEBUG_DRIVER("%sabling VI channel %d overlay %d\n",
enable ? "En" : "Dis", channel, overlay);
@@ -35,17 +38,17 @@ static void sun8i_vi_layer_enable(struct sun8i_mixer *mixer, int channel,
val = 0;
regmap_update_bits(mixer->engine.regs,
- SUN8I_MIXER_CHAN_VI_LAYER_ATTR(channel, overlay),
+ SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, overlay),
SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN, val);
if (!enable || zpos != old_zpos) {
regmap_update_bits(mixer->engine.regs,
- SUN8I_MIXER_BLEND_PIPE_CTL,
+ SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
SUN8I_MIXER_BLEND_PIPE_CTL_EN(old_zpos),
0);
regmap_update_bits(mixer->engine.regs,
- SUN8I_MIXER_BLEND_ROUTE,
+ SUN8I_MIXER_BLEND_ROUTE(bld_base),
SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(old_zpos),
0);
}
@@ -54,12 +57,13 @@ static void sun8i_vi_layer_enable(struct sun8i_mixer *mixer, int channel,
val = SUN8I_MIXER_BLEND_PIPE_CTL_EN(zpos);
regmap_update_bits(mixer->engine.regs,
- SUN8I_MIXER_BLEND_PIPE_CTL, val, val);
+ SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
+ val, val);
val = channel << SUN8I_MIXER_BLEND_ROUTE_PIPE_SHIFT(zpos);
regmap_update_bits(mixer->engine.regs,
- SUN8I_MIXER_BLEND_ROUTE,
+ SUN8I_MIXER_BLEND_ROUTE(bld_base),
SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(zpos),
val);
}
@@ -72,6 +76,7 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
struct drm_plane_state *state = plane->state;
const struct drm_format_info *format = state->fb->format;
u32 src_w, src_h, dst_w, dst_h;
+ u32 bld_base, ch_base;
u32 outsize, insize;
u32 hphase, vphase;
bool subsampled;
@@ -79,6 +84,9 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
DRM_DEBUG_DRIVER("Updating VI channel %d overlay %d\n",
channel, overlay);
+ bld_base = sun8i_blender_base(mixer);
+ ch_base = sun8i_channel_base(mixer, channel);
+
src_w = drm_rect_width(&state->src) >> 16;
src_h = drm_rect_height(&state->src) >> 16;
dst_w = drm_rect_width(&state->dst);
@@ -115,10 +123,10 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
(state->src.y1 >> 16) & ~(format->vsub - 1));
DRM_DEBUG_DRIVER("Layer source size W: %d H: %d\n", src_w, src_h);
regmap_write(mixer->engine.regs,
- SUN8I_MIXER_CHAN_VI_LAYER_SIZE(channel, overlay),
+ SUN8I_MIXER_CHAN_VI_LAYER_SIZE(ch_base, overlay),
insize);
regmap_write(mixer->engine.regs,
- SUN8I_MIXER_CHAN_VI_OVL_SIZE(channel),
+ SUN8I_MIXER_CHAN_VI_OVL_SIZE(ch_base),
insize);
/*
@@ -149,10 +157,10 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
state->dst.x1, state->dst.y1);
DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h);
regmap_write(mixer->engine.regs,
- SUN8I_MIXER_BLEND_ATTR_COORD(zpos),
+ SUN8I_MIXER_BLEND_ATTR_COORD(bld_base, zpos),
SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1));
regmap_write(mixer->engine.regs,
- SUN8I_MIXER_BLEND_ATTR_INSIZE(zpos),
+ SUN8I_MIXER_BLEND_ATTR_INSIZE(bld_base, zpos),
outsize);
return 0;
@@ -163,7 +171,9 @@ static int sun8i_vi_layer_update_formats(struct sun8i_mixer *mixer, int channel,
{
struct drm_plane_state *state = plane->state;
const struct de2_fmt_info *fmt_info;
- u32 val;
+ u32 val, ch_base;
+
+ ch_base = sun8i_channel_base(mixer, channel);
fmt_info = sun8i_mixer_format_info(state->fb->format->format);
if (!fmt_info) {
@@ -173,7 +183,7 @@ static int sun8i_vi_layer_update_formats(struct sun8i_mixer *mixer, int channel,
val = fmt_info->de2_fmt << SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_OFFSET;
regmap_update_bits(mixer->engine.regs,
- SUN8I_MIXER_CHAN_VI_LAYER_ATTR(channel, overlay),
+ SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, overlay),
SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_MASK, val);
if (fmt_info->csc != SUN8I_CSC_MODE_OFF) {
@@ -189,9 +199,17 @@ static int sun8i_vi_layer_update_formats(struct sun8i_mixer *mixer, int channel,
val = 0;
regmap_update_bits(mixer->engine.regs,
- SUN8I_MIXER_CHAN_VI_LAYER_ATTR(channel, overlay),
+ SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, overlay),
SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE, val);
+ /* It seems that YUV formats use global alpha setting. */
+ if (mixer->cfg->is_de3)
+ regmap_update_bits(mixer->engine.regs,
+ SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base,
+ overlay),
+ SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA_MASK,
+ SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA(0xff));
+
return 0;
}
@@ -204,8 +222,11 @@ static int sun8i_vi_layer_update_buffer(struct sun8i_mixer *mixer, int channel,
struct drm_gem_cma_object *gem;
u32 dx, dy, src_x, src_y;
dma_addr_t paddr;
+ u32 ch_base;
int i;
+ ch_base = sun8i_channel_base(mixer, channel);
+
/* Adjust x and y to be dividable by subsampling factor */
src_x = (state->src.x1 >> 16) & ~(format->hsub - 1);
src_y = (state->src.y1 >> 16) & ~(format->vsub - 1);
@@ -235,17 +256,17 @@ static int sun8i_vi_layer_update_buffer(struct sun8i_mixer *mixer, int channel,
DRM_DEBUG_DRIVER("Layer %d. line width: %d bytes\n",
i + 1, fb->pitches[i]);
regmap_write(mixer->engine.regs,
- SUN8I_MIXER_CHAN_VI_LAYER_PITCH(channel,
+ SUN8I_MIXER_CHAN_VI_LAYER_PITCH(ch_base,
overlay, i),
- fb->pitches[i]);
+ fb->pitches[i]);
DRM_DEBUG_DRIVER("Setting %d. buffer address to %pad\n",
i + 1, &paddr);
regmap_write(mixer->engine.regs,
- SUN8I_MIXER_CHAN_VI_LAYER_TOP_LADDR(channel,
+ SUN8I_MIXER_CHAN_VI_LAYER_TOP_LADDR(ch_base,
overlay, i),
- lower_32_bits(paddr));
+ lower_32_bits(paddr));
}
return 0;
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.h b/drivers/gpu/drm/sun4i/sun8i_vi_layer.h
index 6996627a0a76..8a5e6d01c85d 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.h
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.h
@@ -12,23 +12,26 @@
#include <drm/drm_plane.h>
-#define SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch, layer) \
- (0x2000 + 0x1000 * (ch) + 0x30 * (layer) + 0x0)
-#define SUN8I_MIXER_CHAN_VI_LAYER_SIZE(ch, layer) \
- (0x2000 + 0x1000 * (ch) + 0x30 * (layer) + 0x4)
-#define SUN8I_MIXER_CHAN_VI_LAYER_COORD(ch, layer) \
- (0x2000 + 0x1000 * (ch) + 0x30 * (layer) + 0x8)
-#define SUN8I_MIXER_CHAN_VI_LAYER_PITCH(ch, layer, plane) \
- (0x2000 + 0x1000 * (ch) + 0x30 * (layer) + 0xc + 4 * (plane))
-#define SUN8I_MIXER_CHAN_VI_LAYER_TOP_LADDR(ch, layer, plane) \
- (0x2000 + 0x1000 * (ch) + 0x30 * (layer) + 0x18 + 4 * (plane))
-#define SUN8I_MIXER_CHAN_VI_OVL_SIZE(ch) (0x2000 + 0x1000 * (ch) + 0xe8)
+#define SUN8I_MIXER_CHAN_VI_LAYER_ATTR(base, layer) \
+ ((base) + 0x30 * (layer) + 0x0)
+#define SUN8I_MIXER_CHAN_VI_LAYER_SIZE(base, layer) \
+ ((base) + 0x30 * (layer) + 0x4)
+#define SUN8I_MIXER_CHAN_VI_LAYER_COORD(base, layer) \
+ ((base) + 0x30 * (layer) + 0x8)
+#define SUN8I_MIXER_CHAN_VI_LAYER_PITCH(base, layer, plane) \
+ ((base) + 0x30 * (layer) + 0xc + 4 * (plane))
+#define SUN8I_MIXER_CHAN_VI_LAYER_TOP_LADDR(base, layer, plane) \
+ ((base) + 0x30 * (layer) + 0x18 + 4 * (plane))
+#define SUN8I_MIXER_CHAN_VI_OVL_SIZE(base) \
+ ((base) + 0xe8)
#define SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN BIT(0)
/* RGB mode should be set for RGB formats and cleared for YCbCr */
#define SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE BIT(15)
#define SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_OFFSET 8
#define SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_MASK GENMASK(12, 8)
+#define SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA_MASK GENMASK(31, 24)
+#define SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA(x) ((x) << 24)
struct sun8i_mixer;
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
index d3f1acb234b7..7ba75011adf9 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
@@ -833,6 +833,16 @@ static const u32 bicubic4coefftab32[480] = {
0x1012110d, 0x1012110d, 0x1013110c, 0x1013110c,
};
+static u32 sun8i_vi_scaler_base(struct sun8i_mixer *mixer, int channel)
+{
+ if (mixer->cfg->is_de3)
+ return DE3_VI_SCALER_UNIT_BASE +
+ DE3_VI_SCALER_UNIT_SIZE * channel;
+ else
+ return DE2_VI_SCALER_UNIT_BASE +
+ DE2_VI_SCALER_UNIT_SIZE * channel;
+}
+
static int sun8i_vi_scaler_coef_index(unsigned int step)
{
unsigned int scale, int_part, float_part;
@@ -857,7 +867,7 @@ static int sun8i_vi_scaler_coef_index(unsigned int step)
}
}
-static void sun8i_vi_scaler_set_coeff(struct regmap *map, int layer,
+static void sun8i_vi_scaler_set_coeff(struct regmap *map, u32 base,
u32 hstep, u32 vstep,
const struct drm_format_info *format)
{
@@ -877,29 +887,31 @@ static void sun8i_vi_scaler_set_coeff(struct regmap *map, int layer,
offset = sun8i_vi_scaler_coef_index(hstep) *
SUN8I_VI_SCALER_COEFF_COUNT;
for (i = 0; i < SUN8I_VI_SCALER_COEFF_COUNT; i++) {
- regmap_write(map, SUN8I_SCALER_VSU_YHCOEFF0(layer, i),
+ regmap_write(map, SUN8I_SCALER_VSU_YHCOEFF0(base, i),
lan3coefftab32_left[offset + i]);
- regmap_write(map, SUN8I_SCALER_VSU_YHCOEFF1(layer, i),
+ regmap_write(map, SUN8I_SCALER_VSU_YHCOEFF1(base, i),
lan3coefftab32_right[offset + i]);
- regmap_write(map, SUN8I_SCALER_VSU_CHCOEFF0(layer, i),
+ regmap_write(map, SUN8I_SCALER_VSU_CHCOEFF0(base, i),
ch_left[offset + i]);
- regmap_write(map, SUN8I_SCALER_VSU_CHCOEFF1(layer, i),
+ regmap_write(map, SUN8I_SCALER_VSU_CHCOEFF1(base, i),
ch_right[offset + i]);
}
offset = sun8i_vi_scaler_coef_index(hstep) *
SUN8I_VI_SCALER_COEFF_COUNT;
for (i = 0; i < SUN8I_VI_SCALER_COEFF_COUNT; i++) {
- regmap_write(map, SUN8I_SCALER_VSU_YVCOEFF(layer, i),
+ regmap_write(map, SUN8I_SCALER_VSU_YVCOEFF(base, i),
lan2coefftab32[offset + i]);
- regmap_write(map, SUN8I_SCALER_VSU_CVCOEFF(layer, i),
+ regmap_write(map, SUN8I_SCALER_VSU_CVCOEFF(base, i),
cy[offset + i]);
}
}
void sun8i_vi_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable)
{
- u32 val;
+ u32 val, base;
+
+ base = sun8i_vi_scaler_base(mixer, layer);
if (enable)
val = SUN8I_SCALER_VSU_CTRL_EN |
@@ -907,7 +919,8 @@ void sun8i_vi_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable)
else
val = 0;
- regmap_write(mixer->engine.regs, SUN8I_SCALER_VSU_CTRL(layer), val);
+ regmap_write(mixer->engine.regs,
+ SUN8I_SCALER_VSU_CTRL(base), val);
}
void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int layer,
@@ -917,6 +930,9 @@ void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int layer,
{
u32 chphase, cvphase;
u32 insize, outsize;
+ u32 base;
+
+ base = sun8i_vi_scaler_base(mixer, layer);
hphase <<= SUN8I_VI_SCALER_PHASE_FRAC - 16;
vphase <<= SUN8I_VI_SCALER_PHASE_FRAC - 16;
@@ -940,32 +956,44 @@ void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int layer,
cvphase = vphase;
}
+ if (mixer->cfg->is_de3) {
+ u32 val;
+
+ if (format->hsub == 1 && format->vsub == 1)
+ val = SUN50I_SCALER_VSU_SCALE_MODE_UI;
+ else
+ val = SUN50I_SCALER_VSU_SCALE_MODE_NORMAL;
+
+ regmap_write(mixer->engine.regs,
+ SUN50I_SCALER_VSU_SCALE_MODE(base), val);
+ }
+
regmap_write(mixer->engine.regs,
- SUN8I_SCALER_VSU_OUTSIZE(layer), outsize);
+ SUN8I_SCALER_VSU_OUTSIZE(base), outsize);
regmap_write(mixer->engine.regs,
- SUN8I_SCALER_VSU_YINSIZE(layer), insize);
+ SUN8I_SCALER_VSU_YINSIZE(base), insize);
regmap_write(mixer->engine.regs,
- SUN8I_SCALER_VSU_YHSTEP(layer), hscale);
+ SUN8I_SCALER_VSU_YHSTEP(base), hscale);
regmap_write(mixer->engine.regs,
- SUN8I_SCALER_VSU_YVSTEP(layer), vscale);
+ SUN8I_SCALER_VSU_YVSTEP(base), vscale);
regmap_write(mixer->engine.regs,
- SUN8I_SCALER_VSU_YHPHASE(layer), hphase);
+ SUN8I_SCALER_VSU_YHPHASE(base), hphase);
regmap_write(mixer->engine.regs,
- SUN8I_SCALER_VSU_YVPHASE(layer), vphase);
+ SUN8I_SCALER_VSU_YVPHASE(base), vphase);
regmap_write(mixer->engine.regs,
- SUN8I_SCALER_VSU_CINSIZE(layer),
+ SUN8I_SCALER_VSU_CINSIZE(base),
SUN8I_VI_SCALER_SIZE(src_w / format->hsub,
src_h / format->vsub));
regmap_write(mixer->engine.regs,
- SUN8I_SCALER_VSU_CHSTEP(layer),
+ SUN8I_SCALER_VSU_CHSTEP(base),
hscale / format->hsub);
regmap_write(mixer->engine.regs,
- SUN8I_SCALER_VSU_CVSTEP(layer),
+ SUN8I_SCALER_VSU_CVSTEP(base),
vscale / format->vsub);
regmap_write(mixer->engine.regs,
- SUN8I_SCALER_VSU_CHPHASE(layer), chphase);
+ SUN8I_SCALER_VSU_CHPHASE(base), chphase);
regmap_write(mixer->engine.regs,
- SUN8I_SCALER_VSU_CVPHASE(layer), cvphase);
- sun8i_vi_scaler_set_coeff(mixer->engine.regs, layer,
+ SUN8I_SCALER_VSU_CVPHASE(base), cvphase);
+ sun8i_vi_scaler_set_coeff(mixer->engine.regs, base,
hscale, vscale, format);
}
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.h b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.h
index a595ab643a5a..68f6593b369a 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.h
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.h
@@ -12,6 +12,12 @@
#include <drm/drm_fourcc.h>
#include "sun8i_mixer.h"
+#define DE2_VI_SCALER_UNIT_BASE 0x20000
+#define DE2_VI_SCALER_UNIT_SIZE 0x20000
+
+#define DE3_VI_SCALER_UNIT_BASE 0x20000
+#define DE3_VI_SCALER_UNIT_SIZE 0x08000
+
/* this two macros assumes 16 fractional bits which is standard in DRM */
#define SUN8I_VI_SCALER_SCALE_MIN 1
#define SUN8I_VI_SCALER_SCALE_MAX ((1UL << 20) - 1)
@@ -21,34 +27,48 @@
#define SUN8I_VI_SCALER_COEFF_COUNT 32
#define SUN8I_VI_SCALER_SIZE(w, h) (((h) - 1) << 16 | ((w) - 1))
-#define SUN8I_SCALER_VSU_CTRL(ch) (0x20000 + 0x20000 * (ch) + 0x0)
-#define SUN8I_SCALER_VSU_OUTSIZE(ch) (0x20000 + 0x20000 * (ch) + 0x40)
-#define SUN8I_SCALER_VSU_YINSIZE(ch) (0x20000 + 0x20000 * (ch) + 0x80)
-#define SUN8I_SCALER_VSU_YHSTEP(ch) (0x20000 + 0x20000 * (ch) + 0x88)
-#define SUN8I_SCALER_VSU_YVSTEP(ch) (0x20000 + 0x20000 * (ch) + 0x8c)
-#define SUN8I_SCALER_VSU_YHPHASE(ch) (0x20000 + 0x20000 * (ch) + 0x90)
-#define SUN8I_SCALER_VSU_YVPHASE(ch) (0x20000 + 0x20000 * (ch) + 0x98)
-#define SUN8I_SCALER_VSU_CINSIZE(ch) (0x20000 + 0x20000 * (ch) + 0xc0)
-#define SUN8I_SCALER_VSU_CHSTEP(ch) (0x20000 + 0x20000 * (ch) + 0xc8)
-#define SUN8I_SCALER_VSU_CVSTEP(ch) (0x20000 + 0x20000 * (ch) + 0xcc)
-#define SUN8I_SCALER_VSU_CHPHASE(ch) (0x20000 + 0x20000 * (ch) + 0xd0)
-#define SUN8I_SCALER_VSU_CVPHASE(ch) (0x20000 + 0x20000 * (ch) + 0xd8)
-#define SUN8I_SCALER_VSU_YHCOEFF0(ch, i) \
- (0x20000 + 0x20000 * (ch) + 0x200 + 0x4 * (i))
-#define SUN8I_SCALER_VSU_YHCOEFF1(ch, i) \
- (0x20000 + 0x20000 * (ch) + 0x300 + 0x4 * (i))
-#define SUN8I_SCALER_VSU_YVCOEFF(ch, i) \
- (0x20000 + 0x20000 * (ch) + 0x400 + 0x4 * (i))
-#define SUN8I_SCALER_VSU_CHCOEFF0(ch, i) \
- (0x20000 + 0x20000 * (ch) + 0x600 + 0x4 * (i))
-#define SUN8I_SCALER_VSU_CHCOEFF1(ch, i) \
- (0x20000 + 0x20000 * (ch) + 0x700 + 0x4 * (i))
-#define SUN8I_SCALER_VSU_CVCOEFF(ch, i) \
- (0x20000 + 0x20000 * (ch) + 0x800 + 0x4 * (i))
+#define SUN8I_SCALER_VSU_CTRL(base) ((base) + 0x0)
+#define SUN50I_SCALER_VSU_SCALE_MODE(base) ((base) + 0x10)
+#define SUN50I_SCALER_VSU_DIR_THR(base) ((base) + 0x20)
+#define SUN50I_SCALER_VSU_EDGE_THR(base) ((base) + 0x24)
+#define SUN50I_SCALER_VSU_EDSCL_CTRL(base) ((base) + 0x28)
+#define SUN50I_SCALER_VSU_ANGLE_THR(base) ((base) + 0x2c)
+#define SUN8I_SCALER_VSU_OUTSIZE(base) ((base) + 0x40)
+#define SUN8I_SCALER_VSU_YINSIZE(base) ((base) + 0x80)
+#define SUN8I_SCALER_VSU_YHSTEP(base) ((base) + 0x88)
+#define SUN8I_SCALER_VSU_YVSTEP(base) ((base) + 0x8c)
+#define SUN8I_SCALER_VSU_YHPHASE(base) ((base) + 0x90)
+#define SUN8I_SCALER_VSU_YVPHASE(base) ((base) + 0x98)
+#define SUN8I_SCALER_VSU_CINSIZE(base) ((base) + 0xc0)
+#define SUN8I_SCALER_VSU_CHSTEP(base) ((base) + 0xc8)
+#define SUN8I_SCALER_VSU_CVSTEP(base) ((base) + 0xcc)
+#define SUN8I_SCALER_VSU_CHPHASE(base) ((base) + 0xd0)
+#define SUN8I_SCALER_VSU_CVPHASE(base) ((base) + 0xd8)
+#define SUN8I_SCALER_VSU_YHCOEFF0(base, i) ((base) + 0x200 + 0x4 * (i))
+#define SUN8I_SCALER_VSU_YHCOEFF1(base, i) ((base) + 0x300 + 0x4 * (i))
+#define SUN8I_SCALER_VSU_YVCOEFF(base, i) ((base) + 0x400 + 0x4 * (i))
+#define SUN8I_SCALER_VSU_CHCOEFF0(base, i) ((base) + 0x600 + 0x4 * (i))
+#define SUN8I_SCALER_VSU_CHCOEFF1(base, i) ((base) + 0x700 + 0x4 * (i))
+#define SUN8I_SCALER_VSU_CVCOEFF(base, i) ((base) + 0x800 + 0x4 * (i))
#define SUN8I_SCALER_VSU_CTRL_EN BIT(0)
#define SUN8I_SCALER_VSU_CTRL_COEFF_RDY BIT(4)
+#define SUN50I_SCALER_VSU_SUB_ZERO_DIR_THR(x) (((x) << 24) & 0xFF)
+#define SUN50I_SCALER_VSU_ZERO_DIR_THR(x) (((x) << 16) & 0xFF)
+#define SUN50I_SCALER_VSU_HORZ_DIR_THR(x) (((x) << 8) & 0xFF)
+#define SUN50I_SCALER_VSU_VERT_DIR_THR(x) ((x) & 0xFF)
+
+#define SUN50I_SCALER_VSU_SCALE_MODE_UI 0
+#define SUN50I_SCALER_VSU_SCALE_MODE_NORMAL 1
+#define SUN50I_SCALER_VSU_SCALE_MODE_ED_SCALE 2
+
+#define SUN50I_SCALER_VSU_EDGE_SHIFT(x) (((x) << 16) & 0xF)
+#define SUN50I_SCALER_VSU_EDGE_OFFSET(x) ((x) & 0xFF)
+
+#define SUN50I_SCALER_VSU_ANGLE_SHIFT(x) (((x) << 16) & 0xF)
+#define SUN50I_SCALER_VSU_ANGLE_OFFSET(x) ((x) & 0xFF)
+
void sun8i_vi_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable);
void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int layer,
u32 src_w, u32 src_h, u32 dst_w, u32 dst_h,
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
index 33e533268488..3dac08b24140 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
@@ -140,7 +140,6 @@ static int tilcdc_commit(struct drm_device *dev,
static const struct drm_mode_config_funcs mode_config_funcs = {
.fb_create = tilcdc_fb_create,
- .output_poll_changed = drm_fb_helper_output_poll_changed,
.atomic_check = tilcdc_atomic_check,
.atomic_commit = tilcdc_commit,
};
@@ -191,9 +190,6 @@ static void tilcdc_fini(struct drm_device *dev)
drm_dev_unregister(dev);
drm_kms_helper_poll_fini(dev);
-
- drm_fb_cma_fbdev_fini(dev);
-
drm_irq_uninstall(dev);
drm_mode_config_cleanup(dev);
tilcdc_remove_external_device(dev);
@@ -396,16 +392,14 @@ static int tilcdc_init(struct drm_driver *ddrv, struct device *dev)
drm_mode_config_reset(ddev);
- ret = drm_fb_cma_fbdev_init(ddev, bpp, 0);
- if (ret)
- goto init_failed;
-
drm_kms_helper_poll_init(ddev);
ret = drm_dev_register(ddev, 0);
if (ret)
goto init_failed;
+ drm_fbdev_generic_setup(ddev, bpp);
+
priv->is_registered = true;
return 0;
@@ -519,7 +513,6 @@ DEFINE_DRM_GEM_CMA_FOPS(fops);
static struct drm_driver tilcdc_driver = {
.driver_features = (DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET |
DRIVER_PRIME | DRIVER_ATOMIC),
- .lastclose = drm_fb_helper_lastclose,
.irq_handler = tilcdc_irq,
.gem_free_object_unlocked = drm_gem_cma_free_object,
.gem_print_info = drm_gem_cma_print_info,
diff --git a/drivers/gpu/drm/tinydrm/Kconfig b/drivers/gpu/drm/tinydrm/Kconfig
index 16f4b5c91f1b..2c408ac1a900 100644
--- a/drivers/gpu/drm/tinydrm/Kconfig
+++ b/drivers/gpu/drm/tinydrm/Kconfig
@@ -10,6 +10,17 @@ menuconfig DRM_TINYDRM
config TINYDRM_MIPI_DBI
tristate
+config TINYDRM_HX8357D
+ tristate "DRM support for HX8357D display panels"
+ depends on DRM_TINYDRM && SPI
+ depends on BACKLIGHT_CLASS_DEVICE
+ select TINYDRM_MIPI_DBI
+ help
+ DRM driver for the following HX8357D panels:
+ * YX350HV15-T 3.5" 340x350 TFT (Adafruit 3.5")
+
+ If M is selected the module will be called hx8357d.
+
config TINYDRM_ILI9225
tristate "DRM support for ILI9225 display panels"
depends on DRM_TINYDRM && SPI
diff --git a/drivers/gpu/drm/tinydrm/Makefile b/drivers/gpu/drm/tinydrm/Makefile
index 14d99080665a..f823066f7743 100644
--- a/drivers/gpu/drm/tinydrm/Makefile
+++ b/drivers/gpu/drm/tinydrm/Makefile
@@ -4,6 +4,7 @@ obj-$(CONFIG_DRM_TINYDRM) += core/
obj-$(CONFIG_TINYDRM_MIPI_DBI) += mipi-dbi.o
# Displays
+obj-$(CONFIG_TINYDRM_HX8357D) += hx8357d.o
obj-$(CONFIG_TINYDRM_ILI9225) += ili9225.o
obj-$(CONFIG_TINYDRM_ILI9341) += ili9341.o
obj-$(CONFIG_TINYDRM_MI0283QT) += mi0283qt.o
diff --git a/drivers/gpu/drm/tinydrm/core/tinydrm-core.c b/drivers/gpu/drm/tinydrm/core/tinydrm-core.c
index 255341ee4eb9..9af51d982a33 100644
--- a/drivers/gpu/drm/tinydrm/core/tinydrm-core.c
+++ b/drivers/gpu/drm/tinydrm/core/tinydrm-core.c
@@ -146,6 +146,7 @@ static int tinydrm_init(struct device *parent, struct tinydrm_device *tdev,
drm->dev_private = tdev;
drm_mode_config_init(drm);
drm->mode_config.funcs = &tinydrm_mode_config_funcs;
+ drm->mode_config.allow_fb_modifiers = true;
return 0;
}
diff --git a/drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c b/drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c
index 7e8e24d0b7a7..eacfc0ec8ff1 100644
--- a/drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c
+++ b/drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c
@@ -184,6 +184,10 @@ tinydrm_display_pipe_init(struct tinydrm_device *tdev,
struct drm_display_mode mode_copy;
struct drm_connector *connector;
int ret;
+ static const uint64_t modifiers[] = {
+ DRM_FORMAT_MOD_LINEAR,
+ DRM_FORMAT_MOD_INVALID
+ };
drm_mode_copy(&mode_copy, mode);
ret = tinydrm_rotate_mode(&mode_copy, rotation);
@@ -202,6 +206,6 @@ tinydrm_display_pipe_init(struct tinydrm_device *tdev,
return PTR_ERR(connector);
return drm_simple_display_pipe_init(drm, &tdev->pipe, funcs, formats,
- format_count, NULL, connector);
+ format_count, modifiers, connector);
}
EXPORT_SYMBOL(tinydrm_display_pipe_init);
diff --git a/drivers/gpu/drm/tinydrm/hx8357d.c b/drivers/gpu/drm/tinydrm/hx8357d.c
new file mode 100644
index 000000000000..c3e51c2baebc
--- /dev/null
+++ b/drivers/gpu/drm/tinydrm/hx8357d.c
@@ -0,0 +1,270 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * DRM driver for the HX8357D LCD controller
+ *
+ * Copyright 2018 Broadcom
+ * Copyright 2018 David Lechner <david@lechnology.com>
+ * Copyright 2016 Noralf Trønnes
+ * Copyright (C) 2015 Adafruit Industries
+ * Copyright (C) 2013 Christian Vogelgsang
+ */
+
+#include <linux/backlight.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/spi/spi.h>
+
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_modeset_helper.h>
+#include <drm/tinydrm/mipi-dbi.h>
+#include <drm/tinydrm/tinydrm-helpers.h>
+#include <video/mipi_display.h>
+
+#define HX8357D_SETOSC 0xb0
+#define HX8357D_SETPOWER 0xb1
+#define HX8357D_SETRGB 0xb3
+#define HX8357D_SETCYC 0xb3
+#define HX8357D_SETCOM 0xb6
+#define HX8357D_SETEXTC 0xb9
+#define HX8357D_SETSTBA 0xc0
+#define HX8357D_SETPANEL 0xcc
+#define HX8357D_SETGAMMA 0xe0
+
+#define HX8357D_MADCTL_MY 0x80
+#define HX8357D_MADCTL_MX 0x40
+#define HX8357D_MADCTL_MV 0x20
+#define HX8357D_MADCTL_ML 0x10
+#define HX8357D_MADCTL_RGB 0x00
+#define HX8357D_MADCTL_BGR 0x08
+#define HX8357D_MADCTL_MH 0x04
+
+static void yx240qv29_enable(struct drm_simple_display_pipe *pipe,
+ struct drm_crtc_state *crtc_state,
+ struct drm_plane_state *plane_state)
+{
+ struct tinydrm_device *tdev = pipe_to_tinydrm(pipe);
+ struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
+ u8 addr_mode;
+ int ret;
+
+ DRM_DEBUG_KMS("\n");
+
+ ret = mipi_dbi_poweron_conditional_reset(mipi);
+ if (ret < 0)
+ return;
+ if (ret == 1)
+ goto out_enable;
+
+ /* setextc */
+ mipi_dbi_command(mipi, HX8357D_SETEXTC, 0xFF, 0x83, 0x57);
+ msleep(150);
+
+ /* setRGB which also enables SDO */
+ mipi_dbi_command(mipi, HX8357D_SETRGB, 0x00, 0x00, 0x06, 0x06);
+
+ /* -1.52V */
+ mipi_dbi_command(mipi, HX8357D_SETCOM, 0x25);
+
+ /* Normal mode 70Hz, Idle mode 55 Hz */
+ mipi_dbi_command(mipi, HX8357D_SETOSC, 0x68);
+
+ /* Set Panel - BGR, Gate direction swapped */
+ mipi_dbi_command(mipi, HX8357D_SETPANEL, 0x05);
+
+ mipi_dbi_command(mipi, HX8357D_SETPOWER,
+ 0x00, /* Not deep standby */
+ 0x15, /* BT */
+ 0x1C, /* VSPR */
+ 0x1C, /* VSNR */
+ 0x83, /* AP */
+ 0xAA); /* FS */
+
+ mipi_dbi_command(mipi, HX8357D_SETSTBA,
+ 0x50, /* OPON normal */
+ 0x50, /* OPON idle */
+ 0x01, /* STBA */
+ 0x3C, /* STBA */
+ 0x1E, /* STBA */
+ 0x08); /* GEN */
+
+ mipi_dbi_command(mipi, HX8357D_SETCYC,
+ 0x02, /* NW 0x02 */
+ 0x40, /* RTN */
+ 0x00, /* DIV */
+ 0x2A, /* DUM */
+ 0x2A, /* DUM */
+ 0x0D, /* GDON */
+ 0x78); /* GDOFF */
+
+ mipi_dbi_command(mipi, HX8357D_SETGAMMA,
+ 0x02,
+ 0x0A,
+ 0x11,
+ 0x1d,
+ 0x23,
+ 0x35,
+ 0x41,
+ 0x4b,
+ 0x4b,
+ 0x42,
+ 0x3A,
+ 0x27,
+ 0x1B,
+ 0x08,
+ 0x09,
+ 0x03,
+ 0x02,
+ 0x0A,
+ 0x11,
+ 0x1d,
+ 0x23,
+ 0x35,
+ 0x41,
+ 0x4b,
+ 0x4b,
+ 0x42,
+ 0x3A,
+ 0x27,
+ 0x1B,
+ 0x08,
+ 0x09,
+ 0x03,
+ 0x00,
+ 0x01);
+
+ /* 16 bit */
+ mipi_dbi_command(mipi, MIPI_DCS_SET_PIXEL_FORMAT,
+ MIPI_DCS_PIXEL_FMT_16BIT);
+
+ /* TE off */
+ mipi_dbi_command(mipi, MIPI_DCS_SET_TEAR_ON, 0x00);
+
+ /* tear line */
+ mipi_dbi_command(mipi, MIPI_DCS_SET_TEAR_SCANLINE, 0x00, 0x02);
+
+ /* Exit Sleep */
+ mipi_dbi_command(mipi, MIPI_DCS_EXIT_SLEEP_MODE);
+ msleep(150);
+
+ /* display on */
+ mipi_dbi_command(mipi, MIPI_DCS_SET_DISPLAY_ON);
+ usleep_range(5000, 7000);
+
+out_enable:
+ switch (mipi->rotation) {
+ default:
+ addr_mode = HX8357D_MADCTL_MX | HX8357D_MADCTL_MY;
+ break;
+ case 90:
+ addr_mode = HX8357D_MADCTL_MV | HX8357D_MADCTL_MY;
+ break;
+ case 180:
+ addr_mode = 0;
+ break;
+ case 270:
+ addr_mode = HX8357D_MADCTL_MV | HX8357D_MADCTL_MX;
+ break;
+ }
+ mipi_dbi_command(mipi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode);
+ mipi_dbi_enable_flush(mipi, crtc_state, plane_state);
+}
+
+static const struct drm_simple_display_pipe_funcs hx8357d_pipe_funcs = {
+ .enable = yx240qv29_enable,
+ .disable = mipi_dbi_pipe_disable,
+ .update = tinydrm_display_pipe_update,
+ .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
+};
+
+static const struct drm_display_mode yx350hv15_mode = {
+ TINYDRM_MODE(320, 480, 60, 75),
+};
+
+DEFINE_DRM_GEM_CMA_FOPS(hx8357d_fops);
+
+static struct drm_driver hx8357d_driver = {
+ .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_ATOMIC,
+ .fops = &hx8357d_fops,
+ TINYDRM_GEM_DRIVER_OPS,
+ .debugfs_init = mipi_dbi_debugfs_init,
+ .name = "hx8357d",
+ .desc = "HX8357D",
+ .date = "20181023",
+ .major = 1,
+ .minor = 0,
+};
+
+static const struct of_device_id hx8357d_of_match[] = {
+ { .compatible = "adafruit,yx350hv15" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, hx8357d_of_match);
+
+static const struct spi_device_id hx8357d_id[] = {
+ { "yx350hv15", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, hx8357d_id);
+
+static int hx8357d_probe(struct spi_device *spi)
+{
+ struct device *dev = &spi->dev;
+ struct mipi_dbi *mipi;
+ struct gpio_desc *dc;
+ u32 rotation = 0;
+ int ret;
+
+ mipi = devm_kzalloc(dev, sizeof(*mipi), GFP_KERNEL);
+ if (!mipi)
+ return -ENOMEM;
+
+ dc = devm_gpiod_get(dev, "dc", GPIOD_OUT_LOW);
+ if (IS_ERR(dc)) {
+ DRM_DEV_ERROR(dev, "Failed to get gpio 'dc'\n");
+ return PTR_ERR(dc);
+ }
+
+ mipi->backlight = devm_of_find_backlight(dev);
+ if (IS_ERR(mipi->backlight))
+ return PTR_ERR(mipi->backlight);
+
+ device_property_read_u32(dev, "rotation", &rotation);
+
+ ret = mipi_dbi_spi_init(spi, mipi, dc);
+ if (ret)
+ return ret;
+
+ ret = mipi_dbi_init(&spi->dev, mipi, &hx8357d_pipe_funcs,
+ &hx8357d_driver, &yx350hv15_mode, rotation);
+ if (ret)
+ return ret;
+
+ spi_set_drvdata(spi, mipi);
+
+ return devm_tinydrm_register(&mipi->tinydrm);
+}
+
+static void hx8357d_shutdown(struct spi_device *spi)
+{
+ struct mipi_dbi *mipi = spi_get_drvdata(spi);
+
+ tinydrm_shutdown(&mipi->tinydrm);
+}
+
+static struct spi_driver hx8357d_spi_driver = {
+ .driver = {
+ .name = "hx8357d",
+ .of_match_table = hx8357d_of_match,
+ },
+ .id_table = hx8357d_id,
+ .probe = hx8357d_probe,
+ .shutdown = hx8357d_shutdown,
+};
+module_spi_driver(hx8357d_spi_driver);
+
+MODULE_DESCRIPTION("HX8357D DRM driver");
+MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/tinydrm/mipi-dbi.c b/drivers/gpu/drm/tinydrm/mipi-dbi.c
index cb3441e51d5f..1bb870021f6e 100644
--- a/drivers/gpu/drm/tinydrm/mipi-dbi.c
+++ b/drivers/gpu/drm/tinydrm/mipi-dbi.c
@@ -240,10 +240,10 @@ static int mipi_dbi_fb_dirty(struct drm_framebuffer *fb,
mipi_dbi_command(mipi, MIPI_DCS_SET_COLUMN_ADDRESS,
(clip.x1 >> 8) & 0xFF, clip.x1 & 0xFF,
- (clip.x2 >> 8) & 0xFF, (clip.x2 - 1) & 0xFF);
+ ((clip.x2 - 1) >> 8) & 0xFF, (clip.x2 - 1) & 0xFF);
mipi_dbi_command(mipi, MIPI_DCS_SET_PAGE_ADDRESS,
(clip.y1 >> 8) & 0xFF, clip.y1 & 0xFF,
- (clip.y2 >> 8) & 0xFF, (clip.y2 - 1) & 0xFF);
+ ((clip.y2 - 1) >> 8) & 0xFF, (clip.y2 - 1) & 0xFF);
ret = mipi_dbi_command_buf(mipi, MIPI_DCS_WRITE_MEMORY_START, tr,
(clip.x2 - clip.x1) * (clip.y2 - clip.y1) * 2);
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index 26b889f86670..d87935bf8e30 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -45,6 +45,14 @@
static void ttm_bo_global_kobj_release(struct kobject *kobj);
+/**
+ * ttm_global_mutex - protecting the global BO state
+ */
+DEFINE_MUTEX(ttm_global_mutex);
+struct ttm_bo_global ttm_bo_glob = {
+ .use_count = 0
+};
+
static struct attribute ttm_bo_count = {
.name = "bo_count",
.mode = S_IRUGO
@@ -872,7 +880,7 @@ static int ttm_bo_add_move_fence(struct ttm_buffer_object *bo,
if (fence) {
reservation_object_add_shared_fence(bo->resv, fence);
- ret = reservation_object_reserve_shared(bo->resv);
+ ret = reservation_object_reserve_shared(bo->resv, 1);
if (unlikely(ret))
return ret;
@@ -977,7 +985,7 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo,
bool has_erestartsys = false;
int i, ret;
- ret = reservation_object_reserve_shared(bo->resv);
+ ret = reservation_object_reserve_shared(bo->resv, 1);
if (unlikely(ret))
return ret;
@@ -1519,35 +1527,45 @@ static void ttm_bo_global_kobj_release(struct kobject *kobj)
container_of(kobj, struct ttm_bo_global, kobj);
__free_page(glob->dummy_read_page);
- kfree(glob);
}
-void ttm_bo_global_release(struct drm_global_reference *ref)
+static void ttm_bo_global_release(void)
{
- struct ttm_bo_global *glob = ref->object;
+ struct ttm_bo_global *glob = &ttm_bo_glob;
+
+ mutex_lock(&ttm_global_mutex);
+ if (--glob->use_count > 0)
+ goto out;
kobject_del(&glob->kobj);
kobject_put(&glob->kobj);
+ ttm_mem_global_release(&ttm_mem_glob);
+out:
+ mutex_unlock(&ttm_global_mutex);
}
-EXPORT_SYMBOL(ttm_bo_global_release);
-int ttm_bo_global_init(struct drm_global_reference *ref)
+static int ttm_bo_global_init(void)
{
- struct ttm_bo_global_ref *bo_ref =
- container_of(ref, struct ttm_bo_global_ref, ref);
- struct ttm_bo_global *glob = ref->object;
- int ret;
+ struct ttm_bo_global *glob = &ttm_bo_glob;
+ int ret = 0;
unsigned i;
- mutex_init(&glob->device_list_mutex);
+ mutex_lock(&ttm_global_mutex);
+ if (++glob->use_count > 1)
+ goto out;
+
+ ret = ttm_mem_global_init(&ttm_mem_glob);
+ if (ret)
+ goto out;
+
spin_lock_init(&glob->lru_lock);
- glob->mem_glob = bo_ref->mem_glob;
+ glob->mem_glob = &ttm_mem_glob;
glob->mem_glob->bo_glob = glob;
glob->dummy_read_page = alloc_page(__GFP_ZERO | GFP_DMA32);
if (unlikely(glob->dummy_read_page == NULL)) {
ret = -ENOMEM;
- goto out_no_drp;
+ goto out;
}
for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i)
@@ -1559,13 +1577,10 @@ int ttm_bo_global_init(struct drm_global_reference *ref)
&glob->kobj, &ttm_bo_glob_kobj_type, ttm_get_kobj(), "buffer_objects");
if (unlikely(ret != 0))
kobject_put(&glob->kobj);
- return ret;
-out_no_drp:
- kfree(glob);
+out:
+ mutex_unlock(&ttm_global_mutex);
return ret;
}
-EXPORT_SYMBOL(ttm_bo_global_init);
-
int ttm_bo_device_release(struct ttm_bo_device *bdev)
{
@@ -1587,9 +1602,9 @@ int ttm_bo_device_release(struct ttm_bo_device *bdev)
}
}
- mutex_lock(&glob->device_list_mutex);
+ mutex_lock(&ttm_global_mutex);
list_del(&bdev->device_list);
- mutex_unlock(&glob->device_list_mutex);
+ mutex_unlock(&ttm_global_mutex);
cancel_delayed_work_sync(&bdev->wq);
@@ -1604,18 +1619,25 @@ int ttm_bo_device_release(struct ttm_bo_device *bdev)
drm_vma_offset_manager_destroy(&bdev->vma_manager);
+ if (!ret)
+ ttm_bo_global_release();
+
return ret;
}
EXPORT_SYMBOL(ttm_bo_device_release);
int ttm_bo_device_init(struct ttm_bo_device *bdev,
- struct ttm_bo_global *glob,
struct ttm_bo_driver *driver,
struct address_space *mapping,
uint64_t file_page_offset,
bool need_dma32)
{
- int ret = -EINVAL;
+ struct ttm_bo_global *glob = &ttm_bo_glob;
+ int ret;
+
+ ret = ttm_bo_global_init();
+ if (ret)
+ return ret;
bdev->driver = driver;
@@ -1636,12 +1658,13 @@ int ttm_bo_device_init(struct ttm_bo_device *bdev,
bdev->dev_mapping = mapping;
bdev->glob = glob;
bdev->need_dma32 = need_dma32;
- mutex_lock(&glob->device_list_mutex);
+ mutex_lock(&ttm_global_mutex);
list_add_tail(&bdev->device_list, &glob->device_list);
- mutex_unlock(&glob->device_list_mutex);
+ mutex_unlock(&ttm_global_mutex);
return 0;
out_no_sys:
+ ttm_bo_global_release();
return ret;
}
EXPORT_SYMBOL(ttm_bo_device_init);
diff --git a/drivers/gpu/drm/ttm/ttm_execbuf_util.c b/drivers/gpu/drm/ttm/ttm_execbuf_util.c
index e73ae0d22897..efa005a1c1b7 100644
--- a/drivers/gpu/drm/ttm/ttm_execbuf_util.c
+++ b/drivers/gpu/drm/ttm/ttm_execbuf_util.c
@@ -129,7 +129,7 @@ int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket,
if (!entry->shared)
continue;
- ret = reservation_object_reserve_shared(bo->resv);
+ ret = reservation_object_reserve_shared(bo->resv, 1);
if (!ret)
continue;
}
@@ -151,7 +151,7 @@ int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket,
}
if (!ret && entry->shared)
- ret = reservation_object_reserve_shared(bo->resv);
+ ret = reservation_object_reserve_shared(bo->resv, 1);
if (unlikely(ret != 0)) {
if (ret == -EINTR)
@@ -187,14 +187,12 @@ void ttm_eu_fence_buffer_objects(struct ww_acquire_ctx *ticket,
struct ttm_buffer_object *bo;
struct ttm_bo_global *glob;
struct ttm_bo_device *bdev;
- struct ttm_bo_driver *driver;
if (list_empty(list))
return;
bo = list_first_entry(list, struct ttm_validate_buffer, head)->bo;
bdev = bo->bdev;
- driver = bdev->driver;
glob = bo->bdev->glob;
spin_lock(&glob->lru_lock);
diff --git a/drivers/gpu/drm/ttm/ttm_memory.c b/drivers/gpu/drm/ttm/ttm_memory.c
index 450387c92b63..f1567c353b54 100644
--- a/drivers/gpu/drm/ttm/ttm_memory.c
+++ b/drivers/gpu/drm/ttm/ttm_memory.c
@@ -41,6 +41,9 @@
#define TTM_MEMORY_ALLOC_RETRIES 4
+struct ttm_mem_global ttm_mem_glob;
+EXPORT_SYMBOL(ttm_mem_glob);
+
struct ttm_mem_zone {
struct kobject kobj;
struct ttm_mem_global *glob;
@@ -216,14 +219,6 @@ static ssize_t ttm_mem_global_store(struct kobject *kobj,
return size;
}
-static void ttm_mem_global_kobj_release(struct kobject *kobj)
-{
- struct ttm_mem_global *glob =
- container_of(kobj, struct ttm_mem_global, kobj);
-
- kfree(glob);
-}
-
static struct attribute *ttm_mem_global_attrs[] = {
&ttm_mem_global_lower_mem_limit,
NULL
@@ -235,7 +230,6 @@ static const struct sysfs_ops ttm_mem_global_ops = {
};
static struct kobj_type ttm_mem_glob_kobj_type = {
- .release = &ttm_mem_global_kobj_release,
.sysfs_ops = &ttm_mem_global_ops,
.default_attrs = ttm_mem_global_attrs,
};
@@ -464,7 +458,6 @@ out_no_zone:
ttm_mem_global_release(glob);
return ret;
}
-EXPORT_SYMBOL(ttm_mem_global_init);
void ttm_mem_global_release(struct ttm_mem_global *glob)
{
@@ -486,7 +479,6 @@ void ttm_mem_global_release(struct ttm_mem_global *glob)
kobject_del(&glob->kobj);
kobject_put(&glob->kobj);
}
-EXPORT_SYMBOL(ttm_mem_global_release);
static void ttm_check_swapping(struct ttm_mem_global *glob)
{
diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c
index f455f095a146..1b014d92855b 100644
--- a/drivers/gpu/drm/udl/udl_main.c
+++ b/drivers/gpu/drm/udl/udl_main.c
@@ -350,15 +350,10 @@ int udl_driver_load(struct drm_device *dev, unsigned long flags)
if (ret)
goto err;
- ret = drm_vblank_init(dev, 1);
- if (ret)
- goto err_fb;
-
drm_kms_helper_poll_init(dev);
return 0;
-err_fb:
- udl_fbdev_cleanup(dev);
+
err:
if (udl->urbs.count)
udl_free_urb_list(dev);
diff --git a/drivers/gpu/drm/v3d/v3d_debugfs.c b/drivers/gpu/drm/v3d/v3d_debugfs.c
index 4db62c545748..eb2b2d2f8553 100644
--- a/drivers/gpu/drm/v3d/v3d_debugfs.c
+++ b/drivers/gpu/drm/v3d/v3d_debugfs.c
@@ -71,10 +71,13 @@ static int v3d_v3d_debugfs_regs(struct seq_file *m, void *unused)
V3D_READ(v3d_hub_reg_defs[i].reg));
}
- for (i = 0; i < ARRAY_SIZE(v3d_gca_reg_defs); i++) {
- seq_printf(m, "%s (0x%04x): 0x%08x\n",
- v3d_gca_reg_defs[i].name, v3d_gca_reg_defs[i].reg,
- V3D_GCA_READ(v3d_gca_reg_defs[i].reg));
+ if (v3d->ver < 41) {
+ for (i = 0; i < ARRAY_SIZE(v3d_gca_reg_defs); i++) {
+ seq_printf(m, "%s (0x%04x): 0x%08x\n",
+ v3d_gca_reg_defs[i].name,
+ v3d_gca_reg_defs[i].reg,
+ V3D_GCA_READ(v3d_gca_reg_defs[i].reg));
+ }
}
for (core = 0; core < v3d->cores; core++) {
@@ -176,9 +179,44 @@ static int v3d_debugfs_bo_stats(struct seq_file *m, void *unused)
return 0;
}
+static int v3d_measure_clock(struct seq_file *m, void *unused)
+{
+ struct drm_info_node *node = (struct drm_info_node *)m->private;
+ struct drm_device *dev = node->minor->dev;
+ struct v3d_dev *v3d = to_v3d_dev(dev);
+ uint32_t cycles;
+ int core = 0;
+ int measure_ms = 1000;
+
+ if (v3d->ver >= 40) {
+ V3D_CORE_WRITE(core, V3D_V4_PCTR_0_SRC_0_3,
+ V3D_SET_FIELD(V3D_PCTR_CYCLE_COUNT,
+ V3D_PCTR_S0));
+ V3D_CORE_WRITE(core, V3D_V4_PCTR_0_CLR, 1);
+ V3D_CORE_WRITE(core, V3D_V4_PCTR_0_EN, 1);
+ } else {
+ V3D_CORE_WRITE(core, V3D_V3_PCTR_0_PCTRS0,
+ V3D_PCTR_CYCLE_COUNT);
+ V3D_CORE_WRITE(core, V3D_V3_PCTR_0_CLR, 1);
+ V3D_CORE_WRITE(core, V3D_V3_PCTR_0_EN,
+ V3D_V3_PCTR_0_EN_ENABLE |
+ 1);
+ }
+ msleep(measure_ms);
+ cycles = V3D_CORE_READ(core, V3D_PCTR_0_PCTR0);
+
+ seq_printf(m, "cycles: %d (%d.%d Mhz)\n",
+ cycles,
+ cycles / (measure_ms * 1000),
+ (cycles / (measure_ms * 100)) % 10);
+
+ return 0;
+}
+
static const struct drm_info_list v3d_debugfs_list[] = {
{"v3d_ident", v3d_v3d_debugfs_ident, 0},
{"v3d_regs", v3d_v3d_debugfs_regs, 0},
+ {"measure_clock", v3d_measure_clock, 0},
{"bo_stats", v3d_debugfs_bo_stats, 0},
};
diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h
index e6fed696ad86..cbe5be0c47eb 100644
--- a/drivers/gpu/drm/v3d/v3d_drv.h
+++ b/drivers/gpu/drm/v3d/v3d_drv.h
@@ -198,6 +198,11 @@ struct v3d_exec_info {
*/
struct dma_fence *bin_done_fence;
+ /* Fence for when the scheduler considers the render to be
+ * done, for when the BOs reservations should be complete.
+ */
+ struct dma_fence *render_done_fence;
+
struct kref refcount;
/* This is the array of BOs that were looked up at the start of exec. */
diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c
index 70c54774400b..b88c96911453 100644
--- a/drivers/gpu/drm/v3d/v3d_gem.c
+++ b/drivers/gpu/drm/v3d/v3d_gem.c
@@ -209,7 +209,7 @@ v3d_flush_caches(struct v3d_dev *v3d)
static void
v3d_attach_object_fences(struct v3d_exec_info *exec)
{
- struct dma_fence *out_fence = &exec->render.base.s_fence->finished;
+ struct dma_fence *out_fence = exec->render_done_fence;
struct v3d_bo *bo;
int i;
@@ -305,7 +305,7 @@ retry:
for (i = 0; i < exec->bo_count; i++) {
bo = to_v3d_bo(&exec->bo[i]->base);
- ret = reservation_object_reserve_shared(bo->resv);
+ ret = reservation_object_reserve_shared(bo->resv, 1);
if (ret) {
v3d_unlock_bo_reservations(dev, exec, acquire_ctx);
return ret;
@@ -409,6 +409,7 @@ v3d_exec_cleanup(struct kref *ref)
dma_fence_put(exec->render.done_fence);
dma_fence_put(exec->bin_done_fence);
+ dma_fence_put(exec->render_done_fence);
for (i = 0; i < exec->bo_count; i++)
drm_gem_object_put_unlocked(&exec->bo[i]->base);
@@ -521,12 +522,12 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
kref_init(&exec->refcount);
ret = drm_syncobj_find_fence(file_priv, args->in_sync_bcl,
- 0, &exec->bin.in_fence);
+ 0, 0, &exec->bin.in_fence);
if (ret == -EINVAL)
goto fail;
ret = drm_syncobj_find_fence(file_priv, args->in_sync_rcl,
- 0, &exec->render.in_fence);
+ 0, 0, &exec->render.in_fence);
if (ret == -EINVAL)
goto fail;
@@ -572,6 +573,9 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
if (ret)
goto fail_unreserve;
+ exec->render_done_fence =
+ dma_fence_get(&exec->render.base.s_fence->finished);
+
kref_get(&exec->refcount); /* put by scheduler job completion */
drm_sched_entity_push_job(&exec->render.base,
&v3d_priv->sched_entity[V3D_RENDER]);
@@ -585,7 +589,7 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
sync_out = drm_syncobj_find(file_priv, args->out_sync);
if (sync_out) {
drm_syncobj_replace_fence(sync_out, 0,
- &exec->render.base.s_fence->finished);
+ exec->render_done_fence);
drm_syncobj_put(sync_out);
}
diff --git a/drivers/gpu/drm/v3d/v3d_regs.h b/drivers/gpu/drm/v3d/v3d_regs.h
index 854046565989..c3a5e4e44f73 100644
--- a/drivers/gpu/drm/v3d/v3d_regs.h
+++ b/drivers/gpu/drm/v3d/v3d_regs.h
@@ -267,6 +267,36 @@
# define V3D_PTB_BXCF_RWORDERDISA BIT(1)
# define V3D_PTB_BXCF_CLIPDISA BIT(0)
+#define V3D_V3_PCTR_0_EN 0x00674
+#define V3D_V3_PCTR_0_EN_ENABLE BIT(31)
+#define V3D_V4_PCTR_0_EN 0x00650
+/* When a bit is set, resets the counter to 0. */
+#define V3D_V3_PCTR_0_CLR 0x00670
+#define V3D_V4_PCTR_0_CLR 0x00654
+#define V3D_PCTR_0_OVERFLOW 0x00658
+
+#define V3D_V3_PCTR_0_PCTRS0 0x00684
+#define V3D_V3_PCTR_0_PCTRS15 0x00660
+#define V3D_V3_PCTR_0_PCTRSX(x) (V3D_V3_PCTR_0_PCTRS0 + \
+ 4 * (x))
+/* Each src reg muxes four counters each. */
+#define V3D_V4_PCTR_0_SRC_0_3 0x00660
+#define V3D_V4_PCTR_0_SRC_28_31 0x0067c
+# define V3D_PCTR_S0_MASK V3D_MASK(6, 0)
+# define V3D_PCTR_S0_SHIFT 0
+# define V3D_PCTR_S1_MASK V3D_MASK(14, 8)
+# define V3D_PCTR_S1_SHIFT 8
+# define V3D_PCTR_S2_MASK V3D_MASK(22, 16)
+# define V3D_PCTR_S2_SHIFT 16
+# define V3D_PCTR_S3_MASK V3D_MASK(30, 24)
+# define V3D_PCTR_S3_SHIFT 24
+# define V3D_PCTR_CYCLE_COUNT 32
+
+/* Output values of the counters. */
+#define V3D_PCTR_0_PCTR0 0x00680
+#define V3D_PCTR_0_PCTR31 0x006fc
+#define V3D_PCTR_0_PCTRX(x) (V3D_PCTR_0_PCTR0 + \
+ 4 * (x))
#define V3D_GMP_STATUS 0x00800
# define V3D_GMP_STATUS_GMPRST BIT(31)
# define V3D_GMP_STATUS_WR_COUNT_MASK V3D_MASK(30, 24)
diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c
index 9243dea6e6ad..445b2ef03303 100644
--- a/drivers/gpu/drm/v3d/v3d_sched.c
+++ b/drivers/gpu/drm/v3d/v3d_sched.c
@@ -35,6 +35,8 @@ v3d_job_free(struct drm_sched_job *sched_job)
{
struct v3d_job *job = to_v3d_job(sched_job);
+ drm_sched_job_cleanup(sched_job);
+
v3d_exec_put(job->exec);
}
@@ -167,9 +169,6 @@ v3d_job_timedout(struct drm_sched_job *sched_job)
if (job->timedout_ctca != ctca || job->timedout_ctra != ctra) {
job->timedout_ctca = ctca;
job->timedout_ctra = ctra;
-
- schedule_delayed_work(&job->base.sched->work_tdr,
- job->base.sched->timeout);
return;
}
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
index 1f1780ccdbdf..f6f5cd80c04d 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.c
+++ b/drivers/gpu/drm/vc4/vc4_drv.c
@@ -33,6 +33,7 @@
#include <linux/pm_runtime.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_fb_helper.h>
+#include <drm/drm_atomic_helper.h>
#include "uapi/drm/vc4_drm.h"
#include "vc4_drv.h"
@@ -308,6 +309,8 @@ static void vc4_drm_unbind(struct device *dev)
drm_dev_unregister(drm);
+ drm_atomic_helper_shutdown(drm);
+
drm_mode_config_cleanup(drm);
drm_atomic_private_obj_fini(&vc4->ctm_manager);
diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c
index 5b22e996af6c..41881ce4132d 100644
--- a/drivers/gpu/drm/vc4/vc4_gem.c
+++ b/drivers/gpu/drm/vc4/vc4_gem.c
@@ -635,7 +635,7 @@ retry:
for (i = 0; i < exec->bo_count; i++) {
bo = to_vc4_bo(&exec->bo[i]->base);
- ret = reservation_object_reserve_shared(bo->resv);
+ ret = reservation_object_reserve_shared(bo->resv, 1);
if (ret) {
vc4_unlock_bo_reservations(dev, exec, acquire_ctx);
return ret;
@@ -1173,7 +1173,7 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
if (args->in_sync) {
ret = drm_syncobj_find_fence(file_priv, args->in_sync,
- 0, &in_fence);
+ 0, 0, &in_fence);
if (ret)
goto fail;
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
index 9dc3fcbd290b..98fae4daa08c 100644
--- a/drivers/gpu/drm/vc4/vc4_plane.c
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
@@ -266,30 +266,59 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
u32 subpixel_src_mask = (1 << 16) - 1;
u32 format = fb->format->format;
int num_planes = fb->format->num_planes;
- u32 h_subsample = 1;
- u32 v_subsample = 1;
- int i;
+ int min_scale = 1, max_scale = INT_MAX;
+ struct drm_crtc_state *crtc_state;
+ u32 h_subsample, v_subsample;
+ int i, ret;
+
+ crtc_state = drm_atomic_get_existing_crtc_state(state->state,
+ state->crtc);
+ if (!crtc_state) {
+ DRM_DEBUG_KMS("Invalid crtc state\n");
+ return -EINVAL;
+ }
+
+ /* No configuring scaling on the cursor plane, since it gets
+ * non-vblank-synced updates, and scaling requires LBM changes which
+ * have to be vblank-synced.
+ */
+ if (plane->type == DRM_PLANE_TYPE_CURSOR) {
+ min_scale = DRM_PLANE_HELPER_NO_SCALING;
+ max_scale = DRM_PLANE_HELPER_NO_SCALING;
+ } else {
+ min_scale = 1;
+ max_scale = INT_MAX;
+ }
+
+ ret = drm_atomic_helper_check_plane_state(state, crtc_state,
+ min_scale, max_scale,
+ true, true);
+ if (ret)
+ return ret;
+
+ h_subsample = drm_format_horz_chroma_subsampling(format);
+ v_subsample = drm_format_vert_chroma_subsampling(format);
for (i = 0; i < num_planes; i++)
vc4_state->offsets[i] = bo->paddr + fb->offsets[i];
/* We don't support subpixel source positioning for scaling. */
- if ((state->src_x & subpixel_src_mask) ||
- (state->src_y & subpixel_src_mask) ||
- (state->src_w & subpixel_src_mask) ||
- (state->src_h & subpixel_src_mask)) {
+ if ((state->src.x1 & subpixel_src_mask) ||
+ (state->src.x2 & subpixel_src_mask) ||
+ (state->src.y1 & subpixel_src_mask) ||
+ (state->src.y2 & subpixel_src_mask)) {
return -EINVAL;
}
- vc4_state->src_x = state->src_x >> 16;
- vc4_state->src_y = state->src_y >> 16;
- vc4_state->src_w[0] = state->src_w >> 16;
- vc4_state->src_h[0] = state->src_h >> 16;
+ vc4_state->src_x = state->src.x1 >> 16;
+ vc4_state->src_y = state->src.y1 >> 16;
+ vc4_state->src_w[0] = (state->src.x2 - state->src.x1) >> 16;
+ vc4_state->src_h[0] = (state->src.y2 - state->src.y1) >> 16;
- vc4_state->crtc_x = state->crtc_x;
- vc4_state->crtc_y = state->crtc_y;
- vc4_state->crtc_w = state->crtc_w;
- vc4_state->crtc_h = state->crtc_h;
+ vc4_state->crtc_x = state->dst.x1;
+ vc4_state->crtc_y = state->dst.y1;
+ vc4_state->crtc_w = state->dst.x2 - state->dst.x1;
+ vc4_state->crtc_h = state->dst.y2 - state->dst.y1;
vc4_state->x_scaling[0] = vc4_get_scaling_mode(vc4_state->src_w[0],
vc4_state->crtc_w);
@@ -302,8 +331,6 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
if (num_planes > 1) {
vc4_state->is_yuv = true;
- h_subsample = drm_format_horz_chroma_subsampling(format);
- v_subsample = drm_format_vert_chroma_subsampling(format);
vc4_state->src_w[1] = vc4_state->src_w[0] / h_subsample;
vc4_state->src_h[1] = vc4_state->src_h[0] / v_subsample;
@@ -321,45 +348,11 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
if (vc4_state->is_unity)
vc4_state->x_scaling[0] = VC4_SCALING_PPF;
} else {
+ vc4_state->is_yuv = false;
vc4_state->x_scaling[1] = VC4_SCALING_NONE;
vc4_state->y_scaling[1] = VC4_SCALING_NONE;
}
- /* No configuring scaling on the cursor plane, since it gets
- non-vblank-synced updates, and scaling requires requires
- LBM changes which have to be vblank-synced.
- */
- if (plane->type == DRM_PLANE_TYPE_CURSOR && !vc4_state->is_unity)
- return -EINVAL;
-
- /* Clamp the on-screen start x/y to 0. The hardware doesn't
- * support negative y, and negative x wastes bandwidth.
- */
- if (vc4_state->crtc_x < 0) {
- for (i = 0; i < num_planes; i++) {
- u32 cpp = fb->format->cpp[i];
- u32 subs = ((i == 0) ? 1 : h_subsample);
-
- vc4_state->offsets[i] += (cpp *
- (-vc4_state->crtc_x) / subs);
- }
- vc4_state->src_w[0] += vc4_state->crtc_x;
- vc4_state->src_w[1] += vc4_state->crtc_x / h_subsample;
- vc4_state->crtc_x = 0;
- }
-
- if (vc4_state->crtc_y < 0) {
- for (i = 0; i < num_planes; i++) {
- u32 subs = ((i == 0) ? 1 : v_subsample);
-
- vc4_state->offsets[i] += (fb->pitches[i] *
- (-vc4_state->crtc_y) / subs);
- }
- vc4_state->src_h[0] += vc4_state->crtc_y;
- vc4_state->src_h[1] += vc4_state->crtc_y / v_subsample;
- vc4_state->crtc_y = 0;
- }
-
return 0;
}
@@ -467,6 +460,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
const struct hvs_format *format = vc4_get_hvs_format(fb->format->format);
u64 base_format_mod = fourcc_mod_broadcom_mod(fb->modifier);
int num_planes = drm_format_num_planes(format->drm);
+ u32 h_subsample, v_subsample;
bool mix_plane_alpha;
bool covers_screen;
u32 scl0, scl1, pitch0;
@@ -512,26 +506,77 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
scl1 = vc4_get_scl_field(state, 0);
}
+ h_subsample = drm_format_horz_chroma_subsampling(format->drm);
+ v_subsample = drm_format_vert_chroma_subsampling(format->drm);
+
switch (base_format_mod) {
case DRM_FORMAT_MOD_LINEAR:
tiling = SCALER_CTL0_TILING_LINEAR;
pitch0 = VC4_SET_FIELD(fb->pitches[0], SCALER_SRC_PITCH);
+
+ /* Adjust the base pointer to the first pixel to be scanned
+ * out.
+ */
+ for (i = 0; i < num_planes; i++) {
+ vc4_state->offsets[i] += vc4_state->src_y /
+ (i ? v_subsample : 1) *
+ fb->pitches[i];
+ vc4_state->offsets[i] += vc4_state->src_x /
+ (i ? h_subsample : 1) *
+ fb->format->cpp[i];
+ }
+
break;
case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: {
- /* For T-tiled, the FB pitch is "how many bytes from
- * one row to the next, such that pitch * tile_h ==
- * tile_size * tiles_per_row."
- */
u32 tile_size_shift = 12; /* T tiles are 4kb */
+ /* Whole-tile offsets, mostly for setting the pitch. */
+ u32 tile_w_shift = fb->format->cpp[0] == 2 ? 6 : 5;
u32 tile_h_shift = 5; /* 16 and 32bpp are 32 pixels high */
+ u32 tile_w_mask = (1 << tile_w_shift) - 1;
+ /* The height mask on 32-bit-per-pixel tiles is 63, i.e. twice
+ * the height (in pixels) of a 4k tile.
+ */
+ u32 tile_h_mask = (2 << tile_h_shift) - 1;
+ /* For T-tiled, the FB pitch is "how many bytes from one row to
+ * the next, such that
+ *
+ * pitch * tile_h == tile_size * tiles_per_row
+ */
u32 tiles_w = fb->pitches[0] >> (tile_size_shift - tile_h_shift);
+ u32 tiles_l = vc4_state->src_x >> tile_w_shift;
+ u32 tiles_r = tiles_w - tiles_l;
+ u32 tiles_t = vc4_state->src_y >> tile_h_shift;
+ /* Intra-tile offsets, which modify the base address (the
+ * SCALER_PITCH0_TILE_Y_OFFSET tells HVS how to walk from that
+ * base address).
+ */
+ u32 tile_y = (vc4_state->src_y >> 4) & 1;
+ u32 subtile_y = (vc4_state->src_y >> 2) & 3;
+ u32 utile_y = vc4_state->src_y & 3;
+ u32 x_off = vc4_state->src_x & tile_w_mask;
+ u32 y_off = vc4_state->src_y & tile_h_mask;
tiling = SCALER_CTL0_TILING_256B_OR_T;
+ pitch0 = (VC4_SET_FIELD(x_off, SCALER_PITCH0_SINK_PIX) |
+ VC4_SET_FIELD(y_off, SCALER_PITCH0_TILE_Y_OFFSET) |
+ VC4_SET_FIELD(tiles_l, SCALER_PITCH0_TILE_WIDTH_L) |
+ VC4_SET_FIELD(tiles_r, SCALER_PITCH0_TILE_WIDTH_R));
+ vc4_state->offsets[0] += tiles_t * (tiles_w << tile_size_shift);
+ vc4_state->offsets[0] += subtile_y << 8;
+ vc4_state->offsets[0] += utile_y << 4;
+
+ /* Rows of tiles alternate left-to-right and right-to-left. */
+ if (tiles_t & 1) {
+ pitch0 |= SCALER_PITCH0_TILE_INITIAL_LINE_DIR;
+ vc4_state->offsets[0] += (tiles_w - tiles_l) <<
+ tile_size_shift;
+ vc4_state->offsets[0] -= (1 + !tile_y) << 10;
+ } else {
+ vc4_state->offsets[0] += tiles_l << tile_size_shift;
+ vc4_state->offsets[0] += tile_y << 10;
+ }
- pitch0 = (VC4_SET_FIELD(0, SCALER_PITCH0_TILE_Y_OFFSET) |
- VC4_SET_FIELD(0, SCALER_PITCH0_TILE_WIDTH_L) |
- VC4_SET_FIELD(tiles_w, SCALER_PITCH0_TILE_WIDTH_R));
break;
}
@@ -903,7 +948,6 @@ static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {
static void vc4_plane_destroy(struct drm_plane *plane)
{
- drm_plane_helper_disable(plane, NULL);
drm_plane_cleanup(plane);
}
diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h
index d6864fa4bd14..931088014272 100644
--- a/drivers/gpu/drm/vc4/vc4_regs.h
+++ b/drivers/gpu/drm/vc4/vc4_regs.h
@@ -1037,14 +1037,18 @@ enum hvs_pixel_format {
#define SCALER_TILE_HEIGHT_MASK VC4_MASK(15, 0)
#define SCALER_TILE_HEIGHT_SHIFT 0
+/* Common PITCH0 fields */
+#define SCALER_PITCH0_SINK_PIX_MASK VC4_MASK(31, 26)
+#define SCALER_PITCH0_SINK_PIX_SHIFT 26
+
/* PITCH0 fields for T-tiled. */
#define SCALER_PITCH0_TILE_WIDTH_L_MASK VC4_MASK(22, 16)
#define SCALER_PITCH0_TILE_WIDTH_L_SHIFT 16
#define SCALER_PITCH0_TILE_LINE_DIR BIT(15)
#define SCALER_PITCH0_TILE_INITIAL_LINE_DIR BIT(14)
/* Y offset within a tile. */
-#define SCALER_PITCH0_TILE_Y_OFFSET_MASK VC4_MASK(13, 7)
-#define SCALER_PITCH0_TILE_Y_OFFSET_SHIFT 7
+#define SCALER_PITCH0_TILE_Y_OFFSET_MASK VC4_MASK(13, 8)
+#define SCALER_PITCH0_TILE_Y_OFFSET_SHIFT 8
#define SCALER_PITCH0_TILE_WIDTH_R_MASK VC4_MASK(6, 0)
#define SCALER_PITCH0_TILE_WIDTH_R_SHIFT 0
diff --git a/drivers/gpu/drm/vgem/vgem_drv.c b/drivers/gpu/drm/vgem/vgem_drv.c
index ec6af8b920da..5930facd6d2d 100644
--- a/drivers/gpu/drm/vgem/vgem_drv.c
+++ b/drivers/gpu/drm/vgem/vgem_drv.c
@@ -431,7 +431,8 @@ static void vgem_release(struct drm_device *dev)
}
static struct drm_driver vgem_driver = {
- .driver_features = DRIVER_GEM | DRIVER_PRIME,
+ .driver_features = DRIVER_GEM | DRIVER_PRIME |
+ DRIVER_RENDER,
.release = vgem_release,
.open = vgem_open,
.postclose = vgem_postclose,
@@ -471,31 +472,31 @@ static int __init vgem_init(void)
if (!vgem_device)
return -ENOMEM;
- ret = drm_dev_init(&vgem_device->drm, &vgem_driver, NULL);
- if (ret)
- goto out_free;
-
vgem_device->platform =
platform_device_register_simple("vgem", -1, NULL, 0);
if (IS_ERR(vgem_device->platform)) {
ret = PTR_ERR(vgem_device->platform);
- goto out_fini;
+ goto out_free;
}
dma_coerce_mask_and_coherent(&vgem_device->platform->dev,
DMA_BIT_MASK(64));
+ ret = drm_dev_init(&vgem_device->drm, &vgem_driver,
+ &vgem_device->platform->dev);
+ if (ret)
+ goto out_unregister;
/* Final step: expose the device/driver to userspace */
ret = drm_dev_register(&vgem_device->drm, 0);
if (ret)
- goto out_unregister;
+ goto out_fini;
return 0;
-out_unregister:
- platform_device_unregister(vgem_device->platform);
out_fini:
drm_dev_fini(&vgem_device->drm);
+out_unregister:
+ platform_device_unregister(vgem_device->platform);
out_free:
kfree(vgem_device);
return ret;
diff --git a/drivers/gpu/drm/vgem/vgem_fence.c b/drivers/gpu/drm/vgem/vgem_fence.c
index e6ee71323a66..c1c420afe2dd 100644
--- a/drivers/gpu/drm/vgem/vgem_fence.c
+++ b/drivers/gpu/drm/vgem/vgem_fence.c
@@ -180,7 +180,7 @@ int vgem_fence_attach_ioctl(struct drm_device *dev,
reservation_object_lock(resv, NULL);
if (arg->flags & VGEM_FENCE_WRITE)
reservation_object_add_excl_fence(resv, fence);
- else if ((ret = reservation_object_reserve_shared(resv)) == 0)
+ else if ((ret = reservation_object_reserve_shared(resv, 1)) == 0)
reservation_object_add_shared_fence(resv, fence);
reservation_object_unlock(resv);
diff --git a/drivers/gpu/drm/virtio/virtgpu_drm_bus.c b/drivers/gpu/drm/virtio/virtgpu_drm_bus.c
index 757ca28ab93e..0887e0b64b9c 100644
--- a/drivers/gpu/drm/virtio/virtgpu_drm_bus.c
+++ b/drivers/gpu/drm/virtio/virtgpu_drm_bus.c
@@ -53,6 +53,37 @@ int drm_virtio_init(struct drm_driver *driver, struct virtio_device *vdev)
0,
"virtiodrmfb");
+ /*
+ * Normally the drm_dev_set_unique() call is done by core DRM.
+ * The following comment covers, why virtio cannot rely on it.
+ *
+ * Unlike the other virtual GPU drivers, virtio abstracts the
+ * underlying bus type by using struct virtio_device.
+ *
+ * Hence the dev_is_pci() check, used in core DRM, will fail
+ * and the unique returned will be the virtio_device "virtio0",
+ * while a "pci:..." one is required.
+ *
+ * A few other ideas were considered:
+ * - Extend the dev_is_pci() check [in drm_set_busid] to
+ * consider virtio.
+ * Seems like a bigger hack than what we have already.
+ *
+ * - Point drm_device::dev to the parent of the virtio_device
+ * Semantic changes:
+ * * Using the wrong device for i2c, framebuffer_alloc and
+ * prime import.
+ * Visual changes:
+ * * Helpers such as DRM_DEV_ERROR, dev_info, drm_printer,
+ * will print the wrong information.
+ *
+ * We could address the latter issues, by introducing
+ * drm_device::bus_dev, ... which would be used solely for this.
+ *
+ * So for the moment keep things as-is, with a bulky comment
+ * for the next person who feels like removing this
+ * drm_dev_set_unique() quirk.
+ */
snprintf(unique, sizeof(unique), "pci:%s", pname);
ret = drm_dev_set_unique(dev, unique);
if (ret)
diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h
index d29f0c7c768c..2a8aaea72af3 100644
--- a/drivers/gpu/drm/virtio/virtgpu_drv.h
+++ b/drivers/gpu/drm/virtio/virtgpu_drv.h
@@ -65,6 +65,7 @@ struct virtio_gpu_object {
struct ttm_placement placement;
struct ttm_buffer_object tbo;
struct ttm_bo_kmap_obj kmap;
+ bool created;
};
#define gem_to_virtio_gpu_obj(gobj) \
container_of((gobj), struct virtio_gpu_object, gem_base)
@@ -142,9 +143,6 @@ struct virtio_gpu_fbdev {
};
struct virtio_gpu_mman {
- struct ttm_bo_global_ref bo_global_ref;
- struct drm_global_reference mem_global_ref;
- bool mem_global_referenced;
struct ttm_bo_device bdev;
};
@@ -190,8 +188,7 @@ struct virtio_gpu_device {
struct kmem_cache *vbufs;
bool vqs_ready;
- struct idr resource_idr;
- spinlock_t resource_idr_lock;
+ struct ida resource_ida;
wait_queue_head_t resp_wq;
/* current display info */
@@ -200,8 +197,7 @@ struct virtio_gpu_device {
struct virtio_gpu_fence_driver fence_drv;
- struct idr ctx_id_idr;
- spinlock_t ctx_id_idr_lock;
+ struct ida ctx_id_ida;
bool has_virgl_3d;
@@ -259,11 +255,8 @@ int virtio_gpu_surface_dirty(struct virtio_gpu_framebuffer *qfb,
/* virtio vg */
int virtio_gpu_alloc_vbufs(struct virtio_gpu_device *vgdev);
void virtio_gpu_free_vbufs(struct virtio_gpu_device *vgdev);
-void virtio_gpu_resource_id_get(struct virtio_gpu_device *vgdev,
- uint32_t *resid);
-void virtio_gpu_resource_id_put(struct virtio_gpu_device *vgdev, uint32_t id);
void virtio_gpu_cmd_create_resource(struct virtio_gpu_device *vgdev,
- uint32_t resource_id,
+ struct virtio_gpu_object *bo,
uint32_t format,
uint32_t width,
uint32_t height);
@@ -285,7 +278,6 @@ void virtio_gpu_cmd_set_scanout(struct virtio_gpu_device *vgdev,
uint32_t x, uint32_t y);
int virtio_gpu_object_attach(struct virtio_gpu_device *vgdev,
struct virtio_gpu_object *obj,
- uint32_t resource_id,
struct virtio_gpu_fence **fence);
void virtio_gpu_object_detach(struct virtio_gpu_device *vgdev,
struct virtio_gpu_object *obj);
@@ -324,6 +316,7 @@ void virtio_gpu_cmd_transfer_to_host_3d(struct virtio_gpu_device *vgdev,
struct virtio_gpu_fence **fence);
void
virtio_gpu_cmd_resource_create_3d(struct virtio_gpu_device *vgdev,
+ struct virtio_gpu_object *bo,
struct virtio_gpu_resource_create_3d *rc_3d,
struct virtio_gpu_fence **fence);
void virtio_gpu_ctrl_ack(struct virtqueue *vq);
diff --git a/drivers/gpu/drm/virtio/virtgpu_fb.c b/drivers/gpu/drm/virtio/virtgpu_fb.c
index cea749f4ec39..fb1cc8b2f119 100644
--- a/drivers/gpu/drm/virtio/virtgpu_fb.c
+++ b/drivers/gpu/drm/virtio/virtgpu_fb.c
@@ -214,7 +214,7 @@ static int virtio_gpufb_create(struct drm_fb_helper *helper,
struct drm_framebuffer *fb;
struct drm_mode_fb_cmd2 mode_cmd = {};
struct virtio_gpu_object *obj;
- uint32_t resid, format, size;
+ uint32_t format, size;
int ret;
mode_cmd.width = sizes->surface_width;
@@ -231,8 +231,7 @@ static int virtio_gpufb_create(struct drm_fb_helper *helper,
if (IS_ERR(obj))
return PTR_ERR(obj);
- virtio_gpu_resource_id_get(vgdev, &resid);
- virtio_gpu_cmd_create_resource(vgdev, resid, format,
+ virtio_gpu_cmd_create_resource(vgdev, obj, format,
mode_cmd.width, mode_cmd.height);
ret = virtio_gpu_object_kmap(obj);
@@ -242,7 +241,7 @@ static int virtio_gpufb_create(struct drm_fb_helper *helper,
}
/* attach the object to the resource */
- ret = virtio_gpu_object_attach(vgdev, obj, resid, NULL);
+ ret = virtio_gpu_object_attach(vgdev, obj, NULL);
if (ret)
goto err_obj_attach;
diff --git a/drivers/gpu/drm/virtio/virtgpu_gem.c b/drivers/gpu/drm/virtio/virtgpu_gem.c
index 82c817f37cf7..f06586393974 100644
--- a/drivers/gpu/drm/virtio/virtgpu_gem.c
+++ b/drivers/gpu/drm/virtio/virtgpu_gem.c
@@ -87,7 +87,6 @@ int virtio_gpu_mode_dumb_create(struct drm_file *file_priv,
struct virtio_gpu_object *obj;
int ret;
uint32_t pitch;
- uint32_t resid;
uint32_t format;
if (args->bpp != 32)
@@ -103,13 +102,12 @@ int virtio_gpu_mode_dumb_create(struct drm_file *file_priv,
goto fail;
format = virtio_gpu_translate_format(DRM_FORMAT_HOST_XRGB8888);
- virtio_gpu_resource_id_get(vgdev, &resid);
- virtio_gpu_cmd_create_resource(vgdev, resid, format,
+ obj = gem_to_virtio_gpu_obj(gobj);
+ virtio_gpu_cmd_create_resource(vgdev, obj, format,
args->width, args->height);
/* attach the object to the resource */
- obj = gem_to_virtio_gpu_obj(gobj);
- ret = virtio_gpu_object_attach(vgdev, obj, resid, NULL);
+ ret = virtio_gpu_object_attach(vgdev, obj, NULL);
if (ret)
goto fail;
diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c
index f16b875d6a46..bc5afa4f906e 100644
--- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c
+++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c
@@ -217,7 +217,6 @@ static int virtio_gpu_resource_create_ioctl(struct drm_device *dev, void *data,
struct virtio_gpu_device *vgdev = dev->dev_private;
struct drm_virtgpu_resource_create *rc = data;
int ret;
- uint32_t res_id;
struct virtio_gpu_object *qobj;
struct drm_gem_object *obj;
uint32_t handle = 0;
@@ -244,8 +243,6 @@ static int virtio_gpu_resource_create_ioctl(struct drm_device *dev, void *data,
INIT_LIST_HEAD(&validate_list);
memset(&mainbuf, 0, sizeof(struct ttm_validate_buffer));
- virtio_gpu_resource_id_get(vgdev, &res_id);
-
size = rc->size;
/* allocate a single page size object */
@@ -253,17 +250,15 @@ static int virtio_gpu_resource_create_ioctl(struct drm_device *dev, void *data,
size = PAGE_SIZE;
qobj = virtio_gpu_alloc_object(dev, size, false, false);
- if (IS_ERR(qobj)) {
- ret = PTR_ERR(qobj);
- goto fail_id;
- }
+ if (IS_ERR(qobj))
+ return PTR_ERR(qobj);
obj = &qobj->gem_base;
if (!vgdev->has_virgl_3d) {
- virtio_gpu_cmd_create_resource(vgdev, res_id, rc->format,
+ virtio_gpu_cmd_create_resource(vgdev, qobj, rc->format,
rc->width, rc->height);
- ret = virtio_gpu_object_attach(vgdev, qobj, res_id, NULL);
+ ret = virtio_gpu_object_attach(vgdev, qobj, NULL);
} else {
/* use a gem reference since unref list undoes them */
drm_gem_object_get(&qobj->gem_base);
@@ -276,7 +271,7 @@ static int virtio_gpu_resource_create_ioctl(struct drm_device *dev, void *data,
goto fail_unref;
}
- rc_3d.resource_id = cpu_to_le32(res_id);
+ rc_3d.resource_id = cpu_to_le32(qobj->hw_res_handle);
rc_3d.target = cpu_to_le32(rc->target);
rc_3d.format = cpu_to_le32(rc->format);
rc_3d.bind = cpu_to_le32(rc->bind);
@@ -288,8 +283,8 @@ static int virtio_gpu_resource_create_ioctl(struct drm_device *dev, void *data,
rc_3d.nr_samples = cpu_to_le32(rc->nr_samples);
rc_3d.flags = cpu_to_le32(rc->flags);
- virtio_gpu_cmd_resource_create_3d(vgdev, &rc_3d, NULL);
- ret = virtio_gpu_object_attach(vgdev, qobj, res_id, &fence);
+ virtio_gpu_cmd_resource_create_3d(vgdev, qobj, &rc_3d, NULL);
+ ret = virtio_gpu_object_attach(vgdev, qobj, &fence);
if (ret) {
ttm_eu_backoff_reservation(&ticket, &validate_list);
goto fail_unref;
@@ -297,8 +292,6 @@ static int virtio_gpu_resource_create_ioctl(struct drm_device *dev, void *data,
ttm_eu_fence_buffer_objects(&ticket, &validate_list, &fence->f);
}
- qobj->hw_res_handle = res_id;
-
ret = drm_gem_handle_create(file_priv, obj, &handle);
if (ret) {
@@ -311,7 +304,7 @@ static int virtio_gpu_resource_create_ioctl(struct drm_device *dev, void *data,
}
drm_gem_object_put_unlocked(obj);
- rc->res_handle = res_id; /* similiar to a VM address */
+ rc->res_handle = qobj->hw_res_handle; /* similiar to a VM address */
rc->bo_handle = handle;
if (vgdev->has_virgl_3d) {
@@ -326,8 +319,6 @@ fail_unref:
}
//fail_obj:
// drm_gem_object_handle_unreference_unlocked(obj);
-fail_id:
- virtio_gpu_resource_id_put(vgdev, res_id);
return ret;
}
diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c b/drivers/gpu/drm/virtio/virtgpu_kms.c
index 65060c08522d..bf609dcae224 100644
--- a/drivers/gpu/drm/virtio/virtgpu_kms.c
+++ b/drivers/gpu/drm/virtio/virtgpu_kms.c
@@ -52,39 +52,22 @@ static void virtio_gpu_config_changed_work_func(struct work_struct *work)
events_clear, &events_clear);
}
-static void virtio_gpu_ctx_id_get(struct virtio_gpu_device *vgdev,
- uint32_t *resid)
+static int virtio_gpu_context_create(struct virtio_gpu_device *vgdev,
+ uint32_t nlen, const char *name)
{
- int handle;
-
- idr_preload(GFP_KERNEL);
- spin_lock(&vgdev->ctx_id_idr_lock);
- handle = idr_alloc(&vgdev->ctx_id_idr, NULL, 1, 0, 0);
- spin_unlock(&vgdev->ctx_id_idr_lock);
- idr_preload_end();
- *resid = handle;
-}
+ int handle = ida_alloc_min(&vgdev->ctx_id_ida, 1, GFP_KERNEL);
-static void virtio_gpu_ctx_id_put(struct virtio_gpu_device *vgdev, uint32_t id)
-{
- spin_lock(&vgdev->ctx_id_idr_lock);
- idr_remove(&vgdev->ctx_id_idr, id);
- spin_unlock(&vgdev->ctx_id_idr_lock);
-}
-
-static void virtio_gpu_context_create(struct virtio_gpu_device *vgdev,
- uint32_t nlen, const char *name,
- uint32_t *ctx_id)
-{
- virtio_gpu_ctx_id_get(vgdev, ctx_id);
- virtio_gpu_cmd_context_create(vgdev, *ctx_id, nlen, name);
+ if (handle < 0)
+ return handle;
+ virtio_gpu_cmd_context_create(vgdev, handle, nlen, name);
+ return handle;
}
static void virtio_gpu_context_destroy(struct virtio_gpu_device *vgdev,
uint32_t ctx_id)
{
virtio_gpu_cmd_context_destroy(vgdev, ctx_id);
- virtio_gpu_ctx_id_put(vgdev, ctx_id);
+ ida_free(&vgdev->ctx_id_ida, ctx_id);
}
static void virtio_gpu_init_vq(struct virtio_gpu_queue *vgvq,
@@ -151,10 +134,8 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags)
vgdev->dev = dev->dev;
spin_lock_init(&vgdev->display_info_lock);
- spin_lock_init(&vgdev->ctx_id_idr_lock);
- idr_init(&vgdev->ctx_id_idr);
- spin_lock_init(&vgdev->resource_idr_lock);
- idr_init(&vgdev->resource_idr);
+ ida_init(&vgdev->ctx_id_ida);
+ ida_init(&vgdev->resource_ida);
init_waitqueue_head(&vgdev->resp_wq);
virtio_gpu_init_vq(&vgdev->ctrlq, virtio_gpu_dequeue_ctrl_func);
virtio_gpu_init_vq(&vgdev->cursorq, virtio_gpu_dequeue_cursor_func);
@@ -271,7 +252,7 @@ int virtio_gpu_driver_open(struct drm_device *dev, struct drm_file *file)
{
struct virtio_gpu_device *vgdev = dev->dev_private;
struct virtio_gpu_fpriv *vfpriv;
- uint32_t id;
+ int id;
char dbgname[TASK_COMM_LEN];
/* can't create contexts without 3d renderer */
@@ -284,7 +265,9 @@ int virtio_gpu_driver_open(struct drm_device *dev, struct drm_file *file)
return -ENOMEM;
get_task_comm(dbgname, current);
- virtio_gpu_context_create(vgdev, strlen(dbgname), dbgname, &id);
+ id = virtio_gpu_context_create(vgdev, strlen(dbgname), dbgname);
+ if (id < 0)
+ return id;
vfpriv->ctx_id = id;
file->driver_priv = vfpriv;
diff --git a/drivers/gpu/drm/virtio/virtgpu_object.c b/drivers/gpu/drm/virtio/virtgpu_object.c
index eca765537470..77eac4eb06b1 100644
--- a/drivers/gpu/drm/virtio/virtgpu_object.c
+++ b/drivers/gpu/drm/virtio/virtgpu_object.c
@@ -25,6 +25,18 @@
#include "virtgpu_drv.h"
+static void virtio_gpu_resource_id_get(struct virtio_gpu_device *vgdev,
+ uint32_t *resid)
+{
+ int handle = ida_alloc_min(&vgdev->resource_ida, 1, GFP_KERNEL);
+ *resid = handle;
+}
+
+static void virtio_gpu_resource_id_put(struct virtio_gpu_device *vgdev, uint32_t id)
+{
+ ida_free(&vgdev->resource_ida, id);
+}
+
static void virtio_gpu_ttm_bo_destroy(struct ttm_buffer_object *tbo)
{
struct virtio_gpu_object *bo;
@@ -33,13 +45,14 @@ static void virtio_gpu_ttm_bo_destroy(struct ttm_buffer_object *tbo)
bo = container_of(tbo, struct virtio_gpu_object, tbo);
vgdev = (struct virtio_gpu_device *)bo->gem_base.dev->dev_private;
- if (bo->hw_res_handle)
+ if (bo->created)
virtio_gpu_cmd_unref_resource(vgdev, bo->hw_res_handle);
if (bo->pages)
virtio_gpu_object_free_sg_table(bo);
if (bo->vmap)
virtio_gpu_object_kunmap(bo);
drm_gem_object_release(&bo->gem_base);
+ virtio_gpu_resource_id_put(vgdev, bo->hw_res_handle);
kfree(bo);
}
@@ -81,9 +94,11 @@ int virtio_gpu_object_create(struct virtio_gpu_device *vgdev,
bo = kzalloc(sizeof(struct virtio_gpu_object), GFP_KERNEL);
if (bo == NULL)
return -ENOMEM;
+ virtio_gpu_resource_id_get(vgdev, &bo->hw_res_handle);
size = roundup(size, PAGE_SIZE);
ret = drm_gem_object_init(vgdev->ddev, &bo->gem_base, size);
if (ret != 0) {
+ virtio_gpu_resource_id_put(vgdev, bo->hw_res_handle);
kfree(bo);
return ret;
}
diff --git a/drivers/gpu/drm/virtio/virtgpu_ttm.c b/drivers/gpu/drm/virtio/virtgpu_ttm.c
index e3152d45c5f1..4bfbf25fabff 100644
--- a/drivers/gpu/drm/virtio/virtgpu_ttm.c
+++ b/drivers/gpu/drm/virtio/virtgpu_ttm.c
@@ -50,62 +50,6 @@ virtio_gpu_device *virtio_gpu_get_vgdev(struct ttm_bo_device *bdev)
return vgdev;
}
-static int virtio_gpu_ttm_mem_global_init(struct drm_global_reference *ref)
-{
- return ttm_mem_global_init(ref->object);
-}
-
-static void virtio_gpu_ttm_mem_global_release(struct drm_global_reference *ref)
-{
- ttm_mem_global_release(ref->object);
-}
-
-static int virtio_gpu_ttm_global_init(struct virtio_gpu_device *vgdev)
-{
- struct drm_global_reference *global_ref;
- int r;
-
- vgdev->mman.mem_global_referenced = false;
- global_ref = &vgdev->mman.mem_global_ref;
- global_ref->global_type = DRM_GLOBAL_TTM_MEM;
- global_ref->size = sizeof(struct ttm_mem_global);
- global_ref->init = &virtio_gpu_ttm_mem_global_init;
- global_ref->release = &virtio_gpu_ttm_mem_global_release;
-
- r = drm_global_item_ref(global_ref);
- if (r != 0) {
- DRM_ERROR("Failed setting up TTM memory accounting "
- "subsystem.\n");
- return r;
- }
-
- vgdev->mman.bo_global_ref.mem_glob =
- vgdev->mman.mem_global_ref.object;
- global_ref = &vgdev->mman.bo_global_ref.ref;
- global_ref->global_type = DRM_GLOBAL_TTM_BO;
- global_ref->size = sizeof(struct ttm_bo_global);
- global_ref->init = &ttm_bo_global_init;
- global_ref->release = &ttm_bo_global_release;
- r = drm_global_item_ref(global_ref);
- if (r != 0) {
- DRM_ERROR("Failed setting up TTM BO subsystem.\n");
- drm_global_item_unref(&vgdev->mman.mem_global_ref);
- return r;
- }
-
- vgdev->mman.mem_global_referenced = true;
- return 0;
-}
-
-static void virtio_gpu_ttm_global_fini(struct virtio_gpu_device *vgdev)
-{
- if (vgdev->mman.mem_global_referenced) {
- drm_global_item_unref(&vgdev->mman.bo_global_ref.ref);
- drm_global_item_unref(&vgdev->mman.mem_global_ref);
- vgdev->mman.mem_global_referenced = false;
- }
-}
-
int virtio_gpu_mmap(struct file *filp, struct vm_area_struct *vma)
{
struct drm_file *file_priv;
@@ -347,8 +291,7 @@ static void virtio_gpu_bo_move_notify(struct ttm_buffer_object *tbo,
} else if (new_mem->placement & TTM_PL_FLAG_TT) {
if (bo->hw_res_handle) {
- virtio_gpu_object_attach(vgdev, bo, bo->hw_res_handle,
- NULL);
+ virtio_gpu_object_attach(vgdev, bo, NULL);
}
}
}
@@ -383,12 +326,8 @@ int virtio_gpu_ttm_init(struct virtio_gpu_device *vgdev)
{
int r;
- r = virtio_gpu_ttm_global_init(vgdev);
- if (r)
- return r;
/* No others user of address space so set it to 0 */
r = ttm_bo_device_init(&vgdev->mman.bdev,
- vgdev->mman.bo_global_ref.ref.object,
&virtio_gpu_bo_driver,
vgdev->ddev->anon_inode->i_mapping,
DRM_FILE_PAGE_OFFSET, 0);
@@ -407,13 +346,11 @@ int virtio_gpu_ttm_init(struct virtio_gpu_device *vgdev)
err_mm_init:
ttm_bo_device_release(&vgdev->mman.bdev);
err_dev_init:
- virtio_gpu_ttm_global_fini(vgdev);
return r;
}
void virtio_gpu_ttm_fini(struct virtio_gpu_device *vgdev)
{
ttm_bo_device_release(&vgdev->mman.bdev);
- virtio_gpu_ttm_global_fini(vgdev);
DRM_INFO("virtio_gpu: ttm finalized\n");
}
diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c
index 4e2e037aed34..51bef1775e47 100644
--- a/drivers/gpu/drm/virtio/virtgpu_vq.c
+++ b/drivers/gpu/drm/virtio/virtgpu_vq.c
@@ -38,26 +38,6 @@
+ MAX_INLINE_CMD_SIZE \
+ MAX_INLINE_RESP_SIZE)
-void virtio_gpu_resource_id_get(struct virtio_gpu_device *vgdev,
- uint32_t *resid)
-{
- int handle;
-
- idr_preload(GFP_KERNEL);
- spin_lock(&vgdev->resource_idr_lock);
- handle = idr_alloc(&vgdev->resource_idr, NULL, 1, 0, GFP_NOWAIT);
- spin_unlock(&vgdev->resource_idr_lock);
- idr_preload_end();
- *resid = handle;
-}
-
-void virtio_gpu_resource_id_put(struct virtio_gpu_device *vgdev, uint32_t id)
-{
- spin_lock(&vgdev->resource_idr_lock);
- idr_remove(&vgdev->resource_idr, id);
- spin_unlock(&vgdev->resource_idr_lock);
-}
-
void virtio_gpu_ctrl_ack(struct virtqueue *vq)
{
struct drm_device *dev = vq->vdev->priv;
@@ -98,10 +78,9 @@ virtio_gpu_get_vbuf(struct virtio_gpu_device *vgdev,
{
struct virtio_gpu_vbuffer *vbuf;
- vbuf = kmem_cache_alloc(vgdev->vbufs, GFP_KERNEL);
+ vbuf = kmem_cache_zalloc(vgdev->vbufs, GFP_KERNEL);
if (!vbuf)
return ERR_PTR(-ENOMEM);
- memset(vbuf, 0, VBUFFER_SIZE);
BUG_ON(size > MAX_INLINE_CMD_SIZE);
vbuf->buf = (void *)vbuf + sizeof(*vbuf);
@@ -388,7 +367,7 @@ retry:
/* create a basic resource */
void virtio_gpu_cmd_create_resource(struct virtio_gpu_device *vgdev,
- uint32_t resource_id,
+ struct virtio_gpu_object *bo,
uint32_t format,
uint32_t width,
uint32_t height)
@@ -400,12 +379,13 @@ void virtio_gpu_cmd_create_resource(struct virtio_gpu_device *vgdev,
memset(cmd_p, 0, sizeof(*cmd_p));
cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_CREATE_2D);
- cmd_p->resource_id = cpu_to_le32(resource_id);
+ cmd_p->resource_id = cpu_to_le32(bo->hw_res_handle);
cmd_p->format = cpu_to_le32(format);
cmd_p->width = cpu_to_le32(width);
cmd_p->height = cpu_to_le32(height);
virtio_gpu_queue_ctrl_buffer(vgdev, vbuf);
+ bo->created = true;
}
void virtio_gpu_cmd_unref_resource(struct virtio_gpu_device *vgdev,
@@ -772,6 +752,7 @@ void virtio_gpu_cmd_context_detach_resource(struct virtio_gpu_device *vgdev,
void
virtio_gpu_cmd_resource_create_3d(struct virtio_gpu_device *vgdev,
+ struct virtio_gpu_object *bo,
struct virtio_gpu_resource_create_3d *rc_3d,
struct virtio_gpu_fence **fence)
{
@@ -786,6 +767,7 @@ virtio_gpu_cmd_resource_create_3d(struct virtio_gpu_device *vgdev,
cmd_p->hdr.flags = 0;
virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, &cmd_p->hdr, fence);
+ bo->created = true;
}
void virtio_gpu_cmd_transfer_to_host_3d(struct virtio_gpu_device *vgdev,
@@ -861,7 +843,6 @@ void virtio_gpu_cmd_submit(struct virtio_gpu_device *vgdev,
int virtio_gpu_object_attach(struct virtio_gpu_device *vgdev,
struct virtio_gpu_object *obj,
- uint32_t resource_id,
struct virtio_gpu_fence **fence)
{
bool use_dma_api = !virtio_has_iommu_quirk(vgdev->vdev);
@@ -869,6 +850,9 @@ int virtio_gpu_object_attach(struct virtio_gpu_device *vgdev,
struct scatterlist *sg;
int si, nents;
+ if (!obj->created)
+ return 0;
+
if (!obj->pages) {
int ret;
@@ -902,10 +886,9 @@ int virtio_gpu_object_attach(struct virtio_gpu_device *vgdev,
ents[si].padding = 0;
}
- virtio_gpu_cmd_resource_attach_backing(vgdev, resource_id,
+ virtio_gpu_cmd_resource_attach_backing(vgdev, obj->hw_res_handle,
ents, nents,
fence);
- obj->hw_res_handle = resource_id;
return 0;
}
diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c
index 07cfde1b4132..a3d57e0f5ee5 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.c
+++ b/drivers/gpu/drm/vkms/vkms_drv.c
@@ -108,17 +108,18 @@ static int __init vkms_init(void)
if (!vkms_device)
return -ENOMEM;
- ret = drm_dev_init(&vkms_device->drm, &vkms_driver, NULL);
- if (ret)
- goto out_free;
-
vkms_device->platform =
platform_device_register_simple(DRIVER_NAME, -1, NULL, 0);
if (IS_ERR(vkms_device->platform)) {
ret = PTR_ERR(vkms_device->platform);
- goto out_fini;
+ goto out_free;
}
+ ret = drm_dev_init(&vkms_device->drm, &vkms_driver,
+ &vkms_device->platform->dev);
+ if (ret)
+ goto out_unregister;
+
vkms_device->drm.irq_enabled = true;
ret = drm_vblank_init(&vkms_device->drm, 1);
@@ -129,20 +130,20 @@ static int __init vkms_init(void)
ret = vkms_modeset_init(vkms_device);
if (ret)
- goto out_unregister;
+ goto out_fini;
ret = drm_dev_register(&vkms_device->drm, 0);
if (ret)
- goto out_unregister;
+ goto out_fini;
return 0;
-out_unregister:
- platform_device_unregister(vkms_device->platform);
-
out_fini:
drm_dev_fini(&vkms_device->drm);
+out_unregister:
+ platform_device_unregister(vkms_device->platform);
+
out_free:
kfree(vkms_device);
return ret;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index 61a84b958d67..b9c078860a7c 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -801,11 +801,6 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
DRM_INFO("MMIO at 0x%08x size is %u kiB\n",
dev_priv->mmio_start, dev_priv->mmio_size / 1024);
- ret = vmw_ttm_global_init(dev_priv);
- if (unlikely(ret != 0))
- goto out_err0;
-
-
vmw_master_init(&dev_priv->fbdev_master);
ttm_lock_set_kill(&dev_priv->fbdev_master.lock, false, SIGTERM);
dev_priv->active_master = &dev_priv->fbdev_master;
@@ -816,7 +811,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
if (unlikely(dev_priv->mmio_virt == NULL)) {
ret = -ENOMEM;
DRM_ERROR("Failed mapping MMIO.\n");
- goto out_err3;
+ goto out_err0;
}
/* Need mmio memory to check for fifo pitchlock cap. */
@@ -828,8 +823,8 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
goto out_err4;
}
- dev_priv->tdev = ttm_object_device_init
- (dev_priv->mem_global_ref.object, 12, &vmw_prime_dmabuf_ops);
+ dev_priv->tdev = ttm_object_device_init(&ttm_mem_glob, 12,
+ &vmw_prime_dmabuf_ops);
if (unlikely(dev_priv->tdev == NULL)) {
DRM_ERROR("Unable to initialize TTM object management.\n");
@@ -870,7 +865,6 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
}
ret = ttm_bo_device_init(&dev_priv->bdev,
- dev_priv->bo_global_ref.ref.object,
&vmw_bo_driver,
dev->anon_inode->i_mapping,
VMWGFX_FILE_PAGE_OFFSET,
@@ -992,8 +986,6 @@ out_no_device:
ttm_object_device_release(&dev_priv->tdev);
out_err4:
memunmap(dev_priv->mmio_virt);
-out_err3:
- vmw_ttm_global_release(dev_priv);
out_err0:
for (i = vmw_res_context; i < vmw_res_max; ++i)
idr_destroy(&dev_priv->res_idr[i]);
@@ -1045,7 +1037,6 @@ static void vmw_driver_unload(struct drm_device *dev)
memunmap(dev_priv->mmio_virt);
if (dev_priv->ctx.staged_bindings)
vmw_binding_state_free(dev_priv->ctx.staged_bindings);
- vmw_ttm_global_release(dev_priv);
for (i = vmw_res_context; i < vmw_res_max; ++i)
idr_destroy(&dev_priv->res_idr[i]);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index 59f614225bcd..28df788da44e 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -417,8 +417,6 @@ enum {
struct vmw_private {
struct ttm_bo_device bdev;
- struct ttm_bo_global_ref bo_global_ref;
- struct drm_global_reference mem_global_ref;
struct vmw_fifo_state fifo;
@@ -842,8 +840,6 @@ extern int vmw_fifo_flush(struct vmw_private *dev_priv,
* TTM glue - vmwgfx_ttm_glue.c
*/
-extern int vmw_ttm_global_init(struct vmw_private *dev_priv);
-extern void vmw_ttm_global_release(struct vmw_private *dev_priv);
extern int vmw_mmap(struct file *filp, struct vm_area_struct *vma);
/**
@@ -1363,7 +1359,7 @@ vmw_bo_reference(struct vmw_buffer_object *buf)
static inline struct ttm_mem_global *vmw_mem_glob(struct vmw_private *dev_priv)
{
- return (struct ttm_mem_global *) dev_priv->mem_global_ref.object;
+ return &ttm_mem_glob;
}
static inline void vmw_fifo_resource_inc(struct vmw_private *dev_priv)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index dca04d4246ea..e6b11f6ae2e4 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -493,24 +493,24 @@ int vmw_du_cursor_plane_atomic_check(struct drm_plane *plane,
struct drm_plane_state *new_state)
{
int ret = 0;
+ struct drm_crtc_state *crtc_state = NULL;
struct vmw_surface *surface = NULL;
struct drm_framebuffer *fb = new_state->fb;
- struct drm_rect src = drm_plane_state_src(new_state);
- struct drm_rect dest = drm_plane_state_dest(new_state);
+ if (new_state->crtc)
+ crtc_state = drm_atomic_get_new_crtc_state(new_state->state,
+ new_state->crtc);
- /* Turning off */
- if (!fb)
+ ret = drm_atomic_helper_check_plane_state(new_state, crtc_state,
+ DRM_PLANE_HELPER_NO_SCALING,
+ DRM_PLANE_HELPER_NO_SCALING,
+ true, true);
+ if (ret)
return ret;
- ret = drm_plane_helper_check_update(plane, new_state->crtc, fb,
- &src, &dest,
- DRM_MODE_ROTATE_0,
- DRM_PLANE_HELPER_NO_SCALING,
- DRM_PLANE_HELPER_NO_SCALING,
- true, true, &new_state->visible);
- if (!ret)
- return ret;
+ /* Turning off */
+ if (!fb)
+ return 0;
/* A lot of the code assumes this */
if (new_state->crtc_w != 64 || new_state->crtc_h != 64) {
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
index 723578117191..4b5378495eea 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
@@ -274,7 +274,6 @@ static const struct drm_connector_funcs vmw_legacy_connector_funcs = {
static const struct
drm_connector_helper_funcs vmw_ldu_connector_helper_funcs = {
- .best_encoder = drm_atomic_helper_best_encoder,
};
/*
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
index 53316b1bda3d..333418dc259f 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
@@ -389,7 +389,6 @@ static const struct drm_connector_funcs vmw_sou_connector_funcs = {
static const struct
drm_connector_helper_funcs vmw_sou_connector_helper_funcs = {
- .best_encoder = drm_atomic_helper_best_encoder,
};
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
index e086565c1da6..c3e435f444c1 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
@@ -1054,7 +1054,6 @@ static const struct drm_connector_funcs vmw_stdu_connector_funcs = {
static const struct
drm_connector_helper_funcs vmw_stdu_connector_helper_funcs = {
- .best_encoder = drm_atomic_helper_best_encoder,
};
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c
index 7b1e5a5cbd2c..154eb09aa91e 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c
@@ -42,57 +42,3 @@ int vmw_mmap(struct file *filp, struct vm_area_struct *vma)
dev_priv = vmw_priv(file_priv->minor->dev);
return ttm_bo_mmap(filp, vma, &dev_priv->bdev);
}
-
-static int vmw_ttm_mem_global_init(struct drm_global_reference *ref)
-{
- DRM_INFO("global init.\n");
- return ttm_mem_global_init(ref->object);
-}
-
-static void vmw_ttm_mem_global_release(struct drm_global_reference *ref)
-{
- ttm_mem_global_release(ref->object);
-}
-
-int vmw_ttm_global_init(struct vmw_private *dev_priv)
-{
- struct drm_global_reference *global_ref;
- int ret;
-
- global_ref = &dev_priv->mem_global_ref;
- global_ref->global_type = DRM_GLOBAL_TTM_MEM;
- global_ref->size = sizeof(struct ttm_mem_global);
- global_ref->init = &vmw_ttm_mem_global_init;
- global_ref->release = &vmw_ttm_mem_global_release;
-
- ret = drm_global_item_ref(global_ref);
- if (unlikely(ret != 0)) {
- DRM_ERROR("Failed setting up TTM memory accounting.\n");
- return ret;
- }
-
- dev_priv->bo_global_ref.mem_glob =
- dev_priv->mem_global_ref.object;
- global_ref = &dev_priv->bo_global_ref.ref;
- global_ref->global_type = DRM_GLOBAL_TTM_BO;
- global_ref->size = sizeof(struct ttm_bo_global);
- global_ref->init = &ttm_bo_global_init;
- global_ref->release = &ttm_bo_global_release;
- ret = drm_global_item_ref(global_ref);
-
- if (unlikely(ret != 0)) {
- DRM_ERROR("Failed setting up TTM buffer objects.\n");
- goto out_no_bo;
- }
-
- return 0;
-out_no_bo:
- drm_global_item_unref(&dev_priv->mem_global_ref);
- return ret;
-}
-
-void vmw_ttm_global_release(struct vmw_private *dev_priv)
-{
- drm_global_item_unref(&dev_priv->bo_global_ref.ref);
- drm_global_item_unref(&dev_priv->mem_global_ref);
-}
diff --git a/drivers/gpu/drm/zte/zx_drm_drv.c b/drivers/gpu/drm/zte/zx_drm_drv.c
index 11ef17c2d1c1..f5ea32ae8600 100644
--- a/drivers/gpu/drm/zte/zx_drm_drv.c
+++ b/drivers/gpu/drm/zte/zx_drm_drv.c
@@ -114,7 +114,7 @@ out_unbind:
component_unbind_all(dev, drm);
out_unregister:
dev_set_drvdata(dev, NULL);
- drm_dev_unref(drm);
+ drm_dev_put(drm);
return ret;
}
@@ -124,10 +124,11 @@ static void zx_drm_unbind(struct device *dev)
drm_dev_unregister(drm);
drm_kms_helper_poll_fini(drm);
+ drm_atomic_helper_shutdown(drm);
drm_mode_config_cleanup(drm);
component_unbind_all(dev, drm);
dev_set_drvdata(dev, NULL);
- drm_dev_unref(drm);
+ drm_dev_put(drm);
}
static const struct component_master_ops zx_drm_master_ops = {
diff --git a/drivers/gpu/drm/zte/zx_plane.c b/drivers/gpu/drm/zte/zx_plane.c
index ae8c53b4b261..83d236fd893c 100644
--- a/drivers/gpu/drm/zte/zx_plane.c
+++ b/drivers/gpu/drm/zte/zx_plane.c
@@ -446,7 +446,6 @@ static const struct drm_plane_helper_funcs zx_gl_plane_helper_funcs = {
static void zx_plane_destroy(struct drm_plane *plane)
{
- drm_plane_helper_disable(plane, NULL);
drm_plane_cleanup(plane);
}
diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c
index 954eefe144e2..aa0e30a2ba18 100644
--- a/drivers/gpu/ipu-v3/ipu-csi.c
+++ b/drivers/gpu/ipu-v3/ipu-csi.c
@@ -232,7 +232,7 @@ static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code,
case MEDIA_BUS_FMT_BGR565_2X8_LE:
case MEDIA_BUS_FMT_RGB565_2X8_BE:
case MEDIA_BUS_FMT_RGB565_2X8_LE:
- if (mbus_type == V4L2_MBUS_CSI2)
+ if (mbus_type == V4L2_MBUS_CSI2_DPHY)
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB565;
else
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
@@ -359,7 +359,7 @@ static int fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg,
else
csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE;
break;
- case V4L2_MBUS_CSI2:
+ case V4L2_MBUS_CSI2_DPHY:
/*
* MIPI CSI-2 requires non gated clock mode, all other
* parameters are not applicable for MIPI CSI-2 bus.
@@ -611,7 +611,7 @@ int ipu_csi_set_mipi_datatype(struct ipu_csi *csi, u32 vc,
if (vc > 3)
return -EINVAL;
- ret = mbus_code_to_bus_cfg(&cfg, mbus_fmt->code, V4L2_MBUS_CSI2);
+ ret = mbus_code_to_bus_cfg(&cfg, mbus_fmt->code, V4L2_MBUS_CSI2_DPHY);
if (ret < 0)
return ret;
diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index cf2a18571d48..a132c37d7334 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -380,6 +380,9 @@ int vga_switcheroo_register_audio_client(struct pci_dev *pdev,
mutex_unlock(&vgasr_mutex);
return -EINVAL;
}
+ /* notify if GPU has been already bound */
+ if (ops->gpu_bound)
+ ops->gpu_bound(pdev, id);
}
mutex_unlock(&vgasr_mutex);
diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c
index c61b04555779..dc8e039bfab5 100644
--- a/drivers/gpu/vga/vgaarb.c
+++ b/drivers/gpu/vga/vgaarb.c
@@ -676,7 +676,7 @@ static bool vga_arbiter_add_pci_device(struct pci_dev *pdev)
vga_arbiter_check_bridge_sharing(vgadev);
/* Add to the list */
- list_add(&vgadev->list, &vga_list);
+ list_add_tail(&vgadev->list, &vga_list);
vga_count++;
vgaarb_info(&pdev->dev, "VGA device added: decodes=%s,owns=%s,locks=%s\n",
vga_iostate_to_str(vgadev->decodes),
@@ -1408,6 +1408,18 @@ static void __init vga_arb_select_default_device(void)
struct vga_device *vgadev;
#if defined(CONFIG_X86) || defined(CONFIG_IA64)
+ u64 base = screen_info.lfb_base;
+ u64 size = screen_info.lfb_size;
+ u64 limit;
+ resource_size_t start, end;
+ unsigned long flags;
+ int i;
+
+ if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE)
+ base |= (u64)screen_info.ext_lfb_base << 32;
+
+ limit = base + size;
+
list_for_each_entry(vgadev, &vga_list, list) {
struct device *dev = &vgadev->pdev->dev;
/*
@@ -1418,11 +1430,6 @@ static void __init vga_arb_select_default_device(void)
* Select the device owning the boot framebuffer if there is
* one.
*/
- resource_size_t start, end, limit;
- unsigned long flags;
- int i;
-
- limit = screen_info.lfb_base + screen_info.lfb_size;
/* Does firmware framebuffer belong to us? */
for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
@@ -1437,7 +1444,7 @@ static void __init vga_arb_select_default_device(void)
if (!start || !end)
continue;
- if (screen_info.lfb_base < start || limit >= end)
+ if (base < start || limit >= end)
continue;
if (!vga_default_device())
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 61e1953ff921..41e9935fc584 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -149,6 +149,7 @@ config HID_APPLEIR
config HID_ASUS
tristate "Asus"
depends on LEDS_CLASS
+ depends on ASUS_WMI || ASUS_WMI=n
---help---
Support for Asus notebook built-in keyboard and touchpad via i2c, and
the Asus Republic of Gamers laptop keyboard special keys.
@@ -182,6 +183,18 @@ config HID_BETOP_FF
Currently the following devices are known to be supported:
- BETOP 2185 PC & BFM MODE
+config HID_BIGBEN_FF
+ tristate "BigBen Interactive Kids' gamepad support"
+ depends on USB_HID
+ depends on NEW_LEDS
+ depends on LEDS_CLASS
+ select INPUT_FF_MEMLESS
+ help
+ Support for the "Kid-friendly Wired Controller" PS3OFMINIPAD
+ gamepad made by BigBen Interactive, originally sold as a PS3
+ accessory. This driver fixes input mapping and adds support for
+ force feedback effects and LEDs on the device.
+
config HID_CHERRY
tristate "Cherry Cymotion keyboard"
depends on HID
@@ -351,7 +364,7 @@ config HOLTEK_FF
config HID_GOOGLE_HAMMER
tristate "Google Hammer Keyboard"
- depends on USB_HID && LEDS_CLASS
+ depends on USB_HID && LEDS_CLASS && MFD_CROS_EC
---help---
Say Y here if you have a Google Hammer device.
@@ -596,6 +609,7 @@ config HID_MICROSOFT
tristate "Microsoft non-fully HID-compliant devices"
depends on HID
default !EXPERT
+ select INPUT_FF_MEMLESS
---help---
Support for Microsoft devices that are not fully compliant with HID standard.
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index bd7ac53b75c5..896a51ce7ce0 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -31,6 +31,7 @@ obj-$(CONFIG_HID_ASUS) += hid-asus.o
obj-$(CONFIG_HID_AUREAL) += hid-aureal.o
obj-$(CONFIG_HID_BELKIN) += hid-belkin.o
obj-$(CONFIG_HID_BETOP_FF) += hid-betopff.o
+obj-$(CONFIG_HID_BIGBEN_FF) += hid-bigbenff.o
obj-$(CONFIG_HID_CHERRY) += hid-cherry.o
obj-$(CONFIG_HID_CHICONY) += hid-chicony.o
obj-$(CONFIG_HID_CMEDIA) += hid-cmedia.o
diff --git a/drivers/hid/hid-alps.c b/drivers/hid/hid-alps.c
index aec253b44156..3cd7229b6e54 100644
--- a/drivers/hid/hid-alps.c
+++ b/drivers/hid/hid-alps.c
@@ -660,6 +660,20 @@ exit:
return ret;
}
+static int alps_sp_open(struct input_dev *dev)
+{
+ struct hid_device *hid = input_get_drvdata(dev);
+
+ return hid_hw_open(hid);
+}
+
+static void alps_sp_close(struct input_dev *dev)
+{
+ struct hid_device *hid = input_get_drvdata(dev);
+
+ hid_hw_close(hid);
+}
+
static int alps_input_configured(struct hid_device *hdev, struct hid_input *hi)
{
struct alps_dev *data = hid_get_drvdata(hdev);
@@ -733,6 +747,10 @@ static int alps_input_configured(struct hid_device *hdev, struct hid_input *hi)
input2->id.version = input->id.version;
input2->dev.parent = input->dev.parent;
+ input_set_drvdata(input2, hdev);
+ input2->open = alps_sp_open;
+ input2->close = alps_sp_close;
+
__set_bit(EV_KEY, input2->evbit);
data->sp_btn_cnt = (data->sp_btn_info & 0x0F);
for (i = 0; i < data->sp_btn_cnt; i++)
diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c
index 88a5672f42cd..a1fa2fc8c9b5 100644
--- a/drivers/hid/hid-asus.c
+++ b/drivers/hid/hid-asus.c
@@ -29,6 +29,7 @@
#include <linux/dmi.h>
#include <linux/hid.h>
#include <linux/module.h>
+#include <linux/platform_data/x86/asus-wmi.h>
#include <linux/input/mt.h>
#include <linux/usb.h> /* For to_usb_interface for T100 touchpad intf check */
@@ -349,6 +350,27 @@ static void asus_kbd_backlight_work(struct work_struct *work)
hid_err(led->hdev, "Asus failed to set keyboard backlight: %d\n", ret);
}
+/* WMI-based keyboard backlight LED control (via asus-wmi driver) takes
+ * precedence. We only activate HID-based backlight control when the
+ * WMI control is not available.
+ */
+static bool asus_kbd_wmi_led_control_present(struct hid_device *hdev)
+{
+ u32 value;
+ int ret;
+
+ if (!IS_ENABLED(CONFIG_ASUS_WMI))
+ return false;
+
+ ret = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS2,
+ ASUS_WMI_DEVID_KBD_BACKLIGHT, 0, &value);
+ hid_dbg(hdev, "WMI backlight check: rc %d value %x", ret, value);
+ if (ret)
+ return false;
+
+ return !!(value & ASUS_WMI_DSTS_PRESENCE_BIT);
+}
+
static int asus_kbd_register_leds(struct hid_device *hdev)
{
struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
@@ -436,7 +458,9 @@ static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi)
drvdata->input = input;
- if (drvdata->enable_backlight && asus_kbd_register_leds(hdev))
+ if (drvdata->enable_backlight &&
+ !asus_kbd_wmi_led_control_present(hdev) &&
+ asus_kbd_register_leds(hdev))
hid_warn(hdev, "Failed to initialize backlight.\n");
return 0;
diff --git a/drivers/hid/hid-bigbenff.c b/drivers/hid/hid-bigbenff.c
new file mode 100644
index 000000000000..3f6abd190df4
--- /dev/null
+++ b/drivers/hid/hid-bigbenff.c
@@ -0,0 +1,414 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/*
+ * LED & force feedback support for BigBen Interactive
+ *
+ * 0x146b:0x0902 "Bigben Interactive Bigben Game Pad"
+ * "Kid-friendly Wired Controller" PS3OFMINIPAD SONY
+ * sold for use with the PS3
+ *
+ * Copyright (c) 2018 Hanno Zulla <kontakt@hanno.de>
+ */
+
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/leds.h>
+#include <linux/hid.h>
+
+#include "hid-ids.h"
+
+
+/*
+ * The original descriptor for 0x146b:0x0902
+ *
+ * 0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
+ * 0x09, 0x05, // Usage (Game Pad)
+ * 0xA1, 0x01, // Collection (Application)
+ * 0x15, 0x00, // Logical Minimum (0)
+ * 0x25, 0x01, // Logical Maximum (1)
+ * 0x35, 0x00, // Physical Minimum (0)
+ * 0x45, 0x01, // Physical Maximum (1)
+ * 0x75, 0x01, // Report Size (1)
+ * 0x95, 0x0D, // Report Count (13)
+ * 0x05, 0x09, // Usage Page (Button)
+ * 0x19, 0x01, // Usage Minimum (0x01)
+ * 0x29, 0x0D, // Usage Maximum (0x0D)
+ * 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ * 0x95, 0x03, // Report Count (3)
+ * 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ * 0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
+ * 0x25, 0x07, // Logical Maximum (7)
+ * 0x46, 0x3B, 0x01, // Physical Maximum (315)
+ * 0x75, 0x04, // Report Size (4)
+ * 0x95, 0x01, // Report Count (1)
+ * 0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter)
+ * 0x09, 0x39, // Usage (Hat switch)
+ * 0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State)
+ * 0x65, 0x00, // Unit (None)
+ * 0x95, 0x01, // Report Count (1)
+ * 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ * 0x26, 0xFF, 0x00, // Logical Maximum (255)
+ * 0x46, 0xFF, 0x00, // Physical Maximum (255)
+ * 0x09, 0x30, // Usage (X)
+ * 0x09, 0x31, // Usage (Y)
+ * 0x09, 0x32, // Usage (Z)
+ * 0x09, 0x35, // Usage (Rz)
+ * 0x75, 0x08, // Report Size (8)
+ * 0x95, 0x04, // Report Count (4)
+ * 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ * 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
+ * 0x09, 0x20, // Usage (0x20)
+ * 0x09, 0x21, // Usage (0x21)
+ * 0x09, 0x22, // Usage (0x22)
+ * 0x09, 0x23, // Usage (0x23)
+ * 0x09, 0x24, // Usage (0x24)
+ * 0x09, 0x25, // Usage (0x25)
+ * 0x09, 0x26, // Usage (0x26)
+ * 0x09, 0x27, // Usage (0x27)
+ * 0x09, 0x28, // Usage (0x28)
+ * 0x09, 0x29, // Usage (0x29)
+ * 0x09, 0x2A, // Usage (0x2A)
+ * 0x09, 0x2B, // Usage (0x2B)
+ * 0x95, 0x0C, // Report Count (12)
+ * 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ * 0x0A, 0x21, 0x26, // Usage (0x2621)
+ * 0x95, 0x08, // Report Count (8)
+ * 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+ * 0x0A, 0x21, 0x26, // Usage (0x2621)
+ * 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+ * 0x26, 0xFF, 0x03, // Logical Maximum (1023)
+ * 0x46, 0xFF, 0x03, // Physical Maximum (1023)
+ * 0x09, 0x2C, // Usage (0x2C)
+ * 0x09, 0x2D, // Usage (0x2D)
+ * 0x09, 0x2E, // Usage (0x2E)
+ * 0x09, 0x2F, // Usage (0x2F)
+ * 0x75, 0x10, // Report Size (16)
+ * 0x95, 0x04, // Report Count (4)
+ * 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ * 0xC0, // End Collection
+ */
+
+#define PID0902_RDESC_ORIG_SIZE 137
+
+/*
+ * The fixed descriptor for 0x146b:0x0902
+ *
+ * - map buttons according to gamepad.rst
+ * - assign right stick from Z/Rz to Rx/Ry
+ * - map previously unused analog trigger data to Z/RZ
+ * - simplify feature and output descriptor
+ */
+static __u8 pid0902_rdesc_fixed[] = {
+ 0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */
+ 0x09, 0x05, /* Usage (Game Pad) */
+ 0xA1, 0x01, /* Collection (Application) */
+ 0x15, 0x00, /* Logical Minimum (0) */
+ 0x25, 0x01, /* Logical Maximum (1) */
+ 0x35, 0x00, /* Physical Minimum (0) */
+ 0x45, 0x01, /* Physical Maximum (1) */
+ 0x75, 0x01, /* Report Size (1) */
+ 0x95, 0x0D, /* Report Count (13) */
+ 0x05, 0x09, /* Usage Page (Button) */
+ 0x09, 0x05, /* Usage (BTN_WEST) */
+ 0x09, 0x01, /* Usage (BTN_SOUTH) */
+ 0x09, 0x02, /* Usage (BTN_EAST) */
+ 0x09, 0x04, /* Usage (BTN_NORTH) */
+ 0x09, 0x07, /* Usage (BTN_TL) */
+ 0x09, 0x08, /* Usage (BTN_TR) */
+ 0x09, 0x09, /* Usage (BTN_TL2) */
+ 0x09, 0x0A, /* Usage (BTN_TR2) */
+ 0x09, 0x0B, /* Usage (BTN_SELECT) */
+ 0x09, 0x0C, /* Usage (BTN_START) */
+ 0x09, 0x0E, /* Usage (BTN_THUMBL) */
+ 0x09, 0x0F, /* Usage (BTN_THUMBR) */
+ 0x09, 0x0D, /* Usage (BTN_MODE) */
+ 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0x75, 0x01, /* Report Size (1) */
+ 0x95, 0x03, /* Report Count (3) */
+ 0x81, 0x01, /* Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */
+ 0x25, 0x07, /* Logical Maximum (7) */
+ 0x46, 0x3B, 0x01, /* Physical Maximum (315) */
+ 0x75, 0x04, /* Report Size (4) */
+ 0x95, 0x01, /* Report Count (1) */
+ 0x65, 0x14, /* Unit (System: English Rotation, Length: Centimeter) */
+ 0x09, 0x39, /* Usage (Hat switch) */
+ 0x81, 0x42, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State) */
+ 0x65, 0x00, /* Unit (None) */
+ 0x95, 0x01, /* Report Count (1) */
+ 0x81, 0x01, /* Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0x26, 0xFF, 0x00, /* Logical Maximum (255) */
+ 0x46, 0xFF, 0x00, /* Physical Maximum (255) */
+ 0x09, 0x30, /* Usage (X) */
+ 0x09, 0x31, /* Usage (Y) */
+ 0x09, 0x33, /* Usage (Rx) */
+ 0x09, 0x34, /* Usage (Ry) */
+ 0x75, 0x08, /* Report Size (8) */
+ 0x95, 0x04, /* Report Count (4) */
+ 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0x95, 0x0A, /* Report Count (10) */
+ 0x81, 0x01, /* Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */
+ 0x26, 0xFF, 0x00, /* Logical Maximum (255) */
+ 0x46, 0xFF, 0x00, /* Physical Maximum (255) */
+ 0x09, 0x32, /* Usage (Z) */
+ 0x09, 0x35, /* Usage (Rz) */
+ 0x95, 0x02, /* Report Count (2) */
+ 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0x95, 0x08, /* Report Count (8) */
+ 0x81, 0x01, /* Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0x06, 0x00, 0xFF, /* Usage Page (Vendor Defined 0xFF00) */
+ 0xB1, 0x02, /* Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) */
+ 0x0A, 0x21, 0x26, /* Usage (0x2621) */
+ 0x95, 0x08, /* Report Count (8) */
+ 0x91, 0x02, /* Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) */
+ 0x0A, 0x21, 0x26, /* Usage (0x2621) */
+ 0x95, 0x08, /* Report Count (8) */
+ 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
+ 0xC0, /* End Collection */
+};
+
+#define NUM_LEDS 4
+
+struct bigben_device {
+ struct hid_device *hid;
+ struct hid_report *report;
+ u8 led_state; /* LED1 = 1 .. LED4 = 8 */
+ u8 right_motor_on; /* right motor off/on 0/1 */
+ u8 left_motor_force; /* left motor force 0-255 */
+ struct led_classdev *leds[NUM_LEDS];
+ bool work_led;
+ bool work_ff;
+ struct work_struct worker;
+};
+
+
+static void bigben_worker(struct work_struct *work)
+{
+ struct bigben_device *bigben = container_of(work,
+ struct bigben_device, worker);
+ struct hid_field *report_field = bigben->report->field[0];
+
+ if (bigben->work_led) {
+ bigben->work_led = false;
+ report_field->value[0] = 0x01; /* 1 = led message */
+ report_field->value[1] = 0x08; /* reserved value, always 8 */
+ report_field->value[2] = bigben->led_state;
+ report_field->value[3] = 0x00; /* padding */
+ report_field->value[4] = 0x00; /* padding */
+ report_field->value[5] = 0x00; /* padding */
+ report_field->value[6] = 0x00; /* padding */
+ report_field->value[7] = 0x00; /* padding */
+ hid_hw_request(bigben->hid, bigben->report, HID_REQ_SET_REPORT);
+ }
+
+ if (bigben->work_ff) {
+ bigben->work_ff = false;
+ report_field->value[0] = 0x02; /* 2 = rumble effect message */
+ report_field->value[1] = 0x08; /* reserved value, always 8 */
+ report_field->value[2] = bigben->right_motor_on;
+ report_field->value[3] = bigben->left_motor_force;
+ report_field->value[4] = 0xff; /* duration 0-254 (255 = nonstop) */
+ report_field->value[5] = 0x00; /* padding */
+ report_field->value[6] = 0x00; /* padding */
+ report_field->value[7] = 0x00; /* padding */
+ hid_hw_request(bigben->hid, bigben->report, HID_REQ_SET_REPORT);
+ }
+}
+
+static int hid_bigben_play_effect(struct input_dev *dev, void *data,
+ struct ff_effect *effect)
+{
+ struct bigben_device *bigben = data;
+ u8 right_motor_on;
+ u8 left_motor_force;
+
+ if (effect->type != FF_RUMBLE)
+ return 0;
+
+ right_motor_on = effect->u.rumble.weak_magnitude ? 1 : 0;
+ left_motor_force = effect->u.rumble.strong_magnitude / 256;
+
+ if (right_motor_on != bigben->right_motor_on ||
+ left_motor_force != bigben->left_motor_force) {
+ bigben->right_motor_on = right_motor_on;
+ bigben->left_motor_force = left_motor_force;
+ bigben->work_ff = true;
+ schedule_work(&bigben->worker);
+ }
+
+ return 0;
+}
+
+static void bigben_set_led(struct led_classdev *led,
+ enum led_brightness value)
+{
+ struct device *dev = led->dev->parent;
+ struct hid_device *hid = to_hid_device(dev);
+ struct bigben_device *bigben = hid_get_drvdata(hid);
+ int n;
+ bool work;
+
+ if (!bigben) {
+ hid_err(hid, "no device data\n");
+ return;
+ }
+
+ for (n = 0; n < NUM_LEDS; n++) {
+ if (led == bigben->leds[n]) {
+ if (value == LED_OFF) {
+ work = (bigben->led_state & BIT(n));
+ bigben->led_state &= ~BIT(n);
+ } else {
+ work = !(bigben->led_state & BIT(n));
+ bigben->led_state |= BIT(n);
+ }
+
+ if (work) {
+ bigben->work_led = true;
+ schedule_work(&bigben->worker);
+ }
+ return;
+ }
+ }
+}
+
+static enum led_brightness bigben_get_led(struct led_classdev *led)
+{
+ struct device *dev = led->dev->parent;
+ struct hid_device *hid = to_hid_device(dev);
+ struct bigben_device *bigben = hid_get_drvdata(hid);
+ int n;
+
+ if (!bigben) {
+ hid_err(hid, "no device data\n");
+ return LED_OFF;
+ }
+
+ for (n = 0; n < NUM_LEDS; n++) {
+ if (led == bigben->leds[n])
+ return (bigben->led_state & BIT(n)) ? LED_ON : LED_OFF;
+ }
+
+ return LED_OFF;
+}
+
+static void bigben_remove(struct hid_device *hid)
+{
+ struct bigben_device *bigben = hid_get_drvdata(hid);
+
+ cancel_work_sync(&bigben->worker);
+ hid_hw_close(hid);
+ hid_hw_stop(hid);
+}
+
+static int bigben_probe(struct hid_device *hid,
+ const struct hid_device_id *id)
+{
+ struct bigben_device *bigben;
+ struct hid_input *hidinput;
+ struct list_head *report_list;
+ struct led_classdev *led;
+ char *name;
+ size_t name_sz;
+ int n, error;
+
+ bigben = devm_kzalloc(&hid->dev, sizeof(*bigben), GFP_KERNEL);
+ if (!bigben)
+ return -ENOMEM;
+ hid_set_drvdata(hid, bigben);
+ bigben->hid = hid;
+
+ error = hid_parse(hid);
+ if (error) {
+ hid_err(hid, "parse failed\n");
+ return error;
+ }
+
+ error = hid_hw_start(hid, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
+ if (error) {
+ hid_err(hid, "hw start failed\n");
+ return error;
+ }
+
+ report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+ bigben->report = list_entry(report_list->next,
+ struct hid_report, list);
+
+ hidinput = list_first_entry(&hid->inputs, struct hid_input, list);
+ set_bit(FF_RUMBLE, hidinput->input->ffbit);
+
+ INIT_WORK(&bigben->worker, bigben_worker);
+
+ error = input_ff_create_memless(hidinput->input, bigben,
+ hid_bigben_play_effect);
+ if (error)
+ return error;
+
+ name_sz = strlen(dev_name(&hid->dev)) + strlen(":red:bigben#") + 1;
+
+ for (n = 0; n < NUM_LEDS; n++) {
+ led = devm_kzalloc(
+ &hid->dev,
+ sizeof(struct led_classdev) + name_sz,
+ GFP_KERNEL
+ );
+ if (!led)
+ return -ENOMEM;
+ name = (void *)(&led[1]);
+ snprintf(name, name_sz,
+ "%s:red:bigben%d",
+ dev_name(&hid->dev), n + 1
+ );
+ led->name = name;
+ led->brightness = (n == 0) ? LED_ON : LED_OFF;
+ led->max_brightness = 1;
+ led->brightness_get = bigben_get_led;
+ led->brightness_set = bigben_set_led;
+ bigben->leds[n] = led;
+ error = devm_led_classdev_register(&hid->dev, led);
+ if (error)
+ return error;
+ }
+
+ /* initial state: LED1 is on, no rumble effect */
+ bigben->led_state = BIT(0);
+ bigben->right_motor_on = 0;
+ bigben->left_motor_force = 0;
+ bigben->work_led = true;
+ bigben->work_ff = true;
+ schedule_work(&bigben->worker);
+
+ hid_info(hid, "LED and force feedback support for BigBen gamepad\n");
+
+ return 0;
+}
+
+static __u8 *bigben_report_fixup(struct hid_device *hid, __u8 *rdesc,
+ unsigned int *rsize)
+{
+ if (*rsize == PID0902_RDESC_ORIG_SIZE) {
+ rdesc = pid0902_rdesc_fixed;
+ *rsize = sizeof(pid0902_rdesc_fixed);
+ } else
+ hid_warn(hid, "unexpected rdesc, please submit for review\n");
+ return rdesc;
+}
+
+static const struct hid_device_id bigben_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_BIGBEN, USB_DEVICE_ID_BIGBEN_PS3OFMINIPAD) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, bigben_devices);
+
+static struct hid_driver bigben_driver = {
+ .name = "bigben",
+ .id_table = bigben_devices,
+ .probe = bigben_probe,
+ .report_fixup = bigben_report_fixup,
+ .remove = bigben_remove,
+};
+module_hid_driver(bigben_driver);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 44564f61e9cc..5bec9244c45b 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -406,7 +406,7 @@ static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
case HID_GLOBAL_ITEM_TAG_REPORT_SIZE:
parser->global.report_size = item_udata(item);
- if (parser->global.report_size > 128) {
+ if (parser->global.report_size > 256) {
hid_err(parser->device, "invalid report_size %d\n",
parser->global.report_size);
return -1;
diff --git a/drivers/hid/hid-cougar.c b/drivers/hid/hid-cougar.c
index ad2e87de7dc5..3f0916b64c60 100644
--- a/drivers/hid/hid-cougar.c
+++ b/drivers/hid/hid-cougar.c
@@ -7,6 +7,7 @@
#include <linux/hid.h>
#include <linux/module.h>
+#include <linux/printk.h>
#include "hid-ids.h"
@@ -15,11 +16,9 @@ MODULE_DESCRIPTION("Cougar 500k Gaming Keyboard");
MODULE_LICENSE("GPL");
MODULE_INFO(key_mappings, "G1-G6 are mapped to F13-F18");
-static int cougar_g6_is_space = 1;
-module_param_named(g6_is_space, cougar_g6_is_space, int, 0600);
+static bool g6_is_space = true;
MODULE_PARM_DESC(g6_is_space,
- "If set, G6 programmable key sends SPACE instead of F18 (0=off, 1=on) (default=1)");
-
+ "If true, G6 programmable key sends SPACE instead of F18 (default=true)");
#define COUGAR_VENDOR_USAGE 0xff00ff00
@@ -82,20 +81,23 @@ struct cougar {
static LIST_HEAD(cougar_udev_list);
static DEFINE_MUTEX(cougar_udev_list_lock);
-static void cougar_fix_g6_mapping(struct hid_device *hdev)
+/**
+ * cougar_fix_g6_mapping - configure the mapping for key G6/Spacebar
+ */
+static void cougar_fix_g6_mapping(void)
{
int i;
for (i = 0; cougar_mapping[i][0]; i++) {
if (cougar_mapping[i][0] == COUGAR_KEY_G6) {
cougar_mapping[i][1] =
- cougar_g6_is_space ? KEY_SPACE : KEY_F18;
- hid_info(hdev, "G6 mapped to %s\n",
- cougar_g6_is_space ? "space" : "F18");
+ g6_is_space ? KEY_SPACE : KEY_F18;
+ pr_info("cougar: G6 mapped to %s\n",
+ g6_is_space ? "space" : "F18");
return;
}
}
- hid_warn(hdev, "no mapping defined for G6/spacebar");
+ pr_warn("cougar: no mappings defined for G6/spacebar");
}
/*
@@ -154,7 +156,8 @@ static void cougar_remove_shared_data(void *resource)
* Bind the device group's shared data to this cougar struct.
* If no shared data exists for this group, create and initialize it.
*/
-static int cougar_bind_shared_data(struct hid_device *hdev, struct cougar *cougar)
+static int cougar_bind_shared_data(struct hid_device *hdev,
+ struct cougar *cougar)
{
struct cougar_shared *shared;
int error = 0;
@@ -228,7 +231,6 @@ static int cougar_probe(struct hid_device *hdev,
* to it.
*/
if (hdev->collection->usage == HID_GD_KEYBOARD) {
- cougar_fix_g6_mapping(hdev);
list_for_each_entry_safe(hidinput, next, &hdev->inputs, list) {
if (hidinput->registered && hidinput->input != NULL) {
cougar->shared->input = hidinput->input;
@@ -237,6 +239,8 @@ static int cougar_probe(struct hid_device *hdev,
}
}
} else if (hdev->collection->usage == COUGAR_VENDOR_USAGE) {
+ /* Preinit the mapping table */
+ cougar_fix_g6_mapping();
error = hid_hw_open(hdev);
if (error)
goto fail_stop_and_cleanup;
@@ -257,26 +261,32 @@ static int cougar_raw_event(struct hid_device *hdev, struct hid_report *report,
u8 *data, int size)
{
struct cougar *cougar;
+ struct cougar_shared *shared;
unsigned char code, action;
int i;
cougar = hid_get_drvdata(hdev);
- if (!cougar->special_intf || !cougar->shared ||
- !cougar->shared->input || !cougar->shared->enabled)
+ shared = cougar->shared;
+ if (!cougar->special_intf || !shared)
return 0;
+ if (!shared->enabled || !shared->input)
+ return -EPERM;
+
code = data[COUGAR_FIELD_CODE];
action = data[COUGAR_FIELD_ACTION];
for (i = 0; cougar_mapping[i][0]; i++) {
if (code == cougar_mapping[i][0]) {
- input_event(cougar->shared->input, EV_KEY,
+ input_event(shared->input, EV_KEY,
cougar_mapping[i][1], action);
- input_sync(cougar->shared->input);
- return 0;
+ input_sync(shared->input);
+ return -EPERM;
}
}
- hid_warn(hdev, "unmapped special key code %x: ignoring\n", code);
- return 0;
+ /* Avoid warnings on the same unmapped key twice */
+ if (action != 0)
+ hid_warn(hdev, "unmapped special key code %0x: ignoring\n", code);
+ return -EPERM;
}
static void cougar_remove(struct hid_device *hdev)
@@ -293,6 +303,26 @@ static void cougar_remove(struct hid_device *hdev)
hid_hw_stop(hdev);
}
+static int cougar_param_set_g6_is_space(const char *val,
+ const struct kernel_param *kp)
+{
+ int ret;
+
+ ret = param_set_bool(val, kp);
+ if (ret)
+ return ret;
+
+ cougar_fix_g6_mapping();
+
+ return 0;
+}
+
+static const struct kernel_param_ops cougar_g6_is_space_ops = {
+ .set = cougar_param_set_g6_is_space,
+ .get = param_get_bool,
+};
+module_param_cb(g6_is_space, &cougar_g6_is_space_ops, &g6_is_space, 0644);
+
static struct hid_device_id cougar_id_table[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_SOLID_YEAR,
USB_DEVICE_ID_COUGAR_500K_GAMING_KEYBOARD) },
diff --git a/drivers/hid/hid-elan.c b/drivers/hid/hid-elan.c
index 07e26c3567eb..0bfd6d1b44c1 100644
--- a/drivers/hid/hid-elan.c
+++ b/drivers/hid/hid-elan.c
@@ -497,7 +497,7 @@ static int elan_probe(struct hid_device *hdev, const struct hid_device_id *id)
return 0;
if (!drvdata->input) {
- hid_err(hdev, "Input device is not registred\n");
+ hid_err(hdev, "Input device is not registered\n");
ret = -ENAVAIL;
goto err;
}
diff --git a/drivers/hid/hid-google-hammer.c b/drivers/hid/hid-google-hammer.c
index 6bf4da7ad63a..ee5e0bdcf078 100644
--- a/drivers/hid/hid-google-hammer.c
+++ b/drivers/hid/hid-google-hammer.c
@@ -13,16 +13,268 @@
* any later version.
*/
+#include <linux/acpi.h>
#include <linux/hid.h>
#include <linux/leds.h>
+#include <linux/mfd/cros_ec.h>
+#include <linux/mfd/cros_ec_commands.h>
#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_wakeup.h>
+#include <asm/unaligned.h>
#include "hid-ids.h"
-#define MAX_BRIGHTNESS 100
+/*
+ * C(hrome)B(ase)A(ttached)S(witch) - switch exported by Chrome EC and reporting
+ * state of the "Whiskers" base - attached or detached. Whiskers USB device also
+ * reports position of the keyboard - folded or not. Combining base state and
+ * position allows us to generate proper "Tablet mode" events.
+ */
+struct cbas_ec {
+ struct device *dev; /* The platform device (EC) */
+ struct input_dev *input;
+ bool base_present;
+ struct notifier_block notifier;
+};
-/* HID usage for keyboard backlight (Alphanumeric display brightness) */
-#define HID_AD_BRIGHTNESS 0x00140046
+static struct cbas_ec cbas_ec;
+static DEFINE_SPINLOCK(cbas_ec_lock);
+static DEFINE_MUTEX(cbas_ec_reglock);
+
+static bool cbas_parse_base_state(const void *data)
+{
+ u32 switches = get_unaligned_le32(data);
+
+ return !!(switches & BIT(EC_MKBP_BASE_ATTACHED));
+}
+
+static int cbas_ec_query_base(struct cros_ec_device *ec_dev, bool get_state,
+ bool *state)
+{
+ struct ec_params_mkbp_info *params;
+ struct cros_ec_command *msg;
+ int ret;
+
+ msg = kzalloc(sizeof(*msg) + max(sizeof(u32), sizeof(*params)),
+ GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ msg->command = EC_CMD_MKBP_INFO;
+ msg->version = 1;
+ msg->outsize = sizeof(*params);
+ msg->insize = sizeof(u32);
+ params = (struct ec_params_mkbp_info *)msg->data;
+ params->info_type = get_state ?
+ EC_MKBP_INFO_CURRENT : EC_MKBP_INFO_SUPPORTED;
+ params->event_type = EC_MKBP_EVENT_SWITCH;
+
+ ret = cros_ec_cmd_xfer_status(ec_dev, msg);
+ if (ret >= 0) {
+ if (ret != sizeof(u32)) {
+ dev_warn(ec_dev->dev, "wrong result size: %d != %zu\n",
+ ret, sizeof(u32));
+ ret = -EPROTO;
+ } else {
+ *state = cbas_parse_base_state(msg->data);
+ ret = 0;
+ }
+ }
+
+ kfree(msg);
+
+ return ret;
+}
+
+static int cbas_ec_notify(struct notifier_block *nb,
+ unsigned long queued_during_suspend,
+ void *_notify)
+{
+ struct cros_ec_device *ec = _notify;
+ unsigned long flags;
+ bool base_present;
+
+ if (ec->event_data.event_type == EC_MKBP_EVENT_SWITCH) {
+ base_present = cbas_parse_base_state(
+ &ec->event_data.data.switches);
+ dev_dbg(cbas_ec.dev,
+ "%s: base: %d\n", __func__, base_present);
+
+ if (device_may_wakeup(cbas_ec.dev) ||
+ !queued_during_suspend) {
+
+ pm_wakeup_event(cbas_ec.dev, 0);
+
+ spin_lock_irqsave(&cbas_ec_lock, flags);
+
+ /*
+ * While input layer dedupes the events, we do not want
+ * to disrupt the state reported by the base by
+ * overriding it with state reported by the LID. Only
+ * report changes, as we assume that on attach the base
+ * is not folded.
+ */
+ if (base_present != cbas_ec.base_present) {
+ input_report_switch(cbas_ec.input,
+ SW_TABLET_MODE,
+ !base_present);
+ input_sync(cbas_ec.input);
+ cbas_ec.base_present = base_present;
+ }
+
+ spin_unlock_irqrestore(&cbas_ec_lock, flags);
+ }
+ }
+
+ return NOTIFY_OK;
+}
+
+static __maybe_unused int cbas_ec_resume(struct device *dev)
+{
+ struct cros_ec_device *ec = dev_get_drvdata(dev->parent);
+ bool base_present;
+ int error;
+
+ error = cbas_ec_query_base(ec, true, &base_present);
+ if (error) {
+ dev_warn(dev, "failed to fetch base state on resume: %d\n",
+ error);
+ } else {
+ spin_lock_irq(&cbas_ec_lock);
+
+ cbas_ec.base_present = base_present;
+
+ /*
+ * Only report if base is disconnected. If base is connected,
+ * it will resend its state on resume, and we'll update it
+ * in hammer_event().
+ */
+ if (!cbas_ec.base_present) {
+ input_report_switch(cbas_ec.input, SW_TABLET_MODE, 1);
+ input_sync(cbas_ec.input);
+ }
+
+ spin_unlock_irq(&cbas_ec_lock);
+ }
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(cbas_ec_pm_ops, NULL, cbas_ec_resume);
+
+static void cbas_ec_set_input(struct input_dev *input)
+{
+ /* Take the lock so hammer_event() does not race with us here */
+ spin_lock_irq(&cbas_ec_lock);
+ cbas_ec.input = input;
+ spin_unlock_irq(&cbas_ec_lock);
+}
+
+static int __cbas_ec_probe(struct platform_device *pdev)
+{
+ struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent);
+ struct input_dev *input;
+ bool base_supported;
+ int error;
+
+ error = cbas_ec_query_base(ec, false, &base_supported);
+ if (error)
+ return error;
+
+ if (!base_supported)
+ return -ENXIO;
+
+ input = devm_input_allocate_device(&pdev->dev);
+ if (!input)
+ return -ENOMEM;
+
+ input->name = "Whiskers Tablet Mode Switch";
+ input->id.bustype = BUS_HOST;
+
+ input_set_capability(input, EV_SW, SW_TABLET_MODE);
+
+ error = input_register_device(input);
+ if (error) {
+ dev_err(&pdev->dev, "cannot register input device: %d\n",
+ error);
+ return error;
+ }
+
+ /* Seed the state */
+ error = cbas_ec_query_base(ec, true, &cbas_ec.base_present);
+ if (error) {
+ dev_err(&pdev->dev, "cannot query base state: %d\n", error);
+ return error;
+ }
+
+ input_report_switch(input, SW_TABLET_MODE, !cbas_ec.base_present);
+
+ cbas_ec_set_input(input);
+
+ cbas_ec.dev = &pdev->dev;
+ cbas_ec.notifier.notifier_call = cbas_ec_notify;
+ error = blocking_notifier_chain_register(&ec->event_notifier,
+ &cbas_ec.notifier);
+ if (error) {
+ dev_err(&pdev->dev, "cannot register notifier: %d\n", error);
+ cbas_ec_set_input(NULL);
+ return error;
+ }
+
+ device_init_wakeup(&pdev->dev, true);
+ return 0;
+}
+
+static int cbas_ec_probe(struct platform_device *pdev)
+{
+ int retval;
+
+ mutex_lock(&cbas_ec_reglock);
+
+ if (cbas_ec.input) {
+ retval = -EBUSY;
+ goto out;
+ }
+
+ retval = __cbas_ec_probe(pdev);
+
+out:
+ mutex_unlock(&cbas_ec_reglock);
+ return retval;
+}
+
+static int cbas_ec_remove(struct platform_device *pdev)
+{
+ struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent);
+
+ mutex_lock(&cbas_ec_reglock);
+
+ blocking_notifier_chain_unregister(&ec->event_notifier,
+ &cbas_ec.notifier);
+ cbas_ec_set_input(NULL);
+
+ mutex_unlock(&cbas_ec_reglock);
+ return 0;
+}
+
+static const struct acpi_device_id cbas_ec_acpi_ids[] = {
+ { "GOOG000B", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, cbas_ec_acpi_ids);
+
+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),
+ .pm = &cbas_ec_pm_ops,
+ },
+};
+
+#define MAX_BRIGHTNESS 100
struct hammer_kbd_leds {
struct led_classdev cdev;
@@ -90,33 +342,130 @@ static int hammer_register_leds(struct hid_device *hdev)
return devm_led_classdev_register(&hdev->dev, &kbd_backlight->cdev);
}
-static int hammer_input_configured(struct hid_device *hdev,
- struct hid_input *hi)
+#define HID_UP_GOOGLEVENDOR 0xffd10000
+#define HID_VD_KBD_FOLDED 0x00000019
+#define WHISKERS_KBD_FOLDED (HID_UP_GOOGLEVENDOR | HID_VD_KBD_FOLDED)
+
+/* HID usage for keyboard backlight (Alphanumeric display brightness) */
+#define HID_AD_BRIGHTNESS 0x00140046
+
+static int hammer_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field,
+ struct hid_usage *usage,
+ unsigned long **bit, int *max)
{
- struct list_head *report_list =
- &hdev->report_enum[HID_OUTPUT_REPORT].report_list;
+ if (hdev->product == USB_DEVICE_ID_GOOGLE_WHISKERS &&
+ usage->hid == WHISKERS_KBD_FOLDED) {
+ /*
+ * We do not want to have this usage mapped as it will get
+ * mixed in with "base attached" signal and delivered over
+ * separate input device for tablet switch mode.
+ */
+ return -1;
+ }
+
+ return 0;
+}
+
+static int hammer_event(struct hid_device *hid, struct hid_field *field,
+ struct hid_usage *usage, __s32 value)
+{
+ unsigned long flags;
+
+ if (hid->product == USB_DEVICE_ID_GOOGLE_WHISKERS &&
+ usage->hid == WHISKERS_KBD_FOLDED) {
+ spin_lock_irqsave(&cbas_ec_lock, flags);
+
+ hid_dbg(hid, "%s: base: %d, folded: %d\n", __func__,
+ cbas_ec.base_present, value);
+
+ /*
+ * We should not get event if base is detached, but in case
+ * we happen to service HID and EC notifications out of order
+ * let's still check the "base present" flag.
+ */
+ if (cbas_ec.input && cbas_ec.base_present) {
+ input_report_switch(cbas_ec.input,
+ SW_TABLET_MODE, value);
+ input_sync(cbas_ec.input);
+ }
+
+ spin_unlock_irqrestore(&cbas_ec_lock, flags);
+ return 1; /* We handled this event */
+ }
+
+ return 0;
+}
+
+static bool hammer_is_keyboard_interface(struct hid_device *hdev)
+{
+ struct hid_report_enum *re = &hdev->report_enum[HID_INPUT_REPORT];
struct hid_report *report;
- if (list_empty(report_list))
- return 0;
+ list_for_each_entry(report, &re->report_list, list)
+ if (report->application == HID_GD_KEYBOARD)
+ return true;
- report = list_first_entry(report_list, struct hid_report, list);
+ return false;
+}
+
+static bool hammer_has_backlight_control(struct hid_device *hdev)
+{
+ struct hid_report_enum *re = &hdev->report_enum[HID_OUTPUT_REPORT];
+ struct hid_report *report;
+ int i, j;
- if (report->maxfield == 1 &&
- report->field[0]->application == HID_GD_KEYBOARD &&
- report->field[0]->maxusage == 1 &&
- report->field[0]->usage[0].hid == HID_AD_BRIGHTNESS) {
- int err = hammer_register_leds(hdev);
+ list_for_each_entry(report, &re->report_list, list) {
+ if (report->application != HID_GD_KEYBOARD)
+ continue;
- if (err)
+ for (i = 0; i < report->maxfield; i++) {
+ struct hid_field *field = report->field[i];
+
+ for (j = 0; j < field->maxusage; j++)
+ if (field->usage[j].hid == HID_AD_BRIGHTNESS)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static int hammer_probe(struct hid_device *hdev,
+ const struct hid_device_id *id)
+{
+ int error;
+
+ /*
+ * We always want to poll for, and handle tablet mode events from
+ * Whiskers, even when nobody has opened the input device. This also
+ * prevents the hid core from dropping early tablet mode events from
+ * the device.
+ */
+ if (hdev->product == USB_DEVICE_ID_GOOGLE_WHISKERS &&
+ hammer_is_keyboard_interface(hdev))
+ hdev->quirks |= HID_QUIRK_ALWAYS_POLL;
+
+ error = hid_parse(hdev);
+ if (error)
+ return error;
+
+ error = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ if (error)
+ return error;
+
+ if (hammer_has_backlight_control(hdev)) {
+ error = hammer_register_leds(hdev);
+ if (error)
hid_warn(hdev,
"Failed to register keyboard backlight: %d\n",
- err);
+ error);
}
return 0;
}
+
static const struct hid_device_id hammer_devices[] = {
{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_HAMMER) },
@@ -133,8 +482,34 @@ MODULE_DEVICE_TABLE(hid, hammer_devices);
static struct hid_driver hammer_driver = {
.name = "hammer",
.id_table = hammer_devices,
- .input_configured = hammer_input_configured,
+ .probe = hammer_probe,
+ .input_mapping = hammer_input_mapping,
+ .event = hammer_event,
};
-module_hid_driver(hammer_driver);
+
+static int __init hammer_init(void)
+{
+ int error;
+
+ error = platform_driver_register(&cbas_ec_driver);
+ if (error)
+ return error;
+
+ error = hid_register_driver(&hammer_driver);
+ if (error) {
+ platform_driver_unregister(&cbas_ec_driver);
+ return error;
+ }
+
+ return 0;
+}
+module_init(hammer_init);
+
+static void __exit hammer_exit(void)
+{
+ hid_unregister_driver(&hammer_driver);
+ platform_driver_unregister(&cbas_ec_driver);
+}
+module_exit(hammer_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 5146ee029db4..c0d668944dbe 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -92,6 +92,7 @@
#define USB_DEVICE_ID_APPLE_MIGHTYMOUSE 0x0304
#define USB_DEVICE_ID_APPLE_MAGICMOUSE 0x030d
#define USB_DEVICE_ID_APPLE_MAGICTRACKPAD 0x030e
+#define USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 0x0265
#define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI 0x020e
#define USB_DEVICE_ID_APPLE_FOUNTAIN_ISO 0x020f
#define USB_DEVICE_ID_APPLE_GEYSER_ANSI 0x0214
@@ -229,6 +230,9 @@
#define USB_VENDOR_ID_BETOP_2185V2PC 0x8380
#define USB_VENDOR_ID_BETOP_2185V2BFM 0x20bc
+#define USB_VENDOR_ID_BIGBEN 0x146b
+#define USB_DEVICE_ID_BIGBEN_PS3OFMINIPAD 0x0902
+
#define USB_VENDOR_ID_BTC 0x046e
#define USB_DEVICE_ID_BTC_EMPREX_REMOTE 0x5578
#define USB_DEVICE_ID_BTC_EMPREX_REMOTE_2 0x5577
@@ -342,6 +346,7 @@
#define USB_DEVICE_ID_DMI_ENC 0x5fab
#define USB_VENDOR_ID_DRAGONRISE 0x0079
+#define USB_DEVICE_ID_REDRAGON_SEYMUR2 0x0006
#define USB_DEVICE_ID_DRAGONRISE_WIIU 0x1800
#define USB_DEVICE_ID_DRAGONRISE_PS3 0x1801
#define USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR 0x1803
@@ -799,6 +804,7 @@
#define USB_DEVICE_ID_MS_TOUCH_COVER_2 0x07a7
#define USB_DEVICE_ID_MS_TYPE_COVER_2 0x07a9
#define USB_DEVICE_ID_MS_POWER_COVER 0x07da
+#define USB_DEVICE_ID_MS_XBOX_ONE_S_CONTROLLER 0x02fd
#define USB_VENDOR_ID_MOJO 0x8282
#define USB_DEVICE_ID_RETRO_ADAPTER 0x3201
@@ -921,6 +927,9 @@
#define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3003 0x3003
#define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008 0x3008
+#define I2C_VENDOR_ID_RAYDIUM 0x2386
+#define I2C_PRODUCT_ID_RAYDIUM_4B33 0x4b33
+
#define USB_VENDOR_ID_RAZER 0x1532
#define USB_DEVICE_ID_RAZER_BLADE_14 0x011D
@@ -976,7 +985,6 @@
#define USB_DEVICE_ID_SIS817_TOUCH 0x0817
#define USB_DEVICE_ID_SIS_TS 0x1013
#define USB_DEVICE_ID_SIS1030_TOUCH 0x1030
-#define USB_DEVICE_ID_SIS10FB_TOUCH 0x10fb
#define USB_VENDOR_ID_SKYCABLE 0x1223
#define USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER 0x3F07
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index a481eaf39e88..a2f74e6adc70 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -758,6 +758,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
break;
case HID_UP_DIGITIZER:
+ if ((field->application & 0xff) == 0x01) /* Digitizer */
+ __set_bit(INPUT_PROP_POINTER, input->propbit);
+ else if ((field->application & 0xff) == 0x02) /* Pen */
+ __set_bit(INPUT_PROP_DIRECT, input->propbit);
+
switch (usage->hid & 0xff) {
case 0x00: /* Undefined */
goto ignore;
@@ -1516,6 +1521,7 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid,
struct hid_input *hidinput = kzalloc(sizeof(*hidinput), GFP_KERNEL);
struct input_dev *input_dev = input_allocate_device();
const char *suffix = NULL;
+ size_t suffix_len, name_len;
if (!hidinput || !input_dev)
goto fail;
@@ -1559,10 +1565,15 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid,
}
if (suffix) {
- hidinput->name = kasprintf(GFP_KERNEL, "%s %s",
- hid->name, suffix);
- if (!hidinput->name)
- goto fail;
+ name_len = strlen(hid->name);
+ suffix_len = strlen(suffix);
+ if ((name_len < suffix_len) ||
+ strcmp(hid->name + name_len - suffix_len, suffix)) {
+ hidinput->name = kasprintf(GFP_KERNEL, "%s %s",
+ hid->name, suffix);
+ if (!hidinput->name)
+ goto fail;
+ }
}
input_set_drvdata(input_dev, hid);
@@ -1827,3 +1838,47 @@ void hidinput_disconnect(struct hid_device *hid)
}
EXPORT_SYMBOL_GPL(hidinput_disconnect);
+/**
+ * hid_scroll_counter_handle_scroll() - Send high- and low-resolution scroll
+ * events given a high-resolution wheel
+ * movement.
+ * @counter: a hid_scroll_counter struct describing the wheel.
+ * @hi_res_value: the movement of the wheel, in the mouse's high-resolution
+ * units.
+ *
+ * Given a high-resolution movement, this function converts the movement into
+ * microns and emits high-resolution scroll events for the input device. It also
+ * uses the multiplier from &struct hid_scroll_counter to emit low-resolution
+ * scroll events when appropriate for backwards-compatibility with userspace
+ * input libraries.
+ */
+void hid_scroll_counter_handle_scroll(struct hid_scroll_counter *counter,
+ int hi_res_value)
+{
+ int low_res_value, remainder, multiplier;
+
+ input_report_rel(counter->dev, REL_WHEEL_HI_RES,
+ hi_res_value * counter->microns_per_hi_res_unit);
+
+ /*
+ * Update the low-res remainder with the high-res value,
+ * but reset if the direction has changed.
+ */
+ remainder = counter->remainder;
+ if ((remainder ^ hi_res_value) < 0)
+ remainder = 0;
+ remainder += hi_res_value;
+
+ /*
+ * Then just use the resolution multiplier to see if
+ * we should send a low-res (aka regular wheel) event.
+ */
+ multiplier = counter->resolution_multiplier;
+ low_res_value = remainder / multiplier;
+ remainder -= low_res_value * multiplier;
+ counter->remainder = remainder;
+
+ if (low_res_value)
+ input_report_rel(counter->dev, REL_WHEEL, low_res_value);
+}
+EXPORT_SYMBOL_GPL(hid_scroll_counter_handle_scroll);
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
index 19cc980eebce..f01280898b24 100644
--- a/drivers/hid/hid-logitech-hidpp.c
+++ b/drivers/hid/hid-logitech-hidpp.c
@@ -64,6 +64,14 @@ MODULE_PARM_DESC(disable_tap_to_click,
#define HIDPP_QUIRK_NO_HIDINPUT BIT(23)
#define HIDPP_QUIRK_FORCE_OUTPUT_REPORTS BIT(24)
#define HIDPP_QUIRK_UNIFYING BIT(25)
+#define HIDPP_QUIRK_HI_RES_SCROLL_1P0 BIT(26)
+#define HIDPP_QUIRK_HI_RES_SCROLL_X2120 BIT(27)
+#define HIDPP_QUIRK_HI_RES_SCROLL_X2121 BIT(28)
+
+/* Convenience constant to check for any high-res support. */
+#define HIDPP_QUIRK_HI_RES_SCROLL (HIDPP_QUIRK_HI_RES_SCROLL_1P0 | \
+ HIDPP_QUIRK_HI_RES_SCROLL_X2120 | \
+ HIDPP_QUIRK_HI_RES_SCROLL_X2121)
#define HIDPP_QUIRK_DELAYED_INIT HIDPP_QUIRK_NO_HIDINPUT
@@ -149,6 +157,7 @@ struct hidpp_device {
unsigned long capabilities;
struct hidpp_battery battery;
+ struct hid_scroll_counter vertical_wheel_counter;
};
/* HID++ 1.0 error codes */
@@ -400,32 +409,53 @@ static void hidpp_prefix_name(char **name, int name_length)
#define HIDPP_SET_LONG_REGISTER 0x82
#define HIDPP_GET_LONG_REGISTER 0x83
-#define HIDPP_REG_GENERAL 0x00
-
-static int hidpp10_enable_battery_reporting(struct hidpp_device *hidpp_dev)
+/**
+ * hidpp10_set_register_bit() - Sets a single bit in a HID++ 1.0 register.
+ * @hidpp_dev: the device to set the register on.
+ * @register_address: the address of the register to modify.
+ * @byte: the byte of the register to modify. Should be less than 3.
+ * Return: 0 if successful, otherwise a negative error code.
+ */
+static int hidpp10_set_register_bit(struct hidpp_device *hidpp_dev,
+ u8 register_address, u8 byte, u8 bit)
{
struct hidpp_report response;
int ret;
u8 params[3] = { 0 };
ret = hidpp_send_rap_command_sync(hidpp_dev,
- REPORT_ID_HIDPP_SHORT,
- HIDPP_GET_REGISTER,
- HIDPP_REG_GENERAL,
- NULL, 0, &response);
+ REPORT_ID_HIDPP_SHORT,
+ HIDPP_GET_REGISTER,
+ register_address,
+ NULL, 0, &response);
if (ret)
return ret;
memcpy(params, response.rap.params, 3);
- /* Set the battery bit */
- params[0] |= BIT(4);
+ params[byte] |= BIT(bit);
return hidpp_send_rap_command_sync(hidpp_dev,
- REPORT_ID_HIDPP_SHORT,
- HIDPP_SET_REGISTER,
- HIDPP_REG_GENERAL,
- params, 3, &response);
+ REPORT_ID_HIDPP_SHORT,
+ HIDPP_SET_REGISTER,
+ register_address,
+ params, 3, &response);
+}
+
+
+#define HIDPP_REG_GENERAL 0x00
+
+static int hidpp10_enable_battery_reporting(struct hidpp_device *hidpp_dev)
+{
+ return hidpp10_set_register_bit(hidpp_dev, HIDPP_REG_GENERAL, 0, 4);
+}
+
+#define HIDPP_REG_FEATURES 0x01
+
+/* On HID++ 1.0 devices, high-res scroll was called "scrolling acceleration". */
+static int hidpp10_enable_scrolling_acceleration(struct hidpp_device *hidpp_dev)
+{
+ return hidpp10_set_register_bit(hidpp_dev, HIDPP_REG_FEATURES, 0, 6);
}
#define HIDPP_REG_BATTERY_STATUS 0x07
@@ -1137,6 +1167,100 @@ static int hidpp_battery_get_property(struct power_supply *psy,
}
/* -------------------------------------------------------------------------- */
+/* 0x2120: Hi-resolution scrolling */
+/* -------------------------------------------------------------------------- */
+
+#define HIDPP_PAGE_HI_RESOLUTION_SCROLLING 0x2120
+
+#define CMD_HI_RESOLUTION_SCROLLING_SET_HIGHRES_SCROLLING_MODE 0x10
+
+static int hidpp_hrs_set_highres_scrolling_mode(struct hidpp_device *hidpp,
+ bool enabled, u8 *multiplier)
+{
+ u8 feature_index;
+ u8 feature_type;
+ int ret;
+ u8 params[1];
+ struct hidpp_report response;
+
+ ret = hidpp_root_get_feature(hidpp,
+ HIDPP_PAGE_HI_RESOLUTION_SCROLLING,
+ &feature_index,
+ &feature_type);
+ if (ret)
+ return ret;
+
+ params[0] = enabled ? BIT(0) : 0;
+ ret = hidpp_send_fap_command_sync(hidpp, feature_index,
+ CMD_HI_RESOLUTION_SCROLLING_SET_HIGHRES_SCROLLING_MODE,
+ params, sizeof(params), &response);
+ if (ret)
+ return ret;
+ *multiplier = response.fap.params[1];
+ return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+/* 0x2121: HiRes Wheel */
+/* -------------------------------------------------------------------------- */
+
+#define HIDPP_PAGE_HIRES_WHEEL 0x2121
+
+#define CMD_HIRES_WHEEL_GET_WHEEL_CAPABILITY 0x00
+#define CMD_HIRES_WHEEL_SET_WHEEL_MODE 0x20
+
+static int hidpp_hrw_get_wheel_capability(struct hidpp_device *hidpp,
+ u8 *multiplier)
+{
+ u8 feature_index;
+ u8 feature_type;
+ int ret;
+ struct hidpp_report response;
+
+ ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_HIRES_WHEEL,
+ &feature_index, &feature_type);
+ if (ret)
+ goto return_default;
+
+ ret = hidpp_send_fap_command_sync(hidpp, feature_index,
+ CMD_HIRES_WHEEL_GET_WHEEL_CAPABILITY,
+ NULL, 0, &response);
+ if (ret)
+ goto return_default;
+
+ *multiplier = response.fap.params[0];
+ return 0;
+return_default:
+ hid_warn(hidpp->hid_dev,
+ "Couldn't get wheel multiplier (error %d), assuming %d.\n",
+ ret, *multiplier);
+ return ret;
+}
+
+static int hidpp_hrw_set_wheel_mode(struct hidpp_device *hidpp, bool invert,
+ bool high_resolution, bool use_hidpp)
+{
+ u8 feature_index;
+ u8 feature_type;
+ int ret;
+ u8 params[1];
+ struct hidpp_report response;
+
+ ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_HIRES_WHEEL,
+ &feature_index, &feature_type);
+ if (ret)
+ return ret;
+
+ params[0] = (invert ? BIT(2) : 0) |
+ (high_resolution ? BIT(1) : 0) |
+ (use_hidpp ? BIT(0) : 0);
+
+ return hidpp_send_fap_command_sync(hidpp, feature_index,
+ CMD_HIRES_WHEEL_SET_WHEEL_MODE,
+ params, sizeof(params), &response);
+}
+
+/* -------------------------------------------------------------------------- */
/* 0x4301: Solar Keyboard */
/* -------------------------------------------------------------------------- */
@@ -2399,7 +2523,8 @@ static int m560_raw_event(struct hid_device *hdev, u8 *data, int size)
input_report_rel(mydata->input, REL_Y, v);
v = hid_snto32(data[6], 8);
- input_report_rel(mydata->input, REL_WHEEL, v);
+ hid_scroll_counter_handle_scroll(
+ &hidpp->vertical_wheel_counter, v);
input_sync(mydata->input);
}
@@ -2528,6 +2653,72 @@ static int g920_get_config(struct hidpp_device *hidpp)
}
/* -------------------------------------------------------------------------- */
+/* High-resolution scroll wheels */
+/* -------------------------------------------------------------------------- */
+
+/**
+ * struct hi_res_scroll_info - Stores info on a device's high-res scroll wheel.
+ * @product_id: the HID product ID of the device being described.
+ * @microns_per_hi_res_unit: the distance moved by the user's finger for each
+ * high-resolution unit reported by the device, in
+ * 256ths of a millimetre.
+ */
+struct hi_res_scroll_info {
+ __u32 product_id;
+ int microns_per_hi_res_unit;
+};
+
+static struct hi_res_scroll_info hi_res_scroll_devices[] = {
+ { /* Anywhere MX */
+ .product_id = 0x1017, .microns_per_hi_res_unit = 445 },
+ { /* Performance MX */
+ .product_id = 0x101a, .microns_per_hi_res_unit = 406 },
+ { /* M560 */
+ .product_id = 0x402d, .microns_per_hi_res_unit = 435 },
+ { /* MX Master 2S */
+ .product_id = 0x4069, .microns_per_hi_res_unit = 406 },
+};
+
+static int hi_res_scroll_look_up_microns(__u32 product_id)
+{
+ int i;
+ int num_devices = sizeof(hi_res_scroll_devices)
+ / sizeof(hi_res_scroll_devices[0]);
+ for (i = 0; i < num_devices; i++) {
+ if (hi_res_scroll_devices[i].product_id == product_id)
+ return hi_res_scroll_devices[i].microns_per_hi_res_unit;
+ }
+ /* We don't have a value for this device, so use a sensible default. */
+ return 406;
+}
+
+static int hi_res_scroll_enable(struct hidpp_device *hidpp)
+{
+ int ret;
+ u8 multiplier = 8;
+
+ if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_X2121) {
+ ret = hidpp_hrw_set_wheel_mode(hidpp, false, true, false);
+ hidpp_hrw_get_wheel_capability(hidpp, &multiplier);
+ } else if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_X2120) {
+ ret = hidpp_hrs_set_highres_scrolling_mode(hidpp, true,
+ &multiplier);
+ } else /* if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_1P0) */
+ ret = hidpp10_enable_scrolling_acceleration(hidpp);
+
+ if (ret)
+ return ret;
+
+ hidpp->vertical_wheel_counter.resolution_multiplier = multiplier;
+ hidpp->vertical_wheel_counter.microns_per_hi_res_unit =
+ hi_res_scroll_look_up_microns(hidpp->hid_dev->product);
+ hid_info(hidpp->hid_dev, "multiplier = %d, microns = %d\n",
+ multiplier,
+ hidpp->vertical_wheel_counter.microns_per_hi_res_unit);
+ return 0;
+}
+
+/* -------------------------------------------------------------------------- */
/* Generic HID++ devices */
/* -------------------------------------------------------------------------- */
@@ -2572,6 +2763,11 @@ static void hidpp_populate_input(struct hidpp_device *hidpp,
wtp_populate_input(hidpp, input, origin_is_hid_core);
else if (hidpp->quirks & HIDPP_QUIRK_CLASS_M560)
m560_populate_input(hidpp, input, origin_is_hid_core);
+
+ if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL) {
+ input_set_capability(input, EV_REL, REL_WHEEL_HI_RES);
+ hidpp->vertical_wheel_counter.dev = input;
+ }
}
static int hidpp_input_configured(struct hid_device *hdev,
@@ -2690,6 +2886,27 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report,
return 0;
}
+static int hidpp_event(struct hid_device *hdev, struct hid_field *field,
+ struct hid_usage *usage, __s32 value)
+{
+ /* This function will only be called for scroll events, due to the
+ * restriction imposed in hidpp_usages.
+ */
+ struct hidpp_device *hidpp = hid_get_drvdata(hdev);
+ struct hid_scroll_counter *counter = &hidpp->vertical_wheel_counter;
+ /* A scroll event may occur before the multiplier has been retrieved or
+ * the input device set, or high-res scroll enabling may fail. In such
+ * cases we must return early (falling back to default behaviour) to
+ * avoid a crash in hid_scroll_counter_handle_scroll.
+ */
+ if (!(hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL) || value == 0
+ || counter->dev == NULL || counter->resolution_multiplier == 0)
+ return 0;
+
+ hid_scroll_counter_handle_scroll(counter, value);
+ return 1;
+}
+
static int hidpp_initialize_battery(struct hidpp_device *hidpp)
{
static atomic_t battery_no = ATOMIC_INIT(0);
@@ -2901,6 +3118,9 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
if (hidpp->battery.ps)
power_supply_changed(hidpp->battery.ps);
+ if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL)
+ hi_res_scroll_enable(hidpp);
+
if (!(hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT) || hidpp->delayed_input)
/* if the input nodes are already created, we can stop now */
return;
@@ -3086,35 +3306,63 @@ static void hidpp_remove(struct hid_device *hdev)
mutex_destroy(&hidpp->send_mutex);
}
+#define LDJ_DEVICE(product) \
+ HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, \
+ USB_VENDOR_ID_LOGITECH, (product))
+
static const struct hid_device_id hidpp_devices[] = {
{ /* wireless touchpad */
- HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
- USB_VENDOR_ID_LOGITECH, 0x4011),
+ LDJ_DEVICE(0x4011),
.driver_data = HIDPP_QUIRK_CLASS_WTP | HIDPP_QUIRK_DELAYED_INIT |
HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS },
{ /* wireless touchpad T650 */
- HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
- USB_VENDOR_ID_LOGITECH, 0x4101),
+ LDJ_DEVICE(0x4101),
.driver_data = HIDPP_QUIRK_CLASS_WTP | HIDPP_QUIRK_DELAYED_INIT },
{ /* wireless touchpad T651 */
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH,
USB_DEVICE_ID_LOGITECH_T651),
.driver_data = HIDPP_QUIRK_CLASS_WTP },
+ { /* Mouse Logitech Anywhere MX */
+ LDJ_DEVICE(0x1017), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 },
+ { /* Mouse Logitech Cube */
+ LDJ_DEVICE(0x4010), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2120 },
+ { /* Mouse Logitech M335 */
+ LDJ_DEVICE(0x4050), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
+ { /* Mouse Logitech M515 */
+ LDJ_DEVICE(0x4007), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2120 },
{ /* Mouse logitech M560 */
- HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
- USB_VENDOR_ID_LOGITECH, 0x402d),
- .driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560 },
+ LDJ_DEVICE(0x402d),
+ .driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560
+ | HIDPP_QUIRK_HI_RES_SCROLL_X2120 },
+ { /* Mouse Logitech M705 (firmware RQM17) */
+ LDJ_DEVICE(0x101b), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 },
+ { /* Mouse Logitech M705 (firmware RQM67) */
+ LDJ_DEVICE(0x406d), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
+ { /* Mouse Logitech M720 */
+ LDJ_DEVICE(0x405e), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
+ { /* Mouse Logitech MX Anywhere 2 */
+ LDJ_DEVICE(0x404a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
+ { LDJ_DEVICE(0xb013), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
+ { LDJ_DEVICE(0xb018), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
+ { LDJ_DEVICE(0xb01f), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
+ { /* Mouse Logitech MX Anywhere 2S */
+ LDJ_DEVICE(0x406a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
+ { /* Mouse Logitech MX Master */
+ LDJ_DEVICE(0x4041), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
+ { LDJ_DEVICE(0x4060), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
+ { LDJ_DEVICE(0x4071), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
+ { /* Mouse Logitech MX Master 2S */
+ LDJ_DEVICE(0x4069), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
+ { /* Mouse Logitech Performance MX */
+ LDJ_DEVICE(0x101a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 },
{ /* Keyboard logitech K400 */
- HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
- USB_VENDOR_ID_LOGITECH, 0x4024),
+ LDJ_DEVICE(0x4024),
.driver_data = HIDPP_QUIRK_CLASS_K400 },
{ /* Solar Keyboard Logitech K750 */
- HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
- USB_VENDOR_ID_LOGITECH, 0x4002),
+ LDJ_DEVICE(0x4002),
.driver_data = HIDPP_QUIRK_CLASS_K750 },
- { HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
- USB_VENDOR_ID_LOGITECH, HID_ANY_ID)},
+ { LDJ_DEVICE(HID_ANY_ID) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL),
.driver_data = HIDPP_QUIRK_CLASS_G920 | HIDPP_QUIRK_FORCE_OUTPUT_REPORTS},
@@ -3123,12 +3371,19 @@ static const struct hid_device_id hidpp_devices[] = {
MODULE_DEVICE_TABLE(hid, hidpp_devices);
+static const struct hid_usage_id hidpp_usages[] = {
+ { HID_GD_WHEEL, EV_REL, REL_WHEEL },
+ { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
+};
+
static struct hid_driver hidpp_driver = {
.name = "logitech-hidpp-device",
.id_table = hidpp_devices,
.probe = hidpp_probe,
.remove = hidpp_remove,
.raw_event = hidpp_raw_event,
+ .usage_table = hidpp_usages,
+ .event = hidpp_event,
.input_configured = hidpp_input_configured,
.input_mapping = hidpp_input_mapping,
.input_mapped = hidpp_input_mapped,
diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
index b454c4386157..1d5ea678d268 100644
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -54,6 +54,8 @@ module_param(report_undeciphered, bool, 0644);
MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state field using a MSC_RAW event");
#define TRACKPAD_REPORT_ID 0x28
+#define TRACKPAD2_USB_REPORT_ID 0x02
+#define TRACKPAD2_BT_REPORT_ID 0x31
#define MOUSE_REPORT_ID 0x29
#define DOUBLE_REPORT_ID 0xf7
/* These definitions are not precise, but they're close enough. (Bits
@@ -91,6 +93,17 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie
#define TRACKPAD_RES_Y \
((TRACKPAD_MAX_Y - TRACKPAD_MIN_Y) / (TRACKPAD_DIMENSION_Y / 100))
+#define TRACKPAD2_DIMENSION_X (float)16000
+#define TRACKPAD2_MIN_X -3678
+#define TRACKPAD2_MAX_X 3934
+#define TRACKPAD2_RES_X \
+ ((TRACKPAD2_MAX_X - TRACKPAD2_MIN_X) / (TRACKPAD2_DIMENSION_X / 100))
+#define TRACKPAD2_DIMENSION_Y (float)11490
+#define TRACKPAD2_MIN_Y -2478
+#define TRACKPAD2_MAX_Y 2587
+#define TRACKPAD2_RES_Y \
+ ((TRACKPAD2_MAX_Y - TRACKPAD2_MIN_Y) / (TRACKPAD2_DIMENSION_Y / 100))
+
/**
* struct magicmouse_sc - Tracks Magic Mouse-specific data.
* @input: Input device through which we report events.
@@ -183,6 +196,7 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda
{
struct input_dev *input = msc->input;
int id, x, y, size, orientation, touch_major, touch_minor, state, down;
+ int pressure = 0;
if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) {
id = (tdata[6] << 2 | tdata[5] >> 6) & 0xf;
@@ -194,6 +208,17 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda
touch_minor = tdata[4];
state = tdata[7] & TOUCH_STATE_MASK;
down = state != TOUCH_STATE_NONE;
+ } else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) {
+ id = tdata[8] & 0xf;
+ x = (tdata[1] << 27 | tdata[0] << 19) >> 19;
+ y = -((tdata[3] << 30 | tdata[2] << 22 | tdata[1] << 14) >> 19);
+ size = tdata[6];
+ orientation = (tdata[8] >> 5) - 4;
+ touch_major = tdata[4];
+ touch_minor = tdata[5];
+ pressure = tdata[7];
+ state = tdata[3] & 0xC0;
+ down = state == 0x80;
} else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
id = (tdata[7] << 2 | tdata[6] >> 6) & 0xf;
x = (tdata[1] << 27 | tdata[0] << 19) >> 19;
@@ -215,7 +240,8 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda
/* If requested, emulate a scroll wheel by detecting small
* vertical touch motions.
*/
- if (emulate_scroll_wheel) {
+ if (emulate_scroll_wheel && (input->id.product !=
+ USB_DEVICE_ID_APPLE_MAGICTRACKPAD2)) {
unsigned long now = jiffies;
int step_x = msc->touches[id].scroll_x - x;
int step_y = msc->touches[id].scroll_y - y;
@@ -269,10 +295,14 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda
input_report_abs(input, ABS_MT_POSITION_X, x);
input_report_abs(input, ABS_MT_POSITION_Y, y);
+ if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2)
+ input_report_abs(input, ABS_MT_PRESSURE, pressure);
+
if (report_undeciphered) {
if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE)
input_event(input, EV_MSC, MSC_RAW, tdata[7]);
- else /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
+ else if (input->id.product !=
+ USB_DEVICE_ID_APPLE_MAGICTRACKPAD2)
input_event(input, EV_MSC, MSC_RAW, tdata[8]);
}
}
@@ -287,6 +317,7 @@ static int magicmouse_raw_event(struct hid_device *hdev,
switch (data[0]) {
case TRACKPAD_REPORT_ID:
+ case TRACKPAD2_BT_REPORT_ID:
/* Expect four bytes of prefix, and N*9 bytes of touch data. */
if (size < 4 || ((size - 4) % 9) != 0)
return 0;
@@ -308,6 +339,22 @@ static int magicmouse_raw_event(struct hid_device *hdev,
* ts = data[1] >> 6 | data[2] << 2 | data[3] << 10;
*/
break;
+ case TRACKPAD2_USB_REPORT_ID:
+ /* Expect twelve bytes of prefix and N*9 bytes of touch data. */
+ if (size < 12 || ((size - 12) % 9) != 0)
+ return 0;
+ npoints = (size - 12) / 9;
+ if (npoints > 15) {
+ hid_warn(hdev, "invalid size value (%d) for TRACKPAD2_USB_REPORT_ID\n",
+ size);
+ return 0;
+ }
+ msc->ntouches = 0;
+ for (ii = 0; ii < npoints; ii++)
+ magicmouse_emit_touch(msc, ii, data + ii * 9 + 12);
+
+ clicks = data[1];
+ break;
case MOUSE_REPORT_ID:
/* Expect six bytes of prefix, and N*8 bytes of touch data. */
if (size < 6 || ((size - 6) % 8) != 0)
@@ -352,6 +399,9 @@ static int magicmouse_raw_event(struct hid_device *hdev,
magicmouse_emit_buttons(msc, clicks & 3);
input_report_rel(input, REL_X, x);
input_report_rel(input, REL_Y, y);
+ } else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) {
+ input_mt_sync_frame(input);
+ input_report_key(input, BTN_MOUSE, clicks & 1);
} else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
input_report_key(input, BTN_MOUSE, clicks & 1);
input_mt_report_pointer_emulation(input, true);
@@ -364,6 +414,7 @@ static int magicmouse_raw_event(struct hid_device *hdev,
static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hdev)
{
int error;
+ int mt_flags = 0;
__set_bit(EV_KEY, input->evbit);
@@ -380,6 +431,22 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd
__set_bit(REL_WHEEL, input->relbit);
__set_bit(REL_HWHEEL, input->relbit);
}
+ } else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) {
+ /* setting the device name to ensure the same driver settings
+ * get loaded, whether connected through bluetooth or USB
+ */
+ input->name = "Apple Inc. Magic Trackpad 2";
+
+ __clear_bit(EV_MSC, input->evbit);
+ __clear_bit(BTN_0, input->keybit);
+ __clear_bit(BTN_RIGHT, input->keybit);
+ __clear_bit(BTN_MIDDLE, input->keybit);
+ __set_bit(BTN_MOUSE, input->keybit);
+ __set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
+ __set_bit(BTN_TOOL_FINGER, input->keybit);
+
+ mt_flags = INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED |
+ INPUT_MT_TRACK;
} else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
/* input->keybit is initialized with incorrect button info
* for Magic Trackpad. There really is only one physical
@@ -402,14 +469,13 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd
__set_bit(EV_ABS, input->evbit);
- error = input_mt_init_slots(input, 16, 0);
+ error = input_mt_init_slots(input, 16, mt_flags);
if (error)
return error;
input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255 << 2,
4, 0);
input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 255 << 2,
4, 0);
- input_set_abs_params(input, ABS_MT_ORIENTATION, -31, 32, 1, 0);
/* Note: Touch Y position from the device is inverted relative
* to how pointer motion is reported (and relative to how USB
@@ -418,6 +484,7 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd
* inverse of the reported Y.
*/
if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) {
+ input_set_abs_params(input, ABS_MT_ORIENTATION, -31, 32, 1, 0);
input_set_abs_params(input, ABS_MT_POSITION_X,
MOUSE_MIN_X, MOUSE_MAX_X, 4, 0);
input_set_abs_params(input, ABS_MT_POSITION_Y,
@@ -427,7 +494,25 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd
MOUSE_RES_X);
input_abs_set_res(input, ABS_MT_POSITION_Y,
MOUSE_RES_Y);
+ } else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) {
+ input_set_abs_params(input, ABS_MT_PRESSURE, 0, 253, 0, 0);
+ input_set_abs_params(input, ABS_PRESSURE, 0, 253, 0, 0);
+ input_set_abs_params(input, ABS_MT_ORIENTATION, -3, 4, 0, 0);
+ input_set_abs_params(input, ABS_X, TRACKPAD2_MIN_X,
+ TRACKPAD2_MAX_X, 0, 0);
+ input_set_abs_params(input, ABS_Y, TRACKPAD2_MIN_Y,
+ TRACKPAD2_MAX_Y, 0, 0);
+ input_set_abs_params(input, ABS_MT_POSITION_X,
+ TRACKPAD2_MIN_X, TRACKPAD2_MAX_X, 0, 0);
+ input_set_abs_params(input, ABS_MT_POSITION_Y,
+ TRACKPAD2_MIN_Y, TRACKPAD2_MAX_Y, 0, 0);
+
+ input_abs_set_res(input, ABS_X, TRACKPAD2_RES_X);
+ input_abs_set_res(input, ABS_Y, TRACKPAD2_RES_Y);
+ input_abs_set_res(input, ABS_MT_POSITION_X, TRACKPAD2_RES_X);
+ input_abs_set_res(input, ABS_MT_POSITION_Y, TRACKPAD2_RES_Y);
} else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
+ input_set_abs_params(input, ABS_MT_ORIENTATION, -31, 32, 1, 0);
input_set_abs_params(input, ABS_X, TRACKPAD_MIN_X,
TRACKPAD_MAX_X, 4, 0);
input_set_abs_params(input, ABS_Y, TRACKPAD_MIN_Y,
@@ -447,7 +532,8 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd
input_set_events_per_packet(input, 60);
- if (report_undeciphered) {
+ if (report_undeciphered &&
+ input->id.product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) {
__set_bit(EV_MSC, input->evbit);
__set_bit(MSC_RAW, input->mscbit);
}
@@ -465,7 +551,8 @@ static int magicmouse_input_mapping(struct hid_device *hdev,
msc->input = hi->input;
/* Magic Trackpad does not give relative data after switching to MT */
- if (hi->input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD &&
+ if ((hi->input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD ||
+ hi->input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) &&
field->flags & HID_MAIN_ITEM_RELATIVE)
return -1;
@@ -494,11 +581,20 @@ static int magicmouse_input_configured(struct hid_device *hdev,
static int magicmouse_probe(struct hid_device *hdev,
const struct hid_device_id *id)
{
- const u8 feature[] = { 0xd7, 0x01 };
+ const u8 *feature;
+ const u8 feature_mt[] = { 0xD7, 0x01 };
+ const u8 feature_mt_trackpad2_usb[] = { 0x02, 0x01 };
+ const u8 feature_mt_trackpad2_bt[] = { 0xF1, 0x02, 0x01 };
u8 *buf;
struct magicmouse_sc *msc;
struct hid_report *report;
int ret;
+ int feature_size;
+
+ if (id->vendor == USB_VENDOR_ID_APPLE &&
+ id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 &&
+ hdev->type != HID_TYPE_USBMOUSE)
+ return 0;
msc = devm_kzalloc(&hdev->dev, sizeof(*msc), GFP_KERNEL);
if (msc == NULL) {
@@ -532,7 +628,14 @@ static int magicmouse_probe(struct hid_device *hdev,
if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE)
report = hid_register_report(hdev, HID_INPUT_REPORT,
MOUSE_REPORT_ID, 0);
- else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
+ else if (id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) {
+ if (id->vendor == BT_VENDOR_ID_APPLE)
+ report = hid_register_report(hdev, HID_INPUT_REPORT,
+ TRACKPAD2_BT_REPORT_ID, 0);
+ else /* USB_VENDOR_ID_APPLE */
+ report = hid_register_report(hdev, HID_INPUT_REPORT,
+ TRACKPAD2_USB_REPORT_ID, 0);
+ } else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
report = hid_register_report(hdev, HID_INPUT_REPORT,
TRACKPAD_REPORT_ID, 0);
report = hid_register_report(hdev, HID_INPUT_REPORT,
@@ -546,7 +649,20 @@ static int magicmouse_probe(struct hid_device *hdev,
}
report->size = 6;
- buf = kmemdup(feature, sizeof(feature), GFP_KERNEL);
+ if (id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) {
+ if (id->vendor == BT_VENDOR_ID_APPLE) {
+ feature_size = sizeof(feature_mt_trackpad2_bt);
+ feature = feature_mt_trackpad2_bt;
+ } else { /* USB_VENDOR_ID_APPLE */
+ feature_size = sizeof(feature_mt_trackpad2_usb);
+ feature = feature_mt_trackpad2_usb;
+ }
+ } else {
+ feature_size = sizeof(feature_mt);
+ feature = feature_mt;
+ }
+
+ buf = kmemdup(feature, feature_size, GFP_KERNEL);
if (!buf) {
ret = -ENOMEM;
goto err_stop_hw;
@@ -560,10 +676,10 @@ static int magicmouse_probe(struct hid_device *hdev,
* but there seems to be no other way of switching the mode.
* Thus the super-ugly hacky success check below.
*/
- ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(feature),
+ ret = hid_hw_raw_request(hdev, buf[0], buf, feature_size,
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
kfree(buf);
- if (ret != -EIO && ret != sizeof(feature)) {
+ if (ret != -EIO && ret != feature_size) {
hid_err(hdev, "unable to request touch data (%d)\n", ret);
goto err_stop_hw;
}
@@ -579,6 +695,10 @@ static const struct hid_device_id magic_mice[] = {
USB_DEVICE_ID_APPLE_MAGICMOUSE), .driver_data = 0 },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
USB_DEVICE_ID_APPLE_MAGICTRACKPAD), .driver_data = 0 },
+ { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE,
+ USB_DEVICE_ID_APPLE_MAGICTRACKPAD2), .driver_data = 0 },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE,
+ USB_DEVICE_ID_APPLE_MAGICTRACKPAD2), .driver_data = 0 },
{ }
};
MODULE_DEVICE_TABLE(hid, magic_mice);
diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c
index 72d983626afd..330cb073cb66 100644
--- a/drivers/hid/hid-microsoft.c
+++ b/drivers/hid/hid-microsoft.c
@@ -29,11 +29,41 @@
#define MS_NOGET BIT(4)
#define MS_DUPLICATE_USAGES BIT(5)
#define MS_SURFACE_DIAL BIT(6)
+#define MS_QUIRK_FF BIT(7)
+
+struct ms_data {
+ unsigned long quirks;
+ struct hid_device *hdev;
+ struct work_struct ff_worker;
+ __u8 strong;
+ __u8 weak;
+ void *output_report_dmabuf;
+};
+
+#define XB1S_FF_REPORT 3
+#define ENABLE_WEAK BIT(0)
+#define ENABLE_STRONG BIT(1)
+
+enum {
+ MAGNITUDE_STRONG = 2,
+ MAGNITUDE_WEAK,
+ MAGNITUDE_NUM
+};
+
+struct xb1s_ff_report {
+ __u8 report_id;
+ __u8 enable;
+ __u8 magnitude[MAGNITUDE_NUM];
+ __u8 duration_10ms;
+ __u8 start_delay_10ms;
+ __u8 loop_count;
+} __packed;
static __u8 *ms_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
{
- unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+ struct ms_data *ms = hid_get_drvdata(hdev);
+ unsigned long quirks = ms->quirks;
/*
* Microsoft Wireless Desktop Receiver (Model 1028) has
@@ -159,7 +189,8 @@ static int ms_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
- unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+ struct ms_data *ms = hid_get_drvdata(hdev);
+ unsigned long quirks = ms->quirks;
if (quirks & MS_ERGONOMY) {
int ret = ms_ergonomy_kb_quirk(hi, usage, bit, max);
@@ -185,7 +216,8 @@ static int ms_input_mapped(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
- unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+ struct ms_data *ms = hid_get_drvdata(hdev);
+ unsigned long quirks = ms->quirks;
if (quirks & MS_DUPLICATE_USAGES)
clear_bit(usage->code, *bit);
@@ -196,7 +228,8 @@ static int ms_input_mapped(struct hid_device *hdev, struct hid_input *hi,
static int ms_event(struct hid_device *hdev, struct hid_field *field,
struct hid_usage *usage, __s32 value)
{
- unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+ struct ms_data *ms = hid_get_drvdata(hdev);
+ unsigned long quirks = ms->quirks;
struct input_dev *input;
if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput ||
@@ -251,12 +284,97 @@ static int ms_event(struct hid_device *hdev, struct hid_field *field,
return 0;
}
+static void ms_ff_worker(struct work_struct *work)
+{
+ struct ms_data *ms = container_of(work, struct ms_data, ff_worker);
+ struct hid_device *hdev = ms->hdev;
+ struct xb1s_ff_report *r = ms->output_report_dmabuf;
+ int ret;
+
+ memset(r, 0, sizeof(*r));
+
+ r->report_id = XB1S_FF_REPORT;
+ r->enable = ENABLE_WEAK | ENABLE_STRONG;
+ /*
+ * Specifying maximum duration and maximum loop count should
+ * cover maximum duration of a single effect, which is 65536
+ * ms
+ */
+ r->duration_10ms = U8_MAX;
+ r->loop_count = U8_MAX;
+ r->magnitude[MAGNITUDE_STRONG] = ms->strong; /* left actuator */
+ r->magnitude[MAGNITUDE_WEAK] = ms->weak; /* right actuator */
+
+ ret = hid_hw_output_report(hdev, (__u8 *)r, sizeof(*r));
+ if (ret)
+ hid_warn(hdev, "failed to send FF report\n");
+}
+
+static int ms_play_effect(struct input_dev *dev, void *data,
+ struct ff_effect *effect)
+{
+ struct hid_device *hid = input_get_drvdata(dev);
+ struct ms_data *ms = hid_get_drvdata(hid);
+
+ if (effect->type != FF_RUMBLE)
+ return 0;
+
+ /*
+ * Magnitude is 0..100 so scale the 16-bit input here
+ */
+ ms->strong = ((u32) effect->u.rumble.strong_magnitude * 100) / U16_MAX;
+ ms->weak = ((u32) effect->u.rumble.weak_magnitude * 100) / U16_MAX;
+
+ schedule_work(&ms->ff_worker);
+ return 0;
+}
+
+static int ms_init_ff(struct hid_device *hdev)
+{
+ struct hid_input *hidinput = list_entry(hdev->inputs.next,
+ struct hid_input, list);
+ struct input_dev *input_dev = hidinput->input;
+ struct ms_data *ms = hid_get_drvdata(hdev);
+
+ if (!(ms->quirks & MS_QUIRK_FF))
+ return 0;
+
+ ms->hdev = hdev;
+ INIT_WORK(&ms->ff_worker, ms_ff_worker);
+
+ ms->output_report_dmabuf = devm_kzalloc(&hdev->dev,
+ sizeof(struct xb1s_ff_report),
+ GFP_KERNEL);
+ if (ms->output_report_dmabuf == NULL)
+ return -ENOMEM;
+
+ input_set_capability(input_dev, EV_FF, FF_RUMBLE);
+ return input_ff_create_memless(input_dev, NULL, ms_play_effect);
+}
+
+static void ms_remove_ff(struct hid_device *hdev)
+{
+ struct ms_data *ms = hid_get_drvdata(hdev);
+
+ if (!(ms->quirks & MS_QUIRK_FF))
+ return;
+
+ cancel_work_sync(&ms->ff_worker);
+}
+
static int ms_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
unsigned long quirks = id->driver_data;
+ struct ms_data *ms;
int ret;
- hid_set_drvdata(hdev, (void *)quirks);
+ ms = devm_kzalloc(&hdev->dev, sizeof(*ms), GFP_KERNEL);
+ if (ms == NULL)
+ return -ENOMEM;
+
+ ms->quirks = quirks;
+
+ hid_set_drvdata(hdev, ms);
if (quirks & MS_NOGET)
hdev->quirks |= HID_QUIRK_NOGET;
@@ -277,11 +395,21 @@ static int ms_probe(struct hid_device *hdev, const struct hid_device_id *id)
goto err_free;
}
+ ret = ms_init_ff(hdev);
+ if (ret)
+ hid_err(hdev, "could not initialize ff, continuing anyway");
+
return 0;
err_free:
return ret;
}
+static void ms_remove(struct hid_device *hdev)
+{
+ hid_hw_stop(hdev);
+ ms_remove_ff(hdev);
+}
+
static const struct hid_device_id ms_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV),
.driver_data = MS_HIDINPUT },
@@ -318,6 +446,8 @@ static const struct hid_device_id ms_devices[] = {
.driver_data = MS_PRESENTER },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, 0x091B),
.driver_data = MS_SURFACE_DIAL },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_XBOX_ONE_S_CONTROLLER),
+ .driver_data = MS_QUIRK_FF },
{ }
};
MODULE_DEVICE_TABLE(hid, ms_devices);
@@ -330,6 +460,7 @@ static struct hid_driver ms_driver = {
.input_mapped = ms_input_mapped,
.event = ms_event,
.probe = ms_probe,
+ .remove = ms_remove,
};
module_hid_driver(ms_driver);
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index da954f3f4da7..f7c6de2b6730 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -1319,6 +1319,13 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
return mt_touch_input_mapping(hdev, hi, field, usage, bit, max,
application);
+ /*
+ * some egalax touchscreens have "application == DG_TOUCHSCREEN"
+ * for the stylus. Overwrite the hid_input application
+ */
+ if (field->physical == HID_DG_STYLUS)
+ hi->application = HID_DG_STYLUS;
+
/* let hid-core decide for the others */
return 0;
}
@@ -1507,14 +1514,12 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
struct mt_device *td = hid_get_drvdata(hdev);
char *name;
const char *suffix = NULL;
- unsigned int application = 0;
struct mt_report_data *rdata;
struct mt_application *mt_application = NULL;
struct hid_report *report;
int ret;
list_for_each_entry(report, &hi->reports, hidinput_list) {
- application = report->application;
rdata = mt_find_report_data(td, report);
if (!rdata) {
hid_err(hdev, "failed to allocate data for report\n");
@@ -1529,46 +1534,33 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
if (ret)
return ret;
}
-
- /*
- * some egalax touchscreens have "application == DG_TOUCHSCREEN"
- * for the stylus. Check this first, and then rely on
- * the application field.
- */
- if (report->field[0]->physical == HID_DG_STYLUS) {
- suffix = "Pen";
- /* force BTN_STYLUS to allow tablet matching in udev */
- __set_bit(BTN_STYLUS, hi->input->keybit);
- }
}
- if (!suffix) {
- switch (application) {
- case HID_GD_KEYBOARD:
- case HID_GD_KEYPAD:
- case HID_GD_MOUSE:
- case HID_DG_TOUCHPAD:
- case HID_GD_SYSTEM_CONTROL:
- case HID_CP_CONSUMER_CONTROL:
- case HID_GD_WIRELESS_RADIO_CTLS:
- case HID_GD_SYSTEM_MULTIAXIS:
- /* already handled by hid core */
- break;
- case HID_DG_TOUCHSCREEN:
- /* we do not set suffix = "Touchscreen" */
- hi->input->name = hdev->name;
- break;
- case HID_DG_STYLUS:
- /* force BTN_STYLUS to allow tablet matching in udev */
- __set_bit(BTN_STYLUS, hi->input->keybit);
- break;
- case HID_VD_ASUS_CUSTOM_MEDIA_KEYS:
- suffix = "Custom Media Keys";
- break;
- default:
- suffix = "UNKNOWN";
- break;
- }
+ switch (hi->application) {
+ case HID_GD_KEYBOARD:
+ case HID_GD_KEYPAD:
+ case HID_GD_MOUSE:
+ case HID_DG_TOUCHPAD:
+ case HID_GD_SYSTEM_CONTROL:
+ case HID_CP_CONSUMER_CONTROL:
+ case HID_GD_WIRELESS_RADIO_CTLS:
+ case HID_GD_SYSTEM_MULTIAXIS:
+ /* already handled by hid core */
+ break;
+ case HID_DG_TOUCHSCREEN:
+ /* we do not set suffix = "Touchscreen" */
+ hi->input->name = hdev->name;
+ break;
+ case HID_DG_STYLUS:
+ /* force BTN_STYLUS to allow tablet matching in udev */
+ __set_bit(BTN_STYLUS, hi->input->keybit);
+ break;
+ case HID_VD_ASUS_CUSTOM_MEDIA_KEYS:
+ suffix = "Custom Media Keys";
+ break;
+ default:
+ suffix = "UNKNOWN";
+ break;
}
if (suffix) {
diff --git a/drivers/hid/hid-picolcd_cir.c b/drivers/hid/hid-picolcd_cir.c
index 32747b7f917e..bf6f29ca3315 100644
--- a/drivers/hid/hid-picolcd_cir.c
+++ b/drivers/hid/hid-picolcd_cir.c
@@ -45,7 +45,7 @@ int picolcd_raw_cir(struct picolcd_data *data,
{
unsigned long flags;
int i, w, sz;
- DEFINE_IR_RAW_EVENT(rawir);
+ struct ir_raw_event rawir = {};
/* ignore if rc_dev is NULL or status is shunned */
spin_lock_irqsave(&data->lock, flags);
@@ -67,7 +67,6 @@ int picolcd_raw_cir(struct picolcd_data *data,
*/
sz = size > 0 ? min((int)raw_data[0], size-1) : 0;
for (i = 0; i+1 < sz; i += 2) {
- init_ir_raw_event(&rawir);
w = (raw_data[i] << 8) | (raw_data[i+1]);
rawir.pulse = !!(w & 0x8000);
rawir.duration = US_TO_NS(rawir.pulse ? (65536 - w) : w);
diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
index 249d49b6b16c..8237dd86fb17 100644
--- a/drivers/hid/hid-quirks.c
+++ b/drivers/hid/hid-quirks.c
@@ -70,6 +70,7 @@ static const struct hid_device_id hid_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC), HID_QUIRK_NOGET },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRACAL_RAPHNET, USB_DEVICE_ID_RAPHNET_2NES2SNES), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRACAL_RAPHNET, USB_DEVICE_ID_RAPHNET_4NES4SNES), HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_REDRAGON_SEYMUR2), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE1), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_PS3), HID_QUIRK_MULTI_INPUT },
@@ -106,7 +107,6 @@ static const struct hid_device_id hid_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C05A), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C06A), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_MCS, USB_DEVICE_ID_MCS_GAMEPADBLOCK), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS), HID_QUIRK_NOGET },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER), HID_QUIRK_NO_INIT_REPORTS },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_PRO_2), HID_QUIRK_NO_INIT_REPORTS },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2), HID_QUIRK_NO_INIT_REPORTS },
diff --git a/drivers/hid/i2c-hid/Makefile b/drivers/hid/i2c-hid/Makefile
index 832d8f9aaba2..099e1ce2f234 100644
--- a/drivers/hid/i2c-hid/Makefile
+++ b/drivers/hid/i2c-hid/Makefile
@@ -3,3 +3,6 @@
#
obj-$(CONFIG_I2C_HID) += i2c-hid.o
+
+i2c-hid-objs = i2c-hid-core.o
+i2c-hid-$(CONFIG_DMI) += i2c-hid-dmi-quirks.o
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid-core.c
index f3076659361a..3cde7c1b9c33 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid-core.c
@@ -43,11 +43,13 @@
#include <linux/platform_data/i2c-hid.h>
#include "../hid-ids.h"
+#include "i2c-hid.h"
/* quirks to control the device */
#define I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV BIT(0)
#define I2C_HID_QUIRK_NO_IRQ_AFTER_RESET BIT(1)
-#define I2C_HID_QUIRK_RESEND_REPORT_DESCR BIT(2)
+#define I2C_HID_QUIRK_NO_RUNTIME_PM BIT(2)
+#define I2C_HID_QUIRK_DELAY_AFTER_SLEEP BIT(3)
/* flags */
#define I2C_HID_STARTED 0
@@ -157,6 +159,8 @@ struct i2c_hid {
bool irq_wake_enabled;
struct mutex reset_lock;
+
+ unsigned long sleep_delay;
};
static const struct i2c_hid_quirks {
@@ -169,9 +173,10 @@ static const struct i2c_hid_quirks {
{ USB_VENDOR_ID_WEIDA, USB_DEVICE_ID_WEIDA_8755,
I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV },
{ I2C_VENDOR_ID_HANTICK, I2C_PRODUCT_ID_HANTICK_5288,
- I2C_HID_QUIRK_NO_IRQ_AFTER_RESET },
- { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS10FB_TOUCH,
- I2C_HID_QUIRK_RESEND_REPORT_DESCR },
+ I2C_HID_QUIRK_NO_IRQ_AFTER_RESET |
+ I2C_HID_QUIRK_NO_RUNTIME_PM },
+ { I2C_VENDOR_ID_RAYDIUM, I2C_PRODUCT_ID_RAYDIUM_4B33,
+ I2C_HID_QUIRK_DELAY_AFTER_SLEEP },
{ 0, 0 }
};
@@ -387,6 +392,7 @@ static int i2c_hid_set_power(struct i2c_client *client, int power_state)
{
struct i2c_hid *ihid = i2c_get_clientdata(client);
int ret;
+ unsigned long now, delay;
i2c_hid_dbg(ihid, "%s\n", __func__);
@@ -404,9 +410,22 @@ static int i2c_hid_set_power(struct i2c_client *client, int power_state)
goto set_pwr_exit;
}
+ if (ihid->quirks & I2C_HID_QUIRK_DELAY_AFTER_SLEEP &&
+ power_state == I2C_HID_PWR_ON) {
+ now = jiffies;
+ if (time_after(ihid->sleep_delay, now)) {
+ delay = jiffies_to_usecs(ihid->sleep_delay - now);
+ usleep_range(delay, delay + 1);
+ }
+ }
+
ret = __i2c_hid_command(client, &hid_set_power_cmd, power_state,
0, NULL, 0, NULL, 0);
+ if (ihid->quirks & I2C_HID_QUIRK_DELAY_AFTER_SLEEP &&
+ power_state == I2C_HID_PWR_SLEEP)
+ ihid->sleep_delay = jiffies + msecs_to_jiffies(20);
+
if (ret)
dev_err(&client->dev, "failed to change power setting.\n");
@@ -669,6 +688,7 @@ static int i2c_hid_parse(struct hid_device *hid)
char *rdesc;
int ret;
int tries = 3;
+ char *use_override;
i2c_hid_dbg(ihid, "entering %s\n", __func__);
@@ -687,26 +707,37 @@ static int i2c_hid_parse(struct hid_device *hid)
if (ret)
return ret;
- rdesc = kzalloc(rsize, GFP_KERNEL);
-
- if (!rdesc) {
- dbg_hid("couldn't allocate rdesc memory\n");
- return -ENOMEM;
- }
+ use_override = i2c_hid_get_dmi_hid_report_desc_override(client->name,
+ &rsize);
- i2c_hid_dbg(ihid, "asking HID report descriptor\n");
-
- ret = i2c_hid_command(client, &hid_report_descr_cmd, rdesc, rsize);
- if (ret) {
- hid_err(hid, "reading report descriptor failed\n");
- kfree(rdesc);
- return -EIO;
+ if (use_override) {
+ rdesc = use_override;
+ i2c_hid_dbg(ihid, "Using a HID report descriptor override\n");
+ } else {
+ rdesc = kzalloc(rsize, GFP_KERNEL);
+
+ if (!rdesc) {
+ dbg_hid("couldn't allocate rdesc memory\n");
+ return -ENOMEM;
+ }
+
+ i2c_hid_dbg(ihid, "asking HID report descriptor\n");
+
+ ret = i2c_hid_command(client, &hid_report_descr_cmd,
+ rdesc, rsize);
+ if (ret) {
+ hid_err(hid, "reading report descriptor failed\n");
+ kfree(rdesc);
+ return -EIO;
+ }
}
i2c_hid_dbg(ihid, "Report Descriptor: %*ph\n", rsize, rdesc);
ret = hid_parse_report(hid, rdesc, rsize);
- kfree(rdesc);
+ if (!use_override)
+ kfree(rdesc);
+
if (ret) {
dbg_hid("parsing report descriptor failed\n");
return ret;
@@ -833,12 +864,19 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
int ret;
/* i2c hid fetch using a fixed descriptor size (30 bytes) */
- i2c_hid_dbg(ihid, "Fetching the HID descriptor\n");
- ret = i2c_hid_command(client, &hid_descr_cmd, ihid->hdesc_buffer,
- sizeof(struct i2c_hid_desc));
- if (ret) {
- dev_err(&client->dev, "hid_descr_cmd failed\n");
- return -ENODEV;
+ if (i2c_hid_get_dmi_i2c_hid_desc_override(client->name)) {
+ i2c_hid_dbg(ihid, "Using a HID descriptor override\n");
+ ihid->hdesc =
+ *i2c_hid_get_dmi_i2c_hid_desc_override(client->name);
+ } else {
+ i2c_hid_dbg(ihid, "Fetching the HID descriptor\n");
+ ret = i2c_hid_command(client, &hid_descr_cmd,
+ ihid->hdesc_buffer,
+ sizeof(struct i2c_hid_desc));
+ if (ret) {
+ dev_err(&client->dev, "hid_descr_cmd failed\n");
+ return -ENODEV;
+ }
}
/* Validate the length of HID descriptor, the 4 first bytes:
@@ -1105,7 +1143,9 @@ static int i2c_hid_probe(struct i2c_client *client,
goto err_mem_free;
}
- pm_runtime_put(&client->dev);
+ if (!(ihid->quirks & I2C_HID_QUIRK_NO_RUNTIME_PM))
+ pm_runtime_put(&client->dev);
+
return 0;
err_mem_free:
@@ -1130,7 +1170,8 @@ static int i2c_hid_remove(struct i2c_client *client)
struct i2c_hid *ihid = i2c_get_clientdata(client);
struct hid_device *hid;
- pm_runtime_get_sync(&client->dev);
+ if (!(ihid->quirks & I2C_HID_QUIRK_NO_RUNTIME_PM))
+ pm_runtime_get_sync(&client->dev);
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
pm_runtime_put_noidle(&client->dev);
@@ -1236,22 +1277,13 @@ static int i2c_hid_resume(struct device *dev)
/* Instead of resetting device, simply powers the device on. This
* solves "incomplete reports" on Raydium devices 2386:3118 and
- * 2386:4B33
+ * 2386:4B33 and fixes various SIS touchscreens no longer sending
+ * data after a suspend/resume.
*/
ret = i2c_hid_set_power(client, I2C_HID_PWR_ON);
if (ret)
return ret;
- /* Some devices need to re-send report descr cmd
- * after resume, after this it will be back normal.
- * otherwise it issues too many incomplete reports.
- */
- if (ihid->quirks & I2C_HID_QUIRK_RESEND_REPORT_DESCR) {
- ret = i2c_hid_command(client, &hid_report_descr_cmd, NULL, 0);
- if (ret)
- return ret;
- }
-
if (hid->driver && hid->driver->reset_resume) {
ret = hid->driver->reset_resume(hid);
return ret;
diff --git a/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c
new file mode 100644
index 000000000000..89f2976f9c53
--- /dev/null
+++ b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c
@@ -0,0 +1,385 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/*
+ * Quirks for I2C-HID devices that do not supply proper descriptors
+ *
+ * Copyright (c) 2018 Julian Sax <jsbc@gmx.de>
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/dmi.h>
+#include <linux/mod_devicetable.h>
+
+#include "i2c-hid.h"
+
+
+struct i2c_hid_desc_override {
+ union {
+ struct i2c_hid_desc *i2c_hid_desc;
+ uint8_t *i2c_hid_desc_buffer;
+ };
+ uint8_t *hid_report_desc;
+ unsigned int hid_report_desc_size;
+ uint8_t *i2c_name;
+};
+
+
+/*
+ * descriptors for the SIPODEV SP1064 touchpad
+ *
+ * This device does not supply any descriptors and on windows a filter
+ * driver operates between the i2c-hid layer and the device and injects
+ * these descriptors when the device is prompted. The descriptors were
+ * extracted by listening to the i2c-hid traffic that occurs between the
+ * windows filter driver and the windows i2c-hid driver.
+ */
+
+static const struct i2c_hid_desc_override sipodev_desc = {
+ .i2c_hid_desc_buffer = (uint8_t [])
+ {0x1e, 0x00, /* Length of descriptor */
+ 0x00, 0x01, /* Version of descriptor */
+ 0xdb, 0x01, /* Length of report descriptor */
+ 0x21, 0x00, /* Location of report descriptor */
+ 0x24, 0x00, /* Location of input report */
+ 0x1b, 0x00, /* Max input report length */
+ 0x25, 0x00, /* Location of output report */
+ 0x11, 0x00, /* Max output report length */
+ 0x22, 0x00, /* Location of command register */
+ 0x23, 0x00, /* Location of data register */
+ 0x11, 0x09, /* Vendor ID */
+ 0x88, 0x52, /* Product ID */
+ 0x06, 0x00, /* Version ID */
+ 0x00, 0x00, 0x00, 0x00 /* Reserved */
+ },
+
+ .hid_report_desc = (uint8_t [])
+ {0x05, 0x01, /* Usage Page (Desktop), */
+ 0x09, 0x02, /* Usage (Mouse), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x01, /* Report ID (1), */
+ 0x09, 0x01, /* Usage (Pointer), */
+ 0xA1, 0x00, /* Collection (Physical), */
+ 0x05, 0x09, /* Usage Page (Button), */
+ 0x19, 0x01, /* Usage Minimum (01h), */
+ 0x29, 0x02, /* Usage Maximum (02h), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x95, 0x02, /* Report Count (2), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x95, 0x06, /* Report Count (6), */
+ 0x81, 0x01, /* Input (Constant), */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x09, 0x30, /* Usage (X), */
+ 0x09, 0x31, /* Usage (Y), */
+ 0x15, 0x81, /* Logical Minimum (-127), */
+ 0x25, 0x7F, /* Logical Maximum (127), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x95, 0x02, /* Report Count (2), */
+ 0x81, 0x06, /* Input (Variable, Relative), */
+ 0xC0, /* End Collection, */
+ 0xC0, /* End Collection, */
+ 0x05, 0x0D, /* Usage Page (Digitizer), */
+ 0x09, 0x05, /* Usage (Touchpad), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x04, /* Report ID (4), */
+ 0x05, 0x0D, /* Usage Page (Digitizer), */
+ 0x09, 0x22, /* Usage (Finger), */
+ 0xA1, 0x02, /* Collection (Logical), */
+ 0x15, 0x00, /* Logical Minimum (0), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x09, 0x47, /* Usage (Touch Valid), */
+ 0x09, 0x42, /* Usage (Tip Switch), */
+ 0x95, 0x02, /* Report Count (2), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x75, 0x03, /* Report Size (3), */
+ 0x25, 0x05, /* Logical Maximum (5), */
+ 0x09, 0x51, /* Usage (Contact Identifier), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x26, 0x44, 0x0A, /* Logical Maximum (2628), */
+ 0x75, 0x10, /* Report Size (16), */
+ 0x55, 0x0E, /* Unit Exponent (14), */
+ 0x65, 0x11, /* Unit (Centimeter), */
+ 0x09, 0x30, /* Usage (X), */
+ 0x46, 0x1A, 0x04, /* Physical Maximum (1050), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x46, 0xBC, 0x02, /* Physical Maximum (700), */
+ 0x26, 0x34, 0x05, /* Logical Maximum (1332), */
+ 0x09, 0x31, /* Usage (Y), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xC0, /* End Collection, */
+ 0x05, 0x0D, /* Usage Page (Digitizer), */
+ 0x09, 0x22, /* Usage (Finger), */
+ 0xA1, 0x02, /* Collection (Logical), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x09, 0x47, /* Usage (Touch Valid), */
+ 0x09, 0x42, /* Usage (Tip Switch), */
+ 0x95, 0x02, /* Report Count (2), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x75, 0x03, /* Report Size (3), */
+ 0x25, 0x05, /* Logical Maximum (5), */
+ 0x09, 0x51, /* Usage (Contact Identifier), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x26, 0x44, 0x0A, /* Logical Maximum (2628), */
+ 0x75, 0x10, /* Report Size (16), */
+ 0x09, 0x30, /* Usage (X), */
+ 0x46, 0x1A, 0x04, /* Physical Maximum (1050), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x46, 0xBC, 0x02, /* Physical Maximum (700), */
+ 0x26, 0x34, 0x05, /* Logical Maximum (1332), */
+ 0x09, 0x31, /* Usage (Y), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xC0, /* End Collection, */
+ 0x05, 0x0D, /* Usage Page (Digitizer), */
+ 0x09, 0x22, /* Usage (Finger), */
+ 0xA1, 0x02, /* Collection (Logical), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x09, 0x47, /* Usage (Touch Valid), */
+ 0x09, 0x42, /* Usage (Tip Switch), */
+ 0x95, 0x02, /* Report Count (2), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x75, 0x03, /* Report Size (3), */
+ 0x25, 0x05, /* Logical Maximum (5), */
+ 0x09, 0x51, /* Usage (Contact Identifier), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x26, 0x44, 0x0A, /* Logical Maximum (2628), */
+ 0x75, 0x10, /* Report Size (16), */
+ 0x09, 0x30, /* Usage (X), */
+ 0x46, 0x1A, 0x04, /* Physical Maximum (1050), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x46, 0xBC, 0x02, /* Physical Maximum (700), */
+ 0x26, 0x34, 0x05, /* Logical Maximum (1332), */
+ 0x09, 0x31, /* Usage (Y), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xC0, /* End Collection, */
+ 0x05, 0x0D, /* Usage Page (Digitizer), */
+ 0x09, 0x22, /* Usage (Finger), */
+ 0xA1, 0x02, /* Collection (Logical), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x09, 0x47, /* Usage (Touch Valid), */
+ 0x09, 0x42, /* Usage (Tip Switch), */
+ 0x95, 0x02, /* Report Count (2), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x75, 0x03, /* Report Size (3), */
+ 0x25, 0x05, /* Logical Maximum (5), */
+ 0x09, 0x51, /* Usage (Contact Identifier), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x26, 0x44, 0x0A, /* Logical Maximum (2628), */
+ 0x75, 0x10, /* Report Size (16), */
+ 0x09, 0x30, /* Usage (X), */
+ 0x46, 0x1A, 0x04, /* Physical Maximum (1050), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x46, 0xBC, 0x02, /* Physical Maximum (700), */
+ 0x26, 0x34, 0x05, /* Logical Maximum (1332), */
+ 0x09, 0x31, /* Usage (Y), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xC0, /* End Collection, */
+ 0x05, 0x0D, /* Usage Page (Digitizer), */
+ 0x55, 0x0C, /* Unit Exponent (12), */
+ 0x66, 0x01, 0x10, /* Unit (Seconds), */
+ 0x47, 0xFF, 0xFF, 0x00, 0x00,/* Physical Maximum (65535), */
+ 0x27, 0xFF, 0xFF, 0x00, 0x00,/* Logical Maximum (65535), */
+ 0x75, 0x10, /* Report Size (16), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x09, 0x56, /* Usage (Scan Time), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x09, 0x54, /* Usage (Contact Count), */
+ 0x25, 0x7F, /* Logical Maximum (127), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x05, 0x09, /* Usage Page (Button), */
+ 0x09, 0x01, /* Usage (01h), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x95, 0x07, /* Report Count (7), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0x05, 0x0D, /* Usage Page (Digitizer), */
+ 0x85, 0x02, /* Report ID (2), */
+ 0x09, 0x55, /* Usage (Contact Count Maximum), */
+ 0x09, 0x59, /* Usage (59h), */
+ 0x75, 0x04, /* Report Size (4), */
+ 0x95, 0x02, /* Report Count (2), */
+ 0x25, 0x0F, /* Logical Maximum (15), */
+ 0xB1, 0x02, /* Feature (Variable), */
+ 0x05, 0x0D, /* Usage Page (Digitizer), */
+ 0x85, 0x07, /* Report ID (7), */
+ 0x09, 0x60, /* Usage (60h), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0xB1, 0x02, /* Feature (Variable), */
+ 0x95, 0x07, /* Report Count (7), */
+ 0xB1, 0x03, /* Feature (Constant, Variable), */
+ 0x85, 0x06, /* Report ID (6), */
+ 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */
+ 0x09, 0xC5, /* Usage (C5h), */
+ 0x26, 0xFF, 0x00, /* Logical Maximum (255), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x96, 0x00, 0x01, /* Report Count (256), */
+ 0xB1, 0x02, /* Feature (Variable), */
+ 0xC0, /* End Collection, */
+ 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */
+ 0x09, 0x01, /* Usage (01h), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x0D, /* Report ID (13), */
+ 0x26, 0xFF, 0x00, /* Logical Maximum (255), */
+ 0x19, 0x01, /* Usage Minimum (01h), */
+ 0x29, 0x02, /* Usage Maximum (02h), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x95, 0x02, /* Report Count (2), */
+ 0xB1, 0x02, /* Feature (Variable), */
+ 0xC0, /* End Collection, */
+ 0x05, 0x0D, /* Usage Page (Digitizer), */
+ 0x09, 0x0E, /* Usage (Configuration), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x03, /* Report ID (3), */
+ 0x09, 0x22, /* Usage (Finger), */
+ 0xA1, 0x02, /* Collection (Logical), */
+ 0x09, 0x52, /* Usage (Device Mode), */
+ 0x25, 0x0A, /* Logical Maximum (10), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0xB1, 0x02, /* Feature (Variable), */
+ 0xC0, /* End Collection, */
+ 0x09, 0x22, /* Usage (Finger), */
+ 0xA1, 0x00, /* Collection (Physical), */
+ 0x85, 0x05, /* Report ID (5), */
+ 0x09, 0x57, /* Usage (57h), */
+ 0x09, 0x58, /* Usage (58h), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x95, 0x02, /* Report Count (2), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0xB1, 0x02, /* Feature (Variable), */
+ 0x95, 0x06, /* Report Count (6), */
+ 0xB1, 0x03, /* Feature (Constant, Variable),*/
+ 0xC0, /* End Collection, */
+ 0xC0 /* End Collection */
+ },
+ .hid_report_desc_size = 475,
+ .i2c_name = "SYNA3602:00"
+};
+
+
+static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = {
+ {
+ .ident = "Teclast F6 Pro",
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TECLAST"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "F6 Pro"),
+ },
+ .driver_data = (void *)&sipodev_desc
+ },
+ {
+ .ident = "Teclast F7",
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TECLAST"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "F7"),
+ },
+ .driver_data = (void *)&sipodev_desc
+ },
+ {
+ .ident = "Trekstor Primebook C13",
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TREKSTOR"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Primebook C13"),
+ },
+ .driver_data = (void *)&sipodev_desc
+ },
+ {
+ .ident = "Trekstor Primebook C11",
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TREKSTOR"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Primebook C11"),
+ },
+ .driver_data = (void *)&sipodev_desc
+ },
+ {
+ .ident = "Direkt-Tek DTLAPY116-2",
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Direkt-Tek"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "DTLAPY116-2"),
+ },
+ .driver_data = (void *)&sipodev_desc
+ },
+ {
+ .ident = "Direkt-Tek DTLAPY133-1",
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Direkt-Tek"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "DTLAPY133-1"),
+ },
+ .driver_data = (void *)&sipodev_desc
+ },
+ {
+ .ident = "Mediacom Flexbook Edge 11",
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "MEDIACOM"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "FlexBook edge11 - M-FBE11"),
+ },
+ .driver_data = (void *)&sipodev_desc
+ },
+ { } /* Terminate list */
+};
+
+
+struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name)
+{
+ struct i2c_hid_desc_override *override;
+ const struct dmi_system_id *system_id;
+
+ system_id = dmi_first_match(i2c_hid_dmi_desc_override_table);
+ if (!system_id)
+ return NULL;
+
+ override = system_id->driver_data;
+ if (strcmp(override->i2c_name, i2c_name))
+ return NULL;
+
+ return override->i2c_hid_desc;
+}
+
+char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name,
+ unsigned int *size)
+{
+ struct i2c_hid_desc_override *override;
+ const struct dmi_system_id *system_id;
+
+ system_id = dmi_first_match(i2c_hid_dmi_desc_override_table);
+ if (!system_id)
+ return NULL;
+
+ override = system_id->driver_data;
+ if (strcmp(override->i2c_name, i2c_name))
+ return NULL;
+
+ *size = override->hid_report_desc_size;
+ return override->hid_report_desc;
+}
diff --git a/drivers/hid/i2c-hid/i2c-hid.h b/drivers/hid/i2c-hid/i2c-hid.h
new file mode 100644
index 000000000000..a8c19aef5824
--- /dev/null
+++ b/drivers/hid/i2c-hid/i2c-hid.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#ifndef I2C_HID_H
+#define I2C_HID_H
+
+
+#ifdef CONFIG_DMI
+struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name);
+char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name,
+ unsigned int *size);
+#else
+static inline struct i2c_hid_desc
+ *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name)
+{ return NULL; }
+static inline char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name,
+ unsigned int *size)
+{ return NULL; }
+#endif
+
+#endif
diff --git a/drivers/hid/intel-ish-hid/ipc/hw-ish.h b/drivers/hid/intel-ish-hid/ipc/hw-ish.h
index da133716bed0..08a8327dfd22 100644
--- a/drivers/hid/intel-ish-hid/ipc/hw-ish.h
+++ b/drivers/hid/intel-ish-hid/ipc/hw-ish.h
@@ -29,6 +29,7 @@
#define CNL_Ax_DEVICE_ID 0x9DFC
#define GLK_Ax_DEVICE_ID 0x31A2
#define CNL_H_DEVICE_ID 0xA37C
+#define ICL_MOBILE_DEVICE_ID 0x34FC
#define SPT_H_DEVICE_ID 0xA135
#define REVISION_ID_CHT_A0 0x6
diff --git a/drivers/hid/intel-ish-hid/ipc/ipc.c b/drivers/hid/intel-ish-hid/ipc/ipc.c
index bfbca7ec54ce..742191bb24c6 100644
--- a/drivers/hid/intel-ish-hid/ipc/ipc.c
+++ b/drivers/hid/intel-ish-hid/ipc/ipc.c
@@ -280,14 +280,14 @@ static int write_ipc_from_queue(struct ishtp_device *dev)
* if tx send list is empty - return 0;
* may happen, as RX_COMPLETE handler doesn't check list emptiness.
*/
- if (list_empty(&dev->wr_processing_list_head.link)) {
+ if (list_empty(&dev->wr_processing_list)) {
spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
out_ipc_locked = 0;
return 0;
}
- ipc_link = list_entry(dev->wr_processing_list_head.link.next,
- struct wr_msg_ctl_info, link);
+ ipc_link = list_first_entry(&dev->wr_processing_list,
+ struct wr_msg_ctl_info, link);
/* first 4 bytes of the data is the doorbell value (IPC header) */
length = ipc_link->length - sizeof(uint32_t);
doorbell_val = *(uint32_t *)ipc_link->inline_data;
@@ -338,7 +338,7 @@ static int write_ipc_from_queue(struct ishtp_device *dev)
ipc_send_compl = ipc_link->ipc_send_compl;
ipc_send_compl_prm = ipc_link->ipc_send_compl_prm;
list_del_init(&ipc_link->link);
- list_add_tail(&ipc_link->link, &dev->wr_free_list_head.link);
+ list_add(&ipc_link->link, &dev->wr_free_list);
spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
/*
@@ -372,18 +372,18 @@ static int write_ipc_to_queue(struct ishtp_device *dev,
unsigned char *msg, int length)
{
struct wr_msg_ctl_info *ipc_link;
- unsigned long flags;
+ unsigned long flags;
if (length > IPC_FULL_MSG_SIZE)
return -EMSGSIZE;
spin_lock_irqsave(&dev->wr_processing_spinlock, flags);
- if (list_empty(&dev->wr_free_list_head.link)) {
+ if (list_empty(&dev->wr_free_list)) {
spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
return -ENOMEM;
}
- ipc_link = list_entry(dev->wr_free_list_head.link.next,
- struct wr_msg_ctl_info, link);
+ ipc_link = list_first_entry(&dev->wr_free_list,
+ struct wr_msg_ctl_info, link);
list_del_init(&ipc_link->link);
ipc_link->ipc_send_compl = ipc_send_compl;
@@ -391,7 +391,7 @@ static int write_ipc_to_queue(struct ishtp_device *dev,
ipc_link->length = length;
memcpy(ipc_link->inline_data, msg, length);
- list_add_tail(&ipc_link->link, &dev->wr_processing_list_head.link);
+ list_add_tail(&ipc_link->link, &dev->wr_processing_list);
spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
write_ipc_from_queue(dev);
@@ -487,17 +487,13 @@ static int ish_fw_reset_handler(struct ishtp_device *dev)
{
uint32_t reset_id;
unsigned long flags;
- struct wr_msg_ctl_info *processing, *next;
/* Read reset ID */
reset_id = ish_reg_read(dev, IPC_REG_ISH2HOST_MSG) & 0xFFFF;
/* Clear IPC output queue */
spin_lock_irqsave(&dev->wr_processing_spinlock, flags);
- list_for_each_entry_safe(processing, next,
- &dev->wr_processing_list_head.link, link) {
- list_move_tail(&processing->link, &dev->wr_free_list_head.link);
- }
+ list_splice_init(&dev->wr_processing_list, &dev->wr_free_list);
spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
/* ISHTP notification in IPC_RESET */
@@ -921,9 +917,9 @@ struct ishtp_device *ish_dev_init(struct pci_dev *pdev)
spin_lock_init(&dev->out_ipc_spinlock);
/* Init IPC processing and free lists */
- INIT_LIST_HEAD(&dev->wr_processing_list_head.link);
- INIT_LIST_HEAD(&dev->wr_free_list_head.link);
- for (i = 0; i < IPC_TX_FIFO_SIZE; ++i) {
+ INIT_LIST_HEAD(&dev->wr_processing_list);
+ INIT_LIST_HEAD(&dev->wr_free_list);
+ for (i = 0; i < IPC_TX_FIFO_SIZE; i++) {
struct wr_msg_ctl_info *tx_buf;
tx_buf = devm_kzalloc(&pdev->dev,
@@ -939,7 +935,7 @@ struct ishtp_device *ish_dev_init(struct pci_dev *pdev)
i);
break;
}
- list_add_tail(&tx_buf->link, &dev->wr_free_list_head.link);
+ list_add_tail(&tx_buf->link, &dev->wr_free_list);
}
dev->ops = &ish_hw_ops;
diff --git a/drivers/hid/intel-ish-hid/ipc/pci-ish.c b/drivers/hid/intel-ish-hid/ipc/pci-ish.c
index a1125a5c7965..8793cc49f855 100644
--- a/drivers/hid/intel-ish-hid/ipc/pci-ish.c
+++ b/drivers/hid/intel-ish-hid/ipc/pci-ish.c
@@ -38,6 +38,7 @@ static const struct pci_device_id ish_pci_tbl[] = {
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, CNL_Ax_DEVICE_ID)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, GLK_Ax_DEVICE_ID)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, CNL_H_DEVICE_ID)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, ICL_MOBILE_DEVICE_ID)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, SPT_H_DEVICE_ID)},
{0, }
};
@@ -114,18 +115,19 @@ static const struct pci_device_id ish_invalid_pci_ids[] = {
*/
static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
- struct ishtp_device *dev;
+ int ret;
struct ish_hw *hw;
- int ret;
+ struct ishtp_device *ishtp;
+ struct device *dev = &pdev->dev;
/* Check for invalid platforms for ISH support */
if (pci_dev_present(ish_invalid_pci_ids))
return -ENODEV;
/* enable pci dev */
- ret = pci_enable_device(pdev);
+ ret = pcim_enable_device(pdev);
if (ret) {
- dev_err(&pdev->dev, "ISH: Failed to enable PCI device\n");
+ dev_err(dev, "ISH: Failed to enable PCI device\n");
return ret;
}
@@ -133,65 +135,44 @@ static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_master(pdev);
/* pci request regions for ISH driver */
- ret = pci_request_regions(pdev, KBUILD_MODNAME);
+ ret = pcim_iomap_regions(pdev, 1 << 0, KBUILD_MODNAME);
if (ret) {
- dev_err(&pdev->dev, "ISH: Failed to get PCI regions\n");
- goto disable_device;
+ dev_err(dev, "ISH: Failed to get PCI regions\n");
+ return ret;
}
/* allocates and initializes the ISH dev structure */
- dev = ish_dev_init(pdev);
- if (!dev) {
+ ishtp = ish_dev_init(pdev);
+ if (!ishtp) {
ret = -ENOMEM;
- goto release_regions;
+ return ret;
}
- hw = to_ish_hw(dev);
- dev->print_log = ish_event_tracer;
+ hw = to_ish_hw(ishtp);
+ ishtp->print_log = ish_event_tracer;
/* mapping IO device memory */
- hw->mem_addr = pci_iomap(pdev, 0, 0);
- if (!hw->mem_addr) {
- dev_err(&pdev->dev, "ISH: mapping I/O range failure\n");
- ret = -ENOMEM;
- goto free_device;
- }
-
- dev->pdev = pdev;
-
+ hw->mem_addr = pcim_iomap_table(pdev)[0];
+ ishtp->pdev = pdev;
pdev->dev_flags |= PCI_DEV_FLAGS_NO_D3;
/* request and enable interrupt */
- ret = request_irq(pdev->irq, ish_irq_handler, IRQF_SHARED,
- KBUILD_MODNAME, dev);
+ ret = devm_request_irq(dev, pdev->irq, ish_irq_handler,
+ IRQF_SHARED, KBUILD_MODNAME, ishtp);
if (ret) {
- dev_err(&pdev->dev, "ISH: request IRQ failure (%d)\n",
- pdev->irq);
- goto free_device;
+ dev_err(dev, "ISH: request IRQ %d failed\n", pdev->irq);
+ return ret;
}
- dev_set_drvdata(dev->devc, dev);
+ dev_set_drvdata(ishtp->devc, ishtp);
- init_waitqueue_head(&dev->suspend_wait);
- init_waitqueue_head(&dev->resume_wait);
+ init_waitqueue_head(&ishtp->suspend_wait);
+ init_waitqueue_head(&ishtp->resume_wait);
- ret = ish_init(dev);
+ ret = ish_init(ishtp);
if (ret)
- goto free_irq;
+ return ret;
return 0;
-
-free_irq:
- free_irq(pdev->irq, dev);
-free_device:
- pci_iounmap(pdev, hw->mem_addr);
-release_regions:
- pci_release_regions(pdev);
-disable_device:
- pci_clear_master(pdev);
- pci_disable_device(pdev);
- dev_err(&pdev->dev, "ISH: PCI driver initialization failed.\n");
-
- return ret;
}
/**
@@ -203,16 +184,9 @@ disable_device:
static void ish_remove(struct pci_dev *pdev)
{
struct ishtp_device *ishtp_dev = pci_get_drvdata(pdev);
- struct ish_hw *hw = to_ish_hw(ishtp_dev);
ishtp_bus_remove_all_clients(ishtp_dev, false);
ish_device_disable(ishtp_dev);
-
- free_irq(pdev->irq, ishtp_dev);
- pci_iounmap(pdev, hw->mem_addr);
- pci_release_regions(pdev);
- pci_clear_master(pdev);
- pci_disable_device(pdev);
}
static struct device __maybe_unused *ish_resume_device;
diff --git a/drivers/hid/intel-ish-hid/ishtp-hid-client.c b/drivers/hid/intel-ish-hid/ishtp-hid-client.c
index 2d28cffc1404..e64243bc9c96 100644
--- a/drivers/hid/intel-ish-hid/ishtp-hid-client.c
+++ b/drivers/hid/intel-ish-hid/ishtp-hid-client.c
@@ -320,23 +320,14 @@ do_get_report:
*/
static void ish_cl_event_cb(struct ishtp_cl_device *device)
{
- struct ishtp_cl *hid_ishtp_cl = device->driver_data;
+ struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(device);
struct ishtp_cl_rb *rb_in_proc;
size_t r_length;
- unsigned long flags;
if (!hid_ishtp_cl)
return;
- spin_lock_irqsave(&hid_ishtp_cl->in_process_spinlock, flags);
- while (!list_empty(&hid_ishtp_cl->in_process_list.list)) {
- rb_in_proc = list_entry(
- hid_ishtp_cl->in_process_list.list.next,
- struct ishtp_cl_rb, list);
- list_del_init(&rb_in_proc->list);
- spin_unlock_irqrestore(&hid_ishtp_cl->in_process_spinlock,
- flags);
-
+ while ((rb_in_proc = ishtp_cl_rx_get_rb(hid_ishtp_cl)) != NULL) {
if (!rb_in_proc->buffer.data)
return;
@@ -346,9 +337,7 @@ static void ish_cl_event_cb(struct ishtp_cl_device *device)
process_recv(hid_ishtp_cl, rb_in_proc->buffer.data, r_length);
ishtp_cl_io_rb_recycle(rb_in_proc);
- spin_lock_irqsave(&hid_ishtp_cl->in_process_spinlock, flags);
}
- spin_unlock_irqrestore(&hid_ishtp_cl->in_process_spinlock, flags);
}
/**
@@ -637,8 +626,8 @@ static int ishtp_get_report_descriptor(struct ishtp_cl *hid_ishtp_cl,
static int hid_ishtp_cl_init(struct ishtp_cl *hid_ishtp_cl, int reset)
{
struct ishtp_device *dev;
- unsigned long flags;
struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
+ struct ishtp_fw_client *fw_client;
int i;
int rv;
@@ -660,16 +649,14 @@ static int hid_ishtp_cl_init(struct ishtp_cl *hid_ishtp_cl, int reset)
hid_ishtp_cl->rx_ring_size = HID_CL_RX_RING_SIZE;
hid_ishtp_cl->tx_ring_size = HID_CL_TX_RING_SIZE;
- spin_lock_irqsave(&dev->fw_clients_lock, flags);
- i = ishtp_fw_cl_by_uuid(dev, &hid_ishtp_guid);
- if (i < 0) {
- spin_unlock_irqrestore(&dev->fw_clients_lock, flags);
+ fw_client = ishtp_fw_cl_get_client(dev, &hid_ishtp_guid);
+ if (!fw_client) {
dev_err(&client_data->cl_device->dev,
"ish client uuid not found\n");
- return i;
+ return -ENOENT;
}
- hid_ishtp_cl->fw_client_id = dev->fw_clients[i].client_id;
- spin_unlock_irqrestore(&dev->fw_clients_lock, flags);
+
+ hid_ishtp_cl->fw_client_id = fw_client->client_id;
hid_ishtp_cl->state = ISHTP_CL_CONNECTING;
rv = ishtp_cl_connect(hid_ishtp_cl);
@@ -765,7 +752,7 @@ static void hid_ishtp_cl_reset_handler(struct work_struct *work)
if (!hid_ishtp_cl)
return;
- cl_device->driver_data = hid_ishtp_cl;
+ ishtp_set_drvdata(cl_device, hid_ishtp_cl);
hid_ishtp_cl->client_data = client_data;
client_data->hid_ishtp_cl = hid_ishtp_cl;
@@ -814,7 +801,7 @@ static int hid_ishtp_cl_probe(struct ishtp_cl_device *cl_device)
if (!hid_ishtp_cl)
return -ENOMEM;
- cl_device->driver_data = hid_ishtp_cl;
+ ishtp_set_drvdata(cl_device, hid_ishtp_cl);
hid_ishtp_cl->client_data = client_data;
client_data->hid_ishtp_cl = hid_ishtp_cl;
client_data->cl_device = cl_device;
@@ -844,7 +831,7 @@ static int hid_ishtp_cl_probe(struct ishtp_cl_device *cl_device)
*/
static int hid_ishtp_cl_remove(struct ishtp_cl_device *cl_device)
{
- struct ishtp_cl *hid_ishtp_cl = cl_device->driver_data;
+ struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device);
struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
@@ -874,7 +861,7 @@ static int hid_ishtp_cl_remove(struct ishtp_cl_device *cl_device)
*/
static int hid_ishtp_cl_reset(struct ishtp_cl_device *cl_device)
{
- struct ishtp_cl *hid_ishtp_cl = cl_device->driver_data;
+ struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device);
struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
@@ -898,7 +885,7 @@ static int hid_ishtp_cl_reset(struct ishtp_cl_device *cl_device)
static int hid_ishtp_cl_suspend(struct device *device)
{
struct ishtp_cl_device *cl_device = to_ishtp_cl_device(device);
- struct ishtp_cl *hid_ishtp_cl = cl_device->driver_data;
+ struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device);
struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
@@ -919,7 +906,7 @@ static int hid_ishtp_cl_suspend(struct device *device)
static int hid_ishtp_cl_resume(struct device *device)
{
struct ishtp_cl_device *cl_device = to_ishtp_cl_device(device);
- struct ishtp_cl *hid_ishtp_cl = cl_device->driver_data;
+ struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device);
struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
diff --git a/drivers/hid/intel-ish-hid/ishtp/bus.c b/drivers/hid/intel-ish-hid/ishtp/bus.c
index 2623a567ffba..728dc6d4561a 100644
--- a/drivers/hid/intel-ish-hid/ishtp/bus.c
+++ b/drivers/hid/intel-ish-hid/ishtp/bus.c
@@ -149,6 +149,31 @@ int ishtp_fw_cl_by_uuid(struct ishtp_device *dev, const uuid_le *uuid)
EXPORT_SYMBOL(ishtp_fw_cl_by_uuid);
/**
+ * ishtp_fw_cl_get_client() - return client information to client
+ * @dev: the ishtp device structure
+ * @uuid: uuid of the client to search
+ *
+ * Search firmware client using UUID and reture related client information.
+ *
+ * Return: pointer of client information on success, NULL on failure.
+ */
+struct ishtp_fw_client *ishtp_fw_cl_get_client(struct ishtp_device *dev,
+ const uuid_le *uuid)
+{
+ int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->fw_clients_lock, flags);
+ i = ishtp_fw_cl_by_uuid(dev, uuid);
+ spin_unlock_irqrestore(&dev->fw_clients_lock, flags);
+ if (i < 0 || dev->fw_clients[i].props.fixed_address)
+ return NULL;
+
+ return &dev->fw_clients[i];
+}
+EXPORT_SYMBOL(ishtp_fw_cl_get_client);
+
+/**
* ishtp_fw_cl_by_id() - return index to fw_clients for client_id
* @dev: the ishtp device structure
* @client_id: fw client id to search
@@ -564,6 +589,33 @@ void ishtp_put_device(struct ishtp_cl_device *cl_device)
EXPORT_SYMBOL(ishtp_put_device);
/**
+ * ishtp_set_drvdata() - set client driver data
+ * @cl_device: client device instance
+ * @data: driver data need to be set
+ *
+ * Set client driver data to cl_device->driver_data.
+ */
+void ishtp_set_drvdata(struct ishtp_cl_device *cl_device, void *data)
+{
+ cl_device->driver_data = data;
+}
+EXPORT_SYMBOL(ishtp_set_drvdata);
+
+/**
+ * ishtp_get_drvdata() - get client driver data
+ * @cl_device: client device instance
+ *
+ * Get client driver data from cl_device->driver_data.
+ *
+ * Return: pointer of driver data
+ */
+void *ishtp_get_drvdata(struct ishtp_cl_device *cl_device)
+{
+ return cl_device->driver_data;
+}
+EXPORT_SYMBOL(ishtp_get_drvdata);
+
+/**
* ishtp_bus_new_client() - Create a new client
* @dev: ISHTP device instance
*
diff --git a/drivers/hid/intel-ish-hid/ishtp/bus.h b/drivers/hid/intel-ish-hid/ishtp/bus.h
index a1ffae7f26ad..b8a5bcc82536 100644
--- a/drivers/hid/intel-ish-hid/ishtp/bus.h
+++ b/drivers/hid/intel-ish-hid/ishtp/bus.h
@@ -101,6 +101,9 @@ void ishtp_reset_compl_handler(struct ishtp_device *dev);
void ishtp_put_device(struct ishtp_cl_device *);
void ishtp_get_device(struct ishtp_cl_device *);
+void ishtp_set_drvdata(struct ishtp_cl_device *cl_device, void *data);
+void *ishtp_get_drvdata(struct ishtp_cl_device *cl_device);
+
int __ishtp_cl_driver_register(struct ishtp_cl_driver *driver,
struct module *owner);
#define ishtp_cl_driver_register(driver) \
@@ -110,5 +113,7 @@ void ishtp_cl_driver_unregister(struct ishtp_cl_driver *driver);
int ishtp_register_event_cb(struct ishtp_cl_device *device,
void (*read_cb)(struct ishtp_cl_device *));
int ishtp_fw_cl_by_uuid(struct ishtp_device *dev, const uuid_le *cuuid);
+struct ishtp_fw_client *ishtp_fw_cl_get_client(struct ishtp_device *dev,
+ const uuid_le *uuid);
#endif /* _LINUX_ISHTP_CL_BUS_H */
diff --git a/drivers/hid/intel-ish-hid/ishtp/client-buffers.c b/drivers/hid/intel-ish-hid/ishtp/client-buffers.c
index b9b917d2d50d..248651c35497 100644
--- a/drivers/hid/intel-ish-hid/ishtp/client-buffers.c
+++ b/drivers/hid/intel-ish-hid/ishtp/client-buffers.c
@@ -69,6 +69,8 @@ int ishtp_cl_alloc_tx_ring(struct ishtp_cl *cl)
int j;
unsigned long flags;
+ cl->tx_ring_free_size = 0;
+
/* Allocate pool to free Tx bufs */
for (j = 0; j < cl->tx_ring_size; ++j) {
struct ishtp_cl_tx_ring *tx_buf;
@@ -85,6 +87,7 @@ int ishtp_cl_alloc_tx_ring(struct ishtp_cl *cl)
spin_lock_irqsave(&cl->tx_free_list_spinlock, flags);
list_add_tail(&tx_buf->list, &cl->tx_free_list.list);
+ ++cl->tx_ring_free_size;
spin_unlock_irqrestore(&cl->tx_free_list_spinlock, flags);
}
return 0;
@@ -144,6 +147,7 @@ void ishtp_cl_free_tx_ring(struct ishtp_cl *cl)
tx_buf = list_entry(cl->tx_free_list.list.next,
struct ishtp_cl_tx_ring, list);
list_del(&tx_buf->list);
+ --cl->tx_ring_free_size;
kfree(tx_buf->send_buf.data);
kfree(tx_buf);
}
@@ -255,3 +259,48 @@ int ishtp_cl_io_rb_recycle(struct ishtp_cl_rb *rb)
return rets;
}
EXPORT_SYMBOL(ishtp_cl_io_rb_recycle);
+
+/**
+ * ishtp_cl_tx_empty() -test whether client device tx buffer is empty
+ * @cl: Pointer to client device instance
+ *
+ * Look client device tx buffer list, and check whether this list is empty
+ *
+ * Return: true if client tx buffer list is empty else false
+ */
+bool ishtp_cl_tx_empty(struct ishtp_cl *cl)
+{
+ int tx_list_empty;
+ unsigned long tx_flags;
+
+ spin_lock_irqsave(&cl->tx_list_spinlock, tx_flags);
+ tx_list_empty = list_empty(&cl->tx_list.list);
+ spin_unlock_irqrestore(&cl->tx_list_spinlock, tx_flags);
+
+ return !!tx_list_empty;
+}
+EXPORT_SYMBOL(ishtp_cl_tx_empty);
+
+/**
+ * ishtp_cl_rx_get_rb() -Get a rb from client device rx buffer list
+ * @cl: Pointer to client device instance
+ *
+ * Check client device in-processing buffer list and get a rb from it.
+ *
+ * Return: rb pointer if buffer list isn't empty else NULL
+ */
+struct ishtp_cl_rb *ishtp_cl_rx_get_rb(struct ishtp_cl *cl)
+{
+ unsigned long rx_flags;
+ struct ishtp_cl_rb *rb;
+
+ spin_lock_irqsave(&cl->in_process_spinlock, rx_flags);
+ rb = list_first_entry_or_null(&cl->in_process_list.list,
+ struct ishtp_cl_rb, list);
+ if (rb)
+ list_del_init(&rb->list);
+ spin_unlock_irqrestore(&cl->in_process_spinlock, rx_flags);
+
+ return rb;
+}
+EXPORT_SYMBOL(ishtp_cl_rx_get_rb);
diff --git a/drivers/hid/intel-ish-hid/ishtp/client.c b/drivers/hid/intel-ish-hid/ishtp/client.c
index 007443ef5fca..faeccdb1475b 100644
--- a/drivers/hid/intel-ish-hid/ishtp/client.c
+++ b/drivers/hid/intel-ish-hid/ishtp/client.c
@@ -22,6 +22,25 @@
#include "hbm.h"
#include "client.h"
+int ishtp_cl_get_tx_free_buffer_size(struct ishtp_cl *cl)
+{
+ unsigned long tx_free_flags;
+ int size;
+
+ spin_lock_irqsave(&cl->tx_free_list_spinlock, tx_free_flags);
+ size = cl->tx_ring_free_size * cl->device->fw_client->props.max_msg_length;
+ spin_unlock_irqrestore(&cl->tx_free_list_spinlock, tx_free_flags);
+
+ return size;
+}
+EXPORT_SYMBOL(ishtp_cl_get_tx_free_buffer_size);
+
+int ishtp_cl_get_tx_free_rings(struct ishtp_cl *cl)
+{
+ return cl->tx_ring_free_size;
+}
+EXPORT_SYMBOL(ishtp_cl_get_tx_free_rings);
+
/**
* ishtp_read_list_flush() - Flush read queue
* @cl: ishtp client instance
@@ -90,6 +109,7 @@ static void ishtp_cl_init(struct ishtp_cl *cl, struct ishtp_device *dev)
cl->rx_ring_size = CL_DEF_RX_RING_SIZE;
cl->tx_ring_size = CL_DEF_TX_RING_SIZE;
+ cl->tx_ring_free_size = cl->tx_ring_size;
/* dma */
cl->last_tx_path = CL_TX_PATH_IPC;
@@ -577,6 +597,8 @@ int ishtp_cl_send(struct ishtp_cl *cl, uint8_t *buf, size_t length)
* max ISHTP message size per client
*/
list_del_init(&cl_msg->list);
+ --cl->tx_ring_free_size;
+
spin_unlock_irqrestore(&cl->tx_free_list_spinlock, tx_free_flags);
memcpy(cl_msg->send_buf.data, buf, length);
cl_msg->send_buf.size = length;
@@ -685,6 +707,7 @@ static void ipc_tx_callback(void *prm)
ishtp_write_message(dev, &ishtp_hdr, pmsg);
spin_lock_irqsave(&cl->tx_free_list_spinlock, tx_free_flags);
list_add_tail(&cl_msg->list, &cl->tx_free_list.list);
+ ++cl->tx_ring_free_size;
spin_unlock_irqrestore(&cl->tx_free_list_spinlock,
tx_free_flags);
} else {
@@ -778,6 +801,7 @@ static void ishtp_cl_send_msg_dma(struct ishtp_device *dev,
ishtp_write_message(dev, &hdr, (unsigned char *)&dma_xfer);
spin_lock_irqsave(&cl->tx_free_list_spinlock, tx_free_flags);
list_add_tail(&cl_msg->list, &cl->tx_free_list.list);
+ ++cl->tx_ring_free_size;
spin_unlock_irqrestore(&cl->tx_free_list_spinlock, tx_free_flags);
++cl->send_msg_cnt_dma;
}
diff --git a/drivers/hid/intel-ish-hid/ishtp/client.h b/drivers/hid/intel-ish-hid/ishtp/client.h
index 79eade547f5d..042f4c4853b1 100644
--- a/drivers/hid/intel-ish-hid/ishtp/client.h
+++ b/drivers/hid/intel-ish-hid/ishtp/client.h
@@ -84,6 +84,7 @@ struct ishtp_cl {
/* Client Tx buffers list */
unsigned int tx_ring_size;
struct ishtp_cl_tx_ring tx_list, tx_free_list;
+ int tx_ring_free_size;
spinlock_t tx_list_spinlock;
spinlock_t tx_free_list_spinlock;
size_t tx_offs; /* Offset in buffer at head of 'tx_list' */
@@ -137,6 +138,8 @@ int ishtp_cl_alloc_rx_ring(struct ishtp_cl *cl);
int ishtp_cl_alloc_tx_ring(struct ishtp_cl *cl);
void ishtp_cl_free_rx_ring(struct ishtp_cl *cl);
void ishtp_cl_free_tx_ring(struct ishtp_cl *cl);
+int ishtp_cl_get_tx_free_buffer_size(struct ishtp_cl *cl);
+int ishtp_cl_get_tx_free_rings(struct ishtp_cl *cl);
/* DMA I/F functions */
void recv_ishtp_cl_msg_dma(struct ishtp_device *dev, void *msg,
@@ -178,5 +181,7 @@ int ishtp_cl_flush_queues(struct ishtp_cl *cl);
/* exported functions from ISHTP client buffer management scope */
int ishtp_cl_io_rb_recycle(struct ishtp_cl_rb *rb);
+bool ishtp_cl_tx_empty(struct ishtp_cl *cl);
+struct ishtp_cl_rb *ishtp_cl_rx_get_rb(struct ishtp_cl *cl);
#endif /* _ISHTP_CLIENT_H_ */
diff --git a/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h b/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h
index 6a6d927b78b0..e7c6bfefaf9e 100644
--- a/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h
+++ b/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h
@@ -207,7 +207,7 @@ struct ishtp_device {
struct work_struct bh_hbm_work;
/* IPC write queue */
- struct wr_msg_ctl_info wr_processing_list_head, wr_free_list_head;
+ struct list_head wr_processing_list, wr_free_list;
/* For both processing list and free list */
spinlock_t wr_processing_spinlock;
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c
index 23872d08308c..a746017fac17 100644
--- a/drivers/hid/usbhid/hiddev.c
+++ b/drivers/hid/usbhid/hiddev.c
@@ -512,14 +512,24 @@ static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd,
if (cmd == HIDIOCGCOLLECTIONINDEX) {
if (uref->usage_index >= field->maxusage)
goto inval;
+ uref->usage_index =
+ array_index_nospec(uref->usage_index,
+ field->maxusage);
} else if (uref->usage_index >= field->report_count)
goto inval;
}
- if ((cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) &&
- (uref_multi->num_values > HID_MAX_MULTI_USAGES ||
- uref->usage_index + uref_multi->num_values > field->report_count))
- goto inval;
+ if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
+ if (uref_multi->num_values > HID_MAX_MULTI_USAGES ||
+ uref->usage_index + uref_multi->num_values >
+ field->report_count)
+ goto inval;
+
+ uref->usage_index =
+ array_index_nospec(uref->usage_index,
+ field->report_count -
+ uref_multi->num_values);
+ }
switch (cmd) {
case HIDIOCGUSAGE:
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index e0a06be5ef5c..5dd3a8245f0f 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -3335,6 +3335,7 @@ static void wacom_setup_intuos(struct wacom_wac *wacom_wac)
void wacom_setup_device_quirks(struct wacom *wacom)
{
+ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
struct wacom_features *features = &wacom->wacom_wac.features;
/* The pen and pad share the same interface on most devices */
@@ -3464,6 +3465,24 @@ void wacom_setup_device_quirks(struct wacom *wacom)
if (features->type == REMOTE)
features->device_type |= WACOM_DEVICETYPE_WL_MONITOR;
+
+ /* HID descriptor for DTK-2451 / DTH-2452 claims to report lots
+ * of things it shouldn't. Lets fix up the damage...
+ */
+ if (wacom->hdev->product == 0x382 || wacom->hdev->product == 0x37d) {
+ features->quirks &= ~WACOM_QUIRK_TOOLSERIAL;
+ __clear_bit(BTN_TOOL_BRUSH, wacom_wac->pen_input->keybit);
+ __clear_bit(BTN_TOOL_PENCIL, wacom_wac->pen_input->keybit);
+ __clear_bit(BTN_TOOL_AIRBRUSH, wacom_wac->pen_input->keybit);
+ __clear_bit(ABS_Z, wacom_wac->pen_input->absbit);
+ __clear_bit(ABS_DISTANCE, wacom_wac->pen_input->absbit);
+ __clear_bit(ABS_TILT_X, wacom_wac->pen_input->absbit);
+ __clear_bit(ABS_TILT_Y, wacom_wac->pen_input->absbit);
+ __clear_bit(ABS_WHEEL, wacom_wac->pen_input->absbit);
+ __clear_bit(ABS_MISC, wacom_wac->pen_input->absbit);
+ __clear_bit(MSC_SERIAL, wacom_wac->pen_input->mscbit);
+ __clear_bit(EV_MSC, wacom_wac->pen_input->evbit);
+ }
}
int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c
index 741857d80da1..de8193f3b838 100644
--- a/drivers/hv/channel.c
+++ b/drivers/hv/channel.c
@@ -79,85 +79,96 @@ void vmbus_setevent(struct vmbus_channel *channel)
}
EXPORT_SYMBOL_GPL(vmbus_setevent);
-/*
- * vmbus_open - Open the specified channel.
- */
-int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
- u32 recv_ringbuffer_size, void *userdata, u32 userdatalen,
- void (*onchannelcallback)(void *context), void *context)
+/* vmbus_free_ring - drop mapping of ring buffer */
+void vmbus_free_ring(struct vmbus_channel *channel)
+{
+ hv_ringbuffer_cleanup(&channel->outbound);
+ hv_ringbuffer_cleanup(&channel->inbound);
+
+ if (channel->ringbuffer_page) {
+ __free_pages(channel->ringbuffer_page,
+ get_order(channel->ringbuffer_pagecount
+ << PAGE_SHIFT));
+ channel->ringbuffer_page = NULL;
+ }
+}
+EXPORT_SYMBOL_GPL(vmbus_free_ring);
+
+/* vmbus_alloc_ring - allocate and map pages for ring buffer */
+int vmbus_alloc_ring(struct vmbus_channel *newchannel,
+ u32 send_size, u32 recv_size)
+{
+ struct page *page;
+ int order;
+
+ if (send_size % PAGE_SIZE || recv_size % PAGE_SIZE)
+ return -EINVAL;
+
+ /* Allocate the ring buffer */
+ order = get_order(send_size + recv_size);
+ page = alloc_pages_node(cpu_to_node(newchannel->target_cpu),
+ GFP_KERNEL|__GFP_ZERO, order);
+
+ if (!page)
+ page = alloc_pages(GFP_KERNEL|__GFP_ZERO, order);
+
+ if (!page)
+ return -ENOMEM;
+
+ newchannel->ringbuffer_page = page;
+ newchannel->ringbuffer_pagecount = (send_size + recv_size) >> PAGE_SHIFT;
+ newchannel->ringbuffer_send_offset = send_size >> PAGE_SHIFT;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(vmbus_alloc_ring);
+
+static int __vmbus_open(struct vmbus_channel *newchannel,
+ void *userdata, u32 userdatalen,
+ void (*onchannelcallback)(void *context), void *context)
{
struct vmbus_channel_open_channel *open_msg;
struct vmbus_channel_msginfo *open_info = NULL;
+ struct page *page = newchannel->ringbuffer_page;
+ u32 send_pages, recv_pages;
unsigned long flags;
- int ret, err = 0;
- struct page *page;
+ int err;
- if (send_ringbuffer_size % PAGE_SIZE ||
- recv_ringbuffer_size % PAGE_SIZE)
+ if (userdatalen > MAX_USER_DEFINED_BYTES)
return -EINVAL;
+ send_pages = newchannel->ringbuffer_send_offset;
+ recv_pages = newchannel->ringbuffer_pagecount - send_pages;
+
spin_lock_irqsave(&newchannel->lock, flags);
- if (newchannel->state == CHANNEL_OPEN_STATE) {
- newchannel->state = CHANNEL_OPENING_STATE;
- } else {
+ if (newchannel->state != CHANNEL_OPEN_STATE) {
spin_unlock_irqrestore(&newchannel->lock, flags);
return -EINVAL;
}
spin_unlock_irqrestore(&newchannel->lock, flags);
+ newchannel->state = CHANNEL_OPENING_STATE;
newchannel->onchannel_callback = onchannelcallback;
newchannel->channel_callback_context = context;
- /* Allocate the ring buffer */
- page = alloc_pages_node(cpu_to_node(newchannel->target_cpu),
- GFP_KERNEL|__GFP_ZERO,
- get_order(send_ringbuffer_size +
- recv_ringbuffer_size));
-
- if (!page)
- page = alloc_pages(GFP_KERNEL|__GFP_ZERO,
- get_order(send_ringbuffer_size +
- recv_ringbuffer_size));
-
- if (!page) {
- err = -ENOMEM;
- goto error_set_chnstate;
- }
-
- newchannel->ringbuffer_pages = page_address(page);
- newchannel->ringbuffer_pagecount = (send_ringbuffer_size +
- recv_ringbuffer_size) >> PAGE_SHIFT;
-
- ret = hv_ringbuffer_init(&newchannel->outbound, page,
- send_ringbuffer_size >> PAGE_SHIFT);
-
- if (ret != 0) {
- err = ret;
- goto error_free_pages;
- }
-
- ret = hv_ringbuffer_init(&newchannel->inbound,
- &page[send_ringbuffer_size >> PAGE_SHIFT],
- recv_ringbuffer_size >> PAGE_SHIFT);
- if (ret != 0) {
- err = ret;
- goto error_free_pages;
- }
+ err = hv_ringbuffer_init(&newchannel->outbound, page, send_pages);
+ if (err)
+ goto error_clean_ring;
+ err = hv_ringbuffer_init(&newchannel->inbound,
+ &page[send_pages], recv_pages);
+ if (err)
+ goto error_clean_ring;
/* Establish the gpadl for the ring buffer */
newchannel->ringbuffer_gpadlhandle = 0;
- ret = vmbus_establish_gpadl(newchannel,
- page_address(page),
- send_ringbuffer_size +
- recv_ringbuffer_size,
+ err = vmbus_establish_gpadl(newchannel,
+ page_address(newchannel->ringbuffer_page),
+ (send_pages + recv_pages) << PAGE_SHIFT,
&newchannel->ringbuffer_gpadlhandle);
-
- if (ret != 0) {
- err = ret;
- goto error_free_pages;
- }
+ if (err)
+ goto error_clean_ring;
/* Create and init the channel open message */
open_info = kmalloc(sizeof(*open_info) +
@@ -176,15 +187,9 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
open_msg->openid = newchannel->offermsg.child_relid;
open_msg->child_relid = newchannel->offermsg.child_relid;
open_msg->ringbuffer_gpadlhandle = newchannel->ringbuffer_gpadlhandle;
- open_msg->downstream_ringbuffer_pageoffset = send_ringbuffer_size >>
- PAGE_SHIFT;
+ open_msg->downstream_ringbuffer_pageoffset = newchannel->ringbuffer_send_offset;
open_msg->target_vp = newchannel->target_vp;
- if (userdatalen > MAX_USER_DEFINED_BYTES) {
- err = -EINVAL;
- goto error_free_gpadl;
- }
-
if (userdatalen)
memcpy(open_msg->userdata, userdata, userdatalen);
@@ -195,18 +200,16 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
if (newchannel->rescind) {
err = -ENODEV;
- goto error_free_gpadl;
+ goto error_free_info;
}
- ret = vmbus_post_msg(open_msg,
+ err = vmbus_post_msg(open_msg,
sizeof(struct vmbus_channel_open_channel), true);
- trace_vmbus_open(open_msg, ret);
+ trace_vmbus_open(open_msg, err);
- if (ret != 0) {
- err = ret;
+ if (err != 0)
goto error_clean_msglist;
- }
wait_for_completion(&open_info->waitevent);
@@ -216,12 +219,12 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
if (newchannel->rescind) {
err = -ENODEV;
- goto error_free_gpadl;
+ goto error_free_info;
}
if (open_info->response.open_result.status) {
err = -EAGAIN;
- goto error_free_gpadl;
+ goto error_free_info;
}
newchannel->state = CHANNEL_OPENED_STATE;
@@ -232,19 +235,50 @@ error_clean_msglist:
spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
list_del(&open_info->msglistentry);
spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
-
+error_free_info:
+ kfree(open_info);
error_free_gpadl:
vmbus_teardown_gpadl(newchannel, newchannel->ringbuffer_gpadlhandle);
- kfree(open_info);
-error_free_pages:
+ newchannel->ringbuffer_gpadlhandle = 0;
+error_clean_ring:
hv_ringbuffer_cleanup(&newchannel->outbound);
hv_ringbuffer_cleanup(&newchannel->inbound);
- __free_pages(page,
- get_order(send_ringbuffer_size + recv_ringbuffer_size));
-error_set_chnstate:
newchannel->state = CHANNEL_OPEN_STATE;
return err;
}
+
+/*
+ * vmbus_connect_ring - Open the channel but reuse ring buffer
+ */
+int vmbus_connect_ring(struct vmbus_channel *newchannel,
+ void (*onchannelcallback)(void *context), void *context)
+{
+ return __vmbus_open(newchannel, NULL, 0, onchannelcallback, context);
+}
+EXPORT_SYMBOL_GPL(vmbus_connect_ring);
+
+/*
+ * vmbus_open - Open the specified channel.
+ */
+int vmbus_open(struct vmbus_channel *newchannel,
+ u32 send_ringbuffer_size, u32 recv_ringbuffer_size,
+ void *userdata, u32 userdatalen,
+ void (*onchannelcallback)(void *context), void *context)
+{
+ int err;
+
+ err = vmbus_alloc_ring(newchannel, send_ringbuffer_size,
+ recv_ringbuffer_size);
+ if (err)
+ return err;
+
+ err = __vmbus_open(newchannel, userdata, userdatalen,
+ onchannelcallback, context);
+ if (err)
+ vmbus_free_ring(newchannel);
+
+ return err;
+}
EXPORT_SYMBOL_GPL(vmbus_open);
/* Used for Hyper-V Socket: a guest client's connect() to the host */
@@ -612,10 +646,8 @@ static int vmbus_close_internal(struct vmbus_channel *channel)
* in Hyper-V Manager), the driver's remove() invokes vmbus_close():
* here we should skip most of the below cleanup work.
*/
- if (channel->state != CHANNEL_OPENED_STATE) {
- ret = -EINVAL;
- goto out;
- }
+ if (channel->state != CHANNEL_OPENED_STATE)
+ return -EINVAL;
channel->state = CHANNEL_OPEN_STATE;
@@ -637,11 +669,10 @@ static int vmbus_close_internal(struct vmbus_channel *channel)
* If we failed to post the close msg,
* it is perhaps better to leak memory.
*/
- goto out;
}
/* Tear down the gpadl for the channel's ring buffer */
- if (channel->ringbuffer_gpadlhandle) {
+ else if (channel->ringbuffer_gpadlhandle) {
ret = vmbus_teardown_gpadl(channel,
channel->ringbuffer_gpadlhandle);
if (ret) {
@@ -650,74 +681,78 @@ static int vmbus_close_internal(struct vmbus_channel *channel)
* If we failed to teardown gpadl,
* it is perhaps better to leak memory.
*/
- goto out;
}
- }
-
- /* Cleanup the ring buffers for this channel */
- hv_ringbuffer_cleanup(&channel->outbound);
- hv_ringbuffer_cleanup(&channel->inbound);
- free_pages((unsigned long)channel->ringbuffer_pages,
- get_order(channel->ringbuffer_pagecount * PAGE_SIZE));
+ channel->ringbuffer_gpadlhandle = 0;
+ }
-out:
return ret;
}
-/*
- * vmbus_close - Close the specified channel
- */
-void vmbus_close(struct vmbus_channel *channel)
+/* disconnect ring - close all channels */
+int vmbus_disconnect_ring(struct vmbus_channel *channel)
{
- struct list_head *cur, *tmp;
- struct vmbus_channel *cur_channel;
+ struct vmbus_channel *cur_channel, *tmp;
+ unsigned long flags;
+ LIST_HEAD(list);
+ int ret;
- if (channel->primary_channel != NULL) {
- /*
- * We will only close sub-channels when
- * the primary is closed.
- */
- return;
- }
- /*
- * Close all the sub-channels first and then close the
- * primary channel.
- */
- list_for_each_safe(cur, tmp, &channel->sc_list) {
- cur_channel = list_entry(cur, struct vmbus_channel, sc_list);
- if (cur_channel->rescind) {
+ if (channel->primary_channel != NULL)
+ return -EINVAL;
+
+ /* Snapshot the list of subchannels */
+ spin_lock_irqsave(&channel->lock, flags);
+ list_splice_init(&channel->sc_list, &list);
+ channel->num_sc = 0;
+ spin_unlock_irqrestore(&channel->lock, flags);
+
+ list_for_each_entry_safe(cur_channel, tmp, &list, sc_list) {
+ if (cur_channel->rescind)
wait_for_completion(&cur_channel->rescind_event);
- mutex_lock(&vmbus_connection.channel_mutex);
- vmbus_close_internal(cur_channel);
- hv_process_channel_removal(
- cur_channel->offermsg.child_relid);
- } else {
- mutex_lock(&vmbus_connection.channel_mutex);
- vmbus_close_internal(cur_channel);
+
+ mutex_lock(&vmbus_connection.channel_mutex);
+ if (vmbus_close_internal(cur_channel) == 0) {
+ vmbus_free_ring(cur_channel);
+
+ if (cur_channel->rescind)
+ hv_process_channel_removal(cur_channel);
}
mutex_unlock(&vmbus_connection.channel_mutex);
}
+
/*
* Now close the primary.
*/
mutex_lock(&vmbus_connection.channel_mutex);
- vmbus_close_internal(channel);
+ ret = vmbus_close_internal(channel);
mutex_unlock(&vmbus_connection.channel_mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(vmbus_disconnect_ring);
+
+/*
+ * vmbus_close - Close the specified channel
+ */
+void vmbus_close(struct vmbus_channel *channel)
+{
+ if (vmbus_disconnect_ring(channel) == 0)
+ vmbus_free_ring(channel);
}
EXPORT_SYMBOL_GPL(vmbus_close);
/**
* vmbus_sendpacket() - Send the specified buffer on the given channel
- * @channel: Pointer to vmbus_channel structure.
- * @buffer: Pointer to the buffer you want to receive the data into.
- * @bufferlen: Maximum size of what the the buffer will hold
+ * @channel: Pointer to vmbus_channel structure
+ * @buffer: Pointer to the buffer you want to send the data from.
+ * @bufferlen: Maximum size of what the buffer holds.
* @requestid: Identifier of the request
- * @type: Type of packet that is being send e.g. negotiate, time
- * packet etc.
+ * @type: Type of packet that is being sent e.g. negotiate, time
+ * packet etc.
+ * @flags: 0 or VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED
*
- * Sends data in @buffer directly to hyper-v via the vmbus
- * This will send the data unparsed to hyper-v.
+ * Sends data in @buffer directly to Hyper-V via the vmbus.
+ * This will send the data unparsed to Hyper-V.
*
* Mainly used by Hyper-V drivers.
*/
@@ -850,12 +885,13 @@ int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel,
EXPORT_SYMBOL_GPL(vmbus_sendpacket_mpb_desc);
/**
- * vmbus_recvpacket() - Retrieve the user packet on the specified channel
- * @channel: Pointer to vmbus_channel structure.
+ * __vmbus_recvpacket() - Retrieve the user packet on the specified channel
+ * @channel: Pointer to vmbus_channel structure
* @buffer: Pointer to the buffer you want to receive the data into.
- * @bufferlen: Maximum size of what the the buffer will hold
- * @buffer_actual_len: The actual size of the data after it was received
+ * @bufferlen: Maximum size of what the buffer can hold.
+ * @buffer_actual_len: The actual size of the data after it was received.
* @requestid: Identifier of the request
+ * @raw: true means keep the vmpacket_descriptor header in the received data.
*
* Receives directly from the hyper-v vmbus and puts the data it received
* into Buffer. This will receive the data unparsed from hyper-v.
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index 0f0e091c117c..6277597d3d58 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -198,24 +198,19 @@ static u16 hv_get_dev_type(const struct vmbus_channel *channel)
}
/**
- * vmbus_prep_negotiate_resp() - Create default response for Hyper-V Negotiate message
+ * vmbus_prep_negotiate_resp() - Create default response for Negotiate message
* @icmsghdrp: Pointer to msg header structure
- * @icmsg_negotiate: Pointer to negotiate message structure
* @buf: Raw buffer channel data
+ * @fw_version: The framework versions we can support.
+ * @fw_vercnt: The size of @fw_version.
+ * @srv_version: The service versions we can support.
+ * @srv_vercnt: The size of @srv_version.
+ * @nego_fw_version: The selected framework version.
+ * @nego_srv_version: The selected service version.
*
- * @icmsghdrp is of type &struct icmsg_hdr.
- * Set up and fill in default negotiate response message.
- *
- * The fw_version and fw_vercnt specifies the framework version that
- * we can support.
- *
- * The srv_version and srv_vercnt specifies the service
- * versions we can support.
- *
- * Versions are given in decreasing order.
- *
- * nego_fw_version and nego_srv_version store the selected protocol versions.
+ * Note: Versions are given in decreasing order.
*
+ * Set up and fill in default negotiate response message.
* Mainly used by Hyper-V drivers.
*/
bool vmbus_prep_negotiate_resp(struct icmsg_hdr *icmsghdrp,
@@ -385,21 +380,14 @@ static void vmbus_release_relid(u32 relid)
trace_vmbus_release_relid(&msg, ret);
}
-void hv_process_channel_removal(u32 relid)
+void hv_process_channel_removal(struct vmbus_channel *channel)
{
+ struct vmbus_channel *primary_channel;
unsigned long flags;
- struct vmbus_channel *primary_channel, *channel;
BUG_ON(!mutex_is_locked(&vmbus_connection.channel_mutex));
-
- /*
- * Make sure channel is valid as we may have raced.
- */
- channel = relid2channel(relid);
- if (!channel)
- return;
-
BUG_ON(!channel->rescind);
+
if (channel->target_cpu != get_cpu()) {
put_cpu();
smp_call_function_single(channel->target_cpu,
@@ -429,7 +417,7 @@ void hv_process_channel_removal(u32 relid)
cpumask_clear_cpu(channel->target_cpu,
&primary_channel->alloced_cpus_in_node);
- vmbus_release_relid(relid);
+ vmbus_release_relid(channel->offermsg.child_relid);
free_channel(channel);
}
@@ -606,16 +594,18 @@ static void init_vp_index(struct vmbus_channel *channel, u16 dev_type)
bool perf_chn = vmbus_devs[dev_type].perf_device;
struct vmbus_channel *primary = channel->primary_channel;
int next_node;
- struct cpumask available_mask;
+ cpumask_var_t available_mask;
struct cpumask *alloced_mask;
if ((vmbus_proto_version == VERSION_WS2008) ||
- (vmbus_proto_version == VERSION_WIN7) || (!perf_chn)) {
+ (vmbus_proto_version == VERSION_WIN7) || (!perf_chn) ||
+ !alloc_cpumask_var(&available_mask, GFP_KERNEL)) {
/*
* Prior to win8, all channel interrupts are
* delivered on cpu 0.
* Also if the channel is not a performance critical
* channel, bind it to cpu 0.
+ * In case alloc_cpumask_var() fails, bind it to cpu 0.
*/
channel->numa_node = 0;
channel->target_cpu = 0;
@@ -653,7 +643,7 @@ static void init_vp_index(struct vmbus_channel *channel, u16 dev_type)
cpumask_clear(alloced_mask);
}
- cpumask_xor(&available_mask, alloced_mask,
+ cpumask_xor(available_mask, alloced_mask,
cpumask_of_node(primary->numa_node));
cur_cpu = -1;
@@ -671,10 +661,10 @@ static void init_vp_index(struct vmbus_channel *channel, u16 dev_type)
}
while (true) {
- cur_cpu = cpumask_next(cur_cpu, &available_mask);
+ cur_cpu = cpumask_next(cur_cpu, available_mask);
if (cur_cpu >= nr_cpu_ids) {
cur_cpu = -1;
- cpumask_copy(&available_mask,
+ cpumask_copy(available_mask,
cpumask_of_node(primary->numa_node));
continue;
}
@@ -704,6 +694,8 @@ static void init_vp_index(struct vmbus_channel *channel, u16 dev_type)
channel->target_cpu = cur_cpu;
channel->target_vp = hv_cpu_number_to_vp_number(cur_cpu);
+
+ free_cpumask_var(available_mask);
}
static void vmbus_wait_for_unload(void)
@@ -943,7 +935,7 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
* The channel is currently not open;
* it is safe for us to cleanup the channel.
*/
- hv_process_channel_removal(rescind->child_relid);
+ hv_process_channel_removal(channel);
} else {
complete(&channel->rescind_event);
}
diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c
index ced041899456..f4d08c8ac7f8 100644
--- a/drivers/hv/connection.c
+++ b/drivers/hv/connection.c
@@ -76,6 +76,7 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo,
__u32 version)
{
int ret = 0;
+ unsigned int cur_cpu;
struct vmbus_channel_initiate_contact *msg;
unsigned long flags;
@@ -118,9 +119,10 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo,
* the CPU attempting to connect may not be CPU 0.
*/
if (version >= VERSION_WIN8_1) {
- msg->target_vcpu =
- hv_cpu_number_to_vp_number(smp_processor_id());
- vmbus_connection.connect_cpu = smp_processor_id();
+ cur_cpu = get_cpu();
+ msg->target_vcpu = hv_cpu_number_to_vp_number(cur_cpu);
+ vmbus_connection.connect_cpu = cur_cpu;
+ put_cpu();
} else {
msg->target_vcpu = 0;
vmbus_connection.connect_cpu = 0;
diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c
index 748a1c4172a6..332d7c34be5c 100644
--- a/drivers/hv/hv.c
+++ b/drivers/hv/hv.c
@@ -189,6 +189,17 @@ static void hv_init_clockevent_device(struct clock_event_device *dev, int cpu)
int hv_synic_alloc(void)
{
int cpu;
+ struct hv_per_cpu_context *hv_cpu;
+
+ /*
+ * First, zero all per-cpu memory areas so hv_synic_free() can
+ * detect what memory has been allocated and cleanup properly
+ * after any failures.
+ */
+ for_each_present_cpu(cpu) {
+ hv_cpu = per_cpu_ptr(hv_context.cpu_context, cpu);
+ memset(hv_cpu, 0, sizeof(*hv_cpu));
+ }
hv_context.hv_numa_map = kcalloc(nr_node_ids, sizeof(struct cpumask),
GFP_KERNEL);
@@ -198,10 +209,8 @@ int hv_synic_alloc(void)
}
for_each_present_cpu(cpu) {
- struct hv_per_cpu_context *hv_cpu
- = per_cpu_ptr(hv_context.cpu_context, cpu);
+ hv_cpu = per_cpu_ptr(hv_context.cpu_context, cpu);
- memset(hv_cpu, 0, sizeof(*hv_cpu));
tasklet_init(&hv_cpu->msg_dpc,
vmbus_on_msg_dpc, (unsigned long) hv_cpu);
diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c
index b1b788082793..41631512ae97 100644
--- a/drivers/hv/hv_balloon.c
+++ b/drivers/hv/hv_balloon.c
@@ -689,7 +689,7 @@ static void hv_page_online_one(struct hv_hotadd_state *has, struct page *pg)
__online_page_increment_counters(pg);
__online_page_free(pg);
- WARN_ON_ONCE(!spin_is_locked(&dm_device.ha_lock));
+ lockdep_assert_held(&dm_device.ha_lock);
dm_device.num_pages_onlined++;
}
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index 5eed1e7da15c..a7513a8a8e37 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -353,7 +353,6 @@ static void process_ib_ipinfo(void *in_msg, void *out_msg, int op)
out->body.kvp_ip_val.dhcp_enabled = in->kvp_ip_val.dhcp_enabled;
- default:
utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.adapter_id,
MAX_ADAPTER_ID_SIZE,
UTF16_LITTLE_ENDIAN,
@@ -406,7 +405,7 @@ kvp_send_key(struct work_struct *dummy)
process_ib_ipinfo(in_msg, message, KVP_OP_SET_IP_INFO);
break;
case KVP_OP_GET_IP_INFO:
- process_ib_ipinfo(in_msg, message, KVP_OP_GET_IP_INFO);
+ /* We only need to pass on message->kvp_hdr.operation. */
break;
case KVP_OP_SET:
switch (in_msg->body.kvp_set.data.value_type) {
@@ -421,7 +420,7 @@ kvp_send_key(struct work_struct *dummy)
UTF16_LITTLE_ENDIAN,
message->body.kvp_set.data.value,
HV_KVP_EXCHANGE_MAX_VALUE_SIZE - 1) + 1;
- break;
+ break;
case REG_U32:
/*
@@ -446,6 +445,9 @@ kvp_send_key(struct work_struct *dummy)
break;
}
+
+ break;
+
case KVP_OP_GET:
message->body.kvp_set.data.key_size =
utf16s_to_utf8s(
@@ -454,7 +456,7 @@ kvp_send_key(struct work_struct *dummy)
UTF16_LITTLE_ENDIAN,
message->body.kvp_set.data.key,
HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1) + 1;
- break;
+ break;
case KVP_OP_DELETE:
message->body.kvp_delete.key_size =
@@ -464,12 +466,12 @@ kvp_send_key(struct work_struct *dummy)
UTF16_LITTLE_ENDIAN,
message->body.kvp_delete.key,
HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1) + 1;
- break;
+ break;
case KVP_OP_ENUMERATE:
message->body.kvp_enum_data.index =
in_msg->body.kvp_enum_data.index;
- break;
+ break;
}
kvp_transaction.state = HVUTIL_USERSPACE_REQ;
diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c
index 3e90eb91db45..64d0c85d5161 100644
--- a/drivers/hv/ring_buffer.c
+++ b/drivers/hv/ring_buffer.c
@@ -241,6 +241,7 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info,
void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info)
{
vunmap(ring_info->ring_buffer);
+ ring_info->ring_buffer = NULL;
}
/* Write to the ring buffer. */
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index c71cc857b649..283d184280af 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -498,6 +498,54 @@ static ssize_t device_show(struct device *dev,
}
static DEVICE_ATTR_RO(device);
+static ssize_t driver_override_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct hv_device *hv_dev = device_to_hv_device(dev);
+ char *driver_override, *old, *cp;
+
+ /* We need to keep extra room for a newline */
+ if (count >= (PAGE_SIZE - 1))
+ return -EINVAL;
+
+ driver_override = kstrndup(buf, count, GFP_KERNEL);
+ if (!driver_override)
+ return -ENOMEM;
+
+ cp = strchr(driver_override, '\n');
+ if (cp)
+ *cp = '\0';
+
+ device_lock(dev);
+ old = hv_dev->driver_override;
+ if (strlen(driver_override)) {
+ hv_dev->driver_override = driver_override;
+ } else {
+ kfree(driver_override);
+ hv_dev->driver_override = NULL;
+ }
+ device_unlock(dev);
+
+ kfree(old);
+
+ return count;
+}
+
+static ssize_t driver_override_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct hv_device *hv_dev = device_to_hv_device(dev);
+ ssize_t len;
+
+ device_lock(dev);
+ len = snprintf(buf, PAGE_SIZE, "%s\n", hv_dev->driver_override);
+ device_unlock(dev);
+
+ return len;
+}
+static DEVICE_ATTR_RW(driver_override);
+
/* Set up per device attributes in /sys/bus/vmbus/devices/<bus device> */
static struct attribute *vmbus_dev_attrs[] = {
&dev_attr_id.attr,
@@ -528,6 +576,7 @@ static struct attribute *vmbus_dev_attrs[] = {
&dev_attr_channel_vp_mapping.attr,
&dev_attr_vendor.attr,
&dev_attr_device.attr,
+ &dev_attr_driver_override.attr,
NULL,
};
ATTRIBUTE_GROUPS(vmbus_dev);
@@ -563,17 +612,26 @@ static inline bool is_null_guid(const uuid_le *guid)
return true;
}
-/*
- * Return a matching hv_vmbus_device_id pointer.
- * If there is no match, return NULL.
- */
-static const struct hv_vmbus_device_id *hv_vmbus_get_id(struct hv_driver *drv,
- const uuid_le *guid)
+static const struct hv_vmbus_device_id *
+hv_vmbus_dev_match(const struct hv_vmbus_device_id *id, const uuid_le *guid)
+
+{
+ if (id == NULL)
+ return NULL; /* empty device table */
+
+ for (; !is_null_guid(&id->guid); id++)
+ if (!uuid_le_cmp(id->guid, *guid))
+ return id;
+
+ return NULL;
+}
+
+static const struct hv_vmbus_device_id *
+hv_vmbus_dynid_match(struct hv_driver *drv, const uuid_le *guid)
{
const struct hv_vmbus_device_id *id = NULL;
struct vmbus_dynid *dynid;
- /* Look at the dynamic ids first, before the static ones */
spin_lock(&drv->dynids.lock);
list_for_each_entry(dynid, &drv->dynids.list, node) {
if (!uuid_le_cmp(dynid->id.guid, *guid)) {
@@ -583,18 +641,37 @@ static const struct hv_vmbus_device_id *hv_vmbus_get_id(struct hv_driver *drv,
}
spin_unlock(&drv->dynids.lock);
- if (id)
- return id;
+ return id;
+}
- id = drv->id_table;
- if (id == NULL)
- return NULL; /* empty device table */
+static const struct hv_vmbus_device_id vmbus_device_null = {
+ .guid = NULL_UUID_LE,
+};
- for (; !is_null_guid(&id->guid); id++)
- if (!uuid_le_cmp(id->guid, *guid))
- return id;
+/*
+ * Return a matching hv_vmbus_device_id pointer.
+ * If there is no match, return NULL.
+ */
+static const struct hv_vmbus_device_id *hv_vmbus_get_id(struct hv_driver *drv,
+ struct hv_device *dev)
+{
+ const uuid_le *guid = &dev->dev_type;
+ const struct hv_vmbus_device_id *id;
- return NULL;
+ /* When driver_override is set, only bind to the matching driver */
+ if (dev->driver_override && strcmp(dev->driver_override, drv->name))
+ return NULL;
+
+ /* Look at the dynamic ids first, before the static ones */
+ id = hv_vmbus_dynid_match(drv, guid);
+ if (!id)
+ id = hv_vmbus_dev_match(drv->id_table, guid);
+
+ /* driver_override will always match, send a dummy id */
+ if (!id && dev->driver_override)
+ id = &vmbus_device_null;
+
+ return id;
}
/* vmbus_add_dynid - add a new device ID to this driver and re-probe devices */
@@ -643,7 +720,7 @@ static ssize_t new_id_store(struct device_driver *driver, const char *buf,
if (retval)
return retval;
- if (hv_vmbus_get_id(drv, &guid))
+ if (hv_vmbus_dynid_match(drv, &guid))
return -EEXIST;
retval = vmbus_add_dynid(drv, &guid);
@@ -708,7 +785,7 @@ static int vmbus_match(struct device *device, struct device_driver *driver)
if (is_hvsock_channel(hv_dev->channel))
return drv->hvsock;
- if (hv_vmbus_get_id(drv, &hv_dev->dev_type))
+ if (hv_vmbus_get_id(drv, hv_dev))
return 1;
return 0;
@@ -725,7 +802,7 @@ static int vmbus_probe(struct device *child_device)
struct hv_device *dev = device_to_hv_device(child_device);
const struct hv_vmbus_device_id *dev_id;
- dev_id = hv_vmbus_get_id(drv, &dev->dev_type);
+ dev_id = hv_vmbus_get_id(drv, dev);
if (drv->probe) {
ret = drv->probe(dev, dev_id);
if (ret != 0)
@@ -787,10 +864,9 @@ static void vmbus_device_release(struct device *device)
struct vmbus_channel *channel = hv_dev->channel;
mutex_lock(&vmbus_connection.channel_mutex);
- hv_process_channel_removal(channel->offermsg.child_relid);
+ hv_process_channel_removal(channel);
mutex_unlock(&vmbus_connection.channel_mutex);
kfree(hv_dev);
-
}
/* The one and only one */
diff --git a/drivers/hwmon/aspeed-pwm-tacho.c b/drivers/hwmon/aspeed-pwm-tacho.c
index 5e449eac788a..92de8139d398 100644
--- a/drivers/hwmon/aspeed-pwm-tacho.c
+++ b/drivers/hwmon/aspeed-pwm-tacho.c
@@ -852,7 +852,7 @@ static int aspeed_create_pwm_cooling(struct device *dev,
dev_err(dev, "Property 'cooling-levels' cannot be read.\n");
return ret;
}
- snprintf(cdev->name, MAX_CDEV_NAME_LEN, "%s%d", child->name, pwm_port);
+ snprintf(cdev->name, MAX_CDEV_NAME_LEN, "%pOFn%d", child, pwm_port);
cdev->tcdev = thermal_of_cooling_device_register(child,
cdev->name,
diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c
index a6636fe42189..a7cf00885c5d 100644
--- a/drivers/hwmon/asus_atk0110.c
+++ b/drivers/hwmon/asus_atk0110.c
@@ -1210,10 +1210,8 @@ static int atk_register_hwmon(struct atk_data *data)
data->hwmon_dev = hwmon_device_register_with_groups(dev, "atk0110",
data,
data->attr_groups);
- if (IS_ERR(data->hwmon_dev))
- return PTR_ERR(data->hwmon_dev);
- return 0;
+ return PTR_ERR_OR_ZERO(data->hwmon_dev);
}
static int atk_probe_if(struct atk_data *data)
diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c
index 33d51281272b..84f61cec6319 100644
--- a/drivers/hwmon/hwmon.c
+++ b/drivers/hwmon/hwmon.c
@@ -24,6 +24,9 @@
#include <linux/string.h>
#include <linux/thermal.h>
+#define CREATE_TRACE_POINTS
+#include <trace/events/hwmon.h>
+
#define HWMON_ID_PREFIX "hwmon"
#define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d"
@@ -171,6 +174,13 @@ static int hwmon_thermal_add_sensor(struct device *dev,
}
#endif /* IS_REACHABLE(CONFIG_THERMAL) && ... */
+static int hwmon_attr_base(enum hwmon_sensor_types type)
+{
+ if (type == hwmon_in)
+ return 0;
+ return 1;
+}
+
/* sysfs attribute management */
static ssize_t hwmon_attr_show(struct device *dev,
@@ -185,6 +195,9 @@ static ssize_t hwmon_attr_show(struct device *dev,
if (ret < 0)
return ret;
+ trace_hwmon_attr_show(hattr->index + hwmon_attr_base(hattr->type),
+ hattr->name, val);
+
return sprintf(buf, "%ld\n", val);
}
@@ -193,6 +206,7 @@ static ssize_t hwmon_attr_show_string(struct device *dev,
char *buf)
{
struct hwmon_device_attribute *hattr = to_hwmon_attr(devattr);
+ enum hwmon_sensor_types type = hattr->type;
const char *s;
int ret;
@@ -201,6 +215,9 @@ static ssize_t hwmon_attr_show_string(struct device *dev,
if (ret < 0)
return ret;
+ trace_hwmon_attr_show_string(hattr->index + hwmon_attr_base(type),
+ hattr->name, s);
+
return sprintf(buf, "%s\n", s);
}
@@ -221,14 +238,10 @@ static ssize_t hwmon_attr_store(struct device *dev,
if (ret < 0)
return ret;
- return count;
-}
+ trace_hwmon_attr_store(hattr->index + hwmon_attr_base(hattr->type),
+ hattr->name, val);
-static int hwmon_attr_base(enum hwmon_sensor_types type)
-{
- if (type == hwmon_in)
- return 0;
- return 1;
+ return count;
}
static bool is_string_attr(enum hwmon_sensor_types type, u32 attr)
@@ -356,6 +369,7 @@ static const char * const hwmon_in_attr_templates[] = {
[hwmon_in_max_alarm] = "in%d_max_alarm",
[hwmon_in_lcrit_alarm] = "in%d_lcrit_alarm",
[hwmon_in_crit_alarm] = "in%d_crit_alarm",
+ [hwmon_in_enable] = "in%d_enable",
};
static const char * const hwmon_curr_attr_templates[] = {
@@ -635,8 +649,10 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata,
if (info[i]->config[j] & HWMON_T_INPUT) {
err = hwmon_thermal_add_sensor(dev,
hwdev, j);
- if (err)
- goto free_device;
+ if (err) {
+ device_unregister(hdev);
+ goto ida_remove;
+ }
}
}
}
@@ -644,8 +660,6 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata,
return hdev;
-free_device:
- device_unregister(hdev);
free_hwmon:
kfree(hwdev);
ida_remove:
diff --git a/drivers/hwmon/ibmaem.c b/drivers/hwmon/ibmaem.c
index 1f643782ce04..9e92673f6913 100644
--- a/drivers/hwmon/ibmaem.c
+++ b/drivers/hwmon/ibmaem.c
@@ -101,7 +101,7 @@ static struct platform_driver aem_driver = {
struct aem_ipmi_data {
struct completion read_complete;
struct ipmi_addr address;
- ipmi_user_t user;
+ struct ipmi_user *user;
int interface;
struct kernel_ipmi_msg tx_message;
diff --git a/drivers/hwmon/ibmpex.c b/drivers/hwmon/ibmpex.c
index ab72cabf5a95..bb17a29af64c 100644
--- a/drivers/hwmon/ibmpex.c
+++ b/drivers/hwmon/ibmpex.c
@@ -84,7 +84,7 @@ struct ibmpex_bmc_data {
struct ipmi_addr address;
struct completion read_complete;
- ipmi_user_t user;
+ struct ipmi_user *user;
int interface;
struct kernel_ipmi_msg tx_message;
diff --git a/drivers/hwmon/ibmpowernv.c b/drivers/hwmon/ibmpowernv.c
index 83472808c816..293dd1c6c7b3 100644
--- a/drivers/hwmon/ibmpowernv.c
+++ b/drivers/hwmon/ibmpowernv.c
@@ -181,7 +181,7 @@ static ssize_t show_label(struct device *dev, struct device_attribute *devattr,
return sprintf(buf, "%s\n", sdata->label);
}
-static int __init get_logical_cpu(int hwcpu)
+static int get_logical_cpu(int hwcpu)
{
int cpu;
@@ -192,9 +192,8 @@ static int __init get_logical_cpu(int hwcpu)
return -ENOENT;
}
-static void __init make_sensor_label(struct device_node *np,
- struct sensor_data *sdata,
- const char *label)
+static void make_sensor_label(struct device_node *np,
+ struct sensor_data *sdata, const char *label)
{
u32 id;
size_t n;
@@ -458,9 +457,6 @@ static int populate_attr_groups(struct platform_device *pdev)
for_each_child_of_node(opal, np) {
const char *label;
- if (np->name == NULL)
- continue;
-
type = get_sensor_type(np);
if (type == MAX_SENSOR_TYPE)
continue;
@@ -589,9 +585,6 @@ static int create_device_attrs(struct platform_device *pdev)
const char *label;
enum sensors type;
- if (np->name == NULL)
- continue;
-
type = get_sensor_type(np);
if (type == MAX_SENSOR_TYPE)
continue;
@@ -603,8 +596,8 @@ static int create_device_attrs(struct platform_device *pdev)
if (of_property_read_u32(np, "sensor-id", &sensor_id) &&
of_property_read_u32(np, "sensor-data", &sensor_id)) {
dev_info(&pdev->dev,
- "'sensor-id' missing in the node '%s'\n",
- np->name);
+ "'sensor-id' missing in the node '%pOFn'\n",
+ np);
continue;
}
diff --git a/drivers/hwmon/iio_hwmon.c b/drivers/hwmon/iio_hwmon.c
index 2f3f875c06ac..eed66e533ee2 100644
--- a/drivers/hwmon/iio_hwmon.c
+++ b/drivers/hwmon/iio_hwmon.c
@@ -65,13 +65,9 @@ static int iio_hwmon_probe(struct platform_device *pdev)
int in_i = 1, temp_i = 1, curr_i = 1, humidity_i = 1;
enum iio_chan_type type;
struct iio_channel *channels;
- const char *name = "iio_hwmon";
struct device *hwmon_dev;
char *sname;
- if (dev->of_node && dev->of_node->name)
- name = dev->of_node->name;
-
channels = devm_iio_channel_get_all(dev);
if (IS_ERR(channels)) {
if (PTR_ERR(channels) == -ENODEV)
@@ -141,11 +137,15 @@ static int iio_hwmon_probe(struct platform_device *pdev)
st->attr_group.attrs = st->attrs;
st->groups[0] = &st->attr_group;
- sname = devm_kstrdup(dev, name, GFP_KERNEL);
- if (!sname)
- return -ENOMEM;
+ if (dev->of_node) {
+ sname = devm_kasprintf(dev, GFP_KERNEL, "%pOFn", dev->of_node);
+ if (!sname)
+ return -ENOMEM;
+ strreplace(sname, '-', '_');
+ } else {
+ sname = "iio_hwmon";
+ }
- strreplace(sname, '-', '_');
hwmon_dev = devm_hwmon_device_register_with_groups(dev, sname, st,
st->groups);
return PTR_ERR_OR_ZERO(hwmon_dev);
diff --git a/drivers/hwmon/ina3221.c b/drivers/hwmon/ina3221.c
index e6b49500c52a..d61688f04594 100644
--- a/drivers/hwmon/ina3221.c
+++ b/drivers/hwmon/ina3221.c
@@ -38,9 +38,12 @@
#define INA3221_WARN3 0x0c
#define INA3221_MASK_ENABLE 0x0f
-#define INA3221_CONFIG_MODE_SHUNT BIT(1)
-#define INA3221_CONFIG_MODE_BUS BIT(2)
-#define INA3221_CONFIG_MODE_CONTINUOUS BIT(3)
+#define INA3221_CONFIG_MODE_MASK GENMASK(2, 0)
+#define INA3221_CONFIG_MODE_POWERDOWN 0
+#define INA3221_CONFIG_MODE_SHUNT BIT(0)
+#define INA3221_CONFIG_MODE_BUS BIT(1)
+#define INA3221_CONFIG_MODE_CONTINUOUS BIT(2)
+#define INA3221_CONFIG_CHx_EN(x) BIT(14 - (x))
#define INA3221_RSHUNT_DEFAULT 10000
@@ -74,30 +77,37 @@ enum ina3221_channels {
INA3221_NUM_CHANNELS
};
-static const unsigned int register_channel[] = {
- [INA3221_SHUNT1] = INA3221_CHANNEL1,
- [INA3221_SHUNT2] = INA3221_CHANNEL2,
- [INA3221_SHUNT3] = INA3221_CHANNEL3,
- [INA3221_CRIT1] = INA3221_CHANNEL1,
- [INA3221_CRIT2] = INA3221_CHANNEL2,
- [INA3221_CRIT3] = INA3221_CHANNEL3,
- [INA3221_WARN1] = INA3221_CHANNEL1,
- [INA3221_WARN2] = INA3221_CHANNEL2,
- [INA3221_WARN3] = INA3221_CHANNEL3,
+/**
+ * struct ina3221_input - channel input source specific information
+ * @label: label of channel input source
+ * @shunt_resistor: shunt resistor value of channel input source
+ * @disconnected: connection status of channel input source
+ */
+struct ina3221_input {
+ const char *label;
+ int shunt_resistor;
+ bool disconnected;
};
/**
* struct ina3221_data - device specific information
* @regmap: Register map of the device
* @fields: Register fields of the device
- * @shunt_resistors: Array of resistor values per channel
+ * @inputs: Array of channel input source specific structures
+ * @reg_config: Register value of INA3221_CONFIG
*/
struct ina3221_data {
struct regmap *regmap;
struct regmap_field *fields[F_MAX_FIELDS];
- int shunt_resistors[INA3221_NUM_CHANNELS];
+ struct ina3221_input inputs[INA3221_NUM_CHANNELS];
+ u32 reg_config;
};
+static inline bool ina3221_is_enabled(struct ina3221_data *ina, int channel)
+{
+ return ina->reg_config & INA3221_CONFIG_CHx_EN(channel);
+}
+
static int ina3221_read_value(struct ina3221_data *ina, unsigned int reg,
int *val)
{
@@ -113,107 +123,284 @@ static int ina3221_read_value(struct ina3221_data *ina, unsigned int reg,
return 0;
}
-static ssize_t ina3221_show_bus_voltage(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static const u8 ina3221_in_reg[] = {
+ INA3221_BUS1,
+ INA3221_BUS2,
+ INA3221_BUS3,
+ INA3221_SHUNT1,
+ INA3221_SHUNT2,
+ INA3221_SHUNT3,
+};
+
+static int ina3221_read_in(struct device *dev, u32 attr, int channel, long *val)
{
- struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
+ const bool is_shunt = channel > INA3221_CHANNEL3;
struct ina3221_data *ina = dev_get_drvdata(dev);
- unsigned int reg = sd_attr->index;
- int val, voltage_mv, ret;
-
- ret = ina3221_read_value(ina, reg, &val);
- if (ret)
- return ret;
+ u8 reg = ina3221_in_reg[channel];
+ int regval, ret;
+
+ /* Translate shunt channel index to sensor channel index */
+ channel %= INA3221_NUM_CHANNELS;
+
+ switch (attr) {
+ case hwmon_in_input:
+ if (!ina3221_is_enabled(ina, channel))
+ return -ENODATA;
+
+ ret = ina3221_read_value(ina, reg, &regval);
+ if (ret)
+ return ret;
+
+ /*
+ * Scale of shunt voltage (uV): LSB is 40uV
+ * Scale of bus voltage (mV): LSB is 8mV
+ */
+ *val = regval * (is_shunt ? 40 : 8);
+ return 0;
+ case hwmon_in_enable:
+ *val = ina3221_is_enabled(ina, channel);
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
- voltage_mv = val * 8;
+static const u8 ina3221_curr_reg[][INA3221_NUM_CHANNELS] = {
+ [hwmon_curr_input] = { INA3221_SHUNT1, INA3221_SHUNT2, INA3221_SHUNT3 },
+ [hwmon_curr_max] = { INA3221_WARN1, INA3221_WARN2, INA3221_WARN3 },
+ [hwmon_curr_crit] = { INA3221_CRIT1, INA3221_CRIT2, INA3221_CRIT3 },
+ [hwmon_curr_max_alarm] = { F_WF1, F_WF2, F_WF3 },
+ [hwmon_curr_crit_alarm] = { F_CF1, F_CF2, F_CF3 },
+};
- return snprintf(buf, PAGE_SIZE, "%d\n", voltage_mv);
+static int ina3221_read_curr(struct device *dev, u32 attr,
+ int channel, long *val)
+{
+ struct ina3221_data *ina = dev_get_drvdata(dev);
+ struct ina3221_input *input = &ina->inputs[channel];
+ int resistance_uo = input->shunt_resistor;
+ u8 reg = ina3221_curr_reg[attr][channel];
+ int regval, voltage_nv, ret;
+
+ switch (attr) {
+ case hwmon_curr_input:
+ if (!ina3221_is_enabled(ina, channel))
+ return -ENODATA;
+ /* fall through */
+ case hwmon_curr_crit:
+ case hwmon_curr_max:
+ ret = ina3221_read_value(ina, reg, &regval);
+ if (ret)
+ return ret;
+
+ /* Scale of shunt voltage: LSB is 40uV (40000nV) */
+ voltage_nv = regval * 40000;
+ /* Return current in mA */
+ *val = DIV_ROUND_CLOSEST(voltage_nv, resistance_uo);
+ return 0;
+ case hwmon_curr_crit_alarm:
+ case hwmon_curr_max_alarm:
+ ret = regmap_field_read(ina->fields[reg], &regval);
+ if (ret)
+ return ret;
+ *val = regval;
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
}
-static ssize_t ina3221_show_shunt_voltage(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static int ina3221_write_curr(struct device *dev, u32 attr,
+ int channel, long val)
{
- struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
struct ina3221_data *ina = dev_get_drvdata(dev);
- unsigned int reg = sd_attr->index;
- int val, voltage_uv, ret;
+ struct ina3221_input *input = &ina->inputs[channel];
+ int resistance_uo = input->shunt_resistor;
+ u8 reg = ina3221_curr_reg[attr][channel];
+ int regval, current_ma, voltage_uv;
- ret = ina3221_read_value(ina, reg, &val);
- if (ret)
- return ret;
- voltage_uv = val * 40;
+ /* clamp current */
+ current_ma = clamp_val(val,
+ INT_MIN / resistance_uo,
+ INT_MAX / resistance_uo);
+
+ voltage_uv = DIV_ROUND_CLOSEST(current_ma * resistance_uo, 1000);
- return snprintf(buf, PAGE_SIZE, "%d\n", voltage_uv);
+ /* clamp voltage */
+ voltage_uv = clamp_val(voltage_uv, -163800, 163800);
+
+ /* 1 / 40uV(scale) << 3(register shift) = 5 */
+ regval = DIV_ROUND_CLOSEST(voltage_uv, 5) & 0xfff8;
+
+ return regmap_write(ina->regmap, reg, regval);
}
-static ssize_t ina3221_show_current(struct device *dev,
- struct device_attribute *attr, char *buf)
+static int ina3221_write_enable(struct device *dev, int channel, bool enable)
{
- struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
struct ina3221_data *ina = dev_get_drvdata(dev);
- unsigned int reg = sd_attr->index;
- unsigned int channel = register_channel[reg];
- int resistance_uo = ina->shunt_resistors[channel];
- int val, current_ma, voltage_nv, ret;
+ u16 config, mask = INA3221_CONFIG_CHx_EN(channel);
+ int ret;
- ret = ina3221_read_value(ina, reg, &val);
+ config = enable ? mask : 0;
+
+ /* Enable or disable the channel */
+ ret = regmap_update_bits(ina->regmap, INA3221_CONFIG, mask, config);
if (ret)
return ret;
- voltage_nv = val * 40000;
- current_ma = DIV_ROUND_CLOSEST(voltage_nv, resistance_uo);
+ /* Cache the latest config register value */
+ ret = regmap_read(ina->regmap, INA3221_CONFIG, &ina->reg_config);
+ if (ret)
+ return ret;
- return snprintf(buf, PAGE_SIZE, "%d\n", current_ma);
+ return 0;
}
-static ssize_t ina3221_set_current(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static int ina3221_read(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ switch (type) {
+ case hwmon_in:
+ /* 0-align channel ID */
+ return ina3221_read_in(dev, attr, channel - 1, val);
+ case hwmon_curr:
+ return ina3221_read_curr(dev, attr, channel, val);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int ina3221_write(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long val)
+{
+ switch (type) {
+ case hwmon_in:
+ /* 0-align channel ID */
+ return ina3221_write_enable(dev, channel - 1, val);
+ case hwmon_curr:
+ return ina3221_write_curr(dev, attr, channel, val);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int ina3221_read_string(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, const char **str)
{
- struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
struct ina3221_data *ina = dev_get_drvdata(dev);
- unsigned int reg = sd_attr->index;
- unsigned int channel = register_channel[reg];
- int resistance_uo = ina->shunt_resistors[channel];
- int val, current_ma, voltage_uv, ret;
+ int index = channel - 1;
- ret = kstrtoint(buf, 0, &current_ma);
- if (ret)
- return ret;
+ *str = ina->inputs[index].label;
- /* clamp current */
- current_ma = clamp_val(current_ma,
- INT_MIN / resistance_uo,
- INT_MAX / resistance_uo);
+ return 0;
+}
- voltage_uv = DIV_ROUND_CLOSEST(current_ma * resistance_uo, 1000);
+static umode_t ina3221_is_visible(const void *drvdata,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ const struct ina3221_data *ina = drvdata;
+ const struct ina3221_input *input = NULL;
+
+ switch (type) {
+ case hwmon_in:
+ /* Ignore in0_ */
+ if (channel == 0)
+ return 0;
+
+ switch (attr) {
+ case hwmon_in_label:
+ if (channel - 1 <= INA3221_CHANNEL3)
+ input = &ina->inputs[channel - 1];
+ /* Hide label node if label is not provided */
+ return (input && input->label) ? 0444 : 0;
+ case hwmon_in_input:
+ return 0444;
+ case hwmon_in_enable:
+ return 0644;
+ default:
+ return 0;
+ }
+ case hwmon_curr:
+ switch (attr) {
+ case hwmon_curr_input:
+ case hwmon_curr_crit_alarm:
+ case hwmon_curr_max_alarm:
+ return 0444;
+ case hwmon_curr_crit:
+ case hwmon_curr_max:
+ return 0644;
+ default:
+ return 0;
+ }
+ default:
+ return 0;
+ }
+}
- /* clamp voltage */
- voltage_uv = clamp_val(voltage_uv, -163800, 163800);
+static const u32 ina3221_in_config[] = {
+ /* 0: dummy, skipped in is_visible */
+ HWMON_I_INPUT,
+ /* 1-3: input voltage Channels */
+ HWMON_I_INPUT | HWMON_I_ENABLE | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_ENABLE | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_ENABLE | HWMON_I_LABEL,
+ /* 4-6: shunt voltage Channels */
+ HWMON_I_INPUT,
+ HWMON_I_INPUT,
+ HWMON_I_INPUT,
+ 0
+};
- /* 1 / 40uV(scale) << 3(register shift) = 5 */
- val = DIV_ROUND_CLOSEST(voltage_uv, 5) & 0xfff8;
+static const struct hwmon_channel_info ina3221_in = {
+ .type = hwmon_in,
+ .config = ina3221_in_config,
+};
- ret = regmap_write(ina->regmap, reg, val);
- if (ret)
- return ret;
+#define INA3221_HWMON_CURR_CONFIG (HWMON_C_INPUT | \
+ HWMON_C_CRIT | HWMON_C_CRIT_ALARM | \
+ HWMON_C_MAX | HWMON_C_MAX_ALARM)
- return count;
-}
+static const u32 ina3221_curr_config[] = {
+ INA3221_HWMON_CURR_CONFIG,
+ INA3221_HWMON_CURR_CONFIG,
+ INA3221_HWMON_CURR_CONFIG,
+ 0
+};
+
+static const struct hwmon_channel_info ina3221_curr = {
+ .type = hwmon_curr,
+ .config = ina3221_curr_config,
+};
+
+static const struct hwmon_channel_info *ina3221_info[] = {
+ &ina3221_in,
+ &ina3221_curr,
+ NULL
+};
+
+static const struct hwmon_ops ina3221_hwmon_ops = {
+ .is_visible = ina3221_is_visible,
+ .read_string = ina3221_read_string,
+ .read = ina3221_read,
+ .write = ina3221_write,
+};
+static const struct hwmon_chip_info ina3221_chip_info = {
+ .ops = &ina3221_hwmon_ops,
+ .info = ina3221_info,
+};
+
+/* Extra attribute groups */
static ssize_t ina3221_show_shunt(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
struct ina3221_data *ina = dev_get_drvdata(dev);
unsigned int channel = sd_attr->index;
- unsigned int resistance_uo;
-
- resistance_uo = ina->shunt_resistors[channel];
+ struct ina3221_input *input = &ina->inputs[channel];
- return snprintf(buf, PAGE_SIZE, "%d\n", resistance_uo);
+ return snprintf(buf, PAGE_SIZE, "%d\n", input->shunt_resistor);
}
static ssize_t ina3221_set_shunt(struct device *dev,
@@ -223,6 +410,7 @@ static ssize_t ina3221_set_shunt(struct device *dev,
struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
struct ina3221_data *ina = dev_get_drvdata(dev);
unsigned int channel = sd_attr->index;
+ struct ina3221_input *input = &ina->inputs[channel];
int val;
int ret;
@@ -232,43 +420,11 @@ static ssize_t ina3221_set_shunt(struct device *dev,
val = clamp_val(val, 1, INT_MAX);
- ina->shunt_resistors[channel] = val;
+ input->shunt_resistor = val;
return count;
}
-static ssize_t ina3221_show_alert(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
- struct ina3221_data *ina = dev_get_drvdata(dev);
- unsigned int field = sd_attr->index;
- unsigned int regval;
- int ret;
-
- ret = regmap_field_read(ina->fields[field], &regval);
- if (ret)
- return ret;
-
- return snprintf(buf, PAGE_SIZE, "%d\n", regval);
-}
-
-/* bus voltage */
-static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO,
- ina3221_show_bus_voltage, NULL, INA3221_BUS1);
-static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO,
- ina3221_show_bus_voltage, NULL, INA3221_BUS2);
-static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO,
- ina3221_show_bus_voltage, NULL, INA3221_BUS3);
-
-/* calculated current */
-static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO,
- ina3221_show_current, NULL, INA3221_SHUNT1);
-static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO,
- ina3221_show_current, NULL, INA3221_SHUNT2);
-static SENSOR_DEVICE_ATTR(curr3_input, S_IRUGO,
- ina3221_show_current, NULL, INA3221_SHUNT3);
-
/* shunt resistance */
static SENSOR_DEVICE_ATTR(shunt1_resistor, S_IRUGO | S_IWUSR,
ina3221_show_shunt, ina3221_set_shunt, INA3221_CHANNEL1);
@@ -277,83 +433,16 @@ static SENSOR_DEVICE_ATTR(shunt2_resistor, S_IRUGO | S_IWUSR,
static SENSOR_DEVICE_ATTR(shunt3_resistor, S_IRUGO | S_IWUSR,
ina3221_show_shunt, ina3221_set_shunt, INA3221_CHANNEL3);
-/* critical current */
-static SENSOR_DEVICE_ATTR(curr1_crit, S_IRUGO | S_IWUSR,
- ina3221_show_current, ina3221_set_current, INA3221_CRIT1);
-static SENSOR_DEVICE_ATTR(curr2_crit, S_IRUGO | S_IWUSR,
- ina3221_show_current, ina3221_set_current, INA3221_CRIT2);
-static SENSOR_DEVICE_ATTR(curr3_crit, S_IRUGO | S_IWUSR,
- ina3221_show_current, ina3221_set_current, INA3221_CRIT3);
-
-/* critical current alert */
-static SENSOR_DEVICE_ATTR(curr1_crit_alarm, S_IRUGO,
- ina3221_show_alert, NULL, F_CF1);
-static SENSOR_DEVICE_ATTR(curr2_crit_alarm, S_IRUGO,
- ina3221_show_alert, NULL, F_CF2);
-static SENSOR_DEVICE_ATTR(curr3_crit_alarm, S_IRUGO,
- ina3221_show_alert, NULL, F_CF3);
-
-/* warning current */
-static SENSOR_DEVICE_ATTR(curr1_max, S_IRUGO | S_IWUSR,
- ina3221_show_current, ina3221_set_current, INA3221_WARN1);
-static SENSOR_DEVICE_ATTR(curr2_max, S_IRUGO | S_IWUSR,
- ina3221_show_current, ina3221_set_current, INA3221_WARN2);
-static SENSOR_DEVICE_ATTR(curr3_max, S_IRUGO | S_IWUSR,
- ina3221_show_current, ina3221_set_current, INA3221_WARN3);
-
-/* warning current alert */
-static SENSOR_DEVICE_ATTR(curr1_max_alarm, S_IRUGO,
- ina3221_show_alert, NULL, F_WF1);
-static SENSOR_DEVICE_ATTR(curr2_max_alarm, S_IRUGO,
- ina3221_show_alert, NULL, F_WF2);
-static SENSOR_DEVICE_ATTR(curr3_max_alarm, S_IRUGO,
- ina3221_show_alert, NULL, F_WF3);
-
-/* shunt voltage */
-static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO,
- ina3221_show_shunt_voltage, NULL, INA3221_SHUNT1);
-static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO,
- ina3221_show_shunt_voltage, NULL, INA3221_SHUNT2);
-static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO,
- ina3221_show_shunt_voltage, NULL, INA3221_SHUNT3);
-
static struct attribute *ina3221_attrs[] = {
- /* channel 1 */
- &sensor_dev_attr_in1_input.dev_attr.attr,
- &sensor_dev_attr_curr1_input.dev_attr.attr,
&sensor_dev_attr_shunt1_resistor.dev_attr.attr,
- &sensor_dev_attr_curr1_crit.dev_attr.attr,
- &sensor_dev_attr_curr1_crit_alarm.dev_attr.attr,
- &sensor_dev_attr_curr1_max.dev_attr.attr,
- &sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
- &sensor_dev_attr_in4_input.dev_attr.attr,
-
- /* channel 2 */
- &sensor_dev_attr_in2_input.dev_attr.attr,
- &sensor_dev_attr_curr2_input.dev_attr.attr,
&sensor_dev_attr_shunt2_resistor.dev_attr.attr,
- &sensor_dev_attr_curr2_crit.dev_attr.attr,
- &sensor_dev_attr_curr2_crit_alarm.dev_attr.attr,
- &sensor_dev_attr_curr2_max.dev_attr.attr,
- &sensor_dev_attr_curr2_max_alarm.dev_attr.attr,
- &sensor_dev_attr_in5_input.dev_attr.attr,
-
- /* channel 3 */
- &sensor_dev_attr_in3_input.dev_attr.attr,
- &sensor_dev_attr_curr3_input.dev_attr.attr,
&sensor_dev_attr_shunt3_resistor.dev_attr.attr,
- &sensor_dev_attr_curr3_crit.dev_attr.attr,
- &sensor_dev_attr_curr3_crit_alarm.dev_attr.attr,
- &sensor_dev_attr_curr3_max.dev_attr.attr,
- &sensor_dev_attr_curr3_max_alarm.dev_attr.attr,
- &sensor_dev_attr_in6_input.dev_attr.attr,
-
NULL,
};
ATTRIBUTE_GROUPS(ina3221);
static const struct regmap_range ina3221_yes_ranges[] = {
- regmap_reg_range(INA3221_SHUNT1, INA3221_BUS3),
+ regmap_reg_range(INA3221_CONFIG, INA3221_BUS3),
regmap_reg_range(INA3221_MASK_ENABLE, INA3221_MASK_ENABLE),
};
@@ -370,6 +459,66 @@ static const struct regmap_config ina3221_regmap_config = {
.volatile_table = &ina3221_volatile_table,
};
+static int ina3221_probe_child_from_dt(struct device *dev,
+ struct device_node *child,
+ struct ina3221_data *ina)
+{
+ struct ina3221_input *input;
+ u32 val;
+ int ret;
+
+ ret = of_property_read_u32(child, "reg", &val);
+ if (ret) {
+ dev_err(dev, "missing reg property of %s\n", child->name);
+ return ret;
+ } else if (val > INA3221_CHANNEL3) {
+ dev_err(dev, "invalid reg %d of %s\n", val, child->name);
+ return ret;
+ }
+
+ input = &ina->inputs[val];
+
+ /* Log the disconnected channel input */
+ if (!of_device_is_available(child)) {
+ input->disconnected = true;
+ return 0;
+ }
+
+ /* Save the connected input label if available */
+ of_property_read_string(child, "label", &input->label);
+
+ /* Overwrite default shunt resistor value optionally */
+ if (!of_property_read_u32(child, "shunt-resistor-micro-ohms", &val)) {
+ if (val < 1 || val > INT_MAX) {
+ dev_err(dev, "invalid shunt resistor value %u of %s\n",
+ val, child->name);
+ return -EINVAL;
+ }
+ input->shunt_resistor = val;
+ }
+
+ return 0;
+}
+
+static int ina3221_probe_from_dt(struct device *dev, struct ina3221_data *ina)
+{
+ const struct device_node *np = dev->of_node;
+ struct device_node *child;
+ int ret;
+
+ /* Compatible with non-DT platforms */
+ if (!np)
+ return 0;
+
+ for_each_child_of_node(np, child) {
+ ret = ina3221_probe_child_from_dt(dev, child, ina);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static int ina3221_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -399,7 +548,13 @@ static int ina3221_probe(struct i2c_client *client,
}
for (i = 0; i < INA3221_NUM_CHANNELS; i++)
- ina->shunt_resistors[i] = INA3221_RSHUNT_DEFAULT;
+ ina->inputs[i].shunt_resistor = INA3221_RSHUNT_DEFAULT;
+
+ ret = ina3221_probe_from_dt(dev, ina);
+ if (ret) {
+ dev_err(dev, "Unable to probe from device tree\n");
+ return ret;
+ }
ret = regmap_field_write(ina->fields[F_RST], true);
if (ret) {
@@ -407,9 +562,25 @@ static int ina3221_probe(struct i2c_client *client,
return ret;
}
- hwmon_dev = devm_hwmon_device_register_with_groups(dev,
- client->name,
- ina, ina3221_groups);
+ /* Sync config register after reset */
+ ret = regmap_read(ina->regmap, INA3221_CONFIG, &ina->reg_config);
+ if (ret)
+ return ret;
+
+ /* Disable channels if their inputs are disconnected */
+ for (i = 0; i < INA3221_NUM_CHANNELS; i++) {
+ if (ina->inputs[i].disconnected)
+ ina->reg_config &= ~INA3221_CONFIG_CHx_EN(i);
+ }
+ ret = regmap_write(ina->regmap, INA3221_CONFIG, ina->reg_config);
+ if (ret)
+ return ret;
+
+ dev_set_drvdata(dev, ina);
+
+ hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, ina,
+ &ina3221_chip_info,
+ ina3221_groups);
if (IS_ERR(hwmon_dev)) {
dev_err(dev, "Unable to register hwmon device\n");
return PTR_ERR(hwmon_dev);
@@ -418,6 +589,60 @@ static int ina3221_probe(struct i2c_client *client,
return 0;
}
+static int __maybe_unused ina3221_suspend(struct device *dev)
+{
+ struct ina3221_data *ina = dev_get_drvdata(dev);
+ int ret;
+
+ /* Save config register value and enable cache-only */
+ ret = regmap_read(ina->regmap, INA3221_CONFIG, &ina->reg_config);
+ if (ret)
+ return ret;
+
+ /* Set to power-down mode for power saving */
+ ret = regmap_update_bits(ina->regmap, INA3221_CONFIG,
+ INA3221_CONFIG_MODE_MASK,
+ INA3221_CONFIG_MODE_POWERDOWN);
+ if (ret)
+ return ret;
+
+ regcache_cache_only(ina->regmap, true);
+ regcache_mark_dirty(ina->regmap);
+
+ return 0;
+}
+
+static int __maybe_unused ina3221_resume(struct device *dev)
+{
+ struct ina3221_data *ina = dev_get_drvdata(dev);
+ int ret;
+
+ regcache_cache_only(ina->regmap, false);
+
+ /* Software reset the chip */
+ ret = regmap_field_write(ina->fields[F_RST], true);
+ if (ret) {
+ dev_err(dev, "Unable to reset device\n");
+ return ret;
+ }
+
+ /* Restore cached register values to hardware */
+ ret = regcache_sync(ina->regmap);
+ if (ret)
+ return ret;
+
+ /* Restore config register value to hardware */
+ ret = regmap_write(ina->regmap, INA3221_CONFIG, ina->reg_config);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static const struct dev_pm_ops ina3221_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(ina3221_suspend, ina3221_resume)
+};
+
static const struct of_device_id ina3221_of_match_table[] = {
{ .compatible = "ti,ina3221", },
{ /* sentinel */ }
@@ -435,6 +660,7 @@ static struct i2c_driver ina3221_i2c_driver = {
.driver = {
.name = INA3221_DRIVER_NAME,
.of_match_table = ina3221_of_match_table,
+ .pm = &ina3221_pm,
},
.id_table = ina3221_ids,
};
diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c
index bb15d7816a29..2cef0c37ff6f 100644
--- a/drivers/hwmon/k10temp.c
+++ b/drivers/hwmon/k10temp.c
@@ -325,8 +325,9 @@ static int k10temp_probe(struct pci_dev *pdev,
data->pdev = pdev;
- if (boot_cpu_data.x86 == 0x15 && (boot_cpu_data.x86_model == 0x60 ||
- boot_cpu_data.x86_model == 0x70)) {
+ if (boot_cpu_data.x86 == 0x15 &&
+ ((boot_cpu_data.x86_model & 0xf0) == 0x60 ||
+ (boot_cpu_data.x86_model & 0xf0) == 0x70)) {
data->read_htcreg = read_htcreg_nb_f15;
data->read_tempreg = read_tempreg_nb_f15;
} else if (boot_cpu_data.x86 == 0x17) {
diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c
index 49f4b33a5685..c7f20543b2bf 100644
--- a/drivers/hwmon/lm75.c
+++ b/drivers/hwmon/lm75.c
@@ -47,6 +47,7 @@ enum lm75_type { /* keep sorted in alphabetical order */
lm75b,
max6625,
max6626,
+ max31725,
mcp980x,
stds75,
tcn75,
@@ -64,7 +65,6 @@ enum lm75_type { /* keep sorted in alphabetical order */
static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
-
/* The LM75 registers */
#define LM75_REG_TEMP 0x00
#define LM75_REG_CONF 0x01
@@ -76,7 +76,7 @@ struct lm75_data {
struct i2c_client *client;
struct regmap *regmap;
u8 orig_conf;
- u8 resolution; /* In bits, between 9 and 12 */
+ u8 resolution; /* In bits, between 9 and 16 */
u8 resolution_limits;
unsigned int sample_time; /* In ms */
};
@@ -254,7 +254,8 @@ static const struct regmap_config lm75_regmap_config = {
.volatile_reg = lm75_is_volatile_reg,
.val_format_endian = REGMAP_ENDIAN_BIG,
.cache_type = REGCACHE_RBTREE,
- .use_single_rw = true,
+ .use_single_read = true,
+ .use_single_write = true,
};
static void lm75_remove(void *data)
@@ -339,6 +340,10 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)
data->resolution_limits = 9;
data->sample_time = MSEC_PER_SEC / 4;
break;
+ case max31725:
+ data->resolution = 16;
+ data->sample_time = MSEC_PER_SEC / 8;
+ break;
case tcn75:
data->resolution = 9;
data->sample_time = MSEC_PER_SEC / 8;
@@ -415,6 +420,8 @@ static const struct i2c_device_id lm75_ids[] = {
{ "lm75b", lm75b, },
{ "max6625", max6625, },
{ "max6626", max6626, },
+ { "max31725", max31725, },
+ { "max31726", max31725, },
{ "mcp980x", mcp980x, },
{ "stds75", stds75, },
{ "tcn75", tcn75, },
@@ -472,6 +479,14 @@ static const struct of_device_id lm75_of_match[] = {
.data = (void *)max6626
},
{
+ .compatible = "maxim,max31725",
+ .data = (void *)max31725
+ },
+ {
+ .compatible = "maxim,max31726",
+ .data = (void *)max31725
+ },
+ {
.compatible = "maxim,mcp980x",
.data = (void *)mcp980x
},
diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c
index d40fe5122e94..e7333f8e185c 100644
--- a/drivers/hwmon/lm92.c
+++ b/drivers/hwmon/lm92.c
@@ -127,8 +127,8 @@ static struct lm92_data *lm92_update_device(struct device *dev)
mutex_lock(&data->update_lock);
- if (time_after(jiffies, data->last_updated + HZ)
- || !data->valid) {
+ if (time_after(jiffies, data->last_updated + HZ) ||
+ !data->valid) {
dev_dbg(&client->dev, "Updating lm92 data\n");
for (i = 0; i < t_num_regs; i++) {
data->temp[i] =
@@ -153,7 +153,7 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
}
static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
- const char *buf, size_t count)
+ const char *buf, size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct lm92_data *data = dev_get_drvdata(dev);
@@ -161,7 +161,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
int nr = attr->index;
long val;
int err;
-
+
err = kstrtol(buf, 10, &val);
if (err)
return err;
@@ -178,6 +178,7 @@ static ssize_t show_temp_hyst(struct device *dev,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct lm92_data *data = lm92_update_device(dev);
+
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index])
- TEMP_FROM_REG(data->temp[t_hyst]));
}
@@ -186,6 +187,7 @@ static ssize_t temp1_min_hyst_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct lm92_data *data = lm92_update_device(dev);
+
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[t_min])
+ TEMP_FROM_REG(data->temp[t_hyst]));
}
@@ -206,7 +208,7 @@ static ssize_t set_temp_hyst(struct device *dev,
val = clamp_val(val, -120000, 220000);
mutex_lock(&data->update_lock);
- data->temp[t_hyst] =
+ data->temp[t_hyst] =
TEMP_TO_REG(TEMP_FROM_REG(data->temp[attr->index]) - val);
i2c_smbus_write_word_swapped(client, LM92_REG_TEMP_HYST,
data->temp[t_hyst]);
@@ -218,6 +220,7 @@ static ssize_t alarms_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct lm92_data *data = lm92_update_device(dev);
+
return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->temp[t_input]));
}
@@ -324,7 +327,6 @@ static int lm92_probe(struct i2c_client *new_client,
return PTR_ERR_OR_ZERO(hwmon_dev);
}
-
/*
* Module and driver stuff
*/
diff --git a/drivers/hwmon/lm95245.c b/drivers/hwmon/lm95245.c
index 27cb06d65594..996b50246175 100644
--- a/drivers/hwmon/lm95245.c
+++ b/drivers/hwmon/lm95245.c
@@ -541,7 +541,8 @@ static const struct regmap_config lm95245_regmap_config = {
.writeable_reg = lm95245_is_writeable_reg,
.volatile_reg = lm95245_is_volatile_reg,
.cache_type = REGCACHE_RBTREE,
- .use_single_rw = true,
+ .use_single_read = true,
+ .use_single_write = true,
};
static const u32 lm95245_chip_config[] = {
diff --git a/drivers/hwmon/mc13783-adc.c b/drivers/hwmon/mc13783-adc.c
index 78fe8759d2a9..825b922a3f92 100644
--- a/drivers/hwmon/mc13783-adc.c
+++ b/drivers/hwmon/mc13783-adc.c
@@ -1,21 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Driver for the ADC on Freescale Semiconductor MC13783 and MC13892 PMICs.
*
* Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
* Copyright (C) 2009 Sascha Hauer, Pengutronix
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/mfd/mc13xxx.h>
diff --git a/drivers/hwmon/nct6775.c b/drivers/hwmon/nct6775.c
index 78603b78cf41..c3040079b1cb 100644
--- a/drivers/hwmon/nct6775.c
+++ b/drivers/hwmon/nct6775.c
@@ -42,6 +42,10 @@
* nct6793d 15 6 6 2+6 0xd120 0xc1 0x5ca3
* nct6795d 14 6 6 2+6 0xd350 0xc1 0x5ca3
* nct6796d 14 7 7 2+6 0xd420 0xc1 0x5ca3
+ * nct6797d 14 7 7 2+6 0xd450 0xc1 0x5ca3
+ * (0xd451)
+ * nct6798d 14 7 7 2+6 0xd458 0xc1 0x5ca3
+ * (0xd459)
*
* #temp lists the number of monitored temperature sources (first value) plus
* the number of directly connectable temperature sensors (second value).
@@ -69,7 +73,7 @@
#define USE_ALTERNATE
enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791, nct6792, nct6793,
- nct6795, nct6796 };
+ nct6795, nct6796, nct6797, nct6798 };
/* used to set data->name = nct6775_device_names[data->sio_kind] */
static const char * const nct6775_device_names[] = {
@@ -82,6 +86,8 @@ static const char * const nct6775_device_names[] = {
"nct6793",
"nct6795",
"nct6796",
+ "nct6797",
+ "nct6798",
};
static const char * const nct6775_sio_names[] __initconst = {
@@ -94,6 +100,8 @@ static const char * const nct6775_sio_names[] __initconst = {
"NCT6793D",
"NCT6795D",
"NCT6796D",
+ "NCT6797D",
+ "NCT6798D",
};
static unsigned short force_id;
@@ -129,7 +137,9 @@ MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal");
#define SIO_NCT6793_ID 0xd120
#define SIO_NCT6795_ID 0xd350
#define SIO_NCT6796_ID 0xd420
-#define SIO_ID_MASK 0xFFF0
+#define SIO_NCT6797_ID 0xd450
+#define SIO_NCT6798_ID 0xd458
+#define SIO_ID_MASK 0xFFF8
enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 };
@@ -504,7 +514,7 @@ static const s8 NCT6779_BEEP_BITS[] = {
static const u16 NCT6779_REG_FAN[] = {
0x4c0, 0x4c2, 0x4c4, 0x4c6, 0x4c8, 0x4ca, 0x4ce };
static const u16 NCT6779_REG_FAN_PULSES[NUM_FAN] = {
- 0x644, 0x645, 0x646, 0x647, 0x648, 0x649 };
+ 0x644, 0x645, 0x646, 0x647, 0x648, 0x649, 0x64f };
static const u16 NCT6779_REG_CRITICAL_PWM_ENABLE[] = {
0x136, 0x236, 0x336, 0x836, 0x936, 0xa36, 0xb36 };
@@ -704,10 +714,10 @@ static const char *const nct6795_temp_label[] = {
"PCH_CHIP_TEMP",
"PCH_CPU_TEMP",
"PCH_MCH_TEMP",
- "PCH_DIM0_TEMP",
- "PCH_DIM1_TEMP",
- "PCH_DIM2_TEMP",
- "PCH_DIM3_TEMP",
+ "Agent0 Dimm0",
+ "Agent0 Dimm1",
+ "Agent1 Dimm0",
+ "Agent1 Dimm1",
"BYTE_TEMP0",
"BYTE_TEMP1",
"PECI Agent 0 Calibration",
@@ -742,10 +752,10 @@ static const char *const nct6796_temp_label[] = {
"PCH_CHIP_TEMP",
"PCH_CPU_TEMP",
"PCH_MCH_TEMP",
- "PCH_DIM0_TEMP",
- "PCH_DIM1_TEMP",
- "PCH_DIM2_TEMP",
- "PCH_DIM3_TEMP",
+ "Agent0 Dimm0",
+ "Agent0 Dimm1",
+ "Agent1 Dimm0",
+ "Agent1 Dimm1",
"BYTE_TEMP0",
"BYTE_TEMP1",
"PECI Agent 0 Calibration",
@@ -757,6 +767,44 @@ static const char *const nct6796_temp_label[] = {
#define NCT6796_TEMP_MASK 0xbfff0ffe
#define NCT6796_VIRT_TEMP_MASK 0x80000c00
+static const char *const nct6798_temp_label[] = {
+ "",
+ "SYSTIN",
+ "CPUTIN",
+ "AUXTIN0",
+ "AUXTIN1",
+ "AUXTIN2",
+ "AUXTIN3",
+ "AUXTIN4",
+ "SMBUSMASTER 0",
+ "SMBUSMASTER 1",
+ "Virtual_TEMP",
+ "Virtual_TEMP",
+ "",
+ "",
+ "",
+ "",
+ "PECI Agent 0",
+ "PECI Agent 1",
+ "PCH_CHIP_CPU_MAX_TEMP",
+ "PCH_CHIP_TEMP",
+ "PCH_CPU_TEMP",
+ "PCH_MCH_TEMP",
+ "Agent0 Dimm0",
+ "Agent0 Dimm1",
+ "Agent1 Dimm0",
+ "Agent1 Dimm1",
+ "BYTE_TEMP0",
+ "BYTE_TEMP1",
+ "",
+ "",
+ "",
+ "Virtual_TEMP"
+};
+
+#define NCT6798_TEMP_MASK 0x8fff0ffe
+#define NCT6798_VIRT_TEMP_MASK 0x80000c00
+
/* NCT6102D/NCT6106D specific data */
#define NCT6106_REG_VBAT 0x318
@@ -1288,6 +1336,8 @@ static bool is_word_sized(struct nct6775_data *data, u16 reg)
case nct6793:
case nct6795:
case nct6796:
+ case nct6797:
+ case nct6798:
return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
(reg & 0xfff0) == 0x4c0 ||
reg == 0x402 ||
@@ -1643,6 +1693,8 @@ static void nct6775_update_pwm_limits(struct device *dev)
case nct6793:
case nct6795:
case nct6796:
+ case nct6797:
+ case nct6798:
reg = nct6775_read_value(data,
data->REG_CRITICAL_PWM_ENABLE[i]);
if (reg & data->CRITICAL_PWM_ENABLE_MASK)
@@ -2847,6 +2899,8 @@ store_temp_tolerance(struct device *dev, struct device_attribute *attr,
* Fan speed tolerance is a tricky beast, since the associated register is
* a tick counter, but the value is reported and configured as rpm.
* Compute resulting low and high rpm values and report the difference.
+ * A fan speed tolerance only makes sense if a fan target speed has been
+ * configured, so only display values other than 0 if that is the case.
*/
static ssize_t
show_speed_tolerance(struct device *dev, struct device_attribute *attr,
@@ -2855,19 +2909,23 @@ show_speed_tolerance(struct device *dev, struct device_attribute *attr,
struct nct6775_data *data = nct6775_update_device(dev);
struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
int nr = sattr->index;
- int low = data->target_speed[nr] - data->target_speed_tolerance[nr];
- int high = data->target_speed[nr] + data->target_speed_tolerance[nr];
- int tolerance;
-
- if (low <= 0)
- low = 1;
- if (high > 0xffff)
- high = 0xffff;
- if (high < low)
- high = low;
-
- tolerance = (fan_from_reg16(low, data->fan_div[nr])
- - fan_from_reg16(high, data->fan_div[nr])) / 2;
+ int target = data->target_speed[nr];
+ int tolerance = 0;
+
+ if (target) {
+ int low = target - data->target_speed_tolerance[nr];
+ int high = target + data->target_speed_tolerance[nr];
+
+ if (low <= 0)
+ low = 1;
+ if (high > 0xffff)
+ high = 0xffff;
+ if (high < low)
+ high = low;
+
+ tolerance = (fan_from_reg16(low, data->fan_div[nr])
+ - fan_from_reg16(high, data->fan_div[nr])) / 2;
+ }
return sprintf(buf, "%d\n", tolerance);
}
@@ -3071,6 +3129,8 @@ store_auto_pwm(struct device *dev, struct device_attribute *attr,
case nct6793:
case nct6795:
case nct6796:
+ case nct6797:
+ case nct6798:
nct6775_write_value(data, data->REG_CRITICAL_PWM[nr],
val);
reg = nct6775_read_value(data,
@@ -3430,7 +3490,6 @@ nct6775_check_fan_inputs(struct nct6775_data *data)
bool pwm3pin = false, pwm4pin = false, pwm5pin = false;
bool pwm6pin = false, pwm7pin = false;
int sioreg = data->sioreg;
- int regval;
/* Store SIO_REG_ENABLE for use during resume */
superio_select(sioreg, NCT6775_LD_HWM);
@@ -3438,10 +3497,10 @@ nct6775_check_fan_inputs(struct nct6775_data *data)
/* fan4 and fan5 share some pins with the GPIO and serial flash */
if (data->kind == nct6775) {
- regval = superio_inb(sioreg, 0x2c);
+ int cr2c = superio_inb(sioreg, 0x2c);
- fan3pin = regval & BIT(6);
- pwm3pin = regval & BIT(7);
+ fan3pin = cr2c & BIT(6);
+ pwm3pin = cr2c & BIT(7);
/* On NCT6775, fan4 shares pins with the fdc interface */
fan4pin = !(superio_inb(sioreg, 0x2A) & 0x80);
@@ -3486,85 +3545,130 @@ nct6775_check_fan_inputs(struct nct6775_data *data)
fan4min = fan4pin;
pwm3pin = fan3pin;
} else if (data->kind == nct6106) {
- regval = superio_inb(sioreg, 0x24);
- fan3pin = !(regval & 0x80);
- pwm3pin = regval & 0x08;
- } else {
- /* NCT6779D, NCT6791D, NCT6792D, NCT6793D, NCT6795D, NCT6796D */
- int regval_1b, regval_2a, regval_2f;
- bool dsw_en;
-
- regval = superio_inb(sioreg, 0x1c);
+ int cr24 = superio_inb(sioreg, 0x24);
- fan3pin = !(regval & BIT(5));
- fan4pin = !(regval & BIT(6));
- fan5pin = !(regval & BIT(7));
-
- pwm3pin = !(regval & BIT(0));
- pwm4pin = !(regval & BIT(1));
- pwm5pin = !(regval & BIT(2));
+ fan3pin = !(cr24 & 0x80);
+ pwm3pin = cr24 & 0x08;
+ } else {
+ /*
+ * NCT6779D, NCT6791D, NCT6792D, NCT6793D, NCT6795D, NCT6796D,
+ * NCT6797D, NCT6798D
+ */
+ int cr1a = superio_inb(sioreg, 0x1a);
+ int cr1b = superio_inb(sioreg, 0x1b);
+ int cr1c = superio_inb(sioreg, 0x1c);
+ int cr1d = superio_inb(sioreg, 0x1d);
+ int cr2a = superio_inb(sioreg, 0x2a);
+ int cr2b = superio_inb(sioreg, 0x2b);
+ int cr2d = superio_inb(sioreg, 0x2d);
+ int cr2f = superio_inb(sioreg, 0x2f);
+ bool dsw_en = cr2f & BIT(3);
+ bool ddr4_en = cr2f & BIT(4);
+ int cre0;
+ int creb;
+ int cred;
+
+ superio_select(sioreg, NCT6775_LD_12);
+ cre0 = superio_inb(sioreg, 0xe0);
+ creb = superio_inb(sioreg, 0xeb);
+ cred = superio_inb(sioreg, 0xed);
+
+ fan3pin = !(cr1c & BIT(5));
+ fan4pin = !(cr1c & BIT(6));
+ fan5pin = !(cr1c & BIT(7));
+
+ pwm3pin = !(cr1c & BIT(0));
+ pwm4pin = !(cr1c & BIT(1));
+ pwm5pin = !(cr1c & BIT(2));
- regval = superio_inb(sioreg, 0x2d);
switch (data->kind) {
case nct6791:
+ fan6pin = cr2d & BIT(1);
+ pwm6pin = cr2d & BIT(0);
+ break;
case nct6792:
- fan6pin = regval & BIT(1);
- pwm6pin = regval & BIT(0);
+ fan6pin = !dsw_en && (cr2d & BIT(1));
+ pwm6pin = !dsw_en && (cr2d & BIT(0));
break;
case nct6793:
+ fan5pin |= cr1b & BIT(5);
+ fan5pin |= creb & BIT(5);
+
+ fan6pin = creb & BIT(3);
+
+ pwm5pin |= cr2d & BIT(7);
+ pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0));
+
+ pwm6pin = !dsw_en && (cr2d & BIT(0));
+ pwm6pin |= creb & BIT(2);
+ break;
case nct6795:
+ fan5pin |= cr1b & BIT(5);
+ fan5pin |= creb & BIT(5);
+
+ fan6pin = (cr2a & BIT(4)) &&
+ (!dsw_en || (cred & BIT(4)));
+ fan6pin |= creb & BIT(3);
+
+ pwm5pin |= cr2d & BIT(7);
+ pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0));
+
+ pwm6pin = (cr2a & BIT(3)) && (cred & BIT(2));
+ pwm6pin |= creb & BIT(2);
+ break;
case nct6796:
- regval_1b = superio_inb(sioreg, 0x1b);
- regval_2a = superio_inb(sioreg, 0x2a);
- regval_2f = superio_inb(sioreg, 0x2f);
- dsw_en = regval_2f & BIT(3);
+ fan5pin |= cr1b & BIT(5);
+ fan5pin |= (cre0 & BIT(3)) && !(cr1b & BIT(0));
+ fan5pin |= creb & BIT(5);
- if (!pwm5pin)
- pwm5pin = regval & BIT(7);
+ fan6pin = (cr2a & BIT(4)) &&
+ (!dsw_en || (cred & BIT(4)));
+ fan6pin |= creb & BIT(3);
- if (!fan5pin)
- fan5pin = regval_1b & BIT(5);
+ fan7pin = !(cr2b & BIT(2));
- superio_select(sioreg, NCT6775_LD_12);
- if (data->kind != nct6796) {
- int regval_eb = superio_inb(sioreg, 0xeb);
+ pwm5pin |= cr2d & BIT(7);
+ pwm5pin |= (cre0 & BIT(4)) && !(cr1b & BIT(0));
+ pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0));
- if (!dsw_en) {
- fan6pin = regval & BIT(1);
- pwm6pin = regval & BIT(0);
- }
+ pwm6pin = (cr2a & BIT(3)) && (cred & BIT(2));
+ pwm6pin |= creb & BIT(2);
- if (!fan5pin)
- fan5pin = regval_eb & BIT(5);
- if (!pwm5pin)
- pwm5pin = (regval_eb & BIT(4)) &&
- !(regval_2a & BIT(0));
- if (!fan6pin)
- fan6pin = regval_eb & BIT(3);
- if (!pwm6pin)
- pwm6pin = regval_eb & BIT(2);
- }
+ pwm7pin = !(cr1d & (BIT(2) | BIT(3)));
+ break;
+ case nct6797:
+ fan5pin |= !ddr4_en && (cr1b & BIT(5));
+ fan5pin |= creb & BIT(5);
- if (data->kind == nct6795 || data->kind == nct6796) {
- int regval_ed = superio_inb(sioreg, 0xed);
+ fan6pin = cr2a & BIT(4);
+ fan6pin |= creb & BIT(3);
- if (!fan6pin)
- fan6pin = (regval_2a & BIT(4)) &&
- (!dsw_en ||
- (dsw_en && (regval_ed & BIT(4))));
- if (!pwm6pin)
- pwm6pin = (regval_2a & BIT(3)) &&
- (regval_ed & BIT(2));
- }
+ fan7pin = cr1a & BIT(1);
- if (data->kind == nct6796) {
- int regval_1d = superio_inb(sioreg, 0x1d);
- int regval_2b = superio_inb(sioreg, 0x2b);
+ pwm5pin |= (creb & BIT(4)) && !(cr2a & BIT(0));
+ pwm5pin |= !ddr4_en && (cr2d & BIT(7));
- fan7pin = !(regval_2b & BIT(2));
- pwm7pin = !(regval_1d & (BIT(2) | BIT(3)));
- }
+ pwm6pin = creb & BIT(2);
+ pwm6pin |= cred & BIT(2);
+ pwm7pin = cr1d & BIT(4);
+ break;
+ case nct6798:
+ fan6pin = !(cr1b & BIT(0)) && (cre0 & BIT(3));
+ fan6pin |= cr2a & BIT(4);
+ fan6pin |= creb & BIT(5);
+
+ fan7pin = cr1b & BIT(5);
+ fan7pin |= !(cr2b & BIT(2));
+ fan7pin |= creb & BIT(3);
+
+ pwm6pin = !(cr1b & BIT(0)) && (cre0 & BIT(4));
+ pwm6pin |= !(cred & BIT(2)) && (cr2a & BIT(3));
+ pwm6pin |= (creb & BIT(4)) && !(cr2a & BIT(0));
+
+ pwm7pin = !(cr1d & (BIT(2) | BIT(3)));
+ pwm7pin |= cr2d & BIT(7);
+ pwm7pin |= creb & BIT(2);
break;
default: /* NCT6779D */
break;
@@ -3943,8 +4047,12 @@ static int nct6775_probe(struct platform_device *pdev)
case nct6793:
case nct6795:
case nct6796:
+ case nct6797:
+ case nct6798:
data->in_num = 15;
- data->pwm_num = (data->kind == nct6796) ? 7 : 6;
+ data->pwm_num = (data->kind == nct6796 ||
+ data->kind == nct6797 ||
+ data->kind == nct6798) ? 7 : 6;
data->auto_pwm_num = 4;
data->has_fan_div = false;
data->temp_fixed_num = 6;
@@ -3978,6 +4086,7 @@ static int nct6775_probe(struct platform_device *pdev)
data->virt_temp_mask = NCT6793_VIRT_TEMP_MASK;
break;
case nct6795:
+ case nct6797:
data->temp_label = nct6795_temp_label;
data->temp_mask = NCT6795_TEMP_MASK;
data->virt_temp_mask = NCT6795_VIRT_TEMP_MASK;
@@ -3987,6 +4096,11 @@ static int nct6775_probe(struct platform_device *pdev)
data->temp_mask = NCT6796_TEMP_MASK;
data->virt_temp_mask = NCT6796_VIRT_TEMP_MASK;
break;
+ case nct6798:
+ data->temp_label = nct6798_temp_label;
+ data->temp_mask = NCT6798_TEMP_MASK;
+ data->virt_temp_mask = NCT6798_VIRT_TEMP_MASK;
+ break;
}
data->REG_CONFIG = NCT6775_REG_CONFIG;
@@ -4256,6 +4370,8 @@ static int nct6775_probe(struct platform_device *pdev)
case nct6793:
case nct6795:
case nct6796:
+ case nct6797:
+ case nct6798:
break;
}
@@ -4291,6 +4407,8 @@ static int nct6775_probe(struct platform_device *pdev)
case nct6793:
case nct6795:
case nct6796:
+ case nct6797:
+ case nct6798:
tmp |= 0x7e;
break;
}
@@ -4493,6 +4611,12 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
case SIO_NCT6796_ID:
sio_data->kind = nct6796;
break;
+ case SIO_NCT6797_ID:
+ sio_data->kind = nct6797;
+ break;
+ case SIO_NCT6798_ID:
+ sio_data->kind = nct6798;
+ break;
default:
if (val != 0xffff)
pr_debug("unsupported chip ID: 0x%04x\n", val);
diff --git a/drivers/hwmon/npcm750-pwm-fan.c b/drivers/hwmon/npcm750-pwm-fan.c
index 8474d601aa63..b3b907bdfb63 100644
--- a/drivers/hwmon/npcm750-pwm-fan.c
+++ b/drivers/hwmon/npcm750-pwm-fan.c
@@ -52,7 +52,7 @@
/* Define the Counter Register, value = 100 for match 100% */
#define NPCM7XX_PWM_COUNTER_DEFAULT_NUM 255
-#define NPCM7XX_PWM_CMR_DEFAULT_NUM 127
+#define NPCM7XX_PWM_CMR_DEFAULT_NUM 255
#define NPCM7XX_PWM_CMR_MAX 255
/* default all PWM channels PRESCALE2 = 1 */
@@ -861,7 +861,7 @@ static int npcm7xx_create_pwm_cooling(struct device *dev,
dev_err(dev, "Property 'cooling-levels' cannot be read.\n");
return ret;
}
- snprintf(cdev->name, THERMAL_NAME_LENGTH, "%s%d", child->name,
+ snprintf(cdev->name, THERMAL_NAME_LENGTH, "%pOFn%d", child,
pwm_port);
cdev->tcdev = thermal_of_cooling_device_register(child,
@@ -908,7 +908,7 @@ static int npcm7xx_en_pwm_fan(struct device *dev,
if (fan_cnt < 1)
return -EINVAL;
- fan_ch = devm_kzalloc(dev, sizeof(*fan_ch) * fan_cnt, GFP_KERNEL);
+ fan_ch = devm_kcalloc(dev, fan_cnt, sizeof(*fan_ch), GFP_KERNEL);
if (!fan_ch)
return -ENOMEM;
diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig
index a82018aaf473..629cb45f8557 100644
--- a/drivers/hwmon/pmbus/Kconfig
+++ b/drivers/hwmon/pmbus/Kconfig
@@ -5,7 +5,6 @@
menuconfig PMBUS
tristate "PMBus support"
depends on I2C
- default n
help
Say yes here if you want to enable PMBus support.
@@ -28,7 +27,6 @@ config SENSORS_PMBUS
config SENSORS_ADM1275
tristate "Analog Devices ADM1275 and compatibles"
- default n
help
If you say yes here you get hardware monitoring support for Analog
Devices ADM1075, ADM1272, ADM1275, ADM1276, ADM1278, ADM1293,
@@ -49,7 +47,6 @@ config SENSORS_IBM_CFFPS
config SENSORS_IR35221
tristate "Infineon IR35221"
- default n
help
If you say yes here you get hardware monitoring support for the
Infineon IR35221 controller.
@@ -59,7 +56,6 @@ config SENSORS_IR35221
config SENSORS_LM25066
tristate "National Semiconductor LM25066 and compatibles"
- default n
help
If you say yes here you get hardware monitoring support for National
Semiconductor LM25056, LM25066, LM5064, and LM5066.
@@ -69,7 +65,6 @@ config SENSORS_LM25066
config SENSORS_LTC2978
tristate "Linear Technologies LTC2978 and compatibles"
- default n
help
If you say yes here you get hardware monitoring support for Linear
Technology LTC2974, LTC2975, LTC2977, LTC2978, LTC2980, LTC3880,
@@ -83,11 +78,11 @@ config SENSORS_LTC2978_REGULATOR
depends on SENSORS_LTC2978 && REGULATOR
help
If you say yes here you get regulator support for Linear
- Technology LTC2974, LTC2977, LTC2978, LTC3880, LTC3883, and LTM4676.
+ Technology LTC2974, LTC2977, LTC2978, LTC3880, LTC3883, LTM4676
+ and LTM4686.
config SENSORS_LTC3815
tristate "Linear Technologies LTC3815"
- default n
help
If you say yes here you get hardware monitoring support for Linear
Technology LTC3815.
@@ -97,7 +92,6 @@ config SENSORS_LTC3815
config SENSORS_MAX16064
tristate "Maxim MAX16064"
- default n
help
If you say yes here you get hardware monitoring support for Maxim
MAX16064.
@@ -107,7 +101,6 @@ config SENSORS_MAX16064
config SENSORS_MAX20751
tristate "Maxim MAX20751"
- default n
help
If you say yes here you get hardware monitoring support for Maxim
MAX20751.
@@ -117,7 +110,6 @@ config SENSORS_MAX20751
config SENSORS_MAX31785
tristate "Maxim MAX31785 and compatibles"
- default n
help
If you say yes here you get hardware monitoring support for Maxim
MAX31785.
@@ -127,7 +119,6 @@ config SENSORS_MAX31785
config SENSORS_MAX34440
tristate "Maxim MAX34440 and compatibles"
- default n
help
If you say yes here you get hardware monitoring support for Maxim
MAX34440, MAX34441, MAX34446, MAX34451, MAX34460, and MAX34461.
@@ -137,7 +128,6 @@ config SENSORS_MAX34440
config SENSORS_MAX8688
tristate "Maxim MAX8688"
- default n
help
If you say yes here you get hardware monitoring support for Maxim
MAX8688.
@@ -147,7 +137,6 @@ config SENSORS_MAX8688
config SENSORS_TPS40422
tristate "TI TPS40422"
- default n
help
If you say yes here you get hardware monitoring support for TI
TPS40422.
@@ -166,7 +155,6 @@ config SENSORS_TPS53679
config SENSORS_UCD9000
tristate "TI UCD90120, UCD90124, UCD90160, UCD9090, UCD90910"
- default n
help
If you say yes here you get hardware monitoring support for TI
UCD90120, UCD90124, UCD90160, UCD9090, UCD90910, Sequencer and System
@@ -177,7 +165,6 @@ config SENSORS_UCD9000
config SENSORS_UCD9200
tristate "TI UCD9220, UCD9222, UCD9224, UCD9240, UCD9244, UCD9246, UCD9248"
- default n
help
If you say yes here you get hardware monitoring support for TI
UCD9220, UCD9222, UCD9224, UCD9240, UCD9244, UCD9246, and UCD9248
@@ -188,7 +175,6 @@ config SENSORS_UCD9200
config SENSORS_ZL6100
tristate "Intersil ZL6100 and compatibles"
- default n
help
If you say yes here you get hardware monitoring support for Intersil
ZL2004, ZL2005, ZL2006, ZL2008, ZL2105, ZL2106, ZL6100, ZL6105,
diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c
index 58b789c28b48..07afb92bb36b 100644
--- a/drivers/hwmon/pmbus/ltc2978.c
+++ b/drivers/hwmon/pmbus/ltc2978.c
@@ -4,6 +4,7 @@
* Copyright (c) 2011 Ericsson AB.
* Copyright (c) 2013, 2014, 2015 Guenter Roeck
* Copyright (c) 2015 Linear Technology
+ * Copyright (c) 2018 Analog Devices Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -28,7 +29,7 @@
#include "pmbus.h"
enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882,
- ltc3883, ltc3886, ltc3887, ltm2987, ltm4675, ltm4676 };
+ ltc3883, ltc3886, ltc3887, ltm2987, ltm4675, ltm4676, ltm4686 };
/* Common for all chips */
#define LTC2978_MFR_VOUT_PEAK 0xdd
@@ -81,6 +82,7 @@ enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882,
#define LTM4676_ID_REV1 0x4400
#define LTM4676_ID_REV2 0x4480
#define LTM4676A_ID 0x47e0
+#define LTM4686_ID 0x4770
#define LTC2974_NUM_PAGES 4
#define LTC2978_NUM_PAGES 8
@@ -512,6 +514,7 @@ static const struct i2c_device_id ltc2978_id[] = {
{"ltm2987", ltm2987},
{"ltm4675", ltm4675},
{"ltm4676", ltm4676},
+ {"ltm4686", ltm4686},
{}
};
MODULE_DEVICE_TABLE(i2c, ltc2978_id);
@@ -588,6 +591,8 @@ static int ltc2978_get_id(struct i2c_client *client)
else if (chip_id == LTM4676_ID_REV1 || chip_id == LTM4676_ID_REV2 ||
chip_id == LTM4676A_ID)
return ltm4676;
+ else if (chip_id == LTM4686_ID)
+ return ltm4686;
dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id);
return -ENODEV;
@@ -684,6 +689,7 @@ static int ltc2978_probe(struct i2c_client *client,
case ltc3887:
case ltm4675:
case ltm4676:
+ case ltm4686:
data->features |= FEAT_CLEAR_PEAKS | FEAT_NEEDS_POLLING;
info->read_word_data = ltc3880_read_word_data;
info->pages = LTC3880_NUM_PAGES;
@@ -770,6 +776,7 @@ static const struct of_device_id ltc2978_of_match[] = {
{ .compatible = "lltc,ltm2987" },
{ .compatible = "lltc,ltm4675" },
{ .compatible = "lltc,ltm4676" },
+ { .compatible = "lltc,ltm4686" },
{ }
};
MODULE_DEVICE_TABLE(of, ltc2978_of_match);
diff --git a/drivers/hwmon/pmbus/pmbus.c b/drivers/hwmon/pmbus/pmbus.c
index 7718e58dbda5..7688dab32f6e 100644
--- a/drivers/hwmon/pmbus/pmbus.c
+++ b/drivers/hwmon/pmbus/pmbus.c
@@ -118,6 +118,8 @@ static int pmbus_identify(struct i2c_client *client,
} else {
info->pages = 1;
}
+
+ pmbus_clear_faults(client);
}
if (pmbus_check_byte_register(client, 0, PMBUS_VOUT_MODE)) {
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
index 82c3754e21e3..2e2b5851139c 100644
--- a/drivers/hwmon/pmbus/pmbus_core.c
+++ b/drivers/hwmon/pmbus/pmbus_core.c
@@ -2015,7 +2015,10 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data,
if (ret >= 0 && (ret & PB_CAPABILITY_ERROR_CHECK))
client->flags |= I2C_CLIENT_PEC;
- pmbus_clear_faults(client);
+ if (data->info->pages)
+ pmbus_clear_faults(client);
+ else
+ pmbus_clear_fault_page(client, -1);
if (info->identify) {
ret = (*info->identify)(client, info);
diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c
index 7838af58f92d..7da6a160d45a 100644
--- a/drivers/hwmon/pwm-fan.c
+++ b/drivers/hwmon/pwm-fan.c
@@ -221,8 +221,12 @@ static int pwm_fan_probe(struct platform_device *pdev)
ctx->pwm = devm_of_pwm_get(&pdev->dev, pdev->dev.of_node, NULL);
if (IS_ERR(ctx->pwm)) {
- dev_err(&pdev->dev, "Could not get PWM\n");
- return PTR_ERR(ctx->pwm);
+ ret = PTR_ERR(ctx->pwm);
+
+ if (ret != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Could not get PWM: %d\n", ret);
+
+ return ret;
}
platform_set_drvdata(pdev, ctx);
@@ -290,9 +294,19 @@ static int pwm_fan_remove(struct platform_device *pdev)
static int pwm_fan_suspend(struct device *dev)
{
struct pwm_fan_ctx *ctx = dev_get_drvdata(dev);
+ struct pwm_args args;
+ int ret;
+
+ pwm_get_args(ctx->pwm, &args);
+
+ if (ctx->pwm_value) {
+ ret = pwm_config(ctx->pwm, 0, args.period);
+ if (ret < 0)
+ return ret;
- if (ctx->pwm_value)
pwm_disable(ctx->pwm);
+ }
+
return 0;
}
diff --git a/drivers/hwmon/scmi-hwmon.c b/drivers/hwmon/scmi-hwmon.c
index 91976b6ca300..2e005edee0c9 100644
--- a/drivers/hwmon/scmi-hwmon.c
+++ b/drivers/hwmon/scmi-hwmon.c
@@ -56,7 +56,7 @@ scmi_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_types type,
const struct scmi_sensors *scmi_sensors = drvdata;
sensor = *(scmi_sensors->info[type] + channel);
- if (sensor && sensor->name)
+ if (sensor)
return S_IRUGO;
return 0;
diff --git a/drivers/hwmon/scpi-hwmon.c b/drivers/hwmon/scpi-hwmon.c
index 7e49da50bc69..111d521e2189 100644
--- a/drivers/hwmon/scpi-hwmon.c
+++ b/drivers/hwmon/scpi-hwmon.c
@@ -286,10 +286,8 @@ static int scpi_hwmon_probe(struct platform_device *pdev)
* any thermal zones or if the thermal subsystem is
* not configured.
*/
- if (IS_ERR(z)) {
+ if (IS_ERR(z))
devm_kfree(dev, zone);
- continue;
- }
}
return 0;
diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c
index 2be77752cd56..c878242f3486 100644
--- a/drivers/hwmon/sht15.c
+++ b/drivers/hwmon/sht15.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* sht15.c - support for the SHT15 Temperature and Humidity Sensor
*
@@ -9,10 +10,6 @@
*
* Copyright (c) 2007 Wouter Horre
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
* For further information, see the Documentation/hwmon/sht15 file.
*/
diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c
index dfc40c740d07..6778283e36f9 100644
--- a/drivers/hwmon/tmp102.c
+++ b/drivers/hwmon/tmp102.c
@@ -212,7 +212,8 @@ static const struct regmap_config tmp102_regmap_config = {
.volatile_reg = tmp102_is_volatile_reg,
.val_format_endian = REGMAP_ENDIAN_BIG,
.cache_type = REGCACHE_RBTREE,
- .use_single_rw = true,
+ .use_single_read = true,
+ .use_single_write = true,
};
static int tmp102_probe(struct i2c_client *client,
diff --git a/drivers/hwmon/tmp108.c b/drivers/hwmon/tmp108.c
index 91bb94639286..429bfeae4ca8 100644
--- a/drivers/hwmon/tmp108.c
+++ b/drivers/hwmon/tmp108.c
@@ -345,7 +345,8 @@ static const struct regmap_config tmp108_regmap_config = {
.volatile_reg = tmp108_is_volatile_reg,
.val_format_endian = REGMAP_ENDIAN_BIG,
.cache_type = REGCACHE_RBTREE,
- .use_single_rw = true,
+ .use_single_read = true,
+ .use_single_write = true,
};
static int tmp108_probe(struct i2c_client *client,
diff --git a/drivers/hwmon/tmp421.c b/drivers/hwmon/tmp421.c
index e36399213324..8844c9565d2a 100644
--- a/drivers/hwmon/tmp421.c
+++ b/drivers/hwmon/tmp421.c
@@ -226,8 +226,10 @@ static int tmp421_detect(struct i2c_client *client,
{
enum chips kind;
struct i2c_adapter *adapter = client->adapter;
- const char * const names[] = { "TMP421", "TMP422", "TMP423",
- "TMP441", "TMP442" };
+ static const char * const names[] = {
+ "TMP421", "TMP422", "TMP423",
+ "TMP441", "TMP442"
+ };
int addr = client->addr;
u8 reg;
diff --git a/drivers/hwtracing/coresight/coresight-catu.c b/drivers/hwtracing/coresight/coresight-catu.c
index ff94e58845b7..170fbb66bda2 100644
--- a/drivers/hwtracing/coresight/coresight-catu.c
+++ b/drivers/hwtracing/coresight/coresight-catu.c
@@ -406,6 +406,7 @@ static inline int catu_wait_for_ready(struct catu_drvdata *drvdata)
static int catu_enable_hw(struct catu_drvdata *drvdata, void *data)
{
+ int rc;
u32 control, mode;
struct etr_buf *etr_buf = data;
@@ -418,6 +419,10 @@ static int catu_enable_hw(struct catu_drvdata *drvdata, void *data)
return -EBUSY;
}
+ rc = coresight_claim_device_unlocked(drvdata->base);
+ if (rc)
+ return rc;
+
control |= BIT(CATU_CONTROL_ENABLE);
if (etr_buf && etr_buf->mode == ETR_MODE_CATU) {
@@ -459,6 +464,7 @@ static int catu_disable_hw(struct catu_drvdata *drvdata)
int rc = 0;
catu_write_control(drvdata, 0);
+ coresight_disclaim_device_unlocked(drvdata->base);
if (catu_wait_for_ready(drvdata)) {
dev_info(drvdata->dev, "Timeout while waiting for READY\n");
rc = -EAGAIN;
diff --git a/drivers/hwtracing/coresight/coresight-dynamic-replicator.c b/drivers/hwtracing/coresight/coresight-dynamic-replicator.c
index f6d0571ab9dd..299667b887fc 100644
--- a/drivers/hwtracing/coresight/coresight-dynamic-replicator.c
+++ b/drivers/hwtracing/coresight/coresight-dynamic-replicator.c
@@ -34,48 +34,87 @@ struct replicator_state {
struct coresight_device *csdev;
};
+/*
+ * replicator_reset : Reset the replicator configuration to sane values.
+ */
+static void replicator_reset(struct replicator_state *drvdata)
+{
+ CS_UNLOCK(drvdata->base);
+
+ if (!coresight_claim_device_unlocked(drvdata->base)) {
+ writel_relaxed(0xff, drvdata->base + REPLICATOR_IDFILTER0);
+ writel_relaxed(0xff, drvdata->base + REPLICATOR_IDFILTER1);
+ coresight_disclaim_device_unlocked(drvdata->base);
+ }
+
+ CS_LOCK(drvdata->base);
+}
+
static int replicator_enable(struct coresight_device *csdev, int inport,
int outport)
{
+ int rc = 0;
+ u32 reg;
struct replicator_state *drvdata = dev_get_drvdata(csdev->dev.parent);
+ switch (outport) {
+ case 0:
+ reg = REPLICATOR_IDFILTER0;
+ break;
+ case 1:
+ reg = REPLICATOR_IDFILTER1;
+ break;
+ default:
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
CS_UNLOCK(drvdata->base);
- /*
- * Ensure that the other port is disabled
- * 0x00 - passing through the replicator unimpeded
- * 0xff - disable (or impede) the flow of ATB data
- */
- if (outport == 0) {
- writel_relaxed(0x00, drvdata->base + REPLICATOR_IDFILTER0);
- writel_relaxed(0xff, drvdata->base + REPLICATOR_IDFILTER1);
- } else {
- writel_relaxed(0x00, drvdata->base + REPLICATOR_IDFILTER1);
- writel_relaxed(0xff, drvdata->base + REPLICATOR_IDFILTER0);
+ if ((readl_relaxed(drvdata->base + REPLICATOR_IDFILTER0) == 0xff) &&
+ (readl_relaxed(drvdata->base + REPLICATOR_IDFILTER1) == 0xff))
+ rc = coresight_claim_device_unlocked(drvdata->base);
+
+ /* Ensure that the outport is enabled. */
+ if (!rc) {
+ writel_relaxed(0x00, drvdata->base + reg);
+ dev_dbg(drvdata->dev, "REPLICATOR enabled\n");
}
CS_LOCK(drvdata->base);
- dev_info(drvdata->dev, "REPLICATOR enabled\n");
- return 0;
+ return rc;
}
static void replicator_disable(struct coresight_device *csdev, int inport,
int outport)
{
+ u32 reg;
struct replicator_state *drvdata = dev_get_drvdata(csdev->dev.parent);
+ switch (outport) {
+ case 0:
+ reg = REPLICATOR_IDFILTER0;
+ break;
+ case 1:
+ reg = REPLICATOR_IDFILTER1;
+ break;
+ default:
+ WARN_ON(1);
+ return;
+ }
+
CS_UNLOCK(drvdata->base);
/* disable the flow of ATB data through port */
- if (outport == 0)
- writel_relaxed(0xff, drvdata->base + REPLICATOR_IDFILTER0);
- else
- writel_relaxed(0xff, drvdata->base + REPLICATOR_IDFILTER1);
+ writel_relaxed(0xff, drvdata->base + reg);
+ if ((readl_relaxed(drvdata->base + REPLICATOR_IDFILTER0) == 0xff) &&
+ (readl_relaxed(drvdata->base + REPLICATOR_IDFILTER1) == 0xff))
+ coresight_disclaim_device_unlocked(drvdata->base);
CS_LOCK(drvdata->base);
- dev_info(drvdata->dev, "REPLICATOR disabled\n");
+ dev_dbg(drvdata->dev, "REPLICATOR disabled\n");
}
static const struct coresight_ops_link replicator_link_ops = {
@@ -156,7 +195,11 @@ static int replicator_probe(struct amba_device *adev, const struct amba_id *id)
desc.groups = replicator_groups;
drvdata->csdev = coresight_register(&desc);
- return PTR_ERR_OR_ZERO(drvdata->csdev);
+ if (!IS_ERR(drvdata->csdev)) {
+ replicator_reset(drvdata);
+ return 0;
+ }
+ return PTR_ERR(drvdata->csdev);
}
#ifdef CONFIG_PM
diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c
index 306119eaf16a..824be0c5f592 100644
--- a/drivers/hwtracing/coresight/coresight-etb10.c
+++ b/drivers/hwtracing/coresight/coresight-etb10.c
@@ -5,7 +5,6 @@
* Description: CoreSight Embedded Trace Buffer driver
*/
-#include <asm/local.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
@@ -28,6 +27,7 @@
#include "coresight-priv.h"
+#include "coresight-etm-perf.h"
#define ETB_RAM_DEPTH_REG 0x004
#define ETB_STATUS_REG 0x00c
@@ -71,8 +71,8 @@
* @miscdev: specifics to handle "/dev/xyz.etb" entry.
* @spinlock: only one at a time pls.
* @reading: synchronise user space access to etb buffer.
- * @mode: this ETB is being used.
* @buf: area of memory where ETB buffer content gets sent.
+ * @mode: this ETB is being used.
* @buffer_depth: size of @buf.
* @trigger_cntr: amount of words to store after a trigger.
*/
@@ -84,12 +84,15 @@ struct etb_drvdata {
struct miscdevice miscdev;
spinlock_t spinlock;
local_t reading;
- local_t mode;
u8 *buf;
+ u32 mode;
u32 buffer_depth;
u32 trigger_cntr;
};
+static int etb_set_buffer(struct coresight_device *csdev,
+ struct perf_output_handle *handle);
+
static unsigned int etb_get_buffer_depth(struct etb_drvdata *drvdata)
{
u32 depth = 0;
@@ -103,7 +106,7 @@ static unsigned int etb_get_buffer_depth(struct etb_drvdata *drvdata)
return depth;
}
-static void etb_enable_hw(struct etb_drvdata *drvdata)
+static void __etb_enable_hw(struct etb_drvdata *drvdata)
{
int i;
u32 depth;
@@ -131,32 +134,92 @@ static void etb_enable_hw(struct etb_drvdata *drvdata)
CS_LOCK(drvdata->base);
}
-static int etb_enable(struct coresight_device *csdev, u32 mode)
+static int etb_enable_hw(struct etb_drvdata *drvdata)
+{
+ __etb_enable_hw(drvdata);
+ return 0;
+}
+
+static int etb_enable_sysfs(struct coresight_device *csdev)
{
- u32 val;
+ int ret = 0;
unsigned long flags;
struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
- val = local_cmpxchg(&drvdata->mode,
- CS_MODE_DISABLED, mode);
- /*
- * When accessing from Perf, a HW buffer can be handled
- * by a single trace entity. In sysFS mode many tracers
- * can be logging to the same HW buffer.
- */
- if (val == CS_MODE_PERF)
- return -EBUSY;
+ spin_lock_irqsave(&drvdata->spinlock, flags);
+
+ /* Don't messup with perf sessions. */
+ if (drvdata->mode == CS_MODE_PERF) {
+ ret = -EBUSY;
+ goto out;
+ }
/* Nothing to do, the tracer is already enabled. */
- if (val == CS_MODE_SYSFS)
+ if (drvdata->mode == CS_MODE_SYSFS)
goto out;
- spin_lock_irqsave(&drvdata->spinlock, flags);
- etb_enable_hw(drvdata);
+ ret = etb_enable_hw(drvdata);
+ if (!ret)
+ drvdata->mode = CS_MODE_SYSFS;
+
+out:
spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ return ret;
+}
+
+static int etb_enable_perf(struct coresight_device *csdev, void *data)
+{
+ int ret = 0;
+ unsigned long flags;
+ struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+ spin_lock_irqsave(&drvdata->spinlock, flags);
+
+ /* No need to continue if the component is already in use. */
+ if (drvdata->mode != CS_MODE_DISABLED) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ /*
+ * We don't have an internal state to clean up if we fail to setup
+ * the perf buffer. So we can perform the step before we turn the
+ * ETB on and leave without cleaning up.
+ */
+ ret = etb_set_buffer(csdev, (struct perf_output_handle *)data);
+ if (ret)
+ goto out;
+
+ ret = etb_enable_hw(drvdata);
+ if (!ret)
+ drvdata->mode = CS_MODE_PERF;
out:
- dev_info(drvdata->dev, "ETB enabled\n");
+ spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ return ret;
+}
+
+static int etb_enable(struct coresight_device *csdev, u32 mode, void *data)
+{
+ int ret;
+ struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+ switch (mode) {
+ case CS_MODE_SYSFS:
+ ret = etb_enable_sysfs(csdev);
+ break;
+ case CS_MODE_PERF:
+ ret = etb_enable_perf(csdev, data);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ if (ret)
+ return ret;
+
+ dev_dbg(drvdata->dev, "ETB enabled\n");
return 0;
}
@@ -256,13 +319,16 @@ static void etb_disable(struct coresight_device *csdev)
unsigned long flags;
spin_lock_irqsave(&drvdata->spinlock, flags);
- etb_disable_hw(drvdata);
- etb_dump_hw(drvdata);
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
- local_set(&drvdata->mode, CS_MODE_DISABLED);
+ /* Disable the ETB only if it needs to */
+ if (drvdata->mode != CS_MODE_DISABLED) {
+ etb_disable_hw(drvdata);
+ etb_dump_hw(drvdata);
+ drvdata->mode = CS_MODE_DISABLED;
+ }
+ spin_unlock_irqrestore(&drvdata->spinlock, flags);
- dev_info(drvdata->dev, "ETB disabled\n");
+ dev_dbg(drvdata->dev, "ETB disabled\n");
}
static void *etb_alloc_buffer(struct coresight_device *csdev, int cpu,
@@ -294,12 +360,14 @@ static void etb_free_buffer(void *config)
}
static int etb_set_buffer(struct coresight_device *csdev,
- struct perf_output_handle *handle,
- void *sink_config)
+ struct perf_output_handle *handle)
{
int ret = 0;
unsigned long head;
- struct cs_buffers *buf = sink_config;
+ struct cs_buffers *buf = etm_perf_sink_config(handle);
+
+ if (!buf)
+ return -EINVAL;
/* wrap head around to the amount of space we have */
head = handle->head & ((buf->nr_pages << PAGE_SHIFT) - 1);
@@ -315,37 +383,7 @@ static int etb_set_buffer(struct coresight_device *csdev,
return ret;
}
-static unsigned long etb_reset_buffer(struct coresight_device *csdev,
- struct perf_output_handle *handle,
- void *sink_config)
-{
- unsigned long size = 0;
- struct cs_buffers *buf = sink_config;
-
- if (buf) {
- /*
- * In snapshot mode ->data_size holds the new address of the
- * ring buffer's head. The size itself is the whole address
- * range since we want the latest information.
- */
- if (buf->snapshot)
- handle->head = local_xchg(&buf->data_size,
- buf->nr_pages << PAGE_SHIFT);
-
- /*
- * Tell the tracer PMU how much we got in this run and if
- * something went wrong along the way. Nobody else can use
- * this cs_buffers instance until we are done. As such
- * resetting parameters here and squaring off with the ring
- * buffer API in the tracer PMU is fine.
- */
- size = local_xchg(&buf->data_size, 0);
- }
-
- return size;
-}
-
-static void etb_update_buffer(struct coresight_device *csdev,
+static unsigned long etb_update_buffer(struct coresight_device *csdev,
struct perf_output_handle *handle,
void *sink_config)
{
@@ -354,13 +392,13 @@ static void etb_update_buffer(struct coresight_device *csdev,
u8 *buf_ptr;
const u32 *barrier;
u32 read_ptr, write_ptr, capacity;
- u32 status, read_data, to_read;
- unsigned long offset;
+ u32 status, read_data;
+ unsigned long offset, to_read;
struct cs_buffers *buf = sink_config;
struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
if (!buf)
- return;
+ return 0;
capacity = drvdata->buffer_depth * ETB_FRAME_SIZE_WORDS;
@@ -465,18 +503,17 @@ static void etb_update_buffer(struct coresight_device *csdev,
writel_relaxed(0x0, drvdata->base + ETB_RAM_WRITE_POINTER);
/*
- * In snapshot mode all we have to do is communicate to
- * perf_aux_output_end() the address of the current head. In full
- * trace mode the same function expects a size to move rb->aux_head
- * forward.
+ * In snapshot mode we have to update the handle->head to point
+ * to the new location.
*/
- if (buf->snapshot)
- local_set(&buf->data_size, (cur * PAGE_SIZE) + offset);
- else
- local_add(to_read, &buf->data_size);
-
+ if (buf->snapshot) {
+ handle->head = (cur * PAGE_SIZE) + offset;
+ to_read = buf->nr_pages << PAGE_SHIFT;
+ }
etb_enable_hw(drvdata);
CS_LOCK(drvdata->base);
+
+ return to_read;
}
static const struct coresight_ops_sink etb_sink_ops = {
@@ -484,8 +521,6 @@ static const struct coresight_ops_sink etb_sink_ops = {
.disable = etb_disable,
.alloc_buffer = etb_alloc_buffer,
.free_buffer = etb_free_buffer,
- .set_buffer = etb_set_buffer,
- .reset_buffer = etb_reset_buffer,
.update_buffer = etb_update_buffer,
};
@@ -498,14 +533,14 @@ static void etb_dump(struct etb_drvdata *drvdata)
unsigned long flags;
spin_lock_irqsave(&drvdata->spinlock, flags);
- if (local_read(&drvdata->mode) == CS_MODE_SYSFS) {
+ if (drvdata->mode == CS_MODE_SYSFS) {
etb_disable_hw(drvdata);
etb_dump_hw(drvdata);
etb_enable_hw(drvdata);
}
spin_unlock_irqrestore(&drvdata->spinlock, flags);
- dev_info(drvdata->dev, "ETB dumped\n");
+ dev_dbg(drvdata->dev, "ETB dumped\n");
}
static int etb_open(struct inode *inode, struct file *file)
diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c
index 677695635211..abe8249b893b 100644
--- a/drivers/hwtracing/coresight/coresight-etm-perf.c
+++ b/drivers/hwtracing/coresight/coresight-etm-perf.c
@@ -12,6 +12,7 @@
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/perf_event.h>
+#include <linux/percpu-defs.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/workqueue.h>
@@ -22,20 +23,6 @@
static struct pmu etm_pmu;
static bool etm_perf_up;
-/**
- * struct etm_event_data - Coresight specifics associated to an event
- * @work: Handle to free allocated memory outside IRQ context.
- * @mask: Hold the CPU(s) this event was set for.
- * @snk_config: The sink configuration.
- * @path: An array of path, each slot for one CPU.
- */
-struct etm_event_data {
- struct work_struct work;
- cpumask_t mask;
- void *snk_config;
- struct list_head **path;
-};
-
static DEFINE_PER_CPU(struct perf_output_handle, ctx_handle);
static DEFINE_PER_CPU(struct coresight_device *, csdev_src);
@@ -61,6 +48,18 @@ static const struct attribute_group *etm_pmu_attr_groups[] = {
NULL,
};
+static inline struct list_head **
+etm_event_cpu_path_ptr(struct etm_event_data *data, int cpu)
+{
+ return per_cpu_ptr(data->path, cpu);
+}
+
+static inline struct list_head *
+etm_event_cpu_path(struct etm_event_data *data, int cpu)
+{
+ return *etm_event_cpu_path_ptr(data, cpu);
+}
+
static void etm_event_read(struct perf_event *event) {}
static int etm_addr_filters_alloc(struct perf_event *event)
@@ -114,29 +113,30 @@ static void free_event_data(struct work_struct *work)
event_data = container_of(work, struct etm_event_data, work);
mask = &event_data->mask;
- /*
- * First deal with the sink configuration. See comment in
- * etm_setup_aux() about why we take the first available path.
- */
- if (event_data->snk_config) {
+
+ /* Free the sink buffers, if there are any */
+ if (event_data->snk_config && !WARN_ON(cpumask_empty(mask))) {
cpu = cpumask_first(mask);
- sink = coresight_get_sink(event_data->path[cpu]);
+ sink = coresight_get_sink(etm_event_cpu_path(event_data, cpu));
if (sink_ops(sink)->free_buffer)
sink_ops(sink)->free_buffer(event_data->snk_config);
}
for_each_cpu(cpu, mask) {
- if (!(IS_ERR_OR_NULL(event_data->path[cpu])))
- coresight_release_path(event_data->path[cpu]);
+ struct list_head **ppath;
+
+ ppath = etm_event_cpu_path_ptr(event_data, cpu);
+ if (!(IS_ERR_OR_NULL(*ppath)))
+ coresight_release_path(*ppath);
+ *ppath = NULL;
}
- kfree(event_data->path);
+ free_percpu(event_data->path);
kfree(event_data);
}
static void *alloc_event_data(int cpu)
{
- int size;
cpumask_t *mask;
struct etm_event_data *event_data;
@@ -145,16 +145,12 @@ static void *alloc_event_data(int cpu)
if (!event_data)
return NULL;
- /* Make sure nothing disappears under us */
- get_online_cpus();
- size = num_online_cpus();
mask = &event_data->mask;
if (cpu != -1)
cpumask_set_cpu(cpu, mask);
else
- cpumask_copy(mask, cpu_online_mask);
- put_online_cpus();
+ cpumask_copy(mask, cpu_present_mask);
/*
* Each CPU has a single path between source and destination. As such
@@ -164,8 +160,8 @@ static void *alloc_event_data(int cpu)
* unused memory when dealing with single CPU trace scenarios is small
* compared to the cost of searching through an optimized array.
*/
- event_data->path = kcalloc(size,
- sizeof(struct list_head *), GFP_KERNEL);
+ event_data->path = alloc_percpu(struct list_head *);
+
if (!event_data->path) {
kfree(event_data);
return NULL;
@@ -206,34 +202,53 @@ static void *etm_setup_aux(int event_cpu, void **pages,
* on the cmd line. As such the "enable_sink" flag in sysFS is reset.
*/
sink = coresight_get_enabled_sink(true);
- if (!sink)
+ if (!sink || !sink_ops(sink)->alloc_buffer)
goto err;
mask = &event_data->mask;
- /* Setup the path for each CPU in a trace session */
+ /*
+ * Setup the path for each CPU in a trace session. We try to build
+ * trace path for each CPU in the mask. If we don't find an ETM
+ * for the CPU or fail to build a path, we clear the CPU from the
+ * mask and continue with the rest. If ever we try to trace on those
+ * CPUs, we can handle it and fail the session.
+ */
for_each_cpu(cpu, mask) {
+ struct list_head *path;
struct coresight_device *csdev;
csdev = per_cpu(csdev_src, cpu);
- if (!csdev)
- goto err;
+ /*
+ * If there is no ETM associated with this CPU clear it from
+ * the mask and continue with the rest. If ever we try to trace
+ * on this CPU, we handle it accordingly.
+ */
+ if (!csdev) {
+ cpumask_clear_cpu(cpu, mask);
+ continue;
+ }
/*
* Building a path doesn't enable it, it simply builds a
* list of devices from source to sink that can be
* referenced later when the path is actually needed.
*/
- event_data->path[cpu] = coresight_build_path(csdev, sink);
- if (IS_ERR(event_data->path[cpu]))
- goto err;
+ path = coresight_build_path(csdev, sink);
+ if (IS_ERR(path)) {
+ cpumask_clear_cpu(cpu, mask);
+ continue;
+ }
+
+ *etm_event_cpu_path_ptr(event_data, cpu) = path;
}
- if (!sink_ops(sink)->alloc_buffer)
+ /* If we don't have any CPUs ready for tracing, abort */
+ cpu = cpumask_first(mask);
+ if (cpu >= nr_cpu_ids)
goto err;
- cpu = cpumask_first(mask);
- /* Get the AUX specific data from the sink buffer */
+ /* Allocate the sink buffer for this session */
event_data->snk_config =
sink_ops(sink)->alloc_buffer(sink, cpu, pages,
nr_pages, overwrite);
@@ -255,6 +270,7 @@ static void etm_event_start(struct perf_event *event, int flags)
struct etm_event_data *event_data;
struct perf_output_handle *handle = this_cpu_ptr(&ctx_handle);
struct coresight_device *sink, *csdev = per_cpu(csdev_src, cpu);
+ struct list_head *path;
if (!csdev)
goto fail;
@@ -267,18 +283,14 @@ static void etm_event_start(struct perf_event *event, int flags)
if (!event_data)
goto fail;
+ path = etm_event_cpu_path(event_data, cpu);
/* We need a sink, no need to continue without one */
- sink = coresight_get_sink(event_data->path[cpu]);
- if (WARN_ON_ONCE(!sink || !sink_ops(sink)->set_buffer))
- goto fail_end_stop;
-
- /* Configure the sink */
- if (sink_ops(sink)->set_buffer(sink, handle,
- event_data->snk_config))
+ sink = coresight_get_sink(path);
+ if (WARN_ON_ONCE(!sink))
goto fail_end_stop;
/* Nothing will happen without a path */
- if (coresight_enable_path(event_data->path[cpu], CS_MODE_PERF))
+ if (coresight_enable_path(path, CS_MODE_PERF, handle))
goto fail_end_stop;
/* Tell the perf core the event is alive */
@@ -286,11 +298,13 @@ static void etm_event_start(struct perf_event *event, int flags)
/* Finally enable the tracer */
if (source_ops(csdev)->enable(csdev, event, CS_MODE_PERF))
- goto fail_end_stop;
+ goto fail_disable_path;
out:
return;
+fail_disable_path:
+ coresight_disable_path(path);
fail_end_stop:
perf_aux_output_flag(handle, PERF_AUX_FLAG_TRUNCATED);
perf_aux_output_end(handle, 0);
@@ -306,6 +320,7 @@ static void etm_event_stop(struct perf_event *event, int mode)
struct coresight_device *sink, *csdev = per_cpu(csdev_src, cpu);
struct perf_output_handle *handle = this_cpu_ptr(&ctx_handle);
struct etm_event_data *event_data = perf_get_aux(handle);
+ struct list_head *path;
if (event->hw.state == PERF_HES_STOPPED)
return;
@@ -313,7 +328,11 @@ static void etm_event_stop(struct perf_event *event, int mode)
if (!csdev)
return;
- sink = coresight_get_sink(event_data->path[cpu]);
+ path = etm_event_cpu_path(event_data, cpu);
+ if (!path)
+ return;
+
+ sink = coresight_get_sink(path);
if (!sink)
return;
@@ -331,20 +350,13 @@ static void etm_event_stop(struct perf_event *event, int mode)
if (!sink_ops(sink)->update_buffer)
return;
- sink_ops(sink)->update_buffer(sink, handle,
+ size = sink_ops(sink)->update_buffer(sink, handle,
event_data->snk_config);
-
- if (!sink_ops(sink)->reset_buffer)
- return;
-
- size = sink_ops(sink)->reset_buffer(sink, handle,
- event_data->snk_config);
-
perf_aux_output_end(handle, size);
}
/* Disabling the path make its elements available to other sessions */
- coresight_disable_path(event_data->path[cpu]);
+ coresight_disable_path(path);
}
static int etm_event_add(struct perf_event *event, int mode)
diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.h b/drivers/hwtracing/coresight/coresight-etm-perf.h
index 4197df4faf5e..da7d9336a15c 100644
--- a/drivers/hwtracing/coresight/coresight-etm-perf.h
+++ b/drivers/hwtracing/coresight/coresight-etm-perf.h
@@ -7,6 +7,7 @@
#ifndef _CORESIGHT_ETM_PERF_H
#define _CORESIGHT_ETM_PERF_H
+#include <linux/percpu-defs.h>
#include "coresight-priv.h"
struct coresight_device;
@@ -42,14 +43,39 @@ struct etm_filters {
bool ssstatus;
};
+/**
+ * struct etm_event_data - Coresight specifics associated to an event
+ * @work: Handle to free allocated memory outside IRQ context.
+ * @mask: Hold the CPU(s) this event was set for.
+ * @snk_config: The sink configuration.
+ * @path: An array of path, each slot for one CPU.
+ */
+struct etm_event_data {
+ struct work_struct work;
+ cpumask_t mask;
+ void *snk_config;
+ struct list_head * __percpu *path;
+};
#ifdef CONFIG_CORESIGHT
int etm_perf_symlink(struct coresight_device *csdev, bool link);
+static inline void *etm_perf_sink_config(struct perf_output_handle *handle)
+{
+ struct etm_event_data *data = perf_get_aux(handle);
+ if (data)
+ return data->snk_config;
+ return NULL;
+}
#else
static inline int etm_perf_symlink(struct coresight_device *csdev, bool link)
{ return -EINVAL; }
+static inline void *etm_perf_sink_config(struct perf_output_handle *handle)
+{
+ return NULL;
+}
+
#endif /* CONFIG_CORESIGHT */
#endif
diff --git a/drivers/hwtracing/coresight/coresight-etm3x.c b/drivers/hwtracing/coresight/coresight-etm3x.c
index 7c74263c333d..fd5c4cca7db5 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x.c
@@ -355,11 +355,10 @@ static int etm_parse_event_config(struct etm_drvdata *drvdata,
return 0;
}
-static void etm_enable_hw(void *info)
+static int etm_enable_hw(struct etm_drvdata *drvdata)
{
- int i;
+ int i, rc;
u32 etmcr;
- struct etm_drvdata *drvdata = info;
struct etm_config *config = &drvdata->config;
CS_UNLOCK(drvdata->base);
@@ -370,6 +369,9 @@ static void etm_enable_hw(void *info)
etm_set_pwrup(drvdata);
/* Make sure all registers are accessible */
etm_os_unlock(drvdata);
+ rc = coresight_claim_device_unlocked(drvdata->base);
+ if (rc)
+ goto done;
etm_set_prog(drvdata);
@@ -418,9 +420,29 @@ static void etm_enable_hw(void *info)
etm_writel(drvdata, 0x0, ETMVMIDCVR);
etm_clr_prog(drvdata);
+
+done:
+ if (rc)
+ etm_set_pwrdwn(drvdata);
CS_LOCK(drvdata->base);
- dev_dbg(drvdata->dev, "cpu: %d enable smp call done\n", drvdata->cpu);
+ dev_dbg(drvdata->dev, "cpu: %d enable smp call done: %d\n",
+ drvdata->cpu, rc);
+ return rc;
+}
+
+struct etm_enable_arg {
+ struct etm_drvdata *drvdata;
+ int rc;
+};
+
+static void etm_enable_hw_smp_call(void *info)
+{
+ struct etm_enable_arg *arg = info;
+
+ if (WARN_ON(!arg))
+ return;
+ arg->rc = etm_enable_hw(arg->drvdata);
}
static int etm_cpu_id(struct coresight_device *csdev)
@@ -475,14 +497,13 @@ static int etm_enable_perf(struct coresight_device *csdev,
/* Configure the tracer based on the session's specifics */
etm_parse_event_config(drvdata, event);
/* And enable it */
- etm_enable_hw(drvdata);
-
- return 0;
+ return etm_enable_hw(drvdata);
}
static int etm_enable_sysfs(struct coresight_device *csdev)
{
struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+ struct etm_enable_arg arg = { 0 };
int ret;
spin_lock(&drvdata->spinlock);
@@ -492,20 +513,21 @@ static int etm_enable_sysfs(struct coresight_device *csdev)
* hw configuration will take place on the local CPU during bring up.
*/
if (cpu_online(drvdata->cpu)) {
+ arg.drvdata = drvdata;
ret = smp_call_function_single(drvdata->cpu,
- etm_enable_hw, drvdata, 1);
- if (ret)
- goto err;
+ etm_enable_hw_smp_call, &arg, 1);
+ if (!ret)
+ ret = arg.rc;
+ if (!ret)
+ drvdata->sticky_enable = true;
+ } else {
+ ret = -ENODEV;
}
- drvdata->sticky_enable = true;
spin_unlock(&drvdata->spinlock);
- dev_info(drvdata->dev, "ETM tracing enabled\n");
- return 0;
-
-err:
- spin_unlock(&drvdata->spinlock);
+ if (!ret)
+ dev_dbg(drvdata->dev, "ETM tracing enabled\n");
return ret;
}
@@ -555,6 +577,8 @@ static void etm_disable_hw(void *info)
for (i = 0; i < drvdata->nr_cntr; i++)
config->cntr_val[i] = etm_readl(drvdata, ETMCNTVRn(i));
+ coresight_disclaim_device_unlocked(drvdata->base);
+
etm_set_pwrdwn(drvdata);
CS_LOCK(drvdata->base);
@@ -604,7 +628,7 @@ static void etm_disable_sysfs(struct coresight_device *csdev)
spin_unlock(&drvdata->spinlock);
cpus_read_unlock();
- dev_info(drvdata->dev, "ETM tracing disabled\n");
+ dev_dbg(drvdata->dev, "ETM tracing disabled\n");
}
static void etm_disable(struct coresight_device *csdev,
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c
index 1d94ebec027b..53e2fb6e86f6 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x.c
@@ -28,6 +28,7 @@
#include <linux/pm_runtime.h>
#include <asm/sections.h>
#include <asm/local.h>
+#include <asm/virt.h>
#include "coresight-etm4x.h"
#include "coresight-etm-perf.h"
@@ -77,16 +78,24 @@ static int etm4_trace_id(struct coresight_device *csdev)
return drvdata->trcid;
}
-static void etm4_enable_hw(void *info)
+struct etm4_enable_arg {
+ struct etmv4_drvdata *drvdata;
+ int rc;
+};
+
+static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
{
- int i;
- struct etmv4_drvdata *drvdata = info;
+ int i, rc;
struct etmv4_config *config = &drvdata->config;
CS_UNLOCK(drvdata->base);
etm4_os_unlock(drvdata);
+ rc = coresight_claim_device_unlocked(drvdata->base);
+ if (rc)
+ goto done;
+
/* Disable the trace unit before programming trace registers */
writel_relaxed(0, drvdata->base + TRCPRGCTLR);
@@ -174,9 +183,21 @@ static void etm4_enable_hw(void *info)
dev_err(drvdata->dev,
"timeout while waiting for Idle Trace Status\n");
+done:
CS_LOCK(drvdata->base);
- dev_dbg(drvdata->dev, "cpu: %d enable smp call done\n", drvdata->cpu);
+ dev_dbg(drvdata->dev, "cpu: %d enable smp call done: %d\n",
+ drvdata->cpu, rc);
+ return rc;
+}
+
+static void etm4_enable_hw_smp_call(void *info)
+{
+ struct etm4_enable_arg *arg = info;
+
+ if (WARN_ON(!arg))
+ return;
+ arg->rc = etm4_enable_hw(arg->drvdata);
}
static int etm4_parse_event_config(struct etmv4_drvdata *drvdata,
@@ -242,7 +263,7 @@ static int etm4_enable_perf(struct coresight_device *csdev,
if (ret)
goto out;
/* And enable it */
- etm4_enable_hw(drvdata);
+ ret = etm4_enable_hw(drvdata);
out:
return ret;
@@ -251,6 +272,7 @@ out:
static int etm4_enable_sysfs(struct coresight_device *csdev)
{
struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+ struct etm4_enable_arg arg = { 0 };
int ret;
spin_lock(&drvdata->spinlock);
@@ -259,19 +281,17 @@ static int etm4_enable_sysfs(struct coresight_device *csdev)
* Executing etm4_enable_hw on the cpu whose ETM is being enabled
* ensures that register writes occur when cpu is powered.
*/
+ arg.drvdata = drvdata;
ret = smp_call_function_single(drvdata->cpu,
- etm4_enable_hw, drvdata, 1);
- if (ret)
- goto err;
-
- drvdata->sticky_enable = true;
+ etm4_enable_hw_smp_call, &arg, 1);
+ if (!ret)
+ ret = arg.rc;
+ if (!ret)
+ drvdata->sticky_enable = true;
spin_unlock(&drvdata->spinlock);
- dev_info(drvdata->dev, "ETM tracing enabled\n");
- return 0;
-
-err:
- spin_unlock(&drvdata->spinlock);
+ if (!ret)
+ dev_dbg(drvdata->dev, "ETM tracing enabled\n");
return ret;
}
@@ -328,6 +348,8 @@ static void etm4_disable_hw(void *info)
isb();
writel_relaxed(control, drvdata->base + TRCPRGCTLR);
+ coresight_disclaim_device_unlocked(drvdata->base);
+
CS_LOCK(drvdata->base);
dev_dbg(drvdata->dev, "cpu: %d disable smp call done\n", drvdata->cpu);
@@ -380,7 +402,7 @@ static void etm4_disable_sysfs(struct coresight_device *csdev)
spin_unlock(&drvdata->spinlock);
cpus_read_unlock();
- dev_info(drvdata->dev, "ETM tracing disabled\n");
+ dev_dbg(drvdata->dev, "ETM tracing disabled\n");
}
static void etm4_disable(struct coresight_device *csdev,
@@ -605,7 +627,7 @@ static void etm4_set_default_config(struct etmv4_config *config)
config->vinst_ctrl |= BIT(0);
}
-static u64 etm4_get_access_type(struct etmv4_config *config)
+static u64 etm4_get_ns_access_type(struct etmv4_config *config)
{
u64 access_type = 0;
@@ -616,17 +638,26 @@ static u64 etm4_get_access_type(struct etmv4_config *config)
* Bit[13] Exception level 1 - OS
* Bit[14] Exception level 2 - Hypervisor
* Bit[15] Never implemented
- *
- * Always stay away from hypervisor mode.
*/
- access_type = ETM_EXLEVEL_NS_HYP;
-
- if (config->mode & ETM_MODE_EXCL_KERN)
- access_type |= ETM_EXLEVEL_NS_OS;
+ if (!is_kernel_in_hyp_mode()) {
+ /* Stay away from hypervisor mode for non-VHE */
+ access_type = ETM_EXLEVEL_NS_HYP;
+ if (config->mode & ETM_MODE_EXCL_KERN)
+ access_type |= ETM_EXLEVEL_NS_OS;
+ } else if (config->mode & ETM_MODE_EXCL_KERN) {
+ access_type = ETM_EXLEVEL_NS_HYP;
+ }
if (config->mode & ETM_MODE_EXCL_USER)
access_type |= ETM_EXLEVEL_NS_APP;
+ return access_type;
+}
+
+static u64 etm4_get_access_type(struct etmv4_config *config)
+{
+ u64 access_type = etm4_get_ns_access_type(config);
+
/*
* EXLEVEL_S, bits[11:8], don't trace anything happening
* in secure state.
@@ -880,20 +911,10 @@ void etm4_config_trace_mode(struct etmv4_config *config)
addr_acc = config->addr_acc[ETM_DEFAULT_ADDR_COMP];
/* clear default config */
- addr_acc &= ~(ETM_EXLEVEL_NS_APP | ETM_EXLEVEL_NS_OS);
+ addr_acc &= ~(ETM_EXLEVEL_NS_APP | ETM_EXLEVEL_NS_OS |
+ ETM_EXLEVEL_NS_HYP);
- /*
- * EXLEVEL_NS, bits[15:12]
- * The Exception levels are:
- * Bit[12] Exception level 0 - Application
- * Bit[13] Exception level 1 - OS
- * Bit[14] Exception level 2 - Hypervisor
- * Bit[15] Never implemented
- */
- if (mode & ETM_MODE_EXCL_KERN)
- addr_acc |= ETM_EXLEVEL_NS_OS;
- else
- addr_acc |= ETM_EXLEVEL_NS_APP;
+ addr_acc |= etm4_get_ns_access_type(config);
config->addr_acc[ETM_DEFAULT_ADDR_COMP] = addr_acc;
config->addr_acc[ETM_DEFAULT_ADDR_COMP + 1] = addr_acc;
diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c
index 448145a36675..927925151509 100644
--- a/drivers/hwtracing/coresight/coresight-funnel.c
+++ b/drivers/hwtracing/coresight/coresight-funnel.c
@@ -25,6 +25,7 @@
#define FUNNEL_HOLDTIME_MASK 0xf00
#define FUNNEL_HOLDTIME_SHFT 0x8
#define FUNNEL_HOLDTIME (0x7 << FUNNEL_HOLDTIME_SHFT)
+#define FUNNEL_ENSx_MASK 0xff
/**
* struct funnel_drvdata - specifics associated to a funnel component
@@ -42,31 +43,42 @@ struct funnel_drvdata {
unsigned long priority;
};
-static void funnel_enable_hw(struct funnel_drvdata *drvdata, int port)
+static int funnel_enable_hw(struct funnel_drvdata *drvdata, int port)
{
u32 functl;
+ int rc = 0;
CS_UNLOCK(drvdata->base);
functl = readl_relaxed(drvdata->base + FUNNEL_FUNCTL);
+ /* Claim the device only when we enable the first slave */
+ if (!(functl & FUNNEL_ENSx_MASK)) {
+ rc = coresight_claim_device_unlocked(drvdata->base);
+ if (rc)
+ goto done;
+ }
+
functl &= ~FUNNEL_HOLDTIME_MASK;
functl |= FUNNEL_HOLDTIME;
functl |= (1 << port);
writel_relaxed(functl, drvdata->base + FUNNEL_FUNCTL);
writel_relaxed(drvdata->priority, drvdata->base + FUNNEL_PRICTL);
-
+done:
CS_LOCK(drvdata->base);
+ return rc;
}
static int funnel_enable(struct coresight_device *csdev, int inport,
int outport)
{
+ int rc;
struct funnel_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
- funnel_enable_hw(drvdata, inport);
+ rc = funnel_enable_hw(drvdata, inport);
- dev_info(drvdata->dev, "FUNNEL inport %d enabled\n", inport);
- return 0;
+ if (!rc)
+ dev_dbg(drvdata->dev, "FUNNEL inport %d enabled\n", inport);
+ return rc;
}
static void funnel_disable_hw(struct funnel_drvdata *drvdata, int inport)
@@ -79,6 +91,10 @@ static void funnel_disable_hw(struct funnel_drvdata *drvdata, int inport)
functl &= ~(1 << inport);
writel_relaxed(functl, drvdata->base + FUNNEL_FUNCTL);
+ /* Disclaim the device if none of the slaves are now active */
+ if (!(functl & FUNNEL_ENSx_MASK))
+ coresight_disclaim_device_unlocked(drvdata->base);
+
CS_LOCK(drvdata->base);
}
@@ -89,7 +105,7 @@ static void funnel_disable(struct coresight_device *csdev, int inport,
funnel_disable_hw(drvdata, inport);
- dev_info(drvdata->dev, "FUNNEL inport %d disabled\n", inport);
+ dev_dbg(drvdata->dev, "FUNNEL inport %d disabled\n", inport);
}
static const struct coresight_ops_link funnel_link_ops = {
diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h
index 1a6cf3589866..579f34943bf1 100644
--- a/drivers/hwtracing/coresight/coresight-priv.h
+++ b/drivers/hwtracing/coresight/coresight-priv.h
@@ -25,6 +25,13 @@
#define CORESIGHT_DEVID 0xfc8
#define CORESIGHT_DEVTYPE 0xfcc
+
+/*
+ * Coresight device CLAIM protocol.
+ * See PSCI - ARM DEN 0022D, Section: 6.8.1 Debug and Trace save and restore.
+ */
+#define CORESIGHT_CLAIM_SELF_HOSTED BIT(1)
+
#define TIMEOUT_US 100
#define BMVAL(val, lsb, msb) ((val & GENMASK(msb, lsb)) >> lsb)
@@ -137,7 +144,7 @@ static inline void coresight_write_reg_pair(void __iomem *addr, u64 val,
}
void coresight_disable_path(struct list_head *path);
-int coresight_enable_path(struct list_head *path, u32 mode);
+int coresight_enable_path(struct list_head *path, u32 mode, void *sink_data);
struct coresight_device *coresight_get_sink(struct list_head *path);
struct coresight_device *coresight_get_enabled_sink(bool reset);
struct list_head *coresight_build_path(struct coresight_device *csdev,
diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c
index 8d2eaaab6c2f..feac98315471 100644
--- a/drivers/hwtracing/coresight/coresight-replicator.c
+++ b/drivers/hwtracing/coresight/coresight-replicator.c
@@ -35,7 +35,7 @@ static int replicator_enable(struct coresight_device *csdev, int inport,
{
struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
- dev_info(drvdata->dev, "REPLICATOR enabled\n");
+ dev_dbg(drvdata->dev, "REPLICATOR enabled\n");
return 0;
}
@@ -44,7 +44,7 @@ static void replicator_disable(struct coresight_device *csdev, int inport,
{
struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
- dev_info(drvdata->dev, "REPLICATOR disabled\n");
+ dev_dbg(drvdata->dev, "REPLICATOR disabled\n");
}
static const struct coresight_ops_link replicator_link_ops = {
diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c
index c46c70aec1d5..35d6f9709274 100644
--- a/drivers/hwtracing/coresight/coresight-stm.c
+++ b/drivers/hwtracing/coresight/coresight-stm.c
@@ -211,7 +211,7 @@ static int stm_enable(struct coresight_device *csdev,
stm_enable_hw(drvdata);
spin_unlock(&drvdata->spinlock);
- dev_info(drvdata->dev, "STM tracing enabled\n");
+ dev_dbg(drvdata->dev, "STM tracing enabled\n");
return 0;
}
@@ -274,7 +274,7 @@ static void stm_disable(struct coresight_device *csdev,
pm_runtime_put(drvdata->dev);
local_set(&drvdata->mode, CS_MODE_DISABLED);
- dev_info(drvdata->dev, "STM tracing disabled\n");
+ dev_dbg(drvdata->dev, "STM tracing disabled\n");
}
}
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
index 0549249f4b39..53fc83b72a49 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
@@ -10,8 +10,12 @@
#include <linux/slab.h>
#include "coresight-priv.h"
#include "coresight-tmc.h"
+#include "coresight-etm-perf.h"
-static void tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
+static int tmc_set_etf_buffer(struct coresight_device *csdev,
+ struct perf_output_handle *handle);
+
+static void __tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
{
CS_UNLOCK(drvdata->base);
@@ -30,33 +34,41 @@ static void tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
CS_LOCK(drvdata->base);
}
+static int tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
+{
+ int rc = coresight_claim_device(drvdata->base);
+
+ if (rc)
+ return rc;
+
+ __tmc_etb_enable_hw(drvdata);
+ return 0;
+}
+
static void tmc_etb_dump_hw(struct tmc_drvdata *drvdata)
{
char *bufp;
u32 read_data, lost;
- int i;
/* Check if the buffer wrapped around. */
lost = readl_relaxed(drvdata->base + TMC_STS) & TMC_STS_FULL;
bufp = drvdata->buf;
drvdata->len = 0;
while (1) {
- for (i = 0; i < drvdata->memwidth; i++) {
- read_data = readl_relaxed(drvdata->base + TMC_RRD);
- if (read_data == 0xFFFFFFFF)
- goto done;
- memcpy(bufp, &read_data, 4);
- bufp += 4;
- drvdata->len += 4;
- }
+ read_data = readl_relaxed(drvdata->base + TMC_RRD);
+ if (read_data == 0xFFFFFFFF)
+ break;
+ memcpy(bufp, &read_data, 4);
+ bufp += 4;
+ drvdata->len += 4;
}
-done:
+
if (lost)
coresight_insert_barrier_packet(drvdata->buf);
return;
}
-static void tmc_etb_disable_hw(struct tmc_drvdata *drvdata)
+static void __tmc_etb_disable_hw(struct tmc_drvdata *drvdata)
{
CS_UNLOCK(drvdata->base);
@@ -72,7 +84,13 @@ static void tmc_etb_disable_hw(struct tmc_drvdata *drvdata)
CS_LOCK(drvdata->base);
}
-static void tmc_etf_enable_hw(struct tmc_drvdata *drvdata)
+static void tmc_etb_disable_hw(struct tmc_drvdata *drvdata)
+{
+ coresight_disclaim_device(drvdata);
+ __tmc_etb_disable_hw(drvdata);
+}
+
+static void __tmc_etf_enable_hw(struct tmc_drvdata *drvdata)
{
CS_UNLOCK(drvdata->base);
@@ -88,13 +106,24 @@ static void tmc_etf_enable_hw(struct tmc_drvdata *drvdata)
CS_LOCK(drvdata->base);
}
+static int tmc_etf_enable_hw(struct tmc_drvdata *drvdata)
+{
+ int rc = coresight_claim_device(drvdata->base);
+
+ if (rc)
+ return rc;
+
+ __tmc_etf_enable_hw(drvdata);
+ return 0;
+}
+
static void tmc_etf_disable_hw(struct tmc_drvdata *drvdata)
{
CS_UNLOCK(drvdata->base);
tmc_flush_and_stop(drvdata);
tmc_disable_hw(drvdata);
-
+ coresight_disclaim_device_unlocked(drvdata->base);
CS_LOCK(drvdata->base);
}
@@ -170,8 +199,12 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev)
drvdata->buf = buf;
}
- drvdata->mode = CS_MODE_SYSFS;
- tmc_etb_enable_hw(drvdata);
+ ret = tmc_etb_enable_hw(drvdata);
+ if (!ret)
+ drvdata->mode = CS_MODE_SYSFS;
+ else
+ /* Free up the buffer if we failed to enable */
+ used = false;
out:
spin_unlock_irqrestore(&drvdata->spinlock, flags);
@@ -182,37 +215,40 @@ out:
return ret;
}
-static int tmc_enable_etf_sink_perf(struct coresight_device *csdev)
+static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data)
{
int ret = 0;
unsigned long flags;
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+ struct perf_output_handle *handle = data;
spin_lock_irqsave(&drvdata->spinlock, flags);
- if (drvdata->reading) {
+ do {
ret = -EINVAL;
- goto out;
- }
-
- /*
- * In Perf mode there can be only one writer per sink. There
- * is also no need to continue if the ETB/ETR is already operated
- * from sysFS.
- */
- if (drvdata->mode != CS_MODE_DISABLED) {
- ret = -EINVAL;
- goto out;
- }
+ if (drvdata->reading)
+ break;
+ /*
+ * In Perf mode there can be only one writer per sink. There
+ * is also no need to continue if the ETB/ETF is already
+ * operated from sysFS.
+ */
+ if (drvdata->mode != CS_MODE_DISABLED)
+ break;
- drvdata->mode = CS_MODE_PERF;
- tmc_etb_enable_hw(drvdata);
-out:
+ ret = tmc_set_etf_buffer(csdev, handle);
+ if (ret)
+ break;
+ ret = tmc_etb_enable_hw(drvdata);
+ if (!ret)
+ drvdata->mode = CS_MODE_PERF;
+ } while (0);
spin_unlock_irqrestore(&drvdata->spinlock, flags);
return ret;
}
-static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode)
+static int tmc_enable_etf_sink(struct coresight_device *csdev,
+ u32 mode, void *data)
{
int ret;
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
@@ -222,7 +258,7 @@ static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode)
ret = tmc_enable_etf_sink_sysfs(csdev);
break;
case CS_MODE_PERF:
- ret = tmc_enable_etf_sink_perf(csdev);
+ ret = tmc_enable_etf_sink_perf(csdev, data);
break;
/* We shouldn't be here */
default:
@@ -233,7 +269,7 @@ static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode)
if (ret)
return ret;
- dev_info(drvdata->dev, "TMC-ETB/ETF enabled\n");
+ dev_dbg(drvdata->dev, "TMC-ETB/ETF enabled\n");
return 0;
}
@@ -256,12 +292,13 @@ static void tmc_disable_etf_sink(struct coresight_device *csdev)
spin_unlock_irqrestore(&drvdata->spinlock, flags);
- dev_info(drvdata->dev, "TMC-ETB/ETF disabled\n");
+ dev_dbg(drvdata->dev, "TMC-ETB/ETF disabled\n");
}
static int tmc_enable_etf_link(struct coresight_device *csdev,
int inport, int outport)
{
+ int ret;
unsigned long flags;
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
@@ -271,12 +308,14 @@ static int tmc_enable_etf_link(struct coresight_device *csdev,
return -EBUSY;
}
- tmc_etf_enable_hw(drvdata);
- drvdata->mode = CS_MODE_SYSFS;
+ ret = tmc_etf_enable_hw(drvdata);
+ if (!ret)
+ drvdata->mode = CS_MODE_SYSFS;
spin_unlock_irqrestore(&drvdata->spinlock, flags);
- dev_info(drvdata->dev, "TMC-ETF enabled\n");
- return 0;
+ if (!ret)
+ dev_dbg(drvdata->dev, "TMC-ETF enabled\n");
+ return ret;
}
static void tmc_disable_etf_link(struct coresight_device *csdev,
@@ -295,7 +334,7 @@ static void tmc_disable_etf_link(struct coresight_device *csdev,
drvdata->mode = CS_MODE_DISABLED;
spin_unlock_irqrestore(&drvdata->spinlock, flags);
- dev_info(drvdata->dev, "TMC-ETF disabled\n");
+ dev_dbg(drvdata->dev, "TMC-ETF disabled\n");
}
static void *tmc_alloc_etf_buffer(struct coresight_device *csdev, int cpu,
@@ -328,12 +367,14 @@ static void tmc_free_etf_buffer(void *config)
}
static int tmc_set_etf_buffer(struct coresight_device *csdev,
- struct perf_output_handle *handle,
- void *sink_config)
+ struct perf_output_handle *handle)
{
int ret = 0;
unsigned long head;
- struct cs_buffers *buf = sink_config;
+ struct cs_buffers *buf = etm_perf_sink_config(handle);
+
+ if (!buf)
+ return -EINVAL;
/* wrap head around to the amount of space we have */
head = handle->head & ((buf->nr_pages << PAGE_SHIFT) - 1);
@@ -349,36 +390,7 @@ static int tmc_set_etf_buffer(struct coresight_device *csdev,
return ret;
}
-static unsigned long tmc_reset_etf_buffer(struct coresight_device *csdev,
- struct perf_output_handle *handle,
- void *sink_config)
-{
- long size = 0;
- struct cs_buffers *buf = sink_config;
-
- if (buf) {
- /*
- * In snapshot mode ->data_size holds the new address of the
- * ring buffer's head. The size itself is the whole address
- * range since we want the latest information.
- */
- if (buf->snapshot)
- handle->head = local_xchg(&buf->data_size,
- buf->nr_pages << PAGE_SHIFT);
- /*
- * Tell the tracer PMU how much we got in this run and if
- * something went wrong along the way. Nobody else can use
- * this cs_buffers instance until we are done. As such
- * resetting parameters here and squaring off with the ring
- * buffer API in the tracer PMU is fine.
- */
- size = local_xchg(&buf->data_size, 0);
- }
-
- return size;
-}
-
-static void tmc_update_etf_buffer(struct coresight_device *csdev,
+static unsigned long tmc_update_etf_buffer(struct coresight_device *csdev,
struct perf_output_handle *handle,
void *sink_config)
{
@@ -387,17 +399,17 @@ static void tmc_update_etf_buffer(struct coresight_device *csdev,
const u32 *barrier;
u32 *buf_ptr;
u64 read_ptr, write_ptr;
- u32 status, to_read;
- unsigned long offset;
+ u32 status;
+ unsigned long offset, to_read;
struct cs_buffers *buf = sink_config;
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
if (!buf)
- return;
+ return 0;
/* This shouldn't happen */
if (WARN_ON_ONCE(drvdata->mode != CS_MODE_PERF))
- return;
+ return 0;
CS_UNLOCK(drvdata->base);
@@ -438,10 +450,10 @@ static void tmc_update_etf_buffer(struct coresight_device *csdev,
case TMC_MEM_INTF_WIDTH_32BITS:
case TMC_MEM_INTF_WIDTH_64BITS:
case TMC_MEM_INTF_WIDTH_128BITS:
- mask = GENMASK(31, 5);
+ mask = GENMASK(31, 4);
break;
case TMC_MEM_INTF_WIDTH_256BITS:
- mask = GENMASK(31, 6);
+ mask = GENMASK(31, 5);
break;
}
@@ -486,18 +498,14 @@ static void tmc_update_etf_buffer(struct coresight_device *csdev,
}
}
- /*
- * In snapshot mode all we have to do is communicate to
- * perf_aux_output_end() the address of the current head. In full
- * trace mode the same function expects a size to move rb->aux_head
- * forward.
- */
- if (buf->snapshot)
- local_set(&buf->data_size, (cur * PAGE_SIZE) + offset);
- else
- local_add(to_read, &buf->data_size);
-
+ /* In snapshot mode we have to update the head */
+ if (buf->snapshot) {
+ handle->head = (cur * PAGE_SIZE) + offset;
+ to_read = buf->nr_pages << PAGE_SHIFT;
+ }
CS_LOCK(drvdata->base);
+
+ return to_read;
}
static const struct coresight_ops_sink tmc_etf_sink_ops = {
@@ -505,8 +513,6 @@ static const struct coresight_ops_sink tmc_etf_sink_ops = {
.disable = tmc_disable_etf_sink,
.alloc_buffer = tmc_alloc_etf_buffer,
.free_buffer = tmc_free_etf_buffer,
- .set_buffer = tmc_set_etf_buffer,
- .reset_buffer = tmc_reset_etf_buffer,
.update_buffer = tmc_update_etf_buffer,
};
@@ -563,7 +569,7 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
/* Disable the TMC if need be */
if (drvdata->mode == CS_MODE_SYSFS)
- tmc_etb_disable_hw(drvdata);
+ __tmc_etb_disable_hw(drvdata);
drvdata->reading = true;
out:
@@ -603,7 +609,7 @@ int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata)
* can't be NULL.
*/
memset(drvdata->buf, 0, drvdata->size);
- tmc_etb_enable_hw(drvdata);
+ __tmc_etb_enable_hw(drvdata);
} else {
/*
* The ETB/ETF is not tracing and the buffer was just read.
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 2eda5de304c2..f684283890d3 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -10,6 +10,7 @@
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include "coresight-catu.h"
+#include "coresight-etm-perf.h"
#include "coresight-priv.h"
#include "coresight-tmc.h"
@@ -21,6 +22,28 @@ struct etr_flat_buf {
};
/*
+ * etr_perf_buffer - Perf buffer used for ETR
+ * @etr_buf - Actual buffer used by the ETR
+ * @snaphost - Perf session mode
+ * @head - handle->head at the beginning of the session.
+ * @nr_pages - Number of pages in the ring buffer.
+ * @pages - Array of Pages in the ring buffer.
+ */
+struct etr_perf_buffer {
+ struct etr_buf *etr_buf;
+ bool snapshot;
+ unsigned long head;
+ int nr_pages;
+ void **pages;
+};
+
+/* Convert the perf index to an offset within the ETR buffer */
+#define PERF_IDX2OFF(idx, buf) ((idx) % ((buf)->nr_pages << PAGE_SHIFT))
+
+/* Lower limit for ETR hardware buffer */
+#define TMC_ETR_PERF_MIN_BUF_SIZE SZ_1M
+
+/*
* The TMC ETR SG has a page size of 4K. The SG table contains pointers
* to 4KB buffers. However, the OS may use a PAGE_SIZE different from
* 4K (i.e, 16KB or 64KB). This implies that a single OS page could
@@ -536,7 +559,7 @@ tmc_init_etr_sg_table(struct device *dev, int node,
sg_table = tmc_alloc_sg_table(dev, node, nr_tpages, nr_dpages, pages);
if (IS_ERR(sg_table)) {
kfree(etr_table);
- return ERR_PTR(PTR_ERR(sg_table));
+ return ERR_CAST(sg_table);
}
etr_table->sg_table = sg_table;
@@ -728,12 +751,14 @@ tmc_etr_get_catu_device(struct tmc_drvdata *drvdata)
return NULL;
}
-static inline void tmc_etr_enable_catu(struct tmc_drvdata *drvdata)
+static inline int tmc_etr_enable_catu(struct tmc_drvdata *drvdata,
+ struct etr_buf *etr_buf)
{
struct coresight_device *catu = tmc_etr_get_catu_device(drvdata);
if (catu && helper_ops(catu)->enable)
- helper_ops(catu)->enable(catu, drvdata->etr_buf);
+ return helper_ops(catu)->enable(catu, etr_buf);
+ return 0;
}
static inline void tmc_etr_disable_catu(struct tmc_drvdata *drvdata)
@@ -895,17 +920,11 @@ static void tmc_sync_etr_buf(struct tmc_drvdata *drvdata)
tmc_etr_buf_insert_barrier_packet(etr_buf, etr_buf->offset);
}
-static void tmc_etr_enable_hw(struct tmc_drvdata *drvdata)
+static void __tmc_etr_enable_hw(struct tmc_drvdata *drvdata)
{
u32 axictl, sts;
struct etr_buf *etr_buf = drvdata->etr_buf;
- /*
- * If this ETR is connected to a CATU, enable it before we turn
- * this on
- */
- tmc_etr_enable_catu(drvdata);
-
CS_UNLOCK(drvdata->base);
/* Wait for TMCSReady bit to be set */
@@ -924,11 +943,8 @@ static void tmc_etr_enable_hw(struct tmc_drvdata *drvdata)
axictl |= TMC_AXICTL_ARCACHE_OS;
}
- if (etr_buf->mode == ETR_MODE_ETR_SG) {
- if (WARN_ON(!tmc_etr_has_cap(drvdata, TMC_ETR_SG)))
- return;
+ if (etr_buf->mode == ETR_MODE_ETR_SG)
axictl |= TMC_AXICTL_SCT_GAT_MODE;
- }
writel_relaxed(axictl, drvdata->base + TMC_AXICTL);
tmc_write_dba(drvdata, etr_buf->hwaddr);
@@ -954,19 +970,54 @@ static void tmc_etr_enable_hw(struct tmc_drvdata *drvdata)
CS_LOCK(drvdata->base);
}
+static int tmc_etr_enable_hw(struct tmc_drvdata *drvdata,
+ struct etr_buf *etr_buf)
+{
+ int rc;
+
+ /* Callers should provide an appropriate buffer for use */
+ if (WARN_ON(!etr_buf))
+ return -EINVAL;
+
+ if ((etr_buf->mode == ETR_MODE_ETR_SG) &&
+ WARN_ON(!tmc_etr_has_cap(drvdata, TMC_ETR_SG)))
+ return -EINVAL;
+
+ if (WARN_ON(drvdata->etr_buf))
+ return -EBUSY;
+
+ /*
+ * If this ETR is connected to a CATU, enable it before we turn
+ * this on.
+ */
+ rc = tmc_etr_enable_catu(drvdata, etr_buf);
+ if (rc)
+ return rc;
+ rc = coresight_claim_device(drvdata->base);
+ if (!rc) {
+ drvdata->etr_buf = etr_buf;
+ __tmc_etr_enable_hw(drvdata);
+ }
+
+ return rc;
+}
+
/*
* Return the available trace data in the buffer (starts at etr_buf->offset,
* limited by etr_buf->len) from @pos, with a maximum limit of @len,
* also updating the @bufpp on where to find it. Since the trace data
* starts at anywhere in the buffer, depending on the RRP, we adjust the
* @len returned to handle buffer wrapping around.
+ *
+ * We are protected here by drvdata->reading != 0, which ensures the
+ * sysfs_buf stays alive.
*/
ssize_t tmc_etr_get_sysfs_trace(struct tmc_drvdata *drvdata,
loff_t pos, size_t len, char **bufpp)
{
s64 offset;
ssize_t actual = len;
- struct etr_buf *etr_buf = drvdata->etr_buf;
+ struct etr_buf *etr_buf = drvdata->sysfs_buf;
if (pos + actual > etr_buf->len)
actual = etr_buf->len - pos;
@@ -996,10 +1047,17 @@ tmc_etr_free_sysfs_buf(struct etr_buf *buf)
static void tmc_etr_sync_sysfs_buf(struct tmc_drvdata *drvdata)
{
- tmc_sync_etr_buf(drvdata);
+ struct etr_buf *etr_buf = drvdata->etr_buf;
+
+ if (WARN_ON(drvdata->sysfs_buf != etr_buf)) {
+ tmc_etr_free_sysfs_buf(drvdata->sysfs_buf);
+ drvdata->sysfs_buf = NULL;
+ } else {
+ tmc_sync_etr_buf(drvdata);
+ }
}
-static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
+static void __tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
{
CS_UNLOCK(drvdata->base);
@@ -1015,8 +1073,16 @@ static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
CS_LOCK(drvdata->base);
+}
+
+static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
+{
+ __tmc_etr_disable_hw(drvdata);
/* Disable CATU device if this ETR is connected to one */
tmc_etr_disable_catu(drvdata);
+ coresight_disclaim_device(drvdata->base);
+ /* Reset the ETR buf used by hardware */
+ drvdata->etr_buf = NULL;
}
static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
@@ -1024,7 +1090,7 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
int ret = 0;
unsigned long flags;
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
- struct etr_buf *new_buf = NULL, *free_buf = NULL;
+ struct etr_buf *sysfs_buf = NULL, *new_buf = NULL, *free_buf = NULL;
/*
* If we are enabling the ETR from disabled state, we need to make
@@ -1035,7 +1101,8 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
* with the lock released.
*/
spin_lock_irqsave(&drvdata->spinlock, flags);
- if (!drvdata->etr_buf || (drvdata->etr_buf->size != drvdata->size)) {
+ sysfs_buf = READ_ONCE(drvdata->sysfs_buf);
+ if (!sysfs_buf || (sysfs_buf->size != drvdata->size)) {
spin_unlock_irqrestore(&drvdata->spinlock, flags);
/* Allocate memory with the locks released */
@@ -1064,14 +1131,15 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
* If we don't have a buffer or it doesn't match the requested size,
* use the buffer allocated above. Otherwise reuse the existing buffer.
*/
- if (!drvdata->etr_buf ||
- (new_buf && drvdata->etr_buf->size != new_buf->size)) {
- free_buf = drvdata->etr_buf;
- drvdata->etr_buf = new_buf;
+ sysfs_buf = READ_ONCE(drvdata->sysfs_buf);
+ if (!sysfs_buf || (new_buf && sysfs_buf->size != new_buf->size)) {
+ free_buf = sysfs_buf;
+ drvdata->sysfs_buf = new_buf;
}
- drvdata->mode = CS_MODE_SYSFS;
- tmc_etr_enable_hw(drvdata);
+ ret = tmc_etr_enable_hw(drvdata, drvdata->sysfs_buf);
+ if (!ret)
+ drvdata->mode = CS_MODE_SYSFS;
out:
spin_unlock_irqrestore(&drvdata->spinlock, flags);
@@ -1080,24 +1148,244 @@ out:
tmc_etr_free_sysfs_buf(free_buf);
if (!ret)
- dev_info(drvdata->dev, "TMC-ETR enabled\n");
+ dev_dbg(drvdata->dev, "TMC-ETR enabled\n");
return ret;
}
-static int tmc_enable_etr_sink_perf(struct coresight_device *csdev)
+/*
+ * tmc_etr_setup_perf_buf: Allocate ETR buffer for use by perf.
+ * The size of the hardware buffer is dependent on the size configured
+ * via sysfs and the perf ring buffer size. We prefer to allocate the
+ * largest possible size, scaling down the size by half until it
+ * reaches a minimum limit (1M), beyond which we give up.
+ */
+static struct etr_perf_buffer *
+tmc_etr_setup_perf_buf(struct tmc_drvdata *drvdata, int node, int nr_pages,
+ void **pages, bool snapshot)
{
- /* We don't support perf mode yet ! */
- return -EINVAL;
+ struct etr_buf *etr_buf;
+ struct etr_perf_buffer *etr_perf;
+ unsigned long size;
+
+ etr_perf = kzalloc_node(sizeof(*etr_perf), GFP_KERNEL, node);
+ if (!etr_perf)
+ return ERR_PTR(-ENOMEM);
+
+ /*
+ * Try to match the perf ring buffer size if it is larger
+ * than the size requested via sysfs.
+ */
+ if ((nr_pages << PAGE_SHIFT) > drvdata->size) {
+ etr_buf = tmc_alloc_etr_buf(drvdata, (nr_pages << PAGE_SHIFT),
+ 0, node, NULL);
+ if (!IS_ERR(etr_buf))
+ goto done;
+ }
+
+ /*
+ * Else switch to configured size for this ETR
+ * and scale down until we hit the minimum limit.
+ */
+ size = drvdata->size;
+ do {
+ etr_buf = tmc_alloc_etr_buf(drvdata, size, 0, node, NULL);
+ if (!IS_ERR(etr_buf))
+ goto done;
+ size /= 2;
+ } while (size >= TMC_ETR_PERF_MIN_BUF_SIZE);
+
+ kfree(etr_perf);
+ return ERR_PTR(-ENOMEM);
+
+done:
+ etr_perf->etr_buf = etr_buf;
+ return etr_perf;
}
-static int tmc_enable_etr_sink(struct coresight_device *csdev, u32 mode)
+
+static void *tmc_alloc_etr_buffer(struct coresight_device *csdev,
+ int cpu, void **pages, int nr_pages,
+ bool snapshot)
+{
+ struct etr_perf_buffer *etr_perf;
+ struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+ if (cpu == -1)
+ cpu = smp_processor_id();
+
+ etr_perf = tmc_etr_setup_perf_buf(drvdata, cpu_to_node(cpu),
+ nr_pages, pages, snapshot);
+ if (IS_ERR(etr_perf)) {
+ dev_dbg(drvdata->dev, "Unable to allocate ETR buffer\n");
+ return NULL;
+ }
+
+ etr_perf->snapshot = snapshot;
+ etr_perf->nr_pages = nr_pages;
+ etr_perf->pages = pages;
+
+ return etr_perf;
+}
+
+static void tmc_free_etr_buffer(void *config)
+{
+ struct etr_perf_buffer *etr_perf = config;
+
+ if (etr_perf->etr_buf)
+ tmc_free_etr_buf(etr_perf->etr_buf);
+ kfree(etr_perf);
+}
+
+/*
+ * tmc_etr_sync_perf_buffer: Copy the actual trace data from the hardware
+ * buffer to the perf ring buffer.
+ */
+static void tmc_etr_sync_perf_buffer(struct etr_perf_buffer *etr_perf)
+{
+ long bytes, to_copy;
+ long pg_idx, pg_offset, src_offset;
+ unsigned long head = etr_perf->head;
+ char **dst_pages, *src_buf;
+ struct etr_buf *etr_buf = etr_perf->etr_buf;
+
+ head = etr_perf->head;
+ pg_idx = head >> PAGE_SHIFT;
+ pg_offset = head & (PAGE_SIZE - 1);
+ dst_pages = (char **)etr_perf->pages;
+ src_offset = etr_buf->offset;
+ to_copy = etr_buf->len;
+
+ while (to_copy > 0) {
+ /*
+ * In one iteration, we can copy minimum of :
+ * 1) what is available in the source buffer,
+ * 2) what is available in the source buffer, before it
+ * wraps around.
+ * 3) what is available in the destination page.
+ * in one iteration.
+ */
+ bytes = tmc_etr_buf_get_data(etr_buf, src_offset, to_copy,
+ &src_buf);
+ if (WARN_ON_ONCE(bytes <= 0))
+ break;
+ bytes = min(bytes, (long)(PAGE_SIZE - pg_offset));
+
+ memcpy(dst_pages[pg_idx] + pg_offset, src_buf, bytes);
+
+ to_copy -= bytes;
+
+ /* Move destination pointers */
+ pg_offset += bytes;
+ if (pg_offset == PAGE_SIZE) {
+ pg_offset = 0;
+ if (++pg_idx == etr_perf->nr_pages)
+ pg_idx = 0;
+ }
+
+ /* Move source pointers */
+ src_offset += bytes;
+ if (src_offset >= etr_buf->size)
+ src_offset -= etr_buf->size;
+ }
+}
+
+/*
+ * tmc_update_etr_buffer : Update the perf ring buffer with the
+ * available trace data. We use software double buffering at the moment.
+ *
+ * TODO: Add support for reusing the perf ring buffer.
+ */
+static unsigned long
+tmc_update_etr_buffer(struct coresight_device *csdev,
+ struct perf_output_handle *handle,
+ void *config)
+{
+ bool lost = false;
+ unsigned long flags, size = 0;
+ struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+ struct etr_perf_buffer *etr_perf = config;
+ struct etr_buf *etr_buf = etr_perf->etr_buf;
+
+ spin_lock_irqsave(&drvdata->spinlock, flags);
+ if (WARN_ON(drvdata->perf_data != etr_perf)) {
+ lost = true;
+ spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ goto out;
+ }
+
+ CS_UNLOCK(drvdata->base);
+
+ tmc_flush_and_stop(drvdata);
+ tmc_sync_etr_buf(drvdata);
+
+ CS_LOCK(drvdata->base);
+ /* Reset perf specific data */
+ drvdata->perf_data = NULL;
+ spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+ size = etr_buf->len;
+ tmc_etr_sync_perf_buffer(etr_perf);
+
+ /*
+ * Update handle->head in snapshot mode. Also update the size to the
+ * hardware buffer size if there was an overflow.
+ */
+ if (etr_perf->snapshot) {
+ handle->head += size;
+ if (etr_buf->full)
+ size = etr_buf->size;
+ }
+
+ lost |= etr_buf->full;
+out:
+ if (lost)
+ perf_aux_output_flag(handle, PERF_AUX_FLAG_TRUNCATED);
+ return size;
+}
+
+static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data)
+{
+ int rc = 0;
+ unsigned long flags;
+ struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+ struct perf_output_handle *handle = data;
+ struct etr_perf_buffer *etr_perf = etm_perf_sink_config(handle);
+
+ spin_lock_irqsave(&drvdata->spinlock, flags);
+ /*
+ * There can be only one writer per sink in perf mode. If the sink
+ * is already open in SYSFS mode, we can't use it.
+ */
+ if (drvdata->mode != CS_MODE_DISABLED || WARN_ON(drvdata->perf_data)) {
+ rc = -EBUSY;
+ goto unlock_out;
+ }
+
+ if (WARN_ON(!etr_perf || !etr_perf->etr_buf)) {
+ rc = -EINVAL;
+ goto unlock_out;
+ }
+
+ etr_perf->head = PERF_IDX2OFF(handle->head, etr_perf);
+ drvdata->perf_data = etr_perf;
+ rc = tmc_etr_enable_hw(drvdata, etr_perf->etr_buf);
+ if (!rc)
+ drvdata->mode = CS_MODE_PERF;
+
+unlock_out:
+ spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ return rc;
+}
+
+static int tmc_enable_etr_sink(struct coresight_device *csdev,
+ u32 mode, void *data)
{
switch (mode) {
case CS_MODE_SYSFS:
return tmc_enable_etr_sink_sysfs(csdev);
case CS_MODE_PERF:
- return tmc_enable_etr_sink_perf(csdev);
+ return tmc_enable_etr_sink_perf(csdev, data);
}
/* We shouldn't be here */
@@ -1123,12 +1411,15 @@ static void tmc_disable_etr_sink(struct coresight_device *csdev)
spin_unlock_irqrestore(&drvdata->spinlock, flags);
- dev_info(drvdata->dev, "TMC-ETR disabled\n");
+ dev_dbg(drvdata->dev, "TMC-ETR disabled\n");
}
static const struct coresight_ops_sink tmc_etr_sink_ops = {
.enable = tmc_enable_etr_sink,
.disable = tmc_disable_etr_sink,
+ .alloc_buffer = tmc_alloc_etr_buffer,
+ .update_buffer = tmc_update_etr_buffer,
+ .free_buffer = tmc_free_etr_buffer,
};
const struct coresight_ops tmc_etr_cs_ops = {
@@ -1150,21 +1441,19 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
goto out;
}
- /* Don't interfere if operated from Perf */
- if (drvdata->mode == CS_MODE_PERF) {
- ret = -EINVAL;
- goto out;
- }
-
- /* If drvdata::etr_buf is NULL the trace data has been read already */
- if (drvdata->etr_buf == NULL) {
+ /*
+ * We can safely allow reads even if the ETR is operating in PERF mode,
+ * since the sysfs session is captured in mode specific data.
+ * If drvdata::sysfs_data is NULL the trace data has been read already.
+ */
+ if (!drvdata->sysfs_buf) {
ret = -EINVAL;
goto out;
}
- /* Disable the TMC if need be */
+ /* Disable the TMC if we are trying to read from a running session. */
if (drvdata->mode == CS_MODE_SYSFS)
- tmc_etr_disable_hw(drvdata);
+ __tmc_etr_disable_hw(drvdata);
drvdata->reading = true;
out:
@@ -1176,7 +1465,7 @@ out:
int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
{
unsigned long flags;
- struct etr_buf *etr_buf = NULL;
+ struct etr_buf *sysfs_buf = NULL;
/* config types are set a boot time and never change */
if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETR))
@@ -1191,22 +1480,22 @@ int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
* buffer. Since the tracer is still enabled drvdata::buf can't
* be NULL.
*/
- tmc_etr_enable_hw(drvdata);
+ __tmc_etr_enable_hw(drvdata);
} else {
/*
* The ETR is not tracing and the buffer was just read.
* As such prepare to free the trace buffer.
*/
- etr_buf = drvdata->etr_buf;
- drvdata->etr_buf = NULL;
+ sysfs_buf = drvdata->sysfs_buf;
+ drvdata->sysfs_buf = NULL;
}
drvdata->reading = false;
spin_unlock_irqrestore(&drvdata->spinlock, flags);
/* Free allocated memory out side of the spinlock */
- if (etr_buf)
- tmc_free_etr_buf(etr_buf);
+ if (sysfs_buf)
+ tmc_etr_free_sysfs_buf(sysfs_buf);
return 0;
}
diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
index 1b817ec1192c..ea249f0bcd73 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.c
+++ b/drivers/hwtracing/coresight/coresight-tmc.c
@@ -81,7 +81,7 @@ static int tmc_read_prepare(struct tmc_drvdata *drvdata)
}
if (!ret)
- dev_info(drvdata->dev, "TMC read start\n");
+ dev_dbg(drvdata->dev, "TMC read start\n");
return ret;
}
@@ -103,7 +103,7 @@ static int tmc_read_unprepare(struct tmc_drvdata *drvdata)
}
if (!ret)
- dev_info(drvdata->dev, "TMC read end\n");
+ dev_dbg(drvdata->dev, "TMC read end\n");
return ret;
}
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index 7027bd60c4cc..487c53701e9c 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -170,6 +170,8 @@ struct etr_buf {
* @trigger_cntr: amount of words to store after a trigger.
* @etr_caps: Bitmask of capabilities of the TMC ETR, inferred from the
* device configuration register (DEVID)
+ * @perf_data: PERF buffer for ETR.
+ * @sysfs_data: SYSFS buffer for ETR.
*/
struct tmc_drvdata {
void __iomem *base;
@@ -189,6 +191,8 @@ struct tmc_drvdata {
enum tmc_mem_intf_width memwidth;
u32 trigger_cntr;
u32 etr_caps;
+ struct etr_buf *sysfs_buf;
+ void *perf_data;
};
struct etr_buf_operations {
diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c
index 459ef930d98c..b2f72a1fa402 100644
--- a/drivers/hwtracing/coresight/coresight-tpiu.c
+++ b/drivers/hwtracing/coresight/coresight-tpiu.c
@@ -68,13 +68,13 @@ static void tpiu_enable_hw(struct tpiu_drvdata *drvdata)
CS_LOCK(drvdata->base);
}
-static int tpiu_enable(struct coresight_device *csdev, u32 mode)
+static int tpiu_enable(struct coresight_device *csdev, u32 mode, void *__unused)
{
struct tpiu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
tpiu_enable_hw(drvdata);
- dev_info(drvdata->dev, "TPIU enabled\n");
+ dev_dbg(drvdata->dev, "TPIU enabled\n");
return 0;
}
@@ -100,7 +100,7 @@ static void tpiu_disable(struct coresight_device *csdev)
tpiu_disable_hw(drvdata);
- dev_info(drvdata->dev, "TPIU disabled\n");
+ dev_dbg(drvdata->dev, "TPIU disabled\n");
}
static const struct coresight_ops_sink tpiu_sink_ops = {
diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c
index 3e07fd335f8c..2b0df1a0a8df 100644
--- a/drivers/hwtracing/coresight/coresight.c
+++ b/drivers/hwtracing/coresight/coresight.c
@@ -128,16 +128,105 @@ static int coresight_find_link_outport(struct coresight_device *csdev,
return -ENODEV;
}
-static int coresight_enable_sink(struct coresight_device *csdev, u32 mode)
+static inline u32 coresight_read_claim_tags(void __iomem *base)
+{
+ return readl_relaxed(base + CORESIGHT_CLAIMCLR);
+}
+
+static inline bool coresight_is_claimed_self_hosted(void __iomem *base)
+{
+ return coresight_read_claim_tags(base) == CORESIGHT_CLAIM_SELF_HOSTED;
+}
+
+static inline bool coresight_is_claimed_any(void __iomem *base)
+{
+ return coresight_read_claim_tags(base) != 0;
+}
+
+static inline void coresight_set_claim_tags(void __iomem *base)
+{
+ writel_relaxed(CORESIGHT_CLAIM_SELF_HOSTED, base + CORESIGHT_CLAIMSET);
+ isb();
+}
+
+static inline void coresight_clear_claim_tags(void __iomem *base)
+{
+ writel_relaxed(CORESIGHT_CLAIM_SELF_HOSTED, base + CORESIGHT_CLAIMCLR);
+ isb();
+}
+
+/*
+ * coresight_claim_device_unlocked : Claim the device for self-hosted usage
+ * to prevent an external tool from touching this device. As per PSCI
+ * standards, section "Preserving the execution context" => "Debug and Trace
+ * save and Restore", DBGCLAIM[1] is reserved for Self-hosted debug/trace and
+ * DBGCLAIM[0] is reserved for external tools.
+ *
+ * Called with CS_UNLOCKed for the component.
+ * Returns : 0 on success
+ */
+int coresight_claim_device_unlocked(void __iomem *base)
+{
+ if (coresight_is_claimed_any(base))
+ return -EBUSY;
+
+ coresight_set_claim_tags(base);
+ if (coresight_is_claimed_self_hosted(base))
+ return 0;
+ /* There was a race setting the tags, clean up and fail */
+ coresight_clear_claim_tags(base);
+ return -EBUSY;
+}
+
+int coresight_claim_device(void __iomem *base)
+{
+ int rc;
+
+ CS_UNLOCK(base);
+ rc = coresight_claim_device_unlocked(base);
+ CS_LOCK(base);
+
+ return rc;
+}
+
+/*
+ * coresight_disclaim_device_unlocked : Clear the claim tags for the device.
+ * Called with CS_UNLOCKed for the component.
+ */
+void coresight_disclaim_device_unlocked(void __iomem *base)
+{
+
+ if (coresight_is_claimed_self_hosted(base))
+ coresight_clear_claim_tags(base);
+ else
+ /*
+ * The external agent may have not honoured our claim
+ * and has manipulated it. Or something else has seriously
+ * gone wrong in our driver.
+ */
+ WARN_ON_ONCE(1);
+}
+
+void coresight_disclaim_device(void __iomem *base)
+{
+ CS_UNLOCK(base);
+ coresight_disclaim_device_unlocked(base);
+ CS_LOCK(base);
+}
+
+static int coresight_enable_sink(struct coresight_device *csdev,
+ u32 mode, void *data)
{
int ret;
- if (!csdev->enable) {
- if (sink_ops(csdev)->enable) {
- ret = sink_ops(csdev)->enable(csdev, mode);
- if (ret)
- return ret;
- }
+ /*
+ * We need to make sure the "new" session is compatible with the
+ * existing "mode" of operation.
+ */
+ if (sink_ops(csdev)->enable) {
+ ret = sink_ops(csdev)->enable(csdev, mode, data);
+ if (ret)
+ return ret;
csdev->enable = true;
}
@@ -184,8 +273,10 @@ static int coresight_enable_link(struct coresight_device *csdev,
if (atomic_inc_return(&csdev->refcnt[refport]) == 1) {
if (link_ops(csdev)->enable) {
ret = link_ops(csdev)->enable(csdev, inport, outport);
- if (ret)
+ if (ret) {
+ atomic_dec(&csdev->refcnt[refport]);
return ret;
+ }
}
}
@@ -274,13 +365,21 @@ static bool coresight_disable_source(struct coresight_device *csdev)
return !csdev->enable;
}
-void coresight_disable_path(struct list_head *path)
+/*
+ * coresight_disable_path_from : Disable components in the given path beyond
+ * @nd in the list. If @nd is NULL, all the components, except the SOURCE are
+ * disabled.
+ */
+static void coresight_disable_path_from(struct list_head *path,
+ struct coresight_node *nd)
{
u32 type;
- struct coresight_node *nd;
struct coresight_device *csdev, *parent, *child;
- list_for_each_entry(nd, path, link) {
+ if (!nd)
+ nd = list_first_entry(path, struct coresight_node, link);
+
+ list_for_each_entry_continue(nd, path, link) {
csdev = nd->csdev;
type = csdev->type;
@@ -300,7 +399,12 @@ void coresight_disable_path(struct list_head *path)
coresight_disable_sink(csdev);
break;
case CORESIGHT_DEV_TYPE_SOURCE:
- /* sources are disabled from either sysFS or Perf */
+ /*
+ * We skip the first node in the path assuming that it
+ * is the source. So we don't expect a source device in
+ * the middle of a path.
+ */
+ WARN_ON(1);
break;
case CORESIGHT_DEV_TYPE_LINK:
parent = list_prev_entry(nd, link)->csdev;
@@ -313,7 +417,12 @@ void coresight_disable_path(struct list_head *path)
}
}
-int coresight_enable_path(struct list_head *path, u32 mode)
+void coresight_disable_path(struct list_head *path)
+{
+ coresight_disable_path_from(path, NULL);
+}
+
+int coresight_enable_path(struct list_head *path, u32 mode, void *sink_data)
{
int ret = 0;
@@ -338,9 +447,15 @@ int coresight_enable_path(struct list_head *path, u32 mode)
switch (type) {
case CORESIGHT_DEV_TYPE_SINK:
- ret = coresight_enable_sink(csdev, mode);
+ ret = coresight_enable_sink(csdev, mode, sink_data);
+ /*
+ * Sink is the first component turned on. If we
+ * failed to enable the sink, there are no components
+ * that need disabling. Disabling the path here
+ * would mean we could disrupt an existing session.
+ */
if (ret)
- goto err;
+ goto out;
break;
case CORESIGHT_DEV_TYPE_SOURCE:
/* sources are enabled from either sysFS or Perf */
@@ -360,7 +475,7 @@ int coresight_enable_path(struct list_head *path, u32 mode)
out:
return ret;
err:
- coresight_disable_path(path);
+ coresight_disable_path_from(path, nd);
goto out;
}
@@ -635,7 +750,7 @@ int coresight_enable(struct coresight_device *csdev)
goto out;
}
- ret = coresight_enable_path(path, CS_MODE_SYSFS);
+ ret = coresight_enable_path(path, CS_MODE_SYSFS, NULL);
if (ret)
goto err_path;
@@ -995,18 +1110,16 @@ postcore_initcall(coresight_init);
struct coresight_device *coresight_register(struct coresight_desc *desc)
{
- int i;
int ret;
int link_subtype;
int nr_refcnts = 1;
atomic_t *refcnts = NULL;
struct coresight_device *csdev;
- struct coresight_connection *conns = NULL;
csdev = kzalloc(sizeof(*csdev), GFP_KERNEL);
if (!csdev) {
ret = -ENOMEM;
- goto err_kzalloc_csdev;
+ goto err_out;
}
if (desc->type == CORESIGHT_DEV_TYPE_LINK ||
@@ -1022,7 +1135,7 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
refcnts = kcalloc(nr_refcnts, sizeof(*refcnts), GFP_KERNEL);
if (!refcnts) {
ret = -ENOMEM;
- goto err_kzalloc_refcnts;
+ goto err_free_csdev;
}
csdev->refcnt = refcnts;
@@ -1030,22 +1143,7 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
csdev->nr_inport = desc->pdata->nr_inport;
csdev->nr_outport = desc->pdata->nr_outport;
- /* Initialise connections if there is at least one outport */
- if (csdev->nr_outport) {
- conns = kcalloc(csdev->nr_outport, sizeof(*conns), GFP_KERNEL);
- if (!conns) {
- ret = -ENOMEM;
- goto err_kzalloc_conns;
- }
-
- for (i = 0; i < csdev->nr_outport; i++) {
- conns[i].outport = desc->pdata->outports[i];
- conns[i].child_name = desc->pdata->child_names[i];
- conns[i].child_port = desc->pdata->child_ports[i];
- }
- }
-
- csdev->conns = conns;
+ csdev->conns = desc->pdata->conns;
csdev->type = desc->type;
csdev->subtype = desc->subtype;
@@ -1062,7 +1160,11 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
ret = device_register(&csdev->dev);
if (ret) {
put_device(&csdev->dev);
- goto err_kzalloc_csdev;
+ /*
+ * All resources are free'd explicitly via
+ * coresight_device_release(), triggered from put_device().
+ */
+ goto err_out;
}
mutex_lock(&coresight_mutex);
@@ -1074,11 +1176,9 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
return csdev;
-err_kzalloc_conns:
- kfree(refcnts);
-err_kzalloc_refcnts:
+err_free_csdev:
kfree(csdev);
-err_kzalloc_csdev:
+err_out:
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(coresight_register);
diff --git a/drivers/hwtracing/coresight/of_coresight.c b/drivers/hwtracing/coresight/of_coresight.c
index 6880bee195c8..89092f83567e 100644
--- a/drivers/hwtracing/coresight/of_coresight.c
+++ b/drivers/hwtracing/coresight/of_coresight.c
@@ -45,8 +45,13 @@ of_coresight_get_endpoint_device(struct device_node *endpoint)
endpoint, of_dev_node_match);
}
-static void of_coresight_get_ports(const struct device_node *node,
- int *nr_inport, int *nr_outport)
+static inline bool of_coresight_legacy_ep_is_input(struct device_node *ep)
+{
+ return of_property_read_bool(ep, "slave-mode");
+}
+
+static void of_coresight_get_ports_legacy(const struct device_node *node,
+ int *nr_inport, int *nr_outport)
{
struct device_node *ep = NULL;
int in = 0, out = 0;
@@ -56,7 +61,7 @@ static void of_coresight_get_ports(const struct device_node *node,
if (!ep)
break;
- if (of_property_read_bool(ep, "slave-mode"))
+ if (of_coresight_legacy_ep_is_input(ep))
in++;
else
out++;
@@ -67,32 +72,77 @@ static void of_coresight_get_ports(const struct device_node *node,
*nr_outport = out;
}
+static struct device_node *of_coresight_get_port_parent(struct device_node *ep)
+{
+ struct device_node *parent = of_graph_get_port_parent(ep);
+
+ /*
+ * Skip one-level up to the real device node, if we
+ * are using the new bindings.
+ */
+ if (!of_node_cmp(parent->name, "in-ports") ||
+ !of_node_cmp(parent->name, "out-ports"))
+ parent = of_get_next_parent(parent);
+
+ return parent;
+}
+
+static inline struct device_node *
+of_coresight_get_input_ports_node(const struct device_node *node)
+{
+ return of_get_child_by_name(node, "in-ports");
+}
+
+static inline struct device_node *
+of_coresight_get_output_ports_node(const struct device_node *node)
+{
+ return of_get_child_by_name(node, "out-ports");
+}
+
+static inline int
+of_coresight_count_ports(struct device_node *port_parent)
+{
+ int i = 0;
+ struct device_node *ep = NULL;
+
+ while ((ep = of_graph_get_next_endpoint(port_parent, ep)))
+ i++;
+ return i;
+}
+
+static void of_coresight_get_ports(const struct device_node *node,
+ int *nr_inport, int *nr_outport)
+{
+ struct device_node *input_ports = NULL, *output_ports = NULL;
+
+ input_ports = of_coresight_get_input_ports_node(node);
+ output_ports = of_coresight_get_output_ports_node(node);
+
+ if (input_ports || output_ports) {
+ if (input_ports) {
+ *nr_inport = of_coresight_count_ports(input_ports);
+ of_node_put(input_ports);
+ }
+ if (output_ports) {
+ *nr_outport = of_coresight_count_ports(output_ports);
+ of_node_put(output_ports);
+ }
+ } else {
+ /* Fall back to legacy DT bindings parsing */
+ of_coresight_get_ports_legacy(node, nr_inport, nr_outport);
+ }
+}
+
static int of_coresight_alloc_memory(struct device *dev,
struct coresight_platform_data *pdata)
{
- /* List of output port on this component */
- pdata->outports = devm_kcalloc(dev,
- pdata->nr_outport,
- sizeof(*pdata->outports),
- GFP_KERNEL);
- if (!pdata->outports)
- return -ENOMEM;
-
- /* Children connected to this component via @outports */
- pdata->child_names = devm_kcalloc(dev,
- pdata->nr_outport,
- sizeof(*pdata->child_names),
- GFP_KERNEL);
- if (!pdata->child_names)
- return -ENOMEM;
-
- /* Port number on the child this component is connected to */
- pdata->child_ports = devm_kcalloc(dev,
- pdata->nr_outport,
- sizeof(*pdata->child_ports),
- GFP_KERNEL);
- if (!pdata->child_ports)
- return -ENOMEM;
+ if (pdata->nr_outport) {
+ pdata->conns = devm_kzalloc(dev, pdata->nr_outport *
+ sizeof(*pdata->conns),
+ GFP_KERNEL);
+ if (!pdata->conns)
+ return -ENOMEM;
+ }
return 0;
}
@@ -114,17 +164,78 @@ int of_coresight_get_cpu(const struct device_node *node)
}
EXPORT_SYMBOL_GPL(of_coresight_get_cpu);
+/*
+ * of_coresight_parse_endpoint : Parse the given output endpoint @ep
+ * and fill the connection information in @conn
+ *
+ * Parses the local port, remote device name and the remote port.
+ *
+ * Returns :
+ * 1 - If the parsing is successful and a connection record
+ * was created for an output connection.
+ * 0 - If the parsing completed without any fatal errors.
+ * -Errno - Fatal error, abort the scanning.
+ */
+static int of_coresight_parse_endpoint(struct device *dev,
+ struct device_node *ep,
+ struct coresight_connection *conn)
+{
+ int ret = 0;
+ struct of_endpoint endpoint, rendpoint;
+ struct device_node *rparent = NULL;
+ struct device_node *rep = NULL;
+ struct device *rdev = NULL;
+
+ do {
+ /* Parse the local port details */
+ if (of_graph_parse_endpoint(ep, &endpoint))
+ break;
+ /*
+ * Get a handle on the remote endpoint and the device it is
+ * attached to.
+ */
+ rep = of_graph_get_remote_endpoint(ep);
+ if (!rep)
+ break;
+ rparent = of_coresight_get_port_parent(rep);
+ if (!rparent)
+ break;
+ if (of_graph_parse_endpoint(rep, &rendpoint))
+ break;
+
+ /* If the remote device is not available, defer probing */
+ rdev = of_coresight_get_endpoint_device(rparent);
+ if (!rdev) {
+ ret = -EPROBE_DEFER;
+ break;
+ }
+
+ conn->outport = endpoint.port;
+ conn->child_name = devm_kstrdup(dev,
+ dev_name(rdev),
+ GFP_KERNEL);
+ conn->child_port = rendpoint.port;
+ /* Connection record updated */
+ ret = 1;
+ } while (0);
+
+ of_node_put(rparent);
+ of_node_put(rep);
+ put_device(rdev);
+
+ return ret;
+}
+
struct coresight_platform_data *
of_get_coresight_platform_data(struct device *dev,
const struct device_node *node)
{
- int i = 0, ret = 0;
+ int ret = 0;
struct coresight_platform_data *pdata;
- struct of_endpoint endpoint, rendpoint;
- struct device *rdev;
+ struct coresight_connection *conn;
struct device_node *ep = NULL;
- struct device_node *rparent = NULL;
- struct device_node *rport = NULL;
+ const struct device_node *parent = NULL;
+ bool legacy_binding = false;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
@@ -132,63 +243,54 @@ of_get_coresight_platform_data(struct device *dev,
/* Use device name as sysfs handle */
pdata->name = dev_name(dev);
+ pdata->cpu = of_coresight_get_cpu(node);
/* Get the number of input and output port for this component */
of_coresight_get_ports(node, &pdata->nr_inport, &pdata->nr_outport);
- if (pdata->nr_outport) {
- ret = of_coresight_alloc_memory(dev, pdata);
- if (ret)
- return ERR_PTR(ret);
-
- /* Iterate through each port to discover topology */
- do {
- /* Get a handle on a port */
- ep = of_graph_get_next_endpoint(node, ep);
- if (!ep)
- break;
-
- /*
- * No need to deal with input ports, processing for as
- * processing for output ports will deal with them.
- */
- if (of_find_property(ep, "slave-mode", NULL))
- continue;
-
- /* Get a handle on the local endpoint */
- ret = of_graph_parse_endpoint(ep, &endpoint);
-
- if (ret)
- continue;
-
- /* The local out port number */
- pdata->outports[i] = endpoint.port;
-
- /*
- * Get a handle on the remote port and parent
- * attached to it.
- */
- rparent = of_graph_get_remote_port_parent(ep);
- rport = of_graph_get_remote_port(ep);
-
- if (!rparent || !rport)
- continue;
+ /* If there are no output connections, we are done */
+ if (!pdata->nr_outport)
+ return pdata;
- if (of_graph_parse_endpoint(rport, &rendpoint))
- continue;
+ ret = of_coresight_alloc_memory(dev, pdata);
+ if (ret)
+ return ERR_PTR(ret);
- rdev = of_coresight_get_endpoint_device(rparent);
- if (!rdev)
- return ERR_PTR(-EPROBE_DEFER);
-
- pdata->child_names[i] = dev_name(rdev);
- pdata->child_ports[i] = rendpoint.id;
-
- i++;
- } while (ep);
+ parent = of_coresight_get_output_ports_node(node);
+ /*
+ * If the DT uses obsoleted bindings, the ports are listed
+ * under the device and we need to filter out the input
+ * ports.
+ */
+ if (!parent) {
+ legacy_binding = true;
+ parent = node;
+ dev_warn_once(dev, "Uses obsolete Coresight DT bindings\n");
}
- pdata->cpu = of_coresight_get_cpu(node);
+ conn = pdata->conns;
+
+ /* Iterate through each output port to discover topology */
+ while ((ep = of_graph_get_next_endpoint(parent, ep))) {
+ /*
+ * Legacy binding mixes input/output ports under the
+ * same parent. So, skip the input ports if we are dealing
+ * with legacy binding, as they processed with their
+ * connected output ports.
+ */
+ if (legacy_binding && of_coresight_legacy_ep_is_input(ep))
+ continue;
+
+ ret = of_coresight_parse_endpoint(dev, ep, conn);
+ switch (ret) {
+ case 1:
+ conn++; /* Fall through */
+ case 0:
+ break;
+ default:
+ return ERR_PTR(ret);
+ }
+ }
return pdata;
}
diff --git a/drivers/hwtracing/stm/Kconfig b/drivers/hwtracing/stm/Kconfig
index 723e2d90083d..752dd66742bf 100644
--- a/drivers/hwtracing/stm/Kconfig
+++ b/drivers/hwtracing/stm/Kconfig
@@ -11,6 +11,35 @@ config STM
if STM
+config STM_PROTO_BASIC
+ tristate "Basic STM framing protocol driver"
+ default CONFIG_STM
+ help
+ This is a simple framing protocol for sending data over STM
+ devices. This was the protocol that the STM framework used
+ exclusively until the MIPI SyS-T support was added. Use this
+ driver for compatibility with your existing STM setup.
+
+ The receiving side only needs to be able to decode the MIPI
+ STP protocol in order to extract the data.
+
+ If you want to be able to use the basic protocol or want the
+ backwards compatibility for your existing setup, say Y.
+
+config STM_PROTO_SYS_T
+ tristate "MIPI SyS-T STM framing protocol driver"
+ default CONFIG_STM
+ help
+ This is an implementation of MIPI SyS-T protocol to be used
+ over the STP transport. In addition to the data payload, it
+ also carries additional metadata for time correlation, better
+ means of trace source identification, etc.
+
+ The receiving side must be able to decode this protocol in
+ addition to the MIPI STP, in order to extract the data.
+
+ If you don't know what this is, say N.
+
config STM_DUMMY
tristate "Dummy STM driver"
help
diff --git a/drivers/hwtracing/stm/Makefile b/drivers/hwtracing/stm/Makefile
index effc19e5190f..1692fcd29277 100644
--- a/drivers/hwtracing/stm/Makefile
+++ b/drivers/hwtracing/stm/Makefile
@@ -3,6 +3,12 @@ obj-$(CONFIG_STM) += stm_core.o
stm_core-y := core.o policy.o
+obj-$(CONFIG_STM_PROTO_BASIC) += stm_p_basic.o
+obj-$(CONFIG_STM_PROTO_SYS_T) += stm_p_sys-t.o
+
+stm_p_basic-y := p_basic.o
+stm_p_sys-t-y := p_sys-t.o
+
obj-$(CONFIG_STM_DUMMY) += dummy_stm.o
obj-$(CONFIG_STM_SOURCE_CONSOLE) += stm_console.o
diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c
index 10bcb5d73f90..93ce3aa740a9 100644
--- a/drivers/hwtracing/stm/core.c
+++ b/drivers/hwtracing/stm/core.c
@@ -293,15 +293,15 @@ static int stm_output_assign(struct stm_device *stm, unsigned int width,
if (width > stm->data->sw_nchannels)
return -EINVAL;
- if (policy_node) {
- stp_policy_node_get_ranges(policy_node,
- &midx, &mend, &cidx, &cend);
- } else {
- midx = stm->data->sw_start;
- cidx = 0;
- mend = stm->data->sw_end;
- cend = stm->data->sw_nchannels - 1;
- }
+ /* We no longer accept policy_node==NULL here */
+ if (WARN_ON_ONCE(!policy_node))
+ return -EINVAL;
+
+ /*
+ * Also, the caller holds reference to policy_node, so it won't
+ * disappear on us.
+ */
+ stp_policy_node_get_ranges(policy_node, &midx, &mend, &cidx, &cend);
spin_lock(&stm->mc_lock);
spin_lock(&output->lock);
@@ -316,11 +316,26 @@ static int stm_output_assign(struct stm_device *stm, unsigned int width,
output->master = midx;
output->channel = cidx;
output->nr_chans = width;
+ if (stm->pdrv->output_open) {
+ void *priv = stp_policy_node_priv(policy_node);
+
+ if (WARN_ON_ONCE(!priv))
+ goto unlock;
+
+ /* configfs subsys mutex is held by the caller */
+ ret = stm->pdrv->output_open(priv, output);
+ if (ret)
+ goto unlock;
+ }
+
stm_output_claim(stm, output);
dev_dbg(&stm->dev, "assigned %u:%u (+%u)\n", midx, cidx, width);
ret = 0;
unlock:
+ if (ret)
+ output->nr_chans = 0;
+
spin_unlock(&output->lock);
spin_unlock(&stm->mc_lock);
@@ -333,6 +348,8 @@ static void stm_output_free(struct stm_device *stm, struct stm_output *output)
spin_lock(&output->lock);
if (output->nr_chans)
stm_output_disclaim(stm, output);
+ if (stm->pdrv && stm->pdrv->output_close)
+ stm->pdrv->output_close(output);
spin_unlock(&output->lock);
spin_unlock(&stm->mc_lock);
}
@@ -349,6 +366,127 @@ static int major_match(struct device *dev, const void *data)
return MAJOR(dev->devt) == major;
}
+/*
+ * Framing protocol management
+ * Modules can implement STM protocol drivers and (un-)register them
+ * with the STM class framework.
+ */
+static struct list_head stm_pdrv_head;
+static struct mutex stm_pdrv_mutex;
+
+struct stm_pdrv_entry {
+ struct list_head entry;
+ const struct stm_protocol_driver *pdrv;
+ const struct config_item_type *node_type;
+};
+
+static const struct stm_pdrv_entry *
+__stm_lookup_protocol(const char *name)
+{
+ struct stm_pdrv_entry *pe;
+
+ /*
+ * If no name is given (NULL or ""), fall back to "p_basic".
+ */
+ if (!name || !*name)
+ name = "p_basic";
+
+ list_for_each_entry(pe, &stm_pdrv_head, entry) {
+ if (!strcmp(name, pe->pdrv->name))
+ return pe;
+ }
+
+ return NULL;
+}
+
+int stm_register_protocol(const struct stm_protocol_driver *pdrv)
+{
+ struct stm_pdrv_entry *pe = NULL;
+ int ret = -ENOMEM;
+
+ mutex_lock(&stm_pdrv_mutex);
+
+ if (__stm_lookup_protocol(pdrv->name)) {
+ ret = -EEXIST;
+ goto unlock;
+ }
+
+ pe = kzalloc(sizeof(*pe), GFP_KERNEL);
+ if (!pe)
+ goto unlock;
+
+ if (pdrv->policy_attr) {
+ pe->node_type = get_policy_node_type(pdrv->policy_attr);
+ if (!pe->node_type)
+ goto unlock;
+ }
+
+ list_add_tail(&pe->entry, &stm_pdrv_head);
+ pe->pdrv = pdrv;
+
+ ret = 0;
+unlock:
+ mutex_unlock(&stm_pdrv_mutex);
+
+ if (ret)
+ kfree(pe);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(stm_register_protocol);
+
+void stm_unregister_protocol(const struct stm_protocol_driver *pdrv)
+{
+ struct stm_pdrv_entry *pe, *iter;
+
+ mutex_lock(&stm_pdrv_mutex);
+
+ list_for_each_entry_safe(pe, iter, &stm_pdrv_head, entry) {
+ if (pe->pdrv == pdrv) {
+ list_del(&pe->entry);
+
+ if (pe->node_type) {
+ kfree(pe->node_type->ct_attrs);
+ kfree(pe->node_type);
+ }
+ kfree(pe);
+ break;
+ }
+ }
+
+ mutex_unlock(&stm_pdrv_mutex);
+}
+EXPORT_SYMBOL_GPL(stm_unregister_protocol);
+
+static bool stm_get_protocol(const struct stm_protocol_driver *pdrv)
+{
+ return try_module_get(pdrv->owner);
+}
+
+void stm_put_protocol(const struct stm_protocol_driver *pdrv)
+{
+ module_put(pdrv->owner);
+}
+
+int stm_lookup_protocol(const char *name,
+ const struct stm_protocol_driver **pdrv,
+ const struct config_item_type **node_type)
+{
+ const struct stm_pdrv_entry *pe;
+
+ mutex_lock(&stm_pdrv_mutex);
+
+ pe = __stm_lookup_protocol(name);
+ if (pe && pe->pdrv && stm_get_protocol(pe->pdrv)) {
+ *pdrv = pe->pdrv;
+ *node_type = pe->node_type;
+ }
+
+ mutex_unlock(&stm_pdrv_mutex);
+
+ return pe ? 0 : -ENOENT;
+}
+
static int stm_char_open(struct inode *inode, struct file *file)
{
struct stm_file *stmf;
@@ -405,42 +543,81 @@ static int stm_char_release(struct inode *inode, struct file *file)
return 0;
}
-static int stm_file_assign(struct stm_file *stmf, char *id, unsigned int width)
+static int
+stm_assign_first_policy(struct stm_device *stm, struct stm_output *output,
+ char **ids, unsigned int width)
{
- struct stm_device *stm = stmf->stm;
- int ret;
+ struct stp_policy_node *pn;
+ int err, n;
- stmf->policy_node = stp_policy_node_lookup(stm, id);
+ /*
+ * On success, stp_policy_node_lookup() will return holding the
+ * configfs subsystem mutex, which is then released in
+ * stp_policy_node_put(). This allows the pdrv->output_open() in
+ * stm_output_assign() to serialize against the attribute accessors.
+ */
+ for (n = 0, pn = NULL; ids[n] && !pn; n++)
+ pn = stp_policy_node_lookup(stm, ids[n]);
- ret = stm_output_assign(stm, width, stmf->policy_node, &stmf->output);
+ if (!pn)
+ return -EINVAL;
- if (stmf->policy_node)
- stp_policy_node_put(stmf->policy_node);
+ err = stm_output_assign(stm, width, pn, output);
- return ret;
+ stp_policy_node_put(pn);
+
+ return err;
}
-static ssize_t notrace stm_write(struct stm_data *data, unsigned int master,
- unsigned int channel, const char *buf, size_t count)
+/**
+ * stm_data_write() - send the given payload as data packets
+ * @data: stm driver's data
+ * @m: STP master
+ * @c: STP channel
+ * @ts_first: timestamp the first packet
+ * @buf: data payload buffer
+ * @count: data payload size
+ */
+ssize_t notrace stm_data_write(struct stm_data *data, unsigned int m,
+ unsigned int c, bool ts_first, const void *buf,
+ size_t count)
{
- unsigned int flags = STP_PACKET_TIMESTAMPED;
- const unsigned char *p = buf, nil = 0;
- size_t pos;
+ unsigned int flags = ts_first ? STP_PACKET_TIMESTAMPED : 0;
ssize_t sz;
+ size_t pos;
- for (pos = 0, p = buf; count > pos; pos += sz, p += sz) {
+ for (pos = 0, sz = 0; pos < count; pos += sz) {
sz = min_t(unsigned int, count - pos, 8);
- sz = data->packet(data, master, channel, STP_PACKET_DATA, flags,
- sz, p);
- flags = 0;
-
- if (sz < 0)
+ sz = data->packet(data, m, c, STP_PACKET_DATA, flags, sz,
+ &((u8 *)buf)[pos]);
+ if (sz <= 0)
break;
+
+ if (ts_first) {
+ flags = 0;
+ ts_first = false;
+ }
}
- data->packet(data, master, channel, STP_PACKET_FLAG, 0, 0, &nil);
+ return sz < 0 ? sz : pos;
+}
+EXPORT_SYMBOL_GPL(stm_data_write);
+
+static ssize_t notrace
+stm_write(struct stm_device *stm, struct stm_output *output,
+ unsigned int chan, const char *buf, size_t count)
+{
+ int err;
+
+ /* stm->pdrv is serialized against policy_mutex */
+ if (!stm->pdrv)
+ return -ENODEV;
+
+ err = stm->pdrv->write(stm->data, output, chan, buf, count);
+ if (err < 0)
+ return err;
- return pos;
+ return err;
}
static ssize_t stm_char_write(struct file *file, const char __user *buf,
@@ -455,16 +632,21 @@ static ssize_t stm_char_write(struct file *file, const char __user *buf,
count = PAGE_SIZE - 1;
/*
- * if no m/c have been assigned to this writer up to this
- * point, use "default" policy entry
+ * If no m/c have been assigned to this writer up to this
+ * point, try to use the task name and "default" policy entries.
*/
if (!stmf->output.nr_chans) {
- err = stm_file_assign(stmf, "default", 1);
+ char comm[sizeof(current->comm)];
+ char *ids[] = { comm, "default", NULL };
+
+ get_task_comm(comm, current);
+
+ err = stm_assign_first_policy(stmf->stm, &stmf->output, ids, 1);
/*
* EBUSY means that somebody else just assigned this
* output, which is just fine for write()
*/
- if (err && err != -EBUSY)
+ if (err)
return err;
}
@@ -480,8 +662,7 @@ static ssize_t stm_char_write(struct file *file, const char __user *buf,
pm_runtime_get_sync(&stm->dev);
- count = stm_write(stm->data, stmf->output.master, stmf->output.channel,
- kbuf, count);
+ count = stm_write(stm, &stmf->output, 0, kbuf, count);
pm_runtime_mark_last_busy(&stm->dev);
pm_runtime_put_autosuspend(&stm->dev);
@@ -550,6 +731,7 @@ static int stm_char_policy_set_ioctl(struct stm_file *stmf, void __user *arg)
{
struct stm_device *stm = stmf->stm;
struct stp_policy_id *id;
+ char *ids[] = { NULL, NULL };
int ret = -EINVAL;
u32 size;
@@ -582,7 +764,9 @@ static int stm_char_policy_set_ioctl(struct stm_file *stmf, void __user *arg)
id->width > PAGE_SIZE / stm->data->sw_mmiosz)
goto err_free;
- ret = stm_file_assign(stmf, id->id, id->width);
+ ids[0] = id->id;
+ ret = stm_assign_first_policy(stmf->stm, &stmf->output, ids,
+ id->width);
if (ret)
goto err_free;
@@ -818,8 +1002,8 @@ EXPORT_SYMBOL_GPL(stm_unregister_device);
static int stm_source_link_add(struct stm_source_device *src,
struct stm_device *stm)
{
- char *id;
- int err;
+ char *ids[] = { NULL, "default", NULL };
+ int err = -ENOMEM;
mutex_lock(&stm->link_mutex);
spin_lock(&stm->link_lock);
@@ -833,19 +1017,13 @@ static int stm_source_link_add(struct stm_source_device *src,
spin_unlock(&stm->link_lock);
mutex_unlock(&stm->link_mutex);
- id = kstrdup(src->data->name, GFP_KERNEL);
- if (id) {
- src->policy_node =
- stp_policy_node_lookup(stm, id);
-
- kfree(id);
- }
-
- err = stm_output_assign(stm, src->data->nr_chans,
- src->policy_node, &src->output);
+ ids[0] = kstrdup(src->data->name, GFP_KERNEL);
+ if (!ids[0])
+ goto fail_detach;
- if (src->policy_node)
- stp_policy_node_put(src->policy_node);
+ err = stm_assign_first_policy(stm, &src->output, ids,
+ src->data->nr_chans);
+ kfree(ids[0]);
if (err)
goto fail_detach;
@@ -1134,9 +1312,7 @@ int notrace stm_source_write(struct stm_source_data *data,
stm = srcu_dereference(src->link, &stm_source_srcu);
if (stm)
- count = stm_write(stm->data, src->output.master,
- src->output.channel + chan,
- buf, count);
+ count = stm_write(stm, &src->output, chan, buf, count);
else
count = -ENODEV;
@@ -1163,7 +1339,15 @@ static int __init stm_core_init(void)
goto err_src;
init_srcu_struct(&stm_source_srcu);
+ INIT_LIST_HEAD(&stm_pdrv_head);
+ mutex_init(&stm_pdrv_mutex);
+ /*
+ * So as to not confuse existing users with a requirement
+ * to load yet another module, do it here.
+ */
+ if (IS_ENABLED(CONFIG_STM_PROTO_BASIC))
+ (void)request_module_nowait("stm_p_basic");
stm_core_up++;
return 0;
diff --git a/drivers/hwtracing/stm/heartbeat.c b/drivers/hwtracing/stm/heartbeat.c
index 7db42395e131..3e7df1c0477f 100644
--- a/drivers/hwtracing/stm/heartbeat.c
+++ b/drivers/hwtracing/stm/heartbeat.c
@@ -76,7 +76,7 @@ static int stm_heartbeat_init(void)
goto fail_unregister;
stm_heartbeat[i].data.nr_chans = 1;
- stm_heartbeat[i].data.link = stm_heartbeat_link;
+ stm_heartbeat[i].data.link = stm_heartbeat_link;
stm_heartbeat[i].data.unlink = stm_heartbeat_unlink;
hrtimer_init(&stm_heartbeat[i].hrtimer, CLOCK_MONOTONIC,
HRTIMER_MODE_ABS);
diff --git a/drivers/hwtracing/stm/p_basic.c b/drivers/hwtracing/stm/p_basic.c
new file mode 100644
index 000000000000..8980a6a5fd6c
--- /dev/null
+++ b/drivers/hwtracing/stm/p_basic.c
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Basic framing protocol for STM devices.
+ * Copyright (c) 2018, Intel Corporation.
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/stm.h>
+#include "stm.h"
+
+static ssize_t basic_write(struct stm_data *data, struct stm_output *output,
+ unsigned int chan, const char *buf, size_t count)
+{
+ unsigned int c = output->channel + chan;
+ unsigned int m = output->master;
+ const unsigned char nil = 0;
+ ssize_t sz;
+
+ sz = stm_data_write(data, m, c, true, buf, count);
+ if (sz > 0)
+ data->packet(data, m, c, STP_PACKET_FLAG, 0, 0, &nil);
+
+ return sz;
+}
+
+static const struct stm_protocol_driver basic_pdrv = {
+ .owner = THIS_MODULE,
+ .name = "p_basic",
+ .write = basic_write,
+};
+
+static int basic_stm_init(void)
+{
+ return stm_register_protocol(&basic_pdrv);
+}
+
+static void basic_stm_exit(void)
+{
+ stm_unregister_protocol(&basic_pdrv);
+}
+
+module_init(basic_stm_init);
+module_exit(basic_stm_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Basic STM framing protocol driver");
+MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@linux.intel.com>");
diff --git a/drivers/hwtracing/stm/p_sys-t.c b/drivers/hwtracing/stm/p_sys-t.c
new file mode 100644
index 000000000000..b178a5495b67
--- /dev/null
+++ b/drivers/hwtracing/stm/p_sys-t.c
@@ -0,0 +1,382 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MIPI SyS-T framing protocol for STM devices.
+ * Copyright (c) 2018, Intel Corporation.
+ */
+
+#include <linux/configfs.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/uuid.h>
+#include <linux/stm.h>
+#include "stm.h"
+
+enum sys_t_message_type {
+ MIPI_SYST_TYPE_BUILD = 0,
+ MIPI_SYST_TYPE_SHORT32,
+ MIPI_SYST_TYPE_STRING,
+ MIPI_SYST_TYPE_CATALOG,
+ MIPI_SYST_TYPE_RAW = 6,
+ MIPI_SYST_TYPE_SHORT64,
+ MIPI_SYST_TYPE_CLOCK,
+};
+
+enum sys_t_message_severity {
+ MIPI_SYST_SEVERITY_MAX = 0,
+ MIPI_SYST_SEVERITY_FATAL,
+ MIPI_SYST_SEVERITY_ERROR,
+ MIPI_SYST_SEVERITY_WARNING,
+ MIPI_SYST_SEVERITY_INFO,
+ MIPI_SYST_SEVERITY_USER1,
+ MIPI_SYST_SEVERITY_USER2,
+ MIPI_SYST_SEVERITY_DEBUG,
+};
+
+enum sys_t_message_build_subtype {
+ MIPI_SYST_BUILD_ID_COMPACT32 = 0,
+ MIPI_SYST_BUILD_ID_COMPACT64,
+ MIPI_SYST_BUILD_ID_LONG,
+};
+
+enum sys_t_message_clock_subtype {
+ MIPI_SYST_CLOCK_TRANSPORT_SYNC = 1,
+};
+
+enum sys_t_message_string_subtype {
+ MIPI_SYST_STRING_GENERIC = 1,
+ MIPI_SYST_STRING_FUNCTIONENTER,
+ MIPI_SYST_STRING_FUNCTIONEXIT,
+ MIPI_SYST_STRING_INVALIDPARAM = 5,
+ MIPI_SYST_STRING_ASSERT = 7,
+ MIPI_SYST_STRING_PRINTF_32 = 11,
+ MIPI_SYST_STRING_PRINTF_64 = 12,
+};
+
+#define MIPI_SYST_TYPE(t) ((u32)(MIPI_SYST_TYPE_ ## t))
+#define MIPI_SYST_SEVERITY(s) ((u32)(MIPI_SYST_SEVERITY_ ## s) << 4)
+#define MIPI_SYST_OPT_LOC BIT(8)
+#define MIPI_SYST_OPT_LEN BIT(9)
+#define MIPI_SYST_OPT_CHK BIT(10)
+#define MIPI_SYST_OPT_TS BIT(11)
+#define MIPI_SYST_UNIT(u) ((u32)(u) << 12)
+#define MIPI_SYST_ORIGIN(o) ((u32)(o) << 16)
+#define MIPI_SYST_OPT_GUID BIT(23)
+#define MIPI_SYST_SUBTYPE(s) ((u32)(MIPI_SYST_ ## s) << 24)
+#define MIPI_SYST_UNITLARGE(u) (MIPI_SYST_UNIT(u & 0xf) | \
+ MIPI_SYST_ORIGIN(u >> 4))
+#define MIPI_SYST_TYPES(t, s) (MIPI_SYST_TYPE(t) | \
+ MIPI_SYST_SUBTYPE(t ## _ ## s))
+
+#define DATA_HEADER (MIPI_SYST_TYPES(STRING, GENERIC) | \
+ MIPI_SYST_SEVERITY(INFO) | \
+ MIPI_SYST_OPT_GUID)
+
+#define CLOCK_SYNC_HEADER (MIPI_SYST_TYPES(CLOCK, TRANSPORT_SYNC) | \
+ MIPI_SYST_SEVERITY(MAX))
+
+struct sys_t_policy_node {
+ uuid_t uuid;
+ bool do_len;
+ unsigned long ts_interval;
+ unsigned long clocksync_interval;
+};
+
+struct sys_t_output {
+ struct sys_t_policy_node node;
+ unsigned long ts_jiffies;
+ unsigned long clocksync_jiffies;
+};
+
+static void sys_t_policy_node_init(void *priv)
+{
+ struct sys_t_policy_node *pn = priv;
+
+ generate_random_uuid(pn->uuid.b);
+}
+
+static int sys_t_output_open(void *priv, struct stm_output *output)
+{
+ struct sys_t_policy_node *pn = priv;
+ struct sys_t_output *opriv;
+
+ opriv = kzalloc(sizeof(*opriv), GFP_ATOMIC);
+ if (!opriv)
+ return -ENOMEM;
+
+ memcpy(&opriv->node, pn, sizeof(opriv->node));
+ output->pdrv_private = opriv;
+
+ return 0;
+}
+
+static void sys_t_output_close(struct stm_output *output)
+{
+ kfree(output->pdrv_private);
+}
+
+static ssize_t sys_t_policy_uuid_show(struct config_item *item,
+ char *page)
+{
+ struct sys_t_policy_node *pn = to_pdrv_policy_node(item);
+
+ return sprintf(page, "%pU\n", &pn->uuid);
+}
+
+static ssize_t
+sys_t_policy_uuid_store(struct config_item *item, const char *page,
+ size_t count)
+{
+ struct mutex *mutexp = &item->ci_group->cg_subsys->su_mutex;
+ struct sys_t_policy_node *pn = to_pdrv_policy_node(item);
+ int ret;
+
+ mutex_lock(mutexp);
+ ret = uuid_parse(page, &pn->uuid);
+ mutex_unlock(mutexp);
+
+ return ret < 0 ? ret : count;
+}
+
+CONFIGFS_ATTR(sys_t_policy_, uuid);
+
+static ssize_t sys_t_policy_do_len_show(struct config_item *item,
+ char *page)
+{
+ struct sys_t_policy_node *pn = to_pdrv_policy_node(item);
+
+ return sprintf(page, "%d\n", pn->do_len);
+}
+
+static ssize_t
+sys_t_policy_do_len_store(struct config_item *item, const char *page,
+ size_t count)
+{
+ struct mutex *mutexp = &item->ci_group->cg_subsys->su_mutex;
+ struct sys_t_policy_node *pn = to_pdrv_policy_node(item);
+ int ret;
+
+ mutex_lock(mutexp);
+ ret = kstrtobool(page, &pn->do_len);
+ mutex_unlock(mutexp);
+
+ return ret ? ret : count;
+}
+
+CONFIGFS_ATTR(sys_t_policy_, do_len);
+
+static ssize_t sys_t_policy_ts_interval_show(struct config_item *item,
+ char *page)
+{
+ struct sys_t_policy_node *pn = to_pdrv_policy_node(item);
+
+ return sprintf(page, "%u\n", jiffies_to_msecs(pn->ts_interval));
+}
+
+static ssize_t
+sys_t_policy_ts_interval_store(struct config_item *item, const char *page,
+ size_t count)
+{
+ struct mutex *mutexp = &item->ci_group->cg_subsys->su_mutex;
+ struct sys_t_policy_node *pn = to_pdrv_policy_node(item);
+ unsigned int ms;
+ int ret;
+
+ mutex_lock(mutexp);
+ ret = kstrtouint(page, 10, &ms);
+ mutex_unlock(mutexp);
+
+ if (!ret) {
+ pn->ts_interval = msecs_to_jiffies(ms);
+ return count;
+ }
+
+ return ret;
+}
+
+CONFIGFS_ATTR(sys_t_policy_, ts_interval);
+
+static ssize_t sys_t_policy_clocksync_interval_show(struct config_item *item,
+ char *page)
+{
+ struct sys_t_policy_node *pn = to_pdrv_policy_node(item);
+
+ return sprintf(page, "%u\n", jiffies_to_msecs(pn->clocksync_interval));
+}
+
+static ssize_t
+sys_t_policy_clocksync_interval_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct mutex *mutexp = &item->ci_group->cg_subsys->su_mutex;
+ struct sys_t_policy_node *pn = to_pdrv_policy_node(item);
+ unsigned int ms;
+ int ret;
+
+ mutex_lock(mutexp);
+ ret = kstrtouint(page, 10, &ms);
+ mutex_unlock(mutexp);
+
+ if (!ret) {
+ pn->clocksync_interval = msecs_to_jiffies(ms);
+ return count;
+ }
+
+ return ret;
+}
+
+CONFIGFS_ATTR(sys_t_policy_, clocksync_interval);
+
+static struct configfs_attribute *sys_t_policy_attrs[] = {
+ &sys_t_policy_attr_uuid,
+ &sys_t_policy_attr_do_len,
+ &sys_t_policy_attr_ts_interval,
+ &sys_t_policy_attr_clocksync_interval,
+ NULL,
+};
+
+static inline bool sys_t_need_ts(struct sys_t_output *op)
+{
+ if (op->node.ts_interval &&
+ time_after(op->ts_jiffies + op->node.ts_interval, jiffies)) {
+ op->ts_jiffies = jiffies;
+
+ return true;
+ }
+
+ return false;
+}
+
+static bool sys_t_need_clock_sync(struct sys_t_output *op)
+{
+ if (op->node.clocksync_interval &&
+ time_after(op->clocksync_jiffies + op->node.clocksync_interval,
+ jiffies)) {
+ op->clocksync_jiffies = jiffies;
+
+ return true;
+ }
+
+ return false;
+}
+
+static ssize_t
+sys_t_clock_sync(struct stm_data *data, unsigned int m, unsigned int c)
+{
+ u32 header = CLOCK_SYNC_HEADER;
+ const unsigned char nil = 0;
+ u64 payload[2]; /* Clock value and frequency */
+ ssize_t sz;
+
+ sz = data->packet(data, m, c, STP_PACKET_DATA, STP_PACKET_TIMESTAMPED,
+ 4, (u8 *)&header);
+ if (sz <= 0)
+ return sz;
+
+ payload[0] = ktime_get_real_ns();
+ payload[1] = NSEC_PER_SEC;
+ sz = stm_data_write(data, m, c, false, &payload, sizeof(payload));
+ if (sz <= 0)
+ return sz;
+
+ data->packet(data, m, c, STP_PACKET_FLAG, 0, 0, &nil);
+
+ return sizeof(header) + sizeof(payload);
+}
+
+static ssize_t sys_t_write(struct stm_data *data, struct stm_output *output,
+ unsigned int chan, const char *buf, size_t count)
+{
+ struct sys_t_output *op = output->pdrv_private;
+ unsigned int c = output->channel + chan;
+ unsigned int m = output->master;
+ const unsigned char nil = 0;
+ u32 header = DATA_HEADER;
+ ssize_t sz;
+
+ /* We require an existing policy node to proceed */
+ if (!op)
+ return -EINVAL;
+
+ if (sys_t_need_clock_sync(op)) {
+ sz = sys_t_clock_sync(data, m, c);
+ if (sz <= 0)
+ return sz;
+ }
+
+ if (op->node.do_len)
+ header |= MIPI_SYST_OPT_LEN;
+ if (sys_t_need_ts(op))
+ header |= MIPI_SYST_OPT_TS;
+
+ /*
+ * STP framing rules for SyS-T frames:
+ * * the first packet of the SyS-T frame is timestamped;
+ * * the last packet is a FLAG.
+ */
+ /* Message layout: HEADER / GUID / [LENGTH /][TIMESTAMP /] DATA */
+ /* HEADER */
+ sz = data->packet(data, m, c, STP_PACKET_DATA, STP_PACKET_TIMESTAMPED,
+ 4, (u8 *)&header);
+ if (sz <= 0)
+ return sz;
+
+ /* GUID */
+ sz = stm_data_write(data, m, c, false, op->node.uuid.b, UUID_SIZE);
+ if (sz <= 0)
+ return sz;
+
+ /* [LENGTH] */
+ if (op->node.do_len) {
+ u16 length = count;
+
+ sz = data->packet(data, m, c, STP_PACKET_DATA, 0, 2,
+ (u8 *)&length);
+ if (sz <= 0)
+ return sz;
+ }
+
+ /* [TIMESTAMP] */
+ if (header & MIPI_SYST_OPT_TS) {
+ u64 ts = ktime_get_real_ns();
+
+ sz = stm_data_write(data, m, c, false, &ts, sizeof(ts));
+ if (sz <= 0)
+ return sz;
+ }
+
+ /* DATA */
+ sz = stm_data_write(data, m, c, false, buf, count);
+ if (sz > 0)
+ data->packet(data, m, c, STP_PACKET_FLAG, 0, 0, &nil);
+
+ return sz;
+}
+
+static const struct stm_protocol_driver sys_t_pdrv = {
+ .owner = THIS_MODULE,
+ .name = "p_sys-t",
+ .priv_sz = sizeof(struct sys_t_policy_node),
+ .write = sys_t_write,
+ .policy_attr = sys_t_policy_attrs,
+ .policy_node_init = sys_t_policy_node_init,
+ .output_open = sys_t_output_open,
+ .output_close = sys_t_output_close,
+};
+
+static int sys_t_stm_init(void)
+{
+ return stm_register_protocol(&sys_t_pdrv);
+}
+
+static void sys_t_stm_exit(void)
+{
+ stm_unregister_protocol(&sys_t_pdrv);
+}
+
+module_init(sys_t_stm_init);
+module_exit(sys_t_stm_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MIPI SyS-T STM framing protocol driver");
+MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@linux.intel.com>");
diff --git a/drivers/hwtracing/stm/policy.c b/drivers/hwtracing/stm/policy.c
index 3fd07e275b34..0910ec807187 100644
--- a/drivers/hwtracing/stm/policy.c
+++ b/drivers/hwtracing/stm/policy.c
@@ -33,8 +33,18 @@ struct stp_policy_node {
unsigned int last_master;
unsigned int first_channel;
unsigned int last_channel;
+ /* this is the one that's exposed to the attributes */
+ unsigned char priv[0];
};
+void *stp_policy_node_priv(struct stp_policy_node *pn)
+{
+ if (!pn)
+ return NULL;
+
+ return pn->priv;
+}
+
static struct configfs_subsystem stp_policy_subsys;
void stp_policy_node_get_ranges(struct stp_policy_node *policy_node,
@@ -68,6 +78,14 @@ to_stp_policy_node(struct config_item *item)
NULL;
}
+void *to_pdrv_policy_node(struct config_item *item)
+{
+ struct stp_policy_node *node = to_stp_policy_node(item);
+
+ return stp_policy_node_priv(node);
+}
+EXPORT_SYMBOL_GPL(to_pdrv_policy_node);
+
static ssize_t
stp_policy_node_masters_show(struct config_item *item, char *page)
{
@@ -163,7 +181,9 @@ unlock:
static void stp_policy_node_release(struct config_item *item)
{
- kfree(to_stp_policy_node(item));
+ struct stp_policy_node *node = to_stp_policy_node(item);
+
+ kfree(node);
}
static struct configfs_item_operations stp_policy_node_item_ops = {
@@ -182,10 +202,34 @@ static struct configfs_attribute *stp_policy_node_attrs[] = {
static const struct config_item_type stp_policy_type;
static const struct config_item_type stp_policy_node_type;
+const struct config_item_type *
+get_policy_node_type(struct configfs_attribute **attrs)
+{
+ struct config_item_type *type;
+ struct configfs_attribute **merged;
+
+ type = kmemdup(&stp_policy_node_type, sizeof(stp_policy_node_type),
+ GFP_KERNEL);
+ if (!type)
+ return NULL;
+
+ merged = memcat_p(stp_policy_node_attrs, attrs);
+ if (!merged) {
+ kfree(type);
+ return NULL;
+ }
+
+ type->ct_attrs = merged;
+
+ return type;
+}
+
static struct config_group *
stp_policy_node_make(struct config_group *group, const char *name)
{
+ const struct config_item_type *type = &stp_policy_node_type;
struct stp_policy_node *policy_node, *parent_node;
+ const struct stm_protocol_driver *pdrv;
struct stp_policy *policy;
if (group->cg_item.ci_type == &stp_policy_type) {
@@ -199,12 +243,20 @@ stp_policy_node_make(struct config_group *group, const char *name)
if (!policy->stm)
return ERR_PTR(-ENODEV);
- policy_node = kzalloc(sizeof(struct stp_policy_node), GFP_KERNEL);
+ pdrv = policy->stm->pdrv;
+ policy_node =
+ kzalloc(offsetof(struct stp_policy_node, priv[pdrv->priv_sz]),
+ GFP_KERNEL);
if (!policy_node)
return ERR_PTR(-ENOMEM);
- config_group_init_type_name(&policy_node->group, name,
- &stp_policy_node_type);
+ if (pdrv->policy_node_init)
+ pdrv->policy_node_init((void *)policy_node->priv);
+
+ if (policy->stm->pdrv_node_type)
+ type = policy->stm->pdrv_node_type;
+
+ config_group_init_type_name(&policy_node->group, name, type);
policy_node->policy = policy;
@@ -254,8 +306,25 @@ static ssize_t stp_policy_device_show(struct config_item *item,
CONFIGFS_ATTR_RO(stp_policy_, device);
+static ssize_t stp_policy_protocol_show(struct config_item *item,
+ char *page)
+{
+ struct stp_policy *policy = to_stp_policy(item);
+ ssize_t count;
+
+ count = sprintf(page, "%s\n",
+ (policy && policy->stm) ?
+ policy->stm->pdrv->name :
+ "<none>");
+
+ return count;
+}
+
+CONFIGFS_ATTR_RO(stp_policy_, protocol);
+
static struct configfs_attribute *stp_policy_attrs[] = {
&stp_policy_attr_device,
+ &stp_policy_attr_protocol,
NULL,
};
@@ -276,6 +345,7 @@ void stp_policy_unbind(struct stp_policy *policy)
stm->policy = NULL;
policy->stm = NULL;
+ stm_put_protocol(stm->pdrv);
stm_put_device(stm);
}
@@ -311,11 +381,14 @@ static const struct config_item_type stp_policy_type = {
};
static struct config_group *
-stp_policies_make(struct config_group *group, const char *name)
+stp_policy_make(struct config_group *group, const char *name)
{
+ const struct config_item_type *pdrv_node_type;
+ const struct stm_protocol_driver *pdrv;
+ char *devname, *proto, *p;
struct config_group *ret;
struct stm_device *stm;
- char *devname, *p;
+ int err;
devname = kasprintf(GFP_KERNEL, "%s", name);
if (!devname)
@@ -326,6 +399,7 @@ stp_policies_make(struct config_group *group, const char *name)
* <device_name> is the name of an existing stm device; may
* contain dots;
* <policy_name> is an arbitrary string; may not contain dots
+ * <device_name>:<protocol_name>.<policy_name>
*/
p = strrchr(devname, '.');
if (!p) {
@@ -335,11 +409,28 @@ stp_policies_make(struct config_group *group, const char *name)
*p = '\0';
+ /*
+ * look for ":<protocol_name>":
+ * + no protocol suffix: fall back to whatever is available;
+ * + unknown protocol: fail the whole thing
+ */
+ proto = strrchr(devname, ':');
+ if (proto)
+ *proto++ = '\0';
+
stm = stm_find_device(devname);
+ if (!stm) {
+ kfree(devname);
+ return ERR_PTR(-ENODEV);
+ }
+
+ err = stm_lookup_protocol(proto, &pdrv, &pdrv_node_type);
kfree(devname);
- if (!stm)
+ if (err) {
+ stm_put_device(stm);
return ERR_PTR(-ENODEV);
+ }
mutex_lock(&stm->policy_mutex);
if (stm->policy) {
@@ -349,31 +440,37 @@ stp_policies_make(struct config_group *group, const char *name)
stm->policy = kzalloc(sizeof(*stm->policy), GFP_KERNEL);
if (!stm->policy) {
- ret = ERR_PTR(-ENOMEM);
- goto unlock_policy;
+ mutex_unlock(&stm->policy_mutex);
+ stm_put_protocol(pdrv);
+ stm_put_device(stm);
+ return ERR_PTR(-ENOMEM);
}
config_group_init_type_name(&stm->policy->group, name,
&stp_policy_type);
- stm->policy->stm = stm;
+ stm->pdrv = pdrv;
+ stm->pdrv_node_type = pdrv_node_type;
+ stm->policy->stm = stm;
ret = &stm->policy->group;
unlock_policy:
mutex_unlock(&stm->policy_mutex);
- if (IS_ERR(ret))
+ if (IS_ERR(ret)) {
+ stm_put_protocol(stm->pdrv);
stm_put_device(stm);
+ }
return ret;
}
-static struct configfs_group_operations stp_policies_group_ops = {
- .make_group = stp_policies_make,
+static struct configfs_group_operations stp_policy_root_group_ops = {
+ .make_group = stp_policy_make,
};
-static const struct config_item_type stp_policies_type = {
- .ct_group_ops = &stp_policies_group_ops,
+static const struct config_item_type stp_policy_root_type = {
+ .ct_group_ops = &stp_policy_root_group_ops,
.ct_owner = THIS_MODULE,
};
@@ -381,7 +478,7 @@ static struct configfs_subsystem stp_policy_subsys = {
.su_group = {
.cg_item = {
.ci_namebuf = "stp-policy",
- .ci_type = &stp_policies_type,
+ .ci_type = &stp_policy_root_type,
},
},
};
@@ -392,7 +489,7 @@ static struct configfs_subsystem stp_policy_subsys = {
static struct stp_policy_node *
__stp_policy_node_lookup(struct stp_policy *policy, char *s)
{
- struct stp_policy_node *policy_node, *ret;
+ struct stp_policy_node *policy_node, *ret = NULL;
struct list_head *head = &policy->group.cg_children;
struct config_item *item;
char *start, *end = s;
@@ -400,10 +497,6 @@ __stp_policy_node_lookup(struct stp_policy *policy, char *s)
if (list_empty(head))
return NULL;
- /* return the first entry if everything else fails */
- item = list_entry(head->next, struct config_item, ci_entry);
- ret = to_stp_policy_node(item);
-
next:
for (;;) {
start = strsep(&end, "/");
@@ -449,25 +542,25 @@ stp_policy_node_lookup(struct stm_device *stm, char *s)
if (policy_node)
config_item_get(&policy_node->group.cg_item);
- mutex_unlock(&stp_policy_subsys.su_mutex);
+ else
+ mutex_unlock(&stp_policy_subsys.su_mutex);
return policy_node;
}
void stp_policy_node_put(struct stp_policy_node *policy_node)
{
+ lockdep_assert_held(&stp_policy_subsys.su_mutex);
+
+ mutex_unlock(&stp_policy_subsys.su_mutex);
config_item_put(&policy_node->group.cg_item);
}
int __init stp_configfs_init(void)
{
- int err;
-
config_group_init(&stp_policy_subsys.su_group);
mutex_init(&stp_policy_subsys.su_mutex);
- err = configfs_register_subsystem(&stp_policy_subsys);
-
- return err;
+ return configfs_register_subsystem(&stp_policy_subsys);
}
void __exit stp_configfs_exit(void)
diff --git a/drivers/hwtracing/stm/stm.h b/drivers/hwtracing/stm/stm.h
index 923571adc6f4..3569439d53bb 100644
--- a/drivers/hwtracing/stm/stm.h
+++ b/drivers/hwtracing/stm/stm.h
@@ -10,20 +10,17 @@
#ifndef _STM_STM_H_
#define _STM_STM_H_
+#include <linux/configfs.h>
+
struct stp_policy;
struct stp_policy_node;
+struct stm_protocol_driver;
-struct stp_policy_node *
-stp_policy_node_lookup(struct stm_device *stm, char *s);
-void stp_policy_node_put(struct stp_policy_node *policy_node);
-void stp_policy_unbind(struct stp_policy *policy);
-
-void stp_policy_node_get_ranges(struct stp_policy_node *policy_node,
- unsigned int *mstart, unsigned int *mend,
- unsigned int *cstart, unsigned int *cend);
int stp_configfs_init(void);
void stp_configfs_exit(void);
+void *stp_policy_node_priv(struct stp_policy_node *pn);
+
struct stp_master {
unsigned int nr_free;
unsigned long chan_map[0];
@@ -40,6 +37,9 @@ struct stm_device {
struct mutex link_mutex;
spinlock_t link_lock;
struct list_head link_list;
+ /* framing protocol in use */
+ const struct stm_protocol_driver *pdrv;
+ const struct config_item_type *pdrv_node_type;
/* master allocation */
spinlock_t mc_lock;
struct stp_master *masters[0];
@@ -48,16 +48,28 @@ struct stm_device {
#define to_stm_device(_d) \
container_of((_d), struct stm_device, dev)
+struct stp_policy_node *
+stp_policy_node_lookup(struct stm_device *stm, char *s);
+void stp_policy_node_put(struct stp_policy_node *policy_node);
+void stp_policy_unbind(struct stp_policy *policy);
+
+void stp_policy_node_get_ranges(struct stp_policy_node *policy_node,
+ unsigned int *mstart, unsigned int *mend,
+ unsigned int *cstart, unsigned int *cend);
+
+const struct config_item_type *
+get_policy_node_type(struct configfs_attribute **attrs);
+
struct stm_output {
spinlock_t lock;
unsigned int master;
unsigned int channel;
unsigned int nr_chans;
+ void *pdrv_private;
};
struct stm_file {
struct stm_device *stm;
- struct stp_policy_node *policy_node;
struct stm_output output;
};
@@ -71,11 +83,35 @@ struct stm_source_device {
struct stm_device __rcu *link;
struct list_head link_entry;
/* one output per stm_source device */
- struct stp_policy_node *policy_node;
struct stm_output output;
};
#define to_stm_source_device(_d) \
container_of((_d), struct stm_source_device, dev)
+void *to_pdrv_policy_node(struct config_item *item);
+
+struct stm_protocol_driver {
+ struct module *owner;
+ const char *name;
+ ssize_t (*write)(struct stm_data *data,
+ struct stm_output *output, unsigned int chan,
+ const char *buf, size_t count);
+ void (*policy_node_init)(void *arg);
+ int (*output_open)(void *priv, struct stm_output *output);
+ void (*output_close)(struct stm_output *output);
+ ssize_t priv_sz;
+ struct configfs_attribute **policy_attr;
+};
+
+int stm_register_protocol(const struct stm_protocol_driver *pdrv);
+void stm_unregister_protocol(const struct stm_protocol_driver *pdrv);
+int stm_lookup_protocol(const char *name,
+ const struct stm_protocol_driver **pdrv,
+ const struct config_item_type **type);
+void stm_put_protocol(const struct stm_protocol_driver *pdrv);
+ssize_t stm_data_write(struct stm_data *data, unsigned int m,
+ unsigned int c, bool ts_first, const void *buf,
+ size_t count);
+
#endif /* _STM_STM_H_ */
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 451d4ae50e66..f2c681971201 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -224,6 +224,15 @@ config I2C_NFORCE2_S4985
This driver can also be built as a module. If so, the module
will be called i2c-nforce2-s4985.
+config I2C_NVIDIA_GPU
+ tristate "NVIDIA GPU I2C controller"
+ depends on PCI
+ help
+ If you say yes to this option, support will be included for the
+ NVIDIA GPU I2C controller which is used to communicate with the GPU's
+ Type-C controller. This driver can also be built as a module called
+ i2c-nvidia-gpu.
+
config I2C_SIS5595
tristate "SiS 5595"
depends on PCI
@@ -432,12 +441,13 @@ config I2C_BCM_KONA
If you do not need KONA I2C interface, say N.
config I2C_BRCMSTB
- tristate "BRCM Settop I2C controller"
- depends on ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST
+ tristate "BRCM Settop/DSL I2C controller"
+ depends on ARCH_BRCMSTB || BMIPS_GENERIC || ARCH_BCM_63XX || \
+ COMPILE_TEST
default y
help
If you say yes to this option, support will be included for the
- I2C interface on the Broadcom Settop SoCs.
+ I2C interface on the Broadcom Settop/DSL SoCs.
If you do not need I2C interface, say N.
@@ -751,7 +761,7 @@ config I2C_OCORES
config I2C_OMAP
tristate "OMAP I2C adapter"
- depends on ARCH_OMAP
+ depends on ARCH_OMAP || ARCH_K3
default y if MACH_OMAP_H3 || MACH_OMAP_OSK
help
If you say yes to this option, support will be included for the
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 18b26af82b1c..5f0cb6915969 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_I2C_ISCH) += i2c-isch.o
obj-$(CONFIG_I2C_ISMT) += i2c-ismt.o
obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o
obj-$(CONFIG_I2C_NFORCE2_S4985) += i2c-nforce2-s4985.o
+obj-$(CONFIG_I2C_NVIDIA_GPU) += i2c-nvidia-gpu.o
obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o
obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o
obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o
diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c
index a4f956c6d567..8dc9161ced38 100644
--- a/drivers/i2c/busses/i2c-aspeed.c
+++ b/drivers/i2c/busses/i2c-aspeed.c
@@ -82,6 +82,11 @@
#define ASPEED_I2CD_INTR_RX_DONE BIT(2)
#define ASPEED_I2CD_INTR_TX_NAK BIT(1)
#define ASPEED_I2CD_INTR_TX_ACK BIT(0)
+#define ASPEED_I2CD_INTR_MASTER_ERRORS \
+ (ASPEED_I2CD_INTR_SDA_DL_TIMEOUT | \
+ ASPEED_I2CD_INTR_SCL_TIMEOUT | \
+ ASPEED_I2CD_INTR_ABNORMAL | \
+ ASPEED_I2CD_INTR_ARBIT_LOSS)
#define ASPEED_I2CD_INTR_ALL \
(ASPEED_I2CD_INTR_SDA_DL_TIMEOUT | \
ASPEED_I2CD_INTR_BUS_RECOVER_DONE | \
@@ -137,7 +142,8 @@ struct aspeed_i2c_bus {
/* Synchronizes I/O mem access to base. */
spinlock_t lock;
struct completion cmd_complete;
- u32 (*get_clk_reg_val)(u32 divisor);
+ u32 (*get_clk_reg_val)(struct device *dev,
+ u32 divisor);
unsigned long parent_clk_frequency;
u32 bus_frequency;
/* Transaction state. */
@@ -227,32 +233,26 @@ reset_out:
}
#if IS_ENABLED(CONFIG_I2C_SLAVE)
-static bool aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus)
+static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
{
- u32 command, irq_status, status_ack = 0;
+ u32 command, irq_handled = 0;
struct i2c_client *slave = bus->slave;
- bool irq_handled = true;
u8 value;
- if (!slave) {
- irq_handled = false;
- goto out;
- }
+ if (!slave)
+ return 0;
command = readl(bus->base + ASPEED_I2C_CMD_REG);
- irq_status = readl(bus->base + ASPEED_I2C_INTR_STS_REG);
/* Slave was requested, restart state machine. */
if (irq_status & ASPEED_I2CD_INTR_SLAVE_MATCH) {
- status_ack |= ASPEED_I2CD_INTR_SLAVE_MATCH;
+ irq_handled |= ASPEED_I2CD_INTR_SLAVE_MATCH;
bus->slave_state = ASPEED_I2C_SLAVE_START;
}
/* Slave is not currently active, irq was for someone else. */
- if (bus->slave_state == ASPEED_I2C_SLAVE_STOP) {
- irq_handled = false;
- goto out;
- }
+ if (bus->slave_state == ASPEED_I2C_SLAVE_STOP)
+ return irq_handled;
dev_dbg(bus->dev, "slave irq status 0x%08x, cmd 0x%08x\n",
irq_status, command);
@@ -269,31 +269,31 @@ static bool aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus)
bus->slave_state =
ASPEED_I2C_SLAVE_WRITE_REQUESTED;
}
- status_ack |= ASPEED_I2CD_INTR_RX_DONE;
+ irq_handled |= ASPEED_I2CD_INTR_RX_DONE;
}
/* Slave was asked to stop. */
if (irq_status & ASPEED_I2CD_INTR_NORMAL_STOP) {
- status_ack |= ASPEED_I2CD_INTR_NORMAL_STOP;
+ irq_handled |= ASPEED_I2CD_INTR_NORMAL_STOP;
bus->slave_state = ASPEED_I2C_SLAVE_STOP;
}
if (irq_status & ASPEED_I2CD_INTR_TX_NAK) {
- status_ack |= ASPEED_I2CD_INTR_TX_NAK;
+ irq_handled |= ASPEED_I2CD_INTR_TX_NAK;
bus->slave_state = ASPEED_I2C_SLAVE_STOP;
}
+ if (irq_status & ASPEED_I2CD_INTR_TX_ACK)
+ irq_handled |= ASPEED_I2CD_INTR_TX_ACK;
switch (bus->slave_state) {
case ASPEED_I2C_SLAVE_READ_REQUESTED:
if (irq_status & ASPEED_I2CD_INTR_TX_ACK)
dev_err(bus->dev, "Unexpected ACK on read request.\n");
bus->slave_state = ASPEED_I2C_SLAVE_READ_PROCESSED;
-
i2c_slave_event(slave, I2C_SLAVE_READ_REQUESTED, &value);
writel(value, bus->base + ASPEED_I2C_BYTE_BUF_REG);
writel(ASPEED_I2CD_S_TX_CMD, bus->base + ASPEED_I2C_CMD_REG);
break;
case ASPEED_I2C_SLAVE_READ_PROCESSED:
- status_ack |= ASPEED_I2CD_INTR_TX_ACK;
if (!(irq_status & ASPEED_I2CD_INTR_TX_ACK))
dev_err(bus->dev,
"Expected ACK after processed read.\n");
@@ -317,13 +317,6 @@ static bool aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus)
break;
}
- if (status_ack != irq_status)
- dev_err(bus->dev,
- "irq handled != irq. expected %x, but was %x\n",
- irq_status, status_ack);
- writel(status_ack, bus->base + ASPEED_I2C_INTR_STS_REG);
-
-out:
return irq_handled;
}
#endif /* CONFIG_I2C_SLAVE */
@@ -380,21 +373,21 @@ static int aspeed_i2c_is_irq_error(u32 irq_status)
return 0;
}
-static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
+static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
{
- u32 irq_status, status_ack = 0, command = 0;
+ u32 irq_handled = 0, command = 0;
struct i2c_msg *msg;
u8 recv_byte;
int ret;
- irq_status = readl(bus->base + ASPEED_I2C_INTR_STS_REG);
- /* Ack all interrupt bits. */
- writel(irq_status, bus->base + ASPEED_I2C_INTR_STS_REG);
-
if (irq_status & ASPEED_I2CD_INTR_BUS_RECOVER_DONE) {
bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
- status_ack |= ASPEED_I2CD_INTR_BUS_RECOVER_DONE;
+ irq_handled |= ASPEED_I2CD_INTR_BUS_RECOVER_DONE;
goto out_complete;
+ } else {
+ /* Master is not currently active, irq was for someone else. */
+ if (bus->master_state == ASPEED_I2C_MASTER_INACTIVE)
+ goto out_no_complete;
}
/*
@@ -403,19 +396,22 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
* INACTIVE state.
*/
ret = aspeed_i2c_is_irq_error(irq_status);
- if (ret < 0) {
+ if (ret) {
dev_dbg(bus->dev, "received error interrupt: 0x%08x\n",
irq_status);
bus->cmd_err = ret;
bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
+ irq_handled |= (irq_status & ASPEED_I2CD_INTR_MASTER_ERRORS);
goto out_complete;
}
/* We are in an invalid state; reset bus to a known state. */
if (!bus->msgs) {
- dev_err(bus->dev, "bus in unknown state\n");
+ dev_err(bus->dev, "bus in unknown state. irq_status: 0x%x\n",
+ irq_status);
bus->cmd_err = -EIO;
- if (bus->master_state != ASPEED_I2C_MASTER_STOP)
+ if (bus->master_state != ASPEED_I2C_MASTER_STOP &&
+ bus->master_state != ASPEED_I2C_MASTER_INACTIVE)
aspeed_i2c_do_stop(bus);
goto out_no_complete;
}
@@ -428,13 +424,18 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
*/
if (bus->master_state == ASPEED_I2C_MASTER_START) {
if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) {
+ if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_NAK))) {
+ bus->cmd_err = -ENXIO;
+ bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
+ goto out_complete;
+ }
pr_devel("no slave present at %02x\n", msg->addr);
- status_ack |= ASPEED_I2CD_INTR_TX_NAK;
+ irq_handled |= ASPEED_I2CD_INTR_TX_NAK;
bus->cmd_err = -ENXIO;
aspeed_i2c_do_stop(bus);
goto out_no_complete;
}
- status_ack |= ASPEED_I2CD_INTR_TX_ACK;
+ irq_handled |= ASPEED_I2CD_INTR_TX_ACK;
if (msg->len == 0) { /* SMBUS_QUICK */
aspeed_i2c_do_stop(bus);
goto out_no_complete;
@@ -449,14 +450,14 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
case ASPEED_I2C_MASTER_TX:
if (unlikely(irq_status & ASPEED_I2CD_INTR_TX_NAK)) {
dev_dbg(bus->dev, "slave NACKed TX\n");
- status_ack |= ASPEED_I2CD_INTR_TX_NAK;
+ irq_handled |= ASPEED_I2CD_INTR_TX_NAK;
goto error_and_stop;
} else if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) {
dev_err(bus->dev, "slave failed to ACK TX\n");
goto error_and_stop;
}
- status_ack |= ASPEED_I2CD_INTR_TX_ACK;
- /* fallthrough intended */
+ irq_handled |= ASPEED_I2CD_INTR_TX_ACK;
+ /* fall through */
case ASPEED_I2C_MASTER_TX_FIRST:
if (bus->buf_index < msg->len) {
bus->master_state = ASPEED_I2C_MASTER_TX;
@@ -472,13 +473,13 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
/* RX may not have completed yet (only address cycle) */
if (!(irq_status & ASPEED_I2CD_INTR_RX_DONE))
goto out_no_complete;
- /* fallthrough intended */
+ /* fall through */
case ASPEED_I2C_MASTER_RX:
if (unlikely(!(irq_status & ASPEED_I2CD_INTR_RX_DONE))) {
dev_err(bus->dev, "master failed to RX\n");
goto error_and_stop;
}
- status_ack |= ASPEED_I2CD_INTR_RX_DONE;
+ irq_handled |= ASPEED_I2CD_INTR_RX_DONE;
recv_byte = readl(bus->base + ASPEED_I2C_BYTE_BUF_REG) >> 8;
msg->buf[bus->buf_index++] = recv_byte;
@@ -506,11 +507,13 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
goto out_no_complete;
case ASPEED_I2C_MASTER_STOP:
if (unlikely(!(irq_status & ASPEED_I2CD_INTR_NORMAL_STOP))) {
- dev_err(bus->dev, "master failed to STOP\n");
+ dev_err(bus->dev,
+ "master failed to STOP. irq_status:0x%x\n",
+ irq_status);
bus->cmd_err = -EIO;
/* Do not STOP as we have already tried. */
} else {
- status_ack |= ASPEED_I2CD_INTR_NORMAL_STOP;
+ irq_handled |= ASPEED_I2CD_INTR_NORMAL_STOP;
}
bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
@@ -540,33 +543,57 @@ out_complete:
bus->master_xfer_result = bus->msgs_index + 1;
complete(&bus->cmd_complete);
out_no_complete:
- if (irq_status != status_ack)
- dev_err(bus->dev,
- "irq handled != irq. expected 0x%08x, but was 0x%08x\n",
- irq_status, status_ack);
- return !!irq_status;
+ return irq_handled;
}
static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id)
{
struct aspeed_i2c_bus *bus = dev_id;
- bool ret;
+ u32 irq_received, irq_remaining, irq_handled;
spin_lock(&bus->lock);
+ irq_received = readl(bus->base + ASPEED_I2C_INTR_STS_REG);
+ /* Ack all interrupts except for Rx done */
+ writel(irq_received & ~ASPEED_I2CD_INTR_RX_DONE,
+ bus->base + ASPEED_I2C_INTR_STS_REG);
+ irq_remaining = irq_received;
#if IS_ENABLED(CONFIG_I2C_SLAVE)
- if (aspeed_i2c_slave_irq(bus)) {
- dev_dbg(bus->dev, "irq handled by slave.\n");
- ret = true;
- goto out;
+ /*
+ * In most cases, interrupt bits will be set one by one, although
+ * multiple interrupt bits could be set at the same time. It's also
+ * possible that master interrupt bits could be set along with slave
+ * interrupt bits. Each case needs to be handled using corresponding
+ * handlers depending on the current state.
+ */
+ if (bus->master_state != ASPEED_I2C_MASTER_INACTIVE) {
+ irq_handled = aspeed_i2c_master_irq(bus, irq_remaining);
+ irq_remaining &= ~irq_handled;
+ if (irq_remaining)
+ irq_handled |= aspeed_i2c_slave_irq(bus, irq_remaining);
+ } else {
+ irq_handled = aspeed_i2c_slave_irq(bus, irq_remaining);
+ irq_remaining &= ~irq_handled;
+ if (irq_remaining)
+ irq_handled |= aspeed_i2c_master_irq(bus,
+ irq_remaining);
}
+#else
+ irq_handled = aspeed_i2c_master_irq(bus, irq_remaining);
#endif /* CONFIG_I2C_SLAVE */
- ret = aspeed_i2c_master_irq(bus);
+ irq_remaining &= ~irq_handled;
+ if (irq_remaining)
+ dev_err(bus->dev,
+ "irq handled != irq. expected 0x%08x, but was 0x%08x\n",
+ irq_received, irq_handled);
-out:
+ /* Ack Rx done */
+ if (irq_received & ASPEED_I2CD_INTR_RX_DONE)
+ writel(ASPEED_I2CD_INTR_RX_DONE,
+ bus->base + ASPEED_I2C_INTR_STS_REG);
spin_unlock(&bus->lock);
- return ret ? IRQ_HANDLED : IRQ_NONE;
+ return irq_remaining ? IRQ_NONE : IRQ_HANDLED;
}
static int aspeed_i2c_master_xfer(struct i2c_adapter *adap,
@@ -684,16 +711,27 @@ static const struct i2c_algorithm aspeed_i2c_algo = {
#endif /* CONFIG_I2C_SLAVE */
};
-static u32 aspeed_i2c_get_clk_reg_val(u32 clk_high_low_max, u32 divisor)
+static u32 aspeed_i2c_get_clk_reg_val(struct device *dev,
+ u32 clk_high_low_mask,
+ u32 divisor)
{
- u32 base_clk, clk_high, clk_low, tmp;
+ u32 base_clk_divisor, clk_high_low_max, clk_high, clk_low, tmp;
+
+ /*
+ * SCL_high and SCL_low represent a value 1 greater than what is stored
+ * since a zero divider is meaningless. Thus, the max value each can
+ * store is every bit set + 1. Since SCL_high and SCL_low are added
+ * together (see below), the max value of both is the max value of one
+ * them times two.
+ */
+ clk_high_low_max = (clk_high_low_mask + 1) * 2;
/*
* The actual clock frequency of SCL is:
* SCL_freq = APB_freq / (base_freq * (SCL_high + SCL_low))
* = APB_freq / divisor
* where base_freq is a programmable clock divider; its value is
- * base_freq = 1 << base_clk
+ * base_freq = 1 << base_clk_divisor
* SCL_high is the number of base_freq clock cycles that SCL stays high
* and SCL_low is the number of base_freq clock cycles that SCL stays
* low for a period of SCL.
@@ -703,47 +741,59 @@ static u32 aspeed_i2c_get_clk_reg_val(u32 clk_high_low_max, u32 divisor)
* SCL_low = clk_low + 1
* Thus,
* SCL_freq = APB_freq /
- * ((1 << base_clk) * (clk_high + 1 + clk_low + 1))
+ * ((1 << base_clk_divisor) * (clk_high + 1 + clk_low + 1))
* The documentation recommends clk_high >= clk_high_max / 2 and
* clk_low >= clk_low_max / 2 - 1 when possible; this last constraint
* gives us the following solution:
*/
- base_clk = divisor > clk_high_low_max ?
+ base_clk_divisor = divisor > clk_high_low_max ?
ilog2((divisor - 1) / clk_high_low_max) + 1 : 0;
- tmp = (divisor + (1 << base_clk) - 1) >> base_clk;
- clk_low = tmp / 2;
- clk_high = tmp - clk_low;
- if (clk_high)
- clk_high--;
+ if (base_clk_divisor > ASPEED_I2CD_TIME_BASE_DIVISOR_MASK) {
+ base_clk_divisor = ASPEED_I2CD_TIME_BASE_DIVISOR_MASK;
+ clk_low = clk_high_low_mask;
+ clk_high = clk_high_low_mask;
+ dev_err(dev,
+ "clamping clock divider: divider requested, %u, is greater than largest possible divider, %u.\n",
+ divisor, (1 << base_clk_divisor) * clk_high_low_max);
+ } else {
+ tmp = (divisor + (1 << base_clk_divisor) - 1)
+ >> base_clk_divisor;
+ clk_low = tmp / 2;
+ clk_high = tmp - clk_low;
+
+ if (clk_high)
+ clk_high--;
- if (clk_low)
- clk_low--;
+ if (clk_low)
+ clk_low--;
+ }
return ((clk_high << ASPEED_I2CD_TIME_SCL_HIGH_SHIFT)
& ASPEED_I2CD_TIME_SCL_HIGH_MASK)
| ((clk_low << ASPEED_I2CD_TIME_SCL_LOW_SHIFT)
& ASPEED_I2CD_TIME_SCL_LOW_MASK)
- | (base_clk & ASPEED_I2CD_TIME_BASE_DIVISOR_MASK);
+ | (base_clk_divisor
+ & ASPEED_I2CD_TIME_BASE_DIVISOR_MASK);
}
-static u32 aspeed_i2c_24xx_get_clk_reg_val(u32 divisor)
+static u32 aspeed_i2c_24xx_get_clk_reg_val(struct device *dev, u32 divisor)
{
/*
* clk_high and clk_low are each 3 bits wide, so each can hold a max
* value of 8 giving a clk_high_low_max of 16.
*/
- return aspeed_i2c_get_clk_reg_val(16, divisor);
+ return aspeed_i2c_get_clk_reg_val(dev, GENMASK(2, 0), divisor);
}
-static u32 aspeed_i2c_25xx_get_clk_reg_val(u32 divisor)
+static u32 aspeed_i2c_25xx_get_clk_reg_val(struct device *dev, u32 divisor)
{
/*
* clk_high and clk_low are each 4 bits wide, so each can hold a max
* value of 16 giving a clk_high_low_max of 32.
*/
- return aspeed_i2c_get_clk_reg_val(32, divisor);
+ return aspeed_i2c_get_clk_reg_val(dev, GENMASK(3, 0), divisor);
}
/* precondition: bus.lock has been acquired. */
@@ -756,7 +806,7 @@ static int aspeed_i2c_init_clk(struct aspeed_i2c_bus *bus)
clk_reg_val &= (ASPEED_I2CD_TIME_TBUF_MASK |
ASPEED_I2CD_TIME_THDSTA_MASK |
ASPEED_I2CD_TIME_TACST_MASK);
- clk_reg_val |= bus->get_clk_reg_val(divisor);
+ clk_reg_val |= bus->get_clk_reg_val(bus->dev, divisor);
writel(clk_reg_val, bus->base + ASPEED_I2C_AC_TIMING_REG1);
writel(ASPEED_NO_TIMEOUT_CTRL, bus->base + ASPEED_I2C_AC_TIMING_REG2);
@@ -872,7 +922,8 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev)
if (!match)
bus->get_clk_reg_val = aspeed_i2c_24xx_get_clk_reg_val;
else
- bus->get_clk_reg_val = (u32 (*)(u32))match->data;
+ bus->get_clk_reg_val = (u32 (*)(struct device *, u32))
+ match->data;
/* Initialize the I2C adapter */
spin_lock_init(&bus->lock);
diff --git a/drivers/i2c/busses/i2c-designware-baytrail.c b/drivers/i2c/busses/i2c-designware-baytrail.c
index a2a275cfc1f6..33da07d64494 100644
--- a/drivers/i2c/busses/i2c-designware-baytrail.c
+++ b/drivers/i2c/busses/i2c-designware-baytrail.c
@@ -3,141 +3,15 @@
* Intel BayTrail PMIC I2C bus semaphore implementaion
* Copyright (c) 2014, Intel Corporation.
*/
-#include <linux/delay.h>
#include <linux/device.h>
#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
-#include <linux/pm_qos.h>
#include <asm/iosf_mbi.h>
#include "i2c-designware-core.h"
-#define SEMAPHORE_TIMEOUT 500
-#define PUNIT_SEMAPHORE 0x7
-#define PUNIT_SEMAPHORE_CHT 0x10e
-#define PUNIT_SEMAPHORE_BIT BIT(0)
-#define PUNIT_SEMAPHORE_ACQUIRE BIT(1)
-
-static unsigned long acquired;
-
-static u32 get_sem_addr(struct dw_i2c_dev *dev)
-{
- if (dev->flags & MODEL_CHERRYTRAIL)
- return PUNIT_SEMAPHORE_CHT;
- else
- return PUNIT_SEMAPHORE;
-}
-
-static int get_sem(struct dw_i2c_dev *dev, u32 *sem)
-{
- u32 addr = get_sem_addr(dev);
- u32 data;
- int ret;
-
- ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, addr, &data);
- if (ret) {
- dev_err(dev->dev, "iosf failed to read punit semaphore\n");
- return ret;
- }
-
- *sem = data & PUNIT_SEMAPHORE_BIT;
-
- return 0;
-}
-
-static void reset_semaphore(struct dw_i2c_dev *dev)
-{
- if (iosf_mbi_modify(BT_MBI_UNIT_PMC, MBI_REG_READ, get_sem_addr(dev),
- 0, PUNIT_SEMAPHORE_BIT))
- dev_err(dev->dev, "iosf failed to reset punit semaphore during write\n");
-
- pm_qos_update_request(&dev->pm_qos, PM_QOS_DEFAULT_VALUE);
-
- iosf_mbi_call_pmic_bus_access_notifier_chain(MBI_PMIC_BUS_ACCESS_END,
- NULL);
- iosf_mbi_punit_release();
-}
-
-static int baytrail_i2c_acquire(struct dw_i2c_dev *dev)
-{
- u32 addr;
- u32 sem = PUNIT_SEMAPHORE_ACQUIRE;
- int ret;
- unsigned long start, end;
-
- might_sleep();
-
- if (!dev || !dev->dev)
- return -ENODEV;
-
- if (!dev->release_lock)
- return 0;
-
- iosf_mbi_punit_acquire();
- iosf_mbi_call_pmic_bus_access_notifier_chain(MBI_PMIC_BUS_ACCESS_BEGIN,
- NULL);
-
- /*
- * Disallow the CPU to enter C6 or C7 state, entering these states
- * requires the punit to talk to the pmic and if this happens while
- * we're holding the semaphore, the SoC hangs.
- */
- pm_qos_update_request(&dev->pm_qos, 0);
-
- addr = get_sem_addr(dev);
-
- /* host driver writes to side band semaphore register */
- ret = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, addr, sem);
- if (ret) {
- dev_err(dev->dev, "iosf punit semaphore request failed\n");
- goto out;
- }
-
- /* host driver waits for bit 0 to be set in semaphore register */
- start = jiffies;
- end = start + msecs_to_jiffies(SEMAPHORE_TIMEOUT);
- do {
- ret = get_sem(dev, &sem);
- if (!ret && sem) {
- acquired = jiffies;
- dev_dbg(dev->dev, "punit semaphore acquired after %ums\n",
- jiffies_to_msecs(jiffies - start));
- return 0;
- }
-
- usleep_range(1000, 2000);
- } while (time_before(jiffies, end));
-
- dev_err(dev->dev, "punit semaphore timed out, resetting\n");
-out:
- reset_semaphore(dev);
-
- ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, addr, &sem);
- if (ret)
- dev_err(dev->dev, "iosf failed to read punit semaphore\n");
- else
- dev_err(dev->dev, "PUNIT SEM: %d\n", sem);
-
- WARN_ON(1);
-
- return -ETIMEDOUT;
-}
-
-static void baytrail_i2c_release(struct dw_i2c_dev *dev)
-{
- if (!dev || !dev->dev)
- return;
-
- if (!dev->acquire_lock)
- return;
-
- reset_semaphore(dev);
- dev_dbg(dev->dev, "punit semaphore held for %ums\n",
- jiffies_to_msecs(jiffies - acquired));
-}
-
int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev)
{
acpi_status status;
@@ -162,18 +36,9 @@ int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev)
return -EPROBE_DEFER;
dev_info(dev->dev, "I2C bus managed by PUNIT\n");
- dev->acquire_lock = baytrail_i2c_acquire;
- dev->release_lock = baytrail_i2c_release;
- dev->pm_disabled = true;
-
- pm_qos_add_request(&dev->pm_qos, PM_QOS_CPU_DMA_LATENCY,
- PM_QOS_DEFAULT_VALUE);
+ dev->acquire_lock = iosf_mbi_block_punit_i2c_access;
+ dev->release_lock = iosf_mbi_unblock_punit_i2c_access;
+ dev->shared_with_punit = true;
return 0;
}
-
-void i2c_dw_remove_lock_support(struct dw_i2c_dev *dev)
-{
- if (dev->acquire_lock)
- pm_qos_remove_request(&dev->pm_qos);
-}
diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c
index 69ec4a791f23..a4730111d290 100644
--- a/drivers/i2c/busses/i2c-designware-common.c
+++ b/drivers/i2c/busses/i2c-designware-common.c
@@ -201,6 +201,8 @@ int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev)
dev_dbg(dev->dev, "SDA Hold Time TX:RX = %d:%d\n",
dev->sda_hold_time & ~(u32)DW_IC_SDA_HOLD_RX_MASK,
dev->sda_hold_time >> DW_IC_SDA_HOLD_RX_SHIFT);
+ } else if (dev->set_sda_hold_time) {
+ dev->set_sda_hold_time(dev);
} else if (dev->sda_hold_time) {
dev_warn(dev->dev,
"Hardware too old to adjust SDA hold time.\n");
@@ -267,7 +269,7 @@ int i2c_dw_acquire_lock(struct dw_i2c_dev *dev)
if (!dev->acquire_lock)
return 0;
- ret = dev->acquire_lock(dev);
+ ret = dev->acquire_lock();
if (!ret)
return 0;
@@ -279,7 +281,7 @@ int i2c_dw_acquire_lock(struct dw_i2c_dev *dev)
void i2c_dw_release_lock(struct dw_i2c_dev *dev)
{
if (dev->release_lock)
- dev->release_lock(dev);
+ dev->release_lock();
}
/*
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index e367b1af4ab2..b4a0b2b99a78 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -10,7 +10,6 @@
*/
#include <linux/i2c.h>
-#include <linux/pm_qos.h>
#define DW_IC_DEFAULT_FUNCTIONALITY (I2C_FUNC_I2C | \
I2C_FUNC_SMBUS_BYTE | \
@@ -209,10 +208,9 @@
* @fp_lcnt: fast plus LCNT value
* @hs_hcnt: high speed HCNT value
* @hs_lcnt: high speed LCNT value
- * @pm_qos: pm_qos_request used while holding a hardware lock on the bus
* @acquire_lock: function to acquire a hardware lock on the bus
* @release_lock: function to release a hardware lock on the bus
- * @pm_disabled: true if power-management should be disabled for this i2c-bus
+ * @shared_with_punit: true if this bus is shared with the SoCs PUNIT
* @disable: function to disable the controller
* @disable_int: function to disable all interrupts
* @init: function to initialize the I2C hardware
@@ -225,6 +223,7 @@
struct dw_i2c_dev {
struct device *dev;
void __iomem *base;
+ void __iomem *ext;
struct completion cmd_complete;
struct clk *clk;
struct reset_control *rst;
@@ -262,13 +261,13 @@ struct dw_i2c_dev {
u16 fp_lcnt;
u16 hs_hcnt;
u16 hs_lcnt;
- struct pm_qos_request pm_qos;
- int (*acquire_lock)(struct dw_i2c_dev *dev);
- void (*release_lock)(struct dw_i2c_dev *dev);
- bool pm_disabled;
+ int (*acquire_lock)(void);
+ void (*release_lock)(void);
+ bool shared_with_punit;
void (*disable)(struct dw_i2c_dev *dev);
void (*disable_int)(struct dw_i2c_dev *dev);
int (*init)(struct dw_i2c_dev *dev);
+ int (*set_sda_hold_time)(struct dw_i2c_dev *dev);
int mode;
struct i2c_bus_recovery_info rinfo;
};
@@ -276,8 +275,11 @@ struct dw_i2c_dev {
#define ACCESS_SWAP 0x00000001
#define ACCESS_16BIT 0x00000002
#define ACCESS_INTR_MASK 0x00000004
+#define ACCESS_NO_IRQ_SUSPEND 0x00000008
#define MODEL_CHERRYTRAIL 0x00000100
+#define MODEL_MSCC_OCELOT 0x00000200
+#define MODEL_MASK 0x00000f00
u32 dw_readl(struct dw_i2c_dev *dev, int offset);
void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset);
@@ -317,8 +319,6 @@ static inline int i2c_dw_probe_slave(struct dw_i2c_dev *dev) { return -EINVAL; }
#if IS_ENABLED(CONFIG_I2C_DESIGNWARE_BAYTRAIL)
extern int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev);
-extern void i2c_dw_remove_lock_support(struct dw_i2c_dev *dev);
#else
static inline int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev) { return 0; }
-static inline void i2c_dw_remove_lock_support(struct dw_i2c_dev *dev) {}
#endif
diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c
index 94d94b4a9a0d..8d1bc44d2530 100644
--- a/drivers/i2c/busses/i2c-designware-master.c
+++ b/drivers/i2c/busses/i2c-designware-master.c
@@ -34,11 +34,11 @@ static void i2c_dw_configure_fifo_master(struct dw_i2c_dev *dev)
static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
{
- u32 ic_clk = i2c_dw_clk_rate(dev);
const char *mode_str, *fp_str = "";
u32 comp_param1;
u32 sda_falling_time, scl_falling_time;
struct i2c_timings *t = &dev->timings;
+ u32 ic_clk;
int ret;
ret = i2c_dw_acquire_lock(dev);
@@ -53,6 +53,7 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
/* Calculate SCL timing parameters for standard mode if not set */
if (!dev->ss_hcnt || !dev->ss_lcnt) {
+ ic_clk = i2c_dw_clk_rate(dev);
dev->ss_hcnt =
i2c_dw_scl_hcnt(ic_clk,
4000, /* tHD;STA = tHIGH = 4.0 us */
@@ -89,6 +90,7 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
* needed also in high speed mode.
*/
if (!dev->fs_hcnt || !dev->fs_lcnt) {
+ ic_clk = i2c_dw_clk_rate(dev);
dev->fs_hcnt =
i2c_dw_scl_hcnt(ic_clk,
600, /* tHD;STA = tHIGH = 0.6 us */
@@ -707,7 +709,7 @@ int i2c_dw_probe(struct dw_i2c_dev *dev)
adap->dev.parent = dev->dev;
i2c_set_adapdata(adap, dev);
- if (dev->pm_disabled) {
+ if (dev->flags & ACCESS_NO_IRQ_SUSPEND) {
irq_flags = IRQF_NO_SUSPEND;
} else {
irq_flags = IRQF_SHARED | IRQF_COND_SUSPEND;
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index b5750fd85125..9eaac3be1f63 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -85,10 +85,6 @@ static int dw_i2c_acpi_configure(struct platform_device *pdev)
struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
struct i2c_timings *t = &dev->timings;
u32 ss_ht = 0, fp_ht = 0, hs_ht = 0, fs_ht = 0;
- acpi_handle handle = ACPI_HANDLE(&pdev->dev);
- const struct acpi_device_id *id;
- struct acpi_device *adev;
- const char *uid;
dev->adapter.nr = -1;
dev->tx_fifo_depth = 32;
@@ -119,22 +115,6 @@ static int dw_i2c_acpi_configure(struct platform_device *pdev)
break;
}
- id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev);
- if (id && id->driver_data)
- dev->flags |= (u32)id->driver_data;
-
- if (acpi_bus_get_device(handle, &adev))
- return -ENODEV;
-
- /*
- * Cherrytrail I2C7 gets used for the PMIC which gets accessed
- * through ACPI opregions during late suspend / early resume
- * disable pm for it.
- */
- uid = adev->pnp.unique_id;
- if ((dev->flags & MODEL_CHERRYTRAIL) && !strcmp(uid, "7"))
- dev->pm_disabled = true;
-
return 0;
}
@@ -143,8 +123,8 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = {
{ "INT33C3", 0 },
{ "INT3432", 0 },
{ "INT3433", 0 },
- { "80860F41", 0 },
- { "808622C1", MODEL_CHERRYTRAIL },
+ { "80860F41", ACCESS_NO_IRQ_SUSPEND },
+ { "808622C1", ACCESS_NO_IRQ_SUSPEND | MODEL_CHERRYTRAIL },
{ "AMD0010", ACCESS_INTR_MASK },
{ "AMDI0010", ACCESS_INTR_MASK },
{ "AMDI0510", 0 },
@@ -161,6 +141,51 @@ static inline int dw_i2c_acpi_configure(struct platform_device *pdev)
}
#endif
+#ifdef CONFIG_OF
+#define MSCC_ICPU_CFG_TWI_DELAY 0x0
+#define MSCC_ICPU_CFG_TWI_DELAY_ENABLE BIT(0)
+#define MSCC_ICPU_CFG_TWI_SPIKE_FILTER 0x4
+
+static int mscc_twi_set_sda_hold_time(struct dw_i2c_dev *dev)
+{
+ writel((dev->sda_hold_time << 1) | MSCC_ICPU_CFG_TWI_DELAY_ENABLE,
+ dev->ext + MSCC_ICPU_CFG_TWI_DELAY);
+
+ return 0;
+}
+
+static int dw_i2c_of_configure(struct platform_device *pdev)
+{
+ struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
+ struct resource *mem;
+
+ switch (dev->flags & MODEL_MASK) {
+ case MODEL_MSCC_OCELOT:
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ dev->ext = devm_ioremap_resource(&pdev->dev, mem);
+ if (!IS_ERR(dev->ext))
+ dev->set_sda_hold_time = mscc_twi_set_sda_hold_time;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id dw_i2c_of_match[] = {
+ { .compatible = "snps,designware-i2c", },
+ { .compatible = "mscc,ocelot-i2c", .data = (void *)MODEL_MSCC_OCELOT },
+ {},
+};
+MODULE_DEVICE_TABLE(of, dw_i2c_of_match);
+#else
+static inline int dw_i2c_of_configure(struct platform_device *pdev)
+{
+ return -ENODEV;
+}
+#endif
+
static void i2c_dw_configure_master(struct dw_i2c_dev *dev)
{
struct i2c_timings *t = &dev->timings;
@@ -221,7 +246,7 @@ static void dw_i2c_plat_pm_cleanup(struct dw_i2c_dev *dev)
{
pm_runtime_disable(dev->dev);
- if (dev->pm_disabled)
+ if (dev->shared_with_punit)
pm_runtime_put_noidle(dev->dev);
}
@@ -291,6 +316,11 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
else
t->bus_freq_hz = 400000;
+ dev->flags |= (uintptr_t)device_get_match_data(&pdev->dev);
+
+ if (pdev->dev.of_node)
+ dw_i2c_of_configure(pdev);
+
if (has_acpi_companion(&pdev->dev))
dw_i2c_acpi_configure(pdev);
@@ -348,7 +378,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_active(&pdev->dev);
- if (dev->pm_disabled)
+ if (dev->shared_with_punit)
pm_runtime_get_noresume(&pdev->dev);
pm_runtime_enable(&pdev->dev);
@@ -388,19 +418,9 @@ static int dw_i2c_plat_remove(struct platform_device *pdev)
if (!IS_ERR_OR_NULL(dev->rst))
reset_control_assert(dev->rst);
- i2c_dw_remove_lock_support(dev);
-
return 0;
}
-#ifdef CONFIG_OF
-static const struct of_device_id dw_i2c_of_match[] = {
- { .compatible = "snps,designware-i2c", },
- {},
-};
-MODULE_DEVICE_TABLE(of, dw_i2c_of_match);
-#endif
-
#ifdef CONFIG_PM_SLEEP
static int dw_i2c_plat_prepare(struct device *dev)
{
@@ -434,7 +454,7 @@ static int dw_i2c_plat_suspend(struct device *dev)
{
struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
- if (i_dev->pm_disabled)
+ if (i_dev->shared_with_punit)
return 0;
i_dev->disable(i_dev);
@@ -447,7 +467,7 @@ static int dw_i2c_plat_resume(struct device *dev)
{
struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
- if (!i_dev->pm_disabled)
+ if (!i_dev->shared_with_punit)
i2c_dw_prepare_clk(i_dev, true);
i_dev->init(i_dev);
diff --git a/drivers/i2c/busses/i2c-isch.c b/drivers/i2c/busses/i2c-isch.c
index 0cf1379f4e80..5c754bf659e2 100644
--- a/drivers/i2c/busses/i2c-isch.c
+++ b/drivers/i2c/busses/i2c-isch.c
@@ -164,7 +164,7 @@ static s32 sch_access(struct i2c_adapter *adap, u16 addr,
* run ~75 kHz instead which should do no harm.
*/
dev_notice(&sch_adapter.dev,
- "Clock divider unitialized. Setting defaults\n");
+ "Clock divider uninitialized. Setting defaults\n");
outw(backbone_speed / (4 * 100), SMBHSTCLK);
}
diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
index 1e57f58fcb00..a74ef76705e0 100644
--- a/drivers/i2c/busses/i2c-mt65xx.c
+++ b/drivers/i2c/busses/i2c-mt65xx.c
@@ -441,6 +441,8 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
u16 control_reg;
u16 restart_flag = 0;
u32 reg_4g_mode;
+ u8 *dma_rd_buf = NULL;
+ u8 *dma_wr_buf = NULL;
dma_addr_t rpaddr = 0;
dma_addr_t wpaddr = 0;
int ret;
@@ -500,10 +502,18 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
if (i2c->op == I2C_MASTER_RD) {
writel(I2C_DMA_INT_FLAG_NONE, i2c->pdmabase + OFFSET_INT_FLAG);
writel(I2C_DMA_CON_RX, i2c->pdmabase + OFFSET_CON);
- rpaddr = dma_map_single(i2c->dev, msgs->buf,
+
+ dma_rd_buf = i2c_get_dma_safe_msg_buf(msgs, 0);
+ if (!dma_rd_buf)
+ return -ENOMEM;
+
+ rpaddr = dma_map_single(i2c->dev, dma_rd_buf,
msgs->len, DMA_FROM_DEVICE);
- if (dma_mapping_error(i2c->dev, rpaddr))
+ if (dma_mapping_error(i2c->dev, rpaddr)) {
+ i2c_put_dma_safe_msg_buf(dma_rd_buf, msgs, false);
+
return -ENOMEM;
+ }
if (i2c->dev_comp->support_33bits) {
reg_4g_mode = mtk_i2c_set_4g_mode(rpaddr);
@@ -515,10 +525,18 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
} else if (i2c->op == I2C_MASTER_WR) {
writel(I2C_DMA_INT_FLAG_NONE, i2c->pdmabase + OFFSET_INT_FLAG);
writel(I2C_DMA_CON_TX, i2c->pdmabase + OFFSET_CON);
- wpaddr = dma_map_single(i2c->dev, msgs->buf,
+
+ dma_wr_buf = i2c_get_dma_safe_msg_buf(msgs, 0);
+ if (!dma_wr_buf)
+ return -ENOMEM;
+
+ wpaddr = dma_map_single(i2c->dev, dma_wr_buf,
msgs->len, DMA_TO_DEVICE);
- if (dma_mapping_error(i2c->dev, wpaddr))
+ if (dma_mapping_error(i2c->dev, wpaddr)) {
+ i2c_put_dma_safe_msg_buf(dma_wr_buf, msgs, false);
+
return -ENOMEM;
+ }
if (i2c->dev_comp->support_33bits) {
reg_4g_mode = mtk_i2c_set_4g_mode(wpaddr);
@@ -530,16 +548,39 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
} else {
writel(I2C_DMA_CLR_FLAG, i2c->pdmabase + OFFSET_INT_FLAG);
writel(I2C_DMA_CLR_FLAG, i2c->pdmabase + OFFSET_CON);
- wpaddr = dma_map_single(i2c->dev, msgs->buf,
+
+ dma_wr_buf = i2c_get_dma_safe_msg_buf(msgs, 0);
+ if (!dma_wr_buf)
+ return -ENOMEM;
+
+ wpaddr = dma_map_single(i2c->dev, dma_wr_buf,
msgs->len, DMA_TO_DEVICE);
- if (dma_mapping_error(i2c->dev, wpaddr))
+ if (dma_mapping_error(i2c->dev, wpaddr)) {
+ i2c_put_dma_safe_msg_buf(dma_wr_buf, msgs, false);
+
return -ENOMEM;
- rpaddr = dma_map_single(i2c->dev, (msgs + 1)->buf,
+ }
+
+ dma_rd_buf = i2c_get_dma_safe_msg_buf((msgs + 1), 0);
+ if (!dma_rd_buf) {
+ dma_unmap_single(i2c->dev, wpaddr,
+ msgs->len, DMA_TO_DEVICE);
+
+ i2c_put_dma_safe_msg_buf(dma_wr_buf, msgs, false);
+
+ return -ENOMEM;
+ }
+
+ rpaddr = dma_map_single(i2c->dev, dma_rd_buf,
(msgs + 1)->len,
DMA_FROM_DEVICE);
if (dma_mapping_error(i2c->dev, rpaddr)) {
dma_unmap_single(i2c->dev, wpaddr,
msgs->len, DMA_TO_DEVICE);
+
+ i2c_put_dma_safe_msg_buf(dma_wr_buf, msgs, false);
+ i2c_put_dma_safe_msg_buf(dma_rd_buf, (msgs + 1), false);
+
return -ENOMEM;
}
@@ -578,14 +619,21 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
if (i2c->op == I2C_MASTER_WR) {
dma_unmap_single(i2c->dev, wpaddr,
msgs->len, DMA_TO_DEVICE);
+
+ i2c_put_dma_safe_msg_buf(dma_wr_buf, msgs, true);
} else if (i2c->op == I2C_MASTER_RD) {
dma_unmap_single(i2c->dev, rpaddr,
msgs->len, DMA_FROM_DEVICE);
+
+ i2c_put_dma_safe_msg_buf(dma_rd_buf, msgs, true);
} else {
dma_unmap_single(i2c->dev, wpaddr, msgs->len,
DMA_TO_DEVICE);
dma_unmap_single(i2c->dev, rpaddr, (msgs + 1)->len,
DMA_FROM_DEVICE);
+
+ i2c_put_dma_safe_msg_buf(dma_wr_buf, msgs, true);
+ i2c_put_dma_safe_msg_buf(dma_rd_buf, (msgs + 1), true);
}
if (ret == 0) {
diff --git a/drivers/i2c/busses/i2c-nvidia-gpu.c b/drivers/i2c/busses/i2c-nvidia-gpu.c
new file mode 100644
index 000000000000..8822357bca0c
--- /dev/null
+++ b/drivers/i2c/busses/i2c-nvidia-gpu.c
@@ -0,0 +1,368 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Nvidia GPU I2C controller Driver
+ *
+ * Copyright (C) 2018 NVIDIA Corporation. All rights reserved.
+ * Author: Ajay Gupta <ajayg@nvidia.com>
+ */
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+
+#include <asm/unaligned.h>
+
+/* I2C definitions */
+#define I2C_MST_CNTL 0x00
+#define I2C_MST_CNTL_GEN_START BIT(0)
+#define I2C_MST_CNTL_GEN_STOP BIT(1)
+#define I2C_MST_CNTL_CMD_READ (1 << 2)
+#define I2C_MST_CNTL_CMD_WRITE (2 << 2)
+#define I2C_MST_CNTL_BURST_SIZE_SHIFT 6
+#define I2C_MST_CNTL_GEN_NACK BIT(28)
+#define I2C_MST_CNTL_STATUS GENMASK(30, 29)
+#define I2C_MST_CNTL_STATUS_OKAY (0 << 29)
+#define I2C_MST_CNTL_STATUS_NO_ACK (1 << 29)
+#define I2C_MST_CNTL_STATUS_TIMEOUT (2 << 29)
+#define I2C_MST_CNTL_STATUS_BUS_BUSY (3 << 29)
+#define I2C_MST_CNTL_CYCLE_TRIGGER BIT(31)
+
+#define I2C_MST_ADDR 0x04
+
+#define I2C_MST_I2C0_TIMING 0x08
+#define I2C_MST_I2C0_TIMING_SCL_PERIOD_100KHZ 0x10e
+#define I2C_MST_I2C0_TIMING_TIMEOUT_CLK_CNT 16
+#define I2C_MST_I2C0_TIMING_TIMEOUT_CLK_CNT_MAX 255
+#define I2C_MST_I2C0_TIMING_TIMEOUT_CHECK BIT(24)
+
+#define I2C_MST_DATA 0x0c
+
+#define I2C_MST_HYBRID_PADCTL 0x20
+#define I2C_MST_HYBRID_PADCTL_MODE_I2C BIT(0)
+#define I2C_MST_HYBRID_PADCTL_I2C_SCL_INPUT_RCV BIT(14)
+#define I2C_MST_HYBRID_PADCTL_I2C_SDA_INPUT_RCV BIT(15)
+
+struct gpu_i2c_dev {
+ struct device *dev;
+ void __iomem *regs;
+ struct i2c_adapter adapter;
+ struct i2c_board_info *gpu_ccgx_ucsi;
+};
+
+static void gpu_enable_i2c_bus(struct gpu_i2c_dev *i2cd)
+{
+ u32 val;
+
+ /* enable I2C */
+ val = readl(i2cd->regs + I2C_MST_HYBRID_PADCTL);
+ val |= I2C_MST_HYBRID_PADCTL_MODE_I2C |
+ I2C_MST_HYBRID_PADCTL_I2C_SCL_INPUT_RCV |
+ I2C_MST_HYBRID_PADCTL_I2C_SDA_INPUT_RCV;
+ writel(val, i2cd->regs + I2C_MST_HYBRID_PADCTL);
+
+ /* enable 100KHZ mode */
+ val = I2C_MST_I2C0_TIMING_SCL_PERIOD_100KHZ;
+ val |= (I2C_MST_I2C0_TIMING_TIMEOUT_CLK_CNT_MAX
+ << I2C_MST_I2C0_TIMING_TIMEOUT_CLK_CNT);
+ val |= I2C_MST_I2C0_TIMING_TIMEOUT_CHECK;
+ writel(val, i2cd->regs + I2C_MST_I2C0_TIMING);
+}
+
+static int gpu_i2c_check_status(struct gpu_i2c_dev *i2cd)
+{
+ unsigned long target = jiffies + msecs_to_jiffies(1000);
+ u32 val;
+
+ do {
+ val = readl(i2cd->regs + I2C_MST_CNTL);
+ if (!(val & I2C_MST_CNTL_CYCLE_TRIGGER))
+ break;
+ if ((val & I2C_MST_CNTL_STATUS) !=
+ I2C_MST_CNTL_STATUS_BUS_BUSY)
+ break;
+ usleep_range(500, 600);
+ } while (time_is_after_jiffies(target));
+
+ if (time_is_before_jiffies(target)) {
+ dev_err(i2cd->dev, "i2c timeout error %x\n", val);
+ return -ETIME;
+ }
+
+ val = readl(i2cd->regs + I2C_MST_CNTL);
+ switch (val & I2C_MST_CNTL_STATUS) {
+ case I2C_MST_CNTL_STATUS_OKAY:
+ return 0;
+ case I2C_MST_CNTL_STATUS_NO_ACK:
+ return -EIO;
+ case I2C_MST_CNTL_STATUS_TIMEOUT:
+ return -ETIME;
+ default:
+ return 0;
+ }
+}
+
+static int gpu_i2c_read(struct gpu_i2c_dev *i2cd, u8 *data, u16 len)
+{
+ int status;
+ u32 val;
+
+ val = I2C_MST_CNTL_GEN_START | I2C_MST_CNTL_CMD_READ |
+ (len << I2C_MST_CNTL_BURST_SIZE_SHIFT) |
+ I2C_MST_CNTL_CYCLE_TRIGGER | I2C_MST_CNTL_GEN_NACK;
+ writel(val, i2cd->regs + I2C_MST_CNTL);
+
+ status = gpu_i2c_check_status(i2cd);
+ if (status < 0)
+ return status;
+
+ val = readl(i2cd->regs + I2C_MST_DATA);
+ switch (len) {
+ case 1:
+ data[0] = val;
+ break;
+ case 2:
+ put_unaligned_be16(val, data);
+ break;
+ case 3:
+ put_unaligned_be16(val >> 8, data);
+ data[2] = val;
+ break;
+ case 4:
+ put_unaligned_be32(val, data);
+ break;
+ default:
+ break;
+ }
+ return status;
+}
+
+static int gpu_i2c_start(struct gpu_i2c_dev *i2cd)
+{
+ writel(I2C_MST_CNTL_GEN_START, i2cd->regs + I2C_MST_CNTL);
+ return gpu_i2c_check_status(i2cd);
+}
+
+static int gpu_i2c_stop(struct gpu_i2c_dev *i2cd)
+{
+ writel(I2C_MST_CNTL_GEN_STOP, i2cd->regs + I2C_MST_CNTL);
+ return gpu_i2c_check_status(i2cd);
+}
+
+static int gpu_i2c_write(struct gpu_i2c_dev *i2cd, u8 data)
+{
+ u32 val;
+
+ writel(data, i2cd->regs + I2C_MST_DATA);
+
+ val = I2C_MST_CNTL_CMD_WRITE | (1 << I2C_MST_CNTL_BURST_SIZE_SHIFT);
+ writel(val, i2cd->regs + I2C_MST_CNTL);
+
+ return gpu_i2c_check_status(i2cd);
+}
+
+static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct gpu_i2c_dev *i2cd = i2c_get_adapdata(adap);
+ int status, status2;
+ int i, j;
+
+ /*
+ * The controller supports maximum 4 byte read due to known
+ * limitation of sending STOP after every read.
+ */
+ for (i = 0; i < num; i++) {
+ if (msgs[i].flags & I2C_M_RD) {
+ /* program client address before starting read */
+ writel(msgs[i].addr, i2cd->regs + I2C_MST_ADDR);
+ /* gpu_i2c_read has implicit start */
+ status = gpu_i2c_read(i2cd, msgs[i].buf, msgs[i].len);
+ if (status < 0)
+ goto stop;
+ } else {
+ u8 addr = i2c_8bit_addr_from_msg(msgs + i);
+
+ status = gpu_i2c_start(i2cd);
+ if (status < 0) {
+ if (i == 0)
+ return status;
+ goto stop;
+ }
+
+ status = gpu_i2c_write(i2cd, addr);
+ if (status < 0)
+ goto stop;
+
+ for (j = 0; j < msgs[i].len; j++) {
+ status = gpu_i2c_write(i2cd, msgs[i].buf[j]);
+ if (status < 0)
+ goto stop;
+ }
+ }
+ }
+ status = gpu_i2c_stop(i2cd);
+ if (status < 0)
+ return status;
+
+ return i;
+stop:
+ status2 = gpu_i2c_stop(i2cd);
+ if (status2 < 0)
+ dev_err(i2cd->dev, "i2c stop failed %d\n", status2);
+ return status;
+}
+
+static const struct i2c_adapter_quirks gpu_i2c_quirks = {
+ .max_read_len = 4,
+ .flags = I2C_AQ_COMB_WRITE_THEN_READ,
+};
+
+static u32 gpu_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm gpu_i2c_algorithm = {
+ .master_xfer = gpu_i2c_master_xfer,
+ .functionality = gpu_i2c_functionality,
+};
+
+/*
+ * This driver is for Nvidia GPU cards with USB Type-C interface.
+ * We want to identify the cards using vendor ID and class code only
+ * to avoid dependency of adding product id for any new card which
+ * requires this driver.
+ * Currently there is no class code defined for UCSI device over PCI
+ * so using UNKNOWN class for now and it will be updated when UCSI
+ * over PCI gets a class code.
+ * There is no other NVIDIA cards with UNKNOWN class code. Even if the
+ * driver gets loaded for an undesired card then eventually i2c_read()
+ * (initiated from UCSI i2c_client) will timeout or UCSI commands will
+ * timeout.
+ */
+#define PCI_CLASS_SERIAL_UNKNOWN 0x0c80
+static const struct pci_device_id gpu_i2c_ids[] = {
+ { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_SERIAL_UNKNOWN << 8, 0xffffff00},
+ { }
+};
+MODULE_DEVICE_TABLE(pci, gpu_i2c_ids);
+
+static int gpu_populate_client(struct gpu_i2c_dev *i2cd, int irq)
+{
+ struct i2c_client *ccgx_client;
+
+ i2cd->gpu_ccgx_ucsi = devm_kzalloc(i2cd->dev,
+ sizeof(*i2cd->gpu_ccgx_ucsi),
+ GFP_KERNEL);
+ if (!i2cd->gpu_ccgx_ucsi)
+ return -ENOMEM;
+
+ strlcpy(i2cd->gpu_ccgx_ucsi->type, "ccgx-ucsi",
+ sizeof(i2cd->gpu_ccgx_ucsi->type));
+ i2cd->gpu_ccgx_ucsi->addr = 0x8;
+ i2cd->gpu_ccgx_ucsi->irq = irq;
+ ccgx_client = i2c_new_device(&i2cd->adapter, i2cd->gpu_ccgx_ucsi);
+ if (!ccgx_client)
+ return -ENODEV;
+
+ return 0;
+}
+
+static int gpu_i2c_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct gpu_i2c_dev *i2cd;
+ int status;
+
+ i2cd = devm_kzalloc(&pdev->dev, sizeof(*i2cd), GFP_KERNEL);
+ if (!i2cd)
+ return -ENOMEM;
+
+ i2cd->dev = &pdev->dev;
+ dev_set_drvdata(&pdev->dev, i2cd);
+
+ status = pcim_enable_device(pdev);
+ if (status < 0) {
+ dev_err(&pdev->dev, "pcim_enable_device failed %d\n", status);
+ return status;
+ }
+
+ pci_set_master(pdev);
+
+ i2cd->regs = pcim_iomap(pdev, 0, 0);
+ if (!i2cd->regs) {
+ dev_err(&pdev->dev, "pcim_iomap failed\n");
+ return -ENOMEM;
+ }
+
+ status = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI);
+ if (status < 0) {
+ dev_err(&pdev->dev, "pci_alloc_irq_vectors err %d\n", status);
+ return status;
+ }
+
+ gpu_enable_i2c_bus(i2cd);
+
+ i2c_set_adapdata(&i2cd->adapter, i2cd);
+ i2cd->adapter.owner = THIS_MODULE;
+ strlcpy(i2cd->adapter.name, "NVIDIA GPU I2C adapter",
+ sizeof(i2cd->adapter.name));
+ i2cd->adapter.algo = &gpu_i2c_algorithm;
+ i2cd->adapter.quirks = &gpu_i2c_quirks;
+ i2cd->adapter.dev.parent = &pdev->dev;
+ status = i2c_add_adapter(&i2cd->adapter);
+ if (status < 0)
+ goto free_irq_vectors;
+
+ status = gpu_populate_client(i2cd, pdev->irq);
+ if (status < 0) {
+ dev_err(&pdev->dev, "gpu_populate_client failed %d\n", status);
+ goto del_adapter;
+ }
+
+ return 0;
+
+del_adapter:
+ i2c_del_adapter(&i2cd->adapter);
+free_irq_vectors:
+ pci_free_irq_vectors(pdev);
+ return status;
+}
+
+static void gpu_i2c_remove(struct pci_dev *pdev)
+{
+ struct gpu_i2c_dev *i2cd = dev_get_drvdata(&pdev->dev);
+
+ i2c_del_adapter(&i2cd->adapter);
+ pci_free_irq_vectors(pdev);
+}
+
+static int gpu_i2c_resume(struct device *dev)
+{
+ struct gpu_i2c_dev *i2cd = dev_get_drvdata(dev);
+
+ gpu_enable_i2c_bus(i2cd);
+ return 0;
+}
+
+static UNIVERSAL_DEV_PM_OPS(gpu_i2c_driver_pm, NULL, gpu_i2c_resume, NULL);
+
+static struct pci_driver gpu_i2c_driver = {
+ .name = "nvidia-gpu",
+ .id_table = gpu_i2c_ids,
+ .probe = gpu_i2c_probe,
+ .remove = gpu_i2c_remove,
+ .driver = {
+ .pm = &gpu_i2c_driver_pm,
+ },
+};
+
+module_pci_driver(gpu_i2c_driver);
+
+MODULE_AUTHOR("Ajay Gupta <ajayg@nvidia.com>");
+MODULE_DESCRIPTION("Nvidia GPU I2C controller Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index 65d06a819307..b1086bfb0465 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -661,9 +661,6 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
dev_dbg(omap->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
msg->addr, msg->len, msg->flags, stop);
- if (msg->len == 0)
- return -EINVAL;
-
omap->receiver = !!(msg->flags & I2C_M_RD);
omap_i2c_resize_fifo(omap, msg->len, omap->receiver);
@@ -1179,6 +1176,10 @@ static const struct i2c_algorithm omap_i2c_algo = {
.functionality = omap_i2c_func,
};
+static const struct i2c_adapter_quirks omap_i2c_quirks = {
+ .flags = I2C_AQ_NO_ZERO_LEN,
+};
+
#ifdef CONFIG_OF
static struct omap_i2c_bus_platform_data omap2420_pdata = {
.rev = OMAP_I2C_IP_VERSION_1,
@@ -1453,6 +1454,7 @@ omap_i2c_probe(struct platform_device *pdev)
adap->class = I2C_CLASS_DEPRECATED;
strlcpy(adap->name, "OMAP I2C adapter", sizeof(adap->name));
adap->algo = &omap_i2c_algo;
+ adap->quirks = &omap_i2c_quirks;
adap->dev.parent = &pdev->dev;
adap->dev.of_node = pdev->dev.of_node;
adap->bus_recovery_info = &omap_i2c_bus_recovery_info;
diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c
index f2a2067525ef..f6f4ed8afc93 100644
--- a/drivers/i2c/busses/i2c-powermac.c
+++ b/drivers/i2c/busses/i2c-powermac.c
@@ -388,9 +388,8 @@ static void i2c_powermac_register_devices(struct i2c_adapter *adap,
static int i2c_powermac_probe(struct platform_device *dev)
{
struct pmac_i2c_bus *bus = dev_get_platdata(&dev->dev);
- struct device_node *parent = NULL;
+ struct device_node *parent;
struct i2c_adapter *adapter;
- const char *basename;
int rc;
if (bus == NULL)
@@ -407,23 +406,25 @@ static int i2c_powermac_probe(struct platform_device *dev)
parent = of_get_parent(pmac_i2c_get_controller(bus));
if (parent == NULL)
return -EINVAL;
- basename = parent->name;
+ snprintf(adapter->name, sizeof(adapter->name), "%pOFn %d",
+ parent,
+ pmac_i2c_get_channel(bus));
+ of_node_put(parent);
break;
case pmac_i2c_bus_pmu:
- basename = "pmu";
+ snprintf(adapter->name, sizeof(adapter->name), "pmu %d",
+ pmac_i2c_get_channel(bus));
break;
case pmac_i2c_bus_smu:
/* This is not what we used to do but I'm fixing drivers at
* the same time as this change
*/
- basename = "smu";
+ snprintf(adapter->name, sizeof(adapter->name), "smu %d",
+ pmac_i2c_get_channel(bus));
break;
default:
return -EINVAL;
}
- snprintf(adapter->name, sizeof(adapter->name), "%s %d", basename,
- pmac_i2c_get_channel(bus));
- of_node_put(parent);
platform_set_drvdata(dev, adapter);
adapter->algo = &i2c_powermac_algorithm;
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index 36732eb688a4..db075bc0d952 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -201,21 +201,23 @@ static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err)
static irqreturn_t geni_i2c_irq(int irq, void *dev)
{
struct geni_i2c_dev *gi2c = dev;
- int j;
+ void __iomem *base = gi2c->se.base;
+ int j, p;
u32 m_stat;
u32 rx_st;
u32 dm_tx_st;
u32 dm_rx_st;
u32 dma;
+ u32 val;
struct i2c_msg *cur;
unsigned long flags;
spin_lock_irqsave(&gi2c->lock, flags);
- m_stat = readl_relaxed(gi2c->se.base + SE_GENI_M_IRQ_STATUS);
- rx_st = readl_relaxed(gi2c->se.base + SE_GENI_RX_FIFO_STATUS);
- dm_tx_st = readl_relaxed(gi2c->se.base + SE_DMA_TX_IRQ_STAT);
- dm_rx_st = readl_relaxed(gi2c->se.base + SE_DMA_RX_IRQ_STAT);
- dma = readl_relaxed(gi2c->se.base + SE_GENI_DMA_MODE_EN);
+ m_stat = readl_relaxed(base + SE_GENI_M_IRQ_STATUS);
+ rx_st = readl_relaxed(base + SE_GENI_RX_FIFO_STATUS);
+ dm_tx_st = readl_relaxed(base + SE_DMA_TX_IRQ_STAT);
+ dm_rx_st = readl_relaxed(base + SE_DMA_RX_IRQ_STAT);
+ dma = readl_relaxed(base + SE_GENI_DMA_MODE_EN);
cur = gi2c->cur;
if (!cur ||
@@ -238,26 +240,17 @@ static irqreturn_t geni_i2c_irq(int irq, void *dev)
/* Disable the TX Watermark interrupt to stop TX */
if (!dma)
- writel_relaxed(0, gi2c->se.base +
- SE_GENI_TX_WATERMARK_REG);
- goto irqret;
- }
-
- if (dma) {
+ writel_relaxed(0, base + SE_GENI_TX_WATERMARK_REG);
+ } else if (dma) {
dev_dbg(gi2c->se.dev, "i2c dma tx:0x%x, dma rx:0x%x\n",
dm_tx_st, dm_rx_st);
- goto irqret;
- }
-
- if (cur->flags & I2C_M_RD &&
- m_stat & (M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN)) {
+ } else if (cur->flags & I2C_M_RD &&
+ m_stat & (M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN)) {
u32 rxcnt = rx_st & RX_FIFO_WC_MSK;
for (j = 0; j < rxcnt; j++) {
- u32 val;
- int p = 0;
-
- val = readl_relaxed(gi2c->se.base + SE_GENI_RX_FIFOn);
+ p = 0;
+ val = readl_relaxed(base + SE_GENI_RX_FIFOn);
while (gi2c->cur_rd < cur->len && p < sizeof(val)) {
cur->buf[gi2c->cur_rd++] = val & 0xff;
val >>= 8;
@@ -270,44 +263,39 @@ static irqreturn_t geni_i2c_irq(int irq, void *dev)
m_stat & M_TX_FIFO_WATERMARK_EN) {
for (j = 0; j < gi2c->tx_wm; j++) {
u32 temp;
- u32 val = 0;
- int p = 0;
+ val = 0;
+ p = 0;
while (gi2c->cur_wr < cur->len && p < sizeof(val)) {
temp = cur->buf[gi2c->cur_wr++];
val |= temp << (p * 8);
p++;
}
- writel_relaxed(val, gi2c->se.base + SE_GENI_TX_FIFOn);
+ writel_relaxed(val, base + SE_GENI_TX_FIFOn);
/* TX Complete, Disable the TX Watermark interrupt */
if (gi2c->cur_wr == cur->len) {
- writel_relaxed(0, gi2c->se.base +
- SE_GENI_TX_WATERMARK_REG);
+ writel_relaxed(0, base + SE_GENI_TX_WATERMARK_REG);
break;
}
}
}
-irqret:
+
if (m_stat)
- writel_relaxed(m_stat, gi2c->se.base + SE_GENI_M_IRQ_CLEAR);
+ writel_relaxed(m_stat, base + SE_GENI_M_IRQ_CLEAR);
+
+ if (dma && dm_tx_st)
+ writel_relaxed(dm_tx_st, base + SE_DMA_TX_IRQ_CLR);
+ if (dma && dm_rx_st)
+ writel_relaxed(dm_rx_st, base + SE_DMA_RX_IRQ_CLR);
- if (dma) {
- if (dm_tx_st)
- writel_relaxed(dm_tx_st, gi2c->se.base +
- SE_DMA_TX_IRQ_CLR);
- if (dm_rx_st)
- writel_relaxed(dm_rx_st, gi2c->se.base +
- SE_DMA_RX_IRQ_CLR);
- }
/* if this is err with done-bit not set, handle that through timeout. */
- if (m_stat & M_CMD_DONE_EN || m_stat & M_CMD_ABORT_EN)
- complete(&gi2c->done);
- else if (dm_tx_st & TX_DMA_DONE || dm_tx_st & TX_RESET_DONE)
- complete(&gi2c->done);
- else if (dm_rx_st & RX_DMA_DONE || dm_rx_st & RX_RESET_DONE)
+ if (m_stat & M_CMD_DONE_EN || m_stat & M_CMD_ABORT_EN ||
+ dm_tx_st & TX_DMA_DONE || dm_tx_st & TX_RESET_DONE ||
+ dm_rx_st & RX_DMA_DONE || dm_rx_st & RX_RESET_DONE)
complete(&gi2c->done);
spin_unlock_irqrestore(&gi2c->lock, flags);
+
return IRQ_HANDLED;
}
@@ -365,23 +353,24 @@ static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
u32 m_param)
{
dma_addr_t rx_dma;
- enum geni_se_xfer_mode mode;
- unsigned long time_left = XFER_TIMEOUT;
-
- gi2c->cur = msg;
- mode = msg->len > 32 ? GENI_SE_DMA : GENI_SE_FIFO;
- geni_se_select_mode(&gi2c->se, mode);
- writel_relaxed(msg->len, gi2c->se.base + SE_I2C_RX_TRANS_LEN);
- geni_se_setup_m_cmd(&gi2c->se, I2C_READ, m_param);
- if (mode == GENI_SE_DMA) {
- int ret;
-
- ret = geni_se_rx_dma_prep(&gi2c->se, msg->buf, msg->len,
- &rx_dma);
- if (ret) {
- mode = GENI_SE_FIFO;
- geni_se_select_mode(&gi2c->se, mode);
- }
+ unsigned long time_left;
+ void *dma_buf;
+ struct geni_se *se = &gi2c->se;
+ size_t len = msg->len;
+
+ dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
+ if (dma_buf)
+ geni_se_select_mode(se, GENI_SE_DMA);
+ else
+ geni_se_select_mode(se, GENI_SE_FIFO);
+
+ writel_relaxed(len, se->base + SE_I2C_RX_TRANS_LEN);
+ geni_se_setup_m_cmd(se, I2C_READ, m_param);
+
+ if (dma_buf && geni_se_rx_dma_prep(se, dma_buf, len, &rx_dma)) {
+ geni_se_select_mode(se, GENI_SE_FIFO);
+ i2c_put_dma_safe_msg_buf(dma_buf, msg, false);
+ dma_buf = NULL;
}
time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
@@ -389,11 +378,13 @@ static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
geni_i2c_abort_xfer(gi2c);
gi2c->cur_rd = 0;
- if (mode == GENI_SE_DMA) {
+ if (dma_buf) {
if (gi2c->err)
geni_i2c_rx_fsm_rst(gi2c);
- geni_se_rx_dma_unprep(&gi2c->se, rx_dma, msg->len);
+ geni_se_rx_dma_unprep(se, rx_dma, len);
+ i2c_put_dma_safe_msg_buf(dma_buf, msg, !gi2c->err);
}
+
return gi2c->err;
}
@@ -401,38 +392,41 @@ static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
u32 m_param)
{
dma_addr_t tx_dma;
- enum geni_se_xfer_mode mode;
unsigned long time_left;
-
- gi2c->cur = msg;
- mode = msg->len > 32 ? GENI_SE_DMA : GENI_SE_FIFO;
- geni_se_select_mode(&gi2c->se, mode);
- writel_relaxed(msg->len, gi2c->se.base + SE_I2C_TX_TRANS_LEN);
- geni_se_setup_m_cmd(&gi2c->se, I2C_WRITE, m_param);
- if (mode == GENI_SE_DMA) {
- int ret;
-
- ret = geni_se_tx_dma_prep(&gi2c->se, msg->buf, msg->len,
- &tx_dma);
- if (ret) {
- mode = GENI_SE_FIFO;
- geni_se_select_mode(&gi2c->se, mode);
- }
+ void *dma_buf;
+ struct geni_se *se = &gi2c->se;
+ size_t len = msg->len;
+
+ dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
+ if (dma_buf)
+ geni_se_select_mode(se, GENI_SE_DMA);
+ else
+ geni_se_select_mode(se, GENI_SE_FIFO);
+
+ writel_relaxed(len, se->base + SE_I2C_TX_TRANS_LEN);
+ geni_se_setup_m_cmd(se, I2C_WRITE, m_param);
+
+ if (dma_buf && geni_se_tx_dma_prep(se, dma_buf, len, &tx_dma)) {
+ geni_se_select_mode(se, GENI_SE_FIFO);
+ i2c_put_dma_safe_msg_buf(dma_buf, msg, false);
+ dma_buf = NULL;
}
- if (mode == GENI_SE_FIFO) /* Get FIFO IRQ */
- writel_relaxed(1, gi2c->se.base + SE_GENI_TX_WATERMARK_REG);
+ if (!dma_buf) /* Get FIFO IRQ */
+ writel_relaxed(1, se->base + SE_GENI_TX_WATERMARK_REG);
time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
if (!time_left)
geni_i2c_abort_xfer(gi2c);
gi2c->cur_wr = 0;
- if (mode == GENI_SE_DMA) {
+ if (dma_buf) {
if (gi2c->err)
geni_i2c_tx_fsm_rst(gi2c);
- geni_se_tx_dma_unprep(&gi2c->se, tx_dma, msg->len);
+ geni_se_tx_dma_unprep(se, tx_dma, len);
+ i2c_put_dma_safe_msg_buf(dma_buf, msg, !gi2c->err);
}
+
return gi2c->err;
}
@@ -460,6 +454,7 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
m_param |= ((msgs[i].addr << SLV_ADDR_SHFT) & SLV_ADDR_MSK);
+ gi2c->cur = &msgs[i];
if (msgs[i].flags & I2C_M_RD)
ret = geni_i2c_rx_one_msg(gi2c, &msgs[i], m_param);
else
@@ -576,18 +571,19 @@ static int geni_i2c_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "i2c fifo/se-dma mode. fifo depth:%d\n", tx_depth);
- ret = i2c_add_adapter(&gi2c->adap);
- if (ret) {
- dev_err(&pdev->dev, "Error adding i2c adapter %d\n", ret);
- return ret;
- }
-
gi2c->suspended = 1;
pm_runtime_set_suspended(gi2c->se.dev);
pm_runtime_set_autosuspend_delay(gi2c->se.dev, I2C_AUTO_SUSPEND_DELAY);
pm_runtime_use_autosuspend(gi2c->se.dev);
pm_runtime_enable(gi2c->se.dev);
+ ret = i2c_add_adapter(&gi2c->adap);
+ if (ret) {
+ dev_err(&pdev->dev, "Error adding i2c adapter %d\n", ret);
+ pm_runtime_disable(gi2c->se.dev);
+ return ret;
+ }
+
return 0;
}
@@ -595,8 +591,8 @@ static int geni_i2c_remove(struct platform_device *pdev)
{
struct geni_i2c_dev *gi2c = platform_get_drvdata(pdev);
- pm_runtime_disable(gi2c->se.dev);
i2c_del_adapter(&gi2c->adap);
+ pm_runtime_disable(gi2c->se.dev);
return 0;
}
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index c86c3ae1318f..e09cd0775ae9 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -1088,11 +1088,6 @@ static int qup_i2c_xfer(struct i2c_adapter *adap,
writel(I2C_MINI_CORE | I2C_N_VAL, qup->base + QUP_CONFIG);
for (idx = 0; idx < num; idx++) {
- if (msgs[idx].len == 0) {
- ret = -EINVAL;
- goto out;
- }
-
if (qup_i2c_poll_state_i2c_master(qup)) {
ret = -EIO;
goto out;
@@ -1520,9 +1515,6 @@ qup_i2c_determine_mode_v2(struct qup_i2c_dev *qup,
/* All i2c_msgs should be transferred using either dma or cpu */
for (idx = 0; idx < num; idx++) {
- if (msgs[idx].len == 0)
- return -EINVAL;
-
if (msgs[idx].flags & I2C_M_RD)
max_rx_len = max_t(unsigned int, max_rx_len,
msgs[idx].len);
@@ -1636,9 +1628,14 @@ static const struct i2c_algorithm qup_i2c_algo_v2 = {
* which limits the possible read to 256 (QUP_READ_LIMIT) bytes.
*/
static const struct i2c_adapter_quirks qup_i2c_quirks = {
+ .flags = I2C_AQ_NO_ZERO_LEN,
.max_read_len = QUP_READ_LIMIT,
};
+static const struct i2c_adapter_quirks qup_i2c_quirks_v2 = {
+ .flags = I2C_AQ_NO_ZERO_LEN,
+};
+
static void qup_i2c_enable_clocks(struct qup_i2c_dev *qup)
{
clk_prepare_enable(qup->clk);
@@ -1701,6 +1698,7 @@ static int qup_i2c_probe(struct platform_device *pdev)
is_qup_v1 = true;
} else {
qup->adap.algo = &qup_i2c_algo_v2;
+ qup->adap.quirks = &qup_i2c_quirks_v2;
is_qup_v1 = false;
if (acpi_match_device(qup_i2c_acpi_match, qup->dev))
goto nodma;
diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c
index 52cf42b32f0a..4aa7dde876f3 100644
--- a/drivers/i2c/busses/i2c-rcar.c
+++ b/drivers/i2c/busses/i2c-rcar.c
@@ -806,8 +806,12 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
time_left = wait_event_timeout(priv->wait, priv->flags & ID_DONE,
num * adap->timeout);
- if (!time_left) {
+
+ /* cleanup DMA if it couldn't complete properly due to an error */
+ if (priv->dma_direction != DMA_NONE)
rcar_i2c_cleanup_dma(priv);
+
+ if (!time_left) {
rcar_i2c_init(priv);
ret = -ETIMEDOUT;
} else if (priv->flags & ID_NACK) {
diff --git a/drivers/i2c/busses/i2c-scmi.c b/drivers/i2c/busses/i2c-scmi.c
index a01389b85f13..7e9a2bbf5ddc 100644
--- a/drivers/i2c/busses/i2c-scmi.c
+++ b/drivers/i2c/busses/i2c-scmi.c
@@ -152,6 +152,7 @@ acpi_smbus_cmi_access(struct i2c_adapter *adap, u16 addr, unsigned short flags,
mt_params[3].type = ACPI_TYPE_INTEGER;
mt_params[3].integer.value = len;
mt_params[4].type = ACPI_TYPE_BUFFER;
+ mt_params[4].buffer.length = len;
mt_params[4].buffer.pointer = data->block + 1;
}
break;
diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c
index 818cab14e87c..a7a7a9c3bc7c 100644
--- a/drivers/i2c/busses/i2c-sh_mobile.c
+++ b/drivers/i2c/busses/i2c-sh_mobile.c
@@ -947,27 +947,9 @@ static int sh_mobile_i2c_remove(struct platform_device *dev)
return 0;
}
-static int sh_mobile_i2c_runtime_nop(struct device *dev)
-{
- /* Runtime PM callback shared between ->runtime_suspend()
- * and ->runtime_resume(). Simply returns success.
- *
- * This driver re-initializes all registers after
- * pm_runtime_get_sync() anyway so there is no need
- * to save and restore registers here.
- */
- return 0;
-}
-
-static const struct dev_pm_ops sh_mobile_i2c_dev_pm_ops = {
- .runtime_suspend = sh_mobile_i2c_runtime_nop,
- .runtime_resume = sh_mobile_i2c_runtime_nop,
-};
-
static struct platform_driver sh_mobile_i2c_driver = {
.driver = {
.name = "i2c-sh_mobile",
- .pm = &sh_mobile_i2c_dev_pm_ops,
.of_match_table = sh_mobile_i2c_dt_ids,
},
.probe = sh_mobile_i2c_probe,
diff --git a/drivers/i2c/busses/i2c-synquacer.c b/drivers/i2c/busses/i2c-synquacer.c
index 915f5edbab33..2184b7c3580e 100644
--- a/drivers/i2c/busses/i2c-synquacer.c
+++ b/drivers/i2c/busses/i2c-synquacer.c
@@ -404,7 +404,7 @@ static irqreturn_t synquacer_i2c_isr(int irq, void *dev_id)
if (i2c->state == STATE_READ)
goto prepare_read;
- /* fallthru */
+ /* fall through */
case STATE_WRITE:
if (bsr & SYNQUACER_I2C_BSR_LRB) {
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 60c8561fbe65..437294ea2f0a 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -684,9 +684,6 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
tegra_i2c_flush_fifos(i2c_dev);
- if (msg->len == 0)
- return -EINVAL;
-
i2c_dev->msg_buf = msg->buf;
i2c_dev->msg_buf_remaining = msg->len;
i2c_dev->msg_err = I2C_ERR_NONE;
@@ -831,6 +828,7 @@ static const struct i2c_algorithm tegra_i2c_algo = {
/* payload size is only 12 bit */
static const struct i2c_adapter_quirks tegra_i2c_quirks = {
+ .flags = I2C_AQ_NO_ZERO_LEN,
.max_read_len = 4096,
.max_write_len = 4096,
};
diff --git a/drivers/i2c/busses/i2c-uniphier-f.c b/drivers/i2c/busses/i2c-uniphier-f.c
index a403e8579b65..dd384743dbbd 100644
--- a/drivers/i2c/busses/i2c-uniphier-f.c
+++ b/drivers/i2c/busses/i2c-uniphier-f.c
@@ -98,6 +98,7 @@ struct uniphier_fi2c_priv {
unsigned int flags;
unsigned int busy_cnt;
unsigned int clk_cycle;
+ spinlock_t lock; /* IRQ synchronization */
};
static void uniphier_fi2c_fill_txfifo(struct uniphier_fi2c_priv *priv,
@@ -142,9 +143,10 @@ static void uniphier_fi2c_set_irqs(struct uniphier_fi2c_priv *priv)
writel(priv->enabled_irqs, priv->membase + UNIPHIER_FI2C_IE);
}
-static void uniphier_fi2c_clear_irqs(struct uniphier_fi2c_priv *priv)
+static void uniphier_fi2c_clear_irqs(struct uniphier_fi2c_priv *priv,
+ u32 mask)
{
- writel(-1, priv->membase + UNIPHIER_FI2C_IC);
+ writel(mask, priv->membase + UNIPHIER_FI2C_IC);
}
static void uniphier_fi2c_stop(struct uniphier_fi2c_priv *priv)
@@ -162,12 +164,17 @@ static irqreturn_t uniphier_fi2c_interrupt(int irq, void *dev_id)
struct uniphier_fi2c_priv *priv = dev_id;
u32 irq_status;
+ spin_lock(&priv->lock);
+
irq_status = readl(priv->membase + UNIPHIER_FI2C_INT);
+ irq_status &= priv->enabled_irqs;
dev_dbg(&priv->adap.dev,
"interrupt: enabled_irqs=%04x, irq_status=%04x\n",
priv->enabled_irqs, irq_status);
+ uniphier_fi2c_clear_irqs(priv, irq_status);
+
if (irq_status & UNIPHIER_FI2C_INT_STOP)
goto complete;
@@ -230,6 +237,8 @@ static irqreturn_t uniphier_fi2c_interrupt(int irq, void *dev_id)
goto handled;
}
+ spin_unlock(&priv->lock);
+
return IRQ_NONE;
data_done:
@@ -244,7 +253,7 @@ complete:
}
handled:
- uniphier_fi2c_clear_irqs(priv);
+ spin_unlock(&priv->lock);
return IRQ_HANDLED;
}
@@ -252,6 +261,8 @@ handled:
static void uniphier_fi2c_tx_init(struct uniphier_fi2c_priv *priv, u16 addr)
{
priv->enabled_irqs |= UNIPHIER_FI2C_INT_TE;
+ uniphier_fi2c_set_irqs(priv);
+
/* do not use TX byte counter */
writel(0, priv->membase + UNIPHIER_FI2C_TBC);
/* set slave address */
@@ -284,6 +295,8 @@ static void uniphier_fi2c_rx_init(struct uniphier_fi2c_priv *priv, u16 addr)
priv->enabled_irqs |= UNIPHIER_FI2C_INT_RF;
}
+ uniphier_fi2c_set_irqs(priv);
+
/* set slave address with RD bit */
writel(UNIPHIER_FI2C_DTTX_CMD | UNIPHIER_FI2C_DTTX_RD | addr << 1,
priv->membase + UNIPHIER_FI2C_DTTX);
@@ -307,14 +320,16 @@ static void uniphier_fi2c_recover(struct uniphier_fi2c_priv *priv)
}
static int uniphier_fi2c_master_xfer_one(struct i2c_adapter *adap,
- struct i2c_msg *msg, bool stop)
+ struct i2c_msg *msg, bool repeat,
+ bool stop)
{
struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap);
bool is_read = msg->flags & I2C_M_RD;
- unsigned long time_left;
+ unsigned long time_left, flags;
- dev_dbg(&adap->dev, "%s: addr=0x%02x, len=%d, stop=%d\n",
- is_read ? "receive" : "transmit", msg->addr, msg->len, stop);
+ dev_dbg(&adap->dev, "%s: addr=0x%02x, len=%d, repeat=%d, stop=%d\n",
+ is_read ? "receive" : "transmit", msg->addr, msg->len,
+ repeat, stop);
priv->len = msg->len;
priv->buf = msg->buf;
@@ -326,22 +341,36 @@ static int uniphier_fi2c_master_xfer_one(struct i2c_adapter *adap,
priv->flags |= UNIPHIER_FI2C_STOP;
reinit_completion(&priv->comp);
- uniphier_fi2c_clear_irqs(priv);
+ uniphier_fi2c_clear_irqs(priv, U32_MAX);
writel(UNIPHIER_FI2C_RST_TBRST | UNIPHIER_FI2C_RST_RBRST,
priv->membase + UNIPHIER_FI2C_RST); /* reset TX/RX FIFO */
+ spin_lock_irqsave(&priv->lock, flags);
+
if (is_read)
uniphier_fi2c_rx_init(priv, msg->addr);
else
uniphier_fi2c_tx_init(priv, msg->addr);
- uniphier_fi2c_set_irqs(priv);
-
dev_dbg(&adap->dev, "start condition\n");
- writel(UNIPHIER_FI2C_CR_MST | UNIPHIER_FI2C_CR_STA,
- priv->membase + UNIPHIER_FI2C_CR);
+ /*
+ * For a repeated START condition, writing a slave address to the FIFO
+ * kicks the controller. So, the UNIPHIER_FI2C_CR register should be
+ * written only for a non-repeated START condition.
+ */
+ if (!repeat)
+ writel(UNIPHIER_FI2C_CR_MST | UNIPHIER_FI2C_CR_STA,
+ priv->membase + UNIPHIER_FI2C_CR);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
time_left = wait_for_completion_timeout(&priv->comp, adap->timeout);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->enabled_irqs = 0;
+ uniphier_fi2c_set_irqs(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
if (!time_left) {
dev_err(&adap->dev, "transaction timeout.\n");
uniphier_fi2c_recover(priv);
@@ -394,6 +423,7 @@ static int uniphier_fi2c_master_xfer(struct i2c_adapter *adap,
struct i2c_msg *msgs, int num)
{
struct i2c_msg *msg, *emsg = msgs + num;
+ bool repeat = false;
int ret;
ret = uniphier_fi2c_check_bus_busy(adap);
@@ -404,9 +434,11 @@ static int uniphier_fi2c_master_xfer(struct i2c_adapter *adap,
/* Emit STOP if it is the last message or I2C_M_STOP is set. */
bool stop = (msg + 1 == emsg) || (msg->flags & I2C_M_STOP);
- ret = uniphier_fi2c_master_xfer_one(adap, msg, stop);
+ ret = uniphier_fi2c_master_xfer_one(adap, msg, repeat, stop);
if (ret)
return ret;
+
+ repeat = !stop;
}
return num;
@@ -529,6 +561,7 @@ static int uniphier_fi2c_probe(struct platform_device *pdev)
priv->clk_cycle = clk_rate / bus_speed;
init_completion(&priv->comp);
+ spin_lock_init(&priv->lock);
priv->adap.owner = THIS_MODULE;
priv->adap.algo = &uniphier_fi2c_algo;
priv->adap.dev.parent = dev;
diff --git a/drivers/i2c/busses/i2c-zx2967.c b/drivers/i2c/busses/i2c-zx2967.c
index 48281c1b30c6..b8f9e020d80e 100644
--- a/drivers/i2c/busses/i2c-zx2967.c
+++ b/drivers/i2c/busses/i2c-zx2967.c
@@ -281,9 +281,6 @@ static int zx2967_i2c_xfer_msg(struct zx2967_i2c *i2c,
int ret;
int i;
- if (msg->len == 0)
- return -EINVAL;
-
zx2967_i2c_flush_fifos(i2c);
i2c->cur_trans = msg->buf;
@@ -498,6 +495,10 @@ static const struct i2c_algorithm zx2967_i2c_algo = {
.functionality = zx2967_i2c_func,
};
+static const struct i2c_adapter_quirks zx2967_i2c_quirks = {
+ .flags = I2C_AQ_NO_ZERO_LEN,
+};
+
static const struct of_device_id zx2967_i2c_of_match[] = {
{ .compatible = "zte,zx296718-i2c", },
{ },
@@ -568,6 +569,7 @@ static int zx2967_i2c_probe(struct platform_device *pdev)
strlcpy(i2c->adap.name, "zx2967 i2c adapter",
sizeof(i2c->adap.name));
i2c->adap.algo = &zx2967_i2c_algo;
+ i2c->adap.quirks = &zx2967_i2c_quirks;
i2c->adap.nr = pdev->id;
i2c->adap.dev.parent = &pdev->dev;
i2c->adap.dev.of_node = pdev->dev.of_node;
diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c
index 9ee9a15e7134..28460f6a60cc 100644
--- a/drivers/i2c/i2c-core-base.c
+++ b/drivers/i2c/i2c-core-base.c
@@ -306,10 +306,7 @@ static int i2c_smbus_host_notify_to_irq(const struct i2c_client *client)
if (client->flags & I2C_CLIENT_TEN)
return -EINVAL;
- irq = irq_find_mapping(adap->host_notify_domain, client->addr);
- if (!irq)
- irq = irq_create_mapping(adap->host_notify_domain,
- client->addr);
+ irq = irq_create_mapping(adap->host_notify_domain, client->addr);
return irq > 0 ? irq : -ENXIO;
}
@@ -433,6 +430,8 @@ static int i2c_device_remove(struct device *dev)
dev_pm_clear_wake_irq(&client->dev);
device_init_wakeup(&client->dev, false);
+ client->irq = 0;
+
return status;
}
@@ -1922,6 +1921,11 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
int ret;
+ if (!adap->algo->master_xfer) {
+ dev_dbg(&adap->dev, "I2C level transfers not supported\n");
+ return -EOPNOTSUPP;
+ }
+
/* REVISIT the fault reporting model here is weak:
*
* - When we get an error after receiving N bytes from a slave,
@@ -1938,35 +1942,19 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
* one (discarding status on the second message) or errno
* (discarding status on the first one).
*/
-
- if (adap->algo->master_xfer) {
-#ifdef DEBUG
- for (ret = 0; ret < num; ret++) {
- dev_dbg(&adap->dev,
- "master_xfer[%d] %c, addr=0x%02x, len=%d%s\n",
- ret, (msgs[ret].flags & I2C_M_RD) ? 'R' : 'W',
- msgs[ret].addr, msgs[ret].len,
- (msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
- }
-#endif
-
- if (in_atomic() || irqs_disabled()) {
- ret = i2c_trylock_bus(adap, I2C_LOCK_SEGMENT);
- if (!ret)
- /* I2C activity is ongoing. */
- return -EAGAIN;
- } else {
- i2c_lock_bus(adap, I2C_LOCK_SEGMENT);
- }
-
- ret = __i2c_transfer(adap, msgs, num);
- i2c_unlock_bus(adap, I2C_LOCK_SEGMENT);
-
- return ret;
+ if (in_atomic() || irqs_disabled()) {
+ ret = i2c_trylock_bus(adap, I2C_LOCK_SEGMENT);
+ if (!ret)
+ /* I2C activity is ongoing. */
+ return -EAGAIN;
} else {
- dev_dbg(&adap->dev, "I2C level transfers not supported\n");
- return -EOPNOTSUPP;
+ i2c_lock_bus(adap, I2C_LOCK_SEGMENT);
}
+
+ ret = __i2c_transfer(adap, msgs, num);
+ i2c_unlock_bus(adap, I2C_LOCK_SEGMENT);
+
+ return ret;
}
EXPORT_SYMBOL(i2c_transfer);
@@ -2270,7 +2258,7 @@ EXPORT_SYMBOL(i2c_put_adapter);
*
* Return: NULL if a DMA safe buffer was not obtained. Use msg->buf with PIO.
* Or a valid pointer to be used with DMA. After use, release it by
- * calling i2c_release_dma_safe_msg_buf().
+ * calling i2c_put_dma_safe_msg_buf().
*
* This function must only be called from process context!
*/
diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c
index 401308e3d036..13882a2a4f60 100644
--- a/drivers/i2c/muxes/i2c-mux-gpio.c
+++ b/drivers/i2c/muxes/i2c-mux-gpio.c
@@ -22,18 +22,16 @@ struct gpiomux {
struct i2c_mux_gpio_platform_data data;
unsigned gpio_base;
struct gpio_desc **gpios;
- int *values;
};
static void i2c_mux_gpio_set(const struct gpiomux *mux, unsigned val)
{
- int i;
+ DECLARE_BITMAP(values, BITS_PER_TYPE(val));
- for (i = 0; i < mux->data.n_gpios; i++)
- mux->values[i] = (val >> i) & 1;
+ values[0] = val;
- gpiod_set_array_value_cansleep(mux->data.n_gpios,
- mux->gpios, mux->values);
+ gpiod_set_array_value_cansleep(mux->data.n_gpios, mux->gpios, NULL,
+ values);
}
static int i2c_mux_gpio_select(struct i2c_mux_core *muxc, u32 chan)
@@ -182,15 +180,13 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
return -EPROBE_DEFER;
muxc = i2c_mux_alloc(parent, &pdev->dev, mux->data.n_values,
- mux->data.n_gpios * sizeof(*mux->gpios) +
- mux->data.n_gpios * sizeof(*mux->values), 0,
+ mux->data.n_gpios * sizeof(*mux->gpios), 0,
i2c_mux_gpio_select, NULL);
if (!muxc) {
ret = -ENOMEM;
goto alloc_failed;
}
mux->gpios = muxc->priv;
- mux->values = (int *)(mux->gpios + mux->data.n_gpios);
muxc->priv = mux;
platform_set_drvdata(pdev, muxc);
diff --git a/drivers/i2c/muxes/i2c-mux-gpmux.c b/drivers/i2c/muxes/i2c-mux-gpmux.c
index 92cf5f48afe6..f60b670deff7 100644
--- a/drivers/i2c/muxes/i2c-mux-gpmux.c
+++ b/drivers/i2c/muxes/i2c-mux-gpmux.c
@@ -120,8 +120,8 @@ static int i2c_mux_probe(struct platform_device *pdev)
ret = of_property_read_u32(child, "reg", &chan);
if (ret < 0) {
- dev_err(dev, "no reg property for node '%s'\n",
- child->name);
+ dev_err(dev, "no reg property for node '%pOFn'\n",
+ child);
goto err_children;
}
diff --git a/drivers/i2c/muxes/i2c-mux-ltc4306.c b/drivers/i2c/muxes/i2c-mux-ltc4306.c
index a9af93259b19..83a714605cd6 100644
--- a/drivers/i2c/muxes/i2c-mux-ltc4306.c
+++ b/drivers/i2c/muxes/i2c-mux-ltc4306.c
@@ -208,7 +208,7 @@ MODULE_DEVICE_TABLE(of, ltc4306_of_match);
static int ltc4306_probe(struct i2c_client *client)
{
- struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
+ struct i2c_adapter *adap = client->adapter;
const struct chip_desc *chip;
struct i2c_mux_core *muxc;
struct ltc4306 *data;
diff --git a/drivers/i2c/muxes/i2c-mux-mlxcpld.c b/drivers/i2c/muxes/i2c-mux-mlxcpld.c
index f2bf3e57ed67..5ed55ca4fe93 100644
--- a/drivers/i2c/muxes/i2c-mux-mlxcpld.c
+++ b/drivers/i2c/muxes/i2c-mux-mlxcpld.c
@@ -132,7 +132,7 @@ static int mlxcpld_mux_deselect(struct i2c_mux_core *muxc, u32 chan)
static int mlxcpld_mux_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
+ struct i2c_adapter *adap = client->adapter;
struct mlxcpld_mux_plat_data *pdata = dev_get_platdata(&client->dev);
struct i2c_mux_core *muxc;
int num, force;
diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
index 24bd9275fde5..bfabf985e830 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -347,7 +347,7 @@ static void pca954x_cleanup(struct i2c_mux_core *muxc)
static int pca954x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
+ struct i2c_adapter *adap = client->adapter;
struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev);
struct device *dev = &client->dev;
struct device_node *np = dev->of_node;
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index 44a7a255ef74..f9b59d41813f 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -1784,7 +1784,7 @@ static int ide_cd_probe(ide_drive_t *drive)
ide_cd_read_toc(drive);
g->fops = &idecd_ops;
g->flags |= GENHD_FL_REMOVABLE | GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE;
- device_add_disk(&drive->gendev, g);
+ device_add_disk(&drive->gendev, g, NULL);
return 0;
out_free_disk:
diff --git a/drivers/ide/ide-gd.c b/drivers/ide/ide-gd.c
index e823394ed543..04e008e8f6f9 100644
--- a/drivers/ide/ide-gd.c
+++ b/drivers/ide/ide-gd.c
@@ -416,7 +416,7 @@ static int ide_gd_probe(ide_drive_t *drive)
if (drive->dev_flags & IDE_DFLAG_REMOVABLE)
g->flags = GENHD_FL_REMOVABLE;
g->fops = &ide_gd_ops;
- device_add_disk(&drive->gendev, g);
+ device_add_disk(&drive->gendev, g, NULL);
return 0;
out_free_disk:
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index b2ccce5fb071..8b5d85c91e9d 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -1066,46 +1066,43 @@ static const struct idle_cpu idle_cpu_dnv = {
.disable_promotion_to_c1e = true,
};
-#define ICPU(model, cpu) \
- { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&cpu }
-
static const struct x86_cpu_id intel_idle_ids[] __initconst = {
- ICPU(INTEL_FAM6_NEHALEM_EP, idle_cpu_nehalem),
- ICPU(INTEL_FAM6_NEHALEM, idle_cpu_nehalem),
- ICPU(INTEL_FAM6_NEHALEM_G, idle_cpu_nehalem),
- ICPU(INTEL_FAM6_WESTMERE, idle_cpu_nehalem),
- ICPU(INTEL_FAM6_WESTMERE_EP, idle_cpu_nehalem),
- ICPU(INTEL_FAM6_NEHALEM_EX, idle_cpu_nehalem),
- ICPU(INTEL_FAM6_ATOM_PINEVIEW, idle_cpu_atom),
- ICPU(INTEL_FAM6_ATOM_LINCROFT, idle_cpu_lincroft),
- ICPU(INTEL_FAM6_WESTMERE_EX, idle_cpu_nehalem),
- ICPU(INTEL_FAM6_SANDYBRIDGE, idle_cpu_snb),
- ICPU(INTEL_FAM6_SANDYBRIDGE_X, idle_cpu_snb),
- ICPU(INTEL_FAM6_ATOM_CEDARVIEW, idle_cpu_atom),
- ICPU(INTEL_FAM6_ATOM_SILVERMONT1, idle_cpu_byt),
- ICPU(INTEL_FAM6_ATOM_MERRIFIELD, idle_cpu_tangier),
- ICPU(INTEL_FAM6_ATOM_AIRMONT, idle_cpu_cht),
- ICPU(INTEL_FAM6_IVYBRIDGE, idle_cpu_ivb),
- ICPU(INTEL_FAM6_IVYBRIDGE_X, idle_cpu_ivt),
- ICPU(INTEL_FAM6_HASWELL_CORE, idle_cpu_hsw),
- ICPU(INTEL_FAM6_HASWELL_X, idle_cpu_hsw),
- ICPU(INTEL_FAM6_HASWELL_ULT, idle_cpu_hsw),
- ICPU(INTEL_FAM6_HASWELL_GT3E, idle_cpu_hsw),
- ICPU(INTEL_FAM6_ATOM_SILVERMONT2, idle_cpu_avn),
- ICPU(INTEL_FAM6_BROADWELL_CORE, idle_cpu_bdw),
- ICPU(INTEL_FAM6_BROADWELL_GT3E, idle_cpu_bdw),
- ICPU(INTEL_FAM6_BROADWELL_X, idle_cpu_bdw),
- ICPU(INTEL_FAM6_BROADWELL_XEON_D, idle_cpu_bdw),
- ICPU(INTEL_FAM6_SKYLAKE_MOBILE, idle_cpu_skl),
- ICPU(INTEL_FAM6_SKYLAKE_DESKTOP, idle_cpu_skl),
- ICPU(INTEL_FAM6_KABYLAKE_MOBILE, idle_cpu_skl),
- ICPU(INTEL_FAM6_KABYLAKE_DESKTOP, idle_cpu_skl),
- ICPU(INTEL_FAM6_SKYLAKE_X, idle_cpu_skx),
- ICPU(INTEL_FAM6_XEON_PHI_KNL, idle_cpu_knl),
- ICPU(INTEL_FAM6_XEON_PHI_KNM, idle_cpu_knl),
- ICPU(INTEL_FAM6_ATOM_GOLDMONT, idle_cpu_bxt),
- ICPU(INTEL_FAM6_ATOM_GEMINI_LAKE, idle_cpu_bxt),
- ICPU(INTEL_FAM6_ATOM_DENVERTON, idle_cpu_dnv),
+ INTEL_CPU_FAM6(NEHALEM_EP, idle_cpu_nehalem),
+ INTEL_CPU_FAM6(NEHALEM, idle_cpu_nehalem),
+ INTEL_CPU_FAM6(NEHALEM_G, idle_cpu_nehalem),
+ INTEL_CPU_FAM6(WESTMERE, idle_cpu_nehalem),
+ INTEL_CPU_FAM6(WESTMERE_EP, idle_cpu_nehalem),
+ INTEL_CPU_FAM6(NEHALEM_EX, idle_cpu_nehalem),
+ INTEL_CPU_FAM6(ATOM_BONNELL, idle_cpu_atom),
+ INTEL_CPU_FAM6(ATOM_BONNELL_MID, idle_cpu_lincroft),
+ INTEL_CPU_FAM6(WESTMERE_EX, idle_cpu_nehalem),
+ INTEL_CPU_FAM6(SANDYBRIDGE, idle_cpu_snb),
+ INTEL_CPU_FAM6(SANDYBRIDGE_X, idle_cpu_snb),
+ INTEL_CPU_FAM6(ATOM_SALTWELL, idle_cpu_atom),
+ INTEL_CPU_FAM6(ATOM_SILVERMONT, idle_cpu_byt),
+ INTEL_CPU_FAM6(ATOM_SILVERMONT_MID, idle_cpu_tangier),
+ INTEL_CPU_FAM6(ATOM_AIRMONT, idle_cpu_cht),
+ INTEL_CPU_FAM6(IVYBRIDGE, idle_cpu_ivb),
+ INTEL_CPU_FAM6(IVYBRIDGE_X, idle_cpu_ivt),
+ INTEL_CPU_FAM6(HASWELL_CORE, idle_cpu_hsw),
+ INTEL_CPU_FAM6(HASWELL_X, idle_cpu_hsw),
+ INTEL_CPU_FAM6(HASWELL_ULT, idle_cpu_hsw),
+ INTEL_CPU_FAM6(HASWELL_GT3E, idle_cpu_hsw),
+ INTEL_CPU_FAM6(ATOM_SILVERMONT_X, idle_cpu_avn),
+ INTEL_CPU_FAM6(BROADWELL_CORE, idle_cpu_bdw),
+ INTEL_CPU_FAM6(BROADWELL_GT3E, idle_cpu_bdw),
+ INTEL_CPU_FAM6(BROADWELL_X, idle_cpu_bdw),
+ INTEL_CPU_FAM6(BROADWELL_XEON_D, idle_cpu_bdw),
+ INTEL_CPU_FAM6(SKYLAKE_MOBILE, idle_cpu_skl),
+ INTEL_CPU_FAM6(SKYLAKE_DESKTOP, idle_cpu_skl),
+ INTEL_CPU_FAM6(KABYLAKE_MOBILE, idle_cpu_skl),
+ INTEL_CPU_FAM6(KABYLAKE_DESKTOP, idle_cpu_skl),
+ INTEL_CPU_FAM6(SKYLAKE_X, idle_cpu_skx),
+ INTEL_CPU_FAM6(XEON_PHI_KNL, idle_cpu_knl),
+ INTEL_CPU_FAM6(XEON_PHI_KNM, idle_cpu_knl),
+ INTEL_CPU_FAM6(ATOM_GOLDMONT, idle_cpu_bxt),
+ INTEL_CPU_FAM6(ATOM_GOLDMONT_PLUS, idle_cpu_bxt),
+ INTEL_CPU_FAM6(ATOM_GOLDMONT_X, idle_cpu_dnv),
{}
};
@@ -1322,7 +1319,7 @@ static void intel_idle_state_table_update(void)
ivt_idle_state_table_update();
break;
case INTEL_FAM6_ATOM_GOLDMONT:
- case INTEL_FAM6_ATOM_GEMINI_LAKE:
+ case INTEL_FAM6_ATOM_GOLDMONT_PLUS:
bxt_idle_state_table_update();
break;
case INTEL_FAM6_SKYLAKE_DESKTOP:
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index 829dc96c9dd6..7993a67bd351 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -60,6 +60,33 @@ config ADXL345_SPI
will be called adxl345_spi and you will also get adxl345_core
for the core module.
+config ADXL372
+ tristate
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+
+config ADXL372_SPI
+ tristate "Analog Devices ADXL372 3-Axis Accelerometer SPI Driver"
+ depends on SPI
+ select ADXL372
+ select REGMAP_SPI
+ help
+ Say yes here to add support for the Analog Devices ADXL372 triaxial
+ acceleration sensor.
+ To compile this driver as a module, choose M here: the
+ module will be called adxl372_spi.
+
+config ADXL372_I2C
+ tristate "Analog Devices ADXL372 3-Axis Accelerometer I2C Driver"
+ depends on I2C
+ select ADXL372
+ select REGMAP_I2C
+ help
+ Say yes here to add support for the Analog Devices ADXL372 triaxial
+ acceleration sensor.
+ To compile this driver as a module, choose M here: the
+ module will be called adxl372_i2c.
+
config BMA180
tristate "Bosch BMA180/BMA250 3-Axis Accelerometer Driver"
depends on I2C
diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile
index 636d4d1b2990..56bd0215e0d4 100644
--- a/drivers/iio/accel/Makefile
+++ b/drivers/iio/accel/Makefile
@@ -9,6 +9,9 @@ obj-$(CONFIG_ADIS16209) += adis16209.o
obj-$(CONFIG_ADXL345) += adxl345_core.o
obj-$(CONFIG_ADXL345_I2C) += adxl345_i2c.o
obj-$(CONFIG_ADXL345_SPI) += adxl345_spi.o
+obj-$(CONFIG_ADXL372) += adxl372.o
+obj-$(CONFIG_ADXL372_I2C) += adxl372_i2c.o
+obj-$(CONFIG_ADXL372_SPI) += adxl372_spi.o
obj-$(CONFIG_BMA180) += bma180.o
obj-$(CONFIG_BMA220) += bma220_spi.o
obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel-core.o
diff --git a/drivers/iio/accel/adxl345_i2c.c b/drivers/iio/accel/adxl345_i2c.c
index 785c89de91e7..f22f71315a0c 100644
--- a/drivers/iio/accel/adxl345_i2c.c
+++ b/drivers/iio/accel/adxl345_i2c.c
@@ -27,6 +27,9 @@ static int adxl345_i2c_probe(struct i2c_client *client,
{
struct regmap *regmap;
+ if (!id)
+ return -ENODEV;
+
regmap = devm_regmap_init_i2c(client, &adxl345_i2c_regmap_config);
if (IS_ERR(regmap)) {
dev_err(&client->dev, "Error initializing i2c regmap: %ld\n",
@@ -35,7 +38,7 @@ static int adxl345_i2c_probe(struct i2c_client *client,
}
return adxl345_core_probe(&client->dev, regmap, id->driver_data,
- id ? id->name : NULL);
+ id->name);
}
static int adxl345_i2c_remove(struct i2c_client *client)
diff --git a/drivers/iio/accel/adxl372.c b/drivers/iio/accel/adxl372.c
new file mode 100644
index 000000000000..3b84cb243a87
--- /dev/null
+++ b/drivers/iio/accel/adxl372.c
@@ -0,0 +1,975 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * ADXL372 3-Axis Digital Accelerometer core driver
+ *
+ * Copyright 2018 Analog Devices Inc.
+ */
+
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/events.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#include "adxl372.h"
+
+/* ADXL372 registers definition */
+#define ADXL372_DEVID 0x00
+#define ADXL372_DEVID_MST 0x01
+#define ADXL372_PARTID 0x02
+#define ADXL372_STATUS_1 0x04
+#define ADXL372_STATUS_2 0x05
+#define ADXL372_FIFO_ENTRIES_2 0x06
+#define ADXL372_FIFO_ENTRIES_1 0x07
+#define ADXL372_X_DATA_H 0x08
+#define ADXL372_X_DATA_L 0x09
+#define ADXL372_Y_DATA_H 0x0A
+#define ADXL372_Y_DATA_L 0x0B
+#define ADXL372_Z_DATA_H 0x0C
+#define ADXL372_Z_DATA_L 0x0D
+#define ADXL372_X_MAXPEAK_H 0x15
+#define ADXL372_X_MAXPEAK_L 0x16
+#define ADXL372_Y_MAXPEAK_H 0x17
+#define ADXL372_Y_MAXPEAK_L 0x18
+#define ADXL372_Z_MAXPEAK_H 0x19
+#define ADXL372_Z_MAXPEAK_L 0x1A
+#define ADXL372_OFFSET_X 0x20
+#define ADXL372_OFFSET_Y 0x21
+#define ADXL372_OFFSET_Z 0x22
+#define ADXL372_X_THRESH_ACT_H 0x23
+#define ADXL372_X_THRESH_ACT_L 0x24
+#define ADXL372_Y_THRESH_ACT_H 0x25
+#define ADXL372_Y_THRESH_ACT_L 0x26
+#define ADXL372_Z_THRESH_ACT_H 0x27
+#define ADXL372_Z_THRESH_ACT_L 0x28
+#define ADXL372_TIME_ACT 0x29
+#define ADXL372_X_THRESH_INACT_H 0x2A
+#define ADXL372_X_THRESH_INACT_L 0x2B
+#define ADXL372_Y_THRESH_INACT_H 0x2C
+#define ADXL372_Y_THRESH_INACT_L 0x2D
+#define ADXL372_Z_THRESH_INACT_H 0x2E
+#define ADXL372_Z_THRESH_INACT_L 0x2F
+#define ADXL372_TIME_INACT_H 0x30
+#define ADXL372_TIME_INACT_L 0x31
+#define ADXL372_X_THRESH_ACT2_H 0x32
+#define ADXL372_X_THRESH_ACT2_L 0x33
+#define ADXL372_Y_THRESH_ACT2_H 0x34
+#define ADXL372_Y_THRESH_ACT2_L 0x35
+#define ADXL372_Z_THRESH_ACT2_H 0x36
+#define ADXL372_Z_THRESH_ACT2_L 0x37
+#define ADXL372_HPF 0x38
+#define ADXL372_FIFO_SAMPLES 0x39
+#define ADXL372_FIFO_CTL 0x3A
+#define ADXL372_INT1_MAP 0x3B
+#define ADXL372_INT2_MAP 0x3C
+#define ADXL372_TIMING 0x3D
+#define ADXL372_MEASURE 0x3E
+#define ADXL372_POWER_CTL 0x3F
+#define ADXL372_SELF_TEST 0x40
+#define ADXL372_RESET 0x41
+#define ADXL372_FIFO_DATA 0x42
+
+#define ADXL372_DEVID_VAL 0xAD
+#define ADXL372_PARTID_VAL 0xFA
+#define ADXL372_RESET_CODE 0x52
+
+/* ADXL372_POWER_CTL */
+#define ADXL372_POWER_CTL_MODE_MSK GENMASK_ULL(1, 0)
+#define ADXL372_POWER_CTL_MODE(x) (((x) & 0x3) << 0)
+
+/* ADXL372_MEASURE */
+#define ADXL372_MEASURE_LINKLOOP_MSK GENMASK_ULL(5, 4)
+#define ADXL372_MEASURE_LINKLOOP_MODE(x) (((x) & 0x3) << 4)
+#define ADXL372_MEASURE_BANDWIDTH_MSK GENMASK_ULL(2, 0)
+#define ADXL372_MEASURE_BANDWIDTH_MODE(x) (((x) & 0x7) << 0)
+
+/* ADXL372_TIMING */
+#define ADXL372_TIMING_ODR_MSK GENMASK_ULL(7, 5)
+#define ADXL372_TIMING_ODR_MODE(x) (((x) & 0x7) << 5)
+
+/* ADXL372_FIFO_CTL */
+#define ADXL372_FIFO_CTL_FORMAT_MSK GENMASK(5, 3)
+#define ADXL372_FIFO_CTL_FORMAT_MODE(x) (((x) & 0x7) << 3)
+#define ADXL372_FIFO_CTL_MODE_MSK GENMASK(2, 1)
+#define ADXL372_FIFO_CTL_MODE_MODE(x) (((x) & 0x3) << 1)
+#define ADXL372_FIFO_CTL_SAMPLES_MSK BIT(1)
+#define ADXL372_FIFO_CTL_SAMPLES_MODE(x) (((x) > 0xFF) ? 1 : 0)
+
+/* ADXL372_STATUS_1 */
+#define ADXL372_STATUS_1_DATA_RDY(x) (((x) >> 0) & 0x1)
+#define ADXL372_STATUS_1_FIFO_RDY(x) (((x) >> 1) & 0x1)
+#define ADXL372_STATUS_1_FIFO_FULL(x) (((x) >> 2) & 0x1)
+#define ADXL372_STATUS_1_FIFO_OVR(x) (((x) >> 3) & 0x1)
+#define ADXL372_STATUS_1_USR_NVM_BUSY(x) (((x) >> 5) & 0x1)
+#define ADXL372_STATUS_1_AWAKE(x) (((x) >> 6) & 0x1)
+#define ADXL372_STATUS_1_ERR_USR_REGS(x) (((x) >> 7) & 0x1)
+
+/* ADXL372_INT1_MAP */
+#define ADXL372_INT1_MAP_DATA_RDY_MSK BIT(0)
+#define ADXL372_INT1_MAP_DATA_RDY_MODE(x) (((x) & 0x1) << 0)
+#define ADXL372_INT1_MAP_FIFO_RDY_MSK BIT(1)
+#define ADXL372_INT1_MAP_FIFO_RDY_MODE(x) (((x) & 0x1) << 1)
+#define ADXL372_INT1_MAP_FIFO_FULL_MSK BIT(2)
+#define ADXL372_INT1_MAP_FIFO_FULL_MODE(x) (((x) & 0x1) << 2)
+#define ADXL372_INT1_MAP_FIFO_OVR_MSK BIT(3)
+#define ADXL372_INT1_MAP_FIFO_OVR_MODE(x) (((x) & 0x1) << 3)
+#define ADXL372_INT1_MAP_INACT_MSK BIT(4)
+#define ADXL372_INT1_MAP_INACT_MODE(x) (((x) & 0x1) << 4)
+#define ADXL372_INT1_MAP_ACT_MSK BIT(5)
+#define ADXL372_INT1_MAP_ACT_MODE(x) (((x) & 0x1) << 5)
+#define ADXL372_INT1_MAP_AWAKE_MSK BIT(6)
+#define ADXL372_INT1_MAP_AWAKE_MODE(x) (((x) & 0x1) << 6)
+#define ADXL372_INT1_MAP_LOW_MSK BIT(7)
+#define ADXL372_INT1_MAP_LOW_MODE(x) (((x) & 0x1) << 7)
+
+/* The ADXL372 includes a deep, 512 sample FIFO buffer */
+#define ADXL372_FIFO_SIZE 512
+
+/*
+ * At +/- 200g with 12-bit resolution, scale is computed as:
+ * (200 + 200) * 9.81 / (2^12 - 1) = 0.958241
+ */
+#define ADXL372_USCALE 958241
+
+enum adxl372_op_mode {
+ ADXL372_STANDBY,
+ ADXL372_WAKE_UP,
+ ADXL372_INSTANT_ON,
+ ADXL372_FULL_BW_MEASUREMENT,
+};
+
+enum adxl372_act_proc_mode {
+ ADXL372_DEFAULT,
+ ADXL372_LINKED,
+ ADXL372_LOOPED,
+};
+
+enum adxl372_th_activity {
+ ADXL372_ACTIVITY,
+ ADXL372_ACTIVITY2,
+ ADXL372_INACTIVITY,
+};
+
+enum adxl372_odr {
+ ADXL372_ODR_400HZ,
+ ADXL372_ODR_800HZ,
+ ADXL372_ODR_1600HZ,
+ ADXL372_ODR_3200HZ,
+ ADXL372_ODR_6400HZ,
+};
+
+enum adxl372_bandwidth {
+ ADXL372_BW_200HZ,
+ ADXL372_BW_400HZ,
+ ADXL372_BW_800HZ,
+ ADXL372_BW_1600HZ,
+ ADXL372_BW_3200HZ,
+};
+
+static const unsigned int adxl372_th_reg_high_addr[3] = {
+ [ADXL372_ACTIVITY] = ADXL372_X_THRESH_ACT_H,
+ [ADXL372_ACTIVITY2] = ADXL372_X_THRESH_ACT2_H,
+ [ADXL372_INACTIVITY] = ADXL372_X_THRESH_INACT_H,
+};
+
+enum adxl372_fifo_format {
+ ADXL372_XYZ_FIFO,
+ ADXL372_X_FIFO,
+ ADXL372_Y_FIFO,
+ ADXL372_XY_FIFO,
+ ADXL372_Z_FIFO,
+ ADXL372_XZ_FIFO,
+ ADXL372_YZ_FIFO,
+ ADXL372_XYZ_PEAK_FIFO,
+};
+
+enum adxl372_fifo_mode {
+ ADXL372_FIFO_BYPASSED,
+ ADXL372_FIFO_STREAMED,
+ ADXL372_FIFO_TRIGGERED,
+ ADXL372_FIFO_OLD_SAVED
+};
+
+static const int adxl372_samp_freq_tbl[5] = {
+ 400, 800, 1600, 3200, 6400,
+};
+
+static const int adxl372_bw_freq_tbl[5] = {
+ 200, 400, 800, 1600, 3200,
+};
+
+struct adxl372_axis_lookup {
+ unsigned int bits;
+ enum adxl372_fifo_format fifo_format;
+};
+
+static const struct adxl372_axis_lookup adxl372_axis_lookup_table[] = {
+ { BIT(0), ADXL372_X_FIFO },
+ { BIT(1), ADXL372_Y_FIFO },
+ { BIT(2), ADXL372_Z_FIFO },
+ { BIT(0) | BIT(1), ADXL372_XY_FIFO },
+ { BIT(0) | BIT(2), ADXL372_XZ_FIFO },
+ { BIT(1) | BIT(2), ADXL372_YZ_FIFO },
+ { BIT(0) | BIT(1) | BIT(2), ADXL372_XYZ_FIFO },
+};
+
+#define ADXL372_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_SAMP_FREQ) | \
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
+ .scan_index = index, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 12, \
+ .storagebits = 16, \
+ .shift = 4, \
+ }, \
+}
+
+static const struct iio_chan_spec adxl372_channels[] = {
+ ADXL372_ACCEL_CHANNEL(0, ADXL372_X_DATA_H, X),
+ ADXL372_ACCEL_CHANNEL(1, ADXL372_Y_DATA_H, Y),
+ ADXL372_ACCEL_CHANNEL(2, ADXL372_Z_DATA_H, Z),
+};
+
+struct adxl372_state {
+ int irq;
+ struct device *dev;
+ struct regmap *regmap;
+ struct iio_trigger *dready_trig;
+ enum adxl372_fifo_mode fifo_mode;
+ enum adxl372_fifo_format fifo_format;
+ enum adxl372_op_mode op_mode;
+ enum adxl372_act_proc_mode act_proc_mode;
+ enum adxl372_odr odr;
+ enum adxl372_bandwidth bw;
+ u32 act_time_ms;
+ u32 inact_time_ms;
+ u8 fifo_set_size;
+ u8 int1_bitmask;
+ u8 int2_bitmask;
+ u16 watermark;
+ __be16 fifo_buf[ADXL372_FIFO_SIZE];
+};
+
+static const unsigned long adxl372_channel_masks[] = {
+ BIT(0), BIT(1), BIT(2),
+ BIT(0) | BIT(1),
+ BIT(0) | BIT(2),
+ BIT(1) | BIT(2),
+ BIT(0) | BIT(1) | BIT(2),
+ 0
+};
+
+static int adxl372_read_axis(struct adxl372_state *st, u8 addr)
+{
+ __be16 regval;
+ int ret;
+
+ ret = regmap_bulk_read(st->regmap, addr, &regval, sizeof(regval));
+ if (ret < 0)
+ return ret;
+
+ return be16_to_cpu(regval);
+}
+
+static int adxl372_set_op_mode(struct adxl372_state *st,
+ enum adxl372_op_mode op_mode)
+{
+ int ret;
+
+ ret = regmap_update_bits(st->regmap, ADXL372_POWER_CTL,
+ ADXL372_POWER_CTL_MODE_MSK,
+ ADXL372_POWER_CTL_MODE(op_mode));
+ if (ret < 0)
+ return ret;
+
+ st->op_mode = op_mode;
+
+ return ret;
+}
+
+static int adxl372_set_odr(struct adxl372_state *st,
+ enum adxl372_odr odr)
+{
+ int ret;
+
+ ret = regmap_update_bits(st->regmap, ADXL372_TIMING,
+ ADXL372_TIMING_ODR_MSK,
+ ADXL372_TIMING_ODR_MODE(odr));
+ if (ret < 0)
+ return ret;
+
+ st->odr = odr;
+
+ return ret;
+}
+
+static int adxl372_find_closest_match(const int *array,
+ unsigned int size, int val)
+{
+ int i;
+
+ for (i = 0; i < size; i++) {
+ if (val <= array[i])
+ return i;
+ }
+
+ return size - 1;
+}
+
+static int adxl372_set_bandwidth(struct adxl372_state *st,
+ enum adxl372_bandwidth bw)
+{
+ int ret;
+
+ ret = regmap_update_bits(st->regmap, ADXL372_MEASURE,
+ ADXL372_MEASURE_BANDWIDTH_MSK,
+ ADXL372_MEASURE_BANDWIDTH_MODE(bw));
+ if (ret < 0)
+ return ret;
+
+ st->bw = bw;
+
+ return ret;
+}
+
+static int adxl372_set_act_proc_mode(struct adxl372_state *st,
+ enum adxl372_act_proc_mode mode)
+{
+ int ret;
+
+ ret = regmap_update_bits(st->regmap,
+ ADXL372_MEASURE,
+ ADXL372_MEASURE_LINKLOOP_MSK,
+ ADXL372_MEASURE_LINKLOOP_MODE(mode));
+ if (ret < 0)
+ return ret;
+
+ st->act_proc_mode = mode;
+
+ return ret;
+}
+
+static int adxl372_set_activity_threshold(struct adxl372_state *st,
+ enum adxl372_th_activity act,
+ bool ref_en, bool enable,
+ unsigned int threshold)
+{
+ unsigned char buf[6];
+ unsigned char th_reg_high_val, th_reg_low_val, th_reg_high_addr;
+
+ /* scale factor is 100 mg/code */
+ th_reg_high_val = (threshold / 100) >> 3;
+ th_reg_low_val = ((threshold / 100) << 5) | (ref_en << 1) | enable;
+ th_reg_high_addr = adxl372_th_reg_high_addr[act];
+
+ buf[0] = th_reg_high_val;
+ buf[1] = th_reg_low_val;
+ buf[2] = th_reg_high_val;
+ buf[3] = th_reg_low_val;
+ buf[4] = th_reg_high_val;
+ buf[5] = th_reg_low_val;
+
+ return regmap_bulk_write(st->regmap, th_reg_high_addr,
+ buf, ARRAY_SIZE(buf));
+}
+
+static int adxl372_set_activity_time_ms(struct adxl372_state *st,
+ unsigned int act_time_ms)
+{
+ unsigned int reg_val, scale_factor;
+ int ret;
+
+ /*
+ * 3.3 ms per code is the scale factor of the TIME_ACT register for
+ * ODR = 6400 Hz. It is 6.6 ms per code for ODR = 3200 Hz and below.
+ */
+ if (st->odr == ADXL372_ODR_6400HZ)
+ scale_factor = 3300;
+ else
+ scale_factor = 6600;
+
+ reg_val = DIV_ROUND_CLOSEST(act_time_ms * 1000, scale_factor);
+
+ /* TIME_ACT register is 8 bits wide */
+ if (reg_val > 0xFF)
+ reg_val = 0xFF;
+
+ ret = regmap_write(st->regmap, ADXL372_TIME_ACT, reg_val);
+ if (ret < 0)
+ return ret;
+
+ st->act_time_ms = act_time_ms;
+
+ return ret;
+}
+
+static int adxl372_set_inactivity_time_ms(struct adxl372_state *st,
+ unsigned int inact_time_ms)
+{
+ unsigned int reg_val_h, reg_val_l, res, scale_factor;
+ int ret;
+
+ /*
+ * 13 ms per code is the scale factor of the TIME_INACT register for
+ * ODR = 6400 Hz. It is 26 ms per code for ODR = 3200 Hz and below.
+ */
+ if (st->odr == ADXL372_ODR_6400HZ)
+ scale_factor = 13;
+ else
+ scale_factor = 26;
+
+ res = DIV_ROUND_CLOSEST(inact_time_ms, scale_factor);
+ reg_val_h = (res >> 8) & 0xFF;
+ reg_val_l = res & 0xFF;
+
+ ret = regmap_write(st->regmap, ADXL372_TIME_INACT_H, reg_val_h);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_write(st->regmap, ADXL372_TIME_INACT_L, reg_val_l);
+ if (ret < 0)
+ return ret;
+
+ st->inact_time_ms = inact_time_ms;
+
+ return ret;
+}
+
+static int adxl372_set_interrupts(struct adxl372_state *st,
+ unsigned char int1_bitmask,
+ unsigned char int2_bitmask)
+{
+ int ret;
+
+ ret = regmap_write(st->regmap, ADXL372_INT1_MAP, int1_bitmask);
+ if (ret < 0)
+ return ret;
+
+ return regmap_write(st->regmap, ADXL372_INT2_MAP, int2_bitmask);
+}
+
+static int adxl372_configure_fifo(struct adxl372_state *st)
+{
+ unsigned int fifo_samples, fifo_ctl;
+ int ret;
+
+ /* FIFO must be configured while in standby mode */
+ ret = adxl372_set_op_mode(st, ADXL372_STANDBY);
+ if (ret < 0)
+ return ret;
+
+ fifo_samples = st->watermark & 0xFF;
+ fifo_ctl = ADXL372_FIFO_CTL_FORMAT_MODE(st->fifo_format) |
+ ADXL372_FIFO_CTL_MODE_MODE(st->fifo_mode) |
+ ADXL372_FIFO_CTL_SAMPLES_MODE(st->watermark);
+
+ ret = regmap_write(st->regmap, ADXL372_FIFO_SAMPLES, fifo_samples);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_write(st->regmap, ADXL372_FIFO_CTL, fifo_ctl);
+ if (ret < 0)
+ return ret;
+
+ return adxl372_set_op_mode(st, ADXL372_FULL_BW_MEASUREMENT);
+}
+
+static int adxl372_get_status(struct adxl372_state *st,
+ u8 *status1, u8 *status2,
+ u16 *fifo_entries)
+{
+ __be32 buf;
+ u32 val;
+ int ret;
+
+ /* STATUS1, STATUS2, FIFO_ENTRIES2 and FIFO_ENTRIES are adjacent regs */
+ ret = regmap_bulk_read(st->regmap, ADXL372_STATUS_1,
+ &buf, sizeof(buf));
+ if (ret < 0)
+ return ret;
+
+ val = be32_to_cpu(buf);
+
+ *status1 = (val >> 24) & 0x0F;
+ *status2 = (val >> 16) & 0x0F;
+ /*
+ * FIFO_ENTRIES contains the least significant byte, and FIFO_ENTRIES2
+ * contains the two most significant bits
+ */
+ *fifo_entries = val & 0x3FF;
+
+ return ret;
+}
+
+static irqreturn_t adxl372_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct adxl372_state *st = iio_priv(indio_dev);
+ u8 status1, status2;
+ u16 fifo_entries;
+ int i, ret;
+
+ ret = adxl372_get_status(st, &status1, &status2, &fifo_entries);
+ if (ret < 0)
+ goto err;
+
+ if (st->fifo_mode != ADXL372_FIFO_BYPASSED &&
+ ADXL372_STATUS_1_FIFO_FULL(status1)) {
+ /*
+ * When reading data from multiple axes from the FIFO,
+ * to ensure that data is not overwritten and stored out
+ * of order at least one sample set must be left in the
+ * FIFO after every read.
+ */
+ fifo_entries -= st->fifo_set_size;
+
+ /* Read data from the FIFO */
+ ret = regmap_noinc_read(st->regmap, ADXL372_FIFO_DATA,
+ st->fifo_buf,
+ fifo_entries * sizeof(u16));
+ if (ret < 0)
+ goto err;
+
+ /* Each sample is 2 bytes */
+ for (i = 0; i < fifo_entries * sizeof(u16);
+ i += st->fifo_set_size * sizeof(u16))
+ iio_push_to_buffers(indio_dev, &st->fifo_buf[i]);
+ }
+err:
+ iio_trigger_notify_done(indio_dev->trig);
+ return IRQ_HANDLED;
+}
+
+static int adxl372_setup(struct adxl372_state *st)
+{
+ unsigned int regval;
+ int ret;
+
+ ret = regmap_read(st->regmap, ADXL372_DEVID, &regval);
+ if (ret < 0)
+ return ret;
+
+ if (regval != ADXL372_DEVID_VAL) {
+ dev_err(st->dev, "Invalid chip id %x\n", regval);
+ return -ENODEV;
+ }
+
+ ret = adxl372_set_op_mode(st, ADXL372_STANDBY);
+ if (ret < 0)
+ return ret;
+
+ /* Set threshold for activity detection to 1g */
+ ret = adxl372_set_activity_threshold(st, ADXL372_ACTIVITY,
+ true, true, 1000);
+ if (ret < 0)
+ return ret;
+
+ /* Set threshold for inactivity detection to 100mg */
+ ret = adxl372_set_activity_threshold(st, ADXL372_INACTIVITY,
+ true, true, 100);
+ if (ret < 0)
+ return ret;
+
+ /* Set activity processing in Looped mode */
+ ret = adxl372_set_act_proc_mode(st, ADXL372_LOOPED);
+ if (ret < 0)
+ return ret;
+
+ ret = adxl372_set_odr(st, ADXL372_ODR_6400HZ);
+ if (ret < 0)
+ return ret;
+
+ ret = adxl372_set_bandwidth(st, ADXL372_BW_3200HZ);
+ if (ret < 0)
+ return ret;
+
+ /* Set activity timer to 1ms */
+ ret = adxl372_set_activity_time_ms(st, 1);
+ if (ret < 0)
+ return ret;
+
+ /* Set inactivity timer to 10s */
+ ret = adxl372_set_inactivity_time_ms(st, 10000);
+ if (ret < 0)
+ return ret;
+
+ /* Set the mode of operation to full bandwidth measurement mode */
+ return adxl372_set_op_mode(st, ADXL372_FULL_BW_MEASUREMENT);
+}
+
+static int adxl372_reg_access(struct iio_dev *indio_dev,
+ unsigned int reg,
+ unsigned int writeval,
+ unsigned int *readval)
+{
+ struct adxl372_state *st = iio_priv(indio_dev);
+
+ if (readval)
+ return regmap_read(st->regmap, reg, readval);
+ else
+ return regmap_write(st->regmap, reg, writeval);
+}
+
+static int adxl372_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long info)
+{
+ struct adxl372_state *st = iio_priv(indio_dev);
+ int ret;
+
+ switch (info) {
+ case IIO_CHAN_INFO_RAW:
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
+
+ ret = adxl372_read_axis(st, chan->address);
+ iio_device_release_direct_mode(indio_dev);
+ if (ret < 0)
+ return ret;
+
+ *val = sign_extend32(ret >> chan->scan_type.shift,
+ chan->scan_type.realbits - 1);
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = 0;
+ *val2 = ADXL372_USCALE;
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *val = adxl372_samp_freq_tbl[st->odr];
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+ *val = adxl372_bw_freq_tbl[st->bw];
+ return IIO_VAL_INT;
+ }
+
+ return -EINVAL;
+}
+
+static int adxl372_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long info)
+{
+ struct adxl372_state *st = iio_priv(indio_dev);
+ int odr_index, bw_index, ret;
+
+ switch (info) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ odr_index = adxl372_find_closest_match(adxl372_samp_freq_tbl,
+ ARRAY_SIZE(adxl372_samp_freq_tbl),
+ val);
+ ret = adxl372_set_odr(st, odr_index);
+ if (ret < 0)
+ return ret;
+ /*
+ * The timer period depends on the ODR selected.
+ * At 3200 Hz and below, it is 6.6 ms; at 6400 Hz, it is 3.3 ms
+ */
+ ret = adxl372_set_activity_time_ms(st, st->act_time_ms);
+ if (ret < 0)
+ return ret;
+ /*
+ * The timer period depends on the ODR selected.
+ * At 3200 Hz and below, it is 26 ms; at 6400 Hz, it is 13 ms
+ */
+ ret = adxl372_set_inactivity_time_ms(st, st->inact_time_ms);
+ if (ret < 0)
+ return ret;
+ /*
+ * The maximum bandwidth is constrained to at most half of
+ * the ODR to ensure that the Nyquist criteria is not violated
+ */
+ if (st->bw > odr_index)
+ ret = adxl372_set_bandwidth(st, odr_index);
+
+ return ret;
+ case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+ bw_index = adxl372_find_closest_match(adxl372_bw_freq_tbl,
+ ARRAY_SIZE(adxl372_bw_freq_tbl),
+ val);
+ return adxl372_set_bandwidth(st, bw_index);
+ default:
+ return -EINVAL;
+ }
+}
+
+static ssize_t adxl372_show_filter_freq_avail(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct adxl372_state *st = iio_priv(indio_dev);
+ int i;
+ size_t len = 0;
+
+ for (i = 0; i <= st->odr; i++)
+ len += scnprintf(buf + len, PAGE_SIZE - len,
+ "%d ", adxl372_bw_freq_tbl[i]);
+
+ buf[len - 1] = '\n';
+
+ return len;
+}
+
+static ssize_t adxl372_get_fifo_enabled(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct adxl372_state *st = iio_priv(indio_dev);
+
+ return sprintf(buf, "%d\n", st->fifo_mode);
+}
+
+static ssize_t adxl372_get_fifo_watermark(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct adxl372_state *st = iio_priv(indio_dev);
+
+ return sprintf(buf, "%d\n", st->watermark);
+}
+
+static IIO_CONST_ATTR(hwfifo_watermark_min, "1");
+static IIO_CONST_ATTR(hwfifo_watermark_max,
+ __stringify(ADXL372_FIFO_SIZE));
+static IIO_DEVICE_ATTR(hwfifo_watermark, 0444,
+ adxl372_get_fifo_watermark, NULL, 0);
+static IIO_DEVICE_ATTR(hwfifo_enabled, 0444,
+ adxl372_get_fifo_enabled, NULL, 0);
+
+static const struct attribute *adxl372_fifo_attributes[] = {
+ &iio_const_attr_hwfifo_watermark_min.dev_attr.attr,
+ &iio_const_attr_hwfifo_watermark_max.dev_attr.attr,
+ &iio_dev_attr_hwfifo_watermark.dev_attr.attr,
+ &iio_dev_attr_hwfifo_enabled.dev_attr.attr,
+ NULL,
+};
+
+static int adxl372_set_watermark(struct iio_dev *indio_dev, unsigned int val)
+{
+ struct adxl372_state *st = iio_priv(indio_dev);
+
+ if (val > ADXL372_FIFO_SIZE)
+ val = ADXL372_FIFO_SIZE;
+
+ st->watermark = val;
+
+ return 0;
+}
+
+static int adxl372_buffer_postenable(struct iio_dev *indio_dev)
+{
+ struct adxl372_state *st = iio_priv(indio_dev);
+ unsigned int mask;
+ int i, ret;
+
+ ret = adxl372_set_interrupts(st, ADXL372_INT1_MAP_FIFO_FULL_MSK, 0);
+ if (ret < 0)
+ return ret;
+
+ mask = *indio_dev->active_scan_mask;
+
+ for (i = 0; i < ARRAY_SIZE(adxl372_axis_lookup_table); i++) {
+ if (mask == adxl372_axis_lookup_table[i].bits)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(adxl372_axis_lookup_table))
+ return -EINVAL;
+
+ st->fifo_format = adxl372_axis_lookup_table[i].fifo_format;
+ st->fifo_set_size = bitmap_weight(indio_dev->active_scan_mask,
+ indio_dev->masklength);
+ /*
+ * The 512 FIFO samples can be allotted in several ways, such as:
+ * 170 sample sets of concurrent 3-axis data
+ * 256 sample sets of concurrent 2-axis data (user selectable)
+ * 512 sample sets of single-axis data
+ */
+ if ((st->watermark * st->fifo_set_size) > ADXL372_FIFO_SIZE)
+ st->watermark = (ADXL372_FIFO_SIZE / st->fifo_set_size);
+
+ st->fifo_mode = ADXL372_FIFO_STREAMED;
+
+ ret = adxl372_configure_fifo(st);
+ if (ret < 0) {
+ st->fifo_mode = ADXL372_FIFO_BYPASSED;
+ adxl372_set_interrupts(st, 0, 0);
+ return ret;
+ }
+
+ return iio_triggered_buffer_postenable(indio_dev);
+}
+
+static int adxl372_buffer_predisable(struct iio_dev *indio_dev)
+{
+ struct adxl372_state *st = iio_priv(indio_dev);
+ int ret;
+
+ ret = iio_triggered_buffer_predisable(indio_dev);
+ if (ret < 0)
+ return ret;
+
+ adxl372_set_interrupts(st, 0, 0);
+ st->fifo_mode = ADXL372_FIFO_BYPASSED;
+ adxl372_configure_fifo(st);
+
+ return 0;
+}
+
+static const struct iio_buffer_setup_ops adxl372_buffer_ops = {
+ .postenable = adxl372_buffer_postenable,
+ .predisable = adxl372_buffer_predisable,
+};
+
+static int adxl372_dready_trig_set_state(struct iio_trigger *trig,
+ bool state)
+{
+ struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+ struct adxl372_state *st = iio_priv(indio_dev);
+ unsigned long int mask = 0;
+
+ if (state)
+ mask = ADXL372_INT1_MAP_FIFO_FULL_MSK;
+
+ return adxl372_set_interrupts(st, mask, 0);
+}
+
+static int adxl372_validate_trigger(struct iio_dev *indio_dev,
+ struct iio_trigger *trig)
+{
+ struct adxl372_state *st = iio_priv(indio_dev);
+
+ if (st->dready_trig != trig)
+ return -EINVAL;
+
+ return 0;
+}
+
+static const struct iio_trigger_ops adxl372_trigger_ops = {
+ .validate_device = &iio_trigger_validate_own_device,
+ .set_trigger_state = adxl372_dready_trig_set_state,
+};
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("400 800 1600 3200 6400");
+static IIO_DEVICE_ATTR(in_accel_filter_low_pass_3db_frequency_available,
+ 0444, adxl372_show_filter_freq_avail, NULL, 0);
+
+static struct attribute *adxl372_attributes[] = {
+ &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+ &iio_dev_attr_in_accel_filter_low_pass_3db_frequency_available.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group adxl372_attrs_group = {
+ .attrs = adxl372_attributes,
+};
+
+static const struct iio_info adxl372_info = {
+ .validate_trigger = &adxl372_validate_trigger,
+ .attrs = &adxl372_attrs_group,
+ .read_raw = adxl372_read_raw,
+ .write_raw = adxl372_write_raw,
+ .debugfs_reg_access = &adxl372_reg_access,
+ .hwfifo_set_watermark = adxl372_set_watermark,
+};
+
+bool adxl372_readable_noinc_reg(struct device *dev, unsigned int reg)
+{
+ return (reg == ADXL372_FIFO_DATA);
+}
+EXPORT_SYMBOL_GPL(adxl372_readable_noinc_reg);
+
+int adxl372_probe(struct device *dev, struct regmap *regmap,
+ int irq, const char *name)
+{
+ struct iio_dev *indio_dev;
+ struct adxl372_state *st;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+ dev_set_drvdata(dev, indio_dev);
+
+ st->dev = dev;
+ st->regmap = regmap;
+ st->irq = irq;
+
+ indio_dev->channels = adxl372_channels;
+ indio_dev->num_channels = ARRAY_SIZE(adxl372_channels);
+ indio_dev->available_scan_masks = adxl372_channel_masks;
+ indio_dev->dev.parent = dev;
+ indio_dev->name = name;
+ indio_dev->info = &adxl372_info;
+ indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
+
+ ret = adxl372_setup(st);
+ if (ret < 0) {
+ dev_err(dev, "ADXL372 setup failed\n");
+ return ret;
+ }
+
+ ret = devm_iio_triggered_buffer_setup(dev,
+ indio_dev, NULL,
+ adxl372_trigger_handler,
+ &adxl372_buffer_ops);
+ if (ret < 0)
+ return ret;
+
+ iio_buffer_set_attrs(indio_dev->buffer, adxl372_fifo_attributes);
+
+ if (st->irq) {
+ st->dready_trig = devm_iio_trigger_alloc(dev,
+ "%s-dev%d",
+ indio_dev->name,
+ indio_dev->id);
+ if (st->dready_trig == NULL)
+ return -ENOMEM;
+
+ st->dready_trig->ops = &adxl372_trigger_ops;
+ st->dready_trig->dev.parent = dev;
+ iio_trigger_set_drvdata(st->dready_trig, indio_dev);
+ ret = devm_iio_trigger_register(dev, st->dready_trig);
+ if (ret < 0)
+ return ret;
+
+ indio_dev->trig = iio_trigger_get(st->dready_trig);
+
+ ret = devm_request_threaded_irq(dev, st->irq,
+ iio_trigger_generic_data_rdy_poll,
+ NULL,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ indio_dev->name, st->dready_trig);
+ if (ret < 0)
+ return ret;
+ }
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+EXPORT_SYMBOL_GPL(adxl372_probe);
+
+MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>");
+MODULE_DESCRIPTION("Analog Devices ADXL372 3-axis accelerometer driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/accel/adxl372.h b/drivers/iio/accel/adxl372.h
new file mode 100644
index 000000000000..80a0aa9714fc
--- /dev/null
+++ b/drivers/iio/accel/adxl372.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * ADXL372 3-Axis Digital Accelerometer
+ *
+ * Copyright 2018 Analog Devices Inc.
+ */
+
+#ifndef _ADXL372_H_
+#define _ADXL372_H_
+
+#define ADXL372_REVID 0x03
+
+int adxl372_probe(struct device *dev, struct regmap *regmap,
+ int irq, const char *name);
+bool adxl372_readable_noinc_reg(struct device *dev, unsigned int reg);
+
+#endif /* _ADXL372_H_ */
diff --git a/drivers/iio/accel/adxl372_i2c.c b/drivers/iio/accel/adxl372_i2c.c
new file mode 100644
index 000000000000..e1affe480c77
--- /dev/null
+++ b/drivers/iio/accel/adxl372_i2c.c
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * ADXL372 3-Axis Digital Accelerometer I2C driver
+ *
+ * Copyright 2018 Analog Devices Inc.
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include "adxl372.h"
+
+static const struct regmap_config adxl372_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .readable_noinc_reg = adxl372_readable_noinc_reg,
+};
+
+static int adxl372_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct regmap *regmap;
+ unsigned int regval;
+ int ret;
+
+ regmap = devm_regmap_init_i2c(client, &adxl372_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ ret = regmap_read(regmap, ADXL372_REVID, &regval);
+ if (ret < 0)
+ return ret;
+
+ /* Starting with the 3rd revision an I2C chip bug was fixed */
+ if (regval < 3)
+ dev_warn(&client->dev,
+ "I2C might not work properly with other devices on the bus");
+
+ return adxl372_probe(&client->dev, regmap, client->irq, id->name);
+}
+
+static const struct i2c_device_id adxl372_i2c_id[] = {
+ { "adxl372", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, adxl372_i2c_id);
+
+static struct i2c_driver adxl372_i2c_driver = {
+ .driver = {
+ .name = "adxl372_i2c",
+ },
+ .probe = adxl372_i2c_probe,
+ .id_table = adxl372_i2c_id,
+};
+
+module_i2c_driver(adxl372_i2c_driver);
+
+MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>");
+MODULE_DESCRIPTION("Analog Devices ADXL372 3-axis accelerometer I2C driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/accel/adxl372_spi.c b/drivers/iio/accel/adxl372_spi.c
new file mode 100644
index 000000000000..e14e655ef165
--- /dev/null
+++ b/drivers/iio/accel/adxl372_spi.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * ADXL372 3-Axis Digital Accelerometer SPI driver
+ *
+ * Copyright 2018 Analog Devices Inc.
+ */
+
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+
+#include "adxl372.h"
+
+static const struct regmap_config adxl372_spi_regmap_config = {
+ .reg_bits = 7,
+ .pad_bits = 1,
+ .val_bits = 8,
+ .read_flag_mask = BIT(0),
+ .readable_noinc_reg = adxl372_readable_noinc_reg,
+};
+
+static int adxl372_spi_probe(struct spi_device *spi)
+{
+ const struct spi_device_id *id = spi_get_device_id(spi);
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init_spi(spi, &adxl372_spi_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return adxl372_probe(&spi->dev, regmap, spi->irq, id->name);
+}
+
+static const struct spi_device_id adxl372_spi_id[] = {
+ { "adxl372", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(spi, adxl372_spi_id);
+
+static struct spi_driver adxl372_spi_driver = {
+ .driver = {
+ .name = "adxl372_spi",
+ },
+ .probe = adxl372_spi_probe,
+ .id_table = adxl372_spi_id,
+};
+
+module_spi_driver(adxl372_spi_driver);
+
+MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>");
+MODULE_DESCRIPTION("Analog Devices ADXL372 3-axis accelerometer SPI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 4a754921fb6f..a52fea8749a9 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -501,6 +501,16 @@ config MCP3422
This driver can also be built as a module. If so, the module will be
called mcp3422.
+config MCP3911
+ tristate "Microchip Technology MCP3911 driver"
+ depends on SPI
+ help
+ Say yes here to build support for Microchip Technology's MCP3911
+ analog to digital converter.
+
+ This driver can also be built as a module. If so, the module will be
+ called mcp3911.
+
config MEDIATEK_MT6577_AUXADC
tristate "MediaTek AUXADC driver"
depends on ARCH_MEDIATEK || COMPILE_TEST
@@ -596,6 +606,26 @@ config QCOM_SPMI_VADC
To compile this driver as a module, choose M here: the module will
be called qcom-spmi-vadc.
+config QCOM_SPMI_ADC5
+ tristate "Qualcomm Technologies Inc. SPMI PMIC5 ADC"
+ depends on SPMI
+ select REGMAP_SPMI
+ select QCOM_VADC_COMMON
+ help
+ This is the IIO Voltage PMIC5 ADC driver for Qualcomm Technologies Inc.
+
+ The driver supports multiple channels read. The ADC is a 16-bit
+ sigma-delta ADC. The hardware supports calibrated results for
+ conversion requests and clients include reading voltage phone
+ power, on board system thermistors connected to the PMIC ADC,
+ PMIC die temperature, charger temperature, battery current, USB voltage
+ input, voltage signals connected to supported PMIC GPIO inputs. The
+ hardware supports internal pull-up for thermistors and can choose between
+ a 100k, 30k and 400k pull up using the ADC channels.
+
+ To compile this driver as a module, choose M here: the module will
+ be called qcom-spmi-adc5.
+
config RCAR_GYRO_ADC
tristate "Renesas R-Car GyroADC driver"
depends on ARCH_RCAR_GEN2 || COMPILE_TEST
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 03db7b578f9c..a6e6a0b659e2 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -47,12 +47,14 @@ obj-$(CONFIG_MAX1363) += max1363.o
obj-$(CONFIG_MAX9611) += max9611.o
obj-$(CONFIG_MCP320X) += mcp320x.o
obj-$(CONFIG_MCP3422) += mcp3422.o
+obj-$(CONFIG_MCP3911) += mcp3911.o
obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
obj-$(CONFIG_MESON_SARADC) += meson_saradc.o
obj-$(CONFIG_MXS_LRADC_ADC) += mxs-lradc-adc.o
obj-$(CONFIG_NAU7802) += nau7802.o
obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o
+obj-$(CONFIG_QCOM_SPMI_ADC5) += qcom-spmi-adc5.o
obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o
obj-$(CONFIG_QCOM_VADC_COMMON) += qcom-vadc-common.o
obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o
diff --git a/drivers/iio/adc/ad7298.c b/drivers/iio/adc/ad7298.c
index 2b20c6c8ec7f..e0220825fde0 100644
--- a/drivers/iio/adc/ad7298.c
+++ b/drivers/iio/adc/ad7298.c
@@ -385,6 +385,6 @@ static struct spi_driver ad7298_driver = {
};
module_spi_driver(ad7298_driver);
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7298 ADC");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c
index fbaae47746a8..0549686b9ef8 100644
--- a/drivers/iio/adc/ad7476.c
+++ b/drivers/iio/adc/ad7476.c
@@ -328,6 +328,6 @@ static struct spi_driver ad7476_driver = {
};
module_spi_driver(ad7476_driver);
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7476 and similar 1-channel ADCs");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/ad7793.c b/drivers/iio/adc/ad7793.c
index d4bbe5b53318..4ac3ae62f56f 100644
--- a/drivers/iio/adc/ad7793.c
+++ b/drivers/iio/adc/ad7793.c
@@ -822,6 +822,6 @@ static struct spi_driver ad7793_driver = {
};
module_spi_driver(ad7793_driver);
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7793 and similar ADCs");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/ad7887.c b/drivers/iio/adc/ad7887.c
index 205c0f1761aa..9d4c2467d362 100644
--- a/drivers/iio/adc/ad7887.c
+++ b/drivers/iio/adc/ad7887.c
@@ -362,6 +362,6 @@ static struct spi_driver ad7887_driver = {
};
module_spi_driver(ad7887_driver);
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7887 ADC");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/ad7923.c b/drivers/iio/adc/ad7923.c
index ffb7e089969c..d62dbb62be45 100644
--- a/drivers/iio/adc/ad7923.c
+++ b/drivers/iio/adc/ad7923.c
@@ -363,7 +363,7 @@ static struct spi_driver ad7923_driver = {
};
module_spi_driver(ad7923_driver);
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_AUTHOR("Patrick Vasseur <patrick.vasseur@c-s.fr>");
MODULE_DESCRIPTION("Analog Devices AD7904/AD7914/AD7923/AD7924 ADC");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c
index e1da67d5ee22..7a5b5d00a87d 100644
--- a/drivers/iio/adc/ad799x.c
+++ b/drivers/iio/adc/ad799x.c
@@ -892,6 +892,6 @@ static struct i2c_driver ad799x_driver = {
};
module_i2c_driver(ad799x_driver);
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD799x ADC");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index 44b516863c9d..75d2f73582a3 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -248,12 +248,14 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *idev = pf->indio_dev;
struct at91_adc_state *st = iio_priv(idev);
+ struct iio_chan_spec const *chan;
int i, j = 0;
for (i = 0; i < idev->masklength; i++) {
if (!test_bit(i, idev->active_scan_mask))
continue;
- st->buffer[j] = at91_adc_readl(st, AT91_ADC_CHAN(st, i));
+ chan = idev->channels + i;
+ st->buffer[j] = at91_adc_readl(st, AT91_ADC_CHAN(st, chan->channel));
j++;
}
@@ -279,6 +281,8 @@ static void handle_adc_eoc_trigger(int irq, struct iio_dev *idev)
iio_trigger_poll(idev->trig);
} else {
st->last_value = at91_adc_readl(st, AT91_ADC_CHAN(st, st->chnb));
+ /* Needed to ACK the DRDY interruption */
+ at91_adc_readl(st, AT91_ADC_LCDR);
st->done = true;
wake_up_interruptible(&st->wq_data_avail);
}
diff --git a/drivers/iio/adc/envelope-detector.c b/drivers/iio/adc/envelope-detector.c
index 4ebda8ab54fe..2f2b563c1162 100644
--- a/drivers/iio/adc/envelope-detector.c
+++ b/drivers/iio/adc/envelope-detector.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Driver for an envelope detector using a DAC and a comparator
*
* Copyright (C) 2016 Axentia Technologies AB
*
* Author: Peter Rosin <peda@axentia.se>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
/*
diff --git a/drivers/iio/adc/fsl-imx25-gcq.c b/drivers/iio/adc/fsl-imx25-gcq.c
index ea264fa9e567..929c617db364 100644
--- a/drivers/iio/adc/fsl-imx25-gcq.c
+++ b/drivers/iio/adc/fsl-imx25-gcq.c
@@ -209,12 +209,14 @@ static int mx25_gcq_setup_cfgs(struct platform_device *pdev,
ret = of_property_read_u32(child, "reg", &reg);
if (ret) {
dev_err(dev, "Failed to get reg property\n");
+ of_node_put(child);
return ret;
}
if (reg >= MX25_NUM_CFGS) {
dev_err(dev,
"reg value is greater than the number of available configuration registers\n");
+ of_node_put(child);
return -EINVAL;
}
@@ -228,6 +230,7 @@ static int mx25_gcq_setup_cfgs(struct platform_device *pdev,
if (IS_ERR(priv->vref[refp])) {
dev_err(dev, "Error, trying to use external voltage reference without a vref-%s regulator.",
mx25_gcq_refp_names[refp]);
+ of_node_put(child);
return PTR_ERR(priv->vref[refp]);
}
priv->channel_vref_mv[reg] =
@@ -240,6 +243,7 @@ static int mx25_gcq_setup_cfgs(struct platform_device *pdev,
break;
default:
dev_err(dev, "Invalid positive reference %d\n", refp);
+ of_node_put(child);
return -EINVAL;
}
@@ -254,10 +258,12 @@ static int mx25_gcq_setup_cfgs(struct platform_device *pdev,
if ((refp & MX25_ADCQ_CFG_REFP_MASK) != refp) {
dev_err(dev, "Invalid fsl,adc-refp property value\n");
+ of_node_put(child);
return -EINVAL;
}
if ((refn & MX25_ADCQ_CFG_REFN_MASK) != refn) {
dev_err(dev, "Invalid fsl,adc-refn property value\n");
+ of_node_put(child);
return -EINVAL;
}
diff --git a/drivers/iio/adc/max9611.c b/drivers/iio/adc/max9611.c
index 0538ff8c4ac1..643a4e66eb80 100644
--- a/drivers/iio/adc/max9611.c
+++ b/drivers/iio/adc/max9611.c
@@ -289,7 +289,7 @@ static int max9611_read_csa_voltage(struct max9611_dev *max9611,
return ret;
if (*adc_raw > 0) {
- *csa_gain = gain_selectors[i];
+ *csa_gain = (enum max9611_csa_gain)gain_selectors[i];
return 0;
}
}
diff --git a/drivers/iio/adc/mcp3911.c b/drivers/iio/adc/mcp3911.c
new file mode 100644
index 000000000000..dd52f08ec82e
--- /dev/null
+++ b/drivers/iio/adc/mcp3911.c
@@ -0,0 +1,363 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for Microchip MCP3911, Two-channel Analog Front End
+ *
+ * Copyright (C) 2018 Marcus Folkesson <marcus.folkesson@gmail.com>
+ * Copyright (C) 2018 Kent Gustavsson <kent@minoris.se>
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+
+#define MCP3911_REG_CHANNEL0 0x00
+#define MCP3911_REG_CHANNEL1 0x03
+#define MCP3911_REG_MOD 0x06
+#define MCP3911_REG_PHASE 0x07
+#define MCP3911_REG_GAIN 0x09
+
+#define MCP3911_REG_STATUSCOM 0x0a
+#define MCP3911_STATUSCOM_CH1_24WIDTH BIT(4)
+#define MCP3911_STATUSCOM_CH0_24WIDTH BIT(3)
+#define MCP3911_STATUSCOM_EN_OFFCAL BIT(2)
+#define MCP3911_STATUSCOM_EN_GAINCAL BIT(1)
+
+#define MCP3911_REG_CONFIG 0x0c
+#define MCP3911_CONFIG_CLKEXT BIT(1)
+#define MCP3911_CONFIG_VREFEXT BIT(2)
+
+#define MCP3911_REG_OFFCAL_CH0 0x0e
+#define MCP3911_REG_GAINCAL_CH0 0x11
+#define MCP3911_REG_OFFCAL_CH1 0x14
+#define MCP3911_REG_GAINCAL_CH1 0x17
+#define MCP3911_REG_VREFCAL 0x1a
+
+#define MCP3911_CHANNEL(x) (MCP3911_REG_CHANNEL0 + x * 3)
+#define MCP3911_OFFCAL(x) (MCP3911_REG_OFFCAL_CH0 + x * 6)
+
+/* Internal voltage reference in uV */
+#define MCP3911_INT_VREF_UV 1200000
+
+#define MCP3911_REG_READ(reg, id) ((((reg) << 1) | ((id) << 5) | (1 << 0)) & 0xff)
+#define MCP3911_REG_WRITE(reg, id) ((((reg) << 1) | ((id) << 5) | (0 << 0)) & 0xff)
+
+#define MCP3911_NUM_CHANNELS 2
+
+struct mcp3911 {
+ struct spi_device *spi;
+ struct mutex lock;
+ struct regulator *vref;
+ struct clk *clki;
+ u32 dev_addr;
+};
+
+static int mcp3911_read(struct mcp3911 *adc, u8 reg, u32 *val, u8 len)
+{
+ int ret;
+
+ reg = MCP3911_REG_READ(reg, adc->dev_addr);
+ ret = spi_write_then_read(adc->spi, &reg, 1, val, len);
+ if (ret < 0)
+ return ret;
+
+ be32_to_cpus(val);
+ *val >>= ((4 - len) * 8);
+ dev_dbg(&adc->spi->dev, "reading 0x%x from register 0x%x\n", *val,
+ reg >> 1);
+ return ret;
+}
+
+static int mcp3911_write(struct mcp3911 *adc, u8 reg, u32 val, u8 len)
+{
+ dev_dbg(&adc->spi->dev, "writing 0x%x to register 0x%x\n", val, reg);
+
+ val <<= (3 - len) * 8;
+ cpu_to_be32s(&val);
+ val |= MCP3911_REG_WRITE(reg, adc->dev_addr);
+
+ return spi_write(adc->spi, &val, len + 1);
+}
+
+static int mcp3911_update(struct mcp3911 *adc, u8 reg, u32 mask,
+ u32 val, u8 len)
+{
+ u32 tmp;
+ int ret;
+
+ ret = mcp3911_read(adc, reg, &tmp, len);
+ if (ret)
+ return ret;
+
+ val &= mask;
+ val |= tmp & ~mask;
+ return mcp3911_write(adc, reg, val, len);
+}
+
+static int mcp3911_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *channel, int *val,
+ int *val2, long mask)
+{
+ struct mcp3911 *adc = iio_priv(indio_dev);
+ int ret = -EINVAL;
+
+ mutex_lock(&adc->lock);
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = mcp3911_read(adc,
+ MCP3911_CHANNEL(channel->channel), val, 3);
+ if (ret)
+ goto out;
+
+ ret = IIO_VAL_INT;
+ break;
+
+ case IIO_CHAN_INFO_OFFSET:
+ ret = mcp3911_read(adc,
+ MCP3911_OFFCAL(channel->channel), val, 3);
+ if (ret)
+ goto out;
+
+ ret = IIO_VAL_INT;
+ break;
+
+ case IIO_CHAN_INFO_SCALE:
+ if (adc->vref) {
+ ret = regulator_get_voltage(adc->vref);
+ if (ret < 0) {
+ dev_err(indio_dev->dev.parent,
+ "failed to get vref voltage: %d\n",
+ ret);
+ goto out;
+ }
+
+ *val = ret / 1000;
+ } else {
+ *val = MCP3911_INT_VREF_UV;
+ }
+
+ *val2 = 24;
+ ret = IIO_VAL_FRACTIONAL_LOG2;
+ break;
+ }
+
+out:
+ mutex_unlock(&adc->lock);
+ return ret;
+}
+
+static int mcp3911_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *channel, int val,
+ int val2, long mask)
+{
+ struct mcp3911 *adc = iio_priv(indio_dev);
+ int ret = -EINVAL;
+
+ mutex_lock(&adc->lock);
+ switch (mask) {
+ case IIO_CHAN_INFO_OFFSET:
+ if (val2 != 0) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Write offset */
+ ret = mcp3911_write(adc, MCP3911_OFFCAL(channel->channel), val,
+ 3);
+ if (ret)
+ goto out;
+
+ /* Enable offset*/
+ ret = mcp3911_update(adc, MCP3911_REG_STATUSCOM,
+ MCP3911_STATUSCOM_EN_OFFCAL,
+ MCP3911_STATUSCOM_EN_OFFCAL, 2);
+ break;
+ }
+
+out:
+ mutex_unlock(&adc->lock);
+ return ret;
+}
+
+#define MCP3911_CHAN(idx) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = idx, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_OFFSET) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
+}
+
+static const struct iio_chan_spec mcp3911_channels[] = {
+ MCP3911_CHAN(0),
+ MCP3911_CHAN(1),
+};
+
+static const struct iio_info mcp3911_info = {
+ .read_raw = mcp3911_read_raw,
+ .write_raw = mcp3911_write_raw,
+};
+
+static int mcp3911_config(struct mcp3911 *adc, struct device_node *of_node)
+{
+ u32 configreg;
+ int ret;
+
+ of_property_read_u32(of_node, "device-addr", &adc->dev_addr);
+ if (adc->dev_addr > 3) {
+ dev_err(&adc->spi->dev,
+ "invalid device address (%i). Must be in range 0-3.\n",
+ adc->dev_addr);
+ return -EINVAL;
+ }
+ dev_dbg(&adc->spi->dev, "use device address %i\n", adc->dev_addr);
+
+ ret = mcp3911_read(adc, MCP3911_REG_CONFIG, &configreg, 2);
+ if (ret)
+ return ret;
+
+ if (adc->vref) {
+ dev_dbg(&adc->spi->dev, "use external voltage reference\n");
+ configreg |= MCP3911_CONFIG_VREFEXT;
+ } else {
+ dev_dbg(&adc->spi->dev,
+ "use internal voltage reference (1.2V)\n");
+ configreg &= ~MCP3911_CONFIG_VREFEXT;
+ }
+
+ if (adc->clki) {
+ dev_dbg(&adc->spi->dev, "use external clock as clocksource\n");
+ configreg |= MCP3911_CONFIG_CLKEXT;
+ } else {
+ dev_dbg(&adc->spi->dev,
+ "use crystal oscillator as clocksource\n");
+ configreg &= ~MCP3911_CONFIG_CLKEXT;
+ }
+
+ return mcp3911_write(adc, MCP3911_REG_CONFIG, configreg, 2);
+}
+
+static int mcp3911_probe(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev;
+ struct mcp3911 *adc;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ adc = iio_priv(indio_dev);
+ adc->spi = spi;
+
+ adc->vref = devm_regulator_get_optional(&adc->spi->dev, "vref");
+ if (IS_ERR(adc->vref)) {
+ if (PTR_ERR(adc->vref) == -ENODEV) {
+ adc->vref = NULL;
+ } else {
+ dev_err(&adc->spi->dev,
+ "failed to get regulator (%ld)\n",
+ PTR_ERR(adc->vref));
+ return PTR_ERR(adc->vref);
+ }
+
+ } else {
+ ret = regulator_enable(adc->vref);
+ if (ret)
+ return ret;
+ }
+
+ adc->clki = devm_clk_get(&adc->spi->dev, NULL);
+ if (IS_ERR(adc->clki)) {
+ if (PTR_ERR(adc->clki) == -ENOENT) {
+ adc->clki = NULL;
+ } else {
+ dev_err(&adc->spi->dev,
+ "failed to get adc clk (%ld)\n",
+ PTR_ERR(adc->clki));
+ ret = PTR_ERR(adc->clki);
+ goto reg_disable;
+ }
+ } else {
+ ret = clk_prepare_enable(adc->clki);
+ if (ret < 0) {
+ dev_err(&adc->spi->dev,
+ "Failed to enable clki: %d\n", ret);
+ goto reg_disable;
+ }
+ }
+
+ ret = mcp3911_config(adc, spi->dev.of_node);
+ if (ret)
+ goto clk_disable;
+
+ 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;
+ indio_dev->info = &mcp3911_info;
+ spi_set_drvdata(spi, indio_dev);
+
+ indio_dev->channels = mcp3911_channels;
+ indio_dev->num_channels = ARRAY_SIZE(mcp3911_channels);
+
+ mutex_init(&adc->lock);
+
+ ret = iio_device_register(indio_dev);
+ if (ret)
+ goto clk_disable;
+
+ return ret;
+
+clk_disable:
+ clk_disable_unprepare(adc->clki);
+reg_disable:
+ if (adc->vref)
+ regulator_disable(adc->vref);
+
+ return ret;
+}
+
+static int mcp3911_remove(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
+ struct mcp3911 *adc = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+
+ clk_disable_unprepare(adc->clki);
+ if (adc->vref)
+ regulator_disable(adc->vref);
+
+ return 0;
+}
+
+static const struct of_device_id mcp3911_dt_ids[] = {
+ { .compatible = "microchip,mcp3911" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, mcp3911_dt_ids);
+
+static const struct spi_device_id mcp3911_id[] = {
+ { "mcp3911", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, mcp3911_id);
+
+static struct spi_driver mcp3911_driver = {
+ .driver = {
+ .name = "mcp3911",
+ .of_match_table = mcp3911_dt_ids,
+ },
+ .probe = mcp3911_probe,
+ .remove = mcp3911_remove,
+ .id_table = mcp3911_id,
+};
+module_spi_driver(mcp3911_driver);
+
+MODULE_AUTHOR("Marcus Folkesson <marcus.folkesson@gmail.com>");
+MODULE_AUTHOR("Kent Gustavsson <kent@minoris.se>");
+MODULE_DESCRIPTION("Microchip Technology MCP3911");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c
index da2d16dfa63e..028ccd218f82 100644
--- a/drivers/iio/adc/meson_saradc.c
+++ b/drivers/iio/adc/meson_saradc.c
@@ -148,7 +148,6 @@
#define MESON_SAR_ADC_DELTA_10_TS_REVE1 BIT(26)
#define MESON_SAR_ADC_DELTA_10_CHAN1_DELTA_VALUE_MASK GENMASK(25, 16)
#define MESON_SAR_ADC_DELTA_10_TS_REVE0 BIT(15)
- #define MESON_SAR_ADC_DELTA_10_TS_C_SHIFT 11
#define MESON_SAR_ADC_DELTA_10_TS_C_MASK GENMASK(14, 11)
#define MESON_SAR_ADC_DELTA_10_TS_VBG_EN BIT(10)
#define MESON_SAR_ADC_DELTA_10_CHAN0_DELTA_VALUE_MASK GENMASK(9, 0)
@@ -173,6 +172,7 @@
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = _chan, \
+ .address = _chan, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_AVERAGE_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
@@ -235,7 +235,7 @@ struct meson_sar_adc_data {
struct meson_sar_adc_priv {
struct regmap *regmap;
struct regulator *vref;
- const struct meson_sar_adc_data *data;
+ const struct meson_sar_adc_param *param;
struct clk *clkin;
struct clk *core_clk;
struct clk *adc_sel_clk;
@@ -280,7 +280,7 @@ static int meson_sar_adc_calib_val(struct iio_dev *indio_dev, int val)
/* use val_calib = scale * val_raw + offset calibration function */
tmp = div_s64((s64)val * priv->calibscale, MILLION) + priv->calibbias;
- return clamp(tmp, 0, (1 << priv->data->param->resolution) - 1);
+ return clamp(tmp, 0, (1 << priv->param->resolution) - 1);
}
static int meson_sar_adc_wait_busy_clear(struct iio_dev *indio_dev)
@@ -324,15 +324,15 @@ static int meson_sar_adc_read_raw_sample(struct iio_dev *indio_dev,
regmap_read(priv->regmap, MESON_SAR_ADC_FIFO_RD, &regval);
fifo_chan = FIELD_GET(MESON_SAR_ADC_FIFO_RD_CHAN_ID_MASK, regval);
- if (fifo_chan != chan->channel) {
+ if (fifo_chan != chan->address) {
dev_err(&indio_dev->dev,
- "ADC FIFO entry belongs to channel %d instead of %d\n",
- fifo_chan, chan->channel);
+ "ADC FIFO entry belongs to channel %d instead of %lu\n",
+ fifo_chan, chan->address);
return -EINVAL;
}
fifo_val = FIELD_GET(MESON_SAR_ADC_FIFO_RD_SAMPLE_VALUE_MASK, regval);
- fifo_val &= GENMASK(priv->data->param->resolution - 1, 0);
+ fifo_val &= GENMASK(priv->param->resolution - 1, 0);
*val = meson_sar_adc_calib_val(indio_dev, fifo_val);
return 0;
@@ -344,16 +344,16 @@ static void meson_sar_adc_set_averaging(struct iio_dev *indio_dev,
enum meson_sar_adc_num_samples samples)
{
struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
- int val, channel = chan->channel;
+ int val, address = chan->address;
- val = samples << MESON_SAR_ADC_AVG_CNTL_NUM_SAMPLES_SHIFT(channel);
+ val = samples << MESON_SAR_ADC_AVG_CNTL_NUM_SAMPLES_SHIFT(address);
regmap_update_bits(priv->regmap, MESON_SAR_ADC_AVG_CNTL,
- MESON_SAR_ADC_AVG_CNTL_NUM_SAMPLES_MASK(channel),
+ MESON_SAR_ADC_AVG_CNTL_NUM_SAMPLES_MASK(address),
val);
- val = mode << MESON_SAR_ADC_AVG_CNTL_AVG_MODE_SHIFT(channel);
+ val = mode << MESON_SAR_ADC_AVG_CNTL_AVG_MODE_SHIFT(address);
regmap_update_bits(priv->regmap, MESON_SAR_ADC_AVG_CNTL,
- MESON_SAR_ADC_AVG_CNTL_AVG_MODE_MASK(channel), val);
+ MESON_SAR_ADC_AVG_CNTL_AVG_MODE_MASK(address), val);
}
static void meson_sar_adc_enable_channel(struct iio_dev *indio_dev,
@@ -373,23 +373,23 @@ static void meson_sar_adc_enable_channel(struct iio_dev *indio_dev,
/* map channel index 0 to the channel which we want to read */
regval = FIELD_PREP(MESON_SAR_ADC_CHAN_LIST_ENTRY_MASK(0),
- chan->channel);
+ chan->address);
regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_LIST,
MESON_SAR_ADC_CHAN_LIST_ENTRY_MASK(0), regval);
regval = FIELD_PREP(MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_MUX_MASK,
- chan->channel);
+ chan->address);
regmap_update_bits(priv->regmap, MESON_SAR_ADC_DETECT_IDLE_SW,
MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_MUX_MASK,
regval);
regval = FIELD_PREP(MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_MUX_SEL_MASK,
- chan->channel);
+ chan->address);
regmap_update_bits(priv->regmap, MESON_SAR_ADC_DETECT_IDLE_SW,
MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_MUX_SEL_MASK,
regval);
- if (chan->channel == 6)
+ if (chan->address == 6)
regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
MESON_SAR_ADC_DELTA_10_TEMP_SEL, 0);
}
@@ -451,7 +451,7 @@ static int meson_sar_adc_lock(struct iio_dev *indio_dev)
mutex_lock(&indio_dev->mlock);
- if (priv->data->param->has_bl30_integration) {
+ if (priv->param->has_bl30_integration) {
/* prevent BL30 from using the SAR ADC while we are using it */
regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY,
MESON_SAR_ADC_DELAY_KERNEL_BUSY,
@@ -479,7 +479,7 @@ static void meson_sar_adc_unlock(struct iio_dev *indio_dev)
{
struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
- if (priv->data->param->has_bl30_integration)
+ if (priv->param->has_bl30_integration)
/* allow BL30 to use the SAR ADC again */
regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY,
MESON_SAR_ADC_DELAY_KERNEL_BUSY, 0);
@@ -527,8 +527,8 @@ static int meson_sar_adc_get_sample(struct iio_dev *indio_dev,
if (ret) {
dev_warn(indio_dev->dev.parent,
- "failed to read sample for channel %d: %d\n",
- chan->channel, ret);
+ "failed to read sample for channel %lu: %d\n",
+ chan->address, ret);
return ret;
}
@@ -563,7 +563,7 @@ static int meson_sar_adc_iio_info_read_raw(struct iio_dev *indio_dev,
}
*val = ret / 1000;
- *val2 = priv->data->param->resolution;
+ *val2 = priv->param->resolution;
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_CHAN_INFO_CALIBBIAS:
@@ -636,7 +636,7 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev)
*/
meson_sar_adc_set_chan7_mux(indio_dev, CHAN7_MUX_CH7_INPUT);
- if (priv->data->param->has_bl30_integration) {
+ if (priv->param->has_bl30_integration) {
/*
* leave sampling delay and the input clocks as configured by
* BL30 to make sure BL30 gets the values it expects when
@@ -716,7 +716,7 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev)
return ret;
}
- ret = clk_set_rate(priv->adc_clk, priv->data->param->clock_rate);
+ ret = clk_set_rate(priv->adc_clk, priv->param->clock_rate);
if (ret) {
dev_err(indio_dev->dev.parent,
"failed to set adc clock rate\n");
@@ -729,7 +729,7 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev)
static void meson_sar_adc_set_bandgap(struct iio_dev *indio_dev, bool on_off)
{
struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
- const struct meson_sar_adc_param *param = priv->data->param;
+ const struct meson_sar_adc_param *param = priv->param;
u32 enable_mask;
if (param->bandgap_reg == MESON_SAR_ADC_REG11)
@@ -849,13 +849,13 @@ static int meson_sar_adc_calib(struct iio_dev *indio_dev)
int ret, nominal0, nominal1, value0, value1;
/* use points 25% and 75% for calibration */
- nominal0 = (1 << priv->data->param->resolution) / 4;
- nominal1 = (1 << priv->data->param->resolution) * 3 / 4;
+ nominal0 = (1 << priv->param->resolution) / 4;
+ nominal1 = (1 << priv->param->resolution) * 3 / 4;
meson_sar_adc_set_chan7_mux(indio_dev, CHAN7_MUX_VDD_DIV4);
usleep_range(10, 20);
ret = meson_sar_adc_get_sample(indio_dev,
- &meson_sar_adc_iio_channels[7],
+ &indio_dev->channels[7],
MEAN_AVERAGING, EIGHT_SAMPLES, &value0);
if (ret < 0)
goto out;
@@ -863,7 +863,7 @@ static int meson_sar_adc_calib(struct iio_dev *indio_dev)
meson_sar_adc_set_chan7_mux(indio_dev, CHAN7_MUX_VDD_MUL3_DIV4);
usleep_range(10, 20);
ret = meson_sar_adc_get_sample(indio_dev,
- &meson_sar_adc_iio_channels[7],
+ &indio_dev->channels[7],
MEAN_AVERAGING, EIGHT_SAMPLES, &value1);
if (ret < 0)
goto out;
@@ -979,11 +979,11 @@ MODULE_DEVICE_TABLE(of, meson_sar_adc_of_match);
static int meson_sar_adc_probe(struct platform_device *pdev)
{
+ const struct meson_sar_adc_data *match_data;
struct meson_sar_adc_priv *priv;
struct iio_dev *indio_dev;
struct resource *res;
void __iomem *base;
- const struct of_device_id *match;
int irq, ret;
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv));
@@ -995,15 +995,15 @@ static int meson_sar_adc_probe(struct platform_device *pdev)
priv = iio_priv(indio_dev);
init_completion(&priv->done);
- match = of_match_device(meson_sar_adc_of_match, &pdev->dev);
- if (!match) {
- dev_err(&pdev->dev, "failed to match device\n");
+ match_data = of_device_get_match_data(&pdev->dev);
+ if (!match_data) {
+ dev_err(&pdev->dev, "failed to get match data\n");
return -ENODEV;
}
- priv->data = match->data;
+ priv->param = match_data->param;
- indio_dev->name = priv->data->name;
+ indio_dev->name = match_data->name;
indio_dev->dev.parent = &pdev->dev;
indio_dev->dev.of_node = pdev->dev.of_node;
indio_dev->modes = INDIO_DIRECT_MODE;
@@ -1027,7 +1027,7 @@ static int meson_sar_adc_probe(struct platform_device *pdev)
return ret;
priv->regmap = devm_regmap_init_mmio(&pdev->dev, base,
- priv->data->param->regmap_config);
+ priv->param->regmap_config);
if (IS_ERR(priv->regmap))
return PTR_ERR(priv->regmap);
diff --git a/drivers/iio/adc/qcom-pm8xxx-xoadc.c b/drivers/iio/adc/qcom-pm8xxx-xoadc.c
index b093ecddf1a8..c30c002f1fef 100644
--- a/drivers/iio/adc/qcom-pm8xxx-xoadc.c
+++ b/drivers/iio/adc/qcom-pm8xxx-xoadc.c
@@ -708,8 +708,8 @@ static int pm8xxx_of_xlate(struct iio_dev *indio_dev,
* mux.
*/
if (iiospec->args_count != 2) {
- dev_err(&indio_dev->dev, "wrong number of arguments for %s need 2 got %d\n",
- iiospec->np->name,
+ dev_err(&indio_dev->dev, "wrong number of arguments for %pOFn need 2 got %d\n",
+ iiospec->np,
iiospec->args_count);
return -EINVAL;
}
diff --git a/drivers/iio/adc/qcom-spmi-adc5.c b/drivers/iio/adc/qcom-spmi-adc5.c
new file mode 100644
index 000000000000..f9af6b082916
--- /dev/null
+++ b/drivers/iio/adc/qcom-spmi-adc5.c
@@ -0,0 +1,793 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/bitops.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/iio/iio.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/log2.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include <dt-bindings/iio/qcom,spmi-vadc.h>
+#include "qcom-vadc-common.h"
+
+#define ADC5_USR_REVISION1 0x0
+#define ADC5_USR_STATUS1 0x8
+#define ADC5_USR_STATUS1_REQ_STS BIT(1)
+#define ADC5_USR_STATUS1_EOC BIT(0)
+#define ADC5_USR_STATUS1_REQ_STS_EOC_MASK 0x3
+
+#define ADC5_USR_STATUS2 0x9
+#define ADC5_USR_STATUS2_CONV_SEQ_MASK 0x70
+#define ADC5_USR_STATUS2_CONV_SEQ_MASK_SHIFT 0x5
+
+#define ADC5_USR_IBAT_MEAS 0xf
+#define ADC5_USR_IBAT_MEAS_SUPPORTED BIT(0)
+
+#define ADC5_USR_DIG_PARAM 0x42
+#define ADC5_USR_DIG_PARAM_CAL_VAL BIT(6)
+#define ADC5_USR_DIG_PARAM_CAL_VAL_SHIFT 6
+#define ADC5_USR_DIG_PARAM_CAL_SEL 0x30
+#define ADC5_USR_DIG_PARAM_CAL_SEL_SHIFT 4
+#define ADC5_USR_DIG_PARAM_DEC_RATIO_SEL 0xc
+#define ADC5_USR_DIG_PARAM_DEC_RATIO_SEL_SHIFT 2
+
+#define ADC5_USR_FAST_AVG_CTL 0x43
+#define ADC5_USR_FAST_AVG_CTL_EN BIT(7)
+#define ADC5_USR_FAST_AVG_CTL_SAMPLES_MASK 0x7
+
+#define ADC5_USR_CH_SEL_CTL 0x44
+
+#define ADC5_USR_DELAY_CTL 0x45
+#define ADC5_USR_HW_SETTLE_DELAY_MASK 0xf
+
+#define ADC5_USR_EN_CTL1 0x46
+#define ADC5_USR_EN_CTL1_ADC_EN BIT(7)
+
+#define ADC5_USR_CONV_REQ 0x47
+#define ADC5_USR_CONV_REQ_REQ BIT(7)
+
+#define ADC5_USR_DATA0 0x50
+
+#define ADC5_USR_DATA1 0x51
+
+#define ADC5_USR_IBAT_DATA0 0x52
+
+#define ADC5_USR_IBAT_DATA1 0x53
+
+/*
+ * Conversion time varies based on the decimation, clock rate, fast average
+ * samples and measurements queued across different VADC peripherals.
+ * Set the timeout to a max of 100ms.
+ */
+#define ADC5_CONV_TIME_MIN_US 263
+#define ADC5_CONV_TIME_MAX_US 264
+#define ADC5_CONV_TIME_RETRY 400
+#define ADC5_CONV_TIMEOUT msecs_to_jiffies(100)
+
+/* Digital version >= 5.3 supports hw_settle_2 */
+#define ADC5_HW_SETTLE_DIFF_MINOR 3
+#define ADC5_HW_SETTLE_DIFF_MAJOR 5
+
+enum adc5_cal_method {
+ ADC5_NO_CAL = 0,
+ ADC5_RATIOMETRIC_CAL,
+ ADC5_ABSOLUTE_CAL
+};
+
+enum adc5_cal_val {
+ ADC5_TIMER_CAL = 0,
+ ADC5_NEW_CAL
+};
+
+/**
+ * struct adc5_channel_prop - ADC channel property.
+ * @channel: channel number, refer to the channel list.
+ * @cal_method: calibration method.
+ * @cal_val: calibration value
+ * @decimation: sampling rate supported for the channel.
+ * @prescale: channel scaling performed on the input signal.
+ * @hw_settle_time: the time between AMUX being configured and the
+ * start of conversion.
+ * @avg_samples: ability to provide single result from the ADC
+ * that is an average of multiple measurements.
+ * @scale_fn_type: Represents the scaling function to convert voltage
+ * physical units desired by the client for the channel.
+ * @datasheet_name: Channel name used in device tree.
+ */
+struct adc5_channel_prop {
+ unsigned int channel;
+ enum adc5_cal_method cal_method;
+ enum adc5_cal_val cal_val;
+ unsigned int decimation;
+ unsigned int prescale;
+ unsigned int hw_settle_time;
+ unsigned int avg_samples;
+ enum vadc_scale_fn_type scale_fn_type;
+ const char *datasheet_name;
+};
+
+/**
+ * struct adc5_chip - ADC private structure.
+ * @regmap: SPMI ADC5 peripheral register map field.
+ * @dev: SPMI ADC5 device.
+ * @base: base address for the ADC peripheral.
+ * @nchannels: number of ADC channels.
+ * @chan_props: array of ADC channel properties.
+ * @iio_chans: array of IIO channels specification.
+ * @poll_eoc: use polling instead of interrupt.
+ * @complete: ADC result notification after interrupt is received.
+ * @lock: ADC lock for access to the peripheral.
+ * @data: software configuration data.
+ */
+struct adc5_chip {
+ struct regmap *regmap;
+ struct device *dev;
+ u16 base;
+ unsigned int nchannels;
+ struct adc5_channel_prop *chan_props;
+ struct iio_chan_spec *iio_chans;
+ bool poll_eoc;
+ struct completion complete;
+ struct mutex lock;
+ const struct adc5_data *data;
+};
+
+static const struct vadc_prescale_ratio adc5_prescale_ratios[] = {
+ {.num = 1, .den = 1},
+ {.num = 1, .den = 3},
+ {.num = 1, .den = 4},
+ {.num = 1, .den = 6},
+ {.num = 1, .den = 20},
+ {.num = 1, .den = 8},
+ {.num = 10, .den = 81},
+ {.num = 1, .den = 10},
+ {.num = 1, .den = 16}
+};
+
+static int adc5_read(struct adc5_chip *adc, u16 offset, u8 *data, int len)
+{
+ return regmap_bulk_read(adc->regmap, adc->base + offset, data, len);
+}
+
+static int adc5_write(struct adc5_chip *adc, u16 offset, u8 *data, int len)
+{
+ return regmap_bulk_write(adc->regmap, adc->base + offset, data, len);
+}
+
+static int adc5_prescaling_from_dt(u32 num, u32 den)
+{
+ unsigned int pre;
+
+ for (pre = 0; pre < ARRAY_SIZE(adc5_prescale_ratios); pre++)
+ if (adc5_prescale_ratios[pre].num == num &&
+ adc5_prescale_ratios[pre].den == den)
+ break;
+
+ if (pre == ARRAY_SIZE(adc5_prescale_ratios))
+ return -EINVAL;
+
+ return pre;
+}
+
+static int adc5_hw_settle_time_from_dt(u32 value,
+ const unsigned int *hw_settle)
+{
+ unsigned int i;
+
+ for (i = 0; i < VADC_HW_SETTLE_SAMPLES_MAX; i++) {
+ if (value == hw_settle[i])
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+static int adc5_avg_samples_from_dt(u32 value)
+{
+ if (!is_power_of_2(value) || value > ADC5_AVG_SAMPLES_MAX)
+ return -EINVAL;
+
+ return __ffs(value);
+}
+
+static int adc5_decimation_from_dt(u32 value,
+ const unsigned int *decimation)
+{
+ unsigned int i;
+
+ for (i = 0; i < ADC5_DECIMATION_SAMPLES_MAX; i++) {
+ if (value == decimation[i])
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+static int adc5_read_voltage_data(struct adc5_chip *adc, u16 *data)
+{
+ int ret;
+ u8 rslt_lsb, rslt_msb;
+
+ ret = adc5_read(adc, ADC5_USR_DATA0, &rslt_lsb, sizeof(rslt_lsb));
+ if (ret)
+ return ret;
+
+ ret = adc5_read(adc, ADC5_USR_DATA1, &rslt_msb, sizeof(rslt_lsb));
+ if (ret)
+ return ret;
+
+ *data = (rslt_msb << 8) | rslt_lsb;
+
+ if (*data == ADC5_USR_DATA_CHECK) {
+ pr_err("Invalid data:0x%x\n", *data);
+ return -EINVAL;
+ }
+
+ pr_debug("voltage raw code:0x%x\n", *data);
+
+ return 0;
+}
+
+static int adc5_poll_wait_eoc(struct adc5_chip *adc)
+{
+ unsigned int count, retry = ADC5_CONV_TIME_RETRY;
+ u8 status1;
+ int ret;
+
+ for (count = 0; count < retry; count++) {
+ ret = adc5_read(adc, ADC5_USR_STATUS1, &status1,
+ sizeof(status1));
+ if (ret)
+ return ret;
+
+ status1 &= ADC5_USR_STATUS1_REQ_STS_EOC_MASK;
+ if (status1 == ADC5_USR_STATUS1_EOC)
+ return 0;
+
+ usleep_range(ADC5_CONV_TIME_MIN_US, ADC5_CONV_TIME_MAX_US);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static void adc5_update_dig_param(struct adc5_chip *adc,
+ struct adc5_channel_prop *prop, u8 *data)
+{
+ /* Update calibration value */
+ *data &= ~ADC5_USR_DIG_PARAM_CAL_VAL;
+ *data |= (prop->cal_val << ADC5_USR_DIG_PARAM_CAL_VAL_SHIFT);
+
+ /* Update calibration select */
+ *data &= ~ADC5_USR_DIG_PARAM_CAL_SEL;
+ *data |= (prop->cal_method << ADC5_USR_DIG_PARAM_CAL_SEL_SHIFT);
+
+ /* Update decimation ratio select */
+ *data &= ~ADC5_USR_DIG_PARAM_DEC_RATIO_SEL;
+ *data |= (prop->decimation << ADC5_USR_DIG_PARAM_DEC_RATIO_SEL_SHIFT);
+}
+
+static int adc5_configure(struct adc5_chip *adc,
+ struct adc5_channel_prop *prop)
+{
+ int ret;
+ u8 buf[6];
+
+ /* Read registers 0x42 through 0x46 */
+ ret = adc5_read(adc, ADC5_USR_DIG_PARAM, buf, sizeof(buf));
+ if (ret < 0)
+ return ret;
+
+ /* Digital param selection */
+ adc5_update_dig_param(adc, prop, &buf[0]);
+
+ /* Update fast average sample value */
+ buf[1] &= (u8) ~ADC5_USR_FAST_AVG_CTL_SAMPLES_MASK;
+ buf[1] |= prop->avg_samples;
+
+ /* Select ADC channel */
+ buf[2] = prop->channel;
+
+ /* Select HW settle delay for channel */
+ buf[3] &= (u8) ~ADC5_USR_HW_SETTLE_DELAY_MASK;
+ buf[3] |= prop->hw_settle_time;
+
+ /* Select ADC enable */
+ buf[4] |= ADC5_USR_EN_CTL1_ADC_EN;
+
+ /* Select CONV request */
+ buf[5] |= ADC5_USR_CONV_REQ_REQ;
+
+ if (!adc->poll_eoc)
+ reinit_completion(&adc->complete);
+
+ return adc5_write(adc, ADC5_USR_DIG_PARAM, buf, sizeof(buf));
+}
+
+static int adc5_do_conversion(struct adc5_chip *adc,
+ struct adc5_channel_prop *prop,
+ struct iio_chan_spec const *chan,
+ u16 *data_volt, u16 *data_cur)
+{
+ int ret;
+
+ mutex_lock(&adc->lock);
+
+ ret = adc5_configure(adc, prop);
+ if (ret) {
+ pr_err("ADC configure failed with %d\n", ret);
+ goto unlock;
+ }
+
+ if (adc->poll_eoc) {
+ ret = adc5_poll_wait_eoc(adc);
+ if (ret < 0) {
+ pr_err("EOC bit not set\n");
+ goto unlock;
+ }
+ } else {
+ ret = wait_for_completion_timeout(&adc->complete,
+ ADC5_CONV_TIMEOUT);
+ if (!ret) {
+ pr_debug("Did not get completion timeout.\n");
+ ret = adc5_poll_wait_eoc(adc);
+ if (ret < 0) {
+ pr_err("EOC bit not set\n");
+ goto unlock;
+ }
+ }
+ }
+
+ ret = adc5_read_voltage_data(adc, data_volt);
+unlock:
+ mutex_unlock(&adc->lock);
+
+ return ret;
+}
+
+static irqreturn_t adc5_isr(int irq, void *dev_id)
+{
+ struct adc5_chip *adc = dev_id;
+
+ complete(&adc->complete);
+
+ return IRQ_HANDLED;
+}
+
+static int adc5_of_xlate(struct iio_dev *indio_dev,
+ const struct of_phandle_args *iiospec)
+{
+ struct adc5_chip *adc = iio_priv(indio_dev);
+ int i;
+
+ for (i = 0; i < adc->nchannels; i++)
+ if (adc->chan_props[i].channel == iiospec->args[0])
+ return i;
+
+ return -EINVAL;
+}
+
+static int adc5_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val, int *val2,
+ long mask)
+{
+ struct adc5_chip *adc = iio_priv(indio_dev);
+ struct adc5_channel_prop *prop;
+ u16 adc_code_volt, adc_code_cur;
+ int ret;
+
+ prop = &adc->chan_props[chan->address];
+
+ switch (mask) {
+ case IIO_CHAN_INFO_PROCESSED:
+ ret = adc5_do_conversion(adc, prop, chan,
+ &adc_code_volt, &adc_code_cur);
+ if (ret)
+ return ret;
+
+ ret = qcom_adc5_hw_scale(prop->scale_fn_type,
+ &adc5_prescale_ratios[prop->prescale],
+ adc->data,
+ adc_code_volt, val);
+ if (ret)
+ return ret;
+
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct iio_info adc5_info = {
+ .read_raw = adc5_read_raw,
+ .of_xlate = adc5_of_xlate,
+};
+
+struct adc5_channels {
+ const char *datasheet_name;
+ unsigned int prescale_index;
+ enum iio_chan_type type;
+ long info_mask;
+ enum vadc_scale_fn_type scale_fn_type;
+};
+
+#define ADC5_CHAN(_dname, _type, _mask, _pre, _scale) \
+ { \
+ .datasheet_name = _dname, \
+ .prescale_index = _pre, \
+ .type = _type, \
+ .info_mask = _mask, \
+ .scale_fn_type = _scale, \
+ }, \
+
+#define ADC5_CHAN_TEMP(_dname, _pre, _scale) \
+ ADC5_CHAN(_dname, IIO_TEMP, \
+ BIT(IIO_CHAN_INFO_PROCESSED), \
+ _pre, _scale) \
+
+#define ADC5_CHAN_VOLT(_dname, _pre, _scale) \
+ ADC5_CHAN(_dname, IIO_VOLTAGE, \
+ BIT(IIO_CHAN_INFO_PROCESSED), \
+ _pre, _scale) \
+
+static const struct adc5_channels adc5_chans_pmic[ADC5_MAX_CHANNEL] = {
+ [ADC5_REF_GND] = ADC5_CHAN_VOLT("ref_gnd", 1,
+ SCALE_HW_CALIB_DEFAULT)
+ [ADC5_1P25VREF] = ADC5_CHAN_VOLT("vref_1p25", 1,
+ SCALE_HW_CALIB_DEFAULT)
+ [ADC5_VPH_PWR] = ADC5_CHAN_VOLT("vph_pwr", 3,
+ SCALE_HW_CALIB_DEFAULT)
+ [ADC5_VBAT_SNS] = ADC5_CHAN_VOLT("vbat_sns", 3,
+ SCALE_HW_CALIB_DEFAULT)
+ [ADC5_DIE_TEMP] = ADC5_CHAN_TEMP("die_temp", 1,
+ SCALE_HW_CALIB_PMIC_THERM)
+ [ADC5_USB_IN_I] = ADC5_CHAN_VOLT("usb_in_i_uv", 1,
+ SCALE_HW_CALIB_DEFAULT)
+ [ADC5_USB_IN_V_16] = ADC5_CHAN_VOLT("usb_in_v_div_16", 16,
+ SCALE_HW_CALIB_DEFAULT)
+ [ADC5_CHG_TEMP] = ADC5_CHAN_TEMP("chg_temp", 1,
+ SCALE_HW_CALIB_PM5_CHG_TEMP)
+ /* Charger prescales SBUx and MID_CHG to fit within 1.8V upper unit */
+ [ADC5_SBUx] = ADC5_CHAN_VOLT("chg_sbux", 3,
+ SCALE_HW_CALIB_DEFAULT)
+ [ADC5_MID_CHG_DIV6] = ADC5_CHAN_VOLT("chg_mid_chg", 6,
+ SCALE_HW_CALIB_DEFAULT)
+ [ADC5_XO_THERM_100K_PU] = ADC5_CHAN_TEMP("xo_therm", 1,
+ SCALE_HW_CALIB_XOTHERM)
+ [ADC5_AMUX_THM1_100K_PU] = ADC5_CHAN_TEMP("amux_thm1_100k_pu", 1,
+ SCALE_HW_CALIB_THERM_100K_PULLUP)
+ [ADC5_AMUX_THM2_100K_PU] = ADC5_CHAN_TEMP("amux_thm2_100k_pu", 1,
+ SCALE_HW_CALIB_THERM_100K_PULLUP)
+ [ADC5_AMUX_THM3_100K_PU] = ADC5_CHAN_TEMP("amux_thm3_100k_pu", 1,
+ SCALE_HW_CALIB_THERM_100K_PULLUP)
+ [ADC5_AMUX_THM2] = ADC5_CHAN_TEMP("amux_thm2", 1,
+ SCALE_HW_CALIB_PM5_SMB_TEMP)
+};
+
+static const struct adc5_channels adc5_chans_rev2[ADC5_MAX_CHANNEL] = {
+ [ADC5_REF_GND] = ADC5_CHAN_VOLT("ref_gnd", 1,
+ SCALE_HW_CALIB_DEFAULT)
+ [ADC5_1P25VREF] = ADC5_CHAN_VOLT("vref_1p25", 1,
+ SCALE_HW_CALIB_DEFAULT)
+ [ADC5_VPH_PWR] = ADC5_CHAN_VOLT("vph_pwr", 3,
+ SCALE_HW_CALIB_DEFAULT)
+ [ADC5_VBAT_SNS] = ADC5_CHAN_VOLT("vbat_sns", 3,
+ SCALE_HW_CALIB_DEFAULT)
+ [ADC5_VCOIN] = ADC5_CHAN_VOLT("vcoin", 3,
+ SCALE_HW_CALIB_DEFAULT)
+ [ADC5_DIE_TEMP] = ADC5_CHAN_TEMP("die_temp", 1,
+ SCALE_HW_CALIB_PMIC_THERM)
+ [ADC5_AMUX_THM1_100K_PU] = ADC5_CHAN_TEMP("amux_thm1_100k_pu", 1,
+ SCALE_HW_CALIB_THERM_100K_PULLUP)
+ [ADC5_AMUX_THM2_100K_PU] = ADC5_CHAN_TEMP("amux_thm2_100k_pu", 1,
+ SCALE_HW_CALIB_THERM_100K_PULLUP)
+ [ADC5_AMUX_THM3_100K_PU] = ADC5_CHAN_TEMP("amux_thm3_100k_pu", 1,
+ SCALE_HW_CALIB_THERM_100K_PULLUP)
+ [ADC5_AMUX_THM4_100K_PU] = ADC5_CHAN_TEMP("amux_thm4_100k_pu", 1,
+ SCALE_HW_CALIB_THERM_100K_PULLUP)
+ [ADC5_AMUX_THM5_100K_PU] = ADC5_CHAN_TEMP("amux_thm5_100k_pu", 1,
+ SCALE_HW_CALIB_THERM_100K_PULLUP)
+ [ADC5_XO_THERM_100K_PU] = ADC5_CHAN_TEMP("xo_therm_100k_pu", 1,
+ SCALE_HW_CALIB_THERM_100K_PULLUP)
+};
+
+static int adc5_get_dt_channel_data(struct adc5_chip *adc,
+ struct adc5_channel_prop *prop,
+ struct device_node *node,
+ const struct adc5_data *data)
+{
+ const char *name = node->name, *channel_name;
+ u32 chan, value, varr[2];
+ int ret;
+ struct device *dev = adc->dev;
+
+ ret = of_property_read_u32(node, "reg", &chan);
+ if (ret) {
+ dev_err(dev, "invalid channel number %s\n", name);
+ return ret;
+ }
+
+ if (chan > ADC5_PARALLEL_ISENSE_VBAT_IDATA ||
+ !data->adc_chans[chan].datasheet_name) {
+ dev_err(dev, "%s invalid channel number %d\n", name, chan);
+ return -EINVAL;
+ }
+
+ /* the channel has DT description */
+ prop->channel = chan;
+
+ channel_name = of_get_property(node,
+ "label", NULL) ? : node->name;
+ if (!channel_name) {
+ pr_err("Invalid channel name\n");
+ return -EINVAL;
+ }
+ prop->datasheet_name = channel_name;
+
+ ret = of_property_read_u32(node, "qcom,decimation", &value);
+ if (!ret) {
+ ret = adc5_decimation_from_dt(value, data->decimation);
+ if (ret < 0) {
+ dev_err(dev, "%02x invalid decimation %d\n",
+ chan, value);
+ return ret;
+ }
+ prop->decimation = ret;
+ } else {
+ prop->decimation = ADC5_DECIMATION_DEFAULT;
+ }
+
+ ret = of_property_read_u32_array(node, "qcom,pre-scaling", varr, 2);
+ if (!ret) {
+ ret = adc5_prescaling_from_dt(varr[0], varr[1]);
+ if (ret < 0) {
+ dev_err(dev, "%02x invalid pre-scaling <%d %d>\n",
+ chan, varr[0], varr[1]);
+ return ret;
+ }
+ prop->prescale = ret;
+ }
+
+ ret = of_property_read_u32(node, "qcom,hw-settle-time", &value);
+ if (!ret) {
+ u8 dig_version[2];
+
+ ret = adc5_read(adc, ADC5_USR_REVISION1, dig_version,
+ sizeof(dig_version));
+ if (ret < 0) {
+ dev_err(dev, "Invalid dig version read %d\n", ret);
+ return ret;
+ }
+
+ pr_debug("dig_ver:minor:%d, major:%d\n", dig_version[0],
+ dig_version[1]);
+ /* Digital controller >= 5.3 have hw_settle_2 option */
+ if (dig_version[0] >= ADC5_HW_SETTLE_DIFF_MINOR &&
+ dig_version[1] >= ADC5_HW_SETTLE_DIFF_MAJOR)
+ ret = adc5_hw_settle_time_from_dt(value,
+ data->hw_settle_2);
+ else
+ ret = adc5_hw_settle_time_from_dt(value,
+ data->hw_settle_1);
+
+ if (ret < 0) {
+ dev_err(dev, "%02x invalid hw-settle-time %d us\n",
+ chan, value);
+ return ret;
+ }
+ prop->hw_settle_time = ret;
+ } else {
+ prop->hw_settle_time = VADC_DEF_HW_SETTLE_TIME;
+ }
+
+ ret = of_property_read_u32(node, "qcom,avg-samples", &value);
+ if (!ret) {
+ ret = adc5_avg_samples_from_dt(value);
+ if (ret < 0) {
+ dev_err(dev, "%02x invalid avg-samples %d\n",
+ chan, value);
+ return ret;
+ }
+ prop->avg_samples = ret;
+ } else {
+ prop->avg_samples = VADC_DEF_AVG_SAMPLES;
+ }
+
+ if (of_property_read_bool(node, "qcom,ratiometric"))
+ prop->cal_method = ADC5_RATIOMETRIC_CAL;
+ else
+ prop->cal_method = ADC5_ABSOLUTE_CAL;
+
+ /*
+ * Default to using timer calibration. Using a fresh calibration value
+ * for every conversion will increase the overall time for a request.
+ */
+ prop->cal_val = ADC5_TIMER_CAL;
+
+ dev_dbg(dev, "%02x name %s\n", chan, name);
+
+ return 0;
+}
+
+static const struct adc5_data adc5_data_pmic = {
+ .full_scale_code_volt = 0x70e4,
+ .full_scale_code_cur = 0x2710,
+ .adc_chans = adc5_chans_pmic,
+ .decimation = (unsigned int [ADC5_DECIMATION_SAMPLES_MAX])
+ {250, 420, 840},
+ .hw_settle_1 = (unsigned int [VADC_HW_SETTLE_SAMPLES_MAX])
+ {15, 100, 200, 300, 400, 500, 600, 700,
+ 800, 900, 1, 2, 4, 6, 8, 10},
+ .hw_settle_2 = (unsigned int [VADC_HW_SETTLE_SAMPLES_MAX])
+ {15, 100, 200, 300, 400, 500, 600, 700,
+ 1, 2, 4, 8, 16, 32, 64, 128},
+};
+
+static const struct adc5_data adc5_data_pmic_rev2 = {
+ .full_scale_code_volt = 0x4000,
+ .full_scale_code_cur = 0x1800,
+ .adc_chans = adc5_chans_rev2,
+ .decimation = (unsigned int [ADC5_DECIMATION_SAMPLES_MAX])
+ {256, 512, 1024},
+ .hw_settle_1 = (unsigned int [VADC_HW_SETTLE_SAMPLES_MAX])
+ {0, 100, 200, 300, 400, 500, 600, 700,
+ 800, 900, 1, 2, 4, 6, 8, 10},
+ .hw_settle_2 = (unsigned int [VADC_HW_SETTLE_SAMPLES_MAX])
+ {15, 100, 200, 300, 400, 500, 600, 700,
+ 1, 2, 4, 8, 16, 32, 64, 128},
+};
+
+static const struct of_device_id adc5_match_table[] = {
+ {
+ .compatible = "qcom,spmi-adc5",
+ .data = &adc5_data_pmic,
+ },
+ {
+ .compatible = "qcom,spmi-adc-rev2",
+ .data = &adc5_data_pmic_rev2,
+ },
+ { }
+};
+
+static int adc5_get_dt_data(struct adc5_chip *adc, struct device_node *node)
+{
+ const struct adc5_channels *adc_chan;
+ struct iio_chan_spec *iio_chan;
+ struct adc5_channel_prop prop, *chan_props;
+ struct device_node *child;
+ unsigned int index = 0;
+ const struct of_device_id *id;
+ const struct adc5_data *data;
+ int ret;
+
+ adc->nchannels = of_get_available_child_count(node);
+ if (!adc->nchannels)
+ return -EINVAL;
+
+ adc->iio_chans = devm_kcalloc(adc->dev, adc->nchannels,
+ sizeof(*adc->iio_chans), GFP_KERNEL);
+ if (!adc->iio_chans)
+ return -ENOMEM;
+
+ adc->chan_props = devm_kcalloc(adc->dev, adc->nchannels,
+ sizeof(*adc->chan_props), GFP_KERNEL);
+ if (!adc->chan_props)
+ return -ENOMEM;
+
+ chan_props = adc->chan_props;
+ iio_chan = adc->iio_chans;
+ id = of_match_node(adc5_match_table, node);
+ if (id)
+ data = id->data;
+ else
+ data = &adc5_data_pmic;
+ adc->data = data;
+
+ for_each_available_child_of_node(node, child) {
+ ret = adc5_get_dt_channel_data(adc, &prop, child, data);
+ if (ret) {
+ of_node_put(child);
+ return ret;
+ }
+
+ prop.scale_fn_type =
+ data->adc_chans[prop.channel].scale_fn_type;
+ *chan_props = prop;
+ adc_chan = &data->adc_chans[prop.channel];
+
+ iio_chan->channel = prop.channel;
+ iio_chan->datasheet_name = prop.datasheet_name;
+ iio_chan->extend_name = prop.datasheet_name;
+ iio_chan->info_mask_separate = adc_chan->info_mask;
+ iio_chan->type = adc_chan->type;
+ iio_chan->address = index;
+ iio_chan++;
+ chan_props++;
+ index++;
+ }
+
+ return 0;
+}
+
+static int adc5_probe(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ struct iio_dev *indio_dev;
+ struct adc5_chip *adc;
+ struct regmap *regmap;
+ int ret, irq_eoc;
+ u32 reg;
+
+ regmap = dev_get_regmap(dev->parent, NULL);
+ if (!regmap)
+ return -ENODEV;
+
+ ret = of_property_read_u32(node, "reg", &reg);
+ if (ret < 0)
+ return ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*adc));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ adc = iio_priv(indio_dev);
+ adc->regmap = regmap;
+ adc->dev = dev;
+ adc->base = reg;
+ init_completion(&adc->complete);
+ mutex_init(&adc->lock);
+
+ ret = adc5_get_dt_data(adc, node);
+ if (ret) {
+ pr_err("adc get dt data failed\n");
+ return ret;
+ }
+
+ irq_eoc = platform_get_irq(pdev, 0);
+ if (irq_eoc < 0) {
+ if (irq_eoc == -EPROBE_DEFER || irq_eoc == -EINVAL)
+ return irq_eoc;
+ adc->poll_eoc = true;
+ } else {
+ ret = devm_request_irq(dev, irq_eoc, adc5_isr, 0,
+ "pm-adc5", adc);
+ if (ret)
+ return ret;
+ }
+
+ indio_dev->dev.parent = dev;
+ indio_dev->dev.of_node = node;
+ indio_dev->name = pdev->name;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &adc5_info;
+ indio_dev->channels = adc->iio_chans;
+ indio_dev->num_channels = adc->nchannels;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static struct platform_driver adc5_driver = {
+ .driver = {
+ .name = "qcom-spmi-adc5.c",
+ .of_match_table = adc5_match_table,
+ },
+ .probe = adc5_probe,
+};
+module_platform_driver(adc5_driver);
+
+MODULE_ALIAS("platform:qcom-spmi-adc5");
+MODULE_DESCRIPTION("Qualcomm Technologies Inc. PMIC5 ADC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/qcom-vadc-common.c b/drivers/iio/adc/qcom-vadc-common.c
index fe3d7826783c..dcd7fb5b9fb2 100644
--- a/drivers/iio/adc/qcom-vadc-common.c
+++ b/drivers/iio/adc/qcom-vadc-common.c
@@ -47,8 +47,79 @@ static const struct vadc_map_pt adcmap_100k_104ef_104fb[] = {
{44, 125}
};
+/*
+ * Voltage to temperature table for 100k pull up for NTCG104EF104 with
+ * 1.875V reference.
+ */
+static const struct vadc_map_pt adcmap_100k_104ef_104fb_1875_vref[] = {
+ { 1831, -40000 },
+ { 1814, -35000 },
+ { 1791, -30000 },
+ { 1761, -25000 },
+ { 1723, -20000 },
+ { 1675, -15000 },
+ { 1616, -10000 },
+ { 1545, -5000 },
+ { 1463, 0 },
+ { 1370, 5000 },
+ { 1268, 10000 },
+ { 1160, 15000 },
+ { 1049, 20000 },
+ { 937, 25000 },
+ { 828, 30000 },
+ { 726, 35000 },
+ { 630, 40000 },
+ { 544, 45000 },
+ { 467, 50000 },
+ { 399, 55000 },
+ { 340, 60000 },
+ { 290, 65000 },
+ { 247, 70000 },
+ { 209, 75000 },
+ { 179, 80000 },
+ { 153, 85000 },
+ { 130, 90000 },
+ { 112, 95000 },
+ { 96, 100000 },
+ { 82, 105000 },
+ { 71, 110000 },
+ { 62, 115000 },
+ { 53, 120000 },
+ { 46, 125000 },
+};
+
+static int qcom_vadc_scale_hw_calib_volt(
+ const struct vadc_prescale_ratio *prescale,
+ const struct adc5_data *data,
+ u16 adc_code, int *result_uv);
+static int qcom_vadc_scale_hw_calib_therm(
+ const struct vadc_prescale_ratio *prescale,
+ const struct adc5_data *data,
+ u16 adc_code, int *result_mdec);
+static int qcom_vadc_scale_hw_smb_temp(
+ const struct vadc_prescale_ratio *prescale,
+ const struct adc5_data *data,
+ u16 adc_code, int *result_mdec);
+static int qcom_vadc_scale_hw_chg5_temp(
+ const struct vadc_prescale_ratio *prescale,
+ const struct adc5_data *data,
+ u16 adc_code, int *result_mdec);
+static int qcom_vadc_scale_hw_calib_die_temp(
+ const struct vadc_prescale_ratio *prescale,
+ const struct adc5_data *data,
+ u16 adc_code, int *result_mdec);
+
+static struct qcom_adc5_scale_type scale_adc5_fn[] = {
+ [SCALE_HW_CALIB_DEFAULT] = {qcom_vadc_scale_hw_calib_volt},
+ [SCALE_HW_CALIB_THERM_100K_PULLUP] = {qcom_vadc_scale_hw_calib_therm},
+ [SCALE_HW_CALIB_XOTHERM] = {qcom_vadc_scale_hw_calib_therm},
+ [SCALE_HW_CALIB_PMIC_THERM] = {qcom_vadc_scale_hw_calib_die_temp},
+ [SCALE_HW_CALIB_PM5_CHG_TEMP] = {qcom_vadc_scale_hw_chg5_temp},
+ [SCALE_HW_CALIB_PM5_SMB_TEMP] = {qcom_vadc_scale_hw_smb_temp},
+};
+
static int qcom_vadc_map_voltage_temp(const struct vadc_map_pt *pts,
- u32 tablesize, s32 input, s64 *output)
+ u32 tablesize, s32 input, int *output)
{
bool descending = 1;
u32 i = 0;
@@ -128,7 +199,7 @@ static int qcom_vadc_scale_therm(const struct vadc_linear_graph *calib_graph,
bool absolute, u16 adc_code,
int *result_mdec)
{
- s64 voltage = 0, result = 0;
+ s64 voltage = 0;
int ret;
qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage);
@@ -138,12 +209,11 @@ static int qcom_vadc_scale_therm(const struct vadc_linear_graph *calib_graph,
ret = qcom_vadc_map_voltage_temp(adcmap_100k_104ef_104fb,
ARRAY_SIZE(adcmap_100k_104ef_104fb),
- voltage, &result);
+ voltage, result_mdec);
if (ret)
return ret;
- result *= 1000;
- *result_mdec = result;
+ *result_mdec *= 1000;
return 0;
}
@@ -191,6 +261,99 @@ static int qcom_vadc_scale_chg_temp(const struct vadc_linear_graph *calib_graph,
return 0;
}
+static int qcom_vadc_scale_code_voltage_factor(u16 adc_code,
+ const struct vadc_prescale_ratio *prescale,
+ const struct adc5_data *data,
+ unsigned int factor)
+{
+ s64 voltage, temp, adc_vdd_ref_mv = 1875;
+
+ /*
+ * The normal data range is between 0V to 1.875V. On cases where
+ * we read low voltage values, the ADC code can go beyond the
+ * range and the scale result is incorrect so we clamp the values
+ * for the cases where the code represents a value below 0V
+ */
+ if (adc_code > VADC5_MAX_CODE)
+ adc_code = 0;
+
+ /* (ADC code * vref_vadc (1.875V)) / full_scale_code */
+ voltage = (s64) adc_code * adc_vdd_ref_mv * 1000;
+ voltage = div64_s64(voltage, data->full_scale_code_volt);
+ if (voltage > 0) {
+ voltage *= prescale->den;
+ temp = prescale->num * factor;
+ voltage = div64_s64(voltage, temp);
+ } else {
+ voltage = 0;
+ }
+
+ return (int) voltage;
+}
+
+static int qcom_vadc_scale_hw_calib_volt(
+ const struct vadc_prescale_ratio *prescale,
+ const struct adc5_data *data,
+ u16 adc_code, int *result_uv)
+{
+ *result_uv = qcom_vadc_scale_code_voltage_factor(adc_code,
+ prescale, data, 1);
+
+ return 0;
+}
+
+static int qcom_vadc_scale_hw_calib_therm(
+ const struct vadc_prescale_ratio *prescale,
+ const struct adc5_data *data,
+ u16 adc_code, int *result_mdec)
+{
+ int voltage;
+
+ voltage = qcom_vadc_scale_code_voltage_factor(adc_code,
+ prescale, data, 1000);
+
+ /* Map voltage to temperature from look-up table */
+ return qcom_vadc_map_voltage_temp(adcmap_100k_104ef_104fb_1875_vref,
+ ARRAY_SIZE(adcmap_100k_104ef_104fb_1875_vref),
+ voltage, result_mdec);
+}
+
+static int qcom_vadc_scale_hw_calib_die_temp(
+ const struct vadc_prescale_ratio *prescale,
+ const struct adc5_data *data,
+ u16 adc_code, int *result_mdec)
+{
+ *result_mdec = qcom_vadc_scale_code_voltage_factor(adc_code,
+ prescale, data, 2);
+ *result_mdec -= KELVINMIL_CELSIUSMIL;
+
+ return 0;
+}
+
+static int qcom_vadc_scale_hw_smb_temp(
+ const struct vadc_prescale_ratio *prescale,
+ const struct adc5_data *data,
+ u16 adc_code, int *result_mdec)
+{
+ *result_mdec = qcom_vadc_scale_code_voltage_factor(adc_code * 100,
+ prescale, data, PMIC5_SMB_TEMP_SCALE_FACTOR);
+ *result_mdec = PMIC5_SMB_TEMP_CONSTANT - *result_mdec;
+
+ return 0;
+}
+
+static int qcom_vadc_scale_hw_chg5_temp(
+ const struct vadc_prescale_ratio *prescale,
+ const struct adc5_data *data,
+ u16 adc_code, int *result_mdec)
+{
+ *result_mdec = qcom_vadc_scale_code_voltage_factor(adc_code,
+ prescale, data, 4);
+ *result_mdec = PMIC5_CHG_TEMP_SCALE_FACTOR - *result_mdec;
+
+ return 0;
+}
+
int qcom_vadc_scale(enum vadc_scale_fn_type scaletype,
const struct vadc_linear_graph *calib_graph,
const struct vadc_prescale_ratio *prescale,
@@ -221,6 +384,22 @@ int qcom_vadc_scale(enum vadc_scale_fn_type scaletype,
}
EXPORT_SYMBOL(qcom_vadc_scale);
+int qcom_adc5_hw_scale(enum vadc_scale_fn_type scaletype,
+ const struct vadc_prescale_ratio *prescale,
+ const struct adc5_data *data,
+ u16 adc_code, int *result)
+{
+ if (!(scaletype >= SCALE_HW_CALIB_DEFAULT &&
+ scaletype < SCALE_HW_CALIB_INVALID)) {
+ pr_err("Invalid scale type %d\n", scaletype);
+ return -EINVAL;
+ }
+
+ return scale_adc5_fn[scaletype].scale_fn(prescale, data,
+ adc_code, result);
+}
+EXPORT_SYMBOL(qcom_adc5_hw_scale);
+
int qcom_vadc_decimation_from_dt(u32 value)
{
if (!is_power_of_2(value) || value < VADC_DECIMATION_MIN ||
diff --git a/drivers/iio/adc/qcom-vadc-common.h b/drivers/iio/adc/qcom-vadc-common.h
index 1d5354ff5c72..bbb1fa02b382 100644
--- a/drivers/iio/adc/qcom-vadc-common.h
+++ b/drivers/iio/adc/qcom-vadc-common.h
@@ -25,15 +25,31 @@
#define VADC_DECIMATION_MIN 512
#define VADC_DECIMATION_MAX 4096
+#define ADC5_DEF_VBAT_PRESCALING 1 /* 1:3 */
+#define ADC5_DECIMATION_SHORT 250
+#define ADC5_DECIMATION_MEDIUM 420
+#define ADC5_DECIMATION_LONG 840
+/* Default decimation - 1024 for rev2, 840 for pmic5 */
+#define ADC5_DECIMATION_DEFAULT 2
+#define ADC5_DECIMATION_SAMPLES_MAX 3
#define VADC_HW_SETTLE_DELAY_MAX 10000
+#define VADC_HW_SETTLE_SAMPLES_MAX 16
#define VADC_AVG_SAMPLES_MAX 512
+#define ADC5_AVG_SAMPLES_MAX 16
#define KELVINMIL_CELSIUSMIL 273150
+#define PMIC5_CHG_TEMP_SCALE_FACTOR 377500
+#define PMIC5_SMB_TEMP_CONSTANT 419400
+#define PMIC5_SMB_TEMP_SCALE_FACTOR 356
#define PMI_CHG_SCALE_1 -138890
#define PMI_CHG_SCALE_2 391750000000LL
+#define VADC5_MAX_CODE 0x7fff
+#define ADC5_FULL_SCALE_CODE 0x70e4
+#define ADC5_USR_DATA_CHECK 0x8000
+
/**
* struct vadc_map_pt - Map the graph representation for ADC channel
* @x: Represent the ADC digitized code.
@@ -89,6 +105,18 @@ struct vadc_prescale_ratio {
* SCALE_PMIC_THERM: Returns result in milli degree's Centigrade.
* SCALE_XOTHERM: Returns XO thermistor voltage in millidegC.
* SCALE_PMI_CHG_TEMP: Conversion for PMI CHG temp
+ * SCALE_HW_CALIB_DEFAULT: Default scaling to convert raw adc code to
+ * voltage (uV) with hardware applied offset/slope values to adc code.
+ * SCALE_HW_CALIB_THERM_100K_PULLUP: Returns temperature in millidegC using
+ * lookup table. The hardware applies offset/slope to adc code.
+ * SCALE_HW_CALIB_XOTHERM: Returns XO thermistor voltage in millidegC using
+ * 100k pullup. The hardware applies offset/slope to adc code.
+ * SCALE_HW_CALIB_PMIC_THERM: Returns result in milli degree's Centigrade.
+ * The hardware applies offset/slope to adc code.
+ * SCALE_HW_CALIB_PM5_CHG_TEMP: Returns result in millidegrees for PMIC5
+ * charger temperature.
+ * SCALE_HW_CALIB_PM5_SMB_TEMP: Returns result in millidegrees for PMIC5
+ * SMB1390 temperature.
*/
enum vadc_scale_fn_type {
SCALE_DEFAULT = 0,
@@ -96,6 +124,22 @@ enum vadc_scale_fn_type {
SCALE_PMIC_THERM,
SCALE_XOTHERM,
SCALE_PMI_CHG_TEMP,
+ SCALE_HW_CALIB_DEFAULT,
+ SCALE_HW_CALIB_THERM_100K_PULLUP,
+ SCALE_HW_CALIB_XOTHERM,
+ SCALE_HW_CALIB_PMIC_THERM,
+ SCALE_HW_CALIB_PM5_CHG_TEMP,
+ SCALE_HW_CALIB_PM5_SMB_TEMP,
+ SCALE_HW_CALIB_INVALID,
+};
+
+struct adc5_data {
+ const u32 full_scale_code_volt;
+ const u32 full_scale_code_cur;
+ const struct adc5_channels *adc_chans;
+ unsigned int *decimation;
+ unsigned int *hw_settle_1;
+ unsigned int *hw_settle_2;
};
int qcom_vadc_scale(enum vadc_scale_fn_type scaletype,
@@ -104,6 +148,16 @@ int qcom_vadc_scale(enum vadc_scale_fn_type scaletype,
bool absolute,
u16 adc_code, int *result_mdec);
+struct qcom_adc5_scale_type {
+ int (*scale_fn)(const struct vadc_prescale_ratio *prescale,
+ const struct adc5_data *data, u16 adc_code, int *result);
+};
+
+int qcom_adc5_hw_scale(enum vadc_scale_fn_type scaletype,
+ const struct vadc_prescale_ratio *prescale,
+ const struct adc5_data *data,
+ u16 adc_code, int *result_mdec);
+
int qcom_vadc_decimation_from_dt(u32 value);
#endif /* QCOM_VADC_COMMON_H */
diff --git a/drivers/iio/adc/rcar-gyroadc.c b/drivers/iio/adc/rcar-gyroadc.c
index dcb50172186f..4e982b51bcda 100644
--- a/drivers/iio/adc/rcar-gyroadc.c
+++ b/drivers/iio/adc/rcar-gyroadc.c
@@ -343,8 +343,8 @@ static int rcar_gyroadc_parse_subdevs(struct iio_dev *indio_dev)
for_each_child_of_node(np, child) {
of_id = of_match_node(rcar_gyroadc_child_match, child);
if (!of_id) {
- dev_err(dev, "Ignoring unsupported ADC \"%s\".",
- child->name);
+ dev_err(dev, "Ignoring unsupported ADC \"%pOFn\".",
+ child);
continue;
}
@@ -381,16 +381,16 @@ static int rcar_gyroadc_parse_subdevs(struct iio_dev *indio_dev)
ret = of_property_read_u32(child, "reg", &reg);
if (ret) {
dev_err(dev,
- "Failed to get child reg property of ADC \"%s\".\n",
- child->name);
+ "Failed to get child reg property of ADC \"%pOFn\".\n",
+ child);
return ret;
}
/* Channel number is too high. */
if (reg >= num_channels) {
dev_err(dev,
- "Only %i channels supported with %s, but reg = <%i>.\n",
- num_channels, child->name, reg);
+ "Only %i channels supported with %pOFn, but reg = <%i>.\n",
+ num_channels, child, reg);
return ret;
}
}
diff --git a/drivers/iio/adc/sc27xx_adc.c b/drivers/iio/adc/sc27xx_adc.c
index 2b60efea0c39..7940b23dcad9 100644
--- a/drivers/iio/adc/sc27xx_adc.c
+++ b/drivers/iio/adc/sc27xx_adc.c
@@ -5,10 +5,12 @@
#include <linux/iio/iio.h>
#include <linux/interrupt.h>
#include <linux/module.h>
+#include <linux/nvmem-consumer.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
+#include <linux/slab.h>
/* PMIC global registers definition */
#define SC27XX_MODULE_EN 0xc08
@@ -87,16 +89,73 @@ struct sc27xx_adc_linear_graph {
* should use the small-scale graph, and if more than 1.2v, we should use the
* big-scale graph.
*/
-static const struct sc27xx_adc_linear_graph big_scale_graph = {
+static struct sc27xx_adc_linear_graph big_scale_graph = {
4200, 3310,
3600, 2832,
};
-static const struct sc27xx_adc_linear_graph small_scale_graph = {
+static struct sc27xx_adc_linear_graph small_scale_graph = {
1000, 3413,
100, 341,
};
+static const struct sc27xx_adc_linear_graph big_scale_graph_calib = {
+ 4200, 856,
+ 3600, 733,
+};
+
+static const struct sc27xx_adc_linear_graph small_scale_graph_calib = {
+ 1000, 833,
+ 100, 80,
+};
+
+static int sc27xx_adc_get_calib_data(u32 calib_data, int calib_adc)
+{
+ return ((calib_data & 0xff) + calib_adc - 128) * 4;
+}
+
+static int sc27xx_adc_scale_calibration(struct sc27xx_adc_data *data,
+ bool big_scale)
+{
+ const struct sc27xx_adc_linear_graph *calib_graph;
+ struct sc27xx_adc_linear_graph *graph;
+ struct nvmem_cell *cell;
+ const char *cell_name;
+ u32 calib_data = 0;
+ void *buf;
+ size_t len;
+
+ if (big_scale) {
+ calib_graph = &big_scale_graph_calib;
+ graph = &big_scale_graph;
+ cell_name = "big_scale_calib";
+ } else {
+ calib_graph = &small_scale_graph_calib;
+ graph = &small_scale_graph;
+ cell_name = "small_scale_calib";
+ }
+
+ cell = nvmem_cell_get(data->dev, cell_name);
+ if (IS_ERR(cell))
+ return PTR_ERR(cell);
+
+ buf = nvmem_cell_read(cell, &len);
+ nvmem_cell_put(cell);
+
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
+
+ memcpy(&calib_data, buf, min(len, sizeof(u32)));
+
+ /* Only need to calibrate the adc values in the linear graph. */
+ graph->adc0 = sc27xx_adc_get_calib_data(calib_data, calib_graph->adc0);
+ graph->adc1 = sc27xx_adc_get_calib_data(calib_data >> 8,
+ calib_graph->adc1);
+
+ kfree(buf);
+ return 0;
+}
+
static int sc27xx_adc_get_ratio(int channel, int scale)
{
switch (channel) {
@@ -209,7 +268,7 @@ static void sc27xx_adc_volt_ratio(struct sc27xx_adc_data *data,
*div_denominator = ratio & SC27XX_RATIO_DENOMINATOR_MASK;
}
-static int sc27xx_adc_to_volt(const struct sc27xx_adc_linear_graph *graph,
+static int sc27xx_adc_to_volt(struct sc27xx_adc_linear_graph *graph,
int raw_adc)
{
int tmp;
@@ -273,6 +332,17 @@ static int sc27xx_adc_read_raw(struct iio_dev *indio_dev,
int ret, tmp;
switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ mutex_lock(&indio_dev->mlock);
+ ret = sc27xx_adc_read(data, chan->channel, scale, &tmp);
+ mutex_unlock(&indio_dev->mlock);
+
+ if (ret)
+ return ret;
+
+ *val = tmp;
+ return IIO_VAL_INT;
+
case IIO_CHAN_INFO_PROCESSED:
mutex_lock(&indio_dev->mlock);
ret = sc27xx_adc_read_processed(data, chan->channel, scale,
@@ -315,48 +385,47 @@ static const struct iio_info sc27xx_info = {
.write_raw = &sc27xx_adc_write_raw,
};
-#define SC27XX_ADC_CHANNEL(index) { \
+#define SC27XX_ADC_CHANNEL(index, mask) { \
.type = IIO_VOLTAGE, \
.channel = index, \
- .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | \
- BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_separate = mask | BIT(IIO_CHAN_INFO_SCALE), \
.datasheet_name = "CH##index", \
.indexed = 1, \
}
static const struct iio_chan_spec sc27xx_channels[] = {
- SC27XX_ADC_CHANNEL(0),
- SC27XX_ADC_CHANNEL(1),
- SC27XX_ADC_CHANNEL(2),
- SC27XX_ADC_CHANNEL(3),
- SC27XX_ADC_CHANNEL(4),
- SC27XX_ADC_CHANNEL(5),
- SC27XX_ADC_CHANNEL(6),
- SC27XX_ADC_CHANNEL(7),
- SC27XX_ADC_CHANNEL(8),
- SC27XX_ADC_CHANNEL(9),
- SC27XX_ADC_CHANNEL(10),
- SC27XX_ADC_CHANNEL(11),
- SC27XX_ADC_CHANNEL(12),
- SC27XX_ADC_CHANNEL(13),
- SC27XX_ADC_CHANNEL(14),
- SC27XX_ADC_CHANNEL(15),
- SC27XX_ADC_CHANNEL(16),
- SC27XX_ADC_CHANNEL(17),
- SC27XX_ADC_CHANNEL(18),
- SC27XX_ADC_CHANNEL(19),
- SC27XX_ADC_CHANNEL(20),
- SC27XX_ADC_CHANNEL(21),
- SC27XX_ADC_CHANNEL(22),
- SC27XX_ADC_CHANNEL(23),
- SC27XX_ADC_CHANNEL(24),
- SC27XX_ADC_CHANNEL(25),
- SC27XX_ADC_CHANNEL(26),
- SC27XX_ADC_CHANNEL(27),
- SC27XX_ADC_CHANNEL(28),
- SC27XX_ADC_CHANNEL(29),
- SC27XX_ADC_CHANNEL(30),
- SC27XX_ADC_CHANNEL(31),
+ SC27XX_ADC_CHANNEL(0, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(1, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(2, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(3, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(4, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(5, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(6, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(7, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(8, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(9, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(10, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(11, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(12, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(13, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(14, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(15, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(16, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(17, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(18, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(19, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(20, BIT(IIO_CHAN_INFO_RAW)),
+ SC27XX_ADC_CHANNEL(21, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(22, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(23, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(24, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(25, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(26, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(27, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(28, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(29, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(30, BIT(IIO_CHAN_INFO_PROCESSED)),
+ SC27XX_ADC_CHANNEL(31, BIT(IIO_CHAN_INFO_PROCESSED)),
};
static int sc27xx_adc_enable(struct sc27xx_adc_data *data)
@@ -380,6 +449,15 @@ static int sc27xx_adc_enable(struct sc27xx_adc_data *data)
if (ret)
goto disable_clk;
+ /* ADC channel scales' calibration from nvmem device */
+ ret = sc27xx_adc_scale_calibration(data, true);
+ if (ret)
+ goto disable_clk;
+
+ ret = sc27xx_adc_scale_calibration(data, false);
+ if (ret)
+ goto disable_clk;
+
return 0;
disable_clk:
diff --git a/drivers/iio/adc/ti-ads7950.c b/drivers/iio/adc/ti-ads7950.c
index a5bd5944bc66..0ad63592cc3c 100644
--- a/drivers/iio/adc/ti-ads7950.c
+++ b/drivers/iio/adc/ti-ads7950.c
@@ -51,7 +51,7 @@
struct ti_ads7950_state {
struct spi_device *spi;
- struct spi_transfer ring_xfer[TI_ADS7950_MAX_CHAN + 2];
+ struct spi_transfer ring_xfer;
struct spi_transfer scan_single_xfer[3];
struct spi_message ring_msg;
struct spi_message scan_single_msg;
@@ -65,11 +65,11 @@ struct ti_ads7950_state {
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
*/
- __be16 rx_buf[TI_ADS7950_MAX_CHAN + TI_ADS7950_TIMESTAMP_SIZE]
+ u16 rx_buf[TI_ADS7950_MAX_CHAN + 2 + TI_ADS7950_TIMESTAMP_SIZE]
____cacheline_aligned;
- __be16 tx_buf[TI_ADS7950_MAX_CHAN];
- __be16 single_tx;
- __be16 single_rx;
+ u16 tx_buf[TI_ADS7950_MAX_CHAN + 2];
+ u16 single_tx;
+ u16 single_rx;
};
@@ -108,7 +108,7 @@ enum ti_ads7950_id {
.realbits = bits, \
.storagebits = 16, \
.shift = 12 - (bits), \
- .endianness = IIO_BE, \
+ .endianness = IIO_CPU, \
}, \
}
@@ -249,23 +249,14 @@ static int ti_ads7950_update_scan_mode(struct iio_dev *indio_dev,
len = 0;
for_each_set_bit(i, active_scan_mask, indio_dev->num_channels) {
cmd = TI_ADS7950_CR_WRITE | TI_ADS7950_CR_CHAN(i) | st->settings;
- st->tx_buf[len++] = cpu_to_be16(cmd);
+ st->tx_buf[len++] = cmd;
}
/* Data for the 1st channel is not returned until the 3rd transfer */
- len += 2;
- for (i = 0; i < len; i++) {
- if ((i + 2) < len)
- st->ring_xfer[i].tx_buf = &st->tx_buf[i];
- if (i >= 2)
- st->ring_xfer[i].rx_buf = &st->rx_buf[i - 2];
- st->ring_xfer[i].len = 2;
- st->ring_xfer[i].cs_change = 1;
- }
- /* make sure last transfer's cs_change is not set */
- st->ring_xfer[len - 1].cs_change = 0;
+ st->tx_buf[len++] = 0;
+ st->tx_buf[len++] = 0;
- spi_message_init_with_transfers(&st->ring_msg, st->ring_xfer, len);
+ st->ring_xfer.len = len * 2;
return 0;
}
@@ -281,7 +272,7 @@ static irqreturn_t ti_ads7950_trigger_handler(int irq, void *p)
if (ret < 0)
goto out;
- iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf,
+ iio_push_to_buffers_with_timestamp(indio_dev, &st->rx_buf[2],
iio_get_time_ns(indio_dev));
out:
@@ -298,13 +289,13 @@ static int ti_ads7950_scan_direct(struct iio_dev *indio_dev, unsigned int ch)
mutex_lock(&indio_dev->mlock);
cmd = TI_ADS7950_CR_WRITE | TI_ADS7950_CR_CHAN(ch) | st->settings;
- st->single_tx = cpu_to_be16(cmd);
+ st->single_tx = cmd;
ret = spi_sync(st->spi, &st->scan_single_msg);
if (ret)
goto out;
- ret = be16_to_cpu(st->single_rx);
+ ret = st->single_rx;
out:
mutex_unlock(&indio_dev->mlock);
@@ -378,6 +369,14 @@ static int ti_ads7950_probe(struct spi_device *spi)
const struct ti_ads7950_chip_info *info;
int ret;
+ spi->bits_per_word = 16;
+ spi->mode |= SPI_CS_WORD;
+ ret = spi_setup(spi);
+ if (ret < 0) {
+ dev_err(&spi->dev, "Error in spi setup\n");
+ return ret;
+ }
+
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
@@ -398,6 +397,16 @@ static int ti_ads7950_probe(struct spi_device *spi)
indio_dev->num_channels = info->num_channels;
indio_dev->info = &ti_ads7950_info;
+ /* build spi ring message */
+ spi_message_init(&st->ring_msg);
+
+ st->ring_xfer.tx_buf = &st->tx_buf[0];
+ st->ring_xfer.rx_buf = &st->rx_buf[0];
+ /* len will be set later */
+ st->ring_xfer.cs_change = true;
+
+ spi_message_add_tail(&st->ring_xfer, &st->ring_msg);
+
/*
* Setup default message. The sample is read at the end of the first
* transfer, then it takes one full cycle to convert the sample and one
diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c
index 80df5a377d30..cafb1dcadc48 100644
--- a/drivers/iio/adc/ti_am335x_adc.c
+++ b/drivers/iio/adc/ti_am335x_adc.c
@@ -693,16 +693,12 @@ static int __maybe_unused tiadc_suspend(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct tiadc_device *adc_dev = iio_priv(indio_dev);
- struct ti_tscadc_dev *tscadc_dev;
unsigned int idle;
- tscadc_dev = ti_tscadc_dev_get(to_platform_device(dev));
- if (!device_may_wakeup(tscadc_dev->dev)) {
- idle = tiadc_readl(adc_dev, REG_CTRL);
- idle &= ~(CNTRLREG_TSCSSENB);
- tiadc_writel(adc_dev, REG_CTRL, (idle |
- CNTRLREG_POWERDOWN));
- }
+ idle = tiadc_readl(adc_dev, REG_CTRL);
+ idle &= ~(CNTRLREG_TSCSSENB);
+ tiadc_writel(adc_dev, REG_CTRL, (idle |
+ CNTRLREG_POWERDOWN));
return 0;
}
diff --git a/drivers/iio/amplifiers/ad8366.c b/drivers/iio/amplifiers/ad8366.c
index 0138337aedd1..4b76b61ba4be 100644
--- a/drivers/iio/amplifiers/ad8366.c
+++ b/drivers/iio/amplifiers/ad8366.c
@@ -209,6 +209,6 @@ static struct spi_driver ad8366_driver = {
module_spi_driver(ad8366_driver);
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD8366 VGA");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/chemical/bme680.h b/drivers/iio/chemical/bme680.h
index e049323f209a..0ae89b87e2d6 100644
--- a/drivers/iio/chemical/bme680.h
+++ b/drivers/iio/chemical/bme680.h
@@ -4,10 +4,10 @@
#define BME680_REG_CHIP_I2C_ID 0xD0
#define BME680_REG_CHIP_SPI_ID 0x50
-#define BME680_CHIP_ID_VAL 0x61
+#define BME680_CHIP_ID_VAL 0x61
#define BME680_REG_SOFT_RESET_I2C 0xE0
#define BME680_REG_SOFT_RESET_SPI 0x60
-#define BME680_CMD_SOFTRESET 0xB6
+#define BME680_CMD_SOFTRESET 0xB6
#define BME680_REG_STATUS 0x73
#define BME680_SPI_MEM_PAGE_BIT BIT(4)
#define BME680_SPI_MEM_PAGE_1_VAL 1
@@ -18,6 +18,7 @@
#define BME680_REG_GAS_MSB 0x2A
#define BME680_REG_GAS_R_LSB 0x2B
#define BME680_GAS_STAB_BIT BIT(4)
+#define BME680_GAS_RANGE_MASK GENMASK(3, 0)
#define BME680_REG_CTRL_HUMIDITY 0x72
#define BME680_OSRS_HUMIDITY_MASK GENMASK(2, 0)
@@ -26,9 +27,8 @@
#define BME680_OSRS_TEMP_MASK GENMASK(7, 5)
#define BME680_OSRS_PRESS_MASK GENMASK(4, 2)
#define BME680_MODE_MASK GENMASK(1, 0)
-
-#define BME680_MODE_FORCED 1
-#define BME680_MODE_SLEEP 0
+#define BME680_MODE_FORCED 1
+#define BME680_MODE_SLEEP 0
#define BME680_REG_CONFIG 0x75
#define BME680_FILTER_MASK GENMASK(4, 2)
@@ -39,24 +39,21 @@
#define BME680_MAX_OVERFLOW_VAL 0x40000000
#define BME680_HUM_REG_SHIFT_VAL 4
-#define BME680_BIT_H1_DATA_MSK 0x0F
+#define BME680_BIT_H1_DATA_MASK GENMASK(3, 0)
#define BME680_REG_RES_HEAT_RANGE 0x02
-#define BME680_RHRANGE_MSK 0x30
+#define BME680_RHRANGE_MASK GENMASK(5, 4)
#define BME680_REG_RES_HEAT_VAL 0x00
#define BME680_REG_RANGE_SW_ERR 0x04
-#define BME680_RSERROR_MSK 0xF0
+#define BME680_RSERROR_MASK GENMASK(7, 4)
#define BME680_REG_RES_HEAT_0 0x5A
#define BME680_REG_GAS_WAIT_0 0x64
-#define BME680_GAS_RANGE_MASK 0x0F
#define BME680_ADC_GAS_RES_SHIFT 6
#define BME680_AMB_TEMP 25
#define BME680_REG_CTRL_GAS_1 0x71
#define BME680_RUN_GAS_MASK BIT(4)
#define BME680_NB_CONV_MASK GENMASK(3, 0)
-#define BME680_RUN_GAS_EN_BIT BIT(4)
-#define BME680_NB_CONV_0_VAL 0
#define BME680_REG_MEAS_STAT_0 0x1D
#define BME680_GAS_MEAS_BIT BIT(6)
diff --git a/drivers/iio/chemical/bme680_core.c b/drivers/iio/chemical/bme680_core.c
index 7d9bb62baa3f..70c1fe4366f4 100644
--- a/drivers/iio/chemical/bme680_core.c
+++ b/drivers/iio/chemical/bme680_core.c
@@ -91,8 +91,6 @@ static const struct iio_chan_spec bme680_channels[] = {
},
};
-static const int bme680_oversampling_avail[] = { 1, 2, 4, 8, 16 };
-
static int bme680_read_calib(struct bme680_data *data,
struct bme680_calib *calib)
{
@@ -102,16 +100,14 @@ static int bme680_read_calib(struct bme680_data *data,
__le16 buf;
/* Temperature related coefficients */
- ret = regmap_bulk_read(data->regmap, BME680_T1_LSB_REG,
- (u8 *) &buf, 2);
+ ret = regmap_bulk_read(data->regmap, BME680_T1_LSB_REG, (u8 *) &buf, 2);
if (ret < 0) {
dev_err(dev, "failed to read BME680_T1_LSB_REG\n");
return ret;
}
calib->par_t1 = le16_to_cpu(buf);
- ret = regmap_bulk_read(data->regmap, BME680_T2_LSB_REG,
- (u8 *) &buf, 2);
+ ret = regmap_bulk_read(data->regmap, BME680_T2_LSB_REG, (u8 *) &buf, 2);
if (ret < 0) {
dev_err(dev, "failed to read BME680_T2_LSB_REG\n");
return ret;
@@ -126,16 +122,14 @@ static int bme680_read_calib(struct bme680_data *data,
calib->par_t3 = tmp;
/* Pressure related coefficients */
- ret = regmap_bulk_read(data->regmap, BME680_P1_LSB_REG,
- (u8 *) &buf, 2);
+ ret = regmap_bulk_read(data->regmap, BME680_P1_LSB_REG, (u8 *) &buf, 2);
if (ret < 0) {
dev_err(dev, "failed to read BME680_P1_LSB_REG\n");
return ret;
}
calib->par_p1 = le16_to_cpu(buf);
- ret = regmap_bulk_read(data->regmap, BME680_P2_LSB_REG,
- (u8 *) &buf, 2);
+ ret = regmap_bulk_read(data->regmap, BME680_P2_LSB_REG, (u8 *) &buf, 2);
if (ret < 0) {
dev_err(dev, "failed to read BME680_P2_LSB_REG\n");
return ret;
@@ -149,16 +143,14 @@ static int bme680_read_calib(struct bme680_data *data,
}
calib->par_p3 = tmp;
- ret = regmap_bulk_read(data->regmap, BME680_P4_LSB_REG,
- (u8 *) &buf, 2);
+ ret = regmap_bulk_read(data->regmap, BME680_P4_LSB_REG, (u8 *) &buf, 2);
if (ret < 0) {
dev_err(dev, "failed to read BME680_P4_LSB_REG\n");
return ret;
}
calib->par_p4 = le16_to_cpu(buf);
- ret = regmap_bulk_read(data->regmap, BME680_P5_LSB_REG,
- (u8 *) &buf, 2);
+ ret = regmap_bulk_read(data->regmap, BME680_P5_LSB_REG, (u8 *) &buf, 2);
if (ret < 0) {
dev_err(dev, "failed to read BME680_P5_LSB_REG\n");
return ret;
@@ -179,16 +171,14 @@ static int bme680_read_calib(struct bme680_data *data,
}
calib->par_p7 = tmp;
- ret = regmap_bulk_read(data->regmap, BME680_P8_LSB_REG,
- (u8 *) &buf, 2);
+ ret = regmap_bulk_read(data->regmap, BME680_P8_LSB_REG, (u8 *) &buf, 2);
if (ret < 0) {
dev_err(dev, "failed to read BME680_P8_LSB_REG\n");
return ret;
}
calib->par_p8 = le16_to_cpu(buf);
- ret = regmap_bulk_read(data->regmap, BME680_P9_LSB_REG,
- (u8 *) &buf, 2);
+ ret = regmap_bulk_read(data->regmap, BME680_P9_LSB_REG, (u8 *) &buf, 2);
if (ret < 0) {
dev_err(dev, "failed to read BME680_P9_LSB_REG\n");
return ret;
@@ -208,30 +198,26 @@ static int bme680_read_calib(struct bme680_data *data,
dev_err(dev, "failed to read BME680_H1_MSB_REG\n");
return ret;
}
-
ret = regmap_read(data->regmap, BME680_H1_LSB_REG, &tmp_lsb);
if (ret < 0) {
dev_err(dev, "failed to read BME680_H1_LSB_REG\n");
return ret;
}
-
calib->par_h1 = (tmp_msb << BME680_HUM_REG_SHIFT_VAL) |
- (tmp_lsb & BME680_BIT_H1_DATA_MSK);
+ (tmp_lsb & BME680_BIT_H1_DATA_MASK);
ret = regmap_read(data->regmap, BME680_H2_MSB_REG, &tmp_msb);
if (ret < 0) {
dev_err(dev, "failed to read BME680_H2_MSB_REG\n");
return ret;
}
-
ret = regmap_read(data->regmap, BME680_H2_LSB_REG, &tmp_lsb);
if (ret < 0) {
dev_err(dev, "failed to read BME680_H2_LSB_REG\n");
return ret;
}
-
calib->par_h2 = (tmp_msb << BME680_HUM_REG_SHIFT_VAL) |
- (tmp_lsb >> BME680_HUM_REG_SHIFT_VAL);
+ (tmp_lsb >> BME680_HUM_REG_SHIFT_VAL);
ret = regmap_read(data->regmap, BME680_H3_REG, &tmp);
if (ret < 0) {
@@ -276,8 +262,8 @@ static int bme680_read_calib(struct bme680_data *data,
}
calib->par_gh1 = tmp;
- ret = regmap_bulk_read(data->regmap, BME680_GH2_LSB_REG,
- (u8 *) &buf, 2);
+ ret = regmap_bulk_read(data->regmap, BME680_GH2_LSB_REG, (u8 *) &buf,
+ 2);
if (ret < 0) {
dev_err(dev, "failed to read BME680_GH2_LSB_REG\n");
return ret;
@@ -297,7 +283,7 @@ static int bme680_read_calib(struct bme680_data *data,
dev_err(dev, "failed to read resistance heat range\n");
return ret;
}
- calib->res_heat_range = (tmp & BME680_RHRANGE_MSK) / 16;
+ calib->res_heat_range = FIELD_GET(BME680_RHRANGE_MASK, tmp);
ret = regmap_read(data->regmap, BME680_REG_RES_HEAT_VAL, &tmp);
if (ret < 0) {
@@ -311,7 +297,7 @@ static int bme680_read_calib(struct bme680_data *data,
dev_err(dev, "failed to read range software error\n");
return ret;
}
- calib->range_sw_err = (tmp & BME680_RSERROR_MSK) / 16;
+ calib->range_sw_err = FIELD_GET(BME680_RSERROR_MASK, tmp);
return 0;
}
@@ -408,10 +394,7 @@ static u32 bme680_compensate_humid(struct bme680_data *data,
var6 = (var4 * var5) >> 1;
calc_hum = (((var3 + var6) >> 10) * 1000) >> 12;
- if (calc_hum > 100000) /* Cap at 100%rH */
- calc_hum = 100000;
- else if (calc_hum < 0)
- calc_hum = 0;
+ calc_hum = clamp(calc_hum, 0, 100000); /* clamp between 0-100 %rH */
return calc_hum;
}
@@ -518,12 +501,20 @@ static int bme680_set_mode(struct bme680_data *data, bool mode)
return ret;
}
+static u8 bme680_oversampling_to_reg(u8 val)
+{
+ return ilog2(val) + 1;
+}
+
static int bme680_chip_config(struct bme680_data *data)
{
struct device *dev = regmap_get_device(data->regmap);
int ret;
- u8 osrs = FIELD_PREP(BME680_OSRS_HUMIDITY_MASK,
- data->oversampling_humid + 1);
+ u8 osrs;
+
+ osrs = FIELD_PREP(
+ BME680_OSRS_HUMIDITY_MASK,
+ bme680_oversampling_to_reg(data->oversampling_humid));
/*
* Highly recommended to set oversampling of humidity before
* temperature/pressure oversampling.
@@ -544,12 +535,12 @@ static int bme680_chip_config(struct bme680_data *data)
return ret;
}
- osrs = FIELD_PREP(BME680_OSRS_TEMP_MASK, data->oversampling_temp + 1) |
- FIELD_PREP(BME680_OSRS_PRESS_MASK, data->oversampling_press + 1);
-
+ osrs = FIELD_PREP(BME680_OSRS_TEMP_MASK,
+ bme680_oversampling_to_reg(data->oversampling_temp)) |
+ FIELD_PREP(BME680_OSRS_PRESS_MASK,
+ bme680_oversampling_to_reg(data->oversampling_press));
ret = regmap_write_bits(data->regmap, BME680_REG_CTRL_MEAS,
- BME680_OSRS_TEMP_MASK |
- BME680_OSRS_PRESS_MASK,
+ BME680_OSRS_TEMP_MASK | BME680_OSRS_PRESS_MASK,
osrs);
if (ret < 0)
dev_err(dev, "failed to write ctrl_meas register\n");
@@ -577,14 +568,15 @@ static int bme680_gas_config(struct bme680_data *data)
/* set target heating duration */
ret = regmap_write(data->regmap, BME680_REG_GAS_WAIT_0, heatr_dur);
if (ret < 0) {
- dev_err(dev, "failted to write gas_wait_0 register\n");
+ dev_err(dev, "failed to write gas_wait_0 register\n");
return ret;
}
- /* Selecting the runGas and NB conversion settings for the sensor */
+ /* Enable the gas sensor and select heater profile set-point 0 */
ret = regmap_update_bits(data->regmap, BME680_REG_CTRL_GAS_1,
BME680_RUN_GAS_MASK | BME680_NB_CONV_MASK,
- BME680_RUN_GAS_EN_BIT | BME680_NB_CONV_0_VAL);
+ FIELD_PREP(BME680_RUN_GAS_MASK, 1) |
+ FIELD_PREP(BME680_NB_CONV_MASK, 0));
if (ret < 0)
dev_err(dev, "failed to write ctrl_gas_1 register\n");
@@ -782,13 +774,13 @@ static int bme680_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
switch (chan->type) {
case IIO_TEMP:
- *val = 1 << data->oversampling_temp;
+ *val = data->oversampling_temp;
return IIO_VAL_INT;
case IIO_PRESSURE:
- *val = 1 << data->oversampling_press;
+ *val = data->oversampling_press;
return IIO_VAL_INT;
case IIO_HUMIDITYRELATIVE:
- *val = 1 << data->oversampling_humid;
+ *val = data->oversampling_humid;
return IIO_VAL_INT;
default:
return -EINVAL;
@@ -798,52 +790,9 @@ static int bme680_read_raw(struct iio_dev *indio_dev,
}
}
-static int bme680_write_oversampling_ratio_temp(struct bme680_data *data,
- int val)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(bme680_oversampling_avail); i++) {
- if (bme680_oversampling_avail[i] == val) {
- data->oversampling_temp = ilog2(val);
-
- return bme680_chip_config(data);
- }
- }
-
- return -EINVAL;
-}
-
-static int bme680_write_oversampling_ratio_press(struct bme680_data *data,
- int val)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(bme680_oversampling_avail); i++) {
- if (bme680_oversampling_avail[i] == val) {
- data->oversampling_press = ilog2(val);
-
- return bme680_chip_config(data);
- }
- }
-
- return -EINVAL;
-}
-
-static int bme680_write_oversampling_ratio_humid(struct bme680_data *data,
- int val)
+static bool bme680_is_valid_oversampling(int rate)
{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(bme680_oversampling_avail); i++) {
- if (bme680_oversampling_avail[i] == val) {
- data->oversampling_humid = ilog2(val);
-
- return bme680_chip_config(data);
- }
- }
-
- return -EINVAL;
+ return (rate > 0 && rate <= 16 && is_power_of_2(rate));
}
static int bme680_write_raw(struct iio_dev *indio_dev,
@@ -852,18 +801,31 @@ static int bme680_write_raw(struct iio_dev *indio_dev,
{
struct bme680_data *data = iio_priv(indio_dev);
+ if (val2 != 0)
+ return -EINVAL;
+
switch (mask) {
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ {
+ if (!bme680_is_valid_oversampling(val))
+ return -EINVAL;
+
switch (chan->type) {
case IIO_TEMP:
- return bme680_write_oversampling_ratio_temp(data, val);
+ data->oversampling_temp = val;
+ break;
case IIO_PRESSURE:
- return bme680_write_oversampling_ratio_press(data, val);
+ data->oversampling_press = val;
+ break;
case IIO_HUMIDITYRELATIVE:
- return bme680_write_oversampling_ratio_humid(data, val);
+ data->oversampling_humid = val;
+ break;
default:
return -EINVAL;
}
+
+ return bme680_chip_config(data);
+ }
default:
return -EINVAL;
}
@@ -925,9 +887,9 @@ int bme680_core_probe(struct device *dev, struct regmap *regmap,
indio_dev->modes = INDIO_DIRECT_MODE;
/* default values for the sensor */
- data->oversampling_humid = ilog2(2); /* 2X oversampling rate */
- data->oversampling_press = ilog2(4); /* 4X oversampling rate */
- data->oversampling_temp = ilog2(8); /* 8X oversampling rate */
+ data->oversampling_humid = 2; /* 2X oversampling rate */
+ data->oversampling_press = 4; /* 4X oversampling rate */
+ data->oversampling_temp = 8; /* 8X oversampling rate */
data->heater_temp = 320; /* degree Celsius */
data->heater_dur = 150; /* milliseconds */
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index 80beb64e9e0c..bb2057fd1b6f 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -120,6 +120,16 @@ config AD5624R_SPI
Say yes here to build support for Analog Devices AD5624R, AD5644R and
AD5664R converters (DAC). This driver uses the common SPI interface.
+config LTC1660
+ tristate "Linear Technology LTC1660/LTC1665 DAC SPI driver"
+ depends on SPI
+ help
+ Say yes here to build support for Linear Technology
+ LTC1660 and LTC1665 Digital to Analog Converters.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ltc1660.
+
config LTC2632
tristate "Linear Technology LTC2632-12/10/8 DAC spi driver"
depends on SPI
diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile
index a1b37cf99441..2ac93cc4a389 100644
--- a/drivers/iio/dac/Makefile
+++ b/drivers/iio/dac/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_CIO_DAC) += cio-dac.o
obj-$(CONFIG_DPOT_DAC) += dpot-dac.o
obj-$(CONFIG_DS4424) += ds4424.o
obj-$(CONFIG_LPC18XX_DAC) += lpc18xx_dac.o
+obj-$(CONFIG_LTC1660) += ltc1660.o
obj-$(CONFIG_LTC2632) += ltc2632.o
obj-$(CONFIG_M62332) += m62332.o
obj-$(CONFIG_MAX517) += max517.o
diff --git a/drivers/iio/dac/ad5064.c b/drivers/iio/dac/ad5064.c
index bf4fc40ec84d..2f98cb2a3b96 100644
--- a/drivers/iio/dac/ad5064.c
+++ b/drivers/iio/dac/ad5064.c
@@ -808,6 +808,40 @@ static int ad5064_set_config(struct ad5064_state *st, unsigned int val)
return ad5064_write(st, cmd, 0, val, 0);
}
+static int ad5064_request_vref(struct ad5064_state *st, struct device *dev)
+{
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < ad5064_num_vref(st); ++i)
+ st->vref_reg[i].supply = ad5064_vref_name(st, i);
+
+ if (!st->chip_info->internal_vref)
+ return devm_regulator_bulk_get(dev, ad5064_num_vref(st),
+ st->vref_reg);
+
+ /*
+ * This assumes that when the regulator has an internal VREF
+ * there is only one external VREF connection, which is
+ * currently the case for all supported devices.
+ */
+ st->vref_reg[0].consumer = devm_regulator_get_optional(dev, "vref");
+ if (!IS_ERR(st->vref_reg[0].consumer))
+ return 0;
+
+ ret = PTR_ERR(st->vref_reg[0].consumer);
+ if (ret != -ENODEV)
+ return ret;
+
+ /* If no external regulator was supplied use the internal VREF */
+ st->use_internal_vref = true;
+ ret = ad5064_set_config(st, AD5064_CONFIG_INT_VREF_ENABLE);
+ if (ret)
+ dev_err(dev, "Failed to enable internal vref: %d\n", ret);
+
+ return ret;
+}
+
static int ad5064_probe(struct device *dev, enum ad5064_type type,
const char *name, ad5064_write_func write)
{
@@ -828,22 +862,11 @@ static int ad5064_probe(struct device *dev, enum ad5064_type type,
st->dev = dev;
st->write = write;
- for (i = 0; i < ad5064_num_vref(st); ++i)
- st->vref_reg[i].supply = ad5064_vref_name(st, i);
+ ret = ad5064_request_vref(st, dev);
+ if (ret)
+ return ret;
- ret = devm_regulator_bulk_get(dev, ad5064_num_vref(st),
- st->vref_reg);
- if (ret) {
- if (!st->chip_info->internal_vref)
- return ret;
- st->use_internal_vref = true;
- ret = ad5064_set_config(st, AD5064_CONFIG_INT_VREF_ENABLE);
- if (ret) {
- dev_err(dev, "Failed to enable internal vref: %d\n",
- ret);
- return ret;
- }
- } else {
+ if (!st->use_internal_vref) {
ret = regulator_bulk_enable(ad5064_num_vref(st), st->vref_reg);
if (ret)
return ret;
diff --git a/drivers/iio/dac/ad5446.c b/drivers/iio/dac/ad5446.c
index fd26a4272fc5..c3426708b6b5 100644
--- a/drivers/iio/dac/ad5446.c
+++ b/drivers/iio/dac/ad5446.c
@@ -628,6 +628,6 @@ static void __exit ad5446_exit(void)
}
module_exit(ad5446_exit);
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD5444/AD5446 DAC");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/dac/ad5504.c b/drivers/iio/dac/ad5504.c
index d9037ea59168..0ae23a268017 100644
--- a/drivers/iio/dac/ad5504.c
+++ b/drivers/iio/dac/ad5504.c
@@ -369,6 +369,6 @@ static struct spi_driver ad5504_driver = {
};
module_spi_driver(ad5504_driver);
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD5501/AD5501 DAC");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c
index 2ddbfc3fdbae..0e134b13967a 100644
--- a/drivers/iio/dac/ad5686.c
+++ b/drivers/iio/dac/ad5686.c
@@ -470,6 +470,6 @@ int ad5686_remove(struct device *dev)
}
EXPORT_SYMBOL_GPL(ad5686_remove);
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD5686/85/84 DAC");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/dac/ad5758.c b/drivers/iio/dac/ad5758.c
index bd36333257af..ef41f12bf262 100644
--- a/drivers/iio/dac/ad5758.c
+++ b/drivers/iio/dac/ad5758.c
@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/property.h>
#include <linux/spi/spi.h>
+#include <linux/gpio/consumer.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -108,6 +109,7 @@ struct ad5758_range {
struct ad5758_state {
struct spi_device *spi;
struct mutex lock;
+ struct gpio_desc *gpio_reset;
struct ad5758_range out_range;
unsigned int dc_dc_mode;
unsigned int dc_dc_ilim;
@@ -474,6 +476,21 @@ static int ad5758_internal_buffers_en(struct ad5758_state *st, bool enable)
AD5758_CAL_MEM_UNREFRESHED_MSK);
}
+static int ad5758_reset(struct ad5758_state *st)
+{
+ if (st->gpio_reset) {
+ gpiod_set_value(st->gpio_reset, 0);
+ usleep_range(100, 1000);
+ gpiod_set_value(st->gpio_reset, 1);
+ usleep_range(100, 1000);
+
+ return 0;
+ } else {
+ /* Perform a software reset */
+ return ad5758_soft_reset(st);
+ }
+}
+
static int ad5758_reg_access(struct iio_dev *indio_dev,
unsigned int reg,
unsigned int writeval,
@@ -768,13 +785,18 @@ static int ad5758_init(struct ad5758_state *st)
{
int regval, ret;
+ st->gpio_reset = devm_gpiod_get_optional(&st->spi->dev, "reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(st->gpio_reset))
+ return PTR_ERR(st->gpio_reset);
+
/* Disable CRC checks */
ret = ad5758_crc_disable(st);
if (ret < 0)
return ret;
- /* Perform a software reset */
- ret = ad5758_soft_reset(st);
+ /* Perform a reset */
+ ret = ad5758_reset(st);
if (ret < 0)
return ret;
diff --git a/drivers/iio/dac/ad5791.c b/drivers/iio/dac/ad5791.c
index 7569bf6868c2..84ce5e6ecf3f 100644
--- a/drivers/iio/dac/ad5791.c
+++ b/drivers/iio/dac/ad5791.c
@@ -467,6 +467,6 @@ static struct spi_driver ad5791_driver = {
};
module_spi_driver(ad5791_driver);
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD5760/AD5780/AD5781/AD5790/AD5791 DAC");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/dac/dpot-dac.c b/drivers/iio/dac/dpot-dac.c
index aaa2103d7c2b..a791d0a09d3b 100644
--- a/drivers/iio/dac/dpot-dac.c
+++ b/drivers/iio/dac/dpot-dac.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* IIO DAC emulation driver using a digital potentiometer
*
* Copyright (C) 2016 Axentia Technologies AB
*
* Author: Peter Rosin <peda@axentia.se>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
/*
diff --git a/drivers/iio/dac/ltc1660.c b/drivers/iio/dac/ltc1660.c
new file mode 100644
index 000000000000..10866838c72a
--- /dev/null
+++ b/drivers/iio/dac/ltc1660.c
@@ -0,0 +1,250 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for Linear Technology LTC1665/LTC1660, 8 channels DAC
+ *
+ * Copyright (C) 2018 Marcus Folkesson <marcus.folkesson@gmail.com>
+ */
+#include <linux/bitops.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+
+#define LTC1660_REG_WAKE 0x0
+#define LTC1660_REG_DAC_A 0x1
+#define LTC1660_REG_DAC_B 0x2
+#define LTC1660_REG_DAC_C 0x3
+#define LTC1660_REG_DAC_D 0x4
+#define LTC1660_REG_DAC_E 0x5
+#define LTC1660_REG_DAC_F 0x6
+#define LTC1660_REG_DAC_G 0x7
+#define LTC1660_REG_DAC_H 0x8
+#define LTC1660_REG_SLEEP 0xe
+
+#define LTC1660_NUM_CHANNELS 8
+
+static const struct regmap_config ltc1660_regmap_config = {
+ .reg_bits = 4,
+ .val_bits = 12,
+};
+
+enum ltc1660_supported_device_ids {
+ ID_LTC1660,
+ ID_LTC1665,
+};
+
+struct ltc1660_priv {
+ struct spi_device *spi;
+ struct regmap *regmap;
+ struct regulator *vref_reg;
+ unsigned int value[LTC1660_NUM_CHANNELS];
+ unsigned int vref_mv;
+};
+
+static int ltc1660_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val,
+ int *val2,
+ long mask)
+{
+ struct ltc1660_priv *priv = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ *val = priv->value[chan->channel];
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = regulator_get_voltage(priv->vref_reg);
+ if (*val < 0) {
+ dev_err(&priv->spi->dev, "failed to read vref regulator: %d\n",
+ *val);
+ return *val;
+ }
+
+ /* Convert to mV */
+ *val /= 1000;
+ *val2 = chan->scan_type.realbits;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ltc1660_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val,
+ int val2,
+ long mask)
+{
+ struct ltc1660_priv *priv = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (val2 != 0)
+ return -EINVAL;
+
+ if (val < 0 || val > GENMASK(chan->scan_type.realbits - 1, 0))
+ return -EINVAL;
+
+ ret = regmap_write(priv->regmap, chan->channel,
+ (val << chan->scan_type.shift));
+ if (!ret)
+ priv->value[chan->channel] = val;
+
+ return ret;
+ default:
+ return -EINVAL;
+ }
+}
+
+#define LTC1660_CHAN(chan, bits) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .output = 1, \
+ .channel = chan, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = (bits), \
+ .storagebits = 16, \
+ .shift = 12 - (bits), \
+ }, \
+}
+
+#define LTC1660_OCTAL_CHANNELS(bits) { \
+ LTC1660_CHAN(LTC1660_REG_DAC_A, bits), \
+ LTC1660_CHAN(LTC1660_REG_DAC_B, bits), \
+ LTC1660_CHAN(LTC1660_REG_DAC_C, bits), \
+ LTC1660_CHAN(LTC1660_REG_DAC_D, bits), \
+ LTC1660_CHAN(LTC1660_REG_DAC_E, bits), \
+ LTC1660_CHAN(LTC1660_REG_DAC_F, bits), \
+ LTC1660_CHAN(LTC1660_REG_DAC_G, bits), \
+ LTC1660_CHAN(LTC1660_REG_DAC_H, bits), \
+}
+
+static const struct iio_chan_spec ltc1660_channels[][LTC1660_NUM_CHANNELS] = {
+ [ID_LTC1660] = LTC1660_OCTAL_CHANNELS(10),
+ [ID_LTC1665] = LTC1660_OCTAL_CHANNELS(8),
+};
+
+static const struct iio_info ltc1660_info = {
+ .read_raw = &ltc1660_read_raw,
+ .write_raw = &ltc1660_write_raw,
+};
+
+static int __maybe_unused ltc1660_suspend(struct device *dev)
+{
+ struct ltc1660_priv *priv = iio_priv(spi_get_drvdata(
+ to_spi_device(dev)));
+ return regmap_write(priv->regmap, LTC1660_REG_SLEEP, 0x00);
+}
+
+static int __maybe_unused ltc1660_resume(struct device *dev)
+{
+ struct ltc1660_priv *priv = iio_priv(spi_get_drvdata(
+ to_spi_device(dev)));
+ return regmap_write(priv->regmap, LTC1660_REG_WAKE, 0x00);
+}
+static SIMPLE_DEV_PM_OPS(ltc1660_pm_ops, ltc1660_suspend, ltc1660_resume);
+
+static int ltc1660_probe(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev;
+ struct ltc1660_priv *priv;
+ const struct spi_device_id *id = spi_get_device_id(spi);
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*priv));
+ if (indio_dev == NULL)
+ return -ENOMEM;
+
+ priv = iio_priv(indio_dev);
+ priv->regmap = devm_regmap_init_spi(spi, &ltc1660_regmap_config);
+ if (IS_ERR(priv->regmap)) {
+ dev_err(&spi->dev, "failed to register spi regmap %ld\n",
+ PTR_ERR(priv->regmap));
+ return PTR_ERR(priv->regmap);
+ }
+
+ priv->vref_reg = devm_regulator_get(&spi->dev, "vref");
+ if (IS_ERR(priv->vref_reg)) {
+ dev_err(&spi->dev, "vref regulator not specified\n");
+ return PTR_ERR(priv->vref_reg);
+ }
+
+ ret = regulator_enable(priv->vref_reg);
+ if (ret) {
+ dev_err(&spi->dev, "failed to enable vref regulator: %d\n",
+ ret);
+ return ret;
+ }
+
+ priv->spi = spi;
+ spi_set_drvdata(spi, indio_dev);
+ indio_dev->dev.parent = &spi->dev;
+ indio_dev->info = &ltc1660_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = ltc1660_channels[id->driver_data];
+ indio_dev->num_channels = LTC1660_NUM_CHANNELS;
+ indio_dev->name = id->name;
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(&spi->dev, "failed to register iio device: %d\n",
+ ret);
+ goto error_disable_reg;
+ }
+
+ return 0;
+
+error_disable_reg:
+ regulator_disable(priv->vref_reg);
+
+ return ret;
+}
+
+static int ltc1660_remove(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
+ struct ltc1660_priv *priv = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ regulator_disable(priv->vref_reg);
+
+ return 0;
+}
+
+static const struct of_device_id ltc1660_dt_ids[] = {
+ { .compatible = "lltc,ltc1660", .data = (void *)ID_LTC1660 },
+ { .compatible = "lltc,ltc1665", .data = (void *)ID_LTC1665 },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ltc1660_dt_ids);
+
+static const struct spi_device_id ltc1660_id[] = {
+ {"ltc1660", ID_LTC1660},
+ {"ltc1665", ID_LTC1665},
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(spi, ltc1660_id);
+
+static struct spi_driver ltc1660_driver = {
+ .driver = {
+ .name = "ltc1660",
+ .of_match_table = ltc1660_dt_ids,
+ .pm = &ltc1660_pm_ops,
+ },
+ .probe = ltc1660_probe,
+ .remove = ltc1660_remove,
+ .id_table = ltc1660_id,
+};
+module_spi_driver(ltc1660_driver);
+
+MODULE_AUTHOR("Marcus Folkesson <marcus.folkesson@gmail.com>");
+MODULE_DESCRIPTION("Linear Technology LTC1660/LTC1665 DAC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/dac/max517.c b/drivers/iio/dac/max517.c
index 1d853247a205..451d10e323cf 100644
--- a/drivers/iio/dac/max517.c
+++ b/drivers/iio/dac/max517.c
@@ -113,15 +113,14 @@ static int max517_write_raw(struct iio_dev *indio_dev,
return ret;
}
-#ifdef CONFIG_PM_SLEEP
-static int max517_suspend(struct device *dev)
+static int __maybe_unused max517_suspend(struct device *dev)
{
u8 outbuf = COMMAND_PD;
return i2c_master_send(to_i2c_client(dev), &outbuf, 1);
}
-static int max517_resume(struct device *dev)
+static int __maybe_unused max517_resume(struct device *dev)
{
u8 outbuf = 0;
@@ -129,10 +128,6 @@ static int max517_resume(struct device *dev)
}
static SIMPLE_DEV_PM_OPS(max517_pm_ops, max517_suspend, max517_resume);
-#define MAX517_PM_OPS (&max517_pm_ops)
-#else
-#define MAX517_PM_OPS NULL
-#endif
static const struct iio_info max517_info = {
.read_raw = max517_read_raw,
@@ -229,7 +224,7 @@ MODULE_DEVICE_TABLE(i2c, max517_id);
static struct i2c_driver max517_driver = {
.driver = {
.name = MAX517_DRV_NAME,
- .pm = MAX517_PM_OPS,
+ .pm = &max517_pm_ops,
},
.probe = max517_probe,
.remove = max517_remove,
diff --git a/drivers/iio/dac/max5821.c b/drivers/iio/dac/max5821.c
index d0ecc1fdd8fc..f0cf6903dcd2 100644
--- a/drivers/iio/dac/max5821.c
+++ b/drivers/iio/dac/max5821.c
@@ -270,8 +270,7 @@ static int max5821_write_raw(struct iio_dev *indio_dev,
}
}
-#ifdef CONFIG_PM_SLEEP
-static int max5821_suspend(struct device *dev)
+static int __maybe_unused max5821_suspend(struct device *dev)
{
u8 outbuf[2] = { MAX5821_EXTENDED_COMMAND_MODE,
MAX5821_EXTENDED_DAC_A |
@@ -281,7 +280,7 @@ static int max5821_suspend(struct device *dev)
return i2c_master_send(to_i2c_client(dev), outbuf, 2);
}
-static int max5821_resume(struct device *dev)
+static int __maybe_unused max5821_resume(struct device *dev)
{
u8 outbuf[2] = { MAX5821_EXTENDED_COMMAND_MODE,
MAX5821_EXTENDED_DAC_A |
@@ -292,10 +291,6 @@ static int max5821_resume(struct device *dev)
}
static SIMPLE_DEV_PM_OPS(max5821_pm_ops, max5821_suspend, max5821_resume);
-#define MAX5821_PM_OPS (&max5821_pm_ops)
-#else
-#define MAX5821_PM_OPS NULL
-#endif /* CONFIG_PM_SLEEP */
static const struct iio_info max5821_info = {
.read_raw = max5821_read_raw,
@@ -392,7 +387,7 @@ static struct i2c_driver max5821_driver = {
.driver = {
.name = "max5821",
.of_match_table = max5821_of_match,
- .pm = MAX5821_PM_OPS,
+ .pm = &max5821_pm_ops,
},
.probe = max5821_probe,
.remove = max5821_remove,
diff --git a/drivers/iio/dac/mcp4725.c b/drivers/iio/dac/mcp4725.c
index 8b5aad4c32d9..6d71fd905e29 100644
--- a/drivers/iio/dac/mcp4725.c
+++ b/drivers/iio/dac/mcp4725.c
@@ -45,7 +45,7 @@ struct mcp4725_data {
struct regulator *vref_reg;
};
-static int mcp4725_suspend(struct device *dev)
+static int __maybe_unused mcp4725_suspend(struct device *dev)
{
struct mcp4725_data *data = iio_priv(i2c_get_clientdata(
to_i2c_client(dev)));
@@ -58,7 +58,7 @@ static int mcp4725_suspend(struct device *dev)
return i2c_master_send(data->client, outbuf, 2);
}
-static int mcp4725_resume(struct device *dev)
+static int __maybe_unused mcp4725_resume(struct device *dev)
{
struct mcp4725_data *data = iio_priv(i2c_get_clientdata(
to_i2c_client(dev)));
@@ -71,13 +71,7 @@ static int mcp4725_resume(struct device *dev)
return i2c_master_send(data->client, outbuf, 2);
}
-
-#ifdef CONFIG_PM_SLEEP
static SIMPLE_DEV_PM_OPS(mcp4725_pm_ops, mcp4725_suspend, mcp4725_resume);
-#define MCP4725_PM_OPS (&mcp4725_pm_ops)
-#else
-#define MCP4725_PM_OPS NULL
-#endif
static ssize_t mcp4725_store_eeprom(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
@@ -547,7 +541,7 @@ static struct i2c_driver mcp4725_driver = {
.driver = {
.name = MCP4725_DRV_NAME,
.of_match_table = of_match_ptr(mcp4725_of_match),
- .pm = MCP4725_PM_OPS,
+ .pm = &mcp4725_pm_ops,
},
.probe = mcp4725_probe,
.remove = mcp4725_remove,
diff --git a/drivers/iio/dac/mcp4922.c b/drivers/iio/dac/mcp4922.c
index bf9aa3fc0534..b5190d1dae8e 100644
--- a/drivers/iio/dac/mcp4922.c
+++ b/drivers/iio/dac/mcp4922.c
@@ -94,17 +94,22 @@ static int mcp4922_write_raw(struct iio_dev *indio_dev,
long mask)
{
struct mcp4922_state *state = iio_priv(indio_dev);
+ int ret;
if (val2 != 0)
return -EINVAL;
switch (mask) {
case IIO_CHAN_INFO_RAW:
- if (val > GENMASK(chan->scan_type.realbits-1, 0))
+ if (val < 0 || val > GENMASK(chan->scan_type.realbits - 1, 0))
return -EINVAL;
val <<= chan->scan_type.shift;
- state->value[chan->channel] = val;
- return mcp4922_spi_write(state, chan->channel, val);
+
+ ret = mcp4922_spi_write(state, chan->channel, val);
+ if (!ret)
+ state->value[chan->channel] = val;
+ return ret;
+
default:
return -EINVAL;
}
diff --git a/drivers/iio/dac/ti-dac5571.c b/drivers/iio/dac/ti-dac5571.c
index e39d1e901353..f6dcd8bce2b0 100644
--- a/drivers/iio/dac/ti-dac5571.c
+++ b/drivers/iio/dac/ti-dac5571.c
@@ -421,6 +421,7 @@ MODULE_DEVICE_TABLE(i2c, dac5571_id);
static struct i2c_driver dac5571_driver = {
.driver = {
.name = "ti-dac5571",
+ .of_match_table = of_match_ptr(dac5571_of_id),
},
.probe = dac5571_probe,
.remove = dac5571_remove,
diff --git a/drivers/iio/frequency/ad9523.c b/drivers/iio/frequency/ad9523.c
index f4a508107f0d..f3f94fbdd20a 100644
--- a/drivers/iio/frequency/ad9523.c
+++ b/drivers/iio/frequency/ad9523.c
@@ -1078,6 +1078,6 @@ static struct spi_driver ad9523_driver = {
};
module_spi_driver(ad9523_driver);
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD9523 CLOCKDIST/PLL");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/frequency/adf4350.c b/drivers/iio/frequency/adf4350.c
index 6d768431d90e..f4748ff243f7 100644
--- a/drivers/iio/frequency/adf4350.c
+++ b/drivers/iio/frequency/adf4350.c
@@ -388,7 +388,7 @@ static struct adf4350_platform_data *adf4350_parse_dt(struct device *dev)
if (!pdata)
return NULL;
- strncpy(&pdata->name[0], np->name, SPI_NAME_SIZE - 1);
+ snprintf(&pdata->name[0], SPI_NAME_SIZE - 1, "%pOFn", np);
tmp = 10000;
of_property_read_u32(np, "adi,channel-spacing", &tmp);
diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
index 15ccadc74891..3e29562ce374 100644
--- a/drivers/iio/health/max30102.c
+++ b/drivers/iio/health/max30102.c
@@ -282,9 +282,11 @@ static int max30102_read_measurement(struct max30102_data *data,
switch (measurements) {
case 3:
MAX30102_COPY_DATA(2);
- case 2: /* fall-through */
+ /* fall through */
+ case 2:
MAX30102_COPY_DATA(1);
- case 1: /* fall-through */
+ /* fall through */
+ case 1:
MAX30102_COPY_DATA(0);
break;
default:
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
index d80ef468508a..1e428c196a82 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
@@ -23,6 +23,7 @@
#include <linux/iio/iio.h>
#include <linux/acpi.h>
#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
#include "inv_mpu_iio.h"
/*
@@ -926,6 +927,39 @@ error_power_off:
return result;
}
+static int inv_mpu_core_enable_regulator(struct inv_mpu6050_state *st)
+{
+ int result;
+
+ result = regulator_enable(st->vddio_supply);
+ if (result) {
+ dev_err(regmap_get_device(st->map),
+ "Failed to enable regulator: %d\n", result);
+ } else {
+ /* Give the device a little bit of time to start up. */
+ usleep_range(35000, 70000);
+ }
+
+ return result;
+}
+
+static int inv_mpu_core_disable_regulator(struct inv_mpu6050_state *st)
+{
+ int result;
+
+ result = regulator_disable(st->vddio_supply);
+ if (result)
+ dev_err(regmap_get_device(st->map),
+ "Failed to disable regulator: %d\n", result);
+
+ return result;
+}
+
+static void inv_mpu_core_disable_regulator_action(void *_data)
+{
+ inv_mpu_core_disable_regulator(_data);
+}
+
int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
int (*inv_mpu_bus_setup)(struct iio_dev *), int chip_type)
{
@@ -992,6 +1026,28 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
return -EINVAL;
}
+ st->vddio_supply = devm_regulator_get(dev, "vddio");
+ if (IS_ERR(st->vddio_supply)) {
+ if (PTR_ERR(st->vddio_supply) != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get vddio regulator %d\n",
+ (int)PTR_ERR(st->vddio_supply));
+
+ return PTR_ERR(st->vddio_supply);
+ }
+
+ result = inv_mpu_core_enable_regulator(st);
+ if (result)
+ return result;
+
+ result = devm_add_action(dev, inv_mpu_core_disable_regulator_action,
+ st);
+ if (result) {
+ inv_mpu_core_disable_regulator_action(st);
+ dev_err(dev, "Failed to setup regulator cleanup action %d\n",
+ result);
+ return result;
+ }
+
/* power is turned on inside check chip type*/
result = inv_check_and_setup_chip(st);
if (result)
@@ -1051,7 +1107,12 @@ static int inv_mpu_resume(struct device *dev)
int result;
mutex_lock(&st->lock);
+ result = inv_mpu_core_enable_regulator(st);
+ if (result)
+ goto out_unlock;
+
result = inv_mpu6050_set_power_itg(st, true);
+out_unlock:
mutex_unlock(&st->lock);
return result;
@@ -1064,6 +1125,7 @@ static int inv_mpu_suspend(struct device *dev)
mutex_lock(&st->lock);
result = inv_mpu6050_set_power_itg(st, false);
+ inv_mpu_core_disable_regulator(st);
mutex_unlock(&st->lock);
return result;
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
index e69a59659dbc..6bcc11fc1b88 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
@@ -129,6 +129,7 @@ struct inv_mpu6050_hw {
* @chip_period: chip internal period estimation (~1kHz).
* @it_timestamp: timestamp from previous interrupt.
* @data_timestamp: timestamp for next data sample.
+ * @vddio_supply voltage regulator for the chip.
*/
struct inv_mpu6050_state {
struct mutex lock;
@@ -149,6 +150,7 @@ struct inv_mpu6050_state {
s64 chip_period;
s64 it_timestamp;
s64 data_timestamp;
+ struct regulator *vddio_supply;
};
/*register and associated bit definition*/
diff --git a/drivers/iio/imu/st_lsm6dsx/Kconfig b/drivers/iio/imu/st_lsm6dsx/Kconfig
index ccc817e17eb8..094fd006b63d 100644
--- a/drivers/iio/imu/st_lsm6dsx/Kconfig
+++ b/drivers/iio/imu/st_lsm6dsx/Kconfig
@@ -9,7 +9,7 @@ config IIO_ST_LSM6DSX
help
Say yes here to build support for STMicroelectronics LSM6DSx imu
sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm,
- ism330dlc
+ ism330dlc, lsm6dso
To compile this driver as a module, choose M here: the module
will be called st_lsm6dsx.
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
index edcd838037cd..ef73519a0fb6 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
@@ -19,6 +19,7 @@
#define ST_LSM6DSL_DEV_NAME "lsm6dsl"
#define ST_LSM6DSM_DEV_NAME "lsm6dsm"
#define ST_ISM330DLC_DEV_NAME "ism330dlc"
+#define ST_LSM6DSO_DEV_NAME "lsm6dso"
enum st_lsm6dsx_hw_id {
ST_LSM6DS3_ID,
@@ -26,14 +27,20 @@ enum st_lsm6dsx_hw_id {
ST_LSM6DSL_ID,
ST_LSM6DSM_ID,
ST_ISM330DLC_ID,
+ ST_LSM6DSO_ID,
ST_LSM6DSX_MAX_ID,
};
-#define ST_LSM6DSX_BUFF_SIZE 400
+#define ST_LSM6DSX_BUFF_SIZE 512
#define ST_LSM6DSX_CHAN_SIZE 2
#define ST_LSM6DSX_SAMPLE_SIZE 6
+#define ST_LSM6DSX_TAG_SIZE 1
+#define ST_LSM6DSX_TAGGED_SAMPLE_SIZE (ST_LSM6DSX_SAMPLE_SIZE + \
+ ST_LSM6DSX_TAG_SIZE)
#define ST_LSM6DSX_MAX_WORD_LEN ((32 / ST_LSM6DSX_SAMPLE_SIZE) * \
ST_LSM6DSX_SAMPLE_SIZE)
+#define ST_LSM6DSX_MAX_TAGGED_WORD_LEN ((32 / ST_LSM6DSX_TAGGED_SAMPLE_SIZE) \
+ * ST_LSM6DSX_TAGGED_SAMPLE_SIZE)
#define ST_LSM6DSX_SHIFT_VAL(val, mask) (((val) << __ffs(mask)) & (mask))
struct st_lsm6dsx_reg {
@@ -41,13 +48,17 @@ struct st_lsm6dsx_reg {
u8 mask;
};
+struct st_lsm6dsx_hw;
+
/**
* struct st_lsm6dsx_fifo_ops - ST IMU FIFO settings
+ * @read_fifo: Read FIFO callback.
* @fifo_th: FIFO threshold register info (addr + mask).
* @fifo_diff: FIFO diff status register info (addr + mask).
* @th_wl: FIFO threshold word length.
*/
struct st_lsm6dsx_fifo_ops {
+ int (*read_fifo)(struct st_lsm6dsx_hw *hw);
struct {
u8 addr;
u16 mask;
@@ -79,6 +90,7 @@ struct st_lsm6dsx_hw_ts_settings {
* @max_fifo_size: Sensor max fifo length in FIFO words.
* @id: List of hw id supported by the driver configuration.
* @decimator: List of decimator register info (addr + mask).
+ * @batch: List of FIFO batching register info (addr + mask).
* @fifo_ops: Sensor hw FIFO parameters.
* @ts_settings: Hw timer related settings.
*/
@@ -87,6 +99,7 @@ struct st_lsm6dsx_settings {
u16 max_fifo_size;
enum st_lsm6dsx_hw_id id[ST_LSM6DSX_MAX_ID];
struct st_lsm6dsx_reg decimator[ST_LSM6DSX_MAX_ID];
+ struct st_lsm6dsx_reg batch[ST_LSM6DSX_MAX_ID];
struct st_lsm6dsx_fifo_ops fifo_ops;
struct st_lsm6dsx_hw_ts_settings ts_settings;
};
@@ -175,5 +188,8 @@ int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor,
int st_lsm6dsx_flush_fifo(struct st_lsm6dsx_hw *hw);
int st_lsm6dsx_set_fifo_mode(struct st_lsm6dsx_hw *hw,
enum st_lsm6dsx_fifo_mode fifo_mode);
+int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw);
+int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw);
+int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, u8 *val);
#endif /* ST_LSM6DSX_H */
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
index 631360b14ca7..b5263fc522ca 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
@@ -12,6 +12,11 @@
* buffer contains the data of all the enabled FIFO data sets
* (e.g. Gx, Gy, Gz, Ax, Ay, Az), then data are repeated depending on the
* value of the decimation factor and ODR set for each FIFO data set.
+ *
+ * LSM6DSO: The FIFO buffer can be configured to store data from gyroscope and
+ * accelerometer. Each sample is queued with a tag (1B) indicating data source
+ * (gyroscope, accelerometer, hw timer).
+ *
* FIFO supported modes:
* - BYPASS: FIFO disabled
* - CONTINUOUS: FIFO enabled. When the buffer is full, the FIFO index
@@ -46,6 +51,7 @@
#define ST_LSM6DSX_FIFO_ODR_MASK GENMASK(6, 3)
#define ST_LSM6DSX_FIFO_EMPTY_MASK BIT(12)
#define ST_LSM6DSX_REG_FIFO_OUTL_ADDR 0x3e
+#define ST_LSM6DSX_REG_FIFO_OUT_TAG_ADDR 0x78
#define ST_LSM6DSX_REG_TS_RESET_ADDR 0x42
#define ST_LSM6DSX_MAX_FIFO_ODR_VAL 0x08
@@ -58,6 +64,12 @@ struct st_lsm6dsx_decimator_entry {
u8 val;
};
+enum st_lsm6dsx_fifo_tag {
+ ST_LSM6DSX_GYRO_TAG = 0x01,
+ ST_LSM6DSX_ACC_TAG = 0x02,
+ ST_LSM6DSX_TS_TAG = 0x04,
+};
+
static const
struct st_lsm6dsx_decimator_entry st_lsm6dsx_decimator_table[] = {
{ 0, 0x0 },
@@ -177,12 +189,34 @@ static int st_lsm6dsx_set_fifo_odr(struct st_lsm6dsx_sensor *sensor,
bool enable)
{
struct st_lsm6dsx_hw *hw = sensor->hw;
+ const struct st_lsm6dsx_reg *batch_reg;
u8 data;
- data = hw->enable_mask ? ST_LSM6DSX_MAX_FIFO_ODR_VAL : 0;
- return regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_FIFO_MODE_ADDR,
- ST_LSM6DSX_FIFO_ODR_MASK,
- FIELD_PREP(ST_LSM6DSX_FIFO_ODR_MASK, data));
+ batch_reg = &hw->settings->batch[sensor->id];
+ if (batch_reg->addr) {
+ int val;
+
+ if (enable) {
+ int err;
+
+ err = st_lsm6dsx_check_odr(sensor, sensor->odr,
+ &data);
+ if (err < 0)
+ return err;
+ } else {
+ data = 0;
+ }
+ val = ST_LSM6DSX_SHIFT_VAL(data, batch_reg->mask);
+ return regmap_update_bits(hw->regmap, batch_reg->addr,
+ batch_reg->mask, val);
+ } else {
+ data = hw->enable_mask ? ST_LSM6DSX_MAX_FIFO_ODR_VAL : 0;
+ return regmap_update_bits(hw->regmap,
+ ST_LSM6DSX_REG_FIFO_MODE_ADDR,
+ ST_LSM6DSX_FIFO_ODR_MASK,
+ FIELD_PREP(ST_LSM6DSX_FIFO_ODR_MASK,
+ data));
+ }
}
int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor, u16 watermark)
@@ -250,21 +284,21 @@ static int st_lsm6dsx_reset_hw_ts(struct st_lsm6dsx_hw *hw)
}
/*
- * Set max bulk read to ST_LSM6DSX_MAX_WORD_LEN in order to avoid
- * a kmalloc for each bus access
+ * Set max bulk read to ST_LSM6DSX_MAX_WORD_LEN/ST_LSM6DSX_MAX_TAGGED_WORD_LEN
+ * in order to avoid a kmalloc for each bus access
*/
-static inline int st_lsm6dsx_read_block(struct st_lsm6dsx_hw *hw, u8 *data,
- unsigned int data_len)
+static inline int st_lsm6dsx_read_block(struct st_lsm6dsx_hw *hw, u8 addr,
+ u8 *data, unsigned int data_len,
+ unsigned int max_word_len)
{
unsigned int word_len, read_len = 0;
int err;
while (read_len < data_len) {
word_len = min_t(unsigned int, data_len - read_len,
- ST_LSM6DSX_MAX_WORD_LEN);
- err = regmap_bulk_read(hw->regmap,
- ST_LSM6DSX_REG_FIFO_OUTL_ADDR,
- data + read_len, word_len);
+ max_word_len);
+ err = regmap_bulk_read(hw->regmap, addr, data + read_len,
+ word_len);
if (err < 0)
return err;
read_len += word_len;
@@ -282,7 +316,7 @@ static inline int st_lsm6dsx_read_block(struct st_lsm6dsx_hw *hw, u8 *data,
*
* Return: Number of bytes read from the FIFO
*/
-static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
+int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
{
u16 fifo_len, pattern_len = hw->sip * ST_LSM6DSX_SAMPLE_SIZE;
u16 fifo_diff_mask = hw->settings->fifo_ops.fifo_diff.mask;
@@ -314,7 +348,9 @@ static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
gyro_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_GYRO]);
for (read_len = 0; read_len < fifo_len; read_len += pattern_len) {
- err = st_lsm6dsx_read_block(hw, hw->buff, pattern_len);
+ err = st_lsm6dsx_read_block(hw, ST_LSM6DSX_REG_FIFO_OUTL_ADDR,
+ hw->buff, pattern_len,
+ ST_LSM6DSX_MAX_WORD_LEN);
if (err < 0) {
dev_err(hw->dev,
"failed to read pattern from fifo (err=%d)\n",
@@ -400,13 +436,111 @@ static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
return read_len;
}
+/**
+ * st_lsm6dsx_read_tagged_fifo() - LSM6DSO read FIFO routine
+ * @hw: Pointer to instance of struct st_lsm6dsx_hw.
+ *
+ * Read samples from the hw FIFO and push them to IIO buffers.
+ *
+ * Return: Number of bytes read from the FIFO
+ */
+int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw)
+{
+ u16 pattern_len = hw->sip * ST_LSM6DSX_TAGGED_SAMPLE_SIZE;
+ u16 fifo_len, fifo_diff_mask;
+ struct st_lsm6dsx_sensor *acc_sensor, *gyro_sensor;
+ u8 iio_buff[ST_LSM6DSX_IIO_BUFF_SIZE], tag;
+ bool reset_ts = false;
+ int i, err, read_len;
+ __le16 fifo_status;
+ s64 ts = 0;
+
+ err = regmap_bulk_read(hw->regmap,
+ hw->settings->fifo_ops.fifo_diff.addr,
+ &fifo_status, sizeof(fifo_status));
+ if (err < 0) {
+ dev_err(hw->dev, "failed to read fifo status (err=%d)\n",
+ err);
+ return err;
+ }
+
+ fifo_diff_mask = hw->settings->fifo_ops.fifo_diff.mask;
+ fifo_len = (le16_to_cpu(fifo_status) & fifo_diff_mask) *
+ ST_LSM6DSX_TAGGED_SAMPLE_SIZE;
+ if (!fifo_len)
+ return 0;
+
+ acc_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_ACC]);
+ gyro_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_GYRO]);
+
+ for (read_len = 0; read_len < fifo_len; read_len += pattern_len) {
+ err = st_lsm6dsx_read_block(hw,
+ ST_LSM6DSX_REG_FIFO_OUT_TAG_ADDR,
+ hw->buff, pattern_len,
+ ST_LSM6DSX_MAX_TAGGED_WORD_LEN);
+ if (err < 0) {
+ dev_err(hw->dev,
+ "failed to read pattern from fifo (err=%d)\n",
+ err);
+ return err;
+ }
+
+ for (i = 0; i < pattern_len;
+ i += ST_LSM6DSX_TAGGED_SAMPLE_SIZE) {
+ memcpy(iio_buff, &hw->buff[i + ST_LSM6DSX_TAG_SIZE],
+ ST_LSM6DSX_SAMPLE_SIZE);
+
+ tag = hw->buff[i] >> 3;
+ switch (tag) {
+ case ST_LSM6DSX_TS_TAG:
+ /*
+ * hw timestamp is 4B long and it is stored
+ * in FIFO according to this schema:
+ * B0 = ts[7:0], B1 = ts[15:8], B2 = ts[23:16],
+ * B3 = ts[31:24]
+ */
+ ts = le32_to_cpu(*((__le32 *)iio_buff));
+ /*
+ * check if hw timestamp engine is going to
+ * reset (the sensor generates an interrupt
+ * to signal the hw timestamp will reset in
+ * 1.638s)
+ */
+ if (!reset_ts && ts >= 0xffff0000)
+ reset_ts = true;
+ ts *= ST_LSM6DSX_TS_SENSITIVITY;
+ break;
+ case ST_LSM6DSX_GYRO_TAG:
+ iio_push_to_buffers_with_timestamp(
+ hw->iio_devs[ST_LSM6DSX_ID_GYRO],
+ iio_buff, gyro_sensor->ts_ref + ts);
+ break;
+ case ST_LSM6DSX_ACC_TAG:
+ iio_push_to_buffers_with_timestamp(
+ hw->iio_devs[ST_LSM6DSX_ID_ACC],
+ iio_buff, acc_sensor->ts_ref + ts);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (unlikely(reset_ts)) {
+ err = st_lsm6dsx_reset_hw_ts(hw);
+ if (err < 0)
+ return err;
+ }
+ return read_len;
+}
+
int st_lsm6dsx_flush_fifo(struct st_lsm6dsx_hw *hw)
{
int err;
mutex_lock(&hw->fifo_lock);
- st_lsm6dsx_read_fifo(hw);
+ hw->settings->fifo_ops.read_fifo(hw);
err = st_lsm6dsx_set_fifo_mode(hw, ST_LSM6DSX_FIFO_BYPASS);
mutex_unlock(&hw->fifo_lock);
@@ -478,7 +612,7 @@ static irqreturn_t st_lsm6dsx_handler_thread(int irq, void *private)
int count;
mutex_lock(&hw->fifo_lock);
- count = st_lsm6dsx_read_fifo(hw);
+ count = hw->settings->fifo_ops.read_fifo(hw);
mutex_unlock(&hw->fifo_lock);
return !count ? IRQ_NONE : IRQ_HANDLED;
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
index aebbe0ddd8d8..2ad3c610e4b6 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
@@ -23,6 +23,12 @@
* - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
* - FIFO size: 4KB
*
+ * - LSM6DSO
+ * - Accelerometer/Gyroscope supported ODR [Hz]: 13, 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: 3KB
+ *
* Copyright 2016 STMicroelectronics Inc.
*
* Lorenzo Bianconi <lorenzo.bianconi@st.com>
@@ -171,6 +177,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
},
},
.fifo_ops = {
+ .read_fifo = st_lsm6dsx_read_fifo,
.fifo_th = {
.addr = 0x06,
.mask = GENMASK(11, 0),
@@ -217,6 +224,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
},
},
.fifo_ops = {
+ .read_fifo = st_lsm6dsx_read_fifo,
.fifo_th = {
.addr = 0x06,
.mask = GENMASK(11, 0),
@@ -265,6 +273,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
},
},
.fifo_ops = {
+ .read_fifo = st_lsm6dsx_read_fifo,
.fifo_th = {
.addr = 0x06,
.mask = GENMASK(10, 0),
@@ -294,6 +303,45 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
},
},
},
+ {
+ .wai = 0x6c,
+ .max_fifo_size = 512,
+ .id = {
+ [0] = ST_LSM6DSO_ID,
+ },
+ .batch = {
+ [ST_LSM6DSX_ID_ACC] = {
+ .addr = 0x09,
+ .mask = GENMASK(3, 0),
+ },
+ [ST_LSM6DSX_ID_GYRO] = {
+ .addr = 0x09,
+ .mask = GENMASK(7, 4),
+ },
+ },
+ .fifo_ops = {
+ .read_fifo = st_lsm6dsx_read_tagged_fifo,
+ .fifo_th = {
+ .addr = 0x07,
+ .mask = GENMASK(8, 0),
+ },
+ .fifo_diff = {
+ .addr = 0x3a,
+ .mask = GENMASK(8, 0),
+ },
+ .th_wl = 1,
+ },
+ .ts_settings = {
+ .timer_en = {
+ .addr = 0x19,
+ .mask = BIT(5),
+ },
+ .decimator = {
+ .addr = 0x0a,
+ .mask = GENMASK(7, 6),
+ },
+ },
+ },
};
#define ST_LSM6DSX_CHANNEL(chan_type, addr, mod, scan_idx) \
@@ -395,8 +443,7 @@ static int st_lsm6dsx_set_full_scale(struct st_lsm6dsx_sensor *sensor,
return 0;
}
-static int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr,
- u8 *val)
+int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, u8 *val)
{
int i;
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
index 377c4e9997da..448b7bc1e578 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
@@ -61,6 +61,10 @@ static const struct of_device_id st_lsm6dsx_i2c_of_match[] = {
.compatible = "st,ism330dlc",
.data = (void *)ST_ISM330DLC_ID,
},
+ {
+ .compatible = "st,lsm6dso",
+ .data = (void *)ST_LSM6DSO_ID,
+ },
{},
};
MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match);
@@ -71,6 +75,7 @@ static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = {
{ ST_LSM6DSL_DEV_NAME, ST_LSM6DSL_ID },
{ ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID },
{ ST_ISM330DLC_DEV_NAME, ST_ISM330DLC_ID },
+ { ST_LSM6DSO_DEV_NAME, ST_LSM6DSO_ID },
{},
};
MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table);
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
index fec5c6ce7eb7..b1df8a6973e6 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
@@ -61,6 +61,10 @@ static const struct of_device_id st_lsm6dsx_spi_of_match[] = {
.compatible = "st,ism330dlc",
.data = (void *)ST_ISM330DLC_ID,
},
+ {
+ .compatible = "st,lsm6dso",
+ .data = (void *)ST_LSM6DSO_ID,
+ },
{},
};
MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match);
@@ -71,6 +75,7 @@ static const struct spi_device_id st_lsm6dsx_spi_id_table[] = {
{ ST_LSM6DSL_DEV_NAME, ST_LSM6DSL_ID },
{ ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID },
{ ST_ISM330DLC_DEV_NAME, ST_ISM330DLC_ID },
+ { ST_LSM6DSO_DEV_NAME, ST_LSM6DSO_ID },
{},
};
MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table);
diff --git a/drivers/iio/light/apds9960.c b/drivers/iio/light/apds9960.c
index 1f112ae15f3c..b09b8b60bd83 100644
--- a/drivers/iio/light/apds9960.c
+++ b/drivers/iio/light/apds9960.c
@@ -206,7 +206,8 @@ static const struct regmap_config apds9960_regmap_config = {
.name = APDS9960_REGMAP_NAME,
.reg_bits = 8,
.val_bits = 8,
- .use_single_rw = 1,
+ .use_single_read = true,
+ .use_single_write = true,
.volatile_table = &apds9960_volatile_table,
.precious_table = &apds9960_precious_table,
diff --git a/drivers/iio/light/bh1750.c b/drivers/iio/light/bh1750.c
index a814828e69f5..28347df78cff 100644
--- a/drivers/iio/light/bh1750.c
+++ b/drivers/iio/light/bh1750.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* ROHM BH1710/BH1715/BH1721/BH1750/BH1751 ambient light sensor driver
*
* Copyright (c) Tomasz Duszynski <tduszyns@gmail.com>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
* Data sheets:
* http://rohmfs.rohm.com/en/products/databook/datasheet/ic/sensor/light/bh1710fvc-e.pdf
* http://rohmfs.rohm.com/en/products/databook/datasheet/ic/sensor/light/bh1715fvc-e.pdf
@@ -281,8 +278,7 @@ static int bh1750_remove(struct i2c_client *client)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
-static int bh1750_suspend(struct device *dev)
+static int __maybe_unused bh1750_suspend(struct device *dev)
{
int ret;
struct bh1750_data *data =
@@ -300,10 +296,6 @@ static int bh1750_suspend(struct device *dev)
}
static SIMPLE_DEV_PM_OPS(bh1750_pm_ops, bh1750_suspend, NULL);
-#define BH1750_PM_OPS (&bh1750_pm_ops)
-#else
-#define BH1750_PM_OPS NULL
-#endif
static const struct i2c_device_id bh1750_id[] = {
{ "bh1710", BH1710 },
@@ -315,10 +307,21 @@ static const struct i2c_device_id bh1750_id[] = {
};
MODULE_DEVICE_TABLE(i2c, bh1750_id);
+static const struct of_device_id bh1750_of_match[] = {
+ { .compatible = "rohm,bh1710", },
+ { .compatible = "rohm,bh1715", },
+ { .compatible = "rohm,bh1721", },
+ { .compatible = "rohm,bh1750", },
+ { .compatible = "rohm,bh1751", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, bh1750_of_match);
+
static struct i2c_driver bh1750_driver = {
.driver = {
.name = "bh1750",
- .pm = BH1750_PM_OPS,
+ .of_match_table = bh1750_of_match,
+ .pm = &bh1750_pm_ops,
},
.probe = bh1750_probe,
.remove = bh1750_remove,
diff --git a/drivers/iio/light/max44000.c b/drivers/iio/light/max44000.c
index bcdb0eb9e537..d3fb460cfbdc 100644
--- a/drivers/iio/light/max44000.c
+++ b/drivers/iio/light/max44000.c
@@ -99,7 +99,6 @@ static const int max44000_alspga_shift[] = {0, 2, 4, 7};
* Handling this internally is also required for buffer support because the
* channel's scan_type can't be modified dynamically.
*/
-static const int max44000_alstim_shift[] = {0, 2, 4, 6};
#define MAX44000_ALSTIM_SHIFT(alstim) (2 * (alstim))
/* Available integration times with pretty manual alignment: */
@@ -473,17 +472,18 @@ static bool max44000_precious_reg(struct device *dev, unsigned int reg)
}
static const struct regmap_config max44000_regmap_config = {
- .reg_bits = 8,
- .val_bits = 8,
-
- .max_register = MAX44000_REG_PRX_DATA,
- .readable_reg = max44000_readable_reg,
- .writeable_reg = max44000_writeable_reg,
- .volatile_reg = max44000_volatile_reg,
- .precious_reg = max44000_precious_reg,
-
- .use_single_rw = 1,
- .cache_type = REGCACHE_RBTREE,
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = MAX44000_REG_PRX_DATA,
+ .readable_reg = max44000_readable_reg,
+ .writeable_reg = max44000_writeable_reg,
+ .volatile_reg = max44000_volatile_reg,
+ .precious_reg = max44000_precious_reg,
+
+ .use_single_read = true,
+ .use_single_write = true,
+ .cache_type = REGCACHE_RBTREE,
};
static irqreturn_t max44000_trigger_handler(int irq, void *p)
diff --git a/drivers/iio/light/tsl2772.c b/drivers/iio/light/tsl2772.c
index df5b2a0da96c..83cece921843 100644
--- a/drivers/iio/light/tsl2772.c
+++ b/drivers/iio/light/tsl2772.c
@@ -20,6 +20,7 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/platform_data/tsl2772.h>
+#include <linux/regulator/consumer.h>
/* Cal defs */
#define PROX_STAT_CAL 0
@@ -107,6 +108,11 @@
#define TSL2772_ALS_GAIN_TRIM_MIN 250
#define TSL2772_ALS_GAIN_TRIM_MAX 4000
+#define TSL2772_MAX_PROX_LEDS 2
+
+#define TSL2772_BOOT_MIN_SLEEP_TIME 10000
+#define TSL2772_BOOT_MAX_SLEEP_TIME 28000
+
/* Device family members */
enum {
tsl2571,
@@ -118,7 +124,8 @@ enum {
tsl2672,
tmd2672,
tsl2772,
- tmd2772
+ tmd2772,
+ apds9930,
};
enum {
@@ -141,11 +148,21 @@ struct tsl2772_chip_info {
const struct iio_info *info;
};
+static const int tsl2772_led_currents[][2] = {
+ { 100000, TSL2772_100_mA },
+ { 50000, TSL2772_50_mA },
+ { 25000, TSL2772_25_mA },
+ { 13000, TSL2772_13_mA },
+ { 0, 0 }
+};
+
struct tsl2772_chip {
kernel_ulong_t id;
struct mutex prox_mutex;
struct mutex als_mutex;
struct i2c_client *client;
+ struct regulator *vdd_supply;
+ struct regulator *vddio_supply;
u16 prox_data;
struct tsl2772_als_info als_cur_info;
struct tsl2772_settings settings;
@@ -197,6 +214,12 @@ static const struct tsl2772_lux tmd2x72_lux_table[TSL2772_DEF_LUX_TABLE_SZ] = {
{ 0, 0 },
};
+static const struct tsl2772_lux apds9930_lux_table[TSL2772_DEF_LUX_TABLE_SZ] = {
+ { 52000, 96824 },
+ { 38792, 67132 },
+ { 0, 0 },
+};
+
static const struct tsl2772_lux *tsl2772_default_lux_table_group[] = {
[tsl2571] = tsl2x71_lux_table,
[tsl2671] = tsl2x71_lux_table,
@@ -208,6 +231,7 @@ static const struct tsl2772_lux *tsl2772_default_lux_table_group[] = {
[tmd2672] = tmd2x72_lux_table,
[tsl2772] = tsl2x72_lux_table,
[tmd2772] = tmd2x72_lux_table,
+ [apds9930] = apds9930_lux_table,
};
static const struct tsl2772_settings tsl2772_default_settings = {
@@ -258,6 +282,7 @@ static const int tsl2772_int_time_avail[][6] = {
[tmd2672] = { 0, 2730, 0, 2730, 0, 699000 },
[tsl2772] = { 0, 2730, 0, 2730, 0, 699000 },
[tmd2772] = { 0, 2730, 0, 2730, 0, 699000 },
+ [apds9930] = { 0, 2730, 0, 2730, 0, 699000 },
};
static int tsl2772_int_calibscale_avail[] = { 1, 8, 16, 120 };
@@ -283,7 +308,8 @@ static const u8 device_channel_config[] = {
[tsl2672] = PRX2,
[tmd2672] = PRX2,
[tsl2772] = ALSPRX2,
- [tmd2772] = ALSPRX2
+ [tmd2772] = ALSPRX2,
+ [apds9930] = ALSPRX2,
};
static int tsl2772_read_status(struct tsl2772_chip *chip)
@@ -497,6 +523,7 @@ static int tsl2772_get_prox(struct iio_dev *indio_dev)
case tmd2672:
case tsl2772:
case tmd2772:
+ case apds9930:
if (!(ret & TSL2772_STA_PRX_VALID)) {
ret = -EINVAL;
goto prox_poll_err;
@@ -515,6 +542,75 @@ prox_poll_err:
return ret;
}
+static int tsl2772_read_prox_led_current(struct tsl2772_chip *chip)
+{
+ struct device_node *of_node = chip->client->dev.of_node;
+ int ret, tmp, i;
+
+ ret = of_property_read_u32(of_node, "led-max-microamp", &tmp);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; tsl2772_led_currents[i][0] != 0; i++) {
+ if (tmp == tsl2772_led_currents[i][0]) {
+ chip->settings.prox_power = tsl2772_led_currents[i][1];
+ return 0;
+ }
+ }
+
+ dev_err(&chip->client->dev, "Invalid value %d for led-max-microamp\n",
+ tmp);
+
+ return -EINVAL;
+
+}
+
+static int tsl2772_read_prox_diodes(struct tsl2772_chip *chip)
+{
+ struct device_node *of_node = chip->client->dev.of_node;
+ int i, ret, num_leds, prox_diode_mask;
+ u32 leds[TSL2772_MAX_PROX_LEDS];
+
+ ret = of_property_count_u32_elems(of_node, "amstaos,proximity-diodes");
+ if (ret < 0)
+ return ret;
+
+ num_leds = ret;
+ if (num_leds > TSL2772_MAX_PROX_LEDS)
+ num_leds = TSL2772_MAX_PROX_LEDS;
+
+ ret = of_property_read_u32_array(of_node, "amstaos,proximity-diodes",
+ leds, num_leds);
+ if (ret < 0) {
+ dev_err(&chip->client->dev,
+ "Invalid value for amstaos,proximity-diodes: %d.\n",
+ ret);
+ return ret;
+ }
+
+ prox_diode_mask = 0;
+ for (i = 0; i < num_leds; i++) {
+ if (leds[i] == 0)
+ prox_diode_mask |= TSL2772_DIODE0;
+ else if (leds[i] == 1)
+ prox_diode_mask |= TSL2772_DIODE1;
+ else {
+ dev_err(&chip->client->dev,
+ "Invalid value %d in amstaos,proximity-diodes.\n",
+ leds[i]);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static void tsl2772_parse_dt(struct tsl2772_chip *chip)
+{
+ tsl2772_read_prox_led_current(chip);
+ tsl2772_read_prox_diodes(chip);
+}
+
/**
* tsl2772_defaults() - Populates the device nominal operating parameters
* with those provided by a 'platform' data struct or
@@ -541,6 +637,8 @@ static void tsl2772_defaults(struct tsl2772_chip *chip)
memcpy(chip->tsl2772_device_lux,
tsl2772_default_lux_table_group[chip->id],
TSL2772_DEFAULT_TABLE_BYTES);
+
+ tsl2772_parse_dt(chip);
}
/**
@@ -595,6 +693,52 @@ static int tsl2772_als_calibrate(struct iio_dev *indio_dev)
return ret;
}
+static void tsl2772_disable_regulators_action(void *_data)
+{
+ struct tsl2772_chip *chip = _data;
+
+ regulator_disable(chip->vdd_supply);
+ regulator_disable(chip->vddio_supply);
+}
+
+static int tsl2772_enable_regulator(struct tsl2772_chip *chip,
+ struct regulator *regulator)
+{
+ int ret;
+
+ ret = regulator_enable(regulator);
+ if (ret < 0) {
+ dev_err(&chip->client->dev, "Failed to enable regulator: %d\n",
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct regulator *tsl2772_get_regulator(struct tsl2772_chip *chip,
+ char *name)
+{
+ struct regulator *regulator;
+ int ret;
+
+ regulator = devm_regulator_get(&chip->client->dev, name);
+ if (IS_ERR(regulator)) {
+ if (PTR_ERR(regulator) != -EPROBE_DEFER)
+ dev_err(&chip->client->dev,
+ "Failed to get %s regulator %d\n",
+ name, (int)PTR_ERR(regulator));
+
+ return regulator;
+ }
+
+ ret = tsl2772_enable_regulator(chip, regulator);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ return regulator;
+}
+
static int tsl2772_chip_on(struct iio_dev *indio_dev)
{
struct tsl2772_chip *chip = iio_priv(indio_dev);
@@ -1260,6 +1404,7 @@ static int tsl2772_device_id_verif(int id, int target)
case tmd2672:
case tsl2772:
case tmd2772:
+ case apds9930:
return (id & 0xf0) == SWORDFISH_ID;
}
@@ -1652,6 +1797,27 @@ static int tsl2772_probe(struct i2c_client *clientp,
chip->client = clientp;
i2c_set_clientdata(clientp, indio_dev);
+ chip->vddio_supply = tsl2772_get_regulator(chip, "vddio");
+ if (IS_ERR(chip->vddio_supply))
+ return PTR_ERR(chip->vddio_supply);
+
+ chip->vdd_supply = tsl2772_get_regulator(chip, "vdd");
+ if (IS_ERR(chip->vdd_supply)) {
+ regulator_disable(chip->vddio_supply);
+ return PTR_ERR(chip->vdd_supply);
+ }
+
+ ret = devm_add_action(&clientp->dev, tsl2772_disable_regulators_action,
+ chip);
+ if (ret < 0) {
+ tsl2772_disable_regulators_action(chip);
+ dev_err(&clientp->dev, "Failed to setup regulator cleanup action %d\n",
+ ret);
+ return ret;
+ }
+
+ usleep_range(TSL2772_BOOT_MIN_SLEEP_TIME, TSL2772_BOOT_MAX_SLEEP_TIME);
+
ret = i2c_smbus_read_byte_data(chip->client,
TSL2772_CMD_REG | TSL2772_CHIPID);
if (ret < 0)
@@ -1725,13 +1891,33 @@ static int tsl2772_probe(struct i2c_client *clientp,
static int tsl2772_suspend(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct tsl2772_chip *chip = iio_priv(indio_dev);
+ int ret;
+
+ ret = tsl2772_chip_off(indio_dev);
+ regulator_disable(chip->vdd_supply);
+ regulator_disable(chip->vddio_supply);
- return tsl2772_chip_off(indio_dev);
+ return ret;
}
static int tsl2772_resume(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct tsl2772_chip *chip = iio_priv(indio_dev);
+ int ret;
+
+ ret = tsl2772_enable_regulator(chip, chip->vddio_supply);
+ if (ret < 0)
+ return ret;
+
+ ret = tsl2772_enable_regulator(chip, chip->vdd_supply);
+ if (ret < 0) {
+ regulator_disable(chip->vddio_supply);
+ return ret;
+ }
+
+ usleep_range(TSL2772_BOOT_MIN_SLEEP_TIME, TSL2772_BOOT_MAX_SLEEP_TIME);
return tsl2772_chip_on(indio_dev);
}
@@ -1758,6 +1944,7 @@ static const struct i2c_device_id tsl2772_idtable[] = {
{ "tmd2672", tmd2672 },
{ "tsl2772", tsl2772 },
{ "tmd2772", tmd2772 },
+ { "apds9930", apds9930},
{}
};
@@ -1774,6 +1961,7 @@ static const struct of_device_id tsl2772_of_match[] = {
{ .compatible = "amstaos,tmd2672" },
{ .compatible = "amstaos,tsl2772" },
{ .compatible = "amstaos,tmd2772" },
+ { .compatible = "avago,apds9930" },
{}
};
MODULE_DEVICE_TABLE(of, tsl2772_of_match);
diff --git a/drivers/iio/magnetometer/hmc5843.h b/drivers/iio/magnetometer/hmc5843.h
index 76a5d7484d8d..a75224cf99df 100644
--- a/drivers/iio/magnetometer/hmc5843.h
+++ b/drivers/iio/magnetometer/hmc5843.h
@@ -31,7 +31,7 @@ enum hmc5843_ids {
};
/**
- * struct hcm5843_data - device specific data
+ * struct hmc5843_data - device specific data
* @dev: actual device
* @lock: update and read regmap data
* @regmap: hardware access register maps
diff --git a/drivers/iio/multiplexer/iio-mux.c b/drivers/iio/multiplexer/iio-mux.c
index e1f44cecdef4..0422ef57914c 100644
--- a/drivers/iio/multiplexer/iio-mux.c
+++ b/drivers/iio/multiplexer/iio-mux.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* IIO multiplexer driver
*
* Copyright (C) 2017 Axentia Technologies AB
*
* Author: Peter Rosin <peda@axentia.se>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/err.h>
diff --git a/drivers/iio/potentiometer/max5481.c b/drivers/iio/potentiometer/max5481.c
index ffe2761333a2..6d2f13fa5662 100644
--- a/drivers/iio/potentiometer/max5481.c
+++ b/drivers/iio/potentiometer/max5481.c
@@ -137,7 +137,6 @@ static int max5481_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
struct max5481_data *data;
const struct spi_device_id *id = spi_get_device_id(spi);
- const struct of_device_id *match;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*data));
@@ -149,10 +148,8 @@ static int max5481_probe(struct spi_device *spi)
data->spi = spi;
- match = of_match_device(of_match_ptr(max5481_match), &spi->dev);
- if (match)
- data->cfg = of_device_get_match_data(&spi->dev);
- else
+ data->cfg = of_device_get_match_data(&spi->dev);
+ if (!data->cfg)
data->cfg = &max5481_cfg[id->driver_data];
indio_dev->name = id->name;
diff --git a/drivers/iio/potentiometer/mcp4018.c b/drivers/iio/potentiometer/mcp4018.c
index 320a7c929777..62151b2a2b12 100644
--- a/drivers/iio/potentiometer/mcp4018.c
+++ b/drivers/iio/potentiometer/mcp4018.c
@@ -147,7 +147,6 @@ static int mcp4018_probe(struct i2c_client *client)
struct device *dev = &client->dev;
struct mcp4018_data *data;
struct iio_dev *indio_dev;
- const struct of_device_id *match;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE)) {
@@ -162,10 +161,8 @@ static int mcp4018_probe(struct i2c_client *client)
i2c_set_clientdata(client, indio_dev);
data->client = client;
- match = of_match_device(of_match_ptr(mcp4018_of_match), dev);
- if (match)
- data->cfg = of_device_get_match_data(dev);
- else
+ data->cfg = of_device_get_match_data(dev);
+ if (!data->cfg)
data->cfg = &mcp4018_cfg[i2c_match_id(mcp4018_id, client)->driver_data];
indio_dev->dev.parent = dev;
@@ -190,4 +187,4 @@ module_i2c_driver(mcp4018_driver);
MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
MODULE_DESCRIPTION("MCP4018 digital potentiometer");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/potentiometer/mcp4531.c b/drivers/iio/potentiometer/mcp4531.c
index df894af6cccb..d71a22d71a30 100644
--- a/drivers/iio/potentiometer/mcp4531.c
+++ b/drivers/iio/potentiometer/mcp4531.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Industrial I/O driver for Microchip digital potentiometers
* Copyright (c) 2015 Axentia Technologies AB
@@ -22,10 +23,6 @@
* mcp4652 2 257 5, 10, 50, 100 01011xx
* mcp4661 2 257 5, 10, 50, 100 0101xxx
* mcp4662 2 257 5, 10, 50, 100 01011xx
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#include <linux/module.h>
@@ -360,7 +357,6 @@ static int mcp4531_probe(struct i2c_client *client)
struct device *dev = &client->dev;
struct mcp4531_data *data;
struct iio_dev *indio_dev;
- const struct of_device_id *match;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_WORD_DATA)) {
@@ -375,10 +371,8 @@ static int mcp4531_probe(struct i2c_client *client)
i2c_set_clientdata(client, indio_dev);
data->client = client;
- match = of_match_device(of_match_ptr(mcp4531_of_match), dev);
- if (match)
- data->cfg = of_device_get_match_data(dev);
- else
+ data->cfg = of_device_get_match_data(dev);
+ if (!data->cfg)
data->cfg = &mcp4531_cfg[i2c_match_id(mcp4531_id, client)->driver_data];
indio_dev->dev.parent = dev;
@@ -403,4 +397,4 @@ module_i2c_driver(mcp4531_driver);
MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
MODULE_DESCRIPTION("MCP4531 digital potentiometer");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/pressure/ms5611.h b/drivers/iio/pressure/ms5611.h
index ead9e9f85894..bc06271fa38b 100644
--- a/drivers/iio/pressure/ms5611.h
+++ b/drivers/iio/pressure/ms5611.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* MS5611 pressure and temperature sensor driver
*
* Copyright (c) Tomasz Duszynski <tduszyns@gmail.com>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
*/
#ifndef _MS5611_H
diff --git a/drivers/iio/pressure/ms5611_core.c b/drivers/iio/pressure/ms5611_core.c
index f950cfde5db9..2f598ad91621 100644
--- a/drivers/iio/pressure/ms5611_core.c
+++ b/drivers/iio/pressure/ms5611_core.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* MS5611 pressure and temperature sensor driver
*
* Copyright (c) Tomasz Duszynski <tduszyns@gmail.com>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
* Data sheet:
* http://www.meas-spec.com/downloads/MS5611-01BA03.pdf
* http://www.meas-spec.com/downloads/MS5607-02BA03.pdf
diff --git a/drivers/iio/pressure/ms5611_i2c.c b/drivers/iio/pressure/ms5611_i2c.c
index 55fb5fc0b6ea..8089c59adce5 100644
--- a/drivers/iio/pressure/ms5611_i2c.c
+++ b/drivers/iio/pressure/ms5611_i2c.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* MS5611 pressure and temperature sensor driver (I2C bus)
*
* Copyright (c) Tomasz Duszynski <tduszyns@gmail.com>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
* 7-bit I2C slave addresses:
*
* 0x77 (CSB pin low)
@@ -117,9 +114,7 @@ static int ms5611_i2c_remove(struct i2c_client *client)
#if defined(CONFIG_OF)
static const struct of_device_id ms5611_i2c_matches[] = {
{ .compatible = "meas,ms5611" },
- { .compatible = "ms5611" },
{ .compatible = "meas,ms5607" },
- { .compatible = "ms5607" },
{ }
};
MODULE_DEVICE_TABLE(of, ms5611_i2c_matches);
diff --git a/drivers/iio/pressure/ms5611_spi.c b/drivers/iio/pressure/ms5611_spi.c
index 932e05001e1a..b463eaa799ab 100644
--- a/drivers/iio/pressure/ms5611_spi.c
+++ b/drivers/iio/pressure/ms5611_spi.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* MS5611 pressure and temperature sensor driver (SPI bus)
*
* Copyright (c) Tomasz Duszynski <tduszyns@gmail.com>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
*/
#include <linux/delay.h>
@@ -119,9 +116,7 @@ static int ms5611_spi_remove(struct spi_device *spi)
#if defined(CONFIG_OF)
static const struct of_device_id ms5611_spi_matches[] = {
{ .compatible = "meas,ms5611" },
- { .compatible = "ms5611" },
{ .compatible = "meas,ms5607" },
- { .compatible = "ms5607" },
{ }
};
MODULE_DEVICE_TABLE(of, ms5611_spi_matches);
diff --git a/drivers/iio/proximity/Kconfig b/drivers/iio/proximity/Kconfig
index 388ef70c11d2..b99367a89f81 100644
--- a/drivers/iio/proximity/Kconfig
+++ b/drivers/iio/proximity/Kconfig
@@ -92,4 +92,15 @@ config SRF08
To compile this driver as a module, choose M here: the
module will be called srf08.
+config VL53L0X_I2C
+ tristate "STMicroelectronics VL53L0X ToF ranger sensor (I2C)"
+ depends on I2C
+ help
+ Say Y here to build a driver for STMicroelectronics VL53L0X
+ ToF ranger sensors with i2c interface.
+ This driver can be used to measure the distance of objects.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vl53l0x-i2c.
+
endmenu
diff --git a/drivers/iio/proximity/Makefile b/drivers/iio/proximity/Makefile
index cac3d7d3325e..6d031f903c4c 100644
--- a/drivers/iio/proximity/Makefile
+++ b/drivers/iio/proximity/Makefile
@@ -11,3 +11,5 @@ obj-$(CONFIG_RFD77402) += rfd77402.o
obj-$(CONFIG_SRF04) += srf04.o
obj-$(CONFIG_SRF08) += srf08.o
obj-$(CONFIG_SX9500) += sx9500.o
+obj-$(CONFIG_VL53L0X_I2C) += vl53l0x-i2c.o
+
diff --git a/drivers/iio/proximity/isl29501.c b/drivers/iio/proximity/isl29501.c
index e5e94540f404..5ae549075b27 100644
--- a/drivers/iio/proximity/isl29501.c
+++ b/drivers/iio/proximity/isl29501.c
@@ -232,7 +232,6 @@ static u32 isl29501_register_write(struct isl29501_private *isl29501,
u32 value)
{
const struct isl29501_register_desc *reg = &isl29501_registers[name];
- u8 msb, lsb;
int ret;
if (!reg->msb && value > U8_MAX)
@@ -241,22 +240,15 @@ static u32 isl29501_register_write(struct isl29501_private *isl29501,
if (value > U16_MAX)
return -ERANGE;
- if (!reg->msb) {
- lsb = value & 0xFF;
- } else {
- msb = (value >> 8) & 0xFF;
- lsb = value & 0xFF;
- }
-
mutex_lock(&isl29501->lock);
if (reg->msb) {
ret = i2c_smbus_write_byte_data(isl29501->client,
- reg->msb, msb);
+ reg->msb, value >> 8);
if (ret < 0)
goto err;
}
- ret = i2c_smbus_write_byte_data(isl29501->client, reg->lsb, lsb);
+ ret = i2c_smbus_write_byte_data(isl29501->client, reg->lsb, value);
err:
mutex_unlock(&isl29501->lock);
diff --git a/drivers/iio/proximity/vl53l0x-i2c.c b/drivers/iio/proximity/vl53l0x-i2c.c
new file mode 100644
index 000000000000..b48216cc1858
--- /dev/null
+++ b/drivers/iio/proximity/vl53l0x-i2c.c
@@ -0,0 +1,164 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Support for ST VL53L0X FlightSense ToF Ranging Sensor on a i2c bus.
+ *
+ * Copyright (C) 2016 STMicroelectronics Imaging Division.
+ * Copyright (C) 2018 Song Qiang <songqiang1304521@gmail.com>
+ *
+ * Datasheet available at
+ * <https://www.st.com/resource/en/datasheet/vl53l0x.pdf>
+ *
+ * Default 7-bit i2c slave address 0x29.
+ *
+ * TODO: FIFO buffer, continuous mode, interrupts, range selection,
+ * sensor ID check.
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+
+#include <linux/iio/iio.h>
+
+#define VL_REG_SYSRANGE_START 0x00
+
+#define VL_REG_SYSRANGE_MODE_MASK GENMASK(3, 0)
+#define VL_REG_SYSRANGE_MODE_SINGLESHOT 0x00
+#define VL_REG_SYSRANGE_MODE_START_STOP BIT(0)
+#define VL_REG_SYSRANGE_MODE_BACKTOBACK BIT(1)
+#define VL_REG_SYSRANGE_MODE_TIMED BIT(2)
+#define VL_REG_SYSRANGE_MODE_HISTOGRAM BIT(3)
+
+#define VL_REG_RESULT_INT_STATUS 0x13
+#define VL_REG_RESULT_RANGE_STATUS 0x14
+#define VL_REG_RESULT_RANGE_STATUS_COMPLETE BIT(0)
+
+struct vl53l0x_data {
+ struct i2c_client *client;
+};
+
+static int vl53l0x_read_proximity(struct vl53l0x_data *data,
+ const struct iio_chan_spec *chan,
+ int *val)
+{
+ struct i2c_client *client = data->client;
+ u16 tries = 20;
+ u8 buffer[12];
+ int ret;
+
+ ret = i2c_smbus_write_byte_data(client, VL_REG_SYSRANGE_START, 1);
+ if (ret < 0)
+ return ret;
+
+ do {
+ ret = i2c_smbus_read_byte_data(client,
+ VL_REG_RESULT_RANGE_STATUS);
+ if (ret < 0)
+ return ret;
+
+ if (ret & VL_REG_RESULT_RANGE_STATUS_COMPLETE)
+ break;
+
+ usleep_range(1000, 5000);
+ } while (--tries);
+ if (!tries)
+ return -ETIMEDOUT;
+
+ ret = i2c_smbus_read_i2c_block_data(client, VL_REG_RESULT_RANGE_STATUS,
+ 12, buffer);
+ if (ret < 0)
+ return ret;
+ else if (ret != 12)
+ return -EREMOTEIO;
+
+ /* Values should be between 30~1200 in millimeters. */
+ *val = (buffer[10] << 8) + buffer[11];
+
+ return 0;
+}
+
+static const struct iio_chan_spec vl53l0x_channels[] = {
+ {
+ .type = IIO_DISTANCE,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ },
+};
+
+static int vl53l0x_read_raw(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ int *val, int *val2, long mask)
+{
+ struct vl53l0x_data *data = iio_priv(indio_dev);
+ int ret;
+
+ if (chan->type != IIO_DISTANCE)
+ return -EINVAL;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = vl53l0x_read_proximity(data, chan, val);
+ if (ret < 0)
+ return ret;
+
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = 0;
+ *val2 = 1000;
+
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info vl53l0x_info = {
+ .read_raw = vl53l0x_read_raw,
+};
+
+static int vl53l0x_probe(struct i2c_client *client)
+{
+ struct vl53l0x_data *data;
+ struct iio_dev *indio_dev;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ data->client = client;
+ i2c_set_clientdata(client, indio_dev);
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_I2C_BLOCK |
+ I2C_FUNC_SMBUS_BYTE_DATA))
+ return -EOPNOTSUPP;
+
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->name = "vl53l0x";
+ indio_dev->info = &vl53l0x_info;
+ indio_dev->channels = vl53l0x_channels;
+ indio_dev->num_channels = ARRAY_SIZE(vl53l0x_channels);
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct of_device_id st_vl53l0x_dt_match[] = {
+ { .compatible = "st,vl53l0x", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, st_vl53l0x_dt_match);
+
+static struct i2c_driver vl53l0x_driver = {
+ .driver = {
+ .name = "vl53l0x-i2c",
+ .of_match_table = st_vl53l0x_dt_match,
+ },
+ .probe_new = vl53l0x_probe,
+};
+module_i2c_driver(vl53l0x_driver);
+
+MODULE_AUTHOR("Song Qiang <songqiang1304521@gmail.com>");
+MODULE_DESCRIPTION("ST vl53l0x ToF ranging sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/temperature/mlx90632.c b/drivers/iio/temperature/mlx90632.c
index 9851311aa3fd..be03be719efe 100644
--- a/drivers/iio/temperature/mlx90632.c
+++ b/drivers/iio/temperature/mlx90632.c
@@ -140,7 +140,8 @@ static const struct regmap_config mlx90632_regmap = {
.rd_table = &mlx90632_readable_regs_tbl,
.wr_table = &mlx90632_writeable_regs_tbl,
- .use_single_rw = true,
+ .use_single_read = true,
+ .use_single_write = true,
.reg_format_endian = REGMAP_ENDIAN_BIG,
.val_format_endian = REGMAP_ENDIAN_BIG,
.cache_type = REGCACHE_RBTREE,
diff --git a/drivers/iio/trigger/iio-trig-sysfs.c b/drivers/iio/trigger/iio-trig-sysfs.c
index 3f0dc9a1a514..45c4897295d6 100644
--- a/drivers/iio/trigger/iio-trig-sysfs.c
+++ b/drivers/iio/trigger/iio-trig-sysfs.c
@@ -222,7 +222,7 @@ static void __exit iio_sysfs_trig_exit(void)
}
module_exit(iio_sysfs_trig_exit);
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Sysfs based trigger for the iio subsystem");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:iio-trig-sysfs");
diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig
index abb6660c099c..0a3ec7c726ec 100644
--- a/drivers/infiniband/Kconfig
+++ b/drivers/infiniband/Kconfig
@@ -26,6 +26,7 @@ config INFINIBAND_USER_MAD
config INFINIBAND_USER_ACCESS
tristate "InfiniBand userspace access (verbs and CM)"
select ANON_INODES
+ depends on MMU
---help---
Userspace InfiniBand access support. This enables the
kernel side of userspace verbs and the userspace
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
index 46b855a42884..0dce94e3c495 100644
--- a/drivers/infiniband/core/addr.c
+++ b/drivers/infiniband/core/addr.c
@@ -45,6 +45,7 @@
#include <net/addrconf.h>
#include <net/ip6_route.h>
#include <rdma/ib_addr.h>
+#include <rdma/ib_sa.h>
#include <rdma/ib.h>
#include <rdma/rdma_netlink.h>
#include <net/netlink.h>
@@ -61,6 +62,7 @@ struct addr_req {
struct rdma_dev_addr *addr, void *context);
unsigned long timeout;
struct delayed_work work;
+ bool resolve_by_gid_attr; /* Consider gid attr in resolve phase */
int status;
u32 seq;
};
@@ -219,60 +221,75 @@ int rdma_addr_size_kss(struct __kernel_sockaddr_storage *addr)
}
EXPORT_SYMBOL(rdma_addr_size_kss);
-void rdma_copy_addr(struct rdma_dev_addr *dev_addr,
- const struct net_device *dev,
- const unsigned char *dst_dev_addr)
+/**
+ * rdma_copy_src_l2_addr - Copy netdevice source addresses
+ * @dev_addr: Destination address pointer where to copy the addresses
+ * @dev: Netdevice whose source addresses to copy
+ *
+ * rdma_copy_src_l2_addr() copies source addresses from the specified netdevice.
+ * This includes unicast address, broadcast address, device type and
+ * interface index.
+ */
+void rdma_copy_src_l2_addr(struct rdma_dev_addr *dev_addr,
+ const struct net_device *dev)
{
dev_addr->dev_type = dev->type;
memcpy(dev_addr->src_dev_addr, dev->dev_addr, MAX_ADDR_LEN);
memcpy(dev_addr->broadcast, dev->broadcast, MAX_ADDR_LEN);
- if (dst_dev_addr)
- memcpy(dev_addr->dst_dev_addr, dst_dev_addr, MAX_ADDR_LEN);
dev_addr->bound_dev_if = dev->ifindex;
}
-EXPORT_SYMBOL(rdma_copy_addr);
+EXPORT_SYMBOL(rdma_copy_src_l2_addr);
-int rdma_translate_ip(const struct sockaddr *addr,
- struct rdma_dev_addr *dev_addr)
+static struct net_device *
+rdma_find_ndev_for_src_ip_rcu(struct net *net, const struct sockaddr *src_in)
{
- struct net_device *dev;
+ struct net_device *dev = NULL;
+ int ret = -EADDRNOTAVAIL;
- if (dev_addr->bound_dev_if) {
- dev = dev_get_by_index(dev_addr->net, dev_addr->bound_dev_if);
- if (!dev)
- return -ENODEV;
- rdma_copy_addr(dev_addr, dev, NULL);
- dev_put(dev);
- return 0;
- }
-
- switch (addr->sa_family) {
+ switch (src_in->sa_family) {
case AF_INET:
- dev = ip_dev_find(dev_addr->net,
- ((const struct sockaddr_in *)addr)->sin_addr.s_addr);
-
- if (!dev)
- return -EADDRNOTAVAIL;
-
- rdma_copy_addr(dev_addr, dev, NULL);
- dev_put(dev);
+ dev = __ip_dev_find(net,
+ ((const struct sockaddr_in *)src_in)->sin_addr.s_addr,
+ false);
+ if (dev)
+ ret = 0;
break;
#if IS_ENABLED(CONFIG_IPV6)
case AF_INET6:
- rcu_read_lock();
- for_each_netdev_rcu(dev_addr->net, dev) {
- if (ipv6_chk_addr(dev_addr->net,
- &((const struct sockaddr_in6 *)addr)->sin6_addr,
+ for_each_netdev_rcu(net, dev) {
+ if (ipv6_chk_addr(net,
+ &((const struct sockaddr_in6 *)src_in)->sin6_addr,
dev, 1)) {
- rdma_copy_addr(dev_addr, dev, NULL);
+ ret = 0;
break;
}
}
- rcu_read_unlock();
break;
#endif
}
- return 0;
+ return ret ? ERR_PTR(ret) : dev;
+}
+
+int rdma_translate_ip(const struct sockaddr *addr,
+ struct rdma_dev_addr *dev_addr)
+{
+ struct net_device *dev;
+
+ if (dev_addr->bound_dev_if) {
+ dev = dev_get_by_index(dev_addr->net, dev_addr->bound_dev_if);
+ if (!dev)
+ return -ENODEV;
+ rdma_copy_src_l2_addr(dev_addr, dev);
+ dev_put(dev);
+ return 0;
+ }
+
+ rcu_read_lock();
+ dev = rdma_find_ndev_for_src_ip_rcu(dev_addr->net, addr);
+ if (!IS_ERR(dev))
+ rdma_copy_src_l2_addr(dev_addr, dev);
+ rcu_read_unlock();
+ return PTR_ERR_OR_ZERO(dev);
}
EXPORT_SYMBOL(rdma_translate_ip);
@@ -295,15 +312,12 @@ static void queue_req(struct addr_req *req)
spin_unlock_bh(&lock);
}
-static int ib_nl_fetch_ha(const struct dst_entry *dst,
- struct rdma_dev_addr *dev_addr,
+static int ib_nl_fetch_ha(struct rdma_dev_addr *dev_addr,
const void *daddr, u32 seq, u16 family)
{
- if (rdma_nl_chk_listeners(RDMA_NL_GROUP_LS))
+ if (!rdma_nl_chk_listeners(RDMA_NL_GROUP_LS))
return -EADDRNOTAVAIL;
- /* We fill in what we can, the response will fill the rest */
- rdma_copy_addr(dev_addr, dst->dev, NULL);
return ib_nl_ip_send_msg(dev_addr, daddr, seq, family);
}
@@ -322,7 +336,7 @@ static int dst_fetch_ha(const struct dst_entry *dst,
neigh_event_send(n, NULL);
ret = -ENODATA;
} else {
- rdma_copy_addr(dev_addr, dst->dev, n->ha);
+ memcpy(dev_addr->dst_dev_addr, n->ha, MAX_ADDR_LEN);
}
neigh_release(n);
@@ -356,18 +370,22 @@ static int fetch_ha(const struct dst_entry *dst, struct rdma_dev_addr *dev_addr,
(const void *)&dst_in6->sin6_addr;
sa_family_t family = dst_in->sa_family;
- /* Gateway + ARPHRD_INFINIBAND -> IB router */
- if (has_gateway(dst, family) && dst->dev->type == ARPHRD_INFINIBAND)
- return ib_nl_fetch_ha(dst, dev_addr, daddr, seq, family);
+ /* If we have a gateway in IB mode then it must be an IB network */
+ if (has_gateway(dst, family) && dev_addr->network == RDMA_NETWORK_IB)
+ return ib_nl_fetch_ha(dev_addr, daddr, seq, family);
else
return dst_fetch_ha(dst, dev_addr, daddr);
}
-static int addr4_resolve(struct sockaddr_in *src_in,
- const struct sockaddr_in *dst_in,
+static int addr4_resolve(struct sockaddr *src_sock,
+ const struct sockaddr *dst_sock,
struct rdma_dev_addr *addr,
struct rtable **prt)
{
+ struct sockaddr_in *src_in = (struct sockaddr_in *)src_sock;
+ const struct sockaddr_in *dst_in =
+ (const struct sockaddr_in *)dst_sock;
+
__be32 src_ip = src_in->sin_addr.s_addr;
__be32 dst_ip = dst_in->sin_addr.s_addr;
struct rtable *rt;
@@ -383,16 +401,8 @@ static int addr4_resolve(struct sockaddr_in *src_in,
if (ret)
return ret;
- src_in->sin_family = AF_INET;
src_in->sin_addr.s_addr = fl4.saddr;
- /* If there's a gateway and type of device not ARPHRD_INFINIBAND, we're
- * definitely in RoCE v2 (as RoCE v1 isn't routable) set the network
- * type accordingly.
- */
- if (rt->rt_uses_gateway && rt->dst.dev->type != ARPHRD_INFINIBAND)
- addr->network = RDMA_NETWORK_IPV4;
-
addr->hoplimit = ip4_dst_hoplimit(&rt->dst);
*prt = rt;
@@ -400,14 +410,16 @@ static int addr4_resolve(struct sockaddr_in *src_in,
}
#if IS_ENABLED(CONFIG_IPV6)
-static int addr6_resolve(struct sockaddr_in6 *src_in,
- const struct sockaddr_in6 *dst_in,
+static int addr6_resolve(struct sockaddr *src_sock,
+ const struct sockaddr *dst_sock,
struct rdma_dev_addr *addr,
struct dst_entry **pdst)
{
+ struct sockaddr_in6 *src_in = (struct sockaddr_in6 *)src_sock;
+ const struct sockaddr_in6 *dst_in =
+ (const struct sockaddr_in6 *)dst_sock;
struct flowi6 fl6;
struct dst_entry *dst;
- struct rt6_info *rt;
int ret;
memset(&fl6, 0, sizeof fl6);
@@ -419,19 +431,8 @@ static int addr6_resolve(struct sockaddr_in6 *src_in,
if (ret < 0)
return ret;
- rt = (struct rt6_info *)dst;
- if (ipv6_addr_any(&src_in->sin6_addr)) {
- src_in->sin6_family = AF_INET6;
+ if (ipv6_addr_any(&src_in->sin6_addr))
src_in->sin6_addr = fl6.saddr;
- }
-
- /* If there's a gateway and type of device not ARPHRD_INFINIBAND, we're
- * definitely in RoCE v2 (as RoCE v1 isn't routable) set the network
- * type accordingly.
- */
- if (rt->rt6i_flags & RTF_GATEWAY &&
- ip6_dst_idev(dst)->dev->type != ARPHRD_INFINIBAND)
- addr->network = RDMA_NETWORK_IPV6;
addr->hoplimit = ip6_dst_hoplimit(dst);
@@ -439,8 +440,8 @@ static int addr6_resolve(struct sockaddr_in6 *src_in,
return 0;
}
#else
-static int addr6_resolve(struct sockaddr_in6 *src_in,
- const struct sockaddr_in6 *dst_in,
+static int addr6_resolve(struct sockaddr *src_sock,
+ const struct sockaddr *dst_sock,
struct rdma_dev_addr *addr,
struct dst_entry **pdst)
{
@@ -451,36 +452,110 @@ static int addr6_resolve(struct sockaddr_in6 *src_in,
static int addr_resolve_neigh(const struct dst_entry *dst,
const struct sockaddr *dst_in,
struct rdma_dev_addr *addr,
+ unsigned int ndev_flags,
u32 seq)
{
- if (dst->dev->flags & IFF_LOOPBACK) {
- int ret;
+ int ret = 0;
- ret = rdma_translate_ip(dst_in, addr);
- if (!ret)
- memcpy(addr->dst_dev_addr, addr->src_dev_addr,
- MAX_ADDR_LEN);
+ if (ndev_flags & IFF_LOOPBACK) {
+ memcpy(addr->dst_dev_addr, addr->src_dev_addr, MAX_ADDR_LEN);
+ } else {
+ if (!(ndev_flags & IFF_NOARP)) {
+ /* If the device doesn't do ARP internally */
+ ret = fetch_ha(dst, addr, dst_in, seq);
+ }
+ }
+ return ret;
+}
- return ret;
+static int copy_src_l2_addr(struct rdma_dev_addr *dev_addr,
+ const struct sockaddr *dst_in,
+ const struct dst_entry *dst,
+ const struct net_device *ndev)
+{
+ int ret = 0;
+
+ if (dst->dev->flags & IFF_LOOPBACK)
+ ret = rdma_translate_ip(dst_in, dev_addr);
+ else
+ rdma_copy_src_l2_addr(dev_addr, dst->dev);
+
+ /*
+ * If there's a gateway and type of device not ARPHRD_INFINIBAND,
+ * we're definitely in RoCE v2 (as RoCE v1 isn't routable) set the
+ * network type accordingly.
+ */
+ if (has_gateway(dst, dst_in->sa_family) &&
+ ndev->type != ARPHRD_INFINIBAND)
+ dev_addr->network = dst_in->sa_family == AF_INET ?
+ RDMA_NETWORK_IPV4 :
+ RDMA_NETWORK_IPV6;
+ else
+ dev_addr->network = RDMA_NETWORK_IB;
+
+ return ret;
+}
+
+static int rdma_set_src_addr_rcu(struct rdma_dev_addr *dev_addr,
+ unsigned int *ndev_flags,
+ const struct sockaddr *dst_in,
+ const struct dst_entry *dst)
+{
+ struct net_device *ndev = READ_ONCE(dst->dev);
+
+ *ndev_flags = ndev->flags;
+ /* A physical device must be the RDMA device to use */
+ if (ndev->flags & IFF_LOOPBACK) {
+ /*
+ * RDMA (IB/RoCE, iWarp) doesn't run on lo interface or
+ * loopback IP address. So if route is resolved to loopback
+ * interface, translate that to a real ndev based on non
+ * loopback IP address.
+ */
+ ndev = rdma_find_ndev_for_src_ip_rcu(dev_net(ndev), dst_in);
+ if (IS_ERR(ndev))
+ return -ENODEV;
}
- /* If the device doesn't do ARP internally */
- if (!(dst->dev->flags & IFF_NOARP))
- return fetch_ha(dst, addr, dst_in, seq);
+ return copy_src_l2_addr(dev_addr, dst_in, dst, ndev);
+}
+
+static int set_addr_netns_by_gid_rcu(struct rdma_dev_addr *addr)
+{
+ struct net_device *ndev;
- rdma_copy_addr(addr, dst->dev, NULL);
+ ndev = rdma_read_gid_attr_ndev_rcu(addr->sgid_attr);
+ if (IS_ERR(ndev))
+ return PTR_ERR(ndev);
+ /*
+ * Since we are holding the rcu, reading net and ifindex
+ * are safe without any additional reference; because
+ * change_net_namespace() in net/core/dev.c does rcu sync
+ * after it changes the state to IFF_DOWN and before
+ * updating netdev fields {net, ifindex}.
+ */
+ addr->net = dev_net(ndev);
+ addr->bound_dev_if = ndev->ifindex;
return 0;
}
+static void rdma_addr_set_net_defaults(struct rdma_dev_addr *addr)
+{
+ addr->net = &init_net;
+ addr->bound_dev_if = 0;
+}
+
static int addr_resolve(struct sockaddr *src_in,
const struct sockaddr *dst_in,
struct rdma_dev_addr *addr,
bool resolve_neigh,
+ bool resolve_by_gid_attr,
u32 seq)
{
- struct net_device *ndev;
- struct dst_entry *dst;
+ struct dst_entry *dst = NULL;
+ unsigned int ndev_flags = 0;
+ struct rtable *rt = NULL;
int ret;
if (!addr->net) {
@@ -488,58 +563,55 @@ static int addr_resolve(struct sockaddr *src_in,
return -EINVAL;
}
- if (src_in->sa_family == AF_INET) {
- struct rtable *rt = NULL;
- const struct sockaddr_in *dst_in4 =
- (const struct sockaddr_in *)dst_in;
-
- ret = addr4_resolve((struct sockaddr_in *)src_in,
- dst_in4, addr, &rt);
- if (ret)
- return ret;
-
- if (resolve_neigh)
- ret = addr_resolve_neigh(&rt->dst, dst_in, addr, seq);
-
- if (addr->bound_dev_if) {
- ndev = dev_get_by_index(addr->net, addr->bound_dev_if);
- } else {
- ndev = rt->dst.dev;
- dev_hold(ndev);
+ rcu_read_lock();
+ if (resolve_by_gid_attr) {
+ if (!addr->sgid_attr) {
+ rcu_read_unlock();
+ pr_warn_ratelimited("%s: missing gid_attr\n", __func__);
+ return -EINVAL;
}
-
- ip_rt_put(rt);
- } else {
- const struct sockaddr_in6 *dst_in6 =
- (const struct sockaddr_in6 *)dst_in;
-
- ret = addr6_resolve((struct sockaddr_in6 *)src_in,
- dst_in6, addr,
- &dst);
- if (ret)
+ /*
+ * If the request is for a specific gid attribute of the
+ * rdma_dev_addr, derive net from the netdevice of the
+ * GID attribute.
+ */
+ ret = set_addr_netns_by_gid_rcu(addr);
+ if (ret) {
+ rcu_read_unlock();
return ret;
-
- if (resolve_neigh)
- ret = addr_resolve_neigh(dst, dst_in, addr, seq);
-
- if (addr->bound_dev_if) {
- ndev = dev_get_by_index(addr->net, addr->bound_dev_if);
- } else {
- ndev = dst->dev;
- dev_hold(ndev);
}
-
- dst_release(dst);
}
-
- if (ndev) {
- if (ndev->flags & IFF_LOOPBACK)
- ret = rdma_translate_ip(dst_in, addr);
- else
- addr->bound_dev_if = ndev->ifindex;
- dev_put(ndev);
+ if (src_in->sa_family == AF_INET) {
+ ret = addr4_resolve(src_in, dst_in, addr, &rt);
+ dst = &rt->dst;
+ } else {
+ ret = addr6_resolve(src_in, dst_in, addr, &dst);
}
+ if (ret) {
+ rcu_read_unlock();
+ goto done;
+ }
+ ret = rdma_set_src_addr_rcu(addr, &ndev_flags, dst_in, dst);
+ rcu_read_unlock();
+
+ /*
+ * Resolve neighbor destination address if requested and
+ * only if src addr translation didn't fail.
+ */
+ if (!ret && resolve_neigh)
+ ret = addr_resolve_neigh(dst, dst_in, addr, ndev_flags, seq);
+ if (src_in->sa_family == AF_INET)
+ ip_rt_put(rt);
+ else
+ dst_release(dst);
+done:
+ /*
+ * Clear the addr net to go back to its original state, only if it was
+ * derived from GID attribute in this context.
+ */
+ if (resolve_by_gid_attr)
+ rdma_addr_set_net_defaults(addr);
return ret;
}
@@ -554,7 +626,8 @@ static void process_one_req(struct work_struct *_work)
src_in = (struct sockaddr *)&req->src_addr;
dst_in = (struct sockaddr *)&req->dst_addr;
req->status = addr_resolve(src_in, dst_in, req->addr,
- true, req->seq);
+ true, req->resolve_by_gid_attr,
+ req->seq);
if (req->status && time_after_eq(jiffies, req->timeout)) {
req->status = -ETIMEDOUT;
} else if (req->status == -ENODATA) {
@@ -586,10 +659,10 @@ static void process_one_req(struct work_struct *_work)
}
int rdma_resolve_ip(struct sockaddr *src_addr, const struct sockaddr *dst_addr,
- struct rdma_dev_addr *addr, int timeout_ms,
+ struct rdma_dev_addr *addr, unsigned long timeout_ms,
void (*callback)(int status, struct sockaddr *src_addr,
struct rdma_dev_addr *addr, void *context),
- void *context)
+ bool resolve_by_gid_attr, void *context)
{
struct sockaddr *src_in, *dst_in;
struct addr_req *req;
@@ -617,10 +690,12 @@ int rdma_resolve_ip(struct sockaddr *src_addr, const struct sockaddr *dst_addr,
req->addr = addr;
req->callback = callback;
req->context = context;
+ req->resolve_by_gid_attr = resolve_by_gid_attr;
INIT_DELAYED_WORK(&req->work, process_one_req);
req->seq = (u32)atomic_inc_return(&ib_nl_addr_request_seq);
- req->status = addr_resolve(src_in, dst_in, addr, true, req->seq);
+ req->status = addr_resolve(src_in, dst_in, addr, true,
+ req->resolve_by_gid_attr, req->seq);
switch (req->status) {
case 0:
req->timeout = jiffies;
@@ -641,25 +716,53 @@ err:
}
EXPORT_SYMBOL(rdma_resolve_ip);
-int rdma_resolve_ip_route(struct sockaddr *src_addr,
- const struct sockaddr *dst_addr,
- struct rdma_dev_addr *addr)
+int roce_resolve_route_from_path(struct sa_path_rec *rec,
+ const struct ib_gid_attr *attr)
{
- struct sockaddr_storage ssrc_addr = {};
- struct sockaddr *src_in = (struct sockaddr *)&ssrc_addr;
+ union {
+ struct sockaddr _sockaddr;
+ struct sockaddr_in _sockaddr_in;
+ struct sockaddr_in6 _sockaddr_in6;
+ } sgid, dgid;
+ struct rdma_dev_addr dev_addr = {};
+ int ret;
- if (src_addr) {
- if (src_addr->sa_family != dst_addr->sa_family)
- return -EINVAL;
+ if (rec->roce.route_resolved)
+ return 0;
- memcpy(src_in, src_addr, rdma_addr_size(src_addr));
- } else {
- src_in->sa_family = dst_addr->sa_family;
- }
+ rdma_gid2ip(&sgid._sockaddr, &rec->sgid);
+ rdma_gid2ip(&dgid._sockaddr, &rec->dgid);
+
+ if (sgid._sockaddr.sa_family != dgid._sockaddr.sa_family)
+ return -EINVAL;
+
+ if (!attr || !attr->ndev)
+ return -EINVAL;
+
+ dev_addr.net = &init_net;
+ dev_addr.sgid_attr = attr;
+
+ ret = addr_resolve(&sgid._sockaddr, &dgid._sockaddr,
+ &dev_addr, false, true, 0);
+ if (ret)
+ return ret;
+
+ if ((dev_addr.network == RDMA_NETWORK_IPV4 ||
+ dev_addr.network == RDMA_NETWORK_IPV6) &&
+ rec->rec_type != SA_PATH_REC_TYPE_ROCE_V2)
+ return -EINVAL;
- return addr_resolve(src_in, dst_addr, addr, false, 0);
+ rec->roce.route_resolved = true;
+ return 0;
}
+/**
+ * rdma_addr_cancel - Cancel resolve ip request
+ * @addr: Pointer to address structure given previously
+ * during rdma_resolve_ip().
+ * rdma_addr_cancel() is synchronous function which cancels any pending
+ * request if there is any.
+ */
void rdma_addr_cancel(struct rdma_dev_addr *addr)
{
struct addr_req *req, *temp_req;
@@ -687,11 +790,6 @@ void rdma_addr_cancel(struct rdma_dev_addr *addr)
* guarentees no work is running and none will be started.
*/
cancel_delayed_work_sync(&found->work);
-
- if (found->callback)
- found->callback(-ECANCELED, (struct sockaddr *)&found->src_addr,
- found->addr, found->context);
-
kfree(found);
}
EXPORT_SYMBOL(rdma_addr_cancel);
@@ -710,7 +808,7 @@ static void resolve_cb(int status, struct sockaddr *src_addr,
int rdma_addr_find_l2_eth_by_grh(const union ib_gid *sgid,
const union ib_gid *dgid,
- u8 *dmac, const struct net_device *ndev,
+ u8 *dmac, const struct ib_gid_attr *sgid_attr,
int *hoplimit)
{
struct rdma_dev_addr dev_addr;
@@ -726,12 +824,12 @@ int rdma_addr_find_l2_eth_by_grh(const union ib_gid *sgid,
rdma_gid2ip(&dgid_addr._sockaddr, dgid);
memset(&dev_addr, 0, sizeof(dev_addr));
- dev_addr.bound_dev_if = ndev->ifindex;
dev_addr.net = &init_net;
+ dev_addr.sgid_attr = sgid_attr;
init_completion(&ctx.comp);
ret = rdma_resolve_ip(&sgid_addr._sockaddr, &dgid_addr._sockaddr,
- &dev_addr, 1000, resolve_cb, &ctx);
+ &dev_addr, 1000, resolve_cb, true, &ctx);
if (ret)
return ret;
diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c
index 3208ad6ad540..5b2fce4a7091 100644
--- a/drivers/infiniband/core/cache.c
+++ b/drivers/infiniband/core/cache.c
@@ -212,9 +212,8 @@ static void free_gid_entry_locked(struct ib_gid_table_entry *entry)
u8 port_num = entry->attr.port_num;
struct ib_gid_table *table = rdma_gid_table(device, port_num);
- pr_debug("%s device=%s port=%d index=%d gid %pI6\n", __func__,
- device->name, port_num, entry->attr.index,
- entry->attr.gid.raw);
+ dev_dbg(&device->dev, "%s port=%d index=%d gid %pI6\n", __func__,
+ port_num, entry->attr.index, entry->attr.gid.raw);
if (rdma_cap_roce_gid_table(device, port_num) &&
entry->state != GID_TABLE_ENTRY_INVALID)
@@ -289,9 +288,9 @@ static void store_gid_entry(struct ib_gid_table *table,
{
entry->state = GID_TABLE_ENTRY_VALID;
- pr_debug("%s device=%s port=%d index=%d gid %pI6\n", __func__,
- entry->attr.device->name, entry->attr.port_num,
- entry->attr.index, entry->attr.gid.raw);
+ dev_dbg(&entry->attr.device->dev, "%s port=%d index=%d gid %pI6\n",
+ __func__, entry->attr.port_num, entry->attr.index,
+ entry->attr.gid.raw);
lockdep_assert_held(&table->lock);
write_lock_irq(&table->rwlock);
@@ -320,17 +319,16 @@ static int add_roce_gid(struct ib_gid_table_entry *entry)
int ret;
if (!attr->ndev) {
- pr_err("%s NULL netdev device=%s port=%d index=%d\n",
- __func__, attr->device->name, attr->port_num,
- attr->index);
+ dev_err(&attr->device->dev, "%s NULL netdev port=%d index=%d\n",
+ __func__, attr->port_num, attr->index);
return -EINVAL;
}
if (rdma_cap_roce_gid_table(attr->device, attr->port_num)) {
ret = attr->device->add_gid(attr, &entry->context);
if (ret) {
- pr_err("%s GID add failed device=%s port=%d index=%d\n",
- __func__, attr->device->name, attr->port_num,
- attr->index);
+ dev_err(&attr->device->dev,
+ "%s GID add failed port=%d index=%d\n",
+ __func__, attr->port_num, attr->index);
return ret;
}
}
@@ -353,9 +351,8 @@ static void del_gid(struct ib_device *ib_dev, u8 port,
lockdep_assert_held(&table->lock);
- pr_debug("%s device=%s port=%d index=%d gid %pI6\n", __func__,
- ib_dev->name, port, ix,
- table->data_vec[ix]->attr.gid.raw);
+ dev_dbg(&ib_dev->dev, "%s port=%d index=%d gid %pI6\n", __func__, port,
+ ix, table->data_vec[ix]->attr.gid.raw);
write_lock_irq(&table->rwlock);
entry = table->data_vec[ix];
@@ -782,9 +779,9 @@ static void release_gid_table(struct ib_device *device, u8 port,
if (is_gid_entry_free(table->data_vec[i]))
continue;
if (kref_read(&table->data_vec[i]->kref) > 1) {
- pr_err("GID entry ref leak for %s (index %d) ref=%d\n",
- device->name, i,
- kref_read(&table->data_vec[i]->kref));
+ dev_err(&device->dev,
+ "GID entry ref leak for index %d ref=%d\n", i,
+ kref_read(&table->data_vec[i]->kref));
leak = true;
}
}
@@ -1252,6 +1249,39 @@ void rdma_hold_gid_attr(const struct ib_gid_attr *attr)
}
EXPORT_SYMBOL(rdma_hold_gid_attr);
+/**
+ * rdma_read_gid_attr_ndev_rcu - Read GID attribute netdevice
+ * which must be in UP state.
+ *
+ * @attr:Pointer to the GID attribute
+ *
+ * Returns pointer to netdevice if the netdevice was attached to GID and
+ * netdevice is in UP state. Caller must hold RCU lock as this API
+ * reads the netdev flags which can change while netdevice migrates to
+ * different net namespace. Returns ERR_PTR with error code otherwise.
+ *
+ */
+struct net_device *rdma_read_gid_attr_ndev_rcu(const struct ib_gid_attr *attr)
+{
+ struct ib_gid_table_entry *entry =
+ container_of(attr, struct ib_gid_table_entry, attr);
+ struct ib_device *device = entry->attr.device;
+ struct net_device *ndev = ERR_PTR(-ENODEV);
+ u8 port_num = entry->attr.port_num;
+ struct ib_gid_table *table;
+ unsigned long flags;
+ bool valid;
+
+ table = rdma_gid_table(device, port_num);
+
+ read_lock_irqsave(&table->rwlock, flags);
+ valid = is_gid_entry_valid(table->data_vec[attr->index]);
+ if (valid && attr->ndev && (READ_ONCE(attr->ndev->flags) & IFF_UP))
+ ndev = attr->ndev;
+ read_unlock_irqrestore(&table->rwlock, flags);
+ return ndev;
+}
+
static int config_non_roce_gid_cache(struct ib_device *device,
u8 port, int gid_tbl_len)
{
@@ -1270,8 +1300,9 @@ static int config_non_roce_gid_cache(struct ib_device *device,
continue;
ret = device->query_gid(device, port, i, &gid_attr.gid);
if (ret) {
- pr_warn("query_gid failed (%d) for %s (index %d)\n",
- ret, device->name, i);
+ dev_warn(&device->dev,
+ "query_gid failed (%d) for index %d\n", ret,
+ i);
goto err;
}
gid_attr.index = i;
@@ -1300,8 +1331,7 @@ static void ib_cache_update(struct ib_device *device,
ret = ib_query_port(device, port, tprops);
if (ret) {
- pr_warn("ib_query_port failed (%d) for %s\n",
- ret, device->name);
+ dev_warn(&device->dev, "ib_query_port failed (%d)\n", ret);
goto err;
}
@@ -1323,8 +1353,9 @@ static void ib_cache_update(struct ib_device *device,
for (i = 0; i < pkey_cache->table_len; ++i) {
ret = ib_query_pkey(device, port, i, pkey_cache->table + i);
if (ret) {
- pr_warn("ib_query_pkey failed (%d) for %s (index %d)\n",
- ret, device->name, i);
+ dev_warn(&device->dev,
+ "ib_query_pkey failed (%d) for index %d\n",
+ ret, i);
goto err;
}
}
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index 6e39c27dca8e..edb2cb758be7 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -3292,8 +3292,11 @@ static int cm_lap_handler(struct cm_work *work)
if (ret)
goto unlock;
- cm_init_av_by_path(param->alternate_path, NULL, &cm_id_priv->alt_av,
- cm_id_priv);
+ 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;
ret = atomic_inc_and_test(&cm_id_priv->work_count);
@@ -4367,7 +4370,7 @@ static void cm_add_one(struct ib_device *ib_device)
cm_dev->going_down = 0;
cm_dev->device = device_create(&cm_class, &ib_device->dev,
MKDEV(0, 0), NULL,
- "%s", ib_device->name);
+ "%s", dev_name(&ib_device->dev));
if (IS_ERR(cm_dev->device)) {
kfree(cm_dev);
return;
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index a36c94930c31..15d5bb7bf6bb 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -639,13 +639,21 @@ static void cma_bind_sgid_attr(struct rdma_id_private *id_priv,
id_priv->id.route.addr.dev_addr.sgid_attr = sgid_attr;
}
-static int cma_acquire_dev(struct rdma_id_private *id_priv,
- const struct rdma_id_private *listen_id_priv)
+/**
+ * cma_acquire_dev_by_src_ip - Acquire cma device, port, gid attribute
+ * based on source ip address.
+ * @id_priv: cm_id which should be bound to cma device
+ *
+ * cma_acquire_dev_by_src_ip() binds cm id to cma device, port and GID attribute
+ * based on source IP address. It returns 0 on success or error code otherwise.
+ * It is applicable to active and passive side cm_id.
+ */
+static int cma_acquire_dev_by_src_ip(struct rdma_id_private *id_priv)
{
struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
const struct ib_gid_attr *sgid_attr;
- struct cma_device *cma_dev;
union ib_gid gid, iboe_gid, *gidp;
+ struct cma_device *cma_dev;
enum ib_gid_type gid_type;
int ret = -ENODEV;
u8 port;
@@ -654,41 +662,125 @@ static int cma_acquire_dev(struct rdma_id_private *id_priv,
id_priv->id.ps == RDMA_PS_IPOIB)
return -EINVAL;
- mutex_lock(&lock);
rdma_ip2gid((struct sockaddr *)&id_priv->id.route.addr.src_addr,
&iboe_gid);
memcpy(&gid, dev_addr->src_dev_addr +
- rdma_addr_gid_offset(dev_addr), sizeof gid);
-
- if (listen_id_priv) {
- cma_dev = listen_id_priv->cma_dev;
- port = listen_id_priv->id.port_num;
- gidp = rdma_protocol_roce(cma_dev->device, port) ?
- &iboe_gid : &gid;
- gid_type = listen_id_priv->gid_type;
- sgid_attr = cma_validate_port(cma_dev->device, port,
- gid_type, gidp, id_priv);
- if (!IS_ERR(sgid_attr)) {
- id_priv->id.port_num = port;
- cma_bind_sgid_attr(id_priv, sgid_attr);
- ret = 0;
- goto out;
+ rdma_addr_gid_offset(dev_addr), sizeof(gid));
+
+ mutex_lock(&lock);
+ list_for_each_entry(cma_dev, &dev_list, list) {
+ for (port = rdma_start_port(cma_dev->device);
+ port <= rdma_end_port(cma_dev->device); port++) {
+ gidp = rdma_protocol_roce(cma_dev->device, port) ?
+ &iboe_gid : &gid;
+ gid_type = cma_dev->default_gid_type[port - 1];
+ sgid_attr = cma_validate_port(cma_dev->device, port,
+ gid_type, gidp, id_priv);
+ if (!IS_ERR(sgid_attr)) {
+ id_priv->id.port_num = port;
+ cma_bind_sgid_attr(id_priv, sgid_attr);
+ cma_attach_to_dev(id_priv, cma_dev);
+ ret = 0;
+ goto out;
+ }
}
}
+out:
+ mutex_unlock(&lock);
+ return ret;
+}
+
+/**
+ * cma_ib_acquire_dev - Acquire cma device, port and SGID attribute
+ * @id_priv: cm id to bind to cma device
+ * @listen_id_priv: listener cm id to match against
+ * @req: Pointer to req structure containaining incoming
+ * request information
+ * cma_ib_acquire_dev() acquires cma device, port and SGID attribute when
+ * rdma device matches for listen_id and incoming request. It also verifies
+ * that a GID table entry is present for the source address.
+ * Returns 0 on success, or returns error code otherwise.
+ */
+static int cma_ib_acquire_dev(struct rdma_id_private *id_priv,
+ const struct rdma_id_private *listen_id_priv,
+ struct cma_req_info *req)
+{
+ struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
+ const struct ib_gid_attr *sgid_attr;
+ enum ib_gid_type gid_type;
+ union ib_gid gid;
+
+ if (dev_addr->dev_type != ARPHRD_INFINIBAND &&
+ id_priv->id.ps == RDMA_PS_IPOIB)
+ return -EINVAL;
+
+ if (rdma_protocol_roce(req->device, req->port))
+ rdma_ip2gid((struct sockaddr *)&id_priv->id.route.addr.src_addr,
+ &gid);
+ else
+ memcpy(&gid, dev_addr->src_dev_addr +
+ rdma_addr_gid_offset(dev_addr), sizeof(gid));
+
+ gid_type = listen_id_priv->cma_dev->default_gid_type[req->port - 1];
+ sgid_attr = cma_validate_port(req->device, req->port,
+ gid_type, &gid, id_priv);
+ if (IS_ERR(sgid_attr))
+ return PTR_ERR(sgid_attr);
+
+ id_priv->id.port_num = req->port;
+ cma_bind_sgid_attr(id_priv, sgid_attr);
+ /* Need to acquire lock to protect against reader
+ * of cma_dev->id_list such as cma_netdev_callback() and
+ * cma_process_remove().
+ */
+ mutex_lock(&lock);
+ cma_attach_to_dev(id_priv, listen_id_priv->cma_dev);
+ mutex_unlock(&lock);
+ return 0;
+}
+
+static int cma_iw_acquire_dev(struct rdma_id_private *id_priv,
+ const struct rdma_id_private *listen_id_priv)
+{
+ struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
+ const struct ib_gid_attr *sgid_attr;
+ struct cma_device *cma_dev;
+ enum ib_gid_type gid_type;
+ int ret = -ENODEV;
+ union ib_gid gid;
+ u8 port;
+
+ if (dev_addr->dev_type != ARPHRD_INFINIBAND &&
+ id_priv->id.ps == RDMA_PS_IPOIB)
+ return -EINVAL;
+
+ memcpy(&gid, dev_addr->src_dev_addr +
+ rdma_addr_gid_offset(dev_addr), sizeof(gid));
+
+ mutex_lock(&lock);
+
+ cma_dev = listen_id_priv->cma_dev;
+ port = listen_id_priv->id.port_num;
+ gid_type = listen_id_priv->gid_type;
+ sgid_attr = cma_validate_port(cma_dev->device, port,
+ gid_type, &gid, id_priv);
+ if (!IS_ERR(sgid_attr)) {
+ id_priv->id.port_num = port;
+ cma_bind_sgid_attr(id_priv, sgid_attr);
+ ret = 0;
+ goto out;
+ }
list_for_each_entry(cma_dev, &dev_list, list) {
for (port = 1; port <= cma_dev->device->phys_port_cnt; ++port) {
- if (listen_id_priv &&
- listen_id_priv->cma_dev == cma_dev &&
+ if (listen_id_priv->cma_dev == cma_dev &&
listen_id_priv->id.port_num == port)
continue;
- gidp = rdma_protocol_roce(cma_dev->device, port) ?
- &iboe_gid : &gid;
gid_type = cma_dev->default_gid_type[port - 1];
sgid_attr = cma_validate_port(cma_dev->device, port,
- gid_type, gidp, id_priv);
+ gid_type, &gid, id_priv);
if (!IS_ERR(sgid_attr)) {
id_priv->id.port_num = port;
cma_bind_sgid_attr(id_priv, sgid_attr);
@@ -785,10 +877,7 @@ struct rdma_cm_id *__rdma_create_id(struct net *net,
if (!id_priv)
return ERR_PTR(-ENOMEM);
- if (caller)
- id_priv->res.kern_name = caller;
- else
- rdma_restrack_set_task(&id_priv->res, current);
+ rdma_restrack_set_task(&id_priv->res, caller);
id_priv->res.type = RDMA_RESTRACK_CM_ID;
id_priv->state = RDMA_CM_IDLE;
id_priv->id.context = context;
@@ -1462,18 +1551,35 @@ static bool cma_protocol_roce(const struct rdma_cm_id *id)
return rdma_protocol_roce(device, port_num);
}
+static bool cma_is_req_ipv6_ll(const struct cma_req_info *req)
+{
+ const struct sockaddr *daddr =
+ (const struct sockaddr *)&req->listen_addr_storage;
+ const struct sockaddr_in6 *daddr6 = (const struct sockaddr_in6 *)daddr;
+
+ /* Returns true if the req is for IPv6 link local */
+ return (daddr->sa_family == AF_INET6 &&
+ (ipv6_addr_type(&daddr6->sin6_addr) & IPV6_ADDR_LINKLOCAL));
+}
+
static bool cma_match_net_dev(const struct rdma_cm_id *id,
const struct net_device *net_dev,
- u8 port_num)
+ const struct cma_req_info *req)
{
const struct rdma_addr *addr = &id->route.addr;
if (!net_dev)
/* This request is an AF_IB request */
- return (!id->port_num || id->port_num == port_num) &&
+ return (!id->port_num || id->port_num == req->port) &&
(addr->src_addr.ss_family == AF_IB);
/*
+ * If the request is not for IPv6 link local, allow matching
+ * request to any netdevice of the one or multiport rdma device.
+ */
+ if (!cma_is_req_ipv6_ll(req))
+ return true;
+ /*
* Net namespaces must match, and if the listner is listening
* on a specific netdevice than netdevice must match as well.
*/
@@ -1500,13 +1606,14 @@ static struct rdma_id_private *cma_find_listener(
hlist_for_each_entry(id_priv, &bind_list->owners, node) {
if (cma_match_private_data(id_priv, ib_event->private_data)) {
if (id_priv->id.device == cm_id->device &&
- cma_match_net_dev(&id_priv->id, net_dev, req->port))
+ cma_match_net_dev(&id_priv->id, net_dev, req))
return id_priv;
list_for_each_entry(id_priv_dev,
&id_priv->listen_list,
listen_list) {
if (id_priv_dev->id.device == cm_id->device &&
- cma_match_net_dev(&id_priv_dev->id, net_dev, req->port))
+ cma_match_net_dev(&id_priv_dev->id,
+ net_dev, req))
return id_priv_dev;
}
}
@@ -1518,18 +1625,18 @@ static struct rdma_id_private *cma_find_listener(
static struct rdma_id_private *
cma_ib_id_from_event(struct ib_cm_id *cm_id,
const struct ib_cm_event *ib_event,
+ struct cma_req_info *req,
struct net_device **net_dev)
{
- struct cma_req_info req;
struct rdma_bind_list *bind_list;
struct rdma_id_private *id_priv;
int err;
- err = cma_save_req_info(ib_event, &req);
+ err = cma_save_req_info(ib_event, req);
if (err)
return ERR_PTR(err);
- *net_dev = cma_get_net_dev(ib_event, &req);
+ *net_dev = cma_get_net_dev(ib_event, req);
if (IS_ERR(*net_dev)) {
if (PTR_ERR(*net_dev) == -EAFNOSUPPORT) {
/* Assuming the protocol is AF_IB */
@@ -1567,17 +1674,17 @@ cma_ib_id_from_event(struct ib_cm_id *cm_id,
}
if (!validate_net_dev(*net_dev,
- (struct sockaddr *)&req.listen_addr_storage,
- (struct sockaddr *)&req.src_addr_storage)) {
+ (struct sockaddr *)&req->listen_addr_storage,
+ (struct sockaddr *)&req->src_addr_storage)) {
id_priv = ERR_PTR(-EHOSTUNREACH);
goto err;
}
}
bind_list = cma_ps_find(*net_dev ? dev_net(*net_dev) : &init_net,
- rdma_ps_from_service_id(req.service_id),
- cma_port_from_service_id(req.service_id));
- id_priv = cma_find_listener(bind_list, cm_id, ib_event, &req, *net_dev);
+ rdma_ps_from_service_id(req->service_id),
+ cma_port_from_service_id(req->service_id));
+ id_priv = cma_find_listener(bind_list, cm_id, ib_event, req, *net_dev);
err:
rcu_read_unlock();
if (IS_ERR(id_priv) && *net_dev) {
@@ -1710,8 +1817,8 @@ void rdma_destroy_id(struct rdma_cm_id *id)
mutex_lock(&id_priv->handler_mutex);
mutex_unlock(&id_priv->handler_mutex);
+ rdma_restrack_del(&id_priv->res);
if (id_priv->cma_dev) {
- rdma_restrack_del(&id_priv->res);
if (rdma_cap_ib_cm(id_priv->id.device, 1)) {
if (id_priv->cm_id.ib)
ib_destroy_cm_id(id_priv->cm_id.ib);
@@ -1902,7 +2009,7 @@ cma_ib_new_conn_id(const struct rdma_cm_id *listen_id,
rt->path_rec[1] = *ib_event->param.req_rcvd.alternate_path;
if (net_dev) {
- rdma_copy_addr(&rt->addr.dev_addr, net_dev, NULL);
+ rdma_copy_src_l2_addr(&rt->addr.dev_addr, net_dev);
} else {
if (!cma_protocol_roce(listen_id) &&
cma_any_addr(cma_src_addr(id_priv))) {
@@ -1952,7 +2059,7 @@ cma_ib_new_udp_id(const struct rdma_cm_id *listen_id,
goto err;
if (net_dev) {
- rdma_copy_addr(&id->route.addr.dev_addr, net_dev, NULL);
+ rdma_copy_src_l2_addr(&id->route.addr.dev_addr, net_dev);
} else {
if (!cma_any_addr(cma_src_addr(id_priv))) {
ret = cma_translate_addr(cma_src_addr(id_priv),
@@ -1999,11 +2106,12 @@ static int cma_ib_req_handler(struct ib_cm_id *cm_id,
{
struct rdma_id_private *listen_id, *conn_id = NULL;
struct rdma_cm_event event = {};
+ struct cma_req_info req = {};
struct net_device *net_dev;
u8 offset;
int ret;
- listen_id = cma_ib_id_from_event(cm_id, ib_event, &net_dev);
+ listen_id = cma_ib_id_from_event(cm_id, ib_event, &req, &net_dev);
if (IS_ERR(listen_id))
return PTR_ERR(listen_id);
@@ -2036,7 +2144,7 @@ static int cma_ib_req_handler(struct ib_cm_id *cm_id,
}
mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING);
- ret = cma_acquire_dev(conn_id, listen_id);
+ ret = cma_ib_acquire_dev(conn_id, listen_id, &req);
if (ret)
goto err2;
@@ -2232,7 +2340,7 @@ static int iw_conn_req_handler(struct iw_cm_id *cm_id,
goto out;
}
- ret = cma_acquire_dev(conn_id, listen_id);
+ ret = cma_iw_acquire_dev(conn_id, listen_id);
if (ret) {
mutex_unlock(&conn_id->handler_mutex);
rdma_destroy_id(new_cm_id);
@@ -2354,8 +2462,8 @@ static void cma_listen_on_dev(struct rdma_id_private *id_priv,
ret = rdma_listen(id, id_priv->backlog);
if (ret)
- pr_warn("RDMA CMA: cma_listen_on_dev, error %d, listening on device %s\n",
- ret, cma_dev->device->name);
+ dev_warn(&cma_dev->device->dev,
+ "RDMA CMA: cma_listen_on_dev, error %d\n", ret);
}
static void cma_listen_on_all(struct rdma_id_private *id_priv)
@@ -2402,8 +2510,8 @@ static void cma_query_handler(int status, struct sa_path_rec *path_rec,
queue_work(cma_wq, &work->work);
}
-static int cma_query_ib_route(struct rdma_id_private *id_priv, int timeout_ms,
- struct cma_work *work)
+static int cma_query_ib_route(struct rdma_id_private *id_priv,
+ unsigned long timeout_ms, struct cma_work *work)
{
struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
struct sa_path_rec path_rec;
@@ -2521,7 +2629,8 @@ static void cma_init_resolve_addr_work(struct cma_work *work,
work->event.event = RDMA_CM_EVENT_ADDR_RESOLVED;
}
-static int cma_resolve_ib_route(struct rdma_id_private *id_priv, int timeout_ms)
+static int cma_resolve_ib_route(struct rdma_id_private *id_priv,
+ unsigned long timeout_ms)
{
struct rdma_route *route = &id_priv->id.route;
struct cma_work *work;
@@ -2643,7 +2752,7 @@ err:
}
EXPORT_SYMBOL(rdma_set_ib_path);
-static int cma_resolve_iw_route(struct rdma_id_private *id_priv, int timeout_ms)
+static int cma_resolve_iw_route(struct rdma_id_private *id_priv)
{
struct cma_work *work;
@@ -2744,7 +2853,7 @@ err1:
return ret;
}
-int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms)
+int rdma_resolve_route(struct rdma_cm_id *id, unsigned long timeout_ms)
{
struct rdma_id_private *id_priv;
int ret;
@@ -2759,7 +2868,7 @@ int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms)
else if (rdma_protocol_roce(id->device, id->port_num))
ret = cma_resolve_iboe_route(id_priv);
else if (rdma_protocol_iwarp(id->device, id->port_num))
- ret = cma_resolve_iw_route(id_priv, timeout_ms);
+ ret = cma_resolve_iw_route(id_priv);
else
ret = -ENOSYS;
@@ -2862,7 +2971,7 @@ static void addr_handler(int status, struct sockaddr *src_addr,
memcpy(cma_src_addr(id_priv), src_addr, rdma_addr_size(src_addr));
if (!status && !id_priv->cma_dev) {
- status = cma_acquire_dev(id_priv, NULL);
+ status = cma_acquire_dev_by_src_ip(id_priv);
if (status)
pr_debug_ratelimited("RDMA CM: ADDR_ERROR: failed to acquire device. status %d\n",
status);
@@ -2882,13 +2991,11 @@ static void addr_handler(int status, struct sockaddr *src_addr,
if (id_priv->id.event_handler(&id_priv->id, &event)) {
cma_exch(id_priv, RDMA_CM_DESTROYING);
mutex_unlock(&id_priv->handler_mutex);
- cma_deref_id(id_priv);
rdma_destroy_id(&id_priv->id);
return;
}
out:
mutex_unlock(&id_priv->handler_mutex);
- cma_deref_id(id_priv);
}
static int cma_resolve_loopback(struct rdma_id_private *id_priv)
@@ -2966,7 +3073,7 @@ static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
}
int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
- const struct sockaddr *dst_addr, int timeout_ms)
+ const struct sockaddr *dst_addr, unsigned long timeout_ms)
{
struct rdma_id_private *id_priv;
int ret;
@@ -2985,16 +3092,16 @@ int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
return -EINVAL;
memcpy(cma_dst_addr(id_priv), dst_addr, rdma_addr_size(dst_addr));
- atomic_inc(&id_priv->refcount);
if (cma_any_addr(dst_addr)) {
ret = cma_resolve_loopback(id_priv);
} else {
if (dst_addr->sa_family == AF_IB) {
ret = cma_resolve_ib_addr(id_priv);
} else {
- ret = rdma_resolve_ip(cma_src_addr(id_priv),
- dst_addr, &id->route.addr.dev_addr,
- timeout_ms, addr_handler, id_priv);
+ ret = rdma_resolve_ip(cma_src_addr(id_priv), dst_addr,
+ &id->route.addr.dev_addr,
+ timeout_ms, addr_handler,
+ false, id_priv);
}
}
if (ret)
@@ -3003,7 +3110,6 @@ int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
return 0;
err:
cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY, RDMA_CM_ADDR_BOUND);
- cma_deref_id(id_priv);
return ret;
}
EXPORT_SYMBOL(rdma_resolve_addr);
@@ -3414,7 +3520,7 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
if (ret)
goto err1;
- ret = cma_acquire_dev(id_priv, NULL);
+ ret = cma_acquire_dev_by_src_ip(id_priv);
if (ret)
goto err1;
}
@@ -3439,10 +3545,9 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
return 0;
err2:
- if (id_priv->cma_dev) {
- rdma_restrack_del(&id_priv->res);
+ rdma_restrack_del(&id_priv->res);
+ if (id_priv->cma_dev)
cma_release_dev(id_priv);
- }
err1:
cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_IDLE);
return ret;
@@ -3839,10 +3944,7 @@ int __rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param,
id_priv = container_of(id, struct rdma_id_private, id);
- if (caller)
- id_priv->res.kern_name = caller;
- else
- rdma_restrack_set_task(&id_priv->res, current);
+ rdma_restrack_set_task(&id_priv->res, caller);
if (!cma_comp(id_priv, RDMA_CM_CONNECT))
return -EINVAL;
@@ -4087,9 +4189,10 @@ static int cma_join_ib_multicast(struct rdma_id_private *id_priv,
(!ib_sa_sendonly_fullmem_support(&sa_client,
id_priv->id.device,
id_priv->id.port_num))) {
- pr_warn("RDMA CM: %s port %u Unable to multicast join\n"
- "RDMA CM: SM doesn't support Send Only Full Member option\n",
- id_priv->id.device->name, id_priv->id.port_num);
+ dev_warn(
+ &id_priv->id.device->dev,
+ "RDMA CM: port %u Unable to multicast join: SM doesn't support Send Only Full Member option\n",
+ id_priv->id.port_num);
return -EOPNOTSUPP;
}
diff --git a/drivers/infiniband/core/cma_configfs.c b/drivers/infiniband/core/cma_configfs.c
index eee38b40be99..8c2dfb3e294e 100644
--- a/drivers/infiniband/core/cma_configfs.c
+++ b/drivers/infiniband/core/cma_configfs.c
@@ -65,7 +65,7 @@ static struct cma_dev_port_group *to_dev_port_group(struct config_item *item)
static bool filter_by_name(struct ib_device *ib_dev, void *cookie)
{
- return !strcmp(ib_dev->name, cookie);
+ return !strcmp(dev_name(&ib_dev->dev), cookie);
}
static int cma_configfs_params_get(struct config_item *item,
diff --git a/drivers/infiniband/core/core_priv.h b/drivers/infiniband/core/core_priv.h
index 77c7005c396c..bb9007a0cca7 100644
--- a/drivers/infiniband/core/core_priv.h
+++ b/drivers/infiniband/core/core_priv.h
@@ -44,7 +44,7 @@
#include "mad_priv.h"
/* Total number of ports combined across all struct ib_devices's */
-#define RDMA_MAX_PORTS 1024
+#define RDMA_MAX_PORTS 8192
struct pkey_index_qp_list {
struct list_head pkey_index_list;
@@ -87,6 +87,7 @@ int ib_device_register_sysfs(struct ib_device *device,
int (*port_callback)(struct ib_device *,
u8, struct kobject *));
void ib_device_unregister_sysfs(struct ib_device *device);
+int ib_device_rename(struct ib_device *ibdev, const char *name);
typedef void (*roce_netdev_callback)(struct ib_device *device, u8 port,
struct net_device *idev, void *cookie);
@@ -338,7 +339,14 @@ int rdma_resolve_ip_route(struct sockaddr *src_addr,
int rdma_addr_find_l2_eth_by_grh(const union ib_gid *sgid,
const union ib_gid *dgid,
- u8 *dmac, const struct net_device *ndev,
+ u8 *dmac, const struct ib_gid_attr *sgid_attr,
int *hoplimit);
+void rdma_copy_src_l2_addr(struct rdma_dev_addr *dev_addr,
+ const struct net_device *dev);
+struct sa_path_rec;
+int roce_resolve_route_from_path(struct sa_path_rec *rec,
+ const struct ib_gid_attr *attr);
+
+struct net_device *rdma_read_gid_attr_ndev_rcu(const struct ib_gid_attr *attr);
#endif /* _CORE_PRIV_H */
diff --git a/drivers/infiniband/core/cq.c b/drivers/infiniband/core/cq.c
index af5ad6a56ae4..b1e5365ddafa 100644
--- a/drivers/infiniband/core/cq.c
+++ b/drivers/infiniband/core/cq.c
@@ -112,12 +112,12 @@ static void ib_cq_poll_work(struct work_struct *work)
IB_POLL_BATCH);
if (completed >= IB_POLL_BUDGET_WORKQUEUE ||
ib_req_notify_cq(cq, IB_POLL_FLAGS) > 0)
- queue_work(ib_comp_wq, &cq->work);
+ queue_work(cq->comp_wq, &cq->work);
}
static void ib_cq_completion_workqueue(struct ib_cq *cq, void *private)
{
- queue_work(ib_comp_wq, &cq->work);
+ queue_work(cq->comp_wq, &cq->work);
}
/**
@@ -161,7 +161,7 @@ struct ib_cq *__ib_alloc_cq(struct ib_device *dev, void *private,
goto out_destroy_cq;
cq->res.type = RDMA_RESTRACK_CQ;
- cq->res.kern_name = caller;
+ rdma_restrack_set_task(&cq->res, caller);
rdma_restrack_add(&cq->res);
switch (cq->poll_ctx) {
@@ -175,9 +175,12 @@ struct ib_cq *__ib_alloc_cq(struct ib_device *dev, void *private,
ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
break;
case IB_POLL_WORKQUEUE:
+ case IB_POLL_UNBOUND_WORKQUEUE:
cq->comp_handler = ib_cq_completion_workqueue;
INIT_WORK(&cq->work, ib_cq_poll_work);
ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
+ cq->comp_wq = (cq->poll_ctx == IB_POLL_WORKQUEUE) ?
+ ib_comp_wq : ib_comp_unbound_wq;
break;
default:
ret = -EINVAL;
@@ -213,6 +216,7 @@ void ib_free_cq(struct ib_cq *cq)
irq_poll_disable(&cq->iop);
break;
case IB_POLL_WORKQUEUE:
+ case IB_POLL_UNBOUND_WORKQUEUE:
cancel_work_sync(&cq->work);
break;
default:
diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c
index db3b6271f09d..87eb4f2cdd7d 100644
--- a/drivers/infiniband/core/device.c
+++ b/drivers/infiniband/core/device.c
@@ -61,6 +61,7 @@ struct ib_client_data {
};
struct workqueue_struct *ib_comp_wq;
+struct workqueue_struct *ib_comp_unbound_wq;
struct workqueue_struct *ib_wq;
EXPORT_SYMBOL_GPL(ib_wq);
@@ -122,8 +123,9 @@ static int ib_device_check_mandatory(struct ib_device *device)
for (i = 0; i < ARRAY_SIZE(mandatory_table); ++i) {
if (!*(void **) ((void *) device + mandatory_table[i].offset)) {
- pr_warn("Device %s is missing mandatory function %s\n",
- device->name, mandatory_table[i].name);
+ dev_warn(&device->dev,
+ "Device is missing mandatory function %s\n",
+ mandatory_table[i].name);
return -EINVAL;
}
}
@@ -163,16 +165,40 @@ static struct ib_device *__ib_device_get_by_name(const char *name)
struct ib_device *device;
list_for_each_entry(device, &device_list, core_list)
- if (!strncmp(name, device->name, IB_DEVICE_NAME_MAX))
+ if (!strcmp(name, dev_name(&device->dev)))
return device;
return NULL;
}
-static int alloc_name(char *name)
+int ib_device_rename(struct ib_device *ibdev, const char *name)
+{
+ struct ib_device *device;
+ int ret = 0;
+
+ if (!strcmp(name, dev_name(&ibdev->dev)))
+ return ret;
+
+ mutex_lock(&device_mutex);
+ list_for_each_entry(device, &device_list, core_list) {
+ if (!strcmp(name, dev_name(&device->dev))) {
+ ret = -EEXIST;
+ goto out;
+ }
+ }
+
+ ret = device_rename(&ibdev->dev, name);
+ if (ret)
+ goto out;
+ strlcpy(ibdev->name, name, IB_DEVICE_NAME_MAX);
+out:
+ mutex_unlock(&device_mutex);
+ return ret;
+}
+
+static int alloc_name(struct ib_device *ibdev, const char *name)
{
unsigned long *inuse;
- char buf[IB_DEVICE_NAME_MAX];
struct ib_device *device;
int i;
@@ -181,24 +207,21 @@ static int alloc_name(char *name)
return -ENOMEM;
list_for_each_entry(device, &device_list, core_list) {
- if (!sscanf(device->name, name, &i))
+ char buf[IB_DEVICE_NAME_MAX];
+
+ if (sscanf(dev_name(&device->dev), name, &i) != 1)
continue;
if (i < 0 || i >= PAGE_SIZE * 8)
continue;
snprintf(buf, sizeof buf, name, i);
- if (!strncmp(buf, device->name, IB_DEVICE_NAME_MAX))
+ if (!strcmp(buf, dev_name(&device->dev)))
set_bit(i, inuse);
}
i = find_first_zero_bit(inuse, PAGE_SIZE * 8);
free_page((unsigned long) inuse);
- snprintf(buf, sizeof buf, name, i);
- if (__ib_device_get_by_name(buf))
- return -ENFILE;
-
- strlcpy(name, buf, IB_DEVICE_NAME_MAX);
- return 0;
+ return dev_set_name(&ibdev->dev, name, i);
}
static void ib_device_release(struct device *device)
@@ -221,9 +244,7 @@ static void ib_device_release(struct device *device)
static int ib_device_uevent(struct device *device,
struct kobj_uevent_env *env)
{
- struct ib_device *dev = container_of(device, struct ib_device, dev);
-
- if (add_uevent_var(env, "NAME=%s", dev->name))
+ if (add_uevent_var(env, "NAME=%s", dev_name(device)))
return -ENOMEM;
/*
@@ -269,7 +290,7 @@ struct ib_device *ib_alloc_device(size_t size)
INIT_LIST_HEAD(&device->event_handler_list);
spin_lock_init(&device->event_handler_lock);
- spin_lock_init(&device->client_data_lock);
+ rwlock_init(&device->client_data_lock);
INIT_LIST_HEAD(&device->client_data_list);
INIT_LIST_HEAD(&device->port_list);
@@ -285,6 +306,7 @@ EXPORT_SYMBOL(ib_alloc_device);
*/
void ib_dealloc_device(struct ib_device *device)
{
+ WARN_ON(!list_empty(&device->client_data_list));
WARN_ON(device->reg_state != IB_DEV_UNREGISTERED &&
device->reg_state != IB_DEV_UNINITIALIZED);
rdma_restrack_clean(&device->res);
@@ -295,9 +317,8 @@ EXPORT_SYMBOL(ib_dealloc_device);
static int add_client_context(struct ib_device *device, struct ib_client *client)
{
struct ib_client_data *context;
- unsigned long flags;
- context = kmalloc(sizeof *context, GFP_KERNEL);
+ context = kmalloc(sizeof(*context), GFP_KERNEL);
if (!context)
return -ENOMEM;
@@ -306,9 +327,9 @@ static int add_client_context(struct ib_device *device, struct ib_client *client
context->going_down = false;
down_write(&lists_rwsem);
- spin_lock_irqsave(&device->client_data_lock, flags);
+ write_lock_irq(&device->client_data_lock);
list_add(&context->list, &device->client_data_list);
- spin_unlock_irqrestore(&device->client_data_lock, flags);
+ write_unlock_irq(&device->client_data_lock);
up_write(&lists_rwsem);
return 0;
@@ -444,22 +465,8 @@ static u32 __dev_new_index(void)
}
}
-/**
- * ib_register_device - Register an IB device with IB core
- * @device:Device to register
- *
- * Low-level drivers use ib_register_device() to register their
- * devices with the IB core. All registered clients will receive a
- * callback for each device that is added. @device must be allocated
- * with ib_alloc_device().
- */
-int ib_register_device(struct ib_device *device,
- int (*port_callback)(struct ib_device *,
- u8, struct kobject *))
+static void setup_dma_device(struct ib_device *device)
{
- int ret;
- struct ib_client *client;
- struct ib_udata uhw = {.outlen = 0, .inlen = 0};
struct device *parent = device->dev.parent;
WARN_ON_ONCE(device->dma_device);
@@ -491,56 +498,113 @@ int ib_register_device(struct ib_device *device,
WARN_ON_ONCE(!parent);
device->dma_device = parent;
}
+}
- mutex_lock(&device_mutex);
+static void cleanup_device(struct ib_device *device)
+{
+ ib_cache_cleanup_one(device);
+ ib_cache_release_one(device);
+ kfree(device->port_pkey_list);
+ kfree(device->port_immutable);
+}
- if (strchr(device->name, '%')) {
- ret = alloc_name(device->name);
- if (ret)
- goto out;
- }
+static int setup_device(struct ib_device *device)
+{
+ struct ib_udata uhw = {.outlen = 0, .inlen = 0};
+ int ret;
- if (ib_device_check_mandatory(device)) {
- ret = -EINVAL;
- goto out;
- }
+ ret = ib_device_check_mandatory(device);
+ if (ret)
+ return ret;
ret = read_port_immutable(device);
if (ret) {
- pr_warn("Couldn't create per port immutable data %s\n",
- device->name);
- goto out;
+ dev_warn(&device->dev,
+ "Couldn't create per port immutable data\n");
+ return ret;
}
- ret = setup_port_pkey_list(device);
+ memset(&device->attrs, 0, sizeof(device->attrs));
+ ret = device->query_device(device, &device->attrs, &uhw);
if (ret) {
- pr_warn("Couldn't create per port_pkey_list\n");
- goto out;
+ dev_warn(&device->dev,
+ "Couldn't query the device attributes\n");
+ goto port_cleanup;
}
- ret = ib_cache_setup_one(device);
+ ret = setup_port_pkey_list(device);
if (ret) {
- pr_warn("Couldn't set up InfiniBand P_Key/GID cache\n");
+ dev_warn(&device->dev, "Couldn't create per port_pkey_list\n");
goto port_cleanup;
}
- ret = ib_device_register_rdmacg(device);
+ ret = ib_cache_setup_one(device);
if (ret) {
- pr_warn("Couldn't register device with rdma cgroup\n");
- goto cache_cleanup;
+ dev_warn(&device->dev,
+ "Couldn't set up InfiniBand P_Key/GID cache\n");
+ goto pkey_cleanup;
+ }
+ return 0;
+
+pkey_cleanup:
+ kfree(device->port_pkey_list);
+port_cleanup:
+ kfree(device->port_immutable);
+ return ret;
+}
+
+/**
+ * ib_register_device - Register an IB device with IB core
+ * @device:Device to register
+ *
+ * Low-level drivers use ib_register_device() to register their
+ * devices with the IB core. All registered clients will receive a
+ * callback for each device that is added. @device must be allocated
+ * with ib_alloc_device().
+ */
+int ib_register_device(struct ib_device *device, const char *name,
+ int (*port_callback)(struct ib_device *, u8,
+ struct kobject *))
+{
+ int ret;
+ struct ib_client *client;
+
+ setup_dma_device(device);
+
+ mutex_lock(&device_mutex);
+
+ if (strchr(name, '%')) {
+ ret = alloc_name(device, name);
+ if (ret)
+ goto out;
+ } else {
+ ret = dev_set_name(&device->dev, name);
+ if (ret)
+ goto out;
+ }
+ if (__ib_device_get_by_name(dev_name(&device->dev))) {
+ ret = -ENFILE;
+ goto out;
}
+ strlcpy(device->name, dev_name(&device->dev), IB_DEVICE_NAME_MAX);
- memset(&device->attrs, 0, sizeof(device->attrs));
- ret = device->query_device(device, &device->attrs, &uhw);
+ ret = setup_device(device);
+ if (ret)
+ goto out;
+
+ device->index = __dev_new_index();
+
+ ret = ib_device_register_rdmacg(device);
if (ret) {
- pr_warn("Couldn't query the device attributes\n");
- goto cg_cleanup;
+ dev_warn(&device->dev,
+ "Couldn't register device with rdma cgroup\n");
+ goto dev_cleanup;
}
ret = ib_device_register_sysfs(device, port_callback);
if (ret) {
- pr_warn("Couldn't register device %s with driver model\n",
- device->name);
+ dev_warn(&device->dev,
+ "Couldn't register device with driver model\n");
goto cg_cleanup;
}
@@ -550,7 +614,6 @@ int ib_register_device(struct ib_device *device,
if (!add_client_context(device, client) && client->add)
client->add(device);
- device->index = __dev_new_index();
down_write(&lists_rwsem);
list_add_tail(&device->core_list, &device_list);
up_write(&lists_rwsem);
@@ -559,11 +622,8 @@ int ib_register_device(struct ib_device *device,
cg_cleanup:
ib_device_unregister_rdmacg(device);
-cache_cleanup:
- ib_cache_cleanup_one(device);
- ib_cache_release_one(device);
-port_cleanup:
- kfree(device->port_immutable);
+dev_cleanup:
+ cleanup_device(device);
out:
mutex_unlock(&device_mutex);
return ret;
@@ -585,21 +645,20 @@ void ib_unregister_device(struct ib_device *device)
down_write(&lists_rwsem);
list_del(&device->core_list);
- spin_lock_irqsave(&device->client_data_lock, flags);
- list_for_each_entry_safe(context, tmp, &device->client_data_list, list)
+ write_lock_irq(&device->client_data_lock);
+ list_for_each_entry(context, &device->client_data_list, list)
context->going_down = true;
- spin_unlock_irqrestore(&device->client_data_lock, flags);
+ write_unlock_irq(&device->client_data_lock);
downgrade_write(&lists_rwsem);
- list_for_each_entry_safe(context, tmp, &device->client_data_list,
- list) {
+ list_for_each_entry(context, &device->client_data_list, list) {
if (context->client->remove)
context->client->remove(device, context->data);
}
up_read(&lists_rwsem);
- ib_device_unregister_rdmacg(device);
ib_device_unregister_sysfs(device);
+ ib_device_unregister_rdmacg(device);
mutex_unlock(&device_mutex);
@@ -609,10 +668,13 @@ void ib_unregister_device(struct ib_device *device)
kfree(device->port_pkey_list);
down_write(&lists_rwsem);
- spin_lock_irqsave(&device->client_data_lock, flags);
- list_for_each_entry_safe(context, tmp, &device->client_data_list, list)
+ write_lock_irqsave(&device->client_data_lock, flags);
+ list_for_each_entry_safe(context, tmp, &device->client_data_list,
+ list) {
+ list_del(&context->list);
kfree(context);
- spin_unlock_irqrestore(&device->client_data_lock, flags);
+ }
+ write_unlock_irqrestore(&device->client_data_lock, flags);
up_write(&lists_rwsem);
device->reg_state = IB_DEV_UNREGISTERED;
@@ -662,9 +724,8 @@ EXPORT_SYMBOL(ib_register_client);
*/
void ib_unregister_client(struct ib_client *client)
{
- struct ib_client_data *context, *tmp;
+ struct ib_client_data *context;
struct ib_device *device;
- unsigned long flags;
mutex_lock(&device_mutex);
@@ -676,14 +737,14 @@ void ib_unregister_client(struct ib_client *client)
struct ib_client_data *found_context = NULL;
down_write(&lists_rwsem);
- spin_lock_irqsave(&device->client_data_lock, flags);
- list_for_each_entry_safe(context, tmp, &device->client_data_list, list)
+ write_lock_irq(&device->client_data_lock);
+ list_for_each_entry(context, &device->client_data_list, list)
if (context->client == client) {
context->going_down = true;
found_context = context;
break;
}
- spin_unlock_irqrestore(&device->client_data_lock, flags);
+ write_unlock_irq(&device->client_data_lock);
up_write(&lists_rwsem);
if (client->remove)
@@ -691,17 +752,18 @@ void ib_unregister_client(struct ib_client *client)
found_context->data : NULL);
if (!found_context) {
- pr_warn("No client context found for %s/%s\n",
- device->name, client->name);
+ dev_warn(&device->dev,
+ "No client context found for %s\n",
+ client->name);
continue;
}
down_write(&lists_rwsem);
- spin_lock_irqsave(&device->client_data_lock, flags);
+ write_lock_irq(&device->client_data_lock);
list_del(&found_context->list);
- kfree(found_context);
- spin_unlock_irqrestore(&device->client_data_lock, flags);
+ write_unlock_irq(&device->client_data_lock);
up_write(&lists_rwsem);
+ kfree(found_context);
}
mutex_unlock(&device_mutex);
@@ -722,13 +784,13 @@ void *ib_get_client_data(struct ib_device *device, struct ib_client *client)
void *ret = NULL;
unsigned long flags;
- spin_lock_irqsave(&device->client_data_lock, flags);
+ read_lock_irqsave(&device->client_data_lock, flags);
list_for_each_entry(context, &device->client_data_list, list)
if (context->client == client) {
ret = context->data;
break;
}
- spin_unlock_irqrestore(&device->client_data_lock, flags);
+ read_unlock_irqrestore(&device->client_data_lock, flags);
return ret;
}
@@ -749,18 +811,18 @@ void ib_set_client_data(struct ib_device *device, struct ib_client *client,
struct ib_client_data *context;
unsigned long flags;
- spin_lock_irqsave(&device->client_data_lock, flags);
+ write_lock_irqsave(&device->client_data_lock, flags);
list_for_each_entry(context, &device->client_data_list, list)
if (context->client == client) {
context->data = data;
goto out;
}
- pr_warn("No client context found for %s/%s\n",
- device->name, client->name);
+ dev_warn(&device->dev, "No client context found for %s\n",
+ client->name);
out:
- spin_unlock_irqrestore(&device->client_data_lock, flags);
+ write_unlock_irqrestore(&device->client_data_lock, flags);
}
EXPORT_SYMBOL(ib_set_client_data);
@@ -1166,10 +1228,19 @@ static int __init ib_core_init(void)
goto err;
}
+ ib_comp_unbound_wq =
+ alloc_workqueue("ib-comp-unb-wq",
+ WQ_UNBOUND | WQ_HIGHPRI | WQ_MEM_RECLAIM |
+ WQ_SYSFS, WQ_UNBOUND_MAX_ACTIVE);
+ if (!ib_comp_unbound_wq) {
+ ret = -ENOMEM;
+ goto err_comp;
+ }
+
ret = class_register(&ib_class);
if (ret) {
pr_warn("Couldn't create InfiniBand device class\n");
- goto err_comp;
+ goto err_comp_unbound;
}
ret = rdma_nl_init();
@@ -1218,6 +1289,8 @@ err_ibnl:
rdma_nl_exit();
err_sysfs:
class_unregister(&ib_class);
+err_comp_unbound:
+ destroy_workqueue(ib_comp_unbound_wq);
err_comp:
destroy_workqueue(ib_comp_wq);
err:
@@ -1236,6 +1309,7 @@ static void __exit ib_core_cleanup(void)
addr_cleanup();
rdma_nl_exit();
class_unregister(&ib_class);
+ destroy_workqueue(ib_comp_unbound_wq);
destroy_workqueue(ib_comp_wq);
/* Make sure that any pending umem accounting work is done. */
destroy_workqueue(ib_wq);
diff --git a/drivers/infiniband/core/fmr_pool.c b/drivers/infiniband/core/fmr_pool.c
index a077500f7f32..83ba0068e8bb 100644
--- a/drivers/infiniband/core/fmr_pool.c
+++ b/drivers/infiniband/core/fmr_pool.c
@@ -213,7 +213,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd,
device = pd->device;
if (!device->alloc_fmr || !device->dealloc_fmr ||
!device->map_phys_fmr || !device->unmap_fmr) {
- pr_info(PFX "Device %s does not support FMRs\n", device->name);
+ dev_info(&device->dev, "Device does not support FMRs\n");
return ERR_PTR(-ENOSYS);
}
@@ -257,7 +257,8 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd,
atomic_set(&pool->flush_ser, 0);
init_waitqueue_head(&pool->force_wait);
- pool->worker = kthread_create_worker(0, "ib_fmr(%s)", device->name);
+ pool->worker =
+ kthread_create_worker(0, "ib_fmr(%s)", dev_name(&device->dev));
if (IS_ERR(pool->worker)) {
pr_warn(PFX "couldn't start cleanup kthread worker\n");
ret = PTR_ERR(pool->worker);
diff --git a/drivers/infiniband/core/iwcm.c b/drivers/infiniband/core/iwcm.c
index 5d676cff41f4..ba668d49c751 100644
--- a/drivers/infiniband/core/iwcm.c
+++ b/drivers/infiniband/core/iwcm.c
@@ -509,7 +509,7 @@ static int iw_cm_map(struct iw_cm_id *cm_id, bool active)
cm_id->m_local_addr = cm_id->local_addr;
cm_id->m_remote_addr = cm_id->remote_addr;
- memcpy(pm_reg_msg.dev_name, cm_id->device->name,
+ memcpy(pm_reg_msg.dev_name, dev_name(&cm_id->device->dev),
sizeof(pm_reg_msg.dev_name));
memcpy(pm_reg_msg.if_name, cm_id->device->iwcm->ifname,
sizeof(pm_reg_msg.if_name));
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index ef459f2f2eeb..d7025cd5be28 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -220,33 +220,37 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device,
int ret2, qpn;
u8 mgmt_class, vclass;
+ if ((qp_type == IB_QPT_SMI && !rdma_cap_ib_smi(device, port_num)) ||
+ (qp_type == IB_QPT_GSI && !rdma_cap_ib_cm(device, port_num)))
+ return ERR_PTR(-EPROTONOSUPPORT);
+
/* Validate parameters */
qpn = get_spl_qp_index(qp_type);
if (qpn == -1) {
- dev_notice(&device->dev,
- "ib_register_mad_agent: invalid QP Type %d\n",
- qp_type);
+ dev_dbg_ratelimited(&device->dev, "%s: invalid QP Type %d\n",
+ __func__, qp_type);
goto error1;
}
if (rmpp_version && rmpp_version != IB_MGMT_RMPP_VERSION) {
- dev_notice(&device->dev,
- "ib_register_mad_agent: invalid RMPP Version %u\n",
- rmpp_version);
+ dev_dbg_ratelimited(&device->dev,
+ "%s: invalid RMPP Version %u\n",
+ __func__, rmpp_version);
goto error1;
}
/* Validate MAD registration request if supplied */
if (mad_reg_req) {
if (mad_reg_req->mgmt_class_version >= MAX_MGMT_VERSION) {
- dev_notice(&device->dev,
- "ib_register_mad_agent: invalid Class Version %u\n",
- mad_reg_req->mgmt_class_version);
+ dev_dbg_ratelimited(&device->dev,
+ "%s: invalid Class Version %u\n",
+ __func__,
+ mad_reg_req->mgmt_class_version);
goto error1;
}
if (!recv_handler) {
- dev_notice(&device->dev,
- "ib_register_mad_agent: no recv_handler\n");
+ dev_dbg_ratelimited(&device->dev,
+ "%s: no recv_handler\n", __func__);
goto error1;
}
if (mad_reg_req->mgmt_class >= MAX_MGMT_CLASS) {
@@ -256,9 +260,9 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device,
*/
if (mad_reg_req->mgmt_class !=
IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) {
- dev_notice(&device->dev,
- "ib_register_mad_agent: Invalid Mgmt Class 0x%x\n",
- mad_reg_req->mgmt_class);
+ dev_dbg_ratelimited(&device->dev,
+ "%s: Invalid Mgmt Class 0x%x\n",
+ __func__, mad_reg_req->mgmt_class);
goto error1;
}
} else if (mad_reg_req->mgmt_class == 0) {
@@ -266,8 +270,9 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device,
* Class 0 is reserved in IBA and is used for
* aliasing of IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE
*/
- dev_notice(&device->dev,
- "ib_register_mad_agent: Invalid Mgmt Class 0\n");
+ dev_dbg_ratelimited(&device->dev,
+ "%s: Invalid Mgmt Class 0\n",
+ __func__);
goto error1;
} else if (is_vendor_class(mad_reg_req->mgmt_class)) {
/*
@@ -275,18 +280,19 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device,
* ensure supplied OUI is not zero
*/
if (!is_vendor_oui(mad_reg_req->oui)) {
- dev_notice(&device->dev,
- "ib_register_mad_agent: No OUI specified for class 0x%x\n",
- mad_reg_req->mgmt_class);
+ dev_dbg_ratelimited(&device->dev,
+ "%s: No OUI specified for class 0x%x\n",
+ __func__,
+ mad_reg_req->mgmt_class);
goto error1;
}
}
/* Make sure class supplied is consistent with RMPP */
if (!ib_is_mad_class_rmpp(mad_reg_req->mgmt_class)) {
if (rmpp_version) {
- dev_notice(&device->dev,
- "ib_register_mad_agent: RMPP version for non-RMPP class 0x%x\n",
- mad_reg_req->mgmt_class);
+ dev_dbg_ratelimited(&device->dev,
+ "%s: RMPP version for non-RMPP class 0x%x\n",
+ __func__, mad_reg_req->mgmt_class);
goto error1;
}
}
@@ -297,9 +303,9 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device,
IB_MGMT_CLASS_SUBN_LID_ROUTED) &&
(mad_reg_req->mgmt_class !=
IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)) {
- dev_notice(&device->dev,
- "ib_register_mad_agent: Invalid SM QP type: class 0x%x\n",
- mad_reg_req->mgmt_class);
+ dev_dbg_ratelimited(&device->dev,
+ "%s: Invalid SM QP type: class 0x%x\n",
+ __func__, mad_reg_req->mgmt_class);
goto error1;
}
} else {
@@ -307,9 +313,9 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device,
IB_MGMT_CLASS_SUBN_LID_ROUTED) ||
(mad_reg_req->mgmt_class ==
IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)) {
- dev_notice(&device->dev,
- "ib_register_mad_agent: Invalid GS QP type: class 0x%x\n",
- mad_reg_req->mgmt_class);
+ dev_dbg_ratelimited(&device->dev,
+ "%s: Invalid GS QP type: class 0x%x\n",
+ __func__, mad_reg_req->mgmt_class);
goto error1;
}
}
@@ -324,18 +330,18 @@ 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_notice(&device->dev,
- "ib_register_mad_agent: Invalid port %d\n",
- port_num);
+ dev_dbg_ratelimited(&device->dev, "%s: Invalid port %d\n",
+ __func__, port_num);
ret = ERR_PTR(-ENODEV);
goto error1;
}
- /* Verify the QP requested is supported. For example, Ethernet devices
- * will not have QP0 */
+ /* Verify the QP requested is supported. For example, Ethernet devices
+ * will not have QP0.
+ */
if (!port_priv->qp_info[qpn].qp) {
- dev_notice(&device->dev,
- "ib_register_mad_agent: QP %d not supported\n", qpn);
+ dev_dbg_ratelimited(&device->dev, "%s: QP %d not supported\n",
+ __func__, qpn);
ret = ERR_PTR(-EPROTONOSUPPORT);
goto error1;
}
@@ -2408,7 +2414,7 @@ static void wait_for_response(struct ib_mad_send_wr_private *mad_send_wr)
}
void ib_reset_mad_timeout(struct ib_mad_send_wr_private *mad_send_wr,
- int timeout_ms)
+ unsigned long timeout_ms)
{
mad_send_wr->timeout = msecs_to_jiffies(timeout_ms);
wait_for_response(mad_send_wr);
@@ -3183,7 +3189,7 @@ static int ib_mad_port_open(struct ib_device *device,
cq_size *= 2;
port_priv->cq = ib_alloc_cq(port_priv->device, port_priv, cq_size, 0,
- IB_POLL_WORKQUEUE);
+ IB_POLL_UNBOUND_WORKQUEUE);
if (IS_ERR(port_priv->cq)) {
dev_err(&device->dev, "Couldn't create ib_mad CQ\n");
ret = PTR_ERR(port_priv->cq);
diff --git a/drivers/infiniband/core/mad_priv.h b/drivers/infiniband/core/mad_priv.h
index d84ae1671898..216509036aa8 100644
--- a/drivers/infiniband/core/mad_priv.h
+++ b/drivers/infiniband/core/mad_priv.h
@@ -221,6 +221,6 @@ void ib_mad_complete_send_wr(struct ib_mad_send_wr_private *mad_send_wr,
void ib_mark_mad_done(struct ib_mad_send_wr_private *mad_send_wr);
void ib_reset_mad_timeout(struct ib_mad_send_wr_private *mad_send_wr,
- int timeout_ms);
+ unsigned long timeout_ms);
#endif /* __IB_MAD_PRIV_H__ */
diff --git a/drivers/infiniband/core/netlink.c b/drivers/infiniband/core/netlink.c
index 3ccaae18ad75..724f5a62e82f 100644
--- a/drivers/infiniband/core/netlink.c
+++ b/drivers/infiniband/core/netlink.c
@@ -47,9 +47,9 @@ static struct {
const struct rdma_nl_cbs *cb_table;
} rdma_nl_types[RDMA_NL_NUM_CLIENTS];
-int rdma_nl_chk_listeners(unsigned int group)
+bool rdma_nl_chk_listeners(unsigned int group)
{
- return (netlink_has_listeners(nls, group)) ? 0 : -1;
+ return netlink_has_listeners(nls, group);
}
EXPORT_SYMBOL(rdma_nl_chk_listeners);
diff --git a/drivers/infiniband/core/nldev.c b/drivers/infiniband/core/nldev.c
index 0385ab438320..573399e3ccc1 100644
--- a/drivers/infiniband/core/nldev.c
+++ b/drivers/infiniband/core/nldev.c
@@ -179,7 +179,8 @@ static int fill_nldev_handle(struct sk_buff *msg, struct ib_device *device)
{
if (nla_put_u32(msg, RDMA_NLDEV_ATTR_DEV_INDEX, device->index))
return -EMSGSIZE;
- if (nla_put_string(msg, RDMA_NLDEV_ATTR_DEV_NAME, device->name))
+ if (nla_put_string(msg, RDMA_NLDEV_ATTR_DEV_NAME,
+ dev_name(&device->dev)))
return -EMSGSIZE;
return 0;
@@ -645,6 +646,36 @@ err:
return err;
}
+static int nldev_set_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct netlink_ext_ack *extack)
+{
+ struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
+ struct ib_device *device;
+ u32 index;
+ int err;
+
+ err = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1, nldev_policy,
+ extack);
+ if (err || !tb[RDMA_NLDEV_ATTR_DEV_INDEX])
+ return -EINVAL;
+
+ index = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
+ device = ib_device_get_by_index(index);
+ if (!device)
+ return -EINVAL;
+
+ if (tb[RDMA_NLDEV_ATTR_DEV_NAME]) {
+ char name[IB_DEVICE_NAME_MAX] = {};
+
+ nla_strlcpy(name, tb[RDMA_NLDEV_ATTR_DEV_NAME],
+ IB_DEVICE_NAME_MAX);
+ err = ib_device_rename(device, name);
+ }
+
+ put_device(&device->dev);
+ return err;
+}
+
static int _nldev_get_dumpit(struct ib_device *device,
struct sk_buff *skb,
struct netlink_callback *cb,
@@ -1077,6 +1108,10 @@ static const struct rdma_nl_cbs nldev_cb_table[RDMA_NLDEV_NUM_OPS] = {
.doit = nldev_get_doit,
.dump = nldev_get_dumpit,
},
+ [RDMA_NLDEV_CMD_SET] = {
+ .doit = nldev_set_doit,
+ .flags = RDMA_NL_ADMIN_PERM,
+ },
[RDMA_NLDEV_CMD_PORT_GET] = {
.doit = nldev_port_get_doit,
.dump = nldev_port_get_dumpit,
diff --git a/drivers/infiniband/core/rdma_core.c b/drivers/infiniband/core/rdma_core.c
index c4118bcd5103..752a55c6bdce 100644
--- a/drivers/infiniband/core/rdma_core.c
+++ b/drivers/infiniband/core/rdma_core.c
@@ -794,44 +794,6 @@ void uverbs_close_fd(struct file *f)
uverbs_uobject_put(uobj);
}
-static void ufile_disassociate_ucontext(struct ib_ucontext *ibcontext)
-{
- struct ib_device *ib_dev = ibcontext->device;
- struct task_struct *owning_process = NULL;
- struct mm_struct *owning_mm = NULL;
-
- owning_process = get_pid_task(ibcontext->tgid, PIDTYPE_PID);
- if (!owning_process)
- return;
-
- owning_mm = get_task_mm(owning_process);
- if (!owning_mm) {
- pr_info("no mm, disassociate ucontext is pending task termination\n");
- while (1) {
- put_task_struct(owning_process);
- usleep_range(1000, 2000);
- owning_process = get_pid_task(ibcontext->tgid,
- PIDTYPE_PID);
- if (!owning_process ||
- owning_process->state == TASK_DEAD) {
- pr_info("disassociate ucontext done, task was terminated\n");
- /* in case task was dead need to release the
- * task struct.
- */
- if (owning_process)
- put_task_struct(owning_process);
- return;
- }
- }
- }
-
- down_write(&owning_mm->mmap_sem);
- ib_dev->disassociate_ucontext(ibcontext);
- up_write(&owning_mm->mmap_sem);
- mmput(owning_mm);
- put_task_struct(owning_process);
-}
-
/*
* Drop the ucontext off the ufile and completely disconnect it from the
* ib_device
@@ -840,20 +802,28 @@ static void ufile_destroy_ucontext(struct ib_uverbs_file *ufile,
enum rdma_remove_reason reason)
{
struct ib_ucontext *ucontext = ufile->ucontext;
+ struct ib_device *ib_dev = ucontext->device;
int ret;
- if (reason == RDMA_REMOVE_DRIVER_REMOVE)
- ufile_disassociate_ucontext(ucontext);
+ /*
+ * If we are closing the FD then the user mmap VMAs must have
+ * already been destroyed as they hold on to the filep, otherwise
+ * they need to be zap'd.
+ */
+ if (reason == RDMA_REMOVE_DRIVER_REMOVE) {
+ uverbs_user_mmap_disassociate(ufile);
+ if (ib_dev->disassociate_ucontext)
+ ib_dev->disassociate_ucontext(ucontext);
+ }
- put_pid(ucontext->tgid);
- ib_rdmacg_uncharge(&ucontext->cg_obj, ucontext->device,
+ ib_rdmacg_uncharge(&ucontext->cg_obj, ib_dev,
RDMACG_RESOURCE_HCA_HANDLE);
/*
* FIXME: Drivers are not permitted to fail dealloc_ucontext, remove
* the error return.
*/
- ret = ucontext->device->dealloc_ucontext(ucontext);
+ ret = ib_dev->dealloc_ucontext(ucontext);
WARN_ON(ret);
ufile->ucontext = NULL;
diff --git a/drivers/infiniband/core/rdma_core.h b/drivers/infiniband/core/rdma_core.h
index f962f2a593ba..4886d2bba7c7 100644
--- a/drivers/infiniband/core/rdma_core.h
+++ b/drivers/infiniband/core/rdma_core.h
@@ -160,5 +160,6 @@ void uverbs_disassociate_api(struct uverbs_api *uapi);
void uverbs_destroy_api(struct uverbs_api *uapi);
void uapi_compute_bundle_size(struct uverbs_api_ioctl_method *method_elm,
unsigned int num_attrs);
+void uverbs_user_mmap_disassociate(struct ib_uverbs_file *ufile);
#endif /* RDMA_CORE_H */
diff --git a/drivers/infiniband/core/restrack.c b/drivers/infiniband/core/restrack.c
index 3b7fa0ccaa08..06d8657ce583 100644
--- a/drivers/infiniband/core/restrack.c
+++ b/drivers/infiniband/core/restrack.c
@@ -50,8 +50,7 @@ void rdma_restrack_clean(struct rdma_restrack_root *res)
dev = container_of(res, struct ib_device, res);
pr_err("restrack: %s", CUT_HERE);
- pr_err("restrack: BUG: RESTRACK detected leak of resources on %s\n",
- dev->name);
+ dev_err(&dev->dev, "BUG: RESTRACK detected leak of resources\n");
hash_for_each(res->hash, bkt, e, node) {
if (rdma_is_kernel_res(e)) {
owner = e->kern_name;
@@ -156,6 +155,21 @@ static bool res_is_user(struct rdma_restrack_entry *res)
}
}
+void rdma_restrack_set_task(struct rdma_restrack_entry *res,
+ const char *caller)
+{
+ if (caller) {
+ res->kern_name = caller;
+ return;
+ }
+
+ if (res->task)
+ put_task_struct(res->task);
+ get_task_struct(current);
+ res->task = current;
+}
+EXPORT_SYMBOL(rdma_restrack_set_task);
+
void rdma_restrack_add(struct rdma_restrack_entry *res)
{
struct ib_device *dev = res_to_dev(res);
@@ -168,7 +182,7 @@ void rdma_restrack_add(struct rdma_restrack_entry *res)
if (res_is_user(res)) {
if (!res->task)
- rdma_restrack_set_task(res, current);
+ rdma_restrack_set_task(res, NULL);
res->kern_name = NULL;
} else {
set_kern_name(res);
@@ -209,7 +223,7 @@ void rdma_restrack_del(struct rdma_restrack_entry *res)
struct ib_device *dev;
if (!res->valid)
- return;
+ goto out;
dev = res_to_dev(res);
if (!dev)
@@ -222,8 +236,12 @@ void rdma_restrack_del(struct rdma_restrack_entry *res)
down_write(&dev->res.rwsem);
hash_del(&res->node);
res->valid = false;
- if (res->task)
- put_task_struct(res->task);
up_write(&dev->res.rwsem);
+
+out:
+ if (res->task) {
+ put_task_struct(res->task);
+ res->task = NULL;
+ }
}
EXPORT_SYMBOL(rdma_restrack_del);
diff --git a/drivers/infiniband/core/rw.c b/drivers/infiniband/core/rw.c
index 683e6d11a564..d22c4a2ebac6 100644
--- a/drivers/infiniband/core/rw.c
+++ b/drivers/infiniband/core/rw.c
@@ -12,6 +12,7 @@
*/
#include <linux/moduleparam.h>
#include <linux/slab.h>
+#include <linux/pci-p2pdma.h>
#include <rdma/mr_pool.h>
#include <rdma/rw.h>
@@ -280,7 +281,11 @@ int rdma_rw_ctx_init(struct rdma_rw_ctx *ctx, struct ib_qp *qp, u8 port_num,
struct ib_device *dev = qp->pd->device;
int ret;
- ret = ib_dma_map_sg(dev, sg, sg_cnt, dir);
+ if (is_pci_p2pdma_page(sg_page(sg)))
+ ret = pci_p2pdma_map_sg(dev->dma_device, sg, sg_cnt, dir);
+ else
+ ret = ib_dma_map_sg(dev, sg, sg_cnt, dir);
+
if (!ret)
return -ENOMEM;
sg_cnt = ret;
@@ -602,7 +607,9 @@ void rdma_rw_ctx_destroy(struct rdma_rw_ctx *ctx, struct ib_qp *qp, u8 port_num,
break;
}
- ib_dma_unmap_sg(qp->pd->device, sg, sg_cnt, dir);
+ /* P2PDMA contexts do not need to be unmapped */
+ if (!is_pci_p2pdma_page(sg_page(sg)))
+ ib_dma_unmap_sg(qp->pd->device, sg, sg_cnt, dir);
}
EXPORT_SYMBOL(rdma_rw_ctx_destroy);
diff --git a/drivers/infiniband/core/sa.h b/drivers/infiniband/core/sa.h
index b1d4bbf4ce5c..cbaaaa92fff3 100644
--- a/drivers/infiniband/core/sa.h
+++ b/drivers/infiniband/core/sa.h
@@ -49,16 +49,14 @@ static inline void ib_sa_client_put(struct ib_sa_client *client)
}
int ib_sa_mcmember_rec_query(struct ib_sa_client *client,
- struct ib_device *device, u8 port_num,
- u8 method,
+ struct ib_device *device, u8 port_num, u8 method,
struct ib_sa_mcmember_rec *rec,
ib_sa_comp_mask comp_mask,
- int timeout_ms, gfp_t gfp_mask,
+ unsigned long timeout_ms, gfp_t gfp_mask,
void (*callback)(int status,
struct ib_sa_mcmember_rec *resp,
void *context),
- void *context,
- struct ib_sa_query **sa_query);
+ void *context, struct ib_sa_query **sa_query);
int mcast_init(void);
void mcast_cleanup(void);
diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c
index 7b794a14d6e8..be5ba5e15496 100644
--- a/drivers/infiniband/core/sa_query.c
+++ b/drivers/infiniband/core/sa_query.c
@@ -761,7 +761,7 @@ static void ib_nl_set_path_rec_attrs(struct sk_buff *skb,
/* Construct the family header first */
header = skb_put(skb, NLMSG_ALIGN(sizeof(*header)));
- memcpy(header->device_name, query->port->agent->device->name,
+ memcpy(header->device_name, dev_name(&query->port->agent->device->dev),
LS_DEVICE_NAME_MAX);
header->port_num = query->port->port_num;
@@ -835,7 +835,6 @@ static int ib_nl_send_msg(struct ib_sa_query *query, gfp_t gfp_mask)
struct sk_buff *skb = NULL;
struct nlmsghdr *nlh;
void *data;
- int ret = 0;
struct ib_sa_mad *mad;
int len;
@@ -862,13 +861,7 @@ static int ib_nl_send_msg(struct ib_sa_query *query, gfp_t gfp_mask)
/* Repair the nlmsg header length */
nlmsg_end(skb, nlh);
- ret = rdma_nl_multicast(skb, RDMA_NL_GROUP_LS, gfp_mask);
- if (!ret)
- ret = len;
- else
- ret = 0;
-
- return ret;
+ return rdma_nl_multicast(skb, RDMA_NL_GROUP_LS, gfp_mask);
}
static int ib_nl_make_request(struct ib_sa_query *query, gfp_t gfp_mask)
@@ -891,14 +884,12 @@ static int ib_nl_make_request(struct ib_sa_query *query, gfp_t gfp_mask)
spin_unlock_irqrestore(&ib_nl_request_lock, flags);
ret = ib_nl_send_msg(query, gfp_mask);
- if (ret <= 0) {
+ if (ret) {
ret = -EIO;
/* Remove the request */
spin_lock_irqsave(&ib_nl_request_lock, flags);
list_del(&query->list);
spin_unlock_irqrestore(&ib_nl_request_lock, flags);
- } else {
- ret = 0;
}
return ret;
@@ -1227,46 +1218,6 @@ static u8 get_src_path_mask(struct ib_device *device, u8 port_num)
return src_path_mask;
}
-static int roce_resolve_route_from_path(struct sa_path_rec *rec,
- const struct ib_gid_attr *attr)
-{
- struct rdma_dev_addr dev_addr = {};
- union {
- struct sockaddr _sockaddr;
- struct sockaddr_in _sockaddr_in;
- struct sockaddr_in6 _sockaddr_in6;
- } sgid_addr, dgid_addr;
- int ret;
-
- if (rec->roce.route_resolved)
- return 0;
- if (!attr || !attr->ndev)
- return -EINVAL;
-
- dev_addr.bound_dev_if = attr->ndev->ifindex;
- /* TODO: Use net from the ib_gid_attr once it is added to it,
- * until than, limit itself to init_net.
- */
- dev_addr.net = &init_net;
-
- rdma_gid2ip(&sgid_addr._sockaddr, &rec->sgid);
- rdma_gid2ip(&dgid_addr._sockaddr, &rec->dgid);
-
- /* validate the route */
- ret = rdma_resolve_ip_route(&sgid_addr._sockaddr,
- &dgid_addr._sockaddr, &dev_addr);
- if (ret)
- return ret;
-
- if ((dev_addr.network == RDMA_NETWORK_IPV4 ||
- dev_addr.network == RDMA_NETWORK_IPV6) &&
- rec->rec_type != SA_PATH_REC_TYPE_ROCE_V2)
- return -EINVAL;
-
- rec->roce.route_resolved = true;
- return 0;
-}
-
static int init_ah_attr_grh_fields(struct ib_device *device, u8 port_num,
struct sa_path_rec *rec,
struct rdma_ah_attr *ah_attr,
@@ -1409,7 +1360,8 @@ static void init_mad(struct ib_sa_query *query, struct ib_mad_agent *agent)
spin_unlock_irqrestore(&tid_lock, flags);
}
-static int send_mad(struct ib_sa_query *query, int timeout_ms, gfp_t gfp_mask)
+static int send_mad(struct ib_sa_query *query, unsigned long timeout_ms,
+ gfp_t gfp_mask)
{
bool preload = gfpflags_allow_blocking(gfp_mask);
unsigned long flags;
@@ -1433,7 +1385,7 @@ static int send_mad(struct ib_sa_query *query, int timeout_ms, gfp_t gfp_mask)
if ((query->flags & IB_SA_ENABLE_LOCAL_SERVICE) &&
(!(query->flags & IB_SA_QUERY_OPA))) {
- if (!rdma_nl_chk_listeners(RDMA_NL_GROUP_LS)) {
+ if (rdma_nl_chk_listeners(RDMA_NL_GROUP_LS)) {
if (!ib_nl_make_request(query, gfp_mask))
return id;
}
@@ -1599,7 +1551,7 @@ int ib_sa_path_rec_get(struct ib_sa_client *client,
struct ib_device *device, u8 port_num,
struct sa_path_rec *rec,
ib_sa_comp_mask comp_mask,
- int timeout_ms, gfp_t gfp_mask,
+ unsigned long timeout_ms, gfp_t gfp_mask,
void (*callback)(int status,
struct sa_path_rec *resp,
void *context),
@@ -1753,7 +1705,7 @@ int ib_sa_service_rec_query(struct ib_sa_client *client,
struct ib_device *device, u8 port_num, u8 method,
struct ib_sa_service_rec *rec,
ib_sa_comp_mask comp_mask,
- int timeout_ms, gfp_t gfp_mask,
+ unsigned long timeout_ms, gfp_t gfp_mask,
void (*callback)(int status,
struct ib_sa_service_rec *resp,
void *context),
@@ -1850,7 +1802,7 @@ int ib_sa_mcmember_rec_query(struct ib_sa_client *client,
u8 method,
struct ib_sa_mcmember_rec *rec,
ib_sa_comp_mask comp_mask,
- int timeout_ms, gfp_t gfp_mask,
+ unsigned long timeout_ms, gfp_t gfp_mask,
void (*callback)(int status,
struct ib_sa_mcmember_rec *resp,
void *context),
@@ -1941,7 +1893,7 @@ int ib_sa_guid_info_rec_query(struct ib_sa_client *client,
struct ib_device *device, u8 port_num,
struct ib_sa_guidinfo_rec *rec,
ib_sa_comp_mask comp_mask, u8 method,
- int timeout_ms, gfp_t gfp_mask,
+ unsigned long timeout_ms, gfp_t gfp_mask,
void (*callback)(int status,
struct ib_sa_guidinfo_rec *resp,
void *context),
@@ -2108,7 +2060,7 @@ static void ib_sa_classport_info_rec_release(struct ib_sa_query *sa_query)
}
static int ib_sa_classport_info_rec_query(struct ib_sa_port *port,
- int timeout_ms,
+ unsigned long timeout_ms,
void (*callback)(void *context),
void *context,
struct ib_sa_query **sa_query)
diff --git a/drivers/infiniband/core/security.c b/drivers/infiniband/core/security.c
index 9b0bea8303e0..1143c0448666 100644
--- a/drivers/infiniband/core/security.c
+++ b/drivers/infiniband/core/security.c
@@ -685,9 +685,8 @@ static int ib_mad_agent_security_change(struct notifier_block *nb,
if (event != LSM_POLICY_CHANGE)
return NOTIFY_DONE;
- ag->smp_allowed = !security_ib_endport_manage_subnet(ag->security,
- ag->device->name,
- ag->port_num);
+ ag->smp_allowed = !security_ib_endport_manage_subnet(
+ ag->security, dev_name(&ag->device->dev), ag->port_num);
return NOTIFY_OK;
}
@@ -708,7 +707,7 @@ int ib_mad_agent_security_setup(struct ib_mad_agent *agent,
return 0;
ret = security_ib_endport_manage_subnet(agent->security,
- agent->device->name,
+ dev_name(&agent->device->dev),
agent->port_num);
if (ret)
return ret;
diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c
index 7fd14ead7b37..6fcce2c206c6 100644
--- a/drivers/infiniband/core/sysfs.c
+++ b/drivers/infiniband/core/sysfs.c
@@ -512,7 +512,7 @@ static ssize_t show_pma_counter(struct ib_port *p, struct port_attribute *attr,
ret = get_perf_mad(p->ibdev, p->port_num, tab_attr->attr_id, &data,
40 + offset / 8, sizeof(data));
if (ret < 0)
- return sprintf(buf, "N/A (no PMA)\n");
+ return ret;
switch (width) {
case 4:
@@ -1036,7 +1036,7 @@ static int add_port(struct ib_device *device, int port_num,
p->port_num = port_num;
ret = kobject_init_and_add(&p->kobj, &port_type,
- device->ports_parent,
+ device->ports_kobj,
"%d", port_num);
if (ret) {
kfree(p);
@@ -1057,10 +1057,12 @@ static int add_port(struct ib_device *device, int port_num,
goto err_put;
}
- 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;
+ if (device->process_mad) {
+ 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;
+ }
p->gid_group.name = "gids";
p->gid_group.attrs = alloc_group_attrs(show_port_gid, attr.gid_tbl_len);
@@ -1118,9 +1120,9 @@ static int add_port(struct ib_device *device, int port_num,
}
/*
- * If port == 0, it means we have only one port and the parent
- * device, not this port device, should be the holder of the
- * hw_counters
+ * 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.
*/
if (device->alloc_hw_stats && port_num)
setup_hw_stats(device, p, port_num);
@@ -1173,7 +1175,8 @@ err_free_gid:
p->gid_group.attrs = NULL;
err_remove_pma:
- sysfs_remove_group(&p->kobj, p->pma_table);
+ if (p->pma_table)
+ sysfs_remove_group(&p->kobj, p->pma_table);
err_put_gid_attrs:
kobject_put(&p->gid_attr_group->kobj);
@@ -1183,7 +1186,7 @@ err_put:
return ret;
}
-static ssize_t show_node_type(struct device *device,
+static ssize_t node_type_show(struct device *device,
struct device_attribute *attr, char *buf)
{
struct ib_device *dev = container_of(device, struct ib_device, dev);
@@ -1198,8 +1201,9 @@ static ssize_t show_node_type(struct device *device,
default: return sprintf(buf, "%d: <unknown>\n", dev->node_type);
}
}
+static DEVICE_ATTR_RO(node_type);
-static ssize_t show_sys_image_guid(struct device *device,
+static ssize_t sys_image_guid_show(struct device *device,
struct device_attribute *dev_attr, char *buf)
{
struct ib_device *dev = container_of(device, struct ib_device, dev);
@@ -1210,8 +1214,9 @@ static ssize_t show_sys_image_guid(struct device *device,
be16_to_cpu(((__be16 *) &dev->attrs.sys_image_guid)[2]),
be16_to_cpu(((__be16 *) &dev->attrs.sys_image_guid)[3]));
}
+static DEVICE_ATTR_RO(sys_image_guid);
-static ssize_t show_node_guid(struct device *device,
+static ssize_t node_guid_show(struct device *device,
struct device_attribute *attr, char *buf)
{
struct ib_device *dev = container_of(device, struct ib_device, dev);
@@ -1222,8 +1227,9 @@ static ssize_t show_node_guid(struct device *device,
be16_to_cpu(((__be16 *) &dev->node_guid)[2]),
be16_to_cpu(((__be16 *) &dev->node_guid)[3]));
}
+static DEVICE_ATTR_RO(node_guid);
-static ssize_t show_node_desc(struct device *device,
+static ssize_t node_desc_show(struct device *device,
struct device_attribute *attr, char *buf)
{
struct ib_device *dev = container_of(device, struct ib_device, dev);
@@ -1231,9 +1237,9 @@ static ssize_t show_node_desc(struct device *device,
return sprintf(buf, "%.64s\n", dev->node_desc);
}
-static ssize_t set_node_desc(struct device *device,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t node_desc_store(struct device *device,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct ib_device *dev = container_of(device, struct ib_device, dev);
struct ib_device_modify desc = {};
@@ -1249,8 +1255,9 @@ static ssize_t set_node_desc(struct device *device,
return count;
}
+static DEVICE_ATTR_RW(node_desc);
-static ssize_t show_fw_ver(struct device *device, struct device_attribute *attr,
+static ssize_t fw_ver_show(struct device *device, struct device_attribute *attr,
char *buf)
{
struct ib_device *dev = container_of(device, struct ib_device, dev);
@@ -1259,19 +1266,19 @@ static ssize_t show_fw_ver(struct device *device, struct device_attribute *attr,
strlcat(buf, "\n", IB_FW_VERSION_NAME_MAX);
return strlen(buf);
}
+static DEVICE_ATTR_RO(fw_ver);
+
+static struct attribute *ib_dev_attrs[] = {
+ &dev_attr_node_type.attr,
+ &dev_attr_node_guid.attr,
+ &dev_attr_sys_image_guid.attr,
+ &dev_attr_fw_ver.attr,
+ &dev_attr_node_desc.attr,
+ NULL,
+};
-static DEVICE_ATTR(node_type, S_IRUGO, show_node_type, NULL);
-static DEVICE_ATTR(sys_image_guid, S_IRUGO, show_sys_image_guid, NULL);
-static DEVICE_ATTR(node_guid, S_IRUGO, show_node_guid, NULL);
-static DEVICE_ATTR(node_desc, S_IRUGO | S_IWUSR, show_node_desc, set_node_desc);
-static DEVICE_ATTR(fw_ver, S_IRUGO, show_fw_ver, NULL);
-
-static struct device_attribute *ib_class_attributes[] = {
- &dev_attr_node_type,
- &dev_attr_sys_image_guid,
- &dev_attr_node_guid,
- &dev_attr_node_desc,
- &dev_attr_fw_ver,
+static const struct attribute_group dev_attr_group = {
+ .attrs = ib_dev_attrs,
};
static void free_port_list_attributes(struct ib_device *device)
@@ -1285,7 +1292,9 @@ static void free_port_list_attributes(struct ib_device *device)
kfree(port->hw_stats);
free_hsag(&port->kobj, port->hw_stats_ag);
}
- sysfs_remove_group(p, port->pma_table);
+
+ if (port->pma_table)
+ sysfs_remove_group(p, port->pma_table);
sysfs_remove_group(p, &port->pkey_group);
sysfs_remove_group(p, &port->gid_group);
sysfs_remove_group(&port->gid_attr_group->kobj,
@@ -1296,7 +1305,7 @@ static void free_port_list_attributes(struct ib_device *device)
kobject_put(p);
}
- kobject_put(device->ports_parent);
+ kobject_put(device->ports_kobj);
}
int ib_device_register_sysfs(struct ib_device *device,
@@ -1307,23 +1316,15 @@ int ib_device_register_sysfs(struct ib_device *device,
int ret;
int i;
- ret = dev_set_name(class_dev, "%s", device->name);
- if (ret)
- return ret;
+ device->groups[0] = &dev_attr_group;
+ class_dev->groups = device->groups;
ret = device_add(class_dev);
if (ret)
goto err;
- for (i = 0; i < ARRAY_SIZE(ib_class_attributes); ++i) {
- ret = device_create_file(class_dev, ib_class_attributes[i]);
- if (ret)
- goto err_unregister;
- }
-
- device->ports_parent = kobject_create_and_add("ports",
- &class_dev->kobj);
- if (!device->ports_parent) {
+ device->ports_kobj = kobject_create_and_add("ports", &class_dev->kobj);
+ if (!device->ports_kobj) {
ret = -ENOMEM;
goto err_put;
}
@@ -1347,20 +1348,15 @@ int ib_device_register_sysfs(struct ib_device *device,
err_put:
free_port_list_attributes(device);
-
-err_unregister:
device_del(class_dev);
-
err:
return ret;
}
void ib_device_unregister_sysfs(struct ib_device *device)
{
- int i;
-
- /* Hold kobject until ib_dealloc_device() */
- kobject_get(&device->dev.kobj);
+ /* Hold device until ib_dealloc_device() */
+ get_device(&device->dev);
free_port_list_attributes(device);
@@ -1369,8 +1365,5 @@ void ib_device_unregister_sysfs(struct ib_device *device)
free_hsag(&device->dev.kobj, device->hw_stats_ag);
}
- for (i = 0; i < ARRAY_SIZE(ib_class_attributes); ++i)
- device_remove_file(&device->dev, ib_class_attributes[i]);
-
device_unregister(&device->dev);
}
diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c
index faa9e6116b2f..73332b9a25b5 100644
--- a/drivers/infiniband/core/ucm.c
+++ b/drivers/infiniband/core/ucm.c
@@ -46,6 +46,8 @@
#include <linux/mutex.h>
#include <linux/slab.h>
+#include <linux/nospec.h>
+
#include <linux/uaccess.h>
#include <rdma/ib.h>
@@ -1120,6 +1122,7 @@ static ssize_t ib_ucm_write(struct file *filp, const char __user *buf,
if (hdr.cmd >= ARRAY_SIZE(ucm_cmd_table))
return -EINVAL;
+ hdr.cmd = array_index_nospec(hdr.cmd, ARRAY_SIZE(ucm_cmd_table));
if (hdr.in + sizeof(hdr) > len)
return -EINVAL;
diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c
index 21863ddde63e..01d68ed46c1b 100644
--- a/drivers/infiniband/core/ucma.c
+++ b/drivers/infiniband/core/ucma.c
@@ -44,6 +44,8 @@
#include <linux/module.h>
#include <linux/nsproxy.h>
+#include <linux/nospec.h>
+
#include <rdma/rdma_user_cm.h>
#include <rdma/ib_marshall.h>
#include <rdma/rdma_cm.h>
@@ -1676,6 +1678,7 @@ static ssize_t ucma_write(struct file *filp, const char __user *buf,
if (hdr.cmd >= ARRAY_SIZE(ucma_cmd_table))
return -EINVAL;
+ hdr.cmd = array_index_nospec(hdr.cmd, ARRAY_SIZE(ucma_cmd_table));
if (hdr.in + sizeof(hdr) > len)
return -EINVAL;
diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c
index a41792dbae1f..c6144df47ea4 100644
--- a/drivers/infiniband/core/umem.c
+++ b/drivers/infiniband/core/umem.c
@@ -85,7 +85,9 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
struct page **page_list;
struct vm_area_struct **vma_list;
unsigned long lock_limit;
+ unsigned long new_pinned;
unsigned long cur_base;
+ struct mm_struct *mm;
unsigned long npages;
int ret;
int i;
@@ -107,25 +109,32 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
if (!can_do_mlock())
return ERR_PTR(-EPERM);
- umem = kzalloc(sizeof *umem, GFP_KERNEL);
- if (!umem)
- return ERR_PTR(-ENOMEM);
+ if (access & IB_ACCESS_ON_DEMAND) {
+ umem = kzalloc(sizeof(struct ib_umem_odp), GFP_KERNEL);
+ if (!umem)
+ return ERR_PTR(-ENOMEM);
+ umem->is_odp = 1;
+ } else {
+ umem = kzalloc(sizeof(*umem), GFP_KERNEL);
+ if (!umem)
+ return ERR_PTR(-ENOMEM);
+ }
umem->context = context;
umem->length = size;
umem->address = addr;
umem->page_shift = PAGE_SHIFT;
umem->writable = ib_access_writable(access);
+ umem->owning_mm = mm = current->mm;
+ mmgrab(mm);
if (access & IB_ACCESS_ON_DEMAND) {
- ret = ib_umem_odp_get(context, umem, access);
+ ret = ib_umem_odp_get(to_ib_umem_odp(umem), access);
if (ret)
goto umem_kfree;
return umem;
}
- umem->odp_data = NULL;
-
/* We assume the memory is from hugetlb until proved otherwise */
umem->hugetlb = 1;
@@ -144,25 +153,25 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
umem->hugetlb = 0;
npages = ib_umem_num_pages(umem);
+ if (npages == 0 || npages > UINT_MAX) {
+ ret = -EINVAL;
+ goto out;
+ }
lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
- down_write(&current->mm->mmap_sem);
- current->mm->pinned_vm += npages;
- if ((current->mm->pinned_vm > lock_limit) && !capable(CAP_IPC_LOCK)) {
- up_write(&current->mm->mmap_sem);
+ down_write(&mm->mmap_sem);
+ if (check_add_overflow(mm->pinned_vm, npages, &new_pinned) ||
+ (new_pinned > lock_limit && !capable(CAP_IPC_LOCK))) {
+ up_write(&mm->mmap_sem);
ret = -ENOMEM;
- goto vma;
+ goto out;
}
- up_write(&current->mm->mmap_sem);
+ mm->pinned_vm = new_pinned;
+ up_write(&mm->mmap_sem);
cur_base = addr & PAGE_MASK;
- if (npages == 0 || npages > UINT_MAX) {
- ret = -EINVAL;
- goto vma;
- }
-
ret = sg_alloc_table(&umem->sg_head, npages, GFP_KERNEL);
if (ret)
goto vma;
@@ -172,14 +181,14 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
sg_list_start = umem->sg_head.sgl;
- down_read(&current->mm->mmap_sem);
while (npages) {
+ down_read(&mm->mmap_sem);
ret = get_user_pages_longterm(cur_base,
min_t(unsigned long, npages,
PAGE_SIZE / sizeof (struct page *)),
gup_flags, page_list, vma_list);
if (ret < 0) {
- up_read(&current->mm->mmap_sem);
+ up_read(&mm->mmap_sem);
goto umem_release;
}
@@ -187,17 +196,20 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
cur_base += ret * PAGE_SIZE;
npages -= ret;
+ /* Continue to hold the mmap_sem as vma_list access
+ * needs to be protected.
+ */
for_each_sg(sg_list_start, sg, ret, i) {
if (vma_list && !is_vm_hugetlb_page(vma_list[i]))
umem->hugetlb = 0;
sg_set_page(sg, page_list[i], PAGE_SIZE, 0);
}
+ up_read(&mm->mmap_sem);
/* preparing for next loop */
sg_list_start = sg;
}
- up_read(&current->mm->mmap_sem);
umem->nmap = ib_dma_map_sg_attrs(context->device,
umem->sg_head.sgl,
@@ -216,29 +228,40 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
umem_release:
__ib_umem_release(context->device, umem, 0);
vma:
- down_write(&current->mm->mmap_sem);
- current->mm->pinned_vm -= ib_umem_num_pages(umem);
- up_write(&current->mm->mmap_sem);
+ down_write(&mm->mmap_sem);
+ mm->pinned_vm -= ib_umem_num_pages(umem);
+ up_write(&mm->mmap_sem);
out:
if (vma_list)
free_page((unsigned long) vma_list);
free_page((unsigned long) page_list);
umem_kfree:
- if (ret)
+ if (ret) {
+ mmdrop(umem->owning_mm);
kfree(umem);
+ }
return ret ? ERR_PTR(ret) : umem;
}
EXPORT_SYMBOL(ib_umem_get);
-static void ib_umem_account(struct work_struct *work)
+static void __ib_umem_release_tail(struct ib_umem *umem)
+{
+ mmdrop(umem->owning_mm);
+ if (umem->is_odp)
+ kfree(to_ib_umem_odp(umem));
+ else
+ kfree(umem);
+}
+
+static void ib_umem_release_defer(struct work_struct *work)
{
struct ib_umem *umem = container_of(work, struct ib_umem, work);
- down_write(&umem->mm->mmap_sem);
- umem->mm->pinned_vm -= umem->diff;
- up_write(&umem->mm->mmap_sem);
- mmput(umem->mm);
- kfree(umem);
+ down_write(&umem->owning_mm->mmap_sem);
+ umem->owning_mm->pinned_vm -= ib_umem_num_pages(umem);
+ up_write(&umem->owning_mm->mmap_sem);
+
+ __ib_umem_release_tail(umem);
}
/**
@@ -248,52 +271,36 @@ static void ib_umem_account(struct work_struct *work)
void ib_umem_release(struct ib_umem *umem)
{
struct ib_ucontext *context = umem->context;
- struct mm_struct *mm;
- struct task_struct *task;
- unsigned long diff;
- if (umem->odp_data) {
- ib_umem_odp_release(umem);
+ if (umem->is_odp) {
+ ib_umem_odp_release(to_ib_umem_odp(umem));
+ __ib_umem_release_tail(umem);
return;
}
__ib_umem_release(umem->context->device, umem, 1);
- task = get_pid_task(umem->context->tgid, PIDTYPE_PID);
- if (!task)
- goto out;
- mm = get_task_mm(task);
- put_task_struct(task);
- if (!mm)
- goto out;
-
- diff = ib_umem_num_pages(umem);
-
/*
* We may be called with the mm's mmap_sem already held. This
* can happen when a userspace munmap() is the call that drops
* the last reference to our file and calls our release
* method. If there are memory regions to destroy, we'll end
* up here and not be able to take the mmap_sem. In that case
- * we defer the vm_locked accounting to the system workqueue.
+ * we defer the vm_locked accounting a workqueue.
*/
if (context->closing) {
- if (!down_write_trylock(&mm->mmap_sem)) {
- INIT_WORK(&umem->work, ib_umem_account);
- umem->mm = mm;
- umem->diff = diff;
-
+ if (!down_write_trylock(&umem->owning_mm->mmap_sem)) {
+ INIT_WORK(&umem->work, ib_umem_release_defer);
queue_work(ib_wq, &umem->work);
return;
}
- } else
- down_write(&mm->mmap_sem);
+ } else {
+ down_write(&umem->owning_mm->mmap_sem);
+ }
+ umem->owning_mm->pinned_vm -= ib_umem_num_pages(umem);
+ up_write(&umem->owning_mm->mmap_sem);
- mm->pinned_vm -= diff;
- up_write(&mm->mmap_sem);
- mmput(mm);
-out:
- kfree(umem);
+ __ib_umem_release_tail(umem);
}
EXPORT_SYMBOL(ib_umem_release);
@@ -303,7 +310,7 @@ int ib_umem_page_count(struct ib_umem *umem)
int n;
struct scatterlist *sg;
- if (umem->odp_data)
+ if (umem->is_odp)
return ib_umem_num_pages(umem);
n = 0;
diff --git a/drivers/infiniband/core/umem_odp.c b/drivers/infiniband/core/umem_odp.c
index 6ec748eccff7..2b4c5e7dd5a1 100644
--- a/drivers/infiniband/core/umem_odp.c
+++ b/drivers/infiniband/core/umem_odp.c
@@ -58,7 +58,7 @@ static u64 node_start(struct umem_odp_node *n)
struct ib_umem_odp *umem_odp =
container_of(n, struct ib_umem_odp, interval_tree);
- return ib_umem_start(umem_odp->umem);
+ return ib_umem_start(&umem_odp->umem);
}
/* Note that the representation of the intervals in the interval tree
@@ -71,140 +71,86 @@ static u64 node_last(struct umem_odp_node *n)
struct ib_umem_odp *umem_odp =
container_of(n, struct ib_umem_odp, interval_tree);
- return ib_umem_end(umem_odp->umem) - 1;
+ return ib_umem_end(&umem_odp->umem) - 1;
}
INTERVAL_TREE_DEFINE(struct umem_odp_node, rb, u64, __subtree_last,
node_start, node_last, static, rbt_ib_umem)
-static void ib_umem_notifier_start_account(struct ib_umem *item)
+static void ib_umem_notifier_start_account(struct ib_umem_odp *umem_odp)
{
- mutex_lock(&item->odp_data->umem_mutex);
-
- /* Only update private counters for this umem if it has them.
- * Otherwise skip it. All page faults will be delayed for this umem. */
- if (item->odp_data->mn_counters_active) {
- int notifiers_count = item->odp_data->notifiers_count++;
-
- if (notifiers_count == 0)
- /* Initialize the completion object for waiting on
- * notifiers. Since notifier_count is zero, no one
- * should be waiting right now. */
- reinit_completion(&item->odp_data->notifier_completion);
- }
- mutex_unlock(&item->odp_data->umem_mutex);
-}
-
-static void ib_umem_notifier_end_account(struct ib_umem *item)
-{
- mutex_lock(&item->odp_data->umem_mutex);
-
- /* Only update private counters for this umem if it has them.
- * Otherwise skip it. All page faults will be delayed for this umem. */
- if (item->odp_data->mn_counters_active) {
+ mutex_lock(&umem_odp->umem_mutex);
+ if (umem_odp->notifiers_count++ == 0)
/*
- * This sequence increase will notify the QP page fault that
- * the page that is going to be mapped in the spte could have
- * been freed.
+ * Initialize the completion object for waiting on
+ * notifiers. Since notifier_count is zero, no one should be
+ * waiting right now.
*/
- ++item->odp_data->notifiers_seq;
- if (--item->odp_data->notifiers_count == 0)
- complete_all(&item->odp_data->notifier_completion);
- }
- mutex_unlock(&item->odp_data->umem_mutex);
+ reinit_completion(&umem_odp->notifier_completion);
+ mutex_unlock(&umem_odp->umem_mutex);
}
-/* Account for a new mmu notifier in an ib_ucontext. */
-static void ib_ucontext_notifier_start_account(struct ib_ucontext *context)
+static void ib_umem_notifier_end_account(struct ib_umem_odp *umem_odp)
{
- atomic_inc(&context->notifier_count);
+ mutex_lock(&umem_odp->umem_mutex);
+ /*
+ * This sequence increase will notify the QP page fault that the page
+ * that is going to be mapped in the spte could have been freed.
+ */
+ ++umem_odp->notifiers_seq;
+ if (--umem_odp->notifiers_count == 0)
+ complete_all(&umem_odp->notifier_completion);
+ mutex_unlock(&umem_odp->umem_mutex);
}
-/* Account for a terminating mmu notifier in an ib_ucontext.
- *
- * Must be called with the ib_ucontext->umem_rwsem semaphore unlocked, since
- * the function takes the semaphore itself. */
-static void ib_ucontext_notifier_end_account(struct ib_ucontext *context)
+static int ib_umem_notifier_release_trampoline(struct ib_umem_odp *umem_odp,
+ u64 start, u64 end, void *cookie)
{
- int zero_notifiers = atomic_dec_and_test(&context->notifier_count);
-
- if (zero_notifiers &&
- !list_empty(&context->no_private_counters)) {
- /* No currently running mmu notifiers. Now is the chance to
- * add private accounting to all previously added umems. */
- struct ib_umem_odp *odp_data, *next;
-
- /* Prevent concurrent mmu notifiers from working on the
- * no_private_counters list. */
- down_write(&context->umem_rwsem);
-
- /* Read the notifier_count again, with the umem_rwsem
- * semaphore taken for write. */
- if (!atomic_read(&context->notifier_count)) {
- list_for_each_entry_safe(odp_data, next,
- &context->no_private_counters,
- no_private_counters) {
- mutex_lock(&odp_data->umem_mutex);
- odp_data->mn_counters_active = true;
- list_del(&odp_data->no_private_counters);
- complete_all(&odp_data->notifier_completion);
- mutex_unlock(&odp_data->umem_mutex);
- }
- }
-
- up_write(&context->umem_rwsem);
- }
-}
+ struct ib_umem *umem = &umem_odp->umem;
-static int ib_umem_notifier_release_trampoline(struct ib_umem *item, u64 start,
- u64 end, void *cookie) {
/*
* Increase the number of notifiers running, to
* prevent any further fault handling on this MR.
*/
- ib_umem_notifier_start_account(item);
- item->odp_data->dying = 1;
+ ib_umem_notifier_start_account(umem_odp);
+ umem_odp->dying = 1;
/* Make sure that the fact the umem is dying is out before we release
* all pending page faults. */
smp_wmb();
- complete_all(&item->odp_data->notifier_completion);
- item->context->invalidate_range(item, ib_umem_start(item),
- ib_umem_end(item));
+ complete_all(&umem_odp->notifier_completion);
+ umem->context->invalidate_range(umem_odp, ib_umem_start(umem),
+ ib_umem_end(umem));
return 0;
}
static void ib_umem_notifier_release(struct mmu_notifier *mn,
struct mm_struct *mm)
{
- struct ib_ucontext *context = container_of(mn, struct ib_ucontext, mn);
-
- if (!context->invalidate_range)
- return;
-
- ib_ucontext_notifier_start_account(context);
- down_read(&context->umem_rwsem);
- rbt_ib_umem_for_each_in_range(&context->umem_tree, 0,
- ULLONG_MAX,
- ib_umem_notifier_release_trampoline,
- true,
- NULL);
- up_read(&context->umem_rwsem);
+ struct ib_ucontext_per_mm *per_mm =
+ container_of(mn, struct ib_ucontext_per_mm, mn);
+
+ down_read(&per_mm->umem_rwsem);
+ if (per_mm->active)
+ rbt_ib_umem_for_each_in_range(
+ &per_mm->umem_tree, 0, ULLONG_MAX,
+ ib_umem_notifier_release_trampoline, true, NULL);
+ up_read(&per_mm->umem_rwsem);
}
-static int invalidate_page_trampoline(struct ib_umem *item, u64 start,
+static int invalidate_page_trampoline(struct ib_umem_odp *item, u64 start,
u64 end, void *cookie)
{
ib_umem_notifier_start_account(item);
- item->context->invalidate_range(item, start, start + PAGE_SIZE);
+ item->umem.context->invalidate_range(item, start, start + PAGE_SIZE);
ib_umem_notifier_end_account(item);
return 0;
}
-static int invalidate_range_start_trampoline(struct ib_umem *item, u64 start,
- u64 end, void *cookie)
+static int invalidate_range_start_trampoline(struct ib_umem_odp *item,
+ u64 start, u64 end, void *cookie)
{
ib_umem_notifier_start_account(item);
- item->context->invalidate_range(item, start, end);
+ item->umem.context->invalidate_range(item, start, end);
return 0;
}
@@ -214,28 +160,30 @@ static int ib_umem_notifier_invalidate_range_start(struct mmu_notifier *mn,
unsigned long end,
bool blockable)
{
- struct ib_ucontext *context = container_of(mn, struct ib_ucontext, mn);
- int ret;
-
- if (!context->invalidate_range)
- return 0;
+ struct ib_ucontext_per_mm *per_mm =
+ container_of(mn, struct ib_ucontext_per_mm, mn);
if (blockable)
- down_read(&context->umem_rwsem);
- else if (!down_read_trylock(&context->umem_rwsem))
+ down_read(&per_mm->umem_rwsem);
+ else if (!down_read_trylock(&per_mm->umem_rwsem))
return -EAGAIN;
- ib_ucontext_notifier_start_account(context);
- ret = rbt_ib_umem_for_each_in_range(&context->umem_tree, start,
- end,
- invalidate_range_start_trampoline,
- blockable, NULL);
- up_read(&context->umem_rwsem);
+ if (!per_mm->active) {
+ up_read(&per_mm->umem_rwsem);
+ /*
+ * At this point active is permanently set and visible to this
+ * CPU without a lock, that fact is relied on to skip the unlock
+ * in range_end.
+ */
+ return 0;
+ }
- return ret;
+ return rbt_ib_umem_for_each_in_range(&per_mm->umem_tree, start, end,
+ invalidate_range_start_trampoline,
+ blockable, NULL);
}
-static int invalidate_range_end_trampoline(struct ib_umem *item, u64 start,
+static int invalidate_range_end_trampoline(struct ib_umem_odp *item, u64 start,
u64 end, void *cookie)
{
ib_umem_notifier_end_account(item);
@@ -247,22 +195,16 @@ static void ib_umem_notifier_invalidate_range_end(struct mmu_notifier *mn,
unsigned long start,
unsigned long end)
{
- struct ib_ucontext *context = container_of(mn, struct ib_ucontext, mn);
+ struct ib_ucontext_per_mm *per_mm =
+ container_of(mn, struct ib_ucontext_per_mm, mn);
- if (!context->invalidate_range)
+ if (unlikely(!per_mm->active))
return;
- /*
- * TODO: we currently bail out if there is any sleepable work to be done
- * in ib_umem_notifier_invalidate_range_start so we shouldn't really block
- * here. But this is ugly and fragile.
- */
- down_read(&context->umem_rwsem);
- rbt_ib_umem_for_each_in_range(&context->umem_tree, start,
+ rbt_ib_umem_for_each_in_range(&per_mm->umem_tree, start,
end,
invalidate_range_end_trampoline, true, NULL);
- up_read(&context->umem_rwsem);
- ib_ucontext_notifier_end_account(context);
+ up_read(&per_mm->umem_rwsem);
}
static const struct mmu_notifier_ops ib_umem_notifiers = {
@@ -271,31 +213,158 @@ static const struct mmu_notifier_ops ib_umem_notifiers = {
.invalidate_range_end = ib_umem_notifier_invalidate_range_end,
};
-struct ib_umem *ib_alloc_odp_umem(struct ib_ucontext *context,
- unsigned long addr,
- size_t size)
+static void add_umem_to_per_mm(struct ib_umem_odp *umem_odp)
{
- struct ib_umem *umem;
+ struct ib_ucontext_per_mm *per_mm = umem_odp->per_mm;
+ struct ib_umem *umem = &umem_odp->umem;
+
+ down_write(&per_mm->umem_rwsem);
+ if (likely(ib_umem_start(umem) != ib_umem_end(umem)))
+ rbt_ib_umem_insert(&umem_odp->interval_tree,
+ &per_mm->umem_tree);
+ up_write(&per_mm->umem_rwsem);
+}
+
+static void remove_umem_from_per_mm(struct ib_umem_odp *umem_odp)
+{
+ struct ib_ucontext_per_mm *per_mm = umem_odp->per_mm;
+ struct ib_umem *umem = &umem_odp->umem;
+
+ down_write(&per_mm->umem_rwsem);
+ if (likely(ib_umem_start(umem) != ib_umem_end(umem)))
+ rbt_ib_umem_remove(&umem_odp->interval_tree,
+ &per_mm->umem_tree);
+ complete_all(&umem_odp->notifier_completion);
+
+ up_write(&per_mm->umem_rwsem);
+}
+
+static struct ib_ucontext_per_mm *alloc_per_mm(struct ib_ucontext *ctx,
+ struct mm_struct *mm)
+{
+ struct ib_ucontext_per_mm *per_mm;
+ int ret;
+
+ per_mm = kzalloc(sizeof(*per_mm), GFP_KERNEL);
+ if (!per_mm)
+ return ERR_PTR(-ENOMEM);
+
+ per_mm->context = ctx;
+ per_mm->mm = mm;
+ per_mm->umem_tree = RB_ROOT_CACHED;
+ init_rwsem(&per_mm->umem_rwsem);
+ per_mm->active = ctx->invalidate_range;
+
+ rcu_read_lock();
+ per_mm->tgid = get_task_pid(current->group_leader, PIDTYPE_PID);
+ rcu_read_unlock();
+
+ WARN_ON(mm != current->mm);
+
+ per_mm->mn.ops = &ib_umem_notifiers;
+ ret = mmu_notifier_register(&per_mm->mn, per_mm->mm);
+ if (ret) {
+ dev_err(&ctx->device->dev,
+ "Failed to register mmu_notifier %d\n", ret);
+ goto out_pid;
+ }
+
+ list_add(&per_mm->ucontext_list, &ctx->per_mm_list);
+ return per_mm;
+
+out_pid:
+ put_pid(per_mm->tgid);
+ kfree(per_mm);
+ return ERR_PTR(ret);
+}
+
+static int get_per_mm(struct ib_umem_odp *umem_odp)
+{
+ struct ib_ucontext *ctx = umem_odp->umem.context;
+ struct ib_ucontext_per_mm *per_mm;
+
+ /*
+ * Generally speaking we expect only one or two per_mm in this list,
+ * so no reason to optimize this search today.
+ */
+ mutex_lock(&ctx->per_mm_list_lock);
+ list_for_each_entry(per_mm, &ctx->per_mm_list, ucontext_list) {
+ if (per_mm->mm == umem_odp->umem.owning_mm)
+ goto found;
+ }
+
+ per_mm = alloc_per_mm(ctx, umem_odp->umem.owning_mm);
+ if (IS_ERR(per_mm)) {
+ mutex_unlock(&ctx->per_mm_list_lock);
+ return PTR_ERR(per_mm);
+ }
+
+found:
+ umem_odp->per_mm = per_mm;
+ per_mm->odp_mrs_count++;
+ mutex_unlock(&ctx->per_mm_list_lock);
+
+ return 0;
+}
+
+static void free_per_mm(struct rcu_head *rcu)
+{
+ kfree(container_of(rcu, struct ib_ucontext_per_mm, rcu));
+}
+
+void put_per_mm(struct ib_umem_odp *umem_odp)
+{
+ struct ib_ucontext_per_mm *per_mm = umem_odp->per_mm;
+ struct ib_ucontext *ctx = umem_odp->umem.context;
+ bool need_free;
+
+ mutex_lock(&ctx->per_mm_list_lock);
+ umem_odp->per_mm = NULL;
+ per_mm->odp_mrs_count--;
+ need_free = per_mm->odp_mrs_count == 0;
+ if (need_free)
+ list_del(&per_mm->ucontext_list);
+ mutex_unlock(&ctx->per_mm_list_lock);
+
+ if (!need_free)
+ return;
+
+ /*
+ * NOTE! mmu_notifier_unregister() can happen between a start/end
+ * callback, resulting in an start/end, and thus an unbalanced
+ * lock. This doesn't really matter to us since we are about to kfree
+ * the memory that holds the lock, however LOCKDEP doesn't like this.
+ */
+ down_write(&per_mm->umem_rwsem);
+ per_mm->active = false;
+ up_write(&per_mm->umem_rwsem);
+
+ WARN_ON(!RB_EMPTY_ROOT(&per_mm->umem_tree.rb_root));
+ mmu_notifier_unregister_no_release(&per_mm->mn, per_mm->mm);
+ put_pid(per_mm->tgid);
+ mmu_notifier_call_srcu(&per_mm->rcu, free_per_mm);
+}
+
+struct ib_umem_odp *ib_alloc_odp_umem(struct ib_ucontext_per_mm *per_mm,
+ unsigned long addr, size_t size)
+{
+ struct ib_ucontext *ctx = per_mm->context;
struct ib_umem_odp *odp_data;
+ struct ib_umem *umem;
int pages = size >> PAGE_SHIFT;
int ret;
- umem = kzalloc(sizeof(*umem), GFP_KERNEL);
- if (!umem)
+ odp_data = kzalloc(sizeof(*odp_data), GFP_KERNEL);
+ if (!odp_data)
return ERR_PTR(-ENOMEM);
-
- umem->context = context;
+ umem = &odp_data->umem;
+ umem->context = ctx;
umem->length = size;
umem->address = addr;
umem->page_shift = PAGE_SHIFT;
umem->writable = 1;
-
- odp_data = kzalloc(sizeof(*odp_data), GFP_KERNEL);
- if (!odp_data) {
- ret = -ENOMEM;
- goto out_umem;
- }
- odp_data->umem = umem;
+ umem->is_odp = 1;
+ odp_data->per_mm = per_mm;
mutex_init(&odp_data->umem_mutex);
init_completion(&odp_data->notifier_completion);
@@ -314,39 +383,34 @@ struct ib_umem *ib_alloc_odp_umem(struct ib_ucontext *context,
goto out_page_list;
}
- down_write(&context->umem_rwsem);
- context->odp_mrs_count++;
- rbt_ib_umem_insert(&odp_data->interval_tree, &context->umem_tree);
- if (likely(!atomic_read(&context->notifier_count)))
- odp_data->mn_counters_active = true;
- else
- list_add(&odp_data->no_private_counters,
- &context->no_private_counters);
- up_write(&context->umem_rwsem);
-
- umem->odp_data = odp_data;
+ /*
+ * Caller must ensure that the umem_odp that the per_mm came from
+ * cannot be freed during the call to ib_alloc_odp_umem.
+ */
+ mutex_lock(&ctx->per_mm_list_lock);
+ per_mm->odp_mrs_count++;
+ mutex_unlock(&ctx->per_mm_list_lock);
+ add_umem_to_per_mm(odp_data);
- return umem;
+ return odp_data;
out_page_list:
vfree(odp_data->page_list);
out_odp_data:
kfree(odp_data);
-out_umem:
- kfree(umem);
return ERR_PTR(ret);
}
EXPORT_SYMBOL(ib_alloc_odp_umem);
-int ib_umem_odp_get(struct ib_ucontext *context, struct ib_umem *umem,
- int access)
+int ib_umem_odp_get(struct ib_umem_odp *umem_odp, int access)
{
+ struct ib_umem *umem = &umem_odp->umem;
+ /*
+ * NOTE: This must called in a process context where umem->owning_mm
+ * == current->mm
+ */
+ struct mm_struct *mm = umem->owning_mm;
int ret_val;
- struct pid *our_pid;
- struct mm_struct *mm = get_task_mm(current);
-
- if (!mm)
- return -EINVAL;
if (access & IB_ACCESS_HUGETLB) {
struct vm_area_struct *vma;
@@ -366,111 +430,43 @@ int ib_umem_odp_get(struct ib_ucontext *context, struct ib_umem *umem,
umem->hugetlb = 0;
}
- /* Prevent creating ODP MRs in child processes */
- rcu_read_lock();
- our_pid = get_task_pid(current->group_leader, PIDTYPE_PID);
- rcu_read_unlock();
- put_pid(our_pid);
- if (context->tgid != our_pid) {
- ret_val = -EINVAL;
- goto out_mm;
- }
-
- umem->odp_data = kzalloc(sizeof(*umem->odp_data), GFP_KERNEL);
- if (!umem->odp_data) {
- ret_val = -ENOMEM;
- goto out_mm;
- }
- umem->odp_data->umem = umem;
-
- mutex_init(&umem->odp_data->umem_mutex);
+ mutex_init(&umem_odp->umem_mutex);
- init_completion(&umem->odp_data->notifier_completion);
+ init_completion(&umem_odp->notifier_completion);
if (ib_umem_num_pages(umem)) {
- umem->odp_data->page_list =
- vzalloc(array_size(sizeof(*umem->odp_data->page_list),
+ umem_odp->page_list =
+ vzalloc(array_size(sizeof(*umem_odp->page_list),
ib_umem_num_pages(umem)));
- if (!umem->odp_data->page_list) {
- ret_val = -ENOMEM;
- goto out_odp_data;
- }
+ if (!umem_odp->page_list)
+ return -ENOMEM;
- umem->odp_data->dma_list =
- vzalloc(array_size(sizeof(*umem->odp_data->dma_list),
+ umem_odp->dma_list =
+ vzalloc(array_size(sizeof(*umem_odp->dma_list),
ib_umem_num_pages(umem)));
- if (!umem->odp_data->dma_list) {
+ if (!umem_odp->dma_list) {
ret_val = -ENOMEM;
goto out_page_list;
}
}
- /*
- * When using MMU notifiers, we will get a
- * notification before the "current" task (and MM) is
- * destroyed. We use the umem_rwsem semaphore to synchronize.
- */
- down_write(&context->umem_rwsem);
- context->odp_mrs_count++;
- if (likely(ib_umem_start(umem) != ib_umem_end(umem)))
- rbt_ib_umem_insert(&umem->odp_data->interval_tree,
- &context->umem_tree);
- if (likely(!atomic_read(&context->notifier_count)) ||
- context->odp_mrs_count == 1)
- umem->odp_data->mn_counters_active = true;
- else
- list_add(&umem->odp_data->no_private_counters,
- &context->no_private_counters);
- downgrade_write(&context->umem_rwsem);
-
- if (context->odp_mrs_count == 1) {
- /*
- * Note that at this point, no MMU notifier is running
- * for this context!
- */
- atomic_set(&context->notifier_count, 0);
- INIT_HLIST_NODE(&context->mn.hlist);
- context->mn.ops = &ib_umem_notifiers;
- /*
- * Lock-dep detects a false positive for mmap_sem vs.
- * umem_rwsem, due to not grasping downgrade_write correctly.
- */
- lockdep_off();
- ret_val = mmu_notifier_register(&context->mn, mm);
- lockdep_on();
- if (ret_val) {
- pr_err("Failed to register mmu_notifier %d\n", ret_val);
- ret_val = -EBUSY;
- goto out_mutex;
- }
- }
-
- up_read(&context->umem_rwsem);
+ ret_val = get_per_mm(umem_odp);
+ if (ret_val)
+ goto out_dma_list;
+ add_umem_to_per_mm(umem_odp);
- /*
- * Note that doing an mmput can cause a notifier for the relevant mm.
- * If the notifier is called while we hold the umem_rwsem, this will
- * cause a deadlock. Therefore, we release the reference only after we
- * released the semaphore.
- */
- mmput(mm);
return 0;
-out_mutex:
- up_read(&context->umem_rwsem);
- vfree(umem->odp_data->dma_list);
+out_dma_list:
+ vfree(umem_odp->dma_list);
out_page_list:
- vfree(umem->odp_data->page_list);
-out_odp_data:
- kfree(umem->odp_data);
-out_mm:
- mmput(mm);
+ vfree(umem_odp->page_list);
return ret_val;
}
-void ib_umem_odp_release(struct ib_umem *umem)
+void ib_umem_odp_release(struct ib_umem_odp *umem_odp)
{
- struct ib_ucontext *context = umem->context;
+ struct ib_umem *umem = &umem_odp->umem;
/*
* Ensure that no more pages are mapped in the umem.
@@ -478,61 +474,13 @@ void ib_umem_odp_release(struct ib_umem *umem)
* It is the driver's responsibility to ensure, before calling us,
* that the hardware will not attempt to access the MR any more.
*/
- ib_umem_odp_unmap_dma_pages(umem, ib_umem_start(umem),
+ ib_umem_odp_unmap_dma_pages(umem_odp, ib_umem_start(umem),
ib_umem_end(umem));
- down_write(&context->umem_rwsem);
- if (likely(ib_umem_start(umem) != ib_umem_end(umem)))
- rbt_ib_umem_remove(&umem->odp_data->interval_tree,
- &context->umem_tree);
- context->odp_mrs_count--;
- if (!umem->odp_data->mn_counters_active) {
- list_del(&umem->odp_data->no_private_counters);
- complete_all(&umem->odp_data->notifier_completion);
- }
-
- /*
- * Downgrade the lock to a read lock. This ensures that the notifiers
- * (who lock the mutex for reading) will be able to finish, and we
- * will be able to enventually obtain the mmu notifiers SRCU. Note
- * that since we are doing it atomically, no other user could register
- * and unregister while we do the check.
- */
- downgrade_write(&context->umem_rwsem);
- if (!context->odp_mrs_count) {
- struct task_struct *owning_process = NULL;
- struct mm_struct *owning_mm = NULL;
-
- owning_process = get_pid_task(context->tgid,
- PIDTYPE_PID);
- if (owning_process == NULL)
- /*
- * The process is already dead, notifier were removed
- * already.
- */
- goto out;
-
- owning_mm = get_task_mm(owning_process);
- if (owning_mm == NULL)
- /*
- * The process' mm is already dead, notifier were
- * removed already.
- */
- goto out_put_task;
- mmu_notifier_unregister(&context->mn, owning_mm);
-
- mmput(owning_mm);
-
-out_put_task:
- put_task_struct(owning_process);
- }
-out:
- up_read(&context->umem_rwsem);
-
- vfree(umem->odp_data->dma_list);
- vfree(umem->odp_data->page_list);
- kfree(umem->odp_data);
- kfree(umem);
+ remove_umem_from_per_mm(umem_odp);
+ put_per_mm(umem_odp);
+ vfree(umem_odp->dma_list);
+ vfree(umem_odp->page_list);
}
/*
@@ -544,7 +492,7 @@ out:
* @access_mask: access permissions needed for this page.
* @current_seq: sequence number for synchronization with invalidations.
* the sequence number is taken from
- * umem->odp_data->notifiers_seq.
+ * umem_odp->notifiers_seq.
*
* The function returns -EFAULT if the DMA mapping operation fails. It returns
* -EAGAIN if a concurrent invalidation prevents us from updating the page.
@@ -554,12 +502,13 @@ out:
* umem.
*/
static int ib_umem_odp_map_dma_single_page(
- struct ib_umem *umem,
+ struct ib_umem_odp *umem_odp,
int page_index,
struct page *page,
u64 access_mask,
unsigned long current_seq)
{
+ struct ib_umem *umem = &umem_odp->umem;
struct ib_device *dev = umem->context->device;
dma_addr_t dma_addr;
int stored_page = 0;
@@ -571,11 +520,11 @@ static int ib_umem_odp_map_dma_single_page(
* handle case of a racing notifier. This check also allows us to bail
* early if we have a notifier running in parallel with us.
*/
- if (ib_umem_mmu_notifier_retry(umem, current_seq)) {
+ if (ib_umem_mmu_notifier_retry(umem_odp, current_seq)) {
ret = -EAGAIN;
goto out;
}
- if (!(umem->odp_data->dma_list[page_index])) {
+ if (!(umem_odp->dma_list[page_index])) {
dma_addr = ib_dma_map_page(dev,
page,
0, BIT(umem->page_shift),
@@ -584,15 +533,15 @@ static int ib_umem_odp_map_dma_single_page(
ret = -EFAULT;
goto out;
}
- umem->odp_data->dma_list[page_index] = dma_addr | access_mask;
- umem->odp_data->page_list[page_index] = page;
+ umem_odp->dma_list[page_index] = dma_addr | access_mask;
+ umem_odp->page_list[page_index] = page;
umem->npages++;
stored_page = 1;
- } else if (umem->odp_data->page_list[page_index] == page) {
- umem->odp_data->dma_list[page_index] |= access_mask;
+ } else if (umem_odp->page_list[page_index] == page) {
+ umem_odp->dma_list[page_index] |= access_mask;
} else {
pr_err("error: got different pages in IB device and from get_user_pages. IB device page: %p, gup page: %p\n",
- umem->odp_data->page_list[page_index], page);
+ umem_odp->page_list[page_index], page);
/* Better remove the mapping now, to prevent any further
* damage. */
remove_existing_mapping = 1;
@@ -605,7 +554,7 @@ out:
if (remove_existing_mapping && umem->context->invalidate_range) {
invalidate_page_trampoline(
- umem,
+ umem_odp,
ib_umem_start(umem) + (page_index >> umem->page_shift),
ib_umem_start(umem) + ((page_index + 1) >>
umem->page_shift),
@@ -621,7 +570,7 @@ out:
*
* Pins the range of pages passed in the argument, and maps them to
* DMA addresses. The DMA addresses of the mapped pages is updated in
- * umem->odp_data->dma_list.
+ * umem_odp->dma_list.
*
* Returns the number of pages mapped in success, negative error code
* for failure.
@@ -629,7 +578,7 @@ out:
* the function from completing its task.
* An -ENOENT error code indicates that userspace process is being terminated
* and mm was already destroyed.
- * @umem: the umem to map and pin
+ * @umem_odp: the umem to map and pin
* @user_virt: the address from which we need to map.
* @bcnt: the minimal number of bytes to pin and map. The mapping might be
* bigger due to alignment, and may also be smaller in case of an error
@@ -639,13 +588,15 @@ out:
* range.
* @current_seq: the MMU notifiers sequance value for synchronization with
* invalidations. the sequance number is read from
- * umem->odp_data->notifiers_seq before calling this function
+ * umem_odp->notifiers_seq before calling this function
*/
-int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 user_virt, u64 bcnt,
- u64 access_mask, unsigned long current_seq)
+int ib_umem_odp_map_dma_pages(struct ib_umem_odp *umem_odp, u64 user_virt,
+ u64 bcnt, u64 access_mask,
+ unsigned long current_seq)
{
+ struct ib_umem *umem = &umem_odp->umem;
struct task_struct *owning_process = NULL;
- struct mm_struct *owning_mm = NULL;
+ struct mm_struct *owning_mm = umem_odp->umem.owning_mm;
struct page **local_page_list = NULL;
u64 page_mask, off;
int j, k, ret = 0, start_idx, npages = 0, page_shift;
@@ -669,15 +620,14 @@ int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 user_virt, u64 bcnt,
user_virt = user_virt & page_mask;
bcnt += off; /* Charge for the first page offset as well. */
- owning_process = get_pid_task(umem->context->tgid, PIDTYPE_PID);
- if (owning_process == NULL) {
+ /*
+ * owning_process is allowed to be NULL, this means somehow the mm is
+ * existing beyond the lifetime of the originating process.. Presumably
+ * mmget_not_zero will fail in this case.
+ */
+ owning_process = get_pid_task(umem_odp->per_mm->tgid, PIDTYPE_PID);
+ if (WARN_ON(!mmget_not_zero(umem_odp->umem.owning_mm))) {
ret = -EINVAL;
- goto out_no_task;
- }
-
- owning_mm = get_task_mm(owning_process);
- if (owning_mm == NULL) {
- ret = -ENOENT;
goto out_put_task;
}
@@ -709,7 +659,7 @@ int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 user_virt, u64 bcnt,
break;
bcnt -= min_t(size_t, npages << PAGE_SHIFT, bcnt);
- mutex_lock(&umem->odp_data->umem_mutex);
+ mutex_lock(&umem_odp->umem_mutex);
for (j = 0; j < npages; j++, user_virt += PAGE_SIZE) {
if (user_virt & ~page_mask) {
p += PAGE_SIZE;
@@ -722,7 +672,7 @@ int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 user_virt, u64 bcnt,
}
ret = ib_umem_odp_map_dma_single_page(
- umem, k, local_page_list[j],
+ umem_odp, k, local_page_list[j],
access_mask, current_seq);
if (ret < 0)
break;
@@ -730,7 +680,7 @@ int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 user_virt, u64 bcnt,
p = page_to_phys(local_page_list[j]);
k++;
}
- mutex_unlock(&umem->odp_data->umem_mutex);
+ mutex_unlock(&umem_odp->umem_mutex);
if (ret < 0) {
/* Release left over pages when handling errors. */
@@ -749,16 +699,17 @@ int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 user_virt, u64 bcnt,
mmput(owning_mm);
out_put_task:
- put_task_struct(owning_process);
-out_no_task:
+ if (owning_process)
+ put_task_struct(owning_process);
free_page((unsigned long)local_page_list);
return ret;
}
EXPORT_SYMBOL(ib_umem_odp_map_dma_pages);
-void ib_umem_odp_unmap_dma_pages(struct ib_umem *umem, u64 virt,
+void ib_umem_odp_unmap_dma_pages(struct ib_umem_odp *umem_odp, u64 virt,
u64 bound)
{
+ struct ib_umem *umem = &umem_odp->umem;
int idx;
u64 addr;
struct ib_device *dev = umem->context->device;
@@ -770,12 +721,12 @@ void ib_umem_odp_unmap_dma_pages(struct ib_umem *umem, u64 virt,
* faults from completion. We might be racing with other
* invalidations, so we must make sure we free each page only
* once. */
- mutex_lock(&umem->odp_data->umem_mutex);
+ mutex_lock(&umem_odp->umem_mutex);
for (addr = virt; addr < bound; addr += BIT(umem->page_shift)) {
idx = (addr - ib_umem_start(umem)) >> umem->page_shift;
- if (umem->odp_data->page_list[idx]) {
- struct page *page = umem->odp_data->page_list[idx];
- dma_addr_t dma = umem->odp_data->dma_list[idx];
+ if (umem_odp->page_list[idx]) {
+ struct page *page = umem_odp->page_list[idx];
+ dma_addr_t dma = umem_odp->dma_list[idx];
dma_addr_t dma_addr = dma & ODP_DMA_ADDR_MASK;
WARN_ON(!dma_addr);
@@ -798,12 +749,12 @@ void ib_umem_odp_unmap_dma_pages(struct ib_umem *umem, u64 virt,
/* on demand pinning support */
if (!umem->context->invalidate_range)
put_page(page);
- umem->odp_data->page_list[idx] = NULL;
- umem->odp_data->dma_list[idx] = 0;
+ umem_odp->page_list[idx] = NULL;
+ umem_odp->dma_list[idx] = 0;
umem->npages--;
}
}
- mutex_unlock(&umem->odp_data->umem_mutex);
+ mutex_unlock(&umem_odp->umem_mutex);
}
EXPORT_SYMBOL(ib_umem_odp_unmap_dma_pages);
@@ -830,7 +781,7 @@ int rbt_ib_umem_for_each_in_range(struct rb_root_cached *root,
return -EAGAIN;
next = rbt_ib_umem_iter_next(node, start, last - 1);
umem = container_of(node, struct ib_umem_odp, interval_tree);
- ret_val = cb(umem->umem, start, last, cookie) || ret_val;
+ ret_val = cb(umem, start, last, cookie) || ret_val;
}
return ret_val;
diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c
index c34a6852d691..f55f48f6b272 100644
--- a/drivers/infiniband/core/user_mad.c
+++ b/drivers/infiniband/core/user_mad.c
@@ -138,7 +138,7 @@ static const dev_t base_issm_dev = MKDEV(IB_UMAD_MAJOR, IB_UMAD_MINOR_BASE) +
static dev_t dynamic_umad_dev;
static dev_t dynamic_issm_dev;
-static DECLARE_BITMAP(dev_map, IB_UMAD_MAX_PORTS);
+static DEFINE_IDA(umad_ida);
static void ib_umad_add_one(struct ib_device *device);
static void ib_umad_remove_one(struct ib_device *device, void *client_data);
@@ -1132,7 +1132,7 @@ static ssize_t show_ibdev(struct device *dev, struct device_attribute *attr,
if (!port)
return -ENODEV;
- return sprintf(buf, "%s\n", port->ib_dev->name);
+ return sprintf(buf, "%s\n", dev_name(&port->ib_dev->dev));
}
static DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL);
@@ -1159,11 +1159,10 @@ static int ib_umad_init_port(struct ib_device *device, int port_num,
dev_t base_umad;
dev_t base_issm;
- devnum = find_first_zero_bit(dev_map, IB_UMAD_MAX_PORTS);
- if (devnum >= IB_UMAD_MAX_PORTS)
+ devnum = ida_alloc_max(&umad_ida, IB_UMAD_MAX_PORTS - 1, GFP_KERNEL);
+ if (devnum < 0)
return -1;
port->dev_num = devnum;
- set_bit(devnum, dev_map);
if (devnum >= IB_UMAD_NUM_FIXED_MINOR) {
base_umad = dynamic_umad_dev + devnum - IB_UMAD_NUM_FIXED_MINOR;
base_issm = dynamic_issm_dev + devnum - IB_UMAD_NUM_FIXED_MINOR;
@@ -1227,7 +1226,7 @@ err_dev:
err_cdev:
cdev_del(&port->cdev);
- clear_bit(devnum, dev_map);
+ ida_free(&umad_ida, devnum);
return -1;
}
@@ -1261,7 +1260,7 @@ static void ib_umad_kill_port(struct ib_umad_port *port)
}
mutex_unlock(&port->file_mutex);
- clear_bit(port->dev_num, dev_map);
+ ida_free(&umad_ida, port->dev_num);
}
static void ib_umad_add_one(struct ib_device *device)
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h
index 5df8e548cc14..c97935a0c7c6 100644
--- a/drivers/infiniband/core/uverbs.h
+++ b/drivers/infiniband/core/uverbs.h
@@ -100,13 +100,14 @@ struct ib_uverbs_device {
atomic_t refcount;
int num_comp_vectors;
struct completion comp;
- struct device *dev;
+ struct device dev;
+ /* First group for device attributes, NULL terminated array */
+ const struct attribute_group *groups[2];
struct ib_device __rcu *ib_dev;
int devnum;
struct cdev cdev;
struct rb_root xrcd_tree;
struct mutex xrcd_tree_mutex;
- struct kobject kobj;
struct srcu_struct disassociate_srcu;
struct mutex lists_mutex; /* protect lists */
struct list_head uverbs_file_list;
@@ -146,7 +147,6 @@ struct ib_uverbs_file {
struct ib_event_handler event_handler;
struct ib_uverbs_async_event_file *async_file;
struct list_head list;
- int is_closed;
/*
* To access the uobjects list hw_destroy_rwsem must be held for write
@@ -158,6 +158,9 @@ struct ib_uverbs_file {
spinlock_t uobjects_lock;
struct list_head uobjects;
+ struct mutex umap_lock;
+ struct list_head umaps;
+
u64 uverbs_cmd_mask;
u64 uverbs_ex_cmd_mask;
@@ -218,12 +221,6 @@ struct ib_ucq_object {
u32 async_events_reported;
};
-struct ib_uflow_resources;
-struct ib_uflow_object {
- struct ib_uobject uobject;
- struct ib_uflow_resources *resources;
-};
-
extern const struct file_operations uverbs_event_fops;
void ib_uverbs_init_event_queue(struct ib_uverbs_event_queue *ev_queue);
struct file *ib_uverbs_alloc_async_event_file(struct ib_uverbs_file *uverbs_file,
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index e012ca80f9d1..a93853770e3c 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -117,18 +117,12 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file,
/* ufile is required when some objects are released */
ucontext->ufile = file;
- rcu_read_lock();
- ucontext->tgid = get_task_pid(current->group_leader, PIDTYPE_PID);
- rcu_read_unlock();
- ucontext->closing = 0;
+ ucontext->closing = false;
ucontext->cleanup_retryable = false;
#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING
- ucontext->umem_tree = RB_ROOT_CACHED;
- init_rwsem(&ucontext->umem_rwsem);
- ucontext->odp_mrs_count = 0;
- INIT_LIST_HEAD(&ucontext->no_private_counters);
-
+ mutex_init(&ucontext->per_mm_list_lock);
+ INIT_LIST_HEAD(&ucontext->per_mm_list);
if (!(ib_dev->attrs.device_cap_flags & IB_DEVICE_ON_DEMAND_PAGING))
ucontext->invalidate_range = NULL;
@@ -172,7 +166,6 @@ err_fd:
put_unused_fd(resp.async_fd);
err_free:
- put_pid(ucontext->tgid);
ib_dev->dealloc_ucontext(ucontext);
err_alloc:
@@ -2769,16 +2762,7 @@ out_put:
return ret ? ret : in_len;
}
-struct ib_uflow_resources {
- size_t max;
- size_t num;
- size_t collection_num;
- size_t counters_num;
- struct ib_counters **counters;
- struct ib_flow_action **collection;
-};
-
-static struct ib_uflow_resources *flow_resources_alloc(size_t num_specs)
+struct ib_uflow_resources *flow_resources_alloc(size_t num_specs)
{
struct ib_uflow_resources *resources;
@@ -2808,6 +2792,7 @@ err:
return NULL;
}
+EXPORT_SYMBOL(flow_resources_alloc);
void ib_uverbs_flow_resources_free(struct ib_uflow_resources *uflow_res)
{
@@ -2826,10 +2811,11 @@ void ib_uverbs_flow_resources_free(struct ib_uflow_resources *uflow_res)
kfree(uflow_res->counters);
kfree(uflow_res);
}
+EXPORT_SYMBOL(ib_uverbs_flow_resources_free);
-static void flow_resources_add(struct ib_uflow_resources *uflow_res,
- enum ib_flow_spec_type type,
- void *ibobj)
+void flow_resources_add(struct ib_uflow_resources *uflow_res,
+ enum ib_flow_spec_type type,
+ void *ibobj)
{
WARN_ON(uflow_res->num >= uflow_res->max);
@@ -2850,6 +2836,7 @@ static void flow_resources_add(struct ib_uflow_resources *uflow_res,
uflow_res->num++;
}
+EXPORT_SYMBOL(flow_resources_add);
static int kern_spec_to_ib_spec_action(struct ib_uverbs_file *ufile,
struct ib_uverbs_flow_spec *kern_spec,
@@ -3484,7 +3471,6 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file,
struct ib_uverbs_create_flow cmd;
struct ib_uverbs_create_flow_resp resp;
struct ib_uobject *uobj;
- struct ib_uflow_object *uflow;
struct ib_flow *flow_id;
struct ib_uverbs_flow_attr *kern_flow_attr;
struct ib_flow_attr *flow_attr;
@@ -3623,13 +3609,8 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file,
err = PTR_ERR(flow_id);
goto err_free;
}
- atomic_inc(&qp->usecnt);
- flow_id->qp = qp;
- flow_id->device = qp->device;
- flow_id->uobject = uobj;
- uobj->object = flow_id;
- uflow = container_of(uobj, typeof(*uflow), uobject);
- uflow->resources = uflow_res;
+
+ ib_set_flow(uobj, flow_id, qp, qp->device, uflow_res);
memset(&resp, 0, sizeof(resp));
resp.flow_handle = uobj->id;
diff --git a/drivers/infiniband/core/uverbs_ioctl.c b/drivers/infiniband/core/uverbs_ioctl.c
index 1a6b229e3db3..b0e493e8d860 100644
--- a/drivers/infiniband/core/uverbs_ioctl.c
+++ b/drivers/infiniband/core/uverbs_ioctl.c
@@ -57,6 +57,7 @@ struct bundle_priv {
struct ib_uverbs_attr *uattrs;
DECLARE_BITMAP(uobj_finalize, UVERBS_API_ATTR_BKEY_LEN);
+ DECLARE_BITMAP(spec_finalize, UVERBS_API_ATTR_BKEY_LEN);
/*
* Must be last. bundle ends in a flex array which overlaps
@@ -143,6 +144,86 @@ static bool uverbs_is_attr_cleared(const struct ib_uverbs_attr *uattr,
0, uattr->len - len);
}
+static int uverbs_process_idrs_array(struct bundle_priv *pbundle,
+ const struct uverbs_api_attr *attr_uapi,
+ struct uverbs_objs_arr_attr *attr,
+ struct ib_uverbs_attr *uattr,
+ u32 attr_bkey)
+{
+ const struct uverbs_attr_spec *spec = &attr_uapi->spec;
+ size_t array_len;
+ u32 *idr_vals;
+ int ret = 0;
+ size_t i;
+
+ if (uattr->attr_data.reserved)
+ return -EINVAL;
+
+ if (uattr->len % sizeof(u32))
+ return -EINVAL;
+
+ array_len = uattr->len / sizeof(u32);
+ if (array_len < spec->u2.objs_arr.min_len ||
+ array_len > spec->u2.objs_arr.max_len)
+ return -EINVAL;
+
+ attr->uobjects =
+ uverbs_alloc(&pbundle->bundle,
+ array_size(array_len, sizeof(*attr->uobjects)));
+ if (IS_ERR(attr->uobjects))
+ return PTR_ERR(attr->uobjects);
+
+ /*
+ * Since idr is 4B and *uobjects is >= 4B, we can use attr->uobjects
+ * to store idrs array and avoid additional memory allocation. The
+ * idrs array is offset to the end of the uobjects array so we will be
+ * able to read idr and replace with a pointer.
+ */
+ idr_vals = (u32 *)(attr->uobjects + array_len) - array_len;
+
+ if (uattr->len > sizeof(uattr->data)) {
+ ret = copy_from_user(idr_vals, u64_to_user_ptr(uattr->data),
+ uattr->len);
+ if (ret)
+ return -EFAULT;
+ } else {
+ memcpy(idr_vals, &uattr->data, uattr->len);
+ }
+
+ for (i = 0; i != array_len; i++) {
+ attr->uobjects[i] = uverbs_get_uobject_from_file(
+ spec->u2.objs_arr.obj_type, pbundle->bundle.ufile,
+ spec->u2.objs_arr.access, idr_vals[i]);
+ if (IS_ERR(attr->uobjects[i])) {
+ ret = PTR_ERR(attr->uobjects[i]);
+ break;
+ }
+ }
+
+ attr->len = i;
+ __set_bit(attr_bkey, pbundle->spec_finalize);
+ return ret;
+}
+
+static int uverbs_free_idrs_array(const struct uverbs_api_attr *attr_uapi,
+ struct uverbs_objs_arr_attr *attr,
+ bool commit)
+{
+ const struct uverbs_attr_spec *spec = &attr_uapi->spec;
+ int current_ret;
+ int ret = 0;
+ size_t i;
+
+ for (i = 0; i != attr->len; i++) {
+ current_ret = uverbs_finalize_object(
+ attr->uobjects[i], spec->u2.objs_arr.access, commit);
+ if (!ret)
+ ret = current_ret;
+ }
+
+ return ret;
+}
+
static int uverbs_process_attr(struct bundle_priv *pbundle,
const struct uverbs_api_attr *attr_uapi,
struct ib_uverbs_attr *uattr, u32 attr_bkey)
@@ -246,6 +327,11 @@ static int uverbs_process_attr(struct bundle_priv *pbundle,
}
break;
+
+ case UVERBS_ATTR_TYPE_IDRS_ARRAY:
+ return uverbs_process_idrs_array(pbundle, attr_uapi,
+ &e->objs_arr_attr, uattr,
+ attr_bkey);
default:
return -EOPNOTSUPP;
}
@@ -300,8 +386,7 @@ static int uverbs_set_attr(struct bundle_priv *pbundle,
return -EPROTONOSUPPORT;
return 0;
}
- attr = srcu_dereference(
- *slot, &pbundle->bundle.ufile->device->disassociate_srcu);
+ attr = rcu_dereference_protected(*slot, true);
/* Reject duplicate attributes from user-space */
if (test_bit(attr_bkey, pbundle->bundle.attr_present))
@@ -384,6 +469,7 @@ static int bundle_destroy(struct bundle_priv *pbundle, bool commit)
unsigned int i;
int ret = 0;
+ /* fast path for simple uobjects */
i = -1;
while ((i = find_next_bit(pbundle->uobj_finalize, key_bitmap_len,
i + 1)) < key_bitmap_len) {
@@ -397,6 +483,30 @@ static int bundle_destroy(struct bundle_priv *pbundle, bool commit)
ret = current_ret;
}
+ i = -1;
+ while ((i = find_next_bit(pbundle->spec_finalize, key_bitmap_len,
+ i + 1)) < key_bitmap_len) {
+ struct uverbs_attr *attr = &pbundle->bundle.attrs[i];
+ const struct uverbs_api_attr *attr_uapi;
+ void __rcu **slot;
+ int current_ret;
+
+ slot = uapi_get_attr_for_method(
+ pbundle,
+ pbundle->method_key | uapi_bkey_to_key_attr(i));
+ if (WARN_ON(!slot))
+ continue;
+
+ attr_uapi = rcu_dereference_protected(*slot, true);
+
+ if (attr_uapi->spec.type == UVERBS_ATTR_TYPE_IDRS_ARRAY) {
+ current_ret = uverbs_free_idrs_array(
+ attr_uapi, &attr->objs_arr_attr, commit);
+ if (!ret)
+ ret = current_ret;
+ }
+ }
+
for (memblock = pbundle->allocated_mem; memblock;) {
struct bundle_alloc_head *tmp = memblock;
@@ -429,7 +539,7 @@ static int ib_uverbs_cmd_verbs(struct ib_uverbs_file *ufile,
uapi_key_ioctl_method(hdr->method_id));
if (unlikely(!slot))
return -EPROTONOSUPPORT;
- method_elm = srcu_dereference(*slot, &ufile->device->disassociate_srcu);
+ method_elm = rcu_dereference_protected(*slot, true);
if (!method_elm->use_stack) {
pbundle = kmalloc(method_elm->bundle_size, GFP_KERNEL);
@@ -461,6 +571,7 @@ static int ib_uverbs_cmd_verbs(struct ib_uverbs_file *ufile,
memset(pbundle->bundle.attr_present, 0,
sizeof(pbundle->bundle.attr_present));
memset(pbundle->uobj_finalize, 0, sizeof(pbundle->uobj_finalize));
+ memset(pbundle->spec_finalize, 0, sizeof(pbundle->spec_finalize));
ret = ib_uverbs_run_method(pbundle, hdr->num_attrs);
destroy_ret = bundle_destroy(pbundle, ret == 0);
@@ -611,3 +722,26 @@ int uverbs_copy_to(const struct uverbs_attr_bundle *bundle, size_t idx,
return 0;
}
EXPORT_SYMBOL(uverbs_copy_to);
+
+int _uverbs_get_const(s64 *to, const struct uverbs_attr_bundle *attrs_bundle,
+ size_t idx, s64 lower_bound, u64 upper_bound,
+ s64 *def_val)
+{
+ const struct uverbs_attr *attr;
+
+ attr = uverbs_attr_get(attrs_bundle, idx);
+ if (IS_ERR(attr)) {
+ if ((PTR_ERR(attr) != -ENOENT) || !def_val)
+ return PTR_ERR(attr);
+
+ *to = *def_val;
+ } else {
+ *to = attr->ptr_attr.data;
+ }
+
+ if (*to < lower_bound || (*to > 0 && (u64)*to > upper_bound))
+ return -EINVAL;
+
+ return 0;
+}
+EXPORT_SYMBOL(_uverbs_get_const);
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index 50152c1b1004..6d373f5515b7 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -45,6 +45,7 @@
#include <linux/cdev.h>
#include <linux/anon_inodes.h>
#include <linux/slab.h>
+#include <linux/sched/mm.h>
#include <linux/uaccess.h>
@@ -72,7 +73,7 @@ enum {
static dev_t dynamic_uverbs_dev;
static struct class *uverbs_class;
-static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES);
+static DEFINE_IDA(uverbs_ida);
static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file,
const char __user *buf, int in_len,
@@ -169,20 +170,16 @@ int uverbs_dealloc_mw(struct ib_mw *mw)
return ret;
}
-static void ib_uverbs_release_dev(struct kobject *kobj)
+static void ib_uverbs_release_dev(struct device *device)
{
struct ib_uverbs_device *dev =
- container_of(kobj, struct ib_uverbs_device, kobj);
+ container_of(device, struct ib_uverbs_device, dev);
uverbs_destroy_api(dev->uapi);
cleanup_srcu_struct(&dev->disassociate_srcu);
kfree(dev);
}
-static struct kobj_type ib_uverbs_dev_ktype = {
- .release = ib_uverbs_release_dev,
-};
-
static void ib_uverbs_release_async_event_file(struct kref *ref)
{
struct ib_uverbs_async_event_file *file =
@@ -265,7 +262,7 @@ void ib_uverbs_release_file(struct kref *ref)
if (atomic_dec_and_test(&file->device->refcount))
ib_uverbs_comp_dev(file->device);
- kobject_put(&file->device->kobj);
+ put_device(&file->device->dev);
kfree(file);
}
@@ -817,6 +814,226 @@ out:
}
/*
+ * Each time we map IO memory into user space this keeps track of the mapping.
+ * When the device is hot-unplugged we 'zap' the mmaps in user space to point
+ * to the zero page and allow the hot unplug to proceed.
+ *
+ * This is necessary for cases like PCI physical hot unplug as the actual BAR
+ * memory may vanish after this and access to it from userspace could MCE.
+ *
+ * RDMA drivers supporting disassociation must have their user space designed
+ * to cope in some way with their IO pages going to the zero page.
+ */
+struct rdma_umap_priv {
+ struct vm_area_struct *vma;
+ struct list_head list;
+};
+
+static const struct vm_operations_struct rdma_umap_ops;
+
+static void rdma_umap_priv_init(struct rdma_umap_priv *priv,
+ struct vm_area_struct *vma)
+{
+ struct ib_uverbs_file *ufile = vma->vm_file->private_data;
+
+ priv->vma = vma;
+ vma->vm_private_data = priv;
+ vma->vm_ops = &rdma_umap_ops;
+
+ mutex_lock(&ufile->umap_lock);
+ list_add(&priv->list, &ufile->umaps);
+ mutex_unlock(&ufile->umap_lock);
+}
+
+/*
+ * The VMA has been dup'd, initialize the vm_private_data with a new tracking
+ * struct
+ */
+static void rdma_umap_open(struct vm_area_struct *vma)
+{
+ struct ib_uverbs_file *ufile = vma->vm_file->private_data;
+ struct rdma_umap_priv *opriv = vma->vm_private_data;
+ struct rdma_umap_priv *priv;
+
+ if (!opriv)
+ return;
+
+ /* We are racing with disassociation */
+ if (!down_read_trylock(&ufile->hw_destroy_rwsem))
+ goto out_zap;
+ /*
+ * Disassociation already completed, the VMA should already be zapped.
+ */
+ if (!ufile->ucontext)
+ goto out_unlock;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ goto out_unlock;
+ rdma_umap_priv_init(priv, vma);
+
+ up_read(&ufile->hw_destroy_rwsem);
+ return;
+
+out_unlock:
+ up_read(&ufile->hw_destroy_rwsem);
+out_zap:
+ /*
+ * We can't allow the VMA to be created with the actual IO pages, that
+ * would break our API contract, and it can't be stopped at this
+ * point, so zap it.
+ */
+ vma->vm_private_data = NULL;
+ zap_vma_ptes(vma, vma->vm_start, vma->vm_end - vma->vm_start);
+}
+
+static void rdma_umap_close(struct vm_area_struct *vma)
+{
+ struct ib_uverbs_file *ufile = vma->vm_file->private_data;
+ struct rdma_umap_priv *priv = vma->vm_private_data;
+
+ if (!priv)
+ return;
+
+ /*
+ * The vma holds a reference on the struct file that created it, which
+ * in turn means that the ib_uverbs_file is guaranteed to exist at
+ * this point.
+ */
+ mutex_lock(&ufile->umap_lock);
+ list_del(&priv->list);
+ mutex_unlock(&ufile->umap_lock);
+ kfree(priv);
+}
+
+static const struct vm_operations_struct rdma_umap_ops = {
+ .open = rdma_umap_open,
+ .close = rdma_umap_close,
+};
+
+static struct rdma_umap_priv *rdma_user_mmap_pre(struct ib_ucontext *ucontext,
+ struct vm_area_struct *vma,
+ unsigned long size)
+{
+ struct ib_uverbs_file *ufile = ucontext->ufile;
+ struct rdma_umap_priv *priv;
+
+ if (vma->vm_end - vma->vm_start != size)
+ return ERR_PTR(-EINVAL);
+
+ /* Driver is using this wrong, must be called by ib_uverbs_mmap */
+ if (WARN_ON(!vma->vm_file ||
+ vma->vm_file->private_data != ufile))
+ return ERR_PTR(-EINVAL);
+ lockdep_assert_held(&ufile->device->disassociate_srcu);
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return ERR_PTR(-ENOMEM);
+ return priv;
+}
+
+/*
+ * Map IO memory into a process. This is to be called by drivers as part of
+ * their mmap() functions if they wish to send something like PCI-E BAR memory
+ * to userspace.
+ */
+int rdma_user_mmap_io(struct ib_ucontext *ucontext, struct vm_area_struct *vma,
+ unsigned long pfn, unsigned long size, pgprot_t prot)
+{
+ struct rdma_umap_priv *priv = rdma_user_mmap_pre(ucontext, vma, size);
+
+ if (IS_ERR(priv))
+ return PTR_ERR(priv);
+
+ vma->vm_page_prot = prot;
+ if (io_remap_pfn_range(vma, vma->vm_start, pfn, size, prot)) {
+ kfree(priv);
+ return -EAGAIN;
+ }
+
+ rdma_umap_priv_init(priv, vma);
+ return 0;
+}
+EXPORT_SYMBOL(rdma_user_mmap_io);
+
+/*
+ * The page case is here for a slightly different reason, the driver expects
+ * to be able to free the page it is sharing to user space when it destroys
+ * its ucontext, which means we need to zap the user space references.
+ *
+ * We could handle this differently by providing an API to allocate a shared
+ * page and then only freeing the shared page when the last ufile is
+ * destroyed.
+ */
+int rdma_user_mmap_page(struct ib_ucontext *ucontext,
+ struct vm_area_struct *vma, struct page *page,
+ unsigned long size)
+{
+ struct rdma_umap_priv *priv = rdma_user_mmap_pre(ucontext, vma, size);
+
+ if (IS_ERR(priv))
+ return PTR_ERR(priv);
+
+ if (remap_pfn_range(vma, vma->vm_start, page_to_pfn(page), size,
+ vma->vm_page_prot)) {
+ kfree(priv);
+ return -EAGAIN;
+ }
+
+ rdma_umap_priv_init(priv, vma);
+ return 0;
+}
+EXPORT_SYMBOL(rdma_user_mmap_page);
+
+void uverbs_user_mmap_disassociate(struct ib_uverbs_file *ufile)
+{
+ struct rdma_umap_priv *priv, *next_priv;
+
+ lockdep_assert_held(&ufile->hw_destroy_rwsem);
+
+ while (1) {
+ struct mm_struct *mm = NULL;
+
+ /* Get an arbitrary mm pointer that hasn't been cleaned yet */
+ mutex_lock(&ufile->umap_lock);
+ if (!list_empty(&ufile->umaps)) {
+ mm = list_first_entry(&ufile->umaps,
+ struct rdma_umap_priv, list)
+ ->vma->vm_mm;
+ mmget(mm);
+ }
+ mutex_unlock(&ufile->umap_lock);
+ if (!mm)
+ return;
+
+ /*
+ * The umap_lock is nested under mmap_sem since it used within
+ * the vma_ops callbacks, so we have to clean the list one mm
+ * at a time to get the lock ordering right. Typically there
+ * will only be one mm, so no big deal.
+ */
+ down_write(&mm->mmap_sem);
+ mutex_lock(&ufile->umap_lock);
+ list_for_each_entry_safe (priv, next_priv, &ufile->umaps,
+ list) {
+ struct vm_area_struct *vma = priv->vma;
+
+ if (vma->vm_mm != mm)
+ continue;
+ list_del_init(&priv->list);
+
+ zap_vma_ptes(vma, vma->vm_start,
+ vma->vm_end - vma->vm_start);
+ vma->vm_flags &= ~(VM_SHARED | VM_MAYSHARE);
+ }
+ mutex_unlock(&ufile->umap_lock);
+ up_write(&mm->mmap_sem);
+ mmput(mm);
+ }
+}
+
+/*
* ib_uverbs_open() does not need the BKL:
*
* - the ib_uverbs_device structures are properly reference counted and
@@ -839,6 +1056,7 @@ static int ib_uverbs_open(struct inode *inode, struct file *filp)
if (!atomic_inc_not_zero(&dev->refcount))
return -ENXIO;
+ get_device(&dev->dev);
srcu_key = srcu_read_lock(&dev->disassociate_srcu);
mutex_lock(&dev->lists_mutex);
ib_dev = srcu_dereference(dev->ib_dev,
@@ -876,9 +1094,10 @@ static int ib_uverbs_open(struct inode *inode, struct file *filp)
spin_lock_init(&file->uobjects_lock);
INIT_LIST_HEAD(&file->uobjects);
init_rwsem(&file->hw_destroy_rwsem);
+ mutex_init(&file->umap_lock);
+ INIT_LIST_HEAD(&file->umaps);
filp->private_data = file;
- kobject_get(&dev->kobj);
list_add_tail(&file->list, &dev->uverbs_file_list);
mutex_unlock(&dev->lists_mutex);
srcu_read_unlock(&dev->disassociate_srcu, srcu_key);
@@ -899,6 +1118,7 @@ err:
if (atomic_dec_and_test(&dev->refcount))
ib_uverbs_comp_dev(dev);
+ put_device(&dev->dev);
return ret;
}
@@ -909,10 +1129,7 @@ static int ib_uverbs_close(struct inode *inode, struct file *filp)
uverbs_destroy_ufile_hw(file, RDMA_REMOVE_CLOSE);
mutex_lock(&file->device->lists_mutex);
- if (!file->is_closed) {
- list_del(&file->list);
- file->is_closed = 1;
- }
+ list_del_init(&file->list);
mutex_unlock(&file->device->lists_mutex);
if (file->async_file)
@@ -951,37 +1168,34 @@ static struct ib_client uverbs_client = {
.remove = ib_uverbs_remove_one
};
-static ssize_t show_ibdev(struct device *device, struct device_attribute *attr,
+static ssize_t ibdev_show(struct device *device, struct device_attribute *attr,
char *buf)
{
+ struct ib_uverbs_device *dev =
+ container_of(device, struct ib_uverbs_device, dev);
int ret = -ENODEV;
int srcu_key;
- struct ib_uverbs_device *dev = dev_get_drvdata(device);
struct ib_device *ib_dev;
- if (!dev)
- return -ENODEV;
-
srcu_key = srcu_read_lock(&dev->disassociate_srcu);
ib_dev = srcu_dereference(dev->ib_dev, &dev->disassociate_srcu);
if (ib_dev)
- ret = sprintf(buf, "%s\n", ib_dev->name);
+ ret = sprintf(buf, "%s\n", dev_name(&ib_dev->dev));
srcu_read_unlock(&dev->disassociate_srcu, srcu_key);
return ret;
}
-static DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL);
+static DEVICE_ATTR_RO(ibdev);
-static ssize_t show_dev_abi_version(struct device *device,
- struct device_attribute *attr, char *buf)
+static ssize_t abi_version_show(struct device *device,
+ struct device_attribute *attr, char *buf)
{
- struct ib_uverbs_device *dev = dev_get_drvdata(device);
+ struct ib_uverbs_device *dev =
+ container_of(device, struct ib_uverbs_device, dev);
int ret = -ENODEV;
int srcu_key;
struct ib_device *ib_dev;
- if (!dev)
- return -ENODEV;
srcu_key = srcu_read_lock(&dev->disassociate_srcu);
ib_dev = srcu_dereference(dev->ib_dev, &dev->disassociate_srcu);
if (ib_dev)
@@ -990,7 +1204,17 @@ static ssize_t show_dev_abi_version(struct device *device,
return ret;
}
-static DEVICE_ATTR(abi_version, S_IRUGO, show_dev_abi_version, NULL);
+static DEVICE_ATTR_RO(abi_version);
+
+static struct attribute *ib_dev_attrs[] = {
+ &dev_attr_abi_version.attr,
+ &dev_attr_ibdev.attr,
+ NULL,
+};
+
+static const struct attribute_group dev_attr_group = {
+ .attrs = ib_dev_attrs,
+};
static CLASS_ATTR_STRING(abi_version, S_IRUGO,
__stringify(IB_USER_VERBS_ABI_VERSION));
@@ -1028,65 +1252,56 @@ static void ib_uverbs_add_one(struct ib_device *device)
return;
}
+ device_initialize(&uverbs_dev->dev);
+ uverbs_dev->dev.class = uverbs_class;
+ uverbs_dev->dev.parent = device->dev.parent;
+ 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);
init_completion(&uverbs_dev->comp);
uverbs_dev->xrcd_tree = RB_ROOT;
mutex_init(&uverbs_dev->xrcd_tree_mutex);
- kobject_init(&uverbs_dev->kobj, &ib_uverbs_dev_ktype);
mutex_init(&uverbs_dev->lists_mutex);
INIT_LIST_HEAD(&uverbs_dev->uverbs_file_list);
INIT_LIST_HEAD(&uverbs_dev->uverbs_events_file_list);
+ rcu_assign_pointer(uverbs_dev->ib_dev, device);
+ uverbs_dev->num_comp_vectors = device->num_comp_vectors;
- devnum = find_first_zero_bit(dev_map, IB_UVERBS_MAX_DEVICES);
- if (devnum >= IB_UVERBS_MAX_DEVICES)
+ devnum = ida_alloc_max(&uverbs_ida, IB_UVERBS_MAX_DEVICES - 1,
+ GFP_KERNEL);
+ if (devnum < 0)
goto err;
uverbs_dev->devnum = devnum;
- set_bit(devnum, dev_map);
if (devnum >= IB_UVERBS_NUM_FIXED_MINOR)
base = dynamic_uverbs_dev + devnum - IB_UVERBS_NUM_FIXED_MINOR;
else
base = IB_UVERBS_BASE_DEV + devnum;
- rcu_assign_pointer(uverbs_dev->ib_dev, device);
- uverbs_dev->num_comp_vectors = device->num_comp_vectors;
-
if (ib_uverbs_create_uapi(device, uverbs_dev))
goto err_uapi;
- cdev_init(&uverbs_dev->cdev, NULL);
+ uverbs_dev->dev.devt = base;
+ dev_set_name(&uverbs_dev->dev, "uverbs%d", uverbs_dev->devnum);
+
+ cdev_init(&uverbs_dev->cdev,
+ device->mmap ? &uverbs_mmap_fops : &uverbs_fops);
uverbs_dev->cdev.owner = THIS_MODULE;
- uverbs_dev->cdev.ops = device->mmap ? &uverbs_mmap_fops : &uverbs_fops;
- cdev_set_parent(&uverbs_dev->cdev, &uverbs_dev->kobj);
- kobject_set_name(&uverbs_dev->cdev.kobj, "uverbs%d", uverbs_dev->devnum);
- if (cdev_add(&uverbs_dev->cdev, base, 1))
- goto err_cdev;
-
- uverbs_dev->dev = device_create(uverbs_class, device->dev.parent,
- uverbs_dev->cdev.dev, uverbs_dev,
- "uverbs%d", uverbs_dev->devnum);
- if (IS_ERR(uverbs_dev->dev))
- goto err_cdev;
-
- if (device_create_file(uverbs_dev->dev, &dev_attr_ibdev))
- goto err_class;
- if (device_create_file(uverbs_dev->dev, &dev_attr_abi_version))
- goto err_class;
- ib_set_client_data(device, &uverbs_client, uverbs_dev);
+ ret = cdev_device_add(&uverbs_dev->cdev, &uverbs_dev->dev);
+ if (ret)
+ goto err_uapi;
+ ib_set_client_data(device, &uverbs_client, uverbs_dev);
return;
-err_class:
- device_destroy(uverbs_class, uverbs_dev->cdev.dev);
-err_cdev:
- cdev_del(&uverbs_dev->cdev);
err_uapi:
- clear_bit(devnum, dev_map);
+ ida_free(&uverbs_ida, devnum);
err:
if (atomic_dec_and_test(&uverbs_dev->refcount))
ib_uverbs_comp_dev(uverbs_dev);
wait_for_completion(&uverbs_dev->comp);
- kobject_put(&uverbs_dev->kobj);
+ put_device(&uverbs_dev->dev);
return;
}
@@ -1107,8 +1322,7 @@ static void ib_uverbs_free_hw_resources(struct ib_uverbs_device *uverbs_dev,
while (!list_empty(&uverbs_dev->uverbs_file_list)) {
file = list_first_entry(&uverbs_dev->uverbs_file_list,
struct ib_uverbs_file, list);
- file->is_closed = 1;
- list_del(&file->list);
+ list_del_init(&file->list);
kref_get(&file->ref);
/* We must release the mutex before going ahead and calling
@@ -1156,10 +1370,8 @@ static void ib_uverbs_remove_one(struct ib_device *device, void *client_data)
if (!uverbs_dev)
return;
- dev_set_drvdata(uverbs_dev->dev, NULL);
- device_destroy(uverbs_class, uverbs_dev->cdev.dev);
- cdev_del(&uverbs_dev->cdev);
- clear_bit(uverbs_dev->devnum, dev_map);
+ cdev_device_del(&uverbs_dev->cdev, &uverbs_dev->dev);
+ ida_free(&uverbs_ida, uverbs_dev->devnum);
if (device->disassociate_ucontext) {
/* We disassociate HW resources and immediately return.
@@ -1182,7 +1394,7 @@ static void ib_uverbs_remove_one(struct ib_device *device, void *client_data)
if (wait_clients)
wait_for_completion(&uverbs_dev->comp);
- kobject_put(&uverbs_dev->kobj);
+ put_device(&uverbs_dev->dev);
}
static char *uverbs_devnode(struct device *dev, umode_t *mode)
diff --git a/drivers/infiniband/core/uverbs_std_types_flow_action.c b/drivers/infiniband/core/uverbs_std_types_flow_action.c
index d8cfafe23bd9..cb9486ad5c67 100644
--- a/drivers/infiniband/core/uverbs_std_types_flow_action.c
+++ b/drivers/infiniband/core/uverbs_std_types_flow_action.c
@@ -326,11 +326,8 @@ static int UVERBS_HANDLER(UVERBS_METHOD_FLOW_ACTION_ESP_CREATE)(
if (IS_ERR(action))
return PTR_ERR(action);
- atomic_set(&action->usecnt, 0);
- action->device = ib_dev;
- action->type = IB_FLOW_ACTION_ESP;
- action->uobject = uobj;
- uobj->object = action;
+ uverbs_flow_action_fill_action(action, uobj, ib_dev,
+ IB_FLOW_ACTION_ESP);
return 0;
}
diff --git a/drivers/infiniband/core/uverbs_uapi.c b/drivers/infiniband/core/uverbs_uapi.c
index be854628a7c6..86f3fc5e04b4 100644
--- a/drivers/infiniband/core/uverbs_uapi.c
+++ b/drivers/infiniband/core/uverbs_uapi.c
@@ -73,6 +73,18 @@ static int uapi_merge_method(struct uverbs_api *uapi,
if (attr->attr.type == UVERBS_ATTR_TYPE_ENUM_IN)
method_elm->driver_method |= is_driver;
+ /*
+ * Like other uobject based things we only support a single
+ * uobject being NEW'd or DESTROY'd
+ */
+ if (attr->attr.type == UVERBS_ATTR_TYPE_IDRS_ARRAY) {
+ u8 access = attr->attr.u2.objs_arr.access;
+
+ if (WARN_ON(access == UVERBS_ACCESS_NEW ||
+ access == UVERBS_ACCESS_DESTROY))
+ return -EINVAL;
+ }
+
attr_slot =
uapi_add_elm(uapi, method_key | uapi_key_attr(attr->id),
sizeof(*attr_slot));
diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c
index 6ee03d6089eb..178899e3ce73 100644
--- a/drivers/infiniband/core/verbs.c
+++ b/drivers/infiniband/core/verbs.c
@@ -264,7 +264,7 @@ struct ib_pd *__ib_alloc_pd(struct ib_device *device, unsigned int flags,
}
pd->res.type = RDMA_RESTRACK_PD;
- pd->res.kern_name = caller;
+ rdma_restrack_set_task(&pd->res, caller);
rdma_restrack_add(&pd->res);
if (mr_access_flags) {
@@ -710,7 +710,7 @@ static int ib_resolve_unicast_gid_dmac(struct ib_device *device,
ret = rdma_addr_find_l2_eth_by_grh(&sgid_attr->gid, &grh->dgid,
ah_attr->roce.dmac,
- sgid_attr->ndev, &hop_limit);
+ sgid_attr, &hop_limit);
grh->hop_limit = hop_limit;
return ret;
@@ -1509,8 +1509,7 @@ static const struct {
};
bool ib_modify_qp_is_ok(enum ib_qp_state cur_state, enum ib_qp_state next_state,
- enum ib_qp_type type, enum ib_qp_attr_mask mask,
- enum rdma_link_layer ll)
+ enum ib_qp_type type, enum ib_qp_attr_mask mask)
{
enum ib_qp_attr_mask req_param, opt_param;
@@ -1629,14 +1628,16 @@ static int _ib_modify_qp(struct ib_qp *qp, struct ib_qp_attr *attr,
if (rdma_ib_or_roce(qp->device, port)) {
if (attr_mask & IB_QP_RQ_PSN && attr->rq_psn & ~0xffffff) {
- pr_warn("%s: %s rq_psn overflow, masking to 24 bits\n",
- __func__, qp->device->name);
+ dev_warn(&qp->device->dev,
+ "%s rq_psn overflow, masking to 24 bits\n",
+ __func__);
attr->rq_psn &= 0xffffff;
}
if (attr_mask & IB_QP_SQ_PSN && attr->sq_psn & ~0xffffff) {
- pr_warn("%s: %s sq_psn overflow, masking to 24 bits\n",
- __func__, qp->device->name);
+ dev_warn(&qp->device->dev,
+ " %s sq_psn overflow, masking to 24 bits\n",
+ __func__);
attr->sq_psn &= 0xffffff;
}
}
@@ -1888,7 +1889,7 @@ struct ib_cq *__ib_create_cq(struct ib_device *device,
cq->cq_context = cq_context;
atomic_set(&cq->usecnt, 0);
cq->res.type = RDMA_RESTRACK_CQ;
- cq->res.kern_name = caller;
+ rdma_restrack_set_task(&cq->res, caller);
rdma_restrack_add(&cq->res);
}
@@ -2621,3 +2622,49 @@ void ib_drain_qp(struct ib_qp *qp)
ib_drain_rq(qp);
}
EXPORT_SYMBOL(ib_drain_qp);
+
+struct net_device *rdma_alloc_netdev(struct ib_device *device, u8 port_num,
+ enum rdma_netdev_t type, const char *name,
+ unsigned char name_assign_type,
+ void (*setup)(struct net_device *))
+{
+ struct rdma_netdev_alloc_params params;
+ struct net_device *netdev;
+ int rc;
+
+ if (!device->rdma_netdev_get_params)
+ return ERR_PTR(-EOPNOTSUPP);
+
+ rc = device->rdma_netdev_get_params(device, port_num, type, &params);
+ if (rc)
+ return ERR_PTR(rc);
+
+ netdev = alloc_netdev_mqs(params.sizeof_priv, name, name_assign_type,
+ setup, params.txqs, params.rxqs);
+ if (!netdev)
+ return ERR_PTR(-ENOMEM);
+
+ return netdev;
+}
+EXPORT_SYMBOL(rdma_alloc_netdev);
+
+int rdma_init_netdev(struct ib_device *device, u8 port_num,
+ enum rdma_netdev_t type, const char *name,
+ unsigned char name_assign_type,
+ void (*setup)(struct net_device *),
+ struct net_device *netdev)
+{
+ struct rdma_netdev_alloc_params params;
+ int rc;
+
+ if (!device->rdma_netdev_get_params)
+ return -EOPNOTSUPP;
+
+ rc = device->rdma_netdev_get_params(device, port_num, type, &params);
+ if (rc)
+ return rc;
+
+ return params.initialize_rdma_netdev(device, port_num,
+ netdev, params.param);
+}
+EXPORT_SYMBOL(rdma_init_netdev);
diff --git a/drivers/infiniband/hw/bnxt_re/bnxt_re.h b/drivers/infiniband/hw/bnxt_re/bnxt_re.h
index 96f76896488d..31baa8939a4f 100644
--- a/drivers/infiniband/hw/bnxt_re/bnxt_re.h
+++ b/drivers/infiniband/hw/bnxt_re/bnxt_re.h
@@ -40,7 +40,6 @@
#ifndef __BNXT_RE_H__
#define __BNXT_RE_H__
#define ROCE_DRV_MODULE_NAME "bnxt_re"
-#define ROCE_DRV_MODULE_VERSION "1.0.0"
#define BNXT_RE_DESC "Broadcom NetXtreme-C/E RoCE Driver"
#define BNXT_RE_PAGE_SHIFT_4K (12)
@@ -120,6 +119,8 @@ struct bnxt_re_dev {
#define BNXT_RE_FLAG_HAVE_L2_REF 3
#define BNXT_RE_FLAG_RCFW_CHANNEL_EN 4
#define BNXT_RE_FLAG_QOS_WORK_REG 5
+#define BNXT_RE_FLAG_RESOURCES_ALLOCATED 7
+#define BNXT_RE_FLAG_RESOURCES_INITIALIZED 8
#define BNXT_RE_FLAG_ISSUE_ROCE_STATS 29
struct net_device *netdev;
unsigned int version, major, minor;
diff --git a/drivers/infiniband/hw/bnxt_re/hw_counters.c b/drivers/infiniband/hw/bnxt_re/hw_counters.c
index 77416bc61e6e..604b71875f5f 100644
--- a/drivers/infiniband/hw/bnxt_re/hw_counters.c
+++ b/drivers/infiniband/hw/bnxt_re/hw_counters.c
@@ -68,6 +68,8 @@ static const char * const bnxt_re_stat_name[] = {
[BNXT_RE_TX_PKTS] = "tx_pkts",
[BNXT_RE_TX_BYTES] = "tx_bytes",
[BNXT_RE_RECOVERABLE_ERRORS] = "recoverable_errors",
+ [BNXT_RE_RX_DROPS] = "rx_roce_drops",
+ [BNXT_RE_RX_DISCARDS] = "rx_roce_discards",
[BNXT_RE_TO_RETRANSMITS] = "to_retransmits",
[BNXT_RE_SEQ_ERR_NAKS_RCVD] = "seq_err_naks_rcvd",
[BNXT_RE_MAX_RETRY_EXCEEDED] = "max_retry_exceeded",
@@ -106,7 +108,8 @@ static const char * const bnxt_re_stat_name[] = {
[BNXT_RE_RES_CQ_LOAD_ERR] = "res_cq_load_err",
[BNXT_RE_RES_SRQ_LOAD_ERR] = "res_srq_load_err",
[BNXT_RE_RES_TX_PCI_ERR] = "res_tx_pci_err",
- [BNXT_RE_RES_RX_PCI_ERR] = "res_rx_pci_err"
+ [BNXT_RE_RES_RX_PCI_ERR] = "res_rx_pci_err",
+ [BNXT_RE_OUT_OF_SEQ_ERR] = "oos_drop_count"
};
int bnxt_re_ib_get_hw_stats(struct ib_device *ibdev,
@@ -128,6 +131,10 @@ int bnxt_re_ib_get_hw_stats(struct ib_device *ibdev,
if (bnxt_re_stats) {
stats->value[BNXT_RE_RECOVERABLE_ERRORS] =
le64_to_cpu(bnxt_re_stats->tx_bcast_pkts);
+ stats->value[BNXT_RE_RX_DROPS] =
+ le64_to_cpu(bnxt_re_stats->rx_drop_pkts);
+ stats->value[BNXT_RE_RX_DISCARDS] =
+ le64_to_cpu(bnxt_re_stats->rx_discard_pkts);
stats->value[BNXT_RE_RX_PKTS] =
le64_to_cpu(bnxt_re_stats->rx_ucast_pkts);
stats->value[BNXT_RE_RX_BYTES] =
@@ -220,6 +227,8 @@ int bnxt_re_ib_get_hw_stats(struct ib_device *ibdev,
rdev->stats.res_tx_pci_err;
stats->value[BNXT_RE_RES_RX_PCI_ERR] =
rdev->stats.res_rx_pci_err;
+ stats->value[BNXT_RE_OUT_OF_SEQ_ERR] =
+ rdev->stats.res_oos_drop_count;
}
return 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 a01a922717d5..76399f477e5c 100644
--- a/drivers/infiniband/hw/bnxt_re/hw_counters.h
+++ b/drivers/infiniband/hw/bnxt_re/hw_counters.h
@@ -51,6 +51,8 @@ enum bnxt_re_hw_stats {
BNXT_RE_TX_PKTS,
BNXT_RE_TX_BYTES,
BNXT_RE_RECOVERABLE_ERRORS,
+ BNXT_RE_RX_DROPS,
+ BNXT_RE_RX_DISCARDS,
BNXT_RE_TO_RETRANSMITS,
BNXT_RE_SEQ_ERR_NAKS_RCVD,
BNXT_RE_MAX_RETRY_EXCEEDED,
@@ -90,6 +92,7 @@ enum bnxt_re_hw_stats {
BNXT_RE_RES_SRQ_LOAD_ERR,
BNXT_RE_RES_TX_PCI_ERR,
BNXT_RE_RES_RX_PCI_ERR,
+ BNXT_RE_OUT_OF_SEQ_ERR,
BNXT_RE_NUM_COUNTERS
};
diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
index bc2b9e038439..54fdd4cf5288 100644
--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c
+++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
@@ -1598,8 +1598,7 @@ int bnxt_re_modify_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr,
curr_qp_state = __to_ib_qp_state(qp->qplib_qp.cur_qp_state);
new_qp_state = qp_attr->qp_state;
if (!ib_modify_qp_is_ok(curr_qp_state, new_qp_state,
- ib_qp->qp_type, qp_attr_mask,
- IB_LINK_LAYER_ETHERNET)) {
+ ib_qp->qp_type, qp_attr_mask)) {
dev_err(rdev_to_dev(rdev),
"Invalid attribute mask: %#x specified ",
qp_attr_mask);
@@ -2664,6 +2663,7 @@ struct ib_cq *bnxt_re_create_cq(struct ib_device *ibdev,
nq->budget++;
atomic_inc(&rdev->cq_count);
+ spin_lock_init(&cq->cq_lock);
if (context) {
struct bnxt_re_cq_resp resp;
diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c
index 85cd1a3593d6..cf2282654210 100644
--- a/drivers/infiniband/hw/bnxt_re/main.c
+++ b/drivers/infiniband/hw/bnxt_re/main.c
@@ -67,7 +67,7 @@
#include "hw_counters.h"
static char version[] =
- BNXT_RE_DESC " v" ROCE_DRV_MODULE_VERSION "\n";
+ BNXT_RE_DESC "\n";
MODULE_AUTHOR("Eddie Wai <eddie.wai@broadcom.com>");
MODULE_DESCRIPTION(BNXT_RE_DESC " Driver");
@@ -535,6 +535,34 @@ static struct bnxt_en_dev *bnxt_re_dev_probe(struct net_device *netdev)
return en_dev;
}
+static ssize_t hw_rev_show(struct device *device, struct device_attribute *attr,
+ char *buf)
+{
+ struct bnxt_re_dev *rdev = to_bnxt_re_dev(device, ibdev.dev);
+
+ return scnprintf(buf, PAGE_SIZE, "0x%x\n", rdev->en_dev->pdev->vendor);
+}
+static DEVICE_ATTR_RO(hw_rev);
+
+static ssize_t hca_type_show(struct device *device,
+ struct device_attribute *attr, char *buf)
+{
+ struct bnxt_re_dev *rdev = to_bnxt_re_dev(device, ibdev.dev);
+
+ return scnprintf(buf, PAGE_SIZE, "%s\n", rdev->ibdev.node_desc);
+}
+static DEVICE_ATTR_RO(hca_type);
+
+static struct attribute *bnxt_re_attributes[] = {
+ &dev_attr_hw_rev.attr,
+ &dev_attr_hca_type.attr,
+ NULL
+};
+
+static const struct attribute_group bnxt_re_dev_attr_group = {
+ .attrs = bnxt_re_attributes,
+};
+
static void bnxt_re_unregister_ib(struct bnxt_re_dev *rdev)
{
ib_unregister_device(&rdev->ibdev);
@@ -547,7 +575,6 @@ static int bnxt_re_register_ib(struct bnxt_re_dev *rdev)
/* ib device init */
ibdev->owner = THIS_MODULE;
ibdev->node_type = RDMA_NODE_IB_CA;
- strlcpy(ibdev->name, "bnxt_re%d", IB_DEVICE_NAME_MAX);
strlcpy(ibdev->node_desc, BNXT_RE_DESC " HCA",
strlen(BNXT_RE_DESC) + 5);
ibdev->phys_port_cnt = 1;
@@ -639,34 +666,11 @@ static int bnxt_re_register_ib(struct bnxt_re_dev *rdev)
ibdev->get_hw_stats = bnxt_re_ib_get_hw_stats;
ibdev->alloc_hw_stats = bnxt_re_ib_alloc_hw_stats;
+ rdma_set_device_sysfs_group(ibdev, &bnxt_re_dev_attr_group);
ibdev->driver_id = RDMA_DRIVER_BNXT_RE;
- return ib_register_device(ibdev, NULL);
-}
-
-static ssize_t show_rev(struct device *device, struct device_attribute *attr,
- char *buf)
-{
- struct bnxt_re_dev *rdev = to_bnxt_re_dev(device, ibdev.dev);
-
- return scnprintf(buf, PAGE_SIZE, "0x%x\n", rdev->en_dev->pdev->vendor);
-}
-
-static ssize_t show_hca(struct device *device, struct device_attribute *attr,
- char *buf)
-{
- struct bnxt_re_dev *rdev = to_bnxt_re_dev(device, ibdev.dev);
-
- return scnprintf(buf, PAGE_SIZE, "%s\n", rdev->ibdev.node_desc);
+ return ib_register_device(ibdev, "bnxt_re%d", NULL);
}
-static DEVICE_ATTR(hw_rev, 0444, show_rev, NULL);
-static DEVICE_ATTR(hca_type, 0444, show_hca, NULL);
-
-static struct device_attribute *bnxt_re_attributes[] = {
- &dev_attr_hw_rev,
- &dev_attr_hca_type
-};
-
static void bnxt_re_dev_remove(struct bnxt_re_dev *rdev)
{
dev_put(rdev->netdev);
@@ -864,10 +868,8 @@ static void bnxt_re_cleanup_res(struct bnxt_re_dev *rdev)
{
int i;
- if (rdev->nq[0].hwq.max_elements) {
- for (i = 1; i < rdev->num_msix; i++)
- bnxt_qplib_disable_nq(&rdev->nq[i - 1]);
- }
+ for (i = 1; i < rdev->num_msix; i++)
+ bnxt_qplib_disable_nq(&rdev->nq[i - 1]);
if (rdev->qplib_res.rcfw)
bnxt_qplib_cleanup_res(&rdev->qplib_res);
@@ -876,6 +878,7 @@ static void bnxt_re_cleanup_res(struct bnxt_re_dev *rdev)
static int bnxt_re_init_res(struct bnxt_re_dev *rdev)
{
int rc = 0, i;
+ int num_vec_enabled = 0;
bnxt_qplib_init_res(&rdev->qplib_res);
@@ -891,9 +894,13 @@ static int bnxt_re_init_res(struct bnxt_re_dev *rdev)
"Failed to enable NQ with rc = 0x%x", rc);
goto fail;
}
+ num_vec_enabled++;
}
return 0;
fail:
+ for (i = num_vec_enabled; i >= 0; i--)
+ bnxt_qplib_disable_nq(&rdev->nq[i]);
+
return rc;
}
@@ -925,6 +932,7 @@ static void bnxt_re_free_res(struct bnxt_re_dev *rdev)
static int bnxt_re_alloc_res(struct bnxt_re_dev *rdev)
{
int rc = 0, i;
+ int num_vec_created = 0;
/* Configure and allocate resources for qplib */
rdev->qplib_res.rcfw = &rdev->rcfw;
@@ -951,7 +959,7 @@ static int bnxt_re_alloc_res(struct bnxt_re_dev *rdev)
if (rc) {
dev_err(rdev_to_dev(rdev), "Alloc Failed NQ%d rc:%#x",
i, rc);
- goto dealloc_dpi;
+ goto free_nq;
}
rc = bnxt_re_net_ring_alloc
(rdev, rdev->nq[i].hwq.pbl[PBL_LVL_0].pg_map_arr,
@@ -964,14 +972,17 @@ static int bnxt_re_alloc_res(struct bnxt_re_dev *rdev)
dev_err(rdev_to_dev(rdev),
"Failed to allocate NQ fw id with rc = 0x%x",
rc);
+ bnxt_qplib_free_nq(&rdev->nq[i]);
goto free_nq;
}
+ num_vec_created++;
}
return 0;
free_nq:
- for (i = 0; i < rdev->num_msix - 1; i++)
+ for (i = num_vec_created; i >= 0; i--) {
+ bnxt_re_net_ring_free(rdev, rdev->nq[i].ring_id);
bnxt_qplib_free_nq(&rdev->nq[i]);
-dealloc_dpi:
+ }
bnxt_qplib_dealloc_dpi(&rdev->qplib_res,
&rdev->qplib_res.dpi_tbl,
&rdev->dpi_privileged);
@@ -989,12 +1000,17 @@ static void bnxt_re_dispatch_event(struct ib_device *ibdev, struct ib_qp *qp,
struct ib_event ib_event;
ib_event.device = ibdev;
- if (qp)
+ if (qp) {
ib_event.element.qp = qp;
- else
+ ib_event.event = event;
+ if (qp->event_handler)
+ qp->event_handler(&ib_event, qp->qp_context);
+
+ } else {
ib_event.element.port_num = port_num;
- ib_event.event = event;
- ib_dispatch_event(&ib_event);
+ ib_event.event = event;
+ ib_dispatch_event(&ib_event);
+ }
}
#define HWRM_QUEUE_PRI2COS_QCFG_INPUT_FLAGS_IVLAN 0x02
@@ -1189,20 +1205,20 @@ static int bnxt_re_setup_qos(struct bnxt_re_dev *rdev)
static void bnxt_re_ib_unreg(struct bnxt_re_dev *rdev)
{
- int i, rc;
+ int rc;
if (test_and_clear_bit(BNXT_RE_FLAG_IBDEV_REGISTERED, &rdev->flags)) {
- for (i = 0; i < ARRAY_SIZE(bnxt_re_attributes); i++)
- device_remove_file(&rdev->ibdev.dev,
- bnxt_re_attributes[i]);
/* Cleanup ib dev */
bnxt_re_unregister_ib(rdev);
}
if (test_and_clear_bit(BNXT_RE_FLAG_QOS_WORK_REG, &rdev->flags))
- cancel_delayed_work(&rdev->worker);
+ cancel_delayed_work_sync(&rdev->worker);
- bnxt_re_cleanup_res(rdev);
- bnxt_re_free_res(rdev);
+ if (test_and_clear_bit(BNXT_RE_FLAG_RESOURCES_INITIALIZED,
+ &rdev->flags))
+ bnxt_re_cleanup_res(rdev);
+ if (test_and_clear_bit(BNXT_RE_FLAG_RESOURCES_ALLOCATED, &rdev->flags))
+ bnxt_re_free_res(rdev);
if (test_and_clear_bit(BNXT_RE_FLAG_RCFW_CHANNEL_EN, &rdev->flags)) {
rc = bnxt_qplib_deinit_rcfw(&rdev->rcfw);
@@ -1241,7 +1257,7 @@ static void bnxt_re_worker(struct work_struct *work)
static int bnxt_re_ib_reg(struct bnxt_re_dev *rdev)
{
- int i, j, rc;
+ int rc;
bool locked;
@@ -1331,12 +1347,15 @@ static int bnxt_re_ib_reg(struct bnxt_re_dev *rdev)
pr_err("Failed to allocate resources: %#x\n", rc);
goto fail;
}
+ set_bit(BNXT_RE_FLAG_RESOURCES_ALLOCATED, &rdev->flags);
rc = bnxt_re_init_res(rdev);
if (rc) {
pr_err("Failed to initialize resources: %#x\n", rc);
goto fail;
}
+ set_bit(BNXT_RE_FLAG_RESOURCES_INITIALIZED, &rdev->flags);
+
if (!rdev->is_virtfn) {
rc = bnxt_re_setup_qos(rdev);
if (rc)
@@ -1358,20 +1377,6 @@ static int bnxt_re_ib_reg(struct bnxt_re_dev *rdev)
}
set_bit(BNXT_RE_FLAG_IBDEV_REGISTERED, &rdev->flags);
dev_info(rdev_to_dev(rdev), "Device registered successfully");
- for (i = 0; i < ARRAY_SIZE(bnxt_re_attributes); i++) {
- rc = device_create_file(&rdev->ibdev.dev,
- bnxt_re_attributes[i]);
- if (rc) {
- dev_err(rdev_to_dev(rdev),
- "Failed to create IB sysfs: %#x", rc);
- /* Must clean up all created device files */
- for (j = 0; j < i; j++)
- device_remove_file(&rdev->ibdev.dev,
- bnxt_re_attributes[j]);
- bnxt_re_unregister_ib(rdev);
- goto fail;
- }
- }
ib_get_eth_speed(&rdev->ibdev, 1, &rdev->active_speed,
&rdev->active_width);
set_bit(BNXT_RE_FLAG_ISSUE_ROCE_STATS, &rdev->flags);
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c
index 6ad0d46ab879..b98b054148cd 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c
+++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c
@@ -36,6 +36,8 @@
* Description: Fast Path Operators
*/
+#define dev_fmt(fmt) "QPLIB: " fmt
+
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/sched.h>
@@ -71,8 +73,7 @@ static void __bnxt_qplib_add_flush_qp(struct bnxt_qplib_qp *qp)
if (!qp->sq.flushed) {
dev_dbg(&scq->hwq.pdev->dev,
- "QPLIB: FP: Adding to SQ Flush list = %p",
- qp);
+ "FP: Adding to SQ Flush list = %p\n", qp);
bnxt_qplib_cancel_phantom_processing(qp);
list_add_tail(&qp->sq_flush, &scq->sqf_head);
qp->sq.flushed = true;
@@ -80,8 +81,7 @@ static void __bnxt_qplib_add_flush_qp(struct bnxt_qplib_qp *qp)
if (!qp->srq) {
if (!qp->rq.flushed) {
dev_dbg(&rcq->hwq.pdev->dev,
- "QPLIB: FP: Adding to RQ Flush list = %p",
- qp);
+ "FP: Adding to RQ Flush list = %p\n", qp);
list_add_tail(&qp->rq_flush, &rcq->rqf_head);
qp->rq.flushed = true;
}
@@ -207,7 +207,7 @@ static int bnxt_qplib_alloc_qp_hdr_buf(struct bnxt_qplib_res *res,
if (!qp->sq_hdr_buf) {
rc = -ENOMEM;
dev_err(&res->pdev->dev,
- "QPLIB: Failed to create sq_hdr_buf");
+ "Failed to create sq_hdr_buf\n");
goto fail;
}
}
@@ -221,7 +221,7 @@ static int bnxt_qplib_alloc_qp_hdr_buf(struct bnxt_qplib_res *res,
if (!qp->rq_hdr_buf) {
rc = -ENOMEM;
dev_err(&res->pdev->dev,
- "QPLIB: Failed to create rq_hdr_buf");
+ "Failed to create rq_hdr_buf\n");
goto fail;
}
}
@@ -277,8 +277,7 @@ static void bnxt_qplib_service_nq(unsigned long data)
num_cqne_processed++;
else
dev_warn(&nq->pdev->dev,
- "QPLIB: cqn - type 0x%x not handled",
- type);
+ "cqn - type 0x%x not handled\n", type);
spin_unlock_bh(&cq->compl_lock);
break;
}
@@ -298,7 +297,7 @@ static void bnxt_qplib_service_nq(unsigned long data)
num_srqne_processed++;
else
dev_warn(&nq->pdev->dev,
- "QPLIB: SRQ event 0x%x not handled",
+ "SRQ event 0x%x not handled\n",
nqsrqe->event);
break;
}
@@ -306,8 +305,7 @@ static void bnxt_qplib_service_nq(unsigned long data)
break;
default:
dev_warn(&nq->pdev->dev,
- "QPLIB: nqe with type = 0x%x not handled",
- type);
+ "nqe with type = 0x%x not handled\n", type);
break;
}
raw_cons++;
@@ -360,7 +358,8 @@ void bnxt_qplib_disable_nq(struct bnxt_qplib_nq *nq)
}
/* Make sure the HW is stopped! */
- bnxt_qplib_nq_stop_irq(nq, true);
+ if (nq->requested)
+ bnxt_qplib_nq_stop_irq(nq, true);
if (nq->bar_reg_iomem)
iounmap(nq->bar_reg_iomem);
@@ -396,7 +395,7 @@ int bnxt_qplib_nq_start_irq(struct bnxt_qplib_nq *nq, int nq_indx,
rc = irq_set_affinity_hint(nq->vector, &nq->mask);
if (rc) {
dev_warn(&nq->pdev->dev,
- "QPLIB: set affinity failed; vector: %d nq_idx: %d\n",
+ "set affinity failed; vector: %d nq_idx: %d\n",
nq->vector, nq_indx);
}
nq->requested = true;
@@ -443,7 +442,7 @@ int bnxt_qplib_enable_nq(struct pci_dev *pdev, struct bnxt_qplib_nq *nq,
rc = bnxt_qplib_nq_start_irq(nq, nq_idx, msix_vector, true);
if (rc) {
dev_err(&nq->pdev->dev,
- "QPLIB: Failed to request irq for nq-idx %d", nq_idx);
+ "Failed to request irq for nq-idx %d\n", nq_idx);
goto fail;
}
@@ -662,8 +661,8 @@ int bnxt_qplib_post_srq_recv(struct bnxt_qplib_srq *srq,
spin_lock(&srq_hwq->lock);
if (srq->start_idx == srq->last_idx) {
- dev_err(&srq_hwq->pdev->dev, "QPLIB: FP: SRQ (0x%x) is full!",
- srq->id);
+ dev_err(&srq_hwq->pdev->dev,
+ "FP: SRQ (0x%x) is full!\n", srq->id);
rc = -EINVAL;
spin_unlock(&srq_hwq->lock);
goto done;
@@ -1324,7 +1323,7 @@ int bnxt_qplib_query_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp)
}
}
if (i == res->sgid_tbl.max)
- dev_warn(&res->pdev->dev, "QPLIB: SGID not found??");
+ dev_warn(&res->pdev->dev, "SGID not found??\n");
qp->ah.hop_limit = sb->hop_limit;
qp->ah.traffic_class = sb->traffic_class;
@@ -1536,7 +1535,7 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp,
if (bnxt_qplib_queue_full(sq)) {
dev_err(&sq->hwq.pdev->dev,
- "QPLIB: prod = %#x cons = %#x qdepth = %#x delta = %#x",
+ "prod = %#x cons = %#x qdepth = %#x delta = %#x\n",
sq->hwq.prod, sq->hwq.cons, sq->hwq.max_elements,
sq->q_full_delta);
rc = -ENOMEM;
@@ -1561,7 +1560,7 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp,
/* Copy the inline data */
if (wqe->inline_len > BNXT_QPLIB_SWQE_MAX_INLINE_LENGTH) {
dev_warn(&sq->hwq.pdev->dev,
- "QPLIB: Inline data length > 96 detected");
+ "Inline data length > 96 detected\n");
data_len = BNXT_QPLIB_SWQE_MAX_INLINE_LENGTH;
} else {
data_len = wqe->inline_len;
@@ -1776,7 +1775,7 @@ done:
queue_work(qp->scq->nq->cqn_wq, &nq_work->work);
} else {
dev_err(&sq->hwq.pdev->dev,
- "QPLIB: FP: Failed to allocate SQ nq_work!");
+ "FP: Failed to allocate SQ nq_work!\n");
rc = -ENOMEM;
}
}
@@ -1815,13 +1814,12 @@ int bnxt_qplib_post_recv(struct bnxt_qplib_qp *qp,
if (qp->state == CMDQ_MODIFY_QP_NEW_STATE_ERR) {
sch_handler = true;
dev_dbg(&rq->hwq.pdev->dev,
- "%s Error QP. Scheduling for poll_cq\n",
- __func__);
+ "%s: Error QP. Scheduling for poll_cq\n", __func__);
goto queue_err;
}
if (bnxt_qplib_queue_full(rq)) {
dev_err(&rq->hwq.pdev->dev,
- "QPLIB: FP: QP (0x%x) RQ is full!", qp->id);
+ "FP: QP (0x%x) RQ is full!\n", qp->id);
rc = -EINVAL;
goto done;
}
@@ -1870,7 +1868,7 @@ queue_err:
queue_work(qp->rcq->nq->cqn_wq, &nq_work->work);
} else {
dev_err(&rq->hwq.pdev->dev,
- "QPLIB: FP: Failed to allocate RQ nq_work!");
+ "FP: Failed to allocate RQ nq_work!\n");
rc = -ENOMEM;
}
}
@@ -1932,7 +1930,7 @@ int bnxt_qplib_create_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq)
if (!cq->dpi) {
dev_err(&rcfw->pdev->dev,
- "QPLIB: FP: CREATE_CQ failed due to NULL DPI");
+ "FP: CREATE_CQ failed due to NULL DPI\n");
return -EINVAL;
}
req.dpi = cpu_to_le32(cq->dpi->dpi);
@@ -1969,6 +1967,7 @@ int bnxt_qplib_create_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq)
INIT_LIST_HEAD(&cq->sqf_head);
INIT_LIST_HEAD(&cq->rqf_head);
spin_lock_init(&cq->compl_lock);
+ spin_lock_init(&cq->flush_lock);
bnxt_qplib_arm_cq_enable(cq);
return 0;
@@ -2172,7 +2171,7 @@ static int do_wa9060(struct bnxt_qplib_qp *qp, struct bnxt_qplib_cq *cq,
* comes back
*/
dev_dbg(&cq->hwq.pdev->dev,
- "FP:Got Phantom CQE");
+ "FP: Got Phantom CQE\n");
sq->condition = false;
sq->single = true;
rc = 0;
@@ -2189,7 +2188,7 @@ static int do_wa9060(struct bnxt_qplib_qp *qp, struct bnxt_qplib_cq *cq,
peek_raw_cq_cons++;
}
dev_err(&cq->hwq.pdev->dev,
- "Should not have come here! cq_cons=0x%x qp=0x%x sq cons sw=0x%x hw=0x%x",
+ "Should not have come here! cq_cons=0x%x qp=0x%x sq cons sw=0x%x hw=0x%x\n",
cq_cons, qp->id, sw_sq_cons, cqe_sq_cons);
rc = -EINVAL;
}
@@ -2213,7 +2212,7 @@ static int bnxt_qplib_cq_process_req(struct bnxt_qplib_cq *cq,
le64_to_cpu(hwcqe->qp_handle));
if (!qp) {
dev_err(&cq->hwq.pdev->dev,
- "QPLIB: FP: Process Req qp is NULL");
+ "FP: Process Req qp is NULL\n");
return -EINVAL;
}
sq = &qp->sq;
@@ -2221,16 +2220,14 @@ static int bnxt_qplib_cq_process_req(struct bnxt_qplib_cq *cq,
cqe_sq_cons = HWQ_CMP(le16_to_cpu(hwcqe->sq_cons_idx), &sq->hwq);
if (cqe_sq_cons > sq->hwq.max_elements) {
dev_err(&cq->hwq.pdev->dev,
- "QPLIB: FP: CQ Process req reported ");
- dev_err(&cq->hwq.pdev->dev,
- "QPLIB: sq_cons_idx 0x%x which exceeded max 0x%x",
+ "FP: CQ Process req reported sq_cons_idx 0x%x which exceeded max 0x%x\n",
cqe_sq_cons, sq->hwq.max_elements);
return -EINVAL;
}
if (qp->sq.flushed) {
dev_dbg(&cq->hwq.pdev->dev,
- "%s: QPLIB: QP in Flush QP = %p\n", __func__, qp);
+ "%s: QP in Flush QP = %p\n", __func__, qp);
goto done;
}
/* Require to walk the sq's swq to fabricate CQEs for all previously
@@ -2262,9 +2259,7 @@ static int bnxt_qplib_cq_process_req(struct bnxt_qplib_cq *cq,
hwcqe->status != CQ_REQ_STATUS_OK) {
cqe->status = hwcqe->status;
dev_err(&cq->hwq.pdev->dev,
- "QPLIB: FP: CQ Processed Req ");
- dev_err(&cq->hwq.pdev->dev,
- "QPLIB: wr_id[%d] = 0x%llx with status 0x%x",
+ "FP: CQ Processed Req wr_id[%d] = 0x%llx with status 0x%x\n",
sw_sq_cons, cqe->wr_id, cqe->status);
cqe++;
(*budget)--;
@@ -2330,12 +2325,12 @@ static int bnxt_qplib_cq_process_res_rc(struct bnxt_qplib_cq *cq,
qp = (struct bnxt_qplib_qp *)((unsigned long)
le64_to_cpu(hwcqe->qp_handle));
if (!qp) {
- dev_err(&cq->hwq.pdev->dev, "QPLIB: process_cq RC qp is NULL");
+ dev_err(&cq->hwq.pdev->dev, "process_cq RC qp is NULL\n");
return -EINVAL;
}
if (qp->rq.flushed) {
dev_dbg(&cq->hwq.pdev->dev,
- "%s: QPLIB: QP in Flush QP = %p\n", __func__, qp);
+ "%s: QP in Flush QP = %p\n", __func__, qp);
goto done;
}
@@ -2356,9 +2351,7 @@ static int bnxt_qplib_cq_process_res_rc(struct bnxt_qplib_cq *cq,
return -EINVAL;
if (wr_id_idx >= srq->hwq.max_elements) {
dev_err(&cq->hwq.pdev->dev,
- "QPLIB: FP: CQ Process RC ");
- dev_err(&cq->hwq.pdev->dev,
- "QPLIB: wr_id idx 0x%x exceeded SRQ max 0x%x",
+ "FP: CQ Process RC wr_id idx 0x%x exceeded SRQ max 0x%x\n",
wr_id_idx, srq->hwq.max_elements);
return -EINVAL;
}
@@ -2371,9 +2364,7 @@ static int bnxt_qplib_cq_process_res_rc(struct bnxt_qplib_cq *cq,
rq = &qp->rq;
if (wr_id_idx >= rq->hwq.max_elements) {
dev_err(&cq->hwq.pdev->dev,
- "QPLIB: FP: CQ Process RC ");
- dev_err(&cq->hwq.pdev->dev,
- "QPLIB: wr_id idx 0x%x exceeded RQ max 0x%x",
+ "FP: CQ Process RC wr_id idx 0x%x exceeded RQ max 0x%x\n",
wr_id_idx, rq->hwq.max_elements);
return -EINVAL;
}
@@ -2409,12 +2400,12 @@ static int bnxt_qplib_cq_process_res_ud(struct bnxt_qplib_cq *cq,
qp = (struct bnxt_qplib_qp *)((unsigned long)
le64_to_cpu(hwcqe->qp_handle));
if (!qp) {
- dev_err(&cq->hwq.pdev->dev, "QPLIB: process_cq UD qp is NULL");
+ dev_err(&cq->hwq.pdev->dev, "process_cq UD qp is NULL\n");
return -EINVAL;
}
if (qp->rq.flushed) {
dev_dbg(&cq->hwq.pdev->dev,
- "%s: QPLIB: QP in Flush QP = %p\n", __func__, qp);
+ "%s: QP in Flush QP = %p\n", __func__, qp);
goto done;
}
cqe = *pcqe;
@@ -2439,9 +2430,7 @@ static int bnxt_qplib_cq_process_res_ud(struct bnxt_qplib_cq *cq,
if (wr_id_idx >= srq->hwq.max_elements) {
dev_err(&cq->hwq.pdev->dev,
- "QPLIB: FP: CQ Process UD ");
- dev_err(&cq->hwq.pdev->dev,
- "QPLIB: wr_id idx 0x%x exceeded SRQ max 0x%x",
+ "FP: CQ Process UD wr_id idx 0x%x exceeded SRQ max 0x%x\n",
wr_id_idx, srq->hwq.max_elements);
return -EINVAL;
}
@@ -2454,9 +2443,7 @@ static int bnxt_qplib_cq_process_res_ud(struct bnxt_qplib_cq *cq,
rq = &qp->rq;
if (wr_id_idx >= rq->hwq.max_elements) {
dev_err(&cq->hwq.pdev->dev,
- "QPLIB: FP: CQ Process UD ");
- dev_err(&cq->hwq.pdev->dev,
- "QPLIB: wr_id idx 0x%x exceeded RQ max 0x%x",
+ "FP: CQ Process UD wr_id idx 0x%x exceeded RQ max 0x%x\n",
wr_id_idx, rq->hwq.max_elements);
return -EINVAL;
}
@@ -2508,13 +2495,12 @@ static int bnxt_qplib_cq_process_res_raweth_qp1(struct bnxt_qplib_cq *cq,
qp = (struct bnxt_qplib_qp *)((unsigned long)
le64_to_cpu(hwcqe->qp_handle));
if (!qp) {
- dev_err(&cq->hwq.pdev->dev,
- "QPLIB: process_cq Raw/QP1 qp is NULL");
+ dev_err(&cq->hwq.pdev->dev, "process_cq Raw/QP1 qp is NULL\n");
return -EINVAL;
}
if (qp->rq.flushed) {
dev_dbg(&cq->hwq.pdev->dev,
- "%s: QPLIB: QP in Flush QP = %p\n", __func__, qp);
+ "%s: QP in Flush QP = %p\n", __func__, qp);
goto done;
}
cqe = *pcqe;
@@ -2543,14 +2529,12 @@ static int bnxt_qplib_cq_process_res_raweth_qp1(struct bnxt_qplib_cq *cq,
srq = qp->srq;
if (!srq) {
dev_err(&cq->hwq.pdev->dev,
- "QPLIB: FP: SRQ used but not defined??");
+ "FP: SRQ used but not defined??\n");
return -EINVAL;
}
if (wr_id_idx >= srq->hwq.max_elements) {
dev_err(&cq->hwq.pdev->dev,
- "QPLIB: FP: CQ Process Raw/QP1 ");
- dev_err(&cq->hwq.pdev->dev,
- "QPLIB: wr_id idx 0x%x exceeded SRQ max 0x%x",
+ "FP: CQ Process Raw/QP1 wr_id idx 0x%x exceeded SRQ max 0x%x\n",
wr_id_idx, srq->hwq.max_elements);
return -EINVAL;
}
@@ -2563,9 +2547,7 @@ static int bnxt_qplib_cq_process_res_raweth_qp1(struct bnxt_qplib_cq *cq,
rq = &qp->rq;
if (wr_id_idx >= rq->hwq.max_elements) {
dev_err(&cq->hwq.pdev->dev,
- "QPLIB: FP: CQ Process Raw/QP1 RQ wr_id ");
- dev_err(&cq->hwq.pdev->dev,
- "QPLIB: ix 0x%x exceeded RQ max 0x%x",
+ "FP: CQ Process Raw/QP1 RQ wr_id idx 0x%x exceeded RQ max 0x%x\n",
wr_id_idx, rq->hwq.max_elements);
return -EINVAL;
}
@@ -2600,14 +2582,14 @@ static int bnxt_qplib_cq_process_terminal(struct bnxt_qplib_cq *cq,
/* Check the Status */
if (hwcqe->status != CQ_TERMINAL_STATUS_OK)
dev_warn(&cq->hwq.pdev->dev,
- "QPLIB: FP: CQ Process Terminal Error status = 0x%x",
+ "FP: CQ Process Terminal Error status = 0x%x\n",
hwcqe->status);
qp = (struct bnxt_qplib_qp *)((unsigned long)
le64_to_cpu(hwcqe->qp_handle));
if (!qp) {
dev_err(&cq->hwq.pdev->dev,
- "QPLIB: FP: CQ Process terminal qp is NULL");
+ "FP: CQ Process terminal qp is NULL\n");
return -EINVAL;
}
@@ -2623,16 +2605,14 @@ static int bnxt_qplib_cq_process_terminal(struct bnxt_qplib_cq *cq,
if (cqe_cons > sq->hwq.max_elements) {
dev_err(&cq->hwq.pdev->dev,
- "QPLIB: FP: CQ Process terminal reported ");
- dev_err(&cq->hwq.pdev->dev,
- "QPLIB: sq_cons_idx 0x%x which exceeded max 0x%x",
+ "FP: CQ Process terminal reported sq_cons_idx 0x%x which exceeded max 0x%x\n",
cqe_cons, sq->hwq.max_elements);
goto do_rq;
}
if (qp->sq.flushed) {
dev_dbg(&cq->hwq.pdev->dev,
- "%s: QPLIB: QP in Flush QP = %p\n", __func__, qp);
+ "%s: QP in Flush QP = %p\n", __func__, qp);
goto sq_done;
}
@@ -2673,16 +2653,14 @@ do_rq:
goto done;
} else if (cqe_cons > rq->hwq.max_elements) {
dev_err(&cq->hwq.pdev->dev,
- "QPLIB: FP: CQ Processed terminal ");
- dev_err(&cq->hwq.pdev->dev,
- "QPLIB: reported rq_cons_idx 0x%x exceeds max 0x%x",
+ "FP: CQ Processed terminal reported rq_cons_idx 0x%x exceeds max 0x%x\n",
cqe_cons, rq->hwq.max_elements);
goto done;
}
if (qp->rq.flushed) {
dev_dbg(&cq->hwq.pdev->dev,
- "%s: QPLIB: QP in Flush QP = %p\n", __func__, qp);
+ "%s: QP in Flush QP = %p\n", __func__, qp);
rc = 0;
goto done;
}
@@ -2704,7 +2682,7 @@ static int bnxt_qplib_cq_process_cutoff(struct bnxt_qplib_cq *cq,
/* Check the Status */
if (hwcqe->status != CQ_CUTOFF_STATUS_OK) {
dev_err(&cq->hwq.pdev->dev,
- "QPLIB: FP: CQ Process Cutoff Error status = 0x%x",
+ "FP: CQ Process Cutoff Error status = 0x%x\n",
hwcqe->status);
return -EINVAL;
}
@@ -2724,16 +2702,12 @@ int bnxt_qplib_process_flush_list(struct bnxt_qplib_cq *cq,
spin_lock_irqsave(&cq->flush_lock, flags);
list_for_each_entry(qp, &cq->sqf_head, sq_flush) {
- dev_dbg(&cq->hwq.pdev->dev,
- "QPLIB: FP: Flushing SQ QP= %p",
- qp);
+ dev_dbg(&cq->hwq.pdev->dev, "FP: Flushing SQ QP= %p\n", qp);
__flush_sq(&qp->sq, qp, &cqe, &budget);
}
list_for_each_entry(qp, &cq->rqf_head, rq_flush) {
- dev_dbg(&cq->hwq.pdev->dev,
- "QPLIB: FP: Flushing RQ QP= %p",
- qp);
+ dev_dbg(&cq->hwq.pdev->dev, "FP: Flushing RQ QP= %p\n", qp);
__flush_rq(&qp->rq, qp, &cqe, &budget);
}
spin_unlock_irqrestore(&cq->flush_lock, flags);
@@ -2801,7 +2775,7 @@ int bnxt_qplib_poll_cq(struct bnxt_qplib_cq *cq, struct bnxt_qplib_cqe *cqe,
goto exit;
default:
dev_err(&cq->hwq.pdev->dev,
- "QPLIB: process_cq unknown type 0x%lx",
+ "process_cq unknown type 0x%lx\n",
hw_cqe->cqe_type_toggle &
CQ_BASE_CQE_TYPE_MASK);
rc = -EINVAL;
@@ -2814,7 +2788,7 @@ int bnxt_qplib_poll_cq(struct bnxt_qplib_cq *cq, struct bnxt_qplib_cqe *cqe,
* next one
*/
dev_err(&cq->hwq.pdev->dev,
- "QPLIB: process_cqe error rc = 0x%x", rc);
+ "process_cqe error rc = 0x%x\n", rc);
}
raw_cons++;
}
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c
index 2852d350ada1..be4e33e9f962 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c
+++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c
@@ -35,6 +35,9 @@
*
* Description: RDMA Controller HW interface
*/
+
+#define dev_fmt(fmt) "QPLIB: " fmt
+
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/pci.h>
@@ -96,14 +99,13 @@ static int __send_message(struct bnxt_qplib_rcfw *rcfw, struct cmdq_base *req,
opcode != CMDQ_BASE_OPCODE_INITIALIZE_FW &&
opcode != CMDQ_BASE_OPCODE_QUERY_VERSION)) {
dev_err(&rcfw->pdev->dev,
- "QPLIB: RCFW not initialized, reject opcode 0x%x",
- opcode);
+ "RCFW not initialized, reject opcode 0x%x\n", opcode);
return -EINVAL;
}
if (test_bit(FIRMWARE_INITIALIZED_FLAG, &rcfw->flags) &&
opcode == CMDQ_BASE_OPCODE_INITIALIZE_FW) {
- dev_err(&rcfw->pdev->dev, "QPLIB: RCFW already initialized!");
+ dev_err(&rcfw->pdev->dev, "RCFW already initialized!\n");
return -EINVAL;
}
@@ -115,7 +117,7 @@ static int __send_message(struct bnxt_qplib_rcfw *rcfw, struct cmdq_base *req,
*/
spin_lock_irqsave(&cmdq->lock, flags);
if (req->cmd_size >= HWQ_FREE_SLOTS(cmdq)) {
- dev_err(&rcfw->pdev->dev, "QPLIB: RCFW: CMDQ is full!");
+ dev_err(&rcfw->pdev->dev, "RCFW: CMDQ is full!\n");
spin_unlock_irqrestore(&cmdq->lock, flags);
return -EAGAIN;
}
@@ -154,7 +156,7 @@ static int __send_message(struct bnxt_qplib_rcfw *rcfw, struct cmdq_base *req,
cmdqe = &cmdq_ptr[get_cmdq_pg(sw_prod)][get_cmdq_idx(sw_prod)];
if (!cmdqe) {
dev_err(&rcfw->pdev->dev,
- "QPLIB: RCFW request failed with no cmdqe!");
+ "RCFW request failed with no cmdqe!\n");
goto done;
}
/* Copy a segment of the req cmd to the cmdq */
@@ -210,7 +212,7 @@ int bnxt_qplib_rcfw_send_message(struct bnxt_qplib_rcfw *rcfw,
if (!retry_cnt || (rc != -EAGAIN && rc != -EBUSY)) {
/* send failed */
- dev_err(&rcfw->pdev->dev, "QPLIB: cmdq[%#x]=%#x send failed",
+ dev_err(&rcfw->pdev->dev, "cmdq[%#x]=%#x send failed\n",
cookie, opcode);
return rc;
}
@@ -224,7 +226,7 @@ int bnxt_qplib_rcfw_send_message(struct bnxt_qplib_rcfw *rcfw,
rc = __wait_for_resp(rcfw, cookie);
if (rc) {
/* timed out */
- dev_err(&rcfw->pdev->dev, "QPLIB: cmdq[%#x]=%#x timedout (%d)msec",
+ dev_err(&rcfw->pdev->dev, "cmdq[%#x]=%#x timedout (%d)msec\n",
cookie, opcode, RCFW_CMD_WAIT_TIME_MS);
set_bit(FIRMWARE_TIMED_OUT, &rcfw->flags);
return rc;
@@ -232,7 +234,7 @@ int bnxt_qplib_rcfw_send_message(struct bnxt_qplib_rcfw *rcfw,
if (evnt->status) {
/* failed with status */
- dev_err(&rcfw->pdev->dev, "QPLIB: cmdq[%#x]=%#x status %#x",
+ dev_err(&rcfw->pdev->dev, "cmdq[%#x]=%#x status %#x\n",
cookie, opcode, evnt->status);
rc = -EFAULT;
}
@@ -298,9 +300,9 @@ static int bnxt_qplib_process_qp_event(struct bnxt_qplib_rcfw *rcfw,
qp_id = le32_to_cpu(err_event->xid);
qp = rcfw->qp_tbl[qp_id].qp_handle;
dev_dbg(&rcfw->pdev->dev,
- "QPLIB: Received QP error notification");
+ "Received QP error notification\n");
dev_dbg(&rcfw->pdev->dev,
- "QPLIB: qpid 0x%x, req_err=0x%x, resp_err=0x%x\n",
+ "qpid 0x%x, req_err=0x%x, resp_err=0x%x\n",
qp_id, err_event->req_err_state_reason,
err_event->res_err_state_reason);
if (!qp)
@@ -309,8 +311,17 @@ static int bnxt_qplib_process_qp_event(struct bnxt_qplib_rcfw *rcfw,
rcfw->aeq_handler(rcfw, qp_event, qp);
break;
default:
- /* Command Response */
- spin_lock_irqsave(&cmdq->lock, flags);
+ /*
+ * Command Response
+ * cmdq->lock needs to be acquired to synchronie
+ * the command send and completion reaping. This function
+ * is always called with creq->lock held. Using
+ * the nested variant of spin_lock.
+ *
+ */
+
+ spin_lock_irqsave_nested(&cmdq->lock, flags,
+ SINGLE_DEPTH_NESTING);
cookie = le16_to_cpu(qp_event->cookie);
mcookie = qp_event->cookie;
blocked = cookie & RCFW_CMD_IS_BLOCKING;
@@ -322,14 +333,16 @@ static int bnxt_qplib_process_qp_event(struct bnxt_qplib_rcfw *rcfw,
memcpy(crsqe->resp, qp_event, sizeof(*qp_event));
crsqe->resp = NULL;
} else {
- dev_err(&rcfw->pdev->dev,
- "QPLIB: CMD %s resp->cookie = %#x, evnt->cookie = %#x",
- crsqe->resp ? "mismatch" : "collision",
- crsqe->resp ? crsqe->resp->cookie : 0, mcookie);
+ if (crsqe->resp && crsqe->resp->cookie)
+ dev_err(&rcfw->pdev->dev,
+ "CMD %s cookie sent=%#x, recd=%#x\n",
+ crsqe->resp ? "mismatch" : "collision",
+ crsqe->resp ? crsqe->resp->cookie : 0,
+ mcookie);
}
if (!test_and_clear_bit(cbit, rcfw->cmdq_bitmap))
dev_warn(&rcfw->pdev->dev,
- "QPLIB: CMD bit %d was not requested", cbit);
+ "CMD bit %d was not requested\n", cbit);
cmdq->cons += crsqe->req_size;
crsqe->req_size = 0;
@@ -376,14 +389,14 @@ static void bnxt_qplib_service_creq(unsigned long data)
(rcfw, (struct creq_func_event *)creqe))
rcfw->creq_func_event_processed++;
else
- dev_warn
- (&rcfw->pdev->dev, "QPLIB:aeqe:%#x Not handled",
- type);
+ dev_warn(&rcfw->pdev->dev,
+ "aeqe:%#x Not handled\n", type);
break;
default:
- dev_warn(&rcfw->pdev->dev, "QPLIB: creqe with ");
- dev_warn(&rcfw->pdev->dev,
- "QPLIB: op_event = 0x%x not handled", type);
+ if (type != ASYNC_EVENT_CMPL_TYPE_HWRM_ASYNC_EVENT)
+ dev_warn(&rcfw->pdev->dev,
+ "creqe with event 0x%x not handled\n",
+ type);
break;
}
raw_cons++;
@@ -551,7 +564,7 @@ int bnxt_qplib_alloc_rcfw_channel(struct pci_dev *pdev,
BNXT_QPLIB_CREQE_UNITS, 0, PAGE_SIZE,
HWQ_TYPE_L2_CMPL)) {
dev_err(&rcfw->pdev->dev,
- "QPLIB: HW channel CREQ allocation failed");
+ "HW channel CREQ allocation failed\n");
goto fail;
}
rcfw->cmdq.max_elements = BNXT_QPLIB_CMDQE_MAX_CNT;
@@ -560,7 +573,7 @@ int bnxt_qplib_alloc_rcfw_channel(struct pci_dev *pdev,
BNXT_QPLIB_CMDQE_UNITS, 0, PAGE_SIZE,
HWQ_TYPE_CTX)) {
dev_err(&rcfw->pdev->dev,
- "QPLIB: HW channel CMDQ allocation failed");
+ "HW channel CMDQ allocation failed\n");
goto fail;
}
@@ -605,21 +618,18 @@ void bnxt_qplib_disable_rcfw_channel(struct bnxt_qplib_rcfw *rcfw)
bnxt_qplib_rcfw_stop_irq(rcfw, true);
- if (rcfw->cmdq_bar_reg_iomem)
- iounmap(rcfw->cmdq_bar_reg_iomem);
- rcfw->cmdq_bar_reg_iomem = NULL;
-
- if (rcfw->creq_bar_reg_iomem)
- iounmap(rcfw->creq_bar_reg_iomem);
- rcfw->creq_bar_reg_iomem = NULL;
+ iounmap(rcfw->cmdq_bar_reg_iomem);
+ iounmap(rcfw->creq_bar_reg_iomem);
indx = find_first_bit(rcfw->cmdq_bitmap, rcfw->bmap_size);
if (indx != rcfw->bmap_size)
dev_err(&rcfw->pdev->dev,
- "QPLIB: disabling RCFW with pending cmd-bit %lx", indx);
+ "disabling RCFW with pending cmd-bit %lx\n", indx);
kfree(rcfw->cmdq_bitmap);
rcfw->bmap_size = 0;
+ rcfw->cmdq_bar_reg_iomem = NULL;
+ rcfw->creq_bar_reg_iomem = NULL;
rcfw->aeq_handler = NULL;
rcfw->vector = 0;
}
@@ -681,8 +691,7 @@ int bnxt_qplib_enable_rcfw_channel(struct pci_dev *pdev,
RCFW_COMM_BASE_OFFSET,
RCFW_COMM_SIZE);
if (!rcfw->cmdq_bar_reg_iomem) {
- dev_err(&rcfw->pdev->dev,
- "QPLIB: CMDQ BAR region %d mapping failed",
+ dev_err(&rcfw->pdev->dev, "CMDQ BAR region %d mapping failed\n",
rcfw->cmdq_bar_reg);
return -ENOMEM;
}
@@ -697,14 +706,15 @@ int bnxt_qplib_enable_rcfw_channel(struct pci_dev *pdev,
res_base = pci_resource_start(pdev, rcfw->creq_bar_reg);
if (!res_base)
dev_err(&rcfw->pdev->dev,
- "QPLIB: CREQ BAR region %d resc start is 0!",
+ "CREQ BAR region %d resc start is 0!\n",
rcfw->creq_bar_reg);
rcfw->creq_bar_reg_iomem = ioremap_nocache(res_base + cp_bar_reg_off,
4);
if (!rcfw->creq_bar_reg_iomem) {
- dev_err(&rcfw->pdev->dev,
- "QPLIB: CREQ BAR region %d mapping failed",
+ dev_err(&rcfw->pdev->dev, "CREQ BAR region %d mapping failed\n",
rcfw->creq_bar_reg);
+ iounmap(rcfw->cmdq_bar_reg_iomem);
+ rcfw->cmdq_bar_reg_iomem = NULL;
return -ENOMEM;
}
rcfw->creq_qp_event_processed = 0;
@@ -717,7 +727,7 @@ int bnxt_qplib_enable_rcfw_channel(struct pci_dev *pdev,
rc = bnxt_qplib_rcfw_start_irq(rcfw, msix_vector, true);
if (rc) {
dev_err(&rcfw->pdev->dev,
- "QPLIB: Failed to request IRQ for CREQ rc = 0x%x", rc);
+ "Failed to request IRQ for CREQ rc = 0x%x\n", rc);
bnxt_qplib_disable_rcfw_channel(rcfw);
return rc;
}
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h
index 46416dfe8830..9a8687dc0a79 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h
+++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h
@@ -154,6 +154,8 @@ struct bnxt_qplib_qp_node {
void *qp_handle; /* ptr to qplib_qp */
};
+#define BNXT_QPLIB_OOS_COUNT_MASK 0xFFFFFFFF
+
/* RCFW Communication Channels */
struct bnxt_qplib_rcfw {
struct pci_dev *pdev;
@@ -190,6 +192,8 @@ struct bnxt_qplib_rcfw {
struct bnxt_qplib_crsq *crsqe_tbl;
int qp_tbl_size;
struct bnxt_qplib_qp_node *qp_tbl;
+ u64 oos_prev;
+ u32 init_oos_stats;
};
void bnxt_qplib_free_rcfw_channel(struct bnxt_qplib_rcfw *rcfw);
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_res.c b/drivers/infiniband/hw/bnxt_re/qplib_res.c
index 539a5d44e6db..59eeac55626f 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_res.c
+++ b/drivers/infiniband/hw/bnxt_re/qplib_res.c
@@ -36,6 +36,8 @@
* Description: QPLib resource manager
*/
+#define dev_fmt(fmt) "QPLIB: " fmt
+
#include <linux/spinlock.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
@@ -68,8 +70,7 @@ static void __free_pbl(struct pci_dev *pdev, struct bnxt_qplib_pbl *pbl,
pbl->pg_map_arr[i]);
else
dev_warn(&pdev->dev,
- "QPLIB: PBL free pg_arr[%d] empty?!",
- i);
+ "PBL free pg_arr[%d] empty?!\n", i);
pbl->pg_arr[i] = NULL;
}
}
@@ -537,7 +538,7 @@ static void bnxt_qplib_free_pkey_tbl(struct bnxt_qplib_res *res,
struct bnxt_qplib_pkey_tbl *pkey_tbl)
{
if (!pkey_tbl->tbl)
- dev_dbg(&res->pdev->dev, "QPLIB: PKEY tbl not present");
+ dev_dbg(&res->pdev->dev, "PKEY tbl not present\n");
else
kfree(pkey_tbl->tbl);
@@ -578,7 +579,7 @@ int bnxt_qplib_dealloc_pd(struct bnxt_qplib_res *res,
struct bnxt_qplib_pd *pd)
{
if (test_and_set_bit(pd->id, pdt->tbl)) {
- dev_warn(&res->pdev->dev, "Freeing an unused PD? pdn = %d",
+ dev_warn(&res->pdev->dev, "Freeing an unused PD? pdn = %d\n",
pd->id);
return -EINVAL;
}
@@ -639,11 +640,11 @@ int bnxt_qplib_dealloc_dpi(struct bnxt_qplib_res *res,
struct bnxt_qplib_dpi *dpi)
{
if (dpi->dpi >= dpit->max) {
- dev_warn(&res->pdev->dev, "Invalid DPI? dpi = %d", dpi->dpi);
+ dev_warn(&res->pdev->dev, "Invalid DPI? dpi = %d\n", dpi->dpi);
return -EINVAL;
}
if (test_and_set_bit(dpi->dpi, dpit->tbl)) {
- dev_warn(&res->pdev->dev, "Freeing an unused DPI? dpi = %d",
+ dev_warn(&res->pdev->dev, "Freeing an unused DPI? dpi = %d\n",
dpi->dpi);
return -EINVAL;
}
@@ -673,22 +674,21 @@ static int bnxt_qplib_alloc_dpi_tbl(struct bnxt_qplib_res *res,
u32 dbr_len, bytes;
if (dpit->dbr_bar_reg_iomem) {
- dev_err(&res->pdev->dev,
- "QPLIB: DBR BAR region %d already mapped", dbr_bar_reg);
+ dev_err(&res->pdev->dev, "DBR BAR region %d already mapped\n",
+ dbr_bar_reg);
return -EALREADY;
}
bar_reg_base = pci_resource_start(res->pdev, dbr_bar_reg);
if (!bar_reg_base) {
- dev_err(&res->pdev->dev,
- "QPLIB: BAR region %d resc start failed", dbr_bar_reg);
+ dev_err(&res->pdev->dev, "BAR region %d resc start failed\n",
+ dbr_bar_reg);
return -ENOMEM;
}
dbr_len = pci_resource_len(res->pdev, dbr_bar_reg) - dbr_offset;
if (!dbr_len || ((dbr_len & (PAGE_SIZE - 1)) != 0)) {
- dev_err(&res->pdev->dev, "QPLIB: Invalid DBR length %d",
- dbr_len);
+ dev_err(&res->pdev->dev, "Invalid DBR length %d\n", dbr_len);
return -ENOMEM;
}
@@ -696,8 +696,7 @@ static int bnxt_qplib_alloc_dpi_tbl(struct bnxt_qplib_res *res,
dbr_len);
if (!dpit->dbr_bar_reg_iomem) {
dev_err(&res->pdev->dev,
- "QPLIB: FP: DBR BAR region %d mapping failed",
- dbr_bar_reg);
+ "FP: DBR BAR region %d mapping failed\n", dbr_bar_reg);
return -ENOMEM;
}
@@ -767,7 +766,7 @@ static int bnxt_qplib_alloc_stats_ctx(struct pci_dev *pdev,
stats->dma = dma_alloc_coherent(&pdev->dev, stats->size,
&stats->dma_map, GFP_KERNEL);
if (!stats->dma) {
- dev_err(&pdev->dev, "QPLIB: Stats DMA allocation failed");
+ dev_err(&pdev->dev, "Stats DMA allocation failed\n");
return -ENOMEM;
}
return 0;
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_sp.c b/drivers/infiniband/hw/bnxt_re/qplib_sp.c
index 4097f3fa25c5..5216b5f844cc 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_sp.c
+++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.c
@@ -36,6 +36,8 @@
* Description: Slow Path Operators
*/
+#define dev_fmt(fmt) "QPLIB: " fmt
+
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/sched.h>
@@ -89,7 +91,7 @@ int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw,
sbuf = bnxt_qplib_rcfw_alloc_sbuf(rcfw, sizeof(*sb));
if (!sbuf) {
dev_err(&rcfw->pdev->dev,
- "QPLIB: SP: QUERY_FUNC alloc side buffer failed");
+ "SP: QUERY_FUNC alloc side buffer failed\n");
return -ENOMEM;
}
@@ -135,8 +137,16 @@ int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw,
attr->max_srq = le16_to_cpu(sb->max_srq);
attr->max_srq_wqes = le32_to_cpu(sb->max_srq_wr) - 1;
attr->max_srq_sges = sb->max_srq_sge;
- /* Bono only reports 1 PKEY for now, but it can support > 1 */
attr->max_pkey = le32_to_cpu(sb->max_pkeys);
+ /*
+ * Some versions of FW reports more than 0xFFFF.
+ * Restrict it for now to 0xFFFF to avoid
+ * reporting trucated value
+ */
+ if (attr->max_pkey > 0xFFFF) {
+ /* ib_port_attr::pkey_tbl_len is u16 */
+ attr->max_pkey = 0xFFFF;
+ }
attr->max_inline_data = le32_to_cpu(sb->max_inline_data);
attr->l2_db_size = (sb->l2_db_space_size + 1) *
@@ -186,8 +196,7 @@ int bnxt_qplib_set_func_resources(struct bnxt_qplib_res *res,
(void *)&resp,
NULL, 0);
if (rc) {
- dev_err(&res->pdev->dev,
- "QPLIB: Failed to set function resources");
+ dev_err(&res->pdev->dev, "Failed to set function resources\n");
}
return rc;
}
@@ -199,7 +208,7 @@ int bnxt_qplib_get_sgid(struct bnxt_qplib_res *res,
{
if (index >= sgid_tbl->max) {
dev_err(&res->pdev->dev,
- "QPLIB: Index %d exceeded SGID table max (%d)",
+ "Index %d exceeded SGID table max (%d)\n",
index, sgid_tbl->max);
return -EINVAL;
}
@@ -217,13 +226,12 @@ int bnxt_qplib_del_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl,
int index;
if (!sgid_tbl) {
- dev_err(&res->pdev->dev, "QPLIB: SGID table not allocated");
+ dev_err(&res->pdev->dev, "SGID table not allocated\n");
return -EINVAL;
}
/* Do we need a sgid_lock here? */
if (!sgid_tbl->active) {
- dev_err(&res->pdev->dev,
- "QPLIB: SGID table has no active entries");
+ dev_err(&res->pdev->dev, "SGID table has no active entries\n");
return -ENOMEM;
}
for (index = 0; index < sgid_tbl->max; index++) {
@@ -231,7 +239,7 @@ int bnxt_qplib_del_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl,
break;
}
if (index == sgid_tbl->max) {
- dev_warn(&res->pdev->dev, "GID not found in the SGID table");
+ dev_warn(&res->pdev->dev, "GID not found in the SGID table\n");
return 0;
}
/* Remove GID from the SGID table */
@@ -244,7 +252,7 @@ int bnxt_qplib_del_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl,
RCFW_CMD_PREP(req, DELETE_GID, cmd_flags);
if (sgid_tbl->hw_id[index] == 0xFFFF) {
dev_err(&res->pdev->dev,
- "QPLIB: GID entry contains an invalid HW id");
+ "GID entry contains an invalid HW id\n");
return -EINVAL;
}
req.gid_index = cpu_to_le16(sgid_tbl->hw_id[index]);
@@ -258,7 +266,7 @@ int bnxt_qplib_del_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl,
sgid_tbl->vlan[index] = 0;
sgid_tbl->active--;
dev_dbg(&res->pdev->dev,
- "QPLIB: SGID deleted hw_id[0x%x] = 0x%x active = 0x%x",
+ "SGID deleted hw_id[0x%x] = 0x%x active = 0x%x\n",
index, sgid_tbl->hw_id[index], sgid_tbl->active);
sgid_tbl->hw_id[index] = (u16)-1;
@@ -277,20 +285,19 @@ int bnxt_qplib_add_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl,
int i, free_idx;
if (!sgid_tbl) {
- dev_err(&res->pdev->dev, "QPLIB: SGID table not allocated");
+ dev_err(&res->pdev->dev, "SGID table not allocated\n");
return -EINVAL;
}
/* Do we need a sgid_lock here? */
if (sgid_tbl->active == sgid_tbl->max) {
- dev_err(&res->pdev->dev, "QPLIB: SGID table is full");
+ dev_err(&res->pdev->dev, "SGID table is full\n");
return -ENOMEM;
}
free_idx = sgid_tbl->max;
for (i = 0; i < sgid_tbl->max; i++) {
if (!memcmp(&sgid_tbl->tbl[i], gid, sizeof(*gid))) {
dev_dbg(&res->pdev->dev,
- "QPLIB: SGID entry already exist in entry %d!",
- i);
+ "SGID entry already exist in entry %d!\n", i);
*index = i;
return -EALREADY;
} else if (!memcmp(&sgid_tbl->tbl[i], &bnxt_qplib_gid_zero,
@@ -301,7 +308,7 @@ int bnxt_qplib_add_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl,
}
if (free_idx == sgid_tbl->max) {
dev_err(&res->pdev->dev,
- "QPLIB: SGID table is FULL but count is not MAX??");
+ "SGID table is FULL but count is not MAX??\n");
return -ENOMEM;
}
if (update) {
@@ -348,7 +355,7 @@ int bnxt_qplib_add_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl,
sgid_tbl->vlan[free_idx] = 1;
dev_dbg(&res->pdev->dev,
- "QPLIB: SGID added hw_id[0x%x] = 0x%x active = 0x%x",
+ "SGID added hw_id[0x%x] = 0x%x active = 0x%x\n",
free_idx, sgid_tbl->hw_id[free_idx], sgid_tbl->active);
*index = free_idx;
@@ -404,7 +411,7 @@ int bnxt_qplib_get_pkey(struct bnxt_qplib_res *res,
}
if (index >= pkey_tbl->max) {
dev_err(&res->pdev->dev,
- "QPLIB: Index %d exceeded PKEY table max (%d)",
+ "Index %d exceeded PKEY table max (%d)\n",
index, pkey_tbl->max);
return -EINVAL;
}
@@ -419,14 +426,13 @@ int bnxt_qplib_del_pkey(struct bnxt_qplib_res *res,
int i, rc = 0;
if (!pkey_tbl) {
- dev_err(&res->pdev->dev, "QPLIB: PKEY table not allocated");
+ dev_err(&res->pdev->dev, "PKEY table not allocated\n");
return -EINVAL;
}
/* Do we need a pkey_lock here? */
if (!pkey_tbl->active) {
- dev_err(&res->pdev->dev,
- "QPLIB: PKEY table has no active entries");
+ dev_err(&res->pdev->dev, "PKEY table has no active entries\n");
return -ENOMEM;
}
for (i = 0; i < pkey_tbl->max; i++) {
@@ -435,8 +441,7 @@ int bnxt_qplib_del_pkey(struct bnxt_qplib_res *res,
}
if (i == pkey_tbl->max) {
dev_err(&res->pdev->dev,
- "QPLIB: PKEY 0x%04x not found in the pkey table",
- *pkey);
+ "PKEY 0x%04x not found in the pkey table\n", *pkey);
return -ENOMEM;
}
memset(&pkey_tbl->tbl[i], 0, sizeof(*pkey));
@@ -453,13 +458,13 @@ int bnxt_qplib_add_pkey(struct bnxt_qplib_res *res,
int i, free_idx, rc = 0;
if (!pkey_tbl) {
- dev_err(&res->pdev->dev, "QPLIB: PKEY table not allocated");
+ dev_err(&res->pdev->dev, "PKEY table not allocated\n");
return -EINVAL;
}
/* Do we need a pkey_lock here? */
if (pkey_tbl->active == pkey_tbl->max) {
- dev_err(&res->pdev->dev, "QPLIB: PKEY table is full");
+ dev_err(&res->pdev->dev, "PKEY table is full\n");
return -ENOMEM;
}
free_idx = pkey_tbl->max;
@@ -471,7 +476,7 @@ int bnxt_qplib_add_pkey(struct bnxt_qplib_res *res,
}
if (free_idx == pkey_tbl->max) {
dev_err(&res->pdev->dev,
- "QPLIB: PKEY table is FULL but count is not MAX??");
+ "PKEY table is FULL but count is not MAX??\n");
return -ENOMEM;
}
/* Add PKEY to the pkey_tbl */
@@ -555,8 +560,7 @@ int bnxt_qplib_free_mrw(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mrw)
int rc;
if (mrw->lkey == 0xFFFFFFFF) {
- dev_info(&res->pdev->dev,
- "QPLIB: SP: Free a reserved lkey MRW");
+ dev_info(&res->pdev->dev, "SP: Free a reserved lkey MRW\n");
return 0;
}
@@ -666,9 +670,8 @@ int bnxt_qplib_reg_mr(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mr,
pages++;
if (pages > MAX_PBL_LVL_1_PGS) {
- dev_err(&res->pdev->dev, "QPLIB: SP: Reg MR pages ");
dev_err(&res->pdev->dev,
- "requested (0x%x) exceeded max (0x%x)",
+ "SP: Reg MR pages requested (0x%x) exceeded max (0x%x)\n",
pages, MAX_PBL_LVL_1_PGS);
return -ENOMEM;
}
@@ -684,7 +687,7 @@ int bnxt_qplib_reg_mr(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mr,
HWQ_TYPE_CTX);
if (rc) {
dev_err(&res->pdev->dev,
- "SP: Reg MR memory allocation failed");
+ "SP: Reg MR memory allocation failed\n");
return -ENOMEM;
}
/* Write to the hwq */
@@ -795,7 +798,7 @@ int bnxt_qplib_get_roce_stats(struct bnxt_qplib_rcfw *rcfw,
sbuf = bnxt_qplib_rcfw_alloc_sbuf(rcfw, sizeof(*sb));
if (!sbuf) {
dev_err(&rcfw->pdev->dev,
- "QPLIB: SP: QUERY_ROCE_STATS alloc side buffer failed");
+ "SP: QUERY_ROCE_STATS alloc side buffer failed\n");
return -ENOMEM;
}
@@ -845,6 +848,16 @@ int bnxt_qplib_get_roce_stats(struct bnxt_qplib_rcfw *rcfw,
stats->res_srq_load_err = le64_to_cpu(sb->res_srq_load_err);
stats->res_tx_pci_err = le64_to_cpu(sb->res_tx_pci_err);
stats->res_rx_pci_err = le64_to_cpu(sb->res_rx_pci_err);
+ if (!rcfw->init_oos_stats) {
+ rcfw->oos_prev = le64_to_cpu(sb->res_oos_drop_count);
+ rcfw->init_oos_stats = 1;
+ } else {
+ stats->res_oos_drop_count +=
+ (le64_to_cpu(sb->res_oos_drop_count) -
+ rcfw->oos_prev) & BNXT_QPLIB_OOS_COUNT_MASK;
+ rcfw->oos_prev = le64_to_cpu(sb->res_oos_drop_count);
+ }
+
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 9d3e8b994945..8079d7f5a008 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_sp.h
+++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.h
@@ -205,6 +205,16 @@ struct bnxt_qplib_roce_stats {
/* res_tx_pci_err is 64 b */
u64 res_rx_pci_err;
/* res_rx_pci_err is 64 b */
+ u64 res_oos_drop_count;
+ /* res_oos_drop_count */
+ u64 active_qp_count_p0;
+ /* port 0 active qps */
+ u64 active_qp_count_p1;
+ /* port 1 active qps */
+ u64 active_qp_count_p2;
+ /* port 2 active qps */
+ u64 active_qp_count_p3;
+ /* port 3 active qps */
};
int bnxt_qplib_get_sgid(struct bnxt_qplib_res *res,
diff --git a/drivers/infiniband/hw/bnxt_re/roce_hsi.h b/drivers/infiniband/hw/bnxt_re/roce_hsi.h
index 3e5a4f760d0e..8a9ead419ac2 100644
--- a/drivers/infiniband/hw/bnxt_re/roce_hsi.h
+++ b/drivers/infiniband/hw/bnxt_re/roce_hsi.h
@@ -2929,6 +2929,11 @@ struct creq_query_roce_stats_resp_sb {
__le64 res_srq_load_err;
__le64 res_tx_pci_err;
__le64 res_rx_pci_err;
+ __le64 res_oos_drop_count;
+ __le64 active_qp_count_p0;
+ __le64 active_qp_count_p1;
+ __le64 active_qp_count_p2;
+ __le64 active_qp_count_p3;
};
/* QP error notification event (16 bytes) */
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c
index 1b9ff21aa1d5..ebbec02cebe0 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_provider.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c
@@ -1127,17 +1127,18 @@ static int iwch_query_port(struct ib_device *ibdev,
return 0;
}
-static ssize_t show_rev(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t hw_rev_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct iwch_dev *iwch_dev = container_of(dev, struct iwch_dev,
ibdev.dev);
pr_debug("%s dev 0x%p\n", __func__, dev);
return sprintf(buf, "%d\n", iwch_dev->rdev.t3cdev_p->type);
}
+static DEVICE_ATTR_RO(hw_rev);
-static ssize_t show_hca(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t hca_type_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct iwch_dev *iwch_dev = container_of(dev, struct iwch_dev,
ibdev.dev);
@@ -1148,9 +1149,10 @@ static ssize_t show_hca(struct device *dev, struct device_attribute *attr,
lldev->ethtool_ops->get_drvinfo(lldev, &info);
return sprintf(buf, "%s\n", info.driver);
}
+static DEVICE_ATTR_RO(hca_type);
-static ssize_t show_board(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t board_id_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct iwch_dev *iwch_dev = container_of(dev, struct iwch_dev,
ibdev.dev);
@@ -1158,6 +1160,7 @@ static ssize_t show_board(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "%x.%x\n", iwch_dev->rdev.rnic_info.pdev->vendor,
iwch_dev->rdev.rnic_info.pdev->device);
}
+static DEVICE_ATTR_RO(board_id);
enum counters {
IPINRECEIVES,
@@ -1274,14 +1277,15 @@ static int iwch_get_mib(struct ib_device *ibdev, struct rdma_hw_stats *stats,
return stats->num_counters;
}
-static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL);
-static DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL);
-static DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL);
+static struct attribute *iwch_class_attributes[] = {
+ &dev_attr_hw_rev.attr,
+ &dev_attr_hca_type.attr,
+ &dev_attr_board_id.attr,
+ NULL
+};
-static struct device_attribute *iwch_class_attributes[] = {
- &dev_attr_hw_rev,
- &dev_attr_hca_type,
- &dev_attr_board_id,
+static const struct attribute_group iwch_attr_group = {
+ .attrs = iwch_class_attributes,
};
static int iwch_port_immutable(struct ib_device *ibdev, u8 port_num,
@@ -1316,10 +1320,8 @@ static void get_dev_fw_ver_str(struct ib_device *ibdev, char *str)
int iwch_register_device(struct iwch_dev *dev)
{
int ret;
- int i;
pr_debug("%s iwch_dev %p\n", __func__, dev);
- strlcpy(dev->ibdev.name, "cxgb3_%d", IB_DEVICE_NAME_MAX);
memset(&dev->ibdev.node_guid, 0, sizeof(dev->ibdev.node_guid));
memcpy(&dev->ibdev.node_guid, dev->rdev.t3cdev_p->lldev->dev_addr, 6);
dev->ibdev.owner = THIS_MODULE;
@@ -1402,33 +1404,16 @@ int iwch_register_device(struct iwch_dev *dev)
sizeof(dev->ibdev.iwcm->ifname));
dev->ibdev.driver_id = RDMA_DRIVER_CXGB3;
- ret = ib_register_device(&dev->ibdev, NULL);
+ rdma_set_device_sysfs_group(&dev->ibdev, &iwch_attr_group);
+ ret = ib_register_device(&dev->ibdev, "cxgb3_%d", NULL);
if (ret)
- goto bail1;
-
- for (i = 0; i < ARRAY_SIZE(iwch_class_attributes); ++i) {
- ret = device_create_file(&dev->ibdev.dev,
- iwch_class_attributes[i]);
- if (ret) {
- goto bail2;
- }
- }
- return 0;
-bail2:
- ib_unregister_device(&dev->ibdev);
-bail1:
- kfree(dev->ibdev.iwcm);
+ kfree(dev->ibdev.iwcm);
return ret;
}
void iwch_unregister_device(struct iwch_dev *dev)
{
- int i;
-
pr_debug("%s iwch_dev %p\n", __func__, dev);
- for (i = 0; i < ARRAY_SIZE(iwch_class_attributes); ++i)
- device_remove_file(&dev->ibdev.dev,
- iwch_class_attributes[i]);
ib_unregister_device(&dev->ibdev);
kfree(dev->ibdev.iwcm);
return;
diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c
index 0f83cbec33f3..615413bd3e8d 100644
--- a/drivers/infiniband/hw/cxgb4/cm.c
+++ b/drivers/infiniband/hw/cxgb4/cm.c
@@ -403,8 +403,7 @@ void _c4iw_free_ep(struct kref *kref)
ep->com.local_addr.ss_family);
dst_release(ep->dst);
cxgb4_l2t_release(ep->l2t);
- if (ep->mpa_skb)
- kfree_skb(ep->mpa_skb);
+ kfree_skb(ep->mpa_skb);
}
if (!skb_queue_empty(&ep->com.ep_skb_list))
skb_queue_purge(&ep->com.ep_skb_list);
diff --git a/drivers/infiniband/hw/cxgb4/cq.c b/drivers/infiniband/hw/cxgb4/cq.c
index 6d3042794094..1fd8798d91a7 100644
--- a/drivers/infiniband/hw/cxgb4/cq.c
+++ b/drivers/infiniband/hw/cxgb4/cq.c
@@ -161,7 +161,7 @@ static int create_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,
cq->gts = rdev->lldi.gts_reg;
cq->rdev = rdev;
- cq->bar2_va = c4iw_bar2_addrs(rdev, cq->cqid, T4_BAR2_QTYPE_INGRESS,
+ cq->bar2_va = c4iw_bar2_addrs(rdev, cq->cqid, CXGB4_BAR2_QTYPE_INGRESS,
&cq->bar2_qid,
user ? &cq->bar2_pa : NULL);
if (user && !cq->bar2_pa) {
diff --git a/drivers/infiniband/hw/cxgb4/provider.c b/drivers/infiniband/hw/cxgb4/provider.c
index 4eda6872e617..cbb3c0ddd990 100644
--- a/drivers/infiniband/hw/cxgb4/provider.c
+++ b/drivers/infiniband/hw/cxgb4/provider.c
@@ -373,8 +373,8 @@ static int c4iw_query_port(struct ib_device *ibdev, u8 port,
return 0;
}
-static ssize_t show_rev(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t hw_rev_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct c4iw_dev *c4iw_dev = container_of(dev, struct c4iw_dev,
ibdev.dev);
@@ -382,9 +382,10 @@ static ssize_t show_rev(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "%d\n",
CHELSIO_CHIP_RELEASE(c4iw_dev->rdev.lldi.adapter_type));
}
+static DEVICE_ATTR_RO(hw_rev);
-static ssize_t show_hca(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t hca_type_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct c4iw_dev *c4iw_dev = container_of(dev, struct c4iw_dev,
ibdev.dev);
@@ -395,9 +396,10 @@ static ssize_t show_hca(struct device *dev, struct device_attribute *attr,
lldev->ethtool_ops->get_drvinfo(lldev, &info);
return sprintf(buf, "%s\n", info.driver);
}
+static DEVICE_ATTR_RO(hca_type);
-static ssize_t show_board(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t board_id_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct c4iw_dev *c4iw_dev = container_of(dev, struct c4iw_dev,
ibdev.dev);
@@ -405,6 +407,7 @@ static ssize_t show_board(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "%x.%x\n", c4iw_dev->rdev.lldi.pdev->vendor,
c4iw_dev->rdev.lldi.pdev->device);
}
+static DEVICE_ATTR_RO(board_id);
enum counters {
IP4INSEGS,
@@ -461,14 +464,15 @@ static int c4iw_get_mib(struct ib_device *ibdev,
return stats->num_counters;
}
-static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL);
-static DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL);
-static DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL);
+static struct attribute *c4iw_class_attributes[] = {
+ &dev_attr_hw_rev.attr,
+ &dev_attr_hca_type.attr,
+ &dev_attr_board_id.attr,
+ NULL
+};
-static struct device_attribute *c4iw_class_attributes[] = {
- &dev_attr_hw_rev,
- &dev_attr_hca_type,
- &dev_attr_board_id,
+static const struct attribute_group c4iw_attr_group = {
+ .attrs = c4iw_class_attributes,
};
static int c4iw_port_immutable(struct ib_device *ibdev, u8 port_num,
@@ -530,12 +534,10 @@ static int fill_res_entry(struct sk_buff *msg, struct rdma_restrack_entry *res)
void c4iw_register_device(struct work_struct *work)
{
int ret;
- int i;
struct uld_ctx *ctx = container_of(work, struct uld_ctx, reg_work);
struct c4iw_dev *dev = ctx->dev;
pr_debug("c4iw_dev %p\n", dev);
- strlcpy(dev->ibdev.name, "cxgb4_%d", IB_DEVICE_NAME_MAX);
memset(&dev->ibdev.node_guid, 0, sizeof(dev->ibdev.node_guid));
memcpy(&dev->ibdev.node_guid, dev->rdev.lldi.ports[0]->dev_addr, 6);
dev->ibdev.owner = THIS_MODULE;
@@ -626,20 +628,13 @@ void c4iw_register_device(struct work_struct *work)
memcpy(dev->ibdev.iwcm->ifname, dev->rdev.lldi.ports[0]->name,
sizeof(dev->ibdev.iwcm->ifname));
+ rdma_set_device_sysfs_group(&dev->ibdev, &c4iw_attr_group);
dev->ibdev.driver_id = RDMA_DRIVER_CXGB4;
- ret = ib_register_device(&dev->ibdev, NULL);
+ ret = ib_register_device(&dev->ibdev, "cxgb4_%d", NULL);
if (ret)
goto err_kfree_iwcm;
-
- for (i = 0; i < ARRAY_SIZE(c4iw_class_attributes); ++i) {
- ret = device_create_file(&dev->ibdev.dev,
- c4iw_class_attributes[i]);
- if (ret)
- goto err_unregister_device;
- }
return;
-err_unregister_device:
- ib_unregister_device(&dev->ibdev);
+
err_kfree_iwcm:
kfree(dev->ibdev.iwcm);
err_dealloc_ctx:
@@ -651,12 +646,7 @@ err_dealloc_ctx:
void c4iw_unregister_device(struct c4iw_dev *dev)
{
- int i;
-
pr_debug("c4iw_dev %p\n", dev);
- for (i = 0; i < ARRAY_SIZE(c4iw_class_attributes); ++i)
- device_remove_file(&dev->ibdev.dev,
- c4iw_class_attributes[i]);
ib_unregister_device(&dev->ibdev);
kfree(dev->ibdev.iwcm);
return;
diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c
index 347fe18b1a41..13478f3b7057 100644
--- a/drivers/infiniband/hw/cxgb4/qp.c
+++ b/drivers/infiniband/hw/cxgb4/qp.c
@@ -99,7 +99,7 @@ static void dealloc_oc_sq(struct c4iw_rdev *rdev, struct t4_sq *sq)
static void dealloc_host_sq(struct c4iw_rdev *rdev, struct t4_sq *sq)
{
dma_free_coherent(&(rdev->lldi.pdev->dev), sq->memsize, sq->queue,
- pci_unmap_addr(sq, mapping));
+ dma_unmap_addr(sq, mapping));
}
static void dealloc_sq(struct c4iw_rdev *rdev, struct t4_sq *sq)
@@ -132,7 +132,7 @@ static int alloc_host_sq(struct c4iw_rdev *rdev, struct t4_sq *sq)
if (!sq->queue)
return -ENOMEM;
sq->phys_addr = virt_to_phys(sq->queue);
- pci_unmap_addr_set(sq, mapping, sq->dma_addr);
+ dma_unmap_addr_set(sq, mapping, sq->dma_addr);
return 0;
}
@@ -279,12 +279,13 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
wq->db = rdev->lldi.db_reg;
- wq->sq.bar2_va = c4iw_bar2_addrs(rdev, wq->sq.qid, T4_BAR2_QTYPE_EGRESS,
+ wq->sq.bar2_va = c4iw_bar2_addrs(rdev, wq->sq.qid,
+ CXGB4_BAR2_QTYPE_EGRESS,
&wq->sq.bar2_qid,
user ? &wq->sq.bar2_pa : NULL);
if (need_rq)
wq->rq.bar2_va = c4iw_bar2_addrs(rdev, wq->rq.qid,
- T4_BAR2_QTYPE_EGRESS,
+ CXGB4_BAR2_QTYPE_EGRESS,
&wq->rq.bar2_qid,
user ? &wq->rq.bar2_pa : NULL);
@@ -2521,7 +2522,7 @@ static void free_srq_queue(struct c4iw_srq *srq, struct c4iw_dev_ucontext *uctx,
dma_free_coherent(&rdev->lldi.pdev->dev,
wq->memsize, wq->queue,
- pci_unmap_addr(wq, mapping));
+ dma_unmap_addr(wq, mapping));
c4iw_rqtpool_free(rdev, wq->rqt_hwaddr, wq->rqt_size);
kfree(wq->sw_rq);
c4iw_put_qpid(rdev, wq->qid, uctx);
@@ -2570,9 +2571,9 @@ static int alloc_srq_queue(struct c4iw_srq *srq, struct c4iw_dev_ucontext *uctx,
goto err_free_rqtpool;
memset(wq->queue, 0, wq->memsize);
- pci_unmap_addr_set(wq, mapping, wq->dma_addr);
+ dma_unmap_addr_set(wq, mapping, wq->dma_addr);
- wq->bar2_va = c4iw_bar2_addrs(rdev, wq->qid, T4_BAR2_QTYPE_EGRESS,
+ wq->bar2_va = c4iw_bar2_addrs(rdev, wq->qid, CXGB4_BAR2_QTYPE_EGRESS,
&wq->bar2_qid,
user ? &wq->bar2_pa : NULL);
@@ -2649,7 +2650,7 @@ static int alloc_srq_queue(struct c4iw_srq *srq, struct c4iw_dev_ucontext *uctx,
err_free_queue:
dma_free_coherent(&rdev->lldi.pdev->dev,
wq->memsize, wq->queue,
- pci_unmap_addr(wq, mapping));
+ dma_unmap_addr(wq, mapping));
err_free_rqtpool:
c4iw_rqtpool_free(rdev, wq->rqt_hwaddr, wq->rqt_size);
err_free_pending_wrs:
@@ -2813,8 +2814,7 @@ err_free_queue:
free_srq_queue(srq, ucontext ? &ucontext->uctx : &rhp->rdev.uctx,
srq->wr_waitp);
err_free_skb:
- if (srq->destroy_skb)
- kfree_skb(srq->destroy_skb);
+ kfree_skb(srq->destroy_skb);
err_free_srq_idx:
c4iw_free_srq_idx(&rhp->rdev, srq->idx);
err_free_wr_wait:
diff --git a/drivers/infiniband/hw/cxgb4/t4.h b/drivers/infiniband/hw/cxgb4/t4.h
index e42021fd6fd6..fff6d48d262f 100644
--- a/drivers/infiniband/hw/cxgb4/t4.h
+++ b/drivers/infiniband/hw/cxgb4/t4.h
@@ -397,7 +397,7 @@ struct t4_srq_pending_wr {
struct t4_srq {
union t4_recv_wr *queue;
dma_addr_t dma_addr;
- DECLARE_PCI_UNMAP_ADDR(mapping);
+ DEFINE_DMA_UNMAP_ADDR(mapping);
struct t4_swrqe *sw_rq;
void __iomem *bar2_va;
u64 bar2_pa;
diff --git a/drivers/infiniband/hw/hfi1/Makefile b/drivers/infiniband/hw/hfi1/Makefile
index f451ba912f47..ff790390c91a 100644
--- a/drivers/infiniband/hw/hfi1/Makefile
+++ b/drivers/infiniband/hw/hfi1/Makefile
@@ -8,12 +8,42 @@
#
obj-$(CONFIG_INFINIBAND_HFI1) += hfi1.o
-hfi1-y := affinity.o chip.o device.o driver.o efivar.o \
- eprom.o exp_rcv.o file_ops.o firmware.o \
- init.o intr.o mad.o mmu_rb.o pcie.o pio.o pio_copy.o platform.o \
- qp.o qsfp.o rc.o ruc.o sdma.o sysfs.o trace.o \
- uc.o ud.o user_exp_rcv.o user_pages.o user_sdma.o verbs.o \
- verbs_txreq.o vnic_main.o vnic_sdma.o
+hfi1-y := \
+ affinity.o \
+ chip.o \
+ device.o \
+ driver.o \
+ efivar.o \
+ eprom.o \
+ exp_rcv.o \
+ file_ops.o \
+ firmware.o \
+ init.o \
+ intr.o \
+ iowait.o \
+ mad.o \
+ mmu_rb.o \
+ msix.o \
+ pcie.o \
+ pio.o \
+ pio_copy.o \
+ platform.o \
+ qp.o \
+ qsfp.o \
+ rc.o \
+ ruc.o \
+ sdma.o \
+ sysfs.o \
+ trace.o \
+ uc.o \
+ ud.o \
+ user_exp_rcv.o \
+ user_pages.o \
+ user_sdma.o \
+ verbs.o \
+ verbs_txreq.o \
+ vnic_main.o \
+ vnic_sdma.o
ifdef CONFIG_DEBUG_FS
hfi1-y += debugfs.o
diff --git a/drivers/infiniband/hw/hfi1/affinity.c b/drivers/infiniband/hw/hfi1/affinity.c
index bedd5fba33b0..2baf38cc1e23 100644
--- a/drivers/infiniband/hw/hfi1/affinity.c
+++ b/drivers/infiniband/hw/hfi1/affinity.c
@@ -817,10 +817,10 @@ static void hfi1_update_sdma_affinity(struct hfi1_msix_entry *msix, int cpu)
set = &entry->def_intr;
cpumask_set_cpu(cpu, &set->mask);
cpumask_set_cpu(cpu, &set->used);
- for (i = 0; i < dd->num_msix_entries; i++) {
+ for (i = 0; i < dd->msix_info.max_requested; i++) {
struct hfi1_msix_entry *other_msix;
- other_msix = &dd->msix_entries[i];
+ other_msix = &dd->msix_info.msix_entries[i];
if (other_msix->type != IRQ_SDMA || other_msix == msix)
continue;
diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c
index e1668bcc2d13..9b20479dc710 100644
--- a/drivers/infiniband/hw/hfi1/chip.c
+++ b/drivers/infiniband/hw/hfi1/chip.c
@@ -67,8 +67,6 @@
#include "debugfs.h"
#include "fault.h"
-#define NUM_IB_PORTS 1
-
uint kdeth_qp;
module_param_named(kdeth_qp, kdeth_qp, uint, S_IRUGO);
MODULE_PARM_DESC(kdeth_qp, "Set the KDETH queue pair prefix");
@@ -1100,9 +1098,9 @@ struct err_reg_info {
const char *desc;
};
-#define NUM_MISC_ERRS (IS_GENERAL_ERR_END - IS_GENERAL_ERR_START)
-#define NUM_DC_ERRS (IS_DC_END - IS_DC_START)
-#define NUM_VARIOUS (IS_VARIOUS_END - IS_VARIOUS_START)
+#define NUM_MISC_ERRS (IS_GENERAL_ERR_END + 1 - IS_GENERAL_ERR_START)
+#define NUM_DC_ERRS (IS_DC_END + 1 - IS_DC_START)
+#define NUM_VARIOUS (IS_VARIOUS_END + 1 - IS_VARIOUS_START)
/*
* Helpers for building HFI and DC error interrupt table entries. Different
@@ -8181,7 +8179,7 @@ static void is_rcv_avail_int(struct hfi1_devdata *dd, unsigned int source)
/**
* is_rcv_urgent_int() - User receive context urgent IRQ handler
* @dd: valid dd
- * @source: logical IRQ source (ofse from IS_RCVURGENT_START)
+ * @source: logical IRQ source (offset from IS_RCVURGENT_START)
*
* RX block receive urgent interrupt. Source is < 160.
*
@@ -8231,7 +8229,7 @@ static const struct is_table is_table[] = {
is_sdma_eng_err_name, is_sdma_eng_err_int },
{ IS_SENDCTXT_ERR_START, IS_SENDCTXT_ERR_END,
is_sendctxt_err_name, is_sendctxt_err_int },
-{ IS_SDMA_START, IS_SDMA_END,
+{ IS_SDMA_START, IS_SDMA_IDLE_END,
is_sdma_eng_name, is_sdma_eng_int },
{ IS_VARIOUS_START, IS_VARIOUS_END,
is_various_name, is_various_int },
@@ -8257,7 +8255,7 @@ static void is_interrupt(struct hfi1_devdata *dd, unsigned int source)
/* avoids a double compare by walking the table in-order */
for (entry = &is_table[0]; entry->is_name; entry++) {
- if (source < entry->end) {
+ if (source <= entry->end) {
trace_hfi1_interrupt(dd, entry, source);
entry->is_int(dd, source - entry->start);
return;
@@ -8276,7 +8274,7 @@ static void is_interrupt(struct hfi1_devdata *dd, unsigned int source)
* context DATA IRQs are threaded and are not supported by this handler.
*
*/
-static irqreturn_t general_interrupt(int irq, void *data)
+irqreturn_t general_interrupt(int irq, void *data)
{
struct hfi1_devdata *dd = data;
u64 regs[CCE_NUM_INT_CSRS];
@@ -8309,7 +8307,7 @@ static irqreturn_t general_interrupt(int irq, void *data)
return handled;
}
-static irqreturn_t sdma_interrupt(int irq, void *data)
+irqreturn_t sdma_interrupt(int irq, void *data)
{
struct sdma_engine *sde = data;
struct hfi1_devdata *dd = sde->dd;
@@ -8401,7 +8399,7 @@ static inline int check_packet_present(struct hfi1_ctxtdata *rcd)
* invoked) is finished. The intent is to avoid extra interrupts while we
* are processing packets anyway.
*/
-static irqreturn_t receive_context_interrupt(int irq, void *data)
+irqreturn_t receive_context_interrupt(int irq, void *data)
{
struct hfi1_ctxtdata *rcd = data;
struct hfi1_devdata *dd = rcd->dd;
@@ -8441,7 +8439,7 @@ static irqreturn_t receive_context_interrupt(int irq, void *data)
* Receive packet thread handler. This expects to be invoked with the
* receive interrupt still blocked.
*/
-static irqreturn_t receive_context_thread(int irq, void *data)
+irqreturn_t receive_context_thread(int irq, void *data)
{
struct hfi1_ctxtdata *rcd = data;
int present;
@@ -9651,30 +9649,10 @@ void qsfp_event(struct work_struct *work)
}
}
-static void init_qsfp_int(struct hfi1_devdata *dd)
+void init_qsfp_int(struct hfi1_devdata *dd)
{
struct hfi1_pportdata *ppd = dd->pport;
- u64 qsfp_mask, cce_int_mask;
- const int qsfp1_int_smask = QSFP1_INT % 64;
- const int qsfp2_int_smask = QSFP2_INT % 64;
-
- /*
- * disable QSFP1 interrupts for HFI1, QSFP2 interrupts for HFI0
- * Qsfp1Int and Qsfp2Int are adjacent bits in the same CSR,
- * therefore just one of QSFP1_INT/QSFP2_INT can be used to find
- * the index of the appropriate CSR in the CCEIntMask CSR array
- */
- cce_int_mask = read_csr(dd, CCE_INT_MASK +
- (8 * (QSFP1_INT / 64)));
- if (dd->hfi1_id) {
- cce_int_mask &= ~((u64)1 << qsfp1_int_smask);
- write_csr(dd, CCE_INT_MASK + (8 * (QSFP1_INT / 64)),
- cce_int_mask);
- } else {
- cce_int_mask &= ~((u64)1 << qsfp2_int_smask);
- write_csr(dd, CCE_INT_MASK + (8 * (QSFP2_INT / 64)),
- cce_int_mask);
- }
+ u64 qsfp_mask;
qsfp_mask = (u64)(QSFP_HFI0_INT_N | QSFP_HFI0_MODPRST_N);
/* Clear current status to avoid spurious interrupts */
@@ -9691,6 +9669,12 @@ static void init_qsfp_int(struct hfi1_devdata *dd)
write_csr(dd,
dd->hfi1_id ? ASIC_QSFP2_INVERT : ASIC_QSFP1_INVERT,
qsfp_mask);
+
+ /* Enable the appropriate QSFP IRQ source */
+ if (!dd->hfi1_id)
+ set_intr_bits(dd, QSFP1_INT, QSFP1_INT, true);
+ else
+ set_intr_bits(dd, QSFP2_INT, QSFP2_INT, true);
}
/*
@@ -10577,12 +10561,29 @@ void set_link_down_reason(struct hfi1_pportdata *ppd, u8 lcl_reason,
}
}
-/*
- * Verify if BCT for data VLs is non-zero.
+/**
+ * data_vls_operational() - Verify if data VL BCT credits and MTU
+ * are both set.
+ * @ppd: pointer to hfi1_pportdata structure
+ *
+ * Return: true - Ok, false -otherwise.
*/
static inline bool data_vls_operational(struct hfi1_pportdata *ppd)
{
- return !!ppd->actual_vls_operational;
+ int i;
+ u64 reg;
+
+ if (!ppd->actual_vls_operational)
+ return false;
+
+ for (i = 0; i < ppd->vls_supported; i++) {
+ reg = read_csr(ppd->dd, SEND_CM_CREDIT_VL + (8 * i));
+ if ((reg && !ppd->dd->vld[i].mtu) ||
+ (!reg && ppd->dd->vld[i].mtu))
+ return false;
+ }
+
+ return true;
}
/*
@@ -10695,7 +10696,8 @@ int set_link_state(struct hfi1_pportdata *ppd, u32 state)
if (!data_vls_operational(ppd)) {
dd_dev_err(dd,
- "%s: data VLs not operational\n", __func__);
+ "%s: Invalid data VL credits or mtu\n",
+ __func__);
ret = -EINVAL;
break;
}
@@ -11932,10 +11934,16 @@ void hfi1_rcvctrl(struct hfi1_devdata *dd, unsigned int op,
rcvctrl &= ~RCV_CTXT_CTRL_ENABLE_SMASK;
}
- if (op & HFI1_RCVCTRL_INTRAVAIL_ENB)
+ if (op & HFI1_RCVCTRL_INTRAVAIL_ENB) {
+ set_intr_bits(dd, IS_RCVAVAIL_START + rcd->ctxt,
+ IS_RCVAVAIL_START + rcd->ctxt, true);
rcvctrl |= RCV_CTXT_CTRL_INTR_AVAIL_SMASK;
- if (op & HFI1_RCVCTRL_INTRAVAIL_DIS)
+ }
+ if (op & HFI1_RCVCTRL_INTRAVAIL_DIS) {
+ set_intr_bits(dd, IS_RCVAVAIL_START + rcd->ctxt,
+ IS_RCVAVAIL_START + rcd->ctxt, false);
rcvctrl &= ~RCV_CTXT_CTRL_INTR_AVAIL_SMASK;
+ }
if ((op & HFI1_RCVCTRL_TAILUPD_ENB) && rcd->rcvhdrtail_kvaddr)
rcvctrl |= RCV_CTXT_CTRL_TAIL_UPD_SMASK;
if (op & HFI1_RCVCTRL_TAILUPD_DIS) {
@@ -11965,6 +11973,13 @@ void hfi1_rcvctrl(struct hfi1_devdata *dd, unsigned int op,
rcvctrl |= RCV_CTXT_CTRL_DONT_DROP_EGR_FULL_SMASK;
if (op & HFI1_RCVCTRL_NO_EGR_DROP_DIS)
rcvctrl &= ~RCV_CTXT_CTRL_DONT_DROP_EGR_FULL_SMASK;
+ if (op & HFI1_RCVCTRL_URGENT_ENB)
+ set_intr_bits(dd, IS_RCVURGENT_START + rcd->ctxt,
+ IS_RCVURGENT_START + rcd->ctxt, true);
+ if (op & HFI1_RCVCTRL_URGENT_DIS)
+ set_intr_bits(dd, IS_RCVURGENT_START + rcd->ctxt,
+ IS_RCVURGENT_START + rcd->ctxt, false);
+
hfi1_cdbg(RCVCTRL, "ctxt %d rcvctrl 0x%llx\n", ctxt, rcvctrl);
write_kctxt_csr(dd, ctxt, RCV_CTXT_CTRL, rcvctrl);
@@ -12963,63 +12978,71 @@ int hfi1_tempsense_rd(struct hfi1_devdata *dd, struct hfi1_temp *temp)
return ret;
}
+/* ========================================================================= */
+
/**
- * get_int_mask - get 64 bit int mask
- * @dd - the devdata
- * @i - the csr (relative to CCE_INT_MASK)
+ * read_mod_write() - Calculate the IRQ register index and set/clear the bits
+ * @dd: valid devdata
+ * @src: IRQ source to determine register index from
+ * @bits: the bits to set or clear
+ * @set: true == set the bits, false == clear the bits
*
- * Returns the mask with the urgent interrupt mask
- * bit clear for kernel receive contexts.
*/
-static u64 get_int_mask(struct hfi1_devdata *dd, u32 i)
+static void read_mod_write(struct hfi1_devdata *dd, u16 src, u64 bits,
+ bool set)
{
- u64 mask = U64_MAX; /* default to no change */
-
- if (i >= (IS_RCVURGENT_START / 64) && i < (IS_RCVURGENT_END / 64)) {
- int j = (i - (IS_RCVURGENT_START / 64)) * 64;
- int k = !j ? IS_RCVURGENT_START % 64 : 0;
+ u64 reg;
+ u16 idx = src / BITS_PER_REGISTER;
- if (j)
- j -= IS_RCVURGENT_START % 64;
- /* j = 0..dd->first_dyn_alloc_ctxt - 1,k = 0..63 */
- for (; j < dd->first_dyn_alloc_ctxt && k < 64; j++, k++)
- /* convert to bit in mask and clear */
- mask &= ~BIT_ULL(k);
- }
- return mask;
+ spin_lock(&dd->irq_src_lock);
+ reg = read_csr(dd, CCE_INT_MASK + (8 * idx));
+ if (set)
+ reg |= bits;
+ else
+ reg &= ~bits;
+ write_csr(dd, CCE_INT_MASK + (8 * idx), reg);
+ spin_unlock(&dd->irq_src_lock);
}
-/* ========================================================================= */
-
-/*
- * Enable/disable chip from delivering interrupts.
+/**
+ * set_intr_bits() - Enable/disable a range (one or more) IRQ sources
+ * @dd: valid devdata
+ * @first: first IRQ source to set/clear
+ * @last: last IRQ source (inclusive) to set/clear
+ * @set: true == set the bits, false == clear the bits
+ *
+ * If first == last, set the exact source.
*/
-void set_intr_state(struct hfi1_devdata *dd, u32 enable)
+int set_intr_bits(struct hfi1_devdata *dd, u16 first, u16 last, bool set)
{
- int i;
+ u64 bits = 0;
+ u64 bit;
+ u16 src;
- /*
- * In HFI, the mask needs to be 1 to allow interrupts.
- */
- if (enable) {
- /* enable all interrupts but urgent on kernel contexts */
- for (i = 0; i < CCE_NUM_INT_CSRS; i++) {
- u64 mask = get_int_mask(dd, i);
+ if (first > NUM_INTERRUPT_SOURCES || last > NUM_INTERRUPT_SOURCES)
+ return -EINVAL;
- write_csr(dd, CCE_INT_MASK + (8 * i), mask);
- }
+ if (last < first)
+ return -ERANGE;
- init_qsfp_int(dd);
- } else {
- for (i = 0; i < CCE_NUM_INT_CSRS; i++)
- write_csr(dd, CCE_INT_MASK + (8 * i), 0ull);
+ for (src = first; src <= last; src++) {
+ bit = src % BITS_PER_REGISTER;
+ /* wrapped to next register? */
+ if (!bit && bits) {
+ read_mod_write(dd, src - 1, bits, set);
+ bits = 0;
+ }
+ bits |= BIT_ULL(bit);
}
+ read_mod_write(dd, last, bits, set);
+
+ return 0;
}
/*
* Clear all interrupt sources on the chip.
*/
-static void clear_all_interrupts(struct hfi1_devdata *dd)
+void clear_all_interrupts(struct hfi1_devdata *dd)
{
int i;
@@ -13043,38 +13066,11 @@ static void clear_all_interrupts(struct hfi1_devdata *dd)
write_csr(dd, DC_DC8051_ERR_CLR, ~(u64)0);
}
-/**
- * hfi1_clean_up_interrupts() - Free all IRQ resources
- * @dd: valid device data data structure
- *
- * Free the MSIx and assoicated PCI resources, if they have been allocated.
- */
-void hfi1_clean_up_interrupts(struct hfi1_devdata *dd)
-{
- int i;
- struct hfi1_msix_entry *me = dd->msix_entries;
-
- /* remove irqs - must happen before disabling/turning off */
- for (i = 0; i < dd->num_msix_entries; i++, me++) {
- if (!me->arg) /* => no irq, no affinity */
- continue;
- hfi1_put_irq_affinity(dd, me);
- pci_free_irq(dd->pcidev, i, me->arg);
- }
-
- /* clean structures */
- kfree(dd->msix_entries);
- dd->msix_entries = NULL;
- dd->num_msix_entries = 0;
-
- pci_free_irq_vectors(dd->pcidev);
-}
-
/*
* Remap the interrupt source from the general handler to the given MSI-X
* interrupt.
*/
-static void remap_intr(struct hfi1_devdata *dd, int isrc, int msix_intr)
+void remap_intr(struct hfi1_devdata *dd, int isrc, int msix_intr)
{
u64 reg;
int m, n;
@@ -13098,8 +13094,7 @@ static void remap_intr(struct hfi1_devdata *dd, int isrc, int msix_intr)
write_csr(dd, CCE_INT_MAP + (8 * m), reg);
}
-static void remap_sdma_interrupts(struct hfi1_devdata *dd,
- int engine, int msix_intr)
+void remap_sdma_interrupts(struct hfi1_devdata *dd, int engine, int msix_intr)
{
/*
* SDMA engine interrupt sources grouped by type, rather than
@@ -13108,204 +13103,16 @@ static void remap_sdma_interrupts(struct hfi1_devdata *dd,
* SDMAProgress
* SDMAIdle
*/
- remap_intr(dd, IS_SDMA_START + 0 * TXE_NUM_SDMA_ENGINES + engine,
- msix_intr);
- remap_intr(dd, IS_SDMA_START + 1 * TXE_NUM_SDMA_ENGINES + engine,
- msix_intr);
- remap_intr(dd, IS_SDMA_START + 2 * TXE_NUM_SDMA_ENGINES + engine,
- msix_intr);
-}
-
-static int request_msix_irqs(struct hfi1_devdata *dd)
-{
- int first_general, last_general;
- int first_sdma, last_sdma;
- int first_rx, last_rx;
- int i, ret = 0;
-
- /* calculate the ranges we are going to use */
- first_general = 0;
- last_general = first_general + 1;
- first_sdma = last_general;
- last_sdma = first_sdma + dd->num_sdma;
- first_rx = last_sdma;
- last_rx = first_rx + dd->n_krcv_queues + dd->num_vnic_contexts;
-
- /* VNIC MSIx interrupts get mapped when VNIC contexts are created */
- dd->first_dyn_msix_idx = first_rx + dd->n_krcv_queues;
-
- /*
- * Sanity check - the code expects all SDMA chip source
- * interrupts to be in the same CSR, starting at bit 0. Verify
- * that this is true by checking the bit location of the start.
- */
- BUILD_BUG_ON(IS_SDMA_START % 64);
-
- for (i = 0; i < dd->num_msix_entries; i++) {
- struct hfi1_msix_entry *me = &dd->msix_entries[i];
- const char *err_info;
- irq_handler_t handler;
- irq_handler_t thread = NULL;
- void *arg = NULL;
- int idx;
- struct hfi1_ctxtdata *rcd = NULL;
- struct sdma_engine *sde = NULL;
- char name[MAX_NAME_SIZE];
-
- /* obtain the arguments to pci_request_irq */
- if (first_general <= i && i < last_general) {
- idx = i - first_general;
- handler = general_interrupt;
- arg = dd;
- snprintf(name, sizeof(name),
- DRIVER_NAME "_%d", dd->unit);
- err_info = "general";
- me->type = IRQ_GENERAL;
- } else if (first_sdma <= i && i < last_sdma) {
- idx = i - first_sdma;
- sde = &dd->per_sdma[idx];
- handler = sdma_interrupt;
- arg = sde;
- snprintf(name, sizeof(name),
- DRIVER_NAME "_%d sdma%d", dd->unit, idx);
- err_info = "sdma";
- remap_sdma_interrupts(dd, idx, i);
- me->type = IRQ_SDMA;
- } else if (first_rx <= i && i < last_rx) {
- idx = i - first_rx;
- rcd = hfi1_rcd_get_by_index_safe(dd, idx);
- if (rcd) {
- /*
- * Set the interrupt register and mask for this
- * context's interrupt.
- */
- rcd->ireg = (IS_RCVAVAIL_START + idx) / 64;
- rcd->imask = ((u64)1) <<
- ((IS_RCVAVAIL_START + idx) % 64);
- handler = receive_context_interrupt;
- thread = receive_context_thread;
- arg = rcd;
- snprintf(name, sizeof(name),
- DRIVER_NAME "_%d kctxt%d",
- dd->unit, idx);
- err_info = "receive context";
- remap_intr(dd, IS_RCVAVAIL_START + idx, i);
- me->type = IRQ_RCVCTXT;
- rcd->msix_intr = i;
- hfi1_rcd_put(rcd);
- }
- } else {
- /* not in our expected range - complain, then
- * ignore it
- */
- dd_dev_err(dd,
- "Unexpected extra MSI-X interrupt %d\n", i);
- continue;
- }
- /* no argument, no interrupt */
- if (!arg)
- continue;
- /* make sure the name is terminated */
- name[sizeof(name) - 1] = 0;
- me->irq = pci_irq_vector(dd->pcidev, i);
- ret = pci_request_irq(dd->pcidev, i, handler, thread, arg,
- name);
- if (ret) {
- dd_dev_err(dd,
- "unable to allocate %s interrupt, irq %d, index %d, err %d\n",
- err_info, me->irq, idx, ret);
- return ret;
- }
- /*
- * assign arg after pci_request_irq call, so it will be
- * cleaned up
- */
- me->arg = arg;
-
- ret = hfi1_get_irq_affinity(dd, me);
- if (ret)
- dd_dev_err(dd, "unable to pin IRQ %d\n", ret);
- }
-
- return ret;
-}
-
-void hfi1_vnic_synchronize_irq(struct hfi1_devdata *dd)
-{
- int i;
-
- for (i = 0; i < dd->vnic.num_ctxt; i++) {
- struct hfi1_ctxtdata *rcd = dd->vnic.ctxt[i];
- struct hfi1_msix_entry *me = &dd->msix_entries[rcd->msix_intr];
-
- synchronize_irq(me->irq);
- }
-}
-
-void hfi1_reset_vnic_msix_info(struct hfi1_ctxtdata *rcd)
-{
- struct hfi1_devdata *dd = rcd->dd;
- struct hfi1_msix_entry *me = &dd->msix_entries[rcd->msix_intr];
-
- if (!me->arg) /* => no irq, no affinity */
- return;
-
- hfi1_put_irq_affinity(dd, me);
- pci_free_irq(dd->pcidev, rcd->msix_intr, me->arg);
-
- me->arg = NULL;
-}
-
-void hfi1_set_vnic_msix_info(struct hfi1_ctxtdata *rcd)
-{
- struct hfi1_devdata *dd = rcd->dd;
- struct hfi1_msix_entry *me;
- int idx = rcd->ctxt;
- void *arg = rcd;
- int ret;
-
- rcd->msix_intr = dd->vnic.msix_idx++;
- me = &dd->msix_entries[rcd->msix_intr];
-
- /*
- * Set the interrupt register and mask for this
- * context's interrupt.
- */
- rcd->ireg = (IS_RCVAVAIL_START + idx) / 64;
- rcd->imask = ((u64)1) <<
- ((IS_RCVAVAIL_START + idx) % 64);
- me->type = IRQ_RCVCTXT;
- me->irq = pci_irq_vector(dd->pcidev, rcd->msix_intr);
- remap_intr(dd, IS_RCVAVAIL_START + idx, rcd->msix_intr);
-
- ret = pci_request_irq(dd->pcidev, rcd->msix_intr,
- receive_context_interrupt,
- receive_context_thread, arg,
- DRIVER_NAME "_%d kctxt%d", dd->unit, idx);
- if (ret) {
- dd_dev_err(dd, "vnic irq request (irq %d, idx %d) fail %d\n",
- me->irq, idx, ret);
- return;
- }
- /*
- * assign arg after pci_request_irq call, so it will be
- * cleaned up
- */
- me->arg = arg;
-
- ret = hfi1_get_irq_affinity(dd, me);
- if (ret) {
- dd_dev_err(dd,
- "unable to pin IRQ %d\n", ret);
- pci_free_irq(dd->pcidev, rcd->msix_intr, me->arg);
- }
+ remap_intr(dd, IS_SDMA_START + engine, msix_intr);
+ remap_intr(dd, IS_SDMA_PROGRESS_START + engine, msix_intr);
+ remap_intr(dd, IS_SDMA_IDLE_START + engine, msix_intr);
}
/*
* Set the general handler to accept all interrupts, remap all
* chip interrupts back to MSI-X 0.
*/
-static void reset_interrupts(struct hfi1_devdata *dd)
+void reset_interrupts(struct hfi1_devdata *dd)
{
int i;
@@ -13318,54 +13125,33 @@ static void reset_interrupts(struct hfi1_devdata *dd)
write_csr(dd, CCE_INT_MAP + (8 * i), 0);
}
+/**
+ * set_up_interrupts() - Initialize the IRQ resources and state
+ * @dd: valid devdata
+ *
+ */
static int set_up_interrupts(struct hfi1_devdata *dd)
{
- u32 total;
- int ret, request;
-
- /*
- * Interrupt count:
- * 1 general, "slow path" interrupt (includes the SDMA engines
- * slow source, SDMACleanupDone)
- * N interrupts - one per used SDMA engine
- * M interrupt - one per kernel receive context
- * V interrupt - one for each VNIC context
- */
- total = 1 + dd->num_sdma + dd->n_krcv_queues + dd->num_vnic_contexts;
-
- /* ask for MSI-X interrupts */
- request = request_msix(dd, total);
- if (request < 0) {
- ret = request;
- goto fail;
- } else {
- dd->msix_entries = kcalloc(total, sizeof(*dd->msix_entries),
- GFP_KERNEL);
- if (!dd->msix_entries) {
- ret = -ENOMEM;
- goto fail;
- }
- /* using MSI-X */
- dd->num_msix_entries = total;
- dd_dev_info(dd, "%u MSI-X interrupts allocated\n", total);
- }
+ int ret;
/* mask all interrupts */
- set_intr_state(dd, 0);
+ set_intr_bits(dd, IS_FIRST_SOURCE, IS_LAST_SOURCE, false);
+
/* clear all pending interrupts */
clear_all_interrupts(dd);
/* reset general handler mask, chip MSI-X mappings */
reset_interrupts(dd);
- ret = request_msix_irqs(dd);
+ /* ask for MSI-X interrupts */
+ ret = msix_initialize(dd);
if (ret)
- goto fail;
+ return ret;
- return 0;
+ ret = msix_request_irqs(dd);
+ if (ret)
+ msix_clean_up_interrupts(dd);
-fail:
- hfi1_clean_up_interrupts(dd);
return ret;
}
@@ -14918,20 +14704,16 @@ err_exit:
}
/**
- * Allocate and initialize the device structure for the hfi.
+ * hfi1_init_dd() - Initialize most of the dd structure.
* @dev: the pci_dev for hfi1_ib device
* @ent: pci_device_id struct for this dev
*
- * Also allocates, initializes, and returns the devdata struct for this
- * device instance
- *
* This is global, and is called directly at init to set up the
* chip-specific function pointers for later use.
*/
-struct hfi1_devdata *hfi1_init_dd(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+int hfi1_init_dd(struct hfi1_devdata *dd)
{
- struct hfi1_devdata *dd;
+ struct pci_dev *pdev = dd->pcidev;
struct hfi1_pportdata *ppd;
u64 reg;
int i, ret;
@@ -14942,13 +14724,8 @@ struct hfi1_devdata *hfi1_init_dd(struct pci_dev *pdev,
"Functional simulator"
};
struct pci_dev *parent = pdev->bus->self;
- u32 sdma_engines;
+ u32 sdma_engines = chip_sdma_engines(dd);
- dd = hfi1_alloc_devdata(pdev, NUM_IB_PORTS *
- sizeof(struct hfi1_pportdata));
- if (IS_ERR(dd))
- goto bail;
- sdma_engines = chip_sdma_engines(dd);
ppd = dd->pport;
for (i = 0; i < dd->num_pports; i++, ppd++) {
int vl;
@@ -15127,6 +14904,12 @@ struct hfi1_devdata *hfi1_init_dd(struct pci_dev *pdev,
if (ret)
goto bail_cleanup;
+ /*
+ * This should probably occur in hfi1_pcie_init(), but historically
+ * occurs after the do_pcie_gen3_transition() code.
+ */
+ tune_pcie_caps(dd);
+
/* start setting dd values and adjusting CSRs */
init_early_variables(dd);
@@ -15239,14 +15022,13 @@ bail_free_cntrs:
free_cntrs(dd);
bail_clear_intr:
hfi1_comp_vectors_clean_up(dd);
- hfi1_clean_up_interrupts(dd);
+ msix_clean_up_interrupts(dd);
bail_cleanup:
hfi1_pcie_ddcleanup(dd);
bail_free:
hfi1_free_devdata(dd);
- dd = ERR_PTR(ret);
bail:
- return dd;
+ return ret;
}
static u16 delay_cycles(struct hfi1_pportdata *ppd, u32 desired_egress_rate,
diff --git a/drivers/infiniband/hw/hfi1/chip.h b/drivers/infiniband/hw/hfi1/chip.h
index 36b04d6300e5..6b9c8f12dff8 100644
--- a/drivers/infiniband/hw/hfi1/chip.h
+++ b/drivers/infiniband/hw/hfi1/chip.h
@@ -52,9 +52,7 @@
*/
/* sizes */
-#define CCE_NUM_MSIX_VECTORS 256
-#define CCE_NUM_INT_CSRS 12
-#define CCE_NUM_INT_MAP_CSRS 96
+#define BITS_PER_REGISTER (BITS_PER_BYTE * sizeof(u64))
#define NUM_INTERRUPT_SOURCES 768
#define RXE_NUM_CONTEXTS 160
#define RXE_PER_CONTEXT_SIZE 0x1000 /* 4k */
@@ -161,34 +159,49 @@
(CR_CREDIT_RETURN_DUE_TO_FORCE_MASK << \
CR_CREDIT_RETURN_DUE_TO_FORCE_SHIFT)
-/* interrupt source numbers */
-#define IS_GENERAL_ERR_START 0
-#define IS_SDMAENG_ERR_START 16
-#define IS_SENDCTXT_ERR_START 32
-#define IS_SDMA_START 192 /* includes SDmaProgress,SDmaIdle */
+/* Specific IRQ sources */
+#define CCE_ERR_INT 0
+#define RXE_ERR_INT 1
+#define MISC_ERR_INT 2
+#define PIO_ERR_INT 4
+#define SDMA_ERR_INT 5
+#define EGRESS_ERR_INT 6
+#define TXE_ERR_INT 7
+#define PBC_INT 240
+#define GPIO_ASSERT_INT 241
+#define QSFP1_INT 242
+#define QSFP2_INT 243
+#define TCRIT_INT 244
+
+/* interrupt source ranges */
+#define IS_FIRST_SOURCE CCE_ERR_INT
+#define IS_GENERAL_ERR_START 0
+#define IS_SDMAENG_ERR_START 16
+#define IS_SENDCTXT_ERR_START 32
+#define IS_SDMA_START 192
+#define IS_SDMA_PROGRESS_START 208
+#define IS_SDMA_IDLE_START 224
#define IS_VARIOUS_START 240
#define IS_DC_START 248
#define IS_RCVAVAIL_START 256
#define IS_RCVURGENT_START 416
#define IS_SENDCREDIT_START 576
#define IS_RESERVED_START 736
-#define IS_MAX_SOURCES 768
+#define IS_LAST_SOURCE 767
/* derived interrupt source values */
-#define IS_GENERAL_ERR_END IS_SDMAENG_ERR_START
-#define IS_SDMAENG_ERR_END IS_SENDCTXT_ERR_START
-#define IS_SENDCTXT_ERR_END IS_SDMA_START
-#define IS_SDMA_END IS_VARIOUS_START
-#define IS_VARIOUS_END IS_DC_START
-#define IS_DC_END IS_RCVAVAIL_START
-#define IS_RCVAVAIL_END IS_RCVURGENT_START
-#define IS_RCVURGENT_END IS_SENDCREDIT_START
-#define IS_SENDCREDIT_END IS_RESERVED_START
-#define IS_RESERVED_END IS_MAX_SOURCES
-
-/* absolute interrupt numbers for QSFP1Int and QSFP2Int */
-#define QSFP1_INT 242
-#define QSFP2_INT 243
+#define IS_GENERAL_ERR_END 7
+#define IS_SDMAENG_ERR_END 31
+#define IS_SENDCTXT_ERR_END 191
+#define IS_SDMA_END 207
+#define IS_SDMA_PROGRESS_END 223
+#define IS_SDMA_IDLE_END 239
+#define IS_VARIOUS_END 244
+#define IS_DC_END 255
+#define IS_RCVAVAIL_END 415
+#define IS_RCVURGENT_END 575
+#define IS_SENDCREDIT_END 735
+#define IS_RESERVED_END IS_LAST_SOURCE
/* DCC_CFG_PORT_CONFIG logical link states */
#define LSTATE_DOWN 0x1
@@ -1416,6 +1429,18 @@ void hfi1_read_link_quality(struct hfi1_devdata *dd, u8 *link_quality);
void hfi1_init_vnic_rsm(struct hfi1_devdata *dd);
void hfi1_deinit_vnic_rsm(struct hfi1_devdata *dd);
+irqreturn_t general_interrupt(int irq, void *data);
+irqreturn_t sdma_interrupt(int irq, void *data);
+irqreturn_t receive_context_interrupt(int irq, void *data);
+irqreturn_t receive_context_thread(int irq, void *data);
+
+int set_intr_bits(struct hfi1_devdata *dd, u16 first, u16 last, bool set);
+void init_qsfp_int(struct hfi1_devdata *dd);
+void clear_all_interrupts(struct hfi1_devdata *dd);
+void remap_intr(struct hfi1_devdata *dd, int isrc, int msix_intr);
+void remap_sdma_interrupts(struct hfi1_devdata *dd, int engine, int msix_intr);
+void reset_interrupts(struct hfi1_devdata *dd);
+
/*
* Interrupt source table.
*
diff --git a/drivers/infiniband/hw/hfi1/chip_registers.h b/drivers/infiniband/hw/hfi1/chip_registers.h
index ee6dca5e2a2f..c6163a347e93 100644
--- a/drivers/infiniband/hw/hfi1/chip_registers.h
+++ b/drivers/infiniband/hw/hfi1/chip_registers.h
@@ -878,6 +878,10 @@
#define SEND_CTRL (TXE + 0x000000000000)
#define SEND_CTRL_CM_RESET_SMASK 0x4ull
#define SEND_CTRL_SEND_ENABLE_SMASK 0x1ull
+#define SEND_CTRL_UNSUPPORTED_VL_SHIFT 3
+#define SEND_CTRL_UNSUPPORTED_VL_MASK 0xFFull
+#define SEND_CTRL_UNSUPPORTED_VL_SMASK (SEND_CTRL_UNSUPPORTED_VL_MASK \
+ << SEND_CTRL_UNSUPPORTED_VL_SHIFT)
#define SEND_CTRL_VL_ARBITER_ENABLE_SMASK 0x2ull
#define SEND_CTXT_CHECK_ENABLE (TXE + 0x000000100080)
#define SEND_CTXT_CHECK_ENABLE_CHECK_BYPASS_VL_MAPPING_SMASK 0x80ull
diff --git a/drivers/infiniband/hw/hfi1/file_ops.c b/drivers/infiniband/hw/hfi1/file_ops.c
index 1fc75647e47b..c22ebc774a6a 100644
--- a/drivers/infiniband/hw/hfi1/file_ops.c
+++ b/drivers/infiniband/hw/hfi1/file_ops.c
@@ -681,7 +681,8 @@ static int hfi1_file_close(struct inode *inode, struct file *fp)
HFI1_RCVCTRL_TAILUPD_DIS |
HFI1_RCVCTRL_ONE_PKT_EGR_DIS |
HFI1_RCVCTRL_NO_RHQ_DROP_DIS |
- HFI1_RCVCTRL_NO_EGR_DROP_DIS, uctxt);
+ HFI1_RCVCTRL_NO_EGR_DROP_DIS |
+ HFI1_RCVCTRL_URGENT_DIS, uctxt);
/* Clear the context's J_KEY */
hfi1_clear_ctxt_jkey(dd, uctxt);
/*
@@ -1096,6 +1097,7 @@ static void user_init(struct hfi1_ctxtdata *uctxt)
hfi1_set_ctxt_jkey(uctxt->dd, uctxt, uctxt->jkey);
rcvctrl_ops = HFI1_RCVCTRL_CTXT_ENB;
+ rcvctrl_ops |= HFI1_RCVCTRL_URGENT_ENB;
if (HFI1_CAP_UGET_MASK(uctxt->flags, HDRSUPP))
rcvctrl_ops |= HFI1_RCVCTRL_TIDFLOW_ENB;
/*
diff --git a/drivers/infiniband/hw/hfi1/hfi.h b/drivers/infiniband/hw/hfi1/hfi.h
index d9470317983f..1401b6ea4a28 100644
--- a/drivers/infiniband/hw/hfi1/hfi.h
+++ b/drivers/infiniband/hw/hfi1/hfi.h
@@ -80,6 +80,7 @@
#include "qsfp.h"
#include "platform.h"
#include "affinity.h"
+#include "msix.h"
/* bumped 1 from s/w major version of TrueScale */
#define HFI1_CHIP_VERS_MAJ 3U
@@ -620,6 +621,8 @@ struct rvt_sge_state;
#define HFI1_RCVCTRL_NO_RHQ_DROP_DIS 0x8000
#define HFI1_RCVCTRL_NO_EGR_DROP_ENB 0x10000
#define HFI1_RCVCTRL_NO_EGR_DROP_DIS 0x20000
+#define HFI1_RCVCTRL_URGENT_ENB 0x40000
+#define HFI1_RCVCTRL_URGENT_DIS 0x80000
/* partition enforcement flags */
#define HFI1_PART_ENFORCE_IN 0x1
@@ -667,6 +670,14 @@ struct hfi1_msix_entry {
struct irq_affinity_notify notify;
};
+struct hfi1_msix_info {
+ /* lock to synchronize in_use_msix access */
+ spinlock_t msix_lock;
+ DECLARE_BITMAP(in_use_msix, CCE_NUM_MSIX_VECTORS);
+ struct hfi1_msix_entry *msix_entries;
+ u16 max_requested;
+};
+
/* per-SL CCA information */
struct cca_timer {
struct hrtimer hrtimer;
@@ -992,7 +1003,6 @@ struct hfi1_vnic_data {
struct idr vesw_idr;
u8 rmt_start;
u8 num_ctxt;
- u32 msix_idx;
};
struct hfi1_vnic_vport_info;
@@ -1205,11 +1215,6 @@ struct hfi1_devdata {
struct diag_client *diag_client;
- /* MSI-X information */
- struct hfi1_msix_entry *msix_entries;
- u32 num_msix_entries;
- u32 first_dyn_msix_idx;
-
/* general interrupt: mask of handled interrupts */
u64 gi_mask[CCE_NUM_INT_CSRS];
@@ -1223,6 +1228,9 @@ struct hfi1_devdata {
*/
struct timer_list synth_stats_timer;
+ /* MSI-X information */
+ struct hfi1_msix_info msix_info;
+
/*
* device counters
*/
@@ -1349,6 +1357,8 @@ struct hfi1_devdata {
/* vnic data */
struct hfi1_vnic_data vnic;
+ /* Lock to protect IRQ SRC register access */
+ spinlock_t irq_src_lock;
};
static inline bool hfi1_vnic_is_rsm_full(struct hfi1_devdata *dd, int spare)
@@ -1431,9 +1441,6 @@ int handle_receive_interrupt(struct hfi1_ctxtdata *rcd, int thread);
int handle_receive_interrupt_nodma_rtail(struct hfi1_ctxtdata *rcd, int thread);
int handle_receive_interrupt_dma_rtail(struct hfi1_ctxtdata *rcd, int thread);
void set_all_slowpath(struct hfi1_devdata *dd);
-void hfi1_vnic_synchronize_irq(struct hfi1_devdata *dd);
-void hfi1_set_vnic_msix_info(struct hfi1_ctxtdata *rcd);
-void hfi1_reset_vnic_msix_info(struct hfi1_ctxtdata *rcd);
extern const struct pci_device_id hfi1_pci_tbl[];
void hfi1_make_ud_req_9B(struct rvt_qp *qp,
@@ -1887,10 +1894,8 @@ struct cc_state *get_cc_state_protected(struct hfi1_pportdata *ppd)
#define HFI1_CTXT_WAITING_URG 4
/* free up any allocated data at closes */
-struct hfi1_devdata *hfi1_init_dd(struct pci_dev *pdev,
- const struct pci_device_id *ent);
+int hfi1_init_dd(struct hfi1_devdata *dd);
void hfi1_free_devdata(struct hfi1_devdata *dd);
-struct hfi1_devdata *hfi1_alloc_devdata(struct pci_dev *pdev, size_t extra);
/* LED beaconing functions */
void hfi1_start_led_override(struct hfi1_pportdata *ppd, unsigned int timeon,
@@ -1963,6 +1968,7 @@ static inline u32 get_rcvhdrtail(const struct hfi1_ctxtdata *rcd)
*/
extern const char ib_hfi1_version[];
+extern const struct attribute_group ib_hfi1_attr_group;
int hfi1_device_create(struct hfi1_devdata *dd);
void hfi1_device_remove(struct hfi1_devdata *dd);
@@ -1974,16 +1980,15 @@ void hfi1_verbs_unregister_sysfs(struct hfi1_devdata *dd);
/* Hook for sysfs read of QSFP */
int qsfp_dump(struct hfi1_pportdata *ppd, char *buf, int len);
-int hfi1_pcie_init(struct pci_dev *pdev, const struct pci_device_id *ent);
-void hfi1_clean_up_interrupts(struct hfi1_devdata *dd);
+int hfi1_pcie_init(struct hfi1_devdata *dd);
void hfi1_pcie_cleanup(struct pci_dev *pdev);
int hfi1_pcie_ddinit(struct hfi1_devdata *dd, struct pci_dev *pdev);
void hfi1_pcie_ddcleanup(struct hfi1_devdata *);
int pcie_speeds(struct hfi1_devdata *dd);
-int request_msix(struct hfi1_devdata *dd, u32 msireq);
int restore_pci_variables(struct hfi1_devdata *dd);
int save_pci_variables(struct hfi1_devdata *dd);
int do_pcie_gen3_transition(struct hfi1_devdata *dd);
+void tune_pcie_caps(struct hfi1_devdata *dd);
int parse_platform_config(struct hfi1_devdata *dd);
int get_platform_config_field(struct hfi1_devdata *dd,
enum platform_config_table_type_encoding
@@ -2124,19 +2129,6 @@ static inline u64 hfi1_pkt_base_sdma_integrity(struct hfi1_devdata *dd)
return base_sdma_integrity;
}
-/*
- * hfi1_early_err is used (only!) to print early errors before devdata is
- * allocated, or when dd->pcidev may not be valid, and at the tail end of
- * cleanup when devdata may have been freed, etc. hfi1_dev_porterr is
- * the same as dd_dev_err, but is used when the message really needs
- * the IB port# to be definitive as to what's happening..
- */
-#define hfi1_early_err(dev, fmt, ...) \
- dev_err(dev, fmt, ##__VA_ARGS__)
-
-#define hfi1_early_info(dev, fmt, ...) \
- dev_info(dev, fmt, ##__VA_ARGS__)
-
#define dd_dev_emerg(dd, fmt, ...) \
dev_emerg(&(dd)->pcidev->dev, "%s: " fmt, \
rvt_get_ibdev_name(&(dd)->verbs_dev.rdi), ##__VA_ARGS__)
diff --git a/drivers/infiniband/hw/hfi1/init.c b/drivers/infiniband/hw/hfi1/init.c
index 758d273c32cf..09044905284f 100644
--- a/drivers/infiniband/hw/hfi1/init.c
+++ b/drivers/infiniband/hw/hfi1/init.c
@@ -83,6 +83,8 @@
#define HFI1_MIN_EAGER_BUFFER_SIZE (4 * 1024) /* 4KB */
#define HFI1_MAX_EAGER_BUFFER_SIZE (256 * 1024) /* 256KB */
+#define NUM_IB_PORTS 1
+
/*
* Number of user receive contexts we are configured to use (to allow for more
* pio buffers per ctxt, etc.) Zero means use one user context per CPU.
@@ -654,9 +656,8 @@ void hfi1_init_pportdata(struct pci_dev *pdev, struct hfi1_pportdata *ppd,
ppd->part_enforce |= HFI1_PART_ENFORCE_IN;
if (loopback) {
- hfi1_early_err(&pdev->dev,
- "Faking data partition 0x8001 in idx %u\n",
- !default_pkey_idx);
+ dd_dev_err(dd, "Faking data partition 0x8001 in idx %u\n",
+ !default_pkey_idx);
ppd->pkeys[!default_pkey_idx] = 0x8001;
}
@@ -702,9 +703,7 @@ void hfi1_init_pportdata(struct pci_dev *pdev, struct hfi1_pportdata *ppd,
return;
bail:
-
- hfi1_early_err(&pdev->dev,
- "Congestion Control Agent disabled for port %d\n", port);
+ dd_dev_err(dd, "Congestion Control Agent disabled for port %d\n", port);
}
/*
@@ -833,6 +832,23 @@ wq_error:
}
/**
+ * enable_general_intr() - Enable the IRQs that will be handled by the
+ * general interrupt handler.
+ * @dd: valid devdata
+ *
+ */
+static void enable_general_intr(struct hfi1_devdata *dd)
+{
+ set_intr_bits(dd, CCE_ERR_INT, MISC_ERR_INT, true);
+ set_intr_bits(dd, PIO_ERR_INT, TXE_ERR_INT, true);
+ set_intr_bits(dd, IS_SENDCTXT_ERR_START, IS_SENDCTXT_ERR_END, true);
+ set_intr_bits(dd, PBC_INT, GPIO_ASSERT_INT, true);
+ set_intr_bits(dd, TCRIT_INT, TCRIT_INT, true);
+ set_intr_bits(dd, IS_DC_START, IS_DC_END, true);
+ set_intr_bits(dd, IS_SENDCREDIT_START, IS_SENDCREDIT_END, true);
+}
+
+/**
* hfi1_init - do the actual initialization sequence on the chip
* @dd: the hfi1_ib device
* @reinit: re-initializing, so don't allocate new memory
@@ -916,6 +932,7 @@ int hfi1_init(struct hfi1_devdata *dd, int reinit)
"failed to allocate kernel ctxt's rcvhdrq and/or egr bufs\n");
ret = lastfail;
}
+ /* enable IRQ */
hfi1_rcd_put(rcd);
}
@@ -954,7 +971,8 @@ done:
HFI1_STATUS_INITTED;
if (!ret) {
/* enable all interrupts from the chip */
- set_intr_state(dd, 1);
+ enable_general_intr(dd);
+ init_qsfp_int(dd);
/* chip is OK for user apps; mark it as initialized */
for (pidx = 0; pidx < dd->num_pports; ++pidx) {
@@ -1051,9 +1069,9 @@ static void shutdown_device(struct hfi1_devdata *dd)
}
dd->flags &= ~HFI1_INITTED;
- /* mask and clean up interrupts, but not errors */
- set_intr_state(dd, 0);
- hfi1_clean_up_interrupts(dd);
+ /* mask and clean up interrupts */
+ set_intr_bits(dd, IS_FIRST_SOURCE, IS_LAST_SOURCE, false);
+ msix_clean_up_interrupts(dd);
for (pidx = 0; pidx < dd->num_pports; ++pidx) {
ppd = dd->pport + pidx;
@@ -1246,15 +1264,19 @@ void hfi1_free_devdata(struct hfi1_devdata *dd)
kobject_put(&dd->kobj);
}
-/*
- * Allocate our primary per-unit data structure. Must be done via verbs
- * allocator, because the verbs cleanup process both does cleanup and
- * free of the data structure.
+/**
+ * hfi1_alloc_devdata - Allocate our primary per-unit data structure.
+ * @pdev: Valid PCI device
+ * @extra: How many bytes to alloc past the default
+ *
+ * Must be done via verbs allocator, because the verbs cleanup process
+ * both does cleanup and free of the data structure.
* "extra" is for chip-specific data.
*
* Use the idr mechanism to get a unit number for this unit.
*/
-struct hfi1_devdata *hfi1_alloc_devdata(struct pci_dev *pdev, size_t extra)
+static struct hfi1_devdata *hfi1_alloc_devdata(struct pci_dev *pdev,
+ size_t extra)
{
unsigned long flags;
struct hfi1_devdata *dd;
@@ -1287,8 +1309,8 @@ struct hfi1_devdata *hfi1_alloc_devdata(struct pci_dev *pdev, size_t extra)
idr_preload_end();
if (ret < 0) {
- hfi1_early_err(&pdev->dev,
- "Could not allocate unit ID: error %d\n", -ret);
+ dev_err(&pdev->dev,
+ "Could not allocate unit ID: error %d\n", -ret);
goto bail;
}
rvt_set_ibdev_name(&dd->verbs_dev.rdi, "%s_%d", class_name(), dd->unit);
@@ -1309,6 +1331,7 @@ struct hfi1_devdata *hfi1_alloc_devdata(struct pci_dev *pdev, size_t extra)
spin_lock_init(&dd->pio_map_lock);
mutex_init(&dd->dc8051_lock);
init_waitqueue_head(&dd->event_queue);
+ spin_lock_init(&dd->irq_src_lock);
dd->int_counter = alloc_percpu(u64);
if (!dd->int_counter) {
@@ -1481,9 +1504,6 @@ static int __init hfi1_mod_init(void)
idr_init(&hfi1_unit_table);
hfi1_dbg_init();
- ret = hfi1_wss_init();
- if (ret < 0)
- goto bail_wss;
ret = pci_register_driver(&hfi1_pci_driver);
if (ret < 0) {
pr_err("Unable to register driver: error %d\n", -ret);
@@ -1492,8 +1512,6 @@ static int __init hfi1_mod_init(void)
goto bail; /* all OK */
bail_dev:
- hfi1_wss_exit();
-bail_wss:
hfi1_dbg_exit();
idr_destroy(&hfi1_unit_table);
dev_cleanup();
@@ -1510,7 +1528,6 @@ static void __exit hfi1_mod_cleanup(void)
{
pci_unregister_driver(&hfi1_pci_driver);
node_affinity_destroy_all();
- hfi1_wss_exit();
hfi1_dbg_exit();
idr_destroy(&hfi1_unit_table);
@@ -1604,23 +1621,23 @@ static void postinit_cleanup(struct hfi1_devdata *dd)
hfi1_free_devdata(dd);
}
-static int init_validate_rcvhdrcnt(struct device *dev, uint thecnt)
+static int init_validate_rcvhdrcnt(struct hfi1_devdata *dd, uint thecnt)
{
if (thecnt <= HFI1_MIN_HDRQ_EGRBUF_CNT) {
- hfi1_early_err(dev, "Receive header queue count too small\n");
+ dd_dev_err(dd, "Receive header queue count too small\n");
return -EINVAL;
}
if (thecnt > HFI1_MAX_HDRQ_EGRBUF_CNT) {
- hfi1_early_err(dev,
- "Receive header queue count cannot be greater than %u\n",
- HFI1_MAX_HDRQ_EGRBUF_CNT);
+ dd_dev_err(dd,
+ "Receive header queue count cannot be greater than %u\n",
+ HFI1_MAX_HDRQ_EGRBUF_CNT);
return -EINVAL;
}
if (thecnt % HDRQ_INCREMENT) {
- hfi1_early_err(dev, "Receive header queue count %d must be divisible by %lu\n",
- thecnt, HDRQ_INCREMENT);
+ dd_dev_err(dd, "Receive header queue count %d must be divisible by %lu\n",
+ thecnt, HDRQ_INCREMENT);
return -EINVAL;
}
@@ -1639,22 +1656,29 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Validate dev ids */
if (!(ent->device == PCI_DEVICE_ID_INTEL0 ||
ent->device == PCI_DEVICE_ID_INTEL1)) {
- hfi1_early_err(&pdev->dev,
- "Failing on unknown Intel deviceid 0x%x\n",
- ent->device);
+ dev_err(&pdev->dev, "Failing on unknown Intel deviceid 0x%x\n",
+ ent->device);
ret = -ENODEV;
goto bail;
}
+ /* Allocate the dd so we can get to work */
+ dd = hfi1_alloc_devdata(pdev, NUM_IB_PORTS *
+ sizeof(struct hfi1_pportdata));
+ if (IS_ERR(dd)) {
+ ret = PTR_ERR(dd);
+ goto bail;
+ }
+
/* Validate some global module parameters */
- ret = init_validate_rcvhdrcnt(&pdev->dev, rcvhdrcnt);
+ ret = init_validate_rcvhdrcnt(dd, rcvhdrcnt);
if (ret)
goto bail;
/* use the encoding function as a sanitization check */
if (!encode_rcv_header_entry_size(hfi1_hdrq_entsize)) {
- hfi1_early_err(&pdev->dev, "Invalid HdrQ Entry size %u\n",
- hfi1_hdrq_entsize);
+ dd_dev_err(dd, "Invalid HdrQ Entry size %u\n",
+ hfi1_hdrq_entsize);
ret = -EINVAL;
goto bail;
}
@@ -1676,10 +1700,10 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
clamp_val(eager_buffer_size,
MIN_EAGER_BUFFER * 8,
MAX_EAGER_BUFFER_TOTAL);
- hfi1_early_info(&pdev->dev, "Eager buffer size %u\n",
- eager_buffer_size);
+ dd_dev_info(dd, "Eager buffer size %u\n",
+ eager_buffer_size);
} else {
- hfi1_early_err(&pdev->dev, "Invalid Eager buffer size of 0\n");
+ dd_dev_err(dd, "Invalid Eager buffer size of 0\n");
ret = -EINVAL;
goto bail;
}
@@ -1687,7 +1711,7 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* restrict value of hfi1_rcvarr_split */
hfi1_rcvarr_split = clamp_val(hfi1_rcvarr_split, 0, 100);
- ret = hfi1_pcie_init(pdev, ent);
+ ret = hfi1_pcie_init(dd);
if (ret)
goto bail;
@@ -1695,12 +1719,9 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
* Do device-specific initialization, function table setup, dd
* allocation, etc.
*/
- dd = hfi1_init_dd(pdev, ent);
-
- if (IS_ERR(dd)) {
- ret = PTR_ERR(dd);
+ ret = hfi1_init_dd(dd);
+ if (ret)
goto clean_bail; /* error already printed */
- }
ret = create_workqueues(dd);
if (ret)
@@ -1731,7 +1752,7 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
dd_dev_err(dd, "Failed to create /dev devices: %d\n", -j);
if (initfail || ret) {
- hfi1_clean_up_interrupts(dd);
+ msix_clean_up_interrupts(dd);
stop_timers(dd);
flush_workqueue(ib_wq);
for (pidx = 0; pidx < dd->num_pports; ++pidx) {
diff --git a/drivers/infiniband/hw/hfi1/iowait.c b/drivers/infiniband/hw/hfi1/iowait.c
new file mode 100644
index 000000000000..582f1ba136ff
--- /dev/null
+++ b/drivers/infiniband/hw/hfi1/iowait.c
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+/*
+ * Copyright(c) 2018 Intel Corporation.
+ *
+ */
+#include "iowait.h"
+#include "trace_iowait.h"
+
+void iowait_set_flag(struct iowait *wait, u32 flag)
+{
+ trace_hfi1_iowait_set(wait, flag);
+ set_bit(flag, &wait->flags);
+}
+
+bool iowait_flag_set(struct iowait *wait, u32 flag)
+{
+ return test_bit(flag, &wait->flags);
+}
+
+inline void iowait_clear_flag(struct iowait *wait, u32 flag)
+{
+ trace_hfi1_iowait_clear(wait, flag);
+ clear_bit(flag, &wait->flags);
+}
+
+/**
+ * iowait_init() - initialize wait structure
+ * @wait: wait struct to initialize
+ * @tx_limit: limit for overflow queuing
+ * @func: restart function for workqueue
+ * @sleep: sleep function for no space
+ * @resume: wakeup function for no space
+ *
+ * This function initializes the iowait
+ * structure embedded in the QP or PQ.
+ *
+ */
+void iowait_init(struct iowait *wait, u32 tx_limit,
+ void (*func)(struct work_struct *work),
+ void (*tidfunc)(struct work_struct *work),
+ int (*sleep)(struct sdma_engine *sde,
+ struct iowait_work *wait,
+ struct sdma_txreq *tx,
+ uint seq,
+ bool pkts_sent),
+ void (*wakeup)(struct iowait *wait, int reason),
+ void (*sdma_drained)(struct iowait *wait))
+{
+ int i;
+
+ wait->count = 0;
+ INIT_LIST_HEAD(&wait->list);
+ init_waitqueue_head(&wait->wait_dma);
+ init_waitqueue_head(&wait->wait_pio);
+ atomic_set(&wait->sdma_busy, 0);
+ atomic_set(&wait->pio_busy, 0);
+ wait->tx_limit = tx_limit;
+ wait->sleep = sleep;
+ wait->wakeup = wakeup;
+ wait->sdma_drained = sdma_drained;
+ wait->flags = 0;
+ for (i = 0; i < IOWAIT_SES; i++) {
+ wait->wait[i].iow = wait;
+ INIT_LIST_HEAD(&wait->wait[i].tx_head);
+ if (i == IOWAIT_IB_SE)
+ INIT_WORK(&wait->wait[i].iowork, func);
+ else
+ INIT_WORK(&wait->wait[i].iowork, tidfunc);
+ }
+}
+
+/**
+ * iowait_cancel_work - cancel all work in iowait
+ * @w: the iowait struct
+ */
+void iowait_cancel_work(struct iowait *w)
+{
+ cancel_work_sync(&iowait_get_ib_work(w)->iowork);
+ cancel_work_sync(&iowait_get_tid_work(w)->iowork);
+}
+
+/**
+ * iowait_set_work_flag - set work flag based on leg
+ * @w - the iowait work struct
+ */
+int iowait_set_work_flag(struct iowait_work *w)
+{
+ if (w == &w->iow->wait[IOWAIT_IB_SE]) {
+ iowait_set_flag(w->iow, IOWAIT_PENDING_IB);
+ return IOWAIT_IB_SE;
+ }
+ iowait_set_flag(w->iow, IOWAIT_PENDING_TID);
+ return IOWAIT_TID_SE;
+}
diff --git a/drivers/infiniband/hw/hfi1/iowait.h b/drivers/infiniband/hw/hfi1/iowait.h
index 3d9c32c7c340..23a58ac0d47c 100644
--- a/drivers/infiniband/hw/hfi1/iowait.h
+++ b/drivers/infiniband/hw/hfi1/iowait.h
@@ -1,7 +1,7 @@
#ifndef _HFI1_IOWAIT_H
#define _HFI1_IOWAIT_H
/*
- * Copyright(c) 2015, 2016 Intel Corporation.
+ * Copyright(c) 2015 - 2018 Intel Corporation.
*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
@@ -49,6 +49,7 @@
#include <linux/list.h>
#include <linux/workqueue.h>
+#include <linux/wait.h>
#include <linux/sched.h>
#include "sdma_txreq.h"
@@ -59,16 +60,47 @@
*/
typedef void (*restart_t)(struct work_struct *work);
+#define IOWAIT_PENDING_IB 0x0
+#define IOWAIT_PENDING_TID 0x1
+
+/*
+ * A QP can have multiple Send Engines (SEs).
+ *
+ * The current use case is for supporting a TID RDMA
+ * packet build/xmit mechanism independent from verbs.
+ */
+#define IOWAIT_SES 2
+#define IOWAIT_IB_SE 0
+#define IOWAIT_TID_SE 1
+
struct sdma_txreq;
struct sdma_engine;
/**
- * struct iowait - linkage for delayed progress/waiting
+ * @iowork: the work struct
+ * @tx_head: list of prebuilt packets
+ * @iow: the parent iowait structure
+ *
+ * This structure is the work item (process) specific
+ * details associated with the each of the two SEs of the
+ * QP.
+ *
+ * The workstruct and the queued TXs are unique to each
+ * SE.
+ */
+struct iowait;
+struct iowait_work {
+ struct work_struct iowork;
+ struct list_head tx_head;
+ struct iowait *iow;
+};
+
+/**
* @list: used to add/insert into QP/PQ wait lists
- * @lock: uses to record the list head lock
* @tx_head: overflow list of sdma_txreq's
* @sleep: no space callback
* @wakeup: space callback wakeup
* @sdma_drained: sdma count drained
+ * @lock: lock protected head of wait queue
* @iowork: workqueue overhead
* @wait_dma: wait for sdma_busy == 0
* @wait_pio: wait for pio_busy == 0
@@ -76,6 +108,8 @@ struct sdma_engine;
* @count: total number of descriptors in tx_head'ed list
* @tx_limit: limit for overflow queuing
* @tx_count: number of tx entry's in tx_head'ed list
+ * @flags: wait flags (one per QP)
+ * @wait: SE array
*
* This is to be embedded in user's state structure
* (QP or PQ).
@@ -98,13 +132,11 @@ struct sdma_engine;
* Waiters explicity know that, but the destroy
* code that unwaits QPs does not.
*/
-
struct iowait {
struct list_head list;
- struct list_head tx_head;
int (*sleep)(
struct sdma_engine *sde,
- struct iowait *wait,
+ struct iowait_work *wait,
struct sdma_txreq *tx,
uint seq,
bool pkts_sent
@@ -112,7 +144,6 @@ struct iowait {
void (*wakeup)(struct iowait *wait, int reason);
void (*sdma_drained)(struct iowait *wait);
seqlock_t *lock;
- struct work_struct iowork;
wait_queue_head_t wait_dma;
wait_queue_head_t wait_pio;
atomic_t sdma_busy;
@@ -121,63 +152,37 @@ struct iowait {
u32 tx_limit;
u32 tx_count;
u8 starved_cnt;
+ unsigned long flags;
+ struct iowait_work wait[IOWAIT_SES];
};
#define SDMA_AVAIL_REASON 0
-/**
- * iowait_init() - initialize wait structure
- * @wait: wait struct to initialize
- * @tx_limit: limit for overflow queuing
- * @func: restart function for workqueue
- * @sleep: sleep function for no space
- * @resume: wakeup function for no space
- *
- * This function initializes the iowait
- * structure embedded in the QP or PQ.
- *
- */
+void iowait_set_flag(struct iowait *wait, u32 flag);
+bool iowait_flag_set(struct iowait *wait, u32 flag);
+void iowait_clear_flag(struct iowait *wait, u32 flag);
-static inline void iowait_init(
- struct iowait *wait,
- u32 tx_limit,
- void (*func)(struct work_struct *work),
- int (*sleep)(
- struct sdma_engine *sde,
- struct iowait *wait,
- struct sdma_txreq *tx,
- uint seq,
- bool pkts_sent),
- void (*wakeup)(struct iowait *wait, int reason),
- void (*sdma_drained)(struct iowait *wait))
-{
- wait->count = 0;
- wait->lock = NULL;
- INIT_LIST_HEAD(&wait->list);
- INIT_LIST_HEAD(&wait->tx_head);
- INIT_WORK(&wait->iowork, func);
- init_waitqueue_head(&wait->wait_dma);
- init_waitqueue_head(&wait->wait_pio);
- atomic_set(&wait->sdma_busy, 0);
- atomic_set(&wait->pio_busy, 0);
- wait->tx_limit = tx_limit;
- wait->sleep = sleep;
- wait->wakeup = wakeup;
- wait->sdma_drained = sdma_drained;
-}
+void iowait_init(struct iowait *wait, u32 tx_limit,
+ void (*func)(struct work_struct *work),
+ void (*tidfunc)(struct work_struct *work),
+ int (*sleep)(struct sdma_engine *sde,
+ struct iowait_work *wait,
+ struct sdma_txreq *tx,
+ uint seq,
+ bool pkts_sent),
+ void (*wakeup)(struct iowait *wait, int reason),
+ void (*sdma_drained)(struct iowait *wait));
/**
- * iowait_schedule() - initialize wait structure
+ * iowait_schedule() - schedule the default send engine work
* @wait: wait struct to schedule
* @wq: workqueue for schedule
* @cpu: cpu
*/
-static inline void iowait_schedule(
- struct iowait *wait,
- struct workqueue_struct *wq,
- int cpu)
+static inline bool iowait_schedule(struct iowait *wait,
+ struct workqueue_struct *wq, int cpu)
{
- queue_work_on(cpu, wq, &wait->iowork);
+ return !!queue_work_on(cpu, wq, &wait->wait[IOWAIT_IB_SE].iowork);
}
/**
@@ -228,6 +233,8 @@ static inline void iowait_sdma_add(struct iowait *wait, int count)
*/
static inline int iowait_sdma_dec(struct iowait *wait)
{
+ if (!wait)
+ return 0;
return atomic_dec_and_test(&wait->sdma_busy);
}
@@ -267,11 +274,13 @@ static inline void iowait_pio_inc(struct iowait *wait)
}
/**
- * iowait_sdma_dec - note pio complete
+ * iowait_pio_dec - note pio complete
* @wait: iowait structure
*/
static inline int iowait_pio_dec(struct iowait *wait)
{
+ if (!wait)
+ return 0;
return atomic_dec_and_test(&wait->pio_busy);
}
@@ -293,9 +302,9 @@ static inline void iowait_drain_wakeup(struct iowait *wait)
/**
* iowait_get_txhead() - get packet off of iowait list
*
- * @wait wait struture
+ * @wait iowait_work struture
*/
-static inline struct sdma_txreq *iowait_get_txhead(struct iowait *wait)
+static inline struct sdma_txreq *iowait_get_txhead(struct iowait_work *wait)
{
struct sdma_txreq *tx = NULL;
@@ -309,6 +318,28 @@ static inline struct sdma_txreq *iowait_get_txhead(struct iowait *wait)
return tx;
}
+static inline u16 iowait_get_desc(struct iowait_work *w)
+{
+ u16 num_desc = 0;
+ struct sdma_txreq *tx = NULL;
+
+ if (!list_empty(&w->tx_head)) {
+ tx = list_first_entry(&w->tx_head, struct sdma_txreq,
+ list);
+ num_desc = tx->num_desc;
+ }
+ return num_desc;
+}
+
+static inline u32 iowait_get_all_desc(struct iowait *w)
+{
+ u32 num_desc = 0;
+
+ num_desc = iowait_get_desc(&w->wait[IOWAIT_IB_SE]);
+ num_desc += iowait_get_desc(&w->wait[IOWAIT_TID_SE]);
+ return num_desc;
+}
+
/**
* iowait_queue - Put the iowait on a wait queue
* @pkts_sent: have some packets been sent before queuing?
@@ -372,12 +403,57 @@ static inline void iowait_starve_find_max(struct iowait *w, u8 *max,
}
/**
- * iowait_packet_queued() - determine if a packet is already built
- * @wait: the wait structure
+ * iowait_packet_queued() - determine if a packet is queued
+ * @wait: the iowait_work structure
*/
-static inline bool iowait_packet_queued(struct iowait *wait)
+static inline bool iowait_packet_queued(struct iowait_work *wait)
{
return !list_empty(&wait->tx_head);
}
+/**
+ * inc_wait_count - increment wait counts
+ * @w: the log work struct
+ * @n: the count
+ */
+static inline void iowait_inc_wait_count(struct iowait_work *w, u16 n)
+{
+ if (!w)
+ return;
+ w->iow->tx_count++;
+ w->iow->count += n;
+}
+
+/**
+ * iowait_get_tid_work - return iowait_work for tid SE
+ * @w: the iowait struct
+ */
+static inline struct iowait_work *iowait_get_tid_work(struct iowait *w)
+{
+ return &w->wait[IOWAIT_TID_SE];
+}
+
+/**
+ * iowait_get_ib_work - return iowait_work for ib SE
+ * @w: the iowait struct
+ */
+static inline struct iowait_work *iowait_get_ib_work(struct iowait *w)
+{
+ return &w->wait[IOWAIT_IB_SE];
+}
+
+/**
+ * iowait_ioww_to_iow - return iowait given iowait_work
+ * @w: the iowait_work struct
+ */
+static inline struct iowait *iowait_ioww_to_iow(struct iowait_work *w)
+{
+ if (likely(w))
+ return w->iow;
+ return NULL;
+}
+
+void iowait_cancel_work(struct iowait *w);
+int iowait_set_work_flag(struct iowait_work *w);
+
#endif
diff --git a/drivers/infiniband/hw/hfi1/mad.c b/drivers/infiniband/hw/hfi1/mad.c
index 0307405491e0..88a0cf930136 100644
--- a/drivers/infiniband/hw/hfi1/mad.c
+++ b/drivers/infiniband/hw/hfi1/mad.c
@@ -1,5 +1,5 @@
/*
- * Copyright(c) 2015-2017 Intel Corporation.
+ * Copyright(c) 2015-2018 Intel Corporation.
*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
@@ -4836,7 +4836,7 @@ static int hfi1_process_opa_mad(struct ib_device *ibdev, int mad_flags,
int ret;
int pkey_idx;
int local_mad = 0;
- u32 resp_len = 0;
+ u32 resp_len = in_wc->byte_len - sizeof(*in_grh);
struct hfi1_ibport *ibp = to_iport(ibdev, port);
pkey_idx = hfi1_lookup_pkey_idx(ibp, LIM_MGMT_P_KEY);
diff --git a/drivers/infiniband/hw/hfi1/mmu_rb.c b/drivers/infiniband/hw/hfi1/mmu_rb.c
index e1c7996c018e..475b769e120c 100644
--- a/drivers/infiniband/hw/hfi1/mmu_rb.c
+++ b/drivers/infiniband/hw/hfi1/mmu_rb.c
@@ -77,7 +77,6 @@ static void do_remove(struct mmu_rb_handler *handler,
static void handle_remove(struct work_struct *work);
static const struct mmu_notifier_ops mn_opts = {
- .flags = MMU_INVALIDATE_DOES_NOT_BLOCK,
.invalidate_range_start = mmu_notifier_range_start,
};
diff --git a/drivers/infiniband/hw/hfi1/msix.c b/drivers/infiniband/hw/hfi1/msix.c
new file mode 100644
index 000000000000..d920b165d696
--- /dev/null
+++ b/drivers/infiniband/hw/hfi1/msix.c
@@ -0,0 +1,363 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+/*
+ * Copyright(c) 2018 Intel Corporation.
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * BSD LICENSE
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * - Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "hfi.h"
+#include "affinity.h"
+#include "sdma.h"
+
+/**
+ * msix_initialize() - Calculate, request and configure MSIx IRQs
+ * @dd: valid hfi1 devdata
+ *
+ */
+int msix_initialize(struct hfi1_devdata *dd)
+{
+ u32 total;
+ int ret;
+ struct hfi1_msix_entry *entries;
+
+ /*
+ * MSIx interrupt count:
+ * one for the general, "slow path" interrupt
+ * one per used SDMA engine
+ * one per kernel receive context
+ * one for each VNIC context
+ * ...any new IRQs should be added here.
+ */
+ total = 1 + dd->num_sdma + dd->n_krcv_queues + dd->num_vnic_contexts;
+
+ if (total >= CCE_NUM_MSIX_VECTORS)
+ return -EINVAL;
+
+ ret = pci_alloc_irq_vectors(dd->pcidev, total, total, PCI_IRQ_MSIX);
+ if (ret < 0) {
+ dd_dev_err(dd, "pci_alloc_irq_vectors() failed: %d\n", ret);
+ return ret;
+ }
+
+ entries = kcalloc(total, sizeof(*dd->msix_info.msix_entries),
+ GFP_KERNEL);
+ if (!entries) {
+ pci_free_irq_vectors(dd->pcidev);
+ return -ENOMEM;
+ }
+
+ dd->msix_info.msix_entries = entries;
+ spin_lock_init(&dd->msix_info.msix_lock);
+ bitmap_zero(dd->msix_info.in_use_msix, total);
+ dd->msix_info.max_requested = total;
+ dd_dev_info(dd, "%u MSI-X interrupts allocated\n", total);
+
+ return 0;
+}
+
+/**
+ * msix_request_irq() - Allocate a free MSIx IRQ
+ * @dd: valid devdata
+ * @arg: context information for the IRQ
+ * @handler: IRQ handler
+ * @thread: IRQ thread handler (could be NULL)
+ * @idx: zero base idx if multiple devices are needed
+ * @type: affinty IRQ type
+ *
+ * Allocated an MSIx vector if available, and then create the appropriate
+ * meta data needed to keep track of the pci IRQ request.
+ *
+ * Return:
+ * < 0 Error
+ * >= 0 MSIx vector
+ *
+ */
+static int msix_request_irq(struct hfi1_devdata *dd, void *arg,
+ irq_handler_t handler, irq_handler_t thread,
+ u32 idx, enum irq_type type)
+{
+ unsigned long nr;
+ int irq;
+ int ret;
+ const char *err_info;
+ char name[MAX_NAME_SIZE];
+ struct hfi1_msix_entry *me;
+
+ /* Allocate an MSIx vector */
+ spin_lock(&dd->msix_info.msix_lock);
+ nr = find_first_zero_bit(dd->msix_info.in_use_msix,
+ dd->msix_info.max_requested);
+ if (nr < dd->msix_info.max_requested)
+ __set_bit(nr, dd->msix_info.in_use_msix);
+ spin_unlock(&dd->msix_info.msix_lock);
+
+ if (nr == dd->msix_info.max_requested)
+ return -ENOSPC;
+
+ /* Specific verification and determine the name */
+ switch (type) {
+ case IRQ_GENERAL:
+ /* general interrupt must be MSIx vector 0 */
+ if (nr) {
+ spin_lock(&dd->msix_info.msix_lock);
+ __clear_bit(nr, dd->msix_info.in_use_msix);
+ spin_unlock(&dd->msix_info.msix_lock);
+ dd_dev_err(dd, "Invalid index %lu for GENERAL IRQ\n",
+ nr);
+ return -EINVAL;
+ }
+ snprintf(name, sizeof(name), DRIVER_NAME "_%d", dd->unit);
+ err_info = "general";
+ break;
+ case IRQ_SDMA:
+ snprintf(name, sizeof(name), DRIVER_NAME "_%d sdma%d",
+ dd->unit, idx);
+ err_info = "sdma";
+ break;
+ case IRQ_RCVCTXT:
+ snprintf(name, sizeof(name), DRIVER_NAME "_%d kctxt%d",
+ dd->unit, idx);
+ err_info = "receive context";
+ break;
+ case IRQ_OTHER:
+ default:
+ return -EINVAL;
+ }
+ name[sizeof(name) - 1] = 0;
+
+ irq = pci_irq_vector(dd->pcidev, nr);
+ ret = pci_request_irq(dd->pcidev, nr, handler, thread, arg, name);
+ if (ret) {
+ dd_dev_err(dd,
+ "%s: request for IRQ %d failed, MSIx %d, err %d\n",
+ err_info, irq, idx, ret);
+ spin_lock(&dd->msix_info.msix_lock);
+ __clear_bit(nr, dd->msix_info.in_use_msix);
+ spin_unlock(&dd->msix_info.msix_lock);
+ return ret;
+ }
+
+ /*
+ * assign arg after pci_request_irq call, so it will be
+ * cleaned up
+ */
+ me = &dd->msix_info.msix_entries[nr];
+ me->irq = irq;
+ me->arg = arg;
+ me->type = type;
+
+ /* This is a request, so a failure is not fatal */
+ ret = hfi1_get_irq_affinity(dd, me);
+ if (ret)
+ dd_dev_err(dd, "unable to pin IRQ %d\n", ret);
+
+ return nr;
+}
+
+/**
+ * msix_request_rcd_irq() - Helper function for RCVAVAIL IRQs
+ * @rcd: valid rcd context
+ *
+ */
+int msix_request_rcd_irq(struct hfi1_ctxtdata *rcd)
+{
+ int nr;
+
+ nr = msix_request_irq(rcd->dd, rcd, receive_context_interrupt,
+ receive_context_thread, rcd->ctxt, IRQ_RCVCTXT);
+ if (nr < 0)
+ return nr;
+
+ /*
+ * Set the interrupt register and mask for this
+ * context's interrupt.
+ */
+ rcd->ireg = (IS_RCVAVAIL_START + rcd->ctxt) / 64;
+ rcd->imask = ((u64)1) << ((IS_RCVAVAIL_START + rcd->ctxt) % 64);
+ rcd->msix_intr = nr;
+ remap_intr(rcd->dd, IS_RCVAVAIL_START + rcd->ctxt, nr);
+
+ return 0;
+}
+
+/**
+ * msix_request_smda_ira() - Helper for getting SDMA IRQ resources
+ * @sde: valid sdma engine
+ *
+ */
+int msix_request_sdma_irq(struct sdma_engine *sde)
+{
+ int nr;
+
+ nr = msix_request_irq(sde->dd, sde, sdma_interrupt, NULL,
+ sde->this_idx, IRQ_SDMA);
+ if (nr < 0)
+ return nr;
+ sde->msix_intr = nr;
+ remap_sdma_interrupts(sde->dd, sde->this_idx, nr);
+
+ return 0;
+}
+
+/**
+ * enable_sdma_src() - Helper to enable SDMA IRQ srcs
+ * @dd: valid devdata structure
+ * @i: index of SDMA engine
+ */
+static void enable_sdma_srcs(struct hfi1_devdata *dd, int i)
+{
+ set_intr_bits(dd, IS_SDMA_START + i, IS_SDMA_START + i, true);
+ set_intr_bits(dd, IS_SDMA_PROGRESS_START + i,
+ IS_SDMA_PROGRESS_START + i, true);
+ set_intr_bits(dd, IS_SDMA_IDLE_START + i, IS_SDMA_IDLE_START + i, true);
+ set_intr_bits(dd, IS_SDMAENG_ERR_START + i, IS_SDMAENG_ERR_START + i,
+ true);
+}
+
+/**
+ * msix_request_irqs() - Allocate all MSIx IRQs
+ * @dd: valid devdata structure
+ *
+ * Helper function to request the used MSIx IRQs.
+ *
+ */
+int msix_request_irqs(struct hfi1_devdata *dd)
+{
+ int i;
+ int ret;
+
+ ret = msix_request_irq(dd, dd, general_interrupt, NULL, 0, IRQ_GENERAL);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < dd->num_sdma; i++) {
+ struct sdma_engine *sde = &dd->per_sdma[i];
+
+ ret = msix_request_sdma_irq(sde);
+ if (ret)
+ return ret;
+ enable_sdma_srcs(sde->dd, i);
+ }
+
+ for (i = 0; i < dd->n_krcv_queues; i++) {
+ struct hfi1_ctxtdata *rcd = hfi1_rcd_get_by_index_safe(dd, i);
+
+ if (rcd)
+ ret = msix_request_rcd_irq(rcd);
+ hfi1_rcd_put(rcd);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * msix_free_irq() - Free the specified MSIx resources and IRQ
+ * @dd: valid devdata
+ * @msix_intr: MSIx vector to free.
+ *
+ */
+void msix_free_irq(struct hfi1_devdata *dd, u8 msix_intr)
+{
+ struct hfi1_msix_entry *me;
+
+ if (msix_intr >= dd->msix_info.max_requested)
+ return;
+
+ me = &dd->msix_info.msix_entries[msix_intr];
+
+ if (!me->arg) /* => no irq, no affinity */
+ return;
+
+ hfi1_put_irq_affinity(dd, me);
+ pci_free_irq(dd->pcidev, msix_intr, me->arg);
+
+ me->arg = NULL;
+
+ spin_lock(&dd->msix_info.msix_lock);
+ __clear_bit(msix_intr, dd->msix_info.in_use_msix);
+ spin_unlock(&dd->msix_info.msix_lock);
+}
+
+/**
+ * hfi1_clean_up_msix_interrupts() - Free all MSIx IRQ resources
+ * @dd: valid device data data structure
+ *
+ * Free the MSIx and associated PCI resources, if they have been allocated.
+ */
+void msix_clean_up_interrupts(struct hfi1_devdata *dd)
+{
+ int i;
+ struct hfi1_msix_entry *me = dd->msix_info.msix_entries;
+
+ /* remove irqs - must happen before disabling/turning off */
+ for (i = 0; i < dd->msix_info.max_requested; i++, me++)
+ msix_free_irq(dd, i);
+
+ /* clean structures */
+ kfree(dd->msix_info.msix_entries);
+ dd->msix_info.msix_entries = NULL;
+ dd->msix_info.max_requested = 0;
+
+ pci_free_irq_vectors(dd->pcidev);
+}
+
+/**
+ * msix_vnic_syncrhonize_irq() - Vnic IRQ synchronize
+ * @dd: valid devdata
+ */
+void msix_vnic_synchronize_irq(struct hfi1_devdata *dd)
+{
+ int i;
+
+ for (i = 0; i < dd->vnic.num_ctxt; i++) {
+ struct hfi1_ctxtdata *rcd = dd->vnic.ctxt[i];
+ struct hfi1_msix_entry *me;
+
+ me = &dd->msix_info.msix_entries[rcd->msix_intr];
+
+ synchronize_irq(me->irq);
+ }
+}
diff --git a/drivers/infiniband/hw/hfi1/msix.h b/drivers/infiniband/hw/hfi1/msix.h
new file mode 100644
index 000000000000..a514881632a4
--- /dev/null
+++ b/drivers/infiniband/hw/hfi1/msix.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/*
+ * Copyright(c) 2018 Intel Corporation.
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * BSD LICENSE
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * - Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef _HFI1_MSIX_H
+#define _HFI1_MSIX_H
+
+#include "hfi.h"
+
+/* MSIx interface */
+int msix_initialize(struct hfi1_devdata *dd);
+int msix_request_irqs(struct hfi1_devdata *dd);
+void msix_clean_up_interrupts(struct hfi1_devdata *dd);
+int msix_request_rcd_irq(struct hfi1_ctxtdata *rcd);
+int msix_request_sdma_irq(struct sdma_engine *sde);
+void msix_free_irq(struct hfi1_devdata *dd, u8 msix_intr);
+
+/* VNIC interface */
+void msix_vnic_synchronize_irq(struct hfi1_devdata *dd);
+
+#endif
diff --git a/drivers/infiniband/hw/hfi1/pcie.c b/drivers/infiniband/hw/hfi1/pcie.c
index 6c967dde58e7..c96d193bb236 100644
--- a/drivers/infiniband/hw/hfi1/pcie.c
+++ b/drivers/infiniband/hw/hfi1/pcie.c
@@ -1,5 +1,5 @@
/*
- * Copyright(c) 2015 - 2017 Intel Corporation.
+ * Copyright(c) 2015 - 2018 Intel Corporation.
*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
@@ -61,19 +61,12 @@
*/
/*
- * Code to adjust PCIe capabilities.
- */
-static void tune_pcie_caps(struct hfi1_devdata *);
-
-/*
* Do all the common PCIe setup and initialization.
- * devdata is not yet allocated, and is not allocated until after this
- * routine returns success. Therefore dd_dev_err() can't be used for error
- * printing.
*/
-int hfi1_pcie_init(struct pci_dev *pdev, const struct pci_device_id *ent)
+int hfi1_pcie_init(struct hfi1_devdata *dd)
{
int ret;
+ struct pci_dev *pdev = dd->pcidev;
ret = pci_enable_device(pdev);
if (ret) {
@@ -89,15 +82,13 @@ int hfi1_pcie_init(struct pci_dev *pdev, const struct pci_device_id *ent)
* about that, it appears. If the original BAR was retained
* in the kernel data structures, this may be OK.
*/
- hfi1_early_err(&pdev->dev, "pci enable failed: error %d\n",
- -ret);
- goto done;
+ dd_dev_err(dd, "pci enable failed: error %d\n", -ret);
+ return ret;
}
ret = pci_request_regions(pdev, DRIVER_NAME);
if (ret) {
- hfi1_early_err(&pdev->dev,
- "pci_request_regions fails: err %d\n", -ret);
+ dd_dev_err(dd, "pci_request_regions fails: err %d\n", -ret);
goto bail;
}
@@ -110,8 +101,7 @@ int hfi1_pcie_init(struct pci_dev *pdev, const struct pci_device_id *ent)
*/
ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (ret) {
- hfi1_early_err(&pdev->dev,
- "Unable to set DMA mask: %d\n", ret);
+ dd_dev_err(dd, "Unable to set DMA mask: %d\n", ret);
goto bail;
}
ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
@@ -119,18 +109,16 @@ int hfi1_pcie_init(struct pci_dev *pdev, const struct pci_device_id *ent)
ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
}
if (ret) {
- hfi1_early_err(&pdev->dev,
- "Unable to set DMA consistent mask: %d\n", ret);
+ dd_dev_err(dd, "Unable to set DMA consistent mask: %d\n", ret);
goto bail;
}
pci_set_master(pdev);
(void)pci_enable_pcie_error_reporting(pdev);
- goto done;
+ return 0;
bail:
hfi1_pcie_cleanup(pdev);
-done:
return ret;
}
@@ -206,7 +194,7 @@ int hfi1_pcie_ddinit(struct hfi1_devdata *dd, struct pci_dev *pdev)
dd_dev_err(dd, "WC mapping of send buffers failed\n");
goto nomem;
}
- dd_dev_info(dd, "WC piobase: %p\n for %x", dd->piobase, TXE_PIO_SIZE);
+ dd_dev_info(dd, "WC piobase: %p for %x\n", dd->piobase, TXE_PIO_SIZE);
dd->physaddr = addr; /* used for io_remap, etc. */
@@ -344,26 +332,6 @@ int pcie_speeds(struct hfi1_devdata *dd)
return 0;
}
-/*
- * Returns:
- * - actual number of interrupts allocated or
- * - error
- */
-int request_msix(struct hfi1_devdata *dd, u32 msireq)
-{
- int nvec;
-
- nvec = pci_alloc_irq_vectors(dd->pcidev, msireq, msireq, PCI_IRQ_MSIX);
- if (nvec < 0) {
- dd_dev_err(dd, "pci_alloc_irq_vectors() failed: %d\n", nvec);
- return nvec;
- }
-
- tune_pcie_caps(dd);
-
- return nvec;
-}
-
/* restore command and BARs after a reset has wiped them out */
int restore_pci_variables(struct hfi1_devdata *dd)
{
@@ -479,14 +447,19 @@ error:
* Check and optionally adjust them to maximize our throughput.
*/
static int hfi1_pcie_caps;
-module_param_named(pcie_caps, hfi1_pcie_caps, int, S_IRUGO);
+module_param_named(pcie_caps, hfi1_pcie_caps, int, 0444);
MODULE_PARM_DESC(pcie_caps, "Max PCIe tuning: Payload (0..3), ReadReq (4..7)");
uint aspm_mode = ASPM_MODE_DISABLED;
-module_param_named(aspm, aspm_mode, uint, S_IRUGO);
+module_param_named(aspm, aspm_mode, uint, 0444);
MODULE_PARM_DESC(aspm, "PCIe ASPM: 0: disable, 1: enable, 2: dynamic");
-static void tune_pcie_caps(struct hfi1_devdata *dd)
+/**
+ * tune_pcie_caps() - Code to adjust PCIe capabilities.
+ * @dd: Valid device data structure
+ *
+ */
+void tune_pcie_caps(struct hfi1_devdata *dd)
{
struct pci_dev *parent;
u16 rc_mpss, rc_mps, ep_mpss, ep_mps;
@@ -650,7 +623,6 @@ pci_resume(struct pci_dev *pdev)
struct hfi1_devdata *dd = pci_get_drvdata(pdev);
dd_dev_info(dd, "HFI1 resume function called\n");
- pci_cleanup_aer_uncorrect_error_status(pdev);
/*
* Running jobs will fail, since it's asynchronous
* unlike sysfs-requested reset. Better than
@@ -1029,6 +1001,7 @@ int do_pcie_gen3_transition(struct hfi1_devdata *dd)
const u8 (*ctle_tunings)[4];
uint static_ctle_mode;
int return_error = 0;
+ u32 target_width;
/* PCIe Gen3 is for the ASIC only */
if (dd->icode != ICODE_RTL_SILICON)
@@ -1068,6 +1041,9 @@ int do_pcie_gen3_transition(struct hfi1_devdata *dd)
return 0;
}
+ /* Previous Gen1/Gen2 bus width */
+ target_width = dd->lbus_width;
+
/*
* Do the Gen3 transition. Steps are those of the PCIe Gen3
* recipe.
@@ -1436,11 +1412,12 @@ retry:
dd_dev_info(dd, "%s: new speed and width: %s\n", __func__,
dd->lbus_info);
- if (dd->lbus_speed != target_speed) { /* not target */
+ if (dd->lbus_speed != target_speed ||
+ dd->lbus_width < target_width) { /* not target */
/* maybe retry */
do_retry = retry_count < pcie_retry;
- dd_dev_err(dd, "PCIe link speed did not switch to Gen%d%s\n",
- pcie_target, do_retry ? ", retrying" : "");
+ dd_dev_err(dd, "PCIe link speed or width did not match target%s\n",
+ do_retry ? ", retrying" : "");
retry_count++;
if (do_retry) {
msleep(100); /* allow time to settle */
diff --git a/drivers/infiniband/hw/hfi1/pio.c b/drivers/infiniband/hw/hfi1/pio.c
index 752057647f09..9ab50d2308dc 100644
--- a/drivers/infiniband/hw/hfi1/pio.c
+++ b/drivers/infiniband/hw/hfi1/pio.c
@@ -71,14 +71,6 @@ void __cm_reset(struct hfi1_devdata *dd, u64 sendctrl)
}
}
-/* defined in header release 48 and higher */
-#ifndef SEND_CTRL_UNSUPPORTED_VL_SHIFT
-#define SEND_CTRL_UNSUPPORTED_VL_SHIFT 3
-#define SEND_CTRL_UNSUPPORTED_VL_MASK 0xffull
-#define SEND_CTRL_UNSUPPORTED_VL_SMASK (SEND_CTRL_UNSUPPORTED_VL_MASK \
- << SEND_CTRL_UNSUPPORTED_VL_SHIFT)
-#endif
-
/* global control of PIO send */
void pio_send_control(struct hfi1_devdata *dd, int op)
{
diff --git a/drivers/infiniband/hw/hfi1/qp.c b/drivers/infiniband/hw/hfi1/qp.c
index 9b1e84a6b1cc..6f3bc4dab858 100644
--- a/drivers/infiniband/hw/hfi1/qp.c
+++ b/drivers/infiniband/hw/hfi1/qp.c
@@ -66,7 +66,7 @@ MODULE_PARM_DESC(qp_table_size, "QP table size");
static void flush_tx_list(struct rvt_qp *qp);
static int iowait_sleep(
struct sdma_engine *sde,
- struct iowait *wait,
+ struct iowait_work *wait,
struct sdma_txreq *stx,
unsigned int seq,
bool pkts_sent);
@@ -134,15 +134,13 @@ const struct rvt_operation_params hfi1_post_parms[RVT_OPERATION_MAX] = {
};
-static void flush_tx_list(struct rvt_qp *qp)
+static void flush_list_head(struct list_head *l)
{
- struct hfi1_qp_priv *priv = qp->priv;
-
- while (!list_empty(&priv->s_iowait.tx_head)) {
+ while (!list_empty(l)) {
struct sdma_txreq *tx;
tx = list_first_entry(
- &priv->s_iowait.tx_head,
+ l,
struct sdma_txreq,
list);
list_del_init(&tx->list);
@@ -151,6 +149,14 @@ static void flush_tx_list(struct rvt_qp *qp)
}
}
+static void flush_tx_list(struct rvt_qp *qp)
+{
+ struct hfi1_qp_priv *priv = qp->priv;
+
+ flush_list_head(&iowait_get_ib_work(&priv->s_iowait)->tx_head);
+ flush_list_head(&iowait_get_tid_work(&priv->s_iowait)->tx_head);
+}
+
static void flush_iowait(struct rvt_qp *qp)
{
struct hfi1_qp_priv *priv = qp->priv;
@@ -282,33 +288,46 @@ void hfi1_modify_qp(struct rvt_qp *qp, struct ib_qp_attr *attr,
}
/**
- * hfi1_check_send_wqe - validate wqe
+ * hfi1_setup_wqe - set up the wqe
* @qp - The qp
* @wqe - The built wqe
+ * @call_send - Determine if the send should be posted or scheduled.
*
- * validate wqe. This is called
- * prior to inserting the wqe into
- * the ring but after the wqe has been
- * setup.
+ * Perform setup of the wqe. This is called
+ * prior to inserting the wqe into the ring but after
+ * the wqe has been setup by RDMAVT. This function
+ * allows the driver the opportunity to perform
+ * validation and additional setup of the wqe.
*
* Returns 0 on success, -EINVAL on failure
*
*/
-int hfi1_check_send_wqe(struct rvt_qp *qp,
- struct rvt_swqe *wqe)
+int hfi1_setup_wqe(struct rvt_qp *qp, struct rvt_swqe *wqe, bool *call_send)
{
struct hfi1_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num);
struct rvt_ah *ah;
+ struct hfi1_pportdata *ppd;
+ struct hfi1_devdata *dd;
switch (qp->ibqp.qp_type) {
case IB_QPT_RC:
case IB_QPT_UC:
if (wqe->length > 0x80000000U)
return -EINVAL;
+ if (wqe->length > qp->pmtu)
+ *call_send = false;
break;
case IB_QPT_SMI:
- ah = ibah_to_rvtah(wqe->ud_wr.ah);
- if (wqe->length > (1 << ah->log_pmtu))
+ /*
+ * SM packets should exclusively use VL15 and their SL is
+ * ignored (IBTA v1.3, Section 3.5.8.2). Therefore, when ah
+ * is created, SL is 0 in most cases and as a result some
+ * fields (vl and pmtu) in ah may not be set correctly,
+ * depending on the SL2SC and SC2VL tables at the time.
+ */
+ ppd = ppd_from_ibp(ibp);
+ dd = dd_from_ppd(ppd);
+ if (wqe->length > dd->vld[15].mtu)
return -EINVAL;
break;
case IB_QPT_GSI:
@@ -321,7 +340,7 @@ int hfi1_check_send_wqe(struct rvt_qp *qp,
default:
break;
}
- return wqe->length <= piothreshold;
+ return 0;
}
/**
@@ -333,7 +352,7 @@ int hfi1_check_send_wqe(struct rvt_qp *qp,
* It is only used in the post send, which doesn't hold
* the s_lock.
*/
-void _hfi1_schedule_send(struct rvt_qp *qp)
+bool _hfi1_schedule_send(struct rvt_qp *qp)
{
struct hfi1_qp_priv *priv = qp->priv;
struct hfi1_ibport *ibp =
@@ -341,10 +360,10 @@ void _hfi1_schedule_send(struct rvt_qp *qp)
struct hfi1_pportdata *ppd = ppd_from_ibp(ibp);
struct hfi1_devdata *dd = dd_from_ibdev(qp->ibqp.device);
- iowait_schedule(&priv->s_iowait, ppd->hfi1_wq,
- priv->s_sde ?
- priv->s_sde->cpu :
- cpumask_first(cpumask_of_node(dd->node)));
+ return iowait_schedule(&priv->s_iowait, ppd->hfi1_wq,
+ priv->s_sde ?
+ priv->s_sde->cpu :
+ cpumask_first(cpumask_of_node(dd->node)));
}
static void qp_pio_drain(struct rvt_qp *qp)
@@ -372,12 +391,32 @@ static void qp_pio_drain(struct rvt_qp *qp)
*
* This schedules qp progress and caller should hold
* the s_lock.
+ * @return true if the first leg is scheduled;
+ * false if the first leg is not scheduled.
*/
-void hfi1_schedule_send(struct rvt_qp *qp)
+bool hfi1_schedule_send(struct rvt_qp *qp)
{
lockdep_assert_held(&qp->s_lock);
- if (hfi1_send_ok(qp))
+ if (hfi1_send_ok(qp)) {
_hfi1_schedule_send(qp);
+ return true;
+ }
+ if (qp->s_flags & HFI1_S_ANY_WAIT_IO)
+ iowait_set_flag(&((struct hfi1_qp_priv *)qp->priv)->s_iowait,
+ IOWAIT_PENDING_IB);
+ return false;
+}
+
+static void hfi1_qp_schedule(struct rvt_qp *qp)
+{
+ struct hfi1_qp_priv *priv = qp->priv;
+ bool ret;
+
+ if (iowait_flag_set(&priv->s_iowait, IOWAIT_PENDING_IB)) {
+ ret = hfi1_schedule_send(qp);
+ if (ret)
+ iowait_clear_flag(&priv->s_iowait, IOWAIT_PENDING_IB);
+ }
}
void hfi1_qp_wakeup(struct rvt_qp *qp, u32 flag)
@@ -388,16 +427,22 @@ void hfi1_qp_wakeup(struct rvt_qp *qp, u32 flag)
if (qp->s_flags & flag) {
qp->s_flags &= ~flag;
trace_hfi1_qpwakeup(qp, flag);
- hfi1_schedule_send(qp);
+ hfi1_qp_schedule(qp);
}
spin_unlock_irqrestore(&qp->s_lock, flags);
/* Notify hfi1_destroy_qp() if it is waiting. */
rvt_put_qp(qp);
}
+void hfi1_qp_unbusy(struct rvt_qp *qp, struct iowait_work *wait)
+{
+ if (iowait_set_work_flag(wait) == IOWAIT_IB_SE)
+ qp->s_flags &= ~RVT_S_BUSY;
+}
+
static int iowait_sleep(
struct sdma_engine *sde,
- struct iowait *wait,
+ struct iowait_work *wait,
struct sdma_txreq *stx,
uint seq,
bool pkts_sent)
@@ -438,7 +483,7 @@ static int iowait_sleep(
rvt_get_qp(qp);
}
write_sequnlock(&dev->iowait_lock);
- qp->s_flags &= ~RVT_S_BUSY;
+ hfi1_qp_unbusy(qp, wait);
spin_unlock_irqrestore(&qp->s_lock, flags);
ret = -EBUSY;
} else {
@@ -637,6 +682,7 @@ void *qp_priv_alloc(struct rvt_dev_info *rdi, struct rvt_qp *qp)
&priv->s_iowait,
1,
_hfi1_do_send,
+ NULL,
iowait_sleep,
iowait_wakeup,
iowait_sdma_drained);
@@ -686,7 +732,7 @@ void stop_send_queue(struct rvt_qp *qp)
{
struct hfi1_qp_priv *priv = qp->priv;
- cancel_work_sync(&priv->s_iowait.iowork);
+ iowait_cancel_work(&priv->s_iowait);
}
void quiesce_qp(struct rvt_qp *qp)
diff --git a/drivers/infiniband/hw/hfi1/qp.h b/drivers/infiniband/hw/hfi1/qp.h
index 078cff7560b6..7adb6dff6813 100644
--- a/drivers/infiniband/hw/hfi1/qp.h
+++ b/drivers/infiniband/hw/hfi1/qp.h
@@ -58,18 +58,6 @@ extern unsigned int hfi1_qp_table_size;
extern const struct rvt_operation_params hfi1_post_parms[];
/*
- * Send if not busy or waiting for I/O and either
- * a RC response is pending or we can process send work requests.
- */
-static inline int hfi1_send_ok(struct rvt_qp *qp)
-{
- return !(qp->s_flags & (RVT_S_BUSY | RVT_S_ANY_WAIT_IO)) &&
- (verbs_txreq_queued(qp) ||
- (qp->s_flags & RVT_S_RESP_PENDING) ||
- !(qp->s_flags & RVT_S_ANY_WAIT_SEND));
-}
-
-/*
* Driver specific s_flags starting at bit 31 down to HFI1_S_MIN_BIT_MASK
*
* HFI1_S_AHG_VALID - ahg header valid on chip
@@ -90,6 +78,20 @@ static inline int hfi1_send_ok(struct rvt_qp *qp)
#define HFI1_S_ANY_WAIT (HFI1_S_ANY_WAIT_IO | RVT_S_ANY_WAIT_SEND)
/*
+ * Send if not busy or waiting for I/O and either
+ * a RC response is pending or we can process send work requests.
+ */
+static inline int hfi1_send_ok(struct rvt_qp *qp)
+{
+ struct hfi1_qp_priv *priv = qp->priv;
+
+ return !(qp->s_flags & (RVT_S_BUSY | HFI1_S_ANY_WAIT_IO)) &&
+ (verbs_txreq_queued(iowait_get_ib_work(&priv->s_iowait)) ||
+ (qp->s_flags & RVT_S_RESP_PENDING) ||
+ !(qp->s_flags & RVT_S_ANY_WAIT_SEND));
+}
+
+/*
* free_ahg - clear ahg from QP
*/
static inline void clear_ahg(struct rvt_qp *qp)
@@ -129,8 +131,8 @@ struct send_context *qp_to_send_context(struct rvt_qp *qp, u8 sc5);
void qp_iter_print(struct seq_file *s, struct rvt_qp_iter *iter);
-void _hfi1_schedule_send(struct rvt_qp *qp);
-void hfi1_schedule_send(struct rvt_qp *qp);
+bool _hfi1_schedule_send(struct rvt_qp *qp);
+bool hfi1_schedule_send(struct rvt_qp *qp);
void hfi1_migrate_qp(struct rvt_qp *qp);
@@ -150,4 +152,5 @@ void quiesce_qp(struct rvt_qp *qp);
u32 mtu_from_qp(struct rvt_dev_info *rdi, struct rvt_qp *qp, u32 pmtu);
int mtu_to_path_mtu(u32 mtu);
void hfi1_error_port_qps(struct hfi1_ibport *ibp, u8 sl);
+void hfi1_qp_unbusy(struct rvt_qp *qp, struct iowait_work *wait);
#endif /* _QP_H */
diff --git a/drivers/infiniband/hw/hfi1/rc.c b/drivers/infiniband/hw/hfi1/rc.c
index 9bd63abb2dfe..188aa4f686a0 100644
--- a/drivers/infiniband/hw/hfi1/rc.c
+++ b/drivers/infiniband/hw/hfi1/rc.c
@@ -309,7 +309,7 @@ int hfi1_make_rc_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps)
}
clear_ahg(qp);
wqe = rvt_get_swqe_ptr(qp, qp->s_last);
- hfi1_send_complete(qp, wqe, qp->s_last != qp->s_acked ?
+ rvt_send_complete(qp, wqe, qp->s_last != qp->s_acked ?
IB_WC_SUCCESS : IB_WC_WR_FLUSH_ERR);
/* will get called again */
goto done_free_tx;
@@ -378,9 +378,9 @@ int hfi1_make_rc_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps)
wqe->wr.ex.invalidate_rkey);
local_ops = 1;
}
- hfi1_send_complete(qp, wqe,
- err ? IB_WC_LOC_PROT_ERR
- : IB_WC_SUCCESS);
+ rvt_send_complete(qp, wqe,
+ err ? IB_WC_LOC_PROT_ERR
+ : IB_WC_SUCCESS);
if (local_ops)
atomic_dec(&qp->local_ops_pending);
goto done_free_tx;
@@ -1043,7 +1043,7 @@ void hfi1_restart_rc(struct rvt_qp *qp, u32 psn, int wait)
hfi1_migrate_qp(qp);
qp->s_retry = qp->s_retry_cnt;
} else if (qp->s_last == qp->s_acked) {
- hfi1_send_complete(qp, wqe, IB_WC_RETRY_EXC_ERR);
+ rvt_send_complete(qp, wqe, IB_WC_RETRY_EXC_ERR);
rvt_error_qp(qp, IB_WC_WR_FLUSH_ERR);
return;
} else { /* need to handle delayed completion */
@@ -1468,7 +1468,7 @@ static int do_rc_ack(struct rvt_qp *qp, u32 aeth, u32 psn, int opcode,
ibp->rvp.n_other_naks++;
class_b:
if (qp->s_last == qp->s_acked) {
- hfi1_send_complete(qp, wqe, status);
+ rvt_send_complete(qp, wqe, status);
rvt_error_qp(qp, IB_WC_WR_FLUSH_ERR);
}
break;
@@ -1644,7 +1644,8 @@ read_middle:
qp->s_rdma_read_len -= pmtu;
update_last_psn(qp, psn);
spin_unlock_irqrestore(&qp->s_lock, flags);
- hfi1_copy_sge(&qp->s_rdma_read_sge, data, pmtu, false, false);
+ rvt_copy_sge(qp, &qp->s_rdma_read_sge,
+ data, pmtu, false, false);
goto bail;
case OP(RDMA_READ_RESPONSE_ONLY):
@@ -1684,7 +1685,8 @@ read_last:
if (unlikely(tlen != qp->s_rdma_read_len))
goto ack_len_err;
aeth = be32_to_cpu(ohdr->u.aeth);
- hfi1_copy_sge(&qp->s_rdma_read_sge, data, tlen, false, false);
+ rvt_copy_sge(qp, &qp->s_rdma_read_sge,
+ data, tlen, false, false);
WARN_ON(qp->s_rdma_read_sge.num_sge);
(void)do_rc_ack(qp, aeth, psn,
OP(RDMA_READ_RESPONSE_LAST), 0, rcd);
@@ -1704,7 +1706,7 @@ ack_len_err:
status = IB_WC_LOC_LEN_ERR;
ack_err:
if (qp->s_last == qp->s_acked) {
- hfi1_send_complete(qp, wqe, status);
+ rvt_send_complete(qp, wqe, status);
rvt_error_qp(qp, IB_WC_WR_FLUSH_ERR);
}
ack_done:
@@ -2144,7 +2146,7 @@ send_middle:
qp->r_rcv_len += pmtu;
if (unlikely(qp->r_rcv_len > qp->r_len))
goto nack_inv;
- hfi1_copy_sge(&qp->r_sge, data, pmtu, true, false);
+ rvt_copy_sge(qp, &qp->r_sge, data, pmtu, true, false);
break;
case OP(RDMA_WRITE_LAST_WITH_IMMEDIATE):
@@ -2200,7 +2202,7 @@ send_last:
wc.byte_len = tlen + qp->r_rcv_len;
if (unlikely(wc.byte_len > qp->r_len))
goto nack_inv;
- hfi1_copy_sge(&qp->r_sge, data, tlen, true, copy_last);
+ rvt_copy_sge(qp, &qp->r_sge, data, tlen, true, copy_last);
rvt_put_ss(&qp->r_sge);
qp->r_msn++;
if (!__test_and_clear_bit(RVT_R_WRID_VALID, &qp->r_aflags))
diff --git a/drivers/infiniband/hw/hfi1/ruc.c b/drivers/infiniband/hw/hfi1/ruc.c
index 5f56f3c1b4c4..7fb317c711df 100644
--- a/drivers/infiniband/hw/hfi1/ruc.c
+++ b/drivers/infiniband/hw/hfi1/ruc.c
@@ -156,333 +156,6 @@ int hfi1_ruc_check_hdr(struct hfi1_ibport *ibp, struct hfi1_packet *packet)
}
/**
- * ruc_loopback - handle UC and RC loopback requests
- * @sqp: the sending QP
- *
- * This is called from hfi1_do_send() to
- * forward a WQE addressed to the same HFI.
- * Note that although we are single threaded due to the send engine, we still
- * have to protect against post_send(). We don't have to worry about
- * receive interrupts since this is a connected protocol and all packets
- * will pass through here.
- */
-static void ruc_loopback(struct rvt_qp *sqp)
-{
- struct hfi1_ibport *ibp = to_iport(sqp->ibqp.device, sqp->port_num);
- struct rvt_qp *qp;
- struct rvt_swqe *wqe;
- struct rvt_sge *sge;
- unsigned long flags;
- struct ib_wc wc;
- u64 sdata;
- atomic64_t *maddr;
- enum ib_wc_status send_status;
- bool release;
- int ret;
- bool copy_last = false;
- int local_ops = 0;
-
- rcu_read_lock();
-
- /*
- * Note that we check the responder QP state after
- * checking the requester's state.
- */
- qp = rvt_lookup_qpn(ib_to_rvt(sqp->ibqp.device), &ibp->rvp,
- sqp->remote_qpn);
-
- spin_lock_irqsave(&sqp->s_lock, flags);
-
- /* Return if we are already busy processing a work request. */
- if ((sqp->s_flags & (RVT_S_BUSY | HFI1_S_ANY_WAIT)) ||
- !(ib_rvt_state_ops[sqp->state] & RVT_PROCESS_OR_FLUSH_SEND))
- goto unlock;
-
- sqp->s_flags |= RVT_S_BUSY;
-
-again:
- if (sqp->s_last == READ_ONCE(sqp->s_head))
- goto clr_busy;
- wqe = rvt_get_swqe_ptr(sqp, sqp->s_last);
-
- /* Return if it is not OK to start a new work request. */
- if (!(ib_rvt_state_ops[sqp->state] & RVT_PROCESS_NEXT_SEND_OK)) {
- if (!(ib_rvt_state_ops[sqp->state] & RVT_FLUSH_SEND))
- goto clr_busy;
- /* We are in the error state, flush the work request. */
- send_status = IB_WC_WR_FLUSH_ERR;
- goto flush_send;
- }
-
- /*
- * We can rely on the entry not changing without the s_lock
- * being held until we update s_last.
- * We increment s_cur to indicate s_last is in progress.
- */
- if (sqp->s_last == sqp->s_cur) {
- if (++sqp->s_cur >= sqp->s_size)
- sqp->s_cur = 0;
- }
- spin_unlock_irqrestore(&sqp->s_lock, flags);
-
- if (!qp || !(ib_rvt_state_ops[qp->state] & RVT_PROCESS_RECV_OK) ||
- qp->ibqp.qp_type != sqp->ibqp.qp_type) {
- ibp->rvp.n_pkt_drops++;
- /*
- * For RC, the requester would timeout and retry so
- * shortcut the timeouts and just signal too many retries.
- */
- if (sqp->ibqp.qp_type == IB_QPT_RC)
- send_status = IB_WC_RETRY_EXC_ERR;
- else
- send_status = IB_WC_SUCCESS;
- goto serr;
- }
-
- memset(&wc, 0, sizeof(wc));
- send_status = IB_WC_SUCCESS;
-
- release = true;
- sqp->s_sge.sge = wqe->sg_list[0];
- sqp->s_sge.sg_list = wqe->sg_list + 1;
- sqp->s_sge.num_sge = wqe->wr.num_sge;
- sqp->s_len = wqe->length;
- switch (wqe->wr.opcode) {
- case IB_WR_REG_MR:
- goto send_comp;
-
- case IB_WR_LOCAL_INV:
- if (!(wqe->wr.send_flags & RVT_SEND_COMPLETION_ONLY)) {
- if (rvt_invalidate_rkey(sqp,
- wqe->wr.ex.invalidate_rkey))
- send_status = IB_WC_LOC_PROT_ERR;
- local_ops = 1;
- }
- goto send_comp;
-
- case IB_WR_SEND_WITH_INV:
- if (!rvt_invalidate_rkey(qp, wqe->wr.ex.invalidate_rkey)) {
- wc.wc_flags = IB_WC_WITH_INVALIDATE;
- wc.ex.invalidate_rkey = wqe->wr.ex.invalidate_rkey;
- }
- goto send;
-
- case IB_WR_SEND_WITH_IMM:
- wc.wc_flags = IB_WC_WITH_IMM;
- wc.ex.imm_data = wqe->wr.ex.imm_data;
- /* FALLTHROUGH */
- case IB_WR_SEND:
-send:
- ret = rvt_get_rwqe(qp, false);
- if (ret < 0)
- goto op_err;
- if (!ret)
- goto rnr_nak;
- break;
-
- case IB_WR_RDMA_WRITE_WITH_IMM:
- if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_WRITE)))
- goto inv_err;
- wc.wc_flags = IB_WC_WITH_IMM;
- wc.ex.imm_data = wqe->wr.ex.imm_data;
- ret = rvt_get_rwqe(qp, true);
- if (ret < 0)
- goto op_err;
- if (!ret)
- goto rnr_nak;
- /* skip copy_last set and qp_access_flags recheck */
- goto do_write;
- case IB_WR_RDMA_WRITE:
- copy_last = rvt_is_user_qp(qp);
- if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_WRITE)))
- goto inv_err;
-do_write:
- if (wqe->length == 0)
- break;
- if (unlikely(!rvt_rkey_ok(qp, &qp->r_sge.sge, wqe->length,
- wqe->rdma_wr.remote_addr,
- wqe->rdma_wr.rkey,
- IB_ACCESS_REMOTE_WRITE)))
- goto acc_err;
- qp->r_sge.sg_list = NULL;
- qp->r_sge.num_sge = 1;
- qp->r_sge.total_len = wqe->length;
- break;
-
- case IB_WR_RDMA_READ:
- if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_READ)))
- goto inv_err;
- if (unlikely(!rvt_rkey_ok(qp, &sqp->s_sge.sge, wqe->length,
- wqe->rdma_wr.remote_addr,
- wqe->rdma_wr.rkey,
- IB_ACCESS_REMOTE_READ)))
- goto acc_err;
- release = false;
- sqp->s_sge.sg_list = NULL;
- sqp->s_sge.num_sge = 1;
- qp->r_sge.sge = wqe->sg_list[0];
- qp->r_sge.sg_list = wqe->sg_list + 1;
- qp->r_sge.num_sge = wqe->wr.num_sge;
- qp->r_sge.total_len = wqe->length;
- break;
-
- case IB_WR_ATOMIC_CMP_AND_SWP:
- case IB_WR_ATOMIC_FETCH_AND_ADD:
- if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_ATOMIC)))
- goto inv_err;
- if (unlikely(!rvt_rkey_ok(qp, &qp->r_sge.sge, sizeof(u64),
- wqe->atomic_wr.remote_addr,
- wqe->atomic_wr.rkey,
- IB_ACCESS_REMOTE_ATOMIC)))
- goto acc_err;
- /* Perform atomic OP and save result. */
- maddr = (atomic64_t *)qp->r_sge.sge.vaddr;
- sdata = wqe->atomic_wr.compare_add;
- *(u64 *)sqp->s_sge.sge.vaddr =
- (wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD) ?
- (u64)atomic64_add_return(sdata, maddr) - sdata :
- (u64)cmpxchg((u64 *)qp->r_sge.sge.vaddr,
- sdata, wqe->atomic_wr.swap);
- rvt_put_mr(qp->r_sge.sge.mr);
- qp->r_sge.num_sge = 0;
- goto send_comp;
-
- default:
- send_status = IB_WC_LOC_QP_OP_ERR;
- goto serr;
- }
-
- sge = &sqp->s_sge.sge;
- while (sqp->s_len) {
- u32 len = sqp->s_len;
-
- if (len > sge->length)
- len = sge->length;
- if (len > sge->sge_length)
- len = sge->sge_length;
- WARN_ON_ONCE(len == 0);
- hfi1_copy_sge(&qp->r_sge, sge->vaddr, len, release, copy_last);
- sge->vaddr += len;
- sge->length -= len;
- sge->sge_length -= len;
- if (sge->sge_length == 0) {
- if (!release)
- rvt_put_mr(sge->mr);
- if (--sqp->s_sge.num_sge)
- *sge = *sqp->s_sge.sg_list++;
- } else if (sge->length == 0 && sge->mr->lkey) {
- if (++sge->n >= RVT_SEGSZ) {
- if (++sge->m >= sge->mr->mapsz)
- break;
- sge->n = 0;
- }
- sge->vaddr =
- sge->mr->map[sge->m]->segs[sge->n].vaddr;
- sge->length =
- sge->mr->map[sge->m]->segs[sge->n].length;
- }
- sqp->s_len -= len;
- }
- if (release)
- rvt_put_ss(&qp->r_sge);
-
- if (!test_and_clear_bit(RVT_R_WRID_VALID, &qp->r_aflags))
- goto send_comp;
-
- if (wqe->wr.opcode == IB_WR_RDMA_WRITE_WITH_IMM)
- wc.opcode = IB_WC_RECV_RDMA_WITH_IMM;
- else
- wc.opcode = IB_WC_RECV;
- wc.wr_id = qp->r_wr_id;
- wc.status = IB_WC_SUCCESS;
- wc.byte_len = wqe->length;
- wc.qp = &qp->ibqp;
- wc.src_qp = qp->remote_qpn;
- wc.slid = rdma_ah_get_dlid(&qp->remote_ah_attr) & U16_MAX;
- wc.sl = rdma_ah_get_sl(&qp->remote_ah_attr);
- wc.port_num = 1;
- /* Signal completion event if the solicited bit is set. */
- rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.recv_cq), &wc,
- wqe->wr.send_flags & IB_SEND_SOLICITED);
-
-send_comp:
- spin_lock_irqsave(&sqp->s_lock, flags);
- ibp->rvp.n_loop_pkts++;
-flush_send:
- sqp->s_rnr_retry = sqp->s_rnr_retry_cnt;
- hfi1_send_complete(sqp, wqe, send_status);
- if (local_ops) {
- atomic_dec(&sqp->local_ops_pending);
- local_ops = 0;
- }
- goto again;
-
-rnr_nak:
- /* Handle RNR NAK */
- if (qp->ibqp.qp_type == IB_QPT_UC)
- goto send_comp;
- ibp->rvp.n_rnr_naks++;
- /*
- * Note: we don't need the s_lock held since the BUSY flag
- * makes this single threaded.
- */
- if (sqp->s_rnr_retry == 0) {
- send_status = IB_WC_RNR_RETRY_EXC_ERR;
- goto serr;
- }
- if (sqp->s_rnr_retry_cnt < 7)
- sqp->s_rnr_retry--;
- spin_lock_irqsave(&sqp->s_lock, flags);
- if (!(ib_rvt_state_ops[sqp->state] & RVT_PROCESS_RECV_OK))
- goto clr_busy;
- rvt_add_rnr_timer(sqp, qp->r_min_rnr_timer <<
- IB_AETH_CREDIT_SHIFT);
- goto clr_busy;
-
-op_err:
- send_status = IB_WC_REM_OP_ERR;
- wc.status = IB_WC_LOC_QP_OP_ERR;
- goto err;
-
-inv_err:
- send_status = IB_WC_REM_INV_REQ_ERR;
- wc.status = IB_WC_LOC_QP_OP_ERR;
- goto err;
-
-acc_err:
- send_status = IB_WC_REM_ACCESS_ERR;
- wc.status = IB_WC_LOC_PROT_ERR;
-err:
- /* responder goes to error state */
- rvt_rc_error(qp, wc.status);
-
-serr:
- spin_lock_irqsave(&sqp->s_lock, flags);
- hfi1_send_complete(sqp, wqe, send_status);
- if (sqp->ibqp.qp_type == IB_QPT_RC) {
- int lastwqe = rvt_error_qp(sqp, IB_WC_WR_FLUSH_ERR);
-
- sqp->s_flags &= ~RVT_S_BUSY;
- spin_unlock_irqrestore(&sqp->s_lock, flags);
- if (lastwqe) {
- struct ib_event ev;
-
- ev.device = sqp->ibqp.device;
- ev.element.qp = &sqp->ibqp;
- ev.event = IB_EVENT_QP_LAST_WQE_REACHED;
- sqp->ibqp.event_handler(&ev, sqp->ibqp.qp_context);
- }
- goto done;
- }
-clr_busy:
- sqp->s_flags &= ~RVT_S_BUSY;
-unlock:
- spin_unlock_irqrestore(&sqp->s_lock, flags);
-done:
- rcu_read_unlock();
-}
-
-/**
* hfi1_make_grh - construct a GRH header
* @ibp: a pointer to the IB port
* @hdr: a pointer to the GRH header being constructed
@@ -825,8 +498,8 @@ void hfi1_do_send_from_rvt(struct rvt_qp *qp)
void _hfi1_do_send(struct work_struct *work)
{
- struct iowait *wait = container_of(work, struct iowait, iowork);
- struct rvt_qp *qp = iowait_to_qp(wait);
+ struct iowait_work *w = container_of(work, struct iowait_work, iowork);
+ struct rvt_qp *qp = iowait_to_qp(w->iow);
hfi1_do_send(qp, true);
}
@@ -850,6 +523,7 @@ void hfi1_do_send(struct rvt_qp *qp, bool in_thread)
ps.ibp = to_iport(qp->ibqp.device, qp->port_num);
ps.ppd = ppd_from_ibp(ps.ibp);
ps.in_thread = in_thread;
+ ps.wait = iowait_get_ib_work(&priv->s_iowait);
trace_hfi1_rc_do_send(qp, in_thread);
@@ -858,7 +532,7 @@ void hfi1_do_send(struct rvt_qp *qp, bool in_thread)
if (!loopback && ((rdma_ah_get_dlid(&qp->remote_ah_attr) &
~((1 << ps.ppd->lmc) - 1)) ==
ps.ppd->lid)) {
- ruc_loopback(qp);
+ rvt_ruc_loopback(qp);
return;
}
make_req = hfi1_make_rc_req;
@@ -868,7 +542,7 @@ void hfi1_do_send(struct rvt_qp *qp, bool in_thread)
if (!loopback && ((rdma_ah_get_dlid(&qp->remote_ah_attr) &
~((1 << ps.ppd->lmc) - 1)) ==
ps.ppd->lid)) {
- ruc_loopback(qp);
+ rvt_ruc_loopback(qp);
return;
}
make_req = hfi1_make_uc_req;
@@ -883,6 +557,8 @@ void hfi1_do_send(struct rvt_qp *qp, bool in_thread)
/* Return if we are already busy processing a work request. */
if (!hfi1_send_ok(qp)) {
+ if (qp->s_flags & HFI1_S_ANY_WAIT_IO)
+ iowait_set_flag(&priv->s_iowait, IOWAIT_PENDING_IB);
spin_unlock_irqrestore(&qp->s_lock, ps.flags);
return;
}
@@ -896,7 +572,7 @@ void hfi1_do_send(struct rvt_qp *qp, bool in_thread)
ps.pkts_sent = false;
/* insure a pre-built packet is handled */
- ps.s_txreq = get_waiting_verbs_txreq(qp);
+ ps.s_txreq = get_waiting_verbs_txreq(ps.wait);
do {
/* Check for a constructed packet to be sent. */
if (ps.s_txreq) {
@@ -907,6 +583,7 @@ void hfi1_do_send(struct rvt_qp *qp, bool in_thread)
*/
if (hfi1_verbs_send(qp, &ps))
return;
+
/* allow other tasks to run */
if (schedule_send_yield(qp, &ps))
return;
@@ -917,44 +594,3 @@ void hfi1_do_send(struct rvt_qp *qp, bool in_thread)
iowait_starve_clear(ps.pkts_sent, &priv->s_iowait);
spin_unlock_irqrestore(&qp->s_lock, ps.flags);
}
-
-/*
- * This should be called with s_lock held.
- */
-void hfi1_send_complete(struct rvt_qp *qp, struct rvt_swqe *wqe,
- enum ib_wc_status status)
-{
- u32 old_last, last;
-
- if (!(ib_rvt_state_ops[qp->state] & RVT_PROCESS_OR_FLUSH_SEND))
- return;
-
- last = qp->s_last;
- old_last = last;
- trace_hfi1_qp_send_completion(qp, wqe, last);
- if (++last >= qp->s_size)
- last = 0;
- trace_hfi1_qp_send_completion(qp, wqe, last);
- qp->s_last = last;
- /* See post_send() */
- barrier();
- rvt_put_swqe(wqe);
- if (qp->ibqp.qp_type == IB_QPT_UD ||
- qp->ibqp.qp_type == IB_QPT_SMI ||
- qp->ibqp.qp_type == IB_QPT_GSI)
- atomic_dec(&ibah_to_rvtah(wqe->ud_wr.ah)->refcount);
-
- rvt_qp_swqe_complete(qp,
- wqe,
- ib_hfi1_wc_opcode[wqe->wr.opcode],
- status);
-
- if (qp->s_acked == old_last)
- qp->s_acked = last;
- if (qp->s_cur == old_last)
- qp->s_cur = last;
- if (qp->s_tail == old_last)
- qp->s_tail = last;
- if (qp->state == IB_QPS_SQD && last == qp->s_cur)
- qp->s_draining = 0;
-}
diff --git a/drivers/infiniband/hw/hfi1/sdma.c b/drivers/infiniband/hw/hfi1/sdma.c
index 88e326d6cc49..891d2386d1ca 100644
--- a/drivers/infiniband/hw/hfi1/sdma.c
+++ b/drivers/infiniband/hw/hfi1/sdma.c
@@ -378,7 +378,7 @@ static inline void complete_tx(struct sdma_engine *sde,
__sdma_txclean(sde->dd, tx);
if (complete)
(*complete)(tx, res);
- if (wait && iowait_sdma_dec(wait))
+ if (iowait_sdma_dec(wait))
iowait_drain_wakeup(wait);
}
@@ -1758,7 +1758,6 @@ static void sdma_desc_avail(struct sdma_engine *sde, uint avail)
struct iowait *wait, *nw;
struct iowait *waits[SDMA_WAIT_BATCH_SIZE];
uint i, n = 0, seq, max_idx = 0;
- struct sdma_txreq *stx;
struct hfi1_ibdev *dev = &sde->dd->verbs_dev;
u8 max_starved_cnt = 0;
@@ -1779,19 +1778,13 @@ static void sdma_desc_avail(struct sdma_engine *sde, uint avail)
nw,
&sde->dmawait,
list) {
- u16 num_desc = 0;
+ u32 num_desc;
if (!wait->wakeup)
continue;
if (n == ARRAY_SIZE(waits))
break;
- if (!list_empty(&wait->tx_head)) {
- stx = list_first_entry(
- &wait->tx_head,
- struct sdma_txreq,
- list);
- num_desc = stx->num_desc;
- }
+ num_desc = iowait_get_all_desc(wait);
if (num_desc > avail)
break;
avail -= num_desc;
@@ -2346,7 +2339,7 @@ static inline u16 submit_tx(struct sdma_engine *sde, struct sdma_txreq *tx)
*/
static int sdma_check_progress(
struct sdma_engine *sde,
- struct iowait *wait,
+ struct iowait_work *wait,
struct sdma_txreq *tx,
bool pkts_sent)
{
@@ -2356,12 +2349,12 @@ static int sdma_check_progress(
if (tx->num_desc <= sde->desc_avail)
return -EAGAIN;
/* pulse the head_lock */
- if (wait && wait->sleep) {
+ if (wait && iowait_ioww_to_iow(wait)->sleep) {
unsigned seq;
seq = raw_seqcount_begin(
(const seqcount_t *)&sde->head_lock.seqcount);
- ret = wait->sleep(sde, wait, tx, seq, pkts_sent);
+ ret = wait->iow->sleep(sde, wait, tx, seq, pkts_sent);
if (ret == -EAGAIN)
sde->desc_avail = sdma_descq_freecnt(sde);
} else {
@@ -2373,7 +2366,7 @@ static int sdma_check_progress(
/**
* sdma_send_txreq() - submit a tx req to ring
* @sde: sdma engine to use
- * @wait: wait structure to use when full (may be NULL)
+ * @wait: SE wait structure to use when full (may be NULL)
* @tx: sdma_txreq to submit
* @pkts_sent: has any packet been sent yet?
*
@@ -2386,7 +2379,7 @@ static int sdma_check_progress(
* -EIOCBQUEUED - tx queued to iowait, -ECOMM bad sdma state
*/
int sdma_send_txreq(struct sdma_engine *sde,
- struct iowait *wait,
+ struct iowait_work *wait,
struct sdma_txreq *tx,
bool pkts_sent)
{
@@ -2397,7 +2390,7 @@ int sdma_send_txreq(struct sdma_engine *sde,
/* user should have supplied entire packet */
if (unlikely(tx->tlen))
return -EINVAL;
- tx->wait = wait;
+ tx->wait = iowait_ioww_to_iow(wait);
spin_lock_irqsave(&sde->tail_lock, flags);
retry:
if (unlikely(!__sdma_running(sde)))
@@ -2406,14 +2399,14 @@ retry:
goto nodesc;
tail = submit_tx(sde, tx);
if (wait)
- iowait_sdma_inc(wait);
+ iowait_sdma_inc(iowait_ioww_to_iow(wait));
sdma_update_tail(sde, tail);
unlock:
spin_unlock_irqrestore(&sde->tail_lock, flags);
return ret;
unlock_noconn:
if (wait)
- iowait_sdma_inc(wait);
+ iowait_sdma_inc(iowait_ioww_to_iow(wait));
tx->next_descq_idx = 0;
#ifdef CONFIG_HFI1_DEBUG_SDMA_ORDER
tx->sn = sde->tail_sn++;
@@ -2422,10 +2415,7 @@ unlock_noconn:
spin_lock(&sde->flushlist_lock);
list_add_tail(&tx->list, &sde->flushlist);
spin_unlock(&sde->flushlist_lock);
- if (wait) {
- wait->tx_count++;
- wait->count += tx->num_desc;
- }
+ iowait_inc_wait_count(wait, tx->num_desc);
schedule_work(&sde->flush_worker);
ret = -ECOMM;
goto unlock;
@@ -2442,9 +2432,9 @@ nodesc:
/**
* sdma_send_txlist() - submit a list of tx req to ring
* @sde: sdma engine to use
- * @wait: wait structure to use when full (may be NULL)
+ * @wait: SE wait structure to use when full (may be NULL)
* @tx_list: list of sdma_txreqs to submit
- * @count: pointer to a u32 which, after return will contain the total number of
+ * @count: pointer to a u16 which, after return will contain the total number of
* sdma_txreqs removed from the tx_list. This will include sdma_txreqs
* whose SDMA descriptors are submitted to the ring and the sdma_txreqs
* which are added to SDMA engine flush list if the SDMA engine state is
@@ -2467,8 +2457,8 @@ nodesc:
* -EINVAL - sdma_txreq incomplete, -EBUSY - no space in ring (wait == NULL)
* -EIOCBQUEUED - tx queued to iowait, -ECOMM bad sdma state
*/
-int sdma_send_txlist(struct sdma_engine *sde, struct iowait *wait,
- struct list_head *tx_list, u32 *count_out)
+int sdma_send_txlist(struct sdma_engine *sde, struct iowait_work *wait,
+ struct list_head *tx_list, u16 *count_out)
{
struct sdma_txreq *tx, *tx_next;
int ret = 0;
@@ -2479,7 +2469,7 @@ int sdma_send_txlist(struct sdma_engine *sde, struct iowait *wait,
spin_lock_irqsave(&sde->tail_lock, flags);
retry:
list_for_each_entry_safe(tx, tx_next, tx_list, list) {
- tx->wait = wait;
+ tx->wait = iowait_ioww_to_iow(wait);
if (unlikely(!__sdma_running(sde)))
goto unlock_noconn;
if (unlikely(tx->num_desc > sde->desc_avail))
@@ -2500,8 +2490,9 @@ retry:
update_tail:
total_count = submit_count + flush_count;
if (wait) {
- iowait_sdma_add(wait, total_count);
- iowait_starve_clear(submit_count > 0, wait);
+ iowait_sdma_add(iowait_ioww_to_iow(wait), total_count);
+ iowait_starve_clear(submit_count > 0,
+ iowait_ioww_to_iow(wait));
}
if (tail != INVALID_TAIL)
sdma_update_tail(sde, tail);
@@ -2511,7 +2502,7 @@ update_tail:
unlock_noconn:
spin_lock(&sde->flushlist_lock);
list_for_each_entry_safe(tx, tx_next, tx_list, list) {
- tx->wait = wait;
+ tx->wait = iowait_ioww_to_iow(wait);
list_del_init(&tx->list);
tx->next_descq_idx = 0;
#ifdef CONFIG_HFI1_DEBUG_SDMA_ORDER
@@ -2520,10 +2511,7 @@ unlock_noconn:
#endif
list_add_tail(&tx->list, &sde->flushlist);
flush_count++;
- if (wait) {
- wait->tx_count++;
- wait->count += tx->num_desc;
- }
+ iowait_inc_wait_count(wait, tx->num_desc);
}
spin_unlock(&sde->flushlist_lock);
schedule_work(&sde->flush_worker);
diff --git a/drivers/infiniband/hw/hfi1/sdma.h b/drivers/infiniband/hw/hfi1/sdma.h
index 46c775f255d1..6dc63d7c5685 100644
--- a/drivers/infiniband/hw/hfi1/sdma.h
+++ b/drivers/infiniband/hw/hfi1/sdma.h
@@ -1,7 +1,7 @@
#ifndef _HFI1_SDMA_H
#define _HFI1_SDMA_H
/*
- * Copyright(c) 2015, 2016 Intel Corporation.
+ * Copyright(c) 2015 - 2018 Intel Corporation.
*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
@@ -62,16 +62,6 @@
/* Hardware limit for SDMA packet size */
#define MAX_SDMA_PKT_SIZE ((16 * 1024) - 1)
-#define SDMA_TXREQ_S_OK 0
-#define SDMA_TXREQ_S_SENDERROR 1
-#define SDMA_TXREQ_S_ABORTED 2
-#define SDMA_TXREQ_S_SHUTDOWN 3
-
-/* flags bits */
-#define SDMA_TXREQ_F_URGENT 0x0001
-#define SDMA_TXREQ_F_AHG_COPY 0x0002
-#define SDMA_TXREQ_F_USE_AHG 0x0004
-
#define SDMA_MAP_NONE 0
#define SDMA_MAP_SINGLE 1
#define SDMA_MAP_PAGE 2
@@ -415,6 +405,7 @@ struct sdma_engine {
struct list_head flushlist;
struct cpumask cpu_mask;
struct kobject kobj;
+ u32 msix_intr;
};
int sdma_init(struct hfi1_devdata *dd, u8 port);
@@ -849,16 +840,16 @@ static inline int sdma_txadd_kvaddr(
dd, SDMA_MAP_SINGLE, tx, addr, len);
}
-struct iowait;
+struct iowait_work;
int sdma_send_txreq(struct sdma_engine *sde,
- struct iowait *wait,
+ struct iowait_work *wait,
struct sdma_txreq *tx,
bool pkts_sent);
int sdma_send_txlist(struct sdma_engine *sde,
- struct iowait *wait,
+ struct iowait_work *wait,
struct list_head *tx_list,
- u32 *count);
+ u16 *count_out);
int sdma_ahg_alloc(struct sdma_engine *sde);
void sdma_ahg_free(struct sdma_engine *sde, int ahg_index);
diff --git a/drivers/infiniband/hw/hfi1/sysfs.c b/drivers/infiniband/hw/hfi1/sysfs.c
index 25e867393463..2be513d4c9da 100644
--- a/drivers/infiniband/hw/hfi1/sysfs.c
+++ b/drivers/infiniband/hw/hfi1/sysfs.c
@@ -494,17 +494,18 @@ static struct kobj_type hfi1_vl2mtu_ktype = {
* Start of per-unit (or driver, in some cases, but replicated
* per unit) functions (these get a device *)
*/
-static ssize_t show_rev(struct device *device, struct device_attribute *attr,
- char *buf)
+static ssize_t hw_rev_show(struct device *device, struct device_attribute *attr,
+ char *buf)
{
struct hfi1_ibdev *dev =
container_of(device, struct hfi1_ibdev, rdi.ibdev.dev);
return sprintf(buf, "%x\n", dd_from_dev(dev)->minrev);
}
+static DEVICE_ATTR_RO(hw_rev);
-static ssize_t show_hfi(struct device *device, struct device_attribute *attr,
- char *buf)
+static ssize_t board_id_show(struct device *device,
+ struct device_attribute *attr, char *buf)
{
struct hfi1_ibdev *dev =
container_of(device, struct hfi1_ibdev, rdi.ibdev.dev);
@@ -517,8 +518,9 @@ static ssize_t show_hfi(struct device *device, struct device_attribute *attr,
ret = scnprintf(buf, PAGE_SIZE, "%s\n", dd->boardname);
return ret;
}
+static DEVICE_ATTR_RO(board_id);
-static ssize_t show_boardversion(struct device *device,
+static ssize_t boardversion_show(struct device *device,
struct device_attribute *attr, char *buf)
{
struct hfi1_ibdev *dev =
@@ -528,8 +530,9 @@ static ssize_t show_boardversion(struct device *device,
/* The string printed here is already newline-terminated. */
return scnprintf(buf, PAGE_SIZE, "%s", dd->boardversion);
}
+static DEVICE_ATTR_RO(boardversion);
-static ssize_t show_nctxts(struct device *device,
+static ssize_t nctxts_show(struct device *device,
struct device_attribute *attr, char *buf)
{
struct hfi1_ibdev *dev =
@@ -546,8 +549,9 @@ static ssize_t show_nctxts(struct device *device,
min(dd->num_user_contexts,
(u32)dd->sc_sizes[SC_USER].count));
}
+static DEVICE_ATTR_RO(nctxts);
-static ssize_t show_nfreectxts(struct device *device,
+static ssize_t nfreectxts_show(struct device *device,
struct device_attribute *attr, char *buf)
{
struct hfi1_ibdev *dev =
@@ -557,8 +561,9 @@ static ssize_t show_nfreectxts(struct device *device,
/* Return the number of free user ports (contexts) available. */
return scnprintf(buf, PAGE_SIZE, "%u\n", dd->freectxts);
}
+static DEVICE_ATTR_RO(nfreectxts);
-static ssize_t show_serial(struct device *device,
+static ssize_t serial_show(struct device *device,
struct device_attribute *attr, char *buf)
{
struct hfi1_ibdev *dev =
@@ -567,8 +572,9 @@ static ssize_t show_serial(struct device *device,
return scnprintf(buf, PAGE_SIZE, "%s", dd->serial);
}
+static DEVICE_ATTR_RO(serial);
-static ssize_t store_chip_reset(struct device *device,
+static ssize_t chip_reset_store(struct device *device,
struct device_attribute *attr, const char *buf,
size_t count)
{
@@ -586,6 +592,7 @@ static ssize_t store_chip_reset(struct device *device,
bail:
return ret < 0 ? ret : count;
}
+static DEVICE_ATTR_WO(chip_reset);
/*
* Convert the reported temperature from an integer (reported in
@@ -598,7 +605,7 @@ bail:
/*
* Dump tempsense values, in decimal, to ease shell-scripts.
*/
-static ssize_t show_tempsense(struct device *device,
+static ssize_t tempsense_show(struct device *device,
struct device_attribute *attr, char *buf)
{
struct hfi1_ibdev *dev =
@@ -622,6 +629,7 @@ static ssize_t show_tempsense(struct device *device,
}
return ret;
}
+static DEVICE_ATTR_RO(tempsense);
/*
* end of per-unit (or driver, in some cases, but replicated
@@ -629,24 +637,20 @@ static ssize_t show_tempsense(struct device *device,
*/
/* start of per-unit file structures and support code */
-static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL);
-static DEVICE_ATTR(board_id, S_IRUGO, show_hfi, NULL);
-static DEVICE_ATTR(nctxts, S_IRUGO, show_nctxts, NULL);
-static DEVICE_ATTR(nfreectxts, S_IRUGO, show_nfreectxts, NULL);
-static DEVICE_ATTR(serial, S_IRUGO, show_serial, NULL);
-static DEVICE_ATTR(boardversion, S_IRUGO, show_boardversion, NULL);
-static DEVICE_ATTR(tempsense, S_IRUGO, show_tempsense, NULL);
-static DEVICE_ATTR(chip_reset, S_IWUSR, NULL, store_chip_reset);
-
-static struct device_attribute *hfi1_attributes[] = {
- &dev_attr_hw_rev,
- &dev_attr_board_id,
- &dev_attr_nctxts,
- &dev_attr_nfreectxts,
- &dev_attr_serial,
- &dev_attr_boardversion,
- &dev_attr_tempsense,
- &dev_attr_chip_reset,
+static struct attribute *hfi1_attributes[] = {
+ &dev_attr_hw_rev.attr,
+ &dev_attr_board_id.attr,
+ &dev_attr_nctxts.attr,
+ &dev_attr_nfreectxts.attr,
+ &dev_attr_serial.attr,
+ &dev_attr_boardversion.attr,
+ &dev_attr_tempsense.attr,
+ &dev_attr_chip_reset.attr,
+ NULL,
+};
+
+const struct attribute_group ib_hfi1_attr_group = {
+ .attrs = hfi1_attributes,
};
int hfi1_create_port_files(struct ib_device *ibdev, u8 port_num,
@@ -832,12 +836,6 @@ int hfi1_verbs_register_sysfs(struct hfi1_devdata *dd)
struct device *class_dev = &dev->dev;
int i, j, ret;
- for (i = 0; i < ARRAY_SIZE(hfi1_attributes); ++i) {
- ret = device_create_file(&dev->dev, hfi1_attributes[i]);
- if (ret)
- goto bail;
- }
-
for (i = 0; i < dd->num_sdma; i++) {
ret = kobject_init_and_add(&dd->per_sdma[i].kobj,
&sde_ktype, &class_dev->kobj,
@@ -855,9 +853,6 @@ int hfi1_verbs_register_sysfs(struct hfi1_devdata *dd)
return 0;
bail:
- for (i = 0; i < ARRAY_SIZE(hfi1_attributes); ++i)
- device_remove_file(&dev->dev, hfi1_attributes[i]);
-
for (i = 0; i < dd->num_sdma; i++)
kobject_del(&dd->per_sdma[i].kobj);
diff --git a/drivers/infiniband/hw/hfi1/trace.h b/drivers/infiniband/hw/hfi1/trace.h
index 8540463ef3f7..84458f1325e1 100644
--- a/drivers/infiniband/hw/hfi1/trace.h
+++ b/drivers/infiniband/hw/hfi1/trace.h
@@ -1,5 +1,5 @@
/*
- * Copyright(c) 2015 - 2017 Intel Corporation.
+ * Copyright(c) 2015 - 2018 Intel Corporation.
*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
@@ -62,3 +62,4 @@ __print_symbolic(etype, \
#include "trace_rx.h"
#include "trace_tx.h"
#include "trace_mmu.h"
+#include "trace_iowait.h"
diff --git a/drivers/infiniband/hw/hfi1/trace_iowait.h b/drivers/infiniband/hw/hfi1/trace_iowait.h
new file mode 100644
index 000000000000..27f4334ece2b
--- /dev/null
+++ b/drivers/infiniband/hw/hfi1/trace_iowait.h
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/*
+ * Copyright(c) 2018 Intel Corporation.
+ *
+ */
+#if !defined(__HFI1_TRACE_IOWAIT_H) || defined(TRACE_HEADER_MULTI_READ)
+#define __HFI1_TRACE_IOWAIT_H
+
+#include <linux/tracepoint.h>
+#include "iowait.h"
+#include "verbs.h"
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM hfi1_iowait
+
+DECLARE_EVENT_CLASS(hfi1_iowait_template,
+ TP_PROTO(struct iowait *wait, u32 flag),
+ TP_ARGS(wait, flag),
+ TP_STRUCT__entry(/* entry */
+ __field(unsigned long, addr)
+ __field(unsigned long, flags)
+ __field(u32, flag)
+ __field(u32, qpn)
+ ),
+ TP_fast_assign(/* assign */
+ __entry->addr = (unsigned long)wait;
+ __entry->flags = wait->flags;
+ __entry->flag = (1 << flag);
+ __entry->qpn = iowait_to_qp(wait)->ibqp.qp_num;
+ ),
+ TP_printk(/* print */
+ "iowait 0x%lx qp %u flags 0x%lx flag 0x%x",
+ __entry->addr,
+ __entry->qpn,
+ __entry->flags,
+ __entry->flag
+ )
+ );
+
+DEFINE_EVENT(hfi1_iowait_template, hfi1_iowait_set,
+ TP_PROTO(struct iowait *wait, u32 flag),
+ TP_ARGS(wait, flag));
+
+DEFINE_EVENT(hfi1_iowait_template, hfi1_iowait_clear,
+ TP_PROTO(struct iowait *wait, u32 flag),
+ TP_ARGS(wait, flag));
+
+#endif /* __HFI1_TRACE_IOWAIT_H */
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_PATH .
+#define TRACE_INCLUDE_FILE trace_iowait
+#include <trace/define_trace.h>
diff --git a/drivers/infiniband/hw/hfi1/uc.c b/drivers/infiniband/hw/hfi1/uc.c
index e254dcec6f64..6aca0c5a7f97 100644
--- a/drivers/infiniband/hw/hfi1/uc.c
+++ b/drivers/infiniband/hw/hfi1/uc.c
@@ -88,7 +88,7 @@ int hfi1_make_uc_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps)
}
clear_ahg(qp);
wqe = rvt_get_swqe_ptr(qp, qp->s_last);
- hfi1_send_complete(qp, wqe, IB_WC_WR_FLUSH_ERR);
+ rvt_send_complete(qp, wqe, IB_WC_WR_FLUSH_ERR);
goto done_free_tx;
}
@@ -140,7 +140,7 @@ int hfi1_make_uc_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps)
qp, wqe->wr.ex.invalidate_rkey);
local_ops = 1;
}
- hfi1_send_complete(qp, wqe, err ? IB_WC_LOC_PROT_ERR
+ rvt_send_complete(qp, wqe, err ? IB_WC_LOC_PROT_ERR
: IB_WC_SUCCESS);
if (local_ops)
atomic_dec(&qp->local_ops_pending);
@@ -426,7 +426,7 @@ send_first:
qp->r_rcv_len += pmtu;
if (unlikely(qp->r_rcv_len > qp->r_len))
goto rewind;
- hfi1_copy_sge(&qp->r_sge, data, pmtu, false, false);
+ rvt_copy_sge(qp, &qp->r_sge, data, pmtu, false, false);
break;
case OP(SEND_LAST_WITH_IMMEDIATE):
@@ -449,7 +449,7 @@ send_last:
if (unlikely(wc.byte_len > qp->r_len))
goto rewind;
wc.opcode = IB_WC_RECV;
- hfi1_copy_sge(&qp->r_sge, data, tlen, false, false);
+ rvt_copy_sge(qp, &qp->r_sge, data, tlen, false, false);
rvt_put_ss(&qp->s_rdma_read_sge);
last_imm:
wc.wr_id = qp->r_wr_id;
@@ -523,7 +523,7 @@ rdma_first:
qp->r_rcv_len += pmtu;
if (unlikely(qp->r_rcv_len > qp->r_len))
goto drop;
- hfi1_copy_sge(&qp->r_sge, data, pmtu, true, false);
+ rvt_copy_sge(qp, &qp->r_sge, data, pmtu, true, false);
break;
case OP(RDMA_WRITE_LAST_WITH_IMMEDIATE):
@@ -550,7 +550,7 @@ rdma_last_imm:
}
wc.byte_len = qp->r_len;
wc.opcode = IB_WC_RECV_RDMA_WITH_IMM;
- hfi1_copy_sge(&qp->r_sge, data, tlen, true, false);
+ rvt_copy_sge(qp, &qp->r_sge, data, tlen, true, false);
rvt_put_ss(&qp->r_sge);
goto last_imm;
@@ -564,7 +564,7 @@ rdma_last:
tlen -= (hdrsize + extra_bytes);
if (unlikely(tlen + qp->r_rcv_len != qp->r_len))
goto drop;
- hfi1_copy_sge(&qp->r_sge, data, tlen, true, false);
+ rvt_copy_sge(qp, &qp->r_sge, data, tlen, true, false);
rvt_put_ss(&qp->r_sge);
break;
diff --git a/drivers/infiniband/hw/hfi1/ud.c b/drivers/infiniband/hw/hfi1/ud.c
index 70d39fc450a1..4baa8f4d49de 100644
--- a/drivers/infiniband/hw/hfi1/ud.c
+++ b/drivers/infiniband/hw/hfi1/ud.c
@@ -210,8 +210,8 @@ static void ud_loopback(struct rvt_qp *sqp, struct rvt_swqe *swqe)
}
hfi1_make_grh(ibp, &grh, &grd, 0, 0);
- hfi1_copy_sge(&qp->r_sge, &grh,
- sizeof(grh), true, false);
+ rvt_copy_sge(qp, &qp->r_sge, &grh,
+ sizeof(grh), true, false);
wc.wc_flags |= IB_WC_GRH;
} else {
rvt_skip_sge(&qp->r_sge, sizeof(struct ib_grh), true);
@@ -228,7 +228,7 @@ static void ud_loopback(struct rvt_qp *sqp, struct rvt_swqe *swqe)
if (len > sge->sge_length)
len = sge->sge_length;
WARN_ON_ONCE(len == 0);
- hfi1_copy_sge(&qp->r_sge, sge->vaddr, len, true, false);
+ rvt_copy_sge(qp, &qp->r_sge, sge->vaddr, len, true, false);
sge->vaddr += len;
sge->length -= len;
sge->sge_length -= len;
@@ -518,7 +518,7 @@ int hfi1_make_ud_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps)
goto bail;
}
wqe = rvt_get_swqe_ptr(qp, qp->s_last);
- hfi1_send_complete(qp, wqe, IB_WC_WR_FLUSH_ERR);
+ rvt_send_complete(qp, wqe, IB_WC_WR_FLUSH_ERR);
goto done_free_tx;
}
@@ -560,7 +560,7 @@ int hfi1_make_ud_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps)
ud_loopback(qp, wqe);
spin_lock_irqsave(&qp->s_lock, tflags);
ps->flags = tflags;
- hfi1_send_complete(qp, wqe, IB_WC_SUCCESS);
+ rvt_send_complete(qp, wqe, IB_WC_SUCCESS);
goto done_free_tx;
}
}
@@ -1019,8 +1019,8 @@ void hfi1_ud_rcv(struct hfi1_packet *packet)
goto drop;
}
if (packet->grh) {
- hfi1_copy_sge(&qp->r_sge, packet->grh,
- sizeof(struct ib_grh), true, false);
+ rvt_copy_sge(qp, &qp->r_sge, packet->grh,
+ sizeof(struct ib_grh), true, false);
wc.wc_flags |= IB_WC_GRH;
} else if (packet->etype == RHF_RCV_TYPE_BYPASS) {
struct ib_grh grh;
@@ -1030,14 +1030,14 @@ void hfi1_ud_rcv(struct hfi1_packet *packet)
* out when creating 16B, add back the GRH here.
*/
hfi1_make_ext_grh(packet, &grh, slid, dlid);
- hfi1_copy_sge(&qp->r_sge, &grh,
- sizeof(struct ib_grh), true, false);
+ rvt_copy_sge(qp, &qp->r_sge, &grh,
+ sizeof(struct ib_grh), true, false);
wc.wc_flags |= IB_WC_GRH;
} else {
rvt_skip_sge(&qp->r_sge, sizeof(struct ib_grh), true);
}
- hfi1_copy_sge(&qp->r_sge, data, wc.byte_len - sizeof(struct ib_grh),
- true, false);
+ rvt_copy_sge(qp, &qp->r_sge, data, wc.byte_len - sizeof(struct ib_grh),
+ true, false);
rvt_put_ss(&qp->r_sge);
if (!test_and_clear_bit(RVT_R_WRID_VALID, &qp->r_aflags))
return;
diff --git a/drivers/infiniband/hw/hfi1/user_sdma.c b/drivers/infiniband/hw/hfi1/user_sdma.c
index 5c88706121c1..3f0aadccd9f6 100644
--- a/drivers/infiniband/hw/hfi1/user_sdma.c
+++ b/drivers/infiniband/hw/hfi1/user_sdma.c
@@ -1,5 +1,5 @@
/*
- * Copyright(c) 2015 - 2017 Intel Corporation.
+ * Copyright(c) 2015 - 2018 Intel Corporation.
*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
@@ -76,8 +76,7 @@ MODULE_PARM_DESC(sdma_comp_size, "Size of User SDMA completion ring. Default: 12
static unsigned initial_pkt_count = 8;
-static int user_sdma_send_pkts(struct user_sdma_request *req,
- unsigned maxpkts);
+static int user_sdma_send_pkts(struct user_sdma_request *req, u16 maxpkts);
static void user_sdma_txreq_cb(struct sdma_txreq *txreq, int status);
static inline void pq_update(struct hfi1_user_sdma_pkt_q *pq);
static void user_sdma_free_request(struct user_sdma_request *req, bool unpin);
@@ -101,7 +100,7 @@ static inline u32 get_lrh_len(struct hfi1_pkt_header, u32 len);
static int defer_packet_queue(
struct sdma_engine *sde,
- struct iowait *wait,
+ struct iowait_work *wait,
struct sdma_txreq *txreq,
uint seq,
bool pkts_sent);
@@ -124,13 +123,13 @@ static struct mmu_rb_ops sdma_rb_ops = {
static int defer_packet_queue(
struct sdma_engine *sde,
- struct iowait *wait,
+ struct iowait_work *wait,
struct sdma_txreq *txreq,
uint seq,
bool pkts_sent)
{
struct hfi1_user_sdma_pkt_q *pq =
- container_of(wait, struct hfi1_user_sdma_pkt_q, busy);
+ container_of(wait->iow, struct hfi1_user_sdma_pkt_q, busy);
struct hfi1_ibdev *dev = &pq->dd->verbs_dev;
struct user_sdma_txreq *tx =
container_of(txreq, struct user_sdma_txreq, txreq);
@@ -187,13 +186,12 @@ int hfi1_user_sdma_alloc_queues(struct hfi1_ctxtdata *uctxt,
pq->ctxt = uctxt->ctxt;
pq->subctxt = fd->subctxt;
pq->n_max_reqs = hfi1_sdma_comp_ring_size;
- pq->state = SDMA_PKT_Q_INACTIVE;
atomic_set(&pq->n_reqs, 0);
init_waitqueue_head(&pq->wait);
atomic_set(&pq->n_locked, 0);
pq->mm = fd->mm;
- iowait_init(&pq->busy, 0, NULL, defer_packet_queue,
+ iowait_init(&pq->busy, 0, NULL, NULL, defer_packet_queue,
activate_packet_queue, NULL);
pq->reqidx = 0;
@@ -276,7 +274,7 @@ int hfi1_user_sdma_free_queues(struct hfi1_filedata *fd,
/* Wait until all requests have been freed. */
wait_event_interruptible(
pq->wait,
- (READ_ONCE(pq->state) == SDMA_PKT_Q_INACTIVE));
+ !atomic_read(&pq->n_reqs));
kfree(pq->reqs);
kfree(pq->req_in_use);
kmem_cache_destroy(pq->txreq_cache);
@@ -312,6 +310,13 @@ static u8 dlid_to_selector(u16 dlid)
return mapping[hash];
}
+/**
+ * hfi1_user_sdma_process_request() - Process and start a user sdma request
+ * @fd: valid file descriptor
+ * @iovec: array of io vectors to process
+ * @dim: overall iovec array size
+ * @count: number of io vector array entries processed
+ */
int hfi1_user_sdma_process_request(struct hfi1_filedata *fd,
struct iovec *iovec, unsigned long dim,
unsigned long *count)
@@ -328,7 +333,6 @@ int hfi1_user_sdma_process_request(struct hfi1_filedata *fd,
u8 opcode, sc, vl;
u16 pkey;
u32 slid;
- int req_queued = 0;
u16 dlid;
u32 selector;
@@ -392,7 +396,6 @@ int hfi1_user_sdma_process_request(struct hfi1_filedata *fd,
req->data_len = 0;
req->pq = pq;
req->cq = cq;
- req->status = -1;
req->ahg_idx = -1;
req->iov_idx = 0;
req->sent = 0;
@@ -400,12 +403,14 @@ int hfi1_user_sdma_process_request(struct hfi1_filedata *fd,
req->seqcomp = 0;
req->seqsubmitted = 0;
req->tids = NULL;
- req->done = 0;
req->has_error = 0;
INIT_LIST_HEAD(&req->txps);
memcpy(&req->info, &info, sizeof(info));
+ /* The request is initialized, count it */
+ atomic_inc(&pq->n_reqs);
+
if (req_opcode(info.ctrl) == EXPECTED) {
/* expected must have a TID info and at least one data vector */
if (req->data_iovs < 2) {
@@ -500,7 +505,6 @@ int hfi1_user_sdma_process_request(struct hfi1_filedata *fd,
ret = pin_vector_pages(req, &req->iovs[i]);
if (ret) {
req->data_iovs = i;
- req->status = ret;
goto free_req;
}
req->data_len += req->iovs[i].iov.iov_len;
@@ -561,23 +565,11 @@ int hfi1_user_sdma_process_request(struct hfi1_filedata *fd,
req->ahg_idx = sdma_ahg_alloc(req->sde);
set_comp_state(pq, cq, info.comp_idx, QUEUED, 0);
- atomic_inc(&pq->n_reqs);
- req_queued = 1;
+ pq->state = SDMA_PKT_Q_ACTIVE;
/* Send the first N packets in the request to buy us some time */
ret = user_sdma_send_pkts(req, pcount);
- if (unlikely(ret < 0 && ret != -EBUSY)) {
- req->status = ret;
+ if (unlikely(ret < 0 && ret != -EBUSY))
goto free_req;
- }
-
- /*
- * It is possible that the SDMA engine would have processed all the
- * submitted packets by the time we get here. Therefore, only set
- * packet queue state to ACTIVE if there are still uncompleted
- * requests.
- */
- if (atomic_read(&pq->n_reqs))
- xchg(&pq->state, SDMA_PKT_Q_ACTIVE);
/*
* This is a somewhat blocking send implementation.
@@ -588,14 +580,8 @@ int hfi1_user_sdma_process_request(struct hfi1_filedata *fd,
while (req->seqsubmitted != req->info.npkts) {
ret = user_sdma_send_pkts(req, pcount);
if (ret < 0) {
- if (ret != -EBUSY) {
- req->status = ret;
- WRITE_ONCE(req->has_error, 1);
- if (READ_ONCE(req->seqcomp) ==
- req->seqsubmitted - 1)
- goto free_req;
- return ret;
- }
+ if (ret != -EBUSY)
+ goto free_req;
wait_event_interruptible_timeout(
pq->busy.wait_dma,
(pq->state == SDMA_PKT_Q_ACTIVE),
@@ -606,10 +592,19 @@ int hfi1_user_sdma_process_request(struct hfi1_filedata *fd,
*count += idx;
return 0;
free_req:
- user_sdma_free_request(req, true);
- if (req_queued)
+ /*
+ * If the submitted seqsubmitted == npkts, the completion routine
+ * controls the final state. If sequbmitted < npkts, wait for any
+ * outstanding packets to finish before cleaning up.
+ */
+ if (req->seqsubmitted < req->info.npkts) {
+ if (req->seqsubmitted)
+ wait_event(pq->busy.wait_dma,
+ (req->seqcomp == req->seqsubmitted - 1));
+ user_sdma_free_request(req, true);
pq_update(pq);
- set_comp_state(pq, cq, info.comp_idx, ERROR, req->status);
+ set_comp_state(pq, cq, info.comp_idx, ERROR, ret);
+ }
return ret;
}
@@ -760,9 +755,10 @@ static int user_sdma_txadd(struct user_sdma_request *req,
return ret;
}
-static int user_sdma_send_pkts(struct user_sdma_request *req, unsigned maxpkts)
+static int user_sdma_send_pkts(struct user_sdma_request *req, u16 maxpkts)
{
- int ret = 0, count;
+ int ret = 0;
+ u16 count;
unsigned npkts = 0;
struct user_sdma_txreq *tx = NULL;
struct hfi1_user_sdma_pkt_q *pq = NULL;
@@ -864,8 +860,10 @@ static int user_sdma_send_pkts(struct user_sdma_request *req, unsigned maxpkts)
changes = set_txreq_header_ahg(req, tx,
datalen);
- if (changes < 0)
+ if (changes < 0) {
+ ret = changes;
goto free_tx;
+ }
}
} else {
ret = sdma_txinit(&tx->txreq, 0, sizeof(req->hdr) +
@@ -914,10 +912,11 @@ static int user_sdma_send_pkts(struct user_sdma_request *req, unsigned maxpkts)
npkts++;
}
dosend:
- ret = sdma_send_txlist(req->sde, &pq->busy, &req->txps, &count);
+ ret = sdma_send_txlist(req->sde,
+ iowait_get_ib_work(&pq->busy),
+ &req->txps, &count);
req->seqsubmitted += count;
if (req->seqsubmitted == req->info.npkts) {
- WRITE_ONCE(req->done, 1);
/*
* The txreq has already been submitted to the HW queue
* so we can free the AHG entry now. Corruption will not
@@ -1365,11 +1364,15 @@ static int set_txreq_header_ahg(struct user_sdma_request *req,
return idx;
}
-/*
- * SDMA tx request completion callback. Called when the SDMA progress
- * state machine gets notification that the SDMA descriptors for this
- * tx request have been processed by the DMA engine. Called in
- * interrupt context.
+/**
+ * user_sdma_txreq_cb() - SDMA tx request completion callback.
+ * @txreq: valid sdma tx request
+ * @status: success/failure of request
+ *
+ * Called when the SDMA progress state machine gets notification that
+ * the SDMA descriptors for this tx request have been processed by the
+ * DMA engine. Called in interrupt context.
+ * Only do work on completed sequences.
*/
static void user_sdma_txreq_cb(struct sdma_txreq *txreq, int status)
{
@@ -1378,7 +1381,7 @@ static void user_sdma_txreq_cb(struct sdma_txreq *txreq, int status)
struct user_sdma_request *req;
struct hfi1_user_sdma_pkt_q *pq;
struct hfi1_user_sdma_comp_q *cq;
- u16 idx;
+ enum hfi1_sdma_comp_state state = COMPLETE;
if (!tx->req)
return;
@@ -1391,39 +1394,25 @@ static void user_sdma_txreq_cb(struct sdma_txreq *txreq, int status)
SDMA_DBG(req, "SDMA completion with error %d",
status);
WRITE_ONCE(req->has_error, 1);
+ state = ERROR;
}
req->seqcomp = tx->seqnum;
kmem_cache_free(pq->txreq_cache, tx);
- tx = NULL;
-
- idx = req->info.comp_idx;
- if (req->status == -1 && status == SDMA_TXREQ_S_OK) {
- if (req->seqcomp == req->info.npkts - 1) {
- req->status = 0;
- user_sdma_free_request(req, false);
- pq_update(pq);
- set_comp_state(pq, cq, idx, COMPLETE, 0);
- }
- } else {
- if (status != SDMA_TXREQ_S_OK)
- req->status = status;
- if (req->seqcomp == (READ_ONCE(req->seqsubmitted) - 1) &&
- (READ_ONCE(req->done) ||
- READ_ONCE(req->has_error))) {
- user_sdma_free_request(req, false);
- pq_update(pq);
- set_comp_state(pq, cq, idx, ERROR, req->status);
- }
- }
+
+ /* sequence isn't complete? We are done */
+ if (req->seqcomp != req->info.npkts - 1)
+ return;
+
+ user_sdma_free_request(req, false);
+ set_comp_state(pq, cq, req->info.comp_idx, state, status);
+ pq_update(pq);
}
static inline void pq_update(struct hfi1_user_sdma_pkt_q *pq)
{
- if (atomic_dec_and_test(&pq->n_reqs)) {
- xchg(&pq->state, SDMA_PKT_Q_INACTIVE);
+ if (atomic_dec_and_test(&pq->n_reqs))
wake_up(&pq->wait);
- }
}
static void user_sdma_free_request(struct user_sdma_request *req, bool unpin)
@@ -1448,6 +1437,8 @@ static void user_sdma_free_request(struct user_sdma_request *req, bool unpin)
if (!node)
continue;
+ req->iovs[i].node = NULL;
+
if (unpin)
hfi1_mmu_rb_remove(req->pq->handler,
&node->rb);
diff --git a/drivers/infiniband/hw/hfi1/user_sdma.h b/drivers/infiniband/hw/hfi1/user_sdma.h
index d2bc77f75253..14dfd757dafd 100644
--- a/drivers/infiniband/hw/hfi1/user_sdma.h
+++ b/drivers/infiniband/hw/hfi1/user_sdma.h
@@ -105,9 +105,10 @@ static inline int ahg_header_set(u32 *arr, int idx, size_t array_size,
#define TXREQ_FLAGS_REQ_ACK BIT(0) /* Set the ACK bit in the header */
#define TXREQ_FLAGS_REQ_DISABLE_SH BIT(1) /* Disable header suppression */
-#define SDMA_PKT_Q_INACTIVE BIT(0)
-#define SDMA_PKT_Q_ACTIVE BIT(1)
-#define SDMA_PKT_Q_DEFERRED BIT(2)
+enum pkt_q_sdma_state {
+ SDMA_PKT_Q_ACTIVE,
+ SDMA_PKT_Q_DEFERRED,
+};
/*
* Maximum retry attempts to submit a TX request
@@ -133,7 +134,7 @@ struct hfi1_user_sdma_pkt_q {
struct user_sdma_request *reqs;
unsigned long *req_in_use;
struct iowait busy;
- unsigned state;
+ enum pkt_q_sdma_state state;
wait_queue_head_t wait;
unsigned long unpinned;
struct mmu_rb_handler *handler;
@@ -203,14 +204,12 @@ struct user_sdma_request {
s8 ahg_idx;
/* Writeable fields shared with interrupt */
- u64 seqcomp ____cacheline_aligned_in_smp;
- u64 seqsubmitted;
- /* status of the last txreq completed */
- int status;
+ u16 seqcomp ____cacheline_aligned_in_smp;
+ u16 seqsubmitted;
/* Send side fields */
struct list_head txps ____cacheline_aligned_in_smp;
- u64 seqnum;
+ u16 seqnum;
/*
* KDETH.OFFSET (TID) field
* The offset can cover multiple packets, depending on the
@@ -228,7 +227,6 @@ struct user_sdma_request {
u16 tididx;
/* progress index moving along the iovs array */
u8 iov_idx;
- u8 done;
u8 has_error;
struct user_sdma_iovec iovs[MAX_VECTORS_PER_REQ];
@@ -248,7 +246,7 @@ struct user_sdma_txreq {
struct user_sdma_request *req;
u16 flags;
unsigned int busycount;
- u64 seqnum;
+ u16 seqnum;
};
int hfi1_user_sdma_alloc_queues(struct hfi1_ctxtdata *uctxt,
diff --git a/drivers/infiniband/hw/hfi1/verbs.c b/drivers/infiniband/hw/hfi1/verbs.c
index a7c586a5589d..48e11e510358 100644
--- a/drivers/infiniband/hw/hfi1/verbs.c
+++ b/drivers/infiniband/hw/hfi1/verbs.c
@@ -129,8 +129,6 @@ unsigned short piothreshold = 256;
module_param(piothreshold, ushort, S_IRUGO);
MODULE_PARM_DESC(piothreshold, "size used to determine sdma vs. pio");
-#define COPY_CACHELESS 1
-#define COPY_ADAPTIVE 2
static unsigned int sge_copy_mode;
module_param(sge_copy_mode, uint, S_IRUGO);
MODULE_PARM_DESC(sge_copy_mode,
@@ -151,159 +149,13 @@ static int pio_wait(struct rvt_qp *qp,
/* 16B trailing buffer */
static const u8 trail_buf[MAX_16B_PADDING];
-static uint wss_threshold;
+static uint wss_threshold = 80;
module_param(wss_threshold, uint, S_IRUGO);
MODULE_PARM_DESC(wss_threshold, "Percentage (1-100) of LLC to use as a threshold for a cacheless copy");
static uint wss_clean_period = 256;
module_param(wss_clean_period, uint, S_IRUGO);
MODULE_PARM_DESC(wss_clean_period, "Count of verbs copies before an entry in the page copy table is cleaned");
-/* memory working set size */
-struct hfi1_wss {
- unsigned long *entries;
- atomic_t total_count;
- atomic_t clean_counter;
- atomic_t clean_entry;
-
- int threshold;
- int num_entries;
- long pages_mask;
-};
-
-static struct hfi1_wss wss;
-
-int hfi1_wss_init(void)
-{
- long llc_size;
- long llc_bits;
- long table_size;
- long table_bits;
-
- /* check for a valid percent range - default to 80 if none or invalid */
- if (wss_threshold < 1 || wss_threshold > 100)
- wss_threshold = 80;
- /* reject a wildly large period */
- if (wss_clean_period > 1000000)
- wss_clean_period = 256;
- /* reject a zero period */
- if (wss_clean_period == 0)
- wss_clean_period = 1;
-
- /*
- * Calculate the table size - the next power of 2 larger than the
- * LLC size. LLC size is in KiB.
- */
- llc_size = wss_llc_size() * 1024;
- table_size = roundup_pow_of_two(llc_size);
-
- /* one bit per page in rounded up table */
- llc_bits = llc_size / PAGE_SIZE;
- table_bits = table_size / PAGE_SIZE;
- wss.pages_mask = table_bits - 1;
- wss.num_entries = table_bits / BITS_PER_LONG;
-
- wss.threshold = (llc_bits * wss_threshold) / 100;
- if (wss.threshold == 0)
- wss.threshold = 1;
-
- atomic_set(&wss.clean_counter, wss_clean_period);
-
- wss.entries = kcalloc(wss.num_entries, sizeof(*wss.entries),
- GFP_KERNEL);
- if (!wss.entries) {
- hfi1_wss_exit();
- return -ENOMEM;
- }
-
- return 0;
-}
-
-void hfi1_wss_exit(void)
-{
- /* coded to handle partially initialized and repeat callers */
- kfree(wss.entries);
- wss.entries = NULL;
-}
-
-/*
- * Advance the clean counter. When the clean period has expired,
- * clean an entry.
- *
- * This is implemented in atomics to avoid locking. Because multiple
- * variables are involved, it can be racy which can lead to slightly
- * inaccurate information. Since this is only a heuristic, this is
- * OK. Any innaccuracies will clean themselves out as the counter
- * advances. That said, it is unlikely the entry clean operation will
- * race - the next possible racer will not start until the next clean
- * period.
- *
- * The clean counter is implemented as a decrement to zero. When zero
- * is reached an entry is cleaned.
- */
-static void wss_advance_clean_counter(void)
-{
- int entry;
- int weight;
- unsigned long bits;
-
- /* become the cleaner if we decrement the counter to zero */
- if (atomic_dec_and_test(&wss.clean_counter)) {
- /*
- * Set, not add, the clean period. This avoids an issue
- * where the counter could decrement below the clean period.
- * Doing a set can result in lost decrements, slowing the
- * clean advance. Since this a heuristic, this possible
- * slowdown is OK.
- *
- * An alternative is to loop, advancing the counter by a
- * clean period until the result is > 0. However, this could
- * lead to several threads keeping another in the clean loop.
- * This could be mitigated by limiting the number of times
- * we stay in the loop.
- */
- atomic_set(&wss.clean_counter, wss_clean_period);
-
- /*
- * Uniquely grab the entry to clean and move to next.
- * The current entry is always the lower bits of
- * wss.clean_entry. The table size, wss.num_entries,
- * is always a power-of-2.
- */
- entry = (atomic_inc_return(&wss.clean_entry) - 1)
- & (wss.num_entries - 1);
-
- /* clear the entry and count the bits */
- bits = xchg(&wss.entries[entry], 0);
- weight = hweight64((u64)bits);
- /* only adjust the contended total count if needed */
- if (weight)
- atomic_sub(weight, &wss.total_count);
- }
-}
-
-/*
- * Insert the given address into the working set array.
- */
-static void wss_insert(void *address)
-{
- u32 page = ((unsigned long)address >> PAGE_SHIFT) & wss.pages_mask;
- u32 entry = page / BITS_PER_LONG; /* assumes this ends up a shift */
- u32 nr = page & (BITS_PER_LONG - 1);
-
- if (!test_and_set_bit(nr, &wss.entries[entry]))
- atomic_inc(&wss.total_count);
-
- wss_advance_clean_counter();
-}
-
-/*
- * Is the working set larger than the threshold?
- */
-static inline bool wss_exceeds_threshold(void)
-{
- return atomic_read(&wss.total_count) >= wss.threshold;
-}
-
/*
* Translate ib_wr_opcode into ib_wc_opcode.
*/
@@ -438,79 +290,6 @@ static const u32 pio_opmask[BIT(3)] = {
*/
__be64 ib_hfi1_sys_image_guid;
-/**
- * hfi1_copy_sge - copy data to SGE memory
- * @ss: the SGE state
- * @data: the data to copy
- * @length: the length of the data
- * @release: boolean to release MR
- * @copy_last: do a separate copy of the last 8 bytes
- */
-void hfi1_copy_sge(
- struct rvt_sge_state *ss,
- void *data, u32 length,
- bool release,
- bool copy_last)
-{
- struct rvt_sge *sge = &ss->sge;
- int i;
- bool in_last = false;
- bool cacheless_copy = false;
-
- if (sge_copy_mode == COPY_CACHELESS) {
- cacheless_copy = length >= PAGE_SIZE;
- } else if (sge_copy_mode == COPY_ADAPTIVE) {
- if (length >= PAGE_SIZE) {
- /*
- * NOTE: this *assumes*:
- * o The first vaddr is the dest.
- * o If multiple pages, then vaddr is sequential.
- */
- wss_insert(sge->vaddr);
- if (length >= (2 * PAGE_SIZE))
- wss_insert(sge->vaddr + PAGE_SIZE);
-
- cacheless_copy = wss_exceeds_threshold();
- } else {
- wss_advance_clean_counter();
- }
- }
- if (copy_last) {
- if (length > 8) {
- length -= 8;
- } else {
- copy_last = false;
- in_last = true;
- }
- }
-
-again:
- while (length) {
- u32 len = rvt_get_sge_length(sge, length);
-
- WARN_ON_ONCE(len == 0);
- if (unlikely(in_last)) {
- /* enforce byte transfer ordering */
- for (i = 0; i < len; i++)
- ((u8 *)sge->vaddr)[i] = ((u8 *)data)[i];
- } else if (cacheless_copy) {
- cacheless_memcpy(sge->vaddr, data, len);
- } else {
- memcpy(sge->vaddr, data, len);
- }
- rvt_update_sge(ss, len, release);
- data += len;
- length -= len;
- }
-
- if (copy_last) {
- copy_last = false;
- in_last = true;
- length = 8;
- goto again;
- }
-}
-
/*
* Make sure the QP is ready and able to accept the given opcode.
*/
@@ -713,7 +492,7 @@ static void verbs_sdma_complete(
spin_lock(&qp->s_lock);
if (tx->wqe) {
- hfi1_send_complete(qp, tx->wqe, IB_WC_SUCCESS);
+ rvt_send_complete(qp, tx->wqe, IB_WC_SUCCESS);
} else if (qp->ibqp.qp_type == IB_QPT_RC) {
struct hfi1_opa_header *hdr;
@@ -737,7 +516,7 @@ static int wait_kmem(struct hfi1_ibdev *dev,
if (ib_rvt_state_ops[qp->state] & RVT_PROCESS_RECV_OK) {
write_seqlock(&dev->iowait_lock);
list_add_tail(&ps->s_txreq->txreq.list,
- &priv->s_iowait.tx_head);
+ &ps->wait->tx_head);
if (list_empty(&priv->s_iowait.list)) {
if (list_empty(&dev->memwait))
mod_timer(&dev->mem_timer, jiffies + 1);
@@ -748,7 +527,7 @@ static int wait_kmem(struct hfi1_ibdev *dev,
rvt_get_qp(qp);
}
write_sequnlock(&dev->iowait_lock);
- qp->s_flags &= ~RVT_S_BUSY;
+ hfi1_qp_unbusy(qp, ps->wait);
ret = -EBUSY;
}
spin_unlock_irqrestore(&qp->s_lock, flags);
@@ -950,8 +729,7 @@ int hfi1_verbs_send_dma(struct rvt_qp *qp, struct hfi1_pkt_state *ps,
if (unlikely(ret))
goto bail_build;
}
- ret = sdma_send_txreq(tx->sde, &priv->s_iowait, &tx->txreq,
- ps->pkts_sent);
+ ret = sdma_send_txreq(tx->sde, ps->wait, &tx->txreq, ps->pkts_sent);
if (unlikely(ret < 0)) {
if (ret == -ECOMM)
goto bail_ecomm;
@@ -1001,7 +779,7 @@ static int pio_wait(struct rvt_qp *qp,
if (ib_rvt_state_ops[qp->state] & RVT_PROCESS_RECV_OK) {
write_seqlock(&dev->iowait_lock);
list_add_tail(&ps->s_txreq->txreq.list,
- &priv->s_iowait.tx_head);
+ &ps->wait->tx_head);
if (list_empty(&priv->s_iowait.list)) {
struct hfi1_ibdev *dev = &dd->verbs_dev;
int was_empty;
@@ -1020,7 +798,7 @@ static int pio_wait(struct rvt_qp *qp,
hfi1_sc_wantpiobuf_intr(sc, 1);
}
write_sequnlock(&dev->iowait_lock);
- qp->s_flags &= ~RVT_S_BUSY;
+ hfi1_qp_unbusy(qp, ps->wait);
ret = -EBUSY;
}
spin_unlock_irqrestore(&qp->s_lock, flags);
@@ -1160,7 +938,7 @@ int hfi1_verbs_send_pio(struct rvt_qp *qp, struct hfi1_pkt_state *ps,
pio_bail:
if (qp->s_wqe) {
spin_lock_irqsave(&qp->s_lock, flags);
- hfi1_send_complete(qp, qp->s_wqe, wc_status);
+ rvt_send_complete(qp, qp->s_wqe, wc_status);
spin_unlock_irqrestore(&qp->s_lock, flags);
} else if (qp->ibqp.qp_type == IB_QPT_RC) {
spin_lock_irqsave(&qp->s_lock, flags);
@@ -1367,7 +1145,7 @@ int hfi1_verbs_send(struct rvt_qp *qp, struct hfi1_pkt_state *ps)
hfi1_cdbg(PIO, "%s() Failed. Completing with err",
__func__);
spin_lock_irqsave(&qp->s_lock, flags);
- hfi1_send_complete(qp, qp->s_wqe, IB_WC_GENERAL_ERR);
+ rvt_send_complete(qp, qp->s_wqe, IB_WC_GENERAL_ERR);
spin_unlock_irqrestore(&qp->s_lock, flags);
}
return -EINVAL;
@@ -1943,7 +1721,7 @@ int hfi1_register_ib_device(struct hfi1_devdata *dd)
dd->verbs_dev.rdi.driver_f.check_modify_qp = hfi1_check_modify_qp;
dd->verbs_dev.rdi.driver_f.modify_qp = hfi1_modify_qp;
dd->verbs_dev.rdi.driver_f.notify_restart_rc = hfi1_restart_rc;
- dd->verbs_dev.rdi.driver_f.check_send_wqe = hfi1_check_send_wqe;
+ dd->verbs_dev.rdi.driver_f.setup_wqe = hfi1_setup_wqe;
dd->verbs_dev.rdi.driver_f.comp_vect_cpu_lookup =
hfi1_comp_vect_mappings_lookup;
@@ -1956,10 +1734,16 @@ int hfi1_register_ib_device(struct hfi1_devdata *dd)
dd->verbs_dev.rdi.dparms.lkey_table_size = hfi1_lkey_table_size;
dd->verbs_dev.rdi.dparms.nports = dd->num_pports;
dd->verbs_dev.rdi.dparms.npkeys = hfi1_get_npkeys(dd);
+ dd->verbs_dev.rdi.dparms.sge_copy_mode = sge_copy_mode;
+ dd->verbs_dev.rdi.dparms.wss_threshold = wss_threshold;
+ dd->verbs_dev.rdi.dparms.wss_clean_period = wss_clean_period;
/* post send table */
dd->verbs_dev.rdi.post_parms = hfi1_post_parms;
+ /* opcode translation table */
+ dd->verbs_dev.rdi.wc_opcode = ib_hfi1_wc_opcode;
+
ppd = dd->pport;
for (i = 0; i < dd->num_pports; i++, ppd++)
rvt_init_port(&dd->verbs_dev.rdi,
@@ -1967,6 +1751,9 @@ 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, RDMA_DRIVER_HFI1);
if (ret)
goto err_verbs_txreq;
diff --git a/drivers/infiniband/hw/hfi1/verbs.h b/drivers/infiniband/hw/hfi1/verbs.h
index a4d06502f06d..64c9054db5f3 100644
--- a/drivers/infiniband/hw/hfi1/verbs.h
+++ b/drivers/infiniband/hw/hfi1/verbs.h
@@ -166,11 +166,13 @@ struct hfi1_qp_priv {
* This structure is used to hold commonly lookedup and computed values during
* the send engine progress.
*/
+struct iowait_work;
struct hfi1_pkt_state {
struct hfi1_ibdev *dev;
struct hfi1_ibport *ibp;
struct hfi1_pportdata *ppd;
struct verbs_txreq *s_txreq;
+ struct iowait_work *wait;
unsigned long flags;
unsigned long timeout;
unsigned long timeout_int;
@@ -247,7 +249,7 @@ static inline struct hfi1_ibdev *to_idev(struct ib_device *ibdev)
return container_of(rdi, struct hfi1_ibdev, rdi);
}
-static inline struct rvt_qp *iowait_to_qp(struct iowait *s_iowait)
+static inline struct rvt_qp *iowait_to_qp(struct iowait *s_iowait)
{
struct hfi1_qp_priv *priv;
@@ -313,9 +315,6 @@ void hfi1_put_txreq(struct verbs_txreq *tx);
int hfi1_verbs_send(struct rvt_qp *qp, struct hfi1_pkt_state *ps);
-void hfi1_copy_sge(struct rvt_sge_state *ss, void *data, u32 length,
- bool release, bool copy_last);
-
void hfi1_cnp_rcv(struct hfi1_packet *packet);
void hfi1_uc_rcv(struct hfi1_packet *packet);
@@ -343,7 +342,8 @@ int hfi1_check_modify_qp(struct rvt_qp *qp, struct ib_qp_attr *attr,
void hfi1_modify_qp(struct rvt_qp *qp, struct ib_qp_attr *attr,
int attr_mask, struct ib_udata *udata);
void hfi1_restart_rc(struct rvt_qp *qp, u32 psn, int wait);
-int hfi1_check_send_wqe(struct rvt_qp *qp, struct rvt_swqe *wqe);
+int hfi1_setup_wqe(struct rvt_qp *qp, struct rvt_swqe *wqe,
+ bool *call_send);
extern const u32 rc_only_opcode;
extern const u32 uc_only_opcode;
@@ -363,9 +363,6 @@ void hfi1_do_send_from_rvt(struct rvt_qp *qp);
void hfi1_do_send(struct rvt_qp *qp, bool in_thread);
-void hfi1_send_complete(struct rvt_qp *qp, struct rvt_swqe *wqe,
- enum ib_wc_status status);
-
void hfi1_send_rc_ack(struct hfi1_packet *packet, bool is_fecn);
int hfi1_make_rc_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps);
@@ -390,28 +387,6 @@ int hfi1_verbs_send_dma(struct rvt_qp *qp, struct hfi1_pkt_state *ps,
int hfi1_verbs_send_pio(struct rvt_qp *qp, struct hfi1_pkt_state *ps,
u64 pbc);
-int hfi1_wss_init(void);
-void hfi1_wss_exit(void);
-
-/* platform specific: return the lowest level cache (llc) size, in KiB */
-static inline int wss_llc_size(void)
-{
- /* assume that the boot CPU value is universal for all CPUs */
- return boot_cpu_data.x86_cache_size;
-}
-
-/* platform specific: cacheless copy */
-static inline void cacheless_memcpy(void *dst, void *src, size_t n)
-{
- /*
- * Use the only available X64 cacheless copy. Add a __user cast
- * to quiet sparse. The src agument is already in the kernel so
- * there are no security issues. The extra fault recovery machinery
- * is not invoked.
- */
- __copy_user_nocache(dst, (void __user *)src, n, 0);
-}
-
static inline bool opa_bth_is_migration(struct ib_other_headers *ohdr)
{
return ohdr->bth[1] & cpu_to_be32(OPA_BTH_MIG_REQ);
diff --git a/drivers/infiniband/hw/hfi1/verbs_txreq.h b/drivers/infiniband/hw/hfi1/verbs_txreq.h
index 1c19bbc764b2..2a77af26a231 100644
--- a/drivers/infiniband/hw/hfi1/verbs_txreq.h
+++ b/drivers/infiniband/hw/hfi1/verbs_txreq.h
@@ -102,22 +102,19 @@ static inline struct sdma_txreq *get_sdma_txreq(struct verbs_txreq *tx)
return &tx->txreq;
}
-static inline struct verbs_txreq *get_waiting_verbs_txreq(struct rvt_qp *qp)
+static inline struct verbs_txreq *get_waiting_verbs_txreq(struct iowait_work *w)
{
struct sdma_txreq *stx;
- struct hfi1_qp_priv *priv = qp->priv;
- stx = iowait_get_txhead(&priv->s_iowait);
+ stx = iowait_get_txhead(w);
if (stx)
return container_of(stx, struct verbs_txreq, txreq);
return NULL;
}
-static inline bool verbs_txreq_queued(struct rvt_qp *qp)
+static inline bool verbs_txreq_queued(struct iowait_work *w)
{
- struct hfi1_qp_priv *priv = qp->priv;
-
- return iowait_packet_queued(&priv->s_iowait);
+ return iowait_packet_queued(w);
}
void hfi1_put_txreq(struct verbs_txreq *tx);
diff --git a/drivers/infiniband/hw/hfi1/vnic_main.c b/drivers/infiniband/hw/hfi1/vnic_main.c
index c643d80c5a53..c9876d9e3cb9 100644
--- a/drivers/infiniband/hw/hfi1/vnic_main.c
+++ b/drivers/infiniband/hw/hfi1/vnic_main.c
@@ -120,7 +120,7 @@ static int allocate_vnic_ctxt(struct hfi1_devdata *dd,
uctxt->seq_cnt = 1;
uctxt->is_vnic = true;
- hfi1_set_vnic_msix_info(uctxt);
+ msix_request_rcd_irq(uctxt);
hfi1_stats.sps_ctxts++;
dd_dev_dbg(dd, "created vnic context %d\n", uctxt->ctxt);
@@ -135,8 +135,6 @@ static void deallocate_vnic_ctxt(struct hfi1_devdata *dd,
dd_dev_dbg(dd, "closing vnic context %d\n", uctxt->ctxt);
flush_wc();
- hfi1_reset_vnic_msix_info(uctxt);
-
/*
* Disable receive context and interrupt available, reset all
* RcvCtxtCtrl bits to default values.
@@ -148,6 +146,10 @@ static void deallocate_vnic_ctxt(struct hfi1_devdata *dd,
HFI1_RCVCTRL_NO_RHQ_DROP_DIS |
HFI1_RCVCTRL_NO_EGR_DROP_DIS, uctxt);
+ /* msix_intr will always be > 0, only clean up if this is true */
+ if (uctxt->msix_intr)
+ msix_free_irq(dd, uctxt->msix_intr);
+
uctxt->event_flags = 0;
hfi1_clear_tids(uctxt);
@@ -626,7 +628,7 @@ static void hfi1_vnic_down(struct hfi1_vnic_vport_info *vinfo)
idr_remove(&dd->vnic.vesw_idr, vinfo->vesw_id);
/* ensure irqs see the change */
- hfi1_vnic_synchronize_irq(dd);
+ msix_vnic_synchronize_irq(dd);
/* remove unread skbs */
for (i = 0; i < vinfo->num_rx_q; i++) {
@@ -690,8 +692,6 @@ static int hfi1_vnic_init(struct hfi1_vnic_vport_info *vinfo)
rc = hfi1_vnic_txreq_init(dd);
if (rc)
goto txreq_fail;
-
- dd->vnic.msix_idx = dd->first_dyn_msix_idx;
}
for (i = dd->vnic.num_ctxt; i < vinfo->num_rx_q; i++) {
diff --git a/drivers/infiniband/hw/hfi1/vnic_sdma.c b/drivers/infiniband/hw/hfi1/vnic_sdma.c
index c3c96c5869ed..97bd940a056a 100644
--- a/drivers/infiniband/hw/hfi1/vnic_sdma.c
+++ b/drivers/infiniband/hw/hfi1/vnic_sdma.c
@@ -1,5 +1,5 @@
/*
- * Copyright(c) 2017 Intel Corporation.
+ * Copyright(c) 2017 - 2018 Intel Corporation.
*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
@@ -198,8 +198,8 @@ int hfi1_vnic_send_dma(struct hfi1_devdata *dd, u8 q_idx,
goto free_desc;
tx->retry_count = 0;
- ret = sdma_send_txreq(sde, &vnic_sdma->wait, &tx->txreq,
- vnic_sdma->pkts_sent);
+ ret = sdma_send_txreq(sde, iowait_get_ib_work(&vnic_sdma->wait),
+ &tx->txreq, vnic_sdma->pkts_sent);
/* When -ECOMM, sdma callback will be called with ABORT status */
if (unlikely(ret && unlikely(ret != -ECOMM)))
goto free_desc;
@@ -230,13 +230,13 @@ tx_err:
* become available.
*/
static int hfi1_vnic_sdma_sleep(struct sdma_engine *sde,
- struct iowait *wait,
+ struct iowait_work *wait,
struct sdma_txreq *txreq,
uint seq,
bool pkts_sent)
{
struct hfi1_vnic_sdma *vnic_sdma =
- container_of(wait, struct hfi1_vnic_sdma, wait);
+ container_of(wait->iow, struct hfi1_vnic_sdma, wait);
struct hfi1_ibdev *dev = &vnic_sdma->dd->verbs_dev;
struct vnic_txreq *tx = container_of(txreq, struct vnic_txreq, txreq);
@@ -247,7 +247,7 @@ static int hfi1_vnic_sdma_sleep(struct sdma_engine *sde,
vnic_sdma->state = HFI1_VNIC_SDMA_Q_DEFERRED;
write_seqlock(&dev->iowait_lock);
if (list_empty(&vnic_sdma->wait.list))
- iowait_queue(pkts_sent, wait, &sde->dmawait);
+ iowait_queue(pkts_sent, wait->iow, &sde->dmawait);
write_sequnlock(&dev->iowait_lock);
return -EBUSY;
}
@@ -285,7 +285,8 @@ void hfi1_vnic_sdma_init(struct hfi1_vnic_vport_info *vinfo)
for (i = 0; i < vinfo->num_tx_q; i++) {
struct hfi1_vnic_sdma *vnic_sdma = &vinfo->sdma[i];
- iowait_init(&vnic_sdma->wait, 0, NULL, hfi1_vnic_sdma_sleep,
+ iowait_init(&vnic_sdma->wait, 0, NULL, NULL,
+ hfi1_vnic_sdma_sleep,
hfi1_vnic_sdma_wakeup, NULL);
vnic_sdma->sde = &vinfo->dd->per_sdma[i];
vnic_sdma->dd = vinfo->dd;
@@ -295,10 +296,12 @@ void hfi1_vnic_sdma_init(struct hfi1_vnic_vport_info *vinfo)
/* Add a free descriptor watermark for wakeups */
if (vnic_sdma->sde->descq_cnt > HFI1_VNIC_SDMA_DESC_WTRMRK) {
+ struct iowait_work *work;
+
INIT_LIST_HEAD(&vnic_sdma->stx.list);
vnic_sdma->stx.num_desc = HFI1_VNIC_SDMA_DESC_WTRMRK;
- list_add_tail(&vnic_sdma->stx.list,
- &vnic_sdma->wait.tx_head);
+ work = iowait_get_ib_work(&vnic_sdma->wait);
+ list_add_tail(&vnic_sdma->stx.list, &work->tx_head);
}
}
}
diff --git a/drivers/infiniband/hw/hns/Kconfig b/drivers/infiniband/hw/hns/Kconfig
index fddb5fdf92de..21c2100b2ea9 100644
--- a/drivers/infiniband/hw/hns/Kconfig
+++ b/drivers/infiniband/hw/hns/Kconfig
@@ -1,6 +1,7 @@
config INFINIBAND_HNS
tristate "HNS RoCE Driver"
depends on NET_VENDOR_HISILICON
+ depends on INFINIBAND_USER_ACCESS || !INFINIBAND_USER_ACCESS
depends on ARM64 || (COMPILE_TEST && 64BIT)
---help---
This is a RoCE/RDMA driver for the Hisilicon RoCE engine. The engine
diff --git a/drivers/infiniband/hw/hns/hns_roce_ah.c b/drivers/infiniband/hw/hns/hns_roce_ah.c
index 0d96c5bb38cd..9990dc9eb96a 100644
--- a/drivers/infiniband/hw/hns/hns_roce_ah.c
+++ b/drivers/infiniband/hw/hns/hns_roce_ah.c
@@ -49,6 +49,7 @@ struct ib_ah *hns_roce_create_ah(struct ib_pd *ibpd,
struct hns_roce_ah *ah;
u16 vlan_tag = 0xffff;
const struct ib_global_route *grh = rdma_ah_read_grh(ah_attr);
+ bool vlan_en = false;
ah = kzalloc(sizeof(*ah), GFP_ATOMIC);
if (!ah)
@@ -58,8 +59,10 @@ struct ib_ah *hns_roce_create_ah(struct ib_pd *ibpd,
memcpy(ah->av.mac, ah_attr->roce.dmac, ETH_ALEN);
gid_attr = ah_attr->grh.sgid_attr;
- if (is_vlan_dev(gid_attr->ndev))
+ if (is_vlan_dev(gid_attr->ndev)) {
vlan_tag = vlan_dev_vlan_id(gid_attr->ndev);
+ vlan_en = true;
+ }
if (vlan_tag < 0x1000)
vlan_tag |= (rdma_ah_get_sl(ah_attr) &
@@ -71,6 +74,7 @@ struct ib_ah *hns_roce_create_ah(struct ib_pd *ibpd,
HNS_ROCE_PORT_NUM_SHIFT));
ah->av.gid_index = grh->sgid_index;
ah->av.vlan = cpu_to_le16(vlan_tag);
+ ah->av.vlan_en = vlan_en;
dev_dbg(dev, "gid_index = 0x%x,vlan = 0x%x\n", ah->av.gid_index,
ah->av.vlan);
diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h
index 9a24fd0ee3e7..d39bdfdb5de9 100644
--- a/drivers/infiniband/hw/hns/hns_roce_device.h
+++ b/drivers/infiniband/hw/hns/hns_roce_device.h
@@ -88,8 +88,11 @@
#define BITMAP_RR 1
#define MR_TYPE_MR 0x00
+#define MR_TYPE_FRMR 0x01
#define MR_TYPE_DMA 0x03
+#define HNS_ROCE_FRMR_MAX_PA 512
+
#define PKEY_ID 0xffff
#define GUID_LEN 8
#define NODE_DESC_SIZE 64
@@ -193,6 +196,9 @@ enum {
HNS_ROCE_CAP_FLAG_RQ_INLINE = BIT(2),
HNS_ROCE_CAP_FLAG_RECORD_DB = BIT(3),
HNS_ROCE_CAP_FLAG_SQ_RECORD_DB = BIT(4),
+ HNS_ROCE_CAP_FLAG_MW = BIT(7),
+ HNS_ROCE_CAP_FLAG_FRMR = BIT(8),
+ HNS_ROCE_CAP_FLAG_ATOMIC = BIT(10),
};
enum hns_roce_mtt_type {
@@ -219,19 +225,11 @@ struct hns_roce_uar {
unsigned long logic_idx;
};
-struct hns_roce_vma_data {
- struct list_head list;
- struct vm_area_struct *vma;
- struct mutex *vma_list_mutex;
-};
-
struct hns_roce_ucontext {
struct ib_ucontext ibucontext;
struct hns_roce_uar uar;
struct list_head page_list;
struct mutex page_mutex;
- struct list_head vma_list;
- struct mutex vma_list_mutex;
};
struct hns_roce_pd {
@@ -293,6 +291,16 @@ struct hns_roce_mtt {
enum hns_roce_mtt_type mtt_type;
};
+struct hns_roce_mw {
+ struct ib_mw ibmw;
+ u32 pdn;
+ u32 rkey;
+ int enabled; /* MW's active status */
+ u32 pbl_hop_num;
+ u32 pbl_ba_pg_sz;
+ u32 pbl_buf_pg_sz;
+};
+
/* Only support 4K page size for mr register */
#define MR_SIZE_4K 0
@@ -304,6 +312,7 @@ struct hns_roce_mr {
u32 key; /* Key of MR */
u32 pd; /* PD num of MR */
u32 access;/* Access permission of MR */
+ u32 npages;
int enabled; /* MR's active status */
int type; /* MR's register type */
u64 *pbl_buf;/* MR's PBL space */
@@ -457,6 +466,7 @@ struct hns_roce_av {
u8 dgid[HNS_ROCE_GID_SIZE];
u8 mac[6];
__le16 vlan;
+ bool vlan_en;
};
struct hns_roce_ah {
@@ -656,6 +666,7 @@ struct hns_roce_eq_table {
};
struct hns_roce_caps {
+ u64 fw_ver;
u8 num_ports;
int gid_table_len[HNS_ROCE_MAX_PORTS];
int pkey_table_len[HNS_ROCE_MAX_PORTS];
@@ -665,7 +676,9 @@ struct hns_roce_caps {
u32 max_sq_sg; /* 2 */
u32 max_sq_inline; /* 32 */
u32 max_rq_sg; /* 2 */
+ u32 max_extend_sg;
int num_qps; /* 256k */
+ int reserved_qps;
u32 max_wqes; /* 16k */
u32 max_sq_desc_sz; /* 64 */
u32 max_rq_desc_sz; /* 64 */
@@ -738,6 +751,7 @@ struct hns_roce_work {
struct hns_roce_dev *hr_dev;
struct work_struct work;
u32 qpn;
+ u32 cqn;
int event_type;
int sub_type;
};
@@ -764,6 +778,8 @@ struct hns_roce_hw {
struct hns_roce_mr *mr, int flags, u32 pdn,
int mr_access_flags, u64 iova, u64 size,
void *mb_buf);
+ int (*frmr_write_mtpt)(void *mb_buf, struct hns_roce_mr *mr);
+ int (*mw_write_mtpt)(void *mb_buf, struct hns_roce_mw *mw);
void (*write_cqc)(struct hns_roce_dev *hr_dev,
struct hns_roce_cq *hr_cq, void *mb_buf, u64 *mtts,
dma_addr_t dma_handle, int nent, u32 vector);
@@ -863,6 +879,11 @@ static inline struct hns_roce_mr *to_hr_mr(struct ib_mr *ibmr)
return container_of(ibmr, struct hns_roce_mr, ibmr);
}
+static inline struct hns_roce_mw *to_hr_mw(struct ib_mw *ibmw)
+{
+ return container_of(ibmw, struct hns_roce_mw, ibmw);
+}
+
static inline struct hns_roce_qp *to_hr_qp(struct ib_qp *ibqp)
{
return container_of(ibqp, struct hns_roce_qp, ibqp);
@@ -968,12 +989,20 @@ struct ib_mr *hns_roce_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
int hns_roce_rereg_user_mr(struct ib_mr *mr, int flags, u64 start, u64 length,
u64 virt_addr, int mr_access_flags, struct ib_pd *pd,
struct ib_udata *udata);
+struct ib_mr *hns_roce_alloc_mr(struct ib_pd *pd, enum ib_mr_type mr_type,
+ u32 max_num_sg);
+int hns_roce_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, int sg_nents,
+ unsigned int *sg_offset);
int hns_roce_dereg_mr(struct ib_mr *ibmr);
int hns_roce_hw2sw_mpt(struct hns_roce_dev *hr_dev,
struct hns_roce_cmd_mailbox *mailbox,
unsigned long mpt_index);
unsigned long key_to_hw_index(u32 key);
+struct ib_mw *hns_roce_alloc_mw(struct ib_pd *pd, enum ib_mw_type,
+ struct ib_udata *udata);
+int hns_roce_dealloc_mw(struct ib_mw *ibmw);
+
void hns_roce_buf_free(struct hns_roce_dev *hr_dev, u32 size,
struct hns_roce_buf *buf);
int hns_roce_buf_alloc(struct hns_roce_dev *hr_dev, u32 size, u32 max_direct,
diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c
index 081aa91fc162..ca05810c92dc 100644
--- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c
+++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c
@@ -731,7 +731,7 @@ static int hns_roce_v1_rsv_lp_qp(struct hns_roce_dev *hr_dev)
cq_init_attr.comp_vector = 0;
cq = hns_roce_ib_create_cq(&hr_dev->ib_dev, &cq_init_attr, NULL, NULL);
if (IS_ERR(cq)) {
- dev_err(dev, "Create cq for reseved loop qp failed!");
+ dev_err(dev, "Create cq for reserved loop qp failed!");
return -ENOMEM;
}
free_mr->mr_free_cq = to_hr_cq(cq);
@@ -744,7 +744,7 @@ static int hns_roce_v1_rsv_lp_qp(struct hns_roce_dev *hr_dev)
pd = hns_roce_alloc_pd(&hr_dev->ib_dev, NULL, NULL);
if (IS_ERR(pd)) {
- dev_err(dev, "Create pd for reseved loop qp failed!");
+ dev_err(dev, "Create pd for reserved loop qp failed!");
ret = -ENOMEM;
goto alloc_pd_failed;
}
diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
index 0218c0f8c2a7..a4c62ae23a9a 100644
--- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
+++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
@@ -54,6 +54,59 @@ static void set_data_seg_v2(struct hns_roce_v2_wqe_data_seg *dseg,
dseg->len = cpu_to_le32(sg->length);
}
+static void set_frmr_seg(struct hns_roce_v2_rc_send_wqe *rc_sq_wqe,
+ struct hns_roce_wqe_frmr_seg *fseg,
+ const struct ib_reg_wr *wr)
+{
+ struct hns_roce_mr *mr = to_hr_mr(wr->mr);
+
+ /* use ib_access_flags */
+ roce_set_bit(rc_sq_wqe->byte_4,
+ V2_RC_FRMR_WQE_BYTE_4_BIND_EN_S,
+ wr->access & IB_ACCESS_MW_BIND ? 1 : 0);
+ roce_set_bit(rc_sq_wqe->byte_4,
+ V2_RC_FRMR_WQE_BYTE_4_ATOMIC_S,
+ wr->access & IB_ACCESS_REMOTE_ATOMIC ? 1 : 0);
+ roce_set_bit(rc_sq_wqe->byte_4,
+ V2_RC_FRMR_WQE_BYTE_4_RR_S,
+ wr->access & IB_ACCESS_REMOTE_READ ? 1 : 0);
+ roce_set_bit(rc_sq_wqe->byte_4,
+ V2_RC_FRMR_WQE_BYTE_4_RW_S,
+ wr->access & IB_ACCESS_REMOTE_WRITE ? 1 : 0);
+ roce_set_bit(rc_sq_wqe->byte_4,
+ V2_RC_FRMR_WQE_BYTE_4_LW_S,
+ wr->access & IB_ACCESS_LOCAL_WRITE ? 1 : 0);
+
+ /* Data structure reuse may lead to confusion */
+ rc_sq_wqe->msg_len = cpu_to_le32(mr->pbl_ba & 0xffffffff);
+ rc_sq_wqe->inv_key = cpu_to_le32(mr->pbl_ba >> 32);
+
+ rc_sq_wqe->byte_16 = cpu_to_le32(wr->mr->length & 0xffffffff);
+ rc_sq_wqe->byte_20 = cpu_to_le32(wr->mr->length >> 32);
+ 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->pbl_size);
+ roce_set_field(fseg->mode_buf_pg_sz,
+ V2_RC_FRMR_WQE_BYTE_40_PBL_BUF_PG_SZ_M,
+ V2_RC_FRMR_WQE_BYTE_40_PBL_BUF_PG_SZ_S,
+ mr->pbl_buf_pg_sz + PG_SHIFT_OFFSET);
+ roce_set_bit(fseg->mode_buf_pg_sz,
+ V2_RC_FRMR_WQE_BYTE_40_BLK_MODE_S, 0);
+}
+
+static void set_atomic_seg(struct hns_roce_wqe_atomic_seg *aseg,
+ const struct ib_atomic_wr *wr)
+{
+ if (wr->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
+ aseg->fetchadd_swap_data = cpu_to_le64(wr->swap);
+ aseg->cmp_data = cpu_to_le64(wr->compare_add);
+ } else {
+ aseg->fetchadd_swap_data = cpu_to_le64(wr->compare_add);
+ aseg->cmp_data = 0;
+ }
+}
+
static void set_extend_sge(struct hns_roce_qp *qp, const struct ib_send_wr *wr,
unsigned int *sge_ind)
{
@@ -121,6 +174,7 @@ static int set_rwqe_data_seg(struct ib_qp *ibqp, const struct ib_send_wr *wr,
}
if (wr->opcode == IB_WR_RDMA_READ) {
+ *bad_wr = wr;
dev_err(hr_dev->dev, "Not support inline data!\n");
return -EINVAL;
}
@@ -179,6 +233,7 @@ static int hns_roce_v2_post_send(struct ib_qp *ibqp,
struct hns_roce_v2_ud_send_wqe *ud_sq_wqe;
struct hns_roce_v2_rc_send_wqe *rc_sq_wqe;
struct hns_roce_qp *qp = to_hr_qp(ibqp);
+ struct hns_roce_wqe_frmr_seg *fseg;
struct device *dev = hr_dev->dev;
struct hns_roce_v2_db sq_db;
struct ib_qp_attr attr;
@@ -191,6 +246,7 @@ static int hns_roce_v2_post_send(struct ib_qp *ibqp,
int attr_mask;
u32 tmp_len;
int ret = 0;
+ u32 hr_op;
u8 *smac;
int nreq;
int i;
@@ -356,6 +412,9 @@ static int hns_roce_v2_post_send(struct ib_qp *ibqp,
V2_UD_SEND_WQE_BYTE_40_PORTN_S,
qp->port);
+ roce_set_bit(ud_sq_wqe->byte_40,
+ V2_UD_SEND_WQE_BYTE_40_UD_VLAN_EN_S,
+ ah->av.vlan_en ? 1 : 0);
roce_set_field(ud_sq_wqe->byte_48,
V2_UD_SEND_WQE_BYTE_48_SGID_INDX_M,
V2_UD_SEND_WQE_BYTE_48_SGID_INDX_S,
@@ -406,99 +465,100 @@ static int hns_roce_v2_post_send(struct ib_qp *ibqp,
roce_set_bit(rc_sq_wqe->byte_4,
V2_RC_SEND_WQE_BYTE_4_OWNER_S, owner_bit);
+ wqe += sizeof(struct hns_roce_v2_rc_send_wqe);
switch (wr->opcode) {
case IB_WR_RDMA_READ:
- roce_set_field(rc_sq_wqe->byte_4,
- V2_RC_SEND_WQE_BYTE_4_OPCODE_M,
- V2_RC_SEND_WQE_BYTE_4_OPCODE_S,
- HNS_ROCE_V2_WQE_OP_RDMA_READ);
+ hr_op = HNS_ROCE_V2_WQE_OP_RDMA_READ;
rc_sq_wqe->rkey =
cpu_to_le32(rdma_wr(wr)->rkey);
rc_sq_wqe->va =
cpu_to_le64(rdma_wr(wr)->remote_addr);
break;
case IB_WR_RDMA_WRITE:
- roce_set_field(rc_sq_wqe->byte_4,
- V2_RC_SEND_WQE_BYTE_4_OPCODE_M,
- V2_RC_SEND_WQE_BYTE_4_OPCODE_S,
- HNS_ROCE_V2_WQE_OP_RDMA_WRITE);
+ hr_op = HNS_ROCE_V2_WQE_OP_RDMA_WRITE;
rc_sq_wqe->rkey =
cpu_to_le32(rdma_wr(wr)->rkey);
rc_sq_wqe->va =
cpu_to_le64(rdma_wr(wr)->remote_addr);
break;
case IB_WR_RDMA_WRITE_WITH_IMM:
- roce_set_field(rc_sq_wqe->byte_4,
- V2_RC_SEND_WQE_BYTE_4_OPCODE_M,
- V2_RC_SEND_WQE_BYTE_4_OPCODE_S,
- HNS_ROCE_V2_WQE_OP_RDMA_WRITE_WITH_IMM);
+ hr_op = HNS_ROCE_V2_WQE_OP_RDMA_WRITE_WITH_IMM;
rc_sq_wqe->rkey =
cpu_to_le32(rdma_wr(wr)->rkey);
rc_sq_wqe->va =
cpu_to_le64(rdma_wr(wr)->remote_addr);
break;
case IB_WR_SEND:
- roce_set_field(rc_sq_wqe->byte_4,
- V2_RC_SEND_WQE_BYTE_4_OPCODE_M,
- V2_RC_SEND_WQE_BYTE_4_OPCODE_S,
- HNS_ROCE_V2_WQE_OP_SEND);
+ hr_op = HNS_ROCE_V2_WQE_OP_SEND;
break;
case IB_WR_SEND_WITH_INV:
- roce_set_field(rc_sq_wqe->byte_4,
- V2_RC_SEND_WQE_BYTE_4_OPCODE_M,
- V2_RC_SEND_WQE_BYTE_4_OPCODE_S,
- HNS_ROCE_V2_WQE_OP_SEND_WITH_INV);
+ hr_op = HNS_ROCE_V2_WQE_OP_SEND_WITH_INV;
break;
case IB_WR_SEND_WITH_IMM:
- roce_set_field(rc_sq_wqe->byte_4,
- V2_RC_SEND_WQE_BYTE_4_OPCODE_M,
- V2_RC_SEND_WQE_BYTE_4_OPCODE_S,
- HNS_ROCE_V2_WQE_OP_SEND_WITH_IMM);
+ hr_op = HNS_ROCE_V2_WQE_OP_SEND_WITH_IMM;
break;
case IB_WR_LOCAL_INV:
- roce_set_field(rc_sq_wqe->byte_4,
- V2_RC_SEND_WQE_BYTE_4_OPCODE_M,
- V2_RC_SEND_WQE_BYTE_4_OPCODE_S,
- HNS_ROCE_V2_WQE_OP_LOCAL_INV);
+ hr_op = HNS_ROCE_V2_WQE_OP_LOCAL_INV;
+ roce_set_bit(rc_sq_wqe->byte_4,
+ V2_RC_SEND_WQE_BYTE_4_SO_S, 1);
+ rc_sq_wqe->inv_key =
+ cpu_to_le32(wr->ex.invalidate_rkey);
+ break;
+ case IB_WR_REG_MR:
+ hr_op = HNS_ROCE_V2_WQE_OP_FAST_REG_PMR;
+ fseg = wqe;
+ set_frmr_seg(rc_sq_wqe, fseg, reg_wr(wr));
break;
case IB_WR_ATOMIC_CMP_AND_SWP:
- roce_set_field(rc_sq_wqe->byte_4,
- V2_RC_SEND_WQE_BYTE_4_OPCODE_M,
- V2_RC_SEND_WQE_BYTE_4_OPCODE_S,
- HNS_ROCE_V2_WQE_OP_ATOM_CMP_AND_SWAP);
+ hr_op = HNS_ROCE_V2_WQE_OP_ATOM_CMP_AND_SWAP;
+ rc_sq_wqe->rkey =
+ cpu_to_le32(atomic_wr(wr)->rkey);
+ rc_sq_wqe->va =
+ cpu_to_le64(atomic_wr(wr)->remote_addr);
break;
case IB_WR_ATOMIC_FETCH_AND_ADD:
- roce_set_field(rc_sq_wqe->byte_4,
- V2_RC_SEND_WQE_BYTE_4_OPCODE_M,
- V2_RC_SEND_WQE_BYTE_4_OPCODE_S,
- HNS_ROCE_V2_WQE_OP_ATOM_FETCH_AND_ADD);
+ hr_op = HNS_ROCE_V2_WQE_OP_ATOM_FETCH_AND_ADD;
+ rc_sq_wqe->rkey =
+ cpu_to_le32(atomic_wr(wr)->rkey);
+ rc_sq_wqe->va =
+ cpu_to_le64(atomic_wr(wr)->remote_addr);
break;
case IB_WR_MASKED_ATOMIC_CMP_AND_SWP:
- roce_set_field(rc_sq_wqe->byte_4,
- V2_RC_SEND_WQE_BYTE_4_OPCODE_M,
- V2_RC_SEND_WQE_BYTE_4_OPCODE_S,
- HNS_ROCE_V2_WQE_OP_ATOM_MSK_CMP_AND_SWAP);
+ hr_op =
+ HNS_ROCE_V2_WQE_OP_ATOM_MSK_CMP_AND_SWAP;
break;
case IB_WR_MASKED_ATOMIC_FETCH_AND_ADD:
- roce_set_field(rc_sq_wqe->byte_4,
- V2_RC_SEND_WQE_BYTE_4_OPCODE_M,
- V2_RC_SEND_WQE_BYTE_4_OPCODE_S,
- HNS_ROCE_V2_WQE_OP_ATOM_MSK_FETCH_AND_ADD);
+ hr_op =
+ HNS_ROCE_V2_WQE_OP_ATOM_MSK_FETCH_AND_ADD;
break;
default:
- roce_set_field(rc_sq_wqe->byte_4,
- V2_RC_SEND_WQE_BYTE_4_OPCODE_M,
- V2_RC_SEND_WQE_BYTE_4_OPCODE_S,
- HNS_ROCE_V2_WQE_OP_MASK);
+ hr_op = HNS_ROCE_V2_WQE_OP_MASK;
break;
}
- wqe += sizeof(struct hns_roce_v2_rc_send_wqe);
+ roce_set_field(rc_sq_wqe->byte_4,
+ V2_RC_SEND_WQE_BYTE_4_OPCODE_M,
+ V2_RC_SEND_WQE_BYTE_4_OPCODE_S, hr_op);
+
+ if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP ||
+ wr->opcode == IB_WR_ATOMIC_FETCH_AND_ADD) {
+ struct hns_roce_v2_wqe_data_seg *dseg;
+
+ dseg = wqe;
+ set_data_seg_v2(dseg, wr->sg_list);
+ wqe += sizeof(struct hns_roce_v2_wqe_data_seg);
+ set_atomic_seg(wqe, atomic_wr(wr));
+ roce_set_field(rc_sq_wqe->byte_16,
+ V2_RC_SEND_WQE_BYTE_16_SGE_NUM_M,
+ V2_RC_SEND_WQE_BYTE_16_SGE_NUM_S,
+ wr->num_sge);
+ } else if (wr->opcode != IB_WR_REG_MR) {
+ ret = set_rwqe_data_seg(ibqp, wr, rc_sq_wqe,
+ wqe, &sge_ind, bad_wr);
+ if (ret)
+ goto out;
+ }
- ret = set_rwqe_data_seg(ibqp, wr, rc_sq_wqe, wqe,
- &sge_ind, bad_wr);
- if (ret)
- goto out;
ind++;
} else {
dev_err(dev, "Illegal qp_type(0x%x)\n", ibqp->qp_type);
@@ -935,7 +995,24 @@ static int hns_roce_cmq_query_hw_info(struct hns_roce_dev *hr_dev)
resp = (struct hns_roce_query_version *)desc.data;
hr_dev->hw_rev = le32_to_cpu(resp->rocee_hw_version);
- hr_dev->vendor_id = le32_to_cpu(resp->rocee_vendor_id);
+ hr_dev->vendor_id = hr_dev->pci_dev->vendor;
+
+ return 0;
+}
+
+static int hns_roce_query_fw_ver(struct hns_roce_dev *hr_dev)
+{
+ struct hns_roce_query_fw_info *resp;
+ struct hns_roce_cmq_desc desc;
+ int ret;
+
+ hns_roce_cmq_setup_basic_desc(&desc, HNS_QUERY_FW_VER, true);
+ ret = hns_roce_cmq_send(hr_dev, &desc, 1);
+ if (ret)
+ return ret;
+
+ resp = (struct hns_roce_query_fw_info *)desc.data;
+ hr_dev->caps.fw_ver = (u64)(le32_to_cpu(resp->fw_ver));
return 0;
}
@@ -1158,6 +1235,13 @@ static int hns_roce_v2_profile(struct hns_roce_dev *hr_dev)
ret = hns_roce_cmq_query_hw_info(hr_dev);
if (ret) {
+ dev_err(hr_dev->dev, "Query hardware version fail, ret = %d.\n",
+ ret);
+ return ret;
+ }
+
+ ret = hns_roce_query_fw_ver(hr_dev);
+ if (ret) {
dev_err(hr_dev->dev, "Query firmware version fail, ret = %d.\n",
ret);
return ret;
@@ -1185,14 +1269,16 @@ static int hns_roce_v2_profile(struct hns_roce_dev *hr_dev)
return ret;
}
- hr_dev->vendor_part_id = 0;
- hr_dev->sys_image_guid = 0;
+
+ 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->num_qps = HNS_ROCE_V2_MAX_QP_NUM;
caps->max_wqes = HNS_ROCE_V2_MAX_WQE_NUM;
caps->num_cqs = HNS_ROCE_V2_MAX_CQ_NUM;
caps->max_cqes = HNS_ROCE_V2_MAX_CQE_NUM;
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->max_sq_inline = HNS_ROCE_V2_MAX_SQ_INLINE;
caps->num_uars = HNS_ROCE_V2_UAR_NUM;
@@ -1222,6 +1308,7 @@ static int hns_roce_v2_profile(struct hns_roce_dev *hr_dev)
caps->reserved_mrws = 1;
caps->reserved_uars = 0;
caps->reserved_cqs = 0;
+ caps->reserved_qps = HNS_ROCE_V2_RSV_QPS;
caps->qpc_ba_pg_sz = 0;
caps->qpc_buf_pg_sz = 0;
@@ -1255,6 +1342,11 @@ static int hns_roce_v2_profile(struct hns_roce_dev *hr_dev)
HNS_ROCE_CAP_FLAG_RQ_INLINE |
HNS_ROCE_CAP_FLAG_RECORD_DB |
HNS_ROCE_CAP_FLAG_SQ_RECORD_DB;
+
+ if (hr_dev->pci_dev->revision == 0x21)
+ caps->flags |= HNS_ROCE_CAP_FLAG_MW |
+ HNS_ROCE_CAP_FLAG_FRMR;
+
caps->pkey_table_len[0] = 1;
caps->gid_table_len[0] = HNS_ROCE_V2_GID_INDEX_NUM;
caps->ceqe_depth = HNS_ROCE_V2_COMP_EQE_NUM;
@@ -1262,6 +1354,9 @@ static int hns_roce_v2_profile(struct hns_roce_dev *hr_dev)
caps->local_ca_ack_delay = 0;
caps->max_mtu = IB_MTU_4096;
+ if (hr_dev->pci_dev->revision == 0x21)
+ caps->flags |= HNS_ROCE_CAP_FLAG_ATOMIC;
+
ret = hns_roce_v2_set_bt(hr_dev);
if (ret)
dev_err(hr_dev->dev, "Configure bt attribute fail, ret = %d.\n",
@@ -1690,10 +1785,11 @@ static int hns_roce_v2_write_mtpt(void *mb_buf, struct hns_roce_mr *mr,
roce_set_bit(mpt_entry->byte_8_mw_cnt_en, V2_MPT_BYTE_8_RA_EN_S, 0);
roce_set_bit(mpt_entry->byte_8_mw_cnt_en, V2_MPT_BYTE_8_R_INV_EN_S, 1);
- roce_set_bit(mpt_entry->byte_8_mw_cnt_en, V2_MPT_BYTE_8_L_INV_EN_S, 0);
+ roce_set_bit(mpt_entry->byte_8_mw_cnt_en, V2_MPT_BYTE_8_L_INV_EN_S, 1);
roce_set_bit(mpt_entry->byte_8_mw_cnt_en, V2_MPT_BYTE_8_BIND_EN_S,
(mr->access & IB_ACCESS_MW_BIND ? 1 : 0));
- roce_set_bit(mpt_entry->byte_8_mw_cnt_en, V2_MPT_BYTE_8_ATOMIC_EN_S, 0);
+ roce_set_bit(mpt_entry->byte_8_mw_cnt_en, V2_MPT_BYTE_8_ATOMIC_EN_S,
+ mr->access & IB_ACCESS_REMOTE_ATOMIC ? 1 : 0);
roce_set_bit(mpt_entry->byte_8_mw_cnt_en, V2_MPT_BYTE_8_RR_EN_S,
(mr->access & IB_ACCESS_REMOTE_READ ? 1 : 0));
roce_set_bit(mpt_entry->byte_8_mw_cnt_en, V2_MPT_BYTE_8_RW_EN_S,
@@ -1817,6 +1913,88 @@ static int hns_roce_v2_rereg_write_mtpt(struct hns_roce_dev *hr_dev,
return 0;
}
+static int hns_roce_v2_frmr_write_mtpt(void *mb_buf, struct hns_roce_mr *mr)
+{
+ struct hns_roce_v2_mpt_entry *mpt_entry;
+
+ mpt_entry = mb_buf;
+ memset(mpt_entry, 0, sizeof(*mpt_entry));
+
+ roce_set_field(mpt_entry->byte_4_pd_hop_st, V2_MPT_BYTE_4_MPT_ST_M,
+ V2_MPT_BYTE_4_MPT_ST_S, V2_MPT_ST_FREE);
+ roce_set_field(mpt_entry->byte_4_pd_hop_st, V2_MPT_BYTE_4_PBL_HOP_NUM_M,
+ V2_MPT_BYTE_4_PBL_HOP_NUM_S, 1);
+ roce_set_field(mpt_entry->byte_4_pd_hop_st,
+ V2_MPT_BYTE_4_PBL_BA_PG_SZ_M,
+ V2_MPT_BYTE_4_PBL_BA_PG_SZ_S,
+ mr->pbl_ba_pg_sz + PG_SHIFT_OFFSET);
+ roce_set_field(mpt_entry->byte_4_pd_hop_st, V2_MPT_BYTE_4_PD_M,
+ V2_MPT_BYTE_4_PD_S, mr->pd);
+
+ roce_set_bit(mpt_entry->byte_8_mw_cnt_en, V2_MPT_BYTE_8_RA_EN_S, 1);
+ roce_set_bit(mpt_entry->byte_8_mw_cnt_en, V2_MPT_BYTE_8_R_INV_EN_S, 1);
+ roce_set_bit(mpt_entry->byte_8_mw_cnt_en, V2_MPT_BYTE_8_L_INV_EN_S, 1);
+
+ roce_set_bit(mpt_entry->byte_12_mw_pa, V2_MPT_BYTE_12_FRE_S, 1);
+ roce_set_bit(mpt_entry->byte_12_mw_pa, V2_MPT_BYTE_12_PA_S, 0);
+ roce_set_bit(mpt_entry->byte_12_mw_pa, V2_MPT_BYTE_12_MR_MW_S, 0);
+ roce_set_bit(mpt_entry->byte_12_mw_pa, V2_MPT_BYTE_12_BPD_S, 1);
+
+ mpt_entry->pbl_size = cpu_to_le32(mr->pbl_size);
+
+ mpt_entry->pbl_ba_l = cpu_to_le32(lower_32_bits(mr->pbl_ba >> 3));
+ roce_set_field(mpt_entry->byte_48_mode_ba, V2_MPT_BYTE_48_PBL_BA_H_M,
+ V2_MPT_BYTE_48_PBL_BA_H_S,
+ upper_32_bits(mr->pbl_ba >> 3));
+
+ roce_set_field(mpt_entry->byte_64_buf_pa1,
+ V2_MPT_BYTE_64_PBL_BUF_PG_SZ_M,
+ V2_MPT_BYTE_64_PBL_BUF_PG_SZ_S,
+ mr->pbl_buf_pg_sz + PG_SHIFT_OFFSET);
+
+ return 0;
+}
+
+static int hns_roce_v2_mw_write_mtpt(void *mb_buf, struct hns_roce_mw *mw)
+{
+ struct hns_roce_v2_mpt_entry *mpt_entry;
+
+ mpt_entry = mb_buf;
+ memset(mpt_entry, 0, sizeof(*mpt_entry));
+
+ roce_set_field(mpt_entry->byte_4_pd_hop_st, V2_MPT_BYTE_4_MPT_ST_M,
+ V2_MPT_BYTE_4_MPT_ST_S, V2_MPT_ST_FREE);
+ roce_set_field(mpt_entry->byte_4_pd_hop_st, V2_MPT_BYTE_4_PD_M,
+ V2_MPT_BYTE_4_PD_S, mw->pdn);
+ roce_set_field(mpt_entry->byte_4_pd_hop_st,
+ V2_MPT_BYTE_4_PBL_HOP_NUM_M,
+ V2_MPT_BYTE_4_PBL_HOP_NUM_S,
+ mw->pbl_hop_num == HNS_ROCE_HOP_NUM_0 ?
+ 0 : mw->pbl_hop_num);
+ roce_set_field(mpt_entry->byte_4_pd_hop_st,
+ V2_MPT_BYTE_4_PBL_BA_PG_SZ_M,
+ V2_MPT_BYTE_4_PBL_BA_PG_SZ_S,
+ mw->pbl_ba_pg_sz + PG_SHIFT_OFFSET);
+
+ roce_set_bit(mpt_entry->byte_8_mw_cnt_en, V2_MPT_BYTE_8_R_INV_EN_S, 1);
+ roce_set_bit(mpt_entry->byte_8_mw_cnt_en, V2_MPT_BYTE_8_L_INV_EN_S, 1);
+
+ roce_set_bit(mpt_entry->byte_12_mw_pa, V2_MPT_BYTE_12_PA_S, 0);
+ roce_set_bit(mpt_entry->byte_12_mw_pa, V2_MPT_BYTE_12_MR_MW_S, 1);
+ roce_set_bit(mpt_entry->byte_12_mw_pa, V2_MPT_BYTE_12_BPD_S, 1);
+ roce_set_bit(mpt_entry->byte_12_mw_pa, V2_MPT_BYTE_12_BQP_S,
+ mw->ibmw.type == IB_MW_TYPE_1 ? 0 : 1);
+
+ roce_set_field(mpt_entry->byte_64_buf_pa1,
+ V2_MPT_BYTE_64_PBL_BUF_PG_SZ_M,
+ V2_MPT_BYTE_64_PBL_BUF_PG_SZ_S,
+ mw->pbl_buf_pg_sz + PG_SHIFT_OFFSET);
+
+ mpt_entry->lkey = cpu_to_le32(mw->rkey);
+
+ return 0;
+}
+
static void *get_cqe_v2(struct hns_roce_cq *hr_cq, int n)
{
return hns_roce_buf_offset(&hr_cq->hr_buf.hr_buf,
@@ -2274,6 +2452,7 @@ static int hns_roce_v2_poll_one(struct hns_roce_cq *hr_cq,
wc->src_qp = (u8)roce_get_field(cqe->byte_32,
V2_CQE_BYTE_32_RMT_QPN_M,
V2_CQE_BYTE_32_RMT_QPN_S);
+ wc->slid = 0;
wc->wc_flags |= (roce_get_bit(cqe->byte_32,
V2_CQE_BYTE_32_GRH_S) ?
IB_WC_GRH : 0);
@@ -2287,7 +2466,14 @@ static int hns_roce_v2_poll_one(struct hns_roce_cq *hr_cq,
wc->smac[5] = roce_get_field(cqe->byte_28,
V2_CQE_BYTE_28_SMAC_5_M,
V2_CQE_BYTE_28_SMAC_5_S);
- wc->vlan_id = 0xffff;
+ if (roce_get_bit(cqe->byte_28, V2_CQE_BYTE_28_VID_VLD_S)) {
+ wc->vlan_id = (u16)roce_get_field(cqe->byte_28,
+ V2_CQE_BYTE_28_VID_M,
+ V2_CQE_BYTE_28_VID_S);
+ } else {
+ wc->vlan_id = 0xffff;
+ }
+
wc->wc_flags |= (IB_WC_WITH_VLAN | IB_WC_WITH_SMAC);
wc->network_hdr_type = roce_get_field(cqe->byte_28,
V2_CQE_BYTE_28_PORT_TYPE_M,
@@ -2589,21 +2775,16 @@ static void modify_qp_reset_to_init(struct ib_qp *ibqp,
roce_set_bit(qpc_mask->byte_56_dqpn_err, V2_QPC_BYTE_56_RQ_TX_ERR_S, 0);
roce_set_bit(qpc_mask->byte_56_dqpn_err, V2_QPC_BYTE_56_RQ_RX_ERR_S, 0);
- roce_set_field(qpc_mask->byte_60_qpst_mapid, V2_QPC_BYTE_60_MAPID_M,
- V2_QPC_BYTE_60_MAPID_S, 0);
+ roce_set_field(qpc_mask->byte_60_qpst_tempid, V2_QPC_BYTE_60_TEMPID_M,
+ V2_QPC_BYTE_60_TEMPID_S, 0);
- roce_set_bit(qpc_mask->byte_60_qpst_mapid,
- V2_QPC_BYTE_60_INNER_MAP_IND_S, 0);
- roce_set_bit(qpc_mask->byte_60_qpst_mapid, V2_QPC_BYTE_60_SQ_MAP_IND_S,
- 0);
- roce_set_bit(qpc_mask->byte_60_qpst_mapid, V2_QPC_BYTE_60_RQ_MAP_IND_S,
- 0);
- roce_set_bit(qpc_mask->byte_60_qpst_mapid, V2_QPC_BYTE_60_EXT_MAP_IND_S,
- 0);
- roce_set_bit(qpc_mask->byte_60_qpst_mapid, V2_QPC_BYTE_60_SQ_RLS_IND_S,
- 0);
- roce_set_bit(qpc_mask->byte_60_qpst_mapid, V2_QPC_BYTE_60_SQ_EXT_IND_S,
- 0);
+ roce_set_field(qpc_mask->byte_60_qpst_tempid,
+ V2_QPC_BYTE_60_SCC_TOKEN_M, V2_QPC_BYTE_60_SCC_TOKEN_S,
+ 0);
+ roce_set_bit(qpc_mask->byte_60_qpst_tempid,
+ V2_QPC_BYTE_60_SQ_DB_DOING_S, 0);
+ roce_set_bit(qpc_mask->byte_60_qpst_tempid,
+ V2_QPC_BYTE_60_RQ_DB_DOING_S, 0);
roce_set_bit(qpc_mask->byte_28_at_fl, V2_QPC_BYTE_28_CNP_TX_FLAG_S, 0);
roce_set_bit(qpc_mask->byte_28_at_fl, V2_QPC_BYTE_28_CE_FLAG_S, 0);
@@ -2685,7 +2866,8 @@ static void modify_qp_reset_to_init(struct ib_qp *ibqp,
roce_set_field(qpc_mask->byte_132_trrl, V2_QPC_BYTE_132_TRRL_TAIL_MAX_M,
V2_QPC_BYTE_132_TRRL_TAIL_MAX_S, 0);
- roce_set_bit(qpc_mask->byte_140_raq, V2_QPC_BYTE_140_RSVD_RAQ_MAP_S, 0);
+ roce_set_bit(qpc_mask->byte_140_raq, V2_QPC_BYTE_140_RQ_RTY_WAIT_DO_S,
+ 0);
roce_set_field(qpc_mask->byte_140_raq, V2_QPC_BYTE_140_RAQ_TRRL_HEAD_M,
V2_QPC_BYTE_140_RAQ_TRRL_HEAD_S, 0);
roce_set_field(qpc_mask->byte_140_raq, V2_QPC_BYTE_140_RAQ_TRRL_TAIL_M,
@@ -2694,8 +2876,6 @@ static void modify_qp_reset_to_init(struct ib_qp *ibqp,
roce_set_field(qpc_mask->byte_144_raq,
V2_QPC_BYTE_144_RAQ_RTY_INI_PSN_M,
V2_QPC_BYTE_144_RAQ_RTY_INI_PSN_S, 0);
- roce_set_bit(qpc_mask->byte_144_raq, V2_QPC_BYTE_144_RAQ_RTY_INI_IND_S,
- 0);
roce_set_field(qpc_mask->byte_144_raq, V2_QPC_BYTE_144_RAQ_CREDIT_M,
V2_QPC_BYTE_144_RAQ_CREDIT_S, 0);
roce_set_bit(qpc_mask->byte_144_raq, V2_QPC_BYTE_144_RESP_RTY_FLG_S, 0);
@@ -2721,14 +2901,12 @@ static void modify_qp_reset_to_init(struct ib_qp *ibqp,
V2_QPC_BYTE_160_SQ_CONSUMER_IDX_M,
V2_QPC_BYTE_160_SQ_CONSUMER_IDX_S, 0);
- roce_set_field(context->byte_168_irrl_idx,
- V2_QPC_BYTE_168_SQ_SHIFT_BAK_M,
- V2_QPC_BYTE_168_SQ_SHIFT_BAK_S,
- ilog2((unsigned int)hr_qp->sq.wqe_cnt));
- roce_set_field(qpc_mask->byte_168_irrl_idx,
- V2_QPC_BYTE_168_SQ_SHIFT_BAK_M,
- V2_QPC_BYTE_168_SQ_SHIFT_BAK_S, 0);
-
+ roce_set_bit(qpc_mask->byte_168_irrl_idx,
+ V2_QPC_BYTE_168_POLL_DB_WAIT_DO_S, 0);
+ roce_set_bit(qpc_mask->byte_168_irrl_idx,
+ V2_QPC_BYTE_168_SCC_TOKEN_FORBID_SQ_DEQ_S, 0);
+ roce_set_bit(qpc_mask->byte_168_irrl_idx,
+ V2_QPC_BYTE_168_WAIT_ACK_TIMEOUT_S, 0);
roce_set_bit(qpc_mask->byte_168_irrl_idx,
V2_QPC_BYTE_168_MSG_RTY_LP_FLG_S, 0);
roce_set_bit(qpc_mask->byte_168_irrl_idx,
@@ -2746,6 +2924,9 @@ static void modify_qp_reset_to_init(struct ib_qp *ibqp,
roce_set_bit(qpc_mask->byte_172_sq_psn, V2_QPC_BYTE_172_MSG_RNR_FLG_S,
0);
+ roce_set_bit(context->byte_172_sq_psn, V2_QPC_BYTE_172_FRE_S, 1);
+ roce_set_bit(qpc_mask->byte_172_sq_psn, V2_QPC_BYTE_172_FRE_S, 0);
+
roce_set_field(qpc_mask->byte_176_msg_pktn,
V2_QPC_BYTE_176_MSG_USE_PKTN_M,
V2_QPC_BYTE_176_MSG_USE_PKTN_S, 0);
@@ -2790,6 +2971,13 @@ static void modify_qp_reset_to_init(struct ib_qp *ibqp,
V2_QPC_BYTE_232_IRRL_SGE_IDX_M,
V2_QPC_BYTE_232_IRRL_SGE_IDX_S, 0);
+ roce_set_bit(qpc_mask->byte_232_irrl_sge, V2_QPC_BYTE_232_SO_LP_VLD_S,
+ 0);
+ roce_set_bit(qpc_mask->byte_232_irrl_sge,
+ V2_QPC_BYTE_232_FENCE_LP_VLD_S, 0);
+ roce_set_bit(qpc_mask->byte_232_irrl_sge, V2_QPC_BYTE_232_IRRL_LP_VLD_S,
+ 0);
+
qpc_mask->irrl_cur_sge_offset = 0;
roce_set_field(qpc_mask->byte_240_irrl_tail,
@@ -2955,13 +3143,6 @@ static void modify_qp_init_to_init(struct ib_qp *ibqp,
roce_set_field(qpc_mask->byte_56_dqpn_err,
V2_QPC_BYTE_56_DQPN_M, V2_QPC_BYTE_56_DQPN_S, 0);
}
- roce_set_field(context->byte_168_irrl_idx,
- V2_QPC_BYTE_168_SQ_SHIFT_BAK_M,
- V2_QPC_BYTE_168_SQ_SHIFT_BAK_S,
- ilog2((unsigned int)hr_qp->sq.wqe_cnt));
- roce_set_field(qpc_mask->byte_168_irrl_idx,
- V2_QPC_BYTE_168_SQ_SHIFT_BAK_M,
- V2_QPC_BYTE_168_SQ_SHIFT_BAK_S, 0);
}
static int modify_qp_init_to_rtr(struct ib_qp *ibqp,
@@ -3271,13 +3452,6 @@ static int modify_qp_rtr_to_rts(struct ib_qp *ibqp,
* we should set all bits of the relevant fields in context mask to
* 0 at the same time, else set them to 0x1.
*/
- roce_set_field(context->byte_60_qpst_mapid,
- V2_QPC_BYTE_60_RTY_NUM_INI_BAK_M,
- V2_QPC_BYTE_60_RTY_NUM_INI_BAK_S, attr->retry_cnt);
- roce_set_field(qpc_mask->byte_60_qpst_mapid,
- V2_QPC_BYTE_60_RTY_NUM_INI_BAK_M,
- V2_QPC_BYTE_60_RTY_NUM_INI_BAK_S, 0);
-
context->sq_cur_blk_addr = (u32)(mtts[0] >> PAGE_ADDR_SHIFT);
roce_set_field(context->byte_168_irrl_idx,
V2_QPC_BYTE_168_SQ_CUR_BLK_ADDR_M,
@@ -3538,6 +3712,17 @@ static int hns_roce_v2_modify_qp(struct ib_qp *ibqp,
memcpy(src_mac, gid_attr->ndev->dev_addr, ETH_ALEN);
}
+ if (is_vlan_dev(gid_attr->ndev)) {
+ 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);
+ }
+
roce_set_field(context->byte_24_mtu_tc,
V2_QPC_BYTE_24_VLAN_ID_M,
V2_QPC_BYTE_24_VLAN_ID_S, vlan);
@@ -3584,8 +3769,15 @@ static int hns_roce_v2_modify_qp(struct ib_qp *ibqp,
V2_QPC_BYTE_24_HOP_LIMIT_M,
V2_QPC_BYTE_24_HOP_LIMIT_S, 0);
- roce_set_field(context->byte_24_mtu_tc, V2_QPC_BYTE_24_TC_M,
- V2_QPC_BYTE_24_TC_S, grh->traffic_class);
+ if (hr_dev->pci_dev->revision == 0x21 &&
+ gid_attr->gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP)
+ roce_set_field(context->byte_24_mtu_tc,
+ V2_QPC_BYTE_24_TC_M, V2_QPC_BYTE_24_TC_S,
+ grh->traffic_class >> 2);
+ else
+ roce_set_field(context->byte_24_mtu_tc,
+ V2_QPC_BYTE_24_TC_M, V2_QPC_BYTE_24_TC_S,
+ grh->traffic_class);
roce_set_field(qpc_mask->byte_24_mtu_tc, V2_QPC_BYTE_24_TC_M,
V2_QPC_BYTE_24_TC_S, 0);
roce_set_field(context->byte_28_at_fl, V2_QPC_BYTE_28_FL_M,
@@ -3606,9 +3798,9 @@ static int hns_roce_v2_modify_qp(struct ib_qp *ibqp,
set_access_flags(hr_qp, context, qpc_mask, attr, attr_mask);
/* Every status migrate must change state */
- roce_set_field(context->byte_60_qpst_mapid, V2_QPC_BYTE_60_QP_ST_M,
+ 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_mapid, V2_QPC_BYTE_60_QP_ST_M,
+ roce_set_field(qpc_mask->byte_60_qpst_tempid, V2_QPC_BYTE_60_QP_ST_M,
V2_QPC_BYTE_60_QP_ST_S, 0);
/* SW pass context to HW */
@@ -3728,7 +3920,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_mapid,
+ state = roce_get_field(context->byte_60_qpst_tempid,
V2_QPC_BYTE_60_QP_ST_M, V2_QPC_BYTE_60_QP_ST_S);
tmp_qp_state = to_ib_qp_st((enum hns_roce_v2_qp_state)state);
if (tmp_qp_state == -1) {
@@ -3995,13 +4187,103 @@ static void hns_roce_irq_work_handle(struct work_struct *work)
{
struct hns_roce_work *irq_work =
container_of(work, struct hns_roce_work, work);
+ struct device *dev = irq_work->hr_dev->dev;
u32 qpn = irq_work->qpn;
+ u32 cqn = irq_work->cqn;
switch (irq_work->event_type) {
+ case HNS_ROCE_EVENT_TYPE_PATH_MIG:
+ dev_info(dev, "Path migrated succeeded.\n");
+ break;
+ case HNS_ROCE_EVENT_TYPE_PATH_MIG_FAILED:
+ dev_warn(dev, "Path migration failed.\n");
+ break;
+ case HNS_ROCE_EVENT_TYPE_COMM_EST:
+ dev_info(dev, "Communication established.\n");
+ break;
+ case HNS_ROCE_EVENT_TYPE_SQ_DRAINED:
+ dev_warn(dev, "Send queue drained.\n");
+ break;
case HNS_ROCE_EVENT_TYPE_WQ_CATAS_ERROR:
+ dev_err(dev, "Local work queue catastrophic error.\n");
+ hns_roce_set_qps_to_err(irq_work->hr_dev, qpn);
+ switch (irq_work->sub_type) {
+ case HNS_ROCE_LWQCE_QPC_ERROR:
+ dev_err(dev, "QP %d, QPC error.\n", qpn);
+ break;
+ case HNS_ROCE_LWQCE_MTU_ERROR:
+ dev_err(dev, "QP %d, MTU error.\n", qpn);
+ break;
+ case HNS_ROCE_LWQCE_WQE_BA_ADDR_ERROR:
+ dev_err(dev, "QP %d, WQE BA addr error.\n", qpn);
+ break;
+ case HNS_ROCE_LWQCE_WQE_ADDR_ERROR:
+ dev_err(dev, "QP %d, WQE addr error.\n", qpn);
+ break;
+ case HNS_ROCE_LWQCE_SQ_WQE_SHIFT_ERROR:
+ dev_err(dev, "QP %d, WQE shift error.\n", qpn);
+ break;
+ default:
+ dev_err(dev, "Unhandled sub_event type %d.\n",
+ irq_work->sub_type);
+ break;
+ }
+ break;
case HNS_ROCE_EVENT_TYPE_INV_REQ_LOCAL_WQ_ERROR:
+ dev_err(dev, "Invalid request local work queue error.\n");
+ hns_roce_set_qps_to_err(irq_work->hr_dev, qpn);
+ break;
case HNS_ROCE_EVENT_TYPE_LOCAL_WQ_ACCESS_ERROR:
+ dev_err(dev, "Local access violation work queue error.\n");
hns_roce_set_qps_to_err(irq_work->hr_dev, qpn);
+ switch (irq_work->sub_type) {
+ case HNS_ROCE_LAVWQE_R_KEY_VIOLATION:
+ dev_err(dev, "QP %d, R_key violation.\n", qpn);
+ break;
+ case HNS_ROCE_LAVWQE_LENGTH_ERROR:
+ dev_err(dev, "QP %d, length error.\n", qpn);
+ break;
+ case HNS_ROCE_LAVWQE_VA_ERROR:
+ dev_err(dev, "QP %d, VA error.\n", qpn);
+ break;
+ case HNS_ROCE_LAVWQE_PD_ERROR:
+ dev_err(dev, "QP %d, PD error.\n", qpn);
+ break;
+ case HNS_ROCE_LAVWQE_RW_ACC_ERROR:
+ dev_err(dev, "QP %d, rw acc error.\n", qpn);
+ break;
+ case HNS_ROCE_LAVWQE_KEY_STATE_ERROR:
+ dev_err(dev, "QP %d, key state error.\n", qpn);
+ break;
+ case HNS_ROCE_LAVWQE_MR_OPERATION_ERROR:
+ dev_err(dev, "QP %d, MR operation error.\n", qpn);
+ break;
+ default:
+ dev_err(dev, "Unhandled sub_event type %d.\n",
+ irq_work->sub_type);
+ break;
+ }
+ break;
+ case HNS_ROCE_EVENT_TYPE_SRQ_LIMIT_REACH:
+ dev_warn(dev, "SRQ limit reach.\n");
+ break;
+ case HNS_ROCE_EVENT_TYPE_SRQ_LAST_WQE_REACH:
+ dev_warn(dev, "SRQ last wqe reach.\n");
+ break;
+ case HNS_ROCE_EVENT_TYPE_SRQ_CATAS_ERROR:
+ dev_err(dev, "SRQ catas error.\n");
+ break;
+ case HNS_ROCE_EVENT_TYPE_CQ_ACCESS_ERROR:
+ dev_err(dev, "CQ 0x%x access err.\n", cqn);
+ break;
+ case HNS_ROCE_EVENT_TYPE_CQ_OVERFLOW:
+ dev_warn(dev, "CQ 0x%x overflow\n", cqn);
+ break;
+ case HNS_ROCE_EVENT_TYPE_DB_OVERFLOW:
+ dev_warn(dev, "DB overflow.\n");
+ break;
+ case HNS_ROCE_EVENT_TYPE_FLR:
+ dev_warn(dev, "Function level reset.\n");
break;
default:
break;
@@ -4011,7 +4293,8 @@ static void hns_roce_irq_work_handle(struct work_struct *work)
}
static void hns_roce_v2_init_irq_work(struct hns_roce_dev *hr_dev,
- struct hns_roce_eq *eq, u32 qpn)
+ struct hns_roce_eq *eq,
+ u32 qpn, u32 cqn)
{
struct hns_roce_work *irq_work;
@@ -4022,6 +4305,7 @@ static void hns_roce_v2_init_irq_work(struct hns_roce_dev *hr_dev,
INIT_WORK(&(irq_work->work), hns_roce_irq_work_handle);
irq_work->hr_dev = hr_dev;
irq_work->qpn = qpn;
+ irq_work->cqn = cqn;
irq_work->event_type = eq->event_type;
irq_work->sub_type = eq->sub_type;
queue_work(hr_dev->irq_workq, &(irq_work->work));
@@ -4058,124 +4342,6 @@ static void set_eq_cons_index_v2(struct hns_roce_eq *eq)
hns_roce_write64_k(doorbell, eq->doorbell);
}
-static void hns_roce_v2_wq_catas_err_handle(struct hns_roce_dev *hr_dev,
- struct hns_roce_aeqe *aeqe,
- u32 qpn)
-{
- struct device *dev = hr_dev->dev;
- int sub_type;
-
- dev_warn(dev, "Local work queue catastrophic error.\n");
- sub_type = roce_get_field(aeqe->asyn, HNS_ROCE_V2_AEQE_SUB_TYPE_M,
- HNS_ROCE_V2_AEQE_SUB_TYPE_S);
- switch (sub_type) {
- case HNS_ROCE_LWQCE_QPC_ERROR:
- dev_warn(dev, "QP %d, QPC error.\n", qpn);
- break;
- case HNS_ROCE_LWQCE_MTU_ERROR:
- dev_warn(dev, "QP %d, MTU error.\n", qpn);
- break;
- case HNS_ROCE_LWQCE_WQE_BA_ADDR_ERROR:
- dev_warn(dev, "QP %d, WQE BA addr error.\n", qpn);
- break;
- case HNS_ROCE_LWQCE_WQE_ADDR_ERROR:
- dev_warn(dev, "QP %d, WQE addr error.\n", qpn);
- break;
- case HNS_ROCE_LWQCE_SQ_WQE_SHIFT_ERROR:
- dev_warn(dev, "QP %d, WQE shift error.\n", qpn);
- break;
- default:
- dev_err(dev, "Unhandled sub_event type %d.\n", sub_type);
- break;
- }
-}
-
-static void hns_roce_v2_local_wq_access_err_handle(struct hns_roce_dev *hr_dev,
- struct hns_roce_aeqe *aeqe, u32 qpn)
-{
- struct device *dev = hr_dev->dev;
- int sub_type;
-
- dev_warn(dev, "Local access violation work queue error.\n");
- sub_type = roce_get_field(aeqe->asyn, HNS_ROCE_V2_AEQE_SUB_TYPE_M,
- HNS_ROCE_V2_AEQE_SUB_TYPE_S);
- switch (sub_type) {
- case HNS_ROCE_LAVWQE_R_KEY_VIOLATION:
- dev_warn(dev, "QP %d, R_key violation.\n", qpn);
- break;
- case HNS_ROCE_LAVWQE_LENGTH_ERROR:
- dev_warn(dev, "QP %d, length error.\n", qpn);
- break;
- case HNS_ROCE_LAVWQE_VA_ERROR:
- dev_warn(dev, "QP %d, VA error.\n", qpn);
- break;
- case HNS_ROCE_LAVWQE_PD_ERROR:
- dev_err(dev, "QP %d, PD error.\n", qpn);
- break;
- case HNS_ROCE_LAVWQE_RW_ACC_ERROR:
- dev_warn(dev, "QP %d, rw acc error.\n", qpn);
- break;
- case HNS_ROCE_LAVWQE_KEY_STATE_ERROR:
- dev_warn(dev, "QP %d, key state error.\n", qpn);
- break;
- case HNS_ROCE_LAVWQE_MR_OPERATION_ERROR:
- dev_warn(dev, "QP %d, MR operation error.\n", qpn);
- break;
- default:
- dev_err(dev, "Unhandled sub_event type %d.\n", sub_type);
- break;
- }
-}
-
-static void hns_roce_v2_qp_err_handle(struct hns_roce_dev *hr_dev,
- struct hns_roce_aeqe *aeqe,
- int event_type, u32 qpn)
-{
- struct device *dev = hr_dev->dev;
-
- switch (event_type) {
- case HNS_ROCE_EVENT_TYPE_COMM_EST:
- dev_warn(dev, "Communication established.\n");
- break;
- case HNS_ROCE_EVENT_TYPE_SQ_DRAINED:
- dev_warn(dev, "Send queue drained.\n");
- break;
- case HNS_ROCE_EVENT_TYPE_WQ_CATAS_ERROR:
- hns_roce_v2_wq_catas_err_handle(hr_dev, aeqe, qpn);
- break;
- case HNS_ROCE_EVENT_TYPE_INV_REQ_LOCAL_WQ_ERROR:
- dev_warn(dev, "Invalid request local work queue error.\n");
- break;
- case HNS_ROCE_EVENT_TYPE_LOCAL_WQ_ACCESS_ERROR:
- hns_roce_v2_local_wq_access_err_handle(hr_dev, aeqe, qpn);
- break;
- default:
- break;
- }
-
- hns_roce_qp_event(hr_dev, qpn, event_type);
-}
-
-static void hns_roce_v2_cq_err_handle(struct hns_roce_dev *hr_dev,
- struct hns_roce_aeqe *aeqe,
- int event_type, u32 cqn)
-{
- struct device *dev = hr_dev->dev;
-
- switch (event_type) {
- case HNS_ROCE_EVENT_TYPE_CQ_ACCESS_ERROR:
- dev_warn(dev, "CQ 0x%x access err.\n", cqn);
- break;
- case HNS_ROCE_EVENT_TYPE_CQ_OVERFLOW:
- dev_warn(dev, "CQ 0x%x overflow\n", cqn);
- break;
- default:
- break;
- }
-
- hns_roce_cq_event(hr_dev, cqn, event_type);
-}
-
static struct hns_roce_aeqe *get_aeqe_v2(struct hns_roce_eq *eq, u32 entry)
{
u32 buf_chk_sz;
@@ -4251,31 +4417,23 @@ static int hns_roce_v2_aeq_int(struct hns_roce_dev *hr_dev,
switch (event_type) {
case HNS_ROCE_EVENT_TYPE_PATH_MIG:
- dev_warn(dev, "Path migrated succeeded.\n");
- break;
case HNS_ROCE_EVENT_TYPE_PATH_MIG_FAILED:
- dev_warn(dev, "Path migration failed.\n");
- break;
case HNS_ROCE_EVENT_TYPE_COMM_EST:
case HNS_ROCE_EVENT_TYPE_SQ_DRAINED:
case HNS_ROCE_EVENT_TYPE_WQ_CATAS_ERROR:
case HNS_ROCE_EVENT_TYPE_INV_REQ_LOCAL_WQ_ERROR:
case HNS_ROCE_EVENT_TYPE_LOCAL_WQ_ACCESS_ERROR:
- hns_roce_v2_qp_err_handle(hr_dev, aeqe, event_type,
- qpn);
+ hns_roce_qp_event(hr_dev, qpn, event_type);
break;
case HNS_ROCE_EVENT_TYPE_SRQ_LIMIT_REACH:
case HNS_ROCE_EVENT_TYPE_SRQ_LAST_WQE_REACH:
case HNS_ROCE_EVENT_TYPE_SRQ_CATAS_ERROR:
- dev_warn(dev, "SRQ not support.\n");
break;
case HNS_ROCE_EVENT_TYPE_CQ_ACCESS_ERROR:
case HNS_ROCE_EVENT_TYPE_CQ_OVERFLOW:
- hns_roce_v2_cq_err_handle(hr_dev, aeqe, event_type,
- cqn);
+ hns_roce_cq_event(hr_dev, cqn, event_type);
break;
case HNS_ROCE_EVENT_TYPE_DB_OVERFLOW:
- dev_warn(dev, "DB overflow.\n");
break;
case HNS_ROCE_EVENT_TYPE_MB:
hns_roce_cmd_event(hr_dev,
@@ -4284,10 +4442,8 @@ static int hns_roce_v2_aeq_int(struct hns_roce_dev *hr_dev,
le64_to_cpu(aeqe->event.cmd.out_param));
break;
case HNS_ROCE_EVENT_TYPE_CEQ_OVERFLOW:
- dev_warn(dev, "CEQ overflow.\n");
break;
case HNS_ROCE_EVENT_TYPE_FLR:
- dev_warn(dev, "Function level reset.\n");
break;
default:
dev_err(dev, "Unhandled event %d on EQ %d at idx %u.\n",
@@ -4304,7 +4460,7 @@ static int hns_roce_v2_aeq_int(struct hns_roce_dev *hr_dev,
dev_warn(dev, "cons_index overflow, set back to 0.\n");
eq->cons_index = 0;
}
- hns_roce_v2_init_irq_work(hr_dev, eq, qpn);
+ hns_roce_v2_init_irq_work(hr_dev, eq, qpn, cqn);
}
set_eq_cons_index_v2(eq);
@@ -5125,6 +5281,7 @@ static int hns_roce_v2_init_eq_table(struct hns_roce_dev *hr_dev)
create_singlethread_workqueue("hns_roce_irq_workqueue");
if (!hr_dev->irq_workq) {
dev_err(dev, "Create irq workqueue failed!\n");
+ ret = -ENOMEM;
goto err_request_irq_fail;
}
@@ -5195,6 +5352,8 @@ static const struct hns_roce_hw hns_roce_hw_v2 = {
.set_mac = hns_roce_v2_set_mac,
.write_mtpt = hns_roce_v2_write_mtpt,
.rereg_write_mtpt = hns_roce_v2_rereg_write_mtpt,
+ .frmr_write_mtpt = hns_roce_v2_frmr_write_mtpt,
+ .mw_write_mtpt = hns_roce_v2_mw_write_mtpt,
.write_cqc = hns_roce_v2_write_cqc,
.set_hem = hns_roce_v2_set_hem,
.clear_hem = hns_roce_v2_clear_hem,
diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h
index 14aa308befef..8bc820635bbd 100644
--- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h
+++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h
@@ -50,6 +50,7 @@
#define HNS_ROCE_V2_MAX_CQE_NUM 0x10000
#define HNS_ROCE_V2_MAX_RQ_SGE_NUM 0x100
#define HNS_ROCE_V2_MAX_SQ_SGE_NUM 0xff
+#define HNS_ROCE_V2_MAX_EXTEND_SGE_NUM 0x200000
#define HNS_ROCE_V2_MAX_SQ_INLINE 0x20
#define HNS_ROCE_V2_UAR_NUM 256
#define HNS_ROCE_V2_PHY_UAR_NUM 1
@@ -78,6 +79,7 @@
#define HNS_ROCE_INVALID_LKEY 0x100
#define HNS_ROCE_CMQ_TX_TIMEOUT 30000
#define HNS_ROCE_V2_UC_RC_SGE_NUM_IN_WQE 2
+#define HNS_ROCE_V2_RSV_QPS 8
#define HNS_ROCE_CONTEXT_HOP_NUM 1
#define HNS_ROCE_MTT_HOP_NUM 1
@@ -201,6 +203,7 @@ enum {
/* CMQ command */
enum hns_roce_opcode_type {
+ HNS_QUERY_FW_VER = 0x0001,
HNS_ROCE_OPC_QUERY_HW_VER = 0x8000,
HNS_ROCE_OPC_CFG_GLOBAL_PARAM = 0x8001,
HNS_ROCE_OPC_ALLOC_PF_RES = 0x8004,
@@ -324,6 +327,7 @@ struct hns_roce_v2_cq_context {
enum{
V2_MPT_ST_VALID = 0x1,
+ V2_MPT_ST_FREE = 0x2,
};
enum hns_roce_v2_qp_state {
@@ -350,7 +354,7 @@ struct hns_roce_v2_qp_context {
__le32 dmac;
__le32 byte_52_udpspn_dmac;
__le32 byte_56_dqpn_err;
- __le32 byte_60_qpst_mapid;
+ __le32 byte_60_qpst_tempid;
__le32 qkey_xrcd;
__le32 byte_68_rq_db;
__le32 rq_db_record_addr;
@@ -492,26 +496,15 @@ struct hns_roce_v2_qp_context {
#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_MAPID_S 0
-#define V2_QPC_BYTE_60_MAPID_M GENMASK(12, 0)
+#define V2_QPC_BYTE_60_TEMPID_S 0
+#define V2_QPC_BYTE_60_TEMPID_M GENMASK(7, 0)
-#define V2_QPC_BYTE_60_INNER_MAP_IND_S 13
+#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_MAP_IND_S 14
+#define V2_QPC_BYTE_60_SQ_DB_DOING_S 27
-#define V2_QPC_BYTE_60_RQ_MAP_IND_S 15
-
-#define V2_QPC_BYTE_60_TEMPID_S 16
-#define V2_QPC_BYTE_60_TEMPID_M GENMASK(22, 16)
-
-#define V2_QPC_BYTE_60_EXT_MAP_IND_S 23
-
-#define V2_QPC_BYTE_60_RTY_NUM_INI_BAK_S 24
-#define V2_QPC_BYTE_60_RTY_NUM_INI_BAK_M GENMASK(26, 24)
-
-#define V2_QPC_BYTE_60_SQ_RLS_IND_S 27
-
-#define V2_QPC_BYTE_60_SQ_EXT_IND_S 28
+#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)
@@ -534,6 +527,7 @@ struct hns_roce_v2_qp_context {
#define V2_QPC_BYTE_76_RQIE_S 28
+#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)
@@ -588,7 +582,7 @@ struct hns_roce_v2_qp_context {
#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_RSVD_RAQ_MAP_S 15
+#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)
@@ -599,8 +593,6 @@ struct hns_roce_v2_qp_context {
#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_RTY_INI_IND_S 24
-
#define V2_QPC_BYTE_144_RAQ_CREDIT_S 25
#define V2_QPC_BYTE_144_RAQ_CREDIT_M GENMASK(29, 25)
@@ -637,9 +629,10 @@ struct hns_roce_v2_qp_context {
#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_SHIFT_BAK_S 24
-#define V2_QPC_BYTE_168_SQ_SHIFT_BAK_M GENMASK(27, 24)
-
+#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)
@@ -725,6 +718,10 @@ struct hns_roce_v2_qp_context {
#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)
@@ -743,6 +740,9 @@ struct hns_roce_v2_qp_context {
#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)
@@ -818,6 +818,11 @@ struct hns_roce_v2_cqe {
#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)
@@ -878,8 +883,19 @@ struct hns_roce_v2_mpt_entry {
#define V2_MPT_BYTE_8_LW_EN_S 7
+#define V2_MPT_BYTE_8_MW_CNT_S 8
+#define V2_MPT_BYTE_8_MW_CNT_M GENMASK(31, 8)
+
+#define V2_MPT_BYTE_12_FRE_S 0
+
#define V2_MPT_BYTE_12_PA_S 1
+#define V2_MPT_BYTE_12_MR_MW_S 4
+
+#define V2_MPT_BYTE_12_BPD_S 5
+
+#define V2_MPT_BYTE_12_BQP_S 6
+
#define V2_MPT_BYTE_12_INNER_PA_VLD_S 7
#define V2_MPT_BYTE_12_MW_BIND_QPN_S 8
@@ -988,6 +1004,8 @@ struct hns_roce_v2_ud_send_wqe {
#define V2_UD_SEND_WQE_BYTE_40_PORTN_S 24
#define V2_UD_SEND_WQE_BYTE_40_PORTN_M GENMASK(26, 24)
+#define V2_UD_SEND_WQE_BYTE_40_UD_VLAN_EN_S 30
+
#define V2_UD_SEND_WQE_BYTE_40_LBI_S 31
#define V2_UD_SEND_WQE_DMAC_0_S 0
@@ -1042,6 +1060,16 @@ struct hns_roce_v2_rc_send_wqe {
#define V2_RC_SEND_WQE_BYTE_4_INLINE_S 12
+#define V2_RC_FRMR_WQE_BYTE_4_BIND_EN_S 19
+
+#define V2_RC_FRMR_WQE_BYTE_4_ATOMIC_S 20
+
+#define V2_RC_FRMR_WQE_BYTE_4_RR_S 21
+
+#define V2_RC_FRMR_WQE_BYTE_4_RW_S 22
+
+#define V2_RC_FRMR_WQE_BYTE_4_LW_S 23
+
#define V2_RC_SEND_WQE_BYTE_16_XRC_SRQN_S 0
#define V2_RC_SEND_WQE_BYTE_16_XRC_SRQN_M GENMASK(23, 0)
@@ -1051,6 +1079,16 @@ struct hns_roce_v2_rc_send_wqe {
#define V2_RC_SEND_WQE_BYTE_20_MSG_START_SGE_IDX_S 0
#define V2_RC_SEND_WQE_BYTE_20_MSG_START_SGE_IDX_M GENMASK(23, 0)
+struct hns_roce_wqe_frmr_seg {
+ __le32 pbl_size;
+ __le32 mode_buf_pg_sz;
+};
+
+#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 V2_RC_FRMR_WQE_BYTE_40_BLK_MODE_S 8
+
struct hns_roce_v2_wqe_data_seg {
__le32 len;
__le32 lkey;
@@ -1068,6 +1106,11 @@ struct hns_roce_query_version {
__le32 rsv[5];
};
+struct hns_roce_query_fw_info {
+ __le32 fw_ver;
+ __le32 rsv[5];
+};
+
struct hns_roce_cfg_llm_a {
__le32 base_addr_l;
__le32 base_addr_h;
@@ -1564,4 +1607,9 @@ struct hns_roce_eq_context {
#define HNS_ROCE_V2_AEQE_EVENT_QUEUE_NUM_S 0
#define HNS_ROCE_V2_AEQE_EVENT_QUEUE_NUM_M GENMASK(23, 0)
+struct hns_roce_wqe_atomic_seg {
+ __le64 fetchadd_swap_data;
+ __le64 cmp_data;
+};
+
#endif
diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c
index c5cae9a38c04..1b3ee514f2ef 100644
--- a/drivers/infiniband/hw/hns/hns_roce_main.c
+++ b/drivers/infiniband/hw/hns/hns_roce_main.c
@@ -196,6 +196,7 @@ static int hns_roce_query_device(struct ib_device *ib_dev,
memset(props, 0, sizeof(*props));
+ props->fw_ver = hr_dev->caps.fw_ver;
props->sys_image_guid = cpu_to_be64(hr_dev->sys_image_guid);
props->max_mr_size = (u64)(~(0ULL));
props->page_size_cap = hr_dev->caps.page_size_cap;
@@ -215,7 +216,8 @@ static int hns_roce_query_device(struct ib_device *ib_dev,
props->max_pd = hr_dev->caps.num_pds;
props->max_qp_rd_atom = hr_dev->caps.max_qp_dest_rdma;
props->max_qp_init_rd_atom = hr_dev->caps.max_qp_init_rdma;
- props->atomic_cap = IB_ATOMIC_NONE;
+ props->atomic_cap = hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_ATOMIC ?
+ IB_ATOMIC_HCA : IB_ATOMIC_NONE;
props->max_pkeys = 1;
props->local_ca_ack_delay = hr_dev->caps.local_ca_ack_delay;
@@ -344,8 +346,6 @@ static struct ib_ucontext *hns_roce_alloc_ucontext(struct ib_device *ib_dev,
if (ret)
goto error_fail_uar_alloc;
- INIT_LIST_HEAD(&context->vma_list);
- mutex_init(&context->vma_list_mutex);
if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RECORD_DB) {
INIT_LIST_HEAD(&context->page_list);
mutex_init(&context->page_mutex);
@@ -376,76 +376,34 @@ static int hns_roce_dealloc_ucontext(struct ib_ucontext *ibcontext)
return 0;
}
-static void hns_roce_vma_open(struct vm_area_struct *vma)
-{
- vma->vm_ops = NULL;
-}
-
-static void hns_roce_vma_close(struct vm_area_struct *vma)
-{
- struct hns_roce_vma_data *vma_data;
-
- vma_data = (struct hns_roce_vma_data *)vma->vm_private_data;
- vma_data->vma = NULL;
- mutex_lock(vma_data->vma_list_mutex);
- list_del(&vma_data->list);
- mutex_unlock(vma_data->vma_list_mutex);
- kfree(vma_data);
-}
-
-static const struct vm_operations_struct hns_roce_vm_ops = {
- .open = hns_roce_vma_open,
- .close = hns_roce_vma_close,
-};
-
-static int hns_roce_set_vma_data(struct vm_area_struct *vma,
- struct hns_roce_ucontext *context)
-{
- struct list_head *vma_head = &context->vma_list;
- struct hns_roce_vma_data *vma_data;
-
- vma_data = kzalloc(sizeof(*vma_data), GFP_KERNEL);
- if (!vma_data)
- return -ENOMEM;
-
- vma_data->vma = vma;
- vma_data->vma_list_mutex = &context->vma_list_mutex;
- vma->vm_private_data = vma_data;
- vma->vm_ops = &hns_roce_vm_ops;
-
- mutex_lock(&context->vma_list_mutex);
- list_add(&vma_data->list, vma_head);
- mutex_unlock(&context->vma_list_mutex);
-
- return 0;
-}
-
static int hns_roce_mmap(struct ib_ucontext *context,
struct vm_area_struct *vma)
{
struct hns_roce_dev *hr_dev = to_hr_dev(context->device);
- if (((vma->vm_end - vma->vm_start) % PAGE_SIZE) != 0)
- return -EINVAL;
+ switch (vma->vm_pgoff) {
+ case 0:
+ return rdma_user_mmap_io(context, vma,
+ to_hr_ucontext(context)->uar.pfn,
+ PAGE_SIZE,
+ pgprot_noncached(vma->vm_page_prot));
+
+ /* vm_pgoff: 1 -- TPTR */
+ case 1:
+ if (!hr_dev->tptr_dma_addr || !hr_dev->tptr_size)
+ return -EINVAL;
+ /*
+ * FIXME: using io_remap_pfn_range on the dma address returned
+ * by dma_alloc_coherent is totally wrong.
+ */
+ return rdma_user_mmap_io(context, vma,
+ hr_dev->tptr_dma_addr >> PAGE_SHIFT,
+ hr_dev->tptr_size,
+ vma->vm_page_prot);
- if (vma->vm_pgoff == 0) {
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- if (io_remap_pfn_range(vma, vma->vm_start,
- to_hr_ucontext(context)->uar.pfn,
- PAGE_SIZE, vma->vm_page_prot))
- return -EAGAIN;
- } else if (vma->vm_pgoff == 1 && hr_dev->tptr_dma_addr &&
- hr_dev->tptr_size) {
- /* vm_pgoff: 1 -- TPTR */
- if (io_remap_pfn_range(vma, vma->vm_start,
- hr_dev->tptr_dma_addr >> PAGE_SHIFT,
- hr_dev->tptr_size,
- vma->vm_page_prot))
- return -EAGAIN;
- } else
+ default:
return -EINVAL;
-
- return hns_roce_set_vma_data(vma, to_hr_ucontext(context));
+ }
}
static int hns_roce_port_immutable(struct ib_device *ib_dev, u8 port_num,
@@ -471,21 +429,6 @@ static int hns_roce_port_immutable(struct ib_device *ib_dev, u8 port_num,
static void hns_roce_disassociate_ucontext(struct ib_ucontext *ibcontext)
{
- struct hns_roce_ucontext *context = to_hr_ucontext(ibcontext);
- struct hns_roce_vma_data *vma_data, *n;
- struct vm_area_struct *vma;
-
- mutex_lock(&context->vma_list_mutex);
- list_for_each_entry_safe(vma_data, n, &context->vma_list, list) {
- vma = vma_data->vma;
- zap_vma_ptes(vma, vma->vm_start, PAGE_SIZE);
-
- vma->vm_flags &= ~(VM_SHARED | VM_MAYSHARE);
- vma->vm_ops = NULL;
- list_del(&vma_data->list);
- kfree(vma_data);
- }
- mutex_unlock(&context->vma_list_mutex);
}
static void hns_roce_unregister_device(struct hns_roce_dev *hr_dev)
@@ -508,7 +451,6 @@ static int hns_roce_register_device(struct hns_roce_dev *hr_dev)
spin_lock_init(&iboe->lock);
ib_dev = &hr_dev->ib_dev;
- strlcpy(ib_dev->name, "hns_%d", IB_DEVICE_NAME_MAX);
ib_dev->owner = THIS_MODULE;
ib_dev->node_type = RDMA_NODE_IB_CA;
@@ -584,12 +526,27 @@ static int hns_roce_register_device(struct hns_roce_dev *hr_dev)
ib_dev->uverbs_cmd_mask |= (1ULL << IB_USER_VERBS_CMD_REREG_MR);
}
+ /* MW */
+ if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_MW) {
+ ib_dev->alloc_mw = hns_roce_alloc_mw;
+ ib_dev->dealloc_mw = hns_roce_dealloc_mw;
+ ib_dev->uverbs_cmd_mask |=
+ (1ULL << IB_USER_VERBS_CMD_ALLOC_MW) |
+ (1ULL << IB_USER_VERBS_CMD_DEALLOC_MW);
+ }
+
+ /* FRMR */
+ if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_FRMR) {
+ ib_dev->alloc_mr = hns_roce_alloc_mr;
+ ib_dev->map_mr_sg = hns_roce_map_mr_sg;
+ }
+
/* OTHERS */
ib_dev->get_port_immutable = hns_roce_port_immutable;
ib_dev->disassociate_ucontext = hns_roce_disassociate_ucontext;
ib_dev->driver_id = RDMA_DRIVER_HNS;
- ret = ib_register_device(ib_dev, NULL);
+ ret = ib_register_device(ib_dev, "hns_%d", NULL);
if (ret) {
dev_err(dev, "ib_register_device failed!\n");
return ret;
diff --git a/drivers/infiniband/hw/hns/hns_roce_mr.c b/drivers/infiniband/hw/hns/hns_roce_mr.c
index eb26a5f6fc58..521ad2aa3a4e 100644
--- a/drivers/infiniband/hw/hns/hns_roce_mr.c
+++ b/drivers/infiniband/hw/hns/hns_roce_mr.c
@@ -329,7 +329,7 @@ static int hns_roce_mhop_alloc(struct hns_roce_dev *hr_dev, int npages,
u64 bt_idx;
u64 size;
- mhop_num = hr_dev->caps.pbl_hop_num;
+ mhop_num = (mr->type == MR_TYPE_FRMR ? 1 : hr_dev->caps.pbl_hop_num);
pbl_bt_sz = 1 << (hr_dev->caps.pbl_ba_pg_sz + PAGE_SHIFT);
pbl_last_bt_num = (npages + pbl_bt_sz / 8 - 1) / (pbl_bt_sz / 8);
@@ -351,7 +351,7 @@ static int hns_roce_mhop_alloc(struct hns_roce_dev *hr_dev, int npages,
mr->pbl_size = npages;
mr->pbl_ba = mr->pbl_dma_addr;
- mr->pbl_hop_num = hr_dev->caps.pbl_hop_num;
+ mr->pbl_hop_num = mhop_num;
mr->pbl_ba_pg_sz = hr_dev->caps.pbl_ba_pg_sz;
mr->pbl_buf_pg_sz = hr_dev->caps.pbl_buf_pg_sz;
return 0;
@@ -511,7 +511,6 @@ static int hns_roce_mr_alloc(struct hns_roce_dev *hr_dev, u32 pd, u64 iova,
mr->key = hw_index_to_key(index); /* MR key */
if (size == ~0ull) {
- mr->type = MR_TYPE_DMA;
mr->pbl_buf = NULL;
mr->pbl_dma_addr = 0;
/* PBL multi-hop addressing parameters */
@@ -522,7 +521,6 @@ static int hns_roce_mr_alloc(struct hns_roce_dev *hr_dev, u32 pd, u64 iova,
mr->pbl_l1_dma_addr = NULL;
mr->pbl_l0_dma_addr = 0;
} else {
- mr->type = MR_TYPE_MR;
if (!hr_dev->caps.pbl_hop_num) {
mr->pbl_buf = dma_alloc_coherent(dev, npages * 8,
&(mr->pbl_dma_addr),
@@ -548,9 +546,9 @@ static void hns_roce_mhop_free(struct hns_roce_dev *hr_dev,
u32 mhop_num;
u64 bt_idx;
- npages = ib_umem_page_count(mr->umem);
+ npages = mr->pbl_size;
pbl_bt_sz = 1 << (hr_dev->caps.pbl_ba_pg_sz + PAGE_SHIFT);
- mhop_num = hr_dev->caps.pbl_hop_num;
+ mhop_num = (mr->type == MR_TYPE_FRMR) ? 1 : hr_dev->caps.pbl_hop_num;
if (mhop_num == HNS_ROCE_HOP_NUM_0)
return;
@@ -636,7 +634,8 @@ static void hns_roce_mr_free(struct hns_roce_dev *hr_dev,
}
if (mr->size != ~0ULL) {
- npages = ib_umem_page_count(mr->umem);
+ if (mr->type == MR_TYPE_MR)
+ npages = ib_umem_page_count(mr->umem);
if (!hr_dev->caps.pbl_hop_num)
dma_free_coherent(dev, (unsigned int)(npages * 8),
@@ -674,7 +673,10 @@ static int hns_roce_mr_enable(struct hns_roce_dev *hr_dev,
goto err_table;
}
- ret = hr_dev->hw->write_mtpt(mailbox->buf, mr, mtpt_idx);
+ if (mr->type != MR_TYPE_FRMR)
+ ret = hr_dev->hw->write_mtpt(mailbox->buf, mr, mtpt_idx);
+ else
+ ret = hr_dev->hw->frmr_write_mtpt(mailbox->buf, mr);
if (ret) {
dev_err(dev, "Write mtpt fail!\n");
goto err_page;
@@ -855,6 +857,8 @@ struct ib_mr *hns_roce_get_dma_mr(struct ib_pd *pd, int acc)
if (mr == NULL)
return ERR_PTR(-ENOMEM);
+ mr->type = MR_TYPE_DMA;
+
/* Allocate memory region key */
ret = hns_roce_mr_alloc(to_hr_dev(pd->device), to_hr_pd(pd)->pdn, 0,
~0ULL, acc, 0, mr);
@@ -1031,6 +1035,8 @@ struct ib_mr *hns_roce_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
}
}
+ mr->type = MR_TYPE_MR;
+
ret = hns_roce_mr_alloc(hr_dev, to_hr_pd(pd)->pdn, virt_addr, length,
access_flags, n, mr);
if (ret)
@@ -1201,3 +1207,193 @@ int hns_roce_dereg_mr(struct ib_mr *ibmr)
return ret;
}
+
+struct ib_mr *hns_roce_alloc_mr(struct ib_pd *pd, enum ib_mr_type mr_type,
+ u32 max_num_sg)
+{
+ struct hns_roce_dev *hr_dev = to_hr_dev(pd->device);
+ struct device *dev = hr_dev->dev;
+ struct hns_roce_mr *mr;
+ u64 length;
+ u32 page_size;
+ int ret;
+
+ page_size = 1 << (hr_dev->caps.pbl_buf_pg_sz + PAGE_SHIFT);
+ length = max_num_sg * page_size;
+
+ if (mr_type != IB_MR_TYPE_MEM_REG)
+ return ERR_PTR(-EINVAL);
+
+ if (max_num_sg > HNS_ROCE_FRMR_MAX_PA) {
+ dev_err(dev, "max_num_sg larger than %d\n",
+ HNS_ROCE_FRMR_MAX_PA);
+ return ERR_PTR(-EINVAL);
+ }
+
+ mr = kzalloc(sizeof(*mr), GFP_KERNEL);
+ if (!mr)
+ return ERR_PTR(-ENOMEM);
+
+ mr->type = MR_TYPE_FRMR;
+
+ /* Allocate memory region key */
+ ret = hns_roce_mr_alloc(hr_dev, to_hr_pd(pd)->pdn, 0, length,
+ 0, max_num_sg, mr);
+ if (ret)
+ goto err_free;
+
+ ret = hns_roce_mr_enable(hr_dev, mr);
+ if (ret)
+ goto err_mr;
+
+ mr->ibmr.rkey = mr->ibmr.lkey = mr->key;
+ mr->umem = NULL;
+
+ return &mr->ibmr;
+
+err_mr:
+ hns_roce_mr_free(to_hr_dev(pd->device), mr);
+
+err_free:
+ kfree(mr);
+ return ERR_PTR(ret);
+}
+
+static int hns_roce_set_page(struct ib_mr *ibmr, u64 addr)
+{
+ struct hns_roce_mr *mr = to_hr_mr(ibmr);
+
+ mr->pbl_buf[mr->npages++] = cpu_to_le64(addr);
+
+ return 0;
+}
+
+int hns_roce_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, int sg_nents,
+ unsigned int *sg_offset)
+{
+ struct hns_roce_mr *mr = to_hr_mr(ibmr);
+
+ mr->npages = 0;
+
+ return ib_sg_to_pages(ibmr, sg, sg_nents, sg_offset, hns_roce_set_page);
+}
+
+static void hns_roce_mw_free(struct hns_roce_dev *hr_dev,
+ struct hns_roce_mw *mw)
+{
+ struct device *dev = hr_dev->dev;
+ int ret;
+
+ if (mw->enabled) {
+ ret = hns_roce_hw2sw_mpt(hr_dev, NULL, key_to_hw_index(mw->rkey)
+ & (hr_dev->caps.num_mtpts - 1));
+ if (ret)
+ dev_warn(dev, "MW HW2SW_MPT failed (%d)\n", ret);
+
+ hns_roce_table_put(hr_dev, &hr_dev->mr_table.mtpt_table,
+ 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);
+}
+
+static int hns_roce_mw_enable(struct hns_roce_dev *hr_dev,
+ struct hns_roce_mw *mw)
+{
+ struct hns_roce_mr_table *mr_table = &hr_dev->mr_table;
+ struct hns_roce_cmd_mailbox *mailbox;
+ struct device *dev = hr_dev->dev;
+ unsigned long mtpt_idx = key_to_hw_index(mw->rkey);
+ int ret;
+
+ /* prepare HEM entry memory */
+ ret = hns_roce_table_get(hr_dev, &mr_table->mtpt_table, mtpt_idx);
+ if (ret)
+ return ret;
+
+ mailbox = hns_roce_alloc_cmd_mailbox(hr_dev);
+ if (IS_ERR(mailbox)) {
+ ret = PTR_ERR(mailbox);
+ goto err_table;
+ }
+
+ ret = hr_dev->hw->mw_write_mtpt(mailbox->buf, mw);
+ if (ret) {
+ dev_err(dev, "MW write mtpt fail!\n");
+ goto err_page;
+ }
+
+ ret = hns_roce_sw2hw_mpt(hr_dev, mailbox,
+ mtpt_idx & (hr_dev->caps.num_mtpts - 1));
+ if (ret) {
+ dev_err(dev, "MW sw2hw_mpt failed (%d)\n", ret);
+ goto err_page;
+ }
+
+ mw->enabled = 1;
+
+ hns_roce_free_cmd_mailbox(hr_dev, mailbox);
+
+ return 0;
+
+err_page:
+ hns_roce_free_cmd_mailbox(hr_dev, mailbox);
+
+err_table:
+ hns_roce_table_put(hr_dev, &mr_table->mtpt_table, mtpt_idx);
+
+ return ret;
+}
+
+struct ib_mw *hns_roce_alloc_mw(struct ib_pd *ib_pd, enum ib_mw_type type,
+ struct ib_udata *udata)
+{
+ struct hns_roce_dev *hr_dev = to_hr_dev(ib_pd->device);
+ struct hns_roce_mw *mw;
+ unsigned long index = 0;
+ int ret;
+
+ mw = kmalloc(sizeof(*mw), GFP_KERNEL);
+ if (!mw)
+ return ERR_PTR(-ENOMEM);
+
+ /* Allocate a key for mw from bitmap */
+ ret = hns_roce_bitmap_alloc(&hr_dev->mr_table.mtpt_bitmap, &index);
+ if (ret)
+ goto err_bitmap;
+
+ mw->rkey = hw_index_to_key(index);
+
+ mw->ibmw.rkey = mw->rkey;
+ mw->ibmw.type = type;
+ mw->pdn = to_hr_pd(ib_pd)->pdn;
+ mw->pbl_hop_num = hr_dev->caps.pbl_hop_num;
+ mw->pbl_ba_pg_sz = hr_dev->caps.pbl_ba_pg_sz;
+ mw->pbl_buf_pg_sz = hr_dev->caps.pbl_buf_pg_sz;
+
+ ret = hns_roce_mw_enable(hr_dev, mw);
+ if (ret)
+ goto err_mw;
+
+ return &mw->ibmw;
+
+err_mw:
+ hns_roce_mw_free(hr_dev, mw);
+
+err_bitmap:
+ kfree(mw);
+
+ return ERR_PTR(ret);
+}
+
+int hns_roce_dealloc_mw(struct ib_mw *ibmw)
+{
+ struct hns_roce_dev *hr_dev = to_hr_dev(ibmw->device);
+ struct hns_roce_mw *mw = to_hr_mw(ibmw);
+
+ hns_roce_mw_free(hr_dev, mw);
+ kfree(mw);
+
+ return 0;
+}
diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c
index efb7e961ca65..5ebf481a39d9 100644
--- a/drivers/infiniband/hw/hns/hns_roce_qp.c
+++ b/drivers/infiniband/hw/hns/hns_roce_qp.c
@@ -31,6 +31,7 @@
* SOFTWARE.
*/
+#include <linux/pci.h>
#include <linux/platform_device.h>
#include <rdma/ib_addr.h>
#include <rdma/ib_umem.h>
@@ -343,6 +344,7 @@ static int hns_roce_set_user_sq_size(struct hns_roce_dev *hr_dev,
{
u32 roundup_sq_stride = roundup_pow_of_two(hr_dev->caps.max_sq_desc_sz);
u8 max_sq_stride = ilog2(roundup_sq_stride);
+ u32 ex_sge_num;
u32 page_size;
u32 max_cnt;
@@ -372,7 +374,18 @@ static int hns_roce_set_user_sq_size(struct hns_roce_dev *hr_dev,
if (hr_qp->sq.max_gs > 2)
hr_qp->sge.sge_cnt = roundup_pow_of_two(hr_qp->sq.wqe_cnt *
(hr_qp->sq.max_gs - 2));
+
+ if ((hr_qp->sq.max_gs > 2) && (hr_dev->pci_dev->revision == 0x20)) {
+ if (hr_qp->sge.sge_cnt > hr_dev->caps.max_extend_sg) {
+ dev_err(hr_dev->dev,
+ "The extended sge cnt error! sge_cnt=%d\n",
+ hr_qp->sge.sge_cnt);
+ return -EINVAL;
+ }
+ }
+
hr_qp->sge.sge_shift = 4;
+ ex_sge_num = hr_qp->sge.sge_cnt;
/* Get buf size, SQ and RQ are aligned to page_szie */
if (hr_dev->caps.max_sq_sg <= 2) {
@@ -386,6 +399,8 @@ static int hns_roce_set_user_sq_size(struct hns_roce_dev *hr_dev,
hr_qp->sq.wqe_shift), PAGE_SIZE);
} else {
page_size = 1 << (hr_dev->caps.mtt_buf_pg_sz + PAGE_SHIFT);
+ hr_qp->sge.sge_cnt =
+ max(page_size / (1 << hr_qp->sge.sge_shift), ex_sge_num);
hr_qp->buff_size = HNS_ROCE_ALOGN_UP((hr_qp->rq.wqe_cnt <<
hr_qp->rq.wqe_shift), page_size) +
HNS_ROCE_ALOGN_UP((hr_qp->sge.sge_cnt <<
@@ -394,7 +409,7 @@ static int hns_roce_set_user_sq_size(struct hns_roce_dev *hr_dev,
hr_qp->sq.wqe_shift), page_size);
hr_qp->sq.offset = 0;
- if (hr_qp->sge.sge_cnt) {
+ if (ex_sge_num) {
hr_qp->sge.offset = HNS_ROCE_ALOGN_UP(
(hr_qp->sq.wqe_cnt <<
hr_qp->sq.wqe_shift),
@@ -465,6 +480,14 @@ static int hns_roce_set_kernel_sq_size(struct hns_roce_dev *hr_dev,
hr_qp->sge.sge_shift = 4;
}
+ if ((hr_qp->sq.max_gs > 2) && hr_dev->pci_dev->revision == 0x20) {
+ if (hr_qp->sge.sge_cnt > hr_dev->caps.max_extend_sg) {
+ dev_err(dev, "The extended sge cnt error! sge_cnt=%d\n",
+ hr_qp->sge.sge_cnt);
+ return -EINVAL;
+ }
+ }
+
/* Get buf size, SQ and RQ are aligned to PAGE_SIZE */
page_size = 1 << (hr_dev->caps.mtt_buf_pg_sz + PAGE_SHIFT);
hr_qp->sq.offset = 0;
@@ -472,6 +495,8 @@ static int hns_roce_set_kernel_sq_size(struct hns_roce_dev *hr_dev,
page_size);
if (hr_dev->caps.max_sq_sg > 2 && hr_qp->sge.sge_cnt) {
+ hr_qp->sge.sge_cnt = max(page_size/(1 << hr_qp->sge.sge_shift),
+ (u32)hr_qp->sge.sge_cnt);
hr_qp->sge.offset = size;
size += HNS_ROCE_ALOGN_UP(hr_qp->sge.sge_cnt <<
hr_qp->sge.sge_shift, page_size);
@@ -952,8 +977,8 @@ int hns_roce_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
}
}
- if (!ib_modify_qp_is_ok(cur_state, new_state, ibqp->qp_type, attr_mask,
- IB_LINK_LAYER_ETHERNET)) {
+ if (!ib_modify_qp_is_ok(cur_state, new_state, ibqp->qp_type,
+ attr_mask)) {
dev_err(dev, "ib_modify_qp_is_ok failed\n");
goto out;
}
@@ -1106,14 +1131,20 @@ int hns_roce_init_qp_table(struct hns_roce_dev *hr_dev)
{
struct hns_roce_qp_table *qp_table = &hr_dev->qp_table;
int reserved_from_top = 0;
+ int reserved_from_bot;
int ret;
spin_lock_init(&qp_table->lock);
INIT_RADIX_TREE(&hr_dev->qp_table_tree, GFP_ATOMIC);
- /* A port include two SQP, six port total 12 */
+ /* In hw v1, a port include two SQP, six ports total 12 */
+ if (hr_dev->caps.max_sq_sg <= 2)
+ reserved_from_bot = SQP_NUM;
+ else
+ reserved_from_bot = hr_dev->caps.reserved_qps;
+
ret = hns_roce_bitmap_init(&qp_table->bitmap, hr_dev->caps.num_qps,
- hr_dev->caps.num_qps - 1, SQP_NUM,
+ hr_dev->caps.num_qps - 1, reserved_from_bot,
reserved_from_top);
if (ret) {
dev_err(hr_dev->dev, "qp bitmap init failed!error=%d\n",
diff --git a/drivers/infiniband/hw/i40iw/i40iw_cm.c b/drivers/infiniband/hw/i40iw/i40iw_cm.c
index 423818a7d333..771eb6bd0785 100644
--- a/drivers/infiniband/hw/i40iw/i40iw_cm.c
+++ b/drivers/infiniband/hw/i40iw/i40iw_cm.c
@@ -1689,7 +1689,7 @@ static enum i40iw_status_code i40iw_add_mqh_6(struct i40iw_device *iwdev,
unsigned long flags;
rtnl_lock();
- for_each_netdev_rcu(&init_net, ip_dev) {
+ 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)) {
diff --git a/drivers/infiniband/hw/i40iw/i40iw_verbs.c b/drivers/infiniband/hw/i40iw/i40iw_verbs.c
index e2e6c74a7452..102875872bea 100644
--- a/drivers/infiniband/hw/i40iw/i40iw_verbs.c
+++ b/drivers/infiniband/hw/i40iw/i40iw_verbs.c
@@ -2135,10 +2135,10 @@ static int i40iw_dereg_mr(struct ib_mr *ib_mr)
}
/**
- * i40iw_show_rev
+ * hw_rev_show
*/
-static ssize_t i40iw_show_rev(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t hw_rev_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct i40iw_ib_device *iwibdev = container_of(dev,
struct i40iw_ib_device,
@@ -2147,34 +2147,37 @@ static ssize_t i40iw_show_rev(struct device *dev,
return sprintf(buf, "%x\n", hw_rev);
}
+static DEVICE_ATTR_RO(hw_rev);
/**
- * i40iw_show_hca
+ * hca_type_show
*/
-static ssize_t i40iw_show_hca(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t hca_type_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
return sprintf(buf, "I40IW\n");
}
+static DEVICE_ATTR_RO(hca_type);
/**
- * i40iw_show_board
+ * board_id_show
*/
-static ssize_t i40iw_show_board(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t board_id_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%.*s\n", 32, "I40IW Board ID");
}
+static DEVICE_ATTR_RO(board_id);
-static DEVICE_ATTR(hw_rev, S_IRUGO, i40iw_show_rev, NULL);
-static DEVICE_ATTR(hca_type, S_IRUGO, i40iw_show_hca, NULL);
-static DEVICE_ATTR(board_id, S_IRUGO, i40iw_show_board, NULL);
+static struct attribute *i40iw_dev_attributes[] = {
+ &dev_attr_hw_rev.attr,
+ &dev_attr_hca_type.attr,
+ &dev_attr_board_id.attr,
+ NULL
+};
-static struct device_attribute *i40iw_dev_attributes[] = {
- &dev_attr_hw_rev,
- &dev_attr_hca_type,
- &dev_attr_board_id
+static const struct attribute_group i40iw_attr_group = {
+ .attrs = i40iw_dev_attributes,
};
/**
@@ -2752,7 +2755,6 @@ static struct i40iw_ib_device *i40iw_init_rdma_device(struct i40iw_device *iwdev
i40iw_pr_err("iwdev == NULL\n");
return NULL;
}
- strlcpy(iwibdev->ibdev.name, "i40iw%d", IB_DEVICE_NAME_MAX);
iwibdev->ibdev.owner = THIS_MODULE;
iwdev->iwibdev = iwibdev;
iwibdev->iwdev = iwdev;
@@ -2851,20 +2853,6 @@ void i40iw_port_ibevent(struct i40iw_device *iwdev)
}
/**
- * i40iw_unregister_rdma_device - unregister of iwarp from IB
- * @iwibdev: rdma device ptr
- */
-static void i40iw_unregister_rdma_device(struct i40iw_ib_device *iwibdev)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(i40iw_dev_attributes); ++i)
- device_remove_file(&iwibdev->ibdev.dev,
- i40iw_dev_attributes[i]);
- ib_unregister_device(&iwibdev->ibdev);
-}
-
-/**
* i40iw_destroy_rdma_device - destroy rdma device and free resources
* @iwibdev: IB device ptr
*/
@@ -2873,7 +2861,7 @@ void i40iw_destroy_rdma_device(struct i40iw_ib_device *iwibdev)
if (!iwibdev)
return;
- i40iw_unregister_rdma_device(iwibdev);
+ ib_unregister_device(&iwibdev->ibdev);
kfree(iwibdev->ibdev.iwcm);
iwibdev->ibdev.iwcm = NULL;
wait_event_timeout(iwibdev->iwdev->close_wq,
@@ -2888,32 +2876,19 @@ void i40iw_destroy_rdma_device(struct i40iw_ib_device *iwibdev)
*/
int i40iw_register_rdma_device(struct i40iw_device *iwdev)
{
- int i, ret;
+ 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);
iwibdev->ibdev.driver_id = RDMA_DRIVER_I40IW;
- ret = ib_register_device(&iwibdev->ibdev, NULL);
+ ret = ib_register_device(&iwibdev->ibdev, "i40iw%d", NULL);
if (ret)
goto error;
- for (i = 0; i < ARRAY_SIZE(i40iw_dev_attributes); ++i) {
- ret =
- device_create_file(&iwibdev->ibdev.dev,
- i40iw_dev_attributes[i]);
- if (ret) {
- while (i > 0) {
- i--;
- device_remove_file(&iwibdev->ibdev.dev, i40iw_dev_attributes[i]);
- }
- ib_unregister_device(&iwibdev->ibdev);
- goto error;
- }
- }
return 0;
error:
kfree(iwdev->iwibdev->ibdev.iwcm);
diff --git a/drivers/infiniband/hw/mlx4/Kconfig b/drivers/infiniband/hw/mlx4/Kconfig
index db4aa13ebae0..d1de3285fd88 100644
--- a/drivers/infiniband/hw/mlx4/Kconfig
+++ b/drivers/infiniband/hw/mlx4/Kconfig
@@ -1,6 +1,7 @@
config MLX4_INFINIBAND
tristate "Mellanox ConnectX HCA support"
depends on NETDEVICES && ETHERNET && PCI && INET
+ depends on INFINIBAND_USER_ACCESS || !INFINIBAND_USER_ACCESS
depends on MAY_USE_DEVLINK
select NET_VENDOR_MELLANOX
select MLX4_CORE
diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c
index e5466d786bb1..8942f5f7f04d 100644
--- a/drivers/infiniband/hw/mlx4/mad.c
+++ b/drivers/infiniband/hw/mlx4/mad.c
@@ -807,15 +807,17 @@ static int ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
int err;
struct ib_port_attr pattr;
- if (in_wc && in_wc->qp->qp_num) {
- pr_debug("received MAD: slid:%d sqpn:%d "
- "dlid_bits:%d dqpn:%d wc_flags:0x%x, cls %x, mtd %x, atr %x\n",
- in_wc->slid, in_wc->src_qp,
- in_wc->dlid_path_bits,
- in_wc->qp->qp_num,
- in_wc->wc_flags,
- in_mad->mad_hdr.mgmt_class, in_mad->mad_hdr.method,
- be16_to_cpu(in_mad->mad_hdr.attr_id));
+ if (in_wc && in_wc->qp) {
+ pr_debug("received MAD: port:%d slid:%d sqpn:%d "
+ "dlid_bits:%d dqpn:%d wc_flags:0x%x tid:%016llx cls:%x mtd:%x atr:%x\n",
+ port_num,
+ in_wc->slid, in_wc->src_qp,
+ in_wc->dlid_path_bits,
+ in_wc->qp->qp_num,
+ in_wc->wc_flags,
+ be64_to_cpu(in_mad->mad_hdr.tid),
+ in_mad->mad_hdr.mgmt_class, in_mad->mad_hdr.method,
+ be16_to_cpu(in_mad->mad_hdr.attr_id));
if (in_wc->wc_flags & IB_WC_GRH) {
pr_debug("sgid_hi:0x%016llx sgid_lo:0x%016llx\n",
be64_to_cpu(in_grh->sgid.global.subnet_prefix),
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
index 0bbeaaae47e0..0def2323459c 100644
--- a/drivers/infiniband/hw/mlx4/main.c
+++ b/drivers/infiniband/hw/mlx4/main.c
@@ -1140,144 +1140,50 @@ static int mlx4_ib_dealloc_ucontext(struct ib_ucontext *ibcontext)
return 0;
}
-static void mlx4_ib_vma_open(struct vm_area_struct *area)
-{
- /* vma_open is called when a new VMA is created on top of our VMA.
- * This is done through either mremap flow or split_vma (usually due
- * to mlock, madvise, munmap, etc.). We do not support a clone of the
- * vma, as this VMA is strongly hardware related. Therefore we set the
- * vm_ops of the newly created/cloned VMA to NULL, to prevent it from
- * calling us again and trying to do incorrect actions. We assume that
- * the original vma size is exactly a single page that there will be no
- * "splitting" operations on.
- */
- area->vm_ops = NULL;
-}
-
-static void mlx4_ib_vma_close(struct vm_area_struct *area)
-{
- struct mlx4_ib_vma_private_data *mlx4_ib_vma_priv_data;
-
- /* It's guaranteed that all VMAs opened on a FD are closed before the
- * file itself is closed, therefore no sync is needed with the regular
- * closing flow. (e.g. mlx4_ib_dealloc_ucontext) However need a sync
- * with accessing the vma as part of mlx4_ib_disassociate_ucontext.
- * The close operation is usually called under mm->mmap_sem except when
- * process is exiting. The exiting case is handled explicitly as part
- * of mlx4_ib_disassociate_ucontext.
- */
- mlx4_ib_vma_priv_data = (struct mlx4_ib_vma_private_data *)
- area->vm_private_data;
-
- /* set the vma context pointer to null in the mlx4_ib driver's private
- * data to protect against a race condition in mlx4_ib_dissassociate_ucontext().
- */
- mlx4_ib_vma_priv_data->vma = NULL;
-}
-
-static const struct vm_operations_struct mlx4_ib_vm_ops = {
- .open = mlx4_ib_vma_open,
- .close = mlx4_ib_vma_close
-};
-
static void mlx4_ib_disassociate_ucontext(struct ib_ucontext *ibcontext)
{
- int i;
- struct vm_area_struct *vma;
- struct mlx4_ib_ucontext *context = to_mucontext(ibcontext);
-
- /* need to protect from a race on closing the vma as part of
- * mlx4_ib_vma_close().
- */
- for (i = 0; i < HW_BAR_COUNT; i++) {
- vma = context->hw_bar_info[i].vma;
- if (!vma)
- continue;
-
- zap_vma_ptes(context->hw_bar_info[i].vma,
- context->hw_bar_info[i].vma->vm_start, PAGE_SIZE);
-
- context->hw_bar_info[i].vma->vm_flags &=
- ~(VM_SHARED | VM_MAYSHARE);
- /* context going to be destroyed, should not access ops any more */
- context->hw_bar_info[i].vma->vm_ops = NULL;
- }
-}
-
-static void mlx4_ib_set_vma_data(struct vm_area_struct *vma,
- struct mlx4_ib_vma_private_data *vma_private_data)
-{
- vma_private_data->vma = vma;
- vma->vm_private_data = vma_private_data;
- vma->vm_ops = &mlx4_ib_vm_ops;
}
static int mlx4_ib_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
{
struct mlx4_ib_dev *dev = to_mdev(context->device);
- struct mlx4_ib_ucontext *mucontext = to_mucontext(context);
- if (vma->vm_end - vma->vm_start != PAGE_SIZE)
- return -EINVAL;
-
- if (vma->vm_pgoff == 0) {
- /* We prevent double mmaping on same context */
- if (mucontext->hw_bar_info[HW_BAR_DB].vma)
- return -EINVAL;
-
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-
- if (io_remap_pfn_range(vma, vma->vm_start,
- to_mucontext(context)->uar.pfn,
- PAGE_SIZE, vma->vm_page_prot))
- return -EAGAIN;
-
- mlx4_ib_set_vma_data(vma, &mucontext->hw_bar_info[HW_BAR_DB]);
+ switch (vma->vm_pgoff) {
+ case 0:
+ return rdma_user_mmap_io(context, vma,
+ to_mucontext(context)->uar.pfn,
+ PAGE_SIZE,
+ pgprot_noncached(vma->vm_page_prot));
- } else if (vma->vm_pgoff == 1 && dev->dev->caps.bf_reg_size != 0) {
- /* We prevent double mmaping on same context */
- if (mucontext->hw_bar_info[HW_BAR_BF].vma)
+ case 1:
+ if (dev->dev->caps.bf_reg_size == 0)
return -EINVAL;
+ return rdma_user_mmap_io(
+ context, vma,
+ to_mucontext(context)->uar.pfn +
+ dev->dev->caps.num_uars,
+ PAGE_SIZE, pgprot_writecombine(vma->vm_page_prot));
- vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
-
- if (io_remap_pfn_range(vma, vma->vm_start,
- to_mucontext(context)->uar.pfn +
- dev->dev->caps.num_uars,
- PAGE_SIZE, vma->vm_page_prot))
- return -EAGAIN;
-
- mlx4_ib_set_vma_data(vma, &mucontext->hw_bar_info[HW_BAR_BF]);
-
- } else if (vma->vm_pgoff == 3) {
+ case 3: {
struct mlx4_clock_params params;
int ret;
- /* We prevent double mmaping on same context */
- if (mucontext->hw_bar_info[HW_BAR_CLOCK].vma)
- return -EINVAL;
-
ret = mlx4_get_internal_clock_params(dev->dev, &params);
-
if (ret)
return ret;
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- if (io_remap_pfn_range(vma, vma->vm_start,
- (pci_resource_start(dev->dev->persist->pdev,
- params.bar) +
- params.offset)
- >> PAGE_SHIFT,
- PAGE_SIZE, vma->vm_page_prot))
- return -EAGAIN;
-
- mlx4_ib_set_vma_data(vma,
- &mucontext->hw_bar_info[HW_BAR_CLOCK]);
- } else {
- return -EINVAL;
+ return rdma_user_mmap_io(
+ context, vma,
+ (pci_resource_start(dev->dev->persist->pdev,
+ params.bar) +
+ params.offset) >>
+ PAGE_SHIFT,
+ PAGE_SIZE, pgprot_noncached(vma->vm_page_prot));
}
- return 0;
+ default:
+ return -EINVAL;
+ }
}
static struct ib_pd *mlx4_ib_alloc_pd(struct ib_device *ibdev,
@@ -2133,39 +2039,43 @@ out:
return err;
}
-static ssize_t show_hca(struct device *device, struct device_attribute *attr,
- char *buf)
+static ssize_t hca_type_show(struct device *device,
+ struct device_attribute *attr, char *buf)
{
struct mlx4_ib_dev *dev =
container_of(device, struct mlx4_ib_dev, ib_dev.dev);
return sprintf(buf, "MT%d\n", dev->dev->persist->pdev->device);
}
+static DEVICE_ATTR_RO(hca_type);
-static ssize_t show_rev(struct device *device, struct device_attribute *attr,
- char *buf)
+static ssize_t hw_rev_show(struct device *device,
+ struct device_attribute *attr, char *buf)
{
struct mlx4_ib_dev *dev =
container_of(device, struct mlx4_ib_dev, ib_dev.dev);
return sprintf(buf, "%x\n", dev->dev->rev_id);
}
+static DEVICE_ATTR_RO(hw_rev);
-static ssize_t show_board(struct device *device, struct device_attribute *attr,
- char *buf)
+static ssize_t board_id_show(struct device *device,
+ struct device_attribute *attr, char *buf)
{
struct mlx4_ib_dev *dev =
container_of(device, struct mlx4_ib_dev, ib_dev.dev);
return sprintf(buf, "%.*s\n", MLX4_BOARD_ID_LEN,
dev->dev->board_id);
}
+static DEVICE_ATTR_RO(board_id);
-static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL);
-static DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL);
-static DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL);
+static struct attribute *mlx4_class_attributes[] = {
+ &dev_attr_hw_rev.attr,
+ &dev_attr_hca_type.attr,
+ &dev_attr_board_id.attr,
+ NULL
+};
-static struct device_attribute *mlx4_class_attributes[] = {
- &dev_attr_hw_rev,
- &dev_attr_hca_type,
- &dev_attr_board_id
+static const struct attribute_group mlx4_attr_group = {
+ .attrs = mlx4_class_attributes,
};
struct diag_counter {
@@ -2636,7 +2546,6 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
ibdev->dev = dev;
ibdev->bond_next_port = 0;
- strlcpy(ibdev->ib_dev.name, "mlx4_%d", IB_DEVICE_NAME_MAX);
ibdev->ib_dev.owner = THIS_MODULE;
ibdev->ib_dev.node_type = RDMA_NODE_IB_CA;
ibdev->ib_dev.local_dma_lkey = dev->caps.reserved_lkey;
@@ -2898,8 +2807,9 @@ 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);
ibdev->ib_dev.driver_id = RDMA_DRIVER_MLX4;
- if (ib_register_device(&ibdev->ib_dev, NULL))
+ if (ib_register_device(&ibdev->ib_dev, "mlx4_%d", NULL))
goto err_diag_counters;
if (mlx4_ib_mad_init(ibdev))
@@ -2922,12 +2832,6 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
goto err_notif;
}
- for (j = 0; j < ARRAY_SIZE(mlx4_class_attributes); ++j) {
- if (device_create_file(&ibdev->ib_dev.dev,
- mlx4_class_attributes[j]))
- goto err_notif;
- }
-
ibdev->ib_active = true;
mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB)
devlink_port_type_ib_set(mlx4_get_devlink_port(dev, i),
diff --git a/drivers/infiniband/hw/mlx4/mcg.c b/drivers/infiniband/hw/mlx4/mcg.c
index 81ffc007e0a1..d844831179cf 100644
--- a/drivers/infiniband/hw/mlx4/mcg.c
+++ b/drivers/infiniband/hw/mlx4/mcg.c
@@ -673,7 +673,7 @@ static void mlx4_ib_mcg_work_handler(struct work_struct *work)
if (!list_empty(&group->pending_list))
req = list_first_entry(&group->pending_list,
struct mcast_req, group_list);
- if ((method == IB_MGMT_METHOD_GET_RESP)) {
+ if (method == IB_MGMT_METHOD_GET_RESP) {
if (req) {
send_reply_to_slave(req->func, group, &req->sa_mad, status);
--group->func[req->func].num_pend_reqs;
diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h
index e10dccc7958f..8850dfc3826d 100644
--- a/drivers/infiniband/hw/mlx4/mlx4_ib.h
+++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h
@@ -80,16 +80,11 @@ enum hw_bar_type {
HW_BAR_COUNT
};
-struct mlx4_ib_vma_private_data {
- struct vm_area_struct *vma;
-};
-
struct mlx4_ib_ucontext {
struct ib_ucontext ibucontext;
struct mlx4_uar uar;
struct list_head db_page_list;
struct mutex db_page_mutex;
- struct mlx4_ib_vma_private_data hw_bar_info[HW_BAR_COUNT];
struct list_head wqn_ranges_list;
struct mutex wqn_ranges_mutex; /* protect wqn_ranges_list */
};
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c
index 6dd3cd2c2f80..0711ca1dfb8f 100644
--- a/drivers/infiniband/hw/mlx4/qp.c
+++ b/drivers/infiniband/hw/mlx4/qp.c
@@ -2629,7 +2629,6 @@ enum {
static int _mlx4_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
int attr_mask, struct ib_udata *udata)
{
- enum rdma_link_layer ll = IB_LINK_LAYER_UNSPECIFIED;
struct mlx4_ib_dev *dev = to_mdev(ibqp->device);
struct mlx4_ib_qp *qp = to_mqp(ibqp);
enum ib_qp_state cur_state, new_state;
@@ -2639,13 +2638,8 @@ static int _mlx4_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
cur_state = attr_mask & IB_QP_CUR_STATE ? attr->cur_qp_state : qp->state;
new_state = attr_mask & IB_QP_STATE ? attr->qp_state : cur_state;
- if (cur_state != new_state || cur_state != IB_QPS_RESET) {
- int port = attr_mask & IB_QP_PORT ? attr->port_num : qp->port;
- ll = rdma_port_get_link_layer(&dev->ib_dev, port);
- }
-
if (!ib_modify_qp_is_ok(cur_state, new_state, ibqp->qp_type,
- attr_mask, ll)) {
+ attr_mask)) {
pr_debug("qpn 0x%x: invalid attribute mask specified "
"for transition %d to %d. qp_type %d,"
" attr_mask 0x%x\n",
diff --git a/drivers/infiniband/hw/mlx4/sysfs.c b/drivers/infiniband/hw/mlx4/sysfs.c
index e219093d2764..752bdd536130 100644
--- a/drivers/infiniband/hw/mlx4/sysfs.c
+++ b/drivers/infiniband/hw/mlx4/sysfs.c
@@ -818,9 +818,7 @@ int mlx4_ib_device_register_sysfs(struct mlx4_ib_dev *dev)
if (!mlx4_is_master(dev->dev))
return 0;
- dev->iov_parent =
- kobject_create_and_add("iov",
- kobject_get(dev->ib_dev.ports_parent->parent));
+ dev->iov_parent = kobject_create_and_add("iov", &dev->ib_dev.dev.kobj);
if (!dev->iov_parent) {
ret = -ENOMEM;
goto err;
@@ -850,7 +848,6 @@ err_add_entries:
err_ports:
kobject_put(dev->iov_parent);
err:
- kobject_put(dev->ib_dev.ports_parent->parent);
pr_err("mlx4_ib_device_register_sysfs error (%d)\n", ret);
return ret;
}
@@ -886,5 +883,4 @@ void mlx4_ib_device_unregister_sysfs(struct mlx4_ib_dev *device)
kobject_put(device->ports_parent);
kobject_put(device->iov_parent);
kobject_put(device->iov_parent);
- kobject_put(device->ib_dev.ports_parent->parent);
}
diff --git a/drivers/infiniband/hw/mlx5/cmd.c b/drivers/infiniband/hw/mlx5/cmd.c
index c84fef9a8a08..ca060a2e2b36 100644
--- a/drivers/infiniband/hw/mlx5/cmd.c
+++ b/drivers/infiniband/hw/mlx5/cmd.c
@@ -197,3 +197,132 @@ int mlx5_cmd_query_ext_ppcnt_counters(struct mlx5_core_dev *dev, void *out)
return mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPCNT,
0, 0);
}
+
+void mlx5_cmd_destroy_tir(struct mlx5_core_dev *dev, u32 tirn, u16 uid)
+{
+ u32 in[MLX5_ST_SZ_DW(destroy_tir_in)] = {};
+ u32 out[MLX5_ST_SZ_DW(destroy_tir_out)] = {};
+
+ MLX5_SET(destroy_tir_in, in, opcode, MLX5_CMD_OP_DESTROY_TIR);
+ MLX5_SET(destroy_tir_in, in, tirn, tirn);
+ MLX5_SET(destroy_tir_in, in, uid, uid);
+ mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
+}
+
+void mlx5_cmd_destroy_tis(struct mlx5_core_dev *dev, u32 tisn, u16 uid)
+{
+ u32 in[MLX5_ST_SZ_DW(destroy_tis_in)] = {0};
+ u32 out[MLX5_ST_SZ_DW(destroy_tis_out)] = {0};
+
+ MLX5_SET(destroy_tis_in, in, opcode, MLX5_CMD_OP_DESTROY_TIS);
+ MLX5_SET(destroy_tis_in, in, tisn, tisn);
+ MLX5_SET(destroy_tis_in, in, uid, uid);
+ mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
+}
+
+void mlx5_cmd_destroy_rqt(struct mlx5_core_dev *dev, u32 rqtn, u16 uid)
+{
+ u32 in[MLX5_ST_SZ_DW(destroy_rqt_in)] = {};
+ u32 out[MLX5_ST_SZ_DW(destroy_rqt_out)] = {};
+
+ MLX5_SET(destroy_rqt_in, in, opcode, MLX5_CMD_OP_DESTROY_RQT);
+ MLX5_SET(destroy_rqt_in, in, rqtn, rqtn);
+ MLX5_SET(destroy_rqt_in, in, uid, uid);
+ mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
+}
+
+int mlx5_cmd_alloc_transport_domain(struct mlx5_core_dev *dev, u32 *tdn,
+ u16 uid)
+{
+ u32 in[MLX5_ST_SZ_DW(alloc_transport_domain_in)] = {0};
+ u32 out[MLX5_ST_SZ_DW(alloc_transport_domain_out)] = {0};
+ int err;
+
+ MLX5_SET(alloc_transport_domain_in, in, opcode,
+ MLX5_CMD_OP_ALLOC_TRANSPORT_DOMAIN);
+
+ err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
+ if (!err)
+ *tdn = MLX5_GET(alloc_transport_domain_out, out,
+ transport_domain);
+
+ return err;
+}
+
+void mlx5_cmd_dealloc_transport_domain(struct mlx5_core_dev *dev, u32 tdn,
+ u16 uid)
+{
+ u32 in[MLX5_ST_SZ_DW(dealloc_transport_domain_in)] = {0};
+ u32 out[MLX5_ST_SZ_DW(dealloc_transport_domain_out)] = {0};
+
+ MLX5_SET(dealloc_transport_domain_in, in, opcode,
+ MLX5_CMD_OP_DEALLOC_TRANSPORT_DOMAIN);
+ MLX5_SET(dealloc_transport_domain_in, in, transport_domain, tdn);
+ mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
+}
+
+void mlx5_cmd_dealloc_pd(struct mlx5_core_dev *dev, u32 pdn, u16 uid)
+{
+ u32 out[MLX5_ST_SZ_DW(dealloc_pd_out)] = {};
+ u32 in[MLX5_ST_SZ_DW(dealloc_pd_in)] = {};
+
+ MLX5_SET(dealloc_pd_in, in, opcode, MLX5_CMD_OP_DEALLOC_PD);
+ MLX5_SET(dealloc_pd_in, in, pd, pdn);
+ MLX5_SET(dealloc_pd_in, in, uid, uid);
+ mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
+}
+
+int mlx5_cmd_attach_mcg(struct mlx5_core_dev *dev, union ib_gid *mgid,
+ u32 qpn, u16 uid)
+{
+ u32 out[MLX5_ST_SZ_DW(attach_to_mcg_out)] = {};
+ u32 in[MLX5_ST_SZ_DW(attach_to_mcg_in)] = {};
+ void *gid;
+
+ MLX5_SET(attach_to_mcg_in, in, opcode, MLX5_CMD_OP_ATTACH_TO_MCG);
+ MLX5_SET(attach_to_mcg_in, in, qpn, qpn);
+ MLX5_SET(attach_to_mcg_in, in, uid, uid);
+ gid = MLX5_ADDR_OF(attach_to_mcg_in, in, multicast_gid);
+ memcpy(gid, mgid, sizeof(*mgid));
+ return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
+}
+
+int mlx5_cmd_detach_mcg(struct mlx5_core_dev *dev, union ib_gid *mgid,
+ u32 qpn, u16 uid)
+{
+ u32 out[MLX5_ST_SZ_DW(detach_from_mcg_out)] = {};
+ u32 in[MLX5_ST_SZ_DW(detach_from_mcg_in)] = {};
+ void *gid;
+
+ MLX5_SET(detach_from_mcg_in, in, opcode, MLX5_CMD_OP_DETACH_FROM_MCG);
+ MLX5_SET(detach_from_mcg_in, in, qpn, qpn);
+ MLX5_SET(detach_from_mcg_in, in, uid, uid);
+ gid = MLX5_ADDR_OF(detach_from_mcg_in, in, multicast_gid);
+ memcpy(gid, mgid, sizeof(*mgid));
+ return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
+}
+
+int mlx5_cmd_xrcd_alloc(struct mlx5_core_dev *dev, u32 *xrcdn, u16 uid)
+{
+ u32 out[MLX5_ST_SZ_DW(alloc_xrcd_out)] = {};
+ u32 in[MLX5_ST_SZ_DW(alloc_xrcd_in)] = {};
+ int err;
+
+ MLX5_SET(alloc_xrcd_in, in, opcode, MLX5_CMD_OP_ALLOC_XRCD);
+ MLX5_SET(alloc_xrcd_in, in, uid, uid);
+ err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
+ if (!err)
+ *xrcdn = MLX5_GET(alloc_xrcd_out, out, xrcd);
+ return err;
+}
+
+int mlx5_cmd_xrcd_dealloc(struct mlx5_core_dev *dev, u32 xrcdn, u16 uid)
+{
+ u32 out[MLX5_ST_SZ_DW(dealloc_xrcd_out)] = {};
+ u32 in[MLX5_ST_SZ_DW(dealloc_xrcd_in)] = {};
+
+ MLX5_SET(dealloc_xrcd_in, in, opcode, MLX5_CMD_OP_DEALLOC_XRCD);
+ MLX5_SET(dealloc_xrcd_in, in, xrcd, xrcdn);
+ MLX5_SET(dealloc_xrcd_in, in, uid, uid);
+ return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
+}
diff --git a/drivers/infiniband/hw/mlx5/cmd.h b/drivers/infiniband/hw/mlx5/cmd.h
index 88cbb1c41703..c03c56455534 100644
--- a/drivers/infiniband/hw/mlx5/cmd.h
+++ b/drivers/infiniband/hw/mlx5/cmd.h
@@ -47,4 +47,18 @@ int mlx5_cmd_modify_cong_params(struct mlx5_core_dev *mdev,
int mlx5_cmd_alloc_memic(struct mlx5_memic *memic, phys_addr_t *addr,
u64 length, u32 alignment);
int mlx5_cmd_dealloc_memic(struct mlx5_memic *memic, u64 addr, u64 length);
+void mlx5_cmd_dealloc_pd(struct mlx5_core_dev *dev, u32 pdn, u16 uid);
+void mlx5_cmd_destroy_tir(struct mlx5_core_dev *dev, u32 tirn, u16 uid);
+void mlx5_cmd_destroy_tis(struct mlx5_core_dev *dev, u32 tisn, u16 uid);
+void mlx5_cmd_destroy_rqt(struct mlx5_core_dev *dev, u32 rqtn, u16 uid);
+int mlx5_cmd_alloc_transport_domain(struct mlx5_core_dev *dev, u32 *tdn,
+ u16 uid);
+void mlx5_cmd_dealloc_transport_domain(struct mlx5_core_dev *dev, u32 tdn,
+ u16 uid);
+int mlx5_cmd_attach_mcg(struct mlx5_core_dev *dev, union ib_gid *mgid,
+ u32 qpn, u16 uid);
+int mlx5_cmd_detach_mcg(struct mlx5_core_dev *dev, union ib_gid *mgid,
+ u32 qpn, u16 uid);
+int mlx5_cmd_xrcd_alloc(struct mlx5_core_dev *dev, u32 *xrcdn, u16 uid);
+int mlx5_cmd_xrcd_dealloc(struct mlx5_core_dev *dev, u32 xrcdn, u16 uid);
#endif /* MLX5_IB_CMD_H */
diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c
index 088205d7f1a1..7d769b5538b4 100644
--- a/drivers/infiniband/hw/mlx5/cq.c
+++ b/drivers/infiniband/hw/mlx5/cq.c
@@ -393,7 +393,7 @@ static void handle_atomics(struct mlx5_ib_qp *qp, struct mlx5_cqe64 *cqe64,
static void free_cq_buf(struct mlx5_ib_dev *dev, struct mlx5_ib_cq_buf *buf)
{
- mlx5_frag_buf_free(dev->mdev, &buf->fbc.frag_buf);
+ mlx5_frag_buf_free(dev->mdev, &buf->frag_buf);
}
static void get_sig_err_item(struct mlx5_sig_err_cqe *cqe,
@@ -728,16 +728,11 @@ static int alloc_cq_frag_buf(struct mlx5_ib_dev *dev,
int nent,
int cqe_size)
{
- struct mlx5_frag_buf_ctrl *c = &buf->fbc;
- struct mlx5_frag_buf *frag_buf = &c->frag_buf;
- u32 cqc_buff[MLX5_ST_SZ_DW(cqc)] = {0};
+ struct mlx5_frag_buf *frag_buf = &buf->frag_buf;
+ u8 log_wq_stride = 6 + (cqe_size == 128 ? 1 : 0);
+ u8 log_wq_sz = ilog2(cqe_size);
int err;
- MLX5_SET(cqc, cqc_buff, log_cq_size, ilog2(cqe_size));
- MLX5_SET(cqc, cqc_buff, cqe_sz, (cqe_size == 128) ? 1 : 0);
-
- mlx5_core_init_cq_frag_buf(&buf->fbc, cqc_buff);
-
err = mlx5_frag_buf_alloc_node(dev->mdev,
nent * cqe_size,
frag_buf,
@@ -745,6 +740,8 @@ static int alloc_cq_frag_buf(struct mlx5_ib_dev *dev,
if (err)
return err;
+ mlx5_init_fbc(frag_buf->frags, log_wq_stride, log_wq_sz, &buf->fbc);
+
buf->cqe_size = cqe_size;
buf->nent = nent;
@@ -877,6 +874,7 @@ 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;
}
+ MLX5_SET(create_cq_in, *cqb, uid, to_mucontext(context)->devx_uid);
return 0;
err_cqb:
@@ -934,7 +932,7 @@ static int create_cq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq,
*inlen = MLX5_ST_SZ_BYTES(create_cq_in) +
MLX5_FLD_SZ_BYTES(create_cq_in, pas[0]) *
- cq->buf.fbc.frag_buf.npages;
+ cq->buf.frag_buf.npages;
*cqb = kvzalloc(*inlen, GFP_KERNEL);
if (!*cqb) {
err = -ENOMEM;
@@ -942,11 +940,11 @@ static int create_cq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq,
}
pas = (__be64 *)MLX5_ADDR_OF(create_cq_in, *cqb, pas);
- mlx5_fill_page_frag_array(&cq->buf.fbc.frag_buf, pas);
+ mlx5_fill_page_frag_array(&cq->buf.frag_buf, pas);
cqc = MLX5_ADDR_OF(create_cq_in, *cqb, cq_context);
MLX5_SET(cqc, cqc, log_page_size,
- cq->buf.fbc.frag_buf.page_shift -
+ cq->buf.frag_buf.page_shift -
MLX5_ADAPTER_PAGE_SHIFT);
*index = dev->mdev->priv.uar->index;
@@ -1365,11 +1363,10 @@ int mlx5_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata)
cqe_size = 64;
err = resize_kernel(dev, cq, entries, cqe_size);
if (!err) {
- struct mlx5_frag_buf_ctrl *c;
+ struct mlx5_frag_buf *frag_buf = &cq->resize_buf->frag_buf;
- c = &cq->resize_buf->fbc;
- npas = c->frag_buf.npages;
- page_shift = c->frag_buf.page_shift;
+ npas = frag_buf->npages;
+ page_shift = frag_buf->page_shift;
}
}
@@ -1390,8 +1387,7 @@ int mlx5_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata)
mlx5_ib_populate_pas(dev, cq->resize_umem, page_shift,
pas, 0);
else
- mlx5_fill_page_frag_array(&cq->resize_buf->fbc.frag_buf,
- pas);
+ mlx5_fill_page_frag_array(&cq->resize_buf->frag_buf, pas);
MLX5_SET(modify_cq_in, in,
modify_field_select_resize_field_select.resize_field_select.resize_field_select,
@@ -1459,7 +1455,7 @@ ex:
return err;
}
-int mlx5_ib_get_cqe_size(struct mlx5_ib_dev *dev, struct ib_cq *ibcq)
+int mlx5_ib_get_cqe_size(struct ib_cq *ibcq)
{
struct mlx5_ib_cq *cq;
diff --git a/drivers/infiniband/hw/mlx5/devx.c b/drivers/infiniband/hw/mlx5/devx.c
index f2f11e652dcd..61aab7c0c513 100644
--- a/drivers/infiniband/hw/mlx5/devx.c
+++ b/drivers/infiniband/hw/mlx5/devx.c
@@ -19,7 +19,7 @@
#define MLX5_MAX_DESTROY_INBOX_SIZE_DW MLX5_ST_SZ_DW(delete_fte_in)
struct devx_obj {
struct mlx5_core_dev *mdev;
- u32 obj_id;
+ u64 obj_id;
u32 dinlen; /* destroy inbox length */
u32 dinbox[MLX5_MAX_DESTROY_INBOX_SIZE_DW];
};
@@ -45,13 +45,14 @@ static struct mlx5_ib_ucontext *devx_ufile2uctx(struct ib_uverbs_file *file)
return to_mucontext(ib_uverbs_get_ucontext(file));
}
-int mlx5_ib_devx_create(struct mlx5_ib_dev *dev, struct mlx5_ib_ucontext *context)
+int mlx5_ib_devx_create(struct mlx5_ib_dev *dev)
{
u32 in[MLX5_ST_SZ_DW(create_uctx_in)] = {0};
u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {0};
u64 general_obj_types;
void *hdr;
int err;
+ u16 uid;
hdr = MLX5_ADDR_OF(create_uctx_in, in, hdr);
@@ -60,9 +61,6 @@ int mlx5_ib_devx_create(struct mlx5_ib_dev *dev, struct mlx5_ib_ucontext *contex
!(general_obj_types & MLX5_GENERAL_OBJ_TYPES_CAP_UMEM))
return -EINVAL;
- if (!capable(CAP_NET_RAW))
- return -EPERM;
-
MLX5_SET(general_obj_in_cmd_hdr, hdr, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT);
MLX5_SET(general_obj_in_cmd_hdr, hdr, obj_type, MLX5_OBJ_TYPE_UCTX);
@@ -70,19 +68,18 @@ int mlx5_ib_devx_create(struct mlx5_ib_dev *dev, struct mlx5_ib_ucontext *contex
if (err)
return err;
- context->devx_uid = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id);
- return 0;
+ uid = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id);
+ return uid;
}
-void mlx5_ib_devx_destroy(struct mlx5_ib_dev *dev,
- struct mlx5_ib_ucontext *context)
+void mlx5_ib_devx_destroy(struct mlx5_ib_dev *dev, u16 uid)
{
u32 in[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)] = {0};
u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {0};
MLX5_SET(general_obj_in_cmd_hdr, in, opcode, MLX5_CMD_OP_DESTROY_GENERAL_OBJECT);
MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, MLX5_OBJ_TYPE_UCTX);
- MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, context->devx_uid);
+ MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, uid);
mlx5_cmd_exec(dev->mdev, in, sizeof(in), out, sizeof(out));
}
@@ -109,150 +106,218 @@ bool mlx5_ib_devx_is_flow_dest(void *obj, int *dest_id, int *dest_type)
}
}
+/*
+ * As the obj_id in the firmware is not globally unique the object type
+ * must be considered upon checking for a valid object id.
+ * For that the opcode of the creator command is encoded as part of the obj_id.
+ */
+static u64 get_enc_obj_id(u16 opcode, u32 obj_id)
+{
+ return ((u64)opcode << 32) | obj_id;
+}
+
static int devx_is_valid_obj_id(struct devx_obj *obj, const void *in)
{
u16 opcode = MLX5_GET(general_obj_in_cmd_hdr, in, opcode);
- u32 obj_id;
+ u64 obj_id;
switch (opcode) {
case MLX5_CMD_OP_MODIFY_GENERAL_OBJECT:
case MLX5_CMD_OP_QUERY_GENERAL_OBJECT:
- obj_id = MLX5_GET(general_obj_in_cmd_hdr, in, obj_id);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_GENERAL_OBJECT,
+ MLX5_GET(general_obj_in_cmd_hdr, in,
+ obj_id));
break;
case MLX5_CMD_OP_QUERY_MKEY:
- obj_id = MLX5_GET(query_mkey_in, in, mkey_index);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_MKEY,
+ MLX5_GET(query_mkey_in, in,
+ mkey_index));
break;
case MLX5_CMD_OP_QUERY_CQ:
- obj_id = MLX5_GET(query_cq_in, in, cqn);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_CQ,
+ MLX5_GET(query_cq_in, in, cqn));
break;
case MLX5_CMD_OP_MODIFY_CQ:
- obj_id = MLX5_GET(modify_cq_in, in, cqn);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_CQ,
+ MLX5_GET(modify_cq_in, in, cqn));
break;
case MLX5_CMD_OP_QUERY_SQ:
- obj_id = MLX5_GET(query_sq_in, in, sqn);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_SQ,
+ MLX5_GET(query_sq_in, in, sqn));
break;
case MLX5_CMD_OP_MODIFY_SQ:
- obj_id = MLX5_GET(modify_sq_in, in, sqn);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_SQ,
+ MLX5_GET(modify_sq_in, in, sqn));
break;
case MLX5_CMD_OP_QUERY_RQ:
- obj_id = MLX5_GET(query_rq_in, in, rqn);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_RQ,
+ MLX5_GET(query_rq_in, in, rqn));
break;
case MLX5_CMD_OP_MODIFY_RQ:
- obj_id = MLX5_GET(modify_rq_in, in, rqn);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_RQ,
+ MLX5_GET(modify_rq_in, in, rqn));
break;
case MLX5_CMD_OP_QUERY_RMP:
- obj_id = MLX5_GET(query_rmp_in, in, rmpn);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_RMP,
+ MLX5_GET(query_rmp_in, in, rmpn));
break;
case MLX5_CMD_OP_MODIFY_RMP:
- obj_id = MLX5_GET(modify_rmp_in, in, rmpn);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_RMP,
+ MLX5_GET(modify_rmp_in, in, rmpn));
break;
case MLX5_CMD_OP_QUERY_RQT:
- obj_id = MLX5_GET(query_rqt_in, in, rqtn);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_RQT,
+ MLX5_GET(query_rqt_in, in, rqtn));
break;
case MLX5_CMD_OP_MODIFY_RQT:
- obj_id = MLX5_GET(modify_rqt_in, in, rqtn);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_RQT,
+ MLX5_GET(modify_rqt_in, in, rqtn));
break;
case MLX5_CMD_OP_QUERY_TIR:
- obj_id = MLX5_GET(query_tir_in, in, tirn);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_TIR,
+ MLX5_GET(query_tir_in, in, tirn));
break;
case MLX5_CMD_OP_MODIFY_TIR:
- obj_id = MLX5_GET(modify_tir_in, in, tirn);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_TIR,
+ MLX5_GET(modify_tir_in, in, tirn));
break;
case MLX5_CMD_OP_QUERY_TIS:
- obj_id = MLX5_GET(query_tis_in, in, tisn);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_TIS,
+ MLX5_GET(query_tis_in, in, tisn));
break;
case MLX5_CMD_OP_MODIFY_TIS:
- obj_id = MLX5_GET(modify_tis_in, in, tisn);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_TIS,
+ MLX5_GET(modify_tis_in, in, tisn));
break;
case MLX5_CMD_OP_QUERY_FLOW_TABLE:
- obj_id = MLX5_GET(query_flow_table_in, in, table_id);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_FLOW_TABLE,
+ MLX5_GET(query_flow_table_in, in,
+ table_id));
break;
case MLX5_CMD_OP_MODIFY_FLOW_TABLE:
- obj_id = MLX5_GET(modify_flow_table_in, in, table_id);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_FLOW_TABLE,
+ MLX5_GET(modify_flow_table_in, in,
+ table_id));
break;
case MLX5_CMD_OP_QUERY_FLOW_GROUP:
- obj_id = MLX5_GET(query_flow_group_in, in, group_id);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_FLOW_GROUP,
+ MLX5_GET(query_flow_group_in, in,
+ group_id));
break;
case MLX5_CMD_OP_QUERY_FLOW_TABLE_ENTRY:
- obj_id = MLX5_GET(query_fte_in, in, flow_index);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY,
+ MLX5_GET(query_fte_in, in,
+ flow_index));
break;
case MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY:
- obj_id = MLX5_GET(set_fte_in, in, flow_index);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY,
+ MLX5_GET(set_fte_in, in, flow_index));
break;
case MLX5_CMD_OP_QUERY_Q_COUNTER:
- obj_id = MLX5_GET(query_q_counter_in, in, counter_set_id);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_ALLOC_Q_COUNTER,
+ MLX5_GET(query_q_counter_in, in,
+ counter_set_id));
break;
case MLX5_CMD_OP_QUERY_FLOW_COUNTER:
- obj_id = MLX5_GET(query_flow_counter_in, in, flow_counter_id);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_ALLOC_FLOW_COUNTER,
+ MLX5_GET(query_flow_counter_in, in,
+ flow_counter_id));
break;
case MLX5_CMD_OP_QUERY_MODIFY_HEADER_CONTEXT:
- obj_id = MLX5_GET(general_obj_in_cmd_hdr, in, obj_id);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_ALLOC_MODIFY_HEADER_CONTEXT,
+ MLX5_GET(general_obj_in_cmd_hdr, in,
+ obj_id));
break;
case MLX5_CMD_OP_QUERY_SCHEDULING_ELEMENT:
- obj_id = MLX5_GET(query_scheduling_element_in, in,
- scheduling_element_id);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_SCHEDULING_ELEMENT,
+ MLX5_GET(query_scheduling_element_in,
+ in, scheduling_element_id));
break;
case MLX5_CMD_OP_MODIFY_SCHEDULING_ELEMENT:
- obj_id = MLX5_GET(modify_scheduling_element_in, in,
- scheduling_element_id);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_SCHEDULING_ELEMENT,
+ MLX5_GET(modify_scheduling_element_in,
+ in, scheduling_element_id));
break;
case MLX5_CMD_OP_ADD_VXLAN_UDP_DPORT:
- obj_id = MLX5_GET(add_vxlan_udp_dport_in, in, vxlan_udp_port);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_ADD_VXLAN_UDP_DPORT,
+ MLX5_GET(add_vxlan_udp_dport_in, in,
+ vxlan_udp_port));
break;
case MLX5_CMD_OP_QUERY_L2_TABLE_ENTRY:
- obj_id = MLX5_GET(query_l2_table_entry_in, in, table_index);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_SET_L2_TABLE_ENTRY,
+ MLX5_GET(query_l2_table_entry_in, in,
+ table_index));
break;
case MLX5_CMD_OP_SET_L2_TABLE_ENTRY:
- obj_id = MLX5_GET(set_l2_table_entry_in, in, table_index);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_SET_L2_TABLE_ENTRY,
+ MLX5_GET(set_l2_table_entry_in, in,
+ table_index));
break;
case MLX5_CMD_OP_QUERY_QP:
- obj_id = MLX5_GET(query_qp_in, in, qpn);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_QP,
+ MLX5_GET(query_qp_in, in, qpn));
break;
case MLX5_CMD_OP_RST2INIT_QP:
- obj_id = MLX5_GET(rst2init_qp_in, in, qpn);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_QP,
+ MLX5_GET(rst2init_qp_in, in, qpn));
break;
case MLX5_CMD_OP_INIT2RTR_QP:
- obj_id = MLX5_GET(init2rtr_qp_in, in, qpn);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_QP,
+ MLX5_GET(init2rtr_qp_in, in, qpn));
break;
case MLX5_CMD_OP_RTR2RTS_QP:
- obj_id = MLX5_GET(rtr2rts_qp_in, in, qpn);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_QP,
+ MLX5_GET(rtr2rts_qp_in, in, qpn));
break;
case MLX5_CMD_OP_RTS2RTS_QP:
- obj_id = MLX5_GET(rts2rts_qp_in, in, qpn);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_QP,
+ MLX5_GET(rts2rts_qp_in, in, qpn));
break;
case MLX5_CMD_OP_SQERR2RTS_QP:
- obj_id = MLX5_GET(sqerr2rts_qp_in, in, qpn);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_QP,
+ MLX5_GET(sqerr2rts_qp_in, in, qpn));
break;
case MLX5_CMD_OP_2ERR_QP:
- obj_id = MLX5_GET(qp_2err_in, in, qpn);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_QP,
+ MLX5_GET(qp_2err_in, in, qpn));
break;
case MLX5_CMD_OP_2RST_QP:
- obj_id = MLX5_GET(qp_2rst_in, in, qpn);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_QP,
+ MLX5_GET(qp_2rst_in, in, qpn));
break;
case MLX5_CMD_OP_QUERY_DCT:
- obj_id = MLX5_GET(query_dct_in, in, dctn);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_DCT,
+ MLX5_GET(query_dct_in, in, dctn));
break;
case MLX5_CMD_OP_QUERY_XRQ:
- obj_id = MLX5_GET(query_xrq_in, in, xrqn);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_XRQ,
+ MLX5_GET(query_xrq_in, in, xrqn));
break;
case MLX5_CMD_OP_QUERY_XRC_SRQ:
- obj_id = MLX5_GET(query_xrc_srq_in, in, xrc_srqn);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_XRC_SRQ,
+ MLX5_GET(query_xrc_srq_in, in,
+ xrc_srqn));
break;
case MLX5_CMD_OP_ARM_XRC_SRQ:
- obj_id = MLX5_GET(arm_xrc_srq_in, in, xrc_srqn);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_XRC_SRQ,
+ MLX5_GET(arm_xrc_srq_in, in, xrc_srqn));
break;
case MLX5_CMD_OP_QUERY_SRQ:
- obj_id = MLX5_GET(query_srq_in, in, srqn);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_SRQ,
+ MLX5_GET(query_srq_in, in, srqn));
break;
case MLX5_CMD_OP_ARM_RQ:
- obj_id = MLX5_GET(arm_rq_in, in, srq_number);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_RQ,
+ MLX5_GET(arm_rq_in, in, srq_number));
break;
case MLX5_CMD_OP_DRAIN_DCT:
case MLX5_CMD_OP_ARM_DCT_FOR_KEY_VIOLATION:
- obj_id = MLX5_GET(drain_dct_in, in, dctn);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_DCT,
+ MLX5_GET(drain_dct_in, in, dctn));
break;
case MLX5_CMD_OP_ARM_XRQ:
- obj_id = MLX5_GET(arm_xrq_in, in, xrqn);
+ obj_id = get_enc_obj_id(MLX5_CMD_OP_CREATE_XRQ,
+ MLX5_GET(arm_xrq_in, in, xrqn));
break;
default:
return false;
@@ -264,11 +329,102 @@ static int devx_is_valid_obj_id(struct devx_obj *obj, const void *in)
return false;
}
-static bool devx_is_obj_create_cmd(const void *in)
+static void devx_set_umem_valid(const void *in)
{
u16 opcode = MLX5_GET(general_obj_in_cmd_hdr, in, opcode);
switch (opcode) {
+ case MLX5_CMD_OP_CREATE_MKEY:
+ MLX5_SET(create_mkey_in, in, mkey_umem_valid, 1);
+ break;
+ case MLX5_CMD_OP_CREATE_CQ:
+ {
+ void *cqc;
+
+ MLX5_SET(create_cq_in, in, cq_umem_valid, 1);
+ cqc = MLX5_ADDR_OF(create_cq_in, in, cq_context);
+ MLX5_SET(cqc, cqc, dbr_umem_valid, 1);
+ break;
+ }
+ case MLX5_CMD_OP_CREATE_QP:
+ {
+ void *qpc;
+
+ qpc = MLX5_ADDR_OF(create_qp_in, in, qpc);
+ MLX5_SET(qpc, qpc, dbr_umem_valid, 1);
+ MLX5_SET(create_qp_in, in, wq_umem_valid, 1);
+ break;
+ }
+
+ case MLX5_CMD_OP_CREATE_RQ:
+ {
+ void *rqc, *wq;
+
+ rqc = MLX5_ADDR_OF(create_rq_in, in, ctx);
+ wq = MLX5_ADDR_OF(rqc, rqc, wq);
+ MLX5_SET(wq, wq, dbr_umem_valid, 1);
+ MLX5_SET(wq, wq, wq_umem_valid, 1);
+ break;
+ }
+
+ case MLX5_CMD_OP_CREATE_SQ:
+ {
+ void *sqc, *wq;
+
+ sqc = MLX5_ADDR_OF(create_sq_in, in, ctx);
+ wq = MLX5_ADDR_OF(sqc, sqc, wq);
+ MLX5_SET(wq, wq, dbr_umem_valid, 1);
+ MLX5_SET(wq, wq, wq_umem_valid, 1);
+ break;
+ }
+
+ case MLX5_CMD_OP_MODIFY_CQ:
+ MLX5_SET(modify_cq_in, in, cq_umem_valid, 1);
+ break;
+
+ case MLX5_CMD_OP_CREATE_RMP:
+ {
+ void *rmpc, *wq;
+
+ rmpc = MLX5_ADDR_OF(create_rmp_in, in, ctx);
+ wq = MLX5_ADDR_OF(rmpc, rmpc, wq);
+ MLX5_SET(wq, wq, dbr_umem_valid, 1);
+ MLX5_SET(wq, wq, wq_umem_valid, 1);
+ break;
+ }
+
+ case MLX5_CMD_OP_CREATE_XRQ:
+ {
+ void *xrqc, *wq;
+
+ xrqc = MLX5_ADDR_OF(create_xrq_in, in, xrq_context);
+ wq = MLX5_ADDR_OF(xrqc, xrqc, wq);
+ MLX5_SET(wq, wq, dbr_umem_valid, 1);
+ MLX5_SET(wq, wq, wq_umem_valid, 1);
+ break;
+ }
+
+ case MLX5_CMD_OP_CREATE_XRC_SRQ:
+ {
+ void *xrc_srqc;
+
+ MLX5_SET(create_xrc_srq_in, in, xrc_srq_umem_valid, 1);
+ xrc_srqc = MLX5_ADDR_OF(create_xrc_srq_in, in,
+ xrc_srq_context_entry);
+ MLX5_SET(xrc_srqc, xrc_srqc, dbr_umem_valid, 1);
+ break;
+ }
+
+ default:
+ return;
+ }
+}
+
+static bool devx_is_obj_create_cmd(const void *in, u16 *opcode)
+{
+ *opcode = MLX5_GET(general_obj_in_cmd_hdr, in, opcode);
+
+ switch (*opcode) {
case MLX5_CMD_OP_CREATE_GENERAL_OBJECT:
case MLX5_CMD_OP_CREATE_MKEY:
case MLX5_CMD_OP_CREATE_CQ:
@@ -284,7 +440,7 @@ static bool devx_is_obj_create_cmd(const void *in)
case MLX5_CMD_OP_CREATE_FLOW_TABLE:
case MLX5_CMD_OP_CREATE_FLOW_GROUP:
case MLX5_CMD_OP_ALLOC_FLOW_COUNTER:
- case MLX5_CMD_OP_ALLOC_ENCAP_HEADER:
+ case MLX5_CMD_OP_ALLOC_PACKET_REFORMAT_CONTEXT:
case MLX5_CMD_OP_ALLOC_MODIFY_HEADER_CONTEXT:
case MLX5_CMD_OP_CREATE_SCHEDULING_ELEMENT:
case MLX5_CMD_OP_ADD_VXLAN_UDP_DPORT:
@@ -385,12 +541,49 @@ static bool devx_is_obj_query_cmd(const void *in)
}
}
+static bool devx_is_whitelist_cmd(void *in)
+{
+ u16 opcode = MLX5_GET(general_obj_in_cmd_hdr, in, opcode);
+
+ switch (opcode) {
+ case MLX5_CMD_OP_QUERY_HCA_CAP:
+ case MLX5_CMD_OP_QUERY_HCA_VPORT_CONTEXT:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static int devx_get_uid(struct mlx5_ib_ucontext *c, void *cmd_in)
+{
+ if (devx_is_whitelist_cmd(cmd_in)) {
+ struct mlx5_ib_dev *dev;
+
+ if (c->devx_uid)
+ return c->devx_uid;
+
+ dev = to_mdev(c->ibucontext.device);
+ if (dev->devx_whitelist_uid)
+ return dev->devx_whitelist_uid;
+
+ return -EOPNOTSUPP;
+ }
+
+ if (!c->devx_uid)
+ return -EINVAL;
+
+ if (!capable(CAP_NET_RAW))
+ return -EPERM;
+
+ return c->devx_uid;
+}
static bool devx_is_general_cmd(void *in)
{
u16 opcode = MLX5_GET(general_obj_in_cmd_hdr, in, opcode);
switch (opcode) {
case MLX5_CMD_OP_QUERY_HCA_CAP:
+ case MLX5_CMD_OP_QUERY_HCA_VPORT_CONTEXT:
case MLX5_CMD_OP_QUERY_VPORT_STATE:
case MLX5_CMD_OP_QUERY_ADAPTER:
case MLX5_CMD_OP_QUERY_ISSI:
@@ -498,14 +691,16 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OTHER)(
MLX5_IB_ATTR_DEVX_OTHER_CMD_OUT);
void *cmd_out;
int err;
+ int uid;
c = devx_ufile2uctx(file);
if (IS_ERR(c))
return PTR_ERR(c);
dev = to_mdev(c->ibucontext.device);
- if (!c->devx_uid)
- return -EPERM;
+ uid = devx_get_uid(c, cmd_in);
+ if (uid < 0)
+ return uid;
/* Only white list of some general HCA commands are allowed for this method. */
if (!devx_is_general_cmd(cmd_in))
@@ -515,7 +710,7 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OTHER)(
if (IS_ERR(cmd_out))
return PTR_ERR(cmd_out);
- MLX5_SET(general_obj_in_cmd_hdr, cmd_in, uid, c->devx_uid);
+ MLX5_SET(general_obj_in_cmd_hdr, cmd_in, uid, uid);
err = mlx5_cmd_exec(dev->mdev, cmd_in,
uverbs_attr_get_len(attrs, MLX5_IB_ATTR_DEVX_OTHER_CMD_IN),
cmd_out, cmd_out_len);
@@ -627,9 +822,9 @@ static void devx_obj_build_destroy_cmd(void *in, void *out, void *din,
MLX5_SET(general_obj_in_cmd_hdr, din, opcode,
MLX5_CMD_OP_DEALLOC_FLOW_COUNTER);
break;
- case MLX5_CMD_OP_ALLOC_ENCAP_HEADER:
+ case MLX5_CMD_OP_ALLOC_PACKET_REFORMAT_CONTEXT:
MLX5_SET(general_obj_in_cmd_hdr, din, opcode,
- MLX5_CMD_OP_DEALLOC_ENCAP_HEADER);
+ MLX5_CMD_OP_DEALLOC_PACKET_REFORMAT_CONTEXT);
break;
case MLX5_CMD_OP_ALLOC_MODIFY_HEADER_CONTEXT:
MLX5_SET(general_obj_in_cmd_hdr, din, opcode,
@@ -726,11 +921,15 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_CREATE)(
u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)];
struct devx_obj *obj;
int err;
+ int uid;
+ u32 obj_id;
+ u16 opcode;
- if (!c->devx_uid)
- return -EPERM;
+ uid = devx_get_uid(c, cmd_in);
+ if (uid < 0)
+ return uid;
- if (!devx_is_obj_create_cmd(cmd_in))
+ if (!devx_is_obj_create_cmd(cmd_in, &opcode))
return -EINVAL;
cmd_out = uverbs_zalloc(attrs, cmd_out_len);
@@ -741,7 +940,9 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_CREATE)(
if (!obj)
return -ENOMEM;
- MLX5_SET(general_obj_in_cmd_hdr, cmd_in, uid, c->devx_uid);
+ MLX5_SET(general_obj_in_cmd_hdr, cmd_in, uid, uid);
+ devx_set_umem_valid(cmd_in);
+
err = mlx5_cmd_exec(dev->mdev, cmd_in,
uverbs_attr_get_len(attrs, MLX5_IB_ATTR_DEVX_OBJ_CREATE_CMD_IN),
cmd_out, cmd_out_len);
@@ -750,13 +951,15 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_CREATE)(
uobj->object = obj;
obj->mdev = dev->mdev;
- devx_obj_build_destroy_cmd(cmd_in, cmd_out, obj->dinbox, &obj->dinlen, &obj->obj_id);
+ devx_obj_build_destroy_cmd(cmd_in, cmd_out, obj->dinbox, &obj->dinlen,
+ &obj_id);
WARN_ON(obj->dinlen > MLX5_MAX_DESTROY_INBOX_SIZE_DW * sizeof(u32));
err = uverbs_copy_to(attrs, MLX5_IB_ATTR_DEVX_OBJ_CREATE_CMD_OUT, cmd_out, cmd_out_len);
if (err)
goto obj_destroy;
+ obj->obj_id = get_enc_obj_id(opcode, obj_id);
return 0;
obj_destroy:
@@ -778,9 +981,11 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_MODIFY)(
struct devx_obj *obj = uobj->object;
void *cmd_out;
int err;
+ int uid;
- if (!c->devx_uid)
- return -EPERM;
+ uid = devx_get_uid(c, cmd_in);
+ if (uid < 0)
+ return uid;
if (!devx_is_obj_modify_cmd(cmd_in))
return -EINVAL;
@@ -792,7 +997,9 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_MODIFY)(
if (IS_ERR(cmd_out))
return PTR_ERR(cmd_out);
- MLX5_SET(general_obj_in_cmd_hdr, cmd_in, uid, c->devx_uid);
+ MLX5_SET(general_obj_in_cmd_hdr, cmd_in, uid, uid);
+ devx_set_umem_valid(cmd_in);
+
err = mlx5_cmd_exec(obj->mdev, cmd_in,
uverbs_attr_get_len(attrs, MLX5_IB_ATTR_DEVX_OBJ_MODIFY_CMD_IN),
cmd_out, cmd_out_len);
@@ -815,9 +1022,11 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_QUERY)(
struct devx_obj *obj = uobj->object;
void *cmd_out;
int err;
+ int uid;
- if (!c->devx_uid)
- return -EPERM;
+ uid = devx_get_uid(c, cmd_in);
+ if (uid < 0)
+ return uid;
if (!devx_is_obj_query_cmd(cmd_in))
return -EINVAL;
@@ -829,7 +1038,7 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_QUERY)(
if (IS_ERR(cmd_out))
return PTR_ERR(cmd_out);
- MLX5_SET(general_obj_in_cmd_hdr, cmd_in, uid, c->devx_uid);
+ MLX5_SET(general_obj_in_cmd_hdr, cmd_in, uid, uid);
err = mlx5_cmd_exec(obj->mdev, cmd_in,
uverbs_attr_get_len(attrs, MLX5_IB_ATTR_DEVX_OBJ_QUERY_CMD_IN),
cmd_out, cmd_out_len);
@@ -928,6 +1137,9 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_UMEM_REG)(
int err;
if (!c->devx_uid)
+ return -EINVAL;
+
+ if (!capable(CAP_NET_RAW))
return -EPERM;
obj = kzalloc(sizeof(struct devx_umem), GFP_KERNEL);
diff --git a/drivers/infiniband/hw/mlx5/flow.c b/drivers/infiniband/hw/mlx5/flow.c
index 1a29f47f836e..f86cdcafdafc 100644
--- a/drivers/infiniband/hw/mlx5/flow.c
+++ b/drivers/infiniband/hw/mlx5/flow.c
@@ -7,7 +7,9 @@
#include <rdma/ib_verbs.h>
#include <rdma/uverbs_types.h>
#include <rdma/uverbs_ioctl.h>
+#include <rdma/uverbs_std_types.h>
#include <rdma/mlx5_user_ioctl_cmds.h>
+#include <rdma/mlx5_user_ioctl_verbs.h>
#include <rdma/ib_umem.h>
#include <linux/mlx5/driver.h>
#include <linux/mlx5/fs.h>
@@ -16,6 +18,24 @@
#define UVERBS_MODULE_NAME mlx5_ib
#include <rdma/uverbs_named_ioctl.h>
+static int
+mlx5_ib_ft_type_to_namespace(enum mlx5_ib_uapi_flow_table_type table_type,
+ enum mlx5_flow_namespace_type *namespace)
+{
+ switch (table_type) {
+ case MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_RX:
+ *namespace = MLX5_FLOW_NAMESPACE_BYPASS;
+ break;
+ case MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_TX:
+ *namespace = MLX5_FLOW_NAMESPACE_EGRESS;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static const struct uverbs_attr_spec mlx5_ib_flow_type[] = {
[MLX5_IB_FLOW_TYPE_NORMAL] = {
.type = UVERBS_ATTR_TYPE_PTR_IN,
@@ -38,11 +58,15 @@ static const struct uverbs_attr_spec mlx5_ib_flow_type[] = {
},
};
+#define MLX5_IB_CREATE_FLOW_MAX_FLOW_ACTIONS 2
static int UVERBS_HANDLER(MLX5_IB_METHOD_CREATE_FLOW)(
struct ib_uverbs_file *file, struct uverbs_attr_bundle *attrs)
{
+ struct mlx5_flow_act flow_act = {.flow_tag = MLX5_FS_DEFAULT_FLOW_TAG};
struct mlx5_ib_flow_handler *flow_handler;
struct mlx5_ib_flow_matcher *fs_matcher;
+ struct ib_uobject **arr_flow_actions;
+ struct ib_uflow_resources *uflow_res;
void *devx_obj;
int dest_id, dest_type;
void *cmd_in;
@@ -52,6 +76,7 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_CREATE_FLOW)(
struct ib_uobject *uobj =
uverbs_attr_get_uobject(attrs, MLX5_IB_ATTR_CREATE_FLOW_HANDLE);
struct mlx5_ib_dev *dev = to_mdev(uobj->context->device);
+ int len, ret, i;
if (!capable(CAP_NET_RAW))
return -EPERM;
@@ -61,7 +86,14 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_CREATE_FLOW)(
dest_qp = uverbs_attr_is_valid(attrs,
MLX5_IB_ATTR_CREATE_FLOW_DEST_QP);
- if ((dest_devx && dest_qp) || (!dest_devx && !dest_qp))
+ fs_matcher = uverbs_attr_get_obj(attrs,
+ MLX5_IB_ATTR_CREATE_FLOW_MATCHER);
+ if (fs_matcher->ns_type == MLX5_FLOW_NAMESPACE_BYPASS &&
+ ((dest_devx && dest_qp) || (!dest_devx && !dest_qp)))
+ return -EINVAL;
+
+ if (fs_matcher->ns_type == MLX5_FLOW_NAMESPACE_EGRESS &&
+ (dest_devx || dest_qp))
return -EINVAL;
if (dest_devx) {
@@ -75,7 +107,7 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_CREATE_FLOW)(
*/
if (!mlx5_ib_devx_is_flow_dest(devx_obj, &dest_id, &dest_type))
return -EINVAL;
- } else {
+ } else if (dest_qp) {
struct mlx5_ib_qp *mqp;
qp = uverbs_attr_get_obj(attrs,
@@ -92,6 +124,8 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_CREATE_FLOW)(
else
dest_id = mqp->raw_packet_qp.rq.tirn;
dest_type = MLX5_FLOW_DESTINATION_TYPE_TIR;
+ } else {
+ dest_type = MLX5_FLOW_DESTINATION_TYPE_PORT;
}
if (dev->rep)
@@ -101,16 +135,48 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_CREATE_FLOW)(
attrs, MLX5_IB_ATTR_CREATE_FLOW_MATCH_VALUE);
inlen = uverbs_attr_get_len(attrs,
MLX5_IB_ATTR_CREATE_FLOW_MATCH_VALUE);
- fs_matcher = uverbs_attr_get_obj(attrs,
- MLX5_IB_ATTR_CREATE_FLOW_MATCHER);
- flow_handler = mlx5_ib_raw_fs_rule_add(dev, fs_matcher, cmd_in, inlen,
+
+ uflow_res = flow_resources_alloc(MLX5_IB_CREATE_FLOW_MAX_FLOW_ACTIONS);
+ if (!uflow_res)
+ return -ENOMEM;
+
+ len = uverbs_attr_get_uobjs_arr(attrs,
+ MLX5_IB_ATTR_CREATE_FLOW_ARR_FLOW_ACTIONS, &arr_flow_actions);
+ for (i = 0; i < len; i++) {
+ struct mlx5_ib_flow_action *maction =
+ to_mflow_act(arr_flow_actions[i]->object);
+
+ ret = parse_flow_flow_action(maction, false, &flow_act);
+ if (ret)
+ goto err_out;
+ flow_resources_add(uflow_res, IB_FLOW_SPEC_ACTION_HANDLE,
+ arr_flow_actions[i]->object);
+ }
+
+ ret = uverbs_copy_from(&flow_act.flow_tag, attrs,
+ MLX5_IB_ATTR_CREATE_FLOW_TAG);
+ if (!ret) {
+ if (flow_act.flow_tag >= BIT(24)) {
+ ret = -EINVAL;
+ goto err_out;
+ }
+ flow_act.flags |= FLOW_ACT_HAS_TAG;
+ }
+
+ flow_handler = mlx5_ib_raw_fs_rule_add(dev, fs_matcher, &flow_act,
+ cmd_in, inlen,
dest_id, dest_type);
- if (IS_ERR(flow_handler))
- return PTR_ERR(flow_handler);
+ if (IS_ERR(flow_handler)) {
+ ret = PTR_ERR(flow_handler);
+ goto err_out;
+ }
- ib_set_flow(uobj, &flow_handler->ibflow, qp, &dev->ib_dev);
+ ib_set_flow(uobj, &flow_handler->ibflow, qp, &dev->ib_dev, uflow_res);
return 0;
+err_out:
+ ib_uverbs_flow_resources_free(uflow_res);
+ return ret;
}
static int flow_matcher_cleanup(struct ib_uobject *uobject,
@@ -134,12 +200,14 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_FLOW_MATCHER_CREATE)(
attrs, MLX5_IB_ATTR_FLOW_MATCHER_CREATE_HANDLE);
struct mlx5_ib_dev *dev = to_mdev(uobj->context->device);
struct mlx5_ib_flow_matcher *obj;
+ u32 flags;
int err;
obj = kzalloc(sizeof(struct mlx5_ib_flow_matcher), GFP_KERNEL);
if (!obj)
return -ENOMEM;
+ obj->ns_type = MLX5_FLOW_NAMESPACE_BYPASS;
obj->mask_len = uverbs_attr_get_len(
attrs, MLX5_IB_ATTR_FLOW_MATCHER_MATCH_MASK);
err = uverbs_copy_from(&obj->matcher_mask,
@@ -165,6 +233,19 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_FLOW_MATCHER_CREATE)(
if (err)
goto end;
+ err = uverbs_get_flags32(&flags, attrs,
+ MLX5_IB_ATTR_FLOW_MATCHER_FLOW_FLAGS,
+ IB_FLOW_ATTR_FLAGS_EGRESS);
+ if (err)
+ goto end;
+
+ if (flags) {
+ err = mlx5_ib_ft_type_to_namespace(
+ MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_TX, &obj->ns_type);
+ if (err)
+ goto end;
+ }
+
uobj->object = obj;
obj->mdev = dev->mdev;
atomic_set(&obj->usecnt, 0);
@@ -175,6 +256,248 @@ end:
return err;
}
+void mlx5_ib_destroy_flow_action_raw(struct mlx5_ib_flow_action *maction)
+{
+ switch (maction->flow_action_raw.sub_type) {
+ case MLX5_IB_FLOW_ACTION_MODIFY_HEADER:
+ mlx5_modify_header_dealloc(maction->flow_action_raw.dev->mdev,
+ maction->flow_action_raw.action_id);
+ break;
+ case MLX5_IB_FLOW_ACTION_PACKET_REFORMAT:
+ mlx5_packet_reformat_dealloc(maction->flow_action_raw.dev->mdev,
+ maction->flow_action_raw.action_id);
+ break;
+ case MLX5_IB_FLOW_ACTION_DECAP:
+ break;
+ default:
+ break;
+ }
+}
+
+static struct ib_flow_action *
+mlx5_ib_create_modify_header(struct mlx5_ib_dev *dev,
+ enum mlx5_ib_uapi_flow_table_type ft_type,
+ u8 num_actions, void *in)
+{
+ enum mlx5_flow_namespace_type namespace;
+ struct mlx5_ib_flow_action *maction;
+ int ret;
+
+ ret = mlx5_ib_ft_type_to_namespace(ft_type, &namespace);
+ if (ret)
+ return ERR_PTR(-EINVAL);
+
+ maction = kzalloc(sizeof(*maction), GFP_KERNEL);
+ if (!maction)
+ return ERR_PTR(-ENOMEM);
+
+ ret = mlx5_modify_header_alloc(dev->mdev, namespace, num_actions, in,
+ &maction->flow_action_raw.action_id);
+
+ if (ret) {
+ kfree(maction);
+ return ERR_PTR(ret);
+ }
+ maction->flow_action_raw.sub_type =
+ MLX5_IB_FLOW_ACTION_MODIFY_HEADER;
+ maction->flow_action_raw.dev = dev;
+
+ return &maction->ib_action;
+}
+
+static bool mlx5_ib_modify_header_supported(struct mlx5_ib_dev *dev)
+{
+ return MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev,
+ max_modify_header_actions) ||
+ MLX5_CAP_FLOWTABLE_NIC_TX(dev->mdev, max_modify_header_actions);
+}
+
+static int UVERBS_HANDLER(MLX5_IB_METHOD_FLOW_ACTION_CREATE_MODIFY_HEADER)(
+ struct ib_uverbs_file *file,
+ struct uverbs_attr_bundle *attrs)
+{
+ struct ib_uobject *uobj = uverbs_attr_get_uobject(
+ attrs, MLX5_IB_ATTR_CREATE_MODIFY_HEADER_HANDLE);
+ struct mlx5_ib_dev *mdev = to_mdev(uobj->context->device);
+ enum mlx5_ib_uapi_flow_table_type ft_type;
+ struct ib_flow_action *action;
+ size_t num_actions;
+ void *in;
+ int len;
+ int ret;
+
+ if (!mlx5_ib_modify_header_supported(mdev))
+ return -EOPNOTSUPP;
+
+ in = uverbs_attr_get_alloced_ptr(attrs,
+ MLX5_IB_ATTR_CREATE_MODIFY_HEADER_ACTIONS_PRM);
+ len = uverbs_attr_get_len(attrs,
+ MLX5_IB_ATTR_CREATE_MODIFY_HEADER_ACTIONS_PRM);
+
+ if (len % MLX5_UN_SZ_BYTES(set_action_in_add_action_in_auto))
+ return -EINVAL;
+
+ ret = uverbs_get_const(&ft_type, attrs,
+ MLX5_IB_ATTR_CREATE_MODIFY_HEADER_FT_TYPE);
+ if (ret)
+ return ret;
+
+ num_actions = len / MLX5_UN_SZ_BYTES(set_action_in_add_action_in_auto),
+ action = mlx5_ib_create_modify_header(mdev, ft_type, num_actions, in);
+ if (IS_ERR(action))
+ return PTR_ERR(action);
+
+ uverbs_flow_action_fill_action(action, uobj, uobj->context->device,
+ IB_FLOW_ACTION_UNSPECIFIED);
+
+ return 0;
+}
+
+static bool mlx5_ib_flow_action_packet_reformat_valid(struct mlx5_ib_dev *ibdev,
+ u8 packet_reformat_type,
+ u8 ft_type)
+{
+ switch (packet_reformat_type) {
+ case MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L2_TUNNEL:
+ if (ft_type == MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_TX)
+ return MLX5_CAP_FLOWTABLE(ibdev->mdev,
+ encap_general_header);
+ break;
+ case MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L3_TUNNEL:
+ if (ft_type == MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_TX)
+ return MLX5_CAP_FLOWTABLE_NIC_TX(ibdev->mdev,
+ reformat_l2_to_l3_tunnel);
+ break;
+ case MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L3_TUNNEL_TO_L2:
+ if (ft_type == MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_RX)
+ return MLX5_CAP_FLOWTABLE_NIC_RX(ibdev->mdev,
+ reformat_l3_tunnel_to_l2);
+ break;
+ case MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2:
+ if (ft_type == MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_RX)
+ return MLX5_CAP_FLOWTABLE_NIC_RX(ibdev->mdev, decap);
+ break;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+static int mlx5_ib_dv_to_prm_packet_reforamt_type(u8 dv_prt, u8 *prm_prt)
+{
+ switch (dv_prt) {
+ case MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L2_TUNNEL:
+ *prm_prt = MLX5_REFORMAT_TYPE_L2_TO_L2_TUNNEL;
+ break;
+ case MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L3_TUNNEL_TO_L2:
+ *prm_prt = MLX5_REFORMAT_TYPE_L3_TUNNEL_TO_L2;
+ break;
+ case MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L3_TUNNEL:
+ *prm_prt = MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mlx5_ib_flow_action_create_packet_reformat_ctx(
+ struct mlx5_ib_dev *dev,
+ struct mlx5_ib_flow_action *maction,
+ u8 ft_type, u8 dv_prt,
+ void *in, size_t len)
+{
+ enum mlx5_flow_namespace_type namespace;
+ u8 prm_prt;
+ int ret;
+
+ ret = mlx5_ib_ft_type_to_namespace(ft_type, &namespace);
+ if (ret)
+ return ret;
+
+ ret = mlx5_ib_dv_to_prm_packet_reforamt_type(dv_prt, &prm_prt);
+ if (ret)
+ return ret;
+
+ ret = mlx5_packet_reformat_alloc(dev->mdev, prm_prt, len,
+ in, namespace,
+ &maction->flow_action_raw.action_id);
+ if (ret)
+ return ret;
+
+ maction->flow_action_raw.sub_type =
+ MLX5_IB_FLOW_ACTION_PACKET_REFORMAT;
+ maction->flow_action_raw.dev = dev;
+
+ return 0;
+}
+
+static int UVERBS_HANDLER(MLX5_IB_METHOD_FLOW_ACTION_CREATE_PACKET_REFORMAT)(
+ struct ib_uverbs_file *file,
+ struct uverbs_attr_bundle *attrs)
+{
+ struct ib_uobject *uobj = uverbs_attr_get_uobject(attrs,
+ MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_HANDLE);
+ struct mlx5_ib_dev *mdev = to_mdev(uobj->context->device);
+ enum mlx5_ib_uapi_flow_action_packet_reformat_type dv_prt;
+ enum mlx5_ib_uapi_flow_table_type ft_type;
+ struct mlx5_ib_flow_action *maction;
+ int ret;
+
+ ret = uverbs_get_const(&ft_type, attrs,
+ MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_FT_TYPE);
+ if (ret)
+ return ret;
+
+ ret = uverbs_get_const(&dv_prt, attrs,
+ MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_TYPE);
+ if (ret)
+ return ret;
+
+ if (!mlx5_ib_flow_action_packet_reformat_valid(mdev, dv_prt, ft_type))
+ return -EOPNOTSUPP;
+
+ maction = kzalloc(sizeof(*maction), GFP_KERNEL);
+ if (!maction)
+ return -ENOMEM;
+
+ if (dv_prt ==
+ MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2) {
+ maction->flow_action_raw.sub_type =
+ MLX5_IB_FLOW_ACTION_DECAP;
+ maction->flow_action_raw.dev = mdev;
+ } else {
+ void *in;
+ int len;
+
+ in = uverbs_attr_get_alloced_ptr(attrs,
+ MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_DATA_BUF);
+ if (IS_ERR(in)) {
+ ret = PTR_ERR(in);
+ goto free_maction;
+ }
+
+ len = uverbs_attr_get_len(attrs,
+ MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_DATA_BUF);
+
+ ret = mlx5_ib_flow_action_create_packet_reformat_ctx(mdev,
+ maction, ft_type, dv_prt, in, len);
+ if (ret)
+ goto free_maction;
+ }
+
+ uverbs_flow_action_fill_action(&maction->ib_action, uobj,
+ uobj->context->device,
+ IB_FLOW_ACTION_UNSPECIFIED);
+ return 0;
+
+free_maction:
+ kfree(maction);
+ return ret;
+}
+
DECLARE_UVERBS_NAMED_METHOD(
MLX5_IB_METHOD_CREATE_FLOW,
UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_FLOW_HANDLE,
@@ -195,7 +518,15 @@ DECLARE_UVERBS_NAMED_METHOD(
UVERBS_ACCESS_READ),
UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_FLOW_DEST_DEVX,
MLX5_IB_OBJECT_DEVX_OBJ,
- UVERBS_ACCESS_READ));
+ UVERBS_ACCESS_READ),
+ UVERBS_ATTR_IDRS_ARR(MLX5_IB_ATTR_CREATE_FLOW_ARR_FLOW_ACTIONS,
+ UVERBS_OBJECT_FLOW_ACTION,
+ UVERBS_ACCESS_READ, 1,
+ MLX5_IB_CREATE_FLOW_MAX_FLOW_ACTIONS,
+ UA_OPTIONAL),
+ UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_CREATE_FLOW_TAG,
+ UVERBS_ATTR_TYPE(u32),
+ UA_OPTIONAL));
DECLARE_UVERBS_NAMED_METHOD_DESTROY(
MLX5_IB_METHOD_DESTROY_FLOW,
@@ -210,6 +541,44 @@ ADD_UVERBS_METHODS(mlx5_ib_fs,
&UVERBS_METHOD(MLX5_IB_METHOD_DESTROY_FLOW));
DECLARE_UVERBS_NAMED_METHOD(
+ MLX5_IB_METHOD_FLOW_ACTION_CREATE_MODIFY_HEADER,
+ UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_MODIFY_HEADER_HANDLE,
+ UVERBS_OBJECT_FLOW_ACTION,
+ UVERBS_ACCESS_NEW,
+ UA_MANDATORY),
+ UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_CREATE_MODIFY_HEADER_ACTIONS_PRM,
+ UVERBS_ATTR_MIN_SIZE(MLX5_UN_SZ_BYTES(
+ set_action_in_add_action_in_auto)),
+ UA_MANDATORY,
+ UA_ALLOC_AND_COPY),
+ UVERBS_ATTR_CONST_IN(MLX5_IB_ATTR_CREATE_MODIFY_HEADER_FT_TYPE,
+ enum mlx5_ib_uapi_flow_table_type,
+ UA_MANDATORY));
+
+DECLARE_UVERBS_NAMED_METHOD(
+ MLX5_IB_METHOD_FLOW_ACTION_CREATE_PACKET_REFORMAT,
+ UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_HANDLE,
+ UVERBS_OBJECT_FLOW_ACTION,
+ UVERBS_ACCESS_NEW,
+ UA_MANDATORY),
+ UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_DATA_BUF,
+ UVERBS_ATTR_MIN_SIZE(1),
+ UA_ALLOC_AND_COPY,
+ UA_OPTIONAL),
+ UVERBS_ATTR_CONST_IN(MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_TYPE,
+ enum mlx5_ib_uapi_flow_action_packet_reformat_type,
+ UA_MANDATORY),
+ UVERBS_ATTR_CONST_IN(MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_FT_TYPE,
+ enum mlx5_ib_uapi_flow_table_type,
+ UA_MANDATORY));
+
+ADD_UVERBS_METHODS(
+ mlx5_ib_flow_actions,
+ UVERBS_OBJECT_FLOW_ACTION,
+ &UVERBS_METHOD(MLX5_IB_METHOD_FLOW_ACTION_CREATE_MODIFY_HEADER),
+ &UVERBS_METHOD(MLX5_IB_METHOD_FLOW_ACTION_CREATE_PACKET_REFORMAT));
+
+DECLARE_UVERBS_NAMED_METHOD(
MLX5_IB_METHOD_FLOW_MATCHER_CREATE,
UVERBS_ATTR_IDR(MLX5_IB_ATTR_FLOW_MATCHER_CREATE_HANDLE,
MLX5_IB_OBJECT_FLOW_MATCHER,
@@ -224,7 +593,10 @@ DECLARE_UVERBS_NAMED_METHOD(
UA_MANDATORY),
UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_FLOW_MATCHER_MATCH_CRITERIA,
UVERBS_ATTR_TYPE(u8),
- UA_MANDATORY));
+ UA_MANDATORY),
+ UVERBS_ATTR_FLAGS_IN(MLX5_IB_ATTR_FLOW_MATCHER_FLOW_FLAGS,
+ enum ib_flow_flags,
+ UA_OPTIONAL));
DECLARE_UVERBS_NAMED_METHOD_DESTROY(
MLX5_IB_METHOD_FLOW_MATCHER_DESTROY,
@@ -247,6 +619,7 @@ int mlx5_ib_get_flow_trees(const struct uverbs_object_tree_def **root)
root[i++] = &flow_objects;
root[i++] = &mlx5_ib_fs;
+ root[i++] = &mlx5_ib_flow_actions;
return i;
}
diff --git a/drivers/infiniband/hw/mlx5/ib_rep.c b/drivers/infiniband/hw/mlx5/ib_rep.c
index 35a0e04c38f2..584ff2ea7810 100644
--- a/drivers/infiniband/hw/mlx5/ib_rep.c
+++ b/drivers/infiniband/hw/mlx5/ib_rep.c
@@ -39,9 +39,6 @@ static const struct mlx5_ib_profile rep_profile = {
STAGE_CREATE(MLX5_IB_STAGE_POST_IB_REG_UMR,
mlx5_ib_stage_post_ib_reg_umr_init,
NULL),
- STAGE_CREATE(MLX5_IB_STAGE_CLASS_ATTR,
- mlx5_ib_stage_class_attr_init,
- NULL),
};
static int
diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c
index c414f3809e5c..e9c428071df3 100644
--- a/drivers/infiniband/hw/mlx5/main.c
+++ b/drivers/infiniband/hw/mlx5/main.c
@@ -1571,14 +1571,57 @@ static void deallocate_uars(struct mlx5_ib_dev *dev,
mlx5_cmd_free_uar(dev->mdev, bfregi->sys_pages[i]);
}
-static int mlx5_ib_alloc_transport_domain(struct mlx5_ib_dev *dev, u32 *tdn)
+int mlx5_ib_enable_lb(struct mlx5_ib_dev *dev, bool td, bool qp)
+{
+ int err = 0;
+
+ mutex_lock(&dev->lb.mutex);
+ if (td)
+ dev->lb.user_td++;
+ if (qp)
+ dev->lb.qps++;
+
+ if (dev->lb.user_td == 2 ||
+ dev->lb.qps == 1) {
+ if (!dev->lb.enabled) {
+ err = mlx5_nic_vport_update_local_lb(dev->mdev, true);
+ dev->lb.enabled = true;
+ }
+ }
+
+ mutex_unlock(&dev->lb.mutex);
+
+ return err;
+}
+
+void mlx5_ib_disable_lb(struct mlx5_ib_dev *dev, bool td, bool qp)
+{
+ mutex_lock(&dev->lb.mutex);
+ if (td)
+ dev->lb.user_td--;
+ if (qp)
+ dev->lb.qps--;
+
+ if (dev->lb.user_td == 1 &&
+ dev->lb.qps == 0) {
+ if (dev->lb.enabled) {
+ mlx5_nic_vport_update_local_lb(dev->mdev, false);
+ dev->lb.enabled = false;
+ }
+ }
+
+ mutex_unlock(&dev->lb.mutex);
+}
+
+static int mlx5_ib_alloc_transport_domain(struct mlx5_ib_dev *dev, u32 *tdn,
+ u16 uid)
{
int err;
if (!MLX5_CAP_GEN(dev->mdev, log_max_transport_domain))
return 0;
- err = mlx5_core_alloc_transport_domain(dev->mdev, tdn);
+ err = mlx5_cmd_alloc_transport_domain(dev->mdev, tdn, uid);
if (err)
return err;
@@ -1587,35 +1630,23 @@ static int mlx5_ib_alloc_transport_domain(struct mlx5_ib_dev *dev, u32 *tdn)
!MLX5_CAP_GEN(dev->mdev, disable_local_lb_mc)))
return err;
- mutex_lock(&dev->lb_mutex);
- dev->user_td++;
-
- if (dev->user_td == 2)
- err = mlx5_nic_vport_update_local_lb(dev->mdev, true);
-
- mutex_unlock(&dev->lb_mutex);
- return err;
+ return mlx5_ib_enable_lb(dev, true, false);
}
-static void mlx5_ib_dealloc_transport_domain(struct mlx5_ib_dev *dev, u32 tdn)
+static void mlx5_ib_dealloc_transport_domain(struct mlx5_ib_dev *dev, u32 tdn,
+ u16 uid)
{
if (!MLX5_CAP_GEN(dev->mdev, log_max_transport_domain))
return;
- mlx5_core_dealloc_transport_domain(dev->mdev, tdn);
+ mlx5_cmd_dealloc_transport_domain(dev->mdev, tdn, uid);
if ((MLX5_CAP_GEN(dev->mdev, port_type) != MLX5_CAP_PORT_TYPE_ETH) ||
(!MLX5_CAP_GEN(dev->mdev, disable_local_lb_uc) &&
!MLX5_CAP_GEN(dev->mdev, disable_local_lb_mc)))
return;
- mutex_lock(&dev->lb_mutex);
- dev->user_td--;
-
- if (dev->user_td < 2)
- mlx5_nic_vport_update_local_lb(dev->mdev, false);
-
- mutex_unlock(&dev->lb_mutex);
+ mlx5_ib_disable_lb(dev, true, false);
}
static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev,
@@ -1727,30 +1758,24 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev,
context->ibucontext.invalidate_range = &mlx5_ib_invalidate_range;
#endif
- err = mlx5_ib_alloc_transport_domain(dev, &context->tdn);
- if (err)
- goto out_uars;
-
if (req.flags & MLX5_IB_ALLOC_UCTX_DEVX) {
- /* Block DEVX on Infiniband as of SELinux */
- if (mlx5_ib_port_link_layer(ibdev, 1) != IB_LINK_LAYER_ETHERNET) {
- err = -EPERM;
- goto out_td;
- }
-
- err = mlx5_ib_devx_create(dev, context);
- if (err)
- goto out_td;
+ err = mlx5_ib_devx_create(dev);
+ if (err < 0)
+ goto out_uars;
+ context->devx_uid = err;
}
+ err = mlx5_ib_alloc_transport_domain(dev, &context->tdn,
+ context->devx_uid);
+ if (err)
+ goto out_devx;
+
if (MLX5_CAP_GEN(dev->mdev, dump_fill_mkey)) {
err = mlx5_cmd_dump_fill_mkey(dev->mdev, &dump_fill_mkey);
if (err)
goto out_mdev;
}
- INIT_LIST_HEAD(&context->vma_private_list);
- mutex_init(&context->vma_private_list_mutex);
INIT_LIST_HEAD(&context->db_page_list);
mutex_init(&context->db_page_mutex);
@@ -1826,13 +1851,21 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev,
context->lib_caps = req.lib_caps;
print_lib_caps(dev, context->lib_caps);
+ if (mlx5_lag_is_active(dev->mdev)) {
+ u8 port = mlx5_core_native_port_num(dev->mdev);
+
+ atomic_set(&context->tx_port_affinity,
+ atomic_add_return(
+ 1, &dev->roce[port].tx_port_affinity));
+ }
+
return &context->ibucontext;
out_mdev:
+ mlx5_ib_dealloc_transport_domain(dev, context->tdn, context->devx_uid);
+out_devx:
if (req.flags & MLX5_IB_ALLOC_UCTX_DEVX)
- mlx5_ib_devx_destroy(dev, context);
-out_td:
- mlx5_ib_dealloc_transport_domain(dev, context->tdn);
+ mlx5_ib_devx_destroy(dev, context->devx_uid);
out_uars:
deallocate_uars(dev, context);
@@ -1855,11 +1888,18 @@ static int mlx5_ib_dealloc_ucontext(struct ib_ucontext *ibcontext)
struct mlx5_ib_dev *dev = to_mdev(ibcontext->device);
struct mlx5_bfreg_info *bfregi;
- if (context->devx_uid)
- mlx5_ib_devx_destroy(dev, context);
+#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING
+ /* All umem's must be destroyed before destroying the ucontext. */
+ mutex_lock(&ibcontext->per_mm_list_lock);
+ WARN_ON(!list_empty(&ibcontext->per_mm_list));
+ mutex_unlock(&ibcontext->per_mm_list_lock);
+#endif
bfregi = &context->bfregi;
- mlx5_ib_dealloc_transport_domain(dev, context->tdn);
+ mlx5_ib_dealloc_transport_domain(dev, context->tdn, context->devx_uid);
+
+ if (context->devx_uid)
+ mlx5_ib_devx_destroy(dev, context->devx_uid);
deallocate_uars(dev, context);
kfree(bfregi->sys_pages);
@@ -1900,94 +1940,9 @@ static int get_extended_index(unsigned long offset)
return get_arg(offset) | ((offset >> 16) & 0xff) << 8;
}
-static void mlx5_ib_vma_open(struct vm_area_struct *area)
-{
- /* vma_open is called when a new VMA is created on top of our VMA. This
- * is done through either mremap flow or split_vma (usually due to
- * mlock, madvise, munmap, etc.) We do not support a clone of the VMA,
- * as this VMA is strongly hardware related. Therefore we set the
- * vm_ops of the newly created/cloned VMA to NULL, to prevent it from
- * calling us again and trying to do incorrect actions. We assume that
- * the original VMA size is exactly a single page, and therefore all
- * "splitting" operation will not happen to it.
- */
- area->vm_ops = NULL;
-}
-
-static void mlx5_ib_vma_close(struct vm_area_struct *area)
-{
- struct mlx5_ib_vma_private_data *mlx5_ib_vma_priv_data;
-
- /* It's guaranteed that all VMAs opened on a FD are closed before the
- * file itself is closed, therefore no sync is needed with the regular
- * closing flow. (e.g. mlx5 ib_dealloc_ucontext)
- * However need a sync with accessing the vma as part of
- * mlx5_ib_disassociate_ucontext.
- * The close operation is usually called under mm->mmap_sem except when
- * process is exiting.
- * The exiting case is handled explicitly as part of
- * mlx5_ib_disassociate_ucontext.
- */
- mlx5_ib_vma_priv_data = (struct mlx5_ib_vma_private_data *)area->vm_private_data;
-
- /* setting the vma context pointer to null in the mlx5_ib driver's
- * private data, to protect a race condition in
- * mlx5_ib_disassociate_ucontext().
- */
- mlx5_ib_vma_priv_data->vma = NULL;
- mutex_lock(mlx5_ib_vma_priv_data->vma_private_list_mutex);
- list_del(&mlx5_ib_vma_priv_data->list);
- mutex_unlock(mlx5_ib_vma_priv_data->vma_private_list_mutex);
- kfree(mlx5_ib_vma_priv_data);
-}
-
-static const struct vm_operations_struct mlx5_ib_vm_ops = {
- .open = mlx5_ib_vma_open,
- .close = mlx5_ib_vma_close
-};
-
-static int mlx5_ib_set_vma_data(struct vm_area_struct *vma,
- struct mlx5_ib_ucontext *ctx)
-{
- struct mlx5_ib_vma_private_data *vma_prv;
- struct list_head *vma_head = &ctx->vma_private_list;
-
- vma_prv = kzalloc(sizeof(*vma_prv), GFP_KERNEL);
- if (!vma_prv)
- return -ENOMEM;
-
- vma_prv->vma = vma;
- vma_prv->vma_private_list_mutex = &ctx->vma_private_list_mutex;
- vma->vm_private_data = vma_prv;
- vma->vm_ops = &mlx5_ib_vm_ops;
-
- mutex_lock(&ctx->vma_private_list_mutex);
- list_add(&vma_prv->list, vma_head);
- mutex_unlock(&ctx->vma_private_list_mutex);
-
- return 0;
-}
static void mlx5_ib_disassociate_ucontext(struct ib_ucontext *ibcontext)
{
- struct vm_area_struct *vma;
- struct mlx5_ib_vma_private_data *vma_private, *n;
- struct mlx5_ib_ucontext *context = to_mucontext(ibcontext);
-
- mutex_lock(&context->vma_private_list_mutex);
- list_for_each_entry_safe(vma_private, n, &context->vma_private_list,
- list) {
- vma = vma_private->vma;
- zap_vma_ptes(vma, vma->vm_start, PAGE_SIZE);
- /* context going to be destroyed, should
- * not access ops any more.
- */
- vma->vm_flags &= ~(VM_SHARED | VM_MAYSHARE);
- vma->vm_ops = NULL;
- list_del(&vma_private->list);
- kfree(vma_private);
- }
- mutex_unlock(&context->vma_private_list_mutex);
}
static inline char *mmap_cmd2str(enum mlx5_ib_mmap_cmd cmd)
@@ -2010,9 +1965,6 @@ static int mlx5_ib_mmap_clock_info_page(struct mlx5_ib_dev *dev,
struct vm_area_struct *vma,
struct mlx5_ib_ucontext *context)
{
- phys_addr_t pfn;
- int err;
-
if (vma->vm_end - vma->vm_start != PAGE_SIZE)
return -EINVAL;
@@ -2025,13 +1977,8 @@ static int mlx5_ib_mmap_clock_info_page(struct mlx5_ib_dev *dev,
if (!dev->mdev->clock_info_page)
return -EOPNOTSUPP;
- pfn = page_to_pfn(dev->mdev->clock_info_page);
- err = remap_pfn_range(vma, vma->vm_start, pfn, PAGE_SIZE,
- vma->vm_page_prot);
- if (err)
- return err;
-
- return mlx5_ib_set_vma_data(vma, context);
+ return rdma_user_mmap_page(&context->ibucontext, vma,
+ dev->mdev->clock_info_page, PAGE_SIZE);
}
static int uar_mmap(struct mlx5_ib_dev *dev, enum mlx5_ib_mmap_cmd cmd,
@@ -2121,21 +2068,15 @@ static int uar_mmap(struct mlx5_ib_dev *dev, enum mlx5_ib_mmap_cmd cmd,
pfn = uar_index2pfn(dev, uar_index);
mlx5_ib_dbg(dev, "uar idx 0x%lx, pfn %pa\n", idx, &pfn);
- vma->vm_page_prot = prot;
- err = io_remap_pfn_range(vma, vma->vm_start, pfn,
- PAGE_SIZE, vma->vm_page_prot);
+ err = rdma_user_mmap_io(&context->ibucontext, vma, pfn, PAGE_SIZE,
+ prot);
if (err) {
mlx5_ib_err(dev,
- "io_remap_pfn_range failed with error=%d, mmap_cmd=%s\n",
+ "rdma_user_mmap_io failed with error=%d, mmap_cmd=%s\n",
err, mmap_cmd2str(cmd));
- err = -EAGAIN;
goto err;
}
- err = mlx5_ib_set_vma_data(vma, context);
- if (err)
- goto err;
-
if (dyn_uar)
bfregi->sys_pages[idx] = uar_index;
return 0;
@@ -2160,7 +2101,6 @@ static int dm_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
size_t map_size = vma->vm_end - vma->vm_start;
u32 npages = map_size >> PAGE_SHIFT;
phys_addr_t pfn;
- pgprot_t prot;
if (find_next_zero_bit(mctx->dm_pages, page_idx + npages, page_idx) !=
page_idx + npages)
@@ -2170,14 +2110,8 @@ static int dm_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
MLX5_CAP64_DEV_MEM(dev->mdev, memic_bar_start_addr)) >>
PAGE_SHIFT) +
page_idx;
- prot = pgprot_writecombine(vma->vm_page_prot);
- vma->vm_page_prot = prot;
-
- if (io_remap_pfn_range(vma, vma->vm_start, pfn, map_size,
- vma->vm_page_prot))
- return -EAGAIN;
-
- return mlx5_ib_set_vma_data(vma, mctx);
+ return rdma_user_mmap_io(context, vma, pfn, map_size,
+ pgprot_writecombine(vma->vm_page_prot));
}
static int mlx5_ib_mmap(struct ib_ucontext *ibcontext, struct vm_area_struct *vma)
@@ -2318,21 +2252,30 @@ static struct ib_pd *mlx5_ib_alloc_pd(struct ib_device *ibdev,
struct mlx5_ib_alloc_pd_resp resp;
struct mlx5_ib_pd *pd;
int err;
+ u32 out[MLX5_ST_SZ_DW(alloc_pd_out)] = {};
+ u32 in[MLX5_ST_SZ_DW(alloc_pd_in)] = {};
+ u16 uid = 0;
pd = kmalloc(sizeof(*pd), GFP_KERNEL);
if (!pd)
return ERR_PTR(-ENOMEM);
- err = mlx5_core_alloc_pd(to_mdev(ibdev)->mdev, &pd->pdn);
+ uid = context ? to_mucontext(context)->devx_uid : 0;
+ MLX5_SET(alloc_pd_in, in, opcode, MLX5_CMD_OP_ALLOC_PD);
+ MLX5_SET(alloc_pd_in, in, uid, uid);
+ err = mlx5_cmd_exec(to_mdev(ibdev)->mdev, in, sizeof(in),
+ out, sizeof(out));
if (err) {
kfree(pd);
return ERR_PTR(err);
}
+ pd->pdn = MLX5_GET(alloc_pd_out, out, pd);
+ pd->uid = uid;
if (context) {
resp.pdn = pd->pdn;
if (ib_copy_to_udata(udata, &resp, sizeof(resp))) {
- mlx5_core_dealloc_pd(to_mdev(ibdev)->mdev, pd->pdn);
+ mlx5_cmd_dealloc_pd(to_mdev(ibdev)->mdev, pd->pdn, uid);
kfree(pd);
return ERR_PTR(-EFAULT);
}
@@ -2346,7 +2289,7 @@ static int mlx5_ib_dealloc_pd(struct ib_pd *pd)
struct mlx5_ib_dev *mdev = to_mdev(pd->device);
struct mlx5_ib_pd *mpd = to_mpd(pd);
- mlx5_core_dealloc_pd(mdev->mdev, mpd->pdn);
+ mlx5_cmd_dealloc_pd(mdev->mdev, mpd->pdn, mpd->uid);
kfree(mpd);
return 0;
@@ -2452,20 +2395,50 @@ static int check_mpls_supp_fields(u32 field_support, const __be32 *set_mask)
offsetof(typeof(filter), field) -\
sizeof(filter.field))
-static int parse_flow_flow_action(const union ib_flow_spec *ib_spec,
- const struct ib_flow_attr *flow_attr,
- struct mlx5_flow_act *action)
+int parse_flow_flow_action(struct mlx5_ib_flow_action *maction,
+ bool is_egress,
+ struct mlx5_flow_act *action)
{
- struct mlx5_ib_flow_action *maction = to_mflow_act(ib_spec->action.act);
switch (maction->ib_action.type) {
case IB_FLOW_ACTION_ESP:
+ if (action->action & (MLX5_FLOW_CONTEXT_ACTION_ENCRYPT |
+ MLX5_FLOW_CONTEXT_ACTION_DECRYPT))
+ return -EINVAL;
/* Currently only AES_GCM keymat is supported by the driver */
action->esp_id = (uintptr_t)maction->esp_aes_gcm.ctx;
- action->action |= flow_attr->flags & IB_FLOW_ATTR_FLAGS_EGRESS ?
+ action->action |= is_egress ?
MLX5_FLOW_CONTEXT_ACTION_ENCRYPT :
MLX5_FLOW_CONTEXT_ACTION_DECRYPT;
return 0;
+ case IB_FLOW_ACTION_UNSPECIFIED:
+ if (maction->flow_action_raw.sub_type ==
+ MLX5_IB_FLOW_ACTION_MODIFY_HEADER) {
+ if (action->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
+ return -EINVAL;
+ action->action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
+ action->modify_id = maction->flow_action_raw.action_id;
+ return 0;
+ }
+ if (maction->flow_action_raw.sub_type ==
+ MLX5_IB_FLOW_ACTION_DECAP) {
+ if (action->action & MLX5_FLOW_CONTEXT_ACTION_DECAP)
+ return -EINVAL;
+ action->action |= MLX5_FLOW_CONTEXT_ACTION_DECAP;
+ return 0;
+ }
+ if (maction->flow_action_raw.sub_type ==
+ MLX5_IB_FLOW_ACTION_PACKET_REFORMAT) {
+ if (action->action &
+ MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT)
+ return -EINVAL;
+ action->action |=
+ MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
+ action->reformat_id =
+ maction->flow_action_raw.action_id;
+ return 0;
+ }
+ /* fall through */
default:
return -EOPNOTSUPP;
}
@@ -2793,7 +2766,7 @@ static int parse_flow_attr(struct mlx5_core_dev *mdev, u32 *match_c,
return -EINVAL;
action->flow_tag = ib_spec->flow_tag.tag_id;
- action->has_flow_tag = true;
+ action->flags |= FLOW_ACT_HAS_TAG;
break;
case IB_FLOW_SPEC_ACTION_DROP:
if (FIELDS_NOT_SUPPORTED(ib_spec->drop,
@@ -2802,7 +2775,8 @@ static int parse_flow_attr(struct mlx5_core_dev *mdev, u32 *match_c,
action->action |= MLX5_FLOW_CONTEXT_ACTION_DROP;
break;
case IB_FLOW_SPEC_ACTION_HANDLE:
- ret = parse_flow_flow_action(ib_spec, flow_attr, action);
+ ret = parse_flow_flow_action(to_mflow_act(ib_spec->action.act),
+ flow_attr->flags & IB_FLOW_ATTR_FLAGS_EGRESS, action);
if (ret)
return ret;
break;
@@ -2883,10 +2857,10 @@ is_valid_esp_aes_gcm(struct mlx5_core_dev *mdev,
* rules would be supported, always return VALID_SPEC_NA.
*/
if (!is_crypto)
- return egress ? VALID_SPEC_INVALID : VALID_SPEC_NA;
+ return VALID_SPEC_NA;
return is_crypto && is_ipsec &&
- (!egress || (!is_drop && !flow_act->has_flow_tag)) ?
+ (!egress || (!is_drop && !(flow_act->flags & FLOW_ACT_HAS_TAG))) ?
VALID_SPEC_VALID : VALID_SPEC_INVALID;
}
@@ -3026,14 +3000,15 @@ enum flow_table_type {
static struct mlx5_ib_flow_prio *_get_prio(struct mlx5_flow_namespace *ns,
struct mlx5_ib_flow_prio *prio,
int priority,
- int num_entries, int num_groups)
+ int num_entries, int num_groups,
+ u32 flags)
{
struct mlx5_flow_table *ft;
ft = mlx5_create_auto_grouped_flow_table(ns, priority,
num_entries,
num_groups,
- 0, 0);
+ 0, flags);
if (IS_ERR(ft))
return ERR_CAST(ft);
@@ -3053,26 +3028,43 @@ static struct mlx5_ib_flow_prio *get_flow_table(struct mlx5_ib_dev *dev,
int max_table_size;
int num_entries;
int num_groups;
+ u32 flags = 0;
int priority;
max_table_size = BIT(MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev,
log_max_ft_size));
if (flow_attr->type == IB_FLOW_ATTR_NORMAL) {
- if (ft_type == MLX5_IB_FT_TX)
- priority = 0;
- else if (flow_is_multicast_only(flow_attr) &&
- !dont_trap)
+ enum mlx5_flow_namespace_type fn_type;
+
+ if (flow_is_multicast_only(flow_attr) &&
+ !dont_trap)
priority = MLX5_IB_FLOW_MCAST_PRIO;
else
priority = ib_prio_to_core_prio(flow_attr->priority,
dont_trap);
- ns = mlx5_get_flow_namespace(dev->mdev,
- ft_type == MLX5_IB_FT_TX ?
- MLX5_FLOW_NAMESPACE_EGRESS :
- MLX5_FLOW_NAMESPACE_BYPASS);
+ if (ft_type == MLX5_IB_FT_RX) {
+ fn_type = MLX5_FLOW_NAMESPACE_BYPASS;
+ prio = &dev->flow_db->prios[priority];
+ if (!dev->rep &&
+ MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev, decap))
+ flags |= MLX5_FLOW_TABLE_TUNNEL_EN_DECAP;
+ if (!dev->rep &&
+ MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev,
+ reformat_l3_tunnel_to_l2))
+ flags |= MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT;
+ } else {
+ max_table_size =
+ BIT(MLX5_CAP_FLOWTABLE_NIC_TX(dev->mdev,
+ log_max_ft_size));
+ fn_type = MLX5_FLOW_NAMESPACE_EGRESS;
+ prio = &dev->flow_db->egress_prios[priority];
+ if (!dev->rep &&
+ MLX5_CAP_FLOWTABLE_NIC_TX(dev->mdev, reformat))
+ flags |= MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT;
+ }
+ ns = mlx5_get_flow_namespace(dev->mdev, fn_type);
num_entries = MLX5_FS_MAX_ENTRIES;
num_groups = MLX5_FS_MAX_TYPES;
- prio = &dev->flow_db->prios[priority];
} else if (flow_attr->type == IB_FLOW_ATTR_ALL_DEFAULT ||
flow_attr->type == IB_FLOW_ATTR_MC_DEFAULT) {
ns = mlx5_get_flow_namespace(dev->mdev,
@@ -3104,7 +3096,8 @@ static struct mlx5_ib_flow_prio *get_flow_table(struct mlx5_ib_dev *dev,
ft = prio->flow_table;
if (!ft)
- return _get_prio(ns, prio, priority, num_entries, num_groups);
+ return _get_prio(ns, prio, priority, num_entries, num_groups,
+ flags);
return prio;
}
@@ -3271,6 +3264,9 @@ static struct mlx5_ib_flow_handler *_create_flow_rule(struct mlx5_ib_dev *dev,
if (!is_valid_attr(dev->mdev, flow_attr))
return ERR_PTR(-EINVAL);
+ if (dev->rep && is_egress)
+ return ERR_PTR(-EINVAL);
+
spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
handler = kzalloc(sizeof(*handler), GFP_KERNEL);
if (!handler || !spec) {
@@ -3320,15 +3316,18 @@ static struct mlx5_ib_flow_handler *_create_flow_rule(struct mlx5_ib_dev *dev,
}
if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_COUNT) {
+ struct mlx5_ib_mcounters *mcounters;
+
err = flow_counters_set_data(flow_act.counters, ucmd);
if (err)
goto free;
+ mcounters = to_mcounters(flow_act.counters);
handler->ibcounters = flow_act.counters;
dest_arr[dest_num].type =
MLX5_FLOW_DESTINATION_TYPE_COUNTER;
- dest_arr[dest_num].counter =
- to_mcounters(flow_act.counters)->hw_cntrs_hndl;
+ dest_arr[dest_num].counter_id =
+ mlx5_fc_id(mcounters->hw_cntrs_hndl);
dest_num++;
}
@@ -3346,7 +3345,7 @@ static struct mlx5_ib_flow_handler *_create_flow_rule(struct mlx5_ib_dev *dev,
MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO;
}
- if (flow_act.has_flow_tag &&
+ if ((flow_act.flags & FLOW_ACT_HAS_TAG) &&
(flow_attr->type == IB_FLOW_ATTR_ALL_DEFAULT ||
flow_attr->type == IB_FLOW_ATTR_MC_DEFAULT)) {
mlx5_ib_warn(dev, "Flow tag %u and attribute type %x isn't allowed in leftovers\n",
@@ -3658,34 +3657,54 @@ free_ucmd:
return ERR_PTR(err);
}
-static struct mlx5_ib_flow_prio *_get_flow_table(struct mlx5_ib_dev *dev,
- int priority, bool mcast)
+static struct mlx5_ib_flow_prio *
+_get_flow_table(struct mlx5_ib_dev *dev,
+ struct mlx5_ib_flow_matcher *fs_matcher,
+ bool mcast)
{
- int max_table_size;
struct mlx5_flow_namespace *ns = NULL;
struct mlx5_ib_flow_prio *prio;
+ int max_table_size;
+ u32 flags = 0;
+ int priority;
+
+ if (fs_matcher->ns_type == MLX5_FLOW_NAMESPACE_BYPASS) {
+ max_table_size = BIT(MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev,
+ log_max_ft_size));
+ if (MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev, decap))
+ flags |= MLX5_FLOW_TABLE_TUNNEL_EN_DECAP;
+ if (MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev,
+ reformat_l3_tunnel_to_l2))
+ flags |= MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT;
+ } else { /* Can only be MLX5_FLOW_NAMESPACE_EGRESS */
+ max_table_size = BIT(MLX5_CAP_FLOWTABLE_NIC_TX(dev->mdev,
+ log_max_ft_size));
+ if (MLX5_CAP_FLOWTABLE_NIC_TX(dev->mdev, reformat))
+ flags |= MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT;
+ }
- max_table_size = BIT(MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev,
- log_max_ft_size));
if (max_table_size < MLX5_FS_MAX_ENTRIES)
return ERR_PTR(-ENOMEM);
if (mcast)
priority = MLX5_IB_FLOW_MCAST_PRIO;
else
- priority = ib_prio_to_core_prio(priority, false);
+ priority = ib_prio_to_core_prio(fs_matcher->priority, false);
- ns = mlx5_get_flow_namespace(dev->mdev, MLX5_FLOW_NAMESPACE_BYPASS);
+ ns = mlx5_get_flow_namespace(dev->mdev, fs_matcher->ns_type);
if (!ns)
return ERR_PTR(-ENOTSUPP);
- prio = &dev->flow_db->prios[priority];
+ if (fs_matcher->ns_type == MLX5_FLOW_NAMESPACE_BYPASS)
+ prio = &dev->flow_db->prios[priority];
+ else
+ prio = &dev->flow_db->egress_prios[priority];
if (prio->flow_table)
return prio;
return _get_prio(ns, prio, priority, MLX5_FS_MAX_ENTRIES,
- MLX5_FS_MAX_TYPES);
+ MLX5_FS_MAX_TYPES, flags);
}
static struct mlx5_ib_flow_handler *
@@ -3693,10 +3712,10 @@ _create_raw_flow_rule(struct mlx5_ib_dev *dev,
struct mlx5_ib_flow_prio *ft_prio,
struct mlx5_flow_destination *dst,
struct mlx5_ib_flow_matcher *fs_matcher,
+ struct mlx5_flow_act *flow_act,
void *cmd_in, int inlen)
{
struct mlx5_ib_flow_handler *handler;
- struct mlx5_flow_act flow_act = {.flow_tag = MLX5_FS_DEFAULT_FLOW_TAG};
struct mlx5_flow_spec *spec;
struct mlx5_flow_table *ft = ft_prio->flow_table;
int err = 0;
@@ -3715,9 +3734,8 @@ _create_raw_flow_rule(struct mlx5_ib_dev *dev,
fs_matcher->mask_len);
spec->match_criteria_enable = fs_matcher->match_criteria_enable;
- flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
handler->rule = mlx5_add_flow_rules(ft, spec,
- &flow_act, dst, 1);
+ flow_act, dst, 1);
if (IS_ERR(handler->rule)) {
err = PTR_ERR(handler->rule);
@@ -3779,12 +3797,12 @@ static bool raw_fs_is_multicast(struct mlx5_ib_flow_matcher *fs_matcher,
struct mlx5_ib_flow_handler *
mlx5_ib_raw_fs_rule_add(struct mlx5_ib_dev *dev,
struct mlx5_ib_flow_matcher *fs_matcher,
+ struct mlx5_flow_act *flow_act,
void *cmd_in, int inlen, int dest_id,
int dest_type)
{
struct mlx5_flow_destination *dst;
struct mlx5_ib_flow_prio *ft_prio;
- int priority = fs_matcher->priority;
struct mlx5_ib_flow_handler *handler;
bool mcast;
int err;
@@ -3802,7 +3820,7 @@ mlx5_ib_raw_fs_rule_add(struct mlx5_ib_dev *dev,
mcast = raw_fs_is_multicast(fs_matcher, cmd_in);
mutex_lock(&dev->flow_db->lock);
- ft_prio = _get_flow_table(dev, priority, mcast);
+ ft_prio = _get_flow_table(dev, fs_matcher, mcast);
if (IS_ERR(ft_prio)) {
err = PTR_ERR(ft_prio);
goto unlock;
@@ -3811,13 +3829,18 @@ mlx5_ib_raw_fs_rule_add(struct mlx5_ib_dev *dev,
if (dest_type == MLX5_FLOW_DESTINATION_TYPE_TIR) {
dst->type = dest_type;
dst->tir_num = dest_id;
- } else {
+ flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
+ } else if (dest_type == MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE) {
dst->type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE_NUM;
dst->ft_num = dest_id;
+ flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
+ } else {
+ dst->type = MLX5_FLOW_DESTINATION_TYPE_PORT;
+ flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_ALLOW;
}
- handler = _create_raw_flow_rule(dev, ft_prio, dst, fs_matcher, cmd_in,
- inlen);
+ handler = _create_raw_flow_rule(dev, ft_prio, dst, fs_matcher, flow_act,
+ cmd_in, inlen);
if (IS_ERR(handler)) {
err = PTR_ERR(handler);
@@ -3995,6 +4018,9 @@ static int mlx5_ib_destroy_flow_action(struct ib_flow_action *action)
*/
mlx5_accel_esp_destroy_xfrm(maction->esp_aes_gcm.ctx);
break;
+ case IB_FLOW_ACTION_UNSPECIFIED:
+ mlx5_ib_destroy_flow_action_raw(maction);
+ break;
default:
WARN_ON(true);
break;
@@ -4009,13 +4035,17 @@ static int mlx5_ib_mcg_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
struct mlx5_ib_dev *dev = to_mdev(ibqp->device);
struct mlx5_ib_qp *mqp = to_mqp(ibqp);
int err;
+ u16 uid;
+
+ uid = ibqp->pd ?
+ to_mpd(ibqp->pd)->uid : 0;
if (mqp->flags & MLX5_IB_QP_UNDERLAY) {
mlx5_ib_dbg(dev, "Attaching a multi cast group to underlay QP is not supported\n");
return -EOPNOTSUPP;
}
- err = mlx5_core_attach_mcg(dev->mdev, gid, ibqp->qp_num);
+ err = mlx5_cmd_attach_mcg(dev->mdev, gid, ibqp->qp_num, uid);
if (err)
mlx5_ib_warn(dev, "failed attaching QPN 0x%x, MGID %pI6\n",
ibqp->qp_num, gid->raw);
@@ -4027,8 +4057,11 @@ static int mlx5_ib_mcg_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
{
struct mlx5_ib_dev *dev = to_mdev(ibqp->device);
int err;
+ u16 uid;
- err = mlx5_core_detach_mcg(dev->mdev, gid, ibqp->qp_num);
+ uid = ibqp->pd ?
+ to_mpd(ibqp->pd)->uid : 0;
+ err = mlx5_cmd_detach_mcg(dev->mdev, gid, ibqp->qp_num, uid);
if (err)
mlx5_ib_warn(dev, "failed detaching QPN 0x%x, MGID %pI6\n",
ibqp->qp_num, gid->raw);
@@ -4049,16 +4082,17 @@ static int init_node_data(struct mlx5_ib_dev *dev)
return mlx5_query_node_guid(dev, &dev->ib_dev.node_guid);
}
-static ssize_t show_fw_pages(struct device *device, struct device_attribute *attr,
- char *buf)
+static ssize_t fw_pages_show(struct device *device,
+ struct device_attribute *attr, char *buf)
{
struct mlx5_ib_dev *dev =
container_of(device, struct mlx5_ib_dev, ib_dev.dev);
return sprintf(buf, "%d\n", dev->mdev->priv.fw_pages);
}
+static DEVICE_ATTR_RO(fw_pages);
-static ssize_t show_reg_pages(struct device *device,
+static ssize_t reg_pages_show(struct device *device,
struct device_attribute *attr, char *buf)
{
struct mlx5_ib_dev *dev =
@@ -4066,44 +4100,47 @@ static ssize_t show_reg_pages(struct device *device,
return sprintf(buf, "%d\n", atomic_read(&dev->mdev->priv.reg_pages));
}
+static DEVICE_ATTR_RO(reg_pages);
-static ssize_t show_hca(struct device *device, struct device_attribute *attr,
- char *buf)
+static ssize_t hca_type_show(struct device *device,
+ struct device_attribute *attr, char *buf)
{
struct mlx5_ib_dev *dev =
container_of(device, struct mlx5_ib_dev, ib_dev.dev);
return sprintf(buf, "MT%d\n", dev->mdev->pdev->device);
}
+static DEVICE_ATTR_RO(hca_type);
-static ssize_t show_rev(struct device *device, struct device_attribute *attr,
- char *buf)
+static ssize_t hw_rev_show(struct device *device,
+ struct device_attribute *attr, char *buf)
{
struct mlx5_ib_dev *dev =
container_of(device, struct mlx5_ib_dev, ib_dev.dev);
return sprintf(buf, "%x\n", dev->mdev->rev_id);
}
+static DEVICE_ATTR_RO(hw_rev);
-static ssize_t show_board(struct device *device, struct device_attribute *attr,
- char *buf)
+static ssize_t board_id_show(struct device *device,
+ struct device_attribute *attr, char *buf)
{
struct mlx5_ib_dev *dev =
container_of(device, struct mlx5_ib_dev, ib_dev.dev);
return sprintf(buf, "%.*s\n", MLX5_BOARD_ID_LEN,
dev->mdev->board_id);
}
+static DEVICE_ATTR_RO(board_id);
-static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL);
-static DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL);
-static DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL);
-static DEVICE_ATTR(fw_pages, S_IRUGO, show_fw_pages, NULL);
-static DEVICE_ATTR(reg_pages, S_IRUGO, show_reg_pages, NULL);
+static struct attribute *mlx5_class_attributes[] = {
+ &dev_attr_hw_rev.attr,
+ &dev_attr_hca_type.attr,
+ &dev_attr_board_id.attr,
+ &dev_attr_fw_pages.attr,
+ &dev_attr_reg_pages.attr,
+ NULL,
+};
-static struct device_attribute *mlx5_class_attributes[] = {
- &dev_attr_hw_rev,
- &dev_attr_hca_type,
- &dev_attr_board_id,
- &dev_attr_fw_pages,
- &dev_attr_reg_pages,
+static const struct attribute_group mlx5_attr_group = {
+ .attrs = mlx5_class_attributes,
};
static void pkey_change_handler(struct work_struct *work)
@@ -5163,22 +5200,14 @@ done:
return num_counters;
}
-static struct net_device*
-mlx5_ib_alloc_rdma_netdev(struct ib_device *hca,
- u8 port_num,
- enum rdma_netdev_t type,
- const char *name,
- unsigned char name_assign_type,
- void (*setup)(struct net_device *))
+static int mlx5_ib_rn_get_params(struct ib_device *device, u8 port_num,
+ enum rdma_netdev_t type,
+ struct rdma_netdev_alloc_params *params)
{
- struct net_device *netdev;
-
if (type != RDMA_NETDEV_IPOIB)
- return ERR_PTR(-EOPNOTSUPP);
+ return -EOPNOTSUPP;
- netdev = mlx5_rdma_netdev_alloc(to_mdev(hca)->mdev, hca,
- name, setup);
- return netdev;
+ return mlx5_rdma_rn_get_params(to_mdev(device)->mdev, device, params);
}
static void delay_drop_debugfs_cleanup(struct mlx5_ib_dev *dev)
@@ -5636,7 +5665,6 @@ void mlx5_ib_stage_init_cleanup(struct mlx5_ib_dev *dev)
int mlx5_ib_stage_init_init(struct mlx5_ib_dev *dev)
{
struct mlx5_core_dev *mdev = dev->mdev;
- const char *name;
int err;
int i;
@@ -5669,12 +5697,6 @@ int mlx5_ib_stage_init_init(struct mlx5_ib_dev *dev)
if (mlx5_use_mad_ifc(dev))
get_ext_port_caps(dev);
- if (!mlx5_lag_is_active(mdev))
- name = "mlx5_%d";
- else
- name = "mlx5_bond_%d";
-
- strlcpy(dev->ib_dev.name, name, IB_DEVICE_NAME_MAX);
dev->ib_dev.owner = THIS_MODULE;
dev->ib_dev.node_type = RDMA_NODE_IB_CA;
dev->ib_dev.local_dma_lkey = 0 /* not supported for now */;
@@ -5824,8 +5846,9 @@ int mlx5_ib_stage_caps_init(struct mlx5_ib_dev *dev)
dev->ib_dev.check_mr_status = mlx5_ib_check_mr_status;
dev->ib_dev.get_dev_fw_str = get_dev_fw_str;
dev->ib_dev.get_vector_affinity = mlx5_ib_get_vector_affinity;
- if (MLX5_CAP_GEN(mdev, ipoib_enhanced_offloads))
- dev->ib_dev.alloc_rdma_netdev = mlx5_ib_alloc_rdma_netdev;
+ if (MLX5_CAP_GEN(mdev, ipoib_enhanced_offloads) &&
+ IS_ENABLED(CONFIG_MLX5_CORE_IPOIB))
+ dev->ib_dev.rdma_netdev_get_params = mlx5_ib_rn_get_params;
if (mlx5_core_is_pf(mdev)) {
dev->ib_dev.get_vf_config = mlx5_ib_get_vf_config;
@@ -5880,7 +5903,7 @@ int mlx5_ib_stage_caps_init(struct mlx5_ib_dev *dev)
if ((MLX5_CAP_GEN(dev->mdev, port_type) == MLX5_CAP_PORT_TYPE_ETH) &&
(MLX5_CAP_GEN(dev->mdev, disable_local_lb_uc) ||
MLX5_CAP_GEN(dev->mdev, disable_local_lb_mc)))
- mutex_init(&dev->lb_mutex);
+ mutex_init(&dev->lb.mutex);
return 0;
}
@@ -6087,7 +6110,14 @@ static int mlx5_ib_stage_populate_specs(struct mlx5_ib_dev *dev)
int mlx5_ib_stage_ib_reg_init(struct mlx5_ib_dev *dev)
{
- return ib_register_device(&dev->ib_dev, NULL);
+ const char *name;
+
+ rdma_set_device_sysfs_group(&dev->ib_dev, &mlx5_attr_group);
+ if (!mlx5_lag_is_active(dev->mdev))
+ name = "mlx5_%d";
+ else
+ name = "mlx5_bond_%d";
+ return ib_register_device(&dev->ib_dev, name, NULL);
}
void mlx5_ib_stage_pre_ib_reg_umr_cleanup(struct mlx5_ib_dev *dev)
@@ -6117,21 +6147,6 @@ static void mlx5_ib_stage_delay_drop_cleanup(struct mlx5_ib_dev *dev)
cancel_delay_drop(dev);
}
-int mlx5_ib_stage_class_attr_init(struct mlx5_ib_dev *dev)
-{
- int err;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(mlx5_class_attributes); i++) {
- err = device_create_file(&dev->ib_dev.dev,
- mlx5_class_attributes[i]);
- if (err)
- return err;
- }
-
- return 0;
-}
-
static int mlx5_ib_stage_rep_reg_init(struct mlx5_ib_dev *dev)
{
mlx5_ib_register_vport_reps(dev);
@@ -6155,6 +6170,8 @@ void __mlx5_ib_remove(struct mlx5_ib_dev *dev,
profile->stage[stage].cleanup(dev);
}
+ if (dev->devx_whitelist_uid)
+ mlx5_ib_devx_destroy(dev, dev->devx_whitelist_uid);
ib_dealloc_device((struct ib_device *)dev);
}
@@ -6163,8 +6180,7 @@ void *__mlx5_ib_add(struct mlx5_ib_dev *dev,
{
int err;
int i;
-
- printk_once(KERN_INFO "%s", mlx5_version);
+ int uid;
for (i = 0; i < MLX5_IB_STAGE_MAX; i++) {
if (profile->stage[i].init) {
@@ -6174,6 +6190,10 @@ void *__mlx5_ib_add(struct mlx5_ib_dev *dev,
}
}
+ uid = mlx5_ib_devx_create(dev);
+ if (uid > 0)
+ dev->devx_whitelist_uid = uid;
+
dev->profile = profile;
dev->ib_active = true;
@@ -6234,9 +6254,6 @@ static const struct mlx5_ib_profile pf_profile = {
STAGE_CREATE(MLX5_IB_STAGE_DELAY_DROP,
mlx5_ib_stage_delay_drop_init,
mlx5_ib_stage_delay_drop_cleanup),
- STAGE_CREATE(MLX5_IB_STAGE_CLASS_ATTR,
- mlx5_ib_stage_class_attr_init,
- NULL),
};
static const struct mlx5_ib_profile nic_rep_profile = {
@@ -6279,9 +6296,6 @@ static const struct mlx5_ib_profile nic_rep_profile = {
STAGE_CREATE(MLX5_IB_STAGE_POST_IB_REG_UMR,
mlx5_ib_stage_post_ib_reg_umr_init,
NULL),
- STAGE_CREATE(MLX5_IB_STAGE_CLASS_ATTR,
- mlx5_ib_stage_class_attr_init,
- NULL),
STAGE_CREATE(MLX5_IB_STAGE_REP_REG,
mlx5_ib_stage_rep_reg_init,
mlx5_ib_stage_rep_reg_cleanup),
diff --git a/drivers/infiniband/hw/mlx5/mem.c b/drivers/infiniband/hw/mlx5/mem.c
index f3dbd75a0a96..549234988bb4 100644
--- a/drivers/infiniband/hw/mlx5/mem.c
+++ b/drivers/infiniband/hw/mlx5/mem.c
@@ -57,7 +57,7 @@ void mlx5_ib_cont_pages(struct ib_umem *umem, u64 addr,
int entry;
unsigned long page_shift = umem->page_shift;
- if (umem->odp_data) {
+ if (umem->is_odp) {
*ncont = ib_umem_page_count(umem);
*count = *ncont << (page_shift - PAGE_SHIFT);
*shift = page_shift;
@@ -152,14 +152,13 @@ void __mlx5_ib_populate_pas(struct mlx5_ib_dev *dev, struct ib_umem *umem,
struct scatterlist *sg;
int entry;
#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING
- const bool odp = umem->odp_data != NULL;
-
- if (odp) {
+ if (umem->is_odp) {
WARN_ON(shift != 0);
WARN_ON(access_flags != (MLX5_IB_MTT_READ | MLX5_IB_MTT_WRITE));
for (i = 0; i < num_pages; ++i) {
- dma_addr_t pa = umem->odp_data->dma_list[offset + i];
+ dma_addr_t pa =
+ to_ib_umem_odp(umem)->dma_list[offset + i];
pas[i] = cpu_to_be64(umem_dma_to_mtt(pa));
}
diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h
index 320d4dfe8c2f..b651a7a6fde9 100644
--- a/drivers/infiniband/hw/mlx5/mlx5_ib.h
+++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h
@@ -39,8 +39,10 @@
#include <rdma/ib_smi.h>
#include <linux/mlx5/driver.h>
#include <linux/mlx5/cq.h>
+#include <linux/mlx5/fs.h>
#include <linux/mlx5/qp.h>
#include <linux/mlx5/srq.h>
+#include <linux/mlx5/fs.h>
#include <linux/types.h>
#include <linux/mlx5/transobj.h>
#include <rdma/ib_user_verbs.h>
@@ -48,17 +50,17 @@
#include <rdma/uverbs_ioctl.h>
#include <rdma/mlx5_user_ioctl_cmds.h>
-#define mlx5_ib_dbg(dev, format, arg...) \
-pr_debug("%s:%s:%d:(pid %d): " format, (dev)->ib_dev.name, __func__, \
- __LINE__, current->pid, ##arg)
+#define mlx5_ib_dbg(_dev, format, arg...) \
+ dev_dbg(&(_dev)->ib_dev.dev, "%s:%d:(pid %d): " format, __func__, \
+ __LINE__, current->pid, ##arg)
-#define mlx5_ib_err(dev, format, arg...) \
-pr_err("%s:%s:%d:(pid %d): " format, (dev)->ib_dev.name, __func__, \
- __LINE__, current->pid, ##arg)
+#define mlx5_ib_err(_dev, format, arg...) \
+ dev_err(&(_dev)->ib_dev.dev, "%s:%d:(pid %d): " format, __func__, \
+ __LINE__, current->pid, ##arg)
-#define mlx5_ib_warn(dev, format, arg...) \
-pr_warn("%s:%s:%d:(pid %d): " format, (dev)->ib_dev.name, __func__, \
- __LINE__, current->pid, ##arg)
+#define mlx5_ib_warn(_dev, format, arg...) \
+ dev_warn(&(_dev)->ib_dev.dev, "%s:%d:(pid %d): " format, __func__, \
+ __LINE__, current->pid, ##arg)
#define field_avail(type, fld, sz) (offsetof(type, fld) + \
sizeof(((type *)0)->fld) <= (sz))
@@ -114,13 +116,6 @@ enum {
MLX5_MEMIC_BASE_SIZE = 1 << MLX5_MEMIC_BASE_ALIGN,
};
-struct mlx5_ib_vma_private_data {
- struct list_head list;
- struct vm_area_struct *vma;
- /* protect vma_private_list add/del */
- struct mutex *vma_private_list_mutex;
-};
-
struct mlx5_ib_ucontext {
struct ib_ucontext ibucontext;
struct list_head db_page_list;
@@ -132,13 +127,12 @@ struct mlx5_ib_ucontext {
u8 cqe_version;
/* Transport Domain number */
u32 tdn;
- struct list_head vma_private_list;
- /* protect vma_private_list add/del */
- struct mutex vma_private_list_mutex;
u64 lib_caps;
DECLARE_BITMAP(dm_pages, MLX5_MAX_MEMIC_PAGES);
u16 devx_uid;
+ /* For RoCE LAG TX affinity */
+ atomic_t tx_port_affinity;
};
static inline struct mlx5_ib_ucontext *to_mucontext(struct ib_ucontext *ibucontext)
@@ -149,6 +143,13 @@ static inline struct mlx5_ib_ucontext *to_mucontext(struct ib_ucontext *ibuconte
struct mlx5_ib_pd {
struct ib_pd ibpd;
u32 pdn;
+ u16 uid;
+};
+
+enum {
+ MLX5_IB_FLOW_ACTION_MODIFY_HEADER,
+ MLX5_IB_FLOW_ACTION_PACKET_REFORMAT,
+ MLX5_IB_FLOW_ACTION_DECAP,
};
#define MLX5_IB_FLOW_MCAST_PRIO (MLX5_BY_PASS_NUM_PRIOS - 1)
@@ -180,6 +181,7 @@ struct mlx5_ib_flow_matcher {
struct mlx5_ib_match_params matcher_mask;
int mask_len;
enum mlx5_ib_flow_type flow_type;
+ enum mlx5_flow_namespace_type ns_type;
u16 priority;
struct mlx5_core_dev *mdev;
atomic_t usecnt;
@@ -188,6 +190,7 @@ struct mlx5_ib_flow_matcher {
struct mlx5_ib_flow_db {
struct mlx5_ib_flow_prio prios[MLX5_IB_NUM_FLOW_FT];
+ struct mlx5_ib_flow_prio egress_prios[MLX5_IB_NUM_FLOW_FT];
struct mlx5_ib_flow_prio sniffer[MLX5_IB_NUM_SNIFFER_FTS];
struct mlx5_ib_flow_prio egress[MLX5_IB_NUM_EGRESS_FTS];
struct mlx5_flow_table *lag_demux_ft;
@@ -322,6 +325,7 @@ enum {
struct mlx5_ib_rwq_ind_table {
struct ib_rwq_ind_table ib_rwq_ind_tbl;
u32 rqtn;
+ u16 uid;
};
struct mlx5_ib_ubuffer {
@@ -428,13 +432,14 @@ struct mlx5_ib_qp {
struct list_head cq_send_list;
struct mlx5_rate_limit rl;
u32 underlay_qpn;
- bool tunnel_offload_en;
+ u32 flags_en;
/* storage for qp sub type when core qp type is IB_QPT_DRIVER */
enum ib_qp_type qp_sub_type;
};
struct mlx5_ib_cq_buf {
struct mlx5_frag_buf_ctrl fbc;
+ struct mlx5_frag_buf frag_buf;
struct ib_umem *umem;
int cqe_size;
int nent;
@@ -535,6 +540,7 @@ struct mlx5_ib_srq {
struct mlx5_ib_xrcd {
struct ib_xrcd ibxrcd;
u32 xrcdn;
+ u16 uid;
};
enum mlx5_ib_mtt_access_flags {
@@ -699,7 +705,7 @@ struct mlx5_roce {
rwlock_t netdev_lock;
struct net_device *netdev;
struct notifier_block nb;
- atomic_t next_port;
+ atomic_t tx_port_affinity;
enum ib_port_state last_port_state;
struct mlx5_ib_dev *dev;
u8 native_port_num;
@@ -814,6 +820,11 @@ struct mlx5_ib_flow_action {
u64 ib_flags;
struct mlx5_accel_esp_xfrm *ctx;
} esp_aes_gcm;
+ struct {
+ struct mlx5_ib_dev *dev;
+ u32 sub_type;
+ u32 action_id;
+ } flow_action_raw;
};
};
@@ -858,9 +869,20 @@ to_mcounters(struct ib_counters *ibcntrs)
return container_of(ibcntrs, struct mlx5_ib_mcounters, ibcntrs);
}
+int parse_flow_flow_action(struct mlx5_ib_flow_action *maction,
+ bool is_egress,
+ struct mlx5_flow_act *action);
+struct mlx5_ib_lb_state {
+ /* protect the user_td */
+ struct mutex mutex;
+ u32 user_td;
+ int qps;
+ bool enabled;
+};
+
struct mlx5_ib_dev {
struct ib_device ib_dev;
- const struct uverbs_object_tree_def *driver_trees[6];
+ const struct uverbs_object_tree_def *driver_trees[7];
struct mlx5_core_dev *mdev;
struct mlx5_roce roce[MLX5_MAX_PORTS];
int num_ports;
@@ -899,13 +921,12 @@ struct mlx5_ib_dev {
const struct mlx5_ib_profile *profile;
struct mlx5_eswitch_rep *rep;
- /* protect the user_td */
- struct mutex lb_mutex;
- u32 user_td;
+ struct mlx5_ib_lb_state lb;
u8 umr_fence;
struct list_head ib_dev_list;
u64 sys_image_guid;
struct mlx5_memic memic;
+ u16 devx_whitelist_uid;
};
static inline struct mlx5_ib_cq *to_mibcq(struct mlx5_core_cq *mcq)
@@ -1016,6 +1037,8 @@ int mlx5_ib_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr);
int mlx5_ib_destroy_srq(struct ib_srq *srq);
int mlx5_ib_post_srq_recv(struct ib_srq *ibsrq, const struct ib_recv_wr *wr,
const struct ib_recv_wr **bad_wr);
+int mlx5_ib_enable_lb(struct mlx5_ib_dev *dev, bool td, bool qp);
+void mlx5_ib_disable_lb(struct mlx5_ib_dev *dev, bool td, bool qp);
struct ib_qp *mlx5_ib_create_qp(struct ib_pd *pd,
struct ib_qp_init_attr *init_attr,
struct ib_udata *udata);
@@ -1105,7 +1128,7 @@ void __mlx5_ib_populate_pas(struct mlx5_ib_dev *dev, struct ib_umem *umem,
void mlx5_ib_populate_pas(struct mlx5_ib_dev *dev, struct ib_umem *umem,
int page_shift, __be64 *pas, int access_flags);
void mlx5_ib_copy_pas(u64 *old, u64 *new, int step, int num);
-int mlx5_ib_get_cqe_size(struct mlx5_ib_dev *dev, struct ib_cq *ibcq);
+int mlx5_ib_get_cqe_size(struct ib_cq *ibcq);
int mlx5_mr_cache_init(struct mlx5_ib_dev *dev);
int mlx5_mr_cache_cleanup(struct mlx5_ib_dev *dev);
@@ -1140,7 +1163,7 @@ void mlx5_ib_pfault(struct mlx5_core_dev *mdev, void *context,
int mlx5_ib_odp_init_one(struct mlx5_ib_dev *ibdev);
int __init mlx5_ib_odp_init(void);
void mlx5_ib_odp_cleanup(void);
-void mlx5_ib_invalidate_range(struct ib_umem *umem, unsigned long start,
+void mlx5_ib_invalidate_range(struct ib_umem_odp *umem_odp, unsigned long start,
unsigned long end);
void mlx5_odp_init_mr_cache_entry(struct mlx5_cache_ent *ent);
void mlx5_odp_populate_klm(struct mlx5_klm *pklm, size_t offset,
@@ -1179,7 +1202,6 @@ void mlx5_ib_stage_pre_ib_reg_umr_cleanup(struct mlx5_ib_dev *dev);
int mlx5_ib_stage_ib_reg_init(struct mlx5_ib_dev *dev);
void mlx5_ib_stage_ib_reg_cleanup(struct mlx5_ib_dev *dev);
int mlx5_ib_stage_post_ib_reg_umr_init(struct mlx5_ib_dev *dev);
-int mlx5_ib_stage_class_attr_init(struct mlx5_ib_dev *dev);
void __mlx5_ib_remove(struct mlx5_ib_dev *dev,
const struct mlx5_ib_profile *profile,
int stage);
@@ -1228,22 +1250,20 @@ void mlx5_ib_put_native_port_mdev(struct mlx5_ib_dev *dev,
u8 port_num);
#if IS_ENABLED(CONFIG_INFINIBAND_USER_ACCESS)
-int mlx5_ib_devx_create(struct mlx5_ib_dev *dev,
- struct mlx5_ib_ucontext *context);
-void mlx5_ib_devx_destroy(struct mlx5_ib_dev *dev,
- struct mlx5_ib_ucontext *context);
+int mlx5_ib_devx_create(struct mlx5_ib_dev *dev);
+void mlx5_ib_devx_destroy(struct mlx5_ib_dev *dev, u16 uid);
const struct uverbs_object_tree_def *mlx5_ib_get_devx_tree(void);
struct mlx5_ib_flow_handler *mlx5_ib_raw_fs_rule_add(
struct mlx5_ib_dev *dev, struct mlx5_ib_flow_matcher *fs_matcher,
- void *cmd_in, int inlen, int dest_id, int dest_type);
+ struct mlx5_flow_act *flow_act, void *cmd_in, int inlen,
+ int dest_id, int dest_type);
bool mlx5_ib_devx_is_flow_dest(void *obj, int *dest_id, int *dest_type);
int mlx5_ib_get_flow_trees(const struct uverbs_object_tree_def **root);
+void mlx5_ib_destroy_flow_action_raw(struct mlx5_ib_flow_action *maction);
#else
static inline int
-mlx5_ib_devx_create(struct mlx5_ib_dev *dev,
- struct mlx5_ib_ucontext *context) { return -EOPNOTSUPP; };
-static inline void mlx5_ib_devx_destroy(struct mlx5_ib_dev *dev,
- struct mlx5_ib_ucontext *context) {}
+mlx5_ib_devx_create(struct mlx5_ib_dev *dev) { return -EOPNOTSUPP; };
+static inline void mlx5_ib_devx_destroy(struct mlx5_ib_dev *dev, u16 uid) {}
static inline const struct uverbs_object_tree_def *
mlx5_ib_get_devx_tree(void) { return NULL; }
static inline bool mlx5_ib_devx_is_flow_dest(void *obj, int *dest_id,
@@ -1256,6 +1276,11 @@ mlx5_ib_get_flow_trees(const struct uverbs_object_tree_def **root)
{
return 0;
}
+static inline void
+mlx5_ib_destroy_flow_action_raw(struct mlx5_ib_flow_action *maction)
+{
+ return;
+};
#endif
static inline void init_query_mad(struct ib_smp *mad)
{
diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c
index 9fb1d9cb9401..9b195d65a13e 100644
--- a/drivers/infiniband/hw/mlx5/mr.c
+++ b/drivers/infiniband/hw/mlx5/mr.c
@@ -98,7 +98,7 @@ static bool use_umr_mtt_update(struct mlx5_ib_mr *mr, u64 start, u64 length)
#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING
static void update_odp_mr(struct mlx5_ib_mr *mr)
{
- if (mr->umem->odp_data) {
+ if (mr->umem->is_odp) {
/*
* This barrier prevents the compiler from moving the
* setting of umem->odp_data->private to point to our
@@ -107,7 +107,7 @@ static void update_odp_mr(struct mlx5_ib_mr *mr)
* handle invalidations.
*/
smp_wmb();
- mr->umem->odp_data->private = mr;
+ to_ib_umem_odp(mr->umem)->private = mr;
/*
* Make sure we will see the new
* umem->odp_data->private value in the invalidation
@@ -544,6 +544,9 @@ void mlx5_mr_cache_free(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr)
int shrink = 0;
int c;
+ if (!mr->allocated_from_cache)
+ return;
+
c = order2idx(dev, mr->order);
if (c < 0 || c >= MAX_MR_CACHE_ENTRIES) {
mlx5_ib_warn(dev, "order %d, cache index %d\n", mr->order, c);
@@ -688,7 +691,6 @@ int mlx5_mr_cache_init(struct mlx5_ib_dev *dev)
init_completion(&ent->compl);
INIT_WORK(&ent->work, cache_work_func);
INIT_DELAYED_WORK(&ent->dwork, delayed_cache_work_func);
- queue_work(cache->wq, &ent->work);
if (i > MR_CACHE_LAST_STD_ENTRY) {
mlx5_odp_init_mr_cache_entry(ent);
@@ -708,6 +710,7 @@ int mlx5_mr_cache_init(struct mlx5_ib_dev *dev)
ent->limit = dev->mdev->profile->mr_cache[i].limit;
else
ent->limit = 0;
+ queue_work(cache->wq, &ent->work);
}
err = mlx5_mr_cache_debugfs_init(dev);
@@ -1624,14 +1627,16 @@ static void dereg_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr)
struct ib_umem *umem = mr->umem;
#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING
- if (umem && umem->odp_data) {
+ if (umem && umem->is_odp) {
+ struct ib_umem_odp *umem_odp = to_ib_umem_odp(umem);
+
/* Prevent new page faults from succeeding */
mr->live = 0;
/* Wait for all running page-fault handlers to finish. */
synchronize_srcu(&dev->mr_srcu);
/* Destroy all page mappings */
- if (umem->odp_data->page_list)
- mlx5_ib_invalidate_range(umem, ib_umem_start(umem),
+ if (umem_odp->page_list)
+ mlx5_ib_invalidate_range(umem_odp, ib_umem_start(umem),
ib_umem_end(umem));
else
mlx5_ib_free_implicit_mr(mr);
@@ -1647,18 +1652,19 @@ static void dereg_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr)
umem = NULL;
}
#endif
-
clean_mr(dev, mr);
+ /*
+ * We should unregister the DMA address from the HCA before
+ * remove the DMA mapping.
+ */
+ mlx5_mr_cache_free(dev, mr);
if (umem) {
ib_umem_release(umem);
atomic_sub(npages, &dev->mdev->priv.reg_pages);
}
-
if (!mr->allocated_from_cache)
kfree(mr);
- else
- mlx5_mr_cache_free(dev, mr);
}
int mlx5_ib_dereg_mr(struct ib_mr *ibmr)
diff --git a/drivers/infiniband/hw/mlx5/odp.c b/drivers/infiniband/hw/mlx5/odp.c
index d216e0d2921d..b04eb6775326 100644
--- a/drivers/infiniband/hw/mlx5/odp.c
+++ b/drivers/infiniband/hw/mlx5/odp.c
@@ -61,13 +61,21 @@ static int check_parent(struct ib_umem_odp *odp,
return mr && mr->parent == parent && !odp->dying;
}
+struct ib_ucontext_per_mm *mr_to_per_mm(struct mlx5_ib_mr *mr)
+{
+ if (WARN_ON(!mr || !mr->umem || !mr->umem->is_odp))
+ return NULL;
+
+ return to_ib_umem_odp(mr->umem)->per_mm;
+}
+
static struct ib_umem_odp *odp_next(struct ib_umem_odp *odp)
{
struct mlx5_ib_mr *mr = odp->private, *parent = mr->parent;
- struct ib_ucontext *ctx = odp->umem->context;
+ struct ib_ucontext_per_mm *per_mm = odp->per_mm;
struct rb_node *rb;
- down_read(&ctx->umem_rwsem);
+ down_read(&per_mm->umem_rwsem);
while (1) {
rb = rb_next(&odp->interval_tree.rb);
if (!rb)
@@ -79,19 +87,19 @@ static struct ib_umem_odp *odp_next(struct ib_umem_odp *odp)
not_found:
odp = NULL;
end:
- up_read(&ctx->umem_rwsem);
+ up_read(&per_mm->umem_rwsem);
return odp;
}
-static struct ib_umem_odp *odp_lookup(struct ib_ucontext *ctx,
- u64 start, u64 length,
+static struct ib_umem_odp *odp_lookup(u64 start, u64 length,
struct mlx5_ib_mr *parent)
{
+ struct ib_ucontext_per_mm *per_mm = mr_to_per_mm(parent);
struct ib_umem_odp *odp;
struct rb_node *rb;
- down_read(&ctx->umem_rwsem);
- odp = rbt_ib_umem_lookup(&ctx->umem_tree, start, length);
+ down_read(&per_mm->umem_rwsem);
+ odp = rbt_ib_umem_lookup(&per_mm->umem_tree, start, length);
if (!odp)
goto end;
@@ -102,13 +110,13 @@ static struct ib_umem_odp *odp_lookup(struct ib_ucontext *ctx,
if (!rb)
goto not_found;
odp = rb_entry(rb, struct ib_umem_odp, interval_tree.rb);
- if (ib_umem_start(odp->umem) > start + length)
+ if (ib_umem_start(&odp->umem) > start + length)
goto not_found;
}
not_found:
odp = NULL;
end:
- up_read(&ctx->umem_rwsem);
+ up_read(&per_mm->umem_rwsem);
return odp;
}
@@ -116,7 +124,6 @@ void mlx5_odp_populate_klm(struct mlx5_klm *pklm, size_t offset,
size_t nentries, struct mlx5_ib_mr *mr, int flags)
{
struct ib_pd *pd = mr->ibmr.pd;
- struct ib_ucontext *ctx = pd->uobject->context;
struct mlx5_ib_dev *dev = to_mdev(pd->device);
struct ib_umem_odp *odp;
unsigned long va;
@@ -131,13 +138,13 @@ void mlx5_odp_populate_klm(struct mlx5_klm *pklm, size_t offset,
return;
}
- odp = odp_lookup(ctx, offset * MLX5_IMR_MTT_SIZE,
- nentries * MLX5_IMR_MTT_SIZE, mr);
+ odp = odp_lookup(offset * MLX5_IMR_MTT_SIZE,
+ nentries * MLX5_IMR_MTT_SIZE, mr);
for (i = 0; i < nentries; i++, pklm++) {
pklm->bcount = cpu_to_be32(MLX5_IMR_MTT_SIZE);
va = (offset + i) * MLX5_IMR_MTT_SIZE;
- if (odp && odp->umem->address == va) {
+ if (odp && odp->umem.address == va) {
struct mlx5_ib_mr *mtt = odp->private;
pklm->key = cpu_to_be32(mtt->ibmr.lkey);
@@ -153,13 +160,13 @@ void mlx5_odp_populate_klm(struct mlx5_klm *pklm, size_t offset,
static void mr_leaf_free_action(struct work_struct *work)
{
struct ib_umem_odp *odp = container_of(work, struct ib_umem_odp, work);
- int idx = ib_umem_start(odp->umem) >> MLX5_IMR_MTT_SHIFT;
+ int idx = ib_umem_start(&odp->umem) >> MLX5_IMR_MTT_SHIFT;
struct mlx5_ib_mr *mr = odp->private, *imr = mr->parent;
mr->parent = NULL;
synchronize_srcu(&mr->dev->mr_srcu);
- ib_umem_release(odp->umem);
+ ib_umem_release(&odp->umem);
if (imr->live)
mlx5_ib_update_xlt(imr, idx, 1, 0,
MLX5_IB_UPD_XLT_INDIRECT |
@@ -170,22 +177,24 @@ static void mr_leaf_free_action(struct work_struct *work)
wake_up(&imr->q_leaf_free);
}
-void mlx5_ib_invalidate_range(struct ib_umem *umem, unsigned long start,
+void mlx5_ib_invalidate_range(struct ib_umem_odp *umem_odp, unsigned long start,
unsigned long end)
{
struct mlx5_ib_mr *mr;
const u64 umr_block_mask = (MLX5_UMR_MTT_ALIGNMENT /
sizeof(struct mlx5_mtt)) - 1;
u64 idx = 0, blk_start_idx = 0;
+ struct ib_umem *umem;
int in_block = 0;
u64 addr;
- if (!umem || !umem->odp_data) {
+ if (!umem_odp) {
pr_err("invalidation called on NULL umem or non-ODP umem\n");
return;
}
+ umem = &umem_odp->umem;
- mr = umem->odp_data->private;
+ mr = umem_odp->private;
if (!mr || !mr->ibmr.pd)
return;
@@ -208,7 +217,7 @@ void mlx5_ib_invalidate_range(struct ib_umem *umem, unsigned long start,
* estimate the cost of another UMR vs. the cost of bigger
* UMR.
*/
- if (umem->odp_data->dma_list[idx] &
+ if (umem_odp->dma_list[idx] &
(ODP_READ_ALLOWED_BIT | ODP_WRITE_ALLOWED_BIT)) {
if (!in_block) {
blk_start_idx = idx;
@@ -237,13 +246,13 @@ void mlx5_ib_invalidate_range(struct ib_umem *umem, unsigned long start,
* needed.
*/
- ib_umem_odp_unmap_dma_pages(umem, start, end);
+ ib_umem_odp_unmap_dma_pages(umem_odp, start, end);
if (unlikely(!umem->npages && mr->parent &&
- !umem->odp_data->dying)) {
- WRITE_ONCE(umem->odp_data->dying, 1);
+ !umem_odp->dying)) {
+ WRITE_ONCE(umem_odp->dying, 1);
atomic_inc(&mr->parent->num_leaf_free);
- schedule_work(&umem->odp_data->work);
+ schedule_work(&umem_odp->work);
}
}
@@ -366,16 +375,15 @@ fail:
static struct ib_umem_odp *implicit_mr_get_data(struct mlx5_ib_mr *mr,
u64 io_virt, size_t bcnt)
{
- struct ib_ucontext *ctx = mr->ibmr.pd->uobject->context;
struct mlx5_ib_dev *dev = to_mdev(mr->ibmr.pd->device);
struct ib_umem_odp *odp, *result = NULL;
+ struct ib_umem_odp *odp_mr = to_ib_umem_odp(mr->umem);
u64 addr = io_virt & MLX5_IMR_MTT_MASK;
int nentries = 0, start_idx = 0, ret;
struct mlx5_ib_mr *mtt;
- struct ib_umem *umem;
- mutex_lock(&mr->umem->odp_data->umem_mutex);
- odp = odp_lookup(ctx, addr, 1, mr);
+ mutex_lock(&odp_mr->umem_mutex);
+ odp = odp_lookup(addr, 1, mr);
mlx5_ib_dbg(dev, "io_virt:%llx bcnt:%zx addr:%llx odp:%p\n",
io_virt, bcnt, addr, odp);
@@ -385,22 +393,23 @@ next_mr:
if (nentries)
nentries++;
} else {
- umem = ib_alloc_odp_umem(ctx, addr, MLX5_IMR_MTT_SIZE);
- if (IS_ERR(umem)) {
- mutex_unlock(&mr->umem->odp_data->umem_mutex);
- return ERR_CAST(umem);
+ odp = ib_alloc_odp_umem(odp_mr->per_mm, addr,
+ MLX5_IMR_MTT_SIZE);
+ if (IS_ERR(odp)) {
+ mutex_unlock(&odp_mr->umem_mutex);
+ return ERR_CAST(odp);
}
- mtt = implicit_mr_alloc(mr->ibmr.pd, umem, 0, mr->access_flags);
+ mtt = implicit_mr_alloc(mr->ibmr.pd, &odp->umem, 0,
+ mr->access_flags);
if (IS_ERR(mtt)) {
- mutex_unlock(&mr->umem->odp_data->umem_mutex);
- ib_umem_release(umem);
+ mutex_unlock(&odp_mr->umem_mutex);
+ ib_umem_release(&odp->umem);
return ERR_CAST(mtt);
}
- odp = umem->odp_data;
odp->private = mtt;
- mtt->umem = umem;
+ mtt->umem = &odp->umem;
mtt->mmkey.iova = addr;
mtt->parent = mr;
INIT_WORK(&odp->work, mr_leaf_free_action);
@@ -417,7 +426,7 @@ next_mr:
addr += MLX5_IMR_MTT_SIZE;
if (unlikely(addr < io_virt + bcnt)) {
odp = odp_next(odp);
- if (odp && odp->umem->address != addr)
+ if (odp && odp->umem.address != addr)
odp = NULL;
goto next_mr;
}
@@ -432,7 +441,7 @@ next_mr:
}
}
- mutex_unlock(&mr->umem->odp_data->umem_mutex);
+ mutex_unlock(&odp_mr->umem_mutex);
return result;
}
@@ -460,36 +469,36 @@ struct mlx5_ib_mr *mlx5_ib_alloc_implicit_mr(struct mlx5_ib_pd *pd,
return imr;
}
-static int mr_leaf_free(struct ib_umem *umem, u64 start,
- u64 end, void *cookie)
+static int mr_leaf_free(struct ib_umem_odp *umem_odp, u64 start, u64 end,
+ void *cookie)
{
- struct mlx5_ib_mr *mr = umem->odp_data->private, *imr = cookie;
+ struct mlx5_ib_mr *mr = umem_odp->private, *imr = cookie;
+ struct ib_umem *umem = &umem_odp->umem;
if (mr->parent != imr)
return 0;
- ib_umem_odp_unmap_dma_pages(umem,
- ib_umem_start(umem),
+ ib_umem_odp_unmap_dma_pages(umem_odp, ib_umem_start(umem),
ib_umem_end(umem));
- if (umem->odp_data->dying)
+ if (umem_odp->dying)
return 0;
- WRITE_ONCE(umem->odp_data->dying, 1);
+ WRITE_ONCE(umem_odp->dying, 1);
atomic_inc(&imr->num_leaf_free);
- schedule_work(&umem->odp_data->work);
+ schedule_work(&umem_odp->work);
return 0;
}
void mlx5_ib_free_implicit_mr(struct mlx5_ib_mr *imr)
{
- struct ib_ucontext *ctx = imr->ibmr.pd->uobject->context;
+ struct ib_ucontext_per_mm *per_mm = mr_to_per_mm(imr);
- down_read(&ctx->umem_rwsem);
- rbt_ib_umem_for_each_in_range(&ctx->umem_tree, 0, ULLONG_MAX,
+ down_read(&per_mm->umem_rwsem);
+ rbt_ib_umem_for_each_in_range(&per_mm->umem_tree, 0, ULLONG_MAX,
mr_leaf_free, true, imr);
- up_read(&ctx->umem_rwsem);
+ up_read(&per_mm->umem_rwsem);
wait_event(imr->q_leaf_free, !atomic_read(&imr->num_leaf_free));
}
@@ -497,6 +506,7 @@ void mlx5_ib_free_implicit_mr(struct mlx5_ib_mr *imr)
static int pagefault_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr,
u64 io_virt, size_t bcnt, u32 *bytes_mapped)
{
+ struct ib_umem_odp *odp_mr = to_ib_umem_odp(mr->umem);
u64 access_mask = ODP_READ_ALLOWED_BIT;
int npages = 0, page_shift, np;
u64 start_idx, page_mask;
@@ -505,7 +515,7 @@ static int pagefault_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr,
size_t size;
int ret;
- if (!mr->umem->odp_data->page_list) {
+ if (!odp_mr->page_list) {
odp = implicit_mr_get_data(mr, io_virt, bcnt);
if (IS_ERR(odp))
@@ -513,11 +523,11 @@ static int pagefault_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr,
mr = odp->private;
} else {
- odp = mr->umem->odp_data;
+ odp = odp_mr;
}
next_mr:
- size = min_t(size_t, bcnt, ib_umem_end(odp->umem) - io_virt);
+ size = min_t(size_t, bcnt, ib_umem_end(&odp->umem) - io_virt);
page_shift = mr->umem->page_shift;
page_mask = ~(BIT(page_shift) - 1);
@@ -533,7 +543,7 @@ next_mr:
*/
smp_rmb();
- ret = ib_umem_odp_map_dma_pages(mr->umem, io_virt, size,
+ ret = ib_umem_odp_map_dma_pages(to_ib_umem_odp(mr->umem), io_virt, size,
access_mask, current_seq);
if (ret < 0)
@@ -542,7 +552,8 @@ next_mr:
np = ret;
mutex_lock(&odp->umem_mutex);
- if (!ib_umem_mmu_notifier_retry(mr->umem, current_seq)) {
+ if (!ib_umem_mmu_notifier_retry(to_ib_umem_odp(mr->umem),
+ current_seq)) {
/*
* No need to check whether the MTTs really belong to
* this MR, since ib_umem_odp_map_dma_pages already
@@ -575,7 +586,7 @@ next_mr:
io_virt += size;
next = odp_next(odp);
- if (unlikely(!next || next->umem->address != io_virt)) {
+ if (unlikely(!next || next->umem.address != io_virt)) {
mlx5_ib_dbg(dev, "next implicit leaf removed at 0x%llx. got %p\n",
io_virt, next);
return -EAGAIN;
diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c
index 6cba2a02d11b..6841c0f9237f 100644
--- a/drivers/infiniband/hw/mlx5/qp.c
+++ b/drivers/infiniband/hw/mlx5/qp.c
@@ -37,6 +37,7 @@
#include <linux/mlx5/fs.h>
#include "mlx5_ib.h"
#include "ib_rep.h"
+#include "cmd.h"
/* not supported currently */
static int wq_signature;
@@ -850,6 +851,7 @@ static int create_user_qp(struct mlx5_ib_dev *dev, struct ib_pd *pd,
goto err_umem;
}
+ MLX5_SET(create_qp_in, *in, uid, to_mpd(pd)->uid);
pas = (__be64 *)MLX5_ADDR_OF(create_qp_in, *in, pas);
if (ubuffer->umem)
mlx5_ib_populate_pas(dev, ubuffer->umem, page_shift, pas, 0);
@@ -1051,7 +1053,8 @@ static u32 get_rx_type(struct mlx5_ib_qp *qp, struct ib_qp_init_attr *attr)
static int is_connected(enum ib_qp_type qp_type)
{
- if (qp_type == IB_QPT_RC || qp_type == IB_QPT_UC)
+ if (qp_type == IB_QPT_RC || qp_type == IB_QPT_UC ||
+ qp_type == MLX5_IB_QPT_DCI)
return 1;
return 0;
@@ -1059,11 +1062,13 @@ static int is_connected(enum ib_qp_type qp_type)
static int create_raw_packet_qp_tis(struct mlx5_ib_dev *dev,
struct mlx5_ib_qp *qp,
- struct mlx5_ib_sq *sq, u32 tdn)
+ struct mlx5_ib_sq *sq, u32 tdn,
+ struct ib_pd *pd)
{
u32 in[MLX5_ST_SZ_DW(create_tis_in)] = {0};
void *tisc = MLX5_ADDR_OF(create_tis_in, in, ctx);
+ MLX5_SET(create_tis_in, in, uid, to_mpd(pd)->uid);
MLX5_SET(tisc, tisc, transport_domain, tdn);
if (qp->flags & MLX5_IB_QP_UNDERLAY)
MLX5_SET(tisc, tisc, underlay_qpn, qp->underlay_qpn);
@@ -1072,9 +1077,9 @@ static int create_raw_packet_qp_tis(struct mlx5_ib_dev *dev,
}
static void destroy_raw_packet_qp_tis(struct mlx5_ib_dev *dev,
- struct mlx5_ib_sq *sq)
+ struct mlx5_ib_sq *sq, struct ib_pd *pd)
{
- mlx5_core_destroy_tis(dev->mdev, sq->tisn);
+ mlx5_cmd_destroy_tis(dev->mdev, sq->tisn, to_mpd(pd)->uid);
}
static void destroy_flow_rule_vport_sq(struct mlx5_ib_dev *dev,
@@ -1114,6 +1119,7 @@ static int create_raw_packet_qp_sq(struct mlx5_ib_dev *dev,
goto err_umem;
}
+ MLX5_SET(create_sq_in, in, uid, to_mpd(pd)->uid);
sqc = MLX5_ADDR_OF(create_sq_in, in, ctx);
MLX5_SET(sqc, sqc, flush_in_error_en, 1);
if (MLX5_CAP_ETH(dev->mdev, multi_pkt_send_wqe))
@@ -1188,7 +1194,7 @@ static size_t get_rq_pas_size(void *qpc)
static int create_raw_packet_qp_rq(struct mlx5_ib_dev *dev,
struct mlx5_ib_rq *rq, void *qpin,
- size_t qpinlen)
+ size_t qpinlen, struct ib_pd *pd)
{
struct mlx5_ib_qp *mqp = rq->base.container_mibqp;
__be64 *pas;
@@ -1209,6 +1215,7 @@ static int create_raw_packet_qp_rq(struct mlx5_ib_dev *dev,
if (!in)
return -ENOMEM;
+ MLX5_SET(create_rq_in, in, uid, to_mpd(pd)->uid);
rqc = MLX5_ADDR_OF(create_rq_in, in, ctx);
if (!(rq->flags & MLX5_IB_RQ_CVLAN_STRIPPING))
MLX5_SET(rqc, rqc, vsd, 1);
@@ -1256,10 +1263,23 @@ static bool tunnel_offload_supported(struct mlx5_core_dev *dev)
MLX5_CAP_ETH(dev, tunnel_stateless_geneve_rx));
}
+static void destroy_raw_packet_qp_tir(struct mlx5_ib_dev *dev,
+ struct mlx5_ib_rq *rq,
+ u32 qp_flags_en,
+ struct ib_pd *pd)
+{
+ if (qp_flags_en & (MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC |
+ MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_MC))
+ mlx5_ib_disable_lb(dev, false, true);
+ mlx5_cmd_destroy_tir(dev->mdev, rq->tirn, to_mpd(pd)->uid);
+}
+
static int create_raw_packet_qp_tir(struct mlx5_ib_dev *dev,
struct mlx5_ib_rq *rq, u32 tdn,
- bool tunnel_offload_en)
+ u32 *qp_flags_en,
+ struct ib_pd *pd)
{
+ u8 lb_flag = 0;
u32 *in;
void *tirc;
int inlen;
@@ -1270,33 +1290,45 @@ static int create_raw_packet_qp_tir(struct mlx5_ib_dev *dev,
if (!in)
return -ENOMEM;
+ MLX5_SET(create_tir_in, in, uid, to_mpd(pd)->uid);
tirc = MLX5_ADDR_OF(create_tir_in, in, ctx);
MLX5_SET(tirc, tirc, disp_type, MLX5_TIRC_DISP_TYPE_DIRECT);
MLX5_SET(tirc, tirc, inline_rqn, rq->base.mqp.qpn);
MLX5_SET(tirc, tirc, transport_domain, tdn);
- if (tunnel_offload_en)
+ if (*qp_flags_en & MLX5_QP_FLAG_TUNNEL_OFFLOADS)
MLX5_SET(tirc, tirc, tunneled_offload_en, 1);
- if (dev->rep)
- MLX5_SET(tirc, tirc, self_lb_block,
- MLX5_TIRC_SELF_LB_BLOCK_BLOCK_UNICAST_);
+ if (*qp_flags_en & MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC)
+ lb_flag |= MLX5_TIRC_SELF_LB_BLOCK_BLOCK_UNICAST;
+
+ if (*qp_flags_en & MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_MC)
+ lb_flag |= MLX5_TIRC_SELF_LB_BLOCK_BLOCK_MULTICAST;
+
+ if (dev->rep) {
+ lb_flag |= MLX5_TIRC_SELF_LB_BLOCK_BLOCK_UNICAST;
+ *qp_flags_en |= MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC;
+ }
+
+ MLX5_SET(tirc, tirc, self_lb_block, lb_flag);
err = mlx5_core_create_tir(dev->mdev, in, inlen, &rq->tirn);
+ if (!err && MLX5_GET(tirc, tirc, self_lb_block)) {
+ err = mlx5_ib_enable_lb(dev, false, true);
+
+ if (err)
+ destroy_raw_packet_qp_tir(dev, rq, 0, pd);
+ }
kvfree(in);
return err;
}
-static void destroy_raw_packet_qp_tir(struct mlx5_ib_dev *dev,
- struct mlx5_ib_rq *rq)
-{
- mlx5_core_destroy_tir(dev->mdev, rq->tirn);
-}
-
static int create_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
u32 *in, size_t inlen,
- struct ib_pd *pd)
+ struct ib_pd *pd,
+ struct ib_udata *udata,
+ struct mlx5_ib_create_qp_resp *resp)
{
struct mlx5_ib_raw_packet_qp *raw_packet_qp = &qp->raw_packet_qp;
struct mlx5_ib_sq *sq = &raw_packet_qp->sq;
@@ -1306,9 +1338,10 @@ static int create_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
struct mlx5_ib_ucontext *mucontext = to_mucontext(ucontext);
int err;
u32 tdn = mucontext->tdn;
+ u16 uid = to_mpd(pd)->uid;
if (qp->sq.wqe_cnt) {
- err = create_raw_packet_qp_tis(dev, qp, sq, tdn);
+ err = create_raw_packet_qp_tis(dev, qp, sq, tdn, pd);
if (err)
return err;
@@ -1316,6 +1349,13 @@ static int create_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
if (err)
goto err_destroy_tis;
+ if (uid) {
+ resp->tisn = sq->tisn;
+ resp->comp_mask |= MLX5_IB_CREATE_QP_RESP_MASK_TISN;
+ resp->sqn = sq->base.mqp.qpn;
+ resp->comp_mask |= MLX5_IB_CREATE_QP_RESP_MASK_SQN;
+ }
+
sq->base.container_mibqp = qp;
sq->base.mqp.event = mlx5_ib_qp_event;
}
@@ -1327,22 +1367,32 @@ static int create_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
rq->flags |= MLX5_IB_RQ_CVLAN_STRIPPING;
if (qp->flags & MLX5_IB_QP_PCI_WRITE_END_PADDING)
rq->flags |= MLX5_IB_RQ_PCI_WRITE_END_PADDING;
- err = create_raw_packet_qp_rq(dev, rq, in, inlen);
+ err = create_raw_packet_qp_rq(dev, rq, in, inlen, pd);
if (err)
goto err_destroy_sq;
-
- err = create_raw_packet_qp_tir(dev, rq, tdn,
- qp->tunnel_offload_en);
+ err = create_raw_packet_qp_tir(dev, rq, tdn, &qp->flags_en, pd);
if (err)
goto err_destroy_rq;
+
+ if (uid) {
+ resp->rqn = rq->base.mqp.qpn;
+ resp->comp_mask |= MLX5_IB_CREATE_QP_RESP_MASK_RQN;
+ resp->tirn = rq->tirn;
+ resp->comp_mask |= MLX5_IB_CREATE_QP_RESP_MASK_TIRN;
+ }
}
qp->trans_qp.base.mqp.qpn = qp->sq.wqe_cnt ? sq->base.mqp.qpn :
rq->base.mqp.qpn;
+ err = ib_copy_to_udata(udata, resp, min(udata->outlen, sizeof(*resp)));
+ if (err)
+ goto err_destroy_tir;
return 0;
+err_destroy_tir:
+ destroy_raw_packet_qp_tir(dev, rq, qp->flags_en, pd);
err_destroy_rq:
destroy_raw_packet_qp_rq(dev, rq);
err_destroy_sq:
@@ -1350,7 +1400,7 @@ err_destroy_sq:
return err;
destroy_raw_packet_qp_sq(dev, sq);
err_destroy_tis:
- destroy_raw_packet_qp_tis(dev, sq);
+ destroy_raw_packet_qp_tis(dev, sq, pd);
return err;
}
@@ -1363,13 +1413,13 @@ static void destroy_raw_packet_qp(struct mlx5_ib_dev *dev,
struct mlx5_ib_rq *rq = &raw_packet_qp->rq;
if (qp->rq.wqe_cnt) {
- destroy_raw_packet_qp_tir(dev, rq);
+ destroy_raw_packet_qp_tir(dev, rq, qp->flags_en, qp->ibqp.pd);
destroy_raw_packet_qp_rq(dev, rq);
}
if (qp->sq.wqe_cnt) {
destroy_raw_packet_qp_sq(dev, sq);
- destroy_raw_packet_qp_tis(dev, sq);
+ destroy_raw_packet_qp_tis(dev, sq, qp->ibqp.pd);
}
}
@@ -1387,7 +1437,11 @@ static void raw_packet_qp_copy_info(struct mlx5_ib_qp *qp,
static void destroy_rss_raw_qp_tir(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp)
{
- mlx5_core_destroy_tir(dev->mdev, qp->rss_qp.tirn);
+ if (qp->flags_en & (MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC |
+ MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_MC))
+ mlx5_ib_disable_lb(dev, false, true);
+ mlx5_cmd_destroy_tir(dev->mdev, qp->rss_qp.tirn,
+ to_mpd(qp->ibqp.pd)->uid);
}
static int create_rss_raw_qp_tir(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
@@ -1410,6 +1464,7 @@ static int create_rss_raw_qp_tir(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
u32 tdn = mucontext->tdn;
struct mlx5_ib_create_qp_rss ucmd = {};
size_t required_cmd_sz;
+ u8 lb_flag = 0;
if (init_attr->qp_type != IB_QPT_RAW_PACKET)
return -EOPNOTSUPP;
@@ -1444,7 +1499,9 @@ static int create_rss_raw_qp_tir(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
return -EOPNOTSUPP;
}
- if (ucmd.flags & ~MLX5_QP_FLAG_TUNNEL_OFFLOADS) {
+ if (ucmd.flags & ~(MLX5_QP_FLAG_TUNNEL_OFFLOADS |
+ MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC |
+ MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_MC)) {
mlx5_ib_dbg(dev, "invalid flags\n");
return -EOPNOTSUPP;
}
@@ -1461,6 +1518,16 @@ static int create_rss_raw_qp_tir(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
return -EOPNOTSUPP;
}
+ if (ucmd.flags & MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC || dev->rep) {
+ lb_flag |= MLX5_TIRC_SELF_LB_BLOCK_BLOCK_UNICAST;
+ qp->flags_en |= MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC;
+ }
+
+ if (ucmd.flags & MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_MC) {
+ lb_flag |= MLX5_TIRC_SELF_LB_BLOCK_BLOCK_MULTICAST;
+ qp->flags_en |= MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_MC;
+ }
+
err = ib_copy_to_udata(udata, &resp, min(udata->outlen, sizeof(resp)));
if (err) {
mlx5_ib_dbg(dev, "copy failed\n");
@@ -1472,6 +1539,7 @@ static int create_rss_raw_qp_tir(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
if (!in)
return -ENOMEM;
+ MLX5_SET(create_tir_in, in, uid, to_mpd(pd)->uid);
tirc = MLX5_ADDR_OF(create_tir_in, in, ctx);
MLX5_SET(tirc, tirc, disp_type,
MLX5_TIRC_DISP_TYPE_INDIRECT);
@@ -1484,6 +1552,8 @@ static int create_rss_raw_qp_tir(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
if (ucmd.flags & MLX5_QP_FLAG_TUNNEL_OFFLOADS)
MLX5_SET(tirc, tirc, tunneled_offload_en, 1);
+ MLX5_SET(tirc, tirc, self_lb_block, lb_flag);
+
if (ucmd.rx_hash_fields_mask & MLX5_RX_HASH_INNER)
hfso = MLX5_ADDR_OF(tirc, tirc, rx_hash_field_selector_inner);
else
@@ -1580,26 +1650,141 @@ static int create_rss_raw_qp_tir(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
MLX5_SET(rx_hash_field_select, hfso, selected_fields, selected_fields);
create_tir:
- if (dev->rep)
- MLX5_SET(tirc, tirc, self_lb_block,
- MLX5_TIRC_SELF_LB_BLOCK_BLOCK_UNICAST_);
-
err = mlx5_core_create_tir(dev->mdev, in, inlen, &qp->rss_qp.tirn);
+ if (!err && MLX5_GET(tirc, tirc, self_lb_block)) {
+ err = mlx5_ib_enable_lb(dev, false, true);
+
+ if (err)
+ mlx5_cmd_destroy_tir(dev->mdev, qp->rss_qp.tirn,
+ to_mpd(pd)->uid);
+ }
+
if (err)
goto err;
+ if (mucontext->devx_uid) {
+ resp.comp_mask |= MLX5_IB_CREATE_QP_RESP_MASK_TIRN;
+ resp.tirn = qp->rss_qp.tirn;
+ }
+
+ err = ib_copy_to_udata(udata, &resp, min(udata->outlen, sizeof(resp)));
+ if (err)
+ goto err_copy;
+
kvfree(in);
/* qpn is reserved for that QP */
qp->trans_qp.base.mqp.qpn = 0;
qp->flags |= MLX5_IB_QP_RSS;
return 0;
+err_copy:
+ mlx5_cmd_destroy_tir(dev->mdev, qp->rss_qp.tirn, mucontext->devx_uid);
err:
kvfree(in);
return err;
}
+static void configure_responder_scat_cqe(struct ib_qp_init_attr *init_attr,
+ void *qpc)
+{
+ int rcqe_sz;
+
+ if (init_attr->qp_type == MLX5_IB_QPT_DCI)
+ return;
+
+ rcqe_sz = mlx5_ib_get_cqe_size(init_attr->recv_cq);
+
+ if (rcqe_sz == 128) {
+ MLX5_SET(qpc, qpc, cs_res, MLX5_RES_SCAT_DATA64_CQE);
+ return;
+ }
+
+ if (init_attr->qp_type != MLX5_IB_QPT_DCT)
+ MLX5_SET(qpc, qpc, cs_res, MLX5_RES_SCAT_DATA32_CQE);
+}
+
+static void configure_requester_scat_cqe(struct mlx5_ib_dev *dev,
+ struct ib_qp_init_attr *init_attr,
+ struct mlx5_ib_create_qp *ucmd,
+ void *qpc)
+{
+ enum ib_qp_type qpt = init_attr->qp_type;
+ int scqe_sz;
+ bool allow_scat_cqe = 0;
+
+ if (qpt == IB_QPT_UC || qpt == IB_QPT_UD)
+ return;
+
+ if (ucmd)
+ allow_scat_cqe = ucmd->flags & MLX5_QP_FLAG_ALLOW_SCATTER_CQE;
+
+ if (!allow_scat_cqe && init_attr->sq_sig_type != IB_SIGNAL_ALL_WR)
+ return;
+
+ scqe_sz = mlx5_ib_get_cqe_size(init_attr->send_cq);
+ if (scqe_sz == 128) {
+ MLX5_SET(qpc, qpc, cs_req, MLX5_REQ_SCAT_DATA64_CQE);
+ return;
+ }
+
+ if (init_attr->qp_type != MLX5_IB_QPT_DCI ||
+ MLX5_CAP_GEN(dev->mdev, dc_req_scat_data_cqe))
+ MLX5_SET(qpc, qpc, cs_req, MLX5_REQ_SCAT_DATA32_CQE);
+}
+
+static int atomic_size_to_mode(int size_mask)
+{
+ /* driver does not support atomic_size > 256B
+ * and does not know how to translate bigger sizes
+ */
+ int supported_size_mask = size_mask & 0x1ff;
+ int log_max_size;
+
+ if (!supported_size_mask)
+ return -EOPNOTSUPP;
+
+ log_max_size = __fls(supported_size_mask);
+
+ if (log_max_size > 3)
+ return log_max_size;
+
+ return MLX5_ATOMIC_MODE_8B;
+}
+
+static int get_atomic_mode(struct mlx5_ib_dev *dev,
+ enum ib_qp_type qp_type)
+{
+ u8 atomic_operations = MLX5_CAP_ATOMIC(dev->mdev, atomic_operations);
+ u8 atomic = MLX5_CAP_GEN(dev->mdev, atomic);
+ int atomic_mode = -EOPNOTSUPP;
+ int atomic_size_mask;
+
+ if (!atomic)
+ return -EOPNOTSUPP;
+
+ if (qp_type == MLX5_IB_QPT_DCT)
+ atomic_size_mask = MLX5_CAP_ATOMIC(dev->mdev, atomic_size_dc);
+ else
+ atomic_size_mask = MLX5_CAP_ATOMIC(dev->mdev, atomic_size_qp);
+
+ if ((atomic_operations & MLX5_ATOMIC_OPS_EXTENDED_CMP_SWAP) ||
+ (atomic_operations & MLX5_ATOMIC_OPS_EXTENDED_FETCH_ADD))
+ atomic_mode = atomic_size_to_mode(atomic_size_mask);
+
+ if (atomic_mode <= 0 &&
+ (atomic_operations & MLX5_ATOMIC_OPS_CMP_SWAP &&
+ atomic_operations & MLX5_ATOMIC_OPS_FETCH_ADD))
+ atomic_mode = MLX5_ATOMIC_MODE_IB_COMP;
+
+ return atomic_mode;
+}
+
+static inline bool check_flags_mask(uint64_t input, uint64_t supported)
+{
+ return (input & ~supported) == 0;
+}
+
static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd,
struct ib_qp_init_attr *init_attr,
struct ib_udata *udata, struct mlx5_ib_qp *qp)
@@ -1697,20 +1882,47 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd,
return -EFAULT;
}
+ if (!check_flags_mask(ucmd.flags,
+ MLX5_QP_FLAG_SIGNATURE |
+ MLX5_QP_FLAG_SCATTER_CQE |
+ MLX5_QP_FLAG_TUNNEL_OFFLOADS |
+ MLX5_QP_FLAG_BFREG_INDEX |
+ MLX5_QP_FLAG_TYPE_DCT |
+ MLX5_QP_FLAG_TYPE_DCI |
+ MLX5_QP_FLAG_ALLOW_SCATTER_CQE))
+ return -EINVAL;
+
err = get_qp_user_index(to_mucontext(pd->uobject->context),
&ucmd, udata->inlen, &uidx);
if (err)
return err;
qp->wq_sig = !!(ucmd.flags & MLX5_QP_FLAG_SIGNATURE);
- qp->scat_cqe = !!(ucmd.flags & MLX5_QP_FLAG_SCATTER_CQE);
+ if (MLX5_CAP_GEN(dev->mdev, sctr_data_cqe))
+ qp->scat_cqe = !!(ucmd.flags & MLX5_QP_FLAG_SCATTER_CQE);
if (ucmd.flags & MLX5_QP_FLAG_TUNNEL_OFFLOADS) {
if (init_attr->qp_type != IB_QPT_RAW_PACKET ||
!tunnel_offload_supported(mdev)) {
mlx5_ib_dbg(dev, "Tunnel offload isn't supported\n");
return -EOPNOTSUPP;
}
- qp->tunnel_offload_en = true;
+ qp->flags_en |= MLX5_QP_FLAG_TUNNEL_OFFLOADS;
+ }
+
+ if (ucmd.flags & MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC) {
+ if (init_attr->qp_type != IB_QPT_RAW_PACKET) {
+ mlx5_ib_dbg(dev, "Self-LB UC isn't supported\n");
+ return -EOPNOTSUPP;
+ }
+ qp->flags_en |= MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC;
+ }
+
+ if (ucmd.flags & MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_MC) {
+ if (init_attr->qp_type != IB_QPT_RAW_PACKET) {
+ mlx5_ib_dbg(dev, "Self-LB UM isn't supported\n");
+ return -EOPNOTSUPP;
+ }
+ qp->flags_en |= MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_MC;
}
if (init_attr->create_flags & IB_QP_CREATE_SOURCE_QPN) {
@@ -1811,23 +2023,10 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd,
MLX5_SET(qpc, qpc, cd_slave_receive, 1);
if (qp->scat_cqe && is_connected(init_attr->qp_type)) {
- int rcqe_sz;
- int scqe_sz;
-
- rcqe_sz = mlx5_ib_get_cqe_size(dev, init_attr->recv_cq);
- scqe_sz = mlx5_ib_get_cqe_size(dev, init_attr->send_cq);
-
- if (rcqe_sz == 128)
- MLX5_SET(qpc, qpc, cs_res, MLX5_RES_SCAT_DATA64_CQE);
- else
- MLX5_SET(qpc, qpc, cs_res, MLX5_RES_SCAT_DATA32_CQE);
-
- if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR) {
- if (scqe_sz == 128)
- MLX5_SET(qpc, qpc, cs_req, MLX5_REQ_SCAT_DATA64_CQE);
- else
- MLX5_SET(qpc, qpc, cs_req, MLX5_REQ_SCAT_DATA32_CQE);
- }
+ configure_responder_scat_cqe(init_attr, qpc);
+ configure_requester_scat_cqe(dev, init_attr,
+ (pd && pd->uobject) ? &ucmd : NULL,
+ qpc);
}
if (qp->rq.wqe_cnt) {
@@ -1911,7 +2110,8 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd,
qp->flags & MLX5_IB_QP_UNDERLAY) {
qp->raw_packet_qp.sq.ubuffer.buf_addr = ucmd.sq_buf_addr;
raw_packet_qp_copy_info(qp, &qp->raw_packet_qp);
- err = create_raw_packet_qp(dev, qp, in, inlen, pd);
+ err = create_raw_packet_qp(dev, qp, in, inlen, pd, udata,
+ &resp);
} else {
err = mlx5_core_create_qp(dev->mdev, &base->mqp, in, inlen);
}
@@ -2192,6 +2392,7 @@ static struct ib_qp *mlx5_ib_create_dct(struct ib_pd *pd,
goto err_free;
}
+ MLX5_SET(create_dct_in, qp->dct.in, uid, to_mpd(pd)->uid);
dctc = MLX5_ADDR_OF(create_dct_in, qp->dct.in, dct_context_entry);
qp->qp_sub_type = MLX5_IB_QPT_DCT;
MLX5_SET(dctc, dctc, pd, to_mpd(pd)->pdn);
@@ -2200,6 +2401,9 @@ static struct ib_qp *mlx5_ib_create_dct(struct ib_pd *pd,
MLX5_SET64(dctc, dctc, dc_access_key, ucmd->access_key);
MLX5_SET(dctc, dctc, user_index, uidx);
+ if (ucmd->flags & MLX5_QP_FLAG_SCATTER_CQE)
+ configure_responder_scat_cqe(attr, dctc);
+
qp->state = IB_QPS_RESET;
return &qp->ibqp;
@@ -2405,13 +2609,15 @@ int mlx5_ib_destroy_qp(struct ib_qp *qp)
return 0;
}
-static __be32 to_mlx5_access_flags(struct mlx5_ib_qp *qp, const struct ib_qp_attr *attr,
- int attr_mask)
+static int to_mlx5_access_flags(struct mlx5_ib_qp *qp,
+ const struct ib_qp_attr *attr,
+ int attr_mask, __be32 *hw_access_flags)
{
- u32 hw_access_flags = 0;
u8 dest_rd_atomic;
u32 access_flags;
+ struct mlx5_ib_dev *dev = to_mdev(qp->ibqp.device);
+
if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)
dest_rd_atomic = attr->max_dest_rd_atomic;
else
@@ -2426,13 +2632,25 @@ static __be32 to_mlx5_access_flags(struct mlx5_ib_qp *qp, const struct ib_qp_att
access_flags &= IB_ACCESS_REMOTE_WRITE;
if (access_flags & IB_ACCESS_REMOTE_READ)
- hw_access_flags |= MLX5_QP_BIT_RRE;
- if (access_flags & IB_ACCESS_REMOTE_ATOMIC)
- hw_access_flags |= (MLX5_QP_BIT_RAE | MLX5_ATOMIC_MODE_CX);
+ *hw_access_flags |= MLX5_QP_BIT_RRE;
+ if ((access_flags & IB_ACCESS_REMOTE_ATOMIC) &&
+ qp->ibqp.qp_type == IB_QPT_RC) {
+ int atomic_mode;
+
+ atomic_mode = get_atomic_mode(dev, qp->ibqp.qp_type);
+ if (atomic_mode < 0)
+ return -EOPNOTSUPP;
+
+ *hw_access_flags |= MLX5_QP_BIT_RAE;
+ *hw_access_flags |= atomic_mode << MLX5_ATOMIC_MODE_OFFSET;
+ }
+
if (access_flags & IB_ACCESS_REMOTE_WRITE)
- hw_access_flags |= MLX5_QP_BIT_RWE;
+ *hw_access_flags |= MLX5_QP_BIT_RWE;
+
+ *hw_access_flags = cpu_to_be32(*hw_access_flags);
- return cpu_to_be32(hw_access_flags);
+ return 0;
}
enum {
@@ -2458,7 +2676,8 @@ static int ib_rate_to_mlx5(struct mlx5_ib_dev *dev, u8 rate)
}
static int modify_raw_packet_eth_prio(struct mlx5_core_dev *dev,
- struct mlx5_ib_sq *sq, u8 sl)
+ struct mlx5_ib_sq *sq, u8 sl,
+ struct ib_pd *pd)
{
void *in;
void *tisc;
@@ -2471,6 +2690,7 @@ static int modify_raw_packet_eth_prio(struct mlx5_core_dev *dev,
return -ENOMEM;
MLX5_SET(modify_tis_in, in, bitmask.prio, 1);
+ MLX5_SET(modify_tis_in, in, uid, to_mpd(pd)->uid);
tisc = MLX5_ADDR_OF(modify_tis_in, in, ctx);
MLX5_SET(tisc, tisc, prio, ((sl & 0x7) << 1));
@@ -2483,7 +2703,8 @@ static int modify_raw_packet_eth_prio(struct mlx5_core_dev *dev,
}
static int modify_raw_packet_tx_affinity(struct mlx5_core_dev *dev,
- struct mlx5_ib_sq *sq, u8 tx_affinity)
+ struct mlx5_ib_sq *sq, u8 tx_affinity,
+ struct ib_pd *pd)
{
void *in;
void *tisc;
@@ -2496,6 +2717,7 @@ static int modify_raw_packet_tx_affinity(struct mlx5_core_dev *dev,
return -ENOMEM;
MLX5_SET(modify_tis_in, in, bitmask.lag_tx_port_affinity, 1);
+ MLX5_SET(modify_tis_in, in, uid, to_mpd(pd)->uid);
tisc = MLX5_ADDR_OF(modify_tis_in, in, ctx);
MLX5_SET(tisc, tisc, lag_tx_port_affinity, tx_affinity);
@@ -2580,7 +2802,7 @@ static int mlx5_set_path(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
if ((qp->ibqp.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);
+ sl & 0xf, qp->ibqp.pd);
return 0;
}
@@ -2728,9 +2950,9 @@ static int ib_mask_to_mlx5_opt(int ib_mask)
return result;
}
-static int modify_raw_packet_qp_rq(struct mlx5_ib_dev *dev,
- struct mlx5_ib_rq *rq, int new_state,
- const struct mlx5_modify_raw_qp_param *raw_qp_param)
+static int modify_raw_packet_qp_rq(
+ struct mlx5_ib_dev *dev, struct mlx5_ib_rq *rq, int new_state,
+ const struct mlx5_modify_raw_qp_param *raw_qp_param, struct ib_pd *pd)
{
void *in;
void *rqc;
@@ -2743,6 +2965,7 @@ static int modify_raw_packet_qp_rq(struct mlx5_ib_dev *dev,
return -ENOMEM;
MLX5_SET(modify_rq_in, in, rq_state, rq->state);
+ MLX5_SET(modify_rq_in, in, uid, to_mpd(pd)->uid);
rqc = MLX5_ADDR_OF(modify_rq_in, in, ctx);
MLX5_SET(rqc, rqc, state, new_state);
@@ -2753,8 +2976,9 @@ static int modify_raw_packet_qp_rq(struct mlx5_ib_dev *dev,
MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_RQ_COUNTER_SET_ID);
MLX5_SET(rqc, rqc, counter_set_id, raw_qp_param->rq_q_ctr_id);
} else
- pr_info_once("%s: RAW PACKET QP counters are not supported on current FW\n",
- dev->ib_dev.name);
+ dev_info_once(
+ &dev->ib_dev.dev,
+ "RAW PACKET QP counters are not supported on current FW\n");
}
err = mlx5_core_modify_rq(dev->mdev, rq->base.mqp.qpn, in, inlen);
@@ -2768,10 +2992,9 @@ out:
return err;
}
-static int modify_raw_packet_qp_sq(struct mlx5_core_dev *dev,
- struct mlx5_ib_sq *sq,
- int new_state,
- const struct mlx5_modify_raw_qp_param *raw_qp_param)
+static int modify_raw_packet_qp_sq(
+ struct mlx5_core_dev *dev, struct mlx5_ib_sq *sq, int new_state,
+ const struct mlx5_modify_raw_qp_param *raw_qp_param, struct ib_pd *pd)
{
struct mlx5_ib_qp *ibqp = sq->base.container_mibqp;
struct mlx5_rate_limit old_rl = ibqp->rl;
@@ -2788,6 +3011,7 @@ static int modify_raw_packet_qp_sq(struct mlx5_core_dev *dev,
if (!in)
return -ENOMEM;
+ MLX5_SET(modify_sq_in, in, uid, to_mpd(pd)->uid);
MLX5_SET(modify_sq_in, in, sq_state, sq->state);
sqc = MLX5_ADDR_OF(modify_sq_in, in, ctx);
@@ -2890,7 +3114,8 @@ static int modify_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
}
if (modify_rq) {
- err = modify_raw_packet_qp_rq(dev, rq, rq_state, raw_qp_param);
+ err = modify_raw_packet_qp_rq(dev, rq, rq_state, raw_qp_param,
+ qp->ibqp.pd);
if (err)
return err;
}
@@ -2898,17 +3123,50 @@ static int modify_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
if (modify_sq) {
if (tx_affinity) {
err = modify_raw_packet_tx_affinity(dev->mdev, sq,
- tx_affinity);
+ tx_affinity,
+ qp->ibqp.pd);
if (err)
return err;
}
- return modify_raw_packet_qp_sq(dev->mdev, sq, sq_state, raw_qp_param);
+ return modify_raw_packet_qp_sq(dev->mdev, sq, sq_state,
+ raw_qp_param, qp->ibqp.pd);
}
return 0;
}
+static unsigned int get_tx_affinity(struct mlx5_ib_dev *dev,
+ struct mlx5_ib_pd *pd,
+ struct mlx5_ib_qp_base *qp_base,
+ u8 port_num)
+{
+ struct mlx5_ib_ucontext *ucontext = NULL;
+ unsigned int tx_port_affinity;
+
+ if (pd && pd->ibpd.uobject && pd->ibpd.uobject->context)
+ ucontext = to_mucontext(pd->ibpd.uobject->context);
+
+ if (ucontext) {
+ tx_port_affinity = (unsigned int)atomic_add_return(
+ 1, &ucontext->tx_port_affinity) %
+ MLX5_MAX_PORTS +
+ 1;
+ mlx5_ib_dbg(dev, "Set tx affinity 0x%x to qpn 0x%x ucontext %p\n",
+ tx_port_affinity, qp_base->mqp.qpn, ucontext);
+ } else {
+ tx_port_affinity =
+ (unsigned int)atomic_add_return(
+ 1, &dev->roce[port_num].tx_port_affinity) %
+ MLX5_MAX_PORTS +
+ 1;
+ mlx5_ib_dbg(dev, "Set tx affinity 0x%x to qpn 0x%x\n",
+ tx_port_affinity, qp_base->mqp.qpn);
+ }
+
+ return tx_port_affinity;
+}
+
static int __mlx5_ib_modify_qp(struct ib_qp *ibqp,
const struct ib_qp_attr *attr, int attr_mask,
enum ib_qp_state cur_state, enum ib_qp_state new_state,
@@ -2974,6 +3232,7 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp,
if (!context)
return -ENOMEM;
+ pd = get_pd(qp);
context->flags = cpu_to_be32(mlx5_st << 16);
if (!(attr_mask & IB_QP_PATH_MIG_STATE)) {
@@ -3002,9 +3261,7 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp,
(ibqp->qp_type == IB_QPT_XRC_TGT)) {
if (mlx5_lag_is_active(dev->mdev)) {
u8 p = mlx5_core_native_port_num(dev->mdev);
- tx_affinity = (unsigned int)atomic_add_return(1,
- &dev->roce[p].next_port) %
- MLX5_MAX_PORTS + 1;
+ tx_affinity = get_tx_affinity(dev, pd, base, p);
context->flags |= cpu_to_be32(tx_affinity << 24);
}
}
@@ -3062,7 +3319,6 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp,
goto out;
}
- pd = get_pd(qp);
get_cqs(qp->ibqp.qp_type, qp->ibqp.send_cq, qp->ibqp.recv_cq,
&send_cq, &recv_cq);
@@ -3092,8 +3348,15 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp,
cpu_to_be32(fls(attr->max_dest_rd_atomic - 1) << 21);
}
- if (attr_mask & (IB_QP_ACCESS_FLAGS | IB_QP_MAX_DEST_RD_ATOMIC))
- context->params2 |= to_mlx5_access_flags(qp, attr, attr_mask);
+ if (attr_mask & (IB_QP_ACCESS_FLAGS | IB_QP_MAX_DEST_RD_ATOMIC)) {
+ __be32 access_flags = 0;
+
+ err = to_mlx5_access_flags(qp, attr, attr_mask, &access_flags);
+ if (err)
+ goto out;
+
+ context->params2 |= access_flags;
+ }
if (attr_mask & IB_QP_MIN_RNR_TIMER)
context->rnr_nextrecvpsn |= cpu_to_be32(attr->min_rnr_timer << 24);
@@ -3243,7 +3506,9 @@ static bool modify_dci_qp_is_ok(enum ib_qp_state cur_state, enum ib_qp_state new
int req = IB_QP_STATE;
int opt = 0;
- if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) {
+ if (new_state == IB_QPS_RESET) {
+ return is_valid_mask(attr_mask, req, opt);
+ } else if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) {
req |= IB_QP_PKEY_INDEX | IB_QP_PORT;
return is_valid_mask(attr_mask, req, opt);
} else if (cur_state == IB_QPS_INIT && new_state == IB_QPS_INIT) {
@@ -3307,10 +3572,14 @@ static int mlx5_ib_modify_dct(struct ib_qp *ibqp, struct ib_qp_attr *attr,
if (attr->qp_access_flags & IB_ACCESS_REMOTE_WRITE)
MLX5_SET(dctc, dctc, rwe, 1);
if (attr->qp_access_flags & IB_ACCESS_REMOTE_ATOMIC) {
- if (!mlx5_ib_dc_atomic_is_supported(dev))
+ int atomic_mode;
+
+ atomic_mode = get_atomic_mode(dev, MLX5_IB_QPT_DCT);
+ if (atomic_mode < 0)
return -EOPNOTSUPP;
+
+ MLX5_SET(dctc, dctc, atomic_mode, atomic_mode);
MLX5_SET(dctc, dctc, rae, 1);
- MLX5_SET(dctc, dctc, atomic_mode, MLX5_ATOMIC_MODE_DCT_CX);
}
MLX5_SET(dctc, dctc, pkey_index, attr->pkey_index);
MLX5_SET(dctc, dctc, port, attr->port_num);
@@ -3367,7 +3636,6 @@ int mlx5_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
size_t required_cmd_sz;
int err = -EINVAL;
int port;
- enum rdma_link_layer ll = IB_LINK_LAYER_UNSPECIFIED;
if (ibqp->rwq_ind_tbl)
return -ENOSYS;
@@ -3413,7 +3681,6 @@ int mlx5_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
if (!(cur_state == new_state && cur_state == IB_QPS_RESET)) {
port = attr_mask & IB_QP_PORT ? attr->port_num : qp->port;
- ll = dev->ib_dev.get_link_layer(&dev->ib_dev, port);
}
if (qp->flags & MLX5_IB_QP_UNDERLAY) {
@@ -3424,7 +3691,8 @@ int mlx5_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
}
} else if (qp_type != MLX5_IB_QPT_REG_UMR &&
qp_type != MLX5_IB_QPT_DCI &&
- !ib_modify_qp_is_ok(cur_state, new_state, qp_type, attr_mask, ll)) {
+ !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);
goto out;
@@ -4371,6 +4639,12 @@ static int _mlx5_ib_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr,
u8 next_fence = 0;
u8 fence;
+ if (unlikely(mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR &&
+ !drain)) {
+ *bad_wr = wr;
+ return -EIO;
+ }
+
if (unlikely(ibqp->qp_type == IB_QPT_GSI))
return mlx5_ib_gsi_post_send(ibqp, wr, bad_wr);
@@ -4380,13 +4654,6 @@ static int _mlx5_ib_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr,
spin_lock_irqsave(&qp->sq.lock, flags);
- if (mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR && !drain) {
- err = -EIO;
- *bad_wr = wr;
- nreq = 0;
- goto out;
- }
-
for (nreq = 0; wr; nreq++, wr = wr->next) {
if (unlikely(wr->opcode >= ARRAY_SIZE(mlx5_ib_opcode))) {
mlx5_ib_warn(dev, "\n");
@@ -4700,18 +4967,17 @@ static int _mlx5_ib_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr,
int ind;
int i;
+ if (unlikely(mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR &&
+ !drain)) {
+ *bad_wr = wr;
+ return -EIO;
+ }
+
if (unlikely(ibqp->qp_type == IB_QPT_GSI))
return mlx5_ib_gsi_post_recv(ibqp, wr, bad_wr);
spin_lock_irqsave(&qp->rq.lock, flags);
- if (mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR && !drain) {
- err = -EIO;
- *bad_wr = wr;
- nreq = 0;
- goto out;
- }
-
ind = qp->rq.head & (qp->rq.wqe_cnt - 1);
for (nreq = 0; wr; nreq++, wr = wr->next) {
@@ -5175,6 +5441,7 @@ struct ib_xrcd *mlx5_ib_alloc_xrcd(struct ib_device *ibdev,
struct mlx5_ib_dev *dev = to_mdev(ibdev);
struct mlx5_ib_xrcd *xrcd;
int err;
+ u16 uid;
if (!MLX5_CAP_GEN(dev->mdev, xrc))
return ERR_PTR(-ENOSYS);
@@ -5183,12 +5450,14 @@ struct ib_xrcd *mlx5_ib_alloc_xrcd(struct ib_device *ibdev,
if (!xrcd)
return ERR_PTR(-ENOMEM);
- err = mlx5_core_xrcd_alloc(dev->mdev, &xrcd->xrcdn);
+ uid = context ? to_mucontext(context)->devx_uid : 0;
+ err = mlx5_cmd_xrcd_alloc(dev->mdev, &xrcd->xrcdn, uid);
if (err) {
kfree(xrcd);
return ERR_PTR(-ENOMEM);
}
+ xrcd->uid = uid;
return &xrcd->ibxrcd;
}
@@ -5196,9 +5465,10 @@ int mlx5_ib_dealloc_xrcd(struct ib_xrcd *xrcd)
{
struct mlx5_ib_dev *dev = to_mdev(xrcd->device);
u32 xrcdn = to_mxrcd(xrcd)->xrcdn;
+ u16 uid = to_mxrcd(xrcd)->uid;
int err;
- err = mlx5_core_xrcd_dealloc(dev->mdev, xrcdn);
+ err = mlx5_cmd_xrcd_dealloc(dev->mdev, xrcdn, uid);
if (err)
mlx5_ib_warn(dev, "failed to dealloc xrcdn 0x%x\n", xrcdn);
@@ -5268,6 +5538,7 @@ static int create_rq(struct mlx5_ib_rwq *rwq, struct ib_pd *pd,
if (!in)
return -ENOMEM;
+ MLX5_SET(create_rq_in, in, uid, to_mpd(pd)->uid);
rqc = MLX5_ADDR_OF(create_rq_in, in, ctx);
MLX5_SET(rqc, rqc, mem_rq_type,
MLX5_RQC_MEM_RQ_TYPE_MEMORY_RQ_INLINE);
@@ -5443,8 +5714,7 @@ static int prepare_user_rq(struct ib_pd *pd,
err = create_user_rq(dev, pd, rwq, &ucmd);
if (err) {
mlx5_ib_dbg(dev, "err %d\n", err);
- if (err)
- return err;
+ return err;
}
rwq->user_index = ucmd.user_index;
@@ -5573,6 +5843,9 @@ struct ib_rwq_ind_table *mlx5_ib_create_rwq_ind_table(struct ib_device *device,
for (i = 0; i < sz; i++)
MLX5_SET(rqtc, rqtc, rq_num[i], init_attr->ind_tbl[i]->wq_num);
+ rwq_ind_tbl->uid = to_mpd(init_attr->ind_tbl[0]->pd)->uid;
+ MLX5_SET(create_rqt_in, in, uid, rwq_ind_tbl->uid);
+
err = mlx5_core_create_rqt(dev->mdev, in, inlen, &rwq_ind_tbl->rqtn);
kvfree(in);
@@ -5591,7 +5864,7 @@ struct ib_rwq_ind_table *mlx5_ib_create_rwq_ind_table(struct ib_device *device,
return &rwq_ind_tbl->ib_rwq_ind_tbl;
err_copy:
- mlx5_core_destroy_rqt(dev->mdev, rwq_ind_tbl->rqtn);
+ mlx5_cmd_destroy_rqt(dev->mdev, rwq_ind_tbl->rqtn, rwq_ind_tbl->uid);
err:
kfree(rwq_ind_tbl);
return ERR_PTR(err);
@@ -5602,7 +5875,7 @@ int mlx5_ib_destroy_rwq_ind_table(struct ib_rwq_ind_table *ib_rwq_ind_tbl)
struct mlx5_ib_rwq_ind_table *rwq_ind_tbl = to_mrwq_ind_table(ib_rwq_ind_tbl);
struct mlx5_ib_dev *dev = to_mdev(ib_rwq_ind_tbl->device);
- mlx5_core_destroy_rqt(dev->mdev, rwq_ind_tbl->rqtn);
+ mlx5_cmd_destroy_rqt(dev->mdev, rwq_ind_tbl->rqtn, rwq_ind_tbl->uid);
kfree(rwq_ind_tbl);
return 0;
@@ -5653,6 +5926,7 @@ int mlx5_ib_modify_wq(struct ib_wq *wq, struct ib_wq_attr *wq_attr,
if (wq_state == IB_WQS_ERR)
wq_state = MLX5_RQC_STATE_ERR;
MLX5_SET(modify_rq_in, in, rq_state, curr_wq_state);
+ MLX5_SET(modify_rq_in, in, uid, to_mpd(wq->pd)->uid);
MLX5_SET(rqc, rqc, state, wq_state);
if (wq_attr_mask & IB_WQ_FLAGS) {
@@ -5684,8 +5958,9 @@ int mlx5_ib_modify_wq(struct ib_wq *wq, struct ib_wq_attr *wq_attr,
MLX5_SET(rqc, rqc, counter_set_id,
dev->port->cnts.set_id);
} else
- pr_info_once("%s: Receive WQ counters are not supported on current FW\n",
- dev->ib_dev.name);
+ dev_info_once(
+ &dev->ib_dev.dev,
+ "Receive WQ counters are not supported on current FW\n");
}
err = mlx5_core_modify_rq(dev->mdev, rwq->core_qp.qpn, in, inlen);
diff --git a/drivers/infiniband/hw/mlx5/srq.c b/drivers/infiniband/hw/mlx5/srq.c
index d359fecf7a5b..d012e7dbcc38 100644
--- a/drivers/infiniband/hw/mlx5/srq.c
+++ b/drivers/infiniband/hw/mlx5/srq.c
@@ -144,6 +144,7 @@ static int create_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq,
in->log_page_size = page_shift - MLX5_ADAPTER_PAGE_SHIFT;
in->page_offset = offset;
+ in->uid = to_mpd(pd)->uid;
if (MLX5_CAP_GEN(dev->mdev, cqe_version) == MLX5_CQE_VERSION_V1 &&
in->type != IB_SRQT_BASIC)
in->user_index = uidx;
diff --git a/drivers/infiniband/hw/mthca/mthca_mad.c b/drivers/infiniband/hw/mthca/mthca_mad.c
index 093f7755c843..2e5dc0a67cfc 100644
--- a/drivers/infiniband/hw/mthca/mthca_mad.c
+++ b/drivers/infiniband/hw/mthca/mthca_mad.c
@@ -58,8 +58,9 @@ static int mthca_update_rate(struct mthca_dev *dev, u8 port_num)
ret = ib_query_port(&dev->ib_dev, port_num, tprops);
if (ret) {
- printk(KERN_WARNING "ib_query_port failed (%d) for %s port %d\n",
- ret, dev->ib_dev.name, port_num);
+ dev_warn(&dev->ib_dev.dev,
+ "ib_query_port failed (%d) forport %d\n", ret,
+ port_num);
goto out;
}
diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c
index f3e80dec1334..92c49bff22bc 100644
--- a/drivers/infiniband/hw/mthca/mthca_main.c
+++ b/drivers/infiniband/hw/mthca/mthca_main.c
@@ -986,7 +986,8 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type)
goto err_free_dev;
}
- if (mthca_cmd_init(mdev)) {
+ err = mthca_cmd_init(mdev);
+ if (err) {
mthca_err(mdev, "Failed to init command interface, aborting.\n");
goto err_free_dev;
}
@@ -1014,8 +1015,7 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type)
err = mthca_setup_hca(mdev);
if (err == -EBUSY && (mdev->mthca_flags & MTHCA_FLAG_MSI_X)) {
- if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
- pci_free_irq_vectors(pdev);
+ pci_free_irq_vectors(pdev);
mdev->mthca_flags &= ~MTHCA_FLAG_MSI_X;
err = mthca_setup_hca(mdev);
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c
index 0d3473b4596e..691c6f048938 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.c
+++ b/drivers/infiniband/hw/mthca/mthca_provider.c
@@ -1076,16 +1076,17 @@ static int mthca_unmap_fmr(struct list_head *fmr_list)
return err;
}
-static ssize_t show_rev(struct device *device, struct device_attribute *attr,
- char *buf)
+static ssize_t hw_rev_show(struct device *device,
+ struct device_attribute *attr, char *buf)
{
struct mthca_dev *dev =
container_of(device, struct mthca_dev, ib_dev.dev);
return sprintf(buf, "%x\n", dev->rev_id);
}
+static DEVICE_ATTR_RO(hw_rev);
-static ssize_t show_hca(struct device *device, struct device_attribute *attr,
- char *buf)
+static ssize_t hca_type_show(struct device *device,
+ struct device_attribute *attr, char *buf)
{
struct mthca_dev *dev =
container_of(device, struct mthca_dev, ib_dev.dev);
@@ -1103,23 +1104,26 @@ static ssize_t show_hca(struct device *device, struct device_attribute *attr,
return sprintf(buf, "unknown\n");
}
}
+static DEVICE_ATTR_RO(hca_type);
-static ssize_t show_board(struct device *device, struct device_attribute *attr,
- char *buf)
+static ssize_t board_id_show(struct device *device,
+ struct device_attribute *attr, char *buf)
{
struct mthca_dev *dev =
container_of(device, struct mthca_dev, ib_dev.dev);
return sprintf(buf, "%.*s\n", MTHCA_BOARD_ID_LEN, dev->board_id);
}
+static DEVICE_ATTR_RO(board_id);
-static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL);
-static DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL);
-static DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL);
+static struct attribute *mthca_dev_attributes[] = {
+ &dev_attr_hw_rev.attr,
+ &dev_attr_hca_type.attr,
+ &dev_attr_board_id.attr,
+ NULL
+};
-static struct device_attribute *mthca_dev_attributes[] = {
- &dev_attr_hw_rev,
- &dev_attr_hca_type,
- &dev_attr_board_id
+static const struct attribute_group mthca_attr_group = {
+ .attrs = mthca_dev_attributes,
};
static int mthca_init_node_data(struct mthca_dev *dev)
@@ -1192,13 +1196,11 @@ static void get_dev_fw_str(struct ib_device *device, char *str)
int mthca_register_device(struct mthca_dev *dev)
{
int ret;
- int i;
ret = mthca_init_node_data(dev);
if (ret)
return ret;
- strlcpy(dev->ib_dev.name, "mthca%d", IB_DEVICE_NAME_MAX);
dev->ib_dev.owner = THIS_MODULE;
dev->ib_dev.uverbs_abi_ver = MTHCA_UVERBS_ABI_VERSION;
@@ -1296,20 +1298,12 @@ int mthca_register_device(struct mthca_dev *dev)
mutex_init(&dev->cap_mask_mutex);
+ rdma_set_device_sysfs_group(&dev->ib_dev, &mthca_attr_group);
dev->ib_dev.driver_id = RDMA_DRIVER_MTHCA;
- ret = ib_register_device(&dev->ib_dev, NULL);
+ ret = ib_register_device(&dev->ib_dev, "mthca%d", NULL);
if (ret)
return ret;
- for (i = 0; i < ARRAY_SIZE(mthca_dev_attributes); ++i) {
- ret = device_create_file(&dev->ib_dev.dev,
- mthca_dev_attributes[i]);
- if (ret) {
- ib_unregister_device(&dev->ib_dev);
- return ret;
- }
- }
-
mthca_start_catas_poll(dev);
return 0;
diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c
index 3d37f2373d63..9d178ee3c96a 100644
--- a/drivers/infiniband/hw/mthca/mthca_qp.c
+++ b/drivers/infiniband/hw/mthca/mthca_qp.c
@@ -872,8 +872,8 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
new_state = attr_mask & IB_QP_STATE ? attr->qp_state : cur_state;
- if (!ib_modify_qp_is_ok(cur_state, new_state, ibqp->qp_type, attr_mask,
- IB_LINK_LAYER_UNSPECIFIED)) {
+ if (!ib_modify_qp_is_ok(cur_state, new_state, ibqp->qp_type,
+ attr_mask)) {
mthca_dbg(dev, "Bad QP transition (transport %d) "
"%d->%d with attr 0x%08x\n",
qp->transport, cur_state, new_state,
diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c
index 42b68aa999fc..e00add6d78ec 100644
--- a/drivers/infiniband/hw/nes/nes.c
+++ b/drivers/infiniband/hw/nes/nes.c
@@ -456,9 +456,6 @@ static int nes_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
void __iomem *mmio_regs = NULL;
u8 hw_rev;
- assert(pcidev != NULL);
- assert(ent != NULL);
-
printk(KERN_INFO PFX "NetEffect RNIC driver v%s loading. (%s)\n",
DRV_VERSION, pci_name(pcidev));
diff --git a/drivers/infiniband/hw/nes/nes.h b/drivers/infiniband/hw/nes/nes.h
index bedaa02749fb..a895fe980d10 100644
--- a/drivers/infiniband/hw/nes/nes.h
+++ b/drivers/infiniband/hw/nes/nes.h
@@ -149,18 +149,9 @@ do { \
printk(KERN_ERR PFX "%s[%u]: " fmt, __func__, __LINE__, ##args); \
} while (0)
-#define assert(expr) \
-do { \
- if (!(expr)) { \
- printk(KERN_ERR PFX "Assertion failed! %s, %s, %s, line %d\n", \
- #expr, __FILE__, __func__, __LINE__); \
- } \
-} while (0)
-
#define NES_EVENT_TIMEOUT 1200000
#else
#define nes_debug(level, fmt, args...) no_printk(fmt, ##args)
-#define assert(expr) do {} while (0)
#define NES_EVENT_TIMEOUT 100000
#endif
diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c
index bd0675d8f298..5517e392bc01 100644
--- a/drivers/infiniband/hw/nes/nes_hw.c
+++ b/drivers/infiniband/hw/nes/nes_hw.c
@@ -1443,7 +1443,7 @@ static int nes_init_2025_phy(struct nes_device *nesdev, u8 phy_type, u8 phy_inde
mdelay(1);
nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7ee);
temp_phy_data2 = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
- } while ((temp_phy_data2 == temp_phy_data));
+ } while (temp_phy_data2 == temp_phy_data);
/* wait for tracking */
counter = 0;
diff --git a/drivers/infiniband/hw/nes/nes_mgt.c b/drivers/infiniband/hw/nes/nes_mgt.c
index 9bdb84dc225c..e96ffff61c3a 100644
--- a/drivers/infiniband/hw/nes/nes_mgt.c
+++ b/drivers/infiniband/hw/nes/nes_mgt.c
@@ -198,9 +198,9 @@ static struct sk_buff *nes_get_next_skb(struct nes_device *nesdev, struct nes_qp
if (skb) {
/* Continue processing fpdu */
- if (skb->next == (struct sk_buff *)&nesqp->pau_list)
+ skb = skb_peek_next(skb, &nesqp->pau_list);
+ if (!skb)
goto out;
- skb = skb->next;
processacks = false;
} else {
/* Starting a new one */
@@ -553,12 +553,10 @@ static void queue_fpdus(struct sk_buff *skb, struct nes_vnic *nesvnic, struct ne
if (skb_queue_len(&nesqp->pau_list) == 0) {
skb_queue_head(&nesqp->pau_list, skb);
} else {
- tmpskb = nesqp->pau_list.next;
- while (tmpskb != (struct sk_buff *)&nesqp->pau_list) {
+ skb_queue_walk(&nesqp->pau_list, tmpskb) {
cb = (struct nes_rskb_cb *)&tmpskb->cb[0];
if (before(seqnum, cb->seqnum))
break;
- tmpskb = tmpskb->next;
}
skb_insert(tmpskb, skb, &nesqp->pau_list);
}
diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c
index 61014e251555..16f33454c198 100644
--- a/drivers/infiniband/hw/nes/nes_nic.c
+++ b/drivers/infiniband/hw/nes/nes_nic.c
@@ -146,8 +146,6 @@ static int nes_netdev_open(struct net_device *netdev)
struct list_head *list_pos, *list_temp;
unsigned long flags;
- assert(nesdev != NULL);
-
if (nesvnic->netdev_open == 1)
return 0;
diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c
index 6940c7215961..92d1cadd4cfd 100644
--- a/drivers/infiniband/hw/nes/nes_verbs.c
+++ b/drivers/infiniband/hw/nes/nes_verbs.c
@@ -687,7 +687,7 @@ static struct ib_pd *nes_alloc_pd(struct ib_device *ibdev,
}
nes_debug(NES_DBG_PD, "Allocating PD (%p) for ib device %s\n",
- nespd, nesvnic->nesibdev->ibdev.name);
+ nespd, dev_name(&nesvnic->nesibdev->ibdev.dev));
nespd->pd_id = (pd_num << (PAGE_SHIFT-12)) + nesadapter->base_pd;
@@ -2556,8 +2556,8 @@ static int nes_dereg_mr(struct ib_mr *ib_mr)
/**
* show_rev
*/
-static ssize_t show_rev(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t hw_rev_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct nes_ib_device *nesibdev =
container_of(dev, struct nes_ib_device, ibdev.dev);
@@ -2566,40 +2566,40 @@ static ssize_t show_rev(struct device *dev, struct device_attribute *attr,
nes_debug(NES_DBG_INIT, "\n");
return sprintf(buf, "%x\n", nesvnic->nesdev->nesadapter->hw_rev);
}
-
+static DEVICE_ATTR_RO(hw_rev);
/**
* show_hca
*/
-static ssize_t show_hca(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t hca_type_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
nes_debug(NES_DBG_INIT, "\n");
return sprintf(buf, "NES020\n");
}
-
+static DEVICE_ATTR_RO(hca_type);
/**
* show_board
*/
-static ssize_t show_board(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t board_id_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
nes_debug(NES_DBG_INIT, "\n");
return sprintf(buf, "%.*s\n", 32, "NES020 Board ID");
}
+static DEVICE_ATTR_RO(board_id);
-
-static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL);
-static DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL);
-static DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL);
-
-static struct device_attribute *nes_dev_attributes[] = {
- &dev_attr_hw_rev,
- &dev_attr_hca_type,
- &dev_attr_board_id
+static struct attribute *nes_dev_attributes[] = {
+ &dev_attr_hw_rev.attr,
+ &dev_attr_hca_type.attr,
+ &dev_attr_board_id.attr,
+ NULL
};
+static const struct attribute_group nes_attr_group = {
+ .attrs = nes_dev_attributes,
+};
/**
* nes_query_qp
@@ -3640,7 +3640,6 @@ struct nes_ib_device *nes_init_ofa_device(struct net_device *netdev)
if (nesibdev == NULL) {
return NULL;
}
- strlcpy(nesibdev->ibdev.name, "nes%d", IB_DEVICE_NAME_MAX);
nesibdev->ibdev.owner = THIS_MODULE;
nesibdev->ibdev.node_type = RDMA_NODE_RNIC;
@@ -3795,10 +3794,11 @@ int nes_register_ofa_device(struct nes_ib_device *nesibdev)
struct nes_vnic *nesvnic = nesibdev->nesvnic;
struct nes_device *nesdev = nesvnic->nesdev;
struct nes_adapter *nesadapter = nesdev->nesadapter;
- int i, ret;
+ int ret;
+ rdma_set_device_sysfs_group(&nesvnic->nesibdev->ibdev, &nes_attr_group);
nesvnic->nesibdev->ibdev.driver_id = RDMA_DRIVER_NES;
- ret = ib_register_device(&nesvnic->nesibdev->ibdev, NULL);
+ ret = ib_register_device(&nesvnic->nesibdev->ibdev, "nes%d", NULL);
if (ret) {
return ret;
}
@@ -3809,19 +3809,6 @@ int nes_register_ofa_device(struct nes_ib_device *nesibdev)
nesibdev->max_qp = (nesadapter->max_qp-NES_FIRST_QPN) / nesadapter->port_count;
nesibdev->max_pd = nesadapter->max_pd / nesadapter->port_count;
- for (i = 0; i < ARRAY_SIZE(nes_dev_attributes); ++i) {
- ret = device_create_file(&nesibdev->ibdev.dev, nes_dev_attributes[i]);
- if (ret) {
- while (i > 0) {
- i--;
- device_remove_file(&nesibdev->ibdev.dev,
- nes_dev_attributes[i]);
- }
- ib_unregister_device(&nesibdev->ibdev);
- return ret;
- }
- }
-
nesvnic->of_device_registered = 1;
return 0;
@@ -3834,15 +3821,9 @@ int nes_register_ofa_device(struct nes_ib_device *nesibdev)
static void nes_unregister_ofa_device(struct nes_ib_device *nesibdev)
{
struct nes_vnic *nesvnic = nesibdev->nesvnic;
- int i;
- for (i = 0; i < ARRAY_SIZE(nes_dev_attributes); ++i) {
- device_remove_file(&nesibdev->ibdev.dev, nes_dev_attributes[i]);
- }
-
- if (nesvnic->of_device_registered) {
+ if (nesvnic->of_device_registered)
ib_unregister_device(&nesibdev->ibdev);
- }
nesvnic->of_device_registered = 0;
}
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c
index e578281471af..241a57a07485 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c
@@ -792,7 +792,7 @@ static void ocrdma_dispatch_ibevent(struct ocrdma_dev *dev,
qp->srq->ibsrq.
srq_context);
} else if (dev_event) {
- pr_err("%s: Fatal event received\n", dev->ibdev.name);
+ dev_err(&dev->ibdev.dev, "Fatal event received\n");
ib_dispatch_event(&ib_evt);
}
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_main.c b/drivers/infiniband/hw/ocrdma/ocrdma_main.c
index 7832ee3e0c84..873cc7f6fe61 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_main.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_main.c
@@ -114,9 +114,37 @@ static void get_dev_fw_str(struct ib_device *device, char *str)
snprintf(str, IB_FW_VERSION_NAME_MAX, "%s", &dev->attr.fw_ver[0]);
}
+/* OCRDMA sysfs interface */
+static ssize_t hw_rev_show(struct device *device,
+ struct device_attribute *attr, char *buf)
+{
+ struct ocrdma_dev *dev = dev_get_drvdata(device);
+
+ return scnprintf(buf, PAGE_SIZE, "0x%x\n", dev->nic_info.pdev->vendor);
+}
+static DEVICE_ATTR_RO(hw_rev);
+
+static ssize_t hca_type_show(struct device *device,
+ struct device_attribute *attr, char *buf)
+{
+ struct ocrdma_dev *dev = dev_get_drvdata(device);
+
+ return scnprintf(buf, PAGE_SIZE, "%s\n", &dev->model_number[0]);
+}
+static DEVICE_ATTR_RO(hca_type);
+
+static struct attribute *ocrdma_attributes[] = {
+ &dev_attr_hw_rev.attr,
+ &dev_attr_hca_type.attr,
+ NULL
+};
+
+static const struct attribute_group ocrdma_attr_group = {
+ .attrs = ocrdma_attributes,
+};
+
static int ocrdma_register_device(struct ocrdma_dev *dev)
{
- strlcpy(dev->ibdev.name, "ocrdma%d", IB_DEVICE_NAME_MAX);
ocrdma_get_guid(dev, (u8 *)&dev->ibdev.node_guid);
BUILD_BUG_ON(sizeof(OCRDMA_NODE_DESC) > IB_DEVICE_NODE_DESC_MAX);
memcpy(dev->ibdev.node_desc, OCRDMA_NODE_DESC,
@@ -213,8 +241,9 @@ static int ocrdma_register_device(struct ocrdma_dev *dev)
dev->ibdev.destroy_srq = ocrdma_destroy_srq;
dev->ibdev.post_srq_recv = ocrdma_post_srq_recv;
}
+ rdma_set_device_sysfs_group(&dev->ibdev, &ocrdma_attr_group);
dev->ibdev.driver_id = RDMA_DRIVER_OCRDMA;
- return ib_register_device(&dev->ibdev, NULL);
+ return ib_register_device(&dev->ibdev, "ocrdma%d", NULL);
}
static int ocrdma_alloc_resources(struct ocrdma_dev *dev)
@@ -260,42 +289,9 @@ static void ocrdma_free_resources(struct ocrdma_dev *dev)
kfree(dev->cq_tbl);
}
-/* OCRDMA sysfs interface */
-static ssize_t show_rev(struct device *device, struct device_attribute *attr,
- char *buf)
-{
- struct ocrdma_dev *dev = dev_get_drvdata(device);
-
- return scnprintf(buf, PAGE_SIZE, "0x%x\n", dev->nic_info.pdev->vendor);
-}
-
-static ssize_t show_hca_type(struct device *device,
- struct device_attribute *attr, char *buf)
-{
- struct ocrdma_dev *dev = dev_get_drvdata(device);
-
- return scnprintf(buf, PAGE_SIZE, "%s\n", &dev->model_number[0]);
-}
-
-static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL);
-static DEVICE_ATTR(hca_type, S_IRUGO, show_hca_type, NULL);
-
-static struct device_attribute *ocrdma_attributes[] = {
- &dev_attr_hw_rev,
- &dev_attr_hca_type
-};
-
-static void ocrdma_remove_sysfiles(struct ocrdma_dev *dev)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(ocrdma_attributes); i++)
- device_remove_file(&dev->ibdev.dev, ocrdma_attributes[i]);
-}
-
static struct ocrdma_dev *ocrdma_add(struct be_dev_info *dev_info)
{
- int status = 0, i;
+ int status = 0;
u8 lstate = 0;
struct ocrdma_dev *dev;
@@ -331,9 +327,6 @@ static struct ocrdma_dev *ocrdma_add(struct be_dev_info *dev_info)
if (!status)
ocrdma_update_link_state(dev, lstate);
- for (i = 0; i < ARRAY_SIZE(ocrdma_attributes); i++)
- if (device_create_file(&dev->ibdev.dev, ocrdma_attributes[i]))
- goto sysfs_err;
/* Init stats */
ocrdma_add_port_stats(dev);
/* Interrupt Moderation */
@@ -348,8 +341,6 @@ static struct ocrdma_dev *ocrdma_add(struct be_dev_info *dev_info)
dev_name(&dev->nic_info.pdev->dev), dev->id);
return dev;
-sysfs_err:
- ocrdma_remove_sysfiles(dev);
alloc_err:
ocrdma_free_resources(dev);
ocrdma_cleanup_hw(dev);
@@ -376,7 +367,6 @@ static void ocrdma_remove(struct ocrdma_dev *dev)
* of the registered clients.
*/
cancel_delayed_work_sync(&dev->eqd_work);
- ocrdma_remove_sysfiles(dev);
ib_unregister_device(&dev->ibdev);
ocrdma_rem_port_stats(dev);
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_stats.c b/drivers/infiniband/hw/ocrdma/ocrdma_stats.c
index 24d20a4aa262..290d776edf48 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_stats.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_stats.c
@@ -764,7 +764,8 @@ void ocrdma_add_port_stats(struct ocrdma_dev *dev)
return;
/* Create post stats base dir */
- dev->dir = debugfs_create_dir(dev->ibdev.name, ocrdma_dbgfs_dir);
+ dev->dir =
+ debugfs_create_dir(dev_name(&dev->ibdev.dev), ocrdma_dbgfs_dir);
if (!dev->dir)
goto err;
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
index c158ca9fde6d..06d2a7f3304c 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
@@ -1480,8 +1480,7 @@ int ocrdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
new_qps = old_qps;
spin_unlock_irqrestore(&qp->q_lock, flags);
- if (!ib_modify_qp_is_ok(old_qps, new_qps, ibqp->qp_type, attr_mask,
- IB_LINK_LAYER_ETHERNET)) {
+ if (!ib_modify_qp_is_ok(old_qps, new_qps, ibqp->qp_type, attr_mask)) {
pr_err("%s(%d) invalid attribute mask=0x%x specified for\n"
"qpn=0x%x of type=0x%x old_qps=0x%x, new_qps=0x%x\n",
__func__, dev->id, attr_mask, qp->id, ibqp->qp_type,
diff --git a/drivers/infiniband/hw/qedr/main.c b/drivers/infiniband/hw/qedr/main.c
index a0af6d424aed..8d6ff9df49fe 100644
--- a/drivers/infiniband/hw/qedr/main.c
+++ b/drivers/infiniband/hw/qedr/main.c
@@ -133,6 +133,33 @@ static int qedr_iw_port_immutable(struct ib_device *ibdev, u8 port_num,
return 0;
}
+/* QEDR sysfs interface */
+static ssize_t hw_rev_show(struct device *device, struct device_attribute *attr,
+ char *buf)
+{
+ struct qedr_dev *dev = dev_get_drvdata(device);
+
+ return scnprintf(buf, PAGE_SIZE, "0x%x\n", dev->pdev->vendor);
+}
+static DEVICE_ATTR_RO(hw_rev);
+
+static ssize_t hca_type_show(struct device *device,
+ struct device_attribute *attr, char *buf)
+{
+ return scnprintf(buf, PAGE_SIZE, "%s\n", "HCA_TYPE_TO_SET");
+}
+static DEVICE_ATTR_RO(hca_type);
+
+static struct attribute *qedr_attributes[] = {
+ &dev_attr_hw_rev.attr,
+ &dev_attr_hca_type.attr,
+ NULL
+};
+
+static const struct attribute_group qedr_attr_group = {
+ .attrs = qedr_attributes,
+};
+
static int qedr_iw_register_device(struct qedr_dev *dev)
{
dev->ibdev.node_type = RDMA_NODE_RNIC;
@@ -170,8 +197,6 @@ static int qedr_register_device(struct qedr_dev *dev)
{
int rc;
- strlcpy(dev->ibdev.name, "qedr%d", IB_DEVICE_NAME_MAX);
-
dev->ibdev.node_guid = dev->attr.node_guid;
memcpy(dev->ibdev.node_desc, QEDR_NODE_DESC, sizeof(QEDR_NODE_DESC));
dev->ibdev.owner = THIS_MODULE;
@@ -262,9 +287,9 @@ static int qedr_register_device(struct qedr_dev *dev)
dev->ibdev.get_link_layer = qedr_link_layer;
dev->ibdev.get_dev_fw_str = qedr_get_dev_fw_str;
-
+ rdma_set_device_sysfs_group(&dev->ibdev, &qedr_attr_group);
dev->ibdev.driver_id = RDMA_DRIVER_QEDR;
- return ib_register_device(&dev->ibdev, NULL);
+ return ib_register_device(&dev->ibdev, "qedr%d", NULL);
}
/* This function allocates fast-path status block memory */
@@ -404,37 +429,6 @@ err1:
return rc;
}
-/* QEDR sysfs interface */
-static ssize_t show_rev(struct device *device, struct device_attribute *attr,
- char *buf)
-{
- struct qedr_dev *dev = dev_get_drvdata(device);
-
- return scnprintf(buf, PAGE_SIZE, "0x%x\n", dev->pdev->vendor);
-}
-
-static ssize_t show_hca_type(struct device *device,
- struct device_attribute *attr, char *buf)
-{
- return scnprintf(buf, PAGE_SIZE, "%s\n", "HCA_TYPE_TO_SET");
-}
-
-static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL);
-static DEVICE_ATTR(hca_type, S_IRUGO, show_hca_type, NULL);
-
-static struct device_attribute *qedr_attributes[] = {
- &dev_attr_hw_rev,
- &dev_attr_hca_type
-};
-
-static void qedr_remove_sysfiles(struct qedr_dev *dev)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(qedr_attributes); i++)
- device_remove_file(&dev->ibdev.dev, qedr_attributes[i]);
-}
-
static void qedr_pci_set_atomic(struct qedr_dev *dev, struct pci_dev *pdev)
{
int rc = pci_enable_atomic_ops_to_root(pdev,
@@ -855,7 +849,7 @@ static struct qedr_dev *qedr_add(struct qed_dev *cdev, struct pci_dev *pdev,
{
struct qed_dev_rdma_info dev_info;
struct qedr_dev *dev;
- int rc = 0, i;
+ int rc = 0;
dev = (struct qedr_dev *)ib_alloc_device(sizeof(*dev));
if (!dev) {
@@ -914,18 +908,12 @@ static struct qedr_dev *qedr_add(struct qed_dev *cdev, struct pci_dev *pdev,
goto reg_err;
}
- for (i = 0; i < ARRAY_SIZE(qedr_attributes); i++)
- if (device_create_file(&dev->ibdev.dev, qedr_attributes[i]))
- goto sysfs_err;
-
if (!test_and_set_bit(QEDR_ENET_STATE_BIT, &dev->enet_state))
qedr_ib_dispatch_event(dev, QEDR_PORT, IB_EVENT_PORT_ACTIVE);
DP_DEBUG(dev, QEDR_MSG_INIT, "qedr driver loaded successfully\n");
return dev;
-sysfs_err:
- ib_unregister_device(&dev->ibdev);
reg_err:
qedr_sync_free_irqs(dev);
irq_err:
@@ -944,7 +932,6 @@ static void qedr_remove(struct qedr_dev *dev)
/* First unregister with stack to stop all the active traffic
* of the registered clients.
*/
- qedr_remove_sysfiles(dev);
ib_unregister_device(&dev->ibdev);
qedr_stop_hw(dev);
diff --git a/drivers/infiniband/hw/qedr/qedr.h b/drivers/infiniband/hw/qedr/qedr.h
index a2d708dceb8d..53bbe6b4e6e6 100644
--- a/drivers/infiniband/hw/qedr/qedr.h
+++ b/drivers/infiniband/hw/qedr/qedr.h
@@ -43,7 +43,7 @@
#include "qedr_hsi_rdma.h"
#define QEDR_NODE_DESC "QLogic 579xx RoCE HCA"
-#define DP_NAME(dev) ((dev)->ibdev.name)
+#define DP_NAME(_dev) dev_name(&(_dev)->ibdev.dev)
#define IS_IWARP(_dev) ((_dev)->rdma_type == QED_RDMA_TYPE_IWARP)
#define IS_ROCE(_dev) ((_dev)->rdma_type == QED_RDMA_TYPE_ROCE)
diff --git a/drivers/infiniband/hw/qedr/qedr_roce_cm.c b/drivers/infiniband/hw/qedr/qedr_roce_cm.c
index 85578887421b..e1ac2fd60bb1 100644
--- a/drivers/infiniband/hw/qedr/qedr_roce_cm.c
+++ b/drivers/infiniband/hw/qedr/qedr_roce_cm.c
@@ -519,9 +519,9 @@ static inline int qedr_gsi_build_packet(struct qedr_dev *dev,
}
if (ether_addr_equal(udh.eth.smac_h, udh.eth.dmac_h))
- packet->tx_dest = QED_ROCE_LL2_TX_DEST_LB;
+ packet->tx_dest = QED_LL2_TX_DEST_LB;
else
- packet->tx_dest = QED_ROCE_LL2_TX_DEST_NW;
+ packet->tx_dest = QED_LL2_TX_DEST_NW;
packet->roce_mode = roce_mode;
memcpy(packet->header.vaddr, ud_header_buffer, header_size);
diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c
index 8cc3df24e04e..82ee4b4a7084 100644
--- a/drivers/infiniband/hw/qedr/verbs.c
+++ b/drivers/infiniband/hw/qedr/verbs.c
@@ -1447,7 +1447,6 @@ struct ib_srq *qedr_create_srq(struct ib_pd *ibpd,
u64 pbl_base_addr, phy_prod_pair_addr;
struct ib_ucontext *ib_ctx = NULL;
struct qedr_srq_hwq_info *hw_srq;
- struct qedr_ucontext *ctx = NULL;
u32 page_cnt, page_size;
struct qedr_srq *srq;
int rc = 0;
@@ -1473,7 +1472,6 @@ struct ib_srq *qedr_create_srq(struct ib_pd *ibpd,
if (udata && ibpd->uobject && ibpd->uobject->context) {
ib_ctx = ibpd->uobject->context;
- ctx = get_qedr_ucontext(ib_ctx);
if (ib_copy_from_udata(&ureq, udata, sizeof(ureq))) {
DP_ERR(dev,
@@ -2240,8 +2238,7 @@ int qedr_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
if (rdma_protocol_roce(&dev->ibdev, 1)) {
if (!ib_modify_qp_is_ok(old_qp_state, new_qp_state,
- ibqp->qp_type, attr_mask,
- IB_LINK_LAYER_ETHERNET)) {
+ ibqp->qp_type, attr_mask)) {
DP_ERR(dev,
"modify qp: invalid attribute mask=0x%x specified for\n"
"qpn=0x%x of type=0x%x old_qp_state=0x%x, new_qp_state=0x%x\n",
diff --git a/drivers/infiniband/hw/qib/qib.h b/drivers/infiniband/hw/qib/qib.h
index 3461df002f81..83d2349188db 100644
--- a/drivers/infiniband/hw/qib/qib.h
+++ b/drivers/infiniband/hw/qib/qib.h
@@ -1390,13 +1390,13 @@ static inline u32 qib_get_hdrqtail(const struct qib_ctxtdata *rcd)
*/
extern const char ib_qib_version[];
+extern const struct attribute_group qib_attr_group;
int qib_device_create(struct qib_devdata *);
void qib_device_remove(struct qib_devdata *);
int qib_create_port_files(struct ib_device *ibdev, u8 port_num,
struct kobject *kobj);
-int qib_verbs_register_sysfs(struct qib_devdata *);
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_pcie.c b/drivers/infiniband/hw/qib/qib_pcie.c
index 5ac7b31c346b..30595b358d8f 100644
--- a/drivers/infiniband/hw/qib/qib_pcie.c
+++ b/drivers/infiniband/hw/qib/qib_pcie.c
@@ -597,7 +597,6 @@ qib_pci_resume(struct pci_dev *pdev)
struct qib_devdata *dd = pci_get_drvdata(pdev);
qib_devinfo(pdev, "QIB resume function called\n");
- pci_cleanup_aer_uncorrect_error_status(pdev);
/*
* Running jobs will fail, since it's asynchronous
* unlike sysfs-requested reset. Better than
diff --git a/drivers/infiniband/hw/qib/qib_qp.c b/drivers/infiniband/hw/qib/qib_qp.c
index 344e401915f7..a81905df2d0f 100644
--- a/drivers/infiniband/hw/qib/qib_qp.c
+++ b/drivers/infiniband/hw/qib/qib_qp.c
@@ -378,25 +378,22 @@ void qib_flush_qp_waiters(struct rvt_qp *qp)
* qib_check_send_wqe - validate wr/wqe
* @qp - The qp
* @wqe - The built wqe
+ * @call_send - Determine if the send should be posted or scheduled
*
- * validate wr/wqe. This is called
- * prior to inserting the wqe into
- * the ring but after the wqe has been
- * setup.
- *
- * Returns 1 to force direct progress, 0 otherwise, -EINVAL on failure
+ * Returns 0 on success, -EINVAL on failure
*/
int qib_check_send_wqe(struct rvt_qp *qp,
- struct rvt_swqe *wqe)
+ struct rvt_swqe *wqe, bool *call_send)
{
struct rvt_ah *ah;
- int ret = 0;
switch (qp->ibqp.qp_type) {
case IB_QPT_RC:
case IB_QPT_UC:
if (wqe->length > 0x80000000U)
return -EINVAL;
+ if (wqe->length > qp->pmtu)
+ *call_send = false;
break;
case IB_QPT_SMI:
case IB_QPT_GSI:
@@ -405,12 +402,12 @@ int qib_check_send_wqe(struct rvt_qp *qp,
if (wqe->length > (1 << ah->log_pmtu))
return -EINVAL;
/* progress hint */
- ret = 1;
+ *call_send = true;
break;
default:
break;
}
- return ret;
+ return 0;
}
#ifdef CONFIG_DEBUG_FS
diff --git a/drivers/infiniband/hw/qib/qib_rc.c b/drivers/infiniband/hw/qib/qib_rc.c
index f35fdeb14347..6fa002940451 100644
--- a/drivers/infiniband/hw/qib/qib_rc.c
+++ b/drivers/infiniband/hw/qib/qib_rc.c
@@ -254,7 +254,7 @@ int qib_make_rc_req(struct rvt_qp *qp, unsigned long *flags)
goto bail;
}
wqe = rvt_get_swqe_ptr(qp, qp->s_last);
- qib_send_complete(qp, wqe, qp->s_last != qp->s_acked ?
+ rvt_send_complete(qp, wqe, qp->s_last != qp->s_acked ?
IB_WC_SUCCESS : IB_WC_WR_FLUSH_ERR);
/* will get called again */
goto done;
@@ -838,7 +838,7 @@ void qib_restart_rc(struct rvt_qp *qp, u32 psn, int wait)
qib_migrate_qp(qp);
qp->s_retry = qp->s_retry_cnt;
} else if (qp->s_last == qp->s_acked) {
- qib_send_complete(qp, wqe, IB_WC_RETRY_EXC_ERR);
+ rvt_send_complete(qp, wqe, IB_WC_RETRY_EXC_ERR);
rvt_error_qp(qp, IB_WC_WR_FLUSH_ERR);
return;
} else /* XXX need to handle delayed completion */
@@ -1221,7 +1221,7 @@ static int do_rc_ack(struct rvt_qp *qp, u32 aeth, u32 psn, int opcode,
ibp->rvp.n_other_naks++;
class_b:
if (qp->s_last == qp->s_acked) {
- qib_send_complete(qp, wqe, status);
+ rvt_send_complete(qp, wqe, status);
rvt_error_qp(qp, IB_WC_WR_FLUSH_ERR);
}
break;
@@ -1425,7 +1425,8 @@ read_middle:
qp->s_rdma_read_len -= pmtu;
update_last_psn(qp, psn);
spin_unlock_irqrestore(&qp->s_lock, flags);
- qib_copy_sge(&qp->s_rdma_read_sge, data, pmtu, 0);
+ rvt_copy_sge(qp, &qp->s_rdma_read_sge,
+ data, pmtu, false, false);
goto bail;
case OP(RDMA_READ_RESPONSE_ONLY):
@@ -1471,7 +1472,8 @@ read_last:
if (unlikely(tlen != qp->s_rdma_read_len))
goto ack_len_err;
aeth = be32_to_cpu(ohdr->u.aeth);
- qib_copy_sge(&qp->s_rdma_read_sge, data, tlen, 0);
+ rvt_copy_sge(qp, &qp->s_rdma_read_sge,
+ data, tlen, false, false);
WARN_ON(qp->s_rdma_read_sge.num_sge);
(void) do_rc_ack(qp, aeth, psn,
OP(RDMA_READ_RESPONSE_LAST), 0, rcd);
@@ -1490,7 +1492,7 @@ ack_len_err:
status = IB_WC_LOC_LEN_ERR;
ack_err:
if (qp->s_last == qp->s_acked) {
- qib_send_complete(qp, wqe, status);
+ rvt_send_complete(qp, wqe, status);
rvt_error_qp(qp, IB_WC_WR_FLUSH_ERR);
}
ack_done:
@@ -1844,7 +1846,7 @@ send_middle:
qp->r_rcv_len += pmtu;
if (unlikely(qp->r_rcv_len > qp->r_len))
goto nack_inv;
- qib_copy_sge(&qp->r_sge, data, pmtu, 1);
+ rvt_copy_sge(qp, &qp->r_sge, data, pmtu, true, false);
break;
case OP(RDMA_WRITE_LAST_WITH_IMMEDIATE):
@@ -1890,7 +1892,7 @@ send_last:
wc.byte_len = tlen + qp->r_rcv_len;
if (unlikely(wc.byte_len > qp->r_len))
goto nack_inv;
- qib_copy_sge(&qp->r_sge, data, tlen, 1);
+ rvt_copy_sge(qp, &qp->r_sge, data, tlen, true, false);
rvt_put_ss(&qp->r_sge);
qp->r_msn++;
if (!test_and_clear_bit(RVT_R_WRID_VALID, &qp->r_aflags))
diff --git a/drivers/infiniband/hw/qib/qib_ruc.c b/drivers/infiniband/hw/qib/qib_ruc.c
index f8a7de795beb..1fa21938f310 100644
--- a/drivers/infiniband/hw/qib/qib_ruc.c
+++ b/drivers/infiniband/hw/qib/qib_ruc.c
@@ -171,307 +171,6 @@ err:
}
/**
- * qib_ruc_loopback - handle UC and RC lookback requests
- * @sqp: the sending QP
- *
- * This is called from qib_do_send() to
- * forward a WQE addressed to the same HCA.
- * Note that although we are single threaded due to the tasklet, we still
- * have to protect against post_send(). We don't have to worry about
- * receive interrupts since this is a connected protocol and all packets
- * will pass through here.
- */
-static void qib_ruc_loopback(struct rvt_qp *sqp)
-{
- struct qib_ibport *ibp = to_iport(sqp->ibqp.device, sqp->port_num);
- struct qib_pportdata *ppd = ppd_from_ibp(ibp);
- struct qib_devdata *dd = ppd->dd;
- struct rvt_dev_info *rdi = &dd->verbs_dev.rdi;
- struct rvt_qp *qp;
- struct rvt_swqe *wqe;
- struct rvt_sge *sge;
- unsigned long flags;
- struct ib_wc wc;
- u64 sdata;
- atomic64_t *maddr;
- enum ib_wc_status send_status;
- int release;
- int ret;
-
- rcu_read_lock();
- /*
- * Note that we check the responder QP state after
- * checking the requester's state.
- */
- qp = rvt_lookup_qpn(rdi, &ibp->rvp, sqp->remote_qpn);
- if (!qp)
- goto done;
-
- spin_lock_irqsave(&sqp->s_lock, flags);
-
- /* Return if we are already busy processing a work request. */
- if ((sqp->s_flags & (RVT_S_BUSY | RVT_S_ANY_WAIT)) ||
- !(ib_rvt_state_ops[sqp->state] & RVT_PROCESS_OR_FLUSH_SEND))
- goto unlock;
-
- sqp->s_flags |= RVT_S_BUSY;
-
-again:
- if (sqp->s_last == READ_ONCE(sqp->s_head))
- goto clr_busy;
- wqe = rvt_get_swqe_ptr(sqp, sqp->s_last);
-
- /* Return if it is not OK to start a new work reqeust. */
- if (!(ib_rvt_state_ops[sqp->state] & RVT_PROCESS_NEXT_SEND_OK)) {
- if (!(ib_rvt_state_ops[sqp->state] & RVT_FLUSH_SEND))
- goto clr_busy;
- /* We are in the error state, flush the work request. */
- send_status = IB_WC_WR_FLUSH_ERR;
- goto flush_send;
- }
-
- /*
- * We can rely on the entry not changing without the s_lock
- * being held until we update s_last.
- * We increment s_cur to indicate s_last is in progress.
- */
- if (sqp->s_last == sqp->s_cur) {
- if (++sqp->s_cur >= sqp->s_size)
- sqp->s_cur = 0;
- }
- spin_unlock_irqrestore(&sqp->s_lock, flags);
-
- if (!qp || !(ib_rvt_state_ops[qp->state] & RVT_PROCESS_RECV_OK) ||
- qp->ibqp.qp_type != sqp->ibqp.qp_type) {
- ibp->rvp.n_pkt_drops++;
- /*
- * For RC, the requester would timeout and retry so
- * shortcut the timeouts and just signal too many retries.
- */
- if (sqp->ibqp.qp_type == IB_QPT_RC)
- send_status = IB_WC_RETRY_EXC_ERR;
- else
- send_status = IB_WC_SUCCESS;
- goto serr;
- }
-
- memset(&wc, 0, sizeof(wc));
- send_status = IB_WC_SUCCESS;
-
- release = 1;
- sqp->s_sge.sge = wqe->sg_list[0];
- sqp->s_sge.sg_list = wqe->sg_list + 1;
- sqp->s_sge.num_sge = wqe->wr.num_sge;
- sqp->s_len = wqe->length;
- switch (wqe->wr.opcode) {
- case IB_WR_SEND_WITH_IMM:
- wc.wc_flags = IB_WC_WITH_IMM;
- wc.ex.imm_data = wqe->wr.ex.imm_data;
- /* FALLTHROUGH */
- case IB_WR_SEND:
- ret = rvt_get_rwqe(qp, false);
- if (ret < 0)
- goto op_err;
- if (!ret)
- goto rnr_nak;
- break;
-
- case IB_WR_RDMA_WRITE_WITH_IMM:
- if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_WRITE)))
- goto inv_err;
- wc.wc_flags = IB_WC_WITH_IMM;
- wc.ex.imm_data = wqe->wr.ex.imm_data;
- ret = rvt_get_rwqe(qp, true);
- if (ret < 0)
- goto op_err;
- if (!ret)
- goto rnr_nak;
- /* FALLTHROUGH */
- case IB_WR_RDMA_WRITE:
- if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_WRITE)))
- goto inv_err;
- if (wqe->length == 0)
- break;
- if (unlikely(!rvt_rkey_ok(qp, &qp->r_sge.sge, wqe->length,
- wqe->rdma_wr.remote_addr,
- wqe->rdma_wr.rkey,
- IB_ACCESS_REMOTE_WRITE)))
- goto acc_err;
- qp->r_sge.sg_list = NULL;
- qp->r_sge.num_sge = 1;
- qp->r_sge.total_len = wqe->length;
- break;
-
- case IB_WR_RDMA_READ:
- if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_READ)))
- goto inv_err;
- if (unlikely(!rvt_rkey_ok(qp, &sqp->s_sge.sge, wqe->length,
- wqe->rdma_wr.remote_addr,
- wqe->rdma_wr.rkey,
- IB_ACCESS_REMOTE_READ)))
- goto acc_err;
- release = 0;
- sqp->s_sge.sg_list = NULL;
- sqp->s_sge.num_sge = 1;
- qp->r_sge.sge = wqe->sg_list[0];
- qp->r_sge.sg_list = wqe->sg_list + 1;
- qp->r_sge.num_sge = wqe->wr.num_sge;
- qp->r_sge.total_len = wqe->length;
- break;
-
- case IB_WR_ATOMIC_CMP_AND_SWP:
- case IB_WR_ATOMIC_FETCH_AND_ADD:
- if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_ATOMIC)))
- goto inv_err;
- if (unlikely(!rvt_rkey_ok(qp, &qp->r_sge.sge, sizeof(u64),
- wqe->atomic_wr.remote_addr,
- wqe->atomic_wr.rkey,
- IB_ACCESS_REMOTE_ATOMIC)))
- goto acc_err;
- /* Perform atomic OP and save result. */
- maddr = (atomic64_t *) qp->r_sge.sge.vaddr;
- sdata = wqe->atomic_wr.compare_add;
- *(u64 *) sqp->s_sge.sge.vaddr =
- (wqe->atomic_wr.wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD) ?
- (u64) atomic64_add_return(sdata, maddr) - sdata :
- (u64) cmpxchg((u64 *) qp->r_sge.sge.vaddr,
- sdata, wqe->atomic_wr.swap);
- rvt_put_mr(qp->r_sge.sge.mr);
- qp->r_sge.num_sge = 0;
- goto send_comp;
-
- default:
- send_status = IB_WC_LOC_QP_OP_ERR;
- goto serr;
- }
-
- sge = &sqp->s_sge.sge;
- while (sqp->s_len) {
- u32 len = sqp->s_len;
-
- if (len > sge->length)
- len = sge->length;
- if (len > sge->sge_length)
- len = sge->sge_length;
- BUG_ON(len == 0);
- qib_copy_sge(&qp->r_sge, sge->vaddr, len, release);
- sge->vaddr += len;
- sge->length -= len;
- sge->sge_length -= len;
- if (sge->sge_length == 0) {
- if (!release)
- rvt_put_mr(sge->mr);
- if (--sqp->s_sge.num_sge)
- *sge = *sqp->s_sge.sg_list++;
- } else if (sge->length == 0 && sge->mr->lkey) {
- if (++sge->n >= RVT_SEGSZ) {
- if (++sge->m >= sge->mr->mapsz)
- break;
- sge->n = 0;
- }
- sge->vaddr =
- sge->mr->map[sge->m]->segs[sge->n].vaddr;
- sge->length =
- sge->mr->map[sge->m]->segs[sge->n].length;
- }
- sqp->s_len -= len;
- }
- if (release)
- rvt_put_ss(&qp->r_sge);
-
- if (!test_and_clear_bit(RVT_R_WRID_VALID, &qp->r_aflags))
- goto send_comp;
-
- if (wqe->wr.opcode == IB_WR_RDMA_WRITE_WITH_IMM)
- wc.opcode = IB_WC_RECV_RDMA_WITH_IMM;
- else
- wc.opcode = IB_WC_RECV;
- wc.wr_id = qp->r_wr_id;
- wc.status = IB_WC_SUCCESS;
- wc.byte_len = wqe->length;
- wc.qp = &qp->ibqp;
- wc.src_qp = qp->remote_qpn;
- wc.slid = rdma_ah_get_dlid(&qp->remote_ah_attr);
- wc.sl = rdma_ah_get_sl(&qp->remote_ah_attr);
- wc.port_num = 1;
- /* Signal completion event if the solicited bit is set. */
- rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.recv_cq), &wc,
- wqe->wr.send_flags & IB_SEND_SOLICITED);
-
-send_comp:
- spin_lock_irqsave(&sqp->s_lock, flags);
- ibp->rvp.n_loop_pkts++;
-flush_send:
- sqp->s_rnr_retry = sqp->s_rnr_retry_cnt;
- qib_send_complete(sqp, wqe, send_status);
- goto again;
-
-rnr_nak:
- /* Handle RNR NAK */
- if (qp->ibqp.qp_type == IB_QPT_UC)
- goto send_comp;
- ibp->rvp.n_rnr_naks++;
- /*
- * Note: we don't need the s_lock held since the BUSY flag
- * makes this single threaded.
- */
- if (sqp->s_rnr_retry == 0) {
- send_status = IB_WC_RNR_RETRY_EXC_ERR;
- goto serr;
- }
- if (sqp->s_rnr_retry_cnt < 7)
- sqp->s_rnr_retry--;
- spin_lock_irqsave(&sqp->s_lock, flags);
- if (!(ib_rvt_state_ops[sqp->state] & RVT_PROCESS_RECV_OK))
- goto clr_busy;
- rvt_add_rnr_timer(sqp, qp->r_min_rnr_timer <<
- IB_AETH_CREDIT_SHIFT);
- goto clr_busy;
-
-op_err:
- send_status = IB_WC_REM_OP_ERR;
- wc.status = IB_WC_LOC_QP_OP_ERR;
- goto err;
-
-inv_err:
- send_status = IB_WC_REM_INV_REQ_ERR;
- wc.status = IB_WC_LOC_QP_OP_ERR;
- goto err;
-
-acc_err:
- send_status = IB_WC_REM_ACCESS_ERR;
- wc.status = IB_WC_LOC_PROT_ERR;
-err:
- /* responder goes to error state */
- rvt_rc_error(qp, wc.status);
-
-serr:
- spin_lock_irqsave(&sqp->s_lock, flags);
- qib_send_complete(sqp, wqe, send_status);
- if (sqp->ibqp.qp_type == IB_QPT_RC) {
- int lastwqe = rvt_error_qp(sqp, IB_WC_WR_FLUSH_ERR);
-
- sqp->s_flags &= ~RVT_S_BUSY;
- spin_unlock_irqrestore(&sqp->s_lock, flags);
- if (lastwqe) {
- struct ib_event ev;
-
- ev.device = sqp->ibqp.device;
- ev.element.qp = &sqp->ibqp;
- ev.event = IB_EVENT_QP_LAST_WQE_REACHED;
- sqp->ibqp.event_handler(&ev, sqp->ibqp.qp_context);
- }
- goto done;
- }
-clr_busy:
- sqp->s_flags &= ~RVT_S_BUSY;
-unlock:
- spin_unlock_irqrestore(&sqp->s_lock, flags);
-done:
- rcu_read_unlock();
-}
-
-/**
* qib_make_grh - construct a GRH header
* @ibp: a pointer to the IB port
* @hdr: a pointer to the GRH header being constructed
@@ -573,7 +272,7 @@ void qib_do_send(struct rvt_qp *qp)
qp->ibqp.qp_type == IB_QPT_UC) &&
(rdma_ah_get_dlid(&qp->remote_ah_attr) &
~((1 << ppd->lmc) - 1)) == ppd->lid) {
- qib_ruc_loopback(qp);
+ rvt_ruc_loopback(qp);
return;
}
@@ -613,42 +312,3 @@ void qib_do_send(struct rvt_qp *qp)
spin_unlock_irqrestore(&qp->s_lock, flags);
}
-
-/*
- * This should be called with s_lock held.
- */
-void qib_send_complete(struct rvt_qp *qp, struct rvt_swqe *wqe,
- enum ib_wc_status status)
-{
- u32 old_last, last;
-
- if (!(ib_rvt_state_ops[qp->state] & RVT_PROCESS_OR_FLUSH_SEND))
- return;
-
- last = qp->s_last;
- old_last = last;
- if (++last >= qp->s_size)
- last = 0;
- qp->s_last = last;
- /* See post_send() */
- barrier();
- rvt_put_swqe(wqe);
- if (qp->ibqp.qp_type == IB_QPT_UD ||
- qp->ibqp.qp_type == IB_QPT_SMI ||
- qp->ibqp.qp_type == IB_QPT_GSI)
- atomic_dec(&ibah_to_rvtah(wqe->ud_wr.ah)->refcount);
-
- rvt_qp_swqe_complete(qp,
- wqe,
- ib_qib_wc_opcode[wqe->wr.opcode],
- status);
-
- if (qp->s_acked == old_last)
- qp->s_acked = last;
- if (qp->s_cur == old_last)
- qp->s_cur = last;
- if (qp->s_tail == old_last)
- qp->s_tail = last;
- if (qp->state == IB_QPS_SQD && last == qp->s_cur)
- qp->s_draining = 0;
-}
diff --git a/drivers/infiniband/hw/qib/qib_sdma.c b/drivers/infiniband/hw/qib/qib_sdma.c
index d0723d4aef5c..757d4c9d713d 100644
--- a/drivers/infiniband/hw/qib/qib_sdma.c
+++ b/drivers/infiniband/hw/qib/qib_sdma.c
@@ -651,7 +651,7 @@ unmap:
if (ib_rvt_state_ops[qp->state] & RVT_PROCESS_RECV_OK)
rvt_error_qp(qp, IB_WC_GENERAL_ERR);
} else if (qp->s_wqe)
- qib_send_complete(qp, qp->s_wqe, IB_WC_GENERAL_ERR);
+ rvt_send_complete(qp, qp->s_wqe, IB_WC_GENERAL_ERR);
spin_unlock(&qp->s_lock);
spin_unlock(&qp->r_lock);
/* return zero to process the next send work request */
diff --git a/drivers/infiniband/hw/qib/qib_sysfs.c b/drivers/infiniband/hw/qib/qib_sysfs.c
index ca2638d8f35e..1cf4ca3f23e3 100644
--- a/drivers/infiniband/hw/qib/qib_sysfs.c
+++ b/drivers/infiniband/hw/qib/qib_sysfs.c
@@ -551,17 +551,18 @@ static struct kobj_type qib_diagc_ktype = {
* Start of per-unit (or driver, in some cases, but replicated
* per unit) functions (these get a device *)
*/
-static ssize_t show_rev(struct device *device, struct device_attribute *attr,
- char *buf)
+static ssize_t hw_rev_show(struct device *device, struct device_attribute *attr,
+ char *buf)
{
struct qib_ibdev *dev =
container_of(device, struct qib_ibdev, rdi.ibdev.dev);
return sprintf(buf, "%x\n", dd_from_dev(dev)->minrev);
}
+static DEVICE_ATTR_RO(hw_rev);
-static ssize_t show_hca(struct device *device, struct device_attribute *attr,
- char *buf)
+static ssize_t hca_type_show(struct device *device,
+ struct device_attribute *attr, char *buf)
{
struct qib_ibdev *dev =
container_of(device, struct qib_ibdev, rdi.ibdev.dev);
@@ -574,15 +575,18 @@ static ssize_t show_hca(struct device *device, struct device_attribute *attr,
ret = scnprintf(buf, PAGE_SIZE, "%s\n", dd->boardname);
return ret;
}
+static DEVICE_ATTR_RO(hca_type);
+static DEVICE_ATTR(board_id, 0444, hca_type_show, NULL);
-static ssize_t show_version(struct device *device,
+static ssize_t version_show(struct device *device,
struct device_attribute *attr, char *buf)
{
/* The string printed here is already newline-terminated. */
return scnprintf(buf, PAGE_SIZE, "%s", (char *)ib_qib_version);
}
+static DEVICE_ATTR_RO(version);
-static ssize_t show_boardversion(struct device *device,
+static ssize_t boardversion_show(struct device *device,
struct device_attribute *attr, char *buf)
{
struct qib_ibdev *dev =
@@ -592,9 +596,9 @@ static ssize_t show_boardversion(struct device *device,
/* The string printed here is already newline-terminated. */
return scnprintf(buf, PAGE_SIZE, "%s", dd->boardversion);
}
+static DEVICE_ATTR_RO(boardversion);
-
-static ssize_t show_localbus_info(struct device *device,
+static ssize_t localbus_info_show(struct device *device,
struct device_attribute *attr, char *buf)
{
struct qib_ibdev *dev =
@@ -604,9 +608,9 @@ static ssize_t show_localbus_info(struct device *device,
/* The string printed here is already newline-terminated. */
return scnprintf(buf, PAGE_SIZE, "%s", dd->lbus_info);
}
+static DEVICE_ATTR_RO(localbus_info);
-
-static ssize_t show_nctxts(struct device *device,
+static ssize_t nctxts_show(struct device *device,
struct device_attribute *attr, char *buf)
{
struct qib_ibdev *dev =
@@ -620,9 +624,10 @@ static ssize_t show_nctxts(struct device *device,
(dd->first_user_ctxt > dd->cfgctxts) ? 0 :
(dd->cfgctxts - dd->first_user_ctxt));
}
+static DEVICE_ATTR_RO(nctxts);
-static ssize_t show_nfreectxts(struct device *device,
- struct device_attribute *attr, char *buf)
+static ssize_t nfreectxts_show(struct device *device,
+ struct device_attribute *attr, char *buf)
{
struct qib_ibdev *dev =
container_of(device, struct qib_ibdev, rdi.ibdev.dev);
@@ -631,8 +636,9 @@ static ssize_t show_nfreectxts(struct device *device,
/* Return the number of free user ports (contexts) available. */
return scnprintf(buf, PAGE_SIZE, "%u\n", dd->freectxts);
}
+static DEVICE_ATTR_RO(nfreectxts);
-static ssize_t show_serial(struct device *device,
+static ssize_t serial_show(struct device *device,
struct device_attribute *attr, char *buf)
{
struct qib_ibdev *dev =
@@ -644,8 +650,9 @@ static ssize_t show_serial(struct device *device,
strcat(buf, "\n");
return strlen(buf);
}
+static DEVICE_ATTR_RO(serial);
-static ssize_t store_chip_reset(struct device *device,
+static ssize_t chip_reset_store(struct device *device,
struct device_attribute *attr, const char *buf,
size_t count)
{
@@ -663,11 +670,12 @@ static ssize_t store_chip_reset(struct device *device,
bail:
return ret < 0 ? ret : count;
}
+static DEVICE_ATTR_WO(chip_reset);
/*
* Dump tempsense regs. in decimal, to ease shell-scripts.
*/
-static ssize_t show_tempsense(struct device *device,
+static ssize_t tempsense_show(struct device *device,
struct device_attribute *attr, char *buf)
{
struct qib_ibdev *dev =
@@ -695,6 +703,7 @@ static ssize_t show_tempsense(struct device *device,
*(signed char *)(regvals + 7));
return ret;
}
+static DEVICE_ATTR_RO(tempsense);
/*
* end of per-unit (or driver, in some cases, but replicated
@@ -702,30 +711,23 @@ static ssize_t show_tempsense(struct device *device,
*/
/* start of per-unit file structures and support code */
-static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL);
-static DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL);
-static DEVICE_ATTR(board_id, S_IRUGO, show_hca, NULL);
-static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
-static DEVICE_ATTR(nctxts, S_IRUGO, show_nctxts, NULL);
-static DEVICE_ATTR(nfreectxts, S_IRUGO, show_nfreectxts, NULL);
-static DEVICE_ATTR(serial, S_IRUGO, show_serial, NULL);
-static DEVICE_ATTR(boardversion, S_IRUGO, show_boardversion, NULL);
-static DEVICE_ATTR(tempsense, S_IRUGO, show_tempsense, NULL);
-static DEVICE_ATTR(localbus_info, S_IRUGO, show_localbus_info, NULL);
-static DEVICE_ATTR(chip_reset, S_IWUSR, NULL, store_chip_reset);
-
-static struct device_attribute *qib_attributes[] = {
- &dev_attr_hw_rev,
- &dev_attr_hca_type,
- &dev_attr_board_id,
- &dev_attr_version,
- &dev_attr_nctxts,
- &dev_attr_nfreectxts,
- &dev_attr_serial,
- &dev_attr_boardversion,
- &dev_attr_tempsense,
- &dev_attr_localbus_info,
- &dev_attr_chip_reset,
+static struct attribute *qib_attributes[] = {
+ &dev_attr_hw_rev.attr,
+ &dev_attr_hca_type.attr,
+ &dev_attr_board_id.attr,
+ &dev_attr_version.attr,
+ &dev_attr_nctxts.attr,
+ &dev_attr_nfreectxts.attr,
+ &dev_attr_serial.attr,
+ &dev_attr_boardversion.attr,
+ &dev_attr_tempsense.attr,
+ &dev_attr_localbus_info.attr,
+ &dev_attr_chip_reset.attr,
+ NULL,
+};
+
+const struct attribute_group qib_attr_group = {
+ .attrs = qib_attributes,
};
int qib_create_port_files(struct ib_device *ibdev, u8 port_num,
@@ -827,27 +829,6 @@ bail:
}
/*
- * Register and create our files in /sys/class/infiniband.
- */
-int qib_verbs_register_sysfs(struct qib_devdata *dd)
-{
- struct ib_device *dev = &dd->verbs_dev.rdi.ibdev;
- int i, ret;
-
- for (i = 0; i < ARRAY_SIZE(qib_attributes); ++i) {
- ret = device_create_file(&dev->dev, qib_attributes[i]);
- if (ret)
- goto bail;
- }
-
- return 0;
-bail:
- for (i = 0; i < ARRAY_SIZE(qib_attributes); ++i)
- device_remove_file(&dev->dev, qib_attributes[i]);
- return ret;
-}
-
-/*
* Unregister and remove our files in /sys/class/infiniband.
*/
void qib_verbs_unregister_sysfs(struct qib_devdata *dd)
diff --git a/drivers/infiniband/hw/qib/qib_uc.c b/drivers/infiniband/hw/qib/qib_uc.c
index 3e54bc11e0ae..30c70ad0f4bf 100644
--- a/drivers/infiniband/hw/qib/qib_uc.c
+++ b/drivers/infiniband/hw/qib/qib_uc.c
@@ -68,7 +68,7 @@ int qib_make_uc_req(struct rvt_qp *qp, unsigned long *flags)
goto bail;
}
wqe = rvt_get_swqe_ptr(qp, qp->s_last);
- qib_send_complete(qp, wqe, IB_WC_WR_FLUSH_ERR);
+ rvt_send_complete(qp, wqe, IB_WC_WR_FLUSH_ERR);
goto done;
}
@@ -359,7 +359,7 @@ send_first:
qp->r_rcv_len += pmtu;
if (unlikely(qp->r_rcv_len > qp->r_len))
goto rewind;
- qib_copy_sge(&qp->r_sge, data, pmtu, 0);
+ rvt_copy_sge(qp, &qp->r_sge, data, pmtu, false, false);
break;
case OP(SEND_LAST_WITH_IMMEDIATE):
@@ -385,7 +385,7 @@ send_last:
if (unlikely(wc.byte_len > qp->r_len))
goto rewind;
wc.opcode = IB_WC_RECV;
- qib_copy_sge(&qp->r_sge, data, tlen, 0);
+ rvt_copy_sge(qp, &qp->r_sge, data, tlen, false, false);
rvt_put_ss(&qp->s_rdma_read_sge);
last_imm:
wc.wr_id = qp->r_wr_id;
@@ -449,7 +449,7 @@ rdma_first:
qp->r_rcv_len += pmtu;
if (unlikely(qp->r_rcv_len > qp->r_len))
goto drop;
- qib_copy_sge(&qp->r_sge, data, pmtu, 1);
+ rvt_copy_sge(qp, &qp->r_sge, data, pmtu, true, false);
break;
case OP(RDMA_WRITE_LAST_WITH_IMMEDIATE):
@@ -479,7 +479,7 @@ rdma_last_imm:
}
wc.byte_len = qp->r_len;
wc.opcode = IB_WC_RECV_RDMA_WITH_IMM;
- qib_copy_sge(&qp->r_sge, data, tlen, 1);
+ rvt_copy_sge(qp, &qp->r_sge, data, tlen, true, false);
rvt_put_ss(&qp->r_sge);
goto last_imm;
@@ -495,7 +495,7 @@ rdma_last:
tlen -= (hdrsize + pad + 4);
if (unlikely(tlen + qp->r_rcv_len != qp->r_len))
goto drop;
- qib_copy_sge(&qp->r_sge, data, tlen, 1);
+ rvt_copy_sge(qp, &qp->r_sge, data, tlen, true, false);
rvt_put_ss(&qp->r_sge);
break;
diff --git a/drivers/infiniband/hw/qib/qib_ud.c b/drivers/infiniband/hw/qib/qib_ud.c
index f8d029a2390f..4d4c31ea4e2d 100644
--- a/drivers/infiniband/hw/qib/qib_ud.c
+++ b/drivers/infiniband/hw/qib/qib_ud.c
@@ -162,8 +162,8 @@ static void qib_ud_loopback(struct rvt_qp *sqp, struct rvt_swqe *swqe)
const struct ib_global_route *grd = rdma_ah_read_grh(ah_attr);
qib_make_grh(ibp, &grh, grd, 0, 0);
- qib_copy_sge(&qp->r_sge, &grh,
- sizeof(grh), 1);
+ rvt_copy_sge(qp, &qp->r_sge, &grh,
+ sizeof(grh), true, false);
wc.wc_flags |= IB_WC_GRH;
} else
rvt_skip_sge(&qp->r_sge, sizeof(struct ib_grh), true);
@@ -179,7 +179,7 @@ static void qib_ud_loopback(struct rvt_qp *sqp, struct rvt_swqe *swqe)
if (len > sge->sge_length)
len = sge->sge_length;
BUG_ON(len == 0);
- qib_copy_sge(&qp->r_sge, sge->vaddr, len, 1);
+ rvt_copy_sge(qp, &qp->r_sge, sge->vaddr, len, true, false);
sge->vaddr += len;
sge->length -= len;
sge->sge_length -= len;
@@ -260,7 +260,7 @@ int qib_make_ud_req(struct rvt_qp *qp, unsigned long *flags)
goto bail;
}
wqe = rvt_get_swqe_ptr(qp, qp->s_last);
- qib_send_complete(qp, wqe, IB_WC_WR_FLUSH_ERR);
+ rvt_send_complete(qp, wqe, IB_WC_WR_FLUSH_ERR);
goto done;
}
@@ -304,7 +304,7 @@ int qib_make_ud_req(struct rvt_qp *qp, unsigned long *flags)
qib_ud_loopback(qp, wqe);
spin_lock_irqsave(&qp->s_lock, tflags);
*flags = tflags;
- qib_send_complete(qp, wqe, IB_WC_SUCCESS);
+ rvt_send_complete(qp, wqe, IB_WC_SUCCESS);
goto done;
}
}
@@ -551,12 +551,13 @@ void qib_ud_rcv(struct qib_ibport *ibp, struct ib_header *hdr,
goto drop;
}
if (has_grh) {
- qib_copy_sge(&qp->r_sge, &hdr->u.l.grh,
- sizeof(struct ib_grh), 1);
+ rvt_copy_sge(qp, &qp->r_sge, &hdr->u.l.grh,
+ sizeof(struct ib_grh), true, false);
wc.wc_flags |= IB_WC_GRH;
} else
rvt_skip_sge(&qp->r_sge, sizeof(struct ib_grh), true);
- qib_copy_sge(&qp->r_sge, data, wc.byte_len - sizeof(struct ib_grh), 1);
+ rvt_copy_sge(qp, &qp->r_sge, data, wc.byte_len - sizeof(struct ib_grh),
+ true, false);
rvt_put_ss(&qp->r_sge);
if (!test_and_clear_bit(RVT_R_WRID_VALID, &qp->r_aflags))
return;
diff --git a/drivers/infiniband/hw/qib/qib_verbs.c b/drivers/infiniband/hw/qib/qib_verbs.c
index 41babbc0db58..4b0f5761a646 100644
--- a/drivers/infiniband/hw/qib/qib_verbs.c
+++ b/drivers/infiniband/hw/qib/qib_verbs.c
@@ -131,27 +131,6 @@ const enum ib_wc_opcode ib_qib_wc_opcode[] = {
*/
__be64 ib_qib_sys_image_guid;
-/**
- * qib_copy_sge - copy data to SGE memory
- * @ss: the SGE state
- * @data: the data to copy
- * @length: the length of the data
- */
-void qib_copy_sge(struct rvt_sge_state *ss, void *data, u32 length, int release)
-{
- struct rvt_sge *sge = &ss->sge;
-
- while (length) {
- u32 len = rvt_get_sge_length(sge, length);
-
- WARN_ON_ONCE(len == 0);
- memcpy(sge->vaddr, data, len);
- rvt_update_sge(ss, len, release);
- data += len;
- length -= len;
- }
-}
-
/*
* Count the number of DMA descriptors needed to send length bytes of data.
* Don't modify the qib_sge_state to get the count.
@@ -752,7 +731,7 @@ static void sdma_complete(struct qib_sdma_txreq *cookie, int status)
spin_lock(&qp->s_lock);
if (tx->wqe)
- qib_send_complete(qp, tx->wqe, IB_WC_SUCCESS);
+ rvt_send_complete(qp, tx->wqe, IB_WC_SUCCESS);
else if (qp->ibqp.qp_type == IB_QPT_RC) {
struct ib_header *hdr;
@@ -1025,7 +1004,7 @@ done:
}
if (qp->s_wqe) {
spin_lock_irqsave(&qp->s_lock, flags);
- qib_send_complete(qp, qp->s_wqe, IB_WC_SUCCESS);
+ rvt_send_complete(qp, qp->s_wqe, IB_WC_SUCCESS);
spin_unlock_irqrestore(&qp->s_lock, flags);
} else if (qp->ibqp.qp_type == IB_QPT_RC) {
spin_lock_irqsave(&qp->s_lock, flags);
@@ -1512,6 +1491,9 @@ static void qib_fill_device_attr(struct qib_devdata *dd)
rdi->dparms.props.max_mcast_grp;
/* post send table */
dd->verbs_dev.rdi.post_parms = qib_post_parms;
+
+ /* opcode translation table */
+ dd->verbs_dev.rdi.wc_opcode = ib_qib_wc_opcode;
}
/**
@@ -1588,7 +1570,7 @@ int qib_register_ib_device(struct qib_devdata *dd)
dd->verbs_dev.rdi.driver_f.port_callback = qib_create_port_files;
dd->verbs_dev.rdi.driver_f.get_pci_dev = qib_get_pci_dev;
dd->verbs_dev.rdi.driver_f.check_ah = qib_check_ah;
- dd->verbs_dev.rdi.driver_f.check_send_wqe = qib_check_send_wqe;
+ dd->verbs_dev.rdi.driver_f.setup_wqe = qib_check_send_wqe;
dd->verbs_dev.rdi.driver_f.notify_new_ah = qib_notify_new_ah;
dd->verbs_dev.rdi.driver_f.alloc_qpn = qib_alloc_qpn;
dd->verbs_dev.rdi.driver_f.qp_priv_alloc = qib_qp_priv_alloc;
@@ -1631,6 +1613,7 @@ int qib_register_ib_device(struct qib_devdata *dd)
dd->verbs_dev.rdi.dparms.node = dd->assigned_node_id;
dd->verbs_dev.rdi.dparms.core_cap_flags = RDMA_CORE_PORT_IBA_IB;
dd->verbs_dev.rdi.dparms.max_mad_size = IB_MGMT_MAD_SIZE;
+ dd->verbs_dev.rdi.dparms.sge_copy_mode = RVT_SGE_COPY_MEMCPY;
qib_fill_device_attr(dd);
@@ -1642,19 +1625,14 @@ 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);
ret = rvt_register_device(&dd->verbs_dev.rdi, RDMA_DRIVER_QIB);
if (ret)
goto err_tx;
- ret = qib_verbs_register_sysfs(dd);
- if (ret)
- goto err_class;
-
return ret;
-err_class:
- rvt_unregister_device(&dd->verbs_dev.rdi);
err_tx:
while (!list_empty(&dev->txreq_free)) {
struct list_head *l = dev->txreq_free.next;
@@ -1716,14 +1694,14 @@ void qib_unregister_ib_device(struct qib_devdata *dd)
* It is only used in post send, which doesn't hold
* the s_lock.
*/
-void _qib_schedule_send(struct rvt_qp *qp)
+bool _qib_schedule_send(struct rvt_qp *qp)
{
struct qib_ibport *ibp =
to_iport(qp->ibqp.device, qp->port_num);
struct qib_pportdata *ppd = ppd_from_ibp(ibp);
struct qib_qp_priv *priv = qp->priv;
- queue_work(ppd->qib_wq, &priv->s_work);
+ return queue_work(ppd->qib_wq, &priv->s_work);
}
/**
@@ -1733,8 +1711,9 @@ void _qib_schedule_send(struct rvt_qp *qp)
* This schedules qp progress. The s_lock
* should be held.
*/
-void qib_schedule_send(struct rvt_qp *qp)
+bool qib_schedule_send(struct rvt_qp *qp)
{
if (qib_send_ok(qp))
- _qib_schedule_send(qp);
+ return _qib_schedule_send(qp);
+ return false;
}
diff --git a/drivers/infiniband/hw/qib/qib_verbs.h b/drivers/infiniband/hw/qib/qib_verbs.h
index 666613eef88f..a4426c24b0d1 100644
--- a/drivers/infiniband/hw/qib/qib_verbs.h
+++ b/drivers/infiniband/hw/qib/qib_verbs.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 - 2017 Intel Corporation. All rights reserved.
+ * Copyright (c) 2012 - 2018 Intel Corporation. All rights reserved.
* Copyright (c) 2006 - 2012 QLogic Corporation. All rights reserved.
* Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
*
@@ -223,8 +223,8 @@ static inline int qib_send_ok(struct rvt_qp *qp)
!(qp->s_flags & RVT_S_ANY_WAIT_SEND));
}
-void _qib_schedule_send(struct rvt_qp *qp);
-void qib_schedule_send(struct rvt_qp *qp);
+bool _qib_schedule_send(struct rvt_qp *qp);
+bool qib_schedule_send(struct rvt_qp *qp);
static inline int qib_pkey_ok(u16 pkey1, u16 pkey2)
{
@@ -292,9 +292,6 @@ void qib_put_txreq(struct qib_verbs_txreq *tx);
int qib_verbs_send(struct rvt_qp *qp, struct ib_header *hdr,
u32 hdrwords, struct rvt_sge_state *ss, u32 len);
-void qib_copy_sge(struct rvt_sge_state *ss, void *data, u32 length,
- int release);
-
void qib_uc_rcv(struct qib_ibport *ibp, struct ib_header *hdr,
int has_grh, void *data, u32 tlen, struct rvt_qp *qp);
@@ -303,7 +300,8 @@ void qib_rc_rcv(struct qib_ctxtdata *rcd, struct ib_header *hdr,
int qib_check_ah(struct ib_device *ibdev, struct rdma_ah_attr *ah_attr);
-int qib_check_send_wqe(struct rvt_qp *qp, struct rvt_swqe *wqe);
+int qib_check_send_wqe(struct rvt_qp *qp, struct rvt_swqe *wqe,
+ bool *call_send);
struct ib_ah *qib_create_qp0_ah(struct qib_ibport *ibp, u16 dlid);
@@ -333,9 +331,6 @@ void _qib_do_send(struct work_struct *work);
void qib_do_send(struct rvt_qp *qp);
-void qib_send_complete(struct rvt_qp *qp, struct rvt_swqe *wqe,
- enum ib_wc_status status);
-
void qib_send_rc_ack(struct rvt_qp *qp);
int qib_make_rc_req(struct rvt_qp *qp, unsigned long *flags);
diff --git a/drivers/infiniband/hw/usnic/usnic_debugfs.c b/drivers/infiniband/hw/usnic/usnic_debugfs.c
index 92dc66cc2d50..a3115709fb03 100644
--- a/drivers/infiniband/hw/usnic/usnic_debugfs.c
+++ b/drivers/infiniband/hw/usnic/usnic_debugfs.c
@@ -165,6 +165,5 @@ void usnic_debugfs_flow_add(struct usnic_ib_qp_grp_flow *qp_flow)
void usnic_debugfs_flow_remove(struct usnic_ib_qp_grp_flow *qp_flow)
{
- if (!IS_ERR_OR_NULL(qp_flow->dbgfs_dentry))
- debugfs_remove(qp_flow->dbgfs_dentry);
+ debugfs_remove(qp_flow->dbgfs_dentry);
}
diff --git a/drivers/infiniband/hw/usnic/usnic_ib_main.c b/drivers/infiniband/hw/usnic/usnic_ib_main.c
index f0538a460328..73bd00f8d2c8 100644
--- a/drivers/infiniband/hw/usnic/usnic_ib_main.c
+++ b/drivers/infiniband/hw/usnic/usnic_ib_main.c
@@ -76,7 +76,7 @@ static LIST_HEAD(usnic_ib_ibdev_list);
static int usnic_ib_dump_vf_hdr(void *obj, char *buf, int buf_sz)
{
struct usnic_ib_vf *vf = obj;
- return scnprintf(buf, buf_sz, "PF: %s ", vf->pf->ib_dev.name);
+ return scnprintf(buf, buf_sz, "PF: %s ", dev_name(&vf->pf->ib_dev.dev));
}
/* End callback dump funcs */
@@ -138,7 +138,7 @@ static void usnic_ib_handle_usdev_event(struct usnic_ib_dev *us_ibdev,
netdev = us_ibdev->netdev;
switch (event) {
case NETDEV_REBOOT:
- usnic_info("PF Reset on %s\n", us_ibdev->ib_dev.name);
+ usnic_info("PF Reset on %s\n", dev_name(&us_ibdev->ib_dev.dev));
usnic_ib_qp_grp_modify_active_to_err(us_ibdev);
ib_event.event = IB_EVENT_PORT_ERR;
ib_event.device = &us_ibdev->ib_dev;
@@ -151,7 +151,8 @@ static void usnic_ib_handle_usdev_event(struct usnic_ib_dev *us_ibdev,
if (!us_ibdev->ufdev->link_up &&
netif_carrier_ok(netdev)) {
usnic_fwd_carrier_up(us_ibdev->ufdev);
- usnic_info("Link UP on %s\n", us_ibdev->ib_dev.name);
+ usnic_info("Link UP on %s\n",
+ dev_name(&us_ibdev->ib_dev.dev));
ib_event.event = IB_EVENT_PORT_ACTIVE;
ib_event.device = &us_ibdev->ib_dev;
ib_event.element.port_num = 1;
@@ -159,7 +160,8 @@ static void usnic_ib_handle_usdev_event(struct usnic_ib_dev *us_ibdev,
} else if (us_ibdev->ufdev->link_up &&
!netif_carrier_ok(netdev)) {
usnic_fwd_carrier_down(us_ibdev->ufdev);
- usnic_info("Link DOWN on %s\n", us_ibdev->ib_dev.name);
+ usnic_info("Link DOWN on %s\n",
+ dev_name(&us_ibdev->ib_dev.dev));
usnic_ib_qp_grp_modify_active_to_err(us_ibdev);
ib_event.event = IB_EVENT_PORT_ERR;
ib_event.device = &us_ibdev->ib_dev;
@@ -168,17 +170,17 @@ static void usnic_ib_handle_usdev_event(struct usnic_ib_dev *us_ibdev,
} else {
usnic_dbg("Ignoring %s on %s\n",
netdev_cmd_to_name(event),
- us_ibdev->ib_dev.name);
+ dev_name(&us_ibdev->ib_dev.dev));
}
break;
case NETDEV_CHANGEADDR:
if (!memcmp(us_ibdev->ufdev->mac, netdev->dev_addr,
sizeof(us_ibdev->ufdev->mac))) {
usnic_dbg("Ignoring addr change on %s\n",
- us_ibdev->ib_dev.name);
+ dev_name(&us_ibdev->ib_dev.dev));
} else {
usnic_info(" %s old mac: %pM new mac: %pM\n",
- us_ibdev->ib_dev.name,
+ dev_name(&us_ibdev->ib_dev.dev),
us_ibdev->ufdev->mac,
netdev->dev_addr);
usnic_fwd_set_mac(us_ibdev->ufdev, netdev->dev_addr);
@@ -193,19 +195,19 @@ static void usnic_ib_handle_usdev_event(struct usnic_ib_dev *us_ibdev,
case NETDEV_CHANGEMTU:
if (us_ibdev->ufdev->mtu != netdev->mtu) {
usnic_info("MTU Change on %s old: %u new: %u\n",
- us_ibdev->ib_dev.name,
+ dev_name(&us_ibdev->ib_dev.dev),
us_ibdev->ufdev->mtu, netdev->mtu);
usnic_fwd_set_mtu(us_ibdev->ufdev, netdev->mtu);
usnic_ib_qp_grp_modify_active_to_err(us_ibdev);
} else {
usnic_dbg("Ignoring MTU change on %s\n",
- us_ibdev->ib_dev.name);
+ dev_name(&us_ibdev->ib_dev.dev));
}
break;
default:
usnic_dbg("Ignoring event %s on %s",
netdev_cmd_to_name(event),
- us_ibdev->ib_dev.name);
+ dev_name(&us_ibdev->ib_dev.dev));
}
mutex_unlock(&us_ibdev->usdev_lock);
}
@@ -267,7 +269,7 @@ static int usnic_ib_handle_inet_event(struct usnic_ib_dev *us_ibdev,
default:
usnic_info("Ignoring event %s on %s",
netdev_cmd_to_name(event),
- us_ibdev->ib_dev.name);
+ dev_name(&us_ibdev->ib_dev.dev));
}
mutex_unlock(&us_ibdev->usdev_lock);
@@ -364,7 +366,6 @@ static void *usnic_ib_device_add(struct pci_dev *dev)
us_ibdev->ib_dev.num_comp_vectors = USNIC_IB_NUM_COMP_VECTORS;
us_ibdev->ib_dev.dev.parent = &dev->dev;
us_ibdev->ib_dev.uverbs_abi_ver = USNIC_UVERBS_ABI_VERSION;
- strlcpy(us_ibdev->ib_dev.name, "usnic_%d", IB_DEVICE_NAME_MAX);
us_ibdev->ib_dev.uverbs_cmd_mask =
(1ull << IB_USER_VERBS_CMD_GET_CONTEXT) |
@@ -416,7 +417,9 @@ static void *usnic_ib_device_add(struct pci_dev *dev)
us_ibdev->ib_dev.driver_id = RDMA_DRIVER_USNIC;
- if (ib_register_device(&us_ibdev->ib_dev, NULL))
+ rdma_set_device_sysfs_group(&us_ibdev->ib_dev, &usnic_attr_group);
+
+ if (ib_register_device(&us_ibdev->ib_dev, "usnic_%d", NULL))
goto err_fwd_dealloc;
usnic_fwd_set_mtu(us_ibdev->ufdev, us_ibdev->netdev->mtu);
@@ -437,9 +440,9 @@ static void *usnic_ib_device_add(struct pci_dev *dev)
kref_init(&us_ibdev->vf_cnt);
usnic_info("Added ibdev: %s netdev: %s with mac %pM Link: %u MTU: %u\n",
- us_ibdev->ib_dev.name, netdev_name(us_ibdev->netdev),
- us_ibdev->ufdev->mac, us_ibdev->ufdev->link_up,
- us_ibdev->ufdev->mtu);
+ dev_name(&us_ibdev->ib_dev.dev),
+ netdev_name(us_ibdev->netdev), us_ibdev->ufdev->mac,
+ us_ibdev->ufdev->link_up, us_ibdev->ufdev->mtu);
return us_ibdev;
err_fwd_dealloc:
@@ -452,7 +455,7 @@ err_dealloc:
static void usnic_ib_device_remove(struct usnic_ib_dev *us_ibdev)
{
- usnic_info("Unregistering %s\n", us_ibdev->ib_dev.name);
+ usnic_info("Unregistering %s\n", dev_name(&us_ibdev->ib_dev.dev));
usnic_ib_sysfs_unregister_usdev(us_ibdev);
usnic_fwd_dev_free(us_ibdev->ufdev);
ib_unregister_device(&us_ibdev->ib_dev);
@@ -591,7 +594,7 @@ static int usnic_ib_pci_probe(struct pci_dev *pdev,
mutex_unlock(&pf->usdev_lock);
usnic_info("Registering usnic VF %s into PF %s\n", pci_name(pdev),
- pf->ib_dev.name);
+ dev_name(&pf->ib_dev.dev));
usnic_ib_log_vf(vf);
return 0;
diff --git a/drivers/infiniband/hw/usnic/usnic_ib_sysfs.c b/drivers/infiniband/hw/usnic/usnic_ib_sysfs.c
index 4210ca14014d..a7e4b2ccfaf8 100644
--- a/drivers/infiniband/hw/usnic/usnic_ib_sysfs.c
+++ b/drivers/infiniband/hw/usnic/usnic_ib_sysfs.c
@@ -46,9 +46,8 @@
#include "usnic_ib_sysfs.h"
#include "usnic_log.h"
-static ssize_t usnic_ib_show_board(struct device *device,
- struct device_attribute *attr,
- char *buf)
+static ssize_t board_id_show(struct device *device,
+ struct device_attribute *attr, char *buf)
{
struct usnic_ib_dev *us_ibdev =
container_of(device, struct usnic_ib_dev, ib_dev.dev);
@@ -60,13 +59,13 @@ static ssize_t usnic_ib_show_board(struct device *device,
return scnprintf(buf, PAGE_SIZE, "%hu\n", subsystem_device_id);
}
+static DEVICE_ATTR_RO(board_id);
/*
* Report the configuration for this PF
*/
static ssize_t
-usnic_ib_show_config(struct device *device, struct device_attribute *attr,
- char *buf)
+config_show(struct device *device, struct device_attribute *attr, char *buf)
{
struct usnic_ib_dev *us_ibdev;
char *ptr;
@@ -94,7 +93,7 @@ usnic_ib_show_config(struct device *device, struct device_attribute *attr,
n = scnprintf(ptr, left,
"%s: %s:%d.%d, %s, %pM, %u VFs\n Per VF:",
- us_ibdev->ib_dev.name,
+ dev_name(&us_ibdev->ib_dev.dev),
busname,
PCI_SLOT(us_ibdev->pdev->devfn),
PCI_FUNC(us_ibdev->pdev->devfn),
@@ -119,17 +118,17 @@ usnic_ib_show_config(struct device *device, struct device_attribute *attr,
UPDATE_PTR_LEFT(n, ptr, left);
} else {
n = scnprintf(ptr, left, "%s: no VFs\n",
- us_ibdev->ib_dev.name);
+ dev_name(&us_ibdev->ib_dev.dev));
UPDATE_PTR_LEFT(n, ptr, left);
}
mutex_unlock(&us_ibdev->usdev_lock);
return ptr - buf;
}
+static DEVICE_ATTR_RO(config);
static ssize_t
-usnic_ib_show_iface(struct device *device, struct device_attribute *attr,
- char *buf)
+iface_show(struct device *device, struct device_attribute *attr, char *buf)
{
struct usnic_ib_dev *us_ibdev;
@@ -138,10 +137,10 @@ usnic_ib_show_iface(struct device *device, struct device_attribute *attr,
return scnprintf(buf, PAGE_SIZE, "%s\n",
netdev_name(us_ibdev->netdev));
}
+static DEVICE_ATTR_RO(iface);
static ssize_t
-usnic_ib_show_max_vf(struct device *device, struct device_attribute *attr,
- char *buf)
+max_vf_show(struct device *device, struct device_attribute *attr, char *buf)
{
struct usnic_ib_dev *us_ibdev;
@@ -150,10 +149,10 @@ usnic_ib_show_max_vf(struct device *device, struct device_attribute *attr,
return scnprintf(buf, PAGE_SIZE, "%u\n",
kref_read(&us_ibdev->vf_cnt));
}
+static DEVICE_ATTR_RO(max_vf);
static ssize_t
-usnic_ib_show_qp_per_vf(struct device *device, struct device_attribute *attr,
- char *buf)
+qp_per_vf_show(struct device *device, struct device_attribute *attr, char *buf)
{
struct usnic_ib_dev *us_ibdev;
int qp_per_vf;
@@ -165,10 +164,10 @@ usnic_ib_show_qp_per_vf(struct device *device, struct device_attribute *attr,
return scnprintf(buf, PAGE_SIZE,
"%d\n", qp_per_vf);
}
+static DEVICE_ATTR_RO(qp_per_vf);
static ssize_t
-usnic_ib_show_cq_per_vf(struct device *device, struct device_attribute *attr,
- char *buf)
+cq_per_vf_show(struct device *device, struct device_attribute *attr, char *buf)
{
struct usnic_ib_dev *us_ibdev;
@@ -177,21 +176,20 @@ usnic_ib_show_cq_per_vf(struct device *device, struct device_attribute *attr,
return scnprintf(buf, PAGE_SIZE, "%d\n",
us_ibdev->vf_res_cnt[USNIC_VNIC_RES_TYPE_CQ]);
}
+static DEVICE_ATTR_RO(cq_per_vf);
+
+static struct attribute *usnic_class_attributes[] = {
+ &dev_attr_board_id.attr,
+ &dev_attr_config.attr,
+ &dev_attr_iface.attr,
+ &dev_attr_max_vf.attr,
+ &dev_attr_qp_per_vf.attr,
+ &dev_attr_cq_per_vf.attr,
+ NULL
+};
-static DEVICE_ATTR(board_id, S_IRUGO, usnic_ib_show_board, NULL);
-static DEVICE_ATTR(config, S_IRUGO, usnic_ib_show_config, NULL);
-static DEVICE_ATTR(iface, S_IRUGO, usnic_ib_show_iface, NULL);
-static DEVICE_ATTR(max_vf, S_IRUGO, usnic_ib_show_max_vf, NULL);
-static DEVICE_ATTR(qp_per_vf, S_IRUGO, usnic_ib_show_qp_per_vf, NULL);
-static DEVICE_ATTR(cq_per_vf, S_IRUGO, usnic_ib_show_cq_per_vf, NULL);
-
-static struct device_attribute *usnic_class_attributes[] = {
- &dev_attr_board_id,
- &dev_attr_config,
- &dev_attr_iface,
- &dev_attr_max_vf,
- &dev_attr_qp_per_vf,
- &dev_attr_cq_per_vf,
+const struct attribute_group usnic_attr_group = {
+ .attrs = usnic_class_attributes,
};
struct qpn_attribute {
@@ -278,18 +276,6 @@ static struct kobj_type usnic_ib_qpn_type = {
int usnic_ib_sysfs_register_usdev(struct usnic_ib_dev *us_ibdev)
{
- int i;
- int err;
- for (i = 0; i < ARRAY_SIZE(usnic_class_attributes); ++i) {
- err = device_create_file(&us_ibdev->ib_dev.dev,
- usnic_class_attributes[i]);
- if (err) {
- usnic_err("Failed to create device file %d for %s eith err %d",
- i, us_ibdev->ib_dev.name, err);
- return -EINVAL;
- }
- }
-
/* create kernel object for looking at individual QPs */
kobject_get(&us_ibdev->ib_dev.dev.kobj);
us_ibdev->qpn_kobj = kobject_create_and_add("qpn",
@@ -304,12 +290,6 @@ int usnic_ib_sysfs_register_usdev(struct usnic_ib_dev *us_ibdev)
void usnic_ib_sysfs_unregister_usdev(struct usnic_ib_dev *us_ibdev)
{
- int i;
- for (i = 0; i < ARRAY_SIZE(usnic_class_attributes); ++i) {
- device_remove_file(&us_ibdev->ib_dev.dev,
- usnic_class_attributes[i]);
- }
-
kobject_put(us_ibdev->qpn_kobj);
}
diff --git a/drivers/infiniband/hw/usnic/usnic_ib_sysfs.h b/drivers/infiniband/hw/usnic/usnic_ib_sysfs.h
index 3d98e16cfeaf..b1f064cec850 100644
--- a/drivers/infiniband/hw/usnic/usnic_ib_sysfs.h
+++ b/drivers/infiniband/hw/usnic/usnic_ib_sysfs.h
@@ -41,4 +41,6 @@ void usnic_ib_sysfs_unregister_usdev(struct usnic_ib_dev *us_ibdev);
void usnic_ib_sysfs_qpn_add(struct usnic_ib_qp_grp *qp_grp);
void usnic_ib_sysfs_qpn_remove(struct usnic_ib_qp_grp *qp_grp);
+extern const struct attribute_group usnic_attr_group;
+
#endif /* !USNIC_IB_SYSFS_H_ */
diff --git a/drivers/infiniband/hw/usnic/usnic_ib_verbs.c b/drivers/infiniband/hw/usnic/usnic_ib_verbs.c
index 9973ac893635..0b91ff36768a 100644
--- a/drivers/infiniband/hw/usnic/usnic_ib_verbs.c
+++ b/drivers/infiniband/hw/usnic/usnic_ib_verbs.c
@@ -159,7 +159,8 @@ static int usnic_ib_fill_create_qp_resp(struct usnic_ib_qp_grp *qp_grp,
err = ib_copy_to_udata(udata, &resp, sizeof(resp));
if (err) {
- usnic_err("Failed to copy udata for %s", us_ibdev->ib_dev.name);
+ usnic_err("Failed to copy udata for %s",
+ dev_name(&us_ibdev->ib_dev.dev));
return err;
}
@@ -197,7 +198,7 @@ find_free_vf_and_create_qp_grp(struct usnic_ib_dev *us_ibdev,
vnic = vf->vnic;
if (!usnic_vnic_check_room(vnic, res_spec)) {
usnic_dbg("Found used vnic %s from %s\n",
- us_ibdev->ib_dev.name,
+ dev_name(&us_ibdev->ib_dev.dev),
pci_name(usnic_vnic_get_pdev(
vnic)));
qp_grp = usnic_ib_qp_grp_create(us_ibdev->ufdev,
@@ -230,7 +231,8 @@ find_free_vf_and_create_qp_grp(struct usnic_ib_dev *us_ibdev,
spin_unlock(&vf->lock);
}
- usnic_info("No free qp grp found on %s\n", us_ibdev->ib_dev.name);
+ usnic_info("No free qp grp found on %s\n",
+ dev_name(&us_ibdev->ib_dev.dev));
return ERR_PTR(-ENOMEM);
qp_grp_check:
@@ -471,7 +473,7 @@ struct ib_pd *usnic_ib_alloc_pd(struct ib_device *ibdev,
}
usnic_info("domain 0x%p allocated for context 0x%p and device %s\n",
- pd, context, ibdev->name);
+ pd, context, dev_name(&ibdev->dev));
return &pd->ibpd;
}
@@ -508,20 +510,20 @@ struct ib_qp *usnic_ib_create_qp(struct ib_pd *pd,
err = ib_copy_from_udata(&cmd, udata, sizeof(cmd));
if (err) {
usnic_err("%s: cannot copy udata for create_qp\n",
- us_ibdev->ib_dev.name);
+ dev_name(&us_ibdev->ib_dev.dev));
return ERR_PTR(-EINVAL);
}
err = create_qp_validate_user_data(cmd);
if (err) {
usnic_err("%s: Failed to validate user data\n",
- us_ibdev->ib_dev.name);
+ dev_name(&us_ibdev->ib_dev.dev));
return ERR_PTR(-EINVAL);
}
if (init_attr->qp_type != IB_QPT_UD) {
usnic_err("%s asked to make a non-UD QP: %d\n",
- us_ibdev->ib_dev.name, init_attr->qp_type);
+ dev_name(&us_ibdev->ib_dev.dev), init_attr->qp_type);
return ERR_PTR(-EINVAL);
}
diff --git a/drivers/infiniband/hw/usnic/usnic_transport.c b/drivers/infiniband/hw/usnic/usnic_transport.c
index e0a95538c364..82dd810bc000 100644
--- a/drivers/infiniband/hw/usnic/usnic_transport.c
+++ b/drivers/infiniband/hw/usnic/usnic_transport.c
@@ -121,7 +121,7 @@ void usnic_transport_unrsrv_port(enum usnic_transport_type type, u16 port_num)
if (type == USNIC_TRANSPORT_ROCE_CUSTOM) {
spin_lock(&roce_bitmap_lock);
if (!port_num) {
- usnic_err("Unreserved unvalid port num 0 for %s\n",
+ usnic_err("Unreserved invalid port num 0 for %s\n",
usnic_transport_to_str(type));
goto out_roce_custom;
}
diff --git a/drivers/infiniband/hw/usnic/usnic_uiom.c b/drivers/infiniband/hw/usnic/usnic_uiom.c
index 9dd39daa602b..49275a548751 100644
--- a/drivers/infiniband/hw/usnic/usnic_uiom.c
+++ b/drivers/infiniband/hw/usnic/usnic_uiom.c
@@ -54,18 +54,6 @@ static struct workqueue_struct *usnic_uiom_wq;
((void *) &((struct usnic_uiom_chunk *) 0)->page_list[1] - \
(void *) &((struct usnic_uiom_chunk *) 0)->page_list[0]))
-static void usnic_uiom_reg_account(struct work_struct *work)
-{
- struct usnic_uiom_reg *umem = container_of(work,
- struct usnic_uiom_reg, work);
-
- down_write(&umem->mm->mmap_sem);
- umem->mm->locked_vm -= umem->diff;
- up_write(&umem->mm->mmap_sem);
- mmput(umem->mm);
- kfree(umem);
-}
-
static int usnic_uiom_dma_fault(struct iommu_domain *domain,
struct device *dev,
unsigned long iova, int flags,
@@ -99,8 +87,9 @@ static void usnic_uiom_put_pages(struct list_head *chunk_list, int dirty)
}
static int usnic_uiom_get_pages(unsigned long addr, size_t size, int writable,
- int dmasync, struct list_head *chunk_list)
+ int dmasync, struct usnic_uiom_reg *uiomr)
{
+ struct list_head *chunk_list = &uiomr->chunk_list;
struct page **page_list;
struct scatterlist *sg;
struct usnic_uiom_chunk *chunk;
@@ -114,6 +103,7 @@ static int usnic_uiom_get_pages(unsigned long addr, size_t size, int writable,
int flags;
dma_addr_t pa;
unsigned int gup_flags;
+ struct mm_struct *mm;
/*
* If the combination of the addr and size requested for this memory
@@ -136,7 +126,8 @@ static int usnic_uiom_get_pages(unsigned long addr, size_t size, int writable,
npages = PAGE_ALIGN(size + (addr & ~PAGE_MASK)) >> PAGE_SHIFT;
- down_write(&current->mm->mmap_sem);
+ uiomr->owning_mm = mm = current->mm;
+ down_write(&mm->mmap_sem);
locked = npages + current->mm->pinned_vm;
lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
@@ -196,10 +187,12 @@ static int usnic_uiom_get_pages(unsigned long addr, size_t size, int writable,
out:
if (ret < 0)
usnic_uiom_put_pages(chunk_list, 0);
- else
- current->mm->pinned_vm = locked;
+ else {
+ mm->pinned_vm = locked;
+ mmgrab(uiomr->owning_mm);
+ }
- up_write(&current->mm->mmap_sem);
+ up_write(&mm->mmap_sem);
free_page((unsigned long) page_list);
return ret;
}
@@ -379,7 +372,7 @@ struct usnic_uiom_reg *usnic_uiom_reg_get(struct usnic_uiom_pd *pd,
uiomr->pd = pd;
err = usnic_uiom_get_pages(addr, size, writable, dmasync,
- &uiomr->chunk_list);
+ uiomr);
if (err) {
usnic_err("Failed get_pages vpn [0x%lx,0x%lx] err %d\n",
vpn_start, vpn_last, err);
@@ -426,29 +419,39 @@ out_put_intervals:
out_put_pages:
usnic_uiom_put_pages(&uiomr->chunk_list, 0);
spin_unlock(&pd->lock);
+ mmdrop(uiomr->owning_mm);
out_free_uiomr:
kfree(uiomr);
return ERR_PTR(err);
}
-void usnic_uiom_reg_release(struct usnic_uiom_reg *uiomr,
- struct ib_ucontext *ucontext)
+static void __usnic_uiom_release_tail(struct usnic_uiom_reg *uiomr)
{
- struct task_struct *task;
- struct mm_struct *mm;
- unsigned long diff;
+ mmdrop(uiomr->owning_mm);
+ kfree(uiomr);
+}
- __usnic_uiom_reg_release(uiomr->pd, uiomr, 1);
+static inline size_t usnic_uiom_num_pages(struct usnic_uiom_reg *uiomr)
+{
+ return PAGE_ALIGN(uiomr->length + uiomr->offset) >> PAGE_SHIFT;
+}
- task = get_pid_task(ucontext->tgid, PIDTYPE_PID);
- if (!task)
- goto out;
- mm = get_task_mm(task);
- put_task_struct(task);
- if (!mm)
- goto out;
+static void usnic_uiom_release_defer(struct work_struct *work)
+{
+ struct usnic_uiom_reg *uiomr =
+ container_of(work, struct usnic_uiom_reg, work);
- diff = PAGE_ALIGN(uiomr->length + uiomr->offset) >> PAGE_SHIFT;
+ down_write(&uiomr->owning_mm->mmap_sem);
+ uiomr->owning_mm->pinned_vm -= usnic_uiom_num_pages(uiomr);
+ up_write(&uiomr->owning_mm->mmap_sem);
+
+ __usnic_uiom_release_tail(uiomr);
+}
+
+void usnic_uiom_reg_release(struct usnic_uiom_reg *uiomr,
+ struct ib_ucontext *context)
+{
+ __usnic_uiom_reg_release(uiomr->pd, uiomr, 1);
/*
* We may be called with the mm's mmap_sem already held. This
@@ -456,25 +459,21 @@ void usnic_uiom_reg_release(struct usnic_uiom_reg *uiomr,
* the last reference to our file and calls our release
* method. If there are memory regions to destroy, we'll end
* up here and not be able to take the mmap_sem. In that case
- * we defer the vm_locked accounting to the system workqueue.
+ * we defer the vm_locked accounting to a workqueue.
*/
- if (ucontext->closing) {
- if (!down_write_trylock(&mm->mmap_sem)) {
- INIT_WORK(&uiomr->work, usnic_uiom_reg_account);
- uiomr->mm = mm;
- uiomr->diff = diff;
-
+ if (context->closing) {
+ if (!down_write_trylock(&uiomr->owning_mm->mmap_sem)) {
+ INIT_WORK(&uiomr->work, usnic_uiom_release_defer);
queue_work(usnic_uiom_wq, &uiomr->work);
return;
}
- } else
- down_write(&mm->mmap_sem);
+ } else {
+ down_write(&uiomr->owning_mm->mmap_sem);
+ }
+ uiomr->owning_mm->pinned_vm -= usnic_uiom_num_pages(uiomr);
+ up_write(&uiomr->owning_mm->mmap_sem);
- mm->pinned_vm -= diff;
- up_write(&mm->mmap_sem);
- mmput(mm);
-out:
- kfree(uiomr);
+ __usnic_uiom_release_tail(uiomr);
}
struct usnic_uiom_pd *usnic_uiom_alloc_pd(void)
diff --git a/drivers/infiniband/hw/usnic/usnic_uiom.h b/drivers/infiniband/hw/usnic/usnic_uiom.h
index 8c096acff123..b86a9731071b 100644
--- a/drivers/infiniband/hw/usnic/usnic_uiom.h
+++ b/drivers/infiniband/hw/usnic/usnic_uiom.h
@@ -71,8 +71,7 @@ struct usnic_uiom_reg {
int writable;
struct list_head chunk_list;
struct work_struct work;
- struct mm_struct *mm;
- unsigned long diff;
+ struct mm_struct *owning_mm;
};
struct usnic_uiom_chunk {
diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c
index a5719899f49a..398443f43dc3 100644
--- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c
+++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c
@@ -65,32 +65,36 @@ static struct workqueue_struct *event_wq;
static int pvrdma_add_gid(const struct ib_gid_attr *attr, void **context);
static int pvrdma_del_gid(const struct ib_gid_attr *attr, void **context);
-static ssize_t show_hca(struct device *device, struct device_attribute *attr,
- char *buf)
+static ssize_t hca_type_show(struct device *device,
+ struct device_attribute *attr, char *buf)
{
return sprintf(buf, "VMW_PVRDMA-%s\n", DRV_VERSION);
}
+static DEVICE_ATTR_RO(hca_type);
-static ssize_t show_rev(struct device *device, struct device_attribute *attr,
- char *buf)
+static ssize_t hw_rev_show(struct device *device,
+ struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", PVRDMA_REV_ID);
}
+static DEVICE_ATTR_RO(hw_rev);
-static ssize_t show_board(struct device *device, struct device_attribute *attr,
- char *buf)
+static ssize_t board_id_show(struct device *device,
+ struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", PVRDMA_BOARD_ID);
}
+static DEVICE_ATTR_RO(board_id);
-static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL);
-static DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL);
-static DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL);
+static struct attribute *pvrdma_class_attributes[] = {
+ &dev_attr_hw_rev.attr,
+ &dev_attr_hca_type.attr,
+ &dev_attr_board_id.attr,
+ NULL,
+};
-static struct device_attribute *pvrdma_class_attributes[] = {
- &dev_attr_hw_rev,
- &dev_attr_hca_type,
- &dev_attr_board_id
+static const struct attribute_group pvrdma_attr_group = {
+ .attrs = pvrdma_class_attributes,
};
static void pvrdma_get_fw_ver_str(struct ib_device *device, char *str)
@@ -160,9 +164,7 @@ static struct net_device *pvrdma_get_netdev(struct ib_device *ibdev,
static int pvrdma_register_device(struct pvrdma_dev *dev)
{
int ret = -1;
- int i = 0;
- strlcpy(dev->ib_dev.name, "vmw_pvrdma%d", IB_DEVICE_NAME_MAX);
dev->ib_dev.node_guid = dev->dsr->caps.node_guid;
dev->sys_image_guid = dev->dsr->caps.sys_image_guid;
dev->flags = 0;
@@ -266,24 +268,16 @@ static int pvrdma_register_device(struct pvrdma_dev *dev)
}
dev->ib_dev.driver_id = RDMA_DRIVER_VMW_PVRDMA;
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, NULL);
+ ret = ib_register_device(&dev->ib_dev, "vmw_pvrdma%d", NULL);
if (ret)
goto err_srq_free;
- for (i = 0; i < ARRAY_SIZE(pvrdma_class_attributes); ++i) {
- ret = device_create_file(&dev->ib_dev.dev,
- pvrdma_class_attributes[i]);
- if (ret)
- goto err_class;
- }
-
dev->ib_active = true;
return 0;
-err_class:
- ib_unregister_device(&dev->ib_dev);
err_srq_free:
kfree(dev->srq_tbl);
err_qp_free:
@@ -735,7 +729,7 @@ static void pvrdma_netdevice_event_handle(struct pvrdma_dev *dev,
default:
dev_dbg(&dev->pdev->dev, "ignore netdevice event %ld on %s\n",
- event, dev->ib_dev.name);
+ event, dev_name(&dev->ib_dev.dev));
break;
}
}
diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_qp.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_qp.c
index 60083c0363a5..cf22f57a9f0d 100644
--- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_qp.c
+++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_qp.c
@@ -499,7 +499,7 @@ int pvrdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
next_state = (attr_mask & IB_QP_STATE) ? attr->qp_state : cur_state;
if (!ib_modify_qp_is_ok(cur_state, next_state, ibqp->qp_type,
- attr_mask, IB_LINK_LAYER_ETHERNET)) {
+ attr_mask)) {
ret = -EINVAL;
goto out;
}
diff --git a/drivers/infiniband/sw/rdmavt/Kconfig b/drivers/infiniband/sw/rdmavt/Kconfig
index 98e798007f75..7df896a18d38 100644
--- a/drivers/infiniband/sw/rdmavt/Kconfig
+++ b/drivers/infiniband/sw/rdmavt/Kconfig
@@ -1,6 +1,6 @@
config INFINIBAND_RDMAVT
tristate "RDMA verbs transport library"
- depends on 64BIT && ARCH_DMA_ADDR_T_64BIT
+ depends on X86_64 && ARCH_DMA_ADDR_T_64BIT
depends on PCI
select DMA_VIRT_OPS
---help---
diff --git a/drivers/infiniband/sw/rdmavt/qp.c b/drivers/infiniband/sw/rdmavt/qp.c
index 5ce403c6cddb..1735deb1a9d4 100644
--- a/drivers/infiniband/sw/rdmavt/qp.c
+++ b/drivers/infiniband/sw/rdmavt/qp.c
@@ -118,6 +118,187 @@ const int ib_rvt_state_ops[IB_QPS_ERR + 1] = {
};
EXPORT_SYMBOL(ib_rvt_state_ops);
+/* platform specific: return the last level cache (llc) size, in KiB */
+static int rvt_wss_llc_size(void)
+{
+ /* assume that the boot CPU value is universal for all CPUs */
+ return boot_cpu_data.x86_cache_size;
+}
+
+/* platform specific: cacheless copy */
+static void cacheless_memcpy(void *dst, void *src, size_t n)
+{
+ /*
+ * Use the only available X64 cacheless copy. Add a __user cast
+ * to quiet sparse. The src agument is already in the kernel so
+ * there are no security issues. The extra fault recovery machinery
+ * is not invoked.
+ */
+ __copy_user_nocache(dst, (void __user *)src, n, 0);
+}
+
+void rvt_wss_exit(struct rvt_dev_info *rdi)
+{
+ struct rvt_wss *wss = rdi->wss;
+
+ if (!wss)
+ return;
+
+ /* coded to handle partially initialized and repeat callers */
+ kfree(wss->entries);
+ wss->entries = NULL;
+ kfree(rdi->wss);
+ rdi->wss = NULL;
+}
+
+/**
+ * rvt_wss_init - Init wss data structures
+ *
+ * Return: 0 on success
+ */
+int rvt_wss_init(struct rvt_dev_info *rdi)
+{
+ unsigned int sge_copy_mode = rdi->dparms.sge_copy_mode;
+ unsigned int wss_threshold = rdi->dparms.wss_threshold;
+ unsigned int wss_clean_period = rdi->dparms.wss_clean_period;
+ long llc_size;
+ long llc_bits;
+ long table_size;
+ long table_bits;
+ struct rvt_wss *wss;
+ int node = rdi->dparms.node;
+
+ if (sge_copy_mode != RVT_SGE_COPY_ADAPTIVE) {
+ rdi->wss = NULL;
+ return 0;
+ }
+
+ rdi->wss = kzalloc_node(sizeof(*rdi->wss), GFP_KERNEL, node);
+ if (!rdi->wss)
+ return -ENOMEM;
+ wss = rdi->wss;
+
+ /* check for a valid percent range - default to 80 if none or invalid */
+ if (wss_threshold < 1 || wss_threshold > 100)
+ wss_threshold = 80;
+
+ /* reject a wildly large period */
+ if (wss_clean_period > 1000000)
+ wss_clean_period = 256;
+
+ /* reject a zero period */
+ if (wss_clean_period == 0)
+ wss_clean_period = 1;
+
+ /*
+ * Calculate the table size - the next power of 2 larger than the
+ * LLC size. LLC size is in KiB.
+ */
+ llc_size = rvt_wss_llc_size() * 1024;
+ table_size = roundup_pow_of_two(llc_size);
+
+ /* one bit per page in rounded up table */
+ llc_bits = llc_size / PAGE_SIZE;
+ table_bits = table_size / PAGE_SIZE;
+ wss->pages_mask = table_bits - 1;
+ wss->num_entries = table_bits / BITS_PER_LONG;
+
+ wss->threshold = (llc_bits * wss_threshold) / 100;
+ if (wss->threshold == 0)
+ wss->threshold = 1;
+
+ wss->clean_period = wss_clean_period;
+ atomic_set(&wss->clean_counter, wss_clean_period);
+
+ wss->entries = kcalloc_node(wss->num_entries, sizeof(*wss->entries),
+ GFP_KERNEL, node);
+ if (!wss->entries) {
+ rvt_wss_exit(rdi);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/*
+ * Advance the clean counter. When the clean period has expired,
+ * clean an entry.
+ *
+ * This is implemented in atomics to avoid locking. Because multiple
+ * variables are involved, it can be racy which can lead to slightly
+ * inaccurate information. Since this is only a heuristic, this is
+ * OK. Any innaccuracies will clean themselves out as the counter
+ * advances. That said, it is unlikely the entry clean operation will
+ * race - the next possible racer will not start until the next clean
+ * period.
+ *
+ * The clean counter is implemented as a decrement to zero. When zero
+ * is reached an entry is cleaned.
+ */
+static void wss_advance_clean_counter(struct rvt_wss *wss)
+{
+ int entry;
+ int weight;
+ unsigned long bits;
+
+ /* become the cleaner if we decrement the counter to zero */
+ if (atomic_dec_and_test(&wss->clean_counter)) {
+ /*
+ * Set, not add, the clean period. This avoids an issue
+ * where the counter could decrement below the clean period.
+ * Doing a set can result in lost decrements, slowing the
+ * clean advance. Since this a heuristic, this possible
+ * slowdown is OK.
+ *
+ * An alternative is to loop, advancing the counter by a
+ * clean period until the result is > 0. However, this could
+ * lead to several threads keeping another in the clean loop.
+ * This could be mitigated by limiting the number of times
+ * we stay in the loop.
+ */
+ atomic_set(&wss->clean_counter, wss->clean_period);
+
+ /*
+ * Uniquely grab the entry to clean and move to next.
+ * The current entry is always the lower bits of
+ * wss.clean_entry. The table size, wss.num_entries,
+ * is always a power-of-2.
+ */
+ entry = (atomic_inc_return(&wss->clean_entry) - 1)
+ & (wss->num_entries - 1);
+
+ /* clear the entry and count the bits */
+ bits = xchg(&wss->entries[entry], 0);
+ weight = hweight64((u64)bits);
+ /* only adjust the contended total count if needed */
+ if (weight)
+ atomic_sub(weight, &wss->total_count);
+ }
+}
+
+/*
+ * Insert the given address into the working set array.
+ */
+static void wss_insert(struct rvt_wss *wss, void *address)
+{
+ u32 page = ((unsigned long)address >> PAGE_SHIFT) & wss->pages_mask;
+ u32 entry = page / BITS_PER_LONG; /* assumes this ends up a shift */
+ u32 nr = page & (BITS_PER_LONG - 1);
+
+ if (!test_and_set_bit(nr, &wss->entries[entry]))
+ atomic_inc(&wss->total_count);
+
+ wss_advance_clean_counter(wss);
+}
+
+/*
+ * Is the working set larger than the threshold?
+ */
+static inline bool wss_exceeds_threshold(struct rvt_wss *wss)
+{
+ return atomic_read(&wss->total_count) >= wss->threshold;
+}
+
static void get_map_page(struct rvt_qpn_table *qpt,
struct rvt_qpn_map *map)
{
@@ -1164,11 +1345,8 @@ int rvt_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
int lastwqe = 0;
int mig = 0;
int pmtu = 0; /* for gcc warning only */
- enum rdma_link_layer link;
int opa_ah;
- link = rdma_port_get_link_layer(ibqp->device, qp->port_num);
-
spin_lock_irq(&qp->r_lock);
spin_lock(&qp->s_hlock);
spin_lock(&qp->s_lock);
@@ -1179,7 +1357,7 @@ int rvt_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
opa_ah = rdma_cap_opa_ah(ibqp->device, qp->port_num);
if (!ib_modify_qp_is_ok(cur_state, new_state, ibqp->qp_type,
- attr_mask, link))
+ attr_mask))
goto inval;
if (rdi->driver_f.check_modify_qp &&
@@ -1718,7 +1896,7 @@ static inline int rvt_qp_is_avail(
*/
static int rvt_post_one_wr(struct rvt_qp *qp,
const struct ib_send_wr *wr,
- int *call_send)
+ bool *call_send)
{
struct rvt_swqe *wqe;
u32 next;
@@ -1823,15 +2001,11 @@ static int rvt_post_one_wr(struct rvt_qp *qp,
wqe->wr.num_sge = j;
}
- /* general part of wqe valid - allow for driver checks */
- if (rdi->driver_f.check_send_wqe) {
- ret = rdi->driver_f.check_send_wqe(qp, wqe);
- if (ret < 0)
- goto bail_inval_free;
- if (ret)
- *call_send = ret;
- }
-
+ /*
+ * Calculate and set SWQE PSN values prior to handing it off
+ * to the driver's check routine. This give the driver the
+ * opportunity to adjust PSN values based on internal checks.
+ */
log_pmtu = qp->log_pmtu;
if (qp->ibqp.qp_type != IB_QPT_UC &&
qp->ibqp.qp_type != IB_QPT_RC) {
@@ -1856,8 +2030,18 @@ static int rvt_post_one_wr(struct rvt_qp *qp,
(wqe->length ?
((wqe->length - 1) >> log_pmtu) :
0);
- qp->s_next_psn = wqe->lpsn + 1;
}
+
+ /* general part of wqe valid - allow for driver checks */
+ if (rdi->driver_f.setup_wqe) {
+ ret = rdi->driver_f.setup_wqe(qp, wqe, call_send);
+ if (ret < 0)
+ goto bail_inval_free_ref;
+ }
+
+ if (!(rdi->post_parms[wr->opcode].flags & RVT_OPERATION_LOCAL))
+ qp->s_next_psn = wqe->lpsn + 1;
+
if (unlikely(reserved_op)) {
wqe->wr.send_flags |= RVT_SEND_RESERVE_USED;
rvt_qp_wqe_reserve(qp, wqe);
@@ -1871,6 +2055,10 @@ static int rvt_post_one_wr(struct rvt_qp *qp,
return 0;
+bail_inval_free_ref:
+ if (qp->ibqp.qp_type != IB_QPT_UC &&
+ qp->ibqp.qp_type != IB_QPT_RC)
+ atomic_dec(&ibah_to_rvtah(ud_wr(wr)->ah)->refcount);
bail_inval_free:
/* release mr holds */
while (j) {
@@ -1897,7 +2085,7 @@ int rvt_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr,
struct rvt_qp *qp = ibqp_to_rvtqp(ibqp);
struct rvt_dev_info *rdi = ib_to_rvt(ibqp->device);
unsigned long flags = 0;
- int call_send;
+ bool call_send;
unsigned nreq = 0;
int err = 0;
@@ -1930,7 +2118,11 @@ int rvt_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr,
bail:
spin_unlock_irqrestore(&qp->s_hlock, flags);
if (nreq) {
- if (call_send)
+ /*
+ * Only call do_send if there is exactly one packet, and the
+ * driver said it was ok.
+ */
+ if (nreq == 1 && call_send)
rdi->driver_f.do_send(qp);
else
rdi->driver_f.schedule_send_no_lock(qp);
@@ -2465,3 +2657,454 @@ void rvt_qp_iter(struct rvt_dev_info *rdi,
rcu_read_unlock();
}
EXPORT_SYMBOL(rvt_qp_iter);
+
+/*
+ * This should be called with s_lock held.
+ */
+void rvt_send_complete(struct rvt_qp *qp, struct rvt_swqe *wqe,
+ enum ib_wc_status status)
+{
+ u32 old_last, last;
+ struct rvt_dev_info *rdi = ib_to_rvt(qp->ibqp.device);
+
+ if (!(ib_rvt_state_ops[qp->state] & RVT_PROCESS_OR_FLUSH_SEND))
+ return;
+
+ last = qp->s_last;
+ old_last = last;
+ trace_rvt_qp_send_completion(qp, wqe, last);
+ if (++last >= qp->s_size)
+ last = 0;
+ trace_rvt_qp_send_completion(qp, wqe, last);
+ qp->s_last = last;
+ /* See post_send() */
+ barrier();
+ rvt_put_swqe(wqe);
+ if (qp->ibqp.qp_type == IB_QPT_UD ||
+ qp->ibqp.qp_type == IB_QPT_SMI ||
+ qp->ibqp.qp_type == IB_QPT_GSI)
+ atomic_dec(&ibah_to_rvtah(wqe->ud_wr.ah)->refcount);
+
+ rvt_qp_swqe_complete(qp,
+ wqe,
+ rdi->wc_opcode[wqe->wr.opcode],
+ status);
+
+ if (qp->s_acked == old_last)
+ qp->s_acked = last;
+ if (qp->s_cur == old_last)
+ qp->s_cur = last;
+ if (qp->s_tail == old_last)
+ qp->s_tail = last;
+ if (qp->state == IB_QPS_SQD && last == qp->s_cur)
+ qp->s_draining = 0;
+}
+EXPORT_SYMBOL(rvt_send_complete);
+
+/**
+ * rvt_copy_sge - copy data to SGE memory
+ * @qp: associated QP
+ * @ss: the SGE state
+ * @data: the data to copy
+ * @length: the length of the data
+ * @release: boolean to release MR
+ * @copy_last: do a separate copy of the last 8 bytes
+ */
+void rvt_copy_sge(struct rvt_qp *qp, struct rvt_sge_state *ss,
+ void *data, u32 length,
+ bool release, bool copy_last)
+{
+ struct rvt_sge *sge = &ss->sge;
+ int i;
+ bool in_last = false;
+ bool cacheless_copy = false;
+ struct rvt_dev_info *rdi = ib_to_rvt(qp->ibqp.device);
+ struct rvt_wss *wss = rdi->wss;
+ unsigned int sge_copy_mode = rdi->dparms.sge_copy_mode;
+
+ if (sge_copy_mode == RVT_SGE_COPY_CACHELESS) {
+ cacheless_copy = length >= PAGE_SIZE;
+ } else if (sge_copy_mode == RVT_SGE_COPY_ADAPTIVE) {
+ if (length >= PAGE_SIZE) {
+ /*
+ * NOTE: this *assumes*:
+ * o The first vaddr is the dest.
+ * o If multiple pages, then vaddr is sequential.
+ */
+ wss_insert(wss, sge->vaddr);
+ if (length >= (2 * PAGE_SIZE))
+ wss_insert(wss, (sge->vaddr + PAGE_SIZE));
+
+ cacheless_copy = wss_exceeds_threshold(wss);
+ } else {
+ wss_advance_clean_counter(wss);
+ }
+ }
+
+ if (copy_last) {
+ if (length > 8) {
+ length -= 8;
+ } else {
+ copy_last = false;
+ in_last = true;
+ }
+ }
+
+again:
+ while (length) {
+ u32 len = rvt_get_sge_length(sge, length);
+
+ WARN_ON_ONCE(len == 0);
+ if (unlikely(in_last)) {
+ /* enforce byte transfer ordering */
+ for (i = 0; i < len; i++)
+ ((u8 *)sge->vaddr)[i] = ((u8 *)data)[i];
+ } else if (cacheless_copy) {
+ cacheless_memcpy(sge->vaddr, data, len);
+ } else {
+ memcpy(sge->vaddr, data, len);
+ }
+ rvt_update_sge(ss, len, release);
+ data += len;
+ length -= len;
+ }
+
+ if (copy_last) {
+ copy_last = false;
+ in_last = true;
+ length = 8;
+ goto again;
+ }
+}
+EXPORT_SYMBOL(rvt_copy_sge);
+
+/**
+ * ruc_loopback - handle UC and RC loopback requests
+ * @sqp: the sending QP
+ *
+ * This is called from rvt_do_send() to forward a WQE addressed to the same HFI
+ * Note that although we are single threaded due to the send engine, we still
+ * have to protect against post_send(). We don't have to worry about
+ * receive interrupts since this is a connected protocol and all packets
+ * will pass through here.
+ */
+void rvt_ruc_loopback(struct rvt_qp *sqp)
+{
+ struct rvt_ibport *rvp = NULL;
+ struct rvt_dev_info *rdi = ib_to_rvt(sqp->ibqp.device);
+ struct rvt_qp *qp;
+ struct rvt_swqe *wqe;
+ struct rvt_sge *sge;
+ unsigned long flags;
+ struct ib_wc wc;
+ u64 sdata;
+ atomic64_t *maddr;
+ enum ib_wc_status send_status;
+ bool release;
+ int ret;
+ bool copy_last = false;
+ int local_ops = 0;
+
+ rcu_read_lock();
+ rvp = rdi->ports[sqp->port_num - 1];
+
+ /*
+ * Note that we check the responder QP state after
+ * checking the requester's state.
+ */
+
+ qp = rvt_lookup_qpn(ib_to_rvt(sqp->ibqp.device), rvp,
+ sqp->remote_qpn);
+
+ spin_lock_irqsave(&sqp->s_lock, flags);
+
+ /* Return if we are already busy processing a work request. */
+ if ((sqp->s_flags & (RVT_S_BUSY | RVT_S_ANY_WAIT)) ||
+ !(ib_rvt_state_ops[sqp->state] & RVT_PROCESS_OR_FLUSH_SEND))
+ goto unlock;
+
+ sqp->s_flags |= RVT_S_BUSY;
+
+again:
+ if (sqp->s_last == READ_ONCE(sqp->s_head))
+ goto clr_busy;
+ wqe = rvt_get_swqe_ptr(sqp, sqp->s_last);
+
+ /* Return if it is not OK to start a new work request. */
+ if (!(ib_rvt_state_ops[sqp->state] & RVT_PROCESS_NEXT_SEND_OK)) {
+ if (!(ib_rvt_state_ops[sqp->state] & RVT_FLUSH_SEND))
+ goto clr_busy;
+ /* We are in the error state, flush the work request. */
+ send_status = IB_WC_WR_FLUSH_ERR;
+ goto flush_send;
+ }
+
+ /*
+ * We can rely on the entry not changing without the s_lock
+ * being held until we update s_last.
+ * We increment s_cur to indicate s_last is in progress.
+ */
+ if (sqp->s_last == sqp->s_cur) {
+ if (++sqp->s_cur >= sqp->s_size)
+ sqp->s_cur = 0;
+ }
+ spin_unlock_irqrestore(&sqp->s_lock, flags);
+
+ if (!qp || !(ib_rvt_state_ops[qp->state] & RVT_PROCESS_RECV_OK) ||
+ qp->ibqp.qp_type != sqp->ibqp.qp_type) {
+ rvp->n_pkt_drops++;
+ /*
+ * For RC, the requester would timeout and retry so
+ * shortcut the timeouts and just signal too many retries.
+ */
+ if (sqp->ibqp.qp_type == IB_QPT_RC)
+ send_status = IB_WC_RETRY_EXC_ERR;
+ else
+ send_status = IB_WC_SUCCESS;
+ goto serr;
+ }
+
+ memset(&wc, 0, sizeof(wc));
+ send_status = IB_WC_SUCCESS;
+
+ release = true;
+ sqp->s_sge.sge = wqe->sg_list[0];
+ sqp->s_sge.sg_list = wqe->sg_list + 1;
+ sqp->s_sge.num_sge = wqe->wr.num_sge;
+ sqp->s_len = wqe->length;
+ switch (wqe->wr.opcode) {
+ case IB_WR_REG_MR:
+ goto send_comp;
+
+ case IB_WR_LOCAL_INV:
+ if (!(wqe->wr.send_flags & RVT_SEND_COMPLETION_ONLY)) {
+ if (rvt_invalidate_rkey(sqp,
+ wqe->wr.ex.invalidate_rkey))
+ send_status = IB_WC_LOC_PROT_ERR;
+ local_ops = 1;
+ }
+ goto send_comp;
+
+ case IB_WR_SEND_WITH_INV:
+ if (!rvt_invalidate_rkey(qp, wqe->wr.ex.invalidate_rkey)) {
+ wc.wc_flags = IB_WC_WITH_INVALIDATE;
+ wc.ex.invalidate_rkey = wqe->wr.ex.invalidate_rkey;
+ }
+ goto send;
+
+ case IB_WR_SEND_WITH_IMM:
+ wc.wc_flags = IB_WC_WITH_IMM;
+ wc.ex.imm_data = wqe->wr.ex.imm_data;
+ /* FALLTHROUGH */
+ case IB_WR_SEND:
+send:
+ ret = rvt_get_rwqe(qp, false);
+ if (ret < 0)
+ goto op_err;
+ if (!ret)
+ goto rnr_nak;
+ break;
+
+ case IB_WR_RDMA_WRITE_WITH_IMM:
+ if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_WRITE)))
+ goto inv_err;
+ wc.wc_flags = IB_WC_WITH_IMM;
+ wc.ex.imm_data = wqe->wr.ex.imm_data;
+ ret = rvt_get_rwqe(qp, true);
+ if (ret < 0)
+ goto op_err;
+ if (!ret)
+ goto rnr_nak;
+ /* skip copy_last set and qp_access_flags recheck */
+ goto do_write;
+ case IB_WR_RDMA_WRITE:
+ copy_last = rvt_is_user_qp(qp);
+ if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_WRITE)))
+ goto inv_err;
+do_write:
+ if (wqe->length == 0)
+ break;
+ if (unlikely(!rvt_rkey_ok(qp, &qp->r_sge.sge, wqe->length,
+ wqe->rdma_wr.remote_addr,
+ wqe->rdma_wr.rkey,
+ IB_ACCESS_REMOTE_WRITE)))
+ goto acc_err;
+ qp->r_sge.sg_list = NULL;
+ qp->r_sge.num_sge = 1;
+ qp->r_sge.total_len = wqe->length;
+ break;
+
+ case IB_WR_RDMA_READ:
+ if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_READ)))
+ goto inv_err;
+ if (unlikely(!rvt_rkey_ok(qp, &sqp->s_sge.sge, wqe->length,
+ wqe->rdma_wr.remote_addr,
+ wqe->rdma_wr.rkey,
+ IB_ACCESS_REMOTE_READ)))
+ goto acc_err;
+ release = false;
+ sqp->s_sge.sg_list = NULL;
+ sqp->s_sge.num_sge = 1;
+ qp->r_sge.sge = wqe->sg_list[0];
+ qp->r_sge.sg_list = wqe->sg_list + 1;
+ qp->r_sge.num_sge = wqe->wr.num_sge;
+ qp->r_sge.total_len = wqe->length;
+ break;
+
+ case IB_WR_ATOMIC_CMP_AND_SWP:
+ case IB_WR_ATOMIC_FETCH_AND_ADD:
+ if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_ATOMIC)))
+ goto inv_err;
+ if (unlikely(!rvt_rkey_ok(qp, &qp->r_sge.sge, sizeof(u64),
+ wqe->atomic_wr.remote_addr,
+ wqe->atomic_wr.rkey,
+ IB_ACCESS_REMOTE_ATOMIC)))
+ goto acc_err;
+ /* Perform atomic OP and save result. */
+ maddr = (atomic64_t *)qp->r_sge.sge.vaddr;
+ sdata = wqe->atomic_wr.compare_add;
+ *(u64 *)sqp->s_sge.sge.vaddr =
+ (wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD) ?
+ (u64)atomic64_add_return(sdata, maddr) - sdata :
+ (u64)cmpxchg((u64 *)qp->r_sge.sge.vaddr,
+ sdata, wqe->atomic_wr.swap);
+ rvt_put_mr(qp->r_sge.sge.mr);
+ qp->r_sge.num_sge = 0;
+ goto send_comp;
+
+ default:
+ send_status = IB_WC_LOC_QP_OP_ERR;
+ goto serr;
+ }
+
+ sge = &sqp->s_sge.sge;
+ while (sqp->s_len) {
+ u32 len = sqp->s_len;
+
+ if (len > sge->length)
+ len = sge->length;
+ if (len > sge->sge_length)
+ len = sge->sge_length;
+ WARN_ON_ONCE(len == 0);
+ rvt_copy_sge(qp, &qp->r_sge, sge->vaddr,
+ len, release, copy_last);
+ sge->vaddr += len;
+ sge->length -= len;
+ sge->sge_length -= len;
+ if (sge->sge_length == 0) {
+ if (!release)
+ rvt_put_mr(sge->mr);
+ if (--sqp->s_sge.num_sge)
+ *sge = *sqp->s_sge.sg_list++;
+ } else if (sge->length == 0 && sge->mr->lkey) {
+ if (++sge->n >= RVT_SEGSZ) {
+ if (++sge->m >= sge->mr->mapsz)
+ break;
+ sge->n = 0;
+ }
+ sge->vaddr =
+ sge->mr->map[sge->m]->segs[sge->n].vaddr;
+ sge->length =
+ sge->mr->map[sge->m]->segs[sge->n].length;
+ }
+ sqp->s_len -= len;
+ }
+ if (release)
+ rvt_put_ss(&qp->r_sge);
+
+ if (!test_and_clear_bit(RVT_R_WRID_VALID, &qp->r_aflags))
+ goto send_comp;
+
+ if (wqe->wr.opcode == IB_WR_RDMA_WRITE_WITH_IMM)
+ wc.opcode = IB_WC_RECV_RDMA_WITH_IMM;
+ else
+ wc.opcode = IB_WC_RECV;
+ wc.wr_id = qp->r_wr_id;
+ wc.status = IB_WC_SUCCESS;
+ wc.byte_len = wqe->length;
+ wc.qp = &qp->ibqp;
+ wc.src_qp = qp->remote_qpn;
+ wc.slid = rdma_ah_get_dlid(&qp->remote_ah_attr) & U16_MAX;
+ wc.sl = rdma_ah_get_sl(&qp->remote_ah_attr);
+ wc.port_num = 1;
+ /* Signal completion event if the solicited bit is set. */
+ rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.recv_cq), &wc,
+ wqe->wr.send_flags & IB_SEND_SOLICITED);
+
+send_comp:
+ spin_lock_irqsave(&sqp->s_lock, flags);
+ rvp->n_loop_pkts++;
+flush_send:
+ sqp->s_rnr_retry = sqp->s_rnr_retry_cnt;
+ rvt_send_complete(sqp, wqe, send_status);
+ if (local_ops) {
+ atomic_dec(&sqp->local_ops_pending);
+ local_ops = 0;
+ }
+ goto again;
+
+rnr_nak:
+ /* Handle RNR NAK */
+ if (qp->ibqp.qp_type == IB_QPT_UC)
+ goto send_comp;
+ rvp->n_rnr_naks++;
+ /*
+ * Note: we don't need the s_lock held since the BUSY flag
+ * makes this single threaded.
+ */
+ if (sqp->s_rnr_retry == 0) {
+ send_status = IB_WC_RNR_RETRY_EXC_ERR;
+ goto serr;
+ }
+ if (sqp->s_rnr_retry_cnt < 7)
+ sqp->s_rnr_retry--;
+ spin_lock_irqsave(&sqp->s_lock, flags);
+ if (!(ib_rvt_state_ops[sqp->state] & RVT_PROCESS_RECV_OK))
+ goto clr_busy;
+ rvt_add_rnr_timer(sqp, qp->r_min_rnr_timer <<
+ IB_AETH_CREDIT_SHIFT);
+ goto clr_busy;
+
+op_err:
+ send_status = IB_WC_REM_OP_ERR;
+ wc.status = IB_WC_LOC_QP_OP_ERR;
+ goto err;
+
+inv_err:
+ send_status = IB_WC_REM_INV_REQ_ERR;
+ wc.status = IB_WC_LOC_QP_OP_ERR;
+ goto err;
+
+acc_err:
+ send_status = IB_WC_REM_ACCESS_ERR;
+ wc.status = IB_WC_LOC_PROT_ERR;
+err:
+ /* responder goes to error state */
+ rvt_rc_error(qp, wc.status);
+
+serr:
+ spin_lock_irqsave(&sqp->s_lock, flags);
+ rvt_send_complete(sqp, wqe, send_status);
+ if (sqp->ibqp.qp_type == IB_QPT_RC) {
+ int lastwqe = rvt_error_qp(sqp, IB_WC_WR_FLUSH_ERR);
+
+ sqp->s_flags &= ~RVT_S_BUSY;
+ spin_unlock_irqrestore(&sqp->s_lock, flags);
+ if (lastwqe) {
+ struct ib_event ev;
+
+ ev.device = sqp->ibqp.device;
+ ev.element.qp = &sqp->ibqp;
+ ev.event = IB_EVENT_QP_LAST_WQE_REACHED;
+ sqp->ibqp.event_handler(&ev, sqp->ibqp.qp_context);
+ }
+ goto done;
+ }
+clr_busy:
+ sqp->s_flags &= ~RVT_S_BUSY;
+unlock:
+ spin_unlock_irqrestore(&sqp->s_lock, flags);
+done:
+ rcu_read_unlock();
+}
+EXPORT_SYMBOL(rvt_ruc_loopback);
diff --git a/drivers/infiniband/sw/rdmavt/qp.h b/drivers/infiniband/sw/rdmavt/qp.h
index 264811fdc530..6d883972e0b8 100644
--- a/drivers/infiniband/sw/rdmavt/qp.h
+++ b/drivers/infiniband/sw/rdmavt/qp.h
@@ -66,4 +66,6 @@ int rvt_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr,
const struct ib_send_wr **bad_wr);
int rvt_post_srq_recv(struct ib_srq *ibsrq, const struct ib_recv_wr *wr,
const struct ib_recv_wr **bad_wr);
+int rvt_wss_init(struct rvt_dev_info *rdi);
+void rvt_wss_exit(struct rvt_dev_info *rdi);
#endif /* DEF_RVTQP_H */
diff --git a/drivers/infiniband/sw/rdmavt/trace_tx.h b/drivers/infiniband/sw/rdmavt/trace_tx.h
index 0ef25fc49f25..d5df352eadb1 100644
--- a/drivers/infiniband/sw/rdmavt/trace_tx.h
+++ b/drivers/infiniband/sw/rdmavt/trace_tx.h
@@ -153,6 +153,48 @@ TRACE_EVENT(
)
);
+TRACE_EVENT(
+ rvt_qp_send_completion,
+ TP_PROTO(struct rvt_qp *qp, struct rvt_swqe *wqe, u32 idx),
+ TP_ARGS(qp, wqe, idx),
+ TP_STRUCT__entry(
+ RDI_DEV_ENTRY(ib_to_rvt(qp->ibqp.device))
+ __field(struct rvt_swqe *, wqe)
+ __field(u64, wr_id)
+ __field(u32, qpn)
+ __field(u32, qpt)
+ __field(u32, length)
+ __field(u32, idx)
+ __field(u32, ssn)
+ __field(enum ib_wr_opcode, opcode)
+ __field(int, send_flags)
+ ),
+ TP_fast_assign(
+ 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;
+ __entry->qpt = qp->ibqp.qp_type;
+ __entry->length = wqe->length;
+ __entry->idx = idx;
+ __entry->ssn = wqe->ssn;
+ __entry->opcode = wqe->wr.opcode;
+ __entry->send_flags = wqe->wr.send_flags;
+ ),
+ TP_printk(
+ "[%s] qpn 0x%x qpt %u wqe %p idx %u wr_id %llx length %u ssn %u opcode %x send_flags %x",
+ __get_str(dev),
+ __entry->qpn,
+ __entry->qpt,
+ __entry->wqe,
+ __entry->idx,
+ __entry->wr_id,
+ __entry->length,
+ __entry->ssn,
+ __entry->opcode,
+ __entry->send_flags
+ )
+);
#endif /* __RVT_TRACE_TX_H */
#undef TRACE_INCLUDE_PATH
diff --git a/drivers/infiniband/sw/rdmavt/vt.c b/drivers/infiniband/sw/rdmavt/vt.c
index 17e4abc067af..723d3daf2eba 100644
--- a/drivers/infiniband/sw/rdmavt/vt.c
+++ b/drivers/infiniband/sw/rdmavt/vt.c
@@ -774,6 +774,13 @@ int rvt_register_device(struct rvt_dev_info *rdi, u32 driver_id)
goto bail_no_mr;
}
+ /* Memory Working Set Size */
+ ret = rvt_wss_init(rdi);
+ if (ret) {
+ rvt_pr_err(rdi, "Error in WSS init.\n");
+ goto bail_mr;
+ }
+
/* Completion queues */
spin_lock_init(&rdi->n_cqs_lock);
@@ -828,10 +835,11 @@ int rvt_register_device(struct rvt_dev_info *rdi, u32 driver_id)
rdi->ibdev.driver_id = driver_id;
/* We are now good to announce we exist */
- ret = ib_register_device(&rdi->ibdev, rdi->driver_f.port_callback);
+ ret = ib_register_device(&rdi->ibdev, dev_name(&rdi->ibdev.dev),
+ rdi->driver_f.port_callback);
if (ret) {
rvt_pr_err(rdi, "Failed to register driver with ib core.\n");
- goto bail_mr;
+ goto bail_wss;
}
rvt_create_mad_agents(rdi);
@@ -839,6 +847,8 @@ int rvt_register_device(struct rvt_dev_info *rdi, u32 driver_id)
rvt_pr_info(rdi, "Registration with rdmavt done.\n");
return ret;
+bail_wss:
+ rvt_wss_exit(rdi);
bail_mr:
rvt_mr_exit(rdi);
@@ -862,6 +872,7 @@ void rvt_unregister_device(struct rvt_dev_info *rdi)
rvt_free_mad_agents(rdi);
ib_unregister_device(&rdi->ibdev);
+ rvt_wss_exit(rdi);
rvt_mr_exit(rdi);
rvt_qp_exit(rdi);
}
diff --git a/drivers/infiniband/sw/rxe/rxe.c b/drivers/infiniband/sw/rxe/rxe.c
index 10999fa69281..383e65c7bbc0 100644
--- a/drivers/infiniband/sw/rxe/rxe.c
+++ b/drivers/infiniband/sw/rxe/rxe.c
@@ -103,7 +103,7 @@ static void rxe_init_device_param(struct rxe_dev *rxe)
rxe->attr.max_res_rd_atom = RXE_MAX_RES_RD_ATOM;
rxe->attr.max_qp_init_rd_atom = RXE_MAX_QP_INIT_RD_ATOM;
rxe->attr.max_ee_init_rd_atom = RXE_MAX_EE_INIT_RD_ATOM;
- rxe->attr.atomic_cap = RXE_ATOMIC_CAP;
+ rxe->attr.atomic_cap = IB_ATOMIC_HCA;
rxe->attr.max_ee = RXE_MAX_EE;
rxe->attr.max_rdd = RXE_MAX_RDD;
rxe->attr.max_mw = RXE_MAX_MW;
@@ -128,9 +128,9 @@ static void rxe_init_device_param(struct rxe_dev *rxe)
/* initialize port attributes */
static int rxe_init_port_param(struct rxe_port *port)
{
- port->attr.state = RXE_PORT_STATE;
- port->attr.max_mtu = RXE_PORT_MAX_MTU;
- port->attr.active_mtu = RXE_PORT_ACTIVE_MTU;
+ port->attr.state = IB_PORT_DOWN;
+ port->attr.max_mtu = IB_MTU_4096;
+ port->attr.active_mtu = IB_MTU_256;
port->attr.gid_tbl_len = RXE_PORT_GID_TBL_LEN;
port->attr.port_cap_flags = RXE_PORT_PORT_CAP_FLAGS;
port->attr.max_msg_sz = RXE_PORT_MAX_MSG_SZ;
@@ -147,8 +147,7 @@ static int rxe_init_port_param(struct rxe_port *port)
port->attr.active_width = RXE_PORT_ACTIVE_WIDTH;
port->attr.active_speed = RXE_PORT_ACTIVE_SPEED;
port->attr.phys_state = RXE_PORT_PHYS_STATE;
- port->mtu_cap =
- ib_mtu_enum_to_int(RXE_PORT_ACTIVE_MTU);
+ port->mtu_cap = ib_mtu_enum_to_int(IB_MTU_256);
port->subnet_prefix = cpu_to_be64(RXE_PORT_SUBNET_PREFIX);
return 0;
@@ -300,7 +299,7 @@ void rxe_set_mtu(struct rxe_dev *rxe, unsigned int ndev_mtu)
mtu = eth_mtu_int_to_enum(ndev_mtu);
/* Make sure that new MTU in range */
- mtu = mtu ? min_t(enum ib_mtu, mtu, RXE_PORT_MAX_MTU) : IB_MTU_256;
+ mtu = mtu ? min_t(enum ib_mtu, mtu, IB_MTU_4096) : IB_MTU_256;
port->attr.active_mtu = mtu;
port->mtu_cap = ib_mtu_enum_to_int(mtu);
diff --git a/drivers/infiniband/sw/rxe/rxe_comp.c b/drivers/infiniband/sw/rxe/rxe_comp.c
index 83311dd07019..ea089cb091ad 100644
--- a/drivers/infiniband/sw/rxe/rxe_comp.c
+++ b/drivers/infiniband/sw/rxe/rxe_comp.c
@@ -191,6 +191,7 @@ static inline void reset_retry_counters(struct rxe_qp *qp)
{
qp->comp.retry_cnt = qp->attr.retry_cnt;
qp->comp.rnr_retry = qp->attr.rnr_retry;
+ qp->comp.started_retry = 0;
}
static inline enum comp_state check_psn(struct rxe_qp *qp,
@@ -253,6 +254,17 @@ static inline enum comp_state check_ack(struct rxe_qp *qp,
case IB_OPCODE_RC_RDMA_READ_RESPONSE_MIDDLE:
if (pkt->opcode != IB_OPCODE_RC_RDMA_READ_RESPONSE_MIDDLE &&
pkt->opcode != IB_OPCODE_RC_RDMA_READ_RESPONSE_LAST) {
+ /* read retries of partial data may restart from
+ * read response first or response only.
+ */
+ if ((pkt->psn == wqe->first_psn &&
+ pkt->opcode ==
+ IB_OPCODE_RC_RDMA_READ_RESPONSE_FIRST) ||
+ (wqe->first_psn == wqe->last_psn &&
+ pkt->opcode ==
+ IB_OPCODE_RC_RDMA_READ_RESPONSE_ONLY))
+ break;
+
return COMPST_ERROR;
}
break;
@@ -499,11 +511,11 @@ static inline enum comp_state complete_wqe(struct rxe_qp *qp,
struct rxe_pkt_info *pkt,
struct rxe_send_wqe *wqe)
{
- qp->comp.opcode = -1;
-
- if (pkt) {
- if (psn_compare(pkt->psn, qp->comp.psn) >= 0)
- qp->comp.psn = (pkt->psn + 1) & BTH_PSN_MASK;
+ if (pkt && wqe->state == wqe_state_pending) {
+ if (psn_compare(wqe->last_psn, qp->comp.psn) >= 0) {
+ qp->comp.psn = (wqe->last_psn + 1) & BTH_PSN_MASK;
+ qp->comp.opcode = -1;
+ }
if (qp->req.wait_psn) {
qp->req.wait_psn = 0;
@@ -676,6 +688,20 @@ int rxe_completer(void *arg)
goto exit;
}
+ /* if we've started a retry, don't start another
+ * retry sequence, unless this is a timeout.
+ */
+ if (qp->comp.started_retry &&
+ !qp->comp.timeout_retry) {
+ if (pkt) {
+ rxe_drop_ref(pkt->qp);
+ kfree_skb(skb);
+ skb = NULL;
+ }
+
+ goto done;
+ }
+
if (qp->comp.retry_cnt > 0) {
if (qp->comp.retry_cnt != 7)
qp->comp.retry_cnt--;
@@ -692,6 +718,7 @@ int rxe_completer(void *arg)
rxe_counter_inc(rxe,
RXE_CNT_COMP_RETRY);
qp->req.need_retry = 1;
+ qp->comp.started_retry = 1;
rxe_run_task(&qp->req.task, 1);
}
@@ -701,7 +728,7 @@ int rxe_completer(void *arg)
skb = NULL;
}
- goto exit;
+ goto done;
} else {
rxe_counter_inc(rxe, RXE_CNT_RETRY_EXCEEDED);
diff --git a/drivers/infiniband/sw/rxe/rxe_cq.c b/drivers/infiniband/sw/rxe/rxe_cq.c
index 2ee4b08b00ea..a57276f2cb84 100644
--- a/drivers/infiniband/sw/rxe/rxe_cq.c
+++ b/drivers/infiniband/sw/rxe/rxe_cq.c
@@ -30,7 +30,7 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
-
+#include <linux/vmalloc.h>
#include "rxe.h"
#include "rxe_loc.h"
#include "rxe_queue.h"
@@ -97,7 +97,7 @@ int rxe_cq_from_init(struct rxe_dev *rxe, struct rxe_cq *cq, int cqe,
err = do_mmap_info(rxe, uresp ? &uresp->mi : NULL, context,
cq->queue->buf, cq->queue->buf_size, &cq->queue->ip);
if (err) {
- kvfree(cq->queue->buf);
+ vfree(cq->queue->buf);
kfree(cq->queue);
return err;
}
diff --git a/drivers/infiniband/sw/rxe/rxe_loc.h b/drivers/infiniband/sw/rxe/rxe_loc.h
index 87d14f7ef21b..afd53f57a62b 100644
--- a/drivers/infiniband/sw/rxe/rxe_loc.h
+++ b/drivers/infiniband/sw/rxe/rxe_loc.h
@@ -144,8 +144,7 @@ void rxe_loopback(struct sk_buff *skb);
int rxe_send(struct rxe_pkt_info *pkt, struct sk_buff *skb);
struct sk_buff *rxe_init_packet(struct rxe_dev *rxe, struct rxe_av *av,
int paylen, struct rxe_pkt_info *pkt);
-int rxe_prepare(struct rxe_dev *rxe, struct rxe_pkt_info *pkt,
- struct sk_buff *skb, u32 *crc);
+int rxe_prepare(struct rxe_pkt_info *pkt, struct sk_buff *skb, u32 *crc);
enum rdma_link_layer rxe_link_layer(struct rxe_dev *rxe, unsigned int port_num);
const char *rxe_parent_name(struct rxe_dev *rxe, unsigned int port_num);
struct device *rxe_dma_device(struct rxe_dev *rxe);
@@ -196,7 +195,7 @@ static inline int qp_mtu(struct rxe_qp *qp)
if (qp->ibqp.qp_type == IB_QPT_RC || qp->ibqp.qp_type == IB_QPT_UC)
return qp->attr.path_mtu;
else
- return RXE_PORT_MAX_MTU;
+ return IB_MTU_4096;
}
static inline int rcv_wqe_size(int max_sge)
diff --git a/drivers/infiniband/sw/rxe/rxe_mr.c b/drivers/infiniband/sw/rxe/rxe_mr.c
index dff605fdf60f..9d3916b93f23 100644
--- a/drivers/infiniband/sw/rxe/rxe_mr.c
+++ b/drivers/infiniband/sw/rxe/rxe_mr.c
@@ -573,33 +573,20 @@ struct rxe_mem *lookup_mem(struct rxe_pd *pd, int access, u32 key,
struct rxe_dev *rxe = to_rdev(pd->ibpd.device);
int index = key >> 8;
- if (index >= RXE_MIN_MR_INDEX && index <= RXE_MAX_MR_INDEX) {
- mem = rxe_pool_get_index(&rxe->mr_pool, index);
- if (!mem)
- goto err1;
- } else {
- goto err1;
+ mem = rxe_pool_get_index(&rxe->mr_pool, index);
+ if (!mem)
+ return NULL;
+
+ if (unlikely((type == lookup_local && mem->lkey != key) ||
+ (type == lookup_remote && mem->rkey != key) ||
+ mem->pd != pd ||
+ (access && !(access & mem->access)) ||
+ mem->state != RXE_MEM_STATE_VALID)) {
+ rxe_drop_ref(mem);
+ mem = NULL;
}
- if ((type == lookup_local && mem->lkey != key) ||
- (type == lookup_remote && mem->rkey != key))
- goto err2;
-
- if (mem->pd != pd)
- goto err2;
-
- if (access && !(access & mem->access))
- goto err2;
-
- if (mem->state != RXE_MEM_STATE_VALID)
- goto err2;
-
return mem;
-
-err2:
- rxe_drop_ref(mem);
-err1:
- return NULL;
}
int rxe_mem_map_pages(struct rxe_dev *rxe, struct rxe_mem *mem,
diff --git a/drivers/infiniband/sw/rxe/rxe_net.c b/drivers/infiniband/sw/rxe/rxe_net.c
index 8094cbaa54a9..40e82e0f6c2d 100644
--- a/drivers/infiniband/sw/rxe/rxe_net.c
+++ b/drivers/infiniband/sw/rxe/rxe_net.c
@@ -72,7 +72,7 @@ struct rxe_dev *get_rxe_by_name(const char *name)
spin_lock_bh(&dev_list_lock);
list_for_each_entry(rxe, &rxe_dev_list, list) {
- if (!strcmp(name, rxe->ib_dev.name)) {
+ if (!strcmp(name, dev_name(&rxe->ib_dev.dev))) {
found = rxe;
break;
}
@@ -182,19 +182,11 @@ static struct dst_entry *rxe_find_route6(struct net_device *ndev,
#endif
-static struct dst_entry *rxe_find_route(struct rxe_dev *rxe,
+static struct dst_entry *rxe_find_route(struct net_device *ndev,
struct rxe_qp *qp,
struct rxe_av *av)
{
- const struct ib_gid_attr *attr;
struct dst_entry *dst = NULL;
- struct net_device *ndev;
-
- attr = rdma_get_gid_attr(&rxe->ib_dev, qp->attr.port_num,
- av->grh.sgid_index);
- if (IS_ERR(attr))
- return NULL;
- ndev = attr->ndev;
if (qp_type(qp) == IB_QPT_RC)
dst = sk_dst_get(qp->sk->sk);
@@ -229,7 +221,6 @@ static struct dst_entry *rxe_find_route(struct rxe_dev *rxe,
sk_dst_set(qp->sk->sk, dst);
}
}
- rdma_put_gid_attr(attr);
return dst;
}
@@ -377,8 +368,8 @@ static void prepare_ipv6_hdr(struct dst_entry *dst, struct sk_buff *skb,
ip6h->payload_len = htons(skb->len - sizeof(*ip6h));
}
-static int prepare4(struct rxe_dev *rxe, struct rxe_pkt_info *pkt,
- struct sk_buff *skb, struct rxe_av *av)
+static int prepare4(struct rxe_pkt_info *pkt, struct sk_buff *skb,
+ struct rxe_av *av)
{
struct rxe_qp *qp = pkt->qp;
struct dst_entry *dst;
@@ -387,7 +378,7 @@ static int prepare4(struct rxe_dev *rxe, struct rxe_pkt_info *pkt,
struct in_addr *saddr = &av->sgid_addr._sockaddr_in.sin_addr;
struct in_addr *daddr = &av->dgid_addr._sockaddr_in.sin_addr;
- dst = rxe_find_route(rxe, qp, av);
+ dst = rxe_find_route(skb->dev, qp, av);
if (!dst) {
pr_err("Host not reachable\n");
return -EHOSTUNREACH;
@@ -396,8 +387,8 @@ static int prepare4(struct rxe_dev *rxe, struct rxe_pkt_info *pkt,
if (!memcmp(saddr, daddr, sizeof(*daddr)))
pkt->mask |= RXE_LOOPBACK_MASK;
- prepare_udp_hdr(skb, htons(RXE_ROCE_V2_SPORT),
- htons(ROCE_V2_UDP_DPORT));
+ prepare_udp_hdr(skb, cpu_to_be16(qp->src_port),
+ cpu_to_be16(ROCE_V2_UDP_DPORT));
prepare_ipv4_hdr(dst, skb, saddr->s_addr, daddr->s_addr, IPPROTO_UDP,
av->grh.traffic_class, av->grh.hop_limit, df, xnet);
@@ -406,15 +397,15 @@ static int prepare4(struct rxe_dev *rxe, struct rxe_pkt_info *pkt,
return 0;
}
-static int prepare6(struct rxe_dev *rxe, struct rxe_pkt_info *pkt,
- struct sk_buff *skb, struct rxe_av *av)
+static int prepare6(struct rxe_pkt_info *pkt, struct sk_buff *skb,
+ struct rxe_av *av)
{
struct rxe_qp *qp = pkt->qp;
struct dst_entry *dst;
struct in6_addr *saddr = &av->sgid_addr._sockaddr_in6.sin6_addr;
struct in6_addr *daddr = &av->dgid_addr._sockaddr_in6.sin6_addr;
- dst = rxe_find_route(rxe, qp, av);
+ dst = rxe_find_route(skb->dev, qp, av);
if (!dst) {
pr_err("Host not reachable\n");
return -EHOSTUNREACH;
@@ -423,8 +414,8 @@ static int prepare6(struct rxe_dev *rxe, struct rxe_pkt_info *pkt,
if (!memcmp(saddr, daddr, sizeof(*daddr)))
pkt->mask |= RXE_LOOPBACK_MASK;
- prepare_udp_hdr(skb, htons(RXE_ROCE_V2_SPORT),
- htons(ROCE_V2_UDP_DPORT));
+ prepare_udp_hdr(skb, cpu_to_be16(qp->src_port),
+ cpu_to_be16(ROCE_V2_UDP_DPORT));
prepare_ipv6_hdr(dst, skb, saddr, daddr, IPPROTO_UDP,
av->grh.traffic_class,
@@ -434,16 +425,15 @@ static int prepare6(struct rxe_dev *rxe, struct rxe_pkt_info *pkt,
return 0;
}
-int rxe_prepare(struct rxe_dev *rxe, struct rxe_pkt_info *pkt,
- struct sk_buff *skb, u32 *crc)
+int rxe_prepare(struct rxe_pkt_info *pkt, struct sk_buff *skb, u32 *crc)
{
int err = 0;
struct rxe_av *av = rxe_get_av(pkt);
if (av->network_type == RDMA_NETWORK_IPV4)
- err = prepare4(rxe, pkt, skb, av);
+ err = prepare4(pkt, skb, av);
else if (av->network_type == RDMA_NETWORK_IPV6)
- err = prepare6(rxe, pkt, skb, av);
+ err = prepare6(pkt, skb, av);
*crc = rxe_icrc_hdr(pkt, skb);
@@ -501,11 +491,6 @@ void rxe_loopback(struct sk_buff *skb)
rxe_rcv(skb);
}
-static inline int addr_same(struct rxe_dev *rxe, struct rxe_av *av)
-{
- return rxe->port.port_guid == av->grh.dgid.global.interface_id;
-}
-
struct sk_buff *rxe_init_packet(struct rxe_dev *rxe, struct rxe_av *av,
int paylen, struct rxe_pkt_info *pkt)
{
@@ -625,7 +610,7 @@ void rxe_port_up(struct rxe_dev *rxe)
port->attr.phys_state = IB_PHYS_STATE_LINK_UP;
rxe_port_event(rxe, IB_EVENT_PORT_ACTIVE);
- pr_info("set %s active\n", rxe->ib_dev.name);
+ dev_info(&rxe->ib_dev.dev, "set active\n");
}
/* Caller must hold net_info_lock */
@@ -638,7 +623,7 @@ void rxe_port_down(struct rxe_dev *rxe)
port->attr.phys_state = IB_PHYS_STATE_LINK_DOWN;
rxe_port_event(rxe, IB_EVENT_PORT_ERR);
- pr_info("set %s down\n", rxe->ib_dev.name);
+ dev_info(&rxe->ib_dev.dev, "set down\n");
}
static int rxe_notify(struct notifier_block *not_blk,
diff --git a/drivers/infiniband/sw/rxe/rxe_param.h b/drivers/infiniband/sw/rxe/rxe_param.h
index 4555510d86c4..bdea899a58ac 100644
--- a/drivers/infiniband/sw/rxe/rxe_param.h
+++ b/drivers/infiniband/sw/rxe/rxe_param.h
@@ -90,7 +90,6 @@ enum rxe_device_param {
RXE_MAX_RES_RD_ATOM = 0x3f000,
RXE_MAX_QP_INIT_RD_ATOM = 128,
RXE_MAX_EE_INIT_RD_ATOM = 0,
- RXE_ATOMIC_CAP = 1,
RXE_MAX_EE = 0,
RXE_MAX_RDD = 0,
RXE_MAX_MW = 0,
@@ -139,9 +138,6 @@ enum rxe_device_param {
/* default/initial rxe port parameters */
enum rxe_port_param {
- RXE_PORT_STATE = IB_PORT_DOWN,
- RXE_PORT_MAX_MTU = IB_MTU_4096,
- RXE_PORT_ACTIVE_MTU = IB_MTU_256,
RXE_PORT_GID_TBL_LEN = 1024,
RXE_PORT_PORT_CAP_FLAGS = RDMA_CORE_CAP_PROT_ROCE_UDP_ENCAP,
RXE_PORT_MAX_MSG_SZ = 0x800000,
diff --git a/drivers/infiniband/sw/rxe/rxe_pool.c b/drivers/infiniband/sw/rxe/rxe_pool.c
index b4a8acc7bb7d..36b53fb94a49 100644
--- a/drivers/infiniband/sw/rxe/rxe_pool.c
+++ b/drivers/infiniband/sw/rxe/rxe_pool.c
@@ -207,7 +207,7 @@ int rxe_pool_init(
kref_init(&pool->ref_cnt);
- spin_lock_init(&pool->pool_lock);
+ rwlock_init(&pool->pool_lock);
if (rxe_type_info[type].flags & RXE_POOL_INDEX) {
err = rxe_pool_init_index(pool,
@@ -222,7 +222,7 @@ int rxe_pool_init(
pool->key_size = rxe_type_info[type].key_size;
}
- pool->state = rxe_pool_valid;
+ pool->state = RXE_POOL_STATE_VALID;
out:
return err;
@@ -232,7 +232,7 @@ static void rxe_pool_release(struct kref *kref)
{
struct rxe_pool *pool = container_of(kref, struct rxe_pool, ref_cnt);
- pool->state = rxe_pool_invalid;
+ pool->state = RXE_POOL_STATE_INVALID;
kfree(pool->table);
}
@@ -245,12 +245,12 @@ int rxe_pool_cleanup(struct rxe_pool *pool)
{
unsigned long flags;
- spin_lock_irqsave(&pool->pool_lock, flags);
- pool->state = rxe_pool_invalid;
+ write_lock_irqsave(&pool->pool_lock, flags);
+ pool->state = RXE_POOL_STATE_INVALID;
if (atomic_read(&pool->num_elem) > 0)
pr_warn("%s pool destroyed with unfree'd elem\n",
pool_name(pool));
- spin_unlock_irqrestore(&pool->pool_lock, flags);
+ write_unlock_irqrestore(&pool->pool_lock, flags);
rxe_pool_put(pool);
@@ -336,10 +336,10 @@ void rxe_add_key(void *arg, void *key)
struct rxe_pool *pool = elem->pool;
unsigned long flags;
- spin_lock_irqsave(&pool->pool_lock, flags);
+ write_lock_irqsave(&pool->pool_lock, flags);
memcpy((u8 *)elem + pool->key_offset, key, pool->key_size);
insert_key(pool, elem);
- spin_unlock_irqrestore(&pool->pool_lock, flags);
+ write_unlock_irqrestore(&pool->pool_lock, flags);
}
void rxe_drop_key(void *arg)
@@ -348,9 +348,9 @@ void rxe_drop_key(void *arg)
struct rxe_pool *pool = elem->pool;
unsigned long flags;
- spin_lock_irqsave(&pool->pool_lock, flags);
+ write_lock_irqsave(&pool->pool_lock, flags);
rb_erase(&elem->node, &pool->tree);
- spin_unlock_irqrestore(&pool->pool_lock, flags);
+ write_unlock_irqrestore(&pool->pool_lock, flags);
}
void rxe_add_index(void *arg)
@@ -359,10 +359,10 @@ void rxe_add_index(void *arg)
struct rxe_pool *pool = elem->pool;
unsigned long flags;
- spin_lock_irqsave(&pool->pool_lock, flags);
+ write_lock_irqsave(&pool->pool_lock, flags);
elem->index = alloc_index(pool);
insert_index(pool, elem);
- spin_unlock_irqrestore(&pool->pool_lock, flags);
+ write_unlock_irqrestore(&pool->pool_lock, flags);
}
void rxe_drop_index(void *arg)
@@ -371,10 +371,10 @@ void rxe_drop_index(void *arg)
struct rxe_pool *pool = elem->pool;
unsigned long flags;
- spin_lock_irqsave(&pool->pool_lock, flags);
+ write_lock_irqsave(&pool->pool_lock, flags);
clear_bit(elem->index - pool->min_index, pool->table);
rb_erase(&elem->node, &pool->tree);
- spin_unlock_irqrestore(&pool->pool_lock, flags);
+ write_unlock_irqrestore(&pool->pool_lock, flags);
}
void *rxe_alloc(struct rxe_pool *pool)
@@ -384,13 +384,13 @@ void *rxe_alloc(struct rxe_pool *pool)
might_sleep_if(!(pool->flags & RXE_POOL_ATOMIC));
- spin_lock_irqsave(&pool->pool_lock, flags);
- if (pool->state != rxe_pool_valid) {
- spin_unlock_irqrestore(&pool->pool_lock, flags);
+ read_lock_irqsave(&pool->pool_lock, flags);
+ if (pool->state != RXE_POOL_STATE_VALID) {
+ read_unlock_irqrestore(&pool->pool_lock, flags);
return NULL;
}
kref_get(&pool->ref_cnt);
- spin_unlock_irqrestore(&pool->pool_lock, flags);
+ read_unlock_irqrestore(&pool->pool_lock, flags);
kref_get(&pool->rxe->ref_cnt);
@@ -436,9 +436,9 @@ void *rxe_pool_get_index(struct rxe_pool *pool, u32 index)
struct rxe_pool_entry *elem = NULL;
unsigned long flags;
- spin_lock_irqsave(&pool->pool_lock, flags);
+ read_lock_irqsave(&pool->pool_lock, flags);
- if (pool->state != rxe_pool_valid)
+ if (pool->state != RXE_POOL_STATE_VALID)
goto out;
node = pool->tree.rb_node;
@@ -450,15 +450,14 @@ void *rxe_pool_get_index(struct rxe_pool *pool, u32 index)
node = node->rb_left;
else if (elem->index < index)
node = node->rb_right;
- else
+ else {
+ kref_get(&elem->ref_cnt);
break;
+ }
}
- if (node)
- kref_get(&elem->ref_cnt);
-
out:
- spin_unlock_irqrestore(&pool->pool_lock, flags);
+ read_unlock_irqrestore(&pool->pool_lock, flags);
return node ? elem : NULL;
}
@@ -469,9 +468,9 @@ void *rxe_pool_get_key(struct rxe_pool *pool, void *key)
int cmp;
unsigned long flags;
- spin_lock_irqsave(&pool->pool_lock, flags);
+ read_lock_irqsave(&pool->pool_lock, flags);
- if (pool->state != rxe_pool_valid)
+ if (pool->state != RXE_POOL_STATE_VALID)
goto out;
node = pool->tree.rb_node;
@@ -494,6 +493,6 @@ void *rxe_pool_get_key(struct rxe_pool *pool, void *key)
kref_get(&elem->ref_cnt);
out:
- spin_unlock_irqrestore(&pool->pool_lock, flags);
+ read_unlock_irqrestore(&pool->pool_lock, flags);
return node ? elem : NULL;
}
diff --git a/drivers/infiniband/sw/rxe/rxe_pool.h b/drivers/infiniband/sw/rxe/rxe_pool.h
index 47df28e43acf..aa4ba307097b 100644
--- a/drivers/infiniband/sw/rxe/rxe_pool.h
+++ b/drivers/infiniband/sw/rxe/rxe_pool.h
@@ -74,8 +74,8 @@ struct rxe_type_info {
extern struct rxe_type_info rxe_type_info[];
enum rxe_pool_state {
- rxe_pool_invalid,
- rxe_pool_valid,
+ RXE_POOL_STATE_INVALID,
+ RXE_POOL_STATE_VALID,
};
struct rxe_pool_entry {
@@ -90,7 +90,7 @@ struct rxe_pool_entry {
struct rxe_pool {
struct rxe_dev *rxe;
- spinlock_t pool_lock; /* pool spinlock */
+ rwlock_t pool_lock; /* protects pool add/del/search */
size_t elem_size;
struct kref ref_cnt;
void (*cleanup)(struct rxe_pool_entry *obj);
diff --git a/drivers/infiniband/sw/rxe/rxe_qp.c b/drivers/infiniband/sw/rxe/rxe_qp.c
index c58452daffc7..b9710907dac2 100644
--- a/drivers/infiniband/sw/rxe/rxe_qp.c
+++ b/drivers/infiniband/sw/rxe/rxe_qp.c
@@ -34,6 +34,7 @@
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/sched.h>
+#include <linux/vmalloc.h>
#include "rxe.h"
#include "rxe_loc.h"
@@ -227,6 +228,16 @@ static int rxe_qp_init_req(struct rxe_dev *rxe, struct rxe_qp *qp,
return err;
qp->sk->sk->sk_user_data = qp;
+ /* pick a source UDP port number for this QP based on
+ * the source QPN. this spreads traffic for different QPs
+ * across different NIC RX queues (while using a single
+ * flow for a given QP to maintain packet order).
+ * the port number must be in the Dynamic Ports range
+ * (0xc000 - 0xffff).
+ */
+ qp->src_port = RXE_ROCE_V2_SPORT +
+ (hash_32_generic(qp_num(qp), 14) & 0x3fff);
+
qp->sq.max_wr = init->cap.max_send_wr;
qp->sq.max_sge = init->cap.max_send_sge;
qp->sq.max_inline = init->cap.max_inline_data;
@@ -247,7 +258,7 @@ static int rxe_qp_init_req(struct rxe_dev *rxe, struct rxe_qp *qp,
&qp->sq.queue->ip);
if (err) {
- kvfree(qp->sq.queue->buf);
+ vfree(qp->sq.queue->buf);
kfree(qp->sq.queue);
return err;
}
@@ -300,7 +311,7 @@ static int rxe_qp_init_resp(struct rxe_dev *rxe, struct rxe_qp *qp,
qp->rq.queue->buf, qp->rq.queue->buf_size,
&qp->rq.queue->ip);
if (err) {
- kvfree(qp->rq.queue->buf);
+ vfree(qp->rq.queue->buf);
kfree(qp->rq.queue);
return err;
}
@@ -408,8 +419,7 @@ int rxe_qp_chk_attr(struct rxe_dev *rxe, struct rxe_qp *qp,
enum ib_qp_state new_state = (mask & IB_QP_STATE) ?
attr->qp_state : cur_state;
- if (!ib_modify_qp_is_ok(cur_state, new_state, qp_type(qp), mask,
- IB_LINK_LAYER_ETHERNET)) {
+ if (!ib_modify_qp_is_ok(cur_state, new_state, qp_type(qp), mask)) {
pr_warn("invalid mask or state for qp\n");
goto err1;
}
diff --git a/drivers/infiniband/sw/rxe/rxe_recv.c b/drivers/infiniband/sw/rxe/rxe_recv.c
index d30dbac24583..5c29a1bb575a 100644
--- a/drivers/infiniband/sw/rxe/rxe_recv.c
+++ b/drivers/infiniband/sw/rxe/rxe_recv.c
@@ -122,7 +122,7 @@ static int check_keys(struct rxe_dev *rxe, struct rxe_pkt_info *pkt,
set_bad_pkey_cntr(port);
goto err1;
}
- } else if (qpn != 0) {
+ } else {
if (unlikely(!pkey_match(pkey,
port->pkey_tbl[qp->attr.pkey_index]
))) {
@@ -134,7 +134,7 @@ static int check_keys(struct rxe_dev *rxe, struct rxe_pkt_info *pkt,
}
if ((qp_type(qp) == IB_QPT_UD || qp_type(qp) == IB_QPT_GSI) &&
- qpn != 0 && pkt->mask) {
+ pkt->mask) {
u32 qkey = (qpn == 1) ? GSI_QKEY : qp->attr.qkey;
if (unlikely(deth_qkey(pkt) != qkey)) {
diff --git a/drivers/infiniband/sw/rxe/rxe_req.c b/drivers/infiniband/sw/rxe/rxe_req.c
index 8be27238a86e..6c361d70d7cd 100644
--- a/drivers/infiniband/sw/rxe/rxe_req.c
+++ b/drivers/infiniband/sw/rxe/rxe_req.c
@@ -73,9 +73,6 @@ static void req_retry(struct rxe_qp *qp)
int npsn;
int first = 1;
- wqe = queue_head(qp->sq.queue);
- npsn = (qp->comp.psn - wqe->first_psn) & BTH_PSN_MASK;
-
qp->req.wqe_index = consumer_index(qp->sq.queue);
qp->req.psn = qp->comp.psn;
qp->req.opcode = -1;
@@ -107,11 +104,17 @@ static void req_retry(struct rxe_qp *qp)
if (first) {
first = 0;
- if (mask & WR_WRITE_OR_SEND_MASK)
+ if (mask & WR_WRITE_OR_SEND_MASK) {
+ npsn = (qp->comp.psn - wqe->first_psn) &
+ BTH_PSN_MASK;
retry_first_write_send(qp, wqe, mask, npsn);
+ }
- if (mask & WR_READ_MASK)
+ if (mask & WR_READ_MASK) {
+ npsn = (wqe->dma.length - wqe->dma.resid) /
+ qp->mtu;
wqe->iova += npsn * qp->mtu;
+ }
}
wqe->state = wqe_state_posted;
@@ -435,7 +438,7 @@ static struct sk_buff *init_req_packet(struct rxe_qp *qp,
if (pkt->mask & RXE_RETH_MASK) {
reth_set_rkey(pkt, ibwr->wr.rdma.rkey);
reth_set_va(pkt, wqe->iova);
- reth_set_len(pkt, wqe->dma.length);
+ reth_set_len(pkt, wqe->dma.resid);
}
if (pkt->mask & RXE_IMMDT_MASK)
@@ -476,7 +479,7 @@ static int fill_packet(struct rxe_qp *qp, struct rxe_send_wqe *wqe,
u32 *p;
int err;
- err = rxe_prepare(rxe, pkt, skb, &crc);
+ err = rxe_prepare(pkt, skb, &crc);
if (err)
return err;
diff --git a/drivers/infiniband/sw/rxe/rxe_resp.c b/drivers/infiniband/sw/rxe/rxe_resp.c
index aa5833318372..c962160292f4 100644
--- a/drivers/infiniband/sw/rxe/rxe_resp.c
+++ b/drivers/infiniband/sw/rxe/rxe_resp.c
@@ -637,7 +637,7 @@ static struct sk_buff *prepare_ack_packet(struct rxe_qp *qp,
if (ack->mask & RXE_ATMACK_MASK)
atmack_set_orig(ack, qp->resp.atomic_orig);
- err = rxe_prepare(rxe, ack, skb, &crc);
+ err = rxe_prepare(ack, skb, &crc);
if (err) {
kfree_skb(skb);
return NULL;
@@ -682,6 +682,7 @@ static enum resp_states read_reply(struct rxe_qp *qp,
rxe_advance_resp_resource(qp);
res->type = RXE_READ_MASK;
+ res->replay = 0;
res->read.va = qp->resp.va;
res->read.va_org = qp->resp.va;
@@ -752,7 +753,8 @@ static enum resp_states read_reply(struct rxe_qp *qp,
state = RESPST_DONE;
} else {
qp->resp.res = NULL;
- qp->resp.opcode = -1;
+ if (!res->replay)
+ qp->resp.opcode = -1;
if (psn_compare(res->cur_psn, qp->resp.psn) >= 0)
qp->resp.psn = res->cur_psn;
state = RESPST_CLEANUP;
@@ -814,6 +816,7 @@ static enum resp_states execute(struct rxe_qp *qp, struct rxe_pkt_info *pkt)
/* next expected psn, read handles this separately */
qp->resp.psn = (pkt->psn + 1) & BTH_PSN_MASK;
+ qp->resp.ack_psn = qp->resp.psn;
qp->resp.opcode = pkt->opcode;
qp->resp.status = IB_WC_SUCCESS;
@@ -1065,7 +1068,7 @@ static enum resp_states duplicate_request(struct rxe_qp *qp,
struct rxe_pkt_info *pkt)
{
enum resp_states rc;
- u32 prev_psn = (qp->resp.psn - 1) & BTH_PSN_MASK;
+ u32 prev_psn = (qp->resp.ack_psn - 1) & BTH_PSN_MASK;
if (pkt->mask & RXE_SEND_MASK ||
pkt->mask & RXE_WRITE_MASK) {
@@ -1108,6 +1111,7 @@ static enum resp_states duplicate_request(struct rxe_qp *qp,
res->state = (pkt->psn == res->first_psn) ?
rdatm_res_state_new :
rdatm_res_state_replay;
+ res->replay = 1;
/* Reset the resource, except length. */
res->read.va_org = iova;
diff --git a/drivers/infiniband/sw/rxe/rxe_srq.c b/drivers/infiniband/sw/rxe/rxe_srq.c
index 0d6c04ba7fc3..c41a5fee81f7 100644
--- a/drivers/infiniband/sw/rxe/rxe_srq.c
+++ b/drivers/infiniband/sw/rxe/rxe_srq.c
@@ -31,6 +31,7 @@
* SOFTWARE.
*/
+#include <linux/vmalloc.h>
#include "rxe.h"
#include "rxe_loc.h"
#include "rxe_queue.h"
@@ -129,13 +130,18 @@ int rxe_srq_from_init(struct rxe_dev *rxe, struct rxe_srq *srq,
err = do_mmap_info(rxe, uresp ? &uresp->mi : NULL, context, q->buf,
q->buf_size, &q->ip);
- if (err)
+ if (err) {
+ vfree(q->buf);
+ kfree(q);
return err;
+ }
if (uresp) {
if (copy_to_user(&uresp->srq_num, &srq->srq_num,
- sizeof(uresp->srq_num)))
+ sizeof(uresp->srq_num))) {
+ rxe_queue_cleanup(q);
return -EFAULT;
+ }
}
return 0;
diff --git a/drivers/infiniband/sw/rxe/rxe_sysfs.c b/drivers/infiniband/sw/rxe/rxe_sysfs.c
index d5ed7571128f..73a19f808e1b 100644
--- a/drivers/infiniband/sw/rxe/rxe_sysfs.c
+++ b/drivers/infiniband/sw/rxe/rxe_sysfs.c
@@ -105,7 +105,7 @@ static int rxe_param_set_add(const char *val, const struct kernel_param *kp)
}
rxe_set_port_state(ndev);
- pr_info("added %s to %s\n", rxe->ib_dev.name, intf);
+ dev_info(&rxe->ib_dev.dev, "added %s\n", intf);
err:
if (ndev)
dev_put(ndev);
diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.c b/drivers/infiniband/sw/rxe/rxe_verbs.c
index f5b1e0ad6142..9c19f2027511 100644
--- a/drivers/infiniband/sw/rxe/rxe_verbs.c
+++ b/drivers/infiniband/sw/rxe/rxe_verbs.c
@@ -1148,18 +1148,21 @@ static ssize_t parent_show(struct device *device,
static DEVICE_ATTR_RO(parent);
-static struct device_attribute *rxe_dev_attributes[] = {
- &dev_attr_parent,
+static struct attribute *rxe_dev_attributes[] = {
+ &dev_attr_parent.attr,
+ NULL
+};
+
+static const struct attribute_group rxe_attr_group = {
+ .attrs = rxe_dev_attributes,
};
int rxe_register_device(struct rxe_dev *rxe)
{
int err;
- int i;
struct ib_device *dev = &rxe->ib_dev;
struct crypto_shash *tfm;
- strlcpy(dev->name, "rxe%d", IB_DEVICE_NAME_MAX);
strlcpy(dev->node_desc, "rxe", sizeof(dev->node_desc));
dev->owner = THIS_MODULE;
@@ -1260,26 +1263,16 @@ int rxe_register_device(struct rxe_dev *rxe)
}
rxe->tfm = tfm;
+ rdma_set_device_sysfs_group(dev, &rxe_attr_group);
dev->driver_id = RDMA_DRIVER_RXE;
- err = ib_register_device(dev, NULL);
+ err = ib_register_device(dev, "rxe%d", NULL);
if (err) {
pr_warn("%s failed with error %d\n", __func__, err);
goto err1;
}
- for (i = 0; i < ARRAY_SIZE(rxe_dev_attributes); ++i) {
- err = device_create_file(&dev->dev, rxe_dev_attributes[i]);
- if (err) {
- pr_warn("%s failed with error %d for attr number %d\n",
- __func__, err, i);
- goto err2;
- }
- }
-
return 0;
-err2:
- ib_unregister_device(dev);
err1:
crypto_free_shash(rxe->tfm);
@@ -1288,12 +1281,8 @@ err1:
int rxe_unregister_device(struct rxe_dev *rxe)
{
- int i;
struct ib_device *dev = &rxe->ib_dev;
- for (i = 0; i < ARRAY_SIZE(rxe_dev_attributes); ++i)
- device_remove_file(&dev->dev, rxe_dev_attributes[i]);
-
ib_unregister_device(dev);
return 0;
diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.h b/drivers/infiniband/sw/rxe/rxe_verbs.h
index af1470d29391..82e670d6eeea 100644
--- a/drivers/infiniband/sw/rxe/rxe_verbs.h
+++ b/drivers/infiniband/sw/rxe/rxe_verbs.h
@@ -158,6 +158,7 @@ struct rxe_comp_info {
int opcode;
int timeout;
int timeout_retry;
+ int started_retry;
u32 retry_cnt;
u32 rnr_retry;
struct rxe_task task;
@@ -171,6 +172,7 @@ enum rdatm_res_state {
struct resp_res {
int type;
+ int replay;
u32 first_psn;
u32 last_psn;
u32 cur_psn;
@@ -195,6 +197,7 @@ struct rxe_resp_info {
enum rxe_qp_state state;
u32 msn;
u32 psn;
+ u32 ack_psn;
int opcode;
int drop_msg;
int goto_error;
@@ -248,6 +251,7 @@ struct rxe_qp {
struct socket *sk;
u32 dst_cookie;
+ u16 src_port;
struct rxe_av pri_av;
struct rxe_av alt_av;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index 1abe3c62f106..1da119d901a9 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -499,8 +499,10 @@ void ipoib_reap_ah(struct work_struct *work);
struct ipoib_path *__path_find(struct net_device *dev, void *gid);
void ipoib_mark_paths_invalid(struct net_device *dev);
void ipoib_flush_paths(struct net_device *dev);
-struct ipoib_dev_priv *ipoib_intf_alloc(struct ib_device *hca, u8 port,
- const char *format);
+struct net_device *ipoib_intf_alloc(struct ib_device *hca, u8 port,
+ const char *format);
+int ipoib_intf_init(struct ib_device *hca, u8 port, const char *format,
+ struct net_device *dev);
void ipoib_ib_tx_timer_func(struct timer_list *t);
void ipoib_ib_dev_flush_light(struct work_struct *work);
void ipoib_ib_dev_flush_normal(struct work_struct *work);
@@ -531,6 +533,8 @@ int ipoib_dma_map_tx(struct ib_device *ca, struct ipoib_tx_buf *tx_req);
void ipoib_dma_unmap_tx(struct ipoib_dev_priv *priv,
struct ipoib_tx_buf *tx_req);
+struct rtnl_link_ops *ipoib_get_link_ops(void);
+
static inline void ipoib_build_sge(struct ipoib_dev_priv *priv,
struct ipoib_tx_buf *tx_req)
{
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
index 3d5424f335cb..0428e01e8f69 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
@@ -1438,11 +1438,15 @@ static void ipoib_cm_skb_reap(struct work_struct *work)
spin_unlock_irqrestore(&priv->lock, flags);
netif_tx_unlock_bh(dev);
- if (skb->protocol == htons(ETH_P_IP))
+ if (skb->protocol == htons(ETH_P_IP)) {
+ memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
+ }
#if IS_ENABLED(CONFIG_IPV6)
- else if (skb->protocol == htons(ETH_P_IPV6))
+ else if (skb->protocol == htons(ETH_P_IPV6)) {
+ memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
+ }
#endif
dev_kfree_skb_any(skb);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index e3d28f9ad9c0..8710214594d8 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -243,7 +243,8 @@ static int ipoib_change_mtu(struct net_device *dev, int new_mtu)
return 0;
}
- if (new_mtu > IPOIB_UD_MTU(priv->max_ib_mtu))
+ if (new_mtu < (ETH_MIN_MTU + IPOIB_ENCAP_LEN) ||
+ new_mtu > IPOIB_UD_MTU(priv->max_ib_mtu))
return -EINVAL;
priv->admin_mtu = new_mtu;
@@ -1880,6 +1881,8 @@ static int ipoib_parent_init(struct net_device *ndev)
sizeof(union ib_gid));
SET_NETDEV_DEV(priv->dev, priv->ca->dev.parent);
+ priv->dev->dev_port = priv->port - 1;
+ /* Let's set this one too for backwards compatibility. */
priv->dev->dev_id = priv->port - 1;
return 0;
@@ -2115,82 +2118,58 @@ static const struct net_device_ops ipoib_netdev_default_pf = {
.ndo_stop = ipoib_ib_dev_stop_default,
};
-static struct net_device
-*ipoib_create_netdev_default(struct ib_device *hca,
- const char *name,
- unsigned char name_assign_type,
- void (*setup)(struct net_device *))
+static struct net_device *ipoib_alloc_netdev(struct ib_device *hca, u8 port,
+ const char *name)
{
struct net_device *dev;
- struct rdma_netdev *rn;
- dev = alloc_netdev((int)sizeof(struct rdma_netdev),
- name,
- name_assign_type, setup);
- if (!dev)
- return NULL;
-
- rn = netdev_priv(dev);
-
- rn->send = ipoib_send;
- rn->attach_mcast = ipoib_mcast_attach;
- rn->detach_mcast = ipoib_mcast_detach;
- rn->hca = hca;
- dev->netdev_ops = &ipoib_netdev_default_pf;
-
- return dev;
-}
-
-static struct net_device *ipoib_get_netdev(struct ib_device *hca, u8 port,
- const char *name)
-{
- struct net_device *dev;
-
- if (hca->alloc_rdma_netdev) {
- dev = hca->alloc_rdma_netdev(hca, port,
- RDMA_NETDEV_IPOIB, name,
- NET_NAME_UNKNOWN,
- ipoib_setup_common);
- if (IS_ERR_OR_NULL(dev) && PTR_ERR(dev) != -EOPNOTSUPP)
- return NULL;
- }
-
- if (!hca->alloc_rdma_netdev || PTR_ERR(dev) == -EOPNOTSUPP)
- dev = ipoib_create_netdev_default(hca, name, NET_NAME_UNKNOWN,
- ipoib_setup_common);
+ dev = rdma_alloc_netdev(hca, port, RDMA_NETDEV_IPOIB, name,
+ NET_NAME_UNKNOWN, ipoib_setup_common);
+ if (!IS_ERR(dev) || PTR_ERR(dev) != -EOPNOTSUPP)
+ return dev;
+ dev = alloc_netdev(sizeof(struct rdma_netdev), name, NET_NAME_UNKNOWN,
+ ipoib_setup_common);
+ if (!dev)
+ return ERR_PTR(-ENOMEM);
return dev;
}
-struct ipoib_dev_priv *ipoib_intf_alloc(struct ib_device *hca, u8 port,
- const char *name)
+int ipoib_intf_init(struct ib_device *hca, u8 port, const char *name,
+ struct net_device *dev)
{
- struct net_device *dev;
+ struct rdma_netdev *rn = netdev_priv(dev);
struct ipoib_dev_priv *priv;
- struct rdma_netdev *rn;
+ int rc;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
- return NULL;
+ return -ENOMEM;
priv->ca = hca;
priv->port = port;
- dev = ipoib_get_netdev(hca, port, name);
- if (!dev)
- goto free_priv;
+ rc = rdma_init_netdev(hca, port, RDMA_NETDEV_IPOIB, name,
+ NET_NAME_UNKNOWN, ipoib_setup_common, dev);
+ if (rc) {
+ if (rc != -EOPNOTSUPP)
+ goto out;
+
+ dev->netdev_ops = &ipoib_netdev_default_pf;
+ rn->send = ipoib_send;
+ rn->attach_mcast = ipoib_mcast_attach;
+ rn->detach_mcast = ipoib_mcast_detach;
+ rn->hca = hca;
+ }
priv->rn_ops = dev->netdev_ops;
- /* fixme : should be after the query_cap */
- if (priv->hca_caps & IB_DEVICE_VIRTUAL_FUNCTION)
+ if (hca->attrs.device_cap_flags & IB_DEVICE_VIRTUAL_FUNCTION)
dev->netdev_ops = &ipoib_netdev_ops_vf;
else
dev->netdev_ops = &ipoib_netdev_ops_pf;
- rn = netdev_priv(dev);
rn->clnt_priv = priv;
-
/*
* Only the child register_netdev flows can handle priv_destructor
* being set, so we force it to NULL here and handle manually until it
@@ -2201,10 +2180,35 @@ struct ipoib_dev_priv *ipoib_intf_alloc(struct ib_device *hca, u8 port,
ipoib_build_priv(dev);
- return priv;
-free_priv:
+ return 0;
+
+out:
kfree(priv);
- return NULL;
+ return rc;
+}
+
+struct net_device *ipoib_intf_alloc(struct ib_device *hca, u8 port,
+ const char *name)
+{
+ struct net_device *dev;
+ int rc;
+
+ dev = ipoib_alloc_netdev(hca, port, name);
+ if (IS_ERR(dev))
+ return dev;
+
+ rc = ipoib_intf_init(hca, port, name, dev);
+ if (rc) {
+ free_netdev(dev);
+ return ERR_PTR(rc);
+ }
+
+ /*
+ * Upon success the caller must ensure ipoib_intf_free is called or
+ * register_netdevice succeed'd and priv_destructor is set to
+ * ipoib_intf_free.
+ */
+ return dev;
}
void ipoib_intf_free(struct net_device *dev)
@@ -2384,19 +2388,51 @@ int ipoib_add_pkey_attr(struct net_device *dev)
return device_create_file(&dev->dev, &dev_attr_pkey);
}
+/*
+ * We erroneously exposed the iface's port number in the dev_id
+ * sysfs field long after dev_port was introduced for that purpose[1],
+ * and we need to stop everyone from relying on that.
+ * Let's overload the shower routine for the dev_id file here
+ * to gently bring the issue up.
+ *
+ * [1] https://www.spinics.net/lists/netdev/msg272123.html
+ */
+static ssize_t dev_id_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct net_device *ndev = to_net_dev(dev);
+
+ if (ndev->dev_id == ndev->dev_port)
+ netdev_info_once(ndev,
+ "\"%s\" wants to know my dev_id. Should it look at dev_port instead? See Documentation/ABI/testing/sysfs-class-net for more info.\n",
+ current->comm);
+
+ return sprintf(buf, "%#x\n", ndev->dev_id);
+}
+static DEVICE_ATTR_RO(dev_id);
+
+int ipoib_intercept_dev_id_attr(struct net_device *dev)
+{
+ device_remove_file(&dev->dev, &dev_attr_dev_id);
+ return device_create_file(&dev->dev, &dev_attr_dev_id);
+}
+
static struct net_device *ipoib_add_port(const char *format,
struct ib_device *hca, u8 port)
{
+ struct rtnl_link_ops *ops = ipoib_get_link_ops();
+ struct rdma_netdev_alloc_params params;
struct ipoib_dev_priv *priv;
struct net_device *ndev;
int result;
- priv = ipoib_intf_alloc(hca, port, format);
- if (!priv) {
- pr_warn("%s, %d: ipoib_intf_alloc failed\n", hca->name, port);
- return ERR_PTR(-ENOMEM);
+ ndev = ipoib_intf_alloc(hca, port, format);
+ if (IS_ERR(ndev)) {
+ pr_warn("%s, %d: ipoib_intf_alloc failed %ld\n", hca->name, port,
+ PTR_ERR(ndev));
+ return ndev;
}
- ndev = priv->dev;
+ priv = ipoib_priv(ndev);
INIT_IB_EVENT_HANDLER(&priv->event_handler,
priv->ca, ipoib_event);
@@ -2417,6 +2453,14 @@ static struct net_device *ipoib_add_port(const char *format,
return ERR_PTR(result);
}
+ if (hca->rdma_netdev_get_params) {
+ int rc = hca->rdma_netdev_get_params(hca, port,
+ RDMA_NETDEV_IPOIB,
+ &params);
+
+ if (!rc && ops->priv_size < params.sizeof_priv)
+ ops->priv_size = params.sizeof_priv;
+ }
/*
* We cannot set priv_destructor before register_netdev because we
* need priv to be always valid during the error flow to execute
@@ -2425,6 +2469,8 @@ static struct net_device *ipoib_add_port(const char *format,
*/
ndev->priv_destructor = ipoib_intf_free;
+ if (ipoib_intercept_dev_id_attr(ndev))
+ goto sysfs_failed;
if (ipoib_cm_add_mode_attr(ndev))
goto sysfs_failed;
if (ipoib_add_pkey_attr(ndev))
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_netlink.c b/drivers/infiniband/ulp/ipoib/ipoib_netlink.c
index d4d553a51fa9..38c984d16996 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_netlink.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_netlink.c
@@ -122,12 +122,26 @@ static int ipoib_new_child_link(struct net *src_net, struct net_device *dev,
} else
child_pkey = nla_get_u16(data[IFLA_IPOIB_PKEY]);
+ err = ipoib_intf_init(ppriv->ca, ppriv->port, dev->name, dev);
+ if (err) {
+ ipoib_warn(ppriv, "failed to initialize pkey device\n");
+ return err;
+ }
+
err = __ipoib_vlan_add(ppriv, ipoib_priv(dev),
child_pkey, IPOIB_RTNL_CHILD);
+ if (err)
+ return err;
- if (!err && data)
+ if (data) {
err = ipoib_changelink(dev, tb, data, extack);
- return err;
+ if (err) {
+ unregister_netdevice(dev);
+ return err;
+ }
+ }
+
+ return 0;
}
static size_t ipoib_get_size(const struct net_device *dev)
@@ -149,6 +163,11 @@ static struct rtnl_link_ops ipoib_link_ops __read_mostly = {
.fill_info = ipoib_fill_info,
};
+struct rtnl_link_ops *ipoib_get_link_ops(void)
+{
+ return &ipoib_link_ops;
+}
+
int __init ipoib_netlink_init(void)
{
return rtnl_link_register(&ipoib_link_ops);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
index 9f36ca786df8..1e88213459f2 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
@@ -277,7 +277,7 @@ void ipoib_event(struct ib_event_handler *handler,
return;
ipoib_dbg(priv, "Event %d on device %s port %d\n", record->event,
- record->device->name, record->element.port_num);
+ dev_name(&record->device->dev), record->element.port_num);
if (record->event == IB_EVENT_SM_CHANGE ||
record->event == IB_EVENT_CLIENT_REREGISTER) {
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
index 341753fbda54..8ac8e18fbe0c 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
@@ -85,7 +85,7 @@ static bool is_child_unique(struct ipoib_dev_priv *ppriv,
/*
* NOTE: If this function fails then the priv->dev will remain valid, however
- * priv can have been freed and must not be touched by caller in the error
+ * priv will have been freed and must not be touched by caller in the error
* case.
*
* If (ndev->reg_state == NETREG_UNINITIALIZED) then it is up to the caller to
@@ -101,6 +101,12 @@ int __ipoib_vlan_add(struct ipoib_dev_priv *ppriv, struct ipoib_dev_priv *priv,
ASSERT_RTNL();
/*
+ * We do not need to touch priv if register_netdevice fails, so just
+ * always use this flow.
+ */
+ ndev->priv_destructor = ipoib_intf_free;
+
+ /*
* Racing with unregister of the parent must be prevented by the
* caller.
*/
@@ -120,9 +126,6 @@ int __ipoib_vlan_add(struct ipoib_dev_priv *ppriv, struct ipoib_dev_priv *priv,
goto out_early;
}
- /* We do not need to touch priv if register_netdevice fails */
- ndev->priv_destructor = ipoib_intf_free;
-
result = register_netdevice(ndev);
if (result) {
ipoib_warn(priv, "failed to initialize; error %i", result);
@@ -182,12 +185,12 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
snprintf(intf_name, sizeof(intf_name), "%s.%04x",
ppriv->dev->name, pkey);
- priv = ipoib_intf_alloc(ppriv->ca, ppriv->port, intf_name);
- if (!priv) {
- result = -ENOMEM;
+ ndev = ipoib_intf_alloc(ppriv->ca, ppriv->port, intf_name);
+ if (IS_ERR(ndev)) {
+ result = PTR_ERR(ndev);
goto out;
}
- ndev = priv->dev;
+ priv = ipoib_priv(ndev);
result = __ipoib_vlan_add(ppriv, priv, pkey, IPOIB_LEGACY_CHILD);
diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c
index 2f6388596f88..96af06cfe0af 100644
--- a/drivers/infiniband/ulp/iser/iser_initiator.c
+++ b/drivers/infiniband/ulp/iser/iser_initiator.c
@@ -589,13 +589,19 @@ void iser_login_rsp(struct ib_cq *cq, struct ib_wc *wc)
ib_conn->post_recv_buf_count--;
}
-static inline void
+static inline int
iser_inv_desc(struct iser_fr_desc *desc, u32 rkey)
{
- if (likely(rkey == desc->rsc.mr->rkey))
+ if (likely(rkey == desc->rsc.mr->rkey)) {
desc->rsc.mr_valid = 0;
- else if (likely(rkey == desc->pi_ctx->sig_mr->rkey))
+ } else if (likely(desc->pi_ctx && rkey == desc->pi_ctx->sig_mr->rkey)) {
desc->pi_ctx->sig_mr_valid = 0;
+ } else {
+ iser_err("Bogus remote invalidation for rkey %#x\n", rkey);
+ return -EINVAL;
+ }
+
+ return 0;
}
static int
@@ -623,12 +629,14 @@ iser_check_remote_inv(struct iser_conn *iser_conn,
if (iser_task->dir[ISER_DIR_IN]) {
desc = iser_task->rdma_reg[ISER_DIR_IN].mem_h;
- iser_inv_desc(desc, rkey);
+ if (unlikely(iser_inv_desc(desc, rkey)))
+ return -EINVAL;
}
if (iser_task->dir[ISER_DIR_OUT]) {
desc = iser_task->rdma_reg[ISER_DIR_OUT].mem_h;
- iser_inv_desc(desc, rkey);
+ if (unlikely(iser_inv_desc(desc, rkey)))
+ return -EINVAL;
}
} else {
iser_err("failed to get task for itt=%d\n", hdr->itt);
diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
index b686a4aaffe8..946b623ba5eb 100644
--- a/drivers/infiniband/ulp/iser/iser_verbs.c
+++ b/drivers/infiniband/ulp/iser/iser_verbs.c
@@ -55,7 +55,7 @@ static void iser_event_handler(struct ib_event_handler *handler,
{
iser_err("async event %s (%d) on device %s port %d\n",
ib_event_msg(event->event), event->event,
- event->device->name, event->element.port_num);
+ dev_name(&event->device->dev), event->element.port_num);
}
/**
@@ -85,7 +85,7 @@ static int iser_create_device_ib_res(struct iser_device *device)
max_cqe = min(ISER_MAX_CQ_LEN, ib_dev->attrs.max_cqe);
iser_info("using %d CQs, device %s supports %d vectors max_cqe %d\n",
- device->comps_used, ib_dev->name,
+ device->comps_used, dev_name(&ib_dev->dev),
ib_dev->num_comp_vectors, max_cqe);
device->pd = ib_alloc_pd(ib_dev,
@@ -468,7 +468,8 @@ static int iser_create_ib_conn_res(struct ib_conn *ib_conn)
iser_conn->max_cmds =
ISER_GET_MAX_XMIT_CMDS(ib_dev->attrs.max_qp_wr);
iser_dbg("device %s supports max_send_wr %d\n",
- device->ib_device->name, ib_dev->attrs.max_qp_wr);
+ dev_name(&device->ib_device->dev),
+ ib_dev->attrs.max_qp_wr);
}
}
@@ -764,7 +765,7 @@ static void iser_addr_handler(struct rdma_cm_id *cma_id)
IB_DEVICE_SIGNATURE_HANDOVER)) {
iser_warn("T10-PI requested but not supported on %s, "
"continue without T10-PI\n",
- ib_conn->device->ib_device->name);
+ dev_name(&ib_conn->device->ib_device->dev));
ib_conn->pi_support = false;
} else {
ib_conn->pi_support = true;
diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c
index f39670c5c25c..e3dd13798d79 100644
--- a/drivers/infiniband/ulp/isert/ib_isert.c
+++ b/drivers/infiniband/ulp/isert/ib_isert.c
@@ -262,7 +262,7 @@ isert_alloc_comps(struct isert_device *device)
isert_info("Using %d CQs, %s supports %d vectors support "
"pi_capable %d\n",
- device->comps_used, device->ib_device->name,
+ device->comps_used, dev_name(&device->ib_device->dev),
device->ib_device->num_comp_vectors,
device->pi_capable);
diff --git a/drivers/infiniband/ulp/opa_vnic/opa_vnic_encap.c b/drivers/infiniband/ulp/opa_vnic/opa_vnic_encap.c
index 267da8215e08..31cd361416ac 100644
--- a/drivers/infiniband/ulp/opa_vnic/opa_vnic_encap.c
+++ b/drivers/infiniband/ulp/opa_vnic/opa_vnic_encap.c
@@ -351,7 +351,8 @@ static uint32_t opa_vnic_get_dlid(struct opa_vnic_adapter *adapter,
if (unlikely(!dlid))
v_warn("Null dlid in MAC address\n");
} else if (def_port != OPA_VNIC_INVALID_PORT) {
- dlid = info->vesw.u_ucast_dlid[def_port];
+ if (def_port < OPA_VESW_MAX_NUM_DEF_PORT)
+ dlid = info->vesw.u_ucast_dlid[def_port];
}
}
diff --git a/drivers/infiniband/ulp/opa_vnic/opa_vnic_vema.c b/drivers/infiniband/ulp/opa_vnic/opa_vnic_vema.c
index 15711dcc6f58..d119d9afa845 100644
--- a/drivers/infiniband/ulp/opa_vnic/opa_vnic_vema.c
+++ b/drivers/infiniband/ulp/opa_vnic/opa_vnic_vema.c
@@ -888,7 +888,8 @@ static void opa_vnic_event(struct ib_event_handler *handler,
return;
c_dbg("OPA_VNIC received event %d on device %s port %d\n",
- record->event, record->device->name, record->element.port_num);
+ record->event, dev_name(&record->device->dev),
+ record->element.port_num);
if (record->event == IB_EVENT_PORT_ERR)
idr_for_each(&port->vport_idr, vema_disable_vport, NULL);
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 0b34e909505f..eed0eb3bb04c 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -1330,17 +1330,8 @@ static void srp_terminate_io(struct srp_rport *rport)
{
struct srp_target_port *target = rport->lld_data;
struct srp_rdma_ch *ch;
- struct Scsi_Host *shost = target->scsi_host;
- struct scsi_device *sdev;
int i, j;
- /*
- * Invoking srp_terminate_io() while srp_queuecommand() is running
- * is not safe. Hence the warning statement below.
- */
- shost_for_each_device(sdev, shost)
- WARN_ON_ONCE(sdev->request_queue->request_fn_active);
-
for (i = 0; i < target->ch_count; i++) {
ch = &target->ch[i];
@@ -3124,7 +3115,8 @@ static ssize_t show_local_ib_device(struct device *dev,
{
struct srp_target_port *target = host_to_target(class_to_shost(dev));
- return sprintf(buf, "%s\n", target->srp_host->srp_dev->dev->name);
+ return sprintf(buf, "%s\n",
+ dev_name(&target->srp_host->srp_dev->dev->dev));
}
static ssize_t show_ch_count(struct device *dev, struct device_attribute *attr,
@@ -3987,7 +3979,7 @@ static ssize_t show_ibdev(struct device *dev, struct device_attribute *attr,
{
struct srp_host *host = container_of(dev, struct srp_host, dev);
- return sprintf(buf, "%s\n", host->srp_dev->dev->name);
+ return sprintf(buf, "%s\n", dev_name(&host->srp_dev->dev->dev));
}
static DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL);
@@ -4019,7 +4011,8 @@ static struct srp_host *srp_add_port(struct srp_device *device, u8 port)
host->dev.class = &srp_class;
host->dev.parent = device->dev->dev.parent;
- dev_set_name(&host->dev, "srp-%s-%d", device->dev->name, port);
+ dev_set_name(&host->dev, "srp-%s-%d", dev_name(&device->dev->dev),
+ port);
if (device_register(&host->dev))
goto free_host;
@@ -4095,7 +4088,7 @@ static void srp_add_one(struct ib_device *device)
srp_dev->mr_max_size = srp_dev->mr_page_size *
srp_dev->max_pages_per_mr;
pr_debug("%s: mr_page_shift = %d, device->max_mr_size = %#llx, device->max_fast_reg_page_list_len = %u, max_pages_per_mr = %d, mr_max_size = %#x\n",
- device->name, mr_page_shift, attr->max_mr_size,
+ dev_name(&device->dev), mr_page_shift, attr->max_mr_size,
attr->max_fast_reg_page_list_len,
srp_dev->max_pages_per_mr, srp_dev->mr_max_size);
diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c
index f37cbad022a2..2357aa727dcf 100644
--- a/drivers/infiniband/ulp/srpt/ib_srpt.c
+++ b/drivers/infiniband/ulp/srpt/ib_srpt.c
@@ -148,7 +148,7 @@ static void srpt_event_handler(struct ib_event_handler *handler,
return;
pr_debug("ASYNC event= %d on device= %s\n", event->event,
- sdev->device->name);
+ dev_name(&sdev->device->dev));
switch (event->event) {
case IB_EVENT_PORT_ERR:
@@ -1941,7 +1941,8 @@ static void __srpt_close_all_ch(struct srpt_port *sport)
if (srpt_disconnect_ch(ch) >= 0)
pr_info("Closing channel %s because target %s_%d has been disabled\n",
ch->sess_name,
- sport->sdev->device->name, sport->port);
+ dev_name(&sport->sdev->device->dev),
+ sport->port);
srpt_close_ch(ch);
}
}
@@ -2127,7 +2128,7 @@ static int srpt_cm_req_recv(struct srpt_device *const sdev,
if (!sport->enabled) {
rej->reason = cpu_to_be32(SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES);
pr_info("rejected SRP_LOGIN_REQ because target port %s_%d has not yet been enabled\n",
- sport->sdev->device->name, port_num);
+ dev_name(&sport->sdev->device->dev), port_num);
goto reject;
}
@@ -2267,7 +2268,7 @@ static int srpt_cm_req_recv(struct srpt_device *const sdev,
rej->reason = cpu_to_be32(
SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES);
pr_info("rejected SRP_LOGIN_REQ because target %s_%d is not enabled\n",
- sdev->device->name, port_num);
+ dev_name(&sdev->device->dev), port_num);
mutex_unlock(&sport->mutex);
goto reject;
}
@@ -2708,7 +2709,7 @@ static void srpt_queue_response(struct se_cmd *cmd)
break;
}
- if (unlikely(WARN_ON_ONCE(state == SRPT_STATE_CMD_RSP_SENT)))
+ if (WARN_ON_ONCE(state == SRPT_STATE_CMD_RSP_SENT))
return;
/* For read commands, transfer the data to the initiator. */
@@ -2842,7 +2843,7 @@ static int srpt_release_sport(struct srpt_port *sport)
while (wait_event_timeout(sport->ch_releaseQ,
srpt_ch_list_empty(sport), 5 * HZ) <= 0) {
pr_info("%s_%d: waiting for session unregistration ...\n",
- sport->sdev->device->name, sport->port);
+ dev_name(&sport->sdev->device->dev), sport->port);
rcu_read_lock();
list_for_each_entry(nexus, &sport->nexus_list, entry) {
list_for_each_entry(ch, &nexus->ch_list, list) {
@@ -2932,7 +2933,7 @@ static int srpt_alloc_srq(struct srpt_device *sdev)
}
pr_debug("create SRQ #wr= %d max_allow=%d dev= %s\n", sdev->srq_size,
- sdev->device->attrs.max_srq_wr, device->name);
+ sdev->device->attrs.max_srq_wr, dev_name(&device->dev));
sdev->ioctx_ring = (struct srpt_recv_ioctx **)
srpt_alloc_ioctx_ring(sdev, sdev->srq_size,
@@ -2965,8 +2966,8 @@ static int srpt_use_srq(struct srpt_device *sdev, bool use_srq)
} else if (use_srq && !sdev->srq) {
ret = srpt_alloc_srq(sdev);
}
- pr_debug("%s(%s): use_srq = %d; ret = %d\n", __func__, device->name,
- sdev->use_srq, ret);
+ pr_debug("%s(%s): use_srq = %d; ret = %d\n", __func__,
+ dev_name(&device->dev), sdev->use_srq, ret);
return ret;
}
@@ -3052,7 +3053,7 @@ static void srpt_add_one(struct ib_device *device)
if (srpt_refresh_port(sport)) {
pr_err("MAD registration failed for %s-%d.\n",
- sdev->device->name, i);
+ dev_name(&sdev->device->dev), i);
goto err_event;
}
}
@@ -3063,7 +3064,7 @@ static void srpt_add_one(struct ib_device *device)
out:
ib_set_client_data(device, &srpt_client, sdev);
- pr_debug("added %s.\n", device->name);
+ pr_debug("added %s.\n", dev_name(&device->dev));
return;
err_event:
@@ -3078,7 +3079,7 @@ free_dev:
kfree(sdev);
err:
sdev = NULL;
- pr_info("%s(%s) failed.\n", __func__, device->name);
+ pr_info("%s(%s) failed.\n", __func__, dev_name(&device->dev));
goto out;
}
@@ -3093,7 +3094,8 @@ static void srpt_remove_one(struct ib_device *device, void *client_data)
int i;
if (!sdev) {
- pr_info("%s(%s): nothing to do.\n", __func__, device->name);
+ pr_info("%s(%s): nothing to do.\n", __func__,
+ dev_name(&device->dev));
return;
}
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 370206f987f9..f48369d6f3a0 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -564,6 +564,7 @@ static ssize_t evdev_write(struct file *file, const char __user *buffer,
input_inject_event(&evdev->handle,
event.type, event.code, event.value);
+ cond_resched();
}
out:
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index cd620e009bad..d4b9db487b16 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -231,6 +231,7 @@ static const struct xpad_device {
{ 0x0e6f, 0x0246, "Rock Candy Gamepad for Xbox One 2015", 0, XTYPE_XBOXONE },
{ 0x0e6f, 0x02ab, "PDP Controller for Xbox One", 0, XTYPE_XBOXONE },
{ 0x0e6f, 0x02a4, "PDP Wired Controller for Xbox One - Stealth Series", 0, XTYPE_XBOXONE },
+ { 0x0e6f, 0x02a6, "PDP Wired Controller for Xbox One - Camo Series", 0, XTYPE_XBOXONE },
{ 0x0e6f, 0x0301, "Logic3 Controller", 0, XTYPE_XBOX360 },
{ 0x0e6f, 0x0346, "Rock Candy Gamepad for Xbox One 2016", 0, XTYPE_XBOXONE },
{ 0x0e6f, 0x0401, "Logic3 Controller", 0, XTYPE_XBOX360 },
@@ -530,6 +531,8 @@ static const struct xboxone_init_packet xboxone_init_packets[] = {
XBOXONE_INIT_PKT(0x0e6f, 0x02ab, xboxone_pdp_init2),
XBOXONE_INIT_PKT(0x0e6f, 0x02a4, xboxone_pdp_init1),
XBOXONE_INIT_PKT(0x0e6f, 0x02a4, xboxone_pdp_init2),
+ XBOXONE_INIT_PKT(0x0e6f, 0x02a6, xboxone_pdp_init1),
+ XBOXONE_INIT_PKT(0x0e6f, 0x02a6, xboxone_pdp_init2),
XBOXONE_INIT_PKT(0x24c6, 0x541a, xboxone_rumblebegin_init),
XBOXONE_INIT_PKT(0x24c6, 0x542a, xboxone_rumblebegin_init),
XBOXONE_INIT_PKT(0x24c6, 0x543a, xboxone_rumblebegin_init),
diff --git a/drivers/input/keyboard/hilkbd.c b/drivers/input/keyboard/hilkbd.c
index 5c7afdec192c..f5c5ae8b6c06 100644
--- a/drivers/input/keyboard/hilkbd.c
+++ b/drivers/input/keyboard/hilkbd.c
@@ -2,7 +2,7 @@
* linux/drivers/hil/hilkbd.c
*
* Copyright (C) 1998 Philip Blundell <philb@gnu.org>
- * Copyright (C) 1999 Matthew Wilcox <willy@bofh.ai>
+ * Copyright (C) 1999 Matthew Wilcox <willy@infradead.org>
* Copyright (C) 1999-2007 Helge Deller <deller@gmx.de>
*
* Very basic HP Human Interface Loop (HIL) driver.
diff --git a/drivers/input/keyboard/sun4i-lradc-keys.c b/drivers/input/keyboard/sun4i-lradc-keys.c
index a37c172452e6..57272df34cd5 100644
--- a/drivers/input/keyboard/sun4i-lradc-keys.c
+++ b/drivers/input/keyboard/sun4i-lradc-keys.c
@@ -185,19 +185,19 @@ static int sun4i_lradc_load_dt_keymap(struct device *dev,
error = of_property_read_u32(pp, "channel", &channel);
if (error || channel != 0) {
- dev_err(dev, "%s: Inval channel prop\n", pp->name);
+ dev_err(dev, "%pOFn: Inval channel prop\n", pp);
return -EINVAL;
}
error = of_property_read_u32(pp, "voltage", &map->voltage);
if (error) {
- dev_err(dev, "%s: Inval voltage prop\n", pp->name);
+ dev_err(dev, "%pOFn: Inval voltage prop\n", pp);
return -EINVAL;
}
error = of_property_read_u32(pp, "linux,code", &map->keycode);
if (error) {
- dev_err(dev, "%s: Inval linux,code prop\n", pp->name);
+ dev_err(dev, "%pOFn: Inval linux,code prop\n", pp);
return -EINVAL;
}
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index eb14ddf69346..8ec483e8688b 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -598,6 +598,7 @@ static ssize_t uinput_inject_events(struct uinput_device *udev,
input_event(udev->dev, ev.type, ev.code, ev.value);
bytes += input_event_size();
+ cond_resched();
}
return bytes;
diff --git a/drivers/input/misc/xen-kbdfront.c b/drivers/input/misc/xen-kbdfront.c
index 594f72e39639..24bc5c5d876f 100644
--- a/drivers/input/misc/xen-kbdfront.c
+++ b/drivers/input/misc/xen-kbdfront.c
@@ -524,7 +524,7 @@ static void xenkbd_backend_changed(struct xenbus_device *dev,
case XenbusStateClosed:
if (dev->state == XenbusStateClosed)
break;
- /* Missed the backend's CLOSING state -- fallthrough */
+ /* fall through - Missed the backend's CLOSING state */
case XenbusStateClosing:
xenbus_frontend_closed(dev);
break;
diff --git a/drivers/input/mouse/cyapa_gen3.c b/drivers/input/mouse/cyapa_gen3.c
index 076dda4a66da..00e395dfc3d5 100644
--- a/drivers/input/mouse/cyapa_gen3.c
+++ b/drivers/input/mouse/cyapa_gen3.c
@@ -1067,7 +1067,7 @@ static int cyapa_gen3_do_operational_check(struct cyapa *cyapa)
return error;
}
- /* Fallthrough state */
+ /* Fall through */
case CYAPA_STATE_BL_IDLE:
/* Try to get firmware version in bootloader mode. */
cyapa_gen3_bl_query_data(cyapa);
@@ -1078,7 +1078,7 @@ static int cyapa_gen3_do_operational_check(struct cyapa *cyapa)
return error;
}
- /* Fallthrough state */
+ /* Fall through */
case CYAPA_STATE_OP:
/*
* Reading query data before going back to the full mode
diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c
index f5ae24865355..b0f9d19b3410 100644
--- a/drivers/input/mouse/elan_i2c_core.c
+++ b/drivers/input/mouse/elan_i2c_core.c
@@ -1346,6 +1346,7 @@ static const struct acpi_device_id elan_acpi_id[] = {
{ "ELAN0611", 0 },
{ "ELAN0612", 0 },
{ "ELAN0618", 0 },
+ { "ELAN061C", 0 },
{ "ELAN061D", 0 },
{ "ELAN0622", 0 },
{ "ELAN1000", 0 },
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 55d33500d55e..5e85f3cca867 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -99,9 +99,7 @@ static int synaptics_mode_cmd(struct psmouse *psmouse, u8 mode)
int synaptics_detect(struct psmouse *psmouse, bool set_properties)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
- u8 param[4];
-
- param[0] = 0;
+ u8 param[4] = { 0 };
ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index e08228061bcd..412fa71245af 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -707,6 +707,7 @@ static ssize_t mousedev_write(struct file *file, const char __user *buffer,
mousedev_generate_response(client, c);
spin_unlock_irq(&client->packet_lock);
+ cond_resched();
}
kill_fasync(&client->fasync, SIGIO, POLL_IN);
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index b8bc71569349..95a78ccbd847 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -1395,15 +1395,26 @@ static void __init i8042_register_ports(void)
for (i = 0; i < I8042_NUM_PORTS; i++) {
struct serio *serio = i8042_ports[i].serio;
- if (serio) {
- printk(KERN_INFO "serio: %s at %#lx,%#lx irq %d\n",
- serio->name,
- (unsigned long) I8042_DATA_REG,
- (unsigned long) I8042_COMMAND_REG,
- i8042_ports[i].irq);
- serio_register_port(serio);
- device_set_wakeup_capable(&serio->dev, true);
- }
+ if (!serio)
+ continue;
+
+ printk(KERN_INFO "serio: %s at %#lx,%#lx irq %d\n",
+ serio->name,
+ (unsigned long) I8042_DATA_REG,
+ (unsigned long) I8042_COMMAND_REG,
+ i8042_ports[i].irq);
+ serio_register_port(serio);
+ device_set_wakeup_capable(&serio->dev, true);
+
+ /*
+ * On platforms using suspend-to-idle, allow the keyboard to
+ * wake up the system from sleep by enabling keyboard wakeups
+ * by default. This is consistent with keyboard wakeup
+ * behavior on many platforms using suspend-to-RAM (ACPI S3)
+ * by default.
+ */
+ if (pm_suspend_via_s2idle() && i == I8042_KBD_PORT_NO)
+ device_set_wakeup_enable(&serio->dev, true);
}
}
diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c
index f8ead9f9c77e..5977b8a34ebe 100644
--- a/drivers/input/serio/serport.c
+++ b/drivers/input/serio/serport.c
@@ -226,7 +226,7 @@ static int serport_ldisc_ioctl(struct tty_struct *tty, struct file *file,
#ifdef CONFIG_COMPAT
#define COMPAT_SPIOCSTYPE _IOW('q', 0x01, compat_ulong_t)
-static long serport_ldisc_compat_ioctl(struct tty_struct *tty,
+static int serport_ldisc_compat_ioctl(struct tty_struct *tty,
struct file *file,
unsigned int cmd, unsigned long arg)
{
diff --git a/drivers/input/serio/xilinx_ps2.c b/drivers/input/serio/xilinx_ps2.c
index 07de1b49293c..6615c02a08fd 100644
--- a/drivers/input/serio/xilinx_ps2.c
+++ b/drivers/input/serio/xilinx_ps2.c
@@ -245,7 +245,7 @@ static int xps2_of_probe(struct platform_device *ofdev)
unsigned int irq;
int error;
- dev_info(dev, "Device Tree Probing \'%s\'\n", dev->of_node->name);
+ dev_info(dev, "Device Tree Probing \'%pOFn\'\n", dev->of_node);
/* Get iospace for the device */
error = of_address_to_resource(dev->of_node, 0, &r_mem);
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 3232af5dcf89..d3aacd534e9c 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -29,7 +29,6 @@
#include <linux/property.h>
#include <linux/slab.h>
#include <linux/gpio/consumer.h>
-#include <linux/property.h>
#include <asm/unaligned.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
@@ -489,7 +488,7 @@ static int mxt_lookup_bootloader_address(struct mxt_data *data, bool retry)
bootloader = appmode - 0x24;
break;
}
- /* Fall through for normal case */
+ /* Fall through - for normal case */
case 0x4c:
case 0x4d:
case 0x5a:
diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c
index d21ca39b0fdb..f2cb23121833 100644
--- a/drivers/input/touchscreen/elants_i2c.c
+++ b/drivers/input/touchscreen/elants_i2c.c
@@ -147,10 +147,11 @@ struct elants_data {
u8 cmd_resp[HEADER_SIZE];
struct completion cmd_done;
- u8 buf[MAX_PACKET_SIZE];
-
bool wake_irq_enabled;
bool keep_power_in_suspend;
+
+ /* Must be last to be used for DMA operations */
+ u8 buf[MAX_PACKET_SIZE] ____cacheline_aligned;
};
static int elants_i2c_send(struct i2c_client *client,
@@ -863,7 +864,7 @@ static irqreturn_t elants_i2c_irq(int irq, void *_dev)
int i;
int len;
- len = i2c_master_recv(client, ts->buf, sizeof(ts->buf));
+ len = i2c_master_recv_dmasafe(client, ts->buf, sizeof(ts->buf));
if (len < 0) {
dev_err(&client->dev, "%s: failed to read data: %d\n",
__func__, len);
diff --git a/drivers/input/touchscreen/of_touchscreen.c b/drivers/input/touchscreen/of_touchscreen.c
index 9642f103b726..6d241d45e312 100644
--- a/drivers/input/touchscreen/of_touchscreen.c
+++ b/drivers/input/touchscreen/of_touchscreen.c
@@ -35,7 +35,7 @@ static bool touchscreen_get_prop_u32(struct device *dev,
static void touchscreen_set_params(struct input_dev *dev,
unsigned long axis,
- int max, int fuzz)
+ int min, int max, int fuzz)
{
struct input_absinfo *absinfo;
@@ -47,6 +47,7 @@ static void touchscreen_set_params(struct input_dev *dev,
}
absinfo = &dev->absinfo[axis];
+ absinfo->minimum = min;
absinfo->maximum = max;
absinfo->fuzz = fuzz;
}
@@ -68,8 +69,9 @@ void touchscreen_parse_properties(struct input_dev *input, bool multitouch,
struct touchscreen_properties *prop)
{
struct device *dev = input->dev.parent;
+ struct input_absinfo *absinfo;
unsigned int axis;
- unsigned int maximum, fuzz;
+ unsigned int minimum, maximum, fuzz;
bool data_present;
input_alloc_absinfo(input);
@@ -77,7 +79,10 @@ void touchscreen_parse_properties(struct input_dev *input, bool multitouch,
return;
axis = multitouch ? ABS_MT_POSITION_X : ABS_X;
- data_present = touchscreen_get_prop_u32(dev, "touchscreen-size-x",
+ data_present = touchscreen_get_prop_u32(dev, "touchscreen-min-x",
+ input_abs_get_min(input, axis),
+ &minimum) |
+ touchscreen_get_prop_u32(dev, "touchscreen-size-x",
input_abs_get_max(input,
axis) + 1,
&maximum) |
@@ -85,10 +90,13 @@ void touchscreen_parse_properties(struct input_dev *input, bool multitouch,
input_abs_get_fuzz(input, axis),
&fuzz);
if (data_present)
- touchscreen_set_params(input, axis, maximum - 1, fuzz);
+ touchscreen_set_params(input, axis, minimum, maximum - 1, fuzz);
axis = multitouch ? ABS_MT_POSITION_Y : ABS_Y;
- data_present = touchscreen_get_prop_u32(dev, "touchscreen-size-y",
+ data_present = touchscreen_get_prop_u32(dev, "touchscreen-min-y",
+ input_abs_get_min(input, axis),
+ &minimum) |
+ touchscreen_get_prop_u32(dev, "touchscreen-size-y",
input_abs_get_max(input,
axis) + 1,
&maximum) |
@@ -96,7 +104,7 @@ void touchscreen_parse_properties(struct input_dev *input, bool multitouch,
input_abs_get_fuzz(input, axis),
&fuzz);
if (data_present)
- touchscreen_set_params(input, axis, maximum - 1, fuzz);
+ touchscreen_set_params(input, axis, minimum, maximum - 1, fuzz);
axis = multitouch ? ABS_MT_PRESSURE : ABS_PRESSURE;
data_present = touchscreen_get_prop_u32(dev,
@@ -108,7 +116,7 @@ void touchscreen_parse_properties(struct input_dev *input, bool multitouch,
input_abs_get_fuzz(input, axis),
&fuzz);
if (data_present)
- touchscreen_set_params(input, axis, maximum, fuzz);
+ touchscreen_set_params(input, axis, 0, maximum, fuzz);
if (!prop)
return;
@@ -117,13 +125,25 @@ void touchscreen_parse_properties(struct input_dev *input, bool multitouch,
prop->max_x = input_abs_get_max(input, axis);
prop->max_y = input_abs_get_max(input, axis + 1);
+
prop->invert_x =
device_property_read_bool(dev, "touchscreen-inverted-x");
+ if (prop->invert_x) {
+ absinfo = &input->absinfo[axis];
+ absinfo->maximum -= absinfo->minimum;
+ absinfo->minimum = 0;
+ }
+
prop->invert_y =
device_property_read_bool(dev, "touchscreen-inverted-y");
+ if (prop->invert_y) {
+ absinfo = &input->absinfo[axis + 1];
+ absinfo->maximum -= absinfo->minimum;
+ absinfo->minimum = 0;
+ }
+
prop->swap_x_y =
device_property_read_bool(dev, "touchscreen-swapped-x-y");
-
if (prop->swap_x_y)
swap(input->absinfo[axis], input->absinfo[axis + 1]);
}
diff --git a/drivers/input/touchscreen/silead.c b/drivers/input/touchscreen/silead.c
index d196ac3d8b8c..09241d4cdebc 100644
--- a/drivers/input/touchscreen/silead.c
+++ b/drivers/input/touchscreen/silead.c
@@ -558,20 +558,33 @@ static int __maybe_unused silead_ts_suspend(struct device *dev)
static int __maybe_unused silead_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
+ bool second_try = false;
int error, status;
silead_ts_set_power(client, SILEAD_POWER_ON);
+ retry:
error = silead_ts_reset(client);
if (error)
return error;
+ if (second_try) {
+ error = silead_ts_load_fw(client);
+ if (error)
+ return error;
+ }
+
error = silead_ts_startup(client);
if (error)
return error;
status = silead_ts_get_status(client);
if (status != SILEAD_STATUS_OK) {
+ if (!second_try) {
+ second_try = true;
+ dev_dbg(dev, "Reloading firmware after unsuccessful resume\n");
+ goto retry;
+ }
dev_err(dev, "Resume error, status: 0x%02x\n", status);
return -ENODEV;
}
diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c
index d5dfa4053bbf..b71673911aac 100644
--- a/drivers/input/touchscreen/st1232.c
+++ b/drivers/input/touchscreen/st1232.c
@@ -195,6 +195,7 @@ static int st1232_ts_probe(struct i2c_client *client,
input_dev->id.bustype = BUS_I2C;
input_dev->dev.parent = &client->dev;
+ __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
__set_bit(EV_SYN, input_dev->evbit);
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(EV_ABS, input_dev->evbit);
diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c
index b86c1e5fbc11..9e8684ab48f4 100644
--- a/drivers/input/touchscreen/ti_am335x_tsc.c
+++ b/drivers/input/touchscreen/ti_am335x_tsc.c
@@ -27,6 +27,7 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/sort.h>
+#include <linux/pm_wakeirq.h>
#include <linux/mfd/ti_am335x_tscadc.h>
@@ -46,6 +47,7 @@ static const int config_pins[] = {
struct titsc {
struct input_dev *input;
struct ti_tscadc_dev *mfd_tscadc;
+ struct device *dev;
unsigned int irq;
unsigned int wires;
unsigned int x_plate_resistance;
@@ -276,7 +278,7 @@ static irqreturn_t titsc_irq(int irq, void *dev)
if (status & IRQENB_HW_PEN) {
ts_dev->pen_down = true;
irqclr |= IRQENB_HW_PEN;
- pm_stay_awake(ts_dev->mfd_tscadc->dev);
+ pm_stay_awake(ts_dev->dev);
}
if (status & IRQENB_PENUP) {
@@ -286,7 +288,7 @@ static irqreturn_t titsc_irq(int irq, void *dev)
input_report_key(input_dev, BTN_TOUCH, 0);
input_report_abs(input_dev, ABS_PRESSURE, 0);
input_sync(input_dev);
- pm_relax(ts_dev->mfd_tscadc->dev);
+ pm_relax(ts_dev->dev);
} else {
ts_dev->pen_down = true;
}
@@ -422,6 +424,7 @@ static int titsc_probe(struct platform_device *pdev)
ts_dev->mfd_tscadc = tscadc_dev;
ts_dev->input = input_dev;
ts_dev->irq = tscadc_dev->irq;
+ ts_dev->dev = &pdev->dev;
err = titsc_parse_dt(pdev, ts_dev);
if (err) {
@@ -436,6 +439,11 @@ static int titsc_probe(struct platform_device *pdev)
goto err_free_mem;
}
+ device_init_wakeup(&pdev->dev, true);
+ err = dev_pm_set_wake_irq(&pdev->dev, ts_dev->irq);
+ if (err)
+ dev_err(&pdev->dev, "irq wake enable failed.\n");
+
titsc_writel(ts_dev, REG_IRQSTATUS, TSC_IRQENB_MASK);
titsc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO0THRES);
titsc_writel(ts_dev, REG_IRQENABLE, IRQENB_EOS);
@@ -467,6 +475,8 @@ static int titsc_probe(struct platform_device *pdev)
return 0;
err_free_irq:
+ dev_pm_clear_wake_irq(&pdev->dev);
+ device_init_wakeup(&pdev->dev, false);
free_irq(ts_dev->irq, ts_dev);
err_free_mem:
input_free_device(input_dev);
@@ -479,6 +489,8 @@ static int titsc_remove(struct platform_device *pdev)
struct titsc *ts_dev = platform_get_drvdata(pdev);
u32 steps;
+ dev_pm_clear_wake_irq(&pdev->dev);
+ device_init_wakeup(&pdev->dev, false);
free_irq(ts_dev->irq, ts_dev);
/* total steps followed by the enable mask */
@@ -499,7 +511,7 @@ static int __maybe_unused titsc_suspend(struct device *dev)
unsigned int idle;
tscadc_dev = ti_tscadc_dev_get(to_platform_device(dev));
- if (device_may_wakeup(tscadc_dev->dev)) {
+ if (device_may_wakeup(dev)) {
titsc_writel(ts_dev, REG_IRQSTATUS, TSC_IRQENB_MASK);
idle = titsc_readl(ts_dev, REG_IRQENABLE);
titsc_writel(ts_dev, REG_IRQENABLE,
@@ -515,11 +527,11 @@ static int __maybe_unused titsc_resume(struct device *dev)
struct ti_tscadc_dev *tscadc_dev;
tscadc_dev = ti_tscadc_dev_get(to_platform_device(dev));
- if (device_may_wakeup(tscadc_dev->dev)) {
+ if (device_may_wakeup(dev)) {
titsc_writel(ts_dev, REG_IRQWAKEUP,
0x00);
titsc_writel(ts_dev, REG_IRQCLR, IRQENB_HW_PEN);
- pm_relax(ts_dev->mfd_tscadc->dev);
+ pm_relax(dev);
}
titsc_step_config(ts_dev);
titsc_writel(ts_dev, REG_FIFO0THR,
diff --git a/drivers/input/touchscreen/tsc200x-core.c b/drivers/input/touchscreen/tsc200x-core.c
index e0fde590df8e..62973ac01381 100644
--- a/drivers/input/touchscreen/tsc200x-core.c
+++ b/drivers/input/touchscreen/tsc200x-core.c
@@ -68,7 +68,8 @@ const struct regmap_config tsc200x_regmap_config = {
.read_flag_mask = TSC200X_REG_READ,
.write_flag_mask = TSC200X_REG_PND0,
.wr_table = &tsc200x_writable_table,
- .use_single_rw = true,
+ .use_single_read = true,
+ .use_single_write = true,
};
EXPORT_SYMBOL_GPL(tsc200x_regmap_config);
diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c
index 2566b4d8b342..73856c2a8ac0 100644
--- a/drivers/input/touchscreen/wm97xx-core.c
+++ b/drivers/input/touchscreen/wm97xx-core.c
@@ -929,7 +929,8 @@ static int __init wm97xx_init(void)
static void __exit wm97xx_exit(void)
{
- driver_unregister(&wm97xx_driver);
+ if (IS_BUILTIN(CONFIG_AC97_BUS))
+ driver_unregister(&wm97xx_driver);
platform_driver_unregister(&wm97xx_mfd_driver);
}
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index c60395b7470f..d9a25715650e 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -186,6 +186,19 @@ config INTEL_IOMMU
and include PCI device scope covered by these DMA
remapping devices.
+config INTEL_IOMMU_DEBUGFS
+ bool "Export Intel IOMMU internals in Debugfs"
+ depends on INTEL_IOMMU && IOMMU_DEBUGFS
+ help
+ !!!WARNING!!!
+
+ DO NOT ENABLE THIS OPTION UNLESS YOU REALLY KNOW WHAT YOU ARE DOING!!!
+
+ Expose Intel IOMMU internals in Debugfs.
+
+ This option is -NOT- intended for production environments, and should
+ only be enabled for debugging Intel IOMMU.
+
config INTEL_IOMMU_SVM
bool "Support for Shared Virtual Memory with Intel IOMMU"
depends on INTEL_IOMMU && X86
@@ -372,6 +385,14 @@ config S390_CCW_IOMMU
Enables bits of IOMMU API required by VFIO. The iommu_ops
is not implemented as it is not necessary for VFIO.
+config S390_AP_IOMMU
+ bool "S390 AP IOMMU Support"
+ depends on S390 && ZCRYPT
+ select IOMMU_API
+ help
+ Enables bits of IOMMU API required by VFIO. The iommu_ops
+ is not implemented as it is not necessary for VFIO.
+
config MTK_IOMMU
bool "MTK IOMMU Support"
depends on ARM || ARM64
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index ab5eba6edf82..a158a68c8ea8 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_ARM_SMMU) += arm-smmu.o
obj-$(CONFIG_ARM_SMMU_V3) += arm-smmu-v3.o
obj-$(CONFIG_DMAR_TABLE) += dmar.o
obj-$(CONFIG_INTEL_IOMMU) += intel-iommu.o intel-pasid.o
+obj-$(CONFIG_INTEL_IOMMU_DEBUGFS) += intel-iommu-debugfs.o
obj-$(CONFIG_INTEL_IOMMU_SVM) += intel-svm.o
obj-$(CONFIG_IPMMU_VMSA) += ipmmu-vmsa.o
obj-$(CONFIG_IRQ_REMAP) += intel_irq_remapping.o irq_remapping.o
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 73e47d93e7a0..1167ff0416cf 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -3069,7 +3069,7 @@ static phys_addr_t amd_iommu_iova_to_phys(struct iommu_domain *dom,
return 0;
offset_mask = pte_pgsize - 1;
- __pte = *pte & PM_ADDR_MASK;
+ __pte = __sme_clr(*pte & PM_ADDR_MASK);
return (__pte & ~offset_mask) | (iova & offset_mask);
}
@@ -3083,6 +3083,8 @@ static bool amd_iommu_capable(enum iommu_cap cap)
return (irq_remapping_enabled == 1);
case IOMMU_CAP_NOEXEC:
return false;
+ default:
+ break;
}
return false;
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index 84b3e4445d46..bb2cd29e1658 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -902,12 +902,22 @@ static bool copy_device_table(void)
}
}
- old_devtb_phys = entry & PAGE_MASK;
+ /*
+ * When SME is enabled in the first kernel, the entry includes the
+ * memory encryption mask(sme_me_mask), we must remove the memory
+ * encryption mask to obtain the true physical address in kdump kernel.
+ */
+ old_devtb_phys = __sme_clr(entry) & PAGE_MASK;
+
if (old_devtb_phys >= 0x100000000ULL) {
pr_err("The address of old device table is above 4G, not trustworthy!\n");
return false;
}
- old_devtb = memremap(old_devtb_phys, dev_table_size, MEMREMAP_WB);
+ old_devtb = (sme_active() && is_kdump_kernel())
+ ? (__force void *)ioremap_encrypted(old_devtb_phys,
+ dev_table_size)
+ : memremap(old_devtb_phys, dev_table_size, MEMREMAP_WB);
+
if (!old_devtb)
return false;
@@ -1709,7 +1719,7 @@ static const struct attribute_group *amd_iommu_groups[] = {
NULL,
};
-static int iommu_init_pci(struct amd_iommu *iommu)
+static int __init iommu_init_pci(struct amd_iommu *iommu)
{
int cap_ptr = iommu->cap_ptr;
u32 range, misc, low, high;
diff --git a/drivers/iommu/amd_iommu_v2.c b/drivers/iommu/amd_iommu_v2.c
index 58da65df03f5..fd552235bd13 100644
--- a/drivers/iommu/amd_iommu_v2.c
+++ b/drivers/iommu/amd_iommu_v2.c
@@ -427,7 +427,6 @@ static void mn_release(struct mmu_notifier *mn, struct mm_struct *mm)
}
static const struct mmu_notifier_ops iommu_mn = {
- .flags = MMU_INVALIDATE_DOES_NOT_BLOCK,
.release = mn_release,
.clear_flush_young = mn_clear_flush_young,
.invalidate_range = mn_invalidate_range,
diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index 5059d09f3202..6947ccf26512 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* IOMMU API for ARM architected SMMUv3 implementations.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
* Copyright (C) 2015 ARM Limited
*
* Author: Will Deacon <will.deacon@arm.com>
@@ -567,7 +556,8 @@ struct arm_smmu_device {
int gerr_irq;
int combined_irq;
- atomic_t sync_nr;
+ u32 sync_nr;
+ u8 prev_cmd_opcode;
unsigned long ias; /* IPA */
unsigned long oas; /* PA */
@@ -611,6 +601,7 @@ struct arm_smmu_domain {
struct mutex init_mutex; /* Protects smmu pointer */
struct io_pgtable_ops *pgtbl_ops;
+ bool non_strict;
enum arm_smmu_domain_stage stage;
union {
@@ -708,7 +699,7 @@ static void queue_inc_prod(struct arm_smmu_queue *q)
}
/*
- * Wait for the SMMU to consume items. If drain is true, wait until the queue
+ * Wait for the SMMU to consume items. If sync is true, wait until the queue
* is empty. Otherwise, wait until there is at least one free slot.
*/
static int queue_poll_cons(struct arm_smmu_queue *q, bool sync, bool wfe)
@@ -901,6 +892,8 @@ static void arm_smmu_cmdq_insert_cmd(struct arm_smmu_device *smmu, u64 *cmd)
struct arm_smmu_queue *q = &smmu->cmdq.q;
bool wfe = !!(smmu->features & ARM_SMMU_FEAT_SEV);
+ smmu->prev_cmd_opcode = FIELD_GET(CMDQ_0_OP, cmd[0]);
+
while (queue_insert_raw(q, cmd) == -ENOSPC) {
if (queue_poll_cons(q, false, wfe))
dev_err_ratelimited(smmu->dev, "CMDQ timeout\n");
@@ -948,15 +941,21 @@ static int __arm_smmu_cmdq_issue_sync_msi(struct arm_smmu_device *smmu)
struct arm_smmu_cmdq_ent ent = {
.opcode = CMDQ_OP_CMD_SYNC,
.sync = {
- .msidata = atomic_inc_return_relaxed(&smmu->sync_nr),
.msiaddr = virt_to_phys(&smmu->sync_count),
},
};
- arm_smmu_cmdq_build_cmd(cmd, &ent);
-
spin_lock_irqsave(&smmu->cmdq.lock, flags);
- arm_smmu_cmdq_insert_cmd(smmu, cmd);
+
+ /* Piggy-back on the previous command if it's a SYNC */
+ if (smmu->prev_cmd_opcode == CMDQ_OP_CMD_SYNC) {
+ ent.sync.msidata = smmu->sync_nr;
+ } else {
+ ent.sync.msidata = ++smmu->sync_nr;
+ arm_smmu_cmdq_build_cmd(cmd, &ent);
+ arm_smmu_cmdq_insert_cmd(smmu, cmd);
+ }
+
spin_unlock_irqrestore(&smmu->cmdq.lock, flags);
return __arm_smmu_sync_poll_msi(smmu, ent.sync.msidata);
@@ -1372,15 +1371,11 @@ static irqreturn_t arm_smmu_combined_irq_handler(int irq, void *dev)
}
/* IO_PGTABLE API */
-static void __arm_smmu_tlb_sync(struct arm_smmu_device *smmu)
-{
- arm_smmu_cmdq_issue_sync(smmu);
-}
-
static void arm_smmu_tlb_sync(void *cookie)
{
struct arm_smmu_domain *smmu_domain = cookie;
- __arm_smmu_tlb_sync(smmu_domain->smmu);
+
+ arm_smmu_cmdq_issue_sync(smmu_domain->smmu);
}
static void arm_smmu_tlb_inv_context(void *cookie)
@@ -1398,8 +1393,14 @@ static void arm_smmu_tlb_inv_context(void *cookie)
cmd.tlbi.vmid = smmu_domain->s2_cfg.vmid;
}
+ /*
+ * NOTE: when io-pgtable is in non-strict mode, we may get here with
+ * PTEs previously cleared by unmaps on the current CPU not yet visible
+ * to the SMMU. We are relying on the DSB implicit in queue_inc_prod()
+ * to guarantee those are observed before the TLBI. Do be careful, 007.
+ */
arm_smmu_cmdq_issue_cmd(smmu, &cmd);
- __arm_smmu_tlb_sync(smmu);
+ arm_smmu_cmdq_issue_sync(smmu);
}
static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size,
@@ -1624,6 +1625,9 @@ static int arm_smmu_domain_finalise(struct iommu_domain *domain)
if (smmu->features & ARM_SMMU_FEAT_COHERENCY)
pgtbl_cfg.quirks = IO_PGTABLE_QUIRK_NO_DMA;
+ if (smmu_domain->non_strict)
+ pgtbl_cfg.quirks |= IO_PGTABLE_QUIRK_NON_STRICT;
+
pgtbl_ops = alloc_io_pgtable_ops(fmt, &pgtbl_cfg, smmu_domain);
if (!pgtbl_ops)
return -ENOMEM;
@@ -1772,12 +1776,20 @@ arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size)
return ops->unmap(ops, iova, size);
}
+static void arm_smmu_flush_iotlb_all(struct iommu_domain *domain)
+{
+ struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+
+ if (smmu_domain->smmu)
+ arm_smmu_tlb_inv_context(smmu_domain);
+}
+
static void arm_smmu_iotlb_sync(struct iommu_domain *domain)
{
struct arm_smmu_device *smmu = to_smmu_domain(domain)->smmu;
if (smmu)
- __arm_smmu_tlb_sync(smmu);
+ arm_smmu_cmdq_issue_sync(smmu);
}
static phys_addr_t
@@ -1917,15 +1929,27 @@ static int arm_smmu_domain_get_attr(struct iommu_domain *domain,
{
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
- if (domain->type != IOMMU_DOMAIN_UNMANAGED)
- return -EINVAL;
-
- switch (attr) {
- case DOMAIN_ATTR_NESTING:
- *(int *)data = (smmu_domain->stage == ARM_SMMU_DOMAIN_NESTED);
- return 0;
+ switch (domain->type) {
+ case IOMMU_DOMAIN_UNMANAGED:
+ switch (attr) {
+ case DOMAIN_ATTR_NESTING:
+ *(int *)data = (smmu_domain->stage == ARM_SMMU_DOMAIN_NESTED);
+ return 0;
+ default:
+ return -ENODEV;
+ }
+ break;
+ case IOMMU_DOMAIN_DMA:
+ switch (attr) {
+ case DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE:
+ *(int *)data = smmu_domain->non_strict;
+ return 0;
+ default:
+ return -ENODEV;
+ }
+ break;
default:
- return -ENODEV;
+ return -EINVAL;
}
}
@@ -1935,26 +1959,37 @@ static int arm_smmu_domain_set_attr(struct iommu_domain *domain,
int ret = 0;
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
- if (domain->type != IOMMU_DOMAIN_UNMANAGED)
- return -EINVAL;
-
mutex_lock(&smmu_domain->init_mutex);
- switch (attr) {
- case DOMAIN_ATTR_NESTING:
- if (smmu_domain->smmu) {
- ret = -EPERM;
- goto out_unlock;
+ switch (domain->type) {
+ case IOMMU_DOMAIN_UNMANAGED:
+ switch (attr) {
+ case DOMAIN_ATTR_NESTING:
+ if (smmu_domain->smmu) {
+ ret = -EPERM;
+ goto out_unlock;
+ }
+
+ if (*(int *)data)
+ smmu_domain->stage = ARM_SMMU_DOMAIN_NESTED;
+ else
+ smmu_domain->stage = ARM_SMMU_DOMAIN_S1;
+ break;
+ default:
+ ret = -ENODEV;
+ }
+ break;
+ case IOMMU_DOMAIN_DMA:
+ switch(attr) {
+ case DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE:
+ smmu_domain->non_strict = *(int *)data;
+ break;
+ default:
+ ret = -ENODEV;
}
-
- if (*(int *)data)
- smmu_domain->stage = ARM_SMMU_DOMAIN_NESTED;
- else
- smmu_domain->stage = ARM_SMMU_DOMAIN_S1;
-
break;
default:
- ret = -ENODEV;
+ ret = -EINVAL;
}
out_unlock:
@@ -1999,7 +2034,7 @@ static struct iommu_ops arm_smmu_ops = {
.attach_dev = arm_smmu_attach_dev,
.map = arm_smmu_map,
.unmap = arm_smmu_unmap,
- .flush_iotlb_all = arm_smmu_iotlb_sync,
+ .flush_iotlb_all = arm_smmu_flush_iotlb_all,
.iotlb_sync = arm_smmu_iotlb_sync,
.iova_to_phys = arm_smmu_iova_to_phys,
.add_device = arm_smmu_add_device,
@@ -2180,7 +2215,6 @@ static int arm_smmu_init_structures(struct arm_smmu_device *smmu)
{
int ret;
- atomic_set(&smmu->sync_nr, 0);
ret = arm_smmu_init_queues(smmu);
if (ret)
return ret;
@@ -2353,8 +2387,8 @@ static int arm_smmu_setup_irqs(struct arm_smmu_device *smmu)
irq = smmu->combined_irq;
if (irq) {
/*
- * Cavium ThunderX2 implementation doesn't not support unique
- * irq lines. Use single irq line for all the SMMUv3 interrupts.
+ * Cavium ThunderX2 implementation doesn't support unique irq
+ * lines. Use a single irq line for all the SMMUv3 interrupts.
*/
ret = devm_request_threaded_irq(smmu->dev, irq,
arm_smmu_combined_irq_handler,
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index fd1b80ef9490..5a28ae892504 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -52,6 +52,7 @@
#include <linux/spinlock.h>
#include <linux/amba/bus.h>
+#include <linux/fsl/mc.h>
#include "io-pgtable.h"
#include "arm-smmu-regs.h"
@@ -246,6 +247,7 @@ struct arm_smmu_domain {
const struct iommu_gather_ops *tlb_ops;
struct arm_smmu_cfg cfg;
enum arm_smmu_domain_stage stage;
+ bool non_strict;
struct mutex init_mutex; /* Protects smmu pointer */
spinlock_t cb_lock; /* Serialises ATS1* ops and TLB syncs */
struct iommu_domain domain;
@@ -447,7 +449,11 @@ static void arm_smmu_tlb_inv_context_s1(void *cookie)
struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
void __iomem *base = ARM_SMMU_CB(smmu_domain->smmu, cfg->cbndx);
- writel_relaxed(cfg->asid, base + ARM_SMMU_CB_S1_TLBIASID);
+ /*
+ * NOTE: this is not a relaxed write; it needs to guarantee that PTEs
+ * cleared by the current CPU are visible to the SMMU before the TLBI.
+ */
+ writel(cfg->asid, base + ARM_SMMU_CB_S1_TLBIASID);
arm_smmu_tlb_sync_context(cookie);
}
@@ -457,7 +463,8 @@ static void arm_smmu_tlb_inv_context_s2(void *cookie)
struct arm_smmu_device *smmu = smmu_domain->smmu;
void __iomem *base = ARM_SMMU_GR0(smmu);
- writel_relaxed(smmu_domain->cfg.vmid, base + ARM_SMMU_GR0_TLBIVMID);
+ /* NOTE: see above */
+ writel(smmu_domain->cfg.vmid, base + ARM_SMMU_GR0_TLBIVMID);
arm_smmu_tlb_sync_global(smmu);
}
@@ -469,6 +476,9 @@ static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size,
bool stage1 = cfg->cbar != CBAR_TYPE_S2_TRANS;
void __iomem *reg = ARM_SMMU_CB(smmu_domain->smmu, cfg->cbndx);
+ if (smmu_domain->smmu->features & ARM_SMMU_FEAT_COHERENT_WALK)
+ wmb();
+
if (stage1) {
reg += leaf ? ARM_SMMU_CB_S1_TLBIVAL : ARM_SMMU_CB_S1_TLBIVA;
@@ -510,6 +520,9 @@ static void arm_smmu_tlb_inv_vmid_nosync(unsigned long iova, size_t size,
struct arm_smmu_domain *smmu_domain = cookie;
void __iomem *base = ARM_SMMU_GR0(smmu_domain->smmu);
+ if (smmu_domain->smmu->features & ARM_SMMU_FEAT_COHERENT_WALK)
+ wmb();
+
writel_relaxed(smmu_domain->cfg.vmid, base + ARM_SMMU_GR0_TLBIVMID);
}
@@ -863,6 +876,9 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
if (smmu->features & ARM_SMMU_FEAT_COHERENT_WALK)
pgtbl_cfg.quirks = IO_PGTABLE_QUIRK_NO_DMA;
+ if (smmu_domain->non_strict)
+ pgtbl_cfg.quirks |= IO_PGTABLE_QUIRK_NON_STRICT;
+
smmu_domain->smmu = smmu;
pgtbl_ops = alloc_io_pgtable_ops(fmt, &pgtbl_cfg, smmu_domain);
if (!pgtbl_ops) {
@@ -1252,6 +1268,14 @@ static size_t arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova,
return ops->unmap(ops, iova, size);
}
+static void arm_smmu_flush_iotlb_all(struct iommu_domain *domain)
+{
+ struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+
+ if (smmu_domain->tlb_ops)
+ smmu_domain->tlb_ops->tlb_flush_all(smmu_domain);
+}
+
static void arm_smmu_iotlb_sync(struct iommu_domain *domain)
{
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
@@ -1459,6 +1483,8 @@ static struct iommu_group *arm_smmu_device_group(struct device *dev)
if (dev_is_pci(dev))
group = pci_device_group(dev);
+ else if (dev_is_fsl_mc(dev))
+ group = fsl_mc_device_group(dev);
else
group = generic_device_group(dev);
@@ -1470,15 +1496,27 @@ static int arm_smmu_domain_get_attr(struct iommu_domain *domain,
{
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
- if (domain->type != IOMMU_DOMAIN_UNMANAGED)
- return -EINVAL;
-
- switch (attr) {
- case DOMAIN_ATTR_NESTING:
- *(int *)data = (smmu_domain->stage == ARM_SMMU_DOMAIN_NESTED);
- return 0;
+ switch(domain->type) {
+ case IOMMU_DOMAIN_UNMANAGED:
+ switch (attr) {
+ case DOMAIN_ATTR_NESTING:
+ *(int *)data = (smmu_domain->stage == ARM_SMMU_DOMAIN_NESTED);
+ return 0;
+ default:
+ return -ENODEV;
+ }
+ break;
+ case IOMMU_DOMAIN_DMA:
+ switch (attr) {
+ case DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE:
+ *(int *)data = smmu_domain->non_strict;
+ return 0;
+ default:
+ return -ENODEV;
+ }
+ break;
default:
- return -ENODEV;
+ return -EINVAL;
}
}
@@ -1488,28 +1526,38 @@ static int arm_smmu_domain_set_attr(struct iommu_domain *domain,
int ret = 0;
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
- if (domain->type != IOMMU_DOMAIN_UNMANAGED)
- return -EINVAL;
-
mutex_lock(&smmu_domain->init_mutex);
- switch (attr) {
- case DOMAIN_ATTR_NESTING:
- if (smmu_domain->smmu) {
- ret = -EPERM;
- goto out_unlock;
+ switch(domain->type) {
+ case IOMMU_DOMAIN_UNMANAGED:
+ switch (attr) {
+ case DOMAIN_ATTR_NESTING:
+ if (smmu_domain->smmu) {
+ ret = -EPERM;
+ goto out_unlock;
+ }
+
+ if (*(int *)data)
+ smmu_domain->stage = ARM_SMMU_DOMAIN_NESTED;
+ else
+ smmu_domain->stage = ARM_SMMU_DOMAIN_S1;
+ break;
+ default:
+ ret = -ENODEV;
+ }
+ break;
+ case IOMMU_DOMAIN_DMA:
+ switch (attr) {
+ case DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE:
+ smmu_domain->non_strict = *(int *)data;
+ break;
+ default:
+ ret = -ENODEV;
}
-
- if (*(int *)data)
- smmu_domain->stage = ARM_SMMU_DOMAIN_NESTED;
- else
- smmu_domain->stage = ARM_SMMU_DOMAIN_S1;
-
break;
default:
- ret = -ENODEV;
+ ret = -EINVAL;
}
-
out_unlock:
mutex_unlock(&smmu_domain->init_mutex);
return ret;
@@ -1562,7 +1610,7 @@ static struct iommu_ops arm_smmu_ops = {
.attach_dev = arm_smmu_attach_dev,
.map = arm_smmu_map,
.unmap = arm_smmu_unmap,
- .flush_iotlb_all = arm_smmu_iotlb_sync,
+ .flush_iotlb_all = arm_smmu_flush_iotlb_all,
.iotlb_sync = arm_smmu_iotlb_sync,
.iova_to_phys = arm_smmu_iova_to_phys,
.add_device = arm_smmu_add_device,
@@ -2036,6 +2084,10 @@ static void arm_smmu_bus_init(void)
bus_set_iommu(&pci_bus_type, &arm_smmu_ops);
}
#endif
+#ifdef CONFIG_FSL_MC_BUS
+ if (!iommu_present(&fsl_mc_bus_type))
+ bus_set_iommu(&fsl_mc_bus_type, &arm_smmu_ops);
+#endif
}
static int arm_smmu_device_probe(struct platform_device *pdev)
diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index 511ff9a1d6d9..d1b04753b204 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -55,6 +55,9 @@ struct iommu_dma_cookie {
};
struct list_head msi_page_list;
spinlock_t msi_lock;
+
+ /* Domain for flush queue callback; NULL if flush queue not in use */
+ struct iommu_domain *fq_domain;
};
static inline size_t cookie_msi_granule(struct iommu_dma_cookie *cookie)
@@ -257,6 +260,20 @@ static int iova_reserve_iommu_regions(struct device *dev,
return ret;
}
+static void iommu_dma_flush_iotlb_all(struct iova_domain *iovad)
+{
+ struct iommu_dma_cookie *cookie;
+ struct iommu_domain *domain;
+
+ cookie = container_of(iovad, struct iommu_dma_cookie, iovad);
+ domain = cookie->fq_domain;
+ /*
+ * The IOMMU driver supporting DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE
+ * implies that ops->flush_iotlb_all must be non-NULL.
+ */
+ domain->ops->flush_iotlb_all(domain);
+}
+
/**
* iommu_dma_init_domain - Initialise a DMA mapping domain
* @domain: IOMMU domain previously prepared by iommu_get_dma_cookie()
@@ -275,6 +292,7 @@ int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base,
struct iommu_dma_cookie *cookie = domain->iova_cookie;
struct iova_domain *iovad = &cookie->iovad;
unsigned long order, base_pfn, end_pfn;
+ int attr;
if (!cookie || cookie->type != IOMMU_DMA_IOVA_COOKIE)
return -EINVAL;
@@ -308,6 +326,13 @@ int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base,
}
init_iova_domain(iovad, 1UL << order, base_pfn);
+
+ if (!cookie->fq_domain && !iommu_domain_get_attr(domain,
+ DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE, &attr) && attr) {
+ cookie->fq_domain = domain;
+ init_iova_flush_queue(iovad, iommu_dma_flush_iotlb_all, NULL);
+ }
+
if (!dev)
return 0;
@@ -393,6 +418,9 @@ static void iommu_dma_free_iova(struct iommu_dma_cookie *cookie,
/* The MSI case is only ever cleaning up its most recent allocation */
if (cookie->type == IOMMU_DMA_MSI_COOKIE)
cookie->msi_iova -= size;
+ else if (cookie->fq_domain) /* non-strict mode */
+ queue_iova(iovad, iova_pfn(iovad, iova),
+ size >> iova_shift(iovad), 0);
else
free_iova_fast(iovad, iova_pfn(iovad, iova),
size >> iova_shift(iovad));
@@ -408,7 +436,9 @@ static void __iommu_dma_unmap(struct iommu_domain *domain, dma_addr_t dma_addr,
dma_addr -= iova_off;
size = iova_align(iovad, size + iova_off);
- WARN_ON(iommu_unmap(domain, dma_addr, size) != size);
+ WARN_ON(iommu_unmap_fast(domain, dma_addr, size) != size);
+ if (!cookie->fq_domain)
+ iommu_tlb_sync(domain);
iommu_dma_free_iova(cookie, dma_addr, size);
}
@@ -491,7 +521,7 @@ static struct page **__iommu_dma_alloc_pages(unsigned int count,
void iommu_dma_free(struct device *dev, struct page **pages, size_t size,
dma_addr_t *handle)
{
- __iommu_dma_unmap(iommu_get_domain_for_dev(dev), *handle, size);
+ __iommu_dma_unmap(iommu_get_dma_domain(dev), *handle, size);
__iommu_dma_free_pages(pages, PAGE_ALIGN(size) >> PAGE_SHIFT);
*handle = IOMMU_MAPPING_ERROR;
}
@@ -518,7 +548,7 @@ struct page **iommu_dma_alloc(struct device *dev, size_t size, gfp_t gfp,
unsigned long attrs, int prot, dma_addr_t *handle,
void (*flush_page)(struct device *, const void *, phys_addr_t))
{
- struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
+ struct iommu_domain *domain = iommu_get_dma_domain(dev);
struct iommu_dma_cookie *cookie = domain->iova_cookie;
struct iova_domain *iovad = &cookie->iovad;
struct page **pages;
@@ -606,9 +636,8 @@ int iommu_dma_mmap(struct page **pages, size_t size, struct vm_area_struct *vma)
}
static dma_addr_t __iommu_dma_map(struct device *dev, phys_addr_t phys,
- size_t size, int prot)
+ size_t size, int prot, struct iommu_domain *domain)
{
- struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
struct iommu_dma_cookie *cookie = domain->iova_cookie;
size_t iova_off = 0;
dma_addr_t iova;
@@ -632,13 +661,14 @@ static dma_addr_t __iommu_dma_map(struct device *dev, phys_addr_t phys,
dma_addr_t iommu_dma_map_page(struct device *dev, struct page *page,
unsigned long offset, size_t size, int prot)
{
- return __iommu_dma_map(dev, page_to_phys(page) + offset, size, prot);
+ return __iommu_dma_map(dev, page_to_phys(page) + offset, size, prot,
+ iommu_get_dma_domain(dev));
}
void iommu_dma_unmap_page(struct device *dev, dma_addr_t handle, size_t size,
enum dma_data_direction dir, unsigned long attrs)
{
- __iommu_dma_unmap(iommu_get_domain_for_dev(dev), handle, size);
+ __iommu_dma_unmap(iommu_get_dma_domain(dev), handle, size);
}
/*
@@ -726,7 +756,7 @@ static void __invalidate_sg(struct scatterlist *sg, int nents)
int iommu_dma_map_sg(struct device *dev, struct scatterlist *sg,
int nents, int prot)
{
- struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
+ struct iommu_domain *domain = iommu_get_dma_domain(dev);
struct iommu_dma_cookie *cookie = domain->iova_cookie;
struct iova_domain *iovad = &cookie->iovad;
struct scatterlist *s, *prev = NULL;
@@ -811,20 +841,21 @@ void iommu_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
sg = tmp;
}
end = sg_dma_address(sg) + sg_dma_len(sg);
- __iommu_dma_unmap(iommu_get_domain_for_dev(dev), start, end - start);
+ __iommu_dma_unmap(iommu_get_dma_domain(dev), start, end - start);
}
dma_addr_t iommu_dma_map_resource(struct device *dev, phys_addr_t phys,
size_t size, enum dma_data_direction dir, unsigned long attrs)
{
return __iommu_dma_map(dev, phys, size,
- dma_info_to_prot(dir, false, attrs) | IOMMU_MMIO);
+ dma_info_to_prot(dir, false, attrs) | IOMMU_MMIO,
+ iommu_get_dma_domain(dev));
}
void iommu_dma_unmap_resource(struct device *dev, dma_addr_t handle,
size_t size, enum dma_data_direction dir, unsigned long attrs)
{
- __iommu_dma_unmap(iommu_get_domain_for_dev(dev), handle, size);
+ __iommu_dma_unmap(iommu_get_dma_domain(dev), handle, size);
}
int iommu_dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
@@ -850,7 +881,7 @@ static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev,
if (!msi_page)
return NULL;
- iova = __iommu_dma_map(dev, msi_addr, size, prot);
+ iova = __iommu_dma_map(dev, msi_addr, size, prot, domain);
if (iommu_dma_mapping_error(dev, iova))
goto out_free_page;
diff --git a/drivers/iommu/fsl_pamu.c b/drivers/iommu/fsl_pamu.c
index 8540625796a1..1b955aea44dd 100644
--- a/drivers/iommu/fsl_pamu.c
+++ b/drivers/iommu/fsl_pamu.c
@@ -543,7 +543,7 @@ u32 get_stash_id(u32 stash_dest_hint, u32 vcpu)
return ~(u32)0;
}
- for_each_node_by_type(node, "cpu") {
+ for_each_of_cpu_node(node) {
prop = of_get_property(node, "reg", &len);
for (i = 0; i < len / sizeof(u32); i++) {
if (be32_to_cpup(&prop[i]) == vcpu) {
diff --git a/drivers/iommu/fsl_pamu_domain.c b/drivers/iommu/fsl_pamu_domain.c
index f089136e9c3f..9b528cfcc6c3 100644
--- a/drivers/iommu/fsl_pamu_domain.c
+++ b/drivers/iommu/fsl_pamu_domain.c
@@ -814,6 +814,55 @@ static int configure_domain_dma_state(struct fsl_dma_domain *dma_domain, bool en
return 0;
}
+static int fsl_pamu_set_windows(struct iommu_domain *domain, u32 w_count)
+{
+ struct fsl_dma_domain *dma_domain = to_fsl_dma_domain(domain);
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&dma_domain->domain_lock, flags);
+ /* Ensure domain is inactive i.e. DMA should be disabled for the domain */
+ if (dma_domain->enabled) {
+ pr_debug("Can't set geometry attributes as domain is active\n");
+ spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+ return -EBUSY;
+ }
+
+ /* Ensure that the geometry has been set for the domain */
+ if (!dma_domain->geom_size) {
+ pr_debug("Please configure geometry before setting the number of windows\n");
+ spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+ return -EINVAL;
+ }
+
+ /*
+ * Ensure we have valid window count i.e. it should be less than
+ * maximum permissible limit and should be a power of two.
+ */
+ if (w_count > pamu_get_max_subwin_cnt() || !is_power_of_2(w_count)) {
+ pr_debug("Invalid window count\n");
+ spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+ return -EINVAL;
+ }
+
+ ret = pamu_set_domain_geometry(dma_domain, &domain->geometry,
+ w_count > 1 ? w_count : 0);
+ if (!ret) {
+ kfree(dma_domain->win_arr);
+ dma_domain->win_arr = kcalloc(w_count,
+ sizeof(*dma_domain->win_arr),
+ GFP_ATOMIC);
+ if (!dma_domain->win_arr) {
+ spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+ return -ENOMEM;
+ }
+ dma_domain->win_cnt = w_count;
+ }
+ spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+
+ return ret;
+}
+
static int fsl_pamu_set_domain_attr(struct iommu_domain *domain,
enum iommu_attr attr_type, void *data)
{
@@ -830,6 +879,9 @@ static int fsl_pamu_set_domain_attr(struct iommu_domain *domain,
case DOMAIN_ATTR_FSL_PAMU_ENABLE:
ret = configure_domain_dma_state(dma_domain, *(int *)data);
break;
+ case DOMAIN_ATTR_WINDOWS:
+ ret = fsl_pamu_set_windows(domain, *(u32 *)data);
+ break;
default:
pr_debug("Unsupported attribute type\n");
ret = -EINVAL;
@@ -856,6 +908,9 @@ static int fsl_pamu_get_domain_attr(struct iommu_domain *domain,
case DOMAIN_ATTR_FSL_PAMUV1:
*(int *)data = DOMAIN_ATTR_FSL_PAMUV1;
break;
+ case DOMAIN_ATTR_WINDOWS:
+ *(u32 *)data = dma_domain->win_cnt;
+ break;
default:
pr_debug("Unsupported attribute type\n");
ret = -EINVAL;
@@ -916,13 +971,13 @@ static struct iommu_group *get_shared_pci_device_group(struct pci_dev *pdev)
static struct iommu_group *get_pci_device_group(struct pci_dev *pdev)
{
struct pci_controller *pci_ctl;
- bool pci_endpt_partioning;
+ bool pci_endpt_partitioning;
struct iommu_group *group = NULL;
pci_ctl = pci_bus_to_host(pdev->bus);
- pci_endpt_partioning = check_pci_ctl_endpt_part(pci_ctl);
+ pci_endpt_partitioning = check_pci_ctl_endpt_part(pci_ctl);
/* We can partition PCIe devices so assign device group to the device */
- if (pci_endpt_partioning) {
+ if (pci_endpt_partitioning) {
group = pci_device_group(&pdev->dev);
/*
@@ -994,62 +1049,6 @@ static void fsl_pamu_remove_device(struct device *dev)
iommu_group_remove_device(dev);
}
-static int fsl_pamu_set_windows(struct iommu_domain *domain, u32 w_count)
-{
- struct fsl_dma_domain *dma_domain = to_fsl_dma_domain(domain);
- unsigned long flags;
- int ret;
-
- spin_lock_irqsave(&dma_domain->domain_lock, flags);
- /* Ensure domain is inactive i.e. DMA should be disabled for the domain */
- if (dma_domain->enabled) {
- pr_debug("Can't set geometry attributes as domain is active\n");
- spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
- return -EBUSY;
- }
-
- /* Ensure that the geometry has been set for the domain */
- if (!dma_domain->geom_size) {
- pr_debug("Please configure geometry before setting the number of windows\n");
- spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
- return -EINVAL;
- }
-
- /*
- * Ensure we have valid window count i.e. it should be less than
- * maximum permissible limit and should be a power of two.
- */
- if (w_count > pamu_get_max_subwin_cnt() || !is_power_of_2(w_count)) {
- pr_debug("Invalid window count\n");
- spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
- return -EINVAL;
- }
-
- ret = pamu_set_domain_geometry(dma_domain, &domain->geometry,
- w_count > 1 ? w_count : 0);
- if (!ret) {
- kfree(dma_domain->win_arr);
- dma_domain->win_arr = kcalloc(w_count,
- sizeof(*dma_domain->win_arr),
- GFP_ATOMIC);
- if (!dma_domain->win_arr) {
- spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
- return -ENOMEM;
- }
- dma_domain->win_cnt = w_count;
- }
- spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
-
- return ret;
-}
-
-static u32 fsl_pamu_get_windows(struct iommu_domain *domain)
-{
- struct fsl_dma_domain *dma_domain = to_fsl_dma_domain(domain);
-
- return dma_domain->win_cnt;
-}
-
static const struct iommu_ops fsl_pamu_ops = {
.capable = fsl_pamu_capable,
.domain_alloc = fsl_pamu_domain_alloc,
@@ -1058,8 +1057,6 @@ static const struct iommu_ops fsl_pamu_ops = {
.detach_dev = fsl_pamu_detach_device,
.domain_window_enable = fsl_pamu_window_enable,
.domain_window_disable = fsl_pamu_window_disable,
- .domain_get_windows = fsl_pamu_get_windows,
- .domain_set_windows = fsl_pamu_set_windows,
.iova_to_phys = fsl_pamu_iova_to_phys,
.domain_set_attr = fsl_pamu_set_domain_attr,
.domain_get_attr = fsl_pamu_get_domain_attr,
diff --git a/drivers/iommu/intel-iommu-debugfs.c b/drivers/iommu/intel-iommu-debugfs.c
new file mode 100644
index 000000000000..7fabf9b1c2dc
--- /dev/null
+++ b/drivers/iommu/intel-iommu-debugfs.c
@@ -0,0 +1,314 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright © 2018 Intel Corporation.
+ *
+ * Authors: Gayatri Kammela <gayatri.kammela@intel.com>
+ * Sohil Mehta <sohil.mehta@intel.com>
+ * Jacob Pan <jacob.jun.pan@linux.intel.com>
+ */
+
+#include <linux/debugfs.h>
+#include <linux/dmar.h>
+#include <linux/intel-iommu.h>
+#include <linux/pci.h>
+
+#include <asm/irq_remapping.h>
+
+struct iommu_regset {
+ int offset;
+ const char *regs;
+};
+
+#define IOMMU_REGSET_ENTRY(_reg_) \
+ { DMAR_##_reg_##_REG, __stringify(_reg_) }
+static const struct iommu_regset iommu_regs[] = {
+ IOMMU_REGSET_ENTRY(VER),
+ IOMMU_REGSET_ENTRY(CAP),
+ IOMMU_REGSET_ENTRY(ECAP),
+ IOMMU_REGSET_ENTRY(GCMD),
+ IOMMU_REGSET_ENTRY(GSTS),
+ IOMMU_REGSET_ENTRY(RTADDR),
+ IOMMU_REGSET_ENTRY(CCMD),
+ IOMMU_REGSET_ENTRY(FSTS),
+ IOMMU_REGSET_ENTRY(FECTL),
+ IOMMU_REGSET_ENTRY(FEDATA),
+ IOMMU_REGSET_ENTRY(FEADDR),
+ IOMMU_REGSET_ENTRY(FEUADDR),
+ IOMMU_REGSET_ENTRY(AFLOG),
+ IOMMU_REGSET_ENTRY(PMEN),
+ IOMMU_REGSET_ENTRY(PLMBASE),
+ IOMMU_REGSET_ENTRY(PLMLIMIT),
+ IOMMU_REGSET_ENTRY(PHMBASE),
+ IOMMU_REGSET_ENTRY(PHMLIMIT),
+ IOMMU_REGSET_ENTRY(IQH),
+ IOMMU_REGSET_ENTRY(IQT),
+ IOMMU_REGSET_ENTRY(IQA),
+ IOMMU_REGSET_ENTRY(ICS),
+ IOMMU_REGSET_ENTRY(IRTA),
+ IOMMU_REGSET_ENTRY(PQH),
+ IOMMU_REGSET_ENTRY(PQT),
+ IOMMU_REGSET_ENTRY(PQA),
+ IOMMU_REGSET_ENTRY(PRS),
+ IOMMU_REGSET_ENTRY(PECTL),
+ IOMMU_REGSET_ENTRY(PEDATA),
+ IOMMU_REGSET_ENTRY(PEADDR),
+ IOMMU_REGSET_ENTRY(PEUADDR),
+ IOMMU_REGSET_ENTRY(MTRRCAP),
+ IOMMU_REGSET_ENTRY(MTRRDEF),
+ IOMMU_REGSET_ENTRY(MTRR_FIX64K_00000),
+ IOMMU_REGSET_ENTRY(MTRR_FIX16K_80000),
+ IOMMU_REGSET_ENTRY(MTRR_FIX16K_A0000),
+ IOMMU_REGSET_ENTRY(MTRR_FIX4K_C0000),
+ IOMMU_REGSET_ENTRY(MTRR_FIX4K_C8000),
+ IOMMU_REGSET_ENTRY(MTRR_FIX4K_D0000),
+ IOMMU_REGSET_ENTRY(MTRR_FIX4K_D8000),
+ IOMMU_REGSET_ENTRY(MTRR_FIX4K_E0000),
+ IOMMU_REGSET_ENTRY(MTRR_FIX4K_E8000),
+ IOMMU_REGSET_ENTRY(MTRR_FIX4K_F0000),
+ IOMMU_REGSET_ENTRY(MTRR_FIX4K_F8000),
+ IOMMU_REGSET_ENTRY(MTRR_PHYSBASE0),
+ IOMMU_REGSET_ENTRY(MTRR_PHYSMASK0),
+ IOMMU_REGSET_ENTRY(MTRR_PHYSBASE1),
+ IOMMU_REGSET_ENTRY(MTRR_PHYSMASK1),
+ IOMMU_REGSET_ENTRY(MTRR_PHYSBASE2),
+ IOMMU_REGSET_ENTRY(MTRR_PHYSMASK2),
+ IOMMU_REGSET_ENTRY(MTRR_PHYSBASE3),
+ IOMMU_REGSET_ENTRY(MTRR_PHYSMASK3),
+ IOMMU_REGSET_ENTRY(MTRR_PHYSBASE4),
+ IOMMU_REGSET_ENTRY(MTRR_PHYSMASK4),
+ IOMMU_REGSET_ENTRY(MTRR_PHYSBASE5),
+ IOMMU_REGSET_ENTRY(MTRR_PHYSMASK5),
+ IOMMU_REGSET_ENTRY(MTRR_PHYSBASE6),
+ IOMMU_REGSET_ENTRY(MTRR_PHYSMASK6),
+ IOMMU_REGSET_ENTRY(MTRR_PHYSBASE7),
+ IOMMU_REGSET_ENTRY(MTRR_PHYSMASK7),
+ IOMMU_REGSET_ENTRY(MTRR_PHYSBASE8),
+ IOMMU_REGSET_ENTRY(MTRR_PHYSMASK8),
+ IOMMU_REGSET_ENTRY(MTRR_PHYSBASE9),
+ IOMMU_REGSET_ENTRY(MTRR_PHYSMASK9),
+ IOMMU_REGSET_ENTRY(VCCAP),
+ IOMMU_REGSET_ENTRY(VCMD),
+ IOMMU_REGSET_ENTRY(VCRSP),
+};
+
+static int iommu_regset_show(struct seq_file *m, void *unused)
+{
+ struct dmar_drhd_unit *drhd;
+ struct intel_iommu *iommu;
+ unsigned long flag;
+ int i, ret = 0;
+ u64 value;
+
+ rcu_read_lock();
+ for_each_active_iommu(iommu, drhd) {
+ if (!drhd->reg_base_addr) {
+ seq_puts(m, "IOMMU: Invalid base address\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ seq_printf(m, "IOMMU: %s Register Base Address: %llx\n",
+ iommu->name, drhd->reg_base_addr);
+ seq_puts(m, "Name\t\t\tOffset\t\tContents\n");
+ /*
+ * Publish the contents of the 64-bit hardware registers
+ * by adding the offset to the pointer (virtual address).
+ */
+ raw_spin_lock_irqsave(&iommu->register_lock, flag);
+ for (i = 0 ; i < ARRAY_SIZE(iommu_regs); i++) {
+ value = dmar_readq(iommu->reg + iommu_regs[i].offset);
+ seq_printf(m, "%-16s\t0x%02x\t\t0x%016llx\n",
+ iommu_regs[i].regs, iommu_regs[i].offset,
+ value);
+ }
+ raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
+ seq_putc(m, '\n');
+ }
+out:
+ rcu_read_unlock();
+
+ return ret;
+}
+DEFINE_SHOW_ATTRIBUTE(iommu_regset);
+
+static void ctx_tbl_entry_show(struct seq_file *m, struct intel_iommu *iommu,
+ int bus)
+{
+ struct context_entry *context;
+ int devfn;
+
+ seq_printf(m, " Context Table Entries for Bus: %d\n", bus);
+ seq_puts(m, " Entry\tB:D.F\tHigh\tLow\n");
+
+ for (devfn = 0; devfn < 256; devfn++) {
+ context = iommu_context_addr(iommu, bus, devfn, 0);
+ if (!context)
+ return;
+
+ if (!context_present(context))
+ continue;
+
+ seq_printf(m, " %-5d\t%02x:%02x.%x\t%-6llx\t%llx\n", devfn,
+ bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
+ context[0].hi, context[0].lo);
+ }
+}
+
+static void root_tbl_entry_show(struct seq_file *m, struct intel_iommu *iommu)
+{
+ unsigned long flags;
+ int bus;
+
+ spin_lock_irqsave(&iommu->lock, flags);
+ seq_printf(m, "IOMMU %s: Root Table Address:%llx\n", iommu->name,
+ (u64)virt_to_phys(iommu->root_entry));
+ seq_puts(m, "Root Table Entries:\n");
+
+ for (bus = 0; bus < 256; bus++) {
+ if (!(iommu->root_entry[bus].lo & 1))
+ continue;
+
+ seq_printf(m, " Bus: %d H: %llx L: %llx\n", bus,
+ iommu->root_entry[bus].hi,
+ iommu->root_entry[bus].lo);
+
+ ctx_tbl_entry_show(m, iommu, bus);
+ seq_putc(m, '\n');
+ }
+ spin_unlock_irqrestore(&iommu->lock, flags);
+}
+
+static int dmar_translation_struct_show(struct seq_file *m, void *unused)
+{
+ struct dmar_drhd_unit *drhd;
+ struct intel_iommu *iommu;
+
+ rcu_read_lock();
+ for_each_active_iommu(iommu, drhd) {
+ root_tbl_entry_show(m, iommu);
+ seq_putc(m, '\n');
+ }
+ rcu_read_unlock();
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(dmar_translation_struct);
+
+#ifdef CONFIG_IRQ_REMAP
+static void ir_tbl_remap_entry_show(struct seq_file *m,
+ struct intel_iommu *iommu)
+{
+ struct irte *ri_entry;
+ unsigned long flags;
+ int idx;
+
+ seq_puts(m, " Entry SrcID DstID Vct IRTE_high\t\tIRTE_low\n");
+
+ raw_spin_lock_irqsave(&irq_2_ir_lock, flags);
+ for (idx = 0; idx < INTR_REMAP_TABLE_ENTRIES; idx++) {
+ ri_entry = &iommu->ir_table->base[idx];
+ if (!ri_entry->present || ri_entry->p_pst)
+ continue;
+
+ seq_printf(m, " %-5d %02x:%02x.%01x %08x %02x %016llx\t%016llx\n",
+ idx, PCI_BUS_NUM(ri_entry->sid),
+ PCI_SLOT(ri_entry->sid), PCI_FUNC(ri_entry->sid),
+ ri_entry->dest_id, ri_entry->vector,
+ ri_entry->high, ri_entry->low);
+ }
+ raw_spin_unlock_irqrestore(&irq_2_ir_lock, flags);
+}
+
+static void ir_tbl_posted_entry_show(struct seq_file *m,
+ struct intel_iommu *iommu)
+{
+ struct irte *pi_entry;
+ unsigned long flags;
+ int idx;
+
+ seq_puts(m, " Entry SrcID PDA_high PDA_low Vct IRTE_high\t\tIRTE_low\n");
+
+ raw_spin_lock_irqsave(&irq_2_ir_lock, flags);
+ for (idx = 0; idx < INTR_REMAP_TABLE_ENTRIES; idx++) {
+ pi_entry = &iommu->ir_table->base[idx];
+ if (!pi_entry->present || !pi_entry->p_pst)
+ continue;
+
+ seq_printf(m, " %-5d %02x:%02x.%01x %08x %08x %02x %016llx\t%016llx\n",
+ idx, PCI_BUS_NUM(pi_entry->sid),
+ PCI_SLOT(pi_entry->sid), PCI_FUNC(pi_entry->sid),
+ pi_entry->pda_h, pi_entry->pda_l << 6,
+ pi_entry->vector, pi_entry->high,
+ pi_entry->low);
+ }
+ raw_spin_unlock_irqrestore(&irq_2_ir_lock, flags);
+}
+
+/*
+ * For active IOMMUs go through the Interrupt remapping
+ * table and print valid entries in a table format for
+ * Remapped and Posted Interrupts.
+ */
+static int ir_translation_struct_show(struct seq_file *m, void *unused)
+{
+ struct dmar_drhd_unit *drhd;
+ struct intel_iommu *iommu;
+ u64 irta;
+
+ rcu_read_lock();
+ for_each_active_iommu(iommu, drhd) {
+ if (!ecap_ir_support(iommu->ecap))
+ continue;
+
+ seq_printf(m, "Remapped Interrupt supported on IOMMU: %s\n",
+ iommu->name);
+
+ if (iommu->ir_table) {
+ irta = virt_to_phys(iommu->ir_table->base);
+ seq_printf(m, " IR table address:%llx\n", irta);
+ ir_tbl_remap_entry_show(m, iommu);
+ } else {
+ seq_puts(m, "Interrupt Remapping is not enabled\n");
+ }
+ seq_putc(m, '\n');
+ }
+
+ seq_puts(m, "****\n\n");
+
+ for_each_active_iommu(iommu, drhd) {
+ if (!cap_pi_support(iommu->cap))
+ continue;
+
+ seq_printf(m, "Posted Interrupt supported on IOMMU: %s\n",
+ iommu->name);
+
+ if (iommu->ir_table) {
+ irta = virt_to_phys(iommu->ir_table->base);
+ seq_printf(m, " IR table address:%llx\n", irta);
+ ir_tbl_posted_entry_show(m, iommu);
+ } else {
+ seq_puts(m, "Interrupt Remapping is not enabled\n");
+ }
+ seq_putc(m, '\n');
+ }
+ rcu_read_unlock();
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(ir_translation_struct);
+#endif
+
+void __init intel_iommu_debugfs_init(void)
+{
+ struct dentry *intel_iommu_debug = debugfs_create_dir("intel",
+ iommu_debugfs_dir);
+
+ debugfs_create_file("iommu_regset", 0444, intel_iommu_debug, NULL,
+ &iommu_regset_fops);
+ debugfs_create_file("dmar_translation_struct", 0444, intel_iommu_debug,
+ NULL, &dmar_translation_struct_fops);
+#ifdef CONFIG_IRQ_REMAP
+ debugfs_create_file("ir_translation_struct", 0444, intel_iommu_debug,
+ NULL, &ir_translation_struct_fops);
+#endif
+}
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index bedc801b06a0..f3ccf025108b 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -185,16 +185,6 @@ static int rwbf_quirk;
static int force_on = 0;
int intel_iommu_tboot_noforce;
-/*
- * 0: Present
- * 1-11: Reserved
- * 12-63: Context Ptr (12 - (haw-1))
- * 64-127: Reserved
- */
-struct root_entry {
- u64 lo;
- u64 hi;
-};
#define ROOT_ENTRY_NR (VTD_PAGE_SIZE/sizeof(struct root_entry))
/*
@@ -220,21 +210,6 @@ static phys_addr_t root_entry_uctp(struct root_entry *re)
return re->hi & VTD_PAGE_MASK;
}
-/*
- * low 64 bits:
- * 0: present
- * 1: fault processing disable
- * 2-3: translation type
- * 12-63: address space root
- * high 64 bits:
- * 0-2: address width
- * 3-6: aval
- * 8-23: domain id
- */
-struct context_entry {
- u64 lo;
- u64 hi;
-};
static inline void context_clear_pasid_enable(struct context_entry *context)
{
@@ -261,7 +236,7 @@ static inline bool __context_present(struct context_entry *context)
return (context->lo & 1);
}
-static inline bool context_present(struct context_entry *context)
+bool context_present(struct context_entry *context)
{
return context_pasid_enabled(context) ?
__context_present(context) :
@@ -788,8 +763,8 @@ static void domain_update_iommu_cap(struct dmar_domain *domain)
domain->iommu_superpage = domain_update_iommu_superpage(NULL);
}
-static inline struct context_entry *iommu_context_addr(struct intel_iommu *iommu,
- u8 bus, u8 devfn, int alloc)
+struct context_entry *iommu_context_addr(struct intel_iommu *iommu, u8 bus,
+ u8 devfn, int alloc)
{
struct root_entry *root = &iommu->root_entry[bus];
struct context_entry *context;
@@ -3895,7 +3870,7 @@ static int intel_mapping_error(struct device *dev, dma_addr_t dma_addr)
return !dma_addr;
}
-const struct dma_map_ops intel_dma_ops = {
+static const struct dma_map_ops intel_dma_ops = {
.alloc = intel_alloc_coherent,
.free = intel_free_coherent,
.map_sg = intel_map_sg,
@@ -3903,9 +3878,7 @@ const struct dma_map_ops intel_dma_ops = {
.map_page = intel_map_page,
.unmap_page = intel_unmap_page,
.mapping_error = intel_mapping_error,
-#ifdef CONFIG_X86
.dma_supported = dma_direct_supported,
-#endif
};
static inline int iommu_domain_cache_init(void)
@@ -4862,6 +4835,7 @@ int __init intel_iommu_init(void)
cpuhp_setup_state(CPUHP_IOMMU_INTEL_DEAD, "iommu/intel:dead", NULL,
intel_iommu_cpu_dead);
intel_iommu_enabled = 1;
+ intel_iommu_debugfs_init();
return 0;
diff --git a/drivers/iommu/intel-svm.c b/drivers/iommu/intel-svm.c
index 4a03e5090952..db301efe126d 100644
--- a/drivers/iommu/intel-svm.c
+++ b/drivers/iommu/intel-svm.c
@@ -273,7 +273,6 @@ static void intel_mm_release(struct mmu_notifier *mn, struct mm_struct *mm)
}
static const struct mmu_notifier_ops intel_mmuops = {
- .flags = MMU_INVALIDATE_DOES_NOT_BLOCK,
.release = intel_mm_release,
.change_pte = intel_change_pte,
.invalidate_range = intel_invalidate_range,
diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c
index 967450bd421a..c2d6c11431de 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -76,7 +76,7 @@ static struct hpet_scope ir_hpet[MAX_HPET_TBS];
* in single-threaded environment with interrupt disabled, so no need to tabke
* the dmar_global_lock.
*/
-static DEFINE_RAW_SPINLOCK(irq_2_ir_lock);
+DEFINE_RAW_SPINLOCK(irq_2_ir_lock);
static const struct irq_domain_ops intel_ir_domain_ops;
static void iommu_disable_irq_remapping(struct intel_iommu *iommu);
diff --git a/drivers/iommu/io-pgtable-arm-v7s.c b/drivers/iommu/io-pgtable-arm-v7s.c
index b5948ba6b3b3..445c3bde0480 100644
--- a/drivers/iommu/io-pgtable-arm-v7s.c
+++ b/drivers/iommu/io-pgtable-arm-v7s.c
@@ -587,6 +587,7 @@ static size_t arm_v7s_split_blk_unmap(struct arm_v7s_io_pgtable *data,
}
io_pgtable_tlb_add_flush(&data->iop, iova, size, size, true);
+ io_pgtable_tlb_sync(&data->iop);
return size;
}
@@ -642,6 +643,13 @@ static size_t __arm_v7s_unmap(struct arm_v7s_io_pgtable *data,
io_pgtable_tlb_sync(iop);
ptep = iopte_deref(pte[i], lvl);
__arm_v7s_free_table(ptep, lvl + 1, data);
+ } else if (iop->cfg.quirks & IO_PGTABLE_QUIRK_NON_STRICT) {
+ /*
+ * Order the PTE update against queueing the IOVA, to
+ * guarantee that a flush callback from a different CPU
+ * has observed it before the TLBIALL can be issued.
+ */
+ smp_wmb();
} else {
io_pgtable_tlb_add_flush(iop, iova, blk_size,
blk_size, true);
@@ -712,7 +720,8 @@ static struct io_pgtable *arm_v7s_alloc_pgtable(struct io_pgtable_cfg *cfg,
IO_PGTABLE_QUIRK_NO_PERMS |
IO_PGTABLE_QUIRK_TLBI_ON_MAP |
IO_PGTABLE_QUIRK_ARM_MTK_4GB |
- IO_PGTABLE_QUIRK_NO_DMA))
+ IO_PGTABLE_QUIRK_NO_DMA |
+ IO_PGTABLE_QUIRK_NON_STRICT))
return NULL;
/* If ARM_MTK_4GB is enabled, the NO_PERMS is also expected. */
diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c
index 88641b4560bc..237cacd4a62b 100644
--- a/drivers/iommu/io-pgtable-arm.c
+++ b/drivers/iommu/io-pgtable-arm.c
@@ -574,13 +574,13 @@ static size_t arm_lpae_split_blk_unmap(struct arm_lpae_io_pgtable *data,
return 0;
tablep = iopte_deref(pte, data);
+ } else if (unmap_idx >= 0) {
+ io_pgtable_tlb_add_flush(&data->iop, iova, size, size, true);
+ io_pgtable_tlb_sync(&data->iop);
+ return size;
}
- if (unmap_idx < 0)
- return __arm_lpae_unmap(data, iova, size, lvl, tablep);
-
- io_pgtable_tlb_add_flush(&data->iop, iova, size, size, true);
- return size;
+ return __arm_lpae_unmap(data, iova, size, lvl, tablep);
}
static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data,
@@ -610,6 +610,13 @@ static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data,
io_pgtable_tlb_sync(iop);
ptep = iopte_deref(pte, data);
__arm_lpae_free_pgtable(data, lvl + 1, ptep);
+ } else if (iop->cfg.quirks & IO_PGTABLE_QUIRK_NON_STRICT) {
+ /*
+ * Order the PTE update against queueing the IOVA, to
+ * guarantee that a flush callback from a different CPU
+ * has observed it before the TLBIALL can be issued.
+ */
+ smp_wmb();
} else {
io_pgtable_tlb_add_flush(iop, iova, size, size, true);
}
@@ -772,7 +779,8 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie)
u64 reg;
struct arm_lpae_io_pgtable *data;
- if (cfg->quirks & ~(IO_PGTABLE_QUIRK_ARM_NS | IO_PGTABLE_QUIRK_NO_DMA))
+ if (cfg->quirks & ~(IO_PGTABLE_QUIRK_ARM_NS | IO_PGTABLE_QUIRK_NO_DMA |
+ IO_PGTABLE_QUIRK_NON_STRICT))
return NULL;
data = arm_lpae_alloc_pgtable(cfg);
@@ -864,7 +872,8 @@ arm_64_lpae_alloc_pgtable_s2(struct io_pgtable_cfg *cfg, void *cookie)
struct arm_lpae_io_pgtable *data;
/* The NS quirk doesn't apply at stage 2 */
- if (cfg->quirks & ~IO_PGTABLE_QUIRK_NO_DMA)
+ if (cfg->quirks & ~(IO_PGTABLE_QUIRK_NO_DMA |
+ IO_PGTABLE_QUIRK_NON_STRICT))
return NULL;
data = arm_lpae_alloc_pgtable(cfg);
diff --git a/drivers/iommu/io-pgtable.h b/drivers/iommu/io-pgtable.h
index 2df79093cad9..47d5ae559329 100644
--- a/drivers/iommu/io-pgtable.h
+++ b/drivers/iommu/io-pgtable.h
@@ -71,12 +71,17 @@ struct io_pgtable_cfg {
* be accessed by a fully cache-coherent IOMMU or CPU (e.g. for a
* software-emulated IOMMU), such that pagetable updates need not
* be treated as explicit DMA data.
+ *
+ * IO_PGTABLE_QUIRK_NON_STRICT: Skip issuing synchronous leaf TLBIs
+ * on unmap, for DMA domains using the flush queue mechanism for
+ * delayed invalidation.
*/
#define IO_PGTABLE_QUIRK_ARM_NS BIT(0)
#define IO_PGTABLE_QUIRK_NO_PERMS BIT(1)
#define IO_PGTABLE_QUIRK_TLBI_ON_MAP BIT(2)
#define IO_PGTABLE_QUIRK_ARM_MTK_4GB BIT(3)
#define IO_PGTABLE_QUIRK_NO_DMA BIT(4)
+ #define IO_PGTABLE_QUIRK_NON_STRICT BIT(5)
unsigned long quirks;
unsigned long pgsize_bitmap;
unsigned int ias;
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 8c15c5980299..edbdf5d6962c 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -32,6 +32,7 @@
#include <linux/pci.h>
#include <linux/bitops.h>
#include <linux/property.h>
+#include <linux/fsl/mc.h>
#include <trace/events/iommu.h>
static struct kset *iommu_group_kset;
@@ -41,6 +42,7 @@ static unsigned int iommu_def_domain_type = IOMMU_DOMAIN_IDENTITY;
#else
static unsigned int iommu_def_domain_type = IOMMU_DOMAIN_DMA;
#endif
+static bool iommu_dma_strict __read_mostly = true;
struct iommu_callback_data {
const struct iommu_ops *ops;
@@ -131,6 +133,12 @@ static int __init iommu_set_def_domain_type(char *str)
}
early_param("iommu.passthrough", iommu_set_def_domain_type);
+static int __init iommu_dma_setup(char *str)
+{
+ return kstrtobool(str, &iommu_dma_strict);
+}
+early_param("iommu.strict", iommu_dma_setup);
+
static ssize_t iommu_group_attr_show(struct kobject *kobj,
struct attribute *__attr, char *buf)
{
@@ -1024,6 +1032,18 @@ struct iommu_group *pci_device_group(struct device *dev)
return iommu_group_alloc();
}
+/* Get the IOMMU group for device on fsl-mc bus */
+struct iommu_group *fsl_mc_device_group(struct device *dev)
+{
+ struct device *cont_dev = fsl_mc_cont_dev(dev);
+ struct iommu_group *group;
+
+ group = iommu_group_get(cont_dev);
+ if (!group)
+ group = iommu_group_alloc();
+ return group;
+}
+
/**
* iommu_group_get_for_dev - Find or create the IOMMU group for a device
* @dev: target device
@@ -1072,6 +1092,13 @@ struct iommu_group *iommu_group_get_for_dev(struct device *dev)
group->default_domain = dom;
if (!group->domain)
group->domain = dom;
+
+ if (dom && !iommu_dma_strict) {
+ int attr = 1;
+ iommu_domain_set_attr(dom,
+ DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE,
+ &attr);
+ }
}
ret = iommu_group_add_device(group, dev);
@@ -1416,7 +1443,16 @@ struct iommu_domain *iommu_get_domain_for_dev(struct device *dev)
EXPORT_SYMBOL_GPL(iommu_get_domain_for_dev);
/*
- * IOMMU groups are really the natrual working unit of the IOMMU, but
+ * For IOMMU_DOMAIN_DMA implementations which already provide their own
+ * guarantees that the group and its default domain are valid and correct.
+ */
+struct iommu_domain *iommu_get_dma_domain(struct device *dev)
+{
+ return dev->iommu_group->default_domain;
+}
+
+/*
+ * IOMMU groups are really the natural working unit of the IOMMU, but
* the IOMMU API works on domains and devices. Bridge that gap by
* iterating over the devices in a group. Ideally we'd have a single
* device which represents the requestor ID of the group, but we also
@@ -1796,7 +1832,6 @@ int iommu_domain_get_attr(struct iommu_domain *domain,
struct iommu_domain_geometry *geometry;
bool *paging;
int ret = 0;
- u32 *count;
switch (attr) {
case DOMAIN_ATTR_GEOMETRY:
@@ -1808,15 +1843,6 @@ int iommu_domain_get_attr(struct iommu_domain *domain,
paging = data;
*paging = (domain->pgsize_bitmap != 0UL);
break;
- case DOMAIN_ATTR_WINDOWS:
- count = data;
-
- if (domain->ops->domain_get_windows != NULL)
- *count = domain->ops->domain_get_windows(domain);
- else
- ret = -ENODEV;
-
- break;
default:
if (!domain->ops->domain_get_attr)
return -EINVAL;
@@ -1832,18 +1858,8 @@ int iommu_domain_set_attr(struct iommu_domain *domain,
enum iommu_attr attr, void *data)
{
int ret = 0;
- u32 *count;
switch (attr) {
- case DOMAIN_ATTR_WINDOWS:
- count = data;
-
- if (domain->ops->domain_set_windows != NULL)
- ret = domain->ops->domain_set_windows(domain, *count);
- else
- ret = -ENODEV;
-
- break;
default:
if (domain->ops->domain_set_attr == NULL)
return -EINVAL;
diff --git a/drivers/iommu/iova.c b/drivers/iommu/iova.c
index 83fe2621effe..f8d3ba247523 100644
--- a/drivers/iommu/iova.c
+++ b/drivers/iommu/iova.c
@@ -56,6 +56,7 @@ init_iova_domain(struct iova_domain *iovad, unsigned long granule,
iovad->granule = granule;
iovad->start_pfn = start_pfn;
iovad->dma_32bit_pfn = 1UL << (32 - iova_shift(iovad));
+ iovad->max32_alloc_size = iovad->dma_32bit_pfn;
iovad->flush_cb = NULL;
iovad->fq = NULL;
iovad->anchor.pfn_lo = iovad->anchor.pfn_hi = IOVA_ANCHOR;
@@ -139,8 +140,10 @@ __cached_rbnode_delete_update(struct iova_domain *iovad, struct iova *free)
cached_iova = rb_entry(iovad->cached32_node, struct iova, node);
if (free->pfn_hi < iovad->dma_32bit_pfn &&
- free->pfn_lo >= cached_iova->pfn_lo)
+ free->pfn_lo >= cached_iova->pfn_lo) {
iovad->cached32_node = rb_next(&free->node);
+ iovad->max32_alloc_size = iovad->dma_32bit_pfn;
+ }
cached_iova = rb_entry(iovad->cached_node, struct iova, node);
if (free->pfn_lo >= cached_iova->pfn_lo)
@@ -190,6 +193,10 @@ static int __alloc_and_insert_iova_range(struct iova_domain *iovad,
/* Walk the tree backwards */
spin_lock_irqsave(&iovad->iova_rbtree_lock, flags);
+ if (limit_pfn <= iovad->dma_32bit_pfn &&
+ size >= iovad->max32_alloc_size)
+ goto iova32_full;
+
curr = __get_cached_rbnode(iovad, limit_pfn);
curr_iova = rb_entry(curr, struct iova, node);
do {
@@ -200,10 +207,8 @@ static int __alloc_and_insert_iova_range(struct iova_domain *iovad,
curr_iova = rb_entry(curr, struct iova, node);
} while (curr && new_pfn <= curr_iova->pfn_hi);
- if (limit_pfn < size || new_pfn < iovad->start_pfn) {
- spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags);
- return -ENOMEM;
- }
+ if (limit_pfn < size || new_pfn < iovad->start_pfn)
+ goto iova32_full;
/* pfn_lo will point to size aligned address if size_aligned is set */
new->pfn_lo = new_pfn;
@@ -214,9 +219,12 @@ static int __alloc_and_insert_iova_range(struct iova_domain *iovad,
__cached_rbnode_insert_update(iovad, new);
spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags);
-
-
return 0;
+
+iova32_full:
+ iovad->max32_alloc_size = size;
+ spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags);
+ return -ENOMEM;
}
static struct kmem_cache *iova_cache;
diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c
index 22b94f8a9a04..b98a03189580 100644
--- a/drivers/iommu/ipmmu-vmsa.c
+++ b/drivers/iommu/ipmmu-vmsa.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* IPMMU VMSA
*
* Copyright (C) 2014 Renesas Electronics Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
*/
#include <linux/bitmap.h>
diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index f9f69f7111a9..44bd5b9166bb 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -11,7 +11,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-#include <linux/bootmem.h>
+#include <linux/memblock.h>
#include <linux/bug.h>
#include <linux/clk.h>
#include <linux/component.h>
diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c
index 676c029494e4..0e780848f59b 100644
--- a/drivers/iommu/mtk_iommu_v1.c
+++ b/drivers/iommu/mtk_iommu_v1.c
@@ -13,7 +13,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-#include <linux/bootmem.h>
+#include <linux/memblock.h>
#include <linux/bug.h>
#include <linux/clk.h>
#include <linux/component.h>
diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
index f7787e757244..c5dd63072529 100644
--- a/drivers/iommu/of_iommu.c
+++ b/drivers/iommu/of_iommu.c
@@ -24,6 +24,7 @@
#include <linux/of_iommu.h>
#include <linux/of_pci.h>
#include <linux/slab.h>
+#include <linux/fsl/mc.h>
#define NO_IOMMU 1
@@ -132,9 +133,8 @@ static int of_pci_iommu_init(struct pci_dev *pdev, u16 alias, void *data)
struct of_phandle_args iommu_spec = { .args_count = 1 };
int err;
- err = of_pci_map_rid(info->np, alias, "iommu-map",
- "iommu-map-mask", &iommu_spec.np,
- iommu_spec.args);
+ err = of_map_rid(info->np, alias, "iommu-map", "iommu-map-mask",
+ &iommu_spec.np, iommu_spec.args);
if (err)
return err == -ENODEV ? NO_IOMMU : err;
@@ -143,6 +143,23 @@ static int of_pci_iommu_init(struct pci_dev *pdev, u16 alias, void *data)
return err;
}
+static int of_fsl_mc_iommu_init(struct fsl_mc_device *mc_dev,
+ struct device_node *master_np)
+{
+ struct of_phandle_args iommu_spec = { .args_count = 1 };
+ int err;
+
+ err = of_map_rid(master_np, mc_dev->icid, "iommu-map",
+ "iommu-map-mask", &iommu_spec.np,
+ iommu_spec.args);
+ if (err)
+ return err == -ENODEV ? NO_IOMMU : err;
+
+ err = of_iommu_xlate(&mc_dev->dev, &iommu_spec);
+ of_node_put(iommu_spec.np);
+ return err;
+}
+
const struct iommu_ops *of_iommu_configure(struct device *dev,
struct device_node *master_np)
{
@@ -174,6 +191,8 @@ const struct iommu_ops *of_iommu_configure(struct device *dev,
err = pci_for_each_dma_alias(to_pci_dev(dev),
of_pci_iommu_init, &info);
+ } else if (dev_is_fsl_mc(dev)) {
+ err = of_fsl_mc_iommu_init(to_fsl_mc_device(dev), master_np);
} else {
struct of_phandle_args iommu_spec;
int idx = 0;
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 383e7b70221d..51a5ef0e96ed 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -310,6 +310,9 @@ config MVEBU_ODMI
config MVEBU_PIC
bool
+config MVEBU_SEI
+ bool
+
config LS_SCFG_MSI
def_bool y if SOC_LS1021A || ARCH_LAYERSCAPE
depends on PCI && PCI_MSI
@@ -371,6 +374,23 @@ config QCOM_PDC
Power Domain Controller driver to manage and configure wakeup
IRQs for Qualcomm Technologies Inc (QTI) mobile chips.
+config CSKY_MPINTC
+ bool "C-SKY Multi Processor Interrupt Controller"
+ depends on CSKY
+ help
+ Say yes here to enable C-SKY SMP interrupt controller driver used
+ for C-SKY SMP system.
+ In fact it's not mmio map in hw and it use ld/st to visit the
+ controller's register inside CPU.
+
+config CSKY_APB_INTC
+ bool "C-SKY APB Interrupt Controller"
+ depends on CSKY
+ help
+ Say yes here to enable C-SKY APB interrupt controller driver used
+ by C-SKY single core SOC system. It use mmio map apb-bus to visit
+ the controller's register.
+
endmenu
config SIFIVE_PLIC
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index fbd1ec8070ef..794c13d3ac3d 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -76,6 +76,7 @@ obj-$(CONFIG_MVEBU_GICP) += irq-mvebu-gicp.o
obj-$(CONFIG_MVEBU_ICU) += irq-mvebu-icu.o
obj-$(CONFIG_MVEBU_ODMI) += irq-mvebu-odmi.o
obj-$(CONFIG_MVEBU_PIC) += irq-mvebu-pic.o
+obj-$(CONFIG_MVEBU_SEI) += irq-mvebu-sei.o
obj-$(CONFIG_LS_SCFG_MSI) += irq-ls-scfg-msi.o
obj-$(CONFIG_EZNPS_GIC) += irq-eznps.o
obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o irq-aspeed-i2c-ic.o
@@ -87,4 +88,6 @@ obj-$(CONFIG_MESON_IRQ_GPIO) += irq-meson-gpio.o
obj-$(CONFIG_GOLDFISH_PIC) += irq-goldfish-pic.o
obj-$(CONFIG_NDS32) += irq-ativic32.o
obj-$(CONFIG_QCOM_PDC) += qcom-pdc.o
+obj-$(CONFIG_CSKY_MPINTC) += irq-csky-mpintc.o
+obj-$(CONFIG_CSKY_APB_INTC) += irq-csky-apb-intc.o
obj-$(CONFIG_SIFIVE_PLIC) += irq-sifive-plic.o
diff --git a/drivers/irqchip/irq-csky-apb-intc.c b/drivers/irqchip/irq-csky-apb-intc.c
new file mode 100644
index 000000000000..2543baba8b1f
--- /dev/null
+++ b/drivers/irqchip/irq-csky-apb-intc.c
@@ -0,0 +1,274 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/module.h>
+#include <linux/irqdomain.h>
+#include <linux/irqchip.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <asm/irq.h>
+
+#define INTC_IRQS 64
+
+#define CK_INTC_ICR 0x00
+#define CK_INTC_PEN31_00 0x14
+#define CK_INTC_PEN63_32 0x2c
+#define CK_INTC_NEN31_00 0x10
+#define CK_INTC_NEN63_32 0x28
+#define CK_INTC_SOURCE 0x40
+#define CK_INTC_DUAL_BASE 0x100
+
+#define GX_INTC_PEN31_00 0x00
+#define GX_INTC_PEN63_32 0x04
+#define GX_INTC_NEN31_00 0x40
+#define GX_INTC_NEN63_32 0x44
+#define GX_INTC_NMASK31_00 0x50
+#define GX_INTC_NMASK63_32 0x54
+#define GX_INTC_SOURCE 0x60
+
+static void __iomem *reg_base;
+static struct irq_domain *root_domain;
+
+static int nr_irq = INTC_IRQS;
+
+/*
+ * When controller support pulse signal, the PEN_reg will hold on signal
+ * without software trigger.
+ *
+ * So, to support pulse signal we need to clear IFR_reg and the address of
+ * IFR_offset is NEN_offset - 8.
+ */
+static void irq_ck_mask_set_bit(struct irq_data *d)
+{
+ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+ struct irq_chip_type *ct = irq_data_get_chip_type(d);
+ unsigned long ifr = ct->regs.mask - 8;
+ u32 mask = d->mask;
+
+ irq_gc_lock(gc);
+ *ct->mask_cache |= mask;
+ irq_reg_writel(gc, *ct->mask_cache, ct->regs.mask);
+ irq_reg_writel(gc, irq_reg_readl(gc, ifr) & ~mask, ifr);
+ irq_gc_unlock(gc);
+}
+
+static void __init ck_set_gc(struct device_node *node, void __iomem *reg_base,
+ u32 mask_reg, u32 irq_base)
+{
+ struct irq_chip_generic *gc;
+
+ gc = irq_get_domain_generic_chip(root_domain, irq_base);
+ gc->reg_base = reg_base;
+ gc->chip_types[0].regs.mask = mask_reg;
+ gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
+ gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
+
+ if (of_find_property(node, "csky,support-pulse-signal", NULL))
+ gc->chip_types[0].chip.irq_unmask = irq_ck_mask_set_bit;
+}
+
+static inline u32 build_channel_val(u32 idx, u32 magic)
+{
+ u32 res;
+
+ /*
+ * Set the same index for each channel
+ */
+ res = idx | (idx << 8) | (idx << 16) | (idx << 24);
+
+ /*
+ * Set the channel magic number in descending order.
+ * The magic is 0x00010203 for ck-intc
+ * The magic is 0x03020100 for gx6605s-intc
+ */
+ return res | magic;
+}
+
+static inline void setup_irq_channel(u32 magic, void __iomem *reg_addr)
+{
+ u32 i;
+
+ /* Setup 64 channel slots */
+ for (i = 0; i < INTC_IRQS; i += 4)
+ writel_relaxed(build_channel_val(i, magic), reg_addr + i);
+}
+
+static int __init
+ck_intc_init_comm(struct device_node *node, struct device_node *parent)
+{
+ int ret;
+
+ if (parent) {
+ pr_err("C-SKY Intc not a root irq controller\n");
+ return -EINVAL;
+ }
+
+ reg_base = of_iomap(node, 0);
+ if (!reg_base) {
+ pr_err("C-SKY Intc unable to map: %p.\n", node);
+ return -EINVAL;
+ }
+
+ root_domain = irq_domain_add_linear(node, nr_irq,
+ &irq_generic_chip_ops, NULL);
+ if (!root_domain) {
+ pr_err("C-SKY Intc irq_domain_add failed.\n");
+ return -ENOMEM;
+ }
+
+ ret = irq_alloc_domain_generic_chips(root_domain, 32, 1,
+ "csky_intc", handle_level_irq,
+ IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN, 0, 0);
+ if (ret) {
+ pr_err("C-SKY Intc irq_alloc_gc failed.\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static inline bool handle_irq_perbit(struct pt_regs *regs, u32 hwirq,
+ u32 irq_base)
+{
+ u32 irq;
+
+ if (hwirq == 0)
+ return 0;
+
+ while (hwirq) {
+ irq = __ffs(hwirq);
+ hwirq &= ~BIT(irq);
+ handle_domain_irq(root_domain, irq_base + irq, regs);
+ }
+
+ return 1;
+}
+
+/* gx6605s 64 irqs interrupt controller */
+static void gx_irq_handler(struct pt_regs *regs)
+{
+ bool ret;
+
+ do {
+ ret = handle_irq_perbit(regs,
+ readl_relaxed(reg_base + GX_INTC_PEN31_00), 0);
+ ret |= handle_irq_perbit(regs,
+ readl_relaxed(reg_base + GX_INTC_PEN63_32), 32);
+ } while (ret);
+}
+
+static int __init
+gx_intc_init(struct device_node *node, struct device_node *parent)
+{
+ int ret;
+
+ ret = ck_intc_init_comm(node, parent);
+ if (ret)
+ return ret;
+
+ /*
+ * Initial enable reg to disable all interrupts
+ */
+ writel_relaxed(0x0, reg_base + GX_INTC_NEN31_00);
+ writel_relaxed(0x0, reg_base + GX_INTC_NEN63_32);
+
+ /*
+ * Initial mask reg with all unmasked, because we only use enalbe reg
+ */
+ writel_relaxed(0x0, reg_base + GX_INTC_NMASK31_00);
+ writel_relaxed(0x0, reg_base + GX_INTC_NMASK63_32);
+
+ setup_irq_channel(0x03020100, reg_base + GX_INTC_SOURCE);
+
+ ck_set_gc(node, reg_base, GX_INTC_NEN31_00, 0);
+ ck_set_gc(node, reg_base, GX_INTC_NEN63_32, 32);
+
+ set_handle_irq(gx_irq_handler);
+
+ return 0;
+}
+IRQCHIP_DECLARE(csky_gx6605s_intc, "csky,gx6605s-intc", gx_intc_init);
+
+/*
+ * C-SKY simple 64 irqs interrupt controller, dual-together could support 128
+ * irqs.
+ */
+static void ck_irq_handler(struct pt_regs *regs)
+{
+ bool ret;
+ void __iomem *reg_pen_lo = reg_base + CK_INTC_PEN31_00;
+ void __iomem *reg_pen_hi = reg_base + CK_INTC_PEN63_32;
+
+ do {
+ /* handle 0 - 31 irqs */
+ ret = handle_irq_perbit(regs, readl_relaxed(reg_pen_lo), 0);
+ ret |= handle_irq_perbit(regs, readl_relaxed(reg_pen_hi), 32);
+
+ if (nr_irq == INTC_IRQS)
+ continue;
+
+ /* handle 64 - 127 irqs */
+ ret |= handle_irq_perbit(regs,
+ readl_relaxed(reg_pen_lo + CK_INTC_DUAL_BASE), 64);
+ ret |= handle_irq_perbit(regs,
+ readl_relaxed(reg_pen_hi + CK_INTC_DUAL_BASE), 96);
+ } while (ret);
+}
+
+static int __init
+ck_intc_init(struct device_node *node, struct device_node *parent)
+{
+ int ret;
+
+ ret = ck_intc_init_comm(node, parent);
+ if (ret)
+ return ret;
+
+ /* Initial enable reg to disable all interrupts */
+ writel_relaxed(0, reg_base + CK_INTC_NEN31_00);
+ writel_relaxed(0, reg_base + CK_INTC_NEN63_32);
+
+ /* Enable irq intc */
+ writel_relaxed(BIT(31), reg_base + CK_INTC_ICR);
+
+ ck_set_gc(node, reg_base, CK_INTC_NEN31_00, 0);
+ ck_set_gc(node, reg_base, CK_INTC_NEN63_32, 32);
+
+ setup_irq_channel(0x00010203, reg_base + CK_INTC_SOURCE);
+
+ set_handle_irq(ck_irq_handler);
+
+ return 0;
+}
+IRQCHIP_DECLARE(ck_intc, "csky,apb-intc", ck_intc_init);
+
+static int __init
+ck_dual_intc_init(struct device_node *node, struct device_node *parent)
+{
+ int ret;
+
+ /* dual-apb-intc up to 128 irq sources*/
+ nr_irq = INTC_IRQS * 2;
+
+ ret = ck_intc_init(node, parent);
+ if (ret)
+ return ret;
+
+ /* Initial enable reg to disable all interrupts */
+ writel_relaxed(0, reg_base + CK_INTC_NEN31_00 + CK_INTC_DUAL_BASE);
+ writel_relaxed(0, reg_base + CK_INTC_NEN63_32 + CK_INTC_DUAL_BASE);
+
+ ck_set_gc(node, reg_base + CK_INTC_DUAL_BASE, CK_INTC_NEN31_00, 64);
+ ck_set_gc(node, reg_base + CK_INTC_DUAL_BASE, CK_INTC_NEN63_32, 96);
+
+ setup_irq_channel(0x00010203,
+ reg_base + CK_INTC_SOURCE + CK_INTC_DUAL_BASE);
+
+ return 0;
+}
+IRQCHIP_DECLARE(ck_dual_intc, "csky,dual-apb-intc", ck_dual_intc_init);
diff --git a/drivers/irqchip/irq-csky-mpintc.c b/drivers/irqchip/irq-csky-mpintc.c
new file mode 100644
index 000000000000..c67c961ab6cc
--- /dev/null
+++ b/drivers/irqchip/irq-csky-mpintc.c
@@ -0,0 +1,198 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/module.h>
+#include <linux/irqdomain.h>
+#include <linux/irqchip.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/smp.h>
+#include <linux/io.h>
+#include <asm/irq.h>
+#include <asm/traps.h>
+#include <asm/reg_ops.h>
+
+static struct irq_domain *root_domain;
+static void __iomem *INTCG_base;
+static void __iomem *INTCL_base;
+
+#define IPI_IRQ 15
+#define INTC_IRQS 256
+#define COMM_IRQ_BASE 32
+
+#define INTCG_SIZE 0x8000
+#define INTCL_SIZE 0x1000
+
+#define INTCG_ICTLR 0x0
+#define INTCG_CICFGR 0x100
+#define INTCG_CIDSTR 0x1000
+
+#define INTCL_PICTLR 0x0
+#define INTCL_SIGR 0x60
+#define INTCL_HPPIR 0x68
+#define INTCL_RDYIR 0x6c
+#define INTCL_SENR 0xa0
+#define INTCL_CENR 0xa4
+#define INTCL_CACR 0xb4
+
+static DEFINE_PER_CPU(void __iomem *, intcl_reg);
+
+static void csky_mpintc_handler(struct pt_regs *regs)
+{
+ void __iomem *reg_base = this_cpu_read(intcl_reg);
+
+ do {
+ handle_domain_irq(root_domain,
+ readl_relaxed(reg_base + INTCL_RDYIR),
+ regs);
+ } while (readl_relaxed(reg_base + INTCL_HPPIR) & BIT(31));
+}
+
+static void csky_mpintc_enable(struct irq_data *d)
+{
+ void __iomem *reg_base = this_cpu_read(intcl_reg);
+
+ writel_relaxed(d->hwirq, reg_base + INTCL_SENR);
+}
+
+static void csky_mpintc_disable(struct irq_data *d)
+{
+ void __iomem *reg_base = this_cpu_read(intcl_reg);
+
+ writel_relaxed(d->hwirq, reg_base + INTCL_CENR);
+}
+
+static void csky_mpintc_eoi(struct irq_data *d)
+{
+ void __iomem *reg_base = this_cpu_read(intcl_reg);
+
+ writel_relaxed(d->hwirq, reg_base + INTCL_CACR);
+}
+
+#ifdef CONFIG_SMP
+static int csky_irq_set_affinity(struct irq_data *d,
+ const struct cpumask *mask_val,
+ bool force)
+{
+ unsigned int cpu;
+ unsigned int offset = 4 * (d->hwirq - COMM_IRQ_BASE);
+
+ if (!force)
+ cpu = cpumask_any_and(mask_val, cpu_online_mask);
+ else
+ cpu = cpumask_first(mask_val);
+
+ if (cpu >= nr_cpu_ids)
+ return -EINVAL;
+
+ /* Enable interrupt destination */
+ cpu |= BIT(31);
+
+ writel_relaxed(cpu, INTCG_base + INTCG_CIDSTR + offset);
+
+ irq_data_update_effective_affinity(d, cpumask_of(cpu));
+
+ return IRQ_SET_MASK_OK_DONE;
+}
+#endif
+
+static struct irq_chip csky_irq_chip = {
+ .name = "C-SKY SMP Intc",
+ .irq_eoi = csky_mpintc_eoi,
+ .irq_enable = csky_mpintc_enable,
+ .irq_disable = csky_mpintc_disable,
+#ifdef CONFIG_SMP
+ .irq_set_affinity = csky_irq_set_affinity,
+#endif
+};
+
+static int csky_irqdomain_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hwirq)
+{
+ if (hwirq < COMM_IRQ_BASE) {
+ irq_set_percpu_devid(irq);
+ irq_set_chip_and_handler(irq, &csky_irq_chip,
+ handle_percpu_irq);
+ } else {
+ irq_set_chip_and_handler(irq, &csky_irq_chip,
+ handle_fasteoi_irq);
+ }
+
+ return 0;
+}
+
+static const struct irq_domain_ops csky_irqdomain_ops = {
+ .map = csky_irqdomain_map,
+ .xlate = irq_domain_xlate_onecell,
+};
+
+#ifdef CONFIG_SMP
+static void csky_mpintc_send_ipi(const struct cpumask *mask)
+{
+ void __iomem *reg_base = this_cpu_read(intcl_reg);
+
+ /*
+ * INTCL_SIGR[3:0] INTID
+ * INTCL_SIGR[8:15] CPUMASK
+ */
+ writel_relaxed((*cpumask_bits(mask)) << 8 | IPI_IRQ,
+ reg_base + INTCL_SIGR);
+}
+#endif
+
+/* C-SKY multi processor interrupt controller */
+static int __init
+csky_mpintc_init(struct device_node *node, struct device_node *parent)
+{
+ int ret;
+ unsigned int cpu, nr_irq;
+#ifdef CONFIG_SMP
+ unsigned int ipi_irq;
+#endif
+
+ if (parent)
+ return 0;
+
+ ret = of_property_read_u32(node, "csky,num-irqs", &nr_irq);
+ if (ret < 0)
+ nr_irq = INTC_IRQS;
+
+ if (INTCG_base == NULL) {
+ INTCG_base = ioremap(mfcr("cr<31, 14>"),
+ INTCL_SIZE*nr_cpu_ids + INTCG_SIZE);
+ if (INTCG_base == NULL)
+ return -EIO;
+
+ INTCL_base = INTCG_base + INTCG_SIZE;
+
+ writel_relaxed(BIT(0), INTCG_base + INTCG_ICTLR);
+ }
+
+ root_domain = irq_domain_add_linear(node, nr_irq, &csky_irqdomain_ops,
+ NULL);
+ if (!root_domain)
+ return -ENXIO;
+
+ /* for every cpu */
+ for_each_present_cpu(cpu) {
+ per_cpu(intcl_reg, cpu) = INTCL_base + (INTCL_SIZE * cpu);
+ writel_relaxed(BIT(0), per_cpu(intcl_reg, cpu) + INTCL_PICTLR);
+ }
+
+ set_handle_irq(&csky_mpintc_handler);
+
+#ifdef CONFIG_SMP
+ ipi_irq = irq_create_mapping(root_domain, IPI_IRQ);
+ if (!ipi_irq)
+ return -EIO;
+
+ set_send_ipi(&csky_mpintc_send_ipi, ipi_irq);
+#endif
+
+ return 0;
+}
+IRQCHIP_DECLARE(csky_mpintc, "csky,mpintc", csky_mpintc_init);
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index c2df341ff6fa..db20e992a40f 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -19,13 +19,16 @@
#include <linux/acpi_iort.h>
#include <linux/bitmap.h>
#include <linux/cpu.h>
+#include <linux/crash_dump.h>
#include <linux/delay.h>
#include <linux/dma-iommu.h>
+#include <linux/efi.h>
#include <linux/interrupt.h>
#include <linux/irqdomain.h>
#include <linux/list.h>
#include <linux/list_sort.h>
#include <linux/log2.h>
+#include <linux/memblock.h>
#include <linux/mm.h>
#include <linux/msi.h>
#include <linux/of.h>
@@ -52,6 +55,7 @@
#define ITS_FLAGS_SAVE_SUSPEND_STATE (1ULL << 3)
#define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING (1 << 0)
+#define RDIST_FLAGS_RD_TABLES_PREALLOCATED (1 << 1)
static u32 lpi_id_bits;
@@ -64,7 +68,7 @@ static u32 lpi_id_bits;
#define LPI_PROPBASE_SZ ALIGN(BIT(LPI_NRBITS), SZ_64K)
#define LPI_PENDBASE_SZ ALIGN(BIT(LPI_NRBITS) / 8, SZ_64K)
-#define LPI_PROP_DEFAULT_PRIO 0xa0
+#define LPI_PROP_DEFAULT_PRIO GICD_INT_DEF_PRI
/*
* Collection structure - just an ID, and a redistributor address to
@@ -173,6 +177,7 @@ static DEFINE_RAW_SPINLOCK(vmovp_lock);
static DEFINE_IDA(its_vpeid_ida);
#define gic_data_rdist() (raw_cpu_ptr(gic_rdists->rdist))
+#define gic_data_rdist_cpu(cpu) (per_cpu_ptr(gic_rdists->rdist, cpu))
#define gic_data_rdist_rd_base() (gic_data_rdist()->rd_base)
#define gic_data_rdist_vlpi_base() (gic_data_rdist_rd_base() + SZ_128K)
@@ -1028,7 +1033,7 @@ static inline u32 its_get_event_id(struct irq_data *d)
static void lpi_write_config(struct irq_data *d, u8 clr, u8 set)
{
irq_hw_number_t hwirq;
- struct page *prop_page;
+ void *va;
u8 *cfg;
if (irqd_is_forwarded_to_vcpu(d)) {
@@ -1036,7 +1041,7 @@ static void lpi_write_config(struct irq_data *d, u8 clr, u8 set)
u32 event = its_get_event_id(d);
struct its_vlpi_map *map;
- prop_page = its_dev->event_map.vm->vprop_page;
+ va = page_address(its_dev->event_map.vm->vprop_page);
map = &its_dev->event_map.vlpi_maps[event];
hwirq = map->vintid;
@@ -1044,11 +1049,11 @@ static void lpi_write_config(struct irq_data *d, u8 clr, u8 set)
map->properties &= ~clr;
map->properties |= set | LPI_PROP_GROUP1;
} else {
- prop_page = gic_rdists->prop_page;
+ va = gic_rdists->prop_table_va;
hwirq = d->hwirq;
}
- cfg = page_address(prop_page) + hwirq - 8192;
+ cfg = va + hwirq - 8192;
*cfg &= ~clr;
*cfg |= set | LPI_PROP_GROUP1;
@@ -1597,6 +1602,15 @@ static void its_lpi_free(unsigned long *bitmap, u32 base, u32 nr_ids)
kfree(bitmap);
}
+static void gic_reset_prop_table(void *va)
+{
+ /* Priority 0xa0, Group-1, disabled */
+ memset(va, LPI_PROP_DEFAULT_PRIO | LPI_PROP_GROUP1, LPI_PROPBASE_SZ);
+
+ /* Make sure the GIC will observe the written configuration */
+ gic_flush_dcache_to_poc(va, LPI_PROPBASE_SZ);
+}
+
static struct page *its_allocate_prop_table(gfp_t gfp_flags)
{
struct page *prop_page;
@@ -1605,13 +1619,7 @@ static struct page *its_allocate_prop_table(gfp_t gfp_flags)
if (!prop_page)
return NULL;
- /* Priority 0xa0, Group-1, disabled */
- memset(page_address(prop_page),
- LPI_PROP_DEFAULT_PRIO | LPI_PROP_GROUP1,
- LPI_PROPBASE_SZ);
-
- /* Make sure the GIC will observe the written configuration */
- gic_flush_dcache_to_poc(page_address(prop_page), LPI_PROPBASE_SZ);
+ gic_reset_prop_table(page_address(prop_page));
return prop_page;
}
@@ -1622,20 +1630,74 @@ static void its_free_prop_table(struct page *prop_page)
get_order(LPI_PROPBASE_SZ));
}
-static int __init its_alloc_lpi_tables(void)
+static bool gic_check_reserved_range(phys_addr_t addr, unsigned long size)
{
- phys_addr_t paddr;
+ phys_addr_t start, end, addr_end;
+ u64 i;
- lpi_id_bits = min_t(u32, GICD_TYPER_ID_BITS(gic_rdists->gicd_typer),
- ITS_MAX_LPI_NRBITS);
- gic_rdists->prop_page = its_allocate_prop_table(GFP_NOWAIT);
- if (!gic_rdists->prop_page) {
- pr_err("Failed to allocate PROPBASE\n");
- return -ENOMEM;
+ /*
+ * We don't bother checking for a kdump kernel as by
+ * construction, the LPI tables are out of this kernel's
+ * memory map.
+ */
+ if (is_kdump_kernel())
+ return true;
+
+ addr_end = addr + size - 1;
+
+ for_each_reserved_mem_region(i, &start, &end) {
+ if (addr >= start && addr_end <= end)
+ return true;
+ }
+
+ /* Not found, not a good sign... */
+ pr_warn("GICv3: Expected reserved range [%pa:%pa], not found\n",
+ &addr, &addr_end);
+ add_taint(TAINT_CRAP, LOCKDEP_STILL_OK);
+ return false;
+}
+
+static int gic_reserve_range(phys_addr_t addr, unsigned long size)
+{
+ if (efi_enabled(EFI_CONFIG_TABLES))
+ return efi_mem_reserve_persistent(addr, size);
+
+ return 0;
+}
+
+static int __init its_setup_lpi_prop_table(void)
+{
+ if (gic_rdists->flags & RDIST_FLAGS_RD_TABLES_PREALLOCATED) {
+ u64 val;
+
+ val = gicr_read_propbaser(gic_data_rdist_rd_base() + GICR_PROPBASER);
+ lpi_id_bits = (val & GICR_PROPBASER_IDBITS_MASK) + 1;
+
+ gic_rdists->prop_table_pa = val & GENMASK_ULL(51, 12);
+ gic_rdists->prop_table_va = memremap(gic_rdists->prop_table_pa,
+ LPI_PROPBASE_SZ,
+ MEMREMAP_WB);
+ gic_reset_prop_table(gic_rdists->prop_table_va);
+ } else {
+ struct page *page;
+
+ lpi_id_bits = min_t(u32,
+ GICD_TYPER_ID_BITS(gic_rdists->gicd_typer),
+ ITS_MAX_LPI_NRBITS);
+ page = its_allocate_prop_table(GFP_NOWAIT);
+ if (!page) {
+ pr_err("Failed to allocate PROPBASE\n");
+ return -ENOMEM;
+ }
+
+ gic_rdists->prop_table_pa = page_to_phys(page);
+ gic_rdists->prop_table_va = page_address(page);
+ WARN_ON(gic_reserve_range(gic_rdists->prop_table_pa,
+ LPI_PROPBASE_SZ));
}
- paddr = page_to_phys(gic_rdists->prop_page);
- pr_info("GIC: using LPI property table @%pa\n", &paddr);
+ pr_info("GICv3: using LPI property table @%pa\n",
+ &gic_rdists->prop_table_pa);
return its_lpi_init(lpi_id_bits);
}
@@ -1924,12 +1986,9 @@ static int its_alloc_collections(struct its_node *its)
static struct page *its_allocate_pending_table(gfp_t gfp_flags)
{
struct page *pend_page;
- /*
- * The pending pages have to be at least 64kB aligned,
- * hence the 'max(LPI_PENDBASE_SZ, SZ_64K)' below.
- */
+
pend_page = alloc_pages(gfp_flags | __GFP_ZERO,
- get_order(max_t(u32, LPI_PENDBASE_SZ, SZ_64K)));
+ get_order(LPI_PENDBASE_SZ));
if (!pend_page)
return NULL;
@@ -1941,36 +2000,103 @@ static struct page *its_allocate_pending_table(gfp_t gfp_flags)
static void its_free_pending_table(struct page *pt)
{
- free_pages((unsigned long)page_address(pt),
- get_order(max_t(u32, LPI_PENDBASE_SZ, SZ_64K)));
+ free_pages((unsigned long)page_address(pt), get_order(LPI_PENDBASE_SZ));
+}
+
+/*
+ * Booting with kdump and LPIs enabled is generally fine. Any other
+ * case is wrong in the absence of firmware/EFI support.
+ */
+static bool enabled_lpis_allowed(void)
+{
+ phys_addr_t addr;
+ u64 val;
+
+ /* Check whether the property table is in a reserved region */
+ val = gicr_read_propbaser(gic_data_rdist_rd_base() + GICR_PROPBASER);
+ addr = val & GENMASK_ULL(51, 12);
+
+ return gic_check_reserved_range(addr, LPI_PROPBASE_SZ);
+}
+
+static int __init allocate_lpi_tables(void)
+{
+ u64 val;
+ int err, cpu;
+
+ /*
+ * If LPIs are enabled while we run this from the boot CPU,
+ * flag the RD tables as pre-allocated if the stars do align.
+ */
+ val = readl_relaxed(gic_data_rdist_rd_base() + GICR_CTLR);
+ if ((val & GICR_CTLR_ENABLE_LPIS) && enabled_lpis_allowed()) {
+ gic_rdists->flags |= (RDIST_FLAGS_RD_TABLES_PREALLOCATED |
+ RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING);
+ pr_info("GICv3: Using preallocated redistributor tables\n");
+ }
+
+ err = its_setup_lpi_prop_table();
+ if (err)
+ return err;
+
+ /*
+ * We allocate all the pending tables anyway, as we may have a
+ * mix of RDs that have had LPIs enabled, and some that
+ * don't. We'll free the unused ones as each CPU comes online.
+ */
+ for_each_possible_cpu(cpu) {
+ struct page *pend_page;
+
+ pend_page = its_allocate_pending_table(GFP_NOWAIT);
+ if (!pend_page) {
+ pr_err("Failed to allocate PENDBASE for CPU%d\n", cpu);
+ return -ENOMEM;
+ }
+
+ gic_data_rdist_cpu(cpu)->pend_page = pend_page;
+ }
+
+ return 0;
}
static void its_cpu_init_lpis(void)
{
void __iomem *rbase = gic_data_rdist_rd_base();
struct page *pend_page;
+ phys_addr_t paddr;
u64 val, tmp;
- /* If we didn't allocate the pending table yet, do it now */
- pend_page = gic_data_rdist()->pend_page;
- if (!pend_page) {
- phys_addr_t paddr;
+ if (gic_data_rdist()->lpi_enabled)
+ return;
- pend_page = its_allocate_pending_table(GFP_NOWAIT);
- if (!pend_page) {
- pr_err("Failed to allocate PENDBASE for CPU%d\n",
- smp_processor_id());
- return;
- }
+ val = readl_relaxed(rbase + GICR_CTLR);
+ if ((gic_rdists->flags & RDIST_FLAGS_RD_TABLES_PREALLOCATED) &&
+ (val & GICR_CTLR_ENABLE_LPIS)) {
+ /*
+ * Check that we get the same property table on all
+ * RDs. If we don't, this is hopeless.
+ */
+ paddr = gicr_read_propbaser(rbase + GICR_PROPBASER);
+ paddr &= GENMASK_ULL(51, 12);
+ if (WARN_ON(gic_rdists->prop_table_pa != paddr))
+ add_taint(TAINT_CRAP, LOCKDEP_STILL_OK);
+
+ paddr = gicr_read_pendbaser(rbase + GICR_PENDBASER);
+ paddr &= GENMASK_ULL(51, 16);
- paddr = page_to_phys(pend_page);
- pr_info("CPU%d: using LPI pending table @%pa\n",
- smp_processor_id(), &paddr);
- gic_data_rdist()->pend_page = pend_page;
+ WARN_ON(!gic_check_reserved_range(paddr, LPI_PENDBASE_SZ));
+ its_free_pending_table(gic_data_rdist()->pend_page);
+ gic_data_rdist()->pend_page = NULL;
+
+ goto out;
}
+ pend_page = gic_data_rdist()->pend_page;
+ paddr = page_to_phys(pend_page);
+ WARN_ON(gic_reserve_range(paddr, LPI_PENDBASE_SZ));
+
/* set PROPBASE */
- val = (page_to_phys(gic_rdists->prop_page) |
+ val = (gic_rdists->prop_table_pa |
GICR_PROPBASER_InnerShareable |
GICR_PROPBASER_RaWaWb |
((LPI_NRBITS - 1) & GICR_PROPBASER_IDBITS_MASK));
@@ -2020,6 +2146,12 @@ static void its_cpu_init_lpis(void)
/* Make sure the GIC has seen the above */
dsb(sy);
+out:
+ gic_data_rdist()->lpi_enabled = true;
+ pr_info("GICv3: CPU%d: using %s LPI pending table @%pa\n",
+ smp_processor_id(),
+ gic_data_rdist()->pend_page ? "allocated" : "reserved",
+ &paddr);
}
static void its_cpu_init_collection(struct its_node *its)
@@ -3498,16 +3630,6 @@ static int redist_disable_lpis(void)
u64 timeout = USEC_PER_SEC;
u64 val;
- /*
- * If coming via a CPU hotplug event, we don't need to disable
- * LPIs before trying to re-enable them. They are already
- * configured and all is well in the world. Detect this case
- * by checking the allocation of the pending table for the
- * current CPU.
- */
- if (gic_data_rdist()->pend_page)
- return 0;
-
if (!gic_rdists_supports_plpis()) {
pr_info("CPU%d: LPIs not supported\n", smp_processor_id());
return -ENXIO;
@@ -3517,7 +3639,21 @@ static int redist_disable_lpis(void)
if (!(val & GICR_CTLR_ENABLE_LPIS))
return 0;
- pr_warn("CPU%d: Booted with LPIs enabled, memory probably corrupted\n",
+ /*
+ * If coming via a CPU hotplug event, we don't need to disable
+ * LPIs before trying to re-enable them. They are already
+ * configured and all is well in the world.
+ *
+ * If running with preallocated tables, there is nothing to do.
+ */
+ if (gic_data_rdist()->lpi_enabled ||
+ (gic_rdists->flags & RDIST_FLAGS_RD_TABLES_PREALLOCATED))
+ return 0;
+
+ /*
+ * From that point on, we only try to do some damage control.
+ */
+ pr_warn("GICv3: CPU%d: Booted with LPIs enabled, memory probably corrupted\n",
smp_processor_id());
add_taint(TAINT_CRAP, LOCKDEP_STILL_OK);
@@ -3773,7 +3909,8 @@ int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,
}
gic_rdists = rdists;
- err = its_alloc_lpi_tables();
+
+ err = allocate_lpi_tables();
if (err)
return err;
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index d5912f1ec884..8f87f40c9460 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -348,48 +348,45 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs
{
u32 irqnr;
- do {
- irqnr = gic_read_iar();
+ irqnr = gic_read_iar();
- if (likely(irqnr > 15 && irqnr < 1020) || irqnr >= 8192) {
- int err;
+ if (likely(irqnr > 15 && irqnr < 1020) || irqnr >= 8192) {
+ int err;
- if (static_branch_likely(&supports_deactivate_key))
+ if (static_branch_likely(&supports_deactivate_key))
+ gic_write_eoir(irqnr);
+ else
+ isb();
+
+ err = handle_domain_irq(gic_data.domain, irqnr, regs);
+ if (err) {
+ WARN_ONCE(true, "Unexpected interrupt received!\n");
+ if (static_branch_likely(&supports_deactivate_key)) {
+ if (irqnr < 8192)
+ gic_write_dir(irqnr);
+ } else {
gic_write_eoir(irqnr);
- else
- isb();
-
- err = handle_domain_irq(gic_data.domain, irqnr, regs);
- if (err) {
- WARN_ONCE(true, "Unexpected interrupt received!\n");
- if (static_branch_likely(&supports_deactivate_key)) {
- if (irqnr < 8192)
- gic_write_dir(irqnr);
- } else {
- gic_write_eoir(irqnr);
- }
}
- continue;
}
- if (irqnr < 16) {
- gic_write_eoir(irqnr);
- if (static_branch_likely(&supports_deactivate_key))
- gic_write_dir(irqnr);
+ return;
+ }
+ if (irqnr < 16) {
+ gic_write_eoir(irqnr);
+ if (static_branch_likely(&supports_deactivate_key))
+ gic_write_dir(irqnr);
#ifdef CONFIG_SMP
- /*
- * Unlike GICv2, we don't need an smp_rmb() here.
- * The control dependency from gic_read_iar to
- * the ISB in gic_write_eoir is enough to ensure
- * that any shared data read by handle_IPI will
- * be read after the ACK.
- */
- handle_IPI(irqnr, regs);
+ /*
+ * Unlike GICv2, we don't need an smp_rmb() here.
+ * The control dependency from gic_read_iar to
+ * the ISB in gic_write_eoir is enough to ensure
+ * that any shared data read by handle_IPI will
+ * be read after the ACK.
+ */
+ handle_IPI(irqnr, regs);
#else
- WARN_ONCE(true, "Unexpected SGI received!\n");
+ WARN_ONCE(true, "Unexpected SGI received!\n");
#endif
- continue;
- }
- } while (irqnr != ICC_IAR1_EL1_SPURIOUS);
+ }
}
static void __init gic_dist_init(void)
@@ -653,7 +650,9 @@ early_param("irqchip.gicv3_nolpi", gicv3_nolpi_cfg);
static int gic_dist_supports_lpis(void)
{
- return !!(readl_relaxed(gic_data.dist_base + GICD_TYPER) & GICD_TYPER_LPIS) && !gicv3_nolpi;
+ return (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) &&
+ !!(readl_relaxed(gic_data.dist_base + GICD_TYPER) & GICD_TYPER_LPIS) &&
+ !gicv3_nolpi);
}
static void gic_cpu_init(void)
@@ -673,10 +672,6 @@ static void gic_cpu_init(void)
gic_cpu_config(rbase, gic_redist_wait_for_rwp);
- /* Give LPIs a spin */
- if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis())
- its_cpu_init();
-
/* initialise system registers */
gic_cpu_sys_reg_init();
}
@@ -689,6 +684,10 @@ static void gic_cpu_init(void)
static int gic_starting_cpu(unsigned int cpu)
{
gic_cpu_init();
+
+ if (gic_dist_supports_lpis())
+ its_cpu_init();
+
return 0;
}
@@ -1127,14 +1126,16 @@ static int __init gic_init_bases(void __iomem *dist_base,
gic_update_vlpi_properties();
- if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis())
- its_init(handle, &gic_data.rdists, gic_data.domain);
-
gic_smp_init();
gic_dist_init();
gic_cpu_init();
gic_cpu_pm_init();
+ if (gic_dist_supports_lpis()) {
+ its_init(handle, &gic_data.rdists, gic_data.domain);
+ its_cpu_init();
+ }
+
return 0;
out_free:
diff --git a/drivers/irqchip/irq-mvebu-icu.c b/drivers/irqchip/irq-mvebu-icu.c
index 13063339b416..547045d89c4b 100644
--- a/drivers/irqchip/irq-mvebu-icu.c
+++ b/drivers/irqchip/irq-mvebu-icu.c
@@ -13,6 +13,7 @@
#include <linux/irq.h>
#include <linux/irqchip.h>
#include <linux/irqdomain.h>
+#include <linux/jump_label.h>
#include <linux/kernel.h>
#include <linux/msi.h>
#include <linux/of_irq.h>
@@ -26,6 +27,10 @@
#define ICU_SETSPI_NSR_AH 0x14
#define ICU_CLRSPI_NSR_AL 0x18
#define ICU_CLRSPI_NSR_AH 0x1c
+#define ICU_SET_SEI_AL 0x50
+#define ICU_SET_SEI_AH 0x54
+#define ICU_CLR_SEI_AL 0x58
+#define ICU_CLR_SEI_AH 0x5C
#define ICU_INT_CFG(x) (0x100 + 4 * (x))
#define ICU_INT_ENABLE BIT(24)
#define ICU_IS_EDGE BIT(28)
@@ -36,12 +41,23 @@
#define ICU_SATA0_ICU_ID 109
#define ICU_SATA1_ICU_ID 107
+struct mvebu_icu_subset_data {
+ unsigned int icu_group;
+ unsigned int offset_set_ah;
+ unsigned int offset_set_al;
+ unsigned int offset_clr_ah;
+ unsigned int offset_clr_al;
+};
+
struct mvebu_icu {
- struct irq_chip irq_chip;
void __iomem *base;
- struct irq_domain *domain;
struct device *dev;
+};
+
+struct mvebu_icu_msi_data {
+ struct mvebu_icu *icu;
atomic_t initialized;
+ const struct mvebu_icu_subset_data *subset_data;
};
struct mvebu_icu_irq_data {
@@ -50,28 +66,40 @@ struct mvebu_icu_irq_data {
unsigned int type;
};
-static void mvebu_icu_init(struct mvebu_icu *icu, struct msi_msg *msg)
+DEFINE_STATIC_KEY_FALSE(legacy_bindings);
+
+static void mvebu_icu_init(struct mvebu_icu *icu,
+ struct mvebu_icu_msi_data *msi_data,
+ struct msi_msg *msg)
{
- if (atomic_cmpxchg(&icu->initialized, false, true))
+ const struct mvebu_icu_subset_data *subset = msi_data->subset_data;
+
+ if (atomic_cmpxchg(&msi_data->initialized, false, true))
return;
- /* Set Clear/Set ICU SPI message address in AP */
- writel_relaxed(msg[0].address_hi, icu->base + ICU_SETSPI_NSR_AH);
- writel_relaxed(msg[0].address_lo, icu->base + ICU_SETSPI_NSR_AL);
- writel_relaxed(msg[1].address_hi, icu->base + ICU_CLRSPI_NSR_AH);
- writel_relaxed(msg[1].address_lo, icu->base + ICU_CLRSPI_NSR_AL);
+ /* Set 'SET' ICU SPI message address in AP */
+ writel_relaxed(msg[0].address_hi, icu->base + subset->offset_set_ah);
+ writel_relaxed(msg[0].address_lo, icu->base + subset->offset_set_al);
+
+ if (subset->icu_group != ICU_GRP_NSR)
+ return;
+
+ /* Set 'CLEAR' ICU SPI message address in AP (level-MSI only) */
+ writel_relaxed(msg[1].address_hi, icu->base + subset->offset_clr_ah);
+ writel_relaxed(msg[1].address_lo, icu->base + subset->offset_clr_al);
}
static void mvebu_icu_write_msg(struct msi_desc *desc, struct msi_msg *msg)
{
struct irq_data *d = irq_get_irq_data(desc->irq);
+ struct mvebu_icu_msi_data *msi_data = platform_msi_get_host_data(d->domain);
struct mvebu_icu_irq_data *icu_irqd = d->chip_data;
struct mvebu_icu *icu = icu_irqd->icu;
unsigned int icu_int;
if (msg->address_lo || msg->address_hi) {
- /* One off initialization */
- mvebu_icu_init(icu, msg);
+ /* One off initialization per domain */
+ mvebu_icu_init(icu, msi_data, msg);
/* Configure the ICU with irq number & type */
icu_int = msg->data | ICU_INT_ENABLE;
if (icu_irqd->type & IRQ_TYPE_EDGE_RISING)
@@ -101,37 +129,66 @@ static void mvebu_icu_write_msg(struct msi_desc *desc, struct msi_msg *msg)
}
}
+static struct irq_chip mvebu_icu_nsr_chip = {
+ .name = "ICU-NSR",
+ .irq_mask = irq_chip_mask_parent,
+ .irq_unmask = irq_chip_unmask_parent,
+ .irq_eoi = irq_chip_eoi_parent,
+ .irq_set_type = irq_chip_set_type_parent,
+ .irq_set_affinity = irq_chip_set_affinity_parent,
+};
+
+static struct irq_chip mvebu_icu_sei_chip = {
+ .name = "ICU-SEI",
+ .irq_ack = irq_chip_ack_parent,
+ .irq_mask = irq_chip_mask_parent,
+ .irq_unmask = irq_chip_unmask_parent,
+ .irq_set_type = irq_chip_set_type_parent,
+ .irq_set_affinity = irq_chip_set_affinity_parent,
+};
+
static int
mvebu_icu_irq_domain_translate(struct irq_domain *d, struct irq_fwspec *fwspec,
unsigned long *hwirq, unsigned int *type)
{
- struct mvebu_icu *icu = d->host_data;
- unsigned int icu_group;
+ struct mvebu_icu_msi_data *msi_data = platform_msi_get_host_data(d);
+ struct mvebu_icu *icu = platform_msi_get_host_data(d);
+ unsigned int param_count = static_branch_unlikely(&legacy_bindings) ? 3 : 2;
/* Check the count of the parameters in dt */
- if (WARN_ON(fwspec->param_count < 3)) {
+ if (WARN_ON(fwspec->param_count != param_count)) {
dev_err(icu->dev, "wrong ICU parameter count %d\n",
fwspec->param_count);
return -EINVAL;
}
- /* Only ICU group type is handled */
- icu_group = fwspec->param[0];
- if (icu_group != ICU_GRP_NSR && icu_group != ICU_GRP_SR &&
- icu_group != ICU_GRP_SEI && icu_group != ICU_GRP_REI) {
- dev_err(icu->dev, "wrong ICU group type %x\n", icu_group);
- return -EINVAL;
+ if (static_branch_unlikely(&legacy_bindings)) {
+ *hwirq = fwspec->param[1];
+ *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
+ if (fwspec->param[0] != ICU_GRP_NSR) {
+ dev_err(icu->dev, "wrong ICU group type %x\n",
+ fwspec->param[0]);
+ return -EINVAL;
+ }
+ } else {
+ *hwirq = fwspec->param[0];
+ *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
+
+ /*
+ * The ICU receives level interrupts. While the NSR are also
+ * level interrupts, SEI are edge interrupts. Force the type
+ * here in this case. Please note that this makes the interrupt
+ * handling unreliable.
+ */
+ if (msi_data->subset_data->icu_group == ICU_GRP_SEI)
+ *type = IRQ_TYPE_EDGE_RISING;
}
- *hwirq = fwspec->param[1];
if (*hwirq >= ICU_MAX_IRQS) {
dev_err(icu->dev, "invalid interrupt number %ld\n", *hwirq);
return -EINVAL;
}
- /* Mask the type to prevent wrong DT configuration */
- *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
-
return 0;
}
@@ -142,8 +199,10 @@ mvebu_icu_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
int err;
unsigned long hwirq;
struct irq_fwspec *fwspec = args;
- struct mvebu_icu *icu = platform_msi_get_host_data(domain);
+ struct mvebu_icu_msi_data *msi_data = platform_msi_get_host_data(domain);
+ struct mvebu_icu *icu = msi_data->icu;
struct mvebu_icu_irq_data *icu_irqd;
+ struct irq_chip *chip = &mvebu_icu_nsr_chip;
icu_irqd = kmalloc(sizeof(*icu_irqd), GFP_KERNEL);
if (!icu_irqd)
@@ -156,7 +215,10 @@ mvebu_icu_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
goto free_irqd;
}
- icu_irqd->icu_group = fwspec->param[0];
+ if (static_branch_unlikely(&legacy_bindings))
+ icu_irqd->icu_group = fwspec->param[0];
+ else
+ icu_irqd->icu_group = msi_data->subset_data->icu_group;
icu_irqd->icu = icu;
err = platform_msi_domain_alloc(domain, virq, nr_irqs);
@@ -170,8 +232,11 @@ mvebu_icu_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
if (err)
goto free_msi;
+ if (icu_irqd->icu_group == ICU_GRP_SEI)
+ chip = &mvebu_icu_sei_chip;
+
err = irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
- &icu->irq_chip, icu_irqd);
+ chip, icu_irqd);
if (err) {
dev_err(icu->dev, "failed to set the data to IRQ domain\n");
goto free_msi;
@@ -204,11 +269,84 @@ static const struct irq_domain_ops mvebu_icu_domain_ops = {
.free = mvebu_icu_irq_domain_free,
};
+static const struct mvebu_icu_subset_data mvebu_icu_nsr_subset_data = {
+ .icu_group = ICU_GRP_NSR,
+ .offset_set_ah = ICU_SETSPI_NSR_AH,
+ .offset_set_al = ICU_SETSPI_NSR_AL,
+ .offset_clr_ah = ICU_CLRSPI_NSR_AH,
+ .offset_clr_al = ICU_CLRSPI_NSR_AL,
+};
+
+static const struct mvebu_icu_subset_data mvebu_icu_sei_subset_data = {
+ .icu_group = ICU_GRP_SEI,
+ .offset_set_ah = ICU_SET_SEI_AH,
+ .offset_set_al = ICU_SET_SEI_AL,
+};
+
+static const struct of_device_id mvebu_icu_subset_of_match[] = {
+ {
+ .compatible = "marvell,cp110-icu-nsr",
+ .data = &mvebu_icu_nsr_subset_data,
+ },
+ {
+ .compatible = "marvell,cp110-icu-sei",
+ .data = &mvebu_icu_sei_subset_data,
+ },
+ {},
+};
+
+static int mvebu_icu_subset_probe(struct platform_device *pdev)
+{
+ struct mvebu_icu_msi_data *msi_data;
+ struct device_node *msi_parent_dn;
+ struct device *dev = &pdev->dev;
+ struct irq_domain *irq_domain;
+
+ msi_data = devm_kzalloc(dev, sizeof(*msi_data), GFP_KERNEL);
+ if (!msi_data)
+ return -ENOMEM;
+
+ if (static_branch_unlikely(&legacy_bindings)) {
+ msi_data->icu = dev_get_drvdata(dev);
+ msi_data->subset_data = &mvebu_icu_nsr_subset_data;
+ } else {
+ msi_data->icu = dev_get_drvdata(dev->parent);
+ msi_data->subset_data = of_device_get_match_data(dev);
+ }
+
+ dev->msi_domain = of_msi_get_domain(dev, dev->of_node,
+ DOMAIN_BUS_PLATFORM_MSI);
+ if (!dev->msi_domain)
+ return -EPROBE_DEFER;
+
+ msi_parent_dn = irq_domain_get_of_node(dev->msi_domain);
+ if (!msi_parent_dn)
+ return -ENODEV;
+
+ irq_domain = platform_msi_create_device_tree_domain(dev, ICU_MAX_IRQS,
+ mvebu_icu_write_msg,
+ &mvebu_icu_domain_ops,
+ msi_data);
+ if (!irq_domain) {
+ dev_err(dev, "Failed to create ICU MSI domain\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static struct platform_driver mvebu_icu_subset_driver = {
+ .probe = mvebu_icu_subset_probe,
+ .driver = {
+ .name = "mvebu-icu-subset",
+ .of_match_table = mvebu_icu_subset_of_match,
+ },
+};
+builtin_platform_driver(mvebu_icu_subset_driver);
+
static int mvebu_icu_probe(struct platform_device *pdev)
{
struct mvebu_icu *icu;
- struct device_node *node = pdev->dev.of_node;
- struct device_node *gicp_dn;
struct resource *res;
int i;
@@ -226,53 +364,38 @@ static int mvebu_icu_probe(struct platform_device *pdev)
return PTR_ERR(icu->base);
}
- icu->irq_chip.name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
- "ICU.%x",
- (unsigned int)res->start);
- if (!icu->irq_chip.name)
- return -ENOMEM;
-
- icu->irq_chip.irq_mask = irq_chip_mask_parent;
- icu->irq_chip.irq_unmask = irq_chip_unmask_parent;
- icu->irq_chip.irq_eoi = irq_chip_eoi_parent;
- icu->irq_chip.irq_set_type = irq_chip_set_type_parent;
-#ifdef CONFIG_SMP
- icu->irq_chip.irq_set_affinity = irq_chip_set_affinity_parent;
-#endif
-
/*
- * We're probed after MSI domains have been resolved, so force
- * resolution here.
+ * Legacy bindings: ICU is one node with one MSI parent: force manually
+ * the probe of the NSR interrupts side.
+ * New bindings: ICU node has children, one per interrupt controller
+ * having its own MSI parent: call platform_populate().
+ * All ICU instances should use the same bindings.
*/
- pdev->dev.msi_domain = of_msi_get_domain(&pdev->dev, node,
- DOMAIN_BUS_PLATFORM_MSI);
- if (!pdev->dev.msi_domain)
- return -EPROBE_DEFER;
-
- gicp_dn = irq_domain_get_of_node(pdev->dev.msi_domain);
- if (!gicp_dn)
- return -ENODEV;
+ if (!of_get_child_count(pdev->dev.of_node))
+ static_branch_enable(&legacy_bindings);
/*
- * Clean all ICU interrupts with type SPI_NSR, required to
+ * Clean all ICU interrupts of type NSR and SEI, required to
* avoid unpredictable SPI assignments done by firmware.
*/
for (i = 0 ; i < ICU_MAX_IRQS ; i++) {
- u32 icu_int = readl_relaxed(icu->base + ICU_INT_CFG(i));
- if ((icu_int >> ICU_GROUP_SHIFT) == ICU_GRP_NSR)
+ u32 icu_int, icu_grp;
+
+ icu_int = readl_relaxed(icu->base + ICU_INT_CFG(i));
+ icu_grp = icu_int >> ICU_GROUP_SHIFT;
+
+ if (icu_grp == ICU_GRP_NSR ||
+ (icu_grp == ICU_GRP_SEI &&
+ !static_branch_unlikely(&legacy_bindings)))
writel_relaxed(0x0, icu->base + ICU_INT_CFG(i));
}
- icu->domain =
- platform_msi_create_device_domain(&pdev->dev, ICU_MAX_IRQS,
- mvebu_icu_write_msg,
- &mvebu_icu_domain_ops, icu);
- if (!icu->domain) {
- dev_err(&pdev->dev, "Failed to create ICU domain\n");
- return -ENOMEM;
- }
+ platform_set_drvdata(pdev, icu);
- return 0;
+ if (static_branch_unlikely(&legacy_bindings))
+ return mvebu_icu_subset_probe(pdev);
+ else
+ return devm_of_platform_populate(&pdev->dev);
}
static const struct of_device_id mvebu_icu_of_match[] = {
diff --git a/drivers/irqchip/irq-mvebu-sei.c b/drivers/irqchip/irq-mvebu-sei.c
new file mode 100644
index 000000000000..add4c9c934c8
--- /dev/null
+++ b/drivers/irqchip/irq-mvebu-sei.c
@@ -0,0 +1,507 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define pr_fmt(fmt) "mvebu-sei: " fmt
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
+#include <linux/msi.h>
+#include <linux/platform_device.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+
+/* Cause register */
+#define GICP_SECR(idx) (0x0 + ((idx) * 0x4))
+/* Mask register */
+#define GICP_SEMR(idx) (0x20 + ((idx) * 0x4))
+#define GICP_SET_SEI_OFFSET 0x30
+
+#define SEI_IRQ_COUNT_PER_REG 32
+#define SEI_IRQ_REG_COUNT 2
+#define SEI_IRQ_COUNT (SEI_IRQ_COUNT_PER_REG * SEI_IRQ_REG_COUNT)
+#define SEI_IRQ_REG_IDX(irq_id) ((irq_id) / SEI_IRQ_COUNT_PER_REG)
+#define SEI_IRQ_REG_BIT(irq_id) ((irq_id) % SEI_IRQ_COUNT_PER_REG)
+
+struct mvebu_sei_interrupt_range {
+ u32 first;
+ u32 size;
+};
+
+struct mvebu_sei_caps {
+ struct mvebu_sei_interrupt_range ap_range;
+ struct mvebu_sei_interrupt_range cp_range;
+};
+
+struct mvebu_sei {
+ struct device *dev;
+ void __iomem *base;
+ struct resource *res;
+ struct irq_domain *sei_domain;
+ struct irq_domain *ap_domain;
+ struct irq_domain *cp_domain;
+ const struct mvebu_sei_caps *caps;
+
+ /* Lock on MSI allocations/releases */
+ struct mutex cp_msi_lock;
+ DECLARE_BITMAP(cp_msi_bitmap, SEI_IRQ_COUNT);
+
+ /* Lock on IRQ masking register */
+ raw_spinlock_t mask_lock;
+};
+
+static void mvebu_sei_ack_irq(struct irq_data *d)
+{
+ struct mvebu_sei *sei = irq_data_get_irq_chip_data(d);
+ u32 reg_idx = SEI_IRQ_REG_IDX(d->hwirq);
+
+ writel_relaxed(BIT(SEI_IRQ_REG_BIT(d->hwirq)),
+ sei->base + GICP_SECR(reg_idx));
+}
+
+static void mvebu_sei_mask_irq(struct irq_data *d)
+{
+ struct mvebu_sei *sei = irq_data_get_irq_chip_data(d);
+ u32 reg, reg_idx = SEI_IRQ_REG_IDX(d->hwirq);
+ unsigned long flags;
+
+ /* 1 disables the interrupt */
+ raw_spin_lock_irqsave(&sei->mask_lock, flags);
+ reg = readl_relaxed(sei->base + GICP_SEMR(reg_idx));
+ reg |= BIT(SEI_IRQ_REG_BIT(d->hwirq));
+ writel_relaxed(reg, sei->base + GICP_SEMR(reg_idx));
+ raw_spin_unlock_irqrestore(&sei->mask_lock, flags);
+}
+
+static void mvebu_sei_unmask_irq(struct irq_data *d)
+{
+ struct mvebu_sei *sei = irq_data_get_irq_chip_data(d);
+ u32 reg, reg_idx = SEI_IRQ_REG_IDX(d->hwirq);
+ unsigned long flags;
+
+ /* 0 enables the interrupt */
+ raw_spin_lock_irqsave(&sei->mask_lock, flags);
+ reg = readl_relaxed(sei->base + GICP_SEMR(reg_idx));
+ reg &= ~BIT(SEI_IRQ_REG_BIT(d->hwirq));
+ writel_relaxed(reg, sei->base + GICP_SEMR(reg_idx));
+ raw_spin_unlock_irqrestore(&sei->mask_lock, flags);
+}
+
+static int mvebu_sei_set_affinity(struct irq_data *d,
+ const struct cpumask *mask_val,
+ bool force)
+{
+ return -EINVAL;
+}
+
+static int mvebu_sei_set_irqchip_state(struct irq_data *d,
+ enum irqchip_irq_state which,
+ bool state)
+{
+ /* We can only clear the pending state by acking the interrupt */
+ if (which != IRQCHIP_STATE_PENDING || state)
+ return -EINVAL;
+
+ mvebu_sei_ack_irq(d);
+ return 0;
+}
+
+static struct irq_chip mvebu_sei_irq_chip = {
+ .name = "SEI",
+ .irq_ack = mvebu_sei_ack_irq,
+ .irq_mask = mvebu_sei_mask_irq,
+ .irq_unmask = mvebu_sei_unmask_irq,
+ .irq_set_affinity = mvebu_sei_set_affinity,
+ .irq_set_irqchip_state = mvebu_sei_set_irqchip_state,
+};
+
+static int mvebu_sei_ap_set_type(struct irq_data *data, unsigned int type)
+{
+ if ((type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_LEVEL_HIGH)
+ return -EINVAL;
+
+ return 0;
+}
+
+static struct irq_chip mvebu_sei_ap_irq_chip = {
+ .name = "AP SEI",
+ .irq_ack = irq_chip_ack_parent,
+ .irq_mask = irq_chip_mask_parent,
+ .irq_unmask = irq_chip_unmask_parent,
+ .irq_set_affinity = irq_chip_set_affinity_parent,
+ .irq_set_type = mvebu_sei_ap_set_type,
+};
+
+static void mvebu_sei_cp_compose_msi_msg(struct irq_data *data,
+ struct msi_msg *msg)
+{
+ struct mvebu_sei *sei = data->chip_data;
+ phys_addr_t set = sei->res->start + GICP_SET_SEI_OFFSET;
+
+ msg->data = data->hwirq + sei->caps->cp_range.first;
+ msg->address_lo = lower_32_bits(set);
+ msg->address_hi = upper_32_bits(set);
+}
+
+static int mvebu_sei_cp_set_type(struct irq_data *data, unsigned int type)
+{
+ if ((type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_EDGE_RISING)
+ return -EINVAL;
+
+ return 0;
+}
+
+static struct irq_chip mvebu_sei_cp_irq_chip = {
+ .name = "CP SEI",
+ .irq_ack = irq_chip_ack_parent,
+ .irq_mask = irq_chip_mask_parent,
+ .irq_unmask = irq_chip_unmask_parent,
+ .irq_set_affinity = irq_chip_set_affinity_parent,
+ .irq_set_type = mvebu_sei_cp_set_type,
+ .irq_compose_msi_msg = mvebu_sei_cp_compose_msi_msg,
+};
+
+static int mvebu_sei_domain_alloc(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs, void *arg)
+{
+ struct mvebu_sei *sei = domain->host_data;
+ struct irq_fwspec *fwspec = arg;
+
+ /* Not much to do, just setup the irqdata */
+ irq_domain_set_hwirq_and_chip(domain, virq, fwspec->param[0],
+ &mvebu_sei_irq_chip, sei);
+
+ return 0;
+}
+
+static void mvebu_sei_domain_free(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs)
+{
+ int i;
+
+ for (i = 0; i < nr_irqs; i++) {
+ struct irq_data *d = irq_domain_get_irq_data(domain, virq + i);
+ irq_set_handler(virq + i, NULL);
+ irq_domain_reset_irq_data(d);
+ }
+}
+
+static const struct irq_domain_ops mvebu_sei_domain_ops = {
+ .alloc = mvebu_sei_domain_alloc,
+ .free = mvebu_sei_domain_free,
+};
+
+static int mvebu_sei_ap_translate(struct irq_domain *domain,
+ struct irq_fwspec *fwspec,
+ unsigned long *hwirq,
+ unsigned int *type)
+{
+ *hwirq = fwspec->param[0];
+ *type = IRQ_TYPE_LEVEL_HIGH;
+
+ return 0;
+}
+
+static int mvebu_sei_ap_alloc(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs, void *arg)
+{
+ struct mvebu_sei *sei = domain->host_data;
+ struct irq_fwspec fwspec;
+ unsigned long hwirq;
+ unsigned int type;
+ int err;
+
+ mvebu_sei_ap_translate(domain, arg, &hwirq, &type);
+
+ fwspec.fwnode = domain->parent->fwnode;
+ fwspec.param_count = 1;
+ fwspec.param[0] = hwirq + sei->caps->ap_range.first;
+
+ err = irq_domain_alloc_irqs_parent(domain, virq, 1, &fwspec);
+ if (err)
+ return err;
+
+ irq_domain_set_info(domain, virq, hwirq,
+ &mvebu_sei_ap_irq_chip, sei,
+ handle_level_irq, NULL, NULL);
+ irq_set_probe(virq);
+
+ return 0;
+}
+
+static const struct irq_domain_ops mvebu_sei_ap_domain_ops = {
+ .translate = mvebu_sei_ap_translate,
+ .alloc = mvebu_sei_ap_alloc,
+ .free = irq_domain_free_irqs_parent,
+};
+
+static void mvebu_sei_cp_release_irq(struct mvebu_sei *sei, unsigned long hwirq)
+{
+ mutex_lock(&sei->cp_msi_lock);
+ clear_bit(hwirq, sei->cp_msi_bitmap);
+ mutex_unlock(&sei->cp_msi_lock);
+}
+
+static int mvebu_sei_cp_domain_alloc(struct irq_domain *domain,
+ unsigned int virq, unsigned int nr_irqs,
+ void *args)
+{
+ struct mvebu_sei *sei = domain->host_data;
+ struct irq_fwspec fwspec;
+ unsigned long hwirq;
+ int ret;
+
+ /* The software only supports single allocations for now */
+ if (nr_irqs != 1)
+ return -ENOTSUPP;
+
+ mutex_lock(&sei->cp_msi_lock);
+ hwirq = find_first_zero_bit(sei->cp_msi_bitmap,
+ sei->caps->cp_range.size);
+ if (hwirq < sei->caps->cp_range.size)
+ set_bit(hwirq, sei->cp_msi_bitmap);
+ mutex_unlock(&sei->cp_msi_lock);
+
+ if (hwirq == sei->caps->cp_range.size)
+ return -ENOSPC;
+
+ fwspec.fwnode = domain->parent->fwnode;
+ fwspec.param_count = 1;
+ fwspec.param[0] = hwirq + sei->caps->cp_range.first;
+
+ ret = irq_domain_alloc_irqs_parent(domain, virq, 1, &fwspec);
+ if (ret)
+ goto free_irq;
+
+ irq_domain_set_info(domain, virq, hwirq,
+ &mvebu_sei_cp_irq_chip, sei,
+ handle_edge_irq, NULL, NULL);
+
+ return 0;
+
+free_irq:
+ mvebu_sei_cp_release_irq(sei, hwirq);
+ return ret;
+}
+
+static void mvebu_sei_cp_domain_free(struct irq_domain *domain,
+ unsigned int virq, unsigned int nr_irqs)
+{
+ struct mvebu_sei *sei = domain->host_data;
+ struct irq_data *d = irq_domain_get_irq_data(domain, virq);
+
+ if (nr_irqs != 1 || d->hwirq >= sei->caps->cp_range.size) {
+ dev_err(sei->dev, "Invalid hwirq %lu\n", d->hwirq);
+ return;
+ }
+
+ mvebu_sei_cp_release_irq(sei, d->hwirq);
+ irq_domain_free_irqs_parent(domain, virq, 1);
+}
+
+static const struct irq_domain_ops mvebu_sei_cp_domain_ops = {
+ .alloc = mvebu_sei_cp_domain_alloc,
+ .free = mvebu_sei_cp_domain_free,
+};
+
+static struct irq_chip mvebu_sei_msi_irq_chip = {
+ .name = "SEI pMSI",
+ .irq_ack = irq_chip_ack_parent,
+ .irq_set_type = irq_chip_set_type_parent,
+};
+
+static struct msi_domain_ops mvebu_sei_msi_ops = {
+};
+
+static struct msi_domain_info mvebu_sei_msi_domain_info = {
+ .flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS,
+ .ops = &mvebu_sei_msi_ops,
+ .chip = &mvebu_sei_msi_irq_chip,
+};
+
+static void mvebu_sei_handle_cascade_irq(struct irq_desc *desc)
+{
+ struct mvebu_sei *sei = irq_desc_get_handler_data(desc);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ u32 idx;
+
+ chained_irq_enter(chip, desc);
+
+ for (idx = 0; idx < SEI_IRQ_REG_COUNT; idx++) {
+ unsigned long irqmap;
+ int bit;
+
+ 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;
+
+ 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);
+ }
+ }
+
+ chained_irq_exit(chip, desc);
+}
+
+static void mvebu_sei_reset(struct mvebu_sei *sei)
+{
+ u32 reg_idx;
+
+ /* Clear IRQ cause registers, mask all interrupts */
+ for (reg_idx = 0; reg_idx < SEI_IRQ_REG_COUNT; reg_idx++) {
+ writel_relaxed(0xFFFFFFFF, sei->base + GICP_SECR(reg_idx));
+ writel_relaxed(0xFFFFFFFF, sei->base + GICP_SEMR(reg_idx));
+ }
+}
+
+static int mvebu_sei_probe(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct irq_domain *plat_domain;
+ struct mvebu_sei *sei;
+ u32 parent_irq;
+ int ret;
+
+ sei = devm_kzalloc(&pdev->dev, sizeof(*sei), GFP_KERNEL);
+ if (!sei)
+ return -ENOMEM;
+
+ sei->dev = &pdev->dev;
+
+ mutex_init(&sei->cp_msi_lock);
+ raw_spin_lock_init(&sei->mask_lock);
+
+ sei->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ sei->base = devm_ioremap_resource(sei->dev, sei->res);
+ if (IS_ERR(sei->base)) {
+ dev_err(sei->dev, "Failed to remap SEI resource\n");
+ return PTR_ERR(sei->base);
+ }
+
+ /* Retrieve the SEI capabilities with the interrupt ranges */
+ sei->caps = of_device_get_match_data(&pdev->dev);
+ if (!sei->caps) {
+ dev_err(sei->dev,
+ "Could not retrieve controller capabilities\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Reserve the single (top-level) parent SPI IRQ from which all the
+ * interrupts handled by this driver will be signaled.
+ */
+ parent_irq = irq_of_parse_and_map(node, 0);
+ if (parent_irq <= 0) {
+ dev_err(sei->dev, "Failed to retrieve top-level SPI IRQ\n");
+ return -ENODEV;
+ }
+
+ /* Create the root SEI domain */
+ sei->sei_domain = irq_domain_create_linear(of_node_to_fwnode(node),
+ (sei->caps->ap_range.size +
+ sei->caps->cp_range.size),
+ &mvebu_sei_domain_ops,
+ sei);
+ if (!sei->sei_domain) {
+ dev_err(sei->dev, "Failed to create SEI IRQ domain\n");
+ ret = -ENOMEM;
+ goto dispose_irq;
+ }
+
+ irq_domain_update_bus_token(sei->sei_domain, DOMAIN_BUS_NEXUS);
+
+ /* Create the 'wired' domain */
+ sei->ap_domain = irq_domain_create_hierarchy(sei->sei_domain, 0,
+ sei->caps->ap_range.size,
+ of_node_to_fwnode(node),
+ &mvebu_sei_ap_domain_ops,
+ sei);
+ if (!sei->ap_domain) {
+ dev_err(sei->dev, "Failed to create AP IRQ domain\n");
+ ret = -ENOMEM;
+ goto remove_sei_domain;
+ }
+
+ irq_domain_update_bus_token(sei->ap_domain, DOMAIN_BUS_WIRED);
+
+ /* Create the 'MSI' domain */
+ sei->cp_domain = irq_domain_create_hierarchy(sei->sei_domain, 0,
+ sei->caps->cp_range.size,
+ of_node_to_fwnode(node),
+ &mvebu_sei_cp_domain_ops,
+ sei);
+ if (!sei->cp_domain) {
+ pr_err("Failed to create CPs IRQ domain\n");
+ ret = -ENOMEM;
+ goto remove_ap_domain;
+ }
+
+ irq_domain_update_bus_token(sei->cp_domain, DOMAIN_BUS_GENERIC_MSI);
+
+ plat_domain = platform_msi_create_irq_domain(of_node_to_fwnode(node),
+ &mvebu_sei_msi_domain_info,
+ sei->cp_domain);
+ if (!plat_domain) {
+ pr_err("Failed to create CPs MSI domain\n");
+ ret = -ENOMEM;
+ goto remove_cp_domain;
+ }
+
+ mvebu_sei_reset(sei);
+
+ irq_set_chained_handler_and_data(parent_irq,
+ mvebu_sei_handle_cascade_irq,
+ sei);
+
+ return 0;
+
+remove_cp_domain:
+ irq_domain_remove(sei->cp_domain);
+remove_ap_domain:
+ irq_domain_remove(sei->ap_domain);
+remove_sei_domain:
+ irq_domain_remove(sei->sei_domain);
+dispose_irq:
+ irq_dispose_mapping(parent_irq);
+
+ return ret;
+}
+
+struct mvebu_sei_caps mvebu_sei_ap806_caps = {
+ .ap_range = {
+ .first = 0,
+ .size = 21,
+ },
+ .cp_range = {
+ .first = 21,
+ .size = 43,
+ },
+};
+
+static const struct of_device_id mvebu_sei_of_match[] = {
+ {
+ .compatible = "marvell,ap806-sei",
+ .data = &mvebu_sei_ap806_caps,
+ },
+ {},
+};
+
+static struct platform_driver mvebu_sei_driver = {
+ .probe = mvebu_sei_probe,
+ .driver = {
+ .name = "mvebu-sei",
+ .of_match_table = mvebu_sei_of_match,
+ },
+};
+builtin_platform_driver(mvebu_sei_driver);
diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c
index 532e9d68c704..357e9daf94ae 100644
--- a/drivers/irqchip/irq-sifive-plic.c
+++ b/drivers/irqchip/irq-sifive-plic.c
@@ -15,6 +15,7 @@
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
+#include <asm/smp.h>
/*
* This driver implements a version of the RISC-V PLIC with the actual layout
@@ -176,7 +177,7 @@ static int plic_find_hart_id(struct device_node *node)
{
for (; node; node = node->parent) {
if (of_device_is_compatible(node, "riscv"))
- return riscv_of_processor_hart(node);
+ return riscv_of_processor_hartid(node);
}
return -1;
@@ -218,7 +219,7 @@ static int __init plic_init(struct device_node *node,
struct of_phandle_args parent;
struct plic_handler *handler;
irq_hw_number_t hwirq;
- int cpu;
+ int cpu, hartid;
if (of_irq_parse_one(node, i, &parent)) {
pr_err("failed to parse parent for context %d.\n", i);
@@ -229,12 +230,13 @@ static int __init plic_init(struct device_node *node,
if (parent.args[0] == -1)
continue;
- cpu = plic_find_hart_id(parent.np);
- if (cpu < 0) {
+ hartid = plic_find_hart_id(parent.np);
+ if (hartid < 0) {
pr_warn("failed to parse hart ID for context %d.\n", i);
continue;
}
+ cpu = riscv_hartid_to_cpuid(hartid);
handler = per_cpu_ptr(&plic_handlers, cpu);
handler->present = true;
handler->ctxid = i;
diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c
index b1b47a40a278..faa7d61b9d6c 100644
--- a/drivers/irqchip/qcom-pdc.c
+++ b/drivers/irqchip/qcom-pdc.c
@@ -124,6 +124,7 @@ static int qcom_pdc_gic_set_type(struct irq_data *d, unsigned int type)
break;
case IRQ_TYPE_EDGE_BOTH:
pdc_type = PDC_EDGE_DUAL;
+ type = IRQ_TYPE_EDGE_RISING;
break;
case IRQ_TYPE_LEVEL_HIGH:
pdc_type = PDC_LEVEL_HIGH;
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index ef5560b848ab..e1da70a9530c 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -1155,12 +1155,6 @@ static int capinc_tty_chars_in_buffer(struct tty_struct *tty)
return mp->outbytes;
}
-static int capinc_tty_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
-{
- return -ENOIOCTLCMD;
-}
-
static void capinc_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
{
pr_debug("capinc_tty_set_termios\n");
@@ -1236,7 +1230,6 @@ 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,
- .ioctl = capinc_tty_ioctl,
.set_termios = capinc_tty_set_termios,
.throttle = capinc_tty_throttle,
.unthrottle = capinc_tty_unthrottle,
diff --git a/drivers/isdn/gigaset/asyncdata.c b/drivers/isdn/gigaset/asyncdata.c
index bc208557f783..c0cbee06bc21 100644
--- a/drivers/isdn/gigaset/asyncdata.c
+++ b/drivers/isdn/gigaset/asyncdata.c
@@ -65,7 +65,7 @@ static unsigned cmd_loop(unsigned numbytes, struct inbuf_t *inbuf)
cs->respdata[0] = 0;
break;
}
- /* --v-- fall through --v-- */
+ /* fall through */
case '\r':
/* end of message line, pass to response handler */
if (cbytes >= MAX_RESP_SIZE) {
@@ -100,7 +100,7 @@ static unsigned cmd_loop(unsigned numbytes, struct inbuf_t *inbuf)
goto exit;
}
/* quoted or not in DLE mode: treat as regular data */
- /* --v-- fall through --v-- */
+ /* fall through */
default:
/* append to line buffer if possible */
if (cbytes < MAX_RESP_SIZE)
diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c
index 1cfcea62aed9..182826e9d07c 100644
--- a/drivers/isdn/gigaset/ev-layer.c
+++ b/drivers/isdn/gigaset/ev-layer.c
@@ -1036,7 +1036,7 @@ static void handle_icall(struct cardstate *cs, struct bc_state *bcs,
break;
default:
dev_err(cs->dev, "internal error: disposition=%d\n", retval);
- /* --v-- fall through --v-- */
+ /* fall through */
case ICALL_IGNORE:
case ICALL_REJECT:
/* hang up actively
@@ -1319,7 +1319,7 @@ static void do_action(int action, struct cardstate *cs,
cs->commands_pending = 1;
break;
}
- /* bad cid: fall through */
+ /* fall through - bad cid */
case ACT_FAILCID:
cs->cur_at_seq = SEQ_NONE;
channel = cs->curchannel;
diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c
index 600c79b030cd..d9a578ac32cd 100644
--- a/drivers/isdn/gigaset/interface.c
+++ b/drivers/isdn/gigaset/interface.c
@@ -206,7 +206,7 @@ static int if_ioctl(struct tty_struct *tty,
? -EFAULT : 0;
if (retval >= 0) {
gigaset_dbg_buffer(DEBUG_IF, "GIGASET_BRKCHARS",
- 6, (const unsigned char *) arg);
+ 6, buf);
retval = cs->ops->brkchars(cs, buf);
}
break;
@@ -233,6 +233,14 @@ static int if_ioctl(struct tty_struct *tty,
return retval;
}
+#ifdef CONFIG_COMPAT
+static long if_compat_ioctl(struct tty_struct *tty,
+ unsigned int cmd, unsigned long arg)
+{
+ return if_ioctl(tty, cmd, (unsigned long)compat_ptr(arg));
+}
+#endif
+
static int if_tiocmget(struct tty_struct *tty)
{
struct cardstate *cs = tty->driver_data;
@@ -472,6 +480,9 @@ static const struct tty_operations if_ops = {
.open = if_open,
.close = if_close,
.ioctl = if_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = if_compat_ioctl,
+#endif
.write = if_write,
.write_room = if_write_room,
.chars_in_buffer = if_chars_in_buffer,
diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c
index 97e00118ccfe..f9264ba0fe77 100644
--- a/drivers/isdn/gigaset/isocdata.c
+++ b/drivers/isdn/gigaset/isocdata.c
@@ -906,7 +906,7 @@ static void cmd_loop(unsigned char *src, int numbytes, struct inbuf_t *inbuf)
cs->respdata[0] = 0;
break;
}
- /* --v-- fall through --v-- */
+ /* fall through */
case '\r':
/* end of message line, pass to response handler */
if (cbytes >= MAX_RESP_SIZE) {
diff --git a/drivers/isdn/hisax/amd7930_fn.c b/drivers/isdn/hisax/amd7930_fn.c
index 77debda2221b..6c336366128c 100644
--- a/drivers/isdn/hisax/amd7930_fn.c
+++ b/drivers/isdn/hisax/amd7930_fn.c
@@ -625,7 +625,7 @@ Amd7930_l1hw(struct PStack *st, int pr, void *arg)
break;
case (HW_RESET | REQUEST):
spin_lock_irqsave(&cs->lock, flags);
- if ((cs->dc.amd7930.ph_state == 8)) {
+ if (cs->dc.amd7930.ph_state == 8) {
/* b-channels off, PH-AR cleared
* change to F3 */
Amd7930_ph_command(cs, 0x20, "HW_RESET REQUEST"); //LMR1 bit 5
diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c
index 8e5b03161b2f..ea0e4c6de3fb 100644
--- a/drivers/isdn/hisax/hfc_pci.c
+++ b/drivers/isdn/hisax/hfc_pci.c
@@ -86,7 +86,7 @@ release_io_hfcpci(struct IsdnCardState *cs)
pci_free_consistent(cs->hw.hfcpci.dev, 0x8000,
cs->hw.hfcpci.fifos, cs->hw.hfcpci.dma);
cs->hw.hfcpci.fifos = NULL;
- iounmap((void *)cs->hw.hfcpci.pci_io);
+ iounmap(cs->hw.hfcpci.pci_io);
}
/********************************************************************************/
@@ -128,7 +128,7 @@ reset_hfcpci(struct IsdnCardState *cs)
Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
/* Clear already pending ints */
- if (Read_hfc(cs, HFCPCI_INT_S1));
+ Read_hfc(cs, HFCPCI_INT_S1);
Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 2); /* HFC ST 2 */
udelay(10);
@@ -158,7 +158,7 @@ reset_hfcpci(struct IsdnCardState *cs)
/* Finally enable IRQ output */
cs->hw.hfcpci.int_m2 = HFCPCI_IRQ_ENABLE;
Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
- if (Read_hfc(cs, HFCPCI_INT_S1));
+ Read_hfc(cs, HFCPCI_INT_S1);
}
/***************************************************/
@@ -1537,7 +1537,7 @@ hfcpci_bh(struct work_struct *work)
cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_TIMER;
Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
/* Clear already pending ints */
- if (Read_hfc(cs, HFCPCI_INT_S1));
+ Read_hfc(cs, HFCPCI_INT_S1);
Write_hfc(cs, HFCPCI_STATES, 4 | HFCPCI_LOAD_STATE);
udelay(10);
Write_hfc(cs, HFCPCI_STATES, 4);
@@ -1692,7 +1692,7 @@ setup_hfcpci(struct IsdnCard *card)
printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n");
return (0);
}
- cs->hw.hfcpci.pci_io = (char *)(unsigned long)dev_hfcpci->resource[1].start;
+ cs->hw.hfcpci.pci_io = ioremap(dev_hfcpci->resource[1].start, 256);
printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: %s card name: %s\n", id_list[i].vendor_name, id_list[i].card_name);
if (!cs->hw.hfcpci.pci_io) {
@@ -1716,7 +1716,6 @@ setup_hfcpci(struct IsdnCard *card)
return 0;
}
pci_write_config_dword(cs->hw.hfcpci.dev, 0x80, (u32)cs->hw.hfcpci.dma);
- cs->hw.hfcpci.pci_io = ioremap((ulong) cs->hw.hfcpci.pci_io, 256);
printk(KERN_INFO
"HFC-PCI: defined at mem %p fifo %p(%lx) IRQ %d HZ %d\n",
cs->hw.hfcpci.pci_io,
diff --git a/drivers/isdn/hisax/hfc_pci.h b/drivers/isdn/hisax/hfc_pci.h
index 4e58700a3e61..4c3b3ba35726 100644
--- a/drivers/isdn/hisax/hfc_pci.h
+++ b/drivers/isdn/hisax/hfc_pci.h
@@ -228,8 +228,8 @@ typedef union {
} fifo_area;
-#define Write_hfc(a, b, c) (*(((u_char *)a->hw.hfcpci.pci_io) + b) = c)
-#define Read_hfc(a, b) (*(((u_char *)a->hw.hfcpci.pci_io) + b))
+#define Write_hfc(a, b, c) (writeb(c, (a->hw.hfcpci.pci_io) + b))
+#define Read_hfc(a, b) (readb((a->hw.hfcpci.pci_io) + b))
extern void main_irq_hcpci(struct BCState *bcs);
extern void releasehfcpci(struct IsdnCardState *cs);
diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c
index 4d3b4b2f2612..12af628d9b2c 100644
--- a/drivers/isdn/hisax/hfc_sx.c
+++ b/drivers/isdn/hisax/hfc_sx.c
@@ -381,7 +381,7 @@ reset_hfcsx(struct IsdnCardState *cs)
Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
/* Clear already pending ints */
- if (Read_hfc(cs, HFCSX_INT_S1));
+ Read_hfc(cs, HFCSX_INT_S1);
Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 2); /* HFC ST 2 */
udelay(10);
@@ -411,7 +411,7 @@ reset_hfcsx(struct IsdnCardState *cs)
/* Finally enable IRQ output */
cs->hw.hfcsx.int_m2 = HFCSX_IRQ_ENABLE;
Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2);
- if (Read_hfc(cs, HFCSX_INT_S2));
+ Read_hfc(cs, HFCSX_INT_S2);
}
/***************************************************/
@@ -1288,7 +1288,7 @@ hfcsx_bh(struct work_struct *work)
cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER;
Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1);
/* Clear already pending ints */
- if (Read_hfc(cs, HFCSX_INT_S1));
+ Read_hfc(cs, HFCSX_INT_S1);
Write_hfc(cs, HFCSX_STATES, 4 | HFCSX_LOAD_STATE);
udelay(10);
diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h
index 338d0408b377..40080e06421c 100644
--- a/drivers/isdn/hisax/hisax.h
+++ b/drivers/isdn/hisax/hisax.h
@@ -703,7 +703,7 @@ struct hfcPCI_hw {
unsigned char nt_mode;
int nt_timer;
struct pci_dev *dev;
- unsigned char *pci_io; /* start of PCI IO memory */
+ void __iomem *pci_io; /* start of PCI IO memory */
dma_addr_t dma; /* dma handle for Fifos */
void *fifos; /* FIFO memory */
int last_bfifo_cnt[2]; /* marker saving last b-fifo frame count */
diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c
index c4be1644f5bb..36eefaa3a7d9 100644
--- a/drivers/isdn/hisax/w6692.c
+++ b/drivers/isdn/hisax/w6692.c
@@ -72,7 +72,7 @@ W6692_new_ph(struct IsdnCardState *cs)
case (W_L1CMD_RST):
ph_command(cs, W_L1CMD_DRC);
l1_msg(cs, HW_RESET | INDICATION, NULL);
- /* fallthru */
+ /* fall through */
case (W_L1IND_CD):
l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL);
break;
@@ -624,7 +624,7 @@ W6692_l1hw(struct PStack *st, int pr, void *arg)
break;
case (HW_RESET | REQUEST):
spin_lock_irqsave(&cs->lock, flags);
- if ((cs->dc.w6692.ph_state == W_L1IND_DRD)) {
+ if (cs->dc.w6692.ph_state == W_L1IND_DRD) {
ph_command(cs, W_L1CMD_ECK);
spin_unlock_irqrestore(&cs->lock, flags);
} else {
diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
index b730037a0e2d..1b2239c1d569 100644
--- a/drivers/isdn/i4l/isdn_tty.c
+++ b/drivers/isdn/i4l/isdn_tty.c
@@ -1412,31 +1412,12 @@ static int
isdn_tty_ioctl(struct tty_struct *tty, uint cmd, ulong arg)
{
modem_info *info = (modem_info *) tty->driver_data;
- int retval;
if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_ioctl"))
return -ENODEV;
if (tty_io_error(tty))
return -EIO;
switch (cmd) {
- case TCSBRK: /* SVID version: non-zero arg --> no break */
-#ifdef ISDN_DEBUG_MODEM_IOCTL
- printk(KERN_DEBUG "ttyI%d ioctl TCSBRK\n", info->line);
-#endif
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- return 0;
- case TCSBRKP: /* support for POSIX tcsendbreak() */
-#ifdef ISDN_DEBUG_MODEM_IOCTL
- printk(KERN_DEBUG "ttyI%d ioctl TCSBRKP\n", info->line);
-#endif
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- return 0;
case TIOCSERGETLSR: /* Get line status register */
#ifdef ISDN_DEBUG_MODEM_IOCTL
printk(KERN_DEBUG "ttyI%d ioctl TIOCSERGETLSR\n", info->line);
diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c
index b05022f94f18..072bb5e36c18 100644
--- a/drivers/isdn/mISDN/l1oip_core.c
+++ b/drivers/isdn/mISDN/l1oip_core.c
@@ -718,8 +718,7 @@ l1oip_socket_thread(void *data)
printk(KERN_DEBUG "%s: socket created and open\n",
__func__);
while (!signal_pending(current)) {
- iov_iter_kvec(&msg.msg_iter, READ | ITER_KVEC, &iov, 1,
- recvbuf_size);
+ iov_iter_kvec(&msg.msg_iter, READ, &iov, 1, recvbuf_size);
recvlen = sock_recvmsg(socket, &msg, 0);
if (recvlen > 0) {
l1oip_socket_parse(hc, &sin_rx, recvbuf, recvlen);
diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c
index 18c0a1281914..15d3ca37669a 100644
--- a/drivers/isdn/mISDN/socket.c
+++ b/drivers/isdn/mISDN/socket.c
@@ -236,8 +236,7 @@ mISDN_sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
}
done:
- if (skb)
- kfree_skb(skb);
+ kfree_skb(skb);
release_sock(sk);
return err;
}
diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c
index 12d9e5f4beb1..58635b5f296f 100644
--- a/drivers/isdn/mISDN/tei.c
+++ b/drivers/isdn/mISDN/tei.c
@@ -1180,8 +1180,7 @@ static int
ctrl_teimanager(struct manager *mgr, void *arg)
{
/* currently we only have one option */
- int *val = (int *)arg;
- int ret = 0;
+ unsigned int *val = (unsigned int *)arg;
switch (val[0]) {
case IMCLEAR_L2:
@@ -1197,9 +1196,9 @@ ctrl_teimanager(struct manager *mgr, void *arg)
test_and_clear_bit(OPTION_L1_HOLD, &mgr->options);
break;
default:
- ret = -EINVAL;
+ return -EINVAL;
}
- return ret;
+ return 0;
}
/* This function does create a L2 for fixed TEI in NT Mode */
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 44097a3e0fcc..a72f97fca57b 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -58,6 +58,16 @@ config LEDS_AAT1290
help
This option enables support for the LEDs on the AAT1290.
+config LEDS_AN30259A
+ tristate "LED support for Panasonic AN30259A"
+ depends on LEDS_CLASS && I2C && OF
+ help
+ This option enables support for the AN30259A 3-channel
+ LED driver.
+
+ To compile this driver as a module, choose M here: the module
+ will be called leds-an30259a.
+
config LEDS_APU
tristate "Front panel LED support for PC Engines APU/APU2/APU3 boards"
depends on LEDS_CLASS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 420b5d2cfa62..4c1b0054f379 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_LEDS_88PM860X) += leds-88pm860x.o
obj-$(CONFIG_LEDS_AAT1290) += leds-aat1290.o
obj-$(CONFIG_LEDS_APU) += leds-apu.o
obj-$(CONFIG_LEDS_AS3645A) += leds-as3645a.o
+obj-$(CONFIG_LEDS_AN30259A) += leds-an30259a.o
obj-$(CONFIG_LEDS_BCM6328) += leds-bcm6328.o
obj-$(CONFIG_LEDS_BCM6358) += leds-bcm6358.o
obj-$(CONFIG_LEDS_BD2802) += leds-bd2802.o
diff --git a/drivers/leds/leds-an30259a.c b/drivers/leds/leds-an30259a.c
new file mode 100644
index 000000000000..1c1f0c8c56f4
--- /dev/null
+++ b/drivers/leds/leds-an30259a.c
@@ -0,0 +1,368 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Driver for Panasonic AN30259A 3-channel LED driver
+//
+// Copyright (c) 2018 Simon Shields <simon@lineageos.org>
+//
+// Datasheet:
+// https://www.alliedelec.com/m/d/a9d2b3ee87c2d1a535a41dd747b1c247.pdf
+
+#include <linux/i2c.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <uapi/linux/uleds.h>
+
+#define AN30259A_MAX_LEDS 3
+
+#define AN30259A_REG_SRESET 0x00
+#define AN30259A_LED_SRESET BIT(0)
+
+/* LED power registers */
+#define AN30259A_REG_LED_ON 0x01
+#define AN30259A_LED_EN(x) BIT((x) - 1)
+#define AN30259A_LED_SLOPE(x) BIT(((x) - 1) + 4)
+
+#define AN30259A_REG_LEDCC(x) (0x03 + ((x) - 1))
+
+/* slope control registers */
+#define AN30259A_REG_SLOPE(x) (0x06 + ((x) - 1))
+#define AN30259A_LED_SLOPETIME1(x) (x)
+#define AN30259A_LED_SLOPETIME2(x) ((x) << 4)
+
+#define AN30259A_REG_LEDCNT1(x) (0x09 + (4 * ((x) - 1)))
+#define AN30259A_LED_DUTYMAX(x) ((x) << 4)
+#define AN30259A_LED_DUTYMID(x) (x)
+
+#define AN30259A_REG_LEDCNT2(x) (0x0A + (4 * ((x) - 1)))
+#define AN30259A_LED_DELAY(x) ((x) << 4)
+#define AN30259A_LED_DUTYMIN(x) (x)
+
+/* detention time control (length of each slope step) */
+#define AN30259A_REG_LEDCNT3(x) (0x0B + (4 * ((x) - 1)))
+#define AN30259A_LED_DT1(x) (x)
+#define AN30259A_LED_DT2(x) ((x) << 4)
+
+#define AN30259A_REG_LEDCNT4(x) (0x0C + (4 * ((x) - 1)))
+#define AN30259A_LED_DT3(x) (x)
+#define AN30259A_LED_DT4(x) ((x) << 4)
+
+#define AN30259A_REG_MAX 0x14
+
+#define AN30259A_BLINK_MAX_TIME 7500 /* ms */
+#define AN30259A_SLOPE_RESOLUTION 500 /* ms */
+
+#define STATE_OFF 0
+#define STATE_KEEP 1
+#define STATE_ON 2
+
+struct an30259a;
+
+struct an30259a_led {
+ struct an30259a *chip;
+ struct led_classdev cdev;
+ u32 num;
+ u32 default_state;
+ bool sloping;
+ char label[LED_MAX_NAME_SIZE];
+};
+
+struct an30259a {
+ struct mutex mutex; /* held when writing to registers */
+ struct i2c_client *client;
+ struct an30259a_led leds[AN30259A_MAX_LEDS];
+ struct regmap *regmap;
+ int num_leds;
+};
+
+static int an30259a_brightness_set(struct led_classdev *cdev,
+ enum led_brightness brightness)
+{
+ struct an30259a_led *led;
+ int ret;
+ unsigned int led_on;
+
+ led = container_of(cdev, struct an30259a_led, cdev);
+ mutex_lock(&led->chip->mutex);
+
+ ret = regmap_read(led->chip->regmap, AN30259A_REG_LED_ON, &led_on);
+ if (ret)
+ goto error;
+
+ switch (brightness) {
+ case LED_OFF:
+ led_on &= ~AN30259A_LED_EN(led->num);
+ led_on &= ~AN30259A_LED_SLOPE(led->num);
+ led->sloping = false;
+ break;
+ default:
+ led_on |= AN30259A_LED_EN(led->num);
+ if (led->sloping)
+ led_on |= AN30259A_LED_SLOPE(led->num);
+ ret = regmap_write(led->chip->regmap,
+ AN30259A_REG_LEDCNT1(led->num),
+ AN30259A_LED_DUTYMAX(0xf) |
+ AN30259A_LED_DUTYMID(0xf));
+ if (ret)
+ goto error;
+ break;
+ }
+
+ ret = regmap_write(led->chip->regmap, AN30259A_REG_LED_ON, led_on);
+ if (ret)
+ goto error;
+
+ ret = regmap_write(led->chip->regmap, AN30259A_REG_LEDCC(led->num),
+ brightness);
+
+error:
+ mutex_unlock(&led->chip->mutex);
+
+ return ret;
+}
+
+static int an30259a_blink_set(struct led_classdev *cdev,
+ unsigned long *delay_off, unsigned long *delay_on)
+{
+ struct an30259a_led *led;
+ int ret, num;
+ unsigned int led_on;
+ unsigned long off = *delay_off, on = *delay_on;
+
+ led = container_of(cdev, struct an30259a_led, cdev);
+
+ mutex_lock(&led->chip->mutex);
+ num = led->num;
+
+ /* slope time can only be a multiple of 500ms. */
+ if (off % AN30259A_SLOPE_RESOLUTION || on % AN30259A_SLOPE_RESOLUTION) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* up to a maximum of 7500ms. */
+ if (off > AN30259A_BLINK_MAX_TIME || on > AN30259A_BLINK_MAX_TIME) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* if no blink specified, default to 1 Hz. */
+ if (!off && !on) {
+ *delay_off = off = 500;
+ *delay_on = on = 500;
+ }
+
+ /* convert into values the HW will understand. */
+ off /= AN30259A_SLOPE_RESOLUTION;
+ on /= AN30259A_SLOPE_RESOLUTION;
+
+ /* duty min should be zero (=off), delay should be zero. */
+ ret = regmap_write(led->chip->regmap, AN30259A_REG_LEDCNT2(num),
+ AN30259A_LED_DELAY(0) | AN30259A_LED_DUTYMIN(0));
+ if (ret)
+ goto error;
+
+ /* reset detention time (no "breathing" effect). */
+ ret = regmap_write(led->chip->regmap, AN30259A_REG_LEDCNT3(num),
+ AN30259A_LED_DT1(0) | AN30259A_LED_DT2(0));
+ if (ret)
+ goto error;
+ ret = regmap_write(led->chip->regmap, AN30259A_REG_LEDCNT4(num),
+ AN30259A_LED_DT3(0) | AN30259A_LED_DT4(0));
+ if (ret)
+ goto error;
+
+ /* slope time controls on/off cycle length. */
+ ret = regmap_write(led->chip->regmap, AN30259A_REG_SLOPE(num),
+ AN30259A_LED_SLOPETIME1(off) |
+ AN30259A_LED_SLOPETIME2(on));
+ if (ret)
+ goto error;
+
+ /* Finally, enable slope mode. */
+ ret = regmap_read(led->chip->regmap, AN30259A_REG_LED_ON, &led_on);
+ if (ret)
+ goto error;
+
+ led_on |= AN30259A_LED_SLOPE(num) | AN30259A_LED_EN(led->num);
+
+ ret = regmap_write(led->chip->regmap, AN30259A_REG_LED_ON, led_on);
+
+ if (!ret)
+ led->sloping = true;
+error:
+ mutex_unlock(&led->chip->mutex);
+
+ return ret;
+}
+
+static int an30259a_dt_init(struct i2c_client *client,
+ struct an30259a *chip)
+{
+ struct device_node *np = client->dev.of_node, *child;
+ int count, ret;
+ int i = 0;
+ const char *str;
+ struct an30259a_led *led;
+
+ count = of_get_child_count(np);
+ if (!count || count > AN30259A_MAX_LEDS)
+ return -EINVAL;
+
+ for_each_available_child_of_node(np, child) {
+ u32 source;
+
+ ret = of_property_read_u32(child, "reg", &source);
+ if (ret != 0 || !source || source > AN30259A_MAX_LEDS) {
+ dev_err(&client->dev, "Couldn't read LED address: %d\n",
+ ret);
+ count--;
+ continue;
+ }
+
+ led = &chip->leds[i];
+
+ led->num = source;
+ led->chip = chip;
+
+ if (of_property_read_string(child, "label", &str))
+ snprintf(led->label, sizeof(led->label), "an30259a::");
+ else
+ snprintf(led->label, sizeof(led->label), "an30259a:%s",
+ str);
+
+ led->cdev.name = led->label;
+
+ if (!of_property_read_string(child, "default-state", &str)) {
+ if (!strcmp(str, "on"))
+ led->default_state = STATE_ON;
+ else if (!strcmp(str, "keep"))
+ led->default_state = STATE_KEEP;
+ else
+ led->default_state = STATE_OFF;
+ }
+
+ of_property_read_string(child, "linux,default-trigger",
+ &led->cdev.default_trigger);
+
+ i++;
+ }
+
+ if (!count)
+ return -EINVAL;
+
+ chip->num_leds = i;
+
+ return 0;
+}
+
+static const struct regmap_config an30259a_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = AN30259A_REG_MAX,
+};
+
+static void an30259a_init_default_state(struct an30259a_led *led)
+{
+ struct an30259a *chip = led->chip;
+ int led_on, err;
+
+ switch (led->default_state) {
+ case STATE_ON:
+ led->cdev.brightness = LED_FULL;
+ break;
+ case STATE_KEEP:
+ err = regmap_read(chip->regmap, AN30259A_REG_LED_ON, &led_on);
+ if (err)
+ break;
+
+ if (!(led_on & AN30259A_LED_EN(led->num))) {
+ led->cdev.brightness = LED_OFF;
+ break;
+ }
+ regmap_read(chip->regmap, AN30259A_REG_LEDCC(led->num),
+ &led->cdev.brightness);
+ break;
+ default:
+ led->cdev.brightness = LED_OFF;
+ }
+
+ an30259a_brightness_set(&led->cdev, led->cdev.brightness);
+}
+
+static int an30259a_probe(struct i2c_client *client)
+{
+ struct an30259a *chip;
+ int i, err;
+
+ chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ err = an30259a_dt_init(client, chip);
+ if (err < 0)
+ return err;
+
+ mutex_init(&chip->mutex);
+ chip->client = client;
+ i2c_set_clientdata(client, chip);
+
+ chip->regmap = devm_regmap_init_i2c(client, &an30259a_regmap_config);
+
+ for (i = 0; i < chip->num_leds; i++) {
+ an30259a_init_default_state(&chip->leds[i]);
+ chip->leds[i].cdev.brightness_set_blocking =
+ an30259a_brightness_set;
+ chip->leds[i].cdev.blink_set = an30259a_blink_set;
+
+ err = devm_led_classdev_register(&client->dev,
+ &chip->leds[i].cdev);
+ if (err < 0)
+ goto exit;
+ }
+ return 0;
+
+exit:
+ mutex_destroy(&chip->mutex);
+ return err;
+}
+
+static int an30259a_remove(struct i2c_client *client)
+{
+ struct an30259a *chip = i2c_get_clientdata(client);
+
+ mutex_destroy(&chip->mutex);
+
+ return 0;
+}
+
+static const struct of_device_id an30259a_match_table[] = {
+ { .compatible = "panasonic,an30259a", },
+ { /* sentinel */ },
+};
+
+MODULE_DEVICE_TABLE(of, an30259a_match_table);
+
+static const struct i2c_device_id an30259a_id[] = {
+ { "an30259a", 0 },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(i2c, an30259a_id);
+
+static struct i2c_driver an30259a_driver = {
+ .driver = {
+ .name = "leds-an32059a",
+ .of_match_table = of_match_ptr(an30259a_match_table),
+ },
+ .probe_new = an30259a_probe,
+ .remove = an30259a_remove,
+ .id_table = an30259a_id,
+};
+
+module_i2c_driver(an30259a_driver);
+
+MODULE_AUTHOR("Simon Shields <simon@lineageos.org>");
+MODULE_DESCRIPTION("AN32059A LED driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/leds-as3645a.c b/drivers/leds/leds-as3645a.c
index f883616d9e60..98a69b1a43f9 100644
--- a/drivers/leds/leds-as3645a.c
+++ b/drivers/leds/leds-as3645a.c
@@ -529,7 +529,7 @@ static int as3645a_parse_node(struct as3645a *flash,
strlcpy(names->flash, name, sizeof(names->flash));
else
snprintf(names->flash, sizeof(names->flash),
- "%s:flash", node->name);
+ "%pOFn:flash", node);
rval = of_property_read_u32(flash->flash_node, "flash-timeout-us",
&cfg->flash_timeout_us);
@@ -573,7 +573,7 @@ static int as3645a_parse_node(struct as3645a *flash,
strlcpy(names->indicator, name, sizeof(names->indicator));
else
snprintf(names->indicator, sizeof(names->indicator),
- "%s:indicator", node->name);
+ "%pOFn:indicator", node);
rval = of_property_read_u32(flash->indicator_node, "led-max-microamp",
&cfg->indicator_max_ua);
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index 764c31301f90..45e012093865 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -81,35 +81,6 @@ static int create_gpio_led(const struct gpio_led *template,
{
int ret, state;
- led_dat->gpiod = template->gpiod;
- if (!led_dat->gpiod) {
- /*
- * This is the legacy code path for platform code that
- * still uses GPIO numbers. Ultimately we would like to get
- * rid of this block completely.
- */
- unsigned long flags = GPIOF_OUT_INIT_LOW;
-
- /* skip leds that aren't available */
- if (!gpio_is_valid(template->gpio)) {
- dev_info(parent, "Skipping unavailable LED gpio %d (%s)\n",
- template->gpio, template->name);
- return 0;
- }
-
- if (template->active_low)
- flags |= GPIOF_ACTIVE_LOW;
-
- ret = devm_gpio_request_one(parent, template->gpio, flags,
- template->name);
- if (ret < 0)
- return ret;
-
- led_dat->gpiod = gpio_to_desc(template->gpio);
- if (!led_dat->gpiod)
- return -EINVAL;
- }
-
led_dat->cdev.name = template->name;
led_dat->cdev.default_trigger = template->default_trigger;
led_dat->can_sleep = gpiod_cansleep(led_dat->gpiod);
@@ -192,6 +163,8 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
return ERR_CAST(led.gpiod);
}
+ led_dat->gpiod = led.gpiod;
+
fwnode_property_read_string(child, "linux,default-trigger",
&led.default_trigger);
@@ -231,6 +204,52 @@ static const struct of_device_id of_gpio_leds_match[] = {
MODULE_DEVICE_TABLE(of, of_gpio_leds_match);
+static struct gpio_desc *gpio_led_get_gpiod(struct device *dev, int idx,
+ const struct gpio_led *template)
+{
+ struct gpio_desc *gpiod;
+ unsigned long flags = GPIOF_OUT_INIT_LOW;
+ int ret;
+
+ /*
+ * This means the LED does not come from the device tree
+ * or ACPI, so let's try just getting it by index from the
+ * device, this will hit the board file, if any and get
+ * the GPIO from there.
+ */
+ gpiod = devm_gpiod_get_index(dev, NULL, idx, flags);
+ if (!IS_ERR(gpiod)) {
+ gpiod_set_consumer_name(gpiod, template->name);
+ return gpiod;
+ }
+ if (PTR_ERR(gpiod) != -ENOENT)
+ return gpiod;
+
+ /*
+ * This is the legacy code path for platform code that
+ * still uses GPIO numbers. Ultimately we would like to get
+ * rid of this block completely.
+ */
+
+ /* skip leds that aren't available */
+ if (!gpio_is_valid(template->gpio))
+ return ERR_PTR(-ENOENT);
+
+ if (template->active_low)
+ flags |= GPIOF_ACTIVE_LOW;
+
+ ret = devm_gpio_request_one(dev, template->gpio, flags,
+ template->name);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ gpiod = gpio_to_desc(template->gpio);
+ if (!gpiod)
+ return ERR_PTR(-EINVAL);
+
+ return gpiod;
+}
+
static int gpio_led_probe(struct platform_device *pdev)
{
struct gpio_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
@@ -246,7 +265,22 @@ static int gpio_led_probe(struct platform_device *pdev)
priv->num_leds = pdata->num_leds;
for (i = 0; i < priv->num_leds; i++) {
- ret = create_gpio_led(&pdata->leds[i], &priv->leds[i],
+ const struct gpio_led *template = &pdata->leds[i];
+ struct gpio_led_data *led_dat = &priv->leds[i];
+
+ if (template->gpiod)
+ led_dat->gpiod = template->gpiod;
+ else
+ led_dat->gpiod =
+ gpio_led_get_gpiod(&pdev->dev,
+ i, template);
+ if (IS_ERR(led_dat->gpiod)) {
+ dev_info(&pdev->dev, "Skipping unavailable LED gpio %d (%s)\n",
+ template->gpio, template->name);
+ continue;
+ }
+
+ ret = create_gpio_led(template, led_dat,
&pdev->dev, NULL,
pdata->gpio_blink_set);
if (ret < 0)
diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c
index df80c89ebe7f..5d3faae51d59 100644
--- a/drivers/leds/leds-pwm.c
+++ b/drivers/leds/leds-pwm.c
@@ -100,8 +100,9 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
led_data->pwm = devm_pwm_get(dev, led->name);
if (IS_ERR(led_data->pwm)) {
ret = PTR_ERR(led_data->pwm);
- dev_err(dev, "unable to request PWM for %s: %d\n",
- led->name, ret);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "unable to request PWM for %s: %d\n",
+ led->name, ret);
return ret;
}
diff --git a/drivers/leds/leds-sc27xx-bltc.c b/drivers/leds/leds-sc27xx-bltc.c
index 9d9b7aab843f..fecf27fb1cdc 100644
--- a/drivers/leds/leds-sc27xx-bltc.c
+++ b/drivers/leds/leds-sc27xx-bltc.c
@@ -32,8 +32,18 @@
#define SC27XX_DUTY_MASK GENMASK(15, 0)
#define SC27XX_MOD_MASK GENMASK(7, 0)
+#define SC27XX_CURVE_SHIFT 8
+#define SC27XX_CURVE_L_MASK GENMASK(7, 0)
+#define SC27XX_CURVE_H_MASK GENMASK(15, 8)
+
#define SC27XX_LEDS_OFFSET 0x10
#define SC27XX_LEDS_MAX 3
+#define SC27XX_LEDS_PATTERN_CNT 4
+/* Stage duration step, in milliseconds */
+#define SC27XX_LEDS_STEP 125
+/* Minimum and maximum duration, in milliseconds */
+#define SC27XX_DELTA_T_MIN SC27XX_LEDS_STEP
+#define SC27XX_DELTA_T_MAX (SC27XX_LEDS_STEP * 255)
struct sc27xx_led {
char name[LED_MAX_NAME_SIZE];
@@ -122,6 +132,113 @@ static int sc27xx_led_set(struct led_classdev *ldev, enum led_brightness value)
return err;
}
+static void sc27xx_led_clamp_align_delta_t(u32 *delta_t)
+{
+ u32 v, offset, t = *delta_t;
+
+ v = t + SC27XX_LEDS_STEP / 2;
+ v = clamp_t(u32, v, SC27XX_DELTA_T_MIN, SC27XX_DELTA_T_MAX);
+ offset = v - SC27XX_DELTA_T_MIN;
+ offset = SC27XX_LEDS_STEP * (offset / SC27XX_LEDS_STEP);
+
+ *delta_t = SC27XX_DELTA_T_MIN + offset;
+}
+
+static int sc27xx_led_pattern_clear(struct led_classdev *ldev)
+{
+ struct sc27xx_led *leds = to_sc27xx_led(ldev);
+ struct regmap *regmap = leds->priv->regmap;
+ u32 base = sc27xx_led_get_offset(leds);
+ u32 ctrl_base = leds->priv->base + SC27XX_LEDS_CTRL;
+ u8 ctrl_shift = SC27XX_CTRL_SHIFT * leds->line;
+ int err;
+
+ mutex_lock(&leds->priv->lock);
+
+ /* Reset the rise, high, fall and low time to zero. */
+ regmap_write(regmap, base + SC27XX_LEDS_CURVE0, 0);
+ regmap_write(regmap, base + SC27XX_LEDS_CURVE1, 0);
+
+ err = regmap_update_bits(regmap, ctrl_base,
+ (SC27XX_LED_RUN | SC27XX_LED_TYPE) << ctrl_shift, 0);
+
+ ldev->brightness = LED_OFF;
+
+ mutex_unlock(&leds->priv->lock);
+
+ return err;
+}
+
+static int sc27xx_led_pattern_set(struct led_classdev *ldev,
+ struct led_pattern *pattern,
+ u32 len, int repeat)
+{
+ struct sc27xx_led *leds = to_sc27xx_led(ldev);
+ u32 base = sc27xx_led_get_offset(leds);
+ u32 ctrl_base = leds->priv->base + SC27XX_LEDS_CTRL;
+ u8 ctrl_shift = SC27XX_CTRL_SHIFT * leds->line;
+ struct regmap *regmap = leds->priv->regmap;
+ int err;
+
+ /*
+ * Must contain 4 tuples to configure the rise time, high time, fall
+ * time and low time to enable the breathing mode.
+ */
+ if (len != SC27XX_LEDS_PATTERN_CNT)
+ return -EINVAL;
+
+ mutex_lock(&leds->priv->lock);
+
+ sc27xx_led_clamp_align_delta_t(&pattern[0].delta_t);
+ err = regmap_update_bits(regmap, base + SC27XX_LEDS_CURVE0,
+ SC27XX_CURVE_L_MASK,
+ pattern[0].delta_t / SC27XX_LEDS_STEP);
+ if (err)
+ goto out;
+
+ sc27xx_led_clamp_align_delta_t(&pattern[1].delta_t);
+ err = regmap_update_bits(regmap, base + SC27XX_LEDS_CURVE1,
+ SC27XX_CURVE_L_MASK,
+ pattern[1].delta_t / SC27XX_LEDS_STEP);
+ if (err)
+ goto out;
+
+ sc27xx_led_clamp_align_delta_t(&pattern[2].delta_t);
+ err = regmap_update_bits(regmap, base + SC27XX_LEDS_CURVE0,
+ SC27XX_CURVE_H_MASK,
+ (pattern[2].delta_t / SC27XX_LEDS_STEP) <<
+ SC27XX_CURVE_SHIFT);
+ if (err)
+ goto out;
+
+ sc27xx_led_clamp_align_delta_t(&pattern[3].delta_t);
+ err = regmap_update_bits(regmap, base + SC27XX_LEDS_CURVE1,
+ SC27XX_CURVE_H_MASK,
+ (pattern[3].delta_t / SC27XX_LEDS_STEP) <<
+ SC27XX_CURVE_SHIFT);
+ if (err)
+ goto out;
+
+ err = regmap_update_bits(regmap, base + SC27XX_LEDS_DUTY,
+ SC27XX_DUTY_MASK,
+ (pattern[1].brightness << SC27XX_DUTY_SHIFT) |
+ SC27XX_MOD_MASK);
+ if (err)
+ goto out;
+
+ /* Enable the LED breathing mode */
+ err = regmap_update_bits(regmap, ctrl_base,
+ SC27XX_LED_RUN << ctrl_shift,
+ SC27XX_LED_RUN << ctrl_shift);
+ if (!err)
+ ldev->brightness = pattern[1].brightness;
+
+out:
+ mutex_unlock(&leds->priv->lock);
+
+ return err;
+}
+
static int sc27xx_led_register(struct device *dev, struct sc27xx_led_priv *priv)
{
int i, err;
@@ -140,6 +257,9 @@ static int sc27xx_led_register(struct device *dev, struct sc27xx_led_priv *priv)
led->priv = priv;
led->ldev.name = led->name;
led->ldev.brightness_set_blocking = sc27xx_led_set;
+ led->ldev.pattern_set = sc27xx_led_pattern_set;
+ led->ldev.pattern_clear = sc27xx_led_pattern_clear;
+ led->ldev.default_trigger = "pattern";
err = devm_led_classdev_register(dev, &led->ldev);
if (err)
@@ -241,4 +361,5 @@ module_platform_driver(sc27xx_led_driver);
MODULE_DESCRIPTION("Spreadtrum SC27xx breathing light controller driver");
MODULE_AUTHOR("Xiaotong Lu <xiaotong.lu@spreadtrum.com>");
+MODULE_AUTHOR("Baolin Wang <baolin.wang@linaro.org>");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/trigger/Kconfig b/drivers/leds/trigger/Kconfig
index 4018af769969..b76fc3cdc8f8 100644
--- a/drivers/leds/trigger/Kconfig
+++ b/drivers/leds/trigger/Kconfig
@@ -129,4 +129,11 @@ config LEDS_TRIGGER_NETDEV
This allows LEDs to be controlled by network device activity.
If unsure, say Y.
+config LEDS_TRIGGER_PATTERN
+ tristate "LED Pattern Trigger"
+ help
+ This allows LEDs to be controlled by a software or hardware pattern
+ which is a series of tuples, of brightness and duration (ms).
+ If unsure, say N
+
endif # LEDS_TRIGGERS
diff --git a/drivers/leds/trigger/Makefile b/drivers/leds/trigger/Makefile
index f3cfe1950538..9bcb64ee8123 100644
--- a/drivers/leds/trigger/Makefile
+++ b/drivers/leds/trigger/Makefile
@@ -13,3 +13,4 @@ obj-$(CONFIG_LEDS_TRIGGER_TRANSIENT) += ledtrig-transient.o
obj-$(CONFIG_LEDS_TRIGGER_CAMERA) += ledtrig-camera.o
obj-$(CONFIG_LEDS_TRIGGER_PANIC) += ledtrig-panic.o
obj-$(CONFIG_LEDS_TRIGGER_NETDEV) += ledtrig-netdev.o
+obj-$(CONFIG_LEDS_TRIGGER_PATTERN) += ledtrig-pattern.o
diff --git a/drivers/leds/trigger/ledtrig-pattern.c b/drivers/leds/trigger/ledtrig-pattern.c
new file mode 100644
index 000000000000..1870cf87afe1
--- /dev/null
+++ b/drivers/leds/trigger/ledtrig-pattern.c
@@ -0,0 +1,400 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * LED pattern trigger
+ *
+ * Idea discussed with Pavel Machek. Raphael Teysseyre implemented
+ * the first version, Baolin Wang simplified and improved the approach.
+ */
+
+#include <linux/kernel.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+
+#define MAX_PATTERNS 1024
+/*
+ * When doing gradual dimming, the led brightness will be updated
+ * every 50 milliseconds.
+ */
+#define UPDATE_INTERVAL 50
+
+struct pattern_trig_data {
+ struct led_classdev *led_cdev;
+ struct led_pattern patterns[MAX_PATTERNS];
+ struct led_pattern *curr;
+ struct led_pattern *next;
+ struct mutex lock;
+ u32 npatterns;
+ int repeat;
+ int last_repeat;
+ int delta_t;
+ bool is_indefinite;
+ bool is_hw_pattern;
+ struct timer_list timer;
+};
+
+static void pattern_trig_update_patterns(struct pattern_trig_data *data)
+{
+ data->curr = data->next;
+ if (!data->is_indefinite && data->curr == data->patterns)
+ data->repeat--;
+
+ if (data->next == data->patterns + data->npatterns - 1)
+ data->next = data->patterns;
+ else
+ data->next++;
+
+ data->delta_t = 0;
+}
+
+static int pattern_trig_compute_brightness(struct pattern_trig_data *data)
+{
+ int step_brightness;
+
+ /*
+ * If current tuple's duration is less than the dimming interval,
+ * we should treat it as a step change of brightness instead of
+ * doing gradual dimming.
+ */
+ if (data->delta_t == 0 || data->curr->delta_t < UPDATE_INTERVAL)
+ return data->curr->brightness;
+
+ step_brightness = abs(data->next->brightness - data->curr->brightness);
+ step_brightness = data->delta_t * step_brightness / data->curr->delta_t;
+
+ if (data->next->brightness > data->curr->brightness)
+ return data->curr->brightness + step_brightness;
+ else
+ return data->curr->brightness - step_brightness;
+}
+
+static void pattern_trig_timer_function(struct timer_list *t)
+{
+ struct pattern_trig_data *data = from_timer(data, t, timer);
+
+ for (;;) {
+ if (!data->is_indefinite && !data->repeat)
+ break;
+
+ if (data->curr->brightness == data->next->brightness) {
+ /* Step change of brightness */
+ led_set_brightness(data->led_cdev,
+ data->curr->brightness);
+ mod_timer(&data->timer,
+ jiffies + msecs_to_jiffies(data->curr->delta_t));
+ if (!data->next->delta_t) {
+ /* Skip the tuple with zero duration */
+ pattern_trig_update_patterns(data);
+ }
+ /* Select next tuple */
+ pattern_trig_update_patterns(data);
+ } else {
+ /* Gradual dimming */
+
+ /*
+ * If the accumulation time is larger than current
+ * tuple's duration, we should go next one and re-check
+ * if we repeated done.
+ */
+ if (data->delta_t > data->curr->delta_t) {
+ pattern_trig_update_patterns(data);
+ continue;
+ }
+
+ led_set_brightness(data->led_cdev,
+ pattern_trig_compute_brightness(data));
+ mod_timer(&data->timer,
+ jiffies + msecs_to_jiffies(UPDATE_INTERVAL));
+
+ /* Accumulate the gradual dimming time */
+ data->delta_t += UPDATE_INTERVAL;
+ }
+
+ break;
+ }
+}
+
+static int pattern_trig_start_pattern(struct led_classdev *led_cdev)
+{
+ struct pattern_trig_data *data = led_cdev->trigger_data;
+
+ if (!data->npatterns)
+ return 0;
+
+ if (data->is_hw_pattern) {
+ return led_cdev->pattern_set(led_cdev, data->patterns,
+ data->npatterns, data->repeat);
+ }
+
+ /* At least 2 tuples for software pattern. */
+ if (data->npatterns < 2)
+ return -EINVAL;
+
+ data->delta_t = 0;
+ data->curr = data->patterns;
+ data->next = data->patterns + 1;
+ data->timer.expires = jiffies;
+ add_timer(&data->timer);
+
+ return 0;
+}
+
+static ssize_t repeat_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct pattern_trig_data *data = led_cdev->trigger_data;
+ int repeat;
+
+ mutex_lock(&data->lock);
+
+ repeat = data->last_repeat;
+
+ mutex_unlock(&data->lock);
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", repeat);
+}
+
+static ssize_t repeat_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct pattern_trig_data *data = led_cdev->trigger_data;
+ int err, res;
+
+ err = kstrtos32(buf, 10, &res);
+ if (err)
+ return err;
+
+ /* Number 0 and negative numbers except -1 are invalid. */
+ if (res < -1 || res == 0)
+ return -EINVAL;
+
+ mutex_lock(&data->lock);
+
+ del_timer_sync(&data->timer);
+
+ if (data->is_hw_pattern)
+ led_cdev->pattern_clear(led_cdev);
+
+ data->last_repeat = data->repeat = res;
+ /* -1 means repeat indefinitely */
+ if (data->repeat == -1)
+ data->is_indefinite = true;
+ else
+ data->is_indefinite = false;
+
+ err = pattern_trig_start_pattern(led_cdev);
+
+ mutex_unlock(&data->lock);
+ return err < 0 ? err : count;
+}
+
+static DEVICE_ATTR_RW(repeat);
+
+static ssize_t pattern_trig_show_patterns(struct pattern_trig_data *data,
+ char *buf, bool hw_pattern)
+{
+ ssize_t count = 0;
+ int i;
+
+ mutex_lock(&data->lock);
+
+ if (!data->npatterns || (data->is_hw_pattern ^ hw_pattern))
+ goto out;
+
+ for (i = 0; i < data->npatterns; i++) {
+ count += scnprintf(buf + count, PAGE_SIZE - count,
+ "%d %u ",
+ data->patterns[i].brightness,
+ data->patterns[i].delta_t);
+ }
+
+ buf[count - 1] = '\n';
+
+out:
+ mutex_unlock(&data->lock);
+ return count;
+}
+
+static ssize_t pattern_trig_store_patterns(struct led_classdev *led_cdev,
+ const char *buf, size_t count,
+ bool hw_pattern)
+{
+ struct pattern_trig_data *data = led_cdev->trigger_data;
+ int ccount, cr, offset = 0, err = 0;
+
+ mutex_lock(&data->lock);
+
+ del_timer_sync(&data->timer);
+
+ if (data->is_hw_pattern)
+ led_cdev->pattern_clear(led_cdev);
+
+ data->is_hw_pattern = hw_pattern;
+ data->npatterns = 0;
+
+ while (offset < count - 1 && data->npatterns < MAX_PATTERNS) {
+ cr = 0;
+ ccount = sscanf(buf + offset, "%d %u %n",
+ &data->patterns[data->npatterns].brightness,
+ &data->patterns[data->npatterns].delta_t, &cr);
+ if (ccount != 2) {
+ data->npatterns = 0;
+ err = -EINVAL;
+ goto out;
+ }
+
+ offset += cr;
+ data->npatterns++;
+ }
+
+ err = pattern_trig_start_pattern(led_cdev);
+ if (err)
+ data->npatterns = 0;
+
+out:
+ mutex_unlock(&data->lock);
+ return err < 0 ? err : count;
+}
+
+static ssize_t pattern_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct pattern_trig_data *data = led_cdev->trigger_data;
+
+ return pattern_trig_show_patterns(data, buf, false);
+}
+
+static ssize_t pattern_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+
+ return pattern_trig_store_patterns(led_cdev, buf, count, false);
+}
+
+static DEVICE_ATTR_RW(pattern);
+
+static ssize_t hw_pattern_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct pattern_trig_data *data = led_cdev->trigger_data;
+
+ return pattern_trig_show_patterns(data, buf, true);
+}
+
+static ssize_t hw_pattern_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+
+ return pattern_trig_store_patterns(led_cdev, buf, count, true);
+}
+
+static DEVICE_ATTR_RW(hw_pattern);
+
+static umode_t pattern_trig_attrs_mode(struct kobject *kobj,
+ struct attribute *attr, int index)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+
+ if (attr == &dev_attr_repeat.attr || attr == &dev_attr_pattern.attr)
+ return attr->mode;
+ else if (attr == &dev_attr_hw_pattern.attr && led_cdev->pattern_set)
+ return attr->mode;
+
+ return 0;
+}
+
+static struct attribute *pattern_trig_attrs[] = {
+ &dev_attr_pattern.attr,
+ &dev_attr_hw_pattern.attr,
+ &dev_attr_repeat.attr,
+ NULL
+};
+
+static const struct attribute_group pattern_trig_group = {
+ .attrs = pattern_trig_attrs,
+ .is_visible = pattern_trig_attrs_mode,
+};
+
+static const struct attribute_group *pattern_trig_groups[] = {
+ &pattern_trig_group,
+ NULL,
+};
+
+static int pattern_trig_activate(struct led_classdev *led_cdev)
+{
+ struct pattern_trig_data *data;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ if (!!led_cdev->pattern_set ^ !!led_cdev->pattern_clear) {
+ dev_warn(led_cdev->dev,
+ "Hardware pattern ops validation failed\n");
+ led_cdev->pattern_set = NULL;
+ led_cdev->pattern_clear = NULL;
+ }
+
+ data->is_indefinite = true;
+ data->last_repeat = -1;
+ mutex_init(&data->lock);
+ data->led_cdev = led_cdev;
+ led_set_trigger_data(led_cdev, data);
+ timer_setup(&data->timer, pattern_trig_timer_function, 0);
+ led_cdev->activated = true;
+
+ return 0;
+}
+
+static void pattern_trig_deactivate(struct led_classdev *led_cdev)
+{
+ struct pattern_trig_data *data = led_cdev->trigger_data;
+
+ if (!led_cdev->activated)
+ return;
+
+ if (led_cdev->pattern_clear)
+ led_cdev->pattern_clear(led_cdev);
+
+ del_timer_sync(&data->timer);
+
+ led_set_brightness(led_cdev, LED_OFF);
+ kfree(data);
+ led_cdev->activated = false;
+}
+
+static struct led_trigger pattern_led_trigger = {
+ .name = "pattern",
+ .activate = pattern_trig_activate,
+ .deactivate = pattern_trig_deactivate,
+ .groups = pattern_trig_groups,
+};
+
+static int __init pattern_trig_init(void)
+{
+ return led_trigger_register(&pattern_led_trigger);
+}
+
+static void __exit pattern_trig_exit(void)
+{
+ led_trigger_unregister(&pattern_led_trigger);
+}
+
+module_init(pattern_trig_init);
+module_exit(pattern_trig_exit);
+
+MODULE_AUTHOR("Raphael Teysseyre <rteysseyre@gmail.com");
+MODULE_AUTHOR("Baolin Wang <baolin.wang@linaro.org");
+MODULE_DESCRIPTION("LED Pattern trigger");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/lightnvm/Kconfig b/drivers/lightnvm/Kconfig
index 439bf90d084d..a872cd720967 100644
--- a/drivers/lightnvm/Kconfig
+++ b/drivers/lightnvm/Kconfig
@@ -4,8 +4,7 @@
menuconfig NVM
bool "Open-Channel SSD target support"
- depends on BLOCK && PCI
- select BLK_DEV_NVME
+ depends on BLOCK
help
Say Y here to get to enable Open-channel SSDs.
diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
index 60aa7bc5a630..efb976a863d2 100644
--- a/drivers/lightnvm/core.c
+++ b/drivers/lightnvm/core.c
@@ -355,6 +355,11 @@ static int nvm_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create)
return -EINVAL;
}
+ if ((tt->flags & NVM_TGT_F_HOST_L2P) != (dev->geo.dom & NVM_RSP_L2P)) {
+ pr_err("nvm: device is incompatible with target L2P type.\n");
+ return -EINVAL;
+ }
+
if (nvm_target_exists(create->tgtname)) {
pr_err("nvm: target name already exists (%s)\n",
create->tgtname);
@@ -598,22 +603,16 @@ static void nvm_ppa_dev_to_tgt(struct nvm_tgt_dev *tgt_dev,
static void nvm_rq_tgt_to_dev(struct nvm_tgt_dev *tgt_dev, struct nvm_rq *rqd)
{
- if (rqd->nr_ppas == 1) {
- nvm_ppa_tgt_to_dev(tgt_dev, &rqd->ppa_addr, 1);
- return;
- }
+ struct ppa_addr *ppa_list = nvm_rq_to_ppa_list(rqd);
- nvm_ppa_tgt_to_dev(tgt_dev, rqd->ppa_list, rqd->nr_ppas);
+ nvm_ppa_tgt_to_dev(tgt_dev, ppa_list, rqd->nr_ppas);
}
static void nvm_rq_dev_to_tgt(struct nvm_tgt_dev *tgt_dev, struct nvm_rq *rqd)
{
- if (rqd->nr_ppas == 1) {
- nvm_ppa_dev_to_tgt(tgt_dev, &rqd->ppa_addr, 1);
- return;
- }
+ struct ppa_addr *ppa_list = nvm_rq_to_ppa_list(rqd);
- nvm_ppa_dev_to_tgt(tgt_dev, rqd->ppa_list, rqd->nr_ppas);
+ nvm_ppa_dev_to_tgt(tgt_dev, ppa_list, rqd->nr_ppas);
}
int nvm_register_tgt_type(struct nvm_tgt_type *tt)
@@ -712,45 +711,23 @@ static void nvm_free_rqd_ppalist(struct nvm_tgt_dev *tgt_dev,
nvm_dev_dma_free(tgt_dev->parent, rqd->ppa_list, rqd->dma_ppa_list);
}
-int nvm_get_chunk_meta(struct nvm_tgt_dev *tgt_dev, struct nvm_chk_meta *meta,
- struct ppa_addr ppa, int nchks)
+static int nvm_set_flags(struct nvm_geo *geo, struct nvm_rq *rqd)
{
- struct nvm_dev *dev = tgt_dev->parent;
-
- nvm_ppa_tgt_to_dev(tgt_dev, &ppa, 1);
-
- return dev->ops->get_chk_meta(tgt_dev->parent, meta,
- (sector_t)ppa.ppa, nchks);
-}
-EXPORT_SYMBOL(nvm_get_chunk_meta);
-
-int nvm_set_tgt_bb_tbl(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *ppas,
- int nr_ppas, int type)
-{
- struct nvm_dev *dev = tgt_dev->parent;
- struct nvm_rq rqd;
- int ret;
+ int flags = 0;
- if (nr_ppas > NVM_MAX_VLBA) {
- pr_err("nvm: unable to update all blocks atomically\n");
- return -EINVAL;
- }
+ if (geo->version == NVM_OCSSD_SPEC_20)
+ return 0;
- memset(&rqd, 0, sizeof(struct nvm_rq));
+ if (rqd->is_seq)
+ flags |= geo->pln_mode >> 1;
- nvm_set_rqd_ppalist(tgt_dev, &rqd, ppas, nr_ppas);
- nvm_rq_tgt_to_dev(tgt_dev, &rqd);
+ if (rqd->opcode == NVM_OP_PREAD)
+ flags |= (NVM_IO_SCRAMBLE_ENABLE | NVM_IO_SUSPEND);
+ else if (rqd->opcode == NVM_OP_PWRITE)
+ flags |= NVM_IO_SCRAMBLE_ENABLE;
- ret = dev->ops->set_bb_tbl(dev, &rqd.ppa_addr, rqd.nr_ppas, type);
- nvm_free_rqd_ppalist(tgt_dev, &rqd);
- if (ret) {
- pr_err("nvm: failed bb mark\n");
- return -EINVAL;
- }
-
- return 0;
+ return flags;
}
-EXPORT_SYMBOL(nvm_set_tgt_bb_tbl);
int nvm_submit_io(struct nvm_tgt_dev *tgt_dev, struct nvm_rq *rqd)
{
@@ -763,6 +740,7 @@ int nvm_submit_io(struct nvm_tgt_dev *tgt_dev, struct nvm_rq *rqd)
nvm_rq_tgt_to_dev(tgt_dev, rqd);
rqd->dev = tgt_dev;
+ rqd->flags = nvm_set_flags(&tgt_dev->geo, rqd);
/* In case of error, fail with right address format */
ret = dev->ops->submit_io(dev, rqd);
@@ -783,6 +761,7 @@ int nvm_submit_io_sync(struct nvm_tgt_dev *tgt_dev, struct nvm_rq *rqd)
nvm_rq_tgt_to_dev(tgt_dev, rqd);
rqd->dev = tgt_dev;
+ rqd->flags = nvm_set_flags(&tgt_dev->geo, rqd);
/* In case of error, fail with right address format */
ret = dev->ops->submit_io_sync(dev, rqd);
@@ -805,27 +784,159 @@ void nvm_end_io(struct nvm_rq *rqd)
}
EXPORT_SYMBOL(nvm_end_io);
+static int nvm_submit_io_sync_raw(struct nvm_dev *dev, struct nvm_rq *rqd)
+{
+ if (!dev->ops->submit_io_sync)
+ return -ENODEV;
+
+ rqd->flags = nvm_set_flags(&dev->geo, rqd);
+
+ return dev->ops->submit_io_sync(dev, rqd);
+}
+
+static int nvm_bb_chunk_sense(struct nvm_dev *dev, struct ppa_addr ppa)
+{
+ struct nvm_rq rqd = { NULL };
+ struct bio bio;
+ struct bio_vec bio_vec;
+ struct page *page;
+ int ret;
+
+ page = alloc_page(GFP_KERNEL);
+ if (!page)
+ return -ENOMEM;
+
+ bio_init(&bio, &bio_vec, 1);
+ bio_add_page(&bio, page, PAGE_SIZE, 0);
+ bio_set_op_attrs(&bio, REQ_OP_READ, 0);
+
+ rqd.bio = &bio;
+ rqd.opcode = NVM_OP_PREAD;
+ rqd.is_seq = 1;
+ rqd.nr_ppas = 1;
+ rqd.ppa_addr = generic_to_dev_addr(dev, ppa);
+
+ ret = nvm_submit_io_sync_raw(dev, &rqd);
+ if (ret)
+ return ret;
+
+ __free_page(page);
+
+ return rqd.error;
+}
+
/*
- * folds a bad block list from its plane representation to its virtual
- * block representation. The fold is done in place and reduced size is
- * returned.
- *
- * If any of the planes status are bad or grown bad block, the virtual block
- * is marked bad. If not bad, the first plane state acts as the block state.
+ * Scans a 1.2 chunk first and last page to determine if its state.
+ * If the chunk is found to be open, also scan it to update the write
+ * pointer.
*/
-int nvm_bb_tbl_fold(struct nvm_dev *dev, u8 *blks, int nr_blks)
+static int nvm_bb_chunk_scan(struct nvm_dev *dev, struct ppa_addr ppa,
+ struct nvm_chk_meta *meta)
{
struct nvm_geo *geo = &dev->geo;
- int blk, offset, pl, blktype;
+ int ret, pg, pl;
- if (nr_blks != geo->num_chk * geo->pln_mode)
- return -EINVAL;
+ /* sense first page */
+ ret = nvm_bb_chunk_sense(dev, ppa);
+ if (ret < 0) /* io error */
+ return ret;
+ else if (ret == 0) /* valid data */
+ meta->state = NVM_CHK_ST_OPEN;
+ else if (ret > 0) {
+ /*
+ * If empty page, the chunk is free, else it is an
+ * actual io error. In that case, mark it offline.
+ */
+ switch (ret) {
+ case NVM_RSP_ERR_EMPTYPAGE:
+ meta->state = NVM_CHK_ST_FREE;
+ return 0;
+ case NVM_RSP_ERR_FAILCRC:
+ case NVM_RSP_ERR_FAILECC:
+ case NVM_RSP_WARN_HIGHECC:
+ meta->state = NVM_CHK_ST_OPEN;
+ goto scan;
+ default:
+ return -ret; /* other io error */
+ }
+ }
+
+ /* sense last page */
+ ppa.g.pg = geo->num_pg - 1;
+ ppa.g.pl = geo->num_pln - 1;
+
+ ret = nvm_bb_chunk_sense(dev, ppa);
+ if (ret < 0) /* io error */
+ return ret;
+ else if (ret == 0) { /* Chunk fully written */
+ meta->state = NVM_CHK_ST_CLOSED;
+ meta->wp = geo->clba;
+ return 0;
+ } else if (ret > 0) {
+ switch (ret) {
+ case NVM_RSP_ERR_EMPTYPAGE:
+ case NVM_RSP_ERR_FAILCRC:
+ case NVM_RSP_ERR_FAILECC:
+ case NVM_RSP_WARN_HIGHECC:
+ meta->state = NVM_CHK_ST_OPEN;
+ break;
+ default:
+ return -ret; /* other io error */
+ }
+ }
+
+scan:
+ /*
+ * chunk is open, we scan sequentially to update the write pointer.
+ * We make the assumption that targets write data across all planes
+ * before moving to the next page.
+ */
+ for (pg = 0; pg < geo->num_pg; pg++) {
+ for (pl = 0; pl < geo->num_pln; pl++) {
+ ppa.g.pg = pg;
+ ppa.g.pl = pl;
+
+ ret = nvm_bb_chunk_sense(dev, ppa);
+ if (ret < 0) /* io error */
+ return ret;
+ else if (ret == 0) {
+ meta->wp += geo->ws_min;
+ } else if (ret > 0) {
+ switch (ret) {
+ case NVM_RSP_ERR_EMPTYPAGE:
+ return 0;
+ case NVM_RSP_ERR_FAILCRC:
+ case NVM_RSP_ERR_FAILECC:
+ case NVM_RSP_WARN_HIGHECC:
+ meta->wp += geo->ws_min;
+ break;
+ default:
+ return -ret; /* other io error */
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * folds a bad block list from its plane representation to its
+ * chunk representation.
+ *
+ * If any of the planes status are bad or grown bad, the chunk is marked
+ * offline. If not bad, the first plane state acts as the chunk state.
+ */
+static int nvm_bb_to_chunk(struct nvm_dev *dev, struct ppa_addr ppa,
+ u8 *blks, int nr_blks, struct nvm_chk_meta *meta)
+{
+ struct nvm_geo *geo = &dev->geo;
+ int ret, blk, pl, offset, blktype;
for (blk = 0; blk < geo->num_chk; blk++) {
offset = blk * geo->pln_mode;
blktype = blks[offset];
- /* Bad blocks on any planes take precedence over other types */
for (pl = 0; pl < geo->pln_mode; pl++) {
if (blks[offset + pl] &
(NVM_BLK_T_BAD|NVM_BLK_T_GRWN_BAD)) {
@@ -834,23 +945,124 @@ int nvm_bb_tbl_fold(struct nvm_dev *dev, u8 *blks, int nr_blks)
}
}
- blks[blk] = blktype;
+ ppa.g.blk = blk;
+
+ meta->wp = 0;
+ meta->type = NVM_CHK_TP_W_SEQ;
+ meta->wi = 0;
+ meta->slba = generic_to_dev_addr(dev, ppa).ppa;
+ meta->cnlb = dev->geo.clba;
+
+ if (blktype == NVM_BLK_T_FREE) {
+ ret = nvm_bb_chunk_scan(dev, ppa, meta);
+ if (ret)
+ return ret;
+ } else {
+ meta->state = NVM_CHK_ST_OFFLINE;
+ }
+
+ meta++;
}
- return geo->num_chk;
+ return 0;
+}
+
+static int nvm_get_bb_meta(struct nvm_dev *dev, sector_t slba,
+ int nchks, struct nvm_chk_meta *meta)
+{
+ struct nvm_geo *geo = &dev->geo;
+ struct ppa_addr ppa;
+ u8 *blks;
+ int ch, lun, nr_blks;
+ int ret;
+
+ ppa.ppa = slba;
+ ppa = dev_to_generic_addr(dev, ppa);
+
+ if (ppa.g.blk != 0)
+ return -EINVAL;
+
+ if ((nchks % geo->num_chk) != 0)
+ return -EINVAL;
+
+ nr_blks = geo->num_chk * geo->pln_mode;
+
+ blks = kmalloc(nr_blks, GFP_KERNEL);
+ if (!blks)
+ return -ENOMEM;
+
+ for (ch = ppa.g.ch; ch < geo->num_ch; ch++) {
+ for (lun = ppa.g.lun; lun < geo->num_lun; lun++) {
+ struct ppa_addr ppa_gen, ppa_dev;
+
+ if (!nchks)
+ goto done;
+
+ ppa_gen.ppa = 0;
+ ppa_gen.g.ch = ch;
+ ppa_gen.g.lun = lun;
+ ppa_dev = generic_to_dev_addr(dev, ppa_gen);
+
+ ret = dev->ops->get_bb_tbl(dev, ppa_dev, blks);
+ if (ret)
+ goto done;
+
+ ret = nvm_bb_to_chunk(dev, ppa_gen, blks, nr_blks,
+ meta);
+ if (ret)
+ goto done;
+
+ meta += geo->num_chk;
+ nchks -= geo->num_chk;
+ }
+ }
+done:
+ kfree(blks);
+ return ret;
}
-EXPORT_SYMBOL(nvm_bb_tbl_fold);
-int nvm_get_tgt_bb_tbl(struct nvm_tgt_dev *tgt_dev, struct ppa_addr ppa,
- u8 *blks)
+int nvm_get_chunk_meta(struct nvm_tgt_dev *tgt_dev, struct ppa_addr ppa,
+ int nchks, struct nvm_chk_meta *meta)
{
struct nvm_dev *dev = tgt_dev->parent;
nvm_ppa_tgt_to_dev(tgt_dev, &ppa, 1);
- return dev->ops->get_bb_tbl(dev, ppa, blks);
+ if (dev->geo.version == NVM_OCSSD_SPEC_12)
+ return nvm_get_bb_meta(dev, (sector_t)ppa.ppa, nchks, meta);
+
+ return dev->ops->get_chk_meta(dev, (sector_t)ppa.ppa, nchks, meta);
+}
+EXPORT_SYMBOL_GPL(nvm_get_chunk_meta);
+
+int nvm_set_chunk_meta(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *ppas,
+ int nr_ppas, int type)
+{
+ struct nvm_dev *dev = tgt_dev->parent;
+ struct nvm_rq rqd;
+ int ret;
+
+ if (dev->geo.version == NVM_OCSSD_SPEC_20)
+ return 0;
+
+ if (nr_ppas > NVM_MAX_VLBA) {
+ pr_err("nvm: unable to update all blocks atomically\n");
+ return -EINVAL;
+ }
+
+ memset(&rqd, 0, sizeof(struct nvm_rq));
+
+ nvm_set_rqd_ppalist(tgt_dev, &rqd, ppas, nr_ppas);
+ nvm_rq_tgt_to_dev(tgt_dev, &rqd);
+
+ ret = dev->ops->set_bb_tbl(dev, &rqd.ppa_addr, rqd.nr_ppas, type);
+ nvm_free_rqd_ppalist(tgt_dev, &rqd);
+ if (ret)
+ return -EINVAL;
+
+ return 0;
}
-EXPORT_SYMBOL(nvm_get_tgt_bb_tbl);
+EXPORT_SYMBOL_GPL(nvm_set_chunk_meta);
static int nvm_core_init(struct nvm_dev *dev)
{
diff --git a/drivers/lightnvm/pblk-cache.c b/drivers/lightnvm/pblk-cache.c
index f565a56b898a..c9fa26f95659 100644
--- a/drivers/lightnvm/pblk-cache.c
+++ b/drivers/lightnvm/pblk-cache.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2016 CNEX Labs
* Initial release: Javier Gonzalez <javier@cnexlabs.com>
diff --git a/drivers/lightnvm/pblk-core.c b/drivers/lightnvm/pblk-core.c
index 00984b486fea..6944aac43b01 100644
--- a/drivers/lightnvm/pblk-core.c
+++ b/drivers/lightnvm/pblk-core.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2016 CNEX Labs
* Initial release: Javier Gonzalez <javier@cnexlabs.com>
@@ -16,7 +17,10 @@
*
*/
+#define CREATE_TRACE_POINTS
+
#include "pblk.h"
+#include "pblk-trace.h"
static void pblk_line_mark_bb(struct work_struct *work)
{
@@ -27,12 +31,12 @@ static void pblk_line_mark_bb(struct work_struct *work)
struct ppa_addr *ppa = line_ws->priv;
int ret;
- ret = nvm_set_tgt_bb_tbl(dev, ppa, 1, NVM_BLK_T_GRWN_BAD);
+ ret = nvm_set_chunk_meta(dev, ppa, 1, NVM_BLK_T_GRWN_BAD);
if (ret) {
struct pblk_line *line;
int pos;
- line = &pblk->lines[pblk_ppa_to_line(*ppa)];
+ line = pblk_ppa_to_line(pblk, *ppa);
pos = pblk_ppa_to_pos(&dev->geo, *ppa);
pblk_err(pblk, "failed to mark bb, line:%d, pos:%d\n",
@@ -80,19 +84,28 @@ static void __pblk_end_io_erase(struct pblk *pblk, struct nvm_rq *rqd)
struct pblk_line *line;
int pos;
- line = &pblk->lines[pblk_ppa_to_line(rqd->ppa_addr)];
+ line = pblk_ppa_to_line(pblk, rqd->ppa_addr);
pos = pblk_ppa_to_pos(geo, rqd->ppa_addr);
chunk = &line->chks[pos];
atomic_dec(&line->left_seblks);
if (rqd->error) {
+ trace_pblk_chunk_reset(pblk_disk_name(pblk),
+ &rqd->ppa_addr, PBLK_CHUNK_RESET_FAILED);
+
chunk->state = NVM_CHK_ST_OFFLINE;
pblk_mark_bb(pblk, line, rqd->ppa_addr);
} else {
+ trace_pblk_chunk_reset(pblk_disk_name(pblk),
+ &rqd->ppa_addr, PBLK_CHUNK_RESET_DONE);
+
chunk->state = NVM_CHK_ST_FREE;
}
+ trace_pblk_chunk_state(pblk_disk_name(pblk), &rqd->ppa_addr,
+ chunk->state);
+
atomic_dec(&pblk->inflight_io);
}
@@ -108,9 +121,9 @@ static void pblk_end_io_erase(struct nvm_rq *rqd)
/*
* Get information for all chunks from the device.
*
- * The caller is responsible for freeing the returned structure
+ * The caller is responsible for freeing (vmalloc) the returned structure
*/
-struct nvm_chk_meta *pblk_chunk_get_info(struct pblk *pblk)
+struct nvm_chk_meta *pblk_get_chunk_meta(struct pblk *pblk)
{
struct nvm_tgt_dev *dev = pblk->dev;
struct nvm_geo *geo = &dev->geo;
@@ -122,11 +135,11 @@ struct nvm_chk_meta *pblk_chunk_get_info(struct pblk *pblk)
ppa.ppa = 0;
len = geo->all_chunks * sizeof(*meta);
- meta = kzalloc(len, GFP_KERNEL);
+ meta = vzalloc(len);
if (!meta)
return ERR_PTR(-ENOMEM);
- ret = nvm_get_chunk_meta(dev, meta, ppa, geo->all_chunks);
+ ret = nvm_get_chunk_meta(dev, ppa, geo->all_chunks, meta);
if (ret) {
kfree(meta);
return ERR_PTR(-EIO);
@@ -192,7 +205,6 @@ void pblk_map_invalidate(struct pblk *pblk, struct ppa_addr ppa)
{
struct pblk_line *line;
u64 paddr;
- int line_id;
#ifdef CONFIG_NVM_PBLK_DEBUG
/* Callers must ensure that the ppa points to a device address */
@@ -200,8 +212,7 @@ void pblk_map_invalidate(struct pblk *pblk, struct ppa_addr ppa)
BUG_ON(pblk_ppa_empty(ppa));
#endif
- line_id = pblk_ppa_to_line(ppa);
- line = &pblk->lines[line_id];
+ line = pblk_ppa_to_line(pblk, ppa);
paddr = pblk_dev_ppa_to_line_addr(pblk, ppa);
__pblk_map_invalidate(pblk, line, paddr);
@@ -227,6 +238,33 @@ static void pblk_invalidate_range(struct pblk *pblk, sector_t slba,
spin_unlock(&pblk->trans_lock);
}
+int pblk_alloc_rqd_meta(struct pblk *pblk, struct nvm_rq *rqd)
+{
+ struct nvm_tgt_dev *dev = pblk->dev;
+
+ rqd->meta_list = nvm_dev_dma_alloc(dev->parent, GFP_KERNEL,
+ &rqd->dma_meta_list);
+ if (!rqd->meta_list)
+ return -ENOMEM;
+
+ if (rqd->nr_ppas == 1)
+ return 0;
+
+ rqd->ppa_list = rqd->meta_list + pblk_dma_meta_size;
+ rqd->dma_ppa_list = rqd->dma_meta_list + pblk_dma_meta_size;
+
+ return 0;
+}
+
+void pblk_free_rqd_meta(struct pblk *pblk, struct nvm_rq *rqd)
+{
+ struct nvm_tgt_dev *dev = pblk->dev;
+
+ if (rqd->meta_list)
+ nvm_dev_dma_free(dev->parent, rqd->meta_list,
+ rqd->dma_meta_list);
+}
+
/* Caller must guarantee that the request is a valid type */
struct nvm_rq *pblk_alloc_rqd(struct pblk *pblk, int type)
{
@@ -258,7 +296,6 @@ struct nvm_rq *pblk_alloc_rqd(struct pblk *pblk, int type)
/* Typically used on completion path. Cannot guarantee request consistency */
void pblk_free_rqd(struct pblk *pblk, struct nvm_rq *rqd, int type)
{
- struct nvm_tgt_dev *dev = pblk->dev;
mempool_t *pool;
switch (type) {
@@ -279,9 +316,7 @@ void pblk_free_rqd(struct pblk *pblk, struct nvm_rq *rqd, int type)
return;
}
- if (rqd->meta_list)
- nvm_dev_dma_free(dev->parent, rqd->meta_list,
- rqd->dma_meta_list);
+ pblk_free_rqd_meta(pblk, rqd);
mempool_free(rqd, pool);
}
@@ -409,6 +444,9 @@ struct list_head *pblk_line_gc_list(struct pblk *pblk, struct pblk_line *line)
}
} else {
line->state = PBLK_LINESTATE_CORRUPT;
+ trace_pblk_line_state(pblk_disk_name(pblk), line->id,
+ line->state);
+
line->gc_group = PBLK_LINEGC_NONE;
move_list = &l_mg->corrupt_list;
pblk_err(pblk, "corrupted vsc for line %d, vsc:%d (%d/%d/%d)\n",
@@ -479,9 +517,30 @@ int pblk_submit_io(struct pblk *pblk, struct nvm_rq *rqd)
return nvm_submit_io(dev, rqd);
}
+void pblk_check_chunk_state_update(struct pblk *pblk, struct nvm_rq *rqd)
+{
+ struct ppa_addr *ppa_list = nvm_rq_to_ppa_list(rqd);
+
+ int i;
+
+ for (i = 0; i < rqd->nr_ppas; i++) {
+ struct ppa_addr *ppa = &ppa_list[i];
+ struct nvm_chk_meta *chunk = pblk_dev_ppa_to_chunk(pblk, *ppa);
+ u64 caddr = pblk_dev_ppa_to_chunk_addr(pblk, *ppa);
+
+ if (caddr == 0)
+ trace_pblk_chunk_state(pblk_disk_name(pblk),
+ ppa, NVM_CHK_ST_OPEN);
+ else if (caddr == chunk->cnlb)
+ trace_pblk_chunk_state(pblk_disk_name(pblk),
+ ppa, NVM_CHK_ST_CLOSED);
+ }
+}
+
int pblk_submit_io_sync(struct pblk *pblk, struct nvm_rq *rqd)
{
struct nvm_tgt_dev *dev = pblk->dev;
+ int ret;
atomic_inc(&pblk->inflight_io);
@@ -490,7 +549,27 @@ int pblk_submit_io_sync(struct pblk *pblk, struct nvm_rq *rqd)
return NVM_IO_ERR;
#endif
- return nvm_submit_io_sync(dev, rqd);
+ ret = nvm_submit_io_sync(dev, rqd);
+
+ if (trace_pblk_chunk_state_enabled() && !ret &&
+ rqd->opcode == NVM_OP_PWRITE)
+ pblk_check_chunk_state_update(pblk, rqd);
+
+ return ret;
+}
+
+int pblk_submit_io_sync_sem(struct pblk *pblk, struct nvm_rq *rqd)
+{
+ struct ppa_addr *ppa_list;
+ int ret;
+
+ ppa_list = (rqd->nr_ppas > 1) ? rqd->ppa_list : &rqd->ppa_addr;
+
+ pblk_down_chunk(pblk, ppa_list[0]);
+ ret = pblk_submit_io_sync(pblk, rqd);
+ pblk_up_chunk(pblk, ppa_list[0]);
+
+ return ret;
}
static void pblk_bio_map_addr_endio(struct bio *bio)
@@ -621,262 +700,227 @@ u64 pblk_lookup_page(struct pblk *pblk, struct pblk_line *line)
return paddr;
}
-/*
- * Submit emeta to one LUN in the raid line at the time to avoid a deadlock when
- * taking the per LUN semaphore.
- */
-static int pblk_line_submit_emeta_io(struct pblk *pblk, struct pblk_line *line,
- void *emeta_buf, u64 paddr, int dir)
+u64 pblk_line_smeta_start(struct pblk *pblk, struct pblk_line *line)
{
struct nvm_tgt_dev *dev = pblk->dev;
struct nvm_geo *geo = &dev->geo;
- struct pblk_line_mgmt *l_mg = &pblk->l_mg;
struct pblk_line_meta *lm = &pblk->lm;
- void *ppa_list, *meta_list;
- struct bio *bio;
- struct nvm_rq rqd;
- dma_addr_t dma_ppa_list, dma_meta_list;
- int min = pblk->min_write_pgs;
- int left_ppas = lm->emeta_sec[0];
- int id = line->id;
- int rq_ppas, rq_len;
- int cmd_op, bio_op;
- int i, j;
- int ret;
+ int bit;
- if (dir == PBLK_WRITE) {
- bio_op = REQ_OP_WRITE;
- cmd_op = NVM_OP_PWRITE;
- } else if (dir == PBLK_READ) {
- bio_op = REQ_OP_READ;
- cmd_op = NVM_OP_PREAD;
- } else
- return -EINVAL;
+ /* This usually only happens on bad lines */
+ bit = find_first_zero_bit(line->blk_bitmap, lm->blk_per_line);
+ if (bit >= lm->blk_per_line)
+ return -1;
- meta_list = nvm_dev_dma_alloc(dev->parent, GFP_KERNEL,
- &dma_meta_list);
- if (!meta_list)
- return -ENOMEM;
+ return bit * geo->ws_opt;
+}
- ppa_list = meta_list + pblk_dma_meta_size;
- dma_ppa_list = dma_meta_list + pblk_dma_meta_size;
+int pblk_line_smeta_read(struct pblk *pblk, struct pblk_line *line)
+{
+ struct nvm_tgt_dev *dev = pblk->dev;
+ struct pblk_line_meta *lm = &pblk->lm;
+ struct bio *bio;
+ struct nvm_rq rqd;
+ u64 paddr = pblk_line_smeta_start(pblk, line);
+ int i, ret;
-next_rq:
memset(&rqd, 0, sizeof(struct nvm_rq));
- rq_ppas = pblk_calc_secs(pblk, left_ppas, 0);
- rq_len = rq_ppas * geo->csecs;
+ ret = pblk_alloc_rqd_meta(pblk, &rqd);
+ if (ret)
+ return ret;
- bio = pblk_bio_map_addr(pblk, emeta_buf, rq_ppas, rq_len,
- l_mg->emeta_alloc_type, GFP_KERNEL);
+ bio = bio_map_kern(dev->q, line->smeta, lm->smeta_len, GFP_KERNEL);
if (IS_ERR(bio)) {
ret = PTR_ERR(bio);
- goto free_rqd_dma;
+ goto clear_rqd;
}
bio->bi_iter.bi_sector = 0; /* internal bio */
- bio_set_op_attrs(bio, bio_op, 0);
+ bio_set_op_attrs(bio, REQ_OP_READ, 0);
rqd.bio = bio;
- rqd.meta_list = meta_list;
- rqd.ppa_list = ppa_list;
- rqd.dma_meta_list = dma_meta_list;
- rqd.dma_ppa_list = dma_ppa_list;
- rqd.opcode = cmd_op;
- rqd.nr_ppas = rq_ppas;
-
- if (dir == PBLK_WRITE) {
- struct pblk_sec_meta *meta_list = rqd.meta_list;
-
- rqd.flags = pblk_set_progr_mode(pblk, PBLK_WRITE);
- for (i = 0; i < rqd.nr_ppas; ) {
- spin_lock(&line->lock);
- paddr = __pblk_alloc_page(pblk, line, min);
- spin_unlock(&line->lock);
- for (j = 0; j < min; j++, i++, paddr++) {
- meta_list[i].lba = cpu_to_le64(ADDR_EMPTY);
- rqd.ppa_list[i] =
- addr_to_gen_ppa(pblk, paddr, id);
- }
- }
- } else {
- for (i = 0; i < rqd.nr_ppas; ) {
- struct ppa_addr ppa = addr_to_gen_ppa(pblk, paddr, id);
- int pos = pblk_ppa_to_pos(geo, ppa);
- int read_type = PBLK_READ_RANDOM;
-
- if (pblk_io_aligned(pblk, rq_ppas))
- read_type = PBLK_READ_SEQUENTIAL;
- rqd.flags = pblk_set_read_mode(pblk, read_type);
-
- while (test_bit(pos, line->blk_bitmap)) {
- paddr += min;
- if (pblk_boundary_paddr_checks(pblk, paddr)) {
- pblk_err(pblk, "corrupt emeta line:%d\n",
- line->id);
- bio_put(bio);
- ret = -EINTR;
- goto free_rqd_dma;
- }
-
- ppa = addr_to_gen_ppa(pblk, paddr, id);
- pos = pblk_ppa_to_pos(geo, ppa);
- }
-
- if (pblk_boundary_paddr_checks(pblk, paddr + min)) {
- pblk_err(pblk, "corrupt emeta line:%d\n",
- line->id);
- bio_put(bio);
- ret = -EINTR;
- goto free_rqd_dma;
- }
+ rqd.opcode = NVM_OP_PREAD;
+ rqd.nr_ppas = lm->smeta_sec;
+ rqd.is_seq = 1;
- for (j = 0; j < min; j++, i++, paddr++)
- rqd.ppa_list[i] =
- addr_to_gen_ppa(pblk, paddr, line->id);
- }
- }
+ for (i = 0; i < lm->smeta_sec; i++, paddr++)
+ rqd.ppa_list[i] = addr_to_gen_ppa(pblk, paddr, line->id);
ret = pblk_submit_io_sync(pblk, &rqd);
if (ret) {
- pblk_err(pblk, "emeta I/O submission failed: %d\n", ret);
+ pblk_err(pblk, "smeta I/O submission failed: %d\n", ret);
bio_put(bio);
- goto free_rqd_dma;
+ goto clear_rqd;
}
atomic_dec(&pblk->inflight_io);
- if (rqd.error) {
- if (dir == PBLK_WRITE)
- pblk_log_write_err(pblk, &rqd);
- else
- pblk_log_read_err(pblk, &rqd);
- }
+ if (rqd.error)
+ pblk_log_read_err(pblk, &rqd);
- emeta_buf += rq_len;
- left_ppas -= rq_ppas;
- if (left_ppas)
- goto next_rq;
-free_rqd_dma:
- nvm_dev_dma_free(dev->parent, rqd.meta_list, rqd.dma_meta_list);
+clear_rqd:
+ pblk_free_rqd_meta(pblk, &rqd);
return ret;
}
-u64 pblk_line_smeta_start(struct pblk *pblk, struct pblk_line *line)
-{
- struct nvm_tgt_dev *dev = pblk->dev;
- struct nvm_geo *geo = &dev->geo;
- struct pblk_line_meta *lm = &pblk->lm;
- int bit;
-
- /* This usually only happens on bad lines */
- bit = find_first_zero_bit(line->blk_bitmap, lm->blk_per_line);
- if (bit >= lm->blk_per_line)
- return -1;
-
- return bit * geo->ws_opt;
-}
-
-static int pblk_line_submit_smeta_io(struct pblk *pblk, struct pblk_line *line,
- u64 paddr, int dir)
+static int pblk_line_smeta_write(struct pblk *pblk, struct pblk_line *line,
+ u64 paddr)
{
struct nvm_tgt_dev *dev = pblk->dev;
struct pblk_line_meta *lm = &pblk->lm;
struct bio *bio;
struct nvm_rq rqd;
- __le64 *lba_list = NULL;
+ __le64 *lba_list = emeta_to_lbas(pblk, line->emeta->buf);
+ __le64 addr_empty = cpu_to_le64(ADDR_EMPTY);
int i, ret;
- int cmd_op, bio_op;
- int flags;
-
- if (dir == PBLK_WRITE) {
- bio_op = REQ_OP_WRITE;
- cmd_op = NVM_OP_PWRITE;
- flags = pblk_set_progr_mode(pblk, PBLK_WRITE);
- lba_list = emeta_to_lbas(pblk, line->emeta->buf);
- } else if (dir == PBLK_READ_RECOV || dir == PBLK_READ) {
- bio_op = REQ_OP_READ;
- cmd_op = NVM_OP_PREAD;
- flags = pblk_set_read_mode(pblk, PBLK_READ_SEQUENTIAL);
- } else
- return -EINVAL;
memset(&rqd, 0, sizeof(struct nvm_rq));
- rqd.meta_list = nvm_dev_dma_alloc(dev->parent, GFP_KERNEL,
- &rqd.dma_meta_list);
- if (!rqd.meta_list)
- return -ENOMEM;
-
- rqd.ppa_list = rqd.meta_list + pblk_dma_meta_size;
- rqd.dma_ppa_list = rqd.dma_meta_list + pblk_dma_meta_size;
+ ret = pblk_alloc_rqd_meta(pblk, &rqd);
+ if (ret)
+ return ret;
bio = bio_map_kern(dev->q, line->smeta, lm->smeta_len, GFP_KERNEL);
if (IS_ERR(bio)) {
ret = PTR_ERR(bio);
- goto free_ppa_list;
+ goto clear_rqd;
}
bio->bi_iter.bi_sector = 0; /* internal bio */
- bio_set_op_attrs(bio, bio_op, 0);
+ bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
rqd.bio = bio;
- rqd.opcode = cmd_op;
- rqd.flags = flags;
+ rqd.opcode = NVM_OP_PWRITE;
rqd.nr_ppas = lm->smeta_sec;
+ rqd.is_seq = 1;
for (i = 0; i < lm->smeta_sec; i++, paddr++) {
struct pblk_sec_meta *meta_list = rqd.meta_list;
rqd.ppa_list[i] = addr_to_gen_ppa(pblk, paddr, line->id);
-
- if (dir == PBLK_WRITE) {
- __le64 addr_empty = cpu_to_le64(ADDR_EMPTY);
-
- meta_list[i].lba = lba_list[paddr] = addr_empty;
- }
+ meta_list[i].lba = lba_list[paddr] = addr_empty;
}
- /*
- * This I/O is sent by the write thread when a line is replace. Since
- * the write thread is the only one sending write and erase commands,
- * there is no need to take the LUN semaphore.
- */
- ret = pblk_submit_io_sync(pblk, &rqd);
+ ret = pblk_submit_io_sync_sem(pblk, &rqd);
if (ret) {
pblk_err(pblk, "smeta I/O submission failed: %d\n", ret);
bio_put(bio);
- goto free_ppa_list;
+ goto clear_rqd;
}
atomic_dec(&pblk->inflight_io);
if (rqd.error) {
- if (dir == PBLK_WRITE) {
- pblk_log_write_err(pblk, &rqd);
- ret = 1;
- } else if (dir == PBLK_READ)
- pblk_log_read_err(pblk, &rqd);
+ pblk_log_write_err(pblk, &rqd);
+ ret = -EIO;
}
-free_ppa_list:
- nvm_dev_dma_free(dev->parent, rqd.meta_list, rqd.dma_meta_list);
-
+clear_rqd:
+ pblk_free_rqd_meta(pblk, &rqd);
return ret;
}
-int pblk_line_read_smeta(struct pblk *pblk, struct pblk_line *line)
+int pblk_line_emeta_read(struct pblk *pblk, struct pblk_line *line,
+ void *emeta_buf)
{
- u64 bpaddr = pblk_line_smeta_start(pblk, line);
+ struct nvm_tgt_dev *dev = pblk->dev;
+ struct nvm_geo *geo = &dev->geo;
+ struct pblk_line_mgmt *l_mg = &pblk->l_mg;
+ struct pblk_line_meta *lm = &pblk->lm;
+ void *ppa_list, *meta_list;
+ struct bio *bio;
+ struct nvm_rq rqd;
+ u64 paddr = line->emeta_ssec;
+ dma_addr_t dma_ppa_list, dma_meta_list;
+ int min = pblk->min_write_pgs;
+ int left_ppas = lm->emeta_sec[0];
+ int line_id = line->id;
+ int rq_ppas, rq_len;
+ int i, j;
+ int ret;
- return pblk_line_submit_smeta_io(pblk, line, bpaddr, PBLK_READ_RECOV);
-}
+ meta_list = nvm_dev_dma_alloc(dev->parent, GFP_KERNEL,
+ &dma_meta_list);
+ if (!meta_list)
+ return -ENOMEM;
-int pblk_line_read_emeta(struct pblk *pblk, struct pblk_line *line,
- void *emeta_buf)
-{
- return pblk_line_submit_emeta_io(pblk, line, emeta_buf,
- line->emeta_ssec, PBLK_READ);
+ ppa_list = meta_list + pblk_dma_meta_size;
+ dma_ppa_list = dma_meta_list + pblk_dma_meta_size;
+
+next_rq:
+ memset(&rqd, 0, sizeof(struct nvm_rq));
+
+ rq_ppas = pblk_calc_secs(pblk, left_ppas, 0);
+ rq_len = rq_ppas * geo->csecs;
+
+ bio = pblk_bio_map_addr(pblk, emeta_buf, rq_ppas, rq_len,
+ l_mg->emeta_alloc_type, GFP_KERNEL);
+ if (IS_ERR(bio)) {
+ ret = PTR_ERR(bio);
+ goto free_rqd_dma;
+ }
+
+ bio->bi_iter.bi_sector = 0; /* internal bio */
+ bio_set_op_attrs(bio, REQ_OP_READ, 0);
+
+ rqd.bio = bio;
+ rqd.meta_list = meta_list;
+ rqd.ppa_list = ppa_list;
+ rqd.dma_meta_list = dma_meta_list;
+ rqd.dma_ppa_list = dma_ppa_list;
+ rqd.opcode = NVM_OP_PREAD;
+ rqd.nr_ppas = rq_ppas;
+
+ for (i = 0; i < rqd.nr_ppas; ) {
+ struct ppa_addr ppa = addr_to_gen_ppa(pblk, paddr, line_id);
+ int pos = pblk_ppa_to_pos(geo, ppa);
+
+ if (pblk_io_aligned(pblk, rq_ppas))
+ rqd.is_seq = 1;
+
+ while (test_bit(pos, line->blk_bitmap)) {
+ paddr += min;
+ if (pblk_boundary_paddr_checks(pblk, paddr)) {
+ bio_put(bio);
+ ret = -EINTR;
+ goto free_rqd_dma;
+ }
+
+ ppa = addr_to_gen_ppa(pblk, paddr, line_id);
+ pos = pblk_ppa_to_pos(geo, ppa);
+ }
+
+ if (pblk_boundary_paddr_checks(pblk, paddr + min)) {
+ bio_put(bio);
+ ret = -EINTR;
+ goto free_rqd_dma;
+ }
+
+ for (j = 0; j < min; j++, i++, paddr++)
+ rqd.ppa_list[i] = addr_to_gen_ppa(pblk, paddr, line_id);
+ }
+
+ ret = pblk_submit_io_sync(pblk, &rqd);
+ if (ret) {
+ pblk_err(pblk, "emeta I/O submission failed: %d\n", ret);
+ bio_put(bio);
+ goto free_rqd_dma;
+ }
+
+ atomic_dec(&pblk->inflight_io);
+
+ if (rqd.error)
+ pblk_log_read_err(pblk, &rqd);
+
+ emeta_buf += rq_len;
+ left_ppas -= rq_ppas;
+ if (left_ppas)
+ goto next_rq;
+
+free_rqd_dma:
+ nvm_dev_dma_free(dev->parent, rqd.meta_list, rqd.dma_meta_list);
+ return ret;
}
static void pblk_setup_e_rq(struct pblk *pblk, struct nvm_rq *rqd,
@@ -885,16 +929,17 @@ static void pblk_setup_e_rq(struct pblk *pblk, struct nvm_rq *rqd,
rqd->opcode = NVM_OP_ERASE;
rqd->ppa_addr = ppa;
rqd->nr_ppas = 1;
- rqd->flags = pblk_set_progr_mode(pblk, PBLK_ERASE);
+ rqd->is_seq = 1;
rqd->bio = NULL;
}
static int pblk_blk_erase_sync(struct pblk *pblk, struct ppa_addr ppa)
{
- struct nvm_rq rqd;
- int ret = 0;
+ struct nvm_rq rqd = {NULL};
+ int ret;
- memset(&rqd, 0, sizeof(struct nvm_rq));
+ trace_pblk_chunk_reset(pblk_disk_name(pblk), &ppa,
+ PBLK_CHUNK_RESET_START);
pblk_setup_e_rq(pblk, &rqd, ppa);
@@ -902,19 +947,6 @@ static int pblk_blk_erase_sync(struct pblk *pblk, struct ppa_addr ppa)
* with writes. Thus, there is no need to take the LUN semaphore.
*/
ret = pblk_submit_io_sync(pblk, &rqd);
- if (ret) {
- struct nvm_tgt_dev *dev = pblk->dev;
- struct nvm_geo *geo = &dev->geo;
-
- pblk_err(pblk, "could not sync erase line:%d,blk:%d\n",
- pblk_ppa_to_line(ppa),
- pblk_ppa_to_pos(geo, ppa));
-
- rqd.error = ret;
- goto out;
- }
-
-out:
rqd.private = pblk;
__pblk_end_io_erase(pblk, &rqd);
@@ -1008,6 +1040,8 @@ static int pblk_line_init_metadata(struct pblk *pblk, struct pblk_line *line,
spin_lock(&l_mg->free_lock);
spin_lock(&line->lock);
line->state = PBLK_LINESTATE_BAD;
+ trace_pblk_line_state(pblk_disk_name(pblk), line->id,
+ line->state);
spin_unlock(&line->lock);
list_add_tail(&line->list, &l_mg->bad_list);
@@ -1071,15 +1105,18 @@ static int pblk_line_init_metadata(struct pblk *pblk, struct pblk_line *line,
static int pblk_line_alloc_bitmaps(struct pblk *pblk, struct pblk_line *line)
{
struct pblk_line_meta *lm = &pblk->lm;
+ struct pblk_line_mgmt *l_mg = &pblk->l_mg;
- line->map_bitmap = kzalloc(lm->sec_bitmap_len, GFP_KERNEL);
+ line->map_bitmap = mempool_alloc(l_mg->bitmap_pool, GFP_KERNEL);
if (!line->map_bitmap)
return -ENOMEM;
+ memset(line->map_bitmap, 0, lm->sec_bitmap_len);
+
/* will be initialized using bb info from map_bitmap */
- line->invalid_bitmap = kmalloc(lm->sec_bitmap_len, GFP_KERNEL);
+ line->invalid_bitmap = mempool_alloc(l_mg->bitmap_pool, GFP_KERNEL);
if (!line->invalid_bitmap) {
- kfree(line->map_bitmap);
+ mempool_free(line->map_bitmap, l_mg->bitmap_pool);
line->map_bitmap = NULL;
return -ENOMEM;
}
@@ -1122,7 +1159,7 @@ static int pblk_line_init_bb(struct pblk *pblk, struct pblk_line *line,
line->smeta_ssec = off;
line->cur_sec = off + lm->smeta_sec;
- if (init && pblk_line_submit_smeta_io(pblk, line, off, PBLK_WRITE)) {
+ if (init && pblk_line_smeta_write(pblk, line, off)) {
pblk_debug(pblk, "line smeta I/O failed. Retry\n");
return 0;
}
@@ -1152,6 +1189,8 @@ static int pblk_line_init_bb(struct pblk *pblk, struct pblk_line *line,
bitmap_weight(line->invalid_bitmap, lm->sec_per_line)) {
spin_lock(&line->lock);
line->state = PBLK_LINESTATE_BAD;
+ trace_pblk_line_state(pblk_disk_name(pblk), line->id,
+ line->state);
spin_unlock(&line->lock);
list_add_tail(&line->list, &l_mg->bad_list);
@@ -1204,6 +1243,8 @@ static int pblk_line_prepare(struct pblk *pblk, struct pblk_line *line)
if (line->state == PBLK_LINESTATE_NEW) {
blk_to_erase = pblk_prepare_new_line(pblk, line);
line->state = PBLK_LINESTATE_FREE;
+ trace_pblk_line_state(pblk_disk_name(pblk), line->id,
+ line->state);
} else {
blk_to_erase = blk_in_line;
}
@@ -1221,6 +1262,8 @@ static int pblk_line_prepare(struct pblk *pblk, struct pblk_line *line)
}
line->state = PBLK_LINESTATE_OPEN;
+ trace_pblk_line_state(pblk_disk_name(pblk), line->id,
+ line->state);
atomic_set(&line->left_eblks, blk_to_erase);
atomic_set(&line->left_seblks, blk_to_erase);
@@ -1265,7 +1308,9 @@ int pblk_line_recov_alloc(struct pblk *pblk, struct pblk_line *line)
void pblk_line_recov_close(struct pblk *pblk, struct pblk_line *line)
{
- kfree(line->map_bitmap);
+ struct pblk_line_mgmt *l_mg = &pblk->l_mg;
+
+ mempool_free(line->map_bitmap, l_mg->bitmap_pool);
line->map_bitmap = NULL;
line->smeta = NULL;
line->emeta = NULL;
@@ -1283,8 +1328,11 @@ static void pblk_line_reinit(struct pblk_line *line)
void pblk_line_free(struct pblk_line *line)
{
- kfree(line->map_bitmap);
- kfree(line->invalid_bitmap);
+ struct pblk *pblk = line->pblk;
+ struct pblk_line_mgmt *l_mg = &pblk->l_mg;
+
+ mempool_free(line->map_bitmap, l_mg->bitmap_pool);
+ mempool_free(line->invalid_bitmap, l_mg->bitmap_pool);
pblk_line_reinit(line);
}
@@ -1312,6 +1360,8 @@ retry:
if (unlikely(bit >= lm->blk_per_line)) {
spin_lock(&line->lock);
line->state = PBLK_LINESTATE_BAD;
+ trace_pblk_line_state(pblk_disk_name(pblk), line->id,
+ line->state);
spin_unlock(&line->lock);
list_add_tail(&line->list, &l_mg->bad_list);
@@ -1446,12 +1496,32 @@ retry_setup:
return line;
}
+void pblk_ppa_to_line_put(struct pblk *pblk, struct ppa_addr ppa)
+{
+ struct pblk_line *line;
+
+ line = pblk_ppa_to_line(pblk, ppa);
+ kref_put(&line->ref, pblk_line_put_wq);
+}
+
+void pblk_rq_to_line_put(struct pblk *pblk, struct nvm_rq *rqd)
+{
+ struct ppa_addr *ppa_list;
+ int i;
+
+ ppa_list = (rqd->nr_ppas > 1) ? rqd->ppa_list : &rqd->ppa_addr;
+
+ for (i = 0; i < rqd->nr_ppas; i++)
+ pblk_ppa_to_line_put(pblk, ppa_list[i]);
+}
+
static void pblk_stop_writes(struct pblk *pblk, struct pblk_line *line)
{
lockdep_assert_held(&pblk->l_mg.free_lock);
pblk_set_space_limit(pblk);
pblk->state = PBLK_STATE_STOPPING;
+ trace_pblk_state(pblk_disk_name(pblk), pblk->state);
}
static void pblk_line_close_meta_sync(struct pblk *pblk)
@@ -1501,6 +1571,7 @@ void __pblk_pipeline_flush(struct pblk *pblk)
return;
}
pblk->state = PBLK_STATE_RECOVERING;
+ trace_pblk_state(pblk_disk_name(pblk), pblk->state);
spin_unlock(&l_mg->free_lock);
pblk_flush_writer(pblk);
@@ -1522,6 +1593,7 @@ void __pblk_pipeline_stop(struct pblk *pblk)
spin_lock(&l_mg->free_lock);
pblk->state = PBLK_STATE_STOPPED;
+ trace_pblk_state(pblk_disk_name(pblk), pblk->state);
l_mg->data_line = NULL;
l_mg->data_next = NULL;
spin_unlock(&l_mg->free_lock);
@@ -1539,13 +1611,14 @@ struct pblk_line *pblk_line_replace_data(struct pblk *pblk)
struct pblk_line *cur, *new = NULL;
unsigned int left_seblks;
- cur = l_mg->data_line;
new = l_mg->data_next;
if (!new)
goto out;
- l_mg->data_line = new;
spin_lock(&l_mg->free_lock);
+ cur = l_mg->data_line;
+ l_mg->data_line = new;
+
pblk_line_setup_metadata(new, l_mg, &pblk->lm);
spin_unlock(&l_mg->free_lock);
@@ -1612,6 +1685,8 @@ static void __pblk_line_put(struct pblk *pblk, struct pblk_line *line)
spin_lock(&line->lock);
WARN_ON(line->state != PBLK_LINESTATE_GC);
line->state = PBLK_LINESTATE_FREE;
+ trace_pblk_line_state(pblk_disk_name(pblk), line->id,
+ line->state);
line->gc_group = PBLK_LINEGC_NONE;
pblk_line_free(line);
@@ -1680,6 +1755,9 @@ int pblk_blk_erase_async(struct pblk *pblk, struct ppa_addr ppa)
rqd->end_io = pblk_end_io_erase;
rqd->private = pblk;
+ trace_pblk_chunk_reset(pblk_disk_name(pblk),
+ &ppa, PBLK_CHUNK_RESET_START);
+
/* The write thread schedules erases so that it minimizes disturbances
* with writes. Thus, there is no need to take the LUN semaphore.
*/
@@ -1689,7 +1767,7 @@ int pblk_blk_erase_async(struct pblk *pblk, struct ppa_addr ppa)
struct nvm_geo *geo = &dev->geo;
pblk_err(pblk, "could not async erase line:%d,blk:%d\n",
- pblk_ppa_to_line(ppa),
+ pblk_ppa_to_line_id(ppa),
pblk_ppa_to_pos(geo, ppa));
}
@@ -1741,10 +1819,9 @@ void pblk_line_close(struct pblk *pblk, struct pblk_line *line)
WARN_ON(line->state != PBLK_LINESTATE_OPEN);
line->state = PBLK_LINESTATE_CLOSED;
move_list = pblk_line_gc_list(pblk, line);
-
list_add_tail(&line->list, move_list);
- kfree(line->map_bitmap);
+ mempool_free(line->map_bitmap, l_mg->bitmap_pool);
line->map_bitmap = NULL;
line->smeta = NULL;
line->emeta = NULL;
@@ -1760,6 +1837,9 @@ void pblk_line_close(struct pblk *pblk, struct pblk_line *line)
spin_unlock(&line->lock);
spin_unlock(&l_mg->gc_lock);
+
+ trace_pblk_line_state(pblk_disk_name(pblk), line->id,
+ line->state);
}
void pblk_line_close_meta(struct pblk *pblk, struct pblk_line *line)
@@ -1778,6 +1858,17 @@ void pblk_line_close_meta(struct pblk *pblk, struct pblk_line *line)
wa->pad = cpu_to_le64(atomic64_read(&pblk->pad_wa));
wa->gc = cpu_to_le64(atomic64_read(&pblk->gc_wa));
+ if (le32_to_cpu(emeta_buf->header.identifier) != PBLK_MAGIC) {
+ emeta_buf->header.identifier = cpu_to_le32(PBLK_MAGIC);
+ memcpy(emeta_buf->header.uuid, pblk->instance_uuid, 16);
+ emeta_buf->header.id = cpu_to_le32(line->id);
+ emeta_buf->header.type = cpu_to_le16(line->type);
+ emeta_buf->header.version_major = EMETA_VERSION_MAJOR;
+ emeta_buf->header.version_minor = EMETA_VERSION_MINOR;
+ emeta_buf->header.crc = cpu_to_le32(
+ pblk_calc_meta_header_crc(pblk, &emeta_buf->header));
+ }
+
emeta_buf->nr_valid_lbas = cpu_to_le64(line->nr_valid_lbas);
emeta_buf->crc = cpu_to_le32(pblk_calc_emeta_crc(pblk, emeta_buf));
@@ -1795,8 +1886,6 @@ void pblk_line_close_meta(struct pblk *pblk, struct pblk_line *line)
spin_unlock(&l_mg->close_lock);
pblk_line_should_sync_meta(pblk);
-
-
}
static void pblk_save_lba_list(struct pblk *pblk, struct pblk_line *line)
@@ -1847,8 +1936,7 @@ void pblk_gen_run_ws(struct pblk *pblk, struct pblk_line *line, void *priv,
queue_work(wq, &line_ws->ws);
}
-static void __pblk_down_page(struct pblk *pblk, struct ppa_addr *ppa_list,
- int nr_ppas, int pos)
+static void __pblk_down_chunk(struct pblk *pblk, int pos)
{
struct pblk_lun *rlun = &pblk->luns[pos];
int ret;
@@ -1857,13 +1945,6 @@ static void __pblk_down_page(struct pblk *pblk, struct ppa_addr *ppa_list,
* Only send one inflight I/O per LUN. Since we map at a page
* granurality, all ppas in the I/O will map to the same LUN
*/
-#ifdef CONFIG_NVM_PBLK_DEBUG
- int i;
-
- for (i = 1; i < nr_ppas; i++)
- WARN_ON(ppa_list[0].a.lun != ppa_list[i].a.lun ||
- ppa_list[0].a.ch != ppa_list[i].a.ch);
-#endif
ret = down_timeout(&rlun->wr_sem, msecs_to_jiffies(30000));
if (ret == -ETIME || ret == -EINTR)
@@ -1871,21 +1952,21 @@ static void __pblk_down_page(struct pblk *pblk, struct ppa_addr *ppa_list,
-ret);
}
-void pblk_down_page(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas)
+void pblk_down_chunk(struct pblk *pblk, struct ppa_addr ppa)
{
struct nvm_tgt_dev *dev = pblk->dev;
struct nvm_geo *geo = &dev->geo;
- int pos = pblk_ppa_to_pos(geo, ppa_list[0]);
+ int pos = pblk_ppa_to_pos(geo, ppa);
- __pblk_down_page(pblk, ppa_list, nr_ppas, pos);
+ __pblk_down_chunk(pblk, pos);
}
-void pblk_down_rq(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas,
+void pblk_down_rq(struct pblk *pblk, struct ppa_addr ppa,
unsigned long *lun_bitmap)
{
struct nvm_tgt_dev *dev = pblk->dev;
struct nvm_geo *geo = &dev->geo;
- int pos = pblk_ppa_to_pos(geo, ppa_list[0]);
+ int pos = pblk_ppa_to_pos(geo, ppa);
/* If the LUN has been locked for this same request, do no attempt to
* lock it again
@@ -1893,30 +1974,21 @@ void pblk_down_rq(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas,
if (test_and_set_bit(pos, lun_bitmap))
return;
- __pblk_down_page(pblk, ppa_list, nr_ppas, pos);
+ __pblk_down_chunk(pblk, pos);
}
-void pblk_up_page(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas)
+void pblk_up_chunk(struct pblk *pblk, struct ppa_addr ppa)
{
struct nvm_tgt_dev *dev = pblk->dev;
struct nvm_geo *geo = &dev->geo;
struct pblk_lun *rlun;
- int pos = pblk_ppa_to_pos(geo, ppa_list[0]);
-
-#ifdef CONFIG_NVM_PBLK_DEBUG
- int i;
-
- for (i = 1; i < nr_ppas; i++)
- WARN_ON(ppa_list[0].a.lun != ppa_list[i].a.lun ||
- ppa_list[0].a.ch != ppa_list[i].a.ch);
-#endif
+ int pos = pblk_ppa_to_pos(geo, ppa);
rlun = &pblk->luns[pos];
up(&rlun->wr_sem);
}
-void pblk_up_rq(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas,
- unsigned long *lun_bitmap)
+void pblk_up_rq(struct pblk *pblk, unsigned long *lun_bitmap)
{
struct nvm_tgt_dev *dev = pblk->dev;
struct nvm_geo *geo = &dev->geo;
@@ -2060,8 +2132,7 @@ void pblk_lookup_l2p_seq(struct pblk *pblk, struct ppa_addr *ppas,
/* If the L2P entry maps to a line, the reference is valid */
if (!pblk_ppa_empty(ppa) && !pblk_addr_in_cache(ppa)) {
- int line_id = pblk_ppa_to_line(ppa);
- struct pblk_line *line = &pblk->lines[line_id];
+ struct pblk_line *line = pblk_ppa_to_line(pblk, ppa);
kref_get(&line->ref);
}
diff --git a/drivers/lightnvm/pblk-gc.c b/drivers/lightnvm/pblk-gc.c
index 157c2567c9e8..2fa118c8eb71 100644
--- a/drivers/lightnvm/pblk-gc.c
+++ b/drivers/lightnvm/pblk-gc.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2016 CNEX Labs
* Initial release: Javier Gonzalez <javier@cnexlabs.com>
@@ -16,8 +17,10 @@
*/
#include "pblk.h"
+#include "pblk-trace.h"
#include <linux/delay.h>
+
static void pblk_gc_free_gc_rq(struct pblk_gc_rq *gc_rq)
{
if (gc_rq->data)
@@ -64,6 +67,8 @@ static void pblk_put_line_back(struct pblk *pblk, struct pblk_line *line)
spin_lock(&line->lock);
WARN_ON(line->state != PBLK_LINESTATE_GC);
line->state = PBLK_LINESTATE_CLOSED;
+ trace_pblk_line_state(pblk_disk_name(pblk), line->id,
+ line->state);
move_list = pblk_line_gc_list(pblk, line);
spin_unlock(&line->lock);
@@ -144,7 +149,7 @@ static __le64 *get_lba_list_from_emeta(struct pblk *pblk,
if (!emeta_buf)
return NULL;
- ret = pblk_line_read_emeta(pblk, line, emeta_buf);
+ ret = pblk_line_emeta_read(pblk, line, emeta_buf);
if (ret) {
pblk_err(pblk, "line %d read emeta failed (%d)\n",
line->id, ret);
@@ -405,6 +410,8 @@ void pblk_gc_free_full_lines(struct pblk *pblk)
spin_lock(&line->lock);
WARN_ON(line->state != PBLK_LINESTATE_CLOSED);
line->state = PBLK_LINESTATE_GC;
+ trace_pblk_line_state(pblk_disk_name(pblk), line->id,
+ line->state);
spin_unlock(&line->lock);
list_del(&line->list);
@@ -451,6 +458,8 @@ next_gc_group:
spin_lock(&line->lock);
WARN_ON(line->state != PBLK_LINESTATE_CLOSED);
line->state = PBLK_LINESTATE_GC;
+ trace_pblk_line_state(pblk_disk_name(pblk), line->id,
+ line->state);
spin_unlock(&line->lock);
list_del(&line->list);
diff --git a/drivers/lightnvm/pblk-init.c b/drivers/lightnvm/pblk-init.c
index 537e98f2b24a..13822594647c 100644
--- a/drivers/lightnvm/pblk-init.c
+++ b/drivers/lightnvm/pblk-init.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2015 IT University of Copenhagen (rrpc.c)
* Copyright (C) 2016 CNEX Labs
@@ -19,15 +20,31 @@
*/
#include "pblk.h"
+#include "pblk-trace.h"
static unsigned int write_buffer_size;
module_param(write_buffer_size, uint, 0644);
MODULE_PARM_DESC(write_buffer_size, "number of entries in a write buffer");
-static struct kmem_cache *pblk_ws_cache, *pblk_rec_cache, *pblk_g_rq_cache,
- *pblk_w_rq_cache;
-static DECLARE_RWSEM(pblk_lock);
+struct pblk_global_caches {
+ struct kmem_cache *ws;
+ struct kmem_cache *rec;
+ struct kmem_cache *g_rq;
+ struct kmem_cache *w_rq;
+
+ struct kref kref;
+
+ struct mutex mutex; /* Ensures consistency between
+ * caches and kref
+ */
+};
+
+static struct pblk_global_caches pblk_caches = {
+ .mutex = __MUTEX_INITIALIZER(pblk_caches.mutex),
+ .kref = KREF_INIT(0),
+};
+
struct bio_set pblk_bio_set;
static int pblk_rw_io(struct request_queue *q, struct pblk *pblk,
@@ -168,36 +185,26 @@ static void pblk_rwb_free(struct pblk *pblk)
if (pblk_rb_tear_down_check(&pblk->rwb))
pblk_err(pblk, "write buffer error on tear down\n");
- pblk_rb_data_free(&pblk->rwb);
- vfree(pblk_rb_entries_ref(&pblk->rwb));
+ pblk_rb_free(&pblk->rwb);
}
static int pblk_rwb_init(struct pblk *pblk)
{
struct nvm_tgt_dev *dev = pblk->dev;
struct nvm_geo *geo = &dev->geo;
- struct pblk_rb_entry *entries;
- unsigned long nr_entries, buffer_size;
- unsigned int power_size, power_seg_sz;
- int pgs_in_buffer;
+ unsigned long buffer_size;
+ int pgs_in_buffer, threshold;
- pgs_in_buffer = max(geo->mw_cunits, geo->ws_opt) * geo->all_luns;
+ threshold = geo->mw_cunits * geo->all_luns;
+ pgs_in_buffer = (max(geo->mw_cunits, geo->ws_opt) + geo->ws_opt)
+ * geo->all_luns;
if (write_buffer_size && (write_buffer_size > pgs_in_buffer))
buffer_size = write_buffer_size;
else
buffer_size = pgs_in_buffer;
- nr_entries = pblk_rb_calculate_size(buffer_size);
-
- entries = vzalloc(array_size(nr_entries, sizeof(struct pblk_rb_entry)));
- if (!entries)
- return -ENOMEM;
-
- power_size = get_count_order(nr_entries);
- power_seg_sz = get_count_order(geo->csecs);
-
- return pblk_rb_init(&pblk->rwb, entries, power_size, power_seg_sz);
+ return pblk_rb_init(&pblk->rwb, buffer_size, threshold, geo->csecs);
}
/* Minimum pages needed within a lun */
@@ -306,53 +313,80 @@ static int pblk_set_addrf(struct pblk *pblk)
return 0;
}
-static int pblk_init_global_caches(struct pblk *pblk)
+static int pblk_create_global_caches(void)
{
- down_write(&pblk_lock);
- pblk_ws_cache = kmem_cache_create("pblk_blk_ws",
+
+ pblk_caches.ws = kmem_cache_create("pblk_blk_ws",
sizeof(struct pblk_line_ws), 0, 0, NULL);
- if (!pblk_ws_cache) {
- up_write(&pblk_lock);
+ if (!pblk_caches.ws)
return -ENOMEM;
- }
- pblk_rec_cache = kmem_cache_create("pblk_rec",
+ pblk_caches.rec = kmem_cache_create("pblk_rec",
sizeof(struct pblk_rec_ctx), 0, 0, NULL);
- if (!pblk_rec_cache) {
- kmem_cache_destroy(pblk_ws_cache);
- up_write(&pblk_lock);
- return -ENOMEM;
- }
+ if (!pblk_caches.rec)
+ goto fail_destroy_ws;
- pblk_g_rq_cache = kmem_cache_create("pblk_g_rq", pblk_g_rq_size,
+ pblk_caches.g_rq = kmem_cache_create("pblk_g_rq", pblk_g_rq_size,
0, 0, NULL);
- if (!pblk_g_rq_cache) {
- kmem_cache_destroy(pblk_ws_cache);
- kmem_cache_destroy(pblk_rec_cache);
- up_write(&pblk_lock);
- return -ENOMEM;
- }
+ if (!pblk_caches.g_rq)
+ goto fail_destroy_rec;
- pblk_w_rq_cache = kmem_cache_create("pblk_w_rq", pblk_w_rq_size,
+ pblk_caches.w_rq = kmem_cache_create("pblk_w_rq", pblk_w_rq_size,
0, 0, NULL);
- if (!pblk_w_rq_cache) {
- kmem_cache_destroy(pblk_ws_cache);
- kmem_cache_destroy(pblk_rec_cache);
- kmem_cache_destroy(pblk_g_rq_cache);
- up_write(&pblk_lock);
- return -ENOMEM;
- }
- up_write(&pblk_lock);
+ if (!pblk_caches.w_rq)
+ goto fail_destroy_g_rq;
return 0;
+
+fail_destroy_g_rq:
+ kmem_cache_destroy(pblk_caches.g_rq);
+fail_destroy_rec:
+ kmem_cache_destroy(pblk_caches.rec);
+fail_destroy_ws:
+ kmem_cache_destroy(pblk_caches.ws);
+
+ return -ENOMEM;
}
-static void pblk_free_global_caches(struct pblk *pblk)
+static int pblk_get_global_caches(void)
{
- kmem_cache_destroy(pblk_ws_cache);
- kmem_cache_destroy(pblk_rec_cache);
- kmem_cache_destroy(pblk_g_rq_cache);
- kmem_cache_destroy(pblk_w_rq_cache);
+ int ret;
+
+ mutex_lock(&pblk_caches.mutex);
+
+ if (kref_read(&pblk_caches.kref) > 0) {
+ kref_get(&pblk_caches.kref);
+ mutex_unlock(&pblk_caches.mutex);
+ return 0;
+ }
+
+ ret = pblk_create_global_caches();
+
+ if (!ret)
+ kref_get(&pblk_caches.kref);
+
+ mutex_unlock(&pblk_caches.mutex);
+
+ return ret;
+}
+
+static void pblk_destroy_global_caches(struct kref *ref)
+{
+ struct pblk_global_caches *c;
+
+ c = container_of(ref, struct pblk_global_caches, kref);
+
+ kmem_cache_destroy(c->ws);
+ kmem_cache_destroy(c->rec);
+ kmem_cache_destroy(c->g_rq);
+ kmem_cache_destroy(c->w_rq);
+}
+
+static void pblk_put_global_caches(void)
+{
+ mutex_lock(&pblk_caches.mutex);
+ kref_put(&pblk_caches.kref, pblk_destroy_global_caches);
+ mutex_unlock(&pblk_caches.mutex);
}
static int pblk_core_init(struct pblk *pblk)
@@ -371,23 +405,19 @@ static int pblk_core_init(struct pblk *pblk)
atomic64_set(&pblk->nr_flush, 0);
pblk->nr_flush_rst = 0;
- pblk->min_write_pgs = geo->ws_opt * (geo->csecs / PAGE_SIZE);
+ pblk->min_write_pgs = geo->ws_opt;
max_write_ppas = pblk->min_write_pgs * geo->all_luns;
pblk->max_write_pgs = min_t(int, max_write_ppas, NVM_MAX_VLBA);
+ pblk->max_write_pgs = min_t(int, pblk->max_write_pgs,
+ queue_max_hw_sectors(dev->q) / (geo->csecs >> SECTOR_SHIFT));
pblk_set_sec_per_write(pblk, pblk->min_write_pgs);
- if (pblk->max_write_pgs > PBLK_MAX_REQ_ADDRS) {
- pblk_err(pblk, "vector list too big(%u > %u)\n",
- pblk->max_write_pgs, PBLK_MAX_REQ_ADDRS);
- return -EINVAL;
- }
-
pblk->pad_dist = kcalloc(pblk->min_write_pgs - 1, sizeof(atomic64_t),
GFP_KERNEL);
if (!pblk->pad_dist)
return -ENOMEM;
- if (pblk_init_global_caches(pblk))
+ if (pblk_get_global_caches())
goto fail_free_pad_dist;
/* Internal bios can be at most the sectors signaled by the device. */
@@ -396,27 +426,27 @@ static int pblk_core_init(struct pblk *pblk)
goto free_global_caches;
ret = mempool_init_slab_pool(&pblk->gen_ws_pool, PBLK_GEN_WS_POOL_SIZE,
- pblk_ws_cache);
+ pblk_caches.ws);
if (ret)
goto free_page_bio_pool;
ret = mempool_init_slab_pool(&pblk->rec_pool, geo->all_luns,
- pblk_rec_cache);
+ pblk_caches.rec);
if (ret)
goto free_gen_ws_pool;
ret = mempool_init_slab_pool(&pblk->r_rq_pool, geo->all_luns,
- pblk_g_rq_cache);
+ pblk_caches.g_rq);
if (ret)
goto free_rec_pool;
ret = mempool_init_slab_pool(&pblk->e_rq_pool, geo->all_luns,
- pblk_g_rq_cache);
+ pblk_caches.g_rq);
if (ret)
goto free_r_rq_pool;
ret = mempool_init_slab_pool(&pblk->w_rq_pool, geo->all_luns,
- pblk_w_rq_cache);
+ pblk_caches.w_rq);
if (ret)
goto free_e_rq_pool;
@@ -462,7 +492,7 @@ free_gen_ws_pool:
free_page_bio_pool:
mempool_exit(&pblk->page_bio_pool);
free_global_caches:
- pblk_free_global_caches(pblk);
+ pblk_put_global_caches();
fail_free_pad_dist:
kfree(pblk->pad_dist);
return -ENOMEM;
@@ -486,7 +516,7 @@ static void pblk_core_free(struct pblk *pblk)
mempool_exit(&pblk->e_rq_pool);
mempool_exit(&pblk->w_rq_pool);
- pblk_free_global_caches(pblk);
+ pblk_put_global_caches();
kfree(pblk->pad_dist);
}
@@ -504,6 +534,9 @@ static void pblk_line_mg_free(struct pblk *pblk)
pblk_mfree(l_mg->eline_meta[i]->buf, l_mg->emeta_alloc_type);
kfree(l_mg->eline_meta[i]);
}
+
+ mempool_destroy(l_mg->bitmap_pool);
+ kmem_cache_destroy(l_mg->bitmap_cache);
}
static void pblk_line_meta_free(struct pblk_line_mgmt *l_mg,
@@ -540,67 +573,6 @@ static void pblk_lines_free(struct pblk *pblk)
kfree(pblk->lines);
}
-static int pblk_bb_get_tbl(struct nvm_tgt_dev *dev, struct pblk_lun *rlun,
- u8 *blks, int nr_blks)
-{
- struct ppa_addr ppa;
- int ret;
-
- ppa.ppa = 0;
- ppa.g.ch = rlun->bppa.g.ch;
- ppa.g.lun = rlun->bppa.g.lun;
-
- ret = nvm_get_tgt_bb_tbl(dev, ppa, blks);
- if (ret)
- return ret;
-
- nr_blks = nvm_bb_tbl_fold(dev->parent, blks, nr_blks);
- if (nr_blks < 0)
- return -EIO;
-
- return 0;
-}
-
-static void *pblk_bb_get_meta(struct pblk *pblk)
-{
- struct nvm_tgt_dev *dev = pblk->dev;
- struct nvm_geo *geo = &dev->geo;
- u8 *meta;
- int i, nr_blks, blk_per_lun;
- int ret;
-
- blk_per_lun = geo->num_chk * geo->pln_mode;
- nr_blks = blk_per_lun * geo->all_luns;
-
- meta = kmalloc(nr_blks, GFP_KERNEL);
- if (!meta)
- return ERR_PTR(-ENOMEM);
-
- for (i = 0; i < geo->all_luns; i++) {
- struct pblk_lun *rlun = &pblk->luns[i];
- u8 *meta_pos = meta + i * blk_per_lun;
-
- ret = pblk_bb_get_tbl(dev, rlun, meta_pos, blk_per_lun);
- if (ret) {
- kfree(meta);
- return ERR_PTR(-EIO);
- }
- }
-
- return meta;
-}
-
-static void *pblk_chunk_get_meta(struct pblk *pblk)
-{
- struct nvm_tgt_dev *dev = pblk->dev;
- struct nvm_geo *geo = &dev->geo;
-
- if (geo->version == NVM_OCSSD_SPEC_12)
- return pblk_bb_get_meta(pblk);
- else
- return pblk_chunk_get_info(pblk);
-}
-
static int pblk_luns_init(struct pblk *pblk)
{
struct nvm_tgt_dev *dev = pblk->dev;
@@ -699,51 +671,7 @@ static void pblk_set_provision(struct pblk *pblk, long nr_free_blks)
atomic_set(&pblk->rl.free_user_blocks, nr_free_blks);
}
-static int pblk_setup_line_meta_12(struct pblk *pblk, struct pblk_line *line,
- void *chunk_meta)
-{
- struct nvm_tgt_dev *dev = pblk->dev;
- struct nvm_geo *geo = &dev->geo;
- struct pblk_line_meta *lm = &pblk->lm;
- int i, chk_per_lun, nr_bad_chks = 0;
-
- chk_per_lun = geo->num_chk * geo->pln_mode;
-
- for (i = 0; i < lm->blk_per_line; i++) {
- struct pblk_lun *rlun = &pblk->luns[i];
- struct nvm_chk_meta *chunk;
- int pos = pblk_ppa_to_pos(geo, rlun->bppa);
- u8 *lun_bb_meta = chunk_meta + pos * chk_per_lun;
-
- chunk = &line->chks[pos];
-
- /*
- * In 1.2 spec. chunk state is not persisted by the device. Thus
- * some of the values are reset each time pblk is instantiated,
- * so we have to assume that the block is closed.
- */
- if (lun_bb_meta[line->id] == NVM_BLK_T_FREE)
- chunk->state = NVM_CHK_ST_CLOSED;
- else
- chunk->state = NVM_CHK_ST_OFFLINE;
-
- chunk->type = NVM_CHK_TP_W_SEQ;
- chunk->wi = 0;
- chunk->slba = -1;
- chunk->cnlb = geo->clba;
- chunk->wp = 0;
-
- if (!(chunk->state & NVM_CHK_ST_OFFLINE))
- continue;
-
- set_bit(pos, line->blk_bitmap);
- nr_bad_chks++;
- }
-
- return nr_bad_chks;
-}
-
-static int pblk_setup_line_meta_20(struct pblk *pblk, struct pblk_line *line,
+static int pblk_setup_line_meta_chk(struct pblk *pblk, struct pblk_line *line,
struct nvm_chk_meta *meta)
{
struct nvm_tgt_dev *dev = pblk->dev;
@@ -772,6 +700,9 @@ static int pblk_setup_line_meta_20(struct pblk *pblk, struct pblk_line *line,
chunk->cnlb = chunk_meta->cnlb;
chunk->wp = chunk_meta->wp;
+ trace_pblk_chunk_state(pblk_disk_name(pblk), &ppa,
+ chunk->state);
+
if (chunk->type & NVM_CHK_TP_SZ_SPEC) {
WARN_ONCE(1, "pblk: custom-sized chunks unsupported\n");
continue;
@@ -790,8 +721,6 @@ static int pblk_setup_line_meta_20(struct pblk *pblk, struct pblk_line *line,
static long pblk_setup_line_meta(struct pblk *pblk, struct pblk_line *line,
void *chunk_meta, int line_id)
{
- struct nvm_tgt_dev *dev = pblk->dev;
- struct nvm_geo *geo = &dev->geo;
struct pblk_line_mgmt *l_mg = &pblk->l_mg;
struct pblk_line_meta *lm = &pblk->lm;
long nr_bad_chks, chk_in_line;
@@ -804,10 +733,7 @@ static long pblk_setup_line_meta(struct pblk *pblk, struct pblk_line *line,
line->vsc = &l_mg->vsc_list[line_id];
spin_lock_init(&line->lock);
- if (geo->version == NVM_OCSSD_SPEC_12)
- nr_bad_chks = pblk_setup_line_meta_12(pblk, line, chunk_meta);
- else
- nr_bad_chks = pblk_setup_line_meta_20(pblk, line, chunk_meta);
+ nr_bad_chks = pblk_setup_line_meta_chk(pblk, line, chunk_meta);
chk_in_line = lm->blk_per_line - nr_bad_chks;
if (nr_bad_chks < 0 || nr_bad_chks > lm->blk_per_line ||
@@ -913,6 +839,17 @@ static int pblk_line_mg_init(struct pblk *pblk)
goto fail_free_smeta;
}
+ l_mg->bitmap_cache = kmem_cache_create("pblk_lm_bitmap",
+ lm->sec_bitmap_len, 0, 0, NULL);
+ if (!l_mg->bitmap_cache)
+ goto fail_free_smeta;
+
+ /* the bitmap pool is used for both valid and map bitmaps */
+ l_mg->bitmap_pool = mempool_create_slab_pool(PBLK_DATA_LINES * 2,
+ l_mg->bitmap_cache);
+ if (!l_mg->bitmap_pool)
+ goto fail_destroy_bitmap_cache;
+
/* emeta allocates three different buffers for managing metadata with
* in-memory and in-media layouts
*/
@@ -965,6 +902,10 @@ fail_free_emeta:
kfree(l_mg->eline_meta[i]->buf);
kfree(l_mg->eline_meta[i]);
}
+
+ mempool_destroy(l_mg->bitmap_pool);
+fail_destroy_bitmap_cache:
+ kmem_cache_destroy(l_mg->bitmap_cache);
fail_free_smeta:
for (i = 0; i < PBLK_DATA_LINES; i++)
kfree(l_mg->sline_meta[i]);
@@ -1058,7 +999,7 @@ static int pblk_lines_init(struct pblk *pblk)
if (ret)
goto fail_free_meta;
- chunk_meta = pblk_chunk_get_meta(pblk);
+ chunk_meta = pblk_get_chunk_meta(pblk);
if (IS_ERR(chunk_meta)) {
ret = PTR_ERR(chunk_meta);
goto fail_free_luns;
@@ -1079,16 +1020,20 @@ static int pblk_lines_init(struct pblk *pblk)
goto fail_free_lines;
nr_free_chks += pblk_setup_line_meta(pblk, line, chunk_meta, i);
+
+ trace_pblk_line_state(pblk_disk_name(pblk), line->id,
+ line->state);
}
if (!nr_free_chks) {
pblk_err(pblk, "too many bad blocks prevent for sane instance\n");
- return -EINTR;
+ ret = -EINTR;
+ goto fail_free_lines;
}
pblk_set_provision(pblk, nr_free_chks);
- kfree(chunk_meta);
+ vfree(chunk_meta);
return 0;
fail_free_lines:
@@ -1165,7 +1110,6 @@ static void pblk_exit(void *private, bool graceful)
{
struct pblk *pblk = private;
- down_write(&pblk_lock);
pblk_gc_exit(pblk, graceful);
pblk_tear_down(pblk, graceful);
@@ -1174,7 +1118,6 @@ static void pblk_exit(void *private, bool graceful)
#endif
pblk_free(pblk);
- up_write(&pblk_lock);
}
static sector_t pblk_capacity(void *private)
@@ -1200,6 +1143,7 @@ static void *pblk_init(struct nvm_tgt_dev *dev, struct gendisk *tdisk,
pblk->dev = dev;
pblk->disk = tdisk;
pblk->state = PBLK_STATE_RUNNING;
+ trace_pblk_state(pblk_disk_name(pblk), pblk->state);
pblk->gc.gc_enabled = 0;
if (!(geo->version == NVM_OCSSD_SPEC_12 ||
@@ -1210,13 +1154,6 @@ static void *pblk_init(struct nvm_tgt_dev *dev, struct gendisk *tdisk,
return ERR_PTR(-EINVAL);
}
- if (geo->version == NVM_OCSSD_SPEC_12 && geo->dom & NVM_RSP_L2P) {
- pblk_err(pblk, "host-side L2P table not supported. (%x)\n",
- geo->dom);
- kfree(pblk);
- return ERR_PTR(-EINVAL);
- }
-
spin_lock_init(&pblk->resubmit_lock);
spin_lock_init(&pblk->trans_lock);
spin_lock_init(&pblk->lock);
diff --git a/drivers/lightnvm/pblk-map.c b/drivers/lightnvm/pblk-map.c
index 953ca31dda68..6dcbd44e3acb 100644
--- a/drivers/lightnvm/pblk-map.c
+++ b/drivers/lightnvm/pblk-map.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2016 CNEX Labs
* Initial release: Javier Gonzalez <javier@cnexlabs.com>
@@ -79,7 +80,7 @@ static int pblk_map_page_data(struct pblk *pblk, unsigned int sentry,
}
}
- pblk_down_rq(pblk, ppa_list, nr_secs, lun_bitmap);
+ pblk_down_rq(pblk, ppa_list[0], lun_bitmap);
return 0;
}
@@ -88,13 +89,14 @@ void pblk_map_rq(struct pblk *pblk, struct nvm_rq *rqd, unsigned int sentry,
unsigned int off)
{
struct pblk_sec_meta *meta_list = rqd->meta_list;
+ struct ppa_addr *ppa_list = nvm_rq_to_ppa_list(rqd);
unsigned int map_secs;
int min = pblk->min_write_pgs;
int i;
for (i = off; i < rqd->nr_ppas; i += min) {
map_secs = (i + min > valid_secs) ? (valid_secs % min) : min;
- if (pblk_map_page_data(pblk, sentry + i, &rqd->ppa_list[i],
+ if (pblk_map_page_data(pblk, sentry + i, &ppa_list[i],
lun_bitmap, &meta_list[i], map_secs)) {
bio_put(rqd->bio);
pblk_free_rqd(pblk, rqd, PBLK_WRITE);
@@ -112,6 +114,7 @@ void pblk_map_erase_rq(struct pblk *pblk, struct nvm_rq *rqd,
struct nvm_geo *geo = &dev->geo;
struct pblk_line_meta *lm = &pblk->lm;
struct pblk_sec_meta *meta_list = rqd->meta_list;
+ struct ppa_addr *ppa_list = nvm_rq_to_ppa_list(rqd);
struct pblk_line *e_line, *d_line;
unsigned int map_secs;
int min = pblk->min_write_pgs;
@@ -119,14 +122,14 @@ void pblk_map_erase_rq(struct pblk *pblk, struct nvm_rq *rqd,
for (i = 0; i < rqd->nr_ppas; i += min) {
map_secs = (i + min > valid_secs) ? (valid_secs % min) : min;
- if (pblk_map_page_data(pblk, sentry + i, &rqd->ppa_list[i],
+ if (pblk_map_page_data(pblk, sentry + i, &ppa_list[i],
lun_bitmap, &meta_list[i], map_secs)) {
bio_put(rqd->bio);
pblk_free_rqd(pblk, rqd, PBLK_WRITE);
pblk_pipeline_stop(pblk);
}
- erase_lun = pblk_ppa_to_pos(geo, rqd->ppa_list[i]);
+ erase_lun = pblk_ppa_to_pos(geo, ppa_list[i]);
/* line can change after page map. We might also be writing the
* last line.
@@ -141,7 +144,7 @@ void pblk_map_erase_rq(struct pblk *pblk, struct nvm_rq *rqd,
set_bit(erase_lun, e_line->erase_bitmap);
atomic_dec(&e_line->left_eblks);
- *erase_ppa = rqd->ppa_list[i];
+ *erase_ppa = ppa_list[i];
erase_ppa->a.blk = e_line->id;
spin_unlock(&e_line->lock);
diff --git a/drivers/lightnvm/pblk-rb.c b/drivers/lightnvm/pblk-rb.c
index f6eec0212dfc..b1f4b51783f4 100644
--- a/drivers/lightnvm/pblk-rb.c
+++ b/drivers/lightnvm/pblk-rb.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2016 CNEX Labs
* Initial release: Javier Gonzalez <javier@cnexlabs.com>
@@ -22,7 +23,7 @@
static DECLARE_RWSEM(pblk_rb_lock);
-void pblk_rb_data_free(struct pblk_rb *rb)
+static void pblk_rb_data_free(struct pblk_rb *rb)
{
struct pblk_rb_pages *p, *t;
@@ -35,25 +36,51 @@ void pblk_rb_data_free(struct pblk_rb *rb)
up_write(&pblk_rb_lock);
}
+void pblk_rb_free(struct pblk_rb *rb)
+{
+ pblk_rb_data_free(rb);
+ vfree(rb->entries);
+}
+
+/*
+ * pblk_rb_calculate_size -- calculate the size of the write buffer
+ */
+static unsigned int pblk_rb_calculate_size(unsigned int nr_entries)
+{
+ /* Alloc a write buffer that can at least fit 128 entries */
+ return (1 << max(get_count_order(nr_entries), 7));
+}
+
/*
* Initialize ring buffer. The data and metadata buffers must be previously
* allocated and their size must be a power of two
* (Documentation/core-api/circular-buffers.rst)
*/
-int pblk_rb_init(struct pblk_rb *rb, struct pblk_rb_entry *rb_entry_base,
- unsigned int power_size, unsigned int power_seg_sz)
+int pblk_rb_init(struct pblk_rb *rb, unsigned int size, unsigned int threshold,
+ unsigned int seg_size)
{
struct pblk *pblk = container_of(rb, struct pblk, rwb);
+ struct pblk_rb_entry *entries;
unsigned int init_entry = 0;
- unsigned int alloc_order = power_size;
unsigned int max_order = MAX_ORDER - 1;
- unsigned int order, iter;
+ unsigned int power_size, power_seg_sz;
+ unsigned int alloc_order, order, iter;
+ unsigned int nr_entries;
+
+ nr_entries = pblk_rb_calculate_size(size);
+ entries = vzalloc(array_size(nr_entries, sizeof(struct pblk_rb_entry)));
+ if (!entries)
+ return -ENOMEM;
+
+ power_size = get_count_order(size);
+ power_seg_sz = get_count_order(seg_size);
down_write(&pblk_rb_lock);
- rb->entries = rb_entry_base;
+ rb->entries = entries;
rb->seg_size = (1 << power_seg_sz);
rb->nr_entries = (1 << power_size);
rb->mem = rb->subm = rb->sync = rb->l2p_update = 0;
+ rb->back_thres = threshold;
rb->flush_point = EMPTY_ENTRY;
spin_lock_init(&rb->w_lock);
@@ -61,6 +88,7 @@ int pblk_rb_init(struct pblk_rb *rb, struct pblk_rb_entry *rb_entry_base,
INIT_LIST_HEAD(&rb->pages);
+ alloc_order = power_size;
if (alloc_order >= max_order) {
order = max_order;
iter = (1 << (alloc_order - max_order));
@@ -79,6 +107,7 @@ int pblk_rb_init(struct pblk_rb *rb, struct pblk_rb_entry *rb_entry_base,
page_set = kmalloc(sizeof(struct pblk_rb_pages), GFP_KERNEL);
if (!page_set) {
up_write(&pblk_rb_lock);
+ vfree(entries);
return -ENOMEM;
}
@@ -88,6 +117,7 @@ int pblk_rb_init(struct pblk_rb *rb, struct pblk_rb_entry *rb_entry_base,
kfree(page_set);
pblk_rb_data_free(rb);
up_write(&pblk_rb_lock);
+ vfree(entries);
return -ENOMEM;
}
kaddr = page_address(page_set->pages);
@@ -124,20 +154,6 @@ int pblk_rb_init(struct pblk_rb *rb, struct pblk_rb_entry *rb_entry_base,
return 0;
}
-/*
- * pblk_rb_calculate_size -- calculate the size of the write buffer
- */
-unsigned int pblk_rb_calculate_size(unsigned int nr_entries)
-{
- /* Alloc a write buffer that can at least fit 128 entries */
- return (1 << max(get_count_order(nr_entries), 7));
-}
-
-void *pblk_rb_entries_ref(struct pblk_rb *rb)
-{
- return rb->entries;
-}
-
static void clean_wctx(struct pblk_w_ctx *w_ctx)
{
int flags;
@@ -168,6 +184,12 @@ static unsigned int pblk_rb_space(struct pblk_rb *rb)
return pblk_rb_ring_space(rb, mem, sync, rb->nr_entries);
}
+unsigned int pblk_rb_ptr_wrap(struct pblk_rb *rb, unsigned int p,
+ unsigned int nr_entries)
+{
+ return (p + nr_entries) & (rb->nr_entries - 1);
+}
+
/*
* Buffer count is calculated with respect to the submission entry signaling the
* entries that are available to send to the media
@@ -194,8 +216,7 @@ unsigned int pblk_rb_read_commit(struct pblk_rb *rb, unsigned int nr_entries)
subm = READ_ONCE(rb->subm);
/* Commit read means updating submission pointer */
- smp_store_release(&rb->subm,
- (subm + nr_entries) & (rb->nr_entries - 1));
+ smp_store_release(&rb->subm, pblk_rb_ptr_wrap(rb, subm, nr_entries));
return subm;
}
@@ -225,10 +246,10 @@ static int __pblk_rb_update_l2p(struct pblk_rb *rb, unsigned int to_update)
pblk_update_map_dev(pblk, w_ctx->lba, w_ctx->ppa,
entry->cacheline);
- line = &pblk->lines[pblk_ppa_to_line(w_ctx->ppa)];
+ line = pblk_ppa_to_line(pblk, w_ctx->ppa);
kref_put(&line->ref, pblk_line_put);
clean_wctx(w_ctx);
- rb->l2p_update = (rb->l2p_update + 1) & (rb->nr_entries - 1);
+ rb->l2p_update = pblk_rb_ptr_wrap(rb, rb->l2p_update, 1);
}
pblk_rl_out(&pblk->rl, user_io, gc_io);
@@ -385,11 +406,14 @@ static int __pblk_rb_may_write(struct pblk_rb *rb, unsigned int nr_entries,
{
unsigned int mem;
unsigned int sync;
+ unsigned int threshold;
sync = READ_ONCE(rb->sync);
mem = READ_ONCE(rb->mem);
- if (pblk_rb_ring_space(rb, mem, sync, rb->nr_entries) < nr_entries)
+ threshold = nr_entries + rb->back_thres;
+
+ if (pblk_rb_ring_space(rb, mem, sync, rb->nr_entries) < threshold)
return 0;
if (pblk_rb_update_l2p(rb, nr_entries, mem, sync))
@@ -407,7 +431,7 @@ static int pblk_rb_may_write(struct pblk_rb *rb, unsigned int nr_entries,
return 0;
/* Protect from read count */
- smp_store_release(&rb->mem, (*pos + nr_entries) & (rb->nr_entries - 1));
+ smp_store_release(&rb->mem, pblk_rb_ptr_wrap(rb, *pos, nr_entries));
return 1;
}
@@ -431,7 +455,7 @@ static int pblk_rb_may_write_flush(struct pblk_rb *rb, unsigned int nr_entries,
if (!__pblk_rb_may_write(rb, nr_entries, pos))
return 0;
- mem = (*pos + nr_entries) & (rb->nr_entries - 1);
+ mem = pblk_rb_ptr_wrap(rb, *pos, nr_entries);
*io_ret = NVM_IO_DONE;
if (bio->bi_opf & REQ_PREFLUSH) {
@@ -571,7 +595,7 @@ try:
/* Release flags on context. Protect from writes */
smp_store_release(&entry->w_ctx.flags, flags);
- pos = (pos + 1) & (rb->nr_entries - 1);
+ pos = pblk_rb_ptr_wrap(rb, pos, 1);
}
if (pad) {
@@ -651,7 +675,7 @@ out:
struct pblk_w_ctx *pblk_rb_w_ctx(struct pblk_rb *rb, unsigned int pos)
{
- unsigned int entry = pos & (rb->nr_entries - 1);
+ unsigned int entry = pblk_rb_ptr_wrap(rb, pos, 0);
return &rb->entries[entry].w_ctx;
}
@@ -697,7 +721,7 @@ unsigned int pblk_rb_sync_advance(struct pblk_rb *rb, unsigned int nr_entries)
}
}
- sync = (sync + nr_entries) & (rb->nr_entries - 1);
+ sync = pblk_rb_ptr_wrap(rb, sync, nr_entries);
/* Protect from counts */
smp_store_release(&rb->sync, sync);
@@ -728,32 +752,6 @@ unsigned int pblk_rb_flush_point_count(struct pblk_rb *rb)
return (submitted < to_flush) ? (to_flush - submitted) : 0;
}
-/*
- * Scan from the current position of the sync pointer to find the entry that
- * corresponds to the given ppa. This is necessary since write requests can be
- * completed out of order. The assumption is that the ppa is close to the sync
- * pointer thus the search will not take long.
- *
- * The caller of this function must guarantee that the sync pointer will no
- * reach the entry while it is using the metadata associated with it. With this
- * assumption in mind, there is no need to take the sync lock.
- */
-struct pblk_rb_entry *pblk_rb_sync_scan_entry(struct pblk_rb *rb,
- struct ppa_addr *ppa)
-{
- unsigned int sync, subm, count;
- unsigned int i;
-
- sync = READ_ONCE(rb->sync);
- subm = READ_ONCE(rb->subm);
- count = pblk_rb_ring_count(subm, sync, rb->nr_entries);
-
- for (i = 0; i < count; i++)
- sync = (sync + 1) & (rb->nr_entries - 1);
-
- return NULL;
-}
-
int pblk_rb_tear_down_check(struct pblk_rb *rb)
{
struct pblk_rb_entry *entry;
diff --git a/drivers/lightnvm/pblk-read.c b/drivers/lightnvm/pblk-read.c
index 5a46d7f9302f..9fba614adeeb 100644
--- a/drivers/lightnvm/pblk-read.c
+++ b/drivers/lightnvm/pblk-read.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2016 CNEX Labs
* Initial release: Javier Gonzalez <javier@cnexlabs.com>
@@ -43,7 +44,7 @@ static void pblk_read_ppalist_rq(struct pblk *pblk, struct nvm_rq *rqd,
unsigned long *read_bitmap)
{
struct pblk_sec_meta *meta_list = rqd->meta_list;
- struct ppa_addr ppas[PBLK_MAX_REQ_ADDRS];
+ struct ppa_addr ppas[NVM_MAX_VLBA];
int nr_secs = rqd->nr_ppas;
bool advanced_bio = false;
int i, j = 0;
@@ -93,9 +94,7 @@ next:
}
if (pblk_io_aligned(pblk, nr_secs))
- rqd->flags = pblk_set_read_mode(pblk, PBLK_READ_SEQUENTIAL);
- else
- rqd->flags = pblk_set_read_mode(pblk, PBLK_READ_RANDOM);
+ rqd->is_seq = 1;
#ifdef CONFIG_NVM_PBLK_DEBUG
atomic_long_add(nr_secs, &pblk->inflight_reads);
@@ -118,10 +117,9 @@ static void pblk_read_check_seq(struct pblk *pblk, struct nvm_rq *rqd,
if (lba != blba + i) {
#ifdef CONFIG_NVM_PBLK_DEBUG
- struct ppa_addr *p;
+ struct ppa_addr *ppa_list = nvm_rq_to_ppa_list(rqd);
- p = (nr_lbas == 1) ? &rqd->ppa_list[i] : &rqd->ppa_addr;
- print_ppa(pblk, p, "seq", i);
+ print_ppa(pblk, &ppa_list[i], "seq", i);
#endif
pblk_err(pblk, "corrupted read LBA (%llu/%llu)\n",
lba, (u64)blba + i);
@@ -150,14 +148,12 @@ static void pblk_read_check_rand(struct pblk *pblk, struct nvm_rq *rqd,
if (lba != meta_lba) {
#ifdef CONFIG_NVM_PBLK_DEBUG
- struct ppa_addr *p;
- int nr_ppas = rqd->nr_ppas;
+ struct ppa_addr *ppa_list = nvm_rq_to_ppa_list(rqd);
- p = (nr_ppas == 1) ? &rqd->ppa_list[j] : &rqd->ppa_addr;
- print_ppa(pblk, p, "seq", j);
+ print_ppa(pblk, &ppa_list[j], "rnd", j);
#endif
pblk_err(pblk, "corrupted read LBA (%llu/%llu)\n",
- lba, meta_lba);
+ meta_lba, lba);
WARN_ON(1);
}
@@ -167,22 +163,6 @@ static void pblk_read_check_rand(struct pblk *pblk, struct nvm_rq *rqd,
WARN_ONCE(j != rqd->nr_ppas, "pblk: corrupted random request\n");
}
-static void pblk_read_put_rqd_kref(struct pblk *pblk, struct nvm_rq *rqd)
-{
- struct ppa_addr *ppa_list;
- int i;
-
- ppa_list = (rqd->nr_ppas > 1) ? rqd->ppa_list : &rqd->ppa_addr;
-
- for (i = 0; i < rqd->nr_ppas; i++) {
- struct ppa_addr ppa = ppa_list[i];
- struct pblk_line *line;
-
- line = &pblk->lines[pblk_ppa_to_line(ppa)];
- kref_put(&line->ref, pblk_line_put_wq);
- }
-}
-
static void pblk_end_user_read(struct bio *bio)
{
#ifdef CONFIG_NVM_PBLK_DEBUG
@@ -210,7 +190,7 @@ static void __pblk_end_io_read(struct pblk *pblk, struct nvm_rq *rqd,
bio_put(int_bio);
if (put_line)
- pblk_read_put_rqd_kref(pblk, rqd);
+ pblk_rq_to_line_put(pblk, rqd);
#ifdef CONFIG_NVM_PBLK_DEBUG
atomic_long_add(rqd->nr_ppas, &pblk->sync_reads);
@@ -270,9 +250,9 @@ static void pblk_end_partial_read(struct nvm_rq *rqd)
i = 0;
hole = find_first_zero_bit(read_bitmap, nr_secs);
do {
- int line_id = pblk_ppa_to_line(rqd->ppa_list[i]);
- struct pblk_line *line = &pblk->lines[line_id];
+ struct pblk_line *line;
+ line = pblk_ppa_to_line(pblk, rqd->ppa_list[i]);
kref_put(&line->ref, pblk_line_put);
meta_list[hole].lba = lba_list_media[i];
@@ -344,7 +324,6 @@ static int pblk_setup_partial_read(struct pblk *pblk, struct nvm_rq *rqd,
rqd->bio = new_bio;
rqd->nr_ppas = nr_holes;
- rqd->flags = pblk_set_read_mode(pblk, PBLK_READ_RANDOM);
pr_ctx->ppa_ptr = NULL;
pr_ctx->orig_bio = bio;
@@ -438,8 +417,6 @@ retry:
} else {
rqd->ppa_addr = ppa;
}
-
- rqd->flags = pblk_set_read_mode(pblk, PBLK_READ_RANDOM);
}
int pblk_submit_read(struct pblk *pblk, struct bio *bio)
@@ -454,13 +431,6 @@ int pblk_submit_read(struct pblk *pblk, struct bio *bio)
DECLARE_BITMAP(read_bitmap, NVM_MAX_VLBA);
int ret = NVM_IO_ERR;
- /* logic error: lba out-of-bounds. Ignore read request */
- if (blba >= pblk->rl.nr_secs || nr_secs > PBLK_MAX_REQ_ADDRS) {
- WARN(1, "pblk: read lba out of bounds (lba:%llu, nr:%d)\n",
- (unsigned long long)blba, nr_secs);
- return NVM_IO_ERR;
- }
-
generic_start_io_acct(q, REQ_OP_READ, bio_sectors(bio),
&pblk->disk->part0);
@@ -484,21 +454,13 @@ int pblk_submit_read(struct pblk *pblk, struct bio *bio)
*/
bio_init_idx = pblk_get_bi_idx(bio);
- rqd->meta_list = nvm_dev_dma_alloc(dev->parent, GFP_KERNEL,
- &rqd->dma_meta_list);
- if (!rqd->meta_list) {
- pblk_err(pblk, "not able to allocate ppa list\n");
+ if (pblk_alloc_rqd_meta(pblk, rqd))
goto fail_rqd_free;
- }
-
- if (nr_secs > 1) {
- rqd->ppa_list = rqd->meta_list + pblk_dma_meta_size;
- rqd->dma_ppa_list = rqd->dma_meta_list + pblk_dma_meta_size;
+ if (nr_secs > 1)
pblk_read_ppalist_rq(pblk, rqd, bio, blba, read_bitmap);
- } else {
+ else
pblk_read_rq(pblk, rqd, bio, blba, read_bitmap);
- }
if (bitmap_full(read_bitmap, nr_secs)) {
atomic_inc(&pblk->inflight_io);
@@ -552,7 +514,7 @@ static int read_ppalist_rq_gc(struct pblk *pblk, struct nvm_rq *rqd,
struct pblk_line *line, u64 *lba_list,
u64 *paddr_list_gc, unsigned int nr_secs)
{
- struct ppa_addr ppa_list_l2p[PBLK_MAX_REQ_ADDRS];
+ struct ppa_addr ppa_list_l2p[NVM_MAX_VLBA];
struct ppa_addr ppa_gc;
int valid_secs = 0;
int i;
@@ -625,15 +587,11 @@ int pblk_submit_read_gc(struct pblk *pblk, struct pblk_gc_rq *gc_rq)
memset(&rqd, 0, sizeof(struct nvm_rq));
- rqd.meta_list = nvm_dev_dma_alloc(dev->parent, GFP_KERNEL,
- &rqd.dma_meta_list);
- if (!rqd.meta_list)
- return -ENOMEM;
+ ret = pblk_alloc_rqd_meta(pblk, &rqd);
+ if (ret)
+ return ret;
if (gc_rq->nr_secs > 1) {
- rqd.ppa_list = rqd.meta_list + pblk_dma_meta_size;
- rqd.dma_ppa_list = rqd.dma_meta_list + pblk_dma_meta_size;
-
gc_rq->secs_to_gc = read_ppalist_rq_gc(pblk, &rqd, gc_rq->line,
gc_rq->lba_list,
gc_rq->paddr_list,
@@ -654,7 +612,8 @@ int pblk_submit_read_gc(struct pblk *pblk, struct pblk_gc_rq *gc_rq)
PBLK_VMALLOC_META, GFP_KERNEL);
if (IS_ERR(bio)) {
pblk_err(pblk, "could not allocate GC bio (%lu)\n",
- PTR_ERR(bio));
+ PTR_ERR(bio));
+ ret = PTR_ERR(bio);
goto err_free_dma;
}
@@ -663,7 +622,6 @@ int pblk_submit_read_gc(struct pblk *pblk, struct pblk_gc_rq *gc_rq)
rqd.opcode = NVM_OP_PREAD;
rqd.nr_ppas = gc_rq->secs_to_gc;
- rqd.flags = pblk_set_read_mode(pblk, PBLK_READ_RANDOM);
rqd.bio = bio;
if (pblk_submit_io_sync(pblk, &rqd)) {
@@ -690,12 +648,12 @@ int pblk_submit_read_gc(struct pblk *pblk, struct pblk_gc_rq *gc_rq)
#endif
out:
- nvm_dev_dma_free(dev->parent, rqd.meta_list, rqd.dma_meta_list);
+ pblk_free_rqd_meta(pblk, &rqd);
return ret;
err_free_bio:
bio_put(bio);
err_free_dma:
- nvm_dev_dma_free(dev->parent, rqd.meta_list, rqd.dma_meta_list);
+ pblk_free_rqd_meta(pblk, &rqd);
return ret;
}
diff --git a/drivers/lightnvm/pblk-recovery.c b/drivers/lightnvm/pblk-recovery.c
index e232e47e1353..5740b7509bd8 100644
--- a/drivers/lightnvm/pblk-recovery.c
+++ b/drivers/lightnvm/pblk-recovery.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2016 CNEX Labs
* Initial: Javier Gonzalez <javier@cnexlabs.com>
@@ -15,6 +16,7 @@
*/
#include "pblk.h"
+#include "pblk-trace.h"
int pblk_recov_check_emeta(struct pblk *pblk, struct line_emeta *emeta_buf)
{
@@ -85,15 +87,39 @@ static int pblk_recov_l2p_from_emeta(struct pblk *pblk, struct pblk_line *line)
return 0;
}
-static int pblk_calc_sec_in_line(struct pblk *pblk, struct pblk_line *line)
+static void pblk_update_line_wp(struct pblk *pblk, struct pblk_line *line,
+ u64 written_secs)
+{
+ int i;
+
+ for (i = 0; i < written_secs; i += pblk->min_write_pgs)
+ pblk_alloc_page(pblk, line, pblk->min_write_pgs);
+}
+
+static u64 pblk_sec_in_open_line(struct pblk *pblk, struct pblk_line *line)
{
- struct nvm_tgt_dev *dev = pblk->dev;
- struct nvm_geo *geo = &dev->geo;
struct pblk_line_meta *lm = &pblk->lm;
int nr_bb = bitmap_weight(line->blk_bitmap, lm->blk_per_line);
+ u64 written_secs = 0;
+ int valid_chunks = 0;
+ int i;
+
+ for (i = 0; i < lm->blk_per_line; i++) {
+ struct nvm_chk_meta *chunk = &line->chks[i];
+
+ if (chunk->state & NVM_CHK_ST_OFFLINE)
+ continue;
+
+ written_secs += chunk->wp;
+ valid_chunks++;
+ }
+
+ if (lm->blk_per_line - nr_bb != valid_chunks)
+ pblk_err(pblk, "recovery line %d is bad\n", line->id);
- return lm->sec_per_line - lm->smeta_sec - lm->emeta_sec[0] -
- nr_bb * geo->clba;
+ pblk_update_line_wp(pblk, line, written_secs - lm->smeta_sec);
+
+ return written_secs;
}
struct pblk_recov_alloc {
@@ -105,115 +131,6 @@ struct pblk_recov_alloc {
dma_addr_t dma_meta_list;
};
-static int pblk_recov_read_oob(struct pblk *pblk, struct pblk_line *line,
- struct pblk_recov_alloc p, u64 r_ptr)
-{
- struct nvm_tgt_dev *dev = pblk->dev;
- struct nvm_geo *geo = &dev->geo;
- struct ppa_addr *ppa_list;
- struct pblk_sec_meta *meta_list;
- struct nvm_rq *rqd;
- struct bio *bio;
- void *data;
- dma_addr_t dma_ppa_list, dma_meta_list;
- u64 r_ptr_int;
- int left_ppas;
- int rq_ppas, rq_len;
- int i, j;
- int ret = 0;
-
- ppa_list = p.ppa_list;
- meta_list = p.meta_list;
- rqd = p.rqd;
- data = p.data;
- dma_ppa_list = p.dma_ppa_list;
- dma_meta_list = p.dma_meta_list;
-
- left_ppas = line->cur_sec - r_ptr;
- if (!left_ppas)
- return 0;
-
- r_ptr_int = r_ptr;
-
-next_read_rq:
- memset(rqd, 0, pblk_g_rq_size);
-
- rq_ppas = pblk_calc_secs(pblk, left_ppas, 0);
- if (!rq_ppas)
- rq_ppas = pblk->min_write_pgs;
- rq_len = rq_ppas * geo->csecs;
-
- bio = bio_map_kern(dev->q, data, rq_len, GFP_KERNEL);
- if (IS_ERR(bio))
- return PTR_ERR(bio);
-
- bio->bi_iter.bi_sector = 0; /* internal bio */
- bio_set_op_attrs(bio, REQ_OP_READ, 0);
-
- rqd->bio = bio;
- rqd->opcode = NVM_OP_PREAD;
- rqd->meta_list = meta_list;
- rqd->nr_ppas = rq_ppas;
- rqd->ppa_list = ppa_list;
- rqd->dma_ppa_list = dma_ppa_list;
- rqd->dma_meta_list = dma_meta_list;
-
- if (pblk_io_aligned(pblk, rq_ppas))
- rqd->flags = pblk_set_read_mode(pblk, PBLK_READ_SEQUENTIAL);
- else
- rqd->flags = pblk_set_read_mode(pblk, PBLK_READ_RANDOM);
-
- for (i = 0; i < rqd->nr_ppas; ) {
- struct ppa_addr ppa;
- int pos;
-
- ppa = addr_to_gen_ppa(pblk, r_ptr_int, line->id);
- pos = pblk_ppa_to_pos(geo, ppa);
-
- while (test_bit(pos, line->blk_bitmap)) {
- r_ptr_int += pblk->min_write_pgs;
- ppa = addr_to_gen_ppa(pblk, r_ptr_int, line->id);
- pos = pblk_ppa_to_pos(geo, ppa);
- }
-
- for (j = 0; j < pblk->min_write_pgs; j++, i++, r_ptr_int++)
- rqd->ppa_list[i] =
- addr_to_gen_ppa(pblk, r_ptr_int, line->id);
- }
-
- /* If read fails, more padding is needed */
- ret = pblk_submit_io_sync(pblk, rqd);
- if (ret) {
- pblk_err(pblk, "I/O submission failed: %d\n", ret);
- return ret;
- }
-
- atomic_dec(&pblk->inflight_io);
-
- /* At this point, the read should not fail. If it does, it is a problem
- * we cannot recover from here. Need FTL log.
- */
- if (rqd->error && rqd->error != NVM_RSP_WARN_HIGHECC) {
- pblk_err(pblk, "L2P recovery failed (%d)\n", rqd->error);
- return -EINTR;
- }
-
- for (i = 0; i < rqd->nr_ppas; i++) {
- u64 lba = le64_to_cpu(meta_list[i].lba);
-
- if (lba == ADDR_EMPTY || lba > pblk->rl.nr_secs)
- continue;
-
- pblk_update_map(pblk, lba, rqd->ppa_list[i]);
- }
-
- left_ppas -= rq_ppas;
- if (left_ppas > 0)
- goto next_read_rq;
-
- return 0;
-}
-
static void pblk_recov_complete(struct kref *ref)
{
struct pblk_pad_rq *pad_rq = container_of(ref, struct pblk_pad_rq, ref);
@@ -223,10 +140,11 @@ static void pblk_recov_complete(struct kref *ref)
static void pblk_end_io_recov(struct nvm_rq *rqd)
{
+ struct ppa_addr *ppa_list = nvm_rq_to_ppa_list(rqd);
struct pblk_pad_rq *pad_rq = rqd->private;
struct pblk *pblk = pad_rq->pblk;
- pblk_up_page(pblk, rqd->ppa_list, rqd->nr_ppas);
+ pblk_up_chunk(pblk, ppa_list[0]);
pblk_free_rqd(pblk, rqd, PBLK_WRITE_INT);
@@ -234,18 +152,17 @@ static void pblk_end_io_recov(struct nvm_rq *rqd)
kref_put(&pad_rq->ref, pblk_recov_complete);
}
-static int pblk_recov_pad_oob(struct pblk *pblk, struct pblk_line *line,
- int left_ppas)
+/* pad line using line bitmap. */
+static int pblk_recov_pad_line(struct pblk *pblk, struct pblk_line *line,
+ int left_ppas)
{
struct nvm_tgt_dev *dev = pblk->dev;
struct nvm_geo *geo = &dev->geo;
- struct ppa_addr *ppa_list;
struct pblk_sec_meta *meta_list;
struct pblk_pad_rq *pad_rq;
struct nvm_rq *rqd;
struct bio *bio;
void *data;
- dma_addr_t dma_ppa_list, dma_meta_list;
__le64 *lba_list = emeta_to_lbas(pblk, line->emeta->buf);
u64 w_ptr = line->cur_sec;
int left_line_ppas, rq_ppas, rq_len;
@@ -279,20 +196,11 @@ next_pad_rq:
rq_len = rq_ppas * geo->csecs;
- meta_list = nvm_dev_dma_alloc(dev->parent, GFP_KERNEL, &dma_meta_list);
- if (!meta_list) {
- ret = -ENOMEM;
- goto fail_free_pad;
- }
-
- ppa_list = (void *)(meta_list) + pblk_dma_meta_size;
- dma_ppa_list = dma_meta_list + pblk_dma_meta_size;
-
bio = pblk_bio_map_addr(pblk, data, rq_ppas, rq_len,
PBLK_VMALLOC_META, GFP_KERNEL);
if (IS_ERR(bio)) {
ret = PTR_ERR(bio);
- goto fail_free_meta;
+ goto fail_free_pad;
}
bio->bi_iter.bi_sector = 0; /* internal bio */
@@ -300,17 +208,19 @@ next_pad_rq:
rqd = pblk_alloc_rqd(pblk, PBLK_WRITE_INT);
+ ret = pblk_alloc_rqd_meta(pblk, rqd);
+ if (ret)
+ goto fail_free_rqd;
+
rqd->bio = bio;
rqd->opcode = NVM_OP_PWRITE;
- rqd->flags = pblk_set_progr_mode(pblk, PBLK_WRITE);
- rqd->meta_list = meta_list;
+ rqd->is_seq = 1;
rqd->nr_ppas = rq_ppas;
- rqd->ppa_list = ppa_list;
- rqd->dma_ppa_list = dma_ppa_list;
- rqd->dma_meta_list = dma_meta_list;
rqd->end_io = pblk_end_io_recov;
rqd->private = pad_rq;
+ meta_list = rqd->meta_list;
+
for (i = 0; i < rqd->nr_ppas; ) {
struct ppa_addr ppa;
int pos;
@@ -338,13 +248,13 @@ next_pad_rq:
}
kref_get(&pad_rq->ref);
- pblk_down_page(pblk, rqd->ppa_list, rqd->nr_ppas);
+ pblk_down_chunk(pblk, rqd->ppa_list[0]);
ret = pblk_submit_io(pblk, rqd);
if (ret) {
pblk_err(pblk, "I/O submission failed: %d\n", ret);
- pblk_up_page(pblk, rqd->ppa_list, rqd->nr_ppas);
- goto fail_free_bio;
+ pblk_up_chunk(pblk, rqd->ppa_list[0]);
+ goto fail_free_rqd;
}
left_line_ppas -= rq_ppas;
@@ -368,157 +278,60 @@ free_rq:
kfree(pad_rq);
return ret;
-fail_free_bio:
+fail_free_rqd:
+ pblk_free_rqd(pblk, rqd, PBLK_WRITE_INT);
bio_put(bio);
-fail_free_meta:
- nvm_dev_dma_free(dev->parent, meta_list, dma_meta_list);
fail_free_pad:
kfree(pad_rq);
vfree(data);
return ret;
}
-/* When this function is called, it means that not all upper pages have been
- * written in a page that contains valid data. In order to recover this data, we
- * first find the write pointer on the device, then we pad all necessary
- * sectors, and finally attempt to read the valid data
- */
-static int pblk_recov_scan_all_oob(struct pblk *pblk, struct pblk_line *line,
- struct pblk_recov_alloc p)
+static int pblk_pad_distance(struct pblk *pblk, struct pblk_line *line)
{
struct nvm_tgt_dev *dev = pblk->dev;
struct nvm_geo *geo = &dev->geo;
- struct ppa_addr *ppa_list;
- struct pblk_sec_meta *meta_list;
- struct nvm_rq *rqd;
- struct bio *bio;
- void *data;
- dma_addr_t dma_ppa_list, dma_meta_list;
- u64 w_ptr = 0, r_ptr;
- int rq_ppas, rq_len;
- int i, j;
- int ret = 0;
- int rec_round;
- int left_ppas = pblk_calc_sec_in_line(pblk, line) - line->cur_sec;
-
- ppa_list = p.ppa_list;
- meta_list = p.meta_list;
- rqd = p.rqd;
- data = p.data;
- dma_ppa_list = p.dma_ppa_list;
- dma_meta_list = p.dma_meta_list;
-
- /* we could recover up until the line write pointer */
- r_ptr = line->cur_sec;
- rec_round = 0;
-
-next_rq:
- memset(rqd, 0, pblk_g_rq_size);
+ int distance = geo->mw_cunits * geo->all_luns * geo->ws_opt;
- rq_ppas = pblk_calc_secs(pblk, left_ppas, 0);
- if (!rq_ppas)
- rq_ppas = pblk->min_write_pgs;
- rq_len = rq_ppas * geo->csecs;
-
- bio = bio_map_kern(dev->q, data, rq_len, GFP_KERNEL);
- if (IS_ERR(bio))
- return PTR_ERR(bio);
-
- bio->bi_iter.bi_sector = 0; /* internal bio */
- bio_set_op_attrs(bio, REQ_OP_READ, 0);
+ return (distance > line->left_msecs) ? line->left_msecs : distance;
+}
- rqd->bio = bio;
- rqd->opcode = NVM_OP_PREAD;
- rqd->meta_list = meta_list;
- rqd->nr_ppas = rq_ppas;
- rqd->ppa_list = ppa_list;
- rqd->dma_ppa_list = dma_ppa_list;
- rqd->dma_meta_list = dma_meta_list;
+static int pblk_line_wp_is_unbalanced(struct pblk *pblk,
+ struct pblk_line *line)
+{
+ struct nvm_tgt_dev *dev = pblk->dev;
+ struct nvm_geo *geo = &dev->geo;
+ struct pblk_line_meta *lm = &pblk->lm;
+ struct pblk_lun *rlun;
+ struct nvm_chk_meta *chunk;
+ struct ppa_addr ppa;
+ u64 line_wp;
+ int pos, i;
- if (pblk_io_aligned(pblk, rq_ppas))
- rqd->flags = pblk_set_read_mode(pblk, PBLK_READ_SEQUENTIAL);
- else
- rqd->flags = pblk_set_read_mode(pblk, PBLK_READ_RANDOM);
+ rlun = &pblk->luns[0];
+ ppa = rlun->bppa;
+ pos = pblk_ppa_to_pos(geo, ppa);
+ chunk = &line->chks[pos];
- for (i = 0; i < rqd->nr_ppas; ) {
- struct ppa_addr ppa;
- int pos;
+ line_wp = chunk->wp;
- w_ptr = pblk_alloc_page(pblk, line, pblk->min_write_pgs);
- ppa = addr_to_gen_ppa(pblk, w_ptr, line->id);
+ for (i = 1; i < lm->blk_per_line; i++) {
+ rlun = &pblk->luns[i];
+ ppa = rlun->bppa;
pos = pblk_ppa_to_pos(geo, ppa);
+ chunk = &line->chks[pos];
- while (test_bit(pos, line->blk_bitmap)) {
- w_ptr += pblk->min_write_pgs;
- ppa = addr_to_gen_ppa(pblk, w_ptr, line->id);
- pos = pblk_ppa_to_pos(geo, ppa);
- }
-
- for (j = 0; j < pblk->min_write_pgs; j++, i++, w_ptr++)
- rqd->ppa_list[i] =
- addr_to_gen_ppa(pblk, w_ptr, line->id);
- }
-
- ret = pblk_submit_io_sync(pblk, rqd);
- if (ret) {
- pblk_err(pblk, "I/O submission failed: %d\n", ret);
- return ret;
- }
-
- atomic_dec(&pblk->inflight_io);
-
- /* This should not happen since the read failed during normal recovery,
- * but the media works funny sometimes...
- */
- if (!rec_round++ && !rqd->error) {
- rec_round = 0;
- for (i = 0; i < rqd->nr_ppas; i++, r_ptr++) {
- u64 lba = le64_to_cpu(meta_list[i].lba);
-
- if (lba == ADDR_EMPTY || lba > pblk->rl.nr_secs)
- continue;
-
- pblk_update_map(pblk, lba, rqd->ppa_list[i]);
- }
- }
-
- /* Reached the end of the written line */
- if (rqd->error == NVM_RSP_ERR_EMPTYPAGE) {
- int pad_secs, nr_error_bits, bit;
- int ret;
-
- bit = find_first_bit((void *)&rqd->ppa_status, rqd->nr_ppas);
- nr_error_bits = rqd->nr_ppas - bit;
-
- /* Roll back failed sectors */
- line->cur_sec -= nr_error_bits;
- line->left_msecs += nr_error_bits;
- bitmap_clear(line->map_bitmap, line->cur_sec, nr_error_bits);
-
- pad_secs = pblk_pad_distance(pblk);
- if (pad_secs > line->left_msecs)
- pad_secs = line->left_msecs;
-
- ret = pblk_recov_pad_oob(pblk, line, pad_secs);
- if (ret)
- pblk_err(pblk, "OOB padding failed (err:%d)\n", ret);
-
- ret = pblk_recov_read_oob(pblk, line, p, r_ptr);
- if (ret)
- pblk_err(pblk, "OOB read failed (err:%d)\n", ret);
-
- left_ppas = 0;
+ if (chunk->wp > line_wp)
+ return 1;
+ else if (chunk->wp < line_wp)
+ line_wp = chunk->wp;
}
- left_ppas -= rq_ppas;
- if (left_ppas > 0)
- goto next_rq;
-
- return ret;
+ return 0;
}
static int pblk_recov_scan_oob(struct pblk *pblk, struct pblk_line *line,
- struct pblk_recov_alloc p, int *done)
+ struct pblk_recov_alloc p)
{
struct nvm_tgt_dev *dev = pblk->dev;
struct nvm_geo *geo = &dev->geo;
@@ -528,11 +341,16 @@ static int pblk_recov_scan_oob(struct pblk *pblk, struct pblk_line *line,
struct bio *bio;
void *data;
dma_addr_t dma_ppa_list, dma_meta_list;
- u64 paddr;
+ __le64 *lba_list;
+ u64 paddr = 0;
+ bool padded = false;
int rq_ppas, rq_len;
int i, j;
- int ret = 0;
- int left_ppas = pblk_calc_sec_in_line(pblk, line);
+ int ret;
+ u64 left_ppas = pblk_sec_in_open_line(pblk, line);
+
+ if (pblk_line_wp_is_unbalanced(pblk, line))
+ pblk_warn(pblk, "recovering unbalanced line (%d)\n", line->id);
ppa_list = p.ppa_list;
meta_list = p.meta_list;
@@ -541,7 +359,7 @@ static int pblk_recov_scan_oob(struct pblk *pblk, struct pblk_line *line,
dma_ppa_list = p.dma_ppa_list;
dma_meta_list = p.dma_meta_list;
- *done = 1;
+ lba_list = emeta_to_lbas(pblk, line->emeta->buf);
next_rq:
memset(rqd, 0, pblk_g_rq_size);
@@ -567,15 +385,13 @@ next_rq:
rqd->dma_meta_list = dma_meta_list;
if (pblk_io_aligned(pblk, rq_ppas))
- rqd->flags = pblk_set_read_mode(pblk, PBLK_READ_SEQUENTIAL);
- else
- rqd->flags = pblk_set_read_mode(pblk, PBLK_READ_RANDOM);
+ rqd->is_seq = 1;
+retry_rq:
for (i = 0; i < rqd->nr_ppas; ) {
struct ppa_addr ppa;
int pos;
- paddr = pblk_alloc_page(pblk, line, pblk->min_write_pgs);
ppa = addr_to_gen_ppa(pblk, paddr, line->id);
pos = pblk_ppa_to_pos(geo, ppa);
@@ -585,9 +401,9 @@ next_rq:
pos = pblk_ppa_to_pos(geo, ppa);
}
- for (j = 0; j < pblk->min_write_pgs; j++, i++, paddr++)
+ for (j = 0; j < pblk->min_write_pgs; j++, i++)
rqd->ppa_list[i] =
- addr_to_gen_ppa(pblk, paddr, line->id);
+ addr_to_gen_ppa(pblk, paddr + j, line->id);
}
ret = pblk_submit_io_sync(pblk, rqd);
@@ -599,31 +415,33 @@ next_rq:
atomic_dec(&pblk->inflight_io);
- /* Reached the end of the written line */
+ /* If a read fails, do a best effort by padding the line and retrying */
if (rqd->error) {
- int nr_error_bits, bit;
+ int pad_distance, ret;
- bit = find_first_bit((void *)&rqd->ppa_status, rqd->nr_ppas);
- nr_error_bits = rqd->nr_ppas - bit;
-
- /* Roll back failed sectors */
- line->cur_sec -= nr_error_bits;
- line->left_msecs += nr_error_bits;
- bitmap_clear(line->map_bitmap, line->cur_sec, nr_error_bits);
+ if (padded) {
+ pblk_log_read_err(pblk, rqd);
+ return -EINTR;
+ }
- left_ppas = 0;
- rqd->nr_ppas = bit;
+ pad_distance = pblk_pad_distance(pblk, line);
+ ret = pblk_recov_pad_line(pblk, line, pad_distance);
+ if (ret)
+ return ret;
- if (rqd->error != NVM_RSP_ERR_EMPTYPAGE)
- *done = 0;
+ padded = true;
+ goto retry_rq;
}
for (i = 0; i < rqd->nr_ppas; i++) {
u64 lba = le64_to_cpu(meta_list[i].lba);
+ lba_list[paddr++] = cpu_to_le64(lba);
+
if (lba == ADDR_EMPTY || lba > pblk->rl.nr_secs)
continue;
+ line->nr_valid_lbas++;
pblk_update_map(pblk, lba, rqd->ppa_list[i]);
}
@@ -631,7 +449,11 @@ next_rq:
if (left_ppas > 0)
goto next_rq;
- return ret;
+#ifdef CONFIG_NVM_PBLK_DEBUG
+ WARN_ON(padded && !pblk_line_is_full(line));
+#endif
+
+ return 0;
}
/* Scan line for lbas on out of bound area */
@@ -645,7 +467,7 @@ static int pblk_recov_l2p_from_oob(struct pblk *pblk, struct pblk_line *line)
struct pblk_recov_alloc p;
void *data;
dma_addr_t dma_ppa_list, dma_meta_list;
- int done, ret = 0;
+ int ret = 0;
meta_list = nvm_dev_dma_alloc(dev->parent, GFP_KERNEL, &dma_meta_list);
if (!meta_list)
@@ -660,7 +482,8 @@ static int pblk_recov_l2p_from_oob(struct pblk *pblk, struct pblk_line *line)
goto free_meta_list;
}
- rqd = pblk_alloc_rqd(pblk, PBLK_READ);
+ rqd = mempool_alloc(&pblk->r_rq_pool, GFP_KERNEL);
+ memset(rqd, 0, pblk_g_rq_size);
p.ppa_list = ppa_list;
p.meta_list = meta_list;
@@ -669,24 +492,17 @@ static int pblk_recov_l2p_from_oob(struct pblk *pblk, struct pblk_line *line)
p.dma_ppa_list = dma_ppa_list;
p.dma_meta_list = dma_meta_list;
- ret = pblk_recov_scan_oob(pblk, line, p, &done);
+ ret = pblk_recov_scan_oob(pblk, line, p);
if (ret) {
- pblk_err(pblk, "could not recover L2P from OOB\n");
+ pblk_err(pblk, "could not recover L2P form OOB\n");
goto out;
}
- if (!done) {
- ret = pblk_recov_scan_all_oob(pblk, line, p);
- if (ret) {
- pblk_err(pblk, "could not recover L2P from OOB\n");
- goto out;
- }
- }
-
if (pblk_line_is_full(line))
pblk_line_recov_close(pblk, line);
out:
+ mempool_free(rqd, &pblk->r_rq_pool);
kfree(data);
free_meta_list:
nvm_dev_dma_free(dev->parent, meta_list, dma_meta_list);
@@ -775,7 +591,7 @@ static void pblk_recov_wa_counters(struct pblk *pblk,
}
static int pblk_line_was_written(struct pblk_line *line,
- struct pblk *pblk)
+ struct pblk *pblk)
{
struct pblk_line_meta *lm = &pblk->lm;
@@ -801,6 +617,18 @@ static int pblk_line_was_written(struct pblk_line *line,
return 1;
}
+static bool pblk_line_is_open(struct pblk *pblk, struct pblk_line *line)
+{
+ struct pblk_line_meta *lm = &pblk->lm;
+ int i;
+
+ for (i = 0; i < lm->blk_per_line; i++)
+ if (line->chks[i].state & NVM_CHK_ST_OPEN)
+ return true;
+
+ return false;
+}
+
struct pblk_line *pblk_recov_l2p(struct pblk *pblk)
{
struct pblk_line_meta *lm = &pblk->lm;
@@ -841,7 +669,7 @@ struct pblk_line *pblk_recov_l2p(struct pblk *pblk)
continue;
/* Lines that cannot be read are assumed as not written here */
- if (pblk_line_read_smeta(pblk, line))
+ if (pblk_line_smeta_read(pblk, line))
continue;
crc = pblk_calc_smeta_crc(pblk, smeta_buf);
@@ -911,7 +739,12 @@ struct pblk_line *pblk_recov_l2p(struct pblk *pblk)
line->emeta = emeta;
memset(line->emeta->buf, 0, lm->emeta_len[0]);
- if (pblk_line_read_emeta(pblk, line, line->emeta->buf)) {
+ if (pblk_line_is_open(pblk, line)) {
+ pblk_recov_l2p_from_oob(pblk, line);
+ goto next;
+ }
+
+ if (pblk_line_emeta_read(pblk, line, line->emeta->buf)) {
pblk_recov_l2p_from_oob(pblk, line);
goto next;
}
@@ -935,6 +768,8 @@ next:
spin_lock(&line->lock);
line->state = PBLK_LINESTATE_CLOSED;
+ trace_pblk_line_state(pblk_disk_name(pblk), line->id,
+ line->state);
move_list = pblk_line_gc_list(pblk, line);
spin_unlock(&line->lock);
@@ -942,26 +777,36 @@ next:
list_move_tail(&line->list, move_list);
spin_unlock(&l_mg->gc_lock);
- kfree(line->map_bitmap);
+ mempool_free(line->map_bitmap, l_mg->bitmap_pool);
line->map_bitmap = NULL;
line->smeta = NULL;
line->emeta = NULL;
} else {
- if (open_lines > 1)
- pblk_err(pblk, "failed to recover L2P\n");
+ spin_lock(&line->lock);
+ line->state = PBLK_LINESTATE_OPEN;
+ spin_unlock(&line->lock);
+
+ line->emeta->mem = 0;
+ atomic_set(&line->emeta->sync, 0);
+
+ trace_pblk_line_state(pblk_disk_name(pblk), line->id,
+ line->state);
- open_lines++;
- line->meta_line = meta_line;
data_line = line;
+ line->meta_line = meta_line;
+
+ open_lines++;
}
}
- spin_lock(&l_mg->free_lock);
if (!open_lines) {
+ spin_lock(&l_mg->free_lock);
WARN_ON_ONCE(!test_and_clear_bit(meta_line,
&l_mg->meta_bitmap));
+ spin_unlock(&l_mg->free_lock);
pblk_line_replace_data(pblk);
} else {
+ spin_lock(&l_mg->free_lock);
/* Allocate next line for preparation */
l_mg->data_next = pblk_line_get(pblk);
if (l_mg->data_next) {
@@ -969,8 +814,8 @@ next:
l_mg->data_next->type = PBLK_LINETYPE_DATA;
is_next = 1;
}
+ spin_unlock(&l_mg->free_lock);
}
- spin_unlock(&l_mg->free_lock);
if (is_next)
pblk_line_erase(pblk, l_mg->data_next);
@@ -998,7 +843,7 @@ int pblk_recov_pad(struct pblk *pblk)
left_msecs = line->left_msecs;
spin_unlock(&l_mg->free_lock);
- ret = pblk_recov_pad_oob(pblk, line, left_msecs);
+ ret = pblk_recov_pad_line(pblk, line, left_msecs);
if (ret) {
pblk_err(pblk, "tear down padding failed (%d)\n", ret);
return ret;
diff --git a/drivers/lightnvm/pblk-rl.c b/drivers/lightnvm/pblk-rl.c
index 6a0616a6fcaf..db55a1c89997 100644
--- a/drivers/lightnvm/pblk-rl.c
+++ b/drivers/lightnvm/pblk-rl.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2016 CNEX Labs
* Initial release: Javier Gonzalez <javier@cnexlabs.com>
@@ -127,7 +128,7 @@ static void __pblk_rl_update_rates(struct pblk_rl *rl,
} else if (free_blocks < rl->high) {
int shift = rl->high_pw - rl->rb_windows_pw;
int user_windows = free_blocks >> shift;
- int user_max = user_windows << PBLK_MAX_REQ_ADDRS_PW;
+ int user_max = user_windows << ilog2(NVM_MAX_VLBA);
rl->rb_user_max = user_max;
rl->rb_gc_max = max - user_max;
@@ -228,7 +229,7 @@ void pblk_rl_init(struct pblk_rl *rl, int budget)
rl->rsv_blocks = min_blocks;
/* This will always be a power-of-2 */
- rb_windows = budget / PBLK_MAX_REQ_ADDRS;
+ rb_windows = budget / NVM_MAX_VLBA;
rl->rb_windows_pw = get_count_order(rb_windows);
/* To start with, all buffer is available to user I/O writers */
diff --git a/drivers/lightnvm/pblk-sysfs.c b/drivers/lightnvm/pblk-sysfs.c
index 9fc3dfa168b4..2d2818155aa8 100644
--- a/drivers/lightnvm/pblk-sysfs.c
+++ b/drivers/lightnvm/pblk-sysfs.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2016 CNEX Labs
* Initial release: Javier Gonzalez <javier@cnexlabs.com>
@@ -262,8 +263,14 @@ static ssize_t pblk_sysfs_lines(struct pblk *pblk, char *page)
sec_in_line = l_mg->data_line->sec_in_line;
meta_weight = bitmap_weight(&l_mg->meta_bitmap,
PBLK_DATA_LINES);
- map_weight = bitmap_weight(l_mg->data_line->map_bitmap,
+
+ spin_lock(&l_mg->data_line->lock);
+ if (l_mg->data_line->map_bitmap)
+ map_weight = bitmap_weight(l_mg->data_line->map_bitmap,
lm->sec_per_line);
+ else
+ map_weight = 0;
+ spin_unlock(&l_mg->data_line->lock);
}
spin_unlock(&l_mg->free_lock);
@@ -337,7 +344,6 @@ static ssize_t pblk_get_write_amp(u64 user, u64 gc, u64 pad,
{
int sz;
-
sz = snprintf(page, PAGE_SIZE,
"user:%lld gc:%lld pad:%lld WA:",
user, gc, pad);
@@ -349,7 +355,7 @@ static ssize_t pblk_get_write_amp(u64 user, u64 gc, u64 pad,
u32 wa_frac;
wa_int = (user + gc + pad) * 100000;
- wa_int = div_u64(wa_int, user);
+ wa_int = div64_u64(wa_int, user);
wa_int = div_u64_rem(wa_int, 100000, &wa_frac);
sz += snprintf(page + sz, PAGE_SIZE - sz, "%llu.%05u\n",
diff --git a/drivers/lightnvm/pblk-trace.h b/drivers/lightnvm/pblk-trace.h
new file mode 100644
index 000000000000..679e5c458ca6
--- /dev/null
+++ b/drivers/lightnvm/pblk-trace.h
@@ -0,0 +1,145 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM pblk
+
+#if !defined(_TRACE_PBLK_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_PBLK_H
+
+#include <linux/tracepoint.h>
+
+struct ppa_addr;
+
+#define show_chunk_flags(state) __print_flags(state, "", \
+ { NVM_CHK_ST_FREE, "FREE", }, \
+ { NVM_CHK_ST_CLOSED, "CLOSED", }, \
+ { NVM_CHK_ST_OPEN, "OPEN", }, \
+ { NVM_CHK_ST_OFFLINE, "OFFLINE", })
+
+#define show_line_state(state) __print_symbolic(state, \
+ { PBLK_LINESTATE_NEW, "NEW", }, \
+ { PBLK_LINESTATE_FREE, "FREE", }, \
+ { PBLK_LINESTATE_OPEN, "OPEN", }, \
+ { PBLK_LINESTATE_CLOSED, "CLOSED", }, \
+ { PBLK_LINESTATE_GC, "GC", }, \
+ { PBLK_LINESTATE_BAD, "BAD", }, \
+ { PBLK_LINESTATE_CORRUPT, "CORRUPT" })
+
+
+#define show_pblk_state(state) __print_symbolic(state, \
+ { PBLK_STATE_RUNNING, "RUNNING", }, \
+ { PBLK_STATE_STOPPING, "STOPPING", }, \
+ { PBLK_STATE_RECOVERING, "RECOVERING", }, \
+ { PBLK_STATE_STOPPED, "STOPPED" })
+
+#define show_chunk_erase_state(state) __print_symbolic(state, \
+ { PBLK_CHUNK_RESET_START, "START", }, \
+ { PBLK_CHUNK_RESET_DONE, "OK", }, \
+ { PBLK_CHUNK_RESET_FAILED, "FAILED" })
+
+
+TRACE_EVENT(pblk_chunk_reset,
+
+ TP_PROTO(const char *name, struct ppa_addr *ppa, int state),
+
+ TP_ARGS(name, ppa, state),
+
+ TP_STRUCT__entry(
+ __string(name, name)
+ __field(u64, ppa)
+ __field(int, state);
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, name);
+ __entry->ppa = ppa->ppa;
+ __entry->state = state;
+ ),
+
+ TP_printk("dev=%s grp=%llu pu=%llu chk=%llu state=%s", __get_str(name),
+ (u64)(((struct ppa_addr *)(&__entry->ppa))->m.grp),
+ (u64)(((struct ppa_addr *)(&__entry->ppa))->m.pu),
+ (u64)(((struct ppa_addr *)(&__entry->ppa))->m.chk),
+ show_chunk_erase_state((int)__entry->state))
+
+);
+
+TRACE_EVENT(pblk_chunk_state,
+
+ TP_PROTO(const char *name, struct ppa_addr *ppa, int state),
+
+ TP_ARGS(name, ppa, state),
+
+ TP_STRUCT__entry(
+ __string(name, name)
+ __field(u64, ppa)
+ __field(int, state);
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, name);
+ __entry->ppa = ppa->ppa;
+ __entry->state = state;
+ ),
+
+ TP_printk("dev=%s grp=%llu pu=%llu chk=%llu state=%s", __get_str(name),
+ (u64)(((struct ppa_addr *)(&__entry->ppa))->m.grp),
+ (u64)(((struct ppa_addr *)(&__entry->ppa))->m.pu),
+ (u64)(((struct ppa_addr *)(&__entry->ppa))->m.chk),
+ show_chunk_flags((int)__entry->state))
+
+);
+
+TRACE_EVENT(pblk_line_state,
+
+ TP_PROTO(const char *name, int line, int state),
+
+ TP_ARGS(name, line, state),
+
+ TP_STRUCT__entry(
+ __string(name, name)
+ __field(int, line)
+ __field(int, state);
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, name);
+ __entry->line = line;
+ __entry->state = state;
+ ),
+
+ TP_printk("dev=%s line=%d state=%s", __get_str(name),
+ (int)__entry->line,
+ show_line_state((int)__entry->state))
+
+);
+
+TRACE_EVENT(pblk_state,
+
+ TP_PROTO(const char *name, int state),
+
+ TP_ARGS(name, state),
+
+ TP_STRUCT__entry(
+ __string(name, name)
+ __field(int, state);
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, name);
+ __entry->state = state;
+ ),
+
+ TP_printk("dev=%s state=%s", __get_str(name),
+ show_pblk_state((int)__entry->state))
+
+);
+
+#endif /* !defined(_TRACE_PBLK_H) || defined(TRACE_HEADER_MULTI_READ) */
+
+/* This part must be outside protection */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH ../../../drivers/lightnvm
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE pblk-trace
+#include <trace/define_trace.h>
diff --git a/drivers/lightnvm/pblk-write.c b/drivers/lightnvm/pblk-write.c
index ee774a86cf1e..fa8726493b39 100644
--- a/drivers/lightnvm/pblk-write.c
+++ b/drivers/lightnvm/pblk-write.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2016 CNEX Labs
* Initial release: Javier Gonzalez <javier@cnexlabs.com>
@@ -16,6 +17,7 @@
*/
#include "pblk.h"
+#include "pblk-trace.h"
static unsigned long pblk_end_w_bio(struct pblk *pblk, struct nvm_rq *rqd,
struct pblk_c_ctx *c_ctx)
@@ -81,8 +83,7 @@ static void pblk_complete_write(struct pblk *pblk, struct nvm_rq *rqd,
#ifdef CONFIG_NVM_PBLK_DEBUG
atomic_long_sub(c_ctx->nr_valid, &pblk->inflight_writes);
#endif
-
- pblk_up_rq(pblk, rqd->ppa_list, rqd->nr_ppas, c_ctx->lun_bitmap);
+ pblk_up_rq(pblk, c_ctx->lun_bitmap);
pos = pblk_rb_sync_init(&pblk->rwb, &flags);
if (pos == c_ctx->sentry) {
@@ -106,14 +107,12 @@ retry:
/* Map remaining sectors in chunk, starting from ppa */
static void pblk_map_remaining(struct pblk *pblk, struct ppa_addr *ppa)
{
- struct nvm_tgt_dev *dev = pblk->dev;
- struct nvm_geo *geo = &dev->geo;
struct pblk_line *line;
struct ppa_addr map_ppa = *ppa;
u64 paddr;
int done = 0;
- line = &pblk->lines[pblk_ppa_to_line(*ppa)];
+ line = pblk_ppa_to_line(pblk, *ppa);
spin_lock(&line->lock);
while (!done) {
@@ -125,15 +124,7 @@ static void pblk_map_remaining(struct pblk *pblk, struct ppa_addr *ppa)
if (!test_and_set_bit(paddr, line->invalid_bitmap))
le32_add_cpu(line->vsc, -1);
- if (geo->version == NVM_OCSSD_SPEC_12) {
- map_ppa.ppa++;
- if (map_ppa.g.pg == geo->num_pg)
- done = 1;
- } else {
- map_ppa.m.sec++;
- if (map_ppa.m.sec == geo->clba)
- done = 1;
- }
+ done = nvm_next_ppa_in_chk(pblk->dev, &map_ppa);
}
line->w_err_gc->has_write_err = 1;
@@ -149,12 +140,11 @@ static void pblk_prepare_resubmit(struct pblk *pblk, unsigned int sentry,
struct pblk_w_ctx *w_ctx;
struct ppa_addr ppa_l2p;
int flags;
- unsigned int pos, i;
+ unsigned int i;
spin_lock(&pblk->trans_lock);
- pos = sentry;
for (i = 0; i < nr_entries; i++) {
- entry = &rb->entries[pos];
+ entry = &rb->entries[pblk_rb_ptr_wrap(rb, sentry, i)];
w_ctx = &entry->w_ctx;
/* Check if the lba has been overwritten */
@@ -168,13 +158,11 @@ static void pblk_prepare_resubmit(struct pblk *pblk, unsigned int sentry,
/* Release flags on write context. Protect from writes */
smp_store_release(&w_ctx->flags, flags);
- /* Decrese the reference count to the line as we will
+ /* Decrease the reference count to the line as we will
* re-map these entries
*/
- line = &pblk->lines[pblk_ppa_to_line(w_ctx->ppa)];
+ line = pblk_ppa_to_line(pblk, w_ctx->ppa);
kref_put(&line->ref, pblk_line_put);
-
- pos = (pos + 1) & (rb->nr_entries - 1);
}
spin_unlock(&pblk->trans_lock);
}
@@ -208,19 +196,14 @@ static void pblk_submit_rec(struct work_struct *work)
struct pblk *pblk = recovery->pblk;
struct nvm_rq *rqd = recovery->rqd;
struct pblk_c_ctx *c_ctx = nvm_rq_to_pdu(rqd);
- struct ppa_addr *ppa_list;
+ struct ppa_addr *ppa_list = nvm_rq_to_ppa_list(rqd);
pblk_log_write_err(pblk, rqd);
- if (rqd->nr_ppas == 1)
- ppa_list = &rqd->ppa_addr;
- else
- ppa_list = rqd->ppa_list;
-
pblk_map_remaining(pblk, ppa_list);
pblk_queue_resubmit(pblk, c_ctx);
- pblk_up_rq(pblk, rqd->ppa_list, rqd->nr_ppas, c_ctx->lun_bitmap);
+ pblk_up_rq(pblk, c_ctx->lun_bitmap);
if (c_ctx->nr_padded)
pblk_bio_free_pages(pblk, rqd->bio, c_ctx->nr_valid,
c_ctx->nr_padded);
@@ -257,11 +240,13 @@ static void pblk_end_io_write(struct nvm_rq *rqd)
if (rqd->error) {
pblk_end_w_fail(pblk, rqd);
return;
- }
+ } else {
+ if (trace_pblk_chunk_state_enabled())
+ pblk_check_chunk_state_update(pblk, rqd);
#ifdef CONFIG_NVM_PBLK_DEBUG
- else
WARN_ONCE(rqd->bio->bi_status, "pblk: corrupted write error\n");
#endif
+ }
pblk_complete_write(pblk, rqd, c_ctx);
atomic_dec(&pblk->inflight_io);
@@ -273,14 +258,18 @@ static void pblk_end_io_write_meta(struct nvm_rq *rqd)
struct pblk_g_ctx *m_ctx = nvm_rq_to_pdu(rqd);
struct pblk_line *line = m_ctx->private;
struct pblk_emeta *emeta = line->emeta;
+ struct ppa_addr *ppa_list = nvm_rq_to_ppa_list(rqd);
int sync;
- pblk_up_page(pblk, rqd->ppa_list, rqd->nr_ppas);
+ pblk_up_chunk(pblk, ppa_list[0]);
if (rqd->error) {
pblk_log_write_err(pblk, rqd);
pblk_err(pblk, "metadata I/O failed. Line %d\n", line->id);
line->w_err_gc->has_write_err = 1;
+ } else {
+ if (trace_pblk_chunk_state_enabled())
+ pblk_check_chunk_state_update(pblk, rqd);
}
sync = atomic_add_return(rqd->nr_ppas, &emeta->sync);
@@ -294,27 +283,16 @@ static void pblk_end_io_write_meta(struct nvm_rq *rqd)
}
static int pblk_alloc_w_rq(struct pblk *pblk, struct nvm_rq *rqd,
- unsigned int nr_secs,
- nvm_end_io_fn(*end_io))
+ unsigned int nr_secs, nvm_end_io_fn(*end_io))
{
- struct nvm_tgt_dev *dev = pblk->dev;
-
/* Setup write request */
rqd->opcode = NVM_OP_PWRITE;
rqd->nr_ppas = nr_secs;
- rqd->flags = pblk_set_progr_mode(pblk, PBLK_WRITE);
+ rqd->is_seq = 1;
rqd->private = pblk;
rqd->end_io = end_io;
- rqd->meta_list = nvm_dev_dma_alloc(dev->parent, GFP_KERNEL,
- &rqd->dma_meta_list);
- if (!rqd->meta_list)
- return -ENOMEM;
-
- rqd->ppa_list = rqd->meta_list + pblk_dma_meta_size;
- rqd->dma_ppa_list = rqd->dma_meta_list + pblk_dma_meta_size;
-
- return 0;
+ return pblk_alloc_rqd_meta(pblk, rqd);
}
static int pblk_setup_w_rq(struct pblk *pblk, struct nvm_rq *rqd,
@@ -375,6 +353,7 @@ int pblk_submit_meta_io(struct pblk *pblk, struct pblk_line *meta_line)
struct pblk_line_mgmt *l_mg = &pblk->l_mg;
struct pblk_line_meta *lm = &pblk->lm;
struct pblk_emeta *emeta = meta_line->emeta;
+ struct ppa_addr *ppa_list;
struct pblk_g_ctx *m_ctx;
struct bio *bio;
struct nvm_rq *rqd;
@@ -409,22 +388,22 @@ int pblk_submit_meta_io(struct pblk *pblk, struct pblk_line *meta_line)
if (ret)
goto fail_free_bio;
+ ppa_list = nvm_rq_to_ppa_list(rqd);
for (i = 0; i < rqd->nr_ppas; ) {
spin_lock(&meta_line->lock);
paddr = __pblk_alloc_page(pblk, meta_line, rq_ppas);
spin_unlock(&meta_line->lock);
for (j = 0; j < rq_ppas; j++, i++, paddr++)
- rqd->ppa_list[i] = addr_to_gen_ppa(pblk, paddr, id);
+ ppa_list[i] = addr_to_gen_ppa(pblk, paddr, id);
}
+ spin_lock(&l_mg->close_lock);
emeta->mem += rq_len;
- if (emeta->mem >= lm->emeta_len[0]) {
- spin_lock(&l_mg->close_lock);
+ if (emeta->mem >= lm->emeta_len[0])
list_del(&meta_line->list);
- spin_unlock(&l_mg->close_lock);
- }
+ spin_unlock(&l_mg->close_lock);
- pblk_down_page(pblk, rqd->ppa_list, rqd->nr_ppas);
+ pblk_down_chunk(pblk, ppa_list[0]);
ret = pblk_submit_io(pblk, rqd);
if (ret) {
@@ -435,7 +414,7 @@ int pblk_submit_meta_io(struct pblk *pblk, struct pblk_line *meta_line)
return NVM_IO_OK;
fail_rollback:
- pblk_up_page(pblk, rqd->ppa_list, rqd->nr_ppas);
+ pblk_up_chunk(pblk, ppa_list[0]);
spin_lock(&l_mg->close_lock);
pblk_dealloc_page(pblk, meta_line, rq_ppas);
list_add(&meta_line->list, &meta_line->list);
@@ -491,14 +470,15 @@ static struct pblk_line *pblk_should_submit_meta_io(struct pblk *pblk,
struct pblk_line *meta_line;
spin_lock(&l_mg->close_lock);
-retry:
if (list_empty(&l_mg->emeta_list)) {
spin_unlock(&l_mg->close_lock);
return NULL;
}
meta_line = list_first_entry(&l_mg->emeta_list, struct pblk_line, list);
- if (meta_line->emeta->mem >= lm->emeta_len[0])
- goto retry;
+ if (meta_line->emeta->mem >= lm->emeta_len[0]) {
+ spin_unlock(&l_mg->close_lock);
+ return NULL;
+ }
spin_unlock(&l_mg->close_lock);
if (!pblk_valid_meta_ppa(pblk, meta_line, data_rqd))
diff --git a/drivers/lightnvm/pblk.h b/drivers/lightnvm/pblk.h
index 4760af7b6499..02bb2e98f8a9 100644
--- a/drivers/lightnvm/pblk.h
+++ b/drivers/lightnvm/pblk.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2015 IT University of Copenhagen (rrpc.h)
* Copyright (C) 2016 CNEX Labs
@@ -37,8 +38,6 @@
#define PBLK_SECTOR (512)
#define PBLK_EXPOSED_PAGE_SIZE (4096)
-#define PBLK_MAX_REQ_ADDRS (64)
-#define PBLK_MAX_REQ_ADDRS_PW (6)
#define PBLK_NR_CLOSE_JOBS (4)
@@ -81,6 +80,12 @@ enum {
PBLK_BLK_ST_CLOSED = 0x2,
};
+enum {
+ PBLK_CHUNK_RESET_START,
+ PBLK_CHUNK_RESET_DONE,
+ PBLK_CHUNK_RESET_FAILED,
+};
+
struct pblk_sec_meta {
u64 reserved;
__le64 lba;
@@ -99,8 +104,8 @@ enum {
PBLK_RL_LOW = 4
};
-#define pblk_dma_meta_size (sizeof(struct pblk_sec_meta) * PBLK_MAX_REQ_ADDRS)
-#define pblk_dma_ppa_size (sizeof(u64) * PBLK_MAX_REQ_ADDRS)
+#define pblk_dma_meta_size (sizeof(struct pblk_sec_meta) * NVM_MAX_VLBA)
+#define pblk_dma_ppa_size (sizeof(u64) * NVM_MAX_VLBA)
/* write buffer completion context */
struct pblk_c_ctx {
@@ -198,6 +203,11 @@ struct pblk_rb {
* will be 4KB
*/
+ unsigned int back_thres; /* Threshold that shall be maintained by
+ * the backpointer in order to respect
+ * geo->mw_cunits on a per chunk basis
+ */
+
struct list_head pages; /* List of data pages */
spinlock_t w_lock; /* Write lock */
@@ -218,8 +228,8 @@ struct pblk_lun {
struct pblk_gc_rq {
struct pblk_line *line;
void *data;
- u64 paddr_list[PBLK_MAX_REQ_ADDRS];
- u64 lba_list[PBLK_MAX_REQ_ADDRS];
+ u64 paddr_list[NVM_MAX_VLBA];
+ u64 lba_list[NVM_MAX_VLBA];
int nr_secs;
int secs_to_gc;
struct list_head list;
@@ -532,6 +542,10 @@ struct pblk_line_mgmt {
struct pblk_emeta *eline_meta[PBLK_DATA_LINES];
unsigned long meta_bitmap;
+ /* Cache and mempool for map/invalid bitmaps */
+ struct kmem_cache *bitmap_cache;
+ mempool_t *bitmap_pool;
+
/* Helpers for fast bitmap calculations */
unsigned long *bb_template;
unsigned long *bb_aux;
@@ -725,10 +739,8 @@ struct pblk_line_ws {
/*
* pblk ring buffer operations
*/
-int pblk_rb_init(struct pblk_rb *rb, struct pblk_rb_entry *rb_entry_base,
- unsigned int power_size, unsigned int power_seg_sz);
-unsigned int pblk_rb_calculate_size(unsigned int nr_entries);
-void *pblk_rb_entries_ref(struct pblk_rb *rb);
+int pblk_rb_init(struct pblk_rb *rb, unsigned int size, unsigned int threshold,
+ unsigned int seg_sz);
int pblk_rb_may_write_user(struct pblk_rb *rb, struct bio *bio,
unsigned int nr_entries, unsigned int *pos);
int pblk_rb_may_write_gc(struct pblk_rb *rb, unsigned int nr_entries,
@@ -751,8 +763,8 @@ unsigned int pblk_rb_read_commit(struct pblk_rb *rb, unsigned int entries);
unsigned int pblk_rb_sync_init(struct pblk_rb *rb, unsigned long *flags);
unsigned int pblk_rb_sync_advance(struct pblk_rb *rb, unsigned int nr_entries);
-struct pblk_rb_entry *pblk_rb_sync_scan_entry(struct pblk_rb *rb,
- struct ppa_addr *ppa);
+unsigned int pblk_rb_ptr_wrap(struct pblk_rb *rb, unsigned int p,
+ unsigned int nr_entries);
void pblk_rb_sync_end(struct pblk_rb *rb, unsigned long *flags);
unsigned int pblk_rb_flush_point_count(struct pblk_rb *rb);
@@ -762,7 +774,7 @@ unsigned int pblk_rb_wrap_pos(struct pblk_rb *rb, unsigned int pos);
int pblk_rb_tear_down_check(struct pblk_rb *rb);
int pblk_rb_pos_oob(struct pblk_rb *rb, u64 pos);
-void pblk_rb_data_free(struct pblk_rb *rb);
+void pblk_rb_free(struct pblk_rb *rb);
ssize_t pblk_rb_sysfs(struct pblk_rb *rb, char *buf);
/*
@@ -770,11 +782,13 @@ ssize_t pblk_rb_sysfs(struct pblk_rb *rb, char *buf);
*/
struct nvm_rq *pblk_alloc_rqd(struct pblk *pblk, int type);
void pblk_free_rqd(struct pblk *pblk, struct nvm_rq *rqd, int type);
+int pblk_alloc_rqd_meta(struct pblk *pblk, struct nvm_rq *rqd);
+void pblk_free_rqd_meta(struct pblk *pblk, struct nvm_rq *rqd);
void pblk_set_sec_per_write(struct pblk *pblk, int sec_per_write);
int pblk_setup_w_rec_rq(struct pblk *pblk, struct nvm_rq *rqd,
struct pblk_c_ctx *c_ctx);
void pblk_discard(struct pblk *pblk, struct bio *bio);
-struct nvm_chk_meta *pblk_chunk_get_info(struct pblk *pblk);
+struct nvm_chk_meta *pblk_get_chunk_meta(struct pblk *pblk);
struct nvm_chk_meta *pblk_chunk_get_off(struct pblk *pblk,
struct nvm_chk_meta *lp,
struct ppa_addr ppa);
@@ -782,13 +796,17 @@ void pblk_log_write_err(struct pblk *pblk, struct nvm_rq *rqd);
void pblk_log_read_err(struct pblk *pblk, struct nvm_rq *rqd);
int pblk_submit_io(struct pblk *pblk, struct nvm_rq *rqd);
int pblk_submit_io_sync(struct pblk *pblk, struct nvm_rq *rqd);
+int pblk_submit_io_sync_sem(struct pblk *pblk, struct nvm_rq *rqd);
int pblk_submit_meta_io(struct pblk *pblk, struct pblk_line *meta_line);
+void pblk_check_chunk_state_update(struct pblk *pblk, struct nvm_rq *rqd);
struct bio *pblk_bio_map_addr(struct pblk *pblk, void *data,
unsigned int nr_secs, unsigned int len,
int alloc_type, gfp_t gfp_mask);
struct pblk_line *pblk_line_get(struct pblk *pblk);
struct pblk_line *pblk_line_get_first_data(struct pblk *pblk);
struct pblk_line *pblk_line_replace_data(struct pblk *pblk);
+void pblk_ppa_to_line_put(struct pblk *pblk, struct ppa_addr ppa);
+void pblk_rq_to_line_put(struct pblk *pblk, struct nvm_rq *rqd);
int pblk_line_recov_alloc(struct pblk *pblk, struct pblk_line *line);
void pblk_line_recov_close(struct pblk *pblk, struct pblk_line *line);
struct pblk_line *pblk_line_get_data(struct pblk *pblk);
@@ -806,8 +824,8 @@ void pblk_gen_run_ws(struct pblk *pblk, struct pblk_line *line, void *priv,
void (*work)(struct work_struct *), gfp_t gfp_mask,
struct workqueue_struct *wq);
u64 pblk_line_smeta_start(struct pblk *pblk, struct pblk_line *line);
-int pblk_line_read_smeta(struct pblk *pblk, struct pblk_line *line);
-int pblk_line_read_emeta(struct pblk *pblk, struct pblk_line *line,
+int pblk_line_smeta_read(struct pblk *pblk, struct pblk_line *line);
+int pblk_line_emeta_read(struct pblk *pblk, struct pblk_line *line,
void *emeta_buf);
int pblk_blk_erase_async(struct pblk *pblk, struct ppa_addr erase_ppa);
void pblk_line_put(struct kref *ref);
@@ -819,12 +837,11 @@ u64 pblk_alloc_page(struct pblk *pblk, struct pblk_line *line, int nr_secs);
u64 __pblk_alloc_page(struct pblk *pblk, struct pblk_line *line, int nr_secs);
int pblk_calc_secs(struct pblk *pblk, unsigned long secs_avail,
unsigned long secs_to_flush);
-void pblk_up_page(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas);
-void pblk_down_rq(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas,
+void pblk_down_rq(struct pblk *pblk, struct ppa_addr ppa,
unsigned long *lun_bitmap);
-void pblk_down_page(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas);
-void pblk_up_rq(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas,
- unsigned long *lun_bitmap);
+void pblk_down_chunk(struct pblk *pblk, struct ppa_addr ppa);
+void pblk_up_chunk(struct pblk *pblk, struct ppa_addr ppa);
+void pblk_up_rq(struct pblk *pblk, unsigned long *lun_bitmap);
int pblk_bio_add_pages(struct pblk *pblk, struct bio *bio, gfp_t flags,
int nr_pages);
void pblk_bio_free_pages(struct pblk *pblk, struct bio *bio, int off,
@@ -976,17 +993,15 @@ static inline int pblk_line_vsc(struct pblk_line *line)
return le32_to_cpu(*line->vsc);
}
-static inline int pblk_pad_distance(struct pblk *pblk)
+static inline int pblk_ppa_to_line_id(struct ppa_addr p)
{
- struct nvm_tgt_dev *dev = pblk->dev;
- struct nvm_geo *geo = &dev->geo;
-
- return geo->mw_cunits * geo->all_luns * geo->ws_opt;
+ return p.a.blk;
}
-static inline int pblk_ppa_to_line(struct ppa_addr p)
+static inline struct pblk_line *pblk_ppa_to_line(struct pblk *pblk,
+ struct ppa_addr p)
{
- return p.a.blk;
+ return &pblk->lines[pblk_ppa_to_line_id(p)];
}
static inline int pblk_ppa_to_pos(struct nvm_geo *geo, struct ppa_addr p)
@@ -1034,6 +1049,25 @@ static inline struct ppa_addr addr_to_gen_ppa(struct pblk *pblk, u64 paddr,
return ppa;
}
+static inline struct nvm_chk_meta *pblk_dev_ppa_to_chunk(struct pblk *pblk,
+ struct ppa_addr p)
+{
+ struct nvm_tgt_dev *dev = pblk->dev;
+ struct nvm_geo *geo = &dev->geo;
+ struct pblk_line *line = pblk_ppa_to_line(pblk, p);
+ int pos = pblk_ppa_to_pos(geo, p);
+
+ return &line->chks[pos];
+}
+
+static inline u64 pblk_dev_ppa_to_chunk_addr(struct pblk *pblk,
+ struct ppa_addr p)
+{
+ struct nvm_tgt_dev *dev = pblk->dev;
+
+ return dev_to_chunk_addr(dev->parent, &pblk->addrf, p);
+}
+
static inline u64 pblk_dev_ppa_to_line_addr(struct pblk *pblk,
struct ppa_addr p)
{
@@ -1067,86 +1101,16 @@ static inline u64 pblk_dev_ppa_to_line_addr(struct pblk *pblk,
static inline struct ppa_addr pblk_ppa32_to_ppa64(struct pblk *pblk, u32 ppa32)
{
- struct ppa_addr ppa64;
-
- ppa64.ppa = 0;
-
- if (ppa32 == -1) {
- ppa64.ppa = ADDR_EMPTY;
- } else if (ppa32 & (1U << 31)) {
- ppa64.c.line = ppa32 & ((~0U) >> 1);
- ppa64.c.is_cached = 1;
- } else {
- struct nvm_tgt_dev *dev = pblk->dev;
- struct nvm_geo *geo = &dev->geo;
-
- if (geo->version == NVM_OCSSD_SPEC_12) {
- struct nvm_addrf_12 *ppaf =
- (struct nvm_addrf_12 *)&pblk->addrf;
-
- ppa64.g.ch = (ppa32 & ppaf->ch_mask) >>
- ppaf->ch_offset;
- ppa64.g.lun = (ppa32 & ppaf->lun_mask) >>
- ppaf->lun_offset;
- ppa64.g.blk = (ppa32 & ppaf->blk_mask) >>
- ppaf->blk_offset;
- ppa64.g.pg = (ppa32 & ppaf->pg_mask) >>
- ppaf->pg_offset;
- ppa64.g.pl = (ppa32 & ppaf->pln_mask) >>
- ppaf->pln_offset;
- ppa64.g.sec = (ppa32 & ppaf->sec_mask) >>
- ppaf->sec_offset;
- } else {
- struct nvm_addrf *lbaf = &pblk->addrf;
-
- ppa64.m.grp = (ppa32 & lbaf->ch_mask) >>
- lbaf->ch_offset;
- ppa64.m.pu = (ppa32 & lbaf->lun_mask) >>
- lbaf->lun_offset;
- ppa64.m.chk = (ppa32 & lbaf->chk_mask) >>
- lbaf->chk_offset;
- ppa64.m.sec = (ppa32 & lbaf->sec_mask) >>
- lbaf->sec_offset;
- }
- }
+ struct nvm_tgt_dev *dev = pblk->dev;
- return ppa64;
+ return nvm_ppa32_to_ppa64(dev->parent, &pblk->addrf, ppa32);
}
static inline u32 pblk_ppa64_to_ppa32(struct pblk *pblk, struct ppa_addr ppa64)
{
- u32 ppa32 = 0;
-
- if (ppa64.ppa == ADDR_EMPTY) {
- ppa32 = ~0U;
- } else if (ppa64.c.is_cached) {
- ppa32 |= ppa64.c.line;
- ppa32 |= 1U << 31;
- } else {
- struct nvm_tgt_dev *dev = pblk->dev;
- struct nvm_geo *geo = &dev->geo;
-
- if (geo->version == NVM_OCSSD_SPEC_12) {
- struct nvm_addrf_12 *ppaf =
- (struct nvm_addrf_12 *)&pblk->addrf;
-
- ppa32 |= ppa64.g.ch << ppaf->ch_offset;
- ppa32 |= ppa64.g.lun << ppaf->lun_offset;
- ppa32 |= ppa64.g.blk << ppaf->blk_offset;
- ppa32 |= ppa64.g.pg << ppaf->pg_offset;
- ppa32 |= ppa64.g.pl << ppaf->pln_offset;
- ppa32 |= ppa64.g.sec << ppaf->sec_offset;
- } else {
- struct nvm_addrf *lbaf = &pblk->addrf;
-
- ppa32 |= ppa64.m.grp << lbaf->ch_offset;
- ppa32 |= ppa64.m.pu << lbaf->lun_offset;
- ppa32 |= ppa64.m.chk << lbaf->chk_offset;
- ppa32 |= ppa64.m.sec << lbaf->sec_offset;
- }
- }
+ struct nvm_tgt_dev *dev = pblk->dev;
- return ppa32;
+ return nvm_ppa64_to_ppa32(dev->parent, &pblk->addrf, ppa64);
}
static inline struct ppa_addr pblk_trans_map_get(struct pblk *pblk,
@@ -1255,44 +1219,6 @@ static inline u32 pblk_calc_emeta_crc(struct pblk *pblk,
return crc;
}
-static inline int pblk_set_progr_mode(struct pblk *pblk, int type)
-{
- struct nvm_tgt_dev *dev = pblk->dev;
- struct nvm_geo *geo = &dev->geo;
- int flags;
-
- if (geo->version == NVM_OCSSD_SPEC_20)
- return 0;
-
- flags = geo->pln_mode >> 1;
-
- if (type == PBLK_WRITE)
- flags |= NVM_IO_SCRAMBLE_ENABLE;
-
- return flags;
-}
-
-enum {
- PBLK_READ_RANDOM = 0,
- PBLK_READ_SEQUENTIAL = 1,
-};
-
-static inline int pblk_set_read_mode(struct pblk *pblk, int type)
-{
- struct nvm_tgt_dev *dev = pblk->dev;
- struct nvm_geo *geo = &dev->geo;
- int flags;
-
- if (geo->version == NVM_OCSSD_SPEC_20)
- return 0;
-
- flags = NVM_IO_SUSPEND | NVM_IO_SCRAMBLE_ENABLE;
- if (type == PBLK_READ_SEQUENTIAL)
- flags |= geo->pln_mode >> 1;
-
- return flags;
-}
-
static inline int pblk_io_aligned(struct pblk *pblk, int nr_secs)
{
return !(nr_secs % pblk->min_write_pgs);
@@ -1375,9 +1301,7 @@ static inline int pblk_boundary_ppa_checks(struct nvm_tgt_dev *tgt_dev,
static inline int pblk_check_io(struct pblk *pblk, struct nvm_rq *rqd)
{
struct nvm_tgt_dev *dev = pblk->dev;
- struct ppa_addr *ppa_list;
-
- ppa_list = (rqd->nr_ppas > 1) ? rqd->ppa_list : &rqd->ppa_addr;
+ struct ppa_addr *ppa_list = nvm_rq_to_ppa_list(rqd);
if (pblk_boundary_ppa_checks(dev, ppa_list, rqd->nr_ppas)) {
WARN_ON(1);
@@ -1386,12 +1310,10 @@ static inline int pblk_check_io(struct pblk *pblk, struct nvm_rq *rqd)
if (rqd->opcode == NVM_OP_PWRITE) {
struct pblk_line *line;
- struct ppa_addr ppa;
int i;
for (i = 0; i < rqd->nr_ppas; i++) {
- ppa = ppa_list[i];
- line = &pblk->lines[pblk_ppa_to_line(ppa)];
+ line = pblk_ppa_to_line(pblk, ppa_list[i]);
spin_lock(&line->lock);
if (line->state != PBLK_LINESTATE_OPEN) {
@@ -1441,4 +1363,11 @@ static inline void pblk_setup_uuid(struct pblk *pblk)
uuid_le_gen(&uuid);
memcpy(pblk->instance_uuid, uuid.b, 16);
}
+
+static inline char *pblk_disk_name(struct pblk *pblk)
+{
+ struct gendisk *disk = pblk->disk;
+
+ return disk->disk_name;
+}
#endif /* PBLK_H_ */
diff --git a/drivers/macintosh/adb-iop.c b/drivers/macintosh/adb-iop.c
index ca623e6446e4..fca31640e3ef 100644
--- a/drivers/macintosh/adb-iop.c
+++ b/drivers/macintosh/adb-iop.c
@@ -20,13 +20,13 @@
#include <linux/init.h>
#include <linux/proc_fs.h>
-#include <asm/macintosh.h>
-#include <asm/macints.h>
+#include <asm/macintosh.h>
+#include <asm/macints.h>
#include <asm/mac_iop.h>
#include <asm/mac_oss.h>
#include <asm/adb_iop.h>
-#include <linux/adb.h>
+#include <linux/adb.h>
/*#define DEBUG_ADB_IOP*/
@@ -38,9 +38,9 @@ static unsigned char *reply_ptr;
#endif
static enum adb_iop_state {
- idle,
- sending,
- awaiting_reply
+ idle,
+ sending,
+ awaiting_reply
} adb_iop_state;
static void adb_iop_start(void);
@@ -66,7 +66,8 @@ static void adb_iop_end_req(struct adb_request *req, int state)
{
req->complete = 1;
current_req = req->next;
- if (req->done) (*req->done)(req);
+ if (req->done)
+ (*req->done)(req);
adb_iop_state = state;
}
@@ -100,7 +101,7 @@ static void adb_iop_complete(struct iop_msg *msg)
static void adb_iop_listen(struct iop_msg *msg)
{
- struct adb_iopmsg *amsg = (struct adb_iopmsg *) msg->message;
+ struct adb_iopmsg *amsg = (struct adb_iopmsg *)msg->message;
struct adb_request *req;
unsigned long flags;
#ifdef DEBUG_ADB_IOP
@@ -113,9 +114,9 @@ static void adb_iop_listen(struct iop_msg *msg)
#ifdef DEBUG_ADB_IOP
printk("adb_iop_listen %p: rcvd packet, %d bytes: %02X %02X", req,
- (uint) amsg->count + 2, (uint) amsg->flags, (uint) amsg->cmd);
+ (uint)amsg->count + 2, (uint)amsg->flags, (uint)amsg->cmd);
for (i = 0; i < amsg->count; i++)
- printk(" %02X", (uint) amsg->data[i]);
+ printk(" %02X", (uint)amsg->data[i]);
printk("\n");
#endif
@@ -168,14 +169,15 @@ static void adb_iop_start(void)
/* get the packet to send */
req = current_req;
- if (!req) return;
+ if (!req)
+ return;
local_irq_save(flags);
#ifdef DEBUG_ADB_IOP
printk("adb_iop_start %p: sending packet, %d bytes:", req, req->nbytes);
- for (i = 0 ; i < req->nbytes ; i++)
- printk(" %02X", (uint) req->data[i]);
+ for (i = 0; i < req->nbytes; i++)
+ printk(" %02X", (uint)req->data[i]);
printk("\n");
#endif
@@ -196,19 +198,20 @@ static void adb_iop_start(void)
/* Now send it. The IOP manager will call adb_iop_complete */
/* when the packet has been sent. */
- iop_send_message(ADB_IOP, ADB_CHAN, req,
- sizeof(amsg), (__u8 *) &amsg, adb_iop_complete);
+ iop_send_message(ADB_IOP, ADB_CHAN, req, sizeof(amsg), (__u8 *)&amsg,
+ adb_iop_complete);
}
int adb_iop_probe(void)
{
- if (!iop_ism_present) return -ENODEV;
+ if (!iop_ism_present)
+ return -ENODEV;
return 0;
}
int adb_iop_init(void)
{
- printk("adb: IOP ISM driver v0.4 for Unified ADB.\n");
+ pr_info("adb: IOP ISM driver v0.4 for Unified ADB\n");
iop_listen(ADB_IOP, ADB_CHAN, adb_iop_listen, "ADB");
return 0;
}
@@ -218,10 +221,12 @@ int adb_iop_send_request(struct adb_request *req, int sync)
int err;
err = adb_iop_write(req);
- if (err) return err;
+ if (err)
+ return err;
if (sync) {
- while (!req->complete) adb_iop_poll();
+ while (!req->complete)
+ adb_iop_poll();
}
return 0;
}
@@ -251,7 +256,9 @@ static int adb_iop_write(struct adb_request *req)
}
local_irq_restore(flags);
- if (adb_iop_state == idle) adb_iop_start();
+
+ if (adb_iop_state == idle)
+ adb_iop_start();
return 0;
}
@@ -263,7 +270,8 @@ int adb_iop_autopoll(int devs)
void adb_iop_poll(void)
{
- if (adb_iop_state == idle) adb_iop_start();
+ if (adb_iop_state == idle)
+ adb_iop_start();
iop_ism_irq_poll(ADB_IOP);
}
diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
index 76e98f0f7a3e..e49d1f287a17 100644
--- a/drivers/macintosh/adb.c
+++ b/drivers/macintosh/adb.c
@@ -203,15 +203,15 @@ static int adb_scan_bus(void)
}
/* Now fill in the handler_id field of the adb_handler entries. */
- pr_debug("adb devices:\n");
for (i = 1; i < 16; i++) {
if (adb_handler[i].original_address == 0)
continue;
adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
(i << 4) | 0xf);
adb_handler[i].handler_id = req.reply[2];
- pr_debug(" [%d]: %d %x\n", i, adb_handler[i].original_address,
- adb_handler[i].handler_id);
+ printk(KERN_DEBUG "adb device [%d]: %d 0x%X\n", i,
+ adb_handler[i].original_address,
+ adb_handler[i].handler_id);
devmask |= 1 << i;
}
return devmask;
@@ -579,6 +579,8 @@ adb_try_handler_change(int address, int new_id)
mutex_lock(&adb_handler_mutex);
ret = try_handler_change(address, new_id);
mutex_unlock(&adb_handler_mutex);
+ if (ret)
+ pr_debug("adb handler change: [%d] 0x%X\n", address, new_id);
return ret;
}
EXPORT_SYMBOL(adb_try_handler_change);
diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c
index a261892c03b3..75482eeab2c4 100644
--- a/drivers/macintosh/adbhid.c
+++ b/drivers/macintosh/adbhid.c
@@ -757,6 +757,7 @@ adbhid_input_register(int id, int default_id, int original_handler_id,
struct input_dev *input_dev;
int err;
int i;
+ char *keyboard_type;
if (adbhid[id]) {
pr_err("Trying to reregister ADB HID on ID %d\n", id);
@@ -798,24 +799,23 @@ adbhid_input_register(int id, int default_id, int original_handler_id,
memcpy(hid->keycode, adb_to_linux_keycodes, sizeof(adb_to_linux_keycodes));
- pr_info("Detected ADB keyboard, type ");
switch (original_handler_id) {
default:
- pr_cont("<unknown>.\n");
+ keyboard_type = "<unknown>";
input_dev->id.version = ADB_KEYBOARD_UNKNOWN;
break;
case 0x01: case 0x02: case 0x03: case 0x06: case 0x08:
case 0x0C: case 0x10: case 0x18: case 0x1B: case 0x1C:
case 0xC0: case 0xC3: case 0xC6:
- pr_cont("ANSI.\n");
+ keyboard_type = "ANSI";
input_dev->id.version = ADB_KEYBOARD_ANSI;
break;
case 0x04: case 0x05: case 0x07: case 0x09: case 0x0D:
case 0x11: case 0x14: case 0x19: case 0x1D: case 0xC1:
case 0xC4: case 0xC7:
- pr_cont("ISO, swapping keys.\n");
+ keyboard_type = "ISO, swapping keys";
input_dev->id.version = ADB_KEYBOARD_ISO;
i = hid->keycode[10];
hid->keycode[10] = hid->keycode[50];
@@ -824,10 +824,11 @@ adbhid_input_register(int id, int default_id, int original_handler_id,
case 0x12: case 0x15: case 0x16: case 0x17: case 0x1A:
case 0x1E: case 0xC2: case 0xC5: case 0xC8: case 0xC9:
- pr_cont("JIS.\n");
+ keyboard_type = "JIS";
input_dev->id.version = ADB_KEYBOARD_JIS;
break;
}
+ pr_info("Detected ADB keyboard, type %s.\n", keyboard_type);
for (i = 0; i < 128; i++)
if (hid->keycode[i])
@@ -972,16 +973,13 @@ adbhid_probe(void)
->get it to send separate codes for left and right shift,
control, option keys */
#if 0 /* handler 5 doesn't send separate codes for R modifiers */
- if (adb_try_handler_change(id, 5))
- printk("ADB keyboard at %d, handler set to 5\n", id);
- else
+ if (!adb_try_handler_change(id, 5))
#endif
- if (adb_try_handler_change(id, 3))
- printk("ADB keyboard at %d, handler set to 3\n", id);
- else
- printk("ADB keyboard at %d, handler 1\n", id);
+ adb_try_handler_change(id, 3);
adb_get_infos(id, &default_id, &cur_handler_id);
+ printk(KERN_DEBUG "ADB keyboard at %d has handler 0x%X\n",
+ id, cur_handler_id);
reg |= adbhid_input_reregister(id, default_id, org_handler_id,
cur_handler_id, 0);
}
@@ -999,48 +997,44 @@ adbhid_probe(void)
for (i = 0; i < mouse_ids.nids; i++) {
int id = mouse_ids.id[i];
int mouse_kind;
+ char *desc = "standard";
adb_get_infos(id, &default_id, &org_handler_id);
if (adb_try_handler_change(id, 4)) {
- printk("ADB mouse at %d, handler set to 4", id);
mouse_kind = ADBMOUSE_EXTENDED;
}
else if (adb_try_handler_change(id, 0x2F)) {
- printk("ADB mouse at %d, handler set to 0x2F", id);
mouse_kind = ADBMOUSE_MICROSPEED;
}
else if (adb_try_handler_change(id, 0x42)) {
- printk("ADB mouse at %d, handler set to 0x42", id);
mouse_kind = ADBMOUSE_TRACKBALLPRO;
}
else if (adb_try_handler_change(id, 0x66)) {
- printk("ADB mouse at %d, handler set to 0x66", id);
mouse_kind = ADBMOUSE_MICROSPEED;
}
else if (adb_try_handler_change(id, 0x5F)) {
- printk("ADB mouse at %d, handler set to 0x5F", id);
mouse_kind = ADBMOUSE_MICROSPEED;
}
else if (adb_try_handler_change(id, 3)) {
- printk("ADB mouse at %d, handler set to 3", id);
mouse_kind = ADBMOUSE_MS_A3;
}
else if (adb_try_handler_change(id, 2)) {
- printk("ADB mouse at %d, handler set to 2", id);
mouse_kind = ADBMOUSE_STANDARD_200;
}
else {
- printk("ADB mouse at %d, handler 1", id);
mouse_kind = ADBMOUSE_STANDARD_100;
}
if ((mouse_kind == ADBMOUSE_TRACKBALLPRO)
|| (mouse_kind == ADBMOUSE_MICROSPEED)) {
+ desc = "Microspeed/MacPoint or compatible";
init_microspeed(id);
} else if (mouse_kind == ADBMOUSE_MS_A3) {
+ desc = "Mouse Systems A3 Mouse or compatible";
init_ms_a3(id);
} else if (mouse_kind == ADBMOUSE_EXTENDED) {
+ desc = "extended";
/*
* Register 1 is usually used for device
* identification. Here, we try to identify
@@ -1054,32 +1048,36 @@ adbhid_probe(void)
(req.reply[1] == 0x9a) && ((req.reply[2] == 0x21)
|| (req.reply[2] == 0x20))) {
mouse_kind = ADBMOUSE_TRACKBALL;
+ desc = "trackman/mouseman";
init_trackball(id);
}
else if ((req.reply_len >= 4) &&
(req.reply[1] == 0x74) && (req.reply[2] == 0x70) &&
(req.reply[3] == 0x61) && (req.reply[4] == 0x64)) {
mouse_kind = ADBMOUSE_TRACKPAD;
+ desc = "trackpad";
init_trackpad(id);
}
else if ((req.reply_len >= 4) &&
(req.reply[1] == 0x4b) && (req.reply[2] == 0x4d) &&
(req.reply[3] == 0x4c) && (req.reply[4] == 0x31)) {
mouse_kind = ADBMOUSE_TURBOMOUSE5;
+ desc = "TurboMouse 5";
init_turbomouse(id);
}
else if ((req.reply_len == 9) &&
(req.reply[1] == 0x4b) && (req.reply[2] == 0x4f) &&
(req.reply[3] == 0x49) && (req.reply[4] == 0x54)) {
if (adb_try_handler_change(id, 0x42)) {
- pr_cont("\nADB MacAlly 2-button mouse at %d, handler set to 0x42", id);
mouse_kind = ADBMOUSE_MACALLY2;
+ desc = "MacAlly 2-button";
}
}
}
- pr_cont("\n");
adb_get_infos(id, &default_id, &cur_handler_id);
+ printk(KERN_DEBUG "ADB mouse (%s) at %d has handler 0x%X\n",
+ desc, id, cur_handler_id);
reg |= adbhid_input_reregister(id, default_id, org_handler_id,
cur_handler_id, mouse_kind);
}
@@ -1092,12 +1090,10 @@ init_trackpad(int id)
struct adb_request req;
unsigned char r1_buffer[8];
- pr_cont(" (trackpad)");
-
adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
ADB_READREG(id,1));
if (req.reply_len < 8)
- pr_cont("bad length for reg. 1\n");
+ pr_err("%s: bad length for reg. 1\n", __func__);
else
{
memcpy(r1_buffer, &req.reply[1], 8);
@@ -1145,8 +1141,6 @@ init_trackball(int id)
{
struct adb_request req;
- pr_cont(" (trackman/mouseman)");
-
adb_request(&req, NULL, ADBREQ_SYNC, 3,
ADB_WRITEREG(id,1), 00,0x81);
@@ -1177,8 +1171,6 @@ init_turbomouse(int id)
{
struct adb_request req;
- pr_cont(" (TurboMouse 5)");
-
adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(3));
@@ -1213,8 +1205,6 @@ init_microspeed(int id)
{
struct adb_request req;
- pr_cont(" (Microspeed/MacPoint or compatible)");
-
adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
/* This will initialize mice using the Microspeed, MacPoint and
@@ -1253,7 +1243,6 @@ init_ms_a3(int id)
{
struct adb_request req;
- pr_cont(" (Mouse Systems A3 Mouse, or compatible)");
adb_request(&req, NULL, ADBREQ_SYNC, 3,
ADB_WRITEREG(id, 0x2),
0x00,
diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c
index 07074820a167..17d3bc917562 100644
--- a/drivers/macintosh/macio_asic.c
+++ b/drivers/macintosh/macio_asic.c
@@ -360,9 +360,10 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip,
struct macio_dev *in_bay,
struct resource *parent_res)
{
+ char name[MAX_NODE_NAME_SIZE + 1];
struct macio_dev *dev;
const u32 *reg;
-
+
if (np == NULL)
return NULL;
@@ -402,6 +403,7 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip,
#endif
/* MacIO itself has a different reg, we use it's PCI base */
+ snprintf(name, sizeof(name), "%pOFn", np);
if (np == chip->of_node) {
dev_set_name(&dev->ofdev.dev, "%1d.%08x:%.*s",
chip->lbus.index,
@@ -410,12 +412,12 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip,
#else
0, /* NuBus may want to do something better here */
#endif
- MAX_NODE_NAME_SIZE, np->name);
+ MAX_NODE_NAME_SIZE, name);
} else {
reg = of_get_property(np, "reg", NULL);
dev_set_name(&dev->ofdev.dev, "%1d.%08x:%.*s",
chip->lbus.index,
- reg ? *reg : 0, MAX_NODE_NAME_SIZE, np->name);
+ reg ? *reg : 0, MAX_NODE_NAME_SIZE, name);
}
/* Setup interrupts & resources */
diff --git a/drivers/macintosh/macio_sysfs.c b/drivers/macintosh/macio_sysfs.c
index ca4fcffe454b..d2451e58acb9 100644
--- a/drivers/macintosh/macio_sysfs.c
+++ b/drivers/macintosh/macio_sysfs.c
@@ -58,7 +58,13 @@ static ssize_t devspec_show(struct device *dev,
static DEVICE_ATTR_RO(modalias);
static DEVICE_ATTR_RO(devspec);
-macio_config_of_attr (name, "%s\n");
+static ssize_t name_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%pOFn\n", dev->of_node);
+}
+static DEVICE_ATTR_RO(name);
+
macio_config_of_attr (type, "%s\n");
static struct attribute *macio_dev_attrs[] = {
diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c
index e8ae2e54151c..0a0b8e1f4236 100644
--- a/drivers/macintosh/smu.c
+++ b/drivers/macintosh/smu.c
@@ -23,7 +23,7 @@
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/dmapool.h>
-#include <linux/bootmem.h>
+#include <linux/memblock.h>
#include <linux/vmalloc.h>
#include <linux/highmem.h>
#include <linux/jiffies.h>
@@ -38,7 +38,6 @@
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/slab.h>
-#include <linux/memblock.h>
#include <linux/sched/signal.h>
#include <asm/byteorder.h>
@@ -493,7 +492,7 @@ int __init smu_init (void)
goto fail_np;
}
- smu = alloc_bootmem(sizeof(struct smu_device));
+ smu = memblock_alloc(sizeof(struct smu_device), SMP_CACHE_BYTES);
spin_lock_init(&smu->lock);
INIT_LIST_HEAD(&smu->cmd_list);
@@ -569,7 +568,7 @@ fail_msg_node:
fail_db_node:
of_node_put(smu->db_node);
fail_bootmem:
- free_bootmem(__pa(smu), sizeof(struct smu_device));
+ memblock_free(__pa(smu), sizeof(struct smu_device));
smu = NULL;
fail_np:
of_node_put(np);
diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c
index 98dd702eb867..bbec6ac0a966 100644
--- a/drivers/macintosh/via-cuda.c
+++ b/drivers/macintosh/via-cuda.c
@@ -766,3 +766,38 @@ cuda_input(unsigned char *buf, int nb)
buf, nb, false);
}
}
+
+/* Offset between Unix time (1970-based) and Mac time (1904-based) */
+#define RTC_OFFSET 2082844800
+
+time64_t cuda_get_time(void)
+{
+ struct adb_request req;
+ u32 now;
+
+ if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0)
+ return 0;
+ while (!req.complete)
+ cuda_poll();
+ if (req.reply_len != 7)
+ pr_err("%s: got %d byte reply\n", __func__, req.reply_len);
+ now = (req.reply[3] << 24) + (req.reply[4] << 16) +
+ (req.reply[5] << 8) + req.reply[6];
+ return (time64_t)now - RTC_OFFSET;
+}
+
+int cuda_set_rtc_time(struct rtc_time *tm)
+{
+ u32 now;
+ struct adb_request req;
+
+ now = lower_32_bits(rtc_tm_to_time64(tm) + RTC_OFFSET);
+ if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME,
+ now >> 24, now >> 16, now >> 8, now) < 0)
+ return -ENXIO;
+ while (!req.complete)
+ cuda_poll();
+ if ((req.reply_len != 3) && (req.reply_len != 7))
+ pr_err("%s: got %d byte reply\n", __func__, req.reply_len);
+ return 0;
+}
diff --git a/drivers/macintosh/via-macii.c b/drivers/macintosh/via-macii.c
index cf6f7d52d6be..ac824d7b2dcf 100644
--- a/drivers/macintosh/via-macii.c
+++ b/drivers/macintosh/via-macii.c
@@ -12,7 +12,7 @@
*
* 1999-08-02 (jmt) - Initial rewrite for Unified ADB.
* 2000-03-29 Tony Mantler <tonym@mac.linux-m68k.org>
- * - Big overhaul, should actually work now.
+ * - Big overhaul, should actually work now.
* 2006-12-31 Finn Thain - Another overhaul.
*
* Suggested reading:
@@ -23,7 +23,7 @@
* Apple's "ADB Analyzer" bus sniffer is invaluable:
* ftp://ftp.apple.com/developer/Tool_Chest/Devices_-_Hardware/Apple_Desktop_Bus/
*/
-
+
#include <stdarg.h>
#include <linux/types.h>
#include <linux/errno.h>
@@ -77,7 +77,7 @@ static volatile unsigned char *via;
#define ST_ODD 0x20 /* ADB state: odd data byte */
#define ST_IDLE 0x30 /* ADB state: idle, nothing to send */
-static int macii_init_via(void);
+static int macii_init_via(void);
static void macii_start(void);
static irqreturn_t macii_interrupt(int irq, void *arg);
static void macii_queue_poll(void);
@@ -120,31 +120,15 @@ static int srq_asserted; /* have to poll for the device that asserted it */
static int command_byte; /* the most recent command byte transmitted */
static int autopoll_devs; /* bits set are device addresses to be polled */
-/* Sanity check for request queue. Doesn't check for cycles. */
-static int request_is_queued(struct adb_request *req) {
- struct adb_request *cur;
- unsigned long flags;
- local_irq_save(flags);
- cur = current_req;
- while (cur) {
- if (cur == req) {
- local_irq_restore(flags);
- return 1;
- }
- cur = cur->next;
- }
- local_irq_restore(flags);
- return 0;
-}
-
/* Check for MacII style ADB */
static int macii_probe(void)
{
- if (macintosh_config->adb_type != MAC_ADB_II) return -ENODEV;
+ if (macintosh_config->adb_type != MAC_ADB_II)
+ return -ENODEV;
via = via1;
- printk("adb: Mac II ADB Driver v1.0 for Unified ADB\n");
+ pr_info("adb: Mac II ADB Driver v1.0 for Unified ADB\n");
return 0;
}
@@ -153,15 +137,17 @@ int macii_init(void)
{
unsigned long flags;
int err;
-
+
local_irq_save(flags);
-
+
err = macii_init_via();
- if (err) goto out;
+ if (err)
+ goto out;
err = request_irq(IRQ_MAC_ADB, macii_interrupt, 0, "ADB",
macii_interrupt);
- if (err) goto out;
+ if (err)
+ goto out;
macii_state = idle;
out:
@@ -169,7 +155,7 @@ out:
return err;
}
-/* initialize the hardware */
+/* initialize the hardware */
static int macii_init_via(void)
{
unsigned char x;
@@ -179,7 +165,7 @@ static int macii_init_via(void)
/* Set up state: idle */
via[B] |= ST_IDLE;
- last_status = via[B] & (ST_MASK|CTLR_IRQ);
+ last_status = via[B] & (ST_MASK | CTLR_IRQ);
/* Shift register on input */
via[ACR] = (via[ACR] & ~SR_CTRL) | SR_EXT;
@@ -205,7 +191,8 @@ static void macii_queue_poll(void)
int next_device;
static struct adb_request req;
- if (!autopoll_devs) return;
+ if (!autopoll_devs)
+ return;
device_mask = (1 << (((command_byte & 0xF0) >> 4) + 1)) - 1;
if (autopoll_devs & ~device_mask)
@@ -213,10 +200,7 @@ static void macii_queue_poll(void)
else
next_device = ffs(autopoll_devs) - 1;
- BUG_ON(request_is_queued(&req));
-
- adb_request(&req, NULL, ADBREQ_NOSEND, 1,
- ADB_READREG(next_device, 0));
+ adb_request(&req, NULL, ADBREQ_NOSEND, 1, ADB_READREG(next_device, 0));
req.sent = 0;
req.complete = 0;
@@ -235,45 +219,47 @@ static void macii_queue_poll(void)
static int macii_send_request(struct adb_request *req, int sync)
{
int err;
- unsigned long flags;
- BUG_ON(request_is_queued(req));
-
- local_irq_save(flags);
err = macii_write(req);
- local_irq_restore(flags);
+ if (err)
+ return err;
- if (!err && sync) {
- while (!req->complete) {
+ if (sync)
+ while (!req->complete)
macii_poll();
- }
- BUG_ON(request_is_queued(req));
- }
- return err;
+ return 0;
}
/* Send an ADB request (append to request queue) */
static int macii_write(struct adb_request *req)
{
+ unsigned long flags;
+
if (req->nbytes < 2 || req->data[0] != ADB_PACKET || req->nbytes > 15) {
req->complete = 1;
return -EINVAL;
}
-
+
req->next = NULL;
req->sent = 0;
req->complete = 0;
req->reply_len = 0;
+ local_irq_save(flags);
+
if (current_req != NULL) {
last_req->next = req;
last_req = req;
} else {
current_req = req;
last_req = req;
- if (macii_state == idle) macii_start();
+ if (macii_state == idle)
+ macii_start();
}
+
+ local_irq_restore(flags);
+
return 0;
}
@@ -287,7 +273,8 @@ static int macii_autopoll(int devs)
/* bit 1 == device 1, and so on. */
autopoll_devs = devs & 0xFFFE;
- if (!autopoll_devs) return 0;
+ if (!autopoll_devs)
+ return 0;
local_irq_save(flags);
@@ -304,7 +291,8 @@ static int macii_autopoll(int devs)
return err;
}
-static inline int need_autopoll(void) {
+static inline int need_autopoll(void)
+{
/* Was the last command Talk Reg 0
* and is the target on the autopoll list?
*/
@@ -317,21 +305,17 @@ static inline int need_autopoll(void) {
/* Prod the chip without interrupts */
static void macii_poll(void)
{
- disable_irq(IRQ_MAC_ADB);
macii_interrupt(0, NULL);
- enable_irq(IRQ_MAC_ADB);
}
/* Reset the bus */
static int macii_reset_bus(void)
{
static struct adb_request req;
-
- if (request_is_queued(&req))
- return 0;
/* Command = 0, Address = ignored */
- adb_request(&req, NULL, 0, 1, ADB_BUSRESET);
+ adb_request(&req, NULL, ADBREQ_NOSEND, 1, ADB_BUSRESET);
+ macii_send_request(&req, 1);
/* Don't want any more requests during the Global Reset low time. */
udelay(3000);
@@ -346,10 +330,6 @@ static void macii_start(void)
req = current_req;
- BUG_ON(req == NULL);
-
- BUG_ON(macii_state != idle);
-
/* Now send it. Be careful though, that first byte of the request
* is actually ADB_PACKET; the real data begins at index 1!
* And req->nbytes is the number of bytes of real data plus one.
@@ -375,7 +355,7 @@ static void macii_start(void)
* to be activity on the ADB bus. The chip will poll to achieve this.
*
* The basic ADB state machine was left unchanged from the original MacII code
- * by Alan Cox, which was based on the CUDA driver for PowerMac.
+ * by Alan Cox, which was based on the CUDA driver for PowerMac.
* The syntax of the ADB status lines is totally different on MacII,
* though. MacII uses the states Command -> Even -> Odd -> Even ->...-> Idle
* for sending and Idle -> Even -> Odd -> Even ->...-> Idle for receiving.
@@ -387,164 +367,166 @@ static void macii_start(void)
static irqreturn_t macii_interrupt(int irq, void *arg)
{
int x;
- static int entered;
struct adb_request *req;
+ unsigned long flags;
+
+ local_irq_save(flags);
if (!arg) {
/* Clear the SR IRQ flag when polling. */
if (via[IFR] & SR_INT)
via[IFR] = SR_INT;
- else
+ else {
+ local_irq_restore(flags);
return IRQ_NONE;
+ }
}
- BUG_ON(entered++);
-
last_status = status;
- status = via[B] & (ST_MASK|CTLR_IRQ);
+ status = via[B] & (ST_MASK | CTLR_IRQ);
switch (macii_state) {
- case idle:
- if (reading_reply) {
- reply_ptr = current_req->reply;
- } else {
- BUG_ON(current_req != NULL);
- reply_ptr = reply_buf;
- }
+ case idle:
+ if (reading_reply) {
+ reply_ptr = current_req->reply;
+ } else {
+ WARN_ON(current_req);
+ reply_ptr = reply_buf;
+ }
- x = via[SR];
+ x = via[SR];
- if ((status & CTLR_IRQ) && (x == 0xFF)) {
- /* Bus timeout without SRQ sequence:
- * data is "FF" while CTLR_IRQ is "H"
- */
- reply_len = 0;
- srq_asserted = 0;
- macii_state = read_done;
- } else {
- macii_state = reading;
- *reply_ptr = x;
- reply_len = 1;
- }
+ if ((status & CTLR_IRQ) && (x == 0xFF)) {
+ /* Bus timeout without SRQ sequence:
+ * data is "FF" while CTLR_IRQ is "H"
+ */
+ reply_len = 0;
+ srq_asserted = 0;
+ macii_state = read_done;
+ } else {
+ macii_state = reading;
+ *reply_ptr = x;
+ reply_len = 1;
+ }
- /* set ADB state = even for first data byte */
- via[B] = (via[B] & ~ST_MASK) | ST_EVEN;
- break;
+ /* set ADB state = even for first data byte */
+ via[B] = (via[B] & ~ST_MASK) | ST_EVEN;
+ break;
- case sending:
- req = current_req;
- if (data_index >= req->nbytes) {
- req->sent = 1;
- macii_state = idle;
-
- if (req->reply_expected) {
- reading_reply = 1;
- } else {
- req->complete = 1;
- current_req = req->next;
- if (req->done) (*req->done)(req);
-
- if (current_req)
- macii_start();
- else
- if (need_autopoll())
- macii_autopoll(autopoll_devs);
- }
+ case sending:
+ req = current_req;
+ if (data_index >= req->nbytes) {
+ req->sent = 1;
+ macii_state = idle;
- if (macii_state == idle) {
- /* reset to shift in */
- via[ACR] &= ~SR_OUT;
- x = via[SR];
- /* set ADB state idle - might get SRQ */
- via[B] = (via[B] & ~ST_MASK) | ST_IDLE;
- }
+ if (req->reply_expected) {
+ reading_reply = 1;
} else {
- via[SR] = req->data[data_index++];
-
- if ( (via[B] & ST_MASK) == ST_CMD ) {
- /* just sent the command byte, set to EVEN */
- via[B] = (via[B] & ~ST_MASK) | ST_EVEN;
- } else {
- /* invert state bits, toggle ODD/EVEN */
- via[B] ^= ST_MASK;
- }
- }
- break;
-
- case reading:
- x = via[SR];
- BUG_ON((status & ST_MASK) == ST_CMD ||
- (status & ST_MASK) == ST_IDLE);
-
- /* Bus timeout with SRQ sequence:
- * data is "XX FF" while CTLR_IRQ is "L L"
- * End of packet without SRQ sequence:
- * data is "XX...YY 00" while CTLR_IRQ is "L...H L"
- * End of packet SRQ sequence:
- * data is "XX...YY 00" while CTLR_IRQ is "L...L L"
- * (where XX is the first response byte and
- * YY is the last byte of valid response data.)
- */
+ req->complete = 1;
+ current_req = req->next;
+ if (req->done)
+ (*req->done)(req);
- srq_asserted = 0;
- if (!(status & CTLR_IRQ)) {
- if (x == 0xFF) {
- if (!(last_status & CTLR_IRQ)) {
- macii_state = read_done;
- reply_len = 0;
- srq_asserted = 1;
- }
- } else if (x == 0x00) {
- macii_state = read_done;
- if (!(last_status & CTLR_IRQ))
- srq_asserted = 1;
- }
+ if (current_req)
+ macii_start();
+ else if (need_autopoll())
+ macii_autopoll(autopoll_devs);
}
- if (macii_state == reading) {
- BUG_ON(reply_len > 15);
- reply_ptr++;
- *reply_ptr = x;
- reply_len++;
+ if (macii_state == idle) {
+ /* reset to shift in */
+ via[ACR] &= ~SR_OUT;
+ x = via[SR];
+ /* set ADB state idle - might get SRQ */
+ via[B] = (via[B] & ~ST_MASK) | ST_IDLE;
}
+ } else {
+ via[SR] = req->data[data_index++];
- /* invert state bits, toggle ODD/EVEN */
- via[B] ^= ST_MASK;
- break;
+ if ((via[B] & ST_MASK) == ST_CMD) {
+ /* just sent the command byte, set to EVEN */
+ via[B] = (via[B] & ~ST_MASK) | ST_EVEN;
+ } else {
+ /* invert state bits, toggle ODD/EVEN */
+ via[B] ^= ST_MASK;
+ }
+ }
+ break;
- case read_done:
- x = via[SR];
+ case reading:
+ x = via[SR];
+ WARN_ON((status & ST_MASK) == ST_CMD ||
+ (status & ST_MASK) == ST_IDLE);
+
+ /* Bus timeout with SRQ sequence:
+ * data is "XX FF" while CTLR_IRQ is "L L"
+ * End of packet without SRQ sequence:
+ * data is "XX...YY 00" while CTLR_IRQ is "L...H L"
+ * End of packet SRQ sequence:
+ * data is "XX...YY 00" while CTLR_IRQ is "L...L L"
+ * (where XX is the first response byte and
+ * YY is the last byte of valid response data.)
+ */
- if (reading_reply) {
- reading_reply = 0;
- req = current_req;
- req->reply_len = reply_len;
- req->complete = 1;
- current_req = req->next;
- if (req->done) (*req->done)(req);
- } else if (reply_len && autopoll_devs)
- adb_input(reply_buf, reply_len, 0);
+ srq_asserted = 0;
+ if (!(status & CTLR_IRQ)) {
+ if (x == 0xFF) {
+ if (!(last_status & CTLR_IRQ)) {
+ macii_state = read_done;
+ reply_len = 0;
+ srq_asserted = 1;
+ }
+ } else if (x == 0x00) {
+ macii_state = read_done;
+ if (!(last_status & CTLR_IRQ))
+ srq_asserted = 1;
+ }
+ }
- macii_state = idle;
+ if (macii_state == reading &&
+ reply_len < ARRAY_SIZE(reply_buf)) {
+ reply_ptr++;
+ *reply_ptr = x;
+ reply_len++;
+ }
- /* SRQ seen before, initiate poll now */
- if (srq_asserted)
- macii_queue_poll();
+ /* invert state bits, toggle ODD/EVEN */
+ via[B] ^= ST_MASK;
+ break;
- if (current_req)
- macii_start();
- else
- if (need_autopoll())
- macii_autopoll(autopoll_devs);
+ case read_done:
+ x = via[SR];
- if (macii_state == idle)
- via[B] = (via[B] & ~ST_MASK) | ST_IDLE;
- break;
+ if (reading_reply) {
+ reading_reply = 0;
+ req = current_req;
+ req->reply_len = reply_len;
+ req->complete = 1;
+ current_req = req->next;
+ if (req->done)
+ (*req->done)(req);
+ } else if (reply_len && autopoll_devs)
+ adb_input(reply_buf, reply_len, 0);
+
+ macii_state = idle;
+
+ /* SRQ seen before, initiate poll now */
+ if (srq_asserted)
+ macii_queue_poll();
+
+ if (current_req)
+ macii_start();
+ else if (need_autopoll())
+ macii_autopoll(autopoll_devs);
+
+ if (macii_state == idle)
+ via[B] = (via[B] & ~ST_MASK) | ST_IDLE;
+ break;
- default:
+ default:
break;
}
- entered--;
+ local_irq_restore(flags);
return IRQ_HANDLED;
}
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index d72c450aebe5..60f57e2abf21 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -1737,6 +1737,39 @@ pmu_enable_irled(int on)
pmu_wait_complete(&req);
}
+/* Offset between Unix time (1970-based) and Mac time (1904-based) */
+#define RTC_OFFSET 2082844800
+
+time64_t pmu_get_time(void)
+{
+ struct adb_request req;
+ u32 now;
+
+ if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0)
+ return 0;
+ pmu_wait_complete(&req);
+ if (req.reply_len != 4)
+ pr_err("%s: got %d byte reply\n", __func__, req.reply_len);
+ now = (req.reply[0] << 24) + (req.reply[1] << 16) +
+ (req.reply[2] << 8) + req.reply[3];
+ return (time64_t)now - RTC_OFFSET;
+}
+
+int pmu_set_rtc_time(struct rtc_time *tm)
+{
+ u32 now;
+ struct adb_request req;
+
+ now = lower_32_bits(rtc_tm_to_time64(tm) + RTC_OFFSET);
+ if (pmu_request(&req, NULL, 5, PMU_SET_RTC,
+ now >> 24, now >> 16, now >> 8, now) < 0)
+ return -ENXIO;
+ pmu_wait_complete(&req);
+ if (req.reply_len != 0)
+ pr_err("%s: got %d byte reply\n", __func__, req.reply_len);
+ return 0;
+}
+
void
pmu_restart(void)
{
diff --git a/drivers/macintosh/windfarm_smu_controls.c b/drivers/macintosh/windfarm_smu_controls.c
index d174c7437337..86d65462a61c 100644
--- a/drivers/macintosh/windfarm_smu_controls.c
+++ b/drivers/macintosh/windfarm_smu_controls.c
@@ -277,7 +277,7 @@ static int __init smu_controls_init(void)
fct = smu_fan_create(fan, 0);
if (fct == NULL) {
printk(KERN_WARNING "windfarm: Failed to create SMU "
- "RPM fan %s\n", fan->name);
+ "RPM fan %pOFn\n", fan);
continue;
}
list_add(&fct->link, &smu_fans);
@@ -296,7 +296,7 @@ static int __init smu_controls_init(void)
fct = smu_fan_create(fan, 1);
if (fct == NULL) {
printk(KERN_WARNING "windfarm: Failed to create SMU "
- "PWM fan %s\n", fan->name);
+ "PWM fan %pOFn\n", fan);
continue;
}
list_add(&fct->link, &smu_fans);
diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c
index da7f4fc1a51d..a0f61eb853c5 100644
--- a/drivers/macintosh/windfarm_smu_sat.c
+++ b/drivers/macintosh/windfarm_smu_sat.c
@@ -22,14 +22,6 @@
#define VERSION "1.0"
-#define DEBUG
-
-#ifdef DEBUG
-#define DBG(args...) printk(args)
-#else
-#define DBG(args...) do { } while(0)
-#endif
-
/* If the cache is older than 800ms we'll refetch it */
#define MAX_AGE msecs_to_jiffies(800)
@@ -106,13 +98,10 @@ struct smu_sdbp_header *smu_sat_get_sdb_partition(unsigned int sat_id, int id,
buf[i+2] = data[3];
buf[i+3] = data[2];
}
-#ifdef DEBUG
- DBG(KERN_DEBUG "sat %d partition %x:", sat_id, id);
- for (i = 0; i < len; ++i)
- DBG(" %x", buf[i]);
- DBG("\n");
-#endif
+ printk(KERN_DEBUG "sat %d partition %x:", sat_id, id);
+ print_hex_dump(KERN_DEBUG, " ", DUMP_PREFIX_OFFSET,
+ 16, 1, buf, len, false);
if (size)
*size = len;
return (struct smu_sdbp_header *) buf;
@@ -132,13 +121,13 @@ static int wf_sat_read_cache(struct wf_sat *sat)
if (err < 0)
return err;
sat->last_read = jiffies;
+
#ifdef LOTSA_DEBUG
{
int i;
- DBG(KERN_DEBUG "wf_sat_get: data is");
- for (i = 0; i < 16; ++i)
- DBG(" %.2x", sat->cache[i]);
- DBG("\n");
+ printk(KERN_DEBUG "wf_sat_get: data is");
+ print_hex_dump(KERN_DEBUG, " ", DUMP_PREFIX_OFFSET,
+ 16, 1, sat->cache, 16, false);
}
#endif
return 0;
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index 841c005d8ebb..3eeb12e93e98 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -105,12 +105,12 @@ config STI_MBOX
config TI_MESSAGE_MANAGER
tristate "Texas Instruments Message Manager Driver"
- depends on ARCH_KEYSTONE
+ depends on ARCH_KEYSTONE || ARCH_K3
help
An implementation of Message Manager slave driver for Keystone
- architecture SoCs from Texas Instruments. Message Manager is a
- communication entity found on few of Texas Instrument's keystone
- architecture SoCs. These may be used for communication between
+ and K3 architecture SoCs from Texas Instruments. Message Manager
+ is a communication entity found on few of Texas Instrument's keystone
+ and K3 architecture SoCs. These may be used for communication between
multiple processors within the SoC. Select this driver if your
platform has support for the hardware block.
diff --git a/drivers/mailbox/bcm-flexrm-mailbox.c b/drivers/mailbox/bcm-flexrm-mailbox.c
index 8ab077ff58f4..d7a8ed7d8097 100644
--- a/drivers/mailbox/bcm-flexrm-mailbox.c
+++ b/drivers/mailbox/bcm-flexrm-mailbox.c
@@ -375,7 +375,7 @@ static u32 flexrm_estimate_header_desc_count(u32 nhcnt)
return hcnt;
}
-static void flexrm_flip_header_toogle(void *desc_ptr)
+static void flexrm_flip_header_toggle(void *desc_ptr)
{
u64 desc = flexrm_read_desc(desc_ptr);
@@ -709,7 +709,7 @@ static void *flexrm_spu_write_descs(struct brcm_message *msg, u32 nhcnt,
wmb();
/* Flip toggle bit in header */
- flexrm_flip_header_toogle(orig_desc_ptr);
+ flexrm_flip_header_toggle(orig_desc_ptr);
return desc_ptr;
}
@@ -838,7 +838,7 @@ static void *flexrm_sba_write_descs(struct brcm_message *msg, u32 nhcnt,
wmb();
/* Flip toggle bit in header */
- flexrm_flip_header_toogle(orig_desc_ptr);
+ flexrm_flip_header_toggle(orig_desc_ptr);
return desc_ptr;
}
diff --git a/drivers/mailbox/mtk-cmdq-mailbox.c b/drivers/mailbox/mtk-cmdq-mailbox.c
index aec46d5d3506..f7cc29c00302 100644
--- a/drivers/mailbox/mtk-cmdq-mailbox.c
+++ b/drivers/mailbox/mtk-cmdq-mailbox.c
@@ -363,6 +363,9 @@ static int cmdq_mbox_send_data(struct mbox_chan *chan, void *data)
WARN_ON(cmdq->suspended);
task = kzalloc(sizeof(*task), GFP_ATOMIC);
+ if (!task)
+ return -ENOMEM;
+
task->cmdq = cmdq;
INIT_LIST_HEAD(&task->list_entry);
task->pa_base = pkt->pa_base;
diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c
index 311e91b1a14f..256f18b67e8a 100644
--- a/drivers/mailbox/pcc.c
+++ b/drivers/mailbox/pcc.c
@@ -461,8 +461,11 @@ static int __init acpi_pcc_probe(void)
count = acpi_table_parse_entries_array(ACPI_SIG_PCCT,
sizeof(struct acpi_table_pcct), proc,
ACPI_PCCT_TYPE_RESERVED, MAX_PCC_SUBSPACES);
- if (count == 0 || count > MAX_PCC_SUBSPACES) {
- pr_warn("Invalid PCCT: %d PCC subspaces\n", count);
+ if (count <= 0 || count > MAX_PCC_SUBSPACES) {
+ if (count < 0)
+ pr_warn("Error parsing PCC subspaces from PCCT\n");
+ else
+ pr_warn("Invalid PCCT: %d PCC subspaces\n", count);
return -EINVAL;
}
diff --git a/drivers/mailbox/qcom-apcs-ipc-mailbox.c b/drivers/mailbox/qcom-apcs-ipc-mailbox.c
index 333ed4a9d4b8..aed23ac9550d 100644
--- a/drivers/mailbox/qcom-apcs-ipc-mailbox.c
+++ b/drivers/mailbox/qcom-apcs-ipc-mailbox.c
@@ -126,6 +126,7 @@ static const struct of_device_id qcom_apcs_ipc_of_match[] = {
{ .compatible = "qcom,msm8916-apcs-kpss-global", .data = (void *)8 },
{ .compatible = "qcom,msm8996-apcs-hmss-global", .data = (void *)16 },
{ .compatible = "qcom,msm8998-apcs-hmss-global", .data = (void *)8 },
+ { .compatible = "qcom,qcs404-apcs-apps-global", .data = (void *)8 },
{ .compatible = "qcom,sdm845-apss-shared", .data = (void *)12 },
{}
};
diff --git a/drivers/mailbox/ti-msgmgr.c b/drivers/mailbox/ti-msgmgr.c
index 5bceafbf6699..713d701b6568 100644
--- a/drivers/mailbox/ti-msgmgr.c
+++ b/drivers/mailbox/ti-msgmgr.c
@@ -560,8 +560,8 @@ static struct mbox_chan *ti_msgmgr_of_xlate(struct mbox_controller *mbox,
}
err:
- dev_err(inst->dev, "Queue ID %d, Proxy ID %d is wrong on %s\n",
- req_qid, req_pid, p->np->name);
+ dev_err(inst->dev, "Queue ID %d, Proxy ID %d is wrong on %pOFn\n",
+ req_qid, req_pid, p->np);
return ERR_PTR(-ENOENT);
}
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index 8b8c123cae66..3db222509e44 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -215,17 +215,6 @@ config BLK_DEV_DM
If unsure, say N.
-config DM_MQ_DEFAULT
- bool "request-based DM: use blk-mq I/O path by default"
- depends on BLK_DEV_DM
- ---help---
- This option enables the blk-mq based I/O path for request-based
- DM devices by default. With the option the dm_mod.use_blk_mq
- module/boot option defaults to Y, without it to N, but it can
- still be overriden either way.
-
- If unsure say N.
-
config DM_DEBUG
bool "Device mapper debugging support"
depends on BLK_DEV_DM
diff --git a/drivers/md/bcache/alloc.c b/drivers/md/bcache/alloc.c
index 7a28232d868b..5002838ea476 100644
--- a/drivers/md/bcache/alloc.c
+++ b/drivers/md/bcache/alloc.c
@@ -484,7 +484,7 @@ int __bch_bucket_alloc_set(struct cache_set *c, unsigned int reserve,
int i;
lockdep_assert_held(&c->bucket_lock);
- BUG_ON(!n || n > c->caches_loaded || n > 8);
+ BUG_ON(!n || n > c->caches_loaded || n > MAX_CACHES_PER_SET);
bkey_init(k);
diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h
index 954dad29e6e8..b61b83bbcfff 100644
--- a/drivers/md/bcache/bcache.h
+++ b/drivers/md/bcache/bcache.h
@@ -1004,7 +1004,7 @@ void bch_open_buckets_free(struct cache_set *c);
int bch_cache_allocator_start(struct cache *ca);
void bch_debug_exit(void);
-void bch_debug_init(struct kobject *kobj);
+void bch_debug_init(void);
void bch_request_exit(void);
int bch_request_init(void);
diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c
index e7d4817681f2..3f4211b5cd33 100644
--- a/drivers/md/bcache/btree.c
+++ b/drivers/md/bcache/btree.c
@@ -2434,7 +2434,7 @@ static int refill_keybuf_fn(struct btree_op *op, struct btree *b,
struct keybuf *buf = refill->buf;
int ret = MAP_CONTINUE;
- if (bkey_cmp(k, refill->end) >= 0) {
+ if (bkey_cmp(k, refill->end) > 0) {
ret = MAP_DONE;
goto out;
}
diff --git a/drivers/md/bcache/closure.h b/drivers/md/bcache/closure.h
index eca0d496b686..c88cdc4ae4ec 100644
--- a/drivers/md/bcache/closure.h
+++ b/drivers/md/bcache/closure.h
@@ -345,7 +345,8 @@ do { \
} while (0)
/**
- * closure_return - finish execution of a closure, with destructor
+ * closure_return_with_destructor - finish execution of a closure,
+ * with destructor
*
* Works like closure_return(), except @destructor will be called when all
* outstanding refs on @cl have been dropped; @destructor may be used to safely
diff --git a/drivers/md/bcache/debug.c b/drivers/md/bcache/debug.c
index 06da66b2488a..8f448b9c96a1 100644
--- a/drivers/md/bcache/debug.c
+++ b/drivers/md/bcache/debug.c
@@ -253,7 +253,7 @@ void bch_debug_exit(void)
debugfs_remove_recursive(bcache_debug);
}
-void __init bch_debug_init(struct kobject *kobj)
+void __init bch_debug_init(void)
{
/*
* it is unnecessary to check return value of
diff --git a/drivers/md/bcache/extents.c b/drivers/md/bcache/extents.c
index c809724e6571..956004366699 100644
--- a/drivers/md/bcache/extents.c
+++ b/drivers/md/bcache/extents.c
@@ -553,7 +553,7 @@ static bool bch_extent_bad(struct btree_keys *bk, const struct bkey *k)
for (i = 0; i < KEY_PTRS(k); i++) {
stale = ptr_stale(b->c, k, i);
- btree_bug_on(stale > 96, b,
+ btree_bug_on(stale > BUCKET_GC_GEN_MAX, b,
"key too stale: %i, need_gc %u",
stale, b->c->need_gc);
diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c
index 51be355a3309..3bf35914bb57 100644
--- a/drivers/md/bcache/request.c
+++ b/drivers/md/bcache/request.c
@@ -395,7 +395,7 @@ static bool check_should_bypass(struct cached_dev *dc, struct bio *bio)
* unless the read-ahead request is for metadata (eg, for gfs2).
*/
if (bio->bi_opf & (REQ_RAHEAD|REQ_BACKGROUND) &&
- !(bio->bi_opf & REQ_META))
+ !(bio->bi_opf & REQ_PRIO))
goto skip;
if (bio->bi_iter.bi_sector & (c->sb.block_size - 1) ||
@@ -850,7 +850,7 @@ static void cached_dev_read_done_bh(struct closure *cl)
bch_mark_cache_accounting(s->iop.c, s->d,
!s->cache_missed, s->iop.bypass);
- trace_bcache_read(s->orig_bio, !s->cache_miss, s->iop.bypass);
+ trace_bcache_read(s->orig_bio, !s->cache_missed, s->iop.bypass);
if (s->iop.status)
continue_at_nobarrier(cl, cached_dev_read_error, bcache_wq);
@@ -877,7 +877,7 @@ static int cached_dev_cache_miss(struct btree *b, struct search *s,
}
if (!(bio->bi_opf & REQ_RAHEAD) &&
- !(bio->bi_opf & REQ_META) &&
+ !(bio->bi_opf & REQ_PRIO) &&
s->iop.c->gc_stats.in_use < CUTOFF_CACHE_READA)
reada = min_t(sector_t, dc->readahead >> 9,
get_capacity(bio->bi_disk) - bio_end_sector(bio));
@@ -1218,6 +1218,9 @@ static int cached_dev_ioctl(struct bcache_device *d, fmode_t mode,
{
struct cached_dev *dc = container_of(d, struct cached_dev, disk);
+ if (dc->io_disable)
+ return -EIO;
+
return __blkdev_driver_ioctl(dc->bdev, mode, cmd, arg);
}
diff --git a/drivers/md/bcache/request.h b/drivers/md/bcache/request.h
index aa055cfeb099..721bf336ed1a 100644
--- a/drivers/md/bcache/request.h
+++ b/drivers/md/bcache/request.h
@@ -39,6 +39,6 @@ void bch_data_insert(struct closure *cl);
void bch_cached_dev_request_init(struct cached_dev *dc);
void bch_flash_dev_request_init(struct bcache_device *d);
-extern struct kmem_cache *bch_search_cache, *bch_passthrough_cache;
+extern struct kmem_cache *bch_search_cache;
#endif /* _BCACHE_REQUEST_H_ */
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index 30ba9aeb5ee8..7bbd670a5a84 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -418,6 +418,7 @@ static int __uuid_write(struct cache_set *c)
{
BKEY_PADDED(key) k;
struct closure cl;
+ struct cache *ca;
closure_init_stack(&cl);
lockdep_assert_held(&bch_register_lock);
@@ -429,6 +430,10 @@ static int __uuid_write(struct cache_set *c)
uuid_io(c, REQ_OP_WRITE, 0, &k.key, &cl);
closure_sync(&cl);
+ /* Only one bucket used for uuid write */
+ ca = PTR_CACHE(c, &k.key, 0);
+ atomic_long_add(ca->sb.bucket_size, &ca->meta_sectors_written);
+
bkey_copy(&c->uuid_bucket, &k.key);
bkey_put(c, &k.key);
return 0;
@@ -643,10 +648,6 @@ static int ioctl_dev(struct block_device *b, fmode_t mode,
unsigned int cmd, unsigned long arg)
{
struct bcache_device *d = b->bd_disk->private_data;
- struct cached_dev *dc = container_of(d, struct cached_dev, disk);
-
- if (dc->io_disable)
- return -EIO;
return d->ioctl(d, mode, cmd, arg);
}
@@ -1008,6 +1009,7 @@ static void cached_dev_detach_finish(struct work_struct *w)
bch_write_bdev_super(dc, &cl);
closure_sync(&cl);
+ calc_cached_dev_sectors(dc->disk.c);
bcache_device_detach(&dc->disk);
list_move(&dc->list, &uncached_devices);
@@ -1152,11 +1154,12 @@ int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c,
}
if (BDEV_STATE(&dc->sb) == BDEV_STATE_DIRTY) {
- bch_sectors_dirty_init(&dc->disk);
atomic_set(&dc->has_dirty, 1);
bch_writeback_queue(dc);
}
+ bch_sectors_dirty_init(&dc->disk);
+
bch_cached_dev_run(dc);
bcache_device_link(&dc->disk, c, "bdev");
atomic_inc(&c->attached_dev_nr);
@@ -2049,6 +2052,8 @@ static int cache_alloc(struct cache *ca)
size_t free;
size_t btree_buckets;
struct bucket *b;
+ int ret = -ENOMEM;
+ const char *err = NULL;
__module_get(THIS_MODULE);
kobject_init(&ca->kobj, &bch_cache_ktype);
@@ -2066,27 +2071,93 @@ static int cache_alloc(struct cache *ca)
*/
btree_buckets = ca->sb.njournal_buckets ?: 8;
free = roundup_pow_of_two(ca->sb.nbuckets) >> 10;
+ if (!free) {
+ ret = -EPERM;
+ err = "ca->sb.nbuckets is too small";
+ goto err_free;
+ }
- if (!init_fifo(&ca->free[RESERVE_BTREE], btree_buckets, GFP_KERNEL) ||
- !init_fifo_exact(&ca->free[RESERVE_PRIO], prio_buckets(ca), GFP_KERNEL) ||
- !init_fifo(&ca->free[RESERVE_MOVINGGC], free, GFP_KERNEL) ||
- !init_fifo(&ca->free[RESERVE_NONE], free, GFP_KERNEL) ||
- !init_fifo(&ca->free_inc, free << 2, GFP_KERNEL) ||
- !init_heap(&ca->heap, free << 3, GFP_KERNEL) ||
- !(ca->buckets = vzalloc(array_size(sizeof(struct bucket),
- ca->sb.nbuckets))) ||
- !(ca->prio_buckets = kzalloc(array3_size(sizeof(uint64_t),
- prio_buckets(ca), 2),
- GFP_KERNEL)) ||
- !(ca->disk_buckets = alloc_bucket_pages(GFP_KERNEL, ca)))
- return -ENOMEM;
+ if (!init_fifo(&ca->free[RESERVE_BTREE], btree_buckets,
+ GFP_KERNEL)) {
+ err = "ca->free[RESERVE_BTREE] alloc failed";
+ goto err_btree_alloc;
+ }
+
+ if (!init_fifo_exact(&ca->free[RESERVE_PRIO], prio_buckets(ca),
+ GFP_KERNEL)) {
+ err = "ca->free[RESERVE_PRIO] alloc failed";
+ goto err_prio_alloc;
+ }
+
+ if (!init_fifo(&ca->free[RESERVE_MOVINGGC], free, GFP_KERNEL)) {
+ err = "ca->free[RESERVE_MOVINGGC] alloc failed";
+ goto err_movinggc_alloc;
+ }
+
+ if (!init_fifo(&ca->free[RESERVE_NONE], free, GFP_KERNEL)) {
+ err = "ca->free[RESERVE_NONE] alloc failed";
+ goto err_none_alloc;
+ }
+
+ if (!init_fifo(&ca->free_inc, free << 2, GFP_KERNEL)) {
+ err = "ca->free_inc alloc failed";
+ goto err_free_inc_alloc;
+ }
+
+ if (!init_heap(&ca->heap, free << 3, GFP_KERNEL)) {
+ err = "ca->heap alloc failed";
+ goto err_heap_alloc;
+ }
+
+ ca->buckets = vzalloc(array_size(sizeof(struct bucket),
+ ca->sb.nbuckets));
+ if (!ca->buckets) {
+ err = "ca->buckets alloc failed";
+ goto err_buckets_alloc;
+ }
+
+ ca->prio_buckets = kzalloc(array3_size(sizeof(uint64_t),
+ prio_buckets(ca), 2),
+ GFP_KERNEL);
+ if (!ca->prio_buckets) {
+ err = "ca->prio_buckets alloc failed";
+ goto err_prio_buckets_alloc;
+ }
+
+ ca->disk_buckets = alloc_bucket_pages(GFP_KERNEL, ca);
+ if (!ca->disk_buckets) {
+ err = "ca->disk_buckets alloc failed";
+ goto err_disk_buckets_alloc;
+ }
ca->prio_last_buckets = ca->prio_buckets + prio_buckets(ca);
for_each_bucket(b, ca)
atomic_set(&b->pin, 0);
-
return 0;
+
+err_disk_buckets_alloc:
+ kfree(ca->prio_buckets);
+err_prio_buckets_alloc:
+ vfree(ca->buckets);
+err_buckets_alloc:
+ free_heap(&ca->heap);
+err_heap_alloc:
+ free_fifo(&ca->free_inc);
+err_free_inc_alloc:
+ free_fifo(&ca->free[RESERVE_NONE]);
+err_none_alloc:
+ free_fifo(&ca->free[RESERVE_MOVINGGC]);
+err_movinggc_alloc:
+ free_fifo(&ca->free[RESERVE_PRIO]);
+err_prio_alloc:
+ free_fifo(&ca->free[RESERVE_BTREE]);
+err_btree_alloc:
+err_free:
+ module_put(THIS_MODULE);
+ if (err)
+ pr_notice("error %s: %s", ca->cache_dev_name, err);
+ return ret;
}
static int register_cache(struct cache_sb *sb, struct page *sb_page,
@@ -2112,6 +2183,8 @@ static int register_cache(struct cache_sb *sb, struct page *sb_page,
blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
if (ret == -ENOMEM)
err = "cache_alloc(): -ENOMEM";
+ else if (ret == -EPERM)
+ err = "cache_alloc(): cache device is too small";
else
err = "cache_alloc(): unknown error";
goto err;
@@ -2386,7 +2459,7 @@ static int __init bcache_init(void)
sysfs_create_files(bcache_kobj, files))
goto err;
- bch_debug_init(bcache_kobj);
+ bch_debug_init();
closure_debug_init();
return 0;
diff --git a/drivers/md/bcache/sysfs.c b/drivers/md/bcache/sysfs.c
index 150cf4f4cf74..26f035a0c5b9 100644
--- a/drivers/md/bcache/sysfs.c
+++ b/drivers/md/bcache/sysfs.c
@@ -285,6 +285,7 @@ STORE(__cached_dev)
1, WRITEBACK_RATE_UPDATE_SECS_MAX);
d_strtoul(writeback_rate_i_term_inverse);
d_strtoul_nonzero(writeback_rate_p_term_inverse);
+ d_strtoul_nonzero(writeback_rate_minimum);
sysfs_strtoul_clamp(io_error_limit, dc->error_limit, 0, INT_MAX);
@@ -412,6 +413,7 @@ static struct attribute *bch_cached_dev_files[] = {
&sysfs_writeback_rate_update_seconds,
&sysfs_writeback_rate_i_term_inverse,
&sysfs_writeback_rate_p_term_inverse,
+ &sysfs_writeback_rate_minimum,
&sysfs_writeback_rate_debug,
&sysfs_errors,
&sysfs_io_error_limit,
diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c
index 69dddeab124c..5936de71883f 100644
--- a/drivers/md/dm-cache-metadata.c
+++ b/drivers/md/dm-cache-metadata.c
@@ -1455,8 +1455,8 @@ static int __load_mappings(struct dm_cache_metadata *cmd,
if (hints_valid) {
r = dm_array_cursor_next(&cmd->hint_cursor);
if (r) {
- DMERR("dm_array_cursor_next for hint failed");
- goto out;
+ dm_array_cursor_end(&cmd->hint_cursor);
+ hints_valid = false;
}
}
diff --git a/drivers/md/dm-cache-policy-smq.c b/drivers/md/dm-cache-policy-smq.c
index 1b5b9ad9e492..b61aac00ff40 100644
--- a/drivers/md/dm-cache-policy-smq.c
+++ b/drivers/md/dm-cache-policy-smq.c
@@ -1200,7 +1200,7 @@ static void queue_demotion(struct smq_policy *mq)
struct policy_work work;
struct entry *e;
- if (unlikely(WARN_ON_ONCE(!mq->migrations_allowed)))
+ if (WARN_ON_ONCE(!mq->migrations_allowed))
return;
e = q_peek(&mq->clean, mq->clean.nr_levels / 2, true);
diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c
index a53413371725..b29a8327eed1 100644
--- a/drivers/md/dm-cache-target.c
+++ b/drivers/md/dm-cache-target.c
@@ -3009,8 +3009,13 @@ static dm_cblock_t get_cache_dev_size(struct cache *cache)
static bool can_resize(struct cache *cache, dm_cblock_t new_size)
{
- if (from_cblock(new_size) > from_cblock(cache->cache_size))
- return true;
+ if (from_cblock(new_size) > from_cblock(cache->cache_size)) {
+ if (cache->sized) {
+ DMERR("%s: unable to extend cache due to missing cache table reload",
+ cache_device_name(cache));
+ return false;
+ }
+ }
/*
* We can't drop a dirty block when shrinking the cache.
@@ -3479,14 +3484,13 @@ static int __init dm_cache_init(void)
int r;
migration_cache = KMEM_CACHE(dm_cache_migration, 0);
- if (!migration_cache) {
- dm_unregister_target(&cache_target);
+ if (!migration_cache)
return -ENOMEM;
- }
r = dm_register_target(&cache_target);
if (r) {
DMERR("cache target registration failed: %d", r);
+ kmem_cache_destroy(migration_cache);
return r;
}
diff --git a/drivers/md/dm-core.h b/drivers/md/dm-core.h
index 7d480c930eaf..224d44503a06 100644
--- a/drivers/md/dm-core.h
+++ b/drivers/md/dm-core.h
@@ -112,18 +112,8 @@ struct mapped_device {
struct dm_stats stats;
- struct kthread_worker kworker;
- struct task_struct *kworker_task;
-
- /* for request-based merge heuristic in dm_request_fn() */
- unsigned seq_rq_merge_deadline_usecs;
- int last_rq_rw;
- sector_t last_rq_pos;
- ktime_t last_rq_start_time;
-
/* for blk-mq request-based DM support */
struct blk_mq_tag_set *tag_set;
- bool use_blk_mq:1;
bool init_tio_pdu:1;
struct srcu_struct io_barrier;
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 0481223b1deb..b8eec515a003 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -2661,6 +2661,7 @@ static int crypt_ctr_optional(struct dm_target *ti, unsigned int argc, char **ar
static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
{
struct crypt_config *cc;
+ const char *devname = dm_table_device_name(ti->table);
int key_size;
unsigned int align_mask;
unsigned long long tmpll;
@@ -2806,18 +2807,22 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
}
ret = -ENOMEM;
- cc->io_queue = alloc_workqueue("kcryptd_io", WQ_HIGHPRI | WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM, 1);
+ cc->io_queue = alloc_workqueue("kcryptd_io/%s",
+ WQ_HIGHPRI | WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM,
+ 1, devname);
if (!cc->io_queue) {
ti->error = "Couldn't create kcryptd io queue";
goto bad;
}
if (test_bit(DM_CRYPT_SAME_CPU, &cc->flags))
- cc->crypt_queue = alloc_workqueue("kcryptd", WQ_HIGHPRI | WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM, 1);
+ cc->crypt_queue = alloc_workqueue("kcryptd/%s",
+ WQ_HIGHPRI | WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM,
+ 1, devname);
else
- cc->crypt_queue = alloc_workqueue("kcryptd",
+ cc->crypt_queue = alloc_workqueue("kcryptd/%s",
WQ_HIGHPRI | WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM | WQ_UNBOUND,
- num_online_cpus());
+ num_online_cpus(), devname);
if (!cc->crypt_queue) {
ti->error = "Couldn't create kcryptd queue";
goto bad;
@@ -2826,7 +2831,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
spin_lock_init(&cc->write_thread_lock);
cc->write_tree = RB_ROOT;
- cc->write_thread = kthread_create(dmcrypt_write, cc, "dmcrypt_write");
+ cc->write_thread = kthread_create(dmcrypt_write, cc, "dmcrypt_write/%s", devname);
if (IS_ERR(cc->write_thread)) {
ret = PTR_ERR(cc->write_thread);
cc->write_thread = NULL;
diff --git a/drivers/md/dm-flakey.c b/drivers/md/dm-flakey.c
index 21d126a5078c..3cb97fa4c11d 100644
--- a/drivers/md/dm-flakey.c
+++ b/drivers/md/dm-flakey.c
@@ -315,10 +315,6 @@ static int flakey_map(struct dm_target *ti, struct bio *bio)
if (bio_op(bio) == REQ_OP_ZONE_RESET)
goto map_bio;
- /* We need to remap reported zones, so remember the BIO iter */
- if (bio_op(bio) == REQ_OP_ZONE_REPORT)
- goto map_bio;
-
/* Are we alive ? */
elapsed = (jiffies - fc->start_time) / HZ;
if (elapsed % (fc->up_interval + fc->down_interval) >= fc->up_interval) {
@@ -380,11 +376,6 @@ static int flakey_end_io(struct dm_target *ti, struct bio *bio,
if (bio_op(bio) == REQ_OP_ZONE_RESET)
return DM_ENDIO_DONE;
- if (bio_op(bio) == REQ_OP_ZONE_REPORT) {
- dm_remap_zone_report(ti, bio, fc->start);
- return DM_ENDIO_DONE;
- }
-
if (!*error && pb->bio_submitted && (bio_data_dir(bio) == READ)) {
if (fc->corrupt_bio_byte && (fc->corrupt_bio_rw == READ) &&
all_corrupt_bio_flags_match(bio, fc)) {
@@ -457,6 +448,26 @@ static int flakey_prepare_ioctl(struct dm_target *ti, struct block_device **bdev
return 0;
}
+#ifdef CONFIG_BLK_DEV_ZONED
+static int flakey_report_zones(struct dm_target *ti, sector_t sector,
+ struct blk_zone *zones, unsigned int *nr_zones,
+ gfp_t gfp_mask)
+{
+ struct flakey_c *fc = ti->private;
+ int ret;
+
+ /* Do report and remap it */
+ ret = blkdev_report_zones(fc->dev->bdev, flakey_map_sector(ti, sector),
+ zones, nr_zones, gfp_mask);
+ if (ret != 0)
+ return ret;
+
+ if (*nr_zones)
+ dm_remap_zone_report(ti, fc->start, zones, nr_zones);
+ return 0;
+}
+#endif
+
static int flakey_iterate_devices(struct dm_target *ti, iterate_devices_callout_fn fn, void *data)
{
struct flakey_c *fc = ti->private;
@@ -467,7 +478,10 @@ static int flakey_iterate_devices(struct dm_target *ti, iterate_devices_callout_
static struct target_type flakey_target = {
.name = "flakey",
.version = {1, 5, 0},
+#ifdef CONFIG_BLK_DEV_ZONED
.features = DM_TARGET_ZONED_HM,
+ .report_zones = flakey_report_zones,
+#endif
.module = THIS_MODULE,
.ctr = flakey_ctr,
.dtr = flakey_dtr,
diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c
index 89ccb64342de..bb3096bf2cc6 100644
--- a/drivers/md/dm-integrity.c
+++ b/drivers/md/dm-integrity.c
@@ -559,7 +559,12 @@ static void section_mac(struct dm_integrity_c *ic, unsigned section, __u8 result
}
memset(result + size, 0, JOURNAL_MAC_SIZE - size);
} else {
- __u8 digest[size];
+ __u8 digest[HASH_MAX_DIGESTSIZE];
+
+ if (WARN_ON(size > sizeof(digest))) {
+ dm_integrity_io_error(ic, "digest_size", -EINVAL);
+ goto err;
+ }
r = crypto_shash_final(desc, digest);
if (unlikely(r)) {
dm_integrity_io_error(ic, "crypto_shash_final", r);
@@ -1324,7 +1329,7 @@ static void integrity_metadata(struct work_struct *w)
struct bio *bio = dm_bio_from_per_bio_data(dio, sizeof(struct dm_integrity_io));
char *checksums;
unsigned extra_space = unlikely(digest_size > ic->tag_size) ? digest_size - ic->tag_size : 0;
- char checksums_onstack[ic->tag_size + extra_space];
+ char checksums_onstack[HASH_MAX_DIGESTSIZE];
unsigned sectors_to_process = dio->range.n_sectors;
sector_t sector = dio->range.logical_sector;
@@ -1333,8 +1338,14 @@ static void integrity_metadata(struct work_struct *w)
checksums = kmalloc((PAGE_SIZE >> SECTOR_SHIFT >> ic->sb->log2_sectors_per_block) * ic->tag_size + extra_space,
GFP_NOIO | __GFP_NORETRY | __GFP_NOWARN);
- if (!checksums)
+ if (!checksums) {
checksums = checksums_onstack;
+ if (WARN_ON(extra_space &&
+ digest_size > sizeof(checksums_onstack))) {
+ r = -EINVAL;
+ goto error;
+ }
+ }
__bio_for_each_segment(bv, bio, iter, dio->orig_bi_iter) {
unsigned pos;
@@ -1546,7 +1557,7 @@ retry_kmap:
} while (++s < ic->sectors_per_block);
#ifdef INTERNAL_VERIFY
if (ic->internal_hash) {
- char checksums_onstack[max(crypto_shash_digestsize(ic->internal_hash), ic->tag_size)];
+ char checksums_onstack[max(HASH_MAX_DIGESTSIZE, MAX_TAG_SIZE)];
integrity_sector_checksum(ic, logical_sector, mem + bv.bv_offset, checksums_onstack);
if (unlikely(memcmp(checksums_onstack, journal_entry_tag(ic, je), ic->tag_size))) {
@@ -1596,7 +1607,7 @@ retry_kmap:
if (ic->internal_hash) {
unsigned digest_size = crypto_shash_digestsize(ic->internal_hash);
if (unlikely(digest_size > ic->tag_size)) {
- char checksums_onstack[digest_size];
+ char checksums_onstack[HASH_MAX_DIGESTSIZE];
integrity_sector_checksum(ic, logical_sector, (char *)js, checksums_onstack);
memcpy(journal_entry_tag(ic, je), checksums_onstack, ic->tag_size);
} else
@@ -2023,7 +2034,7 @@ static void do_journal_write(struct dm_integrity_c *ic, unsigned write_start,
unlikely(from_replay) &&
#endif
ic->internal_hash) {
- char test_tag[max(crypto_shash_digestsize(ic->internal_hash), ic->tag_size)];
+ char test_tag[max_t(size_t, HASH_MAX_DIGESTSIZE, MAX_TAG_SIZE)];
integrity_sector_checksum(ic, sec + ((l - j) << ic->sb->log2_sectors_per_block),
(char *)access_journal_data(ic, i, l), test_tag);
@@ -3462,7 +3473,8 @@ try_smaller_buffer:
r = -ENOMEM;
goto bad;
}
- ic->recalc_tags = kvmalloc((RECALC_SECTORS >> ic->sb->log2_sectors_per_block) * ic->tag_size, GFP_KERNEL);
+ ic->recalc_tags = kvmalloc_array(RECALC_SECTORS >> ic->sb->log2_sectors_per_block,
+ ic->tag_size, GFP_KERNEL);
if (!ic->recalc_tags) {
ti->error = "Cannot allocate tags for recalculating";
r = -ENOMEM;
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index b810ea77e6b1..f666778ad237 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -1720,8 +1720,7 @@ static void free_params(struct dm_ioctl *param, size_t param_size, int param_fla
}
static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl *param_kernel,
- int ioctl_flags,
- struct dm_ioctl **param, int *param_flags)
+ int ioctl_flags, struct dm_ioctl **param, int *param_flags)
{
struct dm_ioctl *dmi;
int secure_data;
@@ -1762,18 +1761,13 @@ static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl *param_kern
*param_flags |= DM_PARAMS_MALLOC;
- if (copy_from_user(dmi, user, param_kernel->data_size))
- goto bad;
+ /* Copy from param_kernel (which was already copied from user) */
+ memcpy(dmi, param_kernel, minimum_data_size);
-data_copied:
- /*
- * Abort if something changed the ioctl data while it was being copied.
- */
- if (dmi->data_size != param_kernel->data_size) {
- DMERR("rejecting ioctl: data size modified while processing parameters");
+ if (copy_from_user(&dmi->data, (char __user *)user + minimum_data_size,
+ param_kernel->data_size - minimum_data_size))
goto bad;
- }
-
+data_copied:
/* Wipe the user buffer so we do not return it to userspace */
if (secure_data && clear_user(user, param_kernel->data_size))
goto bad;
diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c
index d10964d41fd7..8d7ddee6ac4d 100644
--- a/drivers/md/dm-linear.c
+++ b/drivers/md/dm-linear.c
@@ -102,17 +102,6 @@ static int linear_map(struct dm_target *ti, struct bio *bio)
return DM_MAPIO_REMAPPED;
}
-static int linear_end_io(struct dm_target *ti, struct bio *bio,
- blk_status_t *error)
-{
- struct linear_c *lc = ti->private;
-
- if (!*error && bio_op(bio) == REQ_OP_ZONE_REPORT)
- dm_remap_zone_report(ti, bio, lc->start);
-
- return DM_ENDIO_DONE;
-}
-
static void linear_status(struct dm_target *ti, status_type_t type,
unsigned status_flags, char *result, unsigned maxlen)
{
@@ -146,6 +135,26 @@ static int linear_prepare_ioctl(struct dm_target *ti, struct block_device **bdev
return 0;
}
+#ifdef CONFIG_BLK_DEV_ZONED
+static int linear_report_zones(struct dm_target *ti, sector_t sector,
+ struct blk_zone *zones, unsigned int *nr_zones,
+ gfp_t gfp_mask)
+{
+ struct linear_c *lc = (struct linear_c *) ti->private;
+ int ret;
+
+ /* Do report and remap it */
+ ret = blkdev_report_zones(lc->dev->bdev, linear_map_sector(ti, sector),
+ zones, nr_zones, gfp_mask);
+ if (ret != 0)
+ return ret;
+
+ if (*nr_zones)
+ dm_remap_zone_report(ti, lc->start, zones, nr_zones);
+ return 0;
+}
+#endif
+
static int linear_iterate_devices(struct dm_target *ti,
iterate_devices_callout_fn fn, void *data)
{
@@ -208,12 +217,16 @@ static size_t linear_dax_copy_to_iter(struct dm_target *ti, pgoff_t pgoff,
static struct target_type linear_target = {
.name = "linear",
.version = {1, 4, 0},
+#ifdef CONFIG_BLK_DEV_ZONED
.features = DM_TARGET_PASSES_INTEGRITY | DM_TARGET_ZONED_HM,
+ .report_zones = linear_report_zones,
+#else
+ .features = DM_TARGET_PASSES_INTEGRITY,
+#endif
.module = THIS_MODULE,
.ctr = linear_ctr,
.dtr = linear_dtr,
.map = linear_map,
- .end_io = linear_end_io,
.status = linear_status,
.prepare_ioctl = linear_prepare_ioctl,
.iterate_devices = linear_iterate_devices,
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index d94ba6f72ff5..d6a66921daf4 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -203,14 +203,7 @@ static struct multipath *alloc_multipath(struct dm_target *ti)
static int alloc_multipath_stage2(struct dm_target *ti, struct multipath *m)
{
if (m->queue_mode == DM_TYPE_NONE) {
- /*
- * Default to request-based.
- */
- if (dm_use_blk_mq(dm_table_get_md(ti->table)))
- m->queue_mode = DM_TYPE_MQ_REQUEST_BASED;
- else
- m->queue_mode = DM_TYPE_REQUEST_BASED;
-
+ m->queue_mode = DM_TYPE_REQUEST_BASED;
} else if (m->queue_mode == DM_TYPE_BIO_BASED) {
INIT_WORK(&m->process_queued_bios, process_queued_bios);
/*
@@ -537,10 +530,7 @@ static int multipath_clone_and_map(struct dm_target *ti, struct request *rq,
* get the queue busy feedback (via BLK_STS_RESOURCE),
* otherwise I/O merging can suffer.
*/
- if (q->mq_ops)
- return DM_MAPIO_REQUEUE;
- else
- return DM_MAPIO_DELAY_REQUEUE;
+ return DM_MAPIO_REQUEUE;
}
clone->bio = clone->biotail = NULL;
clone->rq_disk = bdev->bd_disk;
@@ -668,7 +658,7 @@ static int multipath_map_bio(struct dm_target *ti, struct bio *bio)
static void process_queued_io_list(struct multipath *m)
{
- if (m->queue_mode == DM_TYPE_MQ_REQUEST_BASED)
+ if (m->queue_mode == DM_TYPE_REQUEST_BASED)
dm_mq_kick_requeue_list(dm_table_get_md(m->ti->table));
else if (m->queue_mode == DM_TYPE_BIO_BASED)
queue_work(kmultipathd, &m->process_queued_bios);
@@ -806,19 +796,19 @@ static int parse_path_selector(struct dm_arg_set *as, struct priority_group *pg,
}
static int setup_scsi_dh(struct block_device *bdev, struct multipath *m,
- const char *attached_handler_name, char **error)
+ const char **attached_handler_name, char **error)
{
struct request_queue *q = bdev_get_queue(bdev);
int r;
if (test_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, &m->flags)) {
retain:
- if (attached_handler_name) {
+ if (*attached_handler_name) {
/*
* Clear any hw_handler_params associated with a
* handler that isn't already attached.
*/
- if (m->hw_handler_name && strcmp(attached_handler_name, m->hw_handler_name)) {
+ if (m->hw_handler_name && strcmp(*attached_handler_name, m->hw_handler_name)) {
kfree(m->hw_handler_params);
m->hw_handler_params = NULL;
}
@@ -830,7 +820,8 @@ retain:
* handler instead of the original table passed in.
*/
kfree(m->hw_handler_name);
- m->hw_handler_name = attached_handler_name;
+ m->hw_handler_name = *attached_handler_name;
+ *attached_handler_name = NULL;
}
}
@@ -867,7 +858,7 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps
struct pgpath *p;
struct multipath *m = ti->private;
struct request_queue *q;
- const char *attached_handler_name;
+ const char *attached_handler_name = NULL;
/* we need at least a path arg */
if (as->argc < 1) {
@@ -890,7 +881,7 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps
attached_handler_name = scsi_dh_attached_handler_name(q, GFP_KERNEL);
if (attached_handler_name || m->hw_handler_name) {
INIT_DELAYED_WORK(&p->activate_path, activate_path_work);
- r = setup_scsi_dh(p->path.dev->bdev, m, attached_handler_name, &ti->error);
+ r = setup_scsi_dh(p->path.dev->bdev, m, &attached_handler_name, &ti->error);
if (r) {
dm_put_device(ti, p->path.dev);
goto bad;
@@ -905,6 +896,7 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps
return p;
bad:
+ kfree(attached_handler_name);
free_pgpath(p);
return ERR_PTR(r);
}
@@ -1087,10 +1079,9 @@ static int parse_features(struct dm_arg_set *as, struct multipath *m)
if (!strcasecmp(queue_mode_name, "bio"))
m->queue_mode = DM_TYPE_BIO_BASED;
- else if (!strcasecmp(queue_mode_name, "rq"))
+ else if (!strcasecmp(queue_mode_name, "rq") ||
+ !strcasecmp(queue_mode_name, "mq"))
m->queue_mode = DM_TYPE_REQUEST_BASED;
- else if (!strcasecmp(queue_mode_name, "mq"))
- m->queue_mode = DM_TYPE_MQ_REQUEST_BASED;
else {
ti->error = "Unknown 'queue_mode' requested";
r = -EINVAL;
@@ -1724,9 +1715,6 @@ static void multipath_status(struct dm_target *ti, status_type_t type,
case DM_TYPE_BIO_BASED:
DMEMIT("queue_mode bio ");
break;
- case DM_TYPE_MQ_REQUEST_BASED:
- DMEMIT("queue_mode mq ");
- break;
default:
WARN_ON_ONCE(true);
break;
@@ -1970,7 +1958,7 @@ static int multipath_busy(struct dm_target *ti)
/* no paths available, for blk-mq: rely on IO mapping to delay requeue */
if (!atomic_read(&m->nr_valid_paths) && test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags))
- return (m->queue_mode != DM_TYPE_MQ_REQUEST_BASED);
+ return (m->queue_mode != DM_TYPE_REQUEST_BASED);
/* Guess which priority_group will be used at next mapping time */
pg = READ_ONCE(m->current_pg);
diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c
index 5ba067fa0c72..e1dd1622a290 100644
--- a/drivers/md/dm-raid.c
+++ b/drivers/md/dm-raid.c
@@ -2475,7 +2475,7 @@ static int super_validate(struct raid_set *rs, struct md_rdev *rdev)
}
/* Enable bitmap creation for RAID levels != 0 */
- mddev->bitmap_info.offset = rt_is_raid0(rs->raid_type) ? 0 : to_sector(4096);
+ mddev->bitmap_info.offset = (rt_is_raid0(rs->raid_type) || rs->journal_dev.dev) ? 0 : to_sector(4096);
mddev->bitmap_info.default_offset = mddev->bitmap_info.offset;
if (!test_and_clear_bit(FirstUse, &rdev->flags)) {
@@ -3353,7 +3353,7 @@ static const char *sync_str(enum sync_state state)
};
/* Return enum sync_state for @mddev derived from @recovery flags */
-static const enum sync_state decipher_sync_action(struct mddev *mddev, unsigned long recovery)
+static enum sync_state decipher_sync_action(struct mddev *mddev, unsigned long recovery)
{
if (test_bit(MD_RECOVERY_FROZEN, &recovery))
return st_frozen;
diff --git a/drivers/md/dm-rq.c b/drivers/md/dm-rq.c
index 6e547b8dd298..7cd36e4d1310 100644
--- a/drivers/md/dm-rq.c
+++ b/drivers/md/dm-rq.c
@@ -23,19 +23,6 @@ static unsigned dm_mq_queue_depth = DM_MQ_QUEUE_DEPTH;
#define RESERVED_REQUEST_BASED_IOS 256
static unsigned reserved_rq_based_ios = RESERVED_REQUEST_BASED_IOS;
-static bool use_blk_mq = IS_ENABLED(CONFIG_DM_MQ_DEFAULT);
-
-bool dm_use_blk_mq_default(void)
-{
- return use_blk_mq;
-}
-
-bool dm_use_blk_mq(struct mapped_device *md)
-{
- return md->use_blk_mq;
-}
-EXPORT_SYMBOL_GPL(dm_use_blk_mq);
-
unsigned dm_get_reserved_rq_based_ios(void)
{
return __dm_get_module_param(&reserved_rq_based_ios,
@@ -59,41 +46,13 @@ int dm_request_based(struct mapped_device *md)
return queue_is_rq_based(md->queue);
}
-static void dm_old_start_queue(struct request_queue *q)
-{
- unsigned long flags;
-
- spin_lock_irqsave(q->queue_lock, flags);
- if (blk_queue_stopped(q))
- blk_start_queue(q);
- spin_unlock_irqrestore(q->queue_lock, flags);
-}
-
-static void dm_mq_start_queue(struct request_queue *q)
+void dm_start_queue(struct request_queue *q)
{
blk_mq_unquiesce_queue(q);
blk_mq_kick_requeue_list(q);
}
-void dm_start_queue(struct request_queue *q)
-{
- if (!q->mq_ops)
- dm_old_start_queue(q);
- else
- dm_mq_start_queue(q);
-}
-
-static void dm_old_stop_queue(struct request_queue *q)
-{
- unsigned long flags;
-
- spin_lock_irqsave(q->queue_lock, flags);
- if (!blk_queue_stopped(q))
- blk_stop_queue(q);
- spin_unlock_irqrestore(q->queue_lock, flags);
-}
-
-static void dm_mq_stop_queue(struct request_queue *q)
+void dm_stop_queue(struct request_queue *q)
{
if (blk_mq_queue_stopped(q))
return;
@@ -101,14 +60,6 @@ static void dm_mq_stop_queue(struct request_queue *q)
blk_mq_quiesce_queue(q);
}
-void dm_stop_queue(struct request_queue *q)
-{
- if (!q->mq_ops)
- dm_old_stop_queue(q);
- else
- dm_mq_stop_queue(q);
-}
-
/*
* Partial completion handling for request-based dm
*/
@@ -179,9 +130,6 @@ static void rq_end_stats(struct mapped_device *md, struct request *orig)
*/
static void rq_completed(struct mapped_device *md, int rw, bool run_queue)
{
- struct request_queue *q = md->queue;
- unsigned long flags;
-
atomic_dec(&md->pending[rw]);
/* nudge anyone waiting on suspend queue */
@@ -189,18 +137,6 @@ static void rq_completed(struct mapped_device *md, int rw, bool run_queue)
wake_up(&md->wait);
/*
- * Run this off this callpath, as drivers could invoke end_io while
- * inside their request_fn (and holding the queue lock). Calling
- * back into ->request_fn() could deadlock attempting to grab the
- * queue lock again.
- */
- if (!q->mq_ops && run_queue) {
- spin_lock_irqsave(q->queue_lock, flags);
- blk_run_queue_async(q);
- spin_unlock_irqrestore(q->queue_lock, flags);
- }
-
- /*
* dm_put() must be at the end of this function. See the comment above
*/
dm_put(md);
@@ -222,27 +158,10 @@ static void dm_end_request(struct request *clone, blk_status_t error)
tio->ti->type->release_clone_rq(clone);
rq_end_stats(md, rq);
- if (!rq->q->mq_ops)
- blk_end_request_all(rq, error);
- else
- blk_mq_end_request(rq, error);
+ blk_mq_end_request(rq, error);
rq_completed(md, rw, true);
}
-/*
- * Requeue the original request of a clone.
- */
-static void dm_old_requeue_request(struct request *rq, unsigned long delay_ms)
-{
- struct request_queue *q = rq->q;
- unsigned long flags;
-
- spin_lock_irqsave(q->queue_lock, flags);
- blk_requeue_request(q, rq);
- blk_delay_queue(q, delay_ms);
- spin_unlock_irqrestore(q->queue_lock, flags);
-}
-
static void __dm_mq_kick_requeue_list(struct request_queue *q, unsigned long msecs)
{
blk_mq_delay_kick_requeue_list(q, msecs);
@@ -273,11 +192,7 @@ static void dm_requeue_original_request(struct dm_rq_target_io *tio, bool delay_
tio->ti->type->release_clone_rq(tio->clone);
}
- if (!rq->q->mq_ops)
- dm_old_requeue_request(rq, delay_ms);
- else
- dm_mq_delay_requeue_request(rq, delay_ms);
-
+ dm_mq_delay_requeue_request(rq, delay_ms);
rq_completed(md, rw, false);
}
@@ -340,10 +255,7 @@ static void dm_softirq_done(struct request *rq)
rq_end_stats(md, rq);
rw = rq_data_dir(rq);
- if (!rq->q->mq_ops)
- blk_end_request_all(rq, tio->error);
- else
- blk_mq_end_request(rq, tio->error);
+ blk_mq_end_request(rq, tio->error);
rq_completed(md, rw, false);
return;
}
@@ -363,17 +275,14 @@ static void dm_complete_request(struct request *rq, blk_status_t error)
struct dm_rq_target_io *tio = tio_from_request(rq);
tio->error = error;
- if (!rq->q->mq_ops)
- blk_complete_request(rq);
- else
- blk_mq_complete_request(rq);
+ blk_mq_complete_request(rq);
}
/*
* Complete the not-mapped clone and the original request with the error status
* through softirq context.
* Target's rq_end_io() function isn't called.
- * This may be used when the target's map_rq() or clone_and_map_rq() functions fail.
+ * This may be used when the target's clone_and_map_rq() function fails.
*/
static void dm_kill_unmapped_request(struct request *rq, blk_status_t error)
{
@@ -381,21 +290,10 @@ static void dm_kill_unmapped_request(struct request *rq, blk_status_t error)
dm_complete_request(rq, error);
}
-/*
- * Called with the clone's queue lock held (in the case of .request_fn)
- */
static void end_clone_request(struct request *clone, blk_status_t error)
{
struct dm_rq_target_io *tio = clone->end_io_data;
- /*
- * Actual request completion is done in a softirq context which doesn't
- * hold the clone's queue lock. Otherwise, deadlock could occur because:
- * - another request may be submitted by the upper level driver
- * of the stacking during the completion
- * - the submission which requires queue lock may be done
- * against this clone's queue
- */
dm_complete_request(tio->orig, error);
}
@@ -446,8 +344,6 @@ static int setup_clone(struct request *clone, struct request *rq,
return 0;
}
-static void map_tio_request(struct kthread_work *work);
-
static void init_tio(struct dm_rq_target_io *tio, struct request *rq,
struct mapped_device *md)
{
@@ -464,8 +360,6 @@ static void init_tio(struct dm_rq_target_io *tio, struct request *rq,
*/
if (!md->init_tio_pdu)
memset(&tio->info, 0, sizeof(tio->info));
- if (md->kworker_task)
- kthread_init_work(&tio->work, map_tio_request);
}
/*
@@ -504,10 +398,7 @@ check_again:
blk_rq_unprep_clone(clone);
tio->ti->type->release_clone_rq(clone);
tio->clone = NULL;
- if (!rq->q->mq_ops)
- r = DM_MAPIO_DELAY_REQUEUE;
- else
- r = DM_MAPIO_REQUEUE;
+ r = DM_MAPIO_REQUEUE;
goto check_again;
}
break;
@@ -530,20 +421,23 @@ check_again:
return r;
}
+/* DEPRECATED: previously used for request-based merge heuristic in dm_request_fn() */
+ssize_t dm_attr_rq_based_seq_io_merge_deadline_show(struct mapped_device *md, char *buf)
+{
+ return sprintf(buf, "%u\n", 0);
+}
+
+ssize_t dm_attr_rq_based_seq_io_merge_deadline_store(struct mapped_device *md,
+ const char *buf, size_t count)
+{
+ return count;
+}
+
static void dm_start_request(struct mapped_device *md, struct request *orig)
{
- if (!orig->q->mq_ops)
- blk_start_request(orig);
- else
- blk_mq_start_request(orig);
+ blk_mq_start_request(orig);
atomic_inc(&md->pending[rq_data_dir(orig)]);
- if (md->seq_rq_merge_deadline_usecs) {
- md->last_rq_pos = rq_end_sector(orig);
- md->last_rq_rw = rq_data_dir(orig);
- md->last_rq_start_time = ktime_get();
- }
-
if (unlikely(dm_stats_used(&md->stats))) {
struct dm_rq_target_io *tio = tio_from_request(orig);
tio->duration_jiffies = jiffies;
@@ -563,8 +457,10 @@ static void dm_start_request(struct mapped_device *md, struct request *orig)
dm_get(md);
}
-static int __dm_rq_init_rq(struct mapped_device *md, struct request *rq)
+static int dm_mq_init_request(struct blk_mq_tag_set *set, struct request *rq,
+ unsigned int hctx_idx, unsigned int numa_node)
{
+ struct mapped_device *md = set->driver_data;
struct dm_rq_target_io *tio = blk_mq_rq_to_pdu(rq);
/*
@@ -581,163 +477,6 @@ static int __dm_rq_init_rq(struct mapped_device *md, struct request *rq)
return 0;
}
-static int dm_rq_init_rq(struct request_queue *q, struct request *rq, gfp_t gfp)
-{
- return __dm_rq_init_rq(q->rq_alloc_data, rq);
-}
-
-static void map_tio_request(struct kthread_work *work)
-{
- struct dm_rq_target_io *tio = container_of(work, struct dm_rq_target_io, work);
-
- if (map_request(tio) == DM_MAPIO_REQUEUE)
- dm_requeue_original_request(tio, false);
-}
-
-ssize_t dm_attr_rq_based_seq_io_merge_deadline_show(struct mapped_device *md, char *buf)
-{
- return sprintf(buf, "%u\n", md->seq_rq_merge_deadline_usecs);
-}
-
-#define MAX_SEQ_RQ_MERGE_DEADLINE_USECS 100000
-
-ssize_t dm_attr_rq_based_seq_io_merge_deadline_store(struct mapped_device *md,
- const char *buf, size_t count)
-{
- unsigned deadline;
-
- if (dm_get_md_type(md) != DM_TYPE_REQUEST_BASED)
- return count;
-
- if (kstrtouint(buf, 10, &deadline))
- return -EINVAL;
-
- if (deadline > MAX_SEQ_RQ_MERGE_DEADLINE_USECS)
- deadline = MAX_SEQ_RQ_MERGE_DEADLINE_USECS;
-
- md->seq_rq_merge_deadline_usecs = deadline;
-
- return count;
-}
-
-static bool dm_old_request_peeked_before_merge_deadline(struct mapped_device *md)
-{
- ktime_t kt_deadline;
-
- if (!md->seq_rq_merge_deadline_usecs)
- return false;
-
- kt_deadline = ns_to_ktime((u64)md->seq_rq_merge_deadline_usecs * NSEC_PER_USEC);
- kt_deadline = ktime_add_safe(md->last_rq_start_time, kt_deadline);
-
- return !ktime_after(ktime_get(), kt_deadline);
-}
-
-/*
- * q->request_fn for old request-based dm.
- * Called with the queue lock held.
- */
-static void dm_old_request_fn(struct request_queue *q)
-{
- struct mapped_device *md = q->queuedata;
- struct dm_target *ti = md->immutable_target;
- struct request *rq;
- struct dm_rq_target_io *tio;
- sector_t pos = 0;
-
- if (unlikely(!ti)) {
- int srcu_idx;
- struct dm_table *map = dm_get_live_table(md, &srcu_idx);
-
- if (unlikely(!map)) {
- dm_put_live_table(md, srcu_idx);
- return;
- }
- ti = dm_table_find_target(map, pos);
- dm_put_live_table(md, srcu_idx);
- }
-
- /*
- * For suspend, check blk_queue_stopped() and increment
- * ->pending within a single queue_lock not to increment the
- * number of in-flight I/Os after the queue is stopped in
- * dm_suspend().
- */
- while (!blk_queue_stopped(q)) {
- rq = blk_peek_request(q);
- if (!rq)
- return;
-
- /* always use block 0 to find the target for flushes for now */
- pos = 0;
- if (req_op(rq) != REQ_OP_FLUSH)
- pos = blk_rq_pos(rq);
-
- if ((dm_old_request_peeked_before_merge_deadline(md) &&
- md_in_flight(md) && rq->bio && !bio_multiple_segments(rq->bio) &&
- md->last_rq_pos == pos && md->last_rq_rw == rq_data_dir(rq)) ||
- (ti->type->busy && ti->type->busy(ti))) {
- blk_delay_queue(q, 10);
- return;
- }
-
- dm_start_request(md, rq);
-
- tio = tio_from_request(rq);
- init_tio(tio, rq, md);
- /* Establish tio->ti before queuing work (map_tio_request) */
- tio->ti = ti;
- kthread_queue_work(&md->kworker, &tio->work);
- BUG_ON(!irqs_disabled());
- }
-}
-
-/*
- * Fully initialize a .request_fn request-based queue.
- */
-int dm_old_init_request_queue(struct mapped_device *md, struct dm_table *t)
-{
- struct dm_target *immutable_tgt;
-
- /* Fully initialize the queue */
- md->queue->cmd_size = sizeof(struct dm_rq_target_io);
- md->queue->rq_alloc_data = md;
- md->queue->request_fn = dm_old_request_fn;
- md->queue->init_rq_fn = dm_rq_init_rq;
-
- immutable_tgt = dm_table_get_immutable_target(t);
- if (immutable_tgt && immutable_tgt->per_io_data_size) {
- /* any target-specific per-io data is immediately after the tio */
- md->queue->cmd_size += immutable_tgt->per_io_data_size;
- md->init_tio_pdu = true;
- }
- if (blk_init_allocated_queue(md->queue) < 0)
- return -EINVAL;
-
- /* disable dm_old_request_fn's merge heuristic by default */
- md->seq_rq_merge_deadline_usecs = 0;
-
- blk_queue_softirq_done(md->queue, dm_softirq_done);
-
- /* Initialize the request-based DM worker thread */
- kthread_init_worker(&md->kworker);
- md->kworker_task = kthread_run(kthread_worker_fn, &md->kworker,
- "kdmwork-%s", dm_device_name(md));
- if (IS_ERR(md->kworker_task)) {
- int error = PTR_ERR(md->kworker_task);
- md->kworker_task = NULL;
- return error;
- }
-
- return 0;
-}
-
-static int dm_mq_init_request(struct blk_mq_tag_set *set, struct request *rq,
- unsigned int hctx_idx, unsigned int numa_node)
-{
- return __dm_rq_init_rq(set->driver_data, rq);
-}
-
static blk_status_t dm_mq_queue_rq(struct blk_mq_hw_ctx *hctx,
const struct blk_mq_queue_data *bd)
{
@@ -790,11 +529,6 @@ int dm_mq_init_request_queue(struct mapped_device *md, struct dm_table *t)
struct dm_target *immutable_tgt;
int err;
- if (!dm_table_all_blk_mq_devices(t)) {
- DMERR("request-based dm-mq may only be stacked on blk-mq device(s)");
- return -EINVAL;
- }
-
md->tag_set = kzalloc_node(sizeof(struct blk_mq_tag_set), GFP_KERNEL, md->numa_node_id);
if (!md->tag_set)
return -ENOMEM;
@@ -845,6 +579,8 @@ void dm_mq_cleanup_mapped_device(struct mapped_device *md)
module_param(reserved_rq_based_ios, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(reserved_rq_based_ios, "Reserved IOs in request-based mempools");
+/* Unused, but preserved for userspace compatibility */
+static bool use_blk_mq = true;
module_param(use_blk_mq, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(use_blk_mq, "Use block multiqueue for request-based DM devices");
diff --git a/drivers/md/dm-rq.h b/drivers/md/dm-rq.h
index f43c45460aac..b39245545229 100644
--- a/drivers/md/dm-rq.h
+++ b/drivers/md/dm-rq.h
@@ -46,10 +46,6 @@ struct dm_rq_clone_bio_info {
struct bio clone;
};
-bool dm_use_blk_mq_default(void);
-bool dm_use_blk_mq(struct mapped_device *md);
-
-int dm_old_init_request_queue(struct mapped_device *md, struct dm_table *t);
int dm_mq_init_request_queue(struct mapped_device *md, struct dm_table *t);
void dm_mq_cleanup_mapped_device(struct mapped_device *md);
diff --git a/drivers/md/dm-sysfs.c b/drivers/md/dm-sysfs.c
index c209b8a19b84..a05fcd50e1b9 100644
--- a/drivers/md/dm-sysfs.c
+++ b/drivers/md/dm-sysfs.c
@@ -92,7 +92,8 @@ static ssize_t dm_attr_suspended_show(struct mapped_device *md, char *buf)
static ssize_t dm_attr_use_blk_mq_show(struct mapped_device *md, char *buf)
{
- sprintf(buf, "%d\n", dm_use_blk_mq(md));
+ /* Purely for userspace compatibility */
+ sprintf(buf, "%d\n", true);
return strlen(buf);
}
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 3d0e2c198f06..9038c302d5c2 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -47,7 +47,6 @@ struct dm_table {
bool integrity_supported:1;
bool singleton:1;
- bool all_blk_mq:1;
unsigned integrity_added:1;
/*
@@ -872,8 +871,7 @@ static bool __table_type_bio_based(enum dm_queue_mode table_type)
static bool __table_type_request_based(enum dm_queue_mode table_type)
{
- return (table_type == DM_TYPE_REQUEST_BASED ||
- table_type == DM_TYPE_MQ_REQUEST_BASED);
+ return table_type == DM_TYPE_REQUEST_BASED;
}
void dm_table_set_type(struct dm_table *t, enum dm_queue_mode type)
@@ -999,10 +997,6 @@ verify_bio_based:
BUG_ON(!request_based); /* No targets in this table */
- /*
- * The only way to establish DM_TYPE_MQ_REQUEST_BASED is by
- * having a compatible target use dm_table_set_type.
- */
t->type = DM_TYPE_REQUEST_BASED;
verify_rq_based:
@@ -1022,11 +1016,9 @@ verify_rq_based:
int srcu_idx;
struct dm_table *live_table = dm_get_live_table(t->md, &srcu_idx);
- /* inherit live table's type and all_blk_mq */
- if (live_table) {
+ /* inherit live table's type */
+ if (live_table)
t->type = live_table->type;
- t->all_blk_mq = live_table->all_blk_mq;
- }
dm_put_live_table(t->md, srcu_idx);
return 0;
}
@@ -1046,17 +1038,10 @@ verify_rq_based:
DMERR("table load rejected: including non-request-stackable devices");
return -EINVAL;
}
- if (v.sq_count && v.mq_count) {
+ if (v.sq_count > 0) {
DMERR("table load rejected: not all devices are blk-mq request-stackable");
return -EINVAL;
}
- t->all_blk_mq = v.mq_count > 0;
-
- if (!t->all_blk_mq &&
- (t->type == DM_TYPE_MQ_REQUEST_BASED || t->type == DM_TYPE_NVME_BIO_BASED)) {
- DMERR("table load rejected: all devices are not blk-mq request-stackable");
- return -EINVAL;
- }
return 0;
}
@@ -1105,11 +1090,6 @@ bool dm_table_request_based(struct dm_table *t)
return __table_type_request_based(dm_table_get_type(t));
}
-bool dm_table_all_blk_mq_devices(struct dm_table *t)
-{
- return t->all_blk_mq;
-}
-
static int dm_table_alloc_md_mempools(struct dm_table *t, struct mapped_device *md)
{
enum dm_queue_mode type = dm_table_get_type(t);
@@ -1937,6 +1917,16 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
*/
if (blk_queue_add_random(q) && dm_table_all_devices_attribute(t, device_is_not_random))
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 request based target, the
+ * queue zone bitmaps must also be updated.
+ * Use blk_revalidate_disk_zones() to handle this.
+ */
+ if (blk_queue_is_zoned(q))
+ blk_revalidate_disk_zones(t->md->disk);
}
unsigned int dm_table_get_num_targets(struct dm_table *t)
@@ -2079,26 +2069,24 @@ struct mapped_device *dm_table_get_md(struct dm_table *t)
}
EXPORT_SYMBOL(dm_table_get_md);
+const char *dm_table_device_name(struct dm_table *t)
+{
+ return dm_device_name(t->md);
+}
+EXPORT_SYMBOL_GPL(dm_table_device_name);
+
void dm_table_run_md_queue_async(struct dm_table *t)
{
struct mapped_device *md;
struct request_queue *queue;
- unsigned long flags;
if (!dm_table_request_based(t))
return;
md = dm_table_get_md(t);
queue = dm_get_md_queue(md);
- if (queue) {
- if (queue->mq_ops)
- blk_mq_run_hw_queues(queue, true);
- else {
- spin_lock_irqsave(queue->queue_lock, flags);
- blk_run_queue_async(queue);
- spin_unlock_irqrestore(queue->queue_lock, flags);
- }
- }
+ if (queue)
+ blk_mq_run_hw_queues(queue, true);
}
EXPORT_SYMBOL(dm_table_run_md_queue_async);
diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c
index 74f6770c70b1..20b0776e39ef 100644
--- a/drivers/md/dm-thin-metadata.c
+++ b/drivers/md/dm-thin-metadata.c
@@ -832,10 +832,8 @@ static void __set_metadata_reserve(struct dm_pool_metadata *pmd)
if (r) {
DMERR("could not get size of metadata device");
pmd->metadata_reserve = max_blocks;
- } else {
- sector_div(total, 10);
- pmd->metadata_reserve = min(max_blocks, total);
- }
+ } else
+ pmd->metadata_reserve = min(max_blocks, div_u64(total, 10));
}
struct dm_pool_metadata *dm_pool_metadata_open(struct block_device *bdev,
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c
index aaf1ad481ee8..0bd8d498b3b9 100644
--- a/drivers/md/dm-thin.c
+++ b/drivers/md/dm-thin.c
@@ -325,7 +325,7 @@ struct thin_c {
* Ensures the thin is not destroyed until the worker has finished
* iterating the active_thins list.
*/
- atomic_t refcount;
+ refcount_t refcount;
struct completion can_destroy;
};
@@ -4044,12 +4044,12 @@ static struct target_type pool_target = {
*--------------------------------------------------------------*/
static void thin_get(struct thin_c *tc)
{
- atomic_inc(&tc->refcount);
+ refcount_inc(&tc->refcount);
}
static void thin_put(struct thin_c *tc)
{
- if (atomic_dec_and_test(&tc->refcount))
+ if (refcount_dec_and_test(&tc->refcount))
complete(&tc->can_destroy);
}
@@ -4193,7 +4193,7 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
r = -EINVAL;
goto bad;
}
- atomic_set(&tc->refcount, 1);
+ refcount_set(&tc->refcount, 1);
init_completion(&tc->can_destroy);
list_add_tail_rcu(&tc->list, &tc->pool->active_thins);
spin_unlock_irqrestore(&tc->pool->lock, flags);
diff --git a/drivers/md/dm-verity-fec.c b/drivers/md/dm-verity-fec.c
index 684af08d0747..0ce04e5b4afb 100644
--- a/drivers/md/dm-verity-fec.c
+++ b/drivers/md/dm-verity-fec.c
@@ -212,12 +212,15 @@ static int fec_read_bufs(struct dm_verity *v, struct dm_verity_io *io,
struct dm_verity_fec_io *fio = fec_io(io);
u64 block, ileaved;
u8 *bbuf, *rs_block;
- u8 want_digest[v->digest_size];
+ u8 want_digest[HASH_MAX_DIGESTSIZE];
unsigned n, k;
if (neras)
*neras = 0;
+ if (WARN_ON(v->digest_size > sizeof(want_digest)))
+ return -EINVAL;
+
/*
* read each of the rsn data blocks that are part of the RS block, and
* interleave contents to available bufs
diff --git a/drivers/md/dm-writecache.c b/drivers/md/dm-writecache.c
index 5f1f80d424dd..2d50eec94cd7 100644
--- a/drivers/md/dm-writecache.c
+++ b/drivers/md/dm-writecache.c
@@ -350,10 +350,7 @@ static struct wc_memory_superblock *sb(struct dm_writecache *wc)
static struct wc_memory_entry *memory_entry(struct dm_writecache *wc, struct wc_entry *e)
{
- if (is_power_of_2(sizeof(struct wc_entry)) && 0)
- return &sb(wc)->entries[e - wc->entries];
- else
- return &sb(wc)->entries[e->index];
+ return &sb(wc)->entries[e->index];
}
static void *memory_data(struct dm_writecache *wc, struct wc_entry *e)
diff --git a/drivers/md/dm-zoned-metadata.c b/drivers/md/dm-zoned-metadata.c
index 969954915566..fa68336560c3 100644
--- a/drivers/md/dm-zoned-metadata.c
+++ b/drivers/md/dm-zoned-metadata.c
@@ -99,7 +99,7 @@ struct dmz_mblock {
struct rb_node node;
struct list_head link;
sector_t no;
- atomic_t ref;
+ unsigned int ref;
unsigned long state;
struct page *page;
void *data;
@@ -296,7 +296,7 @@ static struct dmz_mblock *dmz_alloc_mblock(struct dmz_metadata *zmd,
RB_CLEAR_NODE(&mblk->node);
INIT_LIST_HEAD(&mblk->link);
- atomic_set(&mblk->ref, 0);
+ mblk->ref = 0;
mblk->state = 0;
mblk->no = mblk_no;
mblk->data = page_address(mblk->page);
@@ -339,10 +339,11 @@ static void dmz_insert_mblock(struct dmz_metadata *zmd, struct dmz_mblock *mblk)
}
/*
- * Lookup a metadata block in the rbtree.
+ * Lookup a metadata block in the rbtree. If the block is found, increment
+ * its reference count.
*/
-static struct dmz_mblock *dmz_lookup_mblock(struct dmz_metadata *zmd,
- sector_t mblk_no)
+static struct dmz_mblock *dmz_get_mblock_fast(struct dmz_metadata *zmd,
+ sector_t mblk_no)
{
struct rb_root *root = &zmd->mblk_rbtree;
struct rb_node *node = root->rb_node;
@@ -350,8 +351,17 @@ static struct dmz_mblock *dmz_lookup_mblock(struct dmz_metadata *zmd,
while (node) {
mblk = container_of(node, struct dmz_mblock, node);
- if (mblk->no == mblk_no)
+ if (mblk->no == mblk_no) {
+ /*
+ * If this is the first reference to the block,
+ * remove it from the LRU list.
+ */
+ mblk->ref++;
+ if (mblk->ref == 1 &&
+ !test_bit(DMZ_META_DIRTY, &mblk->state))
+ list_del_init(&mblk->link);
return mblk;
+ }
node = (mblk->no < mblk_no) ? node->rb_left : node->rb_right;
}
@@ -382,32 +392,47 @@ static void dmz_mblock_bio_end_io(struct bio *bio)
}
/*
- * Read a metadata block from disk.
+ * Read an uncached metadata block from disk and add it to the cache.
*/
-static struct dmz_mblock *dmz_fetch_mblock(struct dmz_metadata *zmd,
- sector_t mblk_no)
+static struct dmz_mblock *dmz_get_mblock_slow(struct dmz_metadata *zmd,
+ sector_t mblk_no)
{
- struct dmz_mblock *mblk;
+ struct dmz_mblock *mblk, *m;
sector_t block = zmd->sb[zmd->mblk_primary].block + mblk_no;
struct bio *bio;
- /* Get block and insert it */
+ /* Get a new block and a BIO to read it */
mblk = dmz_alloc_mblock(zmd, mblk_no);
if (!mblk)
return NULL;
- spin_lock(&zmd->mblk_lock);
- atomic_inc(&mblk->ref);
- set_bit(DMZ_META_READING, &mblk->state);
- dmz_insert_mblock(zmd, mblk);
- spin_unlock(&zmd->mblk_lock);
-
bio = bio_alloc(GFP_NOIO, 1);
if (!bio) {
dmz_free_mblock(zmd, mblk);
return NULL;
}
+ spin_lock(&zmd->mblk_lock);
+
+ /*
+ * Make sure that another context did not start reading
+ * the block already.
+ */
+ m = dmz_get_mblock_fast(zmd, mblk_no);
+ if (m) {
+ spin_unlock(&zmd->mblk_lock);
+ dmz_free_mblock(zmd, mblk);
+ bio_put(bio);
+ return m;
+ }
+
+ mblk->ref++;
+ set_bit(DMZ_META_READING, &mblk->state);
+ dmz_insert_mblock(zmd, mblk);
+
+ spin_unlock(&zmd->mblk_lock);
+
+ /* Submit read BIO */
bio->bi_iter.bi_sector = dmz_blk2sect(block);
bio_set_dev(bio, zmd->dev->bdev);
bio->bi_private = mblk;
@@ -484,7 +509,8 @@ static void dmz_release_mblock(struct dmz_metadata *zmd,
spin_lock(&zmd->mblk_lock);
- if (atomic_dec_and_test(&mblk->ref)) {
+ mblk->ref--;
+ if (mblk->ref == 0) {
if (test_bit(DMZ_META_ERROR, &mblk->state)) {
rb_erase(&mblk->node, &zmd->mblk_rbtree);
dmz_free_mblock(zmd, mblk);
@@ -508,18 +534,12 @@ static struct dmz_mblock *dmz_get_mblock(struct dmz_metadata *zmd,
/* Check rbtree */
spin_lock(&zmd->mblk_lock);
- mblk = dmz_lookup_mblock(zmd, mblk_no);
- if (mblk) {
- /* Cache hit: remove block from LRU list */
- if (atomic_inc_return(&mblk->ref) == 1 &&
- !test_bit(DMZ_META_DIRTY, &mblk->state))
- list_del_init(&mblk->link);
- }
+ mblk = dmz_get_mblock_fast(zmd, mblk_no);
spin_unlock(&zmd->mblk_lock);
if (!mblk) {
/* Cache miss: read the block from disk */
- mblk = dmz_fetch_mblock(zmd, mblk_no);
+ mblk = dmz_get_mblock_slow(zmd, mblk_no);
if (!mblk)
return ERR_PTR(-ENOMEM);
}
@@ -753,7 +773,7 @@ int dmz_flush_metadata(struct dmz_metadata *zmd)
spin_lock(&zmd->mblk_lock);
clear_bit(DMZ_META_DIRTY, &mblk->state);
- if (atomic_read(&mblk->ref) == 0)
+ if (mblk->ref == 0)
list_add_tail(&mblk->link, &zmd->mblk_lru_list);
spin_unlock(&zmd->mblk_lock);
}
@@ -2308,7 +2328,7 @@ static void dmz_cleanup_metadata(struct dmz_metadata *zmd)
mblk = list_first_entry(&zmd->mblk_dirty_list,
struct dmz_mblock, link);
dmz_dev_warn(zmd->dev, "mblock %llu still in dirty list (ref %u)",
- (u64)mblk->no, atomic_read(&mblk->ref));
+ (u64)mblk->no, mblk->ref);
list_del_init(&mblk->link);
rb_erase(&mblk->node, &zmd->mblk_rbtree);
dmz_free_mblock(zmd, mblk);
@@ -2326,8 +2346,8 @@ static void dmz_cleanup_metadata(struct dmz_metadata *zmd)
root = &zmd->mblk_rbtree;
rbtree_postorder_for_each_entry_safe(mblk, next, root, node) {
dmz_dev_warn(zmd->dev, "mblock %llu ref %u still in rbtree",
- (u64)mblk->no, atomic_read(&mblk->ref));
- atomic_set(&mblk->ref, 0);
+ (u64)mblk->no, mblk->ref);
+ mblk->ref = 0;
dmz_free_mblock(zmd, mblk);
}
diff --git a/drivers/md/dm-zoned-target.c b/drivers/md/dm-zoned-target.c
index a44183ff4be0..981154e59461 100644
--- a/drivers/md/dm-zoned-target.c
+++ b/drivers/md/dm-zoned-target.c
@@ -19,7 +19,7 @@ struct dmz_bioctx {
struct dmz_target *target;
struct dm_zone *zone;
struct bio *bio;
- atomic_t ref;
+ refcount_t ref;
blk_status_t status;
};
@@ -28,7 +28,7 @@ struct dmz_bioctx {
*/
struct dm_chunk_work {
struct work_struct work;
- atomic_t refcount;
+ refcount_t refcount;
struct dmz_target *target;
unsigned int chunk;
struct bio_list bio_list;
@@ -115,7 +115,7 @@ static int dmz_submit_read_bio(struct dmz_target *dmz, struct dm_zone *zone,
if (nr_blocks == dmz_bio_blocks(bio)) {
/* Setup and submit the BIO */
bio->bi_iter.bi_sector = sector;
- atomic_inc(&bioctx->ref);
+ refcount_inc(&bioctx->ref);
generic_make_request(bio);
return 0;
}
@@ -134,7 +134,7 @@ static int dmz_submit_read_bio(struct dmz_target *dmz, struct dm_zone *zone,
bio_advance(bio, clone->bi_iter.bi_size);
/* Submit the clone */
- atomic_inc(&bioctx->ref);
+ refcount_inc(&bioctx->ref);
generic_make_request(clone);
return 0;
@@ -240,7 +240,7 @@ static void dmz_submit_write_bio(struct dmz_target *dmz, struct dm_zone *zone,
/* Setup and submit the BIO */
bio_set_dev(bio, dmz->dev->bdev);
bio->bi_iter.bi_sector = dmz_start_sect(dmz->metadata, zone) + dmz_blk2sect(chunk_block);
- atomic_inc(&bioctx->ref);
+ refcount_inc(&bioctx->ref);
generic_make_request(bio);
if (dmz_is_seq(zone))
@@ -456,7 +456,7 @@ out:
*/
static inline void dmz_get_chunk_work(struct dm_chunk_work *cw)
{
- atomic_inc(&cw->refcount);
+ refcount_inc(&cw->refcount);
}
/*
@@ -465,7 +465,7 @@ static inline void dmz_get_chunk_work(struct dm_chunk_work *cw)
*/
static void dmz_put_chunk_work(struct dm_chunk_work *cw)
{
- if (atomic_dec_and_test(&cw->refcount)) {
+ if (refcount_dec_and_test(&cw->refcount)) {
WARN_ON(!bio_list_empty(&cw->bio_list));
radix_tree_delete(&cw->target->chunk_rxtree, cw->chunk);
kfree(cw);
@@ -546,7 +546,7 @@ static void dmz_queue_chunk_work(struct dmz_target *dmz, struct bio *bio)
goto out;
INIT_WORK(&cw->work, dmz_chunk_work);
- atomic_set(&cw->refcount, 0);
+ refcount_set(&cw->refcount, 0);
cw->target = dmz;
cw->chunk = chunk;
bio_list_init(&cw->bio_list);
@@ -599,7 +599,7 @@ static int dmz_map(struct dm_target *ti, struct bio *bio)
bioctx->target = dmz;
bioctx->zone = NULL;
bioctx->bio = bio;
- atomic_set(&bioctx->ref, 1);
+ refcount_set(&bioctx->ref, 1);
bioctx->status = BLK_STS_OK;
/* Set the BIO pending in the flush list */
@@ -633,7 +633,7 @@ static int dmz_end_io(struct dm_target *ti, struct bio *bio, blk_status_t *error
if (bioctx->status == BLK_STS_OK && *error)
bioctx->status = *error;
- if (!atomic_dec_and_test(&bioctx->ref))
+ if (!refcount_dec_and_test(&bioctx->ref))
return DM_ENDIO_INCOMPLETE;
/* Done */
@@ -702,8 +702,7 @@ static int dmz_get_zoned_device(struct dm_target *ti, char *path)
dev->zone_nr_blocks = dmz_sect2blk(dev->zone_nr_sectors);
dev->zone_nr_blocks_shift = ilog2(dev->zone_nr_blocks);
- dev->nr_zones = (dev->capacity + dev->zone_nr_sectors - 1)
- >> dev->zone_nr_sectors_shift;
+ dev->nr_zones = blkdev_nr_zones(dev->bdev);
dmz->dev = dev;
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 20f7e4ef5342..c510179a7f84 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -458,6 +458,57 @@ static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
return dm_get_geometry(md, geo);
}
+static int dm_blk_report_zones(struct gendisk *disk, sector_t sector,
+ struct blk_zone *zones, unsigned int *nr_zones,
+ gfp_t gfp_mask)
+{
+#ifdef CONFIG_BLK_DEV_ZONED
+ struct mapped_device *md = disk->private_data;
+ struct dm_target *tgt;
+ 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;
+
+ tgt = dm_table_find_target(map, sector);
+ if (!dm_target_is_valid(tgt)) {
+ ret = -EIO;
+ goto out;
+ }
+
+ /*
+ * If we are executing this, we already know that the block device
+ * is a zoned device and so each target should have support for that
+ * type of drive. A missing report_zones method means that the target
+ * driver has a problem.
+ */
+ if (WARN_ON(!tgt->type->report_zones)) {
+ ret = -EIO;
+ goto out;
+ }
+
+ /*
+ * blkdev_report_zones() will loop and call this again to cover all the
+ * zones of the target, eventually moving on to the next target.
+ * So there is no need to loop here trying to fill the entire array
+ * of zones.
+ */
+ ret = tgt->type->report_zones(tgt, sector, zones,
+ nr_zones, gfp_mask);
+
+out:
+ dm_put_live_table(md, srcu_idx);
+ return ret;
+#else
+ return -ENOTSUPP;
+#endif
+}
+
static int dm_prepare_ioctl(struct mapped_device *md, int *srcu_idx,
struct block_device **bdev)
__acquires(md->io_barrier)
@@ -1156,79 +1207,48 @@ EXPORT_SYMBOL_GPL(dm_accept_partial_bio);
/*
* The zone descriptors obtained with a zone report indicate
- * zone positions within the target device. The zone descriptors
- * must be remapped to match their position within the dm device.
- * A target may call dm_remap_zone_report after completion of a
- * REQ_OP_ZONE_REPORT bio to remap the zone descriptors obtained
- * from the target device mapping to the dm device.
+ * zone positions within the underlying device of the target. The zone
+ * descriptors must be remapped to match their position within the dm device.
+ * The caller target should obtain the zones information using
+ * blkdev_report_zones() to ensure that remapping for partition offset is
+ * already handled.
*/
-void dm_remap_zone_report(struct dm_target *ti, struct bio *bio, sector_t start)
+void dm_remap_zone_report(struct dm_target *ti, sector_t start,
+ struct blk_zone *zones, unsigned int *nr_zones)
{
#ifdef CONFIG_BLK_DEV_ZONED
- struct dm_target_io *tio = container_of(bio, struct dm_target_io, clone);
- struct bio *report_bio = tio->io->orig_bio;
- struct blk_zone_report_hdr *hdr = NULL;
struct blk_zone *zone;
- unsigned int nr_rep = 0;
- unsigned int ofst;
- struct bio_vec bvec;
- struct bvec_iter iter;
- void *addr;
-
- if (bio->bi_status)
- return;
+ unsigned int nrz = *nr_zones;
+ int i;
/*
- * Remap the start sector of the reported zones. For sequential zones,
- * also remap the write pointer position.
+ * Remap the start sector and write pointer position of the zones in
+ * the array. Since we may have obtained from the target underlying
+ * device more zones that the target size, also adjust the number
+ * of zones.
*/
- bio_for_each_segment(bvec, report_bio, iter) {
- addr = kmap_atomic(bvec.bv_page);
-
- /* Remember the report header in the first page */
- if (!hdr) {
- hdr = addr;
- ofst = sizeof(struct blk_zone_report_hdr);
- } else
- ofst = 0;
-
- /* Set zones start sector */
- while (hdr->nr_zones && ofst < bvec.bv_len) {
- zone = addr + ofst;
- if (zone->start >= start + ti->len) {
- hdr->nr_zones = 0;
- break;
- }
- zone->start = zone->start + ti->begin - start;
- 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 = zone->wp + ti->begin - start;
- }
- ofst += sizeof(struct blk_zone);
- hdr->nr_zones--;
- nr_rep++;
+ for (i = 0; i < nrz; i++) {
+ zone = zones + i;
+ if (zone->start >= start + ti->len) {
+ memset(zone, 0, sizeof(struct blk_zone) * (nrz - i));
+ break;
}
- if (addr != hdr)
- kunmap_atomic(addr);
-
- if (!hdr->nr_zones)
- break;
- }
+ zone->start = zone->start + ti->begin - start;
+ if (zone->type == BLK_ZONE_TYPE_CONVENTIONAL)
+ continue;
- if (hdr) {
- hdr->nr_zones = nr_rep;
- kunmap_atomic(hdr);
+ 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 = zone->wp + ti->begin - start;
}
- bio_advance(report_bio, report_bio->bi_iter.bi_size);
-
+ *nr_zones = i;
#else /* !CONFIG_BLK_DEV_ZONED */
- bio->bi_status = BLK_STS_NOTSUPP;
+ *nr_zones = 0;
#endif
}
EXPORT_SYMBOL_GPL(dm_remap_zone_report);
@@ -1314,8 +1334,7 @@ static int clone_bio(struct dm_target_io *tio, struct bio *bio,
return r;
}
- if (bio_op(bio) != REQ_OP_ZONE_REPORT)
- bio_advance(clone, to_bytes(sector - clone->bi_iter.bi_sector));
+ bio_advance(clone, to_bytes(sector - clone->bi_iter.bi_sector));
clone->bi_iter.bi_size = to_bytes(len);
if (unlikely(bio_integrity(bio) != NULL))
@@ -1528,7 +1547,6 @@ static bool __process_abnormal_io(struct clone_info *ci, struct dm_target *ti,
*/
static int __split_and_process_non_flush(struct clone_info *ci)
{
- struct bio *bio = ci->bio;
struct dm_target *ti;
unsigned len;
int r;
@@ -1540,11 +1558,7 @@ static int __split_and_process_non_flush(struct clone_info *ci)
if (unlikely(__process_abnormal_io(ci, ti, &r)))
return r;
- if (bio_op(bio) == REQ_OP_ZONE_REPORT)
- len = ci->sector_count;
- else
- len = min_t(sector_t, max_io_len(ci->sector, ti),
- ci->sector_count);
+ len = min_t(sector_t, max_io_len(ci->sector, ti), ci->sector_count);
r = __clone_and_map_data_bio(ci, ti, ci->sector, &len);
if (r < 0)
@@ -1603,9 +1617,6 @@ static blk_qc_t __split_and_process_bio(struct mapped_device *md,
* We take a clone of the original to store in
* ci.io->orig_bio to be used by end_io_acct() and
* for dec_pending to use for completion handling.
- * As this path is not used for REQ_OP_ZONE_REPORT,
- * the usage of io->orig_bio in dm_remap_zone_report()
- * won't be affected by this reassignment.
*/
struct bio *b = bio_split(bio, bio_sectors(bio) - ci.sector_count,
GFP_NOIO, &md->queue->bio_split);
@@ -1653,7 +1664,7 @@ static blk_qc_t __process_bio(struct mapped_device *md,
* Defend against IO still getting in during teardown
* - as was seen for a time with nvme-fcloop
*/
- if (unlikely(WARN_ON_ONCE(!ti || !dm_target_is_valid(ti)))) {
+ if (WARN_ON_ONCE(!ti || !dm_target_is_valid(ti))) {
error = -EIO;
goto out;
}
@@ -1795,8 +1806,6 @@ static void dm_wq_work(struct work_struct *work);
static void dm_init_normal_md_queue(struct mapped_device *md)
{
- md->use_blk_mq = false;
-
/*
* Initialize aspects of queue that aren't relevant for blk-mq
*/
@@ -1807,8 +1816,6 @@ static void cleanup_mapped_device(struct mapped_device *md)
{
if (md->wq)
destroy_workqueue(md->wq);
- if (md->kworker_task)
- kthread_stop(md->kworker_task);
bioset_exit(&md->bs);
bioset_exit(&md->io_bs);
@@ -1875,7 +1882,6 @@ static struct mapped_device *alloc_dev(int minor)
goto bad_io_barrier;
md->numa_node_id = numa_node_id;
- md->use_blk_mq = dm_use_blk_mq_default();
md->init_tio_pdu = false;
md->type = DM_TYPE_NONE;
mutex_init(&md->suspend_lock);
@@ -1906,7 +1912,6 @@ static struct mapped_device *alloc_dev(int minor)
INIT_WORK(&md->work, dm_wq_work);
init_waitqueue_head(&md->eventq);
init_completion(&md->kobj_holder.completion);
- md->kworker_task = NULL;
md->disk->major = _major;
md->disk->first_minor = minor;
@@ -2206,14 +2211,6 @@ int dm_setup_md_queue(struct mapped_device *md, struct dm_table *t)
switch (type) {
case DM_TYPE_REQUEST_BASED:
- dm_init_normal_md_queue(md);
- r = dm_old_init_request_queue(md, t);
- if (r) {
- DMERR("Cannot initialize queue for request-based mapped device");
- return r;
- }
- break;
- case DM_TYPE_MQ_REQUEST_BASED:
r = dm_mq_init_request_queue(md, t);
if (r) {
DMERR("Cannot initialize queue for request-based dm-mq mapped device");
@@ -2318,9 +2315,6 @@ static void __dm_destroy(struct mapped_device *md, bool wait)
blk_set_queue_dying(md->queue);
- if (dm_request_based(md) && md->kworker_task)
- kthread_flush_worker(&md->kworker);
-
/*
* Take suspend_lock so that presuspend and postsuspend methods
* do not race with internal suspend.
@@ -2573,11 +2567,8 @@ static int __dm_suspend(struct mapped_device *md, struct dm_table *map,
* Stop md->queue before flushing md->wq in case request-based
* dm defers requests to md->wq from md->queue.
*/
- if (dm_request_based(md)) {
+ if (dm_request_based(md))
dm_stop_queue(md->queue);
- if (md->kworker_task)
- kthread_flush_worker(&md->kworker);
- }
flush_workqueue(md->wq);
@@ -2952,7 +2943,6 @@ struct dm_md_mempools *dm_alloc_md_mempools(struct mapped_device *md, enum dm_qu
goto out;
break;
case DM_TYPE_REQUEST_BASED:
- case DM_TYPE_MQ_REQUEST_BASED:
pool_size = max(dm_get_reserved_rq_based_ios(), min_pool_size);
front_pad = offsetof(struct dm_rq_clone_bio_info, clone);
/* per_io_data_size is used for blk-mq pdu at queue allocation */
@@ -3154,6 +3144,7 @@ static const struct block_device_operations dm_blk_dops = {
.release = dm_blk_close,
.ioctl = dm_blk_ioctl,
.getgeo = dm_blk_getgeo,
+ .report_zones = dm_blk_report_zones,
.pr_ops = &dm_pr_ops,
.owner = THIS_MODULE
};
diff --git a/drivers/md/dm.h b/drivers/md/dm.h
index 114a81b27c37..2d539b82ec08 100644
--- a/drivers/md/dm.h
+++ b/drivers/md/dm.h
@@ -70,7 +70,6 @@ struct dm_target *dm_table_get_immutable_target(struct dm_table *t);
struct dm_target *dm_table_get_wildcard_target(struct dm_table *t);
bool dm_table_bio_based(struct dm_table *t);
bool dm_table_request_based(struct dm_table *t);
-bool dm_table_all_blk_mq_devices(struct dm_table *t);
void dm_table_free_md_mempools(struct dm_table *t);
struct dm_md_mempools *dm_table_get_md_mempools(struct dm_table *t);
diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c
index 2fc8c113977f..1cd4f991792c 100644
--- a/drivers/md/md-bitmap.c
+++ b/drivers/md/md-bitmap.c
@@ -2288,9 +2288,9 @@ location_store(struct mddev *mddev, const char *buf, size_t len)
goto out;
}
if (mddev->pers) {
- mddev->pers->quiesce(mddev, 1);
+ mddev_suspend(mddev);
md_bitmap_destroy(mddev);
- mddev->pers->quiesce(mddev, 0);
+ mddev_resume(mddev);
}
mddev->bitmap_info.offset = 0;
if (mddev->bitmap_info.file) {
@@ -2327,8 +2327,8 @@ location_store(struct mddev *mddev, const char *buf, size_t len)
mddev->bitmap_info.offset = offset;
if (mddev->pers) {
struct bitmap *bitmap;
- mddev->pers->quiesce(mddev, 1);
bitmap = md_bitmap_create(mddev, -1);
+ mddev_suspend(mddev);
if (IS_ERR(bitmap))
rv = PTR_ERR(bitmap);
else {
@@ -2337,11 +2337,12 @@ location_store(struct mddev *mddev, const char *buf, size_t len)
if (rv)
mddev->bitmap_info.offset = 0;
}
- mddev->pers->quiesce(mddev, 0);
if (rv) {
md_bitmap_destroy(mddev);
+ mddev_resume(mddev);
goto out;
}
+ mddev_resume(mddev);
}
}
}
diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c
index 0b2af6e74fc3..8dff19d5502e 100644
--- a/drivers/md/md-cluster.c
+++ b/drivers/md/md-cluster.c
@@ -33,13 +33,6 @@ struct dlm_lock_resource {
int mode;
};
-struct suspend_info {
- int slot;
- sector_t lo;
- sector_t hi;
- struct list_head list;
-};
-
struct resync_info {
__le64 lo;
__le64 hi;
@@ -80,7 +73,13 @@ struct md_cluster_info {
struct dlm_lock_resource **other_bitmap_lockres;
struct dlm_lock_resource *resync_lockres;
struct list_head suspend_list;
+
spinlock_t suspend_lock;
+ /* record the region which write should be suspended */
+ sector_t suspend_lo;
+ sector_t suspend_hi;
+ int suspend_from; /* the slot which broadcast suspend_lo/hi */
+
struct md_thread *recovery_thread;
unsigned long recovery_map;
/* communication loc resources */
@@ -105,6 +104,7 @@ enum msg_type {
RE_ADD,
BITMAP_NEEDS_SYNC,
CHANGE_CAPACITY,
+ BITMAP_RESIZE,
};
struct cluster_msg {
@@ -270,25 +270,22 @@ static void add_resync_info(struct dlm_lock_resource *lockres,
ri->hi = cpu_to_le64(hi);
}
-static struct suspend_info *read_resync_info(struct mddev *mddev, struct dlm_lock_resource *lockres)
+static int read_resync_info(struct mddev *mddev,
+ struct dlm_lock_resource *lockres)
{
struct resync_info ri;
- struct suspend_info *s = NULL;
- sector_t hi = 0;
+ struct md_cluster_info *cinfo = mddev->cluster_info;
+ int ret = 0;
dlm_lock_sync(lockres, DLM_LOCK_CR);
memcpy(&ri, lockres->lksb.sb_lvbptr, sizeof(struct resync_info));
- hi = le64_to_cpu(ri.hi);
- if (hi > 0) {
- s = kzalloc(sizeof(struct suspend_info), GFP_KERNEL);
- if (!s)
- goto out;
- s->hi = hi;
- s->lo = le64_to_cpu(ri.lo);
+ if (le64_to_cpu(ri.hi) > 0) {
+ cinfo->suspend_hi = le64_to_cpu(ri.hi);
+ cinfo->suspend_lo = le64_to_cpu(ri.lo);
+ ret = 1;
}
dlm_unlock_sync(lockres);
-out:
- return s;
+ return ret;
}
static void recover_bitmaps(struct md_thread *thread)
@@ -298,7 +295,6 @@ static void recover_bitmaps(struct md_thread *thread)
struct dlm_lock_resource *bm_lockres;
char str[64];
int slot, ret;
- struct suspend_info *s, *tmp;
sector_t lo, hi;
while (cinfo->recovery_map) {
@@ -325,13 +321,17 @@ static void recover_bitmaps(struct md_thread *thread)
/* Clear suspend_area associated with the bitmap */
spin_lock_irq(&cinfo->suspend_lock);
- list_for_each_entry_safe(s, tmp, &cinfo->suspend_list, list)
- if (slot == s->slot) {
- list_del(&s->list);
- kfree(s);
- }
+ cinfo->suspend_hi = 0;
+ cinfo->suspend_lo = 0;
+ cinfo->suspend_from = -1;
spin_unlock_irq(&cinfo->suspend_lock);
+ /* Kick off a reshape if needed */
+ if (test_bit(MD_RESYNCING_REMOTE, &mddev->recovery) &&
+ test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
+ mddev->reshape_position != MaxSector)
+ md_wakeup_thread(mddev->sync_thread);
+
if (hi > 0) {
if (lo < mddev->recovery_cp)
mddev->recovery_cp = lo;
@@ -434,34 +434,23 @@ static void ack_bast(void *arg, int mode)
}
}
-static void __remove_suspend_info(struct md_cluster_info *cinfo, int slot)
-{
- struct suspend_info *s, *tmp;
-
- list_for_each_entry_safe(s, tmp, &cinfo->suspend_list, list)
- if (slot == s->slot) {
- list_del(&s->list);
- kfree(s);
- break;
- }
-}
-
static void remove_suspend_info(struct mddev *mddev, int slot)
{
struct md_cluster_info *cinfo = mddev->cluster_info;
mddev->pers->quiesce(mddev, 1);
spin_lock_irq(&cinfo->suspend_lock);
- __remove_suspend_info(cinfo, slot);
+ cinfo->suspend_hi = 0;
+ cinfo->suspend_lo = 0;
spin_unlock_irq(&cinfo->suspend_lock);
mddev->pers->quiesce(mddev, 0);
}
-
static void process_suspend_info(struct mddev *mddev,
int slot, sector_t lo, sector_t hi)
{
struct md_cluster_info *cinfo = mddev->cluster_info;
- struct suspend_info *s;
+ struct mdp_superblock_1 *sb = NULL;
+ struct md_rdev *rdev;
if (!hi) {
/*
@@ -475,6 +464,12 @@ static void process_suspend_info(struct mddev *mddev,
return;
}
+ rdev_for_each(rdev, mddev)
+ if (rdev->raid_disk > -1 && !test_bit(Faulty, &rdev->flags)) {
+ sb = page_address(rdev->sb_page);
+ break;
+ }
+
/*
* The bitmaps are not same for different nodes
* if RESYNCING is happening in one node, then
@@ -487,26 +482,26 @@ static void process_suspend_info(struct mddev *mddev,
* sync_low/hi is used to record the region which
* arrived in the previous RESYNCING message,
*
- * Call bitmap_sync_with_cluster to clear
- * NEEDED_MASK and set RESYNC_MASK since
- * resync thread is running in another node,
- * so we don't need to do the resync again
- * with the same section */
- md_bitmap_sync_with_cluster(mddev, cinfo->sync_low, cinfo->sync_hi, lo, hi);
+ * Call md_bitmap_sync_with_cluster to clear NEEDED_MASK
+ * and set RESYNC_MASK since resync thread is running
+ * in another node, so we don't need to do the resync
+ * again with the same section.
+ *
+ * Skip md_bitmap_sync_with_cluster in case reshape
+ * happening, because reshaping region is small and
+ * we don't want to trigger lots of WARN.
+ */
+ if (sb && !(le32_to_cpu(sb->feature_map) & MD_FEATURE_RESHAPE_ACTIVE))
+ md_bitmap_sync_with_cluster(mddev, cinfo->sync_low,
+ cinfo->sync_hi, lo, hi);
cinfo->sync_low = lo;
cinfo->sync_hi = hi;
- s = kzalloc(sizeof(struct suspend_info), GFP_KERNEL);
- if (!s)
- return;
- s->slot = slot;
- s->lo = lo;
- s->hi = hi;
mddev->pers->quiesce(mddev, 1);
spin_lock_irq(&cinfo->suspend_lock);
- /* Remove existing entry (if exists) before adding */
- __remove_suspend_info(cinfo, slot);
- list_add(&s->list, &cinfo->suspend_list);
+ cinfo->suspend_from = slot;
+ cinfo->suspend_lo = lo;
+ cinfo->suspend_hi = hi;
spin_unlock_irq(&cinfo->suspend_lock);
mddev->pers->quiesce(mddev, 0);
}
@@ -612,6 +607,11 @@ static int process_recvd_msg(struct mddev *mddev, struct cluster_msg *msg)
case BITMAP_NEEDS_SYNC:
__recover_slot(mddev, le32_to_cpu(msg->slot));
break;
+ case BITMAP_RESIZE:
+ if (le64_to_cpu(msg->high) != mddev->pers->size(mddev, 0, 0))
+ ret = md_bitmap_resize(mddev->bitmap,
+ le64_to_cpu(msg->high), 0, 0);
+ break;
default:
ret = -1;
pr_warn("%s:%d Received unknown message from %d\n",
@@ -800,7 +800,6 @@ static int gather_all_resync_info(struct mddev *mddev, int total_slots)
struct md_cluster_info *cinfo = mddev->cluster_info;
int i, ret = 0;
struct dlm_lock_resource *bm_lockres;
- struct suspend_info *s;
char str[64];
sector_t lo, hi;
@@ -819,16 +818,13 @@ static int gather_all_resync_info(struct mddev *mddev, int total_slots)
bm_lockres->flags |= DLM_LKF_NOQUEUE;
ret = dlm_lock_sync(bm_lockres, DLM_LOCK_PW);
if (ret == -EAGAIN) {
- s = read_resync_info(mddev, bm_lockres);
- if (s) {
+ if (read_resync_info(mddev, bm_lockres)) {
pr_info("%s:%d Resync[%llu..%llu] in progress on %d\n",
__func__, __LINE__,
- (unsigned long long) s->lo,
- (unsigned long long) s->hi, i);
- spin_lock_irq(&cinfo->suspend_lock);
- s->slot = i;
- list_add(&s->list, &cinfo->suspend_list);
- spin_unlock_irq(&cinfo->suspend_lock);
+ (unsigned long long) cinfo->suspend_lo,
+ (unsigned long long) cinfo->suspend_hi,
+ i);
+ cinfo->suspend_from = i;
}
ret = 0;
lockres_free(bm_lockres);
@@ -1001,10 +997,17 @@ static int leave(struct mddev *mddev)
if (!cinfo)
return 0;
- /* BITMAP_NEEDS_SYNC message should be sent when node
+ /*
+ * BITMAP_NEEDS_SYNC message should be sent when node
* is leaving the cluster with dirty bitmap, also we
- * can only deliver it when dlm connection is available */
- if (cinfo->slot_number > 0 && mddev->recovery_cp != MaxSector)
+ * can only deliver it when dlm connection is available.
+ *
+ * Also, we should send BITMAP_NEEDS_SYNC message in
+ * case reshaping is interrupted.
+ */
+ if ((cinfo->slot_number > 0 && mddev->recovery_cp != MaxSector) ||
+ (mddev->reshape_position != MaxSector &&
+ test_bit(MD_CLOSING, &mddev->flags)))
resync_bitmap(mddev);
set_bit(MD_CLUSTER_HOLDING_MUTEX_FOR_RECVD, &cinfo->state);
@@ -1102,6 +1105,80 @@ static void metadata_update_cancel(struct mddev *mddev)
unlock_comm(cinfo);
}
+static int update_bitmap_size(struct mddev *mddev, sector_t size)
+{
+ struct md_cluster_info *cinfo = mddev->cluster_info;
+ struct cluster_msg cmsg = {0};
+ int ret;
+
+ cmsg.type = cpu_to_le32(BITMAP_RESIZE);
+ cmsg.high = cpu_to_le64(size);
+ ret = sendmsg(cinfo, &cmsg, 0);
+ if (ret)
+ pr_err("%s:%d: failed to send BITMAP_RESIZE message (%d)\n",
+ __func__, __LINE__, ret);
+ return ret;
+}
+
+static int resize_bitmaps(struct mddev *mddev, sector_t newsize, sector_t oldsize)
+{
+ struct bitmap_counts *counts;
+ char str[64];
+ struct dlm_lock_resource *bm_lockres;
+ struct bitmap *bitmap = mddev->bitmap;
+ unsigned long my_pages = bitmap->counts.pages;
+ int i, rv;
+
+ /*
+ * We need to ensure all the nodes can grow to a larger
+ * bitmap size before make the reshaping.
+ */
+ rv = update_bitmap_size(mddev, newsize);
+ if (rv)
+ return rv;
+
+ for (i = 0; i < mddev->bitmap_info.nodes; i++) {
+ if (i == md_cluster_ops->slot_number(mddev))
+ continue;
+
+ bitmap = get_bitmap_from_slot(mddev, i);
+ if (IS_ERR(bitmap)) {
+ pr_err("can't get bitmap from slot %d\n", i);
+ goto out;
+ }
+ counts = &bitmap->counts;
+
+ /*
+ * If we can hold the bitmap lock of one node then
+ * the slot is not occupied, update the pages.
+ */
+ snprintf(str, 64, "bitmap%04d", i);
+ bm_lockres = lockres_init(mddev, str, NULL, 1);
+ if (!bm_lockres) {
+ pr_err("Cannot initialize %s lock\n", str);
+ goto out;
+ }
+ bm_lockres->flags |= DLM_LKF_NOQUEUE;
+ rv = dlm_lock_sync(bm_lockres, DLM_LOCK_PW);
+ if (!rv)
+ counts->pages = my_pages;
+ lockres_free(bm_lockres);
+
+ if (my_pages != counts->pages)
+ /*
+ * Let's revert the bitmap size if one node
+ * can't resize bitmap
+ */
+ goto out;
+ }
+
+ return 0;
+out:
+ md_bitmap_free(bitmap);
+ update_bitmap_size(mddev, oldsize);
+ return -1;
+}
+
/*
* return 0 if all the bitmaps have the same sync_size
*/
@@ -1243,6 +1320,16 @@ static int resync_start(struct mddev *mddev)
return dlm_lock_sync_interruptible(cinfo->resync_lockres, DLM_LOCK_EX, mddev);
}
+static void resync_info_get(struct mddev *mddev, sector_t *lo, sector_t *hi)
+{
+ struct md_cluster_info *cinfo = mddev->cluster_info;
+
+ spin_lock_irq(&cinfo->suspend_lock);
+ *lo = cinfo->suspend_lo;
+ *hi = cinfo->suspend_hi;
+ spin_unlock_irq(&cinfo->suspend_lock);
+}
+
static int resync_info_update(struct mddev *mddev, sector_t lo, sector_t hi)
{
struct md_cluster_info *cinfo = mddev->cluster_info;
@@ -1295,21 +1382,14 @@ static int area_resyncing(struct mddev *mddev, int direction,
{
struct md_cluster_info *cinfo = mddev->cluster_info;
int ret = 0;
- struct suspend_info *s;
if ((direction == READ) &&
test_bit(MD_CLUSTER_SUSPEND_READ_BALANCING, &cinfo->state))
return 1;
spin_lock_irq(&cinfo->suspend_lock);
- if (list_empty(&cinfo->suspend_list))
- goto out;
- list_for_each_entry(s, &cinfo->suspend_list, list)
- if (hi > s->lo && lo < s->hi) {
- ret = 1;
- break;
- }
-out:
+ if (hi > cinfo->suspend_lo && lo < cinfo->suspend_hi)
+ ret = 1;
spin_unlock_irq(&cinfo->suspend_lock);
return ret;
}
@@ -1482,6 +1562,7 @@ static struct md_cluster_operations cluster_ops = {
.resync_start = resync_start,
.resync_finish = resync_finish,
.resync_info_update = resync_info_update,
+ .resync_info_get = resync_info_get,
.metadata_update_start = metadata_update_start,
.metadata_update_finish = metadata_update_finish,
.metadata_update_cancel = metadata_update_cancel,
@@ -1492,6 +1573,7 @@ static struct md_cluster_operations cluster_ops = {
.remove_disk = remove_disk,
.load_bitmaps = load_bitmaps,
.gather_bitmaps = gather_bitmaps,
+ .resize_bitmaps = resize_bitmaps,
.lock_all_bitmaps = lock_all_bitmaps,
.unlock_all_bitmaps = unlock_all_bitmaps,
.update_size = update_size,
diff --git a/drivers/md/md-cluster.h b/drivers/md/md-cluster.h
index c0240708f443..a78e3021775d 100644
--- a/drivers/md/md-cluster.h
+++ b/drivers/md/md-cluster.h
@@ -14,6 +14,7 @@ struct md_cluster_operations {
int (*leave)(struct mddev *mddev);
int (*slot_number)(struct mddev *mddev);
int (*resync_info_update)(struct mddev *mddev, sector_t lo, sector_t hi);
+ void (*resync_info_get)(struct mddev *mddev, sector_t *lo, sector_t *hi);
int (*metadata_update_start)(struct mddev *mddev);
int (*metadata_update_finish)(struct mddev *mddev);
void (*metadata_update_cancel)(struct mddev *mddev);
@@ -26,6 +27,7 @@ struct md_cluster_operations {
int (*remove_disk)(struct mddev *mddev, struct md_rdev *rdev);
void (*load_bitmaps)(struct mddev *mddev, int total_slots);
int (*gather_bitmaps)(struct md_rdev *rdev);
+ int (*resize_bitmaps)(struct mddev *mddev, sector_t newsize, sector_t oldsize);
int (*lock_all_bitmaps)(struct mddev *mddev);
void (*unlock_all_bitmaps)(struct mddev *mddev);
void (*update_size)(struct mddev *mddev, sector_t old_dev_sectors);
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 63ceabb4e020..fc488cb30a94 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -452,10 +452,11 @@ static void md_end_flush(struct bio *fbio)
rdev_dec_pending(rdev, mddev);
if (atomic_dec_and_test(&fi->flush_pending)) {
- if (bio->bi_iter.bi_size == 0)
+ if (bio->bi_iter.bi_size == 0) {
/* an empty barrier - all done */
bio_endio(bio);
- else {
+ mempool_free(fi, mddev->flush_pool);
+ } else {
INIT_WORK(&fi->flush_work, submit_flushes);
queue_work(md_wq, &fi->flush_work);
}
@@ -509,10 +510,11 @@ void md_flush_request(struct mddev *mddev, struct bio *bio)
rcu_read_unlock();
if (atomic_dec_and_test(&fi->flush_pending)) {
- if (bio->bi_iter.bi_size == 0)
+ if (bio->bi_iter.bi_size == 0) {
/* an empty barrier - all done */
bio_endio(bio);
- else {
+ mempool_free(fi, mddev->flush_pool);
+ } else {
INIT_WORK(&fi->flush_work, submit_flushes);
queue_work(md_wq, &fi->flush_work);
}
@@ -5904,14 +5906,6 @@ static void __md_stop(struct mddev *mddev)
mddev->to_remove = &md_redundancy_group;
module_put(pers->owner);
clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
-}
-
-void md_stop(struct mddev *mddev)
-{
- /* stop the array and free an attached data structures.
- * This is called from dm-raid
- */
- __md_stop(mddev);
if (mddev->flush_bio_pool) {
mempool_destroy(mddev->flush_bio_pool);
mddev->flush_bio_pool = NULL;
@@ -5920,6 +5914,14 @@ void md_stop(struct mddev *mddev)
mempool_destroy(mddev->flush_pool);
mddev->flush_pool = NULL;
}
+}
+
+void md_stop(struct mddev *mddev)
+{
+ /* stop the array and free an attached data structures.
+ * This is called from dm-raid
+ */
+ __md_stop(mddev);
bioset_exit(&mddev->bio_set);
bioset_exit(&mddev->sync_set);
}
@@ -8370,9 +8372,17 @@ void md_do_sync(struct md_thread *thread)
else if (!mddev->bitmap)
j = mddev->recovery_cp;
- } else if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
+ } else if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) {
max_sectors = mddev->resync_max_sectors;
- else {
+ /*
+ * If the original node aborts reshaping then we continue the
+ * reshaping, so set j again to avoid restart reshape from the
+ * first beginning
+ */
+ if (mddev_is_clustered(mddev) &&
+ mddev->reshape_position != MaxSector)
+ j = mddev->reshape_position;
+ } else {
/* recovery follows the physical size of devices */
max_sectors = mddev->dev_sectors;
j = MaxSector;
@@ -8623,8 +8633,10 @@ void md_do_sync(struct md_thread *thread)
mddev_lock_nointr(mddev);
md_set_array_sectors(mddev, mddev->pers->size(mddev, 0, 0));
mddev_unlock(mddev);
- set_capacity(mddev->gendisk, mddev->array_sectors);
- revalidate_disk(mddev->gendisk);
+ if (!mddev_is_clustered(mddev)) {
+ set_capacity(mddev->gendisk, mddev->array_sectors);
+ revalidate_disk(mddev->gendisk);
+ }
}
spin_lock(&mddev->lock);
@@ -8790,6 +8802,18 @@ static void md_start_sync(struct work_struct *ws)
*/
void md_check_recovery(struct mddev *mddev)
{
+ if (test_bit(MD_ALLOW_SB_UPDATE, &mddev->flags) && mddev->sb_flags) {
+ /* Write superblock - thread that called mddev_suspend()
+ * holds reconfig_mutex for us.
+ */
+ set_bit(MD_UPDATING_SB, &mddev->flags);
+ smp_mb__after_atomic();
+ if (test_bit(MD_ALLOW_SB_UPDATE, &mddev->flags))
+ md_update_sb(mddev, 0);
+ clear_bit_unlock(MD_UPDATING_SB, &mddev->flags);
+ wake_up(&mddev->sb_wait);
+ }
+
if (mddev->suspended)
return;
@@ -8949,16 +8973,6 @@ void md_check_recovery(struct mddev *mddev)
unlock:
wake_up(&mddev->sb_wait);
mddev_unlock(mddev);
- } else if (test_bit(MD_ALLOW_SB_UPDATE, &mddev->flags) && mddev->sb_flags) {
- /* Write superblock - thread that called mddev_suspend()
- * holds reconfig_mutex for us.
- */
- set_bit(MD_UPDATING_SB, &mddev->flags);
- smp_mb__after_atomic();
- if (test_bit(MD_ALLOW_SB_UPDATE, &mddev->flags))
- md_update_sb(mddev, 0);
- clear_bit_unlock(MD_UPDATING_SB, &mddev->flags);
- wake_up(&mddev->sb_wait);
}
}
EXPORT_SYMBOL(md_check_recovery);
@@ -8966,6 +8980,8 @@ EXPORT_SYMBOL(md_check_recovery);
void md_reap_sync_thread(struct mddev *mddev)
{
struct md_rdev *rdev;
+ sector_t old_dev_sectors = mddev->dev_sectors;
+ bool is_reshaped = false;
/* resync has finished, collect result */
md_unregister_thread(&mddev->sync_thread);
@@ -8980,8 +8996,11 @@ void md_reap_sync_thread(struct mddev *mddev)
}
}
if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
- mddev->pers->finish_reshape)
+ mddev->pers->finish_reshape) {
mddev->pers->finish_reshape(mddev);
+ if (mddev_is_clustered(mddev))
+ is_reshaped = true;
+ }
/* If array is no-longer degraded, then any saved_raid_disk
* information must be scrapped.
@@ -9002,6 +9021,14 @@ void md_reap_sync_thread(struct mddev *mddev)
clear_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
clear_bit(MD_RECOVERY_REQUESTED, &mddev->recovery);
clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
+ /*
+ * We call md_cluster_ops->update_size here because sync_size could
+ * be changed by md_update_sb, and MD_RECOVERY_RESHAPE is cleared,
+ * so it is time to update size across cluster.
+ */
+ if (mddev_is_clustered(mddev) && is_reshaped
+ && !test_bit(MD_CLOSING, &mddev->flags))
+ md_cluster_ops->update_size(mddev, old_dev_sectors);
wake_up(&resync_wait);
/* flag recovery needed just to double check */
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
@@ -9201,8 +9228,12 @@ static void check_sb_changes(struct mddev *mddev, struct md_rdev *rdev)
}
if (role != rdev2->raid_disk) {
- /* got activated */
- if (rdev2->raid_disk == -1 && role != 0xffff) {
+ /*
+ * got activated except reshape is happening.
+ */
+ if (rdev2->raid_disk == -1 && role != 0xffff &&
+ !(le32_to_cpu(sb->feature_map) &
+ MD_FEATURE_RESHAPE_ACTIVE)) {
rdev2->saved_raid_disk = role;
ret = remove_and_add_spares(mddev, rdev2);
pr_info("Activated spare: %s\n",
@@ -9228,6 +9259,30 @@ static void check_sb_changes(struct mddev *mddev, struct md_rdev *rdev)
if (mddev->raid_disks != le32_to_cpu(sb->raid_disks))
update_raid_disks(mddev, le32_to_cpu(sb->raid_disks));
+ /*
+ * Since mddev->delta_disks has already updated in update_raid_disks,
+ * so it is time to check reshape.
+ */
+ if (test_bit(MD_RESYNCING_REMOTE, &mddev->recovery) &&
+ (le32_to_cpu(sb->feature_map) & MD_FEATURE_RESHAPE_ACTIVE)) {
+ /*
+ * reshape is happening in the remote node, we need to
+ * update reshape_position and call start_reshape.
+ */
+ mddev->reshape_position = sb->reshape_position;
+ if (mddev->pers->update_reshape_pos)
+ mddev->pers->update_reshape_pos(mddev);
+ if (mddev->pers->start_reshape)
+ mddev->pers->start_reshape(mddev);
+ } else if (test_bit(MD_RESYNCING_REMOTE, &mddev->recovery) &&
+ mddev->reshape_position != MaxSector &&
+ !(le32_to_cpu(sb->feature_map) & MD_FEATURE_RESHAPE_ACTIVE)) {
+ /* reshape is just done in another node. */
+ mddev->reshape_position = MaxSector;
+ if (mddev->pers->update_reshape_pos)
+ mddev->pers->update_reshape_pos(mddev);
+ }
+
/* Finally set the event to be up to date */
mddev->events = le64_to_cpu(sb->events);
}
diff --git a/drivers/md/md.h b/drivers/md/md.h
index 8afd6bfdbfb9..c52afb52c776 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -557,6 +557,7 @@ struct md_personality
int (*check_reshape) (struct mddev *mddev);
int (*start_reshape) (struct mddev *mddev);
void (*finish_reshape) (struct mddev *mddev);
+ void (*update_reshape_pos) (struct mddev *mddev);
/* quiesce suspends or resumes internal processing.
* 1 - stop new actions and wait for action io to complete
* 0 - return to normal behaviour
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 4e990246225e..1d54109071cc 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1734,6 +1734,7 @@ static int raid1_add_disk(struct mddev *mddev, struct md_rdev *rdev)
*/
if (rdev->saved_raid_disk >= 0 &&
rdev->saved_raid_disk >= first &&
+ rdev->saved_raid_disk < conf->raid_disks &&
conf->mirrors[rdev->saved_raid_disk].rdev == NULL)
first = last = rdev->saved_raid_disk;
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index d6f7978b4449..b98e746e7fc4 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -25,6 +25,7 @@
#include <linux/seq_file.h>
#include <linux/ratelimit.h>
#include <linux/kthread.h>
+#include <linux/raid/md_p.h>
#include <trace/events/block.h>
#include "md.h"
#include "raid10.h"
@@ -1808,6 +1809,7 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev)
first = last = rdev->raid_disk;
if (rdev->saved_raid_disk >= first &&
+ rdev->saved_raid_disk < conf->geo.raid_disks &&
conf->mirrors[rdev->saved_raid_disk].rdev == NULL)
mirror = rdev->saved_raid_disk;
else
@@ -3079,6 +3081,8 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
sector_t sect;
int must_sync;
int any_working;
+ int need_recover = 0;
+ int need_replace = 0;
struct raid10_info *mirror = &conf->mirrors[i];
struct md_rdev *mrdev, *mreplace;
@@ -3086,11 +3090,15 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
mrdev = rcu_dereference(mirror->rdev);
mreplace = rcu_dereference(mirror->replacement);
- if ((mrdev == NULL ||
- test_bit(Faulty, &mrdev->flags) ||
- test_bit(In_sync, &mrdev->flags)) &&
- (mreplace == NULL ||
- test_bit(Faulty, &mreplace->flags))) {
+ if (mrdev != NULL &&
+ !test_bit(Faulty, &mrdev->flags) &&
+ !test_bit(In_sync, &mrdev->flags))
+ need_recover = 1;
+ if (mreplace != NULL &&
+ !test_bit(Faulty, &mreplace->flags))
+ need_replace = 1;
+
+ if (!need_recover && !need_replace) {
rcu_read_unlock();
continue;
}
@@ -3213,7 +3221,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
r10_bio->devs[1].devnum = i;
r10_bio->devs[1].addr = to_addr;
- if (!test_bit(In_sync, &mrdev->flags)) {
+ if (need_recover) {
bio = r10_bio->devs[1].bio;
bio->bi_next = biolist;
biolist = bio;
@@ -3230,16 +3238,11 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
bio = r10_bio->devs[1].repl_bio;
if (bio)
bio->bi_end_io = NULL;
- /* Note: if mreplace != NULL, then bio
+ /* Note: if need_replace, then bio
* cannot be NULL as r10buf_pool_alloc will
* have allocated it.
- * So the second test here is pointless.
- * But it keeps semantic-checkers happy, and
- * this comment keeps human reviewers
- * happy.
*/
- if (mreplace == NULL || bio == NULL ||
- test_bit(Faulty, &mreplace->flags))
+ if (!need_replace)
break;
bio->bi_next = biolist;
biolist = bio;
@@ -4286,12 +4289,46 @@ static int raid10_start_reshape(struct mddev *mddev)
spin_unlock_irq(&conf->device_lock);
if (mddev->delta_disks && mddev->bitmap) {
- ret = md_bitmap_resize(mddev->bitmap,
- raid10_size(mddev, 0, conf->geo.raid_disks),
- 0, 0);
+ struct mdp_superblock_1 *sb = NULL;
+ sector_t oldsize, newsize;
+
+ oldsize = raid10_size(mddev, 0, 0);
+ newsize = raid10_size(mddev, 0, conf->geo.raid_disks);
+
+ if (!mddev_is_clustered(mddev)) {
+ ret = md_bitmap_resize(mddev->bitmap, newsize, 0, 0);
+ if (ret)
+ goto abort;
+ else
+ goto out;
+ }
+
+ rdev_for_each(rdev, mddev) {
+ if (rdev->raid_disk > -1 &&
+ !test_bit(Faulty, &rdev->flags))
+ sb = page_address(rdev->sb_page);
+ }
+
+ /*
+ * some node is already performing reshape, and no need to
+ * call md_bitmap_resize again since it should be called when
+ * receiving BITMAP_RESIZE msg
+ */
+ if ((sb && (le32_to_cpu(sb->feature_map) &
+ MD_FEATURE_RESHAPE_ACTIVE)) || (oldsize == newsize))
+ goto out;
+
+ ret = md_bitmap_resize(mddev->bitmap, newsize, 0, 0);
if (ret)
goto abort;
+
+ ret = md_cluster_ops->resize_bitmaps(mddev, newsize, oldsize);
+ if (ret) {
+ md_bitmap_resize(mddev->bitmap, oldsize, 0, 0);
+ goto abort;
+ }
}
+out:
if (mddev->delta_disks > 0) {
rdev_for_each(rdev, mddev)
if (rdev->raid_disk < 0 &&
@@ -4568,6 +4605,32 @@ read_more:
r10_bio->master_bio = read_bio;
r10_bio->read_slot = r10_bio->devs[r10_bio->read_slot].devnum;
+ /*
+ * Broadcast RESYNC message to other nodes, so all nodes would not
+ * write to the region to avoid conflict.
+ */
+ if (mddev_is_clustered(mddev) && conf->cluster_sync_high <= sector_nr) {
+ struct mdp_superblock_1 *sb = NULL;
+ int sb_reshape_pos = 0;
+
+ conf->cluster_sync_low = sector_nr;
+ conf->cluster_sync_high = sector_nr + CLUSTER_RESYNC_WINDOW_SECTORS;
+ sb = page_address(rdev->sb_page);
+ if (sb) {
+ sb_reshape_pos = le64_to_cpu(sb->reshape_position);
+ /*
+ * Set cluster_sync_low again if next address for array
+ * reshape is less than cluster_sync_low. Since we can't
+ * update cluster_sync_low until it has finished reshape.
+ */
+ if (sb_reshape_pos < conf->cluster_sync_low)
+ conf->cluster_sync_low = sb_reshape_pos;
+ }
+
+ md_cluster_ops->resync_info_update(mddev, conf->cluster_sync_low,
+ conf->cluster_sync_high);
+ }
+
/* Now find the locations in the new layout */
__raid10_find_phys(&conf->geo, r10_bio);
@@ -4719,6 +4782,19 @@ static void end_reshape(struct r10conf *conf)
conf->fullsync = 0;
}
+static void raid10_update_reshape_pos(struct mddev *mddev)
+{
+ struct r10conf *conf = mddev->private;
+ sector_t lo, hi;
+
+ md_cluster_ops->resync_info_get(mddev, &lo, &hi);
+ if (((mddev->reshape_position <= hi) && (mddev->reshape_position >= lo))
+ || mddev->reshape_position == MaxSector)
+ conf->reshape_progress = mddev->reshape_position;
+ else
+ WARN_ON_ONCE(1);
+}
+
static int handle_reshape_read_error(struct mddev *mddev,
struct r10bio *r10_bio)
{
@@ -4887,6 +4963,7 @@ static struct md_personality raid10_personality =
.check_reshape = raid10_check_reshape,
.start_reshape = raid10_start_reshape,
.finish_reshape = raid10_finish_reshape,
+ .update_reshape_pos = raid10_update_reshape_pos,
.congested = raid10_congested,
};
diff --git a/drivers/md/raid5-cache.c b/drivers/md/raid5-cache.c
index e6e925add700..ec3a5ef7fee0 100644
--- a/drivers/md/raid5-cache.c
+++ b/drivers/md/raid5-cache.c
@@ -3151,8 +3151,6 @@ int r5l_init_log(struct r5conf *conf, struct md_rdev *rdev)
set_bit(MD_HAS_JOURNAL, &conf->mddev->flags);
return 0;
- rcu_assign_pointer(conf->log, NULL);
- md_unregister_thread(&log->reclaim_thread);
reclaim_thread:
mempool_exit(&log->meta_pool);
out_mempool:
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index e4e98f47865d..4990f0319f6c 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -2681,6 +2681,18 @@ static void raid5_error(struct mddev *mddev, struct md_rdev *rdev)
pr_debug("raid456: error called\n");
spin_lock_irqsave(&conf->device_lock, flags);
+
+ if (test_bit(In_sync, &rdev->flags) &&
+ mddev->degraded == conf->max_degraded) {
+ /*
+ * Don't allow to achieve failed state
+ * Don't try to recover this device
+ */
+ conf->recovery_disabled = mddev->recovery_disabled;
+ spin_unlock_irqrestore(&conf->device_lock, flags);
+ return;
+ }
+
set_bit(Faulty, &rdev->flags);
clear_bit(In_sync, &rdev->flags);
mddev->degraded = raid5_calc_degraded(conf);
diff --git a/drivers/media/Makefile b/drivers/media/Makefile
index 594b462ddf0e..985d35ec6b29 100644
--- a/drivers/media/Makefile
+++ b/drivers/media/Makefile
@@ -3,7 +3,8 @@
# Makefile for the kernel multimedia device drivers.
#
-media-objs := media-device.o media-devnode.o media-entity.o
+media-objs := media-device.o media-devnode.o media-entity.o \
+ media-request.o
#
# I2C drivers should come before other drivers, otherwise they'll fail
diff --git a/drivers/media/cec/Makefile b/drivers/media/cec/Makefile
index 29a2ab9e77c5..ad8677d8c896 100644
--- a/drivers/media/cec/Makefile
+++ b/drivers/media/cec/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
-cec-objs := cec-core.o cec-adap.o cec-api.o cec-edid.o
+cec-objs := cec-core.o cec-adap.o cec-api.o
ifeq ($(CONFIG_CEC_NOTIFIER),y)
cec-objs += cec-notifier.o
diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c
index 030b2602faf0..31d1f4ab915e 100644
--- a/drivers/media/cec/cec-adap.c
+++ b/drivers/media/cec/cec-adap.c
@@ -62,6 +62,19 @@ static unsigned int cec_log_addr2dev(const struct cec_adapter *adap, u8 log_addr
return adap->log_addrs.primary_device_type[i < 0 ? 0 : i];
}
+u16 cec_get_edid_phys_addr(const u8 *edid, unsigned int size,
+ unsigned int *offset)
+{
+ unsigned int loc = cec_get_edid_spa_location(edid, size);
+
+ if (offset)
+ *offset = loc;
+ if (loc == 0)
+ return CEC_PHYS_ADDR_INVALID;
+ return (edid[loc] << 8) | edid[loc + 1];
+}
+EXPORT_SYMBOL_GPL(cec_get_edid_phys_addr);
+
/*
* Queue a new event for this filehandle. If ts == 0, then set it
* to the current time.
@@ -341,7 +354,7 @@ static void cec_data_completed(struct cec_data *data)
*
* This function is called with adap->lock held.
*/
-static void cec_data_cancel(struct cec_data *data)
+static void cec_data_cancel(struct cec_data *data, u8 tx_status)
{
/*
* It's either the current transmit, or it is a pending
@@ -356,13 +369,11 @@ static void cec_data_cancel(struct cec_data *data)
}
if (data->msg.tx_status & CEC_TX_STATUS_OK) {
- /* Mark the canceled RX as a timeout */
data->msg.rx_ts = ktime_get_ns();
- data->msg.rx_status = CEC_RX_STATUS_TIMEOUT;
+ data->msg.rx_status = CEC_RX_STATUS_ABORTED;
} else {
- /* Mark the canceled TX as an error */
data->msg.tx_ts = ktime_get_ns();
- data->msg.tx_status |= CEC_TX_STATUS_ERROR |
+ data->msg.tx_status |= tx_status |
CEC_TX_STATUS_MAX_RETRIES;
data->msg.tx_error_cnt++;
data->attempts = 0;
@@ -390,15 +401,15 @@ static void cec_flush(struct cec_adapter *adap)
while (!list_empty(&adap->transmit_queue)) {
data = list_first_entry(&adap->transmit_queue,
struct cec_data, list);
- cec_data_cancel(data);
+ cec_data_cancel(data, CEC_TX_STATUS_ABORTED);
}
if (adap->transmitting)
- cec_data_cancel(adap->transmitting);
+ cec_data_cancel(adap->transmitting, CEC_TX_STATUS_ABORTED);
/* Cancel the pending timeout work. */
list_for_each_entry_safe(data, n, &adap->wait_queue, list) {
if (cancel_delayed_work(&data->work))
- cec_data_cancel(data);
+ cec_data_cancel(data, CEC_TX_STATUS_OK);
/*
* If cancel_delayed_work returned false, then
* the cec_wait_timeout function is running,
@@ -474,12 +485,13 @@ int cec_thread_func(void *_adap)
* so much traffic on the bus that the adapter was
* unable to transmit for CEC_XFER_TIMEOUT_MS (2.1s).
*/
- dprintk(1, "%s: message %*ph timed out\n", __func__,
+ pr_warn("cec-%s: message %*ph timed out\n", adap->name,
adap->transmitting->msg.len,
adap->transmitting->msg.msg);
adap->tx_timeouts++;
/* Just give up on this. */
- cec_data_cancel(adap->transmitting);
+ cec_data_cancel(adap->transmitting,
+ CEC_TX_STATUS_TIMEOUT);
goto unlock;
}
@@ -514,9 +526,11 @@ int cec_thread_func(void *_adap)
if (data->attempts) {
/* should be >= 3 data bit periods for a retry */
signal_free_time = CEC_SIGNAL_FREE_TIME_RETRY;
- } else if (data->new_initiator) {
+ } else if (adap->last_initiator !=
+ cec_msg_initiator(&data->msg)) {
/* should be >= 5 data bit periods for new initiator */
signal_free_time = CEC_SIGNAL_FREE_TIME_NEW_INITIATOR;
+ adap->last_initiator = cec_msg_initiator(&data->msg);
} else {
/*
* should be >= 7 data bit periods for sending another
@@ -530,7 +544,7 @@ int cec_thread_func(void *_adap)
/* Tell the adapter to transmit, cancel on error */
if (adap->ops->adap_transmit(adap, data->attempts,
signal_free_time, &data->msg))
- cec_data_cancel(data);
+ cec_data_cancel(data, CEC_TX_STATUS_ABORTED);
unlock:
mutex_unlock(&adap->lock);
@@ -701,9 +715,6 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg,
struct cec_fh *fh, bool block)
{
struct cec_data *data;
- u8 last_initiator = 0xff;
- unsigned int timeout;
- int res = 0;
msg->rx_ts = 0;
msg->tx_ts = 0;
@@ -813,23 +824,6 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg,
data->adap = adap;
data->blocking = block;
- /*
- * Determine if this message follows a message from the same
- * initiator. Needed to determine the free signal time later on.
- */
- if (msg->len > 1) {
- if (!(list_empty(&adap->transmit_queue))) {
- const struct cec_data *last;
-
- last = list_last_entry(&adap->transmit_queue,
- const struct cec_data, list);
- last_initiator = cec_msg_initiator(&last->msg);
- } else if (adap->transmitting) {
- last_initiator =
- cec_msg_initiator(&adap->transmitting->msg);
- }
- }
- data->new_initiator = last_initiator != cec_msg_initiator(msg);
init_completion(&data->c);
INIT_DELAYED_WORK(&data->work, cec_wait_timeout);
@@ -846,47 +840,22 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg,
return 0;
/*
- * If we don't get a completion before this time something is really
- * wrong and we time out.
- */
- timeout = CEC_XFER_TIMEOUT_MS;
- /* Add the requested timeout if we have to wait for a reply as well */
- if (msg->timeout)
- timeout += msg->timeout;
-
- /*
* Release the lock and wait, retake the lock afterwards.
*/
mutex_unlock(&adap->lock);
- res = wait_for_completion_killable_timeout(&data->c,
- msecs_to_jiffies(timeout));
+ wait_for_completion_killable(&data->c);
+ if (!data->completed)
+ cancel_delayed_work_sync(&data->work);
mutex_lock(&adap->lock);
- if (data->completed) {
- /* The transmit completed (possibly with an error) */
- *msg = data->msg;
- kfree(data);
- return 0;
- }
- /*
- * The wait for completion timed out or was interrupted, so mark this
- * as non-blocking and disconnect from the filehandle since it is
- * still 'in flight'. When it finally completes it will just drop the
- * result silently.
- */
- data->blocking = false;
- if (data->fh)
- list_del(&data->xfer_list);
- data->fh = NULL;
+ /* Cancel the transmit if it was interrupted */
+ if (!data->completed)
+ cec_data_cancel(data, CEC_TX_STATUS_ABORTED);
- if (res == 0) { /* timed out */
- /* Check if the reply or the transmit failed */
- if (msg->timeout && (msg->tx_status & CEC_TX_STATUS_OK))
- msg->rx_status = CEC_RX_STATUS_TIMEOUT;
- else
- msg->tx_status = CEC_TX_STATUS_MAX_RETRIES;
- }
- return res > 0 ? 0 : res;
+ /* The transmit completed (possibly with an error) */
+ *msg = data->msg;
+ kfree(data);
+ return 0;
}
/* Helper function to be used by drivers and this framework. */
@@ -1044,6 +1013,8 @@ void cec_received_msg_ts(struct cec_adapter *adap,
mutex_lock(&adap->lock);
dprintk(2, "%s: %*ph\n", __func__, msg->len, msg->msg);
+ adap->last_initiator = 0xff;
+
/* Check if this message was for us (directed or broadcast). */
if (!cec_msg_is_broadcast(msg))
valid_la = cec_has_log_addr(adap, msg_dest);
@@ -1506,6 +1477,8 @@ void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block)
}
mutex_lock(&adap->devnode.lock);
+ adap->last_initiator = 0xff;
+
if ((adap->needs_hpd || list_empty(&adap->devnode.fhs)) &&
adap->ops->adap_enable(adap, true)) {
mutex_unlock(&adap->devnode.lock);
diff --git a/drivers/media/cec/cec-api.c b/drivers/media/cec/cec-api.c
index b6536bbad530..391b6fd483e1 100644
--- a/drivers/media/cec/cec-api.c
+++ b/drivers/media/cec/cec-api.c
@@ -77,9 +77,9 @@ static long cec_adap_g_caps(struct cec_adapter *adap,
{
struct cec_caps caps = {};
- strlcpy(caps.driver, adap->devnode.dev.parent->driver->name,
+ strscpy(caps.driver, adap->devnode.dev.parent->driver->name,
sizeof(caps.driver));
- strlcpy(caps.name, adap->name, sizeof(caps.name));
+ strscpy(caps.name, adap->name, sizeof(caps.name));
caps.available_log_addrs = adap->available_log_addrs;
caps.capabilities = adap->capabilities;
caps.version = LINUX_VERSION_CODE;
@@ -101,6 +101,23 @@ static long cec_adap_g_phys_addr(struct cec_adapter *adap,
return 0;
}
+static int cec_validate_phys_addr(u16 phys_addr)
+{
+ int i;
+
+ if (phys_addr == CEC_PHYS_ADDR_INVALID)
+ return 0;
+ for (i = 0; i < 16; i += 4)
+ if (phys_addr & (0xf << i))
+ break;
+ if (i == 16)
+ return 0;
+ for (i += 4; i < 16; i += 4)
+ if ((phys_addr & (0xf << i)) == 0)
+ return -EINVAL;
+ return 0;
+}
+
static long cec_adap_s_phys_addr(struct cec_adapter *adap, struct cec_fh *fh,
bool block, __u16 __user *parg)
{
@@ -112,7 +129,7 @@ static long cec_adap_s_phys_addr(struct cec_adapter *adap, struct cec_fh *fh,
if (copy_from_user(&phys_addr, parg, sizeof(phys_addr)))
return -EFAULT;
- err = cec_phys_addr_validate(phys_addr, NULL, NULL);
+ err = cec_validate_phys_addr(phys_addr);
if (err)
return err;
mutex_lock(&adap->lock);
@@ -665,6 +682,7 @@ const struct file_operations cec_devnode_fops = {
.owner = THIS_MODULE,
.open = cec_open,
.unlocked_ioctl = cec_ioctl,
+ .compat_ioctl = cec_ioctl,
.release = cec_release,
.poll = cec_poll,
.llseek = no_llseek,
diff --git a/drivers/media/cec/cec-core.c b/drivers/media/cec/cec-core.c
index b278ab90b387..e4edc930d4ed 100644
--- a/drivers/media/cec/cec-core.c
+++ b/drivers/media/cec/cec-core.c
@@ -264,7 +264,7 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,
adap = kzalloc(sizeof(*adap), GFP_KERNEL);
if (!adap)
return ERR_PTR(-ENOMEM);
- strlcpy(adap->name, name, sizeof(adap->name));
+ strscpy(adap->name, name, sizeof(adap->name));
adap->phys_addr = CEC_PHYS_ADDR_INVALID;
adap->cec_pin_is_high = true;
adap->log_addrs.cec_version = CEC_OP_CEC_VERSION_2_0;
@@ -307,12 +307,10 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,
return ERR_PTR(-ENOMEM);
}
- snprintf(adap->device_name, sizeof(adap->device_name),
- "RC for %s", name);
snprintf(adap->input_phys, sizeof(adap->input_phys),
- "%s/input0", name);
+ "%s/input0", adap->name);
- adap->rc->device_name = adap->device_name;
+ adap->rc->device_name = adap->name;
adap->rc->input_phys = adap->input_phys;
adap->rc->input_id.bustype = BUS_CEC;
adap->rc->input_id.vendor = 0;
diff --git a/drivers/media/cec/cec-edid.c b/drivers/media/cec/cec-edid.c
deleted file mode 100644
index ec72ac1c0b91..000000000000
--- a/drivers/media/cec/cec-edid.c
+++ /dev/null
@@ -1,155 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * cec-edid - HDMI Consumer Electronics Control EDID & CEC helper functions
- *
- * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <media/cec.h>
-
-/*
- * This EDID is expected to be a CEA-861 compliant, which means that there are
- * at least two blocks and one or more of the extensions blocks are CEA-861
- * blocks.
- *
- * The returned location is guaranteed to be < size - 1.
- */
-static unsigned int cec_get_edid_spa_location(const u8 *edid, unsigned int size)
-{
- unsigned int blocks = size / 128;
- unsigned int block;
- u8 d;
-
- /* Sanity check: at least 2 blocks and a multiple of the block size */
- if (blocks < 2 || size % 128)
- return 0;
-
- /*
- * If there are fewer extension blocks than the size, then update
- * 'blocks'. It is allowed to have more extension blocks than the size,
- * since some hardware can only read e.g. 256 bytes of the EDID, even
- * though more blocks are present. The first CEA-861 extension block
- * should normally be in block 1 anyway.
- */
- if (edid[0x7e] + 1 < blocks)
- blocks = edid[0x7e] + 1;
-
- for (block = 1; block < blocks; block++) {
- unsigned int offset = block * 128;
-
- /* Skip any non-CEA-861 extension blocks */
- if (edid[offset] != 0x02 || edid[offset + 1] != 0x03)
- continue;
-
- /* search Vendor Specific Data Block (tag 3) */
- d = edid[offset + 2] & 0x7f;
- /* Check if there are Data Blocks */
- if (d <= 4)
- continue;
- if (d > 4) {
- unsigned int i = offset + 4;
- unsigned int end = offset + d;
-
- /* Note: 'end' is always < 'size' */
- do {
- u8 tag = edid[i] >> 5;
- u8 len = edid[i] & 0x1f;
-
- if (tag == 3 && len >= 5 && i + len <= end &&
- edid[i + 1] == 0x03 &&
- edid[i + 2] == 0x0c &&
- edid[i + 3] == 0x00)
- return i + 4;
- i += len + 1;
- } while (i < end);
- }
- }
- return 0;
-}
-
-u16 cec_get_edid_phys_addr(const u8 *edid, unsigned int size,
- unsigned int *offset)
-{
- unsigned int loc = cec_get_edid_spa_location(edid, size);
-
- if (offset)
- *offset = loc;
- if (loc == 0)
- return CEC_PHYS_ADDR_INVALID;
- return (edid[loc] << 8) | edid[loc + 1];
-}
-EXPORT_SYMBOL_GPL(cec_get_edid_phys_addr);
-
-void cec_set_edid_phys_addr(u8 *edid, unsigned int size, u16 phys_addr)
-{
- unsigned int loc = cec_get_edid_spa_location(edid, size);
- u8 sum = 0;
- unsigned int i;
-
- if (loc == 0)
- return;
- edid[loc] = phys_addr >> 8;
- edid[loc + 1] = phys_addr & 0xff;
- loc &= ~0x7f;
-
- /* update the checksum */
- for (i = loc; i < loc + 127; i++)
- sum += edid[i];
- edid[i] = 256 - sum;
-}
-EXPORT_SYMBOL_GPL(cec_set_edid_phys_addr);
-
-u16 cec_phys_addr_for_input(u16 phys_addr, u8 input)
-{
- /* Check if input is sane */
- if (WARN_ON(input == 0 || input > 0xf))
- return CEC_PHYS_ADDR_INVALID;
-
- if (phys_addr == 0)
- return input << 12;
-
- if ((phys_addr & 0x0fff) == 0)
- return phys_addr | (input << 8);
-
- if ((phys_addr & 0x00ff) == 0)
- return phys_addr | (input << 4);
-
- if ((phys_addr & 0x000f) == 0)
- return phys_addr | input;
-
- /*
- * All nibbles are used so no valid physical addresses can be assigned
- * to the input.
- */
- return CEC_PHYS_ADDR_INVALID;
-}
-EXPORT_SYMBOL_GPL(cec_phys_addr_for_input);
-
-int cec_phys_addr_validate(u16 phys_addr, u16 *parent, u16 *port)
-{
- int i;
-
- if (parent)
- *parent = phys_addr;
- if (port)
- *port = 0;
- if (phys_addr == CEC_PHYS_ADDR_INVALID)
- return 0;
- for (i = 0; i < 16; i += 4)
- if (phys_addr & (0xf << i))
- break;
- if (i == 16)
- return 0;
- if (parent)
- *parent = phys_addr & (0xfff0 << i);
- if (port)
- *port = (phys_addr >> i) & 0xf;
- for (i += 4; i < 16; i += 4)
- if ((phys_addr & (0xf << i)) == 0)
- return -EINVAL;
- return 0;
-}
-EXPORT_SYMBOL_GPL(cec_phys_addr_validate);
diff --git a/drivers/media/cec/cec-pin.c b/drivers/media/cec/cec-pin.c
index 6e311424f0dc..635db8e70ead 100644
--- a/drivers/media/cec/cec-pin.c
+++ b/drivers/media/cec/cec-pin.c
@@ -935,6 +935,17 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer)
/* Start bit, switch to receive state */
pin->ts = ts;
pin->state = CEC_ST_RX_START_BIT_LOW;
+ /*
+ * If a transmit is pending, then that transmit should
+ * use a signal free time of no more than
+ * CEC_SIGNAL_FREE_TIME_NEW_INITIATOR since it will
+ * have a new initiator due to the receive that is now
+ * starting.
+ */
+ if (pin->tx_msg.len && pin->tx_signal_free_time >
+ CEC_SIGNAL_FREE_TIME_NEW_INITIATOR)
+ pin->tx_signal_free_time =
+ CEC_SIGNAL_FREE_TIME_NEW_INITIATOR;
break;
}
if (ktime_to_ns(pin->ts) == 0)
@@ -1157,6 +1168,15 @@ static int cec_pin_adap_transmit(struct cec_adapter *adap, u8 attempts,
{
struct cec_pin *pin = adap->pin;
+ /*
+ * If a receive is in progress, then this transmit should use
+ * a signal free time of max CEC_SIGNAL_FREE_TIME_NEW_INITIATOR
+ * since when it starts transmitting it will have a new initiator.
+ */
+ if (pin->state != CEC_ST_IDLE &&
+ signal_free_time > CEC_SIGNAL_FREE_TIME_NEW_INITIATOR)
+ signal_free_time = CEC_SIGNAL_FREE_TIME_NEW_INITIATOR;
+
pin->tx_signal_free_time = signal_free_time;
pin->tx_extra_bytes = 0;
pin->tx_msg = *msg;
diff --git a/drivers/media/common/b2c2/flexcop-i2c.c b/drivers/media/common/b2c2/flexcop-i2c.c
index 6675b605eb6f..1f1eaa807811 100644
--- a/drivers/media/common/b2c2/flexcop-i2c.c
+++ b/drivers/media/common/b2c2/flexcop-i2c.c
@@ -226,12 +226,12 @@ int flexcop_i2c_init(struct flexcop_device *fc)
fc->fc_i2c_adap[1].port = FC_I2C_PORT_EEPROM;
fc->fc_i2c_adap[2].port = FC_I2C_PORT_TUNER;
- strlcpy(fc->fc_i2c_adap[0].i2c_adap.name, "B2C2 FlexCop I2C to demod",
- sizeof(fc->fc_i2c_adap[0].i2c_adap.name));
- strlcpy(fc->fc_i2c_adap[1].i2c_adap.name, "B2C2 FlexCop I2C to eeprom",
- sizeof(fc->fc_i2c_adap[1].i2c_adap.name));
- strlcpy(fc->fc_i2c_adap[2].i2c_adap.name, "B2C2 FlexCop I2C to tuner",
- sizeof(fc->fc_i2c_adap[2].i2c_adap.name));
+ strscpy(fc->fc_i2c_adap[0].i2c_adap.name, "B2C2 FlexCop I2C to demod",
+ sizeof(fc->fc_i2c_adap[0].i2c_adap.name));
+ strscpy(fc->fc_i2c_adap[1].i2c_adap.name, "B2C2 FlexCop I2C to eeprom",
+ sizeof(fc->fc_i2c_adap[1].i2c_adap.name));
+ strscpy(fc->fc_i2c_adap[2].i2c_adap.name, "B2C2 FlexCop I2C to tuner",
+ sizeof(fc->fc_i2c_adap[2].i2c_adap.name));
i2c_set_adapdata(&fc->fc_i2c_adap[0].i2c_adap, &fc->fc_i2c_adap[0]);
i2c_set_adapdata(&fc->fc_i2c_adap[1].i2c_adap, &fc->fc_i2c_adap[1]);
diff --git a/drivers/media/common/cx2341x.c b/drivers/media/common/cx2341x.c
index 81dce9a81bd3..1dcc39b87bb7 100644
--- a/drivers/media/common/cx2341x.c
+++ b/drivers/media/common/cx2341x.c
@@ -569,7 +569,7 @@ static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl,
qctrl->step = step;
qctrl->default_value = def;
qctrl->reserved[0] = qctrl->reserved[1] = 0;
- strlcpy(qctrl->name, name, sizeof(qctrl->name));
+ strscpy(qctrl->name, name, sizeof(qctrl->name));
return 0;
default:
diff --git a/drivers/media/common/saa7146/saa7146_fops.c b/drivers/media/common/saa7146/saa7146_fops.c
index d4987fd05d05..c790ae264464 100644
--- a/drivers/media/common/saa7146/saa7146_fops.c
+++ b/drivers/media/common/saa7146/saa7146_fops.c
@@ -606,7 +606,7 @@ int saa7146_register_device(struct video_device *vfd, struct saa7146_dev *dev,
vfd->tvnorms = 0;
for (i = 0; i < dev->ext_vv_data->num_stds; i++)
vfd->tvnorms |= dev->ext_vv_data->stds[i].id;
- strlcpy(vfd->name, name, sizeof(vfd->name));
+ strscpy(vfd->name, name, sizeof(vfd->name));
video_set_drvdata(vfd, dev);
err = video_register_device(vfd, type, -1);
diff --git a/drivers/media/common/saa7146/saa7146_video.c b/drivers/media/common/saa7146/saa7146_video.c
index 0dfa0c09d646..f90aa8109663 100644
--- a/drivers/media/common/saa7146/saa7146_video.c
+++ b/drivers/media/common/saa7146/saa7146_video.c
@@ -451,8 +451,8 @@ static int vidioc_querycap(struct file *file, void *fh, struct v4l2_capability *
struct video_device *vdev = video_devdata(file);
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
- strcpy((char *)cap->driver, "saa7146 v4l2");
- strlcpy((char *)cap->card, dev->ext->name, sizeof(cap->card));
+ strscpy((char *)cap->driver, "saa7146 v4l2", sizeof(cap->driver));
+ strscpy((char *)cap->card, dev->ext->name, sizeof(cap->card));
sprintf((char *)cap->bus_info, "PCI:%s", pci_name(dev->pci));
cap->device_caps =
V4L2_CAP_VIDEO_CAPTURE |
@@ -525,8 +525,8 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtd
{
if (f->index >= ARRAY_SIZE(formats))
return -EINVAL;
- strlcpy((char *)f->description, formats[f->index].name,
- sizeof(f->description));
+ strscpy((char *)f->description, formats[f->index].name,
+ sizeof(f->description));
f->pixelformat = formats[f->index].pixelformat;
return 0;
}
diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c
index 3b02cb570a6e..add9d6361914 100644
--- a/drivers/media/common/siano/smscoreapi.c
+++ b/drivers/media/common/siano/smscoreapi.c
@@ -450,7 +450,7 @@ static struct smscore_registry_entry_t *smscore_find_registry(char *devpath)
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
if (entry) {
entry->mode = default_mode;
- strlcpy(entry->devpath, devpath, sizeof(entry->devpath));
+ strscpy(entry->devpath, devpath, sizeof(entry->devpath));
list_add(&entry->entry, &g_smscore_registry);
} else
pr_err("failed to create smscore_registry.\n");
@@ -735,7 +735,7 @@ int smscore_register_device(struct smsdevice_params_t *params,
dev->postload_handler = params->postload_handler;
dev->device_flags = params->flags;
- strlcpy(dev->devpath, params->devpath, sizeof(dev->devpath));
+ strscpy(dev->devpath, params->devpath, sizeof(dev->devpath));
smscore_registry_settype(dev->devpath, params->device_type);
diff --git a/drivers/media/common/siano/smsir.c b/drivers/media/common/siano/smsir.c
index 56db0a944421..79bd627f84b8 100644
--- a/drivers/media/common/siano/smsir.c
+++ b/drivers/media/common/siano/smsir.c
@@ -26,10 +26,10 @@ void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len)
const s32 *samples = (const void *)buf;
for (i = 0; i < len >> 2; i++) {
- DEFINE_IR_RAW_EVENT(ev);
-
- ev.duration = abs(samples[i]) * 1000; /* Convert to ns */
- ev.pulse = (samples[i] > 0) ? false : true;
+ struct ir_raw_event ev = {
+ .duration = abs(samples[i]) * 1000, /* Convert to ns */
+ .pulse = (samples[i] > 0) ? false : true
+ };
ir_raw_event_store(coredev->ir.dev, &ev);
}
@@ -55,7 +55,7 @@ int sms_ir_init(struct smscore_device_t *coredev)
snprintf(coredev->ir.name, sizeof(coredev->ir.name),
"SMS IR (%s)", sms_get_board(board_id)->name);
- strlcpy(coredev->ir.phys, coredev->devpath, sizeof(coredev->ir.phys));
+ strscpy(coredev->ir.phys, coredev->devpath, sizeof(coredev->ir.phys));
strlcat(coredev->ir.phys, "/ir0", sizeof(coredev->ir.phys));
dev->device_name = coredev->ir.name;
diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-colors.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-colors.c
index 3a3dc23c560c..a4341205c197 100644
--- a/drivers/media/common/v4l2-tpg/v4l2-tpg-colors.c
+++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-colors.c
@@ -602,14 +602,14 @@ const struct tpg_rbg_color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1][V4L2_XFE
[V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SRGB][5] = { 3138, 657, 810 },
[V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SRGB][6] = { 731, 680, 3048 },
[V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SRGB][7] = { 800, 799, 800 },
- [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 },
- [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][1] = { 3046, 3054, 886 },
- [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][2] = { 0, 3058, 3031 },
- [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][3] = { 360, 3079, 877 },
- [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][4] = { 3103, 587, 3027 },
- [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][5] = { 3116, 723, 861 },
- [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][6] = { 789, 744, 3025 },
- [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 },
+ [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_OPRGB][0] = { 3033, 3033, 3033 },
+ [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_OPRGB][1] = { 3046, 3054, 886 },
+ [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_OPRGB][2] = { 0, 3058, 3031 },
+ [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_OPRGB][3] = { 360, 3079, 877 },
+ [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_OPRGB][4] = { 3103, 587, 3027 },
+ [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_OPRGB][5] = { 3116, 723, 861 },
+ [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_OPRGB][6] = { 789, 744, 3025 },
+ [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_OPRGB][7] = { 851, 851, 851 },
[V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 },
[V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE240M][1] = { 2941, 2950, 546 },
[V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE240M][2] = { 0, 2954, 2924 },
@@ -658,14 +658,14 @@ const struct tpg_rbg_color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1][V4L2_XFE
[V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SRGB][5] = { 3138, 657, 810 },
[V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SRGB][6] = { 731, 680, 3048 },
[V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SRGB][7] = { 800, 799, 800 },
- [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 },
- [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][1] = { 3046, 3054, 886 },
- [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][2] = { 0, 3058, 3031 },
- [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][3] = { 360, 3079, 877 },
- [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][4] = { 3103, 587, 3027 },
- [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][5] = { 3116, 723, 861 },
- [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][6] = { 789, 744, 3025 },
- [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 },
+ [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_OPRGB][0] = { 3033, 3033, 3033 },
+ [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_OPRGB][1] = { 3046, 3054, 886 },
+ [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_OPRGB][2] = { 0, 3058, 3031 },
+ [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_OPRGB][3] = { 360, 3079, 877 },
+ [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_OPRGB][4] = { 3103, 587, 3027 },
+ [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_OPRGB][5] = { 3116, 723, 861 },
+ [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_OPRGB][6] = { 789, 744, 3025 },
+ [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_OPRGB][7] = { 851, 851, 851 },
[V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 },
[V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE240M][1] = { 2941, 2950, 546 },
[V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE240M][2] = { 0, 2954, 2924 },
@@ -714,14 +714,14 @@ const struct tpg_rbg_color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1][V4L2_XFE
[V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SRGB][5] = { 3056, 800, 800 },
[V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SRGB][6] = { 800, 800, 3056 },
[V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SRGB][7] = { 800, 800, 800 },
- [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 },
- [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][1] = { 3033, 3033, 851 },
- [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][2] = { 851, 3033, 3033 },
- [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][3] = { 851, 3033, 851 },
- [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][4] = { 3033, 851, 3033 },
- [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][5] = { 3033, 851, 851 },
- [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][6] = { 851, 851, 3033 },
- [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 },
+ [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_OPRGB][0] = { 3033, 3033, 3033 },
+ [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_OPRGB][1] = { 3033, 3033, 851 },
+ [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_OPRGB][2] = { 851, 3033, 3033 },
+ [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_OPRGB][3] = { 851, 3033, 851 },
+ [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_OPRGB][4] = { 3033, 851, 3033 },
+ [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_OPRGB][5] = { 3033, 851, 851 },
+ [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_OPRGB][6] = { 851, 851, 3033 },
+ [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_OPRGB][7] = { 851, 851, 851 },
[V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 },
[V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE240M][1] = { 2926, 2926, 507 },
[V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE240M][2] = { 507, 2926, 2926 },
@@ -770,14 +770,14 @@ const struct tpg_rbg_color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1][V4L2_XFE
[V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SRGB][5] = { 2599, 901, 909 },
[V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SRGB][6] = { 991, 0, 2966 },
[V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SRGB][7] = { 800, 799, 800 },
- [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 },
- [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][1] = { 2989, 3120, 1180 },
- [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][2] = { 1913, 3011, 3009 },
- [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][3] = { 1836, 3099, 1105 },
- [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][4] = { 2627, 413, 2966 },
- [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][5] = { 2576, 943, 951 },
- [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][6] = { 1026, 0, 2942 },
- [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 },
+ [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_OPRGB][0] = { 3033, 3033, 3033 },
+ [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_OPRGB][1] = { 2989, 3120, 1180 },
+ [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_OPRGB][2] = { 1913, 3011, 3009 },
+ [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_OPRGB][3] = { 1836, 3099, 1105 },
+ [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_OPRGB][4] = { 2627, 413, 2966 },
+ [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_OPRGB][5] = { 2576, 943, 951 },
+ [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_OPRGB][6] = { 1026, 0, 2942 },
+ [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_OPRGB][7] = { 851, 851, 851 },
[V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 },
[V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE240M][1] = { 2879, 3022, 874 },
[V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE240M][2] = { 1688, 2903, 2901 },
@@ -826,14 +826,14 @@ const struct tpg_rbg_color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1][V4L2_XFE
[V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SRGB][5] = { 3001, 800, 799 },
[V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SRGB][6] = { 800, 800, 3071 },
[V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SRGB][7] = { 800, 800, 799 },
- [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 },
- [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][1] = { 3033, 3033, 776 },
- [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][2] = { 1068, 3033, 3033 },
- [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][3] = { 1068, 3033, 776 },
- [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][4] = { 2977, 851, 3048 },
- [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][5] = { 2977, 851, 851 },
- [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][6] = { 851, 851, 3048 },
- [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 },
+ [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_OPRGB][0] = { 3033, 3033, 3033 },
+ [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_OPRGB][1] = { 3033, 3033, 776 },
+ [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_OPRGB][2] = { 1068, 3033, 3033 },
+ [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_OPRGB][3] = { 1068, 3033, 776 },
+ [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_OPRGB][4] = { 2977, 851, 3048 },
+ [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_OPRGB][5] = { 2977, 851, 851 },
+ [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_OPRGB][6] = { 851, 851, 3048 },
+ [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_OPRGB][7] = { 851, 851, 851 },
[V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 },
[V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE240M][1] = { 2926, 2926, 423 },
[V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE240M][2] = { 749, 2926, 2926 },
@@ -882,14 +882,14 @@ const struct tpg_rbg_color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1][V4L2_XFE
[V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SRGB][5] = { 3056, 800, 800 },
[V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SRGB][6] = { 800, 800, 3056 },
[V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SRGB][7] = { 800, 800, 800 },
- [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 },
- [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][1] = { 3033, 3033, 851 },
- [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][2] = { 851, 3033, 3033 },
- [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][3] = { 851, 3033, 851 },
- [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][4] = { 3033, 851, 3033 },
- [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][5] = { 3033, 851, 851 },
- [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][6] = { 851, 851, 3033 },
- [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 },
+ [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_OPRGB][0] = { 3033, 3033, 3033 },
+ [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_OPRGB][1] = { 3033, 3033, 851 },
+ [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_OPRGB][2] = { 851, 3033, 3033 },
+ [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_OPRGB][3] = { 851, 3033, 851 },
+ [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_OPRGB][4] = { 3033, 851, 3033 },
+ [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_OPRGB][5] = { 3033, 851, 851 },
+ [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_OPRGB][6] = { 851, 851, 3033 },
+ [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_OPRGB][7] = { 851, 851, 851 },
[V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 },
[V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE240M][1] = { 2926, 2926, 507 },
[V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE240M][2] = { 507, 2926, 2926 },
@@ -922,62 +922,62 @@ const struct tpg_rbg_color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1][V4L2_XFE
[V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][5] = { 1812, 886, 886 },
[V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][6] = { 886, 886, 1812 },
[V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][7] = { 886, 886, 886 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][1] = { 2939, 2939, 781 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][2] = { 1622, 2939, 2939 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][3] = { 1622, 2939, 781 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][4] = { 2502, 547, 2881 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][5] = { 2502, 547, 547 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][6] = { 547, 547, 2881 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][7] = { 547, 547, 547 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][0] = { 3056, 3056, 3056 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][1] = { 3056, 3056, 1031 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][2] = { 1838, 3056, 3056 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][3] = { 1838, 3056, 1031 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][4] = { 2657, 800, 3002 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][5] = { 2657, 800, 800 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][6] = { 800, 800, 3002 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SRGB][7] = { 800, 800, 800 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][1] = { 3033, 3033, 1063 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][2] = { 1828, 3033, 3033 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][3] = { 1828, 3033, 1063 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][4] = { 2633, 851, 2979 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][5] = { 2633, 851, 851 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][6] = { 851, 851, 2979 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][1] = { 2926, 2926, 744 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][2] = { 1594, 2926, 2926 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][3] = { 1594, 2926, 744 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][4] = { 2484, 507, 2867 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][5] = { 2484, 507, 507 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][6] = { 507, 507, 2867 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE240M][7] = { 507, 507, 507 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][0] = { 2125, 2125, 2125 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][1] = { 2125, 2125, 212 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][2] = { 698, 2125, 2125 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][3] = { 698, 2125, 212 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][4] = { 1557, 130, 2043 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][5] = { 1557, 130, 130 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][6] = { 130, 130, 2043 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_NONE][7] = { 130, 130, 130 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_DCI_P3][0] = { 3175, 3175, 3175 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_DCI_P3][1] = { 3175, 3175, 1308 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_DCI_P3][2] = { 2069, 3175, 3175 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_DCI_P3][3] = { 2069, 3175, 1308 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_DCI_P3][4] = { 2816, 1084, 3127 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_DCI_P3][5] = { 2816, 1084, 1084 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_DCI_P3][6] = { 1084, 1084, 3127 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_DCI_P3][7] = { 1084, 1084, 1084 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][0] = { 1812, 1812, 1812 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][1] = { 1812, 1812, 1022 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][2] = { 1402, 1812, 1812 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][3] = { 1402, 1812, 1022 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][4] = { 1692, 886, 1797 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][5] = { 1692, 886, 886 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][6] = { 886, 886, 1797 },
- [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][7] = { 886, 886, 886 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_709][1] = { 2939, 2939, 781 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_709][2] = { 1622, 2939, 2939 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_709][3] = { 1622, 2939, 781 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_709][4] = { 2502, 547, 2881 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_709][5] = { 2502, 547, 547 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_709][6] = { 547, 547, 2881 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_709][7] = { 547, 547, 547 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SRGB][0] = { 3056, 3056, 3056 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SRGB][1] = { 3056, 3056, 1031 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SRGB][2] = { 1838, 3056, 3056 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SRGB][3] = { 1838, 3056, 1031 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SRGB][4] = { 2657, 800, 3002 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SRGB][5] = { 2657, 800, 800 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SRGB][6] = { 800, 800, 3002 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SRGB][7] = { 800, 800, 800 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_OPRGB][0] = { 3033, 3033, 3033 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_OPRGB][1] = { 3033, 3033, 1063 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_OPRGB][2] = { 1828, 3033, 3033 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_OPRGB][3] = { 1828, 3033, 1063 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_OPRGB][4] = { 2633, 851, 2979 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_OPRGB][5] = { 2633, 851, 851 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_OPRGB][6] = { 851, 851, 2979 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_OPRGB][7] = { 851, 851, 851 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SMPTE240M][1] = { 2926, 2926, 744 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SMPTE240M][2] = { 1594, 2926, 2926 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SMPTE240M][3] = { 1594, 2926, 744 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SMPTE240M][4] = { 2484, 507, 2867 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SMPTE240M][5] = { 2484, 507, 507 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SMPTE240M][6] = { 507, 507, 2867 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SMPTE240M][7] = { 507, 507, 507 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_NONE][0] = { 2125, 2125, 2125 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_NONE][1] = { 2125, 2125, 212 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_NONE][2] = { 698, 2125, 2125 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_NONE][3] = { 698, 2125, 212 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_NONE][4] = { 1557, 130, 2043 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_NONE][5] = { 1557, 130, 130 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_NONE][6] = { 130, 130, 2043 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_NONE][7] = { 130, 130, 130 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_DCI_P3][0] = { 3175, 3175, 3175 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_DCI_P3][1] = { 3175, 3175, 1308 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_DCI_P3][2] = { 2069, 3175, 3175 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_DCI_P3][3] = { 2069, 3175, 1308 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_DCI_P3][4] = { 2816, 1084, 3127 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_DCI_P3][5] = { 2816, 1084, 1084 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_DCI_P3][6] = { 1084, 1084, 3127 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_DCI_P3][7] = { 1084, 1084, 1084 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SMPTE2084][0] = { 1812, 1812, 1812 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SMPTE2084][1] = { 1812, 1812, 1022 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SMPTE2084][2] = { 1402, 1812, 1812 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SMPTE2084][3] = { 1402, 1812, 1022 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SMPTE2084][4] = { 1692, 886, 1797 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SMPTE2084][5] = { 1692, 886, 886 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SMPTE2084][6] = { 886, 886, 1797 },
+ [V4L2_COLORSPACE_OPRGB][V4L2_XFER_FUNC_SMPTE2084][7] = { 886, 886, 886 },
[V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 },
[V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_709][1] = { 2877, 2923, 1058 },
[V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_709][2] = { 1837, 2840, 2916 },
@@ -994,14 +994,14 @@ const struct tpg_rbg_color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1][V4L2_XFE
[V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SRGB][5] = { 2517, 1159, 900 },
[V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SRGB][6] = { 1042, 870, 2917 },
[V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SRGB][7] = { 800, 800, 800 },
- [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 },
- [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][1] = { 2976, 3018, 1315 },
- [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][2] = { 2024, 2942, 3011 },
- [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][3] = { 1930, 2926, 1256 },
- [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][4] = { 2563, 1227, 2916 },
- [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][5] = { 2494, 1183, 943 },
- [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][6] = { 1073, 916, 2894 },
- [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 },
+ [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_OPRGB][0] = { 3033, 3033, 3033 },
+ [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_OPRGB][1] = { 2976, 3018, 1315 },
+ [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_OPRGB][2] = { 2024, 2942, 3011 },
+ [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_OPRGB][3] = { 1930, 2926, 1256 },
+ [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_OPRGB][4] = { 2563, 1227, 2916 },
+ [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_OPRGB][5] = { 2494, 1183, 943 },
+ [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_OPRGB][6] = { 1073, 916, 2894 },
+ [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_OPRGB][7] = { 851, 851, 851 },
[V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 },
[V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE240M][1] = { 2864, 2910, 1024 },
[V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE240M][2] = { 1811, 2826, 2903 },
@@ -1050,14 +1050,14 @@ const struct tpg_rbg_color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1][V4L2_XFE
[V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SRGB][5] = { 2880, 998, 902 },
[V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SRGB][6] = { 816, 823, 2940 },
[V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SRGB][7] = { 800, 800, 799 },
- [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_ADOBERGB][0] = { 3033, 3033, 3033 },
- [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_ADOBERGB][1] = { 3029, 3028, 1255 },
- [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_ADOBERGB][2] = { 1406, 2988, 3011 },
- [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_ADOBERGB][3] = { 1398, 2983, 1190 },
- [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_ADOBERGB][4] = { 2860, 1050, 2939 },
- [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_ADOBERGB][5] = { 2857, 1033, 945 },
- [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_ADOBERGB][6] = { 866, 873, 2916 },
- [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_ADOBERGB][7] = { 851, 851, 851 },
+ [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_OPRGB][0] = { 3033, 3033, 3033 },
+ [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_OPRGB][1] = { 3029, 3028, 1255 },
+ [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_OPRGB][2] = { 1406, 2988, 3011 },
+ [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_OPRGB][3] = { 1398, 2983, 1190 },
+ [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_OPRGB][4] = { 2860, 1050, 2939 },
+ [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_OPRGB][5] = { 2857, 1033, 945 },
+ [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_OPRGB][6] = { 866, 873, 2916 },
+ [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_OPRGB][7] = { 851, 851, 851 },
[V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE240M][0] = { 2926, 2926, 2926 },
[V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE240M][1] = { 2923, 2921, 957 },
[V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE240M][2] = { 1125, 2877, 2902 },
@@ -1128,7 +1128,7 @@ static const double rec709_to_240m[3][3] = {
{ 0.0016327, 0.0044133, 0.9939540 },
};
-static const double rec709_to_adobergb[3][3] = {
+static const double rec709_to_oprgb[3][3] = {
{ 0.7151627, 0.2848373, -0.0000000 },
{ 0.0000000, 1.0000000, 0.0000000 },
{ -0.0000000, 0.0411705, 0.9588295 },
@@ -1195,7 +1195,7 @@ static double transfer_rec709_to_rgb(double v)
return (v < 0.081) ? v / 4.5 : pow((v + 0.099) / 1.099, 1.0 / 0.45);
}
-static double transfer_rgb_to_adobergb(double v)
+static double transfer_rgb_to_oprgb(double v)
{
return pow(v, 1.0 / 2.19921875);
}
@@ -1251,8 +1251,8 @@ static void csc(enum v4l2_colorspace colorspace, enum v4l2_xfer_func xfer_func,
case V4L2_COLORSPACE_470_SYSTEM_M:
mult_matrix(r, g, b, rec709_to_ntsc1953);
break;
- case V4L2_COLORSPACE_ADOBERGB:
- mult_matrix(r, g, b, rec709_to_adobergb);
+ case V4L2_COLORSPACE_OPRGB:
+ mult_matrix(r, g, b, rec709_to_oprgb);
break;
case V4L2_COLORSPACE_BT2020:
mult_matrix(r, g, b, rec709_to_bt2020);
@@ -1284,10 +1284,10 @@ static void csc(enum v4l2_colorspace colorspace, enum v4l2_xfer_func xfer_func,
*g = transfer_rgb_to_srgb(*g);
*b = transfer_rgb_to_srgb(*b);
break;
- case V4L2_XFER_FUNC_ADOBERGB:
- *r = transfer_rgb_to_adobergb(*r);
- *g = transfer_rgb_to_adobergb(*g);
- *b = transfer_rgb_to_adobergb(*b);
+ case V4L2_XFER_FUNC_OPRGB:
+ *r = transfer_rgb_to_oprgb(*r);
+ *g = transfer_rgb_to_oprgb(*g);
+ *b = transfer_rgb_to_oprgb(*b);
break;
case V4L2_XFER_FUNC_DCI_P3:
*r = transfer_rgb_to_dcip3(*r);
@@ -1321,7 +1321,7 @@ int main(int argc, char **argv)
V4L2_COLORSPACE_470_SYSTEM_BG,
0,
V4L2_COLORSPACE_SRGB,
- V4L2_COLORSPACE_ADOBERGB,
+ V4L2_COLORSPACE_OPRGB,
V4L2_COLORSPACE_BT2020,
0,
V4L2_COLORSPACE_DCI_P3,
@@ -1336,7 +1336,7 @@ int main(int argc, char **argv)
"V4L2_COLORSPACE_470_SYSTEM_BG",
"",
"V4L2_COLORSPACE_SRGB",
- "V4L2_COLORSPACE_ADOBERGB",
+ "V4L2_COLORSPACE_OPRGB",
"V4L2_COLORSPACE_BT2020",
"",
"V4L2_COLORSPACE_DCI_P3",
@@ -1345,7 +1345,7 @@ int main(int argc, char **argv)
"",
"V4L2_XFER_FUNC_709",
"V4L2_XFER_FUNC_SRGB",
- "V4L2_XFER_FUNC_ADOBERGB",
+ "V4L2_XFER_FUNC_OPRGB",
"V4L2_XFER_FUNC_SMPTE240M",
"V4L2_XFER_FUNC_NONE",
"V4L2_XFER_FUNC_DCI_P3",
diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c
index abd4c788dffd..fa483b95bc5a 100644
--- a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c
+++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c
@@ -202,6 +202,10 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
case V4L2_PIX_FMT_SGBRG12:
case V4L2_PIX_FMT_SGRBG12:
case V4L2_PIX_FMT_SRGGB12:
+ case V4L2_PIX_FMT_SBGGR16:
+ case V4L2_PIX_FMT_SGBRG16:
+ case V4L2_PIX_FMT_SGRBG16:
+ case V4L2_PIX_FMT_SRGGB16:
tpg->interleaved = true;
tpg->vdownsampling[1] = 1;
tpg->hdownsampling[1] = 1;
@@ -235,6 +239,7 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
case V4L2_PIX_FMT_Y12:
case V4L2_PIX_FMT_Y16:
case V4L2_PIX_FMT_Y16_BE:
+ case V4L2_PIX_FMT_Z16:
tpg->color_enc = TGP_COLOR_ENC_LUMA;
break;
case V4L2_PIX_FMT_YUV444:
@@ -351,6 +356,7 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
case V4L2_PIX_FMT_Y12:
case V4L2_PIX_FMT_Y16:
case V4L2_PIX_FMT_Y16_BE:
+ case V4L2_PIX_FMT_Z16:
tpg->twopixelsize[0] = 2 * 2;
break;
case V4L2_PIX_FMT_RGB24:
@@ -392,6 +398,10 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
case V4L2_PIX_FMT_SGRBG12:
case V4L2_PIX_FMT_SGBRG12:
case V4L2_PIX_FMT_SBGGR12:
+ case V4L2_PIX_FMT_SRGGB16:
+ case V4L2_PIX_FMT_SGRBG16:
+ case V4L2_PIX_FMT_SGBRG16:
+ case V4L2_PIX_FMT_SBGGR16:
tpg->twopixelsize[0] = 4;
tpg->twopixelsize[1] = 4;
break;
@@ -1062,6 +1072,7 @@ static void gen_twopix(struct tpg_data *tpg,
buf[0][offset+1] = r_y_h >> 4;
break;
case V4L2_PIX_FMT_Y16:
+ case V4L2_PIX_FMT_Z16:
/*
* Ideally both bytes should be set to r_y_h, but then you won't
* be able to detect endian problems. So keep it 0 except for
@@ -1355,6 +1366,22 @@ static void gen_twopix(struct tpg_data *tpg,
buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;
buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;
break;
+ case V4L2_PIX_FMT_SBGGR16:
+ buf[0][offset] = buf[0][offset + 1] = odd ? g_u_s : b_v;
+ buf[1][offset] = buf[1][offset + 1] = odd ? r_y_h : g_u_s;
+ break;
+ case V4L2_PIX_FMT_SGBRG16:
+ buf[0][offset] = buf[0][offset + 1] = odd ? b_v : g_u_s;
+ buf[1][offset] = buf[1][offset + 1] = odd ? g_u_s : r_y_h;
+ break;
+ case V4L2_PIX_FMT_SGRBG16:
+ buf[0][offset] = buf[0][offset + 1] = odd ? r_y_h : g_u_s;
+ buf[1][offset] = buf[1][offset + 1] = odd ? g_u_s : b_v;
+ break;
+ case V4L2_PIX_FMT_SRGGB16:
+ buf[0][offset] = buf[0][offset + 1] = odd ? g_u_s : r_y_h;
+ buf[1][offset] = buf[1][offset + 1] = odd ? b_v : g_u_s;
+ break;
}
}
@@ -1373,6 +1400,10 @@ unsigned tpg_g_interleaved_plane(const struct tpg_data *tpg, unsigned buf_line)
case V4L2_PIX_FMT_SGBRG12:
case V4L2_PIX_FMT_SGRBG12:
case V4L2_PIX_FMT_SRGGB12:
+ case V4L2_PIX_FMT_SBGGR16:
+ case V4L2_PIX_FMT_SGBRG16:
+ case V4L2_PIX_FMT_SGRBG16:
+ case V4L2_PIX_FMT_SRGGB16:
return buf_line & 1;
default:
return 0;
@@ -1770,7 +1801,7 @@ typedef struct { u16 __; u8 _; } __packed x24;
pos[7] = (chr & (0x01 << 0) ? fg : bg); \
} \
\
- pos += (tpg->hflip ? -8 : 8) / hdiv; \
+ pos += (tpg->hflip ? -8 : 8) / (int)hdiv; \
} \
} \
} while (0)
@@ -2038,8 +2069,12 @@ void tpg_log_status(struct tpg_data *tpg)
tpg->compose.left, tpg->compose.top);
pr_info("tpg colorspace: %d\n", tpg->colorspace);
pr_info("tpg transfer function: %d/%d\n", tpg->xfer_func, tpg->real_xfer_func);
- pr_info("tpg Y'CbCr encoding: %d/%d\n", tpg->ycbcr_enc, tpg->real_ycbcr_enc);
- pr_info("tpg HSV encoding: %d/%d\n", tpg->hsv_enc, tpg->real_hsv_enc);
+ if (tpg->color_enc == TGP_COLOR_ENC_HSV)
+ pr_info("tpg HSV encoding: %d/%d\n",
+ tpg->hsv_enc, tpg->real_hsv_enc);
+ else if (tpg->color_enc == TGP_COLOR_ENC_YCBCR)
+ pr_info("tpg Y'CbCr encoding: %d/%d\n",
+ tpg->ycbcr_enc, tpg->real_ycbcr_enc);
pr_info("tpg quantization: %d/%d\n", tpg->quantization, tpg->real_quantization);
pr_info("tpg RGB range: %d/%d\n", tpg->rgb_range, tpg->real_rgb_range);
}
diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
index 5653e8eebe2b..975ff5669f72 100644
--- a/drivers/media/common/videobuf2/videobuf2-core.c
+++ b/drivers/media/common/videobuf2/videobuf2-core.c
@@ -356,6 +356,8 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
vb->planes[plane].length = plane_sizes[plane];
vb->planes[plane].min_length = plane_sizes[plane];
}
+ call_void_bufop(q, init_buffer, vb);
+
q->bufs[vb->index] = vb;
/* Allocate video buffer memory for the MMAP type */
@@ -497,8 +499,9 @@ static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
pr_info(" buf_init: %u buf_cleanup: %u buf_prepare: %u buf_finish: %u\n",
vb->cnt_buf_init, vb->cnt_buf_cleanup,
vb->cnt_buf_prepare, vb->cnt_buf_finish);
- pr_info(" buf_queue: %u buf_done: %u\n",
- vb->cnt_buf_queue, vb->cnt_buf_done);
+ pr_info(" buf_queue: %u buf_done: %u buf_request_complete: %u\n",
+ vb->cnt_buf_queue, vb->cnt_buf_done,
+ vb->cnt_buf_request_complete);
pr_info(" alloc: %u put: %u prepare: %u finish: %u mmap: %u\n",
vb->cnt_mem_alloc, vb->cnt_mem_put,
vb->cnt_mem_prepare, vb->cnt_mem_finish,
@@ -661,6 +664,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
{
unsigned int num_buffers, allocated_buffers, num_planes = 0;
unsigned plane_sizes[VB2_MAX_PLANES] = { };
+ unsigned int i;
int ret;
if (q->streaming) {
@@ -682,7 +686,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
}
/*
- * Call queue_cancel to clean up any buffers in the PREPARED or
+ * Call queue_cancel to clean up any buffers in the
* QUEUED state which is possible if buffers were prepared or
* queued without ever calling STREAMON.
*/
@@ -718,6 +722,14 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
if (ret)
return ret;
+ /* Check that driver has set sane values */
+ if (WARN_ON(!num_planes))
+ return -EINVAL;
+
+ for (i = 0; i < num_planes; i++)
+ if (WARN_ON(!plane_sizes[i]))
+ return -EINVAL;
+
/* Finally, allocate buffers and video memory */
allocated_buffers =
__vb2_queue_alloc(q, memory, num_buffers, num_planes, plane_sizes);
@@ -921,6 +933,7 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state)
/* sync buffers */
for (plane = 0; plane < vb->num_planes; ++plane)
call_void_memop(vb, finish, vb->planes[plane].mem_priv);
+ vb->synced = false;
}
spin_lock_irqsave(&q->done_lock, flags);
@@ -933,6 +946,14 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state)
vb->state = state;
}
atomic_dec(&q->owned_by_drv_count);
+
+ if (vb->req_obj.req) {
+ /* This is not supported at the moment */
+ WARN_ON(state == VB2_BUF_STATE_REQUEUEING);
+ media_request_object_unbind(&vb->req_obj);
+ media_request_object_put(&vb->req_obj);
+ }
+
spin_unlock_irqrestore(&q->done_lock, flags);
trace_vb2_buf_done(q, vb);
@@ -967,20 +988,19 @@ EXPORT_SYMBOL_GPL(vb2_discard_done);
/*
* __prepare_mmap() - prepare an MMAP buffer
*/
-static int __prepare_mmap(struct vb2_buffer *vb, const void *pb)
+static int __prepare_mmap(struct vb2_buffer *vb)
{
int ret = 0;
- if (pb)
- ret = call_bufop(vb->vb2_queue, fill_vb2_buffer,
- vb, pb, vb->planes);
+ ret = call_bufop(vb->vb2_queue, fill_vb2_buffer,
+ vb, vb->planes);
return ret ? ret : call_vb_qop(vb, buf_prepare, vb);
}
/*
* __prepare_userptr() - prepare a USERPTR buffer
*/
-static int __prepare_userptr(struct vb2_buffer *vb, const void *pb)
+static int __prepare_userptr(struct vb2_buffer *vb)
{
struct vb2_plane planes[VB2_MAX_PLANES];
struct vb2_queue *q = vb->vb2_queue;
@@ -991,12 +1011,10 @@ static int __prepare_userptr(struct vb2_buffer *vb, const void *pb)
memset(planes, 0, sizeof(planes[0]) * vb->num_planes);
/* Copy relevant information provided by the userspace */
- if (pb) {
- ret = call_bufop(vb->vb2_queue, fill_vb2_buffer,
- vb, pb, planes);
- if (ret)
- return ret;
- }
+ ret = call_bufop(vb->vb2_queue, fill_vb2_buffer,
+ vb, planes);
+ if (ret)
+ return ret;
for (plane = 0; plane < vb->num_planes; ++plane) {
/* Skip the plane if already verified */
@@ -1096,7 +1114,7 @@ err:
/*
* __prepare_dmabuf() - prepare a DMABUF buffer
*/
-static int __prepare_dmabuf(struct vb2_buffer *vb, const void *pb)
+static int __prepare_dmabuf(struct vb2_buffer *vb)
{
struct vb2_plane planes[VB2_MAX_PLANES];
struct vb2_queue *q = vb->vb2_queue;
@@ -1107,12 +1125,10 @@ static int __prepare_dmabuf(struct vb2_buffer *vb, const void *pb)
memset(planes, 0, sizeof(planes[0]) * vb->num_planes);
/* Copy relevant information provided by the userspace */
- if (pb) {
- ret = call_bufop(vb->vb2_queue, fill_vb2_buffer,
- vb, pb, planes);
- if (ret)
- return ret;
- }
+ ret = call_bufop(vb->vb2_queue, fill_vb2_buffer,
+ vb, planes);
+ if (ret)
+ return ret;
for (plane = 0; plane < vb->num_planes; ++plane) {
struct dma_buf *dbuf = dma_buf_get(planes[plane].m.fd);
@@ -1241,9 +1257,10 @@ static void __enqueue_in_driver(struct vb2_buffer *vb)
call_void_vb_qop(vb, buf_queue, vb);
}
-static int __buf_prepare(struct vb2_buffer *vb, const void *pb)
+static int __buf_prepare(struct vb2_buffer *vb)
{
struct vb2_queue *q = vb->vb2_queue;
+ enum vb2_buffer_state orig_state = vb->state;
unsigned int plane;
int ret;
@@ -1252,26 +1269,31 @@ static int __buf_prepare(struct vb2_buffer *vb, const void *pb)
return -EIO;
}
+ if (vb->prepared)
+ return 0;
+ WARN_ON(vb->synced);
+
vb->state = VB2_BUF_STATE_PREPARING;
switch (q->memory) {
case VB2_MEMORY_MMAP:
- ret = __prepare_mmap(vb, pb);
+ ret = __prepare_mmap(vb);
break;
case VB2_MEMORY_USERPTR:
- ret = __prepare_userptr(vb, pb);
+ ret = __prepare_userptr(vb);
break;
case VB2_MEMORY_DMABUF:
- ret = __prepare_dmabuf(vb, pb);
+ ret = __prepare_dmabuf(vb);
break;
default:
WARN(1, "Invalid queue type\n");
ret = -EINVAL;
+ break;
}
if (ret) {
dprintk(1, "buffer preparation failed: %d\n", ret);
- vb->state = VB2_BUF_STATE_DEQUEUED;
+ vb->state = orig_state;
return ret;
}
@@ -1279,11 +1301,98 @@ static int __buf_prepare(struct vb2_buffer *vb, const void *pb)
for (plane = 0; plane < vb->num_planes; ++plane)
call_void_memop(vb, prepare, vb->planes[plane].mem_priv);
- vb->state = VB2_BUF_STATE_PREPARED;
+ vb->synced = true;
+ vb->prepared = true;
+ vb->state = orig_state;
return 0;
}
+static int vb2_req_prepare(struct media_request_object *obj)
+{
+ struct vb2_buffer *vb = container_of(obj, struct vb2_buffer, req_obj);
+ int ret;
+
+ if (WARN_ON(vb->state != VB2_BUF_STATE_IN_REQUEST))
+ return -EINVAL;
+
+ mutex_lock(vb->vb2_queue->lock);
+ ret = __buf_prepare(vb);
+ mutex_unlock(vb->vb2_queue->lock);
+ return ret;
+}
+
+static void __vb2_dqbuf(struct vb2_buffer *vb);
+
+static void vb2_req_unprepare(struct media_request_object *obj)
+{
+ struct vb2_buffer *vb = container_of(obj, struct vb2_buffer, req_obj);
+
+ mutex_lock(vb->vb2_queue->lock);
+ __vb2_dqbuf(vb);
+ vb->state = VB2_BUF_STATE_IN_REQUEST;
+ mutex_unlock(vb->vb2_queue->lock);
+ WARN_ON(!vb->req_obj.req);
+}
+
+int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb,
+ struct media_request *req);
+
+static void vb2_req_queue(struct media_request_object *obj)
+{
+ struct vb2_buffer *vb = container_of(obj, struct vb2_buffer, req_obj);
+
+ mutex_lock(vb->vb2_queue->lock);
+ vb2_core_qbuf(vb->vb2_queue, vb->index, NULL, NULL);
+ mutex_unlock(vb->vb2_queue->lock);
+}
+
+static void vb2_req_unbind(struct media_request_object *obj)
+{
+ struct vb2_buffer *vb = container_of(obj, struct vb2_buffer, req_obj);
+
+ if (vb->state == VB2_BUF_STATE_IN_REQUEST)
+ call_void_bufop(vb->vb2_queue, init_buffer, vb);
+}
+
+static void vb2_req_release(struct media_request_object *obj)
+{
+ struct vb2_buffer *vb = container_of(obj, struct vb2_buffer, req_obj);
+
+ if (vb->state == VB2_BUF_STATE_IN_REQUEST)
+ vb->state = VB2_BUF_STATE_DEQUEUED;
+}
+
+static const struct media_request_object_ops vb2_core_req_ops = {
+ .prepare = vb2_req_prepare,
+ .unprepare = vb2_req_unprepare,
+ .queue = vb2_req_queue,
+ .unbind = vb2_req_unbind,
+ .release = vb2_req_release,
+};
+
+bool vb2_request_object_is_buffer(struct media_request_object *obj)
+{
+ return obj->ops == &vb2_core_req_ops;
+}
+EXPORT_SYMBOL_GPL(vb2_request_object_is_buffer);
+
+unsigned int vb2_request_buffer_cnt(struct media_request *req)
+{
+ struct media_request_object *obj;
+ unsigned long flags;
+ unsigned int buffer_cnt = 0;
+
+ spin_lock_irqsave(&req->lock, flags);
+ list_for_each_entry(obj, &req->objects, list)
+ if (vb2_request_object_is_buffer(obj))
+ buffer_cnt++;
+ spin_unlock_irqrestore(&req->lock, flags);
+
+ return buffer_cnt;
+}
+EXPORT_SYMBOL_GPL(vb2_request_buffer_cnt);
+
int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb)
{
struct vb2_buffer *vb;
@@ -1295,8 +1404,12 @@ int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb)
vb->state);
return -EINVAL;
}
+ if (vb->prepared) {
+ dprintk(1, "buffer already prepared\n");
+ return -EINVAL;
+ }
- ret = __buf_prepare(vb, pb);
+ ret = __buf_prepare(vb);
if (ret)
return ret;
@@ -1305,7 +1418,7 @@ int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb)
dprintk(2, "prepare of buffer %d succeeded\n", vb->index);
- return ret;
+ return 0;
}
EXPORT_SYMBOL_GPL(vb2_core_prepare_buf);
@@ -1372,7 +1485,8 @@ static int vb2_start_streaming(struct vb2_queue *q)
return ret;
}
-int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb)
+int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb,
+ struct media_request *req)
{
struct vb2_buffer *vb;
int ret;
@@ -1384,13 +1498,57 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb)
vb = q->bufs[index];
- switch (vb->state) {
- case VB2_BUF_STATE_DEQUEUED:
- ret = __buf_prepare(vb, pb);
+ if ((req && q->uses_qbuf) ||
+ (!req && vb->state != VB2_BUF_STATE_IN_REQUEST &&
+ q->uses_requests)) {
+ dprintk(1, "queue in wrong mode (qbuf vs requests)\n");
+ return -EBUSY;
+ }
+
+ if (req) {
+ int ret;
+
+ q->uses_requests = 1;
+ if (vb->state != VB2_BUF_STATE_DEQUEUED) {
+ dprintk(1, "buffer %d not in dequeued state\n",
+ vb->index);
+ return -EINVAL;
+ }
+
+ media_request_object_init(&vb->req_obj);
+
+ /* Make sure the request is in a safe state for updating. */
+ ret = media_request_lock_for_update(req);
if (ret)
return ret;
- break;
- case VB2_BUF_STATE_PREPARED:
+ ret = media_request_object_bind(req, &vb2_core_req_ops,
+ q, true, &vb->req_obj);
+ media_request_unlock_for_update(req);
+ if (ret)
+ return ret;
+
+ vb->state = VB2_BUF_STATE_IN_REQUEST;
+ /* Fill buffer information for the userspace */
+ if (pb) {
+ call_void_bufop(q, copy_timestamp, vb, pb);
+ call_void_bufop(q, fill_user_buffer, vb, pb);
+ }
+
+ dprintk(2, "qbuf of buffer %d succeeded\n", vb->index);
+ return 0;
+ }
+
+ if (vb->state != VB2_BUF_STATE_IN_REQUEST)
+ q->uses_qbuf = 1;
+
+ switch (vb->state) {
+ case VB2_BUF_STATE_DEQUEUED:
+ case VB2_BUF_STATE_IN_REQUEST:
+ if (!vb->prepared) {
+ ret = __buf_prepare(vb);
+ if (ret)
+ return ret;
+ }
break;
case VB2_BUF_STATE_PREPARING:
dprintk(1, "buffer still being prepared\n");
@@ -1591,6 +1749,11 @@ static void __vb2_dqbuf(struct vb2_buffer *vb)
call_void_memop(vb, unmap_dmabuf, vb->planes[i].mem_priv);
vb->planes[i].dbuf_mapped = 0;
}
+ if (vb->req_obj.req) {
+ media_request_object_unbind(&vb->req_obj);
+ media_request_object_put(&vb->req_obj);
+ }
+ call_void_bufop(q, init_buffer, vb);
}
int vb2_core_dqbuf(struct vb2_queue *q, unsigned int *pindex, void *pb,
@@ -1616,6 +1779,7 @@ int vb2_core_dqbuf(struct vb2_queue *q, unsigned int *pindex, void *pb,
}
call_void_vb_qop(vb, buf_finish, vb);
+ vb->prepared = false;
if (pindex)
*pindex = vb->index;
@@ -1679,6 +1843,8 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
q->start_streaming_called = 0;
q->queued_count = 0;
q->error = 0;
+ q->uses_requests = 0;
+ q->uses_qbuf = 0;
/*
* Remove all buffers from videobuf's list...
@@ -1703,19 +1869,38 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
*/
for (i = 0; i < q->num_buffers; ++i) {
struct vb2_buffer *vb = q->bufs[i];
+ struct media_request *req = vb->req_obj.req;
+
+ /*
+ * If a request is associated with this buffer, then
+ * call buf_request_cancel() to give the driver to complete()
+ * related request objects. Otherwise those objects would
+ * never complete.
+ */
+ if (req) {
+ enum media_request_state state;
+ unsigned long flags;
+
+ spin_lock_irqsave(&req->lock, flags);
+ state = req->state;
+ spin_unlock_irqrestore(&req->lock, flags);
- if (vb->state == VB2_BUF_STATE_PREPARED ||
- vb->state == VB2_BUF_STATE_QUEUED) {
+ if (state == MEDIA_REQUEST_STATE_QUEUED)
+ call_void_vb_qop(vb, buf_request_complete, vb);
+ }
+
+ if (vb->synced) {
unsigned int plane;
for (plane = 0; plane < vb->num_planes; ++plane)
call_void_memop(vb, finish,
vb->planes[plane].mem_priv);
+ vb->synced = false;
}
- if (vb->state != VB2_BUF_STATE_DEQUEUED) {
- vb->state = VB2_BUF_STATE_PREPARED;
+ if (vb->prepared) {
call_void_vb_qop(vb, buf_finish, vb);
+ vb->prepared = false;
}
__vb2_dqbuf(vb);
}
@@ -2272,7 +2457,7 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
* Queue all buffers.
*/
for (i = 0; i < q->num_buffers; i++) {
- ret = vb2_core_qbuf(q, i, NULL);
+ ret = vb2_core_qbuf(q, i, NULL, NULL);
if (ret)
goto err_reqbufs;
fileio->bufs[i].queued = 1;
@@ -2451,7 +2636,7 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
if (copy_timestamp)
b->timestamp = ktime_get_ns();
- ret = vb2_core_qbuf(q, index, NULL);
+ ret = vb2_core_qbuf(q, index, NULL, NULL);
dprintk(5, "vb2_dbuf result: %d\n", ret);
if (ret)
return ret;
@@ -2554,7 +2739,7 @@ static int vb2_thread(void *data)
if (copy_timestamp)
vb->timestamp = ktime_get_ns();
if (!threadio->stop)
- ret = vb2_core_qbuf(q, vb->index, NULL);
+ ret = vb2_core_qbuf(q, vb->index, NULL, NULL);
call_void_qop(q, wait_prepare, q);
if (ret || threadio->stop)
break;
diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c
index 886a2d8d5c6c..a17033ab2c22 100644
--- a/drivers/media/common/videobuf2/videobuf2-v4l2.c
+++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c
@@ -25,6 +25,7 @@
#include <linux/kthread.h>
#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
#include <media/v4l2-fh.h>
#include <media/v4l2-event.h>
#include <media/v4l2-common.h>
@@ -40,10 +41,12 @@ module_param(debug, int, 0644);
pr_info("vb2-v4l2: %s: " fmt, __func__, ## arg); \
} while (0)
-/* Flags that are set by the vb2 core */
+/* Flags that are set by us */
#define V4L2_BUFFER_MASK_FLAGS (V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | \
V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_ERROR | \
V4L2_BUF_FLAG_PREPARED | \
+ V4L2_BUF_FLAG_IN_REQUEST | \
+ V4L2_BUF_FLAG_REQUEST_FD | \
V4L2_BUF_FLAG_TIMESTAMP_MASK)
/* Output buffer flags that should be passed on to the driver */
#define V4L2_BUFFER_OUT_FLAGS (V4L2_BUF_FLAG_PFRAME | V4L2_BUF_FLAG_BFRAME | \
@@ -118,6 +121,16 @@ static int __verify_length(struct vb2_buffer *vb, const struct v4l2_buffer *b)
return 0;
}
+/*
+ * __init_v4l2_vb2_buffer() - initialize the v4l2_vb2_buffer struct
+ */
+static void __init_v4l2_vb2_buffer(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+ vbuf->request_fd = -1;
+}
+
static void __copy_timestamp(struct vb2_buffer *vb, const void *pb)
{
const struct v4l2_buffer *b = pb;
@@ -154,9 +167,181 @@ static void vb2_warn_zero_bytesused(struct vb2_buffer *vb)
pr_warn("use the actual size instead.\n");
}
-static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b,
- const char *opname)
+static int vb2_fill_vb2_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b)
{
+ struct vb2_queue *q = vb->vb2_queue;
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct vb2_plane *planes = vbuf->planes;
+ unsigned int plane;
+ int ret;
+
+ ret = __verify_length(vb, b);
+ if (ret < 0) {
+ dprintk(1, "plane parameters verification failed: %d\n", ret);
+ return ret;
+ }
+ if (b->field == V4L2_FIELD_ALTERNATE && q->is_output) {
+ /*
+ * If the format's field is ALTERNATE, then the buffer's field
+ * should be either TOP or BOTTOM, not ALTERNATE since that
+ * makes no sense. The driver has to know whether the
+ * buffer represents a top or a bottom field in order to
+ * program any DMA correctly. Using ALTERNATE is wrong, since
+ * that just says that it is either a top or a bottom field,
+ * but not which of the two it is.
+ */
+ dprintk(1, "the field is incorrectly set to ALTERNATE for an output buffer\n");
+ return -EINVAL;
+ }
+ vbuf->sequence = 0;
+ vbuf->request_fd = -1;
+
+ if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) {
+ switch (b->memory) {
+ case VB2_MEMORY_USERPTR:
+ for (plane = 0; plane < vb->num_planes; ++plane) {
+ planes[plane].m.userptr =
+ b->m.planes[plane].m.userptr;
+ planes[plane].length =
+ b->m.planes[plane].length;
+ }
+ break;
+ case VB2_MEMORY_DMABUF:
+ for (plane = 0; plane < vb->num_planes; ++plane) {
+ planes[plane].m.fd =
+ b->m.planes[plane].m.fd;
+ planes[plane].length =
+ b->m.planes[plane].length;
+ }
+ break;
+ default:
+ for (plane = 0; plane < vb->num_planes; ++plane) {
+ planes[plane].m.offset =
+ vb->planes[plane].m.offset;
+ planes[plane].length =
+ vb->planes[plane].length;
+ }
+ break;
+ }
+
+ /* Fill in driver-provided information for OUTPUT types */
+ if (V4L2_TYPE_IS_OUTPUT(b->type)) {
+ /*
+ * Will have to go up to b->length when API starts
+ * accepting variable number of planes.
+ *
+ * If bytesused == 0 for the output buffer, then fall
+ * back to the full buffer size. In that case
+ * userspace clearly never bothered to set it and
+ * it's a safe assumption that they really meant to
+ * use the full plane sizes.
+ *
+ * Some drivers, e.g. old codec drivers, use bytesused == 0
+ * as a way to indicate that streaming is finished.
+ * In that case, the driver should use the
+ * allow_zero_bytesused flag to keep old userspace
+ * applications working.
+ */
+ for (plane = 0; plane < vb->num_planes; ++plane) {
+ struct vb2_plane *pdst = &planes[plane];
+ struct v4l2_plane *psrc = &b->m.planes[plane];
+
+ if (psrc->bytesused == 0)
+ vb2_warn_zero_bytesused(vb);
+
+ if (vb->vb2_queue->allow_zero_bytesused)
+ pdst->bytesused = psrc->bytesused;
+ else
+ pdst->bytesused = psrc->bytesused ?
+ psrc->bytesused : pdst->length;
+ pdst->data_offset = psrc->data_offset;
+ }
+ }
+ } else {
+ /*
+ * Single-planar buffers do not use planes array,
+ * so fill in relevant v4l2_buffer struct fields instead.
+ * In videobuf we use our internal V4l2_planes struct for
+ * single-planar buffers as well, for simplicity.
+ *
+ * If bytesused == 0 for the output buffer, then fall back
+ * to the full buffer size as that's a sensible default.
+ *
+ * Some drivers, e.g. old codec drivers, use bytesused == 0 as
+ * a way to indicate that streaming is finished. In that case,
+ * the driver should use the allow_zero_bytesused flag to keep
+ * old userspace applications working.
+ */
+ switch (b->memory) {
+ case VB2_MEMORY_USERPTR:
+ planes[0].m.userptr = b->m.userptr;
+ planes[0].length = b->length;
+ break;
+ case VB2_MEMORY_DMABUF:
+ planes[0].m.fd = b->m.fd;
+ planes[0].length = b->length;
+ break;
+ default:
+ planes[0].m.offset = vb->planes[0].m.offset;
+ planes[0].length = vb->planes[0].length;
+ break;
+ }
+
+ planes[0].data_offset = 0;
+ if (V4L2_TYPE_IS_OUTPUT(b->type)) {
+ if (b->bytesused == 0)
+ vb2_warn_zero_bytesused(vb);
+
+ if (vb->vb2_queue->allow_zero_bytesused)
+ planes[0].bytesused = b->bytesused;
+ else
+ planes[0].bytesused = b->bytesused ?
+ b->bytesused : planes[0].length;
+ } else
+ planes[0].bytesused = 0;
+
+ }
+
+ /* Zero flags that we handle */
+ vbuf->flags = b->flags & ~V4L2_BUFFER_MASK_FLAGS;
+ if (!vb->vb2_queue->copy_timestamp || !V4L2_TYPE_IS_OUTPUT(b->type)) {
+ /*
+ * Non-COPY timestamps and non-OUTPUT queues will get
+ * their timestamp and timestamp source flags from the
+ * queue.
+ */
+ vbuf->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+ }
+
+ if (V4L2_TYPE_IS_OUTPUT(b->type)) {
+ /*
+ * For output buffers mask out the timecode flag:
+ * this will be handled later in vb2_qbuf().
+ * The 'field' is valid metadata for this output buffer
+ * and so that needs to be copied here.
+ */
+ vbuf->flags &= ~V4L2_BUF_FLAG_TIMECODE;
+ vbuf->field = b->field;
+ } else {
+ /* Zero any output buffer flags as this is a capture buffer */
+ vbuf->flags &= ~V4L2_BUFFER_OUT_FLAGS;
+ /* Zero last flag, this is a signal from driver to userspace */
+ vbuf->flags &= ~V4L2_BUF_FLAG_LAST;
+ }
+
+ return 0;
+}
+
+static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *mdev,
+ struct v4l2_buffer *b,
+ const char *opname,
+ struct media_request **p_req)
+{
+ struct media_request *req;
+ struct vb2_v4l2_buffer *vbuf;
+ struct vb2_buffer *vb;
+ int ret;
+
if (b->type != q->type) {
dprintk(1, "%s: invalid buffer type\n", opname);
return -EINVAL;
@@ -178,7 +363,82 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b,
return -EINVAL;
}
- return __verify_planes_array(q->bufs[b->index], b);
+ vb = q->bufs[b->index];
+ vbuf = to_vb2_v4l2_buffer(vb);
+ ret = __verify_planes_array(vb, b);
+ if (ret)
+ return ret;
+
+ if (!vb->prepared) {
+ /* Copy relevant information provided by the userspace */
+ memset(vbuf->planes, 0,
+ sizeof(vbuf->planes[0]) * vb->num_planes);
+ ret = vb2_fill_vb2_v4l2_buffer(vb, b);
+ if (ret)
+ return ret;
+ }
+
+ if (!(b->flags & V4L2_BUF_FLAG_REQUEST_FD)) {
+ if (q->uses_requests) {
+ dprintk(1, "%s: queue uses requests\n", opname);
+ return -EBUSY;
+ }
+ return 0;
+ } else if (!q->supports_requests) {
+ dprintk(1, "%s: queue does not support requests\n", opname);
+ return -EACCES;
+ } else if (q->uses_qbuf) {
+ dprintk(1, "%s: queue does not use requests\n", opname);
+ return -EBUSY;
+ }
+
+ /*
+ * For proper locking when queueing a request you need to be able
+ * to lock access to the vb2 queue, so check that there is a lock
+ * that we can use. In addition p_req must be non-NULL.
+ */
+ if (WARN_ON(!q->lock || !p_req))
+ return -EINVAL;
+
+ /*
+ * Make sure this op is implemented by the driver. It's easy to forget
+ * this callback, but is it important when canceling a buffer in a
+ * queued request.
+ */
+ if (WARN_ON(!q->ops->buf_request_complete))
+ return -EINVAL;
+
+ if (vb->state != VB2_BUF_STATE_DEQUEUED) {
+ dprintk(1, "%s: buffer is not in dequeued state\n", opname);
+ return -EINVAL;
+ }
+
+ if (b->request_fd < 0) {
+ dprintk(1, "%s: request_fd < 0\n", opname);
+ return -EINVAL;
+ }
+
+ req = media_request_get_by_fd(mdev, b->request_fd);
+ if (IS_ERR(req)) {
+ dprintk(1, "%s: invalid request_fd\n", opname);
+ return PTR_ERR(req);
+ }
+
+ /*
+ * Early sanity check. This is checked again when the buffer
+ * is bound to the request in vb2_core_qbuf().
+ */
+ if (req->state != MEDIA_REQUEST_STATE_IDLE &&
+ req->state != MEDIA_REQUEST_STATE_UPDATING) {
+ dprintk(1, "%s: request is not idle\n", opname);
+ media_request_put(req);
+ return -EBUSY;
+ }
+
+ *p_req = req;
+ vbuf->request_fd = b->request_fd;
+
+ return 0;
}
/*
@@ -204,7 +464,7 @@ static void __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb)
b->timecode = vbuf->timecode;
b->sequence = vbuf->sequence;
b->reserved2 = 0;
- b->reserved = 0;
+ b->request_fd = 0;
if (q->is_multiplanar) {
/*
@@ -261,15 +521,15 @@ static void __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb)
case VB2_BUF_STATE_ACTIVE:
b->flags |= V4L2_BUF_FLAG_QUEUED;
break;
+ case VB2_BUF_STATE_IN_REQUEST:
+ b->flags |= V4L2_BUF_FLAG_IN_REQUEST;
+ break;
case VB2_BUF_STATE_ERROR:
b->flags |= V4L2_BUF_FLAG_ERROR;
/* fall through */
case VB2_BUF_STATE_DONE:
b->flags |= V4L2_BUF_FLAG_DONE;
break;
- case VB2_BUF_STATE_PREPARED:
- b->flags |= V4L2_BUF_FLAG_PREPARED;
- break;
case VB2_BUF_STATE_PREPARING:
case VB2_BUF_STATE_DEQUEUED:
case VB2_BUF_STATE_REQUEUEING:
@@ -277,8 +537,17 @@ static void __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb)
break;
}
+ if ((vb->state == VB2_BUF_STATE_DEQUEUED ||
+ vb->state == VB2_BUF_STATE_IN_REQUEST) &&
+ vb->synced && vb->prepared)
+ b->flags |= V4L2_BUF_FLAG_PREPARED;
+
if (vb2_buffer_in_use(q, vb))
b->flags |= V4L2_BUF_FLAG_MAPPED;
+ if (vbuf->request_fd >= 0) {
+ b->flags |= V4L2_BUF_FLAG_REQUEST_FD;
+ b->request_fd = vbuf->request_fd;
+ }
if (!q->is_output &&
b->flags & V4L2_BUF_FLAG_DONE &&
@@ -291,158 +560,28 @@ static void __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb)
* v4l2_buffer by the userspace. It also verifies that struct
* v4l2_buffer has a valid number of planes.
*/
-static int __fill_vb2_buffer(struct vb2_buffer *vb,
- const void *pb, struct vb2_plane *planes)
+static int __fill_vb2_buffer(struct vb2_buffer *vb, struct vb2_plane *planes)
{
- struct vb2_queue *q = vb->vb2_queue;
- const struct v4l2_buffer *b = pb;
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
unsigned int plane;
- int ret;
-
- ret = __verify_length(vb, b);
- if (ret < 0) {
- dprintk(1, "plane parameters verification failed: %d\n", ret);
- return ret;
- }
- if (b->field == V4L2_FIELD_ALTERNATE && q->is_output) {
- /*
- * If the format's field is ALTERNATE, then the buffer's field
- * should be either TOP or BOTTOM, not ALTERNATE since that
- * makes no sense. The driver has to know whether the
- * buffer represents a top or a bottom field in order to
- * program any DMA correctly. Using ALTERNATE is wrong, since
- * that just says that it is either a top or a bottom field,
- * but not which of the two it is.
- */
- dprintk(1, "the field is incorrectly set to ALTERNATE for an output buffer\n");
- return -EINVAL;
- }
- vb->timestamp = 0;
- vbuf->sequence = 0;
- if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) {
- if (b->memory == VB2_MEMORY_USERPTR) {
- for (plane = 0; plane < vb->num_planes; ++plane) {
- planes[plane].m.userptr =
- b->m.planes[plane].m.userptr;
- planes[plane].length =
- b->m.planes[plane].length;
- }
- }
- if (b->memory == VB2_MEMORY_DMABUF) {
- for (plane = 0; plane < vb->num_planes; ++plane) {
- planes[plane].m.fd =
- b->m.planes[plane].m.fd;
- planes[plane].length =
- b->m.planes[plane].length;
- }
- }
-
- /* Fill in driver-provided information for OUTPUT types */
- if (V4L2_TYPE_IS_OUTPUT(b->type)) {
- /*
- * Will have to go up to b->length when API starts
- * accepting variable number of planes.
- *
- * If bytesused == 0 for the output buffer, then fall
- * back to the full buffer size. In that case
- * userspace clearly never bothered to set it and
- * it's a safe assumption that they really meant to
- * use the full plane sizes.
- *
- * Some drivers, e.g. old codec drivers, use bytesused == 0
- * as a way to indicate that streaming is finished.
- * In that case, the driver should use the
- * allow_zero_bytesused flag to keep old userspace
- * applications working.
- */
- for (plane = 0; plane < vb->num_planes; ++plane) {
- struct vb2_plane *pdst = &planes[plane];
- struct v4l2_plane *psrc = &b->m.planes[plane];
-
- if (psrc->bytesused == 0)
- vb2_warn_zero_bytesused(vb);
-
- if (vb->vb2_queue->allow_zero_bytesused)
- pdst->bytesused = psrc->bytesused;
- else
- pdst->bytesused = psrc->bytesused ?
- psrc->bytesused : pdst->length;
- pdst->data_offset = psrc->data_offset;
- }
- }
- } else {
- /*
- * Single-planar buffers do not use planes array,
- * so fill in relevant v4l2_buffer struct fields instead.
- * In videobuf we use our internal V4l2_planes struct for
- * single-planar buffers as well, for simplicity.
- *
- * If bytesused == 0 for the output buffer, then fall back
- * to the full buffer size as that's a sensible default.
- *
- * Some drivers, e.g. old codec drivers, use bytesused == 0 as
- * a way to indicate that streaming is finished. In that case,
- * the driver should use the allow_zero_bytesused flag to keep
- * old userspace applications working.
- */
- if (b->memory == VB2_MEMORY_USERPTR) {
- planes[0].m.userptr = b->m.userptr;
- planes[0].length = b->length;
- }
+ if (!vb->vb2_queue->is_output || !vb->vb2_queue->copy_timestamp)
+ vb->timestamp = 0;
- if (b->memory == VB2_MEMORY_DMABUF) {
- planes[0].m.fd = b->m.fd;
- planes[0].length = b->length;
+ for (plane = 0; plane < vb->num_planes; ++plane) {
+ if (vb->vb2_queue->memory != VB2_MEMORY_MMAP) {
+ planes[plane].m = vbuf->planes[plane].m;
+ planes[plane].length = vbuf->planes[plane].length;
}
-
- if (V4L2_TYPE_IS_OUTPUT(b->type)) {
- if (b->bytesused == 0)
- vb2_warn_zero_bytesused(vb);
-
- if (vb->vb2_queue->allow_zero_bytesused)
- planes[0].bytesused = b->bytesused;
- else
- planes[0].bytesused = b->bytesused ?
- b->bytesused : planes[0].length;
- } else
- planes[0].bytesused = 0;
-
- }
-
- /* Zero flags that the vb2 core handles */
- vbuf->flags = b->flags & ~V4L2_BUFFER_MASK_FLAGS;
- if (!vb->vb2_queue->copy_timestamp || !V4L2_TYPE_IS_OUTPUT(b->type)) {
- /*
- * Non-COPY timestamps and non-OUTPUT queues will get
- * their timestamp and timestamp source flags from the
- * queue.
- */
- vbuf->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+ planes[plane].bytesused = vbuf->planes[plane].bytesused;
+ planes[plane].data_offset = vbuf->planes[plane].data_offset;
}
-
- if (V4L2_TYPE_IS_OUTPUT(b->type)) {
- /*
- * For output buffers mask out the timecode flag:
- * this will be handled later in vb2_qbuf().
- * The 'field' is valid metadata for this output buffer
- * and so that needs to be copied here.
- */
- vbuf->flags &= ~V4L2_BUF_FLAG_TIMECODE;
- vbuf->field = b->field;
- } else {
- /* Zero any output buffer flags as this is a capture buffer */
- vbuf->flags &= ~V4L2_BUFFER_OUT_FLAGS;
- /* Zero last flag, this is a signal from driver to userspace */
- vbuf->flags &= ~V4L2_BUF_FLAG_LAST;
- }
-
return 0;
}
static const struct vb2_buf_ops v4l2_buf_ops = {
.verify_planes_array = __verify_planes_array_core,
+ .init_buffer = __init_v4l2_vb2_buffer,
.fill_user_buffer = __fill_v4l2_buffer,
.fill_vb2_buffer = __fill_vb2_buffer,
.copy_timestamp = __copy_timestamp,
@@ -483,15 +622,30 @@ int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b)
}
EXPORT_SYMBOL(vb2_querybuf);
+static void fill_buf_caps(struct vb2_queue *q, u32 *caps)
+{
+ *caps = 0;
+ if (q->io_modes & VB2_MMAP)
+ *caps |= V4L2_BUF_CAP_SUPPORTS_MMAP;
+ if (q->io_modes & VB2_USERPTR)
+ *caps |= V4L2_BUF_CAP_SUPPORTS_USERPTR;
+ if (q->io_modes & VB2_DMABUF)
+ *caps |= V4L2_BUF_CAP_SUPPORTS_DMABUF;
+ if (q->supports_requests)
+ *caps |= V4L2_BUF_CAP_SUPPORTS_REQUESTS;
+}
+
int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
{
int ret = vb2_verify_memory_type(q, req->memory, req->type);
+ fill_buf_caps(q, &req->capabilities);
return ret ? ret : vb2_core_reqbufs(q, req->memory, &req->count);
}
EXPORT_SYMBOL_GPL(vb2_reqbufs);
-int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b)
+int vb2_prepare_buf(struct vb2_queue *q, struct media_device *mdev,
+ struct v4l2_buffer *b)
{
int ret;
@@ -500,7 +654,10 @@ int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b)
return -EBUSY;
}
- ret = vb2_queue_or_prepare_buf(q, b, "prepare_buf");
+ if (b->flags & V4L2_BUF_FLAG_REQUEST_FD)
+ return -EINVAL;
+
+ ret = vb2_queue_or_prepare_buf(q, mdev, b, "prepare_buf", NULL);
return ret ? ret : vb2_core_prepare_buf(q, b->index, b);
}
@@ -514,6 +671,7 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
int ret = vb2_verify_memory_type(q, create->memory, f->type);
unsigned i;
+ fill_buf_caps(q, &create->capabilities);
create->index = q->num_buffers;
if (create->count == 0)
return ret != -EBUSY ? ret : 0;
@@ -560,8 +718,10 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
}
EXPORT_SYMBOL_GPL(vb2_create_bufs);
-int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
+int vb2_qbuf(struct vb2_queue *q, struct media_device *mdev,
+ struct v4l2_buffer *b)
{
+ struct media_request *req = NULL;
int ret;
if (vb2_fileio_is_active(q)) {
@@ -569,8 +729,13 @@ int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
return -EBUSY;
}
- ret = vb2_queue_or_prepare_buf(q, b, "qbuf");
- return ret ? ret : vb2_core_qbuf(q, b->index, b);
+ ret = vb2_queue_or_prepare_buf(q, mdev, b, "qbuf", &req);
+ if (ret)
+ return ret;
+ ret = vb2_core_qbuf(q, b->index, b, req);
+ if (req)
+ media_request_put(req);
+ return ret;
}
EXPORT_SYMBOL_GPL(vb2_qbuf);
@@ -714,6 +879,7 @@ int vb2_ioctl_reqbufs(struct file *file, void *priv,
struct video_device *vdev = video_devdata(file);
int res = vb2_verify_memory_type(vdev->queue, p->memory, p->type);
+ fill_buf_caps(vdev->queue, &p->capabilities);
if (res)
return res;
if (vb2_queue_is_busy(vdev, file))
@@ -735,6 +901,7 @@ int vb2_ioctl_create_bufs(struct file *file, void *priv,
p->format.type);
p->index = vdev->queue->num_buffers;
+ fill_buf_caps(vdev->queue, &p->capabilities);
/*
* If count == 0, then just check if memory and type are valid.
* Any -EBUSY result from vb2_verify_memory_type can be mapped to 0.
@@ -760,7 +927,7 @@ int vb2_ioctl_prepare_buf(struct file *file, void *priv,
if (vb2_queue_is_busy(vdev, file))
return -EBUSY;
- return vb2_prepare_buf(vdev->queue, p);
+ return vb2_prepare_buf(vdev->queue, vdev->v4l2_dev->mdev, p);
}
EXPORT_SYMBOL_GPL(vb2_ioctl_prepare_buf);
@@ -779,7 +946,7 @@ int vb2_ioctl_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
if (vb2_queue_is_busy(vdev, file))
return -EBUSY;
- return vb2_qbuf(vdev->queue, p);
+ return vb2_qbuf(vdev->queue, vdev->v4l2_dev->mdev, p);
}
EXPORT_SYMBOL_GPL(vb2_ioctl_qbuf);
@@ -961,6 +1128,57 @@ void vb2_ops_wait_finish(struct vb2_queue *vq)
}
EXPORT_SYMBOL_GPL(vb2_ops_wait_finish);
+/*
+ * Note that this function is called during validation time and
+ * thus the req_queue_mutex is held to ensure no request objects
+ * can be added or deleted while validating. So there is no need
+ * to protect the objects list.
+ */
+int vb2_request_validate(struct media_request *req)
+{
+ struct media_request_object *obj;
+ int ret = 0;
+
+ if (!vb2_request_buffer_cnt(req))
+ return -ENOENT;
+
+ list_for_each_entry(obj, &req->objects, list) {
+ if (!obj->ops->prepare)
+ continue;
+
+ ret = obj->ops->prepare(obj);
+ if (ret)
+ break;
+ }
+
+ if (ret) {
+ list_for_each_entry_continue_reverse(obj, &req->objects, list)
+ if (obj->ops->unprepare)
+ obj->ops->unprepare(obj);
+ return ret;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(vb2_request_validate);
+
+void vb2_request_queue(struct media_request *req)
+{
+ struct media_request_object *obj, *obj_safe;
+
+ /*
+ * Queue all objects. Note that buffer objects are at the end of the
+ * objects list, after all other object types. Once buffer objects
+ * are queued, the driver might delete them immediately (if the driver
+ * processes the buffer at once), so we have to use
+ * list_for_each_entry_safe() to handle the case where the object we
+ * queue is deleted.
+ */
+ list_for_each_entry_safe(obj, obj_safe, &req->objects, list)
+ if (obj->ops->queue)
+ obj->ops->queue(obj);
+}
+EXPORT_SYMBOL_GPL(vb2_request_queue);
+
MODULE_DESCRIPTION("Driver helper framework for Video for Linux 2");
MODULE_AUTHOR("Pawel Osciak <pawel@osciak.com>, Marek Szyprowski");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c
index d548f98c7a67..1544e8cef564 100644
--- a/drivers/media/dvb-core/dmxdev.c
+++ b/drivers/media/dvb-core/dmxdev.c
@@ -1265,6 +1265,7 @@ static const struct file_operations dvb_demux_fops = {
.owner = THIS_MODULE,
.read = dvb_demux_read,
.unlocked_ioctl = dvb_demux_ioctl,
+ .compat_ioctl = dvb_demux_ioctl,
.open = dvb_demux_open,
.release = dvb_demux_release,
.poll = dvb_demux_poll,
diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c
index c4e7ebfe4d29..961207cf09eb 100644
--- a/drivers/media/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb-core/dvb_frontend.c
@@ -2422,7 +2422,7 @@ static int dvb_frontend_handle_ioctl(struct file *file,
struct dvb_frontend_info *info = parg;
memset(info, 0, sizeof(*info));
- strcpy(info->name, fe->ops.info.name);
+ strscpy(info->name, fe->ops.info.name, sizeof(info->name));
info->symbol_rate_min = fe->ops.info.symbol_rate_min;
info->symbol_rate_max = fe->ops.info.symbol_rate_max;
info->symbol_rate_tolerance = fe->ops.info.symbol_rate_tolerance;
diff --git a/drivers/media/dvb-core/dvb_vb2.c b/drivers/media/dvb-core/dvb_vb2.c
index b811adf88afa..6974f1731529 100644
--- a/drivers/media/dvb-core/dvb_vb2.c
+++ b/drivers/media/dvb-core/dvb_vb2.c
@@ -146,8 +146,7 @@ static void _fill_dmx_buffer(struct vb2_buffer *vb, void *pb)
dprintk(3, "[%s]\n", ctx->name);
}
-static int _fill_vb2_buffer(struct vb2_buffer *vb,
- const void *pb, struct vb2_plane *planes)
+static int _fill_vb2_buffer(struct vb2_buffer *vb, struct vb2_plane *planes)
{
struct dvb_vb2_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
@@ -194,7 +193,7 @@ int dvb_vb2_init(struct dvb_vb2_ctx *ctx, const char *name, int nonblocking)
spin_lock_init(&ctx->slock);
INIT_LIST_HEAD(&ctx->dvb_q);
- strlcpy(ctx->name, name, DVB_VB2_NAME_MAX);
+ strscpy(ctx->name, name, DVB_VB2_NAME_MAX);
ctx->nonblocking = nonblocking;
ctx->state = DVB_VB2_STATE_INIT;
@@ -385,7 +384,7 @@ int dvb_vb2_qbuf(struct dvb_vb2_ctx *ctx, struct dmx_buffer *b)
{
int ret;
- ret = vb2_core_qbuf(&ctx->vb_q, b->index, b);
+ ret = vb2_core_qbuf(&ctx->vb_q, b->index, b, NULL);
if (ret) {
dprintk(1, "[%s] index=%d errno=%d\n", ctx->name,
b->index, ret);
diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c
index 3c8778570331..b7171bf094fb 100644
--- a/drivers/media/dvb-core/dvbdev.c
+++ b/drivers/media/dvb-core/dvbdev.c
@@ -621,7 +621,7 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
unsigned demux_pad = 0;
unsigned dvr_pad = 0;
unsigned ntuner = 0, ndemod = 0;
- int ret;
+ int ret, pad_source, pad_sink;
static const char *connector_name = "Television";
if (!mdev)
@@ -681,7 +681,7 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
if (ret)
return ret;
- if (!ntuner)
+ if (!ntuner) {
ret = media_create_pad_links(mdev,
MEDIA_ENT_F_CONN_RF,
conn, 0,
@@ -689,22 +689,31 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
demod, 0,
MEDIA_LNK_FL_ENABLED,
false);
- else
+ } else {
+ pad_sink = media_get_pad_index(tuner, true,
+ PAD_SIGNAL_ANALOG);
+ if (pad_sink < 0)
+ return -EINVAL;
ret = media_create_pad_links(mdev,
MEDIA_ENT_F_CONN_RF,
conn, 0,
MEDIA_ENT_F_TUNER,
- tuner, TUNER_PAD_RF_INPUT,
+ tuner, pad_sink,
MEDIA_LNK_FL_ENABLED,
false);
+ }
if (ret)
return ret;
}
if (ntuner && ndemod) {
+ pad_source = media_get_pad_index(tuner, true,
+ PAD_SIGNAL_ANALOG);
+ if (pad_source)
+ return -EINVAL;
ret = media_create_pad_links(mdev,
MEDIA_ENT_F_TUNER,
- tuner, TUNER_PAD_OUTPUT,
+ tuner, pad_source,
MEDIA_ENT_F_DTV_DEMOD,
demod, 0, MEDIA_LNK_FL_ENABLED,
false);
@@ -967,9 +976,9 @@ struct i2c_client *dvb_module_probe(const char *module_name,
return NULL;
if (name)
- strlcpy(board_info->type, name, I2C_NAME_SIZE);
+ strscpy(board_info->type, name, I2C_NAME_SIZE);
else
- strlcpy(board_info->type, module_name, I2C_NAME_SIZE);
+ strscpy(board_info->type, module_name, I2C_NAME_SIZE);
board_info->addr = addr;
board_info->platform_data = platform_data;
diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig
index 048285134cdf..847da72d1256 100644
--- a/drivers/media/dvb-frontends/Kconfig
+++ b/drivers/media/dvb-frontends/Kconfig
@@ -791,6 +791,16 @@ config DVB_LNBH25
An SEC control chip.
Say Y when you want to support this chip.
+config DVB_LNBH29
+ tristate "LNBH29 SEC controller"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ LNB power supply and control voltage
+ regulator chip with step-up converter
+ and I2C interface for STMicroelectronics LNBH29.
+ Say Y when you want to support this chip.
+
config DVB_LNBP21
tristate "LNBP21/LNBH24 SEC controllers"
depends on DVB_CORE && I2C
diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile
index 779dfd027b24..e9179162658c 100644
--- a/drivers/media/dvb-frontends/Makefile
+++ b/drivers/media/dvb-frontends/Makefile
@@ -58,6 +58,7 @@ obj-$(CONFIG_DVB_LGDT3306A) += lgdt3306a.o
obj-$(CONFIG_DVB_LG2160) += lg2160.o
obj-$(CONFIG_DVB_CX24123) += cx24123.o
obj-$(CONFIG_DVB_LNBH25) += lnbh25.o
+obj-$(CONFIG_DVB_LNBH29) += lnbh29.o
obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
obj-$(CONFIG_DVB_LNBP22) += lnbp22.o
obj-$(CONFIG_DVB_ISL6405) += isl6405.o
diff --git a/drivers/media/dvb-frontends/au8522_decoder.c b/drivers/media/dvb-frontends/au8522_decoder.c
index f285096a48f0..b2dd20ffd002 100644
--- a/drivers/media/dvb-frontends/au8522_decoder.c
+++ b/drivers/media/dvb-frontends/au8522_decoder.c
@@ -718,10 +718,12 @@ static int au8522_probe(struct i2c_client *client,
v4l2_i2c_subdev_init(sd, client, &au8522_ops);
#if defined(CONFIG_MEDIA_CONTROLLER)
- state->pads[DEMOD_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK;
- state->pads[DEMOD_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE;
- state->pads[DEMOD_PAD_VBI_OUT].flags = MEDIA_PAD_FL_SOURCE;
- state->pads[DEMOD_PAD_AUDIO_OUT].flags = MEDIA_PAD_FL_SOURCE;
+ state->pads[AU8522_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK;
+ state->pads[AU8522_PAD_IF_INPUT].sig_type = PAD_SIGNAL_ANALOG;
+ state->pads[AU8522_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE;
+ state->pads[AU8522_PAD_VID_OUT].sig_type = PAD_SIGNAL_DV;
+ state->pads[AU8522_PAD_AUDIO_OUT].flags = MEDIA_PAD_FL_SOURCE;
+ state->pads[AU8522_PAD_AUDIO_OUT].sig_type = PAD_SIGNAL_AUDIO;
sd->entity.function = MEDIA_ENT_F_ATV_DECODER;
ret = media_entity_pads_init(&sd->entity, ARRAY_SIZE(state->pads),
diff --git a/drivers/media/dvb-frontends/au8522_priv.h b/drivers/media/dvb-frontends/au8522_priv.h
index 2043c1744753..68299d2705f7 100644
--- a/drivers/media/dvb-frontends/au8522_priv.h
+++ b/drivers/media/dvb-frontends/au8522_priv.h
@@ -40,6 +40,13 @@
#define AU8522_DIGITAL_MODE 1
#define AU8522_SUSPEND_MODE 2
+enum au8522_pads {
+ AU8522_PAD_IF_INPUT,
+ AU8522_PAD_VID_OUT,
+ AU8522_PAD_AUDIO_OUT,
+ AU8522_NUM_PADS
+};
+
struct au8522_state {
struct i2c_client *c;
struct i2c_adapter *i2c;
@@ -71,7 +78,7 @@ struct au8522_state {
struct v4l2_ctrl_handler hdl;
#ifdef CONFIG_MEDIA_CONTROLLER
- struct media_pad pads[DEMOD_NUM_PADS];
+ struct media_pad pads[AU8522_NUM_PADS];
#endif
};
diff --git a/drivers/media/dvb-frontends/cx24123.c b/drivers/media/dvb-frontends/cx24123.c
index e49215020a93..83dfae78579d 100644
--- a/drivers/media/dvb-frontends/cx24123.c
+++ b/drivers/media/dvb-frontends/cx24123.c
@@ -1087,7 +1087,7 @@ struct dvb_frontend *cx24123_attach(const struct cx24123_config *config,
if (config->dont_use_pll)
cx24123_repeater_mode(state, 1, 0);
- strlcpy(state->tuner_i2c_adapter.name, "CX24123 tuner I2C bus",
+ strscpy(state->tuner_i2c_adapter.name, "CX24123 tuner I2C bus",
sizeof(state->tuner_i2c_adapter.name));
state->tuner_i2c_adapter.algo = &cx24123_tuner_i2c_algo;
state->tuner_i2c_adapter.algo_data = NULL;
diff --git a/drivers/media/dvb-frontends/cxd2099.c b/drivers/media/dvb-frontends/cxd2099.c
index 4a0ce3037fd6..5264e873850e 100644
--- a/drivers/media/dvb-frontends/cxd2099.c
+++ b/drivers/media/dvb-frontends/cxd2099.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* cxd2099.c: Driver for the Sony CXD2099AR Common Interface Controller
*
@@ -701,4 +702,4 @@ module_i2c_driver(cxd2099_driver);
MODULE_DESCRIPTION("Sony CXD2099AR Common Interface controller driver");
MODULE_AUTHOR("Ralph Metzler");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/dvb-frontends/cxd2099.h b/drivers/media/dvb-frontends/cxd2099.h
index ec1910dec3f3..0c101bdef01d 100644
--- a/drivers/media/dvb-frontends/cxd2099.h
+++ b/drivers/media/dvb-frontends/cxd2099.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* cxd2099.h: Driver for the Sony CXD2099AR Common Interface Controller
*
diff --git a/drivers/media/dvb-frontends/cxd2820r_core.c b/drivers/media/dvb-frontends/cxd2820r_core.c
index 3e0d8cbd76da..0f0acf98d226 100644
--- a/drivers/media/dvb-frontends/cxd2820r_core.c
+++ b/drivers/media/dvb-frontends/cxd2820r_core.c
@@ -540,7 +540,7 @@ struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *config,
pdata.attach_in_use = true;
memset(&board_info, 0, sizeof(board_info));
- strlcpy(board_info.type, "cxd2820r", I2C_NAME_SIZE);
+ strscpy(board_info.type, "cxd2820r", I2C_NAME_SIZE);
board_info.addr = config->i2c_address;
board_info.platform_data = &pdata;
client = i2c_new_device(adapter, &board_info);
diff --git a/drivers/media/dvb-frontends/dibx000_common.c b/drivers/media/dvb-frontends/dibx000_common.c
index 70119c79ac2b..dc80a8442e7a 100644
--- a/drivers/media/dvb-frontends/dibx000_common.c
+++ b/drivers/media/dvb-frontends/dibx000_common.c
@@ -424,7 +424,7 @@ static int i2c_adapter_init(struct i2c_adapter *i2c_adap,
struct i2c_algorithm *algo, const char *name,
struct dibx000_i2c_master *mst)
{
- strlcpy(i2c_adap->name, name, sizeof(i2c_adap->name));
+ strscpy(i2c_adap->name, name, sizeof(i2c_adap->name));
i2c_adap->algo = algo;
i2c_adap->algo_data = NULL;
i2c_set_adapdata(i2c_adap, mst);
diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c
index 9628d4067fe1..551b7d65fa66 100644
--- a/drivers/media/dvb-frontends/drx39xyj/drxj.c
+++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c
@@ -3555,8 +3555,8 @@ static int ctrl_set_uio_cfg(struct drx_demod_instance *demod, struct drxuio_cfg
if (!ext_attr->has_smatx)
return -EIO;
switch (uio_cfg->mode) {
- case DRX_UIO_MODE_FIRMWARE_SMA: /* falltrough */
- case DRX_UIO_MODE_FIRMWARE_SAW: /* falltrough */
+ case DRX_UIO_MODE_FIRMWARE_SMA: /* fall through */
+ case DRX_UIO_MODE_FIRMWARE_SAW: /* fall through */
case DRX_UIO_MODE_READWRITE:
ext_attr->uio_sma_tx_mode = uio_cfg->mode;
break;
@@ -3579,7 +3579,7 @@ static int ctrl_set_uio_cfg(struct drx_demod_instance *demod, struct drxuio_cfg
if (!ext_attr->has_smarx)
return -EIO;
switch (uio_cfg->mode) {
- case DRX_UIO_MODE_FIRMWARE0: /* falltrough */
+ case DRX_UIO_MODE_FIRMWARE0: /* fall through */
case DRX_UIO_MODE_READWRITE:
ext_attr->uio_sma_rx_mode = uio_cfg->mode;
break;
@@ -3603,7 +3603,7 @@ static int ctrl_set_uio_cfg(struct drx_demod_instance *demod, struct drxuio_cfg
if (!ext_attr->has_gpio)
return -EIO;
switch (uio_cfg->mode) {
- case DRX_UIO_MODE_FIRMWARE0: /* falltrough */
+ case DRX_UIO_MODE_FIRMWARE0: /* fall through */
case DRX_UIO_MODE_READWRITE:
ext_attr->uio_gpio_mode = uio_cfg->mode;
break;
@@ -3639,7 +3639,7 @@ static int ctrl_set_uio_cfg(struct drx_demod_instance *demod, struct drxuio_cfg
}
ext_attr->uio_irqn_mode = uio_cfg->mode;
break;
- case DRX_UIO_MODE_FIRMWARE0: /* falltrough */
+ case DRX_UIO_MODE_FIRMWARE0: /* fall through */
default:
return -EINVAL;
break;
diff --git a/drivers/media/dvb-frontends/lgdt330x.c b/drivers/media/dvb-frontends/lgdt330x.c
index 10d584ce538d..96807e134886 100644
--- a/drivers/media/dvb-frontends/lgdt330x.c
+++ b/drivers/media/dvb-frontends/lgdt330x.c
@@ -929,7 +929,7 @@ struct dvb_frontend *lgdt330x_attach(const struct lgdt330x_config *_config,
struct i2c_board_info board_info = {};
struct lgdt330x_config config = *_config;
- strlcpy(board_info.type, "lgdt330x", sizeof(board_info.type));
+ strscpy(board_info.type, "lgdt330x", sizeof(board_info.type));
board_info.addr = demod_address;
board_info.platform_data = &config;
client = i2c_new_device(i2c, &board_info);
diff --git a/drivers/media/dvb-frontends/lnbh29.c b/drivers/media/dvb-frontends/lnbh29.c
new file mode 100644
index 000000000000..410bae099c32
--- /dev/null
+++ b/drivers/media/dvb-frontends/lnbh29.c
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Driver for LNB supply and control IC STMicroelectronics LNBH29
+//
+// Copyright (c) 2018 Socionext Inc.
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+
+#include <media/dvb_frontend.h>
+#include "lnbh29.h"
+
+/**
+ * struct lnbh29_priv - LNBH29 driver private data
+ * @i2c: Pointer to the I2C adapter structure
+ * @i2c_address: I2C address of LNBH29 chip
+ * @config: Registers configuration
+ * offset 0: 1st register address, always 0x01 (DATA)
+ * offset 1: DATA register value
+ */
+struct lnbh29_priv {
+ struct i2c_adapter *i2c;
+ u8 i2c_address;
+ u8 config[2];
+};
+
+#define LNBH29_STATUS_OLF BIT(0)
+#define LNBH29_STATUS_OTF BIT(1)
+#define LNBH29_STATUS_VMON BIT(2)
+#define LNBH29_STATUS_PNG BIT(3)
+#define LNBH29_STATUS_PDO BIT(4)
+#define LNBH29_VSEL_MASK GENMASK(2, 0)
+#define LNBH29_VSEL_0 0x00
+/* Min: 13.188V, Typ: 13.667V, Max:14V */
+#define LNBH29_VSEL_13 0x03
+/* Min: 18.158V, Typ: 18.817V, Max:19.475V */
+#define LNBH29_VSEL_18 0x07
+
+static int lnbh29_read_vmon(struct lnbh29_priv *priv)
+{
+ u8 addr = 0x00;
+ u8 status[2];
+ int ret;
+ struct i2c_msg msg[2] = {
+ {
+ .addr = priv->i2c_address,
+ .flags = 0,
+ .len = 1,
+ .buf = &addr
+ }, {
+ .addr = priv->i2c_address,
+ .flags = I2C_M_RD,
+ .len = sizeof(status),
+ .buf = status
+ }
+ };
+
+ ret = i2c_transfer(priv->i2c, msg, 2);
+ if (ret >= 0 && ret != 2)
+ ret = -EIO;
+ if (ret < 0) {
+ dev_dbg(&priv->i2c->dev, "LNBH29 I2C transfer failed (%d)\n",
+ ret);
+ return ret;
+ }
+
+ if (status[0] & (LNBH29_STATUS_OLF | LNBH29_STATUS_VMON)) {
+ dev_err(&priv->i2c->dev,
+ "LNBH29 voltage in failure state, status reg 0x%x\n",
+ status[0]);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int lnbh29_set_voltage(struct dvb_frontend *fe,
+ enum fe_sec_voltage voltage)
+{
+ struct lnbh29_priv *priv = fe->sec_priv;
+ u8 data_reg;
+ int ret;
+ struct i2c_msg msg = {
+ .addr = priv->i2c_address,
+ .flags = 0,
+ .len = sizeof(priv->config),
+ .buf = priv->config
+ };
+
+ switch (voltage) {
+ case SEC_VOLTAGE_OFF:
+ data_reg = LNBH29_VSEL_0;
+ break;
+ case SEC_VOLTAGE_13:
+ data_reg = LNBH29_VSEL_13;
+ break;
+ case SEC_VOLTAGE_18:
+ data_reg = LNBH29_VSEL_18;
+ break;
+ default:
+ return -EINVAL;
+ }
+ priv->config[1] &= ~LNBH29_VSEL_MASK;
+ priv->config[1] |= data_reg;
+
+ ret = i2c_transfer(priv->i2c, &msg, 1);
+ if (ret >= 0 && ret != 1)
+ ret = -EIO;
+ if (ret < 0) {
+ dev_err(&priv->i2c->dev, "LNBH29 I2C transfer error (%d)\n",
+ ret);
+ return ret;
+ }
+
+ /* Soft-start time (Vout 0V to 18V) is Typ. 6ms. */
+ usleep_range(6000, 20000);
+
+ if (voltage == SEC_VOLTAGE_OFF)
+ return 0;
+
+ return lnbh29_read_vmon(priv);
+}
+
+static void lnbh29_release(struct dvb_frontend *fe)
+{
+ lnbh29_set_voltage(fe, SEC_VOLTAGE_OFF);
+ kfree(fe->sec_priv);
+ fe->sec_priv = NULL;
+}
+
+struct dvb_frontend *lnbh29_attach(struct dvb_frontend *fe,
+ struct lnbh29_config *cfg,
+ struct i2c_adapter *i2c)
+{
+ struct lnbh29_priv *priv;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return NULL;
+
+ priv->i2c_address = (cfg->i2c_address >> 1);
+ priv->i2c = i2c;
+ priv->config[0] = 0x01;
+ priv->config[1] = cfg->data_config;
+ fe->sec_priv = priv;
+
+ if (lnbh29_set_voltage(fe, SEC_VOLTAGE_OFF)) {
+ dev_err(&i2c->dev, "no LNBH29 found at I2C addr 0x%02x\n",
+ priv->i2c_address);
+ kfree(priv);
+ fe->sec_priv = NULL;
+ return NULL;
+ }
+
+ fe->ops.release_sec = lnbh29_release;
+ fe->ops.set_voltage = lnbh29_set_voltage;
+
+ dev_info(&i2c->dev, "LNBH29 attached at I2C addr 0x%02x\n",
+ priv->i2c_address);
+
+ return fe;
+}
+EXPORT_SYMBOL(lnbh29_attach);
+
+MODULE_AUTHOR("Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>");
+MODULE_DESCRIPTION("STMicroelectronics LNBH29 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/dvb-frontends/lnbh29.h b/drivers/media/dvb-frontends/lnbh29.h
new file mode 100644
index 000000000000..6179921520d9
--- /dev/null
+++ b/drivers/media/dvb-frontends/lnbh29.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Driver for LNB supply and control IC STMicroelectronics LNBH29
+ *
+ * Copyright (c) 2018 Socionext Inc.
+ */
+
+#ifndef LNBH29_H
+#define LNBH29_H
+
+#include <linux/i2c.h>
+#include <linux/dvb/frontend.h>
+
+/* Using very low E.S.R. capacitors or ceramic caps */
+#define LNBH29_DATA_COMP BIT(3)
+
+struct lnbh29_config {
+ u8 i2c_address;
+ u8 data_config;
+};
+
+#if IS_REACHABLE(CONFIG_DVB_LNBH29)
+struct dvb_frontend *lnbh29_attach(struct dvb_frontend *fe,
+ struct lnbh29_config *cfg,
+ struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *lnbh29_attach(struct dvb_frontend *fe,
+ struct lnbh29_config *cfg,
+ struct i2c_adapter *i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c
index dffd2d4bf1c8..123f2a33738b 100644
--- a/drivers/media/dvb-frontends/m88ds3103.c
+++ b/drivers/media/dvb-frontends/m88ds3103.c
@@ -1284,7 +1284,7 @@ struct dvb_frontend *m88ds3103_attach(const struct m88ds3103_config *cfg,
pdata.attach_in_use = true;
memset(&board_info, 0, sizeof(board_info));
- strlcpy(board_info.type, "m88ds3103", I2C_NAME_SIZE);
+ strscpy(board_info.type, "m88ds3103", I2C_NAME_SIZE);
board_info.addr = cfg->i2c_addr;
board_info.platform_data = &pdata;
client = i2c_new_device(i2c, &board_info);
diff --git a/drivers/media/dvb-frontends/mt312.c b/drivers/media/dvb-frontends/mt312.c
index aad07adda37d..03e74a729168 100644
--- a/drivers/media/dvb-frontends/mt312.c
+++ b/drivers/media/dvb-frontends/mt312.c
@@ -815,17 +815,20 @@ struct dvb_frontend *mt312_attach(const struct mt312_config *config,
switch (state->id) {
case ID_VP310:
- strcpy(state->frontend.ops.info.name, "Zarlink VP310 DVB-S");
+ strscpy(state->frontend.ops.info.name, "Zarlink VP310 DVB-S",
+ sizeof(state->frontend.ops.info.name));
state->xtal = MT312_PLL_CLK;
state->freq_mult = 9;
break;
case ID_MT312:
- strcpy(state->frontend.ops.info.name, "Zarlink MT312 DVB-S");
+ strscpy(state->frontend.ops.info.name, "Zarlink MT312 DVB-S",
+ sizeof(state->frontend.ops.info.name));
state->xtal = MT312_PLL_CLK;
state->freq_mult = 6;
break;
case ID_ZL10313:
- strcpy(state->frontend.ops.info.name, "Zarlink ZL10313 DVB-S");
+ strscpy(state->frontend.ops.info.name, "Zarlink ZL10313 DVB-S",
+ sizeof(state->frontend.ops.info.name));
state->xtal = MT312_PLL_CLK_10_111;
state->freq_mult = 9;
break;
diff --git a/drivers/media/dvb-frontends/mxl5xx.c b/drivers/media/dvb-frontends/mxl5xx.c
index 295f37d5f10e..6191315f5970 100644
--- a/drivers/media/dvb-frontends/mxl5xx.c
+++ b/drivers/media/dvb-frontends/mxl5xx.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Driver for the MaxLinear MxL5xx family of tuners/demods
*
@@ -17,7 +18,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
*/
#include <linux/kernel.h>
@@ -739,6 +739,7 @@ static int get_frontend(struct dvb_frontend *fe,
default:
break;
}
+ /* Fall through */
case SYS_DVBS:
switch ((enum MXL_HYDRA_MODULATION_E)
reg_data[DMD_MODULATION_SCHEME_ADDR]) {
@@ -1893,4 +1894,4 @@ EXPORT_SYMBOL_GPL(mxl5xx_attach);
MODULE_DESCRIPTION("MaxLinear MxL5xx DVB-S/S2 tuner-demodulator driver");
MODULE_AUTHOR("Ralph and Marcus Metzler, Metzler Brothers Systementwicklung GbR");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/dvb-frontends/mxl5xx.h b/drivers/media/dvb-frontends/mxl5xx.h
index ad4c21846800..706a2f5d8f97 100644
--- a/drivers/media/dvb-frontends/mxl5xx.h
+++ b/drivers/media/dvb-frontends/mxl5xx.h
@@ -1,3 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Driver for the MaxLinear MxL5xx family of tuners/demods
+ *
+ * Copyright (C) 2014-2015 Ralph Metzler <rjkm@metzlerbros.de>
+ * Marcus Metzler <mocm@metzlerbros.de>
+ * developed for Digital Devices GmbH
+ *
+ * based on code:
+ * Copyright (c) 2011-2013 MaxLinear, Inc. All rights reserved
+ * which was released under GPL V2
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
#ifndef _MXL5XX_H_
#define _MXL5XX_H_
diff --git a/drivers/media/dvb-frontends/mxl5xx_defs.h b/drivers/media/dvb-frontends/mxl5xx_defs.h
index fd9e61e0188f..1442af8dc176 100644
--- a/drivers/media/dvb-frontends/mxl5xx_defs.h
+++ b/drivers/media/dvb-frontends/mxl5xx_defs.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Defines for the Maxlinear MX58x family of tuners/demods
*
diff --git a/drivers/media/dvb-frontends/mxl5xx_regs.h b/drivers/media/dvb-frontends/mxl5xx_regs.h
index 5001dafe1ba8..86d5317eba7a 100644
--- a/drivers/media/dvb-frontends/mxl5xx_regs.h
+++ b/drivers/media/dvb-frontends/mxl5xx_regs.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2011-2013 MaxLinear, Inc. All rights reserved
*
diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c
index d448d9d4879c..d6673f4fb47b 100644
--- a/drivers/media/dvb-frontends/rtl2832_sdr.c
+++ b/drivers/media/dvb-frontends/rtl2832_sdr.c
@@ -439,8 +439,8 @@ static int rtl2832_sdr_querycap(struct file *file, void *fh,
dev_dbg(&pdev->dev, "\n");
- strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
- strlcpy(cap->card, dev->vdev.name, sizeof(cap->card));
+ strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
+ strscpy(cap->card, dev->vdev.name, sizeof(cap->card));
usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
cap->device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_STREAMING |
V4L2_CAP_READWRITE | V4L2_CAP_TUNER;
@@ -976,7 +976,7 @@ static int rtl2832_sdr_g_tuner(struct file *file, void *priv,
dev_dbg(&pdev->dev, "index=%d type=%d\n", v->index, v->type);
if (v->index == 0) {
- strlcpy(v->name, "ADC: Realtek RTL2832", sizeof(v->name));
+ strscpy(v->name, "ADC: Realtek RTL2832", sizeof(v->name));
v->type = V4L2_TUNER_ADC;
v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
v->rangelow = 300000;
@@ -986,7 +986,7 @@ static int rtl2832_sdr_g_tuner(struct file *file, void *priv,
V4L2_SUBDEV_HAS_OP(dev->v4l2_subdev, tuner, g_tuner)) {
ret = v4l2_subdev_call(dev->v4l2_subdev, tuner, g_tuner, v);
} else if (v->index == 1) {
- strlcpy(v->name, "RF: <unknown>", sizeof(v->name));
+ strscpy(v->name, "RF: <unknown>", sizeof(v->name));
v->type = V4L2_TUNER_RF;
v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
v->rangelow = 50000000;
@@ -1133,7 +1133,7 @@ static int rtl2832_sdr_enum_fmt_sdr_cap(struct file *file, void *priv,
if (f->index >= dev->num_formats)
return -EINVAL;
- strlcpy(f->description, formats[f->index].name, sizeof(f->description));
+ strscpy(f->description, formats[f->index].name, sizeof(f->description));
f->pixelformat = formats[f->index].pixelformat;
return 0;
@@ -1394,7 +1394,8 @@ static int rtl2832_sdr_probe(struct platform_device *pdev)
case RTL2832_SDR_TUNER_E4000:
v4l2_ctrl_handler_init(&dev->hdl, 9);
if (subdev)
- v4l2_ctrl_add_handler(&dev->hdl, subdev->ctrl_handler, NULL);
+ v4l2_ctrl_add_handler(&dev->hdl, subdev->ctrl_handler,
+ NULL, true);
break;
case RTL2832_SDR_TUNER_R820T:
case RTL2832_SDR_TUNER_R828D:
@@ -1423,7 +1424,7 @@ static int rtl2832_sdr_probe(struct platform_device *pdev)
v4l2_ctrl_handler_init(&dev->hdl, 2);
if (subdev)
v4l2_ctrl_add_handler(&dev->hdl, subdev->ctrl_handler,
- NULL);
+ NULL, true);
break;
default:
v4l2_ctrl_handler_init(&dev->hdl, 0);
diff --git a/drivers/media/dvb-frontends/s5h1420.c b/drivers/media/dvb-frontends/s5h1420.c
index a65cdf8e8cd9..c63b56f7fc14 100644
--- a/drivers/media/dvb-frontends/s5h1420.c
+++ b/drivers/media/dvb-frontends/s5h1420.c
@@ -912,7 +912,7 @@ struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config,
state->frontend.demodulator_priv = state;
/* create tuner i2c adapter */
- strlcpy(state->tuner_i2c_adapter.name, "S5H1420-PN1010 tuner I2C bus",
+ strscpy(state->tuner_i2c_adapter.name, "S5H1420-PN1010 tuner I2C bus",
sizeof(state->tuner_i2c_adapter.name));
state->tuner_i2c_adapter.algo = &s5h1420_tuner_i2c_algo;
state->tuner_i2c_adapter.algo_data = NULL;
diff --git a/drivers/media/dvb-frontends/stv0910.c b/drivers/media/dvb-frontends/stv0910.c
index 4c86073f1a8d..fc2440d8af36 100644
--- a/drivers/media/dvb-frontends/stv0910.c
+++ b/drivers/media/dvb-frontends/stv0910.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Driver for the ST STV0910 DVB-S/S2 demodulator.
*
@@ -1839,4 +1840,4 @@ EXPORT_SYMBOL_GPL(stv0910_attach);
MODULE_DESCRIPTION("ST STV0910 multistandard frontend driver");
MODULE_AUTHOR("Ralph and Marcus Metzler, Manfred Voelkel");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/dvb-frontends/stv0910.h b/drivers/media/dvb-frontends/stv0910.h
index f37171b7a2de..24ecc6902235 100644
--- a/drivers/media/dvb-frontends/stv0910.h
+++ b/drivers/media/dvb-frontends/stv0910.h
@@ -1,3 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Driver for the ST STV0910 DVB-S/S2 demodulator.
+ *
+ * Copyright (C) 2014-2015 Ralph Metzler <rjkm@metzlerbros.de>
+ * Marcus Metzler <mocm@metzlerbros.de>
+ * developed for Digital Devices GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
#ifndef _STV0910_H_
#define _STV0910_H_
diff --git a/drivers/media/dvb-frontends/stv0910_regs.h b/drivers/media/dvb-frontends/stv0910_regs.h
index f0eb915090bd..448c89b8cd7c 100644
--- a/drivers/media/dvb-frontends/stv0910_regs.h
+++ b/drivers/media/dvb-frontends/stv0910_regs.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* @DVB-S/DVB-S2 STMicroelectronics STV0900 register definitions
* Author Manfred Voelkel, August 2013
diff --git a/drivers/media/dvb-frontends/stv6111.c b/drivers/media/dvb-frontends/stv6111.c
index 0cf460111acb..d5035dac4574 100644
--- a/drivers/media/dvb-frontends/stv6111.c
+++ b/drivers/media/dvb-frontends/stv6111.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Driver for the ST STV6111 tuner
*
@@ -11,7 +12,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
*/
#include <linux/kernel.h>
@@ -687,4 +687,4 @@ EXPORT_SYMBOL_GPL(stv6111_attach);
MODULE_DESCRIPTION("ST STV6111 satellite tuner driver");
MODULE_AUTHOR("Ralph Metzler, Manfred Voelkel");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/dvb-frontends/stv6111.h b/drivers/media/dvb-frontends/stv6111.h
index 5bc1228dc9bd..49e821ac9954 100644
--- a/drivers/media/dvb-frontends/stv6111.h
+++ b/drivers/media/dvb-frontends/stv6111.h
@@ -1,3 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Driver for the ST STV6111 tuner
+ *
+ * Copyright (C) 2014 Digital Devices GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
#ifndef _STV6111_H_
#define _STV6111_H_
diff --git a/drivers/media/dvb-frontends/tc90522.c b/drivers/media/dvb-frontends/tc90522.c
index 2ad81a438d6a..849d63dbc279 100644
--- a/drivers/media/dvb-frontends/tc90522.c
+++ b/drivers/media/dvb-frontends/tc90522.c
@@ -781,7 +781,7 @@ static int tc90522_probe(struct i2c_client *client,
adap->owner = THIS_MODULE;
adap->algo = &tc90522_tuner_i2c_algo;
adap->dev.parent = &client->dev;
- strlcpy(adap->name, "tc90522_sub", sizeof(adap->name));
+ strscpy(adap->name, "tc90522_sub", sizeof(adap->name));
i2c_set_adapdata(adap, state);
ret = i2c_add_adapter(adap);
if (ret < 0)
diff --git a/drivers/media/dvb-frontends/ts2020.c b/drivers/media/dvb-frontends/ts2020.c
index 3e3e40878633..e5cd2cd414f4 100644
--- a/drivers/media/dvb-frontends/ts2020.c
+++ b/drivers/media/dvb-frontends/ts2020.c
@@ -525,7 +525,7 @@ struct dvb_frontend *ts2020_attach(struct dvb_frontend *fe,
pdata.attach_in_use = true;
memset(&board_info, 0, sizeof(board_info));
- strlcpy(board_info.type, "ts2020", I2C_NAME_SIZE);
+ strscpy(board_info.type, "ts2020", I2C_NAME_SIZE);
board_info.addr = config->tuner_address;
board_info.platform_data = &pdata;
client = i2c_new_device(i2c, &board_info);
diff --git a/drivers/media/dvb-frontends/zd1301_demod.c b/drivers/media/dvb-frontends/zd1301_demod.c
index 84a2b25a574a..212f9328cea8 100644
--- a/drivers/media/dvb-frontends/zd1301_demod.c
+++ b/drivers/media/dvb-frontends/zd1301_demod.c
@@ -499,7 +499,8 @@ static int zd1301_demod_probe(struct platform_device *pdev)
goto err_kfree;
/* Create I2C adapter */
- strlcpy(dev->adapter.name, "ZyDAS ZD1301 demod", sizeof(dev->adapter.name));
+ strscpy(dev->adapter.name, "ZyDAS ZD1301 demod",
+ sizeof(dev->adapter.name));
dev->adapter.algo = &zd1301_demod_i2c_algorithm;
dev->adapter.algo_data = NULL;
dev->adapter.dev.parent = pdev->dev.parent;
diff --git a/drivers/media/dvb-frontends/zl10039.c b/drivers/media/dvb-frontends/zl10039.c
index 6293bd920fa6..333e4a1da13b 100644
--- a/drivers/media/dvb-frontends/zl10039.c
+++ b/drivers/media/dvb-frontends/zl10039.c
@@ -288,8 +288,9 @@ struct dvb_frontend *zl10039_attach(struct dvb_frontend *fe,
state->id = state->id & 0x0f;
switch (state->id) {
case ID_ZL10039:
- strcpy(fe->ops.tuner_ops.info.name,
- "Zarlink ZL10039 DVB-S tuner");
+ strscpy(fe->ops.tuner_ops.info.name,
+ "Zarlink ZL10039 DVB-S tuner",
+ sizeof(fe->ops.tuner_ops.info.name));
break;
default:
dprintk("Chip ID=%x does not match a known type\n", state->id);
diff --git a/drivers/media/firewire/firedtv-fe.c b/drivers/media/firewire/firedtv-fe.c
index 69087ae6c1d0..683957885ac4 100644
--- a/drivers/media/firewire/firedtv-fe.c
+++ b/drivers/media/firewire/firedtv-fe.c
@@ -247,7 +247,7 @@ void fdtv_frontend_init(struct firedtv *fdtv, const char *name)
dev_err(fdtv->device, "no frontend for model type %d\n",
fdtv->type);
}
- strcpy(fi->name, name);
+ strscpy(fi->name, name, sizeof(fi->name));
fdtv->fe.dvb = &fdtv->adapter;
fdtv->fe.sec_priv = fdtv;
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 82af97430e5b..704af210e270 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -614,6 +614,28 @@ config VIDEO_IMX274
This is a V4L2 sensor driver for the Sony IMX274
CMOS image sensor.
+config VIDEO_IMX319
+ tristate "Sony IMX319 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
+ IMX319 camera.
+
+ To compile this driver as a module, choose M here: the
+ module will be called imx319.
+
+config VIDEO_IMX355
+ tristate "Sony IMX355 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
+ IMX355 camera.
+
+ To compile this driver as a module, choose M here: the
+ module will be called imx355.
+
config VIDEO_OV2640
tristate "OmniVision OV2640 sensor support"
depends on VIDEO_V4L2 && I2C
@@ -747,6 +769,7 @@ config VIDEO_OV772X
tristate "OmniVision OV772x sensor support"
depends on I2C && VIDEO_V4L2
depends on MEDIA_CAMERA_SUPPORT
+ select REGMAP_SCCB
---help---
This is a Video4Linux2 sensor driver for the OmniVision
OV772x camera.
@@ -786,6 +809,7 @@ config VIDEO_OV7740
config VIDEO_OV9650
tristate "OmniVision OV9650/OV9652 sensor support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+ select REGMAP_SCCB
---help---
This is a V4L2 sensor driver for the Omnivision
OV9650 and OV9652 camera sensors.
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index a94eb03d10d4..260d4d9ec2a1 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -108,5 +108,7 @@ obj-$(CONFIG_VIDEO_OV2659) += ov2659.o
obj-$(CONFIG_VIDEO_TC358743) += tc358743.o
obj-$(CONFIG_VIDEO_IMX258) += imx258.o
obj-$(CONFIG_VIDEO_IMX274) += imx274.o
+obj-$(CONFIG_VIDEO_IMX319) += imx319.o
+obj-$(CONFIG_VIDEO_IMX355) += imx355.o
obj-$(CONFIG_SDR_MAX2175) += max2175.o
diff --git a/drivers/media/i2c/ad5820.c b/drivers/media/i2c/ad5820.c
index 034ebf754007..907323f0ca3b 100644
--- a/drivers/media/i2c/ad5820.c
+++ b/drivers/media/i2c/ad5820.c
@@ -317,7 +317,7 @@ static int ad5820_probe(struct i2c_client *client,
v4l2_i2c_subdev_init(&coil->subdev, client, &ad5820_ops);
coil->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
coil->subdev.internal_ops = &ad5820_internal_ops;
- strcpy(coil->subdev.name, "ad5820 focus");
+ strscpy(coil->subdev.name, "ad5820 focus", sizeof(coil->subdev.name));
ret = media_entity_pads_init(&coil->subdev.entity, 0, NULL);
if (ret < 0)
diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index de10367d550b..99697baad2ea 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -1,19 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* adv7180.c Analog Devices ADV7180 video decoder driver
* Copyright (c) 2009 Intel Corporation
* Copyright (C) 2013 Cogent Embedded, Inc.
* Copyright (C) 2013 Renesas Solutions Corp.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
-
#include <linux/module.h>
#include <linux/init.h>
#include <linux/errno.h>
@@ -761,7 +752,7 @@ static int adv7180_g_mbus_config(struct v4l2_subdev *sd,
struct adv7180_state *state = to_state(sd);
if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
- cfg->type = V4L2_MBUS_CSI2;
+ cfg->type = V4L2_MBUS_CSI2_DPHY;
cfg->flags = V4L2_MBUS_CSI2_1_LANE |
V4L2_MBUS_CSI2_CHANNEL_0 |
V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
diff --git a/drivers/media/i2c/adv748x/adv748x-afe.c b/drivers/media/i2c/adv748x/adv748x-afe.c
index edd25e895e5d..71714634efb0 100644
--- a/drivers/media/i2c/adv748x/adv748x-afe.c
+++ b/drivers/media/i2c/adv748x/adv748x-afe.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Driver for Analog Devices ADV748X 8 channel analog front end (AFE) receiver
* with standard definition processor (SDP)
*
* Copyright (C) 2017 Renesas Electronics Corp.
- *
- * 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.
*/
#include <linux/delay.h>
@@ -286,7 +282,7 @@ static int adv748x_afe_s_stream(struct v4l2_subdev *sd, int enable)
goto unlock;
}
- ret = adv748x_txb_power(state, enable);
+ ret = adv748x_tx_power(&state->txb, enable);
if (ret)
goto unlock;
diff --git a/drivers/media/i2c/adv748x/adv748x-core.c b/drivers/media/i2c/adv748x/adv748x-core.c
index 6ca88daa0ecd..6854d898fdd1 100644
--- a/drivers/media/i2c/adv748x/adv748x-core.c
+++ b/drivers/media/i2c/adv748x/adv748x-core.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Driver for Analog Devices ADV748X HDMI receiver with AFE
*
* Copyright (C) 2017 Renesas Electronics Corp.
*
- * 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.
- *
* Authors:
* Koji Matsuoka <koji.matsuoka.xm@renesas.com>
* Niklas Söderlund <niklas.soderlund@ragnatech.se>
@@ -285,40 +281,23 @@ static const struct adv748x_reg_value adv748x_power_down_txb_1lane[] = {
{ADV748X_PAGE_TXB, 0x31, 0x82}, /* ADI Required Write */
{ADV748X_PAGE_TXB, 0x1e, 0x00}, /* ADI Required Write */
- {ADV748X_PAGE_TXB, 0x00, 0x81}, /* Enable 4-lane MIPI */
+ {ADV748X_PAGE_TXB, 0x00, 0x81}, /* Enable 1-lane MIPI */
{ADV748X_PAGE_TXB, 0xda, 0x01}, /* i2c_mipi_pll_en - 1'b1 */
{ADV748X_PAGE_TXB, 0xc1, 0x3b}, /* ADI Required Write */
{ADV748X_PAGE_EOR, 0xff, 0xff} /* End of register table */
};
-int adv748x_txa_power(struct adv748x_state *state, bool on)
+int adv748x_tx_power(struct adv748x_csi2 *tx, bool on)
{
+ struct adv748x_state *state = tx->state;
+ const struct adv748x_reg_value *reglist;
int val;
- val = txa_read(state, ADV748X_CSI_FS_AS_LS);
- if (val < 0)
- return val;
-
- /*
- * This test against BIT(6) is not documented by the datasheet, but was
- * specified in the downstream driver.
- * Track with a WARN_ONCE to determine if it is ever set by HW.
- */
- WARN_ONCE((on && val & ADV748X_CSI_FS_AS_LS_UNKNOWN),
- "Enabling with unknown bit set");
+ if (!is_tx_enabled(tx))
+ return 0;
- if (on)
- return adv748x_write_regs(state, adv748x_power_up_txa_4lane);
-
- return adv748x_write_regs(state, adv748x_power_down_txa_4lane);
-}
-
-int adv748x_txb_power(struct adv748x_state *state, bool on)
-{
- int val;
-
- val = txb_read(state, ADV748X_CSI_FS_AS_LS);
+ val = tx_read(tx, ADV748X_CSI_FS_AS_LS);
if (val < 0)
return val;
@@ -331,9 +310,13 @@ int adv748x_txb_power(struct adv748x_state *state, bool on)
"Enabling with unknown bit set");
if (on)
- return adv748x_write_regs(state, adv748x_power_up_txb_1lane);
+ reglist = is_txa(tx) ? adv748x_power_up_txa_4lane :
+ adv748x_power_up_txb_1lane;
+ else
+ reglist = is_txa(tx) ? adv748x_power_down_txa_4lane :
+ adv748x_power_down_txb_1lane;
- return adv748x_write_regs(state, adv748x_power_down_txb_1lane);
+ return adv748x_write_regs(state, reglist);
}
/* -----------------------------------------------------------------------------
@@ -399,8 +382,6 @@ static const struct adv748x_reg_value adv748x_init_txa_4lane[] = {
{ADV748X_PAGE_IO, 0x0c, 0xe0}, /* Enable LLC_DLL & Double LLC Timing */
{ADV748X_PAGE_IO, 0x0e, 0xdd}, /* LLC/PIX/SPI PINS TRISTATED AUD */
- /* Outputs Enabled */
- {ADV748X_PAGE_IO, 0x10, 0xa0}, /* Enable 4-lane CSI Tx & Pixel Port */
{ADV748X_PAGE_TXA, 0x00, 0x84}, /* Enable 4-lane MIPI */
{ADV748X_PAGE_TXA, 0x00, 0xa4}, /* Set Auto DPHY Timing */
@@ -454,10 +435,6 @@ static const struct adv748x_reg_value adv748x_init_txb_1lane[] = {
{ADV748X_PAGE_SDP, 0x31, 0x12}, /* ADI Required Write */
{ADV748X_PAGE_SDP, 0xe6, 0x4f}, /* V bit end pos manually in NTSC */
- /* Enable 1-Lane MIPI Tx, */
- /* enable pixel output and route SD through Pixel port */
- {ADV748X_PAGE_IO, 0x10, 0x70},
-
{ADV748X_PAGE_TXB, 0x00, 0x81}, /* Enable 1-lane MIPI */
{ADV748X_PAGE_TXB, 0x00, 0xa1}, /* Set Auto DPHY Timing */
{ADV748X_PAGE_TXB, 0xd2, 0x40}, /* ADI Required Write */
@@ -482,6 +459,7 @@ static const struct adv748x_reg_value adv748x_init_txb_1lane[] = {
static int adv748x_reset(struct adv748x_state *state)
{
int ret;
+ u8 regval = 0;
ret = adv748x_write_regs(state, adv748x_sw_reset);
if (ret < 0)
@@ -496,22 +474,24 @@ static int adv748x_reset(struct adv748x_state *state)
if (ret)
return ret;
- adv748x_txa_power(state, 0);
+ adv748x_tx_power(&state->txa, 0);
/* Init and power down TXB */
ret = adv748x_write_regs(state, adv748x_init_txb_1lane);
if (ret)
return ret;
- adv748x_txb_power(state, 0);
+ adv748x_tx_power(&state->txb, 0);
/* Disable chip powerdown & Enable HDMI Rx block */
io_write(state, ADV748X_IO_PD, ADV748X_IO_PD_RX_EN);
- /* Enable 4-lane CSI Tx & Pixel Port */
- io_write(state, ADV748X_IO_10, ADV748X_IO_10_CSI4_EN |
- ADV748X_IO_10_CSI1_EN |
- ADV748X_IO_10_PIX_OUT_EN);
+ /* Conditionally enable TXa and TXb. */
+ if (is_tx_enabled(&state->txa))
+ regval |= ADV748X_IO_10_CSI4_EN;
+ if (is_tx_enabled(&state->txb))
+ regval |= ADV748X_IO_10_CSI1_EN;
+ io_write(state, ADV748X_IO_10, regval);
/* Use vid_std and v_freq as freerun resolution for CP */
cp_clrset(state, ADV748X_CP_CLMP_POS, ADV748X_CP_CLMP_POS_DIS_AUTO,
@@ -569,7 +549,8 @@ static int adv748x_parse_dt(struct adv748x_state *state)
{
struct device_node *ep_np = NULL;
struct of_endpoint ep;
- bool found = false;
+ bool out_found = false;
+ bool in_found = false;
for_each_endpoint_of_node(state->dev->of_node, ep_np) {
of_graph_parse_endpoint(ep_np, &ep);
@@ -592,10 +573,17 @@ static int adv748x_parse_dt(struct adv748x_state *state)
of_node_get(ep_np);
state->endpoints[ep.port] = ep_np;
- found = true;
+ /*
+ * At least one input endpoint and one output endpoint shall
+ * be defined.
+ */
+ if (ep.port < ADV748X_PORT_TXA)
+ in_found = true;
+ else
+ out_found = true;
}
- return found ? 0 : -ENODEV;
+ return in_found && out_found ? 0 : -ENODEV;
}
static void adv748x_dt_cleanup(struct adv748x_state *state)
@@ -627,6 +615,17 @@ static int adv748x_probe(struct i2c_client *client,
state->i2c_clients[ADV748X_PAGE_IO] = client;
i2c_set_clientdata(client, state);
+ /*
+ * We can not use container_of to get back to the state with two TXs;
+ * Initialize the TXs's fields unconditionally on the endpoint
+ * presence to access them later.
+ */
+ state->txa.state = state->txb.state = state;
+ state->txa.page = ADV748X_PAGE_TXA;
+ state->txb.page = ADV748X_PAGE_TXB;
+ state->txa.port = ADV748X_PORT_TXA;
+ state->txb.port = ADV748X_PORT_TXB;
+
/* Discover and process ports declared by the Device tree endpoints */
ret = adv748x_parse_dt(state);
if (ret) {
@@ -755,4 +754,4 @@ module_i2c_driver(adv748x_driver);
MODULE_AUTHOR("Kieran Bingham <kieran.bingham@ideasonboard.com>");
MODULE_DESCRIPTION("ADV748X video decoder");
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c
index 469be87a3761..6ce21542ed48 100644
--- a/drivers/media/i2c/adv748x/adv748x-csi2.c
+++ b/drivers/media/i2c/adv748x/adv748x-csi2.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Driver for Analog Devices ADV748X CSI-2 Transmitter
*
* Copyright (C) 2017 Renesas Electronics Corp.
- *
- * 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.
*/
#include <linux/module.h>
@@ -18,11 +14,6 @@
#include "adv748x.h"
-static bool is_txa(struct adv748x_csi2 *tx)
-{
- return tx == &tx->state->txa;
-}
-
static int adv748x_csi2_set_virtual_channel(struct adv748x_csi2 *tx,
unsigned int vc)
{
@@ -87,15 +78,15 @@ static int adv748x_csi2_registered(struct v4l2_subdev *sd)
*
* Link HDMI->TXA, and AFE->TXB directly.
*/
- if (is_txa(tx)) {
+ if (is_txa(tx) && is_hdmi_enabled(state))
return adv748x_csi2_register_link(tx, sd->v4l2_dev,
&state->hdmi.sd,
ADV748X_HDMI_SOURCE);
- } else {
+ if (!is_txa(tx) && is_afe_enabled(state))
return adv748x_csi2_register_link(tx, sd->v4l2_dev,
&state->afe.sd,
ADV748X_AFE_SOURCE);
- }
+ return 0;
}
static const struct v4l2_subdev_internal_ops adv748x_csi2_internal_ops = {
@@ -266,19 +257,10 @@ static int adv748x_csi2_init_controls(struct adv748x_csi2 *tx)
int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx)
{
- struct device_node *ep;
int ret;
- /* We can not use container_of to get back to the state with two TXs */
- tx->state = state;
- tx->page = is_txa(tx) ? ADV748X_PAGE_TXA : ADV748X_PAGE_TXB;
-
- ep = state->endpoints[is_txa(tx) ? ADV748X_PORT_TXA : ADV748X_PORT_TXB];
- if (!ep) {
- adv_err(state, "No endpoint found for %s\n",
- is_txa(tx) ? "txa" : "txb");
- return -ENODEV;
- }
+ if (!is_tx_enabled(tx))
+ return 0;
/* Initialise the virtual channel */
adv748x_csi2_set_virtual_channel(tx, 0);
@@ -288,7 +270,7 @@ int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx)
is_txa(tx) ? "txa" : "txb");
/* Ensure that matching is based upon the endpoint fwnodes */
- tx->sd.fwnode = of_fwnode_handle(ep);
+ tx->sd.fwnode = of_fwnode_handle(state->endpoints[tx->port]);
/* Register internal ops for incremental subdev registration */
tx->sd.internal_ops = &adv748x_csi2_internal_ops;
@@ -321,6 +303,9 @@ err_free_media:
void adv748x_csi2_cleanup(struct adv748x_csi2 *tx)
{
+ if (!is_tx_enabled(tx))
+ return;
+
v4l2_async_unregister_subdev(&tx->sd);
media_entity_cleanup(&tx->sd.entity);
v4l2_ctrl_handler_free(&tx->ctrl_hdl);
diff --git a/drivers/media/i2c/adv748x/adv748x-hdmi.c b/drivers/media/i2c/adv748x/adv748x-hdmi.c
index aecc2a84dfec..35d027941482 100644
--- a/drivers/media/i2c/adv748x/adv748x-hdmi.c
+++ b/drivers/media/i2c/adv748x/adv748x-hdmi.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Driver for Analog Devices ADV748X HDMI receiver and Component Processor (CP)
*
* Copyright (C) 2017 Renesas Electronics Corp.
- *
- * 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.
*/
#include <linux/module.h>
@@ -362,7 +358,7 @@ static int adv748x_hdmi_s_stream(struct v4l2_subdev *sd, int enable)
mutex_lock(&state->mutex);
- ret = adv748x_txa_power(state, enable);
+ ret = adv748x_tx_power(&state->txa, enable);
if (ret)
goto done;
diff --git a/drivers/media/i2c/adv748x/adv748x.h b/drivers/media/i2c/adv748x/adv748x.h
index 65f83741277e..39c2fdc3b416 100644
--- a/drivers/media/i2c/adv748x/adv748x.h
+++ b/drivers/media/i2c/adv748x/adv748x.h
@@ -1,13 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Driver for Analog Devices ADV748X video decoder and HDMI receiver
*
* Copyright (C) 2017 Renesas Electronics Corp.
*
- * 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.
- *
* Authors:
* Koji Matsuoka <koji.matsuoka.xm@renesas.com>
* Niklas Söderlund <niklas.soderlund@ragnatech.se>
@@ -82,6 +78,7 @@ struct adv748x_csi2 {
struct adv748x_state *state;
struct v4l2_mbus_framefmt format;
unsigned int page;
+ unsigned int port;
struct media_pad pads[ADV748X_CSI2_NR_PADS];
struct v4l2_ctrl_handler ctrl_hdl;
@@ -91,6 +88,18 @@ struct adv748x_csi2 {
#define notifier_to_csi2(n) container_of(n, struct adv748x_csi2, notifier)
#define adv748x_sd_to_csi2(sd) container_of(sd, struct adv748x_csi2, sd)
+#define is_tx_enabled(_tx) ((_tx)->state->endpoints[(_tx)->port] != NULL)
+#define is_txa(_tx) ((_tx) == &(_tx)->state->txa)
+#define is_afe_enabled(_state) \
+ ((_state)->endpoints[ADV748X_PORT_AIN0] != NULL || \
+ (_state)->endpoints[ADV748X_PORT_AIN1] != NULL || \
+ (_state)->endpoints[ADV748X_PORT_AIN2] != NULL || \
+ (_state)->endpoints[ADV748X_PORT_AIN3] != NULL || \
+ (_state)->endpoints[ADV748X_PORT_AIN4] != NULL || \
+ (_state)->endpoints[ADV748X_PORT_AIN5] != NULL || \
+ (_state)->endpoints[ADV748X_PORT_AIN6] != NULL || \
+ (_state)->endpoints[ADV748X_PORT_AIN7] != NULL)
+#define is_hdmi_enabled(_state) ((_state)->endpoints[ADV748X_PORT_HDMI] != NULL)
enum adv748x_hdmi_pads {
ADV748X_HDMI_SINK,
@@ -376,9 +385,6 @@ int adv748x_write_block(struct adv748x_state *state, int client_page,
#define cp_write(s, r, v) adv748x_write(s, ADV748X_PAGE_CP, r, v)
#define cp_clrset(s, r, m, v) cp_write(s, r, (cp_read(s, r) & ~m) | v)
-#define txa_read(s, r) adv748x_read(s, ADV748X_PAGE_TXA, r)
-#define txb_read(s, r) adv748x_read(s, ADV748X_PAGE_TXB, r)
-
#define tx_read(t, r) adv748x_read(t->state, t->page, r)
#define tx_write(t, r, v) adv748x_write(t->state, t->page, r, v)
@@ -398,8 +404,7 @@ void adv748x_subdev_init(struct v4l2_subdev *sd, struct adv748x_state *state,
int adv748x_register_subdevs(struct adv748x_state *state,
struct v4l2_device *v4l2_dev);
-int adv748x_txa_power(struct adv748x_state *state, bool on);
-int adv748x_txb_power(struct adv748x_state *state, bool on);
+int adv748x_tx_power(struct adv748x_csi2 *tx, bool on);
int adv748x_afe_init(struct adv748x_afe *afe);
void adv748x_afe_cleanup(struct adv748x_afe *afe);
diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c
index 55c2ea0720d9..4551bca3c127 100644
--- a/drivers/media/i2c/adv7511.c
+++ b/drivers/media/i2c/adv7511.c
@@ -550,7 +550,7 @@ static void log_infoframe(struct v4l2_subdev *sd, const struct adv7511_cfg_read_
buffer[3] = 0;
buffer[3] = hdmi_infoframe_checksum(buffer, len + 4);
- if (hdmi_infoframe_unpack(&frame, buffer) < 0) {
+ if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) {
v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc);
return;
}
@@ -1355,10 +1355,10 @@ static int adv7511_set_fmt(struct v4l2_subdev *sd,
state->xfer_func = format->format.xfer_func;
switch (format->format.colorspace) {
- case V4L2_COLORSPACE_ADOBERGB:
+ case V4L2_COLORSPACE_OPRGB:
c = HDMI_COLORIMETRY_EXTENDED;
- ec = y ? HDMI_EXTENDED_COLORIMETRY_ADOBE_YCC_601 :
- HDMI_EXTENDED_COLORIMETRY_ADOBE_RGB;
+ ec = y ? HDMI_EXTENDED_COLORIMETRY_OPYCC_601 :
+ HDMI_EXTENDED_COLORIMETRY_OPRGB;
break;
case V4L2_COLORSPACE_SMPTE170M:
c = y ? HDMI_COLORIMETRY_ITU_601 : HDMI_COLORIMETRY_NONE;
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index 668be2bca57a..9f99ef38bcca 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -2284,8 +2284,10 @@ static int adv76xx_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
state->aspect_ratio.numerator = 16;
state->aspect_ratio.denominator = 9;
- if (!state->edid.present)
+ if (!state->edid.present) {
state->edid.blocks = 0;
+ cec_phys_addr_invalidate(state->cec_adap);
+ }
v4l2_dbg(2, debug, sd, "%s: clear EDID pad %d, edid.present = 0x%x\n",
__func__, edid->pad, state->edid.present);
@@ -2295,8 +2297,8 @@ static int adv76xx_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
edid->blocks = 2;
return -E2BIG;
}
- pa = cec_get_edid_phys_addr(edid->edid, edid->blocks * 128, &spa_loc);
- err = cec_phys_addr_validate(pa, &pa, NULL);
+ pa = v4l2_get_edid_phys_addr(edid->edid, edid->blocks * 128, &spa_loc);
+ err = v4l2_phys_addr_validate(pa, &pa, NULL);
if (err)
return err;
@@ -2418,7 +2420,7 @@ static int adv76xx_read_infoframe(struct v4l2_subdev *sd, int index,
buffer[i + 3] = infoframe_read(sd,
adv76xx_cri[index].payload_addr + i);
- if (hdmi_infoframe_unpack(frame, buffer) < 0) {
+ if (hdmi_infoframe_unpack(frame, buffer, sizeof(buffer)) < 0) {
v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__,
adv76xx_cri[index].desc);
return -ENOENT;
@@ -2474,7 +2476,7 @@ static int adv76xx_log_status(struct v4l2_subdev *sd)
"YCbCr Bt.601 (16-235)", "YCbCr Bt.709 (16-235)",
"xvYCC Bt.601", "xvYCC Bt.709",
"YCbCr Bt.601 (0-255)", "YCbCr Bt.709 (0-255)",
- "sYCC", "Adobe YCC 601", "AdobeRGB", "invalid", "invalid",
+ "sYCC", "opYCC 601", "opRGB", "invalid", "invalid",
"invalid", "invalid", "invalid"
};
static const char * const rgb_quantization_range_txt[] = {
@@ -3093,7 +3095,7 @@ MODULE_DEVICE_TABLE(of, adv76xx_of_id);
static int adv76xx_parse_dt(struct adv76xx_state *state)
{
- struct v4l2_fwnode_endpoint bus_cfg;
+ struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 };
struct device_node *endpoint;
struct device_node *np;
unsigned int flags;
diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c
index 4f8fbdd00e35..0e6384f2016a 100644
--- a/drivers/media/i2c/adv7842.c
+++ b/drivers/media/i2c/adv7842.c
@@ -786,11 +786,13 @@ static int edid_write_hdmi_segment(struct v4l2_subdev *sd, u8 port)
/* Disable I2C access to internal EDID ram from HDMI DDC ports */
rep_write_and_or(sd, 0x77, 0xf3, 0x00);
- if (!state->hdmi_edid.present)
+ if (!state->hdmi_edid.present) {
+ cec_phys_addr_invalidate(state->cec_adap);
return 0;
+ }
- pa = cec_get_edid_phys_addr(edid, 256, &spa_loc);
- err = cec_phys_addr_validate(pa, &pa, NULL);
+ pa = v4l2_get_edid_phys_addr(edid, 256, &spa_loc);
+ err = v4l2_phys_addr_validate(pa, &pa, NULL);
if (err)
return err;
@@ -1525,6 +1527,7 @@ static void adv7842_fill_optional_dv_timings_fields(struct v4l2_subdev *sd,
v4l2_find_dv_timings_cap(timings, adv7842_get_dv_timings_cap(sd),
is_digital_input(sd) ? 250000 : 1000000,
adv7842_check_dv_timings, NULL);
+ timings->bt.flags |= V4L2_DV_FL_CAN_DETECT_REDUCED_FPS;
}
static int adv7842_query_dv_timings(struct v4l2_subdev *sd,
@@ -1596,6 +1599,14 @@ static int adv7842_query_dv_timings(struct v4l2_subdev *sd,
bt->il_vbackporch = 0;
}
adv7842_fill_optional_dv_timings_fields(sd, timings);
+ if ((timings->bt.flags & V4L2_DV_FL_CAN_REDUCE_FPS) &&
+ freq < bt->pixelclock) {
+ u32 reduced_freq = ((u32)bt->pixelclock / 1001) * 1000;
+ u32 delta_freq = abs(freq - reduced_freq);
+
+ if (delta_freq < ((u32)bt->pixelclock - reduced_freq) / 2)
+ timings->bt.flags |= V4L2_DV_FL_REDUCED_FPS;
+ }
} else {
/* find format
* Since LCVS values are inaccurate [REF_03, p. 339-340],
@@ -2563,7 +2574,7 @@ static void log_infoframe(struct v4l2_subdev *sd, struct adv7842_cfg_read_infofr
for (i = 0; i < len; i++)
buffer[i + 3] = infoframe_read(sd, cri->payload_addr + i);
- if (hdmi_infoframe_unpack(&frame, buffer) < 0) {
+ if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) {
v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc);
return;
}
diff --git a/drivers/media/i2c/ak881x.c b/drivers/media/i2c/ak881x.c
index 16682c8477d1..30f9db1351b9 100644
--- a/drivers/media/i2c/ak881x.c
+++ b/drivers/media/i2c/ak881x.c
@@ -136,7 +136,6 @@ static int ak881x_get_selection(struct v4l2_subdev *sd,
switch (sel->target) {
case V4L2_SEL_TGT_CROP_BOUNDS:
- case V4L2_SEL_TGT_CROP_DEFAULT:
sel->r.left = 0;
sel->r.top = 0;
sel->r.width = 720;
diff --git a/drivers/media/i2c/cs53l32a.c b/drivers/media/i2c/cs53l32a.c
index fd70fe2130a1..ef4bdbae4531 100644
--- a/drivers/media/i2c/cs53l32a.c
+++ b/drivers/media/i2c/cs53l32a.c
@@ -149,7 +149,7 @@ static int cs53l32a_probe(struct i2c_client *client,
return -EIO;
if (!id)
- strlcpy(client->name, "cs53l32a", sizeof(client->name));
+ strscpy(client->name, "cs53l32a", sizeof(client->name));
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
diff --git a/drivers/media/i2c/cx25840/cx25840-ir.c b/drivers/media/i2c/cx25840/cx25840-ir.c
index ad7f66c7aac8..69cdc09981af 100644
--- a/drivers/media/i2c/cx25840/cx25840-ir.c
+++ b/drivers/media/i2c/cx25840/cx25840-ir.c
@@ -701,10 +701,8 @@ static int cx25840_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count,
if (v > IR_MAX_DURATION)
v = IR_MAX_DURATION;
- init_ir_raw_event(&p->ir_core_data);
- p->ir_core_data.pulse = u;
- p->ir_core_data.duration = v;
- p->ir_core_data.timeout = w;
+ p->ir_core_data = (struct ir_raw_event)
+ { .pulse = u, .duration = v, .timeout = w };
v4l2_dbg(2, ir_debug, sd, "rx read: %10u ns %s %s\n",
v, u ? "mark" : "space", w ? "(timed out)" : "");
diff --git a/drivers/media/i2c/dw9714.c b/drivers/media/i2c/dw9714.c
index 91fae01d052b..26d83693a681 100644
--- a/drivers/media/i2c/dw9714.c
+++ b/drivers/media/i2c/dw9714.c
@@ -169,8 +169,9 @@ static int dw9714_probe(struct i2c_client *client)
return 0;
err_cleanup:
- dw9714_subdev_cleanup(dw9714_dev);
- dev_err(&client->dev, "Probe failed: %d\n", rval);
+ v4l2_ctrl_handler_free(&dw9714_dev->ctrls_vcm);
+ media_entity_cleanup(&dw9714_dev->sd.entity);
+
return rval;
}
diff --git a/drivers/media/i2c/dw9807-vcm.c b/drivers/media/i2c/dw9807-vcm.c
index 8ba3920b6e2f..b38a4e6d270d 100644
--- a/drivers/media/i2c/dw9807-vcm.c
+++ b/drivers/media/i2c/dw9807-vcm.c
@@ -218,7 +218,8 @@ static int dw9807_probe(struct i2c_client *client)
return 0;
err_cleanup:
- dw9807_subdev_cleanup(dw9807_dev);
+ v4l2_ctrl_handler_free(&dw9807_dev->ctrls_vcm);
+ media_entity_cleanup(&dw9807_dev->sd.entity);
return rval;
}
@@ -229,7 +230,6 @@ static int dw9807_remove(struct i2c_client *client)
struct dw9807_device *dw9807_dev = sd_to_dw9807_vcm(sd);
pm_runtime_disable(&client->dev);
- pm_runtime_set_suspended(&client->dev);
dw9807_subdev_cleanup(dw9807_dev);
diff --git a/drivers/media/i2c/imx274.c b/drivers/media/i2c/imx274.c
index f8c70f1a34fe..11c69281692e 100644
--- a/drivers/media/i2c/imx274.c
+++ b/drivers/media/i2c/imx274.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* imx274.c - IMX274 CMOS Image Sensor driver
*
@@ -6,18 +7,6 @@
* Leon Luo <leonl@leopardimaging.com>
* Edwin Zou <edwinz@leopardimaging.com>
* Luca Ceresoli <luca@lucaceresoli.net>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/clk.h>
@@ -76,7 +65,7 @@
*/
#define IMX274_MIN_EXPOSURE_TIME (4 * 260 / 72)
-#define IMX274_DEFAULT_MODE IMX274_BINNING_OFF
+#define IMX274_DEFAULT_BINNING IMX274_BINNING_OFF
#define IMX274_MAX_WIDTH (3840)
#define IMX274_MAX_HEIGHT (2160)
#define IMX274_MAX_FRAME_RATE (120)
@@ -178,7 +167,7 @@ enum imx274_binning {
* @nocpiop: Number of clocks per internal offset period (see "Integration Time
* in Each Readout Drive Mode (CSI-2)" in the datasheet)
*/
-struct imx274_frmfmt {
+struct imx274_mode {
const struct reg_8 *init_regs;
unsigned int bin_ratio;
int min_frame_len;
@@ -349,20 +338,14 @@ static const struct reg_8 imx274_mode5_1280x720_raw10[] = {
*/
static const struct reg_8 imx274_start_1[] = {
{IMX274_STANDBY_REG, 0x12},
- {IMX274_TABLE_END, 0x00}
-};
-/*
- * imx274 second step register configuration for
- * starting stream
- */
-static const struct reg_8 imx274_start_2[] = {
- {0x3120, 0xF0}, /* clock settings */
- {0x3121, 0x00}, /* clock settings */
- {0x3122, 0x02}, /* clock settings */
- {0x3129, 0x9C}, /* clock settings */
- {0x312A, 0x02}, /* clock settings */
- {0x312D, 0x02}, /* clock settings */
+ /* PLRD: clock settings */
+ {0x3120, 0xF0},
+ {0x3121, 0x00},
+ {0x3122, 0x02},
+ {0x3129, 0x9C},
+ {0x312A, 0x02},
+ {0x312D, 0x02},
{0x310B, 0x00},
@@ -407,20 +390,20 @@ static const struct reg_8 imx274_start_2[] = {
};
/*
- * imx274 third step register configuration for
+ * imx274 second step register configuration for
* starting stream
*/
-static const struct reg_8 imx274_start_3[] = {
+static const struct reg_8 imx274_start_2[] = {
{IMX274_STANDBY_REG, 0x00},
{0x303E, 0x02}, /* SYS_MODE = 2 */
{IMX274_TABLE_END, 0x00}
};
/*
- * imx274 forth step register configuration for
+ * imx274 third step register configuration for
* starting stream
*/
-static const struct reg_8 imx274_start_4[] = {
+static const struct reg_8 imx274_start_3[] = {
{0x30F4, 0x00},
{0x3018, 0xA2}, /* XHS VHS OUTUPT */
{IMX274_TABLE_END, 0x00}
@@ -459,7 +442,7 @@ static const struct reg_8 imx274_tp_regs[] = {
};
/* nocpiop happens to be the same number for the implemented modes */
-static const struct imx274_frmfmt imx274_formats[] = {
+static const struct imx274_mode imx274_modes[] = {
{
/* mode 1, 4K */
.bin_ratio = 1,
@@ -532,7 +515,7 @@ struct stimx274 {
struct regmap *regmap;
struct gpio_desc *reset_gpio;
struct mutex lock; /* mutex lock for operations */
- const struct imx274_frmfmt *mode;
+ const struct imx274_mode *mode;
};
#define IMX274_ROUND(dim, step, flags) \
@@ -666,6 +649,41 @@ static inline int imx274_write_reg(struct stimx274 *priv, u16 addr, u8 val)
}
/**
+ * Read a multibyte register.
+ *
+ * Uses a bulk read where possible.
+ *
+ * @priv: Pointer to device structure
+ * @addr: Address of the LSB register. Other registers must be
+ * consecutive, least-to-most significant.
+ * @val: Pointer to store the register value (cpu endianness)
+ * @nbytes: Number of bytes to read (range: [1..3]).
+ * Other bytes are zet to 0.
+ *
+ * Return: 0 on success, errors otherwise
+ */
+static int imx274_read_mbreg(struct stimx274 *priv, u16 addr, u32 *val,
+ size_t nbytes)
+{
+ __le32 val_le = 0;
+ int err;
+
+ err = regmap_bulk_read(priv->regmap, addr, &val_le, nbytes);
+ if (err) {
+ dev_err(&priv->client->dev,
+ "%s : i2c bulk read failed, %x (%zu bytes)\n",
+ __func__, addr, nbytes);
+ } else {
+ *val = le32_to_cpu(val_le);
+ dev_dbg(&priv->client->dev,
+ "%s : addr 0x%x, val=0x%x (%zu bytes)\n",
+ __func__, addr, *val, nbytes);
+ }
+
+ return err;
+}
+
+/**
* Write a multibyte register.
*
* Uses a bulk write where possible.
@@ -674,7 +692,7 @@ static inline int imx274_write_reg(struct stimx274 *priv, u16 addr, u8 val)
* @addr: Address of the LSB register. Other registers must be
* consecutive, least-to-most significant.
* @val: Value to be written to the register (cpu endianness)
- * @nbytes: Number of bits to write (range: [1..3])
+ * @nbytes: Number of bytes to write (range: [1..3])
*/
static int imx274_write_mbreg(struct stimx274 *priv, u16 addr, u32 val,
size_t nbytes)
@@ -708,10 +726,6 @@ static int imx274_mode_regs(struct stimx274 *priv)
if (err)
return err;
- err = imx274_write_table(priv, imx274_start_2);
- if (err)
- return err;
-
err = imx274_write_table(priv, priv->mode->init_regs);
return err;
@@ -733,7 +747,7 @@ static int imx274_start_stream(struct stimx274 *priv)
* give it 1 extra ms for margin
*/
msleep_range(11);
- err = imx274_write_table(priv, imx274_start_3);
+ err = imx274_write_table(priv, imx274_start_2);
if (err)
return err;
@@ -743,7 +757,7 @@ static int imx274_start_stream(struct stimx274 *priv)
* give it 1 extra ms for margin
*/
msleep_range(8);
- err = imx274_write_table(priv, imx274_start_4);
+ err = imx274_write_table(priv, imx274_start_3);
if (err)
return err;
@@ -881,7 +895,7 @@ static int __imx274_change_compose(struct stimx274 *imx274,
const struct v4l2_rect *cur_crop;
struct v4l2_mbus_framefmt *tgt_fmt;
unsigned int i;
- const struct imx274_frmfmt *best_mode = &imx274_formats[0];
+ const struct imx274_mode *best_mode = &imx274_modes[0];
int best_goodness = INT_MIN;
if (which == V4L2_SUBDEV_FORMAT_TRY) {
@@ -892,8 +906,8 @@ static int __imx274_change_compose(struct stimx274 *imx274,
tgt_fmt = &imx274->format;
}
- for (i = 0; i < ARRAY_SIZE(imx274_formats); i++) {
- unsigned int ratio = imx274_formats[i].bin_ratio;
+ for (i = 0; i < ARRAY_SIZE(imx274_modes); i++) {
+ unsigned int ratio = imx274_modes[i].bin_ratio;
int goodness = imx274_binning_goodness(
imx274,
@@ -903,7 +917,7 @@ static int __imx274_change_compose(struct stimx274 *imx274,
if (goodness >= best_goodness) {
best_goodness = goodness;
- best_mode = &imx274_formats[i];
+ best_mode = &imx274_modes[i];
}
}
@@ -1323,7 +1337,7 @@ static int imx274_s_stream(struct v4l2_subdev *sd, int on)
dev_dbg(&imx274->client->dev, "%s : %s, mode index = %td\n", __func__,
on ? "Stream Start" : "Stream Stop",
- imx274->mode - &imx274_formats[0]);
+ imx274->mode - &imx274_modes[0]);
mutex_lock(&imx274->lock);
@@ -1387,37 +1401,17 @@ fail:
static int imx274_get_frame_length(struct stimx274 *priv, u32 *val)
{
int err;
- u16 svr;
+ u32 svr;
u32 vmax;
- u8 reg_val[3];
-
- /* svr */
- err = imx274_read_reg(priv, IMX274_SVR_REG_LSB, &reg_val[0]);
- if (err)
- goto fail;
- err = imx274_read_reg(priv, IMX274_SVR_REG_MSB, &reg_val[1]);
+ err = imx274_read_mbreg(priv, IMX274_SVR_REG_LSB, &svr, 2);
if (err)
goto fail;
- svr = (reg_val[1] << IMX274_SHIFT_8_BITS) + reg_val[0];
-
- /* vmax */
- err = imx274_read_reg(priv, IMX274_VMAX_REG_3, &reg_val[0]);
+ err = imx274_read_mbreg(priv, IMX274_VMAX_REG_3, &vmax, 3);
if (err)
goto fail;
- err = imx274_read_reg(priv, IMX274_VMAX_REG_2, &reg_val[1]);
- if (err)
- goto fail;
-
- err = imx274_read_reg(priv, IMX274_VMAX_REG_1, &reg_val[2]);
- if (err)
- goto fail;
-
- vmax = ((reg_val[2] & IMX274_MASK_LSB_3_BITS) << IMX274_SHIFT_16_BITS)
- + (reg_val[1] << IMX274_SHIFT_8_BITS) + reg_val[0];
-
*val = vmax * (svr + 1);
return 0;
@@ -1598,8 +1592,7 @@ fail:
static int imx274_set_exposure(struct stimx274 *priv, int val)
{
int err;
- u16 hmax;
- u8 reg_val[2];
+ u32 hmax;
u32 coarse_time; /* exposure time in unit of line (HMAX)*/
dev_dbg(&priv->client->dev,
@@ -1607,14 +1600,10 @@ static int imx274_set_exposure(struct stimx274 *priv, int val)
/* step 1: convert input exposure_time (val) into number of 1[HMAX] */
- /* obtain HMAX value */
- err = imx274_read_reg(priv, IMX274_HMAX_REG_LSB, &reg_val[0]);
- if (err)
- goto fail;
- err = imx274_read_reg(priv, IMX274_HMAX_REG_MSB, &reg_val[1]);
+ err = imx274_read_mbreg(priv, IMX274_HMAX_REG_LSB, &hmax, 2);
if (err)
goto fail;
- hmax = (reg_val[1] << IMX274_SHIFT_8_BITS) + reg_val[0];
+
if (hmax == 0) {
err = -EINVAL;
goto fail;
@@ -1749,9 +1738,8 @@ static int imx274_set_frame_interval(struct stimx274 *priv,
{
int err;
u32 frame_length, req_frame_rate;
- u16 svr;
- u16 hmax;
- u8 reg_val[2];
+ u32 svr;
+ u32 hmax;
dev_dbg(&priv->client->dev, "%s: input frame interval = %d / %d",
__func__, frame_interval.numerator,
@@ -1779,25 +1767,17 @@ static int imx274_set_frame_interval(struct stimx274 *priv,
* frame_length (i.e. VMAX) = (frame_interval) x 72M /(SVR+1) / HMAX
*/
- /* SVR */
- err = imx274_read_reg(priv, IMX274_SVR_REG_LSB, &reg_val[0]);
- if (err)
- goto fail;
- err = imx274_read_reg(priv, IMX274_SVR_REG_MSB, &reg_val[1]);
+ err = imx274_read_mbreg(priv, IMX274_SVR_REG_LSB, &svr, 2);
if (err)
goto fail;
- svr = (reg_val[1] << IMX274_SHIFT_8_BITS) + reg_val[0];
+
dev_dbg(&priv->client->dev,
"%s : register SVR = %d\n", __func__, svr);
- /* HMAX */
- err = imx274_read_reg(priv, IMX274_HMAX_REG_LSB, &reg_val[0]);
- if (err)
- goto fail;
- err = imx274_read_reg(priv, IMX274_HMAX_REG_MSB, &reg_val[1]);
+ err = imx274_read_mbreg(priv, IMX274_HMAX_REG_LSB, &hmax, 2);
if (err)
goto fail;
- hmax = (reg_val[1] << IMX274_SHIFT_8_BITS) + reg_val[0];
+
dev_dbg(&priv->client->dev,
"%s : register HMAX = %d\n", __func__, hmax);
@@ -1871,7 +1851,7 @@ static int imx274_probe(struct i2c_client *client,
mutex_init(&imx274->lock);
/* initialize format */
- imx274->mode = &imx274_formats[IMX274_DEFAULT_MODE];
+ imx274->mode = &imx274_modes[IMX274_DEFAULT_BINNING];
imx274->crop.width = IMX274_MAX_WIDTH;
imx274->crop.height = IMX274_MAX_HEIGHT;
imx274->format.width = imx274->crop.width / imx274->mode->bin_ratio;
@@ -1895,7 +1875,6 @@ static int imx274_probe(struct i2c_client *client,
imx274->client = client;
sd = &imx274->sd;
v4l2_i2c_subdev_init(sd, client, &imx274_subdev_ops);
- strlcpy(sd->name, DRIVER_NAME, sizeof(sd->name));
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
/* initialize subdev media pad */
diff --git a/drivers/media/i2c/imx319.c b/drivers/media/i2c/imx319.c
new file mode 100644
index 000000000000..0d3e27812b93
--- /dev/null
+++ b/drivers/media/i2c/imx319.c
@@ -0,0 +1,2560 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2018 Intel Corporation
+
+#include <asm/unaligned.h>
+#include <linux/acpi.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 <media/v4l2-event.h>
+#include <media/v4l2-fwnode.h>
+
+#define IMX319_REG_MODE_SELECT 0x0100
+#define IMX319_MODE_STANDBY 0x00
+#define IMX319_MODE_STREAMING 0x01
+
+/* Chip ID */
+#define IMX319_REG_CHIP_ID 0x0016
+#define IMX319_CHIP_ID 0x0319
+
+/* V_TIMING internal */
+#define IMX319_REG_FLL 0x0340
+#define IMX319_FLL_MAX 0xffff
+
+/* Exposure control */
+#define IMX319_REG_EXPOSURE 0x0202
+#define IMX319_EXPOSURE_MIN 1
+#define IMX319_EXPOSURE_STEP 1
+#define IMX319_EXPOSURE_DEFAULT 0x04f6
+
+/*
+ * the digital control register for all color control looks like:
+ * +-----------------+------------------+
+ * | [7:0] | [15:8] |
+ * +-----------------+------------------+
+ * | 0x020f | 0x020e |
+ * --------------------------------------
+ * it is used to calculate the digital gain times value(integral + fractional)
+ * the [15:8] bits is the fractional part and [7:0] bits is the integral
+ * calculation equation is:
+ * gain value (unit: times) = REG[15:8] + REG[7:0]/0x100
+ * Only value in 0x0100 ~ 0x0FFF range is allowed.
+ * Analog gain use 10 bits in the registers and allowed range is 0 ~ 960
+ */
+/* Analog gain control */
+#define IMX319_REG_ANALOG_GAIN 0x0204
+#define IMX319_ANA_GAIN_MIN 0
+#define IMX319_ANA_GAIN_MAX 960
+#define IMX319_ANA_GAIN_STEP 1
+#define IMX319_ANA_GAIN_DEFAULT 0
+
+/* Digital gain control */
+#define IMX319_REG_DPGA_USE_GLOBAL_GAIN 0x3ff9
+#define IMX319_REG_DIG_GAIN_GLOBAL 0x020e
+#define IMX319_DGTL_GAIN_MIN 256
+#define IMX319_DGTL_GAIN_MAX 4095
+#define IMX319_DGTL_GAIN_STEP 1
+#define IMX319_DGTL_GAIN_DEFAULT 256
+
+/* Test Pattern Control */
+#define IMX319_REG_TEST_PATTERN 0x0600
+#define IMX319_TEST_PATTERN_DISABLED 0
+#define IMX319_TEST_PATTERN_SOLID_COLOR 1
+#define IMX319_TEST_PATTERN_COLOR_BARS 2
+#define IMX319_TEST_PATTERN_GRAY_COLOR_BARS 3
+#define IMX319_TEST_PATTERN_PN9 4
+
+/* Flip Control */
+#define IMX319_REG_ORIENTATION 0x0101
+
+/* default link frequency and external clock */
+#define IMX319_LINK_FREQ_DEFAULT 482400000
+#define IMX319_EXT_CLK 19200000
+#define IMX319_LINK_FREQ_INDEX 0
+
+struct imx319_reg {
+ u16 address;
+ u8 val;
+};
+
+struct imx319_reg_list {
+ u32 num_of_regs;
+ const struct imx319_reg *regs;
+};
+
+/* Mode : resolution and related config&values */
+struct imx319_mode {
+ /* Frame width */
+ u32 width;
+ /* Frame height */
+ u32 height;
+
+ /* V-timing */
+ u32 fll_def;
+ u32 fll_min;
+
+ /* H-timing */
+ u32 llp;
+
+ /* index of link frequency */
+ u32 link_freq_index;
+
+ /* Default register values */
+ struct imx319_reg_list reg_list;
+};
+
+struct imx319_hwcfg {
+ u32 ext_clk; /* sensor external clk */
+ s64 *link_freqs; /* CSI-2 link frequencies */
+ unsigned int nr_of_link_freqs;
+};
+
+struct imx319 {
+ 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 *exposure;
+ struct v4l2_ctrl *vflip;
+ struct v4l2_ctrl *hflip;
+
+ /* Current mode */
+ const struct imx319_mode *cur_mode;
+
+ struct imx319_hwcfg *hwcfg;
+ s64 link_def_freq; /* CSI-2 link default frequency */
+
+ /*
+ * Mutex for serialized access:
+ * Protect sensor set pad format and start/stop streaming safely.
+ * Protect access to sensor v4l2 controls.
+ */
+ struct mutex mutex;
+
+ /* Streaming on/off */
+ bool streaming;
+};
+
+static const struct imx319_reg imx319_global_regs[] = {
+ { 0x0136, 0x13 },
+ { 0x0137, 0x33 },
+ { 0x3c7e, 0x05 },
+ { 0x3c7f, 0x07 },
+ { 0x4d39, 0x0b },
+ { 0x4d41, 0x33 },
+ { 0x4d43, 0x0c },
+ { 0x4d49, 0x89 },
+ { 0x4e05, 0x0b },
+ { 0x4e0d, 0x33 },
+ { 0x4e0f, 0x0c },
+ { 0x4e15, 0x89 },
+ { 0x4e49, 0x2a },
+ { 0x4e51, 0x33 },
+ { 0x4e53, 0x0c },
+ { 0x4e59, 0x89 },
+ { 0x5601, 0x4f },
+ { 0x560b, 0x45 },
+ { 0x562f, 0x0a },
+ { 0x5643, 0x0a },
+ { 0x5645, 0x0c },
+ { 0x56ef, 0x51 },
+ { 0x586f, 0x33 },
+ { 0x5873, 0x89 },
+ { 0x5905, 0x33 },
+ { 0x5907, 0x89 },
+ { 0x590d, 0x33 },
+ { 0x590f, 0x89 },
+ { 0x5915, 0x33 },
+ { 0x5917, 0x89 },
+ { 0x5969, 0x1c },
+ { 0x596b, 0x72 },
+ { 0x5971, 0x33 },
+ { 0x5973, 0x89 },
+ { 0x5975, 0x33 },
+ { 0x5977, 0x89 },
+ { 0x5979, 0x1c },
+ { 0x597b, 0x72 },
+ { 0x5985, 0x33 },
+ { 0x5987, 0x89 },
+ { 0x5999, 0x1c },
+ { 0x599b, 0x72 },
+ { 0x59a5, 0x33 },
+ { 0x59a7, 0x89 },
+ { 0x7485, 0x08 },
+ { 0x7487, 0x0c },
+ { 0x7489, 0xc7 },
+ { 0x748b, 0x8b },
+ { 0x9004, 0x09 },
+ { 0x9200, 0x6a },
+ { 0x9201, 0x22 },
+ { 0x9202, 0x6a },
+ { 0x9203, 0x23 },
+ { 0x9204, 0x5f },
+ { 0x9205, 0x23 },
+ { 0x9206, 0x5f },
+ { 0x9207, 0x24 },
+ { 0x9208, 0x5f },
+ { 0x9209, 0x26 },
+ { 0x920a, 0x5f },
+ { 0x920b, 0x27 },
+ { 0x920c, 0x5f },
+ { 0x920d, 0x29 },
+ { 0x920e, 0x5f },
+ { 0x920f, 0x2a },
+ { 0x9210, 0x5f },
+ { 0x9211, 0x2c },
+ { 0xbc22, 0x1a },
+ { 0xf01f, 0x04 },
+ { 0xf021, 0x03 },
+ { 0xf023, 0x02 },
+ { 0xf03d, 0x05 },
+ { 0xf03f, 0x03 },
+ { 0xf041, 0x02 },
+ { 0xf0af, 0x04 },
+ { 0xf0b1, 0x03 },
+ { 0xf0b3, 0x02 },
+ { 0xf0cd, 0x05 },
+ { 0xf0cf, 0x03 },
+ { 0xf0d1, 0x02 },
+ { 0xf13f, 0x04 },
+ { 0xf141, 0x03 },
+ { 0xf143, 0x02 },
+ { 0xf15d, 0x05 },
+ { 0xf15f, 0x03 },
+ { 0xf161, 0x02 },
+ { 0xf1cf, 0x04 },
+ { 0xf1d1, 0x03 },
+ { 0xf1d3, 0x02 },
+ { 0xf1ed, 0x05 },
+ { 0xf1ef, 0x03 },
+ { 0xf1f1, 0x02 },
+ { 0xf287, 0x04 },
+ { 0xf289, 0x03 },
+ { 0xf28b, 0x02 },
+ { 0xf2a5, 0x05 },
+ { 0xf2a7, 0x03 },
+ { 0xf2a9, 0x02 },
+ { 0xf2b7, 0x04 },
+ { 0xf2b9, 0x03 },
+ { 0xf2bb, 0x02 },
+ { 0xf2d5, 0x05 },
+ { 0xf2d7, 0x03 },
+ { 0xf2d9, 0x02 },
+};
+
+static const struct imx319_reg_list imx319_global_setting = {
+ .num_of_regs = ARRAY_SIZE(imx319_global_regs),
+ .regs = imx319_global_regs,
+};
+
+static const struct imx319_reg mode_3264x2448_regs[] = {
+ { 0x0112, 0x0a },
+ { 0x0113, 0x0a },
+ { 0x0114, 0x03 },
+ { 0x0342, 0x0f },
+ { 0x0343, 0x80 },
+ { 0x0340, 0x0c },
+ { 0x0341, 0xaa },
+ { 0x0344, 0x00 },
+ { 0x0345, 0x00 },
+ { 0x0346, 0x00 },
+ { 0x0347, 0x00 },
+ { 0x0348, 0x0c },
+ { 0x0349, 0xcf },
+ { 0x034a, 0x09 },
+ { 0x034b, 0x9f },
+ { 0x0220, 0x00 },
+ { 0x0221, 0x11 },
+ { 0x0381, 0x01 },
+ { 0x0383, 0x01 },
+ { 0x0385, 0x01 },
+ { 0x0387, 0x01 },
+ { 0x0900, 0x00 },
+ { 0x0901, 0x11 },
+ { 0x0902, 0x0a },
+ { 0x3140, 0x02 },
+ { 0x3141, 0x00 },
+ { 0x3f0d, 0x0a },
+ { 0x3f14, 0x01 },
+ { 0x3f3c, 0x01 },
+ { 0x3f4d, 0x01 },
+ { 0x3f4c, 0x01 },
+ { 0x4254, 0x7f },
+ { 0x0401, 0x00 },
+ { 0x0404, 0x00 },
+ { 0x0405, 0x10 },
+ { 0x0408, 0x00 },
+ { 0x0409, 0x08 },
+ { 0x040a, 0x00 },
+ { 0x040b, 0x08 },
+ { 0x040c, 0x0c },
+ { 0x040d, 0xc0 },
+ { 0x040e, 0x09 },
+ { 0x040f, 0x90 },
+ { 0x034c, 0x0c },
+ { 0x034d, 0xc0 },
+ { 0x034e, 0x09 },
+ { 0x034f, 0x90 },
+ { 0x3261, 0x00 },
+ { 0x3264, 0x00 },
+ { 0x3265, 0x10 },
+ { 0x0301, 0x05 },
+ { 0x0303, 0x04 },
+ { 0x0305, 0x04 },
+ { 0x0306, 0x01 },
+ { 0x0307, 0x92 },
+ { 0x0309, 0x0a },
+ { 0x030b, 0x02 },
+ { 0x030d, 0x02 },
+ { 0x030e, 0x00 },
+ { 0x030f, 0xfa },
+ { 0x0310, 0x00 },
+ { 0x0820, 0x0f },
+ { 0x0821, 0x13 },
+ { 0x0822, 0x33 },
+ { 0x0823, 0x33 },
+ { 0x3e20, 0x01 },
+ { 0x3e37, 0x00 },
+ { 0x3e3b, 0x01 },
+ { 0x38a3, 0x01 },
+ { 0x38a8, 0x00 },
+ { 0x38a9, 0x00 },
+ { 0x38aa, 0x00 },
+ { 0x38ab, 0x00 },
+ { 0x3234, 0x00 },
+ { 0x3fc1, 0x00 },
+ { 0x3235, 0x00 },
+ { 0x3802, 0x00 },
+ { 0x3143, 0x04 },
+ { 0x360a, 0x00 },
+ { 0x0b00, 0x00 },
+ { 0x0106, 0x00 },
+ { 0x0b05, 0x01 },
+ { 0x0b06, 0x01 },
+ { 0x3230, 0x00 },
+ { 0x3602, 0x01 },
+ { 0x3607, 0x01 },
+ { 0x3c00, 0x00 },
+ { 0x3c01, 0x48 },
+ { 0x3c02, 0xc8 },
+ { 0x3c03, 0xaa },
+ { 0x3c04, 0x91 },
+ { 0x3c05, 0x54 },
+ { 0x3c06, 0x26 },
+ { 0x3c07, 0x20 },
+ { 0x3c08, 0x51 },
+ { 0x3d80, 0x00 },
+ { 0x3f50, 0x00 },
+ { 0x3f56, 0x00 },
+ { 0x3f57, 0x30 },
+ { 0x3f78, 0x01 },
+ { 0x3f79, 0x18 },
+ { 0x3f7c, 0x00 },
+ { 0x3f7d, 0x00 },
+ { 0x3fba, 0x00 },
+ { 0x3fbb, 0x00 },
+ { 0xa081, 0x00 },
+ { 0xe014, 0x00 },
+ { 0x0202, 0x0a },
+ { 0x0203, 0x7a },
+ { 0x0224, 0x01 },
+ { 0x0225, 0xf4 },
+ { 0x0204, 0x00 },
+ { 0x0205, 0x00 },
+ { 0x0216, 0x00 },
+ { 0x0217, 0x00 },
+ { 0x020e, 0x01 },
+ { 0x020f, 0x00 },
+ { 0x0210, 0x01 },
+ { 0x0211, 0x00 },
+ { 0x0212, 0x01 },
+ { 0x0213, 0x00 },
+ { 0x0214, 0x01 },
+ { 0x0215, 0x00 },
+ { 0x0218, 0x01 },
+ { 0x0219, 0x00 },
+ { 0x3614, 0x00 },
+ { 0x3616, 0x0d },
+ { 0x3617, 0x56 },
+ { 0xb612, 0x20 },
+ { 0xb613, 0x20 },
+ { 0xb614, 0x20 },
+ { 0xb615, 0x20 },
+ { 0xb616, 0x0a },
+ { 0xb617, 0x0a },
+ { 0xb618, 0x20 },
+ { 0xb619, 0x20 },
+ { 0xb61a, 0x20 },
+ { 0xb61b, 0x20 },
+ { 0xb61c, 0x0a },
+ { 0xb61d, 0x0a },
+ { 0xb666, 0x30 },
+ { 0xb667, 0x30 },
+ { 0xb668, 0x30 },
+ { 0xb669, 0x30 },
+ { 0xb66a, 0x14 },
+ { 0xb66b, 0x14 },
+ { 0xb66c, 0x20 },
+ { 0xb66d, 0x20 },
+ { 0xb66e, 0x20 },
+ { 0xb66f, 0x20 },
+ { 0xb670, 0x10 },
+ { 0xb671, 0x10 },
+ { 0x3237, 0x00 },
+ { 0x3900, 0x00 },
+ { 0x3901, 0x00 },
+ { 0x3902, 0x00 },
+ { 0x3904, 0x00 },
+ { 0x3905, 0x00 },
+ { 0x3906, 0x00 },
+ { 0x3907, 0x00 },
+ { 0x3908, 0x00 },
+ { 0x3909, 0x00 },
+ { 0x3912, 0x00 },
+ { 0x3930, 0x00 },
+ { 0x3931, 0x00 },
+ { 0x3933, 0x00 },
+ { 0x3934, 0x00 },
+ { 0x3935, 0x00 },
+ { 0x3936, 0x00 },
+ { 0x3937, 0x00 },
+ { 0x30ac, 0x00 },
+};
+
+static const struct imx319_reg mode_3280x2464_regs[] = {
+ { 0x0112, 0x0a },
+ { 0x0113, 0x0a },
+ { 0x0114, 0x03 },
+ { 0x0342, 0x0f },
+ { 0x0343, 0x80 },
+ { 0x0340, 0x0c },
+ { 0x0341, 0xaa },
+ { 0x0344, 0x00 },
+ { 0x0345, 0x00 },
+ { 0x0346, 0x00 },
+ { 0x0347, 0x00 },
+ { 0x0348, 0x0c },
+ { 0x0349, 0xcf },
+ { 0x034a, 0x09 },
+ { 0x034b, 0x9f },
+ { 0x0220, 0x00 },
+ { 0x0221, 0x11 },
+ { 0x0381, 0x01 },
+ { 0x0383, 0x01 },
+ { 0x0385, 0x01 },
+ { 0x0387, 0x01 },
+ { 0x0900, 0x00 },
+ { 0x0901, 0x11 },
+ { 0x0902, 0x0a },
+ { 0x3140, 0x02 },
+ { 0x3141, 0x00 },
+ { 0x3f0d, 0x0a },
+ { 0x3f14, 0x01 },
+ { 0x3f3c, 0x01 },
+ { 0x3f4d, 0x01 },
+ { 0x3f4c, 0x01 },
+ { 0x4254, 0x7f },
+ { 0x0401, 0x00 },
+ { 0x0404, 0x00 },
+ { 0x0405, 0x10 },
+ { 0x0408, 0x00 },
+ { 0x0409, 0x00 },
+ { 0x040a, 0x00 },
+ { 0x040b, 0x00 },
+ { 0x040c, 0x0c },
+ { 0x040d, 0xd0 },
+ { 0x040e, 0x09 },
+ { 0x040f, 0xa0 },
+ { 0x034c, 0x0c },
+ { 0x034d, 0xd0 },
+ { 0x034e, 0x09 },
+ { 0x034f, 0xa0 },
+ { 0x3261, 0x00 },
+ { 0x3264, 0x00 },
+ { 0x3265, 0x10 },
+ { 0x0301, 0x05 },
+ { 0x0303, 0x04 },
+ { 0x0305, 0x04 },
+ { 0x0306, 0x01 },
+ { 0x0307, 0x92 },
+ { 0x0309, 0x0a },
+ { 0x030b, 0x02 },
+ { 0x030d, 0x02 },
+ { 0x030e, 0x00 },
+ { 0x030f, 0xfa },
+ { 0x0310, 0x00 },
+ { 0x0820, 0x0f },
+ { 0x0821, 0x13 },
+ { 0x0822, 0x33 },
+ { 0x0823, 0x33 },
+ { 0x3e20, 0x01 },
+ { 0x3e37, 0x00 },
+ { 0x3e3b, 0x01 },
+ { 0x38a3, 0x01 },
+ { 0x38a8, 0x00 },
+ { 0x38a9, 0x00 },
+ { 0x38aa, 0x00 },
+ { 0x38ab, 0x00 },
+ { 0x3234, 0x00 },
+ { 0x3fc1, 0x00 },
+ { 0x3235, 0x00 },
+ { 0x3802, 0x00 },
+ { 0x3143, 0x04 },
+ { 0x360a, 0x00 },
+ { 0x0b00, 0x00 },
+ { 0x0106, 0x00 },
+ { 0x0b05, 0x01 },
+ { 0x0b06, 0x01 },
+ { 0x3230, 0x00 },
+ { 0x3602, 0x01 },
+ { 0x3607, 0x01 },
+ { 0x3c00, 0x00 },
+ { 0x3c01, 0x48 },
+ { 0x3c02, 0xc8 },
+ { 0x3c03, 0xaa },
+ { 0x3c04, 0x91 },
+ { 0x3c05, 0x54 },
+ { 0x3c06, 0x26 },
+ { 0x3c07, 0x20 },
+ { 0x3c08, 0x51 },
+ { 0x3d80, 0x00 },
+ { 0x3f50, 0x00 },
+ { 0x3f56, 0x00 },
+ { 0x3f57, 0x30 },
+ { 0x3f78, 0x01 },
+ { 0x3f79, 0x18 },
+ { 0x3f7c, 0x00 },
+ { 0x3f7d, 0x00 },
+ { 0x3fba, 0x00 },
+ { 0x3fbb, 0x00 },
+ { 0xa081, 0x00 },
+ { 0xe014, 0x00 },
+ { 0x0202, 0x0a },
+ { 0x0203, 0x7a },
+ { 0x0224, 0x01 },
+ { 0x0225, 0xf4 },
+ { 0x0204, 0x00 },
+ { 0x0205, 0x00 },
+ { 0x0216, 0x00 },
+ { 0x0217, 0x00 },
+ { 0x020e, 0x01 },
+ { 0x020f, 0x00 },
+ { 0x0210, 0x01 },
+ { 0x0211, 0x00 },
+ { 0x0212, 0x01 },
+ { 0x0213, 0x00 },
+ { 0x0214, 0x01 },
+ { 0x0215, 0x00 },
+ { 0x0218, 0x01 },
+ { 0x0219, 0x00 },
+ { 0x3614, 0x00 },
+ { 0x3616, 0x0d },
+ { 0x3617, 0x56 },
+ { 0xb612, 0x20 },
+ { 0xb613, 0x20 },
+ { 0xb614, 0x20 },
+ { 0xb615, 0x20 },
+ { 0xb616, 0x0a },
+ { 0xb617, 0x0a },
+ { 0xb618, 0x20 },
+ { 0xb619, 0x20 },
+ { 0xb61a, 0x20 },
+ { 0xb61b, 0x20 },
+ { 0xb61c, 0x0a },
+ { 0xb61d, 0x0a },
+ { 0xb666, 0x30 },
+ { 0xb667, 0x30 },
+ { 0xb668, 0x30 },
+ { 0xb669, 0x30 },
+ { 0xb66a, 0x14 },
+ { 0xb66b, 0x14 },
+ { 0xb66c, 0x20 },
+ { 0xb66d, 0x20 },
+ { 0xb66e, 0x20 },
+ { 0xb66f, 0x20 },
+ { 0xb670, 0x10 },
+ { 0xb671, 0x10 },
+ { 0x3237, 0x00 },
+ { 0x3900, 0x00 },
+ { 0x3901, 0x00 },
+ { 0x3902, 0x00 },
+ { 0x3904, 0x00 },
+ { 0x3905, 0x00 },
+ { 0x3906, 0x00 },
+ { 0x3907, 0x00 },
+ { 0x3908, 0x00 },
+ { 0x3909, 0x00 },
+ { 0x3912, 0x00 },
+ { 0x3930, 0x00 },
+ { 0x3931, 0x00 },
+ { 0x3933, 0x00 },
+ { 0x3934, 0x00 },
+ { 0x3935, 0x00 },
+ { 0x3936, 0x00 },
+ { 0x3937, 0x00 },
+ { 0x30ac, 0x00 },
+};
+
+static const struct imx319_reg mode_1936x1096_regs[] = {
+ { 0x0112, 0x0a },
+ { 0x0113, 0x0a },
+ { 0x0114, 0x03 },
+ { 0x0342, 0x0f },
+ { 0x0343, 0x80 },
+ { 0x0340, 0x0c },
+ { 0x0341, 0xaa },
+ { 0x0344, 0x00 },
+ { 0x0345, 0x00 },
+ { 0x0346, 0x02 },
+ { 0x0347, 0xac },
+ { 0x0348, 0x0c },
+ { 0x0349, 0xcf },
+ { 0x034a, 0x06 },
+ { 0x034b, 0xf3 },
+ { 0x0220, 0x00 },
+ { 0x0221, 0x11 },
+ { 0x0381, 0x01 },
+ { 0x0383, 0x01 },
+ { 0x0385, 0x01 },
+ { 0x0387, 0x01 },
+ { 0x0900, 0x00 },
+ { 0x0901, 0x11 },
+ { 0x0902, 0x0a },
+ { 0x3140, 0x02 },
+ { 0x3141, 0x00 },
+ { 0x3f0d, 0x0a },
+ { 0x3f14, 0x01 },
+ { 0x3f3c, 0x01 },
+ { 0x3f4d, 0x01 },
+ { 0x3f4c, 0x01 },
+ { 0x4254, 0x7f },
+ { 0x0401, 0x00 },
+ { 0x0404, 0x00 },
+ { 0x0405, 0x10 },
+ { 0x0408, 0x02 },
+ { 0x0409, 0xa0 },
+ { 0x040a, 0x00 },
+ { 0x040b, 0x00 },
+ { 0x040c, 0x07 },
+ { 0x040d, 0x90 },
+ { 0x040e, 0x04 },
+ { 0x040f, 0x48 },
+ { 0x034c, 0x07 },
+ { 0x034d, 0x90 },
+ { 0x034e, 0x04 },
+ { 0x034f, 0x48 },
+ { 0x3261, 0x00 },
+ { 0x3264, 0x00 },
+ { 0x3265, 0x10 },
+ { 0x0301, 0x05 },
+ { 0x0303, 0x04 },
+ { 0x0305, 0x04 },
+ { 0x0306, 0x01 },
+ { 0x0307, 0x92 },
+ { 0x0309, 0x0a },
+ { 0x030b, 0x02 },
+ { 0x030d, 0x02 },
+ { 0x030e, 0x00 },
+ { 0x030f, 0xfa },
+ { 0x0310, 0x00 },
+ { 0x0820, 0x0f },
+ { 0x0821, 0x13 },
+ { 0x0822, 0x33 },
+ { 0x0823, 0x33 },
+ { 0x3e20, 0x01 },
+ { 0x3e37, 0x00 },
+ { 0x3e3b, 0x01 },
+ { 0x38a3, 0x01 },
+ { 0x38a8, 0x00 },
+ { 0x38a9, 0x00 },
+ { 0x38aa, 0x00 },
+ { 0x38ab, 0x00 },
+ { 0x3234, 0x00 },
+ { 0x3fc1, 0x00 },
+ { 0x3235, 0x00 },
+ { 0x3802, 0x00 },
+ { 0x3143, 0x04 },
+ { 0x360a, 0x00 },
+ { 0x0b00, 0x00 },
+ { 0x0106, 0x00 },
+ { 0x0b05, 0x01 },
+ { 0x0b06, 0x01 },
+ { 0x3230, 0x00 },
+ { 0x3602, 0x01 },
+ { 0x3607, 0x01 },
+ { 0x3c00, 0x00 },
+ { 0x3c01, 0x48 },
+ { 0x3c02, 0xc8 },
+ { 0x3c03, 0xaa },
+ { 0x3c04, 0x91 },
+ { 0x3c05, 0x54 },
+ { 0x3c06, 0x26 },
+ { 0x3c07, 0x20 },
+ { 0x3c08, 0x51 },
+ { 0x3d80, 0x00 },
+ { 0x3f50, 0x00 },
+ { 0x3f56, 0x00 },
+ { 0x3f57, 0x30 },
+ { 0x3f78, 0x01 },
+ { 0x3f79, 0x18 },
+ { 0x3f7c, 0x00 },
+ { 0x3f7d, 0x00 },
+ { 0x3fba, 0x00 },
+ { 0x3fbb, 0x00 },
+ { 0xa081, 0x00 },
+ { 0xe014, 0x00 },
+ { 0x0202, 0x05 },
+ { 0x0203, 0x34 },
+ { 0x0224, 0x01 },
+ { 0x0225, 0xf4 },
+ { 0x0204, 0x00 },
+ { 0x0205, 0x00 },
+ { 0x0216, 0x00 },
+ { 0x0217, 0x00 },
+ { 0x020e, 0x01 },
+ { 0x020f, 0x00 },
+ { 0x0210, 0x01 },
+ { 0x0211, 0x00 },
+ { 0x0212, 0x01 },
+ { 0x0213, 0x00 },
+ { 0x0214, 0x01 },
+ { 0x0215, 0x00 },
+ { 0x0218, 0x01 },
+ { 0x0219, 0x00 },
+ { 0x3614, 0x00 },
+ { 0x3616, 0x0d },
+ { 0x3617, 0x56 },
+ { 0xb612, 0x20 },
+ { 0xb613, 0x20 },
+ { 0xb614, 0x20 },
+ { 0xb615, 0x20 },
+ { 0xb616, 0x0a },
+ { 0xb617, 0x0a },
+ { 0xb618, 0x20 },
+ { 0xb619, 0x20 },
+ { 0xb61a, 0x20 },
+ { 0xb61b, 0x20 },
+ { 0xb61c, 0x0a },
+ { 0xb61d, 0x0a },
+ { 0xb666, 0x30 },
+ { 0xb667, 0x30 },
+ { 0xb668, 0x30 },
+ { 0xb669, 0x30 },
+ { 0xb66a, 0x14 },
+ { 0xb66b, 0x14 },
+ { 0xb66c, 0x20 },
+ { 0xb66d, 0x20 },
+ { 0xb66e, 0x20 },
+ { 0xb66f, 0x20 },
+ { 0xb670, 0x10 },
+ { 0xb671, 0x10 },
+ { 0x3237, 0x00 },
+ { 0x3900, 0x00 },
+ { 0x3901, 0x00 },
+ { 0x3902, 0x00 },
+ { 0x3904, 0x00 },
+ { 0x3905, 0x00 },
+ { 0x3906, 0x00 },
+ { 0x3907, 0x00 },
+ { 0x3908, 0x00 },
+ { 0x3909, 0x00 },
+ { 0x3912, 0x00 },
+ { 0x3930, 0x00 },
+ { 0x3931, 0x00 },
+ { 0x3933, 0x00 },
+ { 0x3934, 0x00 },
+ { 0x3935, 0x00 },
+ { 0x3936, 0x00 },
+ { 0x3937, 0x00 },
+ { 0x30ac, 0x00 },
+};
+
+static const struct imx319_reg mode_1920x1080_regs[] = {
+ { 0x0112, 0x0a },
+ { 0x0113, 0x0a },
+ { 0x0114, 0x03 },
+ { 0x0342, 0x0f },
+ { 0x0343, 0x80 },
+ { 0x0340, 0x0c },
+ { 0x0341, 0xaa },
+ { 0x0344, 0x00 },
+ { 0x0345, 0x00 },
+ { 0x0346, 0x02 },
+ { 0x0347, 0xb4 },
+ { 0x0348, 0x0c },
+ { 0x0349, 0xcf },
+ { 0x034a, 0x06 },
+ { 0x034b, 0xeb },
+ { 0x0220, 0x00 },
+ { 0x0221, 0x11 },
+ { 0x0381, 0x01 },
+ { 0x0383, 0x01 },
+ { 0x0385, 0x01 },
+ { 0x0387, 0x01 },
+ { 0x0900, 0x00 },
+ { 0x0901, 0x11 },
+ { 0x0902, 0x0a },
+ { 0x3140, 0x02 },
+ { 0x3141, 0x00 },
+ { 0x3f0d, 0x0a },
+ { 0x3f14, 0x01 },
+ { 0x3f3c, 0x01 },
+ { 0x3f4d, 0x01 },
+ { 0x3f4c, 0x01 },
+ { 0x4254, 0x7f },
+ { 0x0401, 0x00 },
+ { 0x0404, 0x00 },
+ { 0x0405, 0x10 },
+ { 0x0408, 0x02 },
+ { 0x0409, 0xa8 },
+ { 0x040a, 0x00 },
+ { 0x040b, 0x00 },
+ { 0x040c, 0x07 },
+ { 0x040d, 0x80 },
+ { 0x040e, 0x04 },
+ { 0x040f, 0x38 },
+ { 0x034c, 0x07 },
+ { 0x034d, 0x80 },
+ { 0x034e, 0x04 },
+ { 0x034f, 0x38 },
+ { 0x3261, 0x00 },
+ { 0x3264, 0x00 },
+ { 0x3265, 0x10 },
+ { 0x0301, 0x05 },
+ { 0x0303, 0x04 },
+ { 0x0305, 0x04 },
+ { 0x0306, 0x01 },
+ { 0x0307, 0x92 },
+ { 0x0309, 0x0a },
+ { 0x030b, 0x02 },
+ { 0x030d, 0x02 },
+ { 0x030e, 0x00 },
+ { 0x030f, 0xfa },
+ { 0x0310, 0x00 },
+ { 0x0820, 0x0f },
+ { 0x0821, 0x13 },
+ { 0x0822, 0x33 },
+ { 0x0823, 0x33 },
+ { 0x3e20, 0x01 },
+ { 0x3e37, 0x00 },
+ { 0x3e3b, 0x01 },
+ { 0x38a3, 0x01 },
+ { 0x38a8, 0x00 },
+ { 0x38a9, 0x00 },
+ { 0x38aa, 0x00 },
+ { 0x38ab, 0x00 },
+ { 0x3234, 0x00 },
+ { 0x3fc1, 0x00 },
+ { 0x3235, 0x00 },
+ { 0x3802, 0x00 },
+ { 0x3143, 0x04 },
+ { 0x360a, 0x00 },
+ { 0x0b00, 0x00 },
+ { 0x0106, 0x00 },
+ { 0x0b05, 0x01 },
+ { 0x0b06, 0x01 },
+ { 0x3230, 0x00 },
+ { 0x3602, 0x01 },
+ { 0x3607, 0x01 },
+ { 0x3c00, 0x00 },
+ { 0x3c01, 0x48 },
+ { 0x3c02, 0xc8 },
+ { 0x3c03, 0xaa },
+ { 0x3c04, 0x91 },
+ { 0x3c05, 0x54 },
+ { 0x3c06, 0x26 },
+ { 0x3c07, 0x20 },
+ { 0x3c08, 0x51 },
+ { 0x3d80, 0x00 },
+ { 0x3f50, 0x00 },
+ { 0x3f56, 0x00 },
+ { 0x3f57, 0x30 },
+ { 0x3f78, 0x01 },
+ { 0x3f79, 0x18 },
+ { 0x3f7c, 0x00 },
+ { 0x3f7d, 0x00 },
+ { 0x3fba, 0x00 },
+ { 0x3fbb, 0x00 },
+ { 0xa081, 0x00 },
+ { 0xe014, 0x00 },
+ { 0x0202, 0x05 },
+ { 0x0203, 0x34 },
+ { 0x0224, 0x01 },
+ { 0x0225, 0xf4 },
+ { 0x0204, 0x00 },
+ { 0x0205, 0x00 },
+ { 0x0216, 0x00 },
+ { 0x0217, 0x00 },
+ { 0x020e, 0x01 },
+ { 0x020f, 0x00 },
+ { 0x0210, 0x01 },
+ { 0x0211, 0x00 },
+ { 0x0212, 0x01 },
+ { 0x0213, 0x00 },
+ { 0x0214, 0x01 },
+ { 0x0215, 0x00 },
+ { 0x0218, 0x01 },
+ { 0x0219, 0x00 },
+ { 0x3614, 0x00 },
+ { 0x3616, 0x0d },
+ { 0x3617, 0x56 },
+ { 0xb612, 0x20 },
+ { 0xb613, 0x20 },
+ { 0xb614, 0x20 },
+ { 0xb615, 0x20 },
+ { 0xb616, 0x0a },
+ { 0xb617, 0x0a },
+ { 0xb618, 0x20 },
+ { 0xb619, 0x20 },
+ { 0xb61a, 0x20 },
+ { 0xb61b, 0x20 },
+ { 0xb61c, 0x0a },
+ { 0xb61d, 0x0a },
+ { 0xb666, 0x30 },
+ { 0xb667, 0x30 },
+ { 0xb668, 0x30 },
+ { 0xb669, 0x30 },
+ { 0xb66a, 0x14 },
+ { 0xb66b, 0x14 },
+ { 0xb66c, 0x20 },
+ { 0xb66d, 0x20 },
+ { 0xb66e, 0x20 },
+ { 0xb66f, 0x20 },
+ { 0xb670, 0x10 },
+ { 0xb671, 0x10 },
+ { 0x3237, 0x00 },
+ { 0x3900, 0x00 },
+ { 0x3901, 0x00 },
+ { 0x3902, 0x00 },
+ { 0x3904, 0x00 },
+ { 0x3905, 0x00 },
+ { 0x3906, 0x00 },
+ { 0x3907, 0x00 },
+ { 0x3908, 0x00 },
+ { 0x3909, 0x00 },
+ { 0x3912, 0x00 },
+ { 0x3930, 0x00 },
+ { 0x3931, 0x00 },
+ { 0x3933, 0x00 },
+ { 0x3934, 0x00 },
+ { 0x3935, 0x00 },
+ { 0x3936, 0x00 },
+ { 0x3937, 0x00 },
+ { 0x30ac, 0x00 },
+};
+
+static const struct imx319_reg mode_1640x1232_regs[] = {
+ { 0x0112, 0x0a },
+ { 0x0113, 0x0a },
+ { 0x0114, 0x03 },
+ { 0x0342, 0x08 },
+ { 0x0343, 0x20 },
+ { 0x0340, 0x18 },
+ { 0x0341, 0x2a },
+ { 0x0344, 0x00 },
+ { 0x0345, 0x00 },
+ { 0x0346, 0x00 },
+ { 0x0347, 0x00 },
+ { 0x0348, 0x0c },
+ { 0x0349, 0xcf },
+ { 0x034a, 0x09 },
+ { 0x034b, 0x9f },
+ { 0x0220, 0x00 },
+ { 0x0221, 0x11 },
+ { 0x0381, 0x01 },
+ { 0x0383, 0x01 },
+ { 0x0385, 0x01 },
+ { 0x0387, 0x01 },
+ { 0x0900, 0x01 },
+ { 0x0901, 0x22 },
+ { 0x0902, 0x0a },
+ { 0x3140, 0x02 },
+ { 0x3141, 0x00 },
+ { 0x3f0d, 0x0a },
+ { 0x3f14, 0x01 },
+ { 0x3f3c, 0x02 },
+ { 0x3f4d, 0x01 },
+ { 0x3f4c, 0x01 },
+ { 0x4254, 0x7f },
+ { 0x0401, 0x00 },
+ { 0x0404, 0x00 },
+ { 0x0405, 0x10 },
+ { 0x0408, 0x00 },
+ { 0x0409, 0x00 },
+ { 0x040a, 0x00 },
+ { 0x040b, 0x00 },
+ { 0x040c, 0x06 },
+ { 0x040d, 0x68 },
+ { 0x040e, 0x04 },
+ { 0x040f, 0xd0 },
+ { 0x034c, 0x06 },
+ { 0x034d, 0x68 },
+ { 0x034e, 0x04 },
+ { 0x034f, 0xd0 },
+ { 0x3261, 0x00 },
+ { 0x3264, 0x00 },
+ { 0x3265, 0x10 },
+ { 0x0301, 0x05 },
+ { 0x0303, 0x04 },
+ { 0x0305, 0x04 },
+ { 0x0306, 0x01 },
+ { 0x0307, 0x92 },
+ { 0x0309, 0x0a },
+ { 0x030b, 0x02 },
+ { 0x030d, 0x02 },
+ { 0x030e, 0x00 },
+ { 0x030f, 0xfa },
+ { 0x0310, 0x00 },
+ { 0x0820, 0x0f },
+ { 0x0821, 0x13 },
+ { 0x0822, 0x33 },
+ { 0x0823, 0x33 },
+ { 0x3e20, 0x01 },
+ { 0x3e37, 0x00 },
+ { 0x3e3b, 0x01 },
+ { 0x38a3, 0x01 },
+ { 0x38a8, 0x00 },
+ { 0x38a9, 0x00 },
+ { 0x38aa, 0x00 },
+ { 0x38ab, 0x00 },
+ { 0x3234, 0x00 },
+ { 0x3fc1, 0x00 },
+ { 0x3235, 0x00 },
+ { 0x3802, 0x00 },
+ { 0x3143, 0x04 },
+ { 0x360a, 0x00 },
+ { 0x0b00, 0x00 },
+ { 0x0106, 0x00 },
+ { 0x0b05, 0x01 },
+ { 0x0b06, 0x01 },
+ { 0x3230, 0x00 },
+ { 0x3602, 0x01 },
+ { 0x3607, 0x01 },
+ { 0x3c00, 0x00 },
+ { 0x3c01, 0xba },
+ { 0x3c02, 0xc8 },
+ { 0x3c03, 0xaa },
+ { 0x3c04, 0x91 },
+ { 0x3c05, 0x54 },
+ { 0x3c06, 0x26 },
+ { 0x3c07, 0x20 },
+ { 0x3c08, 0x51 },
+ { 0x3d80, 0x00 },
+ { 0x3f50, 0x00 },
+ { 0x3f56, 0x00 },
+ { 0x3f57, 0x30 },
+ { 0x3f78, 0x00 },
+ { 0x3f79, 0x34 },
+ { 0x3f7c, 0x00 },
+ { 0x3f7d, 0x00 },
+ { 0x3fba, 0x00 },
+ { 0x3fbb, 0x00 },
+ { 0xa081, 0x04 },
+ { 0xe014, 0x00 },
+ { 0x0202, 0x04 },
+ { 0x0203, 0xf6 },
+ { 0x0224, 0x01 },
+ { 0x0225, 0xf4 },
+ { 0x0204, 0x00 },
+ { 0x0205, 0x00 },
+ { 0x0216, 0x00 },
+ { 0x0217, 0x00 },
+ { 0x020e, 0x01 },
+ { 0x020f, 0x00 },
+ { 0x0210, 0x01 },
+ { 0x0211, 0x00 },
+ { 0x0212, 0x01 },
+ { 0x0213, 0x00 },
+ { 0x0214, 0x01 },
+ { 0x0215, 0x00 },
+ { 0x0218, 0x01 },
+ { 0x0219, 0x00 },
+ { 0x3614, 0x00 },
+ { 0x3616, 0x0d },
+ { 0x3617, 0x56 },
+ { 0xb612, 0x20 },
+ { 0xb613, 0x20 },
+ { 0xb614, 0x20 },
+ { 0xb615, 0x20 },
+ { 0xb616, 0x0a },
+ { 0xb617, 0x0a },
+ { 0xb618, 0x20 },
+ { 0xb619, 0x20 },
+ { 0xb61a, 0x20 },
+ { 0xb61b, 0x20 },
+ { 0xb61c, 0x0a },
+ { 0xb61d, 0x0a },
+ { 0xb666, 0x30 },
+ { 0xb667, 0x30 },
+ { 0xb668, 0x30 },
+ { 0xb669, 0x30 },
+ { 0xb66a, 0x14 },
+ { 0xb66b, 0x14 },
+ { 0xb66c, 0x20 },
+ { 0xb66d, 0x20 },
+ { 0xb66e, 0x20 },
+ { 0xb66f, 0x20 },
+ { 0xb670, 0x10 },
+ { 0xb671, 0x10 },
+ { 0x3237, 0x00 },
+ { 0x3900, 0x00 },
+ { 0x3901, 0x00 },
+ { 0x3902, 0x00 },
+ { 0x3904, 0x00 },
+ { 0x3905, 0x00 },
+ { 0x3906, 0x00 },
+ { 0x3907, 0x00 },
+ { 0x3908, 0x00 },
+ { 0x3909, 0x00 },
+ { 0x3912, 0x00 },
+ { 0x3930, 0x00 },
+ { 0x3931, 0x00 },
+ { 0x3933, 0x00 },
+ { 0x3934, 0x00 },
+ { 0x3935, 0x00 },
+ { 0x3936, 0x00 },
+ { 0x3937, 0x00 },
+ { 0x30ac, 0x00 },
+};
+
+static const struct imx319_reg mode_1640x922_regs[] = {
+ { 0x0112, 0x0a },
+ { 0x0113, 0x0a },
+ { 0x0114, 0x03 },
+ { 0x0342, 0x08 },
+ { 0x0343, 0x20 },
+ { 0x0340, 0x18 },
+ { 0x0341, 0x2a },
+ { 0x0344, 0x00 },
+ { 0x0345, 0x00 },
+ { 0x0346, 0x01 },
+ { 0x0347, 0x30 },
+ { 0x0348, 0x0c },
+ { 0x0349, 0xcf },
+ { 0x034a, 0x08 },
+ { 0x034b, 0x6f },
+ { 0x0220, 0x00 },
+ { 0x0221, 0x11 },
+ { 0x0381, 0x01 },
+ { 0x0383, 0x01 },
+ { 0x0385, 0x01 },
+ { 0x0387, 0x01 },
+ { 0x0900, 0x01 },
+ { 0x0901, 0x22 },
+ { 0x0902, 0x0a },
+ { 0x3140, 0x02 },
+ { 0x3141, 0x00 },
+ { 0x3f0d, 0x0a },
+ { 0x3f14, 0x01 },
+ { 0x3f3c, 0x02 },
+ { 0x3f4d, 0x01 },
+ { 0x3f4c, 0x01 },
+ { 0x4254, 0x7f },
+ { 0x0401, 0x00 },
+ { 0x0404, 0x00 },
+ { 0x0405, 0x10 },
+ { 0x0408, 0x00 },
+ { 0x0409, 0x00 },
+ { 0x040a, 0x00 },
+ { 0x040b, 0x02 },
+ { 0x040c, 0x06 },
+ { 0x040d, 0x68 },
+ { 0x040e, 0x03 },
+ { 0x040f, 0x9a },
+ { 0x034c, 0x06 },
+ { 0x034d, 0x68 },
+ { 0x034e, 0x03 },
+ { 0x034f, 0x9a },
+ { 0x3261, 0x00 },
+ { 0x3264, 0x00 },
+ { 0x3265, 0x10 },
+ { 0x0301, 0x05 },
+ { 0x0303, 0x04 },
+ { 0x0305, 0x04 },
+ { 0x0306, 0x01 },
+ { 0x0307, 0x92 },
+ { 0x0309, 0x0a },
+ { 0x030b, 0x02 },
+ { 0x030d, 0x02 },
+ { 0x030e, 0x00 },
+ { 0x030f, 0xfa },
+ { 0x0310, 0x00 },
+ { 0x0820, 0x0f },
+ { 0x0821, 0x13 },
+ { 0x0822, 0x33 },
+ { 0x0823, 0x33 },
+ { 0x3e20, 0x01 },
+ { 0x3e37, 0x00 },
+ { 0x3e3b, 0x01 },
+ { 0x38a3, 0x01 },
+ { 0x38a8, 0x00 },
+ { 0x38a9, 0x00 },
+ { 0x38aa, 0x00 },
+ { 0x38ab, 0x00 },
+ { 0x3234, 0x00 },
+ { 0x3fc1, 0x00 },
+ { 0x3235, 0x00 },
+ { 0x3802, 0x00 },
+ { 0x3143, 0x04 },
+ { 0x360a, 0x00 },
+ { 0x0b00, 0x00 },
+ { 0x0106, 0x00 },
+ { 0x0b05, 0x01 },
+ { 0x0b06, 0x01 },
+ { 0x3230, 0x00 },
+ { 0x3602, 0x01 },
+ { 0x3607, 0x01 },
+ { 0x3c00, 0x00 },
+ { 0x3c01, 0xba },
+ { 0x3c02, 0xc8 },
+ { 0x3c03, 0xaa },
+ { 0x3c04, 0x91 },
+ { 0x3c05, 0x54 },
+ { 0x3c06, 0x26 },
+ { 0x3c07, 0x20 },
+ { 0x3c08, 0x51 },
+ { 0x3d80, 0x00 },
+ { 0x3f50, 0x00 },
+ { 0x3f56, 0x00 },
+ { 0x3f57, 0x30 },
+ { 0x3f78, 0x00 },
+ { 0x3f79, 0x34 },
+ { 0x3f7c, 0x00 },
+ { 0x3f7d, 0x00 },
+ { 0x3fba, 0x00 },
+ { 0x3fbb, 0x00 },
+ { 0xa081, 0x04 },
+ { 0xe014, 0x00 },
+ { 0x0202, 0x04 },
+ { 0x0203, 0xf6 },
+ { 0x0224, 0x01 },
+ { 0x0225, 0xf4 },
+ { 0x0204, 0x00 },
+ { 0x0205, 0x00 },
+ { 0x0216, 0x00 },
+ { 0x0217, 0x00 },
+ { 0x020e, 0x01 },
+ { 0x020f, 0x00 },
+ { 0x0210, 0x01 },
+ { 0x0211, 0x00 },
+ { 0x0212, 0x01 },
+ { 0x0213, 0x00 },
+ { 0x0214, 0x01 },
+ { 0x0215, 0x00 },
+ { 0x0218, 0x01 },
+ { 0x0219, 0x00 },
+ { 0x3614, 0x00 },
+ { 0x3616, 0x0d },
+ { 0x3617, 0x56 },
+ { 0xb612, 0x20 },
+ { 0xb613, 0x20 },
+ { 0xb614, 0x20 },
+ { 0xb615, 0x20 },
+ { 0xb616, 0x0a },
+ { 0xb617, 0x0a },
+ { 0xb618, 0x20 },
+ { 0xb619, 0x20 },
+ { 0xb61a, 0x20 },
+ { 0xb61b, 0x20 },
+ { 0xb61c, 0x0a },
+ { 0xb61d, 0x0a },
+ { 0xb666, 0x30 },
+ { 0xb667, 0x30 },
+ { 0xb668, 0x30 },
+ { 0xb669, 0x30 },
+ { 0xb66a, 0x14 },
+ { 0xb66b, 0x14 },
+ { 0xb66c, 0x20 },
+ { 0xb66d, 0x20 },
+ { 0xb66e, 0x20 },
+ { 0xb66f, 0x20 },
+ { 0xb670, 0x10 },
+ { 0xb671, 0x10 },
+ { 0x3237, 0x00 },
+ { 0x3900, 0x00 },
+ { 0x3901, 0x00 },
+ { 0x3902, 0x00 },
+ { 0x3904, 0x00 },
+ { 0x3905, 0x00 },
+ { 0x3906, 0x00 },
+ { 0x3907, 0x00 },
+ { 0x3908, 0x00 },
+ { 0x3909, 0x00 },
+ { 0x3912, 0x00 },
+ { 0x3930, 0x00 },
+ { 0x3931, 0x00 },
+ { 0x3933, 0x00 },
+ { 0x3934, 0x00 },
+ { 0x3935, 0x00 },
+ { 0x3936, 0x00 },
+ { 0x3937, 0x00 },
+ { 0x30ac, 0x00 },
+};
+
+static const struct imx319_reg mode_1296x736_regs[] = {
+ { 0x0112, 0x0a },
+ { 0x0113, 0x0a },
+ { 0x0114, 0x03 },
+ { 0x0342, 0x08 },
+ { 0x0343, 0x20 },
+ { 0x0340, 0x18 },
+ { 0x0341, 0x2a },
+ { 0x0344, 0x00 },
+ { 0x0345, 0x00 },
+ { 0x0346, 0x01 },
+ { 0x0347, 0xf0 },
+ { 0x0348, 0x0c },
+ { 0x0349, 0xcf },
+ { 0x034a, 0x07 },
+ { 0x034b, 0xaf },
+ { 0x0220, 0x00 },
+ { 0x0221, 0x11 },
+ { 0x0381, 0x01 },
+ { 0x0383, 0x01 },
+ { 0x0385, 0x01 },
+ { 0x0387, 0x01 },
+ { 0x0900, 0x01 },
+ { 0x0901, 0x22 },
+ { 0x0902, 0x0a },
+ { 0x3140, 0x02 },
+ { 0x3141, 0x00 },
+ { 0x3f0d, 0x0a },
+ { 0x3f14, 0x01 },
+ { 0x3f3c, 0x02 },
+ { 0x3f4d, 0x01 },
+ { 0x3f4c, 0x01 },
+ { 0x4254, 0x7f },
+ { 0x0401, 0x00 },
+ { 0x0404, 0x00 },
+ { 0x0405, 0x10 },
+ { 0x0408, 0x00 },
+ { 0x0409, 0xac },
+ { 0x040a, 0x00 },
+ { 0x040b, 0x00 },
+ { 0x040c, 0x05 },
+ { 0x040d, 0x10 },
+ { 0x040e, 0x02 },
+ { 0x040f, 0xe0 },
+ { 0x034c, 0x05 },
+ { 0x034d, 0x10 },
+ { 0x034e, 0x02 },
+ { 0x034f, 0xe0 },
+ { 0x3261, 0x00 },
+ { 0x3264, 0x00 },
+ { 0x3265, 0x10 },
+ { 0x0301, 0x05 },
+ { 0x0303, 0x04 },
+ { 0x0305, 0x04 },
+ { 0x0306, 0x01 },
+ { 0x0307, 0x92 },
+ { 0x0309, 0x0a },
+ { 0x030b, 0x02 },
+ { 0x030d, 0x02 },
+ { 0x030e, 0x00 },
+ { 0x030f, 0xfa },
+ { 0x0310, 0x00 },
+ { 0x0820, 0x0f },
+ { 0x0821, 0x13 },
+ { 0x0822, 0x33 },
+ { 0x0823, 0x33 },
+ { 0x3e20, 0x01 },
+ { 0x3e37, 0x00 },
+ { 0x3e3b, 0x01 },
+ { 0x38a3, 0x01 },
+ { 0x38a8, 0x00 },
+ { 0x38a9, 0x00 },
+ { 0x38aa, 0x00 },
+ { 0x38ab, 0x00 },
+ { 0x3234, 0x00 },
+ { 0x3fc1, 0x00 },
+ { 0x3235, 0x00 },
+ { 0x3802, 0x00 },
+ { 0x3143, 0x04 },
+ { 0x360a, 0x00 },
+ { 0x0b00, 0x00 },
+ { 0x0106, 0x00 },
+ { 0x0b05, 0x01 },
+ { 0x0b06, 0x01 },
+ { 0x3230, 0x00 },
+ { 0x3602, 0x01 },
+ { 0x3607, 0x01 },
+ { 0x3c00, 0x00 },
+ { 0x3c01, 0xba },
+ { 0x3c02, 0xc8 },
+ { 0x3c03, 0xaa },
+ { 0x3c04, 0x91 },
+ { 0x3c05, 0x54 },
+ { 0x3c06, 0x26 },
+ { 0x3c07, 0x20 },
+ { 0x3c08, 0x51 },
+ { 0x3d80, 0x00 },
+ { 0x3f50, 0x00 },
+ { 0x3f56, 0x00 },
+ { 0x3f57, 0x30 },
+ { 0x3f78, 0x00 },
+ { 0x3f79, 0x34 },
+ { 0x3f7c, 0x00 },
+ { 0x3f7d, 0x00 },
+ { 0x3fba, 0x00 },
+ { 0x3fbb, 0x00 },
+ { 0xa081, 0x04 },
+ { 0xe014, 0x00 },
+ { 0x0202, 0x04 },
+ { 0x0203, 0xf6 },
+ { 0x0224, 0x01 },
+ { 0x0225, 0xf4 },
+ { 0x0204, 0x00 },
+ { 0x0205, 0x00 },
+ { 0x0216, 0x00 },
+ { 0x0217, 0x00 },
+ { 0x020e, 0x01 },
+ { 0x020f, 0x00 },
+ { 0x0210, 0x01 },
+ { 0x0211, 0x00 },
+ { 0x0212, 0x01 },
+ { 0x0213, 0x00 },
+ { 0x0214, 0x01 },
+ { 0x0215, 0x00 },
+ { 0x0218, 0x01 },
+ { 0x0219, 0x00 },
+ { 0x3614, 0x00 },
+ { 0x3616, 0x0d },
+ { 0x3617, 0x56 },
+ { 0xb612, 0x20 },
+ { 0xb613, 0x20 },
+ { 0xb614, 0x20 },
+ { 0xb615, 0x20 },
+ { 0xb616, 0x0a },
+ { 0xb617, 0x0a },
+ { 0xb618, 0x20 },
+ { 0xb619, 0x20 },
+ { 0xb61a, 0x20 },
+ { 0xb61b, 0x20 },
+ { 0xb61c, 0x0a },
+ { 0xb61d, 0x0a },
+ { 0xb666, 0x30 },
+ { 0xb667, 0x30 },
+ { 0xb668, 0x30 },
+ { 0xb669, 0x30 },
+ { 0xb66a, 0x14 },
+ { 0xb66b, 0x14 },
+ { 0xb66c, 0x20 },
+ { 0xb66d, 0x20 },
+ { 0xb66e, 0x20 },
+ { 0xb66f, 0x20 },
+ { 0xb670, 0x10 },
+ { 0xb671, 0x10 },
+ { 0x3237, 0x00 },
+ { 0x3900, 0x00 },
+ { 0x3901, 0x00 },
+ { 0x3902, 0x00 },
+ { 0x3904, 0x00 },
+ { 0x3905, 0x00 },
+ { 0x3906, 0x00 },
+ { 0x3907, 0x00 },
+ { 0x3908, 0x00 },
+ { 0x3909, 0x00 },
+ { 0x3912, 0x00 },
+ { 0x3930, 0x00 },
+ { 0x3931, 0x00 },
+ { 0x3933, 0x00 },
+ { 0x3934, 0x00 },
+ { 0x3935, 0x00 },
+ { 0x3936, 0x00 },
+ { 0x3937, 0x00 },
+ { 0x30ac, 0x00 },
+};
+
+static const struct imx319_reg mode_1280x720_regs[] = {
+ { 0x0112, 0x0a },
+ { 0x0113, 0x0a },
+ { 0x0114, 0x03 },
+ { 0x0342, 0x08 },
+ { 0x0343, 0x20 },
+ { 0x0340, 0x18 },
+ { 0x0341, 0x2a },
+ { 0x0344, 0x00 },
+ { 0x0345, 0x00 },
+ { 0x0346, 0x02 },
+ { 0x0347, 0x00 },
+ { 0x0348, 0x0c },
+ { 0x0349, 0xcf },
+ { 0x034a, 0x07 },
+ { 0x034b, 0x9f },
+ { 0x0220, 0x00 },
+ { 0x0221, 0x11 },
+ { 0x0381, 0x01 },
+ { 0x0383, 0x01 },
+ { 0x0385, 0x01 },
+ { 0x0387, 0x01 },
+ { 0x0900, 0x01 },
+ { 0x0901, 0x22 },
+ { 0x0902, 0x0a },
+ { 0x3140, 0x02 },
+ { 0x3141, 0x00 },
+ { 0x3f0d, 0x0a },
+ { 0x3f14, 0x01 },
+ { 0x3f3c, 0x02 },
+ { 0x3f4d, 0x01 },
+ { 0x3f4c, 0x01 },
+ { 0x4254, 0x7f },
+ { 0x0401, 0x00 },
+ { 0x0404, 0x00 },
+ { 0x0405, 0x10 },
+ { 0x0408, 0x00 },
+ { 0x0409, 0xb4 },
+ { 0x040a, 0x00 },
+ { 0x040b, 0x00 },
+ { 0x040c, 0x05 },
+ { 0x040d, 0x00 },
+ { 0x040e, 0x02 },
+ { 0x040f, 0xd0 },
+ { 0x034c, 0x05 },
+ { 0x034d, 0x00 },
+ { 0x034e, 0x02 },
+ { 0x034f, 0xd0 },
+ { 0x3261, 0x00 },
+ { 0x3264, 0x00 },
+ { 0x3265, 0x10 },
+ { 0x0301, 0x05 },
+ { 0x0303, 0x04 },
+ { 0x0305, 0x04 },
+ { 0x0306, 0x01 },
+ { 0x0307, 0x92 },
+ { 0x0309, 0x0a },
+ { 0x030b, 0x02 },
+ { 0x030d, 0x02 },
+ { 0x030e, 0x00 },
+ { 0x030f, 0xfa },
+ { 0x0310, 0x00 },
+ { 0x0820, 0x0f },
+ { 0x0821, 0x13 },
+ { 0x0822, 0x33 },
+ { 0x0823, 0x33 },
+ { 0x3e20, 0x01 },
+ { 0x3e37, 0x00 },
+ { 0x3e3b, 0x01 },
+ { 0x38a3, 0x01 },
+ { 0x38a8, 0x00 },
+ { 0x38a9, 0x00 },
+ { 0x38aa, 0x00 },
+ { 0x38ab, 0x00 },
+ { 0x3234, 0x00 },
+ { 0x3fc1, 0x00 },
+ { 0x3235, 0x00 },
+ { 0x3802, 0x00 },
+ { 0x3143, 0x04 },
+ { 0x360a, 0x00 },
+ { 0x0b00, 0x00 },
+ { 0x0106, 0x00 },
+ { 0x0b05, 0x01 },
+ { 0x0b06, 0x01 },
+ { 0x3230, 0x00 },
+ { 0x3602, 0x01 },
+ { 0x3607, 0x01 },
+ { 0x3c00, 0x00 },
+ { 0x3c01, 0xba },
+ { 0x3c02, 0xc8 },
+ { 0x3c03, 0xaa },
+ { 0x3c04, 0x91 },
+ { 0x3c05, 0x54 },
+ { 0x3c06, 0x26 },
+ { 0x3c07, 0x20 },
+ { 0x3c08, 0x51 },
+ { 0x3d80, 0x00 },
+ { 0x3f50, 0x00 },
+ { 0x3f56, 0x00 },
+ { 0x3f57, 0x30 },
+ { 0x3f78, 0x00 },
+ { 0x3f79, 0x34 },
+ { 0x3f7c, 0x00 },
+ { 0x3f7d, 0x00 },
+ { 0x3fba, 0x00 },
+ { 0x3fbb, 0x00 },
+ { 0xa081, 0x04 },
+ { 0xe014, 0x00 },
+ { 0x0202, 0x04 },
+ { 0x0203, 0xf6 },
+ { 0x0224, 0x01 },
+ { 0x0225, 0xf4 },
+ { 0x0204, 0x00 },
+ { 0x0205, 0x00 },
+ { 0x0216, 0x00 },
+ { 0x0217, 0x00 },
+ { 0x020e, 0x01 },
+ { 0x020f, 0x00 },
+ { 0x0210, 0x01 },
+ { 0x0211, 0x00 },
+ { 0x0212, 0x01 },
+ { 0x0213, 0x00 },
+ { 0x0214, 0x01 },
+ { 0x0215, 0x00 },
+ { 0x0218, 0x01 },
+ { 0x0219, 0x00 },
+ { 0x3614, 0x00 },
+ { 0x3616, 0x0d },
+ { 0x3617, 0x56 },
+ { 0xb612, 0x20 },
+ { 0xb613, 0x20 },
+ { 0xb614, 0x20 },
+ { 0xb615, 0x20 },
+ { 0xb616, 0x0a },
+ { 0xb617, 0x0a },
+ { 0xb618, 0x20 },
+ { 0xb619, 0x20 },
+ { 0xb61a, 0x20 },
+ { 0xb61b, 0x20 },
+ { 0xb61c, 0x0a },
+ { 0xb61d, 0x0a },
+ { 0xb666, 0x30 },
+ { 0xb667, 0x30 },
+ { 0xb668, 0x30 },
+ { 0xb669, 0x30 },
+ { 0xb66a, 0x14 },
+ { 0xb66b, 0x14 },
+ { 0xb66c, 0x20 },
+ { 0xb66d, 0x20 },
+ { 0xb66e, 0x20 },
+ { 0xb66f, 0x20 },
+ { 0xb670, 0x10 },
+ { 0xb671, 0x10 },
+ { 0x3237, 0x00 },
+ { 0x3900, 0x00 },
+ { 0x3901, 0x00 },
+ { 0x3902, 0x00 },
+ { 0x3904, 0x00 },
+ { 0x3905, 0x00 },
+ { 0x3906, 0x00 },
+ { 0x3907, 0x00 },
+ { 0x3908, 0x00 },
+ { 0x3909, 0x00 },
+ { 0x3912, 0x00 },
+ { 0x3930, 0x00 },
+ { 0x3931, 0x00 },
+ { 0x3933, 0x00 },
+ { 0x3934, 0x00 },
+ { 0x3935, 0x00 },
+ { 0x3936, 0x00 },
+ { 0x3937, 0x00 },
+ { 0x30ac, 0x00 },
+};
+
+static const char * const imx319_test_pattern_menu[] = {
+ "Disabled",
+ "100% color bars",
+ "Solid color",
+ "Fade to gray color bars",
+ "PN9"
+};
+
+/* supported link frequencies */
+static const s64 link_freq_menu_items[] = {
+ IMX319_LINK_FREQ_DEFAULT,
+};
+
+/* Mode configs */
+static const struct imx319_mode supported_modes[] = {
+ {
+ .width = 3280,
+ .height = 2464,
+ .fll_def = 3242,
+ .fll_min = 3242,
+ .llp = 3968,
+ .link_freq_index = IMX319_LINK_FREQ_INDEX,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_3280x2464_regs),
+ .regs = mode_3280x2464_regs,
+ },
+ },
+ {
+ .width = 3264,
+ .height = 2448,
+ .fll_def = 3242,
+ .fll_min = 3242,
+ .llp = 3968,
+ .link_freq_index = IMX319_LINK_FREQ_INDEX,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_3264x2448_regs),
+ .regs = mode_3264x2448_regs,
+ },
+ },
+ {
+ .width = 1936,
+ .height = 1096,
+ .fll_def = 3242,
+ .fll_min = 3242,
+ .llp = 3968,
+ .link_freq_index = IMX319_LINK_FREQ_INDEX,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_1936x1096_regs),
+ .regs = mode_1936x1096_regs,
+ },
+ },
+ {
+ .width = 1920,
+ .height = 1080,
+ .fll_def = 3242,
+ .fll_min = 3242,
+ .llp = 3968,
+ .link_freq_index = IMX319_LINK_FREQ_INDEX,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_1920x1080_regs),
+ .regs = mode_1920x1080_regs,
+ },
+ },
+ {
+ .width = 1640,
+ .height = 1232,
+ .fll_def = 5146,
+ .fll_min = 5146,
+ .llp = 2500,
+ .link_freq_index = IMX319_LINK_FREQ_INDEX,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_1640x1232_regs),
+ .regs = mode_1640x1232_regs,
+ },
+ },
+ {
+ .width = 1640,
+ .height = 922,
+ .fll_def = 5146,
+ .fll_min = 5146,
+ .llp = 2500,
+ .link_freq_index = IMX319_LINK_FREQ_INDEX,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_1640x922_regs),
+ .regs = mode_1640x922_regs,
+ },
+ },
+ {
+ .width = 1296,
+ .height = 736,
+ .fll_def = 5146,
+ .fll_min = 5146,
+ .llp = 2500,
+ .link_freq_index = IMX319_LINK_FREQ_INDEX,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_1296x736_regs),
+ .regs = mode_1296x736_regs,
+ },
+ },
+ {
+ .width = 1280,
+ .height = 720,
+ .fll_def = 5146,
+ .fll_min = 5146,
+ .llp = 2500,
+ .link_freq_index = IMX319_LINK_FREQ_INDEX,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_1280x720_regs),
+ .regs = mode_1280x720_regs,
+ },
+ },
+};
+
+static inline struct imx319 *to_imx319(struct v4l2_subdev *_sd)
+{
+ return container_of(_sd, struct imx319, sd);
+}
+
+/* Get bayer order based on flip setting. */
+static u32 imx319_get_format_code(struct imx319 *imx319)
+{
+ /*
+ * Only one bayer order is supported.
+ * It depends on the flip settings.
+ */
+ u32 code;
+ 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, },
+ };
+
+ lockdep_assert_held(&imx319->mutex);
+ code = codes[imx319->vflip->val][imx319->hflip->val];
+
+ return code;
+}
+
+/* Read registers up to 4 at a time */
+static int imx319_read_reg(struct imx319 *imx319, u16 reg, u32 len, u32 *val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx319->sd);
+ struct i2c_msg msgs[2];
+ u8 addr_buf[2];
+ u8 data_buf[4] = { 0 };
+ int ret;
+
+ if (len > 4)
+ return -EINVAL;
+
+ put_unaligned_be16(reg, addr_buf);
+ /* 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 imx319_write_reg(struct imx319 *imx319, u16 reg, u32 len, u32 val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx319->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 imx319_write_regs(struct imx319 *imx319,
+ const struct imx319_reg *regs, u32 len)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx319->sd);
+ int ret;
+ u32 i;
+
+ for (i = 0; i < len; i++) {
+ ret = imx319_write_reg(imx319, regs[i].address, 1, regs[i].val);
+ if (ret) {
+ dev_err_ratelimited(&client->dev,
+ "write reg 0x%4.4x return err %d",
+ regs[i].address, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/* Open sub-device */
+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);
+
+ mutex_lock(&imx319->mutex);
+
+ /* Initialize try_fmt */
+ try_fmt->width = imx319->cur_mode->width;
+ try_fmt->height = imx319->cur_mode->height;
+ try_fmt->code = imx319_get_format_code(imx319);
+ try_fmt->field = V4L2_FIELD_NONE;
+
+ mutex_unlock(&imx319->mutex);
+
+ return 0;
+}
+
+static int imx319_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct imx319 *imx319 = container_of(ctrl->handler,
+ struct imx319, ctrl_handler);
+ struct i2c_client *client = v4l2_get_subdevdata(&imx319->sd);
+ s64 max;
+ int ret;
+
+ /* Propagate change of current control to all related controls */
+ switch (ctrl->id) {
+ case V4L2_CID_VBLANK:
+ /* Update max exposure while meeting expected vblanking */
+ max = imx319->cur_mode->height + ctrl->val - 18;
+ __v4l2_ctrl_modify_range(imx319->exposure,
+ imx319->exposure->minimum,
+ max, imx319->exposure->step, max);
+ break;
+ }
+
+ /*
+ * 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:
+ /* Analog gain = 1024/(1024 - ctrl->val) times */
+ ret = imx319_write_reg(imx319, IMX319_REG_ANALOG_GAIN, 2,
+ ctrl->val);
+ break;
+ case V4L2_CID_DIGITAL_GAIN:
+ ret = imx319_write_reg(imx319, IMX319_REG_DIG_GAIN_GLOBAL, 2,
+ ctrl->val);
+ break;
+ case V4L2_CID_EXPOSURE:
+ ret = imx319_write_reg(imx319, IMX319_REG_EXPOSURE, 2,
+ ctrl->val);
+ break;
+ case V4L2_CID_VBLANK:
+ /* Update FLL that meets expected vertical blanking */
+ ret = imx319_write_reg(imx319, IMX319_REG_FLL, 2,
+ imx319->cur_mode->height + ctrl->val);
+ break;
+ case V4L2_CID_TEST_PATTERN:
+ ret = imx319_write_reg(imx319, IMX319_REG_TEST_PATTERN,
+ 2, ctrl->val);
+ break;
+ case V4L2_CID_HFLIP:
+ case V4L2_CID_VFLIP:
+ ret = imx319_write_reg(imx319, IMX319_REG_ORIENTATION, 1,
+ imx319->hflip->val |
+ imx319->vflip->val << 1);
+ break;
+ default:
+ ret = -EINVAL;
+ dev_info(&client->dev, "ctrl(id:0x%x,val:0x%x) is not handled",
+ ctrl->id, ctrl->val);
+ break;
+ }
+
+ pm_runtime_put(&client->dev);
+
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops imx319_ctrl_ops = {
+ .s_ctrl = imx319_set_ctrl,
+};
+
+static int imx319_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ struct imx319 *imx319 = to_imx319(sd);
+
+ if (code->index > 0)
+ return -EINVAL;
+
+ mutex_lock(&imx319->mutex);
+ code->code = imx319_get_format_code(imx319);
+ mutex_unlock(&imx319->mutex);
+
+ return 0;
+}
+
+static int imx319_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ struct imx319 *imx319 = to_imx319(sd);
+
+ if (fse->index >= ARRAY_SIZE(supported_modes))
+ return -EINVAL;
+
+ mutex_lock(&imx319->mutex);
+ if (fse->code != imx319_get_format_code(imx319)) {
+ mutex_unlock(&imx319->mutex);
+ return -EINVAL;
+ }
+ mutex_unlock(&imx319->mutex);
+
+ 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 imx319_update_pad_format(struct imx319 *imx319,
+ const struct imx319_mode *mode,
+ struct v4l2_subdev_format *fmt)
+{
+ fmt->format.width = mode->width;
+ fmt->format.height = mode->height;
+ fmt->format.code = imx319_get_format_code(imx319);
+ fmt->format.field = V4L2_FIELD_NONE;
+}
+
+static int imx319_do_get_pad_format(struct imx319 *imx319,
+ struct v4l2_subdev_pad_config *cfg,
+ 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);
+ fmt->format = *framefmt;
+ } else {
+ imx319_update_pad_format(imx319, imx319->cur_mode, fmt);
+ }
+
+ return 0;
+}
+
+static int imx319_get_pad_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ 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);
+ mutex_unlock(&imx319->mutex);
+
+ return ret;
+}
+
+static int
+imx319_set_pad_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct imx319 *imx319 = to_imx319(sd);
+ const struct imx319_mode *mode;
+ struct v4l2_mbus_framefmt *framefmt;
+ s32 vblank_def;
+ s32 vblank_min;
+ s64 h_blank;
+ u64 pixel_rate;
+ u32 height;
+
+ mutex_lock(&imx319->mutex);
+
+ /*
+ * Only one bayer order is supported.
+ * It depends on the flip settings.
+ */
+ fmt->format.code = imx319_get_format_code(imx319);
+
+ mode = v4l2_find_nearest_size(supported_modes,
+ ARRAY_SIZE(supported_modes),
+ width, height,
+ 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 = fmt->format;
+ } else {
+ imx319->cur_mode = mode;
+ pixel_rate = imx319->link_def_freq * 2 * 4;
+ do_div(pixel_rate, 10);
+ __v4l2_ctrl_s_ctrl_int64(imx319->pixel_rate, pixel_rate);
+ /* Update limits and set FPS to default */
+ height = imx319->cur_mode->height;
+ vblank_def = imx319->cur_mode->fll_def - height;
+ vblank_min = imx319->cur_mode->fll_min - height;
+ height = IMX319_FLL_MAX - height;
+ __v4l2_ctrl_modify_range(imx319->vblank, vblank_min, height, 1,
+ vblank_def);
+ __v4l2_ctrl_s_ctrl(imx319->vblank, vblank_def);
+ h_blank = mode->llp - imx319->cur_mode->width;
+ /*
+ * Currently hblank is not changeable.
+ * So FPS control is done only by vblank.
+ */
+ __v4l2_ctrl_modify_range(imx319->hblank, h_blank,
+ h_blank, 1, h_blank);
+ }
+
+ mutex_unlock(&imx319->mutex);
+
+ return 0;
+}
+
+/* Start streaming */
+static int imx319_start_streaming(struct imx319 *imx319)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx319->sd);
+ const struct imx319_reg_list *reg_list;
+ int ret;
+
+ /* Global Setting */
+ reg_list = &imx319_global_setting;
+ ret = imx319_write_regs(imx319, reg_list->regs, reg_list->num_of_regs);
+ if (ret) {
+ dev_err(&client->dev, "failed to set global settings");
+ return ret;
+ }
+
+ /* Apply default values of current mode */
+ reg_list = &imx319->cur_mode->reg_list;
+ ret = imx319_write_regs(imx319, reg_list->regs, reg_list->num_of_regs);
+ if (ret) {
+ dev_err(&client->dev, "failed to set mode");
+ return ret;
+ }
+
+ /* set digital gain control to all color mode */
+ ret = imx319_write_reg(imx319, IMX319_REG_DPGA_USE_GLOBAL_GAIN, 1, 1);
+ if (ret)
+ return ret;
+
+ /* Apply customized values from user */
+ ret = __v4l2_ctrl_handler_setup(imx319->sd.ctrl_handler);
+ if (ret)
+ return ret;
+
+ return imx319_write_reg(imx319, IMX319_REG_MODE_SELECT,
+ 1, IMX319_MODE_STREAMING);
+}
+
+/* Stop streaming */
+static int imx319_stop_streaming(struct imx319 *imx319)
+{
+ return imx319_write_reg(imx319, IMX319_REG_MODE_SELECT,
+ 1, IMX319_MODE_STANDBY);
+}
+
+static int imx319_set_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct imx319 *imx319 = to_imx319(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret = 0;
+
+ mutex_lock(&imx319->mutex);
+ if (imx319->streaming == enable) {
+ mutex_unlock(&imx319->mutex);
+ return 0;
+ }
+
+ if (enable) {
+ ret = pm_runtime_get_sync(&client->dev);
+ if (ret < 0) {
+ pm_runtime_put_noidle(&client->dev);
+ goto err_unlock;
+ }
+
+ /*
+ * Apply default & customized values
+ * and then start streaming.
+ */
+ ret = imx319_start_streaming(imx319);
+ if (ret)
+ goto err_rpm_put;
+ } else {
+ imx319_stop_streaming(imx319);
+ pm_runtime_put(&client->dev);
+ }
+
+ imx319->streaming = enable;
+
+ /* vflip and hflip cannot change during streaming */
+ __v4l2_ctrl_grab(imx319->vflip, enable);
+ __v4l2_ctrl_grab(imx319->hflip, enable);
+
+ mutex_unlock(&imx319->mutex);
+
+ return ret;
+
+err_rpm_put:
+ pm_runtime_put(&client->dev);
+err_unlock:
+ mutex_unlock(&imx319->mutex);
+
+ return ret;
+}
+
+static int __maybe_unused imx319_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct imx319 *imx319 = to_imx319(sd);
+
+ if (imx319->streaming)
+ imx319_stop_streaming(imx319);
+
+ return 0;
+}
+
+static int __maybe_unused imx319_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct imx319 *imx319 = to_imx319(sd);
+ int ret;
+
+ if (imx319->streaming) {
+ ret = imx319_start_streaming(imx319);
+ if (ret)
+ goto error;
+ }
+
+ return 0;
+
+error:
+ imx319_stop_streaming(imx319);
+ imx319->streaming = 0;
+ return ret;
+}
+
+/* Verify chip ID */
+static int imx319_identify_module(struct imx319 *imx319)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx319->sd);
+ int ret;
+ u32 val;
+
+ ret = imx319_read_reg(imx319, IMX319_REG_CHIP_ID, 2, &val);
+ if (ret)
+ return ret;
+
+ if (val != IMX319_CHIP_ID) {
+ dev_err(&client->dev, "chip id mismatch: %x!=%x",
+ IMX319_CHIP_ID, val);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_subdev_core_ops imx319_subdev_core_ops = {
+ .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+ .unsubscribe_event = v4l2_event_subdev_unsubscribe,
+};
+
+static const struct v4l2_subdev_video_ops imx319_video_ops = {
+ .s_stream = imx319_set_stream,
+};
+
+static const struct v4l2_subdev_pad_ops imx319_pad_ops = {
+ .enum_mbus_code = imx319_enum_mbus_code,
+ .get_fmt = imx319_get_pad_format,
+ .set_fmt = imx319_set_pad_format,
+ .enum_frame_size = imx319_enum_frame_size,
+};
+
+static const struct v4l2_subdev_ops imx319_subdev_ops = {
+ .core = &imx319_subdev_core_ops,
+ .video = &imx319_video_ops,
+ .pad = &imx319_pad_ops,
+};
+
+static const struct media_entity_operations imx319_subdev_entity_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+static const struct v4l2_subdev_internal_ops imx319_internal_ops = {
+ .open = imx319_open,
+};
+
+/* Initialize control handlers */
+static int imx319_init_controls(struct imx319 *imx319)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx319->sd);
+ struct v4l2_ctrl_handler *ctrl_hdlr;
+ s64 exposure_max;
+ s64 vblank_def;
+ s64 vblank_min;
+ s64 hblank;
+ u64 pixel_rate;
+ const struct imx319_mode *mode;
+ u32 max;
+ int ret;
+
+ ctrl_hdlr = &imx319->ctrl_handler;
+ ret = v4l2_ctrl_handler_init(ctrl_hdlr, 10);
+ if (ret)
+ return ret;
+
+ ctrl_hdlr->lock = &imx319->mutex;
+ max = ARRAY_SIZE(link_freq_menu_items) - 1;
+ imx319->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx319_ctrl_ops,
+ V4L2_CID_LINK_FREQ, max, 0,
+ link_freq_menu_items);
+ if (imx319->link_freq)
+ imx319->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ /* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample */
+ pixel_rate = imx319->link_def_freq * 2 * 4;
+ do_div(pixel_rate, 10);
+ /* By default, PIXEL_RATE is read only */
+ imx319->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx319_ctrl_ops,
+ V4L2_CID_PIXEL_RATE, pixel_rate,
+ pixel_rate, 1, pixel_rate);
+
+ /* Initial vblank/hblank/exposure parameters based on current mode */
+ mode = imx319->cur_mode;
+ vblank_def = mode->fll_def - mode->height;
+ vblank_min = mode->fll_min - mode->height;
+ imx319->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx319_ctrl_ops,
+ V4L2_CID_VBLANK, vblank_min,
+ IMX319_FLL_MAX - mode->height,
+ 1, vblank_def);
+
+ hblank = mode->llp - mode->width;
+ imx319->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx319_ctrl_ops,
+ V4L2_CID_HBLANK, hblank, hblank,
+ 1, hblank);
+ if (imx319->hblank)
+ imx319->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ /* fll >= exposure time + adjust parameter (default value is 18) */
+ exposure_max = mode->fll_def - 18;
+ imx319->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx319_ctrl_ops,
+ V4L2_CID_EXPOSURE,
+ IMX319_EXPOSURE_MIN, exposure_max,
+ IMX319_EXPOSURE_STEP,
+ IMX319_EXPOSURE_DEFAULT);
+
+ imx319->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx319_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ imx319->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx319_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+ v4l2_ctrl_new_std(ctrl_hdlr, &imx319_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
+ IMX319_ANA_GAIN_MIN, IMX319_ANA_GAIN_MAX,
+ IMX319_ANA_GAIN_STEP, IMX319_ANA_GAIN_DEFAULT);
+
+ /* Digital gain */
+ v4l2_ctrl_new_std(ctrl_hdlr, &imx319_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
+ IMX319_DGTL_GAIN_MIN, IMX319_DGTL_GAIN_MAX,
+ IMX319_DGTL_GAIN_STEP, IMX319_DGTL_GAIN_DEFAULT);
+
+ v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx319_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(imx319_test_pattern_menu) - 1,
+ 0, 0, imx319_test_pattern_menu);
+ if (ctrl_hdlr->error) {
+ ret = ctrl_hdlr->error;
+ dev_err(&client->dev, "control init failed: %d", ret);
+ goto error;
+ }
+
+ imx319->sd.ctrl_handler = ctrl_hdlr;
+
+ return 0;
+
+error:
+ v4l2_ctrl_handler_free(ctrl_hdlr);
+
+ return ret;
+}
+
+static struct imx319_hwcfg *imx319_get_hwcfg(struct device *dev)
+{
+ struct imx319_hwcfg *cfg;
+ struct v4l2_fwnode_endpoint bus_cfg = {
+ .bus_type = V4L2_MBUS_CSI2_DPHY
+ };
+ struct fwnode_handle *ep;
+ struct fwnode_handle *fwnode = dev_fwnode(dev);
+ unsigned int i;
+ int ret;
+
+ if (!fwnode)
+ return NULL;
+
+ ep = fwnode_graph_get_next_endpoint(fwnode, NULL);
+ if (!ep)
+ return NULL;
+
+ ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
+ if (ret)
+ goto out_err;
+
+ cfg = devm_kzalloc(dev, sizeof(*cfg), GFP_KERNEL);
+ if (!cfg)
+ goto out_err;
+
+ ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency",
+ &cfg->ext_clk);
+ if (ret) {
+ dev_err(dev, "can't get clock frequency");
+ goto out_err;
+ }
+
+ dev_dbg(dev, "ext clk: %d", cfg->ext_clk);
+ if (cfg->ext_clk != IMX319_EXT_CLK) {
+ dev_err(dev, "external clock %d is not supported",
+ cfg->ext_clk);
+ goto out_err;
+ }
+
+ dev_dbg(dev, "num of link freqs: %d", bus_cfg.nr_of_link_frequencies);
+ if (!bus_cfg.nr_of_link_frequencies) {
+ dev_warn(dev, "no link frequencies defined");
+ goto out_err;
+ }
+
+ cfg->nr_of_link_freqs = bus_cfg.nr_of_link_frequencies;
+ cfg->link_freqs = devm_kcalloc(dev,
+ bus_cfg.nr_of_link_frequencies + 1,
+ sizeof(*cfg->link_freqs), GFP_KERNEL);
+ if (!cfg->link_freqs)
+ goto out_err;
+
+ for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) {
+ cfg->link_freqs[i] = bus_cfg.link_frequencies[i];
+ dev_dbg(dev, "link_freq[%d] = %lld", i, cfg->link_freqs[i]);
+ }
+
+ v4l2_fwnode_endpoint_free(&bus_cfg);
+ fwnode_handle_put(ep);
+ return cfg;
+
+out_err:
+ v4l2_fwnode_endpoint_free(&bus_cfg);
+ fwnode_handle_put(ep);
+ return NULL;
+}
+
+static int imx319_probe(struct i2c_client *client)
+{
+ struct imx319 *imx319;
+ int ret;
+ u32 i;
+
+ imx319 = devm_kzalloc(&client->dev, sizeof(*imx319), GFP_KERNEL);
+ if (!imx319)
+ return -ENOMEM;
+
+ mutex_init(&imx319->mutex);
+
+ /* Initialize subdev */
+ v4l2_i2c_subdev_init(&imx319->sd, client, &imx319_subdev_ops);
+
+ /* Check module identity */
+ ret = imx319_identify_module(imx319);
+ if (ret) {
+ dev_err(&client->dev, "failed to find sensor: %d", ret);
+ goto error_probe;
+ }
+
+ imx319->hwcfg = imx319_get_hwcfg(&client->dev);
+ if (!imx319->hwcfg) {
+ dev_err(&client->dev, "failed to get hwcfg");
+ ret = -ENODEV;
+ goto error_probe;
+ }
+
+ imx319->link_def_freq = link_freq_menu_items[IMX319_LINK_FREQ_INDEX];
+ for (i = 0; i < imx319->hwcfg->nr_of_link_freqs; i++) {
+ if (imx319->hwcfg->link_freqs[i] == imx319->link_def_freq) {
+ dev_dbg(&client->dev, "link freq index %d matched", i);
+ break;
+ }
+ }
+
+ if (i == imx319->hwcfg->nr_of_link_freqs) {
+ dev_err(&client->dev, "no link frequency supported");
+ ret = -EINVAL;
+ goto error_probe;
+ }
+
+ /* Set default mode to max resolution */
+ imx319->cur_mode = &supported_modes[0];
+
+ ret = imx319_init_controls(imx319);
+ if (ret) {
+ dev_err(&client->dev, "failed to init controls: %d", ret);
+ goto error_probe;
+ }
+
+ /* Initialize subdev */
+ imx319->sd.internal_ops = &imx319_internal_ops;
+ imx319->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
+ V4L2_SUBDEV_FL_HAS_EVENTS;
+ imx319->sd.entity.ops = &imx319_subdev_entity_ops;
+ imx319->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+
+ /* Initialize source pad */
+ imx319->pad.flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_pads_init(&imx319->sd.entity, 1, &imx319->pad);
+ if (ret) {
+ dev_err(&client->dev, "failed to init entity pads: %d", ret);
+ goto error_handler_free;
+ }
+
+ ret = v4l2_async_register_subdev_sensor_common(&imx319->sd);
+ if (ret < 0)
+ goto error_media_entity;
+
+ /*
+ * Device is already turned on by i2c-core with ACPI domain PM.
+ * Enable runtime PM and turn off the device.
+ */
+ pm_runtime_set_active(&client->dev);
+ pm_runtime_enable(&client->dev);
+ pm_runtime_idle(&client->dev);
+
+ return 0;
+
+error_media_entity:
+ media_entity_cleanup(&imx319->sd.entity);
+
+error_handler_free:
+ v4l2_ctrl_handler_free(imx319->sd.ctrl_handler);
+
+error_probe:
+ mutex_destroy(&imx319->mutex);
+
+ return ret;
+}
+
+static int imx319_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct imx319 *imx319 = to_imx319(sd);
+
+ v4l2_async_unregister_subdev(sd);
+ media_entity_cleanup(&sd->entity);
+ v4l2_ctrl_handler_free(sd->ctrl_handler);
+
+ pm_runtime_disable(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
+
+ mutex_destroy(&imx319->mutex);
+
+ return 0;
+}
+
+static const struct dev_pm_ops imx319_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(imx319_suspend, imx319_resume)
+};
+
+static const struct acpi_device_id imx319_acpi_ids[] = {
+ { "SONY319A" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(acpi, imx319_acpi_ids);
+
+static struct i2c_driver imx319_i2c_driver = {
+ .driver = {
+ .name = "imx319",
+ .pm = &imx319_pm_ops,
+ .acpi_match_table = ACPI_PTR(imx319_acpi_ids),
+ },
+ .probe_new = imx319_probe,
+ .remove = imx319_remove,
+};
+module_i2c_driver(imx319_i2c_driver);
+
+MODULE_AUTHOR("Qiu, Tianshu <tian.shu.qiu@intel.com>");
+MODULE_AUTHOR("Rapolu, Chiranjeevi <chiranjeevi.rapolu@intel.com>");
+MODULE_AUTHOR("Bingbu Cao <bingbu.cao@intel.com>");
+MODULE_AUTHOR("Yang, Hyungwoo <hyungwoo.yang@intel.com>");
+MODULE_DESCRIPTION("Sony imx319 sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
new file mode 100644
index 000000000000..20c8eea5db4b
--- /dev/null
+++ b/drivers/media/i2c/imx355.c
@@ -0,0 +1,1860 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2018 Intel Corporation
+
+#include <asm/unaligned.h>
+#include <linux/acpi.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 <media/v4l2-event.h>
+#include <media/v4l2-fwnode.h>
+
+#define IMX355_REG_MODE_SELECT 0x0100
+#define IMX355_MODE_STANDBY 0x00
+#define IMX355_MODE_STREAMING 0x01
+
+/* Chip ID */
+#define IMX355_REG_CHIP_ID 0x0016
+#define IMX355_CHIP_ID 0x0355
+
+/* V_TIMING internal */
+#define IMX355_REG_FLL 0x0340
+#define IMX355_FLL_MAX 0xffff
+
+/* Exposure control */
+#define IMX355_REG_EXPOSURE 0x0202
+#define IMX355_EXPOSURE_MIN 1
+#define IMX355_EXPOSURE_STEP 1
+#define IMX355_EXPOSURE_DEFAULT 0x0282
+
+/* Analog gain control */
+#define IMX355_REG_ANALOG_GAIN 0x0204
+#define IMX355_ANA_GAIN_MIN 0
+#define IMX355_ANA_GAIN_MAX 960
+#define IMX355_ANA_GAIN_STEP 1
+#define IMX355_ANA_GAIN_DEFAULT 0
+
+/* Digital gain control */
+#define IMX355_REG_DPGA_USE_GLOBAL_GAIN 0x3070
+#define IMX355_REG_DIG_GAIN_GLOBAL 0x020e
+#define IMX355_DGTL_GAIN_MIN 256
+#define IMX355_DGTL_GAIN_MAX 4095
+#define IMX355_DGTL_GAIN_STEP 1
+#define IMX355_DGTL_GAIN_DEFAULT 256
+
+/* Test Pattern Control */
+#define IMX355_REG_TEST_PATTERN 0x0600
+#define IMX355_TEST_PATTERN_DISABLED 0
+#define IMX355_TEST_PATTERN_SOLID_COLOR 1
+#define IMX355_TEST_PATTERN_COLOR_BARS 2
+#define IMX355_TEST_PATTERN_GRAY_COLOR_BARS 3
+#define IMX355_TEST_PATTERN_PN9 4
+
+/* Flip Control */
+#define IMX355_REG_ORIENTATION 0x0101
+
+/* default link frequency and external clock */
+#define IMX355_LINK_FREQ_DEFAULT 360000000
+#define IMX355_EXT_CLK 19200000
+#define IMX355_LINK_FREQ_INDEX 0
+
+struct imx355_reg {
+ u16 address;
+ u8 val;
+};
+
+struct imx355_reg_list {
+ u32 num_of_regs;
+ const struct imx355_reg *regs;
+};
+
+/* Mode : resolution and related config&values */
+struct imx355_mode {
+ /* Frame width */
+ u32 width;
+ /* Frame height */
+ u32 height;
+
+ /* V-timing */
+ u32 fll_def;
+ u32 fll_min;
+
+ /* H-timing */
+ u32 llp;
+
+ /* index of link frequency */
+ u32 link_freq_index;
+
+ /* Default register values */
+ struct imx355_reg_list reg_list;
+};
+
+struct imx355_hwcfg {
+ u32 ext_clk; /* sensor external clk */
+ s64 *link_freqs; /* CSI-2 link frequencies */
+ unsigned int nr_of_link_freqs;
+};
+
+struct imx355 {
+ 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 *exposure;
+ struct v4l2_ctrl *vflip;
+ struct v4l2_ctrl *hflip;
+
+ /* Current mode */
+ const struct imx355_mode *cur_mode;
+
+ struct imx355_hwcfg *hwcfg;
+ s64 link_def_freq; /* CSI-2 link default frequency */
+
+ /*
+ * Mutex for serialized access:
+ * Protect sensor set pad format and start/stop streaming safely.
+ * Protect access to sensor v4l2 controls.
+ */
+ struct mutex mutex;
+
+ /* Streaming on/off */
+ bool streaming;
+};
+
+static const struct imx355_reg imx355_global_regs[] = {
+ { 0x0136, 0x13 },
+ { 0x0137, 0x33 },
+ { 0x304e, 0x03 },
+ { 0x4348, 0x16 },
+ { 0x4350, 0x19 },
+ { 0x4408, 0x0a },
+ { 0x440c, 0x0b },
+ { 0x4411, 0x5f },
+ { 0x4412, 0x2c },
+ { 0x4623, 0x00 },
+ { 0x462c, 0x0f },
+ { 0x462d, 0x00 },
+ { 0x462e, 0x00 },
+ { 0x4684, 0x54 },
+ { 0x480a, 0x07 },
+ { 0x4908, 0x07 },
+ { 0x4909, 0x07 },
+ { 0x490d, 0x0a },
+ { 0x491e, 0x0f },
+ { 0x4921, 0x06 },
+ { 0x4923, 0x28 },
+ { 0x4924, 0x28 },
+ { 0x4925, 0x29 },
+ { 0x4926, 0x29 },
+ { 0x4927, 0x1f },
+ { 0x4928, 0x20 },
+ { 0x4929, 0x20 },
+ { 0x492a, 0x20 },
+ { 0x492c, 0x05 },
+ { 0x492d, 0x06 },
+ { 0x492e, 0x06 },
+ { 0x492f, 0x06 },
+ { 0x4930, 0x03 },
+ { 0x4931, 0x04 },
+ { 0x4932, 0x04 },
+ { 0x4933, 0x05 },
+ { 0x595e, 0x01 },
+ { 0x5963, 0x01 },
+ { 0x3030, 0x01 },
+ { 0x3031, 0x01 },
+ { 0x3045, 0x01 },
+ { 0x4010, 0x00 },
+ { 0x4011, 0x00 },
+ { 0x4012, 0x00 },
+ { 0x4013, 0x01 },
+ { 0x68a8, 0xfe },
+ { 0x68a9, 0xff },
+ { 0x6888, 0x00 },
+ { 0x6889, 0x00 },
+ { 0x68b0, 0x00 },
+ { 0x3058, 0x00 },
+ { 0x305a, 0x00 },
+};
+
+static const struct imx355_reg_list imx355_global_setting = {
+ .num_of_regs = ARRAY_SIZE(imx355_global_regs),
+ .regs = imx355_global_regs,
+};
+
+static const struct imx355_reg mode_3268x2448_regs[] = {
+ { 0x0112, 0x0a },
+ { 0x0113, 0x0a },
+ { 0x0114, 0x03 },
+ { 0x0342, 0x0e },
+ { 0x0343, 0x58 },
+ { 0x0340, 0x0a },
+ { 0x0341, 0x37 },
+ { 0x0344, 0x00 },
+ { 0x0345, 0x08 },
+ { 0x0346, 0x00 },
+ { 0x0347, 0x08 },
+ { 0x0348, 0x0c },
+ { 0x0349, 0xcb },
+ { 0x034a, 0x09 },
+ { 0x034b, 0x97 },
+ { 0x0220, 0x00 },
+ { 0x0222, 0x01 },
+ { 0x0900, 0x00 },
+ { 0x0901, 0x11 },
+ { 0x0902, 0x00 },
+ { 0x034c, 0x0c },
+ { 0x034d, 0xc4 },
+ { 0x034e, 0x09 },
+ { 0x034f, 0x90 },
+ { 0x0301, 0x05 },
+ { 0x0303, 0x01 },
+ { 0x0305, 0x02 },
+ { 0x0306, 0x00 },
+ { 0x0307, 0x78 },
+ { 0x030b, 0x01 },
+ { 0x030d, 0x02 },
+ { 0x030e, 0x00 },
+ { 0x030f, 0x4b },
+ { 0x0310, 0x00 },
+ { 0x0700, 0x00 },
+ { 0x0701, 0x10 },
+ { 0x0820, 0x0b },
+ { 0x0821, 0x40 },
+ { 0x3088, 0x04 },
+ { 0x6813, 0x02 },
+ { 0x6835, 0x07 },
+ { 0x6836, 0x01 },
+ { 0x6837, 0x04 },
+ { 0x684d, 0x07 },
+ { 0x684e, 0x01 },
+ { 0x684f, 0x04 },
+};
+
+static const struct imx355_reg mode_3264x2448_regs[] = {
+ { 0x0112, 0x0a },
+ { 0x0113, 0x0a },
+ { 0x0114, 0x03 },
+ { 0x0342, 0x0e },
+ { 0x0343, 0x58 },
+ { 0x0340, 0x0a },
+ { 0x0341, 0x37 },
+ { 0x0344, 0x00 },
+ { 0x0345, 0x08 },
+ { 0x0346, 0x00 },
+ { 0x0347, 0x08 },
+ { 0x0348, 0x0c },
+ { 0x0349, 0xc7 },
+ { 0x034a, 0x09 },
+ { 0x034b, 0x97 },
+ { 0x0220, 0x00 },
+ { 0x0222, 0x01 },
+ { 0x0900, 0x00 },
+ { 0x0901, 0x11 },
+ { 0x0902, 0x00 },
+ { 0x034c, 0x0c },
+ { 0x034d, 0xc0 },
+ { 0x034e, 0x09 },
+ { 0x034f, 0x90 },
+ { 0x0301, 0x05 },
+ { 0x0303, 0x01 },
+ { 0x0305, 0x02 },
+ { 0x0306, 0x00 },
+ { 0x0307, 0x78 },
+ { 0x030b, 0x01 },
+ { 0x030d, 0x02 },
+ { 0x030e, 0x00 },
+ { 0x030f, 0x4b },
+ { 0x0310, 0x00 },
+ { 0x0700, 0x00 },
+ { 0x0701, 0x10 },
+ { 0x0820, 0x0b },
+ { 0x0821, 0x40 },
+ { 0x3088, 0x04 },
+ { 0x6813, 0x02 },
+ { 0x6835, 0x07 },
+ { 0x6836, 0x01 },
+ { 0x6837, 0x04 },
+ { 0x684d, 0x07 },
+ { 0x684e, 0x01 },
+ { 0x684f, 0x04 },
+};
+
+static const struct imx355_reg mode_3280x2464_regs[] = {
+ { 0x0112, 0x0a },
+ { 0x0113, 0x0a },
+ { 0x0114, 0x03 },
+ { 0x0342, 0x0e },
+ { 0x0343, 0x58 },
+ { 0x0340, 0x0a },
+ { 0x0341, 0x37 },
+ { 0x0344, 0x00 },
+ { 0x0345, 0x00 },
+ { 0x0346, 0x00 },
+ { 0x0347, 0x00 },
+ { 0x0348, 0x0c },
+ { 0x0349, 0xcf },
+ { 0x034a, 0x09 },
+ { 0x034b, 0x9f },
+ { 0x0220, 0x00 },
+ { 0x0222, 0x01 },
+ { 0x0900, 0x00 },
+ { 0x0901, 0x11 },
+ { 0x0902, 0x00 },
+ { 0x034c, 0x0c },
+ { 0x034d, 0xd0 },
+ { 0x034e, 0x09 },
+ { 0x034f, 0xa0 },
+ { 0x0301, 0x05 },
+ { 0x0303, 0x01 },
+ { 0x0305, 0x02 },
+ { 0x0306, 0x00 },
+ { 0x0307, 0x78 },
+ { 0x030b, 0x01 },
+ { 0x030d, 0x02 },
+ { 0x030e, 0x00 },
+ { 0x030f, 0x4b },
+ { 0x0310, 0x00 },
+ { 0x0700, 0x00 },
+ { 0x0701, 0x10 },
+ { 0x0820, 0x0b },
+ { 0x0821, 0x40 },
+ { 0x3088, 0x04 },
+ { 0x6813, 0x02 },
+ { 0x6835, 0x07 },
+ { 0x6836, 0x01 },
+ { 0x6837, 0x04 },
+ { 0x684d, 0x07 },
+ { 0x684e, 0x01 },
+ { 0x684f, 0x04 },
+};
+
+static const struct imx355_reg mode_1940x1096_regs[] = {
+ { 0x0112, 0x0a },
+ { 0x0113, 0x0a },
+ { 0x0114, 0x03 },
+ { 0x0342, 0x0e },
+ { 0x0343, 0x58 },
+ { 0x0340, 0x05 },
+ { 0x0341, 0x1a },
+ { 0x0344, 0x02 },
+ { 0x0345, 0xa0 },
+ { 0x0346, 0x02 },
+ { 0x0347, 0xac },
+ { 0x0348, 0x0a },
+ { 0x0349, 0x33 },
+ { 0x034a, 0x06 },
+ { 0x034b, 0xf3 },
+ { 0x0220, 0x00 },
+ { 0x0222, 0x01 },
+ { 0x0900, 0x00 },
+ { 0x0901, 0x11 },
+ { 0x0902, 0x00 },
+ { 0x034c, 0x07 },
+ { 0x034d, 0x94 },
+ { 0x034e, 0x04 },
+ { 0x034f, 0x48 },
+ { 0x0301, 0x05 },
+ { 0x0303, 0x01 },
+ { 0x0305, 0x02 },
+ { 0x0306, 0x00 },
+ { 0x0307, 0x78 },
+ { 0x030b, 0x01 },
+ { 0x030d, 0x02 },
+ { 0x030e, 0x00 },
+ { 0x030f, 0x4b },
+ { 0x0310, 0x00 },
+ { 0x0700, 0x00 },
+ { 0x0701, 0x10 },
+ { 0x0820, 0x0b },
+ { 0x0821, 0x40 },
+ { 0x3088, 0x04 },
+ { 0x6813, 0x02 },
+ { 0x6835, 0x07 },
+ { 0x6836, 0x01 },
+ { 0x6837, 0x04 },
+ { 0x684d, 0x07 },
+ { 0x684e, 0x01 },
+ { 0x684f, 0x04 },
+};
+
+static const struct imx355_reg mode_1936x1096_regs[] = {
+ { 0x0112, 0x0a },
+ { 0x0113, 0x0a },
+ { 0x0114, 0x03 },
+ { 0x0342, 0x0e },
+ { 0x0343, 0x58 },
+ { 0x0340, 0x05 },
+ { 0x0341, 0x1a },
+ { 0x0344, 0x02 },
+ { 0x0345, 0xa0 },
+ { 0x0346, 0x02 },
+ { 0x0347, 0xac },
+ { 0x0348, 0x0a },
+ { 0x0349, 0x2f },
+ { 0x034a, 0x06 },
+ { 0x034b, 0xf3 },
+ { 0x0220, 0x00 },
+ { 0x0222, 0x01 },
+ { 0x0900, 0x00 },
+ { 0x0901, 0x11 },
+ { 0x0902, 0x00 },
+ { 0x034c, 0x07 },
+ { 0x034d, 0x90 },
+ { 0x034e, 0x04 },
+ { 0x034f, 0x48 },
+ { 0x0301, 0x05 },
+ { 0x0303, 0x01 },
+ { 0x0305, 0x02 },
+ { 0x0306, 0x00 },
+ { 0x0307, 0x78 },
+ { 0x030b, 0x01 },
+ { 0x030d, 0x02 },
+ { 0x030e, 0x00 },
+ { 0x030f, 0x4b },
+ { 0x0310, 0x00 },
+ { 0x0700, 0x00 },
+ { 0x0701, 0x10 },
+ { 0x0820, 0x0b },
+ { 0x0821, 0x40 },
+ { 0x3088, 0x04 },
+ { 0x6813, 0x02 },
+ { 0x6835, 0x07 },
+ { 0x6836, 0x01 },
+ { 0x6837, 0x04 },
+ { 0x684d, 0x07 },
+ { 0x684e, 0x01 },
+ { 0x684f, 0x04 },
+};
+
+static const struct imx355_reg mode_1924x1080_regs[] = {
+ { 0x0112, 0x0a },
+ { 0x0113, 0x0a },
+ { 0x0114, 0x03 },
+ { 0x0342, 0x0e },
+ { 0x0343, 0x58 },
+ { 0x0340, 0x05 },
+ { 0x0341, 0x1a },
+ { 0x0344, 0x02 },
+ { 0x0345, 0xa8 },
+ { 0x0346, 0x02 },
+ { 0x0347, 0xb4 },
+ { 0x0348, 0x0a },
+ { 0x0349, 0x2b },
+ { 0x034a, 0x06 },
+ { 0x034b, 0xeb },
+ { 0x0220, 0x00 },
+ { 0x0222, 0x01 },
+ { 0x0900, 0x00 },
+ { 0x0901, 0x11 },
+ { 0x0902, 0x00 },
+ { 0x034c, 0x07 },
+ { 0x034d, 0x84 },
+ { 0x034e, 0x04 },
+ { 0x034f, 0x38 },
+ { 0x0301, 0x05 },
+ { 0x0303, 0x01 },
+ { 0x0305, 0x02 },
+ { 0x0306, 0x00 },
+ { 0x0307, 0x78 },
+ { 0x030b, 0x01 },
+ { 0x030d, 0x02 },
+ { 0x030e, 0x00 },
+ { 0x030f, 0x4b },
+ { 0x0310, 0x00 },
+ { 0x0700, 0x00 },
+ { 0x0701, 0x10 },
+ { 0x0820, 0x0b },
+ { 0x0821, 0x40 },
+ { 0x3088, 0x04 },
+ { 0x6813, 0x02 },
+ { 0x6835, 0x07 },
+ { 0x6836, 0x01 },
+ { 0x6837, 0x04 },
+ { 0x684d, 0x07 },
+ { 0x684e, 0x01 },
+ { 0x684f, 0x04 },
+};
+
+static const struct imx355_reg mode_1920x1080_regs[] = {
+ { 0x0112, 0x0a },
+ { 0x0113, 0x0a },
+ { 0x0114, 0x03 },
+ { 0x0342, 0x0e },
+ { 0x0343, 0x58 },
+ { 0x0340, 0x05 },
+ { 0x0341, 0x1a },
+ { 0x0344, 0x02 },
+ { 0x0345, 0xa8 },
+ { 0x0346, 0x02 },
+ { 0x0347, 0xb4 },
+ { 0x0348, 0x0a },
+ { 0x0349, 0x27 },
+ { 0x034a, 0x06 },
+ { 0x034b, 0xeb },
+ { 0x0220, 0x00 },
+ { 0x0222, 0x01 },
+ { 0x0900, 0x00 },
+ { 0x0901, 0x11 },
+ { 0x0902, 0x00 },
+ { 0x034c, 0x07 },
+ { 0x034d, 0x80 },
+ { 0x034e, 0x04 },
+ { 0x034f, 0x38 },
+ { 0x0301, 0x05 },
+ { 0x0303, 0x01 },
+ { 0x0305, 0x02 },
+ { 0x0306, 0x00 },
+ { 0x0307, 0x78 },
+ { 0x030b, 0x01 },
+ { 0x030d, 0x02 },
+ { 0x030e, 0x00 },
+ { 0x030f, 0x4b },
+ { 0x0310, 0x00 },
+ { 0x0700, 0x00 },
+ { 0x0701, 0x10 },
+ { 0x0820, 0x0b },
+ { 0x0821, 0x40 },
+ { 0x3088, 0x04 },
+ { 0x6813, 0x02 },
+ { 0x6835, 0x07 },
+ { 0x6836, 0x01 },
+ { 0x6837, 0x04 },
+ { 0x684d, 0x07 },
+ { 0x684e, 0x01 },
+ { 0x684f, 0x04 },
+};
+
+static const struct imx355_reg mode_1640x1232_regs[] = {
+ { 0x0112, 0x0a },
+ { 0x0113, 0x0a },
+ { 0x0114, 0x03 },
+ { 0x0342, 0x07 },
+ { 0x0343, 0x2c },
+ { 0x0340, 0x05 },
+ { 0x0341, 0x1a },
+ { 0x0344, 0x00 },
+ { 0x0345, 0x00 },
+ { 0x0346, 0x00 },
+ { 0x0347, 0x00 },
+ { 0x0348, 0x0c },
+ { 0x0349, 0xcf },
+ { 0x034a, 0x09 },
+ { 0x034b, 0x9f },
+ { 0x0220, 0x00 },
+ { 0x0222, 0x01 },
+ { 0x0900, 0x01 },
+ { 0x0901, 0x22 },
+ { 0x0902, 0x00 },
+ { 0x034c, 0x06 },
+ { 0x034d, 0x68 },
+ { 0x034e, 0x04 },
+ { 0x034f, 0xd0 },
+ { 0x0301, 0x05 },
+ { 0x0303, 0x01 },
+ { 0x0305, 0x02 },
+ { 0x0306, 0x00 },
+ { 0x0307, 0x78 },
+ { 0x030b, 0x01 },
+ { 0x030d, 0x02 },
+ { 0x030e, 0x00 },
+ { 0x030f, 0x4b },
+ { 0x0310, 0x00 },
+ { 0x0700, 0x00 },
+ { 0x0701, 0x10 },
+ { 0x0820, 0x0b },
+ { 0x0821, 0x40 },
+ { 0x3088, 0x04 },
+ { 0x6813, 0x02 },
+ { 0x6835, 0x07 },
+ { 0x6836, 0x01 },
+ { 0x6837, 0x04 },
+ { 0x684d, 0x07 },
+ { 0x684e, 0x01 },
+ { 0x684f, 0x04 },
+};
+
+static const struct imx355_reg mode_1640x922_regs[] = {
+ { 0x0112, 0x0a },
+ { 0x0113, 0x0a },
+ { 0x0114, 0x03 },
+ { 0x0342, 0x07 },
+ { 0x0343, 0x2c },
+ { 0x0340, 0x05 },
+ { 0x0341, 0x1a },
+ { 0x0344, 0x00 },
+ { 0x0345, 0x00 },
+ { 0x0346, 0x01 },
+ { 0x0347, 0x30 },
+ { 0x0348, 0x0c },
+ { 0x0349, 0xcf },
+ { 0x034a, 0x08 },
+ { 0x034b, 0x63 },
+ { 0x0220, 0x00 },
+ { 0x0222, 0x01 },
+ { 0x0900, 0x01 },
+ { 0x0901, 0x22 },
+ { 0x0902, 0x00 },
+ { 0x034c, 0x06 },
+ { 0x034d, 0x68 },
+ { 0x034e, 0x03 },
+ { 0x034f, 0x9a },
+ { 0x0301, 0x05 },
+ { 0x0303, 0x01 },
+ { 0x0305, 0x02 },
+ { 0x0306, 0x00 },
+ { 0x0307, 0x78 },
+ { 0x030b, 0x01 },
+ { 0x030d, 0x02 },
+ { 0x030e, 0x00 },
+ { 0x030f, 0x4b },
+ { 0x0310, 0x00 },
+ { 0x0700, 0x00 },
+ { 0x0701, 0x10 },
+ { 0x0820, 0x0b },
+ { 0x0821, 0x40 },
+ { 0x3088, 0x04 },
+ { 0x6813, 0x02 },
+ { 0x6835, 0x07 },
+ { 0x6836, 0x01 },
+ { 0x6837, 0x04 },
+ { 0x684d, 0x07 },
+ { 0x684e, 0x01 },
+ { 0x684f, 0x04 },
+};
+
+static const struct imx355_reg mode_1300x736_regs[] = {
+ { 0x0112, 0x0a },
+ { 0x0113, 0x0a },
+ { 0x0114, 0x03 },
+ { 0x0342, 0x07 },
+ { 0x0343, 0x2c },
+ { 0x0340, 0x05 },
+ { 0x0341, 0x1a },
+ { 0x0344, 0x01 },
+ { 0x0345, 0x58 },
+ { 0x0346, 0x01 },
+ { 0x0347, 0xf0 },
+ { 0x0348, 0x0b },
+ { 0x0349, 0x7f },
+ { 0x034a, 0x07 },
+ { 0x034b, 0xaf },
+ { 0x0220, 0x00 },
+ { 0x0222, 0x01 },
+ { 0x0900, 0x01 },
+ { 0x0901, 0x22 },
+ { 0x0902, 0x00 },
+ { 0x034c, 0x05 },
+ { 0x034d, 0x14 },
+ { 0x034e, 0x02 },
+ { 0x034f, 0xe0 },
+ { 0x0301, 0x05 },
+ { 0x0303, 0x01 },
+ { 0x0305, 0x02 },
+ { 0x0306, 0x00 },
+ { 0x0307, 0x78 },
+ { 0x030b, 0x01 },
+ { 0x030d, 0x02 },
+ { 0x030e, 0x00 },
+ { 0x030f, 0x4b },
+ { 0x0310, 0x00 },
+ { 0x0700, 0x00 },
+ { 0x0701, 0x10 },
+ { 0x0820, 0x0b },
+ { 0x0821, 0x40 },
+ { 0x3088, 0x04 },
+ { 0x6813, 0x02 },
+ { 0x6835, 0x07 },
+ { 0x6836, 0x01 },
+ { 0x6837, 0x04 },
+ { 0x684d, 0x07 },
+ { 0x684e, 0x01 },
+ { 0x684f, 0x04 },
+};
+
+static const struct imx355_reg mode_1296x736_regs[] = {
+ { 0x0112, 0x0a },
+ { 0x0113, 0x0a },
+ { 0x0114, 0x03 },
+ { 0x0342, 0x07 },
+ { 0x0343, 0x2c },
+ { 0x0340, 0x05 },
+ { 0x0341, 0x1a },
+ { 0x0344, 0x01 },
+ { 0x0345, 0x58 },
+ { 0x0346, 0x01 },
+ { 0x0347, 0xf0 },
+ { 0x0348, 0x0b },
+ { 0x0349, 0x77 },
+ { 0x034a, 0x07 },
+ { 0x034b, 0xaf },
+ { 0x0220, 0x00 },
+ { 0x0222, 0x01 },
+ { 0x0900, 0x01 },
+ { 0x0901, 0x22 },
+ { 0x0902, 0x00 },
+ { 0x034c, 0x05 },
+ { 0x034d, 0x10 },
+ { 0x034e, 0x02 },
+ { 0x034f, 0xe0 },
+ { 0x0301, 0x05 },
+ { 0x0303, 0x01 },
+ { 0x0305, 0x02 },
+ { 0x0306, 0x00 },
+ { 0x0307, 0x78 },
+ { 0x030b, 0x01 },
+ { 0x030d, 0x02 },
+ { 0x030e, 0x00 },
+ { 0x030f, 0x4b },
+ { 0x0310, 0x00 },
+ { 0x0700, 0x00 },
+ { 0x0701, 0x10 },
+ { 0x0820, 0x0b },
+ { 0x0821, 0x40 },
+ { 0x3088, 0x04 },
+ { 0x6813, 0x02 },
+ { 0x6835, 0x07 },
+ { 0x6836, 0x01 },
+ { 0x6837, 0x04 },
+ { 0x684d, 0x07 },
+ { 0x684e, 0x01 },
+ { 0x684f, 0x04 },
+};
+
+static const struct imx355_reg mode_1284x720_regs[] = {
+ { 0x0112, 0x0a },
+ { 0x0113, 0x0a },
+ { 0x0114, 0x03 },
+ { 0x0342, 0x07 },
+ { 0x0343, 0x2c },
+ { 0x0340, 0x05 },
+ { 0x0341, 0x1a },
+ { 0x0344, 0x01 },
+ { 0x0345, 0x68 },
+ { 0x0346, 0x02 },
+ { 0x0347, 0x00 },
+ { 0x0348, 0x0b },
+ { 0x0349, 0x6f },
+ { 0x034a, 0x07 },
+ { 0x034b, 0x9f },
+ { 0x0220, 0x00 },
+ { 0x0222, 0x01 },
+ { 0x0900, 0x01 },
+ { 0x0901, 0x22 },
+ { 0x0902, 0x00 },
+ { 0x034c, 0x05 },
+ { 0x034d, 0x04 },
+ { 0x034e, 0x02 },
+ { 0x034f, 0xd0 },
+ { 0x0301, 0x05 },
+ { 0x0303, 0x01 },
+ { 0x0305, 0x02 },
+ { 0x0306, 0x00 },
+ { 0x0307, 0x78 },
+ { 0x030b, 0x01 },
+ { 0x030d, 0x02 },
+ { 0x030e, 0x00 },
+ { 0x030f, 0x4b },
+ { 0x0310, 0x00 },
+ { 0x0700, 0x00 },
+ { 0x0701, 0x10 },
+ { 0x0820, 0x0b },
+ { 0x0821, 0x40 },
+ { 0x3088, 0x04 },
+ { 0x6813, 0x02 },
+ { 0x6835, 0x07 },
+ { 0x6836, 0x01 },
+ { 0x6837, 0x04 },
+ { 0x684d, 0x07 },
+ { 0x684e, 0x01 },
+ { 0x684f, 0x04 },
+};
+
+static const struct imx355_reg mode_1280x720_regs[] = {
+ { 0x0112, 0x0a },
+ { 0x0113, 0x0a },
+ { 0x0114, 0x03 },
+ { 0x0342, 0x07 },
+ { 0x0343, 0x2c },
+ { 0x0340, 0x05 },
+ { 0x0341, 0x1a },
+ { 0x0344, 0x01 },
+ { 0x0345, 0x68 },
+ { 0x0346, 0x02 },
+ { 0x0347, 0x00 },
+ { 0x0348, 0x0b },
+ { 0x0349, 0x67 },
+ { 0x034a, 0x07 },
+ { 0x034b, 0x9f },
+ { 0x0220, 0x00 },
+ { 0x0222, 0x01 },
+ { 0x0900, 0x01 },
+ { 0x0901, 0x22 },
+ { 0x0902, 0x00 },
+ { 0x034c, 0x05 },
+ { 0x034d, 0x00 },
+ { 0x034e, 0x02 },
+ { 0x034f, 0xd0 },
+ { 0x0301, 0x05 },
+ { 0x0303, 0x01 },
+ { 0x0305, 0x02 },
+ { 0x0306, 0x00 },
+ { 0x0307, 0x78 },
+ { 0x030b, 0x01 },
+ { 0x030d, 0x02 },
+ { 0x030e, 0x00 },
+ { 0x030f, 0x4b },
+ { 0x0310, 0x00 },
+ { 0x0700, 0x00 },
+ { 0x0701, 0x10 },
+ { 0x0820, 0x0b },
+ { 0x0821, 0x40 },
+ { 0x3088, 0x04 },
+ { 0x6813, 0x02 },
+ { 0x6835, 0x07 },
+ { 0x6836, 0x01 },
+ { 0x6837, 0x04 },
+ { 0x684d, 0x07 },
+ { 0x684e, 0x01 },
+ { 0x684f, 0x04 },
+};
+
+static const struct imx355_reg mode_820x616_regs[] = {
+ { 0x0112, 0x0a },
+ { 0x0113, 0x0a },
+ { 0x0114, 0x03 },
+ { 0x0342, 0x0e },
+ { 0x0343, 0x58 },
+ { 0x0340, 0x02 },
+ { 0x0341, 0x8c },
+ { 0x0344, 0x00 },
+ { 0x0345, 0x00 },
+ { 0x0346, 0x00 },
+ { 0x0347, 0x00 },
+ { 0x0348, 0x0c },
+ { 0x0349, 0xcf },
+ { 0x034a, 0x09 },
+ { 0x034b, 0x9f },
+ { 0x0220, 0x00 },
+ { 0x0222, 0x01 },
+ { 0x0900, 0x01 },
+ { 0x0901, 0x44 },
+ { 0x0902, 0x00 },
+ { 0x034c, 0x03 },
+ { 0x034d, 0x34 },
+ { 0x034e, 0x02 },
+ { 0x034f, 0x68 },
+ { 0x0301, 0x05 },
+ { 0x0303, 0x01 },
+ { 0x0305, 0x02 },
+ { 0x0306, 0x00 },
+ { 0x0307, 0x78 },
+ { 0x030b, 0x01 },
+ { 0x030d, 0x02 },
+ { 0x030e, 0x00 },
+ { 0x030f, 0x4b },
+ { 0x0310, 0x00 },
+ { 0x0700, 0x02 },
+ { 0x0701, 0x78 },
+ { 0x0820, 0x0b },
+ { 0x0821, 0x40 },
+ { 0x3088, 0x04 },
+ { 0x6813, 0x02 },
+ { 0x6835, 0x07 },
+ { 0x6836, 0x01 },
+ { 0x6837, 0x04 },
+ { 0x684d, 0x07 },
+ { 0x684e, 0x01 },
+ { 0x684f, 0x04 },
+};
+
+static const char * const imx355_test_pattern_menu[] = {
+ "Disabled",
+ "100% color bars",
+ "Solid color",
+ "Fade to gray color bars",
+ "PN9"
+};
+
+/* supported link frequencies */
+static const s64 link_freq_menu_items[] = {
+ IMX355_LINK_FREQ_DEFAULT,
+};
+
+/* Mode configs */
+static const struct imx355_mode supported_modes[] = {
+ {
+ .width = 3280,
+ .height = 2464,
+ .fll_def = 2615,
+ .fll_min = 2615,
+ .llp = 3672,
+ .link_freq_index = IMX355_LINK_FREQ_INDEX,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_3280x2464_regs),
+ .regs = mode_3280x2464_regs,
+ },
+ },
+ {
+ .width = 3268,
+ .height = 2448,
+ .fll_def = 2615,
+ .fll_min = 2615,
+ .llp = 3672,
+ .link_freq_index = IMX355_LINK_FREQ_INDEX,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_3268x2448_regs),
+ .regs = mode_3268x2448_regs,
+ },
+ },
+ {
+ .width = 3264,
+ .height = 2448,
+ .fll_def = 2615,
+ .fll_min = 2615,
+ .llp = 3672,
+ .link_freq_index = IMX355_LINK_FREQ_INDEX,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_3264x2448_regs),
+ .regs = mode_3264x2448_regs,
+ },
+ },
+ {
+ .width = 1940,
+ .height = 1096,
+ .fll_def = 1306,
+ .fll_min = 1306,
+ .llp = 3672,
+ .link_freq_index = IMX355_LINK_FREQ_INDEX,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_1940x1096_regs),
+ .regs = mode_1940x1096_regs,
+ },
+ },
+ {
+ .width = 1936,
+ .height = 1096,
+ .fll_def = 1306,
+ .fll_min = 1306,
+ .llp = 3672,
+ .link_freq_index = IMX355_LINK_FREQ_INDEX,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_1936x1096_regs),
+ .regs = mode_1936x1096_regs,
+ },
+ },
+ {
+ .width = 1924,
+ .height = 1080,
+ .fll_def = 1306,
+ .fll_min = 1306,
+ .llp = 3672,
+ .link_freq_index = IMX355_LINK_FREQ_INDEX,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_1924x1080_regs),
+ .regs = mode_1924x1080_regs,
+ },
+ },
+ {
+ .width = 1920,
+ .height = 1080,
+ .fll_def = 1306,
+ .fll_min = 1306,
+ .llp = 3672,
+ .link_freq_index = IMX355_LINK_FREQ_INDEX,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_1920x1080_regs),
+ .regs = mode_1920x1080_regs,
+ },
+ },
+ {
+ .width = 1640,
+ .height = 1232,
+ .fll_def = 1306,
+ .fll_min = 1306,
+ .llp = 1836,
+ .link_freq_index = IMX355_LINK_FREQ_INDEX,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_1640x1232_regs),
+ .regs = mode_1640x1232_regs,
+ },
+ },
+ {
+ .width = 1640,
+ .height = 922,
+ .fll_def = 1306,
+ .fll_min = 1306,
+ .llp = 1836,
+ .link_freq_index = IMX355_LINK_FREQ_INDEX,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_1640x922_regs),
+ .regs = mode_1640x922_regs,
+ },
+ },
+ {
+ .width = 1300,
+ .height = 736,
+ .fll_def = 1306,
+ .fll_min = 1306,
+ .llp = 1836,
+ .link_freq_index = IMX355_LINK_FREQ_INDEX,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_1300x736_regs),
+ .regs = mode_1300x736_regs,
+ },
+ },
+ {
+ .width = 1296,
+ .height = 736,
+ .fll_def = 1306,
+ .fll_min = 1306,
+ .llp = 1836,
+ .link_freq_index = IMX355_LINK_FREQ_INDEX,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_1296x736_regs),
+ .regs = mode_1296x736_regs,
+ },
+ },
+ {
+ .width = 1284,
+ .height = 720,
+ .fll_def = 1306,
+ .fll_min = 1306,
+ .llp = 1836,
+ .link_freq_index = IMX355_LINK_FREQ_INDEX,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_1284x720_regs),
+ .regs = mode_1284x720_regs,
+ },
+ },
+ {
+ .width = 1280,
+ .height = 720,
+ .fll_def = 1306,
+ .fll_min = 1306,
+ .llp = 1836,
+ .link_freq_index = IMX355_LINK_FREQ_INDEX,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_1280x720_regs),
+ .regs = mode_1280x720_regs,
+ },
+ },
+ {
+ .width = 820,
+ .height = 616,
+ .fll_def = 652,
+ .fll_min = 652,
+ .llp = 3672,
+ .link_freq_index = IMX355_LINK_FREQ_INDEX,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_820x616_regs),
+ .regs = mode_820x616_regs,
+ },
+ },
+};
+
+static inline struct imx355 *to_imx355(struct v4l2_subdev *_sd)
+{
+ return container_of(_sd, struct imx355, sd);
+}
+
+/* Get bayer order based on flip setting. */
+static u32 imx355_get_format_code(struct imx355 *imx355)
+{
+ /*
+ * Only one bayer order is supported.
+ * It depends on the flip settings.
+ */
+ u32 code;
+ 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, },
+ };
+
+ lockdep_assert_held(&imx355->mutex);
+ code = codes[imx355->vflip->val][imx355->hflip->val];
+
+ return code;
+}
+
+/* Read registers up to 4 at a time */
+static int imx355_read_reg(struct imx355 *imx355, u16 reg, u32 len, u32 *val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd);
+ struct i2c_msg msgs[2];
+ u8 addr_buf[2];
+ u8 data_buf[4] = { 0 };
+ int ret;
+
+ if (len > 4)
+ return -EINVAL;
+
+ put_unaligned_be16(reg, addr_buf);
+ /* 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 imx355_write_reg(struct imx355 *imx355, u16 reg, u32 len, u32 val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx355->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 imx355_write_regs(struct imx355 *imx355,
+ const struct imx355_reg *regs, u32 len)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd);
+ int ret;
+ u32 i;
+
+ for (i = 0; i < len; i++) {
+ ret = imx355_write_reg(imx355, regs[i].address, 1, regs[i].val);
+ if (ret) {
+ dev_err_ratelimited(&client->dev,
+ "write reg 0x%4.4x return err %d",
+ regs[i].address, ret);
+
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/* Open sub-device */
+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);
+
+ mutex_lock(&imx355->mutex);
+
+ /* Initialize try_fmt */
+ try_fmt->width = imx355->cur_mode->width;
+ try_fmt->height = imx355->cur_mode->height;
+ try_fmt->code = imx355_get_format_code(imx355);
+ try_fmt->field = V4L2_FIELD_NONE;
+
+ mutex_unlock(&imx355->mutex);
+
+ return 0;
+}
+
+static int imx355_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct imx355 *imx355 = container_of(ctrl->handler,
+ struct imx355, ctrl_handler);
+ struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd);
+ s64 max;
+ int ret;
+
+ /* Propagate change of current control to all related controls */
+ switch (ctrl->id) {
+ case V4L2_CID_VBLANK:
+ /* Update max exposure while meeting expected vblanking */
+ max = imx355->cur_mode->height + ctrl->val - 10;
+ __v4l2_ctrl_modify_range(imx355->exposure,
+ imx355->exposure->minimum,
+ max, imx355->exposure->step, max);
+ break;
+ }
+
+ /*
+ * 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:
+ /* Analog gain = 1024/(1024 - ctrl->val) times */
+ ret = imx355_write_reg(imx355, IMX355_REG_ANALOG_GAIN, 2,
+ ctrl->val);
+ break;
+ case V4L2_CID_DIGITAL_GAIN:
+ ret = imx355_write_reg(imx355, IMX355_REG_DIG_GAIN_GLOBAL, 2,
+ ctrl->val);
+ break;
+ case V4L2_CID_EXPOSURE:
+ ret = imx355_write_reg(imx355, IMX355_REG_EXPOSURE, 2,
+ ctrl->val);
+ break;
+ case V4L2_CID_VBLANK:
+ /* Update FLL that meets expected vertical blanking */
+ ret = imx355_write_reg(imx355, IMX355_REG_FLL, 2,
+ imx355->cur_mode->height + ctrl->val);
+ break;
+ case V4L2_CID_TEST_PATTERN:
+ ret = imx355_write_reg(imx355, IMX355_REG_TEST_PATTERN,
+ 2, ctrl->val);
+ break;
+ case V4L2_CID_HFLIP:
+ case V4L2_CID_VFLIP:
+ ret = imx355_write_reg(imx355, IMX355_REG_ORIENTATION, 1,
+ imx355->hflip->val |
+ imx355->vflip->val << 1);
+ break;
+ default:
+ ret = -EINVAL;
+ dev_info(&client->dev, "ctrl(id:0x%x,val:0x%x) is not handled",
+ ctrl->id, ctrl->val);
+ break;
+ }
+
+ pm_runtime_put(&client->dev);
+
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops imx355_ctrl_ops = {
+ .s_ctrl = imx355_set_ctrl,
+};
+
+static int imx355_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ struct imx355 *imx355 = to_imx355(sd);
+
+ if (code->index > 0)
+ return -EINVAL;
+
+ mutex_lock(&imx355->mutex);
+ code->code = imx355_get_format_code(imx355);
+ mutex_unlock(&imx355->mutex);
+
+ return 0;
+}
+
+static int imx355_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ struct imx355 *imx355 = to_imx355(sd);
+
+ if (fse->index >= ARRAY_SIZE(supported_modes))
+ return -EINVAL;
+
+ mutex_lock(&imx355->mutex);
+ if (fse->code != imx355_get_format_code(imx355)) {
+ mutex_unlock(&imx355->mutex);
+ return -EINVAL;
+ }
+ mutex_unlock(&imx355->mutex);
+
+ 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 imx355_update_pad_format(struct imx355 *imx355,
+ const struct imx355_mode *mode,
+ struct v4l2_subdev_format *fmt)
+{
+ fmt->format.width = mode->width;
+ fmt->format.height = mode->height;
+ fmt->format.code = imx355_get_format_code(imx355);
+ fmt->format.field = V4L2_FIELD_NONE;
+}
+
+static int imx355_do_get_pad_format(struct imx355 *imx355,
+ struct v4l2_subdev_pad_config *cfg,
+ 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);
+ fmt->format = *framefmt;
+ } else {
+ imx355_update_pad_format(imx355, imx355->cur_mode, fmt);
+ }
+
+ return 0;
+}
+
+static int imx355_get_pad_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ 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);
+ mutex_unlock(&imx355->mutex);
+
+ return ret;
+}
+
+static int
+imx355_set_pad_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct imx355 *imx355 = to_imx355(sd);
+ const struct imx355_mode *mode;
+ struct v4l2_mbus_framefmt *framefmt;
+ s32 vblank_def;
+ s32 vblank_min;
+ s64 h_blank;
+ u64 pixel_rate;
+ u32 height;
+
+ mutex_lock(&imx355->mutex);
+
+ /*
+ * Only one bayer order is supported.
+ * It depends on the flip settings.
+ */
+ fmt->format.code = imx355_get_format_code(imx355);
+
+ mode = v4l2_find_nearest_size(supported_modes,
+ ARRAY_SIZE(supported_modes),
+ width, height,
+ 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 = fmt->format;
+ } else {
+ imx355->cur_mode = mode;
+ pixel_rate = imx355->link_def_freq * 2 * 4;
+ do_div(pixel_rate, 10);
+ __v4l2_ctrl_s_ctrl_int64(imx355->pixel_rate, pixel_rate);
+ /* Update limits and set FPS to default */
+ height = imx355->cur_mode->height;
+ vblank_def = imx355->cur_mode->fll_def - height;
+ vblank_min = imx355->cur_mode->fll_min - height;
+ height = IMX355_FLL_MAX - height;
+ __v4l2_ctrl_modify_range(imx355->vblank, vblank_min, height, 1,
+ vblank_def);
+ __v4l2_ctrl_s_ctrl(imx355->vblank, vblank_def);
+ h_blank = mode->llp - imx355->cur_mode->width;
+ /*
+ * Currently hblank is not changeable.
+ * So FPS control is done only by vblank.
+ */
+ __v4l2_ctrl_modify_range(imx355->hblank, h_blank,
+ h_blank, 1, h_blank);
+ }
+
+ mutex_unlock(&imx355->mutex);
+
+ return 0;
+}
+
+/* Start streaming */
+static int imx355_start_streaming(struct imx355 *imx355)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd);
+ const struct imx355_reg_list *reg_list;
+ int ret;
+
+ /* Global Setting */
+ reg_list = &imx355_global_setting;
+ ret = imx355_write_regs(imx355, reg_list->regs, reg_list->num_of_regs);
+ if (ret) {
+ dev_err(&client->dev, "failed to set global settings");
+ return ret;
+ }
+
+ /* Apply default values of current mode */
+ reg_list = &imx355->cur_mode->reg_list;
+ ret = imx355_write_regs(imx355, reg_list->regs, reg_list->num_of_regs);
+ if (ret) {
+ dev_err(&client->dev, "failed to set mode");
+ return ret;
+ }
+
+ /* set digital gain control to all color mode */
+ ret = imx355_write_reg(imx355, IMX355_REG_DPGA_USE_GLOBAL_GAIN, 1, 1);
+ if (ret)
+ return ret;
+
+ /* Apply customized values from user */
+ ret = __v4l2_ctrl_handler_setup(imx355->sd.ctrl_handler);
+ if (ret)
+ return ret;
+
+ return imx355_write_reg(imx355, IMX355_REG_MODE_SELECT,
+ 1, IMX355_MODE_STREAMING);
+}
+
+/* Stop streaming */
+static int imx355_stop_streaming(struct imx355 *imx355)
+{
+ return imx355_write_reg(imx355, IMX355_REG_MODE_SELECT,
+ 1, IMX355_MODE_STANDBY);
+}
+
+static int imx355_set_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct imx355 *imx355 = to_imx355(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret = 0;
+
+ mutex_lock(&imx355->mutex);
+ if (imx355->streaming == enable) {
+ mutex_unlock(&imx355->mutex);
+ return 0;
+ }
+
+ if (enable) {
+ ret = pm_runtime_get_sync(&client->dev);
+ if (ret < 0) {
+ pm_runtime_put_noidle(&client->dev);
+ goto err_unlock;
+ }
+
+ /*
+ * Apply default & customized values
+ * and then start streaming.
+ */
+ ret = imx355_start_streaming(imx355);
+ if (ret)
+ goto err_rpm_put;
+ } else {
+ imx355_stop_streaming(imx355);
+ pm_runtime_put(&client->dev);
+ }
+
+ imx355->streaming = enable;
+
+ /* vflip and hflip cannot change during streaming */
+ __v4l2_ctrl_grab(imx355->vflip, enable);
+ __v4l2_ctrl_grab(imx355->hflip, enable);
+
+ mutex_unlock(&imx355->mutex);
+
+ return ret;
+
+err_rpm_put:
+ pm_runtime_put(&client->dev);
+err_unlock:
+ mutex_unlock(&imx355->mutex);
+
+ return ret;
+}
+
+static int __maybe_unused imx355_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct imx355 *imx355 = to_imx355(sd);
+
+ if (imx355->streaming)
+ imx355_stop_streaming(imx355);
+
+ return 0;
+}
+
+static int __maybe_unused imx355_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct imx355 *imx355 = to_imx355(sd);
+ int ret;
+
+ if (imx355->streaming) {
+ ret = imx355_start_streaming(imx355);
+ if (ret)
+ goto error;
+ }
+
+ return 0;
+
+error:
+ imx355_stop_streaming(imx355);
+ imx355->streaming = 0;
+ return ret;
+}
+
+/* Verify chip ID */
+static int imx355_identify_module(struct imx355 *imx355)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd);
+ int ret;
+ u32 val;
+
+ ret = imx355_read_reg(imx355, IMX355_REG_CHIP_ID, 2, &val);
+ if (ret)
+ return ret;
+
+ if (val != IMX355_CHIP_ID) {
+ dev_err(&client->dev, "chip id mismatch: %x!=%x",
+ IMX355_CHIP_ID, val);
+ return -EIO;
+ }
+ return 0;
+}
+
+static const struct v4l2_subdev_core_ops imx355_subdev_core_ops = {
+ .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+ .unsubscribe_event = v4l2_event_subdev_unsubscribe,
+};
+
+static const struct v4l2_subdev_video_ops imx355_video_ops = {
+ .s_stream = imx355_set_stream,
+};
+
+static const struct v4l2_subdev_pad_ops imx355_pad_ops = {
+ .enum_mbus_code = imx355_enum_mbus_code,
+ .get_fmt = imx355_get_pad_format,
+ .set_fmt = imx355_set_pad_format,
+ .enum_frame_size = imx355_enum_frame_size,
+};
+
+static const struct v4l2_subdev_ops imx355_subdev_ops = {
+ .core = &imx355_subdev_core_ops,
+ .video = &imx355_video_ops,
+ .pad = &imx355_pad_ops,
+};
+
+static const struct media_entity_operations imx355_subdev_entity_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+static const struct v4l2_subdev_internal_ops imx355_internal_ops = {
+ .open = imx355_open,
+};
+
+/* Initialize control handlers */
+static int imx355_init_controls(struct imx355 *imx355)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd);
+ struct v4l2_ctrl_handler *ctrl_hdlr;
+ s64 exposure_max;
+ s64 vblank_def;
+ s64 vblank_min;
+ s64 hblank;
+ u64 pixel_rate;
+ const struct imx355_mode *mode;
+ u32 max;
+ int ret;
+
+ ctrl_hdlr = &imx355->ctrl_handler;
+ ret = v4l2_ctrl_handler_init(ctrl_hdlr, 10);
+ if (ret)
+ return ret;
+
+ ctrl_hdlr->lock = &imx355->mutex;
+ max = ARRAY_SIZE(link_freq_menu_items) - 1;
+ imx355->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx355_ctrl_ops,
+ V4L2_CID_LINK_FREQ, max, 0,
+ link_freq_menu_items);
+ if (imx355->link_freq)
+ imx355->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ /* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample */
+ pixel_rate = imx355->link_def_freq * 2 * 4;
+ do_div(pixel_rate, 10);
+ /* By default, PIXEL_RATE is read only */
+ imx355->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops,
+ V4L2_CID_PIXEL_RATE, pixel_rate,
+ pixel_rate, 1, pixel_rate);
+
+ /* Initialize vblank/hblank/exposure parameters based on current mode */
+ mode = imx355->cur_mode;
+ vblank_def = mode->fll_def - mode->height;
+ vblank_min = mode->fll_min - mode->height;
+ imx355->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops,
+ V4L2_CID_VBLANK, vblank_min,
+ IMX355_FLL_MAX - mode->height,
+ 1, vblank_def);
+
+ hblank = mode->llp - mode->width;
+ imx355->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops,
+ V4L2_CID_HBLANK, hblank, hblank,
+ 1, hblank);
+ if (imx355->hblank)
+ imx355->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ /* fll >= exposure time + adjust parameter (default value is 10) */
+ exposure_max = mode->fll_def - 10;
+ imx355->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops,
+ V4L2_CID_EXPOSURE,
+ IMX355_EXPOSURE_MIN, exposure_max,
+ IMX355_EXPOSURE_STEP,
+ IMX355_EXPOSURE_DEFAULT);
+
+ imx355->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ imx355->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+ v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
+ IMX355_ANA_GAIN_MIN, IMX355_ANA_GAIN_MAX,
+ IMX355_ANA_GAIN_STEP, IMX355_ANA_GAIN_DEFAULT);
+
+ /* Digital gain */
+ v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
+ IMX355_DGTL_GAIN_MIN, IMX355_DGTL_GAIN_MAX,
+ IMX355_DGTL_GAIN_STEP, IMX355_DGTL_GAIN_DEFAULT);
+
+ v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx355_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(imx355_test_pattern_menu) - 1,
+ 0, 0, imx355_test_pattern_menu);
+ if (ctrl_hdlr->error) {
+ ret = ctrl_hdlr->error;
+ dev_err(&client->dev, "control init failed: %d", ret);
+ goto error;
+ }
+
+ imx355->sd.ctrl_handler = ctrl_hdlr;
+
+ return 0;
+
+error:
+ v4l2_ctrl_handler_free(ctrl_hdlr);
+
+ return ret;
+}
+
+static struct imx355_hwcfg *imx355_get_hwcfg(struct device *dev)
+{
+ struct imx355_hwcfg *cfg;
+ struct v4l2_fwnode_endpoint bus_cfg = {
+ .bus_type = V4L2_MBUS_CSI2_DPHY
+ };
+ struct fwnode_handle *ep;
+ struct fwnode_handle *fwnode = dev_fwnode(dev);
+ unsigned int i;
+ int ret;
+
+ if (!fwnode)
+ return NULL;
+
+ ep = fwnode_graph_get_next_endpoint(fwnode, NULL);
+ if (!ep)
+ return NULL;
+
+ ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
+ if (ret)
+ goto out_err;
+
+ cfg = devm_kzalloc(dev, sizeof(*cfg), GFP_KERNEL);
+ if (!cfg)
+ goto out_err;
+
+ ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency",
+ &cfg->ext_clk);
+ if (ret) {
+ dev_err(dev, "can't get clock frequency");
+ goto out_err;
+ }
+
+ dev_dbg(dev, "ext clk: %d", cfg->ext_clk);
+ if (cfg->ext_clk != IMX355_EXT_CLK) {
+ dev_err(dev, "external clock %d is not supported",
+ cfg->ext_clk);
+ goto out_err;
+ }
+
+ dev_dbg(dev, "num of link freqs: %d", bus_cfg.nr_of_link_frequencies);
+ if (!bus_cfg.nr_of_link_frequencies) {
+ dev_warn(dev, "no link frequencies defined");
+ goto out_err;
+ }
+
+ cfg->nr_of_link_freqs = bus_cfg.nr_of_link_frequencies;
+ cfg->link_freqs = devm_kcalloc(dev,
+ bus_cfg.nr_of_link_frequencies + 1,
+ sizeof(*cfg->link_freqs), GFP_KERNEL);
+ if (!cfg->link_freqs)
+ goto out_err;
+
+ for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) {
+ cfg->link_freqs[i] = bus_cfg.link_frequencies[i];
+ dev_dbg(dev, "link_freq[%d] = %lld", i, cfg->link_freqs[i]);
+ }
+
+ v4l2_fwnode_endpoint_free(&bus_cfg);
+ fwnode_handle_put(ep);
+ return cfg;
+
+out_err:
+ v4l2_fwnode_endpoint_free(&bus_cfg);
+ fwnode_handle_put(ep);
+ return NULL;
+}
+
+static int imx355_probe(struct i2c_client *client)
+{
+ struct imx355 *imx355;
+ int ret;
+ u32 i;
+
+ imx355 = devm_kzalloc(&client->dev, sizeof(*imx355), GFP_KERNEL);
+ if (!imx355)
+ return -ENOMEM;
+
+ mutex_init(&imx355->mutex);
+
+ /* Initialize subdev */
+ v4l2_i2c_subdev_init(&imx355->sd, client, &imx355_subdev_ops);
+
+ /* Check module identity */
+ ret = imx355_identify_module(imx355);
+ if (ret) {
+ dev_err(&client->dev, "failed to find sensor: %d", ret);
+ goto error_probe;
+ }
+
+ imx355->hwcfg = imx355_get_hwcfg(&client->dev);
+ if (!imx355->hwcfg) {
+ dev_err(&client->dev, "failed to get hwcfg");
+ ret = -ENODEV;
+ goto error_probe;
+ }
+
+ imx355->link_def_freq = link_freq_menu_items[IMX355_LINK_FREQ_INDEX];
+ for (i = 0; i < imx355->hwcfg->nr_of_link_freqs; i++) {
+ if (imx355->hwcfg->link_freqs[i] == imx355->link_def_freq) {
+ dev_dbg(&client->dev, "link freq index %d matched", i);
+ break;
+ }
+ }
+
+ if (i == imx355->hwcfg->nr_of_link_freqs) {
+ dev_err(&client->dev, "no link frequency supported");
+ ret = -EINVAL;
+ goto error_probe;
+ }
+
+ /* Set default mode to max resolution */
+ imx355->cur_mode = &supported_modes[0];
+
+ ret = imx355_init_controls(imx355);
+ if (ret) {
+ dev_err(&client->dev, "failed to init controls: %d", ret);
+ goto error_probe;
+ }
+
+ /* Initialize subdev */
+ imx355->sd.internal_ops = &imx355_internal_ops;
+ imx355->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
+ V4L2_SUBDEV_FL_HAS_EVENTS;
+ imx355->sd.entity.ops = &imx355_subdev_entity_ops;
+ imx355->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+
+ /* Initialize source pad */
+ imx355->pad.flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_pads_init(&imx355->sd.entity, 1, &imx355->pad);
+ if (ret) {
+ dev_err(&client->dev, "failed to init entity pads: %d", ret);
+ goto error_handler_free;
+ }
+
+ ret = v4l2_async_register_subdev_sensor_common(&imx355->sd);
+ if (ret < 0)
+ goto error_media_entity;
+
+ /*
+ * Device is already turned on by i2c-core with ACPI domain PM.
+ * Enable runtime PM and turn off the device.
+ */
+ pm_runtime_set_active(&client->dev);
+ pm_runtime_enable(&client->dev);
+ pm_runtime_idle(&client->dev);
+
+ return 0;
+
+error_media_entity:
+ media_entity_cleanup(&imx355->sd.entity);
+
+error_handler_free:
+ v4l2_ctrl_handler_free(imx355->sd.ctrl_handler);
+
+error_probe:
+ mutex_destroy(&imx355->mutex);
+
+ return ret;
+}
+
+static int imx355_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct imx355 *imx355 = to_imx355(sd);
+
+ v4l2_async_unregister_subdev(sd);
+ media_entity_cleanup(&sd->entity);
+ v4l2_ctrl_handler_free(sd->ctrl_handler);
+
+ pm_runtime_disable(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
+
+ mutex_destroy(&imx355->mutex);
+
+ return 0;
+}
+
+static const struct dev_pm_ops imx355_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(imx355_suspend, imx355_resume)
+};
+
+static const struct acpi_device_id imx355_acpi_ids[] = {
+ { "SONY355A" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(acpi, imx355_acpi_ids);
+
+static struct i2c_driver imx355_i2c_driver = {
+ .driver = {
+ .name = "imx355",
+ .pm = &imx355_pm_ops,
+ .acpi_match_table = ACPI_PTR(imx355_acpi_ids),
+ },
+ .probe_new = imx355_probe,
+ .remove = imx355_remove,
+};
+module_i2c_driver(imx355_i2c_driver);
+
+MODULE_AUTHOR("Qiu, Tianshu <tian.shu.qiu@intel.com>");
+MODULE_AUTHOR("Rapolu, Chiranjeevi <chiranjeevi.rapolu@intel.com>");
+MODULE_AUTHOR("Bingbu Cao <bingbu.cao@intel.com>");
+MODULE_AUTHOR("Yang, Hyungwoo <hyungwoo.yang@intel.com>");
+MODULE_DESCRIPTION("Sony imx355 sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/lm3560.c b/drivers/media/i2c/lm3560.c
index 49c6644cbba7..f122f03bd6b7 100644
--- a/drivers/media/i2c/lm3560.c
+++ b/drivers/media/i2c/lm3560.c
@@ -362,7 +362,8 @@ static int lm3560_subdev_init(struct lm3560_flash *flash,
v4l2_i2c_subdev_init(&flash->subdev_led[led_no], client, &lm3560_ops);
flash->subdev_led[led_no].flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
- strcpy(flash->subdev_led[led_no].name, led_name);
+ strscpy(flash->subdev_led[led_no].name, led_name,
+ sizeof(flash->subdev_led[led_no].name));
rval = lm3560_init_controls(flash, led_no);
if (rval)
goto err_out;
diff --git a/drivers/media/i2c/lm3646.c b/drivers/media/i2c/lm3646.c
index 7e9967af36ec..12ef2653987b 100644
--- a/drivers/media/i2c/lm3646.c
+++ b/drivers/media/i2c/lm3646.c
@@ -278,7 +278,8 @@ static int lm3646_subdev_init(struct lm3646_flash *flash)
v4l2_i2c_subdev_init(&flash->subdev_led, client, &lm3646_ops);
flash->subdev_led.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
- strcpy(flash->subdev_led.name, LM3646_NAME);
+ strscpy(flash->subdev_led.name, LM3646_NAME,
+ sizeof(flash->subdev_led.name));
rval = lm3646_init_controls(flash);
if (rval)
goto err_out;
diff --git a/drivers/media/i2c/m5mols/m5mols_core.c b/drivers/media/i2c/m5mols/m5mols_core.c
index 12e79f9e32d5..b8b2bf4cbfb2 100644
--- a/drivers/media/i2c/m5mols/m5mols_core.c
+++ b/drivers/media/i2c/m5mols/m5mols_core.c
@@ -987,7 +987,8 @@ static int m5mols_probe(struct i2c_client *client,
sd = &info->sd;
v4l2_i2c_subdev_init(sd, client, &m5mols_ops);
- strlcpy(sd->name, MODULE_NAME, sizeof(sd->name));
+ /* Static name; NEVER use in new drivers! */
+ strscpy(sd->name, MODULE_NAME, sizeof(sd->name));
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
sd->internal_ops = &m5mols_subdev_internal_ops;
diff --git a/drivers/media/i2c/max2175.c b/drivers/media/i2c/max2175.c
index 008a082cb8ad..7b226fadcdb8 100644
--- a/drivers/media/i2c/max2175.c
+++ b/drivers/media/i2c/max2175.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Maxim Integrated MAX2175 RF to Bits tuner driver
*
@@ -6,15 +7,6 @@
*
* Copyright (C) 2016 Maxim Integrated Products
* Copyright (C) 2017 Renesas Electronics Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/clk.h>
@@ -1165,7 +1157,7 @@ static int max2175_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
if (vt->index > 0)
return -EINVAL;
- strlcpy(vt->name, "RF", sizeof(vt->name));
+ strscpy(vt->name, "RF", sizeof(vt->name));
vt->type = V4L2_TUNER_RF;
vt->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
vt->rangelow = ctx->bands_rf->rangelow;
diff --git a/drivers/media/i2c/max2175.h b/drivers/media/i2c/max2175.h
index eb43373ce7e2..1ece587c153d 100644
--- a/drivers/media/i2c/max2175.h
+++ b/drivers/media/i2c/max2175.h
@@ -1,4 +1,5 @@
-/*
+/* SPDX-License-Identifier: GPL-2.0
+ *
* Maxim Integrated MAX2175 RF to Bits tuner driver
*
* This driver & most of the hard coded values are based on the reference
@@ -6,15 +7,6 @@
*
* Copyright (C) 2016 Maxim Integrated Products
* Copyright (C) 2017 Renesas Electronics Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#ifndef __MAX2175_H__
diff --git a/drivers/media/i2c/msp3400-driver.c b/drivers/media/i2c/msp3400-driver.c
index 3db966db83eb..c63be01059b2 100644
--- a/drivers/media/i2c/msp3400-driver.c
+++ b/drivers/media/i2c/msp3400-driver.c
@@ -688,7 +688,7 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id)
#endif
if (!id)
- strlcpy(client->name, "msp3400", sizeof(client->name));
+ strscpy(client->name, "msp3400", sizeof(client->name));
if (msp_reset(client) == -1) {
dev_dbg_lvl(&client->dev, 1, msp_debug, "msp3400 not found\n");
@@ -703,8 +703,10 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id)
v4l2_i2c_subdev_init(sd, client, &msp_ops);
#if defined(CONFIG_MEDIA_CONTROLLER)
- state->pads[IF_AUD_DEC_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK;
- state->pads[IF_AUD_DEC_PAD_OUT].flags = MEDIA_PAD_FL_SOURCE;
+ state->pads[MSP3400_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK;
+ state->pads[MSP3400_PAD_IF_INPUT].sig_type = PAD_SIGNAL_AUDIO;
+ state->pads[MSP3400_PAD_OUT].flags = MEDIA_PAD_FL_SOURCE;
+ state->pads[MSP3400_PAD_OUT].sig_type = PAD_SIGNAL_AUDIO;
sd->entity.function = MEDIA_ENT_F_IF_AUD_DECODER;
diff --git a/drivers/media/i2c/msp3400-driver.h b/drivers/media/i2c/msp3400-driver.h
index b6c7698bce5a..2bb9d5ff1bbd 100644
--- a/drivers/media/i2c/msp3400-driver.h
+++ b/drivers/media/i2c/msp3400-driver.h
@@ -52,6 +52,12 @@ extern int msp_standard;
extern bool msp_dolby;
extern int msp_stereo_thresh;
+enum msp3400_pads {
+ MSP3400_PAD_IF_INPUT,
+ MSP3400_PAD_OUT,
+ MSP3400_NUM_PADS
+};
+
struct msp_state {
struct v4l2_subdev sd;
struct v4l2_ctrl_handler hdl;
@@ -106,7 +112,7 @@ struct msp_state {
unsigned int watch_stereo:1;
#if IS_ENABLED(CONFIG_MEDIA_CONTROLLER)
- struct media_pad pads[IF_AUD_DEC_PAD_NUM_PADS];
+ struct media_pad pads[MSP3400_NUM_PADS];
#endif
};
diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c
index efda1aa95ca0..1395986a07bb 100644
--- a/drivers/media/i2c/mt9m111.c
+++ b/drivers/media/i2c/mt9m111.c
@@ -445,7 +445,6 @@ static int mt9m111_get_selection(struct v4l2_subdev *sd,
switch (sel->target) {
case V4L2_SEL_TGT_CROP_BOUNDS:
- case V4L2_SEL_TGT_CROP_DEFAULT:
sel->r.left = MT9M111_MIN_DARK_COLS;
sel->r.top = MT9M111_MIN_DARK_ROWS;
sel->r.width = MT9M111_MAX_WIDTH;
diff --git a/drivers/media/i2c/mt9t112.c b/drivers/media/i2c/mt9t112.c
index af8cca984215..ef353a244e33 100644
--- a/drivers/media/i2c/mt9t112.c
+++ b/drivers/media/i2c/mt9t112.c
@@ -888,12 +888,6 @@ static int mt9t112_get_selection(struct v4l2_subdev *sd,
sel->r.width = MAX_WIDTH;
sel->r.height = MAX_HEIGHT;
return 0;
- case V4L2_SEL_TGT_CROP_DEFAULT:
- sel->r.left = 0;
- sel->r.top = 0;
- sel->r.width = VGA_WIDTH;
- sel->r.height = VGA_HEIGHT;
- return 0;
case V4L2_SEL_TGT_CROP:
sel->r = priv->frame;
return 0;
diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c
index f74730d24d8f..67f69ad6ecf4 100644
--- a/drivers/media/i2c/mt9v032.c
+++ b/drivers/media/i2c/mt9v032.c
@@ -989,7 +989,7 @@ static struct mt9v032_platform_data *
mt9v032_get_pdata(struct i2c_client *client)
{
struct mt9v032_platform_data *pdata = NULL;
- struct v4l2_fwnode_endpoint endpoint;
+ struct v4l2_fwnode_endpoint endpoint = { .bus_type = 0 };
struct device_node *np;
struct property *prop;
diff --git a/drivers/media/i2c/noon010pc30.c b/drivers/media/i2c/noon010pc30.c
index 88c498ad45df..11479e65a9ae 100644
--- a/drivers/media/i2c/noon010pc30.c
+++ b/drivers/media/i2c/noon010pc30.c
@@ -720,7 +720,8 @@ static int noon010_probe(struct i2c_client *client,
mutex_init(&info->lock);
sd = &info->sd;
v4l2_i2c_subdev_init(sd, client, &noon010_ops);
- strlcpy(sd->name, MODULE_NAME, sizeof(sd->name));
+ /* Static name; NEVER use in new drivers! */
+ strscpy(sd->name, MODULE_NAME, sizeof(sd->name));
sd->internal_ops = &noon010_subdev_internal_ops;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c
index a66f6201f53c..c8bbc1f52261 100644
--- a/drivers/media/i2c/ov13858.c
+++ b/drivers/media/i2c/ov13858.c
@@ -1230,7 +1230,7 @@ static int ov13858_set_ctrl(struct v4l2_ctrl *ctrl)
* Applying V4L2 control value only happens
* when power is up for streaming
*/
- if (pm_runtime_get_if_in_use(&client->dev) <= 0)
+ if (!pm_runtime_get_if_in_use(&client->dev))
return 0;
ret = 0;
@@ -1735,10 +1735,9 @@ static int ov13858_probe(struct i2c_client *client,
* Device is already turned on by i2c-core with ACPI domain PM.
* Enable runtime PM and turn off the device.
*/
- pm_runtime_get_noresume(&client->dev);
pm_runtime_set_active(&client->dev);
pm_runtime_enable(&client->dev);
- pm_runtime_put(&client->dev);
+ pm_runtime_idle(&client->dev);
return 0;
@@ -1761,14 +1760,7 @@ static int ov13858_remove(struct i2c_client *client)
media_entity_cleanup(&sd->entity);
ov13858_free_controls(ov13858);
- /*
- * Disable runtime PM but keep the device turned on.
- * i2c-core with ACPI domain PM will turn off the device.
- */
- pm_runtime_get_sync(&client->dev);
pm_runtime_disable(&client->dev);
- pm_runtime_set_suspended(&client->dev);
- pm_runtime_put_noidle(&client->dev);
return 0;
}
diff --git a/drivers/media/i2c/ov2640.c b/drivers/media/i2c/ov2640.c
index beb722065152..20a8853ba1e2 100644
--- a/drivers/media/i2c/ov2640.c
+++ b/drivers/media/i2c/ov2640.c
@@ -1010,7 +1010,6 @@ static int ov2640_get_selection(struct v4l2_subdev *sd,
switch (sel->target) {
case V4L2_SEL_TGT_CROP_BOUNDS:
- case V4L2_SEL_TGT_CROP_DEFAULT:
case V4L2_SEL_TGT_CROP:
sel->r.left = 0;
sel->r.top = 0;
diff --git a/drivers/media/i2c/ov2659.c b/drivers/media/i2c/ov2659.c
index 4715edc8ca33..799acce803fe 100644
--- a/drivers/media/i2c/ov2659.c
+++ b/drivers/media/i2c/ov2659.c
@@ -1347,8 +1347,9 @@ static struct ov2659_platform_data *
ov2659_get_pdata(struct i2c_client *client)
{
struct ov2659_platform_data *pdata;
- struct v4l2_fwnode_endpoint *bus_cfg;
+ struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 };
struct device_node *endpoint;
+ int ret;
if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node)
return client->dev.platform_data;
@@ -1357,8 +1358,9 @@ ov2659_get_pdata(struct i2c_client *client)
if (!endpoint)
return NULL;
- bus_cfg = v4l2_fwnode_endpoint_alloc_parse(of_fwnode_handle(endpoint));
- if (IS_ERR(bus_cfg)) {
+ ret = v4l2_fwnode_endpoint_alloc_parse(of_fwnode_handle(endpoint),
+ &bus_cfg);
+ if (ret) {
pdata = NULL;
goto done;
}
@@ -1367,17 +1369,17 @@ ov2659_get_pdata(struct i2c_client *client)
if (!pdata)
goto done;
- if (!bus_cfg->nr_of_link_frequencies) {
+ if (!bus_cfg.nr_of_link_frequencies) {
dev_err(&client->dev,
"link-frequencies property not found or too many\n");
pdata = NULL;
goto done;
}
- pdata->link_frequency = bus_cfg->link_frequencies[0];
+ pdata->link_frequency = bus_cfg.link_frequencies[0];
done:
- v4l2_fwnode_endpoint_free(bus_cfg);
+ v4l2_fwnode_endpoint_free(&bus_cfg);
of_node_put(endpoint);
return pdata;
}
diff --git a/drivers/media/i2c/ov2680.c b/drivers/media/i2c/ov2680.c
index f753a1c333ef..0e34e15b67b3 100644
--- a/drivers/media/i2c/ov2680.c
+++ b/drivers/media/i2c/ov2680.c
@@ -926,7 +926,7 @@ static int ov2680_mode_init(struct ov2680_dev *sensor)
return 0;
}
-static int ov2680_v4l2_init(struct ov2680_dev *sensor)
+static int ov2680_v4l2_register(struct ov2680_dev *sensor)
{
const struct v4l2_ctrl_ops *ops = &ov2680_ctrl_ops;
struct ov2680_ctrls *ctrls = &sensor->ctrls;
@@ -1088,26 +1088,20 @@ static int ov2680_probe(struct i2c_client *client)
mutex_init(&sensor->lock);
- ret = ov2680_v4l2_init(sensor);
+ ret = ov2680_check_id(sensor);
if (ret < 0)
goto lock_destroy;
- ret = ov2680_check_id(sensor);
+ ret = ov2680_v4l2_register(sensor);
if (ret < 0)
- goto error_cleanup;
+ goto lock_destroy;
dev_info(dev, "ov2680 init correctly\n");
return 0;
-error_cleanup:
- dev_err(dev, "ov2680 init fail: %d\n", ret);
-
- media_entity_cleanup(&sensor->sd.entity);
- v4l2_async_unregister_subdev(&sensor->sd);
- v4l2_ctrl_handler_free(&sensor->ctrls.handler);
-
lock_destroy:
+ dev_err(dev, "ov2680 init fail: %d\n", ret);
mutex_destroy(&sensor->lock);
return ret;
diff --git a/drivers/media/i2c/ov2685.c b/drivers/media/i2c/ov2685.c
index 385c1886a947..98a1f2e312b5 100644
--- a/drivers/media/i2c/ov2685.c
+++ b/drivers/media/i2c/ov2685.c
@@ -549,7 +549,7 @@ static int ov2685_set_ctrl(struct v4l2_ctrl *ctrl)
break;
}
- if (pm_runtime_get_if_in_use(&client->dev) <= 0)
+ if (!pm_runtime_get_if_in_use(&client->dev))
return 0;
switch (ctrl->id) {
diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c
index 071f4bc240ca..eaefdb58653b 100644
--- a/drivers/media/i2c/ov5640.c
+++ b/drivers/media/i2c/ov5640.c
@@ -223,8 +223,10 @@ struct ov5640_dev {
int power_count;
struct v4l2_mbus_framefmt fmt;
+ bool pending_fmt_change;
const struct ov5640_mode_info *current_mode;
+ const struct ov5640_mode_info *last_mode;
enum ov5640_frame_rate current_fr;
struct v4l2_fract frame_interval;
@@ -255,7 +257,7 @@ static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
* should be identified and removed to speed register load time
* over i2c.
*/
-
+/* YUV422 UYVY VGA@30fps */
static const struct reg_value ov5640_init_setting_30fps_VGA[] = {
{0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0},
{0x3103, 0x03, 0, 0}, {0x3017, 0x00, 0, 0}, {0x3018, 0x00, 0, 0},
@@ -286,10 +288,10 @@ static const struct reg_value ov5640_init_setting_30fps_VGA[] = {
{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0},
{0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0},
- {0x300e, 0x45, 0, 0}, {0x302e, 0x08, 0, 0}, {0x4300, 0x3f, 0, 0},
+ {0x302e, 0x08, 0, 0}, {0x4300, 0x3f, 0, 0},
{0x501f, 0x00, 0, 0}, {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0},
{0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
- {0x4837, 0x0a, 0, 0}, {0x4800, 0x04, 0, 0}, {0x3824, 0x02, 0, 0},
+ {0x4837, 0x0a, 0, 0}, {0x3824, 0x02, 0, 0},
{0x5000, 0xa7, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0},
{0x5181, 0xf2, 0, 0}, {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0},
{0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0},
@@ -606,7 +608,7 @@ static const struct reg_value ov5640_setting_15fps_720P_1280_720[] = {
{0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0},
{0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0},
{0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0},
- {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x02, 0, 0},
+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
{0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0},
{0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0},
};
@@ -908,6 +910,26 @@ static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg,
}
/* download ov5640 settings to sensor through i2c */
+static int ov5640_set_timings(struct ov5640_dev *sensor,
+ const struct ov5640_mode_info *mode)
+{
+ int ret;
+
+ ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->hact);
+ if (ret < 0)
+ return ret;
+
+ ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPVO, mode->vact);
+ if (ret < 0)
+ return ret;
+
+ ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HTS, mode->htot);
+ if (ret < 0)
+ return ret;
+
+ return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, mode->vtot);
+}
+
static int ov5640_load_regs(struct ov5640_dev *sensor,
const struct ov5640_mode_info *mode)
{
@@ -935,7 +957,13 @@ static int ov5640_load_regs(struct ov5640_dev *sensor,
usleep_range(1000 * delay_ms, 1000 * delay_ms + 100);
}
- return ret;
+ return ov5640_set_timings(sensor, mode);
+}
+
+static int ov5640_set_autoexposure(struct ov5640_dev *sensor, bool on)
+{
+ return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL,
+ BIT(0), on ? 0 : BIT(0));
}
/* read exposure, in number of line periods */
@@ -994,6 +1022,18 @@ static int ov5640_get_gain(struct ov5640_dev *sensor)
return gain & 0x3ff;
}
+static int ov5640_set_gain(struct ov5640_dev *sensor, int gain)
+{
+ return ov5640_write_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN,
+ (u16)gain & 0x3ff);
+}
+
+static int ov5640_set_autogain(struct ov5640_dev *sensor, bool on)
+{
+ return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL,
+ BIT(1), on ? 0 : BIT(1));
+}
+
static int ov5640_set_stream_dvp(struct ov5640_dev *sensor, bool on)
{
int ret;
@@ -1102,12 +1142,25 @@ static int ov5640_set_stream_mipi(struct ov5640_dev *sensor, bool on)
{
int ret;
- ret = ov5640_mod_reg(sensor, OV5640_REG_MIPI_CTRL00, BIT(5),
- on ? 0 : BIT(5));
- if (ret)
- return ret;
- ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00,
- on ? 0x00 : 0x70);
+ /*
+ * Enable/disable the MIPI interface
+ *
+ * 0x300e = on ? 0x45 : 0x40
+ *
+ * FIXME: the sensor manual (version 2.03) reports
+ * [7:5] = 000 : 1 data lane mode
+ * [7:5] = 001 : 2 data lanes mode
+ * But this settings do not work, while the following ones
+ * have been validated for 2 data lanes mode.
+ *
+ * [7:5] = 010 : 2 data lanes mode
+ * [4] = 0 : Power up MIPI HS Tx
+ * [3] = 0 : Power up MIPI LS Rx
+ * [2] = 1/0 : MIPI interface enable/disable
+ * [1:0] = 01/00: FIXME: 'debug'
+ */
+ ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00,
+ on ? 0x45 : 0x40);
if (ret)
return ret;
@@ -1331,7 +1384,7 @@ static int ov5640_set_ae_target(struct ov5640_dev *sensor, int target)
return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1F, fast_low);
}
-static int ov5640_binning_on(struct ov5640_dev *sensor)
+static int ov5640_get_binning(struct ov5640_dev *sensor)
{
u8 temp;
int ret;
@@ -1339,8 +1392,8 @@ static int ov5640_binning_on(struct ov5640_dev *sensor)
ret = ov5640_read_reg(sensor, OV5640_REG_TIMING_TC_REG21, &temp);
if (ret)
return ret;
- temp &= 0xfe;
- return temp ? 1 : 0;
+
+ return temp & BIT(0);
}
static int ov5640_set_binning(struct ov5640_dev *sensor, bool enable)
@@ -1385,30 +1438,6 @@ static int ov5640_set_virtual_channel(struct ov5640_dev *sensor)
return ov5640_write_reg(sensor, OV5640_REG_DEBUG_MODE, temp);
}
-static int ov5640_set_timings(struct ov5640_dev *sensor,
- const struct ov5640_mode_info *mode)
-{
- int ret;
-
- ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->hact);
- if (ret < 0)
- return ret;
-
- ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPVO, mode->vact);
- if (ret < 0)
- return ret;
-
- ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HTS, mode->htot);
- if (ret < 0)
- return ret;
-
- ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, mode->vtot);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
static const struct ov5640_mode_info *
ov5640_find_mode(struct ov5640_dev *sensor, enum ov5640_frame_rate fr,
int width, int height, bool nearest)
@@ -1450,7 +1479,7 @@ static int ov5640_set_mode_exposure_calc(struct ov5640_dev *sensor,
if (ret < 0)
return ret;
prev_shutter = ret;
- ret = ov5640_binning_on(sensor);
+ ret = ov5640_get_binning(sensor);
if (ret < 0)
return ret;
if (ret && mode->id != OV5640_MODE_720P_1280_720 &&
@@ -1571,7 +1600,7 @@ static int ov5640_set_mode_exposure_calc(struct ov5640_dev *sensor,
}
/* set capture gain */
- ret = __v4l2_ctrl_s_ctrl(sensor->ctrls.gain, cap_gain16);
+ ret = ov5640_set_gain(sensor, cap_gain16);
if (ret)
return ret;
@@ -1584,7 +1613,7 @@ static int ov5640_set_mode_exposure_calc(struct ov5640_dev *sensor,
}
/* set exposure */
- return __v4l2_ctrl_s_ctrl(sensor->ctrls.exposure, cap_shutter);
+ return ov5640_set_exposure(sensor, cap_shutter);
}
/*
@@ -1592,53 +1621,45 @@ static int ov5640_set_mode_exposure_calc(struct ov5640_dev *sensor,
* change mode directly
*/
static int ov5640_set_mode_direct(struct ov5640_dev *sensor,
- const struct ov5640_mode_info *mode,
- s32 exposure)
+ const struct ov5640_mode_info *mode)
{
- int ret;
-
if (!mode->reg_data)
return -EINVAL;
/* Write capture setting */
- ret = ov5640_load_regs(sensor, mode);
- if (ret < 0)
- return ret;
-
- /* turn auto gain/exposure back on for direct mode */
- ret = __v4l2_ctrl_s_ctrl(sensor->ctrls.auto_gain, 1);
- if (ret)
- return ret;
-
- return __v4l2_ctrl_s_ctrl(sensor->ctrls.auto_exp, exposure);
+ return ov5640_load_regs(sensor, mode);
}
-static int ov5640_set_mode(struct ov5640_dev *sensor,
- const struct ov5640_mode_info *orig_mode)
+static int ov5640_set_mode(struct ov5640_dev *sensor)
{
const struct ov5640_mode_info *mode = sensor->current_mode;
+ const struct ov5640_mode_info *orig_mode = sensor->last_mode;
enum ov5640_downsize_mode dn_mode, orig_dn_mode;
- s32 exposure;
+ bool auto_gain = sensor->ctrls.auto_gain->val == 1;
+ bool auto_exp = sensor->ctrls.auto_exp->val == V4L2_EXPOSURE_AUTO;
int ret;
dn_mode = mode->dn_mode;
orig_dn_mode = orig_mode->dn_mode;
/* auto gain and exposure must be turned off when changing modes */
- ret = __v4l2_ctrl_s_ctrl(sensor->ctrls.auto_gain, 0);
- if (ret)
- return ret;
+ if (auto_gain) {
+ ret = ov5640_set_autogain(sensor, false);
+ if (ret)
+ return ret;
+ }
- exposure = sensor->ctrls.auto_exp->val;
- ret = ov5640_set_exposure(sensor, V4L2_EXPOSURE_MANUAL);
- if (ret)
- return ret;
+ if (auto_exp) {
+ ret = ov5640_set_autoexposure(sensor, false);
+ if (ret)
+ goto restore_auto_gain;
+ }
if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) ||
(dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) {
/*
* change between subsampling and scaling
- * go through exposure calucation
+ * go through exposure calculation
*/
ret = ov5640_set_mode_exposure_calc(sensor, mode);
} else {
@@ -1646,15 +1667,16 @@ static int ov5640_set_mode(struct ov5640_dev *sensor,
* change inside subsampling or scaling
* download firmware directly
*/
- ret = ov5640_set_mode_direct(sensor, mode, exposure);
+ ret = ov5640_set_mode_direct(sensor, mode);
}
-
if (ret < 0)
- return ret;
+ goto restore_auto_exp_gain;
- ret = ov5640_set_timings(sensor, mode);
- if (ret < 0)
- return ret;
+ /* restore auto gain and exposure */
+ if (auto_gain)
+ ov5640_set_autogain(sensor, true);
+ if (auto_exp)
+ ov5640_set_autoexposure(sensor, true);
ret = ov5640_set_binning(sensor, dn_mode != SCALING);
if (ret < 0)
@@ -1673,8 +1695,18 @@ static int ov5640_set_mode(struct ov5640_dev *sensor,
return ret;
sensor->pending_mode_change = false;
+ sensor->last_mode = mode;
return 0;
+
+restore_auto_exp_gain:
+ if (auto_exp)
+ ov5640_set_autoexposure(sensor, true);
+restore_auto_gain:
+ if (auto_gain)
+ ov5640_set_autogain(sensor, true);
+
+ return ret;
}
static int ov5640_set_framefmt(struct ov5640_dev *sensor,
@@ -1689,6 +1721,7 @@ static int ov5640_restore_mode(struct ov5640_dev *sensor)
ret = ov5640_load_regs(sensor, &ov5640_mode_init_data);
if (ret < 0)
return ret;
+ sensor->last_mode = &ov5640_mode_init_data;
ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f,
(ilog2(OV5640_SCLK2X_ROOT_DIVIDER_DEFAULT) << 2) |
@@ -1697,7 +1730,7 @@ static int ov5640_restore_mode(struct ov5640_dev *sensor)
return ret;
/* now restore the last capture mode */
- ret = ov5640_set_mode(sensor, &ov5640_mode_init_data);
+ ret = ov5640_set_mode(sensor);
if (ret < 0)
return ret;
@@ -1786,23 +1819,69 @@ static int ov5640_set_power(struct ov5640_dev *sensor, bool on)
if (ret)
goto power_off;
- if (sensor->ep.bus_type == V4L2_MBUS_CSI2) {
- /*
- * start streaming briefly followed by stream off in
- * order to coax the clock lane into LP-11 state.
- */
- ret = ov5640_set_stream_mipi(sensor, true);
- if (ret)
- goto power_off;
- usleep_range(1000, 2000);
- ret = ov5640_set_stream_mipi(sensor, false);
- if (ret)
- goto power_off;
+ /* We're done here for DVP bus, while CSI-2 needs setup. */
+ if (sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY)
+ return 0;
+
+ /*
+ * Power up MIPI HS Tx and LS Rx; 2 data lanes mode
+ *
+ * 0x300e = 0x40
+ * [7:5] = 010 : 2 data lanes mode (see FIXME note in
+ * "ov5640_set_stream_mipi()")
+ * [4] = 0 : Power up MIPI HS Tx
+ * [3] = 0 : Power up MIPI LS Rx
+ * [2] = 0 : MIPI interface disabled
+ */
+ ret = ov5640_write_reg(sensor,
+ OV5640_REG_IO_MIPI_CTRL00, 0x40);
+ if (ret)
+ goto power_off;
+
+ /*
+ * Gate clock and set LP11 in 'no packets mode' (idle)
+ *
+ * 0x4800 = 0x24
+ * [5] = 1 : Gate clock when 'no packets'
+ * [2] = 1 : MIPI bus in LP11 when 'no packets'
+ */
+ ret = ov5640_write_reg(sensor,
+ OV5640_REG_MIPI_CTRL00, 0x24);
+ if (ret)
+ goto power_off;
+
+ /*
+ * Set data lanes and clock in LP11 when 'sleeping'
+ *
+ * 0x3019 = 0x70
+ * [6] = 1 : MIPI data lane 2 in LP11 when 'sleeping'
+ * [5] = 1 : MIPI data lane 1 in LP11 when 'sleeping'
+ * [4] = 1 : MIPI clock lane in LP11 when 'sleeping'
+ */
+ ret = ov5640_write_reg(sensor,
+ OV5640_REG_PAD_OUTPUT00, 0x70);
+ if (ret)
+ goto power_off;
+
+ /* Give lanes some time to coax into LP11 state. */
+ usleep_range(500, 1000);
+
+ } else {
+ if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY) {
+ /* Reset MIPI bus settings to their default values. */
+ ov5640_write_reg(sensor,
+ OV5640_REG_IO_MIPI_CTRL00, 0x58);
+ ov5640_write_reg(sensor,
+ OV5640_REG_MIPI_CTRL00, 0x04);
+ ov5640_write_reg(sensor,
+ OV5640_REG_PAD_OUTPUT00, 0x00);
}
- return 0;
+ ov5640_set_power_off(sensor);
}
+ return 0;
+
power_off:
ov5640_set_power_off(sensor);
return ret;
@@ -1968,9 +2047,12 @@ static int ov5640_set_fmt(struct v4l2_subdev *sd,
if (new_mode != sensor->current_mode) {
sensor->current_mode = new_mode;
- sensor->fmt = *mbus_fmt;
sensor->pending_mode_change = true;
}
+ if (mbus_fmt->code != sensor->fmt.code) {
+ sensor->fmt = *mbus_fmt;
+ sensor->pending_fmt_change = true;
+ }
out:
mutex_unlock(&sensor->lock);
return ret;
@@ -2137,20 +2219,20 @@ static int ov5640_set_ctrl_white_balance(struct ov5640_dev *sensor, int awb)
return ret;
}
-static int ov5640_set_ctrl_exposure(struct ov5640_dev *sensor, int exp)
+static int ov5640_set_ctrl_exposure(struct ov5640_dev *sensor,
+ enum v4l2_exposure_auto_type auto_exposure)
{
struct ov5640_ctrls *ctrls = &sensor->ctrls;
- bool auto_exposure = (exp == V4L2_EXPOSURE_AUTO);
+ bool auto_exp = (auto_exposure == V4L2_EXPOSURE_AUTO);
int ret = 0;
if (ctrls->auto_exp->is_new) {
- ret = ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL,
- BIT(0), auto_exposure ? 0 : BIT(0));
+ ret = ov5640_set_autoexposure(sensor, auto_exp);
if (ret)
return ret;
}
- if (!auto_exposure && ctrls->exposure->is_new) {
+ if (!auto_exp && ctrls->exposure->is_new) {
u16 max_exp;
ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_VTS,
@@ -2170,25 +2252,19 @@ static int ov5640_set_ctrl_exposure(struct ov5640_dev *sensor, int exp)
return ret;
}
-static int ov5640_set_ctrl_gain(struct ov5640_dev *sensor, int auto_gain)
+static int ov5640_set_ctrl_gain(struct ov5640_dev *sensor, bool auto_gain)
{
struct ov5640_ctrls *ctrls = &sensor->ctrls;
int ret = 0;
if (ctrls->auto_gain->is_new) {
- ret = ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL,
- BIT(1),
- ctrls->auto_gain->val ? 0 : BIT(1));
+ ret = ov5640_set_autogain(sensor, auto_gain);
if (ret)
return ret;
}
- if (!auto_gain && ctrls->gain->is_new) {
- u16 gain = (u16)ctrls->gain->val;
-
- ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN,
- gain & 0x3ff);
- }
+ if (!auto_gain && ctrls->gain->is_new)
+ ret = ov5640_set_gain(sensor, ctrls->gain->val);
return ret;
}
@@ -2261,16 +2337,12 @@ static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
switch (ctrl->id) {
case V4L2_CID_AUTOGAIN:
- if (!ctrl->val)
- return 0;
val = ov5640_get_gain(sensor);
if (val < 0)
return val;
sensor->ctrls.gain->val = val;
break;
case V4L2_CID_EXPOSURE_AUTO:
- if (ctrl->val == V4L2_EXPOSURE_MANUAL)
- return 0;
val = ov5640_get_exposure(sensor);
if (val < 0)
return val;
@@ -2501,8 +2573,6 @@ static int ov5640_s_frame_interval(struct v4l2_subdev *sd,
if (frame_rate < 0)
frame_rate = OV5640_15_FPS;
- sensor->current_fr = frame_rate;
- sensor->frame_interval = fi->interval;
mode = ov5640_find_mode(sensor, frame_rate, mode->hact,
mode->vact, true);
if (!mode) {
@@ -2510,7 +2580,10 @@ static int ov5640_s_frame_interval(struct v4l2_subdev *sd,
goto out;
}
- if (mode != sensor->current_mode) {
+ if (mode != sensor->current_mode ||
+ frame_rate != sensor->current_fr) {
+ sensor->current_fr = frame_rate;
+ sensor->frame_interval = fi->interval;
sensor->current_mode = mode;
sensor->pending_mode_change = true;
}
@@ -2541,16 +2614,19 @@ static int ov5640_s_stream(struct v4l2_subdev *sd, int enable)
if (sensor->streaming == !enable) {
if (enable && sensor->pending_mode_change) {
- ret = ov5640_set_mode(sensor, sensor->current_mode);
+ ret = ov5640_set_mode(sensor);
if (ret)
goto out;
+ }
+ if (enable && sensor->pending_fmt_change) {
ret = ov5640_set_framefmt(sensor, &sensor->fmt);
if (ret)
goto out;
+ sensor->pending_fmt_change = false;
}
- if (sensor->ep.bus_type == V4L2_MBUS_CSI2)
+ if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY)
ret = ov5640_set_stream_mipi(sensor, enable);
else
ret = ov5640_set_stream_dvp(sensor, enable);
@@ -2642,9 +2718,14 @@ static int ov5640_probe(struct i2c_client *client,
return -ENOMEM;
sensor->i2c_client = client;
+
+ /*
+ * default init sequence initialize sensor to
+ * YUV422 UYVY VGA@30fps
+ */
fmt = &sensor->fmt;
- fmt->code = ov5640_formats[0].code;
- fmt->colorspace = ov5640_formats[0].colorspace;
+ fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
@@ -2656,7 +2737,7 @@ static int ov5640_probe(struct i2c_client *client,
sensor->current_fr = OV5640_30_FPS;
sensor->current_mode =
&ov5640_mode_data[OV5640_30_FPS][OV5640_MODE_VGA_640_480];
- sensor->pending_mode_change = true;
+ sensor->last_mode = sensor->current_mode;
sensor->ae_target = 52;
diff --git a/drivers/media/i2c/ov5645.c b/drivers/media/i2c/ov5645.c
index 1722cdab0daf..5eba8dd7222b 100644
--- a/drivers/media/i2c/ov5645.c
+++ b/drivers/media/i2c/ov5645.c
@@ -1127,7 +1127,7 @@ static int ov5645_probe(struct i2c_client *client,
return ret;
}
- if (ov5645->ep.bus_type != V4L2_MBUS_CSI2) {
+ if (ov5645->ep.bus_type != V4L2_MBUS_CSI2_DPHY) {
dev_err(dev, "invalid bus type, must be CSI2\n");
return -EINVAL;
}
diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index da39c49de503..4589631798c9 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -532,7 +532,7 @@ static const struct v4l2_subdev_internal_ops ov5647_subdev_internal_ops = {
static int ov5647_parse_dt(struct device_node *np)
{
- struct v4l2_fwnode_endpoint bus_cfg;
+ struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 };
struct device_node *ep;
int ret;
diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c
index 7b7c74d77370..041fcbb4eebd 100644
--- a/drivers/media/i2c/ov5670.c
+++ b/drivers/media/i2c/ov5670.c
@@ -2016,7 +2016,7 @@ static int ov5670_set_ctrl(struct v4l2_ctrl *ctrl)
}
/* V4L2 controls values will be applied only when power is already up */
- if (pm_runtime_get_if_in_use(&client->dev) <= 0)
+ if (!pm_runtime_get_if_in_use(&client->dev))
return 0;
switch (ctrl->id) {
@@ -2504,10 +2504,9 @@ static int ov5670_probe(struct i2c_client *client)
* Device is already turned on by i2c-core with ACPI domain PM.
* Enable runtime PM and turn off the device.
*/
- pm_runtime_get_noresume(&client->dev);
pm_runtime_set_active(&client->dev);
pm_runtime_enable(&client->dev);
- pm_runtime_put(&client->dev);
+ pm_runtime_idle(&client->dev);
return 0;
@@ -2536,14 +2535,7 @@ static int ov5670_remove(struct i2c_client *client)
v4l2_ctrl_handler_free(sd->ctrl_handler);
mutex_destroy(&ov5670->mutex);
- /*
- * Disable runtime PM but keep the device turned on.
- * i2c-core with ACPI domain PM will turn off the device.
- */
- pm_runtime_get_sync(&client->dev);
pm_runtime_disable(&client->dev);
- pm_runtime_set_suspended(&client->dev);
- pm_runtime_put_noidle(&client->dev);
return 0;
}
diff --git a/drivers/media/i2c/ov5695.c b/drivers/media/i2c/ov5695.c
index 9a80decd93d3..5d107c53364d 100644
--- a/drivers/media/i2c/ov5695.c
+++ b/drivers/media/i2c/ov5695.c
@@ -1110,7 +1110,7 @@ static int ov5695_set_ctrl(struct v4l2_ctrl *ctrl)
break;
}
- if (pm_runtime_get_if_in_use(&client->dev) <= 0)
+ if (!pm_runtime_get_if_in_use(&client->dev))
return 0;
switch (ctrl->id) {
diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index 17a34b4a819d..5d1b218bb7f0 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -449,7 +449,6 @@ static int ov6650_get_selection(struct v4l2_subdev *sd,
switch (sel->target) {
case V4L2_SEL_TGT_CROP_BOUNDS:
- case V4L2_SEL_TGT_CROP_DEFAULT:
sel->r.left = DEF_HSTRT << 1;
sel->r.top = DEF_VSTRT << 1;
sel->r.width = W_CIF;
diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c
index d3ebb7529fca..0c10203f822b 100644
--- a/drivers/media/i2c/ov7251.c
+++ b/drivers/media/i2c/ov7251.c
@@ -1279,9 +1279,9 @@ static int ov7251_probe(struct i2c_client *client)
return ret;
}
- if (ov7251->ep.bus_type != V4L2_MBUS_CSI2) {
+ if (ov7251->ep.bus_type != V4L2_MBUS_CSI2_DPHY) {
dev_err(dev, "invalid bus type (%u), must be CSI2 (%u)\n",
- ov7251->ep.bus_type, V4L2_MBUS_CSI2);
+ ov7251->ep.bus_type, V4L2_MBUS_CSI2_DPHY);
return -EINVAL;
}
diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c
index 31bf577b0bd3..bc68a3a5b4ec 100644
--- a/drivers/media/i2c/ov7670.c
+++ b/drivers/media/i2c/ov7670.c
@@ -1728,7 +1728,7 @@ static int ov7670_parse_dt(struct device *dev,
struct ov7670_info *info)
{
struct fwnode_handle *fwnode = dev_fwnode(dev);
- struct v4l2_fwnode_endpoint bus_cfg;
+ struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 };
struct fwnode_handle *ep;
int ret;
@@ -1808,17 +1808,24 @@ static int ov7670_probe(struct i2c_client *client,
info->pclk_hb_disable = true;
}
- info->clk = devm_clk_get(&client->dev, "xclk");
- if (IS_ERR(info->clk))
- return PTR_ERR(info->clk);
- ret = clk_prepare_enable(info->clk);
- if (ret)
- return ret;
+ info->clk = devm_clk_get(&client->dev, "xclk"); /* optional */
+ if (IS_ERR(info->clk)) {
+ ret = PTR_ERR(info->clk);
+ if (ret == -ENOENT)
+ info->clk = NULL;
+ else
+ return ret;
+ }
+ if (info->clk) {
+ ret = clk_prepare_enable(info->clk);
+ if (ret)
+ return ret;
- info->clock_speed = clk_get_rate(info->clk) / 1000000;
- if (info->clock_speed < 10 || info->clock_speed > 48) {
- ret = -EINVAL;
- goto clk_disable;
+ info->clock_speed = clk_get_rate(info->clk) / 1000000;
+ if (info->clock_speed < 10 || info->clock_speed > 48) {
+ ret = -EINVAL;
+ goto clk_disable;
+ }
}
ret = ov7670_init_gpio(client, info);
diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c
index 7158c31d8403..fefff7fd7d68 100644
--- a/drivers/media/i2c/ov772x.c
+++ b/drivers/media/i2c/ov772x.c
@@ -21,6 +21,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/v4l2-mediabus.h>
#include <linux/videodev2.h>
@@ -414,6 +415,7 @@ struct ov772x_priv {
struct v4l2_subdev subdev;
struct v4l2_ctrl_handler hdl;
struct clk *clk;
+ struct regmap *regmap;
struct ov772x_camera_info *info;
struct gpio_desc *pwdn_gpio;
struct gpio_desc *rstb_gpio;
@@ -549,51 +551,18 @@ static struct ov772x_priv *to_ov772x(struct v4l2_subdev *sd)
return container_of(sd, struct ov772x_priv, subdev);
}
-static int ov772x_read(struct i2c_client *client, u8 addr)
-{
- int ret;
- u8 val;
-
- ret = i2c_master_send(client, &addr, 1);
- if (ret < 0)
- return ret;
- ret = i2c_master_recv(client, &val, 1);
- if (ret < 0)
- return ret;
-
- return val;
-}
-
-static inline int ov772x_write(struct i2c_client *client, u8 addr, u8 value)
-{
- return i2c_smbus_write_byte_data(client, addr, value);
-}
-
-static int ov772x_mask_set(struct i2c_client *client, u8 command, u8 mask,
- u8 set)
-{
- s32 val = ov772x_read(client, command);
-
- if (val < 0)
- return val;
-
- val &= ~mask;
- val |= set & mask;
-
- return ov772x_write(client, command, val);
-}
-
-static int ov772x_reset(struct i2c_client *client)
+static int ov772x_reset(struct ov772x_priv *priv)
{
int ret;
- ret = ov772x_write(client, COM7, SCCB_RESET);
+ ret = regmap_write(priv->regmap, COM7, SCCB_RESET);
if (ret < 0)
return ret;
usleep_range(1000, 5000);
- return ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE);
+ return regmap_update_bits(priv->regmap, COM2, SOFT_SLEEP_MODE,
+ SOFT_SLEEP_MODE);
}
/*
@@ -611,8 +580,8 @@ static int ov772x_s_stream(struct v4l2_subdev *sd, int enable)
if (priv->streaming == enable)
goto done;
- ret = ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE,
- enable ? 0 : SOFT_SLEEP_MODE);
+ ret = regmap_update_bits(priv->regmap, COM2, SOFT_SLEEP_MODE,
+ enable ? 0 : SOFT_SLEEP_MODE);
if (ret)
goto done;
@@ -657,7 +626,6 @@ static int ov772x_set_frame_rate(struct ov772x_priv *priv,
const struct ov772x_color_format *cfmt,
const struct ov772x_win_size *win)
{
- struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev);
unsigned long fin = clk_get_rate(priv->clk);
unsigned int best_diff;
unsigned int fsize;
@@ -723,11 +691,11 @@ static int ov772x_set_frame_rate(struct ov772x_priv *priv,
}
}
- ret = ov772x_write(client, COM4, com4 | COM4_RESERVED);
+ ret = regmap_write(priv->regmap, COM4, com4 | COM4_RESERVED);
if (ret < 0)
return ret;
- ret = ov772x_write(client, CLKRC, clkrc | CLKRC_RESERVED);
+ ret = regmap_write(priv->regmap, CLKRC, clkrc | CLKRC_RESERVED);
if (ret < 0)
return ret;
@@ -788,8 +756,7 @@ static int ov772x_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct ov772x_priv *priv = container_of(ctrl->handler,
struct ov772x_priv, hdl);
- struct v4l2_subdev *sd = &priv->subdev;
- struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct regmap *regmap = priv->regmap;
int ret = 0;
u8 val;
@@ -808,27 +775,27 @@ static int ov772x_s_ctrl(struct v4l2_ctrl *ctrl)
val = ctrl->val ? VFLIP_IMG : 0x00;
if (priv->info && (priv->info->flags & OV772X_FLAG_VFLIP))
val ^= VFLIP_IMG;
- return ov772x_mask_set(client, COM3, VFLIP_IMG, val);
+ return regmap_update_bits(regmap, COM3, VFLIP_IMG, val);
case V4L2_CID_HFLIP:
val = ctrl->val ? HFLIP_IMG : 0x00;
if (priv->info && (priv->info->flags & OV772X_FLAG_HFLIP))
val ^= HFLIP_IMG;
- return ov772x_mask_set(client, COM3, HFLIP_IMG, val);
+ return regmap_update_bits(regmap, COM3, HFLIP_IMG, val);
case V4L2_CID_BAND_STOP_FILTER:
if (!ctrl->val) {
/* Switch the filter off, it is on now */
- ret = ov772x_mask_set(client, BDBASE, 0xff, 0xff);
+ ret = regmap_update_bits(regmap, BDBASE, 0xff, 0xff);
if (!ret)
- ret = ov772x_mask_set(client, COM8,
- BNDF_ON_OFF, 0);
+ ret = regmap_update_bits(regmap, COM8,
+ BNDF_ON_OFF, 0);
} else {
/* Switch the filter on, set AEC low limit */
val = 256 - ctrl->val;
- ret = ov772x_mask_set(client, COM8,
- BNDF_ON_OFF, BNDF_ON_OFF);
+ ret = regmap_update_bits(regmap, COM8,
+ BNDF_ON_OFF, BNDF_ON_OFF);
if (!ret)
- ret = ov772x_mask_set(client, BDBASE,
- 0xff, val);
+ ret = regmap_update_bits(regmap, BDBASE,
+ 0xff, val);
}
return ret;
@@ -841,18 +808,19 @@ static int ov772x_s_ctrl(struct v4l2_ctrl *ctrl)
static int ov772x_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov772x_priv *priv = to_ov772x(sd);
int ret;
+ unsigned int val;
reg->size = 1;
if (reg->reg > 0xff)
return -EINVAL;
- ret = ov772x_read(client, reg->reg);
+ ret = regmap_read(priv->regmap, reg->reg, &val);
if (ret < 0)
return ret;
- reg->val = (__u64)ret;
+ reg->val = (__u64)val;
return 0;
}
@@ -860,13 +828,13 @@ static int ov772x_g_register(struct v4l2_subdev *sd,
static int ov772x_s_register(struct v4l2_subdev *sd,
const struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov772x_priv *priv = to_ov772x(sd);
if (reg->reg > 0xff ||
reg->val > 0xff)
return -EINVAL;
- return ov772x_write(client, reg->reg, reg->val);
+ return regmap_write(priv->regmap, reg->reg, reg->val);
}
#endif
@@ -896,6 +864,7 @@ static int ov772x_power_on(struct ov772x_priv *priv)
GPIOD_OUT_LOW);
if (IS_ERR(priv->rstb_gpio)) {
dev_info(&client->dev, "Unable to get GPIO \"reset\"");
+ clk_disable_unprepare(priv->clk);
return PTR_ERR(priv->rstb_gpio);
}
@@ -1004,7 +973,7 @@ static void ov772x_select_params(const struct v4l2_mbus_framefmt *mf,
static int ov772x_edgectrl(struct ov772x_priv *priv)
{
- struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev);
+ struct regmap *regmap = priv->regmap;
int ret;
if (!priv->info)
@@ -1018,19 +987,19 @@ static int ov772x_edgectrl(struct ov772x_priv *priv)
* Remove it when manual mode.
*/
- ret = ov772x_mask_set(client, DSPAUTO, EDGE_ACTRL, 0x00);
+ ret = regmap_update_bits(regmap, DSPAUTO, EDGE_ACTRL, 0x00);
if (ret < 0)
return ret;
- ret = ov772x_mask_set(client,
- EDGE_TRSHLD, OV772X_EDGE_THRESHOLD_MASK,
- priv->info->edgectrl.threshold);
+ ret = regmap_update_bits(regmap, EDGE_TRSHLD,
+ OV772X_EDGE_THRESHOLD_MASK,
+ priv->info->edgectrl.threshold);
if (ret < 0)
return ret;
- ret = ov772x_mask_set(client,
- EDGE_STRNGT, OV772X_EDGE_STRENGTH_MASK,
- priv->info->edgectrl.strength);
+ ret = regmap_update_bits(regmap, EDGE_STRNGT,
+ OV772X_EDGE_STRENGTH_MASK,
+ priv->info->edgectrl.strength);
if (ret < 0)
return ret;
@@ -1040,15 +1009,15 @@ static int ov772x_edgectrl(struct ov772x_priv *priv)
*
* Set upper and lower limit.
*/
- ret = ov772x_mask_set(client,
- EDGE_UPPER, OV772X_EDGE_UPPER_MASK,
- priv->info->edgectrl.upper);
+ ret = regmap_update_bits(regmap, EDGE_UPPER,
+ OV772X_EDGE_UPPER_MASK,
+ priv->info->edgectrl.upper);
if (ret < 0)
return ret;
- ret = ov772x_mask_set(client,
- EDGE_LOWER, OV772X_EDGE_LOWER_MASK,
- priv->info->edgectrl.lower);
+ ret = regmap_update_bits(regmap, EDGE_LOWER,
+ OV772X_EDGE_LOWER_MASK,
+ priv->info->edgectrl.lower);
if (ret < 0)
return ret;
}
@@ -1060,12 +1029,11 @@ static int ov772x_set_params(struct ov772x_priv *priv,
const struct ov772x_color_format *cfmt,
const struct ov772x_win_size *win)
{
- struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev);
int ret;
u8 val;
/* Reset hardware. */
- ov772x_reset(client);
+ ov772x_reset(priv);
/* Edge Ctrl. */
ret = ov772x_edgectrl(priv);
@@ -1073,32 +1041,32 @@ static int ov772x_set_params(struct ov772x_priv *priv,
return ret;
/* Format and window size. */
- ret = ov772x_write(client, HSTART, win->rect.left >> 2);
+ ret = regmap_write(priv->regmap, HSTART, win->rect.left >> 2);
if (ret < 0)
goto ov772x_set_fmt_error;
- ret = ov772x_write(client, HSIZE, win->rect.width >> 2);
+ ret = regmap_write(priv->regmap, HSIZE, win->rect.width >> 2);
if (ret < 0)
goto ov772x_set_fmt_error;
- ret = ov772x_write(client, VSTART, win->rect.top >> 1);
+ ret = regmap_write(priv->regmap, VSTART, win->rect.top >> 1);
if (ret < 0)
goto ov772x_set_fmt_error;
- ret = ov772x_write(client, VSIZE, win->rect.height >> 1);
+ ret = regmap_write(priv->regmap, VSIZE, win->rect.height >> 1);
if (ret < 0)
goto ov772x_set_fmt_error;
- ret = ov772x_write(client, HOUTSIZE, win->rect.width >> 2);
+ ret = regmap_write(priv->regmap, HOUTSIZE, win->rect.width >> 2);
if (ret < 0)
goto ov772x_set_fmt_error;
- ret = ov772x_write(client, VOUTSIZE, win->rect.height >> 1);
+ ret = regmap_write(priv->regmap, VOUTSIZE, win->rect.height >> 1);
if (ret < 0)
goto ov772x_set_fmt_error;
- ret = ov772x_write(client, HREF,
+ ret = regmap_write(priv->regmap, HREF,
((win->rect.top & 1) << HREF_VSTART_SHIFT) |
((win->rect.left & 3) << HREF_HSTART_SHIFT) |
((win->rect.height & 1) << HREF_VSIZE_SHIFT) |
((win->rect.width & 3) << HREF_HSIZE_SHIFT));
if (ret < 0)
goto ov772x_set_fmt_error;
- ret = ov772x_write(client, EXHCH,
+ ret = regmap_write(priv->regmap, EXHCH,
((win->rect.height & 1) << EXHCH_VSIZE_SHIFT) |
((win->rect.width & 3) << EXHCH_HSIZE_SHIFT));
if (ret < 0)
@@ -1107,15 +1075,14 @@ static int ov772x_set_params(struct ov772x_priv *priv,
/* Set DSP_CTRL3. */
val = cfmt->dsp3;
if (val) {
- ret = ov772x_mask_set(client,
- DSP_CTRL3, UV_MASK, val);
+ ret = regmap_update_bits(priv->regmap, DSP_CTRL3, UV_MASK, val);
if (ret < 0)
goto ov772x_set_fmt_error;
}
/* DSP_CTRL4: AEC reference point and DSP output format. */
if (cfmt->dsp4) {
- ret = ov772x_write(client, DSP_CTRL4, cfmt->dsp4);
+ ret = regmap_write(priv->regmap, DSP_CTRL4, cfmt->dsp4);
if (ret < 0)
goto ov772x_set_fmt_error;
}
@@ -1131,13 +1098,12 @@ static int ov772x_set_params(struct ov772x_priv *priv,
if (priv->hflip_ctrl->val)
val ^= HFLIP_IMG;
- ret = ov772x_mask_set(client,
- COM3, SWAP_MASK | IMG_MASK, val);
+ ret = regmap_update_bits(priv->regmap, COM3, SWAP_MASK | IMG_MASK, val);
if (ret < 0)
goto ov772x_set_fmt_error;
/* COM7: Sensor resolution and output format control. */
- ret = ov772x_write(client, COM7, win->com7_bit | cfmt->com7);
+ ret = regmap_write(priv->regmap, COM7, win->com7_bit | cfmt->com7);
if (ret < 0)
goto ov772x_set_fmt_error;
@@ -1150,10 +1116,11 @@ static int ov772x_set_params(struct ov772x_priv *priv,
if (priv->band_filter_ctrl->val) {
unsigned short band_filter = priv->band_filter_ctrl->val;
- ret = ov772x_mask_set(client, COM8, BNDF_ON_OFF, BNDF_ON_OFF);
+ ret = regmap_update_bits(priv->regmap, COM8,
+ BNDF_ON_OFF, BNDF_ON_OFF);
if (!ret)
- ret = ov772x_mask_set(client, BDBASE,
- 0xff, 256 - band_filter);
+ ret = regmap_update_bits(priv->regmap, BDBASE,
+ 0xff, 256 - band_filter);
if (ret < 0)
goto ov772x_set_fmt_error;
}
@@ -1162,7 +1129,7 @@ static int ov772x_set_params(struct ov772x_priv *priv,
ov772x_set_fmt_error:
- ov772x_reset(client);
+ ov772x_reset(priv);
return ret;
}
@@ -1180,7 +1147,6 @@ static int ov772x_get_selection(struct v4l2_subdev *sd,
sel->r.top = 0;
switch (sel->target) {
case V4L2_SEL_TGT_CROP_BOUNDS:
- case V4L2_SEL_TGT_CROP_DEFAULT:
case V4L2_SEL_TGT_CROP:
sel->r.width = priv->win->rect.width;
sel->r.height = priv->win->rect.height;
@@ -1276,12 +1242,12 @@ static int ov772x_video_probe(struct ov772x_priv *priv)
return ret;
/* Check and show product ID and manufacturer ID. */
- pid = ov772x_read(client, PID);
- if (pid < 0)
- return pid;
- ver = ov772x_read(client, VER);
- if (ver < 0)
- return ver;
+ ret = regmap_read(priv->regmap, PID, &pid);
+ if (ret < 0)
+ return ret;
+ ret = regmap_read(priv->regmap, VER, &ver);
+ if (ret < 0)
+ return ret;
switch (VERSION(pid, ver)) {
case OV7720:
@@ -1297,12 +1263,12 @@ static int ov772x_video_probe(struct ov772x_priv *priv)
goto done;
}
- midh = ov772x_read(client, MIDH);
- if (midh < 0)
- return midh;
- midl = ov772x_read(client, MIDL);
- if (midl < 0)
- return midl;
+ ret = regmap_read(priv->regmap, MIDH, &midh);
+ if (ret < 0)
+ return ret;
+ ret = regmap_read(priv->regmap, MIDL, &midl);
+ if (ret < 0)
+ return ret;
dev_info(&client->dev,
"%s Product ID %0x:%0x Manufacturer ID %x:%x\n",
@@ -1386,8 +1352,12 @@ static int ov772x_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct ov772x_priv *priv;
- struct i2c_adapter *adapter = client->adapter;
int ret;
+ static const struct regmap_config ov772x_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = DSPAUTO,
+ };
if (!client->dev.of_node && !client->dev.platform_data) {
dev_err(&client->dev,
@@ -1395,16 +1365,16 @@ static int ov772x_probe(struct i2c_client *client,
return -EINVAL;
}
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
- dev_err(&adapter->dev,
- "I2C-Adapter doesn't support SMBUS_BYTE_DATA\n");
- return -EIO;
- }
-
priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
+ priv->regmap = devm_regmap_init_sccb(client, &ov772x_regmap_config);
+ if (IS_ERR(priv->regmap)) {
+ dev_err(&client->dev, "Failed to allocate register map\n");
+ return PTR_ERR(priv->regmap);
+ }
+
priv->info = client->dev.platform_data;
mutex_init(&priv->lock);
diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c
index 605f3e25ad82..6e9c233cfbe3 100644
--- a/drivers/media/i2c/ov7740.c
+++ b/drivers/media/i2c/ov7740.c
@@ -510,7 +510,7 @@ static int ov7740_set_ctrl(struct v4l2_ctrl *ctrl)
int ret;
u8 val = 0;
- if (pm_runtime_get_if_in_use(&client->dev) <= 0)
+ if (!pm_runtime_get_if_in_use(&client->dev))
return 0;
switch (ctrl->id) {
diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c
index 5bea31cd41aa..f0587c0c0a72 100644
--- a/drivers/media/i2c/ov9650.c
+++ b/drivers/media/i2c/ov9650.c
@@ -20,6 +20,7 @@
#include <linux/media.h>
#include <linux/module.h>
#include <linux/ratelimit.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/videodev2.h>
@@ -259,7 +260,7 @@ struct ov965x {
/* Protects the struct fields below */
struct mutex lock;
- struct i2c_client *client;
+ struct regmap *regmap;
/* Exposure row interval in us */
unsigned int exp_row_interval;
@@ -424,51 +425,42 @@ static inline struct ov965x *to_ov965x(struct v4l2_subdev *sd)
return container_of(sd, struct ov965x, sd);
}
-static int ov965x_read(struct i2c_client *client, u8 addr, u8 *val)
+static int ov965x_read(struct ov965x *ov965x, u8 addr, u8 *val)
{
- u8 buf = addr;
- struct i2c_msg msg = {
- .addr = client->addr,
- .flags = 0,
- .len = 1,
- .buf = &buf
- };
int ret;
+ unsigned int buf;
- ret = i2c_transfer(client->adapter, &msg, 1);
- if (ret == 1) {
- msg.flags = I2C_M_RD;
- ret = i2c_transfer(client->adapter, &msg, 1);
-
- if (ret == 1)
- *val = buf;
- }
+ ret = regmap_read(ov965x->regmap, addr, &buf);
+ if (!ret)
+ *val = buf;
+ else
+ *val = -1;
- v4l2_dbg(2, debug, client, "%s: 0x%02x @ 0x%02x. (%d)\n",
+ v4l2_dbg(2, debug, &ov965x->sd, "%s: 0x%02x @ 0x%02x. (%d)\n",
__func__, *val, addr, ret);
- return ret == 1 ? 0 : ret;
+ return ret;
}
-static int ov965x_write(struct i2c_client *client, u8 addr, u8 val)
+static int ov965x_write(struct ov965x *ov965x, u8 addr, u8 val)
{
- u8 buf[2] = { addr, val };
+ int ret;
- int ret = i2c_master_send(client, buf, 2);
+ ret = regmap_write(ov965x->regmap, addr, val);
- v4l2_dbg(2, debug, client, "%s: 0x%02x @ 0x%02X (%d)\n",
+ v4l2_dbg(2, debug, &ov965x->sd, "%s: 0x%02x @ 0x%02X (%d)\n",
__func__, val, addr, ret);
- return ret == 2 ? 0 : ret;
+ return ret;
}
-static int ov965x_write_array(struct i2c_client *client,
+static int ov965x_write_array(struct ov965x *ov965x,
const struct i2c_rv *regs)
{
int i, ret = 0;
for (i = 0; ret == 0 && regs[i].addr != REG_NULL; i++)
- ret = ov965x_write(client, regs[i].addr, regs[i].value);
+ ret = ov965x_write(ov965x, regs[i].addr, regs[i].value);
return ret;
}
@@ -486,7 +478,7 @@ static int ov965x_set_default_gamma_curve(struct ov965x *ov965x)
unsigned int i;
for (i = 0; i < ARRAY_SIZE(gamma_curve); i++) {
- int ret = ov965x_write(ov965x->client, addr, gamma_curve[i]);
+ int ret = ov965x_write(ov965x, addr, gamma_curve[i]);
if (ret < 0)
return ret;
@@ -506,7 +498,7 @@ static int ov965x_set_color_matrix(struct ov965x *ov965x)
unsigned int i;
for (i = 0; i < ARRAY_SIZE(mtx); i++) {
- int ret = ov965x_write(ov965x->client, addr, mtx[i]);
+ int ret = ov965x_write(ov965x, addr, mtx[i]);
if (ret < 0)
return ret;
@@ -542,16 +534,15 @@ static int __ov965x_set_power(struct ov965x *ov965x, int on)
static int ov965x_s_power(struct v4l2_subdev *sd, int on)
{
struct ov965x *ov965x = to_ov965x(sd);
- struct i2c_client *client = ov965x->client;
int ret = 0;
- v4l2_dbg(1, debug, client, "%s: on: %d\n", __func__, on);
+ v4l2_dbg(1, debug, sd, "%s: on: %d\n", __func__, on);
mutex_lock(&ov965x->lock);
if (ov965x->power == !on) {
ret = __ov965x_set_power(ov965x, on);
if (!ret && on) {
- ret = ov965x_write_array(client,
+ ret = ov965x_write_array(ov965x,
ov965x_init_regs);
ov965x->apply_frame_fmt = 1;
ov965x->ctrls.update = 1;
@@ -609,13 +600,13 @@ static int ov965x_set_banding_filter(struct ov965x *ov965x, int value)
int ret;
u8 reg;
- ret = ov965x_read(ov965x->client, REG_COM8, &reg);
+ ret = ov965x_read(ov965x, REG_COM8, &reg);
if (!ret) {
if (value == V4L2_CID_POWER_LINE_FREQUENCY_DISABLED)
reg &= ~COM8_BFILT;
else
reg |= COM8_BFILT;
- ret = ov965x_write(ov965x->client, REG_COM8, reg);
+ ret = ov965x_write(ov965x, REG_COM8, reg);
}
if (value == V4L2_CID_POWER_LINE_FREQUENCY_DISABLED)
return 0;
@@ -631,7 +622,7 @@ static int ov965x_set_banding_filter(struct ov965x *ov965x, int value)
ov965x->fiv->interval.numerator;
mbd = ((mbd / (light_freq * 2)) + 500) / 1000UL;
- return ov965x_write(ov965x->client, REG_MBD, mbd);
+ return ov965x_write(ov965x, REG_MBD, mbd);
}
static int ov965x_set_white_balance(struct ov965x *ov965x, int awb)
@@ -639,17 +630,17 @@ static int ov965x_set_white_balance(struct ov965x *ov965x, int awb)
int ret;
u8 reg;
- ret = ov965x_read(ov965x->client, REG_COM8, &reg);
+ ret = ov965x_read(ov965x, REG_COM8, &reg);
if (!ret) {
reg = awb ? reg | REG_COM8 : reg & ~REG_COM8;
- ret = ov965x_write(ov965x->client, REG_COM8, reg);
+ ret = ov965x_write(ov965x, REG_COM8, reg);
}
if (!ret && !awb) {
- ret = ov965x_write(ov965x->client, REG_BLUE,
+ ret = ov965x_write(ov965x, REG_BLUE,
ov965x->ctrls.blue_balance->val);
if (ret < 0)
return ret;
- ret = ov965x_write(ov965x->client, REG_RED,
+ ret = ov965x_write(ov965x, REG_RED,
ov965x->ctrls.red_balance->val);
}
return ret;
@@ -677,14 +668,13 @@ static int ov965x_set_brightness(struct ov965x *ov965x, int val)
return -EINVAL;
for (i = 0; i < NUM_BR_REGS && !ret; i++)
- ret = ov965x_write(ov965x->client, regs[0][i],
+ ret = ov965x_write(ov965x, regs[0][i],
regs[val][i]);
return ret;
}
static int ov965x_set_gain(struct ov965x *ov965x, int auto_gain)
{
- struct i2c_client *client = ov965x->client;
struct ov965x_ctrls *ctrls = &ov965x->ctrls;
int ret = 0;
u8 reg;
@@ -693,14 +683,14 @@ static int ov965x_set_gain(struct ov965x *ov965x, int auto_gain)
* gain value in REG_VREF, REG_GAIN is not overwritten.
*/
if (ctrls->auto_gain->is_new) {
- ret = ov965x_read(client, REG_COM8, &reg);
+ ret = ov965x_read(ov965x, REG_COM8, &reg);
if (ret < 0)
return ret;
if (ctrls->auto_gain->val)
reg |= COM8_AGC;
else
reg &= ~COM8_AGC;
- ret = ov965x_write(client, REG_COM8, reg);
+ ret = ov965x_write(ov965x, REG_COM8, reg);
if (ret < 0)
return ret;
}
@@ -719,15 +709,15 @@ static int ov965x_set_gain(struct ov965x *ov965x, int auto_gain)
rgain = (gain - ((1 << m) * 16)) / (1 << m);
rgain |= (((1 << m) - 1) << 4);
- ret = ov965x_write(client, REG_GAIN, rgain & 0xff);
+ ret = ov965x_write(ov965x, REG_GAIN, rgain & 0xff);
if (ret < 0)
return ret;
- ret = ov965x_read(client, REG_VREF, &reg);
+ ret = ov965x_read(ov965x, REG_VREF, &reg);
if (ret < 0)
return ret;
reg &= ~VREF_GAIN_MASK;
reg |= (((rgain >> 8) & 0x3) << 6);
- ret = ov965x_write(client, REG_VREF, reg);
+ ret = ov965x_write(ov965x, REG_VREF, reg);
if (ret < 0)
return ret;
/* Return updated control's value to userspace */
@@ -742,10 +732,10 @@ static int ov965x_set_sharpness(struct ov965x *ov965x, unsigned int value)
u8 com14, edge;
int ret;
- ret = ov965x_read(ov965x->client, REG_COM14, &com14);
+ ret = ov965x_read(ov965x, REG_COM14, &com14);
if (ret < 0)
return ret;
- ret = ov965x_read(ov965x->client, REG_EDGE, &edge);
+ ret = ov965x_read(ov965x, REG_EDGE, &edge);
if (ret < 0)
return ret;
com14 = value ? com14 | COM14_EDGE_EN : com14 & ~COM14_EDGE_EN;
@@ -756,33 +746,32 @@ static int ov965x_set_sharpness(struct ov965x *ov965x, unsigned int value)
} else {
com14 &= ~COM14_EEF_X2;
}
- ret = ov965x_write(ov965x->client, REG_COM14, com14);
+ ret = ov965x_write(ov965x, REG_COM14, com14);
if (ret < 0)
return ret;
edge &= ~EDGE_FACTOR_MASK;
edge |= ((u8)value & 0x0f);
- return ov965x_write(ov965x->client, REG_EDGE, edge);
+ return ov965x_write(ov965x, REG_EDGE, edge);
}
static int ov965x_set_exposure(struct ov965x *ov965x, int exp)
{
- struct i2c_client *client = ov965x->client;
struct ov965x_ctrls *ctrls = &ov965x->ctrls;
bool auto_exposure = (exp == V4L2_EXPOSURE_AUTO);
int ret;
u8 reg;
if (ctrls->auto_exp->is_new) {
- ret = ov965x_read(client, REG_COM8, &reg);
+ ret = ov965x_read(ov965x, REG_COM8, &reg);
if (ret < 0)
return ret;
if (auto_exposure)
reg |= (COM8_AEC | COM8_AGC);
else
reg &= ~(COM8_AEC | COM8_AGC);
- ret = ov965x_write(client, REG_COM8, reg);
+ ret = ov965x_write(ov965x, REG_COM8, reg);
if (ret < 0)
return ret;
}
@@ -794,12 +783,12 @@ static int ov965x_set_exposure(struct ov965x *ov965x, int exp)
* Manual exposure value
* [b15:b0] - AECHM (b15:b10), AECH (b9:b2), COM1 (b1:b0)
*/
- ret = ov965x_write(client, REG_COM1, exposure & 0x3);
+ ret = ov965x_write(ov965x, REG_COM1, exposure & 0x3);
if (!ret)
- ret = ov965x_write(client, REG_AECH,
+ ret = ov965x_write(ov965x, REG_AECH,
(exposure >> 2) & 0xff);
if (!ret)
- ret = ov965x_write(client, REG_AECHM,
+ ret = ov965x_write(ov965x, REG_AECHM,
(exposure >> 10) & 0x3f);
/* Update the value to minimize rounding errors */
ctrls->exposure->val = ((exposure * ov965x->exp_row_interval)
@@ -822,7 +811,7 @@ static int ov965x_set_flip(struct ov965x *ov965x)
if (ov965x->ctrls.vflip->val)
mvfp |= MVFP_FLIP;
- return ov965x_write(ov965x->client, REG_MVFP, mvfp);
+ return ov965x_write(ov965x, REG_MVFP, mvfp);
}
#define NUM_SAT_LEVELS 5
@@ -846,7 +835,7 @@ static int ov965x_set_saturation(struct ov965x *ov965x, int val)
return -EINVAL;
for (i = 0; i < NUM_SAT_REGS && !ret; i++)
- ret = ov965x_write(ov965x->client, addr + i, regs[val][i]);
+ ret = ov965x_write(ov965x, addr + i, regs[val][i]);
return ret;
}
@@ -856,16 +845,15 @@ static int ov965x_set_test_pattern(struct ov965x *ov965x, int value)
int ret;
u8 reg;
- ret = ov965x_read(ov965x->client, REG_COM23, &reg);
+ ret = ov965x_read(ov965x, REG_COM23, &reg);
if (ret < 0)
return ret;
reg = value ? reg | COM23_TEST_MODE : reg & ~COM23_TEST_MODE;
- return ov965x_write(ov965x->client, REG_COM23, reg);
+ return ov965x_write(ov965x, REG_COM23, reg);
}
static int __g_volatile_ctrl(struct ov965x *ov965x, struct v4l2_ctrl *ctrl)
{
- struct i2c_client *client = ov965x->client;
unsigned int exposure, gain, m;
u8 reg0, reg1, reg2;
int ret;
@@ -877,10 +865,10 @@ static int __g_volatile_ctrl(struct ov965x *ov965x, struct v4l2_ctrl *ctrl)
case V4L2_CID_AUTOGAIN:
if (!ctrl->val)
return 0;
- ret = ov965x_read(client, REG_GAIN, &reg0);
+ ret = ov965x_read(ov965x, REG_GAIN, &reg0);
if (ret < 0)
return ret;
- ret = ov965x_read(client, REG_VREF, &reg1);
+ ret = ov965x_read(ov965x, REG_VREF, &reg1);
if (ret < 0)
return ret;
gain = ((reg1 >> 6) << 8) | reg0;
@@ -891,13 +879,13 @@ static int __g_volatile_ctrl(struct ov965x *ov965x, struct v4l2_ctrl *ctrl)
case V4L2_CID_EXPOSURE_AUTO:
if (ctrl->val == V4L2_EXPOSURE_MANUAL)
return 0;
- ret = ov965x_read(client, REG_COM1, &reg0);
+ ret = ov965x_read(ov965x, REG_COM1, &reg0);
if (ret < 0)
return ret;
- ret = ov965x_read(client, REG_AECH, &reg1);
+ ret = ov965x_read(ov965x, REG_AECH, &reg1);
if (ret < 0)
return ret;
- ret = ov965x_read(client, REG_AECHM, &reg2);
+ ret = ov965x_read(ov965x, REG_AECHM, &reg2);
if (ret < 0)
return ret;
exposure = ((reg2 & 0x3f) << 10) | (reg1 << 2) |
@@ -1279,32 +1267,31 @@ static int ov965x_set_frame_size(struct ov965x *ov965x)
int i, ret = 0;
for (i = 0; ret == 0 && i < NUM_FMT_REGS; i++)
- ret = ov965x_write(ov965x->client, frame_size_reg_addr[i],
+ ret = ov965x_write(ov965x, frame_size_reg_addr[i],
ov965x->frame_size->regs[i]);
return ret;
}
static int __ov965x_set_params(struct ov965x *ov965x)
{
- struct i2c_client *client = ov965x->client;
struct ov965x_ctrls *ctrls = &ov965x->ctrls;
int ret = 0;
u8 reg;
if (ov965x->apply_frame_fmt) {
reg = DEF_CLKRC + ov965x->fiv->clkrc_div;
- ret = ov965x_write(client, REG_CLKRC, reg);
+ ret = ov965x_write(ov965x, REG_CLKRC, reg);
if (ret < 0)
return ret;
ret = ov965x_set_frame_size(ov965x);
if (ret < 0)
return ret;
- ret = ov965x_read(client, REG_TSLB, &reg);
+ ret = ov965x_read(ov965x, REG_TSLB, &reg);
if (ret < 0)
return ret;
reg &= ~TSLB_YUYV_MASK;
reg |= ov965x->tslb_reg;
- ret = ov965x_write(client, REG_TSLB, reg);
+ ret = ov965x_write(ov965x, REG_TSLB, reg);
if (ret < 0)
return ret;
}
@@ -1318,10 +1305,10 @@ static int __ov965x_set_params(struct ov965x *ov965x)
* Select manual banding filter, the filter will
* be enabled further if required.
*/
- ret = ov965x_read(client, REG_COM11, &reg);
+ ret = ov965x_read(ov965x, REG_COM11, &reg);
if (!ret)
reg |= COM11_BANDING;
- ret = ov965x_write(client, REG_COM11, reg);
+ ret = ov965x_write(ov965x, REG_COM11, reg);
if (ret < 0)
return ret;
/*
@@ -1333,12 +1320,11 @@ static int __ov965x_set_params(struct ov965x *ov965x)
static int ov965x_s_stream(struct v4l2_subdev *sd, int on)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov965x *ov965x = to_ov965x(sd);
struct ov965x_ctrls *ctrls = &ov965x->ctrls;
int ret = 0;
- v4l2_dbg(1, debug, client, "%s: on: %d\n", __func__, on);
+ v4l2_dbg(1, debug, sd, "%s: on: %d\n", __func__, on);
mutex_lock(&ov965x->lock);
if (ov965x->streaming == !on) {
@@ -1358,7 +1344,7 @@ static int ov965x_s_stream(struct v4l2_subdev *sd, int on)
ctrls->update = 0;
}
if (!ret)
- ret = ov965x_write(client, REG_COM2,
+ ret = ov965x_write(ov965x, REG_COM2,
on ? 0x01 : 0x11);
}
if (!ret)
@@ -1421,6 +1407,7 @@ static int ov965x_configure_gpios_pdata(struct ov965x *ov965x,
{
int ret, i;
int gpios[NUM_GPIOS];
+ struct device *dev = regmap_get_device(ov965x->regmap);
gpios[GPIO_PWDN] = pdata->gpio_pwdn;
gpios[GPIO_RST] = pdata->gpio_reset;
@@ -1430,7 +1417,7 @@ static int ov965x_configure_gpios_pdata(struct ov965x *ov965x,
if (!gpio_is_valid(gpio))
continue;
- ret = devm_gpio_request_one(&ov965x->client->dev, gpio,
+ ret = devm_gpio_request_one(dev, gpio,
GPIOF_OUT_INIT_HIGH, "OV965X");
if (ret < 0)
return ret;
@@ -1446,7 +1433,7 @@ static int ov965x_configure_gpios_pdata(struct ov965x *ov965x,
static int ov965x_configure_gpios(struct ov965x *ov965x)
{
- struct device *dev = &ov965x->client->dev;
+ struct device *dev = regmap_get_device(ov965x->regmap);
ov965x->gpios[GPIO_PWDN] = devm_gpiod_get_optional(dev, "powerdown",
GPIOD_OUT_HIGH);
@@ -1467,7 +1454,6 @@ static int ov965x_configure_gpios(struct ov965x *ov965x)
static int ov965x_detect_sensor(struct v4l2_subdev *sd)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov965x *ov965x = to_ov965x(sd);
u8 pid, ver;
int ret;
@@ -1480,9 +1466,9 @@ static int ov965x_detect_sensor(struct v4l2_subdev *sd)
msleep(25);
/* Check sensor revision */
- ret = ov965x_read(client, REG_PID, &pid);
+ ret = ov965x_read(ov965x, REG_PID, &pid);
if (!ret)
- ret = ov965x_read(client, REG_VER, &ver);
+ ret = ov965x_read(ov965x, REG_VER, &ver);
__ov965x_set_power(ov965x, 0);
@@ -1509,12 +1495,21 @@ static int ov965x_probe(struct i2c_client *client,
struct v4l2_subdev *sd;
struct ov965x *ov965x;
int ret;
+ static const struct regmap_config ov965x_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0xab,
+ };
ov965x = devm_kzalloc(&client->dev, sizeof(*ov965x), GFP_KERNEL);
if (!ov965x)
return -ENOMEM;
- ov965x->client = client;
+ ov965x->regmap = devm_regmap_init_sccb(client, &ov965x_regmap_config);
+ if (IS_ERR(ov965x->regmap)) {
+ dev_err(&client->dev, "Failed to allocate register map\n");
+ return PTR_ERR(ov965x->regmap);
+ }
if (pdata) {
if (pdata->mclk_frequency == 0) {
@@ -1527,7 +1522,7 @@ static int ov965x_probe(struct i2c_client *client,
if (ret < 0)
return ret;
} else if (dev_fwnode(&client->dev)) {
- ov965x->clk = devm_clk_get(&ov965x->client->dev, NULL);
+ ov965x->clk = devm_clk_get(&client->dev, NULL);
if (IS_ERR(ov965x->clk))
return PTR_ERR(ov965x->clk);
ov965x->mclk_frequency = clk_get_rate(ov965x->clk);
@@ -1546,7 +1541,7 @@ static int ov965x_probe(struct i2c_client *client,
sd = &ov965x->sd;
v4l2_i2c_subdev_init(sd, client, &ov965x_subdev_ops);
- strlcpy(sd->name, DRIVER_NAME, sizeof(sd->name));
+ strscpy(sd->name, DRIVER_NAME, sizeof(sd->name));
sd->internal_ops = &ov965x_sd_internal_ops;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
diff --git a/drivers/media/i2c/rj54n1cb0c.c b/drivers/media/i2c/rj54n1cb0c.c
index 6ad998ad1b16..4cc51e001874 100644
--- a/drivers/media/i2c/rj54n1cb0c.c
+++ b/drivers/media/i2c/rj54n1cb0c.c
@@ -589,7 +589,6 @@ static int rj54n1_get_selection(struct v4l2_subdev *sd,
switch (sel->target) {
case V4L2_SEL_TGT_CROP_BOUNDS:
- case V4L2_SEL_TGT_CROP_DEFAULT:
sel->r.left = RJ54N1_COLUMN_SKIP;
sel->r.top = RJ54N1_ROW_SKIP;
sel->r.width = RJ54N1_MAX_WIDTH;
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
index ce196b60f917..c461847ddae8 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c
+++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
@@ -1603,7 +1603,7 @@ static int s5c73m3_get_platform_data(struct s5c73m3 *state)
const struct s5c73m3_platform_data *pdata = dev->platform_data;
struct device_node *node = dev->of_node;
struct device_node *node_ep;
- struct v4l2_fwnode_endpoint ep;
+ struct v4l2_fwnode_endpoint ep = { .bus_type = 0 };
int ret;
if (!node) {
@@ -1644,7 +1644,7 @@ static int s5c73m3_get_platform_data(struct s5c73m3 *state)
if (ret)
return ret;
- if (ep.bus_type != V4L2_MBUS_CSI2) {
+ if (ep.bus_type != V4L2_MBUS_CSI2_DPHY) {
dev_err(dev, "unsupported bus type\n");
return -EINVAL;
}
@@ -1683,7 +1683,7 @@ static int s5c73m3_probe(struct i2c_client *client,
v4l2_subdev_init(sd, &s5c73m3_subdev_ops);
sd->owner = client->dev.driver->owner;
v4l2_set_subdevdata(sd, state);
- strlcpy(sd->name, "S5C73M3", sizeof(sd->name));
+ strscpy(sd->name, "S5C73M3", sizeof(sd->name));
sd->internal_ops = &s5c73m3_internal_ops;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
@@ -1698,7 +1698,8 @@ static int s5c73m3_probe(struct i2c_client *client,
return ret;
v4l2_i2c_subdev_init(oif_sd, client, &oif_subdev_ops);
- strcpy(oif_sd->name, "S5C73M3-OIF");
+ /* Static name; NEVER use in new drivers! */
+ strscpy(oif_sd->name, "S5C73M3-OIF", sizeof(oif_sd->name));
oif_sd->internal_ops = &oif_internal_ops;
oif_sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
diff --git a/drivers/media/i2c/s5k4ecgx.c b/drivers/media/i2c/s5k4ecgx.c
index 6ebcf254989a..79aa2740edc4 100644
--- a/drivers/media/i2c/s5k4ecgx.c
+++ b/drivers/media/i2c/s5k4ecgx.c
@@ -954,7 +954,8 @@ static int s5k4ecgx_probe(struct i2c_client *client,
sd = &priv->sd;
/* Registering subdev */
v4l2_i2c_subdev_init(sd, client, &s5k4ecgx_ops);
- strlcpy(sd->name, S5K4ECGX_DRIVER_NAME, sizeof(sd->name));
+ /* Static name; NEVER use in new drivers! */
+ strscpy(sd->name, S5K4ECGX_DRIVER_NAME, sizeof(sd->name));
sd->internal_ops = &s5k4ecgx_subdev_internal_ops;
/* Support v4l2 sub-device user space API */
diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c
index 5007c9659342..727db7c0670a 100644
--- a/drivers/media/i2c/s5k5baf.c
+++ b/drivers/media/i2c/s5k5baf.c
@@ -766,7 +766,7 @@ static int s5k5baf_hw_set_video_bus(struct s5k5baf *state)
{
u16 en_pkts;
- if (state->bus_type == V4L2_MBUS_CSI2)
+ if (state->bus_type == V4L2_MBUS_CSI2_DPHY)
en_pkts = EN_PACKETS_CSI2;
else
en_pkts = 0;
@@ -1841,7 +1841,7 @@ static int s5k5baf_parse_device_node(struct s5k5baf *state, struct device *dev)
{
struct device_node *node = dev->of_node;
struct device_node *node_ep;
- struct v4l2_fwnode_endpoint ep;
+ struct v4l2_fwnode_endpoint ep = { .bus_type = 0 };
int ret;
if (!node) {
@@ -1875,7 +1875,7 @@ static int s5k5baf_parse_device_node(struct s5k5baf *state, struct device *dev)
state->bus_type = ep.bus_type;
switch (state->bus_type) {
- case V4L2_MBUS_CSI2:
+ case V4L2_MBUS_CSI2_DPHY:
state->nlanes = ep.bus.mipi_csi2.num_data_lanes;
break;
case V4L2_MBUS_PARALLEL:
diff --git a/drivers/media/i2c/s5k6aa.c b/drivers/media/i2c/s5k6aa.c
index 13c10b5e2b45..ab26f549d716 100644
--- a/drivers/media/i2c/s5k6aa.c
+++ b/drivers/media/i2c/s5k6aa.c
@@ -688,7 +688,7 @@ static int s5k6aa_configure_video_bus(struct s5k6aa *s5k6aa,
* but there is nothing indicating how to switch between both
* in the datasheet. For now default BT.601 interface is assumed.
*/
- if (bus_type == V4L2_MBUS_CSI2)
+ if (bus_type == V4L2_MBUS_CSI2_DPHY)
cfg = nlanes;
else if (bus_type != V4L2_MBUS_PARALLEL)
return -EINVAL;
@@ -1576,7 +1576,8 @@ static int s5k6aa_probe(struct i2c_client *client,
sd = &s5k6aa->sd;
v4l2_i2c_subdev_init(sd, client, &s5k6aa_subdev_ops);
- strlcpy(sd->name, DRIVER_NAME, sizeof(sd->name));
+ /* Static name; NEVER use in new drivers! */
+ strscpy(sd->name, DRIVER_NAME, sizeof(sd->name));
sd->internal_ops = &s5k6aa_subdev_internal_ops;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
diff --git a/drivers/media/i2c/saa7115.c b/drivers/media/i2c/saa7115.c
index b07114b5efb2..6bc278aa31fc 100644
--- a/drivers/media/i2c/saa7115.c
+++ b/drivers/media/i2c/saa7115.c
@@ -59,10 +59,16 @@ enum saa711x_model {
SAA7118,
};
+enum saa711x_pads {
+ SAA711X_PAD_IF_INPUT,
+ SAA711X_PAD_VID_OUT,
+ SAA711X_NUM_PADS
+};
+
struct saa711x_state {
struct v4l2_subdev sd;
#ifdef CONFIG_MEDIA_CONTROLLER
- struct media_pad pads[DEMOD_NUM_PADS];
+ struct media_pad pads[SAA711X_NUM_PADS];
#endif
struct v4l2_ctrl_handler hdl;
@@ -1765,7 +1771,7 @@ static int saa711x_detect_chip(struct i2c_client *client,
* the lower nibble is a gm7113c.
*/
- strlcpy(name, "gm7113c", CHIP_VER_SIZE);
+ strscpy(name, "gm7113c", CHIP_VER_SIZE);
if (!autodetect && strcmp(name, id->name))
return -EINVAL;
@@ -1779,7 +1785,7 @@ static int saa711x_detect_chip(struct i2c_client *client,
/* Check if it is a CJC7113 */
if (!memcmp(name, "1111111111111111", CHIP_VER_SIZE)) {
- strlcpy(name, "cjc7113", CHIP_VER_SIZE);
+ strscpy(name, "cjc7113", CHIP_VER_SIZE);
if (!autodetect && strcmp(name, id->name))
return -EINVAL;
@@ -1825,7 +1831,7 @@ static int saa711x_probe(struct i2c_client *client,
if (ident < 0)
return ident;
- strlcpy(client->name, name, sizeof(client->name));
+ strscpy(client->name, name, sizeof(client->name));
state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
if (state == NULL)
@@ -1834,13 +1840,15 @@ static int saa711x_probe(struct i2c_client *client,
v4l2_i2c_subdev_init(sd, client, &saa711x_ops);
#if defined(CONFIG_MEDIA_CONTROLLER)
- state->pads[DEMOD_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK;
- state->pads[DEMOD_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE;
- state->pads[DEMOD_PAD_VBI_OUT].flags = MEDIA_PAD_FL_SOURCE;
+ state->pads[SAA711X_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK;
+ state->pads[SAA711X_PAD_IF_INPUT].sig_type = PAD_SIGNAL_ANALOG;
+ state->pads[SAA711X_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE;
+ state->pads[SAA711X_PAD_VID_OUT].sig_type = PAD_SIGNAL_DV;
sd->entity.function = MEDIA_ENT_F_ATV_DECODER;
- ret = media_entity_pads_init(&sd->entity, DEMOD_NUM_PADS, state->pads);
+ ret = media_entity_pads_init(&sd->entity, SAA711X_NUM_PADS,
+ state->pads);
if (ret < 0)
return ret;
#endif
diff --git a/drivers/media/i2c/saa7127.c b/drivers/media/i2c/saa7127.c
index e58a150cec5c..a67865b810c0 100644
--- a/drivers/media/i2c/saa7127.c
+++ b/drivers/media/i2c/saa7127.c
@@ -761,10 +761,10 @@ static int saa7127_probe(struct i2c_client *client,
saa7127_write(sd, SAA7129_REG_FADE_KEY_COL2,
read_result);
state->ident = SAA7129;
- strlcpy(client->name, "saa7129", I2C_NAME_SIZE);
+ strscpy(client->name, "saa7129", I2C_NAME_SIZE);
} else {
state->ident = SAA7127;
- strlcpy(client->name, "saa7127", I2C_NAME_SIZE);
+ strscpy(client->name, "saa7127", I2C_NAME_SIZE);
}
}
diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c
index 1236683da8f7..58a45c353e27 100644
--- a/drivers/media/i2c/smiapp/smiapp-core.c
+++ b/drivers/media/i2c/smiapp/smiapp-core.c
@@ -624,7 +624,7 @@ static int smiapp_init_late_controls(struct smiapp_sensor *sensor)
{
unsigned long *valid_link_freqs = &sensor->valid_link_freqs[
sensor->csi_format->compressed - sensor->compressed_min_bpp];
- unsigned int max, i;
+ unsigned int i;
for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++) {
int max_value = (1 << sensor->csi_format->width) - 1;
@@ -635,8 +635,6 @@ static int smiapp_init_late_controls(struct smiapp_sensor *sensor)
0, max_value, 1, max_value);
}
- for (max = 0; sensor->hwcfg->op_sys_clock[max + 1]; max++);
-
sensor->link_freq = v4l2_ctrl_new_int_menu(
&sensor->src->ctrl_handler, &smiapp_ctrl_ops,
V4L2_CID_LINK_FREQ, __fls(*valid_link_freqs),
@@ -2617,9 +2615,7 @@ static void smiapp_create_subdev(struct smiapp_sensor *sensor,
ssd->npads = num_pads;
ssd->source_pad = num_pads - 1;
- snprintf(ssd->sd.name,
- sizeof(ssd->sd.name), "%s %s %d-%4.4x", sensor->minfo.name,
- name, i2c_adapter_id(client->adapter), client->addr);
+ v4l2_i2c_subdev_set_name(&ssd->sd, client, sensor->minfo.name, name);
smiapp_get_native_size(ssd, &ssd->sink_fmt);
@@ -2761,7 +2757,7 @@ static int __maybe_unused smiapp_resume(struct device *dev)
static struct smiapp_hwconfig *smiapp_get_hwconfig(struct device *dev)
{
struct smiapp_hwconfig *hwcfg;
- struct v4l2_fwnode_endpoint *bus_cfg;
+ struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 };
struct fwnode_handle *ep;
struct fwnode_handle *fwnode = dev_fwnode(dev);
u32 rotation;
@@ -2775,27 +2771,33 @@ static struct smiapp_hwconfig *smiapp_get_hwconfig(struct device *dev)
if (!ep)
return NULL;
- bus_cfg = v4l2_fwnode_endpoint_alloc_parse(ep);
- if (IS_ERR(bus_cfg))
+ bus_cfg.bus_type = V4L2_MBUS_CSI2_DPHY;
+ rval = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
+ if (rval == -ENXIO) {
+ bus_cfg = (struct v4l2_fwnode_endpoint)
+ { .bus_type = V4L2_MBUS_CCP2 };
+ rval = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
+ }
+ if (rval)
goto out_err;
hwcfg = devm_kzalloc(dev, sizeof(*hwcfg), GFP_KERNEL);
if (!hwcfg)
goto out_err;
- switch (bus_cfg->bus_type) {
- case V4L2_MBUS_CSI2:
+ switch (bus_cfg.bus_type) {
+ case V4L2_MBUS_CSI2_DPHY:
hwcfg->csi_signalling_mode = SMIAPP_CSI_SIGNALLING_MODE_CSI2;
- hwcfg->lanes = bus_cfg->bus.mipi_csi2.num_data_lanes;
+ hwcfg->lanes = bus_cfg.bus.mipi_csi2.num_data_lanes;
break;
case V4L2_MBUS_CCP2:
- hwcfg->csi_signalling_mode = (bus_cfg->bus.mipi_csi1.strobe) ?
+ hwcfg->csi_signalling_mode = (bus_cfg.bus.mipi_csi1.strobe) ?
SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_STROBE :
SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK;
hwcfg->lanes = 1;
break;
default:
- dev_err(dev, "unsupported bus %u\n", bus_cfg->bus_type);
+ dev_err(dev, "unsupported bus %u\n", bus_cfg.bus_type);
goto out_err;
}
@@ -2827,28 +2829,28 @@ static struct smiapp_hwconfig *smiapp_get_hwconfig(struct device *dev)
dev_dbg(dev, "nvm %d, clk %d, mode %d\n",
hwcfg->nvm_size, hwcfg->ext_clk, hwcfg->csi_signalling_mode);
- if (!bus_cfg->nr_of_link_frequencies) {
+ if (!bus_cfg.nr_of_link_frequencies) {
dev_warn(dev, "no link frequencies defined\n");
goto out_err;
}
hwcfg->op_sys_clock = devm_kcalloc(
- dev, bus_cfg->nr_of_link_frequencies + 1 /* guardian */,
+ dev, bus_cfg.nr_of_link_frequencies + 1 /* guardian */,
sizeof(*hwcfg->op_sys_clock), GFP_KERNEL);
if (!hwcfg->op_sys_clock)
goto out_err;
- for (i = 0; i < bus_cfg->nr_of_link_frequencies; i++) {
- hwcfg->op_sys_clock[i] = bus_cfg->link_frequencies[i];
+ for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) {
+ hwcfg->op_sys_clock[i] = bus_cfg.link_frequencies[i];
dev_dbg(dev, "freq %d: %lld\n", i, hwcfg->op_sys_clock[i]);
}
- v4l2_fwnode_endpoint_free(bus_cfg);
+ v4l2_fwnode_endpoint_free(&bus_cfg);
fwnode_handle_put(ep);
return hwcfg;
out_err:
- v4l2_fwnode_endpoint_free(bus_cfg);
+ v4l2_fwnode_endpoint_free(&bus_cfg);
fwnode_handle_put(ep);
return NULL;
}
@@ -3064,9 +3066,9 @@ static int smiapp_probe(struct i2c_client *client,
if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0)
sensor->pll.flags |= SMIAPP_PLL_FLAG_NO_OP_CLOCKS;
- smiapp_create_subdev(sensor, sensor->scaler, "scaler", 2);
- smiapp_create_subdev(sensor, sensor->binner, "binner", 2);
- smiapp_create_subdev(sensor, sensor->pixel_array, "pixel_array", 1);
+ smiapp_create_subdev(sensor, sensor->scaler, " scaler", 2);
+ smiapp_create_subdev(sensor, sensor->binner, " binner", 2);
+ smiapp_create_subdev(sensor, sensor->pixel_array, " pixel_array", 1);
dev_dbg(&client->dev, "profile %d\n", sensor->minfo.smiapp_profile);
diff --git a/drivers/media/i2c/soc_camera/Makefile b/drivers/media/i2c/soc_camera/Makefile
index 8c7770f62997..09ae483b96ef 100644
--- a/drivers/media/i2c/soc_camera/Makefile
+++ b/drivers/media/i2c/soc_camera/Makefile
@@ -1,10 +1,10 @@
# SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o
-obj-$(CONFIG_SOC_CAMERA_MT9T112) += mt9t112.o
-obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o
-obj-$(CONFIG_SOC_CAMERA_OV5642) += ov5642.o
-obj-$(CONFIG_SOC_CAMERA_OV772X) += ov772x.o
-obj-$(CONFIG_SOC_CAMERA_OV9640) += ov9640.o
-obj-$(CONFIG_SOC_CAMERA_OV9740) += ov9740.o
-obj-$(CONFIG_SOC_CAMERA_RJ54N1) += rj54n1cb0c.o
-obj-$(CONFIG_SOC_CAMERA_TW9910) += tw9910.o
+obj-$(CONFIG_SOC_CAMERA_MT9M001) += soc_mt9m001.o
+obj-$(CONFIG_SOC_CAMERA_MT9T112) += soc_mt9t112.o
+obj-$(CONFIG_SOC_CAMERA_MT9V022) += soc_mt9v022.o
+obj-$(CONFIG_SOC_CAMERA_OV5642) += soc_ov5642.o
+obj-$(CONFIG_SOC_CAMERA_OV772X) += soc_ov772x.o
+obj-$(CONFIG_SOC_CAMERA_OV9640) += soc_ov9640.o
+obj-$(CONFIG_SOC_CAMERA_OV9740) += soc_ov9740.o
+obj-$(CONFIG_SOC_CAMERA_RJ54N1) += soc_rj54n1cb0c.o
+obj-$(CONFIG_SOC_CAMERA_TW9910) += soc_tw9910.o
diff --git a/drivers/media/i2c/soc_camera/mt9m001.c b/drivers/media/i2c/soc_camera/soc_mt9m001.c
index 1bfb0d53059e..a1a85ff838c5 100644
--- a/drivers/media/i2c/soc_camera/mt9m001.c
+++ b/drivers/media/i2c/soc_camera/soc_mt9m001.c
@@ -243,7 +243,6 @@ static int mt9m001_get_selection(struct v4l2_subdev *sd,
switch (sel->target) {
case V4L2_SEL_TGT_CROP_BOUNDS:
- case V4L2_SEL_TGT_CROP_DEFAULT:
sel->r.left = MT9M001_COLUMN_SKIP;
sel->r.top = MT9M001_ROW_SKIP;
sel->r.width = MT9M001_MAX_WIDTH;
diff --git a/drivers/media/i2c/soc_camera/mt9t112.c b/drivers/media/i2c/soc_camera/soc_mt9t112.c
index b53c36dfa469..ea1ff270bc2d 100644
--- a/drivers/media/i2c/soc_camera/mt9t112.c
+++ b/drivers/media/i2c/soc_camera/soc_mt9t112.c
@@ -884,12 +884,6 @@ static int mt9t112_get_selection(struct v4l2_subdev *sd,
sel->r.width = MAX_WIDTH;
sel->r.height = MAX_HEIGHT;
return 0;
- case V4L2_SEL_TGT_CROP_DEFAULT:
- sel->r.left = 0;
- sel->r.top = 0;
- sel->r.width = VGA_WIDTH;
- sel->r.height = VGA_HEIGHT;
- return 0;
case V4L2_SEL_TGT_CROP:
sel->r = priv->frame;
return 0;
diff --git a/drivers/media/i2c/soc_camera/mt9v022.c b/drivers/media/i2c/soc_camera/soc_mt9v022.c
index 762f06919329..6d922b17ea94 100644
--- a/drivers/media/i2c/soc_camera/mt9v022.c
+++ b/drivers/media/i2c/soc_camera/soc_mt9v022.c
@@ -368,7 +368,6 @@ static int mt9v022_get_selection(struct v4l2_subdev *sd,
switch (sel->target) {
case V4L2_SEL_TGT_CROP_BOUNDS:
- case V4L2_SEL_TGT_CROP_DEFAULT:
sel->r.left = MT9V022_COLUMN_SKIP;
sel->r.top = MT9V022_ROW_SKIP;
sel->r.width = MT9V022_MAX_WIDTH;
diff --git a/drivers/media/i2c/soc_camera/ov5642.c b/drivers/media/i2c/soc_camera/soc_ov5642.c
index 39f420db9c70..0931898c79dd 100644
--- a/drivers/media/i2c/soc_camera/ov5642.c
+++ b/drivers/media/i2c/soc_camera/soc_ov5642.c
@@ -896,7 +896,6 @@ static int ov5642_get_selection(struct v4l2_subdev *sd,
switch (sel->target) {
case V4L2_SEL_TGT_CROP_BOUNDS:
- case V4L2_SEL_TGT_CROP_DEFAULT:
sel->r.left = 0;
sel->r.top = 0;
sel->r.width = OV5642_MAX_WIDTH;
@@ -913,7 +912,7 @@ static int ov5642_get_selection(struct v4l2_subdev *sd,
static int ov5642_g_mbus_config(struct v4l2_subdev *sd,
struct v4l2_mbus_config *cfg)
{
- cfg->type = V4L2_MBUS_CSI2;
+ cfg->type = V4L2_MBUS_CSI2_DPHY;
cfg->flags = V4L2_MBUS_CSI2_2_LANE | V4L2_MBUS_CSI2_CHANNEL_0 |
V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
diff --git a/drivers/media/i2c/soc_camera/ov772x.c b/drivers/media/i2c/soc_camera/soc_ov772x.c
index 14377af7c888..fafd372527b2 100644
--- a/drivers/media/i2c/soc_camera/ov772x.c
+++ b/drivers/media/i2c/soc_camera/soc_ov772x.c
@@ -862,7 +862,6 @@ static int ov772x_get_selection(struct v4l2_subdev *sd,
sel->r.top = 0;
switch (sel->target) {
case V4L2_SEL_TGT_CROP_BOUNDS:
- case V4L2_SEL_TGT_CROP_DEFAULT:
sel->r.width = OV772X_MAX_WIDTH;
sel->r.height = OV772X_MAX_HEIGHT;
return 0;
diff --git a/drivers/media/i2c/soc_camera/ov9640.c b/drivers/media/i2c/soc_camera/soc_ov9640.c
index c63948989688..eb91b8240083 100644
--- a/drivers/media/i2c/soc_camera/ov9640.c
+++ b/drivers/media/i2c/soc_camera/soc_ov9640.c
@@ -554,7 +554,6 @@ static int ov9640_get_selection(struct v4l2_subdev *sd,
sel->r.top = 0;
switch (sel->target) {
case V4L2_SEL_TGT_CROP_BOUNDS:
- case V4L2_SEL_TGT_CROP_DEFAULT:
case V4L2_SEL_TGT_CROP:
sel->r.width = W_SXGA;
sel->r.height = H_SXGA;
diff --git a/drivers/media/i2c/soc_camera/ov9740.c b/drivers/media/i2c/soc_camera/soc_ov9740.c
index 755de2289c39..a07d3145d1b4 100644
--- a/drivers/media/i2c/soc_camera/ov9740.c
+++ b/drivers/media/i2c/soc_camera/soc_ov9740.c
@@ -730,7 +730,6 @@ static int ov9740_get_selection(struct v4l2_subdev *sd,
switch (sel->target) {
case V4L2_SEL_TGT_CROP_BOUNDS:
- case V4L2_SEL_TGT_CROP_DEFAULT:
case V4L2_SEL_TGT_CROP:
sel->r.left = 0;
sel->r.top = 0;
diff --git a/drivers/media/i2c/soc_camera/rj54n1cb0c.c b/drivers/media/i2c/soc_camera/soc_rj54n1cb0c.c
index 02398d0bc649..f0cb49a6167b 100644
--- a/drivers/media/i2c/soc_camera/rj54n1cb0c.c
+++ b/drivers/media/i2c/soc_camera/soc_rj54n1cb0c.c
@@ -591,7 +591,6 @@ static int rj54n1_get_selection(struct v4l2_subdev *sd,
switch (sel->target) {
case V4L2_SEL_TGT_CROP_BOUNDS:
- case V4L2_SEL_TGT_CROP_DEFAULT:
sel->r.left = RJ54N1_COLUMN_SKIP;
sel->r.top = RJ54N1_ROW_SKIP;
sel->r.width = RJ54N1_MAX_WIDTH;
diff --git a/drivers/media/i2c/soc_camera/tw9910.c b/drivers/media/i2c/soc_camera/soc_tw9910.c
index bdb5e0a431e9..bdb5e0a431e9 100644
--- a/drivers/media/i2c/soc_camera/tw9910.c
+++ b/drivers/media/i2c/soc_camera/soc_tw9910.c
diff --git a/drivers/media/i2c/sr030pc30.c b/drivers/media/i2c/sr030pc30.c
index 2a4882cddc51..11f6c7a5e0e7 100644
--- a/drivers/media/i2c/sr030pc30.c
+++ b/drivers/media/i2c/sr030pc30.c
@@ -569,7 +569,7 @@ static int sr030pc30_base_config(struct v4l2_subdev *sd)
if (!ret)
ret = sr030pc30_pwr_ctrl(sd, false, false);
- if (!ret && !info->pdata)
+ if (ret)
return ret;
expmin = EXPOS_MIN_MS * info->pdata->clk_rate / (8 * 1000);
@@ -703,7 +703,6 @@ static int sr030pc30_probe(struct i2c_client *client,
return -ENOMEM;
sd = &info->sd;
- strcpy(sd->name, MODULE_NAME);
info->pdata = client->dev.platform_data;
v4l2_i2c_subdev_init(sd, client, &sr030pc30_ops);
diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c
index 44c41933415a..a38e54b8f687 100644
--- a/drivers/media/i2c/tc358743.c
+++ b/drivers/media/i2c/tc358743.c
@@ -444,7 +444,7 @@ static void print_avi_infoframe(struct v4l2_subdev *sd)
i2c_rd(sd, PK_AVI_0HEAD, buffer, HDMI_INFOFRAME_SIZE(AVI));
- if (hdmi_infoframe_unpack(&frame, buffer) < 0) {
+ if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) {
v4l2_err(sd, "%s: unpack of AVI infoframe failed\n", __func__);
return;
}
@@ -1243,9 +1243,9 @@ static int tc358743_log_status(struct v4l2_subdev *sd)
u8 vi_status3 = i2c_rd8(sd, VI_STATUS3);
const int deep_color_mode[4] = { 8, 10, 12, 16 };
static const char * const input_color_space[] = {
- "RGB", "YCbCr 601", "Adobe RGB", "YCbCr 709", "NA (4)",
+ "RGB", "YCbCr 601", "opRGB", "YCbCr 709", "NA (4)",
"xvYCC 601", "NA(6)", "xvYCC 709", "NA(8)", "sYCC601",
- "NA(10)", "NA(11)", "NA(12)", "Adobe YCC 601"};
+ "NA(10)", "NA(11)", "NA(12)", "opYCC 601"};
v4l2_info(sd, "-----Chip status-----\n");
v4l2_info(sd, "Chip ID: 0x%02x\n",
@@ -1607,7 +1607,7 @@ static int tc358743_g_mbus_config(struct v4l2_subdev *sd,
{
struct tc358743_state *state = to_state(sd);
- cfg->type = V4L2_MBUS_CSI2;
+ cfg->type = V4L2_MBUS_CSI2_DPHY;
/* Support for non-continuous CSI-2 clock is missing in the driver */
cfg->flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
@@ -1789,7 +1789,7 @@ static int tc358743_s_edid(struct v4l2_subdev *sd,
return -E2BIG;
}
pa = cec_get_edid_phys_addr(edid->edid, edid->blocks * 128, NULL);
- err = cec_phys_addr_validate(pa, &pa, NULL);
+ err = v4l2_phys_addr_validate(pa, &pa, NULL);
if (err)
return err;
@@ -1895,11 +1895,11 @@ static void tc358743_gpio_reset(struct tc358743_state *state)
static int tc358743_probe_of(struct tc358743_state *state)
{
struct device *dev = &state->i2c_client->dev;
- struct v4l2_fwnode_endpoint *endpoint;
+ struct v4l2_fwnode_endpoint endpoint = { .bus_type = 0 };
struct device_node *ep;
struct clk *refclk;
u32 bps_pr_lane;
- int ret = -EINVAL;
+ int ret;
refclk = devm_clk_get(dev, "refclk");
if (IS_ERR(refclk)) {
@@ -1915,26 +1915,28 @@ static int tc358743_probe_of(struct tc358743_state *state)
return -EINVAL;
}
- endpoint = v4l2_fwnode_endpoint_alloc_parse(of_fwnode_handle(ep));
- if (IS_ERR(endpoint)) {
+ ret = v4l2_fwnode_endpoint_alloc_parse(of_fwnode_handle(ep), &endpoint);
+ if (ret) {
dev_err(dev, "failed to parse endpoint\n");
- ret = PTR_ERR(endpoint);
+ ret = ret;
goto put_node;
}
- if (endpoint->bus_type != V4L2_MBUS_CSI2 ||
- endpoint->bus.mipi_csi2.num_data_lanes == 0 ||
- endpoint->nr_of_link_frequencies == 0) {
+ if (endpoint.bus_type != V4L2_MBUS_CSI2_DPHY ||
+ endpoint.bus.mipi_csi2.num_data_lanes == 0 ||
+ endpoint.nr_of_link_frequencies == 0) {
dev_err(dev, "missing CSI-2 properties in endpoint\n");
+ ret = -EINVAL;
goto free_endpoint;
}
- if (endpoint->bus.mipi_csi2.num_data_lanes > 4) {
+ if (endpoint.bus.mipi_csi2.num_data_lanes > 4) {
dev_err(dev, "invalid number of lanes\n");
+ ret = -EINVAL;
goto free_endpoint;
}
- state->bus = endpoint->bus.mipi_csi2;
+ state->bus = endpoint.bus.mipi_csi2;
ret = clk_prepare_enable(refclk);
if (ret) {
@@ -1967,7 +1969,7 @@ static int tc358743_probe_of(struct tc358743_state *state)
* The CSI bps per lane must be between 62.5 Mbps and 1 Gbps.
* The default is 594 Mbps for 4-lane 1080p60 or 2-lane 720p60.
*/
- bps_pr_lane = 2 * endpoint->link_frequencies[0];
+ 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);
goto disable_clk;
@@ -2013,7 +2015,7 @@ static int tc358743_probe_of(struct tc358743_state *state)
disable_clk:
clk_disable_unprepare(refclk);
free_endpoint:
- v4l2_fwnode_endpoint_free(endpoint);
+ v4l2_fwnode_endpoint_free(&endpoint);
put_node:
of_node_put(ep);
return ret;
diff --git a/drivers/media/i2c/tda1997x.c b/drivers/media/i2c/tda1997x.c
index d114ac5243ec..e8613e364403 100644
--- a/drivers/media/i2c/tda1997x.c
+++ b/drivers/media/i2c/tda1997x.c
@@ -1253,7 +1253,7 @@ tda1997x_parse_infoframe(struct tda1997x_state *state, u16 addr)
/* read data */
len = io_readn(sd, addr, sizeof(buffer), buffer);
- err = hdmi_infoframe_unpack(&frame, buffer);
+ err = hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer));
if (err) {
v4l_err(state->client,
"failed parsing %d byte infoframe: 0x%04x/0x%02x\n",
@@ -1928,7 +1928,7 @@ static int tda1997x_log_infoframe(struct v4l2_subdev *sd, int addr)
/* read data */
len = io_readn(sd, addr, sizeof(buffer), buffer);
v4l2_dbg(1, debug, sd, "infoframe: addr=%d len=%d\n", addr, len);
- err = hdmi_infoframe_unpack(&frame, buffer);
+ err = hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer));
if (err) {
v4l_err(state->client,
"failed parsing %d byte infoframe: 0x%04x/0x%02x\n",
@@ -2265,7 +2265,7 @@ MODULE_DEVICE_TABLE(of, tda1997x_of_id);
static int tda1997x_parse_dt(struct tda1997x_state *state)
{
struct tda1997x_platform_data *pdata = &state->pdata;
- struct v4l2_fwnode_endpoint bus_cfg;
+ struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 };
struct device_node *ep;
struct device_node *np;
unsigned int flags;
diff --git a/drivers/media/i2c/tvaudio.c b/drivers/media/i2c/tvaudio.c
index 5919214a56bf..af2da977a685 100644
--- a/drivers/media/i2c/tvaudio.c
+++ b/drivers/media/i2c/tvaudio.c
@@ -1981,7 +1981,7 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id *
/* fill required data structures */
if (!id)
- strlcpy(client->name, desc->name, I2C_NAME_SIZE);
+ strscpy(client->name, desc->name, I2C_NAME_SIZE);
chip->desc = desc;
chip->shadow.count = desc->registers+1;
chip->prevmode = -1;
diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c
index 675b9ae212ab..1cc83cb934e2 100644
--- a/drivers/media/i2c/tvp514x.c
+++ b/drivers/media/i2c/tvp514x.c
@@ -989,7 +989,7 @@ static struct tvp514x_platform_data *
tvp514x_get_pdata(struct i2c_client *client)
{
struct tvp514x_platform_data *pdata = NULL;
- struct v4l2_fwnode_endpoint bus_cfg;
+ struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 };
struct device_node *endpoint;
unsigned int flags;
diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index 76e6bed5a1da..0e91b9949c3a 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -10,8 +10,10 @@
#include <linux/videodev2.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of_graph.h>
+#include <linux/regmap.h>
#include <media/v4l2-async.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
@@ -26,6 +28,9 @@
#define TVP5150_MAX_CROP_LEFT 511
#define TVP5150_MAX_CROP_TOP 127
#define TVP5150_CROP_SHIFT 2
+#define TVP5150_MBUS_FMT MEDIA_BUS_FMT_UYVY8_2X8
+#define TVP5150_FIELD V4L2_FIELD_ALTERNATE
+#define TVP5150_COLORSPACE V4L2_COLORSPACE_SMPTE170M
MODULE_DESCRIPTION("Texas Instruments TVP5150A/TVP5150AM1/TVP5151 video decoder driver");
MODULE_AUTHOR("Mauro Carvalho Chehab");
@@ -38,20 +43,31 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)");
#define dprintk0(__dev, __arg...) dev_dbg_lvl(__dev, 0, 0, __arg)
+enum tvp5150_pads {
+ TVP5150_PAD_IF_INPUT,
+ TVP5150_PAD_VID_OUT,
+ TVP5150_NUM_PADS
+};
+
struct tvp5150 {
struct v4l2_subdev sd;
#ifdef CONFIG_MEDIA_CONTROLLER
- struct media_pad pads[DEMOD_NUM_PADS];
+ struct media_pad pads[TVP5150_NUM_PADS];
struct media_entity input_ent[TVP5150_INPUT_NUM];
struct media_pad input_pad[TVP5150_INPUT_NUM];
#endif
struct v4l2_ctrl_handler hdl;
struct v4l2_rect rect;
+ struct regmap *regmap;
+ int irq;
v4l2_std_id norm; /* Current set standard */
+ v4l2_std_id detected_norm;
u32 input;
u32 output;
+ u32 oe;
int enable;
+ bool lock;
u16 dev_id;
u16 rom_ver;
@@ -71,32 +87,14 @@ static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
static int tvp5150_read(struct v4l2_subdev *sd, unsigned char addr)
{
- struct i2c_client *c = v4l2_get_subdevdata(sd);
- int rc;
-
- rc = i2c_smbus_read_byte_data(c, addr);
- if (rc < 0) {
- dev_err(sd->dev, "i2c i/o error: rc == %d\n", rc);
- return rc;
- }
-
- dev_dbg_lvl(sd->dev, 2, debug, "tvp5150: read 0x%02x = %02x\n", addr, rc);
-
- return rc;
-}
-
-static int tvp5150_write(struct v4l2_subdev *sd, unsigned char addr,
- unsigned char value)
-{
- struct i2c_client *c = v4l2_get_subdevdata(sd);
- int rc;
+ struct tvp5150 *decoder = to_tvp5150(sd);
+ int ret, val;
- dev_dbg_lvl(sd->dev, 2, debug, "tvp5150: writing %02x %02x\n", addr, value);
- rc = i2c_smbus_write_byte_data(c, addr, value);
- if (rc < 0)
- dev_err(sd->dev, "i2c i/o error: rc == %d\n", rc);
+ ret = regmap_read(decoder->regmap, addr, &val);
+ if (ret < 0)
+ return ret;
- return rc;
+ return val;
}
static void dump_reg_range(struct v4l2_subdev *sd, char *s, u8 init,
@@ -262,8 +260,8 @@ static void tvp5150_selmux(struct v4l2_subdev *sd)
{
int opmode = 0;
struct tvp5150 *decoder = to_tvp5150(sd);
+ unsigned int mask, val;
int input = 0;
- int val;
/* Only tvp5150am1 and tvp5151 have signal generator support */
if ((decoder->dev_id == 0x5150 && decoder->rom_ver == 0x0400) ||
@@ -288,8 +286,8 @@ static void tvp5150_selmux(struct v4l2_subdev *sd)
decoder->input, decoder->output,
input, opmode);
- tvp5150_write(sd, TVP5150_OP_MODE_CTL, opmode);
- tvp5150_write(sd, TVP5150_VD_IN_SRC_SEL_1, input);
+ regmap_write(decoder->regmap, TVP5150_OP_MODE_CTL, opmode);
+ regmap_write(decoder->regmap, TVP5150_VD_IN_SRC_SEL_1, input);
/*
* Setup the FID/GLCO/VLK/HVLK and INTREQ/GPCL/VBLK output signals. For
@@ -298,17 +296,12 @@ static void tvp5150_selmux(struct v4l2_subdev *sd)
* field indicator (FID) signal on FID/GLCO/VLK/HVLK and set
* INTREQ/GPCL/VBLK to logic 1.
*/
- val = tvp5150_read(sd, TVP5150_MISC_CTL);
- if (val < 0) {
- dev_err(sd->dev, "%s: failed with error = %d\n", __func__, val);
- return;
- }
-
+ mask = TVP5150_MISC_CTL_GPCL | TVP5150_MISC_CTL_HVLK;
if (decoder->input == TVP5150_SVIDEO)
- val = (val & ~TVP5150_MISC_CTL_GPCL) | TVP5150_MISC_CTL_HVLK;
+ val = TVP5150_MISC_CTL_HVLK;
else
- val = (val & ~TVP5150_MISC_CTL_HVLK) | TVP5150_MISC_CTL_GPCL;
- tvp5150_write(sd, TVP5150_MISC_CTL, val);
+ val = TVP5150_MISC_CTL_GPCL;
+ regmap_update_bits(decoder->regmap, TVP5150_MISC_CTL, mask, val);
};
struct i2c_reg_value {
@@ -454,9 +447,7 @@ static const struct i2c_reg_value tvp5150_init_default[] = {
/* Default values as sugested at TVP5150AM1 datasheet */
static const struct i2c_reg_value tvp5150_init_enable[] = {
- {
- TVP5150_CONF_SHARED_PIN, 2
- }, { /* Automatic offset and AGC enabled */
+ { /* Automatic offset and AGC enabled */
TVP5150_ANAL_CHL_CTL, 0x15
}, { /* Activate YCrCb output 0x9 or 0xd ? */
TVP5150_MISC_CTL, TVP5150_MISC_CTL_GPCL |
@@ -583,8 +574,10 @@ static struct i2c_vbi_ram_value vbi_ram_default[] = {
static int tvp5150_write_inittab(struct v4l2_subdev *sd,
const struct i2c_reg_value *regs)
{
+ struct tvp5150 *decoder = to_tvp5150(sd);
+
while (regs->reg != 0xff) {
- tvp5150_write(sd, regs->reg, regs->value);
+ regmap_write(decoder->regmap, regs->reg, regs->value);
regs++;
}
return 0;
@@ -592,15 +585,17 @@ static int tvp5150_write_inittab(struct v4l2_subdev *sd,
static int tvp5150_vdp_init(struct v4l2_subdev *sd)
{
+ struct tvp5150 *decoder = to_tvp5150(sd);
+ struct regmap *map = decoder->regmap;
unsigned int i;
int j;
/* Disable Full Field */
- tvp5150_write(sd, TVP5150_FULL_FIELD_ENA, 0);
+ regmap_write(map, TVP5150_FULL_FIELD_ENA, 0);
/* Before programming, Line mode should be at 0xff */
for (i = TVP5150_LINE_MODE_INI; i <= TVP5150_LINE_MODE_END; i++)
- tvp5150_write(sd, i, 0xff);
+ regmap_write(map, i, 0xff);
/* Load Ram Table */
for (j = 0; j < ARRAY_SIZE(vbi_ram_default); j++) {
@@ -609,11 +604,12 @@ static int tvp5150_vdp_init(struct v4l2_subdev *sd)
if (!regs->type.vbi_type)
continue;
- tvp5150_write(sd, TVP5150_CONF_RAM_ADDR_HIGH, regs->reg >> 8);
- tvp5150_write(sd, TVP5150_CONF_RAM_ADDR_LOW, regs->reg);
+ regmap_write(map, TVP5150_CONF_RAM_ADDR_HIGH, regs->reg >> 8);
+ regmap_write(map, TVP5150_CONF_RAM_ADDR_LOW, regs->reg);
for (i = 0; i < 16; i++)
- tvp5150_write(sd, TVP5150_VDP_CONF_RAM_DATA, regs->values[i]);
+ regmap_write(map, TVP5150_VDP_CONF_RAM_DATA,
+ regs->values[i]);
}
return 0;
}
@@ -693,10 +689,10 @@ static int tvp5150_set_vbi(struct v4l2_subdev *sd,
reg = ((line - 6) << 1) + TVP5150_LINE_MODE_INI;
if (fields & 1)
- tvp5150_write(sd, reg, type);
+ regmap_write(decoder->regmap, reg, type);
if (fields & 2)
- tvp5150_write(sd, reg + 1, type);
+ regmap_write(decoder->regmap, reg + 1, type);
return type;
}
@@ -742,8 +738,6 @@ static int tvp5150_set_std(struct v4l2_subdev *sd, v4l2_std_id std)
struct tvp5150 *decoder = to_tvp5150(sd);
int fmt = 0;
- decoder->norm = std;
-
/* First tests should be against specific std */
if (std == V4L2_STD_NTSC_443) {
@@ -763,7 +757,16 @@ static int tvp5150_set_std(struct v4l2_subdev *sd, v4l2_std_id std)
}
dev_dbg_lvl(sd->dev, 1, debug, "Set video std register to %d.\n", fmt);
- tvp5150_write(sd, TVP5150_VIDEO_STD, fmt);
+ regmap_write(decoder->regmap, TVP5150_VIDEO_STD, fmt);
+ return 0;
+}
+
+static int tvp5150_g_std(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+ struct tvp5150 *decoder = to_tvp5150(sd);
+
+ *std = decoder->norm;
+
return 0;
}
@@ -780,33 +783,166 @@ static int tvp5150_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
else
decoder->rect.height = TVP5150_V_MAX_OTHERS;
+ decoder->norm = std;
return tvp5150_set_std(sd, std);
}
+static v4l2_std_id tvp5150_read_std(struct v4l2_subdev *sd)
+{
+ int val = tvp5150_read(sd, TVP5150_STATUS_REG_5);
+
+ switch (val & 0x0F) {
+ case 0x01:
+ return V4L2_STD_NTSC;
+ case 0x03:
+ return V4L2_STD_PAL;
+ case 0x05:
+ return V4L2_STD_PAL_M;
+ case 0x07:
+ return V4L2_STD_PAL_N | V4L2_STD_PAL_Nc;
+ case 0x09:
+ return V4L2_STD_NTSC_443;
+ case 0xb:
+ return V4L2_STD_SECAM;
+ default:
+ return V4L2_STD_UNKNOWN;
+ }
+}
+
+static int query_lock(struct v4l2_subdev *sd)
+{
+ struct tvp5150 *decoder = to_tvp5150(sd);
+ int status;
+
+ if (decoder->irq)
+ return decoder->lock;
+
+ regmap_read(decoder->regmap, TVP5150_STATUS_REG_1, &status);
+
+ /* For standard detection, we need the 3 locks */
+ return (status & 0x0e) == 0x0e;
+}
+
+static int tvp5150_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id)
+{
+ *std_id = query_lock(sd) ? tvp5150_read_std(sd) : V4L2_STD_UNKNOWN;
+
+ return 0;
+}
+
+static const struct v4l2_event tvp5150_ev_fmt = {
+ .type = V4L2_EVENT_SOURCE_CHANGE,
+ .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
+};
+
+static irqreturn_t tvp5150_isr(int irq, void *dev_id)
+{
+ struct tvp5150 *decoder = dev_id;
+ struct regmap *map = decoder->regmap;
+ unsigned int mask, active = 0, status = 0;
+
+ mask = TVP5150_MISC_CTL_YCBCR_OE | TVP5150_MISC_CTL_SYNC_OE |
+ TVP5150_MISC_CTL_CLOCK_OE;
+
+ regmap_read(map, TVP5150_INT_STATUS_REG_A, &status);
+ if (status) {
+ regmap_write(map, TVP5150_INT_STATUS_REG_A, status);
+
+ if (status & TVP5150_INT_A_LOCK) {
+ decoder->lock = !!(status & TVP5150_INT_A_LOCK_STATUS);
+ dev_dbg_lvl(decoder->sd.dev, 1, debug,
+ "sync lo%s signal\n",
+ decoder->lock ? "ck" : "ss");
+ v4l2_subdev_notify_event(&decoder->sd, &tvp5150_ev_fmt);
+ regmap_update_bits(map, TVP5150_MISC_CTL, mask,
+ decoder->lock ? decoder->oe : 0);
+ }
+
+ return IRQ_HANDLED;
+ }
+
+ regmap_read(map, TVP5150_INT_ACTIVE_REG_B, &active);
+ if (active) {
+ status = 0;
+ regmap_read(map, TVP5150_INT_STATUS_REG_B, &status);
+ if (status)
+ regmap_write(map, TVP5150_INT_RESET_REG_B, status);
+ }
+
+ return IRQ_HANDLED;
+}
+
static int tvp5150_reset(struct v4l2_subdev *sd, u32 val)
{
struct tvp5150 *decoder = to_tvp5150(sd);
+ struct regmap *map = decoder->regmap;
/* Initializes TVP5150 to its default values */
tvp5150_write_inittab(sd, tvp5150_init_default);
+ if (decoder->irq) {
+ /* Configure pins: FID, VSYNC, INTREQ, SCLK */
+ regmap_write(map, TVP5150_CONF_SHARED_PIN, 0x0);
+ /* Set interrupt polarity to active high */
+ regmap_write(map, TVP5150_INT_CONF, TVP5150_VDPOE | 0x1);
+ regmap_write(map, TVP5150_INTT_CONFIG_REG_B, 0x1);
+ } else {
+ /* Configure pins: FID, VSYNC, GPCL/VBLK, SCLK */
+ regmap_write(map, TVP5150_CONF_SHARED_PIN, 0x2);
+ /* Keep interrupt polarity active low */
+ regmap_write(map, TVP5150_INT_CONF, TVP5150_VDPOE);
+ regmap_write(map, TVP5150_INTT_CONFIG_REG_B, 0x0);
+ }
+
/* Initializes VDP registers */
tvp5150_vdp_init(sd);
/* Selects decoder input */
tvp5150_selmux(sd);
+ /* Initialize image preferences */
+ v4l2_ctrl_handler_setup(&decoder->hdl);
+
+ return 0;
+}
+
+static int tvp5150_enable(struct v4l2_subdev *sd)
+{
+ struct tvp5150 *decoder = to_tvp5150(sd);
+ v4l2_std_id std;
+
/* Initializes TVP5150 to stream enabled values */
tvp5150_write_inittab(sd, tvp5150_init_enable);
- /* Initialize image preferences */
- v4l2_ctrl_handler_setup(&decoder->hdl);
+ if (decoder->norm == V4L2_STD_ALL)
+ std = tvp5150_read_std(sd);
+ else
+ std = decoder->norm;
- tvp5150_set_std(sd, decoder->norm);
+ /* Disable autoswitch mode */
+ tvp5150_set_std(sd, std);
- if (decoder->mbus_type == V4L2_MBUS_PARALLEL)
- tvp5150_write(sd, TVP5150_DATA_RATE_SEL, 0x40);
+ /*
+ * Enable the YCbCr and clock outputs. In discrete sync mode
+ * (non-BT.656) additionally enable the the sync outputs.
+ */
+ switch (decoder->mbus_type) {
+ case V4L2_MBUS_PARALLEL:
+ /* 8-bit 4:2:2 YUV with discrete sync output */
+ regmap_update_bits(decoder->regmap, TVP5150_DATA_RATE_SEL,
+ 0x7, 0x0);
+ decoder->oe = TVP5150_MISC_CTL_YCBCR_OE |
+ TVP5150_MISC_CTL_CLOCK_OE |
+ TVP5150_MISC_CTL_SYNC_OE;
+ break;
+ case V4L2_MBUS_BT656:
+ decoder->oe = TVP5150_MISC_CTL_YCBCR_OE |
+ TVP5150_MISC_CTL_CLOCK_OE;
+ break;
+ default:
+ return -EINVAL;
+ }
return 0;
};
@@ -818,17 +954,18 @@ static int tvp5150_s_ctrl(struct v4l2_ctrl *ctrl)
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
- tvp5150_write(sd, TVP5150_BRIGHT_CTL, ctrl->val);
+ regmap_write(decoder->regmap, TVP5150_BRIGHT_CTL, ctrl->val);
return 0;
case V4L2_CID_CONTRAST:
- tvp5150_write(sd, TVP5150_CONTRAST_CTL, ctrl->val);
+ regmap_write(decoder->regmap, TVP5150_CONTRAST_CTL, ctrl->val);
return 0;
case V4L2_CID_SATURATION:
- tvp5150_write(sd, TVP5150_SATURATION_CTL, ctrl->val);
+ regmap_write(decoder->regmap, TVP5150_SATURATION_CTL,
+ ctrl->val);
return 0;
case V4L2_CID_HUE:
- tvp5150_write(sd, TVP5150_HUE_CTL, ctrl->val);
- break;
+ regmap_write(decoder->regmap, TVP5150_HUE_CTL, ctrl->val);
+ return 0;
case V4L2_CID_TEST_PATTERN:
decoder->enable = ctrl->val ? false : true;
tvp5150_selmux(sd);
@@ -837,36 +974,26 @@ static int tvp5150_s_ctrl(struct v4l2_ctrl *ctrl)
return -EINVAL;
}
-static v4l2_std_id tvp5150_read_std(struct v4l2_subdev *sd)
+static void tvp5150_set_default(v4l2_std_id std, struct v4l2_rect *crop)
{
- int val = tvp5150_read(sd, TVP5150_STATUS_REG_5);
-
- switch (val & 0x0F) {
- case 0x01:
- return V4L2_STD_NTSC;
- case 0x03:
- return V4L2_STD_PAL;
- case 0x05:
- return V4L2_STD_PAL_M;
- case 0x07:
- return V4L2_STD_PAL_N | V4L2_STD_PAL_Nc;
- case 0x09:
- return V4L2_STD_NTSC_443;
- case 0xb:
- return V4L2_STD_SECAM;
- default:
- return V4L2_STD_UNKNOWN;
- }
+ /* Default is no cropping */
+ crop->top = 0;
+ crop->left = 0;
+ crop->width = TVP5150_H_MAX;
+ if (std & V4L2_STD_525_60)
+ crop->height = TVP5150_V_MAX_525_60;
+ else
+ crop->height = TVP5150_V_MAX_OTHERS;
}
static int tvp5150_fill_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_format *format)
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *f;
struct tvp5150 *decoder = to_tvp5150(sd);
- if (!format || (format->pad != DEMOD_PAD_VID_OUT))
+ if (!format || (format->pad != TVP5150_PAD_VID_OUT))
return -EINVAL;
f = &format->format;
@@ -874,12 +1001,12 @@ static int tvp5150_fill_fmt(struct v4l2_subdev *sd,
f->width = decoder->rect.width;
f->height = decoder->rect.height / 2;
- f->code = MEDIA_BUS_FMT_UYVY8_2X8;
- f->field = V4L2_FIELD_ALTERNATE;
- f->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ f->code = TVP5150_MBUS_FMT;
+ f->field = TVP5150_FIELD;
+ f->colorspace = TVP5150_COLORSPACE;
dev_dbg_lvl(sd->dev, 1, debug, "width = %d, height = %d\n", f->width,
- f->height);
+ f->height);
return 0;
}
@@ -901,9 +1028,6 @@ static int tvp5150_set_selection(struct v4l2_subdev *sd,
/* tvp5150 has some special limits */
rect.left = clamp(rect.left, 0, TVP5150_MAX_CROP_LEFT);
- rect.width = clamp_t(unsigned int, rect.width,
- TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect.left,
- TVP5150_H_MAX - rect.left);
rect.top = clamp(rect.top, 0, TVP5150_MAX_CROP_TOP);
/* Calculate height based on current standard */
@@ -917,22 +1041,29 @@ static int tvp5150_set_selection(struct v4l2_subdev *sd,
else
hmax = TVP5150_V_MAX_OTHERS;
- rect.height = clamp_t(unsigned int, rect.height,
+ /*
+ * alignments:
+ * - width = 2 due to UYVY colorspace
+ * - height, image = no special alignment
+ */
+ v4l_bound_align_image(&rect.width,
+ TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect.left,
+ TVP5150_H_MAX - rect.left, 1, &rect.height,
hmax - TVP5150_MAX_CROP_TOP - rect.top,
- hmax - rect.top);
-
- tvp5150_write(sd, TVP5150_VERT_BLANKING_START, rect.top);
- tvp5150_write(sd, TVP5150_VERT_BLANKING_STOP,
- rect.top + rect.height - hmax);
- tvp5150_write(sd, TVP5150_ACT_VD_CROP_ST_MSB,
- rect.left >> TVP5150_CROP_SHIFT);
- tvp5150_write(sd, TVP5150_ACT_VD_CROP_ST_LSB,
- rect.left | (1 << TVP5150_CROP_SHIFT));
- tvp5150_write(sd, TVP5150_ACT_VD_CROP_STP_MSB,
- (rect.left + rect.width - TVP5150_MAX_CROP_LEFT) >>
- TVP5150_CROP_SHIFT);
- tvp5150_write(sd, TVP5150_ACT_VD_CROP_STP_LSB,
- rect.left + rect.width - TVP5150_MAX_CROP_LEFT);
+ hmax - rect.top, 0, 0);
+
+ regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_START, rect.top);
+ regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_STOP,
+ rect.top + rect.height - hmax);
+ regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_MSB,
+ rect.left >> TVP5150_CROP_SHIFT);
+ regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_LSB,
+ rect.left | (1 << TVP5150_CROP_SHIFT));
+ regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_MSB,
+ (rect.left + rect.width - TVP5150_MAX_CROP_LEFT) >>
+ TVP5150_CROP_SHIFT);
+ regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_LSB,
+ rect.left + rect.width - TVP5150_MAX_CROP_LEFT);
decoder->rect = rect;
@@ -951,7 +1082,6 @@ static int tvp5150_get_selection(struct v4l2_subdev *sd,
switch (sel->target) {
case V4L2_SEL_TGT_CROP_BOUNDS:
- case V4L2_SEL_TGT_CROP_DEFAULT:
sel->r.left = 0;
sel->r.top = 0;
sel->r.width = TVP5150_H_MAX;
@@ -989,6 +1119,27 @@ static int tvp5150_g_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 tvp5150 *decoder = to_tvp5150(sd);
+ v4l2_std_id std;
+
+ /*
+ * Reset selection to maximum on subdev_open() if autodetection is on
+ * and a standard change is detected.
+ */
+ if (decoder->norm == V4L2_STD_ALL) {
+ std = tvp5150_read_std(sd);
+ if (std != decoder->detected_norm) {
+ decoder->detected_norm = std;
+ tvp5150_set_default(std, &decoder->rect);
+ }
+ }
+
+ return 0;
+}
+
static int tvp5150_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
@@ -996,7 +1147,7 @@ static int tvp5150_enum_mbus_code(struct v4l2_subdev *sd,
if (code->pad || code->index)
return -EINVAL;
- code->code = MEDIA_BUS_FMT_UYVY8_2X8;
+ code->code = TVP5150_MBUS_FMT;
return 0;
}
@@ -1006,10 +1157,10 @@ static int tvp5150_enum_frame_size(struct v4l2_subdev *sd,
{
struct tvp5150 *decoder = to_tvp5150(sd);
- if (fse->index >= 8 || fse->code != MEDIA_BUS_FMT_UYVY8_2X8)
+ if (fse->index >= 8 || fse->code != TVP5150_MBUS_FMT)
return -EINVAL;
- fse->code = MEDIA_BUS_FMT_UYVY8_2X8;
+ fse->code = TVP5150_MBUS_FMT;
fse->min_width = decoder->rect.width;
fse->max_width = decoder->rect.width;
fse->min_height = decoder->rect.height / 2;
@@ -1059,27 +1210,28 @@ static const struct media_entity_operations tvp5150_sd_media_ops = {
static int tvp5150_s_stream(struct v4l2_subdev *sd, int enable)
{
struct tvp5150 *decoder = to_tvp5150(sd);
- int val;
+ unsigned int mask, val = 0, int_val = 0;
- /* Enable or disable the video output signals. */
- val = tvp5150_read(sd, TVP5150_MISC_CTL);
- if (val < 0)
- return val;
-
- val &= ~(TVP5150_MISC_CTL_YCBCR_OE | TVP5150_MISC_CTL_SYNC_OE |
- TVP5150_MISC_CTL_CLOCK_OE);
+ mask = TVP5150_MISC_CTL_YCBCR_OE | TVP5150_MISC_CTL_SYNC_OE |
+ TVP5150_MISC_CTL_CLOCK_OE;
if (enable) {
- /*
- * Enable the YCbCr and clock outputs. In discrete sync mode
- * (non-BT.656) additionally enable the the sync outputs.
- */
- val |= TVP5150_MISC_CTL_YCBCR_OE | TVP5150_MISC_CTL_CLOCK_OE;
- if (decoder->mbus_type == V4L2_MBUS_PARALLEL)
- val |= TVP5150_MISC_CTL_SYNC_OE;
+ tvp5150_enable(sd);
+
+ /* Enable outputs if decoder is locked */
+ if (decoder->irq)
+ val = decoder->lock ? decoder->oe : 0;
+ else
+ val = decoder->oe;
+ int_val = TVP5150_INT_A_LOCK;
+ v4l2_subdev_notify_event(&decoder->sd, &tvp5150_ev_fmt);
}
- tvp5150_write(sd, TVP5150_MISC_CTL, val);
+ regmap_update_bits(decoder->regmap, TVP5150_MISC_CTL, mask, val);
+ if (decoder->irq)
+ /* Enable / Disable lock interrupt */
+ regmap_update_bits(decoder->regmap, TVP5150_INT_ENABLE_REG_A,
+ TVP5150_INT_A_LOCK, int_val);
return 0;
}
@@ -1103,6 +1255,8 @@ static int tvp5150_s_routing(struct v4l2_subdev *sd,
static int tvp5150_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt)
{
+ struct tvp5150 *decoder = to_tvp5150(sd);
+
/*
* this is for capturing 36 raw vbi lines
* if there's a way to cut off the beginning 2 vbi lines
@@ -1112,16 +1266,18 @@ static int tvp5150_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt
*/
if (fmt->sample_format == V4L2_PIX_FMT_GREY)
- tvp5150_write(sd, TVP5150_LUMA_PROC_CTL_1, 0x70);
+ regmap_write(decoder->regmap, TVP5150_LUMA_PROC_CTL_1, 0x70);
if (fmt->count[0] == 18 && fmt->count[1] == 18) {
- tvp5150_write(sd, TVP5150_VERT_BLANKING_START, 0x00);
- tvp5150_write(sd, TVP5150_VERT_BLANKING_STOP, 0x01);
+ regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_START,
+ 0x00);
+ regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_STOP, 0x01);
}
return 0;
}
static int tvp5150_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi)
{
+ struct tvp5150 *decoder = to_tvp5150(sd);
int i;
if (svbi->service_set != 0) {
@@ -1132,17 +1288,17 @@ static int tvp5150_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_f
0xf0, i, 3);
}
/* Enables FIFO */
- tvp5150_write(sd, TVP5150_FIFO_OUT_CTRL, 1);
+ regmap_write(decoder->regmap, TVP5150_FIFO_OUT_CTRL, 1);
} else {
/* Disables FIFO*/
- tvp5150_write(sd, TVP5150_FIFO_OUT_CTRL, 0);
+ regmap_write(decoder->regmap, TVP5150_FIFO_OUT_CTRL, 0);
/* Disable Full Field */
- tvp5150_write(sd, TVP5150_FULL_FIELD_ENA, 0);
+ regmap_write(decoder->regmap, TVP5150_FULL_FIELD_ENA, 0);
/* Disable Line modes */
for (i = TVP5150_LINE_MODE_INI; i <= TVP5150_LINE_MODE_END; i++)
- tvp5150_write(sd, i, 0xff);
+ regmap_write(decoder->regmap, i, 0xff);
}
return 0;
}
@@ -1180,7 +1336,9 @@ static int tvp5150_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *
static int tvp5150_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
{
- return tvp5150_write(sd, reg->reg & 0xff, reg->val & 0xff);
+ struct tvp5150 *decoder = to_tvp5150(sd);
+
+ return regmap_write(decoder->regmap, reg->reg & 0xff, reg->val & 0xff);
}
#endif
@@ -1217,7 +1375,7 @@ static int tvp5150_registered(struct v4l2_subdev *sd)
return ret;
ret = media_create_pad_link(input, 0, &sd->entity,
- DEMOD_PAD_IF_INPUT, 0);
+ TVP5150_PAD_IF_INPUT, 0);
if (ret < 0) {
media_device_unregister_entity(input);
return ret;
@@ -1249,6 +1407,8 @@ static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = {
static const struct v4l2_subdev_video_ops tvp5150_video_ops = {
.s_std = tvp5150_s_std,
+ .g_std = tvp5150_g_std,
+ .querystd = tvp5150_querystd,
.s_stream = tvp5150_s_stream,
.s_routing = tvp5150_s_routing,
.g_mbus_config = tvp5150_g_mbus_config,
@@ -1262,6 +1422,7 @@ static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = {
};
static const struct v4l2_subdev_pad_ops tvp5150_pad_ops = {
+ .init_cfg = tvp5150_init_cfg,
.enum_mbus_code = tvp5150_enum_mbus_code,
.enum_frame_size = tvp5150_enum_frame_size,
.set_fmt = tvp5150_fill_fmt,
@@ -1282,16 +1443,87 @@ static const struct v4l2_subdev_internal_ops tvp5150_internal_ops = {
.registered = tvp5150_registered,
};
-
/****************************************************************************
I2C Client & Driver
****************************************************************************/
+static const struct regmap_range tvp5150_readable_ranges[] = {
+ {
+ .range_min = TVP5150_VD_IN_SRC_SEL_1,
+ .range_max = TVP5150_AUTOSW_MSK,
+ }, {
+ .range_min = TVP5150_COLOR_KIL_THSH_CTL,
+ .range_max = TVP5150_CONF_SHARED_PIN,
+ }, {
+ .range_min = TVP5150_ACT_VD_CROP_ST_MSB,
+ .range_max = TVP5150_HORIZ_SYNC_START,
+ }, {
+ .range_min = TVP5150_VERT_BLANKING_START,
+ .range_max = TVP5150_INTT_CONFIG_REG_B,
+ }, {
+ .range_min = TVP5150_VIDEO_STD,
+ .range_max = TVP5150_VIDEO_STD,
+ }, {
+ .range_min = TVP5150_CB_GAIN_FACT,
+ .range_max = TVP5150_REV_SELECT,
+ }, {
+ .range_min = TVP5150_MSB_DEV_ID,
+ .range_max = TVP5150_STATUS_REG_5,
+ }, {
+ .range_min = TVP5150_CC_DATA_INI,
+ .range_max = TVP5150_TELETEXT_FIL_ENA,
+ }, {
+ .range_min = TVP5150_INT_STATUS_REG_A,
+ .range_max = TVP5150_FIFO_OUT_CTRL,
+ }, {
+ .range_min = TVP5150_FULL_FIELD_ENA,
+ .range_max = TVP5150_FULL_FIELD_MODE_REG,
+ },
+};
+
+static bool tvp5150_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case TVP5150_VERT_LN_COUNT_MSB:
+ case TVP5150_VERT_LN_COUNT_LSB:
+ case TVP5150_INT_STATUS_REG_A:
+ case TVP5150_INT_STATUS_REG_B:
+ case TVP5150_INT_ACTIVE_REG_B:
+ case TVP5150_STATUS_REG_1:
+ case TVP5150_STATUS_REG_2:
+ case TVP5150_STATUS_REG_3:
+ case TVP5150_STATUS_REG_4:
+ case TVP5150_STATUS_REG_5:
+ /* CC, WSS, VPS, VITC data? */
+ case TVP5150_VBI_FIFO_READ_DATA:
+ case TVP5150_VDP_STATUS_REG:
+ case TVP5150_FIFO_WORD_COUNT:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_access_table tvp5150_readable_table = {
+ .yes_ranges = tvp5150_readable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(tvp5150_readable_ranges),
+};
+
+static struct regmap_config tvp5150_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0xff,
+
+ .cache_type = REGCACHE_RBTREE,
+
+ .rd_table = &tvp5150_readable_table,
+ .volatile_reg = tvp5150_volatile_reg,
+};
+
static int tvp5150_detect_version(struct tvp5150 *core)
{
struct v4l2_subdev *sd = &core->sd;
struct i2c_client *c = v4l2_get_subdevdata(sd);
- unsigned int i;
u8 regs[4];
int res;
@@ -1299,11 +1531,10 @@ static int tvp5150_detect_version(struct tvp5150 *core)
* Read consequent registers - TVP5150_MSB_DEV_ID, TVP5150_LSB_DEV_ID,
* TVP5150_ROM_MAJOR_VER, TVP5150_ROM_MINOR_VER
*/
- for (i = 0; i < 4; i++) {
- res = tvp5150_read(sd, TVP5150_MSB_DEV_ID + i);
- if (res < 0)
- return res;
- regs[i] = res;
+ res = regmap_bulk_read(core->regmap, TVP5150_MSB_DEV_ID, regs, 4);
+ if (res < 0) {
+ dev_err(&c->dev, "reading ID registers failed: %d\n", res);
+ return res;
}
core->dev_id = (regs[0] << 8) | regs[1];
@@ -1319,7 +1550,7 @@ static int tvp5150_detect_version(struct tvp5150 *core)
dev_info(sd->dev, "tvp5150am1 detected.\n");
/* ITU-T BT.656.4 timing */
- tvp5150_write(sd, TVP5150_REV_SELECT, 0);
+ regmap_write(core->regmap, TVP5150_REV_SELECT, 0);
} else if (core->dev_id == 0x5151 && core->rom_ver == 0x0100) {
dev_info(sd->dev, "tvp5151 detected.\n");
} else {
@@ -1362,7 +1593,7 @@ static int tvp5150_init(struct i2c_client *c)
static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np)
{
- struct v4l2_fwnode_endpoint bus_cfg;
+ struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 };
struct device_node *ep;
#ifdef CONFIG_MEDIA_CONTROLLER
struct device_node *connectors, *child;
@@ -1403,8 +1634,8 @@ static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np)
ret = of_property_read_u32(child, "input", &input_type);
if (ret) {
dev_err(decoder->sd.dev,
- "missing type property in node %s\n",
- child->name);
+ "missing type property in node %pOFn\n",
+ child);
goto err_connector;
}
@@ -1439,8 +1670,8 @@ static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np)
ret = of_property_read_string(child, "label", &name);
if (ret < 0) {
dev_err(decoder->sd.dev,
- "missing label property in node %s\n",
- child->name);
+ "missing label property in node %pOFn\n",
+ child);
goto err_connector;
}
@@ -1466,6 +1697,7 @@ static int tvp5150_probe(struct i2c_client *c,
struct tvp5150 *core;
struct v4l2_subdev *sd;
struct device_node *np = c->dev.of_node;
+ struct regmap *map;
int res;
/* Check if the adapter supports the needed features */
@@ -1481,6 +1713,11 @@ static int tvp5150_probe(struct i2c_client *c,
if (!core)
return -ENOMEM;
+ map = devm_regmap_init_i2c(c, &tvp5150_config);
+ if (IS_ERR(map))
+ return PTR_ERR(map);
+
+ core->regmap = map;
sd = &core->sd;
if (IS_ENABLED(CONFIG_OF) && np) {
@@ -1499,13 +1736,14 @@ static int tvp5150_probe(struct i2c_client *c,
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
#if defined(CONFIG_MEDIA_CONTROLLER)
- core->pads[DEMOD_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK;
- core->pads[DEMOD_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE;
- core->pads[DEMOD_PAD_VBI_OUT].flags = MEDIA_PAD_FL_SOURCE;
+ core->pads[TVP5150_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK;
+ core->pads[TVP5150_PAD_IF_INPUT].sig_type = PAD_SIGNAL_ANALOG;
+ core->pads[TVP5150_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE;
+ core->pads[TVP5150_PAD_VID_OUT].sig_type = PAD_SIGNAL_DV;
sd->entity.function = MEDIA_ENT_F_ATV_DECODER;
- res = media_entity_pads_init(&sd->entity, DEMOD_NUM_PADS, core->pads);
+ res = media_entity_pads_init(&sd->entity, TVP5150_NUM_PADS, core->pads);
if (res < 0)
return res;
@@ -1517,6 +1755,7 @@ static int tvp5150_probe(struct i2c_client *c,
return res;
core->norm = V4L2_STD_ALL; /* Default is autodetect */
+ core->detected_norm = V4L2_STD_UNKNOWN;
core->input = TVP5150_COMPOSITE1;
core->enable = true;
@@ -1534,7 +1773,7 @@ static int tvp5150_probe(struct i2c_client *c,
27000000, 1, 27000000);
v4l2_ctrl_new_std_menu_items(&core->hdl, &tvp5150_ctrl_ops,
V4L2_CID_TEST_PATTERN,
- ARRAY_SIZE(tvp5150_test_patterns),
+ ARRAY_SIZE(tvp5150_test_patterns) - 1,
0, 0, tvp5150_test_patterns);
sd->ctrl_handler = &core->hdl;
if (core->hdl.error) {
@@ -1542,16 +1781,17 @@ static int tvp5150_probe(struct i2c_client *c,
goto err;
}
- /* Default is no cropping */
- core->rect.top = 0;
- if (tvp5150_read_std(sd) & V4L2_STD_525_60)
- core->rect.height = TVP5150_V_MAX_525_60;
- else
- core->rect.height = TVP5150_V_MAX_OTHERS;
- core->rect.left = 0;
- core->rect.width = TVP5150_H_MAX;
+ tvp5150_set_default(tvp5150_read_std(sd), &core->rect);
+ core->irq = c->irq;
tvp5150_reset(sd, 0); /* Calls v4l2_ctrl_handler_setup() */
+ if (c->irq) {
+ res = devm_request_threaded_irq(&c->dev, c->irq, NULL,
+ tvp5150_isr, IRQF_TRIGGER_HIGH |
+ IRQF_ONESHOT, "tvp5150", core);
+ if (res)
+ return res;
+ }
res = v4l2_async_register_subdev(sd);
if (res < 0)
diff --git a/drivers/media/i2c/tvp5150_reg.h b/drivers/media/i2c/tvp5150_reg.h
index d3a764cae1a0..9088186c24d1 100644
--- a/drivers/media/i2c/tvp5150_reg.h
+++ b/drivers/media/i2c/tvp5150_reg.h
@@ -125,8 +125,11 @@
#define TVP5150_TELETEXT_FIL_ENA 0xbb /* Teletext filter enable */
/* Reserved BCh-BFh */
#define TVP5150_INT_STATUS_REG_A 0xc0 /* Interrupt status register A */
+#define TVP5150_INT_A_LOCK_STATUS BIT(7)
+#define TVP5150_INT_A_LOCK BIT(6)
#define TVP5150_INT_ENABLE_REG_A 0xc1 /* Interrupt enable register A */
#define TVP5150_INT_CONF 0xc2 /* Interrupt configuration */
+#define TVP5150_VDPOE BIT(2)
#define TVP5150_VDP_CONF_RAM_DATA 0xc3 /* VDP configuration RAM data */
#define TVP5150_CONF_RAM_ADDR_LOW 0xc4 /* Configuration RAM address low byte */
#define TVP5150_CONF_RAM_ADDR_HIGH 0xc5 /* Configuration RAM address high byte */
diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c
index 4f5c627579c7..cab2f2bd0aa9 100644
--- a/drivers/media/i2c/tvp7002.c
+++ b/drivers/media/i2c/tvp7002.c
@@ -889,7 +889,7 @@ static const struct v4l2_subdev_ops tvp7002_ops = {
static struct tvp7002_config *
tvp7002_get_pdata(struct i2c_client *client)
{
- struct v4l2_fwnode_endpoint bus_cfg;
+ struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 };
struct tvp7002_config *pdata = NULL;
struct device_node *endpoint;
unsigned int flags;
diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c
index 06d29d8f6be8..4d49af86c15e 100644
--- a/drivers/media/i2c/video-i2c.c
+++ b/drivers/media/i2c/video-i2c.c
@@ -352,8 +352,8 @@ static int video_i2c_querycap(struct file *file, void *priv,
struct video_i2c_data *data = video_drvdata(file);
struct i2c_client *client = data->client;
- strlcpy(vcap->driver, data->v4l2_dev.name, sizeof(vcap->driver));
- strlcpy(vcap->card, data->vdev.name, sizeof(vcap->card));
+ strscpy(vcap->driver, data->v4l2_dev.name, sizeof(vcap->driver));
+ strscpy(vcap->card, data->vdev.name, sizeof(vcap->card));
sprintf(vcap->bus_info, "I2C:%d-%d", client->adapter->nr, client->addr);
@@ -378,7 +378,7 @@ static int video_i2c_enum_input(struct file *file, void *fh,
if (vin->index > 0)
return -EINVAL;
- strlcpy(vin->name, "Camera", sizeof(vin->name));
+ strscpy(vin->name, "Camera", sizeof(vin->name));
vin->type = V4L2_INPUT_TYPE_CAMERA;
@@ -534,7 +534,7 @@ static int video_i2c_probe(struct i2c_client *client,
data->client = client;
v4l2_dev = &data->v4l2_dev;
- strlcpy(v4l2_dev->name, VIDEO_I2C_DRIVER, sizeof(v4l2_dev->name));
+ strscpy(v4l2_dev->name, VIDEO_I2C_DRIVER, sizeof(v4l2_dev->name));
ret = v4l2_device_register(&client->dev, v4l2_dev);
if (ret < 0)
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index 3bae24b15eaa..bed24372e61f 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -30,6 +30,7 @@
#include <media/media-device.h>
#include <media/media-devnode.h>
#include <media/media-entity.h>
+#include <media/media-request.h>
#ifdef CONFIG_MEDIA_CONTROLLER
@@ -69,14 +70,14 @@ static long media_device_get_info(struct media_device *dev, void *arg)
memset(info, 0, sizeof(*info));
if (dev->driver_name[0])
- strlcpy(info->driver, dev->driver_name, sizeof(info->driver));
+ strscpy(info->driver, dev->driver_name, sizeof(info->driver));
else
- strlcpy(info->driver, dev->dev->driver->name,
+ strscpy(info->driver, dev->dev->driver->name,
sizeof(info->driver));
- strlcpy(info->model, dev->model, sizeof(info->model));
- strlcpy(info->serial, dev->serial, sizeof(info->serial));
- strlcpy(info->bus_info, dev->bus_info, sizeof(info->bus_info));
+ strscpy(info->model, dev->model, sizeof(info->model));
+ strscpy(info->serial, dev->serial, sizeof(info->serial));
+ strscpy(info->bus_info, dev->bus_info, sizeof(info->bus_info));
info->media_version = LINUX_VERSION_CODE;
info->driver_version = info->media_version;
@@ -115,7 +116,7 @@ static long media_device_enum_entities(struct media_device *mdev, void *arg)
entd->id = media_entity_id(ent);
if (ent->name)
- strlcpy(entd->name, ent->name, sizeof(entd->name));
+ strscpy(entd->name, ent->name, sizeof(entd->name));
entd->type = ent->function;
entd->revision = 0; /* Unused */
entd->flags = ent->flags;
@@ -268,7 +269,7 @@ static long media_device_get_topology(struct media_device *mdev, void *arg)
kentity.id = entity->graph_obj.id;
kentity.function = entity->function;
kentity.flags = entity->flags;
- strlcpy(kentity.name, entity->name,
+ strscpy(kentity.name, entity->name,
sizeof(kentity.name));
if (copy_to_user(uentity, &kentity, sizeof(kentity)))
@@ -377,10 +378,19 @@ static long media_device_get_topology(struct media_device *mdev, void *arg)
return ret;
}
+static long media_device_request_alloc(struct media_device *mdev,
+ int *alloc_fd)
+{
+ if (!mdev->ops || !mdev->ops->req_validate || !mdev->ops->req_queue)
+ return -ENOTTY;
+
+ return media_request_alloc(mdev, alloc_fd);
+}
+
static long copy_arg_from_user(void *karg, void __user *uarg, unsigned int cmd)
{
- /* All media IOCTLs are _IOWR() */
- if (copy_from_user(karg, uarg, _IOC_SIZE(cmd)))
+ if ((_IOC_DIR(cmd) & _IOC_WRITE) &&
+ copy_from_user(karg, uarg, _IOC_SIZE(cmd)))
return -EFAULT;
return 0;
@@ -388,8 +398,8 @@ static long copy_arg_from_user(void *karg, void __user *uarg, unsigned int cmd)
static long copy_arg_to_user(void __user *uarg, void *karg, unsigned int cmd)
{
- /* All media IOCTLs are _IOWR() */
- if (copy_to_user(uarg, karg, _IOC_SIZE(cmd)))
+ if ((_IOC_DIR(cmd) & _IOC_READ) &&
+ copy_to_user(uarg, karg, _IOC_SIZE(cmd)))
return -EFAULT;
return 0;
@@ -425,6 +435,7 @@ static const struct media_ioctl_info ioctl_info[] = {
MEDIA_IOC(ENUM_LINKS, media_device_enum_links, MEDIA_IOC_FL_GRAPH_MUTEX),
MEDIA_IOC(SETUP_LINK, media_device_setup_link, MEDIA_IOC_FL_GRAPH_MUTEX),
MEDIA_IOC(G_TOPOLOGY, media_device_get_topology, MEDIA_IOC_FL_GRAPH_MUTEX),
+ MEDIA_IOC(REQUEST_ALLOC, media_device_request_alloc, 0),
};
static long media_device_ioctl(struct file *filp, unsigned int cmd,
@@ -691,9 +702,13 @@ void media_device_init(struct media_device *mdev)
INIT_LIST_HEAD(&mdev->pads);
INIT_LIST_HEAD(&mdev->links);
INIT_LIST_HEAD(&mdev->entity_notify);
+
+ mutex_init(&mdev->req_queue_mutex);
mutex_init(&mdev->graph_mutex);
ida_init(&mdev->entity_internal_idx);
+ atomic_set(&mdev->request_id, 0);
+
dev_dbg(mdev->dev, "Media device initialized\n");
}
EXPORT_SYMBOL_GPL(media_device_init);
@@ -704,6 +719,7 @@ void media_device_cleanup(struct media_device *mdev)
mdev->entity_internal_idx_max = 0;
media_graph_walk_cleanup(&mdev->pm_count_walk);
mutex_destroy(&mdev->graph_mutex);
+ mutex_destroy(&mdev->req_queue_mutex);
}
EXPORT_SYMBOL_GPL(media_device_cleanup);
@@ -836,9 +852,9 @@ void media_device_pci_init(struct media_device *mdev,
mdev->dev = &pci_dev->dev;
if (name)
- strlcpy(mdev->model, name, sizeof(mdev->model));
+ strscpy(mdev->model, name, sizeof(mdev->model));
else
- strlcpy(mdev->model, pci_name(pci_dev), sizeof(mdev->model));
+ strscpy(mdev->model, pci_name(pci_dev), sizeof(mdev->model));
sprintf(mdev->bus_info, "PCI:%s", pci_name(pci_dev));
@@ -859,17 +875,17 @@ void __media_device_usb_init(struct media_device *mdev,
mdev->dev = &udev->dev;
if (driver_name)
- strlcpy(mdev->driver_name, driver_name,
+ strscpy(mdev->driver_name, driver_name,
sizeof(mdev->driver_name));
if (board_name)
- strlcpy(mdev->model, board_name, sizeof(mdev->model));
+ strscpy(mdev->model, board_name, sizeof(mdev->model));
else if (udev->product)
- strlcpy(mdev->model, udev->product, sizeof(mdev->model));
+ strscpy(mdev->model, udev->product, sizeof(mdev->model));
else
- strlcpy(mdev->model, "unknown model", sizeof(mdev->model));
+ strscpy(mdev->model, "unknown model", sizeof(mdev->model));
if (udev->serial)
- strlcpy(mdev->serial, udev->serial, sizeof(mdev->serial));
+ strscpy(mdev->serial, udev->serial, sizeof(mdev->serial));
usb_make_path(udev, mdev->bus_info, sizeof(mdev->bus_info));
mdev->hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index 3498551e618e..0b1cb3559140 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -662,6 +662,32 @@ static void __media_entity_remove_link(struct media_entity *entity,
kfree(link);
}
+int media_get_pad_index(struct media_entity *entity, bool is_sink,
+ enum media_pad_signal_type sig_type)
+{
+ int i;
+ bool pad_is_sink;
+
+ if (!entity)
+ return -EINVAL;
+
+ for (i = 0; i < entity->num_pads; i++) {
+ if (entity->pads[i].flags == MEDIA_PAD_FL_SINK)
+ pad_is_sink = true;
+ else if (entity->pads[i].flags == MEDIA_PAD_FL_SOURCE)
+ pad_is_sink = false;
+ else
+ continue; /* This is an error! */
+
+ if (pad_is_sink != is_sink)
+ continue;
+ if (entity->pads[i].sig_type == sig_type)
+ return i;
+ }
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(media_get_pad_index);
+
int
media_create_pad_link(struct media_entity *source, u16 source_pad,
struct media_entity *sink, u16 sink_pad, u32 flags)
diff --git a/drivers/media/media-request.c b/drivers/media/media-request.c
new file mode 100644
index 000000000000..4e9db1fed697
--- /dev/null
+++ b/drivers/media/media-request.c
@@ -0,0 +1,501 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Media device request objects
+ *
+ * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ * Copyright (C) 2018 Intel Corporation
+ * Copyright (C) 2018 Google, Inc.
+ *
+ * Author: Hans Verkuil <hans.verkuil@cisco.com>
+ * Author: Sakari Ailus <sakari.ailus@linux.intel.com>
+ */
+
+#include <linux/anon_inodes.h>
+#include <linux/file.h>
+#include <linux/refcount.h>
+
+#include <media/media-device.h>
+#include <media/media-request.h>
+
+static const char * const request_state[] = {
+ [MEDIA_REQUEST_STATE_IDLE] = "idle",
+ [MEDIA_REQUEST_STATE_VALIDATING] = "validating",
+ [MEDIA_REQUEST_STATE_QUEUED] = "queued",
+ [MEDIA_REQUEST_STATE_COMPLETE] = "complete",
+ [MEDIA_REQUEST_STATE_CLEANING] = "cleaning",
+ [MEDIA_REQUEST_STATE_UPDATING] = "updating",
+};
+
+static const char *
+media_request_state_str(enum media_request_state state)
+{
+ BUILD_BUG_ON(ARRAY_SIZE(request_state) != NR_OF_MEDIA_REQUEST_STATE);
+
+ if (WARN_ON(state >= ARRAY_SIZE(request_state)))
+ return "invalid";
+ return request_state[state];
+}
+
+static void media_request_clean(struct media_request *req)
+{
+ struct media_request_object *obj, *obj_safe;
+
+ /* Just a sanity check. No other code path is allowed to change this. */
+ WARN_ON(req->state != MEDIA_REQUEST_STATE_CLEANING);
+ WARN_ON(req->updating_count);
+ WARN_ON(req->access_count);
+
+ list_for_each_entry_safe(obj, obj_safe, &req->objects, list) {
+ media_request_object_unbind(obj);
+ media_request_object_put(obj);
+ }
+
+ req->updating_count = 0;
+ req->access_count = 0;
+ WARN_ON(req->num_incomplete_objects);
+ req->num_incomplete_objects = 0;
+ wake_up_interruptible_all(&req->poll_wait);
+}
+
+static void media_request_release(struct kref *kref)
+{
+ struct media_request *req =
+ container_of(kref, struct media_request, kref);
+ struct media_device *mdev = req->mdev;
+
+ dev_dbg(mdev->dev, "request: release %s\n", req->debug_str);
+
+ /* No other users, no need for a spinlock */
+ req->state = MEDIA_REQUEST_STATE_CLEANING;
+
+ media_request_clean(req);
+
+ if (mdev->ops->req_free)
+ mdev->ops->req_free(req);
+ else
+ kfree(req);
+}
+
+void media_request_put(struct media_request *req)
+{
+ kref_put(&req->kref, media_request_release);
+}
+EXPORT_SYMBOL_GPL(media_request_put);
+
+static int media_request_close(struct inode *inode, struct file *filp)
+{
+ struct media_request *req = filp->private_data;
+
+ media_request_put(req);
+ return 0;
+}
+
+static __poll_t media_request_poll(struct file *filp,
+ struct poll_table_struct *wait)
+{
+ struct media_request *req = filp->private_data;
+ unsigned long flags;
+ __poll_t ret = 0;
+
+ if (!(poll_requested_events(wait) & EPOLLPRI))
+ return 0;
+
+ spin_lock_irqsave(&req->lock, flags);
+ if (req->state == MEDIA_REQUEST_STATE_COMPLETE) {
+ ret = EPOLLPRI;
+ goto unlock;
+ }
+ if (req->state != MEDIA_REQUEST_STATE_QUEUED) {
+ ret = EPOLLERR;
+ goto unlock;
+ }
+
+ poll_wait(filp, &req->poll_wait, wait);
+
+unlock:
+ spin_unlock_irqrestore(&req->lock, flags);
+ return ret;
+}
+
+static long media_request_ioctl_queue(struct media_request *req)
+{
+ struct media_device *mdev = req->mdev;
+ enum media_request_state state;
+ unsigned long flags;
+ int ret;
+
+ dev_dbg(mdev->dev, "request: queue %s\n", req->debug_str);
+
+ /*
+ * Ensure the request that is validated will be the one that gets queued
+ * next by serialising the queueing process. This mutex is also used
+ * to serialize with canceling a vb2 queue and with setting values such
+ * as controls in a request.
+ */
+ mutex_lock(&mdev->req_queue_mutex);
+
+ media_request_get(req);
+
+ spin_lock_irqsave(&req->lock, flags);
+ if (req->state == MEDIA_REQUEST_STATE_IDLE)
+ req->state = MEDIA_REQUEST_STATE_VALIDATING;
+ state = req->state;
+ spin_unlock_irqrestore(&req->lock, flags);
+ if (state != MEDIA_REQUEST_STATE_VALIDATING) {
+ dev_dbg(mdev->dev,
+ "request: unable to queue %s, request in state %s\n",
+ req->debug_str, media_request_state_str(state));
+ media_request_put(req);
+ mutex_unlock(&mdev->req_queue_mutex);
+ return -EBUSY;
+ }
+
+ ret = mdev->ops->req_validate(req);
+
+ /*
+ * If the req_validate was successful, then we mark the state as QUEUED
+ * and call req_queue. The reason we set the state first is that this
+ * allows req_queue to unbind or complete the queued objects in case
+ * they are immediately 'consumed'. State changes from QUEUED to another
+ * state can only happen if either the driver changes the state or if
+ * the user cancels the vb2 queue. The driver can only change the state
+ * after each object is queued through the req_queue op (and note that
+ * that op cannot fail), so setting the state to QUEUED up front is
+ * safe.
+ *
+ * The other reason for changing the state is if the vb2 queue is
+ * canceled, and that uses the req_queue_mutex which is still locked
+ * while req_queue is called, so that's safe as well.
+ */
+ spin_lock_irqsave(&req->lock, flags);
+ req->state = ret ? MEDIA_REQUEST_STATE_IDLE
+ : MEDIA_REQUEST_STATE_QUEUED;
+ spin_unlock_irqrestore(&req->lock, flags);
+
+ if (!ret)
+ mdev->ops->req_queue(req);
+
+ mutex_unlock(&mdev->req_queue_mutex);
+
+ if (ret) {
+ dev_dbg(mdev->dev, "request: can't queue %s (%d)\n",
+ req->debug_str, ret);
+ media_request_put(req);
+ }
+
+ return ret;
+}
+
+static long media_request_ioctl_reinit(struct media_request *req)
+{
+ struct media_device *mdev = req->mdev;
+ unsigned long flags;
+
+ spin_lock_irqsave(&req->lock, flags);
+ if (req->state != MEDIA_REQUEST_STATE_IDLE &&
+ req->state != MEDIA_REQUEST_STATE_COMPLETE) {
+ dev_dbg(mdev->dev,
+ "request: %s not in idle or complete state, cannot reinit\n",
+ req->debug_str);
+ spin_unlock_irqrestore(&req->lock, flags);
+ return -EBUSY;
+ }
+ if (req->access_count) {
+ dev_dbg(mdev->dev,
+ "request: %s is being accessed, cannot reinit\n",
+ req->debug_str);
+ spin_unlock_irqrestore(&req->lock, flags);
+ return -EBUSY;
+ }
+ req->state = MEDIA_REQUEST_STATE_CLEANING;
+ spin_unlock_irqrestore(&req->lock, flags);
+
+ media_request_clean(req);
+
+ spin_lock_irqsave(&req->lock, flags);
+ req->state = MEDIA_REQUEST_STATE_IDLE;
+ spin_unlock_irqrestore(&req->lock, flags);
+
+ return 0;
+}
+
+static long media_request_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct media_request *req = filp->private_data;
+
+ switch (cmd) {
+ case MEDIA_REQUEST_IOC_QUEUE:
+ return media_request_ioctl_queue(req);
+ case MEDIA_REQUEST_IOC_REINIT:
+ return media_request_ioctl_reinit(req);
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+static const struct file_operations request_fops = {
+ .owner = THIS_MODULE,
+ .poll = media_request_poll,
+ .unlocked_ioctl = media_request_ioctl,
+ .release = media_request_close,
+};
+
+struct media_request *
+media_request_get_by_fd(struct media_device *mdev, int request_fd)
+{
+ struct file *filp;
+ struct media_request *req;
+
+ if (!mdev || !mdev->ops ||
+ !mdev->ops->req_validate || !mdev->ops->req_queue)
+ return ERR_PTR(-EACCES);
+
+ filp = fget(request_fd);
+ if (!filp)
+ goto err_no_req_fd;
+
+ if (filp->f_op != &request_fops)
+ goto err_fput;
+ req = filp->private_data;
+ if (req->mdev != mdev)
+ goto err_fput;
+
+ /*
+ * Note: as long as someone has an open filehandle of the request,
+ * the request can never be released. The fget() above ensures that
+ * even if userspace closes the request filehandle, the release()
+ * fop won't be called, so the media_request_get() always succeeds
+ * and there is no race condition where the request was released
+ * before media_request_get() is called.
+ */
+ media_request_get(req);
+ fput(filp);
+
+ return req;
+
+err_fput:
+ fput(filp);
+
+err_no_req_fd:
+ dev_dbg(mdev->dev, "cannot find request_fd %d\n", request_fd);
+ return ERR_PTR(-EINVAL);
+}
+EXPORT_SYMBOL_GPL(media_request_get_by_fd);
+
+int media_request_alloc(struct media_device *mdev, int *alloc_fd)
+{
+ struct media_request *req;
+ struct file *filp;
+ int fd;
+ int ret;
+
+ /* Either both are NULL or both are non-NULL */
+ if (WARN_ON(!mdev->ops->req_alloc ^ !mdev->ops->req_free))
+ return -ENOMEM;
+
+ fd = get_unused_fd_flags(O_CLOEXEC);
+ if (fd < 0)
+ return fd;
+
+ filp = anon_inode_getfile("request", &request_fops, NULL, O_CLOEXEC);
+ if (IS_ERR(filp)) {
+ ret = PTR_ERR(filp);
+ goto err_put_fd;
+ }
+
+ if (mdev->ops->req_alloc)
+ req = mdev->ops->req_alloc(mdev);
+ else
+ req = kzalloc(sizeof(*req), GFP_KERNEL);
+ if (!req) {
+ ret = -ENOMEM;
+ goto err_fput;
+ }
+
+ filp->private_data = req;
+ req->mdev = mdev;
+ req->state = MEDIA_REQUEST_STATE_IDLE;
+ req->num_incomplete_objects = 0;
+ kref_init(&req->kref);
+ INIT_LIST_HEAD(&req->objects);
+ spin_lock_init(&req->lock);
+ init_waitqueue_head(&req->poll_wait);
+ req->updating_count = 0;
+ req->access_count = 0;
+
+ *alloc_fd = fd;
+
+ snprintf(req->debug_str, sizeof(req->debug_str), "%u:%d",
+ atomic_inc_return(&mdev->request_id), fd);
+ dev_dbg(mdev->dev, "request: allocated %s\n", req->debug_str);
+
+ fd_install(fd, filp);
+
+ return 0;
+
+err_fput:
+ fput(filp);
+
+err_put_fd:
+ put_unused_fd(fd);
+
+ return ret;
+}
+
+static void media_request_object_release(struct kref *kref)
+{
+ struct media_request_object *obj =
+ container_of(kref, struct media_request_object, kref);
+ struct media_request *req = obj->req;
+
+ if (WARN_ON(req))
+ media_request_object_unbind(obj);
+ obj->ops->release(obj);
+}
+
+struct media_request_object *
+media_request_object_find(struct media_request *req,
+ const struct media_request_object_ops *ops,
+ void *priv)
+{
+ struct media_request_object *obj;
+ struct media_request_object *found = NULL;
+ unsigned long flags;
+
+ if (WARN_ON(!ops || !priv))
+ return NULL;
+
+ spin_lock_irqsave(&req->lock, flags);
+ list_for_each_entry(obj, &req->objects, list) {
+ if (obj->ops == ops && obj->priv == priv) {
+ media_request_object_get(obj);
+ found = obj;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&req->lock, flags);
+ return found;
+}
+EXPORT_SYMBOL_GPL(media_request_object_find);
+
+void media_request_object_put(struct media_request_object *obj)
+{
+ kref_put(&obj->kref, media_request_object_release);
+}
+EXPORT_SYMBOL_GPL(media_request_object_put);
+
+void media_request_object_init(struct media_request_object *obj)
+{
+ obj->ops = NULL;
+ obj->req = NULL;
+ obj->priv = NULL;
+ obj->completed = false;
+ INIT_LIST_HEAD(&obj->list);
+ kref_init(&obj->kref);
+}
+EXPORT_SYMBOL_GPL(media_request_object_init);
+
+int media_request_object_bind(struct media_request *req,
+ const struct media_request_object_ops *ops,
+ void *priv, bool is_buffer,
+ struct media_request_object *obj)
+{
+ unsigned long flags;
+ int ret = -EBUSY;
+
+ if (WARN_ON(!ops->release))
+ return -EACCES;
+
+ spin_lock_irqsave(&req->lock, flags);
+
+ if (WARN_ON(req->state != MEDIA_REQUEST_STATE_UPDATING))
+ goto unlock;
+
+ obj->req = req;
+ obj->ops = ops;
+ obj->priv = priv;
+
+ if (is_buffer)
+ list_add_tail(&obj->list, &req->objects);
+ else
+ list_add(&obj->list, &req->objects);
+ req->num_incomplete_objects++;
+ ret = 0;
+
+unlock:
+ spin_unlock_irqrestore(&req->lock, flags);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(media_request_object_bind);
+
+void media_request_object_unbind(struct media_request_object *obj)
+{
+ struct media_request *req = obj->req;
+ unsigned long flags;
+ bool completed = false;
+
+ if (WARN_ON(!req))
+ return;
+
+ spin_lock_irqsave(&req->lock, flags);
+ list_del(&obj->list);
+ obj->req = NULL;
+
+ if (req->state == MEDIA_REQUEST_STATE_COMPLETE)
+ goto unlock;
+
+ if (WARN_ON(req->state == MEDIA_REQUEST_STATE_VALIDATING))
+ goto unlock;
+
+ if (req->state == MEDIA_REQUEST_STATE_CLEANING) {
+ if (!obj->completed)
+ req->num_incomplete_objects--;
+ goto unlock;
+ }
+
+ if (WARN_ON(!req->num_incomplete_objects))
+ goto unlock;
+
+ req->num_incomplete_objects--;
+ if (req->state == MEDIA_REQUEST_STATE_QUEUED &&
+ !req->num_incomplete_objects) {
+ req->state = MEDIA_REQUEST_STATE_COMPLETE;
+ completed = true;
+ wake_up_interruptible_all(&req->poll_wait);
+ }
+
+unlock:
+ spin_unlock_irqrestore(&req->lock, flags);
+ if (obj->ops->unbind)
+ obj->ops->unbind(obj);
+ if (completed)
+ media_request_put(req);
+}
+EXPORT_SYMBOL_GPL(media_request_object_unbind);
+
+void media_request_object_complete(struct media_request_object *obj)
+{
+ struct media_request *req = obj->req;
+ unsigned long flags;
+ bool completed = false;
+
+ spin_lock_irqsave(&req->lock, flags);
+ if (obj->completed)
+ goto unlock;
+ obj->completed = true;
+ if (WARN_ON(!req->num_incomplete_objects) ||
+ WARN_ON(req->state != MEDIA_REQUEST_STATE_QUEUED))
+ goto unlock;
+
+ if (!--req->num_incomplete_objects) {
+ req->state = MEDIA_REQUEST_STATE_COMPLETE;
+ wake_up_interruptible_all(&req->poll_wait);
+ completed = true;
+ }
+unlock:
+ spin_unlock_irqrestore(&req->lock, flags);
+ if (completed)
+ media_request_put(req);
+}
+EXPORT_SYMBOL_GPL(media_request_object_complete);
diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c
index cf05e11da01b..d4906c04dc6e 100644
--- a/drivers/media/pci/bt8xx/bttv-driver.c
+++ b/drivers/media/pci/bt8xx/bttv-driver.c
@@ -2040,7 +2040,6 @@ limit_scaled_size_lock (struct bttv_fh * fh,
max_width = max_width & width_mask;
/* Max. scale factor is 16:1 for frames, 8:1 for fields. */
- min_height = min_height;
/* Min. scale factor is 1:1. */
max_height >>= !V4L2_FIELD_HAS_BOTH(field);
@@ -2473,8 +2472,8 @@ static int bttv_querycap(struct file *file, void *priv,
if (0 == v4l2)
return -EINVAL;
- strlcpy(cap->driver, "bttv", sizeof(cap->driver));
- strlcpy(cap->card, btv->video_dev.name, sizeof(cap->card));
+ strscpy(cap->driver, "bttv", sizeof(cap->driver));
+ strscpy(cap->card, btv->video_dev.name, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info),
"PCI:%s", pci_name(btv->c.pci));
cap->capabilities =
@@ -2535,7 +2534,7 @@ static int bttv_enum_fmt_cap_ovr(struct v4l2_fmtdesc *f)
return -EINVAL;
f->pixelformat = formats[i].fourcc;
- strlcpy(f->description, formats[i].name, sizeof(f->description));
+ strscpy(f->description, formats[i].name, sizeof(f->description));
return i;
}
@@ -2782,7 +2781,7 @@ static int bttv_g_tuner(struct file *file, void *priv,
t->rxsubchans = V4L2_TUNER_SUB_MONO;
t->capability = V4L2_TUNER_CAP_NORM;
bttv_call_all(btv, tuner, g_tuner, t);
- strcpy(t->name, "Television");
+ strscpy(t->name, "Television", sizeof(t->name));
t->type = V4L2_TUNER_ANALOG_TV;
if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)
t->signal = 0xffff;
@@ -3257,7 +3256,7 @@ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
if (0 != t->index)
return -EINVAL;
- strcpy(t->name, "Radio");
+ strscpy(t->name, "Radio", sizeof(t->name));
t->type = V4L2_TUNER_RADIO;
radio_enable(btv);
@@ -4211,7 +4210,7 @@ static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id)
/* register video4linux + input */
if (!bttv_tvcards[btv->c.type].no_video) {
v4l2_ctrl_add_handler(&btv->radio_ctrl_handler, hdl,
- v4l2_ctrl_radio_filter);
+ v4l2_ctrl_radio_filter, false);
if (btv->radio_ctrl_handler.error) {
result = btv->radio_ctrl_handler.error;
goto fail2;
diff --git a/drivers/media/pci/bt8xx/bttv-i2c.c b/drivers/media/pci/bt8xx/bttv-i2c.c
index c76823eb399d..15ff7f9d8373 100644
--- a/drivers/media/pci/bt8xx/bttv-i2c.c
+++ b/drivers/media/pci/bt8xx/bttv-i2c.c
@@ -347,13 +347,13 @@ static void do_i2c_scan(char *name, struct i2c_client *c)
/* init + register i2c adapter */
int init_bttv_i2c(struct bttv *btv)
{
- strlcpy(btv->i2c_client.name, "bttv internal", I2C_NAME_SIZE);
+ strscpy(btv->i2c_client.name, "bttv internal", I2C_NAME_SIZE);
if (i2c_hw)
btv->use_i2c_hw = 1;
if (btv->use_i2c_hw) {
/* bt878 */
- strlcpy(btv->c.i2c_adap.name, "bt878",
+ strscpy(btv->c.i2c_adap.name, "bt878",
sizeof(btv->c.i2c_adap.name));
btv->c.i2c_adap.algo = &bttv_algo;
} else {
@@ -362,7 +362,7 @@ int init_bttv_i2c(struct bttv *btv)
if (i2c_udelay<5)
i2c_udelay=5;
- strlcpy(btv->c.i2c_adap.name, "bttv",
+ strscpy(btv->c.i2c_adap.name, "bttv",
sizeof(btv->c.i2c_adap.name));
btv->i2c_algo = bttv_i2c_algo_bit_template;
btv->i2c_algo.udelay = i2c_udelay;
diff --git a/drivers/media/pci/bt8xx/bttv-input.c b/drivers/media/pci/bt8xx/bttv-input.c
index 08266b23826e..d34fbaa027c2 100644
--- a/drivers/media/pci/bt8xx/bttv-input.c
+++ b/drivers/media/pci/bt8xx/bttv-input.c
@@ -370,7 +370,7 @@ static int get_key_pv951(struct IR_i2c *ir, enum rc_proto *protocol,
/* Instantiate the I2C IR receiver device, if present */
void init_bttv_i2c_ir(struct bttv *btv)
{
- const unsigned short addr_list[] = {
+ static const unsigned short addr_list[] = {
0x1a, 0x18, 0x64, 0x30, 0x71,
I2C_CLIENT_END
};
@@ -382,7 +382,7 @@ void init_bttv_i2c_ir(struct bttv *btv)
memset(&info, 0, sizeof(struct i2c_board_info));
memset(&btv->init_data, 0, sizeof(btv->init_data));
- strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+ strscpy(info.type, "ir_video", I2C_NAME_SIZE);
switch (btv->c.type) {
case BTTV_BOARD_PV951:
diff --git a/drivers/media/pci/bt8xx/dvb-bt8xx.c b/drivers/media/pci/bt8xx/dvb-bt8xx.c
index 2f810b7130e6..b46fbe557dd9 100644
--- a/drivers/media/pci/bt8xx/dvb-bt8xx.c
+++ b/drivers/media/pci/bt8xx/dvb-bt8xx.c
@@ -819,7 +819,8 @@ static int dvb_bt8xx_probe(struct bttv_sub_device *sub)
mutex_init(&card->lock);
card->bttv_nr = sub->core->nr;
- strlcpy(card->card_name, sub->core->v4l2_dev.name, sizeof(card->card_name));
+ strscpy(card->card_name, sub->core->v4l2_dev.name,
+ sizeof(card->card_name));
card->i2c_adapter = &sub->core->i2c_adap;
switch(sub->core->type) {
diff --git a/drivers/media/pci/cobalt/cobalt-alsa-main.c b/drivers/media/pci/cobalt/cobalt-alsa-main.c
index e5022b620856..c57f87a68269 100644
--- a/drivers/media/pci/cobalt/cobalt-alsa-main.c
+++ b/drivers/media/pci/cobalt/cobalt-alsa-main.c
@@ -65,7 +65,7 @@ static int snd_cobalt_card_set_names(struct snd_cobalt_card *cobsc)
struct snd_card *sc = cobsc->sc;
/* sc->driver is used by alsa-lib's configurator: simple, unique */
- strlcpy(sc->driver, "cobalt", sizeof(sc->driver));
+ strscpy(sc->driver, "cobalt", sizeof(sc->driver));
/* sc->shortname is a symlink in /proc/asound: COBALT-M -> cardN */
snprintf(sc->shortname, sizeof(sc->shortname), "cobalt-%d-%d",
diff --git a/drivers/media/pci/cobalt/cobalt-alsa-pcm.c b/drivers/media/pci/cobalt/cobalt-alsa-pcm.c
index f6a7df13cd04..38d00935a292 100644
--- a/drivers/media/pci/cobalt/cobalt-alsa-pcm.c
+++ b/drivers/media/pci/cobalt/cobalt-alsa-pcm.c
@@ -557,7 +557,7 @@ int snd_cobalt_pcm_create(struct snd_cobalt_card *cobsc)
&snd_cobalt_pcm_capture_ops);
sp->info_flags = 0;
sp->private_data = cobsc;
- strlcpy(sp->name, "cobalt", sizeof(sp->name));
+ strscpy(sp->name, "cobalt", sizeof(sp->name));
} else {
cobalt_s_bit_sysctrl(cobalt,
COBALT_SYS_CTRL_AUDIO_OPP_RESETN_BIT, 0);
@@ -581,7 +581,7 @@ int snd_cobalt_pcm_create(struct snd_cobalt_card *cobsc)
&snd_cobalt_pcm_playback_ops);
sp->info_flags = 0;
sp->private_data = cobsc;
- strlcpy(sp->name, "cobalt", sizeof(sp->name));
+ strscpy(sp->name, "cobalt", sizeof(sp->name));
}
return 0;
diff --git a/drivers/media/pci/cobalt/cobalt-v4l2.c b/drivers/media/pci/cobalt/cobalt-v4l2.c
index e2a4c705d353..0525f5e1565b 100644
--- a/drivers/media/pci/cobalt/cobalt-v4l2.c
+++ b/drivers/media/pci/cobalt/cobalt-v4l2.c
@@ -479,8 +479,8 @@ static int cobalt_querycap(struct file *file, void *priv_fh,
struct cobalt_stream *s = video_drvdata(file);
struct cobalt *cobalt = s->cobalt;
- strlcpy(vcap->driver, "cobalt", sizeof(vcap->driver));
- strlcpy(vcap->card, "cobalt", sizeof(vcap->card));
+ strscpy(vcap->driver, "cobalt", sizeof(vcap->driver));
+ strscpy(vcap->card, "cobalt", sizeof(vcap->card));
snprintf(vcap->bus_info, sizeof(vcap->bus_info),
"PCIe:%s", pci_name(cobalt->pci_dev));
vcap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
@@ -693,15 +693,15 @@ static int cobalt_enum_fmt_vid_cap(struct file *file, void *priv_fh,
{
switch (f->index) {
case 0:
- strlcpy(f->description, "YUV 4:2:2", sizeof(f->description));
+ strscpy(f->description, "YUV 4:2:2", sizeof(f->description));
f->pixelformat = V4L2_PIX_FMT_YUYV;
break;
case 1:
- strlcpy(f->description, "RGB24", sizeof(f->description));
+ strscpy(f->description, "RGB24", sizeof(f->description));
f->pixelformat = V4L2_PIX_FMT_RGB24;
break;
case 2:
- strlcpy(f->description, "RGB32", sizeof(f->description));
+ strscpy(f->description, "RGB32", sizeof(f->description));
f->pixelformat = V4L2_PIX_FMT_BGR32;
break;
default:
@@ -898,11 +898,11 @@ static int cobalt_enum_fmt_vid_out(struct file *file, void *priv_fh,
{
switch (f->index) {
case 0:
- strlcpy(f->description, "YUV 4:2:2", sizeof(f->description));
+ strscpy(f->description, "YUV 4:2:2", sizeof(f->description));
f->pixelformat = V4L2_PIX_FMT_YUYV;
break;
case 1:
- strlcpy(f->description, "RGB32", sizeof(f->description));
+ strscpy(f->description, "RGB32", sizeof(f->description));
f->pixelformat = V4L2_PIX_FMT_BGR32;
break;
default:
@@ -1064,10 +1064,15 @@ static int cobalt_subscribe_event(struct v4l2_fh *fh,
static int cobalt_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
{
+ struct cobalt_stream *s = video_drvdata(file);
+ struct v4l2_fract fps;
+
if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- a->parm.capture.timeperframe.numerator = 1;
- a->parm.capture.timeperframe.denominator = 60;
+
+ fps = v4l2_calc_timeperframe(&s->timings);
+ a->parm.capture.timeperframe.numerator = fps.numerator;
+ a->parm.capture.timeperframe.denominator = fps.denominator;
a->parm.capture.readbuffers = 3;
return 0;
}
diff --git a/drivers/media/pci/cx18/cx18-alsa-main.c b/drivers/media/pci/cx18/cx18-alsa-main.c
index 93443d1457c5..687477748fdd 100644
--- a/drivers/media/pci/cx18/cx18-alsa-main.c
+++ b/drivers/media/pci/cx18/cx18-alsa-main.c
@@ -112,7 +112,7 @@ static int snd_cx18_card_set_names(struct snd_cx18_card *cxsc)
struct snd_card *sc = cxsc->sc;
/* sc->driver is used by alsa-lib's configurator: simple, unique */
- strlcpy(sc->driver, "CX23418", sizeof(sc->driver));
+ strscpy(sc->driver, "CX23418", sizeof(sc->driver));
/* sc->shortname is a symlink in /proc/asound: CX18-M -> cardN */
snprintf(sc->shortname, sizeof(sc->shortname), "CX18-%d",
diff --git a/drivers/media/pci/cx18/cx18-alsa-pcm.c b/drivers/media/pci/cx18/cx18-alsa-pcm.c
index 4f31042a442a..3eafc27956c2 100644
--- a/drivers/media/pci/cx18/cx18-alsa-pcm.c
+++ b/drivers/media/pci/cx18/cx18-alsa-pcm.c
@@ -345,7 +345,7 @@ int snd_cx18_pcm_create(struct snd_cx18_card *cxsc)
&snd_cx18_pcm_capture_ops);
sp->info_flags = 0;
sp->private_data = cxsc;
- strlcpy(sp->name, cx->card_name, sizeof(sp->name));
+ strscpy(sp->name, cx->card_name, sizeof(sp->name));
return 0;
diff --git a/drivers/media/pci/cx18/cx18-cards.c b/drivers/media/pci/cx18/cx18-cards.c
index c2cf965d639e..2dcbccfbd60d 100644
--- a/drivers/media/pci/cx18/cx18-cards.c
+++ b/drivers/media/pci/cx18/cx18-cards.c
@@ -602,8 +602,8 @@ int cx18_get_input(struct cx18 *cx, u16 index, struct v4l2_input *input)
if (index >= cx->nof_inputs)
return -EINVAL;
input->index = index;
- strlcpy(input->name, input_strs[card_input->video_type - 1],
- sizeof(input->name));
+ strscpy(input->name, input_strs[card_input->video_type - 1],
+ sizeof(input->name));
input->type = (card_input->video_type == CX18_CARD_INPUT_VID_TUNER ?
V4L2_INPUT_TYPE_TUNER : V4L2_INPUT_TYPE_CAMERA);
input->audioset = (1 << cx->nof_audio_inputs) - 1;
@@ -625,8 +625,8 @@ int cx18_get_audio_input(struct cx18 *cx, u16 index, struct v4l2_audio *audio)
memset(audio, 0, sizeof(*audio));
if (index >= cx->nof_audio_inputs)
return -EINVAL;
- strlcpy(audio->name, input_strs[aud_input->audio_type - 1],
- sizeof(audio->name));
+ strscpy(audio->name, input_strs[aud_input->audio_type - 1],
+ sizeof(audio->name));
audio->index = index;
audio->capability = V4L2_AUDCAP_STEREO;
return 0;
diff --git a/drivers/media/pci/cx18/cx18-driver.c b/drivers/media/pci/cx18/cx18-driver.c
index 0c389a3fb4e5..a6ba4ca5aa91 100644
--- a/drivers/media/pci/cx18/cx18-driver.c
+++ b/drivers/media/pci/cx18/cx18-driver.c
@@ -328,7 +328,7 @@ void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv)
if (!c)
return;
- strlcpy(c->name, "cx18 tveeprom tmp", sizeof(c->name));
+ strscpy(c->name, "cx18 tveeprom tmp", sizeof(c->name));
c->adapter = &cx->i2c_adap[0];
c->addr = 0xa0 >> 1;
@@ -1252,7 +1252,7 @@ static void cx18_cancel_out_work_orders(struct cx18 *cx)
{
int i;
for (i = 0; i < CX18_MAX_STREAMS; i++)
- if (&cx->streams[i].video_dev)
+ if (cx->streams[i].video_dev.v4l2_dev)
cancel_work_sync(&cx->streams[i].out_work_order);
}
diff --git a/drivers/media/pci/cx18/cx18-i2c.c b/drivers/media/pci/cx18/cx18-i2c.c
index f0eb181f2b94..a89c666953f5 100644
--- a/drivers/media/pci/cx18/cx18-i2c.c
+++ b/drivers/media/pci/cx18/cx18-i2c.c
@@ -83,7 +83,7 @@ static int cx18_i2c_new_ir(struct cx18 *cx, struct i2c_adapter *adap, u32 hw,
unsigned short addr_list[2] = { addr, I2C_CLIENT_END };
memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, type, I2C_NAME_SIZE);
+ strscpy(info.type, type, I2C_NAME_SIZE);
/* Our default information for ir-kbd-i2c.c to use */
switch (hw) {
diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c
index 80b902b12a78..854116375a7c 100644
--- a/drivers/media/pci/cx18/cx18-ioctl.c
+++ b/drivers/media/pci/cx18/cx18-ioctl.c
@@ -397,8 +397,8 @@ static int cx18_querycap(struct file *file, void *fh,
struct cx18_stream *s = video_drvdata(file);
struct cx18 *cx = id->cx;
- strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver));
- strlcpy(vcap->card, cx->card_name, sizeof(vcap->card));
+ strscpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver));
+ strscpy(vcap->card, cx->card_name, sizeof(vcap->card));
snprintf(vcap->bus_info, sizeof(vcap->bus_info),
"PCI:%s", pci_name(cx->pci_dev));
vcap->capabilities = cx->v4l2_cap; /* capabilities */
@@ -632,9 +632,9 @@ static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
cx18_call_all(cx, tuner, g_tuner, vt);
if (vt->type == V4L2_TUNER_RADIO)
- strlcpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name));
+ strscpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name));
else
- strlcpy(vt->name, "cx18 TV Tuner", sizeof(vt->name));
+ strscpy(vt->name, "cx18 TV Tuner", sizeof(vt->name));
return 0;
}
diff --git a/drivers/media/pci/cx23885/altera-ci.c b/drivers/media/pci/cx23885/altera-ci.c
index 62bc8049b320..198c05e83f5c 100644
--- a/drivers/media/pci/cx23885/altera-ci.c
+++ b/drivers/media/pci/cx23885/altera-ci.c
@@ -665,6 +665,10 @@ static int altera_hw_filt_init(struct altera_ci_config *config, int hw_filt_nr)
}
temp_int = append_internal(inter);
+ if (!temp_int) {
+ ret = -ENOMEM;
+ goto err;
+ }
inter->filts_used = 1;
inter->dev = config->dev;
inter->fpga_rw = config->fpga_rw;
@@ -699,6 +703,7 @@ err:
__func__, ret);
kfree(pid_filt);
+ kfree(inter);
return ret;
}
@@ -733,6 +738,10 @@ int altera_ci_init(struct altera_ci_config *config, int ci_nr)
}
temp_int = append_internal(inter);
+ if (!temp_int) {
+ ret = -ENOMEM;
+ goto err;
+ }
inter->cis_used = 1;
inter->dev = config->dev;
inter->fpga_rw = config->fpga_rw;
@@ -801,6 +810,7 @@ err:
ci_dbg_print("%s: Cannot initialize CI: Error %d.\n", __func__, ret);
kfree(state);
+ kfree(inter);
return ret;
}
diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c
index a71f3c7569ce..a00b77d80ed9 100644
--- a/drivers/media/pci/cx23885/cx23885-417.c
+++ b/drivers/media/pci/cx23885/cx23885-417.c
@@ -1280,7 +1280,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
return -EINVAL;
if (0 != t->index)
return -EINVAL;
- strcpy(t->name, "Television");
+ strscpy(t->name, "Television", sizeof(t->name));
call_all(dev, tuner, g_tuner, t);
dprintk(1, "VIDIOC_G_TUNER: tuner type %d\n", t->type);
@@ -1329,8 +1329,8 @@ static int vidioc_querycap(struct file *file, void *priv,
struct cx23885_dev *dev = video_drvdata(file);
struct cx23885_tsport *tsport = &dev->ts1;
- strlcpy(cap->driver, dev->name, sizeof(cap->driver));
- strlcpy(cap->card, cx23885_boards[tsport->dev->board].name,
+ strscpy(cap->driver, dev->name, sizeof(cap->driver));
+ strscpy(cap->card, cx23885_boards[tsport->dev->board].name,
sizeof(cap->card));
sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci));
cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
@@ -1349,7 +1349,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
if (f->index != 0)
return -EINVAL;
- strlcpy(f->description, "MPEG", sizeof(f->description));
+ strscpy(f->description, "MPEG", sizeof(f->description));
f->pixelformat = V4L2_PIX_FMT_MPEG;
return 0;
@@ -1527,7 +1527,7 @@ int cx23885_417_register(struct cx23885_dev *dev)
dev->cxhdl.priv = dev;
dev->cxhdl.func = cx23885_api_func;
cx2341x_handler_set_50hz(&dev->cxhdl, tsport->height == 576);
- v4l2_ctrl_add_handler(&dev->ctrl_handler, &dev->cxhdl.hdl, NULL);
+ v4l2_ctrl_add_handler(&dev->ctrl_handler, &dev->cxhdl.hdl, NULL, false);
/* Allocate and initialize V4L video device */
dev->v4l_device = cx23885_video_dev_alloc(tsport,
diff --git a/drivers/media/pci/cx23885/cx23885-alsa.c b/drivers/media/pci/cx23885/cx23885-alsa.c
index db1e8ff35474..ee9d329c4038 100644
--- a/drivers/media/pci/cx23885/cx23885-alsa.c
+++ b/drivers/media/pci/cx23885/cx23885-alsa.c
@@ -526,7 +526,7 @@ static int snd_cx23885_pcm(struct cx23885_audio_dev *chip, int device,
if (err < 0)
return err;
pcm->private_data = chip;
- strcpy(pcm->name, name);
+ strscpy(pcm->name, name, sizeof(pcm->name));
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cx23885_pcm_ops);
return 0;
@@ -571,7 +571,7 @@ struct cx23885_audio_dev *cx23885_audio_register(struct cx23885_dev *dev)
if (err < 0)
goto error;
- strcpy(card->driver, "CX23885");
+ strscpy(card->driver, "CX23885", sizeof(card->driver));
sprintf(card->shortname, "Conexant CX23885");
sprintf(card->longname, "%s at %s", card->shortname, dev->name);
diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c
index 7d52173073d6..0d0929c54f93 100644
--- a/drivers/media/pci/cx23885/cx23885-dvb.c
+++ b/drivers/media/pci/cx23885/cx23885-dvb.c
@@ -1165,7 +1165,7 @@ static int dvb_register_ci_mac(struct cx23885_tsport *port)
sp2_config.priv = port;
sp2_config.ci_control = cx23885_sp2_ci_ctrl;
memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "sp2", I2C_NAME_SIZE);
+ strscpy(info.type, "sp2", I2C_NAME_SIZE);
info.addr = 0x40;
info.platform_data = &sp2_config;
request_module(info.type);
@@ -1831,7 +1831,7 @@ static int dvb_register(struct cx23885_tsport *port)
case 1:
/* attach demod + tuner combo */
memset(&info, 0, sizeof(info));
- strlcpy(info.type, "tda10071_cx24118", I2C_NAME_SIZE);
+ strscpy(info.type, "tda10071_cx24118", I2C_NAME_SIZE);
info.addr = 0x05;
info.platform_data = &tda10071_pdata;
request_module("tda10071");
@@ -1848,7 +1848,7 @@ static int dvb_register(struct cx23885_tsport *port)
/* attach SEC */
a8293_pdata.dvb_frontend = fe0->dvb.frontend;
memset(&info, 0, sizeof(info));
- strlcpy(info.type, "a8293", I2C_NAME_SIZE);
+ strscpy(info.type, "a8293", I2C_NAME_SIZE);
info.addr = 0x0b;
info.platform_data = &a8293_pdata;
request_module("a8293");
@@ -1869,7 +1869,7 @@ static int dvb_register(struct cx23885_tsport *port)
si2165_pdata.chip_mode = SI2165_MODE_PLL_XTAL;
si2165_pdata.ref_freq_hz = 16000000;
memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "si2165", I2C_NAME_SIZE);
+ strscpy(info.type, "si2165", I2C_NAME_SIZE);
info.addr = 0x64;
info.platform_data = &si2165_pdata;
request_module(info.type);
@@ -1903,7 +1903,7 @@ static int dvb_register(struct cx23885_tsport *port)
/* attach demod + tuner combo */
memset(&info, 0, sizeof(info));
- strlcpy(info.type, "tda10071_cx24118", I2C_NAME_SIZE);
+ strscpy(info.type, "tda10071_cx24118", I2C_NAME_SIZE);
info.addr = 0x05;
info.platform_data = &tda10071_pdata;
request_module("tda10071");
@@ -1920,7 +1920,7 @@ static int dvb_register(struct cx23885_tsport *port)
/* attach SEC */
a8293_pdata.dvb_frontend = fe0->dvb.frontend;
memset(&info, 0, sizeof(info));
- strlcpy(info.type, "a8293", I2C_NAME_SIZE);
+ strscpy(info.type, "a8293", I2C_NAME_SIZE);
info.addr = 0x0b;
info.platform_data = &a8293_pdata;
request_module("a8293");
@@ -1953,7 +1953,7 @@ static int dvb_register(struct cx23885_tsport *port)
ts2020_config.fe = fe0->dvb.frontend;
ts2020_config.get_agc_pwm = m88ds3103_get_agc_pwm;
memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "ts2020", I2C_NAME_SIZE);
+ strscpy(info.type, "ts2020", I2C_NAME_SIZE);
info.addr = 0x60;
info.platform_data = &ts2020_config;
request_module(info.type);
@@ -1990,7 +1990,7 @@ static int dvb_register(struct cx23885_tsport *port)
si2168_config.fe = &fe0->dvb.frontend;
si2168_config.ts_mode = SI2168_TS_SERIAL;
memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "si2168", I2C_NAME_SIZE);
+ strscpy(info.type, "si2168", I2C_NAME_SIZE);
info.addr = 0x64;
info.platform_data = &si2168_config;
request_module(info.type);
@@ -2009,7 +2009,7 @@ static int dvb_register(struct cx23885_tsport *port)
si2157_config.fe = fe0->dvb.frontend;
si2157_config.if_port = 1;
memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "si2157", I2C_NAME_SIZE);
+ strscpy(info.type, "si2157", I2C_NAME_SIZE);
info.addr = 0x60;
info.platform_data = &si2157_config;
request_module(info.type);
@@ -2037,7 +2037,7 @@ static int dvb_register(struct cx23885_tsport *port)
si2168_config.fe = &fe0->dvb.frontend;
si2168_config.ts_mode = SI2168_TS_PARALLEL;
memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "si2168", I2C_NAME_SIZE);
+ strscpy(info.type, "si2168", I2C_NAME_SIZE);
info.addr = 0x64;
info.platform_data = &si2168_config;
request_module(info.type);
@@ -2055,7 +2055,7 @@ static int dvb_register(struct cx23885_tsport *port)
si2157_config.fe = fe0->dvb.frontend;
si2157_config.if_port = 1;
memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "si2157", I2C_NAME_SIZE);
+ strscpy(info.type, "si2157", I2C_NAME_SIZE);
info.addr = 0x60;
info.platform_data = &si2157_config;
request_module(info.type);
@@ -2085,7 +2085,7 @@ static int dvb_register(struct cx23885_tsport *port)
ts2020_config.fe = fe0->dvb.frontend;
ts2020_config.get_agc_pwm = m88ds3103_get_agc_pwm;
memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "ts2020", I2C_NAME_SIZE);
+ strscpy(info.type, "ts2020", I2C_NAME_SIZE);
info.addr = 0x60;
info.platform_data = &ts2020_config;
request_module(info.type);
@@ -2134,7 +2134,7 @@ static int dvb_register(struct cx23885_tsport *port)
}
memset(&info, 0, sizeof(info));
- strlcpy(info.type, "m88ds3103", I2C_NAME_SIZE);
+ strscpy(info.type, "m88ds3103", I2C_NAME_SIZE);
info.addr = 0x68;
info.platform_data = &m88ds3103_pdata;
request_module(info.type);
@@ -2154,7 +2154,7 @@ static int dvb_register(struct cx23885_tsport *port)
ts2020_config.fe = fe0->dvb.frontend;
ts2020_config.get_agc_pwm = m88ds3103_get_agc_pwm;
memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "ts2020", I2C_NAME_SIZE);
+ strscpy(info.type, "ts2020", I2C_NAME_SIZE);
info.addr = 0x60;
info.platform_data = &ts2020_config;
request_module(info.type);
@@ -2199,7 +2199,7 @@ static int dvb_register(struct cx23885_tsport *port)
si2168_config.i2c_adapter = &adapter;
si2168_config.fe = &fe0->dvb.frontend;
memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "si2168", I2C_NAME_SIZE);
+ strscpy(info.type, "si2168", I2C_NAME_SIZE);
info.addr = 0x64;
info.platform_data = &si2168_config;
request_module(info.type);
@@ -2217,7 +2217,7 @@ static int dvb_register(struct cx23885_tsport *port)
si2157_config.fe = fe0->dvb.frontend;
si2157_config.if_port = 1;
memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "si2157", I2C_NAME_SIZE);
+ strscpy(info.type, "si2157", I2C_NAME_SIZE);
info.addr = 0x60;
info.platform_data = &si2157_config;
request_module(info.type);
@@ -2250,7 +2250,7 @@ static int dvb_register(struct cx23885_tsport *port)
/* attach SEC */
a8293_pdata.dvb_frontend = fe0->dvb.frontend;
memset(&info, 0, sizeof(info));
- strlcpy(info.type, "a8293", I2C_NAME_SIZE);
+ strscpy(info.type, "a8293", I2C_NAME_SIZE);
info.addr = 0x0b;
info.platform_data = &a8293_pdata;
request_module("a8293");
@@ -2267,7 +2267,7 @@ static int dvb_register(struct cx23885_tsport *port)
memset(&m88rs6000t_config, 0, sizeof(m88rs6000t_config));
m88rs6000t_config.fe = fe0->dvb.frontend;
memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "m88rs6000t", I2C_NAME_SIZE);
+ strscpy(info.type, "m88rs6000t", I2C_NAME_SIZE);
info.addr = 0x21;
info.platform_data = &m88rs6000t_config;
request_module("%s", info.type);
@@ -2292,7 +2292,7 @@ static int dvb_register(struct cx23885_tsport *port)
si2168_config.fe = &fe0->dvb.frontend;
si2168_config.ts_mode = SI2168_TS_SERIAL;
memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "si2168", I2C_NAME_SIZE);
+ strscpy(info.type, "si2168", I2C_NAME_SIZE);
info.addr = 0x64;
info.platform_data = &si2168_config;
request_module("%s", info.type);
@@ -2310,7 +2310,7 @@ static int dvb_register(struct cx23885_tsport *port)
si2157_config.fe = fe0->dvb.frontend;
si2157_config.if_port = 1;
memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "si2157", I2C_NAME_SIZE);
+ strscpy(info.type, "si2157", I2C_NAME_SIZE);
info.addr = 0x60;
info.platform_data = &si2157_config;
request_module("%s", info.type);
@@ -2345,7 +2345,7 @@ static int dvb_register(struct cx23885_tsport *port)
si2168_config.fe = &fe0->dvb.frontend;
si2168_config.ts_mode = SI2168_TS_SERIAL;
memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "si2168", I2C_NAME_SIZE);
+ strscpy(info.type, "si2168", I2C_NAME_SIZE);
info.addr = 0x64;
info.platform_data = &si2168_config;
request_module("%s", info.type);
@@ -2363,7 +2363,7 @@ static int dvb_register(struct cx23885_tsport *port)
si2157_config.fe = fe0->dvb.frontend;
si2157_config.if_port = 1;
memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "si2157", I2C_NAME_SIZE);
+ strscpy(info.type, "si2157", I2C_NAME_SIZE);
info.addr = 0x60;
info.platform_data = &si2157_config;
request_module("%s", info.type);
@@ -2392,7 +2392,7 @@ static int dvb_register(struct cx23885_tsport *port)
si2168_config.fe = &fe0->dvb.frontend;
si2168_config.ts_mode = SI2168_TS_SERIAL;
memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "si2168", I2C_NAME_SIZE);
+ strscpy(info.type, "si2168", I2C_NAME_SIZE);
info.addr = 0x66;
info.platform_data = &si2168_config;
request_module("%s", info.type);
@@ -2410,7 +2410,7 @@ static int dvb_register(struct cx23885_tsport *port)
si2157_config.fe = fe0->dvb.frontend;
si2157_config.if_port = 1;
memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "si2157", I2C_NAME_SIZE);
+ strscpy(info.type, "si2157", I2C_NAME_SIZE);
info.addr = 0x62;
info.platform_data = &si2157_config;
request_module("%s", info.type);
@@ -2452,7 +2452,7 @@ static int dvb_register(struct cx23885_tsport *port)
si2157_config.if_port = 1;
si2157_config.inversion = 1;
memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "si2157", I2C_NAME_SIZE);
+ strscpy(info.type, "si2157", I2C_NAME_SIZE);
info.addr = 0x60;
info.platform_data = &si2157_config;
request_module("%s", info.type);
@@ -2488,7 +2488,7 @@ static int dvb_register(struct cx23885_tsport *port)
si2157_config.if_port = 1;
si2157_config.inversion = 1;
memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "si2157", I2C_NAME_SIZE);
+ strscpy(info.type, "si2157", I2C_NAME_SIZE);
info.addr = 0x62;
info.platform_data = &si2157_config;
request_module("%s", info.type);
@@ -2528,7 +2528,7 @@ static int dvb_register(struct cx23885_tsport *port)
si2157_config.if_port = 1;
si2157_config.inversion = 1;
memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "si2157", I2C_NAME_SIZE);
+ strscpy(info.type, "si2157", I2C_NAME_SIZE);
info.addr = 0x60;
info.platform_data = &si2157_config;
request_module("%s", info.type);
diff --git a/drivers/media/pci/cx23885/cx23885-i2c.c b/drivers/media/pci/cx23885/cx23885-i2c.c
index ef863492c0ac..d0df3dfff694 100644
--- a/drivers/media/pci/cx23885/cx23885-i2c.c
+++ b/drivers/media/pci/cx23885/cx23885-i2c.c
@@ -317,7 +317,7 @@ int cx23885_i2c_register(struct cx23885_i2c *bus)
bus->i2c_client = cx23885_i2c_client_template;
bus->i2c_adap.dev.parent = &dev->pci->dev;
- strlcpy(bus->i2c_adap.name, bus->dev->name,
+ strscpy(bus->i2c_adap.name, bus->dev->name,
sizeof(bus->i2c_adap.name));
bus->i2c_adap.algo_data = bus;
@@ -340,12 +340,12 @@ int cx23885_i2c_register(struct cx23885_i2c *bus)
/* Instantiate the IR receiver device, if present */
if (0 == bus->i2c_rc) {
struct i2c_board_info info;
- const unsigned short addr_list[] = {
+ static const unsigned short addr_list[] = {
0x6b, I2C_CLIENT_END
};
memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+ strscpy(info.type, "ir_video", I2C_NAME_SIZE);
/* Use quick read command for probe, some IR chips don't
* support writes */
i2c_new_probed_device(&bus->i2c_adap, &info, addr_list,
diff --git a/drivers/media/pci/cx23885/cx23885-ioctl.c b/drivers/media/pci/cx23885/cx23885-ioctl.c
index d2cdd40f79f5..d162bf4b4800 100644
--- a/drivers/media/pci/cx23885/cx23885-ioctl.c
+++ b/drivers/media/pci/cx23885/cx23885-ioctl.c
@@ -31,9 +31,9 @@ int cx23885_g_chip_info(struct file *file, void *fh,
if (chip->match.addr == 1) {
if (dev->v4l_device == NULL)
return -EINVAL;
- strlcpy(chip->name, "cx23417", sizeof(chip->name));
+ strscpy(chip->name, "cx23417", sizeof(chip->name));
} else {
- strlcpy(chip->name, dev->v4l2_dev.name, sizeof(chip->name));
+ strscpy(chip->name, dev->v4l2_dev.name, sizeof(chip->name));
}
return 0;
}
diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c
index f8a3deadc77a..92d32a733f1b 100644
--- a/drivers/media/pci/cx23885/cx23885-video.c
+++ b/drivers/media/pci/cx23885/cx23885-video.c
@@ -639,8 +639,8 @@ static int vidioc_querycap(struct file *file, void *priv,
struct cx23885_dev *dev = video_drvdata(file);
struct video_device *vdev = video_devdata(file);
- strcpy(cap->driver, "cx23885");
- strlcpy(cap->card, cx23885_boards[dev->board].name,
+ strscpy(cap->driver, "cx23885", sizeof(cap->driver));
+ strscpy(cap->card, cx23885_boards[dev->board].name,
sizeof(cap->card));
sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci));
cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_AUDIO;
@@ -661,7 +661,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
if (unlikely(f->index >= ARRAY_SIZE(formats)))
return -EINVAL;
- strlcpy(f->description, formats[f->index].name,
+ strscpy(f->description, formats[f->index].name,
sizeof(f->description));
f->pixelformat = formats[f->index].fourcc;
@@ -731,7 +731,7 @@ int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i)
i->index = n;
i->type = V4L2_INPUT_TYPE_CAMERA;
- strcpy(i->name, iname[INPUT(n)->type]);
+ strscpy(i->name, iname[INPUT(n)->type], sizeof(i->name));
i->std = CX23885_NORMS;
if ((CX23885_VMUX_TELEVISION == INPUT(n)->type) ||
(CX23885_VMUX_CABLE == INPUT(n)->type)) {
@@ -828,7 +828,7 @@ static int cx23885_query_audinput(struct file *file, void *priv,
memset(i, 0, sizeof(*i));
i->index = n;
- strcpy(i->name, iname[n]);
+ strscpy(i->name, iname[n], sizeof(i->name));
i->capability = V4L2_AUDCAP_STEREO;
return 0;
@@ -887,7 +887,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
if (0 != t->index)
return -EINVAL;
- strcpy(t->name, "Television");
+ strscpy(t->name, "Television", sizeof(t->name));
call_all(dev, tuner, g_tuner, t);
return 0;
@@ -1186,7 +1186,8 @@ int cx23885_video_register(struct cx23885_dev *dev)
/* Initialize VBI template */
cx23885_vbi_template = cx23885_video_template;
- strcpy(cx23885_vbi_template.name, "cx23885-vbi");
+ strscpy(cx23885_vbi_template.name, "cx23885-vbi",
+ sizeof(cx23885_vbi_template.name));
dev->tvnorm = V4L2_STD_NTSC_M;
dev->fmt = format_by_fourcc(V4L2_PIX_FMT_YUYV);
diff --git a/drivers/media/pci/cx23885/cx23888-ir.c b/drivers/media/pci/cx23885/cx23888-ir.c
index 00329f668b59..1d775c90df51 100644
--- a/drivers/media/pci/cx23885/cx23888-ir.c
+++ b/drivers/media/pci/cx23885/cx23888-ir.c
@@ -696,10 +696,8 @@ static int cx23888_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count,
if (v > IR_MAX_DURATION)
v = IR_MAX_DURATION;
- init_ir_raw_event(&p->ir_core_data);
- p->ir_core_data.pulse = u;
- p->ir_core_data.duration = v;
- p->ir_core_data.timeout = w;
+ p->ir_core_data = (struct ir_raw_event)
+ { .pulse = u, .duration = v, .timeout = w };
v4l2_dbg(2, ir_888_debug, sd, "rx read: %10u ns %s %s\n",
v, u ? "mark" : "space", w ? "(timed out)" : "");
diff --git a/drivers/media/pci/cx25821/cx25821-alsa.c b/drivers/media/pci/cx25821/cx25821-alsa.c
index ef6380651c10..0a6c90e92557 100644
--- a/drivers/media/pci/cx25821/cx25821-alsa.c
+++ b/drivers/media/pci/cx25821/cx25821-alsa.c
@@ -674,7 +674,7 @@ static int snd_cx25821_pcm(struct cx25821_audio_dev *chip, int device,
}
pcm->private_data = chip;
pcm->info_flags = 0;
- strcpy(pcm->name, name);
+ strscpy(pcm->name, name, sizeof(pcm->name));
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cx25821_pcm_ops);
return 0;
@@ -725,7 +725,7 @@ static int cx25821_audio_initdev(struct cx25821_dev *dev)
return err;
}
- strcpy(card->driver, "cx25821");
+ strscpy(card->driver, "cx25821", sizeof(card->driver));
/* Card "creation" */
chip = card->private_data;
@@ -754,10 +754,10 @@ static int cx25821_audio_initdev(struct cx25821_dev *dev)
goto error;
}
- strcpy(card->shortname, "cx25821");
+ strscpy(card->shortname, "cx25821", sizeof(card->shortname));
sprintf(card->longname, "%s at 0x%lx irq %d", chip->dev->name,
chip->iobase, chip->irq);
- strcpy(card->mixername, "CX25821");
+ strscpy(card->mixername, "CX25821", sizeof(card->mixername));
pr_info("%s/%i: ALSA support for cx25821 boards\n", card->driver,
devno);
diff --git a/drivers/media/pci/cx25821/cx25821-i2c.c b/drivers/media/pci/cx25821/cx25821-i2c.c
index 31479a41f359..67d2f7610011 100644
--- a/drivers/media/pci/cx25821/cx25821-i2c.c
+++ b/drivers/media/pci/cx25821/cx25821-i2c.c
@@ -306,7 +306,7 @@ int cx25821_i2c_register(struct cx25821_i2c *bus)
bus->i2c_client = cx25821_i2c_client_template;
bus->i2c_adap.dev.parent = &dev->pci->dev;
- strlcpy(bus->i2c_adap.name, bus->dev->name, sizeof(bus->i2c_adap.name));
+ strscpy(bus->i2c_adap.name, bus->dev->name, sizeof(bus->i2c_adap.name));
bus->i2c_adap.algo_data = bus;
i2c_set_adapdata(&bus->i2c_adap, &dev->v4l2_dev);
diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c
index dbaf42ec26cd..3d23c2e64102 100644
--- a/drivers/media/pci/cx25821/cx25821-video.c
+++ b/drivers/media/pci/cx25821/cx25821-video.c
@@ -322,7 +322,7 @@ static int cx25821_vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
if (unlikely(f->index >= ARRAY_SIZE(formats)))
return -EINVAL;
- strlcpy(f->description, formats[f->index].name, sizeof(f->description));
+ strscpy(f->description, formats[f->index].name, sizeof(f->description));
f->pixelformat = formats[f->index].fourcc;
return 0;
@@ -441,8 +441,8 @@ static int cx25821_vidioc_querycap(struct file *file, void *priv,
V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
const u32 cap_output = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_READWRITE;
- strcpy(cap->driver, "cx25821");
- strlcpy(cap->card, cx25821_boards[dev->board].name, sizeof(cap->card));
+ strscpy(cap->driver, "cx25821", sizeof(cap->driver));
+ strscpy(cap->card, cx25821_boards[dev->board].name, sizeof(cap->card));
sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci));
if (chan->id >= VID_CHANNEL_NUM)
cap->device_caps = cap_output;
@@ -486,7 +486,7 @@ static int cx25821_vidioc_enum_input(struct file *file, void *priv,
i->type = V4L2_INPUT_TYPE_CAMERA;
i->std = CX25821_NORMS;
- strcpy(i->name, "Composite");
+ strscpy(i->name, "Composite", sizeof(i->name));
return 0;
}
@@ -534,7 +534,7 @@ static int cx25821_vidioc_enum_output(struct file *file, void *priv,
o->type = V4L2_INPUT_TYPE_CAMERA;
o->std = CX25821_NORMS;
- strcpy(o->name, "Composite");
+ strscpy(o->name, "Composite", sizeof(o->name));
return 0;
}
diff --git a/drivers/media/pci/cx88/cx88-alsa.c b/drivers/media/pci/cx88/cx88-alsa.c
index 89a65478ae36..b683cbe13dee 100644
--- a/drivers/media/pci/cx88/cx88-alsa.c
+++ b/drivers/media/pci/cx88/cx88-alsa.c
@@ -616,7 +616,7 @@ static int snd_cx88_pcm(struct cx88_audio_dev *chip, int device,
if (err < 0)
return err;
pcm->private_data = chip;
- strcpy(pcm->name, name);
+ strscpy(pcm->name, name, sizeof(pcm->name));
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cx88_pcm_ops);
return 0;
@@ -968,12 +968,12 @@ static int cx88_audio_initdev(struct pci_dev *pci,
goto error;
}
- strcpy(card->driver, "CX88x");
+ strscpy(card->driver, "CX88x", sizeof(card->driver));
sprintf(card->shortname, "Conexant CX%x", pci->device);
sprintf(card->longname, "%s at %#llx",
card->shortname,
(unsigned long long)pci_resource_start(pci, 0));
- strcpy(card->mixername, "CX88");
+ strscpy(card->mixername, "CX88", sizeof(card->mixername));
dprintk(0, "%s/%i: ALSA support for cx2388x boards\n",
card->driver, devno);
diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c
index 7a4876cf9f08..6c0bb9fe4a31 100644
--- a/drivers/media/pci/cx88/cx88-blackbird.c
+++ b/drivers/media/pci/cx88/cx88-blackbird.c
@@ -803,7 +803,7 @@ static int vidioc_querycap(struct file *file, void *priv,
struct cx8802_dev *dev = video_drvdata(file);
struct cx88_core *core = dev->core;
- strcpy(cap->driver, "cx88_blackbird");
+ strscpy(cap->driver, "cx88_blackbird", sizeof(cap->driver));
sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
return cx88_querycap(file, core, cap);
}
@@ -814,7 +814,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
if (f->index != 0)
return -EINVAL;
- strlcpy(f->description, "MPEG", sizeof(f->description));
+ strscpy(f->description, "MPEG", sizeof(f->description));
f->pixelformat = V4L2_PIX_FMT_MPEG;
f->flags = V4L2_FMT_FLAG_COMPRESSED;
return 0;
@@ -995,7 +995,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
if (t->index != 0)
return -EINVAL;
- strcpy(t->name, "Television");
+ strscpy(t->name, "Television", sizeof(t->name));
t->capability = V4L2_TUNER_CAP_NORM;
t->rangehigh = 0xffffffffUL;
call_all(core, tuner, g_tuner, t);
@@ -1183,7 +1183,7 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv)
err = cx2341x_handler_init(&dev->cxhdl, 36);
if (err)
goto fail_core;
- v4l2_ctrl_add_handler(&dev->cxhdl.hdl, &core->video_hdl, NULL);
+ v4l2_ctrl_add_handler(&dev->cxhdl.hdl, &core->video_hdl, NULL, false);
/* blackbird stuff */
pr_info("cx23416 based mpeg encoder (blackbird reference design)\n");
diff --git a/drivers/media/pci/cx88/cx88-cards.c b/drivers/media/pci/cx88/cx88-cards.c
index 07e1483e987d..382af90fd4a9 100644
--- a/drivers/media/pci/cx88/cx88-cards.c
+++ b/drivers/media/pci/cx88/cx88-cards.c
@@ -3693,7 +3693,7 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
core->height = 240;
core->field = V4L2_FIELD_INTERLACED;
- strcpy(core->v4l2_dev.name, core->name);
+ strscpy(core->v4l2_dev.name, core->name, sizeof(core->v4l2_dev.name));
if (v4l2_device_register(NULL, &core->v4l2_dev)) {
kfree(core);
return NULL;
diff --git a/drivers/media/pci/cx88/cx88-i2c.c b/drivers/media/pci/cx88/cx88-i2c.c
index 99f88a05a7c9..48be0b0ad680 100644
--- a/drivers/media/pci/cx88/cx88-i2c.c
+++ b/drivers/media/pci/cx88/cx88-i2c.c
@@ -140,14 +140,14 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
core->i2c_algo = cx8800_i2c_algo_template;
core->i2c_adap.dev.parent = &pci->dev;
- strlcpy(core->i2c_adap.name, core->name, sizeof(core->i2c_adap.name));
+ strscpy(core->i2c_adap.name, core->name, sizeof(core->i2c_adap.name));
core->i2c_adap.owner = THIS_MODULE;
core->i2c_algo.udelay = i2c_udelay;
core->i2c_algo.data = core;
i2c_set_adapdata(&core->i2c_adap, &core->v4l2_dev);
core->i2c_adap.algo_data = &core->i2c_algo;
core->i2c_client.adapter = &core->i2c_adap;
- strlcpy(core->i2c_client.name, "cx88xx internal", I2C_NAME_SIZE);
+ strscpy(core->i2c_client.name, "cx88xx internal", I2C_NAME_SIZE);
cx8800_bit_setscl(core, 1);
cx8800_bit_setsda(core, 1);
diff --git a/drivers/media/pci/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c
index 2f5debce4905..ca76da04b476 100644
--- a/drivers/media/pci/cx88/cx88-input.c
+++ b/drivers/media/pci/cx88/cx88-input.c
@@ -535,7 +535,7 @@ void cx88_ir_irq(struct cx88_core *core)
struct cx88_IR *ir = core->ir;
u32 samples;
unsigned int todo, bits;
- struct ir_raw_event ev;
+ struct ir_raw_event ev = {};
if (!ir || !ir->sampling)
return;
@@ -550,7 +550,6 @@ void cx88_ir_irq(struct cx88_core *core)
if (samples == 0xff && ir->dev->idle)
return;
- init_ir_raw_event(&ev);
for (todo = 32; todo > 0; todo -= bits) {
ev.pulse = samples & 0x80000000 ? false : true;
bits = min(todo, 32U - fls(ev.pulse ? samples : ~samples));
@@ -610,7 +609,7 @@ void cx88_i2c_init_ir(struct cx88_core *core)
return;
memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+ strscpy(info.type, "ir_video", I2C_NAME_SIZE);
switch (core->boardnr) {
case CX88_BOARD_LEADTEK_PVR2000:
@@ -635,7 +634,7 @@ void cx88_i2c_init_ir(struct cx88_core *core)
if (*addrp == 0x71) {
/* Hauppauge Z8F0811 */
- strlcpy(info.type, "ir_z8f0811_haup", I2C_NAME_SIZE);
+ strscpy(info.type, "ir_z8f0811_haup", I2C_NAME_SIZE);
core->init_data.name = core->board.name;
core->init_data.ir_codes = RC_MAP_HAUPPAUGE;
core->init_data.type = RC_PROTO_BIT_RC5 |
diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c
index 7b113bad70d2..e1549d352f70 100644
--- a/drivers/media/pci/cx88/cx88-video.c
+++ b/drivers/media/pci/cx88/cx88-video.c
@@ -811,7 +811,7 @@ int cx88_querycap(struct file *file, struct cx88_core *core,
{
struct video_device *vdev = video_devdata(file);
- strlcpy(cap->card, core->board.name, sizeof(cap->card));
+ strscpy(cap->card, core->board.name, sizeof(cap->card));
cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
if (core->board.tuner_type != UNSET)
cap->device_caps |= V4L2_CAP_TUNER;
@@ -842,7 +842,7 @@ static int vidioc_querycap(struct file *file, void *priv,
struct cx8800_dev *dev = video_drvdata(file);
struct cx88_core *core = dev->core;
- strcpy(cap->driver, "cx8800");
+ strscpy(cap->driver, "cx8800", sizeof(cap->driver));
sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
return cx88_querycap(file, core, cap);
}
@@ -853,7 +853,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
if (unlikely(f->index >= ARRAY_SIZE(formats)))
return -EINVAL;
- strlcpy(f->description, formats[f->index].name, sizeof(f->description));
+ strscpy(f->description, formats[f->index].name, sizeof(f->description));
f->pixelformat = formats[f->index].fourcc;
return 0;
@@ -897,7 +897,7 @@ int cx88_enum_input(struct cx88_core *core, struct v4l2_input *i)
if (!INPUT(n).type)
return -EINVAL;
i->type = V4L2_INPUT_TYPE_CAMERA;
- strcpy(i->name, iname[INPUT(n).type]);
+ strscpy(i->name, iname[INPUT(n).type], sizeof(i->name));
if ((INPUT(n).type == CX88_VMUX_TELEVISION) ||
(INPUT(n).type == CX88_VMUX_CABLE))
i->type = V4L2_INPUT_TYPE_TUNER;
@@ -952,7 +952,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
if (t->index != 0)
return -EINVAL;
- strcpy(t->name, "Television");
+ strscpy(t->name, "Television", sizeof(t->name));
t->capability = V4L2_TUNER_CAP_NORM;
t->rangehigh = 0xffffffffUL;
call_all(core, tuner, g_tuner, t);
@@ -1065,7 +1065,7 @@ static int radio_g_tuner(struct file *file, void *priv,
if (unlikely(t->index > 0))
return -EINVAL;
- strcpy(t->name, "Radio");
+ strscpy(t->name, "Radio", sizeof(t->name));
call_all(core, tuner, g_tuner, t);
return 0;
@@ -1378,7 +1378,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev,
if (vc->id == V4L2_CID_CHROMA_AGC)
core->chroma_agc = vc;
}
- v4l2_ctrl_add_handler(&core->video_hdl, &core->audio_hdl, NULL);
+ v4l2_ctrl_add_handler(&core->video_hdl, &core->audio_hdl, NULL, false);
/* load and configure helper modules */
diff --git a/drivers/media/pci/cx88/cx88-vp3054-i2c.c b/drivers/media/pci/cx88/cx88-vp3054-i2c.c
index 92876de3841c..e4db636e9fad 100644
--- a/drivers/media/pci/cx88/cx88-vp3054-i2c.c
+++ b/drivers/media/pci/cx88/cx88-vp3054-i2c.c
@@ -114,7 +114,7 @@ int vp3054_i2c_probe(struct cx8802_dev *dev)
vp3054_i2c->algo = vp3054_i2c_algo_template;
vp3054_i2c->adap.dev.parent = &dev->pci->dev;
- strlcpy(vp3054_i2c->adap.name, core->name,
+ strscpy(vp3054_i2c->adap.name, core->name,
sizeof(vp3054_i2c->adap.name));
vp3054_i2c->adap.owner = THIS_MODULE;
vp3054_i2c->algo.data = dev;
diff --git a/drivers/media/pci/ddbridge/ddbridge-ci.c b/drivers/media/pci/ddbridge/ddbridge-ci.c
index cfe23d02e561..377991095aba 100644
--- a/drivers/media/pci/ddbridge/ddbridge-ci.c
+++ b/drivers/media/pci/ddbridge/ddbridge-ci.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* ddbridge-ci.c: Digital Devices bridge CI (DuoFlex, CI Bridge) support
*
@@ -13,9 +14,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * To obtain the license, point your browser to
- * http://www.gnu.org/copyleft/gpl.html
*/
#include "ddbridge.h"
diff --git a/drivers/media/pci/ddbridge/ddbridge-ci.h b/drivers/media/pci/ddbridge/ddbridge-ci.h
index 35a39182dd83..cc98656af349 100644
--- a/drivers/media/pci/ddbridge/ddbridge-ci.h
+++ b/drivers/media/pci/ddbridge/ddbridge-ci.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* ddbridge-ci.h: Digital Devices bridge CI (DuoFlex, CI Bridge) support
*
@@ -13,9 +14,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * To obtain the license, point your browser to
- * http://www.gnu.org/copyleft/gpl.html
*/
#ifndef __DDBRIDGE_CI_H__
diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c
index c1b982e8e6c9..7a2d19682fe3 100644
--- a/drivers/media/pci/ddbridge/ddbridge-core.c
+++ b/drivers/media/pci/ddbridge/ddbridge-core.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* ddbridge-core.c: Digital Devices bridge core functions
*
@@ -5,19 +6,14 @@
* Marcus Metzler <mocm@metzlerbros.de>
* Ralph Metzler <rjkm@metzlerbros.de>
*
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 only, as published by the Free Software Foundation.
*
- *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * To obtain the license, point your browser to
- * http://www.gnu.org/copyleft/gpl.html
*/
#include <linux/module.h>
diff --git a/drivers/media/pci/ddbridge/ddbridge-hw.c b/drivers/media/pci/ddbridge/ddbridge-hw.c
index f3cbac07b41f..f9c91bdbd041 100644
--- a/drivers/media/pci/ddbridge/ddbridge-hw.c
+++ b/drivers/media/pci/ddbridge/ddbridge-hw.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* ddbridge-hw.c: Digital Devices bridge hardware maps
*
@@ -13,7 +14,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
*/
#include "ddbridge.h"
diff --git a/drivers/media/pci/ddbridge/ddbridge-hw.h b/drivers/media/pci/ddbridge/ddbridge-hw.h
index 7c142419419c..e34bd94c266b 100644
--- a/drivers/media/pci/ddbridge/ddbridge-hw.h
+++ b/drivers/media/pci/ddbridge/ddbridge-hw.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* ddbridge-hw.h: Digital Devices bridge hardware maps
*
@@ -13,7 +14,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
*/
#ifndef _DDBRIDGE_HW_H_
diff --git a/drivers/media/pci/ddbridge/ddbridge-i2c.c b/drivers/media/pci/ddbridge/ddbridge-i2c.c
index 5a28d7611713..aafa6030c8cc 100644
--- a/drivers/media/pci/ddbridge/ddbridge-i2c.c
+++ b/drivers/media/pci/ddbridge/ddbridge-i2c.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* ddbridge-i2c.c: Digital Devices bridge i2c driver
*
@@ -13,7 +14,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
*/
#include <linux/module.h>
diff --git a/drivers/media/pci/ddbridge/ddbridge-i2c.h b/drivers/media/pci/ddbridge/ddbridge-i2c.h
index 7ed220506c05..90830f7b1638 100644
--- a/drivers/media/pci/ddbridge/ddbridge-i2c.h
+++ b/drivers/media/pci/ddbridge/ddbridge-i2c.h
@@ -1,5 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
- * ddbridge-i2c.c: Digital Devices bridge i2c driver
+ * ddbridge-i2c.h: Digital Devices bridge i2c driver
*
* Copyright (C) 2010-2017 Digital Devices GmbH
* Ralph Metzler <rjkm@metzlerbros.de>
@@ -13,7 +14,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
*/
#ifndef __DDBRIDGE_I2C_H__
diff --git a/drivers/media/pci/ddbridge/ddbridge-io.h b/drivers/media/pci/ddbridge/ddbridge-io.h
index b3646c04f1a7..1a5b31b52494 100644
--- a/drivers/media/pci/ddbridge/ddbridge-io.h
+++ b/drivers/media/pci/ddbridge/ddbridge-io.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* ddbridge-io.h: Digital Devices bridge I/O inline functions
*
@@ -13,7 +14,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
*/
#ifndef __DDBRIDGE_IO_H__
diff --git a/drivers/media/pci/ddbridge/ddbridge-main.c b/drivers/media/pci/ddbridge/ddbridge-main.c
index f4748cfd904b..03dc9924fa2c 100644
--- a/drivers/media/pci/ddbridge/ddbridge-main.c
+++ b/drivers/media/pci/ddbridge/ddbridge-main.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* ddbridge.c: Digital Devices PCIe bridge driver
*
@@ -13,7 +14,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -318,5 +318,5 @@ module_exit(module_exit_ddbridge);
MODULE_DESCRIPTION("Digital Devices PCIe Bridge");
MODULE_AUTHOR("Ralph and Marcus Metzler, Metzler Brothers Systementwicklung GbR");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_VERSION(DDBRIDGE_VERSION);
diff --git a/drivers/media/pci/ddbridge/ddbridge-max.c b/drivers/media/pci/ddbridge/ddbridge-max.c
index 8da1c7b91577..576dd2318e4d 100644
--- a/drivers/media/pci/ddbridge/ddbridge-max.c
+++ b/drivers/media/pci/ddbridge/ddbridge-max.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* ddbridge-max.c: Digital Devices bridge MAX card support
*
@@ -13,7 +14,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
*/
#include <linux/module.h>
diff --git a/drivers/media/pci/ddbridge/ddbridge-max.h b/drivers/media/pci/ddbridge/ddbridge-max.h
index 9838c73973b6..6543dfc77138 100644
--- a/drivers/media/pci/ddbridge/ddbridge-max.h
+++ b/drivers/media/pci/ddbridge/ddbridge-max.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* ddbridge-max.h: Digital Devices bridge MAX card support
*
@@ -13,7 +14,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
*/
#ifndef _DDBRIDGE_MAX_H_
diff --git a/drivers/media/pci/ddbridge/ddbridge-regs.h b/drivers/media/pci/ddbridge/ddbridge-regs.h
index f9e1cbb99b53..2942a7f35099 100644
--- a/drivers/media/pci/ddbridge/ddbridge-regs.h
+++ b/drivers/media/pci/ddbridge/ddbridge-regs.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* ddbridge-regs.h: Digital Devices PCIe bridge driver
*
@@ -7,14 +8,10 @@
* modify it under the terms of the GNU General Public License
* version 2 only, as published by the Free Software Foundation.
*
- *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * To obtain the license, point your browser to
- * http://www.gnu.org/copyleft/gpl.html
*/
#ifndef __DDBRIDGE_REGS_H__
diff --git a/drivers/media/pci/ddbridge/ddbridge-sx8.c b/drivers/media/pci/ddbridge/ddbridge-sx8.c
index 64f05f5ee039..374fcee94960 100644
--- a/drivers/media/pci/ddbridge/ddbridge-sx8.c
+++ b/drivers/media/pci/ddbridge/ddbridge-sx8.c
@@ -398,9 +398,7 @@ static int set_parameters(struct dvb_frontend *fe)
}
stat = start(fe, 3, mask, ts_config);
} else {
- u32 flags = (iq_mode == 2) ? 1 : 0;
-
- stat = start_iq(fe, flags, 4, ts_config);
+ stat = start_iq(fe, 0, 4, ts_config);
}
if (!stat) {
state->started = 1;
diff --git a/drivers/media/pci/ddbridge/ddbridge.h b/drivers/media/pci/ddbridge/ddbridge.h
index 8a354dfb6c22..f137155bf79e 100644
--- a/drivers/media/pci/ddbridge/ddbridge.h
+++ b/drivers/media/pci/ddbridge/ddbridge.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* ddbridge.h: Digital Devices PCIe bridge driver
*
@@ -8,14 +9,10 @@
* modify it under the terms of the GNU General Public License
* version 2 only, as published by the Free Software Foundation.
*
- *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * To obtain the license, point your browser to
- * http://www.gnu.org/copyleft/gpl.html
*/
#ifndef _DDBRIDGE_H_
diff --git a/drivers/media/pci/dm1105/dm1105.c b/drivers/media/pci/dm1105/dm1105.c
index 1ddb0576fb7b..a84c8270ea13 100644
--- a/drivers/media/pci/dm1105/dm1105.c
+++ b/drivers/media/pci/dm1105/dm1105.c
@@ -1046,7 +1046,7 @@ static int dm1105_probe(struct pci_dev *pdev,
/* i2c */
i2c_set_adapdata(&dev->i2c_adap, dev);
- strcpy(dev->i2c_adap.name, DRIVER_NAME);
+ strscpy(dev->i2c_adap.name, DRIVER_NAME, sizeof(dev->i2c_adap.name));
dev->i2c_adap.owner = THIS_MODULE;
dev->i2c_adap.dev.parent = &pdev->dev;
dev->i2c_adap.algo = &dm1105_algo;
@@ -1057,7 +1057,8 @@ static int dm1105_probe(struct pci_dev *pdev,
goto err_dm1105_hw_exit;
i2c_set_adapdata(&dev->i2c_bb_adap, dev);
- strcpy(dev->i2c_bb_adap.name, DM1105_I2C_GPIO_NAME);
+ strscpy(dev->i2c_bb_adap.name, DM1105_I2C_GPIO_NAME,
+ sizeof(dev->i2c_bb_adap.name));
dev->i2c_bb_adap.owner = THIS_MODULE;
dev->i2c_bb_adap.dev.parent = &pdev->dev;
dev->i2c_bb_adap.algo_data = &dev->i2c_bit;
diff --git a/drivers/media/pci/dt3155/dt3155.c b/drivers/media/pci/dt3155/dt3155.c
index 1775c36891ae..17d69bd5d7f1 100644
--- a/drivers/media/pci/dt3155/dt3155.c
+++ b/drivers/media/pci/dt3155/dt3155.c
@@ -307,8 +307,8 @@ static int dt3155_querycap(struct file *filp, void *p,
{
struct dt3155_priv *pd = video_drvdata(filp);
- strcpy(cap->driver, DT3155_NAME);
- strcpy(cap->card, DT3155_NAME " frame grabber");
+ strscpy(cap->driver, DT3155_NAME, sizeof(cap->driver));
+ strscpy(cap->card, DT3155_NAME " frame grabber", sizeof(cap->card));
sprintf(cap->bus_info, "PCI:%s", pci_name(pd->pdev));
cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
@@ -322,7 +322,7 @@ static int dt3155_enum_fmt_vid_cap(struct file *filp,
if (f->index)
return -EINVAL;
f->pixelformat = V4L2_PIX_FMT_GREY;
- strcpy(f->description, "8-bit Greyscale");
+ strscpy(f->description, "8-bit Greyscale", sizeof(f->description));
return 0;
}
@@ -378,7 +378,7 @@ static int dt3155_enum_input(struct file *filp, void *p,
snprintf(input->name, sizeof(input->name), "VID%d",
input->index);
else
- strlcpy(input->name, "J2/VID0", sizeof(input->name));
+ strscpy(input->name, "J2/VID0", sizeof(input->name));
input->type = V4L2_INPUT_TYPE_CAMERA;
input->std = V4L2_STD_ALL;
input->status = 0;
diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c
index 29027159eced..452eb9b42140 100644
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c
@@ -218,13 +218,11 @@ static int cio2_fbpt_init(struct cio2_device *cio2, struct cio2_queue *q)
{
struct device *dev = &cio2->pci_dev->dev;
- q->fbpt = dma_alloc_coherent(dev, CIO2_FBPT_SIZE, &q->fbpt_bus_addr,
- GFP_KERNEL);
+ q->fbpt = dma_zalloc_coherent(dev, CIO2_FBPT_SIZE, &q->fbpt_bus_addr,
+ GFP_KERNEL);
if (!q->fbpt)
return -ENOMEM;
- memset(q->fbpt, 0, CIO2_FBPT_SIZE);
-
return 0;
}
@@ -1066,8 +1064,8 @@ static int cio2_v4l2_querycap(struct file *file, void *fh,
{
struct cio2_device *cio2 = video_drvdata(file);
- strlcpy(cap->driver, CIO2_NAME, sizeof(cap->driver));
- strlcpy(cap->card, CIO2_DEVICE_NAME, sizeof(cap->card));
+ strscpy(cap->driver, CIO2_NAME, sizeof(cap->driver));
+ strscpy(cap->card, CIO2_DEVICE_NAME, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info),
"PCI:%s", pci_name(cio2->pci_dev));
@@ -1145,7 +1143,7 @@ cio2_video_enum_input(struct file *file, void *fh, struct v4l2_input *input)
if (input->index > 0)
return -EINVAL;
- strlcpy(input->name, "camera", sizeof(input->name));
+ strscpy(input->name, "camera", sizeof(input->name));
input->type = V4L2_INPUT_TYPE_CAMERA;
return 0;
@@ -1435,13 +1433,13 @@ static int cio2_notifier_complete(struct v4l2_async_notifier *notifier)
struct cio2_device *cio2 = container_of(notifier, struct cio2_device,
notifier);
struct sensor_async_subdev *s_asd;
+ struct v4l2_async_subdev *asd;
struct cio2_queue *q;
- unsigned int i, pad;
+ unsigned int pad;
int ret;
- for (i = 0; i < notifier->num_subdevs; i++) {
- s_asd = container_of(cio2->notifier.subdevs[i],
- struct sensor_async_subdev, asd);
+ list_for_each_entry(asd, &cio2->notifier.asd_list, asd_list) {
+ s_asd = container_of(asd, struct sensor_async_subdev, asd);
q = &cio2->queue[s_asd->csi2.port];
for (pad = 0; pad < q->sensor->entity.num_pads; pad++)
@@ -1463,7 +1461,7 @@ static int cio2_notifier_complete(struct v4l2_async_notifier *notifier)
if (ret) {
dev_err(&cio2->pci_dev->dev,
"failed to create link for %s\n",
- cio2->queue[i].sensor->name);
+ q->sensor->name);
return ret;
}
}
@@ -1484,7 +1482,7 @@ static int cio2_fwnode_parse(struct device *dev,
struct sensor_async_subdev *s_asd =
container_of(asd, struct sensor_async_subdev, asd);
- if (vep->bus_type != V4L2_MBUS_CSI2) {
+ if (vep->bus_type != V4L2_MBUS_CSI2_DPHY) {
dev_err(dev, "Only CSI2 bus type is currently supported\n");
return -EINVAL;
}
@@ -1499,6 +1497,8 @@ static int cio2_notifier_init(struct cio2_device *cio2)
{
int ret;
+ v4l2_async_notifier_init(&cio2->notifier);
+
ret = v4l2_async_notifier_parse_fwnode_endpoints(
&cio2->pci_dev->dev, &cio2->notifier,
sizeof(struct sensor_async_subdev),
@@ -1506,7 +1506,7 @@ static int cio2_notifier_init(struct cio2_device *cio2)
if (ret < 0)
return ret;
- if (!cio2->notifier.num_subdevs)
+ if (list_empty(&cio2->notifier.asd_list))
return -ENODEV; /* no endpoint */
cio2->notifier.ops = &cio2_async_ops;
@@ -1785,7 +1785,7 @@ static int cio2_pci_probe(struct pci_dev *pci_dev,
mutex_init(&cio2->lock);
cio2->media_dev.dev = &cio2->pci_dev->dev;
- strlcpy(cio2->media_dev.model, CIO2_DEVICE_NAME,
+ strscpy(cio2->media_dev.model, CIO2_DEVICE_NAME,
sizeof(cio2->media_dev.model));
snprintf(cio2->media_dev.bus_info, sizeof(cio2->media_dev.bus_info),
"PCI:%s", pci_name(cio2->pci_dev));
diff --git a/drivers/media/pci/ivtv/ivtv-alsa-main.c b/drivers/media/pci/ivtv/ivtv-alsa-main.c
index c1856f609d2c..0de8a9f5011a 100644
--- a/drivers/media/pci/ivtv/ivtv-alsa-main.c
+++ b/drivers/media/pci/ivtv/ivtv-alsa-main.c
@@ -109,7 +109,7 @@ static int snd_ivtv_card_set_names(struct snd_ivtv_card *itvsc)
struct snd_card *sc = itvsc->sc;
/* sc->driver is used by alsa-lib's configurator: simple, unique */
- strlcpy(sc->driver, "CX2341[56]", sizeof(sc->driver));
+ strscpy(sc->driver, "CX2341[56]", sizeof(sc->driver));
/* sc->shortname is a symlink in /proc/asound: IVTV-M -> cardN */
snprintf(sc->shortname, sizeof(sc->shortname), "IVTV-%d",
diff --git a/drivers/media/pci/ivtv/ivtv-alsa-pcm.c b/drivers/media/pci/ivtv/ivtv-alsa-pcm.c
index 5326d86fa375..737c52de7558 100644
--- a/drivers/media/pci/ivtv/ivtv-alsa-pcm.c
+++ b/drivers/media/pci/ivtv/ivtv-alsa-pcm.c
@@ -350,7 +350,7 @@ int snd_ivtv_pcm_create(struct snd_ivtv_card *itvsc)
&snd_ivtv_pcm_capture_ops);
sp->info_flags = 0;
sp->private_data = itvsc;
- strlcpy(sp->name, itv->card_name, sizeof(sp->name));
+ strscpy(sp->name, itv->card_name, sizeof(sp->name));
return 0;
diff --git a/drivers/media/pci/ivtv/ivtv-cards.c b/drivers/media/pci/ivtv/ivtv-cards.c
index c63792964a03..4ff46a6d0503 100644
--- a/drivers/media/pci/ivtv/ivtv-cards.c
+++ b/drivers/media/pci/ivtv/ivtv-cards.c
@@ -1317,8 +1317,8 @@ int ivtv_get_input(struct ivtv *itv, u16 index, struct v4l2_input *input)
if (index >= itv->nof_inputs)
return -EINVAL;
input->index = index;
- strlcpy(input->name, input_strs[card_input->video_type - 1],
- sizeof(input->name));
+ strscpy(input->name, input_strs[card_input->video_type - 1],
+ sizeof(input->name));
input->type = (card_input->video_type == IVTV_CARD_INPUT_VID_TUNER ?
V4L2_INPUT_TYPE_TUNER : V4L2_INPUT_TYPE_CAMERA);
input->audioset = (1 << itv->nof_audio_inputs) - 1;
@@ -1334,7 +1334,7 @@ int ivtv_get_output(struct ivtv *itv, u16 index, struct v4l2_output *output)
if (index >= itv->card->nof_outputs)
return -EINVAL;
output->index = index;
- strlcpy(output->name, card_output->name, sizeof(output->name));
+ strscpy(output->name, card_output->name, sizeof(output->name));
output->type = V4L2_OUTPUT_TYPE_ANALOG;
output->audioset = 1;
output->std = V4L2_STD_ALL;
@@ -1353,8 +1353,8 @@ int ivtv_get_audio_input(struct ivtv *itv, u16 index, struct v4l2_audio *audio)
memset(audio, 0, sizeof(*audio));
if (index >= itv->nof_audio_inputs)
return -EINVAL;
- strlcpy(audio->name, input_strs[aud_input->audio_type - 1],
- sizeof(audio->name));
+ strscpy(audio->name, input_strs[aud_input->audio_type - 1],
+ sizeof(audio->name));
audio->index = index;
audio->capability = V4L2_AUDCAP_STEREO;
return 0;
@@ -1365,6 +1365,6 @@ int ivtv_get_audio_output(struct ivtv *itv, u16 index, struct v4l2_audioout *aud
memset(aud_output, 0, sizeof(*aud_output));
if (itv->card->video_outputs == NULL || index != 0)
return -EINVAL;
- strlcpy(aud_output->name, "A/V Audio Out", sizeof(aud_output->name));
+ strscpy(aud_output->name, "A/V Audio Out", sizeof(aud_output->name));
return 0;
}
diff --git a/drivers/media/pci/ivtv/ivtv-i2c.c b/drivers/media/pci/ivtv/ivtv-i2c.c
index e9ce54dd5e01..55ef1385519e 100644
--- a/drivers/media/pci/ivtv/ivtv-i2c.c
+++ b/drivers/media/pci/ivtv/ivtv-i2c.c
@@ -218,7 +218,7 @@ static int ivtv_i2c_new_ir(struct ivtv *itv, u32 hw, const char *type, u8 addr)
memset(&info, 0, sizeof(struct i2c_board_info));
info.platform_data = init_data;
- strlcpy(info.type, type, I2C_NAME_SIZE);
+ strscpy(info.type, type, I2C_NAME_SIZE);
return i2c_new_probed_device(adap, &info, addr_list, NULL) == NULL ?
-1 : 0;
@@ -239,14 +239,14 @@ struct i2c_client *ivtv_i2c_new_ir_legacy(struct ivtv *itv)
* allocations, so this function must be called after all other i2c
* devices we care about are registered.
*/
- const unsigned short addr_list[] = {
+ static const unsigned short addr_list[] = {
0x1a, /* Hauppauge IR external - collides with WM8739 */
0x18, /* Hauppauge IR internal */
I2C_CLIENT_END
};
memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+ strscpy(info.type, "ir_video", I2C_NAME_SIZE);
return i2c_new_probed_device(&itv->i2c_adap, &info, addr_list, NULL);
}
diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c
index 4cdc6d2be85d..a66f8b872520 100644
--- a/drivers/media/pci/ivtv/ivtv-ioctl.c
+++ b/drivers/media/pci/ivtv/ivtv-ioctl.c
@@ -36,6 +36,7 @@
#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
@@ -747,8 +748,8 @@ static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vc
struct ivtv *itv = id->itv;
struct ivtv_stream *s = &itv->streams[id->type];
- strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver));
- strlcpy(vcap->card, itv->card_name, sizeof(vcap->card));
+ strscpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver));
+ strscpy(vcap->card, itv->card_name, sizeof(vcap->card));
snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(itv->pdev));
vcap->capabilities = itv->v4l2_cap | V4L2_CAP_DEVICE_CAPS;
vcap->device_caps = s->caps;
@@ -1227,9 +1228,9 @@ static int ivtv_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
ivtv_call_all(itv, tuner, g_tuner, vt);
if (vt->type == V4L2_TUNER_RADIO)
- strlcpy(vt->name, "ivtv Radio Tuner", sizeof(vt->name));
+ strscpy(vt->name, "ivtv Radio Tuner", sizeof(vt->name));
else
- strlcpy(vt->name, "ivtv TV Tuner", sizeof(vt->name));
+ strscpy(vt->name, "ivtv TV Tuner", sizeof(vt->name));
return 0;
}
@@ -1627,6 +1628,21 @@ 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)
@@ -1749,7 +1765,13 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
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);
@@ -1763,14 +1785,22 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
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;
- ev->u.vsync_field = test_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags) ?
+ 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) {
- ev->u.vsync_field = VIDEO_VSYNC_FIELD_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;
diff --git a/drivers/media/pci/ivtv/ivtv-streams.c b/drivers/media/pci/ivtv/ivtv-streams.c
index d27c6df97566..a641f20e3f86 100644
--- a/drivers/media/pci/ivtv/ivtv-streams.c
+++ b/drivers/media/pci/ivtv/ivtv-streams.c
@@ -51,6 +51,9 @@ static const struct v4l2_file_operations ivtv_v4l2_enc_fops = {
.write = ivtv_v4l2_write,
.open = ivtv_v4l2_open,
.unlocked_ioctl = video_ioctl2,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl32 = video_ioctl2, /* for ivtv_default() */
+#endif
.release = ivtv_v4l2_close,
.poll = ivtv_v4l2_enc_poll,
};
@@ -61,6 +64,9 @@ static const struct v4l2_file_operations ivtv_v4l2_dec_fops = {
.write = ivtv_v4l2_write,
.open = ivtv_v4l2_open,
.unlocked_ioctl = video_ioctl2,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl32 = video_ioctl2, /* for ivtv_default() */
+#endif
.release = ivtv_v4l2_close,
.poll = ivtv_v4l2_dec_poll,
};
@@ -69,6 +75,9 @@ static const struct v4l2_file_operations ivtv_v4l2_radio_fops = {
.owner = THIS_MODULE,
.open = ivtv_v4l2_open,
.unlocked_ioctl = video_ioctl2,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl32 = video_ioctl2, /* for ivtv_default() */
+#endif
.release = ivtv_v4l2_close,
.poll = ivtv_v4l2_enc_poll,
};
diff --git a/drivers/media/pci/ivtv/ivtv-yuv.c b/drivers/media/pci/ivtv/ivtv-yuv.c
index 44936d6d7c39..1380474519f2 100644
--- a/drivers/media/pci/ivtv/ivtv-yuv.c
+++ b/drivers/media/pci/ivtv/ivtv-yuv.c
@@ -935,7 +935,7 @@ static void ivtv_yuv_init(struct ivtv *itv)
}
/* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */
- yi->blanking_ptr = kzalloc(720 * 16, GFP_KERNEL|__GFP_NOWARN);
+ yi->blanking_ptr = kzalloc(720 * 16, GFP_ATOMIC|__GFP_NOWARN);
if (yi->blanking_ptr) {
yi->blanking_dmaptr = pci_map_single(itv->pdev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE);
} else {
diff --git a/drivers/media/pci/ivtv/ivtvfb.c b/drivers/media/pci/ivtv/ivtvfb.c
index 5ddaa8ed11a5..3e02de02ffdd 100644
--- a/drivers/media/pci/ivtv/ivtvfb.c
+++ b/drivers/media/pci/ivtv/ivtvfb.c
@@ -624,7 +624,7 @@ static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix)
IVTVFB_DEBUG_INFO("ivtvfb_get_fix\n");
memset(fix, 0, sizeof(struct fb_fix_screeninfo));
- strlcpy(fix->id, "cx23415 TV out", sizeof(fix->id));
+ strscpy(fix->id, "cx23415 TV out", sizeof(fix->id));
fix->smem_start = oi->video_pbase;
fix->smem_len = oi->video_buffer_size;
fix->type = FB_TYPE_PACKED_PIXELS;
diff --git a/drivers/media/pci/meye/meye.c b/drivers/media/pci/meye/meye.c
index 8001d3e9134e..bd870e60c32b 100644
--- a/drivers/media/pci/meye/meye.c
+++ b/drivers/media/pci/meye/meye.c
@@ -1019,8 +1019,8 @@ static int meyeioc_stilljcapt(int *len)
static int vidioc_querycap(struct file *file, void *fh,
struct v4l2_capability *cap)
{
- strcpy(cap->driver, "meye");
- strcpy(cap->card, "meye");
+ strscpy(cap->driver, "meye", sizeof(cap->driver));
+ strscpy(cap->card, "meye", sizeof(cap->card));
sprintf(cap->bus_info, "PCI:%s", pci_name(meye.mchip_dev));
cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
@@ -1035,7 +1035,7 @@ static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
if (i->index != 0)
return -EINVAL;
- strcpy(i->name, "Camera");
+ strscpy(i->name, "Camera", sizeof(i->name));
i->type = V4L2_INPUT_TYPE_CAMERA;
return 0;
@@ -1118,12 +1118,12 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh,
if (f->index == 0) {
/* standard YUV 422 capture */
f->flags = 0;
- strcpy(f->description, "YUV422");
+ strscpy(f->description, "YUV422", sizeof(f->description));
f->pixelformat = V4L2_PIX_FMT_YUYV;
} else {
/* compressed MJPEG capture */
f->flags = V4L2_FMT_FLAG_COMPRESSED;
- strcpy(f->description, "MJPEG");
+ strscpy(f->description, "MJPEG", sizeof(f->description));
f->pixelformat = V4L2_PIX_FMT_MJPEG;
}
@@ -1460,7 +1460,7 @@ static int meye_mmap(struct file *file, struct vm_area_struct *vma)
unsigned long page, pos;
mutex_lock(&meye.lock);
- if (size > gbuffers * gbufsize) {
+ if (size > gbuffers * gbufsize || offset > gbuffers * gbufsize - size) {
mutex_unlock(&meye.lock);
return -EINVAL;
}
diff --git a/drivers/media/pci/ngene/ngene-i2c.c b/drivers/media/pci/ngene/ngene-i2c.c
index 092d46c2a3a9..02a06f6c97f8 100644
--- a/drivers/media/pci/ngene/ngene-i2c.c
+++ b/drivers/media/pci/ngene/ngene-i2c.c
@@ -161,7 +161,7 @@ int ngene_i2c_init(struct ngene *dev, int dev_nr)
i2c_set_adapdata(adap, &(dev->channel[dev_nr]));
- strcpy(adap->name, "nGene");
+ strscpy(adap->name, "nGene", sizeof(adap->name));
adap->algo = &ngene_i2c_algo;
adap->algo_data = (void *)&(dev->channel[dev_nr]);
diff --git a/drivers/media/pci/pluto2/pluto2.c b/drivers/media/pci/pluto2/pluto2.c
index 5e6fe686f420..872c796621d2 100644
--- a/drivers/media/pci/pluto2/pluto2.c
+++ b/drivers/media/pci/pluto2/pluto2.c
@@ -633,7 +633,7 @@ static int pluto2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* i2c */
i2c_set_adapdata(&pluto->i2c_adap, pluto);
- strcpy(pluto->i2c_adap.name, DRIVER_NAME);
+ strscpy(pluto->i2c_adap.name, DRIVER_NAME, sizeof(pluto->i2c_adap.name));
pluto->i2c_adap.owner = THIS_MODULE;
pluto->i2c_adap.dev.parent = &pdev->dev;
pluto->i2c_adap.algo_data = &pluto->i2c_bit;
diff --git a/drivers/media/pci/pt1/pt1.c b/drivers/media/pci/pt1/pt1.c
index 7f878fc41b7e..f4b8030e2369 100644
--- a/drivers/media/pci/pt1/pt1.c
+++ b/drivers/media/pci/pt1/pt1.c
@@ -1354,7 +1354,7 @@ static int pt1_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
i2c_adap->algo = &pt1_i2c_algo;
i2c_adap->algo_data = NULL;
i2c_adap->dev.parent = &pdev->dev;
- strcpy(i2c_adap->name, DRIVER_NAME);
+ strscpy(i2c_adap->name, DRIVER_NAME, sizeof(i2c_adap->name));
i2c_set_adapdata(i2c_adap, pt1);
ret = i2c_add_adapter(i2c_adap);
if (ret < 0)
diff --git a/drivers/media/pci/pt3/pt3.c b/drivers/media/pci/pt3/pt3.c
index 90273b4d772f..7a7afae4c84c 100644
--- a/drivers/media/pci/pt3/pt3.c
+++ b/drivers/media/pci/pt3/pt3.c
@@ -765,7 +765,7 @@ static int pt3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
i2c->algo = &pt3_i2c_algo;
i2c->algo_data = NULL;
i2c->dev.parent = &pdev->dev;
- strlcpy(i2c->name, DRV_NAME, sizeof(i2c->name));
+ strscpy(i2c->name, DRV_NAME, sizeof(i2c->name));
i2c_set_adapdata(i2c, pt3);
ret = i2c_add_adapter(i2c);
if (ret < 0)
diff --git a/drivers/media/pci/saa7134/saa7134-alsa.c b/drivers/media/pci/saa7134/saa7134-alsa.c
index b90cfde6e301..dc9cdaaee1fb 100644
--- a/drivers/media/pci/saa7134/saa7134-alsa.c
+++ b/drivers/media/pci/saa7134/saa7134-alsa.c
@@ -901,7 +901,7 @@ static int snd_card_saa7134_pcm(snd_card_saa7134_t *saa7134, int device)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_saa7134_capture_ops);
pcm->private_data = saa7134;
pcm->info_flags = 0;
- strcpy(pcm->name, "SAA7134 PCM");
+ strscpy(pcm->name, "SAA7134 PCM", sizeof(pcm->name));
return 0;
}
@@ -1074,7 +1074,7 @@ static int snd_card_saa7134_new_mixer(snd_card_saa7134_t * chip)
unsigned int idx;
int err, addr;
- strcpy(card->mixername, "SAA7134 Mixer");
+ strscpy(card->mixername, "SAA7134 Mixer", sizeof(card->mixername));
for (idx = 0; idx < ARRAY_SIZE(snd_saa7134_volume_controls); idx++) {
kcontrol = snd_ctl_new1(&snd_saa7134_volume_controls[idx],
@@ -1138,7 +1138,7 @@ static int alsa_card_saa7134_create(struct saa7134_dev *dev, int devnum)
if (err < 0)
return err;
- strcpy(card->driver, "SAA7134");
+ strscpy(card->driver, "SAA7134", sizeof(card->driver));
/* Card "creation" */
@@ -1178,7 +1178,7 @@ static int alsa_card_saa7134_create(struct saa7134_dev *dev, int devnum)
/* End of "creation" */
- strcpy(card->shortname, "SAA7134");
+ strscpy(card->shortname, "SAA7134", sizeof(card->shortname));
sprintf(card->longname, "%s at 0x%lx irq %d",
chip->dev->name, chip->iobase, chip->irq);
diff --git a/drivers/media/pci/saa7134/saa7134-cards.c b/drivers/media/pci/saa7134/saa7134-cards.c
index 9d6688a82b50..40ce033cb884 100644
--- a/drivers/media/pci/saa7134/saa7134-cards.c
+++ b/drivers/media/pci/saa7134/saa7134-cards.c
@@ -3628,6 +3628,21 @@ struct saa7134_board saa7134_boards[] = {
.vmux = 1,
.amux = TV,
.gpio = 0x0200000,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE2,
+ .gpio = 0x0200000,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE2,
+ .vmux = 0,
+ .amux = LINE2,
+ .gpio = 0x0200000,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ .gpio = 0x0200000,
}},
},
[SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA] = {
diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c
index 9e76de2411ae..8984b1bf57a5 100644
--- a/drivers/media/pci/saa7134/saa7134-core.c
+++ b/drivers/media/pci/saa7134/saa7134-core.c
@@ -845,12 +845,13 @@ static void saa7134_create_entities(struct saa7134_dev *dev)
*/
if (!decoder) {
dev->demod.name = "saa713x";
- dev->demod_pad[DEMOD_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK;
- dev->demod_pad[DEMOD_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE;
- dev->demod_pad[DEMOD_PAD_VBI_OUT].flags = MEDIA_PAD_FL_SOURCE;
+ dev->demod_pad[SAA7134_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK;
+ dev->demod_pad[SAA7134_PAD_IF_INPUT].sig_type = PAD_SIGNAL_ANALOG;
+ dev->demod_pad[SAA7134_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE;
+ dev->demod_pad[SAA7134_PAD_VID_OUT].sig_type = PAD_SIGNAL_DV;
dev->demod.function = MEDIA_ENT_F_ATV_DECODER;
- ret = media_entity_pads_init(&dev->demod, DEMOD_NUM_PADS,
+ ret = media_entity_pads_init(&dev->demod, SAA7134_NUM_PADS,
dev->demod_pad);
if (ret < 0)
pr_err("failed to initialize demod pad!\n");
diff --git a/drivers/media/pci/saa7134/saa7134-empress.c b/drivers/media/pci/saa7134/saa7134-empress.c
index 66acfd35ffc6..9735bbb908e3 100644
--- a/drivers/media/pci/saa7134/saa7134-empress.c
+++ b/drivers/media/pci/saa7134/saa7134-empress.c
@@ -100,7 +100,7 @@ static int empress_enum_fmt_vid_cap(struct file *file, void *priv,
if (f->index != 0)
return -EINVAL;
- strlcpy(f->description, "MPEG TS", sizeof(f->description));
+ strscpy(f->description, "MPEG TS", sizeof(f->description));
f->pixelformat = V4L2_PIX_FMT_MPEG;
f->flags = V4L2_FMT_FLAG_COMPRESSED;
return 0;
@@ -265,9 +265,9 @@ static int empress_init(struct saa7134_dev *dev)
"%s empress (%s)", dev->name,
saa7134_boards[dev->board].name);
v4l2_ctrl_handler_init(hdl, 21);
- v4l2_ctrl_add_handler(hdl, &dev->ctrl_handler, empress_ctrl_filter);
+ v4l2_ctrl_add_handler(hdl, &dev->ctrl_handler, empress_ctrl_filter, false);
if (dev->empress_sd)
- v4l2_ctrl_add_handler(hdl, dev->empress_sd->ctrl_handler, NULL);
+ v4l2_ctrl_add_handler(hdl, dev->empress_sd->ctrl_handler, NULL, true);
if (hdl->error) {
video_device_release(dev->empress_dev);
return hdl->error;
diff --git a/drivers/media/pci/saa7134/saa7134-go7007.c b/drivers/media/pci/saa7134/saa7134-go7007.c
index 2799538e2d7e..275c5e151818 100644
--- a/drivers/media/pci/saa7134/saa7134-go7007.c
+++ b/drivers/media/pci/saa7134/saa7134-go7007.c
@@ -435,7 +435,7 @@ static int saa7134_go7007_init(struct saa7134_dev *dev)
go->board_id = GO7007_BOARDID_PCI_VOYAGER;
snprintf(go->bus_info, sizeof(go->bus_info), "PCI:%s", pci_name(dev->pci));
- strlcpy(go->name, saa7134_boards[dev->board].name, sizeof(go->name));
+ strscpy(go->name, saa7134_boards[dev->board].name, sizeof(go->name));
go->hpi_ops = &saa7134_go7007_hpi_ops;
go->hpi_context = saa;
saa->dev = dev;
diff --git a/drivers/media/pci/saa7134/saa7134-i2c.c b/drivers/media/pci/saa7134/saa7134-i2c.c
index cf1e526de56a..51af3310654c 100644
--- a/drivers/media/pci/saa7134/saa7134-i2c.c
+++ b/drivers/media/pci/saa7134/saa7134-i2c.c
@@ -437,7 +437,7 @@ int saa7134_i2c_register(struct saa7134_dev *dev)
{
dev->i2c_adap = saa7134_adap_template;
dev->i2c_adap.dev.parent = &dev->pci->dev;
- strcpy(dev->i2c_adap.name,dev->name);
+ strscpy(dev->i2c_adap.name, dev->name, sizeof(dev->i2c_adap.name));
dev->i2c_adap.algo_data = dev;
i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
i2c_add_adapter(&dev->i2c_adap);
diff --git a/drivers/media/pci/saa7134/saa7134-input.c b/drivers/media/pci/saa7134/saa7134-input.c
index 0e28c5021ac4..999b2774b220 100644
--- a/drivers/media/pci/saa7134/saa7134-input.c
+++ b/drivers/media/pci/saa7134/saa7134-input.c
@@ -953,7 +953,7 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
memset(&info, 0, sizeof(struct i2c_board_info));
memset(&dev->init_data, 0, sizeof(dev->init_data));
- strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+ strscpy(info.type, "ir_video", I2C_NAME_SIZE);
switch (dev->board) {
case SAA7134_BOARD_PINNACLE_PCTV_110i:
diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c
index 1a50ec9d084f..8f28741ebb35 100644
--- a/drivers/media/pci/saa7134/saa7134-video.c
+++ b/drivers/media/pci/saa7134/saa7134-video.c
@@ -1445,7 +1445,8 @@ int saa7134_enum_input(struct file *file, void *priv, struct v4l2_input *i)
if (card_in(dev, i->index).type == SAA7134_NO_INPUT)
return -EINVAL;
i->index = n;
- strcpy(i->name, saa7134_input_name[card_in(dev, n).type]);
+ strscpy(i->name, saa7134_input_name[card_in(dev, n).type],
+ sizeof(i->name));
switch (card_in(dev, n).type) {
case SAA7134_INPUT_TV:
case SAA7134_INPUT_TV_MONO:
@@ -1502,8 +1503,8 @@ int saa7134_querycap(struct file *file, void *priv,
unsigned int tuner_type = dev->tuner_type;
- strcpy(cap->driver, "saa7134");
- strlcpy(cap->card, saa7134_boards[dev->board].name,
+ strscpy(cap->driver, "saa7134", sizeof(cap->driver));
+ strscpy(cap->card, saa7134_boards[dev->board].name,
sizeof(cap->card));
sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
@@ -1747,7 +1748,7 @@ int saa7134_g_tuner(struct file *file, void *priv,
if (n == SAA7134_INPUT_MAX)
return -EINVAL;
if (card_in(dev, n).type != SAA7134_NO_INPUT) {
- strcpy(t->name, "Television");
+ strscpy(t->name, "Television", sizeof(t->name));
t->type = V4L2_TUNER_ANALOG_TV;
saa_call_all(dev, tuner, g_tuner, t);
t->capability = V4L2_TUNER_CAP_NORM |
@@ -1819,7 +1820,7 @@ static int saa7134_enum_fmt_vid_cap(struct file *file, void *priv,
if (f->index >= FORMATS)
return -EINVAL;
- strlcpy(f->description, formats[f->index].name,
+ strscpy(f->description, formats[f->index].name,
sizeof(f->description));
f->pixelformat = formats[f->index].fourcc;
@@ -1838,7 +1839,7 @@ static int saa7134_enum_fmt_vid_overlay(struct file *file, void *priv,
if ((f->index >= FORMATS) || formats[f->index].planar)
return -EINVAL;
- strlcpy(f->description, formats[f->index].name,
+ strscpy(f->description, formats[f->index].name,
sizeof(f->description));
f->pixelformat = formats[f->index].fourcc;
@@ -1939,7 +1940,7 @@ static int radio_g_tuner(struct file *file, void *priv,
if (0 != t->index)
return -EINVAL;
- strcpy(t->name, "Radio");
+ strscpy(t->name, "Radio", sizeof(t->name));
saa_call_all(dev, tuner, g_tuner, t);
t->audmode &= V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO;
@@ -2136,7 +2137,7 @@ int saa7134_video_init1(struct saa7134_dev *dev)
hdl = &dev->radio_ctrl_handler;
v4l2_ctrl_handler_init(hdl, 2);
v4l2_ctrl_add_handler(hdl, &dev->ctrl_handler,
- v4l2_ctrl_radio_filter);
+ v4l2_ctrl_radio_filter, false);
if (hdl->error)
return hdl->error;
}
diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h
index d99e937a98c1..480228456014 100644
--- a/drivers/media/pci/saa7134/saa7134.h
+++ b/drivers/media/pci/saa7134/saa7134.h
@@ -547,6 +547,12 @@ struct saa7134_mpeg_ops {
unsigned long status);
};
+enum saa7134_pads {
+ SAA7134_PAD_IF_INPUT,
+ SAA7134_PAD_VID_OUT,
+ SAA7134_NUM_PADS
+};
+
/* global device status */
struct saa7134_dev {
struct list_head devlist;
@@ -674,7 +680,7 @@ struct saa7134_dev {
struct media_pad input_pad[SAA7134_INPUT_MAX + 1];
struct media_entity demod;
- struct media_pad demod_pad[DEMOD_NUM_PADS];
+ struct media_pad demod_pad[SAA7134_NUM_PADS];
struct media_pad video_pad, vbi_pad;
struct media_entity *decoder;
diff --git a/drivers/media/pci/saa7146/mxb.c b/drivers/media/pci/saa7146/mxb.c
index 6b5582b7c595..44440c6208df 100644
--- a/drivers/media/pci/saa7146/mxb.c
+++ b/drivers/media/pci/saa7146/mxb.c
@@ -553,7 +553,7 @@ static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
DEB_EE("VIDIOC_G_TUNER: %d\n", t->index);
memset(t, 0, sizeof(*t));
- strlcpy(t->name, "TV Tuner", sizeof(t->name));
+ strscpy(t->name, "TV Tuner", sizeof(t->name));
t->type = V4L2_TUNER_ANALOG_TV;
t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO |
V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
diff --git a/drivers/media/pci/saa7164/saa7164-core.c b/drivers/media/pci/saa7164/saa7164-core.c
index d697e1ad929c..f33349e16359 100644
--- a/drivers/media/pci/saa7164/saa7164-core.c
+++ b/drivers/media/pci/saa7164/saa7164-core.c
@@ -179,7 +179,7 @@ static void saa7164_histogram_reset(struct saa7164_histogram *hg, char *name)
int i;
memset(hg, 0, sizeof(struct saa7164_histogram));
- strcpy(hg->name, name);
+ strscpy(hg->name, name, sizeof(hg->name));
/* First 30ms x 1ms */
for (i = 0; i < 30; i++)
diff --git a/drivers/media/pci/saa7164/saa7164-dvb.c b/drivers/media/pci/saa7164/saa7164-dvb.c
index 4f9f03c3b252..dfb118d7d1ec 100644
--- a/drivers/media/pci/saa7164/saa7164-dvb.c
+++ b/drivers/media/pci/saa7164/saa7164-dvb.c
@@ -120,7 +120,7 @@ static int si2157_attach(struct saa7164_port *port, struct i2c_adapter *adapter,
memset(&bi, 0, sizeof(bi));
- strlcpy(bi.type, "si2157", I2C_NAME_SIZE);
+ strscpy(bi.type, "si2157", I2C_NAME_SIZE);
bi.platform_data = cfg;
bi.addr = addr8bit >> 1;
@@ -643,7 +643,7 @@ int saa7164_dvb_register(struct saa7164_port *port)
si2168_config.fe = &port->dvb.frontend;
si2168_config.ts_mode = SI2168_TS_SERIAL;
memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "si2168", I2C_NAME_SIZE);
+ strscpy(info.type, "si2168", I2C_NAME_SIZE);
info.addr = 0xc8 >> 1;
info.platform_data = &si2168_config;
request_module(info.type);
@@ -663,7 +663,7 @@ int saa7164_dvb_register(struct saa7164_port *port)
si2157_config.if_port = 1;
si2157_config.fe = port->dvb.frontend;
memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "si2157", I2C_NAME_SIZE);
+ strscpy(info.type, "si2157", I2C_NAME_SIZE);
info.addr = 0xc0 >> 1;
info.platform_data = &si2157_config;
request_module(info.type);
@@ -688,7 +688,7 @@ int saa7164_dvb_register(struct saa7164_port *port)
si2168_config.fe = &port->dvb.frontend;
si2168_config.ts_mode = SI2168_TS_SERIAL;
memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "si2168", I2C_NAME_SIZE);
+ strscpy(info.type, "si2168", I2C_NAME_SIZE);
info.addr = 0xcc >> 1;
info.platform_data = &si2168_config;
request_module(info.type);
@@ -708,7 +708,7 @@ int saa7164_dvb_register(struct saa7164_port *port)
si2157_config.fe = port->dvb.frontend;
si2157_config.if_port = 1;
memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "si2157", I2C_NAME_SIZE);
+ strscpy(info.type, "si2157", I2C_NAME_SIZE);
info.addr = 0xc0 >> 1;
info.platform_data = &si2157_config;
request_module(info.type);
diff --git a/drivers/media/pci/saa7164/saa7164-encoder.c b/drivers/media/pci/saa7164/saa7164-encoder.c
index 32136ebe4f61..adec2bab8352 100644
--- a/drivers/media/pci/saa7164/saa7164-encoder.c
+++ b/drivers/media/pci/saa7164/saa7164-encoder.c
@@ -258,7 +258,7 @@ int saa7164_enum_input(struct file *file, void *priv, struct v4l2_input *i)
if (i->index >= 7)
return -EINVAL;
- strcpy(i->name, inputs[i->index]);
+ strscpy(i->name, inputs[i->index], sizeof(i->name));
if (i->index == 0)
i->type = V4L2_INPUT_TYPE_TUNER;
@@ -325,7 +325,7 @@ int saa7164_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
if (0 != t->index)
return -EINVAL;
- strcpy(t->name, "tuner");
+ strscpy(t->name, "tuner", sizeof(t->name));
t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO;
t->rangelow = SAA7164_TV_MIN_FREQ;
t->rangehigh = SAA7164_TV_MAX_FREQ;
@@ -497,8 +497,8 @@ static int vidioc_querycap(struct file *file, void *priv,
struct saa7164_port *port = fh->port;
struct saa7164_dev *dev = port->dev;
- strcpy(cap->driver, dev->name);
- strlcpy(cap->card, saa7164_boards[dev->board].name,
+ strscpy(cap->driver, dev->name, sizeof(cap->driver));
+ strscpy(cap->card, saa7164_boards[dev->board].name,
sizeof(cap->card));
sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
@@ -520,7 +520,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
if (f->index != 0)
return -EINVAL;
- strlcpy(f->description, "MPEG", sizeof(f->description));
+ strscpy(f->description, "MPEG", sizeof(f->description));
f->pixelformat = V4L2_PIX_FMT_MPEG;
return 0;
diff --git a/drivers/media/pci/saa7164/saa7164-i2c.c b/drivers/media/pci/saa7164/saa7164-i2c.c
index 6d13cbb9d010..317f48bc6506 100644
--- a/drivers/media/pci/saa7164/saa7164-i2c.c
+++ b/drivers/media/pci/saa7164/saa7164-i2c.c
@@ -99,7 +99,7 @@ int saa7164_i2c_register(struct saa7164_i2c *bus)
bus->i2c_adap.dev.parent = &dev->pci->dev;
- strlcpy(bus->i2c_adap.name, bus->dev->name,
+ strscpy(bus->i2c_adap.name, bus->dev->name,
sizeof(bus->i2c_adap.name));
bus->i2c_adap.algo_data = bus;
diff --git a/drivers/media/pci/saa7164/saa7164-vbi.c b/drivers/media/pci/saa7164/saa7164-vbi.c
index 221de91a8bae..841c7e94405d 100644
--- a/drivers/media/pci/saa7164/saa7164-vbi.c
+++ b/drivers/media/pci/saa7164/saa7164-vbi.c
@@ -208,8 +208,8 @@ static int vidioc_querycap(struct file *file, void *priv,
struct saa7164_port *port = fh->port;
struct saa7164_dev *dev = port->dev;
- strcpy(cap->driver, dev->name);
- strlcpy(cap->card, saa7164_boards[dev->board].name,
+ strscpy(cap->driver, dev->name, sizeof(cap->driver));
+ strscpy(cap->card, saa7164_boards[dev->board].name,
sizeof(cap->card));
sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
diff --git a/drivers/media/pci/smipcie/smipcie-main.c b/drivers/media/pci/smipcie/smipcie-main.c
index 6dbe3b4d09ce..4d5ddbcb3514 100644
--- a/drivers/media/pci/smipcie/smipcie-main.c
+++ b/drivers/media/pci/smipcie/smipcie-main.c
@@ -191,7 +191,7 @@ static int smi_i2c_init(struct smi_dev *dev)
/* i2c bus 0 */
smi_i2c_cfg(dev, I2C_A_SW_CTL);
i2c_set_adapdata(&dev->i2c_bus[0], dev);
- strcpy(dev->i2c_bus[0].name, "SMI-I2C0");
+ strscpy(dev->i2c_bus[0].name, "SMI-I2C0", sizeof(dev->i2c_bus[0].name));
dev->i2c_bus[0].owner = THIS_MODULE;
dev->i2c_bus[0].dev.parent = &dev->pci_dev->dev;
dev->i2c_bus[0].algo_data = &dev->i2c_bit[0];
@@ -213,7 +213,7 @@ static int smi_i2c_init(struct smi_dev *dev)
/* i2c bus 1 */
smi_i2c_cfg(dev, I2C_B_SW_CTL);
i2c_set_adapdata(&dev->i2c_bus[1], dev);
- strcpy(dev->i2c_bus[1].name, "SMI-I2C1");
+ strscpy(dev->i2c_bus[1].name, "SMI-I2C1", sizeof(dev->i2c_bus[1].name));
dev->i2c_bus[1].owner = THIS_MODULE;
dev->i2c_bus[1].dev.parent = &dev->pci_dev->dev;
dev->i2c_bus[1].algo_data = &dev->i2c_bit[1];
@@ -549,7 +549,7 @@ static int smi_dvbsky_m88ds3103_fe_attach(struct smi_port *port)
}
/* attach tuner */
ts2020_config.fe = port->fe;
- strlcpy(tuner_info.type, "ts2020", I2C_NAME_SIZE);
+ strscpy(tuner_info.type, "ts2020", I2C_NAME_SIZE);
tuner_info.addr = 0x60;
tuner_info.platform_data = &ts2020_config;
tuner_client = smi_add_i2c_client(tuner_i2c_adapter, &tuner_info);
@@ -605,7 +605,7 @@ static int smi_dvbsky_m88rs6000_fe_attach(struct smi_port *port)
}
/* attach tuner */
m88rs6000t_config.fe = port->fe;
- strlcpy(tuner_info.type, "m88rs6000t", I2C_NAME_SIZE);
+ strscpy(tuner_info.type, "m88rs6000t", I2C_NAME_SIZE);
tuner_info.addr = 0x21;
tuner_info.platform_data = &m88rs6000t_config;
tuner_client = smi_add_i2c_client(tuner_i2c_adapter, &tuner_info);
@@ -647,7 +647,7 @@ static int smi_dvbsky_sit2_fe_attach(struct smi_port *port)
si2168_config.ts_mode = SI2168_TS_PARALLEL;
memset(&client_info, 0, sizeof(struct i2c_board_info));
- strlcpy(client_info.type, "si2168", I2C_NAME_SIZE);
+ strscpy(client_info.type, "si2168", I2C_NAME_SIZE);
client_info.addr = 0x64;
client_info.platform_data = &si2168_config;
@@ -664,7 +664,7 @@ static int smi_dvbsky_sit2_fe_attach(struct smi_port *port)
si2157_config.if_port = 1;
memset(&client_info, 0, sizeof(struct i2c_board_info));
- strlcpy(client_info.type, "si2157", I2C_NAME_SIZE);
+ strscpy(client_info.type, "si2157", I2C_NAME_SIZE);
client_info.addr = 0x60;
client_info.platform_data = &si2157_config;
diff --git a/drivers/media/pci/solo6x10/solo6x10-g723.c b/drivers/media/pci/solo6x10/solo6x10-g723.c
index 2ac33b5cc454..2cc05a9d57ac 100644
--- a/drivers/media/pci/solo6x10/solo6x10-g723.c
+++ b/drivers/media/pci/solo6x10/solo6x10-g723.c
@@ -354,7 +354,7 @@ static int solo_snd_pcm_init(struct solo_dev *solo_dev)
snd_pcm_chip(pcm) = solo_dev;
pcm->info_flags = 0;
- strcpy(pcm->name, card->shortname);
+ strscpy(pcm->name, card->shortname, sizeof(pcm->name));
for (i = 0, ss = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
ss; ss = ss->next, i++)
@@ -394,8 +394,8 @@ int solo_g723_init(struct solo_dev *solo_dev)
card = solo_dev->snd_card;
- strcpy(card->driver, SOLO6X10_NAME);
- strcpy(card->shortname, "SOLO-6x10 Audio");
+ strscpy(card->driver, SOLO6X10_NAME, sizeof(card->driver));
+ strscpy(card->shortname, "SOLO-6x10 Audio", sizeof(card->shortname));
sprintf(card->longname, "%s on %s IRQ %d", card->shortname,
pci_name(solo_dev->pdev), solo_dev->pdev->irq);
@@ -404,7 +404,7 @@ int solo_g723_init(struct solo_dev *solo_dev)
goto snd_error;
/* Mixer controls */
- strcpy(card->mixername, "SOLO-6x10");
+ strscpy(card->mixername, "SOLO-6x10", sizeof(card->mixername));
kctl = snd_solo_capture_volume;
kctl.count = solo_dev->nr_chans;
diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c
index 25f9f2ebff1d..9d27e7463070 100644
--- a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c
+++ b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c
@@ -775,7 +775,7 @@ static int solo_enc_querycap(struct file *file, void *priv,
struct solo_enc_dev *solo_enc = video_drvdata(file);
struct solo_dev *solo_dev = solo_enc->solo_dev;
- strcpy(cap->driver, SOLO6X10_NAME);
+ strscpy(cap->driver, SOLO6X10_NAME, sizeof(cap->driver));
snprintf(cap->card, sizeof(cap->card), "Softlogic 6x10 Enc %d",
solo_enc->ch);
snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
@@ -834,17 +834,18 @@ static int solo_enc_enum_fmt_cap(struct file *file, void *priv,
switch (dev_type) {
case SOLO_DEV_6010:
f->pixelformat = V4L2_PIX_FMT_MPEG4;
- strcpy(f->description, "MPEG-4 part 2");
+ strscpy(f->description, "MPEG-4 part 2",
+ sizeof(f->description));
break;
case SOLO_DEV_6110:
f->pixelformat = V4L2_PIX_FMT_H264;
- strcpy(f->description, "H.264");
+ strscpy(f->description, "H.264", sizeof(f->description));
break;
}
break;
case 1:
f->pixelformat = V4L2_PIX_FMT_MJPEG;
- strcpy(f->description, "MJPEG");
+ strscpy(f->description, "MJPEG", sizeof(f->description));
break;
default:
return -EINVAL;
@@ -1126,7 +1127,8 @@ static int solo_s_ctrl(struct v4l2_ctrl *ctrl)
solo_enc->md_thresholds->p_new.p_u16);
break;
case V4L2_CID_OSD_TEXT:
- strcpy(solo_enc->osd_text, ctrl->p_new.p_char);
+ strscpy(solo_enc->osd_text, ctrl->p_new.p_char,
+ sizeof(solo_enc->osd_text));
return solo_osd_print(solo_enc);
default:
return -EINVAL;
diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2.c b/drivers/media/pci/solo6x10/solo6x10-v4l2.c
index 99ffd1ed4a73..69fc939fd3d9 100644
--- a/drivers/media/pci/solo6x10/solo6x10-v4l2.c
+++ b/drivers/media/pci/solo6x10/solo6x10-v4l2.c
@@ -383,8 +383,8 @@ static int solo_querycap(struct file *file, void *priv,
{
struct solo_dev *solo_dev = video_drvdata(file);
- strcpy(cap->driver, SOLO6X10_NAME);
- strcpy(cap->card, "Softlogic 6x10");
+ strscpy(cap->driver, SOLO6X10_NAME, sizeof(cap->driver));
+ strscpy(cap->card, "Softlogic 6x10", sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
pci_name(solo_dev->pdev));
cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
@@ -470,7 +470,7 @@ static int solo_enum_fmt_cap(struct file *file, void *priv,
return -EINVAL;
f->pixelformat = V4L2_PIX_FMT_UYVY;
- strlcpy(f->description, "UYUV 4:2:2 Packed", sizeof(f->description));
+ strscpy(f->description, "UYUV 4:2:2 Packed", sizeof(f->description));
return 0;
}
diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c
index 1858efedaf1a..411177ec4d72 100644
--- a/drivers/media/pci/sta2x11/sta2x11_vip.c
+++ b/drivers/media/pci/sta2x11/sta2x11_vip.c
@@ -419,8 +419,8 @@ static int vidioc_querycap(struct file *file, void *priv,
{
struct sta2x11_vip *vip = video_drvdata(file);
- strcpy(cap->driver, KBUILD_MODNAME);
- strcpy(cap->card, KBUILD_MODNAME);
+ strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
+ strscpy(cap->card, KBUILD_MODNAME, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
pci_name(vip->pdev));
cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
@@ -580,7 +580,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
if (f->index != 0)
return -EINVAL;
- strcpy(f->description, "4:2:2, packed, UYVY");
+ strscpy(f->description, "4:2:2, packed, UYVY", sizeof(f->description));
f->pixelformat = V4L2_PIX_FMT_UYVY;
f->flags = 0;
return 0;
diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c
index d6816effb878..409defc75c05 100644
--- a/drivers/media/pci/ttpci/av7110.c
+++ b/drivers/media/pci/ttpci/av7110.c
@@ -2482,7 +2482,8 @@ static int av7110_attach(struct saa7146_dev* dev,
get recognized before the main driver is fully loaded */
saa7146_write(dev, GPIO_CTRL, 0x500000);
- strlcpy(av7110->i2c_adap.name, pci_ext->ext_priv, sizeof(av7110->i2c_adap.name));
+ strscpy(av7110->i2c_adap.name, pci_ext->ext_priv,
+ sizeof(av7110->i2c_adap.name));
saa7146_i2c_adapter_prepare(dev, &av7110->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120); /* 275 kHz */
diff --git a/drivers/media/pci/ttpci/av7110_av.c b/drivers/media/pci/ttpci/av7110_av.c
index ef1bc17cdc4d..1073e4671b68 100644
--- a/drivers/media/pci/ttpci/av7110_av.c
+++ b/drivers/media/pci/ttpci/av7110_av.c
@@ -932,7 +932,6 @@ static int dvb_video_get_event (struct av7110 *av7110, struct video_event *event
return 0;
}
-
/******************************************************************************
* DVB device file operations
******************************************************************************/
@@ -1095,6 +1094,42 @@ static int play_iframe(struct av7110 *av7110, char __user *buf, unsigned int len
return 0;
}
+#ifdef CONFIG_COMPAT
+struct compat_video_still_picture {
+ compat_uptr_t iFrame;
+ int32_t size;
+};
+#define VIDEO_STILLPICTURE32 _IOW('o', 30, struct compat_video_still_picture)
+
+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)
+
+static int dvb_compat_video_get_event(struct av7110 *av7110,
+ struct compat_video_event *event, int flags)
+{
+ struct video_event ev;
+ int ret;
+
+ ret = dvb_video_get_event(av7110, &ev, flags);
+
+ *event = (struct compat_video_event) {
+ .type = ev.type,
+ .timestamp = ev.timestamp,
+ .u.size = ev.u.size,
+ };
+
+ return ret;
+}
+#endif
static int dvb_video_ioctl(struct file *file,
unsigned int cmd, void *parg)
@@ -1184,6 +1219,12 @@ static int dvb_video_ioctl(struct file *file,
memcpy(parg, &av7110->videostate, sizeof(struct video_status));
break;
+#ifdef CONFIG_COMPAT
+ case VIDEO_GET_EVENT32:
+ ret = dvb_compat_video_get_event(av7110, parg, file->f_flags);
+ break;
+#endif
+
case VIDEO_GET_EVENT:
ret = dvb_video_get_event(av7110, parg, file->f_flags);
break;
@@ -1226,6 +1267,19 @@ static int dvb_video_ioctl(struct file *file,
1, (u16) arg);
break;
+#ifdef CONFIG_COMPAT
+ case VIDEO_STILLPICTURE32:
+ {
+ struct compat_video_still_picture *pic =
+ (struct compat_video_still_picture *) parg;
+ av7110->videostate.stream_source = VIDEO_SOURCE_MEMORY;
+ dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout);
+ ret = play_iframe(av7110, compat_ptr(pic->iFrame),
+ pic->size, file->f_flags & O_NONBLOCK);
+ break;
+ }
+#endif
+
case VIDEO_STILLPICTURE:
{
struct video_still_picture *pic =
@@ -1533,6 +1587,7 @@ static const struct file_operations dvb_video_fops = {
.owner = THIS_MODULE,
.write = dvb_video_write,
.unlocked_ioctl = dvb_generic_ioctl,
+ .compat_ioctl = dvb_generic_ioctl,
.open = dvb_video_open,
.release = dvb_video_release,
.poll = dvb_video_poll,
@@ -1552,6 +1607,7 @@ static const struct file_operations dvb_audio_fops = {
.owner = THIS_MODULE,
.write = dvb_audio_write,
.unlocked_ioctl = dvb_generic_ioctl,
+ .compat_ioctl = dvb_generic_ioctl,
.open = dvb_audio_open,
.release = dvb_audio_release,
.poll = dvb_audio_poll,
diff --git a/drivers/media/pci/ttpci/av7110_v4l.c b/drivers/media/pci/ttpci/av7110_v4l.c
index e4cf42c32284..d1fe15365f4a 100644
--- a/drivers/media/pci/ttpci/av7110_v4l.c
+++ b/drivers/media/pci/ttpci/av7110_v4l.c
@@ -332,7 +332,7 @@ static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
return -EINVAL;
memset(t, 0, sizeof(*t));
- strcpy((char *)t->name, "Television");
+ strscpy((char *)t->name, "Television", sizeof(t->name));
t->type = V4L2_TUNER_ANALOG_TV;
t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO |
diff --git a/drivers/media/pci/ttpci/budget-core.c b/drivers/media/pci/ttpci/budget-core.c
index b3dc45b91101..35b696bdb2df 100644
--- a/drivers/media/pci/ttpci/budget-core.c
+++ b/drivers/media/pci/ttpci/budget-core.c
@@ -504,10 +504,12 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
if (bi->type != BUDGET_FS_ACTIVY)
saa7146_write(dev, GPIO_CTRL, 0x500000); /* GPIO 3 = 1 */
- strlcpy(budget->i2c_adap.name, budget->card->name, sizeof(budget->i2c_adap.name));
+ strscpy(budget->i2c_adap.name, budget->card->name,
+ sizeof(budget->i2c_adap.name));
saa7146_i2c_adapter_prepare(dev, &budget->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120);
- strcpy(budget->i2c_adap.name, budget->card->name);
+ strscpy(budget->i2c_adap.name, budget->card->name,
+ sizeof(budget->i2c_adap.name));
if (i2c_add_adapter(&budget->i2c_adap) < 0) {
ret = -ENOMEM;
diff --git a/drivers/media/pci/tw5864/tw5864-video.c b/drivers/media/pci/tw5864/tw5864-video.c
index ff2b7da90c08..5a1f3aa4101a 100644
--- a/drivers/media/pci/tw5864/tw5864-video.c
+++ b/drivers/media/pci/tw5864/tw5864-video.c
@@ -610,7 +610,7 @@ static int tw5864_querycap(struct file *file, void *priv,
{
struct tw5864_input *input = video_drvdata(file);
- strcpy(cap->driver, "tw5864");
+ strscpy(cap->driver, "tw5864", sizeof(cap->driver));
snprintf(cap->card, sizeof(cap->card), "TW5864 Encoder %d",
input->nr);
sprintf(cap->bus_info, "PCI:%s", pci_name(input->root->pci));
diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c
index 8c1f4a049764..d3f727045ae8 100644
--- a/drivers/media/pci/tw68/tw68-video.c
+++ b/drivers/media/pci/tw68/tw68-video.c
@@ -734,8 +734,8 @@ static int tw68_querycap(struct file *file, void *priv,
{
struct tw68_dev *dev = video_drvdata(file);
- strcpy(cap->driver, "tw68");
- strlcpy(cap->card, "Techwell Capture Card",
+ strscpy(cap->driver, "tw68", sizeof(cap->driver));
+ strscpy(cap->card, "Techwell Capture Card",
sizeof(cap->card));
sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
cap->device_caps =
@@ -789,7 +789,7 @@ static int tw68_enum_fmt_vid_cap(struct file *file, void *priv,
if (f->index >= FORMATS)
return -EINVAL;
- strlcpy(f->description, formats[f->index].name,
+ strscpy(f->description, formats[f->index].name,
sizeof(f->description));
f->pixelformat = formats[f->index].fourcc;
diff --git a/drivers/media/pci/tw686x/tw686x-audio.c b/drivers/media/pci/tw686x/tw686x-audio.c
index 77190768622a..a28329698e20 100644
--- a/drivers/media/pci/tw686x/tw686x-audio.c
+++ b/drivers/media/pci/tw686x/tw686x-audio.c
@@ -295,7 +295,7 @@ static int tw686x_snd_pcm_init(struct tw686x_dev *dev)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &tw686x_pcm_ops);
snd_pcm_chip(pcm) = dev;
pcm->info_flags = 0;
- strlcpy(pcm->name, "tw686x PCM", sizeof(pcm->name));
+ strscpy(pcm->name, "tw686x PCM", sizeof(pcm->name));
for (i = 0, ss = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
ss; ss = ss->next, i++)
@@ -390,9 +390,9 @@ int tw686x_audio_init(struct tw686x_dev *dev)
return err;
dev->snd_card = card;
- strlcpy(card->driver, "tw686x", sizeof(card->driver));
- strlcpy(card->shortname, "tw686x", sizeof(card->shortname));
- strlcpy(card->longname, pci_name(pci_dev), sizeof(card->longname));
+ strscpy(card->driver, "tw686x", sizeof(card->driver));
+ strscpy(card->shortname, "tw686x", sizeof(card->shortname));
+ strscpy(card->longname, pci_name(pci_dev), sizeof(card->longname));
snd_card_set_dev(card, &pci_dev->dev);
for (ch = 0; ch < max_channels(dev); ch++) {
diff --git a/drivers/media/pci/tw686x/tw686x-video.c b/drivers/media/pci/tw686x/tw686x-video.c
index 3a06c000f97b..4890b7f1248b 100644
--- a/drivers/media/pci/tw686x/tw686x-video.c
+++ b/drivers/media/pci/tw686x/tw686x-video.c
@@ -765,8 +765,8 @@ static int tw686x_querycap(struct file *file, void *priv,
struct tw686x_video_channel *vc = video_drvdata(file);
struct tw686x_dev *dev = vc->dev;
- strlcpy(cap->driver, "tw686x", sizeof(cap->driver));
- strlcpy(cap->card, dev->name, sizeof(cap->card));
+ strscpy(cap->driver, "tw686x", sizeof(cap->driver));
+ strscpy(cap->card, dev->name, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info),
"PCI:%s", pci_name(dev->pci_dev));
cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 54fe90acb5b2..70c4f6c54881 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -58,6 +58,7 @@ config VIDEO_MUX
select MULTIPLEXER
depends on VIDEO_V4L2 && OF && VIDEO_V4L2_SUBDEV_API && MEDIA_CONTROLLER
select REGMAP
+ select V4L2_FWNODE
help
This driver provides support for N:1 video bus multiplexers.
@@ -181,6 +182,15 @@ config VIDEO_CODA
config VIDEO_IMX_VDOA
def_tristate VIDEO_CODA if SOC_IMX6Q || COMPILE_TEST
+config VIDEO_IMX_PXP
+ tristate "i.MX Pixel Pipeline (PXP)"
+ depends on VIDEO_DEV && VIDEO_V4L2 && (ARCH_MXC || COMPILE_TEST)
+ select VIDEOBUF2_DMA_CONTIG
+ select V4L2_MEM2MEM_DEV
+ help
+ The i.MX Pixel Pipeline is a memory-to-memory engine for scaling,
+ color space conversion, and rotation.
+
config VIDEO_MEDIATEK_JPEG
tristate "Mediatek JPEG Codec driver"
depends on MTK_IOMMU_V1 || COMPILE_TEST
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index 41322ab65802..6ab6200dd9c9 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -25,6 +25,8 @@ obj-$(CONFIG_VIDEO_TI_CAL) += ti-vpe/
obj-$(CONFIG_VIDEO_MX2_EMMAPRP) += mx2_emmaprp.o
obj-$(CONFIG_VIDEO_CODA) += coda/
+obj-$(CONFIG_VIDEO_IMX_PXP) += imx-pxp.o
+
obj-$(CONFIG_VIDEO_SH_VEU) += sh_veu.o
obj-$(CONFIG_CEC_GPIO) += cec-gpio/
diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c
index b05738a95e55..e13d2b3a7168 100644
--- a/drivers/media/platform/am437x/am437x-vpfe.c
+++ b/drivers/media/platform/am437x/am437x-vpfe.c
@@ -1408,8 +1408,8 @@ static int vpfe_querycap(struct file *file, void *priv,
vpfe_dbg(2, vpfe, "vpfe_querycap\n");
- strlcpy(cap->driver, VPFE_MODULE_NAME, sizeof(cap->driver));
- strlcpy(cap->card, "TI AM437x VPFE", sizeof(cap->card));
+ strscpy(cap->driver, VPFE_MODULE_NAME, sizeof(cap->driver));
+ strscpy(cap->card, "TI AM437x VPFE", sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info),
"platform:%s", vpfe->v4l2_dev.name);
cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
@@ -2386,7 +2386,7 @@ static int vpfe_probe_complete(struct vpfe_device *vpfe)
INIT_LIST_HEAD(&vpfe->dma_queue);
vdev = &vpfe->video_dev;
- strlcpy(vdev->name, VPFE_MODULE_NAME, sizeof(vdev->name));
+ strscpy(vdev->name, VPFE_MODULE_NAME, sizeof(vdev->name));
vdev->release = video_device_release_empty;
vdev->fops = &vpfe_fops;
vdev->ioctl_ops = &vpfe_ioctl_ops;
@@ -2423,30 +2423,32 @@ static const struct v4l2_async_notifier_operations vpfe_async_ops = {
};
static struct vpfe_config *
-vpfe_get_pdata(struct platform_device *pdev)
+vpfe_get_pdata(struct vpfe_device *vpfe)
{
struct device_node *endpoint = NULL;
- struct v4l2_fwnode_endpoint bus_cfg;
+ struct device *dev = vpfe->pdev;
struct vpfe_subdev_info *sdinfo;
struct vpfe_config *pdata;
unsigned int flags;
unsigned int i;
int err;
- dev_dbg(&pdev->dev, "vpfe_get_pdata\n");
+ dev_dbg(dev, "vpfe_get_pdata\n");
- if (!IS_ENABLED(CONFIG_OF) || !pdev->dev.of_node)
- return pdev->dev.platform_data;
+ v4l2_async_notifier_init(&vpfe->notifier);
- pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!IS_ENABLED(CONFIG_OF) || !dev->of_node)
+ return dev->platform_data;
+
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return NULL;
for (i = 0; ; i++) {
+ struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 };
struct device_node *rem;
- endpoint = of_graph_get_next_endpoint(pdev->dev.of_node,
- endpoint);
+ endpoint = of_graph_get_next_endpoint(dev->of_node, endpoint);
if (!endpoint)
break;
@@ -2455,7 +2457,8 @@ vpfe_get_pdata(struct platform_device *pdev)
/* we only support camera */
sdinfo->inputs[0].index = i;
- strcpy(sdinfo->inputs[0].name, "Camera");
+ strscpy(sdinfo->inputs[0].name, "Camera",
+ sizeof(sdinfo->inputs[0].name));
sdinfo->inputs[0].type = V4L2_INPUT_TYPE_CAMERA;
sdinfo->inputs[0].std = V4L2_STD_ALL;
sdinfo->inputs[0].capabilities = V4L2_IN_CAP_STD;
@@ -2473,16 +2476,16 @@ vpfe_get_pdata(struct platform_device *pdev)
err = v4l2_fwnode_endpoint_parse(of_fwnode_handle(endpoint),
&bus_cfg);
if (err) {
- dev_err(&pdev->dev, "Could not parse the endpoint\n");
- goto done;
+ dev_err(dev, "Could not parse the endpoint\n");
+ goto cleanup;
}
sdinfo->vpfe_param.bus_width = bus_cfg.bus.parallel.bus_width;
if (sdinfo->vpfe_param.bus_width < 8 ||
sdinfo->vpfe_param.bus_width > 16) {
- dev_err(&pdev->dev, "Invalid bus width.\n");
- goto done;
+ dev_err(dev, "Invalid bus width.\n");
+ goto cleanup;
}
flags = bus_cfg.bus.parallel.flags;
@@ -2495,29 +2498,25 @@ vpfe_get_pdata(struct platform_device *pdev)
rem = of_graph_get_remote_port_parent(endpoint);
if (!rem) {
- dev_err(&pdev->dev, "Remote device at %pOF not found\n",
+ dev_err(dev, "Remote device at %pOF not found\n",
endpoint);
- goto done;
+ goto cleanup;
}
- pdata->asd[i] = devm_kzalloc(&pdev->dev,
- sizeof(struct v4l2_async_subdev),
- GFP_KERNEL);
- if (!pdata->asd[i]) {
+ pdata->asd[i] = v4l2_async_notifier_add_fwnode_subdev(
+ &vpfe->notifier, of_fwnode_handle(rem),
+ sizeof(struct v4l2_async_subdev));
+ if (IS_ERR(pdata->asd[i])) {
of_node_put(rem);
- pdata = NULL;
- goto done;
+ goto cleanup;
}
-
- pdata->asd[i]->match_type = V4L2_ASYNC_MATCH_FWNODE;
- pdata->asd[i]->match.fwnode = of_fwnode_handle(rem);
- of_node_put(rem);
}
of_node_put(endpoint);
return pdata;
-done:
+cleanup:
+ v4l2_async_notifier_cleanup(&vpfe->notifier);
of_node_put(endpoint);
return NULL;
}
@@ -2529,34 +2528,39 @@ done:
*/
static int vpfe_probe(struct platform_device *pdev)
{
- struct vpfe_config *vpfe_cfg = vpfe_get_pdata(pdev);
+ struct vpfe_config *vpfe_cfg;
struct vpfe_device *vpfe;
struct vpfe_ccdc *ccdc;
struct resource *res;
int ret;
- if (!vpfe_cfg) {
- dev_err(&pdev->dev, "No platform data\n");
- return -EINVAL;
- }
-
vpfe = devm_kzalloc(&pdev->dev, sizeof(*vpfe), GFP_KERNEL);
if (!vpfe)
return -ENOMEM;
vpfe->pdev = &pdev->dev;
+
+ vpfe_cfg = vpfe_get_pdata(vpfe);
+ if (!vpfe_cfg) {
+ dev_err(&pdev->dev, "No platform data\n");
+ return -EINVAL;
+ }
+
vpfe->cfg = vpfe_cfg;
ccdc = &vpfe->ccdc;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ccdc->ccdc_cfg.base_addr = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(ccdc->ccdc_cfg.base_addr))
- return PTR_ERR(ccdc->ccdc_cfg.base_addr);
+ if (IS_ERR(ccdc->ccdc_cfg.base_addr)) {
+ ret = PTR_ERR(ccdc->ccdc_cfg.base_addr);
+ goto probe_out_cleanup;
+ }
ret = platform_get_irq(pdev, 0);
if (ret <= 0) {
dev_err(&pdev->dev, "No IRQ resource\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto probe_out_cleanup;
}
vpfe->irq = ret;
@@ -2564,14 +2568,15 @@ static int vpfe_probe(struct platform_device *pdev)
"vpfe_capture0", vpfe);
if (ret) {
dev_err(&pdev->dev, "Unable to request interrupt\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto probe_out_cleanup;
}
ret = v4l2_device_register(&pdev->dev, &vpfe->v4l2_dev);
if (ret) {
vpfe_err(vpfe,
"Unable to register v4l2 device.\n");
- return ret;
+ goto probe_out_cleanup;
}
/* set the driver data in platform device */
@@ -2595,11 +2600,8 @@ static int vpfe_probe(struct platform_device *pdev)
goto probe_out_v4l2_unregister;
}
- vpfe->notifier.subdevs = vpfe->cfg->asd;
- vpfe->notifier.num_subdevs = ARRAY_SIZE(vpfe->cfg->asd);
vpfe->notifier.ops = &vpfe_async_ops;
- ret = v4l2_async_notifier_register(&vpfe->v4l2_dev,
- &vpfe->notifier);
+ ret = v4l2_async_notifier_register(&vpfe->v4l2_dev, &vpfe->notifier);
if (ret) {
vpfe_err(vpfe, "Error registering async notifier\n");
ret = -EINVAL;
@@ -2610,6 +2612,8 @@ static int vpfe_probe(struct platform_device *pdev)
probe_out_v4l2_unregister:
v4l2_device_unregister(&vpfe->v4l2_dev);
+probe_out_cleanup:
+ v4l2_async_notifier_cleanup(&vpfe->notifier);
return ret;
}
@@ -2625,6 +2629,7 @@ static int vpfe_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
v4l2_async_notifier_unregister(&vpfe->notifier);
+ v4l2_async_notifier_cleanup(&vpfe->notifier);
v4l2_device_unregister(&vpfe->v4l2_dev);
video_unregister_device(&vpfe->video_dev);
diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c
index d89e14524d42..50178968b8a6 100644
--- a/drivers/media/platform/atmel/atmel-isc.c
+++ b/drivers/media/platform/atmel/atmel-isc.c
@@ -1238,8 +1238,8 @@ static int isc_querycap(struct file *file, void *priv,
{
struct isc_device *isc = video_drvdata(file);
- strcpy(cap->driver, ATMEL_ISC_NAME);
- strcpy(cap->card, "Atmel Image Sensor Controller");
+ strscpy(cap->driver, ATMEL_ISC_NAME, 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);
@@ -1393,7 +1393,7 @@ static int isc_enum_input(struct file *file, void *priv,
inp->type = V4L2_INPUT_TYPE_CAMERA;
inp->std = 0;
- strcpy(inp->name, "Camera");
+ strscpy(inp->name, "Camera", sizeof(inp->name));
return 0;
}
@@ -1951,7 +1951,7 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier)
INIT_WORK(&isc->awb_work, isc_awb_work);
/* Register video device */
- strlcpy(vdev->name, ATMEL_ISC_NAME, sizeof(vdev->name));
+ strscpy(vdev->name, ATMEL_ISC_NAME, sizeof(vdev->name));
vdev->release = video_device_release_empty;
vdev->fops = &isc_fops;
vdev->ioctl_ops = &isc_ioctl_ops;
@@ -1983,8 +1983,10 @@ static void isc_subdev_cleanup(struct isc_device *isc)
{
struct isc_subdev_entity *subdev_entity;
- list_for_each_entry(subdev_entity, &isc->subdev_entities, list)
+ list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
v4l2_async_notifier_unregister(&subdev_entity->notifier);
+ v4l2_async_notifier_cleanup(&subdev_entity->notifier);
+ }
INIT_LIST_HEAD(&isc->subdev_entities);
}
@@ -2026,7 +2028,6 @@ static int isc_parse_dt(struct device *dev, struct isc_device *isc)
{
struct device_node *np = dev->of_node;
struct device_node *epn = NULL, *rem;
- struct v4l2_fwnode_endpoint v4l2_epn;
struct isc_subdev_entity *subdev_entity;
unsigned int flags;
int ret;
@@ -2034,6 +2035,8 @@ static int isc_parse_dt(struct device *dev, struct isc_device *isc)
INIT_LIST_HEAD(&isc->subdev_entities);
while (1) {
+ struct v4l2_fwnode_endpoint v4l2_epn = { .bus_type = 0 };
+
epn = of_graph_get_next_endpoint(np, epn);
if (!epn)
return 0;
@@ -2201,8 +2204,15 @@ static int atmel_isc_probe(struct platform_device *pdev)
}
list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
- subdev_entity->notifier.subdevs = &subdev_entity->asd;
- subdev_entity->notifier.num_subdevs = 1;
+ v4l2_async_notifier_init(&subdev_entity->notifier);
+
+ ret = v4l2_async_notifier_add_subdev(&subdev_entity->notifier,
+ subdev_entity->asd);
+ if (ret) {
+ fwnode_handle_put(subdev_entity->asd->match.fwnode);
+ goto cleanup_subdev;
+ }
+
subdev_entity->notifier.ops = &isc_async_ops;
ret = v4l2_async_notifier_register(&isc->v4l2_dev,
diff --git a/drivers/media/platform/atmel/atmel-isi.c b/drivers/media/platform/atmel/atmel-isi.c
index e8db4df1e7c4..fdb255e4a956 100644
--- a/drivers/media/platform/atmel/atmel-isi.c
+++ b/drivers/media/platform/atmel/atmel-isi.c
@@ -655,9 +655,9 @@ static int isi_enum_fmt_vid_cap(struct file *file, void *priv,
static int isi_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- strlcpy(cap->driver, "atmel-isi", sizeof(cap->driver));
- strlcpy(cap->card, "Atmel Image Sensor Interface", sizeof(cap->card));
- strlcpy(cap->bus_info, "platform:isi", sizeof(cap->bus_info));
+ strscpy(cap->driver, "atmel-isi", sizeof(cap->driver));
+ strscpy(cap->card, "Atmel Image Sensor Interface", sizeof(cap->card));
+ strscpy(cap->bus_info, "platform:isi", sizeof(cap->bus_info));
return 0;
}
@@ -668,7 +668,7 @@ static int isi_enum_input(struct file *file, void *priv,
return -EINVAL;
i->type = V4L2_INPUT_TYPE_CAMERA;
- strlcpy(i->name, "Camera", sizeof(i->name));
+ strscpy(i->name, "Camera", sizeof(i->name));
return 0;
}
@@ -790,7 +790,7 @@ static int atmel_isi_parse_dt(struct atmel_isi *isi,
struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
- struct v4l2_fwnode_endpoint ep;
+ struct v4l2_fwnode_endpoint ep = { .bus_type = 0 };
int err;
/* Default settings for ISI */
@@ -1124,7 +1124,6 @@ static int isi_graph_parse(struct atmel_isi *isi, struct device_node *node)
static int isi_graph_init(struct atmel_isi *isi)
{
- struct v4l2_async_subdev **subdevs = NULL;
int ret;
/* Parse the graph to extract a list of subdevice DT nodes. */
@@ -1134,23 +1133,20 @@ static int isi_graph_init(struct atmel_isi *isi)
return ret;
}
- /* Register the subdevices notifier. */
- subdevs = devm_kzalloc(isi->dev, sizeof(*subdevs), GFP_KERNEL);
- if (!subdevs) {
+ v4l2_async_notifier_init(&isi->notifier);
+
+ ret = v4l2_async_notifier_add_subdev(&isi->notifier, &isi->entity.asd);
+ if (ret) {
of_node_put(isi->entity.node);
- return -ENOMEM;
+ return ret;
}
- subdevs[0] = &isi->entity.asd;
-
- isi->notifier.subdevs = subdevs;
- isi->notifier.num_subdevs = 1;
isi->notifier.ops = &isi_graph_notify_ops;
ret = v4l2_async_notifier_register(&isi->v4l2_dev, &isi->notifier);
if (ret < 0) {
dev_err(isi->dev, "Notifier registration failed\n");
- of_node_put(isi->entity.node);
+ v4l2_async_notifier_cleanup(&isi->notifier);
return ret;
}
@@ -1202,7 +1198,7 @@ static int atmel_isi_probe(struct platform_device *pdev)
isi->vdev->fops = &isi_fops;
isi->vdev->v4l2_dev = &isi->v4l2_dev;
isi->vdev->queue = &isi->queue;
- strlcpy(isi->vdev->name, KBUILD_MODNAME, sizeof(isi->vdev->name));
+ strscpy(isi->vdev->name, KBUILD_MODNAME, sizeof(isi->vdev->name));
isi->vdev->release = video_device_release;
isi->vdev->ioctl_ops = &isi_ioctl_ops;
isi->vdev->lock = &isi->lock;
@@ -1303,6 +1299,7 @@ static int atmel_isi_remove(struct platform_device *pdev)
isi->fb_descriptors_phys);
pm_runtime_disable(&pdev->dev);
v4l2_async_notifier_unregister(&isi->notifier);
+ v4l2_async_notifier_cleanup(&isi->notifier);
v4l2_device_unregister(&isi->v4l2_dev);
return 0;
diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c
index 43e43c7b3e98..31ace114eda1 100644
--- a/drivers/media/platform/cadence/cdns-csi2rx.c
+++ b/drivers/media/platform/cadence/cdns-csi2rx.c
@@ -361,7 +361,7 @@ static int csi2rx_get_resources(struct csi2rx_priv *csi2rx,
static int csi2rx_parse_dt(struct csi2rx_priv *csi2rx)
{
- struct v4l2_fwnode_endpoint v4l2_ep;
+ struct v4l2_fwnode_endpoint v4l2_ep = { .bus_type = 0 };
struct fwnode_handle *fwh;
struct device_node *ep;
int ret;
@@ -378,7 +378,7 @@ static int csi2rx_parse_dt(struct csi2rx_priv *csi2rx)
return ret;
}
- if (v4l2_ep.bus_type != V4L2_MBUS_CSI2) {
+ if (v4l2_ep.bus_type != V4L2_MBUS_CSI2_DPHY) {
dev_err(csi2rx->dev, "Unsupported media bus type: 0x%x\n",
v4l2_ep.bus_type);
of_node_put(ep);
@@ -399,18 +399,22 @@ static int csi2rx_parse_dt(struct csi2rx_priv *csi2rx)
csi2rx->asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
of_node_put(ep);
- csi2rx->notifier.subdevs = devm_kzalloc(csi2rx->dev,
- sizeof(*csi2rx->notifier.subdevs),
- GFP_KERNEL);
- if (!csi2rx->notifier.subdevs)
- return -ENOMEM;
+ v4l2_async_notifier_init(&csi2rx->notifier);
+
+ ret = v4l2_async_notifier_add_subdev(&csi2rx->notifier, &csi2rx->asd);
+ if (ret) {
+ fwnode_handle_put(csi2rx->asd.match.fwnode);
+ return ret;
+ }
- csi2rx->notifier.subdevs[0] = &csi2rx->asd;
- csi2rx->notifier.num_subdevs = 1;
csi2rx->notifier.ops = &csi2rx_notifier_ops;
- return v4l2_async_subdev_notifier_register(&csi2rx->subdev,
- &csi2rx->notifier);
+ ret = v4l2_async_subdev_notifier_register(&csi2rx->subdev,
+ &csi2rx->notifier);
+ if (ret)
+ v4l2_async_notifier_cleanup(&csi2rx->notifier);
+
+ return ret;
}
static int csi2rx_probe(struct platform_device *pdev)
@@ -450,11 +454,11 @@ static int csi2rx_probe(struct platform_device *pdev)
ret = media_entity_pads_init(&csi2rx->subdev.entity, CSI2RX_PAD_MAX,
csi2rx->pads);
if (ret)
- goto err_free_priv;
+ goto err_cleanup;
ret = v4l2_async_register_subdev(&csi2rx->subdev);
if (ret < 0)
- goto err_free_priv;
+ goto err_cleanup;
dev_info(&pdev->dev,
"Probed CSI2RX with %u/%u lanes, %u streams, %s D-PHY\n",
@@ -463,6 +467,8 @@ static int csi2rx_probe(struct platform_device *pdev)
return 0;
+err_cleanup:
+ v4l2_async_notifier_cleanup(&csi2rx->notifier);
err_free_priv:
kfree(csi2rx);
return ret;
diff --git a/drivers/media/platform/cadence/cdns-csi2tx.c b/drivers/media/platform/cadence/cdns-csi2tx.c
index 40d0de690ff4..5042d053b94e 100644
--- a/drivers/media/platform/cadence/cdns-csi2tx.c
+++ b/drivers/media/platform/cadence/cdns-csi2tx.c
@@ -432,7 +432,7 @@ static int csi2tx_get_resources(struct csi2tx_priv *csi2tx,
static int csi2tx_check_lanes(struct csi2tx_priv *csi2tx)
{
- struct v4l2_fwnode_endpoint v4l2_ep;
+ struct v4l2_fwnode_endpoint v4l2_ep = { .bus_type = 0 };
struct device_node *ep;
int ret;
@@ -446,7 +446,7 @@ static int csi2tx_check_lanes(struct csi2tx_priv *csi2tx)
goto out;
}
- if (v4l2_ep.bus_type != V4L2_MBUS_CSI2) {
+ if (v4l2_ep.bus_type != V4L2_MBUS_CSI2_DPHY) {
dev_err(csi2tx->dev, "Unsupported media bus type: 0x%x\n",
v4l2_ep.bus_type);
ret = -EINVAL;
diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c
index 726b3b93a486..2848ea5f464d 100644
--- a/drivers/media/platform/coda/coda-common.c
+++ b/drivers/media/platform/coda/coda-common.c
@@ -376,8 +376,7 @@ static struct vdoa_data *coda_get_vdoa_data(void)
vdoa_data = ERR_PTR(-EPROBE_DEFER);
out:
- if (vdoa_node)
- of_node_put(vdoa_node);
+ of_node_put(vdoa_node);
return vdoa_data;
}
@@ -390,10 +389,10 @@ static int coda_querycap(struct file *file, void *priv,
{
struct coda_ctx *ctx = fh_to_ctx(priv);
- strlcpy(cap->driver, CODA_NAME, sizeof(cap->driver));
- strlcpy(cap->card, coda_product_name(ctx->dev->devtype->product),
+ strscpy(cap->driver, CODA_NAME, sizeof(cap->driver));
+ strscpy(cap->card, coda_product_name(ctx->dev->devtype->product),
sizeof(cap->card));
- strlcpy(cap->bus_info, "platform:" CODA_NAME, sizeof(cap->bus_info));
+ strscpy(cap->bus_info, "platform:" CODA_NAME, sizeof(cap->bus_info));
cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
@@ -1804,7 +1803,8 @@ static int coda_s_ctrl(struct v4l2_ctrl *ctrl)
break;
case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
/* TODO: switch between baseline and constrained baseline */
- ctx->params.h264_profile_idc = 66;
+ if (ctx->inst_type == CODA_INST_ENCODER)
+ ctx->params.h264_profile_idc = 66;
break;
case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
/* nothing to do, this is set by the encoder */
@@ -2408,7 +2408,7 @@ static int coda_register_device(struct coda_dev *dev, int i)
if (i >= dev->devtype->num_vdevs)
return -EINVAL;
- strlcpy(vfd->name, dev->devtype->vdevs[i]->name, sizeof(vfd->name));
+ strscpy(vfd->name, dev->devtype->vdevs[i]->name, sizeof(vfd->name));
vfd->fops = &coda_fops;
vfd->ioctl_ops = &coda_ioctl_ops;
vfd->release = video_device_release_empty,
diff --git a/drivers/media/platform/davinci/isif.c b/drivers/media/platform/davinci/isif.c
index f924e76e2fbf..340f8218f54d 100644
--- a/drivers/media/platform/davinci/isif.c
+++ b/drivers/media/platform/davinci/isif.c
@@ -1100,7 +1100,8 @@ fail_nobase_res:
while (i >= 0) {
res = platform_get_resource(pdev, IORESOURCE_MEM, i);
- release_mem_region(res->start, resource_size(res));
+ if (res)
+ release_mem_region(res->start, resource_size(res));
i--;
}
vpfe_unregister_ccdc_device(&isif_hw_dev);
diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c
index b0eb3d899eb4..5c235898af7b 100644
--- a/drivers/media/platform/davinci/vpbe_display.c
+++ b/drivers/media/platform/davinci/vpbe_display.c
@@ -521,7 +521,7 @@ vpbe_disp_calculate_scale_factor(struct vpbe_display *disp_dev,
else if (v_scale == 4)
layer_info->v_zoom = ZOOM_X4;
if (v_exp)
- layer_info->h_exp = V_EXP_6_OVER_5;
+ layer_info->v_exp = V_EXP_6_OVER_5;
} else {
/* no scaling, only cropping. Set display area to crop area */
cfg->ysize = expected_ysize;
@@ -647,7 +647,7 @@ static int vpbe_display_querycap(struct file *file, void *priv,
dev_name(vpbe_dev->pdev));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
dev_name(vpbe_dev->pdev));
- strlcpy(cap->card, vpbe_dev->cfg->module_name, sizeof(cap->card));
+ strscpy(cap->card, vpbe_dev->cfg->module_name, sizeof(cap->card));
return 0;
}
@@ -816,10 +816,12 @@ static int vpbe_display_enum_fmt(struct file *file, void *priv,
fmt->index = index;
fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
if (index == 0) {
- strcpy(fmt->description, "YUV 4:2:2 - UYVY");
+ strscpy(fmt->description, "YUV 4:2:2 - UYVY",
+ sizeof(fmt->description));
fmt->pixelformat = V4L2_PIX_FMT_UYVY;
} else {
- strcpy(fmt->description, "Y/CbCr 4:2:0");
+ strscpy(fmt->description, "Y/CbCr 4:2:0",
+ sizeof(fmt->description));
fmt->pixelformat = V4L2_PIX_FMT_NV12;
}
diff --git a/drivers/media/platform/davinci/vpbe_venc.c b/drivers/media/platform/davinci/vpbe_venc.c
index ddcad7b3e76c..ca78eb29641a 100644
--- a/drivers/media/platform/davinci/vpbe_venc.c
+++ b/drivers/media/platform/davinci/vpbe_venc.c
@@ -616,7 +616,7 @@ struct v4l2_subdev *venc_sub_dev_init(struct v4l2_device *v4l2_dev,
v4l2_subdev_init(&venc->sd, &venc_ops);
- strcpy(venc->sd.name, venc_name);
+ strscpy(venc->sd.name, venc_name, sizeof(venc->sd.name));
if (v4l2_device_register_subdev(v4l2_dev, &venc->sd) < 0) {
v4l2_err(v4l2_dev,
"vpbe unable to register venc sub device\n");
diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c
index 8613358ed245..ea3ddd5a42bd 100644
--- a/drivers/media/platform/davinci/vpfe_capture.c
+++ b/drivers/media/platform/davinci/vpfe_capture.c
@@ -889,9 +889,9 @@ static int vpfe_querycap(struct file *file, void *priv,
cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
- strlcpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver));
- strlcpy(cap->bus_info, "VPFE", sizeof(cap->bus_info));
- strlcpy(cap->card, vpfe_dev->cfg->card_name, sizeof(cap->card));
+ strscpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver));
+ strscpy(cap->bus_info, "VPFE", sizeof(cap->bus_info));
+ strscpy(cap->card, vpfe_dev->cfg->card_name, sizeof(cap->card));
return 0;
}
diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c
index a96f53ce8088..6216b7ac6875 100644
--- a/drivers/media/platform/davinci/vpif_capture.c
+++ b/drivers/media/platform/davinci/vpif_capture.c
@@ -949,11 +949,13 @@ static int vpif_enum_fmt_vid_cap(struct file *file, void *priv,
/* Fill in the information about format */
if (ch->vpifparams.iface.if_type == VPIF_IF_RAW_BAYER) {
fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- strcpy(fmt->description, "Raw Mode -Bayer Pattern GrRBGb");
+ strscpy(fmt->description, "Raw Mode -Bayer Pattern GrRBGb",
+ sizeof(fmt->description));
fmt->pixelformat = V4L2_PIX_FMT_SBGGR8;
} else {
fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- strcpy(fmt->description, "YCbCr4:2:2 Semi-Planar");
+ strscpy(fmt->description, "YCbCr4:2:2 Semi-Planar",
+ sizeof(fmt->description));
fmt->pixelformat = V4L2_PIX_FMT_NV16;
}
return 0;
@@ -1094,10 +1096,10 @@ static int vpif_querycap(struct file *file, void *priv,
cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
- strlcpy(cap->driver, VPIF_DRIVER_NAME, sizeof(cap->driver));
+ strscpy(cap->driver, VPIF_DRIVER_NAME, sizeof(cap->driver));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
dev_name(vpif_dev));
- strlcpy(cap->card, config->card_name, sizeof(cap->card));
+ strscpy(cap->card, config->card_name, sizeof(cap->card));
return 0;
}
@@ -1463,7 +1465,7 @@ static int vpif_probe_complete(void)
/* Initialize the video_device structure */
vdev = &ch->video_dev;
- strlcpy(vdev->name, VPIF_DRIVER_NAME, sizeof(vdev->name));
+ strscpy(vdev->name, VPIF_DRIVER_NAME, sizeof(vdev->name));
vdev->release = video_device_release_empty;
vdev->fops = &vpif_fops;
vdev->ioctl_ops = &vpif_ioctl_ops;
@@ -1509,12 +1511,13 @@ static struct vpif_capture_config *
vpif_capture_get_pdata(struct platform_device *pdev)
{
struct device_node *endpoint = NULL;
- struct v4l2_fwnode_endpoint bus_cfg;
struct vpif_capture_config *pdata;
struct vpif_subdev_info *sdinfo;
struct vpif_capture_chan_config *chan;
unsigned int i;
+ v4l2_async_notifier_init(&vpif_obj.notifier);
+
/*
* DT boot: OF node from parent device contains
* video ports & endpoints data.
@@ -1537,6 +1540,7 @@ vpif_capture_get_pdata(struct platform_device *pdev)
return NULL;
for (i = 0; i < VPIF_CAPTURE_NUM_CHANNELS; i++) {
+ struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 };
struct device_node *rem;
unsigned int flags;
int err;
@@ -1546,14 +1550,25 @@ vpif_capture_get_pdata(struct platform_device *pdev)
if (!endpoint)
break;
+ rem = of_graph_get_remote_port_parent(endpoint);
+ if (!rem) {
+ dev_dbg(&pdev->dev, "Remote device at %pOF not found\n",
+ endpoint);
+ of_node_put(endpoint);
+ goto done;
+ }
+
sdinfo = &pdata->subdev_info[i];
chan = &pdata->chan_config[i];
chan->inputs = devm_kcalloc(&pdev->dev,
VPIF_CAPTURE_NUM_CHANNELS,
sizeof(*chan->inputs),
GFP_KERNEL);
- if (!chan->inputs)
- return NULL;
+ if (!chan->inputs) {
+ of_node_put(rem);
+ of_node_put(endpoint);
+ goto err_cleanup;
+ }
chan->input_count++;
chan->inputs[i].input.type = V4L2_INPUT_TYPE_CAMERA;
@@ -1562,12 +1577,16 @@ vpif_capture_get_pdata(struct platform_device *pdev)
err = v4l2_fwnode_endpoint_parse(of_fwnode_handle(endpoint),
&bus_cfg);
+ of_node_put(endpoint);
if (err) {
dev_err(&pdev->dev, "Could not parse the endpoint\n");
+ of_node_put(rem);
goto done;
}
+
dev_dbg(&pdev->dev, "Endpoint %pOF, bus_width = %d\n",
endpoint, bus_cfg.bus.parallel.bus_width);
+
flags = bus_cfg.bus.parallel.flags;
if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
@@ -1576,39 +1595,29 @@ vpif_capture_get_pdata(struct platform_device *pdev)
if (flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
chan->vpif_if.vd_pol = 1;
- rem = of_graph_get_remote_port_parent(endpoint);
- if (!rem) {
- dev_dbg(&pdev->dev, "Remote device at %pOF not found\n",
- endpoint);
- goto done;
- }
-
- dev_dbg(&pdev->dev, "Remote device %s, %pOF found\n",
- rem->name, rem);
+ dev_dbg(&pdev->dev, "Remote device %pOF found\n", rem);
sdinfo->name = rem->full_name;
- pdata->asd[i] = devm_kzalloc(&pdev->dev,
- sizeof(struct v4l2_async_subdev),
- GFP_KERNEL);
- if (!pdata->asd[i]) {
+ pdata->asd[i] = v4l2_async_notifier_add_fwnode_subdev(
+ &vpif_obj.notifier, of_fwnode_handle(rem),
+ sizeof(struct v4l2_async_subdev));
+ if (IS_ERR(pdata->asd[i])) {
of_node_put(rem);
- pdata = NULL;
- goto done;
+ goto err_cleanup;
}
-
- pdata->asd[i]->match_type = V4L2_ASYNC_MATCH_FWNODE;
- pdata->asd[i]->match.fwnode = of_fwnode_handle(rem);
- of_node_put(rem);
}
done:
- if (pdata) {
- pdata->asd_sizes[0] = i;
- pdata->subdev_count = i;
- pdata->card_name = "DA850/OMAP-L138 Video Capture";
- }
+ pdata->asd_sizes[0] = i;
+ pdata->subdev_count = i;
+ pdata->card_name = "DA850/OMAP-L138 Video Capture";
return pdata;
+
+err_cleanup:
+ v4l2_async_notifier_cleanup(&vpif_obj.notifier);
+
+ return NULL;
}
/**
@@ -1633,23 +1642,18 @@ static __init int vpif_probe(struct platform_device *pdev)
return -EINVAL;
}
- if (!pdev->dev.platform_data) {
- dev_warn(&pdev->dev, "Missing platform data. Giving up.\n");
- return -EINVAL;
- }
-
vpif_dev = &pdev->dev;
err = initialize_vpif();
if (err) {
v4l2_err(vpif_dev->driver, "Error initializing vpif\n");
- return err;
+ goto cleanup;
}
err = v4l2_device_register(vpif_dev, &vpif_obj.v4l2_dev);
if (err) {
v4l2_err(vpif_dev->driver, "Error registering v4l2 device\n");
- return err;
+ goto cleanup;
}
while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, res_idx))) {
@@ -1698,8 +1702,6 @@ static __init int vpif_probe(struct platform_device *pdev)
}
vpif_probe_complete();
} else {
- vpif_obj.notifier.subdevs = vpif_obj.config->asd;
- vpif_obj.notifier.num_subdevs = vpif_obj.config->asd_sizes[0];
vpif_obj.notifier.ops = &vpif_async_ops;
err = v4l2_async_notifier_register(&vpif_obj.v4l2_dev,
&vpif_obj.notifier);
@@ -1717,6 +1719,8 @@ probe_subdev_out:
kfree(vpif_obj.sd);
vpif_unregister:
v4l2_device_unregister(&vpif_obj.v4l2_dev);
+cleanup:
+ v4l2_async_notifier_cleanup(&vpif_obj.notifier);
return err;
}
@@ -1732,6 +1736,8 @@ static int vpif_remove(struct platform_device *device)
struct channel_obj *ch;
int i;
+ v4l2_async_notifier_unregister(&vpif_obj.notifier);
+ v4l2_async_notifier_cleanup(&vpif_obj.notifier);
v4l2_device_unregister(&vpif_obj.v4l2_dev);
kfree(vpif_obj.sd);
diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c
index 0f324055cc9f..3517487d9760 100644
--- a/drivers/media/platform/davinci/vpif_display.c
+++ b/drivers/media/platform/davinci/vpif_display.c
@@ -586,10 +586,10 @@ static int vpif_querycap(struct file *file, void *priv,
cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
- strlcpy(cap->driver, VPIF_DRIVER_NAME, sizeof(cap->driver));
+ strscpy(cap->driver, VPIF_DRIVER_NAME, sizeof(cap->driver));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
dev_name(vpif_dev));
- strlcpy(cap->card, config->card_name, sizeof(cap->card));
+ strscpy(cap->card, config->card_name, sizeof(cap->card));
return 0;
}
@@ -602,7 +602,8 @@ static int vpif_enum_fmt_vid_out(struct file *file, void *priv,
/* Fill in the information about format */
fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
- strcpy(fmt->description, "YCbCr4:2:2 YC Planar");
+ strscpy(fmt->description, "YCbCr4:2:2 YC Planar",
+ sizeof(fmt->description));
fmt->pixelformat = V4L2_PIX_FMT_YUV422P;
fmt->flags = 0;
return 0;
@@ -1209,7 +1210,7 @@ static int vpif_probe_complete(void)
/* Initialize the video_device structure */
vdev = &ch->video_dev;
- strlcpy(vdev->name, VPIF_DRIVER_NAME, sizeof(vdev->name));
+ strscpy(vdev->name, VPIF_DRIVER_NAME, sizeof(vdev->name));
vdev->release = video_device_release_empty;
vdev->fops = &vpif_fops;
vdev->ioctl_ops = &vpif_ioctl_ops;
@@ -1299,6 +1300,8 @@ static __init int vpif_probe(struct platform_device *pdev)
goto vpif_unregister;
}
+ v4l2_async_notifier_init(&vpif_obj.notifier);
+
if (!vpif_obj.config->asd_sizes) {
i2c_adap = i2c_get_adapter(vpif_obj.config->i2c_adapter_id);
for (i = 0; i < subdev_count; i++) {
@@ -1322,20 +1325,27 @@ static __init int vpif_probe(struct platform_device *pdev)
goto probe_subdev_out;
}
} else {
- vpif_obj.notifier.subdevs = vpif_obj.config->asd;
- vpif_obj.notifier.num_subdevs = vpif_obj.config->asd_sizes[0];
+ for (i = 0; i < vpif_obj.config->asd_sizes[0]; i++) {
+ err = v4l2_async_notifier_add_subdev(
+ &vpif_obj.notifier, vpif_obj.config->asd[i]);
+ if (err)
+ goto probe_cleanup;
+ }
+
vpif_obj.notifier.ops = &vpif_async_ops;
err = v4l2_async_notifier_register(&vpif_obj.v4l2_dev,
&vpif_obj.notifier);
if (err) {
vpif_err("Error registering async notifier\n");
err = -EINVAL;
- goto probe_subdev_out;
+ goto probe_cleanup;
}
}
return 0;
+probe_cleanup:
+ v4l2_async_notifier_cleanup(&vpif_obj.notifier);
probe_subdev_out:
kfree(vpif_obj.sd);
vpif_unregister:
@@ -1354,6 +1364,11 @@ static int vpif_remove(struct platform_device *device)
struct channel_obj *ch;
int i;
+ if (vpif_obj.config->asd_sizes) {
+ v4l2_async_notifier_unregister(&vpif_obj.notifier);
+ v4l2_async_notifier_cleanup(&vpif_obj.notifier);
+ }
+
v4l2_device_unregister(&vpif_obj.v4l2_dev);
kfree(vpif_obj.sd);
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c
index 17854a379243..838c5c53de37 100644
--- a/drivers/media/platform/exynos-gsc/gsc-core.c
+++ b/drivers/media/platform/exynos-gsc/gsc-core.c
@@ -339,7 +339,7 @@ int gsc_enum_fmt_mplane(struct v4l2_fmtdesc *f)
if (!fmt)
return -EINVAL;
- strlcpy(f->description, fmt->name, sizeof(f->description));
+ strscpy(f->description, fmt->name, sizeof(f->description));
f->pixelformat = fmt->pixelformat;
return 0;
diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c
index c9d2f6c5311a..cc5d690818e1 100644
--- a/drivers/media/platform/exynos-gsc/gsc-m2m.c
+++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c
@@ -294,8 +294,8 @@ static int gsc_m2m_querycap(struct file *file, void *fh,
struct gsc_ctx *ctx = fh_to_ctx(fh);
struct gsc_dev *gsc = ctx->gsc_dev;
- strlcpy(cap->driver, GSC_MODULE_NAME, sizeof(cap->driver));
- strlcpy(cap->card, GSC_MODULE_NAME " gscaler", sizeof(cap->card));
+ strscpy(cap->driver, GSC_MODULE_NAME, sizeof(cap->driver));
+ strscpy(cap->card, GSC_MODULE_NAME " gscaler", sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
dev_name(&gsc->pdev->dev));
cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE;
diff --git a/drivers/media/platform/exynos4-is/common.c b/drivers/media/platform/exynos4-is/common.c
index b90f5bb15517..76f557548dfc 100644
--- a/drivers/media/platform/exynos4-is/common.c
+++ b/drivers/media/platform/exynos4-is/common.c
@@ -40,8 +40,8 @@ EXPORT_SYMBOL(fimc_find_remote_sensor);
void __fimc_vidioc_querycap(struct device *dev, struct v4l2_capability *cap,
unsigned int caps)
{
- strlcpy(cap->driver, dev->driver->name, sizeof(cap->driver));
- strlcpy(cap->card, dev->driver->name, sizeof(cap->card));
+ strscpy(cap->driver, dev->driver->name, sizeof(cap->driver));
+ strscpy(cap->card, dev->driver->name, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info),
"platform:%s", dev_name(dev));
cap->device_caps = caps;
diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c
index a3cdac188190..3e9fcf4f8a13 100644
--- a/drivers/media/platform/exynos4-is/fimc-capture.c
+++ b/drivers/media/platform/exynos4-is/fimc-capture.c
@@ -1087,7 +1087,7 @@ static int fimc_cap_enum_input(struct file *file, void *priv,
fimc_md_graph_unlock(ve);
if (sd)
- strlcpy(i->name, sd->name, sizeof(i->name));
+ strscpy(i->name, sd->name, sizeof(i->name));
return 0;
}
@@ -1424,7 +1424,7 @@ static int fimc_link_setup(struct media_entity *entity,
return 0;
return v4l2_ctrl_add_handler(&vc->ctx->ctrls.handler,
- sensor->ctrl_handler, NULL);
+ sensor->ctrl_handler, NULL, true);
}
static const struct media_entity_operations fimc_sd_media_ops = {
diff --git a/drivers/media/platform/exynos4-is/fimc-is-i2c.c b/drivers/media/platform/exynos4-is/fimc-is-i2c.c
index 70dd4852b2b9..be937caf7645 100644
--- a/drivers/media/platform/exynos4-is/fimc-is-i2c.c
+++ b/drivers/media/platform/exynos4-is/fimc-is-i2c.c
@@ -57,7 +57,7 @@ static int fimc_is_i2c_probe(struct platform_device *pdev)
i2c_adap = &isp_i2c->adapter;
i2c_adap->dev.of_node = node;
i2c_adap->dev.parent = &pdev->dev;
- strlcpy(i2c_adap->name, "exynos4x12-isp-i2c", sizeof(i2c_adap->name));
+ strscpy(i2c_adap->name, "exynos4x12-isp-i2c", sizeof(i2c_adap->name));
i2c_adap->owner = THIS_MODULE;
i2c_adap->algo = &fimc_is_i2c_algorithm;
i2c_adap->class = I2C_CLASS_SPD;
diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c
index 5ddb2321e9e4..f5fc54de19da 100644
--- a/drivers/media/platform/exynos4-is/fimc-is.c
+++ b/drivers/media/platform/exynos4-is/fimc-is.c
@@ -656,7 +656,7 @@ static int fimc_is_hw_open_sensor(struct fimc_is *is,
int fimc_is_hw_initialize(struct fimc_is *is)
{
- const int config_ids[] = {
+ static const int config_ids[] = {
IS_SC_PREVIEW_STILL, IS_SC_PREVIEW_VIDEO,
IS_SC_CAPTURE_STILL, IS_SC_CAPTURE_VIDEO
};
diff --git a/drivers/media/platform/exynos4-is/fimc-isp-video.c b/drivers/media/platform/exynos4-is/fimc-isp-video.c
index a920164f53f1..de6bd28f7e31 100644
--- a/drivers/media/platform/exynos4-is/fimc-isp-video.c
+++ b/drivers/media/platform/exynos4-is/fimc-isp-video.c
@@ -365,7 +365,7 @@ static int isp_video_enum_fmt_mplane(struct file *file, void *priv,
if (WARN_ON(fmt == NULL))
return -EINVAL;
- strlcpy(f->description, fmt->name, sizeof(f->description));
+ strscpy(f->description, fmt->name, sizeof(f->description));
f->pixelformat = fmt->fourcc;
return 0;
diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c
index 70d5f5586a5d..96f0a8a0dcae 100644
--- a/drivers/media/platform/exynos4-is/fimc-lite.c
+++ b/drivers/media/platform/exynos4-is/fimc-lite.c
@@ -654,8 +654,8 @@ static int fimc_lite_querycap(struct file *file, void *priv,
{
struct fimc_lite *fimc = video_drvdata(file);
- strlcpy(cap->driver, FIMC_LITE_DRV_NAME, sizeof(cap->driver));
- strlcpy(cap->card, FIMC_LITE_DRV_NAME, sizeof(cap->card));
+ strscpy(cap->driver, FIMC_LITE_DRV_NAME, sizeof(cap->driver));
+ strscpy(cap->card, FIMC_LITE_DRV_NAME, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
dev_name(&fimc->pdev->dev));
@@ -673,7 +673,7 @@ static int fimc_lite_enum_fmt_mplane(struct file *file, void *priv,
return -EINVAL;
fmt = &fimc_lite_formats[f->index];
- strlcpy(f->description, fmt->name, sizeof(f->description));
+ strscpy(f->description, fmt->name, sizeof(f->description));
f->pixelformat = fmt->fourcc;
return 0;
diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c
index deb499f76412..870501b0f351 100644
--- a/drivers/media/platform/exynos4-is/media-dev.c
+++ b/drivers/media/platform/exynos4-is/media-dev.c
@@ -390,7 +390,7 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd,
{
struct fimc_source_info *pd = &fmd->sensor[index].pdata;
struct device_node *rem, *ep, *np;
- struct v4l2_fwnode_endpoint endpoint;
+ struct v4l2_fwnode_endpoint endpoint = { .bus_type = 0 };
int ret;
/* Assume here a port node can have only one endpoint node. */
@@ -457,11 +457,16 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd,
fmd->sensor[index].asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
fmd->sensor[index].asd.match.fwnode = of_fwnode_handle(rem);
- fmd->async_subdevs[index] = &fmd->sensor[index].asd;
+
+ ret = v4l2_async_notifier_add_subdev(&fmd->subdev_notifier,
+ &fmd->sensor[index].asd);
+ if (ret) {
+ of_node_put(rem);
+ return ret;
+ }
fmd->num_sensors++;
- of_node_put(rem);
return 0;
}
@@ -500,7 +505,7 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd)
ret = fimc_md_parse_port_node(fmd, port, index);
if (ret < 0) {
of_node_put(node);
- goto rpm_put;
+ goto cleanup;
}
index++;
}
@@ -514,12 +519,18 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd)
ret = fimc_md_parse_port_node(fmd, node, index);
if (ret < 0) {
of_node_put(node);
- break;
+ goto cleanup;
}
index++;
}
+
rpm_put:
pm_runtime_put(fmd->pmf);
+ return 0;
+
+cleanup:
+ v4l2_async_notifier_cleanup(&fmd->subdev_notifier);
+ pm_runtime_put(fmd->pmf);
return ret;
}
@@ -1204,9 +1215,9 @@ static ssize_t fimc_md_sysfs_show(struct device *dev,
struct fimc_md *fmd = dev_get_drvdata(dev);
if (fmd->user_subdev_api)
- return strlcpy(buf, "Sub-device API (sub-dev)\n", PAGE_SIZE);
+ return strscpy(buf, "Sub-device API (sub-dev)\n", PAGE_SIZE);
- return strlcpy(buf, "V4L2 video node only API (vid-dev)\n", PAGE_SIZE);
+ return strscpy(buf, "V4L2 video node only API (vid-dev)\n", PAGE_SIZE);
}
static ssize_t fimc_md_sysfs_store(struct device *dev,
@@ -1426,7 +1437,7 @@ static int fimc_md_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&fmd->pipelines);
fmd->pdev = pdev;
- strlcpy(fmd->media_dev.model, "SAMSUNG S5P FIMC",
+ strscpy(fmd->media_dev.model, "SAMSUNG S5P FIMC",
sizeof(fmd->media_dev.model));
fmd->media_dev.ops = &fimc_md_ops;
fmd->media_dev.dev = dev;
@@ -1434,7 +1445,7 @@ static int fimc_md_probe(struct platform_device *pdev)
v4l2_dev = &fmd->v4l2_dev;
v4l2_dev->mdev = &fmd->media_dev;
v4l2_dev->notify = fimc_sensor_notify;
- strlcpy(v4l2_dev->name, "s5p-fimc-md", sizeof(v4l2_dev->name));
+ strscpy(v4l2_dev->name, "s5p-fimc-md", sizeof(v4l2_dev->name));
fmd->use_isp = fimc_md_is_isp_available(dev->of_node);
fmd->user_subdev_api = true;
@@ -1460,6 +1471,8 @@ static int fimc_md_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, fmd);
+ v4l2_async_notifier_init(&fmd->subdev_notifier);
+
ret = fimc_md_register_platform_entities(fmd, dev->of_node);
if (ret)
goto err_clk;
@@ -1470,7 +1483,7 @@ static int fimc_md_probe(struct platform_device *pdev)
ret = device_create_file(&pdev->dev, &dev_attr_subdev_conf_mode);
if (ret)
- goto err_m_ent;
+ goto err_cleanup;
/*
* FIMC platform devices need to be registered before the sclk_cam
* clocks provider, as one of these devices needs to be activated
@@ -1483,8 +1496,6 @@ static int fimc_md_probe(struct platform_device *pdev)
}
if (fmd->num_sensors > 0) {
- fmd->subdev_notifier.subdevs = fmd->async_subdevs;
- fmd->subdev_notifier.num_subdevs = fmd->num_sensors;
fmd->subdev_notifier.ops = &subdev_notifier_ops;
fmd->num_sensors = 0;
@@ -1500,10 +1511,12 @@ err_clk_p:
fimc_md_unregister_clk_provider(fmd);
err_attr:
device_remove_file(&pdev->dev, &dev_attr_subdev_conf_mode);
-err_clk:
- fimc_md_put_clocks(fmd);
+err_cleanup:
+ v4l2_async_notifier_cleanup(&fmd->subdev_notifier);
err_m_ent:
fimc_md_unregister_entities(fmd);
+err_clk:
+ fimc_md_put_clocks(fmd);
err_md:
media_device_cleanup(&fmd->media_dev);
v4l2_device_unregister(&fmd->v4l2_dev);
@@ -1519,6 +1532,7 @@ static int fimc_md_remove(struct platform_device *pdev)
fimc_md_unregister_clk_provider(fmd);
v4l2_async_notifier_unregister(&fmd->subdev_notifier);
+ v4l2_async_notifier_cleanup(&fmd->subdev_notifier);
v4l2_device_unregister(&fmd->v4l2_dev);
device_remove_file(&pdev->dev, &dev_attr_subdev_conf_mode);
diff --git a/drivers/media/platform/exynos4-is/media-dev.h b/drivers/media/platform/exynos4-is/media-dev.h
index 957787a2f480..9f527670395a 100644
--- a/drivers/media/platform/exynos4-is/media-dev.h
+++ b/drivers/media/platform/exynos4-is/media-dev.h
@@ -149,7 +149,6 @@ struct fimc_md {
} clk_provider;
struct v4l2_async_notifier subdev_notifier;
- struct v4l2_async_subdev *async_subdevs[FIMC_MAX_SENSORS];
bool user_subdev_api;
spinlock_t slock;
diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c
index b4e28a299e26..35cb0162085b 100644
--- a/drivers/media/platform/exynos4-is/mipi-csis.c
+++ b/drivers/media/platform/exynos4-is/mipi-csis.c
@@ -718,7 +718,7 @@ static int s5pcsis_parse_dt(struct platform_device *pdev,
struct csis_state *state)
{
struct device_node *node = pdev->dev.of_node;
- struct v4l2_fwnode_endpoint endpoint;
+ struct v4l2_fwnode_endpoint endpoint = { .bus_type = 0 };
int ret;
if (of_property_read_u32(node, "clock-frequency",
diff --git a/drivers/media/platform/fsl-viu.c b/drivers/media/platform/fsl-viu.c
index 0273302aa741..ca6d0317ab42 100644
--- a/drivers/media/platform/fsl-viu.c
+++ b/drivers/media/platform/fsl-viu.c
@@ -565,9 +565,9 @@ static const struct videobuf_queue_ops viu_video_qops = {
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- strcpy(cap->driver, "viu");
- strcpy(cap->card, "viu");
- strcpy(cap->bus_info, "platform:viu");
+ strscpy(cap->driver, "viu", sizeof(cap->driver));
+ strscpy(cap->card, "viu", sizeof(cap->card));
+ strscpy(cap->bus_info, "platform:viu", sizeof(cap->bus_info));
cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_STREAMING |
V4L2_CAP_VIDEO_OVERLAY |
@@ -941,7 +941,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
inp->type = V4L2_INPUT_TYPE_CAMERA;
inp->std = fh->dev->vdev->tvnorms;
- strcpy(inp->name, "Camera");
+ strscpy(inp->name, "Camera", sizeof(inp->name));
return 0;
}
diff --git a/drivers/media/platform/imx-pxp.c b/drivers/media/platform/imx-pxp.c
new file mode 100644
index 000000000000..b76cd0e8313c
--- /dev/null
+++ b/drivers/media/platform/imx-pxp.c
@@ -0,0 +1,1754 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * i.MX Pixel Pipeline (PXP) mem-to-mem scaler/CSC/rotator driver
+ *
+ * Copyright (c) 2018 Pengutronix, Philipp Zabel
+ *
+ * based on vim2m
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Pawel Osciak, <pawel@osciak.com>
+ * Marek Szyprowski, <m.szyprowski@samsung.com>
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include <linux/platform_device.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "imx-pxp.h"
+
+static unsigned int debug;
+module_param(debug, uint, 0644);
+MODULE_PARM_DESC(debug, "activates debug info");
+
+#define MIN_W 8
+#define MIN_H 8
+#define MAX_W 4096
+#define MAX_H 4096
+#define ALIGN_W 3 /* 8x8 pixel blocks */
+#define ALIGN_H 3
+
+/* Flags that indicate a format can be used for capture/output */
+#define MEM2MEM_CAPTURE (1 << 0)
+#define MEM2MEM_OUTPUT (1 << 1)
+
+#define MEM2MEM_NAME "pxp"
+
+/* Flags that indicate processing mode */
+#define MEM2MEM_HFLIP (1 << 0)
+#define MEM2MEM_VFLIP (1 << 1)
+
+#define dprintk(dev, fmt, arg...) \
+ v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
+
+struct pxp_fmt {
+ u32 fourcc;
+ int depth;
+ /* Types the format can be used for */
+ u32 types;
+};
+
+static struct pxp_fmt formats[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_XBGR32,
+ .depth = 32,
+ /* Both capture and output format */
+ .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
+ }, {
+ .fourcc = V4L2_PIX_FMT_ABGR32,
+ .depth = 32,
+ /* Capture-only format */
+ .types = MEM2MEM_CAPTURE,
+ }, {
+ .fourcc = V4L2_PIX_FMT_BGR24,
+ .depth = 24,
+ .types = MEM2MEM_CAPTURE,
+ }, {
+ .fourcc = V4L2_PIX_FMT_RGB565,
+ .depth = 16,
+ .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
+ }, {
+ .fourcc = V4L2_PIX_FMT_RGB555,
+ .depth = 16,
+ .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
+ }, {
+ .fourcc = V4L2_PIX_FMT_RGB444,
+ .depth = 16,
+ .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
+ }, {
+ .fourcc = V4L2_PIX_FMT_YUV32,
+ .depth = 32,
+ .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
+ }, {
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .depth = 16,
+ .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
+ }, {
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .depth = 16,
+ /* Output-only format */
+ .types = MEM2MEM_OUTPUT,
+ }, {
+ .fourcc = V4L2_PIX_FMT_VYUY,
+ .depth = 16,
+ .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
+ }, {
+ .fourcc = V4L2_PIX_FMT_YVYU,
+ .depth = 16,
+ .types = MEM2MEM_OUTPUT,
+ }, {
+ .fourcc = V4L2_PIX_FMT_GREY,
+ .depth = 8,
+ .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
+ }, {
+ .fourcc = V4L2_PIX_FMT_Y4,
+ .depth = 4,
+ .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
+ }, {
+ .fourcc = V4L2_PIX_FMT_NV16,
+ .depth = 16,
+ .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
+ }, {
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .depth = 12,
+ .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
+ }, {
+ .fourcc = V4L2_PIX_FMT_NV21,
+ .depth = 12,
+ .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
+ }, {
+ .fourcc = V4L2_PIX_FMT_NV61,
+ .depth = 16,
+ .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
+ }, {
+ .fourcc = V4L2_PIX_FMT_YUV422P,
+ .depth = 16,
+ .types = MEM2MEM_OUTPUT,
+ }, {
+ .fourcc = V4L2_PIX_FMT_YUV420,
+ .depth = 12,
+ .types = MEM2MEM_OUTPUT,
+ },
+};
+
+#define NUM_FORMATS ARRAY_SIZE(formats)
+
+/* Per-queue, driver-specific private data */
+struct pxp_q_data {
+ unsigned int width;
+ unsigned int height;
+ unsigned int bytesperline;
+ unsigned int sizeimage;
+ unsigned int sequence;
+ struct pxp_fmt *fmt;
+ enum v4l2_ycbcr_encoding ycbcr_enc;
+ enum v4l2_quantization quant;
+};
+
+enum {
+ V4L2_M2M_SRC = 0,
+ V4L2_M2M_DST = 1,
+};
+
+static struct pxp_fmt *find_format(struct v4l2_format *f)
+{
+ struct pxp_fmt *fmt;
+ unsigned int k;
+
+ for (k = 0; k < NUM_FORMATS; k++) {
+ fmt = &formats[k];
+ if (fmt->fourcc == f->fmt.pix.pixelformat)
+ break;
+ }
+
+ if (k == NUM_FORMATS)
+ return NULL;
+
+ return &formats[k];
+}
+
+struct pxp_dev {
+ struct v4l2_device v4l2_dev;
+ struct video_device vfd;
+
+ struct clk *clk;
+ void __iomem *mmio;
+
+ atomic_t num_inst;
+ struct mutex dev_mutex;
+ spinlock_t irqlock;
+
+ struct v4l2_m2m_dev *m2m_dev;
+};
+
+struct pxp_ctx {
+ struct v4l2_fh fh;
+ struct pxp_dev *dev;
+
+ struct v4l2_ctrl_handler hdl;
+
+ /* Abort requested by m2m */
+ int aborting;
+
+ /* Processing mode */
+ int mode;
+ u8 alpha_component;
+
+ enum v4l2_colorspace colorspace;
+ enum v4l2_xfer_func xfer_func;
+
+ /* Source and destination queue data */
+ struct pxp_q_data q_data[2];
+};
+
+static inline struct pxp_ctx *file2ctx(struct file *file)
+{
+ return container_of(file->private_data, struct pxp_ctx, fh);
+}
+
+static struct pxp_q_data *get_q_data(struct pxp_ctx *ctx,
+ enum v4l2_buf_type type)
+{
+ if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ return &ctx->q_data[V4L2_M2M_SRC];
+ else
+ return &ctx->q_data[V4L2_M2M_DST];
+}
+
+static u32 pxp_v4l2_pix_fmt_to_ps_format(u32 v4l2_pix_fmt)
+{
+ switch (v4l2_pix_fmt) {
+ case V4L2_PIX_FMT_XBGR32: return BV_PXP_PS_CTRL_FORMAT__RGB888;
+ case V4L2_PIX_FMT_RGB555: return BV_PXP_PS_CTRL_FORMAT__RGB555;
+ case V4L2_PIX_FMT_RGB444: return BV_PXP_PS_CTRL_FORMAT__RGB444;
+ case V4L2_PIX_FMT_RGB565: return BV_PXP_PS_CTRL_FORMAT__RGB565;
+ case V4L2_PIX_FMT_YUV32: return BV_PXP_PS_CTRL_FORMAT__YUV1P444;
+ case V4L2_PIX_FMT_UYVY: return BV_PXP_PS_CTRL_FORMAT__UYVY1P422;
+ case V4L2_PIX_FMT_YUYV: return BM_PXP_PS_CTRL_WB_SWAP |
+ BV_PXP_PS_CTRL_FORMAT__UYVY1P422;
+ case V4L2_PIX_FMT_VYUY: return BV_PXP_PS_CTRL_FORMAT__VYUY1P422;
+ case V4L2_PIX_FMT_YVYU: return BM_PXP_PS_CTRL_WB_SWAP |
+ BV_PXP_PS_CTRL_FORMAT__VYUY1P422;
+ case V4L2_PIX_FMT_GREY: return BV_PXP_PS_CTRL_FORMAT__Y8;
+ default:
+ case V4L2_PIX_FMT_Y4: return BV_PXP_PS_CTRL_FORMAT__Y4;
+ case V4L2_PIX_FMT_NV16: return BV_PXP_PS_CTRL_FORMAT__YUV2P422;
+ case V4L2_PIX_FMT_NV12: return BV_PXP_PS_CTRL_FORMAT__YUV2P420;
+ case V4L2_PIX_FMT_NV21: return BV_PXP_PS_CTRL_FORMAT__YVU2P420;
+ case V4L2_PIX_FMT_NV61: return BV_PXP_PS_CTRL_FORMAT__YVU2P422;
+ case V4L2_PIX_FMT_YUV422P: return BV_PXP_PS_CTRL_FORMAT__YUV422;
+ case V4L2_PIX_FMT_YUV420: return BV_PXP_PS_CTRL_FORMAT__YUV420;
+ }
+}
+
+static u32 pxp_v4l2_pix_fmt_to_out_format(u32 v4l2_pix_fmt)
+{
+ switch (v4l2_pix_fmt) {
+ case V4L2_PIX_FMT_XBGR32: return BV_PXP_OUT_CTRL_FORMAT__RGB888;
+ case V4L2_PIX_FMT_ABGR32: return BV_PXP_OUT_CTRL_FORMAT__ARGB8888;
+ case V4L2_PIX_FMT_BGR24: return BV_PXP_OUT_CTRL_FORMAT__RGB888P;
+ /* Missing V4L2 pixel formats for ARGB1555 and ARGB4444 */
+ case V4L2_PIX_FMT_RGB555: return BV_PXP_OUT_CTRL_FORMAT__RGB555;
+ case V4L2_PIX_FMT_RGB444: return BV_PXP_OUT_CTRL_FORMAT__RGB444;
+ case V4L2_PIX_FMT_RGB565: return BV_PXP_OUT_CTRL_FORMAT__RGB565;
+ case V4L2_PIX_FMT_YUV32: return BV_PXP_OUT_CTRL_FORMAT__YUV1P444;
+ case V4L2_PIX_FMT_UYVY: return BV_PXP_OUT_CTRL_FORMAT__UYVY1P422;
+ case V4L2_PIX_FMT_VYUY: return BV_PXP_OUT_CTRL_FORMAT__VYUY1P422;
+ case V4L2_PIX_FMT_GREY: return BV_PXP_OUT_CTRL_FORMAT__Y8;
+ default:
+ case V4L2_PIX_FMT_Y4: return BV_PXP_OUT_CTRL_FORMAT__Y4;
+ case V4L2_PIX_FMT_NV16: return BV_PXP_OUT_CTRL_FORMAT__YUV2P422;
+ case V4L2_PIX_FMT_NV12: return BV_PXP_OUT_CTRL_FORMAT__YUV2P420;
+ case V4L2_PIX_FMT_NV61: return BV_PXP_OUT_CTRL_FORMAT__YVU2P422;
+ case V4L2_PIX_FMT_NV21: return BV_PXP_OUT_CTRL_FORMAT__YVU2P420;
+ }
+}
+
+static bool pxp_v4l2_pix_fmt_is_yuv(u32 v4l2_pix_fmt)
+{
+ switch (v4l2_pix_fmt) {
+ case V4L2_PIX_FMT_YUV32:
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_VYUY:
+ case V4L2_PIX_FMT_YVYU:
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV61:
+ case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_YUV422P:
+ case V4L2_PIX_FMT_GREY:
+ case V4L2_PIX_FMT_Y4:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static void pxp_setup_csc(struct pxp_ctx *ctx)
+{
+ struct pxp_dev *dev = ctx->dev;
+ enum v4l2_ycbcr_encoding ycbcr_enc;
+ enum v4l2_quantization quantization;
+
+ if (pxp_v4l2_pix_fmt_is_yuv(ctx->q_data[V4L2_M2M_SRC].fmt->fourcc) &&
+ !pxp_v4l2_pix_fmt_is_yuv(ctx->q_data[V4L2_M2M_DST].fmt->fourcc)) {
+ /*
+ * CSC1 YUV/YCbCr to RGB conversion is implemented as follows:
+ *
+ * |R| |C0 0 C1| |Y + Yoffset |
+ * |G| = |C0 C3 C2| * |Cb + UVoffset|
+ * |B| |C0 C4 0 | |Cr + UVoffset|
+ *
+ * Results are clamped to 0..255.
+ *
+ * BT.601 limited range:
+ *
+ * |R| |1.1644 0.0000 1.5960| |Y - 16 |
+ * |G| = |1.1644 -0.3917 -0.8129| * |Cb - 128|
+ * |B| |1.1644 2.0172 0.0000| |Cr - 128|
+ */
+ static const u32 csc1_coef_bt601_lim[3] = {
+ BM_PXP_CSC1_COEF0_YCBCR_MODE |
+ BF_PXP_CSC1_COEF0_C0(0x12a) | /* 1.1641 (-0.03 %) */
+ BF_PXP_CSC1_COEF0_UV_OFFSET(-128) |
+ BF_PXP_CSC1_COEF0_Y_OFFSET(-16),
+ BF_PXP_CSC1_COEF1_C1(0x198) | /* 1.5938 (-0.23 %) */
+ BF_PXP_CSC1_COEF1_C4(0x204), /* 2.0156 (-0.16 %) */
+ BF_PXP_CSC1_COEF2_C2(0x730) | /* -0.8125 (+0.04 %) */
+ BF_PXP_CSC1_COEF2_C3(0x79c), /* -0.3906 (+0.11 %) */
+ };
+ /*
+ * BT.601 full range:
+ *
+ * |R| |1.0000 0.0000 1.4020| |Y + 0 |
+ * |G| = |1.0000 -0.3441 -0.7141| * |Cb - 128|
+ * |B| |1.0000 1.7720 0.0000| |Cr - 128|
+ */
+ static const u32 csc1_coef_bt601_full[3] = {
+ BM_PXP_CSC1_COEF0_YCBCR_MODE |
+ BF_PXP_CSC1_COEF0_C0(0x100) | /* 1.0000 (+0.00 %) */
+ BF_PXP_CSC1_COEF0_UV_OFFSET(-128) |
+ BF_PXP_CSC1_COEF0_Y_OFFSET(0),
+ BF_PXP_CSC1_COEF1_C1(0x166) | /* 1.3984 (-0.36 %) */
+ BF_PXP_CSC1_COEF1_C4(0x1c5), /* 1.7695 (-0.25 %) */
+ BF_PXP_CSC1_COEF2_C2(0x74a) | /* -0.7109 (+0.32 %) */
+ BF_PXP_CSC1_COEF2_C3(0x7a8), /* -0.3438 (+0.04 %) */
+ };
+ /*
+ * Rec.709 limited range:
+ *
+ * |R| |1.1644 0.0000 1.7927| |Y - 16 |
+ * |G| = |1.1644 -0.2132 -0.5329| * |Cb - 128|
+ * |B| |1.1644 2.1124 0.0000| |Cr - 128|
+ */
+ static const u32 csc1_coef_rec709_lim[3] = {
+ BM_PXP_CSC1_COEF0_YCBCR_MODE |
+ BF_PXP_CSC1_COEF0_C0(0x12a) | /* 1.1641 (-0.03 %) */
+ BF_PXP_CSC1_COEF0_UV_OFFSET(-128) |
+ BF_PXP_CSC1_COEF0_Y_OFFSET(-16),
+ BF_PXP_CSC1_COEF1_C1(0x1ca) | /* 1.7891 (-0.37 %) */
+ BF_PXP_CSC1_COEF1_C4(0x21c), /* 2.1094 (-0.30 %) */
+ BF_PXP_CSC1_COEF2_C2(0x778) | /* -0.5312 (+0.16 %) */
+ BF_PXP_CSC1_COEF2_C3(0x7ca), /* -0.2109 (+0.23 %) */
+ };
+ /*
+ * Rec.709 full range:
+ *
+ * |R| |1.0000 0.0000 1.5748| |Y + 0 |
+ * |G| = |1.0000 -0.1873 -0.4681| * |Cb - 128|
+ * |B| |1.0000 1.8556 0.0000| |Cr - 128|
+ */
+ static const u32 csc1_coef_rec709_full[3] = {
+ BM_PXP_CSC1_COEF0_YCBCR_MODE |
+ BF_PXP_CSC1_COEF0_C0(0x100) | /* 1.0000 (+0.00 %) */
+ BF_PXP_CSC1_COEF0_UV_OFFSET(-128) |
+ BF_PXP_CSC1_COEF0_Y_OFFSET(0),
+ BF_PXP_CSC1_COEF1_C1(0x193) | /* 1.5742 (-0.06 %) */
+ BF_PXP_CSC1_COEF1_C4(0x1db), /* 1.8555 (-0.01 %) */
+ BF_PXP_CSC1_COEF2_C2(0x789) | /* -0.4648 (+0.33 %) */
+ BF_PXP_CSC1_COEF2_C3(0x7d1), /* -0.1836 (+0.37 %) */
+ };
+ /*
+ * BT.2020 limited range:
+ *
+ * |R| |1.1644 0.0000 1.6787| |Y - 16 |
+ * |G| = |1.1644 -0.1874 -0.6505| * |Cb - 128|
+ * |B| |1.1644 2.1418 0.0000| |Cr - 128|
+ */
+ static const u32 csc1_coef_bt2020_lim[3] = {
+ BM_PXP_CSC1_COEF0_YCBCR_MODE |
+ BF_PXP_CSC1_COEF0_C0(0x12a) | /* 1.1641 (-0.03 %) */
+ BF_PXP_CSC1_COEF0_UV_OFFSET(-128) |
+ BF_PXP_CSC1_COEF0_Y_OFFSET(-16),
+ BF_PXP_CSC1_COEF1_C1(0x1ad) | /* 1.6758 (-0.29 %) */
+ BF_PXP_CSC1_COEF1_C4(0x224), /* 2.1406 (-0.11 %) */
+ BF_PXP_CSC1_COEF2_C2(0x75a) | /* -0.6484 (+0.20 %) */
+ BF_PXP_CSC1_COEF2_C3(0x7d1), /* -0.1836 (+0.38 %) */
+ };
+ /*
+ * BT.2020 full range:
+ *
+ * |R| |1.0000 0.0000 1.4746| |Y + 0 |
+ * |G| = |1.0000 -0.1646 -0.5714| * |Cb - 128|
+ * |B| |1.0000 1.8814 0.0000| |Cr - 128|
+ */
+ static const u32 csc1_coef_bt2020_full[3] = {
+ BM_PXP_CSC1_COEF0_YCBCR_MODE |
+ BF_PXP_CSC1_COEF0_C0(0x100) | /* 1.0000 (+0.00 %) */
+ BF_PXP_CSC1_COEF0_UV_OFFSET(-128) |
+ BF_PXP_CSC1_COEF0_Y_OFFSET(0),
+ BF_PXP_CSC1_COEF1_C1(0x179) | /* 1.4727 (-0.19 %) */
+ BF_PXP_CSC1_COEF1_C4(0x1e1), /* 1.8789 (-0.25 %) */
+ BF_PXP_CSC1_COEF2_C2(0x76e) | /* -0.5703 (+0.11 %) */
+ BF_PXP_CSC1_COEF2_C3(0x7d6), /* -0.1641 (+0.05 %) */
+ };
+ /*
+ * SMPTE 240m limited range:
+ *
+ * |R| |1.1644 0.0000 1.7937| |Y - 16 |
+ * |G| = |1.1644 -0.2565 -0.5427| * |Cb - 128|
+ * |B| |1.1644 2.0798 0.0000| |Cr - 128|
+ */
+ static const u32 csc1_coef_smpte240m_lim[3] = {
+ BM_PXP_CSC1_COEF0_YCBCR_MODE |
+ BF_PXP_CSC1_COEF0_C0(0x12a) | /* 1.1641 (-0.03 %) */
+ BF_PXP_CSC1_COEF0_UV_OFFSET(-128) |
+ BF_PXP_CSC1_COEF0_Y_OFFSET(-16),
+ BF_PXP_CSC1_COEF1_C1(0x1cb) | /* 1.7930 (-0.07 %) */
+ BF_PXP_CSC1_COEF1_C4(0x214), /* 2.0781 (-0.17 %) */
+ BF_PXP_CSC1_COEF2_C2(0x776) | /* -0.5391 (+0.36 %) */
+ BF_PXP_CSC1_COEF2_C3(0x7bf), /* -0.2539 (+0.26 %) */
+ };
+ /*
+ * SMPTE 240m full range:
+ *
+ * |R| |1.0000 0.0000 1.5756| |Y + 0 |
+ * |G| = |1.0000 -0.2253 -0.4767| * |Cb - 128|
+ * |B| |1.0000 1.8270 0.0000| |Cr - 128|
+ */
+ static const u32 csc1_coef_smpte240m_full[3] = {
+ BM_PXP_CSC1_COEF0_YCBCR_MODE |
+ BF_PXP_CSC1_COEF0_C0(0x100) | /* 1.0000 (+0.00 %) */
+ BF_PXP_CSC1_COEF0_UV_OFFSET(-128) |
+ BF_PXP_CSC1_COEF0_Y_OFFSET(0),
+ BF_PXP_CSC1_COEF1_C1(0x193) | /* 1.5742 (-0.14 %) */
+ BF_PXP_CSC1_COEF1_C4(0x1d3), /* 1.8242 (-0.28 %) */
+ BF_PXP_CSC1_COEF2_C2(0x786) | /* -0.4766 (+0.01 %) */
+ BF_PXP_CSC1_COEF2_C3(0x7c7), /* -0.2227 (+0.26 %) */
+ };
+ const u32 *csc1_coef;
+
+ ycbcr_enc = ctx->q_data[V4L2_M2M_SRC].ycbcr_enc;
+ quantization = ctx->q_data[V4L2_M2M_SRC].quant;
+
+ if (ycbcr_enc == V4L2_YCBCR_ENC_601) {
+ if (quantization == V4L2_QUANTIZATION_FULL_RANGE)
+ csc1_coef = csc1_coef_bt601_full;
+ else
+ csc1_coef = csc1_coef_bt601_lim;
+ } else if (ycbcr_enc == V4L2_YCBCR_ENC_709) {
+ if (quantization == V4L2_QUANTIZATION_FULL_RANGE)
+ csc1_coef = csc1_coef_rec709_full;
+ else
+ csc1_coef = csc1_coef_rec709_lim;
+ } else if (ycbcr_enc == V4L2_YCBCR_ENC_BT2020) {
+ if (quantization == V4L2_QUANTIZATION_FULL_RANGE)
+ csc1_coef = csc1_coef_bt2020_full;
+ else
+ csc1_coef = csc1_coef_bt2020_lim;
+ } else {
+ if (quantization == V4L2_QUANTIZATION_FULL_RANGE)
+ csc1_coef = csc1_coef_smpte240m_full;
+ else
+ csc1_coef = csc1_coef_smpte240m_lim;
+ }
+
+ writel(csc1_coef[0], dev->mmio + HW_PXP_CSC1_COEF0);
+ writel(csc1_coef[1], dev->mmio + HW_PXP_CSC1_COEF1);
+ writel(csc1_coef[2], dev->mmio + HW_PXP_CSC1_COEF2);
+ } else {
+ writel(BM_PXP_CSC1_COEF0_BYPASS, dev->mmio + HW_PXP_CSC1_COEF0);
+ }
+
+ if (!pxp_v4l2_pix_fmt_is_yuv(ctx->q_data[V4L2_M2M_SRC].fmt->fourcc) &&
+ pxp_v4l2_pix_fmt_is_yuv(ctx->q_data[V4L2_M2M_DST].fmt->fourcc)) {
+ /*
+ * CSC2 RGB to YUV/YCbCr conversion is implemented as follows:
+ *
+ * |Y | |A1 A2 A3| |R| |D1|
+ * |Cb| = |B1 B2 B3| * |G| + |D2|
+ * |Cr| |C1 C2 C3| |B| |D3|
+ *
+ * Results are clamped to 0..255.
+ *
+ * BT.601 limited range:
+ *
+ * |Y | | 0.2568 0.5041 0.0979| |R| |16 |
+ * |Cb| = |-0.1482 -0.2910 0.4392| * |G| + |128|
+ * |Cr| | 0.4392 0.4392 -0.3678| |B| |128|
+ */
+ static const u32 csc2_coef_bt601_lim[6] = {
+ BF_PXP_CSC2_COEF0_A2(0x081) | /* 0.5039 (-0.02 %) */
+ BF_PXP_CSC2_COEF0_A1(0x041), /* 0.2539 (-0.29 %) */
+ BF_PXP_CSC2_COEF1_B1(0x7db) | /* -0.1445 (+0.37 %) */
+ BF_PXP_CSC2_COEF1_A3(0x019), /* 0.0977 (-0.02 %) */
+ BF_PXP_CSC2_COEF2_B3(0x070) | /* 0.4375 (-0.17 %) */
+ BF_PXP_CSC2_COEF2_B2(0x7b6), /* -0.2891 (+0.20 %) */
+ BF_PXP_CSC2_COEF3_C2(0x7a2) | /* -0.3672 (+0.06 %) */
+ BF_PXP_CSC2_COEF3_C1(0x070), /* 0.4375 (-0.17 %) */
+ BF_PXP_CSC2_COEF4_D1(16) |
+ BF_PXP_CSC2_COEF4_C3(0x7ee), /* -0.0703 (+0.11 %) */
+ BF_PXP_CSC2_COEF5_D3(128) |
+ BF_PXP_CSC2_COEF5_D2(128),
+ };
+ /*
+ * BT.601 full range:
+ *
+ * |Y | | 0.2990 0.5870 0.1140| |R| |0 |
+ * |Cb| = |-0.1687 -0.3313 0.5000| * |G| + |128|
+ * |Cr| | 0.5000 0.5000 -0.4187| |B| |128|
+ */
+ static const u32 csc2_coef_bt601_full[6] = {
+ BF_PXP_CSC2_COEF0_A2(0x096) | /* 0.5859 (-0.11 %) */
+ BF_PXP_CSC2_COEF0_A1(0x04c), /* 0.2969 (-0.21 %) */
+ BF_PXP_CSC2_COEF1_B1(0x7d5) | /* -0.1680 (+0.07 %) */
+ BF_PXP_CSC2_COEF1_A3(0x01d), /* 0.1133 (-0.07 %) */
+ BF_PXP_CSC2_COEF2_B3(0x080) | /* 0.5000 (+0.00 %) */
+ BF_PXP_CSC2_COEF2_B2(0x7ac), /* -0.3281 (+0.32 %) */
+ BF_PXP_CSC2_COEF3_C2(0x795) | /* -0.4180 (+0.07 %) */
+ BF_PXP_CSC2_COEF3_C1(0x080), /* 0.5000 (+0.00 %) */
+ BF_PXP_CSC2_COEF4_D1(0) |
+ BF_PXP_CSC2_COEF4_C3(0x7ec), /* -0.0781 (+0.32 %) */
+ BF_PXP_CSC2_COEF5_D3(128) |
+ BF_PXP_CSC2_COEF5_D2(128),
+ };
+ /*
+ * Rec.709 limited range:
+ *
+ * |Y | | 0.1826 0.6142 0.0620| |R| |16 |
+ * |Cb| = |-0.1007 -0.3385 0.4392| * |G| + |128|
+ * |Cr| | 0.4392 0.4392 -0.3990| |B| |128|
+ */
+ static const u32 csc2_coef_rec709_lim[6] = {
+ BF_PXP_CSC2_COEF0_A2(0x09d) | /* 0.6133 (-0.09 %) */
+ BF_PXP_CSC2_COEF0_A1(0x02e), /* 0.1797 (-0.29 %) */
+ BF_PXP_CSC2_COEF1_B1(0x7e7) | /* -0.0977 (+0.30 %) */
+ BF_PXP_CSC2_COEF1_A3(0x00f), /* 0.0586 (-0.34 %) */
+ BF_PXP_CSC2_COEF2_B3(0x070) | /* 0.4375 (-0.17 %) */
+ BF_PXP_CSC2_COEF2_B2(0x7aa), /* -0.3359 (+0.26 %) */
+ BF_PXP_CSC2_COEF3_C2(0x79a) | /* -0.3984 (+0.05 %) */
+ BF_PXP_CSC2_COEF3_C1(0x070), /* 0.4375 (-0.17 %) */
+ BF_PXP_CSC2_COEF4_D1(16) |
+ BF_PXP_CSC2_COEF4_C3(0x7f6), /* -0.0391 (+0.12 %) */
+ BF_PXP_CSC2_COEF5_D3(128) |
+ BF_PXP_CSC2_COEF5_D2(128),
+ };
+ /*
+ * Rec.709 full range:
+ *
+ * |Y | | 0.2126 0.7152 0.0722| |R| |0 |
+ * |Cb| = |-0.1146 -0.3854 0.5000| * |G| + |128|
+ * |Cr| | 0.5000 0.5000 -0.4542| |B| |128|
+ */
+ static const u32 csc2_coef_rec709_full[6] = {
+ BF_PXP_CSC2_COEF0_A2(0x0b7) | /* 0.7148 (-0.04 %) */
+ BF_PXP_CSC2_COEF0_A1(0x036), /* 0.2109 (-0.17 %) */
+ BF_PXP_CSC2_COEF1_B1(0x7e3) | /* -0.1133 (+0.13 %) */
+ BF_PXP_CSC2_COEF1_A3(0x012), /* 0.0703 (-0.19 %) */
+ BF_PXP_CSC2_COEF2_B3(0x080) | /* 0.5000 (+0.00 %) */
+ BF_PXP_CSC2_COEF2_B2(0x79e), /* -0.3828 (+0.26 %) */
+ BF_PXP_CSC2_COEF3_C2(0x78c) | /* -0.4531 (+0.11 %) */
+ BF_PXP_CSC2_COEF3_C1(0x080), /* 0.5000 (+0.00 %) */
+ BF_PXP_CSC2_COEF4_D1(0) |
+ BF_PXP_CSC2_COEF4_C3(0x7f5), /* -0.0430 (+0.28 %) */
+ BF_PXP_CSC2_COEF5_D3(128) |
+ BF_PXP_CSC2_COEF5_D2(128),
+ };
+ /*
+ * BT.2020 limited range:
+ *
+ * |Y | | 0.2256 0.5823 0.0509| |R| |16 |
+ * |Cb| = |-0.1226 -0.3166 0.4392| * |G| + |128|
+ * |Cr| | 0.4392 0.4392 -0.4039| |B| |128|
+ */
+ static const u32 csc2_coef_bt2020_lim[6] = {
+ BF_PXP_CSC2_COEF0_A2(0x095) | /* 0.5820 (-0.03 %) */
+ BF_PXP_CSC2_COEF0_A1(0x039), /* 0.2227 (-0.30 %) */
+ BF_PXP_CSC2_COEF1_B1(0x7e1) | /* -0.1211 (+0.15 %) */
+ BF_PXP_CSC2_COEF1_A3(0x00d), /* 0.0508 (-0.01 %) */
+ BF_PXP_CSC2_COEF2_B3(0x070) | /* 0.4375 (-0.17 %) */
+ BF_PXP_CSC2_COEF2_B2(0x7af), /* -0.3164 (+0.02 %) */
+ BF_PXP_CSC2_COEF3_C2(0x799) | /* -0.4023 (+0.16 %) */
+ BF_PXP_CSC2_COEF3_C1(0x070), /* 0.4375 (-0.17 %) */
+ BF_PXP_CSC2_COEF4_D1(16) |
+ BF_PXP_CSC2_COEF4_C3(0x7f7), /* -0.0352 (+0.02 %) */
+ BF_PXP_CSC2_COEF5_D3(128) |
+ BF_PXP_CSC2_COEF5_D2(128),
+ };
+ /*
+ * BT.2020 full range:
+ *
+ * |Y | | 0.2627 0.6780 0.0593| |R| |0 |
+ * |Cb| = |-0.1396 -0.3604 0.5000| * |G| + |128|
+ * |Cr| | 0.5000 0.5000 -0.4598| |B| |128|
+ */
+ static const u32 csc2_coef_bt2020_full[6] = {
+ BF_PXP_CSC2_COEF0_A2(0x0ad) | /* 0.6758 (-0.22 %) */
+ BF_PXP_CSC2_COEF0_A1(0x043), /* 0.2617 (-0.10 %) */
+ BF_PXP_CSC2_COEF1_B1(0x7dd) | /* -0.1367 (+0.29 %) */
+ BF_PXP_CSC2_COEF1_A3(0x00f), /* 0.0586 (-0.07 %) */
+ BF_PXP_CSC2_COEF2_B3(0x080) | /* 0.5000 (+0.00 %) */
+ BF_PXP_CSC2_COEF2_B2(0x7a4), /* -0.3594 (+0.10 %) */
+ BF_PXP_CSC2_COEF3_C2(0x78b) | /* -0.4570 (+0.28 %) */
+ BF_PXP_CSC2_COEF3_C1(0x080), /* 0.5000 (+0.00 %) */
+ BF_PXP_CSC2_COEF4_D1(0) |
+ BF_PXP_CSC2_COEF4_C3(0x7f6), /* -0.0391 (+0.11 %) */
+ BF_PXP_CSC2_COEF5_D3(128) |
+ BF_PXP_CSC2_COEF5_D2(128),
+ };
+ /*
+ * SMPTE 240m limited range:
+ *
+ * |Y | | 0.1821 0.6020 0.0747| |R| |16 |
+ * |Cb| = |-0.1019 -0.3373 0.4392| * |G| + |128|
+ * |Cr| | 0.4392 0.4392 -0.3909| |B| |128|
+ */
+ static const u32 csc2_coef_smpte240m_lim[6] = {
+ BF_PXP_CSC2_COEF0_A2(0x09a) | /* 0.6016 (-0.05 %) */
+ BF_PXP_CSC2_COEF0_A1(0x02e), /* 0.1797 (-0.24 %) */
+ BF_PXP_CSC2_COEF1_B1(0x7e6) | /* -0.1016 (+0.03 %) */
+ BF_PXP_CSC2_COEF1_A3(0x013), /* 0.0742 (-0.05 %) */
+ BF_PXP_CSC2_COEF2_B3(0x070) | /* 0.4375 (-0.17 %) */
+ BF_PXP_CSC2_COEF2_B2(0x7aa), /* -0.3359 (+0.14 %) */
+ BF_PXP_CSC2_COEF3_C2(0x79c) | /* -0.3906 (+0.03 %) */
+ BF_PXP_CSC2_COEF3_C1(0x070), /* 0.4375 (-0.17 %) */
+ BF_PXP_CSC2_COEF4_D1(16) |
+ BF_PXP_CSC2_COEF4_C3(0x7f4), /* -0.0469 (+0.14 %) */
+ BF_PXP_CSC2_COEF5_D3(128) |
+ BF_PXP_CSC2_COEF5_D2(128),
+ };
+ /*
+ * SMPTE 240m full range:
+ *
+ * |Y | | 0.2120 0.7010 0.0870| |R| |0 |
+ * |Cb| = |-0.1160 -0.3840 0.5000| * |G| + |128|
+ * |Cr| | 0.5000 0.5000 -0.4450| |B| |128|
+ */
+ static const u32 csc2_coef_smpte240m_full[6] = {
+ BF_PXP_CSC2_COEF0_A2(0x0b3) | /* 0.6992 (-0.18 %) */
+ BF_PXP_CSC2_COEF0_A1(0x036), /* 0.2109 (-0.11 %) */
+ BF_PXP_CSC2_COEF1_B1(0x7e3) | /* -0.1133 (+0.27 %) */
+ BF_PXP_CSC2_COEF1_A3(0x016), /* 0.0859 (-0.11 %) */
+ BF_PXP_CSC2_COEF2_B3(0x080) | /* 0.5000 (+0.00 %) */
+ BF_PXP_CSC2_COEF2_B2(0x79e), /* -0.3828 (+0.12 %) */
+ BF_PXP_CSC2_COEF3_C2(0x78f) | /* -0.4414 (+0.36 %) */
+ BF_PXP_CSC2_COEF3_C1(0x080), /* 0.5000 (+0.00 %) */
+ BF_PXP_CSC2_COEF4_D1(0) |
+ BF_PXP_CSC2_COEF4_C3(0x7f2), /* -0.0547 (+0.03 %) */
+ BF_PXP_CSC2_COEF5_D3(128) |
+ BF_PXP_CSC2_COEF5_D2(128),
+ };
+ const u32 *csc2_coef;
+ u32 csc2_ctrl;
+
+ ycbcr_enc = ctx->q_data[V4L2_M2M_DST].ycbcr_enc;
+ quantization = ctx->q_data[V4L2_M2M_DST].quant;
+
+ if (ycbcr_enc == V4L2_YCBCR_ENC_601) {
+ if (quantization == V4L2_QUANTIZATION_FULL_RANGE)
+ csc2_coef = csc2_coef_bt601_full;
+ else
+ csc2_coef = csc2_coef_bt601_lim;
+ } else if (ycbcr_enc == V4L2_YCBCR_ENC_709) {
+ if (quantization == V4L2_QUANTIZATION_FULL_RANGE)
+ csc2_coef = csc2_coef_rec709_full;
+ else
+ csc2_coef = csc2_coef_rec709_lim;
+ } else if (ycbcr_enc == V4L2_YCBCR_ENC_709) {
+ if (quantization == V4L2_QUANTIZATION_FULL_RANGE)
+ csc2_coef = csc2_coef_bt2020_full;
+ else
+ csc2_coef = csc2_coef_bt2020_lim;
+ } else {
+ if (quantization == V4L2_QUANTIZATION_FULL_RANGE)
+ csc2_coef = csc2_coef_smpte240m_full;
+ else
+ csc2_coef = csc2_coef_smpte240m_lim;
+ }
+ if (quantization == V4L2_QUANTIZATION_FULL_RANGE) {
+ csc2_ctrl = BV_PXP_CSC2_CTRL_CSC_MODE__RGB2YUV <<
+ BP_PXP_CSC2_CTRL_CSC_MODE;
+ } else {
+ csc2_ctrl = BV_PXP_CSC2_CTRL_CSC_MODE__RGB2YCbCr <<
+ BP_PXP_CSC2_CTRL_CSC_MODE;
+ }
+
+ writel(csc2_ctrl, dev->mmio + HW_PXP_CSC2_CTRL);
+ writel(csc2_coef[0], dev->mmio + HW_PXP_CSC2_COEF0);
+ writel(csc2_coef[1], dev->mmio + HW_PXP_CSC2_COEF1);
+ writel(csc2_coef[2], dev->mmio + HW_PXP_CSC2_COEF2);
+ writel(csc2_coef[3], dev->mmio + HW_PXP_CSC2_COEF3);
+ writel(csc2_coef[4], dev->mmio + HW_PXP_CSC2_COEF4);
+ writel(csc2_coef[5], dev->mmio + HW_PXP_CSC2_COEF5);
+ } else {
+ writel(BM_PXP_CSC2_CTRL_BYPASS, dev->mmio + HW_PXP_CSC2_CTRL);
+ }
+}
+
+static int pxp_start(struct pxp_ctx *ctx, struct vb2_v4l2_buffer *in_vb,
+ struct vb2_v4l2_buffer *out_vb)
+{
+ struct pxp_dev *dev = ctx->dev;
+ struct pxp_q_data *q_data;
+ u32 src_width, src_height, src_stride, src_fourcc;
+ u32 dst_width, dst_height, dst_stride, dst_fourcc;
+ dma_addr_t p_in, p_out;
+ u32 ctrl, out_ctrl, out_buf, out_buf2, out_pitch, out_lrc, out_ps_ulc;
+ u32 out_ps_lrc;
+ u32 ps_ctrl, ps_buf, ps_ubuf, ps_vbuf, ps_pitch, ps_scale, ps_offset;
+ u32 as_ulc, as_lrc;
+ u32 y_size;
+ u32 decx, decy, xscale, yscale;
+
+ q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+
+ src_width = ctx->q_data[V4L2_M2M_SRC].width;
+ dst_width = ctx->q_data[V4L2_M2M_DST].width;
+ src_height = ctx->q_data[V4L2_M2M_SRC].height;
+ dst_height = ctx->q_data[V4L2_M2M_DST].height;
+ src_stride = ctx->q_data[V4L2_M2M_SRC].bytesperline;
+ dst_stride = ctx->q_data[V4L2_M2M_DST].bytesperline;
+ src_fourcc = ctx->q_data[V4L2_M2M_SRC].fmt->fourcc;
+ dst_fourcc = ctx->q_data[V4L2_M2M_DST].fmt->fourcc;
+
+ p_in = vb2_dma_contig_plane_dma_addr(&in_vb->vb2_buf, 0);
+ p_out = vb2_dma_contig_plane_dma_addr(&out_vb->vb2_buf, 0);
+
+ if (!p_in || !p_out) {
+ v4l2_err(&dev->v4l2_dev,
+ "Acquiring DMA addresses of buffers failed\n");
+ return -EFAULT;
+ }
+
+ out_vb->sequence =
+ get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE)->sequence++;
+ in_vb->sequence = q_data->sequence++;
+ out_vb->vb2_buf.timestamp = in_vb->vb2_buf.timestamp;
+
+ if (in_vb->flags & V4L2_BUF_FLAG_TIMECODE)
+ out_vb->timecode = in_vb->timecode;
+ out_vb->field = in_vb->field;
+ out_vb->flags = in_vb->flags &
+ (V4L2_BUF_FLAG_TIMECODE |
+ V4L2_BUF_FLAG_KEYFRAME |
+ V4L2_BUF_FLAG_PFRAME |
+ V4L2_BUF_FLAG_BFRAME |
+ V4L2_BUF_FLAG_TSTAMP_SRC_MASK);
+
+ /* Rotation disabled, 8x8 block size */
+ ctrl = BF_PXP_CTRL_VFLIP0(!!(ctx->mode & MEM2MEM_VFLIP)) |
+ BF_PXP_CTRL_HFLIP0(!!(ctx->mode & MEM2MEM_HFLIP));
+ /* Always write alpha value as V4L2_CID_ALPHA_COMPONENT */
+ out_ctrl = BF_PXP_OUT_CTRL_ALPHA(ctx->alpha_component) |
+ BF_PXP_OUT_CTRL_ALPHA_OUTPUT(1) |
+ pxp_v4l2_pix_fmt_to_out_format(dst_fourcc);
+ out_buf = p_out;
+ switch (dst_fourcc) {
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV61:
+ out_buf2 = out_buf + dst_stride * dst_height;
+ break;
+ default:
+ out_buf2 = 0;
+ }
+
+ out_pitch = BF_PXP_OUT_PITCH_PITCH(dst_stride);
+ out_lrc = BF_PXP_OUT_LRC_X(dst_width - 1) |
+ BF_PXP_OUT_LRC_Y(dst_height - 1);
+ /* PS covers whole output */
+ out_ps_ulc = BF_PXP_OUT_PS_ULC_X(0) | BF_PXP_OUT_PS_ULC_Y(0);
+ out_ps_lrc = BF_PXP_OUT_PS_LRC_X(dst_width - 1) |
+ BF_PXP_OUT_PS_LRC_Y(dst_height - 1);
+ /* no AS */
+ as_ulc = BF_PXP_OUT_AS_ULC_X(1) | BF_PXP_OUT_AS_ULC_Y(1);
+ as_lrc = BF_PXP_OUT_AS_LRC_X(0) | BF_PXP_OUT_AS_LRC_Y(0);
+
+ decx = (src_width <= dst_width) ? 0 : ilog2(src_width / dst_width);
+ decy = (src_height <= dst_height) ? 0 : ilog2(src_height / dst_height);
+ ps_ctrl = BF_PXP_PS_CTRL_DECX(decx) | BF_PXP_PS_CTRL_DECY(decy) |
+ pxp_v4l2_pix_fmt_to_ps_format(src_fourcc);
+ ps_buf = p_in;
+ y_size = src_stride * src_height;
+ switch (src_fourcc) {
+ case V4L2_PIX_FMT_YUV420:
+ ps_ubuf = ps_buf + y_size;
+ ps_vbuf = ps_ubuf + y_size / 4;
+ break;
+ case V4L2_PIX_FMT_YUV422P:
+ ps_ubuf = ps_buf + y_size;
+ ps_vbuf = ps_ubuf + y_size / 2;
+ break;
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV61:
+ ps_ubuf = ps_buf + y_size;
+ ps_vbuf = 0;
+ break;
+ case V4L2_PIX_FMT_GREY:
+ case V4L2_PIX_FMT_Y4:
+ ps_ubuf = 0;
+ /* In grayscale mode, ps_vbuf contents are reused as CbCr */
+ ps_vbuf = 0x8080;
+ break;
+ default:
+ ps_ubuf = 0;
+ ps_vbuf = 0;
+ break;
+ }
+ ps_pitch = BF_PXP_PS_PITCH_PITCH(src_stride);
+ if (decx) {
+ xscale = (src_width >> decx) * 0x1000 / dst_width;
+ } else {
+ switch (src_fourcc) {
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_VYUY:
+ case V4L2_PIX_FMT_YVYU:
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV61:
+ case V4L2_PIX_FMT_YUV422P:
+ case V4L2_PIX_FMT_YUV420:
+ /*
+ * This avoids sampling past the right edge for
+ * horizontally chroma subsampled formats.
+ */
+ xscale = (src_width - 2) * 0x1000 / (dst_width - 1);
+ break;
+ default:
+ xscale = (src_width - 1) * 0x1000 / (dst_width - 1);
+ break;
+ }
+ }
+ if (decy)
+ yscale = (src_height >> decy) * 0x1000 / dst_height;
+ else
+ yscale = (src_height - 1) * 0x1000 / (dst_height - 1);
+ ps_scale = BF_PXP_PS_SCALE_YSCALE(yscale) |
+ BF_PXP_PS_SCALE_XSCALE(xscale);
+ ps_offset = BF_PXP_PS_OFFSET_YOFFSET(0) | BF_PXP_PS_OFFSET_XOFFSET(0);
+
+ writel(ctrl, dev->mmio + HW_PXP_CTRL);
+ /* skip STAT */
+ writel(out_ctrl, dev->mmio + HW_PXP_OUT_CTRL);
+ writel(out_buf, dev->mmio + HW_PXP_OUT_BUF);
+ writel(out_buf2, dev->mmio + HW_PXP_OUT_BUF2);
+ writel(out_pitch, dev->mmio + HW_PXP_OUT_PITCH);
+ writel(out_lrc, dev->mmio + HW_PXP_OUT_LRC);
+ writel(out_ps_ulc, dev->mmio + HW_PXP_OUT_PS_ULC);
+ writel(out_ps_lrc, dev->mmio + HW_PXP_OUT_PS_LRC);
+ writel(as_ulc, dev->mmio + HW_PXP_OUT_AS_ULC);
+ writel(as_lrc, dev->mmio + HW_PXP_OUT_AS_LRC);
+ writel(ps_ctrl, dev->mmio + HW_PXP_PS_CTRL);
+ writel(ps_buf, dev->mmio + HW_PXP_PS_BUF);
+ writel(ps_ubuf, dev->mmio + HW_PXP_PS_UBUF);
+ writel(ps_vbuf, dev->mmio + HW_PXP_PS_VBUF);
+ writel(ps_pitch, dev->mmio + HW_PXP_PS_PITCH);
+ writel(0x00ffffff, dev->mmio + HW_PXP_PS_BACKGROUND_0);
+ writel(ps_scale, dev->mmio + HW_PXP_PS_SCALE);
+ writel(ps_offset, dev->mmio + HW_PXP_PS_OFFSET);
+ /* disable processed surface color keying */
+ writel(0x00ffffff, dev->mmio + HW_PXP_PS_CLRKEYLOW_0);
+ writel(0x00000000, dev->mmio + HW_PXP_PS_CLRKEYHIGH_0);
+
+ /* disable alpha surface color keying */
+ writel(0x00ffffff, dev->mmio + HW_PXP_AS_CLRKEYLOW_0);
+ writel(0x00000000, dev->mmio + HW_PXP_AS_CLRKEYHIGH_0);
+
+ /* setup CSC */
+ pxp_setup_csc(ctx);
+
+ /* bypass LUT */
+ writel(BM_PXP_LUT_CTRL_BYPASS, dev->mmio + HW_PXP_LUT_CTRL);
+
+ writel(BF_PXP_DATA_PATH_CTRL0_MUX15_SEL(0)|
+ BF_PXP_DATA_PATH_CTRL0_MUX14_SEL(1)|
+ BF_PXP_DATA_PATH_CTRL0_MUX13_SEL(0)|
+ BF_PXP_DATA_PATH_CTRL0_MUX12_SEL(0)|
+ BF_PXP_DATA_PATH_CTRL0_MUX11_SEL(0)|
+ BF_PXP_DATA_PATH_CTRL0_MUX10_SEL(0)|
+ BF_PXP_DATA_PATH_CTRL0_MUX9_SEL(1)|
+ BF_PXP_DATA_PATH_CTRL0_MUX8_SEL(0)|
+ BF_PXP_DATA_PATH_CTRL0_MUX7_SEL(0)|
+ BF_PXP_DATA_PATH_CTRL0_MUX6_SEL(0)|
+ BF_PXP_DATA_PATH_CTRL0_MUX5_SEL(0)|
+ BF_PXP_DATA_PATH_CTRL0_MUX4_SEL(0)|
+ BF_PXP_DATA_PATH_CTRL0_MUX3_SEL(0)|
+ BF_PXP_DATA_PATH_CTRL0_MUX2_SEL(0)|
+ BF_PXP_DATA_PATH_CTRL0_MUX1_SEL(0)|
+ BF_PXP_DATA_PATH_CTRL0_MUX0_SEL(0),
+ dev->mmio + HW_PXP_DATA_PATH_CTRL0);
+ writel(BF_PXP_DATA_PATH_CTRL1_MUX17_SEL(1) |
+ BF_PXP_DATA_PATH_CTRL1_MUX16_SEL(1),
+ dev->mmio + HW_PXP_DATA_PATH_CTRL1);
+
+ writel(0xffff, dev->mmio + HW_PXP_IRQ_MASK);
+
+ /* ungate, enable PS/AS/OUT and PXP operation */
+ writel(BM_PXP_CTRL_IRQ_ENABLE, dev->mmio + HW_PXP_CTRL_SET);
+ writel(BM_PXP_CTRL_ENABLE | BM_PXP_CTRL_ENABLE_CSC2 |
+ BM_PXP_CTRL_ENABLE_LUT | BM_PXP_CTRL_ENABLE_ROTATE0 |
+ BM_PXP_CTRL_ENABLE_PS_AS_OUT, dev->mmio + HW_PXP_CTRL_SET);
+
+ return 0;
+}
+
+static void pxp_job_finish(struct pxp_dev *dev)
+{
+ struct pxp_ctx *curr_ctx;
+ struct vb2_v4l2_buffer *src_vb, *dst_vb;
+ unsigned long flags;
+
+ curr_ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);
+
+ if (curr_ctx == NULL) {
+ pr_err("Instance released before the end of transaction\n");
+ return;
+ }
+
+ src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
+ dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
+
+ spin_lock_irqsave(&dev->irqlock, flags);
+ v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
+ v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+
+ dprintk(curr_ctx->dev, "Finishing transaction\n");
+ v4l2_m2m_job_finish(dev->m2m_dev, curr_ctx->fh.m2m_ctx);
+}
+
+/*
+ * mem2mem callbacks
+ */
+static void pxp_device_run(void *priv)
+{
+ struct pxp_ctx *ctx = priv;
+ struct vb2_v4l2_buffer *src_buf, *dst_buf;
+
+ src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+ dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+
+ pxp_start(ctx, src_buf, dst_buf);
+}
+
+static int pxp_job_ready(void *priv)
+{
+ struct pxp_ctx *ctx = priv;
+
+ if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) < 1 ||
+ v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) < 1) {
+ dprintk(ctx->dev, "Not enough buffers available\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+static void pxp_job_abort(void *priv)
+{
+ struct pxp_ctx *ctx = priv;
+
+ /* Will cancel the transaction in the next interrupt handler */
+ ctx->aborting = 1;
+}
+
+/*
+ * interrupt handler
+ */
+static irqreturn_t pxp_irq_handler(int irq, void *dev_id)
+{
+ struct pxp_dev *dev = dev_id;
+ u32 stat;
+
+ stat = readl(dev->mmio + HW_PXP_STAT);
+
+ if (stat & BM_PXP_STAT_IRQ0) {
+ /* we expect x = 0, y = height, irq0 = 1 */
+ if (stat & ~(BM_PXP_STAT_BLOCKX | BM_PXP_STAT_BLOCKY |
+ BM_PXP_STAT_IRQ0))
+ dprintk(dev, "%s: stat = 0x%08x\n", __func__, stat);
+ writel(BM_PXP_STAT_IRQ0, dev->mmio + HW_PXP_STAT_CLR);
+
+ pxp_job_finish(dev);
+ } else {
+ u32 irq = readl(dev->mmio + HW_PXP_IRQ);
+
+ dprintk(dev, "%s: stat = 0x%08x\n", __func__, stat);
+ dprintk(dev, "%s: irq = 0x%08x\n", __func__, irq);
+
+ writel(irq, dev->mmio + HW_PXP_IRQ_CLR);
+ }
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * video ioctls
+ */
+static int pxp_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ strlcpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver));
+ strlcpy(cap->card, MEM2MEM_NAME, sizeof(cap->card));
+ snprintf(cap->bus_info, sizeof(cap->bus_info),
+ "platform:%s", MEM2MEM_NAME);
+ return 0;
+}
+
+static int pxp_enum_fmt(struct v4l2_fmtdesc *f, u32 type)
+{
+ int i, num;
+ struct pxp_fmt *fmt;
+
+ num = 0;
+
+ for (i = 0; i < NUM_FORMATS; ++i) {
+ if (formats[i].types & type) {
+ /* index-th format of type type found ? */
+ if (num == f->index)
+ break;
+ /*
+ * Correct type but haven't reached our index yet,
+ * just increment per-type index
+ */
+ ++num;
+ }
+ }
+
+ if (i < NUM_FORMATS) {
+ /* Format found */
+ fmt = &formats[i];
+ f->pixelformat = fmt->fourcc;
+ return 0;
+ }
+
+ /* Format not found */
+ return -EINVAL;
+}
+
+static int pxp_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ return pxp_enum_fmt(f, MEM2MEM_CAPTURE);
+}
+
+static int pxp_enum_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ return pxp_enum_fmt(f, MEM2MEM_OUTPUT);
+}
+
+static int pxp_g_fmt(struct pxp_ctx *ctx, struct v4l2_format *f)
+{
+ struct vb2_queue *vq;
+ struct pxp_q_data *q_data;
+
+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+ if (!vq)
+ return -EINVAL;
+
+ q_data = get_q_data(ctx, f->type);
+
+ f->fmt.pix.width = q_data->width;
+ f->fmt.pix.height = q_data->height;
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+ f->fmt.pix.pixelformat = q_data->fmt->fourcc;
+ f->fmt.pix.bytesperline = q_data->bytesperline;
+ f->fmt.pix.sizeimage = q_data->sizeimage;
+ f->fmt.pix.colorspace = ctx->colorspace;
+ f->fmt.pix.xfer_func = ctx->xfer_func;
+ f->fmt.pix.ycbcr_enc = q_data->ycbcr_enc;
+ f->fmt.pix.quantization = q_data->quant;
+
+ return 0;
+}
+
+static int pxp_g_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ return pxp_g_fmt(file2ctx(file), f);
+}
+
+static int pxp_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ return pxp_g_fmt(file2ctx(file), f);
+}
+
+static inline u32 pxp_bytesperline(struct pxp_fmt *fmt, u32 width)
+{
+ switch (fmt->fourcc) {
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_YUV422P:
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV61:
+ return width;
+ default:
+ return (width * fmt->depth) >> 3;
+ }
+}
+
+static inline u32 pxp_sizeimage(struct pxp_fmt *fmt, u32 width, u32 height)
+{
+ return (fmt->depth * width * height) >> 3;
+}
+
+static int pxp_try_fmt(struct v4l2_format *f, struct pxp_fmt *fmt)
+{
+ v4l_bound_align_image(&f->fmt.pix.width, MIN_W, MAX_W, ALIGN_W,
+ &f->fmt.pix.height, MIN_H, MAX_H, ALIGN_H, 0);
+
+ f->fmt.pix.bytesperline = pxp_bytesperline(fmt, f->fmt.pix.width);
+ f->fmt.pix.sizeimage = pxp_sizeimage(fmt, f->fmt.pix.width,
+ f->fmt.pix.height);
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+static void
+pxp_fixup_colorimetry_cap(struct pxp_ctx *ctx, u32 dst_fourcc,
+ enum v4l2_ycbcr_encoding *ycbcr_enc,
+ enum v4l2_quantization *quantization)
+{
+ bool dst_is_yuv = pxp_v4l2_pix_fmt_is_yuv(dst_fourcc);
+
+ if (pxp_v4l2_pix_fmt_is_yuv(ctx->q_data[V4L2_M2M_SRC].fmt->fourcc) ==
+ dst_is_yuv) {
+ /*
+ * There is no support for conversion between different YCbCr
+ * encodings or between RGB limited and full range.
+ */
+ *ycbcr_enc = ctx->q_data[V4L2_M2M_SRC].ycbcr_enc;
+ *quantization = ctx->q_data[V4L2_M2M_SRC].quant;
+ } else {
+ *ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(ctx->colorspace);
+ *quantization = V4L2_MAP_QUANTIZATION_DEFAULT(!dst_is_yuv,
+ ctx->colorspace,
+ *ycbcr_enc);
+ }
+}
+
+static int pxp_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct pxp_fmt *fmt;
+ struct pxp_ctx *ctx = file2ctx(file);
+
+ fmt = find_format(f);
+ if (!fmt) {
+ f->fmt.pix.pixelformat = formats[0].fourcc;
+ fmt = find_format(f);
+ }
+ if (!(fmt->types & MEM2MEM_CAPTURE)) {
+ v4l2_err(&ctx->dev->v4l2_dev,
+ "Fourcc format (0x%08x) invalid.\n",
+ f->fmt.pix.pixelformat);
+ return -EINVAL;
+ }
+
+ f->fmt.pix.colorspace = ctx->colorspace;
+ f->fmt.pix.xfer_func = ctx->xfer_func;
+
+ pxp_fixup_colorimetry_cap(ctx, fmt->fourcc,
+ &f->fmt.pix.ycbcr_enc,
+ &f->fmt.pix.quantization);
+
+ return pxp_try_fmt(f, fmt);
+}
+
+static int pxp_try_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct pxp_fmt *fmt;
+ struct pxp_ctx *ctx = file2ctx(file);
+
+ fmt = find_format(f);
+ if (!fmt) {
+ f->fmt.pix.pixelformat = formats[0].fourcc;
+ fmt = find_format(f);
+ }
+ if (!(fmt->types & MEM2MEM_OUTPUT)) {
+ v4l2_err(&ctx->dev->v4l2_dev,
+ "Fourcc format (0x%08x) invalid.\n",
+ f->fmt.pix.pixelformat);
+ return -EINVAL;
+ }
+
+ if (!f->fmt.pix.colorspace)
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
+
+ return pxp_try_fmt(f, fmt);
+}
+
+static int pxp_s_fmt(struct pxp_ctx *ctx, struct v4l2_format *f)
+{
+ struct pxp_q_data *q_data;
+ struct vb2_queue *vq;
+
+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+ if (!vq)
+ return -EINVAL;
+
+ q_data = get_q_data(ctx, f->type);
+ if (!q_data)
+ return -EINVAL;
+
+ if (vb2_is_busy(vq)) {
+ v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__);
+ return -EBUSY;
+ }
+
+ q_data->fmt = find_format(f);
+ q_data->width = f->fmt.pix.width;
+ q_data->height = f->fmt.pix.height;
+ q_data->bytesperline = f->fmt.pix.bytesperline;
+ q_data->sizeimage = f->fmt.pix.sizeimage;
+
+ dprintk(ctx->dev,
+ "Setting format for type %d, wxh: %dx%d, fmt: %d\n",
+ f->type, q_data->width, q_data->height, q_data->fmt->fourcc);
+
+ return 0;
+}
+
+static int pxp_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct pxp_ctx *ctx = file2ctx(file);
+ int ret;
+
+ ret = pxp_try_fmt_vid_cap(file, priv, f);
+ if (ret)
+ return ret;
+
+ ret = pxp_s_fmt(file2ctx(file), f);
+ if (ret)
+ return ret;
+
+ ctx->q_data[V4L2_M2M_DST].ycbcr_enc = f->fmt.pix.ycbcr_enc;
+ ctx->q_data[V4L2_M2M_DST].quant = f->fmt.pix.quantization;
+
+ return 0;
+}
+
+static int pxp_s_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct pxp_ctx *ctx = file2ctx(file);
+ int ret;
+
+ ret = pxp_try_fmt_vid_out(file, priv, f);
+ if (ret)
+ return ret;
+
+ ret = pxp_s_fmt(file2ctx(file), f);
+ if (ret)
+ return ret;
+
+ ctx->colorspace = f->fmt.pix.colorspace;
+ ctx->xfer_func = f->fmt.pix.xfer_func;
+ ctx->q_data[V4L2_M2M_SRC].ycbcr_enc = f->fmt.pix.ycbcr_enc;
+ ctx->q_data[V4L2_M2M_SRC].quant = f->fmt.pix.quantization;
+
+ pxp_fixup_colorimetry_cap(ctx, ctx->q_data[V4L2_M2M_DST].fmt->fourcc,
+ &ctx->q_data[V4L2_M2M_DST].ycbcr_enc,
+ &ctx->q_data[V4L2_M2M_DST].quant);
+
+ return 0;
+}
+
+static int pxp_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct pxp_ctx *ctx =
+ container_of(ctrl->handler, struct pxp_ctx, hdl);
+
+ switch (ctrl->id) {
+ case V4L2_CID_HFLIP:
+ if (ctrl->val)
+ ctx->mode |= MEM2MEM_HFLIP;
+ else
+ ctx->mode &= ~MEM2MEM_HFLIP;
+ break;
+
+ case V4L2_CID_VFLIP:
+ if (ctrl->val)
+ ctx->mode |= MEM2MEM_VFLIP;
+ else
+ ctx->mode &= ~MEM2MEM_VFLIP;
+ break;
+
+ case V4L2_CID_ALPHA_COMPONENT:
+ ctx->alpha_component = ctrl->val;
+ break;
+
+ default:
+ v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops pxp_ctrl_ops = {
+ .s_ctrl = pxp_s_ctrl,
+};
+
+static const struct v4l2_ioctl_ops pxp_ioctl_ops = {
+ .vidioc_querycap = pxp_querycap,
+
+ .vidioc_enum_fmt_vid_cap = pxp_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = pxp_g_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = pxp_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = pxp_s_fmt_vid_cap,
+
+ .vidioc_enum_fmt_vid_out = pxp_enum_fmt_vid_out,
+ .vidioc_g_fmt_vid_out = pxp_g_fmt_vid_out,
+ .vidioc_try_fmt_vid_out = pxp_try_fmt_vid_out,
+ .vidioc_s_fmt_vid_out = pxp_s_fmt_vid_out,
+
+ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
+ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
+ .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
+ .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
+ .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
+ .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
+ .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
+
+ .vidioc_streamon = v4l2_m2m_ioctl_streamon,
+ .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
+
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+/*
+ * Queue operations
+ */
+static int pxp_queue_setup(struct vb2_queue *vq,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], struct device *alloc_devs[])
+{
+ struct pxp_ctx *ctx = vb2_get_drv_priv(vq);
+ struct pxp_q_data *q_data;
+ unsigned int size, count = *nbuffers;
+
+ q_data = get_q_data(ctx, vq->type);
+
+ size = q_data->sizeimage;
+
+ *nbuffers = count;
+
+ if (*nplanes)
+ return sizes[0] < size ? -EINVAL : 0;
+
+ *nplanes = 1;
+ sizes[0] = size;
+
+ dprintk(ctx->dev, "get %d buffer(s) of size %d each.\n", count, size);
+
+ return 0;
+}
+
+static int pxp_buf_prepare(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct pxp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct pxp_dev *dev = ctx->dev;
+ struct pxp_q_data *q_data;
+
+ dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type);
+
+ q_data = get_q_data(ctx, vb->vb2_queue->type);
+ if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
+ if (vbuf->field == V4L2_FIELD_ANY)
+ vbuf->field = V4L2_FIELD_NONE;
+ if (vbuf->field != V4L2_FIELD_NONE) {
+ dprintk(dev, "%s field isn't supported\n", __func__);
+ return -EINVAL;
+ }
+ }
+
+ if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
+ dprintk(dev, "%s data will not fit into plane (%lu < %lu)\n",
+ __func__, vb2_plane_size(vb, 0),
+ (long)q_data->sizeimage);
+ return -EINVAL;
+ }
+
+ vb2_set_plane_payload(vb, 0, q_data->sizeimage);
+
+ return 0;
+}
+
+static void pxp_buf_queue(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct pxp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+ v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
+}
+
+static int pxp_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct pxp_ctx *ctx = vb2_get_drv_priv(q);
+ struct pxp_q_data *q_data = get_q_data(ctx, q->type);
+
+ q_data->sequence = 0;
+ return 0;
+}
+
+static void pxp_stop_streaming(struct vb2_queue *q)
+{
+ struct pxp_ctx *ctx = vb2_get_drv_priv(q);
+ struct vb2_v4l2_buffer *vbuf;
+ unsigned long flags;
+
+ for (;;) {
+ if (V4L2_TYPE_IS_OUTPUT(q->type))
+ vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+ else
+ vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+ if (vbuf == NULL)
+ return;
+ spin_lock_irqsave(&ctx->dev->irqlock, flags);
+ v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
+ spin_unlock_irqrestore(&ctx->dev->irqlock, flags);
+ }
+}
+
+static const struct vb2_ops pxp_qops = {
+ .queue_setup = pxp_queue_setup,
+ .buf_prepare = pxp_buf_prepare,
+ .buf_queue = pxp_buf_queue,
+ .start_streaming = pxp_start_streaming,
+ .stop_streaming = pxp_stop_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+};
+
+static int queue_init(void *priv, struct vb2_queue *src_vq,
+ struct vb2_queue *dst_vq)
+{
+ struct pxp_ctx *ctx = priv;
+ int ret;
+
+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+ src_vq->drv_priv = ctx;
+ src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ src_vq->ops = &pxp_qops;
+ src_vq->mem_ops = &vb2_dma_contig_memops;
+ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ src_vq->lock = &ctx->dev->dev_mutex;
+ src_vq->dev = ctx->dev->v4l2_dev.dev;
+
+ ret = vb2_queue_init(src_vq);
+ if (ret)
+ return ret;
+
+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+ dst_vq->drv_priv = ctx;
+ dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ dst_vq->ops = &pxp_qops;
+ dst_vq->mem_ops = &vb2_dma_contig_memops;
+ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ dst_vq->lock = &ctx->dev->dev_mutex;
+ dst_vq->dev = ctx->dev->v4l2_dev.dev;
+
+ return vb2_queue_init(dst_vq);
+}
+
+/*
+ * File operations
+ */
+static int pxp_open(struct file *file)
+{
+ struct pxp_dev *dev = video_drvdata(file);
+ struct pxp_ctx *ctx = NULL;
+ struct v4l2_ctrl_handler *hdl;
+ int rc = 0;
+
+ if (mutex_lock_interruptible(&dev->dev_mutex))
+ return -ERESTARTSYS;
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx) {
+ rc = -ENOMEM;
+ goto open_unlock;
+ }
+
+ v4l2_fh_init(&ctx->fh, video_devdata(file));
+ file->private_data = &ctx->fh;
+ ctx->dev = dev;
+ hdl = &ctx->hdl;
+ v4l2_ctrl_handler_init(hdl, 4);
+ v4l2_ctrl_new_std(hdl, &pxp_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(hdl, &pxp_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(hdl, &pxp_ctrl_ops, V4L2_CID_ALPHA_COMPONENT,
+ 0, 255, 1, 255);
+ if (hdl->error) {
+ rc = hdl->error;
+ v4l2_ctrl_handler_free(hdl);
+ kfree(ctx);
+ goto open_unlock;
+ }
+ ctx->fh.ctrl_handler = hdl;
+ v4l2_ctrl_handler_setup(hdl);
+
+ ctx->q_data[V4L2_M2M_SRC].fmt = &formats[0];
+ ctx->q_data[V4L2_M2M_SRC].width = 640;
+ ctx->q_data[V4L2_M2M_SRC].height = 480;
+ ctx->q_data[V4L2_M2M_SRC].bytesperline =
+ pxp_bytesperline(&formats[0], 640);
+ ctx->q_data[V4L2_M2M_SRC].sizeimage =
+ pxp_sizeimage(&formats[0], 640, 480);
+ ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC];
+ ctx->colorspace = V4L2_COLORSPACE_REC709;
+
+ ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
+
+ if (IS_ERR(ctx->fh.m2m_ctx)) {
+ rc = PTR_ERR(ctx->fh.m2m_ctx);
+
+ v4l2_ctrl_handler_free(hdl);
+ v4l2_fh_exit(&ctx->fh);
+ kfree(ctx);
+ goto open_unlock;
+ }
+
+ v4l2_fh_add(&ctx->fh);
+ atomic_inc(&dev->num_inst);
+
+ dprintk(dev, "Created instance: %p, m2m_ctx: %p\n",
+ ctx, ctx->fh.m2m_ctx);
+
+open_unlock:
+ mutex_unlock(&dev->dev_mutex);
+ return rc;
+}
+
+static int pxp_release(struct file *file)
+{
+ struct pxp_dev *dev = video_drvdata(file);
+ struct pxp_ctx *ctx = file2ctx(file);
+
+ dprintk(dev, "Releasing instance %p\n", ctx);
+
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+ v4l2_ctrl_handler_free(&ctx->hdl);
+ mutex_lock(&dev->dev_mutex);
+ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+ mutex_unlock(&dev->dev_mutex);
+ kfree(ctx);
+
+ atomic_dec(&dev->num_inst);
+
+ return 0;
+}
+
+static const struct v4l2_file_operations pxp_fops = {
+ .owner = THIS_MODULE,
+ .open = pxp_open,
+ .release = pxp_release,
+ .poll = v4l2_m2m_fop_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = v4l2_m2m_fop_mmap,
+};
+
+static const struct video_device pxp_videodev = {
+ .name = MEM2MEM_NAME,
+ .vfl_dir = VFL_DIR_M2M,
+ .fops = &pxp_fops,
+ .device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING,
+ .ioctl_ops = &pxp_ioctl_ops,
+ .minor = -1,
+ .release = video_device_release_empty,
+};
+
+static const struct v4l2_m2m_ops m2m_ops = {
+ .device_run = pxp_device_run,
+ .job_ready = pxp_job_ready,
+ .job_abort = pxp_job_abort,
+};
+
+static void pxp_soft_reset(struct pxp_dev *dev)
+{
+ int ret;
+ u32 val;
+
+ writel(BM_PXP_CTRL_SFTRST, dev->mmio + HW_PXP_CTRL_CLR);
+ writel(BM_PXP_CTRL_CLKGATE, dev->mmio + HW_PXP_CTRL_CLR);
+
+ writel(BM_PXP_CTRL_SFTRST, dev->mmio + HW_PXP_CTRL_SET);
+
+ ret = readl_poll_timeout(dev->mmio + HW_PXP_CTRL, val,
+ val & BM_PXP_CTRL_CLKGATE, 0, 100);
+ if (ret < 0)
+ pr_err("PXP reset timeout\n");
+
+ writel(BM_PXP_CTRL_SFTRST, dev->mmio + HW_PXP_CTRL_CLR);
+ writel(BM_PXP_CTRL_CLKGATE, dev->mmio + HW_PXP_CTRL_CLR);
+}
+
+static int pxp_probe(struct platform_device *pdev)
+{
+ struct pxp_dev *dev;
+ struct resource *res;
+ struct video_device *vfd;
+ int irq;
+ int ret;
+
+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ dev->clk = devm_clk_get(&pdev->dev, "axi");
+ if (IS_ERR(dev->clk)) {
+ ret = PTR_ERR(dev->clk);
+ dev_err(&pdev->dev, "Failed to get clk: %d\n", ret);
+ return ret;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ dev->mmio = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(dev->mmio)) {
+ ret = PTR_ERR(dev->mmio);
+ dev_err(&pdev->dev, "Failed to map register space: %d\n", ret);
+ return ret;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "Failed to get irq resource: %d\n", irq);
+ return irq;
+ }
+
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, pxp_irq_handler,
+ IRQF_ONESHOT, dev_name(&pdev->dev), dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to request irq: %d\n", ret);
+ return ret;
+ }
+
+ clk_prepare_enable(dev->clk);
+ pxp_soft_reset(dev);
+
+ spin_lock_init(&dev->irqlock);
+
+ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+ if (ret)
+ goto err_clk;
+
+ atomic_set(&dev->num_inst, 0);
+ mutex_init(&dev->dev_mutex);
+
+ dev->vfd = pxp_videodev;
+ vfd = &dev->vfd;
+ vfd->lock = &dev->dev_mutex;
+ vfd->v4l2_dev = &dev->v4l2_dev;
+
+ video_set_drvdata(vfd, dev);
+ snprintf(vfd->name, sizeof(vfd->name), "%s", pxp_videodev.name);
+ v4l2_info(&dev->v4l2_dev,
+ "Device registered as /dev/video%d\n", vfd->num);
+
+ platform_set_drvdata(pdev, dev);
+
+ dev->m2m_dev = v4l2_m2m_init(&m2m_ops);
+ if (IS_ERR(dev->m2m_dev)) {
+ v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n");
+ ret = PTR_ERR(dev->m2m_dev);
+ goto err_v4l2;
+ }
+
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
+ goto err_m2m;
+ }
+
+ return 0;
+
+err_m2m:
+ v4l2_m2m_release(dev->m2m_dev);
+err_v4l2:
+ v4l2_device_unregister(&dev->v4l2_dev);
+err_clk:
+ clk_disable_unprepare(dev->clk);
+
+ return ret;
+}
+
+static int pxp_remove(struct platform_device *pdev)
+{
+ struct pxp_dev *dev = platform_get_drvdata(pdev);
+
+ writel(BM_PXP_CTRL_CLKGATE, dev->mmio + HW_PXP_CTRL_SET);
+ writel(BM_PXP_CTRL_SFTRST, dev->mmio + HW_PXP_CTRL_SET);
+
+ clk_disable_unprepare(dev->clk);
+
+ v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME);
+ video_unregister_device(&dev->vfd);
+ v4l2_m2m_release(dev->m2m_dev);
+ v4l2_device_unregister(&dev->v4l2_dev);
+
+ return 0;
+}
+
+static const struct of_device_id pxp_dt_ids[] = {
+ { .compatible = "fsl,imx6ull-pxp", .data = NULL },
+ { },
+};
+MODULE_DEVICE_TABLE(of, pxp_dt_ids);
+
+static struct platform_driver pxp_driver = {
+ .probe = pxp_probe,
+ .remove = pxp_remove,
+ .driver = {
+ .name = MEM2MEM_NAME,
+ .of_match_table = of_match_ptr(pxp_dt_ids),
+ },
+};
+
+module_platform_driver(pxp_driver);
+
+MODULE_DESCRIPTION("i.MX PXP mem2mem scaler/CSC/rotator");
+MODULE_AUTHOR("Philipp Zabel <kernel@pengutronix.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/imx-pxp.h b/drivers/media/platform/imx-pxp.h
new file mode 100644
index 000000000000..44f95c749d2e
--- /dev/null
+++ b/drivers/media/platform/imx-pxp.h
@@ -0,0 +1,1685 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Freescale PXP Register Definitions
+ *
+ * based on pxp_dma_v3.h, Xml Revision: 1.77, Template Revision: 1.3
+ *
+ * Copyright 2014-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+#ifndef __IMX_PXP_H__
+#define __IMX_PXP_H__
+
+#define HW_PXP_CTRL (0x00000000)
+#define HW_PXP_CTRL_SET (0x00000004)
+#define HW_PXP_CTRL_CLR (0x00000008)
+#define HW_PXP_CTRL_TOG (0x0000000c)
+
+#define BM_PXP_CTRL_SFTRST 0x80000000
+#define BF_PXP_CTRL_SFTRST(v) \
+ (((v) << 31) & BM_PXP_CTRL_SFTRST)
+#define BM_PXP_CTRL_CLKGATE 0x40000000
+#define BF_PXP_CTRL_CLKGATE(v) \
+ (((v) << 30) & BM_PXP_CTRL_CLKGATE)
+#define BM_PXP_CTRL_RSVD4 0x20000000
+#define BF_PXP_CTRL_RSVD4(v) \
+ (((v) << 29) & BM_PXP_CTRL_RSVD4)
+#define BM_PXP_CTRL_EN_REPEAT 0x10000000
+#define BF_PXP_CTRL_EN_REPEAT(v) \
+ (((v) << 28) & BM_PXP_CTRL_EN_REPEAT)
+#define BM_PXP_CTRL_ENABLE_ROTATE1 0x08000000
+#define BF_PXP_CTRL_ENABLE_ROTATE1(v) \
+ (((v) << 27) & BM_PXP_CTRL_ENABLE_ROTATE1)
+#define BM_PXP_CTRL_ENABLE_ROTATE0 0x04000000
+#define BF_PXP_CTRL_ENABLE_ROTATE0(v) \
+ (((v) << 26) & BM_PXP_CTRL_ENABLE_ROTATE0)
+#define BM_PXP_CTRL_ENABLE_LUT 0x02000000
+#define BF_PXP_CTRL_ENABLE_LUT(v) \
+ (((v) << 25) & BM_PXP_CTRL_ENABLE_LUT)
+#define BM_PXP_CTRL_ENABLE_CSC2 0x01000000
+#define BF_PXP_CTRL_ENABLE_CSC2(v) \
+ (((v) << 24) & BM_PXP_CTRL_ENABLE_CSC2)
+#define BM_PXP_CTRL_BLOCK_SIZE 0x00800000
+#define BF_PXP_CTRL_BLOCK_SIZE(v) \
+ (((v) << 23) & BM_PXP_CTRL_BLOCK_SIZE)
+#define BV_PXP_CTRL_BLOCK_SIZE__8X8 0x0
+#define BV_PXP_CTRL_BLOCK_SIZE__16X16 0x1
+#define BM_PXP_CTRL_RSVD1 0x00400000
+#define BF_PXP_CTRL_RSVD1(v) \
+ (((v) << 22) & BM_PXP_CTRL_RSVD1)
+#define BM_PXP_CTRL_ENABLE_ALPHA_B 0x00200000
+#define BF_PXP_CTRL_ENABLE_ALPHA_B(v) \
+ (((v) << 21) & BM_PXP_CTRL_ENABLE_ALPHA_B)
+#define BM_PXP_CTRL_ENABLE_INPUT_FETCH_STORE 0x00100000
+#define BF_PXP_CTRL_ENABLE_INPUT_FETCH_STORE(v) \
+ (((v) << 20) & BM_PXP_CTRL_ENABLE_INPUT_FETCH_STORE)
+#define BM_PXP_CTRL_ENABLE_WFE_B 0x00080000
+#define BF_PXP_CTRL_ENABLE_WFE_B(v) \
+ (((v) << 19) & BM_PXP_CTRL_ENABLE_WFE_B)
+#define BM_PXP_CTRL_ENABLE_WFE_A 0x00040000
+#define BF_PXP_CTRL_ENABLE_WFE_A(v) \
+ (((v) << 18) & BM_PXP_CTRL_ENABLE_WFE_A)
+#define BM_PXP_CTRL_ENABLE_DITHER 0x00020000
+#define BF_PXP_CTRL_ENABLE_DITHER(v) \
+ (((v) << 17) & BM_PXP_CTRL_ENABLE_DITHER)
+#define BM_PXP_CTRL_ENABLE_PS_AS_OUT 0x00010000
+#define BF_PXP_CTRL_ENABLE_PS_AS_OUT(v) \
+ (((v) << 16) & BM_PXP_CTRL_ENABLE_PS_AS_OUT)
+#define BM_PXP_CTRL_VFLIP1 0x00008000
+#define BF_PXP_CTRL_VFLIP1(v) \
+ (((v) << 15) & BM_PXP_CTRL_VFLIP1)
+#define BM_PXP_CTRL_HFLIP1 0x00004000
+#define BF_PXP_CTRL_HFLIP1(v) \
+ (((v) << 14) & BM_PXP_CTRL_HFLIP1)
+#define BP_PXP_CTRL_ROTATE1 12
+#define BM_PXP_CTRL_ROTATE1 0x00003000
+#define BF_PXP_CTRL_ROTATE1(v) \
+ (((v) << 12) & BM_PXP_CTRL_ROTATE1)
+#define BV_PXP_CTRL_ROTATE1__ROT_0 0x0
+#define BV_PXP_CTRL_ROTATE1__ROT_90 0x1
+#define BV_PXP_CTRL_ROTATE1__ROT_180 0x2
+#define BV_PXP_CTRL_ROTATE1__ROT_270 0x3
+#define BM_PXP_CTRL_VFLIP0 0x00000800
+#define BF_PXP_CTRL_VFLIP0(v) \
+ (((v) << 11) & BM_PXP_CTRL_VFLIP0)
+#define BM_PXP_CTRL_HFLIP0 0x00000400
+#define BF_PXP_CTRL_HFLIP0(v) \
+ (((v) << 10) & BM_PXP_CTRL_HFLIP0)
+#define BP_PXP_CTRL_ROTATE0 8
+#define BM_PXP_CTRL_ROTATE0 0x00000300
+#define BF_PXP_CTRL_ROTATE0(v) \
+ (((v) << 8) & BM_PXP_CTRL_ROTATE0)
+#define BV_PXP_CTRL_ROTATE0__ROT_0 0x0
+#define BV_PXP_CTRL_ROTATE0__ROT_90 0x1
+#define BV_PXP_CTRL_ROTATE0__ROT_180 0x2
+#define BV_PXP_CTRL_ROTATE0__ROT_270 0x3
+#define BP_PXP_CTRL_RSVD0 6
+#define BM_PXP_CTRL_RSVD0 0x000000C0
+#define BF_PXP_CTRL_RSVD0(v) \
+ (((v) << 6) & BM_PXP_CTRL_RSVD0)
+#define BM_PXP_CTRL_HANDSHAKE_ABORT_SKIP 0x00000020
+#define BF_PXP_CTRL_HANDSHAKE_ABORT_SKIP(v) \
+ (((v) << 5) & BM_PXP_CTRL_HANDSHAKE_ABORT_SKIP)
+#define BM_PXP_CTRL_ENABLE_LCD0_HANDSHAKE 0x00000010
+#define BF_PXP_CTRL_ENABLE_LCD0_HANDSHAKE(v) \
+ (((v) << 4) & BM_PXP_CTRL_ENABLE_LCD0_HANDSHAKE)
+#define BM_PXP_CTRL_LUT_DMA_IRQ_ENABLE 0x00000008
+#define BF_PXP_CTRL_LUT_DMA_IRQ_ENABLE(v) \
+ (((v) << 3) & BM_PXP_CTRL_LUT_DMA_IRQ_ENABLE)
+#define BM_PXP_CTRL_NEXT_IRQ_ENABLE 0x00000004
+#define BF_PXP_CTRL_NEXT_IRQ_ENABLE(v) \
+ (((v) << 2) & BM_PXP_CTRL_NEXT_IRQ_ENABLE)
+#define BM_PXP_CTRL_IRQ_ENABLE 0x00000002
+#define BF_PXP_CTRL_IRQ_ENABLE(v) \
+ (((v) << 1) & BM_PXP_CTRL_IRQ_ENABLE)
+#define BM_PXP_CTRL_ENABLE 0x00000001
+#define BF_PXP_CTRL_ENABLE(v) \
+ (((v) << 0) & BM_PXP_CTRL_ENABLE)
+
+#define HW_PXP_STAT (0x00000010)
+#define HW_PXP_STAT_SET (0x00000014)
+#define HW_PXP_STAT_CLR (0x00000018)
+#define HW_PXP_STAT_TOG (0x0000001c)
+
+#define BP_PXP_STAT_BLOCKX 24
+#define BM_PXP_STAT_BLOCKX 0xFF000000
+#define BF_PXP_STAT_BLOCKX(v) \
+ (((v) << 24) & BM_PXP_STAT_BLOCKX)
+#define BP_PXP_STAT_BLOCKY 16
+#define BM_PXP_STAT_BLOCKY 0x00FF0000
+#define BF_PXP_STAT_BLOCKY(v) \
+ (((v) << 16) & BM_PXP_STAT_BLOCKY)
+#define BP_PXP_STAT_AXI_ERROR_ID_1 12
+#define BM_PXP_STAT_AXI_ERROR_ID_1 0x0000F000
+#define BF_PXP_STAT_AXI_ERROR_ID_1(v) \
+ (((v) << 12) & BM_PXP_STAT_AXI_ERROR_ID_1)
+#define BM_PXP_STAT_RSVD2 0x00000800
+#define BF_PXP_STAT_RSVD2(v) \
+ (((v) << 11) & BM_PXP_STAT_RSVD2)
+#define BM_PXP_STAT_AXI_READ_ERROR_1 0x00000400
+#define BF_PXP_STAT_AXI_READ_ERROR_1(v) \
+ (((v) << 10) & BM_PXP_STAT_AXI_READ_ERROR_1)
+#define BM_PXP_STAT_AXI_WRITE_ERROR_1 0x00000200
+#define BF_PXP_STAT_AXI_WRITE_ERROR_1(v) \
+ (((v) << 9) & BM_PXP_STAT_AXI_WRITE_ERROR_1)
+#define BM_PXP_STAT_LUT_DMA_LOAD_DONE_IRQ 0x00000100
+#define BF_PXP_STAT_LUT_DMA_LOAD_DONE_IRQ(v) \
+ (((v) << 8) & BM_PXP_STAT_LUT_DMA_LOAD_DONE_IRQ)
+#define BP_PXP_STAT_AXI_ERROR_ID_0 4
+#define BM_PXP_STAT_AXI_ERROR_ID_0 0x000000F0
+#define BF_PXP_STAT_AXI_ERROR_ID_0(v) \
+ (((v) << 4) & BM_PXP_STAT_AXI_ERROR_ID_0)
+#define BM_PXP_STAT_NEXT_IRQ 0x00000008
+#define BF_PXP_STAT_NEXT_IRQ(v) \
+ (((v) << 3) & BM_PXP_STAT_NEXT_IRQ)
+#define BM_PXP_STAT_AXI_READ_ERROR_0 0x00000004
+#define BF_PXP_STAT_AXI_READ_ERROR_0(v) \
+ (((v) << 2) & BM_PXP_STAT_AXI_READ_ERROR_0)
+#define BM_PXP_STAT_AXI_WRITE_ERROR_0 0x00000002
+#define BF_PXP_STAT_AXI_WRITE_ERROR_0(v) \
+ (((v) << 1) & BM_PXP_STAT_AXI_WRITE_ERROR_0)
+#define BM_PXP_STAT_IRQ0 0x00000001
+#define BF_PXP_STAT_IRQ0(v) \
+ (((v) << 0) & BM_PXP_STAT_IRQ0)
+
+#define HW_PXP_OUT_CTRL (0x00000020)
+#define HW_PXP_OUT_CTRL_SET (0x00000024)
+#define HW_PXP_OUT_CTRL_CLR (0x00000028)
+#define HW_PXP_OUT_CTRL_TOG (0x0000002c)
+
+#define BP_PXP_OUT_CTRL_ALPHA 24
+#define BM_PXP_OUT_CTRL_ALPHA 0xFF000000
+#define BF_PXP_OUT_CTRL_ALPHA(v) \
+ (((v) << 24) & BM_PXP_OUT_CTRL_ALPHA)
+#define BM_PXP_OUT_CTRL_ALPHA_OUTPUT 0x00800000
+#define BF_PXP_OUT_CTRL_ALPHA_OUTPUT(v) \
+ (((v) << 23) & BM_PXP_OUT_CTRL_ALPHA_OUTPUT)
+#define BP_PXP_OUT_CTRL_RSVD1 10
+#define BM_PXP_OUT_CTRL_RSVD1 0x007FFC00
+#define BF_PXP_OUT_CTRL_RSVD1(v) \
+ (((v) << 10) & BM_PXP_OUT_CTRL_RSVD1)
+#define BP_PXP_OUT_CTRL_INTERLACED_OUTPUT 8
+#define BM_PXP_OUT_CTRL_INTERLACED_OUTPUT 0x00000300
+#define BF_PXP_OUT_CTRL_INTERLACED_OUTPUT(v) \
+ (((v) << 8) & BM_PXP_OUT_CTRL_INTERLACED_OUTPUT)
+#define BV_PXP_OUT_CTRL_INTERLACED_OUTPUT__PROGRESSIVE 0x0
+#define BV_PXP_OUT_CTRL_INTERLACED_OUTPUT__FIELD0 0x1
+#define BV_PXP_OUT_CTRL_INTERLACED_OUTPUT__FIELD1 0x2
+#define BV_PXP_OUT_CTRL_INTERLACED_OUTPUT__INTERLACED 0x3
+#define BP_PXP_OUT_CTRL_RSVD0 5
+#define BM_PXP_OUT_CTRL_RSVD0 0x000000E0
+#define BF_PXP_OUT_CTRL_RSVD0(v) \
+ (((v) << 5) & BM_PXP_OUT_CTRL_RSVD0)
+#define BP_PXP_OUT_CTRL_FORMAT 0
+#define BM_PXP_OUT_CTRL_FORMAT 0x0000001F
+#define BF_PXP_OUT_CTRL_FORMAT(v) \
+ (((v) << 0) & BM_PXP_OUT_CTRL_FORMAT)
+#define BV_PXP_OUT_CTRL_FORMAT__ARGB8888 0x0
+#define BV_PXP_OUT_CTRL_FORMAT__RGB888 0x4
+#define BV_PXP_OUT_CTRL_FORMAT__RGB888P 0x5
+#define BV_PXP_OUT_CTRL_FORMAT__ARGB1555 0x8
+#define BV_PXP_OUT_CTRL_FORMAT__ARGB4444 0x9
+#define BV_PXP_OUT_CTRL_FORMAT__RGB555 0xC
+#define BV_PXP_OUT_CTRL_FORMAT__RGB444 0xD
+#define BV_PXP_OUT_CTRL_FORMAT__RGB565 0xE
+#define BV_PXP_OUT_CTRL_FORMAT__YUV1P444 0x10
+#define BV_PXP_OUT_CTRL_FORMAT__UYVY1P422 0x12
+#define BV_PXP_OUT_CTRL_FORMAT__VYUY1P422 0x13
+#define BV_PXP_OUT_CTRL_FORMAT__Y8 0x14
+#define BV_PXP_OUT_CTRL_FORMAT__Y4 0x15
+#define BV_PXP_OUT_CTRL_FORMAT__YUV2P422 0x18
+#define BV_PXP_OUT_CTRL_FORMAT__YUV2P420 0x19
+#define BV_PXP_OUT_CTRL_FORMAT__YVU2P422 0x1A
+#define BV_PXP_OUT_CTRL_FORMAT__YVU2P420 0x1B
+
+#define HW_PXP_OUT_BUF (0x00000030)
+
+#define BP_PXP_OUT_BUF_ADDR 0
+#define BM_PXP_OUT_BUF_ADDR 0xFFFFFFFF
+#define BF_PXP_OUT_BUF_ADDR(v) (v)
+
+#define HW_PXP_OUT_BUF2 (0x00000040)
+
+#define BP_PXP_OUT_BUF2_ADDR 0
+#define BM_PXP_OUT_BUF2_ADDR 0xFFFFFFFF
+#define BF_PXP_OUT_BUF2_ADDR(v) (v)
+
+#define HW_PXP_OUT_PITCH (0x00000050)
+
+#define BP_PXP_OUT_PITCH_RSVD 16
+#define BM_PXP_OUT_PITCH_RSVD 0xFFFF0000
+#define BF_PXP_OUT_PITCH_RSVD(v) \
+ (((v) << 16) & BM_PXP_OUT_PITCH_RSVD)
+#define BP_PXP_OUT_PITCH_PITCH 0
+#define BM_PXP_OUT_PITCH_PITCH 0x0000FFFF
+#define BF_PXP_OUT_PITCH_PITCH(v) \
+ (((v) << 0) & BM_PXP_OUT_PITCH_PITCH)
+
+#define HW_PXP_OUT_LRC (0x00000060)
+
+#define BP_PXP_OUT_LRC_RSVD1 30
+#define BM_PXP_OUT_LRC_RSVD1 0xC0000000
+#define BF_PXP_OUT_LRC_RSVD1(v) \
+ (((v) << 30) & BM_PXP_OUT_LRC_RSVD1)
+#define BP_PXP_OUT_LRC_X 16
+#define BM_PXP_OUT_LRC_X 0x3FFF0000
+#define BF_PXP_OUT_LRC_X(v) \
+ (((v) << 16) & BM_PXP_OUT_LRC_X)
+#define BP_PXP_OUT_LRC_RSVD0 14
+#define BM_PXP_OUT_LRC_RSVD0 0x0000C000
+#define BF_PXP_OUT_LRC_RSVD0(v) \
+ (((v) << 14) & BM_PXP_OUT_LRC_RSVD0)
+#define BP_PXP_OUT_LRC_Y 0
+#define BM_PXP_OUT_LRC_Y 0x00003FFF
+#define BF_PXP_OUT_LRC_Y(v) \
+ (((v) << 0) & BM_PXP_OUT_LRC_Y)
+
+#define HW_PXP_OUT_PS_ULC (0x00000070)
+
+#define BP_PXP_OUT_PS_ULC_RSVD1 30
+#define BM_PXP_OUT_PS_ULC_RSVD1 0xC0000000
+#define BF_PXP_OUT_PS_ULC_RSVD1(v) \
+ (((v) << 30) & BM_PXP_OUT_PS_ULC_RSVD1)
+#define BP_PXP_OUT_PS_ULC_X 16
+#define BM_PXP_OUT_PS_ULC_X 0x3FFF0000
+#define BF_PXP_OUT_PS_ULC_X(v) \
+ (((v) << 16) & BM_PXP_OUT_PS_ULC_X)
+#define BP_PXP_OUT_PS_ULC_RSVD0 14
+#define BM_PXP_OUT_PS_ULC_RSVD0 0x0000C000
+#define BF_PXP_OUT_PS_ULC_RSVD0(v) \
+ (((v) << 14) & BM_PXP_OUT_PS_ULC_RSVD0)
+#define BP_PXP_OUT_PS_ULC_Y 0
+#define BM_PXP_OUT_PS_ULC_Y 0x00003FFF
+#define BF_PXP_OUT_PS_ULC_Y(v) \
+ (((v) << 0) & BM_PXP_OUT_PS_ULC_Y)
+
+#define HW_PXP_OUT_PS_LRC (0x00000080)
+
+#define BP_PXP_OUT_PS_LRC_RSVD1 30
+#define BM_PXP_OUT_PS_LRC_RSVD1 0xC0000000
+#define BF_PXP_OUT_PS_LRC_RSVD1(v) \
+ (((v) << 30) & BM_PXP_OUT_PS_LRC_RSVD1)
+#define BP_PXP_OUT_PS_LRC_X 16
+#define BM_PXP_OUT_PS_LRC_X 0x3FFF0000
+#define BF_PXP_OUT_PS_LRC_X(v) \
+ (((v) << 16) & BM_PXP_OUT_PS_LRC_X)
+#define BP_PXP_OUT_PS_LRC_RSVD0 14
+#define BM_PXP_OUT_PS_LRC_RSVD0 0x0000C000
+#define BF_PXP_OUT_PS_LRC_RSVD0(v) \
+ (((v) << 14) & BM_PXP_OUT_PS_LRC_RSVD0)
+#define BP_PXP_OUT_PS_LRC_Y 0
+#define BM_PXP_OUT_PS_LRC_Y 0x00003FFF
+#define BF_PXP_OUT_PS_LRC_Y(v) \
+ (((v) << 0) & BM_PXP_OUT_PS_LRC_Y)
+
+#define HW_PXP_OUT_AS_ULC (0x00000090)
+
+#define BP_PXP_OUT_AS_ULC_RSVD1 30
+#define BM_PXP_OUT_AS_ULC_RSVD1 0xC0000000
+#define BF_PXP_OUT_AS_ULC_RSVD1(v) \
+ (((v) << 30) & BM_PXP_OUT_AS_ULC_RSVD1)
+#define BP_PXP_OUT_AS_ULC_X 16
+#define BM_PXP_OUT_AS_ULC_X 0x3FFF0000
+#define BF_PXP_OUT_AS_ULC_X(v) \
+ (((v) << 16) & BM_PXP_OUT_AS_ULC_X)
+#define BP_PXP_OUT_AS_ULC_RSVD0 14
+#define BM_PXP_OUT_AS_ULC_RSVD0 0x0000C000
+#define BF_PXP_OUT_AS_ULC_RSVD0(v) \
+ (((v) << 14) & BM_PXP_OUT_AS_ULC_RSVD0)
+#define BP_PXP_OUT_AS_ULC_Y 0
+#define BM_PXP_OUT_AS_ULC_Y 0x00003FFF
+#define BF_PXP_OUT_AS_ULC_Y(v) \
+ (((v) << 0) & BM_PXP_OUT_AS_ULC_Y)
+
+#define HW_PXP_OUT_AS_LRC (0x000000a0)
+
+#define BP_PXP_OUT_AS_LRC_RSVD1 30
+#define BM_PXP_OUT_AS_LRC_RSVD1 0xC0000000
+#define BF_PXP_OUT_AS_LRC_RSVD1(v) \
+ (((v) << 30) & BM_PXP_OUT_AS_LRC_RSVD1)
+#define BP_PXP_OUT_AS_LRC_X 16
+#define BM_PXP_OUT_AS_LRC_X 0x3FFF0000
+#define BF_PXP_OUT_AS_LRC_X(v) \
+ (((v) << 16) & BM_PXP_OUT_AS_LRC_X)
+#define BP_PXP_OUT_AS_LRC_RSVD0 14
+#define BM_PXP_OUT_AS_LRC_RSVD0 0x0000C000
+#define BF_PXP_OUT_AS_LRC_RSVD0(v) \
+ (((v) << 14) & BM_PXP_OUT_AS_LRC_RSVD0)
+#define BP_PXP_OUT_AS_LRC_Y 0
+#define BM_PXP_OUT_AS_LRC_Y 0x00003FFF
+#define BF_PXP_OUT_AS_LRC_Y(v) \
+ (((v) << 0) & BM_PXP_OUT_AS_LRC_Y)
+
+#define HW_PXP_PS_CTRL (0x000000b0)
+#define HW_PXP_PS_CTRL_SET (0x000000b4)
+#define HW_PXP_PS_CTRL_CLR (0x000000b8)
+#define HW_PXP_PS_CTRL_TOG (0x000000bc)
+
+#define BP_PXP_PS_CTRL_RSVD1 12
+#define BM_PXP_PS_CTRL_RSVD1 0xFFFFF000
+#define BF_PXP_PS_CTRL_RSVD1(v) \
+ (((v) << 12) & BM_PXP_PS_CTRL_RSVD1)
+#define BP_PXP_PS_CTRL_DECX 10
+#define BM_PXP_PS_CTRL_DECX 0x00000C00
+#define BF_PXP_PS_CTRL_DECX(v) \
+ (((v) << 10) & BM_PXP_PS_CTRL_DECX)
+#define BV_PXP_PS_CTRL_DECX__DISABLE 0x0
+#define BV_PXP_PS_CTRL_DECX__DECX2 0x1
+#define BV_PXP_PS_CTRL_DECX__DECX4 0x2
+#define BV_PXP_PS_CTRL_DECX__DECX8 0x3
+#define BP_PXP_PS_CTRL_DECY 8
+#define BM_PXP_PS_CTRL_DECY 0x00000300
+#define BF_PXP_PS_CTRL_DECY(v) \
+ (((v) << 8) & BM_PXP_PS_CTRL_DECY)
+#define BV_PXP_PS_CTRL_DECY__DISABLE 0x0
+#define BV_PXP_PS_CTRL_DECY__DECY2 0x1
+#define BV_PXP_PS_CTRL_DECY__DECY4 0x2
+#define BV_PXP_PS_CTRL_DECY__DECY8 0x3
+#define BM_PXP_PS_CTRL_RSVD0 0x00000080
+#define BF_PXP_PS_CTRL_RSVD0(v) \
+ (((v) << 7) & BM_PXP_PS_CTRL_RSVD0)
+#define BM_PXP_PS_CTRL_WB_SWAP 0x00000040
+#define BF_PXP_PS_CTRL_WB_SWAP(v) \
+ (((v) << 6) & BM_PXP_PS_CTRL_WB_SWAP)
+#define BP_PXP_PS_CTRL_FORMAT 0
+#define BM_PXP_PS_CTRL_FORMAT 0x0000003F
+#define BF_PXP_PS_CTRL_FORMAT(v) \
+ (((v) << 0) & BM_PXP_PS_CTRL_FORMAT)
+#define BV_PXP_PS_CTRL_FORMAT__RGB888 0x4
+#define BV_PXP_PS_CTRL_FORMAT__RGB555 0xC
+#define BV_PXP_PS_CTRL_FORMAT__RGB444 0xD
+#define BV_PXP_PS_CTRL_FORMAT__RGB565 0xE
+#define BV_PXP_PS_CTRL_FORMAT__YUV1P444 0x10
+#define BV_PXP_PS_CTRL_FORMAT__UYVY1P422 0x12
+#define BV_PXP_PS_CTRL_FORMAT__VYUY1P422 0x13
+#define BV_PXP_PS_CTRL_FORMAT__Y8 0x14
+#define BV_PXP_PS_CTRL_FORMAT__Y4 0x15
+#define BV_PXP_PS_CTRL_FORMAT__YUV2P422 0x18
+#define BV_PXP_PS_CTRL_FORMAT__YUV2P420 0x19
+#define BV_PXP_PS_CTRL_FORMAT__YVU2P422 0x1A
+#define BV_PXP_PS_CTRL_FORMAT__YVU2P420 0x1B
+#define BV_PXP_PS_CTRL_FORMAT__YUV422 0x1E
+#define BV_PXP_PS_CTRL_FORMAT__YUV420 0x1F
+
+#define HW_PXP_PS_BUF (0x000000c0)
+
+#define BP_PXP_PS_BUF_ADDR 0
+#define BM_PXP_PS_BUF_ADDR 0xFFFFFFFF
+#define BF_PXP_PS_BUF_ADDR(v) (v)
+
+#define HW_PXP_PS_UBUF (0x000000d0)
+
+#define BP_PXP_PS_UBUF_ADDR 0
+#define BM_PXP_PS_UBUF_ADDR 0xFFFFFFFF
+#define BF_PXP_PS_UBUF_ADDR(v) (v)
+
+#define HW_PXP_PS_VBUF (0x000000e0)
+
+#define BP_PXP_PS_VBUF_ADDR 0
+#define BM_PXP_PS_VBUF_ADDR 0xFFFFFFFF
+#define BF_PXP_PS_VBUF_ADDR(v) (v)
+
+#define HW_PXP_PS_PITCH (0x000000f0)
+
+#define BP_PXP_PS_PITCH_RSVD 16
+#define BM_PXP_PS_PITCH_RSVD 0xFFFF0000
+#define BF_PXP_PS_PITCH_RSVD(v) \
+ (((v) << 16) & BM_PXP_PS_PITCH_RSVD)
+#define BP_PXP_PS_PITCH_PITCH 0
+#define BM_PXP_PS_PITCH_PITCH 0x0000FFFF
+#define BF_PXP_PS_PITCH_PITCH(v) \
+ (((v) << 0) & BM_PXP_PS_PITCH_PITCH)
+
+#define HW_PXP_PS_BACKGROUND_0 (0x00000100)
+
+#define BP_PXP_PS_BACKGROUND_0_RSVD 24
+#define BM_PXP_PS_BACKGROUND_0_RSVD 0xFF000000
+#define BF_PXP_PS_BACKGROUND_0_RSVD(v) \
+ (((v) << 24) & BM_PXP_PS_BACKGROUND_0_RSVD)
+#define BP_PXP_PS_BACKGROUND_0_COLOR 0
+#define BM_PXP_PS_BACKGROUND_0_COLOR 0x00FFFFFF
+#define BF_PXP_PS_BACKGROUND_0_COLOR(v) \
+ (((v) << 0) & BM_PXP_PS_BACKGROUND_0_COLOR)
+
+#define HW_PXP_PS_SCALE (0x00000110)
+
+#define BM_PXP_PS_SCALE_RSVD2 0x80000000
+#define BF_PXP_PS_SCALE_RSVD2(v) \
+ (((v) << 31) & BM_PXP_PS_SCALE_RSVD2)
+#define BP_PXP_PS_SCALE_YSCALE 16
+#define BM_PXP_PS_SCALE_YSCALE 0x7FFF0000
+#define BF_PXP_PS_SCALE_YSCALE(v) \
+ (((v) << 16) & BM_PXP_PS_SCALE_YSCALE)
+#define BM_PXP_PS_SCALE_RSVD1 0x00008000
+#define BF_PXP_PS_SCALE_RSVD1(v) \
+ (((v) << 15) & BM_PXP_PS_SCALE_RSVD1)
+#define BP_PXP_PS_SCALE_XSCALE 0
+#define BM_PXP_PS_SCALE_XSCALE 0x00007FFF
+#define BF_PXP_PS_SCALE_XSCALE(v) \
+ (((v) << 0) & BM_PXP_PS_SCALE_XSCALE)
+
+#define HW_PXP_PS_OFFSET (0x00000120)
+
+#define BP_PXP_PS_OFFSET_RSVD2 28
+#define BM_PXP_PS_OFFSET_RSVD2 0xF0000000
+#define BF_PXP_PS_OFFSET_RSVD2(v) \
+ (((v) << 28) & BM_PXP_PS_OFFSET_RSVD2)
+#define BP_PXP_PS_OFFSET_YOFFSET 16
+#define BM_PXP_PS_OFFSET_YOFFSET 0x0FFF0000
+#define BF_PXP_PS_OFFSET_YOFFSET(v) \
+ (((v) << 16) & BM_PXP_PS_OFFSET_YOFFSET)
+#define BP_PXP_PS_OFFSET_RSVD1 12
+#define BM_PXP_PS_OFFSET_RSVD1 0x0000F000
+#define BF_PXP_PS_OFFSET_RSVD1(v) \
+ (((v) << 12) & BM_PXP_PS_OFFSET_RSVD1)
+#define BP_PXP_PS_OFFSET_XOFFSET 0
+#define BM_PXP_PS_OFFSET_XOFFSET 0x00000FFF
+#define BF_PXP_PS_OFFSET_XOFFSET(v) \
+ (((v) << 0) & BM_PXP_PS_OFFSET_XOFFSET)
+
+#define HW_PXP_PS_CLRKEYLOW_0 (0x00000130)
+
+#define BP_PXP_PS_CLRKEYLOW_0_RSVD1 24
+#define BM_PXP_PS_CLRKEYLOW_0_RSVD1 0xFF000000
+#define BF_PXP_PS_CLRKEYLOW_0_RSVD1(v) \
+ (((v) << 24) & BM_PXP_PS_CLRKEYLOW_0_RSVD1)
+#define BP_PXP_PS_CLRKEYLOW_0_PIXEL 0
+#define BM_PXP_PS_CLRKEYLOW_0_PIXEL 0x00FFFFFF
+#define BF_PXP_PS_CLRKEYLOW_0_PIXEL(v) \
+ (((v) << 0) & BM_PXP_PS_CLRKEYLOW_0_PIXEL)
+
+#define HW_PXP_PS_CLRKEYHIGH_0 (0x00000140)
+
+#define BP_PXP_PS_CLRKEYHIGH_0_RSVD1 24
+#define BM_PXP_PS_CLRKEYHIGH_0_RSVD1 0xFF000000
+#define BF_PXP_PS_CLRKEYHIGH_0_RSVD1(v) \
+ (((v) << 24) & BM_PXP_PS_CLRKEYHIGH_0_RSVD1)
+#define BP_PXP_PS_CLRKEYHIGH_0_PIXEL 0
+#define BM_PXP_PS_CLRKEYHIGH_0_PIXEL 0x00FFFFFF
+#define BF_PXP_PS_CLRKEYHIGH_0_PIXEL(v) \
+ (((v) << 0) & BM_PXP_PS_CLRKEYHIGH_0_PIXEL)
+
+#define HW_PXP_AS_CTRL (0x00000150)
+
+#define BP_PXP_AS_CTRL_RSVD1 22
+#define BM_PXP_AS_CTRL_RSVD1 0xFFC00000
+#define BF_PXP_AS_CTRL_RSVD1(v) \
+ (((v) << 22) & BM_PXP_AS_CTRL_RSVD1)
+#define BM_PXP_AS_CTRL_ALPHA1_INVERT 0x00200000
+#define BF_PXP_AS_CTRL_ALPHA1_INVERT(v) \
+ (((v) << 21) & BM_PXP_AS_CTRL_ALPHA1_INVERT)
+#define BM_PXP_AS_CTRL_ALPHA0_INVERT 0x00100000
+#define BF_PXP_AS_CTRL_ALPHA0_INVERT(v) \
+ (((v) << 20) & BM_PXP_AS_CTRL_ALPHA0_INVERT)
+#define BP_PXP_AS_CTRL_ROP 16
+#define BM_PXP_AS_CTRL_ROP 0x000F0000
+#define BF_PXP_AS_CTRL_ROP(v) \
+ (((v) << 16) & BM_PXP_AS_CTRL_ROP)
+#define BV_PXP_AS_CTRL_ROP__MASKAS 0x0
+#define BV_PXP_AS_CTRL_ROP__MASKNOTAS 0x1
+#define BV_PXP_AS_CTRL_ROP__MASKASNOT 0x2
+#define BV_PXP_AS_CTRL_ROP__MERGEAS 0x3
+#define BV_PXP_AS_CTRL_ROP__MERGENOTAS 0x4
+#define BV_PXP_AS_CTRL_ROP__MERGEASNOT 0x5
+#define BV_PXP_AS_CTRL_ROP__NOTCOPYAS 0x6
+#define BV_PXP_AS_CTRL_ROP__NOT 0x7
+#define BV_PXP_AS_CTRL_ROP__NOTMASKAS 0x8
+#define BV_PXP_AS_CTRL_ROP__NOTMERGEAS 0x9
+#define BV_PXP_AS_CTRL_ROP__XORAS 0xA
+#define BV_PXP_AS_CTRL_ROP__NOTXORAS 0xB
+#define BP_PXP_AS_CTRL_ALPHA 8
+#define BM_PXP_AS_CTRL_ALPHA 0x0000FF00
+#define BF_PXP_AS_CTRL_ALPHA(v) \
+ (((v) << 8) & BM_PXP_AS_CTRL_ALPHA)
+#define BP_PXP_AS_CTRL_FORMAT 4
+#define BM_PXP_AS_CTRL_FORMAT 0x000000F0
+#define BF_PXP_AS_CTRL_FORMAT(v) \
+ (((v) << 4) & BM_PXP_AS_CTRL_FORMAT)
+#define BV_PXP_AS_CTRL_FORMAT__ARGB8888 0x0
+#define BV_PXP_AS_CTRL_FORMAT__RGBA8888 0x1
+#define BV_PXP_AS_CTRL_FORMAT__RGB888 0x4
+#define BV_PXP_AS_CTRL_FORMAT__ARGB1555 0x8
+#define BV_PXP_AS_CTRL_FORMAT__ARGB4444 0x9
+#define BV_PXP_AS_CTRL_FORMAT__RGB555 0xC
+#define BV_PXP_AS_CTRL_FORMAT__RGB444 0xD
+#define BV_PXP_AS_CTRL_FORMAT__RGB565 0xE
+#define BM_PXP_AS_CTRL_ENABLE_COLORKEY 0x00000008
+#define BF_PXP_AS_CTRL_ENABLE_COLORKEY(v) \
+ (((v) << 3) & BM_PXP_AS_CTRL_ENABLE_COLORKEY)
+#define BP_PXP_AS_CTRL_ALPHA_CTRL 1
+#define BM_PXP_AS_CTRL_ALPHA_CTRL 0x00000006
+#define BF_PXP_AS_CTRL_ALPHA_CTRL(v) \
+ (((v) << 1) & BM_PXP_AS_CTRL_ALPHA_CTRL)
+#define BV_PXP_AS_CTRL_ALPHA_CTRL__Embedded 0x0
+#define BV_PXP_AS_CTRL_ALPHA_CTRL__Override 0x1
+#define BV_PXP_AS_CTRL_ALPHA_CTRL__Multiply 0x2
+#define BV_PXP_AS_CTRL_ALPHA_CTRL__ROPs 0x3
+#define BM_PXP_AS_CTRL_RSVD0 0x00000001
+#define BF_PXP_AS_CTRL_RSVD0(v) \
+ (((v) << 0) & BM_PXP_AS_CTRL_RSVD0)
+
+#define HW_PXP_AS_BUF (0x00000160)
+
+#define BP_PXP_AS_BUF_ADDR 0
+#define BM_PXP_AS_BUF_ADDR 0xFFFFFFFF
+#define BF_PXP_AS_BUF_ADDR(v) (v)
+
+#define HW_PXP_AS_PITCH (0x00000170)
+
+#define BP_PXP_AS_PITCH_RSVD 16
+#define BM_PXP_AS_PITCH_RSVD 0xFFFF0000
+#define BF_PXP_AS_PITCH_RSVD(v) \
+ (((v) << 16) & BM_PXP_AS_PITCH_RSVD)
+#define BP_PXP_AS_PITCH_PITCH 0
+#define BM_PXP_AS_PITCH_PITCH 0x0000FFFF
+#define BF_PXP_AS_PITCH_PITCH(v) \
+ (((v) << 0) & BM_PXP_AS_PITCH_PITCH)
+
+#define HW_PXP_AS_CLRKEYLOW_0 (0x00000180)
+
+#define BP_PXP_AS_CLRKEYLOW_0_RSVD1 24
+#define BM_PXP_AS_CLRKEYLOW_0_RSVD1 0xFF000000
+#define BF_PXP_AS_CLRKEYLOW_0_RSVD1(v) \
+ (((v) << 24) & BM_PXP_AS_CLRKEYLOW_0_RSVD1)
+#define BP_PXP_AS_CLRKEYLOW_0_PIXEL 0
+#define BM_PXP_AS_CLRKEYLOW_0_PIXEL 0x00FFFFFF
+#define BF_PXP_AS_CLRKEYLOW_0_PIXEL(v) \
+ (((v) << 0) & BM_PXP_AS_CLRKEYLOW_0_PIXEL)
+
+#define HW_PXP_AS_CLRKEYHIGH_0 (0x00000190)
+
+#define BP_PXP_AS_CLRKEYHIGH_0_RSVD1 24
+#define BM_PXP_AS_CLRKEYHIGH_0_RSVD1 0xFF000000
+#define BF_PXP_AS_CLRKEYHIGH_0_RSVD1(v) \
+ (((v) << 24) & BM_PXP_AS_CLRKEYHIGH_0_RSVD1)
+#define BP_PXP_AS_CLRKEYHIGH_0_PIXEL 0
+#define BM_PXP_AS_CLRKEYHIGH_0_PIXEL 0x00FFFFFF
+#define BF_PXP_AS_CLRKEYHIGH_0_PIXEL(v) \
+ (((v) << 0) & BM_PXP_AS_CLRKEYHIGH_0_PIXEL)
+
+#define HW_PXP_CSC1_COEF0 (0x000001a0)
+
+#define BM_PXP_CSC1_COEF0_YCBCR_MODE 0x80000000
+#define BF_PXP_CSC1_COEF0_YCBCR_MODE(v) \
+ (((v) << 31) & BM_PXP_CSC1_COEF0_YCBCR_MODE)
+#define BM_PXP_CSC1_COEF0_BYPASS 0x40000000
+#define BF_PXP_CSC1_COEF0_BYPASS(v) \
+ (((v) << 30) & BM_PXP_CSC1_COEF0_BYPASS)
+#define BM_PXP_CSC1_COEF0_RSVD1 0x20000000
+#define BF_PXP_CSC1_COEF0_RSVD1(v) \
+ (((v) << 29) & BM_PXP_CSC1_COEF0_RSVD1)
+#define BP_PXP_CSC1_COEF0_C0 18
+#define BM_PXP_CSC1_COEF0_C0 0x1FFC0000
+#define BF_PXP_CSC1_COEF0_C0(v) \
+ (((v) << 18) & BM_PXP_CSC1_COEF0_C0)
+#define BP_PXP_CSC1_COEF0_UV_OFFSET 9
+#define BM_PXP_CSC1_COEF0_UV_OFFSET 0x0003FE00
+#define BF_PXP_CSC1_COEF0_UV_OFFSET(v) \
+ (((v) << 9) & BM_PXP_CSC1_COEF0_UV_OFFSET)
+#define BP_PXP_CSC1_COEF0_Y_OFFSET 0
+#define BM_PXP_CSC1_COEF0_Y_OFFSET 0x000001FF
+#define BF_PXP_CSC1_COEF0_Y_OFFSET(v) \
+ (((v) << 0) & BM_PXP_CSC1_COEF0_Y_OFFSET)
+
+#define HW_PXP_CSC1_COEF1 (0x000001b0)
+
+#define BP_PXP_CSC1_COEF1_RSVD1 27
+#define BM_PXP_CSC1_COEF1_RSVD1 0xF8000000
+#define BF_PXP_CSC1_COEF1_RSVD1(v) \
+ (((v) << 27) & BM_PXP_CSC1_COEF1_RSVD1)
+#define BP_PXP_CSC1_COEF1_C1 16
+#define BM_PXP_CSC1_COEF1_C1 0x07FF0000
+#define BF_PXP_CSC1_COEF1_C1(v) \
+ (((v) << 16) & BM_PXP_CSC1_COEF1_C1)
+#define BP_PXP_CSC1_COEF1_RSVD0 11
+#define BM_PXP_CSC1_COEF1_RSVD0 0x0000F800
+#define BF_PXP_CSC1_COEF1_RSVD0(v) \
+ (((v) << 11) & BM_PXP_CSC1_COEF1_RSVD0)
+#define BP_PXP_CSC1_COEF1_C4 0
+#define BM_PXP_CSC1_COEF1_C4 0x000007FF
+#define BF_PXP_CSC1_COEF1_C4(v) \
+ (((v) << 0) & BM_PXP_CSC1_COEF1_C4)
+
+#define HW_PXP_CSC1_COEF2 (0x000001c0)
+
+#define BP_PXP_CSC1_COEF2_RSVD1 27
+#define BM_PXP_CSC1_COEF2_RSVD1 0xF8000000
+#define BF_PXP_CSC1_COEF2_RSVD1(v) \
+ (((v) << 27) & BM_PXP_CSC1_COEF2_RSVD1)
+#define BP_PXP_CSC1_COEF2_C2 16
+#define BM_PXP_CSC1_COEF2_C2 0x07FF0000
+#define BF_PXP_CSC1_COEF2_C2(v) \
+ (((v) << 16) & BM_PXP_CSC1_COEF2_C2)
+#define BP_PXP_CSC1_COEF2_RSVD0 11
+#define BM_PXP_CSC1_COEF2_RSVD0 0x0000F800
+#define BF_PXP_CSC1_COEF2_RSVD0(v) \
+ (((v) << 11) & BM_PXP_CSC1_COEF2_RSVD0)
+#define BP_PXP_CSC1_COEF2_C3 0
+#define BM_PXP_CSC1_COEF2_C3 0x000007FF
+#define BF_PXP_CSC1_COEF2_C3(v) \
+ (((v) << 0) & BM_PXP_CSC1_COEF2_C3)
+
+#define HW_PXP_CSC2_CTRL (0x000001d0)
+
+#define BP_PXP_CSC2_CTRL_RSVD 3
+#define BM_PXP_CSC2_CTRL_RSVD 0xFFFFFFF8
+#define BF_PXP_CSC2_CTRL_RSVD(v) \
+ (((v) << 3) & BM_PXP_CSC2_CTRL_RSVD)
+#define BP_PXP_CSC2_CTRL_CSC_MODE 1
+#define BM_PXP_CSC2_CTRL_CSC_MODE 0x00000006
+#define BF_PXP_CSC2_CTRL_CSC_MODE(v) \
+ (((v) << 1) & BM_PXP_CSC2_CTRL_CSC_MODE)
+#define BV_PXP_CSC2_CTRL_CSC_MODE__YUV2RGB 0x0
+#define BV_PXP_CSC2_CTRL_CSC_MODE__YCbCr2RGB 0x1
+#define BV_PXP_CSC2_CTRL_CSC_MODE__RGB2YUV 0x2
+#define BV_PXP_CSC2_CTRL_CSC_MODE__RGB2YCbCr 0x3
+#define BM_PXP_CSC2_CTRL_BYPASS 0x00000001
+#define BF_PXP_CSC2_CTRL_BYPASS(v) \
+ (((v) << 0) & BM_PXP_CSC2_CTRL_BYPASS)
+
+#define HW_PXP_CSC2_COEF0 (0x000001e0)
+
+#define BP_PXP_CSC2_COEF0_RSVD1 27
+#define BM_PXP_CSC2_COEF0_RSVD1 0xF8000000
+#define BF_PXP_CSC2_COEF0_RSVD1(v) \
+ (((v) << 27) & BM_PXP_CSC2_COEF0_RSVD1)
+#define BP_PXP_CSC2_COEF0_A2 16
+#define BM_PXP_CSC2_COEF0_A2 0x07FF0000
+#define BF_PXP_CSC2_COEF0_A2(v) \
+ (((v) << 16) & BM_PXP_CSC2_COEF0_A2)
+#define BP_PXP_CSC2_COEF0_RSVD0 11
+#define BM_PXP_CSC2_COEF0_RSVD0 0x0000F800
+#define BF_PXP_CSC2_COEF0_RSVD0(v) \
+ (((v) << 11) & BM_PXP_CSC2_COEF0_RSVD0)
+#define BP_PXP_CSC2_COEF0_A1 0
+#define BM_PXP_CSC2_COEF0_A1 0x000007FF
+#define BF_PXP_CSC2_COEF0_A1(v) \
+ (((v) << 0) & BM_PXP_CSC2_COEF0_A1)
+
+#define HW_PXP_CSC2_COEF1 (0x000001f0)
+
+#define BP_PXP_CSC2_COEF1_RSVD1 27
+#define BM_PXP_CSC2_COEF1_RSVD1 0xF8000000
+#define BF_PXP_CSC2_COEF1_RSVD1(v) \
+ (((v) << 27) & BM_PXP_CSC2_COEF1_RSVD1)
+#define BP_PXP_CSC2_COEF1_B1 16
+#define BM_PXP_CSC2_COEF1_B1 0x07FF0000
+#define BF_PXP_CSC2_COEF1_B1(v) \
+ (((v) << 16) & BM_PXP_CSC2_COEF1_B1)
+#define BP_PXP_CSC2_COEF1_RSVD0 11
+#define BM_PXP_CSC2_COEF1_RSVD0 0x0000F800
+#define BF_PXP_CSC2_COEF1_RSVD0(v) \
+ (((v) << 11) & BM_PXP_CSC2_COEF1_RSVD0)
+#define BP_PXP_CSC2_COEF1_A3 0
+#define BM_PXP_CSC2_COEF1_A3 0x000007FF
+#define BF_PXP_CSC2_COEF1_A3(v) \
+ (((v) << 0) & BM_PXP_CSC2_COEF1_A3)
+
+#define HW_PXP_CSC2_COEF2 (0x00000200)
+
+#define BP_PXP_CSC2_COEF2_RSVD1 27
+#define BM_PXP_CSC2_COEF2_RSVD1 0xF8000000
+#define BF_PXP_CSC2_COEF2_RSVD1(v) \
+ (((v) << 27) & BM_PXP_CSC2_COEF2_RSVD1)
+#define BP_PXP_CSC2_COEF2_B3 16
+#define BM_PXP_CSC2_COEF2_B3 0x07FF0000
+#define BF_PXP_CSC2_COEF2_B3(v) \
+ (((v) << 16) & BM_PXP_CSC2_COEF2_B3)
+#define BP_PXP_CSC2_COEF2_RSVD0 11
+#define BM_PXP_CSC2_COEF2_RSVD0 0x0000F800
+#define BF_PXP_CSC2_COEF2_RSVD0(v) \
+ (((v) << 11) & BM_PXP_CSC2_COEF2_RSVD0)
+#define BP_PXP_CSC2_COEF2_B2 0
+#define BM_PXP_CSC2_COEF2_B2 0x000007FF
+#define BF_PXP_CSC2_COEF2_B2(v) \
+ (((v) << 0) & BM_PXP_CSC2_COEF2_B2)
+
+#define HW_PXP_CSC2_COEF3 (0x00000210)
+
+#define BP_PXP_CSC2_COEF3_RSVD1 27
+#define BM_PXP_CSC2_COEF3_RSVD1 0xF8000000
+#define BF_PXP_CSC2_COEF3_RSVD1(v) \
+ (((v) << 27) & BM_PXP_CSC2_COEF3_RSVD1)
+#define BP_PXP_CSC2_COEF3_C2 16
+#define BM_PXP_CSC2_COEF3_C2 0x07FF0000
+#define BF_PXP_CSC2_COEF3_C2(v) \
+ (((v) << 16) & BM_PXP_CSC2_COEF3_C2)
+#define BP_PXP_CSC2_COEF3_RSVD0 11
+#define BM_PXP_CSC2_COEF3_RSVD0 0x0000F800
+#define BF_PXP_CSC2_COEF3_RSVD0(v) \
+ (((v) << 11) & BM_PXP_CSC2_COEF3_RSVD0)
+#define BP_PXP_CSC2_COEF3_C1 0
+#define BM_PXP_CSC2_COEF3_C1 0x000007FF
+#define BF_PXP_CSC2_COEF3_C1(v) \
+ (((v) << 0) & BM_PXP_CSC2_COEF3_C1)
+
+#define HW_PXP_CSC2_COEF4 (0x00000220)
+
+#define BP_PXP_CSC2_COEF4_RSVD1 25
+#define BM_PXP_CSC2_COEF4_RSVD1 0xFE000000
+#define BF_PXP_CSC2_COEF4_RSVD1(v) \
+ (((v) << 25) & BM_PXP_CSC2_COEF4_RSVD1)
+#define BP_PXP_CSC2_COEF4_D1 16
+#define BM_PXP_CSC2_COEF4_D1 0x01FF0000
+#define BF_PXP_CSC2_COEF4_D1(v) \
+ (((v) << 16) & BM_PXP_CSC2_COEF4_D1)
+#define BP_PXP_CSC2_COEF4_RSVD0 11
+#define BM_PXP_CSC2_COEF4_RSVD0 0x0000F800
+#define BF_PXP_CSC2_COEF4_RSVD0(v) \
+ (((v) << 11) & BM_PXP_CSC2_COEF4_RSVD0)
+#define BP_PXP_CSC2_COEF4_C3 0
+#define BM_PXP_CSC2_COEF4_C3 0x000007FF
+#define BF_PXP_CSC2_COEF4_C3(v) \
+ (((v) << 0) & BM_PXP_CSC2_COEF4_C3)
+
+#define HW_PXP_CSC2_COEF5 (0x00000230)
+
+#define BP_PXP_CSC2_COEF5_RSVD1 25
+#define BM_PXP_CSC2_COEF5_RSVD1 0xFE000000
+#define BF_PXP_CSC2_COEF5_RSVD1(v) \
+ (((v) << 25) & BM_PXP_CSC2_COEF5_RSVD1)
+#define BP_PXP_CSC2_COEF5_D3 16
+#define BM_PXP_CSC2_COEF5_D3 0x01FF0000
+#define BF_PXP_CSC2_COEF5_D3(v) \
+ (((v) << 16) & BM_PXP_CSC2_COEF5_D3)
+#define BP_PXP_CSC2_COEF5_RSVD0 9
+#define BM_PXP_CSC2_COEF5_RSVD0 0x0000FE00
+#define BF_PXP_CSC2_COEF5_RSVD0(v) \
+ (((v) << 9) & BM_PXP_CSC2_COEF5_RSVD0)
+#define BP_PXP_CSC2_COEF5_D2 0
+#define BM_PXP_CSC2_COEF5_D2 0x000001FF
+#define BF_PXP_CSC2_COEF5_D2(v) \
+ (((v) << 0) & BM_PXP_CSC2_COEF5_D2)
+
+#define HW_PXP_LUT_CTRL (0x00000240)
+
+#define BM_PXP_LUT_CTRL_BYPASS 0x80000000
+#define BF_PXP_LUT_CTRL_BYPASS(v) \
+ (((v) << 31) & BM_PXP_LUT_CTRL_BYPASS)
+#define BP_PXP_LUT_CTRL_RSVD3 26
+#define BM_PXP_LUT_CTRL_RSVD3 0x7C000000
+#define BF_PXP_LUT_CTRL_RSVD3(v) \
+ (((v) << 26) & BM_PXP_LUT_CTRL_RSVD3)
+#define BP_PXP_LUT_CTRL_LOOKUP_MODE 24
+#define BM_PXP_LUT_CTRL_LOOKUP_MODE 0x03000000
+#define BF_PXP_LUT_CTRL_LOOKUP_MODE(v) \
+ (((v) << 24) & BM_PXP_LUT_CTRL_LOOKUP_MODE)
+#define BV_PXP_LUT_CTRL_LOOKUP_MODE__CACHE_RGB565 0x0
+#define BV_PXP_LUT_CTRL_LOOKUP_MODE__DIRECT_Y8 0x1
+#define BV_PXP_LUT_CTRL_LOOKUP_MODE__DIRECT_RGB444 0x2
+#define BV_PXP_LUT_CTRL_LOOKUP_MODE__DIRECT_RGB454 0x3
+#define BP_PXP_LUT_CTRL_RSVD2 18
+#define BM_PXP_LUT_CTRL_RSVD2 0x00FC0000
+#define BF_PXP_LUT_CTRL_RSVD2(v) \
+ (((v) << 18) & BM_PXP_LUT_CTRL_RSVD2)
+#define BP_PXP_LUT_CTRL_OUT_MODE 16
+#define BM_PXP_LUT_CTRL_OUT_MODE 0x00030000
+#define BF_PXP_LUT_CTRL_OUT_MODE(v) \
+ (((v) << 16) & BM_PXP_LUT_CTRL_OUT_MODE)
+#define BV_PXP_LUT_CTRL_OUT_MODE__RESERVED 0x0
+#define BV_PXP_LUT_CTRL_OUT_MODE__Y8 0x1
+#define BV_PXP_LUT_CTRL_OUT_MODE__RGBW4444CFA 0x2
+#define BV_PXP_LUT_CTRL_OUT_MODE__RGB888 0x3
+#define BP_PXP_LUT_CTRL_RSVD1 11
+#define BM_PXP_LUT_CTRL_RSVD1 0x0000F800
+#define BF_PXP_LUT_CTRL_RSVD1(v) \
+ (((v) << 11) & BM_PXP_LUT_CTRL_RSVD1)
+#define BM_PXP_LUT_CTRL_SEL_8KB 0x00000400
+#define BF_PXP_LUT_CTRL_SEL_8KB(v) \
+ (((v) << 10) & BM_PXP_LUT_CTRL_SEL_8KB)
+#define BM_PXP_LUT_CTRL_LRU_UPD 0x00000200
+#define BF_PXP_LUT_CTRL_LRU_UPD(v) \
+ (((v) << 9) & BM_PXP_LUT_CTRL_LRU_UPD)
+#define BM_PXP_LUT_CTRL_INVALID 0x00000100
+#define BF_PXP_LUT_CTRL_INVALID(v) \
+ (((v) << 8) & BM_PXP_LUT_CTRL_INVALID)
+#define BP_PXP_LUT_CTRL_RSVD0 1
+#define BM_PXP_LUT_CTRL_RSVD0 0x000000FE
+#define BF_PXP_LUT_CTRL_RSVD0(v) \
+ (((v) << 1) & BM_PXP_LUT_CTRL_RSVD0)
+#define BM_PXP_LUT_CTRL_DMA_START 0x00000001
+#define BF_PXP_LUT_CTRL_DMA_START(v) \
+ (((v) << 0) & BM_PXP_LUT_CTRL_DMA_START)
+
+#define HW_PXP_LUT_ADDR (0x00000250)
+
+#define BM_PXP_LUT_ADDR_RSVD2 0x80000000
+#define BF_PXP_LUT_ADDR_RSVD2(v) \
+ (((v) << 31) & BM_PXP_LUT_ADDR_RSVD2)
+#define BP_PXP_LUT_ADDR_NUM_BYTES 16
+#define BM_PXP_LUT_ADDR_NUM_BYTES 0x7FFF0000
+#define BF_PXP_LUT_ADDR_NUM_BYTES(v) \
+ (((v) << 16) & BM_PXP_LUT_ADDR_NUM_BYTES)
+#define BP_PXP_LUT_ADDR_RSVD1 14
+#define BM_PXP_LUT_ADDR_RSVD1 0x0000C000
+#define BF_PXP_LUT_ADDR_RSVD1(v) \
+ (((v) << 14) & BM_PXP_LUT_ADDR_RSVD1)
+#define BP_PXP_LUT_ADDR_ADDR 0
+#define BM_PXP_LUT_ADDR_ADDR 0x00003FFF
+#define BF_PXP_LUT_ADDR_ADDR(v) \
+ (((v) << 0) & BM_PXP_LUT_ADDR_ADDR)
+
+#define HW_PXP_LUT_DATA (0x00000260)
+
+#define BP_PXP_LUT_DATA_DATA 0
+#define BM_PXP_LUT_DATA_DATA 0xFFFFFFFF
+#define BF_PXP_LUT_DATA_DATA(v) (v)
+
+#define HW_PXP_LUT_EXTMEM (0x00000270)
+
+#define BP_PXP_LUT_EXTMEM_ADDR 0
+#define BM_PXP_LUT_EXTMEM_ADDR 0xFFFFFFFF
+#define BF_PXP_LUT_EXTMEM_ADDR(v) (v)
+
+#define HW_PXP_CFA (0x00000280)
+
+#define BP_PXP_CFA_DATA 0
+#define BM_PXP_CFA_DATA 0xFFFFFFFF
+#define BF_PXP_CFA_DATA(v) (v)
+
+#define HW_PXP_ALPHA_A_CTRL (0x00000290)
+
+#define BP_PXP_ALPHA_A_CTRL_S1_GLOBAL_ALPHA 24
+#define BM_PXP_ALPHA_A_CTRL_S1_GLOBAL_ALPHA 0xFF000000
+#define BF_PXP_ALPHA_A_CTRL_S1_GLOBAL_ALPHA(v) \
+ (((v) << 24) & BM_PXP_ALPHA_A_CTRL_S1_GLOBAL_ALPHA)
+#define BP_PXP_ALPHA_A_CTRL_S0_GLOBAL_ALPHA 16
+#define BM_PXP_ALPHA_A_CTRL_S0_GLOBAL_ALPHA 0x00FF0000
+#define BF_PXP_ALPHA_A_CTRL_S0_GLOBAL_ALPHA(v) \
+ (((v) << 16) & BM_PXP_ALPHA_A_CTRL_S0_GLOBAL_ALPHA)
+#define BP_PXP_ALPHA_A_CTRL_RSVD0 14
+#define BM_PXP_ALPHA_A_CTRL_RSVD0 0x0000C000
+#define BF_PXP_ALPHA_A_CTRL_RSVD0(v) \
+ (((v) << 14) & BM_PXP_ALPHA_A_CTRL_RSVD0)
+#define BM_PXP_ALPHA_A_CTRL_S1_COLOR_MODE 0x00002000
+#define BF_PXP_ALPHA_A_CTRL_S1_COLOR_MODE(v) \
+ (((v) << 13) & BM_PXP_ALPHA_A_CTRL_S1_COLOR_MODE)
+#define BV_PXP_ALPHA_A_CTRL_S1_COLOR_MODE__0 0x0
+#define BV_PXP_ALPHA_A_CTRL_S1_COLOR_MODE__1 0x1
+#define BM_PXP_ALPHA_A_CTRL_S1_ALPHA_MODE 0x00001000
+#define BF_PXP_ALPHA_A_CTRL_S1_ALPHA_MODE(v) \
+ (((v) << 12) & BM_PXP_ALPHA_A_CTRL_S1_ALPHA_MODE)
+#define BV_PXP_ALPHA_A_CTRL_S1_ALPHA_MODE__0 0x0
+#define BV_PXP_ALPHA_A_CTRL_S1_ALPHA_MODE__1 0x1
+#define BP_PXP_ALPHA_A_CTRL_S1_GLOBAL_ALPHA_MODE 10
+#define BM_PXP_ALPHA_A_CTRL_S1_GLOBAL_ALPHA_MODE 0x00000C00
+#define BF_PXP_ALPHA_A_CTRL_S1_GLOBAL_ALPHA_MODE(v) \
+ (((v) << 10) & BM_PXP_ALPHA_A_CTRL_S1_GLOBAL_ALPHA_MODE)
+#define BV_PXP_ALPHA_A_CTRL_S1_GLOBAL_ALPHA_MODE__0 0x0
+#define BV_PXP_ALPHA_A_CTRL_S1_GLOBAL_ALPHA_MODE__1 0x0
+#define BV_PXP_ALPHA_A_CTRL_S1_GLOBAL_ALPHA_MODE__2 0x0
+#define BV_PXP_ALPHA_A_CTRL_S1_GLOBAL_ALPHA_MODE__3 0x0
+#define BP_PXP_ALPHA_A_CTRL_S1_S0_FACTOR_MODE 8
+#define BM_PXP_ALPHA_A_CTRL_S1_S0_FACTOR_MODE 0x00000300
+#define BF_PXP_ALPHA_A_CTRL_S1_S0_FACTOR_MODE(v) \
+ (((v) << 8) & BM_PXP_ALPHA_A_CTRL_S1_S0_FACTOR_MODE)
+#define BV_PXP_ALPHA_A_CTRL_S1_S0_FACTOR_MODE__0 0x0
+#define BV_PXP_ALPHA_A_CTRL_S1_S0_FACTOR_MODE__1 0x1
+#define BV_PXP_ALPHA_A_CTRL_S1_S0_FACTOR_MODE__2 0x2
+#define BV_PXP_ALPHA_A_CTRL_S1_S0_FACTOR_MODE__3 0x3
+#define BM_PXP_ALPHA_A_CTRL_RSVD1 0x00000080
+#define BF_PXP_ALPHA_A_CTRL_RSVD1(v) \
+ (((v) << 7) & BM_PXP_ALPHA_A_CTRL_RSVD1)
+#define BM_PXP_ALPHA_A_CTRL_S0_COLOR_MODE 0x00000040
+#define BF_PXP_ALPHA_A_CTRL_S0_COLOR_MODE(v) \
+ (((v) << 6) & BM_PXP_ALPHA_A_CTRL_S0_COLOR_MODE)
+#define BV_PXP_ALPHA_A_CTRL_S0_COLOR_MODE__0 0x0
+#define BV_PXP_ALPHA_A_CTRL_S0_COLOR_MODE__1 0x1
+#define BM_PXP_ALPHA_A_CTRL_S0_ALPHA_MODE 0x00000020
+#define BF_PXP_ALPHA_A_CTRL_S0_ALPHA_MODE(v) \
+ (((v) << 5) & BM_PXP_ALPHA_A_CTRL_S0_ALPHA_MODE)
+#define BV_PXP_ALPHA_A_CTRL_S0_ALPHA_MODE__0 0x0
+#define BV_PXP_ALPHA_A_CTRL_S0_ALPHA_MODE__1 0x1
+#define BP_PXP_ALPHA_A_CTRL_S0_GLOBAL_ALPHA_MODE 3
+#define BM_PXP_ALPHA_A_CTRL_S0_GLOBAL_ALPHA_MODE 0x00000018
+#define BF_PXP_ALPHA_A_CTRL_S0_GLOBAL_ALPHA_MODE(v) \
+ (((v) << 3) & BM_PXP_ALPHA_A_CTRL_S0_GLOBAL_ALPHA_MODE)
+#define BV_PXP_ALPHA_A_CTRL_S0_GLOBAL_ALPHA_MODE__0 0x0
+#define BV_PXP_ALPHA_A_CTRL_S0_GLOBAL_ALPHA_MODE__1 0x1
+#define BV_PXP_ALPHA_A_CTRL_S0_GLOBAL_ALPHA_MODE__2 0x2
+#define BV_PXP_ALPHA_A_CTRL_S0_GLOBAL_ALPHA_MODE__3 0x3
+#define BP_PXP_ALPHA_A_CTRL_S0_S1_FACTOR_MODE 1
+#define BM_PXP_ALPHA_A_CTRL_S0_S1_FACTOR_MODE 0x00000006
+#define BF_PXP_ALPHA_A_CTRL_S0_S1_FACTOR_MODE(v) \
+ (((v) << 1) & BM_PXP_ALPHA_A_CTRL_S0_S1_FACTOR_MODE)
+#define BV_PXP_ALPHA_A_CTRL_S0_S1_FACTOR_MODE__0 0x0
+#define BV_PXP_ALPHA_A_CTRL_S0_S1_FACTOR_MODE__1 0x1
+#define BV_PXP_ALPHA_A_CTRL_S0_S1_FACTOR_MODE__2 0x2
+#define BV_PXP_ALPHA_A_CTRL_S0_S1_FACTOR_MODE__3 0x3
+#define BM_PXP_ALPHA_A_CTRL_POTER_DUFF_ENABLE 0x00000001
+#define BF_PXP_ALPHA_A_CTRL_POTER_DUFF_ENABLE(v) \
+ (((v) << 0) & BM_PXP_ALPHA_A_CTRL_POTER_DUFF_ENABLE)
+#define BV_PXP_ALPHA_A_CTRL_POTER_DUFF_ENABLE__0 0x0
+#define BV_PXP_ALPHA_A_CTRL_POTER_DUFF_ENABLE__1 0x1
+
+#define HW_PXP_ALPHA_B_CTRL (0x000002a0)
+
+#define BP_PXP_ALPHA_B_CTRL_S1_GLOBAL_ALPHA 24
+#define BM_PXP_ALPHA_B_CTRL_S1_GLOBAL_ALPHA 0xFF000000
+#define BF_PXP_ALPHA_B_CTRL_S1_GLOBAL_ALPHA(v) \
+ (((v) << 24) & BM_PXP_ALPHA_B_CTRL_S1_GLOBAL_ALPHA)
+#define BP_PXP_ALPHA_B_CTRL_S0_GLOBAL_ALPHA 16
+#define BM_PXP_ALPHA_B_CTRL_S0_GLOBAL_ALPHA 0x00FF0000
+#define BF_PXP_ALPHA_B_CTRL_S0_GLOBAL_ALPHA(v) \
+ (((v) << 16) & BM_PXP_ALPHA_B_CTRL_S0_GLOBAL_ALPHA)
+#define BP_PXP_ALPHA_B_CTRL_RSVD0 14
+#define BM_PXP_ALPHA_B_CTRL_RSVD0 0x0000C000
+#define BF_PXP_ALPHA_B_CTRL_RSVD0(v) \
+ (((v) << 14) & BM_PXP_ALPHA_B_CTRL_RSVD0)
+#define BM_PXP_ALPHA_B_CTRL_S1_COLOR_MODE 0x00002000
+#define BF_PXP_ALPHA_B_CTRL_S1_COLOR_MODE(v) \
+ (((v) << 13) & BM_PXP_ALPHA_B_CTRL_S1_COLOR_MODE)
+#define BV_PXP_ALPHA_B_CTRL_S1_COLOR_MODE__0 0x0
+#define BV_PXP_ALPHA_B_CTRL_S1_COLOR_MODE__1 0x1
+#define BM_PXP_ALPHA_B_CTRL_S1_ALPHA_MODE 0x00001000
+#define BF_PXP_ALPHA_B_CTRL_S1_ALPHA_MODE(v) \
+ (((v) << 12) & BM_PXP_ALPHA_B_CTRL_S1_ALPHA_MODE)
+#define BV_PXP_ALPHA_B_CTRL_S1_ALPHA_MODE__0 0x0
+#define BV_PXP_ALPHA_B_CTRL_S1_ALPHA_MODE__1 0x1
+#define BP_PXP_ALPHA_B_CTRL_S1_GLOBAL_ALPHA_MODE 10
+#define BM_PXP_ALPHA_B_CTRL_S1_GLOBAL_ALPHA_MODE 0x00000C00
+#define BF_PXP_ALPHA_B_CTRL_S1_GLOBAL_ALPHA_MODE(v) \
+ (((v) << 10) & BM_PXP_ALPHA_B_CTRL_S1_GLOBAL_ALPHA_MODE)
+#define BV_PXP_ALPHA_B_CTRL_S1_GLOBAL_ALPHA_MODE__0 0x0
+#define BV_PXP_ALPHA_B_CTRL_S1_GLOBAL_ALPHA_MODE__1 0x1
+#define BV_PXP_ALPHA_B_CTRL_S1_GLOBAL_ALPHA_MODE__2 0x2
+#define BV_PXP_ALPHA_B_CTRL_S1_GLOBAL_ALPHA_MODE__3 0x3
+#define BP_PXP_ALPHA_B_CTRL_S1_S0_FACTOR_MODE 8
+#define BM_PXP_ALPHA_B_CTRL_S1_S0_FACTOR_MODE 0x00000300
+#define BF_PXP_ALPHA_B_CTRL_S1_S0_FACTOR_MODE(v) \
+ (((v) << 8) & BM_PXP_ALPHA_B_CTRL_S1_S0_FACTOR_MODE)
+#define BV_PXP_ALPHA_B_CTRL_S1_S0_FACTOR_MODE__0 0x0
+#define BV_PXP_ALPHA_B_CTRL_S1_S0_FACTOR_MODE__1 0x1
+#define BV_PXP_ALPHA_B_CTRL_S1_S0_FACTOR_MODE__2 0x2
+#define BV_PXP_ALPHA_B_CTRL_S1_S0_FACTOR_MODE__3 0x3
+#define BM_PXP_ALPHA_B_CTRL_RSVD1 0x00000080
+#define BF_PXP_ALPHA_B_CTRL_RSVD1(v) \
+ (((v) << 7) & BM_PXP_ALPHA_B_CTRL_RSVD1)
+#define BM_PXP_ALPHA_B_CTRL_S0_COLOR_MODE 0x00000040
+#define BF_PXP_ALPHA_B_CTRL_S0_COLOR_MODE(v) \
+ (((v) << 6) & BM_PXP_ALPHA_B_CTRL_S0_COLOR_MODE)
+#define BV_PXP_ALPHA_B_CTRL_S0_COLOR_MODE__0 0x0
+#define BV_PXP_ALPHA_B_CTRL_S0_COLOR_MODE__1 0x1
+#define BM_PXP_ALPHA_B_CTRL_S0_ALPHA_MODE 0x00000020
+#define BF_PXP_ALPHA_B_CTRL_S0_ALPHA_MODE(v) \
+ (((v) << 5) & BM_PXP_ALPHA_B_CTRL_S0_ALPHA_MODE)
+#define BV_PXP_ALPHA_B_CTRL_S0_ALPHA_MODE__0 0x0
+#define BV_PXP_ALPHA_B_CTRL_S0_ALPHA_MODE__1 0x1
+#define BP_PXP_ALPHA_B_CTRL_S0_GLOBAL_ALPHA_MODE 3
+#define BM_PXP_ALPHA_B_CTRL_S0_GLOBAL_ALPHA_MODE 0x00000018
+#define BF_PXP_ALPHA_B_CTRL_S0_GLOBAL_ALPHA_MODE(v) \
+ (((v) << 3) & BM_PXP_ALPHA_B_CTRL_S0_GLOBAL_ALPHA_MODE)
+#define BV_PXP_ALPHA_B_CTRL_S0_GLOBAL_ALPHA_MODE__0 0x0
+#define BV_PXP_ALPHA_B_CTRL_S0_GLOBAL_ALPHA_MODE__1 0x1
+#define BV_PXP_ALPHA_B_CTRL_S0_GLOBAL_ALPHA_MODE__2 0x2
+#define BV_PXP_ALPHA_B_CTRL_S0_GLOBAL_ALPHA_MODE__3 0x3
+#define BP_PXP_ALPHA_B_CTRL_S0_S1_FACTOR_MODE 1
+#define BM_PXP_ALPHA_B_CTRL_S0_S1_FACTOR_MODE 0x00000006
+#define BF_PXP_ALPHA_B_CTRL_S0_S1_FACTOR_MODE(v) \
+ (((v) << 1) & BM_PXP_ALPHA_B_CTRL_S0_S1_FACTOR_MODE)
+#define BV_PXP_ALPHA_B_CTRL_S0_S1_FACTOR_MODE__0 0x0
+#define BV_PXP_ALPHA_B_CTRL_S0_S1_FACTOR_MODE__1 0x1
+#define BV_PXP_ALPHA_B_CTRL_S0_S1_FACTOR_MODE__2 0x2
+#define BV_PXP_ALPHA_B_CTRL_S0_S1_FACTOR_MODE__3 0x3
+#define BM_PXP_ALPHA_B_CTRL_POTER_DUFF_ENABLE 0x00000001
+#define BF_PXP_ALPHA_B_CTRL_POTER_DUFF_ENABLE(v) \
+ (((v) << 0) & BM_PXP_ALPHA_B_CTRL_POTER_DUFF_ENABLE)
+#define BV_PXP_ALPHA_B_CTRL_POTER_DUFF_ENABLE__0 0x0
+#define BV_PXP_ALPHA_B_CTRL_POTER_DUFF_ENABLE__1 0x1
+
+#define HW_PXP_ALPHA_B_CTRL_1 (0x000002b0)
+
+#define BP_PXP_ALPHA_B_CTRL_1_RSVD0 8
+#define BM_PXP_ALPHA_B_CTRL_1_RSVD0 0xFFFFFF00
+#define BF_PXP_ALPHA_B_CTRL_1_RSVD0(v) \
+ (((v) << 8) & BM_PXP_ALPHA_B_CTRL_1_RSVD0)
+#define BP_PXP_ALPHA_B_CTRL_1_ROP 4
+#define BM_PXP_ALPHA_B_CTRL_1_ROP 0x000000F0
+#define BF_PXP_ALPHA_B_CTRL_1_ROP(v) \
+ (((v) << 4) & BM_PXP_ALPHA_B_CTRL_1_ROP)
+#define BV_PXP_ALPHA_B_CTRL_1_ROP__MASKAS 0x0
+#define BV_PXP_ALPHA_B_CTRL_1_ROP__MASKNOTAS 0x1
+#define BV_PXP_ALPHA_B_CTRL_1_ROP__MASKASNOT 0x2
+#define BV_PXP_ALPHA_B_CTRL_1_ROP__MERGEAS 0x3
+#define BV_PXP_ALPHA_B_CTRL_1_ROP__MERGENOTAS 0x4
+#define BV_PXP_ALPHA_B_CTRL_1_ROP__MERGEASNOT 0x5
+#define BV_PXP_ALPHA_B_CTRL_1_ROP__NOTCOPYAS 0x6
+#define BV_PXP_ALPHA_B_CTRL_1_ROP__NOT 0x7
+#define BV_PXP_ALPHA_B_CTRL_1_ROP__NOTMASKAS 0x8
+#define BV_PXP_ALPHA_B_CTRL_1_ROP__NOTMERGEAS 0x9
+#define BV_PXP_ALPHA_B_CTRL_1_ROP__XORAS 0xA
+#define BV_PXP_ALPHA_B_CTRL_1_ROP__NOTXORAS 0xB
+#define BP_PXP_ALPHA_B_CTRL_1_RSVD1 2
+#define BM_PXP_ALPHA_B_CTRL_1_RSVD1 0x0000000C
+#define BF_PXP_ALPHA_B_CTRL_1_RSVD1(v) \
+ (((v) << 2) & BM_PXP_ALPHA_B_CTRL_1_RSVD1)
+#define BM_PXP_ALPHA_B_CTRL_1_OL_CLRKEY_ENABLE 0x00000002
+#define BF_PXP_ALPHA_B_CTRL_1_OL_CLRKEY_ENABLE(v) \
+ (((v) << 1) & BM_PXP_ALPHA_B_CTRL_1_OL_CLRKEY_ENABLE)
+#define BM_PXP_ALPHA_B_CTRL_1_ROP_ENABLE 0x00000001
+#define BF_PXP_ALPHA_B_CTRL_1_ROP_ENABLE(v) \
+ (((v) << 0) & BM_PXP_ALPHA_B_CTRL_1_ROP_ENABLE)
+
+#define HW_PXP_PS_BACKGROUND_1 (0x000002c0)
+
+#define BP_PXP_PS_BACKGROUND_1_RSVD 24
+#define BM_PXP_PS_BACKGROUND_1_RSVD 0xFF000000
+#define BF_PXP_PS_BACKGROUND_1_RSVD(v) \
+ (((v) << 24) & BM_PXP_PS_BACKGROUND_1_RSVD)
+#define BP_PXP_PS_BACKGROUND_1_COLOR 0
+#define BM_PXP_PS_BACKGROUND_1_COLOR 0x00FFFFFF
+#define BF_PXP_PS_BACKGROUND_1_COLOR(v) \
+ (((v) << 0) & BM_PXP_PS_BACKGROUND_1_COLOR)
+
+#define HW_PXP_PS_CLRKEYLOW_1 (0x000002d0)
+
+#define BP_PXP_PS_CLRKEYLOW_1_RSVD1 24
+#define BM_PXP_PS_CLRKEYLOW_1_RSVD1 0xFF000000
+#define BF_PXP_PS_CLRKEYLOW_1_RSVD1(v) \
+ (((v) << 24) & BM_PXP_PS_CLRKEYLOW_1_RSVD1)
+#define BP_PXP_PS_CLRKEYLOW_1_PIXEL 0
+#define BM_PXP_PS_CLRKEYLOW_1_PIXEL 0x00FFFFFF
+#define BF_PXP_PS_CLRKEYLOW_1_PIXEL(v) \
+ (((v) << 0) & BM_PXP_PS_CLRKEYLOW_1_PIXEL)
+
+#define HW_PXP_PS_CLRKEYHIGH_1 (0x000002e0)
+
+#define BP_PXP_PS_CLRKEYHIGH_1_RSVD1 24
+#define BM_PXP_PS_CLRKEYHIGH_1_RSVD1 0xFF000000
+#define BF_PXP_PS_CLRKEYHIGH_1_RSVD1(v) \
+ (((v) << 24) & BM_PXP_PS_CLRKEYHIGH_1_RSVD1)
+#define BP_PXP_PS_CLRKEYHIGH_1_PIXEL 0
+#define BM_PXP_PS_CLRKEYHIGH_1_PIXEL 0x00FFFFFF
+#define BF_PXP_PS_CLRKEYHIGH_1_PIXEL(v) \
+ (((v) << 0) & BM_PXP_PS_CLRKEYHIGH_1_PIXEL)
+
+#define HW_PXP_AS_CLRKEYLOW_1 (0x000002f0)
+
+#define BP_PXP_AS_CLRKEYLOW_1_RSVD1 24
+#define BM_PXP_AS_CLRKEYLOW_1_RSVD1 0xFF000000
+#define BF_PXP_AS_CLRKEYLOW_1_RSVD1(v) \
+ (((v) << 24) & BM_PXP_AS_CLRKEYLOW_1_RSVD1)
+#define BP_PXP_AS_CLRKEYLOW_1_PIXEL 0
+#define BM_PXP_AS_CLRKEYLOW_1_PIXEL 0x00FFFFFF
+#define BF_PXP_AS_CLRKEYLOW_1_PIXEL(v) \
+ (((v) << 0) & BM_PXP_AS_CLRKEYLOW_1_PIXEL)
+
+#define HW_PXP_AS_CLRKEYHIGH_1 (0x00000300)
+
+#define BP_PXP_AS_CLRKEYHIGH_1_RSVD1 24
+#define BM_PXP_AS_CLRKEYHIGH_1_RSVD1 0xFF000000
+#define BF_PXP_AS_CLRKEYHIGH_1_RSVD1(v) \
+ (((v) << 24) & BM_PXP_AS_CLRKEYHIGH_1_RSVD1)
+#define BP_PXP_AS_CLRKEYHIGH_1_PIXEL 0
+#define BM_PXP_AS_CLRKEYHIGH_1_PIXEL 0x00FFFFFF
+#define BF_PXP_AS_CLRKEYHIGH_1_PIXEL(v) \
+ (((v) << 0) & BM_PXP_AS_CLRKEYHIGH_1_PIXEL)
+
+#define HW_PXP_CTRL2 (0x00000310)
+#define HW_PXP_CTRL2_SET (0x00000314)
+#define HW_PXP_CTRL2_CLR (0x00000318)
+#define HW_PXP_CTRL2_TOG (0x0000031c)
+
+#define BP_PXP_CTRL2_RSVD3 28
+#define BM_PXP_CTRL2_RSVD3 0xF0000000
+#define BF_PXP_CTRL2_RSVD3(v) \
+ (((v) << 28) & BM_PXP_CTRL2_RSVD3)
+#define BM_PXP_CTRL2_ENABLE_ROTATE1 0x08000000
+#define BF_PXP_CTRL2_ENABLE_ROTATE1(v) \
+ (((v) << 27) & BM_PXP_CTRL2_ENABLE_ROTATE1)
+#define BM_PXP_CTRL2_ENABLE_ROTATE0 0x04000000
+#define BF_PXP_CTRL2_ENABLE_ROTATE0(v) \
+ (((v) << 26) & BM_PXP_CTRL2_ENABLE_ROTATE0)
+#define BM_PXP_CTRL2_ENABLE_LUT 0x02000000
+#define BF_PXP_CTRL2_ENABLE_LUT(v) \
+ (((v) << 25) & BM_PXP_CTRL2_ENABLE_LUT)
+#define BM_PXP_CTRL2_ENABLE_CSC2 0x01000000
+#define BF_PXP_CTRL2_ENABLE_CSC2(v) \
+ (((v) << 24) & BM_PXP_CTRL2_ENABLE_CSC2)
+#define BM_PXP_CTRL2_BLOCK_SIZE 0x00800000
+#define BF_PXP_CTRL2_BLOCK_SIZE(v) \
+ (((v) << 23) & BM_PXP_CTRL2_BLOCK_SIZE)
+#define BV_PXP_CTRL2_BLOCK_SIZE__8X8 0x0
+#define BV_PXP_CTRL2_BLOCK_SIZE__16X16 0x1
+#define BM_PXP_CTRL2_RSVD2 0x00400000
+#define BF_PXP_CTRL2_RSVD2(v) \
+ (((v) << 22) & BM_PXP_CTRL2_RSVD2)
+#define BM_PXP_CTRL2_ENABLE_ALPHA_B 0x00200000
+#define BF_PXP_CTRL2_ENABLE_ALPHA_B(v) \
+ (((v) << 21) & BM_PXP_CTRL2_ENABLE_ALPHA_B)
+#define BM_PXP_CTRL2_ENABLE_INPUT_FETCH_STORE 0x00100000
+#define BF_PXP_CTRL2_ENABLE_INPUT_FETCH_STORE(v) \
+ (((v) << 20) & BM_PXP_CTRL2_ENABLE_INPUT_FETCH_STORE)
+#define BM_PXP_CTRL2_ENABLE_WFE_B 0x00080000
+#define BF_PXP_CTRL2_ENABLE_WFE_B(v) \
+ (((v) << 19) & BM_PXP_CTRL2_ENABLE_WFE_B)
+#define BM_PXP_CTRL2_ENABLE_WFE_A 0x00040000
+#define BF_PXP_CTRL2_ENABLE_WFE_A(v) \
+ (((v) << 18) & BM_PXP_CTRL2_ENABLE_WFE_A)
+#define BM_PXP_CTRL2_ENABLE_DITHER 0x00020000
+#define BF_PXP_CTRL2_ENABLE_DITHER(v) \
+ (((v) << 17) & BM_PXP_CTRL2_ENABLE_DITHER)
+#define BM_PXP_CTRL2_RSVD1 0x00010000
+#define BF_PXP_CTRL2_RSVD1(v) \
+ (((v) << 16) & BM_PXP_CTRL2_RSVD1)
+#define BM_PXP_CTRL2_VFLIP1 0x00008000
+#define BF_PXP_CTRL2_VFLIP1(v) \
+ (((v) << 15) & BM_PXP_CTRL2_VFLIP1)
+#define BM_PXP_CTRL2_HFLIP1 0x00004000
+#define BF_PXP_CTRL2_HFLIP1(v) \
+ (((v) << 14) & BM_PXP_CTRL2_HFLIP1)
+#define BP_PXP_CTRL2_ROTATE1 12
+#define BM_PXP_CTRL2_ROTATE1 0x00003000
+#define BF_PXP_CTRL2_ROTATE1(v) \
+ (((v) << 12) & BM_PXP_CTRL2_ROTATE1)
+#define BV_PXP_CTRL2_ROTATE1__ROT_0 0x0
+#define BV_PXP_CTRL2_ROTATE1__ROT_90 0x1
+#define BV_PXP_CTRL2_ROTATE1__ROT_180 0x2
+#define BV_PXP_CTRL2_ROTATE1__ROT_270 0x3
+#define BM_PXP_CTRL2_VFLIP0 0x00000800
+#define BF_PXP_CTRL2_VFLIP0(v) \
+ (((v) << 11) & BM_PXP_CTRL2_VFLIP0)
+#define BM_PXP_CTRL2_HFLIP0 0x00000400
+#define BF_PXP_CTRL2_HFLIP0(v) \
+ (((v) << 10) & BM_PXP_CTRL2_HFLIP0)
+#define BP_PXP_CTRL2_ROTATE0 8
+#define BM_PXP_CTRL2_ROTATE0 0x00000300
+#define BF_PXP_CTRL2_ROTATE0(v) \
+ (((v) << 8) & BM_PXP_CTRL2_ROTATE0)
+#define BV_PXP_CTRL2_ROTATE0__ROT_0 0x0
+#define BV_PXP_CTRL2_ROTATE0__ROT_90 0x1
+#define BV_PXP_CTRL2_ROTATE0__ROT_180 0x2
+#define BV_PXP_CTRL2_ROTATE0__ROT_270 0x3
+#define BP_PXP_CTRL2_RSVD0 1
+#define BM_PXP_CTRL2_RSVD0 0x000000FE
+#define BF_PXP_CTRL2_RSVD0(v) \
+ (((v) << 1) & BM_PXP_CTRL2_RSVD0)
+#define BM_PXP_CTRL2_ENABLE 0x00000001
+#define BF_PXP_CTRL2_ENABLE(v) \
+ (((v) << 0) & BM_PXP_CTRL2_ENABLE)
+
+#define HW_PXP_POWER_REG0 (0x00000320)
+
+#define BP_PXP_POWER_REG0_CTRL 12
+#define BM_PXP_POWER_REG0_CTRL 0xFFFFF000
+#define BF_PXP_POWER_REG0_CTRL(v) \
+ (((v) << 12) & BM_PXP_POWER_REG0_CTRL)
+#define BP_PXP_POWER_REG0_ROT0_MEM_LP_STATE 9
+#define BM_PXP_POWER_REG0_ROT0_MEM_LP_STATE 0x00000E00
+#define BF_PXP_POWER_REG0_ROT0_MEM_LP_STATE(v) \
+ (((v) << 9) & BM_PXP_POWER_REG0_ROT0_MEM_LP_STATE)
+#define BV_PXP_POWER_REG0_ROT0_MEM_LP_STATE__NONE 0x0
+#define BV_PXP_POWER_REG0_ROT0_MEM_LP_STATE__LS 0x1
+#define BV_PXP_POWER_REG0_ROT0_MEM_LP_STATE__DS 0x2
+#define BV_PXP_POWER_REG0_ROT0_MEM_LP_STATE__SD 0x4
+#define BP_PXP_POWER_REG0_LUT_LP_STATE_WAY1_BANKN 6
+#define BM_PXP_POWER_REG0_LUT_LP_STATE_WAY1_BANKN 0x000001C0
+#define BF_PXP_POWER_REG0_LUT_LP_STATE_WAY1_BANKN(v) \
+ (((v) << 6) & BM_PXP_POWER_REG0_LUT_LP_STATE_WAY1_BANKN)
+#define BV_PXP_POWER_REG0_LUT_LP_STATE_WAY1_BANKN__NONE 0x0
+#define BV_PXP_POWER_REG0_LUT_LP_STATE_WAY1_BANKN__LS 0x1
+#define BV_PXP_POWER_REG0_LUT_LP_STATE_WAY1_BANKN__DS 0x2
+#define BV_PXP_POWER_REG0_LUT_LP_STATE_WAY1_BANKN__SD 0x4
+#define BP_PXP_POWER_REG0_LUT_LP_STATE_WAY0_BANKN 3
+#define BM_PXP_POWER_REG0_LUT_LP_STATE_WAY0_BANKN 0x00000038
+#define BF_PXP_POWER_REG0_LUT_LP_STATE_WAY0_BANKN(v) \
+ (((v) << 3) & BM_PXP_POWER_REG0_LUT_LP_STATE_WAY0_BANKN)
+#define BV_PXP_POWER_REG0_LUT_LP_STATE_WAY0_BANKN__NONE 0x0
+#define BV_PXP_POWER_REG0_LUT_LP_STATE_WAY0_BANKN__LS 0x1
+#define BV_PXP_POWER_REG0_LUT_LP_STATE_WAY0_BANKN__DS 0x2
+#define BV_PXP_POWER_REG0_LUT_LP_STATE_WAY0_BANKN__SD 0x4
+#define BP_PXP_POWER_REG0_LUT_LP_STATE_WAY0_BANK0 0
+#define BM_PXP_POWER_REG0_LUT_LP_STATE_WAY0_BANK0 0x00000007
+#define BF_PXP_POWER_REG0_LUT_LP_STATE_WAY0_BANK0(v) \
+ (((v) << 0) & BM_PXP_POWER_REG0_LUT_LP_STATE_WAY0_BANK0)
+#define BV_PXP_POWER_REG0_LUT_LP_STATE_WAY0_BANK0__NONE 0x0
+#define BV_PXP_POWER_REG0_LUT_LP_STATE_WAY0_BANK0__LS 0x1
+#define BV_PXP_POWER_REG0_LUT_LP_STATE_WAY0_BANK0__DS 0x2
+#define BV_PXP_POWER_REG0_LUT_LP_STATE_WAY0_BANK0__SD 0x4
+
+#define HW_PXP_POWER_REG1 (0x00000330)
+
+#define BP_PXP_POWER_REG1_RSVD0 24
+#define BM_PXP_POWER_REG1_RSVD0 0xFF000000
+#define BF_PXP_POWER_REG1_RSVD0(v) \
+ (((v) << 24) & BM_PXP_POWER_REG1_RSVD0)
+#define BP_PXP_POWER_REG1_ALU_B_MEM_LP_STATE 21
+#define BM_PXP_POWER_REG1_ALU_B_MEM_LP_STATE 0x00E00000
+#define BF_PXP_POWER_REG1_ALU_B_MEM_LP_STATE(v) \
+ (((v) << 21) & BM_PXP_POWER_REG1_ALU_B_MEM_LP_STATE)
+#define BV_PXP_POWER_REG1_ALU_B_MEM_LP_STATE__NONE 0x0
+#define BV_PXP_POWER_REG1_ALU_B_MEM_LP_STATE__LS 0x1
+#define BV_PXP_POWER_REG1_ALU_B_MEM_LP_STATE__DS 0x2
+#define BV_PXP_POWER_REG1_ALU_B_MEM_LP_STATE__SD 0x4
+#define BP_PXP_POWER_REG1_ALU_A_MEM_LP_STATE 18
+#define BM_PXP_POWER_REG1_ALU_A_MEM_LP_STATE 0x001C0000
+#define BF_PXP_POWER_REG1_ALU_A_MEM_LP_STATE(v) \
+ (((v) << 18) & BM_PXP_POWER_REG1_ALU_A_MEM_LP_STATE)
+#define BV_PXP_POWER_REG1_ALU_A_MEM_LP_STATE__NONE 0x0
+#define BV_PXP_POWER_REG1_ALU_A_MEM_LP_STATE__LS 0x1
+#define BV_PXP_POWER_REG1_ALU_A_MEM_LP_STATE__DS 0x2
+#define BV_PXP_POWER_REG1_ALU_A_MEM_LP_STATE__SD 0x4
+#define BP_PXP_POWER_REG1_DITH2_LUT_MEM_LP_STATE 15
+#define BM_PXP_POWER_REG1_DITH2_LUT_MEM_LP_STATE 0x00038000
+#define BF_PXP_POWER_REG1_DITH2_LUT_MEM_LP_STATE(v) \
+ (((v) << 15) & BM_PXP_POWER_REG1_DITH2_LUT_MEM_LP_STATE)
+#define BV_PXP_POWER_REG1_DITH2_LUT_MEM_LP_STATE__NONE 0x0
+#define BV_PXP_POWER_REG1_DITH2_LUT_MEM_LP_STATE__LS 0x1
+#define BV_PXP_POWER_REG1_DITH2_LUT_MEM_LP_STATE__DS 0x2
+#define BV_PXP_POWER_REG1_DITH2_LUT_MEM_LP_STATE__SD 0x4
+#define BP_PXP_POWER_REG1_DITH1_LUT_MEM_LP_STATE 12
+#define BM_PXP_POWER_REG1_DITH1_LUT_MEM_LP_STATE 0x00007000
+#define BF_PXP_POWER_REG1_DITH1_LUT_MEM_LP_STATE(v) \
+ (((v) << 12) & BM_PXP_POWER_REG1_DITH1_LUT_MEM_LP_STATE)
+#define BV_PXP_POWER_REG1_DITH1_LUT_MEM_LP_STATE__NONE 0x0
+#define BV_PXP_POWER_REG1_DITH1_LUT_MEM_LP_STATE__LS 0x1
+#define BV_PXP_POWER_REG1_DITH1_LUT_MEM_LP_STATE__DS 0x2
+#define BV_PXP_POWER_REG1_DITH1_LUT_MEM_LP_STATE__SD 0x4
+#define BP_PXP_POWER_REG1_DITH0_ERR1_MEM_LP_STATE 9
+#define BM_PXP_POWER_REG1_DITH0_ERR1_MEM_LP_STATE 0x00000E00
+#define BF_PXP_POWER_REG1_DITH0_ERR1_MEM_LP_STATE(v) \
+ (((v) << 9) & BM_PXP_POWER_REG1_DITH0_ERR1_MEM_LP_STATE)
+#define BV_PXP_POWER_REG1_DITH0_ERR1_MEM_LP_STATE__NONE 0x0
+#define BV_PXP_POWER_REG1_DITH0_ERR1_MEM_LP_STATE__LS 0x1
+#define BV_PXP_POWER_REG1_DITH0_ERR1_MEM_LP_STATE__DS 0x2
+#define BV_PXP_POWER_REG1_DITH0_ERR1_MEM_LP_STATE__SD 0x4
+#define BP_PXP_POWER_REG1_DITH0_ERR0_MEM_LP_STATE 6
+#define BM_PXP_POWER_REG1_DITH0_ERR0_MEM_LP_STATE 0x000001C0
+#define BF_PXP_POWER_REG1_DITH0_ERR0_MEM_LP_STATE(v) \
+ (((v) << 6) & BM_PXP_POWER_REG1_DITH0_ERR0_MEM_LP_STATE)
+#define BV_PXP_POWER_REG1_DITH0_ERR0_MEM_LP_STATE__NONE 0x0
+#define BV_PXP_POWER_REG1_DITH0_ERR0_MEM_LP_STATE__LS 0x1
+#define BV_PXP_POWER_REG1_DITH0_ERR0_MEM_LP_STATE__DS 0x2
+#define BV_PXP_POWER_REG1_DITH0_ERR0_MEM_LP_STATE__SD 0x4
+#define BP_PXP_POWER_REG1_DITH0_LUT_MEM_LP_STATE 3
+#define BM_PXP_POWER_REG1_DITH0_LUT_MEM_LP_STATE 0x00000038
+#define BF_PXP_POWER_REG1_DITH0_LUT_MEM_LP_STATE(v) \
+ (((v) << 3) & BM_PXP_POWER_REG1_DITH0_LUT_MEM_LP_STATE)
+#define BV_PXP_POWER_REG1_DITH0_LUT_MEM_LP_STATE__NONE 0x0
+#define BV_PXP_POWER_REG1_DITH0_LUT_MEM_LP_STATE__LS 0x1
+#define BV_PXP_POWER_REG1_DITH0_LUT_MEM_LP_STATE__DS 0x2
+#define BV_PXP_POWER_REG1_DITH0_LUT_MEM_LP_STATE__SD 0x4
+#define BP_PXP_POWER_REG1_ROT1_MEM_LP_STATE 0
+#define BM_PXP_POWER_REG1_ROT1_MEM_LP_STATE 0x00000007
+#define BF_PXP_POWER_REG1_ROT1_MEM_LP_STATE(v) \
+ (((v) << 0) & BM_PXP_POWER_REG1_ROT1_MEM_LP_STATE)
+#define BV_PXP_POWER_REG1_ROT1_MEM_LP_STATE__NONE 0x0
+#define BV_PXP_POWER_REG1_ROT1_MEM_LP_STATE__LS 0x1
+#define BV_PXP_POWER_REG1_ROT1_MEM_LP_STATE__DS 0x2
+#define BV_PXP_POWER_REG1_ROT1_MEM_LP_STATE__SD 0x4
+
+#define HW_PXP_DATA_PATH_CTRL0 (0x00000340)
+#define HW_PXP_DATA_PATH_CTRL0_SET (0x00000344)
+#define HW_PXP_DATA_PATH_CTRL0_CLR (0x00000348)
+#define HW_PXP_DATA_PATH_CTRL0_TOG (0x0000034c)
+
+#define BP_PXP_DATA_PATH_CTRL0_MUX15_SEL 30
+#define BM_PXP_DATA_PATH_CTRL0_MUX15_SEL 0xC0000000
+#define BF_PXP_DATA_PATH_CTRL0_MUX15_SEL(v) \
+ (((v) << 30) & BM_PXP_DATA_PATH_CTRL0_MUX15_SEL)
+#define BV_PXP_DATA_PATH_CTRL0_MUX15_SEL__0 0x0
+#define BV_PXP_DATA_PATH_CTRL0_MUX15_SEL__1 0x1
+#define BV_PXP_DATA_PATH_CTRL0_MUX15_SEL__2 0x2
+#define BV_PXP_DATA_PATH_CTRL0_MUX15_SEL__3 0x3
+#define BP_PXP_DATA_PATH_CTRL0_MUX14_SEL 28
+#define BM_PXP_DATA_PATH_CTRL0_MUX14_SEL 0x30000000
+#define BF_PXP_DATA_PATH_CTRL0_MUX14_SEL(v) \
+ (((v) << 28) & BM_PXP_DATA_PATH_CTRL0_MUX14_SEL)
+#define BV_PXP_DATA_PATH_CTRL0_MUX14_SEL__0 0x0
+#define BV_PXP_DATA_PATH_CTRL0_MUX14_SEL__1 0x1
+#define BV_PXP_DATA_PATH_CTRL0_MUX14_SEL__2 0x2
+#define BV_PXP_DATA_PATH_CTRL0_MUX14_SEL__3 0x3
+#define BP_PXP_DATA_PATH_CTRL0_MUX13_SEL 26
+#define BM_PXP_DATA_PATH_CTRL0_MUX13_SEL 0x0C000000
+#define BF_PXP_DATA_PATH_CTRL0_MUX13_SEL(v) \
+ (((v) << 26) & BM_PXP_DATA_PATH_CTRL0_MUX13_SEL)
+#define BV_PXP_DATA_PATH_CTRL0_MUX13_SEL__0 0x0
+#define BV_PXP_DATA_PATH_CTRL0_MUX13_SEL__1 0x1
+#define BV_PXP_DATA_PATH_CTRL0_MUX13_SEL__2 0x2
+#define BV_PXP_DATA_PATH_CTRL0_MUX13_SEL__3 0x3
+#define BP_PXP_DATA_PATH_CTRL0_MUX12_SEL 24
+#define BM_PXP_DATA_PATH_CTRL0_MUX12_SEL 0x03000000
+#define BF_PXP_DATA_PATH_CTRL0_MUX12_SEL(v) \
+ (((v) << 24) & BM_PXP_DATA_PATH_CTRL0_MUX12_SEL)
+#define BV_PXP_DATA_PATH_CTRL0_MUX12_SEL__0 0x0
+#define BV_PXP_DATA_PATH_CTRL0_MUX12_SEL__1 0x1
+#define BV_PXP_DATA_PATH_CTRL0_MUX12_SEL__2 0x2
+#define BV_PXP_DATA_PATH_CTRL0_MUX12_SEL__3 0x3
+#define BP_PXP_DATA_PATH_CTRL0_MUX11_SEL 22
+#define BM_PXP_DATA_PATH_CTRL0_MUX11_SEL 0x00C00000
+#define BF_PXP_DATA_PATH_CTRL0_MUX11_SEL(v) \
+ (((v) << 22) & BM_PXP_DATA_PATH_CTRL0_MUX11_SEL)
+#define BV_PXP_DATA_PATH_CTRL0_MUX11_SEL__0 0x0
+#define BV_PXP_DATA_PATH_CTRL0_MUX11_SEL__1 0x1
+#define BV_PXP_DATA_PATH_CTRL0_MUX11_SEL__2 0x2
+#define BV_PXP_DATA_PATH_CTRL0_MUX11_SEL__3 0x3
+#define BP_PXP_DATA_PATH_CTRL0_MUX10_SEL 20
+#define BM_PXP_DATA_PATH_CTRL0_MUX10_SEL 0x00300000
+#define BF_PXP_DATA_PATH_CTRL0_MUX10_SEL(v) \
+ (((v) << 20) & BM_PXP_DATA_PATH_CTRL0_MUX10_SEL)
+#define BV_PXP_DATA_PATH_CTRL0_MUX10_SEL__0 0x0
+#define BV_PXP_DATA_PATH_CTRL0_MUX10_SEL__1 0x1
+#define BV_PXP_DATA_PATH_CTRL0_MUX10_SEL__2 0x2
+#define BV_PXP_DATA_PATH_CTRL0_MUX10_SEL__3 0x3
+#define BP_PXP_DATA_PATH_CTRL0_MUX9_SEL 18
+#define BM_PXP_DATA_PATH_CTRL0_MUX9_SEL 0x000C0000
+#define BF_PXP_DATA_PATH_CTRL0_MUX9_SEL(v) \
+ (((v) << 18) & BM_PXP_DATA_PATH_CTRL0_MUX9_SEL)
+#define BV_PXP_DATA_PATH_CTRL0_MUX9_SEL__0 0x0
+#define BV_PXP_DATA_PATH_CTRL0_MUX9_SEL__1 0x1
+#define BV_PXP_DATA_PATH_CTRL0_MUX9_SEL__2 0x2
+#define BV_PXP_DATA_PATH_CTRL0_MUX9_SEL__3 0x3
+#define BP_PXP_DATA_PATH_CTRL0_MUX8_SEL 16
+#define BM_PXP_DATA_PATH_CTRL0_MUX8_SEL 0x00030000
+#define BF_PXP_DATA_PATH_CTRL0_MUX8_SEL(v) \
+ (((v) << 16) & BM_PXP_DATA_PATH_CTRL0_MUX8_SEL)
+#define BV_PXP_DATA_PATH_CTRL0_MUX8_SEL__0 0x0
+#define BV_PXP_DATA_PATH_CTRL0_MUX8_SEL__1 0x1
+#define BV_PXP_DATA_PATH_CTRL0_MUX8_SEL__2 0x2
+#define BV_PXP_DATA_PATH_CTRL0_MUX8_SEL__3 0x3
+#define BP_PXP_DATA_PATH_CTRL0_MUX7_SEL 14
+#define BM_PXP_DATA_PATH_CTRL0_MUX7_SEL 0x0000C000
+#define BF_PXP_DATA_PATH_CTRL0_MUX7_SEL(v) \
+ (((v) << 14) & BM_PXP_DATA_PATH_CTRL0_MUX7_SEL)
+#define BV_PXP_DATA_PATH_CTRL0_MUX7_SEL__0 0x0
+#define BV_PXP_DATA_PATH_CTRL0_MUX7_SEL__1 0x1
+#define BV_PXP_DATA_PATH_CTRL0_MUX7_SEL__2 0x2
+#define BV_PXP_DATA_PATH_CTRL0_MUX7_SEL__3 0x3
+#define BP_PXP_DATA_PATH_CTRL0_MUX6_SEL 12
+#define BM_PXP_DATA_PATH_CTRL0_MUX6_SEL 0x00003000
+#define BF_PXP_DATA_PATH_CTRL0_MUX6_SEL(v) \
+ (((v) << 12) & BM_PXP_DATA_PATH_CTRL0_MUX6_SEL)
+#define BV_PXP_DATA_PATH_CTRL0_MUX6_SEL__0 0x0
+#define BV_PXP_DATA_PATH_CTRL0_MUX6_SEL__1 0x1
+#define BV_PXP_DATA_PATH_CTRL0_MUX6_SEL__2 0x2
+#define BV_PXP_DATA_PATH_CTRL0_MUX6_SEL__3 0x3
+#define BP_PXP_DATA_PATH_CTRL0_MUX5_SEL 10
+#define BM_PXP_DATA_PATH_CTRL0_MUX5_SEL 0x00000C00
+#define BF_PXP_DATA_PATH_CTRL0_MUX5_SEL(v) \
+ (((v) << 10) & BM_PXP_DATA_PATH_CTRL0_MUX5_SEL)
+#define BV_PXP_DATA_PATH_CTRL0_MUX5_SEL__0 0x0
+#define BV_PXP_DATA_PATH_CTRL0_MUX5_SEL__1 0x1
+#define BV_PXP_DATA_PATH_CTRL0_MUX5_SEL__2 0x2
+#define BV_PXP_DATA_PATH_CTRL0_MUX5_SEL__3 0x3
+#define BP_PXP_DATA_PATH_CTRL0_MUX4_SEL 8
+#define BM_PXP_DATA_PATH_CTRL0_MUX4_SEL 0x00000300
+#define BF_PXP_DATA_PATH_CTRL0_MUX4_SEL(v) \
+ (((v) << 8) & BM_PXP_DATA_PATH_CTRL0_MUX4_SEL)
+#define BV_PXP_DATA_PATH_CTRL0_MUX4_SEL__0 0x0
+#define BV_PXP_DATA_PATH_CTRL0_MUX4_SEL__1 0x1
+#define BV_PXP_DATA_PATH_CTRL0_MUX4_SEL__2 0x2
+#define BV_PXP_DATA_PATH_CTRL0_MUX4_SEL__3 0x3
+#define BP_PXP_DATA_PATH_CTRL0_MUX3_SEL 6
+#define BM_PXP_DATA_PATH_CTRL0_MUX3_SEL 0x000000C0
+#define BF_PXP_DATA_PATH_CTRL0_MUX3_SEL(v) \
+ (((v) << 6) & BM_PXP_DATA_PATH_CTRL0_MUX3_SEL)
+#define BV_PXP_DATA_PATH_CTRL0_MUX3_SEL__0 0x0
+#define BV_PXP_DATA_PATH_CTRL0_MUX3_SEL__1 0x1
+#define BV_PXP_DATA_PATH_CTRL0_MUX3_SEL__2 0x2
+#define BV_PXP_DATA_PATH_CTRL0_MUX3_SEL__3 0x3
+#define BP_PXP_DATA_PATH_CTRL0_MUX2_SEL 4
+#define BM_PXP_DATA_PATH_CTRL0_MUX2_SEL 0x00000030
+#define BF_PXP_DATA_PATH_CTRL0_MUX2_SEL(v) \
+ (((v) << 4) & BM_PXP_DATA_PATH_CTRL0_MUX2_SEL)
+#define BV_PXP_DATA_PATH_CTRL0_MUX2_SEL__0 0x0
+#define BV_PXP_DATA_PATH_CTRL0_MUX2_SEL__1 0x1
+#define BV_PXP_DATA_PATH_CTRL0_MUX2_SEL__2 0x2
+#define BV_PXP_DATA_PATH_CTRL0_MUX2_SEL__3 0x3
+#define BP_PXP_DATA_PATH_CTRL0_MUX1_SEL 2
+#define BM_PXP_DATA_PATH_CTRL0_MUX1_SEL 0x0000000C
+#define BF_PXP_DATA_PATH_CTRL0_MUX1_SEL(v) \
+ (((v) << 2) & BM_PXP_DATA_PATH_CTRL0_MUX1_SEL)
+#define BV_PXP_DATA_PATH_CTRL0_MUX1_SEL__0 0x0
+#define BV_PXP_DATA_PATH_CTRL0_MUX1_SEL__1 0x1
+#define BV_PXP_DATA_PATH_CTRL0_MUX1_SEL__2 0x2
+#define BV_PXP_DATA_PATH_CTRL0_MUX1_SEL__3 0x3
+#define BP_PXP_DATA_PATH_CTRL0_MUX0_SEL 0
+#define BM_PXP_DATA_PATH_CTRL0_MUX0_SEL 0x00000003
+#define BF_PXP_DATA_PATH_CTRL0_MUX0_SEL(v) \
+ (((v) << 0) & BM_PXP_DATA_PATH_CTRL0_MUX0_SEL)
+#define BV_PXP_DATA_PATH_CTRL0_MUX0_SEL__0 0x0
+#define BV_PXP_DATA_PATH_CTRL0_MUX0_SEL__1 0x1
+#define BV_PXP_DATA_PATH_CTRL0_MUX0_SEL__2 0x2
+#define BV_PXP_DATA_PATH_CTRL0_MUX0_SEL__3 0x3
+
+#define HW_PXP_DATA_PATH_CTRL1 (0x00000350)
+#define HW_PXP_DATA_PATH_CTRL1_SET (0x00000354)
+#define HW_PXP_DATA_PATH_CTRL1_CLR (0x00000358)
+#define HW_PXP_DATA_PATH_CTRL1_TOG (0x0000035c)
+
+#define BP_PXP_DATA_PATH_CTRL1_RSVD0 4
+#define BM_PXP_DATA_PATH_CTRL1_RSVD0 0xFFFFFFF0
+#define BF_PXP_DATA_PATH_CTRL1_RSVD0(v) \
+ (((v) << 4) & BM_PXP_DATA_PATH_CTRL1_RSVD0)
+#define BP_PXP_DATA_PATH_CTRL1_MUX17_SEL 2
+#define BM_PXP_DATA_PATH_CTRL1_MUX17_SEL 0x0000000C
+#define BF_PXP_DATA_PATH_CTRL1_MUX17_SEL(v) \
+ (((v) << 2) & BM_PXP_DATA_PATH_CTRL1_MUX17_SEL)
+#define BV_PXP_DATA_PATH_CTRL1_MUX17_SEL__0 0x0
+#define BV_PXP_DATA_PATH_CTRL1_MUX17_SEL__1 0x1
+#define BV_PXP_DATA_PATH_CTRL1_MUX17_SEL__2 0x2
+#define BV_PXP_DATA_PATH_CTRL1_MUX17_SEL__3 0x3
+#define BP_PXP_DATA_PATH_CTRL1_MUX16_SEL 0
+#define BM_PXP_DATA_PATH_CTRL1_MUX16_SEL 0x00000003
+#define BF_PXP_DATA_PATH_CTRL1_MUX16_SEL(v) \
+ (((v) << 0) & BM_PXP_DATA_PATH_CTRL1_MUX16_SEL)
+#define BV_PXP_DATA_PATH_CTRL1_MUX16_SEL__0 0x0
+#define BV_PXP_DATA_PATH_CTRL1_MUX16_SEL__1 0x1
+#define BV_PXP_DATA_PATH_CTRL1_MUX16_SEL__2 0x2
+#define BV_PXP_DATA_PATH_CTRL1_MUX16_SEL__3 0x3
+
+#define HW_PXP_INIT_MEM_CTRL (0x00000360)
+#define HW_PXP_INIT_MEM_CTRL_SET (0x00000364)
+#define HW_PXP_INIT_MEM_CTRL_CLR (0x00000368)
+#define HW_PXP_INIT_MEM_CTRL_TOG (0x0000036c)
+
+#define BM_PXP_INIT_MEM_CTRL_START 0x80000000
+#define BF_PXP_INIT_MEM_CTRL_START(v) \
+ (((v) << 31) & BM_PXP_INIT_MEM_CTRL_START)
+#define BP_PXP_INIT_MEM_CTRL_SELECT 27
+#define BM_PXP_INIT_MEM_CTRL_SELECT 0x78000000
+#define BF_PXP_INIT_MEM_CTRL_SELECT(v) \
+ (((v) << 27) & BM_PXP_INIT_MEM_CTRL_SELECT)
+#define BV_PXP_INIT_MEM_CTRL_SELECT__DITHER0_LUT 0x0
+#define BV_PXP_INIT_MEM_CTRL_SELECT__DITHER0_ERR0 0x1
+#define BV_PXP_INIT_MEM_CTRL_SELECT__DITHER0_ERR1 0x2
+#define BV_PXP_INIT_MEM_CTRL_SELECT__DITHER1_LUT 0x3
+#define BV_PXP_INIT_MEM_CTRL_SELECT__DITHER2_LUT 0x4
+#define BV_PXP_INIT_MEM_CTRL_SELECT__ALU_A 0x5
+#define BV_PXP_INIT_MEM_CTRL_SELECT__ALU_B 0x6
+#define BV_PXP_INIT_MEM_CTRL_SELECT__WFE_A_FETCH 0x7
+#define BV_PXP_INIT_MEM_CTRL_SELECT__WFE_B_FETCH 0x8
+#define BV_PXP_INIT_MEM_CTRL_SELECT__RESERVED 0x15
+#define BP_PXP_INIT_MEM_CTRL_RSVD0 16
+#define BM_PXP_INIT_MEM_CTRL_RSVD0 0x07FF0000
+#define BF_PXP_INIT_MEM_CTRL_RSVD0(v) \
+ (((v) << 16) & BM_PXP_INIT_MEM_CTRL_RSVD0)
+#define BP_PXP_INIT_MEM_CTRL_ADDR 0
+#define BM_PXP_INIT_MEM_CTRL_ADDR 0x0000FFFF
+#define BF_PXP_INIT_MEM_CTRL_ADDR(v) \
+ (((v) << 0) & BM_PXP_INIT_MEM_CTRL_ADDR)
+
+#define HW_PXP_INIT_MEM_DATA (0x00000370)
+
+#define BP_PXP_INIT_MEM_DATA_DATA 0
+#define BM_PXP_INIT_MEM_DATA_DATA 0xFFFFFFFF
+#define BF_PXP_INIT_MEM_DATA_DATA(v) (v)
+
+#define HW_PXP_INIT_MEM_DATA_HIGH (0x00000380)
+
+#define BP_PXP_INIT_MEM_DATA_HIGH_DATA 0
+#define BM_PXP_INIT_MEM_DATA_HIGH_DATA 0xFFFFFFFF
+#define BF_PXP_INIT_MEM_DATA_HIGH_DATA(v) (v)
+
+#define HW_PXP_IRQ_MASK (0x00000390)
+#define HW_PXP_IRQ_MASK_SET (0x00000394)
+#define HW_PXP_IRQ_MASK_CLR (0x00000398)
+#define HW_PXP_IRQ_MASK_TOG (0x0000039c)
+
+#define BM_PXP_IRQ_MASK_COMPRESS_DONE_IRQ_EN 0x80000000
+#define BF_PXP_IRQ_MASK_COMPRESS_DONE_IRQ_EN(v) \
+ (((v) << 31) & BM_PXP_IRQ_MASK_COMPRESS_DONE_IRQ_EN)
+#define BP_PXP_IRQ_MASK_RSVD1 16
+#define BM_PXP_IRQ_MASK_RSVD1 0x7FFF0000
+#define BF_PXP_IRQ_MASK_RSVD1(v) \
+ (((v) << 16) & BM_PXP_IRQ_MASK_RSVD1)
+#define BM_PXP_IRQ_MASK_WFE_B_STORE_IRQ_EN 0x00008000
+#define BF_PXP_IRQ_MASK_WFE_B_STORE_IRQ_EN(v) \
+ (((v) << 15) & BM_PXP_IRQ_MASK_WFE_B_STORE_IRQ_EN)
+#define BM_PXP_IRQ_MASK_WFE_A_STORE_IRQ_EN 0x00004000
+#define BF_PXP_IRQ_MASK_WFE_A_STORE_IRQ_EN(v) \
+ (((v) << 14) & BM_PXP_IRQ_MASK_WFE_A_STORE_IRQ_EN)
+#define BM_PXP_IRQ_MASK_DITHER_STORE_IRQ_EN 0x00002000
+#define BF_PXP_IRQ_MASK_DITHER_STORE_IRQ_EN(v) \
+ (((v) << 13) & BM_PXP_IRQ_MASK_DITHER_STORE_IRQ_EN)
+#define BM_PXP_IRQ_MASK_FIRST_STORE_IRQ_EN 0x00001000
+#define BF_PXP_IRQ_MASK_FIRST_STORE_IRQ_EN(v) \
+ (((v) << 12) & BM_PXP_IRQ_MASK_FIRST_STORE_IRQ_EN)
+#define BM_PXP_IRQ_MASK_WFE_B_CH1_STORE_IRQ_EN 0x00000800
+#define BF_PXP_IRQ_MASK_WFE_B_CH1_STORE_IRQ_EN(v) \
+ (((v) << 11) & BM_PXP_IRQ_MASK_WFE_B_CH1_STORE_IRQ_EN)
+#define BM_PXP_IRQ_MASK_WFE_B_CH0_STORE_IRQ_EN 0x00000400
+#define BF_PXP_IRQ_MASK_WFE_B_CH0_STORE_IRQ_EN(v) \
+ (((v) << 10) & BM_PXP_IRQ_MASK_WFE_B_CH0_STORE_IRQ_EN)
+#define BM_PXP_IRQ_MASK_WFE_A_CH1_STORE_IRQ_EN 0x00000200
+#define BF_PXP_IRQ_MASK_WFE_A_CH1_STORE_IRQ_EN(v) \
+ (((v) << 9) & BM_PXP_IRQ_MASK_WFE_A_CH1_STORE_IRQ_EN)
+#define BM_PXP_IRQ_MASK_WFE_A_CH0_STORE_IRQ_EN 0x00000100
+#define BF_PXP_IRQ_MASK_WFE_A_CH0_STORE_IRQ_EN(v) \
+ (((v) << 8) & BM_PXP_IRQ_MASK_WFE_A_CH0_STORE_IRQ_EN)
+#define BM_PXP_IRQ_MASK_DITHER_CH1_STORE_IRQ_EN 0x00000080
+#define BF_PXP_IRQ_MASK_DITHER_CH1_STORE_IRQ_EN(v) \
+ (((v) << 7) & BM_PXP_IRQ_MASK_DITHER_CH1_STORE_IRQ_EN)
+#define BM_PXP_IRQ_MASK_DITHER_CH0_STORE_IRQ_EN 0x00000040
+#define BF_PXP_IRQ_MASK_DITHER_CH0_STORE_IRQ_EN(v) \
+ (((v) << 6) & BM_PXP_IRQ_MASK_DITHER_CH0_STORE_IRQ_EN)
+#define BM_PXP_IRQ_MASK_DITHER_CH1_PREFETCH_IRQ_EN 0x00000020
+#define BF_PXP_IRQ_MASK_DITHER_CH1_PREFETCH_IRQ_EN(v) \
+ (((v) << 5) & BM_PXP_IRQ_MASK_DITHER_CH1_PREFETCH_IRQ_EN)
+#define BM_PXP_IRQ_MASK_DITHER_CH0_PREFETCH_IRQ_EN 0x00000010
+#define BF_PXP_IRQ_MASK_DITHER_CH0_PREFETCH_IRQ_EN(v) \
+ (((v) << 4) & BM_PXP_IRQ_MASK_DITHER_CH0_PREFETCH_IRQ_EN)
+#define BM_PXP_IRQ_MASK_FIRST_CH1_STORE_IRQ_EN 0x00000008
+#define BF_PXP_IRQ_MASK_FIRST_CH1_STORE_IRQ_EN(v) \
+ (((v) << 3) & BM_PXP_IRQ_MASK_FIRST_CH1_STORE_IRQ_EN)
+#define BM_PXP_IRQ_MASK_FIRST_CH0_STORE_IRQ_EN 0x00000004
+#define BF_PXP_IRQ_MASK_FIRST_CH0_STORE_IRQ_EN(v) \
+ (((v) << 2) & BM_PXP_IRQ_MASK_FIRST_CH0_STORE_IRQ_EN)
+#define BM_PXP_IRQ_MASK_FIRST_CH1_PREFETCH_IRQ_EN 0x00000002
+#define BF_PXP_IRQ_MASK_FIRST_CH1_PREFETCH_IRQ_EN(v) \
+ (((v) << 1) & BM_PXP_IRQ_MASK_FIRST_CH1_PREFETCH_IRQ_EN)
+#define BM_PXP_IRQ_MASK_FIRST_CH0_PREFETCH_IRQ_EN 0x00000001
+#define BF_PXP_IRQ_MASK_FIRST_CH0_PREFETCH_IRQ_EN(v) \
+ (((v) << 0) & BM_PXP_IRQ_MASK_FIRST_CH0_PREFETCH_IRQ_EN)
+
+#define HW_PXP_IRQ (0x000003a0)
+#define HW_PXP_IRQ_SET (0x000003a4)
+#define HW_PXP_IRQ_CLR (0x000003a8)
+#define HW_PXP_IRQ_TOG (0x000003ac)
+
+#define BM_PXP_IRQ_COMPRESS_DONE_IRQ 0x80000000
+#define BF_PXP_IRQ_COMPRESS_DONE_IRQ(v) \
+ (((v) << 31) & BM_PXP_IRQ_COMPRESS_DONE_IRQ)
+#define BP_PXP_IRQ_RSVD1 16
+#define BM_PXP_IRQ_RSVD1 0x7FFF0000
+#define BF_PXP_IRQ_RSVD1(v) \
+ (((v) << 16) & BM_PXP_IRQ_RSVD1)
+#define BM_PXP_IRQ_WFE_B_STORE_IRQ 0x00008000
+#define BF_PXP_IRQ_WFE_B_STORE_IRQ(v) \
+ (((v) << 15) & BM_PXP_IRQ_WFE_B_STORE_IRQ)
+#define BM_PXP_IRQ_WFE_A_STORE_IRQ 0x00004000
+#define BF_PXP_IRQ_WFE_A_STORE_IRQ(v) \
+ (((v) << 14) & BM_PXP_IRQ_WFE_A_STORE_IRQ)
+#define BM_PXP_IRQ_DITHER_STORE_IRQ 0x00002000
+#define BF_PXP_IRQ_DITHER_STORE_IRQ(v) \
+ (((v) << 13) & BM_PXP_IRQ_DITHER_STORE_IRQ)
+#define BM_PXP_IRQ_FIRST_STORE_IRQ 0x00001000
+#define BF_PXP_IRQ_FIRST_STORE_IRQ(v) \
+ (((v) << 12) & BM_PXP_IRQ_FIRST_STORE_IRQ)
+#define BM_PXP_IRQ_WFE_B_CH1_STORE_IRQ 0x00000800
+#define BF_PXP_IRQ_WFE_B_CH1_STORE_IRQ(v) \
+ (((v) << 11) & BM_PXP_IRQ_WFE_B_CH1_STORE_IRQ)
+#define BM_PXP_IRQ_WFE_B_CH0_STORE_IRQ 0x00000400
+#define BF_PXP_IRQ_WFE_B_CH0_STORE_IRQ(v) \
+ (((v) << 10) & BM_PXP_IRQ_WFE_B_CH0_STORE_IRQ)
+#define BM_PXP_IRQ_WFE_A_CH1_STORE_IRQ 0x00000200
+#define BF_PXP_IRQ_WFE_A_CH1_STORE_IRQ(v) \
+ (((v) << 9) & BM_PXP_IRQ_WFE_A_CH1_STORE_IRQ)
+#define BM_PXP_IRQ_WFE_A_CH0_STORE_IRQ 0x00000100
+#define BF_PXP_IRQ_WFE_A_CH0_STORE_IRQ(v) \
+ (((v) << 8) & BM_PXP_IRQ_WFE_A_CH0_STORE_IRQ)
+#define BM_PXP_IRQ_DITHER_CH1_STORE_IRQ 0x00000080
+#define BF_PXP_IRQ_DITHER_CH1_STORE_IRQ(v) \
+ (((v) << 7) & BM_PXP_IRQ_DITHER_CH1_STORE_IRQ)
+#define BM_PXP_IRQ_DITHER_CH0_STORE_IRQ 0x00000040
+#define BF_PXP_IRQ_DITHER_CH0_STORE_IRQ(v) \
+ (((v) << 6) & BM_PXP_IRQ_DITHER_CH0_STORE_IRQ)
+#define BM_PXP_IRQ_DITHER_CH1_PREFETCH_IRQ 0x00000020
+#define BF_PXP_IRQ_DITHER_CH1_PREFETCH_IRQ(v) \
+ (((v) << 5) & BM_PXP_IRQ_DITHER_CH1_PREFETCH_IRQ)
+#define BM_PXP_IRQ_DITHER_CH0_PREFETCH_IRQ 0x00000010
+#define BF_PXP_IRQ_DITHER_CH0_PREFETCH_IRQ(v) \
+ (((v) << 4) & BM_PXP_IRQ_DITHER_CH0_PREFETCH_IRQ)
+#define BM_PXP_IRQ_FIRST_CH1_STORE_IRQ 0x00000008
+#define BF_PXP_IRQ_FIRST_CH1_STORE_IRQ(v) \
+ (((v) << 3) & BM_PXP_IRQ_FIRST_CH1_STORE_IRQ)
+#define BM_PXP_IRQ_FIRST_CH0_STORE_IRQ 0x00000004
+#define BF_PXP_IRQ_FIRST_CH0_STORE_IRQ(v) \
+ (((v) << 2) & BM_PXP_IRQ_FIRST_CH0_STORE_IRQ)
+#define BM_PXP_IRQ_FIRST_CH1_PREFETCH_IRQ 0x00000002
+#define BF_PXP_IRQ_FIRST_CH1_PREFETCH_IRQ(v) \
+ (((v) << 1) & BM_PXP_IRQ_FIRST_CH1_PREFETCH_IRQ)
+#define BM_PXP_IRQ_FIRST_CH0_PREFETCH_IRQ 0x00000001
+#define BF_PXP_IRQ_FIRST_CH0_PREFETCH_IRQ(v) \
+ (((v) << 0) & BM_PXP_IRQ_FIRST_CH0_PREFETCH_IRQ)
+
+#define HW_PXP_NEXT (0x00000400)
+
+#define BP_PXP_NEXT_POINTER 2
+#define BM_PXP_NEXT_POINTER 0xFFFFFFFC
+#define BF_PXP_NEXT_POINTER(v) \
+ (((v) << 2) & BM_PXP_NEXT_POINTER)
+#define BM_PXP_NEXT_RSVD 0x00000002
+#define BF_PXP_NEXT_RSVD(v) \
+ (((v) << 1) & BM_PXP_NEXT_RSVD)
+#define BM_PXP_NEXT_ENABLED 0x00000001
+#define BF_PXP_NEXT_ENABLED(v) \
+ (((v) << 0) & BM_PXP_NEXT_ENABLED)
+
+#define HW_PXP_DEBUGCTRL (0x00000410)
+
+#define BP_PXP_DEBUGCTRL_RSVD 12
+#define BM_PXP_DEBUGCTRL_RSVD 0xFFFFF000
+#define BF_PXP_DEBUGCTRL_RSVD(v) \
+ (((v) << 12) & BM_PXP_DEBUGCTRL_RSVD)
+#define BP_PXP_DEBUGCTRL_LUT_CLR_STAT_CNT 8
+#define BM_PXP_DEBUGCTRL_LUT_CLR_STAT_CNT 0x00000F00
+#define BF_PXP_DEBUGCTRL_LUT_CLR_STAT_CNT(v) \
+ (((v) << 8) & BM_PXP_DEBUGCTRL_LUT_CLR_STAT_CNT)
+#define BV_PXP_DEBUGCTRL_LUT_CLR_STAT_CNT__NONE 0x0
+#define BV_PXP_DEBUGCTRL_LUT_CLR_STAT_CNT__MISS_CNT 0x1
+#define BV_PXP_DEBUGCTRL_LUT_CLR_STAT_CNT__HIT_CNT 0x2
+#define BV_PXP_DEBUGCTRL_LUT_CLR_STAT_CNT__LAT_CNT 0x4
+#define BV_PXP_DEBUGCTRL_LUT_CLR_STAT_CNT__MAX_LAT 0x8
+#define BP_PXP_DEBUGCTRL_SELECT 0
+#define BM_PXP_DEBUGCTRL_SELECT 0x000000FF
+#define BF_PXP_DEBUGCTRL_SELECT(v) \
+ (((v) << 0) & BM_PXP_DEBUGCTRL_SELECT)
+#define BV_PXP_DEBUGCTRL_SELECT__NONE 0x0
+#define BV_PXP_DEBUGCTRL_SELECT__CTRL 0x1
+#define BV_PXP_DEBUGCTRL_SELECT__PSBUF 0x2
+#define BV_PXP_DEBUGCTRL_SELECT__PSBAX 0x3
+#define BV_PXP_DEBUGCTRL_SELECT__PSBAY 0x4
+#define BV_PXP_DEBUGCTRL_SELECT__ASBUF 0x5
+#define BV_PXP_DEBUGCTRL_SELECT__ROTATION 0x6
+#define BV_PXP_DEBUGCTRL_SELECT__OUTBUF0 0x7
+#define BV_PXP_DEBUGCTRL_SELECT__OUTBUF1 0x8
+#define BV_PXP_DEBUGCTRL_SELECT__OUTBUF2 0x9
+#define BV_PXP_DEBUGCTRL_SELECT__LUT_STAT 0x10
+#define BV_PXP_DEBUGCTRL_SELECT__LUT_MISS 0x11
+#define BV_PXP_DEBUGCTRL_SELECT__LUT_HIT 0x12
+#define BV_PXP_DEBUGCTRL_SELECT__LUT_LAT 0x13
+#define BV_PXP_DEBUGCTRL_SELECT__LUT_MAX_LAT 0x14
+
+#define HW_PXP_DEBUG (0x00000420)
+
+#define BP_PXP_DEBUG_DATA 0
+#define BM_PXP_DEBUG_DATA 0xFFFFFFFF
+#define BF_PXP_DEBUG_DATA(v) (v)
+
+#define HW_PXP_VERSION (0x00000430)
+
+#define BP_PXP_VERSION_MAJOR 24
+#define BM_PXP_VERSION_MAJOR 0xFF000000
+#define BF_PXP_VERSION_MAJOR(v) \
+ (((v) << 24) & BM_PXP_VERSION_MAJOR)
+#define BP_PXP_VERSION_MINOR 16
+#define BM_PXP_VERSION_MINOR 0x00FF0000
+#define BF_PXP_VERSION_MINOR(v) \
+ (((v) << 16) & BM_PXP_VERSION_MINOR)
+#define BP_PXP_VERSION_STEP 0
+#define BM_PXP_VERSION_STEP 0x0000FFFF
+#define BF_PXP_VERSION_STEP(v) \
+ (((v) << 0) & BM_PXP_VERSION_STEP)
+
+#endif /* __IMX_PXP_H__ */
diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c
index 5f84d2aa47ab..c62e598ee7d0 100644
--- a/drivers/media/platform/m2m-deinterlace.c
+++ b/drivers/media/platform/m2m-deinterlace.c
@@ -438,9 +438,9 @@ static void deinterlace_device_run(void *priv)
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- strlcpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver));
- strlcpy(cap->card, MEM2MEM_NAME, sizeof(cap->card));
- strlcpy(cap->bus_info, MEM2MEM_NAME, sizeof(cap->card));
+ strscpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver));
+ strscpy(cap->card, MEM2MEM_NAME, sizeof(cap->card));
+ strscpy(cap->bus_info, MEM2MEM_NAME, sizeof(cap->card));
/*
* This is only a mem-to-mem video device. The capture and output
* device capability flags are left only for backward compatibility
@@ -474,7 +474,7 @@ static int enum_fmt(struct v4l2_fmtdesc *f, u32 type)
if (i < NUM_FORMATS) {
/* Format found */
fmt = &formats[i];
- strlcpy(f->description, fmt->name, sizeof(f->description));
+ strscpy(f->description, fmt->name, sizeof(f->description));
f->pixelformat = fmt->fourcc;
return 0;
}
diff --git a/drivers/media/platform/marvell-ccic/cafe-driver.c b/drivers/media/platform/marvell-ccic/cafe-driver.c
index 57d2c483ad09..2986cb4b88d0 100644
--- a/drivers/media/platform/marvell-ccic/cafe-driver.c
+++ b/drivers/media/platform/marvell-ccic/cafe-driver.c
@@ -341,7 +341,7 @@ static int cafe_smbus_setup(struct cafe_camera *cam)
return -ENOMEM;
adap->owner = THIS_MODULE;
adap->algo = &cafe_smbus_algo;
- strcpy(adap->name, "cafe_ccic");
+ strscpy(adap->name, "cafe_ccic", sizeof(adap->name));
adap->dev.parent = &cam->pdev->dev;
i2c_set_adapdata(adap, cam);
ret = i2c_add_adapter(adap);
diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c
index dfdbd4354b74..f1b301810260 100644
--- a/drivers/media/platform/marvell-ccic/mcam-core.c
+++ b/drivers/media/platform/marvell-ccic/mcam-core.c
@@ -794,7 +794,7 @@ static void mcam_ctlr_image(struct mcam_camera *cam)
/*
* This field controls the generation of EOF(DVP only)
*/
- if (cam->bus_type != V4L2_MBUS_CSI2)
+ if (cam->bus_type != V4L2_MBUS_CSI2_DPHY)
mcam_reg_set_bit(cam, REG_CTRL0,
C0_EOF_VSYNC | C0_VEDGE_CTRL);
}
@@ -1023,7 +1023,7 @@ static int mcam_read_setup(struct mcam_camera *cam)
cam->calc_dphy(cam);
cam_dbg(cam, "camera: DPHY sets: dphy3=0x%x, dphy5=0x%x, dphy6=0x%x\n",
cam->dphy[0], cam->dphy[1], cam->dphy[2]);
- if (cam->bus_type == V4L2_MBUS_CSI2)
+ if (cam->bus_type == V4L2_MBUS_CSI2_DPHY)
mcam_enable_mipi(cam);
else
mcam_disable_mipi(cam);
@@ -1303,9 +1303,9 @@ static int mcam_vidioc_querycap(struct file *file, void *priv,
{
struct mcam_camera *cam = video_drvdata(file);
- strcpy(cap->driver, "marvell_ccic");
- strcpy(cap->card, "marvell_ccic");
- strlcpy(cap->bus_info, cam->bus_info, sizeof(cap->bus_info));
+ strscpy(cap->driver, "marvell_ccic", sizeof(cap->driver));
+ strscpy(cap->card, "marvell_ccic", sizeof(cap->card));
+ strscpy(cap->bus_info, cam->bus_info, sizeof(cap->bus_info));
cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
@@ -1318,8 +1318,8 @@ static int mcam_vidioc_enum_fmt_vid_cap(struct file *filp,
{
if (fmt->index >= N_MCAM_FMTS)
return -EINVAL;
- strlcpy(fmt->description, mcam_formats[fmt->index].desc,
- sizeof(fmt->description));
+ strscpy(fmt->description, mcam_formats[fmt->index].desc,
+ sizeof(fmt->description));
fmt->pixelformat = mcam_formats[fmt->index].pixelformat;
return 0;
}
@@ -1421,7 +1421,7 @@ static int mcam_vidioc_enum_input(struct file *filp, void *priv,
return -EINVAL;
input->type = V4L2_INPUT_TYPE_CAMERA;
- strcpy(input->name, "Camera");
+ strscpy(input->name, "Camera", sizeof(input->name));
return 0;
}
diff --git a/drivers/media/platform/marvell-ccic/mmp-driver.c b/drivers/media/platform/marvell-ccic/mmp-driver.c
index 6d9f0abb2660..70a2833db0d1 100644
--- a/drivers/media/platform/marvell-ccic/mmp-driver.c
+++ b/drivers/media/platform/marvell-ccic/mmp-driver.c
@@ -362,7 +362,7 @@ static int mmpcam_probe(struct platform_device *pdev)
mcam->mclk_div = pdata->mclk_div;
mcam->bus_type = pdata->bus_type;
mcam->dphy = pdata->dphy;
- if (mcam->bus_type == V4L2_MBUS_CSI2) {
+ if (mcam->bus_type == V4L2_MBUS_CSI2_DPHY) {
cam->mipi_clk = devm_clk_get(mcam->dev, "mipi");
if ((IS_ERR(cam->mipi_clk) && mcam->dphy[2] == 0))
return PTR_ERR(cam->mipi_clk);
@@ -371,7 +371,7 @@ static int mmpcam_probe(struct platform_device *pdev)
mcam->lane = pdata->lane;
mcam->chip_id = MCAM_ARMADA610;
mcam->buffer_mode = B_DMA_sg;
- strlcpy(mcam->bus_info, "platform:mmp-camera", sizeof(mcam->bus_info));
+ strscpy(mcam->bus_info, "platform:mmp-camera", sizeof(mcam->bus_info));
spin_lock_init(&mcam->dev_lock);
/*
* Get our I/O memory.
diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c
index 4f24da8afecc..2a5d5002c27e 100644
--- a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c
+++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c
@@ -94,8 +94,8 @@ static int mtk_jpeg_querycap(struct file *file, void *priv,
{
struct mtk_jpeg_dev *jpeg = video_drvdata(file);
- strlcpy(cap->driver, MTK_JPEG_NAME " decoder", sizeof(cap->driver));
- strlcpy(cap->card, MTK_JPEG_NAME " decoder", sizeof(cap->card));
+ strscpy(cap->driver, MTK_JPEG_NAME " decoder", sizeof(cap->driver));
+ strscpy(cap->card, MTK_JPEG_NAME " decoder", sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
dev_name(jpeg->dev));
diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c
index ceffc31cc6eb..51a13466261e 100644
--- a/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c
+++ b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c
@@ -619,9 +619,9 @@ static int mtk_mdp_m2m_querycap(struct file *file, void *fh,
struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
struct mtk_mdp_dev *mdp = ctx->mdp_dev;
- strlcpy(cap->driver, MTK_MDP_MODULE_NAME, sizeof(cap->driver));
- strlcpy(cap->card, mdp->pdev->name, sizeof(cap->card));
- strlcpy(cap->bus_info, "platform:mt8173", sizeof(cap->bus_info));
+ strscpy(cap->driver, MTK_MDP_MODULE_NAME, sizeof(cap->driver));
+ strscpy(cap->card, mdp->pdev->name, sizeof(cap->card));
+ strscpy(cap->bus_info, "platform:mt8173", sizeof(cap->bus_info));
return 0;
}
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c
index 0c8a8b4c4e1c..ba619647bc10 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c
@@ -613,9 +613,9 @@ static int vidioc_vdec_dqbuf(struct file *file, void *priv,
static int vidioc_vdec_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- strlcpy(cap->driver, MTK_VCODEC_DEC_NAME, sizeof(cap->driver));
- strlcpy(cap->bus_info, MTK_PLATFORM_STR, sizeof(cap->bus_info));
- strlcpy(cap->card, MTK_PLATFORM_STR, sizeof(cap->card));
+ strscpy(cap->driver, MTK_VCODEC_DEC_NAME, sizeof(cap->driver));
+ strscpy(cap->bus_info, MTK_PLATFORM_STR, sizeof(cap->bus_info));
+ strscpy(cap->card, MTK_PLATFORM_STR, sizeof(cap->card));
return 0;
}
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
index 6ad408514a99..54631ad1c71e 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
@@ -222,9 +222,9 @@ static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *prov,
static int vidioc_venc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- strlcpy(cap->driver, MTK_VCODEC_ENC_NAME, sizeof(cap->driver));
- strlcpy(cap->bus_info, MTK_PLATFORM_STR, sizeof(cap->bus_info));
- strlcpy(cap->card, MTK_PLATFORM_STR, sizeof(cap->card));
+ strscpy(cap->driver, MTK_VCODEC_ENC_NAME, sizeof(cap->driver));
+ strscpy(cap->bus_info, MTK_PLATFORM_STR, sizeof(cap->bus_info));
+ strscpy(cap->card, MTK_PLATFORM_STR, sizeof(cap->card));
return 0;
}
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c
index 0c28d0b995cc..e80123cba406 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c
@@ -49,16 +49,13 @@ int mtk_vcodec_mem_alloc(struct mtk_vcodec_ctx *data,
struct mtk_vcodec_ctx *ctx = (struct mtk_vcodec_ctx *)data;
struct device *dev = &ctx->dev->plat_dev->dev;
- mem->va = dma_alloc_coherent(dev, size, &mem->dma_addr, GFP_KERNEL);
-
+ mem->va = dma_zalloc_coherent(dev, size, &mem->dma_addr, GFP_KERNEL);
if (!mem->va) {
mtk_v4l2_err("%s dma_alloc size=%ld failed!", dev_name(dev),
size);
return -ENOMEM;
}
- memset(mem->va, 0, size);
-
mtk_v4l2_debug(3, "[%d] - va = %p", ctx->id, mem->va);
mtk_v4l2_debug(3, "[%d] - dma = 0x%lx", ctx->id,
(unsigned long)mem->dma_addr);
diff --git a/drivers/media/platform/mtk-vpu/mtk_vpu.c b/drivers/media/platform/mtk-vpu/mtk_vpu.c
index f8d35e3ac1dc..616f78b24a79 100644
--- a/drivers/media/platform/mtk-vpu/mtk_vpu.c
+++ b/drivers/media/platform/mtk-vpu/mtk_vpu.c
@@ -480,12 +480,12 @@ EXPORT_SYMBOL_GPL(vpu_get_plat_device);
/* load vpu program/data memory */
static int load_requested_vpu(struct mtk_vpu *vpu,
- const struct firmware *vpu_fw,
u8 fw_type)
{
size_t tcm_size = fw_type ? VPU_DTCM_SIZE : VPU_PTCM_SIZE;
size_t fw_size = fw_type ? VPU_D_FW_SIZE : VPU_P_FW_SIZE;
char *fw_name = fw_type ? VPU_D_FW : VPU_P_FW;
+ const struct firmware *vpu_fw;
size_t dl_size = 0;
size_t extra_fw_size = 0;
void *dest;
@@ -539,7 +539,6 @@ int vpu_load_firmware(struct platform_device *pdev)
struct mtk_vpu *vpu;
struct device *dev = &pdev->dev;
struct vpu_run *run;
- const struct firmware *vpu_fw = NULL;
int ret;
if (!pdev) {
@@ -568,14 +567,14 @@ int vpu_load_firmware(struct platform_device *pdev)
run->signaled = false;
dev_dbg(vpu->dev, "firmware request\n");
/* Downloading program firmware to device*/
- ret = load_requested_vpu(vpu, vpu_fw, P_FW);
+ ret = load_requested_vpu(vpu, P_FW);
if (ret < 0) {
dev_err(dev, "Failed to request %s, %d\n", VPU_P_FW, ret);
goto OUT_LOAD_FW;
}
/* Downloading data firmware to device */
- ret = load_requested_vpu(vpu, vpu_fw, D_FW);
+ ret = load_requested_vpu(vpu, D_FW);
if (ret < 0) {
dev_err(dev, "Failed to request %s, %d\n", VPU_D_FW, ret);
goto OUT_LOAD_FW;
diff --git a/drivers/media/platform/mx2_emmaprp.c b/drivers/media/platform/mx2_emmaprp.c
index 64195c4ddeaf..27b078cf98e3 100644
--- a/drivers/media/platform/mx2_emmaprp.c
+++ b/drivers/media/platform/mx2_emmaprp.c
@@ -413,7 +413,7 @@ static int enum_fmt(struct v4l2_fmtdesc *f, u32 type)
if (i < NUM_FORMATS) {
/* Format found */
fmt = &formats[i];
- strlcpy(f->description, fmt->name, sizeof(f->description) - 1);
+ strscpy(f->description, fmt->name, sizeof(f->description) - 1);
f->pixelformat = fmt->fourcc;
return 0;
}
diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c
index 5700b7818621..f447ae3bb465 100644
--- a/drivers/media/platform/omap/omap_vout.c
+++ b/drivers/media/platform/omap/omap_vout.c
@@ -1041,8 +1041,8 @@ static int vidioc_querycap(struct file *file, void *fh,
{
struct omap_vout_device *vout = fh;
- strlcpy(cap->driver, VOUT_NAME, sizeof(cap->driver));
- strlcpy(cap->card, vout->vfd->name, sizeof(cap->card));
+ strscpy(cap->driver, VOUT_NAME, sizeof(cap->driver));
+ strscpy(cap->card, vout->vfd->name, sizeof(cap->card));
cap->bus_info[0] = '\0';
cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT |
V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
@@ -1060,8 +1060,8 @@ static int vidioc_enum_fmt_vid_out(struct file *file, void *fh,
return -EINVAL;
fmt->flags = omap_formats[index].flags;
- strlcpy(fmt->description, omap_formats[index].description,
- sizeof(fmt->description));
+ strscpy(fmt->description, omap_formats[index].description,
+ sizeof(fmt->description));
fmt->pixelformat = omap_formats[index].pixelformat;
return 0;
@@ -1868,7 +1868,7 @@ static int __init omap_vout_setup_video_data(struct omap_vout_device *vout)
vfd->release = video_device_release;
vfd->ioctl_ops = &vout_ioctl_ops;
- strlcpy(vfd->name, VOUT_NAME, sizeof(vfd->name));
+ strscpy(vfd->name, VOUT_NAME, sizeof(vfd->name));
vfd->fops = &omap_vout_fops;
vfd->v4l2_dev = &vout->vid_dev->v4l2_dev;
diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
index 842e2235047d..77fb7987b42f 100644
--- a/drivers/media/platform/omap3isp/isp.c
+++ b/drivers/media/platform/omap3isp/isp.c
@@ -1677,7 +1677,7 @@ static int isp_register_entities(struct isp_device *isp)
int ret;
isp->media_dev.dev = isp->dev;
- strlcpy(isp->media_dev.model, "TI OMAP3 ISP",
+ strscpy(isp->media_dev.model, "TI OMAP3 ISP",
sizeof(isp->media_dev.model));
isp->media_dev.hw_revision = isp->revision;
isp->media_dev.ops = &isp_media_ops;
@@ -2054,7 +2054,7 @@ static int isp_fwnode_parse(struct device *dev,
dev_dbg(dev, "CSI-1/CCP-2 configuration\n");
csi1 = true;
break;
- case V4L2_MBUS_CSI2:
+ case V4L2_MBUS_CSI2_DPHY:
dev_dbg(dev, "CSI-2 configuration\n");
csi1 = false;
break;
@@ -2220,6 +2220,7 @@ static int isp_probe(struct platform_device *pdev)
mutex_init(&isp->isp_mutex);
spin_lock_init(&isp->stat_lock);
+ v4l2_async_notifier_init(&isp->notifier);
ret = v4l2_async_notifier_parse_fwnode_endpoints(
&pdev->dev, &isp->notifier, sizeof(struct isp_async_subdev),
diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c
index 77b73e27a274..14a1c24037c4 100644
--- a/drivers/media/platform/omap3isp/ispccdc.c
+++ b/drivers/media/platform/omap3isp/ispccdc.c
@@ -2641,7 +2641,7 @@ static int ccdc_init_entities(struct isp_ccdc_device *ccdc)
v4l2_subdev_init(sd, &ccdc_v4l2_ops);
sd->internal_ops = &ccdc_v4l2_internal_ops;
- strlcpy(sd->name, "OMAP3 ISP CCDC", sizeof(sd->name));
+ strscpy(sd->name, "OMAP3 ISP CCDC", sizeof(sd->name));
sd->grp_id = 1 << 16; /* group ID for isp subdevs */
v4l2_set_subdevdata(sd, ccdc);
sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
diff --git a/drivers/media/platform/omap3isp/ispccp2.c b/drivers/media/platform/omap3isp/ispccp2.c
index e062939d0d05..2dea423ffc0e 100644
--- a/drivers/media/platform/omap3isp/ispccp2.c
+++ b/drivers/media/platform/omap3isp/ispccp2.c
@@ -1070,7 +1070,7 @@ static int ccp2_init_entities(struct isp_ccp2_device *ccp2)
v4l2_subdev_init(sd, &ccp2_sd_ops);
sd->internal_ops = &ccp2_sd_internal_ops;
- strlcpy(sd->name, "OMAP3 ISP CCP2", sizeof(sd->name));
+ strscpy(sd->name, "OMAP3 ISP CCP2", sizeof(sd->name));
sd->grp_id = 1 << 16; /* group ID for isp subdevs */
v4l2_set_subdevdata(sd, ccp2);
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
diff --git a/drivers/media/platform/omap3isp/ispcsi2.c b/drivers/media/platform/omap3isp/ispcsi2.c
index a4d3d030e81e..9c180f607bcb 100644
--- a/drivers/media/platform/omap3isp/ispcsi2.c
+++ b/drivers/media/platform/omap3isp/ispcsi2.c
@@ -1234,7 +1234,7 @@ static int csi2_init_entities(struct isp_csi2_device *csi2)
v4l2_subdev_init(sd, &csi2_ops);
sd->internal_ops = &csi2_internal_ops;
- strlcpy(sd->name, "OMAP3 ISP CSI2a", sizeof(sd->name));
+ strscpy(sd->name, "OMAP3 ISP CSI2a", sizeof(sd->name));
sd->grp_id = 1 << 16; /* group ID for isp subdevs */
v4l2_set_subdevdata(sd, csi2);
diff --git a/drivers/media/platform/omap3isp/isppreview.c b/drivers/media/platform/omap3isp/isppreview.c
index 3195f7c8b8b7..6ea6aeafd751 100644
--- a/drivers/media/platform/omap3isp/isppreview.c
+++ b/drivers/media/platform/omap3isp/isppreview.c
@@ -2267,7 +2267,7 @@ static int preview_init_entities(struct isp_prev_device *prev)
v4l2_subdev_init(sd, &preview_v4l2_ops);
sd->internal_ops = &preview_v4l2_internal_ops;
- strlcpy(sd->name, "OMAP3 ISP preview", sizeof(sd->name));
+ strscpy(sd->name, "OMAP3 ISP preview", sizeof(sd->name));
sd->grp_id = 1 << 16; /* group ID for isp subdevs */
v4l2_set_subdevdata(sd, prev);
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
diff --git a/drivers/media/platform/omap3isp/ispresizer.c b/drivers/media/platform/omap3isp/ispresizer.c
index 0b6a87508584..b281cae036b3 100644
--- a/drivers/media/platform/omap3isp/ispresizer.c
+++ b/drivers/media/platform/omap3isp/ispresizer.c
@@ -1723,7 +1723,7 @@ static int resizer_init_entities(struct isp_res_device *res)
v4l2_subdev_init(sd, &resizer_v4l2_ops);
sd->internal_ops = &resizer_v4l2_internal_ops;
- strlcpy(sd->name, "OMAP3 ISP resizer", sizeof(sd->name));
+ strscpy(sd->name, "OMAP3 ISP resizer", sizeof(sd->name));
sd->grp_id = 1 << 16; /* group ID for isp subdevs */
v4l2_set_subdevdata(sd, res);
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c
index 9d228eac24ea..078d64114b24 100644
--- a/drivers/media/platform/omap3isp/ispvideo.c
+++ b/drivers/media/platform/omap3isp/ispvideo.c
@@ -654,9 +654,9 @@ isp_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
{
struct isp_video *video = video_drvdata(file);
- strlcpy(cap->driver, ISP_VIDEO_DRIVER_NAME, sizeof(cap->driver));
- strlcpy(cap->card, video->video.name, sizeof(cap->card));
- strlcpy(cap->bus_info, "media", sizeof(cap->bus_info));
+ strscpy(cap->driver, ISP_VIDEO_DRIVER_NAME, sizeof(cap->driver));
+ strscpy(cap->card, video->video.name, sizeof(cap->card));
+ strscpy(cap->bus_info, "media", sizeof(cap->bus_info));
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT
| V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS;
@@ -940,7 +940,7 @@ isp_video_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
int ret;
mutex_lock(&video->queue_lock);
- ret = vb2_qbuf(&vfh->queue, b);
+ ret = vb2_qbuf(&vfh->queue, video->video.v4l2_dev->mdev, b);
mutex_unlock(&video->queue_lock);
return ret;
@@ -1028,7 +1028,7 @@ static int isp_video_check_external_subdevs(struct isp_video *video,
ctrls.count = 1;
ctrls.controls = &ctrl;
- ret = v4l2_g_ext_ctrls(pipe->external->ctrl_handler, &ctrls);
+ ret = v4l2_g_ext_ctrls(pipe->external->ctrl_handler, NULL, &ctrls);
if (ret < 0) {
dev_warn(isp->dev, "no pixel rate control in subdev %s\n",
pipe->external->name);
@@ -1251,7 +1251,7 @@ isp_video_enum_input(struct file *file, void *fh, struct v4l2_input *input)
if (input->index > 0)
return -EINVAL;
- strlcpy(input->name, "camera", sizeof(input->name));
+ strscpy(input->name, "camera", sizeof(input->name));
input->type = V4L2_INPUT_TYPE_CAMERA;
return 0;
diff --git a/drivers/media/platform/pxa_camera.c b/drivers/media/platform/pxa_camera.c
index b6e9e93bde7a..5f930560eb30 100644
--- a/drivers/media/platform/pxa_camera.c
+++ b/drivers/media/platform/pxa_camera.c
@@ -633,7 +633,7 @@ static unsigned int pxa_mbus_config_compatible(const struct v4l2_mbus_config *cf
mode = common_flags & (V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE);
return (!hsync || !vsync || !pclk || !data || !mode) ?
0 : common_flags;
- case V4L2_MBUS_CSI2:
+ case V4L2_MBUS_CSI2_DPHY:
mipi_lanes = common_flags & V4L2_MBUS_CSI2_LANES;
mipi_clock = common_flags & (V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK |
V4L2_MBUS_CSI2_CONTINUOUS_CLOCK);
@@ -697,7 +697,6 @@ struct pxa_camera_dev {
struct v4l2_pix_format current_pix;
struct v4l2_async_subdev asd;
- struct v4l2_async_subdev *asds[1];
/*
* PXA27x is only supposed to handle one camera on its Quick Capture
@@ -1994,9 +1993,9 @@ static int pxac_vidioc_s_fmt_vid_cap(struct file *filp, void *priv,
static int pxac_vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- strlcpy(cap->bus_info, "platform:pxa-camera", sizeof(cap->bus_info));
- strlcpy(cap->driver, PXA_CAM_DRV_NAME, sizeof(cap->driver));
- strlcpy(cap->card, pxa_cam_driver_description, sizeof(cap->card));
+ strscpy(cap->bus_info, "platform:pxa-camera", sizeof(cap->bus_info));
+ strscpy(cap->driver, PXA_CAM_DRV_NAME, sizeof(cap->driver));
+ strscpy(cap->card, pxa_cam_driver_description, sizeof(cap->card));
cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
@@ -2010,7 +2009,7 @@ static int pxac_vidioc_enum_input(struct file *file, void *priv,
return -EINVAL;
i->type = V4L2_INPUT_TYPE_CAMERA;
- strlcpy(i->name, "Camera", sizeof(i->name));
+ strscpy(i->name, "Camera", sizeof(i->name));
return 0;
}
@@ -2299,7 +2298,7 @@ static int pxa_camera_pdata_from_dt(struct device *dev,
{
u32 mclk_rate;
struct device_node *remote, *np = dev->of_node;
- struct v4l2_fwnode_endpoint ep;
+ struct v4l2_fwnode_endpoint ep = { .bus_type = 0 };
int err = of_property_read_u32(np, "clock-frequency",
&mclk_rate);
if (!err) {
@@ -2352,12 +2351,10 @@ static int pxa_camera_pdata_from_dt(struct device *dev,
asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
remote = of_graph_get_remote_port(np);
- if (remote) {
+ if (remote)
asd->match.fwnode = of_fwnode_handle(remote);
- of_node_put(remote);
- } else {
+ else
dev_notice(dev, "no remote for %pOF\n", np);
- }
out:
of_node_put(np);
@@ -2397,7 +2394,7 @@ static int pxa_camera_probe(struct platform_device *pdev)
pcdev->res = res;
pcdev->pdata = pdev->dev.platform_data;
- if (&pdev->dev.of_node && !pcdev->pdata) {
+ if (pdev->dev.of_node && !pcdev->pdata) {
err = pxa_camera_pdata_from_dt(&pdev->dev, pcdev, &pcdev->asd);
} else {
pcdev->platform_flags = pcdev->pdata->flags;
@@ -2495,9 +2492,14 @@ static int pxa_camera_probe(struct platform_device *pdev)
if (err)
goto exit_deactivate;
- pcdev->asds[0] = &pcdev->asd;
- pcdev->notifier.subdevs = pcdev->asds;
- pcdev->notifier.num_subdevs = 1;
+ v4l2_async_notifier_init(&pcdev->notifier);
+
+ err = v4l2_async_notifier_add_subdev(&pcdev->notifier, &pcdev->asd);
+ if (err) {
+ fwnode_handle_put(pcdev->asd.match.fwnode);
+ goto exit_free_v4l2dev;
+ }
+
pcdev->notifier.ops = &pxa_camera_sensor_ops;
if (!of_have_populated_dt())
@@ -2505,7 +2507,7 @@ static int pxa_camera_probe(struct platform_device *pdev)
err = pxa_camera_init_videobuf2(pcdev);
if (err)
- goto exit_free_v4l2dev;
+ goto exit_notifier_cleanup;
if (pcdev->mclk) {
v4l2_clk_name_i2c(clk_name, sizeof(clk_name),
@@ -2516,7 +2518,7 @@ static int pxa_camera_probe(struct platform_device *pdev)
clk_name, NULL);
if (IS_ERR(pcdev->mclk_clk)) {
err = PTR_ERR(pcdev->mclk_clk);
- goto exit_free_v4l2dev;
+ goto exit_notifier_cleanup;
}
}
@@ -2527,6 +2529,8 @@ static int pxa_camera_probe(struct platform_device *pdev)
return 0;
exit_free_clk:
v4l2_clk_unregister(pcdev->mclk_clk);
+exit_notifier_cleanup:
+ v4l2_async_notifier_cleanup(&pcdev->notifier);
exit_free_v4l2dev:
v4l2_device_unregister(&pcdev->v4l2_dev);
exit_deactivate:
@@ -2550,6 +2554,7 @@ static int pxa_camera_remove(struct platform_device *pdev)
dma_release_channel(pcdev->dma_chans[2]);
v4l2_async_notifier_unregister(&pcdev->notifier);
+ v4l2_async_notifier_cleanup(&pcdev->notifier);
if (pcdev->mclk_clk) {
v4l2_clk_unregister(pcdev->mclk_clk);
diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c
index c9bb0d023db4..58aebe7114cd 100644
--- a/drivers/media/platform/qcom/camss/camss-video.c
+++ b/drivers/media/platform/qcom/camss/camss-video.c
@@ -521,8 +521,8 @@ static int video_querycap(struct file *file, void *fh,
{
struct camss_video *video = video_drvdata(file);
- strlcpy(cap->driver, "qcom-camss", sizeof(cap->driver));
- strlcpy(cap->card, "Qualcomm Camera Subsystem", sizeof(cap->card));
+ strscpy(cap->driver, "qcom-camss", sizeof(cap->driver));
+ strscpy(cap->card, "Qualcomm Camera Subsystem", sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
dev_name(video->camss->dev));
@@ -683,7 +683,7 @@ static int video_enum_input(struct file *file, void *fh,
if (input->index > 0)
return -EINVAL;
- strlcpy(input->name, "camera", sizeof(input->name));
+ strscpy(input->name, "camera", sizeof(input->name));
input->type = V4L2_INPUT_TYPE_CAMERA;
return 0;
@@ -919,7 +919,7 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev,
vdev->vfl_dir = VFL_DIR_RX;
vdev->queue = &video->vb2_q;
vdev->lock = &video->lock;
- strlcpy(vdev->name, name, sizeof(vdev->name));
+ strscpy(vdev->name, name, sizeof(vdev->name));
ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
if (ret < 0) {
diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index 669615fff6a0..45978db3b0be 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -462,61 +462,51 @@ static int camss_of_parse_endpoint_node(struct device *dev,
*
* Return number of "port" nodes found in "ports" node
*/
-static int camss_of_parse_ports(struct device *dev,
- struct v4l2_async_notifier *notifier)
+static int camss_of_parse_ports(struct camss *camss)
{
+ struct device *dev = camss->dev;
struct device_node *node = NULL;
struct device_node *remote = NULL;
- unsigned int size, i;
- int ret;
-
- while ((node = of_graph_get_next_endpoint(dev->of_node, node)))
- if (of_device_is_available(node))
- notifier->num_subdevs++;
-
- of_node_put(node);
- size = sizeof(*notifier->subdevs) * notifier->num_subdevs;
- notifier->subdevs = devm_kzalloc(dev, size, GFP_KERNEL);
- if (!notifier->subdevs) {
- dev_err(dev, "Failed to allocate memory\n");
- return -ENOMEM;
- }
+ int ret, num_subdevs = 0;
- i = 0;
- while ((node = of_graph_get_next_endpoint(dev->of_node, node))) {
+ for_each_endpoint_of_node(dev->of_node, node) {
struct camss_async_subdev *csd;
+ struct v4l2_async_subdev *asd;
if (!of_device_is_available(node))
continue;
- csd = devm_kzalloc(dev, sizeof(*csd), GFP_KERNEL);
- if (!csd) {
- of_node_put(node);
- dev_err(dev, "Failed to allocate memory\n");
- return -ENOMEM;
- }
-
- notifier->subdevs[i++] = &csd->asd;
-
- ret = camss_of_parse_endpoint_node(dev, node, csd);
- if (ret < 0) {
- of_node_put(node);
- return ret;
- }
-
remote = of_graph_get_remote_port_parent(node);
if (!remote) {
dev_err(dev, "Cannot get remote parent\n");
- of_node_put(node);
- return -EINVAL;
+ ret = -EINVAL;
+ goto err_cleanup;
}
- csd->asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
- csd->asd.match.fwnode = of_fwnode_handle(remote);
+ asd = v4l2_async_notifier_add_fwnode_subdev(
+ &camss->notifier, of_fwnode_handle(remote),
+ sizeof(*csd));
+ if (IS_ERR(asd)) {
+ ret = PTR_ERR(asd);
+ of_node_put(remote);
+ goto err_cleanup;
+ }
+
+ csd = container_of(asd, struct camss_async_subdev, asd);
+
+ ret = camss_of_parse_endpoint_node(dev, node, csd);
+ if (ret < 0)
+ goto err_cleanup;
+
+ num_subdevs++;
}
- of_node_put(node);
- return notifier->num_subdevs;
+ return num_subdevs;
+
+err_cleanup:
+ v4l2_async_notifier_cleanup(&camss->notifier);
+ of_node_put(node);
+ return ret;
}
/*
@@ -823,7 +813,7 @@ static int camss_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct camss *camss;
- int ret;
+ int num_subdevs, ret;
camss = kzalloc(sizeof(*camss), GFP_KERNEL);
if (!camss)
@@ -863,20 +853,22 @@ static int camss_probe(struct platform_device *pdev)
if (!camss->vfe)
return -ENOMEM;
- ret = camss_of_parse_ports(dev, &camss->notifier);
- if (ret < 0)
- return ret;
+ v4l2_async_notifier_init(&camss->notifier);
+
+ num_subdevs = camss_of_parse_ports(camss);
+ if (num_subdevs < 0)
+ return num_subdevs;
ret = camss_init_subdevices(camss);
if (ret < 0)
- return ret;
+ goto err_cleanup;
ret = dma_set_mask_and_coherent(dev, 0xffffffff);
if (ret)
- return ret;
+ goto err_cleanup;
camss->media_dev.dev = camss->dev;
- strlcpy(camss->media_dev.model, "Qualcomm Camera Subsystem",
+ strscpy(camss->media_dev.model, "Qualcomm Camera Subsystem",
sizeof(camss->media_dev.model));
camss->media_dev.ops = &camss_media_ops;
media_device_init(&camss->media_dev);
@@ -885,14 +877,14 @@ static int camss_probe(struct platform_device *pdev)
ret = v4l2_device_register(camss->dev, &camss->v4l2_dev);
if (ret < 0) {
dev_err(dev, "Failed to register V4L2 device: %d\n", ret);
- return ret;
+ goto err_cleanup;
}
ret = camss_register_entities(camss);
if (ret < 0)
goto err_register_entities;
- if (camss->notifier.num_subdevs) {
+ if (num_subdevs) {
camss->notifier.ops = &camss_subdev_notifier_ops;
ret = v4l2_async_notifier_register(&camss->v4l2_dev,
@@ -942,6 +934,8 @@ err_register_subdevs:
camss_unregister_entities(camss);
err_register_entities:
v4l2_device_unregister(&camss->v4l2_dev);
+err_cleanup:
+ v4l2_async_notifier_cleanup(&camss->notifier);
return ret;
}
@@ -978,6 +972,7 @@ static int camss_remove(struct platform_device *pdev)
msm_vfe_stop_streaming(&camss->vfe[i]);
v4l2_async_notifier_unregister(&camss->notifier);
+ v4l2_async_notifier_cleanup(&camss->notifier);
camss_unregister_entities(camss);
if (atomic_read(&camss->ref_count) == 0)
diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h
index 418996d8dad8..57b269ca93fd 100644
--- a/drivers/media/platform/qcom/camss/camss.h
+++ b/drivers/media/platform/qcom/camss/camss.h
@@ -17,7 +17,6 @@
#include <media/v4l2-subdev.h>
#include <media/media-device.h>
#include <media/media-entity.h>
-#include <linux/device.h>
#include "camss-csid.h"
#include "camss-csiphy.h"
@@ -92,8 +91,8 @@ struct camss_camera_interface {
};
struct camss_async_subdev {
+ struct v4l2_async_subdev asd; /* must be first */
struct camss_camera_interface interface;
- struct v4l2_async_subdev asd;
};
struct camss_clock {
diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c
index cd3b96e6f24b..e436385bc5ab 100644
--- a/drivers/media/platform/qcom/venus/helpers.c
+++ b/drivers/media/platform/qcom/venus/helpers.c
@@ -472,7 +472,7 @@ static bool is_dynamic_bufmode(struct venus_inst *inst)
caps = venus_caps_by_codec(core, inst->hfi_codec, inst->session_type);
if (!caps)
- return 0;
+ return false;
return caps->cap_bufs_mode_dynamic;
}
diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c
index dfbbbf0f746f..189ec975c6bb 100644
--- a/drivers/media/platform/qcom/venus/vdec.c
+++ b/drivers/media/platform/qcom/venus/vdec.c
@@ -341,9 +341,9 @@ vdec_g_selection(struct file *file, void *fh, struct v4l2_selection *s)
static int
vdec_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
{
- strlcpy(cap->driver, "qcom-venus", sizeof(cap->driver));
- strlcpy(cap->card, "Qualcomm Venus video decoder", sizeof(cap->card));
- strlcpy(cap->bus_info, "platform:qcom-venus", sizeof(cap->bus_info));
+ strscpy(cap->driver, "qcom-venus", sizeof(cap->driver));
+ strscpy(cap->card, "Qualcomm Venus video decoder", sizeof(cap->card));
+ strscpy(cap->bus_info, "platform:qcom-venus", sizeof(cap->bus_info));
return 0;
}
@@ -888,8 +888,7 @@ static void vdec_buf_done(struct venus_inst *inst, unsigned int buf_type,
unsigned int opb_sz = venus_helper_get_opb_size(inst);
vb = &vbuf->vb2_buf;
- vb->planes[0].bytesused =
- max_t(unsigned int, opb_sz, bytesused);
+ vb2_set_plane_payload(vb, 0, bytesused ? : opb_sz);
vb->planes[0].data_offset = data_offset;
vb->timestamp = timestamp_us * NSEC_PER_USEC;
vbuf->sequence = inst->sequence_cap++;
@@ -1153,7 +1152,7 @@ static int vdec_probe(struct platform_device *pdev)
if (!vdev)
return -ENOMEM;
- strlcpy(vdev->name, "qcom-venus-decoder", sizeof(vdev->name));
+ strscpy(vdev->name, "qcom-venus-decoder", sizeof(vdev->name));
vdev->release = video_device_release;
vdev->fops = &vdec_fops;
vdev->ioctl_ops = &vdec_ioctl_ops;
diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c
index 41249d1443fa..ce85962b6adc 100644
--- a/drivers/media/platform/qcom/venus/venc.c
+++ b/drivers/media/platform/qcom/venus/venc.c
@@ -273,9 +273,9 @@ static int venc_v4l2_to_hfi(int id, int value)
static int
venc_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
{
- strlcpy(cap->driver, "qcom-venus", sizeof(cap->driver));
- strlcpy(cap->card, "Qualcomm Venus video encoder", sizeof(cap->card));
- strlcpy(cap->bus_info, "platform:qcom-venus", sizeof(cap->bus_info));
+ strscpy(cap->driver, "qcom-venus", sizeof(cap->driver));
+ strscpy(cap->card, "Qualcomm Venus video encoder", sizeof(cap->card));
+ strscpy(cap->bus_info, "platform:qcom-venus", sizeof(cap->bus_info));
return 0;
}
@@ -1257,7 +1257,7 @@ static int venc_probe(struct platform_device *pdev)
if (!vdev)
return -ENOMEM;
- strlcpy(vdev->name, "qcom-venus-encoder", sizeof(vdev->name));
+ strscpy(vdev->name, "qcom-venus-encoder", sizeof(vdev->name));
vdev->release = video_device_release;
vdev->fops = &venc_fops;
vdev->ioctl_ops = &venc_ioctl_ops;
diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c
index ce09799976ef..f476b2f1eb35 100644
--- a/drivers/media/platform/rcar-vin/rcar-core.c
+++ b/drivers/media/platform/rcar-vin/rcar-core.c
@@ -170,7 +170,6 @@ static int rvin_group_link_notify(struct media_link *link, u32 flags,
if (csi_id == -ENODEV) {
struct v4l2_subdev *sd;
- unsigned int i;
/*
* Make sure the source entity subdevice is registered as
@@ -268,8 +267,8 @@ static int rvin_group_init(struct rvin_group *group, struct rvin_dev *vin)
match = of_match_node(vin->dev->driver->of_match_table,
vin->dev->of_node);
- strlcpy(mdev->driver_name, KBUILD_MODNAME, sizeof(mdev->driver_name));
- strlcpy(mdev->model, match->compatible, sizeof(mdev->model));
+ strscpy(mdev->driver_name, KBUILD_MODNAME, sizeof(mdev->driver_name));
+ strscpy(mdev->model, match->compatible, sizeof(mdev->model));
snprintf(mdev->bus_info, sizeof(mdev->bus_info), "platform:%s",
dev_name(mdev->dev));
@@ -476,7 +475,7 @@ static int rvin_parallel_subdevice_attach(struct rvin_dev *vin,
return ret;
ret = v4l2_ctrl_add_handler(&vin->ctrl_handler, subdev->ctrl_handler,
- NULL);
+ NULL, true);
if (ret < 0) {
v4l2_ctrl_handler_free(&vin->ctrl_handler);
return ret;
@@ -611,6 +610,8 @@ static int rvin_parallel_init(struct rvin_dev *vin)
{
int ret;
+ v4l2_async_notifier_init(&vin->notifier);
+
ret = v4l2_async_notifier_parse_fwnode_endpoints_by_port(
vin->dev, &vin->notifier, sizeof(struct rvin_parallel_entity),
0, rvin_parallel_parse_v4l2);
@@ -803,6 +804,8 @@ static int rvin_mc_parse_of_graph(struct rvin_dev *vin)
return 0;
}
+ v4l2_async_notifier_init(&vin->group->notifier);
+
/*
* Have all VIN's look for CSI-2 subdevices. Some subdevices will
* overlap but the parser function can handle it, so each subdevice
@@ -824,7 +827,7 @@ static int rvin_mc_parse_of_graph(struct rvin_dev *vin)
mutex_unlock(&vin->group->lock);
- if (!vin->group->notifier.num_subdevs)
+ if (list_empty(&vin->group->notifier.asd_list))
return 0;
vin->group->notifier.ops = &rvin_group_notify_ops;
diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c
index dc5ae8025832..b0044a08e71e 100644
--- a/drivers/media/platform/rcar-vin/rcar-csi2.c
+++ b/drivers/media/platform/rcar-vin/rcar-csi2.c
@@ -714,7 +714,7 @@ static int rcsi2_parse_v4l2(struct rcar_csi2 *priv,
if (vep->base.port || vep->base.id)
return -ENOTCONN;
- if (vep->bus_type != V4L2_MBUS_CSI2) {
+ if (vep->bus_type != V4L2_MBUS_CSI2_DPHY) {
dev_err(priv->dev, "Unsupported bus: %u\n", vep->bus_type);
return -EINVAL;
}
@@ -743,7 +743,7 @@ static int rcsi2_parse_v4l2(struct rcar_csi2 *priv,
static int rcsi2_parse_dt(struct rcar_csi2 *priv)
{
struct device_node *ep;
- struct v4l2_fwnode_endpoint v4l2_ep;
+ struct v4l2_fwnode_endpoint v4l2_ep = { .bus_type = 0 };
int ret;
ep = of_graph_get_endpoint_by_regs(priv->dev->of_node, 0, 0);
@@ -771,21 +771,25 @@ static int rcsi2_parse_dt(struct rcar_csi2 *priv)
of_node_put(ep);
- priv->notifier.subdevs = devm_kzalloc(priv->dev,
- sizeof(*priv->notifier.subdevs),
- GFP_KERNEL);
- if (!priv->notifier.subdevs)
- return -ENOMEM;
+ v4l2_async_notifier_init(&priv->notifier);
+
+ ret = v4l2_async_notifier_add_subdev(&priv->notifier, &priv->asd);
+ if (ret) {
+ fwnode_handle_put(priv->asd.match.fwnode);
+ return ret;
+ }
- priv->notifier.num_subdevs = 1;
- priv->notifier.subdevs[0] = &priv->asd;
priv->notifier.ops = &rcar_csi2_notify_ops;
dev_dbg(priv->dev, "Found '%pOF'\n",
to_of_node(priv->asd.match.fwnode));
- return v4l2_async_subdev_notifier_register(&priv->subdev,
- &priv->notifier);
+ ret = v4l2_async_subdev_notifier_register(&priv->subdev,
+ &priv->notifier);
+ if (ret)
+ v4l2_async_notifier_cleanup(&priv->notifier);
+
+ return ret;
}
/* -----------------------------------------------------------------------------
diff --git a/drivers/media/platform/rcar-vin/rcar-v4l2.c b/drivers/media/platform/rcar-vin/rcar-v4l2.c
index 5a54779cfc27..dc77682b4785 100644
--- a/drivers/media/platform/rcar-vin/rcar-v4l2.c
+++ b/drivers/media/platform/rcar-vin/rcar-v4l2.c
@@ -238,8 +238,8 @@ static int rvin_querycap(struct file *file, void *priv,
{
struct rvin_dev *vin = video_drvdata(file);
- strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
- strlcpy(cap->card, "R_Car_VIN", sizeof(cap->card));
+ strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
+ strscpy(cap->card, "R_Car_VIN", sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
dev_name(vin->dev));
return 0;
@@ -440,7 +440,7 @@ static int rvin_enum_input(struct file *file, void *priv,
i->std = vin->vdev.tvnorms;
}
- strlcpy(i->name, "Camera", sizeof(i->name));
+ strscpy(i->name, "Camera", sizeof(i->name));
return 0;
}
@@ -714,7 +714,7 @@ static int rvin_mc_enum_input(struct file *file, void *priv,
return -EINVAL;
i->type = V4L2_INPUT_TYPE_CAMERA;
- strlcpy(i->name, "Camera", sizeof(i->name));
+ strscpy(i->name, "Camera", sizeof(i->name));
return 0;
}
diff --git a/drivers/media/platform/rcar_drif.c b/drivers/media/platform/rcar_drif.c
index 81413ab52475..c417ff8f6fe5 100644
--- a/drivers/media/platform/rcar_drif.c
+++ b/drivers/media/platform/rcar_drif.c
@@ -870,8 +870,8 @@ static int rcar_drif_querycap(struct file *file, void *fh,
{
struct rcar_drif_sdr *sdr = video_drvdata(file);
- strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
- strlcpy(cap->card, sdr->vdev->name, sizeof(cap->card));
+ strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
+ strscpy(cap->card, sdr->vdev->name, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
sdr->vdev->name);
@@ -1164,7 +1164,7 @@ static int rcar_drif_notify_complete(struct v4l2_async_notifier *notifier)
}
ret = v4l2_ctrl_add_handler(&sdr->ctrl_hdl,
- sdr->ep.subdev->ctrl_handler, NULL);
+ sdr->ep.subdev->ctrl_handler, NULL, true);
if (ret) {
rdrif_err(sdr, "failed: ctrl add hdlr ret %d\n", ret);
goto error;
@@ -1213,18 +1213,15 @@ static int rcar_drif_parse_subdevs(struct rcar_drif_sdr *sdr)
{
struct v4l2_async_notifier *notifier = &sdr->notifier;
struct fwnode_handle *fwnode, *ep;
+ int ret;
- notifier->subdevs = devm_kzalloc(sdr->dev, sizeof(*notifier->subdevs),
- GFP_KERNEL);
- if (!notifier->subdevs)
- return -ENOMEM;
+ v4l2_async_notifier_init(notifier);
ep = fwnode_graph_get_next_endpoint(of_fwnode_handle(sdr->dev->of_node),
NULL);
if (!ep)
return 0;
- notifier->subdevs[notifier->num_subdevs] = &sdr->ep.asd;
fwnode = fwnode_graph_get_remote_port_parent(ep);
if (!fwnode) {
dev_warn(sdr->dev, "bad remote port parent\n");
@@ -1234,7 +1231,11 @@ static int rcar_drif_parse_subdevs(struct rcar_drif_sdr *sdr)
sdr->ep.asd.match.fwnode = fwnode;
sdr->ep.asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
- notifier->num_subdevs++;
+ ret = v4l2_async_notifier_add_subdev(notifier, &sdr->ep.asd);
+ if (ret) {
+ fwnode_handle_put(fwnode);
+ return ret;
+ }
/* Get the endpoint properties */
rcar_drif_get_ep_properties(sdr, ep);
@@ -1356,11 +1357,13 @@ static int rcar_drif_sdr_probe(struct rcar_drif_sdr *sdr)
ret = v4l2_async_notifier_register(&sdr->v4l2_dev, &sdr->notifier);
if (ret < 0) {
dev_err(sdr->dev, "failed: notifier register ret %d\n", ret);
- goto error;
+ goto cleanup;
}
return ret;
+cleanup:
+ v4l2_async_notifier_cleanup(&sdr->notifier);
error:
v4l2_device_unregister(&sdr->v4l2_dev);
@@ -1371,6 +1374,7 @@ error:
static void rcar_drif_sdr_remove(struct rcar_drif_sdr *sdr)
{
v4l2_async_notifier_unregister(&sdr->notifier);
+ v4l2_async_notifier_cleanup(&sdr->notifier);
v4l2_device_unregister(&sdr->v4l2_dev);
}
diff --git a/drivers/media/platform/rcar_fdp1.c b/drivers/media/platform/rcar_fdp1.c
index 2a15b7cca338..6bda1eee9170 100644
--- a/drivers/media/platform/rcar_fdp1.c
+++ b/drivers/media/platform/rcar_fdp1.c
@@ -1359,8 +1359,8 @@ static void device_frame_end(struct fdp1_dev *fdp1,
static int fdp1_vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- strlcpy(cap->driver, DRIVER_NAME, sizeof(cap->driver));
- strlcpy(cap->card, DRIVER_NAME, sizeof(cap->card));
+ strscpy(cap->driver, DRIVER_NAME, sizeof(cap->driver));
+ strscpy(cap->card, DRIVER_NAME, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info),
"platform:%s", DRIVER_NAME);
return 0;
@@ -2339,7 +2339,7 @@ static int fdp1_probe(struct platform_device *pdev)
vfd->lock = &fdp1->dev_mutex;
vfd->v4l2_dev = &fdp1->v4l2_dev;
video_set_drvdata(vfd, fdp1);
- strlcpy(vfd->name, fdp1_videodev.name, sizeof(vfd->name));
+ strscpy(vfd->name, fdp1_videodev.name, sizeof(vfd->name));
ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
if (ret) {
diff --git a/drivers/media/platform/rcar_jpu.c b/drivers/media/platform/rcar_jpu.c
index e5c882423f57..1dfd2eb65920 100644
--- a/drivers/media/platform/rcar_jpu.c
+++ b/drivers/media/platform/rcar_jpu.c
@@ -664,11 +664,11 @@ static int jpu_querycap(struct file *file, void *priv,
struct jpu_ctx *ctx = fh_to_ctx(priv);
if (ctx->encoder)
- strlcpy(cap->card, DRV_NAME " encoder", sizeof(cap->card));
+ strscpy(cap->card, DRV_NAME " encoder", sizeof(cap->card));
else
- strlcpy(cap->card, DRV_NAME " decoder", sizeof(cap->card));
+ strscpy(cap->card, DRV_NAME " decoder", sizeof(cap->card));
- strlcpy(cap->driver, DRV_NAME, sizeof(cap->driver));
+ strscpy(cap->driver, DRV_NAME, sizeof(cap->driver));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
dev_name(ctx->jpu->dev));
cap->device_caps |= V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE;
@@ -1654,7 +1654,7 @@ static int jpu_probe(struct platform_device *pdev)
for (i = 0; i < JPU_MAX_QUALITY; i++)
jpu_generate_hdr(i, (unsigned char *)jpeg_hdrs[i]);
- strlcpy(jpu->vfd_encoder.name, DRV_NAME, sizeof(jpu->vfd_encoder.name));
+ strscpy(jpu->vfd_encoder.name, DRV_NAME, sizeof(jpu->vfd_encoder.name));
jpu->vfd_encoder.fops = &jpu_fops;
jpu->vfd_encoder.ioctl_ops = &jpu_ioctl_ops;
jpu->vfd_encoder.minor = -1;
@@ -1671,7 +1671,7 @@ static int jpu_probe(struct platform_device *pdev)
video_set_drvdata(&jpu->vfd_encoder, jpu);
- strlcpy(jpu->vfd_decoder.name, DRV_NAME, sizeof(jpu->vfd_decoder.name));
+ strscpy(jpu->vfd_decoder.name, DRV_NAME, sizeof(jpu->vfd_decoder.name));
jpu->vfd_decoder.fops = &jpu_fops;
jpu->vfd_decoder.ioctl_ops = &jpu_ioctl_ops;
jpu->vfd_decoder.minor = -1;
diff --git a/drivers/media/platform/renesas-ceu.c b/drivers/media/platform/renesas-ceu.c
index ad782901cd7a..150196f7cf96 100644
--- a/drivers/media/platform/renesas-ceu.c
+++ b/drivers/media/platform/renesas-ceu.c
@@ -189,8 +189,6 @@ struct ceu_device {
/* async subdev notification helpers */
struct v4l2_async_notifier notifier;
- /* pointers to "struct ceu_subdevice -> asd" */
- struct v4l2_async_subdev **asds;
/* vb2 queue, capture buffer list and active buffer pointer */
struct vb2_queue vb2_vq;
@@ -1137,8 +1135,8 @@ static int ceu_querycap(struct file *file, void *priv,
{
struct ceu_device *ceudev = video_drvdata(file);
- strlcpy(cap->card, "Renesas CEU", sizeof(cap->card));
- strlcpy(cap->driver, DRIVER_NAME, sizeof(cap->driver));
+ strscpy(cap->card, "Renesas CEU", sizeof(cap->card));
+ strscpy(cap->driver, DRIVER_NAME, sizeof(cap->driver));
snprintf(cap->bus_info, sizeof(cap->bus_info),
"platform:renesas-ceu-%s", dev_name(ceudev->dev));
@@ -1440,7 +1438,7 @@ static int ceu_notify_complete(struct v4l2_async_notifier *notifier)
return ret;
/* Register the video device. */
- strlcpy(vdev->name, DRIVER_NAME, sizeof(vdev->name));
+ strscpy(vdev->name, DRIVER_NAME, sizeof(vdev->name));
vdev->v4l2_dev = v4l2_dev;
vdev->lock = &ceudev->mlock;
vdev->queue = &ceudev->vb2_vq;
@@ -1482,15 +1480,6 @@ static int ceu_init_async_subdevs(struct ceu_device *ceudev, unsigned int n_sd)
if (!ceudev->subdevs)
return -ENOMEM;
- /*
- * Reserve memory for 'n_sd' pointers to async_subdevices.
- * ceudev->asds members will point to &ceu_subdev.asd
- */
- ceudev->asds = devm_kcalloc(ceudev->dev, n_sd,
- sizeof(*ceudev->asds), GFP_KERNEL);
- if (!ceudev->asds)
- return -ENOMEM;
-
ceudev->sd = NULL;
ceudev->sd_index = 0;
ceudev->num_sd = 0;
@@ -1518,6 +1507,7 @@ static int ceu_parse_platform_data(struct ceu_device *ceudev,
return ret;
for (i = 0; i < pdata->num_subdevs; i++) {
+
/* Setup the ceu subdevice and the async subdevice. */
async_sd = &pdata->subdevs[i];
ceu_sd = &ceudev->subdevs[i];
@@ -1529,7 +1519,12 @@ static int ceu_parse_platform_data(struct ceu_device *ceudev,
ceu_sd->asd.match.i2c.adapter_id = async_sd->i2c_adapter_id;
ceu_sd->asd.match.i2c.address = async_sd->i2c_address;
- ceudev->asds[i] = &ceu_sd->asd;
+ ret = v4l2_async_notifier_add_subdev(&ceudev->notifier,
+ &ceu_sd->asd);
+ if (ret) {
+ v4l2_async_notifier_cleanup(&ceudev->notifier);
+ return ret;
+ }
}
return pdata->num_subdevs;
@@ -1541,9 +1536,8 @@ static int ceu_parse_platform_data(struct ceu_device *ceudev,
static int ceu_parse_dt(struct ceu_device *ceudev)
{
struct device_node *of = ceudev->dev->of_node;
- struct v4l2_fwnode_endpoint fw_ep;
+ struct device_node *ep, *remote;
struct ceu_subdev *ceu_sd;
- struct device_node *ep;
unsigned int i;
int num_ep;
int ret;
@@ -1557,45 +1551,55 @@ static int ceu_parse_dt(struct ceu_device *ceudev)
return ret;
for (i = 0; i < num_ep; i++) {
+ struct v4l2_fwnode_endpoint fw_ep = {
+ .bus_type = V4L2_MBUS_PARALLEL,
+ .bus = {
+ .parallel = {
+ .flags = V4L2_MBUS_HSYNC_ACTIVE_HIGH |
+ V4L2_MBUS_VSYNC_ACTIVE_HIGH,
+ .bus_width = 8,
+ },
+ },
+ };
+
ep = of_graph_get_endpoint_by_regs(of, 0, i);
if (!ep) {
dev_err(ceudev->dev,
"No subdevice connected on endpoint %u.\n", i);
ret = -ENODEV;
- goto error_put_node;
+ goto error_cleanup;
}
ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &fw_ep);
if (ret) {
dev_err(ceudev->dev,
- "Unable to parse endpoint #%u.\n", i);
- goto error_put_node;
- }
-
- if (fw_ep.bus_type != V4L2_MBUS_PARALLEL) {
- dev_err(ceudev->dev,
- "Only parallel input supported.\n");
- ret = -EINVAL;
- goto error_put_node;
+ "Unable to parse endpoint #%u: %d.\n", i, ret);
+ goto error_cleanup;
}
/* Setup the ceu subdevice and the async subdevice. */
ceu_sd = &ceudev->subdevs[i];
INIT_LIST_HEAD(&ceu_sd->asd.list);
+ remote = of_graph_get_remote_port_parent(ep);
ceu_sd->mbus_flags = fw_ep.bus.parallel.flags;
ceu_sd->asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
- ceu_sd->asd.match.fwnode =
- fwnode_graph_get_remote_port_parent(
- of_fwnode_handle(ep));
+ ceu_sd->asd.match.fwnode = of_fwnode_handle(remote);
+
+ ret = v4l2_async_notifier_add_subdev(&ceudev->notifier,
+ &ceu_sd->asd);
+ if (ret) {
+ of_node_put(remote);
+ goto error_cleanup;
+ }
- ceudev->asds[i] = &ceu_sd->asd;
of_node_put(ep);
}
return num_ep;
-error_put_node:
+error_cleanup:
+ v4l2_async_notifier_cleanup(&ceudev->notifier);
of_node_put(ep);
return ret;
}
@@ -1674,6 +1678,8 @@ static int ceu_probe(struct platform_device *pdev)
if (ret)
goto error_pm_disable;
+ v4l2_async_notifier_init(&ceudev->notifier);
+
if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
ceu_data = of_match_device(ceu_of_match, dev)->data;
num_subdevs = ceu_parse_dt(ceudev);
@@ -1693,18 +1699,18 @@ static int ceu_probe(struct platform_device *pdev)
ceudev->irq_mask = ceu_data->irq_mask;
ceudev->notifier.v4l2_dev = &ceudev->v4l2_dev;
- ceudev->notifier.subdevs = ceudev->asds;
- ceudev->notifier.num_subdevs = num_subdevs;
ceudev->notifier.ops = &ceu_notify_ops;
ret = v4l2_async_notifier_register(&ceudev->v4l2_dev,
&ceudev->notifier);
if (ret)
- goto error_v4l2_unregister;
+ goto error_cleanup;
dev_info(dev, "Renesas Capture Engine Unit %s\n", dev_name(dev));
return 0;
+error_cleanup:
+ v4l2_async_notifier_cleanup(&ceudev->notifier);
error_v4l2_unregister:
v4l2_device_unregister(&ceudev->v4l2_dev);
error_pm_disable:
@@ -1723,6 +1729,8 @@ static int ceu_remove(struct platform_device *pdev)
v4l2_async_notifier_unregister(&ceudev->notifier);
+ v4l2_async_notifier_cleanup(&ceudev->notifier);
+
v4l2_device_unregister(&ceudev->v4l2_dev);
video_unregister_device(&ceudev->vdev);
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index ab5a6f95044a..9cc9db083870 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -447,9 +447,9 @@ static const struct v4l2_file_operations rga_fops = {
static int
vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
{
- strlcpy(cap->driver, RGA_NAME, sizeof(cap->driver));
- strlcpy(cap->card, "rockchip-rga", sizeof(cap->card));
- strlcpy(cap->bus_info, "platform:rga", sizeof(cap->bus_info));
+ strscpy(cap->driver, RGA_NAME, sizeof(cap->driver));
+ strscpy(cap->card, "rockchip-rga", sizeof(cap->card));
+ strscpy(cap->bus_info, "platform:rga", sizeof(cap->bus_info));
return 0;
}
diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c
index c02dce8b4c6c..c3fc94ef251e 100644
--- a/drivers/media/platform/s3c-camif/camif-capture.c
+++ b/drivers/media/platform/s3c-camif/camif-capture.c
@@ -640,8 +640,8 @@ static int s3c_camif_vidioc_querycap(struct file *file, void *priv,
{
struct camif_vp *vp = video_drvdata(file);
- strlcpy(cap->driver, S3C_CAMIF_DRIVER_NAME, sizeof(cap->driver));
- strlcpy(cap->card, S3C_CAMIF_DRIVER_NAME, sizeof(cap->card));
+ strscpy(cap->driver, S3C_CAMIF_DRIVER_NAME, sizeof(cap->driver));
+ strscpy(cap->card, S3C_CAMIF_DRIVER_NAME, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s.%d",
dev_name(vp->camif->dev), vp->id);
@@ -661,7 +661,7 @@ static int s3c_camif_vidioc_enum_input(struct file *file, void *priv,
return -EINVAL;
input->type = V4L2_INPUT_TYPE_CAMERA;
- strlcpy(input->name, sensor->name, sizeof(input->name));
+ strscpy(input->name, sensor->name, sizeof(input->name));
return 0;
}
@@ -688,7 +688,7 @@ static int s3c_camif_vidioc_enum_fmt(struct file *file, void *priv,
if (!fmt)
return -EINVAL;
- strlcpy(f->description, fmt->name, sizeof(f->description));
+ strscpy(f->description, fmt->name, sizeof(f->description));
f->pixelformat = fmt->fourcc;
pr_debug("fmt(%d): %s\n", f->index, f->description);
@@ -943,7 +943,7 @@ static int s3c_camif_qbuf(struct file *file, void *priv,
if (vp->owner && vp->owner != priv)
return -EBUSY;
- return vb2_qbuf(&vp->vb_queue, buf);
+ return vb2_qbuf(&vp->vb_queue, vp->vdev.v4l2_dev->mdev, buf);
}
static int s3c_camif_dqbuf(struct file *file, void *priv,
@@ -981,7 +981,7 @@ static int s3c_camif_prepare_buf(struct file *file, void *priv,
struct v4l2_buffer *b)
{
struct camif_vp *vp = video_drvdata(file);
- return vb2_prepare_buf(&vp->vb_queue, b);
+ return vb2_prepare_buf(&vp->vb_queue, vp->vdev.v4l2_dev->mdev, b);
}
static int s3c_camif_g_selection(struct file *file, void *priv,
@@ -1555,7 +1555,7 @@ int s3c_camif_create_subdev(struct camif_dev *camif)
v4l2_subdev_init(sd, &s3c_camif_subdev_ops);
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
- strlcpy(sd->name, "S3C-CAMIF", sizeof(sd->name));
+ strscpy(sd->name, "S3C-CAMIF", sizeof(sd->name));
camif->pads[CAMIF_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
camif->pads[CAMIF_SD_PAD_SOURCE_C].flags = MEDIA_PAD_FL_SOURCE;
diff --git a/drivers/media/platform/s3c-camif/camif-core.c b/drivers/media/platform/s3c-camif/camif-core.c
index 79bc0ef6bb41..31759f16458e 100644
--- a/drivers/media/platform/s3c-camif/camif-core.c
+++ b/drivers/media/platform/s3c-camif/camif-core.c
@@ -316,12 +316,12 @@ static int camif_media_dev_init(struct camif_dev *camif)
memset(md, 0, sizeof(*md));
snprintf(md->model, sizeof(md->model), "SAMSUNG S3C%s CAMIF",
ip_rev == S3C6410_CAMIF_IP_REV ? "6410" : "244X");
- strlcpy(md->bus_info, "platform", sizeof(md->bus_info));
+ strscpy(md->bus_info, "platform", sizeof(md->bus_info));
md->hw_revision = ip_rev;
md->dev = camif->dev;
- strlcpy(v4l2_dev->name, "s3c-camif", sizeof(v4l2_dev->name));
+ strscpy(v4l2_dev->name, "s3c-camif", sizeof(v4l2_dev->name));
v4l2_dev->mdev = md;
media_device_init(md);
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
index 04fd2e0493c0..3f9000b70385 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -1276,14 +1276,14 @@ static int s5p_jpeg_querycap(struct file *file, void *priv,
struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
if (ctx->mode == S5P_JPEG_ENCODE) {
- strlcpy(cap->driver, S5P_JPEG_M2M_NAME,
+ strscpy(cap->driver, S5P_JPEG_M2M_NAME,
sizeof(cap->driver));
- strlcpy(cap->card, S5P_JPEG_M2M_NAME " encoder",
+ strscpy(cap->card, S5P_JPEG_M2M_NAME " encoder",
sizeof(cap->card));
} else {
- strlcpy(cap->driver, S5P_JPEG_M2M_NAME,
+ strscpy(cap->driver, S5P_JPEG_M2M_NAME,
sizeof(cap->driver));
- strlcpy(cap->card, S5P_JPEG_M2M_NAME " decoder",
+ strscpy(cap->card, S5P_JPEG_M2M_NAME " decoder",
sizeof(cap->card));
}
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
@@ -1314,7 +1314,7 @@ static int enum_fmt(struct s5p_jpeg_fmt *sjpeg_formats, int n,
if (i >= n)
return -EINVAL;
- strlcpy(f->description, sjpeg_formats[i].name, sizeof(f->description));
+ strscpy(f->description, sjpeg_formats[i].name, sizeof(f->description));
f->pixelformat = sjpeg_formats[i].fourcc;
return 0;
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
index 6a3cc4f86c5d..ece59ce1b149 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
@@ -271,8 +271,8 @@ static int vidioc_querycap(struct file *file, void *priv,
{
struct s5p_mfc_dev *dev = video_drvdata(file);
- strlcpy(cap->driver, S5P_MFC_NAME, sizeof(cap->driver));
- strlcpy(cap->card, dev->vfd_dec->name, sizeof(cap->card));
+ strscpy(cap->driver, S5P_MFC_NAME, sizeof(cap->driver));
+ strscpy(cap->card, dev->vfd_dec->name, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
dev_name(&dev->plat_dev->dev));
/*
@@ -308,7 +308,7 @@ static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f,
if (i == ARRAY_SIZE(formats))
return -EINVAL;
fmt = &formats[i];
- strlcpy(f->description, fmt->name, sizeof(f->description));
+ strscpy(f->description, fmt->name, sizeof(f->description));
f->pixelformat = fmt->fourcc;
return 0;
}
@@ -632,9 +632,9 @@ static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
return -EIO;
}
if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
- return vb2_qbuf(&ctx->vq_src, buf);
+ return vb2_qbuf(&ctx->vq_src, NULL, buf);
else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
- return vb2_qbuf(&ctx->vq_dst, buf);
+ return vb2_qbuf(&ctx->vq_dst, NULL, buf);
return -EINVAL;
}
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
index 3ad4f5073002..8fcf627dedfb 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
@@ -1313,8 +1313,8 @@ static int vidioc_querycap(struct file *file, void *priv,
{
struct s5p_mfc_dev *dev = video_drvdata(file);
- strlcpy(cap->driver, S5P_MFC_NAME, sizeof(cap->driver));
- strlcpy(cap->card, dev->vfd_enc->name, sizeof(cap->card));
+ strscpy(cap->driver, S5P_MFC_NAME, sizeof(cap->driver));
+ strscpy(cap->card, dev->vfd_enc->name, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
dev_name(&dev->plat_dev->dev));
/*
@@ -1344,7 +1344,7 @@ static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f,
if (j == f->index) {
fmt = &formats[i];
- strlcpy(f->description, fmt->name,
+ strscpy(f->description, fmt->name,
sizeof(f->description));
f->pixelformat = fmt->fourcc;
return 0;
@@ -1621,9 +1621,9 @@ static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
mfc_err("Call on QBUF after EOS command\n");
return -EIO;
}
- return vb2_qbuf(&ctx->vq_src, buf);
+ return vb2_qbuf(&ctx->vq_src, NULL, buf);
} else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- return vb2_qbuf(&ctx->vq_dst, buf);
+ return vb2_qbuf(&ctx->vq_dst, NULL, buf);
}
return -EINVAL;
}
diff --git a/drivers/media/platform/sh_veu.c b/drivers/media/platform/sh_veu.c
index 1d274c64de09..09ae64a0004c 100644
--- a/drivers/media/platform/sh_veu.c
+++ b/drivers/media/platform/sh_veu.c
@@ -345,9 +345,9 @@ static int sh_veu_context_init(struct sh_veu_dev *veu)
static int sh_veu_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- strlcpy(cap->driver, "sh-veu", sizeof(cap->driver));
- strlcpy(cap->card, "sh-mobile VEU", sizeof(cap->card));
- strlcpy(cap->bus_info, "platform:sh-veu", sizeof(cap->bus_info));
+ strscpy(cap->driver, "sh-veu", sizeof(cap->driver));
+ strscpy(cap->card, "sh-mobile VEU", sizeof(cap->card));
+ strscpy(cap->bus_info, "platform:sh-veu", sizeof(cap->bus_info));
cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
@@ -359,7 +359,8 @@ static int sh_veu_enum_fmt(struct v4l2_fmtdesc *f, const int *fmt, int fmt_num)
if (f->index >= fmt_num)
return -EINVAL;
- strlcpy(f->description, sh_veu_fmt[fmt[f->index]].name, sizeof(f->description));
+ strscpy(f->description, sh_veu_fmt[fmt[f->index]].name,
+ sizeof(f->description));
f->pixelformat = sh_veu_fmt[fmt[f->index]].fourcc;
return 0;
}
diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c
index 6135e13e24d4..cee58b125548 100644
--- a/drivers/media/platform/sh_vou.c
+++ b/drivers/media/platform/sh_vou.c
@@ -378,9 +378,9 @@ static int sh_vou_querycap(struct file *file, void *priv,
dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
- strlcpy(cap->card, "SuperH VOU", sizeof(cap->card));
- strlcpy(cap->driver, "sh-vou", sizeof(cap->driver));
- strlcpy(cap->bus_info, "platform:sh-vou", sizeof(cap->bus_info));
+ strscpy(cap->card, "SuperH VOU", sizeof(cap->card));
+ strscpy(cap->driver, "sh-vou", sizeof(cap->driver));
+ strscpy(cap->bus_info, "platform:sh-vou", sizeof(cap->bus_info));
cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING;
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
@@ -399,7 +399,7 @@ static int sh_vou_enum_fmt_vid_out(struct file *file, void *priv,
dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
- strlcpy(fmt->description, vou_fmt[fmt->index].desc,
+ strscpy(fmt->description, vou_fmt[fmt->index].desc,
sizeof(fmt->description));
fmt->pixelformat = vou_fmt[fmt->index].pfmt;
@@ -790,7 +790,7 @@ static int sh_vou_enum_output(struct file *file, void *fh,
if (a->index)
return -EINVAL;
- strlcpy(a->name, "Video Out", sizeof(a->name));
+ strscpy(a->name, "Video Out", sizeof(a->name));
a->type = V4L2_OUTPUT_TYPE_ANALOG;
a->std = vou_dev->vdev.tvnorms;
return 0;
diff --git a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
index 0a2c0daaffef..6803f744e307 100644
--- a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
+++ b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
@@ -1564,9 +1564,9 @@ static __poll_t sh_mobile_ceu_poll(struct file *file, poll_table *pt)
static int sh_mobile_ceu_querycap(struct soc_camera_host *ici,
struct v4l2_capability *cap)
{
- strlcpy(cap->card, "SuperH_Mobile_CEU", sizeof(cap->card));
- strlcpy(cap->driver, "sh_mobile_ceu", sizeof(cap->driver));
- strlcpy(cap->bus_info, "platform:sh_mobile_ceu", sizeof(cap->bus_info));
+ strscpy(cap->card, "SuperH_Mobile_CEU", sizeof(cap->card));
+ strscpy(cap->driver, "sh_mobile_ceu", sizeof(cap->driver));
+ strscpy(cap->bus_info, "platform:sh_mobile_ceu", sizeof(cap->bus_info));
cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c
index 66d613629167..21034339cdcb 100644
--- a/drivers/media/platform/soc_camera/soc_camera.c
+++ b/drivers/media/platform/soc_camera/soc_camera.c
@@ -312,7 +312,7 @@ static int soc_camera_enum_input(struct file *file, void *priv,
/* default is camera */
inp->type = V4L2_INPUT_TYPE_CAMERA;
inp->std = icd->vdev->tvnorms;
- strcpy(inp->name, "Camera");
+ strscpy(inp->name, "Camera", sizeof(inp->name));
return 0;
}
@@ -394,7 +394,7 @@ static int soc_camera_qbuf(struct file *file, void *priv,
if (icd->streamer != file)
return -EBUSY;
- return vb2_qbuf(&icd->vb2_vidq, p);
+ return vb2_qbuf(&icd->vb2_vidq, NULL, p);
}
static int soc_camera_dqbuf(struct file *file, void *priv,
@@ -430,7 +430,7 @@ static int soc_camera_prepare_buf(struct file *file, void *priv,
{
struct soc_camera_device *icd = file->private_data;
- return vb2_prepare_buf(&icd->vb2_vidq, b);
+ return vb2_prepare_buf(&icd->vb2_vidq, NULL, b);
}
static int soc_camera_expbuf(struct file *file, void *priv,
@@ -874,7 +874,7 @@ static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv,
format = icd->user_formats[f->index].host_fmt;
if (format->name)
- strlcpy(f->description, format->name, sizeof(f->description));
+ strscpy(f->description, format->name, sizeof(f->description));
f->pixelformat = format->fourcc;
return 0;
}
@@ -910,7 +910,7 @@ static int soc_camera_querycap(struct file *file, void *priv,
WARN_ON(priv != file->private_data);
- strlcpy(cap->driver, ici->drv_name, sizeof(cap->driver));
+ strscpy(cap->driver, ici->drv_name, sizeof(cap->driver));
return ici->ops->querycap(ici, cap);
}
@@ -1181,7 +1181,8 @@ static int soc_camera_probe_finish(struct soc_camera_device *icd)
v4l2_subdev_call(sd, video, g_tvnorms, &icd->vdev->tvnorms);
- ret = v4l2_ctrl_add_handler(&icd->ctrl_handler, sd->ctrl_handler, NULL);
+ ret = v4l2_ctrl_add_handler(&icd->ctrl_handler, sd->ctrl_handler,
+ NULL, true);
if (ret < 0)
return ret;
@@ -1442,8 +1443,14 @@ static int scan_async_group(struct soc_camera_host *ici,
goto eaddpdev;
}
- sasc->notifier.subdevs = asd;
- sasc->notifier.num_subdevs = size;
+ v4l2_async_notifier_init(&sasc->notifier);
+
+ for (i = 0; i < size; i++) {
+ ret = v4l2_async_notifier_add_subdev(&sasc->notifier, asd[i]);
+ if (ret)
+ goto eaddasd;
+ }
+
sasc->notifier.ops = &soc_camera_async_ops;
icd->sasc = sasc;
@@ -1466,6 +1473,8 @@ static int scan_async_group(struct soc_camera_host *ici,
v4l2_clk_unregister(icd->clk);
eclkreg:
icd->clk = NULL;
+eaddasd:
+ v4l2_async_notifier_cleanup(&sasc->notifier);
platform_device_del(sasc->pdev);
eaddpdev:
platform_device_put(sasc->pdev);
@@ -1540,8 +1549,14 @@ static int soc_of_bind(struct soc_camera_host *ici,
goto eaddpdev;
}
- sasc->notifier.subdevs = &info->subdev;
- sasc->notifier.num_subdevs = 1;
+ v4l2_async_notifier_init(&sasc->notifier);
+
+ ret = v4l2_async_notifier_add_subdev(&sasc->notifier, info->subdev);
+ if (ret) {
+ of_node_put(remote);
+ goto eaddasd;
+ }
+
sasc->notifier.ops = &soc_camera_async_ops;
icd->sasc = sasc;
@@ -1568,6 +1583,8 @@ static int soc_of_bind(struct soc_camera_host *ici,
v4l2_clk_unregister(icd->clk);
eclkreg:
icd->clk = NULL;
+eaddasd:
+ v4l2_async_notifier_cleanup(&sasc->notifier);
platform_device_del(sasc->pdev);
eaddpdev:
platform_device_put(sasc->pdev);
@@ -1582,7 +1599,7 @@ static void scan_of_host(struct soc_camera_host *ici)
{
struct device *dev = ici->v4l2_dev.dev;
struct device_node *np = dev->of_node;
- struct device_node *epn = NULL, *ren;
+ struct device_node *epn = NULL, *rem;
unsigned int i;
for (i = 0; ; i++) {
@@ -1590,17 +1607,15 @@ static void scan_of_host(struct soc_camera_host *ici)
if (!epn)
break;
- ren = of_graph_get_remote_port(epn);
- if (!ren) {
+ rem = of_graph_get_remote_port_parent(epn);
+ if (!rem) {
dev_notice(dev, "no remote for %pOF\n", epn);
continue;
}
/* so we now have a remote node to connect */
if (!i)
- soc_of_bind(ici, epn, ren->parent);
-
- of_node_put(ren);
+ soc_of_bind(ici, epn, rem);
if (i) {
dev_err(dev, "multiple subdevices aren't supported yet!\n");
@@ -1926,6 +1941,7 @@ void soc_camera_host_unregister(struct soc_camera_host *ici)
list_for_each_entry(sasc, &notifiers, list) {
/* Must call unlocked to avoid AB-BA dead-lock */
v4l2_async_notifier_unregister(&sasc->notifier);
+ v4l2_async_notifier_cleanup(&sasc->notifier);
put_device(&sasc->pdev->dev);
}
@@ -2026,7 +2042,7 @@ static int video_dev_create(struct soc_camera_device *icd)
if (!vdev)
return -ENOMEM;
- strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name));
+ strscpy(vdev->name, ici->drv_name, sizeof(vdev->name));
vdev->v4l2_dev = &ici->v4l2_dev;
vdev->fops = &soc_camera_fops;
diff --git a/drivers/media/platform/soc_camera/soc_camera_platform.c b/drivers/media/platform/soc_camera/soc_camera_platform.c
index 6745a6e3f464..79fbe1fea95f 100644
--- a/drivers/media/platform/soc_camera/soc_camera_platform.c
+++ b/drivers/media/platform/soc_camera/soc_camera_platform.c
@@ -156,7 +156,7 @@ static int soc_camera_platform_probe(struct platform_device *pdev)
v4l2_subdev_init(&priv->subdev, &platform_subdev_ops);
v4l2_set_subdevdata(&priv->subdev, p);
- strlcpy(priv->subdev.name, dev_name(&pdev->dev),
+ strscpy(priv->subdev.name, dev_name(&pdev->dev),
sizeof(priv->subdev.name));
return v4l2_device_register_subdev(&ici->v4l2_dev, &priv->subdev);
diff --git a/drivers/media/platform/soc_camera/soc_mediabus.c b/drivers/media/platform/soc_camera/soc_mediabus.c
index 0ad4b28266e4..be74008ec0ca 100644
--- a/drivers/media/platform/soc_camera/soc_mediabus.c
+++ b/drivers/media/platform/soc_camera/soc_mediabus.c
@@ -503,7 +503,7 @@ unsigned int soc_mbus_config_compatible(const struct v4l2_mbus_config *cfg,
mode = common_flags & (V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE);
return (!hsync || !vsync || !pclk || !data || !mode) ?
0 : common_flags;
- case V4L2_MBUS_CSI2:
+ case V4L2_MBUS_CSI2_DPHY:
mipi_lanes = common_flags & V4L2_MBUS_CSI2_LANES;
mipi_clock = common_flags & (V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK |
V4L2_MBUS_CSI2_CONTINUOUS_CLOCK);
diff --git a/drivers/media/platform/soc_camera/soc_scale_crop.c b/drivers/media/platform/soc_camera/soc_scale_crop.c
index 6164102e6f9f..8d25ca0490f7 100644
--- a/drivers/media/platform/soc_camera/soc_scale_crop.c
+++ b/drivers/media/platform/soc_camera/soc_scale_crop.c
@@ -52,7 +52,7 @@ int soc_camera_client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect)
return ret;
}
- sdsel.target = V4L2_SEL_TGT_CROP_DEFAULT;
+ sdsel.target = V4L2_SEL_TGT_CROP_BOUNDS;
ret = v4l2_subdev_call(sd, pad, get_selection, NULL, &sdsel);
if (!ret)
*rect = sdsel.r;
diff --git a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c
index 66b64096f5de..79f7db1a9d18 100644
--- a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c
+++ b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c
@@ -688,8 +688,8 @@ static int bdisp_querycap(struct file *file, void *fh,
struct bdisp_ctx *ctx = fh_to_ctx(fh);
struct bdisp_dev *bdisp = ctx->bdisp_dev;
- strlcpy(cap->driver, bdisp->pdev->name, sizeof(cap->driver));
- strlcpy(cap->card, bdisp->pdev->name, sizeof(cap->card));
+ strscpy(cap->driver, bdisp->pdev->name, sizeof(cap->driver));
+ strscpy(cap->card, bdisp->pdev->name, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s%d",
BDISP_NAME, bdisp->id);
diff --git a/drivers/media/platform/sti/delta/delta-v4l2.c b/drivers/media/platform/sti/delta/delta-v4l2.c
index 0b42acd4e3a6..91369fb3ffaa 100644
--- a/drivers/media/platform/sti/delta/delta-v4l2.c
+++ b/drivers/media/platform/sti/delta/delta-v4l2.c
@@ -385,8 +385,8 @@ static int delta_querycap(struct file *file, void *priv,
struct delta_ctx *ctx = to_ctx(file->private_data);
struct delta_dev *delta = ctx->dev;
- strlcpy(cap->driver, DELTA_NAME, sizeof(cap->driver));
- strlcpy(cap->card, delta->vdev->name, sizeof(cap->card));
+ strscpy(cap->driver, DELTA_NAME, sizeof(cap->driver));
+ strscpy(cap->card, delta->vdev->name, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
delta->pdev->name);
diff --git a/drivers/media/platform/sti/hva/hva-v4l2.c b/drivers/media/platform/sti/hva/hva-v4l2.c
index 5a807c7c5e79..c42623dccfd6 100644
--- a/drivers/media/platform/sti/hva/hva-v4l2.c
+++ b/drivers/media/platform/sti/hva/hva-v4l2.c
@@ -257,8 +257,8 @@ static int hva_querycap(struct file *file, void *priv,
struct hva_ctx *ctx = fh_to_ctx(file->private_data);
struct hva_dev *hva = ctx_to_hdev(ctx);
- strlcpy(cap->driver, HVA_NAME, sizeof(cap->driver));
- strlcpy(cap->card, hva->vdev->name, sizeof(cap->card));
+ strscpy(cap->driver, HVA_NAME, sizeof(cap->driver));
+ strscpy(cap->card, hva->vdev->name, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
hva->pdev->name);
diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c
index 721564176d8c..6732874114cf 100644
--- a/drivers/media/platform/stm32/stm32-dcmi.c
+++ b/drivers/media/platform/stm32/stm32-dcmi.c
@@ -659,7 +659,10 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count)
}
/* Enable interruptions */
- reg_set(dcmi->regs, DCMI_IER, IT_FRAME | IT_OVR | IT_ERR);
+ if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG)
+ reg_set(dcmi->regs, DCMI_IER, IT_FRAME | IT_OVR | IT_ERR);
+ else
+ reg_set(dcmi->regs, DCMI_IER, IT_OVR | IT_ERR);
return 0;
@@ -1147,10 +1150,10 @@ static int dcmi_s_selection(struct file *file, void *priv,
static int dcmi_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- strlcpy(cap->driver, DRV_NAME, sizeof(cap->driver));
- strlcpy(cap->card, "STM32 Camera Memory Interface",
+ strscpy(cap->driver, DRV_NAME, sizeof(cap->driver));
+ strscpy(cap->card, "STM32 Camera Memory Interface",
sizeof(cap->card));
- strlcpy(cap->bus_info, "platform:dcmi", sizeof(cap->bus_info));
+ strscpy(cap->bus_info, "platform:dcmi", sizeof(cap->bus_info));
return 0;
}
@@ -1161,7 +1164,7 @@ static int dcmi_enum_input(struct file *file, void *priv,
return -EINVAL;
i->type = V4L2_INPUT_TYPE_CAMERA;
- strlcpy(i->name, "Camera", sizeof(i->name));
+ strscpy(i->name, "Camera", sizeof(i->name));
return 0;
}
@@ -1587,7 +1590,6 @@ static int dcmi_graph_parse(struct stm32_dcmi *dcmi, struct device_node *node)
static int dcmi_graph_init(struct stm32_dcmi *dcmi)
{
- struct v4l2_async_subdev **subdevs = NULL;
int ret;
/* Parse the graph to extract a list of subdevice DT nodes. */
@@ -1597,23 +1599,21 @@ static int dcmi_graph_init(struct stm32_dcmi *dcmi)
return ret;
}
- /* Register the subdevices notifier. */
- subdevs = devm_kzalloc(dcmi->dev, sizeof(*subdevs), GFP_KERNEL);
- if (!subdevs) {
+ v4l2_async_notifier_init(&dcmi->notifier);
+
+ ret = v4l2_async_notifier_add_subdev(&dcmi->notifier,
+ &dcmi->entity.asd);
+ if (ret) {
of_node_put(dcmi->entity.node);
- return -ENOMEM;
+ return ret;
}
- subdevs[0] = &dcmi->entity.asd;
-
- dcmi->notifier.subdevs = subdevs;
- dcmi->notifier.num_subdevs = 1;
dcmi->notifier.ops = &dcmi_graph_notify_ops;
ret = v4l2_async_notifier_register(&dcmi->v4l2_dev, &dcmi->notifier);
if (ret < 0) {
dev_err(dcmi->dev, "Notifier registration failed\n");
- of_node_put(dcmi->entity.node);
+ v4l2_async_notifier_cleanup(&dcmi->notifier);
return ret;
}
@@ -1624,7 +1624,7 @@ static int dcmi_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
const struct of_device_id *match = NULL;
- struct v4l2_fwnode_endpoint ep;
+ struct v4l2_fwnode_endpoint ep = { .bus_type = 0 };
struct stm32_dcmi *dcmi;
struct vb2_queue *q;
struct dma_chan *chan;
@@ -1663,7 +1663,7 @@ static int dcmi_probe(struct platform_device *pdev)
return -ENODEV;
}
- if (ep.bus_type == V4L2_MBUS_CSI2) {
+ if (ep.bus_type == V4L2_MBUS_CSI2_DPHY) {
dev_err(&pdev->dev, "CSI bus not supported\n");
return -ENODEV;
}
@@ -1736,7 +1736,7 @@ static int dcmi_probe(struct platform_device *pdev)
dcmi->vdev->fops = &dcmi_fops;
dcmi->vdev->v4l2_dev = &dcmi->v4l2_dev;
dcmi->vdev->queue = &dcmi->queue;
- strlcpy(dcmi->vdev->name, KBUILD_MODNAME, sizeof(dcmi->vdev->name));
+ strscpy(dcmi->vdev->name, KBUILD_MODNAME, sizeof(dcmi->vdev->name));
dcmi->vdev->release = video_device_release;
dcmi->vdev->ioctl_ops = &dcmi_ioctl_ops;
dcmi->vdev->lock = &dcmi->lock;
@@ -1770,7 +1770,7 @@ static int dcmi_probe(struct platform_device *pdev)
ret = reset_control_assert(dcmi->rstc);
if (ret) {
dev_err(&pdev->dev, "Failed to assert the reset line\n");
- goto err_device_release;
+ goto err_cleanup;
}
usleep_range(3000, 5000);
@@ -1778,7 +1778,7 @@ static int dcmi_probe(struct platform_device *pdev)
ret = reset_control_deassert(dcmi->rstc);
if (ret) {
dev_err(&pdev->dev, "Failed to deassert the reset line\n");
- goto err_device_release;
+ goto err_cleanup;
}
dev_info(&pdev->dev, "Probe done\n");
@@ -1789,6 +1789,8 @@ static int dcmi_probe(struct platform_device *pdev)
return 0;
+err_cleanup:
+ v4l2_async_notifier_cleanup(&dcmi->notifier);
err_device_release:
video_device_release(dcmi->vdev);
err_device_unregister:
@@ -1806,6 +1808,7 @@ static int dcmi_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
v4l2_async_notifier_unregister(&dcmi->notifier);
+ v4l2_async_notifier_cleanup(&dcmi->notifier);
v4l2_device_unregister(&dcmi->v4l2_dev);
dma_release_channel(dcmi->dma_chan);
diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c
index d1febe5baa6d..95a093f41905 100644
--- a/drivers/media/platform/ti-vpe/cal.c
+++ b/drivers/media/platform/ti-vpe/cal.c
@@ -270,7 +270,6 @@ struct cal_ctx {
struct v4l2_fwnode_endpoint endpoint;
struct v4l2_async_subdev asd;
- struct v4l2_async_subdev *asd_list[1];
struct v4l2_fh fh;
struct cal_dev *dev;
@@ -912,8 +911,8 @@ static int cal_querycap(struct file *file, void *priv,
{
struct cal_ctx *ctx = video_drvdata(file);
- strlcpy(cap->driver, CAL_MODULE_NAME, sizeof(cap->driver));
- strlcpy(cap->card, CAL_MODULE_NAME, sizeof(cap->card));
+ strscpy(cap->driver, CAL_MODULE_NAME, sizeof(cap->driver));
+ strscpy(cap->card, CAL_MODULE_NAME, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info),
"platform:%s", ctx->v4l2_dev.name);
@@ -1711,9 +1710,9 @@ static int of_cal_create_instance(struct cal_ctx *ctx, int inst)
}
v4l2_fwnode_endpoint_parse(of_fwnode_handle(remote_ep), endpoint);
- if (endpoint->bus_type != V4L2_MBUS_CSI2) {
- ctx_err(ctx, "Port:%d sub-device %s is not a CSI2 device\n",
- inst, sensor_node->name);
+ if (endpoint->bus_type != V4L2_MBUS_CSI2_DPHY) {
+ ctx_err(ctx, "Port:%d sub-device %pOFn is not a CSI2 device\n",
+ inst, sensor_node);
goto cleanup_exit;
}
@@ -1732,29 +1731,38 @@ static int of_cal_create_instance(struct cal_ctx *ctx, int inst)
endpoint->bus.mipi_csi2.data_lanes[lane]);
ctx_dbg(3, ctx, "\t>\n");
- ctx_dbg(1, ctx, "Port: %d found sub-device %s\n",
- inst, sensor_node->name);
+ ctx_dbg(1, ctx, "Port: %d found sub-device %pOFn\n",
+ inst, sensor_node);
+
+ v4l2_async_notifier_init(&ctx->notifier);
+
+ ret = v4l2_async_notifier_add_subdev(&ctx->notifier, asd);
+ if (ret) {
+ ctx_err(ctx, "Error adding asd\n");
+ goto cleanup_exit;
+ }
- ctx->asd_list[0] = asd;
- ctx->notifier.subdevs = ctx->asd_list;
- ctx->notifier.num_subdevs = 1;
ctx->notifier.ops = &cal_async_ops;
ret = v4l2_async_notifier_register(&ctx->v4l2_dev,
&ctx->notifier);
if (ret) {
ctx_err(ctx, "Error registering async notifier\n");
+ v4l2_async_notifier_cleanup(&ctx->notifier);
ret = -EINVAL;
}
+ /*
+ * On success we need to keep reference on sensor_node, or
+ * if notifier_cleanup was called above, sensor_node was
+ * already put.
+ */
+ sensor_node = NULL;
+
cleanup_exit:
- if (remote_ep)
- of_node_put(remote_ep);
- if (sensor_node)
- of_node_put(sensor_node);
- if (ep_node)
- of_node_put(ep_node);
- if (port)
- of_node_put(port);
+ of_node_put(remote_ep);
+ of_node_put(sensor_node);
+ of_node_put(ep_node);
+ of_node_put(port);
return ret;
}
@@ -1810,15 +1818,17 @@ err_exit:
static int cal_probe(struct platform_device *pdev)
{
struct cal_dev *dev;
+ struct cal_ctx *ctx;
int ret;
int irq;
+ int i;
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
/* set pseudo v4l2 device name so we can use v4l2_printk */
- strlcpy(dev->v4l2_dev.name, CAL_MODULE_NAME,
+ strscpy(dev->v4l2_dev.name, CAL_MODULE_NAME,
sizeof(dev->v4l2_dev.name));
/* save pdev pointer */
@@ -1879,6 +1889,16 @@ static int cal_probe(struct platform_device *pdev)
runtime_disable:
pm_runtime_disable(&pdev->dev);
+ for (i = 0; i < CAL_NUM_CONTEXT; i++) {
+ ctx = dev->ctx[i];
+ if (ctx) {
+ v4l2_async_notifier_unregister(&ctx->notifier);
+ v4l2_async_notifier_cleanup(&ctx->notifier);
+ v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+ v4l2_device_unregister(&ctx->v4l2_dev);
+ }
+ }
+
return ret;
}
@@ -1900,6 +1920,7 @@ static int cal_remove(struct platform_device *pdev)
video_device_node_name(&ctx->vdev));
camerarx_phy_disable(ctx);
v4l2_async_notifier_unregister(&ctx->notifier);
+ v4l2_async_notifier_cleanup(&ctx->notifier);
v4l2_ctrl_handler_free(&ctx->ctrl_handler);
v4l2_device_unregister(&ctx->v4l2_dev);
video_unregister_device(&ctx->vdev);
diff --git a/drivers/media/platform/via-camera.c b/drivers/media/platform/via-camera.c
index c8bb82fe0b9d..24d5759501a5 100644
--- a/drivers/media/platform/via-camera.c
+++ b/drivers/media/platform/via-camera.c
@@ -812,7 +812,7 @@ static int viacam_enum_input(struct file *filp, void *priv,
input->type = V4L2_INPUT_TYPE_CAMERA;
input->std = V4L2_STD_ALL; /* Not sure what should go here */
- strcpy(input->name, "Camera");
+ strscpy(input->name, "Camera", sizeof(input->name));
return 0;
}
@@ -860,8 +860,8 @@ static int viacam_enum_fmt_vid_cap(struct file *filp, void *priv,
{
if (fmt->index >= N_VIA_FMTS)
return -EINVAL;
- strlcpy(fmt->description, via_formats[fmt->index].desc,
- sizeof(fmt->description));
+ strscpy(fmt->description, via_formats[fmt->index].desc,
+ sizeof(fmt->description));
fmt->pixelformat = via_formats[fmt->index].pixelformat;
return 0;
}
@@ -990,8 +990,8 @@ out:
static int viacam_querycap(struct file *filp, void *priv,
struct v4l2_capability *cap)
{
- strcpy(cap->driver, "via-camera");
- strcpy(cap->card, "via-camera");
+ strscpy(cap->driver, "via-camera", sizeof(cap->driver));
+ strscpy(cap->card, "via-camera", sizeof(cap->card));
cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
diff --git a/drivers/media/platform/vicodec/Kconfig b/drivers/media/platform/vicodec/Kconfig
index 2503bcb1529f..ad13329e3461 100644
--- a/drivers/media/platform/vicodec/Kconfig
+++ b/drivers/media/platform/vicodec/Kconfig
@@ -1,6 +1,6 @@
config VIDEO_VICODEC
tristate "Virtual Codec Driver"
- depends on VIDEO_DEV && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+ depends on VIDEO_DEV && VIDEO_V4L2
select VIDEOBUF2_VMALLOC
select V4L2_MEM2MEM_DEV
default n
diff --git a/drivers/media/platform/vicodec/Makefile b/drivers/media/platform/vicodec/Makefile
index 197229428953..01bf7e9308a6 100644
--- a/drivers/media/platform/vicodec/Makefile
+++ b/drivers/media/platform/vicodec/Makefile
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
-vicodec-objs := vicodec-core.o vicodec-codec.o
+vicodec-objs := vicodec-core.o codec-fwht.o codec-v4l2-fwht.o
obj-$(CONFIG_VIDEO_VICODEC) += vicodec.o
diff --git a/drivers/media/platform/vicodec/vicodec-codec.c b/drivers/media/platform/vicodec/codec-fwht.c
index 2d047646f614..36656031b295 100644
--- a/drivers/media/platform/vicodec/vicodec-codec.c
+++ b/drivers/media/platform/vicodec/codec-fwht.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+// SPDX-License-Identifier: LGPL-2.1+
/*
* Copyright 2016 Tom aan de Wiel
* Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
@@ -10,10 +10,20 @@
*/
#include <linux/string.h>
-#include "vicodec-codec.h"
+#include "codec-fwht.h"
+
+/*
+ * Note: bit 0 of the header must always be 0. Otherwise it cannot
+ * be guaranteed that the magic 8 byte sequence (see below) can
+ * never occur in the rlc output.
+ */
+#define PFRAME_BIT BIT(15)
+#define DUPS_MASK 0x1ffe
+
+#define PBLOCK 0
+#define IBLOCK 1
#define ALL_ZEROS 15
-#define DEADZONE_WIDTH 20
static const uint8_t zigzag[64] = {
0,
@@ -164,7 +174,7 @@ static const int quant_table_p[] = {
3, 3, 3, 6, 6, 9, 9, 10,
};
-static void quantize_intra(s16 *coeff, s16 *de_coeff)
+static void quantize_intra(s16 *coeff, s16 *de_coeff, u16 qp)
{
const int *quant = quant_table;
int i, j;
@@ -172,8 +182,7 @@ static void quantize_intra(s16 *coeff, s16 *de_coeff)
for (j = 0; j < 8; j++) {
for (i = 0; i < 8; i++, quant++, coeff++, de_coeff++) {
*coeff >>= *quant;
- if (*coeff >= -DEADZONE_WIDTH &&
- *coeff <= DEADZONE_WIDTH)
+ if (*coeff >= -qp && *coeff <= qp)
*coeff = *de_coeff = 0;
else
*de_coeff = *coeff << *quant;
@@ -191,7 +200,7 @@ static void dequantize_intra(s16 *coeff)
*coeff <<= *quant;
}
-static void quantize_inter(s16 *coeff, s16 *de_coeff)
+static void quantize_inter(s16 *coeff, s16 *de_coeff, u16 qp)
{
const int *quant = quant_table_p;
int i, j;
@@ -199,8 +208,7 @@ static void quantize_inter(s16 *coeff, s16 *de_coeff)
for (j = 0; j < 8; j++) {
for (i = 0; i < 8; i++, quant++, coeff++, de_coeff++) {
*coeff >>= *quant;
- if (*coeff >= -DEADZONE_WIDTH &&
- *coeff <= DEADZONE_WIDTH)
+ if (*coeff >= -qp && *coeff <= qp)
*coeff = *de_coeff = 0;
else
*de_coeff = *coeff << *quant;
@@ -232,7 +240,8 @@ static void fwht(const u8 *block, s16 *output_block, unsigned int stride,
stride *= input_step;
for (i = 0; i < 8; i++, tmp += stride, out += 8) {
- if (input_step == 1) {
+ switch (input_step) {
+ case 1:
workspace1[0] = tmp[0] + tmp[1] - add;
workspace1[1] = tmp[0] - tmp[1];
@@ -244,7 +253,8 @@ static void fwht(const u8 *block, s16 *output_block, unsigned int stride,
workspace1[6] = tmp[6] + tmp[7] - add;
workspace1[7] = tmp[6] - tmp[7];
- } else {
+ break;
+ case 2:
workspace1[0] = tmp[0] + tmp[2] - add;
workspace1[1] = tmp[0] - tmp[2];
@@ -256,6 +266,33 @@ static void fwht(const u8 *block, s16 *output_block, unsigned int stride,
workspace1[6] = tmp[12] + tmp[14] - add;
workspace1[7] = tmp[12] - tmp[14];
+ break;
+ case 3:
+ workspace1[0] = tmp[0] + tmp[3] - add;
+ workspace1[1] = tmp[0] - tmp[3];
+
+ workspace1[2] = tmp[6] + tmp[9] - add;
+ workspace1[3] = tmp[6] - tmp[9];
+
+ workspace1[4] = tmp[12] + tmp[15] - add;
+ workspace1[5] = tmp[12] - tmp[15];
+
+ workspace1[6] = tmp[18] + tmp[21] - add;
+ workspace1[7] = tmp[18] - tmp[21];
+ break;
+ default:
+ workspace1[0] = tmp[0] + tmp[4] - add;
+ workspace1[1] = tmp[0] - tmp[4];
+
+ workspace1[2] = tmp[8] + tmp[12] - add;
+ workspace1[3] = tmp[8] - tmp[12];
+
+ workspace1[4] = tmp[16] + tmp[20] - add;
+ workspace1[5] = tmp[16] - tmp[20];
+
+ workspace1[6] = tmp[24] + tmp[28] - add;
+ workspace1[7] = tmp[24] - tmp[28];
+ break;
}
/* stage 2 */
@@ -588,8 +625,14 @@ static void fill_decoder_block(u8 *dst, const s16 *input, int stride)
int i, j;
for (i = 0; i < 8; i++) {
- for (j = 0; j < 8; j++)
- *dst++ = *input++;
+ for (j = 0; j < 8; j++, input++, dst++) {
+ if (*input < 0)
+ *dst = 0;
+ else if (*input > 255)
+ *dst = 255;
+ else
+ *dst = *input;
+ }
dst += stride - 8;
}
}
@@ -616,7 +659,7 @@ static void add_deltas(s16 *deltas, const u8 *ref, int stride)
}
static u32 encode_plane(u8 *input, u8 *refp, __be16 **rlco, __be16 *rlco_max,
- struct cframe *cf, u32 height, u32 width,
+ struct fwht_cframe *cf, u32 height, u32 width,
unsigned int input_step,
bool is_intra, bool next_is_intra)
{
@@ -637,15 +680,16 @@ static u32 encode_plane(u8 *input, u8 *refp, __be16 **rlco, __be16 *rlco_max,
if (!is_intra)
blocktype = decide_blocktype(input, refp,
deltablock, width, input_step);
- if (is_intra || blocktype == IBLOCK) {
+ if (blocktype == IBLOCK) {
fwht(input, cf->coeffs, width, input_step, 1);
- quantize_intra(cf->coeffs, cf->de_coeffs);
- blocktype = IBLOCK;
+ quantize_intra(cf->coeffs, cf->de_coeffs,
+ cf->i_frame_qp);
} else {
/* inter code */
- encoding |= FRAME_PCODED;
+ encoding |= FWHT_FRAME_PCODED;
fwht16(deltablock, cf->coeffs, 8, 0);
- quantize_inter(cf->coeffs, cf->de_coeffs);
+ quantize_inter(cf->coeffs, cf->de_coeffs,
+ cf->p_frame_qp);
}
if (!next_is_intra) {
ifwht(cf->de_coeffs, cf->de_fwht, blocktype);
@@ -658,9 +702,6 @@ static u32 encode_plane(u8 *input, u8 *refp, __be16 **rlco, __be16 *rlco_max,
input += 8 * input_step;
refp += 8 * 8;
- if (encoding & FRAME_UNENCODED)
- continue;
-
size = rlc(cf->coeffs, *rlco, blocktype);
if (last_size == size &&
!memcmp(*rlco + 1, *rlco - size + 1, 2 * size - 2)) {
@@ -675,13 +716,17 @@ static u32 encode_plane(u8 *input, u8 *refp, __be16 **rlco, __be16 *rlco_max,
} else {
*rlco += size;
}
- if (*rlco >= rlco_max)
- encoding |= FRAME_UNENCODED;
+ if (*rlco >= rlco_max) {
+ encoding |= FWHT_FRAME_UNENCODED;
+ goto exit_loop;
+ }
last_size = size;
}
input += width * 7 * input_step;
}
- if (encoding & FRAME_UNENCODED) {
+
+exit_loop:
+ if (encoding & FWHT_FRAME_UNENCODED) {
u8 *out = (u8 *)rlco_start;
input = input_start;
@@ -694,44 +739,50 @@ static u32 encode_plane(u8 *input, u8 *refp, __be16 **rlco, __be16 *rlco_max,
for (i = 0; i < height * width; i++, input += input_step)
*out++ = (*input == 0xff) ? 0xfe : *input;
*rlco = (__be16 *)out;
+ encoding &= ~FWHT_FRAME_PCODED;
}
return encoding;
}
-u32 encode_frame(struct raw_frame *frm, struct raw_frame *ref_frm,
- struct cframe *cf, bool is_intra, bool next_is_intra)
+u32 fwht_encode_frame(struct fwht_raw_frame *frm,
+ struct fwht_raw_frame *ref_frm,
+ struct fwht_cframe *cf,
+ bool is_intra, bool next_is_intra)
{
unsigned int size = frm->height * frm->width;
__be16 *rlco = cf->rlc_data;
__be16 *rlco_max;
u32 encoding;
+ u32 chroma_h = frm->height / frm->height_div;
+ u32 chroma_w = frm->width / frm->width_div;
+ unsigned int chroma_size = chroma_h * chroma_w;
rlco_max = rlco + size / 2 - 256;
encoding = encode_plane(frm->luma, ref_frm->luma, &rlco, rlco_max, cf,
- frm->height, frm->width,
- 1, is_intra, next_is_intra);
- if (encoding & FRAME_UNENCODED)
- encoding |= LUMA_UNENCODED;
- encoding &= ~FRAME_UNENCODED;
- rlco_max = rlco + size / 8 - 256;
+ frm->height, frm->width,
+ frm->luma_step, is_intra, next_is_intra);
+ if (encoding & FWHT_FRAME_UNENCODED)
+ encoding |= FWHT_LUMA_UNENCODED;
+ encoding &= ~FWHT_FRAME_UNENCODED;
+ rlco_max = rlco + chroma_size / 2 - 256;
encoding |= encode_plane(frm->cb, ref_frm->cb, &rlco, rlco_max, cf,
- frm->height / 2, frm->width / 2,
- frm->chroma_step, is_intra, next_is_intra);
- if (encoding & FRAME_UNENCODED)
- encoding |= CB_UNENCODED;
- encoding &= ~FRAME_UNENCODED;
- rlco_max = rlco + size / 8 - 256;
+ chroma_h, chroma_w,
+ frm->chroma_step, is_intra, next_is_intra);
+ if (encoding & FWHT_FRAME_UNENCODED)
+ encoding |= FWHT_CB_UNENCODED;
+ encoding &= ~FWHT_FRAME_UNENCODED;
+ rlco_max = rlco + chroma_size / 2 - 256;
encoding |= encode_plane(frm->cr, ref_frm->cr, &rlco, rlco_max, cf,
- frm->height / 2, frm->width / 2,
- frm->chroma_step, is_intra, next_is_intra);
- if (encoding & FRAME_UNENCODED)
- encoding |= CR_UNENCODED;
- encoding &= ~FRAME_UNENCODED;
+ chroma_h, chroma_w,
+ frm->chroma_step, is_intra, next_is_intra);
+ if (encoding & FWHT_FRAME_UNENCODED)
+ encoding |= FWHT_CR_UNENCODED;
+ encoding &= ~FWHT_FRAME_UNENCODED;
cf->size = (rlco - cf->rlc_data) * sizeof(*rlco);
return encoding;
}
-static void decode_plane(struct cframe *cf, const __be16 **rlco, u8 *ref,
+static void decode_plane(struct fwht_cframe *cf, const __be16 **rlco, u8 *ref,
u32 height, u32 width, bool uncompressed)
{
unsigned int copies = 0;
@@ -784,14 +835,21 @@ static void decode_plane(struct cframe *cf, const __be16 **rlco, u8 *ref,
}
}
-void decode_frame(struct cframe *cf, struct raw_frame *ref, u32 hdr_flags)
+void fwht_decode_frame(struct fwht_cframe *cf, struct fwht_raw_frame *ref,
+ u32 hdr_flags)
{
const __be16 *rlco = cf->rlc_data;
+ u32 h = cf->height / 2;
+ u32 w = cf->width / 2;
+ if (hdr_flags & FWHT_FL_CHROMA_FULL_HEIGHT)
+ h *= 2;
+ if (hdr_flags & FWHT_FL_CHROMA_FULL_WIDTH)
+ w *= 2;
decode_plane(cf, &rlco, ref->luma, cf->height, cf->width,
- hdr_flags & VICODEC_FL_LUMA_IS_UNCOMPRESSED);
- decode_plane(cf, &rlco, ref->cb, cf->height / 2, cf->width / 2,
- hdr_flags & VICODEC_FL_CB_IS_UNCOMPRESSED);
- decode_plane(cf, &rlco, ref->cr, cf->height / 2, cf->width / 2,
- hdr_flags & VICODEC_FL_CR_IS_UNCOMPRESSED);
+ hdr_flags & FWHT_FL_LUMA_IS_UNCOMPRESSED);
+ decode_plane(cf, &rlco, ref->cb, h, w,
+ hdr_flags & FWHT_FL_CB_IS_UNCOMPRESSED);
+ decode_plane(cf, &rlco, ref->cr, h, w,
+ hdr_flags & FWHT_FL_CR_IS_UNCOMPRESSED);
}
diff --git a/drivers/media/platform/vicodec/vicodec-codec.h b/drivers/media/platform/vicodec/codec-fwht.h
index cdfad1332a3e..3e9391fec5fe 100644
--- a/drivers/media/platform/vicodec/vicodec-codec.h
+++ b/drivers/media/platform/vicodec/codec-fwht.h
@@ -1,18 +1,18 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
+/* SPDX-License-Identifier: LGPL-2.1+ */
/*
* Copyright 2016 Tom aan de Wiel
* Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
*/
-#ifndef VICODEC_RLC_H
-#define VICODEC_RLC_H
+#ifndef CODEC_FWHT_H
+#define CODEC_FWHT_H
#include <linux/types.h>
#include <linux/bitops.h>
#include <asm/byteorder.h>
/*
- * The compressed format consists of a cframe_hdr struct followed by the
+ * The compressed format consists of a fwht_cframe_hdr struct followed by the
* compressed frame data. The header contains the size of that data.
* Each Y, Cb and Cr plane is compressed separately. If the compressed
* size of each plane becomes larger than the uncompressed size, then
@@ -35,7 +35,7 @@
*
* All 16 and 32 bit values are stored in big-endian (network) order.
*
- * Each cframe_hdr starts with an 8 byte magic header that is
+ * Each fwht_cframe_hdr starts with an 8 byte magic header that is
* guaranteed not to occur in the compressed frame data. This header
* can be used to sync to the next frame.
*
@@ -47,48 +47,36 @@
*/
/*
- * Note: bit 0 of the header must always be 0. Otherwise it cannot
- * be guaranteed that the magic 8 byte sequence (see below) can
- * never occur in the rlc output.
- */
-#define PFRAME_BIT (1 << 15)
-#define DUPS_MASK 0x1ffe
-
-/*
* This is a sequence of 8 bytes with the low 4 bits set to 0xf.
*
* This sequence cannot occur in the encoded data
+ *
+ * Note that these two magic values are symmetrical so endian issues here.
*/
-#define VICODEC_MAGIC1 0x4f4f4f4f
-#define VICODEC_MAGIC2 0xffffffff
-
-#define VICODEC_VERSION 1
-
-#define VICODEC_MAX_WIDTH 3840
-#define VICODEC_MAX_HEIGHT 2160
-#define VICODEC_MIN_WIDTH 640
-#define VICODEC_MIN_HEIGHT 480
+#define FWHT_MAGIC1 0x4f4f4f4f
+#define FWHT_MAGIC2 0xffffffff
-#define PBLOCK 0
-#define IBLOCK 1
+#define FWHT_VERSION 1
/* Set if this is an interlaced format */
-#define VICODEC_FL_IS_INTERLACED BIT(0)
+#define FWHT_FL_IS_INTERLACED BIT(0)
/* Set if this is a bottom-first (NTSC) interlaced format */
-#define VICODEC_FL_IS_BOTTOM_FIRST BIT(1)
+#define FWHT_FL_IS_BOTTOM_FIRST BIT(1)
/* Set if each 'frame' contains just one field */
-#define VICODEC_FL_IS_ALTERNATE BIT(2)
+#define FWHT_FL_IS_ALTERNATE BIT(2)
/*
- * If VICODEC_FL_IS_ALTERNATE was set, then this is set if this
+ * If FWHT_FL_IS_ALTERNATE was set, then this is set if this
* 'frame' is the bottom field, else it is the top field.
*/
-#define VICODEC_FL_IS_BOTTOM_FIELD BIT(3)
+#define FWHT_FL_IS_BOTTOM_FIELD BIT(3)
/* Set if this frame is uncompressed */
-#define VICODEC_FL_LUMA_IS_UNCOMPRESSED BIT(4)
-#define VICODEC_FL_CB_IS_UNCOMPRESSED BIT(5)
-#define VICODEC_FL_CR_IS_UNCOMPRESSED BIT(6)
+#define FWHT_FL_LUMA_IS_UNCOMPRESSED BIT(4)
+#define FWHT_FL_CB_IS_UNCOMPRESSED BIT(5)
+#define FWHT_FL_CR_IS_UNCOMPRESSED BIT(6)
+#define FWHT_FL_CHROMA_FULL_HEIGHT BIT(7)
+#define FWHT_FL_CHROMA_FULL_WIDTH BIT(8)
-struct cframe_hdr {
+struct fwht_cframe_hdr {
u32 magic1;
u32 magic2;
__be32 version;
@@ -101,8 +89,10 @@ struct cframe_hdr {
__be32 size;
};
-struct cframe {
+struct fwht_cframe {
unsigned int width, height;
+ u16 i_frame_qp;
+ u16 p_frame_qp;
__be16 *rlc_data;
s16 coeffs[8 * 8];
s16 de_coeffs[8 * 8];
@@ -110,20 +100,26 @@ struct cframe {
u32 size;
};
-struct raw_frame {
+struct fwht_raw_frame {
unsigned int width, height;
+ unsigned int width_div;
+ unsigned int height_div;
+ unsigned int luma_step;
unsigned int chroma_step;
u8 *luma, *cb, *cr;
};
-#define FRAME_PCODED BIT(0)
-#define FRAME_UNENCODED BIT(1)
-#define LUMA_UNENCODED BIT(2)
-#define CB_UNENCODED BIT(3)
-#define CR_UNENCODED BIT(4)
+#define FWHT_FRAME_PCODED BIT(0)
+#define FWHT_FRAME_UNENCODED BIT(1)
+#define FWHT_LUMA_UNENCODED BIT(2)
+#define FWHT_CB_UNENCODED BIT(3)
+#define FWHT_CR_UNENCODED BIT(4)
-u32 encode_frame(struct raw_frame *frm, struct raw_frame *ref_frm,
- struct cframe *cf, bool is_intra, bool next_is_intra);
-void decode_frame(struct cframe *cf, struct raw_frame *ref, u32 hdr_flags);
+u32 fwht_encode_frame(struct fwht_raw_frame *frm,
+ struct fwht_raw_frame *ref_frm,
+ struct fwht_cframe *cf,
+ bool is_intra, bool next_is_intra);
+void fwht_decode_frame(struct fwht_cframe *cf, struct fwht_raw_frame *ref,
+ u32 hdr_flags);
#endif
diff --git a/drivers/media/platform/vicodec/codec-v4l2-fwht.c b/drivers/media/platform/vicodec/codec-v4l2-fwht.c
new file mode 100644
index 000000000000..e5b68fb38aac
--- /dev/null
+++ b/drivers/media/platform/vicodec/codec-v4l2-fwht.c
@@ -0,0 +1,332 @@
+// SPDX-License-Identifier: LGPL-2.1
+/*
+ * A V4L2 frontend for the FWHT codec
+ *
+ * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ */
+
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/videodev2.h>
+#include "codec-v4l2-fwht.h"
+
+static const struct v4l2_fwht_pixfmt_info v4l2_fwht_pixfmts[] = {
+ { V4L2_PIX_FMT_YUV420, 1, 3, 2, 1, 1, 2, 2 },
+ { V4L2_PIX_FMT_YVU420, 1, 3, 2, 1, 1, 2, 2 },
+ { V4L2_PIX_FMT_YUV422P, 1, 2, 1, 1, 1, 2, 1 },
+ { V4L2_PIX_FMT_NV12, 1, 3, 2, 1, 2, 2, 2 },
+ { V4L2_PIX_FMT_NV21, 1, 3, 2, 1, 2, 2, 2 },
+ { V4L2_PIX_FMT_NV16, 1, 2, 1, 1, 2, 2, 1 },
+ { V4L2_PIX_FMT_NV61, 1, 2, 1, 1, 2, 2, 1 },
+ { V4L2_PIX_FMT_NV24, 1, 3, 1, 1, 2, 1, 1 },
+ { V4L2_PIX_FMT_NV42, 1, 3, 1, 1, 2, 1, 1 },
+ { V4L2_PIX_FMT_YUYV, 2, 2, 1, 2, 4, 2, 1 },
+ { V4L2_PIX_FMT_YVYU, 2, 2, 1, 2, 4, 2, 1 },
+ { V4L2_PIX_FMT_UYVY, 2, 2, 1, 2, 4, 2, 1 },
+ { V4L2_PIX_FMT_VYUY, 2, 2, 1, 2, 4, 2, 1 },
+ { V4L2_PIX_FMT_BGR24, 3, 3, 1, 3, 3, 1, 1 },
+ { V4L2_PIX_FMT_RGB24, 3, 3, 1, 3, 3, 1, 1 },
+ { V4L2_PIX_FMT_HSV24, 3, 3, 1, 3, 3, 1, 1 },
+ { V4L2_PIX_FMT_BGR32, 4, 4, 1, 4, 4, 1, 1 },
+ { V4L2_PIX_FMT_XBGR32, 4, 4, 1, 4, 4, 1, 1 },
+ { V4L2_PIX_FMT_RGB32, 4, 4, 1, 4, 4, 1, 1 },
+ { V4L2_PIX_FMT_XRGB32, 4, 4, 1, 4, 4, 1, 1 },
+ { V4L2_PIX_FMT_HSV32, 4, 4, 1, 4, 4, 1, 1 },
+};
+
+const struct v4l2_fwht_pixfmt_info *v4l2_fwht_find_pixfmt(u32 pixelformat)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(v4l2_fwht_pixfmts); i++)
+ if (v4l2_fwht_pixfmts[i].id == pixelformat)
+ return v4l2_fwht_pixfmts + i;
+ return NULL;
+}
+
+const struct v4l2_fwht_pixfmt_info *v4l2_fwht_get_pixfmt(u32 idx)
+{
+ if (idx >= ARRAY_SIZE(v4l2_fwht_pixfmts))
+ return NULL;
+ return v4l2_fwht_pixfmts + idx;
+}
+
+int v4l2_fwht_encode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out)
+{
+ unsigned int size = state->width * state->height;
+ const struct v4l2_fwht_pixfmt_info *info = state->info;
+ struct fwht_cframe_hdr *p_hdr;
+ struct fwht_cframe cf;
+ struct fwht_raw_frame rf;
+ u32 encoding;
+ u32 flags = 0;
+
+ if (!info)
+ return -EINVAL;
+ rf.width = state->width;
+ rf.height = state->height;
+ rf.luma = p_in;
+ rf.width_div = info->width_div;
+ rf.height_div = info->height_div;
+ rf.luma_step = info->luma_step;
+ rf.chroma_step = info->chroma_step;
+
+ switch (info->id) {
+ case V4L2_PIX_FMT_YUV420:
+ rf.cb = rf.luma + size;
+ rf.cr = rf.cb + size / 4;
+ break;
+ case V4L2_PIX_FMT_YVU420:
+ rf.cr = rf.luma + size;
+ rf.cb = rf.cr + size / 4;
+ break;
+ case V4L2_PIX_FMT_YUV422P:
+ rf.cb = rf.luma + size;
+ rf.cr = rf.cb + size / 2;
+ break;
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV24:
+ rf.cb = rf.luma + size;
+ rf.cr = rf.cb + 1;
+ break;
+ case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV61:
+ case V4L2_PIX_FMT_NV42:
+ rf.cr = rf.luma + size;
+ rf.cb = rf.cr + 1;
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ rf.cb = rf.luma + 1;
+ rf.cr = rf.cb + 2;
+ break;
+ case V4L2_PIX_FMT_YVYU:
+ rf.cr = rf.luma + 1;
+ rf.cb = rf.cr + 2;
+ break;
+ case V4L2_PIX_FMT_UYVY:
+ rf.cb = rf.luma;
+ rf.cr = rf.cb + 2;
+ rf.luma++;
+ break;
+ case V4L2_PIX_FMT_VYUY:
+ rf.cr = rf.luma;
+ rf.cb = rf.cr + 2;
+ rf.luma++;
+ break;
+ case V4L2_PIX_FMT_RGB24:
+ case V4L2_PIX_FMT_HSV24:
+ rf.cr = rf.luma;
+ rf.cb = rf.cr + 2;
+ rf.luma++;
+ break;
+ case V4L2_PIX_FMT_BGR24:
+ rf.cb = rf.luma;
+ rf.cr = rf.cb + 2;
+ rf.luma++;
+ break;
+ case V4L2_PIX_FMT_RGB32:
+ case V4L2_PIX_FMT_XRGB32:
+ case V4L2_PIX_FMT_HSV32:
+ rf.cr = rf.luma + 1;
+ rf.cb = rf.cr + 2;
+ rf.luma += 2;
+ break;
+ case V4L2_PIX_FMT_BGR32:
+ case V4L2_PIX_FMT_XBGR32:
+ rf.cb = rf.luma;
+ rf.cr = rf.cb + 2;
+ rf.luma++;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ cf.width = state->width;
+ cf.height = state->height;
+ cf.i_frame_qp = state->i_frame_qp;
+ cf.p_frame_qp = state->p_frame_qp;
+ cf.rlc_data = (__be16 *)(p_out + sizeof(*p_hdr));
+
+ encoding = fwht_encode_frame(&rf, &state->ref_frame, &cf,
+ !state->gop_cnt,
+ state->gop_cnt == state->gop_size - 1);
+ if (!(encoding & FWHT_FRAME_PCODED))
+ state->gop_cnt = 0;
+ if (++state->gop_cnt >= state->gop_size)
+ state->gop_cnt = 0;
+
+ p_hdr = (struct fwht_cframe_hdr *)p_out;
+ p_hdr->magic1 = FWHT_MAGIC1;
+ p_hdr->magic2 = FWHT_MAGIC2;
+ p_hdr->version = htonl(FWHT_VERSION);
+ p_hdr->width = htonl(cf.width);
+ p_hdr->height = htonl(cf.height);
+ if (encoding & FWHT_LUMA_UNENCODED)
+ flags |= FWHT_FL_LUMA_IS_UNCOMPRESSED;
+ if (encoding & FWHT_CB_UNENCODED)
+ flags |= FWHT_FL_CB_IS_UNCOMPRESSED;
+ if (encoding & FWHT_CR_UNENCODED)
+ flags |= FWHT_FL_CR_IS_UNCOMPRESSED;
+ if (rf.height_div == 1)
+ flags |= FWHT_FL_CHROMA_FULL_HEIGHT;
+ if (rf.width_div == 1)
+ flags |= FWHT_FL_CHROMA_FULL_WIDTH;
+ p_hdr->flags = htonl(flags);
+ p_hdr->colorspace = htonl(state->colorspace);
+ p_hdr->xfer_func = htonl(state->xfer_func);
+ p_hdr->ycbcr_enc = htonl(state->ycbcr_enc);
+ p_hdr->quantization = htonl(state->quantization);
+ p_hdr->size = htonl(cf.size);
+ state->ref_frame.width = cf.width;
+ state->ref_frame.height = cf.height;
+ return cf.size + sizeof(*p_hdr);
+}
+
+int v4l2_fwht_decode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out)
+{
+ unsigned int size = state->width * state->height;
+ unsigned int chroma_size = size;
+ unsigned int i;
+ u32 flags;
+ struct fwht_cframe_hdr *p_hdr;
+ struct fwht_cframe cf;
+ u8 *p;
+
+ if (!state->info)
+ return -EINVAL;
+
+ p_hdr = (struct fwht_cframe_hdr *)p_in;
+ cf.width = ntohl(p_hdr->width);
+ cf.height = ntohl(p_hdr->height);
+ flags = ntohl(p_hdr->flags);
+ state->colorspace = ntohl(p_hdr->colorspace);
+ state->xfer_func = ntohl(p_hdr->xfer_func);
+ state->ycbcr_enc = ntohl(p_hdr->ycbcr_enc);
+ state->quantization = ntohl(p_hdr->quantization);
+ cf.rlc_data = (__be16 *)(p_in + sizeof(*p_hdr));
+
+ if (p_hdr->magic1 != FWHT_MAGIC1 ||
+ p_hdr->magic2 != FWHT_MAGIC2 ||
+ ntohl(p_hdr->version) != FWHT_VERSION ||
+ (cf.width & 7) || (cf.height & 7))
+ return -EINVAL;
+
+ /* TODO: support resolution changes */
+ if (cf.width != state->width || cf.height != state->height)
+ return -EINVAL;
+
+ if (!(flags & FWHT_FL_CHROMA_FULL_WIDTH))
+ chroma_size /= 2;
+ if (!(flags & FWHT_FL_CHROMA_FULL_HEIGHT))
+ chroma_size /= 2;
+
+ fwht_decode_frame(&cf, &state->ref_frame, flags);
+
+ switch (state->info->id) {
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_YUV422P:
+ memcpy(p_out, state->ref_frame.luma, size);
+ p_out += size;
+ memcpy(p_out, state->ref_frame.cb, chroma_size);
+ p_out += chroma_size;
+ memcpy(p_out, state->ref_frame.cr, chroma_size);
+ break;
+ case V4L2_PIX_FMT_YVU420:
+ memcpy(p_out, state->ref_frame.luma, size);
+ p_out += size;
+ memcpy(p_out, state->ref_frame.cr, chroma_size);
+ p_out += chroma_size;
+ memcpy(p_out, state->ref_frame.cb, chroma_size);
+ break;
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV24:
+ memcpy(p_out, state->ref_frame.luma, size);
+ p_out += size;
+ for (i = 0, p = p_out; i < chroma_size; i++) {
+ *p++ = state->ref_frame.cb[i];
+ *p++ = state->ref_frame.cr[i];
+ }
+ break;
+ case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV61:
+ case V4L2_PIX_FMT_NV42:
+ memcpy(p_out, state->ref_frame.luma, size);
+ p_out += size;
+ for (i = 0, p = p_out; i < chroma_size; i++) {
+ *p++ = state->ref_frame.cr[i];
+ *p++ = state->ref_frame.cb[i];
+ }
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ for (i = 0, p = p_out; i < size; i += 2) {
+ *p++ = state->ref_frame.luma[i];
+ *p++ = state->ref_frame.cb[i / 2];
+ *p++ = state->ref_frame.luma[i + 1];
+ *p++ = state->ref_frame.cr[i / 2];
+ }
+ break;
+ case V4L2_PIX_FMT_YVYU:
+ for (i = 0, p = p_out; i < size; i += 2) {
+ *p++ = state->ref_frame.luma[i];
+ *p++ = state->ref_frame.cr[i / 2];
+ *p++ = state->ref_frame.luma[i + 1];
+ *p++ = state->ref_frame.cb[i / 2];
+ }
+ break;
+ case V4L2_PIX_FMT_UYVY:
+ for (i = 0, p = p_out; i < size; i += 2) {
+ *p++ = state->ref_frame.cb[i / 2];
+ *p++ = state->ref_frame.luma[i];
+ *p++ = state->ref_frame.cr[i / 2];
+ *p++ = state->ref_frame.luma[i + 1];
+ }
+ break;
+ case V4L2_PIX_FMT_VYUY:
+ for (i = 0, p = p_out; i < size; i += 2) {
+ *p++ = state->ref_frame.cr[i / 2];
+ *p++ = state->ref_frame.luma[i];
+ *p++ = state->ref_frame.cb[i / 2];
+ *p++ = state->ref_frame.luma[i + 1];
+ }
+ break;
+ case V4L2_PIX_FMT_RGB24:
+ case V4L2_PIX_FMT_HSV24:
+ for (i = 0, p = p_out; i < size; i++) {
+ *p++ = state->ref_frame.cr[i];
+ *p++ = state->ref_frame.luma[i];
+ *p++ = state->ref_frame.cb[i];
+ }
+ break;
+ case V4L2_PIX_FMT_BGR24:
+ for (i = 0, p = p_out; i < size; i++) {
+ *p++ = state->ref_frame.cb[i];
+ *p++ = state->ref_frame.luma[i];
+ *p++ = state->ref_frame.cr[i];
+ }
+ break;
+ case V4L2_PIX_FMT_RGB32:
+ case V4L2_PIX_FMT_XRGB32:
+ case V4L2_PIX_FMT_HSV32:
+ for (i = 0, p = p_out; i < size; i++) {
+ *p++ = 0;
+ *p++ = state->ref_frame.cr[i];
+ *p++ = state->ref_frame.luma[i];
+ *p++ = state->ref_frame.cb[i];
+ }
+ break;
+ case V4L2_PIX_FMT_BGR32:
+ case V4L2_PIX_FMT_XBGR32:
+ for (i = 0, p = p_out; i < size; i++) {
+ *p++ = state->ref_frame.cb[i];
+ *p++ = state->ref_frame.luma[i];
+ *p++ = state->ref_frame.cr[i];
+ *p++ = 0;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
diff --git a/drivers/media/platform/vicodec/codec-v4l2-fwht.h b/drivers/media/platform/vicodec/codec-v4l2-fwht.h
new file mode 100644
index 000000000000..162465b78067
--- /dev/null
+++ b/drivers/media/platform/vicodec/codec-v4l2-fwht.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: LGPL-2.1 */
+/*
+ * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ */
+
+#ifndef CODEC_V4L2_FWHT_H
+#define CODEC_V4L2_FWHT_H
+
+#include "codec-fwht.h"
+
+struct v4l2_fwht_pixfmt_info {
+ u32 id;
+ unsigned int bytesperline_mult;
+ unsigned int sizeimage_mult;
+ unsigned int sizeimage_div;
+ unsigned int luma_step;
+ unsigned int chroma_step;
+ /* Chroma plane subsampling */
+ unsigned int width_div;
+ unsigned int height_div;
+};
+
+struct v4l2_fwht_state {
+ const struct v4l2_fwht_pixfmt_info *info;
+ unsigned int width;
+ unsigned int height;
+ unsigned int gop_size;
+ unsigned int gop_cnt;
+ u16 i_frame_qp;
+ u16 p_frame_qp;
+
+ enum v4l2_colorspace colorspace;
+ enum v4l2_ycbcr_encoding ycbcr_enc;
+ enum v4l2_xfer_func xfer_func;
+ enum v4l2_quantization quantization;
+
+ struct fwht_raw_frame ref_frame;
+ u8 *compressed_frame;
+};
+
+const struct v4l2_fwht_pixfmt_info *v4l2_fwht_find_pixfmt(u32 pixelformat);
+const struct v4l2_fwht_pixfmt_info *v4l2_fwht_get_pixfmt(u32 idx);
+
+int v4l2_fwht_encode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out);
+int v4l2_fwht_decode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out);
+
+#endif
diff --git a/drivers/media/platform/vicodec/vicodec-core.c b/drivers/media/platform/vicodec/vicodec-core.c
index 408cd55d3580..1eb9132bfc85 100644
--- a/drivers/media/platform/vicodec/vicodec-core.c
+++ b/drivers/media/platform/vicodec/vicodec-core.c
@@ -23,7 +23,7 @@
#include <media/v4l2-event.h>
#include <media/videobuf2-vmalloc.h>
-#include "vicodec-codec.h"
+#include "codec-v4l2-fwht.h"
MODULE_DESCRIPTION("Virtual codec device");
MODULE_AUTHOR("Hans Verkuil <hans.verkuil@cisco.com>");
@@ -48,6 +48,22 @@ MODULE_PARM_DESC(debug, " activates debug info");
v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
+struct pixfmt_info {
+ u32 id;
+ unsigned int bytesperline_mult;
+ unsigned int sizeimage_mult;
+ unsigned int sizeimage_div;
+ unsigned int luma_step;
+ unsigned int chroma_step;
+ /* Chroma plane subsampling */
+ unsigned int width_div;
+ unsigned int height_div;
+};
+
+static const struct v4l2_fwht_pixfmt_info pixfmt_fwht = {
+ V4L2_PIX_FMT_FWHT, 0, 3, 1, 1, 1, 1, 1
+};
+
static void vicodec_dev_release(struct device *dev)
{
}
@@ -61,10 +77,9 @@ static struct platform_device vicodec_pdev = {
struct vicodec_q_data {
unsigned int width;
unsigned int height;
- unsigned int flags;
unsigned int sizeimage;
unsigned int sequence;
- u32 fourcc;
+ const struct v4l2_fwht_pixfmt_info *info;
};
enum {
@@ -96,24 +111,14 @@ struct vicodec_ctx {
spinlock_t *lock;
struct v4l2_ctrl_handler hdl;
- struct v4l2_ctrl *ctrl_gop_size;
- unsigned int gop_size;
- unsigned int gop_cnt;
- /* Abort requested by m2m */
- int aborting;
struct vb2_v4l2_buffer *last_src_buf;
struct vb2_v4l2_buffer *last_dst_buf;
- enum v4l2_colorspace colorspace;
- enum v4l2_ycbcr_encoding ycbcr_enc;
- enum v4l2_xfer_func xfer_func;
- enum v4l2_quantization quantization;
-
/* Source and destination queue data */
struct vicodec_q_data q_data[2];
- struct raw_frame ref_frame;
- u8 *compressed_frame;
+ struct v4l2_fwht_state state;
+
u32 cur_buf_offset;
u32 comp_max_size;
u32 comp_size;
@@ -123,13 +128,6 @@ struct vicodec_ctx {
bool comp_has_next_frame;
};
-static const u32 pixfmts_yuv[] = {
- V4L2_PIX_FMT_YUV420,
- V4L2_PIX_FMT_YVU420,
- V4L2_PIX_FMT_NV12,
- V4L2_PIX_FMT_NV21,
-};
-
static inline struct vicodec_ctx *file2ctx(struct file *file)
{
return container_of(file->private_data, struct vicodec_ctx, fh);
@@ -152,156 +150,21 @@ static struct vicodec_q_data *get_q_data(struct vicodec_ctx *ctx,
return NULL;
}
-static void encode(struct vicodec_ctx *ctx,
- struct vicodec_q_data *q_data,
- u8 *p_in, u8 *p_out)
-{
- unsigned int size = q_data->width * q_data->height;
- struct cframe_hdr *p_hdr;
- struct cframe cf;
- struct raw_frame rf;
- u32 encoding;
-
- rf.width = q_data->width;
- rf.height = q_data->height;
- rf.luma = p_in;
-
- switch (q_data->fourcc) {
- case V4L2_PIX_FMT_YUV420:
- rf.cb = rf.luma + size;
- rf.cr = rf.cb + size / 4;
- rf.chroma_step = 1;
- break;
- case V4L2_PIX_FMT_YVU420:
- rf.cr = rf.luma + size;
- rf.cb = rf.cr + size / 4;
- rf.chroma_step = 1;
- break;
- case V4L2_PIX_FMT_NV12:
- rf.cb = rf.luma + size;
- rf.cr = rf.cb + 1;
- rf.chroma_step = 2;
- break;
- case V4L2_PIX_FMT_NV21:
- rf.cr = rf.luma + size;
- rf.cb = rf.cr + 1;
- rf.chroma_step = 2;
- break;
- }
-
- cf.width = q_data->width;
- cf.height = q_data->height;
- cf.rlc_data = (__be16 *)(p_out + sizeof(*p_hdr));
-
- encoding = encode_frame(&rf, &ctx->ref_frame, &cf, !ctx->gop_cnt,
- ctx->gop_cnt == ctx->gop_size - 1);
- if (encoding != FRAME_PCODED)
- ctx->gop_cnt = 0;
- if (++ctx->gop_cnt == ctx->gop_size)
- ctx->gop_cnt = 0;
-
- p_hdr = (struct cframe_hdr *)p_out;
- p_hdr->magic1 = VICODEC_MAGIC1;
- p_hdr->magic2 = VICODEC_MAGIC2;
- p_hdr->version = htonl(VICODEC_VERSION);
- p_hdr->width = htonl(cf.width);
- p_hdr->height = htonl(cf.height);
- p_hdr->flags = htonl(q_data->flags);
- if (encoding & LUMA_UNENCODED)
- p_hdr->flags |= htonl(VICODEC_FL_LUMA_IS_UNCOMPRESSED);
- if (encoding & CB_UNENCODED)
- p_hdr->flags |= htonl(VICODEC_FL_CB_IS_UNCOMPRESSED);
- if (encoding & CR_UNENCODED)
- p_hdr->flags |= htonl(VICODEC_FL_CR_IS_UNCOMPRESSED);
- p_hdr->colorspace = htonl(ctx->colorspace);
- p_hdr->xfer_func = htonl(ctx->xfer_func);
- p_hdr->ycbcr_enc = htonl(ctx->ycbcr_enc);
- p_hdr->quantization = htonl(ctx->quantization);
- p_hdr->size = htonl(cf.size);
- ctx->ref_frame.width = cf.width;
- ctx->ref_frame.height = cf.height;
-}
-
-static int decode(struct vicodec_ctx *ctx,
- struct vicodec_q_data *q_data,
- u8 *p_in, u8 *p_out)
-{
- unsigned int size = q_data->width * q_data->height;
- unsigned int i;
- struct cframe_hdr *p_hdr;
- struct cframe cf;
- u8 *p;
-
- p_hdr = (struct cframe_hdr *)p_in;
- cf.width = ntohl(p_hdr->width);
- cf.height = ntohl(p_hdr->height);
- q_data->flags = ntohl(p_hdr->flags);
- ctx->colorspace = ntohl(p_hdr->colorspace);
- ctx->xfer_func = ntohl(p_hdr->xfer_func);
- ctx->ycbcr_enc = ntohl(p_hdr->ycbcr_enc);
- ctx->quantization = ntohl(p_hdr->quantization);
- cf.rlc_data = (__be16 *)(p_in + sizeof(*p_hdr));
-
- if (p_hdr->magic1 != VICODEC_MAGIC1 ||
- p_hdr->magic2 != VICODEC_MAGIC2 ||
- ntohl(p_hdr->version) != VICODEC_VERSION ||
- cf.width < VICODEC_MIN_WIDTH ||
- cf.width > VICODEC_MAX_WIDTH ||
- cf.height < VICODEC_MIN_HEIGHT ||
- cf.height > VICODEC_MAX_HEIGHT ||
- (cf.width & 7) || (cf.height & 7))
- return -EINVAL;
-
- /* TODO: support resolution changes */
- if (cf.width != q_data->width || cf.height != q_data->height)
- return -EINVAL;
-
- decode_frame(&cf, &ctx->ref_frame, q_data->flags);
- memcpy(p_out, ctx->ref_frame.luma, size);
- p_out += size;
-
- switch (q_data->fourcc) {
- case V4L2_PIX_FMT_YUV420:
- memcpy(p_out, ctx->ref_frame.cb, size / 4);
- p_out += size / 4;
- memcpy(p_out, ctx->ref_frame.cr, size / 4);
- break;
- case V4L2_PIX_FMT_YVU420:
- memcpy(p_out, ctx->ref_frame.cr, size / 4);
- p_out += size / 4;
- memcpy(p_out, ctx->ref_frame.cb, size / 4);
- break;
- case V4L2_PIX_FMT_NV12:
- for (i = 0, p = p_out; i < size / 4; i++, p += 2)
- *p = ctx->ref_frame.cb[i];
- for (i = 0, p = p_out + 1; i < size / 4; i++, p += 2)
- *p = ctx->ref_frame.cr[i];
- break;
- case V4L2_PIX_FMT_NV21:
- for (i = 0, p = p_out; i < size / 4; i++, p += 2)
- *p = ctx->ref_frame.cr[i];
- for (i = 0, p = p_out + 1; i < size / 4; i++, p += 2)
- *p = ctx->ref_frame.cb[i];
- break;
- }
- return 0;
-}
-
static int device_process(struct vicodec_ctx *ctx,
struct vb2_v4l2_buffer *in_vb,
struct vb2_v4l2_buffer *out_vb)
{
struct vicodec_dev *dev = ctx->dev;
- struct vicodec_q_data *q_out, *q_cap;
+ struct vicodec_q_data *q_cap;
+ struct v4l2_fwht_state *state = &ctx->state;
u8 *p_in, *p_out;
int ret;
- q_out = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
q_cap = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
if (ctx->is_enc)
p_in = vb2_plane_vaddr(&in_vb->vb2_buf, 0);
else
- p_in = ctx->compressed_frame;
+ p_in = state->compressed_frame;
p_out = vb2_plane_vaddr(&out_vb->vb2_buf, 0);
if (!p_in || !p_out) {
v4l2_err(&dev->v4l2_dev,
@@ -310,17 +173,20 @@ static int device_process(struct vicodec_ctx *ctx,
}
if (ctx->is_enc) {
- struct cframe_hdr *p_hdr = (struct cframe_hdr *)p_out;
+ struct vicodec_q_data *q_out;
- encode(ctx, q_out, p_in, p_out);
- vb2_set_plane_payload(&out_vb->vb2_buf, 0,
- sizeof(*p_hdr) + ntohl(p_hdr->size));
+ q_out = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+ state->info = q_out->info;
+ ret = v4l2_fwht_encode(state, p_in, p_out);
+ if (ret < 0)
+ return ret;
+ vb2_set_plane_payload(&out_vb->vb2_buf, 0, ret);
} else {
- ret = decode(ctx, q_cap, p_in, p_out);
- if (ret)
+ state->info = q_cap->info;
+ ret = v4l2_fwht_decode(state, p_in, p_out);
+ if (ret < 0)
return ret;
- vb2_set_plane_payload(&out_vb->vb2_buf, 0,
- q_cap->width * q_cap->height * 3 / 2);
+ vb2_set_plane_payload(&out_vb->vb2_buf, 0, q_cap->sizeimage);
}
out_vb->sequence = q_cap->sequence++;
@@ -446,10 +312,11 @@ restart:
copy = sizeof(magic) - ctx->comp_magic_cnt;
if (p_out + sz - p < copy)
copy = p_out + sz - p;
- memcpy(ctx->compressed_frame + ctx->comp_magic_cnt,
+ memcpy(ctx->state.compressed_frame + ctx->comp_magic_cnt,
p, copy);
ctx->comp_magic_cnt += copy;
- if (!memcmp(ctx->compressed_frame, magic, ctx->comp_magic_cnt)) {
+ if (!memcmp(ctx->state.compressed_frame, magic,
+ ctx->comp_magic_cnt)) {
p += copy;
state = VB2_BUF_STATE_DONE;
break;
@@ -462,17 +329,18 @@ restart:
}
ctx->comp_size = sizeof(magic);
}
- if (ctx->comp_size < sizeof(struct cframe_hdr)) {
- struct cframe_hdr *p_hdr = (struct cframe_hdr *)ctx->compressed_frame;
- u32 copy = sizeof(struct cframe_hdr) - ctx->comp_size;
+ if (ctx->comp_size < sizeof(struct fwht_cframe_hdr)) {
+ struct fwht_cframe_hdr *p_hdr =
+ (struct fwht_cframe_hdr *)ctx->state.compressed_frame;
+ u32 copy = sizeof(struct fwht_cframe_hdr) - ctx->comp_size;
if (copy > p_out + sz - p)
copy = p_out + sz - p;
- memcpy(ctx->compressed_frame + ctx->comp_size,
+ memcpy(ctx->state.compressed_frame + ctx->comp_size,
p, copy);
p += copy;
ctx->comp_size += copy;
- if (ctx->comp_size < sizeof(struct cframe_hdr)) {
+ if (ctx->comp_size < sizeof(struct fwht_cframe_hdr)) {
job_remove_out_buf(ctx, state);
goto restart;
}
@@ -485,7 +353,7 @@ restart:
if (copy > p_out + sz - p)
copy = p_out + sz - p;
- memcpy(ctx->compressed_frame + ctx->comp_size,
+ memcpy(ctx->state.compressed_frame + ctx->comp_size,
p, copy);
p += copy;
ctx->comp_size += copy;
@@ -497,8 +365,8 @@ restart:
ctx->cur_buf_offset = p - p_out;
ctx->comp_has_frame = true;
ctx->comp_has_next_frame = false;
- if (sz - ctx->cur_buf_offset >= sizeof(struct cframe_hdr)) {
- struct cframe_hdr *p_hdr = (struct cframe_hdr *)p;
+ if (sz - ctx->cur_buf_offset >= sizeof(struct fwht_cframe_hdr)) {
+ struct fwht_cframe_hdr *p_hdr = (struct fwht_cframe_hdr *)p;
u32 frame_size = ntohl(p_hdr->size);
u32 remaining = sz - ctx->cur_buf_offset - sizeof(*p_hdr);
@@ -508,26 +376,18 @@ restart:
return 1;
}
-static void job_abort(void *priv)
-{
- struct vicodec_ctx *ctx = priv;
-
- /* Will cancel the transaction in the next interrupt handler */
- ctx->aborting = 1;
-}
-
/*
* video ioctls
*/
-static u32 find_fmt(u32 fmt)
+static const struct v4l2_fwht_pixfmt_info *find_fmt(u32 fmt)
{
- unsigned int i;
+ const struct v4l2_fwht_pixfmt_info *info =
+ v4l2_fwht_find_pixfmt(fmt);
- for (i = 0; i < ARRAY_SIZE(pixfmts_yuv); i++)
- if (pixfmts_yuv[i] == fmt)
- return fmt;
- return pixfmts_yuv[0];
+ if (!info)
+ info = v4l2_fwht_get_pixfmt(0);
+ return info;
}
static int vidioc_querycap(struct file *file, void *priv,
@@ -547,19 +407,25 @@ static int vidioc_querycap(struct file *file, void *priv,
static int enum_fmt(struct v4l2_fmtdesc *f, bool is_enc, bool is_out)
{
- bool is_yuv = (is_enc && is_out) || (!is_enc && !is_out);
+ bool is_uncomp = (is_enc && is_out) || (!is_enc && !is_out);
if (V4L2_TYPE_IS_MULTIPLANAR(f->type) && !multiplanar)
return -EINVAL;
if (!V4L2_TYPE_IS_MULTIPLANAR(f->type) && multiplanar)
return -EINVAL;
- if (f->index >= (is_yuv ? ARRAY_SIZE(pixfmts_yuv) : 1))
- return -EINVAL;
- if (is_yuv)
- f->pixelformat = pixfmts_yuv[f->index];
- else
+ if (is_uncomp) {
+ const struct v4l2_fwht_pixfmt_info *info =
+ v4l2_fwht_get_pixfmt(f->index);
+
+ if (!info)
+ return -EINVAL;
+ f->pixelformat = info->id;
+ } else {
+ if (f->index)
+ return -EINVAL;
f->pixelformat = V4L2_PIX_FMT_FWHT;
+ }
return 0;
}
@@ -585,12 +451,14 @@ static int vidioc_g_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f)
struct vicodec_q_data *q_data;
struct v4l2_pix_format_mplane *pix_mp;
struct v4l2_pix_format *pix;
+ const struct v4l2_fwht_pixfmt_info *info;
vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
if (!vq)
return -EINVAL;
q_data = get_q_data(ctx, f->type);
+ info = q_data->info;
switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
@@ -601,16 +469,13 @@ static int vidioc_g_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f)
pix->width = q_data->width;
pix->height = q_data->height;
pix->field = V4L2_FIELD_NONE;
- pix->pixelformat = q_data->fourcc;
- if (q_data->fourcc == V4L2_PIX_FMT_FWHT)
- pix->bytesperline = 0;
- else
- pix->bytesperline = q_data->width;
+ pix->pixelformat = info->id;
+ pix->bytesperline = q_data->width * info->bytesperline_mult;
pix->sizeimage = q_data->sizeimage;
- pix->colorspace = ctx->colorspace;
- pix->xfer_func = ctx->xfer_func;
- pix->ycbcr_enc = ctx->ycbcr_enc;
- pix->quantization = ctx->quantization;
+ pix->colorspace = ctx->state.colorspace;
+ pix->xfer_func = ctx->state.xfer_func;
+ pix->ycbcr_enc = ctx->state.ycbcr_enc;
+ pix->quantization = ctx->state.quantization;
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
@@ -621,17 +486,15 @@ static int vidioc_g_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f)
pix_mp->width = q_data->width;
pix_mp->height = q_data->height;
pix_mp->field = V4L2_FIELD_NONE;
- pix_mp->pixelformat = q_data->fourcc;
+ pix_mp->pixelformat = info->id;
pix_mp->num_planes = 1;
- if (q_data->fourcc == V4L2_PIX_FMT_FWHT)
- pix_mp->plane_fmt[0].bytesperline = 0;
- else
- pix_mp->plane_fmt[0].bytesperline = q_data->width;
+ pix_mp->plane_fmt[0].bytesperline =
+ q_data->width * info->bytesperline_mult;
pix_mp->plane_fmt[0].sizeimage = q_data->sizeimage;
- pix_mp->colorspace = ctx->colorspace;
- pix_mp->xfer_func = ctx->xfer_func;
- pix_mp->ycbcr_enc = ctx->ycbcr_enc;
- pix_mp->quantization = ctx->quantization;
+ pix_mp->colorspace = ctx->state.colorspace;
+ pix_mp->xfer_func = ctx->state.xfer_func;
+ pix_mp->ycbcr_enc = ctx->state.ycbcr_enc;
+ pix_mp->quantization = ctx->state.quantization;
memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
memset(pix_mp->plane_fmt[0].reserved, 0,
sizeof(pix_mp->plane_fmt[0].reserved));
@@ -658,40 +521,44 @@ static int vidioc_try_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f)
{
struct v4l2_pix_format_mplane *pix_mp;
struct v4l2_pix_format *pix;
+ struct v4l2_plane_pix_format *plane;
+ const struct v4l2_fwht_pixfmt_info *info = &pixfmt_fwht;
switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
pix = &f->fmt.pix;
+ if (pix->pixelformat != V4L2_PIX_FMT_FWHT)
+ info = find_fmt(pix->pixelformat);
pix->width = clamp(pix->width, MIN_WIDTH, MAX_WIDTH) & ~7;
pix->height = clamp(pix->height, MIN_HEIGHT, MAX_HEIGHT) & ~7;
- pix->bytesperline = pix->width;
- pix->sizeimage = pix->width * pix->height * 3 / 2;
pix->field = V4L2_FIELD_NONE;
- if (pix->pixelformat == V4L2_PIX_FMT_FWHT) {
- pix->bytesperline = 0;
- pix->sizeimage += sizeof(struct cframe_hdr);
- }
+ pix->bytesperline =
+ pix->width * info->bytesperline_mult;
+ pix->sizeimage = pix->width * pix->height *
+ info->sizeimage_mult / info->sizeimage_div;
+ if (pix->pixelformat == V4L2_PIX_FMT_FWHT)
+ pix->sizeimage += sizeof(struct fwht_cframe_hdr);
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
pix_mp = &f->fmt.pix_mp;
+ plane = pix_mp->plane_fmt;
+ if (pix_mp->pixelformat != V4L2_PIX_FMT_FWHT)
+ info = find_fmt(pix_mp->pixelformat);
+ pix_mp->num_planes = 1;
pix_mp->width = clamp(pix_mp->width, MIN_WIDTH, MAX_WIDTH) & ~7;
pix_mp->height =
clamp(pix_mp->height, MIN_HEIGHT, MAX_HEIGHT) & ~7;
- pix_mp->plane_fmt[0].bytesperline = pix_mp->width;
- pix_mp->plane_fmt[0].sizeimage =
- pix_mp->width * pix_mp->height * 3 / 2;
pix_mp->field = V4L2_FIELD_NONE;
- pix_mp->num_planes = 1;
- if (pix_mp->pixelformat == V4L2_PIX_FMT_FWHT) {
- pix_mp->plane_fmt[0].bytesperline = 0;
- pix_mp->plane_fmt[0].sizeimage +=
- sizeof(struct cframe_hdr);
- }
+ plane->bytesperline =
+ pix_mp->width * info->bytesperline_mult;
+ plane->sizeimage = pix_mp->width * pix_mp->height *
+ info->sizeimage_mult / info->sizeimage_div;
+ if (pix_mp->pixelformat == V4L2_PIX_FMT_FWHT)
+ plane->sizeimage += sizeof(struct fwht_cframe_hdr);
memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
- memset(pix_mp->plane_fmt[0].reserved, 0,
- sizeof(pix_mp->plane_fmt[0].reserved));
+ memset(plane->reserved, 0, sizeof(plane->reserved));
break;
default:
return -EINVAL;
@@ -713,25 +580,22 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
return -EINVAL;
pix = &f->fmt.pix;
pix->pixelformat = ctx->is_enc ? V4L2_PIX_FMT_FWHT :
- find_fmt(f->fmt.pix.pixelformat);
- pix->colorspace = ctx->colorspace;
- pix->xfer_func = ctx->xfer_func;
- pix->ycbcr_enc = ctx->ycbcr_enc;
- pix->quantization = ctx->quantization;
+ find_fmt(f->fmt.pix.pixelformat)->id;
+ pix->colorspace = ctx->state.colorspace;
+ pix->xfer_func = ctx->state.xfer_func;
+ pix->ycbcr_enc = ctx->state.ycbcr_enc;
+ pix->quantization = ctx->state.quantization;
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
if (!multiplanar)
return -EINVAL;
pix_mp = &f->fmt.pix_mp;
pix_mp->pixelformat = ctx->is_enc ? V4L2_PIX_FMT_FWHT :
- find_fmt(pix_mp->pixelformat);
- pix_mp->colorspace = ctx->colorspace;
- pix_mp->xfer_func = ctx->xfer_func;
- pix_mp->ycbcr_enc = ctx->ycbcr_enc;
- pix_mp->quantization = ctx->quantization;
- memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
- memset(pix_mp->plane_fmt[0].reserved, 0,
- sizeof(pix_mp->plane_fmt[0].reserved));
+ find_fmt(pix_mp->pixelformat)->id;
+ pix_mp->colorspace = ctx->state.colorspace;
+ pix_mp->xfer_func = ctx->state.xfer_func;
+ pix_mp->ycbcr_enc = ctx->state.ycbcr_enc;
+ pix_mp->quantization = ctx->state.quantization;
break;
default:
return -EINVAL;
@@ -753,7 +617,7 @@ static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
return -EINVAL;
pix = &f->fmt.pix;
pix->pixelformat = !ctx->is_enc ? V4L2_PIX_FMT_FWHT :
- find_fmt(pix->pixelformat);
+ find_fmt(pix->pixelformat)->id;
if (!pix->colorspace)
pix->colorspace = V4L2_COLORSPACE_REC709;
break;
@@ -762,7 +626,7 @@ static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
return -EINVAL;
pix_mp = &f->fmt.pix_mp;
pix_mp->pixelformat = !ctx->is_enc ? V4L2_PIX_FMT_FWHT :
- find_fmt(pix_mp->pixelformat);
+ find_fmt(pix_mp->pixelformat)->id;
if (!pix_mp->colorspace)
pix_mp->colorspace = V4L2_COLORSPACE_REC709;
break;
@@ -795,14 +659,17 @@ static int vidioc_s_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f)
pix = &f->fmt.pix;
if (ctx->is_enc && V4L2_TYPE_IS_OUTPUT(f->type))
fmt_changed =
- q_data->fourcc != pix->pixelformat ||
+ q_data->info->id != pix->pixelformat ||
q_data->width != pix->width ||
q_data->height != pix->height;
if (vb2_is_busy(vq) && fmt_changed)
return -EBUSY;
- q_data->fourcc = pix->pixelformat;
+ if (pix->pixelformat == V4L2_PIX_FMT_FWHT)
+ q_data->info = &pixfmt_fwht;
+ else
+ q_data->info = find_fmt(pix->pixelformat);
q_data->width = pix->width;
q_data->height = pix->height;
q_data->sizeimage = pix->sizeimage;
@@ -812,14 +679,17 @@ static int vidioc_s_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f)
pix_mp = &f->fmt.pix_mp;
if (ctx->is_enc && V4L2_TYPE_IS_OUTPUT(f->type))
fmt_changed =
- q_data->fourcc != pix_mp->pixelformat ||
+ q_data->info->id != pix_mp->pixelformat ||
q_data->width != pix_mp->width ||
q_data->height != pix_mp->height;
if (vb2_is_busy(vq) && fmt_changed)
return -EBUSY;
- q_data->fourcc = pix_mp->pixelformat;
+ if (pix_mp->pixelformat == V4L2_PIX_FMT_FWHT)
+ q_data->info = &pixfmt_fwht;
+ else
+ q_data->info = find_fmt(pix_mp->pixelformat);
q_data->width = pix_mp->width;
q_data->height = pix_mp->height;
q_data->sizeimage = pix_mp->plane_fmt[0].sizeimage;
@@ -830,7 +700,7 @@ static int vidioc_s_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f)
dprintk(ctx->dev,
"Setting format for type %d, wxh: %dx%d, fourcc: %08x\n",
- f->type, q_data->width, q_data->height, q_data->fourcc);
+ f->type, q_data->width, q_data->height, q_data->info->id);
return 0;
}
@@ -865,18 +735,18 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
pix = &f->fmt.pix;
- ctx->colorspace = pix->colorspace;
- ctx->xfer_func = pix->xfer_func;
- ctx->ycbcr_enc = pix->ycbcr_enc;
- ctx->quantization = pix->quantization;
+ ctx->state.colorspace = pix->colorspace;
+ ctx->state.xfer_func = pix->xfer_func;
+ ctx->state.ycbcr_enc = pix->ycbcr_enc;
+ ctx->state.quantization = pix->quantization;
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
pix_mp = &f->fmt.pix_mp;
- ctx->colorspace = pix_mp->colorspace;
- ctx->xfer_func = pix_mp->xfer_func;
- ctx->ycbcr_enc = pix_mp->ycbcr_enc;
- ctx->quantization = pix_mp->quantization;
+ ctx->state.colorspace = pix_mp->colorspace;
+ ctx->state.xfer_func = pix_mp->xfer_func;
+ ctx->state.ycbcr_enc = pix_mp->ycbcr_enc;
+ ctx->state.quantization = pix_mp->quantization;
break;
default:
break;
@@ -962,7 +832,7 @@ static int vicodec_enum_framesizes(struct file *file, void *fh,
case V4L2_PIX_FMT_FWHT:
break;
default:
- if (find_fmt(fsize->pixel_format) == fsize->pixel_format)
+ if (find_fmt(fsize->pixel_format)->id == fsize->pixel_format)
break;
return -EINVAL;
}
@@ -1119,30 +989,35 @@ static int vicodec_start_streaming(struct vb2_queue *q,
{
struct vicodec_ctx *ctx = vb2_get_drv_priv(q);
struct vicodec_q_data *q_data = get_q_data(ctx, q->type);
+ struct v4l2_fwht_state *state = &ctx->state;
unsigned int size = q_data->width * q_data->height;
+ const struct v4l2_fwht_pixfmt_info *info = q_data->info;
+ unsigned int chroma_div = info->width_div * info->height_div;
q_data->sequence = 0;
if (!V4L2_TYPE_IS_OUTPUT(q->type))
return 0;
- ctx->ref_frame.width = ctx->ref_frame.height = 0;
- ctx->ref_frame.luma = kvmalloc(size * 3 / 2, GFP_KERNEL);
- ctx->comp_max_size = size * 3 / 2 + sizeof(struct cframe_hdr);
- ctx->compressed_frame = kvmalloc(ctx->comp_max_size, GFP_KERNEL);
- if (!ctx->ref_frame.luma || !ctx->compressed_frame) {
- kvfree(ctx->ref_frame.luma);
- kvfree(ctx->compressed_frame);
+ state->width = q_data->width;
+ state->height = q_data->height;
+ state->ref_frame.width = state->ref_frame.height = 0;
+ state->ref_frame.luma = kvmalloc(size + 2 * size / chroma_div,
+ GFP_KERNEL);
+ ctx->comp_max_size = size + 2 * size / chroma_div +
+ sizeof(struct fwht_cframe_hdr);
+ state->compressed_frame = kvmalloc(ctx->comp_max_size, GFP_KERNEL);
+ if (!state->ref_frame.luma || !state->compressed_frame) {
+ kvfree(state->ref_frame.luma);
+ kvfree(state->compressed_frame);
vicodec_return_bufs(q, VB2_BUF_STATE_QUEUED);
return -ENOMEM;
}
- ctx->ref_frame.cb = ctx->ref_frame.luma + size;
- ctx->ref_frame.cr = ctx->ref_frame.cb + size / 4;
+ state->ref_frame.cb = state->ref_frame.luma + size;
+ state->ref_frame.cr = state->ref_frame.cb + size / chroma_div;
ctx->last_src_buf = NULL;
ctx->last_dst_buf = NULL;
- v4l2_ctrl_grab(ctx->ctrl_gop_size, true);
- ctx->gop_size = v4l2_ctrl_g_ctrl(ctx->ctrl_gop_size);
- ctx->gop_cnt = 0;
+ state->gop_cnt = 0;
ctx->cur_buf_offset = 0;
ctx->comp_size = 0;
ctx->comp_magic_cnt = 0;
@@ -1160,9 +1035,8 @@ static void vicodec_stop_streaming(struct vb2_queue *q)
if (!V4L2_TYPE_IS_OUTPUT(q->type))
return;
- kvfree(ctx->ref_frame.luma);
- kvfree(ctx->compressed_frame);
- v4l2_ctrl_grab(ctx->ctrl_gop_size, false);
+ kvfree(ctx->state.ref_frame.luma);
+ kvfree(ctx->state.compressed_frame);
}
static const struct vb2_ops vicodec_qops = {
@@ -1211,6 +1085,55 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
return vb2_queue_init(dst_vq);
}
+#define VICODEC_CID_CUSTOM_BASE (V4L2_CID_MPEG_BASE | 0xf000)
+#define VICODEC_CID_I_FRAME_QP (VICODEC_CID_CUSTOM_BASE + 0)
+#define VICODEC_CID_P_FRAME_QP (VICODEC_CID_CUSTOM_BASE + 1)
+
+static int vicodec_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct vicodec_ctx *ctx = container_of(ctrl->handler,
+ struct vicodec_ctx, hdl);
+
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+ ctx->state.gop_size = ctrl->val;
+ return 0;
+ case VICODEC_CID_I_FRAME_QP:
+ ctx->state.i_frame_qp = ctrl->val;
+ return 0;
+ case VICODEC_CID_P_FRAME_QP:
+ ctx->state.p_frame_qp = ctrl->val;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static struct v4l2_ctrl_ops vicodec_ctrl_ops = {
+ .s_ctrl = vicodec_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config vicodec_ctrl_i_frame = {
+ .ops = &vicodec_ctrl_ops,
+ .id = VICODEC_CID_I_FRAME_QP,
+ .name = "FWHT I-Frame QP Value",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 1,
+ .max = 31,
+ .def = 20,
+ .step = 1,
+};
+
+static const struct v4l2_ctrl_config vicodec_ctrl_p_frame = {
+ .ops = &vicodec_ctrl_ops,
+ .id = VICODEC_CID_P_FRAME_QP,
+ .name = "FWHT P-Frame QP Value",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 1,
+ .max = 31,
+ .def = 20,
+ .step = 1,
+};
+
/*
* File operations
*/
@@ -1239,9 +1162,10 @@ static int vicodec_open(struct file *file)
ctx->dev = dev;
hdl = &ctx->hdl;
v4l2_ctrl_handler_init(hdl, 4);
- ctx->ctrl_gop_size = v4l2_ctrl_new_std(hdl, NULL,
- V4L2_CID_MPEG_VIDEO_GOP_SIZE,
- 1, 16, 1, 10);
+ v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_MPEG_VIDEO_GOP_SIZE,
+ 1, 16, 1, 10);
+ v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_i_frame, NULL);
+ v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_p_frame, NULL);
if (hdl->error) {
rc = hdl->error;
v4l2_ctrl_handler_free(hdl);
@@ -1251,25 +1175,34 @@ static int vicodec_open(struct file *file)
ctx->fh.ctrl_handler = hdl;
v4l2_ctrl_handler_setup(hdl);
- ctx->q_data[V4L2_M2M_SRC].fourcc =
- ctx->is_enc ? V4L2_PIX_FMT_YUV420 : V4L2_PIX_FMT_FWHT;
+ ctx->q_data[V4L2_M2M_SRC].info =
+ ctx->is_enc ? v4l2_fwht_get_pixfmt(0) : &pixfmt_fwht;
ctx->q_data[V4L2_M2M_SRC].width = 1280;
ctx->q_data[V4L2_M2M_SRC].height = 720;
- size = 1280 * 720 * 3 / 2;
- ctx->q_data[V4L2_M2M_SRC].sizeimage = size;
+ size = 1280 * 720 * ctx->q_data[V4L2_M2M_SRC].info->sizeimage_mult /
+ ctx->q_data[V4L2_M2M_SRC].info->sizeimage_div;
+ if (ctx->is_enc)
+ ctx->q_data[V4L2_M2M_SRC].sizeimage = size;
+ else
+ ctx->q_data[V4L2_M2M_SRC].sizeimage =
+ size + sizeof(struct fwht_cframe_hdr);
ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC];
- ctx->q_data[V4L2_M2M_DST].fourcc =
- ctx->is_enc ? V4L2_PIX_FMT_FWHT : V4L2_PIX_FMT_YUV420;
- ctx->colorspace = V4L2_COLORSPACE_REC709;
+ ctx->q_data[V4L2_M2M_DST].info =
+ ctx->is_enc ? &pixfmt_fwht : v4l2_fwht_get_pixfmt(0);
+ size = 1280 * 720 * ctx->q_data[V4L2_M2M_DST].info->sizeimage_mult /
+ ctx->q_data[V4L2_M2M_DST].info->sizeimage_div;
+ if (ctx->is_enc)
+ ctx->q_data[V4L2_M2M_DST].sizeimage =
+ size + sizeof(struct fwht_cframe_hdr);
+ else
+ ctx->q_data[V4L2_M2M_DST].sizeimage = size;
+ ctx->state.colorspace = V4L2_COLORSPACE_REC709;
- size += sizeof(struct cframe_hdr);
if (ctx->is_enc) {
- ctx->q_data[V4L2_M2M_DST].sizeimage = size;
ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->enc_dev, ctx,
&queue_init);
ctx->lock = &dev->enc_lock;
} else {
- ctx->q_data[V4L2_M2M_SRC].sizeimage = size;
ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->dec_dev, ctx,
&queue_init);
ctx->lock = &dev->dec_lock;
@@ -1327,7 +1260,6 @@ static const struct video_device vicodec_videodev = {
static const struct v4l2_m2m_ops m2m_ops = {
.device_run = device_run,
- .job_abort = job_abort,
.job_ready = job_ready,
};
@@ -1350,7 +1282,7 @@ static int vicodec_probe(struct platform_device *pdev)
#ifdef CONFIG_MEDIA_CONTROLLER
dev->mdev.dev = &pdev->dev;
- strlcpy(dev->mdev.model, "vicodec", sizeof(dev->mdev.model));
+ strscpy(dev->mdev.model, "vicodec", sizeof(dev->mdev.model));
media_device_init(&dev->mdev);
dev->v4l2_dev.mdev = &dev->mdev;
#endif
@@ -1378,7 +1310,7 @@ static int vicodec_probe(struct platform_device *pdev)
vfd = &dev->enc_vfd;
vfd->lock = &dev->enc_mutex;
vfd->v4l2_dev = &dev->v4l2_dev;
- strlcpy(vfd->name, "vicodec-enc", sizeof(vfd->name));
+ strscpy(vfd->name, "vicodec-enc", sizeof(vfd->name));
v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD);
v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
video_set_drvdata(vfd, dev);
@@ -1395,7 +1327,7 @@ static int vicodec_probe(struct platform_device *pdev)
vfd = &dev->dec_vfd;
vfd->lock = &dev->dec_mutex;
vfd->v4l2_dev = &dev->v4l2_dev;
- strlcpy(vfd->name, "vicodec-dec", sizeof(vfd->name));
+ strscpy(vfd->name, "vicodec-dec", sizeof(vfd->name));
v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD);
v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD);
video_set_drvdata(vfd, dev);
diff --git a/drivers/media/platform/video-mux.c b/drivers/media/platform/video-mux.c
index c01e1592ad0a..c33900e3c23e 100644
--- a/drivers/media/platform/video-mux.c
+++ b/drivers/media/platform/video-mux.c
@@ -21,8 +21,10 @@
#include <linux/of.h>
#include <linux/of_graph.h>
#include <linux/platform_device.h>
+#include <linux/slab.h>
#include <media/v4l2-async.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
#include <media/v4l2-subdev.h>
struct video_mux {
@@ -316,6 +318,38 @@ static const struct v4l2_subdev_ops video_mux_subdev_ops = {
.video = &video_mux_subdev_video_ops,
};
+static int video_mux_parse_endpoint(struct device *dev,
+ struct v4l2_fwnode_endpoint *vep,
+ struct v4l2_async_subdev *asd)
+{
+ /*
+ * it's not an error if remote is missing on a video-mux
+ * input port, return -ENOTCONN to skip this endpoint with
+ * no error.
+ */
+ return fwnode_device_is_available(asd->match.fwnode) ? 0 : -ENOTCONN;
+}
+
+static int video_mux_async_register(struct video_mux *vmux,
+ unsigned int num_input_pads)
+{
+ unsigned int i, *ports;
+ int ret;
+
+ ports = kcalloc(num_input_pads, sizeof(*ports), GFP_KERNEL);
+ if (!ports)
+ return -ENOMEM;
+ for (i = 0; i < num_input_pads; i++)
+ ports[i] = i;
+
+ ret = v4l2_async_register_fwnode_subdev(
+ &vmux->subdev, sizeof(struct v4l2_async_subdev),
+ ports, num_input_pads, video_mux_parse_endpoint);
+
+ kfree(ports);
+ return ret;
+}
+
static int video_mux_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -333,7 +367,7 @@ static int video_mux_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, vmux);
v4l2_subdev_init(&vmux->subdev, &video_mux_subdev_ops);
- snprintf(vmux->subdev.name, sizeof(vmux->subdev.name), "%s", np->name);
+ snprintf(vmux->subdev.name, sizeof(vmux->subdev.name), "%pOFn", np);
vmux->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
vmux->subdev.dev = dev;
@@ -383,7 +417,7 @@ static int video_mux_probe(struct platform_device *pdev)
vmux->subdev.entity.ops = &video_mux_ops;
- return v4l2_async_register_subdev(&vmux->subdev);
+ return video_mux_async_register(vmux, num_pads - 1);
}
static int video_mux_remove(struct platform_device *pdev)
diff --git a/drivers/media/platform/vim2m.c b/drivers/media/platform/vim2m.c
index 462099a141e4..af150a0395df 100644
--- a/drivers/media/platform/vim2m.c
+++ b/drivers/media/platform/vim2m.c
@@ -3,7 +3,8 @@
*
* This is a virtual device driver for testing mem-to-mem videobuf framework.
* It simulates a device that uses memory buffers for both source and
- * destination, processes the data and issues an "irq" (simulated by a timer).
+ * destination, processes the data and issues an "irq" (simulated by a delayed
+ * workqueue).
* The device is capable of multi-instance, multi-buffer-per-transaction
* operation (via the mem2mem framework).
*
@@ -19,7 +20,6 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/fs.h>
-#include <linux/timer.h>
#include <linux/sched.h>
#include <linux/slab.h>
@@ -148,7 +148,7 @@ struct vim2m_dev {
struct mutex dev_mutex;
spinlock_t irqlock;
- struct timer_list timer;
+ struct delayed_work work_run;
struct v4l2_m2m_dev *m2m_dev;
};
@@ -336,12 +336,6 @@ static int device_process(struct vim2m_ctx *ctx,
return 0;
}
-static void schedule_irq(struct vim2m_dev *dev, int msec_timeout)
-{
- dprintk(dev, "Scheduling a simulated irq\n");
- mod_timer(&dev->timer, jiffies + msecs_to_jiffies(msec_timeout));
-}
-
/*
* mem2mem callbacks
*/
@@ -385,15 +379,24 @@ static void 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);
+ /* Apply request controls if any */
+ v4l2_ctrl_request_setup(src_buf->vb2_buf.req_obj.req,
+ &ctx->hdl);
+
device_process(ctx, src_buf, dst_buf);
- /* Run a timer, which simulates a hardware irq */
- schedule_irq(dev, ctx->transtime);
+ /* Complete request controls if any */
+ v4l2_ctrl_request_complete(src_buf->vb2_buf.req_obj.req,
+ &ctx->hdl);
+
+ /* Run delayed work, which simulates a hardware irq */
+ schedule_delayed_work(&dev->work_run, msecs_to_jiffies(ctx->transtime));
}
-static void device_isr(struct timer_list *t)
+static void device_work(struct work_struct *w)
{
- struct vim2m_dev *vim2m_dev = from_timer(vim2m_dev, t, timer);
+ struct vim2m_dev *vim2m_dev =
+ container_of(w, struct vim2m_dev, work_run.work);
struct vim2m_ctx *curr_ctx;
struct vb2_v4l2_buffer *src_vb, *dst_vb;
unsigned long flags;
@@ -805,6 +808,7 @@ static void vim2m_stop_streaming(struct vb2_queue *q)
struct vb2_v4l2_buffer *vbuf;
unsigned long flags;
+ flush_scheduled_work();
for (;;) {
if (V4L2_TYPE_IS_OUTPUT(q->type))
vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
@@ -812,12 +816,21 @@ static void vim2m_stop_streaming(struct vb2_queue *q)
vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
if (vbuf == NULL)
return;
+ v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req,
+ &ctx->hdl);
spin_lock_irqsave(&ctx->dev->irqlock, flags);
v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
spin_unlock_irqrestore(&ctx->dev->irqlock, flags);
}
}
+static void vim2m_buf_request_complete(struct vb2_buffer *vb)
+{
+ struct vim2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+ v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl);
+}
+
static const struct vb2_ops vim2m_qops = {
.queue_setup = vim2m_queue_setup,
.buf_prepare = vim2m_buf_prepare,
@@ -826,6 +839,7 @@ static const struct vb2_ops vim2m_qops = {
.stop_streaming = vim2m_stop_streaming,
.wait_prepare = vb2_ops_wait_prepare,
.wait_finish = vb2_ops_wait_finish,
+ .buf_request_complete = vim2m_buf_request_complete,
};
static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
@@ -841,6 +855,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *ds
src_vq->mem_ops = &vb2_vmalloc_memops;
src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
src_vq->lock = &ctx->dev->dev_mutex;
+ src_vq->supports_requests = true;
ret = vb2_queue_init(src_vq);
if (ret)
@@ -992,6 +1007,11 @@ static const struct v4l2_m2m_ops m2m_ops = {
.job_abort = job_abort,
};
+static const struct media_device_ops m2m_media_ops = {
+ .req_validate = vb2_request_validate,
+ .req_queue = vb2_m2m_request_queue,
+};
+
static int vim2m_probe(struct platform_device *pdev)
{
struct vim2m_dev *dev;
@@ -1015,6 +1035,7 @@ static int vim2m_probe(struct platform_device *pdev)
vfd = &dev->vfd;
vfd->lock = &dev->dev_mutex;
vfd->v4l2_dev = &dev->v4l2_dev;
+ INIT_DELAYED_WORK(&dev->work_run, device_work);
ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
if (ret) {
@@ -1026,7 +1047,6 @@ static int vim2m_probe(struct platform_device *pdev)
v4l2_info(&dev->v4l2_dev,
"Device registered as /dev/video%d\n", vfd->num);
- timer_setup(&dev->timer, device_isr, 0);
platform_set_drvdata(pdev, dev);
dev->m2m_dev = v4l2_m2m_init(&m2m_ops);
@@ -1038,8 +1058,9 @@ static int vim2m_probe(struct platform_device *pdev)
#ifdef CONFIG_MEDIA_CONTROLLER
dev->mdev.dev = &pdev->dev;
- strlcpy(dev->mdev.model, "vim2m", sizeof(dev->mdev.model));
+ strscpy(dev->mdev.model, "vim2m", sizeof(dev->mdev.model));
media_device_init(&dev->mdev);
+ dev->mdev.ops = &m2m_media_ops;
dev->v4l2_dev.mdev = &dev->mdev;
ret = v4l2_m2m_register_media_controller(dev->m2m_dev,
@@ -1083,7 +1104,6 @@ static int vim2m_remove(struct platform_device *pdev)
media_device_cleanup(&dev->mdev);
#endif
v4l2_m2m_release(dev->m2m_dev);
- del_timer_sync(&dev->timer);
video_unregister_device(&dev->vfd);
v4l2_device_unregister(&dev->v4l2_dev);
diff --git a/drivers/media/platform/vimc/vimc-capture.c b/drivers/media/platform/vimc/vimc-capture.c
index ec68feaac378..3f7e9ed56633 100644
--- a/drivers/media/platform/vimc/vimc-capture.c
+++ b/drivers/media/platform/vimc/vimc-capture.c
@@ -71,8 +71,8 @@ static int vimc_cap_querycap(struct file *file, void *priv,
{
struct vimc_cap_device *vcap = video_drvdata(file);
- strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
- strlcpy(cap->card, KBUILD_MODNAME, sizeof(cap->card));
+ strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
+ strscpy(cap->card, KBUILD_MODNAME, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info),
"platform:%s", vcap->vdev.v4l2_dev->name);
@@ -476,7 +476,7 @@ static int vimc_cap_comp_bind(struct device *comp, struct device *master,
vdev->queue = q;
vdev->v4l2_dev = v4l2_dev;
vdev->vfl_dir = VFL_DIR_RX;
- strlcpy(vdev->name, pdata->entity_name, sizeof(vdev->name));
+ strscpy(vdev->name, pdata->entity_name, sizeof(vdev->name));
video_set_drvdata(vdev, &vcap->ved);
/* Register the video_device with the v4l2 and the media framework */
diff --git a/drivers/media/platform/vimc/vimc-common.c b/drivers/media/platform/vimc/vimc-common.c
index 617415c224fe..dee1b9dfc4f6 100644
--- a/drivers/media/platform/vimc/vimc-common.c
+++ b/drivers/media/platform/vimc/vimc-common.c
@@ -430,7 +430,7 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved,
sd->entity.function = function;
sd->entity.ops = &vimc_ent_sd_mops;
sd->owner = THIS_MODULE;
- strlcpy(sd->name, name, sizeof(sd->name));
+ strscpy(sd->name, name, sizeof(sd->name));
v4l2_set_subdevdata(sd, ved);
/* Expose this subdev to user space */
diff --git a/drivers/media/platform/vimc/vimc-core.c b/drivers/media/platform/vimc/vimc-core.c
index 9246f265de31..ce809d2e3d53 100644
--- a/drivers/media/platform/vimc/vimc-core.c
+++ b/drivers/media/platform/vimc/vimc-core.c
@@ -259,7 +259,7 @@ static struct component_match *vimc_add_subdevs(struct vimc_device *vimc)
dev_dbg(&vimc->pdev.dev, "new pdev for %s\n",
vimc->pipe_cfg->ents[i].drv);
- strlcpy(pdata.entity_name, vimc->pipe_cfg->ents[i].name,
+ strscpy(pdata.entity_name, vimc->pipe_cfg->ents[i].name,
sizeof(pdata.entity_name));
vimc->subdevs[i] = platform_device_register_data(&vimc->pdev.dev,
@@ -317,7 +317,7 @@ static int vimc_probe(struct platform_device *pdev)
vimc->v4l2_dev.mdev = &vimc->mdev;
/* Initialize media device */
- strlcpy(vimc->mdev.model, VIMC_MDEV_MODEL_NAME,
+ strscpy(vimc->mdev.model, VIMC_MDEV_MODEL_NAME,
sizeof(vimc->mdev.model));
vimc->mdev.dev = &pdev->dev;
media_device_init(&vimc->mdev);
diff --git a/drivers/media/platform/vimc/vimc-sensor.c b/drivers/media/platform/vimc/vimc-sensor.c
index b2b89315e7ba..edf4c85ae63d 100644
--- a/drivers/media/platform/vimc/vimc-sensor.c
+++ b/drivers/media/platform/vimc/vimc-sensor.c
@@ -317,6 +317,18 @@ static int vimc_sen_s_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_VFLIP:
tpg_s_vflip(&vsen->tpg, ctrl->val);
break;
+ case V4L2_CID_BRIGHTNESS:
+ tpg_s_brightness(&vsen->tpg, ctrl->val);
+ break;
+ case V4L2_CID_CONTRAST:
+ tpg_s_contrast(&vsen->tpg, ctrl->val);
+ break;
+ case V4L2_CID_HUE:
+ tpg_s_hue(&vsen->tpg, ctrl->val);
+ break;
+ case V4L2_CID_SATURATION:
+ tpg_s_saturation(&vsen->tpg, ctrl->val);
+ break;
default:
return -EINVAL;
}
@@ -378,6 +390,14 @@ static int vimc_sen_comp_bind(struct device *comp, struct device *master,
V4L2_CID_VFLIP, 0, 1, 1, 0);
v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops,
V4L2_CID_HFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+ v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 255, 1, 128);
+ v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops,
+ V4L2_CID_HUE, -128, 127, 1, 0);
+ v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops,
+ V4L2_CID_SATURATION, 0, 255, 1, 128);
vsen->sd.ctrl_handler = &vsen->hdl;
if (vsen->hdl.error) {
ret = vsen->hdl.error;
diff --git a/drivers/media/platform/vivid/vivid-cec.c b/drivers/media/platform/vivid/vivid-cec.c
index 71105fa4c5f9..4d822dbed972 100644
--- a/drivers/media/platform/vivid/vivid-cec.c
+++ b/drivers/media/platform/vivid/vivid-cec.c
@@ -241,11 +241,11 @@ static int vivid_received(struct cec_adapter *adap, struct cec_msg *msg)
cec_ops_set_osd_string(msg, &disp_ctl, osd);
switch (disp_ctl) {
case CEC_OP_DISP_CTL_DEFAULT:
- strcpy(dev->osd, osd);
+ strscpy(dev->osd, osd, sizeof(dev->osd));
dev->osd_jiffies = jiffies;
break;
case CEC_OP_DISP_CTL_UNTIL_CLEARED:
- strcpy(dev->osd, osd);
+ strscpy(dev->osd, osd, sizeof(dev->osd));
dev->osd_jiffies = 0;
break;
case CEC_OP_DISP_CTL_CLEAR:
diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c
index 31db363602e5..626e2b24a403 100644
--- a/drivers/media/platform/vivid/vivid-core.c
+++ b/drivers/media/platform/vivid/vivid-core.c
@@ -197,8 +197,8 @@ static int vidioc_querycap(struct file *file, void *priv,
{
struct vivid_dev *dev = video_drvdata(file);
- strcpy(cap->driver, "vivid");
- strcpy(cap->card, "vivid");
+ strscpy(cap->driver, "vivid", sizeof(cap->driver));
+ strscpy(cap->card, "vivid", sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info),
"platform:%s", dev->v4l2_dev.name);
@@ -627,6 +627,13 @@ static void vivid_dev_release(struct v4l2_device *v4l2_dev)
kfree(dev);
}
+#ifdef CONFIG_MEDIA_CONTROLLER
+static const struct media_device_ops vivid_media_ops = {
+ .req_validate = vb2_request_validate,
+ .req_queue = vb2_request_queue,
+};
+#endif
+
static int vivid_create_instance(struct platform_device *pdev, int inst)
{
static const struct v4l2_dv_timings def_dv_timings =
@@ -657,6 +664,16 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
dev->inst = inst;
+#ifdef CONFIG_MEDIA_CONTROLLER
+ dev->v4l2_dev.mdev = &dev->mdev;
+
+ /* Initialize media device */
+ strlcpy(dev->mdev.model, VIVID_MODULE_NAME, sizeof(dev->mdev.model));
+ dev->mdev.dev = &pdev->dev;
+ media_device_init(&dev->mdev);
+ dev->mdev.ops = &vivid_media_ops;
+#endif
+
/* register v4l2_device */
snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
"%s-%03d", VIVID_MODULE_NAME, inst);
@@ -1060,6 +1077,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
q->min_buffers_needed = 2;
q->lock = &dev->mutex;
q->dev = dev->v4l2_dev.dev;
+ q->supports_requests = true;
ret = vb2_queue_init(q);
if (ret)
@@ -1080,6 +1098,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
q->min_buffers_needed = 2;
q->lock = &dev->mutex;
q->dev = dev->v4l2_dev.dev;
+ q->supports_requests = true;
ret = vb2_queue_init(q);
if (ret)
@@ -1100,6 +1119,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
q->min_buffers_needed = 2;
q->lock = &dev->mutex;
q->dev = dev->v4l2_dev.dev;
+ q->supports_requests = true;
ret = vb2_queue_init(q);
if (ret)
@@ -1120,6 +1140,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
q->min_buffers_needed = 2;
q->lock = &dev->mutex;
q->dev = dev->v4l2_dev.dev;
+ q->supports_requests = true;
ret = vb2_queue_init(q);
if (ret)
@@ -1139,6 +1160,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
q->min_buffers_needed = 8;
q->lock = &dev->mutex;
q->dev = dev->v4l2_dev.dev;
+ q->supports_requests = true;
ret = vb2_queue_init(q);
if (ret)
@@ -1174,6 +1196,13 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
vfd->lock = &dev->mutex;
video_set_drvdata(vfd, dev);
+#ifdef CONFIG_MEDIA_CONTROLLER
+ dev->vid_cap_pad.flags = MEDIA_PAD_FL_SINK;
+ ret = media_entity_pads_init(&vfd->entity, 1, &dev->vid_cap_pad);
+ if (ret)
+ goto unreg_dev;
+#endif
+
#ifdef CONFIG_VIDEO_VIVID_CEC
if (in_type_counter[HDMI]) {
struct cec_adapter *adap;
@@ -1226,6 +1255,13 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
vfd->lock = &dev->mutex;
video_set_drvdata(vfd, dev);
+#ifdef CONFIG_MEDIA_CONTROLLER
+ dev->vid_out_pad.flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_pads_init(&vfd->entity, 1, &dev->vid_out_pad);
+ if (ret)
+ goto unreg_dev;
+#endif
+
#ifdef CONFIG_VIDEO_VIVID_CEC
for (i = 0; i < dev->num_outputs; i++) {
struct cec_adapter *adap;
@@ -1275,6 +1311,13 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
vfd->tvnorms = tvnorms_cap;
video_set_drvdata(vfd, dev);
+#ifdef CONFIG_MEDIA_CONTROLLER
+ dev->vbi_cap_pad.flags = MEDIA_PAD_FL_SINK;
+ ret = media_entity_pads_init(&vfd->entity, 1, &dev->vbi_cap_pad);
+ if (ret)
+ goto unreg_dev;
+#endif
+
ret = video_register_device(vfd, VFL_TYPE_VBI, vbi_cap_nr[inst]);
if (ret < 0)
goto unreg_dev;
@@ -1300,6 +1343,13 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
vfd->tvnorms = tvnorms_out;
video_set_drvdata(vfd, dev);
+#ifdef CONFIG_MEDIA_CONTROLLER
+ dev->vbi_out_pad.flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_pads_init(&vfd->entity, 1, &dev->vbi_out_pad);
+ if (ret)
+ goto unreg_dev;
+#endif
+
ret = video_register_device(vfd, VFL_TYPE_VBI, vbi_out_nr[inst]);
if (ret < 0)
goto unreg_dev;
@@ -1323,6 +1373,13 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
vfd->lock = &dev->mutex;
video_set_drvdata(vfd, dev);
+#ifdef CONFIG_MEDIA_CONTROLLER
+ dev->sdr_cap_pad.flags = MEDIA_PAD_FL_SINK;
+ ret = media_entity_pads_init(&vfd->entity, 1, &dev->sdr_cap_pad);
+ if (ret)
+ goto unreg_dev;
+#endif
+
ret = video_register_device(vfd, VFL_TYPE_SDR, sdr_cap_nr[inst]);
if (ret < 0)
goto unreg_dev;
@@ -1369,12 +1426,25 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
video_device_node_name(vfd));
}
+#ifdef CONFIG_MEDIA_CONTROLLER
+ /* Register the media device */
+ ret = media_device_register(&dev->mdev);
+ if (ret) {
+ dev_err(dev->mdev.dev,
+ "media device register failed (err=%d)\n", ret);
+ goto unreg_dev;
+ }
+#endif
+
/* Now that everything is fine, let's add it to device list */
vivid_devs[inst] = dev;
return 0;
unreg_dev:
+#ifdef CONFIG_MEDIA_CONTROLLER
+ media_device_unregister(&dev->mdev);
+#endif
video_unregister_device(&dev->radio_tx_dev);
video_unregister_device(&dev->radio_rx_dev);
video_unregister_device(&dev->sdr_cap_dev);
@@ -1445,6 +1515,10 @@ static int vivid_remove(struct platform_device *pdev)
if (!dev)
continue;
+#ifdef CONFIG_MEDIA_CONTROLLER
+ media_device_unregister(&dev->mdev);
+#endif
+
if (dev->has_vid_cap) {
v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
video_device_node_name(&dev->vid_cap_dev));
diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h
index 477c80a4d44c..1891254c8f0b 100644
--- a/drivers/media/platform/vivid/vivid-core.h
+++ b/drivers/media/platform/vivid/vivid-core.h
@@ -111,7 +111,7 @@ enum vivid_colorspace {
VIVID_CS_170M,
VIVID_CS_709,
VIVID_CS_SRGB,
- VIVID_CS_ADOBERGB,
+ VIVID_CS_OPRGB,
VIVID_CS_2020,
VIVID_CS_DCI_P3,
VIVID_CS_240M,
@@ -136,6 +136,14 @@ struct vivid_cec_work {
struct vivid_dev {
unsigned inst;
struct v4l2_device v4l2_dev;
+#ifdef CONFIG_MEDIA_CONTROLLER
+ struct media_device mdev;
+ struct media_pad vid_cap_pad;
+ struct media_pad vid_out_pad;
+ struct media_pad vbi_cap_pad;
+ struct media_pad vbi_out_pad;
+ struct media_pad sdr_cap_pad;
+#endif
struct v4l2_ctrl_handler ctrl_hdl_user_gen;
struct v4l2_ctrl_handler ctrl_hdl_user_vid;
struct v4l2_ctrl_handler ctrl_hdl_user_aud;
diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c
index 5429193fbb91..bfffeda12f14 100644
--- a/drivers/media/platform/vivid/vivid-ctrls.c
+++ b/drivers/media/platform/vivid/vivid-ctrls.c
@@ -348,7 +348,7 @@ static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl)
V4L2_COLORSPACE_SMPTE170M,
V4L2_COLORSPACE_REC709,
V4L2_COLORSPACE_SRGB,
- V4L2_COLORSPACE_ADOBERGB,
+ V4L2_COLORSPACE_OPRGB,
V4L2_COLORSPACE_BT2020,
V4L2_COLORSPACE_DCI_P3,
V4L2_COLORSPACE_SMPTE240M,
@@ -729,7 +729,7 @@ static const char * const vivid_ctrl_colorspace_strings[] = {
"SMPTE 170M",
"Rec. 709",
"sRGB",
- "AdobeRGB",
+ "opRGB",
"BT.2020",
"DCI-P3",
"SMPTE 240M",
@@ -752,7 +752,7 @@ static const char * const vivid_ctrl_xfer_func_strings[] = {
"Default",
"Rec. 709",
"sRGB",
- "AdobeRGB",
+ "opRGB",
"SMPTE 240M",
"None",
"DCI-P3",
@@ -1662,59 +1662,59 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
v4l2_ctrl_auto_cluster(2, &dev->autogain, 0, true);
if (dev->has_vid_cap) {
- v4l2_ctrl_add_handler(hdl_vid_cap, hdl_user_gen, NULL);
- v4l2_ctrl_add_handler(hdl_vid_cap, hdl_user_vid, NULL);
- v4l2_ctrl_add_handler(hdl_vid_cap, hdl_user_aud, NULL);
- v4l2_ctrl_add_handler(hdl_vid_cap, hdl_streaming, NULL);
- v4l2_ctrl_add_handler(hdl_vid_cap, hdl_sdtv_cap, NULL);
- v4l2_ctrl_add_handler(hdl_vid_cap, hdl_loop_cap, NULL);
- v4l2_ctrl_add_handler(hdl_vid_cap, hdl_fb, NULL);
+ v4l2_ctrl_add_handler(hdl_vid_cap, hdl_user_gen, NULL, false);
+ v4l2_ctrl_add_handler(hdl_vid_cap, hdl_user_vid, NULL, false);
+ v4l2_ctrl_add_handler(hdl_vid_cap, hdl_user_aud, NULL, false);
+ v4l2_ctrl_add_handler(hdl_vid_cap, hdl_streaming, NULL, false);
+ v4l2_ctrl_add_handler(hdl_vid_cap, hdl_sdtv_cap, NULL, false);
+ v4l2_ctrl_add_handler(hdl_vid_cap, hdl_loop_cap, NULL, false);
+ v4l2_ctrl_add_handler(hdl_vid_cap, hdl_fb, NULL, false);
if (hdl_vid_cap->error)
return hdl_vid_cap->error;
dev->vid_cap_dev.ctrl_handler = hdl_vid_cap;
}
if (dev->has_vid_out) {
- v4l2_ctrl_add_handler(hdl_vid_out, hdl_user_gen, NULL);
- v4l2_ctrl_add_handler(hdl_vid_out, hdl_user_aud, NULL);
- v4l2_ctrl_add_handler(hdl_vid_out, hdl_streaming, NULL);
- v4l2_ctrl_add_handler(hdl_vid_out, hdl_fb, NULL);
+ v4l2_ctrl_add_handler(hdl_vid_out, hdl_user_gen, NULL, false);
+ v4l2_ctrl_add_handler(hdl_vid_out, hdl_user_aud, NULL, false);
+ v4l2_ctrl_add_handler(hdl_vid_out, hdl_streaming, NULL, false);
+ v4l2_ctrl_add_handler(hdl_vid_out, hdl_fb, NULL, false);
if (hdl_vid_out->error)
return hdl_vid_out->error;
dev->vid_out_dev.ctrl_handler = hdl_vid_out;
}
if (dev->has_vbi_cap) {
- v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_user_gen, NULL);
- v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_streaming, NULL);
- v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_sdtv_cap, NULL);
- v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_loop_cap, NULL);
+ v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_user_gen, NULL, false);
+ v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_streaming, NULL, false);
+ v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_sdtv_cap, NULL, false);
+ v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_loop_cap, NULL, false);
if (hdl_vbi_cap->error)
return hdl_vbi_cap->error;
dev->vbi_cap_dev.ctrl_handler = hdl_vbi_cap;
}
if (dev->has_vbi_out) {
- v4l2_ctrl_add_handler(hdl_vbi_out, hdl_user_gen, NULL);
- v4l2_ctrl_add_handler(hdl_vbi_out, hdl_streaming, NULL);
+ v4l2_ctrl_add_handler(hdl_vbi_out, hdl_user_gen, NULL, false);
+ v4l2_ctrl_add_handler(hdl_vbi_out, hdl_streaming, NULL, false);
if (hdl_vbi_out->error)
return hdl_vbi_out->error;
dev->vbi_out_dev.ctrl_handler = hdl_vbi_out;
}
if (dev->has_radio_rx) {
- v4l2_ctrl_add_handler(hdl_radio_rx, hdl_user_gen, NULL);
- v4l2_ctrl_add_handler(hdl_radio_rx, hdl_user_aud, NULL);
+ v4l2_ctrl_add_handler(hdl_radio_rx, hdl_user_gen, NULL, false);
+ v4l2_ctrl_add_handler(hdl_radio_rx, hdl_user_aud, NULL, false);
if (hdl_radio_rx->error)
return hdl_radio_rx->error;
dev->radio_rx_dev.ctrl_handler = hdl_radio_rx;
}
if (dev->has_radio_tx) {
- v4l2_ctrl_add_handler(hdl_radio_tx, hdl_user_gen, NULL);
- v4l2_ctrl_add_handler(hdl_radio_tx, hdl_user_aud, NULL);
+ v4l2_ctrl_add_handler(hdl_radio_tx, hdl_user_gen, NULL, false);
+ v4l2_ctrl_add_handler(hdl_radio_tx, hdl_user_aud, NULL, false);
if (hdl_radio_tx->error)
return hdl_radio_tx->error;
dev->radio_tx_dev.ctrl_handler = hdl_radio_tx;
}
if (dev->has_sdr_cap) {
- v4l2_ctrl_add_handler(hdl_sdr_cap, hdl_user_gen, NULL);
- v4l2_ctrl_add_handler(hdl_sdr_cap, hdl_streaming, NULL);
+ v4l2_ctrl_add_handler(hdl_sdr_cap, hdl_user_gen, NULL, false);
+ v4l2_ctrl_add_handler(hdl_sdr_cap, hdl_streaming, NULL, false);
if (hdl_sdr_cap->error)
return hdl_sdr_cap->error;
dev->sdr_cap_dev.ctrl_handler = hdl_sdr_cap;
diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.c b/drivers/media/platform/vivid/vivid-kthread-cap.c
index f06003bb8e42..eebfff2126be 100644
--- a/drivers/media/platform/vivid/vivid-kthread-cap.c
+++ b/drivers/media/platform/vivid/vivid-kthread-cap.c
@@ -703,6 +703,8 @@ static void vivid_thread_vid_cap_tick(struct vivid_dev *dev, int dropped_bufs)
goto update_mv;
if (vid_cap_buf) {
+ v4l2_ctrl_request_setup(vid_cap_buf->vb.vb2_buf.req_obj.req,
+ &dev->ctrl_hdl_vid_cap);
/* Fill buffer */
vivid_fillbuff(dev, vid_cap_buf);
dprintk(dev, 1, "filled buffer %d\n",
@@ -713,6 +715,8 @@ static void vivid_thread_vid_cap_tick(struct vivid_dev *dev, int dropped_bufs)
dev->fb_cap.fmt.pixelformat == dev->fmt_cap->fourcc)
vivid_overlay(dev, vid_cap_buf);
+ v4l2_ctrl_request_complete(vid_cap_buf->vb.vb2_buf.req_obj.req,
+ &dev->ctrl_hdl_vid_cap);
vb2_buffer_done(&vid_cap_buf->vb.vb2_buf, dev->dqbuf_error ?
VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
dprintk(dev, 2, "vid_cap buffer %d done\n",
@@ -720,10 +724,14 @@ static void vivid_thread_vid_cap_tick(struct vivid_dev *dev, int dropped_bufs)
}
if (vbi_cap_buf) {
+ v4l2_ctrl_request_setup(vbi_cap_buf->vb.vb2_buf.req_obj.req,
+ &dev->ctrl_hdl_vbi_cap);
if (dev->stream_sliced_vbi_cap)
vivid_sliced_vbi_cap_process(dev, vbi_cap_buf);
else
vivid_raw_vbi_cap_process(dev, vbi_cap_buf);
+ v4l2_ctrl_request_complete(vbi_cap_buf->vb.vb2_buf.req_obj.req,
+ &dev->ctrl_hdl_vbi_cap);
vb2_buffer_done(&vbi_cap_buf->vb.vb2_buf, dev->dqbuf_error ?
VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
dprintk(dev, 2, "vbi_cap %d done\n",
@@ -891,6 +899,8 @@ void vivid_stop_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming)
buf = list_entry(dev->vid_cap_active.next,
struct vivid_buffer, list);
list_del(&buf->list);
+ v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req,
+ &dev->ctrl_hdl_vid_cap);
vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
dprintk(dev, 2, "vid_cap buffer %d done\n",
buf->vb.vb2_buf.index);
@@ -904,6 +914,8 @@ void vivid_stop_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming)
buf = list_entry(dev->vbi_cap_active.next,
struct vivid_buffer, list);
list_del(&buf->list);
+ v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req,
+ &dev->ctrl_hdl_vbi_cap);
vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
dprintk(dev, 2, "vbi_cap buffer %d done\n",
buf->vb.vb2_buf.index);
diff --git a/drivers/media/platform/vivid/vivid-kthread-out.c b/drivers/media/platform/vivid/vivid-kthread-out.c
index 9981e7548019..5a14810eeb69 100644
--- a/drivers/media/platform/vivid/vivid-kthread-out.c
+++ b/drivers/media/platform/vivid/vivid-kthread-out.c
@@ -75,6 +75,10 @@ static void vivid_thread_vid_out_tick(struct vivid_dev *dev)
return;
if (vid_out_buf) {
+ v4l2_ctrl_request_setup(vid_out_buf->vb.vb2_buf.req_obj.req,
+ &dev->ctrl_hdl_vid_out);
+ v4l2_ctrl_request_complete(vid_out_buf->vb.vb2_buf.req_obj.req,
+ &dev->ctrl_hdl_vid_out);
vid_out_buf->vb.sequence = dev->vid_out_seq_count;
if (dev->field_out == V4L2_FIELD_ALTERNATE) {
/*
@@ -92,6 +96,10 @@ static void vivid_thread_vid_out_tick(struct vivid_dev *dev)
}
if (vbi_out_buf) {
+ v4l2_ctrl_request_setup(vbi_out_buf->vb.vb2_buf.req_obj.req,
+ &dev->ctrl_hdl_vbi_out);
+ v4l2_ctrl_request_complete(vbi_out_buf->vb.vb2_buf.req_obj.req,
+ &dev->ctrl_hdl_vbi_out);
if (dev->stream_sliced_vbi_out)
vivid_sliced_vbi_out_process(dev, vbi_out_buf);
@@ -262,6 +270,8 @@ void vivid_stop_generating_vid_out(struct vivid_dev *dev, bool *pstreaming)
buf = list_entry(dev->vid_out_active.next,
struct vivid_buffer, list);
list_del(&buf->list);
+ v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req,
+ &dev->ctrl_hdl_vid_out);
vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
dprintk(dev, 2, "vid_out buffer %d done\n",
buf->vb.vb2_buf.index);
@@ -275,6 +285,8 @@ void vivid_stop_generating_vid_out(struct vivid_dev *dev, bool *pstreaming)
buf = list_entry(dev->vbi_out_active.next,
struct vivid_buffer, list);
list_del(&buf->list);
+ v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req,
+ &dev->ctrl_hdl_vbi_out);
vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
dprintk(dev, 2, "vbi_out buffer %d done\n",
buf->vb.vb2_buf.index);
diff --git a/drivers/media/platform/vivid/vivid-osd.c b/drivers/media/platform/vivid/vivid-osd.c
index bbbc1b6938a5..1a89593b0c86 100644
--- a/drivers/media/platform/vivid/vivid-osd.c
+++ b/drivers/media/platform/vivid/vivid-osd.c
@@ -110,7 +110,7 @@ static int vivid_fb_get_fix(struct vivid_dev *dev, struct fb_fix_screeninfo *fix
{
dprintk(dev, 1, "vivid_fb_get_fix\n");
memset(fix, 0, sizeof(struct fb_fix_screeninfo));
- strlcpy(fix->id, "vioverlay fb", sizeof(fix->id));
+ strscpy(fix->id, "vioverlay fb", sizeof(fix->id));
fix->smem_start = dev->video_pbase;
fix->smem_len = dev->video_buffer_size;
fix->type = FB_TYPE_PACKED_PIXELS;
diff --git a/drivers/media/platform/vivid/vivid-radio-common.c b/drivers/media/platform/vivid/vivid-radio-common.c
index 7c8efe38ff5b..138c7bce68b1 100644
--- a/drivers/media/platform/vivid/vivid-radio-common.c
+++ b/drivers/media/platform/vivid/vivid-radio-common.c
@@ -76,10 +76,10 @@ void vivid_radio_rds_init(struct vivid_dev *dev)
rds->ta = dev->radio_tx_rds_ta->cur.val;
rds->tp = dev->radio_tx_rds_tp->cur.val;
rds->ms = dev->radio_tx_rds_ms->cur.val;
- strlcpy(rds->psname,
+ strscpy(rds->psname,
dev->radio_tx_rds_psname->p_cur.p_char,
sizeof(rds->psname));
- strlcpy(rds->radiotext,
+ strscpy(rds->radiotext,
dev->radio_tx_rds_radiotext->p_cur.p_char + alt * 64,
sizeof(rds->radiotext));
v4l2_ctrl_unlock(dev->radio_tx_rds_pi);
diff --git a/drivers/media/platform/vivid/vivid-radio-rx.c b/drivers/media/platform/vivid/vivid-radio-rx.c
index 1f86d7d4f72f..232cab508f48 100644
--- a/drivers/media/platform/vivid/vivid-radio-rx.c
+++ b/drivers/media/platform/vivid/vivid-radio-rx.c
@@ -223,7 +223,7 @@ int vivid_radio_rx_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
if (vt->index > 0)
return -EINVAL;
- strlcpy(vt->name, "AM/FM/SW Receiver", sizeof(vt->name));
+ strscpy(vt->name, "AM/FM/SW Receiver", sizeof(vt->name));
vt->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
V4L2_TUNER_CAP_FREQ_BANDS | V4L2_TUNER_CAP_RDS |
(dev->radio_rx_rds_controls ?
diff --git a/drivers/media/platform/vivid/vivid-radio-tx.c b/drivers/media/platform/vivid/vivid-radio-tx.c
index 1a3749ba5e7e..049d40b948bb 100644
--- a/drivers/media/platform/vivid/vivid-radio-tx.c
+++ b/drivers/media/platform/vivid/vivid-radio-tx.c
@@ -103,7 +103,7 @@ int vidioc_g_modulator(struct file *file, void *fh, struct v4l2_modulator *a)
if (a->index > 0)
return -EINVAL;
- strlcpy(a->name, "AM/FM/SW Transmitter", sizeof(a->name));
+ strscpy(a->name, "AM/FM/SW Transmitter", sizeof(a->name));
a->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
V4L2_TUNER_CAP_FREQ_BANDS | V4L2_TUNER_CAP_RDS |
(dev->radio_tx_rds_controls ?
diff --git a/drivers/media/platform/vivid/vivid-rds-gen.c b/drivers/media/platform/vivid/vivid-rds-gen.c
index 39ca9a56448c..b5b104ee64c9 100644
--- a/drivers/media/platform/vivid/vivid-rds-gen.c
+++ b/drivers/media/platform/vivid/vivid-rds-gen.c
@@ -147,11 +147,11 @@ void vivid_rds_gen_fill(struct vivid_rds_gen *rds, unsigned freq,
snprintf(rds->psname, sizeof(rds->psname), "%6d.%1d",
freq / 16, ((freq & 0xf) * 10) / 16);
if (alt)
- strlcpy(rds->radiotext,
+ strscpy(rds->radiotext,
" The Radio Data System can switch between different Radio Texts ",
sizeof(rds->radiotext));
else
- strlcpy(rds->radiotext,
+ strscpy(rds->radiotext,
"An example of Radio Text as transmitted by the Radio Data System",
sizeof(rds->radiotext));
}
diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.c b/drivers/media/platform/vivid/vivid-sdr-cap.c
index cfb7cb4d37a8..dcdc80e272c2 100644
--- a/drivers/media/platform/vivid/vivid-sdr-cap.c
+++ b/drivers/media/platform/vivid/vivid-sdr-cap.c
@@ -102,6 +102,10 @@ static void vivid_thread_sdr_cap_tick(struct vivid_dev *dev)
if (sdr_cap_buf) {
sdr_cap_buf->vb.sequence = dev->sdr_cap_seq_count;
+ v4l2_ctrl_request_setup(sdr_cap_buf->vb.vb2_buf.req_obj.req,
+ &dev->ctrl_hdl_sdr_cap);
+ v4l2_ctrl_request_complete(sdr_cap_buf->vb.vb2_buf.req_obj.req,
+ &dev->ctrl_hdl_sdr_cap);
vivid_sdr_cap_process(dev, sdr_cap_buf);
sdr_cap_buf->vb.vb2_buf.timestamp =
ktime_get_ns() + dev->time_wrap_offset;
@@ -272,6 +276,8 @@ static int sdr_cap_start_streaming(struct vb2_queue *vq, unsigned count)
list_for_each_entry_safe(buf, tmp, &dev->sdr_cap_active, list) {
list_del(&buf->list);
+ v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req,
+ &dev->ctrl_hdl_sdr_cap);
vb2_buffer_done(&buf->vb.vb2_buf,
VB2_BUF_STATE_QUEUED);
}
@@ -293,6 +299,8 @@ static void sdr_cap_stop_streaming(struct vb2_queue *vq)
buf = list_entry(dev->sdr_cap_active.next,
struct vivid_buffer, list);
list_del(&buf->list);
+ v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req,
+ &dev->ctrl_hdl_sdr_cap);
vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
}
@@ -303,12 +311,20 @@ static void sdr_cap_stop_streaming(struct vb2_queue *vq)
mutex_lock(&dev->mutex);
}
+static void sdr_cap_buf_request_complete(struct vb2_buffer *vb)
+{
+ struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+
+ v4l2_ctrl_request_complete(vb->req_obj.req, &dev->ctrl_hdl_sdr_cap);
+}
+
const struct vb2_ops vivid_sdr_cap_qops = {
.queue_setup = sdr_cap_queue_setup,
.buf_prepare = sdr_cap_buf_prepare,
.buf_queue = sdr_cap_buf_queue,
.start_streaming = sdr_cap_start_streaming,
.stop_streaming = sdr_cap_stop_streaming,
+ .buf_request_complete = sdr_cap_buf_request_complete,
.wait_prepare = vb2_ops_wait_prepare,
.wait_finish = vb2_ops_wait_finish,
};
@@ -396,7 +412,7 @@ int vivid_sdr_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
{
switch (vt->index) {
case 0:
- strlcpy(vt->name, "ADC", sizeof(vt->name));
+ strscpy(vt->name, "ADC", sizeof(vt->name));
vt->type = V4L2_TUNER_ADC;
vt->capability =
V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
@@ -404,7 +420,7 @@ int vivid_sdr_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
vt->rangehigh = bands_adc[2].rangehigh;
return 0;
case 1:
- strlcpy(vt->name, "RF", sizeof(vt->name));
+ strscpy(vt->name, "RF", sizeof(vt->name));
vt->type = V4L2_TUNER_RF;
vt->capability =
V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
diff --git a/drivers/media/platform/vivid/vivid-vbi-cap.c b/drivers/media/platform/vivid/vivid-vbi-cap.c
index 92a852955173..903cebeb5ce5 100644
--- a/drivers/media/platform/vivid/vivid-vbi-cap.c
+++ b/drivers/media/platform/vivid/vivid-vbi-cap.c
@@ -204,6 +204,8 @@ static int vbi_cap_start_streaming(struct vb2_queue *vq, unsigned count)
list_for_each_entry_safe(buf, tmp, &dev->vbi_cap_active, list) {
list_del(&buf->list);
+ v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req,
+ &dev->ctrl_hdl_vbi_cap);
vb2_buffer_done(&buf->vb.vb2_buf,
VB2_BUF_STATE_QUEUED);
}
@@ -220,12 +222,20 @@ static void vbi_cap_stop_streaming(struct vb2_queue *vq)
vivid_stop_generating_vid_cap(dev, &dev->vbi_cap_streaming);
}
+static void vbi_cap_buf_request_complete(struct vb2_buffer *vb)
+{
+ struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+
+ v4l2_ctrl_request_complete(vb->req_obj.req, &dev->ctrl_hdl_vbi_cap);
+}
+
const struct vb2_ops vivid_vbi_cap_qops = {
.queue_setup = vbi_cap_queue_setup,
.buf_prepare = vbi_cap_buf_prepare,
.buf_queue = vbi_cap_buf_queue,
.start_streaming = vbi_cap_start_streaming,
.stop_streaming = vbi_cap_stop_streaming,
+ .buf_request_complete = vbi_cap_buf_request_complete,
.wait_prepare = vb2_ops_wait_prepare,
.wait_finish = vb2_ops_wait_finish,
};
diff --git a/drivers/media/platform/vivid/vivid-vbi-out.c b/drivers/media/platform/vivid/vivid-vbi-out.c
index 69486c130a7e..9357c07e30d6 100644
--- a/drivers/media/platform/vivid/vivid-vbi-out.c
+++ b/drivers/media/platform/vivid/vivid-vbi-out.c
@@ -96,6 +96,8 @@ static int vbi_out_start_streaming(struct vb2_queue *vq, unsigned count)
list_for_each_entry_safe(buf, tmp, &dev->vbi_out_active, list) {
list_del(&buf->list);
+ v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req,
+ &dev->ctrl_hdl_vbi_out);
vb2_buffer_done(&buf->vb.vb2_buf,
VB2_BUF_STATE_QUEUED);
}
@@ -115,12 +117,20 @@ static void vbi_out_stop_streaming(struct vb2_queue *vq)
dev->vbi_out_have_cc[1] = false;
}
+static void vbi_out_buf_request_complete(struct vb2_buffer *vb)
+{
+ struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+
+ v4l2_ctrl_request_complete(vb->req_obj.req, &dev->ctrl_hdl_vbi_out);
+}
+
const struct vb2_ops vivid_vbi_out_qops = {
.queue_setup = vbi_out_queue_setup,
.buf_prepare = vbi_out_buf_prepare,
.buf_queue = vbi_out_buf_queue,
.start_streaming = vbi_out_start_streaming,
.stop_streaming = vbi_out_stop_streaming,
+ .buf_request_complete = vbi_out_buf_request_complete,
.wait_prepare = vb2_ops_wait_prepare,
.wait_finish = vb2_ops_wait_finish,
};
diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c
index 1599159f2574..9c8e8be81ce3 100644
--- a/drivers/media/platform/vivid/vivid-vid-cap.c
+++ b/drivers/media/platform/vivid/vivid-vid-cap.c
@@ -51,7 +51,7 @@ static const struct vivid_fmt formats_ovl[] = {
};
/* The number of discrete webcam framesizes */
-#define VIVID_WEBCAM_SIZES 5
+#define VIVID_WEBCAM_SIZES 6
/* The number of discrete webcam frameintervals */
#define VIVID_WEBCAM_IVALS (VIVID_WEBCAM_SIZES * 2)
@@ -59,6 +59,7 @@ static const struct vivid_fmt formats_ovl[] = {
static const struct v4l2_frmsize_discrete webcam_sizes[VIVID_WEBCAM_SIZES] = {
{ 320, 180 },
{ 640, 360 },
+ { 640, 480 },
{ 1280, 720 },
{ 1920, 1080 },
{ 3840, 2160 },
@@ -74,9 +75,11 @@ static const struct v4l2_fract webcam_intervals[VIVID_WEBCAM_IVALS] = {
{ 1, 4 },
{ 1, 5 },
{ 1, 10 },
+ { 2, 25 },
{ 1, 15 },
{ 1, 25 },
{ 1, 30 },
+ { 1, 40 },
{ 1, 50 },
{ 1, 60 },
};
@@ -240,6 +243,8 @@ static int vid_cap_start_streaming(struct vb2_queue *vq, unsigned count)
list_for_each_entry_safe(buf, tmp, &dev->vid_cap_active, list) {
list_del(&buf->list);
+ v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req,
+ &dev->ctrl_hdl_vid_cap);
vb2_buffer_done(&buf->vb.vb2_buf,
VB2_BUF_STATE_QUEUED);
}
@@ -257,6 +262,13 @@ static void vid_cap_stop_streaming(struct vb2_queue *vq)
dev->can_loop_video = false;
}
+static void vid_cap_buf_request_complete(struct vb2_buffer *vb)
+{
+ struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+
+ v4l2_ctrl_request_complete(vb->req_obj.req, &dev->ctrl_hdl_vid_cap);
+}
+
const struct vb2_ops vivid_vid_cap_qops = {
.queue_setup = vid_cap_queue_setup,
.buf_prepare = vid_cap_buf_prepare,
@@ -264,6 +276,7 @@ const struct vb2_ops vivid_vid_cap_qops = {
.buf_queue = vid_cap_buf_queue,
.start_streaming = vid_cap_start_streaming,
.stop_streaming = vid_cap_stop_streaming,
+ .buf_request_complete = vid_cap_buf_request_complete,
.wait_prepare = vb2_ops_wait_prepare,
.wait_finish = vb2_ops_wait_finish,
};
@@ -1505,7 +1518,7 @@ int vivid_video_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
break;
}
}
- strlcpy(vt->name, "TV Tuner", sizeof(vt->name));
+ strscpy(vt->name, "TV Tuner", sizeof(vt->name));
return 0;
}
@@ -1722,7 +1735,7 @@ int vidioc_s_edid(struct file *file, void *_fh,
return -E2BIG;
}
phys_addr = cec_get_edid_phys_addr(edid->edid, edid->blocks * 128, NULL);
- ret = cec_phys_addr_validate(phys_addr, &phys_addr, NULL);
+ ret = v4l2_phys_addr_validate(phys_addr, &phys_addr, NULL);
if (ret)
return ret;
@@ -1738,7 +1751,7 @@ set_phys_addr:
for (i = 0; i < MAX_OUTPUTS && dev->cec_tx_adap[i]; i++)
cec_s_phys_addr(dev->cec_tx_adap[i],
- cec_phys_addr_for_input(phys_addr, i + 1),
+ v4l2_phys_addr_for_input(phys_addr, i + 1),
false);
return 0;
}
diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c
index be531caa2cdf..9645a91b8782 100644
--- a/drivers/media/platform/vivid/vivid-vid-common.c
+++ b/drivers/media/platform/vivid/vivid-vid-common.c
@@ -450,6 +450,34 @@ struct vivid_fmt vivid_formats[] = {
.buffers = 1,
},
{
+ .fourcc = V4L2_PIX_FMT_SBGGR16, /* Bayer BG/GR */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
+ .planes = 1,
+ .buffers = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGBRG16, /* Bayer GB/RG */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
+ .planes = 1,
+ .buffers = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGRBG16, /* Bayer GR/BG */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
+ .planes = 1,
+ .buffers = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SRGGB16, /* Bayer RG/GB */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
+ .planes = 1,
+ .buffers = 1,
+ },
+ {
.fourcc = V4L2_PIX_FMT_HSV24, /* HSV 24bits */
.color_enc = TGP_COLOR_ENC_HSV,
.vdownsampling = { 1 },
@@ -863,7 +891,7 @@ int vidioc_g_edid(struct file *file, void *_fh,
if (edid->blocks > dev->edid_blocks - edid->start_block)
edid->blocks = dev->edid_blocks - edid->start_block;
if (adap)
- cec_set_edid_phys_addr(dev->edid, dev->edid_blocks * 128, adap->phys_addr);
+ v4l2_set_edid_phys_addr(dev->edid, dev->edid_blocks * 128, adap->phys_addr);
memcpy(edid->edid, dev->edid + edid->start_block * 128, edid->blocks * 128);
return 0;
}
diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c
index 51fec66d8d45..aaf13f03d5d4 100644
--- a/drivers/media/platform/vivid/vivid-vid-out.c
+++ b/drivers/media/platform/vivid/vivid-vid-out.c
@@ -162,6 +162,8 @@ static int vid_out_start_streaming(struct vb2_queue *vq, unsigned count)
list_for_each_entry_safe(buf, tmp, &dev->vid_out_active, list) {
list_del(&buf->list);
+ v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req,
+ &dev->ctrl_hdl_vid_out);
vb2_buffer_done(&buf->vb.vb2_buf,
VB2_BUF_STATE_QUEUED);
}
@@ -179,12 +181,20 @@ static void vid_out_stop_streaming(struct vb2_queue *vq)
dev->can_loop_video = false;
}
+static void vid_out_buf_request_complete(struct vb2_buffer *vb)
+{
+ struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+
+ v4l2_ctrl_request_complete(vb->req_obj.req, &dev->ctrl_hdl_vid_out);
+}
+
const struct vb2_ops vivid_vid_out_qops = {
.queue_setup = vid_out_queue_setup,
.buf_prepare = vid_out_buf_prepare,
.buf_queue = vid_out_buf_queue,
.start_streaming = vid_out_start_streaming,
.stop_streaming = vid_out_stop_streaming,
+ .buf_request_complete = vid_out_buf_request_complete,
.wait_prepare = vb2_ops_wait_prepare,
.wait_finish = vb2_ops_wait_finish,
};
@@ -413,7 +423,7 @@ int vivid_try_fmt_vid_out(struct file *file, void *priv,
mp->colorspace = V4L2_COLORSPACE_SMPTE170M;
} else if (mp->colorspace != V4L2_COLORSPACE_SMPTE170M &&
mp->colorspace != V4L2_COLORSPACE_REC709 &&
- mp->colorspace != V4L2_COLORSPACE_ADOBERGB &&
+ mp->colorspace != V4L2_COLORSPACE_OPRGB &&
mp->colorspace != V4L2_COLORSPACE_BT2020 &&
mp->colorspace != V4L2_COLORSPACE_SRGB) {
mp->colorspace = V4L2_COLORSPACE_REC709;
diff --git a/drivers/media/platform/vsp1/vsp1_brx.c b/drivers/media/platform/vsp1/vsp1_brx.c
index 359917b5d842..5e50178b057d 100644
--- a/drivers/media/platform/vsp1/vsp1_brx.c
+++ b/drivers/media/platform/vsp1/vsp1_brx.c
@@ -153,7 +153,7 @@ static int brx_set_format(struct v4l2_subdev *subdev,
format = vsp1_entity_get_pad_format(&brx->entity, config, fmt->pad);
*format = fmt->format;
- /* Reset the compose rectangle */
+ /* Reset the compose rectangle. */
if (fmt->pad != brx->entity.source_pad) {
struct v4l2_rect *compose;
@@ -164,7 +164,7 @@ static int brx_set_format(struct v4l2_subdev *subdev,
compose->height = format->height;
}
- /* Propagate the format code to all pads */
+ /* Propagate the format code to all pads. */
if (fmt->pad == BRX_PAD_SINK(0)) {
unsigned int i;
diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c
index b9c0f695d002..8d86f618ec77 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -770,6 +770,7 @@ int vsp1_du_atomic_update(struct device *dev, unsigned int pipe_index,
struct vsp1_device *vsp1 = dev_get_drvdata(dev);
struct vsp1_drm_pipeline *drm_pipe = &vsp1->drm->pipe[pipe_index];
const struct vsp1_format_info *fmtinfo;
+ unsigned int chroma_hsub;
struct vsp1_rwpf *rpf;
if (rpf_index >= vsp1->info->rpf_count)
@@ -810,10 +811,18 @@ int vsp1_du_atomic_update(struct device *dev, unsigned int pipe_index,
return -EINVAL;
}
+ /*
+ * Only formats with three planes can affect the chroma planes pitch.
+ * All formats with two planes have a horizontal subsampling value of 2,
+ * but combine U and V in a single chroma plane, which thus results in
+ * the luma plane and chroma plane having the same pitch.
+ */
+ chroma_hsub = (fmtinfo->planes == 3) ? fmtinfo->hsub : 1;
+
rpf->fmtinfo = fmtinfo;
rpf->format.num_planes = fmtinfo->planes;
rpf->format.plane_fmt[0].bytesperline = cfg->pitch;
- rpf->format.plane_fmt[1].bytesperline = cfg->pitch;
+ rpf->format.plane_fmt[1].bytesperline = cfg->pitch / chroma_hsub;
rpf->alpha = cfg->alpha;
rpf->mem.addr[0] = cfg->mem[0];
diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c
index b6619c9c18bb..c650e45bb0ad 100644
--- a/drivers/media/platform/vsp1/vsp1_drv.c
+++ b/drivers/media/platform/vsp1/vsp1_drv.c
@@ -242,7 +242,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
mdev->dev = vsp1->dev;
mdev->hw_revision = vsp1->version;
- strlcpy(mdev->model, vsp1->info->model, sizeof(mdev->model));
+ strscpy(mdev->model, vsp1->info->model, sizeof(mdev->model));
snprintf(mdev->bus_info, sizeof(mdev->bus_info), "platform:%s",
dev_name(mdev->dev));
media_device_init(mdev);
@@ -802,7 +802,7 @@ static int vsp1_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, vsp1);
- /* I/O and IRQ resources (clock managed by the clock PM domain) */
+ /* I/O and IRQ resources (clock managed by the clock PM domain). */
io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
vsp1->mmio = devm_ioremap_resource(&pdev->dev, io);
if (IS_ERR(vsp1->mmio))
@@ -821,7 +821,7 @@ static int vsp1_probe(struct platform_device *pdev)
return ret;
}
- /* FCP (optional) */
+ /* FCP (optional). */
fcp_node = of_parse_phandle(pdev->dev.of_node, "renesas,fcp", 0);
if (fcp_node) {
vsp1->fcp = rcar_fcp_get(fcp_node);
@@ -869,7 +869,7 @@ static int vsp1_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "IP version 0x%08x\n", vsp1->version);
- /* Instanciate entities */
+ /* Instantiate entities. */
ret = vsp1_create_entities(vsp1);
if (ret < 0) {
dev_err(&pdev->dev, "failed to create entities\n");
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c
index 36a29e13109e..a54ab528b060 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/vsp1/vsp1_entity.c
@@ -404,7 +404,7 @@ int vsp1_subdev_set_pad_format(struct v4l2_subdev *subdev,
format = vsp1_entity_get_pad_format(entity, config, entity->source_pad);
*format = fmt->format;
- /* Reset the crop and compose rectangles */
+ /* Reset the crop and compose rectangles. */
selection = vsp1_entity_get_pad_selection(entity, config, fmt->pad,
V4L2_SEL_TGT_CROP);
selection->left = 0;
diff --git a/drivers/media/platform/vsp1/vsp1_histo.c b/drivers/media/platform/vsp1/vsp1_histo.c
index 5e15c8ff88d9..8b01e99acd20 100644
--- a/drivers/media/platform/vsp1/vsp1_histo.c
+++ b/drivers/media/platform/vsp1/vsp1_histo.c
@@ -429,8 +429,8 @@ static int histo_v4l2_querycap(struct file *file, void *fh,
cap->device_caps = V4L2_CAP_META_CAPTURE
| V4L2_CAP_STREAMING;
- strlcpy(cap->driver, "vsp1", sizeof(cap->driver));
- strlcpy(cap->card, histo->video.name, sizeof(cap->card));
+ strscpy(cap->driver, "vsp1", sizeof(cap->driver));
+ strscpy(cap->card, histo->video.name, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
dev_name(histo->entity.vsp1->dev));
diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c
index 0cb63244b21a..0b18f0bd7419 100644
--- a/drivers/media/platform/vsp1/vsp1_lif.c
+++ b/drivers/media/platform/vsp1/vsp1_lif.c
@@ -88,14 +88,35 @@ static void lif_configure_stream(struct vsp1_entity *entity,
{
const struct v4l2_mbus_framefmt *format;
struct vsp1_lif *lif = to_lif(&entity->subdev);
- unsigned int hbth = 1300;
- unsigned int obth = 400;
- unsigned int lbth = 200;
+ unsigned int hbth;
+ unsigned int obth;
+ unsigned int lbth;
format = vsp1_entity_get_pad_format(&lif->entity, lif->entity.config,
LIF_PAD_SOURCE);
- obth = min(obth, (format->width + 1) / 2 * format->height - 4);
+ switch (entity->vsp1->version & VI6_IP_VERSION_SOC_MASK) {
+ case VI6_IP_VERSION_MODEL_VSPD_GEN2:
+ case VI6_IP_VERSION_MODEL_VSPD_V2H:
+ hbth = 1536;
+ obth = min(128U, (format->width + 1) / 2 * format->height - 4);
+ lbth = 1520;
+ break;
+
+ case VI6_IP_VERSION_MODEL_VSPDL_GEN3:
+ case VI6_IP_VERSION_MODEL_VSPD_V3:
+ hbth = 0;
+ obth = 1500;
+ lbth = 0;
+ break;
+
+ case VI6_IP_VERSION_MODEL_VSPD_GEN3:
+ default:
+ hbth = 0;
+ obth = 3000;
+ lbth = 0;
+ break;
+ }
vsp1_lif_write(lif, dlb, VI6_LIF_CSBTH,
(hbth << VI6_LIF_CSBTH_HBTH_SHIFT) |
diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h
index 3738ff2f7b85..f6e4157095cc 100644
--- a/drivers/media/platform/vsp1/vsp1_regs.h
+++ b/drivers/media/platform/vsp1/vsp1_regs.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0+ */
/*
* vsp1_regs.h -- R-Car VSP1 Registers Definitions
*
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index f8005b60b9d2..616afa7e165f 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -108,7 +108,7 @@ static void rpf_configure_stream(struct vsp1_entity *entity,
vsp1_rpf_write(rpf, dlb, VI6_RPF_INFMT, infmt);
vsp1_rpf_write(rpf, dlb, VI6_RPF_DSWAP, fmtinfo->swap);
- /* Output location */
+ /* Output location. */
if (pipe->brx) {
const struct v4l2_rect *compose;
@@ -309,7 +309,7 @@ static void rpf_configure_partition(struct vsp1_entity *entity,
/*
* Interlaced pipelines will use the extended pre-cmd to process
- * SRCM_ADDR_{Y,C0,C1}
+ * SRCM_ADDR_{Y,C0,C1}.
*/
if (pipe->interlaced) {
vsp1_rpf_configure_autofld(rpf, dl);
diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c
index 04e4e05af6ae..b1617cb1f2b9 100644
--- a/drivers/media/platform/vsp1/vsp1_sru.c
+++ b/drivers/media/platform/vsp1/vsp1_sru.c
@@ -312,6 +312,11 @@ static unsigned int sru_max_width(struct vsp1_entity *entity,
output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
SRU_PAD_SOURCE);
+ /*
+ * The maximum input width of the SRU is 288 input pixels, but 32
+ * pixels are reserved to support overlapping partition windows when
+ * scaling.
+ */
if (input->width != output->width)
return 512;
else
@@ -333,7 +338,7 @@ static void sru_partition(struct vsp1_entity *entity,
output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
SRU_PAD_SOURCE);
- /* Adapt if SRUx2 is enabled */
+ /* Adapt if SRUx2 is enabled. */
if (input->width != output->width) {
window->width /= 2;
window->left /= 2;
diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c
index c20c84b54936..27012af973b2 100644
--- a/drivers/media/platform/vsp1/vsp1_uds.c
+++ b/drivers/media/platform/vsp1/vsp1_uds.c
@@ -314,13 +314,13 @@ static void uds_configure_partition(struct vsp1_entity *entity,
output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config,
UDS_PAD_SOURCE);
- /* Input size clipping */
+ /* Input size clipping. */
vsp1_uds_write(uds, dlb, VI6_UDS_HSZCLIP, VI6_UDS_HSZCLIP_HCEN |
(0 << VI6_UDS_HSZCLIP_HCL_OFST_SHIFT) |
(partition->uds_sink.width
<< VI6_UDS_HSZCLIP_HCL_SIZE_SHIFT));
- /* Output size clipping */
+ /* Output size clipping. */
vsp1_uds_write(uds, dlb, VI6_UDS_CLIP_SIZE,
(partition->uds_source.width
<< VI6_UDS_CLIP_SIZE_HSIZE_SHIFT) |
@@ -342,6 +342,14 @@ static unsigned int uds_max_width(struct vsp1_entity *entity,
UDS_PAD_SOURCE);
hscale = output->width / input->width;
+ /*
+ * The maximum width of the UDS is 304 pixels. These are input pixels
+ * in the event of up-scaling, and output pixels in the event of
+ * downscaling.
+ *
+ * To support overlapping partition windows we clamp at units of 256 and
+ * the remaining pixels are reserved.
+ */
if (hscale <= 2)
return 256;
else if (hscale <= 4)
@@ -366,7 +374,7 @@ static void uds_partition(struct vsp1_entity *entity,
const struct v4l2_mbus_framefmt *output;
const struct v4l2_mbus_framefmt *input;
- /* Initialise the partition state */
+ /* Initialise the partition state. */
partition->uds_sink = *window;
partition->uds_source = *window;
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index 81d47a09d7bc..771dfe1f7c20 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -38,9 +38,7 @@
#define VSP1_VIDEO_DEF_WIDTH 1024
#define VSP1_VIDEO_DEF_HEIGHT 768
-#define VSP1_VIDEO_MIN_WIDTH 2U
#define VSP1_VIDEO_MAX_WIDTH 8190U
-#define VSP1_VIDEO_MIN_HEIGHT 2U
#define VSP1_VIDEO_MAX_HEIGHT 8190U
/* -----------------------------------------------------------------------------
@@ -136,9 +134,8 @@ static int __vsp1_video_try_format(struct vsp1_video *video,
height = round_down(height, info->vsub);
/* Clamp the width and height. */
- pix->width = clamp(width, VSP1_VIDEO_MIN_WIDTH, VSP1_VIDEO_MAX_WIDTH);
- pix->height = clamp(height, VSP1_VIDEO_MIN_HEIGHT,
- VSP1_VIDEO_MAX_HEIGHT);
+ pix->width = clamp(width, info->hsub, VSP1_VIDEO_MAX_WIDTH);
+ pix->height = clamp(height, info->vsub, VSP1_VIDEO_MAX_HEIGHT);
/*
* Compute and clamp the stride and image size. While not documented in
@@ -867,7 +864,7 @@ static void vsp1_video_cleanup_pipeline(struct vsp1_pipeline *pipe)
pipe->stream_config = NULL;
pipe->configured = false;
- /* Release our partition table allocation */
+ /* Release our partition table allocation. */
kfree(pipe->part_table);
pipe->part_table = NULL;
}
@@ -976,8 +973,8 @@ vsp1_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
cap->device_caps = V4L2_CAP_VIDEO_OUTPUT_MPLANE
| V4L2_CAP_STREAMING;
- strlcpy(cap->driver, "vsp1", sizeof(cap->driver));
- strlcpy(cap->card, video->video.name, sizeof(cap->card));
+ strscpy(cap->driver, "vsp1", sizeof(cap->driver));
+ strscpy(cap->card, video->video.name, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
dev_name(video->vsp1->dev));
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index c2a1a7f97e26..32bb207b2007 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -317,7 +317,7 @@ static void wpf_configure_stream(struct vsp1_entity *entity,
vsp1_wpf_write(wpf, dlb, VI6_WPF_SRCRPF, srcrpf);
- /* Enable interrupts */
+ /* Enable interrupts. */
vsp1_dl_body_write(dlb, VI6_WPF_IRQ_STA(wpf->entity.index), 0);
vsp1_dl_body_write(dlb, VI6_WPF_IRQ_ENB(wpf->entity.index),
VI6_WFP_IRQ_ENB_DFEE);
diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c
index d041f94be832..4ae9d38c9433 100644
--- a/drivers/media/platform/xilinx/xilinx-dma.c
+++ b/drivers/media/platform/xilinx/xilinx-dma.c
@@ -504,10 +504,10 @@ xvip_dma_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS
| dma->xdev->v4l2_caps;
- strlcpy(cap->driver, "xilinx-vipp", sizeof(cap->driver));
- strlcpy(cap->card, dma->video.name, sizeof(cap->card));
- snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s:%u",
- dma->xdev->dev->of_node->name, dma->port);
+ strscpy(cap->driver, "xilinx-vipp", sizeof(cap->driver));
+ strscpy(cap->card, dma->video.name, sizeof(cap->card));
+ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%pOFn:%u",
+ dma->xdev->dev->of_node, dma->port);
return 0;
}
@@ -527,7 +527,7 @@ xvip_dma_enum_format(struct file *file, void *fh, struct v4l2_fmtdesc *f)
return -EINVAL;
f->pixelformat = dma->format.pixelformat;
- strlcpy(f->description, dma->fmtinfo->description,
+ strscpy(f->description, dma->fmtinfo->description,
sizeof(f->description));
return 0;
@@ -693,8 +693,8 @@ int xvip_dma_init(struct xvip_composite_device *xdev, struct xvip_dma *dma,
dma->video.fops = &xvip_dma_fops;
dma->video.v4l2_dev = &xdev->v4l2_dev;
dma->video.queue = &dma->queue;
- snprintf(dma->video.name, sizeof(dma->video.name), "%s %s %u",
- xdev->dev->of_node->name,
+ snprintf(dma->video.name, sizeof(dma->video.name), "%pOFn %s %u",
+ xdev->dev->of_node,
type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? "output" : "input",
port);
dma->video.vfl_type = VFL_TYPE_GRABBER;
diff --git a/drivers/media/platform/xilinx/xilinx-tpg.c b/drivers/media/platform/xilinx/xilinx-tpg.c
index 9c49d1d10bee..851d20dcd550 100644
--- a/drivers/media/platform/xilinx/xilinx-tpg.c
+++ b/drivers/media/platform/xilinx/xilinx-tpg.c
@@ -833,7 +833,7 @@ static int xtpg_probe(struct platform_device *pdev)
v4l2_subdev_init(subdev, &xtpg_ops);
subdev->dev = &pdev->dev;
subdev->internal_ops = &xtpg_internal_ops;
- strlcpy(subdev->name, dev_name(&pdev->dev), sizeof(subdev->name));
+ strscpy(subdev->name, dev_name(&pdev->dev), sizeof(subdev->name));
v4l2_set_subdevdata(subdev, xtpg);
subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
subdev->entity.ops = &xtpg_media_ops;
diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c
index 6d95ec1e9a6b..99e016d35d91 100644
--- a/drivers/media/platform/xilinx/xilinx-vipp.c
+++ b/drivers/media/platform/xilinx/xilinx-vipp.c
@@ -32,33 +32,36 @@
/**
* struct xvip_graph_entity - Entity in the video graph
- * @list: list entry in a graph entities list
- * @node: the entity's DT node
- * @entity: media entity, from the corresponding V4L2 subdev
* @asd: subdev asynchronous registration information
+ * @entity: media entity, from the corresponding V4L2 subdev
* @subdev: V4L2 subdev
*/
struct xvip_graph_entity {
- struct list_head list;
- struct device_node *node;
+ struct v4l2_async_subdev asd; /* must be first */
struct media_entity *entity;
-
- struct v4l2_async_subdev asd;
struct v4l2_subdev *subdev;
};
+static inline struct xvip_graph_entity *
+to_xvip_entity(struct v4l2_async_subdev *asd)
+{
+ return container_of(asd, struct xvip_graph_entity, asd);
+}
+
/* -----------------------------------------------------------------------------
* Graph Management
*/
static struct xvip_graph_entity *
xvip_graph_find_entity(struct xvip_composite_device *xdev,
- const struct device_node *node)
+ const struct fwnode_handle *fwnode)
{
struct xvip_graph_entity *entity;
+ struct v4l2_async_subdev *asd;
- list_for_each_entry(entity, &xdev->entities, list) {
- if (entity->node == node)
+ list_for_each_entry(asd, &xdev->notifier.asd_list, asd_list) {
+ entity = to_xvip_entity(asd);
+ if (entity->asd.match.fwnode == fwnode)
return entity;
}
@@ -75,22 +78,23 @@ static int xvip_graph_build_one(struct xvip_composite_device *xdev,
struct media_pad *remote_pad;
struct xvip_graph_entity *ent;
struct v4l2_fwnode_link link;
- struct device_node *ep = NULL;
+ struct fwnode_handle *ep = NULL;
int ret = 0;
dev_dbg(xdev->dev, "creating links for entity %s\n", local->name);
while (1) {
/* Get the next endpoint and parse its link. */
- ep = of_graph_get_next_endpoint(entity->node, ep);
+ ep = fwnode_graph_get_next_endpoint(entity->asd.match.fwnode,
+ ep);
if (ep == NULL)
break;
- dev_dbg(xdev->dev, "processing endpoint %pOF\n", ep);
+ dev_dbg(xdev->dev, "processing endpoint %p\n", ep);
- ret = v4l2_fwnode_parse_link(of_fwnode_handle(ep), &link);
+ ret = v4l2_fwnode_parse_link(ep, &link);
if (ret < 0) {
- dev_err(xdev->dev, "failed to parse link for %pOF\n",
+ dev_err(xdev->dev, "failed to parse link for %p\n",
ep);
continue;
}
@@ -99,9 +103,8 @@ static int xvip_graph_build_one(struct xvip_composite_device *xdev,
* the link.
*/
if (link.local_port >= local->num_pads) {
- dev_err(xdev->dev, "invalid port number %u for %pOF\n",
- link.local_port,
- to_of_node(link.local_node));
+ dev_err(xdev->dev, "invalid port number %u for %p\n",
+ link.local_port, link.local_node);
v4l2_fwnode_put_link(&link);
ret = -EINVAL;
break;
@@ -110,28 +113,25 @@ static int xvip_graph_build_one(struct xvip_composite_device *xdev,
local_pad = &local->pads[link.local_port];
if (local_pad->flags & MEDIA_PAD_FL_SINK) {
- dev_dbg(xdev->dev, "skipping sink port %pOF:%u\n",
- to_of_node(link.local_node),
- link.local_port);
+ dev_dbg(xdev->dev, "skipping sink port %p:%u\n",
+ link.local_node, link.local_port);
v4l2_fwnode_put_link(&link);
continue;
}
/* Skip DMA engines, they will be processed separately. */
if (link.remote_node == of_fwnode_handle(xdev->dev->of_node)) {
- dev_dbg(xdev->dev, "skipping DMA port %pOF:%u\n",
- to_of_node(link.local_node),
- link.local_port);
+ dev_dbg(xdev->dev, "skipping DMA port %p:%u\n",
+ link.local_node, link.local_port);
v4l2_fwnode_put_link(&link);
continue;
}
/* Find the remote entity. */
- ent = xvip_graph_find_entity(xdev,
- to_of_node(link.remote_node));
+ ent = xvip_graph_find_entity(xdev, link.remote_node);
if (ent == NULL) {
- dev_err(xdev->dev, "no entity found for %pOF\n",
- to_of_node(link.remote_node));
+ dev_err(xdev->dev, "no entity found for %p\n",
+ link.remote_node);
v4l2_fwnode_put_link(&link);
ret = -ENODEV;
break;
@@ -140,8 +140,8 @@ static int xvip_graph_build_one(struct xvip_composite_device *xdev,
remote = ent->entity;
if (link.remote_port >= remote->num_pads) {
- dev_err(xdev->dev, "invalid port number %u on %pOF\n",
- link.remote_port, to_of_node(link.remote_node));
+ dev_err(xdev->dev, "invalid port number %u on %p\n",
+ link.remote_port, link.remote_node);
v4l2_fwnode_put_link(&link);
ret = -EINVAL;
break;
@@ -168,7 +168,7 @@ static int xvip_graph_build_one(struct xvip_composite_device *xdev,
}
}
- of_node_put(ep);
+ fwnode_handle_put(ep);
return ret;
}
@@ -230,8 +230,7 @@ static int xvip_graph_build_dma(struct xvip_composite_device *xdev)
dma->video.name);
/* Find the remote entity. */
- ent = xvip_graph_find_entity(xdev,
- to_of_node(link.remote_node));
+ ent = xvip_graph_find_entity(xdev, link.remote_node);
if (ent == NULL) {
dev_err(xdev->dev, "no entity found for %pOF\n",
to_of_node(link.remote_node));
@@ -289,12 +288,14 @@ static int xvip_graph_notify_complete(struct v4l2_async_notifier *notifier)
struct xvip_composite_device *xdev =
container_of(notifier, struct xvip_composite_device, notifier);
struct xvip_graph_entity *entity;
+ struct v4l2_async_subdev *asd;
int ret;
dev_dbg(xdev->dev, "notify complete, all subdevs registered\n");
/* Create links for every entity. */
- list_for_each_entry(entity, &xdev->entities, list) {
+ list_for_each_entry(asd, &xdev->notifier.asd_list, asd_list) {
+ entity = to_xvip_entity(asd);
ret = xvip_graph_build_one(xdev, entity);
if (ret < 0)
return ret;
@@ -314,22 +315,25 @@ static int xvip_graph_notify_complete(struct v4l2_async_notifier *notifier)
static int xvip_graph_notify_bound(struct v4l2_async_notifier *notifier,
struct v4l2_subdev *subdev,
- struct v4l2_async_subdev *asd)
+ struct v4l2_async_subdev *unused)
{
struct xvip_composite_device *xdev =
container_of(notifier, struct xvip_composite_device, notifier);
struct xvip_graph_entity *entity;
+ struct v4l2_async_subdev *asd;
/* Locate the entity corresponding to the bound subdev and store the
* subdev pointer.
*/
- list_for_each_entry(entity, &xdev->entities, list) {
- if (entity->node != subdev->dev->of_node)
+ list_for_each_entry(asd, &xdev->notifier.asd_list, asd_list) {
+ entity = to_xvip_entity(asd);
+
+ if (entity->asd.match.fwnode != subdev->fwnode)
continue;
if (entity->subdev) {
- dev_err(xdev->dev, "duplicate subdev for node %pOF\n",
- entity->node);
+ dev_err(xdev->dev, "duplicate subdev for node %p\n",
+ entity->asd.match.fwnode);
return -EINVAL;
}
@@ -349,56 +353,60 @@ static const struct v4l2_async_notifier_operations xvip_graph_notify_ops = {
};
static int xvip_graph_parse_one(struct xvip_composite_device *xdev,
- struct device_node *node)
+ struct fwnode_handle *fwnode)
{
- struct xvip_graph_entity *entity;
- struct device_node *remote;
- struct device_node *ep = NULL;
+ struct fwnode_handle *remote;
+ struct fwnode_handle *ep = NULL;
int ret = 0;
- dev_dbg(xdev->dev, "parsing node %pOF\n", node);
+ dev_dbg(xdev->dev, "parsing node %p\n", fwnode);
while (1) {
- ep = of_graph_get_next_endpoint(node, ep);
+ struct v4l2_async_subdev *asd;
+
+ ep = fwnode_graph_get_next_endpoint(fwnode, ep);
if (ep == NULL)
break;
- dev_dbg(xdev->dev, "handling endpoint %pOF\n", ep);
+ dev_dbg(xdev->dev, "handling endpoint %p\n", ep);
- remote = of_graph_get_remote_port_parent(ep);
+ remote = fwnode_graph_get_remote_port_parent(ep);
if (remote == NULL) {
ret = -EINVAL;
- break;
+ goto err_notifier_cleanup;
}
+ fwnode_handle_put(ep);
+
/* Skip entities that we have already processed. */
- if (remote == xdev->dev->of_node ||
+ if (remote == of_fwnode_handle(xdev->dev->of_node) ||
xvip_graph_find_entity(xdev, remote)) {
- of_node_put(remote);
+ fwnode_handle_put(remote);
continue;
}
- entity = devm_kzalloc(xdev->dev, sizeof(*entity), GFP_KERNEL);
- if (entity == NULL) {
- of_node_put(remote);
- ret = -ENOMEM;
- break;
+ asd = v4l2_async_notifier_add_fwnode_subdev(
+ &xdev->notifier, remote,
+ sizeof(struct xvip_graph_entity));
+ if (IS_ERR(asd)) {
+ ret = PTR_ERR(asd);
+ fwnode_handle_put(remote);
+ goto err_notifier_cleanup;
}
-
- entity->node = remote;
- entity->asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
- entity->asd.match.fwnode = of_fwnode_handle(remote);
- list_add_tail(&entity->list, &xdev->entities);
- xdev->num_subdevs++;
}
- of_node_put(ep);
+ return 0;
+
+err_notifier_cleanup:
+ v4l2_async_notifier_cleanup(&xdev->notifier);
+ fwnode_handle_put(ep);
return ret;
}
static int xvip_graph_parse(struct xvip_composite_device *xdev)
{
struct xvip_graph_entity *entity;
+ struct v4l2_async_subdev *asd;
int ret;
/*
@@ -407,14 +415,17 @@ static int xvip_graph_parse(struct xvip_composite_device *xdev)
* loop will handle entities added at the end of the list while walking
* the links.
*/
- ret = xvip_graph_parse_one(xdev, xdev->dev->of_node);
+ ret = xvip_graph_parse_one(xdev, of_fwnode_handle(xdev->dev->of_node));
if (ret < 0)
return 0;
- list_for_each_entry(entity, &xdev->entities, list) {
- ret = xvip_graph_parse_one(xdev, entity->node);
- if (ret < 0)
+ list_for_each_entry(asd, &xdev->notifier.asd_list, asd_list) {
+ entity = to_xvip_entity(asd);
+ ret = xvip_graph_parse_one(xdev, entity->asd.match.fwnode);
+ if (ret < 0) {
+ v4l2_async_notifier_cleanup(&xdev->notifier);
break;
+ }
}
return ret;
@@ -485,17 +496,11 @@ static int xvip_graph_dma_init(struct xvip_composite_device *xdev)
static void xvip_graph_cleanup(struct xvip_composite_device *xdev)
{
- struct xvip_graph_entity *entityp;
- struct xvip_graph_entity *entity;
struct xvip_dma *dmap;
struct xvip_dma *dma;
v4l2_async_notifier_unregister(&xdev->notifier);
-
- list_for_each_entry_safe(entity, entityp, &xdev->entities, list) {
- of_node_put(entity->node);
- list_del(&entity->list);
- }
+ v4l2_async_notifier_cleanup(&xdev->notifier);
list_for_each_entry_safe(dma, dmap, &xdev->dmas, list) {
xvip_dma_cleanup(dma);
@@ -505,10 +510,6 @@ static void xvip_graph_cleanup(struct xvip_composite_device *xdev)
static int xvip_graph_init(struct xvip_composite_device *xdev)
{
- struct xvip_graph_entity *entity;
- struct v4l2_async_subdev **subdevs = NULL;
- unsigned int num_subdevs;
- unsigned int i;
int ret;
/* Init the DMA channels. */
@@ -525,26 +526,12 @@ static int xvip_graph_init(struct xvip_composite_device *xdev)
goto done;
}
- if (!xdev->num_subdevs) {
+ if (list_empty(&xdev->notifier.asd_list)) {
dev_err(xdev->dev, "no subdev found in graph\n");
goto done;
}
/* Register the subdevices notifier. */
- num_subdevs = xdev->num_subdevs;
- subdevs = devm_kcalloc(xdev->dev, num_subdevs, sizeof(*subdevs),
- GFP_KERNEL);
- if (subdevs == NULL) {
- ret = -ENOMEM;
- goto done;
- }
-
- i = 0;
- list_for_each_entry(entity, &xdev->entities, list)
- subdevs[i++] = &entity->asd;
-
- xdev->notifier.subdevs = subdevs;
- xdev->notifier.num_subdevs = num_subdevs;
xdev->notifier.ops = &xvip_graph_notify_ops;
ret = v4l2_async_notifier_register(&xdev->v4l2_dev, &xdev->notifier);
@@ -578,7 +565,7 @@ static int xvip_composite_v4l2_init(struct xvip_composite_device *xdev)
int ret;
xdev->media_dev.dev = xdev->dev;
- strlcpy(xdev->media_dev.model, "Xilinx Video Composite Device",
+ strscpy(xdev->media_dev.model, "Xilinx Video Composite Device",
sizeof(xdev->media_dev.model));
xdev->media_dev.hw_revision = 0;
@@ -610,8 +597,8 @@ static int xvip_composite_probe(struct platform_device *pdev)
return -ENOMEM;
xdev->dev = &pdev->dev;
- INIT_LIST_HEAD(&xdev->entities);
INIT_LIST_HEAD(&xdev->dmas);
+ v4l2_async_notifier_init(&xdev->notifier);
ret = xvip_composite_v4l2_init(xdev);
if (ret < 0)
diff --git a/drivers/media/platform/xilinx/xilinx-vipp.h b/drivers/media/platform/xilinx/xilinx-vipp.h
index faf6b6e80b3b..7e9c4cff33b4 100644
--- a/drivers/media/platform/xilinx/xilinx-vipp.h
+++ b/drivers/media/platform/xilinx/xilinx-vipp.h
@@ -28,8 +28,6 @@
* @media_dev: media device
* @dev: (OF) device
* @notifier: V4L2 asynchronous subdevs notifier
- * @entities: entities in the graph as a list of xvip_graph_entity
- * @num_subdevs: number of subdevs in the pipeline
* @dmas: list of DMA channels at the pipeline output and input
* @v4l2_caps: V4L2 capabilities of the whole device (see VIDIOC_QUERYCAP)
*/
@@ -39,8 +37,6 @@ struct xvip_composite_device {
struct device *dev;
struct v4l2_async_notifier notifier;
- struct list_head entities;
- unsigned int num_subdevs;
struct list_head dmas;
u32 v4l2_caps;
diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c
index 8521bb2825e8..c9d51a5f2838 100644
--- a/drivers/media/radio/dsbr100.c
+++ b/drivers/media/radio/dsbr100.c
@@ -174,8 +174,8 @@ static int vidioc_querycap(struct file *file, void *priv,
{
struct dsbr100_device *radio = video_drvdata(file);
- strlcpy(v->driver, "dsbr100", sizeof(v->driver));
- strlcpy(v->card, "D-Link R-100 USB FM Radio", sizeof(v->card));
+ strscpy(v->driver, "dsbr100", sizeof(v->driver));
+ strscpy(v->card, "D-Link R-100 USB FM Radio", sizeof(v->card));
usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
v->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER;
v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
@@ -191,7 +191,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
return -EINVAL;
dsbr100_getstat(radio);
- strcpy(v->name, "FM");
+ strscpy(v->name, "FM", sizeof(v->name));
v->type = V4L2_TUNER_RADIO;
v->rangelow = FREQ_MIN * FREQ_MUL;
v->rangehigh = FREQ_MAX * FREQ_MUL;
@@ -379,7 +379,8 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
goto err_reg_ctrl;
}
mutex_init(&radio->v4l2_lock);
- strlcpy(radio->videodev.name, v4l2_dev->name, sizeof(radio->videodev.name));
+ strscpy(radio->videodev.name, v4l2_dev->name,
+ sizeof(radio->videodev.name));
radio->videodev.v4l2_dev = v4l2_dev;
radio->videodev.fops = &usb_dsbr100_fops;
radio->videodev.ioctl_ops = &usb_dsbr100_ioctl_ops;
diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c
index 5b82e63885cd..d12e07e32546 100644
--- a/drivers/media/radio/radio-cadet.c
+++ b/drivers/media/radio/radio-cadet.c
@@ -353,9 +353,9 @@ static ssize_t cadet_read(struct file *file, char __user *data, size_t count, lo
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *v)
{
- strlcpy(v->driver, "ADS Cadet", sizeof(v->driver));
- strlcpy(v->card, "ADS Cadet", sizeof(v->card));
- strlcpy(v->bus_info, "ISA:radio-cadet", sizeof(v->bus_info));
+ strscpy(v->driver, "ADS Cadet", sizeof(v->driver));
+ strscpy(v->card, "ADS Cadet", sizeof(v->card));
+ strscpy(v->bus_info, "ISA:radio-cadet", sizeof(v->bus_info));
v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO |
V4L2_CAP_READWRITE | V4L2_CAP_RDS_CAPTURE;
v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
@@ -370,7 +370,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
if (v->index)
return -EINVAL;
v->type = V4L2_TUNER_RADIO;
- strlcpy(v->name, "Radio", sizeof(v->name));
+ strscpy(v->name, "Radio", sizeof(v->name));
v->capability = bands[0].capability | bands[1].capability;
v->rangelow = bands[0].rangelow; /* 520 kHz (start of AM band) */
v->rangehigh = bands[1].rangehigh; /* 108.0 MHz (end of FM band) */
@@ -595,7 +595,7 @@ static int __init cadet_init(void)
struct v4l2_ctrl_handler *hdl;
int res = -ENODEV;
- strlcpy(v4l2_dev->name, "cadet", sizeof(v4l2_dev->name));
+ strscpy(v4l2_dev->name, "cadet", sizeof(v4l2_dev->name));
mutex_init(&dev->lock);
/* If a probe was requested then probe ISAPnP first (safest) */
@@ -639,7 +639,7 @@ static int __init cadet_init(void)
dev->is_fm_band = true;
dev->curfreq = bands[dev->is_fm_band].rangelow;
cadet_setfreq(dev, dev->curfreq);
- strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
+ strscpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
dev->vdev.v4l2_dev = v4l2_dev;
dev->vdev.fops = &cadet_fops;
dev->vdev.ioctl_ops = &cadet_ioctl_ops;
diff --git a/drivers/media/radio/radio-isa.c b/drivers/media/radio/radio-isa.c
index 7312e469e850..551de8a45b95 100644
--- a/drivers/media/radio/radio-isa.c
+++ b/drivers/media/radio/radio-isa.c
@@ -42,8 +42,8 @@ static int radio_isa_querycap(struct file *file, void *priv,
{
struct radio_isa_card *isa = video_drvdata(file);
- strlcpy(v->driver, isa->drv->driver.driver.name, sizeof(v->driver));
- strlcpy(v->card, isa->drv->card, sizeof(v->card));
+ strscpy(v->driver, isa->drv->driver.driver.name, sizeof(v->driver));
+ strscpy(v->card, isa->drv->card, sizeof(v->card));
snprintf(v->bus_info, sizeof(v->bus_info), "ISA:%s", isa->v4l2_dev.name);
v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
@@ -60,7 +60,7 @@ static int radio_isa_g_tuner(struct file *file, void *priv,
if (v->index > 0)
return -EINVAL;
- strlcpy(v->name, "FM", sizeof(v->name));
+ strscpy(v->name, "FM", sizeof(v->name));
v->type = V4L2_TUNER_RADIO;
v->rangelow = FREQ_LOW;
v->rangehigh = FREQ_HIGH;
@@ -198,7 +198,7 @@ static struct radio_isa_card *radio_isa_alloc(struct radio_isa_driver *drv,
dev_set_drvdata(pdev, isa);
isa->drv = drv;
v4l2_dev = &isa->v4l2_dev;
- strlcpy(v4l2_dev->name, dev_name(pdev), sizeof(v4l2_dev->name));
+ strscpy(v4l2_dev->name, dev_name(pdev), sizeof(v4l2_dev->name));
return isa;
}
@@ -243,7 +243,7 @@ static int radio_isa_common_probe(struct radio_isa_card *isa,
mutex_init(&isa->lock);
isa->vdev.lock = &isa->lock;
- strlcpy(isa->vdev.name, v4l2_dev->name, sizeof(isa->vdev.name));
+ strscpy(isa->vdev.name, v4l2_dev->name, sizeof(isa->vdev.name));
isa->vdev.v4l2_dev = v4l2_dev;
isa->vdev.fops = &radio_isa_fops;
isa->vdev.ioctl_ops = &radio_isa_ioctl_ops;
diff --git a/drivers/media/radio/radio-keene.c b/drivers/media/radio/radio-keene.c
index f2ea8bc5f5ee..e9484b013073 100644
--- a/drivers/media/radio/radio-keene.c
+++ b/drivers/media/radio/radio-keene.c
@@ -174,8 +174,8 @@ static int vidioc_querycap(struct file *file, void *priv,
{
struct keene_device *radio = video_drvdata(file);
- strlcpy(v->driver, "radio-keene", sizeof(v->driver));
- strlcpy(v->card, "Keene FM Transmitter", sizeof(v->card));
+ strscpy(v->driver, "radio-keene", sizeof(v->driver));
+ strscpy(v->card, "Keene FM Transmitter", sizeof(v->card));
usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
v->device_caps = V4L2_CAP_RADIO | V4L2_CAP_MODULATOR;
v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
@@ -190,7 +190,7 @@ static int vidioc_g_modulator(struct file *file, void *priv,
if (v->index > 0)
return -EINVAL;
- strlcpy(v->name, "FM", sizeof(v->name));
+ strscpy(v->name, "FM", sizeof(v->name));
v->rangelow = FREQ_MIN * FREQ_MUL;
v->rangehigh = FREQ_MAX * FREQ_MUL;
v->txsubchans = radio->stereo ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
@@ -362,7 +362,7 @@ static int usb_keene_probe(struct usb_interface *intf,
radio->v4l2_dev.ctrl_handler = hdl;
radio->v4l2_dev.release = usb_keene_video_device_release;
- strlcpy(radio->vdev.name, radio->v4l2_dev.name,
+ strscpy(radio->vdev.name, radio->v4l2_dev.name,
sizeof(radio->vdev.name));
radio->vdev.v4l2_dev = &radio->v4l2_dev;
radio->vdev.fops = &usb_keene_fops;
diff --git a/drivers/media/radio/radio-ma901.c b/drivers/media/radio/radio-ma901.c
index fdc481257efd..5cb153727841 100644
--- a/drivers/media/radio/radio-ma901.c
+++ b/drivers/media/radio/radio-ma901.c
@@ -197,8 +197,8 @@ static int vidioc_querycap(struct file *file, void *priv,
{
struct ma901radio_device *radio = video_drvdata(file);
- strlcpy(v->driver, "radio-ma901", sizeof(v->driver));
- strlcpy(v->card, "Masterkit MA901 USB FM Radio", sizeof(v->card));
+ strscpy(v->driver, "radio-ma901", sizeof(v->driver));
+ strscpy(v->card, "Masterkit MA901 USB FM Radio", sizeof(v->card));
usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
v->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER;
v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
@@ -222,7 +222,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
* retval = ma901radio_get_stat(radio, &is_stereo, &v->signal);
*/
- strcpy(v->name, "FM");
+ strscpy(v->name, "FM", sizeof(v->name));
v->type = V4L2_TUNER_RADIO;
v->rangelow = FREQ_MIN * FREQ_MUL;
v->rangehigh = FREQ_MAX * FREQ_MUL;
@@ -400,7 +400,7 @@ static int usb_ma901radio_probe(struct usb_interface *intf,
radio->v4l2_dev.ctrl_handler = &radio->hdl;
radio->v4l2_dev.release = usb_ma901radio_release;
- strlcpy(radio->vdev.name, radio->v4l2_dev.name,
+ strscpy(radio->vdev.name, radio->v4l2_dev.name,
sizeof(radio->vdev.name));
radio->vdev.v4l2_dev = &radio->v4l2_dev;
radio->vdev.fops = &usb_ma901radio_fops;
diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c
index e4e758739246..1b97ad2ce7d0 100644
--- a/drivers/media/radio/radio-maxiradio.c
+++ b/drivers/media/radio/radio-maxiradio.c
@@ -142,7 +142,7 @@ static int maxiradio_probe(struct pci_dev *pdev,
dev->tea.cannot_read_data = true;
dev->tea.v4l2_dev = v4l2_dev;
dev->tea.radio_nr = radio_nr;
- strlcpy(dev->tea.card, "Maxi Radio FM2000", sizeof(dev->tea.card));
+ strscpy(dev->tea.card, "Maxi Radio FM2000", sizeof(dev->tea.card));
snprintf(dev->tea.bus_info, sizeof(dev->tea.bus_info),
"PCI:%s", pci_name(pdev));
diff --git a/drivers/media/radio/radio-miropcm20.c b/drivers/media/radio/radio-miropcm20.c
index 7b35e633118d..b626567b75c5 100644
--- a/drivers/media/radio/radio-miropcm20.c
+++ b/drivers/media/radio/radio-miropcm20.c
@@ -200,8 +200,8 @@ static int vidioc_querycap(struct file *file, void *priv,
{
struct pcm20 *dev = video_drvdata(file);
- strlcpy(v->driver, "Miro PCM20", sizeof(v->driver));
- strlcpy(v->card, "Miro PCM20", sizeof(v->card));
+ strscpy(v->driver, "Miro PCM20", sizeof(v->driver));
+ strscpy(v->card, "Miro PCM20", sizeof(v->card));
snprintf(v->bus_info, sizeof(v->bus_info), "ISA:%s", dev->v4l2_dev.name);
v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE;
v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
@@ -231,7 +231,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
if (v->index)
return -EINVAL;
- strlcpy(v->name, "FM", sizeof(v->name));
+ strscpy(v->name, "FM", sizeof(v->name));
v->type = V4L2_TUNER_RADIO;
v->rangelow = 87*16000;
v->rangehigh = 108*16000;
@@ -443,7 +443,7 @@ static int __init pcm20_init(void)
"you must load the snd-miro driver first!\n");
return -ENODEV;
}
- strlcpy(v4l2_dev->name, "radio-miropcm20", sizeof(v4l2_dev->name));
+ strscpy(v4l2_dev->name, "radio-miropcm20", sizeof(v4l2_dev->name));
mutex_init(&dev->lock);
res = v4l2_device_register(NULL, v4l2_dev);
@@ -474,7 +474,7 @@ static int __init pcm20_init(void)
v4l2_err(v4l2_dev, "Could not register control\n");
goto err_hdl;
}
- strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
+ strscpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
dev->vdev.v4l2_dev = v4l2_dev;
dev->vdev.fops = &pcm20_fops;
dev->vdev.ioctl_ops = &pcm20_ioctl_ops;
diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c
index 0f292c6ba338..ab1324f68199 100644
--- a/drivers/media/radio/radio-mr800.c
+++ b/drivers/media/radio/radio-mr800.c
@@ -266,8 +266,8 @@ static int vidioc_querycap(struct file *file, void *priv,
{
struct amradio_device *radio = video_drvdata(file);
- strlcpy(v->driver, "radio-mr800", sizeof(v->driver));
- strlcpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card));
+ strscpy(v->driver, "radio-mr800", sizeof(v->driver));
+ strscpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card));
usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
v->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER |
V4L2_CAP_HW_FREQ_SEEK;
@@ -291,7 +291,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
if (retval)
return retval;
- strcpy(v->name, "FM");
+ strscpy(v->name, "FM", sizeof(v->name));
v->type = V4L2_TUNER_RADIO;
v->rangelow = FREQ_MIN * FREQ_MUL;
v->rangehigh = FREQ_MAX * FREQ_MUL;
@@ -547,7 +547,7 @@ static int usb_amradio_probe(struct usb_interface *intf,
radio->v4l2_dev.ctrl_handler = &radio->hdl;
radio->v4l2_dev.release = usb_amradio_release;
- strlcpy(radio->vdev.name, radio->v4l2_dev.name,
+ strscpy(radio->vdev.name, radio->v4l2_dev.name,
sizeof(radio->vdev.name));
radio->vdev.v4l2_dev = &radio->v4l2_dev;
radio->vdev.fops = &usb_amradio_fops;
diff --git a/drivers/media/radio/radio-raremono.c b/drivers/media/radio/radio-raremono.c
index 9a5079d64c4a..5e782b3c2fa9 100644
--- a/drivers/media/radio/radio-raremono.c
+++ b/drivers/media/radio/radio-raremono.c
@@ -181,8 +181,8 @@ static int vidioc_querycap(struct file *file, void *priv,
{
struct raremono_device *radio = video_drvdata(file);
- strlcpy(v->driver, "radio-raremono", sizeof(v->driver));
- strlcpy(v->card, "Thanko's Raremono", sizeof(v->card));
+ strscpy(v->driver, "radio-raremono", sizeof(v->driver));
+ strscpy(v->card, "Thanko's Raremono", sizeof(v->card));
usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
@@ -212,7 +212,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
if (v->index > 0)
return -EINVAL;
- strlcpy(v->name, "AM/FM/SW", sizeof(v->name));
+ strscpy(v->name, "AM/FM/SW", sizeof(v->name));
v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
V4L2_TUNER_CAP_FREQ_BANDS;
v->rangelow = AM_FREQ_RANGE_LOW * 16;
@@ -338,7 +338,7 @@ static int usb_raremono_probe(struct usb_interface *intf,
mutex_init(&radio->lock);
- strlcpy(radio->vdev.name, radio->v4l2_dev.name,
+ strscpy(radio->vdev.name, radio->v4l2_dev.name,
sizeof(radio->vdev.name));
radio->vdev.v4l2_dev = &radio->v4l2_dev;
radio->vdev.fops = &usb_raremono_fops;
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index 4f9b97edd9eb..a8fedc963614 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -129,9 +129,9 @@ static void fmi_set_freq(struct fmi *fmi)
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *v)
{
- strlcpy(v->driver, "radio-sf16fmi", sizeof(v->driver));
- strlcpy(v->card, "SF16-FMI/FMP/FMD radio", sizeof(v->card));
- strlcpy(v->bus_info, "ISA:radio-sf16fmi", sizeof(v->bus_info));
+ strscpy(v->driver, "radio-sf16fmi", sizeof(v->driver));
+ strscpy(v->card, "SF16-FMI/FMP/FMD radio", sizeof(v->card));
+ strscpy(v->bus_info, "ISA:radio-sf16fmi", sizeof(v->bus_info));
v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
@@ -145,7 +145,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
if (v->index > 0)
return -EINVAL;
- strlcpy(v->name, "FM", sizeof(v->name));
+ strscpy(v->name, "FM", sizeof(v->name));
v->type = V4L2_TUNER_RADIO;
v->rangelow = RSF16_MINFREQ;
v->rangehigh = RSF16_MAXFREQ;
@@ -315,7 +315,7 @@ static int __init fmi_init(void)
return -ENODEV;
}
- strlcpy(v4l2_dev->name, "sf16fmi", sizeof(v4l2_dev->name));
+ strscpy(v4l2_dev->name, "sf16fmi", sizeof(v4l2_dev->name));
fmi->io = io;
res = v4l2_device_register(NULL, v4l2_dev);
@@ -339,7 +339,7 @@ static int __init fmi_init(void)
return res;
}
- strlcpy(fmi->vdev.name, v4l2_dev->name, sizeof(fmi->vdev.name));
+ strscpy(fmi->vdev.name, v4l2_dev->name, sizeof(fmi->vdev.name));
fmi->vdev.v4l2_dev = v4l2_dev;
fmi->vdev.fops = &fmi_fops;
fmi->vdev.ioctl_ops = &fmi_ioctl_ops;
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
index 7b07d42a9909..ca8a1c263eac 100644
--- a/drivers/media/radio/radio-sf16fmr2.c
+++ b/drivers/media/radio/radio-sf16fmr2.c
@@ -213,8 +213,8 @@ static int fmr2_probe(struct fmr2 *fmr2, struct device *pdev, int io)
if (io == fmr2_cards[i]->io)
return -EBUSY;
- strlcpy(fmr2->v4l2_dev.name, "radio-sf16fmr2",
- sizeof(fmr2->v4l2_dev.name)),
+ strscpy(fmr2->v4l2_dev.name, "radio-sf16fmr2",
+ sizeof(fmr2->v4l2_dev.name)),
fmr2->io = io;
if (!request_region(fmr2->io, 2, fmr2->v4l2_dev.name)) {
@@ -234,7 +234,7 @@ static int fmr2_probe(struct fmr2 *fmr2, struct device *pdev, int io)
fmr2->tea.radio_nr = radio_nr[num_fmr2_cards];
fmr2->tea.ops = &fmr2_tea_ops;
fmr2->tea.ext_init = fmr2_tea_ext_init;
- strlcpy(fmr2->tea.card, card_name, sizeof(fmr2->tea.card));
+ strscpy(fmr2->tea.card, card_name, sizeof(fmr2->tea.card));
snprintf(fmr2->tea.bus_info, sizeof(fmr2->tea.bus_info), "%s:%s",
fmr2->is_fmd2 ? "PnP" : "ISA", dev_name(pdev));
diff --git a/drivers/media/radio/radio-shark.c b/drivers/media/radio/radio-shark.c
index 22f3466af2b1..8230da828d0e 100644
--- a/drivers/media/radio/radio-shark.c
+++ b/drivers/media/radio/radio-shark.c
@@ -345,7 +345,7 @@ static int usb_shark_probe(struct usb_interface *intf,
shark->tea.ops = &shark_tea_ops;
shark->tea.cannot_mute = true;
shark->tea.has_am = true;
- strlcpy(shark->tea.card, "Griffin radioSHARK",
+ strscpy(shark->tea.card, "Griffin radioSHARK",
sizeof(shark->tea.card));
usb_make_path(shark->usbdev, shark->tea.bus_info,
sizeof(shark->tea.bus_info));
diff --git a/drivers/media/radio/radio-shark2.c b/drivers/media/radio/radio-shark2.c
index 4d1a4b3d669c..d150f12382c6 100644
--- a/drivers/media/radio/radio-shark2.c
+++ b/drivers/media/radio/radio-shark2.c
@@ -310,7 +310,7 @@ static int usb_shark_probe(struct usb_interface *intf,
shark->tea.ops = &shark_tea_ops;
shark->tea.has_am = true;
shark->tea.write_before_read = true;
- strlcpy(shark->tea.card, "Griffin radioSHARK2",
+ strscpy(shark->tea.card, "Griffin radioSHARK2",
sizeof(shark->tea.card));
usb_make_path(shark->usbdev, shark->tea.bus_info,
sizeof(shark->tea.bus_info));
diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c
index b52e678c6901..269971145f88 100644
--- a/drivers/media/radio/radio-si476x.c
+++ b/drivers/media/radio/radio-si476x.c
@@ -340,9 +340,9 @@ static int si476x_radio_querycap(struct file *file, void *priv,
{
struct si476x_radio *radio = video_drvdata(file);
- strlcpy(capability->driver, radio->v4l2dev.name,
+ strscpy(capability->driver, radio->v4l2dev.name,
sizeof(capability->driver));
- strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
+ strscpy(capability->card, DRIVER_CARD, sizeof(capability->card));
snprintf(capability->bus_info, sizeof(capability->bus_info),
"platform:%s", radio->v4l2dev.name);
@@ -428,15 +428,15 @@ static int si476x_radio_g_tuner(struct file *file, void *priv,
si476x_core_lock(radio->core);
if (si476x_core_is_a_secondary_tuner(radio->core)) {
- strlcpy(tuner->name, "FM (secondary)", sizeof(tuner->name));
+ strscpy(tuner->name, "FM (secondary)", sizeof(tuner->name));
tuner->rxsubchans = 0;
tuner->rangelow = si476x_bands[SI476X_BAND_FM].rangelow;
} else if (si476x_core_has_am(radio->core)) {
if (si476x_core_is_a_primary_tuner(radio->core))
- strlcpy(tuner->name, "AM/FM (primary)",
+ strscpy(tuner->name, "AM/FM (primary)",
sizeof(tuner->name));
else
- strlcpy(tuner->name, "AM/FM", sizeof(tuner->name));
+ strscpy(tuner->name, "AM/FM", sizeof(tuner->name));
tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO
| V4L2_TUNER_SUB_RDS;
@@ -446,7 +446,7 @@ static int si476x_radio_g_tuner(struct file *file, void *priv,
tuner->rangelow = si476x_bands[SI476X_BAND_AM].rangelow;
} else {
- strlcpy(tuner->name, "FM", sizeof(tuner->name));
+ strscpy(tuner->name, "FM", sizeof(tuner->name));
tuner->rxsubchans = V4L2_TUNER_SUB_RDS;
tuner->capability |= V4L2_TUNER_CAP_RDS
| V4L2_TUNER_CAP_RDS_BLOCK_IO
diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c
index afb763256fd6..6632be648cea 100644
--- a/drivers/media/radio/radio-tea5764.c
+++ b/drivers/media/radio/radio-tea5764.c
@@ -287,8 +287,8 @@ static int vidioc_querycap(struct file *file, void *priv,
struct tea5764_device *radio = video_drvdata(file);
struct video_device *dev = &radio->vdev;
- strlcpy(v->driver, dev->dev.driver->name, sizeof(v->driver));
- strlcpy(v->card, dev->name, sizeof(v->card));
+ strscpy(v->driver, dev->dev.driver->name, sizeof(v->driver));
+ strscpy(v->card, dev->name, sizeof(v->card));
snprintf(v->bus_info, sizeof(v->bus_info),
"I2C:%s", dev_name(&dev->dev));
v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
@@ -305,7 +305,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
if (v->index > 0)
return -EINVAL;
- strlcpy(v->name, "FM", sizeof(v->name));
+ strscpy(v->name, "FM", sizeof(v->name));
v->type = V4L2_TUNER_RADIO;
tea5764_i2c_read(radio);
v->rangelow = FREQ_MIN * FREQ_MUL;
diff --git a/drivers/media/radio/radio-tea5777.c b/drivers/media/radio/radio-tea5777.c
index 04ed1a5d1177..61f751cf1aa4 100644
--- a/drivers/media/radio/radio-tea5777.c
+++ b/drivers/media/radio/radio-tea5777.c
@@ -266,10 +266,10 @@ static int vidioc_querycap(struct file *file, void *priv,
{
struct radio_tea5777 *tea = video_drvdata(file);
- strlcpy(v->driver, tea->v4l2_dev->name, sizeof(v->driver));
- strlcpy(v->card, tea->card, sizeof(v->card));
+ strscpy(v->driver, tea->v4l2_dev->name, sizeof(v->driver));
+ strscpy(v->card, tea->card, sizeof(v->card));
strlcat(v->card, " TEA5777", sizeof(v->card));
- strlcpy(v->bus_info, tea->bus_info, sizeof(v->bus_info));
+ strscpy(v->bus_info, tea->bus_info, sizeof(v->bus_info));
v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
v->device_caps |= V4L2_CAP_HW_FREQ_SEEK;
v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
@@ -304,9 +304,9 @@ static int vidioc_g_tuner(struct file *file, void *priv,
memset(v, 0, sizeof(*v));
if (tea->has_am)
- strlcpy(v->name, "AM/FM", sizeof(v->name));
+ strscpy(v->name, "AM/FM", sizeof(v->name));
else
- strlcpy(v->name, "FM", sizeof(v->name));
+ strscpy(v->name, "FM", sizeof(v->name));
v->type = V4L2_TUNER_RADIO;
v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
V4L2_TUNER_CAP_FREQ_BANDS |
@@ -560,7 +560,7 @@ int radio_tea5777_init(struct radio_tea5777 *tea, struct module *owner)
tea->vd = tea575x_radio;
video_set_drvdata(&tea->vd, tea);
mutex_init(&tea->mutex);
- strlcpy(tea->vd.name, tea->v4l2_dev->name, sizeof(tea->vd.name));
+ strscpy(tea->vd.name, tea->v4l2_dev->name, sizeof(tea->vd.name));
tea->vd.lock = &tea->mutex;
tea->vd.v4l2_dev = tea->v4l2_dev;
tea->fops = tea575x_fops;
diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c
index fc4d9a73ab17..0eda863124e9 100644
--- a/drivers/media/radio/radio-timb.c
+++ b/drivers/media/radio/radio-timb.c
@@ -39,8 +39,8 @@ struct timbradio {
static int timbradio_vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *v)
{
- strlcpy(v->driver, DRIVER_NAME, sizeof(v->driver));
- strlcpy(v->card, "Timberdale Radio", sizeof(v->card));
+ strscpy(v->driver, DRIVER_NAME, sizeof(v->driver));
+ strscpy(v->card, "Timberdale Radio", sizeof(v->card));
snprintf(v->bus_info, sizeof(v->bus_info), "platform:"DRIVER_NAME);
v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
@@ -115,7 +115,7 @@ static int timbradio_probe(struct platform_device *pdev)
tr->pdata = *pdata;
mutex_init(&tr->lock);
- strlcpy(tr->video_dev.name, "Timberdale Radio",
+ strscpy(tr->video_dev.name, "Timberdale Radio",
sizeof(tr->video_dev.name));
tr->video_dev.fops = &timbradio_fops;
tr->video_dev.ioctl_ops = &timbradio_ioctl_ops;
@@ -123,7 +123,7 @@ static int timbradio_probe(struct platform_device *pdev)
tr->video_dev.minor = -1;
tr->video_dev.lock = &tr->lock;
- strlcpy(tr->v4l2_dev.name, DRIVER_NAME, sizeof(tr->v4l2_dev.name));
+ strscpy(tr->v4l2_dev.name, DRIVER_NAME, sizeof(tr->v4l2_dev.name));
err = v4l2_device_register(NULL, &tr->v4l2_dev);
if (err)
goto err;
diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c
index 11aa94f189cb..b95704f3cb8b 100644
--- a/drivers/media/radio/radio-wl1273.c
+++ b/drivers/media/radio/radio-wl1273.c
@@ -1286,11 +1286,11 @@ static int wl1273_fm_vidioc_querycap(struct file *file, void *priv,
dev_dbg(radio->dev, "%s\n", __func__);
- strlcpy(capability->driver, WL1273_FM_DRIVER_NAME,
+ strscpy(capability->driver, WL1273_FM_DRIVER_NAME,
sizeof(capability->driver));
- strlcpy(capability->card, "Texas Instruments Wl1273 FM Radio",
+ strscpy(capability->card, "Texas Instruments Wl1273 FM Radio",
sizeof(capability->card));
- strlcpy(capability->bus_info, radio->bus_type,
+ strscpy(capability->bus_info, radio->bus_type,
sizeof(capability->bus_info));
capability->device_caps = V4L2_CAP_HW_FREQ_SEEK |
@@ -1488,7 +1488,7 @@ static int wl1273_fm_vidioc_g_audio(struct file *file, void *priv,
if (audio->index > 1)
return -EINVAL;
- strlcpy(audio->name, "Radio", sizeof(audio->name));
+ strscpy(audio->name, "Radio", sizeof(audio->name));
audio->capability = V4L2_AUDCAP_STEREO;
return 0;
@@ -1523,7 +1523,7 @@ static int wl1273_fm_vidioc_g_tuner(struct file *file, void *priv,
if (tuner->index > 0)
return -EINVAL;
- strlcpy(tuner->name, WL1273_FM_DRIVER_NAME, sizeof(tuner->name));
+ strscpy(tuner->name, WL1273_FM_DRIVER_NAME, sizeof(tuner->name));
tuner->type = V4L2_TUNER_RADIO;
tuner->rangelow = WL1273_FREQ(WL1273_BAND_JAPAN_LOW);
@@ -1781,7 +1781,7 @@ static int wl1273_fm_vidioc_g_modulator(struct file *file, void *priv,
dev_dbg(radio->dev, "%s\n", __func__);
- strlcpy(modulator->name, WL1273_FM_DRIVER_NAME,
+ strscpy(modulator->name, WL1273_FM_DRIVER_NAME,
sizeof(modulator->name));
modulator->rangelow = WL1273_FREQ(WL1273_BAND_JAPAN_LOW);
diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c
index c40e1753f34b..1d7ab5462c77 100644
--- a/drivers/media/radio/si470x/radio-si470x-common.c
+++ b/drivers/media/radio/si470x/radio-si470x-common.c
@@ -622,7 +622,7 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
}
/* driver constants */
- strcpy(tuner->name, "FM");
+ strscpy(tuner->name, "FM", sizeof(tuner->name));
tuner->type = V4L2_TUNER_RADIO;
tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO |
diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c
index e3b3ecd14a4d..9751ea1d80be 100644
--- a/drivers/media/radio/si470x/radio-si470x-i2c.c
+++ b/drivers/media/radio/si470x/radio-si470x-i2c.c
@@ -229,8 +229,8 @@ static int si470x_fops_release(struct file *file)
static int si470x_vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *capability)
{
- strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
- strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
+ strscpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
+ strscpy(capability->card, DRIVER_CARD, sizeof(capability->card));
capability->device_caps = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_READWRITE |
V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE;
capability->capabilities = capability->device_caps | V4L2_CAP_DEVICE_CAPS;
diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c
index 313a95f195a2..91d6ef5579f7 100644
--- a/drivers/media/radio/si470x/radio-si470x-usb.c
+++ b/drivers/media/radio/si470x/radio-si470x-usb.c
@@ -519,8 +519,8 @@ static int si470x_vidioc_querycap(struct file *file, void *priv,
{
struct si470x_device *radio = video_drvdata(file);
- strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
- strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
+ strscpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
+ strscpy(capability->card, DRIVER_CARD, sizeof(capability->card));
usb_make_path(radio->usbdev, capability->bus_info,
sizeof(capability->bus_info));
capability->device_caps = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_READWRITE |
diff --git a/drivers/media/radio/si4713/radio-platform-si4713.c b/drivers/media/radio/si4713/radio-platform-si4713.c
index 27339ec495f6..733fcf3933e4 100644
--- a/drivers/media/radio/si4713/radio-platform-si4713.c
+++ b/drivers/media/radio/si4713/radio-platform-si4713.c
@@ -67,10 +67,10 @@ static const struct v4l2_file_operations radio_si4713_fops = {
static int radio_si4713_querycap(struct file *file, void *priv,
struct v4l2_capability *capability)
{
- strlcpy(capability->driver, "radio-si4713", sizeof(capability->driver));
- strlcpy(capability->card, "Silicon Labs Si4713 Modulator",
+ strscpy(capability->driver, "radio-si4713", sizeof(capability->driver));
+ strscpy(capability->card, "Silicon Labs Si4713 Modulator",
sizeof(capability->card));
- strlcpy(capability->bus_info, "platform:radio-si4713",
+ strscpy(capability->bus_info, "platform:radio-si4713",
sizeof(capability->bus_info));
capability->device_caps = V4L2_CAP_MODULATOR | V4L2_CAP_RDS_OUTPUT;
capability->capabilities = capability->device_caps | V4L2_CAP_DEVICE_CAPS;
diff --git a/drivers/media/radio/si4713/radio-usb-si4713.c b/drivers/media/radio/si4713/radio-usb-si4713.c
index 1ebbf0217142..23065ecce979 100644
--- a/drivers/media/radio/si4713/radio-usb-si4713.c
+++ b/drivers/media/radio/si4713/radio-usb-si4713.c
@@ -67,8 +67,8 @@ static int vidioc_querycap(struct file *file, void *priv,
{
struct si4713_usb_device *radio = video_drvdata(file);
- strlcpy(v->driver, "radio-usb-si4713", sizeof(v->driver));
- strlcpy(v->card, "Si4713 FM Transmitter", sizeof(v->card));
+ strscpy(v->driver, "radio-usb-si4713", sizeof(v->driver));
+ strscpy(v->card, "Si4713 FM Transmitter", sizeof(v->card));
usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
v->device_caps = V4L2_CAP_MODULATOR | V4L2_CAP_RDS_OUTPUT;
v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
@@ -467,7 +467,7 @@ static int usb_si4713_probe(struct usb_interface *intf,
radio->vdev.ctrl_handler = sd->ctrl_handler;
radio->v4l2_dev.release = usb_si4713_video_device_release;
- strlcpy(radio->vdev.name, radio->v4l2_dev.name,
+ strscpy(radio->vdev.name, radio->v4l2_dev.name,
sizeof(radio->vdev.name));
radio->vdev.v4l2_dev = &radio->v4l2_dev;
radio->vdev.fops = &usb_si4713_fops;
diff --git a/drivers/media/radio/tea575x.c b/drivers/media/radio/tea575x.c
index 7412fe1b10c6..f89f83e04741 100644
--- a/drivers/media/radio/tea575x.c
+++ b/drivers/media/radio/tea575x.c
@@ -233,10 +233,10 @@ static int vidioc_querycap(struct file *file, void *priv,
{
struct snd_tea575x *tea = video_drvdata(file);
- strlcpy(v->driver, tea->v4l2_dev->name, sizeof(v->driver));
- strlcpy(v->card, tea->card, sizeof(v->card));
+ strscpy(v->driver, tea->v4l2_dev->name, sizeof(v->driver));
+ strscpy(v->card, tea->card, sizeof(v->card));
strlcat(v->card, tea->tea5759 ? " TEA5759" : " TEA5757", sizeof(v->card));
- strlcpy(v->bus_info, tea->bus_info, sizeof(v->bus_info));
+ strscpy(v->bus_info, tea->bus_info, sizeof(v->bus_info));
v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
if (!tea->cannot_read_data)
v->device_caps |= V4L2_CAP_HW_FREQ_SEEK;
@@ -296,7 +296,7 @@ int snd_tea575x_g_tuner(struct snd_tea575x *tea, struct v4l2_tuner *v)
snd_tea575x_enum_freq_bands(tea, &band_fm);
memset(v, 0, sizeof(*v));
- strlcpy(v->name, tea->has_am ? "FM/AM" : "FM", sizeof(v->name));
+ strscpy(v->name, tea->has_am ? "FM/AM" : "FM", sizeof(v->name));
v->type = V4L2_TUNER_RADIO;
v->capability = band_fm.capability;
v->rangelow = tea->has_am ? bands[BAND_AM].rangelow : band_fm.rangelow;
@@ -537,7 +537,7 @@ int snd_tea575x_init(struct snd_tea575x *tea, struct module *owner)
tea->vd = tea575x_radio;
video_set_drvdata(&tea->vd, tea);
mutex_init(&tea->mutex);
- strlcpy(tea->vd.name, tea->v4l2_dev->name, sizeof(tea->vd.name));
+ strscpy(tea->vd.name, tea->v4l2_dev->name, sizeof(tea->vd.name));
tea->vd.lock = &tea->mutex;
tea->vd.v4l2_dev = tea->v4l2_dev;
tea->fops = tea575x_fops;
diff --git a/drivers/media/radio/tef6862.c b/drivers/media/radio/tef6862.c
index ed210f4c476a..a76ff2978dfb 100644
--- a/drivers/media/radio/tef6862.c
+++ b/drivers/media/radio/tef6862.c
@@ -79,7 +79,7 @@ static int tef6862_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v)
return -EINVAL;
/* only support FM for now */
- strlcpy(v->name, "FM", sizeof(v->name));
+ strscpy(v->name, "FM", sizeof(v->name));
v->type = V4L2_TUNER_RADIO;
v->rangelow = TEF6862_LO_FREQ;
v->rangehigh = TEF6862_HI_FREQ;
diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c
index dccdf6558e6a..e25fd4d4d280 100644
--- a/drivers/media/radio/wl128x/fmdrv_v4l2.c
+++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c
@@ -190,9 +190,9 @@ release_unlock:
static int fm_v4l2_vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *capability)
{
- strlcpy(capability->driver, FM_DRV_NAME, sizeof(capability->driver));
- strlcpy(capability->card, FM_DRV_CARD_SHORT_NAME,
- sizeof(capability->card));
+ strscpy(capability->driver, FM_DRV_NAME, sizeof(capability->driver));
+ strscpy(capability->card, FM_DRV_CARD_SHORT_NAME,
+ sizeof(capability->card));
sprintf(capability->bus_info, "UART");
capability->device_caps = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_TUNER |
V4L2_CAP_RADIO | V4L2_CAP_MODULATOR |
@@ -249,7 +249,7 @@ static int fm_v4l2_vidioc_g_audio(struct file *file, void *priv,
struct v4l2_audio *audio)
{
memset(audio, 0, sizeof(*audio));
- strcpy(audio->name, "Radio");
+ strscpy(audio->name, "Radio", sizeof(audio->name));
audio->capability = V4L2_AUDCAP_STEREO;
return 0;
@@ -293,7 +293,7 @@ static int fm_v4l2_vidioc_g_tuner(struct file *file, void *priv,
if (ret != 0)
return ret;
- strcpy(tuner->name, "FM");
+ strscpy(tuner->name, "FM", sizeof(tuner->name));
tuner->type = V4L2_TUNER_RADIO;
/* Store rangelow and rangehigh freq in unit of 62.5 Hz */
tuner->rangelow = bottom_freq * 16;
@@ -531,7 +531,8 @@ int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr)
struct v4l2_ctrl *ctrl;
int ret;
- strlcpy(fmdev->v4l2_dev.name, FM_DRV_NAME, sizeof(fmdev->v4l2_dev.name));
+ strscpy(fmdev->v4l2_dev.name, FM_DRV_NAME,
+ sizeof(fmdev->v4l2_dev.name));
ret = v4l2_device_register(NULL, &fmdev->v4l2_dev);
if (ret < 0)
return ret;
diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c
index 8e82610ffaad..265e91a2a70d 100644
--- a/drivers/media/rc/ati_remote.c
+++ b/drivers/media/rc/ati_remote.c
@@ -862,7 +862,7 @@ static int ati_remote_probe(struct usb_interface *interface,
ati_remote->interface = interface;
usb_make_path(udev, ati_remote->rc_phys, sizeof(ati_remote->rc_phys));
- strlcpy(ati_remote->mouse_phys, ati_remote->rc_phys,
+ strscpy(ati_remote->mouse_phys, ati_remote->rc_phys,
sizeof(ati_remote->mouse_phys));
strlcat(ati_remote->rc_phys, "/input0", sizeof(ati_remote->rc_phys));
diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c
index 71b8c9bbf6c4..dd2fd307ef85 100644
--- a/drivers/media/rc/ene_ir.c
+++ b/drivers/media/rc/ene_ir.c
@@ -326,8 +326,6 @@ static int ene_rx_get_sample_reg(struct ene_device *dev)
/* Sense current received carrier */
static void ene_rx_sense_carrier(struct ene_device *dev)
{
- DEFINE_IR_RAW_EVENT(ev);
-
int carrier, duty_cycle;
int period = ene_read_reg(dev, ENE_CIRCAR_PRD);
int hperiod = ene_read_reg(dev, ENE_CIRCAR_HPRD);
@@ -348,9 +346,11 @@ static void ene_rx_sense_carrier(struct ene_device *dev)
dbg("RX: sensed carrier = %d Hz, duty cycle %d%%",
carrier, duty_cycle);
if (dev->carrier_detect_enabled) {
- ev.carrier_report = true;
- ev.carrier = carrier;
- ev.duty_cycle = duty_cycle;
+ struct ir_raw_event ev = {
+ .carrier_report = true,
+ .carrier = carrier,
+ .duty_cycle = duty_cycle
+ };
ir_raw_event_store(dev->rdev, &ev);
}
}
@@ -733,7 +733,7 @@ static irqreturn_t ene_isr(int irq, void *data)
unsigned long flags;
irqreturn_t retval = IRQ_NONE;
struct ene_device *dev = (struct ene_device *)data;
- DEFINE_IR_RAW_EVENT(ev);
+ struct ir_raw_event ev = {};
spin_lock_irqsave(&dev->hw_lock, flags);
diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c
index f2639d0c2fca..601944666b71 100644
--- a/drivers/media/rc/fintek-cir.c
+++ b/drivers/media/rc/fintek-cir.c
@@ -282,7 +282,7 @@ static int fintek_cmdsize(u8 cmd, u8 subcmd)
/* process ir data stored in driver buffer */
static void fintek_process_rx_ir_data(struct fintek_dev *fintek)
{
- DEFINE_IR_RAW_EVENT(rawir);
+ struct ir_raw_event rawir = {};
u8 sample;
bool event = false;
int i;
@@ -314,7 +314,6 @@ static void fintek_process_rx_ir_data(struct fintek_dev *fintek)
break;
case PARSE_IRDATA:
fintek->rem--;
- init_ir_raw_event(&rawir);
rawir.pulse = ((sample & BUF_PULSE_BIT) != 0);
rawir.duration = US_TO_NS((sample & BUF_SAMPLE_MASK)
* CIR_SAMPLE_PERIOD);
diff --git a/drivers/media/rc/igorplugusb.c b/drivers/media/rc/igorplugusb.c
index f563ddd7f739..ba3f95a97f14 100644
--- a/drivers/media/rc/igorplugusb.c
+++ b/drivers/media/rc/igorplugusb.c
@@ -56,7 +56,7 @@ static void igorplugusb_cmd(struct igorplugusb *ir, int cmd);
static void igorplugusb_irdata(struct igorplugusb *ir, unsigned len)
{
- DEFINE_IR_RAW_EVENT(rawir);
+ struct ir_raw_event rawir = {};
unsigned i, start, overflow;
dev_dbg(ir->dev, "irdata: %*ph (len=%u)", len, ir->buf_in, len);
diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c
index 7daac8bab83b..fbacb13b614b 100644
--- a/drivers/media/rc/iguanair.c
+++ b/drivers/media/rc/iguanair.c
@@ -129,12 +129,10 @@ static void process_ir_data(struct iguanair *ir, unsigned len)
break;
}
} else if (len >= 7) {
- DEFINE_IR_RAW_EVENT(rawir);
+ struct ir_raw_event rawir = {};
unsigned i;
bool event = false;
- init_ir_raw_event(&rawir);
-
for (i = 0; i < 7; i++) {
if (ir->buf_in[i] == 0x80) {
rawir.pulse = false;
diff --git a/drivers/media/rc/imon_raw.c b/drivers/media/rc/imon_raw.c
index 32709f96de14..7796098d9c30 100644
--- a/drivers/media/rc/imon_raw.c
+++ b/drivers/media/rc/imon_raw.c
@@ -28,7 +28,7 @@ static inline int is_bit_set(const u8 *buf, int bit)
static void imon_ir_data(struct imon *imon)
{
- DEFINE_IR_RAW_EVENT(rawir);
+ struct ir_raw_event rawir = {};
int offset = 0, size = 5 * 8;
int bit;
diff --git a/drivers/media/rc/ir-hix5hd2.c b/drivers/media/rc/ir-hix5hd2.c
index 700ab4c563d0..abc4d6c1b323 100644
--- a/drivers/media/rc/ir-hix5hd2.c
+++ b/drivers/media/rc/ir-hix5hd2.c
@@ -175,7 +175,7 @@ static irqreturn_t hix5hd2_ir_rx_interrupt(int irq, void *data)
}
if ((irq_sr & INTMS_SYMBRCV) || (irq_sr & INTMS_TIMEOUT)) {
- DEFINE_IR_RAW_EVENT(ev);
+ struct ir_raw_event ev = {};
symb_num = readl_relaxed(priv->base + IR_DATAH);
for (i = 0; i < symb_num; i++) {
diff --git a/drivers/media/rc/ir-imon-decoder.c b/drivers/media/rc/ir-imon-decoder.c
index 67c1b0c15aae..a0efe2605393 100644
--- a/drivers/media/rc/ir-imon-decoder.c
+++ b/drivers/media/rc/ir-imon-decoder.c
@@ -70,24 +70,13 @@ static void ir_imon_decode_scancode(struct rc_dev *dev)
}
if (!imon->stick_keyboard) {
- struct lirc_scancode lsc = {
- .scancode = imon->bits,
- .rc_proto = RC_PROTO_IMON,
- };
+ input_report_rel(dev->input_dev, REL_X, rel_x);
+ input_report_rel(dev->input_dev, REL_Y, rel_y);
- ir_lirc_scancode_event(dev, &lsc);
-
- input_event(imon->idev, EV_MSC, MSC_SCAN, imon->bits);
-
- input_report_rel(imon->idev, REL_X, rel_x);
- input_report_rel(imon->idev, REL_Y, rel_y);
-
- input_report_key(imon->idev, BTN_LEFT,
+ input_report_key(dev->input_dev, BTN_LEFT,
(imon->bits & 0x00010000) != 0);
- input_report_key(imon->idev, BTN_RIGHT,
+ input_report_key(dev->input_dev, BTN_RIGHT,
(imon->bits & 0x00040000) != 0);
- input_sync(imon->idev);
- return;
}
}
@@ -243,62 +232,19 @@ static int ir_imon_encode(enum rc_proto protocol, u32 scancode,
static int ir_imon_register(struct rc_dev *dev)
{
- struct input_dev *idev;
struct imon_dec *imon = &dev->raw->imon;
- int ret;
-
- idev = input_allocate_device();
- if (!idev)
- return -ENOMEM;
-
- snprintf(imon->name, sizeof(imon->name),
- "iMON PAD Stick (%s)", dev->device_name);
- idev->name = imon->name;
- idev->phys = dev->input_phys;
-
- /* Mouse bits */
- set_bit(EV_REL, idev->evbit);
- set_bit(EV_KEY, idev->evbit);
- set_bit(REL_X, idev->relbit);
- set_bit(REL_Y, idev->relbit);
- set_bit(BTN_LEFT, idev->keybit);
- set_bit(BTN_RIGHT, idev->keybit);
-
- /* Report scancodes too */
- set_bit(EV_MSC, idev->evbit);
- set_bit(MSC_SCAN, idev->mscbit);
-
- input_set_drvdata(idev, imon);
-
- ret = input_register_device(idev);
- if (ret < 0) {
- input_free_device(idev);
- return -EIO;
- }
- imon->idev = idev;
imon->stick_keyboard = false;
return 0;
}
-static int ir_imon_unregister(struct rc_dev *dev)
-{
- struct imon_dec *imon = &dev->raw->imon;
-
- input_unregister_device(imon->idev);
- imon->idev = NULL;
-
- return 0;
-}
-
static struct ir_raw_handler imon_handler = {
.protocols = RC_PROTO_BIT_IMON,
.decode = ir_imon_decode,
.encode = ir_imon_encode,
.carrier = 38000,
.raw_register = ir_imon_register,
- .raw_unregister = ir_imon_unregister,
.min_timeout = IMON_UNIT * IMON_BITS * 2,
};
diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c
index 64ea42927669..67f1c179c713 100644
--- a/drivers/media/rc/ir-mce_kbd-decoder.c
+++ b/drivers/media/rc/ir-mce_kbd-decoder.c
@@ -129,13 +129,14 @@ static void mce_kbd_rx_timeout(struct timer_list *t)
if (time_is_before_eq_jiffies(raw->mce_kbd.rx_timeout.expires)) {
for (i = 0; i < 7; i++) {
maskcode = kbd_keycodes[MCIR2_MASK_KEYS_START + i];
- input_report_key(raw->mce_kbd.idev, maskcode, 0);
+ input_report_key(raw->dev->input_dev, maskcode, 0);
}
for (i = 0; i < MCIR2_MASK_KEYS_START; i++)
- input_report_key(raw->mce_kbd.idev, kbd_keycodes[i], 0);
+ input_report_key(raw->dev->input_dev, kbd_keycodes[i],
+ 0);
- input_sync(raw->mce_kbd.idev);
+ input_sync(raw->dev->input_dev);
}
spin_unlock_irqrestore(&raw->mce_kbd.keylock, flags);
}
@@ -154,7 +155,6 @@ static enum mce_kbd_mode mce_kbd_mode(struct mce_kbd_dec *data)
static void ir_mce_kbd_process_keyboard_data(struct rc_dev *dev, u32 scancode)
{
- struct mce_kbd_dec *data = &dev->raw->mce_kbd;
u8 keydata1 = (scancode >> 8) & 0xff;
u8 keydata2 = (scancode >> 16) & 0xff;
u8 shiftmask = scancode & 0xff;
@@ -170,23 +170,22 @@ static void ir_mce_kbd_process_keyboard_data(struct rc_dev *dev, u32 scancode)
keystate = 1;
else
keystate = 0;
- input_report_key(data->idev, maskcode, keystate);
+ input_report_key(dev->input_dev, maskcode, keystate);
}
if (keydata1)
- input_report_key(data->idev, kbd_keycodes[keydata1], 1);
+ input_report_key(dev->input_dev, kbd_keycodes[keydata1], 1);
if (keydata2)
- input_report_key(data->idev, kbd_keycodes[keydata2], 1);
+ input_report_key(dev->input_dev, kbd_keycodes[keydata2], 1);
if (!keydata1 && !keydata2) {
for (i = 0; i < MCIR2_MASK_KEYS_START; i++)
- input_report_key(data->idev, kbd_keycodes[i], 0);
+ input_report_key(dev->input_dev, kbd_keycodes[i], 0);
}
}
static void ir_mce_kbd_process_mouse_data(struct rc_dev *dev, u32 scancode)
{
- struct mce_kbd_dec *data = &dev->raw->mce_kbd;
/* raw mouse coordinates */
u8 xdata = (scancode >> 7) & 0x7f;
u8 ydata = (scancode >> 14) & 0x7f;
@@ -208,11 +207,11 @@ static void ir_mce_kbd_process_mouse_data(struct rc_dev *dev, u32 scancode)
dev_dbg(&dev->dev, "mouse: x = %d, y = %d, btns = %s%s\n",
x, y, left ? "L" : "", right ? "R" : "");
- input_report_rel(data->idev, REL_X, x);
- input_report_rel(data->idev, REL_Y, y);
+ input_report_rel(dev->input_dev, REL_X, x);
+ input_report_rel(dev->input_dev, REL_Y, y);
- input_report_key(data->idev, BTN_LEFT, left);
- input_report_key(data->idev, BTN_RIGHT, right);
+ input_report_key(dev->input_dev, BTN_LEFT, left);
+ input_report_key(dev->input_dev, BTN_RIGHT, right);
}
/**
@@ -355,8 +354,8 @@ again:
lsc.scancode = scancode;
ir_lirc_scancode_event(dev, &lsc);
data->state = STATE_INACTIVE;
- input_event(data->idev, EV_MSC, MSC_SCAN, scancode);
- input_sync(data->idev);
+ input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode);
+ input_sync(dev->input_dev);
return 0;
}
@@ -370,66 +369,18 @@ out:
static int ir_mce_kbd_register(struct rc_dev *dev)
{
struct mce_kbd_dec *mce_kbd = &dev->raw->mce_kbd;
- struct input_dev *idev;
- int i, ret;
-
- idev = input_allocate_device();
- if (!idev)
- return -ENOMEM;
-
- snprintf(mce_kbd->name, sizeof(mce_kbd->name),
- "MCE IR Keyboard/Mouse (%s)", dev->driver_name);
- strlcat(mce_kbd->phys, "/input0", sizeof(mce_kbd->phys));
-
- idev->name = mce_kbd->name;
- idev->phys = mce_kbd->phys;
-
- /* Keyboard bits */
- set_bit(EV_KEY, idev->evbit);
- set_bit(EV_REP, idev->evbit);
- for (i = 0; i < sizeof(kbd_keycodes); i++)
- set_bit(kbd_keycodes[i], idev->keybit);
-
- /* Mouse bits */
- set_bit(EV_REL, idev->evbit);
- set_bit(REL_X, idev->relbit);
- set_bit(REL_Y, idev->relbit);
- set_bit(BTN_LEFT, idev->keybit);
- set_bit(BTN_RIGHT, idev->keybit);
-
- /* Report scancodes too */
- set_bit(EV_MSC, idev->evbit);
- set_bit(MSC_SCAN, idev->mscbit);
timer_setup(&mce_kbd->rx_timeout, mce_kbd_rx_timeout, 0);
spin_lock_init(&mce_kbd->keylock);
- input_set_drvdata(idev, mce_kbd);
-
-#if 0
- /* Adding this reference means two input devices are associated with
- * this rc-core device, which ir-keytable doesn't cope with yet */
- idev->dev.parent = &dev->dev;
-#endif
-
- ret = input_register_device(idev);
- if (ret < 0) {
- input_free_device(idev);
- return -EIO;
- }
-
- mce_kbd->idev = idev;
-
return 0;
}
static int ir_mce_kbd_unregister(struct rc_dev *dev)
{
struct mce_kbd_dec *mce_kbd = &dev->raw->mce_kbd;
- struct input_dev *idev = mce_kbd->idev;
del_timer_sync(&mce_kbd->rx_timeout);
- input_unregister_device(idev);
return 0;
}
diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c
index 68487ce9f79b..d96aed1343e4 100644
--- a/drivers/media/rc/ir-rc6-decoder.c
+++ b/drivers/media/rc/ir-rc6-decoder.c
@@ -40,6 +40,7 @@
#define RC6_6A_MCE_TOGGLE_MASK 0x8000 /* for the body bits */
#define RC6_6A_LCC_MASK 0xffff0000 /* RC6-6A-32 long customer code mask */
#define RC6_6A_MCE_CC 0x800f0000 /* MCE customer code */
+#define RC6_6A_KATHREIN_CC 0x80460000 /* Kathrein RCU-676 customer code */
#ifndef CHAR_BIT
#define CHAR_BIT 8 /* Normally in <limits.h> */
#endif
@@ -242,13 +243,17 @@ again:
toggle = 0;
break;
case 32:
- if ((scancode & RC6_6A_LCC_MASK) == RC6_6A_MCE_CC) {
+ switch (scancode & RC6_6A_LCC_MASK) {
+ case RC6_6A_MCE_CC:
+ case RC6_6A_KATHREIN_CC:
protocol = RC_PROTO_RC6_MCE;
toggle = !!(scancode & RC6_6A_MCE_TOGGLE_MASK);
scancode &= ~RC6_6A_MCE_TOGGLE_MASK;
- } else {
+ break;
+ default:
protocol = RC_PROTO_RC6_6A_32;
toggle = 0;
+ break;
}
break;
default:
diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c
index de77d22c30a7..cd3c60ba8519 100644
--- a/drivers/media/rc/ite-cir.c
+++ b/drivers/media/rc/ite-cir.c
@@ -173,7 +173,7 @@ static void ite_decode_bytes(struct ite_dev *dev, const u8 * data, int
u32 sample_period;
unsigned long *ldata;
unsigned int next_one, next_zero, size;
- DEFINE_IR_RAW_EVENT(ev);
+ struct ir_raw_event ev = {};
if (length == 0)
return;
@@ -1507,9 +1507,6 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id
/* initialize spinlocks */
spin_lock_init(&itdev->lock);
- /* initialize raw event */
- init_ir_raw_event(&itdev->rawir);
-
/* set driver data into the pnp device */
pnp_set_drvdata(pdev, itdev);
itdev->pdev = pdev;
diff --git a/drivers/media/rc/keymaps/rc-behold.c b/drivers/media/rc/keymaps/rc-behold.c
index 9b1b57e3c875..e1b2c8e26883 100644
--- a/drivers/media/rc/keymaps/rc-behold.c
+++ b/drivers/media/rc/keymaps/rc-behold.c
@@ -115,7 +115,7 @@ static struct rc_map_list behold_map = {
.map = {
.scan = behold,
.size = ARRAY_SIZE(behold),
- .rc_proto = RC_PROTO_NEC,
+ .rc_proto = RC_PROTO_NECX,
.name = RC_MAP_BEHOLD,
}
};
diff --git a/drivers/media/rc/keymaps/rc-delock-61959.c b/drivers/media/rc/keymaps/rc-delock-61959.c
index 62de69d78d92..da21d6d6d79f 100644
--- a/drivers/media/rc/keymaps/rc-delock-61959.c
+++ b/drivers/media/rc/keymaps/rc-delock-61959.c
@@ -60,7 +60,7 @@ static struct rc_map_list delock_61959_map = {
.map = {
.scan = delock_61959,
.size = ARRAY_SIZE(delock_61959),
- .rc_proto = RC_PROTO_NEC,
+ .rc_proto = RC_PROTO_NECX,
.name = RC_MAP_DELOCK_61959,
}
};
diff --git a/drivers/media/rc/keymaps/rc-imon-rsc.c b/drivers/media/rc/keymaps/rc-imon-rsc.c
index 83e4564aaa22..6f7ee4859682 100644
--- a/drivers/media/rc/keymaps/rc-imon-rsc.c
+++ b/drivers/media/rc/keymaps/rc-imon-rsc.c
@@ -59,7 +59,7 @@ static struct rc_map_list imon_rsc_map = {
.map = {
.scan = imon_rsc,
.size = ARRAY_SIZE(imon_rsc),
- .rc_proto = RC_PROTO_NEC,
+ .rc_proto = RC_PROTO_NECX,
.name = RC_MAP_IMON_RSC,
}
};
diff --git a/drivers/media/rc/keymaps/rc-it913x-v1.c b/drivers/media/rc/keymaps/rc-it913x-v1.c
index 908d14848ae8..f1b5c52953ad 100644
--- a/drivers/media/rc/keymaps/rc-it913x-v1.c
+++ b/drivers/media/rc/keymaps/rc-it913x-v1.c
@@ -73,7 +73,7 @@ static struct rc_map_list it913x_v1_map = {
.map = {
.scan = it913x_v1_rc,
.size = ARRAY_SIZE(it913x_v1_rc),
- .rc_proto = RC_PROTO_NEC,
+ .rc_proto = RC_PROTO_NECX,
.name = RC_MAP_IT913X_V1,
}
};
diff --git a/drivers/media/rc/keymaps/rc-it913x-v2.c b/drivers/media/rc/keymaps/rc-it913x-v2.c
index 05ab7fa4f90b..be5dfb4fae46 100644
--- a/drivers/media/rc/keymaps/rc-it913x-v2.c
+++ b/drivers/media/rc/keymaps/rc-it913x-v2.c
@@ -72,7 +72,7 @@ static struct rc_map_list it913x_v2_map = {
.map = {
.scan = it913x_v2_rc,
.size = ARRAY_SIZE(it913x_v2_rc),
- .rc_proto = RC_PROTO_NEC,
+ .rc_proto = RC_PROTO_NECX,
.name = RC_MAP_IT913X_V2,
}
};
diff --git a/drivers/media/rc/keymaps/rc-msi-digivox-iii.c b/drivers/media/rc/keymaps/rc-msi-digivox-iii.c
index 8fec0c1dcb12..d50e741c73b7 100644
--- a/drivers/media/rc/keymaps/rc-msi-digivox-iii.c
+++ b/drivers/media/rc/keymaps/rc-msi-digivox-iii.c
@@ -64,7 +64,7 @@ static struct rc_map_list msi_digivox_iii_map = {
.map = {
.scan = msi_digivox_iii,
.size = ARRAY_SIZE(msi_digivox_iii),
- .rc_proto = RC_PROTO_NEC,
+ .rc_proto = RC_PROTO_NECX,
.name = RC_MAP_MSI_DIGIVOX_III,
}
};
diff --git a/drivers/media/rc/keymaps/rc-pixelview-002t.c b/drivers/media/rc/keymaps/rc-pixelview-002t.c
index 4ed85f61d0ee..c0550e09f255 100644
--- a/drivers/media/rc/keymaps/rc-pixelview-002t.c
+++ b/drivers/media/rc/keymaps/rc-pixelview-002t.c
@@ -51,7 +51,7 @@ static struct rc_map_list pixelview_map = {
.map = {
.scan = pixelview_002t,
.size = ARRAY_SIZE(pixelview_002t),
- .rc_proto = RC_PROTO_NEC,
+ .rc_proto = RC_PROTO_NECX,
.name = RC_MAP_PIXELVIEW_002T,
}
};
diff --git a/drivers/media/rc/keymaps/rc-pixelview-mk12.c b/drivers/media/rc/keymaps/rc-pixelview-mk12.c
index 6ded64b732a5..864c8ea5d8e3 100644
--- a/drivers/media/rc/keymaps/rc-pixelview-mk12.c
+++ b/drivers/media/rc/keymaps/rc-pixelview-mk12.c
@@ -57,7 +57,7 @@ static struct rc_map_list pixelview_map = {
.map = {
.scan = pixelview_mk12,
.size = ARRAY_SIZE(pixelview_mk12),
- .rc_proto = RC_PROTO_NEC,
+ .rc_proto = RC_PROTO_NECX,
.name = RC_MAP_PIXELVIEW_MK12,
}
};
diff --git a/drivers/media/rc/keymaps/rc-reddo.c b/drivers/media/rc/keymaps/rc-reddo.c
index 3b37acc7b144..b73223e8c238 100644
--- a/drivers/media/rc/keymaps/rc-reddo.c
+++ b/drivers/media/rc/keymaps/rc-reddo.c
@@ -64,7 +64,7 @@ static struct rc_map_list reddo_map = {
.map = {
.scan = reddo,
.size = ARRAY_SIZE(reddo),
- .rc_proto = RC_PROTO_NEC,
+ .rc_proto = RC_PROTO_NECX,
.name = RC_MAP_REDDO,
}
};
diff --git a/drivers/media/rc/keymaps/rc-terratec-slim.c b/drivers/media/rc/keymaps/rc-terratec-slim.c
index 628272c58d65..58a209811d12 100644
--- a/drivers/media/rc/keymaps/rc-terratec-slim.c
+++ b/drivers/media/rc/keymaps/rc-terratec-slim.c
@@ -58,7 +58,7 @@ static struct rc_map_list terratec_slim_map = {
.map = {
.scan = terratec_slim,
.size = ARRAY_SIZE(terratec_slim),
- .rc_proto = RC_PROTO_NEC,
+ .rc_proto = RC_PROTO_NECX,
.name = RC_MAP_TERRATEC_SLIM,
}
};
diff --git a/drivers/media/rc/keymaps/rc-tivo.c b/drivers/media/rc/keymaps/rc-tivo.c
index 1962e33c8f4e..20268f8b18fd 100644
--- a/drivers/media/rc/keymaps/rc-tivo.c
+++ b/drivers/media/rc/keymaps/rc-tivo.c
@@ -77,7 +77,7 @@ static struct rc_map_list tivo_map = {
.map = {
.scan = tivo,
.size = ARRAY_SIZE(tivo),
- .rc_proto = RC_PROTO_NEC,
+ .rc_proto = RC_PROTO_NEC32,
.name = RC_MAP_TIVO,
}
};
diff --git a/drivers/media/rc/keymaps/rc-total-media-in-hand.c b/drivers/media/rc/keymaps/rc-total-media-in-hand.c
index bc73bee309d8..c34e8f5a88b6 100644
--- a/drivers/media/rc/keymaps/rc-total-media-in-hand.c
+++ b/drivers/media/rc/keymaps/rc-total-media-in-hand.c
@@ -64,7 +64,7 @@ static struct rc_map_list total_media_in_hand_map = {
.map = {
.scan = total_media_in_hand,
.size = ARRAY_SIZE(total_media_in_hand),
- .rc_proto = RC_PROTO_NEC,
+ .rc_proto = RC_PROTO_NECX,
.name = RC_MAP_TOTAL_MEDIA_IN_HAND,
}
};
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index 4c0c8008872a..c9293696dc2d 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -1078,7 +1078,7 @@ static int mceusb_set_rx_carrier_report(struct rc_dev *dev, int enable)
*/
static void mceusb_handle_command(struct mceusb_dev *ir, int index)
{
- DEFINE_IR_RAW_EVENT(rawir);
+ struct ir_raw_event rawir = {};
u8 hi = ir->buf_in[index + 1] & 0xff;
u8 lo = ir->buf_in[index + 2] & 0xff;
u32 carrier_cycles;
@@ -1152,7 +1152,7 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index)
static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
{
- DEFINE_IR_RAW_EVENT(rawir);
+ struct ir_raw_event rawir = {};
bool event = false;
int i = 0;
@@ -1175,7 +1175,6 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
break;
case PARSE_IRDATA:
ir->rem--;
- init_ir_raw_event(&rawir);
rawir.pulse = ((ir->buf_in[i] & MCE_PULSE_BIT) != 0);
rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK);
if (unlikely(!rawir.duration)) {
@@ -1215,11 +1214,13 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
if (ir->rem) {
ir->parser_state = PARSE_IRDATA;
} else {
- init_ir_raw_event(&rawir);
- rawir.timeout = 1;
- rawir.duration = ir->rc->timeout;
+ struct ir_raw_event ev = {
+ .timeout = 1,
+ .duration = ir->rc->timeout
+ };
+
if (ir_raw_event_store_with_filter(ir->rc,
- &rawir))
+ &ev))
event = true;
ir->pulse_tunit = 0;
ir->pulse_count = 0;
@@ -1603,7 +1604,7 @@ static int mceusb_dev_probe(struct usb_interface *intf,
if (dev->descriptor.iManufacturer
&& usb_string(dev, dev->descriptor.iManufacturer,
buf, sizeof(buf)) > 0)
- strlcpy(name, buf, sizeof(name));
+ strscpy(name, buf, sizeof(name));
if (dev->descriptor.iProduct
&& usb_string(dev, dev->descriptor.iProduct,
buf, sizeof(buf)) > 0)
diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c
index f449b35d25e7..9914c83fecb9 100644
--- a/drivers/media/rc/meson-ir.c
+++ b/drivers/media/rc/meson-ir.c
@@ -86,7 +86,7 @@ static irqreturn_t meson_ir_irq(int irqno, void *dev_id)
{
struct meson_ir *ir = dev_id;
u32 duration, status;
- DEFINE_IR_RAW_EVENT(rawir);
+ struct ir_raw_event rawir = {};
spin_lock(&ir->lock);
diff --git a/drivers/media/rc/mtk-cir.c b/drivers/media/rc/mtk-cir.c
index e42efd9d382e..31b7bb431497 100644
--- a/drivers/media/rc/mtk-cir.c
+++ b/drivers/media/rc/mtk-cir.c
@@ -212,7 +212,7 @@ static irqreturn_t mtk_ir_irq(int irqno, void *dev_id)
struct mtk_ir *ir = dev_id;
u8 wid = 0;
u32 i, j, val;
- DEFINE_IR_RAW_EVENT(rawir);
+ struct ir_raw_event rawir = {};
/*
* Reset decoder state machine explicitly is required
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
index b8299c9a9744..5c2cd8d2d155 100644
--- a/drivers/media/rc/nuvoton-cir.c
+++ b/drivers/media/rc/nuvoton-cir.c
@@ -737,7 +737,7 @@ static void nvt_dump_rx_buf(struct nvt_dev *nvt)
*/
static void nvt_process_rx_ir_data(struct nvt_dev *nvt)
{
- DEFINE_IR_RAW_EVENT(rawir);
+ struct ir_raw_event rawir = {};
u8 sample;
int i;
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index e847bdad5c51..c2cbe7f6266c 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -110,12 +110,9 @@ struct ir_raw_event_ctrl {
unsigned int pulse_len;
} sharp;
struct mce_kbd_dec {
- struct input_dev *idev;
/* locks key up timer */
spinlock_t keylock;
struct timer_list rx_timeout;
- char name[64];
- char phys[64];
int state;
u8 header;
u32 body;
@@ -133,8 +130,6 @@ struct ir_raw_event_ctrl {
int last_chk;
unsigned int bits;
bool stick_keyboard;
- struct input_dev *idev;
- char name[64];
} imon;
};
@@ -181,9 +176,10 @@ static inline void init_ir_raw_event_duration(struct ir_raw_event *ev,
unsigned int pulse,
u32 duration)
{
- init_ir_raw_event(ev);
- ev->duration = duration;
- ev->pulse = pulse;
+ *ev = (struct ir_raw_event) {
+ .duration = duration,
+ .pulse = pulse
+ };
}
/**
diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
index e7948908e78c..e10b4644a442 100644
--- a/drivers/media/rc/rc-ir-raw.c
+++ b/drivers/media/rc/rc-ir-raw.c
@@ -102,7 +102,7 @@ EXPORT_SYMBOL_GPL(ir_raw_event_store);
int ir_raw_event_store_edge(struct rc_dev *dev, bool pulse)
{
ktime_t now;
- DEFINE_IR_RAW_EVENT(ev);
+ struct ir_raw_event ev = {};
if (!dev->raw)
return -EINVAL;
@@ -210,7 +210,7 @@ void ir_raw_event_set_idle(struct rc_dev *dev, bool idle)
if (idle) {
dev->raw->this_ev.timeout = true;
ir_raw_event_store(dev, &dev->raw->this_ev);
- init_ir_raw_event(&dev->raw->this_ev);
+ dev->raw->this_ev = (struct ir_raw_event) {};
}
if (dev->s_idle)
@@ -562,10 +562,10 @@ static void ir_raw_edge_handle(struct timer_list *t)
spin_lock_irqsave(&dev->raw->edge_spinlock, flags);
interval = ktime_sub(ktime_get(), dev->raw->last_event);
if (ktime_to_ns(interval) >= dev->timeout) {
- DEFINE_IR_RAW_EVENT(ev);
-
- ev.timeout = true;
- ev.duration = ktime_to_ns(interval);
+ struct ir_raw_event ev = {
+ .timeout = true,
+ .duration = ktime_to_ns(interval)
+ };
ir_raw_event_store(dev, &ev);
} else {
diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
index 3822d9ebcb46..b9f9325b8db1 100644
--- a/drivers/media/rc/rc-loopback.c
+++ b/drivers/media/rc/rc-loopback.c
@@ -103,7 +103,7 @@ static int loop_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
struct loopback_dev *lodev = dev->priv;
u32 rxmask;
unsigned i;
- DEFINE_IR_RAW_EVENT(rawir);
+ struct ir_raw_event rawir = {};
if (lodev->txcarrier < lodev->rxcarriermin ||
lodev->txcarrier > lodev->rxcarriermax) {
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index ca68e1d2b2f9..552bbe82a160 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -274,7 +274,6 @@ static unsigned int ir_update_mapping(struct rc_dev *dev,
unsigned int new_keycode)
{
int old_keycode = rc_map->scan[index].keycode;
- int i;
/* Did the user wish to remove the mapping? */
if (new_keycode == KEY_RESERVED || new_keycode == KEY_UNKNOWN) {
@@ -289,20 +288,9 @@ static unsigned int ir_update_mapping(struct rc_dev *dev,
old_keycode == KEY_RESERVED ? "New" : "Replacing",
rc_map->scan[index].scancode, new_keycode);
rc_map->scan[index].keycode = new_keycode;
- __set_bit(new_keycode, dev->input_dev->keybit);
}
if (old_keycode != KEY_RESERVED) {
- /* A previous mapping was updated... */
- __clear_bit(old_keycode, dev->input_dev->keybit);
- /* ... but another scancode might use the same keycode */
- for (i = 0; i < rc_map->len; i++) {
- if (rc_map->scan[i].keycode == old_keycode) {
- __set_bit(old_keycode, dev->input_dev->keybit);
- break;
- }
- }
-
/* Possibly shrink the keytable, failure is not a problem */
ir_resize_table(dev, rc_map, GFP_ATOMIC);
}
@@ -1755,10 +1743,18 @@ static int rc_prepare_rx_device(struct rc_dev *dev)
dev->enabled_protocols = rc_proto;
}
+ /* Keyboard events */
set_bit(EV_KEY, dev->input_dev->evbit);
set_bit(EV_REP, dev->input_dev->evbit);
set_bit(EV_MSC, dev->input_dev->evbit);
set_bit(MSC_SCAN, dev->input_dev->mscbit);
+ bitmap_fill(dev->input_dev->keybit, KEY_CNT);
+
+ /* Pointer/mouse events */
+ set_bit(EV_REL, dev->input_dev->evbit);
+ set_bit(REL_X, dev->input_dev->relbit);
+ set_bit(REL_Y, dev->input_dev->relbit);
+
if (dev->open)
dev->input_dev->open = ir_open;
if (dev->close)
diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c
index 6bfc24885b5c..08c51ffd74a0 100644
--- a/drivers/media/rc/redrat3.c
+++ b/drivers/media/rc/redrat3.c
@@ -348,7 +348,7 @@ static u32 redrat3_us_to_len(u32 microsec)
static void redrat3_process_ir_data(struct redrat3_dev *rr3)
{
- DEFINE_IR_RAW_EVENT(rawir);
+ struct ir_raw_event rawir = {};
struct device *dev;
unsigned int i, sig_size, single_len, offset, val;
u32 mod_freq;
@@ -358,10 +358,10 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3)
mod_freq = redrat3_val_to_mod_freq(&rr3->irdata);
dev_dbg(dev, "Got mod_freq of %u\n", mod_freq);
if (mod_freq && rr3->wideband) {
- DEFINE_IR_RAW_EVENT(ev);
-
- ev.carrier_report = 1;
- ev.carrier = mod_freq;
+ struct ir_raw_event ev = {
+ .carrier_report = 1,
+ .carrier = mod_freq
+ };
ir_raw_event_store(rr3->rc, &ev);
}
diff --git a/drivers/media/rc/serial_ir.c b/drivers/media/rc/serial_ir.c
index 8bf5637b3a69..ffe2c672d105 100644
--- a/drivers/media/rc/serial_ir.c
+++ b/drivers/media/rc/serial_ir.c
@@ -273,7 +273,7 @@ static void frbwrite(unsigned int l, bool is_pulse)
{
/* simple noise filter */
static unsigned int ptr, pulse, space;
- DEFINE_IR_RAW_EVENT(ev);
+ struct ir_raw_event ev = {};
if (ptr > 0 && is_pulse) {
pulse += l;
@@ -472,10 +472,10 @@ static int hardware_init_port(void)
static void serial_ir_timeout(struct timer_list *unused)
{
- DEFINE_IR_RAW_EVENT(ev);
-
- ev.timeout = true;
- ev.duration = serial_ir.rcdev->timeout;
+ struct ir_raw_event ev = {
+ .timeout = true,
+ .duration = serial_ir.rcdev->timeout
+ };
ir_raw_event_store_with_filter(serial_ir.rcdev, &ev);
ir_raw_event_handle(serial_ir.rcdev);
}
diff --git a/drivers/media/rc/sir_ir.c b/drivers/media/rc/sir_ir.c
index 9ee2c9196b4d..c8951650a368 100644
--- a/drivers/media/rc/sir_ir.c
+++ b/drivers/media/rc/sir_ir.c
@@ -96,7 +96,7 @@ static int sir_tx_ir(struct rc_dev *dev, unsigned int *tx_buf,
static void add_read_queue(int flag, unsigned long val)
{
- DEFINE_IR_RAW_EVENT(ev);
+ struct ir_raw_event ev = {};
pr_debug("add flag %d with val %lu\n", flag, val);
diff --git a/drivers/media/rc/st_rc.c b/drivers/media/rc/st_rc.c
index c855b177103c..15de3ae166a2 100644
--- a/drivers/media/rc/st_rc.c
+++ b/drivers/media/rc/st_rc.c
@@ -67,8 +67,7 @@ struct st_rc_device {
static void st_rc_send_lirc_timeout(struct rc_dev *rdev)
{
- DEFINE_IR_RAW_EVENT(ev);
- ev.timeout = true;
+ struct ir_raw_event ev = { .timeout = true, .duration = rdev->timeout };
ir_raw_event_store(rdev, &ev);
}
@@ -101,7 +100,7 @@ static irqreturn_t st_rc_rx_interrupt(int irq, void *data)
struct st_rc_device *dev = data;
int last_symbol = 0;
u32 status, int_status;
- DEFINE_IR_RAW_EVENT(ev);
+ struct ir_raw_event ev = {};
if (dev->irq_wake)
pm_wakeup_event(dev->dev, 0);
diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c
index c9a70fda88a8..a490d26bd170 100644
--- a/drivers/media/rc/streamzap.c
+++ b/drivers/media/rc/streamzap.c
@@ -130,7 +130,7 @@ static void sz_push(struct streamzap_ir *sz, struct ir_raw_event rawir)
static void sz_push_full_pulse(struct streamzap_ir *sz,
unsigned char value)
{
- DEFINE_IR_RAW_EVENT(rawir);
+ struct ir_raw_event rawir = {};
if (sz->idle) {
int delta;
@@ -175,7 +175,7 @@ static void sz_push_half_pulse(struct streamzap_ir *sz,
static void sz_push_full_space(struct streamzap_ir *sz,
unsigned char value)
{
- DEFINE_IR_RAW_EVENT(rawir);
+ struct ir_raw_event rawir = {};
rawir.pulse = false;
rawir.duration = ((int) value) * SZ_RESOLUTION;
@@ -249,10 +249,10 @@ static void streamzap_callback(struct urb *urb)
break;
case FullSpace:
if (sz->buf_in[i] == SZ_TIMEOUT) {
- DEFINE_IR_RAW_EVENT(rawir);
-
- rawir.pulse = false;
- rawir.duration = sz->rdev->timeout;
+ struct ir_raw_event rawir = {
+ .pulse = false,
+ .duration = sz->rdev->timeout
+ };
sz->idle = true;
if (sz->timeout_enabled)
sz_push(sz, rawir);
@@ -396,7 +396,7 @@ static int streamzap_probe(struct usb_interface *intf,
if (usbdev->descriptor.iManufacturer
&& usb_string(usbdev, usbdev->descriptor.iManufacturer,
buf, sizeof(buf)) > 0)
- strlcpy(name, buf, sizeof(name));
+ strscpy(name, buf, sizeof(name));
if (usbdev->descriptor.iProduct
&& usb_string(usbdev, usbdev->descriptor.iProduct,
diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c
index f500cea228a9..307e44714ea0 100644
--- a/drivers/media/rc/sunxi-cir.c
+++ b/drivers/media/rc/sunxi-cir.c
@@ -99,7 +99,7 @@ static irqreturn_t sunxi_ir_irq(int irqno, void *dev_id)
unsigned char dt;
unsigned int cnt, rc;
struct sunxi_ir *ir = dev_id;
- DEFINE_IR_RAW_EVENT(rawir);
+ struct ir_raw_event rawir = {};
spin_lock(&ir->ir_lock);
diff --git a/drivers/media/rc/ttusbir.c b/drivers/media/rc/ttusbir.c
index aafea3c5170b..8d4b56d057ae 100644
--- a/drivers/media/rc/ttusbir.c
+++ b/drivers/media/rc/ttusbir.c
@@ -117,12 +117,10 @@ static void ttusbir_bulk_complete(struct urb *urb)
*/
static void ttusbir_process_ir_data(struct ttusbir *tt, uint8_t *buf)
{
- struct ir_raw_event rawir;
+ struct ir_raw_event rawir = {};
unsigned i, v, b;
bool event = false;
- init_ir_raw_event(&rawir);
-
for (i = 0; i < 128; i++) {
v = buf[i] & 0xfe;
switch (v) {
diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c
index 851acba9b436..0f07a2c384fa 100644
--- a/drivers/media/rc/winbond-cir.c
+++ b/drivers/media/rc/winbond-cir.c
@@ -322,11 +322,11 @@ wbcir_carrier_report(struct wbcir_data *data)
inb(data->ebase + WBCIR_REG_ECEIR_CNT_HI) << 8;
if (counter > 0 && counter < 0xffff) {
- DEFINE_IR_RAW_EVENT(ev);
-
- ev.carrier_report = 1;
- ev.carrier = DIV_ROUND_CLOSEST(counter * 1000000u,
- data->pulse_duration);
+ struct ir_raw_event ev = {
+ .carrier_report = 1,
+ .carrier = DIV_ROUND_CLOSEST(counter * 1000000u,
+ data->pulse_duration)
+ };
ir_raw_event_store(data->dev, &ev);
}
@@ -362,7 +362,7 @@ static void
wbcir_irq_rx(struct wbcir_data *data, struct pnp_dev *device)
{
u8 irdata;
- DEFINE_IR_RAW_EVENT(rawir);
+ struct ir_raw_event rawir = {};
unsigned duration;
/* Since RXHDLEV is set, at least 8 bytes are in the FIFO */
diff --git a/drivers/media/tuners/e4000.c b/drivers/media/tuners/e4000.c
index fbec1a13dc6a..91956fb55b75 100644
--- a/drivers/media/tuners/e4000.c
+++ b/drivers/media/tuners/e4000.c
@@ -312,7 +312,7 @@ static int e4000_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v)
dev_dbg(&client->dev, "index=%d\n", v->index);
- strlcpy(v->name, "Elonics E4000", sizeof(v->name));
+ strscpy(v->name, "Elonics E4000", sizeof(v->name));
v->type = V4L2_TUNER_RF;
v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
v->rangelow = bands[0].rangelow;
diff --git a/drivers/media/tuners/fc2580.c b/drivers/media/tuners/fc2580.c
index db26892aac84..dd88cf7148d0 100644
--- a/drivers/media/tuners/fc2580.c
+++ b/drivers/media/tuners/fc2580.c
@@ -405,7 +405,7 @@ static int fc2580_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v)
dev_dbg(&client->dev, "index=%d\n", v->index);
- strlcpy(v->name, "FCI FC2580", sizeof(v->name));
+ strscpy(v->name, "FCI FC2580", sizeof(v->name));
v->type = V4L2_TUNER_RF;
v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
v->rangelow = bands[0].rangelow;
diff --git a/drivers/media/tuners/msi001.c b/drivers/media/tuners/msi001.c
index 5de6ed728708..331c198c00bb 100644
--- a/drivers/media/tuners/msi001.c
+++ b/drivers/media/tuners/msi001.c
@@ -305,7 +305,7 @@ static int msi001_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v)
dev_dbg(&spi->dev, "index=%d\n", v->index);
- strlcpy(v->name, "Mirics MSi001", sizeof(v->name));
+ strscpy(v->name, "Mirics MSi001", sizeof(v->name));
v->type = V4L2_TUNER_RF;
v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
v->rangelow = 49000000;
diff --git a/drivers/media/tuners/mt20xx.c b/drivers/media/tuners/mt20xx.c
index 129bf8e1aff8..8b4ce84b6914 100644
--- a/drivers/media/tuners/mt20xx.c
+++ b/drivers/media/tuners/mt20xx.c
@@ -636,7 +636,7 @@ struct dvb_frontend *microtune_attach(struct dvb_frontend *fe,
return NULL;
}
- strlcpy(fe->ops.tuner_ops.info.name, name,
+ strscpy(fe->ops.tuner_ops.info.name, name,
sizeof(fe->ops.tuner_ops.info.name));
tuner_info("microtune %s found, OK\n",name);
return fe;
diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c
index a08d8fe2bb1b..d389f1fc237a 100644
--- a/drivers/media/tuners/si2157.c
+++ b/drivers/media/tuners/si2157.c
@@ -468,11 +468,14 @@ static int si2157_probe(struct i2c_client *client,
dev->ent.name = KBUILD_MODNAME;
dev->ent.function = MEDIA_ENT_F_TUNER;
- dev->pad[TUNER_PAD_RF_INPUT].flags = MEDIA_PAD_FL_SINK;
- dev->pad[TUNER_PAD_OUTPUT].flags = MEDIA_PAD_FL_SOURCE;
- dev->pad[TUNER_PAD_AUD_OUT].flags = MEDIA_PAD_FL_SOURCE;
-
- ret = media_entity_pads_init(&dev->ent, TUNER_NUM_PADS,
+ dev->pad[SI2157_PAD_RF_INPUT].flags = MEDIA_PAD_FL_SINK;
+ dev->pad[SI2157_PAD_RF_INPUT].sig_type = PAD_SIGNAL_ANALOG;
+ dev->pad[SI2157_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE;
+ dev->pad[SI2157_PAD_VID_OUT].sig_type = PAD_SIGNAL_ANALOG;
+ dev->pad[SI2157_PAD_AUD_OUT].flags = MEDIA_PAD_FL_SOURCE;
+ dev->pad[SI2157_PAD_AUD_OUT].sig_type = PAD_SIGNAL_AUDIO;
+
+ ret = media_entity_pads_init(&dev->ent, SI2157_NUM_PADS,
&dev->pad[0]);
if (ret)
diff --git a/drivers/media/tuners/si2157_priv.h b/drivers/media/tuners/si2157_priv.h
index e6436f74abaa..50f86300d965 100644
--- a/drivers/media/tuners/si2157_priv.h
+++ b/drivers/media/tuners/si2157_priv.h
@@ -21,6 +21,13 @@
#include <media/v4l2-mc.h>
#include "si2157.h"
+enum si2157_pads {
+ SI2157_PAD_RF_INPUT,
+ SI2157_PAD_VID_OUT,
+ SI2157_PAD_AUD_OUT,
+ SI2157_NUM_PADS
+};
+
/* state struct */
struct si2157_dev {
struct mutex i2c_mutex;
@@ -35,7 +42,7 @@ struct si2157_dev {
#if defined(CONFIG_MEDIA_CONTROLLER)
struct media_device *mdev;
struct media_entity ent;
- struct media_pad pad[TUNER_NUM_PADS];
+ struct media_pad pad[SI2157_NUM_PADS];
#endif
};
diff --git a/drivers/media/tuners/tuner-simple.c b/drivers/media/tuners/tuner-simple.c
index 29c1473f2e9f..d2169bb3111a 100644
--- a/drivers/media/tuners/tuner-simple.c
+++ b/drivers/media/tuners/tuner-simple.c
@@ -1130,7 +1130,7 @@ struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
priv->nr, dtv_input[priv->nr]);
}
- strlcpy(fe->ops.tuner_ops.info.name, priv->tun->name,
+ strscpy(fe->ops.tuner_ops.info.name, priv->tun->name,
sizeof(fe->ops.tuner_ops.info.name));
return fe;
diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c
index e70c9e2f3798..41fa0f93143d 100644
--- a/drivers/media/usb/airspy/airspy.c
+++ b/drivers/media/usb/airspy/airspy.c
@@ -619,8 +619,8 @@ static int airspy_querycap(struct file *file, void *fh,
{
struct airspy *s = video_drvdata(file);
- strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
- strlcpy(cap->card, s->vdev.name, sizeof(cap->card));
+ strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
+ strscpy(cap->card, s->vdev.name, sizeof(cap->card));
usb_make_path(s->udev, cap->bus_info, sizeof(cap->bus_info));
cap->device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_STREAMING |
V4L2_CAP_READWRITE | V4L2_CAP_TUNER;
@@ -635,7 +635,7 @@ static int airspy_enum_fmt_sdr_cap(struct file *file, void *priv,
if (f->index >= NUM_FORMATS)
return -EINVAL;
- strlcpy(f->description, formats[f->index].name, sizeof(f->description));
+ strscpy(f->description, formats[f->index].name, sizeof(f->description));
f->pixelformat = formats[f->index].pixelformat;
return 0;
@@ -720,14 +720,14 @@ static int airspy_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
int ret;
if (v->index == 0) {
- strlcpy(v->name, "AirSpy ADC", sizeof(v->name));
+ strscpy(v->name, "AirSpy ADC", sizeof(v->name));
v->type = V4L2_TUNER_ADC;
v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
v->rangelow = bands[0].rangelow;
v->rangehigh = bands[0].rangehigh;
ret = 0;
} else if (v->index == 1) {
- strlcpy(v->name, "AirSpy RF", sizeof(v->name));
+ strscpy(v->name, "AirSpy RF", sizeof(v->name));
v->type = V4L2_TUNER_RF;
v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
v->rangelow = bands_rf[0].rangelow;
diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c
index cd363a2100d4..1fdb1601dc65 100644
--- a/drivers/media/usb/au0828/au0828-core.c
+++ b/drivers/media/usb/au0828/au0828-core.c
@@ -266,11 +266,13 @@ static void au0828_media_graph_notify(struct media_entity *new,
create_link:
if (decoder && mixer) {
- ret = media_create_pad_link(decoder,
- DEMOD_PAD_AUDIO_OUT,
- mixer, 0,
- MEDIA_LNK_FL_ENABLED);
- if (ret)
+ ret = media_get_pad_index(decoder, false,
+ PAD_SIGNAL_AUDIO);
+ if (ret >= 0)
+ ret = media_create_pad_link(decoder, ret,
+ mixer, 0,
+ MEDIA_LNK_FL_ENABLED);
+ if (ret < 0)
dev_err(&dev->usbdev->dev,
"Mixer Pad Link Create Error: %d\n", ret);
}
@@ -626,17 +628,16 @@ static int au0828_usb_probe(struct usb_interface *interface,
/* Analog TV */
retval = au0828_analog_register(dev, interface);
if (retval) {
- pr_err("%s() au0282_dev_register failed to register on V4L2\n",
+ pr_err("%s() au0828_analog_register failed to register on V4L2\n",
__func__);
mutex_unlock(&dev->lock);
- kfree(dev);
goto done;
}
/* Digital TV */
retval = au0828_dvb_register(dev);
if (retval)
- pr_err("%s() au0282_dev_register failed\n",
+ pr_err("%s() au0828_dvb_register failed\n",
__func__);
/* Remote controller */
diff --git a/drivers/media/usb/au0828/au0828-i2c.c b/drivers/media/usb/au0828/au0828-i2c.c
index 1b8ec5d9e7ab..92df5b5463af 100644
--- a/drivers/media/usb/au0828/au0828-i2c.c
+++ b/drivers/media/usb/au0828/au0828-i2c.c
@@ -378,7 +378,7 @@ int au0828_i2c_register(struct au0828_dev *dev)
dev->i2c_adap.dev.parent = &dev->usbdev->dev;
- strlcpy(dev->i2c_adap.name, KBUILD_MODNAME,
+ strscpy(dev->i2c_adap.name, KBUILD_MODNAME,
sizeof(dev->i2c_adap.name));
dev->i2c_adap.algo = &dev->i2c_algo;
diff --git a/drivers/media/usb/au0828/au0828-input.c b/drivers/media/usb/au0828/au0828-input.c
index 832ed9f25784..4befa920246c 100644
--- a/drivers/media/usb/au0828/au0828-input.c
+++ b/drivers/media/usb/au0828/au0828-input.c
@@ -113,7 +113,7 @@ static int au8522_rc_andor(struct au0828_rc *ir, u16 reg, u8 mask, u8 value)
static int au0828_get_key_au8522(struct au0828_rc *ir)
{
unsigned char buf[40];
- DEFINE_IR_RAW_EVENT(rawir);
+ struct ir_raw_event rawir = {};
int i, j, rc;
int prv_bit, bit, width;
bool first = true;
@@ -167,7 +167,6 @@ static int au0828_get_key_au8522(struct au0828_rc *ir)
if (first) {
first = false;
- init_ir_raw_event(&rawir);
rawir.pulse = true;
if (width > NEC_START_SPACE - 2 &&
width < NEC_START_SPACE + 2) {
@@ -186,7 +185,6 @@ static int au0828_get_key_au8522(struct au0828_rc *ir)
ir_raw_event_store(ir->rc, &rawir);
}
- init_ir_raw_event(&rawir);
rawir.pulse = prv_bit ? false : true;
rawir.duration = AU8522_UNIT * width;
dprintk(16, "Storing %s with duration %d",
@@ -199,7 +197,6 @@ static int au0828_get_key_au8522(struct au0828_rc *ir)
}
}
- init_ir_raw_event(&rawir);
rawir.pulse = prv_bit ? false : true;
rawir.duration = AU8522_UNIT * width;
dprintk(16, "Storing end %s with duration %d",
diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c
index 62b45062b1e6..efbf210147c7 100644
--- a/drivers/media/usb/au0828/au0828-video.c
+++ b/drivers/media/usb/au0828/au0828-video.c
@@ -1191,8 +1191,8 @@ static int vidioc_querycap(struct file *file, void *priv,
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
dev->std_set_in_tuner_core, dev->dev_state);
- strlcpy(cap->driver, "au0828", sizeof(cap->driver));
- strlcpy(cap->card, dev->board.name, sizeof(cap->card));
+ strscpy(cap->driver, "au0828", sizeof(cap->driver));
+ strscpy(cap->card, dev->board.name, sizeof(cap->card));
usb_make_path(dev->usbdev, cap->bus_info, sizeof(cap->bus_info));
/* set the device capabilities */
@@ -1218,7 +1218,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
dprintk(1, "%s called\n", __func__);
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- strcpy(f->description, "Packed YUV2");
+ strscpy(f->description, "Packed YUV2", sizeof(f->description));
f->flags = 0;
f->pixelformat = V4L2_PIX_FMT_UYVY;
@@ -1349,7 +1349,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
return -EINVAL;
input->index = tmp;
- strcpy(input->name, inames[AUVI_INPUT(tmp).type]);
+ strscpy(input->name, inames[AUVI_INPUT(tmp).type], sizeof(input->name));
if ((AUVI_INPUT(tmp).type == AU0828_VMUX_TELEVISION) ||
(AUVI_INPUT(tmp).type == AU0828_VMUX_CABLE)) {
input->type |= V4L2_INPUT_TYPE_TUNER;
@@ -1465,9 +1465,9 @@ static int vidioc_enumaudio(struct file *file, void *priv, struct v4l2_audio *a)
dprintk(1, "%s called\n", __func__);
if (a->index == 0)
- strcpy(a->name, "Television");
+ strscpy(a->name, "Television", sizeof(a->name));
else
- strcpy(a->name, "Line in");
+ strscpy(a->name, "Line in", sizeof(a->name));
a->capability = V4L2_AUDCAP_STEREO;
return 0;
@@ -1482,9 +1482,9 @@ static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
a->index = dev->ctrl_ainput;
if (a->index == 0)
- strcpy(a->name, "Television");
+ strscpy(a->name, "Television", sizeof(a->name));
else
- strcpy(a->name, "Line in");
+ strscpy(a->name, "Line in", sizeof(a->name));
a->capability = V4L2_AUDCAP_STEREO;
return 0;
@@ -1518,7 +1518,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
dev->std_set_in_tuner_core, dev->dev_state);
- strcpy(t->name, "Auvitek tuner");
+ strscpy(t->name, "Auvitek tuner", sizeof(t->name));
au0828_init_tuner(dev);
i2c_gate_ctrl(dev, 1);
@@ -1978,7 +1978,7 @@ int au0828_analog_register(struct au0828_dev *dev,
dev->vdev.lock = &dev->lock;
dev->vdev.queue = &dev->vb_vidq;
dev->vdev.queue->lock = &dev->vb_queue_lock;
- strcpy(dev->vdev.name, "au0828a video");
+ strscpy(dev->vdev.name, "au0828a video", sizeof(dev->vdev.name));
/* Setup the VBI device */
dev->vbi_dev = au0828_video_template;
@@ -1986,7 +1986,7 @@ int au0828_analog_register(struct au0828_dev *dev,
dev->vbi_dev.lock = &dev->lock;
dev->vbi_dev.queue = &dev->vb_vbiq;
dev->vbi_dev.queue->lock = &dev->vb_vbi_queue_lock;
- strcpy(dev->vbi_dev.name, "au0828a vbi");
+ strscpy(dev->vbi_dev.name, "au0828a vbi", sizeof(dev->vbi_dev.name));
/* Init entities at the Media Controller */
au0828_analog_create_entities(dev);
diff --git a/drivers/media/usb/cpia2/cpia2_v4l.c b/drivers/media/usb/cpia2/cpia2_v4l.c
index 99f106b13280..3f401fbd0ecc 100644
--- a/drivers/media/usb/cpia2/cpia2_v4l.c
+++ b/drivers/media/usb/cpia2/cpia2_v4l.c
@@ -219,12 +219,12 @@ static int cpia2_querycap(struct file *file, void *fh, struct v4l2_capability *v
{
struct camera_data *cam = video_drvdata(file);
- strcpy(vc->driver, "cpia2");
+ strscpy(vc->driver, "cpia2", sizeof(vc->driver));
if (cam->params.pnp_id.product == 0x151)
- strcpy(vc->card, "QX5 Microscope");
+ strscpy(vc->card, "QX5 Microscope", sizeof(vc->card));
else
- strcpy(vc->card, "CPiA2 Camera");
+ strscpy(vc->card, "CPiA2 Camera", sizeof(vc->card));
switch (cam->params.pnp_id.device_type) {
case DEVICE_STV_672:
strcat(vc->card, " (672/");
@@ -281,7 +281,7 @@ static int cpia2_enum_input(struct file *file, void *fh, struct v4l2_input *i)
{
if (i->index)
return -EINVAL;
- strcpy(i->name, "Camera");
+ strscpy(i->name, "Camera", sizeof(i->name));
i->type = V4L2_INPUT_TYPE_CAMERA;
return 0;
}
@@ -319,11 +319,11 @@ static int cpia2_enum_fmt_vid_cap(struct file *file, void *fh,
f->flags = V4L2_FMT_FLAG_COMPRESSED;
switch(index) {
case 0:
- strcpy(f->description, "MJPEG");
+ strscpy(f->description, "MJPEG", sizeof(f->description));
f->pixelformat = V4L2_PIX_FMT_MJPEG;
break;
case 1:
- strcpy(f->description, "JPEG");
+ strscpy(f->description, "JPEG", sizeof(f->description));
f->pixelformat = V4L2_PIX_FMT_JPEG;
break;
default:
@@ -949,7 +949,7 @@ static int cpia2_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer;
buf->length = cam->frame_size;
buf->reserved2 = 0;
- buf->reserved = 0;
+ buf->request_fd = 0;
memset(&buf->timecode, 0, sizeof(buf->timecode));
DBG("DQBUF #%d status:%d seq:%d length:%d\n", buf->index,
diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c
index 2f3b0564d676..2641e23d946b 100644
--- a/drivers/media/usb/cx231xx/cx231xx-417.c
+++ b/drivers/media/usb/cx231xx/cx231xx-417.c
@@ -1583,7 +1583,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
if (f->index != 0)
return -EINVAL;
- strlcpy(f->description, "MPEG", sizeof(f->description));
+ strscpy(f->description, "MPEG", sizeof(f->description));
f->pixelformat = V4L2_PIX_FMT_MPEG;
return 0;
@@ -1992,7 +1992,7 @@ int cx231xx_417_register(struct cx231xx *dev)
dev->mpeg_ctrl_handler.ops = &cx231xx_ops;
if (dev->sd_cx25840)
v4l2_ctrl_add_handler(&dev->mpeg_ctrl_handler.hdl,
- dev->sd_cx25840->ctrl_handler, NULL);
+ dev->sd_cx25840->ctrl_handler, NULL, false);
if (dev->mpeg_ctrl_handler.hdl.error) {
err = dev->mpeg_ctrl_handler.hdl.error;
dprintk(3, "%s: can't add cx25840 controls\n", dev->name);
diff --git a/drivers/media/usb/cx231xx/cx231xx-audio.c b/drivers/media/usb/cx231xx/cx231xx-audio.c
index 32ee7b3f21c9..77f2c65eb79a 100644
--- a/drivers/media/usb/cx231xx/cx231xx-audio.c
+++ b/drivers/media/usb/cx231xx/cx231xx-audio.c
@@ -679,10 +679,10 @@ static int cx231xx_audio_init(struct cx231xx *dev)
&snd_cx231xx_pcm_capture);
pcm->info_flags = 0;
pcm->private_data = dev;
- strcpy(pcm->name, "Conexant cx231xx Capture");
- strcpy(card->driver, "Cx231xx-Audio");
- strcpy(card->shortname, "Cx231xx Audio");
- strcpy(card->longname, "Conexant cx231xx Audio");
+ strscpy(pcm->name, "Conexant cx231xx Capture", sizeof(pcm->name));
+ strscpy(card->driver, "Cx231xx-Audio", sizeof(card->driver));
+ strscpy(card->shortname, "Cx231xx Audio", sizeof(card->shortname));
+ strscpy(card->longname, "Conexant cx231xx Audio", sizeof(card->longname));
INIT_WORK(&dev->wq_trigger, audio_trigger);
diff --git a/drivers/media/usb/cx231xx/cx231xx-input.c b/drivers/media/usb/cx231xx/cx231xx-input.c
index 3e9b73a6b7c9..9f88c640ec2b 100644
--- a/drivers/media/usb/cx231xx/cx231xx-input.c
+++ b/drivers/media/usb/cx231xx/cx231xx-input.c
@@ -67,7 +67,7 @@ int cx231xx_ir_init(struct cx231xx *dev)
dev->init_data.name = cx231xx_boards[dev->model].name;
- strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+ strscpy(info.type, "ir_video", I2C_NAME_SIZE);
info.platform_data = &dev->init_data;
/*
diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c
index f7fcd733a2ca..c990f70c0ea6 100644
--- a/drivers/media/usb/cx231xx/cx231xx-video.c
+++ b/drivers/media/usb/cx231xx/cx231xx-video.c
@@ -1169,7 +1169,7 @@ int cx231xx_enum_input(struct file *file, void *priv,
i->index = n;
i->type = V4L2_INPUT_TYPE_CAMERA;
- strcpy(i->name, iname[INPUT(n)->type]);
+ strscpy(i->name, iname[INPUT(n)->type], sizeof(i->name));
if ((CX231XX_VMUX_TELEVISION == INPUT(n)->type) ||
(CX231XX_VMUX_CABLE == INPUT(n)->type))
@@ -1244,7 +1244,7 @@ int cx231xx_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
if (0 != t->index)
return -EINVAL;
- strcpy(t->name, "Tuner");
+ strscpy(t->name, "Tuner", sizeof(t->name));
t->type = V4L2_TUNER_ANALOG_TV;
t->capability = V4L2_TUNER_CAP_NORM;
@@ -1354,22 +1354,22 @@ int cx231xx_g_chip_info(struct file *file, void *fh,
case 0: /* Cx231xx - internal registers */
return 0;
case 1: /* AFE - read byte */
- strlcpy(chip->name, "AFE (byte)", sizeof(chip->name));
+ strscpy(chip->name, "AFE (byte)", sizeof(chip->name));
return 0;
case 2: /* Video Block - read byte */
- strlcpy(chip->name, "Video (byte)", sizeof(chip->name));
+ strscpy(chip->name, "Video (byte)", sizeof(chip->name));
return 0;
case 3: /* I2S block - read byte */
- strlcpy(chip->name, "I2S (byte)", sizeof(chip->name));
+ strscpy(chip->name, "I2S (byte)", sizeof(chip->name));
return 0;
case 4: /* AFE - read dword */
- strlcpy(chip->name, "AFE (dword)", sizeof(chip->name));
+ strscpy(chip->name, "AFE (dword)", sizeof(chip->name));
return 0;
case 5: /* Video Block - read dword */
- strlcpy(chip->name, "Video (dword)", sizeof(chip->name));
+ strscpy(chip->name, "Video (dword)", sizeof(chip->name));
return 0;
case 6: /* I2S Block - read dword */
- strlcpy(chip->name, "I2S (dword)", sizeof(chip->name));
+ strscpy(chip->name, "I2S (dword)", sizeof(chip->name));
return 0;
}
return -EINVAL;
@@ -1389,7 +1389,7 @@ int cx231xx_g_register(struct file *file, void *priv,
ret = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER,
(u16)reg->reg, value, 4);
reg->val = value[0] | value[1] << 8 |
- value[2] << 16 | value[3] << 24;
+ value[2] << 16 | (u32)value[3] << 24;
reg->size = 4;
break;
case 1: /* AFE - read byte */
@@ -1553,8 +1553,8 @@ int cx231xx_querycap(struct file *file, void *priv,
struct cx231xx_fh *fh = priv;
struct cx231xx *dev = fh->dev;
- strlcpy(cap->driver, "cx231xx", sizeof(cap->driver));
- strlcpy(cap->card, cx231xx_boards[dev->model].name, sizeof(cap->card));
+ strscpy(cap->driver, "cx231xx", sizeof(cap->driver));
+ strscpy(cap->card, cx231xx_boards[dev->model].name, sizeof(cap->card));
usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
if (vdev->vfl_type == VFL_TYPE_RADIO)
@@ -1583,7 +1583,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
if (unlikely(f->index >= ARRAY_SIZE(format)))
return -EINVAL;
- strlcpy(f->description, format[f->index].name, sizeof(f->description));
+ strscpy(f->description, format[f->index].name, sizeof(f->description));
f->pixelformat = format[f->index].fourcc;
return 0;
@@ -1716,7 +1716,7 @@ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
if (t->index)
return -EINVAL;
- strcpy(t->name, "Radio");
+ strscpy(t->name, "Radio", sizeof(t->name));
call_all(dev, tuner, g_tuner, t);
@@ -2204,10 +2204,10 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
if (dev->sd_cx25840) {
v4l2_ctrl_add_handler(&dev->ctrl_handler,
- dev->sd_cx25840->ctrl_handler, NULL);
+ dev->sd_cx25840->ctrl_handler, NULL, true);
v4l2_ctrl_add_handler(&dev->radio_ctrl_handler,
dev->sd_cx25840->ctrl_handler,
- v4l2_ctrl_radio_filter);
+ v4l2_ctrl_radio_filter, true);
}
if (dev->ctrl_handler.error)
@@ -2242,7 +2242,8 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
/* Initialize VBI template */
cx231xx_vbi_template = cx231xx_video_template;
- strcpy(cx231xx_vbi_template.name, "cx231xx-vbi");
+ strscpy(cx231xx_vbi_template.name, "cx231xx-vbi",
+ sizeof(cx231xx_vbi_template.name));
/* Allocate and fill vbi video_device struct */
cx231xx_vdev_init(dev, &dev->vbi_dev, &cx231xx_vbi_template, "vbi");
diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c
index 1f6c1eefe389..80d3bd3a0f24 100644
--- a/drivers/media/usb/dvb-usb-v2/af9035.c
+++ b/drivers/media/usb/dvb-usb-v2/af9035.c
@@ -204,7 +204,7 @@ static int af9035_add_i2c_dev(struct dvb_usb_device *d, const char *type,
.platform_data = platform_data,
};
- strlcpy(board_info.type, type, I2C_NAME_SIZE);
+ strscpy(board_info.type, type, I2C_NAME_SIZE);
/* find first free client */
for (num = 0; num < AF9035_I2C_CLIENT_MAX; num++) {
diff --git a/drivers/media/usb/dvb-usb-v2/anysee.c b/drivers/media/usb/dvb-usb-v2/anysee.c
index 20ee7eea2a91..0df7ad69e6c7 100644
--- a/drivers/media/usb/dvb-usb-v2/anysee.c
+++ b/drivers/media/usb/dvb-usb-v2/anysee.c
@@ -638,7 +638,7 @@ static int anysee_add_i2c_dev(struct dvb_usb_device *d, const char *type,
.platform_data = platform_data,
};
- strlcpy(board_info.type, type, I2C_NAME_SIZE);
+ strscpy(board_info.type, type, I2C_NAME_SIZE);
/* find first free client */
for (num = 0; num < ANYSEE_I2C_CLIENT_MAX; num++) {
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
index 955318ab7f5e..3b8f7931b730 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
@@ -74,7 +74,7 @@ static int dvb_usbv2_i2c_init(struct dvb_usb_device *d)
if (!d->props->i2c_algo)
return 0;
- strlcpy(d->i2c_adap.name, d->name, sizeof(d->i2c_adap.name));
+ strscpy(d->i2c_adap.name, d->name, sizeof(d->i2c_adap.name));
d->i2c_adap.algo = d->props->i2c_algo;
d->i2c_adap.dev.parent = &d->udev->dev;
i2c_set_adapdata(&d->i2c_adap, d);
diff --git a/drivers/media/usb/dvb-usb-v2/dvbsky.c b/drivers/media/usb/dvb-usb-v2/dvbsky.c
index 1aa88d94e57f..e28bd8836751 100644
--- a/drivers/media/usb/dvb-usb-v2/dvbsky.c
+++ b/drivers/media/usb/dvb-usb-v2/dvbsky.c
@@ -31,6 +31,7 @@ MODULE_PARM_DESC(disable_rc, "Disable inbuilt IR receiver.");
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
struct dvbsky_state {
+ struct mutex stream_mutex;
u8 ibuf[DVBSKY_BUF_LEN];
u8 obuf[DVBSKY_BUF_LEN];
u8 last_lock;
@@ -67,17 +68,18 @@ static int dvbsky_usb_generic_rw(struct dvb_usb_device *d,
static int dvbsky_stream_ctrl(struct dvb_usb_device *d, u8 onoff)
{
+ struct dvbsky_state *state = d_to_priv(d);
int ret;
- static u8 obuf_pre[3] = { 0x37, 0, 0 };
- static u8 obuf_post[3] = { 0x36, 3, 0 };
+ u8 obuf_pre[3] = { 0x37, 0, 0 };
+ u8 obuf_post[3] = { 0x36, 3, 0 };
- mutex_lock(&d->usb_mutex);
- ret = dvb_usbv2_generic_rw_locked(d, obuf_pre, 3, NULL, 0);
+ mutex_lock(&state->stream_mutex);
+ ret = dvbsky_usb_generic_rw(d, obuf_pre, 3, NULL, 0);
if (!ret && onoff) {
msleep(20);
- ret = dvb_usbv2_generic_rw_locked(d, obuf_post, 3, NULL, 0);
+ ret = dvbsky_usb_generic_rw(d, obuf_post, 3, NULL, 0);
}
- mutex_unlock(&d->usb_mutex);
+ mutex_unlock(&state->stream_mutex);
return ret;
}
@@ -606,6 +608,8 @@ static int dvbsky_init(struct dvb_usb_device *d)
if (ret)
return ret;
*/
+ mutex_init(&state->stream_mutex);
+
state->last_lock = 0;
return 0;
diff --git a/drivers/media/usb/dvb-usb-v2/gl861.c b/drivers/media/usb/dvb-usb-v2/gl861.c
index 3338b21d8b25..0559417c8af4 100644
--- a/drivers/media/usb/dvb-usb-v2/gl861.c
+++ b/drivers/media/usb/dvb-usb-v2/gl861.c
@@ -507,7 +507,7 @@ static int friio_frontend_attach(struct dvb_usb_adapter *adap)
priv->i2c_client_demod = cl;
priv->tuner_adap.algo = &friio_tuner_i2c_algo;
priv->tuner_adap.dev.parent = &d->udev->dev;
- strlcpy(priv->tuner_adap.name, d->name, sizeof(priv->tuner_adap.name));
+ strscpy(priv->tuner_adap.name, d->name, sizeof(priv->tuner_adap.name));
strlcat(priv->tuner_adap.name, "-tuner", sizeof(priv->tuner_adap.name));
priv->demod_sub_i2c = &priv->tuner_adap;
i2c_set_adapdata(&priv->tuner_adap, d);
diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c
index 0750a975bcb8..f109c04f05ae 100644
--- a/drivers/media/usb/dvb-usb-v2/lmedm04.c
+++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c
@@ -1004,7 +1004,7 @@ static int lme_name(struct dvb_usb_adapter *adap)
" SHARP:BS2F7HZ0194", " RS2000"};
char *name = adap->fe[0]->ops.info.name;
- strlcpy(name, desc, 128);
+ strscpy(name, desc, 128);
strlcat(name, fe_name[st->tuner_config], 128);
return 0;
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.c b/drivers/media/usb/dvb-usb-v2/mxl111sf.c
index 4713ba65e1c2..85cdf593a9ad 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf.c
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.c
@@ -892,11 +892,13 @@ static int mxl111sf_attach_tuner(struct dvb_usb_adapter *adap)
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
state->tuner.function = MEDIA_ENT_F_TUNER;
state->tuner.name = "mxl111sf tuner";
- state->tuner_pads[TUNER_PAD_RF_INPUT].flags = MEDIA_PAD_FL_SINK;
- state->tuner_pads[TUNER_PAD_OUTPUT].flags = MEDIA_PAD_FL_SOURCE;
+ state->tuner_pads[MXL111SF_PAD_RF_INPUT].flags = MEDIA_PAD_FL_SINK;
+ state->tuner_pads[MXL111SF_PAD_RF_INPUT].sig_type = PAD_SIGNAL_ANALOG;
+ state->tuner_pads[MXL111SF_PAD_OUTPUT].flags = MEDIA_PAD_FL_SOURCE;
+ state->tuner_pads[MXL111SF_PAD_OUTPUT].sig_type = PAD_SIGNAL_ANALOG;
ret = media_entity_pads_init(&state->tuner,
- TUNER_NUM_PADS, state->tuner_pads);
+ MXL111SF_NUM_PADS, state->tuner_pads);
if (ret)
return ret;
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.h b/drivers/media/usb/dvb-usb-v2/mxl111sf.h
index 22253d4908eb..ed98654ba7fd 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf.h
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.h
@@ -52,6 +52,12 @@ struct mxl111sf_adap_state {
int (*fe_sleep)(struct dvb_frontend *);
};
+enum mxl111sf_pads {
+ MXL111SF_PAD_RF_INPUT,
+ MXL111SF_PAD_OUTPUT,
+ MXL111SF_NUM_PADS
+};
+
struct mxl111sf_state {
struct dvb_usb_device *d;
@@ -94,7 +100,7 @@ struct mxl111sf_state {
struct mutex msg_lock;
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
struct media_entity tuner;
- struct media_pad tuner_pads[2];
+ struct media_pad tuner_pads[MXL111SF_NUM_PADS];
#endif
};
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
index a970224a94bd..8a83b10e50e0 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -687,7 +687,7 @@ static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap)
/* attach demodulator */
memset(&board_info, 0, sizeof(board_info));
- strlcpy(board_info.type, "rtl2830", I2C_NAME_SIZE);
+ strscpy(board_info.type, "rtl2830", I2C_NAME_SIZE);
board_info.addr = 0x10;
board_info.platform_data = pdata;
request_module("%s", board_info.type);
@@ -908,7 +908,7 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
/* attach demodulator */
memset(&board_info, 0, sizeof(board_info));
- strlcpy(board_info.type, "rtl2832", I2C_NAME_SIZE);
+ strscpy(board_info.type, "rtl2832", I2C_NAME_SIZE);
board_info.addr = 0x10;
board_info.platform_data = pdata;
request_module("%s", board_info.type);
@@ -947,7 +947,7 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
mn88472_config.fe = &adap->fe[1];
mn88472_config.i2c_wr_max = 22,
- strlcpy(info.type, "mn88472", I2C_NAME_SIZE);
+ strscpy(info.type, "mn88472", I2C_NAME_SIZE);
mn88472_config.xtal = 20500000;
mn88472_config.ts_mode = SERIAL_TS_MODE;
mn88472_config.ts_clock = VARIABLE_TS_CLOCK;
@@ -972,7 +972,7 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
mn88473_config.fe = &adap->fe[1];
mn88473_config.i2c_wr_max = 22,
- strlcpy(info.type, "mn88473", I2C_NAME_SIZE);
+ strscpy(info.type, "mn88473", I2C_NAME_SIZE);
info.addr = 0x18;
info.platform_data = &mn88473_config;
request_module(info.type);
@@ -998,7 +998,7 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
si2168_config.ts_mode = SI2168_TS_SERIAL;
si2168_config.ts_clock_inv = false;
si2168_config.ts_clock_gapped = true;
- strlcpy(info.type, "si2168", I2C_NAME_SIZE);
+ strscpy(info.type, "si2168", I2C_NAME_SIZE);
info.addr = 0x64;
info.platform_data = &si2168_config;
request_module(info.type);
@@ -1189,7 +1189,7 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
.clock = 28800000,
};
- strlcpy(info.type, "e4000", I2C_NAME_SIZE);
+ strscpy(info.type, "e4000", I2C_NAME_SIZE);
info.addr = 0x64;
info.platform_data = &e4000_config;
@@ -1213,7 +1213,7 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
};
struct i2c_board_info board_info = {};
- strlcpy(board_info.type, "fc2580", I2C_NAME_SIZE);
+ strscpy(board_info.type, "fc2580", I2C_NAME_SIZE);
board_info.addr = 0x56;
board_info.platform_data = &fc2580_pdata;
request_module("fc2580");
@@ -1244,7 +1244,7 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
if (ret)
goto err;
- strlcpy(board_info.type, "tua9001", I2C_NAME_SIZE);
+ strscpy(board_info.type, "tua9001", I2C_NAME_SIZE);
board_info.addr = 0x60;
board_info.platform_data = &tua9001_pdata;
request_module("tua9001");
@@ -1289,7 +1289,7 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
.inversion = false,
};
- strlcpy(info.type, "si2157", I2C_NAME_SIZE);
+ strscpy(info.type, "si2157", I2C_NAME_SIZE);
info.addr = 0x60;
info.platform_data = &si2157_config;
request_module(info.type);
@@ -1685,7 +1685,7 @@ static int rtl2832u_rc_query(struct dvb_usb_device *d)
{
int ret, i, len;
struct rtl28xxu_dev *dev = d->priv;
- struct ir_raw_event ev;
+ struct ir_raw_event ev = {};
u8 buf[128];
static const struct rtl28xxu_reg_val_mask refresh_tab[] = {
{IR_RX_IF, 0x03, 0xff},
@@ -1751,8 +1751,6 @@ static int rtl2832u_rc_query(struct dvb_usb_device *d)
}
/* pass data to Kernel IR decoder */
- init_ir_raw_event(&ev);
-
for (i = 0; i < len; i++) {
ev.pulse = buf[i] >> 7;
ev.duration = 50800 * (buf[i] & 0x7f);
diff --git a/drivers/media/usb/dvb-usb-v2/zd1301.c b/drivers/media/usb/dvb-usb-v2/zd1301.c
index d1eb4b7bc051..7a41d744ff58 100644
--- a/drivers/media/usb/dvb-usb-v2/zd1301.c
+++ b/drivers/media/usb/dvb-usb-v2/zd1301.c
@@ -177,7 +177,7 @@ static int zd1301_frontend_attach(struct dvb_usb_adapter *adap)
dev->mt2060_pdata.i2c_write_max = 9;
dev->mt2060_pdata.dvb_frontend = frontend;
memset(&board_info, 0, sizeof(board_info));
- strlcpy(board_info.type, "mt2060", I2C_NAME_SIZE);
+ strscpy(board_info.type, "mt2060", I2C_NAME_SIZE);
board_info.addr = 0x60;
board_info.platform_data = &dev->mt2060_pdata;
request_module("%s", "mt2060");
diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c
index 5b51ed7d6243..a51a45c60233 100644
--- a/drivers/media/usb/dvb-usb/cxusb.c
+++ b/drivers/media/usb/dvb-usb/cxusb.c
@@ -1196,7 +1196,7 @@ static int cxusb_mygica_t230_frontend_attach(struct dvb_usb_adapter *adap)
si2168_config.ts_mode = SI2168_TS_PARALLEL;
si2168_config.ts_clock_inv = 1;
memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "si2168", I2C_NAME_SIZE);
+ strscpy(info.type, "si2168", I2C_NAME_SIZE);
info.addr = 0x64;
info.platform_data = &si2168_config;
request_module(info.type);
@@ -1216,7 +1216,7 @@ static int cxusb_mygica_t230_frontend_attach(struct dvb_usb_adapter *adap)
si2157_config.fe = adap->fe_adap[0].fe;
si2157_config.if_port = 1;
memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "si2157", I2C_NAME_SIZE);
+ strscpy(info.type, "si2157", I2C_NAME_SIZE);
info.addr = 0x60;
info.platform_data = &si2157_config;
request_module(info.type);
diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c
index 091389fdf89e..7551dce96f64 100644
--- a/drivers/media/usb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/usb/dvb-usb/dib0700_devices.c
@@ -3763,7 +3763,7 @@ static int xbox_one_attach(struct dvb_usb_adapter *adap)
mn88472_config.ts_mode = PARALLEL_TS_MODE;
mn88472_config.ts_clock = FIXED_TS_CLOCK;
memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "mn88472", I2C_NAME_SIZE);
+ strscpy(info.type, "mn88472", I2C_NAME_SIZE);
info.addr = 0x18;
info.platform_data = &mn88472_config;
request_module(info.type);
@@ -3790,7 +3790,7 @@ static int xbox_one_attach(struct dvb_usb_adapter *adap)
tda18250_config.fe = adap->fe_adap[0].fe;
memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "tda18250", I2C_NAME_SIZE);
+ strscpy(info.type, "tda18250", I2C_NAME_SIZE);
info.addr = 0x60;
info.platform_data = &tda18250_config;
diff --git a/drivers/media/usb/dvb-usb/dvb-usb-i2c.c b/drivers/media/usb/dvb-usb/dvb-usb-i2c.c
index ca0b734e009b..2e07106f4680 100644
--- a/drivers/media/usb/dvb-usb/dvb-usb-i2c.c
+++ b/drivers/media/usb/dvb-usb/dvb-usb-i2c.c
@@ -20,7 +20,7 @@ int dvb_usb_i2c_init(struct dvb_usb_device *d)
return -EINVAL;
}
- strlcpy(d->i2c_adap.name, d->desc->name, sizeof(d->i2c_adap.name));
+ strscpy(d->i2c_adap.name, d->desc->name, sizeof(d->i2c_adap.name));
d->i2c_adap.algo = d->props.i2c_algo;
d->i2c_adap.algo_data = NULL;
d->i2c_adap.dev.parent = &d->udev->dev;
diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c
index 9ce8b4d79d1f..eefe2867815c 100644
--- a/drivers/media/usb/dvb-usb/dw2102.c
+++ b/drivers/media/usb/dvb-usb/dw2102.c
@@ -1589,7 +1589,7 @@ static int tt_s2_4600_frontend_attach(struct dvb_usb_adapter *adap)
m88ds3103_pdata.lnb_hv_pol = 1;
m88ds3103_pdata.lnb_en_pol = 0;
memset(&board_info, 0, sizeof(board_info));
- strlcpy(board_info.type, "m88ds3103", I2C_NAME_SIZE);
+ strscpy(board_info.type, "m88ds3103", I2C_NAME_SIZE);
board_info.addr = 0x68;
board_info.platform_data = &m88ds3103_pdata;
request_module("m88ds3103");
@@ -1608,7 +1608,7 @@ static int tt_s2_4600_frontend_attach(struct dvb_usb_adapter *adap)
/* attach tuner */
ts2020_config.fe = adap->fe_adap[0].fe;
memset(&board_info, 0, sizeof(board_info));
- strlcpy(board_info.type, "ts2022", I2C_NAME_SIZE);
+ strscpy(board_info.type, "ts2022", I2C_NAME_SIZE);
board_info.addr = 0x60;
board_info.platform_data = &ts2020_config;
request_module("ts2020");
diff --git a/drivers/media/usb/dvb-usb/technisat-usb2.c b/drivers/media/usb/dvb-usb/technisat-usb2.c
index 18d0f8f5283f..c659e18b358b 100644
--- a/drivers/media/usb/dvb-usb/technisat-usb2.c
+++ b/drivers/media/usb/dvb-usb/technisat-usb2.c
@@ -566,8 +566,9 @@ static int technisat_usb2_frontend_attach(struct dvb_usb_adapter *a)
a->fe_adap[0].fe->ops.set_voltage = technisat_usb2_set_voltage;
/* if everything was successful assign a nice name to the frontend */
- strlcpy(a->fe_adap[0].fe->ops.info.name, a->dev->desc->name,
- sizeof(a->fe_adap[0].fe->ops.info.name));
+ strscpy(a->fe_adap[0].fe->ops.info.name,
+ a->dev->desc->name,
+ sizeof(a->fe_adap[0].fe->ops.info.name));
} else {
dvb_frontend_detach(a->fe_adap[0].fe);
a->fe_adap[0].fe = NULL;
diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
index 8e799ae1df69..49c9b70b632b 100644
--- a/drivers/media/usb/em28xx/em28xx-audio.c
+++ b/drivers/media/usb/em28xx/em28xx-audio.c
@@ -116,6 +116,7 @@ static void em28xx_audio_isocirq(struct urb *urb)
stride = runtime->frame_bits >> 3;
for (i = 0; i < urb->number_of_packets; i++) {
+ unsigned long flags;
int length =
urb->iso_frame_desc[i].actual_length / stride;
cp = (unsigned char *)urb->transfer_buffer +
@@ -137,7 +138,7 @@ static void em28xx_audio_isocirq(struct urb *urb)
length * stride);
}
- snd_pcm_stream_lock(substream);
+ snd_pcm_stream_lock_irqsave(substream, flags);
dev->adev.hwptr_done_capture += length;
if (dev->adev.hwptr_done_capture >=
@@ -153,7 +154,7 @@ static void em28xx_audio_isocirq(struct urb *urb)
period_elapsed = 1;
}
- snd_pcm_stream_unlock(substream);
+ snd_pcm_stream_unlock_irqrestore(substream, flags);
}
if (period_elapsed)
snd_pcm_period_elapsed(substream);
@@ -842,11 +843,11 @@ static int em28xx_audio_urb_init(struct em28xx *dev)
dev->adev.transfer_buffer = kcalloc(num_urb,
sizeof(*dev->adev.transfer_buffer),
- GFP_ATOMIC);
+ GFP_KERNEL);
if (!dev->adev.transfer_buffer)
return -ENOMEM;
- dev->adev.urb = kcalloc(num_urb, sizeof(*dev->adev.urb), GFP_ATOMIC);
+ dev->adev.urb = kcalloc(num_urb, sizeof(*dev->adev.urb), GFP_KERNEL);
if (!dev->adev.urb) {
kfree(dev->adev.transfer_buffer);
return -ENOMEM;
@@ -859,14 +860,14 @@ static int em28xx_audio_urb_init(struct em28xx *dev)
int j, k;
void *buf;
- urb = usb_alloc_urb(npackets, GFP_ATOMIC);
+ urb = usb_alloc_urb(npackets, GFP_KERNEL);
if (!urb) {
em28xx_audio_free_urb(dev);
return -ENOMEM;
}
dev->adev.urb[i] = urb;
- buf = usb_alloc_coherent(udev, npackets * ep_size, GFP_ATOMIC,
+ buf = usb_alloc_coherent(udev, npackets * ep_size, GFP_KERNEL,
&urb->transfer_dma);
if (!buf) {
dev_err(&dev->intf->dev,
@@ -938,11 +939,11 @@ static int em28xx_audio_init(struct em28xx *dev)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_em28xx_pcm_capture);
pcm->info_flags = 0;
pcm->private_data = dev;
- strcpy(pcm->name, "Empia 28xx Capture");
+ strscpy(pcm->name, "Empia 28xx Capture", sizeof(pcm->name));
- strcpy(card->driver, "Em28xx-Audio");
- strcpy(card->shortname, "Em28xx Audio");
- strcpy(card->longname, "Empia Em28xx Audio");
+ strscpy(card->driver, "Em28xx-Audio", sizeof(card->driver));
+ strscpy(card->shortname, "Em28xx Audio", sizeof(card->shortname));
+ strscpy(card->longname, "Empia Em28xx Audio", sizeof(card->longname));
INIT_WORK(&adev->wq_trigger, audio_trigger);
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index 71c829f31d3b..87b887b7604e 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -2141,13 +2141,13 @@ const struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_COMPOSITE,
.vmux = TVP5150_COMPOSITE1,
- .amux = EM28XX_AUDIO_SRC_LINE,
+ .amux = EM28XX_AMUX_LINE_IN,
.gpio = terratec_av350_unmute_gpio,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
- .amux = EM28XX_AUDIO_SRC_LINE,
+ .amux = EM28XX_AMUX_LINE_IN,
.gpio = terratec_av350_unmute_gpio,
} },
},
@@ -3039,6 +3039,9 @@ static int em28xx_hint_board(struct em28xx *dev)
static void em28xx_card_setup(struct em28xx *dev)
{
+ int i, j, idx;
+ bool duplicate_entry;
+
/*
* If the device can be a webcam, seek for a sensor.
* If sensor is not found, then it isn't a webcam.
@@ -3195,6 +3198,32 @@ static void em28xx_card_setup(struct em28xx *dev)
/* Allow override tuner type by a module parameter */
if (tuner >= 0)
dev->tuner_type = tuner;
+
+ /*
+ * Dynamically generate a list of valid audio inputs for this
+ * specific board, mapping them via enum em28xx_amux.
+ */
+
+ idx = 0;
+ for (i = 0; i < MAX_EM28XX_INPUT; i++) {
+ if (!INPUT(i)->type)
+ continue;
+
+ /* Skip already mapped audio inputs */
+ duplicate_entry = false;
+ for (j = 0; j < idx; j++) {
+ if (INPUT(i)->amux == dev->amux_map[j]) {
+ duplicate_entry = true;
+ break;
+ }
+ }
+ if (duplicate_entry)
+ continue;
+
+ dev->amux_map[idx++] = INPUT(i)->amux;
+ }
+ for (; idx < MAX_EM28XX_INPUT; idx++)
+ dev->amux_map[idx] = EM28XX_AMUX_UNUSED;
}
void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
index 5657f8710ca6..2b8c84a5c9a8 100644
--- a/drivers/media/usb/em28xx/em28xx-core.c
+++ b/drivers/media/usb/em28xx/em28xx-core.c
@@ -777,6 +777,7 @@ EXPORT_SYMBOL_GPL(em28xx_set_mode);
static void em28xx_irq_callback(struct urb *urb)
{
struct em28xx *dev = urb->context;
+ unsigned long flags;
int i;
switch (urb->status) {
@@ -793,9 +794,9 @@ static void em28xx_irq_callback(struct urb *urb)
}
/* Copy data from URB */
- spin_lock(&dev->slock);
+ spin_lock_irqsave(&dev->slock, flags);
dev->usb_ctl.urb_data_copy(dev, urb);
- spin_unlock(&dev->slock);
+ spin_unlock_irqrestore(&dev->slock, flags);
/* Reset urb buffers */
for (i = 0; i < urb->number_of_packets; i++) {
diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
index e19d6342e0d0..02c13d71e6c1 100644
--- a/drivers/media/usb/em28xx/em28xx-i2c.c
+++ b/drivers/media/usb/em28xx/em28xx-i2c.c
@@ -985,7 +985,8 @@ int em28xx_i2c_register(struct em28xx *dev, unsigned int bus,
dev->i2c_adap[bus] = em28xx_adap_template;
dev->i2c_adap[bus].dev.parent = &dev->intf->dev;
- strcpy(dev->i2c_adap[bus].name, dev_name(&dev->intf->dev));
+ strscpy(dev->i2c_adap[bus].name, dev_name(&dev->intf->dev),
+ sizeof(dev->i2c_adap[bus].name));
dev->i2c_bus[bus].bus = bus;
dev->i2c_bus[bus].algo_type = algo_type;
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index 68571bf36d28..f43717ea831d 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -1093,6 +1093,8 @@ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count)
em28xx_videodbg("%s\n", __func__);
+ dev->v4l2->field_count = 0;
+
/*
* Make sure streaming is not already in progress for this type
* of filehandle (e.g. video, vbi)
@@ -1471,9 +1473,9 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
fmt = format_by_fourcc(f->fmt.pix.pixelformat);
if (!fmt) {
- em28xx_videodbg("Fourcc format (%08x) invalid.\n",
- f->fmt.pix.pixelformat);
- return -EINVAL;
+ fmt = &format[0];
+ em28xx_videodbg("Fourcc format (%08x) invalid. Using default (%08x).\n",
+ f->fmt.pix.pixelformat, fmt->fourcc);
}
if (dev->board.is_em2800) {
@@ -1666,6 +1668,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
{
struct em28xx *dev = video_drvdata(file);
unsigned int n;
+ int j;
n = i->index;
if (n >= MAX_EM28XX_INPUT)
@@ -1675,7 +1678,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
i->type = V4L2_INPUT_TYPE_CAMERA;
- strcpy(i->name, iname[INPUT(n)->type]);
+ strscpy(i->name, iname[INPUT(n)->type], sizeof(i->name));
if (INPUT(n)->type == EM28XX_VMUX_TELEVISION)
i->type = V4L2_INPUT_TYPE_TUNER;
@@ -1685,6 +1688,12 @@ static int vidioc_enum_input(struct file *file, void *priv,
if (dev->is_webcam)
i->capabilities = 0;
+ /* Dynamically generates an audioset bitmask */
+ i->audioset = 0;
+ for (j = 0; j < MAX_EM28XX_INPUT; j++)
+ if (dev->amux_map[j] != EM28XX_AMUX_UNUSED)
+ i->audioset |= 1 << j;
+
return 0;
}
@@ -1710,61 +1719,121 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
return 0;
}
-static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+static int em28xx_fill_audio_input(struct em28xx *dev,
+ const char *s,
+ struct v4l2_audio *a,
+ unsigned int index)
{
- struct em28xx *dev = video_drvdata(file);
+ unsigned int idx = dev->amux_map[index];
+
+ /*
+ * With msp3400, almost all mappings use the default (amux = 0).
+ * The only one may use a different value is WinTV USB2, where it
+ * can also be SCART1 input.
+ * As it is very doubtful that we would see new boards with msp3400,
+ * let's just reuse the existing switch.
+ */
+ if (dev->has_msp34xx && idx != EM28XX_AMUX_UNUSED)
+ idx = EM28XX_AMUX_LINE_IN;
- switch (a->index) {
+ switch (idx) {
case EM28XX_AMUX_VIDEO:
- strcpy(a->name, "Television");
+ strscpy(a->name, "Television", sizeof(a->name));
break;
case EM28XX_AMUX_LINE_IN:
- strcpy(a->name, "Line In");
+ strscpy(a->name, "Line In", sizeof(a->name));
break;
case EM28XX_AMUX_VIDEO2:
- strcpy(a->name, "Television alt");
+ strscpy(a->name, "Television alt", sizeof(a->name));
break;
case EM28XX_AMUX_PHONE:
- strcpy(a->name, "Phone");
+ strscpy(a->name, "Phone", sizeof(a->name));
break;
case EM28XX_AMUX_MIC:
- strcpy(a->name, "Mic");
+ strscpy(a->name, "Mic", sizeof(a->name));
break;
case EM28XX_AMUX_CD:
- strcpy(a->name, "CD");
+ strscpy(a->name, "CD", sizeof(a->name));
break;
case EM28XX_AMUX_AUX:
- strcpy(a->name, "Aux");
+ strscpy(a->name, "Aux", sizeof(a->name));
break;
case EM28XX_AMUX_PCM_OUT:
- strcpy(a->name, "PCM");
+ strscpy(a->name, "PCM", sizeof(a->name));
break;
+ case EM28XX_AMUX_UNUSED:
default:
return -EINVAL;
}
-
- a->index = dev->ctl_ainput;
+ a->index = index;
a->capability = V4L2_AUDCAP_STEREO;
+ em28xx_videodbg("%s: audio input index %d is '%s'\n",
+ s, a->index, a->name);
+
return 0;
}
+static int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *a)
+{
+ struct em28xx *dev = video_drvdata(file);
+
+ if (a->index >= MAX_EM28XX_INPUT)
+ return -EINVAL;
+
+ return em28xx_fill_audio_input(dev, __func__, a, a->index);
+}
+
+static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+ struct em28xx *dev = video_drvdata(file);
+ int i;
+
+ for (i = 0; i < MAX_EM28XX_INPUT; i++)
+ if (dev->ctl_ainput == dev->amux_map[i])
+ return em28xx_fill_audio_input(dev, __func__, a, i);
+
+ /* Should never happen! */
+ return -EINVAL;
+}
+
static int vidioc_s_audio(struct file *file, void *priv,
const struct v4l2_audio *a)
{
struct em28xx *dev = video_drvdata(file);
+ int idx, i;
if (a->index >= MAX_EM28XX_INPUT)
return -EINVAL;
- if (!INPUT(a->index)->type)
+
+ idx = dev->amux_map[a->index];
+
+ if (idx == EM28XX_AMUX_UNUSED)
return -EINVAL;
- dev->ctl_ainput = INPUT(a->index)->amux;
- dev->ctl_aoutput = INPUT(a->index)->aout;
+ dev->ctl_ainput = idx;
+
+ /*
+ * FIXME: This is wrong, as different inputs at em28xx_cards
+ * may have different audio outputs. So, the right thing
+ * to do is to implement VIDIOC_G_AUDOUT/VIDIOC_S_AUDOUT.
+ * With the current board definitions, this would work fine,
+ * as, currently, all boards fit.
+ */
+ for (i = 0; i < MAX_EM28XX_INPUT; i++)
+ if (idx == dev->amux_map[i])
+ break;
+ if (i == MAX_EM28XX_INPUT)
+ return -EINVAL;
+
+ dev->ctl_aoutput = INPUT(i)->aout;
if (!dev->ctl_aoutput)
dev->ctl_aoutput = EM28XX_AOUT_MASTER;
+ em28xx_videodbg("%s: set audio input to %d\n", __func__,
+ dev->ctl_ainput);
+
return 0;
}
@@ -1776,7 +1845,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
if (t->index != 0)
return -EINVAL;
- strcpy(t->name, "Tuner");
+ strscpy(t->name, "Tuner", sizeof(t->name));
v4l2_device_call_all(&dev->v4l2->v4l2_dev, 0, tuner, g_tuner, t);
return 0;
@@ -1833,9 +1902,9 @@ static int vidioc_g_chip_info(struct file *file, void *priv,
if (chip->match.addr > 1)
return -EINVAL;
if (chip->match.addr == 1)
- strlcpy(chip->name, "ac97", sizeof(chip->name));
+ strscpy(chip->name, "ac97", sizeof(chip->name));
else
- strlcpy(chip->name,
+ strscpy(chip->name,
dev->v4l2->v4l2_dev.name, sizeof(chip->name));
return 0;
}
@@ -1920,8 +1989,8 @@ static int vidioc_querycap(struct file *file, void *priv,
struct em28xx_v4l2 *v4l2 = dev->v4l2;
struct usb_device *udev = interface_to_usbdev(dev->intf);
- strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
- strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
+ strscpy(cap->driver, "em28xx", sizeof(cap->driver));
+ strscpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
usb_make_path(udev, cap->bus_info, sizeof(cap->bus_info));
if (vdev->vfl_type == VFL_TYPE_GRABBER)
@@ -1954,7 +2023,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
if (unlikely(f->index >= ARRAY_SIZE(format)))
return -EINVAL;
- strlcpy(f->description, format[f->index].name, sizeof(f->description));
+ strscpy(f->description, format[f->index].name, sizeof(f->description));
f->pixelformat = format[f->index].fourcc;
return 0;
@@ -2045,7 +2114,7 @@ static int radio_g_tuner(struct file *file, void *priv,
if (unlikely(t->index > 0))
return -EINVAL;
- strcpy(t->name, "Radio");
+ strscpy(t->name, "Radio", sizeof(t->name));
v4l2_device_call_all(&dev->v4l2->v4l2_dev, 0, tuner, g_tuner, t);
@@ -2302,6 +2371,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_try_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
.vidioc_s_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
.vidioc_enum_framesizes = vidioc_enum_framesizes,
+ .vidioc_enumaudio = vidioc_enumaudio,
.vidioc_g_audio = vidioc_g_audio,
.vidioc_s_audio = vidioc_s_audio,
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index 953caac025f2..a551072e62ed 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -335,6 +335,9 @@ enum em28xx_usb_audio_type {
/**
* em28xx_amux - describes the type of audio input used by em28xx
*
+ * @EM28XX_AMUX_UNUSED:
+ * Used only on em28xx dev->map field, in order to mark an entry
+ * as unused.
* @EM28XX_AMUX_VIDEO:
* On devices without AC97, this is the only value that it is currently
* allowed.
@@ -369,7 +372,8 @@ enum em28xx_usb_audio_type {
* same time, via the alsa mux.
*/
enum em28xx_amux {
- EM28XX_AMUX_VIDEO,
+ EM28XX_AMUX_UNUSED = -1,
+ EM28XX_AMUX_VIDEO = 0,
EM28XX_AMUX_LINE_IN,
/* Some less-common mixer setups */
@@ -692,6 +696,8 @@ struct em28xx {
unsigned int ctl_input; // selected input
unsigned int ctl_ainput;// selected audio input
unsigned int ctl_aoutput;// selected audio output
+ enum em28xx_amux amux_map[MAX_EM28XX_INPUT];
+
int mute;
int volume;
diff --git a/drivers/media/usb/go7007/go7007-driver.c b/drivers/media/usb/go7007/go7007-driver.c
index 62aeebcdd7f7..59cf50355b4e 100644
--- a/drivers/media/usb/go7007/go7007-driver.c
+++ b/drivers/media/usb/go7007/go7007-driver.c
@@ -208,7 +208,7 @@ static int init_i2c_module(struct i2c_adapter *adapter, const struct go_i2c *con
struct i2c_board_info info;
memset(&info, 0, sizeof(info));
- strlcpy(info.type, i2c->type, sizeof(info.type));
+ strscpy(info.type, i2c->type, sizeof(info.type));
info.addr = i2c->addr;
info.flags = i2c->flags;
diff --git a/drivers/media/usb/go7007/go7007-v4l2.c b/drivers/media/usb/go7007/go7007-v4l2.c
index c55c82f70e54..7a2781fa83e7 100644
--- a/drivers/media/usb/go7007/go7007-v4l2.c
+++ b/drivers/media/usb/go7007/go7007-v4l2.c
@@ -284,9 +284,9 @@ static int vidioc_querycap(struct file *file, void *priv,
{
struct go7007 *go = video_drvdata(file);
- strlcpy(cap->driver, "go7007", sizeof(cap->driver));
- strlcpy(cap->card, go->name, sizeof(cap->card));
- strlcpy(cap->bus_info, go->bus_info, sizeof(cap->bus_info));
+ strscpy(cap->driver, "go7007", sizeof(cap->driver));
+ strscpy(cap->card, go->name, sizeof(cap->card));
+ strscpy(cap->bus_info, go->bus_info, sizeof(cap->bus_info));
cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING;
@@ -634,8 +634,8 @@ static int vidioc_enum_input(struct file *file, void *priv,
if (inp->index >= go->board_info->num_inputs)
return -EINVAL;
- strlcpy(inp->name, go->board_info->inputs[inp->index].name,
- sizeof(inp->name));
+ strscpy(inp->name, go->board_info->inputs[inp->index].name,
+ sizeof(inp->name));
/* If this board has a tuner, it will be the first input */
if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) &&
@@ -673,7 +673,7 @@ static int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *a)
if (a->index >= go->board_info->num_aud_inputs)
return -EINVAL;
- strlcpy(a->name, go->board_info->aud_inputs[a->index].name,
+ strscpy(a->name, go->board_info->aud_inputs[a->index].name,
sizeof(a->name));
a->capability = V4L2_AUDCAP_STEREO;
return 0;
@@ -684,7 +684,7 @@ static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a)
struct go7007 *go = video_drvdata(file);
a->index = go->aud_input;
- strlcpy(a->name, go->board_info->aud_inputs[go->aud_input].name,
+ strscpy(a->name, go->board_info->aud_inputs[go->aud_input].name,
sizeof(a->name));
a->capability = V4L2_AUDCAP_STEREO;
return 0;
@@ -742,7 +742,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
if (t->index != 0)
return -EINVAL;
- strlcpy(t->name, "Tuner", sizeof(t->name));
+ strscpy(t->name, "Tuner", sizeof(t->name));
return call_all(&go->v4l2_dev, tuner, g_tuner, t);
}
diff --git a/drivers/media/usb/go7007/snd-go7007.c b/drivers/media/usb/go7007/snd-go7007.c
index 137fc253b122..fc84b37d5587 100644
--- a/drivers/media/usb/go7007/snd-go7007.c
+++ b/drivers/media/usb/go7007/snd-go7007.c
@@ -260,10 +260,10 @@ int go7007_snd_init(struct go7007 *go)
kfree(gosnd);
return ret;
}
- strlcpy(gosnd->card->driver, "go7007", sizeof(gosnd->card->driver));
- strlcpy(gosnd->card->shortname, go->name, sizeof(gosnd->card->driver));
- strlcpy(gosnd->card->longname, gosnd->card->shortname,
- sizeof(gosnd->card->longname));
+ strscpy(gosnd->card->driver, "go7007", sizeof(gosnd->card->driver));
+ strscpy(gosnd->card->shortname, go->name, sizeof(gosnd->card->driver));
+ strscpy(gosnd->card->longname, gosnd->card->shortname,
+ sizeof(gosnd->card->longname));
gosnd->pcm->private_data = go;
snd_pcm_set_ops(gosnd->pcm, SNDRV_PCM_STREAM_CAPTURE,
diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c
index 57aa521e16b1..fce9d6f4b7c9 100644
--- a/drivers/media/usb/gspca/gspca.c
+++ b/drivers/media/usb/gspca/gspca.c
@@ -1193,11 +1193,11 @@ static int vidioc_querycap(struct file *file, void *priv,
{
struct gspca_dev *gspca_dev = video_drvdata(file);
- strlcpy((char *) cap->driver, gspca_dev->sd_desc->name,
- sizeof cap->driver);
+ strscpy((char *)cap->driver, gspca_dev->sd_desc->name,
+ sizeof(cap->driver));
if (gspca_dev->dev->product != NULL) {
- strlcpy((char *) cap->card, gspca_dev->dev->product,
- sizeof cap->card);
+ strscpy((char *)cap->card, gspca_dev->dev->product,
+ sizeof(cap->card));
} else {
snprintf((char *) cap->card, sizeof cap->card,
"USB Camera (%04x:%04x)",
@@ -1222,7 +1222,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
return -EINVAL;
input->type = V4L2_INPUT_TYPE_CAMERA;
input->status = gspca_dev->cam.input_flags;
- strlcpy(input->name, gspca_dev->sd_desc->name,
+ strscpy(input->name, gspca_dev->sd_desc->name,
sizeof input->name);
return 0;
}
diff --git a/drivers/media/usb/gspca/sn9c20x.c b/drivers/media/usb/gspca/sn9c20x.c
index cfa2a04d9f3f..5984bb12bcff 100644
--- a/drivers/media/usb/gspca/sn9c20x.c
+++ b/drivers/media/usb/gspca/sn9c20x.c
@@ -1601,7 +1601,7 @@ static int sd_chip_info(struct gspca_dev *gspca_dev,
if (chip->match.addr > 1)
return -EINVAL;
if (chip->match.addr == 1)
- strlcpy(chip->name, "sensor", sizeof(chip->name));
+ strscpy(chip->name, "sensor", sizeof(chip->name));
return 0;
}
#endif
diff --git a/drivers/media/usb/gspca/sq930x.c b/drivers/media/usb/gspca/sq930x.c
index d7cbcf2b3947..e15b45f022e1 100644
--- a/drivers/media/usb/gspca/sq930x.c
+++ b/drivers/media/usb/gspca/sq930x.c
@@ -1044,7 +1044,7 @@ static void sd_dq_callback(struct gspca_dev *gspca_dev)
v4l2_ctrl_g_ctrl(sd->gain));
gspca_dev->cam.bulk_nurbs = 1;
- ret = usb_submit_urb(gspca_dev->urb[0], GFP_ATOMIC);
+ ret = usb_submit_urb(gspca_dev->urb[0], GFP_KERNEL);
if (ret < 0)
pr_err("sd_dq_callback() err %d\n", ret);
diff --git a/drivers/media/usb/hackrf/hackrf.c b/drivers/media/usb/hackrf/hackrf.c
index 34085a0b15a1..d43785206622 100644
--- a/drivers/media/usb/hackrf/hackrf.c
+++ b/drivers/media/usb/hackrf/hackrf.c
@@ -918,8 +918,8 @@ static int hackrf_querycap(struct file *file, void *fh,
cap->capabilities = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_TUNER |
V4L2_CAP_SDR_OUTPUT | V4L2_CAP_MODULATOR |
V4L2_CAP_DEVICE_CAPS | cap->device_caps;
- strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
- strlcpy(cap->card, dev->rx_vdev.name, sizeof(cap->card));
+ strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
+ strscpy(cap->card, dev->rx_vdev.name, sizeof(cap->card));
usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
return 0;
@@ -1041,14 +1041,14 @@ static int hackrf_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
dev_dbg(dev->dev, "index=%d\n", v->index);
if (v->index == 0) {
- strlcpy(v->name, "HackRF ADC", sizeof(v->name));
+ strscpy(v->name, "HackRF ADC", sizeof(v->name));
v->type = V4L2_TUNER_SDR;
v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
v->rangelow = bands_adc_dac[0].rangelow;
v->rangehigh = bands_adc_dac[0].rangehigh;
ret = 0;
} else if (v->index == 1) {
- strlcpy(v->name, "HackRF RF", sizeof(v->name));
+ strscpy(v->name, "HackRF RF", sizeof(v->name));
v->type = V4L2_TUNER_RF;
v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
v->rangelow = bands_rx_tx[0].rangelow;
@@ -1080,14 +1080,14 @@ static int hackrf_g_modulator(struct file *file, void *fh,
dev_dbg(dev->dev, "index=%d\n", a->index);
if (a->index == 0) {
- strlcpy(a->name, "HackRF DAC", sizeof(a->name));
+ strscpy(a->name, "HackRF DAC", sizeof(a->name));
a->type = V4L2_TUNER_SDR;
a->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
a->rangelow = bands_adc_dac[0].rangelow;
a->rangehigh = bands_adc_dac[0].rangehigh;
ret = 0;
} else if (a->index == 1) {
- strlcpy(a->name, "HackRF RF", sizeof(a->name));
+ strscpy(a->name, "HackRF RF", sizeof(a->name));
a->type = V4L2_TUNER_RF;
a->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
a->rangelow = bands_rx_tx[0].rangelow;
diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c
index 1b89c77bad66..e082086428a4 100644
--- a/drivers/media/usb/hdpvr/hdpvr-video.c
+++ b/drivers/media/usb/hdpvr/hdpvr-video.c
@@ -578,8 +578,8 @@ static int vidioc_querycap(struct file *file, void *priv,
{
struct hdpvr_device *dev = video_drvdata(file);
- strcpy(cap->driver, "hdpvr");
- strcpy(cap->card, "Hauppauge HD PVR");
+ strscpy(cap->driver, "hdpvr", sizeof(cap->driver));
+ strscpy(cap->card, "Hauppauge HD PVR", sizeof(cap->card));
usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_AUDIO |
V4L2_CAP_READWRITE;
@@ -873,7 +873,7 @@ static int vidioc_g_audio(struct file *file, void *private_data,
audio->index = dev->options.audio_input;
audio->capability = V4L2_AUDCAP_STEREO;
- strlcpy(audio->name, audio_iname[audio->index], sizeof(audio->name));
+ strscpy(audio->name, audio_iname[audio->index], sizeof(audio->name));
audio->name[sizeof(audio->name) - 1] = '\0';
return 0;
}
@@ -1238,7 +1238,8 @@ int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent,
/* setup and register video device */
dev->video_dev = hdpvr_video_template;
- strcpy(dev->video_dev.name, "Hauppauge HD PVR");
+ strscpy(dev->video_dev.name, "Hauppauge HD PVR",
+ sizeof(dev->video_dev.name));
dev->video_dev.v4l2_dev = &dev->v4l2_dev;
video_set_drvdata(&dev->video_dev, dev);
diff --git a/drivers/media/usb/msi2500/msi2500.c b/drivers/media/usb/msi2500/msi2500.c
index 65ef755adfdc..10b5b95bee34 100644
--- a/drivers/media/usb/msi2500/msi2500.c
+++ b/drivers/media/usb/msi2500/msi2500.c
@@ -604,8 +604,8 @@ static int msi2500_querycap(struct file *file, void *fh,
dev_dbg(dev->dev, "\n");
- strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
- strlcpy(cap->card, dev->vdev.name, sizeof(cap->card));
+ strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
+ strscpy(cap->card, dev->vdev.name, sizeof(cap->card));
usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
cap->device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_STREAMING |
V4L2_CAP_READWRITE | V4L2_CAP_TUNER;
@@ -916,7 +916,7 @@ static int msi2500_enum_fmt_sdr_cap(struct file *file, void *priv,
if (f->index >= dev->num_formats)
return -EINVAL;
- strlcpy(f->description, formats[f->index].name, sizeof(f->description));
+ strscpy(f->description, formats[f->index].name, sizeof(f->description));
f->pixelformat = formats[f->index].pixelformat;
return 0;
@@ -1017,7 +1017,7 @@ static int msi2500_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
dev_dbg(dev->dev, "index=%d\n", v->index);
if (v->index == 0) {
- strlcpy(v->name, "Mirics MSi2500", sizeof(v->name));
+ strscpy(v->name, "Mirics MSi2500", sizeof(v->name));
v->type = V4L2_TUNER_ADC;
v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
v->rangelow = 1200000;
@@ -1278,7 +1278,7 @@ static int msi2500_probe(struct usb_interface *intf,
}
/* currently all controls are from subdev */
- v4l2_ctrl_add_handler(&dev->hdl, sd->ctrl_handler, NULL);
+ v4l2_ctrl_add_handler(&dev->hdl, sd->ctrl_handler, NULL, true);
dev->v4l2_dev.ctrl_handler = &dev->hdl;
dev->vdev.v4l2_dev = &dev->v4l2_dev;
diff --git a/drivers/media/usb/pulse8-cec/pulse8-cec.c b/drivers/media/usb/pulse8-cec/pulse8-cec.c
index 350635826aae..365c78b748dd 100644
--- a/drivers/media/usb/pulse8-cec/pulse8-cec.c
+++ b/drivers/media/usb/pulse8-cec/pulse8-cec.c
@@ -571,7 +571,8 @@ static int pulse8_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
memset(osd_str + osd_len, ' ', 4 - osd_len);
osd_len = 4;
osd_str[osd_len] = '\0';
- strcpy(adap->log_addrs.osd_name, osd_str);
+ strscpy(adap->log_addrs.osd_name, osd_str,
+ sizeof(adap->log_addrs.osd_name));
}
err = pulse8_send_and_wait(pulse8, cmd, 1 + osd_len,
MSGCODE_COMMAND_ACCEPTED, 0);
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-debug.h b/drivers/media/usb/pvrusb2/pvrusb2-debug.h
index 5cd16292e2fa..1323f949f454 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-debug.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-debug.h
@@ -17,7 +17,7 @@
extern int pvrusb2_debug;
-#define pvr2_trace(msk, fmt, arg...) do {if(msk & pvrusb2_debug) printk(KERN_INFO "pvrusb2: " fmt "\n", ##arg); } while (0)
+#define pvr2_trace(msk, fmt, arg...) do {if (msk & pvrusb2_debug) pr_info("pvrusb2: " fmt "\n", ##arg); } while (0)
/* These are listed in *rough* order of decreasing usefulness and
increasing noise level. */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
index a8519da0020b..7702285c1519 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
@@ -3293,12 +3293,12 @@ void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw)
int nr = pvr2_hdw_get_unit_number(hdw);
LOCK_TAKE(hdw->big_lock);
do {
- printk(KERN_INFO "pvrusb2: ================= START STATUS CARD #%d =================\n", nr);
+ pr_info("pvrusb2: ================= START STATUS CARD #%d =================\n", nr);
v4l2_device_call_all(&hdw->v4l2_dev, 0, core, log_status);
pvr2_trace(PVR2_TRACE_INFO,"cx2341x config:");
cx2341x_log_status(&hdw->enc_ctl_state, "pvrusb2");
pvr2_hdw_state_log_state(hdw);
- printk(KERN_INFO "pvrusb2: ================== END STATUS CARD #%d ==================\n", nr);
+ pr_info("pvrusb2: ================== END STATUS CARD #%d ==================\n", nr);
} while (0);
LOCK_GIVE(hdw->big_lock);
}
@@ -4851,7 +4851,7 @@ static void pvr2_hdw_state_log_state(struct pvr2_hdw *hdw)
for (idx = 0; ; idx++) {
ccnt = pvr2_hdw_report_unlocked(hdw,idx,buf,sizeof(buf));
if (!ccnt) break;
- printk(KERN_INFO "%s %.*s\n",hdw->name,ccnt,buf);
+ pr_info("%s %.*s\n", hdw->name, ccnt, buf);
}
ccnt = pvr2_hdw_report_clients(hdw, buf, sizeof(buf));
if (ccnt >= sizeof(buf))
@@ -4863,7 +4863,7 @@ static void pvr2_hdw_state_log_state(struct pvr2_hdw *hdw)
while ((lcnt + ucnt < ccnt) && (buf[lcnt + ucnt] != '\n')) {
lcnt++;
}
- printk(KERN_INFO "%s %.*s\n", hdw->name, lcnt, buf + ucnt);
+ pr_info("%s %.*s\n", hdw->name, lcnt, buf + ucnt);
ucnt += lcnt + 1;
}
}
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c
index f3003ca05f4b..8f023085c2d9 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c
@@ -478,8 +478,7 @@ static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap,
unsigned int idx,offs,cnt;
for (idx = 0; idx < num; idx++) {
cnt = msgs[idx].len;
- printk(KERN_INFO
- "pvrusb2 i2c xfer %u/%u: addr=0x%x len=%d %s",
+ pr_info("pvrusb2 i2c xfer %u/%u: addr=0x%x len=%d %s",
idx+1,num,
msgs[idx].addr,
cnt,
@@ -487,22 +486,21 @@ static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap,
"read" : "write"));
if ((ret > 0) || !(msgs[idx].flags & I2C_M_RD)) {
if (cnt > 8) cnt = 8;
- printk(KERN_CONT " [");
+ pr_cont(" [");
for (offs = 0; offs < cnt; offs++) {
- if (offs) printk(KERN_CONT " ");
- printk(KERN_CONT "%02x",msgs[idx].buf[offs]);
+ if (offs) pr_cont(" ");
+ pr_cont("%02x", msgs[idx].buf[offs]);
}
- if (offs < cnt) printk(KERN_CONT " ...");
- printk(KERN_CONT "]");
+ if (offs < cnt) pr_cont(" ...");
+ pr_cont("]");
}
if (idx+1 == num) {
- printk(KERN_CONT " result=%d",ret);
+ pr_cont(" result=%d", ret);
}
- printk(KERN_CONT "\n");
+ pr_cont("\n");
}
if (!num) {
- printk(KERN_INFO
- "pvrusb2 i2c xfer null transfer result=%d\n",
+ pr_info("pvrusb2 i2c xfer null transfer result=%d\n",
ret);
}
}
@@ -542,14 +540,14 @@ static int do_i2c_probe(struct pvr2_hdw *hdw, int addr)
static void do_i2c_scan(struct pvr2_hdw *hdw)
{
int i;
- printk(KERN_INFO "%s: i2c scan beginning\n", hdw->name);
+ pr_info("%s: i2c scan beginning\n", hdw->name);
for (i = 0; i < 128; i++) {
if (do_i2c_probe(hdw, i)) {
- printk(KERN_INFO "%s: i2c scan: found device @ 0x%x\n",
+ pr_info("%s: i2c scan: found device @ 0x%x\n",
hdw->name, i);
}
}
- printk(KERN_INFO "%s: i2c scan done.\n", hdw->name);
+ pr_info("%s: i2c scan done.\n", hdw->name);
}
static void pvr2_i2c_register_ir(struct pvr2_hdw *hdw)
@@ -573,7 +571,7 @@ static void pvr2_i2c_register_ir(struct pvr2_hdw *hdw)
/* IR Receiver */
info.addr = 0x18;
info.platform_data = init_data;
- strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+ strscpy(info.type, "ir_video", I2C_NAME_SIZE);
pvr2_trace(PVR2_TRACE_INFO, "Binding %s to i2c address 0x%02x.",
info.type, info.addr);
i2c_new_device(&hdw->i2c_adap, &info);
@@ -588,7 +586,7 @@ static void pvr2_i2c_register_ir(struct pvr2_hdw *hdw)
/* IR Transceiver */
info.addr = 0x71;
info.platform_data = init_data;
- strlcpy(info.type, "ir_z8f0811_haup", I2C_NAME_SIZE);
+ strscpy(info.type, "ir_z8f0811_haup", I2C_NAME_SIZE);
pvr2_trace(PVR2_TRACE_INFO, "Binding %s to i2c address 0x%02x.",
info.type, info.addr);
i2c_new_device(&hdw->i2c_adap, &info);
@@ -612,7 +610,7 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
/* However, deal with various special cases for 24xxx hardware. */
if (ir_mode[hdw->unit_number] == 0) {
- printk(KERN_INFO "%s: IR disabled\n",hdw->name);
+ pr_info("%s: IR disabled\n", hdw->name);
hdw->i2c_func[0x18] = i2c_black_hole;
} else if (ir_mode[hdw->unit_number] == 1) {
if (hdw->ir_scheme_active == PVR2_IR_SCHEME_24XXX) {
@@ -631,7 +629,7 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
// Configure the adapter and set up everything else related to it.
hdw->i2c_adap = pvr2_i2c_adap_template;
hdw->i2c_algo = pvr2_i2c_algo_template;
- strlcpy(hdw->i2c_adap.name,hdw->name,sizeof(hdw->i2c_adap.name));
+ strscpy(hdw->i2c_adap.name, hdw->name, sizeof(hdw->i2c_adap.name));
hdw->i2c_adap.dev.parent = &hdw->usb_dev->dev;
hdw->i2c_adap.algo = &hdw->i2c_algo;
hdw->i2c_adap.algo_data = hdw;
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-main.c b/drivers/media/usb/pvrusb2/pvrusb2-main.c
index cbe2c3a22458..23672dd352f5 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-main.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-main.c
@@ -132,10 +132,10 @@ static int __init pvr_init(void)
ret = usb_register(&pvr_driver);
if (ret == 0)
- printk(KERN_INFO "pvrusb2: " DRIVER_VERSION ":"
+ pr_info("pvrusb2: " DRIVER_VERSION ":"
DRIVER_DESC "\n");
if (pvrusb2_debug)
- printk(KERN_INFO "pvrusb2: Debug mask is %d (0x%x)\n",
+ pr_info("pvrusb2: Debug mask is %d (0x%x)\n",
pvrusb2_debug,pvrusb2_debug);
pvr2_trace(PVR2_TRACE_INIT,"pvr_init complete");
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
index e53a80b589a1..97a93ed4bcda 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
@@ -121,10 +121,10 @@ static int pvr2_querycap(struct file *file, void *priv, struct v4l2_capability *
struct pvr2_v4l2_fh *fh = file->private_data;
struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
- strlcpy(cap->driver, "pvrusb2", sizeof(cap->driver));
- strlcpy(cap->bus_info, pvr2_hdw_get_bus_info(hdw),
- sizeof(cap->bus_info));
- strlcpy(cap->card, pvr2_hdw_get_desc(hdw), sizeof(cap->card));
+ strscpy(cap->driver, "pvrusb2", sizeof(cap->driver));
+ strscpy(cap->bus_info, pvr2_hdw_get_bus_info(hdw),
+ sizeof(cap->bus_info));
+ strscpy(cap->card, pvr2_hdw_get_desc(hdw), sizeof(cap->card));
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER |
V4L2_CAP_AUDIO | V4L2_CAP_RADIO |
V4L2_CAP_READWRITE | V4L2_CAP_DEVICE_CAPS;
@@ -545,7 +545,7 @@ static int pvr2_queryctrl(struct file *file, void *priv,
"QUERYCTRL id=0x%x mapping name=%s (%s)",
vc->id, pvr2_ctrl_get_name(cptr),
pvr2_ctrl_get_desc(cptr));
- strlcpy(vc->name, pvr2_ctrl_get_desc(cptr), sizeof(vc->name));
+ strscpy(vc->name, pvr2_ctrl_get_desc(cptr), sizeof(vc->name));
vc->flags = pvr2_ctrl_get_v4lflags(cptr);
pvr2_ctrl_get_def(cptr, &val);
vc->default_value = val;
@@ -869,7 +869,7 @@ static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
are gone. */
video_unregister_device(&dip->devbase);
- printk(KERN_INFO "%s\n", msg);
+ pr_info("%s\n", msg);
}
@@ -1260,7 +1260,7 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
": Failed to register pvrusb2 v4l device\n");
}
- printk(KERN_INFO "pvrusb2: registered device %s [%s]\n",
+ pr_info("pvrusb2: registered device %s [%s]\n",
video_device_node_name(&dip->devbase),
pvr2_config_get_name(dip->config));
diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c
index 54b036d39c5b..72704f4d5330 100644
--- a/drivers/media/usb/pwc/pwc-if.c
+++ b/drivers/media/usb/pwc/pwc-if.c
@@ -1027,7 +1027,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
/* Init video_device structure */
pdev->vdev = pwc_template;
- strcpy(pdev->vdev.name, name);
+ strscpy(pdev->vdev.name, name, sizeof(pdev->vdev.name));
pdev->vdev.queue = &pdev->vb_queue;
pdev->vdev.queue->lock = &pdev->vb_queue_lock;
video_set_drvdata(&pdev->vdev, pdev);
diff --git a/drivers/media/usb/pwc/pwc-v4l.c b/drivers/media/usb/pwc/pwc-v4l.c
index 043b2b97cee6..bef6e4ef8a7e 100644
--- a/drivers/media/usb/pwc/pwc-v4l.c
+++ b/drivers/media/usb/pwc/pwc-v4l.c
@@ -492,8 +492,8 @@ static int pwc_querycap(struct file *file, void *fh, struct v4l2_capability *cap
{
struct pwc_device *pdev = video_drvdata(file);
- strcpy(cap->driver, PWC_NAME);
- strlcpy(cap->card, pdev->vdev.name, sizeof(cap->card));
+ strscpy(cap->driver, PWC_NAME, sizeof(cap->driver));
+ strscpy(cap->card, pdev->vdev.name, sizeof(cap->card));
usb_make_path(pdev->udev, cap->bus_info, sizeof(cap->bus_info));
cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
V4L2_CAP_READWRITE;
@@ -506,7 +506,7 @@ static int pwc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
if (i->index) /* Only one INPUT is supported */
return -EINVAL;
- strlcpy(i->name, "Camera", sizeof(i->name));
+ strscpy(i->name, "Camera", sizeof(i->name));
i->type = V4L2_INPUT_TYPE_CAMERA;
return 0;
}
@@ -889,11 +889,13 @@ static int pwc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc
/* RAW format */
f->pixelformat = pdev->type <= 646 ? V4L2_PIX_FMT_PWC1 : V4L2_PIX_FMT_PWC2;
f->flags = V4L2_FMT_FLAG_COMPRESSED;
- strlcpy(f->description, "Raw Philips Webcam", sizeof(f->description));
+ strscpy(f->description, "Raw Philips Webcam",
+ sizeof(f->description));
break;
case 1:
f->pixelformat = V4L2_PIX_FMT_YUV420;
- strlcpy(f->description, "4:2:0, planar, Y-Cb-Cr", sizeof(f->description));
+ strscpy(f->description, "4:2:0, planar, Y-Cb-Cr",
+ sizeof(f->description));
break;
default:
return -EINVAL;
diff --git a/drivers/media/usb/rainshadow-cec/rainshadow-cec.c b/drivers/media/usb/rainshadow-cec/rainshadow-cec.c
index cecdcbcd400c..d9964da05976 100644
--- a/drivers/media/usb/rainshadow-cec/rainshadow-cec.c
+++ b/drivers/media/usb/rainshadow-cec/rainshadow-cec.c
@@ -141,7 +141,8 @@ static void rain_irq_work_handler(struct work_struct *work)
!memcmp(rain->cmd, "STA", 3)) {
rain_process_msg(rain);
} else {
- strcpy(rain->cmd_reply, rain->cmd);
+ strscpy(rain->cmd_reply, rain->cmd,
+ sizeof(rain->cmd_reply));
complete(&rain->cmd_done);
}
rain->cmd_idx = 0;
diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c
index 82927eb334c4..5b3e54b76e9a 100644
--- a/drivers/media/usb/s2255/s2255drv.c
+++ b/drivers/media/usb/s2255/s2255drv.c
@@ -730,8 +730,8 @@ static int vidioc_querycap(struct file *file, void *priv,
struct s2255_vc *vc = video_drvdata(file);
struct s2255_dev *dev = vc->dev;
- strlcpy(cap->driver, "s2255", sizeof(cap->driver));
- strlcpy(cap->card, "s2255", sizeof(cap->card));
+ strscpy(cap->driver, "s2255", sizeof(cap->driver));
+ strscpy(cap->card, "s2255", sizeof(cap->card));
usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
V4L2_CAP_READWRITE;
@@ -749,7 +749,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
if (!jpeg_enable && ((formats[index].fourcc == V4L2_PIX_FMT_JPEG) ||
(formats[index].fourcc == V4L2_PIX_FMT_MJPEG)))
return -EINVAL;
- strlcpy(f->description, formats[index].name, sizeof(f->description));
+ strscpy(f->description, formats[index].name, sizeof(f->description));
f->pixelformat = formats[index].fourcc;
return 0;
}
@@ -1195,10 +1195,10 @@ static int vidioc_enum_input(struct file *file, void *priv,
switch (dev->pid) {
case 0x2255:
default:
- strlcpy(inp->name, "Composite", sizeof(inp->name));
+ strscpy(inp->name, "Composite", sizeof(inp->name));
break;
case 0x2257:
- strlcpy(inp->name, (vc->idx < 2) ? "Composite" : "S-Video",
+ strscpy(inp->name, (vc->idx < 2) ? "Composite" : "S-Video",
sizeof(inp->name));
break;
}
diff --git a/drivers/media/usb/stk1160/stk1160-i2c.c b/drivers/media/usb/stk1160/stk1160-i2c.c
index 62a12d5356ad..c3a15564e5cb 100644
--- a/drivers/media/usb/stk1160/stk1160-i2c.c
+++ b/drivers/media/usb/stk1160/stk1160-i2c.c
@@ -260,7 +260,7 @@ int stk1160_i2c_register(struct stk1160 *dev)
dev->i2c_adap = adap_template;
dev->i2c_adap.dev.parent = dev->dev;
- strcpy(dev->i2c_adap.name, "stk1160");
+ strscpy(dev->i2c_adap.name, "stk1160", sizeof(dev->i2c_adap.name));
dev->i2c_adap.algo_data = dev;
i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c
index 504e413edcd2..701ed3d4afe6 100644
--- a/drivers/media/usb/stk1160/stk1160-v4l.c
+++ b/drivers/media/usb/stk1160/stk1160-v4l.c
@@ -344,8 +344,8 @@ static int vidioc_querycap(struct file *file,
{
struct stk1160 *dev = video_drvdata(file);
- strcpy(cap->driver, "stk1160");
- strcpy(cap->card, "stk1160");
+ strscpy(cap->driver, "stk1160", sizeof(cap->driver));
+ strscpy(cap->card, "stk1160", sizeof(cap->card));
usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
cap->device_caps =
V4L2_CAP_VIDEO_CAPTURE |
@@ -361,7 +361,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
if (f->index != 0)
return -EINVAL;
- strlcpy(f->description, format[f->index].name, sizeof(f->description));
+ strscpy(f->description, format[f->index].name, sizeof(f->description));
f->pixelformat = format[f->index].fourcc;
return 0;
}
diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c
index 5accb5241072..e11d5d5b7c26 100644
--- a/drivers/media/usb/stkwebcam/stk-webcam.c
+++ b/drivers/media/usb/stkwebcam/stk-webcam.c
@@ -793,8 +793,8 @@ static int stk_vidioc_querycap(struct file *filp,
{
struct stk_camera *dev = video_drvdata(filp);
- strcpy(cap->driver, "stk");
- strcpy(cap->card, "stk");
+ strscpy(cap->driver, "stk", sizeof(cap->driver));
+ strscpy(cap->card, "stk", sizeof(cap->card));
usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
cap->device_caps = V4L2_CAP_VIDEO_CAPTURE
@@ -809,7 +809,7 @@ static int stk_vidioc_enum_input(struct file *filp,
if (input->index != 0)
return -EINVAL;
- strcpy(input->name, "Syntek USB Camera");
+ strscpy(input->name, "Syntek USB Camera", sizeof(input->name));
input->type = V4L2_INPUT_TYPE_CAMERA;
return 0;
}
@@ -859,23 +859,23 @@ static int stk_vidioc_enum_fmt_vid_cap(struct file *filp,
switch (fmtd->index) {
case 0:
fmtd->pixelformat = V4L2_PIX_FMT_RGB565;
- strcpy(fmtd->description, "r5g6b5");
+ strscpy(fmtd->description, "r5g6b5", sizeof(fmtd->description));
break;
case 1:
fmtd->pixelformat = V4L2_PIX_FMT_RGB565X;
- strcpy(fmtd->description, "r5g6b5BE");
+ strscpy(fmtd->description, "r5g6b5BE", sizeof(fmtd->description));
break;
case 2:
fmtd->pixelformat = V4L2_PIX_FMT_UYVY;
- strcpy(fmtd->description, "yuv4:2:2");
+ strscpy(fmtd->description, "yuv4:2:2", sizeof(fmtd->description));
break;
case 3:
fmtd->pixelformat = V4L2_PIX_FMT_SBGGR8;
- strcpy(fmtd->description, "Raw bayer");
+ strscpy(fmtd->description, "Raw bayer", sizeof(fmtd->description));
break;
case 4:
fmtd->pixelformat = V4L2_PIX_FMT_YUYV;
- strcpy(fmtd->description, "yuv4:2:2");
+ strscpy(fmtd->description, "yuv4:2:2", sizeof(fmtd->description));
break;
default:
return -EINVAL;
diff --git a/drivers/media/usb/tm6000/tm6000-alsa.c b/drivers/media/usb/tm6000/tm6000-alsa.c
index f18cffae4c85..b965931793b5 100644
--- a/drivers/media/usb/tm6000/tm6000-alsa.c
+++ b/drivers/media/usb/tm6000/tm6000-alsa.c
@@ -429,8 +429,8 @@ static int tm6000_audio_init(struct tm6000_core *dev)
snd_printk(KERN_ERR "cannot create card instance %d\n", devnr);
return rc;
}
- strcpy(card->driver, "tm6000-alsa");
- strcpy(card->shortname, "TM5600/60x0");
+ strscpy(card->driver, "tm6000-alsa", sizeof(card->driver));
+ strscpy(card->shortname, "TM5600/60x0", sizeof(card->shortname));
sprintf(card->longname, "TM5600/60x0 Audio at bus %d device %d",
dev->udev->bus->busnum, dev->udev->devnum);
@@ -456,7 +456,7 @@ static int tm6000_audio_init(struct tm6000_core *dev)
pcm->info_flags = 0;
pcm->private_data = chip;
- strcpy(pcm->name, "Trident TM5600/60x0");
+ strscpy(pcm->name, "Trident TM5600/60x0", sizeof(pcm->name));
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_tm6000_pcm_ops);
diff --git a/drivers/media/usb/tm6000/tm6000-i2c.c b/drivers/media/usb/tm6000/tm6000-i2c.c
index ccd1adf862b1..8c0476dfe54f 100644
--- a/drivers/media/usb/tm6000/tm6000-i2c.c
+++ b/drivers/media/usb/tm6000/tm6000-i2c.c
@@ -292,7 +292,7 @@ int tm6000_i2c_register(struct tm6000_core *dev)
dev->i2c_adap.owner = THIS_MODULE;
dev->i2c_adap.algo = &tm6000_algo;
dev->i2c_adap.dev.parent = &dev->udev->dev;
- strlcpy(dev->i2c_adap.name, dev->name, sizeof(dev->i2c_adap.name));
+ strscpy(dev->i2c_adap.name, dev->name, sizeof(dev->i2c_adap.name));
dev->i2c_adap.algo_data = dev;
i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
rc = i2c_add_adapter(&dev->i2c_adap);
@@ -300,7 +300,7 @@ int tm6000_i2c_register(struct tm6000_core *dev)
return rc;
dev->i2c_client.adapter = &dev->i2c_adap;
- strlcpy(dev->i2c_client.name, "tm6000 internal", I2C_NAME_SIZE);
+ strscpy(dev->i2c_client.name, "tm6000 internal", I2C_NAME_SIZE);
tm6000_i2c_eeprom(dev);
return 0;
diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c
index 96055de6e8ce..ee7b5318b351 100644
--- a/drivers/media/usb/tm6000/tm6000-video.c
+++ b/drivers/media/usb/tm6000/tm6000-video.c
@@ -419,6 +419,7 @@ static void tm6000_irq_callback(struct urb *urb)
{
struct tm6000_dmaqueue *dma_q = urb->context;
struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
+ unsigned long flags;
int i;
switch (urb->status) {
@@ -436,9 +437,9 @@ static void tm6000_irq_callback(struct urb *urb)
break;
}
- spin_lock(&dev->slock);
+ spin_lock_irqsave(&dev->slock, flags);
tm6000_isoc_copy(urb);
- spin_unlock(&dev->slock);
+ spin_unlock_irqrestore(&dev->slock, flags);
/* Reset urb buffers */
for (i = 0; i < urb->number_of_packets; i++) {
@@ -855,8 +856,9 @@ static int vidioc_querycap(struct file *file, void *priv,
struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev;
struct video_device *vdev = video_devdata(file);
- strlcpy(cap->driver, "tm6000", sizeof(cap->driver));
- strlcpy(cap->card, "Trident TVMaster TM5600/6000/6010", sizeof(cap->card));
+ strscpy(cap->driver, "tm6000", sizeof(cap->driver));
+ strscpy(cap->card, "Trident TVMaster TM5600/6000/6010",
+ sizeof(cap->card));
usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
if (dev->tuner_type != TUNER_ABSENT)
cap->device_caps |= V4L2_CAP_TUNER;
@@ -878,7 +880,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
if (f->index >= ARRAY_SIZE(format))
return -EINVAL;
- strlcpy(f->description, format[f->index].name, sizeof(f->description));
+ strscpy(f->description, format[f->index].name, sizeof(f->description));
f->pixelformat = format[f->index].fourcc;
return 0;
}
@@ -1090,7 +1092,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
else
i->type = V4L2_INPUT_TYPE_CAMERA;
- strcpy(i->name, iname[dev->vinput[n].type]);
+ strscpy(i->name, iname[dev->vinput[n].type], sizeof(i->name));
i->std = TM6000_STD;
@@ -1187,7 +1189,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
if (0 != t->index)
return -EINVAL;
- strcpy(t->name, "Television");
+ strscpy(t->name, "Television", sizeof(t->name));
t->type = V4L2_TUNER_ANALOG_TV;
t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO;
t->rangehigh = 0xffffffffUL;
@@ -1267,7 +1269,7 @@ static int radio_g_tuner(struct file *file, void *priv,
return -EINVAL;
memset(t, 0, sizeof(*t));
- strcpy(t->name, "Radio");
+ strscpy(t->name, "Radio", sizeof(t->name));
t->type = V4L2_TUNER_RADIO;
t->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
t->rxsubchans = V4L2_TUNER_SUB_STEREO;
@@ -1625,7 +1627,7 @@ int tm6000_v4l2_register(struct tm6000_core *dev)
v4l2_ctrl_new_std(&dev->ctrl_handler, &tm6000_ctrl_ops,
V4L2_CID_HUE, -128, 127, 1, 0);
v4l2_ctrl_add_handler(&dev->ctrl_handler,
- &dev->radio_ctrl_handler, NULL);
+ &dev->radio_ctrl_handler, NULL, false);
if (dev->radio_ctrl_handler.error)
ret = dev->radio_ctrl_handler.error;
diff --git a/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c
index eed56895c2b9..6eb84cf007b4 100644
--- a/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c
+++ b/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c
@@ -1686,7 +1686,7 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
/* i2c */
memset(&ttusb->i2c_adap, 0, sizeof(struct i2c_adapter));
- strcpy(ttusb->i2c_adap.name, "TTUSB DEC");
+ strscpy(ttusb->i2c_adap.name, "TTUSB DEC", sizeof(ttusb->i2c_adap.name));
i2c_set_adapdata(&ttusb->i2c_adap, ttusb);
diff --git a/drivers/media/usb/usbtv/usbtv-audio.c b/drivers/media/usb/usbtv/usbtv-audio.c
index 4ce38246ed64..6f108996142d 100644
--- a/drivers/media/usb/usbtv/usbtv-audio.c
+++ b/drivers/media/usb/usbtv/usbtv-audio.c
@@ -358,8 +358,8 @@ int usbtv_audio_init(struct usbtv *usbtv)
if (rv < 0)
return rv;
- strlcpy(card->driver, usbtv->dev->driver->name, sizeof(card->driver));
- strlcpy(card->shortname, "usbtv", sizeof(card->shortname));
+ strscpy(card->driver, usbtv->dev->driver->name, sizeof(card->driver));
+ strscpy(card->shortname, "usbtv", sizeof(card->shortname));
snprintf(card->longname, sizeof(card->longname),
"USBTV Audio at bus %d device %d", usbtv->udev->bus->busnum,
usbtv->udev->devnum);
@@ -372,7 +372,7 @@ int usbtv_audio_init(struct usbtv *usbtv)
if (rv < 0)
goto err;
- strlcpy(pcm->name, "USBTV Audio Input", sizeof(pcm->name));
+ strscpy(pcm->name, "USBTV Audio Input", sizeof(pcm->name));
pcm->info_flags = 0;
pcm->private_data = usbtv;
diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c
index 36a9a4017185..4a1eab711bdc 100644
--- a/drivers/media/usb/usbtv/usbtv-video.c
+++ b/drivers/media/usb/usbtv/usbtv-video.c
@@ -600,8 +600,8 @@ static int usbtv_querycap(struct file *file, void *priv,
{
struct usbtv *dev = video_drvdata(file);
- strlcpy(cap->driver, "usbtv", sizeof(cap->driver));
- strlcpy(cap->card, "usbtv", sizeof(cap->card));
+ strscpy(cap->driver, "usbtv", sizeof(cap->driver));
+ strscpy(cap->card, "usbtv", sizeof(cap->card));
usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
cap->device_caps = V4L2_CAP_VIDEO_CAPTURE;
cap->device_caps |= V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
@@ -616,10 +616,10 @@ static int usbtv_enum_input(struct file *file, void *priv,
switch (i->index) {
case USBTV_COMPOSITE_INPUT:
- strlcpy(i->name, "Composite", sizeof(i->name));
+ strscpy(i->name, "Composite", sizeof(i->name));
break;
case USBTV_SVIDEO_INPUT:
- strlcpy(i->name, "S-Video", sizeof(i->name));
+ strscpy(i->name, "S-Video", sizeof(i->name));
break;
default:
return -EINVAL;
@@ -636,8 +636,8 @@ static int usbtv_enum_fmt_vid_cap(struct file *file, void *priv,
if (f->index > 0)
return -EINVAL;
- strlcpy(f->description, "16 bpp YUY2, 4:2:2, packed",
- sizeof(f->description));
+ strscpy(f->description, "16 bpp YUY2, 4:2:2, packed",
+ sizeof(f->description));
f->pixelformat = V4L2_PIX_FMT_YUYV;
return 0;
}
@@ -934,7 +934,7 @@ int usbtv_video_init(struct usbtv *usbtv)
}
/* Video structure */
- strlcpy(usbtv->vdev.name, "usbtv", sizeof(usbtv->vdev.name));
+ strscpy(usbtv->vdev.name, "usbtv", sizeof(usbtv->vdev.name));
usbtv->vdev.v4l2_dev = &usbtv->v4l2_dev;
usbtv->vdev.release = video_device_release_empty;
usbtv->vdev.fops = &usbtv_fops;
diff --git a/drivers/media/usb/usbvision/usbvision-core.c b/drivers/media/usb/usbvision/usbvision-core.c
index 7138c2b606cc..31e0e98d6daf 100644
--- a/drivers/media/usb/usbvision/usbvision-core.c
+++ b/drivers/media/usb/usbvision/usbvision-core.c
@@ -1272,7 +1272,6 @@ static void usbvision_isoc_irq(struct urb *urb)
int len;
struct usb_usbvision *usbvision = urb->context;
int i;
- unsigned long start_time = jiffies;
struct usbvision_frame **f;
/* We don't want to do anything if we are about to be removed! */
@@ -1324,8 +1323,6 @@ static void usbvision_isoc_irq(struct urb *urb)
scratch_reset(usbvision);
}
- usbvision->time_in_irq += jiffies - start_time;
-
for (i = 0; i < USBVISION_URB_FRAMES; i++) {
urb->iso_frame_desc[i].status = 0;
urb->iso_frame_desc[i].actual_length = 0;
diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c
index f29d1bef0293..dd2ff8ed6c6a 100644
--- a/drivers/media/usb/usbvision/usbvision-video.c
+++ b/drivers/media/usb/usbvision/usbvision-video.c
@@ -467,8 +467,8 @@ static int vidioc_querycap(struct file *file, void *priv,
struct usb_usbvision *usbvision = video_drvdata(file);
struct video_device *vdev = video_devdata(file);
- strlcpy(vc->driver, "USBVision", sizeof(vc->driver));
- strlcpy(vc->card,
+ strscpy(vc->driver, "USBVision", sizeof(vc->driver));
+ strscpy(vc->card,
usbvision_device_data[usbvision->dev_model].model_string,
sizeof(vc->card));
usb_make_path(usbvision->dev, vc->bus_info, sizeof(vc->bus_info));
@@ -504,9 +504,9 @@ static int vidioc_enum_input(struct file *file, void *priv,
switch (chan) {
case 0:
if (usbvision_device_data[usbvision->dev_model].video_channels == 4) {
- strcpy(vi->name, "White Video Input");
+ strscpy(vi->name, "White Video Input", sizeof(vi->name));
} else {
- strcpy(vi->name, "Television");
+ strscpy(vi->name, "Television", sizeof(vi->name));
vi->type = V4L2_INPUT_TYPE_TUNER;
vi->tuner = chan;
vi->std = USBVISION_NORMS;
@@ -515,22 +515,23 @@ static int vidioc_enum_input(struct file *file, void *priv,
case 1:
vi->type = V4L2_INPUT_TYPE_CAMERA;
if (usbvision_device_data[usbvision->dev_model].video_channels == 4)
- strcpy(vi->name, "Green Video Input");
+ strscpy(vi->name, "Green Video Input", sizeof(vi->name));
else
- strcpy(vi->name, "Composite Video Input");
+ strscpy(vi->name, "Composite Video Input",
+ sizeof(vi->name));
vi->std = USBVISION_NORMS;
break;
case 2:
vi->type = V4L2_INPUT_TYPE_CAMERA;
if (usbvision_device_data[usbvision->dev_model].video_channels == 4)
- strcpy(vi->name, "Yellow Video Input");
+ strscpy(vi->name, "Yellow Video Input", sizeof(vi->name));
else
- strcpy(vi->name, "S-Video Input");
+ strscpy(vi->name, "S-Video Input", sizeof(vi->name));
vi->std = USBVISION_NORMS;
break;
case 3:
vi->type = V4L2_INPUT_TYPE_CAMERA;
- strcpy(vi->name, "Red Video Input");
+ strscpy(vi->name, "Red Video Input", sizeof(vi->name));
vi->std = USBVISION_NORMS;
break;
}
@@ -589,9 +590,9 @@ static int vidioc_g_tuner(struct file *file, void *priv,
if (vt->index) /* Only tuner 0 */
return -EINVAL;
if (vt->type == V4L2_TUNER_RADIO)
- strcpy(vt->name, "Radio");
+ strscpy(vt->name, "Radio", sizeof(vt->name));
else
- strcpy(vt->name, "Television");
+ strscpy(vt->name, "Television", sizeof(vt->name));
/* Let clients fill in the remainder of this struct */
call_all(usbvision, tuner, g_tuner, vt);
@@ -814,7 +815,8 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
{
if (vfd->index >= USBVISION_SUPPORTED_PALETTES - 1)
return -EINVAL;
- strcpy(vfd->description, usbvision_v4l2_format[vfd->index].desc);
+ strscpy(vfd->description, usbvision_v4l2_format[vfd->index].desc,
+ sizeof(vfd->description));
vfd->pixelformat = usbvision_v4l2_format[vfd->index].format;
return 0;
}
diff --git a/drivers/media/usb/usbvision/usbvision.h b/drivers/media/usb/usbvision/usbvision.h
index 6ecdcd58248f..017e7baf5747 100644
--- a/drivers/media/usb/usbvision/usbvision.h
+++ b/drivers/media/usb/usbvision/usbvision.h
@@ -447,7 +447,6 @@ struct usb_usbvision {
unsigned long isoc_skip_count; /* How many empty ISO packets received */
unsigned long isoc_err_count; /* How many bad ISO packets received */
unsigned long isoc_packet_count; /* How many packets we totally got */
- unsigned long time_in_irq; /* How long do we need for interrupt */
int isoc_measure_bandwidth_count;
int frame_num; /* How many video frames we send to user */
int max_strip_len; /* How big is the biggest strip */
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index c2ad102bd693..d45415cbe6e7 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -38,7 +38,7 @@
* Controls
*/
-static struct uvc_control_info uvc_ctrls[] = {
+static const struct uvc_control_info uvc_ctrls[] = {
{
.entity = UVC_GUID_UVC_PROCESSING,
.selector = UVC_PU_BRIGHTNESS_CONTROL,
@@ -354,13 +354,13 @@ static struct uvc_control_info uvc_ctrls[] = {
},
};
-static struct uvc_menu_info power_line_frequency_controls[] = {
+static const struct uvc_menu_info power_line_frequency_controls[] = {
{ 0, "Disabled" },
{ 1, "50 Hz" },
{ 2, "60 Hz" },
};
-static struct uvc_menu_info exposure_auto_controls[] = {
+static const struct uvc_menu_info exposure_auto_controls[] = {
{ 2, "Auto Mode" },
{ 1, "Manual Mode" },
{ 4, "Shutter Priority Mode" },
@@ -421,7 +421,7 @@ static void uvc_ctrl_set_rel_speed(struct uvc_control_mapping *mapping,
data[first+1] = min_t(int, abs(value), 0xff);
}
-static struct uvc_control_mapping uvc_ctrl_mappings[] = {
+static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
{
.id = V4L2_CID_BRIGHTNESS,
.name = "Brightness",
@@ -978,7 +978,7 @@ static s32 __uvc_ctrl_get_value(struct uvc_control_mapping *mapping,
s32 value = mapping->get(mapping, UVC_GET_CUR, data);
if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {
- struct uvc_menu_info *menu = mapping->menu_info;
+ const struct uvc_menu_info *menu = mapping->menu_info;
unsigned int i;
for (i = 0; i < mapping->menu_count; ++i, ++menu) {
@@ -1025,13 +1025,13 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
{
struct uvc_control_mapping *master_map = NULL;
struct uvc_control *master_ctrl = NULL;
- struct uvc_menu_info *menu;
+ const struct uvc_menu_info *menu;
unsigned int i;
memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl));
v4l2_ctrl->id = mapping->id;
v4l2_ctrl->type = mapping->v4l2_type;
- strlcpy(v4l2_ctrl->name, mapping->name, sizeof(v4l2_ctrl->name));
+ strscpy(v4l2_ctrl->name, mapping->name, sizeof(v4l2_ctrl->name));
v4l2_ctrl->flags = 0;
if (!(ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR))
@@ -1145,7 +1145,7 @@ done:
int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
struct v4l2_querymenu *query_menu)
{
- struct uvc_menu_info *menu_info;
+ const struct uvc_menu_info *menu_info;
struct uvc_control_mapping *mapping;
struct uvc_control *ctrl;
u32 index = query_menu->index;
@@ -1191,7 +1191,7 @@ int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
}
}
- strlcpy(query_menu->name, menu_info->name, sizeof(query_menu->name));
+ strscpy(query_menu->name, menu_info->name, sizeof(query_menu->name));
done:
mutex_unlock(&chain->ctrl_mutex);
diff --git a/drivers/media/usb/uvc/uvc_debugfs.c b/drivers/media/usb/uvc/uvc_debugfs.c
index 368f8f8dfcb5..77e7c2419b9b 100644
--- a/drivers/media/usb/uvc/uvc_debugfs.c
+++ b/drivers/media/usb/uvc/uvc_debugfs.c
@@ -106,9 +106,6 @@ void uvc_debugfs_init_stream(struct uvc_streaming *stream)
void uvc_debugfs_cleanup_stream(struct uvc_streaming *stream)
{
- if (stream->debugfs_dir == NULL)
- return;
-
debugfs_remove_recursive(stream->debugfs_dir);
stream->debugfs_dir = NULL;
}
@@ -128,6 +125,5 @@ void uvc_debugfs_init(void)
void uvc_debugfs_cleanup(void)
{
- if (uvc_debugfs_root_dir != NULL)
- debugfs_remove_recursive(uvc_debugfs_root_dir);
+ debugfs_remove_recursive(uvc_debugfs_root_dir);
}
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index d46dc432456c..bc369a0934a3 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -427,7 +427,7 @@ static int uvc_parse_format(struct uvc_device *dev,
fmtdesc = uvc_format_by_guid(&buffer[5]);
if (fmtdesc != NULL) {
- strlcpy(format->name, fmtdesc->name,
+ strscpy(format->name, fmtdesc->name,
sizeof(format->name));
format->fcc = fmtdesc->fcc;
} else {
@@ -445,7 +445,7 @@ static int uvc_parse_format(struct uvc_device *dev,
*/
if (dev->quirks & UVC_QUIRK_FORCE_Y8) {
if (format->fcc == V4L2_PIX_FMT_YUYV) {
- strlcpy(format->name, "Greyscale 8-bit (Y8 )",
+ strscpy(format->name, "Greyscale 8-bit (Y8 )",
sizeof(format->name));
format->fcc = V4L2_PIX_FMT_GREY;
format->bpp = 8;
@@ -471,7 +471,7 @@ static int uvc_parse_format(struct uvc_device *dev,
return -EINVAL;
}
- strlcpy(format->name, "MJPEG", sizeof(format->name));
+ strscpy(format->name, "MJPEG", sizeof(format->name));
format->fcc = V4L2_PIX_FMT_MJPEG;
format->flags = UVC_FMT_FLAG_COMPRESSED;
format->bpp = 0;
@@ -489,13 +489,13 @@ static int uvc_parse_format(struct uvc_device *dev,
switch (buffer[8] & 0x7f) {
case 0:
- strlcpy(format->name, "SD-DV", sizeof(format->name));
+ strscpy(format->name, "SD-DV", sizeof(format->name));
break;
case 1:
- strlcpy(format->name, "SDL-DV", sizeof(format->name));
+ strscpy(format->name, "SDL-DV", sizeof(format->name));
break;
case 2:
- strlcpy(format->name, "HD-DV", sizeof(format->name));
+ strscpy(format->name, "HD-DV", sizeof(format->name));
break;
default:
uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
@@ -914,7 +914,7 @@ static struct uvc_entity *uvc_alloc_entity(u16 type, u8 id,
unsigned int size;
unsigned int i;
- extra_size = ALIGN(extra_size, sizeof(*entity->pads));
+ extra_size = roundup(extra_size, sizeof(*entity->pads));
num_inputs = (type & UVC_TERM_OUTPUT) ? num_pads : num_pads - 1;
size = sizeof(*entity) + extra_size + sizeof(*entity->pads) * num_pads
+ num_inputs;
@@ -1932,7 +1932,7 @@ int uvc_register_video_device(struct uvc_device *dev,
break;
}
- strlcpy(vdev->name, dev->name, sizeof(vdev->name));
+ strscpy(vdev->name, dev->name, sizeof(vdev->name));
/*
* Set the driver data before calling video_register_device, otherwise
@@ -2027,10 +2027,9 @@ static int uvc_register_chains(struct uvc_device *dev)
#ifdef CONFIG_MEDIA_CONTROLLER
ret = uvc_mc_register_entities(chain);
- if (ret < 0) {
- uvc_printk(KERN_INFO, "Failed to register entites "
- "(%d).\n", ret);
- }
+ if (ret < 0)
+ uvc_printk(KERN_INFO,
+ "Failed to register entities (%d).\n", ret);
#endif
}
@@ -2041,10 +2040,7 @@ static int uvc_register_chains(struct uvc_device *dev)
* USB probe, disconnect, suspend and resume
*/
-struct uvc_device_info {
- u32 quirks;
- u32 meta_format;
-};
+static const struct uvc_device_info uvc_quirk_none = { 0 };
static int uvc_probe(struct usb_interface *intf,
const struct usb_device_id *id)
@@ -2053,7 +2049,6 @@ static int uvc_probe(struct usb_interface *intf,
struct uvc_device *dev;
const struct uvc_device_info *info =
(const struct uvc_device_info *)id->driver_info;
- u32 quirks = info ? info->quirks : 0;
int function;
int ret;
@@ -2080,13 +2075,12 @@ static int uvc_probe(struct usb_interface *intf,
dev->udev = usb_get_dev(udev);
dev->intf = usb_get_intf(intf);
dev->intfnum = intf->cur_altsetting->desc.bInterfaceNumber;
- dev->quirks = (uvc_quirks_param == -1)
- ? quirks : uvc_quirks_param;
- if (info)
- dev->meta_format = info->meta_format;
+ dev->info = info ? info : &uvc_quirk_none;
+ dev->quirks = uvc_quirks_param == -1
+ ? dev->info->quirks : uvc_quirks_param;
if (udev->product != NULL)
- strlcpy(dev->name, udev->product, sizeof(dev->name));
+ strscpy(dev->name, udev->product, sizeof(dev->name));
else
snprintf(dev->name, sizeof(dev->name),
"UVC Camera (%04x:%04x)",
@@ -2124,7 +2118,7 @@ static int uvc_probe(struct usb_interface *intf,
le16_to_cpu(udev->descriptor.idVendor),
le16_to_cpu(udev->descriptor.idProduct));
- if (dev->quirks != quirks) {
+ if (dev->quirks != dev->info->quirks) {
uvc_printk(KERN_INFO, "Forcing device quirks to 0x%x by module "
"parameter for testing purpose.\n", dev->quirks);
uvc_printk(KERN_INFO, "Please report required quirks to the "
@@ -2134,11 +2128,11 @@ static int uvc_probe(struct usb_interface *intf,
/* Initialize the media device and register the V4L2 device. */
#ifdef CONFIG_MEDIA_CONTROLLER
dev->mdev.dev = &intf->dev;
- strlcpy(dev->mdev.model, dev->name, sizeof(dev->mdev.model));
+ strscpy(dev->mdev.model, dev->name, sizeof(dev->mdev.model));
if (udev->serial)
- strlcpy(dev->mdev.serial, udev->serial,
+ strscpy(dev->mdev.serial, udev->serial,
sizeof(dev->mdev.serial));
- strcpy(dev->mdev.bus_info, udev->devpath);
+ strscpy(dev->mdev.bus_info, udev->devpath, sizeof(dev->mdev.bus_info));
dev->mdev.hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
media_device_init(&dev->mdev);
@@ -2344,7 +2338,9 @@ static const struct uvc_device_info uvc_quirk_force_y8 = {
.quirks = UVC_QUIRK_FORCE_Y8,
};
-#define UVC_QUIRK_INFO(q) (kernel_ulong_t)&(struct uvc_device_info){.quirks = q}
+#define UVC_INFO_QUIRK(q) (kernel_ulong_t)&(struct uvc_device_info){.quirks = q}
+#define UVC_INFO_META(m) (kernel_ulong_t)&(struct uvc_device_info) \
+ {.meta_format = m}
/*
* The Logitech cameras listed below have their interface class set to
@@ -2453,7 +2449,7 @@ static const struct usb_device_id uvc_ids[] = {
.bInterfaceClass = USB_CLASS_VIDEO,
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_INFO(UVC_QUIRK_RESTORE_CTRLS_ON_INIT) },
+ .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_RESTORE_CTRLS_ON_INIT) },
/* Chicony CNF7129 (Asus EEE 100HE) */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2462,7 +2458,7 @@ static const struct usb_device_id uvc_ids[] = {
.bInterfaceClass = USB_CLASS_VIDEO,
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_INFO(UVC_QUIRK_RESTRICT_FRAME_RATE) },
+ .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_RESTRICT_FRAME_RATE) },
/* Alcor Micro AU3820 (Future Boy PC USB Webcam) */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2525,7 +2521,7 @@ static const struct usb_device_id uvc_ids[] = {
.bInterfaceClass = USB_CLASS_VIDEO,
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_INFO(UVC_QUIRK_PROBE_MINMAX
+ .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_PROBE_MINMAX
| UVC_QUIRK_BUILTIN_ISIGHT) },
/* Apple Built-In iSight via iBridge */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
@@ -2607,7 +2603,7 @@ static const struct usb_device_id uvc_ids[] = {
.bInterfaceClass = USB_CLASS_VIDEO,
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_INFO(UVC_QUIRK_PROBE_MINMAX
+ .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_PROBE_MINMAX
| UVC_QUIRK_PROBE_DEF) },
/* IMC Networks (Medion Akoya) */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
@@ -2707,7 +2703,7 @@ static const struct usb_device_id uvc_ids[] = {
.bInterfaceClass = USB_CLASS_VIDEO,
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_INFO(UVC_QUIRK_PROBE_MINMAX
+ .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_PROBE_MINMAX
| UVC_QUIRK_PROBE_EXTRAFIELDS) },
/* Aveo Technology USB 2.0 Camera (Tasco USB Microscope) */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
@@ -2725,7 +2721,7 @@ static const struct usb_device_id uvc_ids[] = {
.bInterfaceClass = USB_CLASS_VIDEO,
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_INFO(UVC_QUIRK_PROBE_EXTRAFIELDS) },
+ .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_PROBE_EXTRAFIELDS) },
/* Manta MM-353 Plako */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2771,7 +2767,7 @@ static const struct usb_device_id uvc_ids[] = {
.bInterfaceClass = USB_CLASS_VIDEO,
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_INFO(UVC_QUIRK_STATUS_INTERVAL) },
+ .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_STATUS_INTERVAL) },
/* MSI StarCam 370i */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2798,7 +2794,7 @@ static const struct usb_device_id uvc_ids[] = {
.bInterfaceClass = USB_CLASS_VIDEO,
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_INFO(UVC_QUIRK_PROBE_MINMAX
+ .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_PROBE_MINMAX
| UVC_QUIRK_IGNORE_SELECTOR_UNIT) },
/* Oculus VR Positional Tracker DK2 */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
@@ -2818,6 +2814,15 @@ static const struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = (kernel_ulong_t)&uvc_quirk_force_y8 },
+ /* Intel RealSense D4M */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x8086,
+ .idProduct = 0x0b03,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) },
/* Generic USB Video Class */
{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_UNDEFINED) },
{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_15) },
diff --git a/drivers/media/usb/uvc/uvc_entity.c b/drivers/media/usb/uvc/uvc_entity.c
index 554063c07d7a..06bffdf8828b 100644
--- a/drivers/media/usb/uvc/uvc_entity.c
+++ b/drivers/media/usb/uvc/uvc_entity.c
@@ -79,7 +79,7 @@ static int uvc_mc_init_entity(struct uvc_video_chain *chain,
if (UVC_ENTITY_TYPE(entity) != UVC_TT_STREAMING) {
v4l2_subdev_init(&entity->subdev, &uvc_subdev_ops);
- strlcpy(entity->subdev.name, entity->name,
+ strscpy(entity->subdev.name, entity->name,
sizeof(entity->subdev.name));
ret = media_entity_pads_init(&entity->subdev.entity,
diff --git a/drivers/media/usb/uvc/uvc_metadata.c b/drivers/media/usb/uvc/uvc_metadata.c
index cd1aec19cc5b..5f535b515c23 100644
--- a/drivers/media/usb/uvc/uvc_metadata.c
+++ b/drivers/media/usb/uvc/uvc_metadata.c
@@ -33,8 +33,8 @@ static int uvc_meta_v4l2_querycap(struct file *file, void *fh,
struct uvc_streaming *stream = video_get_drvdata(vfh->vdev);
struct uvc_video_chain *chain = stream->chain;
- strlcpy(cap->driver, "uvcvideo", sizeof(cap->driver));
- strlcpy(cap->card, vfh->vdev->name, sizeof(cap->card));
+ strscpy(cap->driver, "uvcvideo", sizeof(cap->driver));
+ strscpy(cap->card, vfh->vdev->name, sizeof(cap->card));
usb_make_path(stream->dev->udev, cap->bus_info, sizeof(cap->bus_info));
cap->capabilities = V4L2_CAP_DEVICE_CAPS | V4L2_CAP_STREAMING
| chain->caps;
@@ -74,7 +74,8 @@ static int uvc_meta_v4l2_try_format(struct file *file, void *fh,
memset(fmt, 0, sizeof(*fmt));
- fmt->dataformat = fmeta == dev->meta_format ? fmeta : V4L2_META_FMT_UVC;
+ fmt->dataformat = fmeta == dev->info->meta_format
+ ? fmeta : V4L2_META_FMT_UVC;
fmt->buffersize = UVC_METATADA_BUF_SIZE;
return 0;
@@ -118,14 +119,14 @@ static int uvc_meta_v4l2_enum_formats(struct file *file, void *fh,
u32 index = fdesc->index;
if (fdesc->type != vfh->vdev->queue->type ||
- index > 1U || (index && !dev->meta_format))
+ index > 1U || (index && !dev->info->meta_format))
return -EINVAL;
memset(fdesc, 0, sizeof(*fdesc));
fdesc->type = vfh->vdev->queue->type;
fdesc->index = index;
- fdesc->pixelformat = index ? dev->meta_format : V4L2_META_FMT_UVC;
+ fdesc->pixelformat = index ? dev->info->meta_format : V4L2_META_FMT_UVC;
return 0;
}
diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c
index fecccb5e7628..8964e16f2b22 100644
--- a/drivers/media/usb/uvc/uvc_queue.c
+++ b/drivers/media/usb/uvc/uvc_queue.c
@@ -300,12 +300,13 @@ int uvc_create_buffers(struct uvc_video_queue *queue,
return ret;
}
-int uvc_queue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf)
+int uvc_queue_buffer(struct uvc_video_queue *queue,
+ struct media_device *mdev, struct v4l2_buffer *buf)
{
int ret;
mutex_lock(&queue->mutex);
- ret = vb2_qbuf(&queue->queue, buf);
+ ret = vb2_qbuf(&queue->queue, mdev, buf);
mutex_unlock(&queue->mutex);
return ret;
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index 18a7384b50ee..84be596d3269 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -591,8 +591,8 @@ static int uvc_ioctl_querycap(struct file *file, void *fh,
struct uvc_video_chain *chain = handle->chain;
struct uvc_streaming *stream = handle->stream;
- strlcpy(cap->driver, "uvcvideo", sizeof(cap->driver));
- strlcpy(cap->card, vdev->name, sizeof(cap->card));
+ strscpy(cap->driver, "uvcvideo", sizeof(cap->driver));
+ strscpy(cap->card, vdev->name, sizeof(cap->card));
usb_make_path(stream->dev->udev, cap->bus_info, sizeof(cap->bus_info));
cap->capabilities = V4L2_CAP_DEVICE_CAPS | V4L2_CAP_STREAMING
| chain->caps;
@@ -618,7 +618,7 @@ static int uvc_ioctl_enum_fmt(struct uvc_streaming *stream,
fmt->flags = 0;
if (format->flags & UVC_FMT_FLAG_COMPRESSED)
fmt->flags |= V4L2_FMT_FLAG_COMPRESSED;
- strlcpy(fmt->description, format->name, sizeof(fmt->description));
+ strscpy(fmt->description, format->name, sizeof(fmt->description));
fmt->description[sizeof(fmt->description) - 1] = 0;
fmt->pixelformat = format->fcc;
return 0;
@@ -751,7 +751,8 @@ static int uvc_ioctl_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
if (!uvc_has_privileges(handle))
return -EBUSY;
- return uvc_queue_buffer(&stream->queue, buf);
+ return uvc_queue_buffer(&stream->queue,
+ stream->vdev.v4l2_dev->mdev, buf);
}
static int uvc_ioctl_expbuf(struct file *file, void *fh,
@@ -859,7 +860,7 @@ static int uvc_ioctl_enum_input(struct file *file, void *fh,
memset(input, 0, sizeof(*input));
input->index = index;
- strlcpy(input->name, iterm->name, sizeof(input->name));
+ strscpy(input->name, iterm->name, sizeof(input->name));
if (UVC_ENTITY_TYPE(iterm) == UVC_ITT_CAMERA)
input->type = V4L2_INPUT_TYPE_CAMERA;
@@ -939,7 +940,7 @@ static int uvc_ioctl_query_ext_ctrl(struct file *file, void *fh,
qec->id = qc.id;
qec->type = qc.type;
- strlcpy(qec->name, qc.name, sizeof(qec->name));
+ strscpy(qec->name, qc.name, sizeof(qec->name));
qec->minimum = qc.minimum;
qec->maximum = qc.maximum;
qec->step = qc.step;
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index e5f5d84f1d1d..c0cbd833d0a4 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -234,7 +234,7 @@ struct uvc_control_mapping {
enum v4l2_ctrl_type v4l2_type;
u32 data_type;
- struct uvc_menu_info *menu_info;
+ const struct uvc_menu_info *menu_info;
u32 menu_count;
u32 master_id;
@@ -572,15 +572,21 @@ struct uvc_streaming {
} clock;
};
+struct uvc_device_info {
+ u32 quirks;
+ u32 meta_format;
+};
+
struct uvc_device {
struct usb_device *udev;
struct usb_interface *intf;
unsigned long warnings;
u32 quirks;
- u32 meta_format;
int intfnum;
char name[32];
+ const struct uvc_device_info *info;
+
struct mutex lock; /* Protects users */
unsigned int users;
atomic_t nmappings;
@@ -694,6 +700,7 @@ int uvc_query_buffer(struct uvc_video_queue *queue,
int uvc_create_buffers(struct uvc_video_queue *queue,
struct v4l2_create_buffers *v4l2_cb);
int uvc_queue_buffer(struct uvc_video_queue *queue,
+ struct media_device *mdev,
struct v4l2_buffer *v4l2_buf);
int uvc_export_buffer(struct uvc_video_queue *queue,
struct v4l2_exportbuffer *exp);
diff --git a/drivers/media/usb/zr364xx/zr364xx.c b/drivers/media/usb/zr364xx/zr364xx.c
index b8886102c5ed..ab35554cbffa 100644
--- a/drivers/media/usb/zr364xx/zr364xx.c
+++ b/drivers/media/usb/zr364xx/zr364xx.c
@@ -702,9 +702,9 @@ static int zr364xx_vidioc_querycap(struct file *file, void *priv,
{
struct zr364xx_camera *cam = video_drvdata(file);
- strlcpy(cap->driver, DRIVER_DESC, sizeof(cap->driver));
- strlcpy(cap->card, cam->udev->product, sizeof(cap->card));
- strlcpy(cap->bus_info, dev_name(&cam->udev->dev),
+ strscpy(cap->driver, DRIVER_DESC, sizeof(cap->driver));
+ strscpy(cap->card, cam->udev->product, sizeof(cap->card));
+ strscpy(cap->bus_info, dev_name(&cam->udev->dev),
sizeof(cap->bus_info));
cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_READWRITE |
@@ -719,7 +719,7 @@ static int zr364xx_vidioc_enum_input(struct file *file, void *priv,
{
if (i->index != 0)
return -EINVAL;
- strcpy(i->name, DRIVER_DESC " Camera");
+ strscpy(i->name, DRIVER_DESC " Camera", sizeof(i->name));
i->type = V4L2_INPUT_TYPE_CAMERA;
return 0;
}
@@ -765,7 +765,7 @@ static int zr364xx_vidioc_enum_fmt_vid_cap(struct file *file,
if (f->index > 0)
return -EINVAL;
f->flags = V4L2_FMT_FLAG_COMPRESSED;
- strcpy(f->description, formats[0].name);
+ strscpy(f->description, formats[0].name, sizeof(f->description));
f->pixelformat = formats[0].fourcc;
return 0;
}
diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c
index 7f858c39753c..03a340cb5a9b 100644
--- a/drivers/media/v4l2-core/tuner-core.c
+++ b/drivers/media/v4l2-core/tuner-core.c
@@ -94,9 +94,56 @@ static const struct v4l2_subdev_ops tuner_ops;
} while (0)
/*
- * Internal struct used inside the driver
+ * Internal enums/struct used inside the driver
*/
+/**
+ * enum tuner_pad_index - tuner pad index for MEDIA_ENT_F_TUNER
+ *
+ * @TUNER_PAD_RF_INPUT:
+ * Radiofrequency (RF) sink pad, usually linked to a RF connector entity.
+ * @TUNER_PAD_OUTPUT:
+ * tuner video output source pad. Contains the video chrominance
+ * and luminance or the hole bandwidth of the signal converted to
+ * an Intermediate Frequency (IF) or to baseband (on zero-IF tuners).
+ * @TUNER_PAD_AUD_OUT:
+ * Tuner audio output source pad. Tuners used to decode analog TV
+ * signals have an extra pad for audio output. Old tuners use an
+ * analog stage with a saw filter for the audio IF frequency. The
+ * output of the pad is, in this case, the audio IF, with should be
+ * decoded either by the bridge chipset (that's the case of cx2388x
+ * chipsets) or may require an external IF sound processor, like
+ * msp34xx. On modern silicon tuners, the audio IF decoder is usually
+ * incorporated at the tuner. On such case, the output of this pad
+ * is an audio sampled data.
+ * @TUNER_NUM_PADS:
+ * Number of pads of the tuner.
+ */
+enum tuner_pad_index {
+ TUNER_PAD_RF_INPUT,
+ TUNER_PAD_OUTPUT,
+ TUNER_PAD_AUD_OUT,
+ TUNER_NUM_PADS
+};
+
+/**
+ * enum if_vid_dec_pad_index - video IF-PLL pad index
+ * for MEDIA_ENT_F_IF_VID_DECODER
+ *
+ * @IF_VID_DEC_PAD_IF_INPUT:
+ * video Intermediate Frequency (IF) sink pad
+ * @IF_VID_DEC_PAD_OUT:
+ * IF-PLL video output source pad. Contains the video chrominance
+ * and luminance IF signals.
+ * @IF_VID_DEC_PAD_NUM_PADS:
+ * Number of pads of the video IF-PLL.
+ */
+enum if_vid_dec_pad_index {
+ IF_VID_DEC_PAD_IF_INPUT,
+ IF_VID_DEC_PAD_OUT,
+ IF_VID_DEC_PAD_NUM_PADS
+};
+
struct tuner {
/* device */
struct dvb_frontend fe;
@@ -685,15 +732,20 @@ register_client:
*/
if (t->type == TUNER_TDA9887) {
t->pad[IF_VID_DEC_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK;
+ t->pad[IF_VID_DEC_PAD_IF_INPUT].sig_type = PAD_SIGNAL_ANALOG;
t->pad[IF_VID_DEC_PAD_OUT].flags = MEDIA_PAD_FL_SOURCE;
+ t->pad[IF_VID_DEC_PAD_OUT].sig_type = PAD_SIGNAL_ANALOG;
ret = media_entity_pads_init(&t->sd.entity,
IF_VID_DEC_PAD_NUM_PADS,
&t->pad[0]);
t->sd.entity.function = MEDIA_ENT_F_IF_VID_DECODER;
} else {
t->pad[TUNER_PAD_RF_INPUT].flags = MEDIA_PAD_FL_SINK;
+ t->pad[TUNER_PAD_RF_INPUT].sig_type = PAD_SIGNAL_ANALOG;
t->pad[TUNER_PAD_OUTPUT].flags = MEDIA_PAD_FL_SOURCE;
+ t->pad[TUNER_PAD_OUTPUT].sig_type = PAD_SIGNAL_ANALOG;
t->pad[TUNER_PAD_AUD_OUT].flags = MEDIA_PAD_FL_SOURCE;
+ t->pad[TUNER_PAD_AUD_OUT].sig_type = PAD_SIGNAL_AUDIO;
ret = media_entity_pads_init(&t->sd.entity, TUNER_NUM_PADS,
&t->pad[0]);
t->sd.entity.function = MEDIA_ENT_F_TUNER;
diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index 2b08d03b251d..a6d91370838d 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -57,6 +57,7 @@ static bool match_i2c(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
{
#if IS_ENABLED(CONFIG_I2C)
struct i2c_client *client = i2c_verify_client(sd->dev);
+
return client &&
asd->match.i2c.adapter_id == client->adapter->nr &&
asd->match.i2c.address == client->addr;
@@ -89,10 +90,11 @@ static LIST_HEAD(subdev_list);
static LIST_HEAD(notifier_list);
static DEFINE_MUTEX(list_lock);
-static struct v4l2_async_subdev *v4l2_async_find_match(
- struct v4l2_async_notifier *notifier, struct v4l2_subdev *sd)
+static struct v4l2_async_subdev *
+v4l2_async_find_match(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *sd)
{
- bool (*match)(struct v4l2_subdev *, struct v4l2_async_subdev *);
+ bool (*match)(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd);
struct v4l2_async_subdev *asd;
list_for_each_entry(asd, &notifier->waiting, list) {
@@ -124,9 +126,34 @@ static struct v4l2_async_subdev *v4l2_async_find_match(
return NULL;
}
+/* Compare two async sub-device descriptors for equivalence */
+static bool asd_equal(struct v4l2_async_subdev *asd_x,
+ struct v4l2_async_subdev *asd_y)
+{
+ if (asd_x->match_type != asd_y->match_type)
+ return false;
+
+ switch (asd_x->match_type) {
+ case V4L2_ASYNC_MATCH_DEVNAME:
+ return strcmp(asd_x->match.device_name,
+ asd_y->match.device_name) == 0;
+ case V4L2_ASYNC_MATCH_I2C:
+ return asd_x->match.i2c.adapter_id ==
+ asd_y->match.i2c.adapter_id &&
+ asd_x->match.i2c.address ==
+ asd_y->match.i2c.address;
+ case V4L2_ASYNC_MATCH_FWNODE:
+ return asd_x->match.fwnode == asd_y->match.fwnode;
+ default:
+ break;
+ }
+
+ return false;
+}
+
/* Find the sub-device notifier registered by a sub-device driver. */
-static struct v4l2_async_notifier *v4l2_async_find_subdev_notifier(
- struct v4l2_subdev *sd)
+static struct v4l2_async_notifier *
+v4l2_async_find_subdev_notifier(struct v4l2_subdev *sd)
{
struct v4l2_async_notifier *n;
@@ -138,8 +165,8 @@ static struct v4l2_async_notifier *v4l2_async_find_subdev_notifier(
}
/* Get v4l2_device related to the notifier if one can be found. */
-static struct v4l2_device *v4l2_async_notifier_find_v4l2_dev(
- struct v4l2_async_notifier *notifier)
+static struct v4l2_device *
+v4l2_async_notifier_find_v4l2_dev(struct v4l2_async_notifier *notifier)
{
while (notifier->parent)
notifier = notifier->parent;
@@ -150,8 +177,8 @@ static struct v4l2_device *v4l2_async_notifier_find_v4l2_dev(
/*
* Return true if all child sub-device notifiers are complete, false otherwise.
*/
-static bool v4l2_async_notifier_can_complete(
- struct v4l2_async_notifier *notifier)
+static bool
+v4l2_async_notifier_can_complete(struct v4l2_async_notifier *notifier)
{
struct v4l2_subdev *sd;
@@ -174,8 +201,8 @@ static bool v4l2_async_notifier_can_complete(
* Complete the master notifier if possible. This is done when all async
* sub-devices have been bound; v4l2_device is also available then.
*/
-static int v4l2_async_notifier_try_complete(
- struct v4l2_async_notifier *notifier)
+static int
+v4l2_async_notifier_try_complete(struct v4l2_async_notifier *notifier)
{
/* Quick check whether there are still more sub-devices here. */
if (!list_empty(&notifier->waiting))
@@ -196,8 +223,8 @@ static int v4l2_async_notifier_try_complete(
return v4l2_async_notifier_call_complete(notifier);
}
-static int v4l2_async_notifier_try_all_subdevs(
- struct v4l2_async_notifier *notifier);
+static int
+v4l2_async_notifier_try_all_subdevs(struct v4l2_async_notifier *notifier);
static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
struct v4l2_device *v4l2_dev,
@@ -243,8 +270,8 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
}
/* Test all async sub-devices in a notifier for a match. */
-static int v4l2_async_notifier_try_all_subdevs(
- struct v4l2_async_notifier *notifier)
+static int
+v4l2_async_notifier_try_all_subdevs(struct v4l2_async_notifier *notifier)
{
struct v4l2_device *v4l2_dev =
v4l2_async_notifier_find_v4l2_dev(notifier);
@@ -281,14 +308,17 @@ again:
static void v4l2_async_cleanup(struct v4l2_subdev *sd)
{
v4l2_device_unregister_subdev(sd);
- /* Subdevice driver will reprobe and put the subdev back onto the list */
+ /*
+ * Subdevice driver will reprobe and put the subdev back
+ * onto the list
+ */
list_del_init(&sd->async_list);
sd->asd = NULL;
}
/* Unbind all sub-devices in the notifier tree. */
-static void v4l2_async_notifier_unbind_all_subdevs(
- struct v4l2_async_notifier *notifier)
+static void
+v4l2_async_notifier_unbind_all_subdevs(struct v4l2_async_notifier *notifier)
{
struct v4l2_subdev *sd, *tmp;
@@ -308,29 +338,23 @@ static void v4l2_async_notifier_unbind_all_subdevs(
notifier->parent = NULL;
}
-/* See if an fwnode can be found in a notifier's lists. */
-static bool __v4l2_async_notifier_fwnode_has_async_subdev(
- struct v4l2_async_notifier *notifier, struct fwnode_handle *fwnode)
+/* See if an async sub-device can be found in a notifier's lists. */
+static bool
+__v4l2_async_notifier_has_async_subdev(struct v4l2_async_notifier *notifier,
+ struct v4l2_async_subdev *asd)
{
- struct v4l2_async_subdev *asd;
+ struct v4l2_async_subdev *asd_y;
struct v4l2_subdev *sd;
- list_for_each_entry(asd, &notifier->waiting, list) {
- if (asd->match_type != V4L2_ASYNC_MATCH_FWNODE)
- continue;
-
- if (asd->match.fwnode == fwnode)
+ list_for_each_entry(asd_y, &notifier->waiting, list)
+ if (asd_equal(asd, asd_y))
return true;
- }
list_for_each_entry(sd, &notifier->done, async_list) {
if (WARN_ON(!sd->asd))
continue;
- if (sd->asd->match_type != V4L2_ASYNC_MATCH_FWNODE)
- continue;
-
- if (sd->asd->match.fwnode == fwnode)
+ if (asd_equal(asd, sd->asd))
return true;
}
@@ -338,76 +362,91 @@ static bool __v4l2_async_notifier_fwnode_has_async_subdev(
}
/*
- * Find out whether an async sub-device was set up for an fwnode already or
+ * Find out whether an async sub-device was set up already or
* whether it exists in a given notifier before @this_index.
+ * If @this_index < 0, search the notifier's entire @asd_list.
*/
-static bool v4l2_async_notifier_fwnode_has_async_subdev(
- struct v4l2_async_notifier *notifier, struct fwnode_handle *fwnode,
- unsigned int this_index)
+static bool
+v4l2_async_notifier_has_async_subdev(struct v4l2_async_notifier *notifier,
+ struct v4l2_async_subdev *asd,
+ int this_index)
{
- unsigned int j;
+ struct v4l2_async_subdev *asd_y;
+ int j = 0;
lockdep_assert_held(&list_lock);
- /* Check that an fwnode is not being added more than once. */
- for (j = 0; j < this_index; j++) {
- struct v4l2_async_subdev *asd = notifier->subdevs[this_index];
- struct v4l2_async_subdev *other_asd = notifier->subdevs[j];
-
- if (other_asd->match_type == V4L2_ASYNC_MATCH_FWNODE &&
- asd->match.fwnode ==
- other_asd->match.fwnode)
+ /* Check that an asd is not being added more than once. */
+ list_for_each_entry(asd_y, &notifier->asd_list, asd_list) {
+ if (this_index >= 0 && j++ >= this_index)
+ break;
+ if (asd_equal(asd, asd_y))
return true;
}
- /* Check than an fwnode did not exist in other notifiers. */
+ /* Check that an asd does not exist in other notifiers. */
list_for_each_entry(notifier, &notifier_list, list)
- if (__v4l2_async_notifier_fwnode_has_async_subdev(
- notifier, fwnode))
+ if (__v4l2_async_notifier_has_async_subdev(notifier, asd))
return true;
return false;
}
-static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
+static int v4l2_async_notifier_asd_valid(struct v4l2_async_notifier *notifier,
+ struct v4l2_async_subdev *asd,
+ int this_index)
{
struct device *dev =
notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL;
- struct v4l2_async_subdev *asd;
- int ret;
- int i;
- if (notifier->num_subdevs > V4L2_MAX_SUBDEVS)
+ if (!asd)
+ return -EINVAL;
+
+ switch (asd->match_type) {
+ case V4L2_ASYNC_MATCH_CUSTOM:
+ case V4L2_ASYNC_MATCH_DEVNAME:
+ case V4L2_ASYNC_MATCH_I2C:
+ case V4L2_ASYNC_MATCH_FWNODE:
+ if (v4l2_async_notifier_has_async_subdev(notifier, asd,
+ this_index)) {
+ dev_dbg(dev, "subdev descriptor already listed in this or other notifiers\n");
+ return -EEXIST;
+ }
+ break;
+ default:
+ dev_err(dev, "Invalid match type %u on %p\n",
+ asd->match_type, asd);
return -EINVAL;
+ }
+
+ return 0;
+}
+
+void v4l2_async_notifier_init(struct v4l2_async_notifier *notifier)
+{
+ mutex_lock(&list_lock);
+
+ INIT_LIST_HEAD(&notifier->asd_list);
+
+ mutex_unlock(&list_lock);
+}
+EXPORT_SYMBOL(v4l2_async_notifier_init);
+
+static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
+{
+ struct v4l2_async_subdev *asd;
+ int ret, i = 0;
INIT_LIST_HEAD(&notifier->waiting);
INIT_LIST_HEAD(&notifier->done);
mutex_lock(&list_lock);
- for (i = 0; i < notifier->num_subdevs; i++) {
- asd = notifier->subdevs[i];
-
- switch (asd->match_type) {
- case V4L2_ASYNC_MATCH_CUSTOM:
- case V4L2_ASYNC_MATCH_DEVNAME:
- case V4L2_ASYNC_MATCH_I2C:
- break;
- case V4L2_ASYNC_MATCH_FWNODE:
- if (v4l2_async_notifier_fwnode_has_async_subdev(
- notifier, asd->match.fwnode, i)) {
- dev_err(dev,
- "fwnode has already been registered or in notifier's subdev list\n");
- ret = -EEXIST;
- goto err_unlock;
- }
- break;
- default:
- dev_err(dev, "Invalid match type %u on %p\n",
- asd->match_type, asd);
- ret = -EINVAL;
+ list_for_each_entry(asd, &notifier->asd_list, asd_list) {
+ ret = v4l2_async_notifier_asd_valid(notifier, asd, i++);
+ if (ret)
goto err_unlock;
- }
+
list_add_tail(&asd->list, &notifier->waiting);
}
@@ -474,8 +513,8 @@ int v4l2_async_subdev_notifier_register(struct v4l2_subdev *sd,
}
EXPORT_SYMBOL(v4l2_async_subdev_notifier_register);
-static void __v4l2_async_notifier_unregister(
- struct v4l2_async_notifier *notifier)
+static void
+__v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
{
if (!notifier || (!notifier->v4l2_dev && !notifier->sd))
return;
@@ -498,36 +537,132 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
}
EXPORT_SYMBOL(v4l2_async_notifier_unregister);
-void v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier)
+static void __v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier)
{
- unsigned int i;
+ struct v4l2_async_subdev *asd, *tmp;
- if (!notifier || !notifier->max_subdevs)
+ if (!notifier)
return;
- for (i = 0; i < notifier->num_subdevs; i++) {
- struct v4l2_async_subdev *asd = notifier->subdevs[i];
-
+ list_for_each_entry_safe(asd, tmp, &notifier->asd_list, asd_list) {
switch (asd->match_type) {
case V4L2_ASYNC_MATCH_FWNODE:
fwnode_handle_put(asd->match.fwnode);
break;
default:
- WARN_ON_ONCE(true);
break;
}
+ list_del(&asd->asd_list);
kfree(asd);
}
+}
- notifier->max_subdevs = 0;
- notifier->num_subdevs = 0;
+void v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier)
+{
+ mutex_lock(&list_lock);
+
+ __v4l2_async_notifier_cleanup(notifier);
- kvfree(notifier->subdevs);
- notifier->subdevs = NULL;
+ mutex_unlock(&list_lock);
}
EXPORT_SYMBOL_GPL(v4l2_async_notifier_cleanup);
+int v4l2_async_notifier_add_subdev(struct v4l2_async_notifier *notifier,
+ struct v4l2_async_subdev *asd)
+{
+ int ret;
+
+ mutex_lock(&list_lock);
+
+ ret = v4l2_async_notifier_asd_valid(notifier, asd, -1);
+ if (ret)
+ goto unlock;
+
+ list_add_tail(&asd->asd_list, &notifier->asd_list);
+
+unlock:
+ mutex_unlock(&list_lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_subdev);
+
+struct v4l2_async_subdev *
+v4l2_async_notifier_add_fwnode_subdev(struct v4l2_async_notifier *notifier,
+ struct fwnode_handle *fwnode,
+ unsigned int asd_struct_size)
+{
+ struct v4l2_async_subdev *asd;
+ int ret;
+
+ asd = kzalloc(asd_struct_size, GFP_KERNEL);
+ if (!asd)
+ return ERR_PTR(-ENOMEM);
+
+ asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
+ asd->match.fwnode = fwnode;
+
+ ret = v4l2_async_notifier_add_subdev(notifier, asd);
+ if (ret) {
+ kfree(asd);
+ return ERR_PTR(ret);
+ }
+
+ return asd;
+}
+EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_fwnode_subdev);
+
+struct v4l2_async_subdev *
+v4l2_async_notifier_add_i2c_subdev(struct v4l2_async_notifier *notifier,
+ int adapter_id, unsigned short address,
+ unsigned int asd_struct_size)
+{
+ struct v4l2_async_subdev *asd;
+ int ret;
+
+ asd = kzalloc(asd_struct_size, GFP_KERNEL);
+ if (!asd)
+ return ERR_PTR(-ENOMEM);
+
+ asd->match_type = V4L2_ASYNC_MATCH_I2C;
+ asd->match.i2c.adapter_id = adapter_id;
+ asd->match.i2c.address = address;
+
+ ret = v4l2_async_notifier_add_subdev(notifier, asd);
+ if (ret) {
+ kfree(asd);
+ return ERR_PTR(ret);
+ }
+
+ return asd;
+}
+EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_i2c_subdev);
+
+struct v4l2_async_subdev *
+v4l2_async_notifier_add_devname_subdev(struct v4l2_async_notifier *notifier,
+ const char *device_name,
+ unsigned int asd_struct_size)
+{
+ struct v4l2_async_subdev *asd;
+ int ret;
+
+ asd = kzalloc(asd_struct_size, GFP_KERNEL);
+ if (!asd)
+ return ERR_PTR(-ENOMEM);
+
+ asd->match_type = V4L2_ASYNC_MATCH_DEVNAME;
+ asd->match.device_name = device_name;
+
+ ret = v4l2_async_notifier_add_subdev(notifier, asd);
+ if (ret) {
+ kfree(asd);
+ return ERR_PTR(ret);
+ }
+
+ return asd;
+}
+EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_devname_subdev);
+
int v4l2_async_register_subdev(struct v4l2_subdev *sd)
{
struct v4l2_async_notifier *subdev_notifier;
@@ -601,7 +736,7 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
mutex_lock(&list_lock);
__v4l2_async_notifier_unregister(sd->subdev_notifier);
- v4l2_async_notifier_cleanup(sd->subdev_notifier);
+ __v4l2_async_notifier_cleanup(sd->subdev_notifier);
kfree(sd->subdev_notifier);
sd->subdev_notifier = NULL;
diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
index b518b92d6d96..50763fb42a1b 100644
--- a/drivers/media/v4l2-core/v4l2-common.c
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -100,7 +100,7 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 _min, s32 _max, s32 _
qctrl->step = step;
qctrl->default_value = def;
qctrl->reserved[0] = qctrl->reserved[1] = 0;
- strlcpy(qctrl->name, name, sizeof(qctrl->name));
+ strscpy(qctrl->name, name, sizeof(qctrl->name));
return 0;
}
EXPORT_SYMBOL(v4l2_ctrl_query_fill);
@@ -109,6 +109,19 @@ EXPORT_SYMBOL(v4l2_ctrl_query_fill);
#if IS_ENABLED(CONFIG_I2C)
+void v4l2_i2c_subdev_set_name(struct v4l2_subdev *sd, struct i2c_client *client,
+ const char *devname, const char *postfix)
+{
+ if (!devname)
+ devname = client->dev.driver->name;
+ if (!postfix)
+ postfix = "";
+
+ snprintf(sd->name, sizeof(sd->name), "%s%s %d-%04x", devname, postfix,
+ i2c_adapter_id(client->adapter), client->addr);
+}
+EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_set_name);
+
void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,
const struct v4l2_subdev_ops *ops)
{
@@ -120,10 +133,7 @@ void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,
/* i2c_client and v4l2_subdev point to one another */
v4l2_set_subdevdata(sd, client);
i2c_set_clientdata(client, sd);
- /* initialize name */
- snprintf(sd->name, sizeof(sd->name), "%s %d-%04x",
- client->dev.driver->name, i2c_adapter_id(client->adapter),
- client->addr);
+ v4l2_i2c_subdev_set_name(sd, client, NULL, NULL);
}
EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_init);
@@ -186,7 +196,7 @@ struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev,
/* Setup the i2c board info with the device type and
the device address. */
memset(&info, 0, sizeof(info));
- strlcpy(info.type, client_type, sizeof(info.type));
+ strscpy(info.type, client_type, sizeof(info.type));
info.addr = addr;
return v4l2_i2c_new_subdev_board(v4l2_dev, adapter, &info, probe_addrs);
@@ -255,7 +265,8 @@ void v4l2_spi_subdev_init(struct v4l2_subdev *sd, struct spi_device *spi,
v4l2_set_subdevdata(sd, spi);
spi_set_drvdata(spi, sd);
/* initialize name */
- strlcpy(sd->name, spi->dev.driver->name, sizeof(sd->name));
+ snprintf(sd->name, sizeof(sd->name), "%s %s",
+ spi->dev.driver->name, dev_name(&spi->dev));
}
EXPORT_SYMBOL_GPL(v4l2_spi_subdev_init);
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
index 6481212fda77..f4325329fbd6 100644
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
@@ -244,6 +244,7 @@ struct v4l2_format32 {
* return: number of created buffers
* @memory: buffer memory type
* @format: frame format, for which buffers are requested
+ * @capabilities: capabilities of this buffer type.
* @reserved: future extensions
*/
struct v4l2_create_buffers32 {
@@ -251,7 +252,8 @@ struct v4l2_create_buffers32 {
__u32 count;
__u32 memory; /* enum v4l2_memory */
struct v4l2_format32 format;
- __u32 reserved[8];
+ __u32 capabilities;
+ __u32 reserved[7];
};
static int __bufsize_v4l2_format(struct v4l2_format32 __user *p32, u32 *size)
@@ -411,6 +413,7 @@ static int put_v4l2_create32(struct v4l2_create_buffers __user *p64,
if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
copy_in_user(p32, p64,
offsetof(struct v4l2_create_buffers32, format)) ||
+ assign_in_user(&p32->capabilities, &p64->capabilities) ||
copy_in_user(p32->reserved, p64->reserved, sizeof(p64->reserved)))
return -EFAULT;
return __put_v4l2_format32(&p64->format, &p32->format);
@@ -482,7 +485,7 @@ struct v4l2_buffer32 {
} m;
__u32 length;
__u32 reserved2;
- __u32 reserved;
+ __s32 request_fd;
};
static int get_v4l2_plane32(struct v4l2_plane __user *p64,
@@ -581,6 +584,7 @@ static int get_v4l2_buffer32(struct v4l2_buffer __user *p64,
{
u32 type;
u32 length;
+ s32 request_fd;
enum v4l2_memory memory;
struct v4l2_plane32 __user *uplane32;
struct v4l2_plane __user *uplane;
@@ -595,7 +599,9 @@ static int get_v4l2_buffer32(struct v4l2_buffer __user *p64,
get_user(memory, &p32->memory) ||
put_user(memory, &p64->memory) ||
get_user(length, &p32->length) ||
- put_user(length, &p64->length))
+ put_user(length, &p64->length) ||
+ get_user(request_fd, &p32->request_fd) ||
+ put_user(request_fd, &p64->request_fd))
return -EFAULT;
if (V4L2_TYPE_IS_OUTPUT(type))
@@ -699,7 +705,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer __user *p64,
copy_in_user(&p32->timecode, &p64->timecode, sizeof(p64->timecode)) ||
assign_in_user(&p32->sequence, &p64->sequence) ||
assign_in_user(&p32->reserved2, &p64->reserved2) ||
- assign_in_user(&p32->reserved, &p64->reserved) ||
+ assign_in_user(&p32->request_fd, &p64->request_fd) ||
get_user(length, &p64->length) ||
put_user(length, &p32->length))
return -EFAULT;
@@ -834,7 +840,8 @@ struct v4l2_ext_controls32 {
__u32 which;
__u32 count;
__u32 error_idx;
- __u32 reserved[2];
+ __s32 request_fd;
+ __u32 reserved[1];
compat_caddr_t controls; /* actually struct v4l2_ext_control32 * */
};
@@ -909,6 +916,7 @@ static int get_v4l2_ext_controls32(struct file *file,
get_user(count, &p32->count) ||
put_user(count, &p64->count) ||
assign_in_user(&p64->error_idx, &p32->error_idx) ||
+ assign_in_user(&p64->request_fd, &p32->request_fd) ||
copy_in_user(p64->reserved, p32->reserved, sizeof(p64->reserved)))
return -EFAULT;
@@ -974,6 +982,7 @@ static int put_v4l2_ext_controls32(struct file *file,
get_user(count, &p64->count) ||
put_user(count, &p32->count) ||
assign_in_user(&p32->error_idx, &p64->error_idx) ||
+ assign_in_user(&p32->request_fd, &p64->request_fd) ||
copy_in_user(p32->reserved, p64->reserved, sizeof(p32->reserved)) ||
get_user(kcontrols, &p64->controls))
return -EFAULT;
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 599c1cbff3b9..6e37950292cd 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -37,8 +37,8 @@
struct v4l2_ctrl_helper {
/* Pointer to the control reference of the master control */
struct v4l2_ctrl_ref *mref;
- /* The control corresponding to the v4l2_ext_control ID field. */
- struct v4l2_ctrl *ctrl;
+ /* 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;
@@ -844,6 +844,8 @@ const char *v4l2_ctrl_get_name(u32 id)
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_MPEG2_SLICE_PARAMS: return "MPEG-2 Slice Parameters";
+ case V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION: return "MPEG-2 Quantization Matrices";
/* VPX controls */
case V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS: return "VPX Number of Partitions";
@@ -1292,6 +1294,12 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
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;
default:
*type = V4L2_CTRL_TYPE_INTEGER;
break;
@@ -1550,6 +1558,7 @@ static void std_log(const struct v4l2_ctrl *ctrl)
static int std_validate(const struct v4l2_ctrl *ctrl, u32 idx,
union v4l2_ctrl_ptr ptr)
{
+ struct v4l2_ctrl_mpeg2_slice_params *p_mpeg2_slice_params;
size_t len;
u64 offset;
s64 val;
@@ -1612,6 +1621,54 @@ static int std_validate(const struct v4l2_ctrl *ctrl, u32 idx,
return -ERANGE;
return 0;
+ case V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS:
+ p_mpeg2_slice_params = ptr.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 11: /* 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;
+ }
+
+ if (p_mpeg2_slice_params->backward_ref_index >= VIDEO_MAX_FRAME ||
+ p_mpeg2_slice_params->forward_ref_index >= VIDEO_MAX_FRAME)
+ return -EINVAL;
+
+ return 0;
+
+ case V4L2_CTRL_TYPE_MPEG2_QUANTIZATION:
+ return 0;
+
default:
return -EINVAL;
}
@@ -1668,6 +1725,13 @@ static int new_to_user(struct v4l2_ext_control *c,
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)
{
@@ -1787,6 +1851,26 @@ static void cur_to_new(struct v4l2_ctrl *ctrl)
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->req = ref;
+}
+
+/* Copy the request value to the new value */
+static void req_to_new(struct v4l2_ctrl_ref *ref)
+{
+ if (!ref)
+ return;
+ if (ref->req)
+ ptr_to_ptr(ref->ctrl, ref->req->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)
@@ -1896,11 +1980,15 @@ int v4l2_ctrl_handler_init_class(struct v4l2_ctrl_handler *hdl,
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);
@@ -1915,6 +2003,14 @@ void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl)
if (hdl == NULL || hdl->buckets == NULL)
return;
+ if (!hdl->req_obj.req && !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) {
@@ -2016,13 +2112,19 @@ 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 *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
@@ -2036,10 +2138,16 @@ static int handler_new_ref(struct v4l2_ctrl_handler *hdl,
if (hdl->error)
return hdl->error;
- new_ref = kzalloc(sizeof(*new_ref), GFP_KERNEL);
+ 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];
+
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
@@ -2079,6 +2187,8 @@ 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;
unlock:
mutex_unlock(hdl->lock);
@@ -2133,6 +2243,12 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
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;
default:
if (type < V4L2_CTRL_COMPOUND_TYPES)
elem_size = sizeof(s32);
@@ -2220,7 +2336,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
ctrl->type_ops->init(ctrl, idx, ctrl->p_new);
}
- if (handler_new_ref(hdl, ctrl)) {
+ if (handler_new_ref(hdl, ctrl, NULL, false, false)) {
kvfree(ctrl);
return NULL;
}
@@ -2389,7 +2505,8 @@ 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 (*filter)(const struct v4l2_ctrl *ctrl),
+ bool from_other_dev)
{
struct v4l2_ctrl_ref *ref;
int ret = 0;
@@ -2412,7 +2529,7 @@ int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl,
/* Filter any unwanted controls */
if (filter && !filter(ctrl))
continue;
- ret = handler_new_ref(hdl, ctrl);
+ ret = handler_new_ref(hdl, ctrl, NULL, from_other_dev, false);
if (ret)
break;
}
@@ -2511,20 +2628,15 @@ void v4l2_ctrl_activate(struct v4l2_ctrl *ctrl, bool active)
}
EXPORT_SYMBOL(v4l2_ctrl_activate);
-/* Grab/ungrab a control.
- Typically used when streaming starts and you want to grab controls,
- preventing the user from changing them.
-
- Just call this and the framework will block any attempts to change
- these controls. */
-void v4l2_ctrl_grab(struct v4l2_ctrl *ctrl, bool grabbed)
+void __v4l2_ctrl_grab(struct v4l2_ctrl *ctrl, bool grabbed)
{
bool old;
if (ctrl == NULL)
return;
- v4l2_ctrl_lock(ctrl);
+ lockdep_assert_held(ctrl->handler->lock);
+
if (grabbed)
/* set V4L2_CTRL_FLAG_GRABBED */
old = test_and_set_bit(1, &ctrl->flags);
@@ -2533,9 +2645,8 @@ void v4l2_ctrl_grab(struct v4l2_ctrl *ctrl, bool grabbed)
old = test_and_clear_bit(1, &ctrl->flags);
if (old != grabbed)
send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_FLAGS);
- v4l2_ctrl_unlock(ctrl);
}
-EXPORT_SYMBOL(v4l2_ctrl_grab);
+EXPORT_SYMBOL(__v4l2_ctrl_grab);
/* Log the control name and value */
static void log_ctrl(const struct v4l2_ctrl *ctrl,
@@ -2722,7 +2833,7 @@ int v4l2_query_ext_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_query_ext_ctr
qc->id = id;
else
qc->id = ctrl->id;
- strlcpy(qc->name, ctrl->name, sizeof(qc->name));
+ strscpy(qc->name, ctrl->name, sizeof(qc->name));
qc->flags = user_flags(ctrl);
qc->type = ctrl->type;
qc->elem_size = ctrl->elem_size;
@@ -2754,7 +2865,7 @@ int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc)
qc->id = qec.id;
qc->type = qec.type;
qc->flags = qec.flags;
- strlcpy(qc->name, qec.name, sizeof(qc->name));
+ strscpy(qc->name, qec.name, sizeof(qc->name));
switch (qc->type) {
case V4L2_CTRL_TYPE_INTEGER:
case V4L2_CTRL_TYPE_BOOLEAN:
@@ -2813,7 +2924,7 @@ int v4l2_querymenu(struct v4l2_ctrl_handler *hdl, struct v4l2_querymenu *qm)
if (ctrl->type == V4L2_CTRL_TYPE_MENU) {
if (ctrl->qmenu[i] == NULL || ctrl->qmenu[i][0] == '\0')
return -EINVAL;
- strlcpy(qm->name, ctrl->qmenu[i], sizeof(qm->name));
+ strscpy(qm->name, ctrl->qmenu[i], sizeof(qm->name));
} else {
qm->value = ctrl->qmenu_int[i];
}
@@ -2821,6 +2932,148 @@ int v4l2_querymenu(struct v4l2_ctrl_handler *hdl, struct v4l2_querymenu *qm)
}
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;
+ /* And buttons */
+ if (ctrl->type == V4L2_CTRL_TYPE_BUTTON)
+ 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;
+ struct v4l2_ctrl_handler *prev_hdl = NULL;
+ struct v4l2_ctrl_ref *ref_ctrl, *ref_ctrl_prev = NULL;
+
+ if (list_empty(&main_hdl->requests_queued))
+ goto queue;
+
+ prev_hdl = list_last_entry(&main_hdl->requests_queued,
+ struct v4l2_ctrl_handler, requests_queued);
+ /*
+ * Note: prev_hdl and hdl must contain the same list of control
+ * references, so if any differences are detected then that is a
+ * driver bug and the WARN_ON is triggered.
+ */
+ mutex_lock(prev_hdl->lock);
+ ref_ctrl_prev = list_first_entry(&prev_hdl->ctrl_refs,
+ struct v4l2_ctrl_ref, node);
+ list_for_each_entry(ref_ctrl, &hdl->ctrl_refs, node) {
+ if (ref_ctrl->req)
+ continue;
+ while (ref_ctrl_prev->ctrl->id < ref_ctrl->ctrl->id) {
+ /* Should never happen, but just in case... */
+ if (list_is_last(&ref_ctrl_prev->node,
+ &prev_hdl->ctrl_refs))
+ break;
+ ref_ctrl_prev = list_next_entry(ref_ctrl_prev, node);
+ }
+ if (WARN_ON(ref_ctrl_prev->ctrl->id != ref_ctrl->ctrl->id))
+ break;
+ ref_ctrl->req = ref_ctrl_prev->req;
+ }
+ mutex_unlock(prev_hdl->lock);
+queue:
+ list_add_tail(&hdl->requests_queued, &main_hdl->requests_queued);
+ hdl->request_is_queued = true;
+}
+
+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);
+
+ list_del_init(&hdl->requests);
+ if (hdl->request_is_queued) {
+ list_del_init(&hdl->requests_queued);
+ hdl->request_is_queued = false;
+ }
+}
+
+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->req == ref) ? 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)
+ list_add_tail(&hdl->requests, &from->requests);
+ }
+ return ret;
+}
/* Some general notes on the atomic requirements of VIDIOC_G/TRY/S_EXT_CTRLS:
@@ -2882,6 +3135,7 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
if (cs->which &&
cs->which != V4L2_CTRL_WHICH_DEF_VAL &&
+ cs->which != V4L2_CTRL_WHICH_REQUEST_VAL &&
V4L2_CTRL_ID2WHICH(id) != cs->which)
return -EINVAL;
@@ -2892,6 +3146,7 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
ref = find_ref_lock(hdl, id);
if (ref == NULL)
return -EINVAL;
+ h->ref = ref;
ctrl = ref->ctrl;
if (ctrl->flags & V4L2_CTRL_FLAG_DISABLED)
return -EINVAL;
@@ -2914,7 +3169,6 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
}
/* Store the ref to the master control of the cluster */
h->mref = ref;
- h->ctrl = ctrl;
/* Initially set next to 0, meaning that there is no other
control in this helper array belonging to the same
cluster */
@@ -2961,15 +3215,15 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
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)
+ 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. */
-int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs)
+static int v4l2_g_ext_ctrls_common(struct v4l2_ctrl_handler *hdl,
+ struct v4l2_ext_controls *cs)
{
struct v4l2_ctrl_helper helper[4];
struct v4l2_ctrl_helper *helpers = helper;
@@ -2999,7 +3253,7 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs
cs->error_idx = cs->count;
for (i = 0; !ret && i < cs->count; i++)
- if (helpers[i].ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY)
+ if (helpers[i].ref->ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY)
ret = -EACCES;
for (i = 0; !ret && i < cs->count; i++) {
@@ -3033,8 +3287,12 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs
u32 idx = i;
do {
- ret = ctrl_to_user(cs->controls + idx,
- helpers[idx].ctrl);
+ if (helpers[idx].ref->req)
+ ret = req_to_user(cs->controls + idx,
+ helpers[idx].ref->req);
+ else
+ ret = ctrl_to_user(cs->controls + idx,
+ helpers[idx].ref->ctrl);
idx = helpers[idx].next;
} while (!ret && idx);
}
@@ -3045,6 +3303,91 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs
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 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);
+
+ 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 */
@@ -3186,7 +3529,7 @@ static int validate_ctrls(struct v4l2_ext_controls *cs,
cs->error_idx = cs->count;
for (i = 0; i < cs->count; i++) {
- struct v4l2_ctrl *ctrl = helpers[i].ctrl;
+ struct v4l2_ctrl *ctrl = helpers[i].ref->ctrl;
union v4l2_ctrl_ptr p_new;
cs->error_idx = i;
@@ -3233,9 +3576,9 @@ static void update_from_auto_cluster(struct v4l2_ctrl *master)
}
/* Try or try-and-set controls */
-static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
- struct v4l2_ext_controls *cs,
- bool set)
+static int try_set_ext_ctrls_common(struct v4l2_fh *fh,
+ struct v4l2_ctrl_handler *hdl,
+ struct v4l2_ext_controls *cs, bool set)
{
struct v4l2_ctrl_helper helper[4];
struct v4l2_ctrl_helper *helpers = helper;
@@ -3298,7 +3641,7 @@ static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
do {
/* Check if the auto control is part of the
list, and remember the new value. */
- if (helpers[tmp_idx].ctrl == master)
+ if (helpers[tmp_idx].ref->ctrl == master)
new_auto_val = cs->controls[tmp_idx].value;
tmp_idx = helpers[tmp_idx].next;
} while (tmp_idx);
@@ -3311,7 +3654,7 @@ static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
/* Copy the new caller-supplied control values.
user_to_new() sets 'is_new' to 1. */
do {
- struct v4l2_ctrl *ctrl = helpers[idx].ctrl;
+ struct v4l2_ctrl *ctrl = helpers[idx].ref->ctrl;
ret = user_to_new(cs->controls + idx, ctrl);
if (!ret && ctrl->is_ptr)
@@ -3320,14 +3663,23 @@ static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
} while (!ret && idx);
if (!ret)
- ret = try_or_set_cluster(fh, master, set, 0);
+ 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].ctrl);
+ helpers[idx].ref->ctrl);
idx = helpers[idx].next;
} while (!ret && idx);
}
@@ -3339,16 +3691,60 @@ static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
return ret;
}
-int v4l2_try_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs)
+static int try_set_ext_ctrls(struct v4l2_fh *fh,
+ struct v4l2_ctrl_handler *hdl, struct media_device *mdev,
+ struct v4l2_ext_controls *cs, bool set)
{
- return try_set_ext_ctrls(NULL, hdl, cs, false);
+ 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);
+
+ ret = media_request_lock_for_update(req);
+ if (ret) {
+ media_request_put(req);
+ return ret;
+ }
+
+ obj = v4l2_ctrls_find_req_obj(hdl, req, set);
+ if (IS_ERR(obj)) {
+ 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, set);
+
+ 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 media_device *mdev,
+ struct v4l2_ext_controls *cs)
+{
+ return try_set_ext_ctrls(NULL, hdl, mdev, cs, false);
}
EXPORT_SYMBOL(v4l2_try_ext_ctrls);
int v4l2_s_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
- struct v4l2_ext_controls *cs)
+ struct media_device *mdev, struct v4l2_ext_controls *cs)
{
- return try_set_ext_ctrls(fh, hdl, cs, true);
+ return try_set_ext_ctrls(fh, hdl, mdev, cs, true);
}
EXPORT_SYMBOL(v4l2_s_ext_ctrls);
@@ -3442,11 +3838,167 @@ int __v4l2_ctrl_s_ctrl_string(struct v4l2_ctrl *ctrl, const char *s)
/* It's a driver bug if this happens. */
WARN_ON(ctrl->type != V4L2_CTRL_TYPE_STRING);
- strlcpy(ctrl->p_new.p_char, s, ctrl->maximum + 1);
+ strscpy(ctrl->p_new.p_char, s, ctrl->maximum + 1);
return set_ctrl(NULL, ctrl, 0);
}
EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_string);
+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) {
+ ref->req = ref;
+
+ 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->req == ref)
+ continue;
+
+ v4l2_ctrl_lock(ctrl);
+ if (ref->req)
+ ptr_to_ptr(ctrl, ref->req->p_req, ref->p_req);
+ else
+ ptr_to_ptr(ctrl, ctrl->p_cur, ref->p_req);
+ v4l2_ctrl_unlock(ctrl);
+ }
+
+ WARN_ON(!hdl->request_is_queued);
+ list_del_init(&hdl->requests_queued);
+ hdl->request_is_queued = false;
+ media_request_object_complete(obj);
+ media_request_object_put(obj);
+}
+EXPORT_SYMBOL(v4l2_ctrl_request_complete);
+
+void 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;
+
+ if (!req || !main_hdl)
+ return;
+
+ if (WARN_ON(req->state != MEDIA_REQUEST_STATE_QUEUED))
+ 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;
+ if (obj->completed) {
+ media_request_object_put(obj);
+ return;
+ }
+ 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->type == V4L2_CTRL_TYPE_BUTTON ||
+ (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->req && r == r->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);
+ }
+
+ try_or_set_cluster(NULL, master, true, 0);
+
+ v4l2_ctrl_unlock(master);
+ }
+
+ media_request_object_put(obj);
+}
+EXPORT_SYMBOL(v4l2_ctrl_request_setup);
+
void v4l2_ctrl_notify(struct v4l2_ctrl *ctrl, v4l2_ctrl_notify_fnc notify, void *priv)
{
if (ctrl == NULL)
diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
index 69e775930fc4..feb749aaaa42 100644
--- a/drivers/media/v4l2-core/v4l2-dev.c
+++ b/drivers/media/v4l2-core/v4l2-dev.c
@@ -444,8 +444,22 @@ static int v4l2_release(struct inode *inode, struct file *filp)
struct video_device *vdev = video_devdata(filp);
int ret = 0;
- if (vdev->fops->release)
- ret = vdev->fops->release(filp);
+ /*
+ * We need to serialize the release() with queueing new requests.
+ * The release() may trigger the cancellation of a streaming
+ * operation, and that should not be mixed with queueing a new
+ * request at the same time.
+ */
+ if (vdev->fops->release) {
+ if (v4l2_device_supports_requests(vdev->v4l2_dev)) {
+ mutex_lock(&vdev->v4l2_dev->mdev->req_queue_mutex);
+ ret = vdev->fops->release(filp);
+ mutex_unlock(&vdev->v4l2_dev->mdev->req_queue_mutex);
+ } else {
+ ret = vdev->fops->release(filp);
+ }
+ }
+
if (vdev->dev_debug & V4L2_DEV_DEBUG_FOP)
dprintk("%s: release\n",
video_device_node_name(vdev));
diff --git a/drivers/media/v4l2-core/v4l2-device.c b/drivers/media/v4l2-core/v4l2-device.c
index 3940e55c72f1..df0ac38c4050 100644
--- a/drivers/media/v4l2-core/v4l2-device.c
+++ b/drivers/media/v4l2-core/v4l2-device.c
@@ -178,7 +178,8 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
sd->v4l2_dev = v4l2_dev;
/* This just returns 0 if either of the two args is NULL */
- err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler, NULL);
+ err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler,
+ NULL, true);
if (err)
goto error_module;
@@ -245,7 +246,7 @@ int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev)
}
video_set_drvdata(vdev, sd);
- strlcpy(vdev->name, sd->name, sizeof(vdev->name));
+ strscpy(vdev->name, sd->name, sizeof(vdev->name));
vdev->v4l2_dev = v4l2_dev;
vdev->fops = &v4l2_subdev_fops;
vdev->release = v4l2_device_release_subdev_node;
diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c
index c81faea96fba..4f23e939ead0 100644
--- a/drivers/media/v4l2-core/v4l2-dv-timings.c
+++ b/drivers/media/v4l2-core/v4l2-dv-timings.c
@@ -15,6 +15,7 @@
#include <media/v4l2-dv-timings.h>
#include <linux/math64.h>
#include <linux/hdmi.h>
+#include <media/cec.h>
MODULE_AUTHOR("Hans Verkuil");
MODULE_DESCRIPTION("V4L2 DV Timings Helper Functions");
@@ -373,6 +374,45 @@ struct v4l2_fract v4l2_dv_timings_aspect_ratio(const struct v4l2_dv_timings *t)
}
EXPORT_SYMBOL_GPL(v4l2_dv_timings_aspect_ratio);
+/** v4l2_calc_timeperframe - helper function to calculate timeperframe based
+ * v4l2_dv_timings fields.
+ * @t - Timings for the video mode.
+ *
+ * Calculates the expected timeperframe using the pixel clock value and
+ * horizontal/vertical measures. This means that v4l2_dv_timings structure
+ * must be correctly and fully filled.
+ */
+struct v4l2_fract v4l2_calc_timeperframe(const struct v4l2_dv_timings *t)
+{
+ const struct v4l2_bt_timings *bt = &t->bt;
+ struct v4l2_fract fps_fract = { 1, 1 };
+ unsigned long n, d;
+ u32 htot, vtot, fps;
+ u64 pclk;
+
+ if (t->type != V4L2_DV_BT_656_1120)
+ return fps_fract;
+
+ htot = V4L2_DV_BT_FRAME_WIDTH(bt);
+ vtot = V4L2_DV_BT_FRAME_HEIGHT(bt);
+ pclk = bt->pixelclock;
+
+ if ((bt->flags & V4L2_DV_FL_CAN_DETECT_REDUCED_FPS) &&
+ (bt->flags & V4L2_DV_FL_REDUCED_FPS))
+ pclk = div_u64(pclk * 1000ULL, 1001);
+
+ fps = (htot * vtot) > 0 ? div_u64((100 * pclk), (htot * vtot)) : 0;
+ if (!fps)
+ return fps_fract;
+
+ rational_best_approximation(fps, 100, fps, 100, &n, &d);
+
+ fps_fract.numerator = d;
+ fps_fract.denominator = n;
+ return fps_fract;
+}
+EXPORT_SYMBOL_GPL(v4l2_calc_timeperframe);
+
/*
* CVT defines
* Based on Coordinated Video Timings Standard
@@ -837,9 +877,9 @@ v4l2_hdmi_rx_colorimetry(const struct hdmi_avi_infoframe *avi,
switch (avi->colorimetry) {
case HDMI_COLORIMETRY_EXTENDED:
switch (avi->extended_colorimetry) {
- case HDMI_EXTENDED_COLORIMETRY_ADOBE_RGB:
- c.colorspace = V4L2_COLORSPACE_ADOBERGB;
- c.xfer_func = V4L2_XFER_FUNC_ADOBERGB;
+ case HDMI_EXTENDED_COLORIMETRY_OPRGB:
+ c.colorspace = V4L2_COLORSPACE_OPRGB;
+ c.xfer_func = V4L2_XFER_FUNC_OPRGB;
break;
case HDMI_EXTENDED_COLORIMETRY_BT2020:
c.colorspace = V4L2_COLORSPACE_BT2020;
@@ -908,10 +948,10 @@ v4l2_hdmi_rx_colorimetry(const struct hdmi_avi_infoframe *avi,
c.ycbcr_enc = V4L2_YCBCR_ENC_601;
c.xfer_func = V4L2_XFER_FUNC_SRGB;
break;
- case HDMI_EXTENDED_COLORIMETRY_ADOBE_YCC_601:
- c.colorspace = V4L2_COLORSPACE_ADOBERGB;
+ case HDMI_EXTENDED_COLORIMETRY_OPYCC_601:
+ c.colorspace = V4L2_COLORSPACE_OPRGB;
c.ycbcr_enc = V4L2_YCBCR_ENC_601;
- c.xfer_func = V4L2_XFER_FUNC_ADOBERGB;
+ c.xfer_func = V4L2_XFER_FUNC_OPRGB;
break;
case HDMI_EXTENDED_COLORIMETRY_BT2020:
c.colorspace = V4L2_COLORSPACE_BT2020;
@@ -942,3 +982,153 @@ v4l2_hdmi_rx_colorimetry(const struct hdmi_avi_infoframe *avi,
return c;
}
EXPORT_SYMBOL_GPL(v4l2_hdmi_rx_colorimetry);
+
+/**
+ * v4l2_get_edid_phys_addr() - find and return the physical address
+ *
+ * @edid: pointer to the EDID data
+ * @size: size in bytes of the EDID data
+ * @offset: If not %NULL then the location of the physical address
+ * bytes in the EDID will be returned here. This is set to 0
+ * if there is no physical address found.
+ *
+ * Return: the physical address or CEC_PHYS_ADDR_INVALID if there is none.
+ */
+u16 v4l2_get_edid_phys_addr(const u8 *edid, unsigned int size,
+ unsigned int *offset)
+{
+ unsigned int loc = cec_get_edid_spa_location(edid, size);
+
+ if (offset)
+ *offset = loc;
+ if (loc == 0)
+ return CEC_PHYS_ADDR_INVALID;
+ return (edid[loc] << 8) | edid[loc + 1];
+}
+EXPORT_SYMBOL_GPL(v4l2_get_edid_phys_addr);
+
+/**
+ * v4l2_set_edid_phys_addr() - find and set the physical address
+ *
+ * @edid: pointer to the EDID data
+ * @size: size in bytes of the EDID data
+ * @phys_addr: the new physical address
+ *
+ * This function finds the location of the physical address in the EDID
+ * and fills in the given physical address and updates the checksum
+ * at the end of the EDID block. It does nothing if the EDID doesn't
+ * contain a physical address.
+ */
+void v4l2_set_edid_phys_addr(u8 *edid, unsigned int size, u16 phys_addr)
+{
+ unsigned int loc = cec_get_edid_spa_location(edid, size);
+ u8 sum = 0;
+ unsigned int i;
+
+ if (loc == 0)
+ return;
+ edid[loc] = phys_addr >> 8;
+ edid[loc + 1] = phys_addr & 0xff;
+ loc &= ~0x7f;
+
+ /* update the checksum */
+ for (i = loc; i < loc + 127; i++)
+ sum += edid[i];
+ edid[i] = 256 - sum;
+}
+EXPORT_SYMBOL_GPL(v4l2_set_edid_phys_addr);
+
+/**
+ * v4l2_phys_addr_for_input() - calculate the PA for an input
+ *
+ * @phys_addr: the physical address of the parent
+ * @input: the number of the input port, must be between 1 and 15
+ *
+ * This function calculates a new physical address based on the input
+ * port number. For example:
+ *
+ * PA = 0.0.0.0 and input = 2 becomes 2.0.0.0
+ *
+ * PA = 3.0.0.0 and input = 1 becomes 3.1.0.0
+ *
+ * PA = 3.2.1.0 and input = 5 becomes 3.2.1.5
+ *
+ * PA = 3.2.1.3 and input = 5 becomes f.f.f.f since it maxed out the depth.
+ *
+ * Return: the new physical address or CEC_PHYS_ADDR_INVALID.
+ */
+u16 v4l2_phys_addr_for_input(u16 phys_addr, u8 input)
+{
+ /* Check if input is sane */
+ if (WARN_ON(input == 0 || input > 0xf))
+ return CEC_PHYS_ADDR_INVALID;
+
+ if (phys_addr == 0)
+ return input << 12;
+
+ if ((phys_addr & 0x0fff) == 0)
+ return phys_addr | (input << 8);
+
+ if ((phys_addr & 0x00ff) == 0)
+ return phys_addr | (input << 4);
+
+ if ((phys_addr & 0x000f) == 0)
+ return phys_addr | input;
+
+ /*
+ * All nibbles are used so no valid physical addresses can be assigned
+ * to the input.
+ */
+ return CEC_PHYS_ADDR_INVALID;
+}
+EXPORT_SYMBOL_GPL(v4l2_phys_addr_for_input);
+
+/**
+ * v4l2_phys_addr_validate() - validate a physical address from an EDID
+ *
+ * @phys_addr: the physical address to validate
+ * @parent: if not %NULL, then this is filled with the parents PA.
+ * @port: if not %NULL, then this is filled with the input port.
+ *
+ * This validates a physical address as read from an EDID. If the
+ * PA is invalid (such as 1.0.1.0 since '0' is only allowed at the end),
+ * then it will return -EINVAL.
+ *
+ * The parent PA is passed into %parent and the input port is passed into
+ * %port. For example:
+ *
+ * PA = 0.0.0.0: has parent 0.0.0.0 and input port 0.
+ *
+ * PA = 1.0.0.0: has parent 0.0.0.0 and input port 1.
+ *
+ * PA = 3.2.0.0: has parent 3.0.0.0 and input port 2.
+ *
+ * PA = f.f.f.f: has parent f.f.f.f and input port 0.
+ *
+ * Return: 0 if the PA is valid, -EINVAL if not.
+ */
+int v4l2_phys_addr_validate(u16 phys_addr, u16 *parent, u16 *port)
+{
+ int i;
+
+ if (parent)
+ *parent = phys_addr;
+ if (port)
+ *port = 0;
+ if (phys_addr == CEC_PHYS_ADDR_INVALID)
+ return 0;
+ for (i = 0; i < 16; i += 4)
+ if (phys_addr & (0xf << i))
+ break;
+ if (i == 16)
+ return 0;
+ if (parent)
+ *parent = phys_addr & (0xfff0 << i);
+ if (port)
+ *port = (phys_addr >> i) & 0xf;
+ for (i += 4; i < 16; i += 4)
+ if ((phys_addr & (0xf << i)) == 0)
+ return -EINVAL;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_phys_addr_validate);
diff --git a/drivers/media/v4l2-core/v4l2-event.c b/drivers/media/v4l2-core/v4l2-event.c
index 127fe6eb91d9..a3ef1f50a4b3 100644
--- a/drivers/media/v4l2-core/v4l2-event.c
+++ b/drivers/media/v4l2-core/v4l2-event.c
@@ -115,14 +115,6 @@ static void __v4l2_event_queue_fh(struct v4l2_fh *fh, const struct v4l2_event *e
if (sev == NULL)
return;
- /*
- * If the event has been added to the fh->subscribed list, but its
- * add op has not completed yet elems will be 0, treat this as
- * not being subscribed.
- */
- if (!sev->elems)
- return;
-
/* Increase event sequence number on fh. */
fh->sequence++;
@@ -208,6 +200,7 @@ int v4l2_event_subscribe(struct v4l2_fh *fh,
struct v4l2_subscribed_event *sev, *found_ev;
unsigned long flags;
unsigned i;
+ int ret = 0;
if (sub->type == V4L2_EVENT_ALL)
return -EINVAL;
@@ -225,31 +218,36 @@ int v4l2_event_subscribe(struct v4l2_fh *fh,
sev->flags = sub->flags;
sev->fh = fh;
sev->ops = ops;
+ sev->elems = elems;
+
+ mutex_lock(&fh->subscribe_lock);
spin_lock_irqsave(&fh->vdev->fh_lock, flags);
found_ev = v4l2_event_subscribed(fh, sub->type, sub->id);
- if (!found_ev)
- list_add(&sev->list, &fh->subscribed);
spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
if (found_ev) {
+ /* Already listening */
kvfree(sev);
- return 0; /* Already listening */
+ goto out_unlock;
}
if (sev->ops && sev->ops->add) {
- int ret = sev->ops->add(sev, elems);
+ ret = sev->ops->add(sev, elems);
if (ret) {
- sev->ops = NULL;
- v4l2_event_unsubscribe(fh, sub);
- return ret;
+ kvfree(sev);
+ goto out_unlock;
}
}
- /* Mark as ready for use */
- sev->elems = elems;
+ spin_lock_irqsave(&fh->vdev->fh_lock, flags);
+ list_add(&sev->list, &fh->subscribed);
+ spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
- return 0;
+out_unlock:
+ mutex_unlock(&fh->subscribe_lock);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(v4l2_event_subscribe);
@@ -288,6 +286,8 @@ int v4l2_event_unsubscribe(struct v4l2_fh *fh,
return 0;
}
+ mutex_lock(&fh->subscribe_lock);
+
spin_lock_irqsave(&fh->vdev->fh_lock, flags);
sev = v4l2_event_subscribed(fh, sub->type, sub->id);
@@ -305,6 +305,8 @@ int v4l2_event_unsubscribe(struct v4l2_fh *fh,
if (sev && sev->ops && sev->ops->del)
sev->ops->del(sev);
+ mutex_unlock(&fh->subscribe_lock);
+
kvfree(sev);
return 0;
diff --git a/drivers/media/v4l2-core/v4l2-fh.c b/drivers/media/v4l2-core/v4l2-fh.c
index 3895999bf880..c91a7bd3ecfc 100644
--- a/drivers/media/v4l2-core/v4l2-fh.c
+++ b/drivers/media/v4l2-core/v4l2-fh.c
@@ -45,6 +45,7 @@ void v4l2_fh_init(struct v4l2_fh *fh, struct video_device *vdev)
INIT_LIST_HEAD(&fh->available);
INIT_LIST_HEAD(&fh->subscribed);
fh->sequence = -1;
+ mutex_init(&fh->subscribe_lock);
}
EXPORT_SYMBOL_GPL(v4l2_fh_init);
@@ -90,6 +91,7 @@ void v4l2_fh_exit(struct v4l2_fh *fh)
return;
v4l_disable_media_source(fh->vdev);
v4l2_event_unsubscribe_all(fh);
+ mutex_destroy(&fh->subscribe_lock);
fh->vdev = NULL;
}
EXPORT_SYMBOL_GPL(v4l2_fh_exit);
diff --git a/drivers/media/v4l2-core/v4l2-flash-led-class.c b/drivers/media/v4l2-core/v4l2-flash-led-class.c
index 215b4804ada2..1697932af5ea 100644
--- a/drivers/media/v4l2-core/v4l2-flash-led-class.c
+++ b/drivers/media/v4l2-core/v4l2-flash-led-class.c
@@ -640,7 +640,7 @@ static struct v4l2_flash *__v4l2_flash_init(
v4l2_subdev_init(sd, &v4l2_flash_subdev_ops);
sd->internal_ops = &v4l2_flash_subdev_internal_ops;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
- strlcpy(sd->name, config->dev_name, sizeof(sd->name));
+ strscpy(sd->name, config->dev_name, sizeof(sd->name));
ret = media_entity_pads_init(&sd->entity, 0, NULL);
if (ret < 0)
diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
index 169bdbb1f61a..218f0da0ce76 100644
--- a/drivers/media/v4l2-core/v4l2-fwnode.c
+++ b/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -36,194 +36,469 @@ enum v4l2_fwnode_bus_type {
V4L2_FWNODE_BUS_TYPE_CSI2_CPHY,
V4L2_FWNODE_BUS_TYPE_CSI1,
V4L2_FWNODE_BUS_TYPE_CCP2,
+ V4L2_FWNODE_BUS_TYPE_CSI2_DPHY,
+ V4L2_FWNODE_BUS_TYPE_PARALLEL,
+ V4L2_FWNODE_BUS_TYPE_BT656,
NR_OF_V4L2_FWNODE_BUS_TYPE,
};
+static const struct v4l2_fwnode_bus_conv {
+ enum v4l2_fwnode_bus_type fwnode_bus_type;
+ enum v4l2_mbus_type mbus_type;
+ const char *name;
+} busses[] = {
+ {
+ V4L2_FWNODE_BUS_TYPE_GUESS,
+ V4L2_MBUS_UNKNOWN,
+ "not specified",
+ }, {
+ V4L2_FWNODE_BUS_TYPE_CSI2_CPHY,
+ V4L2_MBUS_CSI2_CPHY,
+ "MIPI CSI-2 C-PHY",
+ }, {
+ V4L2_FWNODE_BUS_TYPE_CSI1,
+ V4L2_MBUS_CSI1,
+ "MIPI CSI-1",
+ }, {
+ V4L2_FWNODE_BUS_TYPE_CCP2,
+ V4L2_MBUS_CCP2,
+ "compact camera port 2",
+ }, {
+ V4L2_FWNODE_BUS_TYPE_CSI2_DPHY,
+ V4L2_MBUS_CSI2_DPHY,
+ "MIPI CSI-2 D-PHY",
+ }, {
+ V4L2_FWNODE_BUS_TYPE_PARALLEL,
+ V4L2_MBUS_PARALLEL,
+ "parallel",
+ }, {
+ V4L2_FWNODE_BUS_TYPE_BT656,
+ V4L2_MBUS_BT656,
+ "Bt.656",
+ }
+};
+
+static const struct v4l2_fwnode_bus_conv *
+get_v4l2_fwnode_bus_conv_by_fwnode_bus(enum v4l2_fwnode_bus_type type)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(busses); i++)
+ if (busses[i].fwnode_bus_type == type)
+ return &busses[i];
+
+ return NULL;
+}
+
+static enum v4l2_mbus_type
+v4l2_fwnode_bus_type_to_mbus(enum v4l2_fwnode_bus_type type)
+{
+ const struct v4l2_fwnode_bus_conv *conv =
+ get_v4l2_fwnode_bus_conv_by_fwnode_bus(type);
+
+ return conv ? conv->mbus_type : V4L2_MBUS_UNKNOWN;
+}
+
+static const char *
+v4l2_fwnode_bus_type_to_string(enum v4l2_fwnode_bus_type type)
+{
+ const struct v4l2_fwnode_bus_conv *conv =
+ get_v4l2_fwnode_bus_conv_by_fwnode_bus(type);
+
+ return conv ? conv->name : "not found";
+}
+
+static const struct v4l2_fwnode_bus_conv *
+get_v4l2_fwnode_bus_conv_by_mbus(enum v4l2_mbus_type type)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(busses); i++)
+ if (busses[i].mbus_type == type)
+ return &busses[i];
+
+ return NULL;
+}
+
+static const char *
+v4l2_fwnode_mbus_type_to_string(enum v4l2_mbus_type type)
+{
+ const struct v4l2_fwnode_bus_conv *conv =
+ get_v4l2_fwnode_bus_conv_by_mbus(type);
+
+ return conv ? conv->name : "not found";
+}
+
static int v4l2_fwnode_endpoint_parse_csi2_bus(struct fwnode_handle *fwnode,
- struct v4l2_fwnode_endpoint *vep)
+ struct v4l2_fwnode_endpoint *vep,
+ enum v4l2_mbus_type bus_type)
{
struct v4l2_fwnode_bus_mipi_csi2 *bus = &vep->bus.mipi_csi2;
- bool have_clk_lane = false;
+ bool have_clk_lane = false, have_data_lanes = false,
+ have_lane_polarities = false;
unsigned int flags = 0, lanes_used = 0;
+ u32 array[1 + V4L2_FWNODE_CSI2_MAX_DATA_LANES];
+ u32 clock_lane = 0;
+ unsigned int num_data_lanes = 0;
+ bool use_default_lane_mapping = false;
unsigned int i;
u32 v;
int rval;
+ if (bus_type == V4L2_MBUS_CSI2_DPHY ||
+ bus_type == V4L2_MBUS_CSI2_CPHY) {
+ use_default_lane_mapping = true;
+
+ num_data_lanes = min_t(u32, bus->num_data_lanes,
+ V4L2_FWNODE_CSI2_MAX_DATA_LANES);
+
+ clock_lane = bus->clock_lane;
+ if (clock_lane)
+ use_default_lane_mapping = false;
+
+ for (i = 0; i < num_data_lanes; i++) {
+ array[i] = bus->data_lanes[i];
+ if (array[i])
+ use_default_lane_mapping = false;
+ }
+
+ if (use_default_lane_mapping)
+ pr_debug("using default lane mapping\n");
+ }
+
rval = fwnode_property_read_u32_array(fwnode, "data-lanes", NULL, 0);
if (rval > 0) {
- u32 array[1 + V4L2_FWNODE_CSI2_MAX_DATA_LANES];
-
- bus->num_data_lanes =
+ num_data_lanes =
min_t(int, V4L2_FWNODE_CSI2_MAX_DATA_LANES, rval);
fwnode_property_read_u32_array(fwnode, "data-lanes", array,
- bus->num_data_lanes);
+ num_data_lanes);
- for (i = 0; i < bus->num_data_lanes; i++) {
- if (lanes_used & BIT(array[i]))
- pr_warn("duplicated lane %u in data-lanes\n",
- array[i]);
- lanes_used |= BIT(array[i]);
+ have_data_lanes = true;
+ }
- bus->data_lanes[i] = array[i];
+ for (i = 0; i < num_data_lanes; i++) {
+ if (lanes_used & BIT(array[i])) {
+ if (have_data_lanes || !use_default_lane_mapping)
+ pr_warn("duplicated lane %u in data-lanes, using defaults\n",
+ array[i]);
+ use_default_lane_mapping = true;
}
+ lanes_used |= BIT(array[i]);
- rval = fwnode_property_read_u32_array(fwnode,
- "lane-polarities", NULL,
- 0);
- if (rval > 0) {
- if (rval != 1 + bus->num_data_lanes /* clock+data */) {
- pr_warn("invalid number of lane-polarities entries (need %u, got %u)\n",
- 1 + bus->num_data_lanes, rval);
- return -EINVAL;
- }
-
- fwnode_property_read_u32_array(fwnode,
- "lane-polarities", array,
- 1 + bus->num_data_lanes);
+ if (have_data_lanes)
+ pr_debug("lane %u position %u\n", i, array[i]);
+ }
- for (i = 0; i < 1 + bus->num_data_lanes; i++)
- bus->lane_polarities[i] = array[i];
+ rval = fwnode_property_read_u32_array(fwnode, "lane-polarities", NULL,
+ 0);
+ if (rval > 0) {
+ if (rval != 1 + num_data_lanes /* clock+data */) {
+ pr_warn("invalid number of lane-polarities entries (need %u, got %u)\n",
+ 1 + num_data_lanes, rval);
+ return -EINVAL;
}
+ have_lane_polarities = true;
}
if (!fwnode_property_read_u32(fwnode, "clock-lanes", &v)) {
- if (lanes_used & BIT(v))
- pr_warn("duplicated lane %u in clock-lanes\n", v);
- lanes_used |= BIT(v);
-
- bus->clock_lane = v;
+ clock_lane = v;
+ pr_debug("clock lane position %u\n", v);
have_clk_lane = true;
}
- if (fwnode_property_present(fwnode, "clock-noncontinuous"))
+ if (lanes_used & BIT(clock_lane)) {
+ if (have_clk_lane || !use_default_lane_mapping)
+ pr_warn("duplicated lane %u in clock-lanes, using defaults\n",
+ v);
+ use_default_lane_mapping = true;
+ }
+
+ if (fwnode_property_present(fwnode, "clock-noncontinuous")) {
flags |= V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK;
- else if (have_clk_lane || bus->num_data_lanes > 0)
+ pr_debug("non-continuous clock\n");
+ } else {
flags |= V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
+ }
- bus->flags = flags;
- vep->bus_type = V4L2_MBUS_CSI2;
+ if (bus_type == V4L2_MBUS_CSI2_DPHY ||
+ bus_type == V4L2_MBUS_CSI2_CPHY || lanes_used ||
+ have_clk_lane || (flags & ~V4L2_MBUS_CSI2_CONTINUOUS_CLOCK)) {
+ bus->flags = flags;
+ if (bus_type == V4L2_MBUS_UNKNOWN)
+ vep->bus_type = V4L2_MBUS_CSI2_DPHY;
+ bus->num_data_lanes = num_data_lanes;
+
+ if (use_default_lane_mapping) {
+ bus->clock_lane = 0;
+ for (i = 0; i < num_data_lanes; i++)
+ bus->data_lanes[i] = 1 + i;
+ } else {
+ bus->clock_lane = clock_lane;
+ for (i = 0; i < num_data_lanes; i++)
+ bus->data_lanes[i] = array[i];
+ }
+
+ if (have_lane_polarities) {
+ fwnode_property_read_u32_array(fwnode,
+ "lane-polarities", array,
+ 1 + num_data_lanes);
+
+ for (i = 0; i < 1 + num_data_lanes; i++) {
+ bus->lane_polarities[i] = array[i];
+ pr_debug("lane %u polarity %sinverted",
+ i, array[i] ? "" : "not ");
+ }
+ } else {
+ pr_debug("no lane polarities defined, assuming not inverted\n");
+ }
+ }
return 0;
}
-static void v4l2_fwnode_endpoint_parse_parallel_bus(
- struct fwnode_handle *fwnode, struct v4l2_fwnode_endpoint *vep)
+#define PARALLEL_MBUS_FLAGS (V4L2_MBUS_HSYNC_ACTIVE_HIGH | \
+ V4L2_MBUS_HSYNC_ACTIVE_LOW | \
+ V4L2_MBUS_VSYNC_ACTIVE_HIGH | \
+ V4L2_MBUS_VSYNC_ACTIVE_LOW | \
+ V4L2_MBUS_FIELD_EVEN_HIGH | \
+ V4L2_MBUS_FIELD_EVEN_LOW)
+
+static void
+v4l2_fwnode_endpoint_parse_parallel_bus(struct fwnode_handle *fwnode,
+ struct v4l2_fwnode_endpoint *vep,
+ enum v4l2_mbus_type bus_type)
{
struct v4l2_fwnode_bus_parallel *bus = &vep->bus.parallel;
unsigned int flags = 0;
u32 v;
- if (!fwnode_property_read_u32(fwnode, "hsync-active", &v))
+ if (bus_type == V4L2_MBUS_PARALLEL || bus_type == V4L2_MBUS_BT656)
+ flags = bus->flags;
+
+ if (!fwnode_property_read_u32(fwnode, "hsync-active", &v)) {
+ flags &= ~(V4L2_MBUS_HSYNC_ACTIVE_HIGH |
+ V4L2_MBUS_HSYNC_ACTIVE_LOW);
flags |= v ? V4L2_MBUS_HSYNC_ACTIVE_HIGH :
V4L2_MBUS_HSYNC_ACTIVE_LOW;
+ pr_debug("hsync-active %s\n", v ? "high" : "low");
+ }
- if (!fwnode_property_read_u32(fwnode, "vsync-active", &v))
+ if (!fwnode_property_read_u32(fwnode, "vsync-active", &v)) {
+ flags &= ~(V4L2_MBUS_VSYNC_ACTIVE_HIGH |
+ V4L2_MBUS_VSYNC_ACTIVE_LOW);
flags |= v ? V4L2_MBUS_VSYNC_ACTIVE_HIGH :
V4L2_MBUS_VSYNC_ACTIVE_LOW;
+ pr_debug("vsync-active %s\n", v ? "high" : "low");
+ }
- if (!fwnode_property_read_u32(fwnode, "field-even-active", &v))
+ if (!fwnode_property_read_u32(fwnode, "field-even-active", &v)) {
+ flags &= ~(V4L2_MBUS_FIELD_EVEN_HIGH |
+ V4L2_MBUS_FIELD_EVEN_LOW);
flags |= v ? V4L2_MBUS_FIELD_EVEN_HIGH :
V4L2_MBUS_FIELD_EVEN_LOW;
- if (flags)
- vep->bus_type = V4L2_MBUS_PARALLEL;
- else
- vep->bus_type = V4L2_MBUS_BT656;
+ pr_debug("field-even-active %s\n", v ? "high" : "low");
+ }
- if (!fwnode_property_read_u32(fwnode, "pclk-sample", &v))
+ if (!fwnode_property_read_u32(fwnode, "pclk-sample", &v)) {
+ flags &= ~(V4L2_MBUS_PCLK_SAMPLE_RISING |
+ V4L2_MBUS_PCLK_SAMPLE_FALLING);
flags |= v ? V4L2_MBUS_PCLK_SAMPLE_RISING :
V4L2_MBUS_PCLK_SAMPLE_FALLING;
+ pr_debug("pclk-sample %s\n", v ? "high" : "low");
+ }
- if (!fwnode_property_read_u32(fwnode, "data-active", &v))
+ if (!fwnode_property_read_u32(fwnode, "data-active", &v)) {
+ flags &= ~(V4L2_MBUS_PCLK_SAMPLE_RISING |
+ V4L2_MBUS_PCLK_SAMPLE_FALLING);
flags |= v ? V4L2_MBUS_DATA_ACTIVE_HIGH :
V4L2_MBUS_DATA_ACTIVE_LOW;
+ pr_debug("data-active %s\n", v ? "high" : "low");
+ }
- if (fwnode_property_present(fwnode, "slave-mode"))
+ if (fwnode_property_present(fwnode, "slave-mode")) {
+ pr_debug("slave mode\n");
+ flags &= ~V4L2_MBUS_MASTER;
flags |= V4L2_MBUS_SLAVE;
- else
+ } else {
+ flags &= ~V4L2_MBUS_SLAVE;
flags |= V4L2_MBUS_MASTER;
+ }
- if (!fwnode_property_read_u32(fwnode, "bus-width", &v))
+ if (!fwnode_property_read_u32(fwnode, "bus-width", &v)) {
bus->bus_width = v;
+ pr_debug("bus-width %u\n", v);
+ }
- if (!fwnode_property_read_u32(fwnode, "data-shift", &v))
+ if (!fwnode_property_read_u32(fwnode, "data-shift", &v)) {
bus->data_shift = v;
+ pr_debug("data-shift %u\n", v);
+ }
- if (!fwnode_property_read_u32(fwnode, "sync-on-green-active", &v))
+ if (!fwnode_property_read_u32(fwnode, "sync-on-green-active", &v)) {
+ flags &= ~(V4L2_MBUS_VIDEO_SOG_ACTIVE_HIGH |
+ V4L2_MBUS_VIDEO_SOG_ACTIVE_LOW);
flags |= v ? V4L2_MBUS_VIDEO_SOG_ACTIVE_HIGH :
V4L2_MBUS_VIDEO_SOG_ACTIVE_LOW;
+ pr_debug("sync-on-green-active %s\n", v ? "high" : "low");
+ }
- if (!fwnode_property_read_u32(fwnode, "data-enable-active", &v))
+ if (!fwnode_property_read_u32(fwnode, "data-enable-active", &v)) {
+ flags &= ~(V4L2_MBUS_DATA_ENABLE_HIGH |
+ V4L2_MBUS_DATA_ENABLE_LOW);
flags |= v ? V4L2_MBUS_DATA_ENABLE_HIGH :
V4L2_MBUS_DATA_ENABLE_LOW;
+ pr_debug("data-enable-active %s\n", v ? "high" : "low");
+ }
- bus->flags = flags;
-
+ switch (bus_type) {
+ default:
+ bus->flags = flags;
+ if (flags & PARALLEL_MBUS_FLAGS)
+ vep->bus_type = V4L2_MBUS_PARALLEL;
+ else
+ vep->bus_type = V4L2_MBUS_BT656;
+ break;
+ case V4L2_MBUS_PARALLEL:
+ vep->bus_type = V4L2_MBUS_PARALLEL;
+ bus->flags = flags;
+ break;
+ case V4L2_MBUS_BT656:
+ vep->bus_type = V4L2_MBUS_BT656;
+ bus->flags = flags & ~PARALLEL_MBUS_FLAGS;
+ break;
+ }
}
static void
v4l2_fwnode_endpoint_parse_csi1_bus(struct fwnode_handle *fwnode,
struct v4l2_fwnode_endpoint *vep,
- u32 bus_type)
+ enum v4l2_mbus_type bus_type)
{
struct v4l2_fwnode_bus_mipi_csi1 *bus = &vep->bus.mipi_csi1;
u32 v;
- if (!fwnode_property_read_u32(fwnode, "clock-inv", &v))
+ if (!fwnode_property_read_u32(fwnode, "clock-inv", &v)) {
bus->clock_inv = v;
+ pr_debug("clock-inv %u\n", v);
+ }
- if (!fwnode_property_read_u32(fwnode, "strobe", &v))
+ if (!fwnode_property_read_u32(fwnode, "strobe", &v)) {
bus->strobe = v;
+ pr_debug("strobe %u\n", v);
+ }
- if (!fwnode_property_read_u32(fwnode, "data-lanes", &v))
+ if (!fwnode_property_read_u32(fwnode, "data-lanes", &v)) {
bus->data_lane = v;
+ pr_debug("data-lanes %u\n", v);
+ }
- if (!fwnode_property_read_u32(fwnode, "clock-lanes", &v))
+ if (!fwnode_property_read_u32(fwnode, "clock-lanes", &v)) {
bus->clock_lane = v;
+ pr_debug("clock-lanes %u\n", v);
+ }
- if (bus_type == V4L2_FWNODE_BUS_TYPE_CCP2)
+ if (bus_type == V4L2_MBUS_CCP2)
vep->bus_type = V4L2_MBUS_CCP2;
else
vep->bus_type = V4L2_MBUS_CSI1;
}
-int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
- struct v4l2_fwnode_endpoint *vep)
+static int __v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
+ struct v4l2_fwnode_endpoint *vep)
{
- u32 bus_type = 0;
+ u32 bus_type = V4L2_FWNODE_BUS_TYPE_GUESS;
+ enum v4l2_mbus_type mbus_type;
int rval;
- fwnode_graph_parse_endpoint(fwnode, &vep->base);
+ if (vep->bus_type == V4L2_MBUS_UNKNOWN) {
+ /* Zero fields from bus union to until the end */
+ memset(&vep->bus, 0,
+ sizeof(*vep) - offsetof(typeof(*vep), bus));
+ }
- /* Zero fields from bus_type to until the end */
- memset(&vep->bus_type, 0, sizeof(*vep) -
- offsetof(typeof(*vep), bus_type));
+ pr_debug("===== begin V4L2 endpoint properties\n");
+
+ /*
+ * Zero the fwnode graph endpoint memory in case we don't end up parsing
+ * the endpoint.
+ */
+ memset(&vep->base, 0, sizeof(vep->base));
fwnode_property_read_u32(fwnode, "bus-type", &bus_type);
+ pr_debug("fwnode video bus type %s (%u), mbus type %s (%u)\n",
+ v4l2_fwnode_bus_type_to_string(bus_type), bus_type,
+ v4l2_fwnode_mbus_type_to_string(vep->bus_type),
+ vep->bus_type);
+ mbus_type = v4l2_fwnode_bus_type_to_mbus(bus_type);
+
+ if (vep->bus_type != V4L2_MBUS_UNKNOWN) {
+ if (mbus_type != V4L2_MBUS_UNKNOWN &&
+ vep->bus_type != mbus_type) {
+ pr_debug("expecting bus type %s\n",
+ v4l2_fwnode_mbus_type_to_string(vep->bus_type));
+ return -ENXIO;
+ }
+ } else {
+ vep->bus_type = mbus_type;
+ }
- switch (bus_type) {
- case V4L2_FWNODE_BUS_TYPE_GUESS:
- rval = v4l2_fwnode_endpoint_parse_csi2_bus(fwnode, vep);
+ switch (vep->bus_type) {
+ case V4L2_MBUS_UNKNOWN:
+ rval = v4l2_fwnode_endpoint_parse_csi2_bus(fwnode, vep,
+ V4L2_MBUS_UNKNOWN);
if (rval)
return rval;
- /*
- * Parse the parallel video bus properties only if none
- * of the MIPI CSI-2 specific properties were found.
- */
- if (vep->bus.mipi_csi2.flags == 0)
- v4l2_fwnode_endpoint_parse_parallel_bus(fwnode, vep);
-
- return 0;
- case V4L2_FWNODE_BUS_TYPE_CCP2:
- case V4L2_FWNODE_BUS_TYPE_CSI1:
- v4l2_fwnode_endpoint_parse_csi1_bus(fwnode, vep, bus_type);
-
- return 0;
+
+ if (vep->bus_type == V4L2_MBUS_UNKNOWN)
+ v4l2_fwnode_endpoint_parse_parallel_bus(fwnode, vep,
+ V4L2_MBUS_UNKNOWN);
+
+ pr_debug("assuming media bus type %s (%u)\n",
+ v4l2_fwnode_mbus_type_to_string(vep->bus_type),
+ vep->bus_type);
+
+ break;
+ case V4L2_MBUS_CCP2:
+ case V4L2_MBUS_CSI1:
+ v4l2_fwnode_endpoint_parse_csi1_bus(fwnode, vep, vep->bus_type);
+
+ break;
+ case V4L2_MBUS_CSI2_DPHY:
+ case V4L2_MBUS_CSI2_CPHY:
+ rval = v4l2_fwnode_endpoint_parse_csi2_bus(fwnode, vep,
+ vep->bus_type);
+ if (rval)
+ return rval;
+
+ break;
+ case V4L2_MBUS_PARALLEL:
+ case V4L2_MBUS_BT656:
+ v4l2_fwnode_endpoint_parse_parallel_bus(fwnode, vep,
+ vep->bus_type);
+
+ break;
default:
- pr_warn("unsupported bus type %u\n", bus_type);
+ pr_warn("unsupported bus type %u\n", mbus_type);
return -EINVAL;
}
+
+ fwnode_graph_parse_endpoint(fwnode, &vep->base);
+
+ return 0;
+}
+
+int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
+ struct v4l2_fwnode_endpoint *vep)
+{
+ int ret;
+
+ ret = __v4l2_fwnode_endpoint_parse(fwnode, vep);
+
+ pr_debug("===== end V4L2 endpoint properties\n");
+
+ return ret;
}
EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_parse);
@@ -233,49 +508,48 @@ void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep)
return;
kfree(vep->link_frequencies);
- kfree(vep);
}
EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_free);
-struct v4l2_fwnode_endpoint *v4l2_fwnode_endpoint_alloc_parse(
- struct fwnode_handle *fwnode)
+int v4l2_fwnode_endpoint_alloc_parse(struct fwnode_handle *fwnode,
+ struct v4l2_fwnode_endpoint *vep)
{
- struct v4l2_fwnode_endpoint *vep;
int rval;
- vep = kzalloc(sizeof(*vep), GFP_KERNEL);
- if (!vep)
- return ERR_PTR(-ENOMEM);
-
- rval = v4l2_fwnode_endpoint_parse(fwnode, vep);
+ rval = __v4l2_fwnode_endpoint_parse(fwnode, vep);
if (rval < 0)
- goto out_err;
+ return rval;
rval = fwnode_property_read_u64_array(fwnode, "link-frequencies",
NULL, 0);
if (rval > 0) {
+ unsigned int i;
+
vep->link_frequencies =
kmalloc_array(rval, sizeof(*vep->link_frequencies),
GFP_KERNEL);
- if (!vep->link_frequencies) {
- rval = -ENOMEM;
- goto out_err;
- }
+ if (!vep->link_frequencies)
+ return -ENOMEM;
vep->nr_of_link_frequencies = rval;
- rval = fwnode_property_read_u64_array(
- fwnode, "link-frequencies", vep->link_frequencies,
- vep->nr_of_link_frequencies);
- if (rval < 0)
- goto out_err;
+ rval = fwnode_property_read_u64_array(fwnode,
+ "link-frequencies",
+ vep->link_frequencies,
+ vep->nr_of_link_frequencies);
+ if (rval < 0) {
+ v4l2_fwnode_endpoint_free(vep);
+ return rval;
+ }
+
+ for (i = 0; i < vep->nr_of_link_frequencies; i++)
+ pr_info("link-frequencies %u value %llu\n", i,
+ vep->link_frequencies[i]);
}
- return vep;
+ pr_debug("===== end V4L2 endpoint properties\n");
-out_err:
- v4l2_fwnode_endpoint_free(vep);
- return ERR_PTR(rval);
+ return 0;
}
EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_alloc_parse);
@@ -320,43 +594,16 @@ void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
}
EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
-static int v4l2_async_notifier_realloc(struct v4l2_async_notifier *notifier,
- unsigned int max_subdevs)
-{
- struct v4l2_async_subdev **subdevs;
-
- if (max_subdevs <= notifier->max_subdevs)
- return 0;
-
- subdevs = kvmalloc_array(
- max_subdevs, sizeof(*notifier->subdevs),
- GFP_KERNEL | __GFP_ZERO);
- if (!subdevs)
- return -ENOMEM;
-
- if (notifier->subdevs) {
- memcpy(subdevs, notifier->subdevs,
- sizeof(*subdevs) * notifier->num_subdevs);
-
- kvfree(notifier->subdevs);
- }
-
- notifier->subdevs = subdevs;
- notifier->max_subdevs = max_subdevs;
-
- return 0;
-}
-
-static int v4l2_async_notifier_fwnode_parse_endpoint(
- struct device *dev, struct v4l2_async_notifier *notifier,
- struct fwnode_handle *endpoint, unsigned int asd_struct_size,
- int (*parse_endpoint)(struct device *dev,
- struct v4l2_fwnode_endpoint *vep,
- struct v4l2_async_subdev *asd))
+static int
+v4l2_async_notifier_fwnode_parse_endpoint(struct device *dev,
+ struct v4l2_async_notifier *notifier,
+ struct fwnode_handle *endpoint,
+ unsigned int asd_struct_size,
+ parse_endpoint_func parse_endpoint)
{
+ struct v4l2_fwnode_endpoint vep = { .bus_type = 0 };
struct v4l2_async_subdev *asd;
- struct v4l2_fwnode_endpoint *vep;
- int ret = 0;
+ int ret;
asd = kzalloc(asd_struct_size, GFP_KERNEL);
if (!asd)
@@ -367,32 +614,36 @@ static int v4l2_async_notifier_fwnode_parse_endpoint(
fwnode_graph_get_remote_port_parent(endpoint);
if (!asd->match.fwnode) {
dev_warn(dev, "bad remote port parent\n");
- ret = -EINVAL;
+ ret = -ENOTCONN;
goto out_err;
}
- vep = v4l2_fwnode_endpoint_alloc_parse(endpoint);
- if (IS_ERR(vep)) {
- ret = PTR_ERR(vep);
+ ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &vep);
+ if (ret) {
dev_warn(dev, "unable to parse V4L2 fwnode endpoint (%d)\n",
ret);
goto out_err;
}
- ret = parse_endpoint ? parse_endpoint(dev, vep, asd) : 0;
+ ret = parse_endpoint ? parse_endpoint(dev, &vep, asd) : 0;
if (ret == -ENOTCONN)
- dev_dbg(dev, "ignoring port@%u/endpoint@%u\n", vep->base.port,
- vep->base.id);
+ dev_dbg(dev, "ignoring port@%u/endpoint@%u\n", vep.base.port,
+ vep.base.id);
else if (ret < 0)
dev_warn(dev,
"driver could not parse port@%u/endpoint@%u (%d)\n",
- vep->base.port, vep->base.id, ret);
- v4l2_fwnode_endpoint_free(vep);
+ vep.base.port, vep.base.id, ret);
+ v4l2_fwnode_endpoint_free(&vep);
if (ret < 0)
goto out_err;
- notifier->subdevs[notifier->num_subdevs] = asd;
- notifier->num_subdevs++;
+ ret = v4l2_async_notifier_add_subdev(notifier, asd);
+ if (ret < 0) {
+ /* not an error if asd already exists */
+ if (ret == -EEXIST)
+ ret = 0;
+ goto out_err;
+ }
return 0;
@@ -403,56 +654,21 @@ out_err:
return ret == -ENOTCONN ? 0 : ret;
}
-static int __v4l2_async_notifier_parse_fwnode_endpoints(
- struct device *dev, struct v4l2_async_notifier *notifier,
- size_t asd_struct_size, unsigned int port, bool has_port,
- int (*parse_endpoint)(struct device *dev,
- struct v4l2_fwnode_endpoint *vep,
- struct v4l2_async_subdev *asd))
+static int
+__v4l2_async_notifier_parse_fwnode_ep(struct device *dev,
+ struct v4l2_async_notifier *notifier,
+ size_t asd_struct_size,
+ unsigned int port,
+ bool has_port,
+ parse_endpoint_func parse_endpoint)
{
struct fwnode_handle *fwnode;
- unsigned int max_subdevs = notifier->max_subdevs;
- int ret;
+ int ret = 0;
if (WARN_ON(asd_struct_size < sizeof(struct v4l2_async_subdev)))
return -EINVAL;
- for (fwnode = NULL; (fwnode = fwnode_graph_get_next_endpoint(
- dev_fwnode(dev), fwnode)); ) {
- struct fwnode_handle *dev_fwnode;
- bool is_available;
-
- dev_fwnode = fwnode_graph_get_port_parent(fwnode);
- is_available = fwnode_device_is_available(dev_fwnode);
- fwnode_handle_put(dev_fwnode);
- if (!is_available)
- continue;
-
- if (has_port) {
- struct fwnode_endpoint ep;
-
- ret = fwnode_graph_parse_endpoint(fwnode, &ep);
- if (ret) {
- fwnode_handle_put(fwnode);
- return ret;
- }
-
- if (ep.port != port)
- continue;
- }
- max_subdevs++;
- }
-
- /* No subdevs to add? Return here. */
- if (max_subdevs == notifier->max_subdevs)
- return 0;
-
- ret = v4l2_async_notifier_realloc(notifier, max_subdevs);
- if (ret)
- return ret;
-
- for (fwnode = NULL; (fwnode = fwnode_graph_get_next_endpoint(
- dev_fwnode(dev), fwnode)); ) {
+ fwnode_graph_for_each_endpoint(dev_fwnode(dev), fwnode) {
struct fwnode_handle *dev_fwnode;
bool is_available;
@@ -473,13 +689,11 @@ static int __v4l2_async_notifier_parse_fwnode_endpoints(
continue;
}
- if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) {
- ret = -EINVAL;
- break;
- }
-
- ret = v4l2_async_notifier_fwnode_parse_endpoint(
- dev, notifier, fwnode, asd_struct_size, parse_endpoint);
+ ret = v4l2_async_notifier_fwnode_parse_endpoint(dev,
+ notifier,
+ fwnode,
+ asd_struct_size,
+ parse_endpoint);
if (ret < 0)
break;
}
@@ -489,27 +703,29 @@ static int __v4l2_async_notifier_parse_fwnode_endpoints(
return ret;
}
-int v4l2_async_notifier_parse_fwnode_endpoints(
- struct device *dev, struct v4l2_async_notifier *notifier,
- size_t asd_struct_size,
- int (*parse_endpoint)(struct device *dev,
- struct v4l2_fwnode_endpoint *vep,
- struct v4l2_async_subdev *asd))
+int
+v4l2_async_notifier_parse_fwnode_endpoints(struct device *dev,
+ struct v4l2_async_notifier *notifier,
+ size_t asd_struct_size,
+ parse_endpoint_func parse_endpoint)
{
- return __v4l2_async_notifier_parse_fwnode_endpoints(
- dev, notifier, asd_struct_size, 0, false, parse_endpoint);
+ return __v4l2_async_notifier_parse_fwnode_ep(dev, notifier,
+ asd_struct_size, 0,
+ false, parse_endpoint);
}
EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints);
-int v4l2_async_notifier_parse_fwnode_endpoints_by_port(
- struct device *dev, struct v4l2_async_notifier *notifier,
- size_t asd_struct_size, unsigned int port,
- int (*parse_endpoint)(struct device *dev,
- struct v4l2_fwnode_endpoint *vep,
- struct v4l2_async_subdev *asd))
+int
+v4l2_async_notifier_parse_fwnode_endpoints_by_port(struct device *dev,
+ struct v4l2_async_notifier *notifier,
+ size_t asd_struct_size,
+ unsigned int port,
+ parse_endpoint_func parse_endpoint)
{
- return __v4l2_async_notifier_parse_fwnode_endpoints(
- dev, notifier, asd_struct_size, port, true, parse_endpoint);
+ return __v4l2_async_notifier_parse_fwnode_ep(dev, notifier,
+ asd_struct_size,
+ port, true,
+ parse_endpoint);
}
EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints_by_port);
@@ -524,17 +740,18 @@ EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints_by_port);
* -ENOMEM if memory allocation failed
* -EINVAL if property parsing failed
*/
-static int v4l2_fwnode_reference_parse(
- struct device *dev, struct v4l2_async_notifier *notifier,
- const char *prop)
+static int v4l2_fwnode_reference_parse(struct device *dev,
+ struct v4l2_async_notifier *notifier,
+ const char *prop)
{
struct fwnode_reference_args args;
unsigned int index;
int ret;
for (index = 0;
- !(ret = fwnode_property_get_reference_args(
- dev_fwnode(dev), prop, NULL, 0, index, &args));
+ !(ret = fwnode_property_get_reference_args(dev_fwnode(dev),
+ prop, NULL, 0,
+ index, &args));
index++)
fwnode_handle_put(args.fwnode);
@@ -548,31 +765,25 @@ static int v4l2_fwnode_reference_parse(
if (ret != -ENOENT && ret != -ENODATA)
return ret;
- ret = v4l2_async_notifier_realloc(notifier,
- notifier->num_subdevs + index);
- if (ret)
- return ret;
-
- for (index = 0; !fwnode_property_get_reference_args(
- dev_fwnode(dev), prop, NULL, 0, index, &args);
+ for (index = 0;
+ !fwnode_property_get_reference_args(dev_fwnode(dev), prop, NULL,
+ 0, index, &args);
index++) {
struct v4l2_async_subdev *asd;
- if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) {
- ret = -EINVAL;
- goto error;
- }
+ asd = v4l2_async_notifier_add_fwnode_subdev(notifier,
+ args.fwnode,
+ sizeof(*asd));
+ if (IS_ERR(asd)) {
+ ret = PTR_ERR(asd);
+ /* not an error if asd already exists */
+ if (ret == -EEXIST) {
+ fwnode_handle_put(args.fwnode);
+ continue;
+ }
- asd = kzalloc(sizeof(*asd), GFP_KERNEL);
- if (!asd) {
- ret = -ENOMEM;
goto error;
}
-
- notifier->subdevs[notifier->num_subdevs] = asd;
- asd->match.fwnode = args.fwnode;
- asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
- notifier->num_subdevs++;
}
return 0;
@@ -738,9 +949,12 @@ error:
* -EINVAL if property parsing otherwise failed
* -ENOMEM if memory allocation failed
*/
-static struct fwnode_handle *v4l2_fwnode_reference_get_int_prop(
- struct fwnode_handle *fwnode, const char *prop, unsigned int index,
- const char * const *props, unsigned int nprops)
+static struct fwnode_handle *
+v4l2_fwnode_reference_get_int_prop(struct fwnode_handle *fwnode,
+ const char *prop,
+ unsigned int index,
+ const char * const *props,
+ unsigned int nprops)
{
struct fwnode_reference_args fwnode_args;
u64 *args = fwnode_args.args;
@@ -792,6 +1006,12 @@ static struct fwnode_handle *v4l2_fwnode_reference_get_int_prop(
return fwnode;
}
+struct v4l2_fwnode_int_props {
+ const char *name;
+ const char * const *props;
+ unsigned int nprops;
+};
+
/*
* v4l2_fwnode_reference_parse_int_props - parse references for async
* sub-devices
@@ -815,13 +1035,17 @@ static struct fwnode_handle *v4l2_fwnode_reference_get_int_prop(
* -EINVAL if property parsing otherwisefailed
* -ENOMEM if memory allocation failed
*/
-static int v4l2_fwnode_reference_parse_int_props(
- struct device *dev, struct v4l2_async_notifier *notifier,
- const char *prop, const char * const *props, unsigned int nprops)
+static int
+v4l2_fwnode_reference_parse_int_props(struct device *dev,
+ struct v4l2_async_notifier *notifier,
+ const struct v4l2_fwnode_int_props *p)
{
struct fwnode_handle *fwnode;
unsigned int index;
int ret;
+ const char *prop = p->name;
+ const char * const *props = p->props;
+ unsigned int nprops = p->nprops;
index = 0;
do {
@@ -843,31 +1067,26 @@ static int v4l2_fwnode_reference_parse_int_props(
index++;
} while (1);
- ret = v4l2_async_notifier_realloc(notifier,
- notifier->num_subdevs + index);
- if (ret)
- return -ENOMEM;
-
- for (index = 0; !IS_ERR((fwnode = v4l2_fwnode_reference_get_int_prop(
- dev_fwnode(dev), prop, index, props,
- nprops))); index++) {
+ for (index = 0;
+ !IS_ERR((fwnode = v4l2_fwnode_reference_get_int_prop(dev_fwnode(dev),
+ prop, index,
+ props,
+ nprops)));
+ index++) {
struct v4l2_async_subdev *asd;
- if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) {
- ret = -EINVAL;
- goto error;
- }
+ asd = v4l2_async_notifier_add_fwnode_subdev(notifier, fwnode,
+ sizeof(*asd));
+ if (IS_ERR(asd)) {
+ ret = PTR_ERR(asd);
+ /* not an error if asd already exists */
+ if (ret == -EEXIST) {
+ fwnode_handle_put(fwnode);
+ continue;
+ }
- asd = kzalloc(sizeof(struct v4l2_async_subdev), GFP_KERNEL);
- if (!asd) {
- ret = -ENOMEM;
goto error;
}
-
- notifier->subdevs[notifier->num_subdevs] = asd;
- asd->match.fwnode = fwnode;
- asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
- notifier->num_subdevs++;
}
return PTR_ERR(fwnode) == -ENOENT ? 0 : PTR_ERR(fwnode);
@@ -877,15 +1096,11 @@ error:
return ret;
}
-int v4l2_async_notifier_parse_fwnode_sensor_common(
- struct device *dev, struct v4l2_async_notifier *notifier)
+int v4l2_async_notifier_parse_fwnode_sensor_common(struct device *dev,
+ struct v4l2_async_notifier *notifier)
{
static const char * const led_props[] = { "led" };
- static const struct {
- const char *name;
- const char * const *props;
- unsigned int nprops;
- } props[] = {
+ static const struct v4l2_fwnode_int_props props[] = {
{ "flash-leds", led_props, ARRAY_SIZE(led_props) },
{ "lens-focus", NULL, 0 },
};
@@ -895,12 +1110,12 @@ int v4l2_async_notifier_parse_fwnode_sensor_common(
int ret;
if (props[i].props && is_acpi_node(dev_fwnode(dev)))
- ret = v4l2_fwnode_reference_parse_int_props(
- dev, notifier, props[i].name,
- props[i].props, props[i].nprops);
+ ret = v4l2_fwnode_reference_parse_int_props(dev,
+ notifier,
+ &props[i]);
else
- ret = v4l2_fwnode_reference_parse(
- dev, notifier, props[i].name);
+ ret = v4l2_fwnode_reference_parse(dev, notifier,
+ props[i].name);
if (ret && ret != -ENOENT) {
dev_warn(dev, "parsing property \"%s\" failed (%d)\n",
props[i].name, ret);
@@ -924,6 +1139,8 @@ int v4l2_async_register_subdev_sensor_common(struct v4l2_subdev *sd)
if (!notifier)
return -ENOMEM;
+ v4l2_async_notifier_init(notifier);
+
ret = v4l2_async_notifier_parse_fwnode_sensor_common(sd->dev,
notifier);
if (ret < 0)
@@ -952,6 +1169,68 @@ out_cleanup:
}
EXPORT_SYMBOL_GPL(v4l2_async_register_subdev_sensor_common);
+int v4l2_async_register_fwnode_subdev(struct v4l2_subdev *sd,
+ size_t asd_struct_size,
+ unsigned int *ports,
+ unsigned int num_ports,
+ parse_endpoint_func parse_endpoint)
+{
+ struct v4l2_async_notifier *notifier;
+ struct device *dev = sd->dev;
+ struct fwnode_handle *fwnode;
+ int ret;
+
+ if (WARN_ON(!dev))
+ return -ENODEV;
+
+ fwnode = dev_fwnode(dev);
+ if (!fwnode_device_is_available(fwnode))
+ return -ENODEV;
+
+ notifier = kzalloc(sizeof(*notifier), GFP_KERNEL);
+ if (!notifier)
+ return -ENOMEM;
+
+ v4l2_async_notifier_init(notifier);
+
+ if (!ports) {
+ ret = v4l2_async_notifier_parse_fwnode_endpoints(dev, notifier,
+ asd_struct_size,
+ parse_endpoint);
+ if (ret < 0)
+ goto out_cleanup;
+ } else {
+ unsigned int i;
+
+ for (i = 0; i < num_ports; i++) {
+ ret = v4l2_async_notifier_parse_fwnode_endpoints_by_port(dev, notifier, asd_struct_size, ports[i], parse_endpoint);
+ if (ret < 0)
+ goto out_cleanup;
+ }
+ }
+
+ ret = v4l2_async_subdev_notifier_register(sd, notifier);
+ if (ret < 0)
+ goto out_cleanup;
+
+ ret = v4l2_async_register_subdev(sd);
+ if (ret < 0)
+ goto out_unregister;
+
+ sd->subdev_notifier = notifier;
+
+ return 0;
+
+out_unregister:
+ v4l2_async_notifier_unregister(notifier);
+out_cleanup:
+ v4l2_async_notifier_cleanup(notifier);
+ kfree(notifier);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(v4l2_async_register_fwnode_subdev);
+
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 54afc9c7ee6e..c63746968fa3 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -121,7 +121,7 @@ int v4l2_video_std_construct(struct v4l2_standard *vs,
vs->id = id;
v4l2_video_std_frame_period(id, &vs->frameperiod);
vs->framelines = (id & V4L2_STD_525_60) ? 525 : 625;
- strlcpy(vs->name, name, sizeof(vs->name));
+ strscpy(vs->name, name, sizeof(vs->name));
return 0;
}
EXPORT_SYMBOL(v4l2_video_std_construct);
@@ -474,13 +474,13 @@ static void v4l_print_buffer(const void *arg, bool write_only)
const struct v4l2_plane *plane;
int i;
- pr_cont("%02ld:%02d:%02d.%08ld index=%d, type=%s, flags=0x%08x, field=%s, sequence=%d, memory=%s",
+ pr_cont("%02ld:%02d:%02d.%08ld index=%d, type=%s, request_fd=%d, flags=0x%08x, field=%s, sequence=%d, memory=%s",
p->timestamp.tv_sec / 3600,
(int)(p->timestamp.tv_sec / 60) % 60,
(int)(p->timestamp.tv_sec % 60),
(long)p->timestamp.tv_usec,
p->index,
- prt_names(p->type, v4l2_type_names),
+ prt_names(p->type, v4l2_type_names), p->request_fd,
p->flags, prt_names(p->field, v4l2_field_names),
p->sequence, prt_names(p->memory, v4l2_memory_names));
@@ -590,8 +590,8 @@ static void v4l_print_ext_controls(const void *arg, bool write_only)
const struct v4l2_ext_controls *p = arg;
int i;
- pr_cont("which=0x%x, count=%d, error_idx=%d",
- p->which, p->count, p->error_idx);
+ pr_cont("which=0x%x, count=%d, error_idx=%d, request_fd=%d",
+ p->which, p->count, p->error_idx, p->request_fd);
for (i = 0; i < p->count; i++) {
if (!p->controls[i].size)
pr_cont(", id/val=0x%x/0x%x",
@@ -907,7 +907,7 @@ static int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv)
__u32 i;
/* zero the reserved fields */
- c->reserved[0] = c->reserved[1] = 0;
+ c->reserved[0] = 0;
for (i = 0; i < c->count; i++)
c->controls[i].reserved2[0] = 0;
@@ -1309,6 +1309,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_H263: descr = "H.263"; break;
case V4L2_PIX_FMT_MPEG1: descr = "MPEG-1 ES"; break;
case V4L2_PIX_FMT_MPEG2: descr = "MPEG-2 ES"; break;
+ case V4L2_PIX_FMT_MPEG2_SLICE: descr = "MPEG-2 Parsed Slice Data"; break;
case V4L2_PIX_FMT_MPEG4: descr = "MPEG-4 part 2 ES"; break;
case V4L2_PIX_FMT_XVID: descr = "Xvid"; break;
case V4L2_PIX_FMT_VC1_ANNEX_G: descr = "VC-1 (SMPTE 412M Annex G)"; break;
@@ -1336,6 +1337,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_SE401: descr = "GSPCA SE401"; break;
case V4L2_PIX_FMT_S5C_UYVY_JPG: descr = "S5C73MX interleaved UYVY/JPEG"; break;
case V4L2_PIX_FMT_MT21C: descr = "Mediatek Compressed Format"; break;
+ case V4L2_PIX_FMT_SUNXI_TILED_NV12: descr = "Sunxi Tiled NV12 Format"; break;
default:
WARN(1, "Unknown pixelformat 0x%08x\n", fmt->pixelformat);
if (fmt->description[0])
@@ -1352,7 +1354,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
}
if (descr)
- WARN_ON(strlcpy(fmt->description, descr, sz) >= sz);
+ WARN_ON(strscpy(fmt->description, descr, sz) >= sz);
fmt->flags = flags;
}
@@ -1877,7 +1879,7 @@ static int v4l_reqbufs(const struct v4l2_ioctl_ops *ops,
if (ret)
return ret;
- CLEAR_AFTER_FIELD(p, memory);
+ CLEAR_AFTER_FIELD(p, capabilities);
return ops->vidioc_reqbufs(file, fh, p);
}
@@ -1918,7 +1920,7 @@ static int v4l_create_bufs(const struct v4l2_ioctl_ops *ops,
if (ret)
return ret;
- CLEAR_AFTER_FIELD(create, format);
+ CLEAR_AFTER_FIELD(create, capabilities);
v4l_sanitize_format(&create->format);
@@ -2109,9 +2111,9 @@ static int v4l_g_ext_ctrls(const struct v4l2_ioctl_ops *ops,
p->error_idx = p->count;
if (vfh && vfh->ctrl_handler)
- return v4l2_g_ext_ctrls(vfh->ctrl_handler, p);
+ return v4l2_g_ext_ctrls(vfh->ctrl_handler, vfd->v4l2_dev->mdev, p);
if (vfd->ctrl_handler)
- return v4l2_g_ext_ctrls(vfd->ctrl_handler, p);
+ return v4l2_g_ext_ctrls(vfd->ctrl_handler, vfd->v4l2_dev->mdev, p);
if (ops->vidioc_g_ext_ctrls == NULL)
return -ENOTTY;
return check_ext_ctrls(p, 0) ? ops->vidioc_g_ext_ctrls(file, fh, p) :
@@ -2128,9 +2130,9 @@ static int v4l_s_ext_ctrls(const struct v4l2_ioctl_ops *ops,
p->error_idx = p->count;
if (vfh && vfh->ctrl_handler)
- return v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, p);
+ return v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, vfd->v4l2_dev->mdev, p);
if (vfd->ctrl_handler)
- return v4l2_s_ext_ctrls(NULL, vfd->ctrl_handler, p);
+ return v4l2_s_ext_ctrls(NULL, vfd->ctrl_handler, vfd->v4l2_dev->mdev, p);
if (ops->vidioc_s_ext_ctrls == NULL)
return -ENOTTY;
return check_ext_ctrls(p, 0) ? ops->vidioc_s_ext_ctrls(file, fh, p) :
@@ -2147,9 +2149,9 @@ static int v4l_try_ext_ctrls(const struct v4l2_ioctl_ops *ops,
p->error_idx = p->count;
if (vfh && vfh->ctrl_handler)
- return v4l2_try_ext_ctrls(vfh->ctrl_handler, p);
+ return v4l2_try_ext_ctrls(vfh->ctrl_handler, vfd->v4l2_dev->mdev, p);
if (vfd->ctrl_handler)
- return v4l2_try_ext_ctrls(vfd->ctrl_handler, p);
+ return v4l2_try_ext_ctrls(vfd->ctrl_handler, vfd->v4l2_dev->mdev, p);
if (ops->vidioc_try_ext_ctrls == NULL)
return -ENOTTY;
return check_ext_ctrls(p, 0) ? ops->vidioc_try_ext_ctrls(file, fh, p) :
@@ -2391,7 +2393,7 @@ static int v4l_dbg_g_chip_info(const struct v4l2_ioctl_ops *ops,
p->flags |= V4L2_CHIP_FL_WRITABLE;
if (ops->vidioc_g_register)
p->flags |= V4L2_CHIP_FL_READABLE;
- strlcpy(p->name, vfd->v4l2_dev->name, sizeof(p->name));
+ strscpy(p->name, vfd->v4l2_dev->name, sizeof(p->name));
if (ops->vidioc_g_chip_info)
return ops->vidioc_g_chip_info(file, fh, arg);
if (p->match.addr)
@@ -2408,7 +2410,7 @@ static int v4l_dbg_g_chip_info(const struct v4l2_ioctl_ops *ops,
p->flags |= V4L2_CHIP_FL_WRITABLE;
if (sd->ops->core && sd->ops->core->g_register)
p->flags |= V4L2_CHIP_FL_READABLE;
- strlcpy(p->name, sd->name, sizeof(p->name));
+ strscpy(p->name, sd->name, sizeof(p->name));
return 0;
}
break;
@@ -2780,6 +2782,7 @@ static long __video_do_ioctl(struct file *file,
unsigned int cmd, void *arg)
{
struct video_device *vfd = video_devdata(file);
+ struct mutex *req_queue_lock = NULL;
struct mutex *lock; /* ioctl serialization mutex */
const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops;
bool write_only = false;
@@ -2799,10 +2802,27 @@ static long __video_do_ioctl(struct file *file,
if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags))
vfh = file->private_data;
+ /*
+ * We need to serialize streamon/off with queueing new requests.
+ * These ioctls may trigger the cancellation of a streaming
+ * operation, and that should not be mixed with queueing a new
+ * request at the same time.
+ */
+ if (v4l2_device_supports_requests(vfd->v4l2_dev) &&
+ (cmd == VIDIOC_STREAMON || cmd == VIDIOC_STREAMOFF)) {
+ req_queue_lock = &vfd->v4l2_dev->mdev->req_queue_mutex;
+
+ if (mutex_lock_interruptible(req_queue_lock))
+ return -ERESTARTSYS;
+ }
+
lock = v4l2_ioctl_get_lock(vfd, vfh, cmd, arg);
- if (lock && mutex_lock_interruptible(lock))
+ if (lock && mutex_lock_interruptible(lock)) {
+ if (req_queue_lock)
+ mutex_unlock(req_queue_lock);
return -ERESTARTSYS;
+ }
if (!video_is_registered(vfd)) {
ret = -ENODEV;
@@ -2861,6 +2881,8 @@ done:
unlock:
if (lock)
mutex_unlock(lock);
+ if (req_queue_lock)
+ mutex_unlock(req_queue_lock);
return ret;
}
diff --git a/drivers/media/v4l2-core/v4l2-mc.c b/drivers/media/v4l2-core/v4l2-mc.c
index 0fc185a2ce90..014a2a97cadd 100644
--- a/drivers/media/v4l2-core/v4l2-mc.c
+++ b/drivers/media/v4l2-core/v4l2-mc.c
@@ -28,7 +28,7 @@ int v4l2_mc_create_media_graph(struct media_device *mdev)
struct media_entity *io_v4l = NULL, *io_vbi = NULL, *io_swradio = NULL;
bool is_webcam = false;
u32 flags;
- int ret;
+ int ret, pad_sink, pad_source;
if (!mdev)
return 0;
@@ -63,8 +63,10 @@ int v4l2_mc_create_media_graph(struct media_device *mdev)
}
/* It should have at least one I/O entity */
- if (!io_v4l && !io_vbi && !io_swradio)
+ if (!io_v4l && !io_vbi && !io_swradio) {
+ dev_warn(mdev->dev, "Didn't find any I/O entity\n");
return -EINVAL;
+ }
/*
* Here, webcams are modelled on a very simple way: the sensor is
@@ -74,8 +76,10 @@ int v4l2_mc_create_media_graph(struct media_device *mdev)
* PC-consumer's hardware.
*/
if (is_webcam) {
- if (!io_v4l)
+ if (!io_v4l) {
+ dev_warn(mdev->dev, "Didn't find a MEDIA_ENT_F_IO_V4L\n");
return -EINVAL;
+ }
media_device_for_each_entity(entity, mdev) {
if (entity->function != MEDIA_ENT_F_CAM_SENSOR)
@@ -83,46 +87,91 @@ int v4l2_mc_create_media_graph(struct media_device *mdev)
ret = media_create_pad_link(entity, 0,
io_v4l, 0,
MEDIA_LNK_FL_ENABLED);
- if (ret)
+ if (ret) {
+ dev_warn(mdev->dev, "Failed to create a sensor link\n");
return ret;
+ }
}
if (!decoder)
return 0;
}
/* The device isn't a webcam. So, it should have a decoder */
- if (!decoder)
+ if (!decoder) {
+ dev_warn(mdev->dev, "Decoder not found\n");
return -EINVAL;
+ }
/* Link the tuner and IF video output pads */
if (tuner) {
if (if_vid) {
- ret = media_create_pad_link(tuner, TUNER_PAD_OUTPUT,
- if_vid,
- IF_VID_DEC_PAD_IF_INPUT,
+ pad_source = media_get_pad_index(tuner, false,
+ PAD_SIGNAL_ANALOG);
+ pad_sink = media_get_pad_index(if_vid, true,
+ PAD_SIGNAL_ANALOG);
+ if (pad_source < 0 || pad_sink < 0) {
+ dev_warn(mdev->dev, "Couldn't get tuner and/or PLL pad(s): (%d, %d)\n",
+ pad_source, pad_sink);
+ return -EINVAL;
+ }
+ ret = media_create_pad_link(tuner, pad_source,
+ if_vid, pad_sink,
MEDIA_LNK_FL_ENABLED);
- if (ret)
+ if (ret) {
+ dev_warn(mdev->dev, "Couldn't create tuner->PLL link)\n");
return ret;
- ret = media_create_pad_link(if_vid, IF_VID_DEC_PAD_OUT,
- decoder, DEMOD_PAD_IF_INPUT,
- MEDIA_LNK_FL_ENABLED);
- if (ret)
+ }
+
+ pad_source = media_get_pad_index(if_vid, false,
+ PAD_SIGNAL_ANALOG);
+ pad_sink = media_get_pad_index(decoder, true,
+ PAD_SIGNAL_ANALOG);
+ if (pad_source < 0 || pad_sink < 0) {
+ dev_warn(mdev->dev, "get decoder and/or PLL pad(s): (%d, %d)\n",
+ pad_source, pad_sink);
+ return -EINVAL;
+ }
+ ret = media_create_pad_link(if_vid, pad_source,
+ decoder, pad_sink,
+ MEDIA_LNK_FL_ENABLED);
+ if (ret) {
+ dev_warn(mdev->dev, "couldn't link PLL to decoder\n");
return ret;
+ }
} else {
- ret = media_create_pad_link(tuner, TUNER_PAD_OUTPUT,
- decoder, DEMOD_PAD_IF_INPUT,
- MEDIA_LNK_FL_ENABLED);
+ pad_source = media_get_pad_index(tuner, false,
+ PAD_SIGNAL_ANALOG);
+ pad_sink = media_get_pad_index(decoder, true,
+ PAD_SIGNAL_ANALOG);
+ if (pad_source < 0 || pad_sink < 0) {
+ dev_warn(mdev->dev, "couldn't get tuner and/or decoder pad(s): (%d, %d)\n",
+ pad_source, pad_sink);
+ return -EINVAL;
+ }
+ ret = media_create_pad_link(tuner, pad_source,
+ decoder, pad_sink,
+ MEDIA_LNK_FL_ENABLED);
if (ret)
return ret;
}
if (if_aud) {
- ret = media_create_pad_link(tuner, TUNER_PAD_AUD_OUT,
- if_aud,
- IF_AUD_DEC_PAD_IF_INPUT,
+ pad_source = media_get_pad_index(tuner, false,
+ PAD_SIGNAL_AUDIO);
+ pad_sink = media_get_pad_index(if_aud, true,
+ PAD_SIGNAL_AUDIO);
+ if (pad_source < 0 || pad_sink < 0) {
+ dev_warn(mdev->dev, "couldn't get tuner and/or decoder pad(s) for audio: (%d, %d)\n",
+ pad_source, pad_sink);
+ return -EINVAL;
+ }
+ ret = media_create_pad_link(tuner, pad_source,
+ if_aud, pad_sink,
MEDIA_LNK_FL_ENABLED);
- if (ret)
+ if (ret) {
+ dev_warn(mdev->dev, "couldn't link tuner->audio PLL\n");
return ret;
+ }
} else {
if_aud = tuner;
}
@@ -131,27 +180,48 @@ int v4l2_mc_create_media_graph(struct media_device *mdev)
/* Create demod to V4L, VBI and SDR radio links */
if (io_v4l) {
- ret = media_create_pad_link(decoder, DEMOD_PAD_VID_OUT,
- io_v4l, 0,
- MEDIA_LNK_FL_ENABLED);
- if (ret)
+ pad_source = media_get_pad_index(decoder, false, PAD_SIGNAL_DV);
+ if (pad_source < 0) {
+ dev_warn(mdev->dev, "couldn't get decoder output pad for V4L I/O\n");
+ return -EINVAL;
+ }
+ ret = media_create_pad_link(decoder, pad_source,
+ io_v4l, 0,
+ MEDIA_LNK_FL_ENABLED);
+ if (ret) {
+ dev_warn(mdev->dev, "couldn't link decoder output to V4L I/O\n");
return ret;
+ }
}
if (io_swradio) {
- ret = media_create_pad_link(decoder, DEMOD_PAD_VID_OUT,
- io_swradio, 0,
- MEDIA_LNK_FL_ENABLED);
- if (ret)
+ pad_source = media_get_pad_index(decoder, false, PAD_SIGNAL_DV);
+ if (pad_source < 0) {
+ dev_warn(mdev->dev, "couldn't get decoder output pad for SDR\n");
+ return -EINVAL;
+ }
+ ret = media_create_pad_link(decoder, pad_source,
+ io_swradio, 0,
+ MEDIA_LNK_FL_ENABLED);
+ if (ret) {
+ dev_warn(mdev->dev, "couldn't link decoder output to SDR\n");
return ret;
+ }
}
if (io_vbi) {
- ret = media_create_pad_link(decoder, DEMOD_PAD_VBI_OUT,
+ pad_source = media_get_pad_index(decoder, false, PAD_SIGNAL_DV);
+ if (pad_source < 0) {
+ dev_warn(mdev->dev, "couldn't get decoder output pad for VBI\n");
+ return -EINVAL;
+ }
+ ret = media_create_pad_link(decoder, pad_source,
io_vbi, 0,
MEDIA_LNK_FL_ENABLED);
- if (ret)
+ if (ret) {
+ dev_warn(mdev->dev, "couldn't link decoder output to VBI\n");
return ret;
+ }
}
/* Create links for the media connectors */
@@ -161,15 +231,26 @@ int v4l2_mc_create_media_graph(struct media_device *mdev)
case MEDIA_ENT_F_CONN_RF:
if (!tuner)
continue;
-
+ pad_sink = media_get_pad_index(tuner, true,
+ PAD_SIGNAL_ANALOG);
+ if (pad_sink < 0) {
+ dev_warn(mdev->dev, "couldn't get tuner analog pad sink\n");
+ return -EINVAL;
+ }
ret = media_create_pad_link(entity, 0, tuner,
- TUNER_PAD_RF_INPUT,
+ pad_sink,
flags);
break;
case MEDIA_ENT_F_CONN_SVIDEO:
case MEDIA_ENT_F_CONN_COMPOSITE:
+ pad_sink = media_get_pad_index(decoder, true,
+ PAD_SIGNAL_ANALOG);
+ if (pad_sink < 0) {
+ dev_warn(mdev->dev, "couldn't get tuner analog pad sink\n");
+ return -EINVAL;
+ }
ret = media_create_pad_link(entity, 0, decoder,
- DEMOD_PAD_IF_INPUT,
+ pad_sink,
flags);
break;
default:
diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c
index ce9bd1b91210..d7806db222d8 100644
--- a/drivers/media/v4l2-core/v4l2-mem2mem.c
+++ b/drivers/media/v4l2-core/v4l2-mem2mem.c
@@ -387,7 +387,7 @@ static void v4l2_m2m_cancel_job(struct v4l2_m2m_ctx *m2m_ctx)
spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
if (m2m_dev->m2m_ops->job_abort)
m2m_dev->m2m_ops->job_abort(m2m_ctx->priv);
- dprintk("m2m_ctx %p running, will wait to complete", m2m_ctx);
+ dprintk("m2m_ctx %p running, will wait to complete\n", m2m_ctx);
wait_event(m2m_ctx->finished,
!(m2m_ctx->job_flags & TRANS_RUNNING));
} else if (m2m_ctx->job_flags & TRANS_QUEUED) {
@@ -473,12 +473,19 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_querybuf);
int v4l2_m2m_qbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
struct v4l2_buffer *buf)
{
+ struct video_device *vdev = video_devdata(file);
struct vb2_queue *vq;
int ret;
vq = v4l2_m2m_get_vq(m2m_ctx, buf->type);
- ret = vb2_qbuf(vq, buf);
- if (!ret)
+ if (!V4L2_TYPE_IS_OUTPUT(vq->type) &&
+ (buf->flags & V4L2_BUF_FLAG_REQUEST_FD)) {
+ dprintk("%s: requests cannot be used with capture buffers\n",
+ __func__);
+ return -EPERM;
+ }
+ ret = vb2_qbuf(vq, vdev->v4l2_dev->mdev, buf);
+ if (!ret && !(buf->flags & V4L2_BUF_FLAG_IN_REQUEST))
v4l2_m2m_try_schedule(m2m_ctx);
return ret;
@@ -498,15 +505,11 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_dqbuf);
int v4l2_m2m_prepare_buf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
struct v4l2_buffer *buf)
{
+ struct video_device *vdev = video_devdata(file);
struct vb2_queue *vq;
- int ret;
vq = v4l2_m2m_get_vq(m2m_ctx, buf->type);
- ret = vb2_prepare_buf(vq, buf);
- if (!ret)
- v4l2_m2m_try_schedule(m2m_ctx);
-
- return ret;
+ return vb2_prepare_buf(vq, vdev->v4l2_dev->mdev, buf);
}
EXPORT_SYMBOL_GPL(v4l2_m2m_prepare_buf);
@@ -950,6 +953,52 @@ void v4l2_m2m_buf_queue(struct v4l2_m2m_ctx *m2m_ctx,
}
EXPORT_SYMBOL_GPL(v4l2_m2m_buf_queue);
+void vb2_m2m_request_queue(struct media_request *req)
+{
+ struct media_request_object *obj, *obj_safe;
+ struct v4l2_m2m_ctx *m2m_ctx = NULL;
+
+ /*
+ * Queue all objects. Note that buffer objects are at the end of the
+ * objects list, after all other object types. Once buffer objects
+ * are queued, the driver might delete them immediately (if the driver
+ * processes the buffer at once), so we have to use
+ * list_for_each_entry_safe() to handle the case where the object we
+ * queue is deleted.
+ */
+ list_for_each_entry_safe(obj, obj_safe, &req->objects, list) {
+ struct v4l2_m2m_ctx *m2m_ctx_obj;
+ struct vb2_buffer *vb;
+
+ if (!obj->ops->queue)
+ continue;
+
+ if (vb2_request_object_is_buffer(obj)) {
+ /* Sanity checks */
+ vb = container_of(obj, struct vb2_buffer, req_obj);
+ WARN_ON(!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type));
+ m2m_ctx_obj = container_of(vb->vb2_queue,
+ struct v4l2_m2m_ctx,
+ out_q_ctx.q);
+ WARN_ON(m2m_ctx && m2m_ctx_obj != m2m_ctx);
+ m2m_ctx = m2m_ctx_obj;
+ }
+
+ /*
+ * The buffer we queue here can in theory be immediately
+ * unbound, hence the use of list_for_each_entry_safe()
+ * above and why we call the queue op last.
+ */
+ obj->ops->queue(obj);
+ }
+
+ WARN_ON(!m2m_ctx);
+
+ if (m2m_ctx)
+ v4l2_m2m_try_schedule(m2m_ctx);
+}
+EXPORT_SYMBOL_GPL(vb2_m2m_request_queue);
+
/* Videobuf2 ioctl helpers */
int v4l2_m2m_ioctl_reqbufs(struct file *file, void *priv,
diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index 2b63fa6b6fc9..f5f0d71ec745 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -222,17 +222,20 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
case VIDIOC_G_EXT_CTRLS:
if (!vfh->ctrl_handler)
return -ENOTTY;
- return v4l2_g_ext_ctrls(vfh->ctrl_handler, arg);
+ return v4l2_g_ext_ctrls(vfh->ctrl_handler,
+ sd->v4l2_dev->mdev, arg);
case VIDIOC_S_EXT_CTRLS:
if (!vfh->ctrl_handler)
return -ENOTTY;
- return v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, arg);
+ return v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler,
+ sd->v4l2_dev->mdev, arg);
case VIDIOC_TRY_EXT_CTRLS:
if (!vfh->ctrl_handler)
return -ENOTTY;
- return v4l2_try_ext_ctrls(vfh->ctrl_handler, arg);
+ return v4l2_try_ext_ctrls(vfh->ctrl_handler,
+ sd->v4l2_dev->mdev, arg);
case VIDIOC_DQEVENT:
if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
@@ -273,7 +276,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
p->flags |= V4L2_CHIP_FL_WRITABLE;
if (sd->ops->core && sd->ops->core->g_register)
p->flags |= V4L2_CHIP_FL_READABLE;
- strlcpy(p->name, sd->name, sizeof(p->name));
+ strscpy(p->name, sd->name, sizeof(p->name));
return 0;
}
#endif
diff --git a/drivers/memory/atmel-ebi.c b/drivers/memory/atmel-ebi.c
index b907865d4664..c3748b414c27 100644
--- a/drivers/memory/atmel-ebi.c
+++ b/drivers/memory/atmel-ebi.c
@@ -327,8 +327,7 @@ static int atmel_ebi_dev_setup(struct atmel_ebi *ebi, struct device_node *np,
return -EINVAL;
}
- ebid = devm_kzalloc(ebi->dev,
- sizeof(*ebid) + (numcs * sizeof(*ebid->configs)),
+ ebid = devm_kzalloc(ebi->dev, struct_size(ebid, configs, numcs),
GFP_KERNEL);
if (!ebid)
return -ENOMEM;
diff --git a/drivers/memstick/core/ms_block.c b/drivers/memstick/core/ms_block.c
index 716fc8ed31d3..8a02f11076f9 100644
--- a/drivers/memstick/core/ms_block.c
+++ b/drivers/memstick/core/ms_block.c
@@ -2146,7 +2146,7 @@ static int msb_init_disk(struct memstick_dev *card)
set_disk_ro(msb->disk, 1);
msb_start(card);
- device_add_disk(&card->dev, msb->disk);
+ device_add_disk(&card->dev, msb->disk, NULL);
dbg("Disk added");
return 0;
diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c
index 5ee932631fae..0cd30dcb6801 100644
--- a/drivers/memstick/core/mspro_block.c
+++ b/drivers/memstick/core/mspro_block.c
@@ -1236,7 +1236,7 @@ static int mspro_block_init_disk(struct memstick_dev *card)
set_capacity(msb->disk, capacity);
dev_dbg(&card->dev, "capacity set %ld\n", capacity);
- device_add_disk(&card->dev, msb->disk);
+ device_add_disk(&card->dev, msb->disk, NULL);
msb->active = 1;
return 0;
diff --git a/drivers/message/fusion/lsi/mpi_cnfg.h b/drivers/message/fusion/lsi/mpi_cnfg.h
index 059997f8ebce..178f414ea8f9 100644
--- a/drivers/message/fusion/lsi/mpi_cnfg.h
+++ b/drivers/message/fusion/lsi/mpi_cnfg.h
@@ -2004,7 +2004,7 @@ typedef struct _CONFIG_PAGE_FC_PORT_6
U64 LinkFailureCount; /* 50h */
U64 LossOfSyncCount; /* 58h */
U64 LossOfSignalCount; /* 60h */
- U64 PrimativeSeqErrCount; /* 68h */
+ U64 PrimitiveSeqErrCount; /* 68h */
U64 InvalidTxWordCount; /* 70h */
U64 InvalidCrcCount; /* 78h */
U64 FcpInitiatorIoCount; /* 80h */
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index e6b4ae558767..ba551d8dfba4 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -335,11 +335,11 @@ static int mpt_remove_dead_ioc_func(void *arg)
MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg;
struct pci_dev *pdev;
- if ((ioc == NULL))
+ if (!ioc)
return -1;
pdev = ioc->pcidev;
- if ((pdev == NULL))
+ if (!pdev)
return -1;
pci_stop_and_remove_bus_device_locked(pdev);
@@ -7570,11 +7570,11 @@ mpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply)
u8 phy_num = (u8)(evData0);
u8 port_num = (u8)(evData0 >> 8);
u8 port_width = (u8)(evData0 >> 16);
- u8 primative = (u8)(evData0 >> 24);
+ u8 primitive = (u8)(evData0 >> 24);
snprintf(evStr, EVENT_DESCR_STR_SZ,
- "SAS Broadcase Primative: phy=%d port=%d "
- "width=%d primative=0x%02x",
- phy_num, port_num, port_width, primative);
+ "SAS Broadcast Primitive: phy=%d port=%d "
+ "width=%d primitive=0x%02x",
+ phy_num, port_num, port_width, primitive);
break;
}
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c
index b8cf2658649e..9b404fc69c90 100644
--- a/drivers/message/fusion/mptsas.c
+++ b/drivers/message/fusion/mptsas.c
@@ -129,7 +129,7 @@ static void mptsas_expander_delete(MPT_ADAPTER *ioc,
static void mptsas_send_expander_event(struct fw_event_work *fw_event);
static void mptsas_not_responding_devices(MPT_ADAPTER *ioc);
static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc);
-static void mptsas_broadcast_primative_work(struct fw_event_work *fw_event);
+static void mptsas_broadcast_primitive_work(struct fw_event_work *fw_event);
static void mptsas_handle_queue_full_event(struct fw_event_work *fw_event);
static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id);
void mptsas_schedule_target_reset(void *ioc);
@@ -1665,7 +1665,7 @@ mptsas_firmware_event_work(struct work_struct *work)
mptsas_free_fw_event(ioc, fw_event);
break;
case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
- mptsas_broadcast_primative_work(fw_event);
+ mptsas_broadcast_primitive_work(fw_event);
break;
case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
mptsas_send_expander_event(fw_event);
@@ -4826,13 +4826,13 @@ mptsas_issue_tm(MPT_ADAPTER *ioc, u8 type, u8 channel, u8 id, u64 lun,
}
/**
- * mptsas_broadcast_primative_work - Handle broadcast primitives
+ * mptsas_broadcast_primitive_work - Handle broadcast primitives
* @work: work queue payload containing info describing the event
*
* this will be handled in workqueue context.
*/
static void
-mptsas_broadcast_primative_work(struct fw_event_work *fw_event)
+mptsas_broadcast_primitive_work(struct fw_event_work *fw_event)
{
MPT_ADAPTER *ioc = fw_event->ioc;
MPT_FRAME_HDR *mf;
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 11841f4b7b2b..8c5dfdce4326 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -99,6 +99,15 @@ config MFD_AAT2870_CORE
additional drivers must be enabled in order to use the
functionality of the device.
+config MFD_AT91_USART
+ tristate "AT91 USART Driver"
+ select MFD_CORE
+ help
+ Select this to get support for AT91 USART IP. This is a wrapper
+ over at91-usart-serial driver and usart-spi-driver. Only one function
+ can be used at a time. The choice is done at boot time by the probe
+ function of this MFD driver according to a device tree property.
+
config MFD_ATMEL_FLEXCOM
tristate "Atmel Flexcom (Flexible Serial Communication Unit)"
select MFD_CORE
@@ -1023,16 +1032,23 @@ config MFD_RN5T618
functionality of the device.
config MFD_SEC_CORE
- bool "SAMSUNG Electronics PMIC Series Support"
+ tristate "SAMSUNG Electronics PMIC Series Support"
depends on I2C=y
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
help
- Support for the Samsung Electronics MFD series.
- This driver provides common support for accessing the device,
- additional drivers must be enabled in order to use the functionality
- of the device
+ Support for the Samsung Electronics PMIC devices coming
+ usually along with Samsung Exynos SoC chipset.
+ This driver provides common support for accessing the device,
+ additional drivers must be enabled in order to use the functionality
+ of the device
+
+ To compile this driver as a module, choose M here: the
+ module will be called sec-core.
+ Have in mind that important core drivers (like regulators) depend
+ on this driver so building this as a module might require proper
+ initial ramdisk or might not boot up as well in certain scenarios.
config MFD_SI476X_CORE
tristate "Silicon Laboratories 4761/64/68 AM/FM radio."
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 5856a9489cbd..12980a4ad460 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -196,6 +196,7 @@ obj-$(CONFIG_MFD_SPMI_PMIC) += qcom-spmi-pmic.o
obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o
obj-$(CONFIG_MFD_TPS65090) += tps65090.o
obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o
+obj-$(CONFIG_MFD_AT91_USART) += at91-usart.o
obj-$(CONFIG_MFD_ATMEL_FLEXCOM) += atmel-flexcom.o
obj-$(CONFIG_MFD_ATMEL_HLCDC) += atmel-hlcdc.o
obj-$(CONFIG_MFD_ATMEL_SMC) += atmel-smc.o
diff --git a/drivers/mfd/adp5520.c b/drivers/mfd/adp5520.c
index d817f202da5b..be0497b96720 100644
--- a/drivers/mfd/adp5520.c
+++ b/drivers/mfd/adp5520.c
@@ -360,6 +360,6 @@ static struct i2c_driver adp5520_driver = {
module_i2c_driver(adp5520_driver);
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("ADP5520(01) PMIC-MFD Driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/altera-a10sr.c b/drivers/mfd/altera-a10sr.c
index 96e7d2cb7b89..400e0b51844b 100644
--- a/drivers/mfd/altera-a10sr.c
+++ b/drivers/mfd/altera-a10sr.c
@@ -108,7 +108,8 @@ static const struct regmap_config altr_a10sr_regmap_config = {
.cache_type = REGCACHE_NONE,
- .use_single_rw = true,
+ .use_single_read = true,
+ .use_single_write = true,
.read_flag_mask = 1,
.write_flag_mask = 0,
diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c
index 5f1e37d23943..27b61639cdc7 100644
--- a/drivers/mfd/arizona-core.c
+++ b/drivers/mfd/arizona-core.c
@@ -52,8 +52,10 @@ int arizona_clk32k_enable(struct arizona *arizona)
if (ret != 0)
goto err_ref;
ret = clk_prepare_enable(arizona->mclk[ARIZONA_MCLK1]);
- if (ret != 0)
- goto err_pm;
+ if (ret != 0) {
+ pm_runtime_put_sync(arizona->dev);
+ goto err_ref;
+ }
break;
case ARIZONA_32KZ_MCLK2:
ret = clk_prepare_enable(arizona->mclk[ARIZONA_MCLK2]);
@@ -67,8 +69,6 @@ int arizona_clk32k_enable(struct arizona *arizona)
ARIZONA_CLK_32K_ENA);
}
-err_pm:
- pm_runtime_put_sync(arizona->dev);
err_ref:
if (ret != 0)
arizona->clk32k_ref--;
@@ -990,7 +990,7 @@ static const struct mfd_cell wm8998_devs[] = {
int arizona_dev_init(struct arizona *arizona)
{
- const char * const mclk_name[] = { "mclk1", "mclk2" };
+ static const char * const mclk_name[] = { "mclk1", "mclk2" };
struct device *dev = arizona->dev;
const char *type_name = NULL;
unsigned int reg, val;
diff --git a/drivers/mfd/at91-usart.c b/drivers/mfd/at91-usart.c
new file mode 100644
index 000000000000..d20747f612c1
--- /dev/null
+++ b/drivers/mfd/at91-usart.c
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for AT91 USART
+ *
+ * Copyright (C) 2018 Microchip Technology
+ *
+ * Author: Radu Pirea <radu.pirea@microchip.com>
+ *
+ */
+
+#include <dt-bindings/mfd/at91-usart.h>
+
+#include <linux/module.h>
+#include <linux/mfd/core.h>
+#include <linux/of.h>
+#include <linux/property.h>
+
+static struct mfd_cell at91_usart_spi_subdev = {
+ .name = "at91_usart_spi",
+ .of_compatible = "microchip,at91sam9g45-usart-spi",
+ };
+
+static struct mfd_cell at91_usart_serial_subdev = {
+ .name = "atmel_usart_serial",
+ .of_compatible = "atmel,at91rm9200-usart-serial",
+ };
+
+static int at91_usart_mode_probe(struct platform_device *pdev)
+{
+ struct mfd_cell cell;
+ u32 opmode = AT91_USART_MODE_SERIAL;
+
+ device_property_read_u32(&pdev->dev, "atmel,usart-mode", &opmode);
+
+ switch (opmode) {
+ case AT91_USART_MODE_SPI:
+ cell = at91_usart_spi_subdev;
+ break;
+ case AT91_USART_MODE_SERIAL:
+ cell = at91_usart_serial_subdev;
+ break;
+ default:
+ dev_err(&pdev->dev, "atmel,usart-mode has an invalid value %u\n",
+ opmode);
+ return -EINVAL;
+ }
+
+ return devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_AUTO, &cell, 1,
+ NULL, 0, NULL);
+}
+
+static const struct of_device_id at91_usart_mode_of_match[] = {
+ { .compatible = "atmel,at91rm9200-usart" },
+ { .compatible = "atmel,at91sam9260-usart" },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, at91_usart_mode_of_match);
+
+static struct platform_driver at91_usart_mfd = {
+ .probe = at91_usart_mode_probe,
+ .driver = {
+ .name = "at91_usart_mode",
+ .of_match_table = at91_usart_mode_of_match,
+ },
+};
+
+module_platform_driver(at91_usart_mfd);
+
+MODULE_AUTHOR("Radu Pirea <radu.pirea@microchip.com>");
+MODULE_DESCRIPTION("AT91 USART MFD driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c
index 65a9757a6d21..fe6f83766144 100644
--- a/drivers/mfd/cros_ec.c
+++ b/drivers/mfd/cros_ec.c
@@ -218,7 +218,8 @@ EXPORT_SYMBOL(cros_ec_suspend);
static void cros_ec_report_events_during_suspend(struct cros_ec_device *ec_dev)
{
- while (cros_ec_get_next_event(ec_dev, NULL) > 0)
+ while (ec_dev->mkbp_event_supported &&
+ cros_ec_get_next_event(ec_dev, NULL) > 0)
blocking_notifier_call_chain(&ec_dev->event_notifier,
1, ec_dev);
}
diff --git a/drivers/mfd/cros_ec_dev.c b/drivers/mfd/cros_ec_dev.c
index 999dac752bcc..8f9d6964173e 100644
--- a/drivers/mfd/cros_ec_dev.c
+++ b/drivers/mfd/cros_ec_dev.c
@@ -546,6 +546,7 @@ static struct platform_driver cros_ec_dev_driver = {
.name = DRV_NAME,
.pm = &cros_ec_dev_pm_ops,
},
+ .id_table = cros_ec_id,
.probe = ec_device_probe,
.remove = ec_device_remove,
.shutdown = ec_device_shutdown,
diff --git a/drivers/mfd/cros_ec_dev.h b/drivers/mfd/cros_ec_dev.h
index 45e9453608c5..978d836a0248 100644
--- a/drivers/mfd/cros_ec_dev.h
+++ b/drivers/mfd/cros_ec_dev.h
@@ -26,12 +26,13 @@
#define CROS_EC_DEV_VERSION "1.0.0"
-/*
- * @offset: within EC_LPC_ADDR_MEMMAP region
- * @bytes: number of bytes to read. zero means "read a string" (including '\0')
- * (at most only EC_MEMMAP_SIZE bytes can be read)
- * @buffer: where to store the result
- * ioctl returns the number of bytes read, negative on error
+/**
+ * struct cros_ec_readmem - Struct used to read mapped memory.
+ * @offset: Within EC_LPC_ADDR_MEMMAP region.
+ * @bytes: Number of bytes to read. Zero means "read a string" (including '\0')
+ * At most only EC_MEMMAP_SIZE bytes can be read.
+ * @buffer: Where to store the result. The ioctl returns the number of bytes
+ * read or negative on error.
*/
struct cros_ec_readmem {
uint32_t offset;
diff --git a/drivers/mfd/da9052-spi.c b/drivers/mfd/da9052-spi.c
index abfb11818fdc..fdae1288bc6d 100644
--- a/drivers/mfd/da9052-spi.c
+++ b/drivers/mfd/da9052-spi.c
@@ -46,7 +46,8 @@ static int da9052_spi_probe(struct spi_device *spi)
config.reg_bits = 7;
config.pad_bits = 1;
config.val_bits = 8;
- config.use_single_rw = 1;
+ config.use_single_read = true;
+ config.use_single_write = true;
da9052->regmap = devm_regmap_init_spi(spi, &config);
if (IS_ERR(da9052->regmap)) {
diff --git a/drivers/mfd/intel_msic.c b/drivers/mfd/intel_msic.c
index 2017446c5b4b..bb24c2a07900 100644
--- a/drivers/mfd/intel_msic.c
+++ b/drivers/mfd/intel_msic.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Driver for Intel MSIC
*
* Copyright (C) 2011, Intel Corporation
* Author: Mika Westerberg <mika.westerberg@linux.intel.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/err.h>
@@ -54,68 +51,44 @@ struct intel_msic {
};
static struct resource msic_touch_resources[] = {
- {
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ(0),
};
static struct resource msic_adc_resources[] = {
- {
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ(0),
};
static struct resource msic_battery_resources[] = {
- {
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ(0),
};
static struct resource msic_gpio_resources[] = {
- {
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ(0),
};
static struct resource msic_audio_resources[] = {
- {
- .name = "IRQ",
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ_NAMED(0, "IRQ"),
/*
* We will pass IRQ_BASE to the driver now but this can be removed
* when/if the driver starts to use intel_msic_irq_read().
*/
- {
- .name = "IRQ_BASE",
- .flags = IORESOURCE_MEM,
- .start = MSIC_IRQ_STATUS_ACCDET,
- .end = MSIC_IRQ_STATUS_ACCDET,
- },
+ DEFINE_RES_MEM_NAMED(MSIC_IRQ_STATUS_ACCDET, 1, "IRQ_BASE"),
};
static struct resource msic_hdmi_resources[] = {
- {
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ(0),
};
static struct resource msic_thermal_resources[] = {
- {
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ(0),
};
static struct resource msic_power_btn_resources[] = {
- {
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ(0),
};
static struct resource msic_ocd_resources[] = {
- {
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ(0),
};
/*
diff --git a/drivers/mfd/intel_soc_pmic_bxtwc.c b/drivers/mfd/intel_soc_pmic_bxtwc.c
index 15bc052704a6..6310c3bdb991 100644
--- a/drivers/mfd/intel_soc_pmic_bxtwc.c
+++ b/drivers/mfd/intel_soc_pmic_bxtwc.c
@@ -1,27 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* MFD core driver for Intel Broxton Whiskey Cove PMIC
*
* Copyright (C) 2015 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
*/
-#include <linux/module.h>
#include <linux/acpi.h>
-#include <linux/err.h>
#include <linux/delay.h>
+#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mfd/core.h>
#include <linux/mfd/intel_soc_pmic.h>
#include <linux/mfd/intel_soc_pmic_bxtwc.h>
+#include <linux/module.h>
+
#include <asm/intel_pmc_ipc.h>
/* PMIC device registers */
@@ -31,8 +24,8 @@
/* Interrupt Status Registers */
#define BXTWC_IRQLVL1 0x4E02
-#define BXTWC_PWRBTNIRQ 0x4E03
+#define BXTWC_PWRBTNIRQ 0x4E03
#define BXTWC_THRM0IRQ 0x4E04
#define BXTWC_THRM1IRQ 0x4E05
#define BXTWC_THRM2IRQ 0x4E06
@@ -47,10 +40,9 @@
/* Interrupt MASK Registers */
#define BXTWC_MIRQLVL1 0x4E0E
-#define BXTWC_MPWRTNIRQ 0x4E0F
-
#define BXTWC_MIRQLVL1_MCHGR BIT(5)
+#define BXTWC_MPWRBTNIRQ 0x4E0F
#define BXTWC_MTHRM0IRQ 0x4E12
#define BXTWC_MTHRM1IRQ 0x4E13
#define BXTWC_MTHRM2IRQ 0x4E14
@@ -66,9 +58,7 @@
/* Whiskey Cove PMIC share same ACPI ID between different platforms */
#define BROXTON_PMIC_WC_HRV 4
-/* Manage in two IRQ chips since mask registers are not consecutive */
enum bxtwc_irqs {
- /* Level 1 */
BXTWC_PWRBTN_LVL1_IRQ = 0,
BXTWC_TMU_LVL1_IRQ,
BXTWC_THRM_LVL1_IRQ,
@@ -77,9 +67,11 @@ enum bxtwc_irqs {
BXTWC_CHGR_LVL1_IRQ,
BXTWC_GPIO_LVL1_IRQ,
BXTWC_CRIT_LVL1_IRQ,
+};
- /* Level 2 */
- BXTWC_PWRBTN_IRQ,
+enum bxtwc_irqs_pwrbtn {
+ BXTWC_PWRBTN_IRQ = 0,
+ BXTWC_UIBTN_IRQ,
};
enum bxtwc_irqs_bcu {
@@ -113,7 +105,10 @@ static const struct regmap_irq bxtwc_regmap_irqs[] = {
REGMAP_IRQ_REG(BXTWC_CHGR_LVL1_IRQ, 0, BIT(5)),
REGMAP_IRQ_REG(BXTWC_GPIO_LVL1_IRQ, 0, BIT(6)),
REGMAP_IRQ_REG(BXTWC_CRIT_LVL1_IRQ, 0, BIT(7)),
- REGMAP_IRQ_REG(BXTWC_PWRBTN_IRQ, 1, 0x03),
+};
+
+static const struct regmap_irq bxtwc_regmap_irqs_pwrbtn[] = {
+ REGMAP_IRQ_REG(BXTWC_PWRBTN_IRQ, 0, 0x01),
};
static const struct regmap_irq bxtwc_regmap_irqs_bcu[] = {
@@ -125,7 +120,7 @@ static const struct regmap_irq bxtwc_regmap_irqs_adc[] = {
};
static const struct regmap_irq bxtwc_regmap_irqs_chgr[] = {
- REGMAP_IRQ_REG(BXTWC_USBC_IRQ, 0, BIT(5)),
+ REGMAP_IRQ_REG(BXTWC_USBC_IRQ, 0, 0x20),
REGMAP_IRQ_REG(BXTWC_CHGR0_IRQ, 0, 0x1f),
REGMAP_IRQ_REG(BXTWC_CHGR1_IRQ, 1, 0x1f),
};
@@ -144,7 +139,16 @@ static struct regmap_irq_chip bxtwc_regmap_irq_chip = {
.mask_base = BXTWC_MIRQLVL1,
.irqs = bxtwc_regmap_irqs,
.num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs),
- .num_regs = 2,
+ .num_regs = 1,
+};
+
+static struct regmap_irq_chip bxtwc_regmap_irq_chip_pwrbtn = {
+ .name = "bxtwc_irq_chip_pwrbtn",
+ .status_base = BXTWC_PWRBTNIRQ,
+ .mask_base = BXTWC_MPWRBTNIRQ,
+ .irqs = bxtwc_regmap_irqs_pwrbtn,
+ .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_pwrbtn),
+ .num_regs = 1,
};
static struct regmap_irq_chip bxtwc_regmap_irq_chip_tmu = {
@@ -473,6 +477,16 @@ static int bxtwc_probe(struct platform_device *pdev)
}
ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data,
+ BXTWC_PWRBTN_LVL1_IRQ,
+ IRQF_ONESHOT,
+ &bxtwc_regmap_irq_chip_pwrbtn,
+ &pmic->irq_chip_data_pwrbtn);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to add PWRBTN IRQ chip\n");
+ return ret;
+ }
+
+ ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data,
BXTWC_TMU_LVL1_IRQ,
IRQF_ONESHOT,
&bxtwc_regmap_irq_chip_tmu,
diff --git a/drivers/mfd/intel_soc_pmic_chtdc_ti.c b/drivers/mfd/intel_soc_pmic_chtdc_ti.c
index 861277c6580a..64b5c3cc30e7 100644
--- a/drivers/mfd/intel_soc_pmic_chtdc_ti.c
+++ b/drivers/mfd/intel_soc_pmic_chtdc_ti.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Device access for Dollar Cove TI PMIC
*
@@ -6,10 +7,6 @@
*
* Cleanup and forward-ported
* Copyright (c) 2017 Takashi Iwai <tiwai@suse.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/acpi.h>
diff --git a/drivers/mfd/intel_soc_pmic_chtwc.c b/drivers/mfd/intel_soc_pmic_chtwc.c
index b35da01d5bcf..64a3aece9c5e 100644
--- a/drivers/mfd/intel_soc_pmic_chtwc.c
+++ b/drivers/mfd/intel_soc_pmic_chtwc.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* MFD core driver for Intel Cherrytrail Whiskey Cove PMIC
*
@@ -5,10 +6,6 @@
*
* Based on various non upstream patches to support the CHT Whiskey Cove PMIC:
* Copyright (C) 2013-2015 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/acpi.h>
diff --git a/drivers/mfd/intel_soc_pmic_core.c b/drivers/mfd/intel_soc_pmic_core.c
index 274306d98ac1..c9f35378d391 100644
--- a/drivers/mfd/intel_soc_pmic_core.c
+++ b/drivers/mfd/intel_soc_pmic_core.c
@@ -1,31 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0
/*
- * intel_soc_pmic_core.c - Intel SoC PMIC MFD Driver
+ * Intel SoC PMIC MFD Driver
*
* Copyright (C) 2013, 2014 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.
- *
* Author: Yang, Bin <bin.yang@intel.com>
* Author: Zhu, Lejun <lejun.zhu@linux.intel.com>
*/
-#include <linux/module.h>
-#include <linux/mfd/core.h>
+#include <linux/acpi.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/machine.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
-#include <linux/gpio/consumer.h>
-#include <linux/acpi.h>
-#include <linux/regmap.h>
+#include <linux/module.h>
+#include <linux/mfd/core.h>
#include <linux/mfd/intel_soc_pmic.h>
-#include <linux/gpio/machine.h>
#include <linux/pwm.h>
+#include <linux/regmap.h>
+
#include "intel_soc_pmic_core.h"
/* Crystal Cove PMIC shares same ACPI ID between different platforms */
diff --git a/drivers/mfd/intel_soc_pmic_core.h b/drivers/mfd/intel_soc_pmic_core.h
index 90a1416d4dac..d490685845eb 100644
--- a/drivers/mfd/intel_soc_pmic_core.h
+++ b/drivers/mfd/intel_soc_pmic_core.h
@@ -1,17 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
- * intel_soc_pmic_core.h - Intel SoC PMIC MFD Driver
+ * Intel SoC PMIC MFD Driver
*
* Copyright (C) 2012-2014 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.
- *
* Author: Yang, Bin <bin.yang@intel.com>
* Author: Zhu, Lejun <lejun.zhu@linux.intel.com>
*/
diff --git a/drivers/mfd/intel_soc_pmic_crc.c b/drivers/mfd/intel_soc_pmic_crc.c
index 6d19a6d0fb97..b6ab72fa0569 100644
--- a/drivers/mfd/intel_soc_pmic_crc.c
+++ b/drivers/mfd/intel_soc_pmic_crc.c
@@ -1,25 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0
/*
- * intel_soc_pmic_crc.c - Device access for Crystal Cove PMIC
+ * Device access for Crystal Cove PMIC
*
* Copyright (C) 2013, 2014 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.
- *
* Author: Yang, Bin <bin.yang@intel.com>
* Author: Zhu, Lejun <lejun.zhu@linux.intel.com>
*/
-#include <linux/mfd/core.h>
#include <linux/interrupt.h>
#include <linux/regmap.h>
+#include <linux/mfd/core.h>
#include <linux/mfd/intel_soc_pmic.h>
+
#include "intel_soc_pmic_core.h"
#define CRYSTAL_COVE_MAX_REGISTER 0xC6
@@ -36,48 +29,23 @@
#define CRYSTAL_COVE_IRQ_VHDMIOCP 6
static struct resource gpio_resources[] = {
- {
- .name = "GPIO",
- .start = CRYSTAL_COVE_IRQ_GPIO,
- .end = CRYSTAL_COVE_IRQ_GPIO,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_GPIO, "GPIO"),
};
static struct resource pwrsrc_resources[] = {
- {
- .name = "PWRSRC",
- .start = CRYSTAL_COVE_IRQ_PWRSRC,
- .end = CRYSTAL_COVE_IRQ_PWRSRC,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_PWRSRC, "PWRSRC"),
};
static struct resource adc_resources[] = {
- {
- .name = "ADC",
- .start = CRYSTAL_COVE_IRQ_ADC,
- .end = CRYSTAL_COVE_IRQ_ADC,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_ADC, "ADC"),
};
static struct resource thermal_resources[] = {
- {
- .name = "THERMAL",
- .start = CRYSTAL_COVE_IRQ_THRM,
- .end = CRYSTAL_COVE_IRQ_THRM,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_THRM, "THERMAL"),
};
static struct resource bcu_resources[] = {
- {
- .name = "BCU",
- .start = CRYSTAL_COVE_IRQ_BCU,
- .end = CRYSTAL_COVE_IRQ_BCU,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_BCU, "BCU"),
};
static struct mfd_cell crystal_cove_byt_dev[] = {
@@ -134,27 +102,13 @@ static const struct regmap_config crystal_cove_regmap_config = {
};
static const struct regmap_irq crystal_cove_irqs[] = {
- [CRYSTAL_COVE_IRQ_PWRSRC] = {
- .mask = BIT(CRYSTAL_COVE_IRQ_PWRSRC),
- },
- [CRYSTAL_COVE_IRQ_THRM] = {
- .mask = BIT(CRYSTAL_COVE_IRQ_THRM),
- },
- [CRYSTAL_COVE_IRQ_BCU] = {
- .mask = BIT(CRYSTAL_COVE_IRQ_BCU),
- },
- [CRYSTAL_COVE_IRQ_ADC] = {
- .mask = BIT(CRYSTAL_COVE_IRQ_ADC),
- },
- [CRYSTAL_COVE_IRQ_CHGR] = {
- .mask = BIT(CRYSTAL_COVE_IRQ_CHGR),
- },
- [CRYSTAL_COVE_IRQ_GPIO] = {
- .mask = BIT(CRYSTAL_COVE_IRQ_GPIO),
- },
- [CRYSTAL_COVE_IRQ_VHDMIOCP] = {
- .mask = BIT(CRYSTAL_COVE_IRQ_VHDMIOCP),
- },
+ REGMAP_IRQ_REG(CRYSTAL_COVE_IRQ_PWRSRC, 0, BIT(CRYSTAL_COVE_IRQ_PWRSRC)),
+ REGMAP_IRQ_REG(CRYSTAL_COVE_IRQ_THRM, 0, BIT(CRYSTAL_COVE_IRQ_THRM)),
+ REGMAP_IRQ_REG(CRYSTAL_COVE_IRQ_BCU, 0, BIT(CRYSTAL_COVE_IRQ_BCU)),
+ REGMAP_IRQ_REG(CRYSTAL_COVE_IRQ_ADC, 0, BIT(CRYSTAL_COVE_IRQ_ADC)),
+ REGMAP_IRQ_REG(CRYSTAL_COVE_IRQ_CHGR, 0, BIT(CRYSTAL_COVE_IRQ_CHGR)),
+ REGMAP_IRQ_REG(CRYSTAL_COVE_IRQ_GPIO, 0, BIT(CRYSTAL_COVE_IRQ_GPIO)),
+ REGMAP_IRQ_REG(CRYSTAL_COVE_IRQ_VHDMIOCP, 0, BIT(CRYSTAL_COVE_IRQ_VHDMIOCP)),
};
static const struct regmap_irq_chip crystal_cove_irq_chip = {
diff --git a/drivers/mfd/madera-core.c b/drivers/mfd/madera-core.c
index 8cfea969b060..440030cecbbd 100644
--- a/drivers/mfd/madera-core.c
+++ b/drivers/mfd/madera-core.c
@@ -132,32 +132,39 @@ const char *madera_name_from_type(enum madera_type type)
}
EXPORT_SYMBOL_GPL(madera_name_from_type);
-#define MADERA_BOOT_POLL_MAX_INTERVAL_US 5000
-#define MADERA_BOOT_POLL_TIMEOUT_US 25000
+#define MADERA_BOOT_POLL_INTERVAL_USEC 5000
+#define MADERA_BOOT_POLL_TIMEOUT_USEC 25000
static int madera_wait_for_boot(struct madera *madera)
{
+ ktime_t timeout;
unsigned int val;
- int ret;
+ int ret = 0;
/*
* We can't use an interrupt as we need to runtime resume to do so,
* so we poll the status bit. This won't race with the interrupt
* handler because it will be blocked on runtime resume.
+ * The chip could NAK a read request while it is booting so ignore
+ * errors from regmap_read.
*/
- ret = regmap_read_poll_timeout(madera->regmap,
- MADERA_IRQ1_RAW_STATUS_1,
- val,
- (val & MADERA_BOOT_DONE_STS1),
- MADERA_BOOT_POLL_MAX_INTERVAL_US,
- MADERA_BOOT_POLL_TIMEOUT_US);
-
- if (ret)
- dev_err(madera->dev, "Polling BOOT_DONE_STS failed: %d\n", ret);
+ timeout = ktime_add_us(ktime_get(), MADERA_BOOT_POLL_TIMEOUT_USEC);
+ regmap_read(madera->regmap, MADERA_IRQ1_RAW_STATUS_1, &val);
+ while (!(val & MADERA_BOOT_DONE_STS1) &&
+ !ktime_after(ktime_get(), timeout)) {
+ usleep_range(MADERA_BOOT_POLL_INTERVAL_USEC / 2,
+ MADERA_BOOT_POLL_INTERVAL_USEC);
+ regmap_read(madera->regmap, MADERA_IRQ1_RAW_STATUS_1, &val);
+ };
+
+ if (!(val & MADERA_BOOT_DONE_STS1)) {
+ dev_err(madera->dev, "Polling BOOT_DONE_STS timed out\n");
+ ret = -ETIMEDOUT;
+ }
/*
* BOOT_DONE defaults to unmasked on boot so we must ack it.
- * Do this unconditionally to avoid interrupt storms.
+ * Do this even after a timeout to avoid interrupt storms.
*/
regmap_write(madera->regmap, MADERA_IRQ1_STATUS_1,
MADERA_BOOT_DONE_EINT1);
diff --git a/drivers/mfd/max14577.c b/drivers/mfd/max14577.c
index 6cbe96b28f42..ebb13d5de530 100644
--- a/drivers/mfd/max14577.c
+++ b/drivers/mfd/max14577.c
@@ -1,22 +1,12 @@
-/*
- * max14577.c - mfd core driver for the Maxim 14577/77836
- *
- * Copyright (C) 2014 Samsung Electronics
- * Chanwoo Choi <cw00.choi@samsung.com>
- * Krzysztof Kozlowski <krzk@kernel.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 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.
- *
- * This driver is based on max8997.c
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// max14577.c - mfd core driver for the Maxim 14577/77836
+//
+// Copyright (C) 2014 Samsung Electronics
+// Chanwoo Choi <cw00.choi@samsung.com>
+// Krzysztof Kozlowski <krzk@kernel.org>
+//
+// This driver is based on max8997.c
#include <linux/err.h>
#include <linux/module.h>
diff --git a/drivers/mfd/max77620.c b/drivers/mfd/max77620.c
index b1700b5fa640..d8217366ed36 100644
--- a/drivers/mfd/max77620.c
+++ b/drivers/mfd/max77620.c
@@ -285,7 +285,7 @@ static int max77620_config_fps(struct max77620_chip *chip,
}
if (fps_id == MAX77620_FPS_COUNT) {
- dev_err(dev, "FPS node name %s is not valid\n", fps_np->name);
+ dev_err(dev, "FPS node name %pOFn is not valid\n", fps_np);
return -EINVAL;
}
diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c
index b0e8e13c0049..71faf503844b 100644
--- a/drivers/mfd/max77686.c
+++ b/drivers/mfd/max77686.c
@@ -1,26 +1,12 @@
-/*
- * max77686.c - mfd core driver for the Maxim 77686/802
- *
- * Copyright (C) 2012 Samsung Electronics
- * Chiwoong Byun <woong.byun@samsung.com>
- * Jonghwa Lee <jonghwa3.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * This driver is based on max8997.c
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// max77686.c - mfd core driver for the Maxim 77686/802
+//
+// Copyright (C) 2012 Samsung Electronics
+// Chiwoong Byun <woong.byun@samsung.com>
+// Jonghwa Lee <jonghwa3.lee@samsung.com>
+//
+//This driver is based on max8997.c
#include <linux/export.h>
#include <linux/slab.h>
diff --git a/drivers/mfd/max77693.c b/drivers/mfd/max77693.c
index 1c05ea0cba61..901d99d65924 100644
--- a/drivers/mfd/max77693.c
+++ b/drivers/mfd/max77693.c
@@ -1,27 +1,13 @@
-/*
- * max77693.c - mfd core driver for the MAX 77693
- *
- * Copyright (C) 2012 Samsung Electronics
- * SangYoung Son <hello.son@samsung.com>
- *
- * This program is not provided / owned by Maxim Integrated Products.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * This driver is based on max8997.c
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// max77693.c - mfd core driver for the MAX 77693
+//
+// Copyright (C) 2012 Samsung Electronics
+// SangYoung Son <hello.son@samsung.com>
+//
+// This program is not provided / owned by Maxim Integrated Products.
+//
+// This driver is based on max8997.c
#include <linux/module.h>
#include <linux/slab.h>
diff --git a/drivers/mfd/max77843.c b/drivers/mfd/max77843.c
index da9612dbb222..25cbb2242b26 100644
--- a/drivers/mfd/max77843.c
+++ b/drivers/mfd/max77843.c
@@ -1,15 +1,10 @@
-/*
- * MFD core driver for the Maxim MAX77843
- *
- * Copyright (C) 2015 Samsung Electronics
- * Author: Jaewon Kim <jaewon02.kim@samsung.com>
- * Author: Beomho Seo <beomho.seo@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// MFD core driver for the Maxim MAX77843
+//
+// Copyright (C) 2015 Samsung Electronics
+// Author: Jaewon Kim <jaewon02.kim@samsung.com>
+// Author: Beomho Seo <beomho.seo@samsung.com>
#include <linux/err.h>
#include <linux/i2c.h>
diff --git a/drivers/mfd/max8997-irq.c b/drivers/mfd/max8997-irq.c
index 326f17b632a7..93a3b1698d9c 100644
--- a/drivers/mfd/max8997-irq.c
+++ b/drivers/mfd/max8997-irq.c
@@ -1,25 +1,11 @@
-/*
- * max8997-irq.c - Interrupt controller support for MAX8997
- *
- * Copyright (C) 2011 Samsung Electronics Co.Ltd
- * MyungJoo Ham <myungjoo.ham@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * This driver is based on max8998-irq.c
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// max8997-irq.c - Interrupt controller support for MAX8997
+//
+// Copyright (C) 2011 Samsung Electronics Co.Ltd
+// MyungJoo Ham <myungjoo.ham@samsung.com>
+//
+// This driver is based on max8998-irq.c
#include <linux/err.h>
#include <linux/irq.h>
diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c
index 3f554c447521..8c06c09e36d1 100644
--- a/drivers/mfd/max8997.c
+++ b/drivers/mfd/max8997.c
@@ -1,25 +1,11 @@
-/*
- * max8997.c - mfd core driver for the Maxim 8966 and 8997
- *
- * Copyright (C) 2011 Samsung Electronics
- * MyungJoo Ham <myungjoo.ham@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * This driver is based on max8998.c
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// max8997.c - mfd core driver for the Maxim 8966 and 8997
+//
+// Copyright (C) 2011 Samsung Electronics
+// MyungJoo Ham <myungjoo.ham@samsung.com>
+//
+// This driver is based on max8998.c
#include <linux/err.h>
#include <linux/slab.h>
@@ -153,12 +139,6 @@ static struct max8997_platform_data *max8997_i2c_parse_dt_pdata(
pd->ono = irq_of_parse_and_map(dev->of_node, 1);
- /*
- * 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.
- */
-
return pd;
}
@@ -246,7 +226,7 @@ static int max8997_i2c_probe(struct i2c_client *i2c,
*/
/* MAX8997 has a power button input. */
- device_init_wakeup(max8997->dev, pdata->wakeup);
+ device_init_wakeup(max8997->dev, true);
return ret;
@@ -468,6 +448,7 @@ static int max8997_suspend(struct device *dev)
struct i2c_client *i2c = to_i2c_client(dev);
struct max8997_dev *max8997 = i2c_get_clientdata(i2c);
+ disable_irq(max8997->irq);
if (device_may_wakeup(dev))
irq_set_irq_wake(max8997->irq, 1);
return 0;
@@ -480,6 +461,7 @@ static int max8997_resume(struct device *dev)
if (device_may_wakeup(dev))
irq_set_irq_wake(max8997->irq, 0);
+ enable_irq(max8997->irq);
return max8997_irq_resume(max8997);
}
diff --git a/drivers/mfd/max8998-irq.c b/drivers/mfd/max8998-irq.c
index 90bad9ffa7e2..83b6f510bc05 100644
--- a/drivers/mfd/max8998-irq.c
+++ b/drivers/mfd/max8998-irq.c
@@ -1,15 +1,9 @@
-/*
- * Interrupt controller support for MAX8998
- *
- * Copyright (C) 2010 Samsung Electronics Co.Ltd
- * Author: Joonyoung Shim <jy0922.shim@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Interrupt controller support for MAX8998
+//
+// Copyright (C) 2010 Samsung Electronics Co.Ltd
+// Author: Joonyoung Shim <jy0922.shim@samsung.com>
#include <linux/device.h>
#include <linux/interrupt.h>
diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c
index b1d3f70782d9..56409df120f8 100644
--- a/drivers/mfd/max8998.c
+++ b/drivers/mfd/max8998.c
@@ -1,24 +1,10 @@
-/*
- * max8998.c - mfd core driver for the Maxim 8998
- *
- * Copyright (C) 2009-2010 Samsung Electronics
- * Kyungmin Park <kyungmin.park@samsung.com>
- * Marek Szyprowski <m.szyprowski@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// max8998.c - mfd core driver for the Maxim 8998
+//
+// Copyright (C) 2009-2010 Samsung Electronics
+// Kyungmin Park <kyungmin.park@samsung.com>
+// Marek Szyprowski <m.szyprowski@samsung.com>
#include <linux/err.h>
#include <linux/init.h>
diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c
index c63e331738c1..f475e848252f 100644
--- a/drivers/mfd/mc13xxx-core.c
+++ b/drivers/mfd/mc13xxx-core.c
@@ -276,7 +276,8 @@ int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode,
mc13xxx_reg_read(mc13xxx, MC13XXX_ADC0, &old_adc0);
- adc0 = MC13XXX_ADC0_ADINC1 | MC13XXX_ADC0_ADINC2;
+ adc0 = MC13XXX_ADC0_ADINC1 | MC13XXX_ADC0_ADINC2 |
+ MC13XXX_ADC0_CHRGRAWDIV;
adc1 = MC13XXX_ADC1_ADEN | MC13XXX_ADC1_ADTRIGIGN | MC13XXX_ADC1_ASC;
/*
diff --git a/drivers/mfd/mc13xxx-spi.c b/drivers/mfd/mc13xxx-spi.c
index cbc1e5ed599c..ee3411cc5ce4 100644
--- a/drivers/mfd/mc13xxx-spi.c
+++ b/drivers/mfd/mc13xxx-spi.c
@@ -57,7 +57,8 @@ static const struct regmap_config mc13xxx_regmap_spi_config = {
.max_register = MC13XXX_NUMREGS,
.cache_type = REGCACHE_NONE,
- .use_single_rw = 1,
+ .use_single_read = true,
+ .use_single_write = true,
};
static int mc13xxx_spi_read(void *context, const void *reg, size_t reg_size,
diff --git a/drivers/mfd/menelaus.c b/drivers/mfd/menelaus.c
index 29b7164a823b..d28ebe7ecd21 100644
--- a/drivers/mfd/menelaus.c
+++ b/drivers/mfd/menelaus.c
@@ -1094,6 +1094,7 @@ static void menelaus_rtc_alarm_work(struct menelaus_chip *m)
static inline void menelaus_rtc_init(struct menelaus_chip *m)
{
int alarm = (m->client->irq > 0);
+ int err;
/* assume 32KDETEN pin is pulled high */
if (!(menelaus_read_reg(MENELAUS_OSC_CTRL) & 0x80)) {
@@ -1101,6 +1102,12 @@ static inline void menelaus_rtc_init(struct menelaus_chip *m)
return;
}
+ m->rtc = devm_rtc_allocate_device(&m->client->dev);
+ if (IS_ERR(m->rtc))
+ return;
+
+ m->rtc->ops = &menelaus_rtc_ops;
+
/* support RTC alarm; it can issue wakeups */
if (alarm) {
if (menelaus_add_irq_work(MENELAUS_RTCALM_IRQ,
@@ -1125,10 +1132,8 @@ static inline void menelaus_rtc_init(struct menelaus_chip *m)
menelaus_write_reg(MENELAUS_RTC_CTRL, m->rtc_control);
}
- m->rtc = rtc_device_register(DRIVER_NAME,
- &m->client->dev,
- &menelaus_rtc_ops, THIS_MODULE);
- if (IS_ERR(m->rtc)) {
+ err = rtc_register_device(m->rtc);
+ if (err) {
if (alarm) {
menelaus_remove_irq_work(MENELAUS_RTCALM_IRQ);
device_init_wakeup(&m->client->dev, 0);
diff --git a/drivers/mfd/motorola-cpcap.c b/drivers/mfd/motorola-cpcap.c
index 5276911caaec..20d9692640e1 100644
--- a/drivers/mfd/motorola-cpcap.c
+++ b/drivers/mfd/motorola-cpcap.c
@@ -18,6 +18,7 @@
#include <linux/regmap.h>
#include <linux/sysfs.h>
+#include <linux/mfd/core.h>
#include <linux/mfd/motorola-cpcap.h>
#include <linux/spi/spi.h>
@@ -216,6 +217,53 @@ static const struct regmap_config cpcap_regmap_config = {
.val_format_endian = REGMAP_ENDIAN_LITTLE,
};
+static const struct mfd_cell cpcap_mfd_devices[] = {
+ {
+ .name = "cpcap_adc",
+ .of_compatible = "motorola,mapphone-cpcap-adc",
+ }, {
+ .name = "cpcap_battery",
+ .of_compatible = "motorola,cpcap-battery",
+ }, {
+ .name = "cpcap-charger",
+ .of_compatible = "motorola,mapphone-cpcap-charger",
+ }, {
+ .name = "cpcap-regulator",
+ .of_compatible = "motorola,mapphone-cpcap-regulator",
+ }, {
+ .name = "cpcap-rtc",
+ .of_compatible = "motorola,cpcap-rtc",
+ }, {
+ .name = "cpcap-pwrbutton",
+ .of_compatible = "motorola,cpcap-pwrbutton",
+ }, {
+ .name = "cpcap-usb-phy",
+ .of_compatible = "motorola,mapphone-cpcap-usb-phy",
+ }, {
+ .name = "cpcap-led",
+ .id = 0,
+ .of_compatible = "motorola,cpcap-led-red",
+ }, {
+ .name = "cpcap-led",
+ .id = 1,
+ .of_compatible = "motorola,cpcap-led-green",
+ }, {
+ .name = "cpcap-led",
+ .id = 2,
+ .of_compatible = "motorola,cpcap-led-blue",
+ }, {
+ .name = "cpcap-led",
+ .id = 3,
+ .of_compatible = "motorola,cpcap-led-adl",
+ }, {
+ .name = "cpcap-led",
+ .id = 4,
+ .of_compatible = "motorola,cpcap-led-cp",
+ }, {
+ .name = "cpcap-codec",
+ }
+};
+
static int cpcap_probe(struct spi_device *spi)
{
const struct of_device_id *match;
@@ -260,7 +308,8 @@ static int cpcap_probe(struct spi_device *spi)
if (ret)
return ret;
- return devm_of_platform_populate(&cpcap->spi->dev);
+ return devm_mfd_add_devices(&spi->dev, 0, cpcap_mfd_devices,
+ ARRAY_SIZE(cpcap_mfd_devices), NULL, 0, NULL);
}
static struct spi_driver cpcap_driver = {
diff --git a/drivers/mfd/rohm-bd718x7.c b/drivers/mfd/rohm-bd718x7.c
index 75c8ec659547..a29d529a96f4 100644
--- a/drivers/mfd/rohm-bd718x7.c
+++ b/drivers/mfd/rohm-bd718x7.c
@@ -2,26 +2,21 @@
//
// Copyright (C) 2018 ROHM Semiconductors
//
-// ROHM BD71837MWV PMIC driver
+// ROHM BD71837MWV and BD71847MWV PMIC driver
//
-// Datasheet available from
+// Datasheet for BD71837MWV available from
// https://www.rohm.com/datasheet/BD71837MWV/bd71837mwv-e
+#include <linux/gpio_keys.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/mfd/rohm-bd718x7.h>
#include <linux/mfd/core.h>
#include <linux/module.h>
+#include <linux/of_device.h>
#include <linux/regmap.h>
-
-/*
- * gpio_keys.h requires definiton of bool. It is brought in
- * by above includes. Keep this as last until gpio_keys.h gets fixed.
- */
-#include <linux/gpio_keys.h>
-
-static const u8 supported_revisions[] = { 0xA2 /* BD71837 */ };
+#include <linux/types.h>
static struct gpio_keys_button button = {
.code = KEY_POWER,
@@ -35,42 +30,42 @@ static struct gpio_keys_platform_data bd718xx_powerkey_data = {
.name = "bd718xx-pwrkey",
};
-static struct mfd_cell bd71837_mfd_cells[] = {
+static struct mfd_cell bd718xx_mfd_cells[] = {
{
.name = "gpio-keys",
.platform_data = &bd718xx_powerkey_data,
.pdata_size = sizeof(bd718xx_powerkey_data),
},
- { .name = "bd71837-clk", },
- { .name = "bd71837-pmic", },
+ { .name = "bd718xx-clk", },
+ { .name = "bd718xx-pmic", },
};
-static const struct regmap_irq bd71837_irqs[] = {
- REGMAP_IRQ_REG(BD71837_INT_SWRST, 0, BD71837_INT_SWRST_MASK),
- REGMAP_IRQ_REG(BD71837_INT_PWRBTN_S, 0, BD71837_INT_PWRBTN_S_MASK),
- REGMAP_IRQ_REG(BD71837_INT_PWRBTN_L, 0, BD71837_INT_PWRBTN_L_MASK),
- REGMAP_IRQ_REG(BD71837_INT_PWRBTN, 0, BD71837_INT_PWRBTN_MASK),
- REGMAP_IRQ_REG(BD71837_INT_WDOG, 0, BD71837_INT_WDOG_MASK),
- REGMAP_IRQ_REG(BD71837_INT_ON_REQ, 0, BD71837_INT_ON_REQ_MASK),
- REGMAP_IRQ_REG(BD71837_INT_STBY_REQ, 0, BD71837_INT_STBY_REQ_MASK),
+static const struct regmap_irq bd718xx_irqs[] = {
+ REGMAP_IRQ_REG(BD718XX_INT_SWRST, 0, BD718XX_INT_SWRST_MASK),
+ REGMAP_IRQ_REG(BD718XX_INT_PWRBTN_S, 0, BD718XX_INT_PWRBTN_S_MASK),
+ REGMAP_IRQ_REG(BD718XX_INT_PWRBTN_L, 0, BD718XX_INT_PWRBTN_L_MASK),
+ REGMAP_IRQ_REG(BD718XX_INT_PWRBTN, 0, BD718XX_INT_PWRBTN_MASK),
+ REGMAP_IRQ_REG(BD718XX_INT_WDOG, 0, BD718XX_INT_WDOG_MASK),
+ REGMAP_IRQ_REG(BD718XX_INT_ON_REQ, 0, BD718XX_INT_ON_REQ_MASK),
+ REGMAP_IRQ_REG(BD718XX_INT_STBY_REQ, 0, BD718XX_INT_STBY_REQ_MASK),
};
-static struct regmap_irq_chip bd71837_irq_chip = {
- .name = "bd71837-irq",
- .irqs = bd71837_irqs,
- .num_irqs = ARRAY_SIZE(bd71837_irqs),
+static struct regmap_irq_chip bd718xx_irq_chip = {
+ .name = "bd718xx-irq",
+ .irqs = bd718xx_irqs,
+ .num_irqs = ARRAY_SIZE(bd718xx_irqs),
.num_regs = 1,
.irq_reg_stride = 1,
- .status_base = BD71837_REG_IRQ,
- .mask_base = BD71837_REG_MIRQ,
- .ack_base = BD71837_REG_IRQ,
+ .status_base = BD718XX_REG_IRQ,
+ .mask_base = BD718XX_REG_MIRQ,
+ .ack_base = BD718XX_REG_IRQ,
.init_ack_masked = true,
.mask_invert = false,
};
static const struct regmap_range pmic_status_range = {
- .range_min = BD71837_REG_IRQ,
- .range_max = BD71837_REG_POW_STATE,
+ .range_min = BD718XX_REG_IRQ,
+ .range_max = BD718XX_REG_POW_STATE,
};
static const struct regmap_access_table volatile_regs = {
@@ -78,67 +73,53 @@ static const struct regmap_access_table volatile_regs = {
.n_yes_ranges = 1,
};
-static const struct regmap_config bd71837_regmap_config = {
+static const struct regmap_config bd718xx_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.volatile_table = &volatile_regs,
- .max_register = BD71837_MAX_REGISTER - 1,
+ .max_register = BD718XX_MAX_REGISTER - 1,
.cache_type = REGCACHE_RBTREE,
};
-static int bd71837_i2c_probe(struct i2c_client *i2c,
+static int bd718xx_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
- struct bd71837 *bd71837;
- int ret, i;
- unsigned int val;
-
- bd71837 = devm_kzalloc(&i2c->dev, sizeof(struct bd71837), GFP_KERNEL);
+ struct bd718xx *bd718xx;
+ int ret;
- if (!bd71837)
- return -ENOMEM;
-
- bd71837->chip_irq = i2c->irq;
-
- if (!bd71837->chip_irq) {
+ if (!i2c->irq) {
dev_err(&i2c->dev, "No IRQ configured\n");
return -EINVAL;
}
- bd71837->dev = &i2c->dev;
- dev_set_drvdata(&i2c->dev, bd71837);
+ bd718xx = devm_kzalloc(&i2c->dev, sizeof(struct bd718xx), GFP_KERNEL);
- bd71837->regmap = devm_regmap_init_i2c(i2c, &bd71837_regmap_config);
- if (IS_ERR(bd71837->regmap)) {
- dev_err(&i2c->dev, "regmap initialization failed\n");
- return PTR_ERR(bd71837->regmap);
- }
+ if (!bd718xx)
+ return -ENOMEM;
- ret = regmap_read(bd71837->regmap, BD71837_REG_REV, &val);
- if (ret) {
- dev_err(&i2c->dev, "Read BD71837_REG_DEVICE failed\n");
- return ret;
- }
- for (i = 0; i < ARRAY_SIZE(supported_revisions); i++)
- if (supported_revisions[i] == val)
- break;
+ bd718xx->chip_irq = i2c->irq;
+ bd718xx->chip_type = (unsigned int)(uintptr_t)
+ of_device_get_match_data(&i2c->dev);
+ bd718xx->dev = &i2c->dev;
+ dev_set_drvdata(&i2c->dev, bd718xx);
- if (i == ARRAY_SIZE(supported_revisions)) {
- dev_err(&i2c->dev, "Unsupported chip revision\n");
- return -ENODEV;
+ bd718xx->regmap = devm_regmap_init_i2c(i2c, &bd718xx_regmap_config);
+ if (IS_ERR(bd718xx->regmap)) {
+ dev_err(&i2c->dev, "regmap initialization failed\n");
+ return PTR_ERR(bd718xx->regmap);
}
- ret = devm_regmap_add_irq_chip(&i2c->dev, bd71837->regmap,
- bd71837->chip_irq, IRQF_ONESHOT, 0,
- &bd71837_irq_chip, &bd71837->irq_data);
+ ret = devm_regmap_add_irq_chip(&i2c->dev, bd718xx->regmap,
+ bd718xx->chip_irq, IRQF_ONESHOT, 0,
+ &bd718xx_irq_chip, &bd718xx->irq_data);
if (ret) {
dev_err(&i2c->dev, "Failed to add irq_chip\n");
return ret;
}
/* Configure short press to 10 milliseconds */
- ret = regmap_update_bits(bd71837->regmap,
- BD71837_REG_PWRONCONFIG0,
+ ret = regmap_update_bits(bd718xx->regmap,
+ BD718XX_REG_PWRONCONFIG0,
BD718XX_PWRBTN_PRESS_DURATION_MASK,
BD718XX_PWRBTN_SHORT_PRESS_10MS);
if (ret) {
@@ -148,8 +129,8 @@ static int bd71837_i2c_probe(struct i2c_client *i2c,
}
/* Configure long press to 10 seconds */
- ret = regmap_update_bits(bd71837->regmap,
- BD71837_REG_PWRONCONFIG1,
+ ret = regmap_update_bits(bd718xx->regmap,
+ BD718XX_REG_PWRONCONFIG1,
BD718XX_PWRBTN_PRESS_DURATION_MASK,
BD718XX_PWRBTN_LONG_PRESS_10S);
@@ -159,7 +140,7 @@ static int bd71837_i2c_probe(struct i2c_client *i2c,
return ret;
}
- ret = regmap_irq_get_virq(bd71837->irq_data, BD71837_INT_PWRBTN_S);
+ ret = regmap_irq_get_virq(bd718xx->irq_data, BD718XX_INT_PWRBTN_S);
if (ret < 0) {
dev_err(&i2c->dev, "Failed to get the IRQ\n");
@@ -168,44 +149,51 @@ static int bd71837_i2c_probe(struct i2c_client *i2c,
button.irq = ret;
- ret = devm_mfd_add_devices(bd71837->dev, PLATFORM_DEVID_AUTO,
- bd71837_mfd_cells,
- ARRAY_SIZE(bd71837_mfd_cells), NULL, 0,
- regmap_irq_get_domain(bd71837->irq_data));
+ ret = devm_mfd_add_devices(bd718xx->dev, PLATFORM_DEVID_AUTO,
+ bd718xx_mfd_cells,
+ ARRAY_SIZE(bd718xx_mfd_cells), NULL, 0,
+ regmap_irq_get_domain(bd718xx->irq_data));
if (ret)
dev_err(&i2c->dev, "Failed to create subdevices\n");
return ret;
}
-static const struct of_device_id bd71837_of_match[] = {
- { .compatible = "rohm,bd71837", },
+static const struct of_device_id bd718xx_of_match[] = {
+ {
+ .compatible = "rohm,bd71837",
+ .data = (void *)BD718XX_TYPE_BD71837,
+ },
+ {
+ .compatible = "rohm,bd71847",
+ .data = (void *)BD718XX_TYPE_BD71847,
+ },
{ }
};
-MODULE_DEVICE_TABLE(of, bd71837_of_match);
+MODULE_DEVICE_TABLE(of, bd718xx_of_match);
-static struct i2c_driver bd71837_i2c_driver = {
+static struct i2c_driver bd718xx_i2c_driver = {
.driver = {
.name = "rohm-bd718x7",
- .of_match_table = bd71837_of_match,
+ .of_match_table = bd718xx_of_match,
},
- .probe = bd71837_i2c_probe,
+ .probe = bd718xx_i2c_probe,
};
-static int __init bd71837_i2c_init(void)
+static int __init bd718xx_i2c_init(void)
{
- return i2c_add_driver(&bd71837_i2c_driver);
+ return i2c_add_driver(&bd718xx_i2c_driver);
}
/* Initialise early so consumer devices can complete system boot */
-subsys_initcall(bd71837_i2c_init);
+subsys_initcall(bd718xx_i2c_init);
-static void __exit bd71837_i2c_exit(void)
+static void __exit bd718xx_i2c_exit(void)
{
- i2c_del_driver(&bd71837_i2c_driver);
+ i2c_del_driver(&bd718xx_i2c_driver);
}
-module_exit(bd71837_i2c_exit);
+module_exit(bd718xx_i2c_exit);
MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
-MODULE_DESCRIPTION("ROHM BD71837 Power Management IC driver");
+MODULE_DESCRIPTION("ROHM BD71837/BD71847 Power Management IC driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c
index 9613b4257302..e0835c9df7a1 100644
--- a/drivers/mfd/sec-core.c
+++ b/drivers/mfd/sec-core.c
@@ -1,15 +1,7 @@
-/*
- * sec-core.c
- *
- * Copyright (c) 2012 Samsung Electronics Co., Ltd
- * http://www.samsung.com
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Copyright (c) 2012 Samsung Electronics Co., Ltd
+// http://www.samsung.com
#include <linux/module.h>
#include <linux/moduleparam.h>
diff --git a/drivers/mfd/sec-irq.c b/drivers/mfd/sec-irq.c
index 5eb59c233d52..ad0099077e7e 100644
--- a/drivers/mfd/sec-irq.c
+++ b/drivers/mfd/sec-irq.c
@@ -1,19 +1,12 @@
-/*
- * sec-irq.c
- *
- * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd
- * http://www.samsung.com
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Copyright (c) 2011-2014 Samsung Electronics Co., Ltd
+// http://www.samsung.com
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
+#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/mfd/samsung/core.h>
@@ -501,3 +494,10 @@ int sec_irq_init(struct sec_pmic_dev *sec_pmic)
return 0;
}
+EXPORT_SYMBOL_GPL(sec_irq_init);
+
+MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
+MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
+MODULE_AUTHOR("Krzysztof Kozlowski <krzk@kernel.org>");
+MODULE_DESCRIPTION("Interrupt support for the S5M MFD");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/ti-lmu.c b/drivers/mfd/ti-lmu.c
index cfb411cde51c..37d0bdb291c3 100644
--- a/drivers/mfd/ti-lmu.c
+++ b/drivers/mfd/ti-lmu.c
@@ -12,7 +12,7 @@
#include <linux/delay.h>
#include <linux/err.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/mfd/core.h>
@@ -21,28 +21,18 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
-#include <linux/of_gpio.h>
#include <linux/slab.h>
struct ti_lmu_data {
- struct mfd_cell *cells;
+ const struct mfd_cell *cells;
int num_cells;
unsigned int max_register;
};
static int ti_lmu_enable_hw(struct ti_lmu *lmu, enum ti_lmu_id id)
{
- int ret;
-
- if (gpio_is_valid(lmu->en_gpio)) {
- ret = devm_gpio_request_one(lmu->dev, lmu->en_gpio,
- GPIOF_OUT_INIT_HIGH, "lmu_hwen");
- if (ret) {
- dev_err(lmu->dev, "Can not request enable GPIO: %d\n",
- ret);
- return ret;
- }
- }
+ if (lmu->en_gpio)
+ gpiod_set_value(lmu->en_gpio, 1);
/* Delay about 1ms after HW enable pin control */
usleep_range(1000, 1500);
@@ -57,13 +47,14 @@ static int ti_lmu_enable_hw(struct ti_lmu *lmu, enum ti_lmu_id id)
return 0;
}
-static void ti_lmu_disable_hw(struct ti_lmu *lmu)
+static void ti_lmu_disable_hw(void *data)
{
- if (gpio_is_valid(lmu->en_gpio))
- gpio_set_value(lmu->en_gpio, 0);
+ struct ti_lmu *lmu = data;
+ if (lmu->en_gpio)
+ gpiod_set_value(lmu->en_gpio, 0);
}
-static struct mfd_cell lm3532_devices[] = {
+static const struct mfd_cell lm3532_devices[] = {
{
.name = "ti-lmu-backlight",
.id = LM3532,
@@ -78,7 +69,7 @@ static struct mfd_cell lm3532_devices[] = {
.of_compatible = "ti,lm363x-regulator", \
} \
-static struct mfd_cell lm3631_devices[] = {
+static const struct mfd_cell lm3631_devices[] = {
LM363X_REGULATOR(LM3631_BOOST),
LM363X_REGULATOR(LM3631_LDO_CONT),
LM363X_REGULATOR(LM3631_LDO_OREF),
@@ -91,7 +82,7 @@ static struct mfd_cell lm3631_devices[] = {
},
};
-static struct mfd_cell lm3632_devices[] = {
+static const struct mfd_cell lm3632_devices[] = {
LM363X_REGULATOR(LM3632_BOOST),
LM363X_REGULATOR(LM3632_LDO_POS),
LM363X_REGULATOR(LM3632_LDO_NEG),
@@ -102,7 +93,7 @@ static struct mfd_cell lm3632_devices[] = {
},
};
-static struct mfd_cell lm3633_devices[] = {
+static const struct mfd_cell lm3633_devices[] = {
{
.name = "ti-lmu-backlight",
.id = LM3633,
@@ -120,7 +111,7 @@ static struct mfd_cell lm3633_devices[] = {
},
};
-static struct mfd_cell lm3695_devices[] = {
+static const struct mfd_cell lm3695_devices[] = {
{
.name = "ti-lmu-backlight",
.id = LM3695,
@@ -128,7 +119,7 @@ static struct mfd_cell lm3695_devices[] = {
},
};
-static struct mfd_cell lm3697_devices[] = {
+static const struct mfd_cell lm3697_devices[] = {
{
.name = "ti-lmu-backlight",
.id = LM3697,
@@ -157,34 +148,21 @@ TI_LMU_DATA(lm3633, LM3633_MAX_REG);
TI_LMU_DATA(lm3695, LM3695_MAX_REG);
TI_LMU_DATA(lm3697, LM3697_MAX_REG);
-static const struct of_device_id ti_lmu_of_match[] = {
- { .compatible = "ti,lm3532", .data = &lm3532_data },
- { .compatible = "ti,lm3631", .data = &lm3631_data },
- { .compatible = "ti,lm3632", .data = &lm3632_data },
- { .compatible = "ti,lm3633", .data = &lm3633_data },
- { .compatible = "ti,lm3695", .data = &lm3695_data },
- { .compatible = "ti,lm3697", .data = &lm3697_data },
- { }
-};
-MODULE_DEVICE_TABLE(of, ti_lmu_of_match);
-
static int ti_lmu_probe(struct i2c_client *cl, const struct i2c_device_id *id)
{
struct device *dev = &cl->dev;
- const struct of_device_id *match;
const struct ti_lmu_data *data;
struct regmap_config regmap_cfg;
struct ti_lmu *lmu;
int ret;
- match = of_match_device(ti_lmu_of_match, dev);
- if (!match)
- return -ENODEV;
/*
* Get device specific data from of_match table.
* This data is defined by using TI_LMU_DATA() macro.
*/
- data = (struct ti_lmu_data *)match->data;
+ data = of_device_get_match_data(dev);
+ if (!data)
+ return -ENODEV;
lmu = devm_kzalloc(dev, sizeof(*lmu), GFP_KERNEL);
if (!lmu)
@@ -204,11 +182,21 @@ static int ti_lmu_probe(struct i2c_client *cl, const struct i2c_device_id *id)
return PTR_ERR(lmu->regmap);
/* HW enable pin control and additional power up sequence if required */
- lmu->en_gpio = of_get_named_gpio(dev->of_node, "enable-gpios", 0);
+ lmu->en_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH);
+ if (IS_ERR(lmu->en_gpio)) {
+ ret = PTR_ERR(lmu->en_gpio);
+ dev_err(dev, "Can not request enable GPIO: %d\n", ret);
+ return ret;
+ }
+
ret = ti_lmu_enable_hw(lmu, id->driver_data);
if (ret)
return ret;
+ ret = devm_add_action_or_reset(dev, ti_lmu_disable_hw, lmu);
+ if (ret)
+ return ret;
+
/*
* Fault circuit(open/short) can be detected by ti-lmu-fault-monitor.
* After fault detection is done, some devices should re-initialize
@@ -218,18 +206,20 @@ static int ti_lmu_probe(struct i2c_client *cl, const struct i2c_device_id *id)
i2c_set_clientdata(cl, lmu);
- return mfd_add_devices(lmu->dev, 0, data->cells,
- data->num_cells, NULL, 0, NULL);
+ return devm_mfd_add_devices(lmu->dev, 0, data->cells,
+ data->num_cells, NULL, 0, NULL);
}
-static int ti_lmu_remove(struct i2c_client *cl)
-{
- struct ti_lmu *lmu = i2c_get_clientdata(cl);
-
- ti_lmu_disable_hw(lmu);
- mfd_remove_devices(lmu->dev);
- return 0;
-}
+static const struct of_device_id ti_lmu_of_match[] = {
+ { .compatible = "ti,lm3532", .data = &lm3532_data },
+ { .compatible = "ti,lm3631", .data = &lm3631_data },
+ { .compatible = "ti,lm3632", .data = &lm3632_data },
+ { .compatible = "ti,lm3633", .data = &lm3633_data },
+ { .compatible = "ti,lm3695", .data = &lm3695_data },
+ { .compatible = "ti,lm3697", .data = &lm3697_data },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ti_lmu_of_match);
static const struct i2c_device_id ti_lmu_ids[] = {
{ "lm3532", LM3532 },
@@ -244,7 +234,6 @@ MODULE_DEVICE_TABLE(i2c, ti_lmu_ids);
static struct i2c_driver ti_lmu_driver = {
.probe = ti_lmu_probe,
- .remove = ti_lmu_remove,
.driver = {
.name = "ti-lmu",
.of_match_table = ti_lmu_of_match,
diff --git a/drivers/mfd/ti_am335x_tscadc.c b/drivers/mfd/ti_am335x_tscadc.c
index 7a30546880a4..c2d47d78705b 100644
--- a/drivers/mfd/ti_am335x_tscadc.c
+++ b/drivers/mfd/ti_am335x_tscadc.c
@@ -269,7 +269,6 @@ static int ti_tscadc_probe(struct platform_device *pdev)
if (err < 0)
goto err_disable_clk;
- device_init_wakeup(&pdev->dev, true);
platform_set_drvdata(pdev, tscadc);
return 0;
@@ -294,11 +293,24 @@ static int ti_tscadc_remove(struct platform_device *pdev)
return 0;
}
+static int __maybe_unused ti_tscadc_can_wakeup(struct device *dev, void *data)
+{
+ return device_may_wakeup(dev);
+}
+
static int __maybe_unused tscadc_suspend(struct device *dev)
{
struct ti_tscadc_dev *tscadc = dev_get_drvdata(dev);
regmap_write(tscadc->regmap, REG_SE, 0x00);
+ if (device_for_each_child(dev, NULL, ti_tscadc_can_wakeup)) {
+ u32 ctrl;
+
+ regmap_read(tscadc->regmap, REG_CTRL, &ctrl);
+ ctrl &= ~(CNTRLREG_POWERDOWN);
+ ctrl |= CNTRLREG_TSCSSENB;
+ regmap_write(tscadc->regmap, REG_CTRL, ctrl);
+ }
pm_runtime_put_sync(dev);
return 0;
diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c
index dd19f17a1b63..7c3c5fd5fcd0 100644
--- a/drivers/mfd/twl6040.c
+++ b/drivers/mfd/twl6040.c
@@ -613,7 +613,8 @@ static const struct regmap_config twl6040_regmap_config = {
.writeable_reg = twl6040_writeable_reg,
.cache_type = REGCACHE_RBTREE,
- .use_single_rw = true,
+ .use_single_read = true,
+ .use_single_write = true,
};
static const struct regmap_irq twl6040_irqs[] = {
diff --git a/drivers/misc/ad525x_dpot-i2c.c b/drivers/misc/ad525x_dpot-i2c.c
index 4f832002d116..1827c69959fb 100644
--- a/drivers/misc/ad525x_dpot-i2c.c
+++ b/drivers/misc/ad525x_dpot-i2c.c
@@ -114,6 +114,6 @@ static struct i2c_driver ad_dpot_i2c_driver = {
module_i2c_driver(ad_dpot_i2c_driver);
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("digital potentiometer I2C bus driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/misc/ad525x_dpot-spi.c b/drivers/misc/ad525x_dpot-spi.c
index 39a7f517ee7e..0383ec153725 100644
--- a/drivers/misc/ad525x_dpot-spi.c
+++ b/drivers/misc/ad525x_dpot-spi.c
@@ -140,7 +140,7 @@ static struct spi_driver ad_dpot_spi_driver = {
module_spi_driver(ad_dpot_spi_driver);
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("digital potentiometer SPI bus driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("spi:ad_dpot");
diff --git a/drivers/misc/ad525x_dpot.c b/drivers/misc/ad525x_dpot.c
index bc591b7168db..a0afadefcc49 100644
--- a/drivers/misc/ad525x_dpot.c
+++ b/drivers/misc/ad525x_dpot.c
@@ -1,7 +1,7 @@
/*
* ad525x_dpot: Driver for the Analog Devices digital potentiometers
* Copyright (c) 2009-2010 Analog Devices, Inc.
- * Author: Michael Hennerich <hennerich@blackfin.uclinux.org>
+ * Author: Michael Hennerich <michael.hennerich@analog.com>
*
* DEVID #Wipers #Positions Resistor Options (kOhm)
* AD5258 1 64 1, 10, 50, 100
@@ -64,7 +64,7 @@
* Author: Chris Verges <chrisv@cyberswitching.com>
*
* derived from ad5252.c
- * Copyright (c) 2006-2011 Michael Hennerich <hennerich@blackfin.uclinux.org>
+ * Copyright (c) 2006-2011 Michael Hennerich <michael.hennerich@analog.com>
*
* Licensed under the GPL-2 or later.
*/
@@ -760,6 +760,6 @@ EXPORT_SYMBOL(ad_dpot_remove);
MODULE_AUTHOR("Chris Verges <chrisv@cyberswitching.com>, "
- "Michael Hennerich <hennerich@blackfin.uclinux.org>");
+ "Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Digital potentiometer driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/misc/apds990x.c b/drivers/misc/apds990x.c
index ed9412d750b7..24876c615c3c 100644
--- a/drivers/misc/apds990x.c
+++ b/drivers/misc/apds990x.c
@@ -188,7 +188,6 @@ struct apds990x_chip {
#define APDS_LUX_DEFAULT_RATE 200
static const u8 again[] = {1, 8, 16, 120}; /* ALS gain steps */
-static const u8 ir_currents[] = {100, 50, 25, 12}; /* IRled currents in mA */
/* Following two tables must match i.e 10Hz rate means 1 as persistence value */
static const u16 arates_hz[] = {10, 5, 2, 1};
diff --git a/drivers/misc/bh1770glc.c b/drivers/misc/bh1770glc.c
index 9c62bf064f77..17e81ce9925b 100644
--- a/drivers/misc/bh1770glc.c
+++ b/drivers/misc/bh1770glc.c
@@ -180,9 +180,6 @@ static const char reg_vleds[] = "Vleds";
static const s16 prox_rates_hz[] = {100, 50, 33, 25, 14, 10, 5, 2};
static const s16 prox_rates_ms[] = {10, 20, 30, 40, 70, 100, 200, 500};
-/* Supported IR-led currents in mA */
-static const u8 prox_curr_ma[] = {5, 10, 20, 50, 100, 150, 200};
-
/*
* Supported stand alone rates in ms from chip data sheet
* {100, 200, 500, 1000, 2000};
diff --git a/drivers/misc/cxl/flash.c b/drivers/misc/cxl/flash.c
index 43917898fb9a..4d6836f19489 100644
--- a/drivers/misc/cxl/flash.c
+++ b/drivers/misc/cxl/flash.c
@@ -92,8 +92,8 @@ static int update_property(struct device_node *dn, const char *name,
val = (u32 *)new_prop->value;
rc = cxl_update_properties(dn, new_prop);
- pr_devel("%s: update property (%s, length: %i, value: %#x)\n",
- dn->name, name, vd, be32_to_cpu(*val));
+ pr_devel("%pOFn: update property (%s, length: %i, value: %#x)\n",
+ dn, name, vd, be32_to_cpu(*val));
if (rc) {
kfree(new_prop->name);
diff --git a/drivers/misc/cxl/guest.c b/drivers/misc/cxl/guest.c
index 3bc0c15d4d85..5d28d9e454f5 100644
--- a/drivers/misc/cxl/guest.c
+++ b/drivers/misc/cxl/guest.c
@@ -1018,8 +1018,6 @@ err1:
void cxl_guest_remove_afu(struct cxl_afu *afu)
{
- pr_devel("in %s - AFU(%d)\n", __func__, afu->slice);
-
if (!afu)
return;
diff --git a/drivers/misc/echo/echo.c b/drivers/misc/echo/echo.c
index 8a5adc0d2e88..3ebe5d75ad6a 100644
--- a/drivers/misc/echo/echo.c
+++ b/drivers/misc/echo/echo.c
@@ -381,7 +381,7 @@ int16_t oslec_update(struct oslec_state *ec, int16_t tx, int16_t rx)
*/
ec->factor = 0;
ec->shift = 0;
- if ((ec->nonupdate_dwell == 0)) {
+ if (!ec->nonupdate_dwell) {
int p, logp, shift;
/* Determine:
diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
index 68a1ac929917..fe7a1d27a017 100644
--- a/drivers/misc/eeprom/Kconfig
+++ b/drivers/misc/eeprom/Kconfig
@@ -111,4 +111,15 @@ config EEPROM_IDT_89HPESX
This driver can also be built as a module. If so, the module
will be called idt_89hpesx.
+config EEPROM_EE1004
+ tristate "SPD EEPROMs on DDR4 memory modules"
+ depends on I2C && SYSFS
+ help
+ Enable this driver to get read support to SPD EEPROMs following
+ the JEDEC EE1004 standard. These are typically found on DDR4
+ SDRAM memory modules.
+
+ This driver can also be built as a module. If so, the module
+ will be called ee1004.
+
endmenu
diff --git a/drivers/misc/eeprom/Makefile b/drivers/misc/eeprom/Makefile
index 2aab60ef3e3e..a9b4b6579b75 100644
--- a/drivers/misc/eeprom/Makefile
+++ b/drivers/misc/eeprom/Makefile
@@ -7,3 +7,4 @@ obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o
obj-$(CONFIG_EEPROM_93XX46) += eeprom_93xx46.o
obj-$(CONFIG_EEPROM_DIGSY_MTC_CFG) += digsy_mtc_eeprom.o
obj-$(CONFIG_EEPROM_IDT_89HPESX) += idt_89hpesx.o
+obj-$(CONFIG_EEPROM_EE1004) += ee1004.o
diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index 7e50e1d6f58c..636ed7149793 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -106,23 +106,6 @@ static unsigned int at24_write_timeout = 25;
module_param_named(write_timeout, at24_write_timeout, uint, 0);
MODULE_PARM_DESC(at24_write_timeout, "Time (in ms) to try writes (default 25)");
-/*
- * Both reads and writes fail if the previous write didn't complete yet. This
- * macro loops a few times waiting at least long enough for one entire page
- * write to work while making sure that at least one iteration is run before
- * checking the break condition.
- *
- * It takes two parameters: a variable in which the future timeout in jiffies
- * will be stored and a temporary variable holding the time of the last
- * iteration of processing the request. Both should be unsigned integers
- * holding at least 32 bits.
- */
-#define at24_loop_until_timeout(tout, op_time) \
- for (tout = jiffies + msecs_to_jiffies(at24_write_timeout), \
- op_time = 0; \
- op_time ? time_before(op_time, tout) : true; \
- usleep_range(1000, 1500), op_time = jiffies)
-
struct at24_chip_data {
/*
* these fields mirror their equivalents in
@@ -308,13 +291,22 @@ static ssize_t at24_regmap_read(struct at24_data *at24, char *buf,
/* adjust offset for mac and serial read ops */
offset += at24->offset_adj;
- at24_loop_until_timeout(timeout, read_time) {
+ timeout = jiffies + msecs_to_jiffies(at24_write_timeout);
+ do {
+ /*
+ * The timestamp shall be taken before the actual operation
+ * to avoid a premature timeout in case of high CPU load.
+ */
+ read_time = jiffies;
+
ret = regmap_bulk_read(regmap, offset, buf, count);
dev_dbg(&client->dev, "read %zu@%d --> %d (%ld)\n",
count, offset, ret, jiffies);
if (!ret)
return count;
- }
+
+ usleep_range(1000, 1500);
+ } while (time_before(read_time, timeout));
return -ETIMEDOUT;
}
@@ -358,14 +350,23 @@ static ssize_t at24_regmap_write(struct at24_data *at24, const char *buf,
regmap = at24_client->regmap;
client = at24_client->client;
count = at24_adjust_write_count(at24, offset, count);
+ timeout = jiffies + msecs_to_jiffies(at24_write_timeout);
+
+ do {
+ /*
+ * The timestamp shall be taken before the actual operation
+ * to avoid a premature timeout in case of high CPU load.
+ */
+ write_time = jiffies;
- at24_loop_until_timeout(timeout, write_time) {
ret = regmap_bulk_write(regmap, offset, buf, count);
dev_dbg(&client->dev, "write %zu@%d --> %d (%ld)\n",
count, offset, ret, jiffies);
if (!ret)
return count;
- }
+
+ usleep_range(1000, 1500);
+ } while (time_before(write_time, timeout));
return -ETIMEDOUT;
}
diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c
index 840afb398f9e..99de6939cd5a 100644
--- a/drivers/misc/eeprom/at25.c
+++ b/drivers/misc/eeprom/at25.c
@@ -366,7 +366,7 @@ static int at25_probe(struct spi_device *spi)
at25->nvmem_config.word_size = 1;
at25->nvmem_config.size = chip.byte_len;
- at25->nvmem = nvmem_register(&at25->nvmem_config);
+ at25->nvmem = devm_nvmem_register(&spi->dev, &at25->nvmem_config);
if (IS_ERR(at25->nvmem))
return PTR_ERR(at25->nvmem);
@@ -379,16 +379,6 @@ static int at25_probe(struct spi_device *spi)
return 0;
}
-static int at25_remove(struct spi_device *spi)
-{
- struct at25_data *at25;
-
- at25 = spi_get_drvdata(spi);
- nvmem_unregister(at25->nvmem);
-
- return 0;
-}
-
/*-------------------------------------------------------------------------*/
static const struct of_device_id at25_of_match[] = {
@@ -403,7 +393,6 @@ static struct spi_driver at25_driver = {
.of_match_table = at25_of_match,
},
.probe = at25_probe,
- .remove = at25_remove,
};
module_spi_driver(at25_driver);
diff --git a/drivers/misc/eeprom/ee1004.c b/drivers/misc/eeprom/ee1004.c
new file mode 100644
index 000000000000..276c1690ea1b
--- /dev/null
+++ b/drivers/misc/eeprom/ee1004.c
@@ -0,0 +1,281 @@
+/*
+ * ee1004 - driver for DDR4 SPD EEPROMs
+ *
+ * Copyright (C) 2017 Jean Delvare
+ *
+ * Based on the at24 driver:
+ * Copyright (C) 2005-2007 David Brownell
+ * Copyright (C) 2008 Wolfram Sang, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+
+/*
+ * DDR4 memory modules use special EEPROMs following the Jedec EE1004
+ * specification. These are 512-byte EEPROMs using a single I2C address
+ * in the 0x50-0x57 range for data. One of two 256-byte page is selected
+ * by writing a command to I2C address 0x36 or 0x37 on the same I2C bus.
+ *
+ * Therefore we need to request these 2 additional addresses, and serialize
+ * access to all such EEPROMs with a single mutex.
+ *
+ * We assume it is safe to read up to 32 bytes at once from these EEPROMs.
+ * We use SMBus access even if I2C is available, these EEPROMs are small
+ * enough, and reading from them infrequent enough, that we favor simplicity
+ * over performance.
+ */
+
+#define EE1004_ADDR_SET_PAGE 0x36
+#define EE1004_EEPROM_SIZE 512
+#define EE1004_PAGE_SIZE 256
+#define EE1004_PAGE_SHIFT 8
+
+/*
+ * 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 unsigned int ee1004_dev_count;
+static int ee1004_current_page;
+
+static const struct i2c_device_id ee1004_ids[] = {
+ { "ee1004", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ee1004_ids);
+
+/*-------------------------------------------------------------------------*/
+
+static ssize_t ee1004_eeprom_read(struct i2c_client *client, char *buf,
+ unsigned int offset, size_t count)
+{
+ int status;
+
+ if (count > I2C_SMBUS_BLOCK_MAX)
+ count = I2C_SMBUS_BLOCK_MAX;
+ /* Can't cross page boundaries */
+ if (unlikely(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;
+}
+
+static ssize_t ee1004_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);
+ 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;
+
+ /*
+ * Read data from chip, protecting against concurrent access to
+ * other EE1004 SPD EEPROMs on the same adapter.
+ */
+ 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 < 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;
+
+ if (off == EE1004_PAGE_SIZE) {
+ page++;
+ off = 0;
+ }
+ }
+
+ mutex_unlock(&ee1004_bus_lock);
+
+ return requested;
+}
+
+static const struct bin_attribute eeprom_attr = {
+ .attr = {
+ .name = "eeprom",
+ .mode = 0444,
+ },
+ .size = EE1004_EEPROM_SIZE,
+ .read = ee1004_read,
+};
+
+static int ee1004_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ 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;
+ }
+
+ /* 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(client->adapter,
+ EE1004_ADDR_SET_PAGE + cnr);
+ if (!ee1004_set_page[cnr]) {
+ dev_err(&client->dev,
+ "address 0x%02x unavailable\n",
+ EE1004_ADDR_SET_PAGE + cnr);
+ err = -EADDRINUSE;
+ goto err_clients;
+ }
+ }
+ } else if (i2c_adapter_id(client->adapter) !=
+ i2c_adapter_id(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 = i2c_smbus_read_byte(ee1004_set_page[0]);
+ if (err == -ENXIO) {
+ /* Nack means page 1 is selected */
+ ee1004_current_page = 1;
+ } else if (err < 0) {
+ /* Anything else is a real error, bail out */
+ goto err_clients;
+ } else {
+ /* Ack means page 0 is selected, returned value meaningless */
+ ee1004_current_page = 0;
+ }
+ 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;
+ }
+ }
+ mutex_unlock(&ee1004_bus_lock);
+
+ return err;
+}
+
+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;
+ }
+ }
+ mutex_unlock(&ee1004_bus_lock);
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct i2c_driver ee1004_driver = {
+ .driver = {
+ .name = "ee1004",
+ },
+ .probe = ee1004_probe,
+ .remove = ee1004_remove,
+ .id_table = ee1004_ids,
+};
+
+static int __init ee1004_init(void)
+{
+ return i2c_add_driver(&ee1004_driver);
+}
+module_init(ee1004_init);
+
+static void __exit ee1004_exit(void)
+{
+ i2c_del_driver(&ee1004_driver);
+}
+module_exit(ee1004_exit);
+
+MODULE_DESCRIPTION("Driver for EE1004-compliant DDR4 SPD EEPROMs");
+MODULE_AUTHOR("Jean Delvare");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c
index 38766968bfa2..c6dd9ad9bf7b 100644
--- a/drivers/misc/eeprom/eeprom_93xx46.c
+++ b/drivers/misc/eeprom/eeprom_93xx46.c
@@ -439,7 +439,7 @@ static int eeprom_93xx46_probe(struct spi_device *spi)
return -ENODEV;
}
- edev = kzalloc(sizeof(*edev), GFP_KERNEL);
+ edev = devm_kzalloc(&spi->dev, sizeof(*edev), GFP_KERNEL);
if (!edev)
return -ENOMEM;
@@ -449,8 +449,7 @@ static int eeprom_93xx46_probe(struct spi_device *spi)
edev->addrlen = 6;
else {
dev_err(&spi->dev, "unspecified address type\n");
- err = -EINVAL;
- goto fail;
+ return -EINVAL;
}
mutex_init(&edev->lock);
@@ -473,11 +472,9 @@ static int eeprom_93xx46_probe(struct spi_device *spi)
edev->nvmem_config.word_size = 1;
edev->nvmem_config.size = edev->size;
- edev->nvmem = nvmem_register(&edev->nvmem_config);
- if (IS_ERR(edev->nvmem)) {
- err = PTR_ERR(edev->nvmem);
- goto fail;
- }
+ edev->nvmem = devm_nvmem_register(&spi->dev, &edev->nvmem_config);
+ if (IS_ERR(edev->nvmem))
+ return PTR_ERR(edev->nvmem);
dev_info(&spi->dev, "%d-bit eeprom %s\n",
(pd->flags & EE_ADDR8) ? 8 : 16,
@@ -490,21 +487,15 @@ static int eeprom_93xx46_probe(struct spi_device *spi)
spi_set_drvdata(spi, edev);
return 0;
-fail:
- kfree(edev);
- return err;
}
static int eeprom_93xx46_remove(struct spi_device *spi)
{
struct eeprom_93xx46_dev *edev = spi_get_drvdata(spi);
- nvmem_unregister(edev->nvmem);
-
if (!(edev->pdata->flags & EE_READONLY))
device_remove_file(&spi->dev, &dev_attr_erase);
- kfree(edev);
return 0;
}
diff --git a/drivers/misc/genwqe/card_base.c b/drivers/misc/genwqe/card_base.c
index c7cd3675bcd1..d137d0fab9bf 100644
--- a/drivers/misc/genwqe/card_base.c
+++ b/drivers/misc/genwqe/card_base.c
@@ -24,7 +24,6 @@
* controlled from here.
*/
-#include <linux/module.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/err.h>
diff --git a/drivers/misc/genwqe/card_base.h b/drivers/misc/genwqe/card_base.h
index 120738d6e58b..77ed3967c5b0 100644
--- a/drivers/misc/genwqe/card_base.h
+++ b/drivers/misc/genwqe/card_base.h
@@ -408,7 +408,7 @@ struct genwqe_file {
struct file *filp;
struct fasync_struct *async_queue;
- struct task_struct *owner;
+ struct pid *opener;
struct list_head list; /* entry in list of open files */
spinlock_t map_lock; /* lock for dma_mappings */
diff --git a/drivers/misc/genwqe/card_ddcb.c b/drivers/misc/genwqe/card_ddcb.c
index 656449cb4476..9a65bd9d6152 100644
--- a/drivers/misc/genwqe/card_ddcb.c
+++ b/drivers/misc/genwqe/card_ddcb.c
@@ -27,7 +27,6 @@
*/
#include <linux/types.h>
-#include <linux/module.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/pci.h>
diff --git a/drivers/misc/genwqe/card_dev.c b/drivers/misc/genwqe/card_dev.c
index f453ab82f0d7..8c1b63a4337b 100644
--- a/drivers/misc/genwqe/card_dev.c
+++ b/drivers/misc/genwqe/card_dev.c
@@ -52,7 +52,7 @@ static void genwqe_add_file(struct genwqe_dev *cd, struct genwqe_file *cfile)
{
unsigned long flags;
- cfile->owner = current;
+ cfile->opener = get_pid(task_tgid(current));
spin_lock_irqsave(&cd->file_lock, flags);
list_add(&cfile->list, &cd->file_list);
spin_unlock_irqrestore(&cd->file_lock, flags);
@@ -65,6 +65,7 @@ static int genwqe_del_file(struct genwqe_dev *cd, struct genwqe_file *cfile)
spin_lock_irqsave(&cd->file_lock, flags);
list_del(&cfile->list);
spin_unlock_irqrestore(&cd->file_lock, flags);
+ put_pid(cfile->opener);
return 0;
}
@@ -275,7 +276,7 @@ static int genwqe_kill_fasync(struct genwqe_dev *cd, int sig)
return files;
}
-static int genwqe_force_sig(struct genwqe_dev *cd, int sig)
+static int genwqe_terminate(struct genwqe_dev *cd)
{
unsigned int files = 0;
unsigned long flags;
@@ -283,7 +284,7 @@ static int genwqe_force_sig(struct genwqe_dev *cd, int sig)
spin_lock_irqsave(&cd->file_lock, flags);
list_for_each_entry(cfile, &cd->file_list, list) {
- force_sig(sig, cfile->owner);
+ kill_pid(cfile->opener, SIGKILL, 1);
files++;
}
spin_unlock_irqrestore(&cd->file_lock, flags);
@@ -1352,7 +1353,7 @@ static int genwqe_inform_and_stop_processes(struct genwqe_dev *cd)
dev_warn(&pci_dev->dev,
"[%s] send SIGKILL and wait ...\n", __func__);
- rc = genwqe_force_sig(cd, SIGKILL); /* force terminate */
+ rc = genwqe_terminate(cd);
if (rc) {
/* Give kill_timout more seconds to end processes */
for (i = 0; (i < GENWQE_KILL_TIMEOUT) &&
diff --git a/drivers/misc/genwqe/card_utils.c b/drivers/misc/genwqe/card_utils.c
index 8679e0bd8ec2..3fcb9a2fe1c9 100644
--- a/drivers/misc/genwqe/card_utils.c
+++ b/drivers/misc/genwqe/card_utils.c
@@ -23,14 +23,12 @@
*/
#include <linux/kernel.h>
-#include <linux/dma-mapping.h>
#include <linux/sched.h>
#include <linux/vmalloc.h>
#include <linux/page-flags.h>
#include <linux/scatterlist.h>
#include <linux/hugetlb.h>
#include <linux/iommu.h>
-#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/ctype.h>
@@ -298,7 +296,7 @@ static int genwqe_sgl_size(int num_pages)
int genwqe_alloc_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl,
void __user *user_addr, size_t user_size, int write)
{
- int rc;
+ int ret = -ENOMEM;
struct pci_dev *pci_dev = cd->pci_dev;
sgl->fpage_offs = offset_in_page((unsigned long)user_addr);
@@ -318,7 +316,7 @@ int genwqe_alloc_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl,
if (get_order(sgl->sgl_size) > MAX_ORDER) {
dev_err(&pci_dev->dev,
"[%s] err: too much memory requested!\n", __func__);
- return -ENOMEM;
+ return ret;
}
sgl->sgl = __genwqe_alloc_consistent(cd, sgl->sgl_size,
@@ -326,7 +324,7 @@ int genwqe_alloc_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl,
if (sgl->sgl == NULL) {
dev_err(&pci_dev->dev,
"[%s] err: no memory available!\n", __func__);
- return -ENOMEM;
+ return ret;
}
/* Only use buffering on incomplete pages */
@@ -339,7 +337,7 @@ int genwqe_alloc_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl,
/* Sync with user memory */
if (copy_from_user(sgl->fpage + sgl->fpage_offs,
user_addr, sgl->fpage_size)) {
- rc = -EFAULT;
+ ret = -EFAULT;
goto err_out;
}
}
@@ -352,7 +350,7 @@ int genwqe_alloc_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl,
/* Sync with user memory */
if (copy_from_user(sgl->lpage, user_addr + user_size -
sgl->lpage_size, sgl->lpage_size)) {
- rc = -EFAULT;
+ ret = -EFAULT;
goto err_out2;
}
}
@@ -374,7 +372,8 @@ int genwqe_alloc_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl,
sgl->sgl = NULL;
sgl->sgl_dma_addr = 0;
sgl->sgl_size = 0;
- return -ENOMEM;
+
+ return ret;
}
int genwqe_setup_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl,
diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c
index 6193270e7b3d..de20bdaa148d 100644
--- a/drivers/misc/kgdbts.c
+++ b/drivers/misc/kgdbts.c
@@ -985,6 +985,12 @@ static void kgdbts_run_tests(void)
int nmi_sleep = 0;
int i;
+ verbose = 0;
+ if (strstr(config, "V1"))
+ verbose = 1;
+ if (strstr(config, "V2"))
+ verbose = 2;
+
ptr = strchr(config, 'F');
if (ptr)
fork_test = simple_strtol(ptr + 1, NULL, 10);
@@ -1068,13 +1074,6 @@ static int kgdbts_option_setup(char *opt)
return -ENOSPC;
}
strcpy(config, opt);
-
- verbose = 0;
- if (strstr(config, "V1"))
- verbose = 1;
- if (strstr(config, "V2"))
- verbose = 2;
-
return 0;
}
@@ -1086,9 +1085,6 @@ static int configure_kgdbts(void)
if (!strlen(config) || isspace(config[0]))
goto noconfig;
- err = kgdbts_option_setup(config);
- if (err)
- goto noconfig;
final_ack = 0;
run_plant_and_detach_test(1);
diff --git a/drivers/misc/lkdtm/Makefile b/drivers/misc/lkdtm/Makefile
index 3370a4138e94..951c984de61a 100644
--- a/drivers/misc/lkdtm/Makefile
+++ b/drivers/misc/lkdtm/Makefile
@@ -8,7 +8,9 @@ lkdtm-$(CONFIG_LKDTM) += perms.o
lkdtm-$(CONFIG_LKDTM) += refcount.o
lkdtm-$(CONFIG_LKDTM) += rodata_objcopy.o
lkdtm-$(CONFIG_LKDTM) += usercopy.o
+lkdtm-$(CONFIG_LKDTM) += stackleak.o
+KASAN_SANITIZE_stackleak.o := n
KCOV_INSTRUMENT_rodata.o := n
OBJCOPYFLAGS :=
diff --git a/drivers/misc/lkdtm/core.c b/drivers/misc/lkdtm/core.c
index 2154d1bfd18b..2837dc77478e 100644
--- a/drivers/misc/lkdtm/core.c
+++ b/drivers/misc/lkdtm/core.c
@@ -183,6 +183,8 @@ static const struct crashtype crashtypes[] = {
CRASHTYPE(USERCOPY_STACK_FRAME_FROM),
CRASHTYPE(USERCOPY_STACK_BEYOND),
CRASHTYPE(USERCOPY_KERNEL),
+ CRASHTYPE(USERCOPY_KERNEL_DS),
+ CRASHTYPE(STACKLEAK_ERASING),
};
diff --git a/drivers/misc/lkdtm/lkdtm.h b/drivers/misc/lkdtm/lkdtm.h
index 9e513dcfd809..3c6fd327e166 100644
--- a/drivers/misc/lkdtm/lkdtm.h
+++ b/drivers/misc/lkdtm/lkdtm.h
@@ -82,5 +82,9 @@ void lkdtm_USERCOPY_STACK_FRAME_TO(void);
void lkdtm_USERCOPY_STACK_FRAME_FROM(void);
void lkdtm_USERCOPY_STACK_BEYOND(void);
void lkdtm_USERCOPY_KERNEL(void);
+void lkdtm_USERCOPY_KERNEL_DS(void);
+
+/* lkdtm_stackleak.c */
+void lkdtm_STACKLEAK_ERASING(void);
#endif
diff --git a/drivers/misc/lkdtm/stackleak.c b/drivers/misc/lkdtm/stackleak.c
new file mode 100644
index 000000000000..d5a084475abc
--- /dev/null
+++ b/drivers/misc/lkdtm/stackleak.c
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * This code tests that the current task stack is properly erased (filled
+ * with STACKLEAK_POISON).
+ *
+ * Authors:
+ * Alexander Popov <alex.popov@linux.com>
+ * Tycho Andersen <tycho@tycho.ws>
+ */
+
+#include "lkdtm.h"
+#include <linux/stackleak.h>
+
+void lkdtm_STACKLEAK_ERASING(void)
+{
+ unsigned long *sp, left, found, i;
+ const unsigned long check_depth =
+ STACKLEAK_SEARCH_DEPTH / sizeof(unsigned long);
+
+ /*
+ * For the details about the alignment of the poison values, see
+ * the comment in stackleak_track_stack().
+ */
+ sp = PTR_ALIGN(&i, sizeof(unsigned long));
+
+ left = ((unsigned long)sp & (THREAD_SIZE - 1)) / sizeof(unsigned long);
+ sp--;
+
+ /*
+ * One 'long int' at the bottom of the thread stack is reserved
+ * and not poisoned.
+ */
+ if (left > 1) {
+ left--;
+ } else {
+ pr_err("FAIL: not enough stack space for the test\n");
+ return;
+ }
+
+ pr_info("checking unused part of the thread stack (%lu bytes)...\n",
+ left * sizeof(unsigned long));
+
+ /*
+ * Search for 'check_depth' poison values in a row (just like
+ * stackleak_erase() does).
+ */
+ for (i = 0, found = 0; i < left && found <= check_depth; i++) {
+ if (*(sp - i) == STACKLEAK_POISON)
+ found++;
+ else
+ found = 0;
+ }
+
+ if (found <= check_depth) {
+ pr_err("FAIL: thread stack is not erased (checked %lu bytes)\n",
+ i * sizeof(unsigned long));
+ return;
+ }
+
+ pr_info("first %lu bytes are unpoisoned\n",
+ (i - found) * sizeof(unsigned long));
+
+ /* The rest of thread stack should be erased */
+ for (; i < left; i++) {
+ if (*(sp - i) != STACKLEAK_POISON) {
+ pr_err("FAIL: thread stack is NOT properly erased\n");
+ return;
+ }
+ }
+
+ pr_info("OK: the rest of the thread stack is properly erased\n");
+ return;
+}
diff --git a/drivers/misc/lkdtm/usercopy.c b/drivers/misc/lkdtm/usercopy.c
index 9725aed305bb..d5a0e7f1813b 100644
--- a/drivers/misc/lkdtm/usercopy.c
+++ b/drivers/misc/lkdtm/usercopy.c
@@ -18,7 +18,7 @@
* hardened usercopy checks by added "unconst" to all the const copies,
* and making sure "cache_size" isn't optimized into a const.
*/
-static volatile size_t unconst = 0;
+static volatile size_t unconst;
static volatile size_t cache_size = 1024;
static struct kmem_cache *whitelist_cache;
@@ -322,6 +322,19 @@ free_user:
vm_munmap(user_addr, PAGE_SIZE);
}
+void lkdtm_USERCOPY_KERNEL_DS(void)
+{
+ char __user *user_ptr = (char __user *)ERR_PTR(-EINVAL);
+ mm_segment_t old_fs = get_fs();
+ char buf[10] = {0};
+
+ pr_info("attempting copy_to_user on unmapped kernel address\n");
+ set_fs(KERNEL_DS);
+ if (copy_to_user(user_ptr, buf, sizeof(buf)))
+ pr_info("copy_to_user un unmapped kernel address failed\n");
+ set_fs(old_fs);
+}
+
void __init lkdtm_usercopy_init(void)
{
/* Prepare cache that lacks SLAB_USERCOPY flag. */
diff --git a/drivers/misc/mei/bus-fixup.c b/drivers/misc/mei/bus-fixup.c
index a6f41f96f2a1..80215c312f0e 100644
--- a/drivers/misc/mei/bus-fixup.c
+++ b/drivers/misc/mei/bus-fixup.c
@@ -17,7 +17,6 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/uuid.h>
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index 4d77a6ae183a..87281b3695e6 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -599,10 +599,10 @@ static __poll_t mei_poll(struct file *file, poll_table *wait)
mei_cl_read_start(cl, mei_cl_mtu(cl), file);
}
- if (req_events & (POLLOUT | POLLWRNORM)) {
+ if (req_events & (EPOLLOUT | EPOLLWRNORM)) {
poll_wait(file, &cl->tx_wait, wait);
if (cl->tx_cb_queued < dev->tx_queue_limit)
- mask |= POLLOUT | POLLWRNORM;
+ mask |= EPOLLOUT | EPOLLWRNORM;
}
out:
diff --git a/drivers/misc/mic/scif/scif_dma.c b/drivers/misc/mic/scif/scif_dma.c
index 6369aeaa7056..18b8ed57c4ac 100644
--- a/drivers/misc/mic/scif/scif_dma.c
+++ b/drivers/misc/mic/scif/scif_dma.c
@@ -1035,8 +1035,6 @@ scif_rma_list_dma_copy_unaligned(struct scif_copy_work *work,
}
dma_async_issue_pending(chan);
}
- if (ret < 0)
- goto err;
offset += loop_len;
temp += loop_len;
temp_phys += loop_len;
@@ -1553,9 +1551,8 @@ static int scif_rma_list_dma_copy_wrapper(struct scif_endpt *epd,
int src_cache_off, dst_cache_off;
s64 src_offset = work->src_offset, dst_offset = work->dst_offset;
u8 *temp = NULL;
- bool src_local = true, dst_local = false;
+ bool src_local = true;
struct scif_dma_comp_cb *comp_cb;
- dma_addr_t src_dma_addr, dst_dma_addr;
int err;
if (is_dma_copy_aligned(chan->device, 1, 1, 1))
@@ -1569,12 +1566,8 @@ static int scif_rma_list_dma_copy_wrapper(struct scif_endpt *epd,
if (work->loopback)
return scif_rma_list_cpu_copy(work);
- src_dma_addr = __scif_off_to_dma_addr(work->src_window, src_offset);
- dst_dma_addr = __scif_off_to_dma_addr(work->dst_window, dst_offset);
src_local = work->src_window->type == SCIF_WINDOW_SELF;
- dst_local = work->dst_window->type == SCIF_WINDOW_SELF;
- dst_local = dst_local;
/* Allocate dma_completion cb */
comp_cb = kzalloc(sizeof(*comp_cb), GFP_KERNEL);
if (!comp_cb)
diff --git a/drivers/misc/mic/scif/scif_fence.c b/drivers/misc/mic/scif/scif_fence.c
index cac3bcc308a7..7bb929f05d85 100644
--- a/drivers/misc/mic/scif/scif_fence.c
+++ b/drivers/misc/mic/scif/scif_fence.c
@@ -272,7 +272,7 @@ static int _scif_prog_signal(scif_epd_t epd, dma_addr_t dst, u64 val)
dma_fail:
if (!x100)
dma_pool_free(ep->remote_dev->signal_pool, status,
- status->src_dma_addr);
+ src - offsetof(struct scif_status, val));
alloc_fail:
return err;
}
diff --git a/drivers/misc/ocxl/config.c b/drivers/misc/ocxl/config.c
index 2e30de9c694a..57a6bb1fd3c9 100644
--- a/drivers/misc/ocxl/config.c
+++ b/drivers/misc/ocxl/config.c
@@ -280,7 +280,9 @@ int ocxl_config_check_afu_index(struct pci_dev *dev,
u32 val;
int rc, templ_major, templ_minor, len;
- pci_write_config_word(dev, fn->dvsec_afu_info_pos, afu_idx);
+ pci_write_config_byte(dev,
+ fn->dvsec_afu_info_pos + OCXL_DVSEC_AFU_INFO_AFU_IDX,
+ afu_idx);
rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_VERSION, &val);
if (rc)
return rc;
diff --git a/drivers/misc/sgi-gru/grukservices.c b/drivers/misc/sgi-gru/grukservices.c
index 030769018461..4b23d586fc3f 100644
--- a/drivers/misc/sgi-gru/grukservices.c
+++ b/drivers/misc/sgi-gru/grukservices.c
@@ -634,7 +634,7 @@ static int send_noop_message(void *cb, struct gru_message_queue_desc *mqd,
break;
case CBSS_PAGE_OVERFLOW:
STAT(mesq_noop_page_overflow);
- /* fallthru */
+ /* fall through */
default:
BUG();
}
@@ -792,7 +792,7 @@ static int send_message_failure(void *cb, struct gru_message_queue_desc *mqd,
break;
case CBSS_PAGE_OVERFLOW:
STAT(mesq_page_overflow);
- /* fallthru */
+ /* fall through */
default:
BUG();
}
diff --git a/drivers/misc/sgi-gru/grutlbpurge.c b/drivers/misc/sgi-gru/grutlbpurge.c
index be28f05bfafa..03b49d52092e 100644
--- a/drivers/misc/sgi-gru/grutlbpurge.c
+++ b/drivers/misc/sgi-gru/grutlbpurge.c
@@ -261,7 +261,6 @@ static void gru_release(struct mmu_notifier *mn, struct mm_struct *mm)
static const struct mmu_notifier_ops gru_mmuops = {
- .flags = MMU_INVALIDATE_DOES_NOT_BLOCK,
.invalidate_range_start = gru_invalidate_range_start,
.invalidate_range_end = gru_invalidate_range_end,
.release = gru_release,
diff --git a/drivers/misc/sgi-xp/xpc_channel.c b/drivers/misc/sgi-xp/xpc_channel.c
index 05a890ce2ab8..8e6607fc8a67 100644
--- a/drivers/misc/sgi-xp/xpc_channel.c
+++ b/drivers/misc/sgi-xp/xpc_channel.c
@@ -28,7 +28,7 @@ xpc_process_connect(struct xpc_channel *ch, unsigned long *irq_flags)
{
enum xp_retval ret;
- DBUG_ON(!spin_is_locked(&ch->lock));
+ lockdep_assert_held(&ch->lock);
if (!(ch->flags & XPC_C_OPENREQUEST) ||
!(ch->flags & XPC_C_ROPENREQUEST)) {
@@ -82,7 +82,7 @@ xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags)
struct xpc_partition *part = &xpc_partitions[ch->partid];
u32 channel_was_connected = (ch->flags & XPC_C_WASCONNECTED);
- DBUG_ON(!spin_is_locked(&ch->lock));
+ lockdep_assert_held(&ch->lock);
if (!(ch->flags & XPC_C_DISCONNECTING))
return;
@@ -755,7 +755,7 @@ xpc_disconnect_channel(const int line, struct xpc_channel *ch,
{
u32 channel_was_connected = (ch->flags & XPC_C_CONNECTED);
- DBUG_ON(!spin_is_locked(&ch->lock));
+ lockdep_assert_held(&ch->lock);
if (ch->flags & (XPC_C_DISCONNECTING | XPC_C_DISCONNECTED))
return;
diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c
index 0c3ef6f1df54..3eba1c420cc0 100644
--- a/drivers/misc/sgi-xp/xpc_partition.c
+++ b/drivers/misc/sgi-xp/xpc_partition.c
@@ -98,8 +98,7 @@ xpc_get_rsvd_page_pa(int nasid)
len = L1_CACHE_ALIGN(len);
if (len > buf_len) {
- if (buf_base != NULL)
- kfree(buf_base);
+ kfree(buf_base);
buf_len = L1_CACHE_ALIGN(len);
buf = xpc_kmalloc_cacheline_aligned(buf_len, GFP_KERNEL,
&buf_base);
diff --git a/drivers/misc/sgi-xp/xpc_sn2.c b/drivers/misc/sgi-xp/xpc_sn2.c
index 5a12d2a54049..0ae69b9390ce 100644
--- a/drivers/misc/sgi-xp/xpc_sn2.c
+++ b/drivers/misc/sgi-xp/xpc_sn2.c
@@ -1671,7 +1671,7 @@ xpc_teardown_msg_structures_sn2(struct xpc_channel *ch)
{
struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
- DBUG_ON(!spin_is_locked(&ch->lock));
+ lockdep_assert_held(&ch->lock);
ch_sn2->remote_msgqueue_pa = 0;
diff --git a/drivers/misc/sgi-xp/xpc_uv.c b/drivers/misc/sgi-xp/xpc_uv.c
index 340b44d9e8cf..0441abe87880 100644
--- a/drivers/misc/sgi-xp/xpc_uv.c
+++ b/drivers/misc/sgi-xp/xpc_uv.c
@@ -1183,7 +1183,7 @@ xpc_teardown_msg_structures_uv(struct xpc_channel *ch)
{
struct xpc_channel_uv *ch_uv = &ch->sn.uv;
- DBUG_ON(!spin_is_locked(&ch->lock));
+ lockdep_assert_held(&ch->lock);
kfree(ch_uv->cached_notify_gru_mq_desc);
ch_uv->cached_notify_gru_mq_desc = NULL;
diff --git a/drivers/misc/sram.c b/drivers/misc/sram.c
index 74b183baf044..80d8cbe8c01a 100644
--- a/drivers/misc/sram.c
+++ b/drivers/misc/sram.c
@@ -323,10 +323,8 @@ static int sram_reserve_regions(struct sram_dev *sram, struct resource *res)
cur_start = block->start + block->size;
}
- err_chunks:
- if (child)
- of_node_put(child);
-
+err_chunks:
+ of_node_put(child);
kfree(rblocks);
return ret;
diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c
index 2543ef1ece17..9b0b3fa4f836 100644
--- a/drivers/misc/vmw_balloon.c
+++ b/drivers/misc/vmw_balloon.c
@@ -25,6 +25,9 @@
#include <linux/workqueue.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
+#include <linux/rwsem.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
#include <linux/vmw_vmci_defs.h>
#include <linux/vmw_vmci_api.h>
#include <asm/hypervisor.h>
@@ -37,20 +40,20 @@ MODULE_ALIAS("vmware_vmmemctl");
MODULE_LICENSE("GPL");
/*
- * Use __GFP_HIGHMEM to allow pages from HIGHMEM zone. We don't
- * allow wait (__GFP_RECLAIM) for NOSLEEP page allocations. Use
- * __GFP_NOWARN, to suppress page allocation failure warnings.
+ * Use __GFP_HIGHMEM to allow pages from HIGHMEM zone. We don't allow wait
+ * (__GFP_RECLAIM) for huge page allocations. Use __GFP_NOWARN, to suppress page
+ * allocation failure warnings. Disallow access to emergency low-memory pools.
*/
-#define VMW_PAGE_ALLOC_NOSLEEP (__GFP_HIGHMEM|__GFP_NOWARN)
+#define VMW_HUGE_PAGE_ALLOC_FLAGS (__GFP_HIGHMEM|__GFP_NOWARN| \
+ __GFP_NOMEMALLOC)
/*
- * Use GFP_HIGHUSER when executing in a separate kernel thread
- * context and allocation can sleep. This is less stressful to
- * the guest memory system, since it allows the thread to block
- * while memory is reclaimed, and won't take pages from emergency
- * low-memory pools.
+ * Use __GFP_HIGHMEM to allow pages from HIGHMEM zone. We allow lightweight
+ * reclamation (__GFP_NORETRY). Use __GFP_NOWARN, to suppress page allocation
+ * failure warnings. Disallow access to emergency low-memory pools.
*/
-#define VMW_PAGE_ALLOC_CANSLEEP (GFP_HIGHUSER)
+#define VMW_PAGE_ALLOC_FLAGS (__GFP_HIGHMEM|__GFP_NOWARN| \
+ __GFP_NOMEMALLOC|__GFP_NORETRY)
/* Maximum number of refused pages we accumulate during inflation cycle */
#define VMW_BALLOON_MAX_REFUSED 16
@@ -77,225 +80,420 @@ enum vmwballoon_capabilities {
| VMW_BALLOON_BATCHED_2M_CMDS \
| VMW_BALLOON_SIGNALLED_WAKEUP_CMD)
-#define VMW_BALLOON_2M_SHIFT (9)
-#define VMW_BALLOON_NUM_PAGE_SIZES (2)
+#define VMW_BALLOON_2M_ORDER (PMD_SHIFT - PAGE_SHIFT)
-/*
- * Backdoor commands availability:
- *
- * START, GET_TARGET and GUEST_ID are always available,
- *
- * VMW_BALLOON_BASIC_CMDS:
- * LOCK and UNLOCK commands,
- * VMW_BALLOON_BATCHED_CMDS:
- * BATCHED_LOCK and BATCHED_UNLOCK commands.
- * VMW BALLOON_BATCHED_2M_CMDS:
- * BATCHED_2M_LOCK and BATCHED_2M_UNLOCK commands,
- * VMW VMW_BALLOON_SIGNALLED_WAKEUP_CMD:
- * VMW_BALLOON_CMD_VMCI_DOORBELL_SET command.
- */
-#define VMW_BALLOON_CMD_START 0
-#define VMW_BALLOON_CMD_GET_TARGET 1
-#define VMW_BALLOON_CMD_LOCK 2
-#define VMW_BALLOON_CMD_UNLOCK 3
-#define VMW_BALLOON_CMD_GUEST_ID 4
-#define VMW_BALLOON_CMD_BATCHED_LOCK 6
-#define VMW_BALLOON_CMD_BATCHED_UNLOCK 7
-#define VMW_BALLOON_CMD_BATCHED_2M_LOCK 8
-#define VMW_BALLOON_CMD_BATCHED_2M_UNLOCK 9
-#define VMW_BALLOON_CMD_VMCI_DOORBELL_SET 10
-
-
-/* error codes */
-#define VMW_BALLOON_SUCCESS 0
-#define VMW_BALLOON_FAILURE -1
-#define VMW_BALLOON_ERROR_CMD_INVALID 1
-#define VMW_BALLOON_ERROR_PPN_INVALID 2
-#define VMW_BALLOON_ERROR_PPN_LOCKED 3
-#define VMW_BALLOON_ERROR_PPN_UNLOCKED 4
-#define VMW_BALLOON_ERROR_PPN_PINNED 5
-#define VMW_BALLOON_ERROR_PPN_NOTNEEDED 6
-#define VMW_BALLOON_ERROR_RESET 7
-#define VMW_BALLOON_ERROR_BUSY 8
+enum vmballoon_page_size_type {
+ VMW_BALLOON_4K_PAGE,
+ VMW_BALLOON_2M_PAGE,
+ VMW_BALLOON_LAST_SIZE = VMW_BALLOON_2M_PAGE
+};
-#define VMW_BALLOON_SUCCESS_WITH_CAPABILITIES (0x03000000)
+#define VMW_BALLOON_NUM_PAGE_SIZES (VMW_BALLOON_LAST_SIZE + 1)
-/* Batch page description */
+static const char * const vmballoon_page_size_names[] = {
+ [VMW_BALLOON_4K_PAGE] = "4k",
+ [VMW_BALLOON_2M_PAGE] = "2M"
+};
-/*
- * Layout of a page in the batch page:
+enum vmballoon_op {
+ VMW_BALLOON_INFLATE,
+ VMW_BALLOON_DEFLATE
+};
+
+enum vmballoon_op_stat_type {
+ VMW_BALLOON_OP_STAT,
+ VMW_BALLOON_OP_FAIL_STAT
+};
+
+#define VMW_BALLOON_OP_STAT_TYPES (VMW_BALLOON_OP_FAIL_STAT + 1)
+
+/**
+ * enum vmballoon_cmd_type - backdoor commands.
*
- * +-------------+----------+--------+
- * | | | |
- * | Page number | Reserved | Status |
- * | | | |
- * +-------------+----------+--------+
- * 64 PAGE_SHIFT 6 0
+ * Availability of the commands is as followed:
*
- * The reserved field should be set to 0.
+ * %VMW_BALLOON_CMD_START, %VMW_BALLOON_CMD_GET_TARGET and
+ * %VMW_BALLOON_CMD_GUEST_ID are always available.
+ *
+ * If the host reports %VMW_BALLOON_BASIC_CMDS are supported then
+ * %VMW_BALLOON_CMD_LOCK and %VMW_BALLOON_CMD_UNLOCK commands are available.
+ *
+ * If the host reports %VMW_BALLOON_BATCHED_CMDS are supported then
+ * %VMW_BALLOON_CMD_BATCHED_LOCK and VMW_BALLOON_CMD_BATCHED_UNLOCK commands
+ * are available.
+ *
+ * If the host reports %VMW_BALLOON_BATCHED_2M_CMDS are supported then
+ * %VMW_BALLOON_CMD_BATCHED_2M_LOCK and %VMW_BALLOON_CMD_BATCHED_2M_UNLOCK
+ * are supported.
+ *
+ * If the host reports VMW_BALLOON_SIGNALLED_WAKEUP_CMD is supported then
+ * VMW_BALLOON_CMD_VMCI_DOORBELL_SET command is supported.
+ *
+ * @VMW_BALLOON_CMD_START: Communicating supported version with the hypervisor.
+ * @VMW_BALLOON_CMD_GET_TARGET: Gets the balloon target size.
+ * @VMW_BALLOON_CMD_LOCK: Informs the hypervisor about a ballooned page.
+ * @VMW_BALLOON_CMD_UNLOCK: Informs the hypervisor about a page that is about
+ * to be deflated from the balloon.
+ * @VMW_BALLOON_CMD_GUEST_ID: Informs the hypervisor about the type of OS that
+ * runs in the VM.
+ * @VMW_BALLOON_CMD_BATCHED_LOCK: Inform the hypervisor about a batch of
+ * ballooned pages (up to 512).
+ * @VMW_BALLOON_CMD_BATCHED_UNLOCK: Inform the hypervisor about a batch of
+ * pages that are about to be deflated from the
+ * balloon (up to 512).
+ * @VMW_BALLOON_CMD_BATCHED_2M_LOCK: Similar to @VMW_BALLOON_CMD_BATCHED_LOCK
+ * for 2MB pages.
+ * @VMW_BALLOON_CMD_BATCHED_2M_UNLOCK: Similar to
+ * @VMW_BALLOON_CMD_BATCHED_UNLOCK for 2MB
+ * pages.
+ * @VMW_BALLOON_CMD_VMCI_DOORBELL_SET: A command to set doorbell notification
+ * that would be invoked when the balloon
+ * size changes.
+ * @VMW_BALLOON_CMD_LAST: Value of the last command.
*/
-#define VMW_BALLOON_BATCH_MAX_PAGES (PAGE_SIZE / sizeof(u64))
-#define VMW_BALLOON_BATCH_STATUS_MASK ((1UL << 5) - 1)
-#define VMW_BALLOON_BATCH_PAGE_MASK (~((1UL << PAGE_SHIFT) - 1))
-
-struct vmballoon_batch_page {
- u64 pages[VMW_BALLOON_BATCH_MAX_PAGES];
+enum vmballoon_cmd_type {
+ VMW_BALLOON_CMD_START,
+ VMW_BALLOON_CMD_GET_TARGET,
+ VMW_BALLOON_CMD_LOCK,
+ VMW_BALLOON_CMD_UNLOCK,
+ VMW_BALLOON_CMD_GUEST_ID,
+ /* No command 5 */
+ VMW_BALLOON_CMD_BATCHED_LOCK = 6,
+ VMW_BALLOON_CMD_BATCHED_UNLOCK,
+ VMW_BALLOON_CMD_BATCHED_2M_LOCK,
+ VMW_BALLOON_CMD_BATCHED_2M_UNLOCK,
+ VMW_BALLOON_CMD_VMCI_DOORBELL_SET,
+ VMW_BALLOON_CMD_LAST = VMW_BALLOON_CMD_VMCI_DOORBELL_SET,
};
-static u64 vmballoon_batch_get_pa(struct vmballoon_batch_page *batch, int idx)
-{
- return batch->pages[idx] & VMW_BALLOON_BATCH_PAGE_MASK;
-}
+#define VMW_BALLOON_CMD_NUM (VMW_BALLOON_CMD_LAST + 1)
+
+enum vmballoon_error_codes {
+ VMW_BALLOON_SUCCESS,
+ VMW_BALLOON_ERROR_CMD_INVALID,
+ VMW_BALLOON_ERROR_PPN_INVALID,
+ VMW_BALLOON_ERROR_PPN_LOCKED,
+ VMW_BALLOON_ERROR_PPN_UNLOCKED,
+ VMW_BALLOON_ERROR_PPN_PINNED,
+ VMW_BALLOON_ERROR_PPN_NOTNEEDED,
+ VMW_BALLOON_ERROR_RESET,
+ VMW_BALLOON_ERROR_BUSY
+};
-static int vmballoon_batch_get_status(struct vmballoon_batch_page *batch,
- int idx)
-{
- return (int)(batch->pages[idx] & VMW_BALLOON_BATCH_STATUS_MASK);
-}
+#define VMW_BALLOON_SUCCESS_WITH_CAPABILITIES (0x03000000)
-static void vmballoon_batch_set_pa(struct vmballoon_batch_page *batch, int idx,
- u64 pa)
-{
- batch->pages[idx] = pa;
-}
+#define VMW_BALLOON_CMD_WITH_TARGET_MASK \
+ ((1UL << VMW_BALLOON_CMD_GET_TARGET) | \
+ (1UL << VMW_BALLOON_CMD_LOCK) | \
+ (1UL << VMW_BALLOON_CMD_UNLOCK) | \
+ (1UL << VMW_BALLOON_CMD_BATCHED_LOCK) | \
+ (1UL << VMW_BALLOON_CMD_BATCHED_UNLOCK) | \
+ (1UL << VMW_BALLOON_CMD_BATCHED_2M_LOCK) | \
+ (1UL << VMW_BALLOON_CMD_BATCHED_2M_UNLOCK))
+
+static const char * const vmballoon_cmd_names[] = {
+ [VMW_BALLOON_CMD_START] = "start",
+ [VMW_BALLOON_CMD_GET_TARGET] = "target",
+ [VMW_BALLOON_CMD_LOCK] = "lock",
+ [VMW_BALLOON_CMD_UNLOCK] = "unlock",
+ [VMW_BALLOON_CMD_GUEST_ID] = "guestType",
+ [VMW_BALLOON_CMD_BATCHED_LOCK] = "batchLock",
+ [VMW_BALLOON_CMD_BATCHED_UNLOCK] = "batchUnlock",
+ [VMW_BALLOON_CMD_BATCHED_2M_LOCK] = "2m-lock",
+ [VMW_BALLOON_CMD_BATCHED_2M_UNLOCK] = "2m-unlock",
+ [VMW_BALLOON_CMD_VMCI_DOORBELL_SET] = "doorbellSet"
+};
+enum vmballoon_stat_page {
+ VMW_BALLOON_PAGE_STAT_ALLOC,
+ VMW_BALLOON_PAGE_STAT_ALLOC_FAIL,
+ VMW_BALLOON_PAGE_STAT_REFUSED_ALLOC,
+ VMW_BALLOON_PAGE_STAT_REFUSED_FREE,
+ VMW_BALLOON_PAGE_STAT_FREE,
+ VMW_BALLOON_PAGE_STAT_LAST = VMW_BALLOON_PAGE_STAT_FREE
+};
-#define VMWARE_BALLOON_CMD(cmd, arg1, arg2, result) \
-({ \
- unsigned long __status, __dummy1, __dummy2, __dummy3; \
- __asm__ __volatile__ ("inl %%dx" : \
- "=a"(__status), \
- "=c"(__dummy1), \
- "=d"(__dummy2), \
- "=b"(result), \
- "=S" (__dummy3) : \
- "0"(VMW_BALLOON_HV_MAGIC), \
- "1"(VMW_BALLOON_CMD_##cmd), \
- "2"(VMW_BALLOON_HV_PORT), \
- "3"(arg1), \
- "4" (arg2) : \
- "memory"); \
- if (VMW_BALLOON_CMD_##cmd == VMW_BALLOON_CMD_START) \
- result = __dummy1; \
- result &= -1UL; \
- __status & -1UL; \
-})
+#define VMW_BALLOON_PAGE_STAT_NUM (VMW_BALLOON_PAGE_STAT_LAST + 1)
-#ifdef CONFIG_DEBUG_FS
-struct vmballoon_stats {
- unsigned int timer;
- unsigned int doorbell;
-
- /* allocation statistics */
- unsigned int alloc[VMW_BALLOON_NUM_PAGE_SIZES];
- unsigned int alloc_fail[VMW_BALLOON_NUM_PAGE_SIZES];
- unsigned int sleep_alloc;
- unsigned int sleep_alloc_fail;
- unsigned int refused_alloc[VMW_BALLOON_NUM_PAGE_SIZES];
- unsigned int refused_free[VMW_BALLOON_NUM_PAGE_SIZES];
- unsigned int free[VMW_BALLOON_NUM_PAGE_SIZES];
-
- /* monitor operations */
- unsigned int lock[VMW_BALLOON_NUM_PAGE_SIZES];
- unsigned int lock_fail[VMW_BALLOON_NUM_PAGE_SIZES];
- unsigned int unlock[VMW_BALLOON_NUM_PAGE_SIZES];
- unsigned int unlock_fail[VMW_BALLOON_NUM_PAGE_SIZES];
- unsigned int target;
- unsigned int target_fail;
- unsigned int start;
- unsigned int start_fail;
- unsigned int guest_type;
- unsigned int guest_type_fail;
- unsigned int doorbell_set;
- unsigned int doorbell_unset;
+enum vmballoon_stat_general {
+ VMW_BALLOON_STAT_TIMER,
+ VMW_BALLOON_STAT_DOORBELL,
+ VMW_BALLOON_STAT_RESET,
+ VMW_BALLOON_STAT_LAST = VMW_BALLOON_STAT_RESET
};
-#define STATS_INC(stat) (stat)++
-#else
-#define STATS_INC(stat)
-#endif
+#define VMW_BALLOON_STAT_NUM (VMW_BALLOON_STAT_LAST + 1)
-struct vmballoon;
-struct vmballoon_ops {
- void (*add_page)(struct vmballoon *b, int idx, struct page *p);
- int (*lock)(struct vmballoon *b, unsigned int num_pages,
- bool is_2m_pages, unsigned int *target);
- int (*unlock)(struct vmballoon *b, unsigned int num_pages,
- bool is_2m_pages, unsigned int *target);
+static DEFINE_STATIC_KEY_TRUE(vmw_balloon_batching);
+static DEFINE_STATIC_KEY_FALSE(balloon_stat_enabled);
+
+struct vmballoon_ctl {
+ struct list_head pages;
+ struct list_head refused_pages;
+ unsigned int n_refused_pages;
+ unsigned int n_pages;
+ enum vmballoon_page_size_type page_size;
+ enum vmballoon_op op;
};
struct vmballoon_page_size {
/* list of reserved physical pages */
struct list_head pages;
-
- /* transient list of non-balloonable pages */
- struct list_head refused_pages;
- unsigned int n_refused_pages;
};
+/**
+ * struct vmballoon_batch_entry - a batch entry for lock or unlock.
+ *
+ * @status: the status of the operation, which is written by the hypervisor.
+ * @reserved: reserved for future use. Must be set to zero.
+ * @pfn: the physical frame number of the page to be locked or unlocked.
+ */
+struct vmballoon_batch_entry {
+ u64 status : 5;
+ u64 reserved : PAGE_SHIFT - 5;
+ u64 pfn : 52;
+} __packed;
+
struct vmballoon {
struct vmballoon_page_size page_sizes[VMW_BALLOON_NUM_PAGE_SIZES];
- /* supported page sizes. 1 == 4k pages only, 2 == 4k and 2m pages */
- unsigned supported_page_sizes;
+ /**
+ * @max_page_size: maximum supported page size for ballooning.
+ *
+ * Protected by @conf_sem
+ */
+ enum vmballoon_page_size_type max_page_size;
+
+ /**
+ * @size: balloon actual size in basic page size (frames).
+ *
+ * While we currently do not support size which is bigger than 32-bit,
+ * in preparation for future support, use 64-bits.
+ */
+ atomic64_t size;
- /* balloon size in pages */
- unsigned int size;
- unsigned int target;
+ /**
+ * @target: balloon target size in basic page size (frames).
+ *
+ * We do not protect the target under the assumption that setting the
+ * value is always done through a single write. If this assumption ever
+ * breaks, we would have to use X_ONCE for accesses, and suffer the less
+ * optimized code. Although we may read stale target value if multiple
+ * accesses happen at once, the performance impact should be minor.
+ */
+ unsigned long target;
- /* reset flag */
+ /**
+ * @reset_required: reset flag
+ *
+ * Setting this flag may introduce races, but the code is expected to
+ * handle them gracefully. In the worst case, another operation will
+ * fail as reset did not take place. Clearing the flag is done while
+ * holding @conf_sem for write.
+ */
bool reset_required;
+ /**
+ * @capabilities: hypervisor balloon capabilities.
+ *
+ * Protected by @conf_sem.
+ */
unsigned long capabilities;
- struct vmballoon_batch_page *batch_page;
+ /**
+ * @batch_page: pointer to communication batch page.
+ *
+ * When batching is used, batch_page points to a page, which holds up to
+ * %VMW_BALLOON_BATCH_MAX_PAGES entries for locking or unlocking.
+ */
+ struct vmballoon_batch_entry *batch_page;
+
+ /**
+ * @batch_max_pages: maximum pages that can be locked/unlocked.
+ *
+ * Indicates the number of pages that the hypervisor can lock or unlock
+ * at once, according to whether batching is enabled. If batching is
+ * disabled, only a single page can be locked/unlock on each operation.
+ *
+ * Protected by @conf_sem.
+ */
unsigned int batch_max_pages;
- struct page *page;
- const struct vmballoon_ops *ops;
+ /**
+ * @page: page to be locked/unlocked by the hypervisor
+ *
+ * @page is only used when batching is disabled and a single page is
+ * reclaimed on each iteration.
+ *
+ * Protected by @comm_lock.
+ */
+ struct page *page;
-#ifdef CONFIG_DEBUG_FS
/* statistics */
- struct vmballoon_stats stats;
+ struct vmballoon_stats *stats;
+#ifdef CONFIG_DEBUG_FS
/* debugfs file exporting statistics */
struct dentry *dbg_entry;
#endif
- struct sysinfo sysinfo;
-
struct delayed_work dwork;
+ /**
+ * @vmci_doorbell.
+ *
+ * Protected by @conf_sem.
+ */
struct vmci_handle vmci_doorbell;
+
+ /**
+ * @conf_sem: semaphore to protect the configuration and the statistics.
+ */
+ struct rw_semaphore conf_sem;
+
+ /**
+ * @comm_lock: lock to protect the communication with the host.
+ *
+ * Lock ordering: @conf_sem -> @comm_lock .
+ */
+ spinlock_t comm_lock;
};
static struct vmballoon balloon;
+struct vmballoon_stats {
+ /* timer / doorbell operations */
+ atomic64_t general_stat[VMW_BALLOON_STAT_NUM];
+
+ /* allocation statistics for huge and small pages */
+ atomic64_t
+ page_stat[VMW_BALLOON_PAGE_STAT_NUM][VMW_BALLOON_NUM_PAGE_SIZES];
+
+ /* Monitor operations: total operations, and failures */
+ atomic64_t ops[VMW_BALLOON_CMD_NUM][VMW_BALLOON_OP_STAT_TYPES];
+};
+
+static inline bool is_vmballoon_stats_on(void)
+{
+ return IS_ENABLED(CONFIG_DEBUG_FS) &&
+ static_branch_unlikely(&balloon_stat_enabled);
+}
+
+static inline void vmballoon_stats_op_inc(struct vmballoon *b, unsigned int op,
+ enum vmballoon_op_stat_type type)
+{
+ if (is_vmballoon_stats_on())
+ atomic64_inc(&b->stats->ops[op][type]);
+}
+
+static inline void vmballoon_stats_gen_inc(struct vmballoon *b,
+ enum vmballoon_stat_general stat)
+{
+ if (is_vmballoon_stats_on())
+ atomic64_inc(&b->stats->general_stat[stat]);
+}
+
+static inline void vmballoon_stats_gen_add(struct vmballoon *b,
+ enum vmballoon_stat_general stat,
+ unsigned int val)
+{
+ if (is_vmballoon_stats_on())
+ atomic64_add(val, &b->stats->general_stat[stat]);
+}
+
+static inline void vmballoon_stats_page_inc(struct vmballoon *b,
+ enum vmballoon_stat_page stat,
+ enum vmballoon_page_size_type size)
+{
+ if (is_vmballoon_stats_on())
+ atomic64_inc(&b->stats->page_stat[stat][size]);
+}
+
+static inline void vmballoon_stats_page_add(struct vmballoon *b,
+ enum vmballoon_stat_page stat,
+ enum vmballoon_page_size_type size,
+ unsigned int val)
+{
+ if (is_vmballoon_stats_on())
+ atomic64_add(val, &b->stats->page_stat[stat][size]);
+}
+
+static inline unsigned long
+__vmballoon_cmd(struct vmballoon *b, unsigned long cmd, unsigned long arg1,
+ unsigned long arg2, unsigned long *result)
+{
+ unsigned long status, dummy1, dummy2, dummy3, local_result;
+
+ vmballoon_stats_op_inc(b, cmd, VMW_BALLOON_OP_STAT);
+
+ asm volatile ("inl %%dx" :
+ "=a"(status),
+ "=c"(dummy1),
+ "=d"(dummy2),
+ "=b"(local_result),
+ "=S"(dummy3) :
+ "0"(VMW_BALLOON_HV_MAGIC),
+ "1"(cmd),
+ "2"(VMW_BALLOON_HV_PORT),
+ "3"(arg1),
+ "4"(arg2) :
+ "memory");
+
+ /* update the result if needed */
+ if (result)
+ *result = (cmd == VMW_BALLOON_CMD_START) ? dummy1 :
+ local_result;
+
+ /* update target when applicable */
+ if (status == VMW_BALLOON_SUCCESS &&
+ ((1ul << cmd) & VMW_BALLOON_CMD_WITH_TARGET_MASK))
+ WRITE_ONCE(b->target, local_result);
+
+ if (status != VMW_BALLOON_SUCCESS &&
+ status != VMW_BALLOON_SUCCESS_WITH_CAPABILITIES) {
+ vmballoon_stats_op_inc(b, cmd, VMW_BALLOON_OP_FAIL_STAT);
+ pr_debug("%s: %s [0x%lx,0x%lx) failed, returned %ld\n",
+ __func__, vmballoon_cmd_names[cmd], arg1, arg2,
+ status);
+ }
+
+ /* mark reset required accordingly */
+ if (status == VMW_BALLOON_ERROR_RESET)
+ b->reset_required = true;
+
+ return status;
+}
+
+static __always_inline unsigned long
+vmballoon_cmd(struct vmballoon *b, unsigned long cmd, unsigned long arg1,
+ unsigned long arg2)
+{
+ unsigned long dummy;
+
+ return __vmballoon_cmd(b, cmd, arg1, arg2, &dummy);
+}
+
/*
* Send "start" command to the host, communicating supported version
* of the protocol.
*/
-static bool vmballoon_send_start(struct vmballoon *b, unsigned long req_caps)
+static int vmballoon_send_start(struct vmballoon *b, unsigned long req_caps)
{
- unsigned long status, capabilities, dummy = 0;
- bool success;
-
- STATS_INC(b->stats.start);
+ unsigned long status, capabilities;
- status = VMWARE_BALLOON_CMD(START, req_caps, dummy, capabilities);
+ status = __vmballoon_cmd(b, VMW_BALLOON_CMD_START, req_caps, 0,
+ &capabilities);
switch (status) {
case VMW_BALLOON_SUCCESS_WITH_CAPABILITIES:
b->capabilities = capabilities;
- success = true;
break;
case VMW_BALLOON_SUCCESS:
b->capabilities = VMW_BALLOON_BASIC_CMDS;
- success = true;
break;
default:
- success = false;
+ return -EIO;
}
/*
@@ -303,626 +501,693 @@ static bool vmballoon_send_start(struct vmballoon *b, unsigned long req_caps)
* reason disabled, do not use 2MB pages, since otherwise the legacy
* mechanism is used with 2MB pages, causing a failure.
*/
+ b->max_page_size = VMW_BALLOON_4K_PAGE;
if ((b->capabilities & VMW_BALLOON_BATCHED_2M_CMDS) &&
(b->capabilities & VMW_BALLOON_BATCHED_CMDS))
- b->supported_page_sizes = 2;
- else
- b->supported_page_sizes = 1;
-
- if (!success) {
- pr_debug("%s - failed, hv returns %ld\n", __func__, status);
- STATS_INC(b->stats.start_fail);
- }
- return success;
-}
+ b->max_page_size = VMW_BALLOON_2M_PAGE;
-static bool vmballoon_check_status(struct vmballoon *b, unsigned long status)
-{
- switch (status) {
- case VMW_BALLOON_SUCCESS:
- return true;
- case VMW_BALLOON_ERROR_RESET:
- b->reset_required = true;
- /* fall through */
-
- default:
- return false;
- }
+ return 0;
}
-/*
+/**
+ * vmballoon_send_guest_id - communicate guest type to the host.
+ *
+ * @b: pointer to the balloon.
+ *
* Communicate guest type to the host so that it can adjust ballooning
* algorithm to the one most appropriate for the guest. This command
* is normally issued after sending "start" command and is part of
* standard reset sequence.
+ *
+ * Return: zero on success or appropriate error code.
*/
-static bool vmballoon_send_guest_id(struct vmballoon *b)
+static int vmballoon_send_guest_id(struct vmballoon *b)
{
- unsigned long status, dummy = 0;
-
- status = VMWARE_BALLOON_CMD(GUEST_ID, VMW_BALLOON_GUEST_ID, dummy,
- dummy);
-
- STATS_INC(b->stats.guest_type);
+ unsigned long status;
- if (vmballoon_check_status(b, status))
- return true;
+ status = vmballoon_cmd(b, VMW_BALLOON_CMD_GUEST_ID,
+ VMW_BALLOON_GUEST_ID, 0);
- pr_debug("%s - failed, hv returns %ld\n", __func__, status);
- STATS_INC(b->stats.guest_type_fail);
- return false;
+ return status == VMW_BALLOON_SUCCESS ? 0 : -EIO;
}
-static u16 vmballoon_page_size(bool is_2m_page)
+/**
+ * vmballoon_page_order() - return the order of the page
+ * @page_size: the size of the page.
+ *
+ * Return: the allocation order.
+ */
+static inline
+unsigned int vmballoon_page_order(enum vmballoon_page_size_type page_size)
{
- if (is_2m_page)
- return 1 << VMW_BALLOON_2M_SHIFT;
+ return page_size == VMW_BALLOON_2M_PAGE ? VMW_BALLOON_2M_ORDER : 0;
+}
- return 1;
+/**
+ * vmballoon_page_in_frames() - returns the number of frames in a page.
+ * @page_size: the size of the page.
+ *
+ * Return: the number of 4k frames.
+ */
+static inline unsigned int
+vmballoon_page_in_frames(enum vmballoon_page_size_type page_size)
+{
+ return 1 << vmballoon_page_order(page_size);
}
-/*
- * Retrieve desired balloon size from the host.
+/**
+ * vmballoon_send_get_target() - Retrieve desired balloon size from the host.
+ *
+ * @b: pointer to the balloon.
+ *
+ * Return: zero on success, EINVAL if limit does not fit in 32-bit, as required
+ * by the host-guest protocol and EIO if an error occurred in communicating with
+ * the host.
*/
-static bool vmballoon_send_get_target(struct vmballoon *b, u32 *new_target)
+static int vmballoon_send_get_target(struct vmballoon *b)
{
unsigned long status;
- unsigned long target;
unsigned long limit;
- unsigned long dummy = 0;
- u32 limit32;
- /*
- * si_meminfo() is cheap. Moreover, we want to provide dynamic
- * max balloon size later. So let us call si_meminfo() every
- * iteration.
- */
- si_meminfo(&b->sysinfo);
- limit = b->sysinfo.totalram;
+ limit = totalram_pages;
/* Ensure limit fits in 32-bits */
- limit32 = (u32)limit;
- if (limit != limit32)
- return false;
-
- /* update stats */
- STATS_INC(b->stats.target);
+ if (limit != (u32)limit)
+ return -EINVAL;
- status = VMWARE_BALLOON_CMD(GET_TARGET, limit, dummy, target);
- if (vmballoon_check_status(b, status)) {
- *new_target = target;
- return true;
- }
+ status = vmballoon_cmd(b, VMW_BALLOON_CMD_GET_TARGET, limit, 0);
- pr_debug("%s - failed, hv returns %ld\n", __func__, status);
- STATS_INC(b->stats.target_fail);
- return false;
+ return status == VMW_BALLOON_SUCCESS ? 0 : -EIO;
}
-/*
- * Notify the host about allocated page so that host can use it without
- * fear that guest will need it. Host may reject some pages, we need to
- * check the return value and maybe submit a different page.
+/**
+ * vmballoon_alloc_page_list - allocates a list of pages.
+ *
+ * @b: pointer to the balloon.
+ * @ctl: pointer for the %struct vmballoon_ctl, which defines the operation.
+ * @req_n_pages: the number of requested pages.
+ *
+ * Tries to allocate @req_n_pages. Add them to the list of balloon pages in
+ * @ctl.pages and updates @ctl.n_pages to reflect the number of pages.
+ *
+ * Return: zero on success or error code otherwise.
*/
-static int vmballoon_send_lock_page(struct vmballoon *b, unsigned long pfn,
- unsigned int *hv_status, unsigned int *target)
+static int vmballoon_alloc_page_list(struct vmballoon *b,
+ struct vmballoon_ctl *ctl,
+ unsigned int req_n_pages)
{
- unsigned long status, dummy = 0;
- u32 pfn32;
-
- pfn32 = (u32)pfn;
- if (pfn32 != pfn)
- return -EINVAL;
-
- STATS_INC(b->stats.lock[false]);
+ struct page *page;
+ unsigned int i;
- *hv_status = status = VMWARE_BALLOON_CMD(LOCK, pfn, dummy, *target);
- if (vmballoon_check_status(b, status))
- return 0;
+ for (i = 0; i < req_n_pages; i++) {
+ if (ctl->page_size == VMW_BALLOON_2M_PAGE)
+ page = alloc_pages(VMW_HUGE_PAGE_ALLOC_FLAGS,
+ VMW_BALLOON_2M_ORDER);
+ else
+ page = alloc_page(VMW_PAGE_ALLOC_FLAGS);
- pr_debug("%s - ppn %lx, hv returns %ld\n", __func__, pfn, status);
- STATS_INC(b->stats.lock_fail[false]);
- return -EIO;
-}
+ /* Update statistics */
+ vmballoon_stats_page_inc(b, VMW_BALLOON_PAGE_STAT_ALLOC,
+ ctl->page_size);
-static int vmballoon_send_batched_lock(struct vmballoon *b,
- unsigned int num_pages, bool is_2m_pages, unsigned int *target)
-{
- unsigned long status;
- unsigned long pfn = PHYS_PFN(virt_to_phys(b->batch_page));
+ if (page) {
+ /* Success. Add the page to the list and continue. */
+ list_add(&page->lru, &ctl->pages);
+ continue;
+ }
- STATS_INC(b->stats.lock[is_2m_pages]);
+ /* Allocation failed. Update statistics and stop. */
+ vmballoon_stats_page_inc(b, VMW_BALLOON_PAGE_STAT_ALLOC_FAIL,
+ ctl->page_size);
+ break;
+ }
- if (is_2m_pages)
- status = VMWARE_BALLOON_CMD(BATCHED_2M_LOCK, pfn, num_pages,
- *target);
- else
- status = VMWARE_BALLOON_CMD(BATCHED_LOCK, pfn, num_pages,
- *target);
+ ctl->n_pages = i;
- if (vmballoon_check_status(b, status))
- return 0;
-
- pr_debug("%s - batch ppn %lx, hv returns %ld\n", __func__, pfn, status);
- STATS_INC(b->stats.lock_fail[is_2m_pages]);
- return 1;
+ return req_n_pages == ctl->n_pages ? 0 : -ENOMEM;
}
-/*
- * Notify the host that guest intends to release given page back into
- * the pool of available (to the guest) pages.
+/**
+ * vmballoon_handle_one_result - Handle lock/unlock result for a single page.
+ *
+ * @b: pointer for %struct vmballoon.
+ * @page: pointer for the page whose result should be handled.
+ * @page_size: size of the page.
+ * @status: status of the operation as provided by the hypervisor.
*/
-static bool vmballoon_send_unlock_page(struct vmballoon *b, unsigned long pfn,
- unsigned int *target)
+static int vmballoon_handle_one_result(struct vmballoon *b, struct page *page,
+ enum vmballoon_page_size_type page_size,
+ unsigned long status)
{
- unsigned long status, dummy = 0;
- u32 pfn32;
-
- pfn32 = (u32)pfn;
- if (pfn32 != pfn)
- return false;
+ /* On success do nothing. The page is already on the balloon list. */
+ if (likely(status == VMW_BALLOON_SUCCESS))
+ return 0;
- STATS_INC(b->stats.unlock[false]);
+ pr_debug("%s: failed comm pfn %lx status %lu page_size %s\n", __func__,
+ page_to_pfn(page), status,
+ vmballoon_page_size_names[page_size]);
- status = VMWARE_BALLOON_CMD(UNLOCK, pfn, dummy, *target);
- if (vmballoon_check_status(b, status))
- return true;
+ /* Error occurred */
+ vmballoon_stats_page_inc(b, VMW_BALLOON_PAGE_STAT_REFUSED_ALLOC,
+ page_size);
- pr_debug("%s - ppn %lx, hv returns %ld\n", __func__, pfn, status);
- STATS_INC(b->stats.unlock_fail[false]);
- return false;
+ return -EIO;
}
-static bool vmballoon_send_batched_unlock(struct vmballoon *b,
- unsigned int num_pages, bool is_2m_pages, unsigned int *target)
+/**
+ * vmballoon_status_page - returns the status of (un)lock operation
+ *
+ * @b: pointer to the balloon.
+ * @idx: index for the page for which the operation is performed.
+ * @p: pointer to where the page struct is returned.
+ *
+ * Following a lock or unlock operation, returns the status of the operation for
+ * an individual page. Provides the page that the operation was performed on on
+ * the @page argument.
+ *
+ * Returns: The status of a lock or unlock operation for an individual page.
+ */
+static unsigned long vmballoon_status_page(struct vmballoon *b, int idx,
+ struct page **p)
{
- unsigned long status;
- unsigned long pfn = PHYS_PFN(virt_to_phys(b->batch_page));
-
- STATS_INC(b->stats.unlock[is_2m_pages]);
-
- if (is_2m_pages)
- status = VMWARE_BALLOON_CMD(BATCHED_2M_UNLOCK, pfn, num_pages,
- *target);
- else
- status = VMWARE_BALLOON_CMD(BATCHED_UNLOCK, pfn, num_pages,
- *target);
+ if (static_branch_likely(&vmw_balloon_batching)) {
+ /* batching mode */
+ *p = pfn_to_page(b->batch_page[idx].pfn);
+ return b->batch_page[idx].status;
+ }
- if (vmballoon_check_status(b, status))
- return true;
+ /* non-batching mode */
+ *p = b->page;
- pr_debug("%s - batch ppn %lx, hv returns %ld\n", __func__, pfn, status);
- STATS_INC(b->stats.unlock_fail[is_2m_pages]);
- return false;
+ /*
+ * If a failure occurs, the indication will be provided in the status
+ * of the entire operation, which is considered before the individual
+ * page status. So for non-batching mode, the indication is always of
+ * success.
+ */
+ return VMW_BALLOON_SUCCESS;
}
-static struct page *vmballoon_alloc_page(gfp_t flags, bool is_2m_page)
+/**
+ * vmballoon_lock_op - notifies the host about inflated/deflated pages.
+ * @b: pointer to the balloon.
+ * @num_pages: number of inflated/deflated pages.
+ * @page_size: size of the page.
+ * @op: the type of operation (lock or unlock).
+ *
+ * Notify the host about page(s) that were ballooned (or removed from the
+ * balloon) so that host can use it without fear that guest will need it (or
+ * stop using them since the VM does). Host may reject some pages, we need to
+ * check the return value and maybe submit a different page. The pages that are
+ * inflated/deflated are pointed by @b->page.
+ *
+ * Return: result as provided by the hypervisor.
+ */
+static unsigned long vmballoon_lock_op(struct vmballoon *b,
+ unsigned int num_pages,
+ enum vmballoon_page_size_type page_size,
+ enum vmballoon_op op)
{
- if (is_2m_page)
- return alloc_pages(flags, VMW_BALLOON_2M_SHIFT);
+ unsigned long cmd, pfn;
- return alloc_page(flags);
-}
+ lockdep_assert_held(&b->comm_lock);
-static void vmballoon_free_page(struct page *page, bool is_2m_page)
-{
- if (is_2m_page)
- __free_pages(page, VMW_BALLOON_2M_SHIFT);
- else
- __free_page(page);
+ if (static_branch_likely(&vmw_balloon_batching)) {
+ if (op == VMW_BALLOON_INFLATE)
+ cmd = page_size == VMW_BALLOON_2M_PAGE ?
+ VMW_BALLOON_CMD_BATCHED_2M_LOCK :
+ VMW_BALLOON_CMD_BATCHED_LOCK;
+ else
+ cmd = page_size == VMW_BALLOON_2M_PAGE ?
+ VMW_BALLOON_CMD_BATCHED_2M_UNLOCK :
+ VMW_BALLOON_CMD_BATCHED_UNLOCK;
+
+ pfn = PHYS_PFN(virt_to_phys(b->batch_page));
+ } else {
+ cmd = op == VMW_BALLOON_INFLATE ? VMW_BALLOON_CMD_LOCK :
+ VMW_BALLOON_CMD_UNLOCK;
+ pfn = page_to_pfn(b->page);
+
+ /* In non-batching mode, PFNs must fit in 32-bit */
+ if (unlikely(pfn != (u32)pfn))
+ return VMW_BALLOON_ERROR_PPN_INVALID;
+ }
+
+ return vmballoon_cmd(b, cmd, pfn, num_pages);
}
-/*
- * Quickly release all pages allocated for the balloon. This function is
- * called when host decides to "reset" balloon for one reason or another.
- * Unlike normal "deflate" we do not (shall not) notify host of the pages
- * being released.
+/**
+ * vmballoon_add_page - adds a page towards lock/unlock operation.
+ *
+ * @b: pointer to the balloon.
+ * @idx: index of the page to be ballooned in this batch.
+ * @p: pointer to the page that is about to be ballooned.
+ *
+ * Adds the page to be ballooned. Must be called while holding @comm_lock.
*/
-static void vmballoon_pop(struct vmballoon *b)
+static void vmballoon_add_page(struct vmballoon *b, unsigned int idx,
+ struct page *p)
{
- struct page *page, *next;
- unsigned is_2m_pages;
-
- for (is_2m_pages = 0; is_2m_pages < VMW_BALLOON_NUM_PAGE_SIZES;
- is_2m_pages++) {
- struct vmballoon_page_size *page_size =
- &b->page_sizes[is_2m_pages];
- u16 size_per_page = vmballoon_page_size(is_2m_pages);
-
- list_for_each_entry_safe(page, next, &page_size->pages, lru) {
- list_del(&page->lru);
- vmballoon_free_page(page, is_2m_pages);
- STATS_INC(b->stats.free[is_2m_pages]);
- b->size -= size_per_page;
- cond_resched();
- }
- }
+ lockdep_assert_held(&b->comm_lock);
- /* Clearing the batch_page unconditionally has no adverse effect */
- free_page((unsigned long)b->batch_page);
- b->batch_page = NULL;
+ if (static_branch_likely(&vmw_balloon_batching))
+ b->batch_page[idx] = (struct vmballoon_batch_entry)
+ { .pfn = page_to_pfn(p) };
+ else
+ b->page = p;
}
-/*
- * Notify the host of a ballooned page. If host rejects the page put it on the
- * refuse list, those refused page are then released at the end of the
- * inflation cycle.
+/**
+ * vmballoon_lock - lock or unlock a batch of pages.
+ *
+ * @b: pointer to the balloon.
+ * @ctl: pointer for the %struct vmballoon_ctl, which defines the operation.
+ *
+ * Notifies the host of about ballooned pages (after inflation or deflation,
+ * according to @ctl). If the host rejects the page put it on the
+ * @ctl refuse list. These refused page are then released when moving to the
+ * next size of pages.
+ *
+ * Note that we neither free any @page here nor put them back on the ballooned
+ * pages list. Instead we queue it for later processing. We do that for several
+ * reasons. First, we do not want to free the page under the lock. Second, it
+ * allows us to unify the handling of lock and unlock. In the inflate case, the
+ * caller will check if there are too many refused pages and release them.
+ * Although it is not identical to the past behavior, it should not affect
+ * performance.
*/
-static int vmballoon_lock_page(struct vmballoon *b, unsigned int num_pages,
- bool is_2m_pages, unsigned int *target)
+static int vmballoon_lock(struct vmballoon *b, struct vmballoon_ctl *ctl)
{
- int locked, hv_status;
- struct page *page = b->page;
- struct vmballoon_page_size *page_size = &b->page_sizes[false];
-
- /* is_2m_pages can never happen as 2m pages support implies batching */
-
- locked = vmballoon_send_lock_page(b, page_to_pfn(page), &hv_status,
- target);
- if (locked) {
- STATS_INC(b->stats.refused_alloc[false]);
-
- if (locked == -EIO &&
- (hv_status == VMW_BALLOON_ERROR_RESET ||
- hv_status == VMW_BALLOON_ERROR_PPN_NOTNEEDED)) {
- vmballoon_free_page(page, false);
- return -EIO;
- }
-
- /*
- * Place page on the list of non-balloonable pages
- * and retry allocation, unless we already accumulated
- * too many of them, in which case take a breather.
- */
- if (page_size->n_refused_pages < VMW_BALLOON_MAX_REFUSED) {
- page_size->n_refused_pages++;
- list_add(&page->lru, &page_size->refused_pages);
- } else {
- vmballoon_free_page(page, false);
- }
- return locked;
- }
-
- /* track allocated page */
- list_add(&page->lru, &page_size->pages);
+ unsigned long batch_status;
+ struct page *page;
+ unsigned int i, num_pages;
- /* update balloon size */
- b->size++;
+ num_pages = ctl->n_pages;
+ if (num_pages == 0)
+ return 0;
- return 0;
-}
+ /* communication with the host is done under the communication lock */
+ spin_lock(&b->comm_lock);
-static int vmballoon_lock_batched_page(struct vmballoon *b,
- unsigned int num_pages, bool is_2m_pages, unsigned int *target)
-{
- int locked, i;
- u16 size_per_page = vmballoon_page_size(is_2m_pages);
+ i = 0;
+ list_for_each_entry(page, &ctl->pages, lru)
+ vmballoon_add_page(b, i++, page);
- locked = vmballoon_send_batched_lock(b, num_pages, is_2m_pages,
- target);
- if (locked > 0) {
- for (i = 0; i < num_pages; i++) {
- u64 pa = vmballoon_batch_get_pa(b->batch_page, i);
- struct page *p = pfn_to_page(pa >> PAGE_SHIFT);
+ batch_status = vmballoon_lock_op(b, ctl->n_pages, ctl->page_size,
+ ctl->op);
- vmballoon_free_page(p, is_2m_pages);
- }
+ /*
+ * Iterate over the pages in the provided list. Since we are changing
+ * @ctl->n_pages we are saving the original value in @num_pages and
+ * use this value to bound the loop.
+ */
+ for (i = 0; i < num_pages; i++) {
+ unsigned long status;
- return -EIO;
- }
+ status = vmballoon_status_page(b, i, &page);
- for (i = 0; i < num_pages; i++) {
- u64 pa = vmballoon_batch_get_pa(b->batch_page, i);
- struct page *p = pfn_to_page(pa >> PAGE_SHIFT);
- struct vmballoon_page_size *page_size =
- &b->page_sizes[is_2m_pages];
+ /*
+ * Failure of the whole batch overrides a single operation
+ * results.
+ */
+ if (batch_status != VMW_BALLOON_SUCCESS)
+ status = batch_status;
- locked = vmballoon_batch_get_status(b->batch_page, i);
+ /* Continue if no error happened */
+ if (!vmballoon_handle_one_result(b, page, ctl->page_size,
+ status))
+ continue;
- switch (locked) {
- case VMW_BALLOON_SUCCESS:
- list_add(&p->lru, &page_size->pages);
- b->size += size_per_page;
- break;
- case VMW_BALLOON_ERROR_PPN_PINNED:
- case VMW_BALLOON_ERROR_PPN_INVALID:
- if (page_size->n_refused_pages
- < VMW_BALLOON_MAX_REFUSED) {
- list_add(&p->lru, &page_size->refused_pages);
- page_size->n_refused_pages++;
- break;
- }
- /* Fallthrough */
- case VMW_BALLOON_ERROR_RESET:
- case VMW_BALLOON_ERROR_PPN_NOTNEEDED:
- vmballoon_free_page(p, is_2m_pages);
- break;
- default:
- /* This should never happen */
- WARN_ON_ONCE(true);
- }
+ /*
+ * Error happened. Move the pages to the refused list and update
+ * the pages number.
+ */
+ list_move(&page->lru, &ctl->refused_pages);
+ ctl->n_pages--;
+ ctl->n_refused_pages++;
}
- return 0;
+ spin_unlock(&b->comm_lock);
+
+ return batch_status == VMW_BALLOON_SUCCESS ? 0 : -EIO;
}
-/*
- * Release the page allocated for the balloon. Note that we first notify
- * the host so it can make sure the page will be available for the guest
- * to use, if needed.
+/**
+ * vmballoon_release_page_list() - Releases a page list
+ *
+ * @page_list: list of pages to release.
+ * @n_pages: pointer to the number of pages.
+ * @page_size: whether the pages in the list are 2MB (or else 4KB).
+ *
+ * Releases the list of pages and zeros the number of pages.
*/
-static int vmballoon_unlock_page(struct vmballoon *b, unsigned int num_pages,
- bool is_2m_pages, unsigned int *target)
+static void vmballoon_release_page_list(struct list_head *page_list,
+ int *n_pages,
+ enum vmballoon_page_size_type page_size)
{
- struct page *page = b->page;
- struct vmballoon_page_size *page_size = &b->page_sizes[false];
-
- /* is_2m_pages can never happen as 2m pages support implies batching */
+ struct page *page, *tmp;
- if (!vmballoon_send_unlock_page(b, page_to_pfn(page), target)) {
- list_add(&page->lru, &page_size->pages);
- return -EIO;
+ list_for_each_entry_safe(page, tmp, page_list, lru) {
+ list_del(&page->lru);
+ __free_pages(page, vmballoon_page_order(page_size));
}
- /* deallocate page */
- vmballoon_free_page(page, false);
- STATS_INC(b->stats.free[false]);
+ *n_pages = 0;
+}
- /* update balloon size */
- b->size--;
- return 0;
+/*
+ * Release pages that were allocated while attempting to inflate the
+ * balloon but were refused by the host for one reason or another.
+ */
+static void vmballoon_release_refused_pages(struct vmballoon *b,
+ struct vmballoon_ctl *ctl)
+{
+ vmballoon_stats_page_inc(b, VMW_BALLOON_PAGE_STAT_REFUSED_FREE,
+ ctl->page_size);
+
+ vmballoon_release_page_list(&ctl->refused_pages, &ctl->n_refused_pages,
+ ctl->page_size);
}
-static int vmballoon_unlock_batched_page(struct vmballoon *b,
- unsigned int num_pages, bool is_2m_pages,
- unsigned int *target)
+/**
+ * vmballoon_change - retrieve the required balloon change
+ *
+ * @b: pointer for the balloon.
+ *
+ * Return: the required change for the balloon size. A positive number
+ * indicates inflation, a negative number indicates a deflation.
+ */
+static int64_t vmballoon_change(struct vmballoon *b)
{
- int locked, i, ret = 0;
- bool hv_success;
- u16 size_per_page = vmballoon_page_size(is_2m_pages);
+ int64_t size, target;
- hv_success = vmballoon_send_batched_unlock(b, num_pages, is_2m_pages,
- target);
- if (!hv_success)
- ret = -EIO;
+ size = atomic64_read(&b->size);
+ target = READ_ONCE(b->target);
- for (i = 0; i < num_pages; i++) {
- u64 pa = vmballoon_batch_get_pa(b->batch_page, i);
- struct page *p = pfn_to_page(pa >> PAGE_SHIFT);
- struct vmballoon_page_size *page_size =
- &b->page_sizes[is_2m_pages];
+ /*
+ * We must cast first because of int sizes
+ * Otherwise we might get huge positives instead of negatives
+ */
- locked = vmballoon_batch_get_status(b->batch_page, i);
- if (!hv_success || locked != VMW_BALLOON_SUCCESS) {
- /*
- * That page wasn't successfully unlocked by the
- * hypervisor, re-add it to the list of pages owned by
- * the balloon driver.
- */
- list_add(&p->lru, &page_size->pages);
- } else {
- /* deallocate page */
- vmballoon_free_page(p, is_2m_pages);
- STATS_INC(b->stats.free[is_2m_pages]);
-
- /* update balloon size */
- b->size -= size_per_page;
- }
- }
+ if (b->reset_required)
+ return 0;
+
+ /* consider a 2MB slack on deflate, unless the balloon is emptied */
+ if (target < size && target != 0 &&
+ size - target < vmballoon_page_in_frames(VMW_BALLOON_2M_PAGE))
+ return 0;
- return ret;
+ return target - size;
}
-/*
- * Release pages that were allocated while attempting to inflate the
- * balloon but were refused by the host for one reason or another.
+/**
+ * vmballoon_enqueue_page_list() - Enqueues list of pages after inflation.
+ *
+ * @b: pointer to balloon.
+ * @pages: list of pages to enqueue.
+ * @n_pages: pointer to number of pages in list. The value is zeroed.
+ * @page_size: whether the pages are 2MB or 4KB pages.
+ *
+ * Enqueues the provides list of pages in the ballooned page list, clears the
+ * list and zeroes the number of pages that was provided.
*/
-static void vmballoon_release_refused_pages(struct vmballoon *b,
- bool is_2m_pages)
+static void vmballoon_enqueue_page_list(struct vmballoon *b,
+ struct list_head *pages,
+ unsigned int *n_pages,
+ enum vmballoon_page_size_type page_size)
{
- struct page *page, *next;
- struct vmballoon_page_size *page_size =
- &b->page_sizes[is_2m_pages];
+ struct vmballoon_page_size *page_size_info = &b->page_sizes[page_size];
- list_for_each_entry_safe(page, next, &page_size->refused_pages, lru) {
- list_del(&page->lru);
- vmballoon_free_page(page, is_2m_pages);
- STATS_INC(b->stats.refused_free[is_2m_pages]);
- }
-
- page_size->n_refused_pages = 0;
+ list_splice_init(pages, &page_size_info->pages);
+ *n_pages = 0;
}
-static void vmballoon_add_page(struct vmballoon *b, int idx, struct page *p)
+/**
+ * vmballoon_dequeue_page_list() - Dequeues page lists for deflation.
+ *
+ * @b: pointer to balloon.
+ * @pages: list of pages to enqueue.
+ * @n_pages: pointer to number of pages in list. The value is zeroed.
+ * @page_size: whether the pages are 2MB or 4KB pages.
+ * @n_req_pages: the number of requested pages.
+ *
+ * Dequeues the number of requested pages from the balloon for deflation. The
+ * number of dequeued pages may be lower, if not enough pages in the requested
+ * size are available.
+ */
+static void vmballoon_dequeue_page_list(struct vmballoon *b,
+ struct list_head *pages,
+ unsigned int *n_pages,
+ enum vmballoon_page_size_type page_size,
+ unsigned int n_req_pages)
{
- b->page = p;
-}
+ struct vmballoon_page_size *page_size_info = &b->page_sizes[page_size];
+ struct page *page, *tmp;
+ unsigned int i = 0;
-static void vmballoon_add_batched_page(struct vmballoon *b, int idx,
- struct page *p)
-{
- vmballoon_batch_set_pa(b->batch_page, idx,
- (u64)page_to_pfn(p) << PAGE_SHIFT);
+ list_for_each_entry_safe(page, tmp, &page_size_info->pages, lru) {
+ list_move(&page->lru, pages);
+ if (++i == n_req_pages)
+ break;
+ }
+ *n_pages = i;
}
-/*
- * Inflate the balloon towards its target size. Note that we try to limit
- * the rate of allocation to make sure we are not choking the rest of the
- * system.
+/**
+ * vmballoon_inflate() - Inflate the balloon towards its target size.
+ *
+ * @b: pointer to the balloon.
*/
static void vmballoon_inflate(struct vmballoon *b)
{
- unsigned int num_pages = 0;
- int error = 0;
- gfp_t flags = VMW_PAGE_ALLOC_NOSLEEP;
- bool is_2m_pages;
+ int64_t to_inflate_frames;
+ struct vmballoon_ctl ctl = {
+ .pages = LIST_HEAD_INIT(ctl.pages),
+ .refused_pages = LIST_HEAD_INIT(ctl.refused_pages),
+ .page_size = b->max_page_size,
+ .op = VMW_BALLOON_INFLATE
+ };
- pr_debug("%s - size: %d, target %d\n", __func__, b->size, b->target);
+ while ((to_inflate_frames = vmballoon_change(b)) > 0) {
+ unsigned int to_inflate_pages, page_in_frames;
+ int alloc_error, lock_error = 0;
- /*
- * First try NOSLEEP page allocations to inflate balloon.
- *
- * If we do not throttle nosleep allocations, we can drain all
- * free pages in the guest quickly (if the balloon target is high).
- * As a side-effect, draining free pages helps to inform (force)
- * the guest to start swapping if balloon target is not met yet,
- * which is a desired behavior. However, balloon driver can consume
- * all available CPU cycles if too many pages are allocated in a
- * second. Therefore, we throttle nosleep allocations even when
- * the guest is not under memory pressure. OTOH, if we have already
- * predicted that the guest is under memory pressure, then we
- * slowdown page allocations considerably.
- */
+ VM_BUG_ON(!list_empty(&ctl.pages));
+ VM_BUG_ON(ctl.n_pages != 0);
- /*
- * Start with no sleep allocation rate which may be higher
- * than sleeping allocation rate.
- */
- is_2m_pages = b->supported_page_sizes == VMW_BALLOON_NUM_PAGE_SIZES;
+ page_in_frames = vmballoon_page_in_frames(ctl.page_size);
- pr_debug("%s - goal: %d", __func__, b->target - b->size);
+ to_inflate_pages = min_t(unsigned long, b->batch_max_pages,
+ DIV_ROUND_UP_ULL(to_inflate_frames,
+ page_in_frames));
- while (!b->reset_required &&
- b->size + num_pages * vmballoon_page_size(is_2m_pages)
- < b->target) {
- struct page *page;
+ /* Start by allocating */
+ alloc_error = vmballoon_alloc_page_list(b, &ctl,
+ to_inflate_pages);
- if (flags == VMW_PAGE_ALLOC_NOSLEEP)
- STATS_INC(b->stats.alloc[is_2m_pages]);
- else
- STATS_INC(b->stats.sleep_alloc);
-
- page = vmballoon_alloc_page(flags, is_2m_pages);
- if (!page) {
- STATS_INC(b->stats.alloc_fail[is_2m_pages]);
-
- if (is_2m_pages) {
- b->ops->lock(b, num_pages, true, &b->target);
-
- /*
- * ignore errors from locking as we now switch
- * to 4k pages and we might get different
- * errors.
- */
-
- num_pages = 0;
- is_2m_pages = false;
- continue;
- }
-
- if (flags == VMW_PAGE_ALLOC_CANSLEEP) {
- /*
- * CANSLEEP page allocation failed, so guest
- * is under severe memory pressure. We just log
- * the event, but do not stop the inflation
- * due to its negative impact on performance.
- */
- STATS_INC(b->stats.sleep_alloc_fail);
+ /* Actually lock the pages by telling the hypervisor */
+ lock_error = vmballoon_lock(b, &ctl);
+
+ /*
+ * If an error indicates that something serious went wrong,
+ * stop the inflation.
+ */
+ if (lock_error)
+ break;
+
+ /* Update the balloon size */
+ atomic64_add(ctl.n_pages * page_in_frames, &b->size);
+
+ vmballoon_enqueue_page_list(b, &ctl.pages, &ctl.n_pages,
+ ctl.page_size);
+
+ /*
+ * If allocation failed or the number of refused pages exceeds
+ * the maximum allowed, move to the next page size.
+ */
+ if (alloc_error ||
+ ctl.n_refused_pages >= VMW_BALLOON_MAX_REFUSED) {
+ if (ctl.page_size == VMW_BALLOON_4K_PAGE)
break;
- }
/*
- * NOSLEEP page allocation failed, so the guest is
- * under memory pressure. Slowing down page alloctions
- * seems to be reasonable, but doing so might actually
- * cause the hypervisor to throttle us down, resulting
- * in degraded performance. We will count on the
- * scheduler and standard memory management mechanisms
- * for now.
+ * Ignore errors from locking as we now switch to 4k
+ * pages and we might get different errors.
*/
- flags = VMW_PAGE_ALLOC_CANSLEEP;
- continue;
- }
-
- b->ops->add_page(b, num_pages++, page);
- if (num_pages == b->batch_max_pages) {
- error = b->ops->lock(b, num_pages, is_2m_pages,
- &b->target);
- num_pages = 0;
- if (error)
- break;
+ vmballoon_release_refused_pages(b, &ctl);
+ ctl.page_size--;
}
cond_resched();
}
- if (num_pages > 0)
- b->ops->lock(b, num_pages, is_2m_pages, &b->target);
-
- vmballoon_release_refused_pages(b, true);
- vmballoon_release_refused_pages(b, false);
+ /*
+ * Release pages that were allocated while attempting to inflate the
+ * balloon but were refused by the host for one reason or another,
+ * and update the statistics.
+ */
+ if (ctl.n_refused_pages != 0)
+ vmballoon_release_refused_pages(b, &ctl);
}
-/*
+/**
+ * vmballoon_deflate() - Decrease the size of the balloon.
+ *
+ * @b: pointer to the balloon
+ * @n_frames: the number of frames to deflate. If zero, automatically
+ * calculated according to the target size.
+ * @coordinated: whether to coordinate with the host
+ *
* Decrease the size of the balloon allowing guest to use more memory.
+ *
+ * Return: The number of deflated frames (i.e., basic page size units)
*/
-static void vmballoon_deflate(struct vmballoon *b)
+static unsigned long vmballoon_deflate(struct vmballoon *b, uint64_t n_frames,
+ bool coordinated)
{
- unsigned is_2m_pages;
-
- pr_debug("%s - size: %d, target %d\n", __func__, b->size, b->target);
+ unsigned long deflated_frames = 0;
+ unsigned long tried_frames = 0;
+ struct vmballoon_ctl ctl = {
+ .pages = LIST_HEAD_INIT(ctl.pages),
+ .refused_pages = LIST_HEAD_INIT(ctl.refused_pages),
+ .page_size = VMW_BALLOON_4K_PAGE,
+ .op = VMW_BALLOON_DEFLATE
+ };
/* free pages to reach target */
- for (is_2m_pages = 0; is_2m_pages < b->supported_page_sizes;
- is_2m_pages++) {
- struct page *page, *next;
- unsigned int num_pages = 0;
- struct vmballoon_page_size *page_size =
- &b->page_sizes[is_2m_pages];
-
- list_for_each_entry_safe(page, next, &page_size->pages, lru) {
- if (b->reset_required ||
- (b->target > 0 &&
- b->size - num_pages
- * vmballoon_page_size(is_2m_pages)
- < b->target + vmballoon_page_size(true)))
- break;
+ while (true) {
+ unsigned int to_deflate_pages, n_unlocked_frames;
+ unsigned int page_in_frames;
+ int64_t to_deflate_frames;
+ bool deflated_all;
+
+ page_in_frames = vmballoon_page_in_frames(ctl.page_size);
+
+ VM_BUG_ON(!list_empty(&ctl.pages));
+ VM_BUG_ON(ctl.n_pages);
+ VM_BUG_ON(!list_empty(&ctl.refused_pages));
+ VM_BUG_ON(ctl.n_refused_pages);
+
+ /*
+ * If we were requested a specific number of frames, we try to
+ * deflate this number of frames. Otherwise, deflation is
+ * performed according to the target and balloon size.
+ */
+ to_deflate_frames = n_frames ? n_frames - tried_frames :
+ -vmballoon_change(b);
+
+ /* break if no work to do */
+ if (to_deflate_frames <= 0)
+ break;
+
+ /*
+ * Calculate the number of frames based on current page size,
+ * but limit the deflated frames to a single chunk
+ */
+ to_deflate_pages = min_t(unsigned long, b->batch_max_pages,
+ DIV_ROUND_UP_ULL(to_deflate_frames,
+ page_in_frames));
+
+ /* First take the pages from the balloon pages. */
+ vmballoon_dequeue_page_list(b, &ctl.pages, &ctl.n_pages,
+ ctl.page_size, to_deflate_pages);
+
+ /*
+ * Before pages are moving to the refused list, count their
+ * frames as frames that we tried to deflate.
+ */
+ tried_frames += ctl.n_pages * page_in_frames;
+
+ /*
+ * Unlock the pages by communicating with the hypervisor if the
+ * communication is coordinated (i.e., not pop). We ignore the
+ * return code. Instead we check if all the pages we manage to
+ * unlock all the pages. If we failed, we will move to the next
+ * page size, and would eventually try again later.
+ */
+ if (coordinated)
+ vmballoon_lock(b, &ctl);
+
+ /*
+ * Check if we deflated enough. We will move to the next page
+ * size if we did not manage to do so. This calculation takes
+ * place now, as once the pages are released, the number of
+ * pages is zeroed.
+ */
+ deflated_all = (ctl.n_pages == to_deflate_pages);
+
+ /* Update local and global counters */
+ n_unlocked_frames = ctl.n_pages * page_in_frames;
+ atomic64_sub(n_unlocked_frames, &b->size);
+ deflated_frames += n_unlocked_frames;
- list_del(&page->lru);
- b->ops->add_page(b, num_pages++, page);
+ vmballoon_stats_page_add(b, VMW_BALLOON_PAGE_STAT_FREE,
+ ctl.page_size, ctl.n_pages);
- if (num_pages == b->batch_max_pages) {
- int error;
+ /* free the ballooned pages */
+ vmballoon_release_page_list(&ctl.pages, &ctl.n_pages,
+ ctl.page_size);
- error = b->ops->unlock(b, num_pages,
- is_2m_pages, &b->target);
- num_pages = 0;
- if (error)
- return;
- }
+ /* Return the refused pages to the ballooned list. */
+ vmballoon_enqueue_page_list(b, &ctl.refused_pages,
+ &ctl.n_refused_pages,
+ ctl.page_size);
- cond_resched();
+ /* If we failed to unlock all the pages, move to next size. */
+ if (!deflated_all) {
+ if (ctl.page_size == b->max_page_size)
+ break;
+ ctl.page_size++;
}
- if (num_pages > 0)
- b->ops->unlock(b, num_pages, is_2m_pages, &b->target);
+ cond_resched();
}
-}
-static const struct vmballoon_ops vmballoon_basic_ops = {
- .add_page = vmballoon_add_page,
- .lock = vmballoon_lock_page,
- .unlock = vmballoon_unlock_page
-};
+ return deflated_frames;
+}
-static const struct vmballoon_ops vmballoon_batched_ops = {
- .add_page = vmballoon_add_batched_page,
- .lock = vmballoon_lock_batched_page,
- .unlock = vmballoon_unlock_batched_page
-};
+/**
+ * vmballoon_deinit_batching - disables batching mode.
+ *
+ * @b: pointer to &struct vmballoon.
+ *
+ * Disables batching, by deallocating the page for communication with the
+ * hypervisor and disabling the static key to indicate that batching is off.
+ */
+static void vmballoon_deinit_batching(struct vmballoon *b)
+{
+ free_page((unsigned long)b->batch_page);
+ b->batch_page = NULL;
+ static_branch_disable(&vmw_balloon_batching);
+ b->batch_max_pages = 1;
+}
-static bool vmballoon_init_batching(struct vmballoon *b)
+/**
+ * vmballoon_init_batching - enable batching mode.
+ *
+ * @b: pointer to &struct vmballoon.
+ *
+ * Enables batching, by allocating a page for communication with the hypervisor
+ * and enabling the static_key to use batching.
+ *
+ * Return: zero on success or an appropriate error-code.
+ */
+static int vmballoon_init_batching(struct vmballoon *b)
{
struct page *page;
page = alloc_page(GFP_KERNEL | __GFP_ZERO);
if (!page)
- return false;
+ return -ENOMEM;
b->batch_page = page_address(page);
- return true;
+ b->batch_max_pages = PAGE_SIZE / sizeof(struct vmballoon_batch_entry);
+
+ static_branch_enable(&vmw_balloon_batching);
+
+ return 0;
}
/*
@@ -932,7 +1197,7 @@ static void vmballoon_doorbell(void *client_data)
{
struct vmballoon *b = client_data;
- STATS_INC(b->stats.doorbell);
+ vmballoon_stats_gen_inc(b, VMW_BALLOON_STAT_DOORBELL);
mod_delayed_work(system_freezable_wq, &b->dwork, 0);
}
@@ -942,11 +1207,8 @@ static void vmballoon_doorbell(void *client_data)
*/
static void vmballoon_vmci_cleanup(struct vmballoon *b)
{
- int error;
-
- VMWARE_BALLOON_CMD(VMCI_DOORBELL_SET, VMCI_INVALID_ID,
- VMCI_INVALID_ID, error);
- STATS_INC(b->stats.doorbell_unset);
+ vmballoon_cmd(b, VMW_BALLOON_CMD_VMCI_DOORBELL_SET,
+ VMCI_INVALID_ID, VMCI_INVALID_ID);
if (!vmci_handle_is_invalid(b->vmci_doorbell)) {
vmci_doorbell_destroy(b->vmci_doorbell);
@@ -954,12 +1216,19 @@ static void vmballoon_vmci_cleanup(struct vmballoon *b)
}
}
-/*
- * Initialize vmci doorbell, to get notified as soon as balloon changes
+/**
+ * vmballoon_vmci_init - Initialize vmci doorbell.
+ *
+ * @b: pointer to the balloon.
+ *
+ * Return: zero on success or when wakeup command not supported. Error-code
+ * otherwise.
+ *
+ * Initialize vmci doorbell, to get notified as soon as balloon changes.
*/
static int vmballoon_vmci_init(struct vmballoon *b)
{
- unsigned long error, dummy;
+ unsigned long error;
if ((b->capabilities & VMW_BALLOON_SIGNALLED_WAKEUP_CMD) == 0)
return 0;
@@ -971,10 +1240,9 @@ static int vmballoon_vmci_init(struct vmballoon *b)
if (error != VMCI_SUCCESS)
goto fail;
- error = VMWARE_BALLOON_CMD(VMCI_DOORBELL_SET, b->vmci_doorbell.context,
- b->vmci_doorbell.resource, dummy);
-
- STATS_INC(b->stats.doorbell_set);
+ error = __vmballoon_cmd(b, VMW_BALLOON_CMD_VMCI_DOORBELL_SET,
+ b->vmci_doorbell.context,
+ b->vmci_doorbell.resource, NULL);
if (error != VMW_BALLOON_SUCCESS)
goto fail;
@@ -985,6 +1253,23 @@ fail:
return -EIO;
}
+/**
+ * vmballoon_pop - Quickly release all pages allocate for the balloon.
+ *
+ * @b: pointer to the balloon.
+ *
+ * This function is called when host decides to "reset" balloon for one reason
+ * or another. Unlike normal "deflate" we do not (shall not) notify host of the
+ * pages being released.
+ */
+static void vmballoon_pop(struct vmballoon *b)
+{
+ unsigned long size;
+
+ while ((size = atomic64_read(&b->size)))
+ vmballoon_deflate(b, size, false);
+}
+
/*
* Perform standard reset sequence by popping the balloon (in case it
* is not empty) and then restarting protocol. This operation normally
@@ -994,18 +1279,18 @@ static void vmballoon_reset(struct vmballoon *b)
{
int error;
+ down_write(&b->conf_sem);
+
vmballoon_vmci_cleanup(b);
/* free all pages, skipping monitor unlock */
vmballoon_pop(b);
- if (!vmballoon_send_start(b, VMW_BALLOON_CAPABILITIES))
+ if (vmballoon_send_start(b, VMW_BALLOON_CAPABILITIES))
return;
if ((b->capabilities & VMW_BALLOON_BATCHED_CMDS) != 0) {
- b->ops = &vmballoon_batched_ops;
- b->batch_max_pages = VMW_BALLOON_BATCH_MAX_PAGES;
- if (!vmballoon_init_batching(b)) {
+ if (vmballoon_init_batching(b)) {
/*
* We failed to initialize batching, inform the monitor
* about it by sending a null capability.
@@ -1016,52 +1301,70 @@ static void vmballoon_reset(struct vmballoon *b)
return;
}
} else if ((b->capabilities & VMW_BALLOON_BASIC_CMDS) != 0) {
- b->ops = &vmballoon_basic_ops;
- b->batch_max_pages = 1;
+ vmballoon_deinit_batching(b);
}
+ vmballoon_stats_gen_inc(b, VMW_BALLOON_STAT_RESET);
b->reset_required = false;
error = vmballoon_vmci_init(b);
if (error)
pr_err("failed to initialize vmci doorbell\n");
- if (!vmballoon_send_guest_id(b))
+ if (vmballoon_send_guest_id(b))
pr_err("failed to send guest ID to the host\n");
+
+ up_write(&b->conf_sem);
}
-/*
- * Balloon work function: reset protocol, if needed, get the new size and
- * adjust balloon as needed. Repeat in 1 sec.
+/**
+ * vmballoon_work - periodic balloon worker for reset, inflation and deflation.
+ *
+ * @work: pointer to the &work_struct which is provided by the workqueue.
+ *
+ * Resets the protocol if needed, gets the new size and adjusts balloon as
+ * needed. Repeat in 1 sec.
*/
static void vmballoon_work(struct work_struct *work)
{
struct delayed_work *dwork = to_delayed_work(work);
struct vmballoon *b = container_of(dwork, struct vmballoon, dwork);
- unsigned int target;
-
- STATS_INC(b->stats.timer);
+ int64_t change = 0;
if (b->reset_required)
vmballoon_reset(b);
- if (!b->reset_required && vmballoon_send_get_target(b, &target)) {
- /* update target, adjust size */
- b->target = target;
+ down_read(&b->conf_sem);
+
+ /*
+ * Update the stats while holding the semaphore to ensure that
+ * @stats_enabled is consistent with whether the stats are actually
+ * enabled
+ */
+ vmballoon_stats_gen_inc(b, VMW_BALLOON_STAT_TIMER);
+
+ if (!vmballoon_send_get_target(b))
+ change = vmballoon_change(b);
+
+ if (change != 0) {
+ pr_debug("%s - size: %llu, target %lu\n", __func__,
+ atomic64_read(&b->size), READ_ONCE(b->target));
- if (b->size < target)
+ if (change > 0)
vmballoon_inflate(b);
- else if (target == 0 ||
- b->size > target + vmballoon_page_size(true))
- vmballoon_deflate(b);
+ else /* (change < 0) */
+ vmballoon_deflate(b, 0, true);
}
+ up_read(&b->conf_sem);
+
/*
* We are using a freezable workqueue so that balloon operations are
* stopped while the system transitions to/from sleep/hibernation.
*/
queue_delayed_work(system_freezable_wq,
dwork, round_jiffies_relative(HZ));
+
}
/*
@@ -1069,64 +1372,100 @@ static void vmballoon_work(struct work_struct *work)
*/
#ifdef CONFIG_DEBUG_FS
+static const char * const vmballoon_stat_page_names[] = {
+ [VMW_BALLOON_PAGE_STAT_ALLOC] = "alloc",
+ [VMW_BALLOON_PAGE_STAT_ALLOC_FAIL] = "allocFail",
+ [VMW_BALLOON_PAGE_STAT_REFUSED_ALLOC] = "errAlloc",
+ [VMW_BALLOON_PAGE_STAT_REFUSED_FREE] = "errFree",
+ [VMW_BALLOON_PAGE_STAT_FREE] = "free"
+};
+
+static const char * const vmballoon_stat_names[] = {
+ [VMW_BALLOON_STAT_TIMER] = "timer",
+ [VMW_BALLOON_STAT_DOORBELL] = "doorbell",
+ [VMW_BALLOON_STAT_RESET] = "reset",
+};
+
+static int vmballoon_enable_stats(struct vmballoon *b)
+{
+ int r = 0;
+
+ down_write(&b->conf_sem);
+
+ /* did we somehow race with another reader which enabled stats? */
+ if (b->stats)
+ goto out;
+
+ b->stats = kzalloc(sizeof(*b->stats), GFP_KERNEL);
+
+ if (!b->stats) {
+ /* allocation failed */
+ r = -ENOMEM;
+ goto out;
+ }
+ static_key_enable(&balloon_stat_enabled.key);
+out:
+ up_write(&b->conf_sem);
+ return r;
+}
+
+/**
+ * vmballoon_debug_show - shows statistics of balloon operations.
+ * @f: pointer to the &struct seq_file.
+ * @offset: ignored.
+ *
+ * Provides the statistics that can be accessed in vmmemctl in the debugfs.
+ * To avoid the overhead - mainly that of memory - of collecting the statistics,
+ * we only collect statistics after the first time the counters are read.
+ *
+ * Return: zero on success or an error code.
+ */
static int vmballoon_debug_show(struct seq_file *f, void *offset)
{
struct vmballoon *b = f->private;
- struct vmballoon_stats *stats = &b->stats;
+ int i, j;
+
+ /* enables stats if they are disabled */
+ if (!b->stats) {
+ int r = vmballoon_enable_stats(b);
+
+ if (r)
+ return r;
+ }
/* format capabilities info */
- seq_printf(f,
- "balloon capabilities: %#4x\n"
- "used capabilities: %#4lx\n"
- "is resetting: %c\n",
- VMW_BALLOON_CAPABILITIES, b->capabilities,
- b->reset_required ? 'y' : 'n');
+ seq_printf(f, "%-22s: %#16x\n", "balloon capabilities",
+ VMW_BALLOON_CAPABILITIES);
+ seq_printf(f, "%-22s: %#16lx\n", "used capabilities", b->capabilities);
+ seq_printf(f, "%-22s: %16s\n", "is resetting",
+ b->reset_required ? "y" : "n");
/* format size info */
- seq_printf(f,
- "target: %8d pages\n"
- "current: %8d pages\n",
- b->target, b->size);
-
- seq_printf(f,
- "\n"
- "timer: %8u\n"
- "doorbell: %8u\n"
- "start: %8u (%4u failed)\n"
- "guestType: %8u (%4u failed)\n"
- "2m-lock: %8u (%4u failed)\n"
- "lock: %8u (%4u failed)\n"
- "2m-unlock: %8u (%4u failed)\n"
- "unlock: %8u (%4u failed)\n"
- "target: %8u (%4u failed)\n"
- "prim2mAlloc: %8u (%4u failed)\n"
- "primNoSleepAlloc: %8u (%4u failed)\n"
- "primCanSleepAlloc: %8u (%4u failed)\n"
- "prim2mFree: %8u\n"
- "primFree: %8u\n"
- "err2mAlloc: %8u\n"
- "errAlloc: %8u\n"
- "err2mFree: %8u\n"
- "errFree: %8u\n"
- "doorbellSet: %8u\n"
- "doorbellUnset: %8u\n",
- stats->timer,
- stats->doorbell,
- stats->start, stats->start_fail,
- stats->guest_type, stats->guest_type_fail,
- stats->lock[true], stats->lock_fail[true],
- stats->lock[false], stats->lock_fail[false],
- stats->unlock[true], stats->unlock_fail[true],
- stats->unlock[false], stats->unlock_fail[false],
- stats->target, stats->target_fail,
- stats->alloc[true], stats->alloc_fail[true],
- stats->alloc[false], stats->alloc_fail[false],
- stats->sleep_alloc, stats->sleep_alloc_fail,
- stats->free[true],
- stats->free[false],
- stats->refused_alloc[true], stats->refused_alloc[false],
- stats->refused_free[true], stats->refused_free[false],
- stats->doorbell_set, stats->doorbell_unset);
+ seq_printf(f, "%-22s: %16lu\n", "target", READ_ONCE(b->target));
+ seq_printf(f, "%-22s: %16llu\n", "current", atomic64_read(&b->size));
+
+ for (i = 0; i < VMW_BALLOON_CMD_NUM; i++) {
+ if (vmballoon_cmd_names[i] == NULL)
+ continue;
+
+ seq_printf(f, "%-22s: %16llu (%llu failed)\n",
+ vmballoon_cmd_names[i],
+ atomic64_read(&b->stats->ops[i][VMW_BALLOON_OP_STAT]),
+ atomic64_read(&b->stats->ops[i][VMW_BALLOON_OP_FAIL_STAT]));
+ }
+
+ for (i = 0; i < VMW_BALLOON_STAT_NUM; i++)
+ seq_printf(f, "%-22s: %16llu\n",
+ vmballoon_stat_names[i],
+ atomic64_read(&b->stats->general_stat[i]));
+
+ for (i = 0; i < VMW_BALLOON_PAGE_STAT_NUM; i++) {
+ for (j = 0; j < VMW_BALLOON_NUM_PAGE_SIZES; j++)
+ seq_printf(f, "%-18s(%s): %16llu\n",
+ vmballoon_stat_page_names[i],
+ vmballoon_page_size_names[j],
+ atomic64_read(&b->stats->page_stat[i][j]));
+ }
return 0;
}
@@ -1161,7 +1500,10 @@ static int __init vmballoon_debugfs_init(struct vmballoon *b)
static void __exit vmballoon_debugfs_exit(struct vmballoon *b)
{
+ static_key_disable(&balloon_stat_enabled.key);
debugfs_remove(b->dbg_entry);
+ kfree(b->stats);
+ b->stats = NULL;
}
#else
@@ -1179,8 +1521,9 @@ static inline void vmballoon_debugfs_exit(struct vmballoon *b)
static int __init vmballoon_init(void)
{
+ enum vmballoon_page_size_type page_size;
int error;
- unsigned is_2m_pages;
+
/*
* Check if we are running on VMware's hypervisor and bail out
* if we are not.
@@ -1188,11 +1531,10 @@ static int __init vmballoon_init(void)
if (x86_hyper_type != X86_HYPER_VMWARE)
return -ENODEV;
- for (is_2m_pages = 0; is_2m_pages < VMW_BALLOON_NUM_PAGE_SIZES;
- is_2m_pages++) {
- INIT_LIST_HEAD(&balloon.page_sizes[is_2m_pages].pages);
- INIT_LIST_HEAD(&balloon.page_sizes[is_2m_pages].refused_pages);
- }
+ for (page_size = VMW_BALLOON_4K_PAGE;
+ page_size <= VMW_BALLOON_LAST_SIZE; page_size++)
+ INIT_LIST_HEAD(&balloon.page_sizes[page_size].pages);
+
INIT_DELAYED_WORK(&balloon.dwork, vmballoon_work);
@@ -1200,6 +1542,8 @@ static int __init vmballoon_init(void)
if (error)
return error;
+ spin_lock_init(&balloon.comm_lock);
+ init_rwsem(&balloon.conf_sem);
balloon.vmci_doorbell = VMCI_INVALID_HANDLE;
balloon.batch_page = NULL;
balloon.page = NULL;
diff --git a/drivers/misc/vmw_vmci/vmci_driver.c b/drivers/misc/vmw_vmci/vmci_driver.c
index d7eaf1eb11e7..003bfba40758 100644
--- a/drivers/misc/vmw_vmci/vmci_driver.c
+++ b/drivers/misc/vmw_vmci/vmci_driver.c
@@ -113,5 +113,5 @@ module_exit(vmci_drv_exit);
MODULE_AUTHOR("VMware, Inc.");
MODULE_DESCRIPTION("VMware Virtual Machine Communication Interface.");
-MODULE_VERSION("1.1.5.0-k");
+MODULE_VERSION("1.1.6.0-k");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/vmw_vmci/vmci_host.c b/drivers/misc/vmw_vmci/vmci_host.c
index 83e0c95d20a4..edfffc9699ba 100644
--- a/drivers/misc/vmw_vmci/vmci_host.c
+++ b/drivers/misc/vmw_vmci/vmci_host.c
@@ -15,7 +15,6 @@
#include <linux/vmw_vmci_defs.h>
#include <linux/vmw_vmci_api.h>
-#include <linux/moduleparam.h>
#include <linux/miscdevice.h>
#include <linux/interrupt.h>
#include <linux/highmem.h>
@@ -448,15 +447,12 @@ static int vmci_host_do_alloc_queuepair(struct vmci_host_dev *vmci_host_dev,
struct vmci_handle handle;
int vmci_status;
int __user *retptr;
- u32 cid;
if (vmci_host_dev->ct_type != VMCIOBJ_CONTEXT) {
vmci_ioctl_err("only valid for contexts\n");
return -EINVAL;
}
- cid = vmci_ctx_get_id(vmci_host_dev->context);
-
if (vmci_host_dev->user_version < VMCI_VERSION_NOVMVM) {
struct vmci_qp_alloc_info_vmvm alloc_info;
struct vmci_qp_alloc_info_vmvm __user *info = uptr;
diff --git a/drivers/misc/vmw_vmci/vmci_queue_pair.c b/drivers/misc/vmw_vmci/vmci_queue_pair.c
index bd52f29b4a4e..264f4ed8eef2 100644
--- a/drivers/misc/vmw_vmci/vmci_queue_pair.c
+++ b/drivers/misc/vmw_vmci/vmci_queue_pair.c
@@ -3030,7 +3030,7 @@ ssize_t vmci_qpair_enqueue(struct vmci_qp *qpair,
if (!qpair || !buf)
return VMCI_ERROR_INVALID_ARGS;
- iov_iter_kvec(&from, WRITE | ITER_KVEC, &v, 1, buf_size);
+ iov_iter_kvec(&from, WRITE, &v, 1, buf_size);
qp_lock(qpair);
@@ -3074,7 +3074,7 @@ ssize_t vmci_qpair_dequeue(struct vmci_qp *qpair,
if (!qpair || !buf)
return VMCI_ERROR_INVALID_ARGS;
- iov_iter_kvec(&to, READ | ITER_KVEC, &v, 1, buf_size);
+ iov_iter_kvec(&to, READ, &v, 1, buf_size);
qp_lock(qpair);
@@ -3119,7 +3119,7 @@ ssize_t vmci_qpair_peek(struct vmci_qp *qpair,
if (!qpair || !buf)
return VMCI_ERROR_INVALID_ARGS;
- iov_iter_kvec(&to, READ | ITER_KVEC, &v, 1, buf_size);
+ iov_iter_kvec(&to, READ, &v, 1, buf_size);
qp_lock(qpair);
diff --git a/drivers/misc/vmw_vmci/vmci_resource.c b/drivers/misc/vmw_vmci/vmci_resource.c
index 1ab6e8737a5f..da1ee2e1ba99 100644
--- a/drivers/misc/vmw_vmci/vmci_resource.c
+++ b/drivers/misc/vmw_vmci/vmci_resource.c
@@ -57,7 +57,8 @@ static struct vmci_resource *vmci_resource_lookup(struct vmci_handle handle,
if (r->type == type &&
rid == handle.resource &&
- (cid == handle.context || cid == VMCI_INVALID_ID)) {
+ (cid == handle.context || cid == VMCI_INVALID_ID ||
+ handle.context == VMCI_INVALID_ID)) {
resource = r;
break;
}
diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig
index 42e89060cd41..2f38a7ad07e0 100644
--- a/drivers/mmc/core/Kconfig
+++ b/drivers/mmc/core/Kconfig
@@ -14,7 +14,7 @@ config PWRSEQ_EMMC
config PWRSEQ_SD8787
tristate "HW reset support for SD8787 BT + Wifi module"
- depends on OF && (MWIFIEX || BT_MRVL_SDIO)
+ depends on OF && (MWIFIEX || BT_MRVL_SDIO || LIBERTAS_SDIO)
help
This selects hardware reset support for the SD8787 BT + Wifi
module. By default this option is set to n.
diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
index a0b9102c4c6e..c35b5b08bb33 100644
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -1371,6 +1371,16 @@ static void mmc_blk_data_prep(struct mmc_queue *mq, struct mmc_queue_req *mqrq,
if (brq->data.blocks > 1) {
/*
+ * Some SD cards in SPI mode return a CRC error or even lock up
+ * completely when trying to read the last block using a
+ * multiblock read command.
+ */
+ if (mmc_host_is_spi(card->host) && (rq_data_dir(req) == READ) &&
+ (blk_rq_pos(req) + blk_rq_sectors(req) ==
+ get_capacity(md->disk)))
+ brq->data.blocks--;
+
+ /*
* After a read error, we redo the request one sector
* at a time in order to accurately determine which
* sectors can be read successfully.
@@ -2698,7 +2708,7 @@ static int mmc_add_disk(struct mmc_blk_data *md)
int ret;
struct mmc_card *card = md->queue.card;
- device_add_disk(md->parent, md->disk);
+ device_add_disk(md->parent, md->disk, NULL);
md->force_ro.show = force_ro_show;
md->force_ro.store = force_ro_store;
sysfs_attr_init(&md->force_ro.attr);
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index abf9e884386c..f57f5de54206 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -235,7 +235,7 @@ int mmc_of_parse(struct mmc_host *host)
host->caps |= MMC_CAP_NEEDS_POLL;
ret = mmc_gpiod_request_cd(host, "cd", 0, true,
- cd_debounce_delay_ms,
+ cd_debounce_delay_ms * 1000,
&cd_gpio_invert);
if (!ret)
dev_info(host->parent, "Got CD GPIO\n");
diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c
index a8b9fee4d62a..ece34c734693 100644
--- a/drivers/mmc/core/pwrseq_simple.c
+++ b/drivers/mmc/core/pwrseq_simple.c
@@ -40,17 +40,21 @@ static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq,
struct gpio_descs *reset_gpios = pwrseq->reset_gpios;
if (!IS_ERR(reset_gpios)) {
- int i, *values;
+ unsigned long *values;
int nvalues = reset_gpios->ndescs;
- values = kmalloc_array(nvalues, sizeof(int), GFP_KERNEL);
+ values = bitmap_alloc(nvalues, GFP_KERNEL);
if (!values)
return;
- for (i = 0; i < nvalues; i++)
- values[i] = value;
+ if (value)
+ bitmap_fill(values, nvalues);
+ else
+ bitmap_zero(values, nvalues);
+
+ gpiod_set_array_value_cansleep(nvalues, reset_gpios->desc,
+ reset_gpios->info, values);
- gpiod_set_array_value_cansleep(nvalues, reset_gpios->desc, values);
kfree(values);
}
}
diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c
index 2a833686784b..86803a3a04dc 100644
--- a/drivers/mmc/core/slot-gpio.c
+++ b/drivers/mmc/core/slot-gpio.c
@@ -271,7 +271,7 @@ int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id,
if (debounce) {
ret = gpiod_set_debounce(desc, debounce);
if (ret < 0)
- ctx->cd_debounce_delay_ms = debounce;
+ ctx->cd_debounce_delay_ms = debounce / 1000;
}
if (gpio_invert)
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 694d0828215d..1b58739d9744 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -34,6 +34,16 @@ config MMC_QCOM_DML
if unsure, say N.
+config MMC_STM32_SDMMC
+ bool "STMicroelectronics STM32 SDMMC Controller"
+ depends on MMC_ARMMMCI
+ default y
+ help
+ This selects the STMicroelectronics STM32 SDMMC host controller.
+ If you have a STM32 sdmmc host with internal DMA say Y here.
+
+ If unsure, say N.
+
config MMC_PXA
tristate "Intel PXA25x/26x/27x Multimedia Card Interface support"
depends on ARCH_PXA
@@ -345,6 +355,7 @@ 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 MMC_SDHCI_PLTFM
+ depends on OF || ACPI
default ARCH_BCM_IPROC
select MMC_SDHCI_IO_ACCESSORS
help
@@ -592,6 +603,19 @@ config MMC_SDRICOH_CS
To compile this driver as a module, choose M here: the
module will be called sdricoh_cs.
+config MMC_SDHCI_SPRD
+ tristate "Spreadtrum SDIO host Controller"
+ depends on ARCH_SPRD
+ depends on MMC_SDHCI_PLTFM
+ select MMC_SDHCI_IO_ACCESSORS
+ help
+ This selects the SDIO Host Controller in Spreadtrum
+ SoCs, this driver supports R11(IP version: R11P0).
+
+ If you have a controller with this interface, say Y or M here.
+
+ If unsure, say N.
+
config MMC_TMIO_CORE
tristate
@@ -622,14 +646,24 @@ config MMC_SDHI_SYS_DMAC
config MMC_SDHI_INTERNAL_DMAC
tristate "DMA for SDHI SD/SDIO controllers using on-chip bus mastering"
- depends on ARM64 || COMPILE_TEST
+ depends on ARM64 || ARCH_R8A77470 || COMPILE_TEST
depends on MMC_SDHI
- default MMC_SDHI if ARM64
+ default MMC_SDHI if (ARM64 || ARCH_R8A77470)
help
This provides DMA support for SDHI SD/SDIO controllers
using on-chip bus mastering. This supports the controllers
found in arm64 based SoCs.
+config MMC_UNIPHIER
+ tristate "UniPhier SD/eMMC Host Controller support"
+ depends on ARCH_UNIPHIER || COMPILE_TEST
+ depends on OF
+ select MMC_TMIO_CORE
+ help
+ This provides support for the SD/eMMC controller found in
+ UniPhier SoCs. The eMMC variant of this controller is used
+ only for 32-bit SoCs.
+
config MMC_CB710
tristate "ENE CB710 MMC/SD Interface support"
depends on PCI
@@ -772,7 +806,7 @@ config MMC_SH_MMCIF
config MMC_JZ4740
tristate "Ingenic JZ47xx SD/Multimedia Card Interface support"
- depends on MACH_JZ4740 || MACH_JZ4780
+ depends on MIPS
help
This selects support for the SD/MMC controller on Ingenic
JZ4740, JZ4750, JZ4770 and JZ4780 SoCs.
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index ce8398e6f2c0..720d37777098 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -6,6 +6,7 @@
obj-$(CONFIG_MMC_ARMMMCI) += armmmci.o
armmmci-y := mmci.o
armmmci-$(CONFIG_MMC_QCOM_DML) += mmci_qcom_dml.o
+armmmci-$(CONFIG_MMC_STM32_SDMMC) += mmci_stm32_sdmmc.o
obj-$(CONFIG_MMC_PXA) += pxamci.o
obj-$(CONFIG_MMC_MXC) += mxcmmc.o
obj-$(CONFIG_MMC_MXS) += mxs-mmc.o
@@ -42,6 +43,7 @@ obj-$(CONFIG_MMC_TMIO_CORE) += tmio_mmc_core.o
obj-$(CONFIG_MMC_SDHI) += renesas_sdhi_core.o
obj-$(CONFIG_MMC_SDHI_SYS_DMAC) += renesas_sdhi_sys_dmac.o
obj-$(CONFIG_MMC_SDHI_INTERNAL_DMAC) += renesas_sdhi_internal_dmac.o
+obj-$(CONFIG_MMC_UNIPHIER) += uniphier-sd.o
obj-$(CONFIG_MMC_CB710) += cb710-mmc.o
obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o
octeon-mmc-objs := cavium.o cavium-octeon.o
@@ -91,6 +93,7 @@ obj-$(CONFIG_MMC_SDHCI_ST) += sdhci-st.o
obj-$(CONFIG_MMC_SDHCI_MICROCHIP_PIC32) += sdhci-pic32.o
obj-$(CONFIG_MMC_SDHCI_BRCMSTB) += sdhci-brcmstb.o
obj-$(CONFIG_MMC_SDHCI_OMAP) += sdhci-omap.o
+obj-$(CONFIG_MMC_SDHCI_SPRD) += sdhci-sprd.o
obj-$(CONFIG_MMC_CQHCI) += cqhci.o
ifeq ($(CONFIG_CB710_DEBUG),y)
diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
index ab47b018716a..d46c3439b508 100644
--- a/drivers/mmc/host/dw_mmc-exynos.c
+++ b/drivers/mmc/host/dw_mmc-exynos.c
@@ -253,6 +253,8 @@ static void dw_mci_exynos_config_hs400(struct dw_mci *host, u32 timing)
if (timing == MMC_TIMING_MMC_HS400) {
dqs |= DATA_STROBE_EN;
strobe = DQS_CTRL_RD_DELAY(strobe, priv->dqs_delay);
+ } else if (timing == MMC_TIMING_UHS_SDR104) {
+ dqs &= 0xffffff00;
} else {
dqs &= ~DATA_STROBE_EN;
}
@@ -312,6 +314,15 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
if (ios->bus_width == MMC_BUS_WIDTH_8)
wanted <<= 1;
break;
+ case MMC_TIMING_UHS_SDR104:
+ case MMC_TIMING_UHS_SDR50:
+ clksel = (priv->sdr_timing & 0xfff8ffff) |
+ (priv->ciu_div << 16);
+ break;
+ case MMC_TIMING_UHS_DDR50:
+ clksel = (priv->ddr_timing & 0xfff8ffff) |
+ (priv->ciu_div << 16);
+ break;
default:
clksel = priv->sdr_timing;
}
diff --git a/drivers/mmc/host/dw_mmc-hi3798cv200.c b/drivers/mmc/host/dw_mmc-hi3798cv200.c
index f9b333ff259e..bc51cef47c47 100644
--- a/drivers/mmc/host/dw_mmc-hi3798cv200.c
+++ b/drivers/mmc/host/dw_mmc-hi3798cv200.c
@@ -23,6 +23,12 @@ struct hi3798cv200_priv {
struct clk *drive_clk;
};
+static unsigned long dw_mci_hi3798cv200_caps[] = {
+ MMC_CAP_CMD23,
+ MMC_CAP_CMD23,
+ MMC_CAP_CMD23
+};
+
static void dw_mci_hi3798cv200_set_ios(struct dw_mci *host, struct mmc_ios *ios)
{
struct hi3798cv200_priv *priv = host->priv;
@@ -160,6 +166,8 @@ disable_sample_clk:
}
static const struct dw_mci_drv_data hi3798cv200_data = {
+ .caps = dw_mci_hi3798cv200_caps,
+ .num_caps = ARRAY_SIZE(dw_mci_hi3798cv200_caps),
.init = dw_mci_hi3798cv200_init,
.set_ios = dw_mci_hi3798cv200_set_ios,
.execute_tuning = dw_mci_hi3798cv200_execute_tuning,
diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c
index 993386c9ea50..0c1efd5100b7 100644
--- a/drivers/mmc/host/jz4740_mmc.c
+++ b/drivers/mmc/host/jz4740_mmc.c
@@ -115,7 +115,7 @@
enum jz4740_mmc_version {
JZ_MMC_JZ4740,
- JZ_MMC_JZ4750,
+ JZ_MMC_JZ4725B,
JZ_MMC_JZ4780,
};
@@ -176,7 +176,7 @@ struct jz4740_mmc_host {
static void jz4740_mmc_write_irq_mask(struct jz4740_mmc_host *host,
uint32_t val)
{
- if (host->version >= JZ_MMC_JZ4750)
+ if (host->version >= JZ_MMC_JZ4725B)
return writel(val, host->base + JZ_REG_MMC_IMASK);
else
return writew(val, host->base + JZ_REG_MMC_IMASK);
@@ -1012,6 +1012,7 @@ static void jz4740_mmc_free_gpios(struct platform_device *pdev)
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,jz4780-mmc", .data = (void *) JZ_MMC_JZ4780 },
{},
};
diff --git a/drivers/mmc/host/meson-mx-sdio.c b/drivers/mmc/host/meson-mx-sdio.c
index 2cfec33178c1..abe253c262a2 100644
--- a/drivers/mmc/host/meson-mx-sdio.c
+++ b/drivers/mmc/host/meson-mx-sdio.c
@@ -294,7 +294,7 @@ static void meson_mx_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
switch (ios->power_mode) {
case MMC_POWER_OFF:
vdd = 0;
- /* fall-through: */
+ /* fall through */
case MMC_POWER_UP:
if (!IS_ERR(mmc->supply.vmmc)) {
host->error = mmc_regulator_set_ocr(mmc,
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 1841d250e9e2..82bab35fff41 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -28,8 +28,7 @@
#include <linux/amba/bus.h>
#include <linux/clk.h>
#include <linux/scatterlist.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
+#include <linux/of.h>
#include <linux/regulator/consumer.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
@@ -37,6 +36,7 @@
#include <linux/pm_runtime.h>
#include <linux/types.h>
#include <linux/pinctrl/consumer.h>
+#include <linux/reset.h>
#include <asm/div64.h>
#include <asm/io.h>
@@ -46,41 +46,77 @@
#define DRIVER_NAME "mmci-pl18x"
+#ifdef CONFIG_DMA_ENGINE
+void mmci_variant_init(struct mmci_host *host);
+#else
+static inline void mmci_variant_init(struct mmci_host *host) {}
+#endif
+
+#ifdef CONFIG_MMC_STM32_SDMMC
+void sdmmc_variant_init(struct mmci_host *host);
+#else
+static inline void sdmmc_variant_init(struct mmci_host *host) {}
+#endif
+
static unsigned int fmax = 515633;
static struct variant_data variant_arm = {
.fifosize = 16 * 4,
.fifohalfsize = 8 * 4,
+ .cmdreg_cpsm_enable = MCI_CPSM_ENABLE,
+ .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP,
+ .cmdreg_srsp_crc = MCI_CPSM_RESPONSE,
+ .cmdreg_srsp = MCI_CPSM_RESPONSE,
.datalength_bits = 16,
+ .datactrl_blocksz = 11,
+ .datactrl_dpsm_enable = MCI_DPSM_ENABLE,
.pwrreg_powerup = MCI_PWR_UP,
.f_max = 100000000,
.reversed_irq_handling = true,
.mmcimask1 = true,
+ .irq_pio_mask = MCI_IRQ_PIO_MASK,
.start_err = MCI_STARTBITERR,
.opendrain = MCI_ROD,
+ .init = mmci_variant_init,
};
static struct variant_data variant_arm_extended_fifo = {
.fifosize = 128 * 4,
.fifohalfsize = 64 * 4,
+ .cmdreg_cpsm_enable = MCI_CPSM_ENABLE,
+ .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP,
+ .cmdreg_srsp_crc = MCI_CPSM_RESPONSE,
+ .cmdreg_srsp = MCI_CPSM_RESPONSE,
.datalength_bits = 16,
+ .datactrl_blocksz = 11,
+ .datactrl_dpsm_enable = MCI_DPSM_ENABLE,
.pwrreg_powerup = MCI_PWR_UP,
.f_max = 100000000,
.mmcimask1 = true,
+ .irq_pio_mask = MCI_IRQ_PIO_MASK,
.start_err = MCI_STARTBITERR,
.opendrain = MCI_ROD,
+ .init = mmci_variant_init,
};
static struct variant_data variant_arm_extended_fifo_hwfc = {
.fifosize = 128 * 4,
.fifohalfsize = 64 * 4,
.clkreg_enable = MCI_ARM_HWFCEN,
+ .cmdreg_cpsm_enable = MCI_CPSM_ENABLE,
+ .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP,
+ .cmdreg_srsp_crc = MCI_CPSM_RESPONSE,
+ .cmdreg_srsp = MCI_CPSM_RESPONSE,
.datalength_bits = 16,
+ .datactrl_blocksz = 11,
+ .datactrl_dpsm_enable = MCI_DPSM_ENABLE,
.pwrreg_powerup = MCI_PWR_UP,
.f_max = 100000000,
.mmcimask1 = true,
+ .irq_pio_mask = MCI_IRQ_PIO_MASK,
.start_err = MCI_STARTBITERR,
.opendrain = MCI_ROD,
+ .init = mmci_variant_init,
};
static struct variant_data variant_u300 = {
@@ -88,7 +124,13 @@ static struct variant_data variant_u300 = {
.fifohalfsize = 8 * 4,
.clkreg_enable = MCI_ST_U300_HWFCEN,
.clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
+ .cmdreg_cpsm_enable = MCI_CPSM_ENABLE,
+ .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP,
+ .cmdreg_srsp_crc = MCI_CPSM_RESPONSE,
+ .cmdreg_srsp = MCI_CPSM_RESPONSE,
.datalength_bits = 16,
+ .datactrl_blocksz = 11,
+ .datactrl_dpsm_enable = MCI_DPSM_ENABLE,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
.st_sdio = true,
.pwrreg_powerup = MCI_PWR_ON,
@@ -97,8 +139,10 @@ static struct variant_data variant_u300 = {
.pwrreg_clkgate = true,
.pwrreg_nopower = true,
.mmcimask1 = true,
+ .irq_pio_mask = MCI_IRQ_PIO_MASK,
.start_err = MCI_STARTBITERR,
.opendrain = MCI_OD,
+ .init = mmci_variant_init,
};
static struct variant_data variant_nomadik = {
@@ -106,7 +150,13 @@ static struct variant_data variant_nomadik = {
.fifohalfsize = 8 * 4,
.clkreg = MCI_CLK_ENABLE,
.clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
+ .cmdreg_cpsm_enable = MCI_CPSM_ENABLE,
+ .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP,
+ .cmdreg_srsp_crc = MCI_CPSM_RESPONSE,
+ .cmdreg_srsp = MCI_CPSM_RESPONSE,
.datalength_bits = 24,
+ .datactrl_blocksz = 11,
+ .datactrl_dpsm_enable = MCI_DPSM_ENABLE,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
.st_sdio = true,
.st_clkdiv = true,
@@ -116,8 +166,10 @@ static struct variant_data variant_nomadik = {
.pwrreg_clkgate = true,
.pwrreg_nopower = true,
.mmcimask1 = true,
+ .irq_pio_mask = MCI_IRQ_PIO_MASK,
.start_err = MCI_STARTBITERR,
.opendrain = MCI_OD,
+ .init = mmci_variant_init,
};
static struct variant_data variant_ux500 = {
@@ -127,7 +179,13 @@ static struct variant_data variant_ux500 = {
.clkreg_enable = MCI_ST_UX500_HWFCEN,
.clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
.clkreg_neg_edge_enable = MCI_ST_UX500_NEG_EDGE,
+ .cmdreg_cpsm_enable = MCI_CPSM_ENABLE,
+ .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP,
+ .cmdreg_srsp_crc = MCI_CPSM_RESPONSE,
+ .cmdreg_srsp = MCI_CPSM_RESPONSE,
.datalength_bits = 24,
+ .datactrl_blocksz = 11,
+ .datactrl_dpsm_enable = MCI_DPSM_ENABLE,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
.st_sdio = true,
.st_clkdiv = true,
@@ -141,8 +199,10 @@ static struct variant_data variant_ux500 = {
.busy_detect_mask = MCI_ST_BUSYENDMASK,
.pwrreg_nopower = true,
.mmcimask1 = true,
+ .irq_pio_mask = MCI_IRQ_PIO_MASK,
.start_err = MCI_STARTBITERR,
.opendrain = MCI_OD,
+ .init = mmci_variant_init,
};
static struct variant_data variant_ux500v2 = {
@@ -152,8 +212,14 @@ static struct variant_data variant_ux500v2 = {
.clkreg_enable = MCI_ST_UX500_HWFCEN,
.clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
.clkreg_neg_edge_enable = MCI_ST_UX500_NEG_EDGE,
+ .cmdreg_cpsm_enable = MCI_CPSM_ENABLE,
+ .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP,
+ .cmdreg_srsp_crc = MCI_CPSM_RESPONSE,
+ .cmdreg_srsp = MCI_CPSM_RESPONSE,
.datactrl_mask_ddrmode = MCI_DPSM_ST_DDRMODE,
.datalength_bits = 24,
+ .datactrl_blocksz = 11,
+ .datactrl_dpsm_enable = MCI_DPSM_ENABLE,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
.st_sdio = true,
.st_clkdiv = true,
@@ -168,8 +234,10 @@ static struct variant_data variant_ux500v2 = {
.busy_detect_mask = MCI_ST_BUSYENDMASK,
.pwrreg_nopower = true,
.mmcimask1 = true,
+ .irq_pio_mask = MCI_IRQ_PIO_MASK,
.start_err = MCI_STARTBITERR,
.opendrain = MCI_OD,
+ .init = mmci_variant_init,
};
static struct variant_data variant_stm32 = {
@@ -179,7 +247,14 @@ static struct variant_data variant_stm32 = {
.clkreg_enable = MCI_ST_UX500_HWFCEN,
.clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
.clkreg_neg_edge_enable = MCI_ST_UX500_NEG_EDGE,
+ .cmdreg_cpsm_enable = MCI_CPSM_ENABLE,
+ .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP,
+ .cmdreg_srsp_crc = MCI_CPSM_RESPONSE,
+ .cmdreg_srsp = MCI_CPSM_RESPONSE,
+ .irq_pio_mask = MCI_IRQ_PIO_MASK,
.datalength_bits = 24,
+ .datactrl_blocksz = 11,
+ .datactrl_dpsm_enable = MCI_DPSM_ENABLE,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
.st_sdio = true,
.st_clkdiv = true,
@@ -187,6 +262,26 @@ static struct variant_data variant_stm32 = {
.f_max = 48000000,
.pwrreg_clkgate = true,
.pwrreg_nopower = true,
+ .init = mmci_variant_init,
+};
+
+static struct variant_data variant_stm32_sdmmc = {
+ .fifosize = 16 * 4,
+ .fifohalfsize = 8 * 4,
+ .f_max = 208000000,
+ .stm32_clkdiv = true,
+ .cmdreg_cpsm_enable = MCI_CPSM_STM32_ENABLE,
+ .cmdreg_lrsp_crc = MCI_CPSM_STM32_LRSP_CRC,
+ .cmdreg_srsp_crc = MCI_CPSM_STM32_SRSP_CRC,
+ .cmdreg_srsp = MCI_CPSM_STM32_SRSP,
+ .data_cmd_enable = MCI_CPSM_STM32_CMDTRANS,
+ .irq_pio_mask = MCI_IRQ_PIO_STM32_MASK,
+ .datactrl_first = true,
+ .datacnt_useless = true,
+ .datalength_bits = 25,
+ .datactrl_blocksz = 14,
+ .stm32_idmabsize_mask = GENMASK(12, 5),
+ .init = sdmmc_variant_init,
};
static struct variant_data variant_qcom = {
@@ -197,15 +292,22 @@ static struct variant_data variant_qcom = {
MCI_QCOM_CLK_SELECT_IN_FBCLK,
.clkreg_8bit_bus_enable = MCI_QCOM_CLK_WIDEBUS_8,
.datactrl_mask_ddrmode = MCI_QCOM_CLK_SELECT_IN_DDR_MODE,
+ .cmdreg_cpsm_enable = MCI_CPSM_ENABLE,
+ .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP,
+ .cmdreg_srsp_crc = MCI_CPSM_RESPONSE,
+ .cmdreg_srsp = MCI_CPSM_RESPONSE,
.data_cmd_enable = MCI_CPSM_QCOM_DATCMD,
.blksz_datactrl4 = true,
.datalength_bits = 24,
+ .datactrl_blocksz = 11,
+ .datactrl_dpsm_enable = MCI_DPSM_ENABLE,
.pwrreg_powerup = MCI_PWR_UP,
.f_max = 208000000,
.explicit_mclk_control = true,
.qcom_fifo = true,
.qcom_dml = true,
.mmcimask1 = true,
+ .irq_pio_mask = MCI_IRQ_PIO_MASK,
.start_err = MCI_STARTBITERR,
.opendrain = MCI_ROD,
.init = qcom_variant_init,
@@ -226,24 +328,6 @@ static int mmci_card_busy(struct mmc_host *mmc)
return busy;
}
-/*
- * Validate mmc prerequisites
- */
-static int mmci_validate_data(struct mmci_host *host,
- struct mmc_data *data)
-{
- if (!data)
- return 0;
-
- if (!is_power_of_2(data->blksz)) {
- dev_err(mmc_dev(host->mmc),
- "unsupported block size (%d bytes)\n", data->blksz);
- return -EINVAL;
- }
-
- return 0;
-}
-
static void mmci_reg_delay(struct mmci_host *host)
{
/*
@@ -262,7 +346,7 @@ static void mmci_reg_delay(struct mmci_host *host)
/*
* This must be called with host->lock held
*/
-static void mmci_write_clkreg(struct mmci_host *host, u32 clk)
+void mmci_write_clkreg(struct mmci_host *host, u32 clk)
{
if (host->clk_reg != clk) {
host->clk_reg = clk;
@@ -273,7 +357,7 @@ static void mmci_write_clkreg(struct mmci_host *host, u32 clk)
/*
* This must be called with host->lock held
*/
-static void mmci_write_pwrreg(struct mmci_host *host, u32 pwr)
+void mmci_write_pwrreg(struct mmci_host *host, u32 pwr)
{
if (host->pwr_reg != pwr) {
host->pwr_reg = pwr;
@@ -357,6 +441,135 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
mmci_write_clkreg(host, clk);
}
+void mmci_dma_release(struct mmci_host *host)
+{
+ if (host->ops && host->ops->dma_release)
+ host->ops->dma_release(host);
+
+ host->use_dma = false;
+}
+
+void mmci_dma_setup(struct mmci_host *host)
+{
+ if (!host->ops || !host->ops->dma_setup)
+ return;
+
+ if (host->ops->dma_setup(host))
+ return;
+
+ /* initialize pre request cookie */
+ host->next_cookie = 1;
+
+ host->use_dma = true;
+}
+
+/*
+ * Validate mmc prerequisites
+ */
+static int mmci_validate_data(struct mmci_host *host,
+ struct mmc_data *data)
+{
+ if (!data)
+ return 0;
+
+ if (!is_power_of_2(data->blksz)) {
+ dev_err(mmc_dev(host->mmc),
+ "unsupported block size (%d bytes)\n", data->blksz);
+ return -EINVAL;
+ }
+
+ if (host->ops && host->ops->validate_data)
+ return host->ops->validate_data(host, data);
+
+ return 0;
+}
+
+int mmci_prep_data(struct mmci_host *host, struct mmc_data *data, bool next)
+{
+ int err;
+
+ if (!host->ops || !host->ops->prep_data)
+ return 0;
+
+ err = host->ops->prep_data(host, data, next);
+
+ if (next && !err)
+ data->host_cookie = ++host->next_cookie < 0 ?
+ 1 : host->next_cookie;
+
+ return err;
+}
+
+void mmci_unprep_data(struct mmci_host *host, struct mmc_data *data,
+ int err)
+{
+ if (host->ops && host->ops->unprep_data)
+ host->ops->unprep_data(host, data, err);
+
+ data->host_cookie = 0;
+}
+
+void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data)
+{
+ WARN_ON(data->host_cookie && data->host_cookie != host->next_cookie);
+
+ if (host->ops && host->ops->get_next_data)
+ host->ops->get_next_data(host, data);
+}
+
+int mmci_dma_start(struct mmci_host *host, unsigned int datactrl)
+{
+ struct mmc_data *data = host->data;
+ int ret;
+
+ if (!host->use_dma)
+ return -EINVAL;
+
+ ret = mmci_prep_data(host, data, false);
+ if (ret)
+ return ret;
+
+ if (!host->ops || !host->ops->dma_start)
+ return -EINVAL;
+
+ /* Okay, go for it. */
+ dev_vdbg(mmc_dev(host->mmc),
+ "Submit MMCI DMA job, sglen %d blksz %04x blks %04x flags %08x\n",
+ data->sg_len, data->blksz, data->blocks, data->flags);
+
+ host->ops->dma_start(host, &datactrl);
+
+ /* Trigger the DMA transfer */
+ mmci_write_datactrlreg(host, datactrl);
+
+ /*
+ * Let the MMCI say when the data is ended and it's time
+ * to fire next DMA request. When that happens, MMCI will
+ * call mmci_data_end()
+ */
+ writel(readl(host->base + MMCIMASK0) | MCI_DATAENDMASK,
+ host->base + MMCIMASK0);
+ return 0;
+}
+
+void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data)
+{
+ if (!host->use_dma)
+ return;
+
+ if (host->ops && host->ops->dma_finalize)
+ host->ops->dma_finalize(host, data);
+}
+
+void mmci_dma_error(struct mmci_host *host)
+{
+ if (!host->use_dma)
+ return;
+
+ if (host->ops && host->ops->dma_error)
+ host->ops->dma_error(host);
+}
+
static void
mmci_request_end(struct mmci_host *host, struct mmc_request *mrq)
{
@@ -378,7 +591,7 @@ static void mmci_set_mask1(struct mmci_host *host, unsigned int mask)
if (host->singleirq) {
unsigned int mask0 = readl(base + MMCIMASK0);
- mask0 &= ~MCI_IRQ1MASK;
+ mask0 &= ~variant->irq_pio_mask;
mask0 |= mask;
writel(mask0, base + MMCIMASK0);
@@ -415,31 +628,50 @@ static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data)
* no custom DMA interfaces are supported.
*/
#ifdef CONFIG_DMA_ENGINE
-static void mmci_dma_setup(struct mmci_host *host)
+struct mmci_dmae_next {
+ struct dma_async_tx_descriptor *desc;
+ struct dma_chan *chan;
+};
+
+struct mmci_dmae_priv {
+ struct dma_chan *cur;
+ struct dma_chan *rx_channel;
+ struct dma_chan *tx_channel;
+ struct dma_async_tx_descriptor *desc_current;
+ struct mmci_dmae_next next_data;
+};
+
+int mmci_dmae_setup(struct mmci_host *host)
{
const char *rxname, *txname;
+ struct mmci_dmae_priv *dmae;
- host->dma_rx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "rx");
- host->dma_tx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "tx");
+ dmae = devm_kzalloc(mmc_dev(host->mmc), sizeof(*dmae), GFP_KERNEL);
+ if (!dmae)
+ return -ENOMEM;
- /* initialize pre request cookie */
- host->next_data.cookie = 1;
+ host->dma_priv = dmae;
+
+ dmae->rx_channel = dma_request_slave_channel(mmc_dev(host->mmc),
+ "rx");
+ dmae->tx_channel = dma_request_slave_channel(mmc_dev(host->mmc),
+ "tx");
/*
* If only an RX channel is specified, the driver will
* attempt to use it bidirectionally, however if it is
* is specified but cannot be located, DMA will be disabled.
*/
- if (host->dma_rx_channel && !host->dma_tx_channel)
- host->dma_tx_channel = host->dma_rx_channel;
+ if (dmae->rx_channel && !dmae->tx_channel)
+ dmae->tx_channel = dmae->rx_channel;
- if (host->dma_rx_channel)
- rxname = dma_chan_name(host->dma_rx_channel);
+ if (dmae->rx_channel)
+ rxname = dma_chan_name(dmae->rx_channel);
else
rxname = "none";
- if (host->dma_tx_channel)
- txname = dma_chan_name(host->dma_tx_channel);
+ if (dmae->tx_channel)
+ txname = dma_chan_name(dmae->tx_channel);
else
txname = "none";
@@ -450,66 +682,84 @@ static void mmci_dma_setup(struct mmci_host *host)
* Limit the maximum segment size in any SG entry according to
* the parameters of the DMA engine device.
*/
- if (host->dma_tx_channel) {
- struct device *dev = host->dma_tx_channel->device->dev;
+ if (dmae->tx_channel) {
+ struct device *dev = dmae->tx_channel->device->dev;
unsigned int max_seg_size = dma_get_max_seg_size(dev);
if (max_seg_size < host->mmc->max_seg_size)
host->mmc->max_seg_size = max_seg_size;
}
- if (host->dma_rx_channel) {
- struct device *dev = host->dma_rx_channel->device->dev;
+ if (dmae->rx_channel) {
+ struct device *dev = dmae->rx_channel->device->dev;
unsigned int max_seg_size = dma_get_max_seg_size(dev);
if (max_seg_size < host->mmc->max_seg_size)
host->mmc->max_seg_size = max_seg_size;
}
- if (host->ops && host->ops->dma_setup)
- host->ops->dma_setup(host);
+ if (!dmae->tx_channel || !dmae->rx_channel) {
+ mmci_dmae_release(host);
+ return -EINVAL;
+ }
+
+ return 0;
}
/*
* This is used in or so inline it
* so it can be discarded.
*/
-static inline void mmci_dma_release(struct mmci_host *host)
+void mmci_dmae_release(struct mmci_host *host)
{
- if (host->dma_rx_channel)
- dma_release_channel(host->dma_rx_channel);
- if (host->dma_tx_channel)
- dma_release_channel(host->dma_tx_channel);
- host->dma_rx_channel = host->dma_tx_channel = NULL;
-}
+ struct mmci_dmae_priv *dmae = host->dma_priv;
-static void mmci_dma_data_error(struct mmci_host *host)
-{
- dev_err(mmc_dev(host->mmc), "error during DMA transfer!\n");
- dmaengine_terminate_all(host->dma_current);
- host->dma_in_progress = false;
- host->dma_current = NULL;
- host->dma_desc_current = NULL;
- host->data->host_cookie = 0;
+ if (dmae->rx_channel)
+ dma_release_channel(dmae->rx_channel);
+ if (dmae->tx_channel)
+ dma_release_channel(dmae->tx_channel);
+ dmae->rx_channel = dmae->tx_channel = NULL;
}
static void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data)
{
+ struct mmci_dmae_priv *dmae = host->dma_priv;
struct dma_chan *chan;
if (data->flags & MMC_DATA_READ)
- chan = host->dma_rx_channel;
+ chan = dmae->rx_channel;
else
- chan = host->dma_tx_channel;
+ chan = dmae->tx_channel;
dma_unmap_sg(chan->device->dev, data->sg, data->sg_len,
mmc_get_dma_dir(data));
}
-static void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data)
+void mmci_dmae_error(struct mmci_host *host)
{
+ struct mmci_dmae_priv *dmae = host->dma_priv;
+
+ if (!dma_inprogress(host))
+ return;
+
+ dev_err(mmc_dev(host->mmc), "error during DMA transfer!\n");
+ dmaengine_terminate_all(dmae->cur);
+ host->dma_in_progress = false;
+ dmae->cur = NULL;
+ dmae->desc_current = NULL;
+ host->data->host_cookie = 0;
+
+ mmci_dma_unmap(host, host->data);
+}
+
+void mmci_dmae_finalize(struct mmci_host *host, struct mmc_data *data)
+{
+ struct mmci_dmae_priv *dmae = host->dma_priv;
u32 status;
int i;
+ if (!dma_inprogress(host))
+ return;
+
/* Wait up to 1ms for the DMA to complete */
for (i = 0; ; i++) {
status = readl(host->base + MMCISTATUS);
@@ -525,13 +775,12 @@ static void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data)
* contiguous buffers. On TX, we'll get a FIFO underrun error.
*/
if (status & MCI_RXDATAAVLBLMASK) {
- mmci_dma_data_error(host);
+ mmci_dma_error(host);
if (!data->error)
data->error = -EIO;
- }
-
- if (!data->host_cookie)
+ } else if (!data->host_cookie) {
mmci_dma_unmap(host, data);
+ }
/*
* Use of DMA with scatter-gather is impossible.
@@ -543,15 +792,16 @@ static void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data)
}
host->dma_in_progress = false;
- host->dma_current = NULL;
- host->dma_desc_current = NULL;
+ dmae->cur = NULL;
+ dmae->desc_current = NULL;
}
/* prepares DMA channel and DMA descriptor, returns non-zero on failure */
-static int __mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data,
+static int _mmci_dmae_prep_data(struct mmci_host *host, struct mmc_data *data,
struct dma_chan **dma_chan,
struct dma_async_tx_descriptor **dma_desc)
{
+ struct mmci_dmae_priv *dmae = host->dma_priv;
struct variant_data *variant = host->variant;
struct dma_slave_config conf = {
.src_addr = host->phybase + MMCIFIFO,
@@ -570,10 +820,10 @@ static int __mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data,
if (data->flags & MMC_DATA_READ) {
conf.direction = DMA_DEV_TO_MEM;
- chan = host->dma_rx_channel;
+ chan = dmae->rx_channel;
} else {
conf.direction = DMA_MEM_TO_DEV;
- chan = host->dma_tx_channel;
+ chan = dmae->tx_channel;
}
/* If there's no DMA channel, fall back to PIO */
@@ -610,160 +860,137 @@ static int __mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data,
return -ENOMEM;
}
-static inline int mmci_dma_prep_data(struct mmci_host *host,
- struct mmc_data *data)
+int mmci_dmae_prep_data(struct mmci_host *host,
+ struct mmc_data *data,
+ bool next)
{
+ struct mmci_dmae_priv *dmae = host->dma_priv;
+ struct mmci_dmae_next *nd = &dmae->next_data;
+
+ if (!host->use_dma)
+ return -EINVAL;
+
+ if (next)
+ return _mmci_dmae_prep_data(host, data, &nd->chan, &nd->desc);
/* Check if next job is already prepared. */
- if (host->dma_current && host->dma_desc_current)
+ if (dmae->cur && dmae->desc_current)
return 0;
/* No job were prepared thus do it now. */
- return __mmci_dma_prep_data(host, data, &host->dma_current,
- &host->dma_desc_current);
-}
-
-static inline int mmci_dma_prep_next(struct mmci_host *host,
- struct mmc_data *data)
-{
- struct mmci_host_next *nd = &host->next_data;
- return __mmci_dma_prep_data(host, data, &nd->dma_chan, &nd->dma_desc);
+ return _mmci_dmae_prep_data(host, data, &dmae->cur,
+ &dmae->desc_current);
}
-static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl)
+int mmci_dmae_start(struct mmci_host *host, unsigned int *datactrl)
{
- int ret;
+ struct mmci_dmae_priv *dmae = host->dma_priv;
struct mmc_data *data = host->data;
- ret = mmci_dma_prep_data(host, host->data);
- if (ret)
- return ret;
-
- /* Okay, go for it. */
- dev_vdbg(mmc_dev(host->mmc),
- "Submit MMCI DMA job, sglen %d blksz %04x blks %04x flags %08x\n",
- data->sg_len, data->blksz, data->blocks, data->flags);
host->dma_in_progress = true;
- dmaengine_submit(host->dma_desc_current);
- dma_async_issue_pending(host->dma_current);
+ dmaengine_submit(dmae->desc_current);
+ dma_async_issue_pending(dmae->cur);
if (host->variant->qcom_dml)
dml_start_xfer(host, data);
- datactrl |= MCI_DPSM_DMAENABLE;
+ *datactrl |= MCI_DPSM_DMAENABLE;
- /* Trigger the DMA transfer */
- mmci_write_datactrlreg(host, datactrl);
-
- /*
- * Let the MMCI say when the data is ended and it's time
- * to fire next DMA request. When that happens, MMCI will
- * call mmci_data_end()
- */
- writel(readl(host->base + MMCIMASK0) | MCI_DATAENDMASK,
- host->base + MMCIMASK0);
return 0;
}
-static void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data)
+void mmci_dmae_get_next_data(struct mmci_host *host, struct mmc_data *data)
{
- struct mmci_host_next *next = &host->next_data;
-
- WARN_ON(data->host_cookie && data->host_cookie != next->cookie);
- WARN_ON(!data->host_cookie && (next->dma_desc || next->dma_chan));
-
- host->dma_desc_current = next->dma_desc;
- host->dma_current = next->dma_chan;
- next->dma_desc = NULL;
- next->dma_chan = NULL;
-}
+ struct mmci_dmae_priv *dmae = host->dma_priv;
+ struct mmci_dmae_next *next = &dmae->next_data;
-static void mmci_pre_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
- struct mmci_host *host = mmc_priv(mmc);
- struct mmc_data *data = mrq->data;
- struct mmci_host_next *nd = &host->next_data;
-
- if (!data)
+ if (!host->use_dma)
return;
- BUG_ON(data->host_cookie);
+ WARN_ON(!data->host_cookie && (next->desc || next->chan));
- if (mmci_validate_data(host, data))
- return;
-
- if (!mmci_dma_prep_next(host, data))
- data->host_cookie = ++nd->cookie < 0 ? 1 : nd->cookie;
+ dmae->desc_current = next->desc;
+ dmae->cur = next->chan;
+ next->desc = NULL;
+ next->chan = NULL;
}
-static void mmci_post_request(struct mmc_host *mmc, struct mmc_request *mrq,
- int err)
+void mmci_dmae_unprep_data(struct mmci_host *host,
+ struct mmc_data *data, int err)
+
{
- struct mmci_host *host = mmc_priv(mmc);
- struct mmc_data *data = mrq->data;
+ struct mmci_dmae_priv *dmae = host->dma_priv;
- if (!data || !data->host_cookie)
+ if (!host->use_dma)
return;
mmci_dma_unmap(host, data);
if (err) {
- struct mmci_host_next *next = &host->next_data;
+ struct mmci_dmae_next *next = &dmae->next_data;
struct dma_chan *chan;
if (data->flags & MMC_DATA_READ)
- chan = host->dma_rx_channel;
+ chan = dmae->rx_channel;
else
- chan = host->dma_tx_channel;
+ chan = dmae->tx_channel;
dmaengine_terminate_all(chan);
- if (host->dma_desc_current == next->dma_desc)
- host->dma_desc_current = NULL;
+ if (dmae->desc_current == next->desc)
+ dmae->desc_current = NULL;
- if (host->dma_current == next->dma_chan) {
+ if (dmae->cur == next->chan) {
host->dma_in_progress = false;
- host->dma_current = NULL;
+ dmae->cur = NULL;
}
- next->dma_desc = NULL;
- next->dma_chan = NULL;
- data->host_cookie = 0;
+ next->desc = NULL;
+ next->chan = NULL;
}
}
-#else
-/* Blank functions if the DMA engine is not available */
-static void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data)
-{
-}
-static inline void mmci_dma_setup(struct mmci_host *host)
-{
-}
+static struct mmci_host_ops mmci_variant_ops = {
+ .prep_data = mmci_dmae_prep_data,
+ .unprep_data = mmci_dmae_unprep_data,
+ .get_next_data = mmci_dmae_get_next_data,
+ .dma_setup = mmci_dmae_setup,
+ .dma_release = mmci_dmae_release,
+ .dma_start = mmci_dmae_start,
+ .dma_finalize = mmci_dmae_finalize,
+ .dma_error = mmci_dmae_error,
+};
-static inline void mmci_dma_release(struct mmci_host *host)
+void mmci_variant_init(struct mmci_host *host)
{
+ host->ops = &mmci_variant_ops;
}
+#endif
-static inline void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data)
+static void mmci_pre_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
-}
+ struct mmci_host *host = mmc_priv(mmc);
+ struct mmc_data *data = mrq->data;
-static inline void mmci_dma_finalize(struct mmci_host *host,
- struct mmc_data *data)
-{
-}
+ if (!data)
+ return;
-static inline void mmci_dma_data_error(struct mmci_host *host)
-{
+ WARN_ON(data->host_cookie);
+
+ if (mmci_validate_data(host, data))
+ return;
+
+ mmci_prep_data(host, data, true);
}
-static inline int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl)
+static void mmci_post_request(struct mmc_host *mmc, struct mmc_request *mrq,
+ int err)
{
- return -ENOSYS;
-}
+ struct mmci_host *host = mmc_priv(mmc);
+ struct mmc_data *data = mrq->data;
-#define mmci_pre_request NULL
-#define mmci_post_request NULL
+ if (!data || !data->host_cookie)
+ return;
-#endif
+ mmci_unprep_data(host, data, err);
+}
static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
{
@@ -793,11 +1020,11 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
BUG_ON(1 << blksz_bits != data->blksz);
if (variant->blksz_datactrl16)
- datactrl = MCI_DPSM_ENABLE | (data->blksz << 16);
+ datactrl = variant->datactrl_dpsm_enable | (data->blksz << 16);
else if (variant->blksz_datactrl4)
- datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
+ datactrl = variant->datactrl_dpsm_enable | (data->blksz << 4);
else
- datactrl = MCI_DPSM_ENABLE | blksz_bits << 4;
+ datactrl = variant->datactrl_dpsm_enable | blksz_bits << 4;
if (data->flags & MMC_DATA_READ)
datactrl |= MCI_DPSM_DIRECTION;
@@ -831,7 +1058,7 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
* Attempt to use DMA operation mode, if this
* should fail, fall back to PIO mode
*/
- if (!mmci_dma_start_data(host, datactrl))
+ if (!mmci_dma_start(host, datactrl))
return;
/* IRQ mode, map the SG list for CPU reading/writing */
@@ -868,16 +1095,19 @@ mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c)
dev_dbg(mmc_dev(host->mmc), "op %02x arg %08x flags %08x\n",
cmd->opcode, cmd->arg, cmd->flags);
- if (readl(base + MMCICOMMAND) & MCI_CPSM_ENABLE) {
+ if (readl(base + MMCICOMMAND) & host->variant->cmdreg_cpsm_enable) {
writel(0, base + MMCICOMMAND);
mmci_reg_delay(host);
}
- c |= cmd->opcode | MCI_CPSM_ENABLE;
+ c |= cmd->opcode | host->variant->cmdreg_cpsm_enable;
if (cmd->flags & MMC_RSP_PRESENT) {
if (cmd->flags & MMC_RSP_136)
- c |= MCI_CPSM_LONGRSP;
- c |= MCI_CPSM_RESPONSE;
+ c |= host->variant->cmdreg_lrsp_crc;
+ else if (cmd->flags & MMC_RSP_CRC)
+ c |= host->variant->cmdreg_srsp_crc;
+ else
+ c |= host->variant->cmdreg_srsp;
}
if (/*interrupt*/0)
c |= MCI_CPSM_INTERRUPT;
@@ -895,21 +1125,22 @@ static void
mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
unsigned int status)
{
+ unsigned int status_err;
+
/* Make sure we have data to handle */
if (!data)
return;
/* First check for errors */
- if (status & (MCI_DATACRCFAIL | MCI_DATATIMEOUT |
- host->variant->start_err |
- MCI_TXUNDERRUN | MCI_RXOVERRUN)) {
+ status_err = status & (host->variant->start_err |
+ MCI_DATACRCFAIL | MCI_DATATIMEOUT |
+ MCI_TXUNDERRUN | MCI_RXOVERRUN);
+
+ if (status_err) {
u32 remain, success;
/* Terminate the DMA transfer */
- if (dma_inprogress(host)) {
- mmci_dma_data_error(host);
- mmci_dma_unmap(host, data);
- }
+ mmci_dma_error(host);
/*
* Calculate how far we are into the transfer. Note that
@@ -918,22 +1149,26 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
* can be as much as a FIFO-worth of data ahead. This
* matters for FIFO overruns only.
*/
- remain = readl(host->base + MMCIDATACNT);
- success = data->blksz * data->blocks - remain;
+ if (!host->variant->datacnt_useless) {
+ remain = readl(host->base + MMCIDATACNT);
+ success = data->blksz * data->blocks - remain;
+ } else {
+ success = 0;
+ }
dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ, status 0x%08x at 0x%08x\n",
- status, success);
- if (status & MCI_DATACRCFAIL) {
+ status_err, success);
+ if (status_err & MCI_DATACRCFAIL) {
/* Last block was not successful */
success -= 1;
data->error = -EILSEQ;
- } else if (status & MCI_DATATIMEOUT) {
+ } else if (status_err & MCI_DATATIMEOUT) {
data->error = -ETIMEDOUT;
- } else if (status & MCI_STARTBITERR) {
+ } else if (status_err & MCI_STARTBITERR) {
data->error = -ECOMM;
- } else if (status & MCI_TXUNDERRUN) {
+ } else if (status_err & MCI_TXUNDERRUN) {
data->error = -EIO;
- } else if (status & MCI_RXOVERRUN) {
+ } else if (status_err & MCI_RXOVERRUN) {
if (success > host->variant->fifosize)
success -= host->variant->fifosize;
else
@@ -947,8 +1182,8 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
dev_err(mmc_dev(host->mmc), "stray MCI_DATABLOCKEND interrupt\n");
if (status & MCI_DATAEND || data->error) {
- if (dma_inprogress(host))
- mmci_dma_finalize(host, data);
+ mmci_dma_finalize(host, data);
+
mmci_stop_data(host);
if (!data->error)
@@ -1055,16 +1290,15 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
if ((!sbc && !cmd->data) || cmd->error) {
if (host->data) {
/* Terminate the DMA transfer */
- if (dma_inprogress(host)) {
- mmci_dma_data_error(host);
- mmci_dma_unmap(host, host->data);
- }
+ mmci_dma_error(host);
+
mmci_stop_data(host);
}
mmci_request_end(host, host->mrq);
} else if (sbc) {
mmci_start_command(host, host->mrq->cmd, 0);
- } else if (!(cmd->data->flags & MMC_DATA_READ)) {
+ } else if (!host->variant->datactrl_first &&
+ !(cmd->data->flags & MMC_DATA_READ)) {
mmci_start_data(host, cmd->data);
}
}
@@ -1264,7 +1498,7 @@ static irqreturn_t mmci_irq(int irq, void *dev_id)
if (status & host->mask1_reg)
mmci_pio_irq(irq, dev_id);
- status &= ~MCI_IRQ1MASK;
+ status &= ~host->variant->irq_pio_mask;
}
/*
@@ -1328,7 +1562,8 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
if (mrq->data)
mmci_get_next_data(host, mrq->data);
- if (mrq->data && mrq->data->flags & MMC_DATA_READ)
+ if (mrq->data &&
+ (host->variant->datactrl_first || mrq->data->flags & MMC_DATA_READ))
mmci_start_data(host, mrq->data);
if (mrq->sbc)
@@ -1438,8 +1673,16 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
spin_lock_irqsave(&host->lock, flags);
- mmci_set_clkreg(host, ios->clock);
- mmci_write_pwrreg(host, pwr);
+ if (host->ops && host->ops->set_clkreg)
+ host->ops->set_clkreg(host, ios->clock);
+ else
+ mmci_set_clkreg(host, ios->clock);
+
+ if (host->ops && host->ops->set_pwrreg)
+ host->ops->set_pwrreg(host, pwr);
+ else
+ mmci_write_pwrreg(host, pwr);
+
mmci_reg_delay(host);
spin_unlock_irqrestore(&host->lock, flags);
@@ -1518,6 +1761,12 @@ static int mmci_of_parse(struct device_node *np, struct mmc_host *mmc)
host->pwr_reg_add |= MCI_ST_CMDDIREN;
if (of_get_property(np, "st,sig-pin-fbclk", NULL))
host->pwr_reg_add |= MCI_ST_FBCLKEN;
+ if (of_get_property(np, "st,sig-dir", NULL))
+ host->pwr_reg_add |= MCI_STM32_DIRPOL;
+ if (of_get_property(np, "st,neg-edge", NULL))
+ host->clk_reg_add |= MCI_STM32_CLK_NEGEDGE;
+ if (of_get_property(np, "st,use-ckin", NULL))
+ host->clk_reg_add |= MCI_STM32_CLK_SELCKIN;
if (of_get_property(np, "mmc-cap-mmc-highspeed", NULL))
mmc->caps |= MMC_CAP_MMC_HIGHSPEED;
@@ -1644,6 +1893,8 @@ static int mmci_probe(struct amba_device *dev,
*/
if (variant->st_clkdiv)
mmc->f_min = DIV_ROUND_UP(host->mclk, 257);
+ else if (variant->stm32_clkdiv)
+ mmc->f_min = DIV_ROUND_UP(host->mclk, 2046);
else if (variant->explicit_mclk_control)
mmc->f_min = clk_round_rate(host->clk, 100000);
else
@@ -1665,6 +1916,12 @@ static int mmci_probe(struct amba_device *dev,
dev_dbg(mmc_dev(mmc), "clocking block at %u Hz\n", mmc->f_max);
+ host->rst = devm_reset_control_get_optional_exclusive(&dev->dev, NULL);
+ if (IS_ERR(host->rst)) {
+ ret = PTR_ERR(host->rst);
+ goto clk_disable;
+ }
+
/* Get regulators and the supported OCR mask */
ret = mmc_regulator_get_supply(mmc);
if (ret)
@@ -1675,13 +1932,6 @@ static int mmci_probe(struct amba_device *dev,
else if (plat->ocr_mask)
dev_warn(mmc_dev(mmc), "Platform OCR mask is ignored\n");
- /* DT takes precedence over platform data. */
- if (!np) {
- if (!plat->cd_invert)
- mmc->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH;
- mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
- }
-
/* We support these capabilities. */
mmc->caps |= MMC_CAP_CMD23;
@@ -1727,13 +1977,13 @@ static int mmci_probe(struct amba_device *dev,
/*
* Block size can be up to 2048 bytes, but must be a power of two.
*/
- mmc->max_blk_size = 1 << 11;
+ mmc->max_blk_size = 1 << variant->datactrl_blocksz;
/*
* Limit the number of blocks transferred so that we don't overflow
* the maximum request size.
*/
- mmc->max_blk_count = mmc->max_req_size >> 11;
+ mmc->max_blk_count = mmc->max_req_size >> variant->datactrl_blocksz;
spin_lock_init(&host->lock);
@@ -1749,30 +1999,16 @@ static int mmci_probe(struct amba_device *dev,
* - not using DT but using a descriptor table, or
* - using a table of descriptors ALONGSIDE DT, or
* look up these descriptors named "cd" and "wp" right here, fail
- * silently of these do not exist and proceed to try platform data
+ * silently of these do not exist
*/
if (!np) {
ret = mmc_gpiod_request_cd(mmc, "cd", 0, false, 0, NULL);
- if (ret < 0) {
- if (ret == -EPROBE_DEFER)
- goto clk_disable;
- else if (gpio_is_valid(plat->gpio_cd)) {
- ret = mmc_gpio_request_cd(mmc, plat->gpio_cd, 0);
- if (ret)
- goto clk_disable;
- }
- }
+ if (ret == -EPROBE_DEFER)
+ goto clk_disable;
ret = mmc_gpiod_request_ro(mmc, "wp", 0, false, 0, NULL);
- if (ret < 0) {
- if (ret == -EPROBE_DEFER)
- goto clk_disable;
- else if (gpio_is_valid(plat->gpio_wp)) {
- ret = mmc_gpio_request_ro(mmc, plat->gpio_wp);
- if (ret)
- goto clk_disable;
- }
- }
+ if (ret == -EPROBE_DEFER)
+ goto clk_disable;
}
ret = devm_request_irq(&dev->dev, dev->irq[0], mmci_irq, IRQF_SHARED,
@@ -1789,7 +2025,7 @@ static int mmci_probe(struct amba_device *dev,
goto clk_disable;
}
- writel(MCI_IRQENABLE, host->base + MMCIMASK0);
+ writel(MCI_IRQENABLE | variant->start_err, host->base + MMCIMASK0);
amba_set_drvdata(dev, mmc);
@@ -1876,7 +2112,8 @@ static void mmci_restore(struct mmci_host *host)
writel(host->datactrl_reg, host->base + MMCIDATACTRL);
writel(host->pwr_reg, host->base + MMCIPOWER);
}
- writel(MCI_IRQENABLE, host->base + MMCIMASK0);
+ writel(MCI_IRQENABLE | host->variant->start_err,
+ host->base + MMCIMASK0);
mmci_reg_delay(host);
spin_unlock_irqrestore(&host->lock, flags);
@@ -1971,6 +2208,11 @@ static const struct amba_id mmci_ids[] = {
.mask = 0x00ffffff,
.data = &variant_stm32,
},
+ {
+ .id = 0x10153180,
+ .mask = 0xf0ffffff,
+ .data = &variant_stm32_sdmmc,
+ },
/* Qualcomm variants */
{
.id = 0x00051180,
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index 517591d219e9..550dd3914461 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -23,6 +23,14 @@
#define MCI_ST_DATA31DIREN (1 << 5)
#define MCI_ST_FBCLKEN (1 << 7)
#define MCI_ST_DATA74DIREN (1 << 8)
+/*
+ * The STM32 sdmmc does not have PWR_UP/OD/ROD
+ * and uses the power register for
+ */
+#define MCI_STM32_PWR_CYC 0x02
+#define MCI_STM32_VSWITCH BIT(2)
+#define MCI_STM32_VSWITCHEN BIT(3)
+#define MCI_STM32_DIRPOL BIT(4)
#define MMCICLOCK 0x004
#define MCI_CLK_ENABLE (1 << 8)
@@ -50,6 +58,19 @@
#define MCI_QCOM_CLK_SELECT_IN_FBCLK BIT(15)
#define MCI_QCOM_CLK_SELECT_IN_DDR_MODE (BIT(14) | BIT(15))
+/* Modified on STM32 sdmmc */
+#define MCI_STM32_CLK_CLKDIV_MSK GENMASK(9, 0)
+#define MCI_STM32_CLK_WIDEBUS_4 BIT(14)
+#define MCI_STM32_CLK_WIDEBUS_8 BIT(15)
+#define MCI_STM32_CLK_NEGEDGE BIT(16)
+#define MCI_STM32_CLK_HWFCEN BIT(17)
+#define MCI_STM32_CLK_DDR BIT(18)
+#define MCI_STM32_CLK_BUSSPEED BIT(19)
+#define MCI_STM32_CLK_SEL_MSK GENMASK(21, 20)
+#define MCI_STM32_CLK_SELCK (0 << 20)
+#define MCI_STM32_CLK_SELCKIN (1 << 20)
+#define MCI_STM32_CLK_SELFBCK (2 << 20)
+
#define MMCIARGUMENT 0x008
/* The command register controls the Command Path State Machine (CPSM) */
@@ -72,6 +93,15 @@
#define MCI_CPSM_QCOM_CCSDISABLE BIT(15)
#define MCI_CPSM_QCOM_AUTO_CMD19 BIT(16)
#define MCI_CPSM_QCOM_AUTO_CMD21 BIT(21)
+/* Command register in STM32 sdmmc versions */
+#define MCI_CPSM_STM32_CMDTRANS BIT(6)
+#define MCI_CPSM_STM32_CMDSTOP BIT(7)
+#define MCI_CPSM_STM32_WAITRESP_MASK GENMASK(9, 8)
+#define MCI_CPSM_STM32_NORSP (0 << 8)
+#define MCI_CPSM_STM32_SRSP_CRC (1 << 8)
+#define MCI_CPSM_STM32_SRSP (2 << 8)
+#define MCI_CPSM_STM32_LRSP_CRC (3 << 8)
+#define MCI_CPSM_STM32_ENABLE BIT(12)
#define MMCIRESPCMD 0x010
#define MMCIRESPONSE0 0x014
@@ -130,6 +160,8 @@
#define MCI_ST_SDIOIT (1 << 22)
#define MCI_ST_CEATAEND (1 << 23)
#define MCI_ST_CARDBUSY (1 << 24)
+/* Extended status bits for the STM32 variants */
+#define MCI_STM32_BUSYD0 BIT(20)
#define MMCICLEAR 0x038
#define MCI_CMDCRCFAILCLR (1 << 0)
@@ -175,21 +207,45 @@
#define MCI_ST_SDIOITMASK (1 << 22)
#define MCI_ST_CEATAENDMASK (1 << 23)
#define MCI_ST_BUSYENDMASK (1 << 24)
+/* Extended status bits for the STM32 variants */
+#define MCI_STM32_BUSYD0ENDMASK BIT(21)
#define MMCIMASK1 0x040
#define MMCIFIFOCNT 0x048
#define MMCIFIFO 0x080 /* to 0x0bc */
+/* STM32 sdmmc registers for IDMA (Internal DMA) */
+#define MMCI_STM32_IDMACTRLR 0x050
+#define MMCI_STM32_IDMAEN BIT(0)
+#define MMCI_STM32_IDMALLIEN BIT(1)
+
+#define MMCI_STM32_IDMABSIZER 0x054
+#define MMCI_STM32_IDMABNDT_SHIFT 5
+#define MMCI_STM32_IDMABNDT_MASK GENMASK(12, 5)
+
+#define MMCI_STM32_IDMABASE0R 0x058
+
+#define MMCI_STM32_IDMALAR 0x64
+#define MMCI_STM32_IDMALA_MASK GENMASK(13, 0)
+#define MMCI_STM32_ABR BIT(29)
+#define MMCI_STM32_ULS BIT(30)
+#define MMCI_STM32_ULA BIT(31)
+
+#define MMCI_STM32_IDMABAR 0x68
+
#define MCI_IRQENABLE \
- (MCI_CMDCRCFAILMASK|MCI_DATACRCFAILMASK|MCI_CMDTIMEOUTMASK| \
- MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK| \
- MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_STARTBITERRMASK)
+ (MCI_CMDCRCFAILMASK | MCI_DATACRCFAILMASK | MCI_CMDTIMEOUTMASK | \
+ MCI_DATATIMEOUTMASK | MCI_TXUNDERRUNMASK | MCI_RXOVERRUNMASK | \
+ MCI_CMDRESPENDMASK | MCI_CMDSENTMASK)
/* These interrupts are directed to IRQ1 when two IRQ lines are available */
-#define MCI_IRQ1MASK \
+#define MCI_IRQ_PIO_MASK \
(MCI_RXFIFOHALFFULLMASK | MCI_RXDATAAVLBLMASK | \
MCI_TXFIFOHALFEMPTYMASK)
+#define MCI_IRQ_PIO_STM32_MASK \
+ (MCI_RXFIFOHALFFULLMASK | MCI_TXFIFOHALFEMPTYMASK)
+
#define NR_SG 128
#define MMCI_PINCTRL_STATE_OPENDRAIN "opendrain"
@@ -204,6 +260,10 @@ struct mmci_host;
* @clkreg_enable: enable value for MMCICLOCK register
* @clkreg_8bit_bus_enable: enable value for 8 bit bus
* @clkreg_neg_edge_enable: enable value for inverted data/cmd output
+ * @cmdreg_cpsm_enable: enable value for CPSM
+ * @cmdreg_lrsp_crc: enable value for long response with crc
+ * @cmdreg_srsp_crc: enable value for short response with crc
+ * @cmdreg_srsp: enable value for short response without crc
* @datalength_bits: number of bits in the MMCIDATALENGTH register
* @fifosize: number of bytes that can be written when MMCI_TXFIFOEMPTY
* is asserted (likewise for RX)
@@ -212,11 +272,17 @@ struct mmci_host;
* @data_cmd_enable: enable value for data commands.
* @st_sdio: enable ST specific SDIO logic
* @st_clkdiv: true if using a ST-specific clock divider algorithm
+ * @stm32_clkdiv: true if using a STM32-specific clock divider algorithm
* @datactrl_mask_ddrmode: ddr mode mask in datactrl register.
* @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register
* @blksz_datactrl4: true if Block size is at b4..b16 position in datactrl
* register
* @datactrl_mask_sdio: SDIO enable mask in datactrl register
+ * @datactrl_blksz: block size in power of two
+ * @datactrl_dpsm_enable: enable value for DPSM
+ * @datactrl_first: true if data must be setup before send command
+ * @datacnt_useless: true if you could not use datacnt register to read
+ * remaining data
* @pwrreg_powerup: power up value for MMCIPOWER register
* @f_max: maximum clk frequency supported by the controller.
* @signal_direction: input/out direction of bus signals can be indicated
@@ -233,53 +299,75 @@ struct mmci_host;
* @qcom_dml: enables qcom specific dma glue for dma transfers.
* @reversed_irq_handling: handle data irq before cmd irq.
* @mmcimask1: true if variant have a MMCIMASK1 register.
+ * @irq_pio_mask: bitmask used to manage interrupt pio transfert in mmcimask
+ * register
* @start_err: bitmask identifying the STARTBITERR bit inside MMCISTATUS
* register.
* @opendrain: bitmask identifying the OPENDRAIN bit inside MMCIPOWER register
+ * @dma_lli: true if variant has dma link list feature.
+ * @stm32_idmabsize_mask: stm32 sdmmc idma buffer size.
*/
struct variant_data {
unsigned int clkreg;
unsigned int clkreg_enable;
unsigned int clkreg_8bit_bus_enable;
unsigned int clkreg_neg_edge_enable;
+ unsigned int cmdreg_cpsm_enable;
+ unsigned int cmdreg_lrsp_crc;
+ unsigned int cmdreg_srsp_crc;
+ unsigned int cmdreg_srsp;
unsigned int datalength_bits;
unsigned int fifosize;
unsigned int fifohalfsize;
unsigned int data_cmd_enable;
unsigned int datactrl_mask_ddrmode;
unsigned int datactrl_mask_sdio;
- bool st_sdio;
- bool st_clkdiv;
- bool blksz_datactrl16;
- bool blksz_datactrl4;
+ unsigned int datactrl_blocksz;
+ unsigned int datactrl_dpsm_enable;
+ u8 datactrl_first:1;
+ u8 datacnt_useless:1;
+ u8 st_sdio:1;
+ u8 st_clkdiv:1;
+ u8 stm32_clkdiv:1;
+ u8 blksz_datactrl16:1;
+ u8 blksz_datactrl4:1;
u32 pwrreg_powerup;
u32 f_max;
- bool signal_direction;
- bool pwrreg_clkgate;
- bool busy_detect;
+ u8 signal_direction:1;
+ u8 pwrreg_clkgate:1;
+ u8 busy_detect:1;
u32 busy_dpsm_flag;
u32 busy_detect_flag;
u32 busy_detect_mask;
- bool pwrreg_nopower;
- bool explicit_mclk_control;
- bool qcom_fifo;
- bool qcom_dml;
- bool reversed_irq_handling;
- bool mmcimask1;
+ u8 pwrreg_nopower:1;
+ u8 explicit_mclk_control:1;
+ u8 qcom_fifo:1;
+ u8 qcom_dml:1;
+ u8 reversed_irq_handling:1;
+ u8 mmcimask1:1;
+ unsigned int irq_pio_mask;
u32 start_err;
u32 opendrain;
+ u8 dma_lli:1;
+ u32 stm32_idmabsize_mask;
void (*init)(struct mmci_host *host);
};
/* mmci variant callbacks */
struct mmci_host_ops {
- void (*dma_setup)(struct mmci_host *host);
-};
-
-struct mmci_host_next {
- struct dma_async_tx_descriptor *dma_desc;
- struct dma_chan *dma_chan;
- s32 cookie;
+ int (*validate_data)(struct mmci_host *host, struct mmc_data *data);
+ int (*prep_data)(struct mmci_host *host, struct mmc_data *data,
+ bool next);
+ void (*unprep_data)(struct mmci_host *host, struct mmc_data *data,
+ int err);
+ void (*get_next_data)(struct mmci_host *host, struct mmc_data *data);
+ int (*dma_setup)(struct mmci_host *host);
+ void (*dma_release)(struct mmci_host *host);
+ int (*dma_start)(struct mmci_host *host, unsigned int *datactrl);
+ void (*dma_finalize)(struct mmci_host *host, struct mmc_data *data);
+ void (*dma_error)(struct mmci_host *host);
+ void (*set_clkreg)(struct mmci_host *host, unsigned int desired);
+ void (*set_pwrreg)(struct mmci_host *host, unsigned int pwr);
};
struct mmci_host {
@@ -290,7 +378,9 @@ struct mmci_host {
struct mmc_data *data;
struct mmc_host *mmc;
struct clk *clk;
- bool singleirq;
+ u8 singleirq:1;
+
+ struct reset_control *rst;
spinlock_t lock;
@@ -301,10 +391,11 @@ struct mmci_host {
u32 pwr_reg;
u32 pwr_reg_add;
u32 clk_reg;
+ u32 clk_reg_add;
u32 datactrl_reg;
u32 busy_status;
u32 mask1_reg;
- bool vqmmc_enabled;
+ u8 vqmmc_enabled:1;
struct mmci_platform_data *plat;
struct mmci_host_ops *ops;
struct variant_data *variant;
@@ -323,18 +414,25 @@ struct mmci_host {
unsigned int size;
int (*get_rx_fifocnt)(struct mmci_host *h, u32 status, int remain);
-#ifdef CONFIG_DMA_ENGINE
- /* DMA stuff */
- struct dma_chan *dma_current;
- struct dma_chan *dma_rx_channel;
- struct dma_chan *dma_tx_channel;
- struct dma_async_tx_descriptor *dma_desc_current;
- struct mmci_host_next next_data;
- bool dma_in_progress;
+ u8 use_dma:1;
+ u8 dma_in_progress:1;
+ void *dma_priv;
-#define dma_inprogress(host) ((host)->dma_in_progress)
-#else
-#define dma_inprogress(host) (0)
-#endif
+ s32 next_cookie;
};
+#define dma_inprogress(host) ((host)->dma_in_progress)
+
+void mmci_write_clkreg(struct mmci_host *host, u32 clk);
+void mmci_write_pwrreg(struct mmci_host *host, u32 pwr);
+
+int mmci_dmae_prep_data(struct mmci_host *host, struct mmc_data *data,
+ bool next);
+void mmci_dmae_unprep_data(struct mmci_host *host, struct mmc_data *data,
+ int err);
+void mmci_dmae_get_next_data(struct mmci_host *host, struct mmc_data *data);
+int mmci_dmae_setup(struct mmci_host *host);
+void mmci_dmae_release(struct mmci_host *host);
+int mmci_dmae_start(struct mmci_host *host, unsigned int *datactrl);
+void mmci_dmae_finalize(struct mmci_host *host, struct mmc_data *data);
+void mmci_dmae_error(struct mmci_host *host);
diff --git a/drivers/mmc/host/mmci_qcom_dml.c b/drivers/mmc/host/mmci_qcom_dml.c
index be3fab5db83f..25d0a75533ea 100644
--- a/drivers/mmc/host/mmci_qcom_dml.c
+++ b/drivers/mmc/host/mmci_qcom_dml.c
@@ -119,19 +119,23 @@ static int of_get_dml_pipe_index(struct device_node *np, const char *name)
}
/* Initialize the dml hardware connected to SD Card controller */
-static void qcom_dma_setup(struct mmci_host *host)
+static int qcom_dma_setup(struct mmci_host *host)
{
u32 config;
void __iomem *base;
int consumer_id, producer_id;
struct device_node *np = host->mmc->parent->of_node;
+ if (mmci_dmae_setup(host))
+ return -EINVAL;
+
consumer_id = of_get_dml_pipe_index(np, "tx");
producer_id = of_get_dml_pipe_index(np, "rx");
if (producer_id < 0 || consumer_id < 0) {
host->variant->qcom_dml = false;
- return;
+ mmci_dmae_release(host);
+ return -EINVAL;
}
base = host->base + DML_OFFSET;
@@ -175,10 +179,19 @@ static void qcom_dma_setup(struct mmci_host *host)
/* Make sure dml initialization is finished */
mb();
+
+ return 0;
}
static struct mmci_host_ops qcom_variant_ops = {
+ .prep_data = mmci_dmae_prep_data,
+ .unprep_data = mmci_dmae_unprep_data,
+ .get_next_data = mmci_dmae_get_next_data,
.dma_setup = qcom_dma_setup,
+ .dma_release = mmci_dmae_release,
+ .dma_start = mmci_dmae_start,
+ .dma_finalize = mmci_dmae_finalize,
+ .dma_error = mmci_dmae_error,
};
void qcom_variant_init(struct mmci_host *host)
diff --git a/drivers/mmc/host/mmci_stm32_sdmmc.c b/drivers/mmc/host/mmci_stm32_sdmmc.c
new file mode 100644
index 000000000000..cfbfc6f1048f
--- /dev/null
+++ b/drivers/mmc/host/mmci_stm32_sdmmc.c
@@ -0,0 +1,282 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Author: Ludovic.barre@st.com for STMicroelectronics.
+ */
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/reset.h>
+#include <linux/scatterlist.h>
+#include "mmci.h"
+
+#define SDMMC_LLI_BUF_LEN PAGE_SIZE
+#define SDMMC_IDMA_BURST BIT(MMCI_STM32_IDMABNDT_SHIFT)
+
+struct sdmmc_lli_desc {
+ u32 idmalar;
+ u32 idmabase;
+ u32 idmasize;
+};
+
+struct sdmmc_priv {
+ dma_addr_t sg_dma;
+ void *sg_cpu;
+};
+
+int sdmmc_idma_validate_data(struct mmci_host *host,
+ struct mmc_data *data)
+{
+ struct scatterlist *sg;
+ int i;
+
+ /*
+ * idma has constraints on idmabase & idmasize for each element
+ * excepted the last element which has no constraint on idmasize
+ */
+ for_each_sg(data->sg, sg, data->sg_len - 1, i) {
+ if (!IS_ALIGNED(sg_dma_address(data->sg), sizeof(u32)) ||
+ !IS_ALIGNED(sg_dma_len(data->sg), SDMMC_IDMA_BURST)) {
+ dev_err(mmc_dev(host->mmc),
+ "unaligned scatterlist: ofst:%x length:%d\n",
+ data->sg->offset, data->sg->length);
+ return -EINVAL;
+ }
+ }
+
+ if (!IS_ALIGNED(sg_dma_address(data->sg), sizeof(u32))) {
+ dev_err(mmc_dev(host->mmc),
+ "unaligned last scatterlist: ofst:%x length:%d\n",
+ data->sg->offset, data->sg->length);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int _sdmmc_idma_prep_data(struct mmci_host *host,
+ struct mmc_data *data)
+{
+ int n_elem;
+
+ n_elem = dma_map_sg(mmc_dev(host->mmc),
+ data->sg,
+ data->sg_len,
+ mmc_get_dma_dir(data));
+
+ if (!n_elem) {
+ dev_err(mmc_dev(host->mmc), "dma_map_sg failed\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int sdmmc_idma_prep_data(struct mmci_host *host,
+ struct mmc_data *data, bool next)
+{
+ /* Check if job is already prepared. */
+ if (!next && data->host_cookie == host->next_cookie)
+ return 0;
+
+ return _sdmmc_idma_prep_data(host, data);
+}
+
+static void sdmmc_idma_unprep_data(struct mmci_host *host,
+ struct mmc_data *data, int err)
+{
+ dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+ mmc_get_dma_dir(data));
+}
+
+static int sdmmc_idma_setup(struct mmci_host *host)
+{
+ struct sdmmc_priv *idma;
+
+ idma = devm_kzalloc(mmc_dev(host->mmc), sizeof(*idma), GFP_KERNEL);
+ if (!idma)
+ return -ENOMEM;
+
+ host->dma_priv = idma;
+
+ if (host->variant->dma_lli) {
+ idma->sg_cpu = dmam_alloc_coherent(mmc_dev(host->mmc),
+ SDMMC_LLI_BUF_LEN,
+ &idma->sg_dma, GFP_KERNEL);
+ if (!idma->sg_cpu) {
+ dev_err(mmc_dev(host->mmc),
+ "Failed to alloc IDMA descriptor\n");
+ return -ENOMEM;
+ }
+ host->mmc->max_segs = SDMMC_LLI_BUF_LEN /
+ sizeof(struct sdmmc_lli_desc);
+ host->mmc->max_seg_size = host->variant->stm32_idmabsize_mask;
+ } else {
+ host->mmc->max_segs = 1;
+ host->mmc->max_seg_size = host->mmc->max_req_size;
+ }
+
+ return 0;
+}
+
+static int sdmmc_idma_start(struct mmci_host *host, unsigned int *datactrl)
+
+{
+ struct sdmmc_priv *idma = host->dma_priv;
+ struct sdmmc_lli_desc *desc = (struct sdmmc_lli_desc *)idma->sg_cpu;
+ struct mmc_data *data = host->data;
+ struct scatterlist *sg;
+ int i;
+
+ if (!host->variant->dma_lli || data->sg_len == 1) {
+ writel_relaxed(sg_dma_address(data->sg),
+ host->base + MMCI_STM32_IDMABASE0R);
+ writel_relaxed(MMCI_STM32_IDMAEN,
+ host->base + MMCI_STM32_IDMACTRLR);
+ return 0;
+ }
+
+ for_each_sg(data->sg, sg, data->sg_len, i) {
+ desc[i].idmalar = (i + 1) * sizeof(struct sdmmc_lli_desc);
+ desc[i].idmalar |= MMCI_STM32_ULA | MMCI_STM32_ULS
+ | MMCI_STM32_ABR;
+ desc[i].idmabase = sg_dma_address(sg);
+ desc[i].idmasize = sg_dma_len(sg);
+ }
+
+ /* notice the end of link list */
+ desc[data->sg_len - 1].idmalar &= ~MMCI_STM32_ULA;
+
+ dma_wmb();
+ writel_relaxed(idma->sg_dma, host->base + MMCI_STM32_IDMABAR);
+ writel_relaxed(desc[0].idmalar, host->base + MMCI_STM32_IDMALAR);
+ writel_relaxed(desc[0].idmabase, host->base + MMCI_STM32_IDMABASE0R);
+ writel_relaxed(desc[0].idmasize, host->base + MMCI_STM32_IDMABSIZER);
+ writel_relaxed(MMCI_STM32_IDMAEN | MMCI_STM32_IDMALLIEN,
+ host->base + MMCI_STM32_IDMACTRLR);
+
+ return 0;
+}
+
+static void sdmmc_idma_finalize(struct mmci_host *host, struct mmc_data *data)
+{
+ writel_relaxed(0, host->base + MMCI_STM32_IDMACTRLR);
+}
+
+static void mmci_sdmmc_set_clkreg(struct mmci_host *host, unsigned int desired)
+{
+ unsigned int clk = 0, ddr = 0;
+
+ if (host->mmc->ios.timing == MMC_TIMING_MMC_DDR52 ||
+ host->mmc->ios.timing == MMC_TIMING_UHS_DDR50)
+ ddr = MCI_STM32_CLK_DDR;
+
+ /*
+ * cclk = mclk / (2 * clkdiv)
+ * clkdiv 0 => bypass
+ * in ddr mode bypass is not possible
+ */
+ if (desired) {
+ if (desired >= host->mclk && !ddr) {
+ host->cclk = host->mclk;
+ } else {
+ clk = DIV_ROUND_UP(host->mclk, 2 * desired);
+ if (clk > MCI_STM32_CLK_CLKDIV_MSK)
+ clk = MCI_STM32_CLK_CLKDIV_MSK;
+ host->cclk = host->mclk / (2 * clk);
+ }
+ } else {
+ /*
+ * while power-on phase the clock can't be define to 0,
+ * Only power-off and power-cyc deactivate the clock.
+ * if desired clock is 0, set max divider
+ */
+ clk = MCI_STM32_CLK_CLKDIV_MSK;
+ host->cclk = host->mclk / (2 * clk);
+ }
+
+ /* Set actual clock for debug */
+ if (host->mmc->ios.power_mode == MMC_POWER_ON)
+ host->mmc->actual_clock = host->cclk;
+ else
+ host->mmc->actual_clock = 0;
+
+ if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_4)
+ clk |= MCI_STM32_CLK_WIDEBUS_4;
+ if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8)
+ clk |= MCI_STM32_CLK_WIDEBUS_8;
+
+ clk |= MCI_STM32_CLK_HWFCEN;
+ clk |= host->clk_reg_add;
+ clk |= ddr;
+
+ /*
+ * SDMMC_FBCK is selected when an external Delay Block is needed
+ * with SDR104.
+ */
+ if (host->mmc->ios.timing >= MMC_TIMING_UHS_SDR50) {
+ clk |= MCI_STM32_CLK_BUSSPEED;
+ if (host->mmc->ios.timing == MMC_TIMING_UHS_SDR104) {
+ clk &= ~MCI_STM32_CLK_SEL_MSK;
+ clk |= MCI_STM32_CLK_SELFBCK;
+ }
+ }
+
+ mmci_write_clkreg(host, clk);
+}
+
+static void mmci_sdmmc_set_pwrreg(struct mmci_host *host, unsigned int pwr)
+{
+ struct mmc_ios ios = host->mmc->ios;
+
+ pwr = host->pwr_reg_add;
+
+ if (ios.power_mode == MMC_POWER_OFF) {
+ /* Only a reset could power-off sdmmc */
+ reset_control_assert(host->rst);
+ udelay(2);
+ reset_control_deassert(host->rst);
+
+ /*
+ * Set the SDMMC in Power-cycle state.
+ * This will make that the SDMMC_D[7:0], SDMMC_CMD and SDMMC_CK
+ * are driven low, to prevent the Card from being supplied
+ * through the signal lines.
+ */
+ mmci_write_pwrreg(host, MCI_STM32_PWR_CYC | pwr);
+ } else if (ios.power_mode == MMC_POWER_ON) {
+ /*
+ * After power-off (reset): the irq mask defined in probe
+ * functionis lost
+ * ault irq mask (probe) must be activated
+ */
+ writel(MCI_IRQENABLE | host->variant->start_err,
+ host->base + MMCIMASK0);
+
+ /*
+ * After a power-cycle state, we must set the SDMMC in
+ * Power-off. The SDMMC_D[7:0], SDMMC_CMD and SDMMC_CK are
+ * driven high. Then we can set the SDMMC to Power-on state
+ */
+ mmci_write_pwrreg(host, MCI_PWR_OFF | pwr);
+ mdelay(1);
+ mmci_write_pwrreg(host, MCI_PWR_ON | pwr);
+ }
+}
+
+static struct mmci_host_ops sdmmc_variant_ops = {
+ .validate_data = sdmmc_idma_validate_data,
+ .prep_data = sdmmc_idma_prep_data,
+ .unprep_data = sdmmc_idma_unprep_data,
+ .dma_setup = sdmmc_idma_setup,
+ .dma_start = sdmmc_idma_start,
+ .dma_finalize = sdmmc_idma_finalize,
+ .set_clkreg = mmci_sdmmc_set_clkreg,
+ .set_pwrreg = mmci_sdmmc_set_pwrreg,
+};
+
+void sdmmc_variant_init(struct mmci_host *host)
+{
+ host->ops = &sdmmc_variant_ops;
+}
diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
index 04841386b65d..6334cc752d8b 100644
--- a/drivers/mmc/host/mtk-sd.c
+++ b/drivers/mmc/host/mtk-sd.c
@@ -87,6 +87,13 @@
#define SDC_FIFO_CFG 0x228
/*--------------------------------------------------------------------------*/
+/* Top Pad Register Offset */
+/*--------------------------------------------------------------------------*/
+#define EMMC_TOP_CONTROL 0x00
+#define EMMC_TOP_CMD 0x04
+#define EMMC50_PAD_DS_TUNE 0x0c
+
+/*--------------------------------------------------------------------------*/
/* Register Mask */
/*--------------------------------------------------------------------------*/
@@ -261,6 +268,23 @@
#define SDC_FIFO_CFG_WRVALIDSEL (0x1 << 24) /* RW */
#define SDC_FIFO_CFG_RDVALIDSEL (0x1 << 25) /* RW */
+/* EMMC_TOP_CONTROL mask */
+#define PAD_RXDLY_SEL (0x1 << 0) /* RW */
+#define DELAY_EN (0x1 << 1) /* RW */
+#define PAD_DAT_RD_RXDLY2 (0x1f << 2) /* RW */
+#define PAD_DAT_RD_RXDLY (0x1f << 7) /* RW */
+#define PAD_DAT_RD_RXDLY2_SEL (0x1 << 12) /* RW */
+#define PAD_DAT_RD_RXDLY_SEL (0x1 << 13) /* RW */
+#define DATA_K_VALUE_SEL (0x1 << 14) /* RW */
+#define SDC_RX_ENH_EN (0x1 << 15) /* TW */
+
+/* EMMC_TOP_CMD mask */
+#define PAD_CMD_RXDLY2 (0x1f << 0) /* RW */
+#define PAD_CMD_RXDLY (0x1f << 5) /* RW */
+#define PAD_CMD_RD_RXDLY2_SEL (0x1 << 10) /* RW */
+#define PAD_CMD_RD_RXDLY_SEL (0x1 << 11) /* RW */
+#define PAD_CMD_TX_DLY (0x1f << 12) /* RW */
+
#define REQ_CMD_EIO (0x1 << 0)
#define REQ_CMD_TMO (0x1 << 1)
#define REQ_DAT_ERR (0x1 << 2)
@@ -333,6 +357,9 @@ struct msdc_save_para {
u32 emmc50_cfg0;
u32 emmc50_cfg3;
u32 sdc_fifo_cfg;
+ u32 emmc_top_control;
+ u32 emmc_top_cmd;
+ u32 emmc50_pad_ds_tune;
};
struct mtk_mmc_compatible {
@@ -351,6 +378,8 @@ struct msdc_tune_para {
u32 iocon;
u32 pad_tune;
u32 pad_cmd_tune;
+ u32 emmc_top_control;
+ u32 emmc_top_cmd;
};
struct msdc_delay_phase {
@@ -372,6 +401,7 @@ struct msdc_host {
int error;
void __iomem *base; /* host base address */
+ void __iomem *top_base; /* host top register base address */
struct msdc_dma dma; /* dma channel */
u64 dma_mask;
@@ -387,10 +417,10 @@ struct msdc_host {
struct clk *src_clk; /* msdc source clock */
struct clk *h_clk; /* msdc h_clk */
+ struct clk *bus_clk; /* bus clock which used to access register */
struct clk *src_clk_cg; /* msdc source clock control gate */
u32 mclk; /* mmc subsystem clock frequency */
u32 src_clk_freq; /* source clock frequency */
- u32 sclk; /* SD/MS bus clock frequency */
unsigned char timing;
bool vqmmc_enabled;
u32 latch_ck;
@@ -429,6 +459,18 @@ static const struct mtk_mmc_compatible mt8173_compat = {
.support_64g = false,
};
+static const struct mtk_mmc_compatible mt8183_compat = {
+ .clk_div_bits = 12,
+ .hs400_tune = false,
+ .pad_tune_reg = MSDC_PAD_TUNE0,
+ .async_fifo = true,
+ .data_tune = true,
+ .busy_check = true,
+ .stop_clk_fix = true,
+ .enhance_rx = true,
+ .support_64g = true,
+};
+
static const struct mtk_mmc_compatible mt2701_compat = {
.clk_div_bits = 12,
.hs400_tune = false,
@@ -468,6 +510,7 @@ static const struct mtk_mmc_compatible mt7622_compat = {
static const struct of_device_id msdc_of_ids[] = {
{ .compatible = "mediatek,mt8135-mmc", .data = &mt8135_compat},
{ .compatible = "mediatek,mt8173-mmc", .data = &mt8173_compat},
+ { .compatible = "mediatek,mt8183-mmc", .data = &mt8183_compat},
{ .compatible = "mediatek,mt2701-mmc", .data = &mt2701_compat},
{ .compatible = "mediatek,mt2712-mmc", .data = &mt2712_compat},
{ .compatible = "mediatek,mt7622-mmc", .data = &mt7622_compat},
@@ -635,10 +678,10 @@ static void msdc_set_timeout(struct msdc_host *host, u32 ns, u32 clks)
host->timeout_ns = ns;
host->timeout_clks = clks;
- if (host->sclk == 0) {
+ if (host->mmc->actual_clock == 0) {
timeout = 0;
} else {
- clk_ns = 1000000000UL / host->sclk;
+ clk_ns = 1000000000UL / host->mmc->actual_clock;
timeout = (ns + clk_ns - 1) / clk_ns + clks;
/* in 1048576 sclk cycle unit */
timeout = (timeout + (0x1 << 20) - 1) >> 20;
@@ -660,12 +703,14 @@ static void msdc_gate_clock(struct msdc_host *host)
{
clk_disable_unprepare(host->src_clk_cg);
clk_disable_unprepare(host->src_clk);
+ clk_disable_unprepare(host->bus_clk);
clk_disable_unprepare(host->h_clk);
}
static void msdc_ungate_clock(struct msdc_host *host)
{
clk_prepare_enable(host->h_clk);
+ clk_prepare_enable(host->bus_clk);
clk_prepare_enable(host->src_clk);
clk_prepare_enable(host->src_clk_cg);
while (!(readl(host->base + MSDC_CFG) & MSDC_CFG_CKSTB))
@@ -683,6 +728,7 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
if (!hz) {
dev_dbg(host->dev, "set mclk to 0\n");
host->mclk = 0;
+ host->mmc->actual_clock = 0;
sdr_clr_bits(host->base + MSDC_CFG, MSDC_CFG_CKPDN);
return;
}
@@ -761,7 +807,7 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
while (!(readl(host->base + MSDC_CFG) & MSDC_CFG_CKSTB))
cpu_relax();
sdr_set_bits(host->base + MSDC_CFG, MSDC_CFG_CKPDN);
- host->sclk = sclk;
+ host->mmc->actual_clock = sclk;
host->mclk = hz;
host->timing = timing;
/* need because clk changed. */
@@ -772,14 +818,30 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
* mmc_select_hs400() will drop to 50Mhz and High speed mode,
* tune result of hs200/200Mhz is not suitable for 50Mhz
*/
- if (host->sclk <= 52000000) {
+ if (host->mmc->actual_clock <= 52000000) {
writel(host->def_tune_para.iocon, host->base + MSDC_IOCON);
- writel(host->def_tune_para.pad_tune, host->base + tune_reg);
+ if (host->top_base) {
+ writel(host->def_tune_para.emmc_top_control,
+ host->top_base + EMMC_TOP_CONTROL);
+ writel(host->def_tune_para.emmc_top_cmd,
+ host->top_base + EMMC_TOP_CMD);
+ } else {
+ writel(host->def_tune_para.pad_tune,
+ host->base + tune_reg);
+ }
} else {
writel(host->saved_tune_para.iocon, host->base + MSDC_IOCON);
- writel(host->saved_tune_para.pad_tune, host->base + tune_reg);
writel(host->saved_tune_para.pad_cmd_tune,
host->base + PAD_CMD_TUNE);
+ if (host->top_base) {
+ writel(host->saved_tune_para.emmc_top_control,
+ host->top_base + EMMC_TOP_CONTROL);
+ writel(host->saved_tune_para.emmc_top_cmd,
+ host->top_base + EMMC_TOP_CMD);
+ } else {
+ writel(host->saved_tune_para.pad_tune,
+ host->base + tune_reg);
+ }
}
if (timing == MMC_TIMING_MMC_HS400 &&
@@ -787,7 +849,8 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
sdr_set_field(host->base + PAD_CMD_TUNE,
MSDC_PAD_TUNE_CMDRRDLY,
host->hs400_cmd_int_delay);
- dev_dbg(host->dev, "sclk: %d, timing: %d\n", host->sclk, timing);
+ dev_dbg(host->dev, "sclk: %d, timing: %d\n", host->mmc->actual_clock,
+ timing);
}
static inline u32 msdc_cmd_find_resp(struct msdc_host *host,
@@ -1055,6 +1118,7 @@ static void msdc_start_command(struct msdc_host *host,
WARN_ON(host->cmd);
host->cmd = cmd;
+ mod_delayed_work(system_wq, &host->req_timeout, DAT_TIMEOUT);
if (!msdc_cmd_is_ready(host, mrq, cmd))
return;
@@ -1066,7 +1130,6 @@ static void msdc_start_command(struct msdc_host *host,
cmd->error = 0;
rawcmd = msdc_cmd_prepare_raw_cmd(host, mrq, cmd);
- mod_delayed_work(system_wq, &host->req_timeout, DAT_TIMEOUT);
sdr_set_bits(host->base + MSDC_INTEN, cmd_ints_mask);
writel(cmd->arg, host->base + SDC_ARG);
@@ -1351,7 +1414,12 @@ static void msdc_init_hw(struct msdc_host *host)
val = readl(host->base + MSDC_INT);
writel(val, host->base + MSDC_INT);
- writel(0, host->base + tune_reg);
+ if (host->top_base) {
+ writel(0, host->top_base + EMMC_TOP_CONTROL);
+ writel(0, host->top_base + EMMC_TOP_CMD);
+ } else {
+ writel(0, host->base + tune_reg);
+ }
writel(0, host->base + MSDC_IOCON);
sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_DDLSEL, 0);
writel(0x403c0046, host->base + MSDC_PATCH_BIT);
@@ -1375,8 +1443,12 @@ static void msdc_init_hw(struct msdc_host *host)
sdr_set_field(host->base + MSDC_PATCH_BIT2,
MSDC_PB2_RESPWAIT, 3);
if (host->dev_comp->enhance_rx) {
- sdr_set_bits(host->base + SDC_ADV_CFG0,
- SDC_RX_ENHANCE_EN);
+ if (host->top_base)
+ sdr_set_bits(host->top_base + EMMC_TOP_CONTROL,
+ SDC_RX_ENH_EN);
+ else
+ sdr_set_bits(host->base + SDC_ADV_CFG0,
+ SDC_RX_ENHANCE_EN);
} else {
sdr_set_field(host->base + MSDC_PATCH_BIT2,
MSDC_PB2_RESPSTSENSEL, 2);
@@ -1394,11 +1466,26 @@ static void msdc_init_hw(struct msdc_host *host)
sdr_set_bits(host->base + MSDC_PATCH_BIT2,
MSDC_PB2_SUPPORT_64G);
if (host->dev_comp->data_tune) {
- sdr_set_bits(host->base + tune_reg,
- MSDC_PAD_TUNE_RD_SEL | MSDC_PAD_TUNE_CMD_SEL);
+ if (host->top_base) {
+ sdr_set_bits(host->top_base + EMMC_TOP_CONTROL,
+ PAD_DAT_RD_RXDLY_SEL);
+ sdr_clr_bits(host->top_base + EMMC_TOP_CONTROL,
+ DATA_K_VALUE_SEL);
+ sdr_set_bits(host->top_base + EMMC_TOP_CMD,
+ PAD_CMD_RD_RXDLY_SEL);
+ } else {
+ sdr_set_bits(host->base + tune_reg,
+ MSDC_PAD_TUNE_RD_SEL |
+ MSDC_PAD_TUNE_CMD_SEL);
+ }
} else {
/* choose clock tune */
- sdr_set_bits(host->base + tune_reg, MSDC_PAD_TUNE_RXDLYSEL);
+ if (host->top_base)
+ sdr_set_bits(host->top_base + EMMC_TOP_CONTROL,
+ PAD_RXDLY_SEL);
+ else
+ sdr_set_bits(host->base + tune_reg,
+ MSDC_PAD_TUNE_RXDLYSEL);
}
/* Configure to enable SDIO mode.
@@ -1413,9 +1500,20 @@ static void msdc_init_hw(struct msdc_host *host)
sdr_set_field(host->base + SDC_CFG, SDC_CFG_DTOC, 3);
host->def_tune_para.iocon = readl(host->base + MSDC_IOCON);
- host->def_tune_para.pad_tune = readl(host->base + tune_reg);
host->saved_tune_para.iocon = readl(host->base + MSDC_IOCON);
- host->saved_tune_para.pad_tune = readl(host->base + tune_reg);
+ if (host->top_base) {
+ host->def_tune_para.emmc_top_control =
+ readl(host->top_base + EMMC_TOP_CONTROL);
+ host->def_tune_para.emmc_top_cmd =
+ readl(host->top_base + EMMC_TOP_CMD);
+ host->saved_tune_para.emmc_top_control =
+ readl(host->top_base + EMMC_TOP_CONTROL);
+ host->saved_tune_para.emmc_top_cmd =
+ readl(host->top_base + EMMC_TOP_CMD);
+ } else {
+ host->def_tune_para.pad_tune = readl(host->base + tune_reg);
+ host->saved_tune_para.pad_tune = readl(host->base + tune_reg);
+ }
dev_dbg(host->dev, "init hardware done!");
}
@@ -1563,6 +1661,30 @@ static struct msdc_delay_phase get_best_delay(struct msdc_host *host, u32 delay)
return delay_phase;
}
+static inline void msdc_set_cmd_delay(struct msdc_host *host, u32 value)
+{
+ u32 tune_reg = host->dev_comp->pad_tune_reg;
+
+ if (host->top_base)
+ sdr_set_field(host->top_base + EMMC_TOP_CMD, PAD_CMD_RXDLY,
+ value);
+ else
+ sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_CMDRDLY,
+ value);
+}
+
+static inline void msdc_set_data_delay(struct msdc_host *host, u32 value)
+{
+ u32 tune_reg = host->dev_comp->pad_tune_reg;
+
+ if (host->top_base)
+ sdr_set_field(host->top_base + EMMC_TOP_CONTROL,
+ PAD_DAT_RD_RXDLY, value);
+ else
+ sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_DATRRDLY,
+ value);
+}
+
static int msdc_tune_response(struct mmc_host *mmc, u32 opcode)
{
struct msdc_host *host = mmc_priv(mmc);
@@ -1583,8 +1705,7 @@ static int msdc_tune_response(struct mmc_host *mmc, u32 opcode)
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
for (i = 0 ; i < PAD_DELAY_MAX; i++) {
- sdr_set_field(host->base + tune_reg,
- MSDC_PAD_TUNE_CMDRDLY, i);
+ msdc_set_cmd_delay(host, i);
/*
* Using the same parameters, it may sometimes pass the test,
* but sometimes it may fail. To make sure the parameters are
@@ -1608,8 +1729,7 @@ static int msdc_tune_response(struct mmc_host *mmc, u32 opcode)
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
for (i = 0; i < PAD_DELAY_MAX; i++) {
- sdr_set_field(host->base + tune_reg,
- MSDC_PAD_TUNE_CMDRDLY, i);
+ msdc_set_cmd_delay(host, i);
/*
* Using the same parameters, it may sometimes pass the test,
* but sometimes it may fail. To make sure the parameters are
@@ -1633,15 +1753,13 @@ skip_fall:
final_maxlen = final_fall_delay.maxlen;
if (final_maxlen == final_rise_delay.maxlen) {
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
- sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_CMDRDLY,
- final_rise_delay.final_phase);
final_delay = final_rise_delay.final_phase;
} else {
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
- sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_CMDRDLY,
- final_fall_delay.final_phase);
final_delay = final_fall_delay.final_phase;
}
+ msdc_set_cmd_delay(host, final_delay);
+
if (host->dev_comp->async_fifo || host->hs200_cmd_int_delay)
goto skip_internal;
@@ -1716,7 +1834,6 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode)
u32 rise_delay = 0, fall_delay = 0;
struct msdc_delay_phase final_rise_delay, final_fall_delay = { 0,};
u8 final_delay, final_maxlen;
- u32 tune_reg = host->dev_comp->pad_tune_reg;
int i, ret;
sdr_set_field(host->base + MSDC_PATCH_BIT, MSDC_INT_DAT_LATCH_CK_SEL,
@@ -1724,8 +1841,7 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode)
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
for (i = 0 ; i < PAD_DELAY_MAX; i++) {
- sdr_set_field(host->base + tune_reg,
- MSDC_PAD_TUNE_DATRRDLY, i);
+ msdc_set_data_delay(host, i);
ret = mmc_send_tuning(mmc, opcode, NULL);
if (!ret)
rise_delay |= (1 << i);
@@ -1739,8 +1855,7 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode)
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
for (i = 0; i < PAD_DELAY_MAX; i++) {
- sdr_set_field(host->base + tune_reg,
- MSDC_PAD_TUNE_DATRRDLY, i);
+ msdc_set_data_delay(host, i);
ret = mmc_send_tuning(mmc, opcode, NULL);
if (!ret)
fall_delay |= (1 << i);
@@ -1752,29 +1867,97 @@ skip_fall:
if (final_maxlen == final_rise_delay.maxlen) {
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
- sdr_set_field(host->base + tune_reg,
- MSDC_PAD_TUNE_DATRRDLY,
- final_rise_delay.final_phase);
final_delay = final_rise_delay.final_phase;
} else {
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
- sdr_set_field(host->base + tune_reg,
- MSDC_PAD_TUNE_DATRRDLY,
- final_fall_delay.final_phase);
final_delay = final_fall_delay.final_phase;
}
+ msdc_set_data_delay(host, final_delay);
dev_dbg(host->dev, "Final data pad delay: %x\n", final_delay);
return final_delay == 0xff ? -EIO : 0;
}
+/*
+ * MSDC IP which supports data tune + async fifo can do CMD/DAT tune
+ * together, which can save the tuning time.
+ */
+static int msdc_tune_together(struct mmc_host *mmc, u32 opcode)
+{
+ struct msdc_host *host = mmc_priv(mmc);
+ u32 rise_delay = 0, fall_delay = 0;
+ struct msdc_delay_phase final_rise_delay, final_fall_delay = { 0,};
+ u8 final_delay, final_maxlen;
+ int i, ret;
+
+ sdr_set_field(host->base + MSDC_PATCH_BIT, MSDC_INT_DAT_LATCH_CK_SEL,
+ host->latch_ck);
+
+ sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
+ sdr_clr_bits(host->base + MSDC_IOCON,
+ MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL);
+ for (i = 0 ; i < PAD_DELAY_MAX; i++) {
+ msdc_set_cmd_delay(host, i);
+ msdc_set_data_delay(host, i);
+ ret = mmc_send_tuning(mmc, opcode, NULL);
+ if (!ret)
+ rise_delay |= (1 << i);
+ }
+ final_rise_delay = get_best_delay(host, rise_delay);
+ /* if rising edge has enough margin, then do not scan falling edge */
+ if (final_rise_delay.maxlen >= 12 ||
+ (final_rise_delay.start == 0 && final_rise_delay.maxlen >= 4))
+ goto skip_fall;
+
+ sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
+ sdr_set_bits(host->base + MSDC_IOCON,
+ MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL);
+ for (i = 0; i < PAD_DELAY_MAX; i++) {
+ msdc_set_cmd_delay(host, i);
+ msdc_set_data_delay(host, i);
+ ret = mmc_send_tuning(mmc, opcode, NULL);
+ if (!ret)
+ fall_delay |= (1 << i);
+ }
+ final_fall_delay = get_best_delay(host, fall_delay);
+
+skip_fall:
+ final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen);
+ if (final_maxlen == final_rise_delay.maxlen) {
+ sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
+ sdr_clr_bits(host->base + MSDC_IOCON,
+ MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL);
+ final_delay = final_rise_delay.final_phase;
+ } else {
+ sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
+ sdr_set_bits(host->base + MSDC_IOCON,
+ MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL);
+ final_delay = final_fall_delay.final_phase;
+ }
+
+ msdc_set_cmd_delay(host, final_delay);
+ msdc_set_data_delay(host, final_delay);
+
+ dev_dbg(host->dev, "Final pad delay: %x\n", final_delay);
+ return final_delay == 0xff ? -EIO : 0;
+}
+
static int msdc_execute_tuning(struct mmc_host *mmc, u32 opcode)
{
struct msdc_host *host = mmc_priv(mmc);
int ret;
u32 tune_reg = host->dev_comp->pad_tune_reg;
+ if (host->dev_comp->data_tune && host->dev_comp->async_fifo) {
+ ret = msdc_tune_together(mmc, opcode);
+ if (host->hs400_mode) {
+ sdr_clr_bits(host->base + MSDC_IOCON,
+ MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL);
+ msdc_set_data_delay(host, 0);
+ }
+ goto tune_done;
+ }
if (host->hs400_mode &&
host->dev_comp->hs400_tune)
ret = hs400_tune_response(mmc, opcode);
@@ -1790,9 +1973,16 @@ static int msdc_execute_tuning(struct mmc_host *mmc, u32 opcode)
dev_err(host->dev, "Tune data fail!\n");
}
+tune_done:
host->saved_tune_para.iocon = readl(host->base + MSDC_IOCON);
host->saved_tune_para.pad_tune = readl(host->base + tune_reg);
host->saved_tune_para.pad_cmd_tune = readl(host->base + PAD_CMD_TUNE);
+ if (host->top_base) {
+ host->saved_tune_para.emmc_top_control = readl(host->top_base +
+ EMMC_TOP_CONTROL);
+ host->saved_tune_para.emmc_top_cmd = readl(host->top_base +
+ EMMC_TOP_CMD);
+ }
return ret;
}
@@ -1801,7 +1991,11 @@ static int msdc_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios)
struct msdc_host *host = mmc_priv(mmc);
host->hs400_mode = true;
- writel(host->hs400_ds_delay, host->base + PAD_DS_TUNE);
+ if (host->top_base)
+ writel(host->hs400_ds_delay,
+ host->top_base + EMMC50_PAD_DS_TUNE);
+ else
+ writel(host->hs400_ds_delay, host->base + PAD_DS_TUNE);
/* hs400 mode must set it to 0 */
sdr_clr_bits(host->base + MSDC_PATCH_BIT2, MSDC_PATCH_BIT2_CFGCRCSTS);
/* to improve read performance, set outstanding to 2 */
@@ -1884,6 +2078,11 @@ static int msdc_drv_probe(struct platform_device *pdev)
goto host_free;
}
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ host->top_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(host->top_base))
+ host->top_base = NULL;
+
ret = mmc_regulator_get_supply(mmc);
if (ret)
goto host_free;
@@ -1900,6 +2099,9 @@ static int msdc_drv_probe(struct platform_device *pdev)
goto host_free;
}
+ host->bus_clk = devm_clk_get(&pdev->dev, "bus_clk");
+ if (IS_ERR(host->bus_clk))
+ host->bus_clk = NULL;
/*source clock control gate is optional clock*/
host->src_clk_cg = devm_clk_get(&pdev->dev, "source_cg");
if (IS_ERR(host->src_clk_cg))
@@ -2049,7 +2251,6 @@ static void msdc_save_reg(struct msdc_host *host)
host->save_para.msdc_cfg = readl(host->base + MSDC_CFG);
host->save_para.iocon = readl(host->base + MSDC_IOCON);
host->save_para.sdc_cfg = readl(host->base + SDC_CFG);
- host->save_para.pad_tune = readl(host->base + tune_reg);
host->save_para.patch_bit0 = readl(host->base + MSDC_PATCH_BIT);
host->save_para.patch_bit1 = readl(host->base + MSDC_PATCH_BIT1);
host->save_para.patch_bit2 = readl(host->base + MSDC_PATCH_BIT2);
@@ -2058,6 +2259,16 @@ static void msdc_save_reg(struct msdc_host *host)
host->save_para.emmc50_cfg0 = readl(host->base + EMMC50_CFG0);
host->save_para.emmc50_cfg3 = readl(host->base + EMMC50_CFG3);
host->save_para.sdc_fifo_cfg = readl(host->base + SDC_FIFO_CFG);
+ if (host->top_base) {
+ host->save_para.emmc_top_control =
+ readl(host->top_base + EMMC_TOP_CONTROL);
+ host->save_para.emmc_top_cmd =
+ readl(host->top_base + EMMC_TOP_CMD);
+ host->save_para.emmc50_pad_ds_tune =
+ readl(host->top_base + EMMC50_PAD_DS_TUNE);
+ } else {
+ host->save_para.pad_tune = readl(host->base + tune_reg);
+ }
}
static void msdc_restore_reg(struct msdc_host *host)
@@ -2067,7 +2278,6 @@ static void msdc_restore_reg(struct msdc_host *host)
writel(host->save_para.msdc_cfg, host->base + MSDC_CFG);
writel(host->save_para.iocon, host->base + MSDC_IOCON);
writel(host->save_para.sdc_cfg, host->base + SDC_CFG);
- writel(host->save_para.pad_tune, host->base + tune_reg);
writel(host->save_para.patch_bit0, host->base + MSDC_PATCH_BIT);
writel(host->save_para.patch_bit1, host->base + MSDC_PATCH_BIT1);
writel(host->save_para.patch_bit2, host->base + MSDC_PATCH_BIT2);
@@ -2076,6 +2286,16 @@ static void msdc_restore_reg(struct msdc_host *host)
writel(host->save_para.emmc50_cfg0, host->base + EMMC50_CFG0);
writel(host->save_para.emmc50_cfg3, host->base + EMMC50_CFG3);
writel(host->save_para.sdc_fifo_cfg, host->base + SDC_FIFO_CFG);
+ if (host->top_base) {
+ writel(host->save_para.emmc_top_control,
+ host->top_base + EMMC_TOP_CONTROL);
+ writel(host->save_para.emmc_top_cmd,
+ host->top_base + EMMC_TOP_CMD);
+ writel(host->save_para.emmc50_pad_ds_tune,
+ host->top_base + EMMC50_PAD_DS_TUNE);
+ } else {
+ writel(host->save_para.pad_tune, host->base + tune_reg);
+ }
}
static int msdc_runtime_suspend(struct device *dev)
diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c
index de4e6e5bf304..4d17032d15ee 100644
--- a/drivers/mmc/host/mxcmmc.c
+++ b/drivers/mmc/host/mxcmmc.c
@@ -728,7 +728,6 @@ static void mxcmci_cmd_done(struct mxcmci_host *host, unsigned int stat)
static irqreturn_t mxcmci_irq(int irq, void *devid)
{
struct mxcmci_host *host = devid;
- unsigned long flags;
bool sdio_irq;
u32 stat;
@@ -740,9 +739,9 @@ static irqreturn_t mxcmci_irq(int irq, void *devid)
dev_dbg(mmc_dev(host->mmc), "%s: 0x%08x\n", __func__, stat);
- spin_lock_irqsave(&host->lock, flags);
+ spin_lock(&host->lock);
sdio_irq = (stat & STATUS_SDIO_INT_ACTIVE) && host->use_sdio;
- spin_unlock_irqrestore(&host->lock, flags);
+ spin_unlock(&host->lock);
if (mxcmci_use_dma(host) && (stat & (STATUS_WRITE_OP_DONE)))
mxcmci_writel(host, STATUS_WRITE_OP_DONE, MMC_REG_STATUS);
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 68760d4a5d3d..467d889a1638 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -30,7 +30,6 @@
#include <linux/clk.h>
#include <linux/of.h>
#include <linux/of_irq.h>
-#include <linux/of_gpio.h>
#include <linux/of_device.h>
#include <linux/mmc/host.h>
#include <linux/mmc/core.h>
@@ -38,7 +37,6 @@
#include <linux/mmc/slot-gpio.h>
#include <linux/io.h>
#include <linux/irq.h>
-#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h>
@@ -198,7 +196,6 @@ struct omap_hsmmc_host {
struct dma_chan *rx_chan;
int response_busy;
int context_loss;
- int protect_card;
int reqs_blocked;
int req_in_progress;
unsigned long clk_rate;
@@ -207,16 +204,6 @@ struct omap_hsmmc_host {
#define HSMMC_SDIO_IRQ_ENABLED (1 << 1) /* SDIO irq enabled */
struct omap_hsmmc_next next_data;
struct omap_hsmmc_platform_data *pdata;
-
- /* return MMC cover switch state, can be NULL if not supported.
- *
- * possible return values:
- * 0 - closed
- * 1 - open
- */
- int (*get_cover_state)(struct device *dev);
-
- int (*card_detect)(struct device *dev);
};
struct omap_mmc_of_data {
@@ -226,20 +213,6 @@ struct omap_mmc_of_data {
static void omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host);
-static int omap_hsmmc_card_detect(struct device *dev)
-{
- struct omap_hsmmc_host *host = dev_get_drvdata(dev);
-
- return mmc_gpio_get_cd(host->mmc);
-}
-
-static int omap_hsmmc_get_cover_state(struct device *dev)
-{
- struct omap_hsmmc_host *host = dev_get_drvdata(dev);
-
- return mmc_gpio_get_cd(host->mmc);
-}
-
static int omap_hsmmc_enable_supply(struct mmc_host *mmc)
{
int ret;
@@ -484,38 +457,6 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
return 0;
}
-static irqreturn_t omap_hsmmc_cover_irq(int irq, void *dev_id);
-
-static int omap_hsmmc_gpio_init(struct mmc_host *mmc,
- struct omap_hsmmc_host *host,
- struct omap_hsmmc_platform_data *pdata)
-{
- int ret;
-
- if (gpio_is_valid(pdata->gpio_cod)) {
- ret = mmc_gpio_request_cd(mmc, pdata->gpio_cod, 0);
- if (ret)
- return ret;
-
- host->get_cover_state = omap_hsmmc_get_cover_state;
- mmc_gpio_set_cd_isr(mmc, omap_hsmmc_cover_irq);
- } else if (gpio_is_valid(pdata->gpio_cd)) {
- ret = mmc_gpio_request_cd(mmc, pdata->gpio_cd, 0);
- if (ret)
- return ret;
-
- host->card_detect = omap_hsmmc_card_detect;
- }
-
- if (gpio_is_valid(pdata->gpio_wp)) {
- ret = mmc_gpio_request_ro(mmc, pdata->gpio_wp);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
/*
* Start clock to the card
*/
@@ -781,9 +722,6 @@ static void send_init_stream(struct omap_hsmmc_host *host)
int reg = 0;
unsigned long timeout;
- if (host->protect_card)
- return;
-
disable_irq(host->irq);
OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
@@ -804,29 +742,6 @@ static void send_init_stream(struct omap_hsmmc_host *host)
enable_irq(host->irq);
}
-static inline
-int omap_hsmmc_cover_is_closed(struct omap_hsmmc_host *host)
-{
- int r = 1;
-
- if (host->get_cover_state)
- r = host->get_cover_state(host->dev);
- return r;
-}
-
-static ssize_t
-omap_hsmmc_show_cover_switch(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev);
- struct omap_hsmmc_host *host = mmc_priv(mmc);
-
- return sprintf(buf, "%s\n",
- omap_hsmmc_cover_is_closed(host) ? "closed" : "open");
-}
-
-static DEVICE_ATTR(cover_switch, S_IRUGO, omap_hsmmc_show_cover_switch, NULL);
-
static ssize_t
omap_hsmmc_show_slot_name(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -1247,44 +1162,6 @@ err:
return ret;
}
-/* Protect the card while the cover is open */
-static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host)
-{
- if (!host->get_cover_state)
- return;
-
- host->reqs_blocked = 0;
- if (host->get_cover_state(host->dev)) {
- if (host->protect_card) {
- dev_info(host->dev, "%s: cover is closed, "
- "card is now accessible\n",
- mmc_hostname(host->mmc));
- host->protect_card = 0;
- }
- } else {
- if (!host->protect_card) {
- dev_info(host->dev, "%s: cover is open, "
- "card is now inaccessible\n",
- mmc_hostname(host->mmc));
- host->protect_card = 1;
- }
- }
-}
-
-/*
- * irq handler when (cell-phone) cover is mounted/removed
- */
-static irqreturn_t omap_hsmmc_cover_irq(int irq, void *dev_id)
-{
- struct omap_hsmmc_host *host = dev_id;
-
- sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch");
-
- omap_hsmmc_protect_card(host);
- mmc_detect_change(host->mmc, (HZ * 200) / 1000);
- return IRQ_HANDLED;
-}
-
static void omap_hsmmc_dma_callback(void *param)
{
struct omap_hsmmc_host *host = param;
@@ -1555,24 +1432,7 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)
BUG_ON(host->req_in_progress);
BUG_ON(host->dma_ch != -1);
- if (host->protect_card) {
- if (host->reqs_blocked < 3) {
- /*
- * Ensure the controller is left in a consistent
- * state by resetting the command and data state
- * machines.
- */
- omap_hsmmc_reset_controller_fsm(host, SRD);
- omap_hsmmc_reset_controller_fsm(host, SRC);
- host->reqs_blocked += 1;
- }
- req->cmd->error = -EBADF;
- if (req->data)
- req->data->error = -EBADF;
- req->cmd->retries = 0;
- mmc_request_done(mmc, req);
- return;
- } else if (host->reqs_blocked)
+ if (host->reqs_blocked)
host->reqs_blocked = 0;
WARN_ON(host->mrq != NULL);
host->mrq = req;
@@ -1646,15 +1506,6 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
omap_hsmmc_set_bus_mode(host);
}
-static int omap_hsmmc_get_cd(struct mmc_host *mmc)
-{
- struct omap_hsmmc_host *host = mmc_priv(mmc);
-
- if (!host->card_detect)
- return -ENOSYS;
- return host->card_detect(host->dev);
-}
-
static void omap_hsmmc_init_card(struct mmc_host *mmc, struct mmc_card *card)
{
struct omap_hsmmc_host *host = mmc_priv(mmc);
@@ -1793,7 +1644,7 @@ static struct mmc_host_ops omap_hsmmc_ops = {
.pre_req = omap_hsmmc_pre_req,
.request = omap_hsmmc_request,
.set_ios = omap_hsmmc_set_ios,
- .get_cd = omap_hsmmc_get_cd,
+ .get_cd = mmc_gpio_get_cd,
.get_ro = mmc_gpio_get_ro,
.init_card = omap_hsmmc_init_card,
.enable_sdio_irq = omap_hsmmc_enable_sdio_irq,
@@ -1920,10 +1771,6 @@ static struct omap_hsmmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
if (of_find_property(np, "ti,dual-volt", NULL))
pdata->controller_flags |= OMAP_HSMMC_SUPPORTS_DUAL_VOLT;
- pdata->gpio_cd = -EINVAL;
- pdata->gpio_cod = -EINVAL;
- pdata->gpio_wp = -EINVAL;
-
if (of_find_property(np, "ti,non-removable", NULL)) {
pdata->nonremovable = true;
pdata->no_regulator_off_init = true;
@@ -2008,10 +1855,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
host->pbias_enabled = 0;
host->vqmmc_enabled = 0;
- ret = omap_hsmmc_gpio_init(mmc, host, pdata);
- if (ret)
- goto err_gpio;
-
platform_set_drvdata(pdev, host);
if (pdev->dev.of_node)
@@ -2125,8 +1968,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
if (!ret)
mmc->caps |= MMC_CAP_SDIO_IRQ;
- omap_hsmmc_protect_card(host);
-
mmc_add_host(mmc);
if (mmc_pdata(host)->name != NULL) {
@@ -2134,12 +1975,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
if (ret < 0)
goto err_slot_name;
}
- if (host->get_cover_state) {
- ret = device_create_file(&mmc->class_dev,
- &dev_attr_cover_switch);
- if (ret < 0)
- goto err_slot_name;
- }
omap_hsmmc_debugfs(mmc);
pm_runtime_mark_last_busy(host->dev);
@@ -2161,7 +1996,6 @@ err_irq:
if (host->dbclk)
clk_disable_unprepare(host->dbclk);
err1:
-err_gpio:
mmc_free_host(mmc);
err:
return ret;
@@ -2231,7 +2065,6 @@ static int omap_hsmmc_resume(struct device *dev)
if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER))
omap_hsmmc_conf_bus_power(host);
- omap_hsmmc_protect_card(host);
pm_runtime_mark_last_busy(host->dev);
pm_runtime_put_autosuspend(host->dev);
return 0;
diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h
index f13f798d8506..da1e49c45bec 100644
--- a/drivers/mmc/host/renesas_sdhi.h
+++ b/drivers/mmc/host/renesas_sdhi.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Renesas Mobile SDHI
*
* Copyright (C) 2017 Horms Solutions Ltd., Simon Horman
* Copyright (C) 2017 Renesas Electronics Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#ifndef RENESAS_SDHI_H
diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c
index 777e32b0e410..d3ac43c3d0b6 100644
--- a/drivers/mmc/host/renesas_sdhi_core.c
+++ b/drivers/mmc/host/renesas_sdhi_core.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Renesas SDHI
*
@@ -6,10 +7,6 @@
* Copyright (C) 2016-17 Horms Solutions, Simon Horman
* Copyright (C) 2009 Magnus Damm
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
* Based on "Compaq ASIC3 support":
*
* Copyright 2001 Compaq Computer Corporation.
@@ -155,6 +152,52 @@ static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host,
return ret == 0 ? best_freq : clk_get_rate(priv->clk);
}
+static void renesas_sdhi_set_clock(struct tmio_mmc_host *host,
+ unsigned int new_clock)
+{
+ u32 clk = 0, clock;
+
+ sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
+ sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+
+ if (new_clock == 0)
+ goto out;
+
+ /*
+ * Both HS400 and HS200/SD104 set 200MHz, but some devices need to
+ * set 400MHz to distinguish the CPG settings in HS400.
+ */
+ if (host->mmc->ios.timing == MMC_TIMING_MMC_HS400 &&
+ host->pdata->flags & TMIO_MMC_HAVE_4TAP_HS400 &&
+ new_clock == 200000000)
+ new_clock = 400000000;
+
+ clock = renesas_sdhi_clk_update(host, new_clock) / 512;
+
+ for (clk = 0x80000080; new_clock >= (clock << 1); clk >>= 1)
+ clock <<= 1;
+
+ /* 1/1 clock is option */
+ if ((host->pdata->flags & TMIO_MMC_CLK_ACTUAL) && ((clk >> 22) & 0x1)) {
+ if (!(host->mmc->ios.timing == MMC_TIMING_MMC_HS400))
+ clk |= 0xff;
+ else
+ clk &= ~0xff;
+ }
+
+ sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & CLK_CTL_DIV_MASK);
+ if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2))
+ usleep_range(10000, 11000);
+
+ sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN |
+ sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+
+out:
+ /* HW engineers overrode docs: no sleep needed on R-Car2+ */
+ if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2))
+ usleep_range(10000, 11000);
+}
+
static void renesas_sdhi_clk_disable(struct tmio_mmc_host *host)
{
struct renesas_sdhi *priv = host_to_priv(host);
@@ -443,6 +486,19 @@ static int renesas_sdhi_select_tuning(struct tmio_mmc_host *host)
static bool renesas_sdhi_check_scc_error(struct tmio_mmc_host *host)
{
struct renesas_sdhi *priv = host_to_priv(host);
+ bool use_4tap = host->pdata->flags & TMIO_MMC_HAVE_4TAP_HS400;
+
+ /*
+ * Skip checking SCC errors when running on 4 taps in HS400 mode as
+ * any retuning would still result in the same 4 taps being used.
+ */
+ if (!(host->mmc->ios.timing == MMC_TIMING_UHS_SDR104) &&
+ !(host->mmc->ios.timing == MMC_TIMING_MMC_HS200) &&
+ !(host->mmc->ios.timing == MMC_TIMING_MMC_HS400 && !use_4tap))
+ return false;
+
+ if (mmc_doing_retune(host->mmc))
+ return false;
/* Check SCC error */
if (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL) &
@@ -620,8 +676,8 @@ int renesas_sdhi_probe(struct platform_device *pdev,
host->write16_hook = renesas_sdhi_write16_hook;
host->clk_enable = renesas_sdhi_clk_enable;
- host->clk_update = renesas_sdhi_clk_update;
host->clk_disable = renesas_sdhi_clk_disable;
+ host->set_clock = renesas_sdhi_set_clock;
host->multi_io_quirk = renesas_sdhi_multi_io_quirk;
host->dma_ops = dma_ops;
diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c
index ca0b43973769..b6f54102bfdd 100644
--- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c
+++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* DMA support for Internal DMAC with SDHI SD/SDIO controller
*
* Copyright (C) 2016-17 Renesas Electronics Corporation
* Copyright (C) 2016-17 Horms Solutions, Simon Horman
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/bitops.h>
@@ -35,8 +32,8 @@
/* DM_CM_DTRAN_MODE */
#define DTRAN_MODE_CH_NUM_CH0 0 /* "downstream" = for write commands */
-#define DTRAN_MODE_CH_NUM_CH1 BIT(16) /* "uptream" = for read commands */
-#define DTRAN_MODE_BUS_WID_TH (BIT(5) | BIT(4))
+#define DTRAN_MODE_CH_NUM_CH1 BIT(16) /* "upstream" = for read commands */
+#define DTRAN_MODE_BUS_WIDTH (BIT(5) | BIT(4))
#define DTRAN_MODE_ADDR_MODE BIT(0) /* 1 = Increment address */
/* DM_CM_DTRAN_CTRL */
@@ -116,6 +113,7 @@ static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = {
};
static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = {
+ { .compatible = "renesas,sdhi-mmc-r8a77470", .data = &of_rcar_gen3_compatible, },
{ .compatible = "renesas,sdhi-r8a7795", .data = &of_rcar_r8a7795_compatible, },
{ .compatible = "renesas,sdhi-r8a7796", .data = &of_rcar_r8a7795_compatible, },
{ .compatible = "renesas,rcar-gen3-sdhi", .data = &of_rcar_gen3_compatible, },
@@ -174,7 +172,7 @@ renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host,
struct mmc_data *data)
{
struct scatterlist *sg = host->sg_ptr;
- u32 dtran_mode = DTRAN_MODE_BUS_WID_TH | DTRAN_MODE_ADDR_MODE;
+ u32 dtran_mode = DTRAN_MODE_BUS_WIDTH | DTRAN_MODE_ADDR_MODE;
if (!dma_map_sg(&host->pdev->dev, sg, host->sg_len,
mmc_get_dma_dir(data)))
@@ -201,13 +199,14 @@ renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host,
renesas_sdhi_internal_dmac_dm_write(host, DM_DTRAN_ADDR,
sg_dma_address(sg));
+ host->dma_on = true;
+
return;
force_pio_with_unmap:
dma_unmap_sg(&host->pdev->dev, sg, host->sg_len, mmc_get_dma_dir(data));
force_pio:
- host->force_pio = true;
renesas_sdhi_internal_dmac_enable_dma(host, false);
}
@@ -291,16 +290,19 @@ static const struct tmio_mmc_dma_ops renesas_sdhi_internal_dmac_dma_ops = {
* Whitelist of specific R-Car Gen3 SoC ES versions to use this DMAC
* implementation as others may use a different implementation.
*/
-static const struct soc_device_attribute gen3_soc_whitelist[] = {
+static const struct soc_device_attribute soc_whitelist[] = {
/* specific ones */
{ .soc_id = "r8a7795", .revision = "ES1.*",
.data = (void *)BIT(SDHI_INTERNAL_DMAC_ONE_RX_ONLY) },
{ .soc_id = "r8a7796", .revision = "ES1.0",
.data = (void *)BIT(SDHI_INTERNAL_DMAC_ONE_RX_ONLY) },
/* generic ones */
+ { .soc_id = "r8a774a1" },
+ { .soc_id = "r8a77470" },
{ .soc_id = "r8a7795" },
{ .soc_id = "r8a7796" },
{ .soc_id = "r8a77965" },
+ { .soc_id = "r8a77970" },
{ .soc_id = "r8a77980" },
{ .soc_id = "r8a77995" },
{ /* sentinel */ }
@@ -308,13 +310,21 @@ static const struct soc_device_attribute gen3_soc_whitelist[] = {
static int renesas_sdhi_internal_dmac_probe(struct platform_device *pdev)
{
- const struct soc_device_attribute *soc = soc_device_match(gen3_soc_whitelist);
+ const struct soc_device_attribute *soc = soc_device_match(soc_whitelist);
+ struct device *dev = &pdev->dev;
if (!soc)
return -ENODEV;
global_flags |= (unsigned long)soc->data;
+ dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms), GFP_KERNEL);
+ if (!dev->dma_parms)
+ return -ENOMEM;
+
+ /* value is max of SD_SECCNT. Confirmed by HW engineers */
+ dma_set_max_seg_size(dev, 0xffffffff);
+
return renesas_sdhi_probe(pdev, &renesas_sdhi_internal_dmac_dma_ops);
}
diff --git a/drivers/mmc/host/renesas_sdhi_sys_dmac.c b/drivers/mmc/host/renesas_sdhi_sys_dmac.c
index 890f192dedbd..1a4016f635d3 100644
--- a/drivers/mmc/host/renesas_sdhi_sys_dmac.c
+++ b/drivers/mmc/host/renesas_sdhi_sys_dmac.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* DMA support use of SYS DMAC with SDHI SD/SDIO controller
*
@@ -5,10 +6,6 @@
* Copyright (C) 2016-17 Sang Engineering, Wolfram Sang
* Copyright (C) 2017 Horms Solutions, Simon Horman
* Copyright (C) 2010-2011 Guennadi Liakhovetski
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/device.h>
@@ -213,10 +210,8 @@ static void renesas_sdhi_sys_dmac_start_dma_rx(struct tmio_mmc_host *host)
goto pio;
}
- if (sg->length < TMIO_MMC_MIN_DMA_LEN) {
- host->force_pio = true;
+ if (sg->length < TMIO_MMC_MIN_DMA_LEN)
return;
- }
/* The only sg element can be unaligned, use our bounce buffer then */
if (!aligned) {
@@ -240,6 +235,7 @@ static void renesas_sdhi_sys_dmac_start_dma_rx(struct tmio_mmc_host *host)
desc = NULL;
ret = cookie;
}
+ host->dma_on = true;
}
pio:
if (!desc) {
@@ -286,10 +282,8 @@ static void renesas_sdhi_sys_dmac_start_dma_tx(struct tmio_mmc_host *host)
goto pio;
}
- if (sg->length < TMIO_MMC_MIN_DMA_LEN) {
- host->force_pio = true;
+ if (sg->length < TMIO_MMC_MIN_DMA_LEN)
return;
- }
/* The only sg element can be unaligned, use our bounce buffer then */
if (!aligned) {
@@ -318,6 +312,7 @@ static void renesas_sdhi_sys_dmac_start_dma_tx(struct tmio_mmc_host *host)
desc = NULL;
ret = cookie;
}
+ host->dma_on = true;
}
pio:
if (!desc) {
@@ -498,7 +493,8 @@ static const struct soc_device_attribute gen3_soc_whitelist[] = {
static int renesas_sdhi_sys_dmac_probe(struct platform_device *pdev)
{
- if (of_device_get_match_data(&pdev->dev) == &of_rcar_gen3_compatible &&
+ if ((of_device_get_match_data(&pdev->dev) == &of_rcar_gen3_compatible ||
+ of_device_get_match_data(&pdev->dev) == &of_rcar_r8a7795_compatible) &&
!soc_device_match(gen3_soc_whitelist))
return -ENODEV;
diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c
index 32321bd596d8..057e24f4a620 100644
--- a/drivers/mmc/host/sdhci-acpi.c
+++ b/drivers/mmc/host/sdhci-acpi.c
@@ -76,6 +76,7 @@ struct sdhci_acpi_slot {
size_t priv_size;
int (*probe_slot)(struct platform_device *, const char *, const char *);
int (*remove_slot)(struct platform_device *);
+ int (*free_slot)(struct platform_device *pdev);
int (*setup_host)(struct platform_device *pdev);
};
@@ -246,7 +247,7 @@ static const struct sdhci_acpi_chip sdhci_acpi_chip_int = {
static bool sdhci_acpi_byt(void)
{
static const struct x86_cpu_id byt[] = {
- { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT1 },
+ { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT },
{}
};
@@ -470,10 +471,70 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = {
.priv_size = sizeof(struct intel_host),
};
+#define VENDOR_SPECIFIC_PWRCTL_CLEAR_REG 0x1a8
+#define VENDOR_SPECIFIC_PWRCTL_CTL_REG 0x1ac
+static irqreturn_t sdhci_acpi_qcom_handler(int irq, void *ptr)
+{
+ struct sdhci_host *host = ptr;
+
+ sdhci_writel(host, 0x3, VENDOR_SPECIFIC_PWRCTL_CLEAR_REG);
+ sdhci_writel(host, 0x1, VENDOR_SPECIFIC_PWRCTL_CTL_REG);
+
+ return IRQ_HANDLED;
+}
+
+static int qcom_probe_slot(struct platform_device *pdev, const char *hid,
+ const char *uid)
+{
+ struct sdhci_acpi_host *c = platform_get_drvdata(pdev);
+ struct sdhci_host *host = c->host;
+ int *irq = sdhci_acpi_priv(c);
+
+ *irq = -EINVAL;
+
+ if (strcmp(hid, "QCOM8051"))
+ return 0;
+
+ *irq = platform_get_irq(pdev, 1);
+ if (*irq < 0)
+ return 0;
+
+ return request_threaded_irq(*irq, NULL, sdhci_acpi_qcom_handler,
+ IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
+ "sdhci_qcom", host);
+}
+
+static int qcom_free_slot(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct sdhci_acpi_host *c = platform_get_drvdata(pdev);
+ struct sdhci_host *host = c->host;
+ struct acpi_device *adev;
+ int *irq = sdhci_acpi_priv(c);
+ const char *hid;
+
+ adev = ACPI_COMPANION(dev);
+ if (!adev)
+ return -ENODEV;
+
+ hid = acpi_device_hid(adev);
+ if (strcmp(hid, "QCOM8051"))
+ return 0;
+
+ if (*irq < 0)
+ return 0;
+
+ free_irq(*irq, host);
+ return 0;
+}
+
static const struct sdhci_acpi_slot sdhci_acpi_slot_qcom_sd_3v = {
.quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION,
.quirks2 = SDHCI_QUIRK2_NO_1_8_V,
.caps = MMC_CAP_NONREMOVABLE,
+ .priv_size = sizeof(int),
+ .probe_slot = qcom_probe_slot,
+ .free_slot = qcom_free_slot,
};
static const struct sdhci_acpi_slot sdhci_acpi_slot_qcom_sd = {
@@ -756,6 +817,9 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
err_cleanup:
sdhci_cleanup_host(c->host);
err_free:
+ if (c->slot && c->slot->free_slot)
+ c->slot->free_slot(pdev);
+
sdhci_free_host(c->host);
return err;
}
@@ -777,6 +841,10 @@ static int sdhci_acpi_remove(struct platform_device *pdev)
dead = (sdhci_readl(c->host, SDHCI_INT_STATUS) == ~0);
sdhci_remove_host(c->host, dead);
+
+ if (c->slot && c->slot->free_slot)
+ c->slot->free_slot(pdev);
+
sdhci_free_host(c->host);
return 0;
diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h
index dfa58f8b8dfa..3f16d9c90ba2 100644
--- a/drivers/mmc/host/sdhci-esdhc.h
+++ b/drivers/mmc/host/sdhci-esdhc.h
@@ -60,6 +60,7 @@
/* Tuning Block Control Register */
#define ESDHC_TBCTL 0x120
#define ESDHC_TB_EN 0x00000004
+#define ESDHC_TBPTR 0x128
/* Control Register for DMA transfer */
#define ESDHC_DMA_SYSCTL 0x40c
diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c
index d0e83db42ae5..0db99057c44f 100644
--- a/drivers/mmc/host/sdhci-iproc.c
+++ b/drivers/mmc/host/sdhci-iproc.c
@@ -15,6 +15,7 @@
* iProc SDHCI platform driver
*/
+#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/mmc/host.h>
@@ -162,9 +163,19 @@ static void sdhci_iproc_writeb(struct sdhci_host *host, u8 val, int reg)
sdhci_iproc_writel(host, newval, reg & ~3);
}
+static unsigned int sdhci_iproc_get_max_clock(struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+ if (pltfm_host->clk)
+ return sdhci_pltfm_clk_get_max_clock(host);
+ else
+ return pltfm_host->clock;
+}
+
static const struct sdhci_ops sdhci_iproc_ops = {
.set_clock = sdhci_set_clock,
- .get_max_clock = sdhci_pltfm_clk_get_max_clock,
+ .get_max_clock = sdhci_iproc_get_max_clock,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
@@ -178,7 +189,7 @@ static const struct sdhci_ops sdhci_iproc_32only_ops = {
.write_w = sdhci_iproc_writew,
.write_b = sdhci_iproc_writeb,
.set_clock = sdhci_set_clock,
- .get_max_clock = sdhci_pltfm_clk_get_max_clock,
+ .get_max_clock = sdhci_iproc_get_max_clock,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
@@ -256,19 +267,25 @@ static const struct of_device_id sdhci_iproc_of_match[] = {
};
MODULE_DEVICE_TABLE(of, sdhci_iproc_of_match);
+static const struct acpi_device_id sdhci_iproc_acpi_ids[] = {
+ { .id = "BRCM5871", .driver_data = (kernel_ulong_t)&iproc_cygnus_data },
+ { .id = "BRCM5872", .driver_data = (kernel_ulong_t)&iproc_data },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(acpi, sdhci_iproc_acpi_ids);
+
static int sdhci_iproc_probe(struct platform_device *pdev)
{
- const struct of_device_id *match;
- const struct sdhci_iproc_data *iproc_data;
+ struct device *dev = &pdev->dev;
+ const struct sdhci_iproc_data *iproc_data = NULL;
struct sdhci_host *host;
struct sdhci_iproc_host *iproc_host;
struct sdhci_pltfm_host *pltfm_host;
int ret;
- match = of_match_device(sdhci_iproc_of_match, &pdev->dev);
- if (!match)
- return -EINVAL;
- iproc_data = match->data;
+ iproc_data = device_get_match_data(dev);
+ if (!iproc_data)
+ return -ENODEV;
host = sdhci_pltfm_init(pdev, iproc_data->pdata, sizeof(*iproc_host));
if (IS_ERR(host))
@@ -280,19 +297,21 @@ static int sdhci_iproc_probe(struct platform_device *pdev)
iproc_host->data = iproc_data;
mmc_of_parse(host->mmc);
- sdhci_get_of_property(pdev);
+ sdhci_get_property(pdev);
host->mmc->caps |= iproc_host->data->mmc_caps;
- pltfm_host->clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(pltfm_host->clk)) {
- ret = PTR_ERR(pltfm_host->clk);
- goto err;
- }
- ret = clk_prepare_enable(pltfm_host->clk);
- if (ret) {
- dev_err(&pdev->dev, "failed to enable host clk\n");
- goto err;
+ if (dev->of_node) {
+ pltfm_host->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(pltfm_host->clk)) {
+ ret = PTR_ERR(pltfm_host->clk);
+ goto err;
+ }
+ ret = clk_prepare_enable(pltfm_host->clk);
+ if (ret) {
+ dev_err(dev, "failed to enable host clk\n");
+ goto err;
+ }
}
if (iproc_host->data->pdata->quirks & SDHCI_QUIRK_MISSING_CAPS) {
@@ -307,7 +326,8 @@ static int sdhci_iproc_probe(struct platform_device *pdev)
return 0;
err_clk:
- clk_disable_unprepare(pltfm_host->clk);
+ if (dev->of_node)
+ clk_disable_unprepare(pltfm_host->clk);
err:
sdhci_pltfm_free(pdev);
return ret;
@@ -317,6 +337,7 @@ static struct platform_driver sdhci_iproc_driver = {
.driver = {
.name = "sdhci-iproc",
.of_match_table = sdhci_iproc_of_match,
+ .acpi_match_table = ACPI_PTR(sdhci_iproc_acpi_ids),
.pm = &sdhci_pltfm_pmops,
},
.probe = sdhci_iproc_probe,
diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c
index a40bcc27f187..142c4b802f31 100644
--- a/drivers/mmc/host/sdhci-of-arasan.c
+++ b/drivers/mmc/host/sdhci-of-arasan.c
@@ -107,6 +107,11 @@ struct sdhci_arasan_data {
#define SDHCI_ARASAN_QUIRK_CLOCK_UNSTABLE BIT(1)
};
+struct sdhci_arasan_of_data {
+ const struct sdhci_arasan_soc_ctl_map *soc_ctl_map;
+ const struct sdhci_pltfm_data *pdata;
+};
+
static const struct sdhci_arasan_soc_ctl_map rk3399_soc_ctl_map = {
.baseclkfreq = { .reg = 0xf000, .width = 8, .shift = 8 },
.clockmultiplier = { .reg = 0xf02c, .width = 8, .shift = 0},
@@ -226,6 +231,25 @@ static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock)
}
}
+static void sdhci_arasan_am654_set_clock(struct sdhci_host *host,
+ unsigned int clock)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
+
+ if (sdhci_arasan->is_phy_on) {
+ phy_power_off(sdhci_arasan->phy);
+ sdhci_arasan->is_phy_on = false;
+ }
+
+ sdhci_set_clock(host, clock);
+
+ if (clock > PHY_CLK_TOO_SLOW_HZ) {
+ phy_power_on(sdhci_arasan->phy);
+ sdhci_arasan->is_phy_on = true;
+ }
+}
+
static void sdhci_arasan_hs400_enhanced_strobe(struct mmc_host *mmc,
struct mmc_ios *ios)
{
@@ -307,6 +331,33 @@ static const struct sdhci_pltfm_data sdhci_arasan_pdata = {
SDHCI_QUIRK2_STOP_WITH_TC,
};
+static struct sdhci_arasan_of_data sdhci_arasan_data = {
+ .pdata = &sdhci_arasan_pdata,
+};
+
+static const struct sdhci_ops sdhci_arasan_am654_ops = {
+ .set_clock = sdhci_arasan_am654_set_clock,
+ .get_max_clock = sdhci_pltfm_clk_get_max_clock,
+ .get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
+ .set_bus_width = sdhci_set_bus_width,
+ .reset = sdhci_arasan_reset,
+ .set_uhs_signaling = sdhci_set_uhs_signaling,
+};
+
+static const struct sdhci_pltfm_data sdhci_arasan_am654_pdata = {
+ .ops = &sdhci_arasan_am654_ops,
+ .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
+ SDHCI_QUIRK_INVERTED_WRITE_PROTECT |
+ SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12,
+ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
+ SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN |
+ SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400,
+};
+
+static const struct sdhci_arasan_of_data sdhci_arasan_am654_data = {
+ .pdata = &sdhci_arasan_am654_pdata,
+};
+
static u32 sdhci_arasan_cqhci_irq(struct sdhci_host *host, u32 intmask)
{
int cmd_error = 0;
@@ -363,6 +414,11 @@ static const struct sdhci_pltfm_data sdhci_arasan_cqe_pdata = {
SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
};
+static struct sdhci_arasan_of_data sdhci_arasan_rk3399_data = {
+ .soc_ctl_map = &rk3399_soc_ctl_map,
+ .pdata = &sdhci_arasan_cqe_pdata,
+};
+
#ifdef CONFIG_PM_SLEEP
/**
* sdhci_arasan_suspend - Suspend method for the driver
@@ -462,14 +518,25 @@ static const struct of_device_id sdhci_arasan_of_match[] = {
/* SoC-specific compatible strings w/ soc_ctl_map */
{
.compatible = "rockchip,rk3399-sdhci-5.1",
- .data = &rk3399_soc_ctl_map,
+ .data = &sdhci_arasan_rk3399_data,
+ },
+ {
+ .compatible = "ti,am654-sdhci-5.1",
+ .data = &sdhci_arasan_am654_data,
},
-
/* Generic compatible below here */
- { .compatible = "arasan,sdhci-8.9a" },
- { .compatible = "arasan,sdhci-5.1" },
- { .compatible = "arasan,sdhci-4.9a" },
-
+ {
+ .compatible = "arasan,sdhci-8.9a",
+ .data = &sdhci_arasan_data,
+ },
+ {
+ .compatible = "arasan,sdhci-5.1",
+ .data = &sdhci_arasan_data,
+ },
+ {
+ .compatible = "arasan,sdhci-4.9a",
+ .data = &sdhci_arasan_data,
+ },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sdhci_arasan_of_match);
@@ -707,14 +774,11 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
struct sdhci_pltfm_host *pltfm_host;
struct sdhci_arasan_data *sdhci_arasan;
struct device_node *np = pdev->dev.of_node;
- const struct sdhci_pltfm_data *pdata;
-
- if (of_device_is_compatible(pdev->dev.of_node, "arasan,sdhci-5.1"))
- pdata = &sdhci_arasan_cqe_pdata;
- else
- pdata = &sdhci_arasan_pdata;
+ const struct sdhci_arasan_of_data *data;
- host = sdhci_pltfm_init(pdev, pdata, sizeof(*sdhci_arasan));
+ match = of_match_node(sdhci_arasan_of_match, pdev->dev.of_node);
+ data = match->data;
+ host = sdhci_pltfm_init(pdev, data->pdata, sizeof(*sdhci_arasan));
if (IS_ERR(host))
return PTR_ERR(host);
@@ -723,8 +787,7 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
sdhci_arasan->host = host;
- match = of_match_node(sdhci_arasan_of_match, pdev->dev.of_node);
- sdhci_arasan->soc_ctl_map = match->data;
+ sdhci_arasan->soc_ctl_map = data->soc_ctl_map;
node = of_parse_phandle(pdev->dev.of_node, "arasan,soc-ctl-syscon", 0);
if (node) {
@@ -788,7 +851,8 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
ret = mmc_of_parse(host->mmc);
if (ret) {
- dev_err(&pdev->dev, "parsing dt failed (%d)\n", ret);
+ if (ret != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "parsing dt failed (%d)\n", ret);
goto unreg_clk;
}
diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c
index 1b7cd144fb01..a5137845a1c7 100644
--- a/drivers/mmc/host/sdhci-of-dwcmshc.c
+++ b/drivers/mmc/host/sdhci-of-dwcmshc.c
@@ -8,21 +8,51 @@
*/
#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/sizes.h>
#include "sdhci-pltfm.h"
+#define BOUNDARY_OK(addr, len) \
+ ((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1)))
+
struct dwcmshc_priv {
struct clk *bus_clk;
};
+/*
+ * If DMA addr spans 128MB boundary, we split the DMA transfer into two
+ * so that each DMA transfer doesn't exceed the boundary.
+ */
+static void dwcmshc_adma_write_desc(struct sdhci_host *host, void **desc,
+ dma_addr_t addr, int len, unsigned int cmd)
+{
+ int tmplen, offset;
+
+ if (likely(!len || BOUNDARY_OK(addr, len))) {
+ sdhci_adma_write_desc(host, desc, addr, len, cmd);
+ return;
+ }
+
+ offset = addr & (SZ_128M - 1);
+ tmplen = SZ_128M - offset;
+ sdhci_adma_write_desc(host, desc, addr, tmplen, cmd);
+
+ addr += tmplen;
+ len -= tmplen;
+ sdhci_adma_write_desc(host, desc, addr, len, cmd);
+}
+
static const struct sdhci_ops sdhci_dwcmshc_ops = {
.set_clock = sdhci_set_clock,
.set_bus_width = sdhci_set_bus_width,
.set_uhs_signaling = sdhci_set_uhs_signaling,
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
.reset = sdhci_reset,
+ .adma_write_desc = dwcmshc_adma_write_desc,
};
static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = {
@@ -36,12 +66,21 @@ static int dwcmshc_probe(struct platform_device *pdev)
struct sdhci_host *host;
struct dwcmshc_priv *priv;
int err;
+ u32 extra;
host = sdhci_pltfm_init(pdev, &sdhci_dwcmshc_pdata,
sizeof(struct dwcmshc_priv));
if (IS_ERR(host))
return PTR_ERR(host);
+ /*
+ * extra adma table cnt for cross 128M boundary handling.
+ */
+ extra = DIV_ROUND_UP_ULL(dma_get_required_mask(&pdev->dev), SZ_128M);
+ if (extra > SDHCI_MAX_SEGS)
+ extra = SDHCI_MAX_SEGS;
+ host->adma_table_cnt += extra;
+
pltfm_host = sdhci_priv(host);
priv = sdhci_pltfm_priv(pltfm_host);
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index 9cb7554a463d..86fc9f022002 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -78,8 +78,10 @@ struct sdhci_esdhc {
u8 vendor_ver;
u8 spec_ver;
bool quirk_incorrect_hostver;
+ bool quirk_fixup_tuning;
unsigned int peripheral_clock;
const struct esdhc_clk_fixup *clk_fixup;
+ u32 div_ratio;
};
/**
@@ -580,6 +582,7 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
clock, host->max_clk / pre_div / div);
host->mmc->actual_clock = host->max_clk / pre_div / div;
+ esdhc->div_ratio = pre_div * div;
pre_div >>= 1;
div--;
@@ -712,9 +715,24 @@ static int esdhc_signal_voltage_switch(struct mmc_host *mmc,
}
}
+static struct soc_device_attribute soc_fixup_tuning[] = {
+ { .family = "QorIQ T1040", .revision = "1.0", },
+ { .family = "QorIQ T2080", .revision = "1.0", },
+ { .family = "QorIQ T1023", .revision = "1.0", },
+ { .family = "QorIQ LS1021A", .revision = "1.0", },
+ { .family = "QorIQ LS1080A", .revision = "1.0", },
+ { .family = "QorIQ LS2080A", .revision = "1.0", },
+ { .family = "QorIQ LS1012A", .revision = "1.0", },
+ { .family = "QorIQ LS1043A", .revision = "1.*", },
+ { .family = "QorIQ LS1046A", .revision = "1.0", },
+ { },
+};
+
static int esdhc_execute_tuning(struct mmc_host *mmc, u32 opcode)
{
struct sdhci_host *host = mmc_priv(mmc);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
u32 val;
/* Use tuning block for tuning procedure */
@@ -728,7 +746,26 @@ static int esdhc_execute_tuning(struct mmc_host *mmc, u32 opcode)
sdhci_writel(host, val, ESDHC_TBCTL);
esdhc_clock_enable(host, true);
- return sdhci_execute_tuning(mmc, opcode);
+ sdhci_execute_tuning(mmc, opcode);
+ if (host->tuning_err == -EAGAIN && esdhc->quirk_fixup_tuning) {
+
+ /* program TBPTR[TB_WNDW_END_PTR] = 3*DIV_RATIO and
+ * program TBPTR[TB_WNDW_START_PTR] = 5*DIV_RATIO
+ */
+ val = sdhci_readl(host, ESDHC_TBPTR);
+ val = (val & ~((0x7f << 8) | 0x7f)) |
+ (3 * esdhc->div_ratio) | ((5 * esdhc->div_ratio) << 8);
+ sdhci_writel(host, val, ESDHC_TBPTR);
+
+ /* program the software tuning mode by setting
+ * TBCTL[TB_MODE]=2'h3
+ */
+ val = sdhci_readl(host, ESDHC_TBCTL);
+ val |= 0x3;
+ sdhci_writel(host, val, ESDHC_TBCTL);
+ sdhci_execute_tuning(mmc, opcode);
+ }
+ return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -903,6 +940,11 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)
pltfm_host = sdhci_priv(host);
esdhc = sdhci_pltfm_priv(pltfm_host);
+ if (soc_device_match(soc_fixup_tuning))
+ esdhc->quirk_fixup_tuning = true;
+ else
+ esdhc->quirk_fixup_tuning = false;
+
if (esdhc->vendor_ver == VENDOR_V_22)
host->quirks2 |= SDHCI_QUIRK2_HOST_NO_CMD23;
diff --git a/drivers/mmc/host/sdhci-pci-o2micro.c b/drivers/mmc/host/sdhci-pci-o2micro.c
index 77e9bc4aaee9..cc3ffeffd7a2 100644
--- a/drivers/mmc/host/sdhci-pci-o2micro.c
+++ b/drivers/mmc/host/sdhci-pci-o2micro.c
@@ -490,6 +490,9 @@ int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip)
pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
break;
case PCI_DEVICE_ID_O2_SEABIRD0:
+ if (chip->pdev->revision == 0x01)
+ chip->quirks |= SDHCI_QUIRK_DELAY_AFTER_POWER;
+ /* fall through */
case PCI_DEVICE_ID_O2_SEABIRD1:
/* UnLock WP */
ret = pci_read_config_byte(chip->pdev,
diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
index 02bea6159d79..b231c9a3f888 100644
--- a/drivers/mmc/host/sdhci-pltfm.c
+++ b/drivers/mmc/host/sdhci-pltfm.c
@@ -30,6 +30,7 @@
#include <linux/err.h>
#include <linux/module.h>
+#include <linux/property.h>
#include <linux/of.h>
#ifdef CONFIG_PPC
#include <asm/machdep.h>
@@ -51,11 +52,10 @@ static const struct sdhci_ops sdhci_pltfm_ops = {
.set_uhs_signaling = sdhci_set_uhs_signaling,
};
-#ifdef CONFIG_OF
-static bool sdhci_of_wp_inverted(struct device_node *np)
+static bool sdhci_wp_inverted(struct device *dev)
{
- if (of_get_property(np, "sdhci,wp-inverted", NULL) ||
- of_get_property(np, "wp-inverted", NULL))
+ if (device_property_present(dev, "sdhci,wp-inverted") ||
+ device_property_present(dev, "wp-inverted"))
return true;
/* Old device trees don't have the wp-inverted property. */
@@ -66,52 +66,64 @@ static bool sdhci_of_wp_inverted(struct device_node *np)
#endif /* CONFIG_PPC */
}
-void sdhci_get_of_property(struct platform_device *pdev)
+#ifdef CONFIG_OF
+static void sdhci_get_compatibility(struct platform_device *pdev)
{
+ struct sdhci_host *host = platform_get_drvdata(pdev);
struct device_node *np = pdev->dev.of_node;
+
+ if (!np)
+ return;
+
+ if (of_device_is_compatible(np, "fsl,p2020-rev1-esdhc"))
+ host->quirks |= SDHCI_QUIRK_BROKEN_DMA;
+
+ if (of_device_is_compatible(np, "fsl,p2020-esdhc") ||
+ of_device_is_compatible(np, "fsl,p1010-esdhc") ||
+ of_device_is_compatible(np, "fsl,t4240-esdhc") ||
+ of_device_is_compatible(np, "fsl,mpc8536-esdhc"))
+ host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
+}
+#else
+void sdhci_get_compatibility(struct platform_device *pdev) {}
+#endif /* CONFIG_OF */
+
+void sdhci_get_property(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
u32 bus_width;
- if (of_get_property(np, "sdhci,auto-cmd12", NULL))
+ if (device_property_present(dev, "sdhci,auto-cmd12"))
host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
- if (of_get_property(np, "sdhci,1-bit-only", NULL) ||
- (of_property_read_u32(np, "bus-width", &bus_width) == 0 &&
+ if (device_property_present(dev, "sdhci,1-bit-only") ||
+ (device_property_read_u32(dev, "bus-width", &bus_width) == 0 &&
bus_width == 1))
host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA;
- if (sdhci_of_wp_inverted(np))
+ if (sdhci_wp_inverted(dev))
host->quirks |= SDHCI_QUIRK_INVERTED_WRITE_PROTECT;
- if (of_get_property(np, "broken-cd", NULL))
+ if (device_property_present(dev, "broken-cd"))
host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
- if (of_get_property(np, "no-1-8-v", NULL))
+ if (device_property_present(dev, "no-1-8-v"))
host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
- if (of_device_is_compatible(np, "fsl,p2020-rev1-esdhc"))
- host->quirks |= SDHCI_QUIRK_BROKEN_DMA;
-
- if (of_device_is_compatible(np, "fsl,p2020-esdhc") ||
- of_device_is_compatible(np, "fsl,p1010-esdhc") ||
- of_device_is_compatible(np, "fsl,t4240-esdhc") ||
- of_device_is_compatible(np, "fsl,mpc8536-esdhc"))
- host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
+ sdhci_get_compatibility(pdev);
- of_property_read_u32(np, "clock-frequency", &pltfm_host->clock);
+ device_property_read_u32(dev, "clock-frequency", &pltfm_host->clock);
- if (of_find_property(np, "keep-power-in-suspend", NULL))
+ if (device_property_present(dev, "keep-power-in-suspend"))
host->mmc->pm_caps |= MMC_PM_KEEP_POWER;
- if (of_property_read_bool(np, "wakeup-source") ||
- of_property_read_bool(np, "enable-sdio-wakeup")) /* legacy */
+ if (device_property_read_bool(dev, "wakeup-source") ||
+ device_property_read_bool(dev, "enable-sdio-wakeup")) /* legacy */
host->mmc->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
}
-#else
-void sdhci_get_of_property(struct platform_device *pdev) {}
-#endif /* CONFIG_OF */
-EXPORT_SYMBOL_GPL(sdhci_get_of_property);
+EXPORT_SYMBOL_GPL(sdhci_get_property);
struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
const struct sdhci_pltfm_data *pdata,
@@ -184,7 +196,7 @@ int sdhci_pltfm_register(struct platform_device *pdev,
if (IS_ERR(host))
return PTR_ERR(host);
- sdhci_get_of_property(pdev);
+ sdhci_get_property(pdev);
ret = sdhci_add_host(host);
if (ret)
diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h
index 1e91fb1c020e..6109987fc3b5 100644
--- a/drivers/mmc/host/sdhci-pltfm.h
+++ b/drivers/mmc/host/sdhci-pltfm.h
@@ -90,7 +90,12 @@ static inline void sdhci_be32bs_writeb(struct sdhci_host *host, u8 val, int reg)
}
#endif /* CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER */
-extern void sdhci_get_of_property(struct platform_device *pdev);
+void sdhci_get_property(struct platform_device *pdev);
+
+static inline void sdhci_get_of_property(struct platform_device *pdev)
+{
+ return sdhci_get_property(pdev);
+}
extern struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
const struct sdhci_pltfm_data *pdata,
diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c
index b8e96f392428..1783e29eae04 100644
--- a/drivers/mmc/host/sdhci-pxav3.c
+++ b/drivers/mmc/host/sdhci-pxav3.c
@@ -21,17 +21,14 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/io.h>
-#include <linux/gpio.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
-#include <linux/mmc/slot-gpio.h>
#include <linux/platform_data/pxa_sdhci.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
-#include <linux/of_gpio.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/mbus.h>
@@ -452,16 +449,6 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
host->mmc->caps2 |= pdata->host_caps2;
if (pdata->pm_caps)
host->mmc->pm_caps |= pdata->pm_caps;
-
- if (gpio_is_valid(pdata->ext_cd_gpio)) {
- ret = mmc_gpio_request_cd(host->mmc, pdata->ext_cd_gpio,
- 0);
- if (ret) {
- dev_err(mmc_dev(host->mmc),
- "failed to allocate card detect gpio\n");
- goto err_cd_req;
- }
- }
}
pm_runtime_get_noresume(&pdev->dev);
@@ -486,7 +473,6 @@ err_add_host:
pm_runtime_disable(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
err_of_parse:
-err_cd_req:
err_mbus_win:
clk_disable_unprepare(pxa->clk_io);
clk_disable_unprepare(pxa->clk_core);
diff --git a/drivers/mmc/host/sdhci-sirf.c b/drivers/mmc/host/sdhci-sirf.c
index 391d52b467ca..5eada6f87e60 100644
--- a/drivers/mmc/host/sdhci-sirf.c
+++ b/drivers/mmc/host/sdhci-sirf.c
@@ -11,7 +11,6 @@
#include <linux/mmc/host.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/mmc/slot-gpio.h>
#include "sdhci-pltfm.h"
@@ -19,10 +18,6 @@
#define SDHCI_SIRF_8BITBUS BIT(3)
#define SIRF_TUNING_COUNT 16384
-struct sdhci_sirf_priv {
- int gpio_cd;
-};
-
static void sdhci_sirf_set_bus_width(struct sdhci_host *host, int width)
{
u8 ctrl;
@@ -170,9 +165,7 @@ static int sdhci_sirf_probe(struct platform_device *pdev)
{
struct sdhci_host *host;
struct sdhci_pltfm_host *pltfm_host;
- struct sdhci_sirf_priv *priv;
struct clk *clk;
- int gpio_cd;
int ret;
clk = devm_clk_get(&pdev->dev, NULL);
@@ -181,19 +174,12 @@ static int sdhci_sirf_probe(struct platform_device *pdev)
return PTR_ERR(clk);
}
- if (pdev->dev.of_node)
- gpio_cd = of_get_named_gpio(pdev->dev.of_node, "cd-gpios", 0);
- else
- gpio_cd = -EINVAL;
-
- host = sdhci_pltfm_init(pdev, &sdhci_sirf_pdata, sizeof(struct sdhci_sirf_priv));
+ host = sdhci_pltfm_init(pdev, &sdhci_sirf_pdata, 0);
if (IS_ERR(host))
return PTR_ERR(host);
pltfm_host = sdhci_priv(host);
pltfm_host->clk = clk;
- priv = sdhci_pltfm_priv(pltfm_host);
- priv->gpio_cd = gpio_cd;
sdhci_get_of_property(pdev);
@@ -209,15 +195,11 @@ static int sdhci_sirf_probe(struct platform_device *pdev)
* We must request the IRQ after sdhci_add_host(), as the tasklet only
* gets setup in sdhci_add_host() and we oops.
*/
- if (gpio_is_valid(priv->gpio_cd)) {
- ret = mmc_gpio_request_cd(host->mmc, priv->gpio_cd, 0);
- if (ret) {
- dev_err(&pdev->dev, "card detect irq request failed: %d\n",
- ret);
- goto err_request_cd;
- }
+ ret = mmc_gpiod_request_cd(host->mmc, "cd", 0, false, 0, NULL);
+ if (ret == -EPROBE_DEFER)
+ goto err_request_cd;
+ if (!ret)
mmc_gpiod_request_cd_irq(host->mmc);
- }
return 0;
diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c
index 9247d51f2eed..916b5b09c3d1 100644
--- a/drivers/mmc/host/sdhci-spear.c
+++ b/drivers/mmc/host/sdhci-spear.c
@@ -15,13 +15,11 @@
#include <linux/clk.h>
#include <linux/delay.h>
-#include <linux/gpio.h>
#include <linux/highmem.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/slab.h>
@@ -32,7 +30,6 @@
struct spear_sdhci {
struct clk *clk;
- int card_int_gpio;
};
/* sdhci ops */
@@ -43,18 +40,6 @@ static const struct sdhci_ops sdhci_pltfm_ops = {
.set_uhs_signaling = sdhci_set_uhs_signaling,
};
-static void sdhci_probe_config_dt(struct device_node *np,
- struct spear_sdhci *host)
-{
- int cd_gpio;
-
- cd_gpio = of_get_named_gpio(np, "cd-gpios", 0);
- if (!gpio_is_valid(cd_gpio))
- cd_gpio = -1;
-
- host->card_int_gpio = cd_gpio;
-}
-
static int sdhci_probe(struct platform_device *pdev)
{
struct sdhci_host *host;
@@ -109,21 +94,13 @@ static int sdhci_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "Error setting desired clk, clk=%lu\n",
clk_get_rate(sdhci->clk));
- sdhci_probe_config_dt(pdev->dev.of_node, sdhci);
/*
- * It is optional to use GPIOs for sdhci card detection. If
- * sdhci->card_int_gpio < 0, then use original sdhci lines otherwise
- * GPIO lines. We use the built-in GPIO support for this.
+ * It is optional to use GPIOs for sdhci card detection. If we
+ * find a descriptor using slot GPIO, we use it.
*/
- if (sdhci->card_int_gpio >= 0) {
- ret = mmc_gpio_request_cd(host->mmc, sdhci->card_int_gpio, 0);
- if (ret < 0) {
- dev_dbg(&pdev->dev,
- "failed to request card-detect gpio%d\n",
- sdhci->card_int_gpio);
- goto disable_clk;
- }
- }
+ ret = mmc_gpiod_request_cd(host->mmc, "cd", 0, false, 0, NULL);
+ if (ret == -EPROBE_DEFER)
+ goto disable_clk;
ret = sdhci_add_host(host);
if (ret)
diff --git a/drivers/mmc/host/sdhci-sprd.c b/drivers/mmc/host/sdhci-sprd.c
new file mode 100644
index 000000000000..9a822e2e9f0b
--- /dev/null
+++ b/drivers/mmc/host/sdhci-sprd.c
@@ -0,0 +1,498 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Secure Digital Host Controller
+//
+// Copyright (C) 2018 Spreadtrum, Inc.
+// Author: Chunyan Zhang <chunyan.zhang@unisoc.com>
+
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/highmem.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+#include "sdhci-pltfm.h"
+
+/* SDHCI_ARGUMENT2 register high 16bit */
+#define SDHCI_SPRD_ARG2_STUFF GENMASK(31, 16)
+
+#define SDHCI_SPRD_REG_32_DLL_DLY_OFFSET 0x208
+#define SDHCIBSPRD_IT_WR_DLY_INV BIT(5)
+#define SDHCI_SPRD_BIT_CMD_DLY_INV BIT(13)
+#define SDHCI_SPRD_BIT_POSRD_DLY_INV BIT(21)
+#define SDHCI_SPRD_BIT_NEGRD_DLY_INV BIT(29)
+
+#define SDHCI_SPRD_REG_32_BUSY_POSI 0x250
+#define SDHCI_SPRD_BIT_OUTR_CLK_AUTO_EN BIT(25)
+#define SDHCI_SPRD_BIT_INNR_CLK_AUTO_EN BIT(24)
+
+#define SDHCI_SPRD_REG_DEBOUNCE 0x28C
+#define SDHCI_SPRD_BIT_DLL_BAK BIT(0)
+#define SDHCI_SPRD_BIT_DLL_VAL BIT(1)
+
+#define SDHCI_SPRD_INT_SIGNAL_MASK 0x1B7F410B
+
+/* SDHCI_HOST_CONTROL2 */
+#define SDHCI_SPRD_CTRL_HS200 0x0005
+#define SDHCI_SPRD_CTRL_HS400 0x0006
+
+/*
+ * According to the standard specification, BIT(3) of SDHCI_SOFTWARE_RESET is
+ * reserved, and only used on Spreadtrum's design, the hardware cannot work
+ * if this bit is cleared.
+ * 1 : normal work
+ * 0 : hardware reset
+ */
+#define SDHCI_HW_RESET_CARD BIT(3)
+
+#define SDHCI_SPRD_MAX_CUR 0xFFFFFF
+#define SDHCI_SPRD_CLK_MAX_DIV 1023
+
+#define SDHCI_SPRD_CLK_DEF_RATE 26000000
+
+struct sdhci_sprd_host {
+ u32 version;
+ struct clk *clk_sdio;
+ struct clk *clk_enable;
+ u32 base_rate;
+ int flags; /* backup of host attribute */
+};
+
+#define TO_SPRD_HOST(host) sdhci_pltfm_priv(sdhci_priv(host))
+
+static void sdhci_sprd_init_config(struct sdhci_host *host)
+{
+ u16 val;
+
+ /* set dll backup mode */
+ val = sdhci_readl(host, SDHCI_SPRD_REG_DEBOUNCE);
+ val |= SDHCI_SPRD_BIT_DLL_BAK | SDHCI_SPRD_BIT_DLL_VAL;
+ sdhci_writel(host, val, SDHCI_SPRD_REG_DEBOUNCE);
+}
+
+static inline u32 sdhci_sprd_readl(struct sdhci_host *host, int reg)
+{
+ if (unlikely(reg == SDHCI_MAX_CURRENT))
+ return SDHCI_SPRD_MAX_CUR;
+
+ return readl_relaxed(host->ioaddr + reg);
+}
+
+static inline void sdhci_sprd_writel(struct sdhci_host *host, u32 val, int reg)
+{
+ /* SDHCI_MAX_CURRENT is reserved on Spreadtrum's platform */
+ if (unlikely(reg == SDHCI_MAX_CURRENT))
+ return;
+
+ if (unlikely(reg == SDHCI_SIGNAL_ENABLE || reg == SDHCI_INT_ENABLE))
+ val = val & SDHCI_SPRD_INT_SIGNAL_MASK;
+
+ writel_relaxed(val, host->ioaddr + reg);
+}
+
+static inline void sdhci_sprd_writew(struct sdhci_host *host, u16 val, int reg)
+{
+ /* SDHCI_BLOCK_COUNT is Read Only on Spreadtrum's platform */
+ if (unlikely(reg == SDHCI_BLOCK_COUNT))
+ return;
+
+ writew_relaxed(val, host->ioaddr + reg);
+}
+
+static inline void sdhci_sprd_writeb(struct sdhci_host *host, u8 val, int reg)
+{
+ /*
+ * Since BIT(3) of SDHCI_SOFTWARE_RESET is reserved according to the
+ * standard specification, sdhci_reset() write this register directly
+ * without checking other reserved bits, that will clear BIT(3) which
+ * is defined as hardware reset on Spreadtrum's platform and clearing
+ * it by mistake will lead the card not work. So here we need to work
+ * around it.
+ */
+ if (unlikely(reg == SDHCI_SOFTWARE_RESET)) {
+ if (readb_relaxed(host->ioaddr + reg) & SDHCI_HW_RESET_CARD)
+ val |= SDHCI_HW_RESET_CARD;
+ }
+
+ writeb_relaxed(val, host->ioaddr + reg);
+}
+
+static inline void sdhci_sprd_sd_clk_off(struct sdhci_host *host)
+{
+ u16 ctrl = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+
+ ctrl &= ~SDHCI_CLOCK_CARD_EN;
+ sdhci_writew(host, ctrl, SDHCI_CLOCK_CONTROL);
+}
+
+static inline void
+sdhci_sprd_set_dll_invert(struct sdhci_host *host, u32 mask, bool en)
+{
+ u32 dll_dly_offset;
+
+ dll_dly_offset = sdhci_readl(host, SDHCI_SPRD_REG_32_DLL_DLY_OFFSET);
+ if (en)
+ dll_dly_offset |= mask;
+ else
+ dll_dly_offset &= ~mask;
+ sdhci_writel(host, dll_dly_offset, SDHCI_SPRD_REG_32_DLL_DLY_OFFSET);
+}
+
+static inline u32 sdhci_sprd_calc_div(u32 base_clk, u32 clk)
+{
+ u32 div;
+
+ /* select 2x clock source */
+ if (base_clk <= clk * 2)
+ return 0;
+
+ div = (u32) (base_clk / (clk * 2));
+
+ if ((base_clk / div) > (clk * 2))
+ div++;
+
+ if (div > SDHCI_SPRD_CLK_MAX_DIV)
+ div = SDHCI_SPRD_CLK_MAX_DIV;
+
+ if (div % 2)
+ div = (div + 1) / 2;
+ else
+ div = div / 2;
+
+ return div;
+}
+
+static inline void _sdhci_sprd_set_clock(struct sdhci_host *host,
+ unsigned int clk)
+{
+ struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);
+ u32 div, val, mask;
+
+ div = sdhci_sprd_calc_div(sprd_host->base_rate, clk);
+
+ clk |= ((div & 0x300) >> 2) | ((div & 0xFF) << 8);
+ sdhci_enable_clk(host, clk);
+
+ /* enable auto gate sdhc_enable_auto_gate */
+ val = sdhci_readl(host, SDHCI_SPRD_REG_32_BUSY_POSI);
+ mask = SDHCI_SPRD_BIT_OUTR_CLK_AUTO_EN |
+ SDHCI_SPRD_BIT_INNR_CLK_AUTO_EN;
+ if (mask != (val & mask)) {
+ val |= mask;
+ sdhci_writel(host, val, SDHCI_SPRD_REG_32_BUSY_POSI);
+ }
+}
+
+static void sdhci_sprd_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+ bool en = false;
+
+ if (clock == 0) {
+ sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
+ } else if (clock != host->clock) {
+ sdhci_sprd_sd_clk_off(host);
+ _sdhci_sprd_set_clock(host, clock);
+
+ if (clock <= 400000)
+ en = true;
+ sdhci_sprd_set_dll_invert(host, SDHCI_SPRD_BIT_CMD_DLY_INV |
+ SDHCI_SPRD_BIT_POSRD_DLY_INV, en);
+ } else {
+ _sdhci_sprd_set_clock(host, clock);
+ }
+}
+
+static unsigned int sdhci_sprd_get_max_clock(struct sdhci_host *host)
+{
+ struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);
+
+ return clk_round_rate(sprd_host->clk_sdio, ULONG_MAX);
+}
+
+static unsigned int sdhci_sprd_get_min_clock(struct sdhci_host *host)
+{
+ return 400000;
+}
+
+static void sdhci_sprd_set_uhs_signaling(struct sdhci_host *host,
+ unsigned int timing)
+{
+ u16 ctrl_2;
+
+ if (timing == host->timing)
+ return;
+
+ ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ /* Select Bus Speed Mode for host */
+ ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
+ switch (timing) {
+ case MMC_TIMING_UHS_SDR12:
+ ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
+ break;
+ case MMC_TIMING_MMC_HS:
+ case MMC_TIMING_SD_HS:
+ case MMC_TIMING_UHS_SDR25:
+ ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
+ break;
+ case MMC_TIMING_UHS_SDR50:
+ ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
+ break;
+ case MMC_TIMING_UHS_SDR104:
+ ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
+ break;
+ case MMC_TIMING_UHS_DDR50:
+ case MMC_TIMING_MMC_DDR52:
+ ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
+ break;
+ case MMC_TIMING_MMC_HS200:
+ ctrl_2 |= SDHCI_SPRD_CTRL_HS200;
+ break;
+ case MMC_TIMING_MMC_HS400:
+ ctrl_2 |= SDHCI_SPRD_CTRL_HS400;
+ break;
+ default:
+ break;
+ }
+
+ sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+}
+
+static void sdhci_sprd_hw_reset(struct sdhci_host *host)
+{
+ int val;
+
+ /*
+ * Note: don't use sdhci_writeb() API here since it is redirected to
+ * sdhci_sprd_writeb() in which we have a workaround for
+ * SDHCI_SOFTWARE_RESET which would make bit SDHCI_HW_RESET_CARD can
+ * not be cleared.
+ */
+ val = readb_relaxed(host->ioaddr + SDHCI_SOFTWARE_RESET);
+ val &= ~SDHCI_HW_RESET_CARD;
+ writeb_relaxed(val, host->ioaddr + SDHCI_SOFTWARE_RESET);
+ /* wait for 10 us */
+ usleep_range(10, 20);
+
+ val |= SDHCI_HW_RESET_CARD;
+ writeb_relaxed(val, host->ioaddr + SDHCI_SOFTWARE_RESET);
+ usleep_range(300, 500);
+}
+
+static struct sdhci_ops sdhci_sprd_ops = {
+ .read_l = sdhci_sprd_readl,
+ .write_l = sdhci_sprd_writel,
+ .write_b = sdhci_sprd_writeb,
+ .set_clock = sdhci_sprd_set_clock,
+ .get_max_clock = sdhci_sprd_get_max_clock,
+ .get_min_clock = sdhci_sprd_get_min_clock,
+ .set_bus_width = sdhci_set_bus_width,
+ .reset = sdhci_reset,
+ .set_uhs_signaling = sdhci_sprd_set_uhs_signaling,
+ .hw_reset = sdhci_sprd_hw_reset,
+};
+
+static void sdhci_sprd_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);
+
+ host->flags |= sprd_host->flags & SDHCI_AUTO_CMD23;
+
+ /*
+ * From version 4.10 onward, ARGUMENT2 register is also as 32-bit
+ * block count register which doesn't support stuff bits of
+ * CMD23 argument on Spreadtrum's sd host controller.
+ */
+ if (host->version >= SDHCI_SPEC_410 &&
+ mrq->sbc && (mrq->sbc->arg & SDHCI_SPRD_ARG2_STUFF) &&
+ (host->flags & SDHCI_AUTO_CMD23))
+ host->flags &= ~SDHCI_AUTO_CMD23;
+
+ sdhci_request(mmc, mrq);
+}
+
+static const struct sdhci_pltfm_data sdhci_sprd_pdata = {
+ .quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK,
+ .quirks2 = SDHCI_QUIRK2_BROKEN_HS200 |
+ SDHCI_QUIRK2_USE_32BIT_BLK_CNT,
+ .ops = &sdhci_sprd_ops,
+};
+
+static int sdhci_sprd_probe(struct platform_device *pdev)
+{
+ struct sdhci_host *host;
+ struct sdhci_sprd_host *sprd_host;
+ struct clk *clk;
+ int ret = 0;
+
+ host = sdhci_pltfm_init(pdev, &sdhci_sprd_pdata, sizeof(*sprd_host));
+ if (IS_ERR(host))
+ return PTR_ERR(host);
+
+ host->dma_mask = DMA_BIT_MASK(64);
+ pdev->dev.dma_mask = &host->dma_mask;
+ host->mmc_host_ops.request = sdhci_sprd_request;
+
+ host->mmc->caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED |
+ MMC_CAP_ERASE | MMC_CAP_CMD23;
+ ret = mmc_of_parse(host->mmc);
+ if (ret)
+ goto pltfm_free;
+
+ sprd_host = TO_SPRD_HOST(host);
+
+ clk = devm_clk_get(&pdev->dev, "sdio");
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ goto pltfm_free;
+ }
+ sprd_host->clk_sdio = clk;
+ sprd_host->base_rate = clk_get_rate(sprd_host->clk_sdio);
+ if (!sprd_host->base_rate)
+ sprd_host->base_rate = SDHCI_SPRD_CLK_DEF_RATE;
+
+ clk = devm_clk_get(&pdev->dev, "enable");
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ goto pltfm_free;
+ }
+ sprd_host->clk_enable = clk;
+
+ ret = clk_prepare_enable(sprd_host->clk_sdio);
+ if (ret)
+ goto pltfm_free;
+
+ clk_prepare_enable(sprd_host->clk_enable);
+ if (ret)
+ goto clk_disable;
+
+ sdhci_sprd_init_config(host);
+ host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
+ sprd_host->version = ((host->version & SDHCI_VENDOR_VER_MASK) >>
+ SDHCI_VENDOR_VER_SHIFT);
+
+ pm_runtime_get_noresume(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_suspend_ignore_children(&pdev->dev, 1);
+
+ sdhci_enable_v4_mode(host);
+
+ ret = sdhci_setup_host(host);
+ if (ret)
+ goto pm_runtime_disable;
+
+ sprd_host->flags = host->flags;
+
+ ret = __sdhci_add_host(host);
+ if (ret)
+ goto err_cleanup_host;
+
+ pm_runtime_mark_last_busy(&pdev->dev);
+ pm_runtime_put_autosuspend(&pdev->dev);
+
+ return 0;
+
+err_cleanup_host:
+ sdhci_cleanup_host(host);
+
+pm_runtime_disable:
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
+
+ clk_disable_unprepare(sprd_host->clk_enable);
+
+clk_disable:
+ clk_disable_unprepare(sprd_host->clk_sdio);
+
+pltfm_free:
+ sdhci_pltfm_free(pdev);
+ return ret;
+}
+
+static int sdhci_sprd_remove(struct platform_device *pdev)
+{
+ struct sdhci_host *host = platform_get_drvdata(pdev);
+ struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);
+ struct mmc_host *mmc = host->mmc;
+
+ mmc_remove_host(mmc);
+ clk_disable_unprepare(sprd_host->clk_sdio);
+ clk_disable_unprepare(sprd_host->clk_enable);
+
+ mmc_free_host(mmc);
+
+ return 0;
+}
+
+static const struct of_device_id sdhci_sprd_of_match[] = {
+ { .compatible = "sprd,sdhci-r11", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, sdhci_sprd_of_match);
+
+#ifdef CONFIG_PM
+static int sdhci_sprd_runtime_suspend(struct device *dev)
+{
+ struct sdhci_host *host = dev_get_drvdata(dev);
+ struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);
+
+ sdhci_runtime_suspend_host(host);
+
+ clk_disable_unprepare(sprd_host->clk_sdio);
+ clk_disable_unprepare(sprd_host->clk_enable);
+
+ return 0;
+}
+
+static int sdhci_sprd_runtime_resume(struct device *dev)
+{
+ struct sdhci_host *host = dev_get_drvdata(dev);
+ struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);
+ int ret;
+
+ ret = clk_prepare_enable(sprd_host->clk_enable);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(sprd_host->clk_sdio);
+ if (ret) {
+ clk_disable_unprepare(sprd_host->clk_enable);
+ return ret;
+ }
+
+ sdhci_runtime_resume_host(host);
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops sdhci_sprd_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+ SET_RUNTIME_PM_OPS(sdhci_sprd_runtime_suspend,
+ sdhci_sprd_runtime_resume, NULL)
+};
+
+static struct platform_driver sdhci_sprd_driver = {
+ .probe = sdhci_sprd_probe,
+ .remove = sdhci_sprd_remove,
+ .driver = {
+ .name = "sdhci_sprd_r11",
+ .of_match_table = of_match_ptr(sdhci_sprd_of_match),
+ .pm = &sdhci_sprd_pm_ops,
+ },
+};
+module_platform_driver(sdhci_sprd_driver);
+
+MODULE_DESCRIPTION("Spreadtrum sdio host controller r11 driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:sdhci-sprd-r11");
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index 908b23e6a03c..7b95d088fdef 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -16,17 +16,21 @@
#include <linux/err.h>
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/iopoll.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/regulator/consumer.h>
#include <linux/reset.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/gpio/consumer.h>
+#include <linux/ktime.h>
#include "sdhci-pltfm.h"
@@ -34,40 +38,96 @@
#define SDHCI_TEGRA_VENDOR_CLOCK_CTRL 0x100
#define SDHCI_CLOCK_CTRL_TAP_MASK 0x00ff0000
#define SDHCI_CLOCK_CTRL_TAP_SHIFT 16
+#define SDHCI_CLOCK_CTRL_TRIM_MASK 0x1f000000
+#define SDHCI_CLOCK_CTRL_TRIM_SHIFT 24
#define SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE BIT(5)
#define SDHCI_CLOCK_CTRL_PADPIPE_CLKEN_OVERRIDE BIT(3)
#define SDHCI_CLOCK_CTRL_SPI_MODE_CLKEN_OVERRIDE BIT(2)
-#define SDHCI_TEGRA_VENDOR_MISC_CTRL 0x120
-#define SDHCI_MISC_CTRL_ENABLE_SDR104 0x8
-#define SDHCI_MISC_CTRL_ENABLE_SDR50 0x10
-#define SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300 0x20
-#define SDHCI_MISC_CTRL_ENABLE_DDR50 0x200
+#define SDHCI_TEGRA_VENDOR_SYS_SW_CTRL 0x104
+#define SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE BIT(31)
-#define SDHCI_TEGRA_AUTO_CAL_CONFIG 0x1e4
-#define SDHCI_AUTO_CAL_START BIT(31)
-#define SDHCI_AUTO_CAL_ENABLE BIT(29)
+#define SDHCI_TEGRA_VENDOR_CAP_OVERRIDES 0x10c
+#define SDHCI_TEGRA_CAP_OVERRIDES_DQS_TRIM_MASK 0x00003f00
+#define SDHCI_TEGRA_CAP_OVERRIDES_DQS_TRIM_SHIFT 8
-#define NVQUIRK_FORCE_SDHCI_SPEC_200 BIT(0)
-#define NVQUIRK_ENABLE_BLOCK_GAP_DET BIT(1)
-#define NVQUIRK_ENABLE_SDHCI_SPEC_300 BIT(2)
-#define NVQUIRK_ENABLE_SDR50 BIT(3)
-#define NVQUIRK_ENABLE_SDR104 BIT(4)
-#define NVQUIRK_ENABLE_DDR50 BIT(5)
-#define NVQUIRK_HAS_PADCALIB BIT(6)
+#define SDHCI_TEGRA_VENDOR_MISC_CTRL 0x120
+#define SDHCI_MISC_CTRL_ENABLE_SDR104 0x8
+#define SDHCI_MISC_CTRL_ENABLE_SDR50 0x10
+#define SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300 0x20
+#define SDHCI_MISC_CTRL_ENABLE_DDR50 0x200
+
+#define SDHCI_TEGRA_VENDOR_DLLCAL_CFG 0x1b0
+#define SDHCI_TEGRA_DLLCAL_CALIBRATE BIT(31)
+
+#define SDHCI_TEGRA_VENDOR_DLLCAL_STA 0x1bc
+#define SDHCI_TEGRA_DLLCAL_STA_ACTIVE BIT(31)
+
+#define SDHCI_VNDR_TUN_CTRL0_0 0x1c0
+#define SDHCI_VNDR_TUN_CTRL0_TUN_HW_TAP 0x20000
+
+#define SDHCI_TEGRA_AUTO_CAL_CONFIG 0x1e4
+#define SDHCI_AUTO_CAL_START BIT(31)
+#define SDHCI_AUTO_CAL_ENABLE BIT(29)
+#define SDHCI_AUTO_CAL_PDPU_OFFSET_MASK 0x0000ffff
+
+#define SDHCI_TEGRA_SDMEM_COMP_PADCTRL 0x1e0
+#define SDHCI_TEGRA_SDMEM_COMP_PADCTRL_VREF_SEL_MASK 0x0000000f
+#define SDHCI_TEGRA_SDMEM_COMP_PADCTRL_VREF_SEL_VAL 0x7
+#define SDHCI_TEGRA_SDMEM_COMP_PADCTRL_E_INPUT_E_PWRD BIT(31)
+
+#define SDHCI_TEGRA_AUTO_CAL_STATUS 0x1ec
+#define SDHCI_TEGRA_AUTO_CAL_ACTIVE BIT(31)
+
+#define NVQUIRK_FORCE_SDHCI_SPEC_200 BIT(0)
+#define NVQUIRK_ENABLE_BLOCK_GAP_DET BIT(1)
+#define NVQUIRK_ENABLE_SDHCI_SPEC_300 BIT(2)
+#define NVQUIRK_ENABLE_SDR50 BIT(3)
+#define NVQUIRK_ENABLE_SDR104 BIT(4)
+#define NVQUIRK_ENABLE_DDR50 BIT(5)
+#define NVQUIRK_HAS_PADCALIB BIT(6)
+#define NVQUIRK_NEEDS_PAD_CONTROL BIT(7)
+#define NVQUIRK_DIS_CARD_CLK_CONFIG_TAP BIT(8)
struct sdhci_tegra_soc_data {
const struct sdhci_pltfm_data *pdata;
u32 nvquirks;
};
+/* Magic pull up and pull down pad calibration offsets */
+struct sdhci_tegra_autocal_offsets {
+ u32 pull_up_3v3;
+ u32 pull_down_3v3;
+ u32 pull_up_3v3_timeout;
+ u32 pull_down_3v3_timeout;
+ u32 pull_up_1v8;
+ u32 pull_down_1v8;
+ u32 pull_up_1v8_timeout;
+ u32 pull_down_1v8_timeout;
+ u32 pull_up_sdr104;
+ u32 pull_down_sdr104;
+ u32 pull_up_hs400;
+ u32 pull_down_hs400;
+};
+
struct sdhci_tegra {
const struct sdhci_tegra_soc_data *soc_data;
struct gpio_desc *power_gpio;
bool ddr_signaling;
bool pad_calib_required;
+ bool pad_control_available;
struct reset_control *rst;
+ struct pinctrl *pinctrl_sdmmc;
+ struct pinctrl_state *pinctrl_state_3v3;
+ struct pinctrl_state *pinctrl_state_1v8;
+
+ struct sdhci_tegra_autocal_offsets autocal_offsets;
+ ktime_t last_calib;
+
+ u32 default_tap;
+ u32 default_trim;
+ u32 dqs_trim;
};
static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg)
@@ -133,23 +193,149 @@ static void tegra_sdhci_writel(struct sdhci_host *host, u32 val, int reg)
}
}
+static bool tegra_sdhci_configure_card_clk(struct sdhci_host *host, bool enable)
+{
+ bool status;
+ u32 reg;
+
+ reg = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+ status = !!(reg & SDHCI_CLOCK_CARD_EN);
+
+ if (status == enable)
+ return status;
+
+ if (enable)
+ reg |= SDHCI_CLOCK_CARD_EN;
+ else
+ reg &= ~SDHCI_CLOCK_CARD_EN;
+
+ sdhci_writew(host, reg, SDHCI_CLOCK_CONTROL);
+
+ return status;
+}
+
+static void tegra210_sdhci_writew(struct sdhci_host *host, u16 val, int reg)
+{
+ bool is_tuning_cmd = 0;
+ bool clk_enabled;
+ u8 cmd;
+
+ if (reg == SDHCI_COMMAND) {
+ cmd = SDHCI_GET_CMD(val);
+ is_tuning_cmd = cmd == MMC_SEND_TUNING_BLOCK ||
+ cmd == MMC_SEND_TUNING_BLOCK_HS200;
+ }
+
+ if (is_tuning_cmd)
+ clk_enabled = tegra_sdhci_configure_card_clk(host, 0);
+
+ writew(val, host->ioaddr + reg);
+
+ if (is_tuning_cmd) {
+ udelay(1);
+ tegra_sdhci_configure_card_clk(host, clk_enabled);
+ }
+}
+
static unsigned int tegra_sdhci_get_ro(struct sdhci_host *host)
{
return mmc_gpio_get_ro(host->mmc);
}
+static bool tegra_sdhci_is_pad_and_regulator_valid(struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host);
+ int has_1v8, has_3v3;
+
+ /*
+ * The SoCs which have NVQUIRK_NEEDS_PAD_CONTROL require software pad
+ * voltage configuration in order to perform voltage switching. This
+ * means that valid pinctrl info is required on SDHCI instances capable
+ * of performing voltage switching. Whether or not an SDHCI instance is
+ * capable of voltage switching is determined based on the regulator.
+ */
+
+ if (!(tegra_host->soc_data->nvquirks & NVQUIRK_NEEDS_PAD_CONTROL))
+ return true;
+
+ if (IS_ERR(host->mmc->supply.vqmmc))
+ return false;
+
+ has_1v8 = regulator_is_supported_voltage(host->mmc->supply.vqmmc,
+ 1700000, 1950000);
+
+ has_3v3 = regulator_is_supported_voltage(host->mmc->supply.vqmmc,
+ 2700000, 3600000);
+
+ if (has_1v8 == 1 && has_3v3 == 1)
+ return tegra_host->pad_control_available;
+
+ /* Fixed voltage, no pad control required. */
+ return true;
+}
+
+static void tegra_sdhci_set_tap(struct sdhci_host *host, unsigned int tap)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host);
+ const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data;
+ bool card_clk_enabled = false;
+ u32 reg;
+
+ /*
+ * Touching the tap values is a bit tricky on some SoC generations.
+ * The quirk enables a workaround for a glitch that sometimes occurs if
+ * the tap values are changed.
+ */
+
+ if (soc_data->nvquirks & NVQUIRK_DIS_CARD_CLK_CONFIG_TAP)
+ card_clk_enabled = tegra_sdhci_configure_card_clk(host, false);
+
+ reg = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CLOCK_CTRL);
+ reg &= ~SDHCI_CLOCK_CTRL_TAP_MASK;
+ reg |= tap << SDHCI_CLOCK_CTRL_TAP_SHIFT;
+ sdhci_writel(host, reg, SDHCI_TEGRA_VENDOR_CLOCK_CTRL);
+
+ if (soc_data->nvquirks & NVQUIRK_DIS_CARD_CLK_CONFIG_TAP &&
+ card_clk_enabled) {
+ udelay(1);
+ sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+ tegra_sdhci_configure_card_clk(host, card_clk_enabled);
+ }
+}
+
+static void tegra_sdhci_hs400_enhanced_strobe(struct mmc_host *mmc,
+ struct mmc_ios *ios)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ u32 val;
+
+ val = sdhci_readl(host, SDHCI_TEGRA_VENDOR_SYS_SW_CTRL);
+
+ if (ios->enhanced_strobe)
+ val |= SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE;
+ else
+ val &= ~SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE;
+
+ sdhci_writel(host, val, SDHCI_TEGRA_VENDOR_SYS_SW_CTRL);
+
+}
+
static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host);
const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data;
- u32 misc_ctrl, clk_ctrl;
+ u32 misc_ctrl, clk_ctrl, pad_ctrl;
sdhci_reset(host, mask);
if (!(mask & SDHCI_RESET_ALL))
return;
+ tegra_sdhci_set_tap(host, tegra_host->default_tap);
+
misc_ctrl = sdhci_readl(host, SDHCI_TEGRA_VENDOR_MISC_CTRL);
clk_ctrl = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CLOCK_CTRL);
@@ -158,15 +344,10 @@ static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask)
SDHCI_MISC_CTRL_ENABLE_DDR50 |
SDHCI_MISC_CTRL_ENABLE_SDR104);
- clk_ctrl &= ~SDHCI_CLOCK_CTRL_SPI_MODE_CLKEN_OVERRIDE;
+ clk_ctrl &= ~(SDHCI_CLOCK_CTRL_TRIM_MASK |
+ SDHCI_CLOCK_CTRL_SPI_MODE_CLKEN_OVERRIDE);
- /*
- * If the board does not define a regulator for the SDHCI
- * IO voltage, then don't advertise support for UHS modes
- * even if the device supports it because the IO voltage
- * cannot be configured.
- */
- if (!IS_ERR(host->mmc->supply.vqmmc)) {
+ if (tegra_sdhci_is_pad_and_regulator_valid(host)) {
/* Erratum: Enable SDHCI spec v3.00 support */
if (soc_data->nvquirks & NVQUIRK_ENABLE_SDHCI_SPEC_300)
misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300;
@@ -181,24 +362,237 @@ static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask)
clk_ctrl |= SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE;
}
+ clk_ctrl |= tegra_host->default_trim << SDHCI_CLOCK_CTRL_TRIM_SHIFT;
+
sdhci_writel(host, misc_ctrl, SDHCI_TEGRA_VENDOR_MISC_CTRL);
sdhci_writel(host, clk_ctrl, SDHCI_TEGRA_VENDOR_CLOCK_CTRL);
- if (soc_data->nvquirks & NVQUIRK_HAS_PADCALIB)
+ if (soc_data->nvquirks & NVQUIRK_HAS_PADCALIB) {
+ pad_ctrl = sdhci_readl(host, SDHCI_TEGRA_SDMEM_COMP_PADCTRL);
+ pad_ctrl &= ~SDHCI_TEGRA_SDMEM_COMP_PADCTRL_VREF_SEL_MASK;
+ pad_ctrl |= SDHCI_TEGRA_SDMEM_COMP_PADCTRL_VREF_SEL_VAL;
+ sdhci_writel(host, pad_ctrl, SDHCI_TEGRA_SDMEM_COMP_PADCTRL);
+
tegra_host->pad_calib_required = true;
+ }
tegra_host->ddr_signaling = false;
}
-static void tegra_sdhci_pad_autocalib(struct sdhci_host *host)
+static void tegra_sdhci_configure_cal_pad(struct sdhci_host *host, bool enable)
{
u32 val;
- mdelay(1);
+ /*
+ * Enable or disable the additional I/O pad used by the drive strength
+ * calibration process.
+ */
+ val = sdhci_readl(host, SDHCI_TEGRA_SDMEM_COMP_PADCTRL);
+
+ if (enable)
+ val |= SDHCI_TEGRA_SDMEM_COMP_PADCTRL_E_INPUT_E_PWRD;
+ else
+ val &= ~SDHCI_TEGRA_SDMEM_COMP_PADCTRL_E_INPUT_E_PWRD;
+
+ sdhci_writel(host, val, SDHCI_TEGRA_SDMEM_COMP_PADCTRL);
+
+ if (enable)
+ usleep_range(1, 2);
+}
+
+static void tegra_sdhci_set_pad_autocal_offset(struct sdhci_host *host,
+ u16 pdpu)
+{
+ u32 reg;
+
+ reg = sdhci_readl(host, SDHCI_TEGRA_AUTO_CAL_CONFIG);
+ reg &= ~SDHCI_AUTO_CAL_PDPU_OFFSET_MASK;
+ reg |= pdpu;
+ sdhci_writel(host, reg, SDHCI_TEGRA_AUTO_CAL_CONFIG);
+}
+
+static void tegra_sdhci_pad_autocalib(struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host);
+ struct sdhci_tegra_autocal_offsets offsets =
+ tegra_host->autocal_offsets;
+ struct mmc_ios *ios = &host->mmc->ios;
+ bool card_clk_enabled;
+ u16 pdpu;
+ u32 reg;
+ int ret;
+
+ switch (ios->timing) {
+ case MMC_TIMING_UHS_SDR104:
+ pdpu = offsets.pull_down_sdr104 << 8 | offsets.pull_up_sdr104;
+ break;
+ case MMC_TIMING_MMC_HS400:
+ pdpu = offsets.pull_down_hs400 << 8 | offsets.pull_up_hs400;
+ break;
+ default:
+ if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180)
+ pdpu = offsets.pull_down_1v8 << 8 | offsets.pull_up_1v8;
+ else
+ pdpu = offsets.pull_down_3v3 << 8 | offsets.pull_up_3v3;
+ }
+
+ tegra_sdhci_set_pad_autocal_offset(host, pdpu);
+
+ card_clk_enabled = tegra_sdhci_configure_card_clk(host, false);
+
+ tegra_sdhci_configure_cal_pad(host, true);
+
+ reg = sdhci_readl(host, SDHCI_TEGRA_AUTO_CAL_CONFIG);
+ reg |= SDHCI_AUTO_CAL_ENABLE | SDHCI_AUTO_CAL_START;
+ sdhci_writel(host, reg, SDHCI_TEGRA_AUTO_CAL_CONFIG);
+
+ usleep_range(1, 2);
+ /* 10 ms timeout */
+ ret = readl_poll_timeout(host->ioaddr + SDHCI_TEGRA_AUTO_CAL_STATUS,
+ reg, !(reg & SDHCI_TEGRA_AUTO_CAL_ACTIVE),
+ 1000, 10000);
+
+ tegra_sdhci_configure_cal_pad(host, false);
+
+ tegra_sdhci_configure_card_clk(host, card_clk_enabled);
+
+ if (ret) {
+ dev_err(mmc_dev(host->mmc), "Pad autocal timed out\n");
+
+ if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180)
+ pdpu = offsets.pull_down_1v8_timeout << 8 |
+ offsets.pull_up_1v8_timeout;
+ else
+ pdpu = offsets.pull_down_3v3_timeout << 8 |
+ offsets.pull_up_3v3_timeout;
+
+ /* Disable automatic calibration and use fixed offsets */
+ reg = sdhci_readl(host, SDHCI_TEGRA_AUTO_CAL_CONFIG);
+ reg &= ~SDHCI_AUTO_CAL_ENABLE;
+ sdhci_writel(host, reg, SDHCI_TEGRA_AUTO_CAL_CONFIG);
- val = sdhci_readl(host, SDHCI_TEGRA_AUTO_CAL_CONFIG);
- val |= SDHCI_AUTO_CAL_ENABLE | SDHCI_AUTO_CAL_START;
- sdhci_writel(host,val, SDHCI_TEGRA_AUTO_CAL_CONFIG);
+ tegra_sdhci_set_pad_autocal_offset(host, pdpu);
+ }
+}
+
+static void tegra_sdhci_parse_pad_autocal_dt(struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host);
+ struct sdhci_tegra_autocal_offsets *autocal =
+ &tegra_host->autocal_offsets;
+ int err;
+
+ err = device_property_read_u32(host->mmc->parent,
+ "nvidia,pad-autocal-pull-up-offset-3v3",
+ &autocal->pull_up_3v3);
+ if (err)
+ autocal->pull_up_3v3 = 0;
+
+ err = device_property_read_u32(host->mmc->parent,
+ "nvidia,pad-autocal-pull-down-offset-3v3",
+ &autocal->pull_down_3v3);
+ if (err)
+ autocal->pull_down_3v3 = 0;
+
+ err = device_property_read_u32(host->mmc->parent,
+ "nvidia,pad-autocal-pull-up-offset-1v8",
+ &autocal->pull_up_1v8);
+ if (err)
+ autocal->pull_up_1v8 = 0;
+
+ err = device_property_read_u32(host->mmc->parent,
+ "nvidia,pad-autocal-pull-down-offset-1v8",
+ &autocal->pull_down_1v8);
+ if (err)
+ autocal->pull_down_1v8 = 0;
+
+ err = device_property_read_u32(host->mmc->parent,
+ "nvidia,pad-autocal-pull-up-offset-3v3-timeout",
+ &autocal->pull_up_3v3);
+ if (err)
+ autocal->pull_up_3v3_timeout = 0;
+
+ err = device_property_read_u32(host->mmc->parent,
+ "nvidia,pad-autocal-pull-down-offset-3v3-timeout",
+ &autocal->pull_down_3v3);
+ if (err)
+ autocal->pull_down_3v3_timeout = 0;
+
+ err = device_property_read_u32(host->mmc->parent,
+ "nvidia,pad-autocal-pull-up-offset-1v8-timeout",
+ &autocal->pull_up_1v8);
+ if (err)
+ autocal->pull_up_1v8_timeout = 0;
+
+ err = device_property_read_u32(host->mmc->parent,
+ "nvidia,pad-autocal-pull-down-offset-1v8-timeout",
+ &autocal->pull_down_1v8);
+ if (err)
+ autocal->pull_down_1v8_timeout = 0;
+
+ err = device_property_read_u32(host->mmc->parent,
+ "nvidia,pad-autocal-pull-up-offset-sdr104",
+ &autocal->pull_up_sdr104);
+ if (err)
+ autocal->pull_up_sdr104 = autocal->pull_up_1v8;
+
+ err = device_property_read_u32(host->mmc->parent,
+ "nvidia,pad-autocal-pull-down-offset-sdr104",
+ &autocal->pull_down_sdr104);
+ if (err)
+ autocal->pull_down_sdr104 = autocal->pull_down_1v8;
+
+ err = device_property_read_u32(host->mmc->parent,
+ "nvidia,pad-autocal-pull-up-offset-hs400",
+ &autocal->pull_up_hs400);
+ if (err)
+ autocal->pull_up_hs400 = autocal->pull_up_1v8;
+
+ err = device_property_read_u32(host->mmc->parent,
+ "nvidia,pad-autocal-pull-down-offset-hs400",
+ &autocal->pull_down_hs400);
+ if (err)
+ autocal->pull_down_hs400 = autocal->pull_down_1v8;
+}
+
+static void tegra_sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host);
+ ktime_t since_calib = ktime_sub(ktime_get(), tegra_host->last_calib);
+
+ /* 100 ms calibration interval is specified in the TRM */
+ if (ktime_to_ms(since_calib) > 100) {
+ tegra_sdhci_pad_autocalib(host);
+ tegra_host->last_calib = ktime_get();
+ }
+
+ sdhci_request(mmc, mrq);
+}
+
+static void tegra_sdhci_parse_tap_and_trim(struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host);
+ int err;
+
+ err = device_property_read_u32(host->mmc->parent, "nvidia,default-tap",
+ &tegra_host->default_tap);
+ if (err)
+ tegra_host->default_tap = 0;
+
+ err = device_property_read_u32(host->mmc->parent, "nvidia,default-trim",
+ &tegra_host->default_trim);
+ if (err)
+ tegra_host->default_trim = 0;
+
+ err = device_property_read_u32(host->mmc->parent, "nvidia,dqs-trim",
+ &tegra_host->dqs_trim);
+ if (err)
+ tegra_host->dqs_trim = 0x11;
}
static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
@@ -237,34 +631,82 @@ static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
}
}
-static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host,
- unsigned timing)
+static unsigned int tegra_sdhci_get_max_clock(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host);
- if (timing == MMC_TIMING_UHS_DDR50 ||
- timing == MMC_TIMING_MMC_DDR52)
- tegra_host->ddr_signaling = true;
-
- sdhci_set_uhs_signaling(host, timing);
+ return clk_round_rate(pltfm_host->clk, UINT_MAX);
}
-static unsigned int tegra_sdhci_get_max_clock(struct sdhci_host *host)
+static void tegra_sdhci_set_dqs_trim(struct sdhci_host *host, u8 trim)
{
- struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ u32 val;
- return clk_round_rate(pltfm_host->clk, UINT_MAX);
+ val = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CAP_OVERRIDES);
+ val &= ~SDHCI_TEGRA_CAP_OVERRIDES_DQS_TRIM_MASK;
+ val |= trim << SDHCI_TEGRA_CAP_OVERRIDES_DQS_TRIM_SHIFT;
+ sdhci_writel(host, val, SDHCI_TEGRA_VENDOR_CAP_OVERRIDES);
}
-static void tegra_sdhci_set_tap(struct sdhci_host *host, unsigned int tap)
+static void tegra_sdhci_hs400_dll_cal(struct sdhci_host *host)
{
u32 reg;
+ int err;
+
+ reg = sdhci_readl(host, SDHCI_TEGRA_VENDOR_DLLCAL_CFG);
+ reg |= SDHCI_TEGRA_DLLCAL_CALIBRATE;
+ sdhci_writel(host, reg, SDHCI_TEGRA_VENDOR_DLLCAL_CFG);
+
+ /* 1 ms sleep, 5 ms timeout */
+ err = readl_poll_timeout(host->ioaddr + SDHCI_TEGRA_VENDOR_DLLCAL_STA,
+ reg, !(reg & SDHCI_TEGRA_DLLCAL_STA_ACTIVE),
+ 1000, 5000);
+ if (err)
+ dev_err(mmc_dev(host->mmc),
+ "HS400 delay line calibration timed out\n");
+}
- reg = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CLOCK_CTRL);
- reg &= ~SDHCI_CLOCK_CTRL_TAP_MASK;
- reg |= tap << SDHCI_CLOCK_CTRL_TAP_SHIFT;
- sdhci_writel(host, reg, SDHCI_TEGRA_VENDOR_CLOCK_CTRL);
+static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host,
+ unsigned timing)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host);
+ bool set_default_tap = false;
+ bool set_dqs_trim = false;
+ bool do_hs400_dll_cal = false;
+
+ switch (timing) {
+ case MMC_TIMING_UHS_SDR50:
+ case MMC_TIMING_UHS_SDR104:
+ case MMC_TIMING_MMC_HS200:
+ /* Don't set default tap on tunable modes. */
+ break;
+ case MMC_TIMING_MMC_HS400:
+ set_dqs_trim = true;
+ do_hs400_dll_cal = true;
+ break;
+ case MMC_TIMING_MMC_DDR52:
+ case MMC_TIMING_UHS_DDR50:
+ tegra_host->ddr_signaling = true;
+ set_default_tap = true;
+ break;
+ default:
+ set_default_tap = true;
+ break;
+ }
+
+ sdhci_set_uhs_signaling(host, timing);
+
+ tegra_sdhci_pad_autocalib(host);
+
+ if (set_default_tap)
+ tegra_sdhci_set_tap(host, tegra_host->default_tap);
+
+ if (set_dqs_trim)
+ tegra_sdhci_set_dqs_trim(host, tegra_host->dqs_trim);
+
+ if (do_hs400_dll_cal)
+ tegra_sdhci_hs400_dll_cal(host);
}
static int tegra_sdhci_execute_tuning(struct sdhci_host *host, u32 opcode)
@@ -301,6 +743,89 @@ static int tegra_sdhci_execute_tuning(struct sdhci_host *host, u32 opcode)
return mmc_send_tuning(host->mmc, opcode, NULL);
}
+static int tegra_sdhci_set_padctrl(struct sdhci_host *host, int voltage)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host);
+ int ret;
+
+ if (!tegra_host->pad_control_available)
+ return 0;
+
+ if (voltage == MMC_SIGNAL_VOLTAGE_180) {
+ ret = pinctrl_select_state(tegra_host->pinctrl_sdmmc,
+ tegra_host->pinctrl_state_1v8);
+ if (ret < 0)
+ dev_err(mmc_dev(host->mmc),
+ "setting 1.8V failed, ret: %d\n", ret);
+ } else {
+ ret = pinctrl_select_state(tegra_host->pinctrl_sdmmc,
+ tegra_host->pinctrl_state_3v3);
+ if (ret < 0)
+ dev_err(mmc_dev(host->mmc),
+ "setting 3.3V failed, ret: %d\n", ret);
+ }
+
+ return ret;
+}
+
+static int sdhci_tegra_start_signal_voltage_switch(struct mmc_host *mmc,
+ struct mmc_ios *ios)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host);
+ int ret = 0;
+
+ if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
+ ret = tegra_sdhci_set_padctrl(host, ios->signal_voltage);
+ if (ret < 0)
+ return ret;
+ ret = sdhci_start_signal_voltage_switch(mmc, ios);
+ } else if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) {
+ ret = sdhci_start_signal_voltage_switch(mmc, ios);
+ if (ret < 0)
+ return ret;
+ ret = tegra_sdhci_set_padctrl(host, ios->signal_voltage);
+ }
+
+ if (tegra_host->pad_calib_required)
+ tegra_sdhci_pad_autocalib(host);
+
+ return ret;
+}
+
+static int tegra_sdhci_init_pinctrl_info(struct device *dev,
+ struct sdhci_tegra *tegra_host)
+{
+ tegra_host->pinctrl_sdmmc = devm_pinctrl_get(dev);
+ if (IS_ERR(tegra_host->pinctrl_sdmmc)) {
+ dev_dbg(dev, "No pinctrl info, err: %ld\n",
+ PTR_ERR(tegra_host->pinctrl_sdmmc));
+ return -1;
+ }
+
+ tegra_host->pinctrl_state_3v3 =
+ pinctrl_lookup_state(tegra_host->pinctrl_sdmmc, "sdmmc-3v3");
+ if (IS_ERR(tegra_host->pinctrl_state_3v3)) {
+ dev_warn(dev, "Missing 3.3V pad state, err: %ld\n",
+ PTR_ERR(tegra_host->pinctrl_state_3v3));
+ return -1;
+ }
+
+ tegra_host->pinctrl_state_1v8 =
+ pinctrl_lookup_state(tegra_host->pinctrl_sdmmc, "sdmmc-1v8");
+ if (IS_ERR(tegra_host->pinctrl_state_1v8)) {
+ dev_warn(dev, "Missing 1.8V pad state, err: %ld\n",
+ PTR_ERR(tegra_host->pinctrl_state_1v8));
+ return -1;
+ }
+
+ tegra_host->pad_control_available = true;
+
+ return 0;
+}
+
static void tegra_sdhci_voltage_switch(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -421,6 +946,19 @@ static const struct sdhci_tegra_soc_data soc_data_tegra124 = {
.pdata = &sdhci_tegra124_pdata,
};
+static const struct sdhci_ops tegra210_sdhci_ops = {
+ .get_ro = tegra_sdhci_get_ro,
+ .read_w = tegra_sdhci_readw,
+ .write_w = tegra210_sdhci_writew,
+ .write_l = tegra_sdhci_writel,
+ .set_clock = tegra_sdhci_set_clock,
+ .set_bus_width = sdhci_set_bus_width,
+ .reset = tegra_sdhci_reset,
+ .set_uhs_signaling = tegra_sdhci_set_uhs_signaling,
+ .voltage_switch = tegra_sdhci_voltage_switch,
+ .get_max_clock = tegra_sdhci_get_max_clock,
+};
+
static const struct sdhci_pltfm_data sdhci_tegra210_pdata = {
.quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
@@ -429,11 +967,28 @@ static const struct sdhci_pltfm_data sdhci_tegra210_pdata = {
SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
- .ops = &tegra114_sdhci_ops,
+ .ops = &tegra210_sdhci_ops,
};
static const struct sdhci_tegra_soc_data soc_data_tegra210 = {
.pdata = &sdhci_tegra210_pdata,
+ .nvquirks = NVQUIRK_NEEDS_PAD_CONTROL |
+ NVQUIRK_HAS_PADCALIB |
+ NVQUIRK_DIS_CARD_CLK_CONFIG_TAP |
+ NVQUIRK_ENABLE_SDR50 |
+ NVQUIRK_ENABLE_SDR104,
+};
+
+static const struct sdhci_ops tegra186_sdhci_ops = {
+ .get_ro = tegra_sdhci_get_ro,
+ .read_w = tegra_sdhci_readw,
+ .write_l = tegra_sdhci_writel,
+ .set_clock = tegra_sdhci_set_clock,
+ .set_bus_width = sdhci_set_bus_width,
+ .reset = tegra_sdhci_reset,
+ .set_uhs_signaling = tegra_sdhci_set_uhs_signaling,
+ .voltage_switch = tegra_sdhci_voltage_switch,
+ .get_max_clock = tegra_sdhci_get_max_clock,
};
static const struct sdhci_pltfm_data sdhci_tegra186_pdata = {
@@ -452,11 +1007,16 @@ static const struct sdhci_pltfm_data sdhci_tegra186_pdata = {
* But it is not supported as of now.
*/
SDHCI_QUIRK2_BROKEN_64_BIT_DMA,
- .ops = &tegra114_sdhci_ops,
+ .ops = &tegra186_sdhci_ops,
};
static const struct sdhci_tegra_soc_data soc_data_tegra186 = {
.pdata = &sdhci_tegra186_pdata,
+ .nvquirks = NVQUIRK_NEEDS_PAD_CONTROL |
+ NVQUIRK_HAS_PADCALIB |
+ NVQUIRK_DIS_CARD_CLK_CONFIG_TAP |
+ NVQUIRK_ENABLE_SDR50 |
+ NVQUIRK_ENABLE_SDR104,
};
static const struct of_device_id sdhci_tegra_dt_match[] = {
@@ -493,8 +1053,23 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
tegra_host = sdhci_pltfm_priv(pltfm_host);
tegra_host->ddr_signaling = false;
tegra_host->pad_calib_required = false;
+ tegra_host->pad_control_available = false;
tegra_host->soc_data = soc_data;
+ if (soc_data->nvquirks & NVQUIRK_NEEDS_PAD_CONTROL) {
+ rc = tegra_sdhci_init_pinctrl_info(&pdev->dev, tegra_host);
+ if (rc == 0)
+ host->mmc_host_ops.start_signal_voltage_switch =
+ sdhci_tegra_start_signal_voltage_switch;
+ }
+
+ /* Hook to periodically rerun pad calibration */
+ if (soc_data->nvquirks & NVQUIRK_HAS_PADCALIB)
+ host->mmc_host_ops.request = tegra_sdhci_request;
+
+ host->mmc_host_ops.hs400_enhanced_strobe =
+ tegra_sdhci_hs400_enhanced_strobe;
+
rc = mmc_of_parse(host->mmc);
if (rc)
goto err_parse_dt;
@@ -502,6 +1077,10 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
if (tegra_host->soc_data->nvquirks & NVQUIRK_ENABLE_DDR50)
host->mmc->caps |= MMC_CAP_1_8V_DDR;
+ tegra_sdhci_parse_pad_autocal_dt(host);
+
+ tegra_sdhci_parse_tap_and_trim(host);
+
tegra_host->power_gpio = devm_gpiod_get_optional(&pdev->dev, "power",
GPIOD_OUT_HIGH);
if (IS_ERR(tegra_host->power_gpio)) {
diff --git a/drivers/mmc/host/sdhci-xenon-phy.c b/drivers/mmc/host/sdhci-xenon-phy.c
index c335052d0c02..5956e90380e8 100644
--- a/drivers/mmc/host/sdhci-xenon-phy.c
+++ b/drivers/mmc/host/sdhci-xenon-phy.c
@@ -660,8 +660,8 @@ static int get_dt_pad_ctrl_data(struct sdhci_host *host,
return 0;
if (of_address_to_resource(np, 1, &iomem)) {
- dev_err(mmc_dev(host->mmc), "Unable to find SoC PAD ctrl register address for %s\n",
- np->name);
+ dev_err(mmc_dev(host->mmc), "Unable to find SoC PAD ctrl register address for %pOFn\n",
+ np);
return -EINVAL;
}
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 1b3fbd9bd5c5..99bdae53fa2e 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -123,6 +123,29 @@ EXPORT_SYMBOL_GPL(sdhci_dumpregs);
* *
\*****************************************************************************/
+static void sdhci_do_enable_v4_mode(struct sdhci_host *host)
+{
+ u16 ctrl2;
+
+ ctrl2 = sdhci_readb(host, SDHCI_HOST_CONTROL2);
+ if (ctrl2 & SDHCI_CTRL_V4_MODE)
+ return;
+
+ ctrl2 |= SDHCI_CTRL_V4_MODE;
+ sdhci_writeb(host, ctrl2, SDHCI_HOST_CONTROL);
+}
+
+/*
+ * This can be called before sdhci_add_host() by Vendor's host controller
+ * driver to enable v4 mode if supported.
+ */
+void sdhci_enable_v4_mode(struct sdhci_host *host)
+{
+ host->v4_mode = true;
+ sdhci_do_enable_v4_mode(host);
+}
+EXPORT_SYMBOL_GPL(sdhci_enable_v4_mode);
+
static inline bool sdhci_data_line_cmd(struct mmc_command *cmd)
{
return cmd->data || cmd->flags & MMC_RSP_BUSY;
@@ -243,6 +266,52 @@ static void sdhci_set_default_irqs(struct sdhci_host *host)
sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
}
+static void sdhci_config_dma(struct sdhci_host *host)
+{
+ u8 ctrl;
+ u16 ctrl2;
+
+ if (host->version < SDHCI_SPEC_200)
+ return;
+
+ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
+
+ /*
+ * Always adjust the DMA selection as some controllers
+ * (e.g. JMicron) can't do PIO properly when the selection
+ * is ADMA.
+ */
+ ctrl &= ~SDHCI_CTRL_DMA_MASK;
+ if (!(host->flags & SDHCI_REQ_USE_DMA))
+ goto out;
+
+ /* Note if DMA Select is zero then SDMA is selected */
+ if (host->flags & SDHCI_USE_ADMA)
+ ctrl |= SDHCI_CTRL_ADMA32;
+
+ if (host->flags & SDHCI_USE_64_BIT_DMA) {
+ /*
+ * If v4 mode, all supported DMA can be 64-bit addressing if
+ * controller supports 64-bit system address, otherwise only
+ * ADMA can support 64-bit addressing.
+ */
+ if (host->v4_mode) {
+ ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ ctrl2 |= SDHCI_CTRL_64BIT_ADDR;
+ sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2);
+ } else if (host->flags & SDHCI_USE_ADMA) {
+ /*
+ * Don't need to undo SDHCI_CTRL_ADMA32 in order to
+ * set SDHCI_CTRL_ADMA64.
+ */
+ ctrl |= SDHCI_CTRL_ADMA64;
+ }
+ }
+
+out:
+ sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+}
+
static void sdhci_init(struct sdhci_host *host, int soft)
{
struct mmc_host *mmc = host->mmc;
@@ -252,6 +321,9 @@ static void sdhci_init(struct sdhci_host *host, int soft)
else
sdhci_do_reset(host, SDHCI_RESET_ALL);
+ if (host->v4_mode)
+ sdhci_do_enable_v4_mode(host);
+
sdhci_set_default_irqs(host);
host->cqe_on = false;
@@ -554,10 +626,10 @@ static void sdhci_kunmap_atomic(void *buffer, unsigned long *flags)
local_irq_restore(*flags);
}
-static void sdhci_adma_write_desc(struct sdhci_host *host, void *desc,
- dma_addr_t addr, int len, unsigned cmd)
+void sdhci_adma_write_desc(struct sdhci_host *host, void **desc,
+ dma_addr_t addr, int len, unsigned int cmd)
{
- struct sdhci_adma2_64_desc *dma_desc = desc;
+ struct sdhci_adma2_64_desc *dma_desc = *desc;
/* 32-bit and 64-bit descriptors have these members in same position */
dma_desc->cmd = cpu_to_le16(cmd);
@@ -566,6 +638,19 @@ static void sdhci_adma_write_desc(struct sdhci_host *host, void *desc,
if (host->flags & SDHCI_USE_64_BIT_DMA)
dma_desc->addr_hi = cpu_to_le32((u64)addr >> 32);
+
+ *desc += host->desc_sz;
+}
+EXPORT_SYMBOL_GPL(sdhci_adma_write_desc);
+
+static inline void __sdhci_adma_write_desc(struct sdhci_host *host,
+ void **desc, dma_addr_t addr,
+ int len, unsigned int cmd)
+{
+ if (host->ops->adma_write_desc)
+ host->ops->adma_write_desc(host, desc, addr, len, cmd);
+ else
+ sdhci_adma_write_desc(host, desc, addr, len, cmd);
}
static void sdhci_adma_mark_end(void *desc)
@@ -618,28 +703,24 @@ static void sdhci_adma_table_pre(struct sdhci_host *host,
}
/* tran, valid */
- sdhci_adma_write_desc(host, desc, align_addr, offset,
- ADMA2_TRAN_VALID);
+ __sdhci_adma_write_desc(host, &desc, align_addr,
+ offset, ADMA2_TRAN_VALID);
BUG_ON(offset > 65536);
align += SDHCI_ADMA2_ALIGN;
align_addr += SDHCI_ADMA2_ALIGN;
- desc += host->desc_sz;
-
addr += offset;
len -= offset;
}
BUG_ON(len > 65536);
- if (len) {
- /* tran, valid */
- sdhci_adma_write_desc(host, desc, addr, len,
- ADMA2_TRAN_VALID);
- desc += host->desc_sz;
- }
+ /* tran, valid */
+ if (len)
+ __sdhci_adma_write_desc(host, &desc, addr, len,
+ ADMA2_TRAN_VALID);
/*
* If this triggers then we have a calculation bug
@@ -656,7 +737,7 @@ static void sdhci_adma_table_pre(struct sdhci_host *host,
}
} else {
/* Add a terminating entry - nop, end, valid */
- sdhci_adma_write_desc(host, desc, 0, 0, ADMA2_NOP_END_VALID);
+ __sdhci_adma_write_desc(host, &desc, 0, 0, ADMA2_NOP_END_VALID);
}
}
@@ -701,7 +782,7 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
}
}
-static u32 sdhci_sdma_address(struct sdhci_host *host)
+static dma_addr_t sdhci_sdma_address(struct sdhci_host *host)
{
if (host->bounce_buffer)
return host->bounce_addr;
@@ -709,6 +790,17 @@ static u32 sdhci_sdma_address(struct sdhci_host *host)
return sg_dma_address(host->data->sg);
}
+static void sdhci_set_sdma_addr(struct sdhci_host *host, dma_addr_t addr)
+{
+ if (host->v4_mode) {
+ sdhci_writel(host, addr, SDHCI_ADMA_ADDRESS);
+ if (host->flags & SDHCI_USE_64_BIT_DMA)
+ sdhci_writel(host, (u64)addr >> 32, SDHCI_ADMA_ADDRESS_HI);
+ } else {
+ sdhci_writel(host, addr, SDHCI_DMA_ADDRESS);
+ }
+}
+
static unsigned int sdhci_target_timeout(struct sdhci_host *host,
struct mmc_command *cmd,
struct mmc_data *data)
@@ -876,7 +968,6 @@ static void sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
{
- u8 ctrl;
struct mmc_data *data = cmd->data;
host->data_timeout = 0;
@@ -968,30 +1059,11 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
SDHCI_ADMA_ADDRESS_HI);
} else {
WARN_ON(sg_cnt != 1);
- sdhci_writel(host, sdhci_sdma_address(host),
- SDHCI_DMA_ADDRESS);
+ sdhci_set_sdma_addr(host, sdhci_sdma_address(host));
}
}
- /*
- * Always adjust the DMA selection as some controllers
- * (e.g. JMicron) can't do PIO properly when the selection
- * is ADMA.
- */
- if (host->version >= SDHCI_SPEC_200) {
- ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
- ctrl &= ~SDHCI_CTRL_DMA_MASK;
- if ((host->flags & SDHCI_REQ_USE_DMA) &&
- (host->flags & SDHCI_USE_ADMA)) {
- if (host->flags & SDHCI_USE_64_BIT_DMA)
- ctrl |= SDHCI_CTRL_ADMA64;
- else
- ctrl |= SDHCI_CTRL_ADMA32;
- } else {
- ctrl |= SDHCI_CTRL_SDMA;
- }
- sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
- }
+ sdhci_config_dma(host);
if (!(host->flags & SDHCI_REQ_USE_DMA)) {
int flags;
@@ -1010,7 +1082,19 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
/* Set the DMA boundary value and block size */
sdhci_writew(host, SDHCI_MAKE_BLKSZ(host->sdma_boundary, data->blksz),
SDHCI_BLOCK_SIZE);
- sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT);
+
+ /*
+ * For Version 4.10 onwards, if v4 mode is enabled, 32-bit Block Count
+ * can be supported, in that case 16-bit block count register must be 0.
+ */
+ if (host->version >= SDHCI_SPEC_410 && host->v4_mode &&
+ (host->quirks2 & SDHCI_QUIRK2_USE_32BIT_BLK_CNT)) {
+ if (sdhci_readw(host, SDHCI_BLOCK_COUNT))
+ sdhci_writew(host, 0, SDHCI_BLOCK_COUNT);
+ sdhci_writew(host, data->blocks, SDHCI_32BIT_BLK_CNT);
+ } else {
+ sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT);
+ }
}
static inline bool sdhci_auto_cmd12(struct sdhci_host *host,
@@ -1020,6 +1104,43 @@ static inline bool sdhci_auto_cmd12(struct sdhci_host *host,
!mrq->cap_cmd_during_tfr;
}
+static inline void sdhci_auto_cmd_select(struct sdhci_host *host,
+ struct mmc_command *cmd,
+ u16 *mode)
+{
+ bool use_cmd12 = sdhci_auto_cmd12(host, cmd->mrq) &&
+ (cmd->opcode != SD_IO_RW_EXTENDED);
+ bool use_cmd23 = cmd->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23);
+ u16 ctrl2;
+
+ /*
+ * In case of Version 4.10 or later, use of 'Auto CMD Auto
+ * Select' is recommended rather than use of 'Auto CMD12
+ * Enable' or 'Auto CMD23 Enable'.
+ */
+ if (host->version >= SDHCI_SPEC_410 && (use_cmd12 || use_cmd23)) {
+ *mode |= SDHCI_TRNS_AUTO_SEL;
+
+ ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ if (use_cmd23)
+ ctrl2 |= SDHCI_CMD23_ENABLE;
+ else
+ ctrl2 &= ~SDHCI_CMD23_ENABLE;
+ sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2);
+
+ return;
+ }
+
+ /*
+ * If we are sending CMD23, CMD12 never gets sent
+ * on successful completion (so no Auto-CMD12).
+ */
+ if (use_cmd12)
+ *mode |= SDHCI_TRNS_AUTO_CMD12;
+ else if (use_cmd23)
+ *mode |= SDHCI_TRNS_AUTO_CMD23;
+}
+
static void sdhci_set_transfer_mode(struct sdhci_host *host,
struct mmc_command *cmd)
{
@@ -1048,17 +1169,9 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
if (mmc_op_multi(cmd->opcode) || data->blocks > 1) {
mode = SDHCI_TRNS_BLK_CNT_EN | SDHCI_TRNS_MULTI;
- /*
- * If we are sending CMD23, CMD12 never gets sent
- * on successful completion (so no Auto-CMD12).
- */
- if (sdhci_auto_cmd12(host, cmd->mrq) &&
- (cmd->opcode != SD_IO_RW_EXTENDED))
- mode |= SDHCI_TRNS_AUTO_CMD12;
- else if (cmd->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) {
- mode |= SDHCI_TRNS_AUTO_CMD23;
+ sdhci_auto_cmd_select(host, cmd, &mode);
+ if (cmd->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23))
sdhci_writel(host, cmd->mrq->sbc->arg, SDHCI_ARGUMENT2);
- }
}
if (data->flags & MMC_DATA_READ)
@@ -1630,7 +1743,7 @@ EXPORT_SYMBOL_GPL(sdhci_set_power);
* *
\*****************************************************************************/
-static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct sdhci_host *host;
int present;
@@ -1669,6 +1782,7 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
mmiowb();
spin_unlock_irqrestore(&host->lock, flags);
}
+EXPORT_SYMBOL_GPL(sdhci_request);
void sdhci_set_bus_width(struct sdhci_host *host, int width)
{
@@ -2219,7 +2333,7 @@ void sdhci_send_tuning(struct sdhci_host *host, u32 opcode)
}
EXPORT_SYMBOL_GPL(sdhci_send_tuning);
-static void __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode)
+static int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode)
{
int i;
@@ -2236,13 +2350,13 @@ static void __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode)
pr_info("%s: Tuning timeout, falling back to fixed sampling clock\n",
mmc_hostname(host->mmc));
sdhci_abort_tuning(host, opcode);
- return;
+ return -ETIMEDOUT;
}
ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
if (!(ctrl & SDHCI_CTRL_EXEC_TUNING)) {
if (ctrl & SDHCI_CTRL_TUNED_CLK)
- return; /* Success! */
+ return 0; /* Success! */
break;
}
@@ -2254,6 +2368,7 @@ static void __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode)
pr_info("%s: Tuning failed, falling back to fixed sampling clock\n",
mmc_hostname(host->mmc));
sdhci_reset_tuning(host);
+ return -EAGAIN;
}
int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
@@ -2315,7 +2430,7 @@ int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
sdhci_start_tuning(host);
- __sdhci_execute_tuning(host, opcode);
+ host->tuning_err = __sdhci_execute_tuning(host, opcode);
sdhci_end_tuning(host);
out:
@@ -2802,7 +2917,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
* some controllers are faulty, don't trust them.
*/
if (intmask & SDHCI_INT_DMA_END) {
- u32 dmastart, dmanow;
+ dma_addr_t dmastart, dmanow;
dmastart = sdhci_sdma_address(host);
dmanow = dmastart + host->data->bytes_xfered;
@@ -2810,12 +2925,12 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
* Force update to the next DMA block boundary.
*/
dmanow = (dmanow &
- ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1)) +
+ ~((dma_addr_t)SDHCI_DEFAULT_BOUNDARY_SIZE - 1)) +
SDHCI_DEFAULT_BOUNDARY_SIZE;
host->data->bytes_xfered = dmanow - dmastart;
- DBG("DMA base 0x%08x, transferred 0x%06x bytes, next 0x%08x\n",
- dmastart, host->data->bytes_xfered, dmanow);
- sdhci_writel(host, dmanow, SDHCI_DMA_ADDRESS);
+ DBG("DMA base %pad, transferred 0x%06x bytes, next %pad\n",
+ &dmastart, host->data->bytes_xfered, &dmanow);
+ sdhci_set_sdma_addr(host, dmanow);
}
if (intmask & SDHCI_INT_DATA_END) {
@@ -3322,6 +3437,13 @@ struct sdhci_host *sdhci_alloc_host(struct device *dev,
host->sdma_boundary = SDHCI_DEFAULT_BOUNDARY_ARG;
+ /*
+ * The DMA table descriptor count is calculated as the maximum
+ * number of segments times 2, to allow for an alignment
+ * descriptor for each segment, plus 1 for a nop end descriptor.
+ */
+ host->adma_table_cnt = SDHCI_MAX_SEGS * 2 + 1;
+
return host;
}
@@ -3376,6 +3498,9 @@ void __sdhci_read_caps(struct sdhci_host *host, u16 *ver, u32 *caps, u32 *caps1)
sdhci_do_reset(host, SDHCI_RESET_ALL);
+ if (host->v4_mode)
+ sdhci_do_enable_v4_mode(host);
+
of_property_read_u64(mmc_dev(host->mmc)->of_node,
"sdhci-caps-mask", &dt_caps_mask);
of_property_read_u64(mmc_dev(host->mmc)->of_node,
@@ -3470,6 +3595,19 @@ static int sdhci_allocate_bounce_buffer(struct sdhci_host *host)
return 0;
}
+static inline bool sdhci_can_64bit_dma(struct sdhci_host *host)
+{
+ /*
+ * According to SD Host Controller spec v4.10, bit[27] added from
+ * version 4.10 in Capabilities Register is used as 64-bit System
+ * Address support for V4 mode.
+ */
+ if (host->version >= SDHCI_SPEC_410 && host->v4_mode)
+ return host->caps & SDHCI_CAN_64BIT_V4;
+
+ return host->caps & SDHCI_CAN_64BIT;
+}
+
int sdhci_setup_host(struct sdhci_host *host)
{
struct mmc_host *mmc;
@@ -3506,7 +3644,7 @@ int sdhci_setup_host(struct sdhci_host *host)
override_timeout_clk = host->timeout_clk;
- if (host->version > SDHCI_SPEC_300) {
+ if (host->version > SDHCI_SPEC_420) {
pr_err("%s: Unknown controller version (%d). You may experience problems.\n",
mmc_hostname(mmc), host->version);
}
@@ -3541,7 +3679,7 @@ int sdhci_setup_host(struct sdhci_host *host)
* SDHCI_QUIRK2_BROKEN_64_BIT_DMA must be left to the drivers to
* implement.
*/
- if (host->caps & SDHCI_CAN_64BIT)
+ if (sdhci_can_64bit_dma(host))
host->flags |= SDHCI_USE_64_BIT_DMA;
if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
@@ -3559,32 +3697,30 @@ int sdhci_setup_host(struct sdhci_host *host)
}
}
- /* SDMA does not support 64-bit DMA */
- if (host->flags & SDHCI_USE_64_BIT_DMA)
+ /* SDMA does not support 64-bit DMA if v4 mode not set */
+ if ((host->flags & SDHCI_USE_64_BIT_DMA) && !host->v4_mode)
host->flags &= ~SDHCI_USE_SDMA;
if (host->flags & SDHCI_USE_ADMA) {
dma_addr_t dma;
void *buf;
- /*
- * The DMA descriptor table size is calculated as the maximum
- * number of segments times 2, to allow for an alignment
- * descriptor for each segment, plus 1 for a nop end descriptor,
- * all multipled by the descriptor size.
- */
if (host->flags & SDHCI_USE_64_BIT_DMA) {
- host->adma_table_sz = (SDHCI_MAX_SEGS * 2 + 1) *
- SDHCI_ADMA2_64_DESC_SZ;
- host->desc_sz = SDHCI_ADMA2_64_DESC_SZ;
+ host->adma_table_sz = host->adma_table_cnt *
+ SDHCI_ADMA2_64_DESC_SZ(host);
+ host->desc_sz = SDHCI_ADMA2_64_DESC_SZ(host);
} else {
- host->adma_table_sz = (SDHCI_MAX_SEGS * 2 + 1) *
+ host->adma_table_sz = host->adma_table_cnt *
SDHCI_ADMA2_32_DESC_SZ;
host->desc_sz = SDHCI_ADMA2_32_DESC_SZ;
}
host->align_buffer_sz = SDHCI_MAX_SEGS * SDHCI_ADMA2_ALIGN;
- buf = dma_alloc_coherent(mmc_dev(mmc), host->align_buffer_sz +
+ /*
+ * Use zalloc to zero the reserved high 32-bits of 128-bit
+ * descriptors so that they never need to be written.
+ */
+ buf = dma_zalloc_coherent(mmc_dev(mmc), host->align_buffer_sz +
host->adma_table_sz, &dma, GFP_KERNEL);
if (!buf) {
pr_warn("%s: Unable to allocate ADMA buffers - falling back to standard DMA\n",
@@ -3708,10 +3844,13 @@ int sdhci_setup_host(struct sdhci_host *host)
if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12)
host->flags |= SDHCI_AUTO_CMD12;
- /* Auto-CMD23 stuff only works in ADMA or PIO. */
+ /*
+ * For v3 mode, Auto-CMD23 stuff only works in ADMA or PIO.
+ * For v4 mode, SDMA may use Auto-CMD23 as well.
+ */
if ((host->version >= SDHCI_SPEC_300) &&
((host->flags & SDHCI_USE_ADMA) ||
- !(host->flags & SDHCI_USE_SDMA)) &&
+ !(host->flags & SDHCI_USE_SDMA) || host->v4_mode) &&
!(host->quirks2 & SDHCI_QUIRK2_ACMD23_BROKEN)) {
host->flags |= SDHCI_AUTO_CMD23;
DBG("Auto-CMD23 available\n");
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index f0bd36ce3817..b001cf4d3d7e 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -28,6 +28,7 @@
#define SDHCI_DMA_ADDRESS 0x00
#define SDHCI_ARGUMENT2 SDHCI_DMA_ADDRESS
+#define SDHCI_32BIT_BLK_CNT SDHCI_DMA_ADDRESS
#define SDHCI_BLOCK_SIZE 0x04
#define SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF))
@@ -41,6 +42,7 @@
#define SDHCI_TRNS_BLK_CNT_EN 0x02
#define SDHCI_TRNS_AUTO_CMD12 0x04
#define SDHCI_TRNS_AUTO_CMD23 0x08
+#define SDHCI_TRNS_AUTO_SEL 0x0C
#define SDHCI_TRNS_READ 0x10
#define SDHCI_TRNS_MULTI 0x20
@@ -184,6 +186,9 @@
#define SDHCI_CTRL_DRV_TYPE_D 0x0030
#define SDHCI_CTRL_EXEC_TUNING 0x0040
#define SDHCI_CTRL_TUNED_CLK 0x0080
+#define SDHCI_CMD23_ENABLE 0x0800
+#define SDHCI_CTRL_V4_MODE 0x1000
+#define SDHCI_CTRL_64BIT_ADDR 0x2000
#define SDHCI_CTRL_PRESET_VAL_ENABLE 0x8000
#define SDHCI_CAPABILITIES 0x40
@@ -204,6 +209,7 @@
#define SDHCI_CAN_VDD_330 0x01000000
#define SDHCI_CAN_VDD_300 0x02000000
#define SDHCI_CAN_VDD_180 0x04000000
+#define SDHCI_CAN_64BIT_V4 0x08000000
#define SDHCI_CAN_64BIT 0x10000000
#define SDHCI_SUPPORT_SDR50 0x00000001
@@ -270,6 +276,9 @@
#define SDHCI_SPEC_100 0
#define SDHCI_SPEC_200 1
#define SDHCI_SPEC_300 2
+#define SDHCI_SPEC_400 3
+#define SDHCI_SPEC_410 4
+#define SDHCI_SPEC_420 5
/*
* End of controller registers.
@@ -305,8 +314,14 @@ struct sdhci_adma2_32_desc {
*/
#define SDHCI_ADMA2_DESC_ALIGN 8
-/* ADMA2 64-bit DMA descriptor size */
-#define SDHCI_ADMA2_64_DESC_SZ 12
+/*
+ * ADMA2 64-bit DMA descriptor size
+ * According to SD Host Controller spec v4.10, there are two kinds of
+ * descriptors for 64-bit addressing mode: 96-bit Descriptor and 128-bit
+ * Descriptor, if Host Version 4 Enable is set in the Host Control 2
+ * register, 128-bit Descriptor will be selected.
+ */
+#define SDHCI_ADMA2_64_DESC_SZ(host) ((host)->v4_mode ? 16 : 12)
/*
* ADMA2 64-bit descriptor. Note 12-byte descriptor can't always be 8-byte
@@ -450,6 +465,13 @@ struct sdhci_host {
* obtainable timeout.
*/
#define SDHCI_QUIRK2_DISABLE_HW_TIMEOUT (1<<17)
+/*
+ * 32-bit block count may not support eMMC where upper bits of CMD23 are used
+ * for other purposes. Consequently we support 16-bit block count by default.
+ * Otherwise, SDHCI_QUIRK2_USE_32BIT_BLK_CNT can be selected to use 32-bit
+ * block count.
+ */
+#define SDHCI_QUIRK2_USE_32BIT_BLK_CNT (1<<18)
int irq; /* Device IRQ */
void __iomem *ioaddr; /* Mapped address */
@@ -501,6 +523,7 @@ struct sdhci_host {
bool preset_enabled; /* Preset is enabled */
bool pending_reset; /* Cmd/data reset is pending */
bool irq_wake_enabled; /* IRQ wakeup is enabled */
+ bool v4_mode; /* Host Version 4 Enable */
struct mmc_request *mrqs_done[SDHCI_MAX_MRQS]; /* Requests done */
struct mmc_command *cmd; /* Current command */
@@ -554,6 +577,7 @@ struct sdhci_host {
unsigned int tuning_count; /* Timer count for re-tuning */
unsigned int tuning_mode; /* Re-tuning mode supported by host */
+ unsigned int tuning_err; /* Error code for re-tuning */
#define SDHCI_TUNING_MODE_1 0
#define SDHCI_TUNING_MODE_2 1
#define SDHCI_TUNING_MODE_3 2
@@ -563,6 +587,9 @@ struct sdhci_host {
/* Host SDMA buffer boundary. */
u32 sdma_boundary;
+ /* Host ADMA table count */
+ u32 adma_table_cnt;
+
u64 data_timeout;
unsigned long private[0] ____cacheline_aligned;
@@ -603,6 +630,8 @@ struct sdhci_ops {
void (*adma_workaround)(struct sdhci_host *host, u32 intmask);
void (*card_event)(struct sdhci_host *host);
void (*voltage_switch)(struct sdhci_host *host);
+ void (*adma_write_desc)(struct sdhci_host *host, void **desc,
+ dma_addr_t addr, int len, unsigned int cmd);
};
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
@@ -725,6 +754,7 @@ void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
unsigned short vdd);
void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode,
unsigned short vdd);
+void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq);
void sdhci_set_bus_width(struct sdhci_host *host, int width);
void sdhci_reset(struct sdhci_host *host, u8 mask);
void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing);
@@ -733,6 +763,8 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);
int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
struct mmc_ios *ios);
void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable);
+void sdhci_adma_write_desc(struct sdhci_host *host, void **desc,
+ dma_addr_t addr, int len, unsigned int cmd);
#ifdef CONFIG_PM
int sdhci_suspend_host(struct sdhci_host *host);
@@ -747,6 +779,7 @@ bool sdhci_cqe_irq(struct sdhci_host *host, u32 intmask, int *cmd_error,
int *data_error);
void sdhci_dumpregs(struct sdhci_host *host);
+void sdhci_enable_v4_mode(struct sdhci_host *host);
void sdhci_start_tuning(struct sdhci_host *host);
void sdhci_end_tuning(struct sdhci_host *host);
diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
index 4c2a1f8ddbf3..81bd9afb0980 100644
--- a/drivers/mmc/host/sh_mmcif.c
+++ b/drivers/mmc/host/sh_mmcif.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* MMCIF eMMC driver.
*
* Copyright (C) 2010 Renesas Solutions Corp.
* Yusuke Goda <yusuke.goda.sx@renesas.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License.
*/
/*
@@ -1573,6 +1570,6 @@ static struct platform_driver sh_mmcif_driver = {
module_platform_driver(sh_mmcif_driver);
MODULE_DESCRIPTION("SuperH on-chip MMC/eMMC interface driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" DRIVER_NAME);
MODULE_AUTHOR("Yusuke Goda <yusuke.goda.sx@renesas.com>");
diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c
index 568349e1fbc2..279e326e397e 100644
--- a/drivers/mmc/host/sunxi-mmc.c
+++ b/drivers/mmc/host/sunxi-mmc.c
@@ -258,11 +258,16 @@ struct sunxi_mmc_cfg {
/* Does DATA0 needs to be masked while the clock is updated */
bool mask_data0;
- /* hardware only supports new timing mode */
+ /*
+ * hardware only supports new timing mode, either due to lack of
+ * a mode switch in the clock controller, or the mmc controller
+ * is permanently configured in the new timing mode, without the
+ * NTSR mode switch.
+ */
bool needs_new_timings;
- /* hardware can switch between old and new timing modes */
- bool has_timings_switch;
+ /* clock hardware can switch between old and new timing modes */
+ bool ccu_has_timings_switch;
};
struct sunxi_mmc_host {
@@ -787,7 +792,7 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host,
clock <<= 1;
}
- if (host->use_new_timings && host->cfg->has_timings_switch) {
+ if (host->use_new_timings && host->cfg->ccu_has_timings_switch) {
ret = sunxi_ccu_set_mmc_timing_mode(host->clk_mmc, true);
if (ret) {
dev_err(mmc_dev(mmc),
@@ -822,6 +827,12 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host,
/* update card clock rate to account for internal divider */
rate /= div;
+ /*
+ * Configure the controller to use the new timing mode if needed.
+ * On controllers that only support the new timing mode, such as
+ * the eMMC controller on the A64, this register does not exist,
+ * and any writes to it are ignored.
+ */
if (host->use_new_timings) {
/* Don't touch the delay bits */
rval = mmc_readl(host, REG_SD_NTSR);
@@ -1145,7 +1156,7 @@ static const struct sunxi_mmc_cfg sun8i_a83t_emmc_cfg = {
.idma_des_size_bits = 16,
.clk_delays = sunxi_mmc_clk_delays,
.can_calibrate = false,
- .has_timings_switch = true,
+ .ccu_has_timings_switch = true,
};
static const struct sunxi_mmc_cfg sun9i_a80_cfg = {
@@ -1166,6 +1177,7 @@ static const struct sunxi_mmc_cfg sun50i_a64_emmc_cfg = {
.idma_des_size_bits = 13,
.clk_delays = NULL,
.can_calibrate = true,
+ .needs_new_timings = true,
};
static const struct of_device_id sunxi_mmc_of_match[] = {
@@ -1351,7 +1363,7 @@ static int sunxi_mmc_probe(struct platform_device *pdev)
goto error_free_host;
}
- if (host->cfg->has_timings_switch) {
+ if (host->cfg->ccu_has_timings_switch) {
/*
* Supports both old and new timing modes.
* Try setting the clk to new timing mode.
diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c
index a3d8380ab480..b6644ce296b2 100644
--- a/drivers/mmc/host/tifm_sd.c
+++ b/drivers/mmc/host/tifm_sd.c
@@ -336,7 +336,8 @@ static unsigned int tifm_sd_op_flags(struct mmc_command *cmd)
rc |= TIFM_MMCSD_RSP_R0;
break;
case MMC_RSP_R1B:
- rc |= TIFM_MMCSD_RSP_BUSY; // deliberate fall-through
+ rc |= TIFM_MMCSD_RSP_BUSY;
+ /* fall-through */
case MMC_RSP_R1:
rc |= TIFM_MMCSD_RSP_R1;
break;
diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c
index 43a2ea5cff24..93e83ad25976 100644
--- a/drivers/mmc/host/tmio_mmc.c
+++ b/drivers/mmc/host/tmio_mmc.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Driver for the MMC / SD / SDIO cell found in:
*
@@ -7,12 +8,9 @@
* Copyright (C) 2017 Horms Solutions, Simon Horman
* Copyright (C) 2007 Ian Molton
* Copyright (C) 2004 Ian Molton
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
+#include <linux/delay.h>
#include <linux/device.h>
#include <linux/mfd/core.h>
#include <linux/mfd/tmio.h>
@@ -23,6 +21,76 @@
#include "tmio_mmc.h"
+/* Registers specific to this variant */
+#define CTL_SDIO_REGS 0x100
+#define CTL_CLK_AND_WAIT_CTL 0x138
+#define CTL_RESET_SDIO 0x1e0
+
+static void tmio_mmc_clk_start(struct tmio_mmc_host *host)
+{
+ sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN |
+ sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+
+ usleep_range(10000, 11000);
+ sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100);
+ usleep_range(10000, 11000);
+}
+
+static void tmio_mmc_clk_stop(struct tmio_mmc_host *host)
+{
+ sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0000);
+ usleep_range(10000, 11000);
+
+ sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
+ sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+
+ usleep_range(10000, 11000);
+}
+
+static void tmio_mmc_set_clock(struct tmio_mmc_host *host,
+ unsigned int new_clock)
+{
+ unsigned int divisor;
+ u32 clk = 0;
+ int clk_sel;
+
+ if (new_clock == 0) {
+ tmio_mmc_clk_stop(host);
+ return;
+ }
+
+ divisor = host->pdata->hclk / new_clock;
+
+ /* bit7 set: 1/512, ... bit0 set: 1/4, all bits clear: 1/2 */
+ clk_sel = (divisor <= 1);
+ clk = clk_sel ? 0 : (roundup_pow_of_two(divisor) >> 2);
+
+ host->pdata->set_clk_div(host->pdev, clk_sel);
+
+ sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
+ sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+ sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & CLK_CTL_DIV_MASK);
+ usleep_range(10000, 11000);
+
+ tmio_mmc_clk_start(host);
+}
+
+static void tmio_mmc_reset(struct tmio_mmc_host *host)
+{
+ /* FIXME - should we set stop clock reg here */
+ sd_ctrl_write16(host, CTL_RESET_SD, 0x0000);
+ sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0000);
+ usleep_range(10000, 11000);
+ sd_ctrl_write16(host, CTL_RESET_SD, 0x0001);
+ sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0001);
+ usleep_range(10000, 11000);
+
+ if (host->pdata->flags & TMIO_MMC_SDIO_IRQ) {
+ sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask);
+ sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001);
+ }
+}
+
#ifdef CONFIG_PM_SLEEP
static int tmio_mmc_suspend(struct device *dev)
{
@@ -90,8 +158,6 @@ static int tmio_mmc_probe(struct platform_device *pdev)
goto cell_disable;
}
- pdata->flags |= TMIO_MMC_HAVE_HIGH_REG;
-
host = tmio_mmc_host_alloc(pdev, pdata);
if (IS_ERR(host)) {
ret = PTR_ERR(host);
@@ -100,6 +166,8 @@ static int tmio_mmc_probe(struct platform_device *pdev)
/* SD control register space size is 0x200, 0x400 for bus_shift=1 */
host->bus_shift = resource_size(res) >> 10;
+ host->set_clock = tmio_mmc_set_clock;
+ host->reset = tmio_mmc_reset;
host->mmc->f_max = pdata->hclk;
host->mmc->f_min = pdata->hclk / 512;
diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
index 5d141f79e175..1e317027bf53 100644
--- a/drivers/mmc/host/tmio_mmc.h
+++ b/drivers/mmc/host/tmio_mmc.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Driver for the MMC / SD / SDIO cell found in:
*
@@ -8,11 +9,6 @@
* Copyright (C) 2016-17 Horms Solutions, Simon Horman
* Copyright (C) 2007 Ian Molton
* Copyright (C) 2004 Ian Molton
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
*/
#ifndef TMIO_MMC_H
@@ -47,9 +43,6 @@
#define CTL_RESET_SD 0xe0
#define CTL_VERSION 0xe2
#define CTL_SDIF_MODE 0xe6
-#define CTL_SDIO_REGS 0x100
-#define CTL_CLK_AND_WAIT_CTL 0x138
-#define CTL_RESET_SDIO 0x1e0
/* Definitions for values the CTL_STOP_INTERNAL_ACTION register can take */
#define TMIO_STOP_STP BIT(0)
@@ -133,7 +126,6 @@ struct tmio_mmc_host {
/* Callbacks for clock / power control */
void (*set_pwr)(struct platform_device *host, int state);
- void (*set_clk_div)(struct platform_device *host, int state);
/* pio related stuff */
struct scatterlist *sg_ptr;
@@ -146,7 +138,7 @@ struct tmio_mmc_host {
struct tmio_mmc_data *pdata;
/* DMA support */
- bool force_pio;
+ bool dma_on;
struct dma_chan *chan_rx;
struct dma_chan *chan_tx;
struct tasklet_struct dma_issue;
@@ -170,14 +162,14 @@ struct tmio_mmc_host {
/* Mandatory callback */
int (*clk_enable)(struct tmio_mmc_host *host);
+ void (*set_clock)(struct tmio_mmc_host *host, unsigned int clock);
/* Optional callbacks */
- unsigned int (*clk_update)(struct tmio_mmc_host *host,
- unsigned int new_clock);
void (*clk_disable)(struct tmio_mmc_host *host);
int (*multi_io_quirk)(struct mmc_card *card,
unsigned int direction, int blk_size);
int (*write16_hook)(struct tmio_mmc_host *host, int addr);
+ void (*reset)(struct tmio_mmc_host *host);
void (*hw_reset)(struct tmio_mmc_host *host);
void (*prepare_tuning)(struct tmio_mmc_host *host, unsigned long tap);
bool (*check_scc_error)(struct tmio_mmc_host *host);
diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c
index 261b4d62d2b1..8d64f6196f33 100644
--- a/drivers/mmc/host/tmio_mmc_core.c
+++ b/drivers/mmc/host/tmio_mmc_core.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Driver for the MMC / SD / SDIO IP found in:
*
@@ -10,10 +11,6 @@
* Copyright (C) 2007 Ian Molton
* Copyright (C) 2004 Ian Molton
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
* This driver draws mainly on scattered spec sheets, Reverse engineering
* of the toshiba e800 SD driver and some parts of the 2.4 ASIC3 driver (4 bit
* support). (Further 4 bit support from a later datasheet).
@@ -160,100 +157,18 @@ static void tmio_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
}
}
-static void tmio_mmc_clk_start(struct tmio_mmc_host *host)
-{
- sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN |
- sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
-
- /* HW engineers overrode docs: no sleep needed on R-Car2+ */
- if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2))
- usleep_range(10000, 11000);
-
- if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) {
- sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100);
- usleep_range(10000, 11000);
- }
-}
-
-static void tmio_mmc_clk_stop(struct tmio_mmc_host *host)
-{
- if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) {
- sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0000);
- usleep_range(10000, 11000);
- }
-
- sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
- sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
-
- /* HW engineers overrode docs: no sleep needed on R-Car2+ */
- if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2))
- usleep_range(10000, 11000);
-}
-
-static void tmio_mmc_set_clock(struct tmio_mmc_host *host,
- unsigned int new_clock)
-{
- u32 clk = 0, clock;
-
- if (new_clock == 0) {
- tmio_mmc_clk_stop(host);
- return;
- }
- /*
- * Both HS400 and HS200/SD104 set 200MHz, but some devices need to
- * set 400MHz to distinguish the CPG settings in HS400.
- */
- if (host->mmc->ios.timing == MMC_TIMING_MMC_HS400 &&
- host->pdata->flags & TMIO_MMC_HAVE_4TAP_HS400 &&
- new_clock == 200000000)
- new_clock = 400000000;
-
- if (host->clk_update)
- clock = host->clk_update(host, new_clock) / 512;
- else
- clock = host->mmc->f_min;
-
- for (clk = 0x80000080; new_clock >= (clock << 1); clk >>= 1)
- clock <<= 1;
-
- /* 1/1 clock is option */
- if ((host->pdata->flags & TMIO_MMC_CLK_ACTUAL) &&
- ((clk >> 22) & 0x1)) {
- if (!(host->mmc->ios.timing == MMC_TIMING_MMC_HS400))
- clk |= 0xff;
- else
- clk &= ~0xff;
- }
-
- if (host->set_clk_div)
- host->set_clk_div(host->pdev, (clk >> 22) & 1);
-
- sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
- sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
- sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & CLK_CTL_DIV_MASK);
- if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2))
- usleep_range(10000, 11000);
-
- tmio_mmc_clk_start(host);
-}
-
static void tmio_mmc_reset(struct tmio_mmc_host *host)
{
/* FIXME - should we set stop clock reg here */
sd_ctrl_write16(host, CTL_RESET_SD, 0x0000);
- if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG)
- sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0000);
usleep_range(10000, 11000);
sd_ctrl_write16(host, CTL_RESET_SD, 0x0001);
- if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG)
- sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0001);
usleep_range(10000, 11000);
if (host->pdata->flags & TMIO_MMC_SDIO_IRQ) {
sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask);
sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001);
}
-
}
static void tmio_mmc_reset_work(struct work_struct *work)
@@ -294,7 +209,7 @@ static void tmio_mmc_reset_work(struct work_struct *work)
spin_unlock_irqrestore(&host->lock, flags);
- tmio_mmc_reset(host);
+ host->reset(host);
/* Ready for new calls */
host->mrq = NULL;
@@ -446,7 +361,7 @@ static void tmio_mmc_pio_irq(struct tmio_mmc_host *host)
unsigned int count;
unsigned long flags;
- if ((host->chan_tx || host->chan_rx) && !host->force_pio) {
+ if (host->dma_on) {
pr_err("PIO IRQ in DMA mode!\n");
return;
} else if (!data) {
@@ -518,7 +433,7 @@ void tmio_mmc_do_data_irq(struct tmio_mmc_host *host)
*/
if (data->flags & MMC_DATA_READ) {
- if (host->chan_rx && !host->force_pio)
+ if (host->dma_on)
tmio_mmc_check_bounce_buffer(host);
dev_dbg(&host->pdev->dev, "Complete Rx request %p\n",
host->mrq);
@@ -555,7 +470,7 @@ static void tmio_mmc_data_irq(struct tmio_mmc_host *host, unsigned int stat)
if (stat & TMIO_STAT_CRCFAIL || stat & TMIO_STAT_STOPBIT_ERR ||
stat & TMIO_STAT_TXUNDERRUN)
data->error = -EILSEQ;
- if (host->chan_tx && (data->flags & MMC_DATA_WRITE) && !host->force_pio) {
+ if (host->dma_on && (data->flags & MMC_DATA_WRITE)) {
u32 status = sd_ctrl_read16_and_16_as_32(host, CTL_STATUS);
bool done = false;
@@ -579,7 +494,7 @@ static void tmio_mmc_data_irq(struct tmio_mmc_host *host, unsigned int stat)
tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_DATAEND);
tmio_mmc_dataend_dma(host);
}
- } else if (host->chan_rx && (data->flags & MMC_DATA_READ) && !host->force_pio) {
+ } else if (host->dma_on && (data->flags & MMC_DATA_READ)) {
tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_DATAEND);
tmio_mmc_dataend_dma(host);
} else {
@@ -632,7 +547,7 @@ static void tmio_mmc_cmd_irq(struct tmio_mmc_host *host, unsigned int stat)
*/
if (host->data && (!cmd->error || cmd->error == -EILSEQ)) {
if (host->data->flags & MMC_DATA_READ) {
- if (host->force_pio || !host->chan_rx) {
+ if (!host->dma_on) {
tmio_mmc_enable_mmc_irqs(host, TMIO_MASK_READOP);
} else {
tmio_mmc_disable_mmc_irqs(host,
@@ -640,7 +555,7 @@ static void tmio_mmc_cmd_irq(struct tmio_mmc_host *host, unsigned int stat)
tasklet_schedule(&host->dma_issue);
}
} else {
- if (host->force_pio || !host->chan_tx) {
+ if (!host->dma_on) {
tmio_mmc_enable_mmc_irqs(host, TMIO_MASK_WRITEOP);
} else {
tmio_mmc_disable_mmc_irqs(host,
@@ -770,7 +685,7 @@ static int tmio_mmc_start_data(struct tmio_mmc_host *host,
tmio_mmc_init_sg(host, data);
host->data = data;
- host->force_pio = false;
+ host->dma_on = false;
/* Set transfer length / blocksize */
sd_ctrl_write16(host, CTL_SD_XFER_LEN, data->blksz);
@@ -919,8 +834,8 @@ static void tmio_mmc_finish_request(struct tmio_mmc_host *host)
if (mrq->cmd->error || (mrq->data && mrq->data->error))
tmio_mmc_abort_dma(host);
- if (host->check_scc_error)
- host->check_scc_error(host);
+ if (host->check_scc_error && host->check_scc_error(host))
+ mrq->cmd->error = -EILSEQ;
/* If SET_BLOCK_COUNT, continue with main command */
if (host->mrq && !mrq->cmd->error) {
@@ -1043,15 +958,15 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
switch (ios->power_mode) {
case MMC_POWER_OFF:
tmio_mmc_power_off(host);
- tmio_mmc_clk_stop(host);
+ host->set_clock(host, 0);
break;
case MMC_POWER_UP:
tmio_mmc_power_on(host, ios->vdd);
- tmio_mmc_set_clock(host, ios->clock);
+ host->set_clock(host, ios->clock);
tmio_mmc_set_bus_width(host, ios->bus_width);
break;
case MMC_POWER_ON:
- tmio_mmc_set_clock(host, ios->clock);
+ host->set_clock(host, ios->clock);
tmio_mmc_set_bus_width(host, ios->bus_width);
break;
}
@@ -1237,7 +1152,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
int ret;
/*
- * Check the sanity of mmc->f_min to prevent tmio_mmc_set_clock() from
+ * Check the sanity of mmc->f_min to prevent host->set_clock() from
* looping forever...
*/
if (mmc->f_min == 0)
@@ -1247,7 +1162,6 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
_host->write16_hook = NULL;
_host->set_pwr = pdata->set_pwr;
- _host->set_clk_div = pdata->set_clk_div;
ret = tmio_mmc_init_ocr(_host);
if (ret < 0)
@@ -1290,6 +1204,9 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
mmc->caps & MMC_CAP_NEEDS_POLL ||
!mmc_card_is_removable(mmc));
+ if (!_host->reset)
+ _host->reset = tmio_mmc_reset;
+
/*
* On Gen2+, eMMC with NONREMOVABLE currently fails because native
* hotplug gets disabled. It seems RuntimePM related yet we need further
@@ -1310,8 +1227,8 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
if (pdata->flags & TMIO_MMC_SDIO_IRQ)
_host->sdio_irq_mask = TMIO_SDIO_MASK_ALL;
- tmio_mmc_clk_stop(_host);
- tmio_mmc_reset(_host);
+ _host->set_clock(_host, 0);
+ _host->reset(_host);
_host->sdcard_irq_mask = sd_ctrl_read16_and_16_as_32(_host, CTL_IRQ_MASK);
tmio_mmc_disable_mmc_irqs(_host, TMIO_MASK_ALL);
@@ -1394,7 +1311,7 @@ int tmio_mmc_host_runtime_suspend(struct device *dev)
tmio_mmc_disable_mmc_irqs(host, TMIO_MASK_ALL);
if (host->clk_cache)
- tmio_mmc_clk_stop(host);
+ host->set_clock(host, 0);
tmio_mmc_clk_disable(host);
@@ -1411,11 +1328,11 @@ int tmio_mmc_host_runtime_resume(struct device *dev)
{
struct tmio_mmc_host *host = dev_get_drvdata(dev);
- tmio_mmc_reset(host);
+ host->reset(host);
tmio_mmc_clk_enable(host);
if (host->clk_cache)
- tmio_mmc_set_clock(host, host->clk_cache);
+ host->set_clock(host, host->clk_cache);
if (host->native_hotplug)
tmio_mmc_enable_mmc_irqs(host,
diff --git a/drivers/mmc/host/uniphier-sd.c b/drivers/mmc/host/uniphier-sd.c
new file mode 100644
index 000000000000..91a2be41edf6
--- /dev/null
+++ b/drivers/mmc/host/uniphier-sd.c
@@ -0,0 +1,698 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (C) 2017-2018 Socionext Inc.
+// Author: Masahiro Yamada <yamada.masahiro@socionext.com>
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/mfd/tmio.h>
+#include <linux/mmc/host.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+
+#include "tmio_mmc.h"
+
+#define UNIPHIER_SD_CLK_CTL_DIV1024 BIT(16)
+#define UNIPHIER_SD_CLK_CTL_DIV1 BIT(10)
+#define UNIPHIER_SD_CLKCTL_OFFEN BIT(9) // auto SDCLK stop
+#define UNIPHIER_SD_CC_EXT_MODE 0x1b0
+#define UNIPHIER_SD_CC_EXT_MODE_DMA BIT(1)
+#define UNIPHIER_SD_HOST_MODE 0x1c8
+#define UNIPHIER_SD_VOLT 0x1e4
+#define UNIPHIER_SD_VOLT_MASK GENMASK(1, 0)
+#define UNIPHIER_SD_VOLT_OFF 0
+#define UNIPHIER_SD_VOLT_330 1 // 3.3V signal
+#define UNIPHIER_SD_VOLT_180 2 // 1.8V signal
+#define UNIPHIER_SD_DMA_MODE 0x410
+#define UNIPHIER_SD_DMA_MODE_DIR_MASK GENMASK(17, 16)
+#define UNIPHIER_SD_DMA_MODE_DIR_TO_DEV 0
+#define UNIPHIER_SD_DMA_MODE_DIR_FROM_DEV 1
+#define UNIPHIER_SD_DMA_MODE_WIDTH_MASK GENMASK(5, 4)
+#define UNIPHIER_SD_DMA_MODE_WIDTH_8 0
+#define UNIPHIER_SD_DMA_MODE_WIDTH_16 1
+#define UNIPHIER_SD_DMA_MODE_WIDTH_32 2
+#define UNIPHIER_SD_DMA_MODE_WIDTH_64 3
+#define UNIPHIER_SD_DMA_MODE_ADDR_INC BIT(0) // 1: inc, 0: fixed
+#define UNIPHIER_SD_DMA_CTL 0x414
+#define UNIPHIER_SD_DMA_CTL_START BIT(0) // start DMA (auto cleared)
+#define UNIPHIER_SD_DMA_RST 0x418
+#define UNIPHIER_SD_DMA_RST_CH1 BIT(9)
+#define UNIPHIER_SD_DMA_RST_CH0 BIT(8)
+#define UNIPHIER_SD_DMA_ADDR_L 0x440
+#define UNIPHIER_SD_DMA_ADDR_H 0x444
+
+/*
+ * IP is extended to support various features: built-in DMA engine,
+ * 1/1024 divisor, etc.
+ */
+#define UNIPHIER_SD_CAP_EXTENDED_IP BIT(0)
+/* RX channel of the built-in DMA controller is broken (Pro5) */
+#define UNIPHIER_SD_CAP_BROKEN_DMA_RX BIT(1)
+
+struct uniphier_sd_priv {
+ struct tmio_mmc_data tmio_data;
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *pinstate_default;
+ struct pinctrl_state *pinstate_uhs;
+ struct clk *clk;
+ struct reset_control *rst;
+ struct reset_control *rst_br;
+ struct reset_control *rst_hw;
+ struct dma_chan *chan;
+ enum dma_data_direction dma_dir;
+ unsigned long clk_rate;
+ unsigned long caps;
+};
+
+static void *uniphier_sd_priv(struct tmio_mmc_host *host)
+{
+ return container_of(host->pdata, struct uniphier_sd_priv, tmio_data);
+}
+
+static void uniphier_sd_dma_endisable(struct tmio_mmc_host *host, int enable)
+{
+ sd_ctrl_write16(host, CTL_DMA_ENABLE, enable ? DMA_ENABLE_DMASDRW : 0);
+}
+
+/* external DMA engine */
+static void uniphier_sd_external_dma_issue(unsigned long arg)
+{
+ struct tmio_mmc_host *host = (void *)arg;
+ struct uniphier_sd_priv *priv = uniphier_sd_priv(host);
+
+ uniphier_sd_dma_endisable(host, 1);
+ dma_async_issue_pending(priv->chan);
+}
+
+static void uniphier_sd_external_dma_callback(void *param,
+ const struct dmaengine_result *result)
+{
+ struct tmio_mmc_host *host = param;
+ struct uniphier_sd_priv *priv = uniphier_sd_priv(host);
+ unsigned long flags;
+
+ dma_unmap_sg(mmc_dev(host->mmc), host->sg_ptr, host->sg_len,
+ priv->dma_dir);
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ if (result->result == DMA_TRANS_NOERROR) {
+ /*
+ * When the external DMA engine is enabled, strangely enough,
+ * the DATAEND flag can be asserted even if the DMA engine has
+ * not been kicked yet. Enable the TMIO_STAT_DATAEND irq only
+ * after we make sure the DMA engine finishes the transfer,
+ * hence, in this callback.
+ */
+ tmio_mmc_enable_mmc_irqs(host, TMIO_STAT_DATAEND);
+ } else {
+ host->data->error = -ETIMEDOUT;
+ tmio_mmc_do_data_irq(host);
+ }
+
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static void uniphier_sd_external_dma_start(struct tmio_mmc_host *host,
+ struct mmc_data *data)
+{
+ struct uniphier_sd_priv *priv = uniphier_sd_priv(host);
+ enum dma_transfer_direction dma_tx_dir;
+ struct dma_async_tx_descriptor *desc;
+ dma_cookie_t cookie;
+ int sg_len;
+
+ if (!priv->chan)
+ goto force_pio;
+
+ if (data->flags & MMC_DATA_READ) {
+ priv->dma_dir = DMA_FROM_DEVICE;
+ dma_tx_dir = DMA_DEV_TO_MEM;
+ } else {
+ priv->dma_dir = DMA_TO_DEVICE;
+ dma_tx_dir = DMA_MEM_TO_DEV;
+ }
+
+ sg_len = dma_map_sg(mmc_dev(host->mmc), host->sg_ptr, host->sg_len,
+ priv->dma_dir);
+ if (sg_len == 0)
+ goto force_pio;
+
+ desc = dmaengine_prep_slave_sg(priv->chan, host->sg_ptr, sg_len,
+ dma_tx_dir, DMA_CTRL_ACK);
+ if (!desc)
+ goto unmap_sg;
+
+ desc->callback_result = uniphier_sd_external_dma_callback;
+ desc->callback_param = host;
+
+ cookie = dmaengine_submit(desc);
+ if (cookie < 0)
+ goto unmap_sg;
+
+ host->dma_on = true;
+
+ return;
+
+unmap_sg:
+ dma_unmap_sg(mmc_dev(host->mmc), host->sg_ptr, host->sg_len,
+ priv->dma_dir);
+force_pio:
+ uniphier_sd_dma_endisable(host, 0);
+}
+
+static void uniphier_sd_external_dma_enable(struct tmio_mmc_host *host,
+ bool enable)
+{
+}
+
+static void uniphier_sd_external_dma_request(struct tmio_mmc_host *host,
+ struct tmio_mmc_data *pdata)
+{
+ struct uniphier_sd_priv *priv = uniphier_sd_priv(host);
+ struct dma_chan *chan;
+
+ chan = dma_request_chan(mmc_dev(host->mmc), "rx-tx");
+ if (IS_ERR(chan)) {
+ dev_warn(mmc_dev(host->mmc),
+ "failed to request DMA channel. falling back to PIO\n");
+ return; /* just use PIO even for -EPROBE_DEFER */
+ }
+
+ /* this driver uses a single channel for both RX an TX */
+ priv->chan = chan;
+ host->chan_rx = chan;
+ host->chan_tx = chan;
+
+ tasklet_init(&host->dma_issue, uniphier_sd_external_dma_issue,
+ (unsigned long)host);
+}
+
+static void uniphier_sd_external_dma_release(struct tmio_mmc_host *host)
+{
+ struct uniphier_sd_priv *priv = uniphier_sd_priv(host);
+
+ if (priv->chan)
+ dma_release_channel(priv->chan);
+}
+
+static void uniphier_sd_external_dma_abort(struct tmio_mmc_host *host)
+{
+ struct uniphier_sd_priv *priv = uniphier_sd_priv(host);
+
+ uniphier_sd_dma_endisable(host, 0);
+
+ if (priv->chan)
+ dmaengine_terminate_sync(priv->chan);
+}
+
+static void uniphier_sd_external_dma_dataend(struct tmio_mmc_host *host)
+{
+ uniphier_sd_dma_endisable(host, 0);
+
+ tmio_mmc_do_data_irq(host);
+}
+
+static const struct tmio_mmc_dma_ops uniphier_sd_external_dma_ops = {
+ .start = uniphier_sd_external_dma_start,
+ .enable = uniphier_sd_external_dma_enable,
+ .request = uniphier_sd_external_dma_request,
+ .release = uniphier_sd_external_dma_release,
+ .abort = uniphier_sd_external_dma_abort,
+ .dataend = uniphier_sd_external_dma_dataend,
+};
+
+static void uniphier_sd_internal_dma_issue(unsigned long arg)
+{
+ struct tmio_mmc_host *host = (void *)arg;
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+ tmio_mmc_enable_mmc_irqs(host, TMIO_STAT_DATAEND);
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ uniphier_sd_dma_endisable(host, 1);
+ writel(UNIPHIER_SD_DMA_CTL_START, host->ctl + UNIPHIER_SD_DMA_CTL);
+}
+
+static void uniphier_sd_internal_dma_start(struct tmio_mmc_host *host,
+ struct mmc_data *data)
+{
+ struct uniphier_sd_priv *priv = uniphier_sd_priv(host);
+ struct scatterlist *sg = host->sg_ptr;
+ dma_addr_t dma_addr;
+ unsigned int dma_mode_dir;
+ u32 dma_mode;
+ int sg_len;
+
+ if ((data->flags & MMC_DATA_READ) && !host->chan_rx)
+ goto force_pio;
+
+ if (WARN_ON(host->sg_len != 1))
+ goto force_pio;
+
+ if (!IS_ALIGNED(sg->offset, 8))
+ goto force_pio;
+
+ if (data->flags & MMC_DATA_READ) {
+ priv->dma_dir = DMA_FROM_DEVICE;
+ dma_mode_dir = UNIPHIER_SD_DMA_MODE_DIR_FROM_DEV;
+ } else {
+ priv->dma_dir = DMA_TO_DEVICE;
+ dma_mode_dir = UNIPHIER_SD_DMA_MODE_DIR_TO_DEV;
+ }
+
+ sg_len = dma_map_sg(mmc_dev(host->mmc), sg, 1, priv->dma_dir);
+ if (sg_len == 0)
+ goto force_pio;
+
+ dma_mode = FIELD_PREP(UNIPHIER_SD_DMA_MODE_DIR_MASK, dma_mode_dir);
+ dma_mode |= FIELD_PREP(UNIPHIER_SD_DMA_MODE_WIDTH_MASK,
+ UNIPHIER_SD_DMA_MODE_WIDTH_64);
+ dma_mode |= UNIPHIER_SD_DMA_MODE_ADDR_INC;
+
+ writel(dma_mode, host->ctl + UNIPHIER_SD_DMA_MODE);
+
+ dma_addr = sg_dma_address(data->sg);
+ writel(lower_32_bits(dma_addr), host->ctl + UNIPHIER_SD_DMA_ADDR_L);
+ writel(upper_32_bits(dma_addr), host->ctl + UNIPHIER_SD_DMA_ADDR_H);
+
+ host->dma_on = true;
+
+ return;
+force_pio:
+ uniphier_sd_dma_endisable(host, 0);
+}
+
+static void uniphier_sd_internal_dma_enable(struct tmio_mmc_host *host,
+ bool enable)
+{
+}
+
+static void uniphier_sd_internal_dma_request(struct tmio_mmc_host *host,
+ struct tmio_mmc_data *pdata)
+{
+ struct uniphier_sd_priv *priv = uniphier_sd_priv(host);
+
+ /*
+ * Due to a hardware bug, Pro5 cannot use DMA for RX.
+ * We can still use DMA for TX, but PIO for RX.
+ */
+ if (!(priv->caps & UNIPHIER_SD_CAP_BROKEN_DMA_RX))
+ host->chan_rx = (void *)0xdeadbeaf;
+
+ host->chan_tx = (void *)0xdeadbeaf;
+
+ tasklet_init(&host->dma_issue, uniphier_sd_internal_dma_issue,
+ (unsigned long)host);
+}
+
+static void uniphier_sd_internal_dma_release(struct tmio_mmc_host *host)
+{
+ /* Each value is set to zero to assume "disabling" each DMA */
+ host->chan_rx = NULL;
+ host->chan_tx = NULL;
+}
+
+static void uniphier_sd_internal_dma_abort(struct tmio_mmc_host *host)
+{
+ u32 tmp;
+
+ uniphier_sd_dma_endisable(host, 0);
+
+ tmp = readl(host->ctl + UNIPHIER_SD_DMA_RST);
+ tmp &= ~(UNIPHIER_SD_DMA_RST_CH1 | UNIPHIER_SD_DMA_RST_CH0);
+ writel(tmp, host->ctl + UNIPHIER_SD_DMA_RST);
+
+ tmp |= UNIPHIER_SD_DMA_RST_CH1 | UNIPHIER_SD_DMA_RST_CH0;
+ writel(tmp, host->ctl + UNIPHIER_SD_DMA_RST);
+}
+
+static void uniphier_sd_internal_dma_dataend(struct tmio_mmc_host *host)
+{
+ struct uniphier_sd_priv *priv = uniphier_sd_priv(host);
+
+ uniphier_sd_dma_endisable(host, 0);
+ dma_unmap_sg(mmc_dev(host->mmc), host->sg_ptr, 1, priv->dma_dir);
+
+ tmio_mmc_do_data_irq(host);
+}
+
+static const struct tmio_mmc_dma_ops uniphier_sd_internal_dma_ops = {
+ .start = uniphier_sd_internal_dma_start,
+ .enable = uniphier_sd_internal_dma_enable,
+ .request = uniphier_sd_internal_dma_request,
+ .release = uniphier_sd_internal_dma_release,
+ .abort = uniphier_sd_internal_dma_abort,
+ .dataend = uniphier_sd_internal_dma_dataend,
+};
+
+static int uniphier_sd_clk_enable(struct tmio_mmc_host *host)
+{
+ struct uniphier_sd_priv *priv = uniphier_sd_priv(host);
+ struct mmc_host *mmc = host->mmc;
+ int ret;
+
+ ret = clk_prepare_enable(priv->clk);
+ if (ret)
+ return ret;
+
+ ret = clk_set_rate(priv->clk, ULONG_MAX);
+ if (ret)
+ goto disable_clk;
+
+ priv->clk_rate = clk_get_rate(priv->clk);
+
+ /* If max-frequency property is set, use it. */
+ if (!mmc->f_max)
+ mmc->f_max = priv->clk_rate;
+
+ /*
+ * 1/512 is the finest divisor in the original IP. Newer versions
+ * also supports 1/1024 divisor. (UniPhier-specific extension)
+ */
+ if (priv->caps & UNIPHIER_SD_CAP_EXTENDED_IP)
+ mmc->f_min = priv->clk_rate / 1024;
+ else
+ mmc->f_min = priv->clk_rate / 512;
+
+ ret = reset_control_deassert(priv->rst);
+ if (ret)
+ goto disable_clk;
+
+ ret = reset_control_deassert(priv->rst_br);
+ if (ret)
+ goto assert_rst;
+
+ return 0;
+
+assert_rst:
+ reset_control_assert(priv->rst);
+disable_clk:
+ clk_disable_unprepare(priv->clk);
+
+ return ret;
+}
+
+static void uniphier_sd_clk_disable(struct tmio_mmc_host *host)
+{
+ struct uniphier_sd_priv *priv = uniphier_sd_priv(host);
+
+ reset_control_assert(priv->rst_br);
+ reset_control_assert(priv->rst);
+ clk_disable_unprepare(priv->clk);
+}
+
+static void uniphier_sd_hw_reset(struct tmio_mmc_host *host)
+{
+ struct uniphier_sd_priv *priv = uniphier_sd_priv(host);
+
+ reset_control_assert(priv->rst_hw);
+ /* For eMMC, minimum is 1us but give it 9us for good measure */
+ udelay(9);
+ reset_control_deassert(priv->rst_hw);
+ /* For eMMC, minimum is 200us but give it 300us for good measure */
+ usleep_range(300, 1000);
+}
+
+static void uniphier_sd_set_clock(struct tmio_mmc_host *host,
+ unsigned int clock)
+{
+ struct uniphier_sd_priv *priv = uniphier_sd_priv(host);
+ unsigned long divisor;
+ u32 tmp;
+
+ tmp = readl(host->ctl + (CTL_SD_CARD_CLK_CTL << 1));
+
+ /* stop the clock before changing its rate to avoid a glitch signal */
+ tmp &= ~CLK_CTL_SCLKEN;
+ writel(tmp, host->ctl + (CTL_SD_CARD_CLK_CTL << 1));
+
+ if (clock == 0)
+ return;
+
+ tmp &= ~UNIPHIER_SD_CLK_CTL_DIV1024;
+ tmp &= ~UNIPHIER_SD_CLK_CTL_DIV1;
+ tmp &= ~CLK_CTL_DIV_MASK;
+
+ divisor = priv->clk_rate / clock;
+
+ /*
+ * In the original IP, bit[7:0] represents the divisor.
+ * bit7 set: 1/512, ... bit0 set:1/4, all bits clear: 1/2
+ *
+ * The IP does not define a way to achieve 1/1. For UniPhier variants,
+ * bit10 is used for 1/1. Newer versions of UniPhier variants use
+ * bit16 for 1/1024.
+ */
+ if (divisor <= 1)
+ tmp |= UNIPHIER_SD_CLK_CTL_DIV1;
+ else if (priv->caps & UNIPHIER_SD_CAP_EXTENDED_IP && divisor > 512)
+ tmp |= UNIPHIER_SD_CLK_CTL_DIV1024;
+ else
+ tmp |= roundup_pow_of_two(divisor) >> 2;
+
+ writel(tmp, host->ctl + (CTL_SD_CARD_CLK_CTL << 1));
+
+ tmp |= CLK_CTL_SCLKEN;
+ writel(tmp, host->ctl + (CTL_SD_CARD_CLK_CTL << 1));
+}
+
+static void uniphier_sd_host_init(struct tmio_mmc_host *host)
+{
+ struct uniphier_sd_priv *priv = uniphier_sd_priv(host);
+ u32 val;
+
+ /*
+ * Connected to 32bit AXI.
+ * This register holds settings for SoC-specific internal bus
+ * connection. What is worse, the register spec was changed,
+ * breaking the backward compatibility. Write an appropriate
+ * value depending on a flag associated with a compatible string.
+ */
+ if (priv->caps & UNIPHIER_SD_CAP_EXTENDED_IP)
+ val = 0x00000101;
+ else
+ val = 0x00000000;
+
+ writel(val, host->ctl + UNIPHIER_SD_HOST_MODE);
+
+ val = 0;
+ /*
+ * If supported, the controller can automatically
+ * enable/disable the clock line to the card.
+ */
+ if (priv->caps & UNIPHIER_SD_CAP_EXTENDED_IP)
+ val |= UNIPHIER_SD_CLKCTL_OFFEN;
+
+ writel(val, host->ctl + (CTL_SD_CARD_CLK_CTL << 1));
+}
+
+static int uniphier_sd_start_signal_voltage_switch(struct mmc_host *mmc,
+ struct mmc_ios *ios)
+{
+ struct tmio_mmc_host *host = mmc_priv(mmc);
+ struct uniphier_sd_priv *priv = uniphier_sd_priv(host);
+ struct pinctrl_state *pinstate;
+ u32 val, tmp;
+
+ switch (ios->signal_voltage) {
+ case MMC_SIGNAL_VOLTAGE_330:
+ val = UNIPHIER_SD_VOLT_330;
+ pinstate = priv->pinstate_default;
+ break;
+ case MMC_SIGNAL_VOLTAGE_180:
+ val = UNIPHIER_SD_VOLT_180;
+ pinstate = priv->pinstate_uhs;
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ tmp = readl(host->ctl + UNIPHIER_SD_VOLT);
+ tmp &= ~UNIPHIER_SD_VOLT_MASK;
+ tmp |= FIELD_PREP(UNIPHIER_SD_VOLT_MASK, val);
+ writel(tmp, host->ctl + UNIPHIER_SD_VOLT);
+
+ pinctrl_select_state(priv->pinctrl, pinstate);
+
+ return 0;
+}
+
+static int uniphier_sd_uhs_init(struct tmio_mmc_host *host,
+ struct uniphier_sd_priv *priv)
+{
+ priv->pinctrl = devm_pinctrl_get(mmc_dev(host->mmc));
+ if (IS_ERR(priv->pinctrl))
+ return PTR_ERR(priv->pinctrl);
+
+ priv->pinstate_default = pinctrl_lookup_state(priv->pinctrl,
+ PINCTRL_STATE_DEFAULT);
+ if (IS_ERR(priv->pinstate_default))
+ return PTR_ERR(priv->pinstate_default);
+
+ priv->pinstate_uhs = pinctrl_lookup_state(priv->pinctrl, "uhs");
+ if (IS_ERR(priv->pinstate_uhs))
+ return PTR_ERR(priv->pinstate_uhs);
+
+ host->ops.start_signal_voltage_switch =
+ uniphier_sd_start_signal_voltage_switch;
+
+ return 0;
+}
+
+static int uniphier_sd_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct uniphier_sd_priv *priv;
+ struct tmio_mmc_data *tmio_data;
+ struct tmio_mmc_host *host;
+ int irq, ret;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(dev, "failed to get IRQ number");
+ return irq;
+ }
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->caps = (unsigned long)of_device_get_match_data(dev);
+
+ 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);
+ }
+
+ priv->rst = devm_reset_control_get_shared(dev, "host");
+ if (IS_ERR(priv->rst)) {
+ dev_err(dev, "failed to get host reset\n");
+ return PTR_ERR(priv->rst);
+ }
+
+ /* old version has one more reset */
+ if (!(priv->caps & UNIPHIER_SD_CAP_EXTENDED_IP)) {
+ priv->rst_br = devm_reset_control_get_shared(dev, "bridge");
+ if (IS_ERR(priv->rst_br)) {
+ dev_err(dev, "failed to get bridge reset\n");
+ return PTR_ERR(priv->rst_br);
+ }
+ }
+
+ tmio_data = &priv->tmio_data;
+ tmio_data->flags |= TMIO_MMC_32BIT_DATA_PORT;
+
+ host = tmio_mmc_host_alloc(pdev, tmio_data);
+ if (IS_ERR(host))
+ return PTR_ERR(host);
+
+ if (host->mmc->caps & MMC_CAP_HW_RESET) {
+ priv->rst_hw = devm_reset_control_get_exclusive(dev, "hw");
+ if (IS_ERR(priv->rst_hw)) {
+ dev_err(dev, "failed to get hw reset\n");
+ ret = PTR_ERR(priv->rst_hw);
+ goto free_host;
+ }
+ host->hw_reset = uniphier_sd_hw_reset;
+ }
+
+ if (host->mmc->caps & MMC_CAP_UHS) {
+ ret = uniphier_sd_uhs_init(host, priv);
+ if (ret) {
+ dev_warn(dev,
+ "failed to setup UHS (error %d). Disabling UHS.",
+ ret);
+ host->mmc->caps &= ~MMC_CAP_UHS;
+ }
+ }
+
+ ret = devm_request_irq(dev, irq, tmio_mmc_irq, IRQF_SHARED,
+ dev_name(dev), host);
+ if (ret)
+ goto free_host;
+
+ if (priv->caps & UNIPHIER_SD_CAP_EXTENDED_IP)
+ host->dma_ops = &uniphier_sd_internal_dma_ops;
+ else
+ host->dma_ops = &uniphier_sd_external_dma_ops;
+
+ host->bus_shift = 1;
+ host->clk_enable = uniphier_sd_clk_enable;
+ host->clk_disable = uniphier_sd_clk_disable;
+ host->set_clock = uniphier_sd_set_clock;
+
+ ret = uniphier_sd_clk_enable(host);
+ if (ret)
+ goto free_host;
+
+ uniphier_sd_host_init(host);
+
+ tmio_data->ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34;
+ if (host->mmc->caps & MMC_CAP_UHS)
+ tmio_data->ocr_mask |= MMC_VDD_165_195;
+
+ tmio_data->max_segs = 1;
+ tmio_data->max_blk_count = U16_MAX;
+
+ ret = tmio_mmc_host_probe(host);
+ if (ret)
+ goto free_host;
+
+ return 0;
+
+free_host:
+ tmio_mmc_host_free(host);
+
+ return ret;
+}
+
+static int uniphier_sd_remove(struct platform_device *pdev)
+{
+ struct tmio_mmc_host *host = platform_get_drvdata(pdev);
+
+ tmio_mmc_host_remove(host);
+ uniphier_sd_clk_disable(host);
+
+ return 0;
+}
+
+static const struct of_device_id uniphier_sd_match[] = {
+ {
+ .compatible = "socionext,uniphier-sd-v2.91",
+ },
+ {
+ .compatible = "socionext,uniphier-sd-v3.1",
+ .data = (void *)(UNIPHIER_SD_CAP_EXTENDED_IP |
+ UNIPHIER_SD_CAP_BROKEN_DMA_RX),
+ },
+ {
+ .compatible = "socionext,uniphier-sd-v3.1.1",
+ .data = (void *)UNIPHIER_SD_CAP_EXTENDED_IP,
+ },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, uniphier_sd_match);
+
+static struct platform_driver uniphier_sd_driver = {
+ .probe = uniphier_sd_probe,
+ .remove = uniphier_sd_remove,
+ .driver = {
+ .name = "uniphier-sd",
+ .of_match_table = uniphier_sd_match,
+ },
+};
+module_platform_driver(uniphier_sd_driver);
+
+MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
+MODULE_DESCRIPTION("UniPhier SD/eMMC host controller driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/usdhi6rol0.c b/drivers/mmc/host/usdhi6rol0.c
index cdfeb15b6f05..cd8b1b9d4d8a 100644
--- a/drivers/mmc/host/usdhi6rol0.c
+++ b/drivers/mmc/host/usdhi6rol0.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2013-2014 Renesas Electronics Europe Ltd.
* Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
*/
#include <linux/clk.h>
diff --git a/drivers/mtd/ar7part.c b/drivers/mtd/ar7part.c
index fc15ec58230a..0d33cf0842ad 100644
--- a/drivers/mtd/ar7part.c
+++ b/drivers/mtd/ar7part.c
@@ -25,7 +25,7 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
-#include <linux/bootmem.h>
+#include <linux/memblock.h>
#include <linux/module.h>
#include <uapi/linux/magic.h>
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index e514d57a0419..aa983422aa97 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -207,7 +207,7 @@ comment "Disk-On-Chip Device Drivers"
config MTD_DOCG3
tristate "M-Systems Disk-On-Chip G3"
select BCH
- select BCH_CONST_PARAMS
+ select BCH_CONST_PARAMS if !MTD_NAND_BCH
select BITREVERSE
help
This provides an MTD device driver for the M-Systems DiskOnChip
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 270d3c9580c5..c4a1d04b8c80 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -90,7 +90,6 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
SPI_MEM_OP_ADDR(nor->addr_width, to, 1),
SPI_MEM_OP_NO_DUMMY,
SPI_MEM_OP_DATA_OUT(len, buf, 1));
- size_t remaining = len;
int ret;
/* get transfer protocols. */
@@ -101,22 +100,16 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
op.addr.nbytes = 0;
- while (remaining) {
- op.data.nbytes = remaining < UINT_MAX ? remaining : UINT_MAX;
- ret = spi_mem_adjust_op_size(flash->spimem, &op);
- if (ret)
- return ret;
-
- ret = spi_mem_exec_op(flash->spimem, &op);
- if (ret)
- return ret;
+ ret = spi_mem_adjust_op_size(flash->spimem, &op);
+ if (ret)
+ return ret;
+ op.data.nbytes = len < op.data.nbytes ? len : op.data.nbytes;
- op.addr.val += op.data.nbytes;
- remaining -= op.data.nbytes;
- op.data.buf.out += op.data.nbytes;
- }
+ ret = spi_mem_exec_op(flash->spimem, &op);
+ if (ret)
+ return ret;
- return len;
+ return op.data.nbytes;
}
/*
diff --git a/drivers/mtd/maps/gpio-addr-flash.c b/drivers/mtd/maps/gpio-addr-flash.c
index 9d9723693217..a20e85aa770e 100644
--- a/drivers/mtd/maps/gpio-addr-flash.c
+++ b/drivers/mtd/maps/gpio-addr-flash.c
@@ -14,6 +14,7 @@
*/
#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -25,28 +26,24 @@
#include <linux/slab.h>
#include <linux/types.h>
-#define pr_devinit(fmt, args...) \
- ({ static const char __fmt[] = fmt; printk(__fmt, ## args); })
+#define win_mask(x) ((BIT(x)) - 1)
#define DRIVER_NAME "gpio-addr-flash"
-#define PFX DRIVER_NAME ": "
/**
* struct async_state - keep GPIO flash state
* @mtd: MTD state for this mapping
* @map: MTD map state for this flash
- * @gpio_count: number of GPIOs used to address
- * @gpio_addrs: array of GPIOs to twiddle
+ * @gpios: Struct containing the array of GPIO descriptors
* @gpio_values: cached GPIO values
- * @win_size: dedicated memory size (if no GPIOs)
+ * @win_order: dedicated memory size (if no GPIOs)
*/
struct async_state {
struct mtd_info *mtd;
struct map_info map;
- size_t gpio_count;
- unsigned *gpio_addrs;
- int *gpio_values;
- unsigned long win_size;
+ struct gpio_descs *gpios;
+ unsigned int gpio_values;
+ unsigned int win_order;
};
#define gf_map_info_to_state(mi) ((struct async_state *)(mi)->map_priv_1)
@@ -57,21 +54,25 @@ struct async_state {
*
* Rather than call the GPIO framework every time, cache the last-programmed
* value. This speeds up sequential accesses (which are by far the most common
- * type). We rely on the GPIO framework to treat non-zero value as high so
- * that we don't have to normalize the bits.
+ * type).
*/
static void gf_set_gpios(struct async_state *state, unsigned long ofs)
{
- size_t i = 0;
- int value;
- ofs /= state->win_size;
- do {
- value = ofs & (1 << i);
- if (state->gpio_values[i] != value) {
- gpio_set_value(state->gpio_addrs[i], value);
- state->gpio_values[i] = value;
- }
- } while (++i < state->gpio_count);
+ int i;
+
+ ofs >>= state->win_order;
+
+ if (ofs == state->gpio_values)
+ return;
+
+ for (i = 0; i < state->gpios->ndescs; i++) {
+ if ((ofs & BIT(i)) == (state->gpio_values & BIT(i)))
+ continue;
+
+ gpiod_set_value(state->gpios->desc[i], !!(ofs & BIT(i)));
+ }
+
+ state->gpio_values = ofs;
}
/**
@@ -87,7 +88,7 @@ static map_word gf_read(struct map_info *map, unsigned long ofs)
gf_set_gpios(state, ofs);
- word = readw(map->virt + (ofs % state->win_size));
+ word = readw(map->virt + (ofs & win_mask(state->win_order)));
test.x[0] = word;
return test;
}
@@ -109,14 +110,14 @@ static void gf_copy_from(struct map_info *map, void *to, unsigned long from, ssi
int this_len;
while (len) {
- if ((from % state->win_size) + len > state->win_size)
- this_len = state->win_size - (from % state->win_size);
- else
- this_len = len;
+ this_len = from & win_mask(state->win_order);
+ this_len = BIT(state->win_order) - this_len;
+ this_len = min_t(int, len, this_len);
gf_set_gpios(state, from);
- memcpy_fromio(to, map->virt + (from % state->win_size),
- this_len);
+ memcpy_fromio(to,
+ map->virt + (from & win_mask(state->win_order)),
+ this_len);
len -= this_len;
from += this_len;
to += this_len;
@@ -136,7 +137,7 @@ static void gf_write(struct map_info *map, map_word d1, unsigned long ofs)
gf_set_gpios(state, ofs);
d = d1.x[0];
- writew(d, map->virt + (ofs % state->win_size));
+ writew(d, map->virt + (ofs & win_mask(state->win_order)));
}
/**
@@ -156,13 +157,13 @@ static void gf_copy_to(struct map_info *map, unsigned long to,
int this_len;
while (len) {
- if ((to % state->win_size) + len > state->win_size)
- this_len = state->win_size - (to % state->win_size);
- else
- this_len = len;
+ this_len = to & win_mask(state->win_order);
+ this_len = BIT(state->win_order) - this_len;
+ this_len = min_t(int, len, this_len);
gf_set_gpios(state, to);
- memcpy_toio(map->virt + (to % state->win_size), from, len);
+ memcpy_toio(map->virt + (to & win_mask(state->win_order)),
+ from, len);
len -= this_len;
to += this_len;
@@ -180,18 +181,22 @@ static const char * const part_probe_types[] = {
* The platform resource layout expected looks something like:
* struct mtd_partition partitions[] = { ... };
* struct physmap_flash_data flash_data = { ... };
- * unsigned flash_gpios[] = { GPIO_XX, GPIO_XX, ... };
+ * static struct gpiod_lookup_table addr_flash_gpios = {
+ * .dev_id = "gpio-addr-flash.0",
+ * .table = {
+ * GPIO_LOOKUP_IDX("gpio.0", 15, "addr", 0, GPIO_ACTIVE_HIGH),
+ * GPIO_LOOKUP_IDX("gpio.0", 16, "addr", 1, GPIO_ACTIVE_HIGH),
+ * );
+ * };
+ * gpiod_add_lookup_table(&addr_flash_gpios);
+ *
* struct resource flash_resource[] = {
* {
* .name = "cfi_probe",
* .start = 0x20000000,
* .end = 0x201fffff,
* .flags = IORESOURCE_MEM,
- * }, {
- * .start = (unsigned long)flash_gpios,
- * .end = ARRAY_SIZE(flash_gpios),
- * .flags = IORESOURCE_IRQ,
- * }
+ * },
* };
* struct platform_device flash_device = {
* .name = "gpio-addr-flash",
@@ -203,33 +208,25 @@ static const char * const part_probe_types[] = {
*/
static int gpio_flash_probe(struct platform_device *pdev)
{
- size_t i, arr_size;
struct physmap_flash_data *pdata;
struct resource *memory;
- struct resource *gpios;
struct async_state *state;
pdata = dev_get_platdata(&pdev->dev);
memory = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- gpios = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!memory || !gpios || !gpios->end)
+ if (!memory)
return -EINVAL;
- arr_size = sizeof(int) * gpios->end;
- state = kzalloc(sizeof(*state) + arr_size, GFP_KERNEL);
+ state = devm_kzalloc(&pdev->dev, sizeof(*state), GFP_KERNEL);
if (!state)
return -ENOMEM;
- /*
- * We cast start/end to known types in the boards file, so cast
- * away their pointer types here to the known types (gpios->xxx).
- */
- state->gpio_count = gpios->end;
- state->gpio_addrs = (void *)(unsigned long)gpios->start;
- state->gpio_values = (void *)(state + 1);
- state->win_size = resource_size(memory);
- memset(state->gpio_values, 0xff, arr_size);
+ state->gpios = devm_gpiod_get_array(&pdev->dev, "addr", GPIOD_OUT_LOW);
+ if (IS_ERR(state->gpios))
+ return PTR_ERR(state->gpios);
+
+ state->win_order = get_bitmask_order(resource_size(memory)) - 1;
state->map.name = DRIVER_NAME;
state->map.read = gf_read;
@@ -237,38 +234,21 @@ static int gpio_flash_probe(struct platform_device *pdev)
state->map.write = gf_write;
state->map.copy_to = gf_copy_to;
state->map.bankwidth = pdata->width;
- state->map.size = state->win_size * (1 << state->gpio_count);
- state->map.virt = ioremap_nocache(memory->start, state->map.size);
- if (!state->map.virt)
- return -ENOMEM;
+ state->map.size = BIT(state->win_order + state->gpios->ndescs);
+ state->map.virt = devm_ioremap_resource(&pdev->dev, memory);
+ if (IS_ERR(state->map.virt))
+ return PTR_ERR(state->map.virt);
state->map.phys = NO_XIP;
state->map.map_priv_1 = (unsigned long)state;
platform_set_drvdata(pdev, state);
- i = 0;
- do {
- if (gpio_request(state->gpio_addrs[i], DRIVER_NAME)) {
- pr_devinit(KERN_ERR PFX "failed to request gpio %d\n",
- state->gpio_addrs[i]);
- while (i--)
- gpio_free(state->gpio_addrs[i]);
- kfree(state);
- return -EBUSY;
- }
- gpio_direction_output(state->gpio_addrs[i], 0);
- } while (++i < state->gpio_count);
-
- pr_devinit(KERN_NOTICE PFX "probing %d-bit flash bus\n",
- state->map.bankwidth * 8);
+ dev_notice(&pdev->dev, "probing %d-bit flash bus\n",
+ state->map.bankwidth * 8);
state->mtd = do_map_probe(memory->name, &state->map);
- if (!state->mtd) {
- for (i = 0; i < state->gpio_count; ++i)
- gpio_free(state->gpio_addrs[i]);
- kfree(state);
+ if (!state->mtd)
return -ENXIO;
- }
state->mtd->dev.parent = &pdev->dev;
mtd_device_parse_register(state->mtd, part_probe_types, NULL,
@@ -280,13 +260,9 @@ static int gpio_flash_probe(struct platform_device *pdev)
static int gpio_flash_remove(struct platform_device *pdev)
{
struct async_state *state = platform_get_drvdata(pdev);
- size_t i = 0;
- do {
- gpio_free(state->gpio_addrs[i]);
- } while (++i < state->gpio_count);
+
mtd_device_unregister(state->mtd);
map_destroy(state->mtd);
- kfree(state);
return 0;
}
diff --git a/drivers/mtd/maps/physmap_of_core.c b/drivers/mtd/maps/physmap_of_core.c
index 4129535b8e46..ece605d78c21 100644
--- a/drivers/mtd/maps/physmap_of_core.c
+++ b/drivers/mtd/maps/physmap_of_core.c
@@ -31,7 +31,6 @@
struct of_flash_list {
struct mtd_info *mtd;
struct map_info map;
- struct resource *res;
};
struct of_flash {
@@ -56,18 +55,10 @@ static int of_flash_remove(struct platform_device *dev)
mtd_concat_destroy(info->cmtd);
}
- for (i = 0; i < info->list_size; i++) {
+ for (i = 0; i < info->list_size; i++)
if (info->list[i].mtd)
map_destroy(info->list[i].mtd);
- if (info->list[i].map.virt)
- iounmap(info->list[i].map.virt);
-
- if (info->list[i].res) {
- release_resource(info->list[i].res);
- kfree(info->list[i].res);
- }
- }
return 0;
}
@@ -215,10 +206,11 @@ static int of_flash_probe(struct platform_device *dev)
err = -EBUSY;
res_size = resource_size(&res);
- info->list[i].res = request_mem_region(res.start, res_size,
- dev_name(&dev->dev));
- if (!info->list[i].res)
+ info->list[i].map.virt = devm_ioremap_resource(&dev->dev, &res);
+ if (IS_ERR(info->list[i].map.virt)) {
+ err = PTR_ERR(info->list[i].map.virt);
goto err_out;
+ }
err = -ENXIO;
width = of_get_property(dp, "bank-width", NULL);
@@ -246,15 +238,6 @@ static int of_flash_probe(struct platform_device *dev)
if (err)
goto err_out;
- err = -ENOMEM;
- info->list[i].map.virt = ioremap(info->list[i].map.phys,
- info->list[i].map.size);
- if (!info->list[i].map.virt) {
- dev_err(&dev->dev, "Failed to ioremap() flash"
- " region\n");
- goto err_out;
- }
-
simple_map_init(&info->list[i].map);
/*
diff --git a/drivers/mtd/maps/physmap_of_gemini.c b/drivers/mtd/maps/physmap_of_gemini.c
index 830b1b7e702b..9df62ca721d5 100644
--- a/drivers/mtd/maps/physmap_of_gemini.c
+++ b/drivers/mtd/maps/physmap_of_gemini.c
@@ -44,11 +44,6 @@
#define FLASH_PARALLEL_HIGH_PIN_CNT (1 << 20) /* else low pin cnt */
-static const struct of_device_id syscon_match[] = {
- { .compatible = "cortina,gemini-syscon" },
- { },
-};
-
int of_flash_probe_gemini(struct platform_device *pdev,
struct device_node *np,
struct map_info *map)
diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c
index 784c6e1a0391..fd5fe12d7461 100644
--- a/drivers/mtd/maps/sa1100-flash.c
+++ b/drivers/mtd/maps/sa1100-flash.c
@@ -221,7 +221,14 @@ static struct sa_info *sa1100_setup_mtd(struct platform_device *pdev,
info->mtd = info->subdev[0].mtd;
ret = 0;
} else if (info->num_subdev > 1) {
- struct mtd_info *cdev[nr];
+ struct mtd_info **cdev;
+
+ cdev = kmalloc_array(nr, sizeof(*cdev), GFP_KERNEL);
+ if (!cdev) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
/*
* We detected multiple devices. Concatenate them together.
*/
@@ -230,6 +237,7 @@ static struct sa_info *sa1100_setup_mtd(struct platform_device *pdev,
info->mtd = mtd_concat_create(cdev, info->num_subdev,
plat->name);
+ kfree(cdev);
if (info->mtd == NULL) {
ret = -ENXIO;
goto err;
diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c
index 29c0bfd74e8a..b0d44f9214b0 100644
--- a/drivers/mtd/mtd_blkdevs.c
+++ b/drivers/mtd/mtd_blkdevs.c
@@ -27,6 +27,7 @@
#include <linux/mtd/blktrans.h>
#include <linux/mtd/mtd.h>
#include <linux/blkdev.h>
+#include <linux/blk-mq.h>
#include <linux/blkpg.h>
#include <linux/spinlock.h>
#include <linux/hdreg.h>
@@ -45,6 +46,8 @@ static void blktrans_dev_release(struct kref *kref)
dev->disk->private_data = NULL;
blk_cleanup_queue(dev->rq);
+ blk_mq_free_tag_set(dev->tag_set);
+ kfree(dev->tag_set);
put_disk(dev->disk);
list_del(&dev->list);
kfree(dev);
@@ -134,28 +137,39 @@ int mtd_blktrans_cease_background(struct mtd_blktrans_dev *dev)
}
EXPORT_SYMBOL_GPL(mtd_blktrans_cease_background);
-static void mtd_blktrans_work(struct work_struct *work)
+static struct request *mtd_next_request(struct mtd_blktrans_dev *dev)
+{
+ struct request *rq;
+
+ rq = list_first_entry_or_null(&dev->rq_list, struct request, queuelist);
+ if (rq) {
+ list_del_init(&rq->queuelist);
+ blk_mq_start_request(rq);
+ return rq;
+ }
+
+ return NULL;
+}
+
+static void mtd_blktrans_work(struct mtd_blktrans_dev *dev)
+ __releases(&dev->queue_lock)
+ __acquires(&dev->queue_lock)
{
- struct mtd_blktrans_dev *dev =
- container_of(work, struct mtd_blktrans_dev, work);
struct mtd_blktrans_ops *tr = dev->tr;
- struct request_queue *rq = dev->rq;
struct request *req = NULL;
int background_done = 0;
- spin_lock_irq(rq->queue_lock);
-
while (1) {
blk_status_t res;
dev->bg_stop = false;
- if (!req && !(req = blk_fetch_request(rq))) {
+ if (!req && !(req = mtd_next_request(dev))) {
if (tr->background && !background_done) {
- spin_unlock_irq(rq->queue_lock);
+ spin_unlock_irq(&dev->queue_lock);
mutex_lock(&dev->lock);
tr->background(dev);
mutex_unlock(&dev->lock);
- spin_lock_irq(rq->queue_lock);
+ spin_lock_irq(&dev->queue_lock);
/*
* Do background processing just once per idle
* period.
@@ -166,35 +180,39 @@ static void mtd_blktrans_work(struct work_struct *work)
break;
}
- spin_unlock_irq(rq->queue_lock);
+ spin_unlock_irq(&dev->queue_lock);
mutex_lock(&dev->lock);
res = do_blktrans_request(dev->tr, dev, req);
mutex_unlock(&dev->lock);
- spin_lock_irq(rq->queue_lock);
-
- if (!__blk_end_request_cur(req, res))
+ if (!blk_update_request(req, res, blk_rq_cur_bytes(req))) {
+ __blk_mq_end_request(req, res);
req = NULL;
+ }
background_done = 0;
+ spin_lock_irq(&dev->queue_lock);
}
-
- spin_unlock_irq(rq->queue_lock);
}
-static void mtd_blktrans_request(struct request_queue *rq)
+static blk_status_t mtd_queue_rq(struct blk_mq_hw_ctx *hctx,
+ const struct blk_mq_queue_data *bd)
{
struct mtd_blktrans_dev *dev;
- struct request *req = NULL;
- dev = rq->queuedata;
+ dev = hctx->queue->queuedata;
+ if (!dev) {
+ blk_mq_start_request(bd->rq);
+ return BLK_STS_IOERR;
+ }
+
+ spin_lock_irq(&dev->queue_lock);
+ list_add_tail(&bd->rq->queuelist, &dev->rq_list);
+ mtd_blktrans_work(dev);
+ spin_unlock_irq(&dev->queue_lock);
- if (!dev)
- while ((req = blk_fetch_request(rq)) != NULL)
- __blk_end_request_all(req, BLK_STS_IOERR);
- else
- queue_work(dev->wq, &dev->work);
+ return BLK_STS_OK;
}
static int blktrans_open(struct block_device *bdev, fmode_t mode)
@@ -329,6 +347,10 @@ static const struct block_device_operations mtd_block_ops = {
.getgeo = blktrans_getgeo,
};
+static const struct blk_mq_ops mtd_mq_ops = {
+ .queue_rq = mtd_queue_rq,
+};
+
int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
{
struct mtd_blktrans_ops *tr = new->tr;
@@ -416,11 +438,20 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
/* Create the request queue */
spin_lock_init(&new->queue_lock);
- new->rq = blk_init_queue(mtd_blktrans_request, &new->queue_lock);
+ INIT_LIST_HEAD(&new->rq_list);
- if (!new->rq)
+ 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);
@@ -437,17 +468,10 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
gd->queue = new->rq;
- /* Create processing workqueue */
- new->wq = alloc_workqueue("%s%d", 0, 0,
- tr->name, new->mtd->index);
- if (!new->wq)
- goto error4;
- INIT_WORK(&new->work, mtd_blktrans_work);
-
if (new->readonly)
set_disk_ro(gd, 1);
- device_add_disk(&new->mtd->dev, gd);
+ device_add_disk(&new->mtd->dev, gd, NULL);
if (new->disk_attributes) {
ret = sysfs_create_group(&disk_to_dev(gd)->kobj,
@@ -456,7 +480,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
}
return 0;
error4:
- blk_cleanup_queue(new->rq);
+ kfree(new->tag_set);
error3:
put_disk(new->disk);
error2:
@@ -481,15 +505,17 @@ int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old)
/* Stop new requests to arrive */
del_gendisk(old->disk);
- /* Stop workqueue. This will perform any pending request. */
- destroy_workqueue(old->wq);
-
/* Kill current requests */
spin_lock_irqsave(&old->queue_lock, flags);
old->rq->queuedata = NULL;
- blk_start_queue(old->rq);
spin_unlock_irqrestore(&old->queue_lock, flags);
+ /* freeze+quiesce queue to ensure all requests are flushed */
+ blk_mq_freeze_queue(old->rq);
+ blk_mq_quiesce_queue(old->rq);
+ blk_mq_unquiesce_queue(old->rq);
+ blk_mq_unfreeze_queue(old->rq);
+
/* If the device is currently open, tell trans driver to close it,
then put mtd device, and don't touch it again */
mutex_lock(&old->lock);
diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
index 5fc9a1bde4ac..c7efc31384d5 100644
--- a/drivers/mtd/nand/raw/Kconfig
+++ b/drivers/mtd/nand/raw/Kconfig
@@ -227,26 +227,6 @@ config MTD_NAND_DISKONCHIP_BBTWRITE
load time (assuming you build diskonchip as a module) with the module
parameter "inftl_bbt_write=1".
-config MTD_NAND_DOCG4
- tristate "Support for DiskOnChip G4"
- depends on HAS_IOMEM
- select BCH
- select BITREVERSE
- help
- Support for diskonchip G4 nand flash, found in various smartphones and
- PDAs, among them the Palm Treo680, HTC Prophet and Wizard, Toshiba
- Portege G900, Asus P526, and O2 XDA Zinc.
-
- With this driver you will be able to use UBI and create a ubifs on the
- device, so you may wish to consider enabling UBI and UBIFS as well.
-
- These devices ship with the Mys/Sandisk SAFTL formatting, for which
- there is currently no mtd parser, so you may want to use command line
- partitioning to segregate write-protected blocks. On the Treo680, the
- first five erase blocks (256KiB each) are write-protected, followed
- by the block containing the saftl partition table. This is probably
- typical.
-
config MTD_NAND_SHARPSL
tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)"
depends on ARCH_PXA || COMPILE_TEST
diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile
index d5a5f9832b88..57159b349054 100644
--- a/drivers/mtd/nand/raw/Makefile
+++ b/drivers/mtd/nand/raw/Makefile
@@ -15,7 +15,6 @@ obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o
obj-$(CONFIG_MTD_NAND_TANGO) += tango_nand.o
obj-$(CONFIG_MTD_NAND_DAVINCI) += davinci_nand.o
obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o
-obj-$(CONFIG_MTD_NAND_DOCG4) += docg4.o
obj-$(CONFIG_MTD_NAND_FSMC) += fsmc_nand.o
obj-$(CONFIG_MTD_NAND_SHARPSL) += sharpsl.o
obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o
@@ -58,8 +57,11 @@ obj-$(CONFIG_MTD_NAND_QCOM) += qcom_nandc.o
obj-$(CONFIG_MTD_NAND_MTK) += mtk_ecc.o mtk_nand.o
obj-$(CONFIG_MTD_NAND_TEGRA) += tegra_nand.o
-nand-objs := nand_base.o nand_bbt.o nand_timings.o nand_ids.o
+nand-objs := nand_base.o nand_legacy.o nand_bbt.o nand_timings.o nand_ids.o
+nand-objs += nand_onfi.o
+nand-objs += nand_jedec.o
nand-objs += nand_amd.o
+nand-objs += nand_esmt.o
nand-objs += nand_hynix.o
nand-objs += nand_macronix.o
nand-objs += nand_micron.o
diff --git a/drivers/mtd/nand/raw/ams-delta.c b/drivers/mtd/nand/raw/ams-delta.c
index 37a3cc21c7bc..5ba180a291eb 100644
--- a/drivers/mtd/nand/raw/ams-delta.c
+++ b/drivers/mtd/nand/raw/ams-delta.c
@@ -20,23 +20,33 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/rawnand.h>
#include <linux/mtd/partitions.h>
-#include <linux/gpio.h>
#include <linux/platform_data/gpio-omap.h>
#include <asm/io.h>
#include <asm/sizes.h>
-#include <mach/board-ams-delta.h>
-
#include <mach/hardware.h>
/*
* MTD structure for E3 (Delta)
*/
-static struct mtd_info *ams_delta_mtd = NULL;
+
+struct ams_delta_nand {
+ struct nand_chip nand_chip;
+ struct gpio_desc *gpiod_rdy;
+ struct gpio_desc *gpiod_nce;
+ struct gpio_desc *gpiod_nre;
+ struct gpio_desc *gpiod_nwp;
+ struct gpio_desc *gpiod_nwe;
+ struct gpio_desc *gpiod_ale;
+ struct gpio_desc *gpiod_cle;
+ void __iomem *io_base;
+ bool data_in;
+};
/*
* Define partitions for flash devices
@@ -63,48 +73,64 @@ static const struct mtd_partition partition_info[] = {
.size = 3 * SZ_256K },
};
-static void ams_delta_write_byte(struct mtd_info *mtd, u_char byte)
+static void ams_delta_io_write(struct ams_delta_nand *priv, u_char byte)
{
- struct nand_chip *this = mtd_to_nand(mtd);
- void __iomem *io_base = (void __iomem *)nand_get_controller_data(this);
-
- writew(0, io_base + OMAP_MPUIO_IO_CNTL);
- writew(byte, this->IO_ADDR_W);
- gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NWE, 0);
+ writew(byte, priv->nand_chip.legacy.IO_ADDR_W);
+ gpiod_set_value(priv->gpiod_nwe, 0);
ndelay(40);
- gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NWE, 1);
+ gpiod_set_value(priv->gpiod_nwe, 1);
}
-static u_char ams_delta_read_byte(struct mtd_info *mtd)
+static u_char ams_delta_io_read(struct ams_delta_nand *priv)
{
u_char res;
- struct nand_chip *this = mtd_to_nand(mtd);
- void __iomem *io_base = (void __iomem *)nand_get_controller_data(this);
- gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NRE, 0);
+ gpiod_set_value(priv->gpiod_nre, 0);
ndelay(40);
- writew(~0, io_base + OMAP_MPUIO_IO_CNTL);
- res = readw(this->IO_ADDR_R);
- gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NRE, 1);
+ res = readw(priv->nand_chip.legacy.IO_ADDR_R);
+ gpiod_set_value(priv->gpiod_nre, 1);
return res;
}
-static void ams_delta_write_buf(struct mtd_info *mtd, const u_char *buf,
+static void ams_delta_dir_input(struct ams_delta_nand *priv, bool in)
+{
+ writew(in ? ~0 : 0, priv->io_base + OMAP_MPUIO_IO_CNTL);
+ priv->data_in = in;
+}
+
+static void ams_delta_write_buf(struct nand_chip *this, const u_char *buf,
int len)
{
+ struct ams_delta_nand *priv = nand_get_controller_data(this);
int i;
- for (i=0; i<len; i++)
- ams_delta_write_byte(mtd, buf[i]);
+ if (priv->data_in)
+ ams_delta_dir_input(priv, false);
+
+ for (i = 0; i < len; i++)
+ ams_delta_io_write(priv, buf[i]);
}
-static void ams_delta_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void ams_delta_read_buf(struct nand_chip *this, u_char *buf, int len)
{
+ struct ams_delta_nand *priv = nand_get_controller_data(this);
int i;
- for (i=0; i<len; i++)
- buf[i] = ams_delta_read_byte(mtd);
+ if (!priv->data_in)
+ ams_delta_dir_input(priv, true);
+
+ for (i = 0; i < len; i++)
+ buf[i] = ams_delta_io_read(priv);
+}
+
+static u_char ams_delta_read_byte(struct nand_chip *this)
+{
+ u_char res;
+
+ ams_delta_read_buf(this, &res, 1);
+
+ return res;
}
/*
@@ -115,67 +141,40 @@ static void ams_delta_read_buf(struct mtd_info *mtd, u_char *buf, int len)
* NAND_CLE: bit 1 -> bit 7
* NAND_ALE: bit 2 -> bit 6
*/
-static void ams_delta_hwcontrol(struct mtd_info *mtd, int cmd,
+static void ams_delta_hwcontrol(struct nand_chip *this, int cmd,
unsigned int ctrl)
{
+ struct ams_delta_nand *priv = nand_get_controller_data(this);
if (ctrl & NAND_CTRL_CHANGE) {
- gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NCE,
- (ctrl & NAND_NCE) == 0);
- gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_CLE,
- (ctrl & NAND_CLE) != 0);
- gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_ALE,
- (ctrl & NAND_ALE) != 0);
+ gpiod_set_value(priv->gpiod_nce, !(ctrl & NAND_NCE));
+ gpiod_set_value(priv->gpiod_cle, !!(ctrl & NAND_CLE));
+ gpiod_set_value(priv->gpiod_ale, !!(ctrl & NAND_ALE));
}
- if (cmd != NAND_CMD_NONE)
- ams_delta_write_byte(mtd, cmd);
+ if (cmd != NAND_CMD_NONE) {
+ u_char byte = cmd;
+
+ ams_delta_write_buf(this, &byte, 1);
+ }
}
-static int ams_delta_nand_ready(struct mtd_info *mtd)
+static int ams_delta_nand_ready(struct nand_chip *this)
{
- return gpio_get_value(AMS_DELTA_GPIO_PIN_NAND_RB);
+ struct ams_delta_nand *priv = nand_get_controller_data(this);
+
+ return gpiod_get_value(priv->gpiod_rdy);
}
-static const struct gpio _mandatory_gpio[] = {
- {
- .gpio = AMS_DELTA_GPIO_PIN_NAND_NCE,
- .flags = GPIOF_OUT_INIT_HIGH,
- .label = "nand_nce",
- },
- {
- .gpio = AMS_DELTA_GPIO_PIN_NAND_NRE,
- .flags = GPIOF_OUT_INIT_HIGH,
- .label = "nand_nre",
- },
- {
- .gpio = AMS_DELTA_GPIO_PIN_NAND_NWP,
- .flags = GPIOF_OUT_INIT_HIGH,
- .label = "nand_nwp",
- },
- {
- .gpio = AMS_DELTA_GPIO_PIN_NAND_NWE,
- .flags = GPIOF_OUT_INIT_HIGH,
- .label = "nand_nwe",
- },
- {
- .gpio = AMS_DELTA_GPIO_PIN_NAND_ALE,
- .flags = GPIOF_OUT_INIT_LOW,
- .label = "nand_ale",
- },
- {
- .gpio = AMS_DELTA_GPIO_PIN_NAND_CLE,
- .flags = GPIOF_OUT_INIT_LOW,
- .label = "nand_cle",
- },
-};
/*
* Main initialization routine
*/
static int ams_delta_init(struct platform_device *pdev)
{
+ struct ams_delta_nand *priv;
struct nand_chip *this;
+ struct mtd_info *mtd;
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
void __iomem *io_base;
int err = 0;
@@ -184,15 +183,16 @@ static int ams_delta_init(struct platform_device *pdev)
return -ENXIO;
/* Allocate memory for MTD device structure and private data */
- this = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
- if (!this) {
+ priv = devm_kzalloc(&pdev->dev, sizeof(struct ams_delta_nand),
+ GFP_KERNEL);
+ if (!priv) {
pr_warn("Unable to allocate E3 NAND MTD device structure.\n");
- err = -ENOMEM;
- goto out;
+ return -ENOMEM;
}
+ this = &priv->nand_chip;
- ams_delta_mtd = nand_to_mtd(this);
- ams_delta_mtd->owner = THIS_MODULE;
+ mtd = nand_to_mtd(this);
+ mtd->dev.parent = &pdev->dev;
/*
* Don't try to request the memory region from here,
@@ -207,51 +207,93 @@ static int ams_delta_init(struct platform_device *pdev)
goto out_free;
}
- nand_set_controller_data(this, (void *)io_base);
+ priv->io_base = io_base;
+ nand_set_controller_data(this, priv);
/* Set address of NAND IO lines */
- this->IO_ADDR_R = io_base + OMAP_MPUIO_INPUT_LATCH;
- this->IO_ADDR_W = io_base + OMAP_MPUIO_OUTPUT;
- this->read_byte = ams_delta_read_byte;
- this->write_buf = ams_delta_write_buf;
- this->read_buf = ams_delta_read_buf;
- this->cmd_ctrl = ams_delta_hwcontrol;
- if (gpio_request(AMS_DELTA_GPIO_PIN_NAND_RB, "nand_rdy") == 0) {
- this->dev_ready = ams_delta_nand_ready;
- } else {
- this->dev_ready = NULL;
- pr_notice("Couldn't request gpio for Delta NAND ready.\n");
+ this->legacy.IO_ADDR_R = io_base + OMAP_MPUIO_INPUT_LATCH;
+ this->legacy.IO_ADDR_W = io_base + OMAP_MPUIO_OUTPUT;
+ this->legacy.read_byte = ams_delta_read_byte;
+ this->legacy.write_buf = ams_delta_write_buf;
+ this->legacy.read_buf = ams_delta_read_buf;
+ this->legacy.cmd_ctrl = ams_delta_hwcontrol;
+
+ priv->gpiod_rdy = devm_gpiod_get_optional(&pdev->dev, "rdy", GPIOD_IN);
+ if (IS_ERR(priv->gpiod_rdy)) {
+ err = PTR_ERR(priv->gpiod_rdy);
+ dev_warn(&pdev->dev, "RDY GPIO request failed (%d)\n", err);
+ goto out_mtd;
}
+
+ if (priv->gpiod_rdy)
+ this->legacy.dev_ready = ams_delta_nand_ready;
+
/* 25 us command delay time */
- this->chip_delay = 30;
+ this->legacy.chip_delay = 30;
this->ecc.mode = NAND_ECC_SOFT;
this->ecc.algo = NAND_ECC_HAMMING;
- platform_set_drvdata(pdev, io_base);
+ platform_set_drvdata(pdev, priv);
/* Set chip enabled, but */
- err = gpio_request_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio));
- if (err)
- goto out_gpio;
+ priv->gpiod_nwp = devm_gpiod_get(&pdev->dev, "nwp", GPIOD_OUT_HIGH);
+ if (IS_ERR(priv->gpiod_nwp)) {
+ err = PTR_ERR(priv->gpiod_nwp);
+ dev_err(&pdev->dev, "NWP GPIO request failed (%d)\n", err);
+ goto out_mtd;
+ }
+
+ priv->gpiod_nce = devm_gpiod_get(&pdev->dev, "nce", GPIOD_OUT_HIGH);
+ if (IS_ERR(priv->gpiod_nce)) {
+ err = PTR_ERR(priv->gpiod_nce);
+ dev_err(&pdev->dev, "NCE GPIO request failed (%d)\n", err);
+ goto out_mtd;
+ }
+
+ priv->gpiod_nre = devm_gpiod_get(&pdev->dev, "nre", GPIOD_OUT_HIGH);
+ if (IS_ERR(priv->gpiod_nre)) {
+ err = PTR_ERR(priv->gpiod_nre);
+ dev_err(&pdev->dev, "NRE GPIO request failed (%d)\n", err);
+ goto out_mtd;
+ }
+
+ priv->gpiod_nwe = devm_gpiod_get(&pdev->dev, "nwe", GPIOD_OUT_HIGH);
+ if (IS_ERR(priv->gpiod_nwe)) {
+ err = PTR_ERR(priv->gpiod_nwe);
+ dev_err(&pdev->dev, "NWE GPIO request failed (%d)\n", err);
+ goto out_mtd;
+ }
+
+ priv->gpiod_ale = devm_gpiod_get(&pdev->dev, "ale", GPIOD_OUT_LOW);
+ if (IS_ERR(priv->gpiod_ale)) {
+ err = PTR_ERR(priv->gpiod_ale);
+ dev_err(&pdev->dev, "ALE GPIO request failed (%d)\n", err);
+ goto out_mtd;
+ }
+
+ priv->gpiod_cle = devm_gpiod_get(&pdev->dev, "cle", GPIOD_OUT_LOW);
+ if (IS_ERR(priv->gpiod_cle)) {
+ err = PTR_ERR(priv->gpiod_cle);
+ dev_err(&pdev->dev, "CLE GPIO request failed (%d)\n", err);
+ goto out_mtd;
+ }
+
+ /* Initialize data port direction to a known state */
+ ams_delta_dir_input(priv, true);
/* Scan to find existence of the device */
- err = nand_scan(ams_delta_mtd, 1);
+ err = nand_scan(this, 1);
if (err)
goto out_mtd;
/* Register the partitions */
- mtd_device_register(ams_delta_mtd, partition_info,
- ARRAY_SIZE(partition_info));
+ mtd_device_register(mtd, partition_info, ARRAY_SIZE(partition_info));
goto out;
out_mtd:
- gpio_free_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio));
-out_gpio:
- gpio_free(AMS_DELTA_GPIO_PIN_NAND_RB);
iounmap(io_base);
out_free:
- kfree(this);
out:
return err;
}
@@ -261,18 +303,15 @@ out_free:
*/
static int ams_delta_cleanup(struct platform_device *pdev)
{
- void __iomem *io_base = platform_get_drvdata(pdev);
+ struct ams_delta_nand *priv = platform_get_drvdata(pdev);
+ struct mtd_info *mtd = nand_to_mtd(&priv->nand_chip);
+ void __iomem *io_base = priv->io_base;
/* Release resources, unregister device */
- nand_release(ams_delta_mtd);
+ nand_release(mtd_to_nand(mtd));
- gpio_free_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio));
- gpio_free(AMS_DELTA_GPIO_PIN_NAND_RB);
iounmap(io_base);
- /* Free the MTD device structure */
- kfree(mtd_to_nand(ams_delta_mtd));
-
return 0;
}
diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c
index a068b214ebaa..fb33f6be7c4f 100644
--- a/drivers/mtd/nand/raw/atmel/nand-controller.c
+++ b/drivers/mtd/nand/raw/atmel/nand-controller.c
@@ -410,25 +410,15 @@ err:
return -EIO;
}
-static u8 atmel_nand_read_byte(struct mtd_info *mtd)
+static u8 atmel_nand_read_byte(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct atmel_nand *nand = to_atmel_nand(chip);
return ioread8(nand->activecs->io.virt);
}
-static u16 atmel_nand_read_word(struct mtd_info *mtd)
+static void atmel_nand_write_byte(struct nand_chip *chip, u8 byte)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
- struct atmel_nand *nand = to_atmel_nand(chip);
-
- return ioread16(nand->activecs->io.virt);
-}
-
-static void atmel_nand_write_byte(struct mtd_info *mtd, u8 byte)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct atmel_nand *nand = to_atmel_nand(chip);
if (chip->options & NAND_BUSWIDTH_16)
@@ -437,9 +427,8 @@ static void atmel_nand_write_byte(struct mtd_info *mtd, u8 byte)
iowrite8(byte, nand->activecs->io.virt);
}
-static void atmel_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+static void atmel_nand_read_buf(struct nand_chip *chip, u8 *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct atmel_nand *nand = to_atmel_nand(chip);
struct atmel_nand_controller *nc;
@@ -462,9 +451,8 @@ static void atmel_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
ioread8_rep(nand->activecs->io.virt, buf, len);
}
-static void atmel_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+static void atmel_nand_write_buf(struct nand_chip *chip, const u8 *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct atmel_nand *nand = to_atmel_nand(chip);
struct atmel_nand_controller *nc;
@@ -487,34 +475,31 @@ static void atmel_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
iowrite8_rep(nand->activecs->io.virt, buf, len);
}
-static int atmel_nand_dev_ready(struct mtd_info *mtd)
+static int atmel_nand_dev_ready(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct atmel_nand *nand = to_atmel_nand(chip);
return gpiod_get_value(nand->activecs->rb.gpio);
}
-static void atmel_nand_select_chip(struct mtd_info *mtd, int cs)
+static void atmel_nand_select_chip(struct nand_chip *chip, int cs)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct atmel_nand *nand = to_atmel_nand(chip);
if (cs < 0 || cs >= nand->numcs) {
nand->activecs = NULL;
- chip->dev_ready = NULL;
+ chip->legacy.dev_ready = NULL;
return;
}
nand->activecs = &nand->cs[cs];
if (nand->activecs->rb.type == ATMEL_NAND_GPIO_RB)
- chip->dev_ready = atmel_nand_dev_ready;
+ chip->legacy.dev_ready = atmel_nand_dev_ready;
}
-static int atmel_hsmc_nand_dev_ready(struct mtd_info *mtd)
+static int atmel_hsmc_nand_dev_ready(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct atmel_nand *nand = to_atmel_nand(chip);
struct atmel_hsmc_nand_controller *nc;
u32 status;
@@ -526,15 +511,15 @@ static int atmel_hsmc_nand_dev_ready(struct mtd_info *mtd)
return status & ATMEL_HSMC_NFC_SR_RBEDGE(nand->activecs->rb.id);
}
-static void atmel_hsmc_nand_select_chip(struct mtd_info *mtd, int cs)
+static void atmel_hsmc_nand_select_chip(struct nand_chip *chip, int cs)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct atmel_nand *nand = to_atmel_nand(chip);
struct atmel_hsmc_nand_controller *nc;
nc = to_hsmc_nand_controller(chip->controller);
- atmel_nand_select_chip(mtd, cs);
+ atmel_nand_select_chip(chip, cs);
if (!nand->activecs) {
regmap_write(nc->base.smc, ATMEL_HSMC_NFC_CTRL,
@@ -543,7 +528,7 @@ static void atmel_hsmc_nand_select_chip(struct mtd_info *mtd, int cs)
}
if (nand->activecs->rb.type == ATMEL_NAND_NATIVE_RB)
- chip->dev_ready = atmel_hsmc_nand_dev_ready;
+ chip->legacy.dev_ready = atmel_hsmc_nand_dev_ready;
regmap_update_bits(nc->base.smc, ATMEL_HSMC_NFC_CFG,
ATMEL_HSMC_NFC_CFG_PAGESIZE_MASK |
@@ -607,10 +592,9 @@ static int atmel_nfc_exec_op(struct atmel_hsmc_nand_controller *nc, bool poll)
return ret;
}
-static void atmel_hsmc_nand_cmd_ctrl(struct mtd_info *mtd, int dat,
+static void atmel_hsmc_nand_cmd_ctrl(struct nand_chip *chip, int dat,
unsigned int ctrl)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct atmel_nand *nand = to_atmel_nand(chip);
struct atmel_hsmc_nand_controller *nc;
@@ -634,10 +618,9 @@ static void atmel_hsmc_nand_cmd_ctrl(struct mtd_info *mtd, int dat,
}
}
-static void atmel_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+static void atmel_nand_cmd_ctrl(struct nand_chip *chip, int cmd,
unsigned int ctrl)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct atmel_nand *nand = to_atmel_nand(chip);
struct atmel_nand_controller *nc;
@@ -851,7 +834,7 @@ static int atmel_nand_pmecc_write_pg(struct nand_chip *chip, const u8 *buf,
if (ret)
return ret;
- atmel_nand_write_buf(mtd, buf, mtd->writesize);
+ atmel_nand_write_buf(chip, buf, mtd->writesize);
ret = atmel_nand_pmecc_generate_eccbytes(chip, raw);
if (ret) {
@@ -861,20 +844,18 @@ static int atmel_nand_pmecc_write_pg(struct nand_chip *chip, const u8 *buf,
atmel_nand_pmecc_disable(chip, raw);
- atmel_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+ atmel_nand_write_buf(chip, chip->oob_poi, mtd->oobsize);
return nand_prog_page_end_op(chip);
}
-static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
- struct nand_chip *chip, const u8 *buf,
+static int atmel_nand_pmecc_write_page(struct nand_chip *chip, const u8 *buf,
int oob_required, int page)
{
return atmel_nand_pmecc_write_pg(chip, buf, oob_required, page, false);
}
-static int atmel_nand_pmecc_write_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int atmel_nand_pmecc_write_page_raw(struct nand_chip *chip,
const u8 *buf, int oob_required,
int page)
{
@@ -893,8 +874,8 @@ static int atmel_nand_pmecc_read_pg(struct nand_chip *chip, u8 *buf,
if (ret)
return ret;
- atmel_nand_read_buf(mtd, buf, mtd->writesize);
- atmel_nand_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ atmel_nand_read_buf(chip, buf, mtd->writesize);
+ atmel_nand_read_buf(chip, chip->oob_poi, mtd->oobsize);
ret = atmel_nand_pmecc_correct_data(chip, buf, raw);
@@ -903,15 +884,13 @@ static int atmel_nand_pmecc_read_pg(struct nand_chip *chip, u8 *buf,
return ret;
}
-static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
- struct nand_chip *chip, u8 *buf,
+static int atmel_nand_pmecc_read_page(struct nand_chip *chip, u8 *buf,
int oob_required, int page)
{
return atmel_nand_pmecc_read_pg(chip, buf, oob_required, page, false);
}
-static int atmel_nand_pmecc_read_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip, u8 *buf,
+static int atmel_nand_pmecc_read_page_raw(struct nand_chip *chip, u8 *buf,
int oob_required, int page)
{
return atmel_nand_pmecc_read_pg(chip, buf, oob_required, page, true);
@@ -956,7 +935,7 @@ static int atmel_hsmc_nand_pmecc_write_pg(struct nand_chip *chip,
if (ret)
return ret;
- atmel_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+ atmel_nand_write_buf(chip, chip->oob_poi, mtd->oobsize);
nc->op.cmds[0] = NAND_CMD_PAGEPROG;
nc->op.ncmds = 1;
@@ -966,15 +945,14 @@ static int atmel_hsmc_nand_pmecc_write_pg(struct nand_chip *chip,
dev_err(nc->base.dev, "Failed to program NAND page (err = %d)\n",
ret);
- status = chip->waitfunc(mtd, chip);
+ status = chip->legacy.waitfunc(chip);
if (status & NAND_STATUS_FAIL)
return -EIO;
return ret;
}
-static int atmel_hsmc_nand_pmecc_write_page(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int atmel_hsmc_nand_pmecc_write_page(struct nand_chip *chip,
const u8 *buf, int oob_required,
int page)
{
@@ -982,8 +960,7 @@ static int atmel_hsmc_nand_pmecc_write_page(struct mtd_info *mtd,
false);
}
-static int atmel_hsmc_nand_pmecc_write_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int atmel_hsmc_nand_pmecc_write_page_raw(struct nand_chip *chip,
const u8 *buf,
int oob_required, int page)
{
@@ -1045,16 +1022,14 @@ static int atmel_hsmc_nand_pmecc_read_pg(struct nand_chip *chip, u8 *buf,
return ret;
}
-static int atmel_hsmc_nand_pmecc_read_page(struct mtd_info *mtd,
- struct nand_chip *chip, u8 *buf,
+static int atmel_hsmc_nand_pmecc_read_page(struct nand_chip *chip, u8 *buf,
int oob_required, int page)
{
return atmel_hsmc_nand_pmecc_read_pg(chip, buf, oob_required, page,
false);
}
-static int atmel_hsmc_nand_pmecc_read_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int atmel_hsmc_nand_pmecc_read_page_raw(struct nand_chip *chip,
u8 *buf, int oob_required,
int page)
{
@@ -1473,10 +1448,9 @@ static int atmel_hsmc_nand_setup_data_interface(struct atmel_nand *nand,
return 0;
}
-static int atmel_nand_setup_data_interface(struct mtd_info *mtd, int csline,
+static int atmel_nand_setup_data_interface(struct nand_chip *chip, int csline,
const struct nand_data_interface *conf)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct atmel_nand *nand = to_atmel_nand(chip);
struct atmel_nand_controller *nc;
@@ -1498,19 +1472,18 @@ static void atmel_nand_init(struct atmel_nand_controller *nc,
mtd->dev.parent = nc->dev;
nand->base.controller = &nc->base;
- chip->cmd_ctrl = atmel_nand_cmd_ctrl;
- chip->read_byte = atmel_nand_read_byte;
- chip->read_word = atmel_nand_read_word;
- chip->write_byte = atmel_nand_write_byte;
- chip->read_buf = atmel_nand_read_buf;
- chip->write_buf = atmel_nand_write_buf;
+ chip->legacy.cmd_ctrl = atmel_nand_cmd_ctrl;
+ chip->legacy.read_byte = atmel_nand_read_byte;
+ chip->legacy.write_byte = atmel_nand_write_byte;
+ chip->legacy.read_buf = atmel_nand_read_buf;
+ chip->legacy.write_buf = atmel_nand_write_buf;
chip->select_chip = atmel_nand_select_chip;
if (nc->mck && nc->caps->ops->setup_data_interface)
chip->setup_data_interface = atmel_nand_setup_data_interface;
/* Some NANDs require a longer delay than the default one (20us). */
- chip->chip_delay = 40;
+ chip->legacy.chip_delay = 40;
/*
* Use a bounce buffer when the buffer passed by the MTD user is not
@@ -1551,7 +1524,7 @@ static void atmel_hsmc_nand_init(struct atmel_nand_controller *nc,
atmel_nand_init(nc, nand);
/* Overload some methods for the HSMC controller. */
- chip->cmd_ctrl = atmel_hsmc_nand_cmd_ctrl;
+ chip->legacy.cmd_ctrl = atmel_hsmc_nand_cmd_ctrl;
chip->select_chip = atmel_hsmc_nand_select_chip;
}
@@ -1586,9 +1559,7 @@ static struct atmel_nand *atmel_nand_create(struct atmel_nand_controller *nc,
return ERR_PTR(-EINVAL);
}
- nand = devm_kzalloc(nc->dev,
- sizeof(*nand) + (numcs * sizeof(*nand->cs)),
- GFP_KERNEL);
+ nand = devm_kzalloc(nc->dev, struct_size(nand, cs, numcs), GFP_KERNEL);
if (!nand) {
dev_err(nc->dev, "Failed to allocate NAND object\n");
return ERR_PTR(-ENOMEM);
@@ -1694,7 +1665,7 @@ atmel_nand_controller_add_nand(struct atmel_nand_controller *nc,
nc->caps->ops->nand_init(nc, nand);
- ret = nand_scan(mtd, nand->numcs);
+ ret = nand_scan(chip, nand->numcs);
if (ret) {
dev_err(nc->dev, "NAND scan failed: %d\n", ret);
return ret;
@@ -2063,6 +2034,10 @@ atmel_hsmc_nand_controller_legacy_init(struct atmel_hsmc_nand_controller *nc)
nand_np = dev->of_node;
nfc_np = of_find_compatible_node(dev->of_node, NULL,
"atmel,sama5d3-nfc");
+ if (!nfc_np) {
+ dev_err(dev, "Could not find device node for sama5d3-nfc\n");
+ return -ENODEV;
+ }
nc->clk = of_clk_get(nfc_np, 0);
if (IS_ERR(nc->clk)) {
diff --git a/drivers/mtd/nand/raw/au1550nd.c b/drivers/mtd/nand/raw/au1550nd.c
index 35f5c84cd331..9731c1c487f6 100644
--- a/drivers/mtd/nand/raw/au1550nd.c
+++ b/drivers/mtd/nand/raw/au1550nd.c
@@ -24,134 +24,113 @@ struct au1550nd_ctx {
int cs;
void __iomem *base;
- void (*write_byte)(struct mtd_info *, u_char);
+ void (*write_byte)(struct nand_chip *, u_char);
};
/**
* au_read_byte - read one byte from the chip
- * @mtd: MTD device structure
+ * @this: NAND chip object
*
* read function for 8bit buswidth
*/
-static u_char au_read_byte(struct mtd_info *mtd)
+static u_char au_read_byte(struct nand_chip *this)
{
- struct nand_chip *this = mtd_to_nand(mtd);
- u_char ret = readb(this->IO_ADDR_R);
+ u_char ret = readb(this->legacy.IO_ADDR_R);
wmb(); /* drain writebuffer */
return ret;
}
/**
* au_write_byte - write one byte to the chip
- * @mtd: MTD device structure
+ * @this: NAND chip object
* @byte: pointer to data byte to write
*
* write function for 8it buswidth
*/
-static void au_write_byte(struct mtd_info *mtd, u_char byte)
+static void au_write_byte(struct nand_chip *this, u_char byte)
{
- struct nand_chip *this = mtd_to_nand(mtd);
- writeb(byte, this->IO_ADDR_W);
+ writeb(byte, this->legacy.IO_ADDR_W);
wmb(); /* drain writebuffer */
}
/**
* au_read_byte16 - read one byte endianness aware from the chip
- * @mtd: MTD device structure
+ * @this: NAND chip object
*
* read function for 16bit buswidth with endianness conversion
*/
-static u_char au_read_byte16(struct mtd_info *mtd)
+static u_char au_read_byte16(struct nand_chip *this)
{
- struct nand_chip *this = mtd_to_nand(mtd);
- u_char ret = (u_char) cpu_to_le16(readw(this->IO_ADDR_R));
+ u_char ret = (u_char) cpu_to_le16(readw(this->legacy.IO_ADDR_R));
wmb(); /* drain writebuffer */
return ret;
}
/**
* au_write_byte16 - write one byte endianness aware to the chip
- * @mtd: MTD device structure
+ * @this: NAND chip object
* @byte: pointer to data byte to write
*
* write function for 16bit buswidth with endianness conversion
*/
-static void au_write_byte16(struct mtd_info *mtd, u_char byte)
+static void au_write_byte16(struct nand_chip *this, u_char byte)
{
- struct nand_chip *this = mtd_to_nand(mtd);
- writew(le16_to_cpu((u16) byte), this->IO_ADDR_W);
+ writew(le16_to_cpu((u16) byte), this->legacy.IO_ADDR_W);
wmb(); /* drain writebuffer */
}
/**
- * au_read_word - read one word from the chip
- * @mtd: MTD device structure
- *
- * read function for 16bit buswidth without endianness conversion
- */
-static u16 au_read_word(struct mtd_info *mtd)
-{
- struct nand_chip *this = mtd_to_nand(mtd);
- u16 ret = readw(this->IO_ADDR_R);
- wmb(); /* drain writebuffer */
- return ret;
-}
-
-/**
* au_write_buf - write buffer to chip
- * @mtd: MTD device structure
+ * @this: NAND chip object
* @buf: data buffer
* @len: number of bytes to write
*
* write function for 8bit buswidth
*/
-static void au_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+static void au_write_buf(struct nand_chip *this, const u_char *buf, int len)
{
int i;
- struct nand_chip *this = mtd_to_nand(mtd);
for (i = 0; i < len; i++) {
- writeb(buf[i], this->IO_ADDR_W);
+ writeb(buf[i], this->legacy.IO_ADDR_W);
wmb(); /* drain writebuffer */
}
}
/**
* au_read_buf - read chip data into buffer
- * @mtd: MTD device structure
+ * @this: NAND chip object
* @buf: buffer to store date
* @len: number of bytes to read
*
* read function for 8bit buswidth
*/
-static void au_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void au_read_buf(struct nand_chip *this, u_char *buf, int len)
{
int i;
- struct nand_chip *this = mtd_to_nand(mtd);
for (i = 0; i < len; i++) {
- buf[i] = readb(this->IO_ADDR_R);
+ buf[i] = readb(this->legacy.IO_ADDR_R);
wmb(); /* drain writebuffer */
}
}
/**
* au_write_buf16 - write buffer to chip
- * @mtd: MTD device structure
+ * @this: NAND chip object
* @buf: data buffer
* @len: number of bytes to write
*
* write function for 16bit buswidth
*/
-static void au_write_buf16(struct mtd_info *mtd, const u_char *buf, int len)
+static void au_write_buf16(struct nand_chip *this, const u_char *buf, int len)
{
int i;
- struct nand_chip *this = mtd_to_nand(mtd);
u16 *p = (u16 *) buf;
len >>= 1;
for (i = 0; i < len; i++) {
- writew(p[i], this->IO_ADDR_W);
+ writew(p[i], this->legacy.IO_ADDR_W);
wmb(); /* drain writebuffer */
}
@@ -173,7 +152,7 @@ static void au_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
len >>= 1;
for (i = 0; i < len; i++) {
- p[i] = readw(this->IO_ADDR_R);
+ p[i] = readw(this->legacy.IO_ADDR_R);
wmb(); /* drain writebuffer */
}
}
@@ -200,19 +179,19 @@ static void au1550_hwcontrol(struct mtd_info *mtd, int cmd)
switch (cmd) {
case NAND_CTL_SETCLE:
- this->IO_ADDR_W = ctx->base + MEM_STNAND_CMD;
+ this->legacy.IO_ADDR_W = ctx->base + MEM_STNAND_CMD;
break;
case NAND_CTL_CLRCLE:
- this->IO_ADDR_W = ctx->base + MEM_STNAND_DATA;
+ this->legacy.IO_ADDR_W = ctx->base + MEM_STNAND_DATA;
break;
case NAND_CTL_SETALE:
- this->IO_ADDR_W = ctx->base + MEM_STNAND_ADDR;
+ this->legacy.IO_ADDR_W = ctx->base + MEM_STNAND_ADDR;
break;
case NAND_CTL_CLRALE:
- this->IO_ADDR_W = ctx->base + MEM_STNAND_DATA;
+ this->legacy.IO_ADDR_W = ctx->base + MEM_STNAND_DATA;
/* FIXME: Nobody knows why this is necessary,
* but it works only that way */
udelay(1);
@@ -229,12 +208,12 @@ static void au1550_hwcontrol(struct mtd_info *mtd, int cmd)
break;
}
- this->IO_ADDR_R = this->IO_ADDR_W;
+ this->legacy.IO_ADDR_R = this->legacy.IO_ADDR_W;
wmb(); /* Drain the writebuffer */
}
-int au1550_device_ready(struct mtd_info *mtd)
+int au1550_device_ready(struct nand_chip *this)
{
return (alchemy_rdsmem(AU1000_MEM_STSTAT) & 0x1) ? 1 : 0;
}
@@ -248,23 +227,24 @@ int au1550_device_ready(struct mtd_info *mtd)
* chip needs it to be asserted during chip not ready time but the NAND
* controller keeps it released.
*
- * @mtd: MTD device structure
+ * @this: NAND chip object
* @chip: chipnumber to select, -1 for deselect
*/
-static void au1550_select_chip(struct mtd_info *mtd, int chip)
+static void au1550_select_chip(struct nand_chip *this, int chip)
{
}
/**
* au1550_command - Send command to NAND device
- * @mtd: MTD device structure
+ * @this: NAND chip object
* @command: the command to be sent
* @column: the column address for this command, -1 if none
* @page_addr: the page address for this command, -1 if none
*/
-static void au1550_command(struct mtd_info *mtd, unsigned command, int column, int page_addr)
+static void au1550_command(struct nand_chip *this, unsigned command,
+ int column, int page_addr)
{
- struct nand_chip *this = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(this);
struct au1550nd_ctx *ctx = container_of(this, struct au1550nd_ctx,
chip);
int ce_override = 0, i;
@@ -289,9 +269,9 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i
column -= 256;
readcmd = NAND_CMD_READ1;
}
- ctx->write_byte(mtd, readcmd);
+ ctx->write_byte(this, readcmd);
}
- ctx->write_byte(mtd, command);
+ ctx->write_byte(this, command);
/* Set ALE and clear CLE to start address cycle */
au1550_hwcontrol(mtd, NAND_CTL_CLRCLE);
@@ -305,10 +285,10 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i
if (this->options & NAND_BUSWIDTH_16 &&
!nand_opcode_8bits(command))
column >>= 1;
- ctx->write_byte(mtd, column);
+ ctx->write_byte(this, column);
}
if (page_addr != -1) {
- ctx->write_byte(mtd, (u8)(page_addr & 0xff));
+ ctx->write_byte(this, (u8)(page_addr & 0xff));
if (command == NAND_CMD_READ0 ||
command == NAND_CMD_READ1 ||
@@ -326,10 +306,10 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i
au1550_hwcontrol(mtd, NAND_CTL_SETNCE);
}
- ctx->write_byte(mtd, (u8)(page_addr >> 8));
+ ctx->write_byte(this, (u8)(page_addr >> 8));
if (this->options & NAND_ROW_ADDR_3)
- ctx->write_byte(mtd,
+ ctx->write_byte(this,
((page_addr >> 16) & 0x0f));
}
/* Latch in address */
@@ -362,7 +342,8 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i
/* Apply a short delay always to ensure that we do wait tWB. */
ndelay(100);
/* Wait for a chip to become ready... */
- for (i = this->chip_delay; !this->dev_ready(mtd) && i > 0; --i)
+ for (i = this->legacy.chip_delay;
+ !this->legacy.dev_ready(this) && i > 0; --i)
udelay(1);
/* Release -CE and re-enable interrupts. */
@@ -373,7 +354,7 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i
/* Apply this short delay always to ensure that we do wait tWB. */
ndelay(100);
- while(!this->dev_ready(mtd));
+ while(!this->legacy.dev_ready(this));
}
static int find_nand_cs(unsigned long nand_base)
@@ -448,25 +429,24 @@ static int au1550nd_probe(struct platform_device *pdev)
}
ctx->cs = cs;
- this->dev_ready = au1550_device_ready;
+ this->legacy.dev_ready = au1550_device_ready;
this->select_chip = au1550_select_chip;
- this->cmdfunc = au1550_command;
+ this->legacy.cmdfunc = au1550_command;
/* 30 us command delay time */
- this->chip_delay = 30;
+ this->legacy.chip_delay = 30;
this->ecc.mode = NAND_ECC_SOFT;
this->ecc.algo = NAND_ECC_HAMMING;
if (pd->devwidth)
this->options |= NAND_BUSWIDTH_16;
- this->read_byte = (pd->devwidth) ? au_read_byte16 : au_read_byte;
+ this->legacy.read_byte = (pd->devwidth) ? au_read_byte16 : au_read_byte;
ctx->write_byte = (pd->devwidth) ? au_write_byte16 : au_write_byte;
- this->read_word = au_read_word;
- this->write_buf = (pd->devwidth) ? au_write_buf16 : au_write_buf;
- this->read_buf = (pd->devwidth) ? au_read_buf16 : au_read_buf;
+ this->legacy.write_buf = (pd->devwidth) ? au_write_buf16 : au_write_buf;
+ this->legacy.read_buf = (pd->devwidth) ? au_read_buf16 : au_read_buf;
- ret = nand_scan(mtd, 1);
+ ret = nand_scan(this, 1);
if (ret) {
dev_err(&pdev->dev, "NAND scan failed with %d\n", ret);
goto out3;
@@ -492,7 +472,7 @@ static int au1550nd_remove(struct platform_device *pdev)
struct au1550nd_ctx *ctx = platform_get_drvdata(pdev);
struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- nand_release(nand_to_mtd(&ctx->chip));
+ nand_release(&ctx->chip);
iounmap(ctx->base);
release_mem_region(r->start, 0x1000);
kfree(ctx);
diff --git a/drivers/mtd/nand/raw/bcm47xxnflash/main.c b/drivers/mtd/nand/raw/bcm47xxnflash/main.c
index fb31429b70a9..d79694160845 100644
--- a/drivers/mtd/nand/raw/bcm47xxnflash/main.c
+++ b/drivers/mtd/nand/raw/bcm47xxnflash/main.c
@@ -65,7 +65,7 @@ static int bcm47xxnflash_remove(struct platform_device *pdev)
{
struct bcm47xxnflash *nflash = platform_get_drvdata(pdev);
- nand_release(nand_to_mtd(&nflash->nand_chip));
+ nand_release(&nflash->nand_chip);
return 0;
}
diff --git a/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c b/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c
index 60874de430eb..9095a79ebc7d 100644
--- a/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c
+++ b/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c
@@ -170,10 +170,9 @@ static void bcm47xxnflash_ops_bcm4706_write(struct mtd_info *mtd,
* NAND chip ops
**************************************************/
-static void bcm47xxnflash_ops_bcm4706_cmd_ctrl(struct mtd_info *mtd, int cmd,
- unsigned int ctrl)
+static void bcm47xxnflash_ops_bcm4706_cmd_ctrl(struct nand_chip *nand_chip,
+ int cmd, unsigned int ctrl)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
u32 code = 0;
@@ -191,15 +190,14 @@ static void bcm47xxnflash_ops_bcm4706_cmd_ctrl(struct mtd_info *mtd, int cmd,
}
/* Default nand_select_chip calls cmd_ctrl, which is not used in BCM4706 */
-static void bcm47xxnflash_ops_bcm4706_select_chip(struct mtd_info *mtd,
- int chip)
+static void bcm47xxnflash_ops_bcm4706_select_chip(struct nand_chip *chip,
+ int cs)
{
return;
}
-static int bcm47xxnflash_ops_bcm4706_dev_ready(struct mtd_info *mtd)
+static int bcm47xxnflash_ops_bcm4706_dev_ready(struct nand_chip *nand_chip)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
return !!(bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_CTL) & NCTL_READY);
@@ -212,11 +210,11 @@ static int bcm47xxnflash_ops_bcm4706_dev_ready(struct mtd_info *mtd)
* registers of ChipCommon core. Hacking cmd_ctrl to understand and convert
* standard commands would be much more complicated.
*/
-static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd,
+static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct nand_chip *nand_chip,
unsigned command, int column,
int page_addr)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(nand_chip);
struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
struct bcma_drv_cc *cc = b47n->cc;
u32 ctlcode;
@@ -229,10 +227,10 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd,
switch (command) {
case NAND_CMD_RESET:
- nand_chip->cmd_ctrl(mtd, command, NAND_CTRL_CLE);
+ nand_chip->legacy.cmd_ctrl(nand_chip, command, NAND_CTRL_CLE);
ndelay(100);
- nand_wait_ready(mtd);
+ nand_wait_ready(nand_chip);
break;
case NAND_CMD_READID:
ctlcode = NCTL_CSA | 0x01000000 | NCTL_CMD1W | NCTL_CMD0;
@@ -310,9 +308,9 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd,
b47n->curr_command = command;
}
-static u8 bcm47xxnflash_ops_bcm4706_read_byte(struct mtd_info *mtd)
+static u8 bcm47xxnflash_ops_bcm4706_read_byte(struct nand_chip *nand_chip)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(nand_chip);
struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
struct bcma_drv_cc *cc = b47n->cc;
u32 tmp = 0;
@@ -338,31 +336,31 @@ static u8 bcm47xxnflash_ops_bcm4706_read_byte(struct mtd_info *mtd)
return 0;
}
-static void bcm47xxnflash_ops_bcm4706_read_buf(struct mtd_info *mtd,
+static void bcm47xxnflash_ops_bcm4706_read_buf(struct nand_chip *nand_chip,
uint8_t *buf, int len)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
switch (b47n->curr_command) {
case NAND_CMD_READ0:
case NAND_CMD_READOOB:
- bcm47xxnflash_ops_bcm4706_read(mtd, buf, len);
+ bcm47xxnflash_ops_bcm4706_read(nand_to_mtd(nand_chip), buf,
+ len);
return;
}
pr_err("Invalid command for buf read: 0x%X\n", b47n->curr_command);
}
-static void bcm47xxnflash_ops_bcm4706_write_buf(struct mtd_info *mtd,
+static void bcm47xxnflash_ops_bcm4706_write_buf(struct nand_chip *nand_chip,
const uint8_t *buf, int len)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
switch (b47n->curr_command) {
case NAND_CMD_SEQIN:
- bcm47xxnflash_ops_bcm4706_write(mtd, buf, len);
+ bcm47xxnflash_ops_bcm4706_write(nand_to_mtd(nand_chip), buf,
+ len);
return;
}
@@ -386,16 +384,16 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n)
u32 val;
b47n->nand_chip.select_chip = bcm47xxnflash_ops_bcm4706_select_chip;
- nand_chip->cmd_ctrl = bcm47xxnflash_ops_bcm4706_cmd_ctrl;
- nand_chip->dev_ready = bcm47xxnflash_ops_bcm4706_dev_ready;
- b47n->nand_chip.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc;
- b47n->nand_chip.read_byte = bcm47xxnflash_ops_bcm4706_read_byte;
- b47n->nand_chip.read_buf = bcm47xxnflash_ops_bcm4706_read_buf;
- b47n->nand_chip.write_buf = bcm47xxnflash_ops_bcm4706_write_buf;
- b47n->nand_chip.set_features = nand_get_set_features_notsupp;
- b47n->nand_chip.get_features = nand_get_set_features_notsupp;
-
- nand_chip->chip_delay = 50;
+ nand_chip->legacy.cmd_ctrl = bcm47xxnflash_ops_bcm4706_cmd_ctrl;
+ nand_chip->legacy.dev_ready = bcm47xxnflash_ops_bcm4706_dev_ready;
+ b47n->nand_chip.legacy.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc;
+ b47n->nand_chip.legacy.read_byte = bcm47xxnflash_ops_bcm4706_read_byte;
+ b47n->nand_chip.legacy.read_buf = bcm47xxnflash_ops_bcm4706_read_buf;
+ b47n->nand_chip.legacy.write_buf = bcm47xxnflash_ops_bcm4706_write_buf;
+ b47n->nand_chip.legacy.set_features = nand_get_set_features_notsupp;
+ b47n->nand_chip.legacy.get_features = nand_get_set_features_notsupp;
+
+ nand_chip->legacy.chip_delay = 50;
b47n->nand_chip.bbt_options = NAND_BBT_USE_FLASH;
b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */
@@ -423,7 +421,7 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n)
(w4 << 24 | w3 << 18 | w2 << 12 | w1 << 6 | w0));
/* Scan NAND */
- err = nand_scan(nand_to_mtd(&b47n->nand_chip), 1);
+ err = nand_scan(&b47n->nand_chip, 1);
if (err) {
pr_err("Could not scan NAND flash: %d\n", err);
goto exit;
diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
index 4b90d5b380c2..482c6f093f99 100644
--- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
@@ -1231,15 +1231,14 @@ static void brcmnand_send_cmd(struct brcmnand_host *host, int cmd)
* NAND MTD API: read/program/erase
***********************************************************************/
-static void brcmnand_cmd_ctrl(struct mtd_info *mtd, int dat,
- unsigned int ctrl)
+static void brcmnand_cmd_ctrl(struct nand_chip *chip, int dat,
+ unsigned int ctrl)
{
/* intentionally left blank */
}
-static int brcmnand_waitfunc(struct mtd_info *mtd, struct nand_chip *this)
+static int brcmnand_waitfunc(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct brcmnand_host *host = nand_get_controller_data(chip);
struct brcmnand_controller *ctrl = host->ctrl;
unsigned long timeo = msecs_to_jiffies(100);
@@ -1274,7 +1273,6 @@ static int brcmnand_low_level_op(struct brcmnand_host *host,
enum brcmnand_llop_type type, u32 data,
bool last_op)
{
- struct mtd_info *mtd = nand_to_mtd(&host->chip);
struct nand_chip *chip = &host->chip;
struct brcmnand_controller *ctrl = host->ctrl;
u32 tmp;
@@ -1307,13 +1305,13 @@ static int brcmnand_low_level_op(struct brcmnand_host *host,
(void)brcmnand_read_reg(ctrl, BRCMNAND_LL_OP);
brcmnand_send_cmd(host, CMD_LOW_LEVEL_OP);
- return brcmnand_waitfunc(mtd, chip);
+ return brcmnand_waitfunc(chip);
}
-static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command,
+static void brcmnand_cmdfunc(struct nand_chip *chip, unsigned command,
int column, int page_addr)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct brcmnand_host *host = nand_get_controller_data(chip);
struct brcmnand_controller *ctrl = host->ctrl;
u64 addr = (u64)page_addr << chip->page_shift;
@@ -1383,7 +1381,7 @@ static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command,
(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
brcmnand_send_cmd(host, native_cmd);
- brcmnand_waitfunc(mtd, chip);
+ brcmnand_waitfunc(chip);
if (native_cmd == CMD_PARAMETER_READ ||
native_cmd == CMD_PARAMETER_CHANGE_COL) {
@@ -1417,9 +1415,8 @@ static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command,
brcmnand_wp(mtd, 1);
}
-static uint8_t brcmnand_read_byte(struct mtd_info *mtd)
+static uint8_t brcmnand_read_byte(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct brcmnand_host *host = nand_get_controller_data(chip);
struct brcmnand_controller *ctrl = host->ctrl;
uint8_t ret = 0;
@@ -1474,19 +1471,18 @@ static uint8_t brcmnand_read_byte(struct mtd_info *mtd)
return ret;
}
-static void brcmnand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void brcmnand_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
{
int i;
for (i = 0; i < len; i++, buf++)
- *buf = brcmnand_read_byte(mtd);
+ *buf = brcmnand_read_byte(chip);
}
-static void brcmnand_write_buf(struct mtd_info *mtd, const uint8_t *buf,
- int len)
+static void brcmnand_write_buf(struct nand_chip *chip, const uint8_t *buf,
+ int len)
{
int i;
- struct nand_chip *chip = mtd_to_nand(mtd);
struct brcmnand_host *host = nand_get_controller_data(chip);
switch (host->last_cmd) {
@@ -1617,7 +1613,7 @@ static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip,
(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
/* SPARE_AREA_READ does not use ECC, so just use PAGE_READ */
brcmnand_send_cmd(host, CMD_PAGE_READ);
- brcmnand_waitfunc(mtd, chip);
+ brcmnand_waitfunc(chip);
if (likely(buf)) {
brcmnand_soc_data_bus_prepare(ctrl->soc, false);
@@ -1689,7 +1685,7 @@ static int brcmstb_nand_verify_erased_page(struct mtd_info *mtd,
sas = mtd->oobsize / chip->ecc.steps;
/* read without ecc for verification */
- ret = chip->ecc.read_page_raw(mtd, chip, buf, true, page);
+ ret = chip->ecc.read_page_raw(chip, buf, true, page);
if (ret)
return ret;
@@ -1786,9 +1782,10 @@ try_dmaread:
return 0;
}
-static int brcmnand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+static int brcmnand_read_page(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct brcmnand_host *host = nand_get_controller_data(chip);
u8 *oob = oob_required ? (u8 *)chip->oob_poi : NULL;
@@ -1798,10 +1795,11 @@ static int brcmnand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
mtd->writesize >> FC_SHIFT, (u32 *)buf, oob);
}
-static int brcmnand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+static int brcmnand_read_page_raw(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
struct brcmnand_host *host = nand_get_controller_data(chip);
+ struct mtd_info *mtd = nand_to_mtd(chip);
u8 *oob = oob_required ? (u8 *)chip->oob_poi : NULL;
int ret;
@@ -1814,17 +1812,18 @@ static int brcmnand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
return ret;
}
-static int brcmnand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int brcmnand_read_oob(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
return brcmnand_read(mtd, chip, (u64)page << chip->page_shift,
mtd->writesize >> FC_SHIFT,
NULL, (u8 *)chip->oob_poi);
}
-static int brcmnand_read_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int brcmnand_read_oob_raw(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct brcmnand_host *host = nand_get_controller_data(chip);
brcmnand_set_ecc_enabled(host, 0);
@@ -1892,7 +1891,7 @@ static int brcmnand_write(struct mtd_info *mtd, struct nand_chip *chip,
/* we cannot use SPARE_AREA_PROGRAM when PARTIAL_PAGE_EN=0 */
brcmnand_send_cmd(host, CMD_PROGRAM_PAGE);
- status = brcmnand_waitfunc(mtd, chip);
+ status = brcmnand_waitfunc(chip);
if (status & NAND_STATUS_FAIL) {
dev_info(ctrl->dev, "program failed at %llx\n",
@@ -1906,9 +1905,10 @@ out:
return ret;
}
-static int brcmnand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required, int page)
+static int brcmnand_write_page(struct nand_chip *chip, const uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct brcmnand_host *host = nand_get_controller_data(chip);
void *oob = oob_required ? chip->oob_poi : NULL;
@@ -1918,10 +1918,10 @@ static int brcmnand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
return nand_prog_page_end_op(chip);
}
-static int brcmnand_write_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip, const uint8_t *buf,
+static int brcmnand_write_page_raw(struct nand_chip *chip, const uint8_t *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct brcmnand_host *host = nand_get_controller_data(chip);
void *oob = oob_required ? chip->oob_poi : NULL;
@@ -1933,16 +1933,16 @@ static int brcmnand_write_page_raw(struct mtd_info *mtd,
return nand_prog_page_end_op(chip);
}
-static int brcmnand_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int brcmnand_write_oob(struct nand_chip *chip, int page)
{
- return brcmnand_write(mtd, chip, (u64)page << chip->page_shift,
- NULL, chip->oob_poi);
+ return brcmnand_write(nand_to_mtd(chip), chip,
+ (u64)page << chip->page_shift, NULL,
+ chip->oob_poi);
}
-static int brcmnand_write_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int brcmnand_write_oob_raw(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct brcmnand_host *host = nand_get_controller_data(chip);
int ret;
@@ -2270,15 +2270,12 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
mtd->owner = THIS_MODULE;
mtd->dev.parent = &pdev->dev;
- chip->IO_ADDR_R = (void __iomem *)0xdeadbeef;
- chip->IO_ADDR_W = (void __iomem *)0xdeadbeef;
-
- chip->cmd_ctrl = brcmnand_cmd_ctrl;
- chip->cmdfunc = brcmnand_cmdfunc;
- chip->waitfunc = brcmnand_waitfunc;
- chip->read_byte = brcmnand_read_byte;
- chip->read_buf = brcmnand_read_buf;
- chip->write_buf = brcmnand_write_buf;
+ chip->legacy.cmd_ctrl = brcmnand_cmd_ctrl;
+ chip->legacy.cmdfunc = brcmnand_cmdfunc;
+ chip->legacy.waitfunc = brcmnand_waitfunc;
+ chip->legacy.read_byte = brcmnand_read_byte;
+ chip->legacy.read_buf = brcmnand_read_buf;
+ chip->legacy.write_buf = brcmnand_write_buf;
chip->ecc.mode = NAND_ECC_HW;
chip->ecc.read_page = brcmnand_read_page;
@@ -2301,7 +2298,7 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
nand_writereg(ctrl, cfg_offs,
nand_readreg(ctrl, cfg_offs) & ~CFG_BUS_WIDTH);
- ret = nand_scan(mtd, 1);
+ ret = nand_scan(chip, 1);
if (ret)
return ret;
@@ -2616,7 +2613,7 @@ int brcmnand_remove(struct platform_device *pdev)
struct brcmnand_host *host;
list_for_each_entry(host, &ctrl->host_list, node)
- nand_release(nand_to_mtd(&host->chip));
+ nand_release(&host->chip);
clk_disable_unprepare(ctrl->clk);
diff --git a/drivers/mtd/nand/raw/cafe_nand.c b/drivers/mtd/nand/raw/cafe_nand.c
index 1dbe43adcfe7..c1a745940d12 100644
--- a/drivers/mtd/nand/raw/cafe_nand.c
+++ b/drivers/mtd/nand/raw/cafe_nand.c
@@ -100,9 +100,8 @@ static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
#define cafe_readl(cafe, addr) readl((cafe)->mmio + CAFE_##addr)
#define cafe_writel(cafe, datum, addr) writel(datum, (cafe)->mmio + CAFE_##addr)
-static int cafe_device_ready(struct mtd_info *mtd)
+static int cafe_device_ready(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct cafe_priv *cafe = nand_get_controller_data(chip);
int result = !!(cafe_readl(cafe, NAND_STATUS) & 0x40000000);
uint32_t irqs = cafe_readl(cafe, NAND_IRQ);
@@ -117,9 +116,8 @@ static int cafe_device_ready(struct mtd_info *mtd)
}
-static void cafe_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+static void cafe_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct cafe_priv *cafe = nand_get_controller_data(chip);
if (cafe->usedma)
@@ -133,9 +131,8 @@ static void cafe_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
len, cafe->datalen);
}
-static void cafe_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void cafe_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct cafe_priv *cafe = nand_get_controller_data(chip);
if (cafe->usedma)
@@ -148,22 +145,21 @@ static void cafe_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
cafe->datalen += len;
}
-static uint8_t cafe_read_byte(struct mtd_info *mtd)
+static uint8_t cafe_read_byte(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct cafe_priv *cafe = nand_get_controller_data(chip);
uint8_t d;
- cafe_read_buf(mtd, &d, 1);
+ cafe_read_buf(chip, &d, 1);
cafe_dev_dbg(&cafe->pdev->dev, "Read %02x\n", d);
return d;
}
-static void cafe_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
+static void cafe_nand_cmdfunc(struct nand_chip *chip, unsigned command,
int column, int page_addr)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct cafe_priv *cafe = nand_get_controller_data(chip);
int adrbytes = 0;
uint32_t ctl1;
@@ -313,13 +309,12 @@ static void cafe_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
cafe_writel(cafe, cafe->ctl2, NAND_CTRL2);
return;
}
- nand_wait_ready(mtd);
+ nand_wait_ready(chip);
cafe_writel(cafe, cafe->ctl2, NAND_CTRL2);
}
-static void cafe_select_chip(struct mtd_info *mtd, int chipnr)
+static void cafe_select_chip(struct nand_chip *chip, int chipnr)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct cafe_priv *cafe = nand_get_controller_data(chip);
cafe_dev_dbg(&cafe->pdev->dev, "select_chip %d\n", chipnr);
@@ -346,17 +341,19 @@ static irqreturn_t cafe_nand_interrupt(int irq, void *id)
return IRQ_HANDLED;
}
-static int cafe_nand_write_oob(struct mtd_info *mtd,
- struct nand_chip *chip, int page)
+static int cafe_nand_write_oob(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
return nand_prog_page_op(chip, page, mtd->writesize, chip->oob_poi,
mtd->oobsize);
}
/* Don't use -- use nand_read_oob_std for now */
-static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int cafe_nand_read_oob(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
return nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
}
/**
@@ -369,9 +366,10 @@ static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
* The hw generator calculates the error syndrome automatically. Therefore
* we need a special oob layout and handling.
*/
-static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+static int cafe_nand_read_page(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct cafe_priv *cafe = nand_get_controller_data(chip);
unsigned int max_bitflips = 0;
@@ -380,7 +378,7 @@ static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
cafe_readl(cafe, NAND_ECC_SYN01));
nand_read_page_op(chip, page, 0, buf, mtd->writesize);
- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize);
if (checkecc && cafe_readl(cafe, NAND_ECC_RESULT) & (1<<18)) {
unsigned short syn[8], pat[4];
@@ -531,15 +529,15 @@ static struct nand_bbt_descr cafe_bbt_mirror_descr_512 = {
};
-static int cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
- struct nand_chip *chip,
- const uint8_t *buf, int oob_required,
- int page)
+static int cafe_nand_write_page_lowlevel(struct nand_chip *chip,
+ const uint8_t *buf, int oob_required,
+ int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct cafe_priv *cafe = nand_get_controller_data(chip);
nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
- chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize);
/* Set up ECC autogeneration */
cafe->ctl2 |= (1<<30);
@@ -547,7 +545,7 @@ static int cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
return nand_prog_page_end_op(chip);
}
-static int cafe_nand_block_bad(struct mtd_info *mtd, loff_t ofs)
+static int cafe_nand_block_bad(struct nand_chip *chip, loff_t ofs)
{
return 0;
}
@@ -705,23 +703,23 @@ static int cafe_nand_probe(struct pci_dev *pdev,
goto out_ior;
}
- cafe->nand.cmdfunc = cafe_nand_cmdfunc;
- cafe->nand.dev_ready = cafe_device_ready;
- cafe->nand.read_byte = cafe_read_byte;
- cafe->nand.read_buf = cafe_read_buf;
- cafe->nand.write_buf = cafe_write_buf;
+ cafe->nand.legacy.cmdfunc = cafe_nand_cmdfunc;
+ cafe->nand.legacy.dev_ready = cafe_device_ready;
+ cafe->nand.legacy.read_byte = cafe_read_byte;
+ cafe->nand.legacy.read_buf = cafe_read_buf;
+ cafe->nand.legacy.write_buf = cafe_write_buf;
cafe->nand.select_chip = cafe_select_chip;
- cafe->nand.set_features = nand_get_set_features_notsupp;
- cafe->nand.get_features = nand_get_set_features_notsupp;
+ cafe->nand.legacy.set_features = nand_get_set_features_notsupp;
+ cafe->nand.legacy.get_features = nand_get_set_features_notsupp;
- cafe->nand.chip_delay = 0;
+ cafe->nand.legacy.chip_delay = 0;
/* Enable the following for a flash based bad block table */
cafe->nand.bbt_options = NAND_BBT_USE_FLASH;
if (skipbbt) {
cafe->nand.options |= NAND_SKIP_BBTSCAN;
- cafe->nand.block_bad = cafe_nand_block_bad;
+ cafe->nand.legacy.block_bad = cafe_nand_block_bad;
}
if (numtimings && numtimings != 3) {
@@ -783,7 +781,7 @@ static int cafe_nand_probe(struct pci_dev *pdev,
/* Scan to find existence of the device */
cafe->nand.dummy_controller.ops = &cafe_nand_controller_ops;
- err = nand_scan(mtd, 2);
+ err = nand_scan(&cafe->nand, 2);
if (err)
goto out_irq;
@@ -819,7 +817,7 @@ static void cafe_nand_remove(struct pci_dev *pdev)
/* Disable NAND IRQ in global IRQ mask register */
cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK);
free_irq(pdev->irq, mtd);
- nand_release(mtd);
+ nand_release(chip);
free_rs(cafe->rs);
pci_iounmap(pdev, cafe->mmio);
dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
diff --git a/drivers/mtd/nand/raw/cmx270_nand.c b/drivers/mtd/nand/raw/cmx270_nand.c
index b66e254b6802..143e4acacaae 100644
--- a/drivers/mtd/nand/raw/cmx270_nand.c
+++ b/drivers/mtd/nand/raw/cmx270_nand.c
@@ -49,29 +49,26 @@ static const struct mtd_partition partition_info[] = {
};
#define NUM_PARTITIONS (ARRAY_SIZE(partition_info))
-static u_char cmx270_read_byte(struct mtd_info *mtd)
+static u_char cmx270_read_byte(struct nand_chip *this)
{
- struct nand_chip *this = mtd_to_nand(mtd);
-
- return (readl(this->IO_ADDR_R) >> 16);
+ return (readl(this->legacy.IO_ADDR_R) >> 16);
}
-static void cmx270_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+static void cmx270_write_buf(struct nand_chip *this, const u_char *buf,
+ int len)
{
int i;
- struct nand_chip *this = mtd_to_nand(mtd);
for (i=0; i<len; i++)
- writel((*buf++ << 16), this->IO_ADDR_W);
+ writel((*buf++ << 16), this->legacy.IO_ADDR_W);
}
-static void cmx270_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void cmx270_read_buf(struct nand_chip *this, u_char *buf, int len)
{
int i;
- struct nand_chip *this = mtd_to_nand(mtd);
for (i=0; i<len; i++)
- *buf++ = readl(this->IO_ADDR_R) >> 16;
+ *buf++ = readl(this->legacy.IO_ADDR_R) >> 16;
}
static inline void nand_cs_on(void)
@@ -89,11 +86,10 @@ static void nand_cs_off(void)
/*
* hardware specific access to control-lines
*/
-static void cmx270_hwcontrol(struct mtd_info *mtd, int dat,
+static void cmx270_hwcontrol(struct nand_chip *this, int dat,
unsigned int ctrl)
{
- struct nand_chip *this = mtd_to_nand(mtd);
- unsigned int nandaddr = (unsigned int)this->IO_ADDR_W;
+ unsigned int nandaddr = (unsigned int)this->legacy.IO_ADDR_W;
dsb();
@@ -113,9 +109,9 @@ static void cmx270_hwcontrol(struct mtd_info *mtd, int dat,
}
dsb();
- this->IO_ADDR_W = (void __iomem*)nandaddr;
+ this->legacy.IO_ADDR_W = (void __iomem*)nandaddr;
if (dat != NAND_CMD_NONE)
- writel((dat << 16), this->IO_ADDR_W);
+ writel((dat << 16), this->legacy.IO_ADDR_W);
dsb();
}
@@ -123,7 +119,7 @@ static void cmx270_hwcontrol(struct mtd_info *mtd, int dat,
/*
* read device ready pin
*/
-static int cmx270_device_ready(struct mtd_info *mtd)
+static int cmx270_device_ready(struct nand_chip *this)
{
dsb();
@@ -177,23 +173,23 @@ static int __init cmx270_init(void)
cmx270_nand_mtd->owner = THIS_MODULE;
/* insert callbacks */
- this->IO_ADDR_R = cmx270_nand_io;
- this->IO_ADDR_W = cmx270_nand_io;
- this->cmd_ctrl = cmx270_hwcontrol;
- this->dev_ready = cmx270_device_ready;
+ this->legacy.IO_ADDR_R = cmx270_nand_io;
+ this->legacy.IO_ADDR_W = cmx270_nand_io;
+ this->legacy.cmd_ctrl = cmx270_hwcontrol;
+ this->legacy.dev_ready = cmx270_device_ready;
/* 15 us command delay time */
- this->chip_delay = 20;
+ this->legacy.chip_delay = 20;
this->ecc.mode = NAND_ECC_SOFT;
this->ecc.algo = NAND_ECC_HAMMING;
/* read/write functions */
- this->read_byte = cmx270_read_byte;
- this->read_buf = cmx270_read_buf;
- this->write_buf = cmx270_write_buf;
+ this->legacy.read_byte = cmx270_read_byte;
+ this->legacy.read_buf = cmx270_read_buf;
+ this->legacy.write_buf = cmx270_write_buf;
/* Scan to find existence of the device */
- ret = nand_scan(cmx270_nand_mtd, 1);
+ ret = nand_scan(this, 1);
if (ret) {
pr_notice("No NAND device\n");
goto err_scan;
@@ -228,7 +224,7 @@ module_init(cmx270_init);
static void __exit cmx270_cleanup(void)
{
/* Release resources, unregister device */
- nand_release(cmx270_nand_mtd);
+ nand_release(mtd_to_nand(cmx270_nand_mtd));
gpio_free(GPIO_NAND_RB);
gpio_free(GPIO_NAND_CS);
diff --git a/drivers/mtd/nand/raw/cs553x_nand.c b/drivers/mtd/nand/raw/cs553x_nand.c
index beafad62e7d5..c6f578aff5d9 100644
--- a/drivers/mtd/nand/raw/cs553x_nand.c
+++ b/drivers/mtd/nand/raw/cs553x_nand.c
@@ -93,83 +93,74 @@
#define CS_NAND_ECC_CLRECC (1<<1)
#define CS_NAND_ECC_ENECC (1<<0)
-static void cs553x_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void cs553x_read_buf(struct nand_chip *this, u_char *buf, int len)
{
- struct nand_chip *this = mtd_to_nand(mtd);
-
while (unlikely(len > 0x800)) {
- memcpy_fromio(buf, this->IO_ADDR_R, 0x800);
+ memcpy_fromio(buf, this->legacy.IO_ADDR_R, 0x800);
buf += 0x800;
len -= 0x800;
}
- memcpy_fromio(buf, this->IO_ADDR_R, len);
+ memcpy_fromio(buf, this->legacy.IO_ADDR_R, len);
}
-static void cs553x_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+static void cs553x_write_buf(struct nand_chip *this, const u_char *buf, int len)
{
- struct nand_chip *this = mtd_to_nand(mtd);
-
while (unlikely(len > 0x800)) {
- memcpy_toio(this->IO_ADDR_R, buf, 0x800);
+ memcpy_toio(this->legacy.IO_ADDR_R, buf, 0x800);
buf += 0x800;
len -= 0x800;
}
- memcpy_toio(this->IO_ADDR_R, buf, len);
+ memcpy_toio(this->legacy.IO_ADDR_R, buf, len);
}
-static unsigned char cs553x_read_byte(struct mtd_info *mtd)
+static unsigned char cs553x_read_byte(struct nand_chip *this)
{
- struct nand_chip *this = mtd_to_nand(mtd);
- return readb(this->IO_ADDR_R);
+ return readb(this->legacy.IO_ADDR_R);
}
-static void cs553x_write_byte(struct mtd_info *mtd, u_char byte)
+static void cs553x_write_byte(struct nand_chip *this, u_char byte)
{
- struct nand_chip *this = mtd_to_nand(mtd);
int i = 100000;
- while (i && readb(this->IO_ADDR_R + MM_NAND_STS) & CS_NAND_CTLR_BUSY) {
+ while (i && readb(this->legacy.IO_ADDR_R + MM_NAND_STS) & CS_NAND_CTLR_BUSY) {
udelay(1);
i--;
}
- writeb(byte, this->IO_ADDR_W + 0x801);
+ writeb(byte, this->legacy.IO_ADDR_W + 0x801);
}
-static void cs553x_hwcontrol(struct mtd_info *mtd, int cmd,
+static void cs553x_hwcontrol(struct nand_chip *this, int cmd,
unsigned int ctrl)
{
- struct nand_chip *this = mtd_to_nand(mtd);
- void __iomem *mmio_base = this->IO_ADDR_R;
+ void __iomem *mmio_base = this->legacy.IO_ADDR_R;
if (ctrl & NAND_CTRL_CHANGE) {
unsigned char ctl = (ctrl & ~NAND_CTRL_CHANGE ) ^ 0x01;
writeb(ctl, mmio_base + MM_NAND_CTL);
}
if (cmd != NAND_CMD_NONE)
- cs553x_write_byte(mtd, cmd);
+ cs553x_write_byte(this, cmd);
}
-static int cs553x_device_ready(struct mtd_info *mtd)
+static int cs553x_device_ready(struct nand_chip *this)
{
- struct nand_chip *this = mtd_to_nand(mtd);
- void __iomem *mmio_base = this->IO_ADDR_R;
+ void __iomem *mmio_base = this->legacy.IO_ADDR_R;
unsigned char foo = readb(mmio_base + MM_NAND_STS);
return (foo & CS_NAND_STS_FLASH_RDY) && !(foo & CS_NAND_CTLR_BUSY);
}
-static void cs_enable_hwecc(struct mtd_info *mtd, int mode)
+static void cs_enable_hwecc(struct nand_chip *this, int mode)
{
- struct nand_chip *this = mtd_to_nand(mtd);
- void __iomem *mmio_base = this->IO_ADDR_R;
+ void __iomem *mmio_base = this->legacy.IO_ADDR_R;
writeb(0x07, mmio_base + MM_NAND_ECC_CTL);
}
-static int cs_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
+static int cs_calculate_ecc(struct nand_chip *this, const u_char *dat,
+ u_char *ecc_code)
{
uint32_t ecc;
- struct nand_chip *this = mtd_to_nand(mtd);
- void __iomem *mmio_base = this->IO_ADDR_R;
+ void __iomem *mmio_base = this->legacy.IO_ADDR_R;
ecc = readl(mmio_base + MM_NAND_STS);
@@ -208,20 +199,20 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
new_mtd->owner = THIS_MODULE;
/* map physical address */
- this->IO_ADDR_R = this->IO_ADDR_W = ioremap(adr, 4096);
- if (!this->IO_ADDR_R) {
+ this->legacy.IO_ADDR_R = this->legacy.IO_ADDR_W = ioremap(adr, 4096);
+ if (!this->legacy.IO_ADDR_R) {
pr_warn("ioremap cs553x NAND @0x%08lx failed\n", adr);
err = -EIO;
goto out_mtd;
}
- this->cmd_ctrl = cs553x_hwcontrol;
- this->dev_ready = cs553x_device_ready;
- this->read_byte = cs553x_read_byte;
- this->read_buf = cs553x_read_buf;
- this->write_buf = cs553x_write_buf;
+ this->legacy.cmd_ctrl = cs553x_hwcontrol;
+ this->legacy.dev_ready = cs553x_device_ready;
+ this->legacy.read_byte = cs553x_read_byte;
+ this->legacy.read_buf = cs553x_read_buf;
+ this->legacy.write_buf = cs553x_write_buf;
- this->chip_delay = 0;
+ this->legacy.chip_delay = 0;
this->ecc.mode = NAND_ECC_HW;
this->ecc.size = 256;
@@ -241,7 +232,7 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
}
/* Scan to find existence of the device */
- err = nand_scan(new_mtd, 1);
+ err = nand_scan(this, 1);
if (err)
goto out_free;
@@ -251,7 +242,7 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
out_free:
kfree(new_mtd->name);
out_ior:
- iounmap(this->IO_ADDR_R);
+ iounmap(this->legacy.IO_ADDR_R);
out_mtd:
kfree(this);
out:
@@ -333,10 +324,10 @@ static void __exit cs553x_cleanup(void)
continue;
this = mtd_to_nand(mtd);
- mmio_base = this->IO_ADDR_R;
+ mmio_base = this->legacy.IO_ADDR_R;
/* Release resources, unregister device */
- nand_release(mtd);
+ nand_release(this);
kfree(mtd->name);
cs553x_mtd[i] = NULL;
diff --git a/drivers/mtd/nand/raw/davinci_nand.c b/drivers/mtd/nand/raw/davinci_nand.c
index 40145e206a6b..80f228d23cd2 100644
--- a/drivers/mtd/nand/raw/davinci_nand.c
+++ b/drivers/mtd/nand/raw/davinci_nand.c
@@ -97,12 +97,11 @@ static inline void davinci_nand_writel(struct davinci_nand_info *info,
* Access to hardware control lines: ALE, CLE, secondary chipselect.
*/
-static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd,
+static void nand_davinci_hwcontrol(struct nand_chip *nand, int cmd,
unsigned int ctrl)
{
- struct davinci_nand_info *info = to_davinci_nand(mtd);
+ struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(nand));
void __iomem *addr = info->current_cs;
- struct nand_chip *nand = mtd_to_nand(mtd);
/* Did the control lines change? */
if (ctrl & NAND_CTRL_CHANGE) {
@@ -111,16 +110,16 @@ static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd,
else if ((ctrl & NAND_CTRL_ALE) == NAND_CTRL_ALE)
addr += info->mask_ale;
- nand->IO_ADDR_W = addr;
+ nand->legacy.IO_ADDR_W = addr;
}
if (cmd != NAND_CMD_NONE)
- iowrite8(cmd, nand->IO_ADDR_W);
+ iowrite8(cmd, nand->legacy.IO_ADDR_W);
}
-static void nand_davinci_select_chip(struct mtd_info *mtd, int chip)
+static void nand_davinci_select_chip(struct nand_chip *nand, int chip)
{
- struct davinci_nand_info *info = to_davinci_nand(mtd);
+ struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(nand));
info->current_cs = info->vaddr;
@@ -128,8 +127,8 @@ static void nand_davinci_select_chip(struct mtd_info *mtd, int chip)
if (chip > 0)
info->current_cs += info->mask_chipsel;
- info->chip.IO_ADDR_W = info->current_cs;
- info->chip.IO_ADDR_R = info->chip.IO_ADDR_W;
+ info->chip.legacy.IO_ADDR_W = info->current_cs;
+ info->chip.legacy.IO_ADDR_R = info->chip.legacy.IO_ADDR_W;
}
/*----------------------------------------------------------------------*/
@@ -146,16 +145,16 @@ static inline uint32_t nand_davinci_readecc_1bit(struct mtd_info *mtd)
+ 4 * info->core_chipsel);
}
-static void nand_davinci_hwctl_1bit(struct mtd_info *mtd, int mode)
+static void nand_davinci_hwctl_1bit(struct nand_chip *chip, int mode)
{
struct davinci_nand_info *info;
uint32_t nandcfr;
unsigned long flags;
- info = to_davinci_nand(mtd);
+ info = to_davinci_nand(nand_to_mtd(chip));
/* Reset ECC hardware */
- nand_davinci_readecc_1bit(mtd);
+ nand_davinci_readecc_1bit(nand_to_mtd(chip));
spin_lock_irqsave(&davinci_nand_lock, flags);
@@ -170,10 +169,10 @@ static void nand_davinci_hwctl_1bit(struct mtd_info *mtd, int mode)
/*
* Read hardware ECC value and pack into three bytes
*/
-static int nand_davinci_calculate_1bit(struct mtd_info *mtd,
- const u_char *dat, u_char *ecc_code)
+static int nand_davinci_calculate_1bit(struct nand_chip *chip,
+ const u_char *dat, u_char *ecc_code)
{
- unsigned int ecc_val = nand_davinci_readecc_1bit(mtd);
+ unsigned int ecc_val = nand_davinci_readecc_1bit(nand_to_mtd(chip));
unsigned int ecc24 = (ecc_val & 0x0fff) | ((ecc_val & 0x0fff0000) >> 4);
/* invert so that erased block ecc is correct */
@@ -185,10 +184,9 @@ static int nand_davinci_calculate_1bit(struct mtd_info *mtd,
return 0;
}
-static int nand_davinci_correct_1bit(struct mtd_info *mtd, u_char *dat,
+static int nand_davinci_correct_1bit(struct nand_chip *chip, u_char *dat,
u_char *read_ecc, u_char *calc_ecc)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
uint32_t eccNand = read_ecc[0] | (read_ecc[1] << 8) |
(read_ecc[2] << 16);
uint32_t eccCalc = calc_ecc[0] | (calc_ecc[1] << 8) |
@@ -231,9 +229,9 @@ static int nand_davinci_correct_1bit(struct mtd_info *mtd, u_char *dat,
* OOB without recomputing ECC.
*/
-static void nand_davinci_hwctl_4bit(struct mtd_info *mtd, int mode)
+static void nand_davinci_hwctl_4bit(struct nand_chip *chip, int mode)
{
- struct davinci_nand_info *info = to_davinci_nand(mtd);
+ struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(chip));
unsigned long flags;
u32 val;
@@ -266,10 +264,10 @@ nand_davinci_readecc_4bit(struct davinci_nand_info *info, u32 code[4])
}
/* Terminate read ECC; or return ECC (as bytes) of data written to NAND. */
-static int nand_davinci_calculate_4bit(struct mtd_info *mtd,
- const u_char *dat, u_char *ecc_code)
+static int nand_davinci_calculate_4bit(struct nand_chip *chip,
+ const u_char *dat, u_char *ecc_code)
{
- struct davinci_nand_info *info = to_davinci_nand(mtd);
+ struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(chip));
u32 raw_ecc[4], *p;
unsigned i;
@@ -303,11 +301,11 @@ static int nand_davinci_calculate_4bit(struct mtd_info *mtd,
/* Correct up to 4 bits in data we just read, using state left in the
* hardware plus the ecc_code computed when it was first written.
*/
-static int nand_davinci_correct_4bit(struct mtd_info *mtd,
- u_char *data, u_char *ecc_code, u_char *null)
+static int nand_davinci_correct_4bit(struct nand_chip *chip, u_char *data,
+ u_char *ecc_code, u_char *null)
{
int i;
- struct davinci_nand_info *info = to_davinci_nand(mtd);
+ struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(chip));
unsigned short ecc10[8];
unsigned short *ecc16;
u32 syndrome[4];
@@ -436,38 +434,35 @@ correct:
* the two LSBs for NAND access ... so we can issue 32-bit reads/writes
* and have that transparently morphed into multiple NAND operations.
*/
-static void nand_davinci_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void nand_davinci_read_buf(struct nand_chip *chip, uint8_t *buf,
+ int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
-
if ((0x03 & ((uintptr_t)buf)) == 0 && (0x03 & len) == 0)
- ioread32_rep(chip->IO_ADDR_R, buf, len >> 2);
+ ioread32_rep(chip->legacy.IO_ADDR_R, buf, len >> 2);
else if ((0x01 & ((uintptr_t)buf)) == 0 && (0x01 & len) == 0)
- ioread16_rep(chip->IO_ADDR_R, buf, len >> 1);
+ ioread16_rep(chip->legacy.IO_ADDR_R, buf, len >> 1);
else
- ioread8_rep(chip->IO_ADDR_R, buf, len);
+ ioread8_rep(chip->legacy.IO_ADDR_R, buf, len);
}
-static void nand_davinci_write_buf(struct mtd_info *mtd,
- const uint8_t *buf, int len)
+static void nand_davinci_write_buf(struct nand_chip *chip, const uint8_t *buf,
+ int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
-
if ((0x03 & ((uintptr_t)buf)) == 0 && (0x03 & len) == 0)
- iowrite32_rep(chip->IO_ADDR_R, buf, len >> 2);
+ iowrite32_rep(chip->legacy.IO_ADDR_R, buf, len >> 2);
else if ((0x01 & ((uintptr_t)buf)) == 0 && (0x01 & len) == 0)
- iowrite16_rep(chip->IO_ADDR_R, buf, len >> 1);
+ iowrite16_rep(chip->legacy.IO_ADDR_R, buf, len >> 1);
else
- iowrite8_rep(chip->IO_ADDR_R, buf, len);
+ iowrite8_rep(chip->legacy.IO_ADDR_R, buf, len);
}
/*
* Check hardware register for wait status. Returns 1 if device is ready,
* 0 if it is still busy.
*/
-static int nand_davinci_dev_ready(struct mtd_info *mtd)
+static int nand_davinci_dev_ready(struct nand_chip *chip)
{
- struct davinci_nand_info *info = to_davinci_nand(mtd);
+ struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(chip));
return davinci_nand_readl(info, NANDFSR_OFFSET) & BIT(0);
}
@@ -764,9 +759,9 @@ static int nand_davinci_probe(struct platform_device *pdev)
mtd->dev.parent = &pdev->dev;
nand_set_flash_node(&info->chip, pdev->dev.of_node);
- info->chip.IO_ADDR_R = vaddr;
- info->chip.IO_ADDR_W = vaddr;
- info->chip.chip_delay = 0;
+ info->chip.legacy.IO_ADDR_R = vaddr;
+ info->chip.legacy.IO_ADDR_W = vaddr;
+ info->chip.legacy.chip_delay = 0;
info->chip.select_chip = nand_davinci_select_chip;
/* options such as NAND_BBT_USE_FLASH */
@@ -786,12 +781,12 @@ static int nand_davinci_probe(struct platform_device *pdev)
info->mask_cle = pdata->mask_cle ? : MASK_CLE;
/* Set address of hardware control function */
- info->chip.cmd_ctrl = nand_davinci_hwcontrol;
- info->chip.dev_ready = nand_davinci_dev_ready;
+ info->chip.legacy.cmd_ctrl = nand_davinci_hwcontrol;
+ info->chip.legacy.dev_ready = nand_davinci_dev_ready;
/* Speed up buffer I/O */
- info->chip.read_buf = nand_davinci_read_buf;
- info->chip.write_buf = nand_davinci_write_buf;
+ info->chip.legacy.read_buf = nand_davinci_read_buf;
+ info->chip.legacy.write_buf = nand_davinci_write_buf;
/* Use board-specific ECC config */
info->chip.ecc.mode = pdata->ecc_mode;
@@ -807,7 +802,7 @@ static int nand_davinci_probe(struct platform_device *pdev)
/* Scan to find existence of the device(s) */
info->chip.dummy_controller.ops = &davinci_nand_controller_ops;
- ret = nand_scan(mtd, pdata->mask_chipsel ? 2 : 1);
+ ret = nand_scan(&info->chip, pdata->mask_chipsel ? 2 : 1);
if (ret < 0) {
dev_dbg(&pdev->dev, "no NAND chip(s) found\n");
return ret;
@@ -841,7 +836,7 @@ static int nand_davinci_remove(struct platform_device *pdev)
ecc4_busy = false;
spin_unlock_irq(&davinci_nand_lock);
- nand_release(nand_to_mtd(&info->chip));
+ nand_release(&info->chip);
return 0;
}
diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c
index b864b93dd289..830ea247277b 100644
--- a/drivers/mtd/nand/raw/denali.c
+++ b/drivers/mtd/nand/raw/denali.c
@@ -1,15 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* NAND Flash Controller Device Driver
* Copyright © 2009-2010, Intel Corporation and its suppliers.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
+ * Copyright (c) 2017 Socionext Inc.
+ * Reworked by Masahiro Yamada <yamada.masahiro@socionext.com>
*/
#include <linux/bitfield.h>
@@ -25,9 +20,8 @@
#include "denali.h"
-MODULE_LICENSE("GPL");
-
#define DENALI_NAND_NAME "denali-nand"
+#define DENALI_DEFAULT_OOB_SKIP_BYTES 8
/* for Indexed Addressing */
#define DENALI_INDEXED_CTRL 0x00
@@ -222,8 +216,9 @@ static uint32_t denali_check_irq(struct denali_nand_info *denali)
return irq_status;
}
-static void denali_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void denali_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct denali_nand_info *denali = mtd_to_denali(mtd);
u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali);
int i;
@@ -232,9 +227,10 @@ static void denali_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
buf[i] = denali->host_read(denali, addr);
}
-static void denali_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+static void denali_write_buf(struct nand_chip *chip, const uint8_t *buf,
+ int len)
{
- struct denali_nand_info *denali = mtd_to_denali(mtd);
+ struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali);
int i;
@@ -242,9 +238,9 @@ static void denali_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
denali->host_write(denali, addr, buf[i]);
}
-static void denali_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
+static void denali_read_buf16(struct nand_chip *chip, uint8_t *buf, int len)
{
- struct denali_nand_info *denali = mtd_to_denali(mtd);
+ struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali);
uint16_t *buf16 = (uint16_t *)buf;
int i;
@@ -253,10 +249,10 @@ static void denali_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
buf16[i] = denali->host_read(denali, addr);
}
-static void denali_write_buf16(struct mtd_info *mtd, const uint8_t *buf,
+static void denali_write_buf16(struct nand_chip *chip, const uint8_t *buf,
int len)
{
- struct denali_nand_info *denali = mtd_to_denali(mtd);
+ struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali);
const uint16_t *buf16 = (const uint16_t *)buf;
int i;
@@ -265,32 +261,23 @@ static void denali_write_buf16(struct mtd_info *mtd, const uint8_t *buf,
denali->host_write(denali, addr, buf16[i]);
}
-static uint8_t denali_read_byte(struct mtd_info *mtd)
+static uint8_t denali_read_byte(struct nand_chip *chip)
{
uint8_t byte;
- denali_read_buf(mtd, &byte, 1);
+ denali_read_buf(chip, &byte, 1);
return byte;
}
-static void denali_write_byte(struct mtd_info *mtd, uint8_t byte)
-{
- denali_write_buf(mtd, &byte, 1);
-}
-
-static uint16_t denali_read_word(struct mtd_info *mtd)
+static void denali_write_byte(struct nand_chip *chip, uint8_t byte)
{
- uint16_t word;
-
- denali_read_buf16(mtd, (uint8_t *)&word, 2);
-
- return word;
+ denali_write_buf(chip, &byte, 1);
}
-static void denali_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
+static void denali_cmd_ctrl(struct nand_chip *chip, int dat, unsigned int ctrl)
{
- struct denali_nand_info *denali = mtd_to_denali(mtd);
+ struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
uint32_t type;
if (ctrl & NAND_CLE)
@@ -301,7 +288,8 @@ static void denali_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
return;
/*
- * Some commands are followed by chip->dev_ready or chip->waitfunc.
+ * Some commands are followed by chip->legacy.dev_ready or
+ * chip->legacy.waitfunc.
* irq_status must be cleared here to catch the R/B# interrupt later.
*/
if (ctrl & NAND_CTRL_CHANGE)
@@ -310,9 +298,9 @@ static void denali_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
denali->host_write(denali, DENALI_BANK(denali) | type, dat);
}
-static int denali_dev_ready(struct mtd_info *mtd)
+static int denali_dev_ready(struct nand_chip *chip)
{
- struct denali_nand_info *denali = mtd_to_denali(mtd);
+ struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
return !!(denali_check_irq(denali) & INTR__INT_ACT);
}
@@ -698,9 +686,10 @@ static void denali_oob_xfer(struct mtd_info *mtd, struct nand_chip *chip,
false);
}
-static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+static int denali_read_page_raw(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct denali_nand_info *denali = mtd_to_denali(mtd);
int writesize = mtd->writesize;
int oobsize = mtd->oobsize;
@@ -773,17 +762,18 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
return 0;
}
-static int denali_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int denali_read_oob(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
denali_oob_xfer(mtd, chip, page, 0);
return 0;
}
-static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int denali_write_oob(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct denali_nand_info *denali = mtd_to_denali(mtd);
denali_reset_irq(denali);
@@ -793,9 +783,10 @@ static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
return nand_prog_page_end_op(chip);
}
-static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+static int denali_read_page(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct denali_nand_info *denali = mtd_to_denali(mtd);
unsigned long uncor_ecc_flags = 0;
int stat = 0;
@@ -814,7 +805,7 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
return stat;
if (uncor_ecc_flags) {
- ret = denali_read_oob(mtd, chip, page);
+ ret = denali_read_oob(chip, page);
if (ret)
return ret;
@@ -825,9 +816,10 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
return stat;
}
-static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required, int page)
+static int denali_write_page_raw(struct nand_chip *chip, const uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct denali_nand_info *denali = mtd_to_denali(mtd);
int writesize = mtd->writesize;
int oobsize = mtd->oobsize;
@@ -903,25 +895,26 @@ static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
return denali_data_xfer(denali, tmp_buf, size, page, 1, 1);
}
-static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required, int page)
+static int denali_write_page(struct nand_chip *chip, const uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct denali_nand_info *denali = mtd_to_denali(mtd);
return denali_data_xfer(denali, (void *)buf, mtd->writesize,
page, 0, 1);
}
-static void denali_select_chip(struct mtd_info *mtd, int chip)
+static void denali_select_chip(struct nand_chip *chip, int cs)
{
- struct denali_nand_info *denali = mtd_to_denali(mtd);
+ struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
- denali->active_bank = chip;
+ denali->active_bank = cs;
}
-static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip)
+static int denali_waitfunc(struct nand_chip *chip)
{
- struct denali_nand_info *denali = mtd_to_denali(mtd);
+ struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
uint32_t irq_status;
/* R/B# pin transitioned from low to high? */
@@ -930,9 +923,9 @@ static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip)
return irq_status & INTR__INT_ACT ? 0 : NAND_STATUS_FAIL;
}
-static int denali_erase(struct mtd_info *mtd, int page)
+static int denali_erase(struct nand_chip *chip, int page)
{
- struct denali_nand_info *denali = mtd_to_denali(mtd);
+ struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
uint32_t irq_status;
denali_reset_irq(denali);
@@ -947,10 +940,10 @@ static int denali_erase(struct mtd_info *mtd, int page)
return irq_status & INTR__ERASE_COMP ? 0 : -EIO;
}
-static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
+static int denali_setup_data_interface(struct nand_chip *chip, int chipnr,
const struct nand_data_interface *conf)
{
- struct denali_nand_info *denali = mtd_to_denali(mtd);
+ struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
const struct nand_sdr_timings *timings;
unsigned long t_x, mult_x;
int acc_clks, re_2_we, re_2_re, we_2_re, addr_2_data;
@@ -1105,12 +1098,17 @@ static void denali_hw_init(struct denali_nand_info *denali)
denali->revision = swab16(ioread32(denali->reg + REVISION));
/*
- * tell driver how many bit controller will skip before
- * writing ECC code in OOB, this register may be already
- * set by firmware. So we read this value out.
- * if this value is 0, just let it be.
+ * Set how many bytes should be skipped before writing data in OOB.
+ * If a non-zero value has already been set (by firmware or something),
+ * just use it. Otherwise, set the driver default.
*/
denali->oob_skip_bytes = ioread32(denali->reg + SPARE_AREA_SKIP_BYTES);
+ if (!denali->oob_skip_bytes) {
+ denali->oob_skip_bytes = DENALI_DEFAULT_OOB_SKIP_BYTES;
+ iowrite32(denali->oob_skip_bytes,
+ denali->reg + SPARE_AREA_SKIP_BYTES);
+ }
+
denali_detect_max_banks(denali);
iowrite32(0x0F, denali->reg + RB_PIN_ENABLED);
iowrite32(CHIP_EN_DONT_CARE__FLAG, denali->reg + CHIP_ENABLE_DONT_CARE);
@@ -1277,11 +1275,11 @@ static int denali_attach_chip(struct nand_chip *chip)
mtd_set_ooblayout(mtd, &denali_ooblayout_ops);
if (chip->options & NAND_BUSWIDTH_16) {
- chip->read_buf = denali_read_buf16;
- chip->write_buf = denali_write_buf16;
+ chip->legacy.read_buf = denali_read_buf16;
+ chip->legacy.write_buf = denali_write_buf16;
} else {
- chip->read_buf = denali_read_buf;
- chip->write_buf = denali_write_buf;
+ chip->legacy.read_buf = denali_read_buf;
+ chip->legacy.write_buf = denali_write_buf;
}
chip->ecc.read_page = denali_read_page;
chip->ecc.read_page_raw = denali_read_page_raw;
@@ -1289,7 +1287,7 @@ static int denali_attach_chip(struct nand_chip *chip)
chip->ecc.write_page_raw = denali_write_page_raw;
chip->ecc.read_oob = denali_read_oob;
chip->ecc.write_oob = denali_write_oob;
- chip->erase = denali_erase;
+ chip->legacy.erase = denali_erase;
ret = denali_multidev_fixup(denali);
if (ret)
@@ -1358,12 +1356,11 @@ int denali_init(struct denali_nand_info *denali)
mtd->name = "denali-nand";
chip->select_chip = denali_select_chip;
- chip->read_byte = denali_read_byte;
- chip->write_byte = denali_write_byte;
- chip->read_word = denali_read_word;
- chip->cmd_ctrl = denali_cmd_ctrl;
- chip->dev_ready = denali_dev_ready;
- chip->waitfunc = denali_waitfunc;
+ chip->legacy.read_byte = denali_read_byte;
+ chip->legacy.write_byte = denali_write_byte;
+ chip->legacy.cmd_ctrl = denali_cmd_ctrl;
+ chip->legacy.dev_ready = denali_dev_ready;
+ chip->legacy.waitfunc = denali_waitfunc;
if (features & FEATURES__INDEX_ADDR) {
denali->host_read = denali_indexed_read;
@@ -1378,7 +1375,7 @@ int denali_init(struct denali_nand_info *denali)
chip->setup_data_interface = denali_setup_data_interface;
chip->dummy_controller.ops = &denali_controller_ops;
- ret = nand_scan(mtd, denali->max_banks);
+ ret = nand_scan(chip, denali->max_banks);
if (ret)
goto disable_irq;
@@ -1401,9 +1398,11 @@ EXPORT_SYMBOL(denali_init);
void denali_remove(struct denali_nand_info *denali)
{
- struct mtd_info *mtd = nand_to_mtd(&denali->nand);
-
- nand_release(mtd);
+ nand_release(&denali->nand);
denali_disable_irq(denali);
}
EXPORT_SYMBOL(denali_remove);
+
+MODULE_DESCRIPTION("Driver core for Denali NAND controller");
+MODULE_AUTHOR("Intel Corporation and its suppliers");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mtd/nand/raw/denali.h b/drivers/mtd/nand/raw/denali.h
index 1f8feaf924eb..57a5498f58bb 100644
--- a/drivers/mtd/nand/raw/denali.h
+++ b/drivers/mtd/nand/raw/denali.h
@@ -1,15 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* NAND Flash Controller Device Driver
* Copyright (c) 2009 - 2010, Intel Corporation and its suppliers.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
*/
#ifndef __DENALI_H__
diff --git a/drivers/mtd/nand/raw/denali_dt.c b/drivers/mtd/nand/raw/denali_dt.c
index 0faaad032e5f..7c6a8a426606 100644
--- a/drivers/mtd/nand/raw/denali_dt.c
+++ b/drivers/mtd/nand/raw/denali_dt.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* NAND Flash Controller Device Driver for DT
*
* Copyright © 2011, Picochip.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
*/
#include <linux/clk.h>
@@ -202,6 +194,6 @@ static struct platform_driver denali_dt_driver = {
};
module_platform_driver(denali_dt_driver);
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Jamie Iles");
MODULE_DESCRIPTION("DT driver for Denali NAND controller");
diff --git a/drivers/mtd/nand/raw/denali_pci.c b/drivers/mtd/nand/raw/denali_pci.c
index 7c8efc4c7bdf..48e9ac54ad53 100644
--- a/drivers/mtd/nand/raw/denali_pci.c
+++ b/drivers/mtd/nand/raw/denali_pci.c
@@ -1,15 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* NAND Flash Controller Device Driver
* Copyright © 2009-2010, Intel Corporation and its suppliers.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
*/
#include <linux/errno.h>
diff --git a/drivers/mtd/nand/raw/diskonchip.c b/drivers/mtd/nand/raw/diskonchip.c
index 3c46188dd6d2..3a4c373affab 100644
--- a/drivers/mtd/nand/raw/diskonchip.c
+++ b/drivers/mtd/nand/raw/diskonchip.c
@@ -83,9 +83,9 @@ static u_char empty_write_ecc[6] = { 0x4b, 0x00, 0xe2, 0x0e, 0x93, 0xf7 };
#define DoC_is_Millennium(doc) ((doc)->ChipID == DOC_ChipID_DocMil)
#define DoC_is_2000(doc) ((doc)->ChipID == DOC_ChipID_Doc2k)
-static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd,
+static void doc200x_hwcontrol(struct nand_chip *this, int cmd,
unsigned int bitmask);
-static void doc200x_select_chip(struct mtd_info *mtd, int chip);
+static void doc200x_select_chip(struct nand_chip *this, int chip);
static int debug = 0;
module_param(debug, int, 0);
@@ -290,9 +290,8 @@ static inline int DoC_WaitReady(struct doc_priv *doc)
return ret;
}
-static void doc2000_write_byte(struct mtd_info *mtd, u_char datum)
+static void doc2000_write_byte(struct nand_chip *this, u_char datum)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
@@ -302,9 +301,8 @@ static void doc2000_write_byte(struct mtd_info *mtd, u_char datum)
WriteDOC(datum, docptr, 2k_CDSN_IO);
}
-static u_char doc2000_read_byte(struct mtd_info *mtd)
+static u_char doc2000_read_byte(struct nand_chip *this)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
u_char ret;
@@ -317,9 +315,9 @@ static u_char doc2000_read_byte(struct mtd_info *mtd)
return ret;
}
-static void doc2000_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
+static void doc2000_writebuf(struct nand_chip *this, const u_char *buf,
+ int len)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int i;
@@ -334,9 +332,8 @@ static void doc2000_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
printk("\n");
}
-static void doc2000_readbuf(struct mtd_info *mtd, u_char *buf, int len)
+static void doc2000_readbuf(struct nand_chip *this, u_char *buf, int len)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int i;
@@ -344,14 +341,12 @@ static void doc2000_readbuf(struct mtd_info *mtd, u_char *buf, int len)
if (debug)
printk("readbuf of %d bytes: ", len);
- for (i = 0; i < len; i++) {
+ for (i = 0; i < len; i++)
buf[i] = ReadDOC(docptr, 2k_CDSN_IO + i);
- }
}
-static void doc2000_readbuf_dword(struct mtd_info *mtd, u_char *buf, int len)
+static void doc2000_readbuf_dword(struct nand_chip *this, u_char *buf, int len)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int i;
@@ -376,19 +371,19 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
struct doc_priv *doc = nand_get_controller_data(this);
uint16_t ret;
- doc200x_select_chip(mtd, nr);
- doc200x_hwcontrol(mtd, NAND_CMD_READID,
+ doc200x_select_chip(this, nr);
+ doc200x_hwcontrol(this, NAND_CMD_READID,
NAND_CTRL_CLE | NAND_CTRL_CHANGE);
- doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
- doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
+ doc200x_hwcontrol(this, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
+ doc200x_hwcontrol(this, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
/* We can't use dev_ready here, but at least we wait for the
* command to complete
*/
udelay(50);
- ret = this->read_byte(mtd) << 8;
- ret |= this->read_byte(mtd);
+ ret = this->legacy.read_byte(this) << 8;
+ ret |= this->legacy.read_byte(this);
if (doc->ChipID == DOC_ChipID_Doc2k && try_dword && !nr) {
/* First chip probe. See if we get same results by 32-bit access */
@@ -398,10 +393,10 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
} ident;
void __iomem *docptr = doc->virtadr;
- doc200x_hwcontrol(mtd, NAND_CMD_READID,
+ doc200x_hwcontrol(this, NAND_CMD_READID,
NAND_CTRL_CLE | NAND_CTRL_CHANGE);
- doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
- doc200x_hwcontrol(mtd, NAND_CMD_NONE,
+ doc200x_hwcontrol(this, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
+ doc200x_hwcontrol(this, NAND_CMD_NONE,
NAND_NCE | NAND_CTRL_CHANGE);
udelay(50);
@@ -409,7 +404,7 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
ident.dword = readl(docptr + DoC_2k_CDSN_IO);
if (((ident.byte[0] << 8) | ident.byte[1]) == ret) {
pr_info("DiskOnChip 2000 responds to DWORD access\n");
- this->read_buf = &doc2000_readbuf_dword;
+ this->legacy.read_buf = &doc2000_readbuf_dword;
}
}
@@ -438,7 +433,7 @@ static void __init doc2000_count_chips(struct mtd_info *mtd)
pr_debug("Detected %d chips per floor.\n", i);
}
-static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this)
+static int doc200x_wait(struct nand_chip *this)
{
struct doc_priv *doc = nand_get_controller_data(this);
@@ -447,14 +442,13 @@ static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this)
DoC_WaitReady(doc);
nand_status_op(this, NULL);
DoC_WaitReady(doc);
- status = (int)this->read_byte(mtd);
+ status = (int)this->legacy.read_byte(this);
return status;
}
-static void doc2001_write_byte(struct mtd_info *mtd, u_char datum)
+static void doc2001_write_byte(struct nand_chip *this, u_char datum)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
@@ -463,9 +457,8 @@ static void doc2001_write_byte(struct mtd_info *mtd, u_char datum)
WriteDOC(datum, docptr, WritePipeTerm);
}
-static u_char doc2001_read_byte(struct mtd_info *mtd)
+static u_char doc2001_read_byte(struct nand_chip *this)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
@@ -477,9 +470,8 @@ static u_char doc2001_read_byte(struct mtd_info *mtd)
return ReadDOC(docptr, LastDataRead);
}
-static void doc2001_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
+static void doc2001_writebuf(struct nand_chip *this, const u_char *buf, int len)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int i;
@@ -490,9 +482,8 @@ static void doc2001_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
WriteDOC(0x00, docptr, WritePipeTerm);
}
-static void doc2001_readbuf(struct mtd_info *mtd, u_char *buf, int len)
+static void doc2001_readbuf(struct nand_chip *this, u_char *buf, int len)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int i;
@@ -507,9 +498,8 @@ static void doc2001_readbuf(struct mtd_info *mtd, u_char *buf, int len)
buf[i] = ReadDOC(docptr, LastDataRead);
}
-static u_char doc2001plus_read_byte(struct mtd_info *mtd)
+static u_char doc2001plus_read_byte(struct nand_chip *this)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
u_char ret;
@@ -522,9 +512,8 @@ static u_char doc2001plus_read_byte(struct mtd_info *mtd)
return ret;
}
-static void doc2001plus_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
+static void doc2001plus_writebuf(struct nand_chip *this, const u_char *buf, int len)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int i;
@@ -540,9 +529,8 @@ static void doc2001plus_writebuf(struct mtd_info *mtd, const u_char *buf, int le
printk("\n");
}
-static void doc2001plus_readbuf(struct mtd_info *mtd, u_char *buf, int len)
+static void doc2001plus_readbuf(struct nand_chip *this, u_char *buf, int len)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int i;
@@ -571,9 +559,8 @@ static void doc2001plus_readbuf(struct mtd_info *mtd, u_char *buf, int len)
printk("\n");
}
-static void doc2001plus_select_chip(struct mtd_info *mtd, int chip)
+static void doc2001plus_select_chip(struct nand_chip *this, int chip)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int floor = 0;
@@ -598,9 +585,8 @@ static void doc2001plus_select_chip(struct mtd_info *mtd, int chip)
doc->curfloor = floor;
}
-static void doc200x_select_chip(struct mtd_info *mtd, int chip)
+static void doc200x_select_chip(struct nand_chip *this, int chip)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int floor = 0;
@@ -615,12 +601,12 @@ static void doc200x_select_chip(struct mtd_info *mtd, int chip)
chip -= (floor * doc->chips_per_floor);
/* 11.4.4 -- deassert CE before changing chip */
- doc200x_hwcontrol(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
+ doc200x_hwcontrol(this, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
WriteDOC(floor, docptr, FloorSelect);
WriteDOC(chip, docptr, CDSNDeviceSelect);
- doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
+ doc200x_hwcontrol(this, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
doc->curchip = chip;
doc->curfloor = floor;
@@ -628,10 +614,9 @@ static void doc200x_select_chip(struct mtd_info *mtd, int chip)
#define CDSN_CTRL_MSK (CDSN_CTRL_CE | CDSN_CTRL_CLE | CDSN_CTRL_ALE)
-static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd,
+static void doc200x_hwcontrol(struct nand_chip *this, int cmd,
unsigned int ctrl)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
@@ -646,15 +631,16 @@ static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd,
}
if (cmd != NAND_CMD_NONE) {
if (DoC_is_2000(doc))
- doc2000_write_byte(mtd, cmd);
+ doc2000_write_byte(this, cmd);
else
- doc2001_write_byte(mtd, cmd);
+ doc2001_write_byte(this, cmd);
}
}
-static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int column, int page_addr)
+static void doc2001plus_command(struct nand_chip *this, unsigned command,
+ int column, int page_addr)
{
- struct nand_chip *this = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(this);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
@@ -729,13 +715,13 @@ static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int colu
return;
case NAND_CMD_RESET:
- if (this->dev_ready)
+ if (this->legacy.dev_ready)
break;
- udelay(this->chip_delay);
+ udelay(this->legacy.chip_delay);
WriteDOC(NAND_CMD_STATUS, docptr, Mplus_FlashCmd);
WriteDOC(0, docptr, Mplus_WritePipeTerm);
WriteDOC(0, docptr, Mplus_WritePipeTerm);
- while (!(this->read_byte(mtd) & 0x40)) ;
+ while (!(this->legacy.read_byte(this) & 0x40)) ;
return;
/* This applies to read commands */
@@ -744,8 +730,8 @@ static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int colu
* If we don't have access to the busy pin, we apply the given
* command delay
*/
- if (!this->dev_ready) {
- udelay(this->chip_delay);
+ if (!this->legacy.dev_ready) {
+ udelay(this->legacy.chip_delay);
return;
}
}
@@ -754,12 +740,11 @@ static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int colu
* any case on any machine. */
ndelay(100);
/* wait until command is processed */
- while (!this->dev_ready(mtd)) ;
+ while (!this->legacy.dev_ready(this)) ;
}
-static int doc200x_dev_ready(struct mtd_info *mtd)
+static int doc200x_dev_ready(struct nand_chip *this)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
@@ -790,16 +775,15 @@ static int doc200x_dev_ready(struct mtd_info *mtd)
}
}
-static int doc200x_block_bad(struct mtd_info *mtd, loff_t ofs)
+static int doc200x_block_bad(struct nand_chip *this, loff_t ofs)
{
/* This is our last resort if we couldn't find or create a BBT. Just
pretend all blocks are good. */
return 0;
}
-static void doc200x_enable_hwecc(struct mtd_info *mtd, int mode)
+static void doc200x_enable_hwecc(struct nand_chip *this, int mode)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
@@ -816,9 +800,8 @@ static void doc200x_enable_hwecc(struct mtd_info *mtd, int mode)
}
}
-static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode)
+static void doc2001plus_enable_hwecc(struct nand_chip *this, int mode)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
@@ -836,9 +819,9 @@ static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode)
}
/* This code is only called on write */
-static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat, unsigned char *ecc_code)
+static int doc200x_calculate_ecc(struct nand_chip *this, const u_char *dat,
+ unsigned char *ecc_code)
{
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
int i;
@@ -895,11 +878,10 @@ static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat, unsign
return 0;
}
-static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat,
+static int doc200x_correct_data(struct nand_chip *this, u_char *dat,
u_char *read_ecc, u_char *isnull)
{
int i, ret = 0;
- struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
void __iomem *docptr = doc->virtadr;
uint8_t calc_ecc[6];
@@ -1357,9 +1339,9 @@ static inline int __init doc2000_init(struct mtd_info *mtd)
struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
- this->read_byte = doc2000_read_byte;
- this->write_buf = doc2000_writebuf;
- this->read_buf = doc2000_readbuf;
+ this->legacy.read_byte = doc2000_read_byte;
+ this->legacy.write_buf = doc2000_writebuf;
+ this->legacy.read_buf = doc2000_readbuf;
doc->late_init = nftl_scan_bbt;
doc->CDSNControl = CDSN_CTRL_FLASH_IO | CDSN_CTRL_ECC_IO;
@@ -1373,9 +1355,9 @@ static inline int __init doc2001_init(struct mtd_info *mtd)
struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
- this->read_byte = doc2001_read_byte;
- this->write_buf = doc2001_writebuf;
- this->read_buf = doc2001_readbuf;
+ this->legacy.read_byte = doc2001_read_byte;
+ this->legacy.write_buf = doc2001_writebuf;
+ this->legacy.read_buf = doc2001_readbuf;
ReadDOC(doc->virtadr, ChipID);
ReadDOC(doc->virtadr, ChipID);
@@ -1403,13 +1385,13 @@ static inline int __init doc2001plus_init(struct mtd_info *mtd)
struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
- this->read_byte = doc2001plus_read_byte;
- this->write_buf = doc2001plus_writebuf;
- this->read_buf = doc2001plus_readbuf;
+ this->legacy.read_byte = doc2001plus_read_byte;
+ this->legacy.write_buf = doc2001plus_writebuf;
+ this->legacy.read_buf = doc2001plus_readbuf;
doc->late_init = inftl_scan_bbt;
- this->cmd_ctrl = NULL;
+ this->legacy.cmd_ctrl = NULL;
this->select_chip = doc2001plus_select_chip;
- this->cmdfunc = doc2001plus_command;
+ this->legacy.cmdfunc = doc2001plus_command;
this->ecc.hwctl = doc2001plus_enable_hwecc;
doc->chips_per_floor = 1;
@@ -1587,10 +1569,10 @@ static int __init doc_probe(unsigned long physadr)
nand_set_controller_data(nand, doc);
nand->select_chip = doc200x_select_chip;
- nand->cmd_ctrl = doc200x_hwcontrol;
- nand->dev_ready = doc200x_dev_ready;
- nand->waitfunc = doc200x_wait;
- nand->block_bad = doc200x_block_bad;
+ nand->legacy.cmd_ctrl = doc200x_hwcontrol;
+ nand->legacy.dev_ready = doc200x_dev_ready;
+ nand->legacy.waitfunc = doc200x_wait;
+ nand->legacy.block_bad = doc200x_block_bad;
nand->ecc.hwctl = doc200x_enable_hwecc;
nand->ecc.calculate = doc200x_calculate_ecc;
nand->ecc.correct = doc200x_correct_data;
@@ -1620,14 +1602,14 @@ static int __init doc_probe(unsigned long physadr)
else
numchips = doc2001_init(mtd);
- if ((ret = nand_scan(mtd, numchips)) || (ret = doc->late_init(mtd))) {
+ if ((ret = nand_scan(nand, numchips)) || (ret = doc->late_init(mtd))) {
/* DBB note: i believe nand_release is necessary here, as
buffers may have been allocated in nand_base. Check with
Thomas. FIX ME! */
/* nand_release will call mtd_device_unregister, but we
haven't yet added it. This is handled without incident by
mtd_device_unregister, as far as I can tell. */
- nand_release(mtd);
+ nand_release(nand);
goto fail;
}
@@ -1662,7 +1644,7 @@ static void release_nanddoc(void)
doc = nand_get_controller_data(nand);
nextmtd = doc->nextdoc;
- nand_release(mtd);
+ nand_release(nand);
iounmap(doc->virtadr);
release_mem_region(doc->physadr, DOC_IOREMAP_LEN);
free_rs(doc->rs_decoder);
diff --git a/drivers/mtd/nand/raw/docg4.c b/drivers/mtd/nand/raw/docg4.c
deleted file mode 100644
index 427fcbc1b71c..000000000000
--- a/drivers/mtd/nand/raw/docg4.c
+++ /dev/null
@@ -1,1442 +0,0 @@
-/*
- * Copyright © 2012 Mike Dunn <mikedunn@newsguy.com>
- *
- * mtd nand driver for M-Systems DiskOnChip G4
- *
- * 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.
- *
- * Tested on the Palm Treo 680. The G4 is also present on Toshiba Portege, Asus
- * P526, some HTC smartphones (Wizard, Prophet, ...), O2 XDA Zinc, maybe others.
- * Should work on these as well. Let me know!
- *
- * TODO:
- *
- * Mechanism for management of password-protected areas
- *
- * Hamming ecc when reading oob only
- *
- * According to the M-Sys documentation, this device is also available in a
- * "dual-die" configuration having a 256MB capacity, but no mechanism for
- * detecting this variant is documented. Currently this driver assumes 128MB
- * capacity.
- *
- * Support for multiple cascaded devices ("floors"). Not sure which gadgets
- * contain multiple G4s in a cascaded configuration, if any.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/export.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/bitops.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/bch.h>
-#include <linux/bitrev.h>
-#include <linux/jiffies.h>
-
-/*
- * In "reliable mode" consecutive 2k pages are used in parallel (in some
- * fashion) to store the same data. The data can be read back from the
- * even-numbered pages in the normal manner; odd-numbered pages will appear to
- * contain junk. Systems that boot from the docg4 typically write the secondary
- * program loader (SPL) code in this mode. The SPL is loaded by the initial
- * program loader (IPL, stored in the docg4's 2k NOR-like region that is mapped
- * to the reset vector address). This module parameter enables you to use this
- * driver to write the SPL. When in this mode, no more than 2k of data can be
- * written at a time, because the addresses do not increment in the normal
- * manner, and the starting offset must be within an even-numbered 2k region;
- * i.e., invalid starting offsets are 0x800, 0xa00, 0xc00, 0xe00, 0x1800,
- * 0x1a00, ... Reliable mode is a special case and should not be used unless
- * you know what you're doing.
- */
-static bool reliable_mode;
-module_param(reliable_mode, bool, 0);
-MODULE_PARM_DESC(reliable_mode, "pages are programmed in reliable mode");
-
-/*
- * You'll want to ignore badblocks if you're reading a partition that contains
- * data written by the TrueFFS library (i.e., by PalmOS, Windows, etc), since
- * it does not use mtd nand's method for marking bad blocks (using oob area).
- * This will also skip the check of the "page written" flag.
- */
-static bool ignore_badblocks;
-module_param(ignore_badblocks, bool, 0);
-MODULE_PARM_DESC(ignore_badblocks, "no badblock checking performed");
-
-struct docg4_priv {
- struct mtd_info *mtd;
- struct device *dev;
- void __iomem *virtadr;
- int status;
- struct {
- unsigned int command;
- int column;
- int page;
- } last_command;
- uint8_t oob_buf[16];
- uint8_t ecc_buf[7];
- int oob_page;
- struct bch_control *bch;
-};
-
-/*
- * Defines prefixed with DOCG4 are unique to the diskonchip G4. All others are
- * shared with other diskonchip devices (P3, G3 at least).
- *
- * Functions with names prefixed with docg4_ are mtd / nand interface functions
- * (though they may also be called internally). All others are internal.
- */
-
-#define DOC_IOSPACE_DATA 0x0800
-
-/* register offsets */
-#define DOC_CHIPID 0x1000
-#define DOC_DEVICESELECT 0x100a
-#define DOC_ASICMODE 0x100c
-#define DOC_DATAEND 0x101e
-#define DOC_NOP 0x103e
-
-#define DOC_FLASHSEQUENCE 0x1032
-#define DOC_FLASHCOMMAND 0x1034
-#define DOC_FLASHADDRESS 0x1036
-#define DOC_FLASHCONTROL 0x1038
-#define DOC_ECCCONF0 0x1040
-#define DOC_ECCCONF1 0x1042
-#define DOC_HAMMINGPARITY 0x1046
-#define DOC_BCH_SYNDROM(idx) (0x1048 + idx)
-
-#define DOC_ASICMODECONFIRM 0x1072
-#define DOC_CHIPID_INV 0x1074
-#define DOC_POWERMODE 0x107c
-
-#define DOCG4_MYSTERY_REG 0x1050
-
-/* apparently used only to write oob bytes 6 and 7 */
-#define DOCG4_OOB_6_7 0x1052
-
-/* DOC_FLASHSEQUENCE register commands */
-#define DOC_SEQ_RESET 0x00
-#define DOCG4_SEQ_PAGE_READ 0x03
-#define DOCG4_SEQ_FLUSH 0x29
-#define DOCG4_SEQ_PAGEWRITE 0x16
-#define DOCG4_SEQ_PAGEPROG 0x1e
-#define DOCG4_SEQ_BLOCKERASE 0x24
-#define DOCG4_SEQ_SETMODE 0x45
-
-/* DOC_FLASHCOMMAND register commands */
-#define DOCG4_CMD_PAGE_READ 0x00
-#define DOC_CMD_ERASECYCLE2 0xd0
-#define DOCG4_CMD_FLUSH 0x70
-#define DOCG4_CMD_READ2 0x30
-#define DOC_CMD_PROG_BLOCK_ADDR 0x60
-#define DOCG4_CMD_PAGEWRITE 0x80
-#define DOC_CMD_PROG_CYCLE2 0x10
-#define DOCG4_CMD_FAST_MODE 0xa3 /* functionality guessed */
-#define DOC_CMD_RELIABLE_MODE 0x22
-#define DOC_CMD_RESET 0xff
-
-/* DOC_POWERMODE register bits */
-#define DOC_POWERDOWN_READY 0x80
-
-/* DOC_FLASHCONTROL register bits */
-#define DOC_CTRL_CE 0x10
-#define DOC_CTRL_UNKNOWN 0x40
-#define DOC_CTRL_FLASHREADY 0x01
-
-/* DOC_ECCCONF0 register bits */
-#define DOC_ECCCONF0_READ_MODE 0x8000
-#define DOC_ECCCONF0_UNKNOWN 0x2000
-#define DOC_ECCCONF0_ECC_ENABLE 0x1000
-#define DOC_ECCCONF0_DATA_BYTES_MASK 0x07ff
-
-/* DOC_ECCCONF1 register bits */
-#define DOC_ECCCONF1_BCH_SYNDROM_ERR 0x80
-#define DOC_ECCCONF1_ECC_ENABLE 0x07
-#define DOC_ECCCONF1_PAGE_IS_WRITTEN 0x20
-
-/* DOC_ASICMODE register bits */
-#define DOC_ASICMODE_RESET 0x00
-#define DOC_ASICMODE_NORMAL 0x01
-#define DOC_ASICMODE_POWERDOWN 0x02
-#define DOC_ASICMODE_MDWREN 0x04
-#define DOC_ASICMODE_BDETCT_RESET 0x08
-#define DOC_ASICMODE_RSTIN_RESET 0x10
-#define DOC_ASICMODE_RAM_WE 0x20
-
-/* good status values read after read/write/erase operations */
-#define DOCG4_PROGSTATUS_GOOD 0x51
-#define DOCG4_PROGSTATUS_GOOD_2 0xe0
-
-/*
- * On read operations (page and oob-only), the first byte read from I/O reg is a
- * status. On error, it reads 0x73; otherwise, it reads either 0x71 (first read
- * after reset only) or 0x51, so bit 1 is presumed to be an error indicator.
- */
-#define DOCG4_READ_ERROR 0x02 /* bit 1 indicates read error */
-
-/* anatomy of the device */
-#define DOCG4_CHIP_SIZE 0x8000000
-#define DOCG4_PAGE_SIZE 0x200
-#define DOCG4_PAGES_PER_BLOCK 0x200
-#define DOCG4_BLOCK_SIZE (DOCG4_PAGES_PER_BLOCK * DOCG4_PAGE_SIZE)
-#define DOCG4_NUMBLOCKS (DOCG4_CHIP_SIZE / DOCG4_BLOCK_SIZE)
-#define DOCG4_OOB_SIZE 0x10
-#define DOCG4_CHIP_SHIFT 27 /* log_2(DOCG4_CHIP_SIZE) */
-#define DOCG4_PAGE_SHIFT 9 /* log_2(DOCG4_PAGE_SIZE) */
-#define DOCG4_ERASE_SHIFT 18 /* log_2(DOCG4_BLOCK_SIZE) */
-
-/* all but the last byte is included in ecc calculation */
-#define DOCG4_BCH_SIZE (DOCG4_PAGE_SIZE + DOCG4_OOB_SIZE - 1)
-
-#define DOCG4_USERDATA_LEN 520 /* 512 byte page plus 8 oob avail to user */
-
-/* expected values from the ID registers */
-#define DOCG4_IDREG1_VALUE 0x0400
-#define DOCG4_IDREG2_VALUE 0xfbff
-
-/* primitive polynomial used to build the Galois field used by hw ecc gen */
-#define DOCG4_PRIMITIVE_POLY 0x4443
-
-#define DOCG4_M 14 /* Galois field is of order 2^14 */
-#define DOCG4_T 4 /* BCH alg corrects up to 4 bit errors */
-
-#define DOCG4_FACTORY_BBT_PAGE 16 /* page where read-only factory bbt lives */
-#define DOCG4_REDUNDANT_BBT_PAGE 24 /* page where redundant factory bbt lives */
-
-/*
- * Bytes 0, 1 are used as badblock marker.
- * Bytes 2 - 6 are available to the user.
- * Byte 7 is hamming ecc for first 7 oob bytes only.
- * Bytes 8 - 14 are hw-generated ecc covering entire page + oob bytes 0 - 14.
- * Byte 15 (the last) is used by the driver as a "page written" flag.
- */
-static int docg4_ooblayout_ecc(struct mtd_info *mtd, int section,
- struct mtd_oob_region *oobregion)
-{
- if (section)
- return -ERANGE;
-
- oobregion->offset = 7;
- oobregion->length = 9;
-
- return 0;
-}
-
-static int docg4_ooblayout_free(struct mtd_info *mtd, int section,
- struct mtd_oob_region *oobregion)
-{
- if (section)
- return -ERANGE;
-
- oobregion->offset = 2;
- oobregion->length = 5;
-
- return 0;
-}
-
-static const struct mtd_ooblayout_ops docg4_ooblayout_ops = {
- .ecc = docg4_ooblayout_ecc,
- .free = docg4_ooblayout_free,
-};
-
-/*
- * The device has a nop register which M-Sys claims is for the purpose of
- * inserting precise delays. But beware; at least some operations fail if the
- * nop writes are replaced with a generic delay!
- */
-static inline void write_nop(void __iomem *docptr)
-{
- writew(0, docptr + DOC_NOP);
-}
-
-static void docg4_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
-{
- int i;
- struct nand_chip *nand = mtd_to_nand(mtd);
- uint16_t *p = (uint16_t *) buf;
- len >>= 1;
-
- for (i = 0; i < len; i++)
- p[i] = readw(nand->IO_ADDR_R);
-}
-
-static void docg4_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
-{
- int i;
- struct nand_chip *nand = mtd_to_nand(mtd);
- uint16_t *p = (uint16_t *) buf;
- len >>= 1;
-
- for (i = 0; i < len; i++)
- writew(p[i], nand->IO_ADDR_W);
-}
-
-static int poll_status(struct docg4_priv *doc)
-{
- /*
- * Busy-wait for the FLASHREADY bit to be set in the FLASHCONTROL
- * register. Operations known to take a long time (e.g., block erase)
- * should sleep for a while before calling this.
- */
-
- uint16_t flash_status;
- unsigned long timeo;
- void __iomem *docptr = doc->virtadr;
-
- dev_dbg(doc->dev, "%s...\n", __func__);
-
- /* hardware quirk requires reading twice initially */
- flash_status = readw(docptr + DOC_FLASHCONTROL);
-
- timeo = jiffies + msecs_to_jiffies(200); /* generous timeout */
- do {
- cpu_relax();
- flash_status = readb(docptr + DOC_FLASHCONTROL);
- } while (!(flash_status & DOC_CTRL_FLASHREADY) &&
- time_before(jiffies, timeo));
-
- if (unlikely(!(flash_status & DOC_CTRL_FLASHREADY))) {
- dev_err(doc->dev, "%s: timed out!\n", __func__);
- return NAND_STATUS_FAIL;
- }
-
- return 0;
-}
-
-
-static int docg4_wait(struct mtd_info *mtd, struct nand_chip *nand)
-{
-
- struct docg4_priv *doc = nand_get_controller_data(nand);
- int status = NAND_STATUS_WP; /* inverse logic?? */
- dev_dbg(doc->dev, "%s...\n", __func__);
-
- /* report any previously unreported error */
- if (doc->status) {
- status |= doc->status;
- doc->status = 0;
- return status;
- }
-
- status |= poll_status(doc);
- return status;
-}
-
-static void docg4_select_chip(struct mtd_info *mtd, int chip)
-{
- /*
- * Select among multiple cascaded chips ("floors"). Multiple floors are
- * not yet supported, so the only valid non-negative value is 0.
- */
- struct nand_chip *nand = mtd_to_nand(mtd);
- struct docg4_priv *doc = nand_get_controller_data(nand);
- void __iomem *docptr = doc->virtadr;
-
- dev_dbg(doc->dev, "%s: chip %d\n", __func__, chip);
-
- if (chip < 0)
- return; /* deselected */
-
- if (chip > 0)
- dev_warn(doc->dev, "multiple floors currently unsupported\n");
-
- writew(0, docptr + DOC_DEVICESELECT);
-}
-
-static void reset(struct mtd_info *mtd)
-{
- /* full device reset */
-
- struct nand_chip *nand = mtd_to_nand(mtd);
- struct docg4_priv *doc = nand_get_controller_data(nand);
- void __iomem *docptr = doc->virtadr;
-
- writew(DOC_ASICMODE_RESET | DOC_ASICMODE_MDWREN,
- docptr + DOC_ASICMODE);
- writew(~(DOC_ASICMODE_RESET | DOC_ASICMODE_MDWREN),
- docptr + DOC_ASICMODECONFIRM);
- write_nop(docptr);
-
- writew(DOC_ASICMODE_NORMAL | DOC_ASICMODE_MDWREN,
- docptr + DOC_ASICMODE);
- writew(~(DOC_ASICMODE_NORMAL | DOC_ASICMODE_MDWREN),
- docptr + DOC_ASICMODECONFIRM);
-
- writew(DOC_ECCCONF1_ECC_ENABLE, docptr + DOC_ECCCONF1);
-
- poll_status(doc);
-}
-
-static void read_hw_ecc(void __iomem *docptr, uint8_t *ecc_buf)
-{
- /* read the 7 hw-generated ecc bytes */
-
- int i;
- for (i = 0; i < 7; i++) { /* hw quirk; read twice */
- ecc_buf[i] = readb(docptr + DOC_BCH_SYNDROM(i));
- ecc_buf[i] = readb(docptr + DOC_BCH_SYNDROM(i));
- }
-}
-
-static int correct_data(struct mtd_info *mtd, uint8_t *buf, int page)
-{
- /*
- * Called after a page read when hardware reports bitflips.
- * Up to four bitflips can be corrected.
- */
-
- struct nand_chip *nand = mtd_to_nand(mtd);
- struct docg4_priv *doc = nand_get_controller_data(nand);
- void __iomem *docptr = doc->virtadr;
- int i, numerrs, errpos[4];
- const uint8_t blank_read_hwecc[8] = {
- 0xcf, 0x72, 0xfc, 0x1b, 0xa9, 0xc7, 0xb9, 0 };
-
- read_hw_ecc(docptr, doc->ecc_buf); /* read 7 hw-generated ecc bytes */
-
- /* check if read error is due to a blank page */
- if (!memcmp(doc->ecc_buf, blank_read_hwecc, 7))
- return 0; /* yes */
-
- /* skip additional check of "written flag" if ignore_badblocks */
- if (ignore_badblocks == false) {
-
- /*
- * If the hw ecc bytes are not those of a blank page, there's
- * still a chance that the page is blank, but was read with
- * errors. Check the "written flag" in last oob byte, which
- * is set to zero when a page is written. If more than half
- * the bits are set, assume a blank page. Unfortunately, the
- * bit flips(s) are not reported in stats.
- */
-
- if (nand->oob_poi[15]) {
- int bit, numsetbits = 0;
- unsigned long written_flag = nand->oob_poi[15];
- for_each_set_bit(bit, &written_flag, 8)
- numsetbits++;
- if (numsetbits > 4) { /* assume blank */
- dev_warn(doc->dev,
- "error(s) in blank page "
- "at offset %08x\n",
- page * DOCG4_PAGE_SIZE);
- return 0;
- }
- }
- }
-
- /*
- * The hardware ecc unit produces oob_ecc ^ calc_ecc. The kernel's bch
- * algorithm is used to decode this. However the hw operates on page
- * data in a bit order that is the reverse of that of the bch alg,
- * requiring that the bits be reversed on the result. Thanks to Ivan
- * Djelic for his analysis!
- */
- for (i = 0; i < 7; i++)
- doc->ecc_buf[i] = bitrev8(doc->ecc_buf[i]);
-
- numerrs = decode_bch(doc->bch, NULL, DOCG4_USERDATA_LEN, NULL,
- doc->ecc_buf, NULL, errpos);
-
- if (numerrs == -EBADMSG) {
- dev_warn(doc->dev, "uncorrectable errors at offset %08x\n",
- page * DOCG4_PAGE_SIZE);
- return -EBADMSG;
- }
-
- BUG_ON(numerrs < 0); /* -EINVAL, or anything other than -EBADMSG */
-
- /* undo last step in BCH alg (modulo mirroring not needed) */
- for (i = 0; i < numerrs; i++)
- errpos[i] = (errpos[i] & ~7)|(7-(errpos[i] & 7));
-
- /* fix the errors */
- for (i = 0; i < numerrs; i++) {
-
- /* ignore if error within oob ecc bytes */
- if (errpos[i] > DOCG4_USERDATA_LEN * 8)
- continue;
-
- /* if error within oob area preceeding ecc bytes... */
- if (errpos[i] > DOCG4_PAGE_SIZE * 8)
- change_bit(errpos[i] - DOCG4_PAGE_SIZE * 8,
- (unsigned long *)nand->oob_poi);
-
- else /* error in page data */
- change_bit(errpos[i], (unsigned long *)buf);
- }
-
- dev_notice(doc->dev, "%d error(s) corrected at offset %08x\n",
- numerrs, page * DOCG4_PAGE_SIZE);
-
- return numerrs;
-}
-
-static uint8_t docg4_read_byte(struct mtd_info *mtd)
-{
- struct nand_chip *nand = mtd_to_nand(mtd);
- struct docg4_priv *doc = nand_get_controller_data(nand);
-
- dev_dbg(doc->dev, "%s\n", __func__);
-
- if (doc->last_command.command == NAND_CMD_STATUS) {
- int status;
-
- /*
- * Previous nand command was status request, so nand
- * infrastructure code expects to read the status here. If an
- * error occurred in a previous operation, report it.
- */
- doc->last_command.command = 0;
-
- if (doc->status) {
- status = doc->status;
- doc->status = 0;
- }
-
- /* why is NAND_STATUS_WP inverse logic?? */
- else
- status = NAND_STATUS_WP | NAND_STATUS_READY;
-
- return status;
- }
-
- dev_warn(doc->dev, "unexpected call to read_byte()\n");
-
- return 0;
-}
-
-static void write_addr(struct docg4_priv *doc, uint32_t docg4_addr)
-{
- /* write the four address bytes packed in docg4_addr to the device */
-
- void __iomem *docptr = doc->virtadr;
- writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
- docg4_addr >>= 8;
- writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
- docg4_addr >>= 8;
- writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
- docg4_addr >>= 8;
- writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
-}
-
-static int read_progstatus(struct docg4_priv *doc)
-{
- /*
- * This apparently checks the status of programming. Done after an
- * erasure, and after page data is written. On error, the status is
- * saved, to be later retrieved by the nand infrastructure code.
- */
- void __iomem *docptr = doc->virtadr;
-
- /* status is read from the I/O reg */
- uint16_t status1 = readw(docptr + DOC_IOSPACE_DATA);
- uint16_t status2 = readw(docptr + DOC_IOSPACE_DATA);
- uint16_t status3 = readw(docptr + DOCG4_MYSTERY_REG);
-
- dev_dbg(doc->dev, "docg4: %s: %02x %02x %02x\n",
- __func__, status1, status2, status3);
-
- if (status1 != DOCG4_PROGSTATUS_GOOD
- || status2 != DOCG4_PROGSTATUS_GOOD_2
- || status3 != DOCG4_PROGSTATUS_GOOD_2) {
- doc->status = NAND_STATUS_FAIL;
- dev_warn(doc->dev, "read_progstatus failed: "
- "%02x, %02x, %02x\n", status1, status2, status3);
- return -EIO;
- }
- return 0;
-}
-
-static int pageprog(struct mtd_info *mtd)
-{
- /*
- * Final step in writing a page. Writes the contents of its
- * internal buffer out to the flash array, or some such.
- */
-
- struct nand_chip *nand = mtd_to_nand(mtd);
- struct docg4_priv *doc = nand_get_controller_data(nand);
- void __iomem *docptr = doc->virtadr;
- int retval = 0;
-
- dev_dbg(doc->dev, "docg4: %s\n", __func__);
-
- writew(DOCG4_SEQ_PAGEPROG, docptr + DOC_FLASHSEQUENCE);
- writew(DOC_CMD_PROG_CYCLE2, docptr + DOC_FLASHCOMMAND);
- write_nop(docptr);
- write_nop(docptr);
-
- /* Just busy-wait; usleep_range() slows things down noticeably. */
- poll_status(doc);
-
- writew(DOCG4_SEQ_FLUSH, docptr + DOC_FLASHSEQUENCE);
- writew(DOCG4_CMD_FLUSH, docptr + DOC_FLASHCOMMAND);
- writew(DOC_ECCCONF0_READ_MODE | 4, docptr + DOC_ECCCONF0);
- write_nop(docptr);
- write_nop(docptr);
- write_nop(docptr);
- write_nop(docptr);
- write_nop(docptr);
-
- retval = read_progstatus(doc);
- writew(0, docptr + DOC_DATAEND);
- write_nop(docptr);
- poll_status(doc);
- write_nop(docptr);
-
- return retval;
-}
-
-static void sequence_reset(struct mtd_info *mtd)
-{
- /* common starting sequence for all operations */
-
- struct nand_chip *nand = mtd_to_nand(mtd);
- struct docg4_priv *doc = nand_get_controller_data(nand);
- void __iomem *docptr = doc->virtadr;
-
- writew(DOC_CTRL_UNKNOWN | DOC_CTRL_CE, docptr + DOC_FLASHCONTROL);
- writew(DOC_SEQ_RESET, docptr + DOC_FLASHSEQUENCE);
- writew(DOC_CMD_RESET, docptr + DOC_FLASHCOMMAND);
- write_nop(docptr);
- write_nop(docptr);
- poll_status(doc);
- write_nop(docptr);
-}
-
-static void read_page_prologue(struct mtd_info *mtd, uint32_t docg4_addr)
-{
- /* first step in reading a page */
-
- struct nand_chip *nand = mtd_to_nand(mtd);
- struct docg4_priv *doc = nand_get_controller_data(nand);
- void __iomem *docptr = doc->virtadr;
-
- dev_dbg(doc->dev,
- "docg4: %s: g4 page %08x\n", __func__, docg4_addr);
-
- sequence_reset(mtd);
-
- writew(DOCG4_SEQ_PAGE_READ, docptr + DOC_FLASHSEQUENCE);
- writew(DOCG4_CMD_PAGE_READ, docptr + DOC_FLASHCOMMAND);
- write_nop(docptr);
-
- write_addr(doc, docg4_addr);
-
- write_nop(docptr);
- writew(DOCG4_CMD_READ2, docptr + DOC_FLASHCOMMAND);
- write_nop(docptr);
- write_nop(docptr);
-
- poll_status(doc);
-}
-
-static void write_page_prologue(struct mtd_info *mtd, uint32_t docg4_addr)
-{
- /* first step in writing a page */
-
- struct nand_chip *nand = mtd_to_nand(mtd);
- struct docg4_priv *doc = nand_get_controller_data(nand);
- void __iomem *docptr = doc->virtadr;
-
- dev_dbg(doc->dev,
- "docg4: %s: g4 addr: %x\n", __func__, docg4_addr);
- sequence_reset(mtd);
-
- if (unlikely(reliable_mode)) {
- writew(DOCG4_SEQ_SETMODE, docptr + DOC_FLASHSEQUENCE);
- writew(DOCG4_CMD_FAST_MODE, docptr + DOC_FLASHCOMMAND);
- writew(DOC_CMD_RELIABLE_MODE, docptr + DOC_FLASHCOMMAND);
- write_nop(docptr);
- }
-
- writew(DOCG4_SEQ_PAGEWRITE, docptr + DOC_FLASHSEQUENCE);
- writew(DOCG4_CMD_PAGEWRITE, docptr + DOC_FLASHCOMMAND);
- write_nop(docptr);
- write_addr(doc, docg4_addr);
- write_nop(docptr);
- write_nop(docptr);
- poll_status(doc);
-}
-
-static uint32_t mtd_to_docg4_address(int page, int column)
-{
- /*
- * Convert mtd address to format used by the device, 32 bit packed.
- *
- * Some notes on G4 addressing... The M-Sys documentation on this device
- * claims that pages are 2K in length, and indeed, the format of the
- * address used by the device reflects that. But within each page are
- * four 512 byte "sub-pages", each with its own oob data that is
- * read/written immediately after the 512 bytes of page data. This oob
- * data contains the ecc bytes for the preceeding 512 bytes.
- *
- * Rather than tell the mtd nand infrastructure that page size is 2k,
- * with four sub-pages each, we engage in a little subterfuge and tell
- * the infrastructure code that pages are 512 bytes in size. This is
- * done because during the course of reverse-engineering the device, I
- * never observed an instance where an entire 2K "page" was read or
- * written as a unit. Each "sub-page" is always addressed individually,
- * its data read/written, and ecc handled before the next "sub-page" is
- * addressed.
- *
- * This requires us to convert addresses passed by the mtd nand
- * infrastructure code to those used by the device.
- *
- * The address that is written to the device consists of four bytes: the
- * first two are the 2k page number, and the second is the index into
- * the page. The index is in terms of 16-bit half-words and includes
- * the preceeding oob data, so e.g., the index into the second
- * "sub-page" is 0x108, and the full device address of the start of mtd
- * page 0x201 is 0x00800108.
- */
- int g4_page = page / 4; /* device's 2K page */
- int g4_index = (page % 4) * 0x108 + column/2; /* offset into page */
- return (g4_page << 16) | g4_index; /* pack */
-}
-
-static void docg4_command(struct mtd_info *mtd, unsigned command, int column,
- int page_addr)
-{
- /* handle standard nand commands */
-
- struct nand_chip *nand = mtd_to_nand(mtd);
- struct docg4_priv *doc = nand_get_controller_data(nand);
- uint32_t g4_addr = mtd_to_docg4_address(page_addr, column);
-
- dev_dbg(doc->dev, "%s %x, page_addr=%x, column=%x\n",
- __func__, command, page_addr, column);
-
- /*
- * Save the command and its arguments. This enables emulation of
- * standard flash devices, and also some optimizations.
- */
- doc->last_command.command = command;
- doc->last_command.column = column;
- doc->last_command.page = page_addr;
-
- switch (command) {
-
- case NAND_CMD_RESET:
- reset(mtd);
- break;
-
- case NAND_CMD_READ0:
- read_page_prologue(mtd, g4_addr);
- break;
-
- case NAND_CMD_STATUS:
- /* next call to read_byte() will expect a status */
- break;
-
- case NAND_CMD_SEQIN:
- if (unlikely(reliable_mode)) {
- uint16_t g4_page = g4_addr >> 16;
-
- /* writes to odd-numbered 2k pages are invalid */
- if (g4_page & 0x01)
- dev_warn(doc->dev,
- "invalid reliable mode address\n");
- }
-
- write_page_prologue(mtd, g4_addr);
-
- /* hack for deferred write of oob bytes */
- if (doc->oob_page == page_addr)
- memcpy(nand->oob_poi, doc->oob_buf, 16);
- break;
-
- case NAND_CMD_PAGEPROG:
- pageprog(mtd);
- break;
-
- /* we don't expect these, based on review of nand_base.c */
- case NAND_CMD_READOOB:
- case NAND_CMD_READID:
- case NAND_CMD_ERASE1:
- case NAND_CMD_ERASE2:
- dev_warn(doc->dev, "docg4_command: "
- "unexpected nand command 0x%x\n", command);
- break;
-
- }
-}
-
-static int read_page(struct mtd_info *mtd, struct nand_chip *nand,
- uint8_t *buf, int page, bool use_ecc)
-{
- struct docg4_priv *doc = nand_get_controller_data(nand);
- void __iomem *docptr = doc->virtadr;
- uint16_t status, edc_err, *buf16;
- int bits_corrected = 0;
-
- dev_dbg(doc->dev, "%s: page %08x\n", __func__, page);
-
- nand_read_page_op(nand, page, 0, NULL, 0);
-
- writew(DOC_ECCCONF0_READ_MODE |
- DOC_ECCCONF0_ECC_ENABLE |
- DOC_ECCCONF0_UNKNOWN |
- DOCG4_BCH_SIZE,
- docptr + DOC_ECCCONF0);
- write_nop(docptr);
- write_nop(docptr);
- write_nop(docptr);
- write_nop(docptr);
- write_nop(docptr);
-
- /* the 1st byte from the I/O reg is a status; the rest is page data */
- status = readw(docptr + DOC_IOSPACE_DATA);
- if (status & DOCG4_READ_ERROR) {
- dev_err(doc->dev,
- "docg4_read_page: bad status: 0x%02x\n", status);
- writew(0, docptr + DOC_DATAEND);
- return -EIO;
- }
-
- dev_dbg(doc->dev, "%s: status = 0x%x\n", __func__, status);
-
- docg4_read_buf(mtd, buf, DOCG4_PAGE_SIZE); /* read the page data */
-
- /* this device always reads oob after page data */
- /* first 14 oob bytes read from I/O reg */
- docg4_read_buf(mtd, nand->oob_poi, 14);
-
- /* last 2 read from another reg */
- buf16 = (uint16_t *)(nand->oob_poi + 14);
- *buf16 = readw(docptr + DOCG4_MYSTERY_REG);
-
- write_nop(docptr);
-
- if (likely(use_ecc == true)) {
-
- /* read the register that tells us if bitflip(s) detected */
- edc_err = readw(docptr + DOC_ECCCONF1);
- edc_err = readw(docptr + DOC_ECCCONF1);
- dev_dbg(doc->dev, "%s: edc_err = 0x%02x\n", __func__, edc_err);
-
- /* If bitflips are reported, attempt to correct with ecc */
- if (edc_err & DOC_ECCCONF1_BCH_SYNDROM_ERR) {
- bits_corrected = correct_data(mtd, buf, page);
- if (bits_corrected == -EBADMSG)
- mtd->ecc_stats.failed++;
- else
- mtd->ecc_stats.corrected += bits_corrected;
- }
- }
-
- writew(0, docptr + DOC_DATAEND);
- if (bits_corrected == -EBADMSG) /* uncorrectable errors */
- return 0;
- return bits_corrected;
-}
-
-
-static int docg4_read_page_raw(struct mtd_info *mtd, struct nand_chip *nand,
- uint8_t *buf, int oob_required, int page)
-{
- return read_page(mtd, nand, buf, page, false);
-}
-
-static int docg4_read_page(struct mtd_info *mtd, struct nand_chip *nand,
- uint8_t *buf, int oob_required, int page)
-{
- return read_page(mtd, nand, buf, page, true);
-}
-
-static int docg4_read_oob(struct mtd_info *mtd, struct nand_chip *nand,
- int page)
-{
- struct docg4_priv *doc = nand_get_controller_data(nand);
- void __iomem *docptr = doc->virtadr;
- uint16_t status;
-
- dev_dbg(doc->dev, "%s: page %x\n", __func__, page);
-
- nand_read_page_op(nand, page, nand->ecc.size, NULL, 0);
-
- writew(DOC_ECCCONF0_READ_MODE | DOCG4_OOB_SIZE, docptr + DOC_ECCCONF0);
- write_nop(docptr);
- write_nop(docptr);
- write_nop(docptr);
- write_nop(docptr);
- write_nop(docptr);
-
- /* the 1st byte from the I/O reg is a status; the rest is oob data */
- status = readw(docptr + DOC_IOSPACE_DATA);
- if (status & DOCG4_READ_ERROR) {
- dev_warn(doc->dev,
- "docg4_read_oob failed: status = 0x%02x\n", status);
- return -EIO;
- }
-
- dev_dbg(doc->dev, "%s: status = 0x%x\n", __func__, status);
-
- docg4_read_buf(mtd, nand->oob_poi, 16);
-
- write_nop(docptr);
- write_nop(docptr);
- write_nop(docptr);
- writew(0, docptr + DOC_DATAEND);
- write_nop(docptr);
-
- return 0;
-}
-
-static int docg4_erase_block(struct mtd_info *mtd, int page)
-{
- struct nand_chip *nand = mtd_to_nand(mtd);
- struct docg4_priv *doc = nand_get_controller_data(nand);
- void __iomem *docptr = doc->virtadr;
- uint16_t g4_page;
- int status;
-
- dev_dbg(doc->dev, "%s: page %04x\n", __func__, page);
-
- sequence_reset(mtd);
-
- writew(DOCG4_SEQ_BLOCKERASE, docptr + DOC_FLASHSEQUENCE);
- writew(DOC_CMD_PROG_BLOCK_ADDR, docptr + DOC_FLASHCOMMAND);
- write_nop(docptr);
-
- /* only 2 bytes of address are written to specify erase block */
- g4_page = (uint16_t)(page / 4); /* to g4's 2k page addressing */
- writeb(g4_page & 0xff, docptr + DOC_FLASHADDRESS);
- g4_page >>= 8;
- writeb(g4_page & 0xff, docptr + DOC_FLASHADDRESS);
- write_nop(docptr);
-
- /* start the erasure */
- writew(DOC_CMD_ERASECYCLE2, docptr + DOC_FLASHCOMMAND);
- write_nop(docptr);
- write_nop(docptr);
-
- usleep_range(500, 1000); /* erasure is long; take a snooze */
- poll_status(doc);
- writew(DOCG4_SEQ_FLUSH, docptr + DOC_FLASHSEQUENCE);
- writew(DOCG4_CMD_FLUSH, docptr + DOC_FLASHCOMMAND);
- writew(DOC_ECCCONF0_READ_MODE | 4, docptr + DOC_ECCCONF0);
- write_nop(docptr);
- write_nop(docptr);
- write_nop(docptr);
- write_nop(docptr);
- write_nop(docptr);
-
- read_progstatus(doc);
-
- writew(0, docptr + DOC_DATAEND);
- write_nop(docptr);
- poll_status(doc);
- write_nop(docptr);
-
- status = nand->waitfunc(mtd, nand);
- if (status < 0)
- return status;
-
- return status & NAND_STATUS_FAIL ? -EIO : 0;
-}
-
-static int write_page(struct mtd_info *mtd, struct nand_chip *nand,
- const uint8_t *buf, int page, bool use_ecc)
-{
- struct docg4_priv *doc = nand_get_controller_data(nand);
- void __iomem *docptr = doc->virtadr;
- uint8_t ecc_buf[8];
-
- dev_dbg(doc->dev, "%s...\n", __func__);
-
- nand_prog_page_begin_op(nand, page, 0, NULL, 0);
-
- writew(DOC_ECCCONF0_ECC_ENABLE |
- DOC_ECCCONF0_UNKNOWN |
- DOCG4_BCH_SIZE,
- docptr + DOC_ECCCONF0);
- write_nop(docptr);
-
- /* write the page data */
- docg4_write_buf16(mtd, buf, DOCG4_PAGE_SIZE);
-
- /* oob bytes 0 through 5 are written to I/O reg */
- docg4_write_buf16(mtd, nand->oob_poi, 6);
-
- /* oob byte 6 written to a separate reg */
- writew(nand->oob_poi[6], docptr + DOCG4_OOB_6_7);
-
- write_nop(docptr);
- write_nop(docptr);
-
- /* write hw-generated ecc bytes to oob */
- if (likely(use_ecc == true)) {
- /* oob byte 7 is hamming code */
- uint8_t hamming = readb(docptr + DOC_HAMMINGPARITY);
- hamming = readb(docptr + DOC_HAMMINGPARITY); /* 2nd read */
- writew(hamming, docptr + DOCG4_OOB_6_7);
- write_nop(docptr);
-
- /* read the 7 bch bytes from ecc regs */
- read_hw_ecc(docptr, ecc_buf);
- ecc_buf[7] = 0; /* clear the "page written" flag */
- }
-
- /* write user-supplied bytes to oob */
- else {
- writew(nand->oob_poi[7], docptr + DOCG4_OOB_6_7);
- write_nop(docptr);
- memcpy(ecc_buf, &nand->oob_poi[8], 8);
- }
-
- docg4_write_buf16(mtd, ecc_buf, 8);
- write_nop(docptr);
- write_nop(docptr);
- writew(0, docptr + DOC_DATAEND);
- write_nop(docptr);
-
- return nand_prog_page_end_op(nand);
-}
-
-static int docg4_write_page_raw(struct mtd_info *mtd, struct nand_chip *nand,
- const uint8_t *buf, int oob_required, int page)
-{
- return write_page(mtd, nand, buf, page, false);
-}
-
-static int docg4_write_page(struct mtd_info *mtd, struct nand_chip *nand,
- const uint8_t *buf, int oob_required, int page)
-{
- return write_page(mtd, nand, buf, page, true);
-}
-
-static int docg4_write_oob(struct mtd_info *mtd, struct nand_chip *nand,
- int page)
-{
- /*
- * Writing oob-only is not really supported, because MLC nand must write
- * oob bytes at the same time as page data. Nonetheless, we save the
- * oob buffer contents here, and then write it along with the page data
- * if the same page is subsequently written. This allows user space
- * utilities that write the oob data prior to the page data to work
- * (e.g., nandwrite). The disdvantage is that, if the intention was to
- * write oob only, the operation is quietly ignored. Also, oob can get
- * corrupted if two concurrent processes are running nandwrite.
- */
-
- /* note that bytes 7..14 are hw generated hamming/ecc and overwritten */
- struct docg4_priv *doc = nand_get_controller_data(nand);
- doc->oob_page = page;
- memcpy(doc->oob_buf, nand->oob_poi, 16);
- return 0;
-}
-
-static int __init read_factory_bbt(struct mtd_info *mtd)
-{
- /*
- * The device contains a read-only factory bad block table. Read it and
- * update the memory-based bbt accordingly.
- */
-
- struct nand_chip *nand = mtd_to_nand(mtd);
- struct docg4_priv *doc = nand_get_controller_data(nand);
- uint32_t g4_addr = mtd_to_docg4_address(DOCG4_FACTORY_BBT_PAGE, 0);
- uint8_t *buf;
- int i, block;
- __u32 eccfailed_stats = mtd->ecc_stats.failed;
-
- buf = kzalloc(DOCG4_PAGE_SIZE, GFP_KERNEL);
- if (buf == NULL)
- return -ENOMEM;
-
- read_page_prologue(mtd, g4_addr);
- docg4_read_page(mtd, nand, buf, 0, DOCG4_FACTORY_BBT_PAGE);
-
- /*
- * If no memory-based bbt was created, exit. This will happen if module
- * parameter ignore_badblocks is set. Then why even call this function?
- * For an unknown reason, block erase always fails if it's the first
- * operation after device power-up. The above read ensures it never is.
- * Ugly, I know.
- */
- if (nand->bbt == NULL) /* no memory-based bbt */
- goto exit;
-
- if (mtd->ecc_stats.failed > eccfailed_stats) {
- /*
- * Whoops, an ecc failure ocurred reading the factory bbt.
- * It is stored redundantly, so we get another chance.
- */
- eccfailed_stats = mtd->ecc_stats.failed;
- docg4_read_page(mtd, nand, buf, 0, DOCG4_REDUNDANT_BBT_PAGE);
- if (mtd->ecc_stats.failed > eccfailed_stats) {
- dev_warn(doc->dev,
- "The factory bbt could not be read!\n");
- goto exit;
- }
- }
-
- /*
- * Parse factory bbt and update memory-based bbt. Factory bbt format is
- * simple: one bit per block, block numbers increase left to right (msb
- * to lsb). Bit clear means bad block.
- */
- for (i = block = 0; block < DOCG4_NUMBLOCKS; block += 8, i++) {
- int bitnum;
- unsigned long bits = ~buf[i];
- for_each_set_bit(bitnum, &bits, 8) {
- int badblock = block + 7 - bitnum;
- nand->bbt[badblock / 4] |=
- 0x03 << ((badblock % 4) * 2);
- mtd->ecc_stats.badblocks++;
- dev_notice(doc->dev, "factory-marked bad block: %d\n",
- badblock);
- }
- }
- exit:
- kfree(buf);
- return 0;
-}
-
-static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs)
-{
- /*
- * Mark a block as bad. Bad blocks are marked in the oob area of the
- * first page of the block. The default scan_bbt() in the nand
- * infrastructure code works fine for building the memory-based bbt
- * during initialization, as does the nand infrastructure function that
- * checks if a block is bad by reading the bbt. This function replaces
- * the nand default because writes to oob-only are not supported.
- */
-
- int ret, i;
- uint8_t *buf;
- struct nand_chip *nand = mtd_to_nand(mtd);
- struct docg4_priv *doc = nand_get_controller_data(nand);
- struct nand_bbt_descr *bbtd = nand->badblock_pattern;
- int page = (int)(ofs >> nand->page_shift);
- uint32_t g4_addr = mtd_to_docg4_address(page, 0);
-
- dev_dbg(doc->dev, "%s: %08llx\n", __func__, ofs);
-
- if (unlikely(ofs & (DOCG4_BLOCK_SIZE - 1)))
- dev_warn(doc->dev, "%s: ofs %llx not start of block!\n",
- __func__, ofs);
-
- /* allocate blank buffer for page data */
- buf = kzalloc(DOCG4_PAGE_SIZE, GFP_KERNEL);
- if (buf == NULL)
- return -ENOMEM;
-
- /* write bit-wise negation of pattern to oob buffer */
- memset(nand->oob_poi, 0xff, mtd->oobsize);
- for (i = 0; i < bbtd->len; i++)
- nand->oob_poi[bbtd->offs + i] = ~bbtd->pattern[i];
-
- /* write first page of block */
- write_page_prologue(mtd, g4_addr);
- docg4_write_page(mtd, nand, buf, 1, page);
- ret = pageprog(mtd);
-
- kfree(buf);
-
- return ret;
-}
-
-static int docg4_block_neverbad(struct mtd_info *mtd, loff_t ofs)
-{
- /* only called when module_param ignore_badblocks is set */
- return 0;
-}
-
-static int docg4_suspend(struct platform_device *pdev, pm_message_t state)
-{
- /*
- * Put the device into "deep power-down" mode. Note that CE# must be
- * deasserted for this to take effect. The xscale, e.g., can be
- * configured to float this signal when the processor enters power-down,
- * and a suitable pull-up ensures its deassertion.
- */
-
- int i;
- uint8_t pwr_down;
- struct docg4_priv *doc = platform_get_drvdata(pdev);
- void __iomem *docptr = doc->virtadr;
-
- dev_dbg(doc->dev, "%s...\n", __func__);
-
- /* poll the register that tells us we're ready to go to sleep */
- for (i = 0; i < 10; i++) {
- pwr_down = readb(docptr + DOC_POWERMODE);
- if (pwr_down & DOC_POWERDOWN_READY)
- break;
- usleep_range(1000, 4000);
- }
-
- if (pwr_down & DOC_POWERDOWN_READY) {
- dev_err(doc->dev, "suspend failed; "
- "timeout polling DOC_POWERDOWN_READY\n");
- return -EIO;
- }
-
- writew(DOC_ASICMODE_POWERDOWN | DOC_ASICMODE_MDWREN,
- docptr + DOC_ASICMODE);
- writew(~(DOC_ASICMODE_POWERDOWN | DOC_ASICMODE_MDWREN),
- docptr + DOC_ASICMODECONFIRM);
-
- write_nop(docptr);
-
- return 0;
-}
-
-static int docg4_resume(struct platform_device *pdev)
-{
-
- /*
- * Exit power-down. Twelve consecutive reads of the address below
- * accomplishes this, assuming CE# has been asserted.
- */
-
- struct docg4_priv *doc = platform_get_drvdata(pdev);
- void __iomem *docptr = doc->virtadr;
- int i;
-
- dev_dbg(doc->dev, "%s...\n", __func__);
-
- for (i = 0; i < 12; i++)
- readb(docptr + 0x1fff);
-
- return 0;
-}
-
-static void init_mtd_structs(struct mtd_info *mtd)
-{
- /* initialize mtd and nand data structures */
-
- /*
- * Note that some of the following initializations are not usually
- * required within a nand driver because they are performed by the nand
- * infrastructure code as part of nand_scan(). In this case they need
- * to be initialized here because we skip call to nand_scan_ident() (the
- * first half of nand_scan()). The call to nand_scan_ident() could be
- * skipped because for this device the chip id is not read in the manner
- * of a standard nand device.
- */
-
- struct nand_chip *nand = mtd_to_nand(mtd);
- struct docg4_priv *doc = nand_get_controller_data(nand);
-
- mtd->size = DOCG4_CHIP_SIZE;
- mtd->name = "Msys_Diskonchip_G4";
- mtd->writesize = DOCG4_PAGE_SIZE;
- mtd->erasesize = DOCG4_BLOCK_SIZE;
- mtd->oobsize = DOCG4_OOB_SIZE;
- mtd_set_ooblayout(mtd, &docg4_ooblayout_ops);
- nand->chipsize = DOCG4_CHIP_SIZE;
- nand->chip_shift = DOCG4_CHIP_SHIFT;
- nand->bbt_erase_shift = nand->phys_erase_shift = DOCG4_ERASE_SHIFT;
- nand->chip_delay = 20;
- nand->page_shift = DOCG4_PAGE_SHIFT;
- nand->pagemask = 0x3ffff;
- nand->badblockpos = NAND_LARGE_BADBLOCK_POS;
- nand->badblockbits = 8;
- nand->ecc.mode = NAND_ECC_HW_SYNDROME;
- nand->ecc.size = DOCG4_PAGE_SIZE;
- nand->ecc.prepad = 8;
- nand->ecc.bytes = 8;
- nand->ecc.strength = DOCG4_T;
- nand->options = NAND_BUSWIDTH_16 | NAND_NO_SUBPAGE_WRITE;
- nand->IO_ADDR_R = nand->IO_ADDR_W = doc->virtadr + DOC_IOSPACE_DATA;
- nand->controller = &nand->dummy_controller;
- nand_controller_init(nand->controller);
-
- /* methods */
- nand->cmdfunc = docg4_command;
- nand->waitfunc = docg4_wait;
- nand->select_chip = docg4_select_chip;
- nand->read_byte = docg4_read_byte;
- nand->block_markbad = docg4_block_markbad;
- nand->read_buf = docg4_read_buf;
- nand->write_buf = docg4_write_buf16;
- nand->erase = docg4_erase_block;
- nand->set_features = nand_get_set_features_notsupp;
- nand->get_features = nand_get_set_features_notsupp;
- nand->ecc.read_page = docg4_read_page;
- nand->ecc.write_page = docg4_write_page;
- nand->ecc.read_page_raw = docg4_read_page_raw;
- nand->ecc.write_page_raw = docg4_write_page_raw;
- nand->ecc.read_oob = docg4_read_oob;
- nand->ecc.write_oob = docg4_write_oob;
-
- /*
- * The way the nand infrastructure code is written, a memory-based bbt
- * is not created if NAND_SKIP_BBTSCAN is set. With no memory bbt,
- * nand->block_bad() is used. So when ignoring bad blocks, we skip the
- * scan and define a dummy block_bad() which always returns 0.
- */
- if (ignore_badblocks) {
- nand->options |= NAND_SKIP_BBTSCAN;
- nand->block_bad = docg4_block_neverbad;
- }
-
-}
-
-static int read_id_reg(struct mtd_info *mtd)
-{
- struct nand_chip *nand = mtd_to_nand(mtd);
- struct docg4_priv *doc = nand_get_controller_data(nand);
- void __iomem *docptr = doc->virtadr;
- uint16_t id1, id2;
-
- /* check for presence of g4 chip by reading id registers */
- id1 = readw(docptr + DOC_CHIPID);
- id1 = readw(docptr + DOCG4_MYSTERY_REG);
- id2 = readw(docptr + DOC_CHIPID_INV);
- id2 = readw(docptr + DOCG4_MYSTERY_REG);
-
- if (id1 == DOCG4_IDREG1_VALUE && id2 == DOCG4_IDREG2_VALUE) {
- dev_info(doc->dev,
- "NAND device: 128MiB Diskonchip G4 detected\n");
- return 0;
- }
-
- return -ENODEV;
-}
-
-static char const *part_probes[] = { "cmdlinepart", "saftlpart", NULL };
-
-static int docg4_attach_chip(struct nand_chip *chip)
-{
- struct mtd_info *mtd = nand_to_mtd(chip);
- struct docg4_priv *doc = (struct docg4_priv *)(chip + 1);
- int ret;
-
- init_mtd_structs(mtd);
-
- /* Initialize kernel BCH algorithm */
- doc->bch = init_bch(DOCG4_M, DOCG4_T, DOCG4_PRIMITIVE_POLY);
- if (!doc->bch)
- return -EINVAL;
-
- reset(mtd);
-
- ret = read_id_reg(mtd);
- if (ret)
- free_bch(doc->bch);
-
- return ret;
-}
-
-static void docg4_detach_chip(struct nand_chip *chip)
-{
- struct docg4_priv *doc = (struct docg4_priv *)(chip + 1);
-
- free_bch(doc->bch);
-}
-
-static const struct nand_controller_ops docg4_controller_ops = {
- .attach_chip = docg4_attach_chip,
- .detach_chip = docg4_detach_chip,
-};
-
-static int __init probe_docg4(struct platform_device *pdev)
-{
- struct mtd_info *mtd;
- struct nand_chip *nand;
- void __iomem *virtadr;
- struct docg4_priv *doc;
- int len, retval;
- struct resource *r;
- struct device *dev = &pdev->dev;
-
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (r == NULL) {
- dev_err(dev, "no io memory resource defined!\n");
- return -ENODEV;
- }
-
- virtadr = ioremap(r->start, resource_size(r));
- if (!virtadr) {
- dev_err(dev, "Diskonchip ioremap failed: %pR\n", r);
- return -EIO;
- }
-
- len = sizeof(struct nand_chip) + sizeof(struct docg4_priv);
- nand = kzalloc(len, GFP_KERNEL);
- if (nand == NULL) {
- retval = -ENOMEM;
- goto unmap;
- }
-
- mtd = nand_to_mtd(nand);
- doc = (struct docg4_priv *) (nand + 1);
- nand_set_controller_data(nand, doc);
- mtd->dev.parent = &pdev->dev;
- doc->virtadr = virtadr;
- doc->dev = dev;
- platform_set_drvdata(pdev, doc);
-
- /*
- * Running nand_scan() with maxchips == 0 will skip nand_scan_ident(),
- * which is a specific operation with this driver and done in the
- * ->attach_chip callback.
- */
- nand->dummy_controller.ops = &docg4_controller_ops;
- retval = nand_scan(mtd, 0);
- if (retval)
- goto free_nand;
-
- retval = read_factory_bbt(mtd);
- if (retval)
- goto cleanup_nand;
-
- retval = mtd_device_parse_register(mtd, part_probes, NULL, NULL, 0);
- if (retval)
- goto cleanup_nand;
-
- doc->mtd = mtd;
-
- return 0;
-
-cleanup_nand:
- nand_cleanup(nand);
-free_nand:
- kfree(nand);
-unmap:
- iounmap(virtadr);
-
- return retval;
-}
-
-static int __exit cleanup_docg4(struct platform_device *pdev)
-{
- struct docg4_priv *doc = platform_get_drvdata(pdev);
- nand_release(doc->mtd);
- kfree(mtd_to_nand(doc->mtd));
- iounmap(doc->virtadr);
- return 0;
-}
-
-static struct platform_driver docg4_driver = {
- .driver = {
- .name = "docg4",
- },
- .suspend = docg4_suspend,
- .resume = docg4_resume,
- .remove = __exit_p(cleanup_docg4),
-};
-
-module_platform_driver_probe(docg4_driver, probe_docg4);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mike Dunn");
-MODULE_DESCRIPTION("M-Systems DiskOnChip G4 device driver");
diff --git a/drivers/mtd/nand/raw/fsl_elbc_nand.c b/drivers/mtd/nand/raw/fsl_elbc_nand.c
index 55f449b711fd..d6ed697fcfe6 100644
--- a/drivers/mtd/nand/raw/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/raw/fsl_elbc_nand.c
@@ -317,10 +317,10 @@ static void fsl_elbc_do_read(struct nand_chip *chip, int oob)
}
/* cmdfunc send commands to the FCM */
-static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
+static void fsl_elbc_cmdfunc(struct nand_chip *chip, unsigned int command,
int column, int page_addr)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
struct fsl_lbc_ctrl *ctrl = priv->ctrl;
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
@@ -533,7 +533,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
}
}
-static void fsl_elbc_select_chip(struct mtd_info *mtd, int chip)
+static void fsl_elbc_select_chip(struct nand_chip *chip, int cs)
{
/* The hardware does not seem to support multiple
* chips per bank.
@@ -543,9 +543,9 @@ static void fsl_elbc_select_chip(struct mtd_info *mtd, int chip)
/*
* Write buf to the FCM Controller Data Buffer
*/
-static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+static void fsl_elbc_write_buf(struct nand_chip *chip, const u8 *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
unsigned int bufsize = mtd->writesize + mtd->oobsize;
@@ -581,9 +581,8 @@ static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
* read a byte from either the FCM hardware buffer if it has any data left
* otherwise issue a command to read a single byte.
*/
-static u8 fsl_elbc_read_byte(struct mtd_info *mtd)
+static u8 fsl_elbc_read_byte(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
@@ -598,9 +597,8 @@ static u8 fsl_elbc_read_byte(struct mtd_info *mtd)
/*
* Read from the FCM Controller Data Buffer
*/
-static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+static void fsl_elbc_read_buf(struct nand_chip *chip, u8 *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
int avail;
@@ -623,7 +621,7 @@ static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
/* This function is called after Program and Erase Operations to
* check for success or failure.
*/
-static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip)
+static int fsl_elbc_wait(struct nand_chip *chip)
{
struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
@@ -660,8 +658,8 @@ static int fsl_elbc_attach_chip(struct nand_chip *chip)
chip->chipsize);
dev_dbg(priv->dev, "fsl_elbc_init: nand->pagemask = %8x\n",
chip->pagemask);
- dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_delay = %d\n",
- chip->chip_delay);
+ dev_dbg(priv->dev, "fsl_elbc_init: nand->legacy.chip_delay = %d\n",
+ chip->legacy.chip_delay);
dev_dbg(priv->dev, "fsl_elbc_init: nand->badblockpos = %d\n",
chip->badblockpos);
dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_shift = %d\n",
@@ -710,18 +708,19 @@ static const struct nand_controller_ops fsl_elbc_controller_ops = {
.attach_chip = fsl_elbc_attach_chip,
};
-static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+static int fsl_elbc_read_page(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
struct fsl_lbc_ctrl *ctrl = priv->ctrl;
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
nand_read_page_op(chip, page, 0, buf, mtd->writesize);
if (oob_required)
- fsl_elbc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ fsl_elbc_read_buf(chip, chip->oob_poi, mtd->oobsize);
- if (fsl_elbc_wait(mtd, chip) & NAND_STATUS_FAIL)
+ if (fsl_elbc_wait(chip) & NAND_STATUS_FAIL)
mtd->ecc_stats.failed++;
return elbc_fcm_ctrl->max_bitflips;
@@ -730,11 +729,13 @@ static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
/* ECC will be calculated automatically, and errors will be detected in
* waitfunc.
*/
-static int fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required, int page)
+static int fsl_elbc_write_page(struct nand_chip *chip, const uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
- fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+ fsl_elbc_write_buf(chip, chip->oob_poi, mtd->oobsize);
return nand_prog_page_end_op(chip);
}
@@ -742,13 +743,15 @@ static int fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
/* ECC will be calculated automatically, and errors will be detected in
* waitfunc.
*/
-static int fsl_elbc_write_subpage(struct mtd_info *mtd, struct nand_chip *chip,
- uint32_t offset, uint32_t data_len,
- const uint8_t *buf, int oob_required, int page)
+static int fsl_elbc_write_subpage(struct nand_chip *chip, uint32_t offset,
+ uint32_t data_len, const uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
- fsl_elbc_write_buf(mtd, buf, mtd->writesize);
- fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+ fsl_elbc_write_buf(chip, buf, mtd->writesize);
+ fsl_elbc_write_buf(chip, chip->oob_poi, mtd->oobsize);
return nand_prog_page_end_op(chip);
}
@@ -773,14 +776,14 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
/* fill in nand_chip structure */
/* set up function call table */
- chip->read_byte = fsl_elbc_read_byte;
- chip->write_buf = fsl_elbc_write_buf;
- chip->read_buf = fsl_elbc_read_buf;
+ chip->legacy.read_byte = fsl_elbc_read_byte;
+ chip->legacy.write_buf = fsl_elbc_write_buf;
+ chip->legacy.read_buf = fsl_elbc_read_buf;
chip->select_chip = fsl_elbc_select_chip;
- chip->cmdfunc = fsl_elbc_cmdfunc;
- chip->waitfunc = fsl_elbc_wait;
- chip->set_features = nand_get_set_features_notsupp;
- chip->get_features = nand_get_set_features_notsupp;
+ chip->legacy.cmdfunc = fsl_elbc_cmdfunc;
+ chip->legacy.waitfunc = fsl_elbc_wait;
+ chip->legacy.set_features = nand_get_set_features_notsupp;
+ chip->legacy.get_features = nand_get_set_features_notsupp;
chip->bbt_td = &bbt_main_descr;
chip->bbt_md = &bbt_mirror_descr;
@@ -915,7 +918,7 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev)
goto err;
priv->chip.controller->ops = &fsl_elbc_controller_ops;
- ret = nand_scan(mtd, 1);
+ ret = nand_scan(&priv->chip, 1);
if (ret)
goto err;
@@ -942,9 +945,8 @@ static int fsl_elbc_nand_remove(struct platform_device *pdev)
{
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand;
struct fsl_elbc_mtd *priv = dev_get_drvdata(&pdev->dev);
- struct mtd_info *mtd = nand_to_mtd(&priv->chip);
- nand_release(mtd);
+ nand_release(&priv->chip);
fsl_elbc_chip_remove(priv);
mutex_lock(&fsl_elbc_nand_mutex);
diff --git a/drivers/mtd/nand/raw/fsl_ifc_nand.c b/drivers/mtd/nand/raw/fsl_ifc_nand.c
index 24f59d0066af..6f4afc44381a 100644
--- a/drivers/mtd/nand/raw/fsl_ifc_nand.c
+++ b/drivers/mtd/nand/raw/fsl_ifc_nand.c
@@ -30,6 +30,7 @@
#include <linux/mtd/partitions.h>
#include <linux/mtd/nand_ecc.h>
#include <linux/fsl_ifc.h>
+#include <linux/iopoll.h>
#define ERR_BYTE 0xFF /* Value returned for read
bytes when read failed */
@@ -300,9 +301,9 @@ static void fsl_ifc_do_read(struct nand_chip *chip,
}
/* cmdfunc send commands to the IFC NAND Machine */
-static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
- int column, int page_addr) {
- struct nand_chip *chip = mtd_to_nand(mtd);
+static void fsl_ifc_cmdfunc(struct nand_chip *chip, unsigned int command,
+ int column, int page_addr) {
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;
@@ -508,7 +509,7 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
}
}
-static void fsl_ifc_select_chip(struct mtd_info *mtd, int chip)
+static void fsl_ifc_select_chip(struct nand_chip *chip, int cs)
{
/* The hardware does not seem to support multiple
* chips per bank.
@@ -518,9 +519,9 @@ static void fsl_ifc_select_chip(struct mtd_info *mtd, int chip)
/*
* Write buf to the IFC NAND Controller Data Buffer
*/
-static void fsl_ifc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+static void fsl_ifc_write_buf(struct nand_chip *chip, const u8 *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
unsigned int bufsize = mtd->writesize + mtd->oobsize;
@@ -544,9 +545,8 @@ static void fsl_ifc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
* Read a byte from either the IFC hardware buffer
* read function for 8-bit buswidth
*/
-static uint8_t fsl_ifc_read_byte(struct mtd_info *mtd)
+static uint8_t fsl_ifc_read_byte(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
unsigned int offset;
@@ -567,9 +567,8 @@ static uint8_t fsl_ifc_read_byte(struct mtd_info *mtd)
* Read two bytes from the IFC hardware buffer
* read function for 16-bit buswith
*/
-static uint8_t fsl_ifc_read_byte16(struct mtd_info *mtd)
+static uint8_t fsl_ifc_read_byte16(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
uint16_t data;
@@ -590,9 +589,8 @@ static uint8_t fsl_ifc_read_byte16(struct mtd_info *mtd)
/*
* Read from the IFC Controller Data Buffer
*/
-static void fsl_ifc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+static void fsl_ifc_read_buf(struct nand_chip *chip, u8 *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
int avail;
@@ -616,8 +614,9 @@ static void fsl_ifc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
* This function is called after Program and Erase Operations to
* check for success or failure.
*/
-static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip)
+static int fsl_ifc_wait(struct nand_chip *chip)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;
@@ -678,20 +677,21 @@ static int check_erased_page(struct nand_chip *chip, u8 *buf)
return bitflips;
}
-static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+static int fsl_ifc_read_page(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
struct fsl_ifc_nand_ctrl *nctrl = ifc_nand_ctrl;
nand_read_page_op(chip, page, 0, buf, mtd->writesize);
if (oob_required)
- fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ fsl_ifc_read_buf(chip, chip->oob_poi, mtd->oobsize);
if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_ECCER) {
if (!oob_required)
- fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ fsl_ifc_read_buf(chip, chip->oob_poi, mtd->oobsize);
return check_erased_page(chip, buf);
}
@@ -705,11 +705,13 @@ static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
/* ECC will be calculated automatically, and errors will be detected in
* waitfunc.
*/
-static int fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required, int page)
+static int fsl_ifc_write_page(struct nand_chip *chip, const uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
- fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+ fsl_ifc_write_buf(chip, chip->oob_poi, mtd->oobsize);
return nand_prog_page_end_op(chip);
}
@@ -725,8 +727,8 @@ static int fsl_ifc_attach_chip(struct nand_chip *chip)
chip->chipsize);
dev_dbg(priv->dev, "%s: nand->pagemask = %8x\n", __func__,
chip->pagemask);
- dev_dbg(priv->dev, "%s: nand->chip_delay = %d\n", __func__,
- chip->chip_delay);
+ dev_dbg(priv->dev, "%s: nand->legacy.chip_delay = %d\n", __func__,
+ chip->legacy.chip_delay);
dev_dbg(priv->dev, "%s: nand->badblockpos = %d\n", __func__,
chip->badblockpos);
dev_dbg(priv->dev, "%s: nand->chip_shift = %d\n", __func__,
@@ -761,7 +763,7 @@ static const struct nand_controller_ops fsl_ifc_controller_ops = {
.attach_chip = fsl_ifc_attach_chip,
};
-static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv)
+static int fsl_ifc_sram_init(struct fsl_ifc_mtd *priv)
{
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
struct fsl_ifc_runtime __iomem *ifc_runtime = ctrl->rregs;
@@ -769,6 +771,27 @@ static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv)
uint32_t csor = 0, csor_8k = 0, csor_ext = 0;
uint32_t cs = priv->bank;
+ if (ctrl->version < FSL_IFC_VERSION_1_1_0)
+ return 0;
+
+ if (ctrl->version > FSL_IFC_VERSION_1_1_0) {
+ u32 ncfgr, status;
+ int ret;
+
+ /* Trigger auto initialization */
+ ncfgr = ifc_in32(&ifc_runtime->ifc_nand.ncfgr);
+ ifc_out32(ncfgr | IFC_NAND_NCFGR_SRAM_INIT_EN, &ifc_runtime->ifc_nand.ncfgr);
+
+ /* Wait until done */
+ ret = readx_poll_timeout(ifc_in32, &ifc_runtime->ifc_nand.ncfgr,
+ status, !(status & IFC_NAND_NCFGR_SRAM_INIT_EN),
+ 10, IFC_TIMEOUT_MSECS * 1000);
+ if (ret)
+ dev_err(priv->dev, "Failed to initialize SRAM!\n");
+
+ return ret;
+ }
+
/* Save CSOR and CSOR_ext */
csor = ifc_in32(&ifc_global->csor_cs[cs].csor);
csor_ext = ifc_in32(&ifc_global->csor_cs[cs].csor_ext);
@@ -805,12 +828,16 @@ static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv)
wait_event_timeout(ctrl->nand_wait, ctrl->nand_stat,
msecs_to_jiffies(IFC_TIMEOUT_MSECS));
- if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC)
+ if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC) {
pr_err("fsl-ifc: Failed to Initialise SRAM\n");
+ return -ETIMEDOUT;
+ }
/* Restore CSOR and CSOR_ext */
ifc_out32(csor, &ifc_global->csor_cs[cs].csor);
ifc_out32(csor_ext, &ifc_global->csor_cs[cs].csor_ext);
+
+ return 0;
}
static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
@@ -821,6 +848,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
struct nand_chip *chip = &priv->chip;
struct mtd_info *mtd = nand_to_mtd(&priv->chip);
u32 csor;
+ int ret;
/* Fill in fsl_ifc_mtd structure */
mtd->dev.parent = priv->dev;
@@ -830,17 +858,17 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
/* set up function call table */
if ((ifc_in32(&ifc_global->cspr_cs[priv->bank].cspr))
& CSPR_PORT_SIZE_16)
- chip->read_byte = fsl_ifc_read_byte16;
+ chip->legacy.read_byte = fsl_ifc_read_byte16;
else
- chip->read_byte = fsl_ifc_read_byte;
+ chip->legacy.read_byte = fsl_ifc_read_byte;
- chip->write_buf = fsl_ifc_write_buf;
- chip->read_buf = fsl_ifc_read_buf;
+ chip->legacy.write_buf = fsl_ifc_write_buf;
+ chip->legacy.read_buf = fsl_ifc_read_buf;
chip->select_chip = fsl_ifc_select_chip;
- chip->cmdfunc = fsl_ifc_cmdfunc;
- chip->waitfunc = fsl_ifc_wait;
- chip->set_features = nand_get_set_features_notsupp;
- chip->get_features = nand_get_set_features_notsupp;
+ chip->legacy.cmdfunc = fsl_ifc_cmdfunc;
+ chip->legacy.waitfunc = fsl_ifc_wait;
+ chip->legacy.set_features = nand_get_set_features_notsupp;
+ chip->legacy.get_features = nand_get_set_features_notsupp;
chip->bbt_td = &bbt_main_descr;
chip->bbt_md = &bbt_mirror_descr;
@@ -853,10 +881,10 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
if (ifc_in32(&ifc_global->cspr_cs[priv->bank].cspr)
& CSPR_PORT_SIZE_16) {
- chip->read_byte = fsl_ifc_read_byte16;
+ chip->legacy.read_byte = fsl_ifc_read_byte16;
chip->options |= NAND_BUSWIDTH_16;
} else {
- chip->read_byte = fsl_ifc_read_byte;
+ chip->legacy.read_byte = fsl_ifc_read_byte;
}
chip->controller = &ifc_nand_ctrl->controller;
@@ -914,8 +942,9 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
chip->ecc.algo = NAND_ECC_HAMMING;
}
- if (ctrl->version >= FSL_IFC_VERSION_1_1_0)
- fsl_ifc_sram_init(priv);
+ ret = fsl_ifc_sram_init(priv);
+ if (ret)
+ return ret;
/*
* As IFC version 2.0.0 has 16KB of internal SRAM as compared to older
@@ -1051,7 +1080,7 @@ static int fsl_ifc_nand_probe(struct platform_device *dev)
goto err;
priv->chip.controller->ops = &fsl_ifc_controller_ops;
- ret = nand_scan(mtd, 1);
+ ret = nand_scan(&priv->chip, 1);
if (ret)
goto err;
@@ -1077,9 +1106,8 @@ err:
static int fsl_ifc_nand_remove(struct platform_device *dev)
{
struct fsl_ifc_mtd *priv = dev_get_drvdata(&dev->dev);
- struct mtd_info *mtd = nand_to_mtd(&priv->chip);
- nand_release(mtd);
+ nand_release(&priv->chip);
fsl_ifc_chip_remove(priv);
mutex_lock(&fsl_ifc_nand_mutex);
diff --git a/drivers/mtd/nand/raw/fsl_upm.c b/drivers/mtd/nand/raw/fsl_upm.c
index a88e2cf66e0f..673c5a0c9345 100644
--- a/drivers/mtd/nand/raw/fsl_upm.c
+++ b/drivers/mtd/nand/raw/fsl_upm.c
@@ -52,9 +52,9 @@ static inline struct fsl_upm_nand *to_fsl_upm_nand(struct mtd_info *mtdinfo)
chip);
}
-static int fun_chip_ready(struct mtd_info *mtd)
+static int fun_chip_ready(struct nand_chip *chip)
{
- struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
+ struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip));
if (gpio_get_value(fun->rnb_gpio[fun->mchip_number]))
return 1;
@@ -69,7 +69,7 @@ static void fun_wait_rnb(struct fsl_upm_nand *fun)
struct mtd_info *mtd = nand_to_mtd(&fun->chip);
int cnt = 1000000;
- while (--cnt && !fun_chip_ready(mtd))
+ while (--cnt && !fun_chip_ready(&fun->chip))
cpu_relax();
if (!cnt)
dev_err(fun->dev, "tired waiting for RNB\n");
@@ -78,10 +78,9 @@ static void fun_wait_rnb(struct fsl_upm_nand *fun)
}
}
-static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+static void fun_cmd_ctrl(struct nand_chip *chip, int cmd, unsigned int ctrl)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
- struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
+ struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip));
u32 mar;
if (!(ctrl & fun->last_ctrl)) {
@@ -102,51 +101,50 @@ static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
mar = (cmd << (32 - fun->upm.width)) |
fun->mchip_offsets[fun->mchip_number];
- fsl_upm_run_pattern(&fun->upm, chip->IO_ADDR_R, mar);
+ fsl_upm_run_pattern(&fun->upm, chip->legacy.IO_ADDR_R, mar);
if (fun->wait_flags & FSL_UPM_WAIT_RUN_PATTERN)
fun_wait_rnb(fun);
}
-static void fun_select_chip(struct mtd_info *mtd, int mchip_nr)
+static void fun_select_chip(struct nand_chip *chip, int mchip_nr)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
- struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
+ struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip));
if (mchip_nr == -1) {
- chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
+ chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
} else if (mchip_nr >= 0 && mchip_nr < NAND_MAX_CHIPS) {
fun->mchip_number = mchip_nr;
- chip->IO_ADDR_R = fun->io_base + fun->mchip_offsets[mchip_nr];
- chip->IO_ADDR_W = chip->IO_ADDR_R;
+ chip->legacy.IO_ADDR_R = fun->io_base + fun->mchip_offsets[mchip_nr];
+ chip->legacy.IO_ADDR_W = chip->legacy.IO_ADDR_R;
} else {
BUG();
}
}
-static uint8_t fun_read_byte(struct mtd_info *mtd)
+static uint8_t fun_read_byte(struct nand_chip *chip)
{
- struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
+ struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip));
- return in_8(fun->chip.IO_ADDR_R);
+ return in_8(fun->chip.legacy.IO_ADDR_R);
}
-static void fun_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void fun_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
{
- struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
+ struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip));
int i;
for (i = 0; i < len; i++)
- buf[i] = in_8(fun->chip.IO_ADDR_R);
+ buf[i] = in_8(fun->chip.legacy.IO_ADDR_R);
}
-static void fun_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+static void fun_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
{
- struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
+ struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip));
int i;
for (i = 0; i < len; i++) {
- out_8(fun->chip.IO_ADDR_W, buf[i]);
+ out_8(fun->chip.legacy.IO_ADDR_W, buf[i]);
if (fun->wait_flags & FSL_UPM_WAIT_WRITE_BYTE)
fun_wait_rnb(fun);
}
@@ -162,20 +160,20 @@ static int fun_chip_init(struct fsl_upm_nand *fun,
int ret;
struct device_node *flash_np;
- fun->chip.IO_ADDR_R = fun->io_base;
- fun->chip.IO_ADDR_W = fun->io_base;
- fun->chip.cmd_ctrl = fun_cmd_ctrl;
- fun->chip.chip_delay = fun->chip_delay;
- fun->chip.read_byte = fun_read_byte;
- fun->chip.read_buf = fun_read_buf;
- fun->chip.write_buf = fun_write_buf;
+ fun->chip.legacy.IO_ADDR_R = fun->io_base;
+ fun->chip.legacy.IO_ADDR_W = fun->io_base;
+ fun->chip.legacy.cmd_ctrl = fun_cmd_ctrl;
+ fun->chip.legacy.chip_delay = fun->chip_delay;
+ fun->chip.legacy.read_byte = fun_read_byte;
+ fun->chip.legacy.read_buf = fun_read_buf;
+ fun->chip.legacy.write_buf = fun_write_buf;
fun->chip.ecc.mode = NAND_ECC_SOFT;
fun->chip.ecc.algo = NAND_ECC_HAMMING;
if (fun->mchip_count > 1)
fun->chip.select_chip = fun_select_chip;
if (fun->rnb_gpio[0] >= 0)
- fun->chip.dev_ready = fun_chip_ready;
+ fun->chip.legacy.dev_ready = fun_chip_ready;
mtd->dev.parent = fun->dev;
@@ -184,14 +182,14 @@ static int fun_chip_init(struct fsl_upm_nand *fun,
return -ENODEV;
nand_set_flash_node(&fun->chip, flash_np);
- mtd->name = kasprintf(GFP_KERNEL, "0x%llx.%s", (u64)io_res->start,
- flash_np->name);
+ mtd->name = kasprintf(GFP_KERNEL, "0x%llx.%pOFn", (u64)io_res->start,
+ flash_np);
if (!mtd->name) {
ret = -ENOMEM;
goto err;
}
- ret = nand_scan(mtd, fun->mchip_count);
+ ret = nand_scan(&fun->chip, fun->mchip_count);
if (ret)
goto err;
@@ -326,7 +324,7 @@ static int fun_remove(struct platform_device *ofdev)
struct mtd_info *mtd = nand_to_mtd(&fun->chip);
int i;
- nand_release(mtd);
+ nand_release(&fun->chip);
kfree(mtd->name);
for (i = 0; i < fun->mchip_count; i++) {
diff --git a/drivers/mtd/nand/raw/fsmc_nand.c b/drivers/mtd/nand/raw/fsmc_nand.c
index f418236fa020..70ac8d875218 100644
--- a/drivers/mtd/nand/raw/fsmc_nand.c
+++ b/drivers/mtd/nand/raw/fsmc_nand.c
@@ -340,10 +340,9 @@ static int fsmc_calc_timings(struct fsmc_nand_data *host,
return 0;
}
-static int fsmc_setup_data_interface(struct mtd_info *mtd, int csline,
+static int fsmc_setup_data_interface(struct nand_chip *nand, int csline,
const struct nand_data_interface *conf)
{
- struct nand_chip *nand = mtd_to_nand(mtd);
struct fsmc_nand_data *host = nand_get_controller_data(nand);
struct fsmc_nand_timings tims;
const struct nand_sdr_timings *sdrt;
@@ -368,9 +367,9 @@ static int fsmc_setup_data_interface(struct mtd_info *mtd, int csline,
/*
* fsmc_enable_hwecc - Enables Hardware ECC through FSMC registers
*/
-static void fsmc_enable_hwecc(struct mtd_info *mtd, int mode)
+static void fsmc_enable_hwecc(struct nand_chip *chip, int mode)
{
- struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
+ struct fsmc_nand_data *host = mtd_to_fsmc(nand_to_mtd(chip));
writel_relaxed(readl(host->regs_va + FSMC_PC) & ~FSMC_ECCPLEN_256,
host->regs_va + FSMC_PC);
@@ -385,10 +384,10 @@ static void fsmc_enable_hwecc(struct mtd_info *mtd, int mode)
* FSMC. ECC is 13 bytes for 512 bytes of data (supports error correction up to
* max of 8-bits)
*/
-static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data,
+static int fsmc_read_hwecc_ecc4(struct nand_chip *chip, const uint8_t *data,
uint8_t *ecc)
{
- struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
+ struct fsmc_nand_data *host = mtd_to_fsmc(nand_to_mtd(chip));
uint32_t ecc_tmp;
unsigned long deadline = jiffies + FSMC_BUSY_WAIT_TIMEOUT;
@@ -433,10 +432,10 @@ static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data,
* FSMC. ECC is 3 bytes for 512 bytes of data (supports error correction up to
* max of 1-bit)
*/
-static int fsmc_read_hwecc_ecc1(struct mtd_info *mtd, const uint8_t *data,
+static int fsmc_read_hwecc_ecc1(struct nand_chip *chip, const uint8_t *data,
uint8_t *ecc)
{
- struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
+ struct fsmc_nand_data *host = mtd_to_fsmc(nand_to_mtd(chip));
uint32_t ecc_tmp;
ecc_tmp = readl_relaxed(host->regs_va + ECC1);
@@ -610,9 +609,9 @@ static void fsmc_write_buf_dma(struct mtd_info *mtd, const uint8_t *buf,
}
/* fsmc_select_chip - assert or deassert nCE */
-static void fsmc_select_chip(struct mtd_info *mtd, int chipnr)
+static void fsmc_select_chip(struct nand_chip *chip, int chipnr)
{
- struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
+ struct fsmc_nand_data *host = mtd_to_fsmc(nand_to_mtd(chip));
u32 pc;
/* Support only one CS */
@@ -707,7 +706,6 @@ static int fsmc_exec_op(struct nand_chip *chip, const struct nand_operation *op,
/*
* fsmc_read_page_hwecc
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
* @oob_required: caller expects OOB data read to chip->oob_poi
@@ -719,9 +717,10 @@ static int fsmc_exec_op(struct nand_chip *chip, const struct nand_operation *op,
* After this read, fsmc hardware generates and reports error data bits(up to a
* max of 8 bits)
*/
-static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+static int fsmc_read_page_hwecc(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int i, j, s, stat, eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps;
@@ -740,7 +739,7 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
for (i = 0, s = 0; s < eccsteps; s++, i += eccbytes, p += eccsize) {
nand_read_page_op(chip, page, s * eccsize, NULL, 0);
- chip->ecc.hwctl(mtd, NAND_ECC_READ);
+ chip->ecc.hwctl(chip, NAND_ECC_READ);
nand_read_data_op(chip, p, eccsize, false);
for (j = 0; j < eccbytes;) {
@@ -767,9 +766,9 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
}
memcpy(&ecc_code[i], oob, chip->ecc.bytes);
- chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+ chip->ecc.calculate(chip, p, &ecc_calc[i]);
- stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
+ stat = chip->ecc.correct(chip, p, &ecc_code[i], &ecc_calc[i]);
if (stat < 0) {
mtd->ecc_stats.failed++;
} else {
@@ -791,11 +790,10 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
* calc_ecc is a 104 bit information containing maximum of 8 error
* offset informations of 13 bits each in 512 bytes of read data.
*/
-static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat,
- uint8_t *read_ecc, uint8_t *calc_ecc)
+static int fsmc_bch8_correct_data(struct nand_chip *chip, uint8_t *dat,
+ uint8_t *read_ecc, uint8_t *calc_ecc)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
- struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
+ struct fsmc_nand_data *host = mtd_to_fsmc(nand_to_mtd(chip));
uint32_t err_idx[8];
uint32_t num_err, i;
uint32_t ecc1, ecc2, ecc3, ecc4;
@@ -951,6 +949,7 @@ static int fsmc_nand_attach_chip(struct nand_chip *nand)
nand->ecc.correct = nand_correct_data;
nand->ecc.bytes = 3;
nand->ecc.strength = 1;
+ nand->ecc.options |= NAND_ECC_SOFT_HAMMING_SM_ORDER;
break;
case NAND_ECC_SOFT:
@@ -1082,7 +1081,6 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
mtd->dev.parent = &pdev->dev;
nand->exec_op = fsmc_exec_op;
nand->select_chip = fsmc_select_chip;
- nand->chip_delay = 30;
/*
* Setup default ECC mode. nand_dt_init() called from nand_scan_ident()
@@ -1125,7 +1123,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
* Scan to find existence of the device
*/
nand->dummy_controller.ops = &fsmc_nand_controller_ops;
- ret = nand_scan(mtd, 1);
+ ret = nand_scan(nand, 1);
if (ret)
goto release_dma_write_chan;
@@ -1161,7 +1159,7 @@ static int fsmc_nand_remove(struct platform_device *pdev)
struct fsmc_nand_data *host = platform_get_drvdata(pdev);
if (host) {
- nand_release(nand_to_mtd(&host->nand));
+ nand_release(&host->nand);
if (host->mode == USE_DMA_ACCESS) {
dma_release_channel(host->write_dma_chan);
diff --git a/drivers/mtd/nand/raw/gpio.c b/drivers/mtd/nand/raw/gpio.c
index 2780af26d9ab..a6c9a824a7d4 100644
--- a/drivers/mtd/nand/raw/gpio.c
+++ b/drivers/mtd/nand/raw/gpio.c
@@ -73,9 +73,10 @@ static void gpio_nand_dosync(struct gpiomtd *gpiomtd)
static inline void gpio_nand_dosync(struct gpiomtd *gpiomtd) {}
#endif
-static void gpio_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+static void gpio_nand_cmd_ctrl(struct nand_chip *chip, int cmd,
+ unsigned int ctrl)
{
- struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd);
+ struct gpiomtd *gpiomtd = gpio_nand_getpriv(nand_to_mtd(chip));
gpio_nand_dosync(gpiomtd);
@@ -89,13 +90,13 @@ static void gpio_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
if (cmd == NAND_CMD_NONE)
return;
- writeb(cmd, gpiomtd->nand_chip.IO_ADDR_W);
+ writeb(cmd, gpiomtd->nand_chip.legacy.IO_ADDR_W);
gpio_nand_dosync(gpiomtd);
}
-static int gpio_nand_devready(struct mtd_info *mtd)
+static int gpio_nand_devready(struct nand_chip *chip)
{
- struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd);
+ struct gpiomtd *gpiomtd = gpio_nand_getpriv(nand_to_mtd(chip));
return gpiod_get_value(gpiomtd->rdy);
}
@@ -194,7 +195,7 @@ static int gpio_nand_remove(struct platform_device *pdev)
{
struct gpiomtd *gpiomtd = platform_get_drvdata(pdev);
- nand_release(nand_to_mtd(&gpiomtd->nand_chip));
+ nand_release(&gpiomtd->nand_chip);
/* Enable write protection and disable the chip */
if (gpiomtd->nwp && !IS_ERR(gpiomtd->nwp))
@@ -224,9 +225,9 @@ static int gpio_nand_probe(struct platform_device *pdev)
chip = &gpiomtd->nand_chip;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- chip->IO_ADDR_R = devm_ioremap_resource(dev, res);
- if (IS_ERR(chip->IO_ADDR_R))
- return PTR_ERR(chip->IO_ADDR_R);
+ chip->legacy.IO_ADDR_R = devm_ioremap_resource(dev, res);
+ if (IS_ERR(chip->legacy.IO_ADDR_R))
+ return PTR_ERR(chip->legacy.IO_ADDR_R);
res = gpio_nand_get_io_sync(pdev);
if (res) {
@@ -270,15 +271,15 @@ static int gpio_nand_probe(struct platform_device *pdev)
}
/* Using RDY pin */
if (gpiomtd->rdy)
- chip->dev_ready = gpio_nand_devready;
+ chip->legacy.dev_ready = gpio_nand_devready;
nand_set_flash_node(chip, pdev->dev.of_node);
- chip->IO_ADDR_W = chip->IO_ADDR_R;
+ chip->legacy.IO_ADDR_W = chip->legacy.IO_ADDR_R;
chip->ecc.mode = NAND_ECC_SOFT;
chip->ecc.algo = NAND_ECC_HAMMING;
chip->options = gpiomtd->plat.options;
- chip->chip_delay = gpiomtd->plat.chip_delay;
- chip->cmd_ctrl = gpio_nand_cmd_ctrl;
+ chip->legacy.chip_delay = gpiomtd->plat.chip_delay;
+ chip->legacy.cmd_ctrl = gpio_nand_cmd_ctrl;
mtd = nand_to_mtd(chip);
mtd->dev.parent = dev;
@@ -289,7 +290,7 @@ static int gpio_nand_probe(struct platform_device *pdev)
if (gpiomtd->nwp && !IS_ERR(gpiomtd->nwp))
gpiod_direction_output(gpiomtd->nwp, 1);
- ret = nand_scan(mtd, 1);
+ ret = nand_scan(chip, 1);
if (ret)
goto err_wp;
diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c
index 88ea2203e263..bd4cfac6b5aa 100644
--- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c
+++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-lib.c
@@ -471,10 +471,9 @@ void gpmi_nfc_apply_timings(struct gpmi_nand_data *this)
udelay(dll_wait_time_us);
}
-int gpmi_setup_data_interface(struct mtd_info *mtd, int chipnr,
+int gpmi_setup_data_interface(struct nand_chip *chip, int chipnr,
const struct nand_data_interface *conf)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct gpmi_nand_data *this = nand_get_controller_data(chip);
const struct nand_sdr_timings *sdr;
diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
index 1c1ebbc82824..94c2b7525c85 100644
--- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
@@ -783,9 +783,8 @@ error_alloc:
return -ENOMEM;
}
-static void gpmi_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl)
+static void gpmi_cmd_ctrl(struct nand_chip *chip, int data, unsigned int ctrl)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct gpmi_nand_data *this = nand_get_controller_data(chip);
int ret;
@@ -817,17 +816,15 @@ static void gpmi_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl)
this->command_length = 0;
}
-static int gpmi_dev_ready(struct mtd_info *mtd)
+static int gpmi_dev_ready(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct gpmi_nand_data *this = nand_get_controller_data(chip);
return gpmi_is_ready(this, this->current_chip);
}
-static void gpmi_select_chip(struct mtd_info *mtd, int chipnr)
+static void gpmi_select_chip(struct nand_chip *chip, int chipnr)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct gpmi_nand_data *this = nand_get_controller_data(chip);
int ret;
@@ -859,9 +856,8 @@ static void gpmi_select_chip(struct mtd_info *mtd, int chipnr)
this->current_chip = chipnr;
}
-static void gpmi_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void gpmi_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct gpmi_nand_data *this = nand_get_controller_data(chip);
dev_dbg(this->dev, "len is %d\n", len);
@@ -869,9 +865,8 @@ static void gpmi_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
gpmi_read_data(this, buf, len);
}
-static void gpmi_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+static void gpmi_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct gpmi_nand_data *this = nand_get_controller_data(chip);
dev_dbg(this->dev, "len is %d\n", len);
@@ -879,13 +874,12 @@ static void gpmi_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
gpmi_send_data(this, buf, len);
}
-static uint8_t gpmi_read_byte(struct mtd_info *mtd)
+static uint8_t gpmi_read_byte(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct gpmi_nand_data *this = nand_get_controller_data(chip);
uint8_t *buf = this->data_buffer_dma;
- gpmi_read_buf(mtd, buf, 1);
+ gpmi_read_buf(chip, buf, 1);
return buf[0];
}
@@ -1085,8 +1079,8 @@ static int gpmi_ecc_read_page_data(struct nand_chip *chip,
return max_bitflips;
}
-static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+static int gpmi_ecc_read_page(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
nand_read_page_op(chip, page, 0, NULL, 0);
@@ -1094,8 +1088,8 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
}
/* Fake a virtual small page for the subpage read */
-static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
- uint32_t offs, uint32_t len, uint8_t *buf, int page)
+static int gpmi_ecc_read_subpage(struct nand_chip *chip, uint32_t offs,
+ uint32_t len, uint8_t *buf, int page)
{
struct gpmi_nand_data *this = nand_get_controller_data(chip);
void __iomem *bch_regs = this->resources.bch_regs;
@@ -1130,7 +1124,7 @@ static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
dev_dbg(this->dev,
"page:%d, first:%d, last:%d, marker at:%d\n",
page, first, last, marker_pos);
- return gpmi_ecc_read_page(mtd, chip, buf, 0, page);
+ return gpmi_ecc_read_page(chip, buf, 0, page);
}
}
@@ -1182,9 +1176,10 @@ static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
return max_bitflips;
}
-static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required, int page)
+static int gpmi_ecc_write_page(struct nand_chip *chip, const uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct gpmi_nand_data *this = nand_get_controller_data(chip);
struct bch_geometry *nfc_geo = &this->bch_geometry;
const void *payload_virt;
@@ -1324,9 +1319,9 @@ exit_auxiliary:
* ECC-based or raw view of the page is implicit in which function it calls
* (there is a similar pair of ECC-based/raw functions for writing).
*/
-static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int gpmi_ecc_read_oob(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct gpmi_nand_data *this = nand_get_controller_data(chip);
dev_dbg(this->dev, "page number is %d\n", page);
@@ -1335,7 +1330,7 @@ static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
/* Read out the conventional OOB. */
nand_read_page_op(chip, page, mtd->writesize, NULL, 0);
- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize);
/*
* Now, we want to make sure the block mark is correct. In the
@@ -1345,15 +1340,15 @@ static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
if (GPMI_IS_MX23(this)) {
/* Read the block mark into the first byte of the OOB buffer. */
nand_read_page_op(chip, page, 0, NULL, 0);
- chip->oob_poi[0] = chip->read_byte(mtd);
+ chip->oob_poi[0] = chip->legacy.read_byte(chip);
}
return 0;
}
-static int
-gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page)
+static int gpmi_ecc_write_oob(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct mtd_oob_region of = { };
/* Do we have available oob area? */
@@ -1380,10 +1375,10 @@ gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page)
* See set_geometry_by_ecc_info inline comments to have a full description
* of the layout used by the GPMI controller.
*/
-static int gpmi_ecc_read_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip, uint8_t *buf,
+static int gpmi_ecc_read_page_raw(struct nand_chip *chip, uint8_t *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct gpmi_nand_data *this = nand_get_controller_data(chip);
struct bch_geometry *nfc_geo = &this->bch_geometry;
int eccsize = nfc_geo->ecc_chunk_size;
@@ -1464,11 +1459,10 @@ static int gpmi_ecc_read_page_raw(struct mtd_info *mtd,
* See set_geometry_by_ecc_info inline comments to have a full description
* of the layout used by the GPMI controller.
*/
-static int gpmi_ecc_write_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip,
- const uint8_t *buf,
+static int gpmi_ecc_write_page_raw(struct nand_chip *chip, const uint8_t *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct gpmi_nand_data *this = nand_get_controller_data(chip);
struct bch_geometry *nfc_geo = &this->bch_geometry;
int eccsize = nfc_geo->ecc_chunk_size;
@@ -1536,28 +1530,26 @@ static int gpmi_ecc_write_page_raw(struct mtd_info *mtd,
mtd->writesize + mtd->oobsize);
}
-static int gpmi_ecc_read_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int gpmi_ecc_read_oob_raw(struct nand_chip *chip, int page)
{
- return gpmi_ecc_read_page_raw(mtd, chip, NULL, 1, page);
+ return gpmi_ecc_read_page_raw(chip, NULL, 1, page);
}
-static int gpmi_ecc_write_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int gpmi_ecc_write_oob_raw(struct nand_chip *chip, int page)
{
- return gpmi_ecc_write_page_raw(mtd, chip, NULL, 1, page);
+ return gpmi_ecc_write_page_raw(chip, NULL, 1, page);
}
-static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs)
+static int gpmi_block_markbad(struct nand_chip *chip, loff_t ofs)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct gpmi_nand_data *this = nand_get_controller_data(chip);
int ret = 0;
uint8_t *block_mark;
int column, page, chipnr;
chipnr = (int)(ofs >> chip->chip_shift);
- chip->select_chip(mtd, chipnr);
+ chip->select_chip(chip, chipnr);
column = !GPMI_IS_MX23(this) ? mtd->writesize : 0;
@@ -1570,7 +1562,7 @@ static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs)
ret = nand_prog_page_op(chip, page, column, block_mark, 1);
- chip->select_chip(mtd, -1);
+ chip->select_chip(chip, -1);
return ret;
}
@@ -1607,7 +1599,6 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this)
struct boot_rom_geometry *rom_geo = &this->rom_geometry;
struct device *dev = this->dev;
struct nand_chip *chip = &this->nand;
- struct mtd_info *mtd = nand_to_mtd(chip);
unsigned int search_area_size_in_strides;
unsigned int stride;
unsigned int page;
@@ -1619,7 +1610,7 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this)
search_area_size_in_strides = 1 << rom_geo->search_area_stride_exponent;
saved_chip_number = this->current_chip;
- chip->select_chip(mtd, 0);
+ chip->select_chip(chip, 0);
/*
* Loop through the first search area, looking for the NCB fingerprint.
@@ -1637,7 +1628,7 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this)
* and starts in the 12th byte of the page.
*/
nand_read_page_op(chip, page, 12, NULL, 0);
- chip->read_buf(mtd, buffer, strlen(fingerprint));
+ chip->legacy.read_buf(chip, buffer, strlen(fingerprint));
/* Look for the fingerprint. */
if (!memcmp(buffer, fingerprint, strlen(fingerprint))) {
@@ -1647,7 +1638,7 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this)
}
- chip->select_chip(mtd, saved_chip_number);
+ chip->select_chip(chip, saved_chip_number);
if (found_an_ncb_fingerprint)
dev_dbg(dev, "\tFound a fingerprint\n");
@@ -1690,7 +1681,7 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this)
/* Select chip 0. */
saved_chip_number = this->current_chip;
- chip->select_chip(mtd, 0);
+ chip->select_chip(chip, 0);
/* Loop over blocks in the first search area, erasing them. */
dev_dbg(dev, "Erasing the search area...\n");
@@ -1716,13 +1707,13 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this)
/* Write the first page of the current stride. */
dev_dbg(dev, "Writing an NCB fingerprint in page 0x%x\n", page);
- status = chip->ecc.write_page_raw(mtd, chip, buffer, 0, page);
+ status = chip->ecc.write_page_raw(chip, buffer, 0, page);
if (status)
dev_err(dev, "[%s] Write failed.\n", __func__);
}
/* Deselect chip 0. */
- chip->select_chip(mtd, saved_chip_number);
+ chip->select_chip(chip, saved_chip_number);
return 0;
}
@@ -1771,10 +1762,10 @@ static int mx23_boot_init(struct gpmi_nand_data *this)
byte = block << chip->phys_erase_shift;
/* Send the command to read the conventional block mark. */
- chip->select_chip(mtd, chipnr);
+ chip->select_chip(chip, chipnr);
nand_read_page_op(chip, page, mtd->writesize, NULL, 0);
- block_mark = chip->read_byte(mtd);
- chip->select_chip(mtd, -1);
+ block_mark = chip->legacy.read_byte(chip);
+ chip->select_chip(chip, -1);
/*
* Check if the block is marked bad. If so, we need to mark it
@@ -1783,7 +1774,7 @@ static int mx23_boot_init(struct gpmi_nand_data *this)
*/
if (block_mark != 0xff) {
dev_dbg(dev, "Transcribing mark in block %u\n", block);
- ret = chip->block_markbad(mtd, byte);
+ ret = chip->legacy.block_markbad(chip, byte);
if (ret)
dev_err(dev,
"Failed to mark block bad with ret %d\n",
@@ -1911,13 +1902,13 @@ static int gpmi_nand_init(struct gpmi_nand_data *this)
nand_set_flash_node(chip, this->pdev->dev.of_node);
chip->select_chip = gpmi_select_chip;
chip->setup_data_interface = gpmi_setup_data_interface;
- chip->cmd_ctrl = gpmi_cmd_ctrl;
- chip->dev_ready = gpmi_dev_ready;
- chip->read_byte = gpmi_read_byte;
- chip->read_buf = gpmi_read_buf;
- chip->write_buf = gpmi_write_buf;
+ chip->legacy.cmd_ctrl = gpmi_cmd_ctrl;
+ chip->legacy.dev_ready = gpmi_dev_ready;
+ chip->legacy.read_byte = gpmi_read_byte;
+ chip->legacy.read_buf = gpmi_read_buf;
+ chip->legacy.write_buf = gpmi_write_buf;
chip->badblock_pattern = &gpmi_bbt_descr;
- chip->block_markbad = gpmi_block_markbad;
+ chip->legacy.block_markbad = gpmi_block_markbad;
chip->options |= NAND_NO_SUBPAGE_WRITE;
/* Set up swap_block_mark, must be set before the gpmi_set_geometry() */
@@ -1934,7 +1925,7 @@ static int gpmi_nand_init(struct gpmi_nand_data *this)
goto err_out;
chip->dummy_controller.ops = &gpmi_nand_controller_ops;
- ret = nand_scan(mtd, GPMI_IS_MX6(this) ? 2 : 1);
+ ret = nand_scan(chip, GPMI_IS_MX6(this) ? 2 : 1);
if (ret)
goto err_out;
@@ -2026,7 +2017,7 @@ static int gpmi_nand_remove(struct platform_device *pdev)
{
struct gpmi_nand_data *this = platform_get_drvdata(pdev);
- nand_release(nand_to_mtd(&this->nand));
+ nand_release(&this->nand);
gpmi_free_dma_buffer(this);
release_resources(this);
return 0;
diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h
index 69cd0cbde4f2..d0b79bac2728 100644
--- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h
+++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h
@@ -178,7 +178,7 @@ int gpmi_is_ready(struct gpmi_nand_data *, unsigned chip);
int gpmi_send_command(struct gpmi_nand_data *);
int gpmi_enable_clk(struct gpmi_nand_data *this);
int gpmi_disable_clk(struct gpmi_nand_data *this);
-int gpmi_setup_data_interface(struct mtd_info *mtd, int chipnr,
+int gpmi_setup_data_interface(struct nand_chip *chip, int chipnr,
const struct nand_data_interface *conf);
void gpmi_nfc_apply_timings(struct gpmi_nand_data *this);
int gpmi_read_data(struct gpmi_nand_data *, void *buf, int len);
diff --git a/drivers/mtd/nand/raw/hisi504_nand.c b/drivers/mtd/nand/raw/hisi504_nand.c
index 950dc7789296..f043938ee36b 100644
--- a/drivers/mtd/nand/raw/hisi504_nand.c
+++ b/drivers/mtd/nand/raw/hisi504_nand.c
@@ -353,9 +353,8 @@ static int hisi_nfc_send_cmd_reset(struct hinfc_host *host, int chipselect)
return 0;
}
-static void hisi_nfc_select_chip(struct mtd_info *mtd, int chipselect)
+static void hisi_nfc_select_chip(struct nand_chip *chip, int chipselect)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct hinfc_host *host = nand_get_controller_data(chip);
if (chipselect < 0)
@@ -364,9 +363,8 @@ static void hisi_nfc_select_chip(struct mtd_info *mtd, int chipselect)
host->chipselect = chipselect;
}
-static uint8_t hisi_nfc_read_byte(struct mtd_info *mtd)
+static uint8_t hisi_nfc_read_byte(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct hinfc_host *host = nand_get_controller_data(chip);
if (host->command == NAND_CMD_STATUS)
@@ -380,28 +378,17 @@ static uint8_t hisi_nfc_read_byte(struct mtd_info *mtd)
return *(uint8_t *)(host->buffer + host->offset - 1);
}
-static u16 hisi_nfc_read_word(struct mtd_info *mtd)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
- struct hinfc_host *host = nand_get_controller_data(chip);
-
- host->offset += 2;
- return *(u16 *)(host->buffer + host->offset - 2);
-}
-
static void
-hisi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+hisi_nfc_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct hinfc_host *host = nand_get_controller_data(chip);
memcpy(host->buffer + host->offset, buf, len);
host->offset += len;
}
-static void hisi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void hisi_nfc_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct hinfc_host *host = nand_get_controller_data(chip);
memcpy(buf, host->buffer + host->offset, len);
@@ -442,10 +429,10 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr)
}
}
-static void hisi_nfc_cmdfunc(struct mtd_info *mtd, unsigned command, int column,
- int page_addr)
+static void hisi_nfc_cmdfunc(struct nand_chip *chip, unsigned command,
+ int column, int page_addr)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct hinfc_host *host = nand_get_controller_data(chip);
int is_cache_invalid = 1;
unsigned int flag = 0;
@@ -537,15 +524,16 @@ static irqreturn_t hinfc_irq_handle(int irq, void *devid)
return IRQ_HANDLED;
}
-static int hisi_nand_read_page_hwecc(struct mtd_info *mtd,
- struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
+static int hisi_nand_read_page_hwecc(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct hinfc_host *host = nand_get_controller_data(chip);
int max_bitflips = 0, stat = 0, stat_max = 0, status_ecc;
int stat_1, stat_2;
nand_read_page_op(chip, page, 0, buf, mtd->writesize);
- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize);
/* errors which can not be corrected by ECC */
if (host->irq_status & HINFC504_INTS_UE) {
@@ -569,9 +557,9 @@ static int hisi_nand_read_page_hwecc(struct mtd_info *mtd,
return max_bitflips;
}
-static int hisi_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int hisi_nand_read_oob(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct hinfc_host *host = nand_get_controller_data(chip);
nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
@@ -585,13 +573,15 @@ static int hisi_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
return 0;
}
-static int hisi_nand_write_page_hwecc(struct mtd_info *mtd,
- struct nand_chip *chip, const uint8_t *buf, int oob_required,
- int page)
+static int hisi_nand_write_page_hwecc(struct nand_chip *chip,
+ const uint8_t *buf, int oob_required,
+ int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
if (oob_required)
- chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize);
return nand_prog_page_end_op(chip);
}
@@ -792,15 +782,14 @@ static int hisi_nfc_probe(struct platform_device *pdev)
nand_set_controller_data(chip, host);
nand_set_flash_node(chip, np);
- chip->cmdfunc = hisi_nfc_cmdfunc;
+ chip->legacy.cmdfunc = hisi_nfc_cmdfunc;
chip->select_chip = hisi_nfc_select_chip;
- chip->read_byte = hisi_nfc_read_byte;
- chip->read_word = hisi_nfc_read_word;
- chip->write_buf = hisi_nfc_write_buf;
- chip->read_buf = hisi_nfc_read_buf;
- chip->chip_delay = HINFC504_CHIP_DELAY;
- chip->set_features = nand_get_set_features_notsupp;
- chip->get_features = nand_get_set_features_notsupp;
+ chip->legacy.read_byte = hisi_nfc_read_byte;
+ chip->legacy.write_buf = hisi_nfc_write_buf;
+ chip->legacy.read_buf = hisi_nfc_read_buf;
+ chip->legacy.chip_delay = HINFC504_CHIP_DELAY;
+ chip->legacy.set_features = nand_get_set_features_notsupp;
+ chip->legacy.get_features = nand_get_set_features_notsupp;
hisi_nfc_host_init(host);
@@ -811,7 +800,7 @@ static int hisi_nfc_probe(struct platform_device *pdev)
}
chip->dummy_controller.ops = &hisi_nfc_controller_ops;
- ret = nand_scan(mtd, max_chips);
+ ret = nand_scan(chip, max_chips);
if (ret)
return ret;
@@ -828,9 +817,8 @@ static int hisi_nfc_probe(struct platform_device *pdev)
static int hisi_nfc_remove(struct platform_device *pdev)
{
struct hinfc_host *host = platform_get_drvdata(pdev);
- struct mtd_info *mtd = nand_to_mtd(&host->chip);
- nand_release(mtd);
+ nand_release(&host->chip);
return 0;
}
diff --git a/drivers/mtd/nand/raw/internals.h b/drivers/mtd/nand/raw/internals.h
new file mode 100644
index 000000000000..04c2cf74eff3
--- /dev/null
+++ b/drivers/mtd/nand/raw/internals.h
@@ -0,0 +1,115 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018 - Bootlin
+ *
+ * Author: Boris Brezillon <boris.brezillon@bootlin.com>
+ *
+ * Header containing internal definitions to be used only by core files.
+ * NAND controller drivers should not include this file.
+ */
+
+#ifndef __LINUX_RAWNAND_INTERNALS
+#define __LINUX_RAWNAND_INTERNALS
+
+#include <linux/mtd/rawnand.h>
+
+/*
+ * NAND Flash Manufacturer ID Codes
+ */
+#define NAND_MFR_AMD 0x01
+#define NAND_MFR_ATO 0x9b
+#define NAND_MFR_EON 0x92
+#define NAND_MFR_ESMT 0xc8
+#define NAND_MFR_FUJITSU 0x04
+#define NAND_MFR_HYNIX 0xad
+#define NAND_MFR_INTEL 0x89
+#define NAND_MFR_MACRONIX 0xc2
+#define NAND_MFR_MICRON 0x2c
+#define NAND_MFR_NATIONAL 0x8f
+#define NAND_MFR_RENESAS 0x07
+#define NAND_MFR_SAMSUNG 0xec
+#define NAND_MFR_SANDISK 0x45
+#define NAND_MFR_STMICRO 0x20
+#define NAND_MFR_TOSHIBA 0x98
+#define NAND_MFR_WINBOND 0xef
+
+/**
+ * struct nand_manufacturer_ops - NAND Manufacturer operations
+ * @detect: detect the NAND memory organization and capabilities
+ * @init: initialize all vendor specific fields (like the ->read_retry()
+ * implementation) if any.
+ * @cleanup: the ->init() function may have allocated resources, ->cleanup()
+ * is here to let vendor specific code release those resources.
+ * @fixup_onfi_param_page: apply vendor specific fixups to the ONFI parameter
+ * page. This is called after the checksum is verified.
+ */
+struct nand_manufacturer_ops {
+ void (*detect)(struct nand_chip *chip);
+ int (*init)(struct nand_chip *chip);
+ void (*cleanup)(struct nand_chip *chip);
+ void (*fixup_onfi_param_page)(struct nand_chip *chip,
+ struct nand_onfi_params *p);
+};
+
+/**
+ * struct nand_manufacturer - NAND Flash Manufacturer structure
+ * @name: Manufacturer name
+ * @id: manufacturer ID code of device.
+ * @ops: manufacturer operations
+ */
+struct nand_manufacturer {
+ int id;
+ char *name;
+ const struct nand_manufacturer_ops *ops;
+};
+
+
+extern struct nand_flash_dev nand_flash_ids[];
+
+extern const struct nand_manufacturer_ops amd_nand_manuf_ops;
+extern const struct nand_manufacturer_ops esmt_nand_manuf_ops;
+extern const struct nand_manufacturer_ops hynix_nand_manuf_ops;
+extern const struct nand_manufacturer_ops macronix_nand_manuf_ops;
+extern const struct nand_manufacturer_ops micron_nand_manuf_ops;
+extern const struct nand_manufacturer_ops samsung_nand_manuf_ops;
+extern const struct nand_manufacturer_ops toshiba_nand_manuf_ops;
+
+/* Core functions */
+const struct nand_manufacturer *nand_get_manufacturer(u8 id);
+int nand_markbad_bbm(struct nand_chip *chip, loff_t ofs);
+int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr,
+ int allowbbt);
+int onfi_fill_data_interface(struct nand_chip *chip,
+ enum nand_data_interface_type type,
+ int timing_mode);
+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);
+int nand_read_page_raw_notsupp(struct nand_chip *chip, u8 *buf,
+ int oob_required, int page);
+int nand_write_page_raw_notsupp(struct nand_chip *chip, const u8 *buf,
+ int oob_required, int page);
+int nand_exit_status_op(struct nand_chip *chip);
+int nand_read_param_page_op(struct nand_chip *chip, u8 page, void *buf,
+ unsigned int len);
+void nand_decode_ext_id(struct nand_chip *chip);
+void panic_nand_wait(struct nand_chip *chip, unsigned long timeo);
+void sanitize_string(uint8_t *s, size_t len);
+
+/* BBT functions */
+int nand_markbad_bbt(struct nand_chip *chip, loff_t offs);
+int nand_isreserved_bbt(struct nand_chip *chip, loff_t offs);
+int nand_isbad_bbt(struct nand_chip *chip, loff_t offs, int allowbbt);
+
+/* Legacy */
+void nand_legacy_set_defaults(struct nand_chip *chip);
+void nand_legacy_adjust_cmdfunc(struct nand_chip *chip);
+int nand_legacy_check_hooks(struct nand_chip *chip);
+
+/* ONFI functions */
+u16 onfi_crc16(u16 crc, u8 const *p, size_t len);
+int nand_onfi_detect(struct nand_chip *chip);
+
+/* JEDEC functions */
+int nand_jedec_detect(struct nand_chip *chip);
+
+#endif /* __LINUX_RAWNAND_INTERNALS */
diff --git a/drivers/mtd/nand/raw/jz4740_nand.c b/drivers/mtd/nand/raw/jz4740_nand.c
index a7515452bc59..fb59cfca11a7 100644
--- a/drivers/mtd/nand/raw/jz4740_nand.c
+++ b/drivers/mtd/nand/raw/jz4740_nand.c
@@ -78,10 +78,9 @@ static inline struct jz_nand *mtd_to_jz_nand(struct mtd_info *mtd)
return container_of(mtd_to_nand(mtd), struct jz_nand, chip);
}
-static void jz_nand_select_chip(struct mtd_info *mtd, int chipnr)
+static void jz_nand_select_chip(struct nand_chip *chip, int chipnr)
{
- struct jz_nand *nand = mtd_to_jz_nand(mtd);
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip));
uint32_t ctrl;
int banknr;
@@ -92,18 +91,18 @@ static void jz_nand_select_chip(struct mtd_info *mtd, int chipnr)
banknr = -1;
} else {
banknr = nand->banks[chipnr] - 1;
- chip->IO_ADDR_R = nand->bank_base[banknr];
- chip->IO_ADDR_W = nand->bank_base[banknr];
+ chip->legacy.IO_ADDR_R = nand->bank_base[banknr];
+ chip->legacy.IO_ADDR_W = nand->bank_base[banknr];
}
writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
nand->selected_bank = banknr;
}
-static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
+static void jz_nand_cmd_ctrl(struct nand_chip *chip, int dat,
+ unsigned int ctrl)
{
- struct jz_nand *nand = mtd_to_jz_nand(mtd);
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip));
uint32_t reg;
void __iomem *bank_base = nand->bank_base[nand->selected_bank];
@@ -115,7 +114,7 @@ static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
bank_base += JZ_NAND_MEM_ADDR_OFFSET;
else if (ctrl & NAND_CLE)
bank_base += JZ_NAND_MEM_CMD_OFFSET;
- chip->IO_ADDR_W = bank_base;
+ chip->legacy.IO_ADDR_W = bank_base;
reg = readl(nand->base + JZ_REG_NAND_CTRL);
if (ctrl & NAND_NCE)
@@ -125,18 +124,18 @@ static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
writel(reg, nand->base + JZ_REG_NAND_CTRL);
}
if (dat != NAND_CMD_NONE)
- writeb(dat, chip->IO_ADDR_W);
+ writeb(dat, chip->legacy.IO_ADDR_W);
}
-static int jz_nand_dev_ready(struct mtd_info *mtd)
+static int jz_nand_dev_ready(struct nand_chip *chip)
{
- struct jz_nand *nand = mtd_to_jz_nand(mtd);
+ struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip));
return gpiod_get_value_cansleep(nand->busy_gpio);
}
-static void jz_nand_hwctl(struct mtd_info *mtd, int mode)
+static void jz_nand_hwctl(struct nand_chip *chip, int mode)
{
- struct jz_nand *nand = mtd_to_jz_nand(mtd);
+ struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip));
uint32_t reg;
writel(0, nand->base + JZ_REG_NAND_IRQ_STAT);
@@ -162,10 +161,10 @@ static void jz_nand_hwctl(struct mtd_info *mtd, int mode)
writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
}
-static int jz_nand_calculate_ecc_rs(struct mtd_info *mtd, const uint8_t *dat,
- uint8_t *ecc_code)
+static int jz_nand_calculate_ecc_rs(struct nand_chip *chip, const uint8_t *dat,
+ uint8_t *ecc_code)
{
- struct jz_nand *nand = mtd_to_jz_nand(mtd);
+ struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip));
uint32_t reg, status;
int i;
unsigned int timeout = 1000;
@@ -215,10 +214,10 @@ static void jz_nand_correct_data(uint8_t *dat, int index, int mask)
dat[index+1] = (data >> 8) & 0xff;
}
-static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat,
- uint8_t *read_ecc, uint8_t *calc_ecc)
+static int jz_nand_correct_ecc_rs(struct nand_chip *chip, uint8_t *dat,
+ uint8_t *read_ecc, uint8_t *calc_ecc)
{
- struct jz_nand *nand = mtd_to_jz_nand(mtd);
+ struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip));
int i, error_count, index;
uint32_t reg, status, error;
unsigned int timeout = 1000;
@@ -331,19 +330,19 @@ static int jz_nand_detect_bank(struct platform_device *pdev,
if (chipnr == 0) {
/* Detect first chip. */
- ret = nand_scan(mtd, 1);
+ ret = nand_scan(chip, 1);
if (ret)
goto notfound_id;
/* Retrieve the IDs from the first chip. */
- chip->select_chip(mtd, 0);
+ chip->select_chip(chip, 0);
nand_reset_op(chip);
nand_readid_op(chip, 0, id, sizeof(id));
*nand_maf_id = id[0];
*nand_dev_id = id[1];
} else {
/* Detect additional chip. */
- chip->select_chip(mtd, chipnr);
+ chip->select_chip(chip, chipnr);
nand_reset_op(chip);
nand_readid_op(chip, 0, id, sizeof(id));
if (*nand_maf_id != id[0] || *nand_dev_id != id[1]) {
@@ -426,13 +425,13 @@ static int jz_nand_probe(struct platform_device *pdev)
chip->ecc.strength = 4;
chip->ecc.options = NAND_ECC_GENERIC_ERASED_CHECK;
- chip->chip_delay = 50;
- chip->cmd_ctrl = jz_nand_cmd_ctrl;
+ chip->legacy.chip_delay = 50;
+ chip->legacy.cmd_ctrl = jz_nand_cmd_ctrl;
chip->select_chip = jz_nand_select_chip;
chip->dummy_controller.ops = &jz_nand_controller_ops;
if (nand->busy_gpio)
- chip->dev_ready = jz_nand_dev_ready;
+ chip->legacy.dev_ready = jz_nand_dev_ready;
platform_set_drvdata(pdev, nand);
@@ -507,7 +506,7 @@ static int jz_nand_remove(struct platform_device *pdev)
struct jz_nand *nand = platform_get_drvdata(pdev);
size_t i;
- nand_release(nand_to_mtd(&nand->chip));
+ nand_release(&nand->chip);
/* Deassert and disable all chips */
writel(0, nand->base + JZ_REG_NAND_CTRL);
diff --git a/drivers/mtd/nand/raw/jz4780_nand.c b/drivers/mtd/nand/raw/jz4780_nand.c
index db4fa60bd52a..cdf22100ab77 100644
--- a/drivers/mtd/nand/raw/jz4780_nand.c
+++ b/drivers/mtd/nand/raw/jz4780_nand.c
@@ -71,9 +71,9 @@ static inline struct jz4780_nand_controller
return container_of(ctrl, struct jz4780_nand_controller, controller);
}
-static void jz4780_nand_select_chip(struct mtd_info *mtd, int chipnr)
+static void jz4780_nand_select_chip(struct nand_chip *chip, int chipnr)
{
- struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
+ struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip));
struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
struct jz4780_nand_cs *cs;
@@ -86,10 +86,10 @@ static void jz4780_nand_select_chip(struct mtd_info *mtd, int chipnr)
nfc->selected = chipnr;
}
-static void jz4780_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+static void jz4780_nand_cmd_ctrl(struct nand_chip *chip, int cmd,
unsigned int ctrl)
{
- struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
+ struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip));
struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
struct jz4780_nand_cs *cs;
@@ -109,24 +109,24 @@ static void jz4780_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
writeb(cmd, cs->base + OFFSET_CMD);
}
-static int jz4780_nand_dev_ready(struct mtd_info *mtd)
+static int jz4780_nand_dev_ready(struct nand_chip *chip)
{
- struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
+ struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip));
return !gpiod_get_value_cansleep(nand->busy_gpio);
}
-static void jz4780_nand_ecc_hwctl(struct mtd_info *mtd, int mode)
+static void jz4780_nand_ecc_hwctl(struct nand_chip *chip, int mode)
{
- struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
+ struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip));
nand->reading = (mode == NAND_ECC_READ);
}
-static int jz4780_nand_ecc_calculate(struct mtd_info *mtd, const u8 *dat,
+static int jz4780_nand_ecc_calculate(struct nand_chip *chip, const u8 *dat,
u8 *ecc_code)
{
- struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
+ struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip));
struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
struct jz4780_bch_params params;
@@ -144,10 +144,10 @@ static int jz4780_nand_ecc_calculate(struct mtd_info *mtd, const u8 *dat,
return jz4780_bch_calculate(nfc->bch, &params, dat, ecc_code);
}
-static int jz4780_nand_ecc_correct(struct mtd_info *mtd, u8 *dat,
+static int jz4780_nand_ecc_correct(struct nand_chip *chip, u8 *dat,
u8 *read_ecc, u8 *calc_ecc)
{
- struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
+ struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip));
struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
struct jz4780_bch_params params;
@@ -256,7 +256,7 @@ static int jz4780_nand_init_chip(struct platform_device *pdev,
dev_err(dev, "failed to request busy GPIO: %d\n", ret);
return ret;
} else if (nand->busy_gpio) {
- nand->chip.dev_ready = jz4780_nand_dev_ready;
+ nand->chip.legacy.dev_ready = jz4780_nand_dev_ready;
}
nand->wp_gpio = devm_gpiod_get_optional(dev, "wp", GPIOD_OUT_LOW);
@@ -275,24 +275,24 @@ static int jz4780_nand_init_chip(struct platform_device *pdev,
return -ENOMEM;
mtd->dev.parent = dev;
- chip->IO_ADDR_R = cs->base + OFFSET_DATA;
- chip->IO_ADDR_W = cs->base + OFFSET_DATA;
- chip->chip_delay = RB_DELAY_US;
+ chip->legacy.IO_ADDR_R = cs->base + OFFSET_DATA;
+ chip->legacy.IO_ADDR_W = cs->base + OFFSET_DATA;
+ chip->legacy.chip_delay = RB_DELAY_US;
chip->options = NAND_NO_SUBPAGE_WRITE;
chip->select_chip = jz4780_nand_select_chip;
- chip->cmd_ctrl = jz4780_nand_cmd_ctrl;
+ chip->legacy.cmd_ctrl = jz4780_nand_cmd_ctrl;
chip->ecc.mode = NAND_ECC_HW;
chip->controller = &nfc->controller;
nand_set_flash_node(chip, np);
chip->controller->ops = &jz4780_nand_controller_ops;
- ret = nand_scan(mtd, 1);
+ ret = nand_scan(chip, 1);
if (ret)
return ret;
ret = mtd_device_register(mtd, NULL, 0);
if (ret) {
- nand_release(mtd);
+ nand_release(chip);
return ret;
}
@@ -307,7 +307,7 @@ static void jz4780_nand_cleanup_chips(struct jz4780_nand_controller *nfc)
while (!list_empty(&nfc->chips)) {
chip = list_first_entry(&nfc->chips, struct jz4780_nand_chip, chip_list);
- nand_release(nand_to_mtd(&chip->chip));
+ nand_release(&chip->chip);
list_del(&chip->chip_list);
}
}
@@ -352,7 +352,7 @@ static int jz4780_nand_probe(struct platform_device *pdev)
return -ENODEV;
}
- nfc = devm_kzalloc(dev, sizeof(*nfc) + (sizeof(nfc->cs[0]) * num_banks), GFP_KERNEL);
+ nfc = devm_kzalloc(dev, struct_size(nfc, cs, num_banks), GFP_KERNEL);
if (!nfc)
return -ENOMEM;
diff --git a/drivers/mtd/nand/raw/lpc32xx_mlc.c b/drivers/mtd/nand/raw/lpc32xx_mlc.c
index e82abada130a..abbb655fe154 100644
--- a/drivers/mtd/nand/raw/lpc32xx_mlc.c
+++ b/drivers/mtd/nand/raw/lpc32xx_mlc.c
@@ -286,10 +286,9 @@ static void lpc32xx_nand_setup(struct lpc32xx_nand_host *host)
/*
* Hardware specific access to control lines
*/
-static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+static void lpc32xx_nand_cmd_ctrl(struct nand_chip *nand_chip, int cmd,
unsigned int ctrl)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct lpc32xx_nand_host *host = nand_get_controller_data(nand_chip);
if (cmd != NAND_CMD_NONE) {
@@ -303,9 +302,8 @@ static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
/*
* Read Device Ready (NAND device _and_ controller ready)
*/
-static int lpc32xx_nand_device_ready(struct mtd_info *mtd)
+static int lpc32xx_nand_device_ready(struct nand_chip *nand_chip)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct lpc32xx_nand_host *host = nand_get_controller_data(nand_chip);
if ((readb(MLC_ISR(host->io_base)) &
@@ -330,8 +328,9 @@ static irqreturn_t lpc3xxx_nand_irq(int irq, struct lpc32xx_nand_host *host)
return IRQ_HANDLED;
}
-static int lpc32xx_waitfunc_nand(struct mtd_info *mtd, struct nand_chip *chip)
+static int lpc32xx_waitfunc_nand(struct nand_chip *chip)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
if (readb(MLC_ISR(host->io_base)) & MLCISR_NAND_READY)
@@ -349,9 +348,9 @@ exit:
return NAND_STATUS_READY;
}
-static int lpc32xx_waitfunc_controller(struct mtd_info *mtd,
- struct nand_chip *chip)
+static int lpc32xx_waitfunc_controller(struct nand_chip *chip)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
if (readb(MLC_ISR(host->io_base)) & MLCISR_CONTROLLER_READY)
@@ -369,10 +368,10 @@ exit:
return NAND_STATUS_READY;
}
-static int lpc32xx_waitfunc(struct mtd_info *mtd, struct nand_chip *chip)
+static int lpc32xx_waitfunc(struct nand_chip *chip)
{
- lpc32xx_waitfunc_nand(mtd, chip);
- lpc32xx_waitfunc_controller(mtd, chip);
+ lpc32xx_waitfunc_nand(chip);
+ lpc32xx_waitfunc_controller(chip);
return NAND_STATUS_READY;
}
@@ -442,9 +441,10 @@ out1:
return -ENXIO;
}
-static int lpc32xx_read_page(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+static int lpc32xx_read_page(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
int i, j;
uint8_t *oobbuf = chip->oob_poi;
@@ -470,7 +470,7 @@ static int lpc32xx_read_page(struct mtd_info *mtd, struct nand_chip *chip,
writeb(0x00, MLC_ECC_AUTO_DEC_REG(host->io_base));
/* Wait for Controller Ready */
- lpc32xx_waitfunc_controller(mtd, chip);
+ lpc32xx_waitfunc_controller(chip);
/* Check ECC Error status */
mlc_isr = readl(MLC_ISR(host->io_base));
@@ -507,11 +507,11 @@ static int lpc32xx_read_page(struct mtd_info *mtd, struct nand_chip *chip,
return 0;
}
-static int lpc32xx_write_page_lowlevel(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int lpc32xx_write_page_lowlevel(struct nand_chip *chip,
const uint8_t *buf, int oob_required,
int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
const uint8_t *oobbuf = chip->oob_poi;
uint8_t *dma_buf = (uint8_t *)buf;
@@ -551,32 +551,30 @@ static int lpc32xx_write_page_lowlevel(struct mtd_info *mtd,
writeb(0x00, MLC_ECC_AUTO_ENC_REG(host->io_base));
/* Wait for Controller Ready */
- lpc32xx_waitfunc_controller(mtd, chip);
+ lpc32xx_waitfunc_controller(chip);
}
return nand_prog_page_end_op(chip);
}
-static int lpc32xx_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int lpc32xx_read_oob(struct nand_chip *chip, int page)
{
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
/* Read whole page - necessary with MLC controller! */
- lpc32xx_read_page(mtd, chip, host->dummy_buf, 1, page);
+ lpc32xx_read_page(chip, host->dummy_buf, 1, page);
return 0;
}
-static int lpc32xx_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int lpc32xx_write_oob(struct nand_chip *chip, int page)
{
/* None, write_oob conflicts with the automatic LPC MLC ECC decoder! */
return 0;
}
/* Prepares MLC for transfers with H/W ECC enabled: always enabled anyway */
-static void lpc32xx_ecc_enable(struct mtd_info *mtd, int mode)
+static void lpc32xx_ecc_enable(struct nand_chip *chip, int mode)
{
/* Always enabled! */
}
@@ -741,11 +739,11 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
if (res)
goto put_clk;
- nand_chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl;
- nand_chip->dev_ready = lpc32xx_nand_device_ready;
- nand_chip->chip_delay = 25; /* us */
- nand_chip->IO_ADDR_R = MLC_DATA(host->io_base);
- nand_chip->IO_ADDR_W = MLC_DATA(host->io_base);
+ nand_chip->legacy.cmd_ctrl = lpc32xx_nand_cmd_ctrl;
+ nand_chip->legacy.dev_ready = lpc32xx_nand_device_ready;
+ nand_chip->legacy.chip_delay = 25; /* us */
+ nand_chip->legacy.IO_ADDR_R = MLC_DATA(host->io_base);
+ nand_chip->legacy.IO_ADDR_W = MLC_DATA(host->io_base);
/* Init NAND controller */
lpc32xx_nand_setup(host);
@@ -762,7 +760,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
nand_chip->ecc.read_oob = lpc32xx_read_oob;
nand_chip->ecc.strength = 4;
nand_chip->ecc.bytes = 10;
- nand_chip->waitfunc = lpc32xx_waitfunc;
+ nand_chip->legacy.waitfunc = lpc32xx_waitfunc;
nand_chip->options = NAND_NO_SUBPAGE_WRITE;
nand_chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
@@ -802,7 +800,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
* SMALL block or LARGE block.
*/
nand_chip->dummy_controller.ops = &lpc32xx_nand_controller_ops;
- res = nand_scan(mtd, 1);
+ res = nand_scan(nand_chip, 1);
if (res)
goto free_irq;
@@ -839,9 +837,8 @@ free_gpio:
static int lpc32xx_nand_remove(struct platform_device *pdev)
{
struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
- struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
- nand_release(mtd);
+ nand_release(&host->nand_chip);
free_irq(host->irq, host);
if (use_dma)
dma_release_channel(host->dma_chan);
diff --git a/drivers/mtd/nand/raw/lpc32xx_slc.c b/drivers/mtd/nand/raw/lpc32xx_slc.c
index a4e8b7e75135..f2f2cdbb9d04 100644
--- a/drivers/mtd/nand/raw/lpc32xx_slc.c
+++ b/drivers/mtd/nand/raw/lpc32xx_slc.c
@@ -278,11 +278,10 @@ static void lpc32xx_nand_setup(struct lpc32xx_nand_host *host)
/*
* Hardware specific access to control lines
*/
-static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
- unsigned int ctrl)
+static void lpc32xx_nand_cmd_ctrl(struct nand_chip *chip, int cmd,
+ unsigned int ctrl)
{
uint32_t tmp;
- struct nand_chip *chip = mtd_to_nand(mtd);
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
/* Does CE state need to be changed? */
@@ -304,9 +303,8 @@ static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
/*
* Read the Device Ready pin
*/
-static int lpc32xx_nand_device_ready(struct mtd_info *mtd)
+static int lpc32xx_nand_device_ready(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
int rdy = 0;
@@ -337,7 +335,7 @@ static void lpc32xx_wp_disable(struct lpc32xx_nand_host *host)
/*
* Prepares SLC for transfers with H/W ECC enabled
*/
-static void lpc32xx_nand_ecc_enable(struct mtd_info *mtd, int mode)
+static void lpc32xx_nand_ecc_enable(struct nand_chip *chip, int mode)
{
/* Hardware ECC is enabled automatically in hardware as needed */
}
@@ -345,7 +343,7 @@ static void lpc32xx_nand_ecc_enable(struct mtd_info *mtd, int mode)
/*
* Calculates the ECC for the data
*/
-static int lpc32xx_nand_ecc_calculate(struct mtd_info *mtd,
+static int lpc32xx_nand_ecc_calculate(struct nand_chip *chip,
const unsigned char *buf,
unsigned char *code)
{
@@ -359,9 +357,8 @@ static int lpc32xx_nand_ecc_calculate(struct mtd_info *mtd,
/*
* Read a single byte from NAND device
*/
-static uint8_t lpc32xx_nand_read_byte(struct mtd_info *mtd)
+static uint8_t lpc32xx_nand_read_byte(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
return (uint8_t)readl(SLC_DATA(host->io_base));
@@ -370,9 +367,8 @@ static uint8_t lpc32xx_nand_read_byte(struct mtd_info *mtd)
/*
* Simple device read without ECC
*/
-static void lpc32xx_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void lpc32xx_nand_read_buf(struct nand_chip *chip, u_char *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
/* Direct device read with no ECC */
@@ -383,9 +379,9 @@ static void lpc32xx_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
/*
* Simple device write without ECC
*/
-static void lpc32xx_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+static void lpc32xx_nand_write_buf(struct nand_chip *chip, const uint8_t *buf,
+ int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
/* Direct device write with no ECC */
@@ -396,18 +392,20 @@ static void lpc32xx_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int
/*
* Read the OOB data from the device without ECC using FIFO method
*/
-static int lpc32xx_nand_read_oob_syndrome(struct mtd_info *mtd,
- struct nand_chip *chip, int page)
+static int lpc32xx_nand_read_oob_syndrome(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
return nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
}
/*
* Write the OOB data to the device without ECC using FIFO method
*/
-static int lpc32xx_nand_write_oob_syndrome(struct mtd_info *mtd,
- struct nand_chip *chip, int page)
+static int lpc32xx_nand_write_oob_syndrome(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
return nand_prog_page_op(chip, page, mtd->writesize, chip->oob_poi,
mtd->oobsize);
}
@@ -610,10 +608,10 @@ static int lpc32xx_xfer(struct mtd_info *mtd, uint8_t *buf, int eccsubpages,
* Read the data and OOB data from the device, use ECC correction with the
* data, disable ECC for the OOB data
*/
-static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd,
- struct nand_chip *chip, uint8_t *buf,
+static int lpc32xx_nand_read_page_syndrome(struct nand_chip *chip, uint8_t *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
struct mtd_oob_region oobregion = { };
int stat, i, status, error;
@@ -626,7 +624,7 @@ static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd,
status = lpc32xx_xfer(mtd, buf, chip->ecc.steps, 1);
/* Get OOB data */
- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize);
/* Convert to stored ECC format */
lpc32xx_slc_ecc_copy(tmpecc, (uint32_t *) host->ecc_buf, chip->ecc.steps);
@@ -639,7 +637,7 @@ static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd,
oobecc = chip->oob_poi + oobregion.offset;
for (i = 0; i < chip->ecc.steps; i++) {
- stat = chip->ecc.correct(mtd, buf, oobecc,
+ stat = chip->ecc.correct(chip, buf, oobecc,
&tmpecc[i * chip->ecc.bytes]);
if (stat < 0)
mtd->ecc_stats.failed++;
@@ -657,17 +655,18 @@ static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd,
* Read the data and OOB data from the device, no ECC correction with the
* data or OOB data
*/
-static int lpc32xx_nand_read_page_raw_syndrome(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int lpc32xx_nand_read_page_raw_syndrome(struct nand_chip *chip,
uint8_t *buf, int oob_required,
int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
/* Issue read command */
nand_read_page_op(chip, page, 0, NULL, 0);
/* Raw reads can just use the FIFO interface */
- chip->read_buf(mtd, buf, chip->ecc.size * chip->ecc.steps);
- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->legacy.read_buf(chip, buf, chip->ecc.size * chip->ecc.steps);
+ chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize);
return 0;
}
@@ -676,11 +675,11 @@ static int lpc32xx_nand_read_page_raw_syndrome(struct mtd_info *mtd,
* Write the data and OOB data to the device, use ECC with the data,
* disable ECC for the OOB data
*/
-static int lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int lpc32xx_nand_write_page_syndrome(struct nand_chip *chip,
const uint8_t *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
struct mtd_oob_region oobregion = { };
uint8_t *pb;
@@ -705,7 +704,7 @@ static int lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd,
lpc32xx_slc_ecc_copy(pb, (uint32_t *)host->ecc_buf, chip->ecc.steps);
/* Write ECC data to device */
- chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize);
return nand_prog_page_end_op(chip);
}
@@ -714,15 +713,16 @@ static int lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd,
* Write the data and OOB data to the device, no ECC correction with the
* data or OOB data
*/
-static int lpc32xx_nand_write_page_raw_syndrome(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int lpc32xx_nand_write_page_raw_syndrome(struct nand_chip *chip,
const uint8_t *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
/* Raw writes can just use the FIFO interface */
nand_prog_page_begin_op(chip, page, 0, buf,
chip->ecc.size * chip->ecc.steps);
- chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize);
return nand_prog_page_end_op(chip);
}
@@ -878,11 +878,11 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
goto enable_wp;
/* Set NAND IO addresses and command/ready functions */
- chip->IO_ADDR_R = SLC_DATA(host->io_base);
- chip->IO_ADDR_W = SLC_DATA(host->io_base);
- chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl;
- chip->dev_ready = lpc32xx_nand_device_ready;
- chip->chip_delay = 20; /* 20us command delay time */
+ chip->legacy.IO_ADDR_R = SLC_DATA(host->io_base);
+ chip->legacy.IO_ADDR_W = SLC_DATA(host->io_base);
+ chip->legacy.cmd_ctrl = lpc32xx_nand_cmd_ctrl;
+ chip->legacy.dev_ready = lpc32xx_nand_device_ready;
+ chip->legacy.chip_delay = 20; /* 20us command delay time */
/* Init NAND controller */
lpc32xx_nand_setup(host);
@@ -891,9 +891,9 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
/* NAND callbacks for LPC32xx SLC hardware */
chip->ecc.mode = NAND_ECC_HW_SYNDROME;
- chip->read_byte = lpc32xx_nand_read_byte;
- chip->read_buf = lpc32xx_nand_read_buf;
- chip->write_buf = lpc32xx_nand_write_buf;
+ chip->legacy.read_byte = lpc32xx_nand_read_byte;
+ chip->legacy.read_buf = lpc32xx_nand_read_buf;
+ chip->legacy.write_buf = lpc32xx_nand_write_buf;
chip->ecc.read_page_raw = lpc32xx_nand_read_page_raw_syndrome;
chip->ecc.read_page = lpc32xx_nand_read_page_syndrome;
chip->ecc.write_page_raw = lpc32xx_nand_write_page_raw_syndrome;
@@ -925,7 +925,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
/* Find NAND device */
chip->dummy_controller.ops = &lpc32xx_nand_controller_ops;
- res = nand_scan(mtd, 1);
+ res = nand_scan(chip, 1);
if (res)
goto release_dma;
@@ -956,9 +956,8 @@ static int lpc32xx_nand_remove(struct platform_device *pdev)
{
uint32_t tmp;
struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
- struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
- nand_release(mtd);
+ nand_release(&host->nand_chip);
dma_release_channel(host->dma_chan);
/* Force CE high */
diff --git a/drivers/mtd/nand/raw/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c
index bc2ef5209783..650f2b490a05 100644
--- a/drivers/mtd/nand/raw/marvell_nand.c
+++ b/drivers/mtd/nand/raw/marvell_nand.c
@@ -5,6 +5,73 @@
* Copyright (C) 2017 Marvell
* Author: Miquel RAYNAL <miquel.raynal@free-electrons.com>
*
+ *
+ * This NAND controller driver handles two versions of the hardware,
+ * one is called NFCv1 and is available on PXA SoCs and the other is
+ * called NFCv2 and is available on Armada SoCs.
+ *
+ * The main visible difference is that NFCv1 only has Hamming ECC
+ * capabilities, while NFCv2 also embeds a BCH ECC engine. Also, DMA
+ * is not used with NFCv2.
+ *
+ * The ECC layouts are depicted in details in Marvell AN-379, but here
+ * is a brief description.
+ *
+ * When using Hamming, the data is split in 512B chunks (either 1, 2
+ * or 4) and each chunk will have its own ECC "digest" of 6B at the
+ * beginning of the OOB area and eventually the remaining free OOB
+ * bytes (also called "spare" bytes in the driver). This engine
+ * corrects up to 1 bit per chunk and detects reliably an error if
+ * there are at most 2 bitflips. Here is the page layout used by the
+ * controller when Hamming is chosen:
+ *
+ * +-------------------------------------------------------------+
+ * | Data 1 | ... | Data N | ECC 1 | ... | ECCN | Free OOB bytes |
+ * +-------------------------------------------------------------+
+ *
+ * When using the BCH engine, there are N identical (data + free OOB +
+ * ECC) sections and potentially an extra one to deal with
+ * configurations where the chosen (data + free OOB + ECC) sizes do
+ * not align with the page (data + OOB) size. ECC bytes are always
+ * 30B per ECC chunk. Here is the page layout used by the controller
+ * when BCH is chosen:
+ *
+ * +-----------------------------------------
+ * | Data 1 | Free OOB bytes 1 | ECC 1 | ...
+ * +-----------------------------------------
+ *
+ * -------------------------------------------
+ * ... | Data N | Free OOB bytes N | ECC N |
+ * -------------------------------------------
+ *
+ * --------------------------------------------+
+ * Last Data | Last Free OOB bytes | Last ECC |
+ * --------------------------------------------+
+ *
+ * In both cases, the layout seen by the user is always: all data
+ * first, then all free OOB bytes and finally all ECC bytes. With BCH,
+ * ECC bytes are 30B long and are padded with 0xFF to align on 32
+ * bytes.
+ *
+ * The controller has certain limitations that are handled by the
+ * driver:
+ * - It can only read 2k at a time. To overcome this limitation, the
+ * driver issues data cycles on the bus, without issuing new
+ * CMD + ADDR cycles. The Marvell term is "naked" operations.
+ * - The ECC strength in BCH mode cannot be tuned. It is fixed 16
+ * bits. What can be tuned is the ECC block size as long as it
+ * stays between 512B and 2kiB. It's usually chosen based on the
+ * chip ECC requirements. For instance, using 2kiB ECC chunks
+ * provides 4b/512B correctability.
+ * - The controller will always treat data bytes, free OOB bytes
+ * and ECC bytes in that order, no matter what the real layout is
+ * (which is usually all data then all OOB bytes). The
+ * marvell_nfc_layouts array below contains the currently
+ * supported layouts.
+ * - Because of these weird layouts, the Bad Block Markers can be
+ * located in data section. In this case, the NAND_BBT_NO_OOB_BBM
+ * option must be set to prevent scanning/writing bad block
+ * markers.
*/
#include <linux/module.h>
@@ -217,8 +284,11 @@ static const struct marvell_hw_ecc_layout marvell_nfc_layouts[] = {
MARVELL_LAYOUT( 512, 512, 1, 1, 1, 512, 8, 8, 0, 0, 0),
MARVELL_LAYOUT( 2048, 512, 1, 1, 1, 2048, 40, 24, 0, 0, 0),
MARVELL_LAYOUT( 2048, 512, 4, 1, 1, 2048, 32, 30, 0, 0, 0),
+ MARVELL_LAYOUT( 2048, 512, 8, 2, 1, 1024, 0, 30,1024,32, 30),
MARVELL_LAYOUT( 4096, 512, 4, 2, 2, 2048, 32, 30, 0, 0, 0),
MARVELL_LAYOUT( 4096, 512, 8, 5, 4, 1024, 0, 30, 0, 64, 30),
+ MARVELL_LAYOUT( 8192, 512, 4, 4, 4, 2048, 0, 30, 0, 0, 0),
+ MARVELL_LAYOUT( 8192, 512, 8, 9, 8, 1024, 0, 30, 0, 160, 30),
};
/**
@@ -634,9 +704,8 @@ static int marvell_nfc_wait_op(struct nand_chip *chip, unsigned int timeout_ms)
return 0;
}
-static void marvell_nfc_select_chip(struct mtd_info *mtd, int die_nr)
+static void marvell_nfc_select_chip(struct nand_chip *chip, int die_nr)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
u32 ndcr_generic;
@@ -686,7 +755,7 @@ static irqreturn_t marvell_nfc_isr(int irq, void *dev_id)
marvell_nfc_disable_int(nfc, st & NDCR_ALL_INT);
- if (!(st & (NDSR_RDDREQ | NDSR_WRDREQ | NDSR_WRCMDREQ)))
+ if (st & (NDSR_RDY(0) | NDSR_RDY(1)))
complete(&nfc->complete);
return IRQ_HANDLED;
@@ -959,18 +1028,15 @@ static int marvell_nfc_hw_ecc_hmg_do_read_page(struct nand_chip *chip,
return ret;
}
-static int marvell_nfc_hw_ecc_hmg_read_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip, u8 *buf,
+static int marvell_nfc_hw_ecc_hmg_read_page_raw(struct nand_chip *chip, u8 *buf,
int oob_required, int page)
{
return marvell_nfc_hw_ecc_hmg_do_read_page(chip, buf, chip->oob_poi,
true, page);
}
-static int marvell_nfc_hw_ecc_hmg_read_page(struct mtd_info *mtd,
- struct nand_chip *chip,
- u8 *buf, int oob_required,
- int page)
+static int marvell_nfc_hw_ecc_hmg_read_page(struct nand_chip *chip, u8 *buf,
+ int oob_required, int page)
{
const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
unsigned int full_sz = lt->data_bytes + lt->spare_bytes + lt->ecc_bytes;
@@ -1008,8 +1074,7 @@ static int marvell_nfc_hw_ecc_hmg_read_page(struct mtd_info *mtd,
* it appears before the ECC bytes when reading), the ->read_oob_raw() function
* also stands for ->read_oob().
*/
-static int marvell_nfc_hw_ecc_hmg_read_oob_raw(struct mtd_info *mtd,
- struct nand_chip *chip, int page)
+static int marvell_nfc_hw_ecc_hmg_read_oob_raw(struct nand_chip *chip, int page)
{
/* Invalidate page cache */
chip->pagebuf = -1;
@@ -1073,8 +1138,7 @@ static int marvell_nfc_hw_ecc_hmg_do_write_page(struct nand_chip *chip,
return ret;
}
-static int marvell_nfc_hw_ecc_hmg_write_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int marvell_nfc_hw_ecc_hmg_write_page_raw(struct nand_chip *chip,
const u8 *buf,
int oob_required, int page)
{
@@ -1082,8 +1146,7 @@ static int marvell_nfc_hw_ecc_hmg_write_page_raw(struct mtd_info *mtd,
true, page);
}
-static int marvell_nfc_hw_ecc_hmg_write_page(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int marvell_nfc_hw_ecc_hmg_write_page(struct nand_chip *chip,
const u8 *buf,
int oob_required, int page)
{
@@ -1102,10 +1165,11 @@ static int marvell_nfc_hw_ecc_hmg_write_page(struct mtd_info *mtd,
* it appears before the ECC bytes when reading), the ->write_oob_raw() function
* also stands for ->write_oob().
*/
-static int marvell_nfc_hw_ecc_hmg_write_oob_raw(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int marvell_nfc_hw_ecc_hmg_write_oob_raw(struct nand_chip *chip,
int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
/* Invalidate page cache */
chip->pagebuf = -1;
@@ -1116,10 +1180,10 @@ static int marvell_nfc_hw_ecc_hmg_write_oob_raw(struct mtd_info *mtd,
}
/* BCH read helpers */
-static int marvell_nfc_hw_ecc_bch_read_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip, u8 *buf,
+static int marvell_nfc_hw_ecc_bch_read_page_raw(struct nand_chip *chip, u8 *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
u8 *oob = chip->oob_poi;
int chunk_size = lt->data_bytes + lt->spare_bytes + lt->ecc_bytes;
@@ -1228,17 +1292,17 @@ static void marvell_nfc_hw_ecc_bch_read_chunk(struct nand_chip *chip, int chunk,
}
}
-static int marvell_nfc_hw_ecc_bch_read_page(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int marvell_nfc_hw_ecc_bch_read_page(struct nand_chip *chip,
u8 *buf, int oob_required,
int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
- int data_len = lt->data_bytes, spare_len = lt->spare_bytes, ecc_len;
- u8 *data = buf, *spare = chip->oob_poi, *ecc;
+ int data_len = lt->data_bytes, spare_len = lt->spare_bytes;
+ u8 *data = buf, *spare = chip->oob_poi;
int max_bitflips = 0;
u32 failure_mask = 0;
- int chunk, ecc_offset_in_page, ret;
+ int chunk, ret;
/*
* With BCH, OOB is not fully used (and thus not read entirely), not
@@ -1279,73 +1343,98 @@ static int marvell_nfc_hw_ecc_bch_read_page(struct mtd_info *mtd,
* the controller in normal mode and must be re-read in raw mode. To
* avoid dropping the performances, we prefer not to include them. The
* user should re-read the page in raw mode if ECC bytes are required.
+ */
+
+ /*
+ * In case there is any subpage read error reported by ->correct(), we
+ * usually re-read only ECC bytes in raw mode and check if the whole
+ * page is empty. In this case, it is normal that the ECC check failed
+ * and we just ignore the error.
*
- * However, for any subpage read error reported by ->correct(), the ECC
- * bytes must be read in raw mode and the full subpage must be checked
- * to see if it is entirely empty of if there was an actual error.
+ * However, it has been empirically observed that for some layouts (e.g
+ * 2k page, 8b strength per 512B chunk), the controller tries to correct
+ * bits and may create itself bitflips in the erased area. To overcome
+ * this strange behavior, the whole page is re-read in raw mode, not
+ * only the ECC bytes.
*/
for (chunk = 0; chunk < lt->nchunks; chunk++) {
+ int data_off_in_page, spare_off_in_page, ecc_off_in_page;
+ int data_off, spare_off, ecc_off;
+ int data_len, spare_len, ecc_len;
+
/* No failure reported for this chunk, move to the next one */
if (!(failure_mask & BIT(chunk)))
continue;
- /* Derive ECC bytes positions (in page/buffer) and length */
- ecc = chip->oob_poi +
- (lt->full_chunk_cnt * lt->spare_bytes) +
- lt->last_spare_bytes +
- (chunk * ALIGN(lt->ecc_bytes, 32));
- ecc_offset_in_page =
- (chunk * (lt->data_bytes + lt->spare_bytes +
- lt->ecc_bytes)) +
- (chunk < lt->full_chunk_cnt ?
- lt->data_bytes + lt->spare_bytes :
- lt->last_data_bytes + lt->last_spare_bytes);
- ecc_len = chunk < lt->full_chunk_cnt ?
- lt->ecc_bytes : lt->last_ecc_bytes;
-
- /* Do the actual raw read of the ECC bytes */
- nand_change_read_column_op(chip, ecc_offset_in_page,
- ecc, ecc_len, false);
-
- /* Derive data/spare bytes positions (in buffer) and length */
- data = buf + (chunk * lt->data_bytes);
- data_len = chunk < lt->full_chunk_cnt ?
- lt->data_bytes : lt->last_data_bytes;
- spare = chip->oob_poi + (chunk * (lt->spare_bytes +
- lt->ecc_bytes));
- spare_len = chunk < lt->full_chunk_cnt ?
- lt->spare_bytes : lt->last_spare_bytes;
+ data_off_in_page = chunk * (lt->data_bytes + lt->spare_bytes +
+ lt->ecc_bytes);
+ spare_off_in_page = data_off_in_page +
+ (chunk < lt->full_chunk_cnt ? lt->data_bytes :
+ lt->last_data_bytes);
+ ecc_off_in_page = spare_off_in_page +
+ (chunk < lt->full_chunk_cnt ? lt->spare_bytes :
+ lt->last_spare_bytes);
+
+ data_off = chunk * lt->data_bytes;
+ spare_off = chunk * lt->spare_bytes;
+ ecc_off = (lt->full_chunk_cnt * lt->spare_bytes) +
+ lt->last_spare_bytes +
+ (chunk * (lt->ecc_bytes + 2));
+
+ data_len = chunk < lt->full_chunk_cnt ? lt->data_bytes :
+ lt->last_data_bytes;
+ spare_len = chunk < lt->full_chunk_cnt ? lt->spare_bytes :
+ lt->last_spare_bytes;
+ ecc_len = chunk < lt->full_chunk_cnt ? lt->ecc_bytes :
+ lt->last_ecc_bytes;
+
+ /*
+ * Only re-read the ECC bytes, unless we are using the 2k/8b
+ * layout which is buggy in the sense that the ECC engine will
+ * try to correct data bytes anyway, creating bitflips. In this
+ * case, re-read the entire page.
+ */
+ if (lt->writesize == 2048 && lt->strength == 8) {
+ nand_change_read_column_op(chip, data_off_in_page,
+ buf + data_off, data_len,
+ false);
+ nand_change_read_column_op(chip, spare_off_in_page,
+ chip->oob_poi + spare_off, spare_len,
+ false);
+ }
+
+ nand_change_read_column_op(chip, ecc_off_in_page,
+ chip->oob_poi + ecc_off, ecc_len,
+ false);
/* Check the entire chunk (data + spare + ecc) for emptyness */
- marvell_nfc_check_empty_chunk(chip, data, data_len, spare,
- spare_len, ecc, ecc_len,
+ marvell_nfc_check_empty_chunk(chip, buf + data_off, data_len,
+ chip->oob_poi + spare_off, spare_len,
+ chip->oob_poi + ecc_off, ecc_len,
&max_bitflips);
}
return max_bitflips;
}
-static int marvell_nfc_hw_ecc_bch_read_oob_raw(struct mtd_info *mtd,
- struct nand_chip *chip, int page)
+static int marvell_nfc_hw_ecc_bch_read_oob_raw(struct nand_chip *chip, int page)
{
/* Invalidate page cache */
chip->pagebuf = -1;
- return chip->ecc.read_page_raw(mtd, chip, chip->data_buf, true, page);
+ return chip->ecc.read_page_raw(chip, chip->data_buf, true, page);
}
-static int marvell_nfc_hw_ecc_bch_read_oob(struct mtd_info *mtd,
- struct nand_chip *chip, int page)
+static int marvell_nfc_hw_ecc_bch_read_oob(struct nand_chip *chip, int page)
{
/* Invalidate page cache */
chip->pagebuf = -1;
- return chip->ecc.read_page(mtd, chip, chip->data_buf, true, page);
+ return chip->ecc.read_page(chip, chip->data_buf, true, page);
}
/* BCH write helpers */
-static int marvell_nfc_hw_ecc_bch_write_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int marvell_nfc_hw_ecc_bch_write_page_raw(struct nand_chip *chip,
const u8 *buf,
int oob_required, int page)
{
@@ -1458,11 +1547,11 @@ marvell_nfc_hw_ecc_bch_write_chunk(struct nand_chip *chip, int chunk,
return 0;
}
-static int marvell_nfc_hw_ecc_bch_write_page(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int marvell_nfc_hw_ecc_bch_write_page(struct nand_chip *chip,
const u8 *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
const u8 *data = buf;
const u8 *spare = chip->oob_poi;
@@ -1507,27 +1596,29 @@ static int marvell_nfc_hw_ecc_bch_write_page(struct mtd_info *mtd,
return 0;
}
-static int marvell_nfc_hw_ecc_bch_write_oob_raw(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int marvell_nfc_hw_ecc_bch_write_oob_raw(struct nand_chip *chip,
int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
/* Invalidate page cache */
chip->pagebuf = -1;
memset(chip->data_buf, 0xFF, mtd->writesize);
- return chip->ecc.write_page_raw(mtd, chip, chip->data_buf, true, page);
+ return chip->ecc.write_page_raw(chip, chip->data_buf, true, page);
}
-static int marvell_nfc_hw_ecc_bch_write_oob(struct mtd_info *mtd,
- struct nand_chip *chip, int page)
+static int marvell_nfc_hw_ecc_bch_write_oob(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
/* Invalidate page cache */
chip->pagebuf = -1;
memset(chip->data_buf, 0xFF, mtd->writesize);
- return chip->ecc.write_page(mtd, chip, chip->data_buf, true, page);
+ return chip->ecc.write_page(chip, chip->data_buf, true, page);
}
/* NAND framework ->exec_op() hooks and related helpers */
@@ -2097,6 +2188,16 @@ static int marvell_nand_hw_ecc_ctrl_init(struct mtd_info *mtd,
return -ENOTSUPP;
}
+ /* Special care for the layout 2k/8-bit/512B */
+ if (l->writesize == 2048 && l->strength == 8) {
+ if (mtd->oobsize < 128) {
+ dev_err(nfc->dev, "Requested layout needs at least 128 OOB bytes\n");
+ return -ENOTSUPP;
+ } else {
+ chip->bbt_options |= NAND_BBT_NO_OOB_BBM;
+ }
+ }
+
mtd_set_ooblayout(mtd, &marvell_nand_ooblayout_ops);
ecc->steps = l->nchunks;
ecc->size = l->data_bytes;
@@ -2192,11 +2293,10 @@ static struct nand_bbt_descr bbt_mirror_descr = {
.pattern = bbt_mirror_pattern
};
-static int marvell_nfc_setup_data_interface(struct mtd_info *mtd, int chipnr,
+static int marvell_nfc_setup_data_interface(struct nand_chip *chip, int chipnr,
const struct nand_data_interface
*conf)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
unsigned int period_ns = 1000000000 / clk_get_rate(nfc->core_clk) * 2;
@@ -2540,7 +2640,7 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
chip->options |= NAND_BUSWIDTH_AUTO;
- ret = nand_scan(mtd, marvell_nand->nsels);
+ ret = nand_scan(chip, marvell_nand->nsels);
if (ret) {
dev_err(dev, "could not scan the nand chip\n");
return ret;
@@ -2553,7 +2653,7 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
ret = mtd_device_register(mtd, NULL, 0);
if (ret) {
dev_err(dev, "failed to register mtd device: %d\n", ret);
- nand_release(mtd);
+ nand_release(chip);
return ret;
}
@@ -2608,7 +2708,7 @@ static void marvell_nand_chips_cleanup(struct marvell_nfc *nfc)
struct marvell_nand_chip *entry, *temp;
list_for_each_entry_safe(entry, temp, &nfc->chips, node) {
- nand_release(nand_to_mtd(&entry->chip));
+ nand_release(&entry->chip);
list_del(&entry->node);
}
}
@@ -2699,24 +2799,23 @@ static int marvell_nfc_init(struct marvell_nfc *nfc)
struct regmap *sysctrl_base =
syscon_regmap_lookup_by_phandle(np,
"marvell,system-controller");
- u32 reg;
if (IS_ERR(sysctrl_base))
return PTR_ERR(sysctrl_base);
- reg = GENCONF_SOC_DEVICE_MUX_NFC_EN |
- GENCONF_SOC_DEVICE_MUX_ECC_CLK_RST |
- GENCONF_SOC_DEVICE_MUX_ECC_CORE_RST |
- GENCONF_SOC_DEVICE_MUX_NFC_INT_EN;
- regmap_write(sysctrl_base, GENCONF_SOC_DEVICE_MUX, reg);
+ regmap_write(sysctrl_base, GENCONF_SOC_DEVICE_MUX,
+ GENCONF_SOC_DEVICE_MUX_NFC_EN |
+ GENCONF_SOC_DEVICE_MUX_ECC_CLK_RST |
+ GENCONF_SOC_DEVICE_MUX_ECC_CORE_RST |
+ GENCONF_SOC_DEVICE_MUX_NFC_INT_EN);
- regmap_read(sysctrl_base, GENCONF_CLK_GATING_CTRL, &reg);
- reg |= GENCONF_CLK_GATING_CTRL_ND_GATE;
- regmap_write(sysctrl_base, GENCONF_CLK_GATING_CTRL, reg);
+ regmap_update_bits(sysctrl_base, GENCONF_CLK_GATING_CTRL,
+ GENCONF_CLK_GATING_CTRL_ND_GATE,
+ GENCONF_CLK_GATING_CTRL_ND_GATE);
- regmap_read(sysctrl_base, GENCONF_ND_CLK_CTRL, &reg);
- reg |= GENCONF_ND_CLK_CTRL_EN;
- regmap_write(sysctrl_base, GENCONF_ND_CLK_CTRL, reg);
+ regmap_update_bits(sysctrl_base, GENCONF_ND_CLK_CTRL,
+ GENCONF_ND_CLK_CTRL_EN,
+ GENCONF_ND_CLK_CTRL_EN);
}
/* Configure the DMA if appropriate */
diff --git a/drivers/mtd/nand/raw/mpc5121_nfc.c b/drivers/mtd/nand/raw/mpc5121_nfc.c
index 6d1740d54e0d..86a0aabe08df 100644
--- a/drivers/mtd/nand/raw/mpc5121_nfc.c
+++ b/drivers/mtd/nand/raw/mpc5121_nfc.c
@@ -263,8 +263,10 @@ static void mpc5121_nfc_addr_cycle(struct mtd_info *mtd, int column, int page)
}
/* Control chip select signals */
-static void mpc5121_nfc_select_chip(struct mtd_info *mtd, int chip)
+static void mpc5121_nfc_select_chip(struct nand_chip *nand, int chip)
{
+ struct mtd_info *mtd = nand_to_mtd(nand);
+
if (chip < 0) {
nfc_clear(mtd, NFC_CONFIG1, NFC_CE);
return;
@@ -299,9 +301,9 @@ static int ads5121_chipselect_init(struct mtd_info *mtd)
}
/* Control chips select signal on ADS5121 board */
-static void ads5121_select_chip(struct mtd_info *mtd, int chip)
+static void ads5121_select_chip(struct nand_chip *nand, int chip)
{
- struct nand_chip *nand = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(nand);
struct mpc5121_nfc_prv *prv = nand_get_controller_data(nand);
u8 v;
@@ -309,16 +311,16 @@ static void ads5121_select_chip(struct mtd_info *mtd, int chip)
v |= 0x0F;
if (chip >= 0) {
- mpc5121_nfc_select_chip(mtd, 0);
+ mpc5121_nfc_select_chip(nand, 0);
v &= ~(1 << chip);
} else
- mpc5121_nfc_select_chip(mtd, -1);
+ mpc5121_nfc_select_chip(nand, -1);
out_8(prv->csreg, v);
}
/* Read NAND Ready/Busy signal */
-static int mpc5121_nfc_dev_ready(struct mtd_info *mtd)
+static int mpc5121_nfc_dev_ready(struct nand_chip *nand)
{
/*
* NFC handles ready/busy signal internally. Therefore, this function
@@ -328,10 +330,10 @@ static int mpc5121_nfc_dev_ready(struct mtd_info *mtd)
}
/* Write command to NAND flash */
-static void mpc5121_nfc_command(struct mtd_info *mtd, unsigned command,
- int column, int page)
+static void mpc5121_nfc_command(struct nand_chip *chip, unsigned command,
+ int column, int page)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
prv->column = (column >= 0) ? column : 0;
@@ -362,7 +364,7 @@ static void mpc5121_nfc_command(struct mtd_info *mtd, unsigned command,
break;
case NAND_CMD_SEQIN:
- mpc5121_nfc_command(mtd, NAND_CMD_READ0, column, page);
+ mpc5121_nfc_command(chip, NAND_CMD_READ0, column, page);
column = 0;
break;
@@ -493,34 +495,24 @@ static void mpc5121_nfc_buf_copy(struct mtd_info *mtd, u_char *buf, int len,
}
/* Read data from NFC buffers */
-static void mpc5121_nfc_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void mpc5121_nfc_read_buf(struct nand_chip *chip, u_char *buf, int len)
{
- mpc5121_nfc_buf_copy(mtd, buf, len, 0);
+ mpc5121_nfc_buf_copy(nand_to_mtd(chip), buf, len, 0);
}
/* Write data to NFC buffers */
-static void mpc5121_nfc_write_buf(struct mtd_info *mtd,
- const u_char *buf, int len)
+static void mpc5121_nfc_write_buf(struct nand_chip *chip, const u_char *buf,
+ int len)
{
- mpc5121_nfc_buf_copy(mtd, (u_char *)buf, len, 1);
+ mpc5121_nfc_buf_copy(nand_to_mtd(chip), (u_char *)buf, len, 1);
}
/* Read byte from NFC buffers */
-static u8 mpc5121_nfc_read_byte(struct mtd_info *mtd)
+static u8 mpc5121_nfc_read_byte(struct nand_chip *chip)
{
u8 tmp;
- mpc5121_nfc_read_buf(mtd, &tmp, sizeof(tmp));
-
- return tmp;
-}
-
-/* Read word from NFC buffers */
-static u16 mpc5121_nfc_read_word(struct mtd_info *mtd)
-{
- u16 tmp;
-
- mpc5121_nfc_read_buf(mtd, (u_char *)&tmp, sizeof(tmp));
+ mpc5121_nfc_read_buf(chip, &tmp, sizeof(tmp));
return tmp;
}
@@ -700,15 +692,14 @@ static int mpc5121_nfc_probe(struct platform_device *op)
}
mtd->name = "MPC5121 NAND";
- chip->dev_ready = mpc5121_nfc_dev_ready;
- chip->cmdfunc = mpc5121_nfc_command;
- chip->read_byte = mpc5121_nfc_read_byte;
- chip->read_word = mpc5121_nfc_read_word;
- chip->read_buf = mpc5121_nfc_read_buf;
- chip->write_buf = mpc5121_nfc_write_buf;
+ chip->legacy.dev_ready = mpc5121_nfc_dev_ready;
+ chip->legacy.cmdfunc = mpc5121_nfc_command;
+ chip->legacy.read_byte = mpc5121_nfc_read_byte;
+ chip->legacy.read_buf = mpc5121_nfc_read_buf;
+ chip->legacy.write_buf = mpc5121_nfc_write_buf;
chip->select_chip = mpc5121_nfc_select_chip;
- chip->set_features = nand_get_set_features_notsupp;
- chip->get_features = nand_get_set_features_notsupp;
+ chip->legacy.set_features = nand_get_set_features_notsupp;
+ chip->legacy.get_features = nand_get_set_features_notsupp;
chip->bbt_options = NAND_BBT_USE_FLASH;
chip->ecc.mode = NAND_ECC_SOFT;
chip->ecc.algo = NAND_ECC_HAMMING;
@@ -778,7 +769,7 @@ static int mpc5121_nfc_probe(struct platform_device *op)
}
/* Detect NAND chips */
- retval = nand_scan(mtd, be32_to_cpup(chips_no));
+ retval = nand_scan(chip, be32_to_cpup(chips_no));
if (retval) {
dev_err(dev, "NAND Flash not found !\n");
goto error;
@@ -828,7 +819,7 @@ static int mpc5121_nfc_remove(struct platform_device *op)
struct device *dev = &op->dev;
struct mtd_info *mtd = dev_get_drvdata(dev);
- nand_release(mtd);
+ nand_release(mtd_to_nand(mtd));
mpc5121_nfc_free(dev, mtd);
return 0;
diff --git a/drivers/mtd/nand/raw/mtk_nand.c b/drivers/mtd/nand/raw/mtk_nand.c
index 57b5ed1699e3..2bb0df1b7244 100644
--- a/drivers/mtd/nand/raw/mtk_nand.c
+++ b/drivers/mtd/nand/raw/mtk_nand.c
@@ -389,23 +389,22 @@ static int mtk_nfc_hw_runtime_config(struct mtd_info *mtd)
return 0;
}
-static void mtk_nfc_select_chip(struct mtd_info *mtd, int chip)
+static void mtk_nfc_select_chip(struct nand_chip *nand, int chip)
{
- struct nand_chip *nand = mtd_to_nand(mtd);
struct mtk_nfc *nfc = nand_get_controller_data(nand);
struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(nand);
if (chip < 0)
return;
- mtk_nfc_hw_runtime_config(mtd);
+ mtk_nfc_hw_runtime_config(nand_to_mtd(nand));
nfi_writel(nfc, mtk_nand->sels[chip], NFI_CSEL);
}
-static int mtk_nfc_dev_ready(struct mtd_info *mtd)
+static int mtk_nfc_dev_ready(struct nand_chip *nand)
{
- struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
+ struct mtk_nfc *nfc = nand_get_controller_data(nand);
if (nfi_readl(nfc, NFI_STA) & STA_BUSY)
return 0;
@@ -413,9 +412,10 @@ static int mtk_nfc_dev_ready(struct mtd_info *mtd)
return 1;
}
-static void mtk_nfc_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
+static void mtk_nfc_cmd_ctrl(struct nand_chip *chip, int dat,
+ unsigned int ctrl)
{
- struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
+ struct mtk_nfc *nfc = nand_get_controller_data(chip);
if (ctrl & NAND_ALE) {
mtk_nfc_send_address(nfc, dat);
@@ -438,9 +438,8 @@ static inline void mtk_nfc_wait_ioready(struct mtk_nfc *nfc)
dev_err(nfc->dev, "data not ready\n");
}
-static inline u8 mtk_nfc_read_byte(struct mtd_info *mtd)
+static inline u8 mtk_nfc_read_byte(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct mtk_nfc *nfc = nand_get_controller_data(chip);
u32 reg;
@@ -467,17 +466,17 @@ static inline u8 mtk_nfc_read_byte(struct mtd_info *mtd)
return nfi_readb(nfc, NFI_DATAR);
}
-static void mtk_nfc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+static void mtk_nfc_read_buf(struct nand_chip *chip, u8 *buf, int len)
{
int i;
for (i = 0; i < len; i++)
- buf[i] = mtk_nfc_read_byte(mtd);
+ buf[i] = mtk_nfc_read_byte(chip);
}
-static void mtk_nfc_write_byte(struct mtd_info *mtd, u8 byte)
+static void mtk_nfc_write_byte(struct nand_chip *chip, u8 byte)
{
- struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
+ struct mtk_nfc *nfc = nand_get_controller_data(chip);
u32 reg;
reg = nfi_readl(nfc, NFI_STA) & NFI_FSM_MASK;
@@ -496,18 +495,18 @@ static void mtk_nfc_write_byte(struct mtd_info *mtd, u8 byte)
nfi_writeb(nfc, byte, NFI_DATAW);
}
-static void mtk_nfc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+static void mtk_nfc_write_buf(struct nand_chip *chip, const u8 *buf, int len)
{
int i;
for (i = 0; i < len; i++)
- mtk_nfc_write_byte(mtd, buf[i]);
+ mtk_nfc_write_byte(chip, buf[i]);
}
-static int mtk_nfc_setup_data_interface(struct mtd_info *mtd, int csline,
+static int mtk_nfc_setup_data_interface(struct nand_chip *chip, int csline,
const struct nand_data_interface *conf)
{
- struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
+ struct mtk_nfc *nfc = nand_get_controller_data(chip);
const struct nand_sdr_timings *timings;
u32 rate, tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt;
@@ -807,27 +806,27 @@ static int mtk_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
return nand_prog_page_end_op(chip);
}
-static int mtk_nfc_write_page_hwecc(struct mtd_info *mtd,
- struct nand_chip *chip, const u8 *buf,
+static int mtk_nfc_write_page_hwecc(struct nand_chip *chip, const u8 *buf,
int oob_on, int page)
{
- return mtk_nfc_write_page(mtd, chip, buf, page, 0);
+ return mtk_nfc_write_page(nand_to_mtd(chip), chip, buf, page, 0);
}
-static int mtk_nfc_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- const u8 *buf, int oob_on, int pg)
+static int mtk_nfc_write_page_raw(struct nand_chip *chip, const u8 *buf,
+ int oob_on, int pg)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct mtk_nfc *nfc = nand_get_controller_data(chip);
mtk_nfc_format_page(mtd, buf);
return mtk_nfc_write_page(mtd, chip, nfc->buffer, pg, 1);
}
-static int mtk_nfc_write_subpage_hwecc(struct mtd_info *mtd,
- struct nand_chip *chip, u32 offset,
+static int mtk_nfc_write_subpage_hwecc(struct nand_chip *chip, u32 offset,
u32 data_len, const u8 *buf,
int oob_on, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct mtk_nfc *nfc = nand_get_controller_data(chip);
int ret;
@@ -839,10 +838,9 @@ static int mtk_nfc_write_subpage_hwecc(struct mtd_info *mtd,
return mtk_nfc_write_page(mtd, chip, nfc->buffer, page, 1);
}
-static int mtk_nfc_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int mtk_nfc_write_oob_std(struct nand_chip *chip, int page)
{
- return mtk_nfc_write_page_raw(mtd, chip, NULL, 1, page);
+ return mtk_nfc_write_page_raw(chip, NULL, 1, page);
}
static int mtk_nfc_update_ecc_stats(struct mtd_info *mtd, u8 *buf, u32 sectors)
@@ -969,23 +967,25 @@ done:
return bitflips;
}
-static int mtk_nfc_read_subpage_hwecc(struct mtd_info *mtd,
- struct nand_chip *chip, u32 off,
+static int mtk_nfc_read_subpage_hwecc(struct nand_chip *chip, u32 off,
u32 len, u8 *p, int pg)
{
- return mtk_nfc_read_subpage(mtd, chip, off, len, p, pg, 0);
+ return mtk_nfc_read_subpage(nand_to_mtd(chip), chip, off, len, p, pg,
+ 0);
}
-static int mtk_nfc_read_page_hwecc(struct mtd_info *mtd,
- struct nand_chip *chip, u8 *p,
- int oob_on, int pg)
+static int mtk_nfc_read_page_hwecc(struct nand_chip *chip, u8 *p, int oob_on,
+ int pg)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
return mtk_nfc_read_subpage(mtd, chip, 0, mtd->writesize, p, pg, 0);
}
-static int mtk_nfc_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- u8 *buf, int oob_on, int page)
+static int mtk_nfc_read_page_raw(struct nand_chip *chip, u8 *buf, int oob_on,
+ int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
struct mtk_nfc *nfc = nand_get_controller_data(chip);
struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
@@ -1011,10 +1011,9 @@ static int mtk_nfc_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
return ret;
}
-static int mtk_nfc_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int mtk_nfc_read_oob_std(struct nand_chip *chip, int page)
{
- return mtk_nfc_read_page_raw(mtd, chip, NULL, 1, page);
+ return mtk_nfc_read_page_raw(chip, NULL, 1, page);
}
static inline void mtk_nfc_hw_init(struct mtk_nfc *nfc)
@@ -1333,13 +1332,13 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
nand_set_controller_data(nand, nfc);
nand->options |= NAND_USE_BOUNCE_BUFFER | NAND_SUBPAGE_READ;
- nand->dev_ready = mtk_nfc_dev_ready;
+ nand->legacy.dev_ready = mtk_nfc_dev_ready;
nand->select_chip = mtk_nfc_select_chip;
- nand->write_byte = mtk_nfc_write_byte;
- nand->write_buf = mtk_nfc_write_buf;
- nand->read_byte = mtk_nfc_read_byte;
- nand->read_buf = mtk_nfc_read_buf;
- nand->cmd_ctrl = mtk_nfc_cmd_ctrl;
+ nand->legacy.write_byte = mtk_nfc_write_byte;
+ nand->legacy.write_buf = mtk_nfc_write_buf;
+ nand->legacy.read_byte = mtk_nfc_read_byte;
+ nand->legacy.read_buf = mtk_nfc_read_buf;
+ nand->legacy.cmd_ctrl = mtk_nfc_cmd_ctrl;
nand->setup_data_interface = mtk_nfc_setup_data_interface;
/* set default mode in case dt entry is missing */
@@ -1365,14 +1364,14 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
mtk_nfc_hw_init(nfc);
- ret = nand_scan(mtd, nsels);
+ ret = nand_scan(nand, nsels);
if (ret)
return ret;
ret = mtd_device_register(mtd, NULL, 0);
if (ret) {
dev_err(dev, "mtd parse partition error\n");
- nand_release(mtd);
+ nand_release(nand);
return ret;
}
@@ -1538,7 +1537,7 @@ static int mtk_nfc_remove(struct platform_device *pdev)
while (!list_empty(&nfc->chips)) {
chip = list_first_entry(&nfc->chips, struct mtk_nfc_nand_chip,
node);
- nand_release(nand_to_mtd(&chip->nand));
+ nand_release(&chip->nand);
list_del(&chip->node);
}
diff --git a/drivers/mtd/nand/raw/mxc_nand.c b/drivers/mtd/nand/raw/mxc_nand.c
index 4c9214dea424..88bd3f6a499c 100644
--- a/drivers/mtd/nand/raw/mxc_nand.c
+++ b/drivers/mtd/nand/raw/mxc_nand.c
@@ -136,8 +136,8 @@ struct mxc_nand_devtype_data {
void (*irq_control)(struct mxc_nand_host *, int);
u32 (*get_ecc_status)(struct mxc_nand_host *);
const struct mtd_ooblayout_ops *ooblayout;
- void (*select_chip)(struct mtd_info *mtd, int chip);
- int (*setup_data_interface)(struct mtd_info *mtd, int csline,
+ void (*select_chip)(struct nand_chip *chip, int cs);
+ int (*setup_data_interface)(struct nand_chip *chip, int csline,
const struct nand_data_interface *conf);
void (*enable_hwecc)(struct nand_chip *chip, bool enable);
@@ -701,7 +701,7 @@ static void mxc_nand_enable_hwecc_v3(struct nand_chip *chip, bool enable)
}
/* This functions is used by upper layer to checks if device is ready */
-static int mxc_nand_dev_ready(struct mtd_info *mtd)
+static int mxc_nand_dev_ready(struct nand_chip *chip)
{
/*
* NFC handles R/B internally. Therefore, this function
@@ -816,8 +816,8 @@ static int mxc_nand_read_page_v2_v3(struct nand_chip *chip, void *buf,
return max_bitflips;
}
-static int mxc_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+static int mxc_nand_read_page(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
struct mxc_nand_host *host = nand_get_controller_data(chip);
void *oob_buf;
@@ -830,8 +830,8 @@ static int mxc_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
return host->devtype_data->read_page(chip, buf, oob_buf, 1, page);
}
-static int mxc_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+static int mxc_nand_read_page_raw(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
struct mxc_nand_host *host = nand_get_controller_data(chip);
void *oob_buf;
@@ -844,8 +844,7 @@ static int mxc_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
return host->devtype_data->read_page(chip, buf, oob_buf, 0, page);
}
-static int mxc_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int mxc_nand_read_oob(struct nand_chip *chip, int page)
{
struct mxc_nand_host *host = nand_get_controller_data(chip);
@@ -874,22 +873,21 @@ static int mxc_nand_write_page(struct nand_chip *chip, const uint8_t *buf,
return 0;
}
-static int mxc_nand_write_page_ecc(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required,
- int page)
+static int mxc_nand_write_page_ecc(struct nand_chip *chip, const uint8_t *buf,
+ int oob_required, int page)
{
return mxc_nand_write_page(chip, buf, true, page);
}
-static int mxc_nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required, int page)
+static int mxc_nand_write_page_raw(struct nand_chip *chip, const uint8_t *buf,
+ int oob_required, int page)
{
return mxc_nand_write_page(chip, buf, false, page);
}
-static int mxc_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int mxc_nand_write_oob(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct mxc_nand_host *host = nand_get_controller_data(chip);
memset(host->data_buf, 0xff, mtd->writesize);
@@ -897,9 +895,8 @@ static int mxc_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
return mxc_nand_write_page(chip, host->data_buf, false, page);
}
-static u_char mxc_nand_read_byte(struct mtd_info *mtd)
+static u_char mxc_nand_read_byte(struct nand_chip *nand_chip)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
uint8_t ret;
@@ -921,25 +918,13 @@ static u_char mxc_nand_read_byte(struct mtd_info *mtd)
return ret;
}
-static uint16_t mxc_nand_read_word(struct mtd_info *mtd)
-{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
- struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
- uint16_t ret;
-
- ret = *(uint16_t *)(host->data_buf + host->buf_start);
- host->buf_start += 2;
-
- return ret;
-}
-
/* Write data of length len to buffer buf. The data to be
* written on NAND Flash is first copied to RAMbuffer. After the Data Input
* Operation by the NFC, the data is written to NAND Flash */
-static void mxc_nand_write_buf(struct mtd_info *mtd,
- const u_char *buf, int len)
+static void mxc_nand_write_buf(struct nand_chip *nand_chip, const u_char *buf,
+ int len)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(nand_chip);
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
u16 col = host->buf_start;
int n = mtd->oobsize + mtd->writesize - col;
@@ -955,9 +940,10 @@ static void mxc_nand_write_buf(struct mtd_info *mtd,
* Flash first the data output cycle is initiated by the NFC, which copies
* the data to RAMbuffer. This data of length len is then copied to buffer buf.
*/
-static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void mxc_nand_read_buf(struct nand_chip *nand_chip, u_char *buf,
+ int len)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(nand_chip);
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
u16 col = host->buf_start;
int n = mtd->oobsize + mtd->writesize - col;
@@ -971,9 +957,8 @@ static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
/* This function is used by upper layer for select and
* deselect of the NAND chip */
-static void mxc_nand_select_chip_v1_v3(struct mtd_info *mtd, int chip)
+static void mxc_nand_select_chip_v1_v3(struct nand_chip *nand_chip, int chip)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
if (chip == -1) {
@@ -992,9 +977,8 @@ static void mxc_nand_select_chip_v1_v3(struct mtd_info *mtd, int chip)
}
}
-static void mxc_nand_select_chip_v2(struct mtd_info *mtd, int chip)
+static void mxc_nand_select_chip_v2(struct nand_chip *nand_chip, int chip)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
if (chip == -1) {
@@ -1155,11 +1139,10 @@ static void preset_v1(struct mtd_info *mtd)
writew(0x4, NFC_V1_V2_WRPROT);
}
-static int mxc_nand_v2_setup_data_interface(struct mtd_info *mtd, int csline,
+static int mxc_nand_v2_setup_data_interface(struct nand_chip *chip, int csline,
const struct nand_data_interface *conf)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
- struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+ struct mxc_nand_host *host = nand_get_controller_data(chip);
int tRC_min_ns, tRC_ps, ret;
unsigned long rate, rate_round;
const struct nand_sdr_timings *timings;
@@ -1349,10 +1332,10 @@ static void preset_v3(struct mtd_info *mtd)
/* Used by the upper layer to write command to NAND Flash for
* different operations to be carried out on NAND Flash */
-static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
- int column, int page_addr)
+static void mxc_nand_command(struct nand_chip *nand_chip, unsigned command,
+ int column, int page_addr)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(nand_chip);
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
dev_dbg(host->dev, "mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n",
@@ -1409,17 +1392,17 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
}
}
-static int mxc_nand_set_features(struct mtd_info *mtd, struct nand_chip *chip,
- int addr, u8 *subfeature_param)
+static int mxc_nand_set_features(struct nand_chip *chip, int addr,
+ u8 *subfeature_param)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
- struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct mxc_nand_host *host = nand_get_controller_data(chip);
int i;
host->buf_start = 0;
for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
- chip->write_byte(mtd, subfeature_param[i]);
+ chip->legacy.write_byte(chip, subfeature_param[i]);
memcpy32_toio(host->main_area0, host->data_buf, mtd->writesize);
host->devtype_data->send_cmd(host, NAND_CMD_SET_FEATURES, false);
@@ -1429,11 +1412,11 @@ static int mxc_nand_set_features(struct mtd_info *mtd, struct nand_chip *chip,
return 0;
}
-static int mxc_nand_get_features(struct mtd_info *mtd, struct nand_chip *chip,
- int addr, u8 *subfeature_param)
+static int mxc_nand_get_features(struct nand_chip *chip, int addr,
+ u8 *subfeature_param)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
- struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct mxc_nand_host *host = nand_get_controller_data(chip);
int i;
host->devtype_data->send_cmd(host, NAND_CMD_GET_FEATURES, false);
@@ -1443,7 +1426,7 @@ static int mxc_nand_get_features(struct mtd_info *mtd, struct nand_chip *chip,
host->buf_start = 0;
for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
- *subfeature_param++ = chip->read_byte(mtd);
+ *subfeature_param++ = chip->legacy.read_byte(chip);
return 0;
}
@@ -1786,18 +1769,17 @@ static int mxcnd_probe(struct platform_device *pdev)
mtd->name = DRIVER_NAME;
/* 50 us command delay time */
- this->chip_delay = 5;
+ this->legacy.chip_delay = 5;
nand_set_controller_data(this, host);
nand_set_flash_node(this, pdev->dev.of_node),
- this->dev_ready = mxc_nand_dev_ready;
- this->cmdfunc = mxc_nand_command;
- this->read_byte = mxc_nand_read_byte;
- this->read_word = mxc_nand_read_word;
- this->write_buf = mxc_nand_write_buf;
- this->read_buf = mxc_nand_read_buf;
- this->set_features = mxc_nand_set_features;
- this->get_features = mxc_nand_get_features;
+ this->legacy.dev_ready = mxc_nand_dev_ready;
+ this->legacy.cmdfunc = mxc_nand_command;
+ this->legacy.read_byte = mxc_nand_read_byte;
+ this->legacy.write_buf = mxc_nand_write_buf;
+ this->legacy.read_buf = mxc_nand_read_buf;
+ this->legacy.set_features = mxc_nand_set_features;
+ this->legacy.get_features = mxc_nand_get_features;
host->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(host->clk))
@@ -1900,7 +1882,7 @@ static int mxcnd_probe(struct platform_device *pdev)
/* Scan the NAND device */
this->dummy_controller.ops = &mxcnd_controller_ops;
- err = nand_scan(mtd, is_imx25_nfc(host) ? 4 : 1);
+ err = nand_scan(this, is_imx25_nfc(host) ? 4 : 1);
if (err)
goto escan;
@@ -1928,7 +1910,7 @@ static int mxcnd_remove(struct platform_device *pdev)
{
struct mxc_nand_host *host = platform_get_drvdata(pdev);
- nand_release(nand_to_mtd(&host->nand));
+ nand_release(&host->nand);
if (host->clk_act)
clk_disable_unprepare(host->clk);
diff --git a/drivers/mtd/nand/raw/nand_amd.c b/drivers/mtd/nand/raw/nand_amd.c
index 22f060f38123..890c5b43e03c 100644
--- a/drivers/mtd/nand/raw/nand_amd.c
+++ b/drivers/mtd/nand/raw/nand_amd.c
@@ -15,7 +15,7 @@
* GNU General Public License for more details.
*/
-#include <linux/mtd/rawnand.h>
+#include "internals.h"
static void amd_nand_decode_id(struct nand_chip *chip)
{
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index d527e448ce19..71050a0b31df 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -36,10 +36,8 @@
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/mm.h>
-#include <linux/nmi.h>
#include <linux/types.h>
#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
#include <linux/mtd/nand_ecc.h>
#include <linux/mtd/nand_bch.h>
#include <linux/interrupt.h>
@@ -48,6 +46,8 @@
#include <linux/mtd/partitions.h>
#include <linux/of.h>
+#include "internals.h"
+
static int nand_get_device(struct mtd_info *mtd, int new_state);
static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
@@ -253,183 +253,16 @@ static void nand_release_device(struct mtd_info *mtd)
}
/**
- * nand_read_byte - [DEFAULT] read one byte from the chip
- * @mtd: MTD device structure
- *
- * Default read function for 8bit buswidth
- */
-static uint8_t nand_read_byte(struct mtd_info *mtd)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
- return readb(chip->IO_ADDR_R);
-}
-
-/**
- * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip
- * @mtd: MTD device structure
- *
- * Default read function for 16bit buswidth with endianness conversion.
- *
- */
-static uint8_t nand_read_byte16(struct mtd_info *mtd)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
- return (uint8_t) cpu_to_le16(readw(chip->IO_ADDR_R));
-}
-
-/**
- * nand_read_word - [DEFAULT] read one word from the chip
- * @mtd: MTD device structure
- *
- * Default read function for 16bit buswidth without endianness conversion.
- */
-static u16 nand_read_word(struct mtd_info *mtd)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
- return readw(chip->IO_ADDR_R);
-}
-
-/**
- * nand_select_chip - [DEFAULT] control CE line
- * @mtd: MTD device structure
- * @chipnr: chipnumber to select, -1 for deselect
- *
- * Default select function for 1 chip devices.
- */
-static void nand_select_chip(struct mtd_info *mtd, int chipnr)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
-
- switch (chipnr) {
- case -1:
- chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
- break;
- case 0:
- break;
-
- default:
- BUG();
- }
-}
-
-/**
- * nand_write_byte - [DEFAULT] write single byte to chip
- * @mtd: MTD device structure
- * @byte: value to write
- *
- * Default function to write a byte to I/O[7:0]
- */
-static void nand_write_byte(struct mtd_info *mtd, uint8_t byte)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
-
- chip->write_buf(mtd, &byte, 1);
-}
-
-/**
- * nand_write_byte16 - [DEFAULT] write single byte to a chip with width 16
- * @mtd: MTD device structure
- * @byte: value to write
- *
- * Default function to write a byte to I/O[7:0] on a 16-bit wide chip.
- */
-static void nand_write_byte16(struct mtd_info *mtd, uint8_t byte)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
- uint16_t word = byte;
-
- /*
- * It's not entirely clear what should happen to I/O[15:8] when writing
- * a byte. The ONFi spec (Revision 3.1; 2012-09-19, Section 2.16) reads:
- *
- * When the host supports a 16-bit bus width, only data is
- * transferred at the 16-bit width. All address and command line
- * transfers shall use only the lower 8-bits of the data bus. During
- * command transfers, the host may place any value on the upper
- * 8-bits of the data bus. During address transfers, the host shall
- * set the upper 8-bits of the data bus to 00h.
- *
- * One user of the write_byte callback is nand_set_features. The
- * four parameters are specified to be written to I/O[7:0], but this is
- * neither an address nor a command transfer. Let's assume a 0 on the
- * upper I/O lines is OK.
- */
- chip->write_buf(mtd, (uint8_t *)&word, 2);
-}
-
-/**
- * nand_write_buf - [DEFAULT] write buffer to chip
- * @mtd: MTD device structure
- * @buf: data buffer
- * @len: number of bytes to write
- *
- * Default write function for 8bit buswidth.
- */
-static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
-
- iowrite8_rep(chip->IO_ADDR_W, buf, len);
-}
-
-/**
- * nand_read_buf - [DEFAULT] read chip data into buffer
- * @mtd: MTD device structure
- * @buf: buffer to store date
- * @len: number of bytes to read
- *
- * Default read function for 8bit buswidth.
- */
-static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
-
- ioread8_rep(chip->IO_ADDR_R, buf, len);
-}
-
-/**
- * nand_write_buf16 - [DEFAULT] write buffer to chip
- * @mtd: MTD device structure
- * @buf: data buffer
- * @len: number of bytes to write
- *
- * Default write function for 16bit buswidth.
- */
-static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
- u16 *p = (u16 *) buf;
-
- iowrite16_rep(chip->IO_ADDR_W, p, len >> 1);
-}
-
-/**
- * nand_read_buf16 - [DEFAULT] read chip data into buffer
- * @mtd: MTD device structure
- * @buf: buffer to store date
- * @len: number of bytes to read
- *
- * Default read function for 16bit buswidth.
- */
-static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
- u16 *p = (u16 *) buf;
-
- ioread16_rep(chip->IO_ADDR_R, p, len >> 1);
-}
-
-/**
* nand_block_bad - [DEFAULT] Read bad block marker from the chip
- * @mtd: MTD device structure
+ * @chip: NAND chip object
* @ofs: offset from device start
*
* Check, if the block is bad.
*/
-static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)
+static int nand_block_bad(struct nand_chip *chip, loff_t ofs)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int page, page_end, res;
- struct nand_chip *chip = mtd_to_nand(mtd);
u8 bad;
if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
@@ -439,7 +272,7 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)
page_end = page + (chip->bbt_options & NAND_BBT_SCAN2NDPAGE ? 2 : 1);
for (; page < page_end; page++) {
- res = chip->ecc.read_oob(mtd, chip, page);
+ res = chip->ecc.read_oob(chip, page);
if (res < 0)
return res;
@@ -458,16 +291,16 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)
/**
* nand_default_block_markbad - [DEFAULT] mark a block bad via bad block marker
- * @mtd: MTD device structure
+ * @chip: NAND chip object
* @ofs: offset from device start
*
* This is the default implementation, which can be overridden by a hardware
* specific driver. It provides the details for writing a bad block marker to a
* block.
*/
-static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
+static int nand_default_block_markbad(struct nand_chip *chip, loff_t ofs)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct mtd_oob_ops ops;
uint8_t buf[2] = { 0, 0 };
int ret = 0, res, i = 0;
@@ -499,13 +332,34 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
}
/**
+ * nand_markbad_bbm - mark a block by updating the BBM
+ * @chip: NAND chip object
+ * @ofs: offset of the block to mark bad
+ */
+int nand_markbad_bbm(struct nand_chip *chip, loff_t ofs)
+{
+ if (chip->legacy.block_markbad)
+ return chip->legacy.block_markbad(chip, ofs);
+
+ return nand_default_block_markbad(chip, ofs);
+}
+
+static int nand_isbad_bbm(struct nand_chip *chip, loff_t ofs)
+{
+ if (chip->legacy.block_bad)
+ return chip->legacy.block_bad(chip, ofs);
+
+ return nand_block_bad(chip, ofs);
+}
+
+/**
* nand_block_markbad_lowlevel - mark a block bad
* @mtd: MTD device structure
* @ofs: offset from device start
*
* This function performs the generic NAND bad block marking steps (i.e., bad
* block table(s) and/or marker(s)). We only allow the hardware driver to
- * specify how to write bad block markers to OOB (chip->block_markbad).
+ * specify how to write bad block markers to OOB (chip->legacy.block_markbad).
*
* We try operations in the following order:
*
@@ -529,17 +383,17 @@ static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs)
memset(&einfo, 0, sizeof(einfo));
einfo.addr = ofs;
einfo.len = 1ULL << chip->phys_erase_shift;
- nand_erase_nand(mtd, &einfo, 0);
+ nand_erase_nand(chip, &einfo, 0);
/* Write bad block marker to OOB */
nand_get_device(mtd, FL_WRITING);
- ret = chip->block_markbad(mtd, ofs);
+ ret = nand_markbad_bbm(chip, ofs);
nand_release_device(mtd);
}
/* Mark block bad in BBT */
if (chip->bbt) {
- res = nand_markbad_bbt(mtd, ofs);
+ res = nand_markbad_bbt(chip, ofs);
if (!ret)
ret = res;
}
@@ -589,7 +443,7 @@ static int nand_block_isreserved(struct mtd_info *mtd, loff_t ofs)
if (!chip->bbt)
return 0;
/* Return info from the table */
- return nand_isreserved_bbt(mtd, ofs);
+ return nand_isreserved_bbt(chip, ofs);
}
/**
@@ -605,89 +459,14 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int allowbbt)
{
struct nand_chip *chip = mtd_to_nand(mtd);
- if (!chip->bbt)
- return chip->block_bad(mtd, ofs);
-
/* Return info from the table */
- return nand_isbad_bbt(mtd, ofs, allowbbt);
-}
+ if (chip->bbt)
+ return nand_isbad_bbt(chip, ofs, allowbbt);
-/**
- * panic_nand_wait_ready - [GENERIC] Wait for the ready pin after commands.
- * @mtd: MTD device structure
- * @timeo: Timeout
- *
- * Helper function for nand_wait_ready used when needing to wait in interrupt
- * context.
- */
-static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
- int i;
-
- /* Wait for the device to get ready */
- for (i = 0; i < timeo; i++) {
- if (chip->dev_ready(mtd))
- break;
- touch_softlockup_watchdog();
- mdelay(1);
- }
+ return nand_isbad_bbm(chip, ofs);
}
/**
- * nand_wait_ready - [GENERIC] Wait for the ready pin after commands.
- * @mtd: MTD device structure
- *
- * Wait for the ready pin after a command, and warn if a timeout occurs.
- */
-void nand_wait_ready(struct mtd_info *mtd)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
- unsigned long timeo = 400;
-
- if (in_interrupt() || oops_in_progress)
- return panic_nand_wait_ready(mtd, timeo);
-
- /* Wait until command is processed or timeout occurs */
- timeo = jiffies + msecs_to_jiffies(timeo);
- do {
- if (chip->dev_ready(mtd))
- return;
- cond_resched();
- } while (time_before(jiffies, timeo));
-
- if (!chip->dev_ready(mtd))
- pr_warn_ratelimited("timeout while waiting for chip to become ready\n");
-}
-EXPORT_SYMBOL_GPL(nand_wait_ready);
-
-/**
- * nand_wait_status_ready - [GENERIC] Wait for the ready status after commands.
- * @mtd: MTD device structure
- * @timeo: Timeout in ms
- *
- * Wait for status ready (i.e. command done) or timeout.
- */
-static void nand_wait_status_ready(struct mtd_info *mtd, unsigned long timeo)
-{
- register struct nand_chip *chip = mtd_to_nand(mtd);
- int ret;
-
- timeo = jiffies + msecs_to_jiffies(timeo);
- do {
- u8 status;
-
- ret = nand_read_data_op(chip, &status, sizeof(status), true);
- if (ret)
- return;
-
- if (status & NAND_STATUS_READY)
- break;
- touch_softlockup_watchdog();
- } while (time_before(jiffies, timeo));
-};
-
-/**
* nand_soft_waitrdy - Poll STATUS reg until RDY bit is set to 1
* @chip: NAND chip structure
* @timeout_ms: Timeout in ms
@@ -753,273 +532,6 @@ int nand_soft_waitrdy(struct nand_chip *chip, unsigned long timeout_ms)
EXPORT_SYMBOL_GPL(nand_soft_waitrdy);
/**
- * nand_command - [DEFAULT] Send command to NAND device
- * @mtd: MTD device structure
- * @command: the command to be sent
- * @column: the column address for this command, -1 if none
- * @page_addr: the page address for this command, -1 if none
- *
- * Send command to NAND device. This function is used for small page devices
- * (512 Bytes per page).
- */
-static void nand_command(struct mtd_info *mtd, unsigned int command,
- int column, int page_addr)
-{
- register struct nand_chip *chip = mtd_to_nand(mtd);
- int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE;
-
- /* Write out the command to the device */
- if (command == NAND_CMD_SEQIN) {
- int readcmd;
-
- if (column >= mtd->writesize) {
- /* OOB area */
- column -= mtd->writesize;
- readcmd = NAND_CMD_READOOB;
- } else if (column < 256) {
- /* First 256 bytes --> READ0 */
- readcmd = NAND_CMD_READ0;
- } else {
- column -= 256;
- readcmd = NAND_CMD_READ1;
- }
- chip->cmd_ctrl(mtd, readcmd, ctrl);
- ctrl &= ~NAND_CTRL_CHANGE;
- }
- if (command != NAND_CMD_NONE)
- chip->cmd_ctrl(mtd, command, ctrl);
-
- /* Address cycle, when necessary */
- ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE;
- /* Serially input address */
- if (column != -1) {
- /* Adjust columns for 16 bit buswidth */
- if (chip->options & NAND_BUSWIDTH_16 &&
- !nand_opcode_8bits(command))
- column >>= 1;
- chip->cmd_ctrl(mtd, column, ctrl);
- ctrl &= ~NAND_CTRL_CHANGE;
- }
- if (page_addr != -1) {
- chip->cmd_ctrl(mtd, page_addr, ctrl);
- ctrl &= ~NAND_CTRL_CHANGE;
- chip->cmd_ctrl(mtd, page_addr >> 8, ctrl);
- if (chip->options & NAND_ROW_ADDR_3)
- chip->cmd_ctrl(mtd, page_addr >> 16, ctrl);
- }
- chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
-
- /*
- * Program and erase have their own busy handlers status and sequential
- * in needs no delay
- */
- switch (command) {
-
- case NAND_CMD_NONE:
- case NAND_CMD_PAGEPROG:
- case NAND_CMD_ERASE1:
- case NAND_CMD_ERASE2:
- case NAND_CMD_SEQIN:
- case NAND_CMD_STATUS:
- case NAND_CMD_READID:
- case NAND_CMD_SET_FEATURES:
- return;
-
- case NAND_CMD_RESET:
- if (chip->dev_ready)
- break;
- udelay(chip->chip_delay);
- chip->cmd_ctrl(mtd, NAND_CMD_STATUS,
- NAND_CTRL_CLE | NAND_CTRL_CHANGE);
- chip->cmd_ctrl(mtd,
- NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
- /* EZ-NAND can take upto 250ms as per ONFi v4.0 */
- nand_wait_status_ready(mtd, 250);
- return;
-
- /* This applies to read commands */
- case NAND_CMD_READ0:
- /*
- * READ0 is sometimes used to exit GET STATUS mode. When this
- * is the case no address cycles are requested, and we can use
- * this information to detect that we should not wait for the
- * device to be ready.
- */
- if (column == -1 && page_addr == -1)
- return;
-
- default:
- /*
- * If we don't have access to the busy pin, we apply the given
- * command delay
- */
- if (!chip->dev_ready) {
- udelay(chip->chip_delay);
- return;
- }
- }
- /*
- * Apply this short delay always to ensure that we do wait tWB in
- * any case on any machine.
- */
- ndelay(100);
-
- nand_wait_ready(mtd);
-}
-
-static void nand_ccs_delay(struct nand_chip *chip)
-{
- /*
- * The controller already takes care of waiting for tCCS when the RNDIN
- * or RNDOUT command is sent, return directly.
- */
- if (!(chip->options & NAND_WAIT_TCCS))
- return;
-
- /*
- * Wait tCCS_min if it is correctly defined, otherwise wait 500ns
- * (which should be safe for all NANDs).
- */
- if (chip->setup_data_interface)
- ndelay(chip->data_interface.timings.sdr.tCCS_min / 1000);
- else
- ndelay(500);
-}
-
-/**
- * nand_command_lp - [DEFAULT] Send command to NAND large page device
- * @mtd: MTD device structure
- * @command: the command to be sent
- * @column: the column address for this command, -1 if none
- * @page_addr: the page address for this command, -1 if none
- *
- * Send command to NAND device. This is the version for the new large page
- * devices. We don't have the separate regions as we have in the small page
- * devices. We must emulate NAND_CMD_READOOB to keep the code compatible.
- */
-static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
- int column, int page_addr)
-{
- register struct nand_chip *chip = mtd_to_nand(mtd);
-
- /* Emulate NAND_CMD_READOOB */
- if (command == NAND_CMD_READOOB) {
- column += mtd->writesize;
- command = NAND_CMD_READ0;
- }
-
- /* Command latch cycle */
- if (command != NAND_CMD_NONE)
- chip->cmd_ctrl(mtd, command,
- NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
-
- if (column != -1 || page_addr != -1) {
- int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
-
- /* Serially input address */
- if (column != -1) {
- /* Adjust columns for 16 bit buswidth */
- if (chip->options & NAND_BUSWIDTH_16 &&
- !nand_opcode_8bits(command))
- column >>= 1;
- chip->cmd_ctrl(mtd, column, ctrl);
- ctrl &= ~NAND_CTRL_CHANGE;
-
- /* Only output a single addr cycle for 8bits opcodes. */
- if (!nand_opcode_8bits(command))
- chip->cmd_ctrl(mtd, column >> 8, ctrl);
- }
- if (page_addr != -1) {
- chip->cmd_ctrl(mtd, page_addr, ctrl);
- chip->cmd_ctrl(mtd, page_addr >> 8,
- NAND_NCE | NAND_ALE);
- if (chip->options & NAND_ROW_ADDR_3)
- chip->cmd_ctrl(mtd, page_addr >> 16,
- NAND_NCE | NAND_ALE);
- }
- }
- chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
-
- /*
- * Program and erase have their own busy handlers status, sequential
- * in and status need no delay.
- */
- switch (command) {
-
- case NAND_CMD_NONE:
- case NAND_CMD_CACHEDPROG:
- case NAND_CMD_PAGEPROG:
- case NAND_CMD_ERASE1:
- case NAND_CMD_ERASE2:
- case NAND_CMD_SEQIN:
- case NAND_CMD_STATUS:
- case NAND_CMD_READID:
- case NAND_CMD_SET_FEATURES:
- return;
-
- case NAND_CMD_RNDIN:
- nand_ccs_delay(chip);
- return;
-
- case NAND_CMD_RESET:
- if (chip->dev_ready)
- break;
- udelay(chip->chip_delay);
- chip->cmd_ctrl(mtd, NAND_CMD_STATUS,
- NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
- chip->cmd_ctrl(mtd, NAND_CMD_NONE,
- NAND_NCE | NAND_CTRL_CHANGE);
- /* EZ-NAND can take upto 250ms as per ONFi v4.0 */
- nand_wait_status_ready(mtd, 250);
- return;
-
- case NAND_CMD_RNDOUT:
- /* No ready / busy check necessary */
- chip->cmd_ctrl(mtd, NAND_CMD_RNDOUTSTART,
- NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
- chip->cmd_ctrl(mtd, NAND_CMD_NONE,
- NAND_NCE | NAND_CTRL_CHANGE);
-
- nand_ccs_delay(chip);
- return;
-
- case NAND_CMD_READ0:
- /*
- * READ0 is sometimes used to exit GET STATUS mode. When this
- * is the case no address cycles are requested, and we can use
- * this information to detect that READSTART should not be
- * issued.
- */
- if (column == -1 && page_addr == -1)
- return;
-
- chip->cmd_ctrl(mtd, NAND_CMD_READSTART,
- NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
- chip->cmd_ctrl(mtd, NAND_CMD_NONE,
- NAND_NCE | NAND_CTRL_CHANGE);
-
- /* This applies to read commands */
- default:
- /*
- * If we don't have access to the busy pin, we apply the given
- * command delay.
- */
- if (!chip->dev_ready) {
- udelay(chip->chip_delay);
- return;
- }
- }
-
- /*
- * Apply this short delay always to ensure that we do wait tWB in
- * any case on any machine.
- */
- ndelay(100);
-
- nand_wait_ready(mtd);
-}
-
-/**
* panic_nand_get_device - [GENERIC] Get chip for selected access
* @chip: the nand chip descriptor
* @mtd: MTD device structure
@@ -1078,7 +590,6 @@ retry:
/**
* panic_nand_wait - [GENERIC] wait until the command is done
- * @mtd: MTD device structure
* @chip: NAND chip structure
* @timeo: timeout
*
@@ -1086,13 +597,12 @@ retry:
* we are in interrupt context. May happen when in panic and trying to write
* an oops through mtdoops.
*/
-static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip,
- unsigned long timeo)
+void panic_nand_wait(struct nand_chip *chip, unsigned long timeo)
{
int i;
for (i = 0; i < timeo; i++) {
- if (chip->dev_ready) {
- if (chip->dev_ready(mtd))
+ if (chip->legacy.dev_ready) {
+ if (chip->legacy.dev_ready(chip))
break;
} else {
int ret;
@@ -1110,60 +620,6 @@ static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip,
}
}
-/**
- * nand_wait - [DEFAULT] wait until the command is done
- * @mtd: MTD device structure
- * @chip: NAND chip structure
- *
- * Wait for command done. This applies to erase and program only.
- */
-static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
-{
-
- unsigned long timeo = 400;
- u8 status;
- int ret;
-
- /*
- * Apply this short delay always to ensure that we do wait tWB in any
- * case on any machine.
- */
- ndelay(100);
-
- ret = nand_status_op(chip, NULL);
- if (ret)
- return ret;
-
- if (in_interrupt() || oops_in_progress)
- panic_nand_wait(mtd, chip, timeo);
- else {
- timeo = jiffies + msecs_to_jiffies(timeo);
- do {
- if (chip->dev_ready) {
- if (chip->dev_ready(mtd))
- break;
- } else {
- ret = nand_read_data_op(chip, &status,
- sizeof(status), true);
- if (ret)
- return ret;
-
- if (status & NAND_STATUS_READY)
- break;
- }
- cond_resched();
- } while (time_before(jiffies, timeo));
- }
-
- ret = nand_read_data_op(chip, &status, sizeof(status), true);
- if (ret)
- return ret;
-
- /* This can happen if in case of timeout or buggy dev_ready */
- WARN_ON(!(status & NAND_STATUS_READY));
- return status;
-}
-
static bool nand_supports_get_features(struct nand_chip *chip, int addr)
{
return (chip->parameters.supports_set_get_features &&
@@ -1177,48 +633,6 @@ static bool nand_supports_set_features(struct nand_chip *chip, int addr)
}
/**
- * nand_get_features - wrapper to perform a GET_FEATURE
- * @chip: NAND chip info structure
- * @addr: feature address
- * @subfeature_param: the subfeature parameters, a four bytes array
- *
- * Returns 0 for success, a negative error otherwise. Returns -ENOTSUPP if the
- * operation cannot be handled.
- */
-int nand_get_features(struct nand_chip *chip, int addr,
- u8 *subfeature_param)
-{
- struct mtd_info *mtd = nand_to_mtd(chip);
-
- if (!nand_supports_get_features(chip, addr))
- return -ENOTSUPP;
-
- return chip->get_features(mtd, chip, addr, subfeature_param);
-}
-EXPORT_SYMBOL_GPL(nand_get_features);
-
-/**
- * nand_set_features - wrapper to perform a SET_FEATURE
- * @chip: NAND chip info structure
- * @addr: feature address
- * @subfeature_param: the subfeature parameters, a four bytes array
- *
- * Returns 0 for success, a negative error otherwise. Returns -ENOTSUPP if the
- * operation cannot be handled.
- */
-int nand_set_features(struct nand_chip *chip, int addr,
- u8 *subfeature_param)
-{
- struct mtd_info *mtd = nand_to_mtd(chip);
-
- if (!nand_supports_set_features(chip, addr))
- return -ENOTSUPP;
-
- return chip->set_features(mtd, chip, addr, subfeature_param);
-}
-EXPORT_SYMBOL_GPL(nand_set_features);
-
-/**
* nand_reset_data_interface - Reset data interface and timings
* @chip: The NAND chip
* @chipnr: Internal die id
@@ -1229,7 +643,6 @@ EXPORT_SYMBOL_GPL(nand_set_features);
*/
static int nand_reset_data_interface(struct nand_chip *chip, int chipnr)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
int ret;
if (!chip->setup_data_interface)
@@ -1250,7 +663,7 @@ static int nand_reset_data_interface(struct nand_chip *chip, int chipnr)
*/
onfi_fill_data_interface(chip, NAND_SDR_IFACE, 0);
- ret = chip->setup_data_interface(mtd, chipnr, &chip->data_interface);
+ ret = chip->setup_data_interface(chip, chipnr, &chip->data_interface);
if (ret)
pr_err("Failed to configure data interface to SDR timing mode 0\n");
@@ -1272,7 +685,6 @@ static int nand_reset_data_interface(struct nand_chip *chip, int chipnr)
*/
static int nand_setup_data_interface(struct nand_chip *chip, int chipnr)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = {
chip->onfi_timing_mode_default,
};
@@ -1283,16 +695,16 @@ static int nand_setup_data_interface(struct nand_chip *chip, int chipnr)
/* Change the mode on the chip side (if supported by the NAND chip) */
if (nand_supports_set_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE)) {
- chip->select_chip(mtd, chipnr);
+ chip->select_chip(chip, chipnr);
ret = nand_set_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE,
tmode_param);
- chip->select_chip(mtd, -1);
+ chip->select_chip(chip, -1);
if (ret)
return ret;
}
/* Change the mode on the controller side */
- ret = chip->setup_data_interface(mtd, chipnr, &chip->data_interface);
+ ret = chip->setup_data_interface(chip, chipnr, &chip->data_interface);
if (ret)
return ret;
@@ -1301,10 +713,10 @@ static int nand_setup_data_interface(struct nand_chip *chip, int chipnr)
return 0;
memset(tmode_param, 0, ONFI_SUBFEATURE_PARAM_LEN);
- chip->select_chip(mtd, chipnr);
+ chip->select_chip(chip, chipnr);
ret = nand_get_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE,
tmode_param);
- chip->select_chip(mtd, -1);
+ chip->select_chip(chip, -1);
if (ret)
goto err_reset_chip;
@@ -1322,9 +734,9 @@ err_reset_chip:
* timing mode.
*/
nand_reset_data_interface(chip, chipnr);
- chip->select_chip(mtd, chipnr);
+ chip->select_chip(chip, chipnr);
nand_reset_op(chip);
- chip->select_chip(mtd, -1);
+ chip->select_chip(chip, -1);
return ret;
}
@@ -1345,7 +757,6 @@ err_reset_chip:
*/
static int nand_init_data_interface(struct nand_chip *chip)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
int modes, mode, ret;
if (!chip->setup_data_interface)
@@ -1356,15 +767,15 @@ static int nand_init_data_interface(struct nand_chip *chip)
* if the NAND does not support ONFI, fallback to the default ONFI
* timing mode.
*/
- modes = onfi_get_async_timing_mode(chip);
- if (modes == ONFI_TIMING_MODE_UNKNOWN) {
+ if (chip->parameters.onfi) {
+ modes = chip->parameters.onfi->async_timing_mode;
+ } else {
if (!chip->onfi_timing_mode_default)
return 0;
modes = GENMASK(chip->onfi_timing_mode_default, 0);
}
-
for (mode = fls(modes) - 1; mode >= 0; mode--) {
ret = onfi_fill_data_interface(chip, NAND_SDR_IFACE, mode);
if (ret)
@@ -1374,7 +785,7 @@ static int nand_init_data_interface(struct nand_chip *chip)
* Pass NAND_DATA_IFACE_CHECK_ONLY to only check if the
* controller supports the requested timings.
*/
- ret = chip->setup_data_interface(mtd,
+ ret = chip->setup_data_interface(chip,
NAND_DATA_IFACE_CHECK_ONLY,
&chip->data_interface);
if (!ret) {
@@ -1554,9 +965,9 @@ int nand_read_page_op(struct nand_chip *chip, unsigned int page,
buf, len);
}
- chip->cmdfunc(mtd, NAND_CMD_READ0, offset_in_page, page);
+ chip->legacy.cmdfunc(chip, NAND_CMD_READ0, offset_in_page, page);
if (len)
- chip->read_buf(mtd, buf, len);
+ chip->legacy.read_buf(chip, buf, len);
return 0;
}
@@ -1574,10 +985,9 @@ EXPORT_SYMBOL_GPL(nand_read_page_op);
*
* Returns 0 on success, a negative error code otherwise.
*/
-static int nand_read_param_page_op(struct nand_chip *chip, u8 page, void *buf,
- unsigned int len)
+int nand_read_param_page_op(struct nand_chip *chip, u8 page, void *buf,
+ unsigned int len)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
unsigned int i;
u8 *p = buf;
@@ -1603,9 +1013,9 @@ static int nand_read_param_page_op(struct nand_chip *chip, u8 page, void *buf,
return nand_exec_op(chip, &op);
}
- chip->cmdfunc(mtd, NAND_CMD_PARAM, page, -1);
+ chip->legacy.cmdfunc(chip, NAND_CMD_PARAM, page, -1);
for (i = 0; i < len; i++)
- p[i] = chip->read_byte(mtd);
+ p[i] = chip->legacy.read_byte(chip);
return 0;
}
@@ -1666,9 +1076,9 @@ int nand_change_read_column_op(struct nand_chip *chip,
return nand_exec_op(chip, &op);
}
- chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset_in_page, -1);
+ chip->legacy.cmdfunc(chip, NAND_CMD_RNDOUT, offset_in_page, -1);
if (len)
- chip->read_buf(mtd, buf, len);
+ chip->legacy.read_buf(chip, buf, len);
return 0;
}
@@ -1703,9 +1113,9 @@ int nand_read_oob_op(struct nand_chip *chip, unsigned int page,
mtd->writesize + offset_in_oob,
buf, len);
- chip->cmdfunc(mtd, NAND_CMD_READOOB, offset_in_oob, page);
+ chip->legacy.cmdfunc(chip, NAND_CMD_READOOB, offset_in_oob, page);
if (len)
- chip->read_buf(mtd, buf, len);
+ chip->legacy.read_buf(chip, buf, len);
return 0;
}
@@ -1815,10 +1225,10 @@ int nand_prog_page_begin_op(struct nand_chip *chip, unsigned int page,
return nand_exec_prog_page_op(chip, page, offset_in_page, buf,
len, false);
- chip->cmdfunc(mtd, NAND_CMD_SEQIN, offset_in_page, page);
+ chip->legacy.cmdfunc(chip, NAND_CMD_SEQIN, offset_in_page, page);
if (buf)
- chip->write_buf(mtd, buf, len);
+ chip->legacy.write_buf(chip, buf, len);
return 0;
}
@@ -1835,7 +1245,6 @@ EXPORT_SYMBOL_GPL(nand_prog_page_begin_op);
*/
int nand_prog_page_end_op(struct nand_chip *chip)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
int ret;
u8 status;
@@ -1857,8 +1266,8 @@ int nand_prog_page_end_op(struct nand_chip *chip)
if (ret)
return ret;
} else {
- chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
- ret = chip->waitfunc(mtd, chip);
+ chip->legacy.cmdfunc(chip, NAND_CMD_PAGEPROG, -1, -1);
+ ret = chip->legacy.waitfunc(chip);
if (ret < 0)
return ret;
@@ -1902,10 +1311,11 @@ int nand_prog_page_op(struct nand_chip *chip, unsigned int page,
status = nand_exec_prog_page_op(chip, page, offset_in_page, buf,
len, true);
} else {
- chip->cmdfunc(mtd, NAND_CMD_SEQIN, offset_in_page, page);
- chip->write_buf(mtd, buf, len);
- chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
- status = chip->waitfunc(mtd, chip);
+ chip->legacy.cmdfunc(chip, NAND_CMD_SEQIN, offset_in_page,
+ page);
+ chip->legacy.write_buf(chip, buf, len);
+ chip->legacy.cmdfunc(chip, NAND_CMD_PAGEPROG, -1, -1);
+ status = chip->legacy.waitfunc(chip);
}
if (status & NAND_STATUS_FAIL)
@@ -1970,9 +1380,9 @@ int nand_change_write_column_op(struct nand_chip *chip,
return nand_exec_op(chip, &op);
}
- chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset_in_page, -1);
+ chip->legacy.cmdfunc(chip, NAND_CMD_RNDIN, offset_in_page, -1);
if (len)
- chip->write_buf(mtd, buf, len);
+ chip->legacy.write_buf(chip, buf, len);
return 0;
}
@@ -1994,7 +1404,6 @@ EXPORT_SYMBOL_GPL(nand_change_write_column_op);
int nand_readid_op(struct nand_chip *chip, u8 addr, void *buf,
unsigned int len)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
unsigned int i;
u8 *id = buf;
@@ -2018,10 +1427,10 @@ int nand_readid_op(struct nand_chip *chip, u8 addr, void *buf,
return nand_exec_op(chip, &op);
}
- chip->cmdfunc(mtd, NAND_CMD_READID, addr, -1);
+ chip->legacy.cmdfunc(chip, NAND_CMD_READID, addr, -1);
for (i = 0; i < len; i++)
- id[i] = chip->read_byte(mtd);
+ id[i] = chip->legacy.read_byte(chip);
return 0;
}
@@ -2040,8 +1449,6 @@ EXPORT_SYMBOL_GPL(nand_readid_op);
*/
int nand_status_op(struct nand_chip *chip, u8 *status)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
-
if (chip->exec_op) {
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(&chip->data_interface);
@@ -2058,9 +1465,9 @@ int nand_status_op(struct nand_chip *chip, u8 *status)
return nand_exec_op(chip, &op);
}
- chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
+ chip->legacy.cmdfunc(chip, NAND_CMD_STATUS, -1, -1);
if (status)
- *status = chip->read_byte(mtd);
+ *status = chip->legacy.read_byte(chip);
return 0;
}
@@ -2079,8 +1486,6 @@ EXPORT_SYMBOL_GPL(nand_status_op);
*/
int nand_exit_status_op(struct nand_chip *chip)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
-
if (chip->exec_op) {
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_READ0, 0),
@@ -2090,11 +1495,10 @@ int nand_exit_status_op(struct nand_chip *chip)
return nand_exec_op(chip, &op);
}
- chip->cmdfunc(mtd, NAND_CMD_READ0, -1, -1);
+ chip->legacy.cmdfunc(chip, NAND_CMD_READ0, -1, -1);
return 0;
}
-EXPORT_SYMBOL_GPL(nand_exit_status_op);
/**
* nand_erase_op - Do an erase operation
@@ -2109,7 +1513,6 @@ EXPORT_SYMBOL_GPL(nand_exit_status_op);
*/
int nand_erase_op(struct nand_chip *chip, unsigned int eraseblock)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
unsigned int page = eraseblock <<
(chip->phys_erase_shift - chip->page_shift);
int ret;
@@ -2139,10 +1542,10 @@ int nand_erase_op(struct nand_chip *chip, unsigned int eraseblock)
if (ret)
return ret;
} else {
- chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
- chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
+ chip->legacy.cmdfunc(chip, NAND_CMD_ERASE1, -1, page);
+ chip->legacy.cmdfunc(chip, NAND_CMD_ERASE2, -1, -1);
- ret = chip->waitfunc(mtd, chip);
+ ret = chip->legacy.waitfunc(chip);
if (ret < 0)
return ret;
@@ -2171,7 +1574,6 @@ EXPORT_SYMBOL_GPL(nand_erase_op);
static int nand_set_features_op(struct nand_chip *chip, u8 feature,
const void *data)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
const u8 *params = data;
int i, ret;
@@ -2190,11 +1592,11 @@ static int nand_set_features_op(struct nand_chip *chip, u8 feature,
return nand_exec_op(chip, &op);
}
- chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, feature, -1);
+ chip->legacy.cmdfunc(chip, NAND_CMD_SET_FEATURES, feature, -1);
for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
- chip->write_byte(mtd, params[i]);
+ chip->legacy.write_byte(chip, params[i]);
- ret = chip->waitfunc(mtd, chip);
+ ret = chip->legacy.waitfunc(chip);
if (ret < 0)
return ret;
@@ -2219,7 +1621,6 @@ 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)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
u8 *params = data;
int i;
@@ -2239,9 +1640,31 @@ static int nand_get_features_op(struct nand_chip *chip, u8 feature,
return nand_exec_op(chip, &op);
}
- chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, feature, -1);
+ chip->legacy.cmdfunc(chip, NAND_CMD_GET_FEATURES, feature, -1);
for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
- params[i] = chip->read_byte(mtd);
+ params[i] = chip->legacy.read_byte(chip);
+
+ return 0;
+}
+
+static int nand_wait_rdy_op(struct nand_chip *chip, unsigned int timeout_ms,
+ unsigned int delay_ns)
+{
+ if (chip->exec_op) {
+ struct nand_op_instr instrs[] = {
+ NAND_OP_WAIT_RDY(PSEC_TO_MSEC(timeout_ms),
+ PSEC_TO_NSEC(delay_ns)),
+ };
+ struct nand_operation op = NAND_OPERATION(instrs);
+
+ return nand_exec_op(chip, &op);
+ }
+
+ /* Apply delay or wait for ready/busy pin */
+ if (!chip->legacy.dev_ready)
+ udelay(chip->legacy.chip_delay);
+ else
+ nand_wait_ready(chip);
return 0;
}
@@ -2258,8 +1681,6 @@ static int nand_get_features_op(struct nand_chip *chip, u8 feature,
*/
int nand_reset_op(struct nand_chip *chip)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
-
if (chip->exec_op) {
const struct nand_sdr_timings *sdr =
nand_get_sdr_timings(&chip->data_interface);
@@ -2272,7 +1693,7 @@ int nand_reset_op(struct nand_chip *chip)
return nand_exec_op(chip, &op);
}
- chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+ chip->legacy.cmdfunc(chip, NAND_CMD_RESET, -1, -1);
return 0;
}
@@ -2294,8 +1715,6 @@ EXPORT_SYMBOL_GPL(nand_reset_op);
int nand_read_data_op(struct nand_chip *chip, void *buf, unsigned int len,
bool force_8bit)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
-
if (!len || !buf)
return -EINVAL;
@@ -2315,9 +1734,9 @@ int nand_read_data_op(struct nand_chip *chip, void *buf, unsigned int len,
unsigned int i;
for (i = 0; i < len; i++)
- p[i] = chip->read_byte(mtd);
+ p[i] = chip->legacy.read_byte(chip);
} else {
- chip->read_buf(mtd, buf, len);
+ chip->legacy.read_buf(chip, buf, len);
}
return 0;
@@ -2340,8 +1759,6 @@ EXPORT_SYMBOL_GPL(nand_read_data_op);
int nand_write_data_op(struct nand_chip *chip, const void *buf,
unsigned int len, bool force_8bit)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
-
if (!len || !buf)
return -EINVAL;
@@ -2361,9 +1778,9 @@ int nand_write_data_op(struct nand_chip *chip, const void *buf,
unsigned int i;
for (i = 0; i < len; i++)
- chip->write_byte(mtd, p[i]);
+ chip->legacy.write_byte(chip, p[i]);
} else {
- chip->write_buf(mtd, buf, len);
+ chip->legacy.write_buf(chip, buf, len);
}
return 0;
@@ -2798,7 +2215,6 @@ EXPORT_SYMBOL_GPL(nand_subop_get_data_len);
*/
int nand_reset(struct nand_chip *chip, int chipnr)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_data_interface saved_data_intf = chip->data_interface;
int ret;
@@ -2810,9 +2226,9 @@ int nand_reset(struct nand_chip *chip, int chipnr)
* The CS line has to be released before we can apply the new NAND
* interface settings, hence this weird ->select_chip() dance.
*/
- chip->select_chip(mtd, chipnr);
+ chip->select_chip(chip, chipnr);
ret = nand_reset_op(chip);
- chip->select_chip(mtd, -1);
+ chip->select_chip(chip, -1);
if (ret)
return ret;
@@ -2836,6 +2252,48 @@ int nand_reset(struct nand_chip *chip, int chipnr)
EXPORT_SYMBOL_GPL(nand_reset);
/**
+ * nand_get_features - wrapper to perform a GET_FEATURE
+ * @chip: NAND chip info structure
+ * @addr: feature address
+ * @subfeature_param: the subfeature parameters, a four bytes array
+ *
+ * Returns 0 for success, a negative error otherwise. Returns -ENOTSUPP if the
+ * operation cannot be handled.
+ */
+int nand_get_features(struct nand_chip *chip, int addr,
+ u8 *subfeature_param)
+{
+ if (!nand_supports_get_features(chip, addr))
+ return -ENOTSUPP;
+
+ if (chip->legacy.get_features)
+ return chip->legacy.get_features(chip, addr, subfeature_param);
+
+ return nand_get_features_op(chip, addr, subfeature_param);
+}
+
+/**
+ * nand_set_features - wrapper to perform a SET_FEATURE
+ * @chip: NAND chip info structure
+ * @addr: feature address
+ * @subfeature_param: the subfeature parameters, a four bytes array
+ *
+ * Returns 0 for success, a negative error otherwise. Returns -ENOTSUPP if the
+ * operation cannot be handled.
+ */
+int nand_set_features(struct nand_chip *chip, int addr,
+ u8 *subfeature_param)
+{
+ if (!nand_supports_set_features(chip, addr))
+ return -ENOTSUPP;
+
+ if (chip->legacy.set_features)
+ return chip->legacy.set_features(chip, addr, subfeature_param);
+
+ return nand_set_features_op(chip, addr, subfeature_param);
+}
+
+/**
* nand_check_erased_buf - check if a buffer contains (almost) only 0xff data
* @buf: buffer to test
* @len: buffer length
@@ -2968,7 +2426,6 @@ EXPORT_SYMBOL(nand_check_erased_ecc_chunk);
/**
* nand_read_page_raw_notsupp - dummy read raw page function
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
* @oob_required: caller requires OOB data read to chip->oob_poi
@@ -2976,16 +2433,14 @@ EXPORT_SYMBOL(nand_check_erased_ecc_chunk);
*
* Returns -ENOTSUPP unconditionally.
*/
-int nand_read_page_raw_notsupp(struct mtd_info *mtd, struct nand_chip *chip,
- u8 *buf, int oob_required, int page)
+int nand_read_page_raw_notsupp(struct nand_chip *chip, u8 *buf,
+ int oob_required, int page)
{
return -ENOTSUPP;
}
-EXPORT_SYMBOL(nand_read_page_raw_notsupp);
/**
* nand_read_page_raw - [INTERN] read raw page data without ecc
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
* @oob_required: caller requires OOB data read to chip->oob_poi
@@ -2993,9 +2448,10 @@ EXPORT_SYMBOL(nand_read_page_raw_notsupp);
*
* Not for syndrome calculating ECC controllers, which use a special oob layout.
*/
-int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+int nand_read_page_raw(struct nand_chip *chip, uint8_t *buf, int oob_required,
+ int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int ret;
ret = nand_read_page_op(chip, page, 0, buf, mtd->writesize);
@@ -3015,7 +2471,6 @@ EXPORT_SYMBOL(nand_read_page_raw);
/**
* nand_read_page_raw_syndrome - [INTERN] read raw page data without ecc
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
* @oob_required: caller requires OOB data read to chip->oob_poi
@@ -3023,10 +2478,10 @@ EXPORT_SYMBOL(nand_read_page_raw);
*
* We need a special oob layout and handling even when OOB isn't used.
*/
-static int nand_read_page_raw_syndrome(struct mtd_info *mtd,
- struct nand_chip *chip, uint8_t *buf,
+static int nand_read_page_raw_syndrome(struct nand_chip *chip, uint8_t *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
uint8_t *oob = chip->oob_poi;
@@ -3080,15 +2535,15 @@ static int nand_read_page_raw_syndrome(struct mtd_info *mtd,
/**
* nand_read_page_swecc - [REPLACEABLE] software ECC based page read function
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
* @oob_required: caller requires OOB data read to chip->oob_poi
* @page: page number to read
*/
-static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+static int nand_read_page_swecc(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int i, eccsize = chip->ecc.size, ret;
int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps;
@@ -3097,10 +2552,10 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *ecc_code = chip->ecc.code_buf;
unsigned int max_bitflips = 0;
- chip->ecc.read_page_raw(mtd, chip, buf, 1, page);
+ chip->ecc.read_page_raw(chip, buf, 1, page);
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
- chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+ chip->ecc.calculate(chip, p, &ecc_calc[i]);
ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
chip->ecc.total);
@@ -3113,7 +2568,7 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
int stat;
- stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
+ stat = chip->ecc.correct(chip, p, &ecc_code[i], &ecc_calc[i]);
if (stat < 0) {
mtd->ecc_stats.failed++;
} else {
@@ -3126,17 +2581,16 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
/**
* nand_read_subpage - [REPLACEABLE] ECC based sub-page read function
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @data_offs: offset of requested data within the page
* @readlen: data length
* @bufpoi: buffer to store read data
* @page: page number to read
*/
-static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
- uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi,
- int page)
+static int nand_read_subpage(struct nand_chip *chip, uint32_t data_offs,
+ uint32_t readlen, uint8_t *bufpoi, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int start_step, end_step, num_steps, ret;
uint8_t *p;
int data_col_addr, i, gaps = 0;
@@ -3165,7 +2619,7 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
/* Calculate ECC */
for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size)
- chip->ecc.calculate(mtd, p, &chip->ecc.calc_buf[i]);
+ chip->ecc.calculate(chip, p, &chip->ecc.calc_buf[i]);
/*
* The performance is faster if we position offsets according to
@@ -3214,7 +2668,7 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) {
int stat;
- stat = chip->ecc.correct(mtd, p, &chip->ecc.code_buf[i],
+ stat = chip->ecc.correct(chip, p, &chip->ecc.code_buf[i],
&chip->ecc.calc_buf[i]);
if (stat == -EBADMSG &&
(chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
@@ -3238,7 +2692,6 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
/**
* nand_read_page_hwecc - [REPLACEABLE] hardware ECC based page read function
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
* @oob_required: caller requires OOB data read to chip->oob_poi
@@ -3246,9 +2699,10 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
*
* Not for syndrome calculating ECC controllers which need a special oob layout.
*/
-static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+static int nand_read_page_hwecc(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int i, eccsize = chip->ecc.size, ret;
int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps;
@@ -3262,13 +2716,13 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
return ret;
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
- chip->ecc.hwctl(mtd, NAND_ECC_READ);
+ chip->ecc.hwctl(chip, NAND_ECC_READ);
ret = nand_read_data_op(chip, p, eccsize, false);
if (ret)
return ret;
- chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+ chip->ecc.calculate(chip, p, &ecc_calc[i]);
}
ret = nand_read_data_op(chip, chip->oob_poi, mtd->oobsize, false);
@@ -3286,7 +2740,7 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
int stat;
- stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
+ stat = chip->ecc.correct(chip, p, &ecc_code[i], &ecc_calc[i]);
if (stat == -EBADMSG &&
(chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
/* check for empty pages with bitflips */
@@ -3308,7 +2762,6 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
/**
* nand_read_page_hwecc_oob_first - [REPLACEABLE] hw ecc, read oob first
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
* @oob_required: caller requires OOB data read to chip->oob_poi
@@ -3320,9 +2773,10 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
* multiple ECC steps, follows the "infix ECC" scheme and reads/writes ECC from
* the data area, by overwriting the NAND manufacturer bad block markings.
*/
-static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
- struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
+static int nand_read_page_hwecc_oob_first(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int i, eccsize = chip->ecc.size, ret;
int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps;
@@ -3348,15 +2802,15 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
int stat;
- chip->ecc.hwctl(mtd, NAND_ECC_READ);
+ chip->ecc.hwctl(chip, NAND_ECC_READ);
ret = nand_read_data_op(chip, p, eccsize, false);
if (ret)
return ret;
- chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+ chip->ecc.calculate(chip, p, &ecc_calc[i]);
- stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL);
+ stat = chip->ecc.correct(chip, p, &ecc_code[i], NULL);
if (stat == -EBADMSG &&
(chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
/* check for empty pages with bitflips */
@@ -3378,7 +2832,6 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
/**
* nand_read_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page read
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
* @oob_required: caller requires OOB data read to chip->oob_poi
@@ -3387,9 +2840,10 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
* The hw generator calculates the error syndrome automatically. Therefore we
* need a special oob layout and handling.
*/
-static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+static int nand_read_page_syndrome(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int ret, i, eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps;
@@ -3405,7 +2859,7 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
int stat;
- chip->ecc.hwctl(mtd, NAND_ECC_READ);
+ chip->ecc.hwctl(chip, NAND_ECC_READ);
ret = nand_read_data_op(chip, p, eccsize, false);
if (ret)
@@ -3420,13 +2874,13 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
oob += chip->ecc.prepad;
}
- chip->ecc.hwctl(mtd, NAND_ECC_READSYN);
+ chip->ecc.hwctl(chip, NAND_ECC_READSYN);
ret = nand_read_data_op(chip, oob, eccbytes, false);
if (ret)
return ret;
- stat = chip->ecc.correct(mtd, p, oob, NULL);
+ stat = chip->ecc.correct(chip, p, oob, NULL);
oob += eccbytes;
@@ -3502,17 +2956,15 @@ static uint8_t *nand_transfer_oob(struct mtd_info *mtd, uint8_t *oob,
/**
* nand_setup_read_retry - [INTERN] Set the READ RETRY mode
- * @mtd: MTD device structure
+ * @chip: NAND chip object
* @retry_mode: the retry mode to use
*
* Some vendors supply a special command to shift the Vt threshold, to be used
* when there are too many bitflips in a page (i.e., ECC error). After setting
* a new threshold, the host should retry reading the page.
*/
-static int nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
+static int nand_setup_read_retry(struct nand_chip *chip, int retry_mode)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
-
pr_debug("setting READ RETRY mode %d\n", retry_mode);
if (retry_mode >= chip->read_retries)
@@ -3521,7 +2973,18 @@ static int nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
if (!chip->setup_read_retry)
return -EOPNOTSUPP;
- return chip->setup_read_retry(mtd, retry_mode);
+ return chip->setup_read_retry(chip, retry_mode);
+}
+
+static void nand_wait_readrdy(struct nand_chip *chip)
+{
+ const struct nand_sdr_timings *sdr;
+
+ if (!(chip->options & NAND_NEED_READRDY))
+ return;
+
+ sdr = nand_get_sdr_timings(&chip->data_interface);
+ WARN_ON(nand_wait_rdy_op(chip, PSEC_TO_MSEC(sdr->tR_max), 0));
}
/**
@@ -3549,7 +3012,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
bool ecc_fail = false;
chipnr = (int)(from >> chip->chip_shift);
- chip->select_chip(mtd, chipnr);
+ chip->select_chip(chip, chipnr);
realpage = (int)(from >> chip->page_shift);
page = realpage & chip->pagemask;
@@ -3589,16 +3052,15 @@ read_retry:
* the read methods return max bitflips per ecc step.
*/
if (unlikely(ops->mode == MTD_OPS_RAW))
- ret = chip->ecc.read_page_raw(mtd, chip, bufpoi,
+ ret = chip->ecc.read_page_raw(chip, bufpoi,
oob_required,
page);
else if (!aligned && NAND_HAS_SUBPAGE_READ(chip) &&
!oob)
- ret = chip->ecc.read_subpage(mtd, chip,
- col, bytes, bufpoi,
- page);
+ ret = chip->ecc.read_subpage(chip, col, bytes,
+ bufpoi, page);
else
- ret = chip->ecc.read_page(mtd, chip, bufpoi,
+ ret = chip->ecc.read_page(chip, bufpoi,
oob_required, page);
if (ret < 0) {
if (use_bufpoi)
@@ -3631,18 +3093,12 @@ read_retry:
}
}
- if (chip->options & NAND_NEED_READRDY) {
- /* Apply delay or wait for ready/busy pin */
- if (!chip->dev_ready)
- udelay(chip->chip_delay);
- else
- nand_wait_ready(mtd);
- }
+ nand_wait_readrdy(chip);
if (mtd->ecc_stats.failed - ecc_failures) {
if (retry_mode + 1 < chip->read_retries) {
retry_mode++;
- ret = nand_setup_read_retry(mtd,
+ ret = nand_setup_read_retry(chip,
retry_mode);
if (ret < 0)
break;
@@ -3669,7 +3125,7 @@ read_retry:
/* Reset to retry mode 0 */
if (retry_mode) {
- ret = nand_setup_read_retry(mtd, 0);
+ ret = nand_setup_read_retry(chip, 0);
if (ret < 0)
break;
retry_mode = 0;
@@ -3687,11 +3143,11 @@ read_retry:
/* Check, if we cross a chip boundary */
if (!page) {
chipnr++;
- chip->select_chip(mtd, -1);
- chip->select_chip(mtd, chipnr);
+ chip->select_chip(chip, -1);
+ chip->select_chip(chip, chipnr);
}
}
- chip->select_chip(mtd, -1);
+ chip->select_chip(chip, -1);
ops->retlen = ops->len - (size_t) readlen;
if (oob)
@@ -3708,12 +3164,13 @@ read_retry:
/**
* nand_read_oob_std - [REPLACEABLE] the most common OOB data read function
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @page: page number to read
*/
-int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page)
+int nand_read_oob_std(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
return nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
}
EXPORT_SYMBOL(nand_read_oob_std);
@@ -3721,13 +3178,12 @@ EXPORT_SYMBOL(nand_read_oob_std);
/**
* nand_read_oob_syndrome - [REPLACEABLE] OOB data read function for HW ECC
* with syndromes
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @page: page number to read
*/
-int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int nand_read_oob_syndrome(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int length = mtd->oobsize;
int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
int eccsize = chip->ecc.size;
@@ -3772,16 +3228,16 @@ int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
return 0;
}
-EXPORT_SYMBOL(nand_read_oob_syndrome);
/**
* nand_write_oob_std - [REPLACEABLE] the most common OOB data write function
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @page: page number to write
*/
-int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page)
+int nand_write_oob_std(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
return nand_prog_page_op(chip, page, mtd->writesize, chip->oob_poi,
mtd->oobsize);
}
@@ -3790,13 +3246,12 @@ EXPORT_SYMBOL(nand_write_oob_std);
/**
* nand_write_oob_syndrome - [REPLACEABLE] OOB data write function for HW ECC
* with syndrome - only for large page flash
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @page: page number to write
*/
-int nand_write_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int nand_write_oob_syndrome(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
int eccsize = chip->ecc.size, length = mtd->oobsize;
int ret, i, len, pos, sndcmd = 0, steps = chip->ecc.steps;
@@ -3860,7 +3315,6 @@ int nand_write_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
return nand_prog_page_end_op(chip);
}
-EXPORT_SYMBOL(nand_write_oob_syndrome);
/**
* nand_do_read_oob - [INTERN] NAND read out-of-band
@@ -3890,7 +3344,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
len = mtd_oobavail(mtd, ops);
chipnr = (int)(from >> chip->chip_shift);
- chip->select_chip(mtd, chipnr);
+ chip->select_chip(chip, chipnr);
/* Shift to get page */
realpage = (int)(from >> chip->page_shift);
@@ -3898,9 +3352,9 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
while (1) {
if (ops->mode == MTD_OPS_RAW)
- ret = chip->ecc.read_oob_raw(mtd, chip, page);
+ ret = chip->ecc.read_oob_raw(chip, page);
else
- ret = chip->ecc.read_oob(mtd, chip, page);
+ ret = chip->ecc.read_oob(chip, page);
if (ret < 0)
break;
@@ -3908,13 +3362,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
len = min(len, readlen);
buf = nand_transfer_oob(mtd, buf, ops, len);
- if (chip->options & NAND_NEED_READRDY) {
- /* Apply delay or wait for ready/busy pin */
- if (!chip->dev_ready)
- udelay(chip->chip_delay);
- else
- nand_wait_ready(mtd);
- }
+ nand_wait_readrdy(chip);
max_bitflips = max_t(unsigned int, max_bitflips, ret);
@@ -3929,11 +3377,11 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
/* Check, if we cross a chip boundary */
if (!page) {
chipnr++;
- chip->select_chip(mtd, -1);
- chip->select_chip(mtd, chipnr);
+ chip->select_chip(chip, -1);
+ chip->select_chip(chip, chipnr);
}
}
- chip->select_chip(mtd, -1);
+ chip->select_chip(chip, -1);
ops->oobretlen = ops->ooblen - readlen;
@@ -3979,7 +3427,6 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
/**
* nand_write_page_raw_notsupp - dummy raw page write function
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: data buffer
* @oob_required: must write chip->oob_poi to OOB
@@ -3987,16 +3434,14 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
*
* Returns -ENOTSUPP unconditionally.
*/
-int nand_write_page_raw_notsupp(struct mtd_info *mtd, struct nand_chip *chip,
- const u8 *buf, int oob_required, int page)
+int nand_write_page_raw_notsupp(struct nand_chip *chip, const u8 *buf,
+ int oob_required, int page)
{
return -ENOTSUPP;
}
-EXPORT_SYMBOL(nand_write_page_raw_notsupp);
/**
* nand_write_page_raw - [INTERN] raw page write function
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: data buffer
* @oob_required: must write chip->oob_poi to OOB
@@ -4004,9 +3449,10 @@ EXPORT_SYMBOL(nand_write_page_raw_notsupp);
*
* Not for syndrome calculating ECC controllers, which use a special oob layout.
*/
-int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required, int page)
+int nand_write_page_raw(struct nand_chip *chip, const uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int ret;
ret = nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
@@ -4026,7 +3472,6 @@ EXPORT_SYMBOL(nand_write_page_raw);
/**
* nand_write_page_raw_syndrome - [INTERN] raw page write function
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: data buffer
* @oob_required: must write chip->oob_poi to OOB
@@ -4034,11 +3479,11 @@ EXPORT_SYMBOL(nand_write_page_raw);
*
* We need a special oob layout and handling even when ECC isn't checked.
*/
-static int nand_write_page_raw_syndrome(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int nand_write_page_raw_syndrome(struct nand_chip *chip,
const uint8_t *buf, int oob_required,
int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
uint8_t *oob = chip->oob_poi;
@@ -4091,16 +3536,15 @@ static int nand_write_page_raw_syndrome(struct mtd_info *mtd,
}
/**
* nand_write_page_swecc - [REPLACEABLE] software ECC based page write function
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: data buffer
* @oob_required: must write chip->oob_poi to OOB
* @page: page number to write
*/
-static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required,
- int page)
+static int nand_write_page_swecc(struct nand_chip *chip, const uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int i, eccsize = chip->ecc.size, ret;
int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps;
@@ -4109,28 +3553,27 @@ static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
/* Software ECC calculation */
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
- chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+ chip->ecc.calculate(chip, p, &ecc_calc[i]);
ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
chip->ecc.total);
if (ret)
return ret;
- return chip->ecc.write_page_raw(mtd, chip, buf, 1, page);
+ return chip->ecc.write_page_raw(chip, buf, 1, page);
}
/**
* nand_write_page_hwecc - [REPLACEABLE] hardware ECC based page write function
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: data buffer
* @oob_required: must write chip->oob_poi to OOB
* @page: page number to write
*/
-static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required,
- int page)
+static int nand_write_page_hwecc(struct nand_chip *chip, const uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int i, eccsize = chip->ecc.size, ret;
int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps;
@@ -4142,13 +3585,13 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
return ret;
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
- chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+ chip->ecc.hwctl(chip, NAND_ECC_WRITE);
ret = nand_write_data_op(chip, p, eccsize, false);
if (ret)
return ret;
- chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+ chip->ecc.calculate(chip, p, &ecc_calc[i]);
}
ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
@@ -4166,7 +3609,6 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
/**
* nand_write_subpage_hwecc - [REPLACEABLE] hardware ECC based subpage write
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @offset: column address of subpage within the page
* @data_len: data length
@@ -4174,11 +3616,11 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
* @oob_required: must write chip->oob_poi to OOB
* @page: page number to write
*/
-static int nand_write_subpage_hwecc(struct mtd_info *mtd,
- struct nand_chip *chip, uint32_t offset,
- uint32_t data_len, const uint8_t *buf,
- int oob_required, int page)
+static int nand_write_subpage_hwecc(struct nand_chip *chip, uint32_t offset,
+ uint32_t data_len, const uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
uint8_t *oob_buf = chip->oob_poi;
uint8_t *ecc_calc = chip->ecc.calc_buf;
int ecc_size = chip->ecc.size;
@@ -4195,7 +3637,7 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd,
for (step = 0; step < ecc_steps; step++) {
/* configure controller for WRITE access */
- chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+ chip->ecc.hwctl(chip, NAND_ECC_WRITE);
/* write data (untouched subpages already masked by 0xFF) */
ret = nand_write_data_op(chip, buf, ecc_size, false);
@@ -4206,7 +3648,7 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd,
if ((step < start_step) || (step > end_step))
memset(ecc_calc, 0xff, ecc_bytes);
else
- chip->ecc.calculate(mtd, buf, ecc_calc);
+ chip->ecc.calculate(chip, buf, ecc_calc);
/* mask OOB of un-touched subpages by padding 0xFF */
/* if oob_required, preserve OOB metadata of written subpage */
@@ -4237,7 +3679,6 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd,
/**
* nand_write_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page write
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: data buffer
* @oob_required: must write chip->oob_poi to OOB
@@ -4246,11 +3687,10 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd,
* The hw generator calculates the error syndrome automatically. Therefore we
* need a special oob layout and handling.
*/
-static int nand_write_page_syndrome(struct mtd_info *mtd,
- struct nand_chip *chip,
- const uint8_t *buf, int oob_required,
- int page)
+static int nand_write_page_syndrome(struct nand_chip *chip, const uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int i, eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps;
@@ -4263,7 +3703,7 @@ static int nand_write_page_syndrome(struct mtd_info *mtd,
return ret;
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
- chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+ chip->ecc.hwctl(chip, NAND_ECC_WRITE);
ret = nand_write_data_op(chip, p, eccsize, false);
if (ret)
@@ -4278,7 +3718,7 @@ static int nand_write_page_syndrome(struct mtd_info *mtd,
oob += chip->ecc.prepad;
}
- chip->ecc.calculate(mtd, p, oob);
+ chip->ecc.calculate(chip, p, oob);
ret = nand_write_data_op(chip, oob, eccbytes, false);
if (ret)
@@ -4331,14 +3771,13 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
subpage = 0;
if (unlikely(raw))
- status = chip->ecc.write_page_raw(mtd, chip, buf,
- oob_required, page);
+ status = chip->ecc.write_page_raw(chip, buf, oob_required,
+ page);
else if (subpage)
- status = chip->ecc.write_subpage(mtd, chip, offset, data_len,
- buf, oob_required, page);
+ status = chip->ecc.write_subpage(chip, offset, data_len, buf,
+ oob_required, page);
else
- status = chip->ecc.write_page(mtd, chip, buf, oob_required,
- page);
+ status = chip->ecc.write_page(chip, buf, oob_required, page);
if (status < 0)
return status;
@@ -4423,7 +3862,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
column = to & (mtd->writesize - 1);
chipnr = (int)(to >> chip->chip_shift);
- chip->select_chip(mtd, chipnr);
+ chip->select_chip(chip, chipnr);
/* Check, if it is write protected */
if (nand_check_wp(mtd)) {
@@ -4499,8 +3938,8 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
/* Check, if we cross a chip boundary */
if (!page) {
chipnr++;
- chip->select_chip(mtd, -1);
- chip->select_chip(mtd, chipnr);
+ chip->select_chip(chip, -1);
+ chip->select_chip(chip, chipnr);
}
}
@@ -4509,7 +3948,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
ops->oobretlen = ops->ooblen;
err_out:
- chip->select_chip(mtd, -1);
+ chip->select_chip(chip, -1);
return ret;
}
@@ -4535,10 +3974,10 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
/* Grab the device */
panic_nand_get_device(chip, mtd, FL_WRITING);
- chip->select_chip(mtd, chipnr);
+ chip->select_chip(chip, chipnr);
/* Wait for the device to get ready */
- panic_nand_wait(mtd, chip, 400);
+ panic_nand_wait(chip, 400);
memset(&ops, 0, sizeof(ops));
ops.len = len;
@@ -4587,14 +4026,14 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
*/
nand_reset(chip, chipnr);
- chip->select_chip(mtd, chipnr);
+ chip->select_chip(chip, chipnr);
/* Shift to get page */
page = (int)(to >> chip->page_shift);
/* Check, if it is write protected */
if (nand_check_wp(mtd)) {
- chip->select_chip(mtd, -1);
+ chip->select_chip(chip, -1);
return -EROFS;
}
@@ -4605,11 +4044,11 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
nand_fill_oob(mtd, ops->oobbuf, ops->ooblen, ops);
if (ops->mode == MTD_OPS_RAW)
- status = chip->ecc.write_oob_raw(mtd, chip, page & chip->pagemask);
+ status = chip->ecc.write_oob_raw(chip, page & chip->pagemask);
else
- status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask);
+ status = chip->ecc.write_oob(chip, page & chip->pagemask);
- chip->select_chip(mtd, -1);
+ chip->select_chip(chip, -1);
if (status)
return status;
@@ -4656,14 +4095,13 @@ out:
/**
* single_erase - [GENERIC] NAND standard block erase command function
- * @mtd: MTD device structure
+ * @chip: NAND chip object
* @page: the page address of the block which will be erased
*
* Standard erase command for NAND chips. Returns NAND status.
*/
-static int single_erase(struct mtd_info *mtd, int page)
+static int single_erase(struct nand_chip *chip, int page)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
unsigned int eraseblock;
/* Send commands to erase a block */
@@ -4681,22 +4119,22 @@ static int single_erase(struct mtd_info *mtd, int page)
*/
static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)
{
- return nand_erase_nand(mtd, instr, 0);
+ return nand_erase_nand(mtd_to_nand(mtd), instr, 0);
}
/**
* nand_erase_nand - [INTERN] erase block(s)
- * @mtd: MTD device structure
+ * @chip: NAND chip object
* @instr: erase instruction
* @allowbbt: allow erasing the bbt area
*
* Erase one ore more blocks.
*/
-int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
+int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr,
int allowbbt)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int page, status, pages_per_block, ret, chipnr;
- struct nand_chip *chip = mtd_to_nand(mtd);
loff_t len;
pr_debug("%s: start = 0x%012llx, len = %llu\n",
@@ -4717,7 +4155,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
pages_per_block = 1 << (chip->phys_erase_shift - chip->page_shift);
/* Select the NAND device */
- chip->select_chip(mtd, chipnr);
+ chip->select_chip(chip, chipnr);
/* Check, if it is write protected */
if (nand_check_wp(mtd)) {
@@ -4748,7 +4186,11 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
(page + pages_per_block))
chip->pagebuf = -1;
- status = chip->erase(mtd, page & chip->pagemask);
+ if (chip->legacy.erase)
+ status = chip->legacy.erase(chip,
+ page & chip->pagemask);
+ else
+ status = single_erase(chip, page & chip->pagemask);
/* See if block erase succeeded */
if (status) {
@@ -4767,8 +4209,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
/* Check, if we cross a chip boundary */
if (len && !(page & chip->pagemask)) {
chipnr++;
- chip->select_chip(mtd, -1);
- chip->select_chip(mtd, chipnr);
+ chip->select_chip(chip, -1);
+ chip->select_chip(chip, chipnr);
}
}
@@ -4776,7 +4218,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
erase_exit:
/* Deselect and wake up anyone waiting on the device */
- chip->select_chip(mtd, -1);
+ chip->select_chip(chip, -1);
nand_release_device(mtd);
/* Return more or less happy */
@@ -4812,11 +4254,11 @@ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
/* Select the NAND device */
nand_get_device(mtd, FL_READING);
- chip->select_chip(mtd, chipnr);
+ chip->select_chip(chip, chipnr);
ret = nand_block_checkbad(mtd, offs, 0);
- chip->select_chip(mtd, -1);
+ chip->select_chip(chip, -1);
nand_release_device(mtd);
return ret;
@@ -4879,51 +4321,6 @@ static int nand_max_bad_blocks(struct mtd_info *mtd, loff_t ofs, size_t len)
}
/**
- * nand_default_set_features- [REPLACEABLE] set NAND chip features
- * @mtd: MTD device structure
- * @chip: nand chip info structure
- * @addr: feature address.
- * @subfeature_param: the subfeature parameters, a four bytes array.
- */
-static int nand_default_set_features(struct mtd_info *mtd,
- struct nand_chip *chip, int addr,
- uint8_t *subfeature_param)
-{
- return nand_set_features_op(chip, addr, subfeature_param);
-}
-
-/**
- * nand_default_get_features- [REPLACEABLE] get NAND chip features
- * @mtd: MTD device structure
- * @chip: nand chip info structure
- * @addr: feature address.
- * @subfeature_param: the subfeature parameters, a four bytes array.
- */
-static int nand_default_get_features(struct mtd_info *mtd,
- struct nand_chip *chip, int addr,
- uint8_t *subfeature_param)
-{
- return nand_get_features_op(chip, addr, subfeature_param);
-}
-
-/**
- * nand_get_set_features_notsupp - set/get features stub returning -ENOTSUPP
- * @mtd: MTD device structure
- * @chip: nand chip info structure
- * @addr: feature address.
- * @subfeature_param: the subfeature parameters, a four bytes array.
- *
- * Should be used by NAND controller drivers that do not support the SET/GET
- * FEATURES operations.
- */
-int nand_get_set_features_notsupp(struct mtd_info *mtd, struct nand_chip *chip,
- int addr, u8 *subfeature_param)
-{
- return -ENOTSUPP;
-}
-EXPORT_SYMBOL(nand_get_set_features_notsupp);
-
-/**
* nand_suspend - [MTD Interface] Suspend the NAND flash
* @mtd: MTD device structure
*/
@@ -4960,44 +4357,7 @@ static void nand_shutdown(struct mtd_info *mtd)
/* Set default functions */
static void nand_set_defaults(struct nand_chip *chip)
{
- unsigned int busw = chip->options & NAND_BUSWIDTH_16;
-
- /* check for proper chip_delay setup, set 20us if not */
- if (!chip->chip_delay)
- chip->chip_delay = 20;
-
- /* check, if a user supplied command function given */
- if (!chip->cmdfunc && !chip->exec_op)
- chip->cmdfunc = nand_command;
-
- /* check, if a user supplied wait function given */
- if (chip->waitfunc == NULL)
- chip->waitfunc = nand_wait;
-
- if (!chip->select_chip)
- chip->select_chip = nand_select_chip;
-
- /* set for ONFI nand */
- if (!chip->set_features)
- chip->set_features = nand_default_set_features;
- if (!chip->get_features)
- chip->get_features = nand_default_get_features;
-
- /* If called twice, pointers that depend on busw may need to be reset */
- if (!chip->read_byte || chip->read_byte == nand_read_byte)
- chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;
- if (!chip->read_word)
- chip->read_word = nand_read_word;
- if (!chip->block_bad)
- chip->block_bad = nand_block_bad;
- if (!chip->block_markbad)
- chip->block_markbad = nand_default_block_markbad;
- if (!chip->write_buf || chip->write_buf == nand_write_buf)
- chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;
- if (!chip->write_byte || chip->write_byte == nand_write_byte)
- chip->write_byte = busw ? nand_write_byte16 : nand_write_byte;
- if (!chip->read_buf || chip->read_buf == nand_read_buf)
- chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
+ nand_legacy_set_defaults(chip);
if (!chip->controller) {
chip->controller = &chip->dummy_controller;
@@ -5009,7 +4369,7 @@ static void nand_set_defaults(struct nand_chip *chip)
}
/* Sanitize ONFI strings so we can safely print them */
-static void sanitize_string(uint8_t *s, size_t len)
+void sanitize_string(uint8_t *s, size_t len)
{
ssize_t i;
@@ -5026,390 +4386,6 @@ static void sanitize_string(uint8_t *s, size_t len)
strim(s);
}
-static u16 onfi_crc16(u16 crc, u8 const *p, size_t len)
-{
- int i;
- while (len--) {
- crc ^= *p++ << 8;
- for (i = 0; i < 8; i++)
- crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0);
- }
-
- return crc;
-}
-
-/* Parse the Extended Parameter Page. */
-static int nand_flash_detect_ext_param_page(struct nand_chip *chip,
- struct nand_onfi_params *p)
-{
- struct onfi_ext_param_page *ep;
- struct onfi_ext_section *s;
- struct onfi_ext_ecc_info *ecc;
- uint8_t *cursor;
- int ret;
- int len;
- int i;
-
- len = le16_to_cpu(p->ext_param_page_length) * 16;
- ep = kmalloc(len, GFP_KERNEL);
- if (!ep)
- return -ENOMEM;
-
- /* Send our own NAND_CMD_PARAM. */
- ret = nand_read_param_page_op(chip, 0, NULL, 0);
- if (ret)
- goto ext_out;
-
- /* Use the Change Read Column command to skip the ONFI param pages. */
- ret = nand_change_read_column_op(chip,
- sizeof(*p) * p->num_of_param_pages,
- ep, len, true);
- if (ret)
- goto ext_out;
-
- ret = -EINVAL;
- if ((onfi_crc16(ONFI_CRC_BASE, ((uint8_t *)ep) + 2, len - 2)
- != le16_to_cpu(ep->crc))) {
- pr_debug("fail in the CRC.\n");
- goto ext_out;
- }
-
- /*
- * Check the signature.
- * Do not strictly follow the ONFI spec, maybe changed in future.
- */
- if (strncmp(ep->sig, "EPPS", 4)) {
- pr_debug("The signature is invalid.\n");
- goto ext_out;
- }
-
- /* find the ECC section. */
- cursor = (uint8_t *)(ep + 1);
- for (i = 0; i < ONFI_EXT_SECTION_MAX; i++) {
- s = ep->sections + i;
- if (s->type == ONFI_SECTION_TYPE_2)
- break;
- cursor += s->length * 16;
- }
- if (i == ONFI_EXT_SECTION_MAX) {
- pr_debug("We can not find the ECC section.\n");
- goto ext_out;
- }
-
- /* get the info we want. */
- ecc = (struct onfi_ext_ecc_info *)cursor;
-
- if (!ecc->codeword_size) {
- pr_debug("Invalid codeword size\n");
- goto ext_out;
- }
-
- chip->ecc_strength_ds = ecc->ecc_bits;
- chip->ecc_step_ds = 1 << ecc->codeword_size;
- ret = 0;
-
-ext_out:
- kfree(ep);
- return ret;
-}
-
-/*
- * Recover data with bit-wise majority
- */
-static void nand_bit_wise_majority(const void **srcbufs,
- unsigned int nsrcbufs,
- void *dstbuf,
- unsigned int bufsize)
-{
- int i, j, k;
-
- for (i = 0; i < bufsize; i++) {
- u8 val = 0;
-
- for (j = 0; j < 8; j++) {
- unsigned int cnt = 0;
-
- for (k = 0; k < nsrcbufs; k++) {
- const u8 *srcbuf = srcbufs[k];
-
- if (srcbuf[i] & BIT(j))
- cnt++;
- }
-
- if (cnt > nsrcbufs / 2)
- val |= BIT(j);
- }
-
- ((u8 *)dstbuf)[i] = val;
- }
-}
-
-/*
- * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise.
- */
-static int nand_flash_detect_onfi(struct nand_chip *chip)
-{
- struct mtd_info *mtd = nand_to_mtd(chip);
- struct nand_onfi_params *p;
- struct onfi_params *onfi;
- int onfi_version = 0;
- char id[4];
- int i, ret, val;
-
- /* Try ONFI for unknown chip or LP */
- ret = nand_readid_op(chip, 0x20, id, sizeof(id));
- if (ret || strncmp(id, "ONFI", 4))
- return 0;
-
- /* ONFI chip: allocate a buffer to hold its parameter page */
- p = kzalloc((sizeof(*p) * 3), GFP_KERNEL);
- if (!p)
- return -ENOMEM;
-
- ret = nand_read_param_page_op(chip, 0, NULL, 0);
- if (ret) {
- ret = 0;
- goto free_onfi_param_page;
- }
-
- for (i = 0; i < 3; i++) {
- ret = nand_read_data_op(chip, &p[i], sizeof(*p), true);
- if (ret) {
- ret = 0;
- goto free_onfi_param_page;
- }
-
- if (onfi_crc16(ONFI_CRC_BASE, (u8 *)&p[i], 254) ==
- le16_to_cpu(p->crc)) {
- if (i)
- memcpy(p, &p[i], sizeof(*p));
- break;
- }
- }
-
- if (i == 3) {
- const void *srcbufs[3] = {p, p + 1, p + 2};
-
- pr_warn("Could not find a valid ONFI parameter page, trying bit-wise majority to recover it\n");
- nand_bit_wise_majority(srcbufs, ARRAY_SIZE(srcbufs), p,
- sizeof(*p));
-
- if (onfi_crc16(ONFI_CRC_BASE, (u8 *)p, 254) !=
- le16_to_cpu(p->crc)) {
- pr_err("ONFI parameter recovery failed, aborting\n");
- goto free_onfi_param_page;
- }
- }
-
- if (chip->manufacturer.desc && chip->manufacturer.desc->ops &&
- chip->manufacturer.desc->ops->fixup_onfi_param_page)
- chip->manufacturer.desc->ops->fixup_onfi_param_page(chip, p);
-
- /* Check version */
- val = le16_to_cpu(p->revision);
- if (val & ONFI_VERSION_2_3)
- onfi_version = 23;
- else if (val & ONFI_VERSION_2_2)
- onfi_version = 22;
- else if (val & ONFI_VERSION_2_1)
- onfi_version = 21;
- else if (val & ONFI_VERSION_2_0)
- onfi_version = 20;
- else if (val & ONFI_VERSION_1_0)
- onfi_version = 10;
-
- if (!onfi_version) {
- pr_info("unsupported ONFI version: %d\n", val);
- goto free_onfi_param_page;
- }
-
- sanitize_string(p->manufacturer, sizeof(p->manufacturer));
- sanitize_string(p->model, sizeof(p->model));
- chip->parameters.model = kstrdup(p->model, GFP_KERNEL);
- if (!chip->parameters.model) {
- ret = -ENOMEM;
- goto free_onfi_param_page;
- }
-
- mtd->writesize = le32_to_cpu(p->byte_per_page);
-
- /*
- * pages_per_block and blocks_per_lun may not be a power-of-2 size
- * (don't ask me who thought of this...). MTD assumes that these
- * dimensions will be power-of-2, so just truncate the remaining area.
- */
- mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
- mtd->erasesize *= mtd->writesize;
-
- mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
-
- /* See erasesize comment */
- chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
- chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
- chip->bits_per_cell = p->bits_per_cell;
-
- chip->max_bb_per_die = le16_to_cpu(p->bb_per_lun);
- chip->blocks_per_die = le32_to_cpu(p->blocks_per_lun);
-
- if (le16_to_cpu(p->features) & ONFI_FEATURE_16_BIT_BUS)
- chip->options |= NAND_BUSWIDTH_16;
-
- if (p->ecc_bits != 0xff) {
- chip->ecc_strength_ds = p->ecc_bits;
- chip->ecc_step_ds = 512;
- } else if (onfi_version >= 21 &&
- (le16_to_cpu(p->features) & ONFI_FEATURE_EXT_PARAM_PAGE)) {
-
- /*
- * The nand_flash_detect_ext_param_page() uses the
- * Change Read Column command which maybe not supported
- * by the chip->cmdfunc. So try to update the chip->cmdfunc
- * now. We do not replace user supplied command function.
- */
- if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
- chip->cmdfunc = nand_command_lp;
-
- /* The Extended Parameter Page is supported since ONFI 2.1. */
- if (nand_flash_detect_ext_param_page(chip, p))
- pr_warn("Failed to detect ONFI extended param page\n");
- } else {
- pr_warn("Could not retrieve ONFI ECC requirements\n");
- }
-
- /* Save some parameters from the parameter page for future use */
- if (le16_to_cpu(p->opt_cmd) & ONFI_OPT_CMD_SET_GET_FEATURES) {
- chip->parameters.supports_set_get_features = true;
- bitmap_set(chip->parameters.get_feature_list,
- ONFI_FEATURE_ADDR_TIMING_MODE, 1);
- bitmap_set(chip->parameters.set_feature_list,
- ONFI_FEATURE_ADDR_TIMING_MODE, 1);
- }
-
- onfi = kzalloc(sizeof(*onfi), GFP_KERNEL);
- if (!onfi) {
- ret = -ENOMEM;
- goto free_model;
- }
-
- onfi->version = onfi_version;
- onfi->tPROG = le16_to_cpu(p->t_prog);
- 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->vendor_revision = le16_to_cpu(p->vendor_revision);
- memcpy(onfi->vendor, p->vendor, sizeof(p->vendor));
- chip->parameters.onfi = onfi;
-
- /* Identification done, free the full ONFI parameter page and exit */
- kfree(p);
-
- return 1;
-
-free_model:
- kfree(chip->parameters.model);
-free_onfi_param_page:
- kfree(p);
-
- return ret;
-}
-
-/*
- * Check if the NAND chip is JEDEC compliant, returns 1 if it is, 0 otherwise.
- */
-static int nand_flash_detect_jedec(struct nand_chip *chip)
-{
- struct mtd_info *mtd = nand_to_mtd(chip);
- struct nand_jedec_params *p;
- struct jedec_ecc_info *ecc;
- int jedec_version = 0;
- char id[5];
- int i, val, ret;
-
- /* Try JEDEC for unknown chip or LP */
- ret = nand_readid_op(chip, 0x40, id, sizeof(id));
- if (ret || strncmp(id, "JEDEC", sizeof(id)))
- return 0;
-
- /* JEDEC chip: allocate a buffer to hold its parameter page */
- p = kzalloc(sizeof(*p), GFP_KERNEL);
- if (!p)
- return -ENOMEM;
-
- ret = nand_read_param_page_op(chip, 0x40, NULL, 0);
- if (ret) {
- ret = 0;
- goto free_jedec_param_page;
- }
-
- for (i = 0; i < 3; i++) {
- ret = nand_read_data_op(chip, p, sizeof(*p), true);
- if (ret) {
- ret = 0;
- goto free_jedec_param_page;
- }
-
- if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 510) ==
- le16_to_cpu(p->crc))
- break;
- }
-
- if (i == 3) {
- pr_err("Could not find valid JEDEC parameter page; aborting\n");
- goto free_jedec_param_page;
- }
-
- /* Check version */
- val = le16_to_cpu(p->revision);
- if (val & (1 << 2))
- jedec_version = 10;
- else if (val & (1 << 1))
- jedec_version = 1; /* vendor specific version */
-
- if (!jedec_version) {
- pr_info("unsupported JEDEC version: %d\n", val);
- goto free_jedec_param_page;
- }
-
- sanitize_string(p->manufacturer, sizeof(p->manufacturer));
- sanitize_string(p->model, sizeof(p->model));
- chip->parameters.model = kstrdup(p->model, GFP_KERNEL);
- if (!chip->parameters.model) {
- ret = -ENOMEM;
- goto free_jedec_param_page;
- }
-
- mtd->writesize = le32_to_cpu(p->byte_per_page);
-
- /* Please reference to the comment for nand_flash_detect_onfi. */
- mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
- mtd->erasesize *= mtd->writesize;
-
- mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
-
- /* Please reference to the comment for nand_flash_detect_onfi. */
- chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
- chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
- chip->bits_per_cell = p->bits_per_cell;
-
- if (le16_to_cpu(p->features) & JEDEC_FEATURE_16_BIT_BUS)
- chip->options |= NAND_BUSWIDTH_16;
-
- /* ECC info */
- ecc = &p->ecc_info[0];
-
- if (ecc->codeword_size >= 9) {
- chip->ecc_strength_ds = ecc->ecc_bits;
- chip->ecc_step_ds = 1 << ecc->codeword_size;
- } else {
- pr_warn("Invalid codeword size\n");
- }
-
-free_jedec_param_page:
- kfree(p);
- return ret;
-}
-
/*
* nand_id_has_period - Check if an ID string has a given wraparound period
* @id_data: the ID string
@@ -5625,6 +4601,12 @@ static void nand_manufacturer_cleanup(struct nand_chip *chip)
chip->manufacturer.desc->ops->cleanup(chip);
}
+static const char *
+nand_manufacturer_name(const struct nand_manufacturer *manufacturer)
+{
+ return manufacturer ? manufacturer->name : "Unknown";
+}
+
/*
* Get the flash and manufacturer id and lookup if the type is supported.
*/
@@ -5645,7 +4627,7 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
return ret;
/* Select the device */
- chip->select_chip(mtd, 0);
+ chip->select_chip(chip, 0);
/* Send the command for reading device ID */
ret = nand_readid_op(chip, 0, id_data, 2);
@@ -5709,14 +4691,14 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
if (!type->name || !type->pagesize) {
/* Check if the chip is ONFI compliant */
- ret = nand_flash_detect_onfi(chip);
+ ret = nand_onfi_detect(chip);
if (ret < 0)
return ret;
else if (ret)
goto ident_done;
/* Check if the chip is JEDEC compliant */
- ret = nand_flash_detect_jedec(chip);
+ ret = nand_jedec_detect(chip);
if (ret < 0)
return ret;
else if (ret)
@@ -5783,11 +4765,8 @@ ident_done:
chip->options |= NAND_ROW_ADDR_3;
chip->badblockbits = 8;
- chip->erase = single_erase;
- /* Do not replace user supplied command function! */
- if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
- chip->cmdfunc = nand_command_lp;
+ nand_legacy_adjust_cmdfunc(chip);
pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
maf_id, dev_id);
@@ -5953,7 +4932,7 @@ static int nand_dt_init(struct nand_chip *chip)
/**
* nand_scan_ident - Scan for the NAND device
- * @mtd: MTD device structure
+ * @chip: NAND chip object
* @maxchips: number of chips to scan for
* @table: alternative NAND ID table
*
@@ -5965,11 +4944,12 @@ static int nand_dt_init(struct nand_chip *chip)
* prevented dynamic allocations during this phase which was unconvenient and
* as been banned for the benefit of the ->init_ecc()/cleanup_ecc() hooks.
*/
-static int nand_scan_ident(struct mtd_info *mtd, int maxchips,
+static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips,
struct nand_flash_dev *table)
{
- int i, nand_maf_id, nand_dev_id;
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ int nand_maf_id, nand_dev_id;
+ unsigned int i;
int ret;
/* Enforce the right timings for reset/detection */
@@ -5982,21 +4962,15 @@ static int nand_scan_ident(struct mtd_info *mtd, int maxchips,
if (!mtd->name && mtd->dev.parent)
mtd->name = dev_name(mtd->dev.parent);
- /*
- * ->cmdfunc() is legacy and will only be used if ->exec_op() is not
- * populated.
- */
- if (!chip->exec_op) {
- /*
- * Default functions assigned for ->cmdfunc() and
- * ->select_chip() both expect ->cmd_ctrl() to be populated.
- */
- if ((!chip->cmdfunc || !chip->select_chip) && !chip->cmd_ctrl) {
- pr_err("->cmd_ctrl() should be provided\n");
- return -EINVAL;
- }
+ if (chip->exec_op && !chip->select_chip) {
+ pr_err("->select_chip() is mandatory when implementing ->exec_op()\n");
+ return -EINVAL;
}
+ ret = nand_legacy_check_hooks(chip);
+ if (ret)
+ return ret;
+
/* Set the default functions */
nand_set_defaults(chip);
@@ -6005,14 +4979,14 @@ static int nand_scan_ident(struct mtd_info *mtd, int maxchips,
if (ret) {
if (!(chip->options & NAND_SCAN_SILENT_NODEV))
pr_warn("No NAND device found\n");
- chip->select_chip(mtd, -1);
+ chip->select_chip(chip, -1);
return ret;
}
nand_maf_id = chip->id.data[0];
nand_dev_id = chip->id.data[1];
- chip->select_chip(mtd, -1);
+ chip->select_chip(chip, -1);
/* Check for a chip array */
for (i = 1; i < maxchips; i++) {
@@ -6021,15 +4995,15 @@ static int nand_scan_ident(struct mtd_info *mtd, int maxchips,
/* See comment in nand_get_flash_type for reset */
nand_reset(chip, i);
- chip->select_chip(mtd, i);
+ chip->select_chip(chip, i);
/* Send the command for reading device ID */
nand_readid_op(chip, 0, id, sizeof(id));
/* Read manufacturer and device IDs */
if (nand_maf_id != id[0] || nand_dev_id != id[1]) {
- chip->select_chip(mtd, -1);
+ chip->select_chip(chip, -1);
break;
}
- chip->select_chip(mtd, -1);
+ chip->select_chip(chip, -1);
}
if (i > 1)
pr_info("%d chips detected\n", i);
@@ -6070,6 +5044,10 @@ static int nand_set_ecc_soft_ops(struct mtd_info *mtd)
ecc->size = 256;
ecc->bytes = 3;
ecc->strength = 1;
+
+ if (IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC))
+ ecc->options |= NAND_ECC_SOFT_HAMMING_SM_ORDER;
+
return 0;
case NAND_ECC_BCH:
if (!mtd_nand_has_bch()) {
@@ -6423,15 +5401,15 @@ static bool nand_ecc_strength_good(struct mtd_info *mtd)
/**
* nand_scan_tail - Scan for the NAND device
- * @mtd: MTD device structure
+ * @chip: NAND chip object
*
* This is the second phase of the normal nand_scan() function. It fills out
* all the uninitialized function pointers with the defaults and scans for a
* bad block table if appropriate.
*/
-static int nand_scan_tail(struct mtd_info *mtd)
+static int nand_scan_tail(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_ecc_ctrl *ecc = &chip->ecc;
int ret, i;
@@ -6451,9 +5429,9 @@ static int nand_scan_tail(struct mtd_info *mtd)
* to explictly select the relevant die when interacting with the NAND
* chip.
*/
- chip->select_chip(mtd, 0);
+ chip->select_chip(chip, 0);
ret = nand_manufacturer_init(chip);
- chip->select_chip(mtd, -1);
+ chip->select_chip(chip, -1);
if (ret)
goto err_free_buf;
@@ -6770,33 +5748,31 @@ static void nand_detach(struct nand_chip *chip)
/**
* nand_scan_with_ids - [NAND Interface] Scan for the NAND device
- * @mtd: MTD device structure
- * @maxchips: number of chips to scan for. @nand_scan_ident() will not be run if
- * this parameter is zero (useful for specific drivers that must
- * handle this part of the process themselves, e.g docg4).
+ * @chip: NAND chip object
+ * @maxchips: number of chips to scan for.
* @ids: optional flash IDs table
*
* This fills out all the uninitialized function pointers with the defaults.
* The flash ID is read and the mtd/chip structures are filled with the
* appropriate values.
*/
-int nand_scan_with_ids(struct mtd_info *mtd, int maxchips,
+int nand_scan_with_ids(struct nand_chip *chip, unsigned int maxchips,
struct nand_flash_dev *ids)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
int ret;
- if (maxchips) {
- ret = nand_scan_ident(mtd, maxchips, ids);
- if (ret)
- return ret;
- }
+ if (!maxchips)
+ return -EINVAL;
+
+ ret = nand_scan_ident(chip, maxchips, ids);
+ if (ret)
+ return ret;
ret = nand_attach(chip);
if (ret)
goto cleanup_ident;
- ret = nand_scan_tail(mtd);
+ ret = nand_scan_tail(chip);
if (ret)
goto detach_chip;
@@ -6847,12 +5823,12 @@ EXPORT_SYMBOL_GPL(nand_cleanup);
/**
* nand_release - [NAND Interface] Unregister the MTD device and free resources
* held by the NAND device
- * @mtd: MTD device structure
+ * @chip: NAND chip object
*/
-void nand_release(struct mtd_info *mtd)
+void nand_release(struct nand_chip *chip)
{
- mtd_device_unregister(mtd);
- nand_cleanup(mtd_to_nand(mtd));
+ mtd_device_unregister(nand_to_mtd(chip));
+ nand_cleanup(chip);
}
EXPORT_SYMBOL_GPL(nand_release);
diff --git a/drivers/mtd/nand/raw/nand_bbt.c b/drivers/mtd/nand/raw/nand_bbt.c
index 39db352f8757..98a826838b60 100644
--- a/drivers/mtd/nand/raw/nand_bbt.c
+++ b/drivers/mtd/nand/raw/nand_bbt.c
@@ -61,13 +61,14 @@
#include <linux/types.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/bbm.h>
-#include <linux/mtd/rawnand.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/vmalloc.h>
#include <linux/export.h>
#include <linux/string.h>
+#include "internals.h"
+
#define BBT_BLOCK_GOOD 0x00
#define BBT_BLOCK_WORN 0x01
#define BBT_BLOCK_RESERVED 0x02
@@ -683,14 +684,13 @@ static void mark_bbt_block_bad(struct nand_chip *this,
struct nand_bbt_descr *td,
int chip, int block)
{
- struct mtd_info *mtd = nand_to_mtd(this);
loff_t to;
int res;
bbt_mark_entry(this, block, BBT_BLOCK_WORN);
to = (loff_t)block << this->bbt_erase_shift;
- res = this->block_markbad(mtd, to);
+ res = nand_markbad_bbm(this, to);
if (res)
pr_warn("nand_bbt: error %d while marking block %d bad\n",
res, block);
@@ -854,7 +854,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
memset(&einfo, 0, sizeof(einfo));
einfo.addr = to;
einfo.len = 1 << this->bbt_erase_shift;
- res = nand_erase_nand(mtd, &einfo, 1);
+ res = nand_erase_nand(this, &einfo, 1);
if (res < 0) {
pr_warn("nand_bbt: error while erasing BBT block %d\n",
res);
@@ -1388,12 +1388,11 @@ EXPORT_SYMBOL(nand_create_bbt);
/**
* nand_isreserved_bbt - [NAND Interface] Check if a block is reserved
- * @mtd: MTD device structure
+ * @this: NAND chip object
* @offs: offset in the device
*/
-int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs)
+int nand_isreserved_bbt(struct nand_chip *this, loff_t offs)
{
- struct nand_chip *this = mtd_to_nand(mtd);
int block;
block = (int)(offs >> this->bbt_erase_shift);
@@ -1402,13 +1401,12 @@ int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs)
/**
* nand_isbad_bbt - [NAND Interface] Check if a block is bad
- * @mtd: MTD device structure
+ * @this: NAND chip object
* @offs: offset in the device
* @allowbbt: allow access to bad block table region
*/
-int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
+int nand_isbad_bbt(struct nand_chip *this, loff_t offs, int allowbbt)
{
- struct nand_chip *this = mtd_to_nand(mtd);
int block, res;
block = (int)(offs >> this->bbt_erase_shift);
@@ -1430,12 +1428,12 @@ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
/**
* nand_markbad_bbt - [NAND Interface] Mark a block bad in the BBT
- * @mtd: MTD device structure
+ * @this: NAND chip object
* @offs: offset of the bad block
*/
-int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs)
+int nand_markbad_bbt(struct nand_chip *this, loff_t offs)
{
- struct nand_chip *this = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(this);
int block, ret = 0;
block = (int)(offs >> this->bbt_erase_shift);
diff --git a/drivers/mtd/nand/raw/nand_bch.c b/drivers/mtd/nand/raw/nand_bch.c
index b7387ace567a..574c0ca16160 100644
--- a/drivers/mtd/nand/raw/nand_bch.c
+++ b/drivers/mtd/nand/raw/nand_bch.c
@@ -43,14 +43,13 @@ struct nand_bch_control {
/**
* nand_bch_calculate_ecc - [NAND Interface] Calculate ECC for data block
- * @mtd: MTD block structure
+ * @chip: NAND chip object
* @buf: input buffer with raw data
* @code: output buffer with ECC
*/
-int nand_bch_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf,
+int nand_bch_calculate_ecc(struct nand_chip *chip, const unsigned char *buf,
unsigned char *code)
{
- const struct nand_chip *chip = mtd_to_nand(mtd);
struct nand_bch_control *nbc = chip->ecc.priv;
unsigned int i;
@@ -67,17 +66,16 @@ EXPORT_SYMBOL(nand_bch_calculate_ecc);
/**
* nand_bch_correct_data - [NAND Interface] Detect and correct bit error(s)
- * @mtd: MTD block structure
+ * @chip: NAND chip object
* @buf: raw data read from the chip
* @read_ecc: ECC from the chip
* @calc_ecc: the ECC calculated from raw data
*
* Detect and correct bit errors for a data byte block
*/
-int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
+int nand_bch_correct_data(struct nand_chip *chip, unsigned char *buf,
unsigned char *read_ecc, unsigned char *calc_ecc)
{
- const struct nand_chip *chip = mtd_to_nand(mtd);
struct nand_bch_control *nbc = chip->ecc.priv;
unsigned int *errloc = nbc->errloc;
int i, count;
diff --git a/drivers/mtd/nand/raw/nand_ecc.c b/drivers/mtd/nand/raw/nand_ecc.c
index 8e132edbc5ce..4f4347533058 100644
--- a/drivers/mtd/nand/raw/nand_ecc.c
+++ b/drivers/mtd/nand/raw/nand_ecc.c
@@ -132,9 +132,10 @@ static const char addressbits[256] = {
* @buf: input buffer with raw data
* @eccsize: data bytes per ECC step (256 or 512)
* @code: output buffer with ECC
+ * @sm_order: Smart Media byte ordering
*/
void __nand_calculate_ecc(const unsigned char *buf, unsigned int eccsize,
- unsigned char *code)
+ unsigned char *code, bool sm_order)
{
int i;
const uint32_t *bp = (uint32_t *)buf;
@@ -330,45 +331,26 @@ void __nand_calculate_ecc(const unsigned char *buf, unsigned int eccsize,
* possible, but benchmarks showed that on the system this is developed
* the code below is the fastest
*/
-#ifdef CONFIG_MTD_NAND_ECC_SMC
- code[0] =
- (invparity[rp7] << 7) |
- (invparity[rp6] << 6) |
- (invparity[rp5] << 5) |
- (invparity[rp4] << 4) |
- (invparity[rp3] << 3) |
- (invparity[rp2] << 2) |
- (invparity[rp1] << 1) |
- (invparity[rp0]);
- code[1] =
- (invparity[rp15] << 7) |
- (invparity[rp14] << 6) |
- (invparity[rp13] << 5) |
- (invparity[rp12] << 4) |
- (invparity[rp11] << 3) |
- (invparity[rp10] << 2) |
- (invparity[rp9] << 1) |
- (invparity[rp8]);
-#else
- code[1] =
- (invparity[rp7] << 7) |
- (invparity[rp6] << 6) |
- (invparity[rp5] << 5) |
- (invparity[rp4] << 4) |
- (invparity[rp3] << 3) |
- (invparity[rp2] << 2) |
- (invparity[rp1] << 1) |
- (invparity[rp0]);
- code[0] =
- (invparity[rp15] << 7) |
- (invparity[rp14] << 6) |
- (invparity[rp13] << 5) |
- (invparity[rp12] << 4) |
- (invparity[rp11] << 3) |
- (invparity[rp10] << 2) |
- (invparity[rp9] << 1) |
- (invparity[rp8]);
-#endif
+ if (sm_order) {
+ code[0] = (invparity[rp7] << 7) | (invparity[rp6] << 6) |
+ (invparity[rp5] << 5) | (invparity[rp4] << 4) |
+ (invparity[rp3] << 3) | (invparity[rp2] << 2) |
+ (invparity[rp1] << 1) | (invparity[rp0]);
+ code[1] = (invparity[rp15] << 7) | (invparity[rp14] << 6) |
+ (invparity[rp13] << 5) | (invparity[rp12] << 4) |
+ (invparity[rp11] << 3) | (invparity[rp10] << 2) |
+ (invparity[rp9] << 1) | (invparity[rp8]);
+ } else {
+ code[1] = (invparity[rp7] << 7) | (invparity[rp6] << 6) |
+ (invparity[rp5] << 5) | (invparity[rp4] << 4) |
+ (invparity[rp3] << 3) | (invparity[rp2] << 2) |
+ (invparity[rp1] << 1) | (invparity[rp0]);
+ code[0] = (invparity[rp15] << 7) | (invparity[rp14] << 6) |
+ (invparity[rp13] << 5) | (invparity[rp12] << 4) |
+ (invparity[rp11] << 3) | (invparity[rp10] << 2) |
+ (invparity[rp9] << 1) | (invparity[rp8]);
+ }
+
if (eccsize_mult == 1)
code[2] =
(invparity[par & 0xf0] << 7) |
@@ -394,15 +376,16 @@ EXPORT_SYMBOL(__nand_calculate_ecc);
/**
* nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte
* block
- * @mtd: MTD block structure
+ * @chip: NAND chip object
* @buf: input buffer with raw data
* @code: output buffer with ECC
*/
-int nand_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf,
+int nand_calculate_ecc(struct nand_chip *chip, const unsigned char *buf,
unsigned char *code)
{
- __nand_calculate_ecc(buf,
- mtd_to_nand(mtd)->ecc.size, code);
+ bool sm_order = chip->ecc.options & NAND_ECC_SOFT_HAMMING_SM_ORDER;
+
+ __nand_calculate_ecc(buf, chip->ecc.size, code, sm_order);
return 0;
}
@@ -414,12 +397,13 @@ EXPORT_SYMBOL(nand_calculate_ecc);
* @read_ecc: ECC from the chip
* @calc_ecc: the ECC calculated from raw data
* @eccsize: data bytes per ECC step (256 or 512)
+ * @sm_order: Smart Media byte order
*
* Detect and correct a 1 bit error for eccsize byte block
*/
int __nand_correct_data(unsigned char *buf,
unsigned char *read_ecc, unsigned char *calc_ecc,
- unsigned int eccsize)
+ unsigned int eccsize, bool sm_order)
{
unsigned char b0, b1, b2, bit_addr;
unsigned int byte_addr;
@@ -431,13 +415,14 @@ int __nand_correct_data(unsigned char *buf,
* we might need the xor result more than once,
* so keep them in a local var
*/
-#ifdef CONFIG_MTD_NAND_ECC_SMC
- b0 = read_ecc[0] ^ calc_ecc[0];
- b1 = read_ecc[1] ^ calc_ecc[1];
-#else
- b0 = read_ecc[1] ^ calc_ecc[1];
- b1 = read_ecc[0] ^ calc_ecc[0];
-#endif
+ if (sm_order) {
+ b0 = read_ecc[0] ^ calc_ecc[0];
+ b1 = read_ecc[1] ^ calc_ecc[1];
+ } else {
+ b0 = read_ecc[1] ^ calc_ecc[1];
+ b1 = read_ecc[0] ^ calc_ecc[0];
+ }
+
b2 = read_ecc[2] ^ calc_ecc[2];
/* check if there are any bitfaults */
@@ -491,18 +476,20 @@ EXPORT_SYMBOL(__nand_correct_data);
/**
* nand_correct_data - [NAND Interface] Detect and correct bit error(s)
- * @mtd: MTD block structure
+ * @chip: NAND chip object
* @buf: raw data read from the chip
* @read_ecc: ECC from the chip
* @calc_ecc: the ECC calculated from raw data
*
* Detect and correct a 1 bit error for 256/512 byte block
*/
-int nand_correct_data(struct mtd_info *mtd, unsigned char *buf,
+int nand_correct_data(struct nand_chip *chip, unsigned char *buf,
unsigned char *read_ecc, unsigned char *calc_ecc)
{
- return __nand_correct_data(buf, read_ecc, calc_ecc,
- mtd_to_nand(mtd)->ecc.size);
+ bool sm_order = chip->ecc.options & NAND_ECC_SOFT_HAMMING_SM_ORDER;
+
+ return __nand_correct_data(buf, read_ecc, calc_ecc, chip->ecc.size,
+ sm_order);
}
EXPORT_SYMBOL(nand_correct_data);
diff --git a/drivers/mtd/nand/raw/nand_esmt.c b/drivers/mtd/nand/raw/nand_esmt.c
new file mode 100644
index 000000000000..96f039a83bc8
--- /dev/null
+++ b/drivers/mtd/nand/raw/nand_esmt.c
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Toradex AG
+ *
+ * Author: Marcel Ziswiler <marcel.ziswiler@toradex.com>
+ */
+
+#include <linux/mtd/rawnand.h>
+#include "internals.h"
+
+static void esmt_nand_decode_id(struct nand_chip *chip)
+{
+ nand_decode_ext_id(chip);
+
+ /* Extract ECC requirements from 5th id byte. */
+ if (chip->id.len >= 5 && nand_is_slc(chip)) {
+ chip->ecc_step_ds = 512;
+ switch (chip->id.data[4] & 0x3) {
+ case 0x0:
+ chip->ecc_strength_ds = 4;
+ break;
+ case 0x1:
+ chip->ecc_strength_ds = 2;
+ break;
+ case 0x2:
+ chip->ecc_strength_ds = 1;
+ break;
+ default:
+ WARN(1, "Could not get ECC info");
+ chip->ecc_step_ds = 0;
+ break;
+ }
+ }
+}
+
+static int esmt_nand_init(struct nand_chip *chip)
+{
+ if (nand_is_slc(chip))
+ chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
+
+ return 0;
+}
+
+const struct nand_manufacturer_ops esmt_nand_manuf_ops = {
+ .detect = esmt_nand_decode_id,
+ .init = esmt_nand_init,
+};
diff --git a/drivers/mtd/nand/raw/nand_hynix.c b/drivers/mtd/nand/raw/nand_hynix.c
index 4ffbb26e76d6..ac1b5c103968 100644
--- a/drivers/mtd/nand/raw/nand_hynix.c
+++ b/drivers/mtd/nand/raw/nand_hynix.c
@@ -15,10 +15,11 @@
* GNU General Public License for more details.
*/
-#include <linux/mtd/rawnand.h>
#include <linux/sizes.h>
#include <linux/slab.h>
+#include "internals.h"
+
#define NAND_HYNIX_CMD_SET_PARAMS 0x36
#define NAND_HYNIX_CMD_APPLY_PARAMS 0x16
@@ -79,8 +80,6 @@ static bool hynix_nand_has_valid_jedecid(struct nand_chip *chip)
static int hynix_nand_cmd_op(struct nand_chip *chip, u8 cmd)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
-
if (chip->exec_op) {
struct nand_op_instr instrs[] = {
NAND_OP_CMD(cmd, 0),
@@ -90,14 +89,13 @@ static int hynix_nand_cmd_op(struct nand_chip *chip, u8 cmd)
return nand_exec_op(chip, &op);
}
- chip->cmdfunc(mtd, cmd, -1, -1);
+ chip->legacy.cmdfunc(chip, cmd, -1, -1);
return 0;
}
static int hynix_nand_reg_write_op(struct nand_chip *chip, u8 addr, u8 val)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
u16 column = ((u16)addr << 8) | addr;
if (chip->exec_op) {
@@ -110,15 +108,14 @@ static int hynix_nand_reg_write_op(struct nand_chip *chip, u8 addr, u8 val)
return nand_exec_op(chip, &op);
}
- chip->cmdfunc(mtd, NAND_CMD_NONE, column, -1);
- chip->write_byte(mtd, val);
+ chip->legacy.cmdfunc(chip, NAND_CMD_NONE, column, -1);
+ chip->legacy.write_byte(chip, val);
return 0;
}
-static int hynix_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
+static int hynix_nand_setup_read_retry(struct nand_chip *chip, int retry_mode)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct hynix_nand *hynix = nand_get_manufacturer_data(chip);
const u8 *values;
int i, ret;
diff --git a/drivers/mtd/nand/raw/nand_ids.c b/drivers/mtd/nand/raw/nand_ids.c
index 5423c3bb388e..ea5a342cd91e 100644
--- a/drivers/mtd/nand/raw/nand_ids.c
+++ b/drivers/mtd/nand/raw/nand_ids.c
@@ -6,9 +6,11 @@
* published by the Free Software Foundation.
*
*/
-#include <linux/mtd/rawnand.h>
+
#include <linux/sizes.h>
+#include "internals.h"
+
#define LP_OPTIONS 0
#define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16)
@@ -169,21 +171,21 @@ struct nand_flash_dev nand_flash_ids[] = {
/* Manufacturer IDs */
static const struct nand_manufacturer nand_manufacturers[] = {
- {NAND_MFR_TOSHIBA, "Toshiba", &toshiba_nand_manuf_ops},
- {NAND_MFR_ESMT, "ESMT"},
- {NAND_MFR_SAMSUNG, "Samsung", &samsung_nand_manuf_ops},
+ {NAND_MFR_AMD, "AMD/Spansion", &amd_nand_manuf_ops},
+ {NAND_MFR_ATO, "ATO"},
+ {NAND_MFR_EON, "Eon"},
+ {NAND_MFR_ESMT, "ESMT", &esmt_nand_manuf_ops},
{NAND_MFR_FUJITSU, "Fujitsu"},
- {NAND_MFR_NATIONAL, "National"},
- {NAND_MFR_RENESAS, "Renesas"},
- {NAND_MFR_STMICRO, "ST Micro"},
{NAND_MFR_HYNIX, "Hynix", &hynix_nand_manuf_ops},
- {NAND_MFR_MICRON, "Micron", &micron_nand_manuf_ops},
- {NAND_MFR_AMD, "AMD/Spansion", &amd_nand_manuf_ops},
+ {NAND_MFR_INTEL, "Intel"},
{NAND_MFR_MACRONIX, "Macronix", &macronix_nand_manuf_ops},
- {NAND_MFR_EON, "Eon"},
+ {NAND_MFR_MICRON, "Micron", &micron_nand_manuf_ops},
+ {NAND_MFR_NATIONAL, "National"},
+ {NAND_MFR_RENESAS, "Renesas"},
+ {NAND_MFR_SAMSUNG, "Samsung", &samsung_nand_manuf_ops},
{NAND_MFR_SANDISK, "SanDisk"},
- {NAND_MFR_INTEL, "Intel"},
- {NAND_MFR_ATO, "ATO"},
+ {NAND_MFR_STMICRO, "ST Micro"},
+ {NAND_MFR_TOSHIBA, "Toshiba", &toshiba_nand_manuf_ops},
{NAND_MFR_WINBOND, "Winbond"},
};
diff --git a/drivers/mtd/nand/raw/nand_jedec.c b/drivers/mtd/nand/raw/nand_jedec.c
new file mode 100644
index 000000000000..5c26492c841d
--- /dev/null
+++ b/drivers/mtd/nand/raw/nand_jedec.c
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
+ * 2002-2006 Thomas Gleixner (tglx@linutronix.de)
+ *
+ * Credits:
+ * David Woodhouse for adding multichip support
+ *
+ * Aleph One Ltd. and Toby Churchill Ltd. for supporting the
+ * rework for 2K page size chips
+ *
+ * This file contains all ONFI helpers.
+ */
+
+#include <linux/slab.h>
+
+#include "internals.h"
+
+/*
+ * Check if the NAND chip is JEDEC compliant, returns 1 if it is, 0 otherwise.
+ */
+int nand_jedec_detect(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct nand_jedec_params *p;
+ struct jedec_ecc_info *ecc;
+ int jedec_version = 0;
+ char id[5];
+ int i, val, ret;
+
+ /* Try JEDEC for unknown chip or LP */
+ ret = nand_readid_op(chip, 0x40, id, sizeof(id));
+ if (ret || strncmp(id, "JEDEC", sizeof(id)))
+ return 0;
+
+ /* JEDEC chip: allocate a buffer to hold its parameter page */
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+
+ ret = nand_read_param_page_op(chip, 0x40, NULL, 0);
+ if (ret) {
+ ret = 0;
+ goto free_jedec_param_page;
+ }
+
+ for (i = 0; i < 3; i++) {
+ ret = nand_read_data_op(chip, p, sizeof(*p), true);
+ if (ret) {
+ ret = 0;
+ goto free_jedec_param_page;
+ }
+
+ if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 510) ==
+ le16_to_cpu(p->crc))
+ break;
+ }
+
+ if (i == 3) {
+ pr_err("Could not find valid JEDEC parameter page; aborting\n");
+ goto free_jedec_param_page;
+ }
+
+ /* Check version */
+ val = le16_to_cpu(p->revision);
+ if (val & (1 << 2))
+ jedec_version = 10;
+ else if (val & (1 << 1))
+ jedec_version = 1; /* vendor specific version */
+
+ if (!jedec_version) {
+ pr_info("unsupported JEDEC version: %d\n", val);
+ goto free_jedec_param_page;
+ }
+
+ sanitize_string(p->manufacturer, sizeof(p->manufacturer));
+ sanitize_string(p->model, sizeof(p->model));
+ chip->parameters.model = kstrdup(p->model, GFP_KERNEL);
+ if (!chip->parameters.model) {
+ ret = -ENOMEM;
+ goto free_jedec_param_page;
+ }
+
+ mtd->writesize = le32_to_cpu(p->byte_per_page);
+
+ /* Please reference to the comment for nand_flash_detect_onfi. */
+ mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
+ mtd->erasesize *= mtd->writesize;
+
+ mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
+
+ /* Please reference to the comment for nand_flash_detect_onfi. */
+ chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
+ chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
+ chip->bits_per_cell = p->bits_per_cell;
+
+ if (le16_to_cpu(p->features) & JEDEC_FEATURE_16_BIT_BUS)
+ chip->options |= NAND_BUSWIDTH_16;
+
+ /* ECC info */
+ ecc = &p->ecc_info[0];
+
+ if (ecc->codeword_size >= 9) {
+ chip->ecc_strength_ds = ecc->ecc_bits;
+ chip->ecc_step_ds = 1 << ecc->codeword_size;
+ } else {
+ pr_warn("Invalid codeword size\n");
+ }
+
+free_jedec_param_page:
+ kfree(p);
+ return ret;
+}
diff --git a/drivers/mtd/nand/raw/nand_legacy.c b/drivers/mtd/nand/raw/nand_legacy.c
new file mode 100644
index 000000000000..c5ddc86cd98c
--- /dev/null
+++ b/drivers/mtd/nand/raw/nand_legacy.c
@@ -0,0 +1,642 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
+ * 2002-2006 Thomas Gleixner (tglx@linutronix.de)
+ *
+ * Credits:
+ * David Woodhouse for adding multichip support
+ *
+ * Aleph One Ltd. and Toby Churchill Ltd. for supporting the
+ * rework for 2K page size chips
+ *
+ * This file contains all legacy helpers/code that should be removed
+ * at some point.
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/nmi.h>
+
+#include "internals.h"
+
+/**
+ * nand_read_byte - [DEFAULT] read one byte from the chip
+ * @chip: NAND chip object
+ *
+ * Default read function for 8bit buswidth
+ */
+static uint8_t nand_read_byte(struct nand_chip *chip)
+{
+ return readb(chip->legacy.IO_ADDR_R);
+}
+
+/**
+ * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip
+ * @chip: NAND chip object
+ *
+ * Default read function for 16bit buswidth with endianness conversion.
+ *
+ */
+static uint8_t nand_read_byte16(struct nand_chip *chip)
+{
+ return (uint8_t) cpu_to_le16(readw(chip->legacy.IO_ADDR_R));
+}
+
+/**
+ * nand_select_chip - [DEFAULT] control CE line
+ * @chip: NAND chip object
+ * @chipnr: chipnumber to select, -1 for deselect
+ *
+ * Default select function for 1 chip devices.
+ */
+static void nand_select_chip(struct nand_chip *chip, int chipnr)
+{
+ switch (chipnr) {
+ case -1:
+ chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE,
+ 0 | NAND_CTRL_CHANGE);
+ break;
+ case 0:
+ break;
+
+ default:
+ BUG();
+ }
+}
+
+/**
+ * nand_write_byte - [DEFAULT] write single byte to chip
+ * @chip: NAND chip object
+ * @byte: value to write
+ *
+ * Default function to write a byte to I/O[7:0]
+ */
+static void nand_write_byte(struct nand_chip *chip, uint8_t byte)
+{
+ chip->legacy.write_buf(chip, &byte, 1);
+}
+
+/**
+ * nand_write_byte16 - [DEFAULT] write single byte to a chip with width 16
+ * @chip: NAND chip object
+ * @byte: value to write
+ *
+ * Default function to write a byte to I/O[7:0] on a 16-bit wide chip.
+ */
+static void nand_write_byte16(struct nand_chip *chip, uint8_t byte)
+{
+ uint16_t word = byte;
+
+ /*
+ * It's not entirely clear what should happen to I/O[15:8] when writing
+ * a byte. The ONFi spec (Revision 3.1; 2012-09-19, Section 2.16) reads:
+ *
+ * When the host supports a 16-bit bus width, only data is
+ * transferred at the 16-bit width. All address and command line
+ * transfers shall use only the lower 8-bits of the data bus. During
+ * command transfers, the host may place any value on the upper
+ * 8-bits of the data bus. During address transfers, the host shall
+ * set the upper 8-bits of the data bus to 00h.
+ *
+ * One user of the write_byte callback is nand_set_features. The
+ * four parameters are specified to be written to I/O[7:0], but this is
+ * neither an address nor a command transfer. Let's assume a 0 on the
+ * upper I/O lines is OK.
+ */
+ chip->legacy.write_buf(chip, (uint8_t *)&word, 2);
+}
+
+/**
+ * nand_write_buf - [DEFAULT] write buffer to chip
+ * @chip: NAND chip object
+ * @buf: data buffer
+ * @len: number of bytes to write
+ *
+ * Default write function for 8bit buswidth.
+ */
+static void nand_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
+{
+ iowrite8_rep(chip->legacy.IO_ADDR_W, buf, len);
+}
+
+/**
+ * nand_read_buf - [DEFAULT] read chip data into buffer
+ * @chip: NAND chip object
+ * @buf: buffer to store date
+ * @len: number of bytes to read
+ *
+ * Default read function for 8bit buswidth.
+ */
+static void nand_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
+{
+ ioread8_rep(chip->legacy.IO_ADDR_R, buf, len);
+}
+
+/**
+ * nand_write_buf16 - [DEFAULT] write buffer to chip
+ * @chip: NAND chip object
+ * @buf: data buffer
+ * @len: number of bytes to write
+ *
+ * Default write function for 16bit buswidth.
+ */
+static void nand_write_buf16(struct nand_chip *chip, const uint8_t *buf,
+ int len)
+{
+ u16 *p = (u16 *) buf;
+
+ iowrite16_rep(chip->legacy.IO_ADDR_W, p, len >> 1);
+}
+
+/**
+ * nand_read_buf16 - [DEFAULT] read chip data into buffer
+ * @chip: NAND chip object
+ * @buf: buffer to store date
+ * @len: number of bytes to read
+ *
+ * Default read function for 16bit buswidth.
+ */
+static void nand_read_buf16(struct nand_chip *chip, uint8_t *buf, int len)
+{
+ u16 *p = (u16 *) buf;
+
+ ioread16_rep(chip->legacy.IO_ADDR_R, p, len >> 1);
+}
+
+/**
+ * panic_nand_wait_ready - [GENERIC] Wait for the ready pin after commands.
+ * @mtd: MTD device structure
+ * @timeo: Timeout
+ *
+ * Helper function for nand_wait_ready used when needing to wait in interrupt
+ * context.
+ */
+static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ int i;
+
+ /* Wait for the device to get ready */
+ for (i = 0; i < timeo; i++) {
+ if (chip->legacy.dev_ready(chip))
+ break;
+ touch_softlockup_watchdog();
+ mdelay(1);
+ }
+}
+
+/**
+ * nand_wait_ready - [GENERIC] Wait for the ready pin after commands.
+ * @chip: NAND chip object
+ *
+ * Wait for the ready pin after a command, and warn if a timeout occurs.
+ */
+void nand_wait_ready(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ unsigned long timeo = 400;
+
+ if (in_interrupt() || oops_in_progress)
+ return panic_nand_wait_ready(mtd, timeo);
+
+ /* Wait until command is processed or timeout occurs */
+ timeo = jiffies + msecs_to_jiffies(timeo);
+ do {
+ if (chip->legacy.dev_ready(chip))
+ return;
+ cond_resched();
+ } while (time_before(jiffies, timeo));
+
+ if (!chip->legacy.dev_ready(chip))
+ pr_warn_ratelimited("timeout while waiting for chip to become ready\n");
+}
+EXPORT_SYMBOL_GPL(nand_wait_ready);
+
+/**
+ * nand_wait_status_ready - [GENERIC] Wait for the ready status after commands.
+ * @mtd: MTD device structure
+ * @timeo: Timeout in ms
+ *
+ * Wait for status ready (i.e. command done) or timeout.
+ */
+static void nand_wait_status_ready(struct mtd_info *mtd, unsigned long timeo)
+{
+ register struct nand_chip *chip = mtd_to_nand(mtd);
+ int ret;
+
+ timeo = jiffies + msecs_to_jiffies(timeo);
+ do {
+ u8 status;
+
+ ret = nand_read_data_op(chip, &status, sizeof(status), true);
+ if (ret)
+ return;
+
+ if (status & NAND_STATUS_READY)
+ break;
+ touch_softlockup_watchdog();
+ } while (time_before(jiffies, timeo));
+};
+
+/**
+ * nand_command - [DEFAULT] Send command to NAND device
+ * @chip: NAND chip object
+ * @command: the command to be sent
+ * @column: the column address for this command, -1 if none
+ * @page_addr: the page address for this command, -1 if none
+ *
+ * Send command to NAND device. This function is used for small page devices
+ * (512 Bytes per page).
+ */
+static void nand_command(struct nand_chip *chip, unsigned int command,
+ int column, int page_addr)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE;
+
+ /* Write out the command to the device */
+ if (command == NAND_CMD_SEQIN) {
+ int readcmd;
+
+ if (column >= mtd->writesize) {
+ /* OOB area */
+ column -= mtd->writesize;
+ readcmd = NAND_CMD_READOOB;
+ } else if (column < 256) {
+ /* First 256 bytes --> READ0 */
+ readcmd = NAND_CMD_READ0;
+ } else {
+ column -= 256;
+ readcmd = NAND_CMD_READ1;
+ }
+ chip->legacy.cmd_ctrl(chip, readcmd, ctrl);
+ ctrl &= ~NAND_CTRL_CHANGE;
+ }
+ if (command != NAND_CMD_NONE)
+ chip->legacy.cmd_ctrl(chip, command, ctrl);
+
+ /* Address cycle, when necessary */
+ ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE;
+ /* Serially input address */
+ if (column != -1) {
+ /* Adjust columns for 16 bit buswidth */
+ if (chip->options & NAND_BUSWIDTH_16 &&
+ !nand_opcode_8bits(command))
+ column >>= 1;
+ chip->legacy.cmd_ctrl(chip, column, ctrl);
+ ctrl &= ~NAND_CTRL_CHANGE;
+ }
+ if (page_addr != -1) {
+ chip->legacy.cmd_ctrl(chip, page_addr, ctrl);
+ ctrl &= ~NAND_CTRL_CHANGE;
+ chip->legacy.cmd_ctrl(chip, page_addr >> 8, ctrl);
+ if (chip->options & NAND_ROW_ADDR_3)
+ chip->legacy.cmd_ctrl(chip, page_addr >> 16, ctrl);
+ }
+ chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE,
+ NAND_NCE | NAND_CTRL_CHANGE);
+
+ /*
+ * Program and erase have their own busy handlers status and sequential
+ * in needs no delay
+ */
+ switch (command) {
+
+ case NAND_CMD_NONE:
+ case NAND_CMD_PAGEPROG:
+ case NAND_CMD_ERASE1:
+ case NAND_CMD_ERASE2:
+ case NAND_CMD_SEQIN:
+ case NAND_CMD_STATUS:
+ case NAND_CMD_READID:
+ case NAND_CMD_SET_FEATURES:
+ return;
+
+ case NAND_CMD_RESET:
+ if (chip->legacy.dev_ready)
+ break;
+ udelay(chip->legacy.chip_delay);
+ chip->legacy.cmd_ctrl(chip, NAND_CMD_STATUS,
+ NAND_CTRL_CLE | NAND_CTRL_CHANGE);
+ chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE,
+ NAND_NCE | NAND_CTRL_CHANGE);
+ /* EZ-NAND can take upto 250ms as per ONFi v4.0 */
+ nand_wait_status_ready(mtd, 250);
+ return;
+
+ /* This applies to read commands */
+ case NAND_CMD_READ0:
+ /*
+ * READ0 is sometimes used to exit GET STATUS mode. When this
+ * is the case no address cycles are requested, and we can use
+ * this information to detect that we should not wait for the
+ * device to be ready.
+ */
+ if (column == -1 && page_addr == -1)
+ return;
+
+ default:
+ /*
+ * If we don't have access to the busy pin, we apply the given
+ * command delay
+ */
+ if (!chip->legacy.dev_ready) {
+ udelay(chip->legacy.chip_delay);
+ return;
+ }
+ }
+ /*
+ * Apply this short delay always to ensure that we do wait tWB in
+ * any case on any machine.
+ */
+ ndelay(100);
+
+ nand_wait_ready(chip);
+}
+
+static void nand_ccs_delay(struct nand_chip *chip)
+{
+ /*
+ * The controller already takes care of waiting for tCCS when the RNDIN
+ * or RNDOUT command is sent, return directly.
+ */
+ if (!(chip->options & NAND_WAIT_TCCS))
+ return;
+
+ /*
+ * Wait tCCS_min if it is correctly defined, otherwise wait 500ns
+ * (which should be safe for all NANDs).
+ */
+ if (chip->setup_data_interface)
+ ndelay(chip->data_interface.timings.sdr.tCCS_min / 1000);
+ else
+ ndelay(500);
+}
+
+/**
+ * nand_command_lp - [DEFAULT] Send command to NAND large page device
+ * @chip: NAND chip object
+ * @command: the command to be sent
+ * @column: the column address for this command, -1 if none
+ * @page_addr: the page address for this command, -1 if none
+ *
+ * Send command to NAND device. This is the version for the new large page
+ * devices. We don't have the separate regions as we have in the small page
+ * devices. We must emulate NAND_CMD_READOOB to keep the code compatible.
+ */
+static void nand_command_lp(struct nand_chip *chip, unsigned int command,
+ int column, int page_addr)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
+ /* Emulate NAND_CMD_READOOB */
+ if (command == NAND_CMD_READOOB) {
+ column += mtd->writesize;
+ command = NAND_CMD_READ0;
+ }
+
+ /* Command latch cycle */
+ if (command != NAND_CMD_NONE)
+ chip->legacy.cmd_ctrl(chip, command,
+ NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+
+ if (column != -1 || page_addr != -1) {
+ int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
+
+ /* Serially input address */
+ if (column != -1) {
+ /* Adjust columns for 16 bit buswidth */
+ if (chip->options & NAND_BUSWIDTH_16 &&
+ !nand_opcode_8bits(command))
+ column >>= 1;
+ chip->legacy.cmd_ctrl(chip, column, ctrl);
+ ctrl &= ~NAND_CTRL_CHANGE;
+
+ /* Only output a single addr cycle for 8bits opcodes. */
+ if (!nand_opcode_8bits(command))
+ chip->legacy.cmd_ctrl(chip, column >> 8, ctrl);
+ }
+ if (page_addr != -1) {
+ chip->legacy.cmd_ctrl(chip, page_addr, ctrl);
+ chip->legacy.cmd_ctrl(chip, page_addr >> 8,
+ NAND_NCE | NAND_ALE);
+ if (chip->options & NAND_ROW_ADDR_3)
+ chip->legacy.cmd_ctrl(chip, page_addr >> 16,
+ NAND_NCE | NAND_ALE);
+ }
+ }
+ chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE,
+ NAND_NCE | NAND_CTRL_CHANGE);
+
+ /*
+ * Program and erase have their own busy handlers status, sequential
+ * in and status need no delay.
+ */
+ switch (command) {
+
+ case NAND_CMD_NONE:
+ case NAND_CMD_CACHEDPROG:
+ case NAND_CMD_PAGEPROG:
+ case NAND_CMD_ERASE1:
+ case NAND_CMD_ERASE2:
+ case NAND_CMD_SEQIN:
+ case NAND_CMD_STATUS:
+ case NAND_CMD_READID:
+ case NAND_CMD_SET_FEATURES:
+ return;
+
+ case NAND_CMD_RNDIN:
+ nand_ccs_delay(chip);
+ return;
+
+ case NAND_CMD_RESET:
+ if (chip->legacy.dev_ready)
+ break;
+ udelay(chip->legacy.chip_delay);
+ chip->legacy.cmd_ctrl(chip, NAND_CMD_STATUS,
+ NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+ chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE,
+ NAND_NCE | NAND_CTRL_CHANGE);
+ /* EZ-NAND can take upto 250ms as per ONFi v4.0 */
+ nand_wait_status_ready(mtd, 250);
+ return;
+
+ case NAND_CMD_RNDOUT:
+ /* No ready / busy check necessary */
+ chip->legacy.cmd_ctrl(chip, NAND_CMD_RNDOUTSTART,
+ NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+ chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE,
+ NAND_NCE | NAND_CTRL_CHANGE);
+
+ nand_ccs_delay(chip);
+ return;
+
+ case NAND_CMD_READ0:
+ /*
+ * READ0 is sometimes used to exit GET STATUS mode. When this
+ * is the case no address cycles are requested, and we can use
+ * this information to detect that READSTART should not be
+ * issued.
+ */
+ if (column == -1 && page_addr == -1)
+ return;
+
+ chip->legacy.cmd_ctrl(chip, NAND_CMD_READSTART,
+ NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+ chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE,
+ NAND_NCE | NAND_CTRL_CHANGE);
+
+ /* This applies to read commands */
+ default:
+ /*
+ * If we don't have access to the busy pin, we apply the given
+ * command delay.
+ */
+ if (!chip->legacy.dev_ready) {
+ udelay(chip->legacy.chip_delay);
+ return;
+ }
+ }
+
+ /*
+ * Apply this short delay always to ensure that we do wait tWB in
+ * any case on any machine.
+ */
+ ndelay(100);
+
+ nand_wait_ready(chip);
+}
+
+/**
+ * nand_get_set_features_notsupp - set/get features stub returning -ENOTSUPP
+ * @chip: nand chip info structure
+ * @addr: feature address.
+ * @subfeature_param: the subfeature parameters, a four bytes array.
+ *
+ * Should be used by NAND controller drivers that do not support the SET/GET
+ * FEATURES operations.
+ */
+int nand_get_set_features_notsupp(struct nand_chip *chip, int addr,
+ u8 *subfeature_param)
+{
+ return -ENOTSUPP;
+}
+EXPORT_SYMBOL(nand_get_set_features_notsupp);
+
+/**
+ * nand_wait - [DEFAULT] wait until the command is done
+ * @mtd: MTD device structure
+ * @chip: NAND chip structure
+ *
+ * Wait for command done. This applies to erase and program only.
+ */
+static int nand_wait(struct nand_chip *chip)
+{
+
+ unsigned long timeo = 400;
+ u8 status;
+ int ret;
+
+ /*
+ * Apply this short delay always to ensure that we do wait tWB in any
+ * case on any machine.
+ */
+ ndelay(100);
+
+ ret = nand_status_op(chip, NULL);
+ if (ret)
+ return ret;
+
+ if (in_interrupt() || oops_in_progress)
+ panic_nand_wait(chip, timeo);
+ else {
+ timeo = jiffies + msecs_to_jiffies(timeo);
+ do {
+ if (chip->legacy.dev_ready) {
+ if (chip->legacy.dev_ready(chip))
+ break;
+ } else {
+ ret = nand_read_data_op(chip, &status,
+ sizeof(status), true);
+ if (ret)
+ return ret;
+
+ if (status & NAND_STATUS_READY)
+ break;
+ }
+ cond_resched();
+ } while (time_before(jiffies, timeo));
+ }
+
+ ret = nand_read_data_op(chip, &status, sizeof(status), true);
+ if (ret)
+ return ret;
+
+ /* This can happen if in case of timeout or buggy dev_ready */
+ WARN_ON(!(status & NAND_STATUS_READY));
+ return status;
+}
+
+void nand_legacy_set_defaults(struct nand_chip *chip)
+{
+ unsigned int busw = chip->options & NAND_BUSWIDTH_16;
+
+ if (chip->exec_op)
+ return;
+
+ /* check for proper chip_delay setup, set 20us if not */
+ if (!chip->legacy.chip_delay)
+ chip->legacy.chip_delay = 20;
+
+ /* check, if a user supplied command function given */
+ if (!chip->legacy.cmdfunc && !chip->exec_op)
+ chip->legacy.cmdfunc = nand_command;
+
+ /* check, if a user supplied wait function given */
+ if (chip->legacy.waitfunc == NULL)
+ chip->legacy.waitfunc = nand_wait;
+
+ if (!chip->select_chip)
+ chip->select_chip = nand_select_chip;
+
+ /* If called twice, pointers that depend on busw may need to be reset */
+ if (!chip->legacy.read_byte || chip->legacy.read_byte == nand_read_byte)
+ chip->legacy.read_byte = busw ? nand_read_byte16 : nand_read_byte;
+ if (!chip->legacy.write_buf || chip->legacy.write_buf == nand_write_buf)
+ chip->legacy.write_buf = busw ? nand_write_buf16 : nand_write_buf;
+ if (!chip->legacy.write_byte || chip->legacy.write_byte == nand_write_byte)
+ chip->legacy.write_byte = busw ? nand_write_byte16 : nand_write_byte;
+ if (!chip->legacy.read_buf || chip->legacy.read_buf == nand_read_buf)
+ chip->legacy.read_buf = busw ? nand_read_buf16 : nand_read_buf;
+}
+
+void nand_legacy_adjust_cmdfunc(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
+ /* Do not replace user supplied command function! */
+ if (mtd->writesize > 512 && chip->legacy.cmdfunc == nand_command)
+ chip->legacy.cmdfunc = nand_command_lp;
+}
+
+int nand_legacy_check_hooks(struct nand_chip *chip)
+{
+ /*
+ * ->legacy.cmdfunc() is legacy and will only be used if ->exec_op() is
+ * not populated.
+ */
+ if (chip->exec_op)
+ return 0;
+
+ /*
+ * Default functions assigned for ->legacy.cmdfunc() and
+ * ->select_chip() both expect ->legacy.cmd_ctrl() to be populated.
+ */
+ if ((!chip->legacy.cmdfunc || !chip->select_chip) &&
+ !chip->legacy.cmd_ctrl) {
+ pr_err("->legacy.cmd_ctrl() should be provided\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/drivers/mtd/nand/raw/nand_macronix.c b/drivers/mtd/nand/raw/nand_macronix.c
index 49c546c97c6f..358dcc957bb2 100644
--- a/drivers/mtd/nand/raw/nand_macronix.c
+++ b/drivers/mtd/nand/raw/nand_macronix.c
@@ -15,7 +15,7 @@
* GNU General Public License for more details.
*/
-#include <linux/mtd/rawnand.h>
+#include "internals.h"
/*
* Macronix AC series does not support using SET/GET_FEATURES to change
diff --git a/drivers/mtd/nand/raw/nand_micron.c b/drivers/mtd/nand/raw/nand_micron.c
index f5dc0a7a2456..b85e1c13b79e 100644
--- a/drivers/mtd/nand/raw/nand_micron.c
+++ b/drivers/mtd/nand/raw/nand_micron.c
@@ -15,9 +15,10 @@
* GNU General Public License for more details.
*/
-#include <linux/mtd/rawnand.h>
#include <linux/slab.h>
+#include "internals.h"
+
/*
* Special Micron status bit 3 indicates that the block has been
* corrected by on-die ECC and should be rewritten.
@@ -74,9 +75,8 @@ struct micron_nand {
struct micron_on_die_ecc ecc;
};
-static int micron_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
+static int micron_nand_setup_read_retry(struct nand_chip *chip, int retry_mode)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = {retry_mode};
return nand_set_features(chip, ONFI_FEATURE_ADDR_READ_RETRY, feature);
@@ -290,10 +290,10 @@ static int micron_nand_on_die_ecc_status_8(struct nand_chip *chip, u8 status)
}
static int
-micron_nand_read_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required,
- int page)
+micron_nand_read_page_on_die_ecc(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
u8 status;
int ret, max_bitflips = 0;
@@ -332,9 +332,8 @@ out:
}
static int
-micron_nand_write_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required,
- int page)
+micron_nand_write_page_on_die_ecc(struct nand_chip *chip, const uint8_t *buf,
+ int oob_required, int page)
{
int ret;
@@ -342,7 +341,7 @@ micron_nand_write_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip,
if (ret)
return ret;
- ret = nand_write_page_raw(mtd, chip, buf, oob_required, page);
+ ret = nand_write_page_raw(chip, buf, oob_required, page);
micron_nand_on_die_ecc_setup(chip, false);
return ret;
diff --git a/drivers/mtd/nand/raw/nand_onfi.c b/drivers/mtd/nand/raw/nand_onfi.c
new file mode 100644
index 000000000000..d8184cf591ad
--- /dev/null
+++ b/drivers/mtd/nand/raw/nand_onfi.c
@@ -0,0 +1,305 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
+ * 2002-2006 Thomas Gleixner (tglx@linutronix.de)
+ *
+ * Credits:
+ * David Woodhouse for adding multichip support
+ *
+ * Aleph One Ltd. and Toby Churchill Ltd. for supporting the
+ * rework for 2K page size chips
+ *
+ * This file contains all ONFI helpers.
+ */
+
+#include <linux/slab.h>
+
+#include "internals.h"
+
+u16 onfi_crc16(u16 crc, u8 const *p, size_t len)
+{
+ int i;
+ while (len--) {
+ crc ^= *p++ << 8;
+ for (i = 0; i < 8; i++)
+ crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0);
+ }
+
+ return crc;
+}
+
+/* Parse the Extended Parameter Page. */
+static int nand_flash_detect_ext_param_page(struct nand_chip *chip,
+ struct nand_onfi_params *p)
+{
+ struct onfi_ext_param_page *ep;
+ struct onfi_ext_section *s;
+ struct onfi_ext_ecc_info *ecc;
+ uint8_t *cursor;
+ int ret;
+ int len;
+ int i;
+
+ len = le16_to_cpu(p->ext_param_page_length) * 16;
+ ep = kmalloc(len, GFP_KERNEL);
+ if (!ep)
+ return -ENOMEM;
+
+ /* Send our own NAND_CMD_PARAM. */
+ ret = nand_read_param_page_op(chip, 0, NULL, 0);
+ if (ret)
+ goto ext_out;
+
+ /* Use the Change Read Column command to skip the ONFI param pages. */
+ ret = nand_change_read_column_op(chip,
+ sizeof(*p) * p->num_of_param_pages,
+ ep, len, true);
+ if (ret)
+ goto ext_out;
+
+ ret = -EINVAL;
+ if ((onfi_crc16(ONFI_CRC_BASE, ((uint8_t *)ep) + 2, len - 2)
+ != le16_to_cpu(ep->crc))) {
+ pr_debug("fail in the CRC.\n");
+ goto ext_out;
+ }
+
+ /*
+ * Check the signature.
+ * Do not strictly follow the ONFI spec, maybe changed in future.
+ */
+ if (strncmp(ep->sig, "EPPS", 4)) {
+ pr_debug("The signature is invalid.\n");
+ goto ext_out;
+ }
+
+ /* find the ECC section. */
+ cursor = (uint8_t *)(ep + 1);
+ for (i = 0; i < ONFI_EXT_SECTION_MAX; i++) {
+ s = ep->sections + i;
+ if (s->type == ONFI_SECTION_TYPE_2)
+ break;
+ cursor += s->length * 16;
+ }
+ if (i == ONFI_EXT_SECTION_MAX) {
+ pr_debug("We can not find the ECC section.\n");
+ goto ext_out;
+ }
+
+ /* get the info we want. */
+ ecc = (struct onfi_ext_ecc_info *)cursor;
+
+ if (!ecc->codeword_size) {
+ pr_debug("Invalid codeword size\n");
+ goto ext_out;
+ }
+
+ chip->ecc_strength_ds = ecc->ecc_bits;
+ chip->ecc_step_ds = 1 << ecc->codeword_size;
+ ret = 0;
+
+ext_out:
+ kfree(ep);
+ return ret;
+}
+
+/*
+ * Recover data with bit-wise majority
+ */
+static void nand_bit_wise_majority(const void **srcbufs,
+ unsigned int nsrcbufs,
+ void *dstbuf,
+ unsigned int bufsize)
+{
+ int i, j, k;
+
+ for (i = 0; i < bufsize; i++) {
+ u8 val = 0;
+
+ for (j = 0; j < 8; j++) {
+ unsigned int cnt = 0;
+
+ for (k = 0; k < nsrcbufs; k++) {
+ const u8 *srcbuf = srcbufs[k];
+
+ if (srcbuf[i] & BIT(j))
+ cnt++;
+ }
+
+ if (cnt > nsrcbufs / 2)
+ val |= BIT(j);
+ }
+
+ ((u8 *)dstbuf)[i] = val;
+ }
+}
+
+/*
+ * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise.
+ */
+int nand_onfi_detect(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ struct nand_onfi_params *p;
+ struct onfi_params *onfi;
+ int onfi_version = 0;
+ char id[4];
+ int i, ret, val;
+
+ /* Try ONFI for unknown chip or LP */
+ ret = nand_readid_op(chip, 0x20, id, sizeof(id));
+ if (ret || strncmp(id, "ONFI", 4))
+ return 0;
+
+ /* ONFI chip: allocate a buffer to hold its parameter page */
+ p = kzalloc((sizeof(*p) * 3), GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+
+ ret = nand_read_param_page_op(chip, 0, NULL, 0);
+ if (ret) {
+ ret = 0;
+ goto free_onfi_param_page;
+ }
+
+ for (i = 0; i < 3; i++) {
+ ret = nand_read_data_op(chip, &p[i], sizeof(*p), true);
+ if (ret) {
+ ret = 0;
+ goto free_onfi_param_page;
+ }
+
+ if (onfi_crc16(ONFI_CRC_BASE, (u8 *)&p[i], 254) ==
+ le16_to_cpu(p->crc)) {
+ if (i)
+ memcpy(p, &p[i], sizeof(*p));
+ break;
+ }
+ }
+
+ if (i == 3) {
+ const void *srcbufs[3] = {p, p + 1, p + 2};
+
+ pr_warn("Could not find a valid ONFI parameter page, trying bit-wise majority to recover it\n");
+ nand_bit_wise_majority(srcbufs, ARRAY_SIZE(srcbufs), p,
+ sizeof(*p));
+
+ if (onfi_crc16(ONFI_CRC_BASE, (u8 *)p, 254) !=
+ le16_to_cpu(p->crc)) {
+ pr_err("ONFI parameter recovery failed, aborting\n");
+ goto free_onfi_param_page;
+ }
+ }
+
+ if (chip->manufacturer.desc && chip->manufacturer.desc->ops &&
+ chip->manufacturer.desc->ops->fixup_onfi_param_page)
+ chip->manufacturer.desc->ops->fixup_onfi_param_page(chip, p);
+
+ /* Check version */
+ val = le16_to_cpu(p->revision);
+ if (val & ONFI_VERSION_2_3)
+ onfi_version = 23;
+ else if (val & ONFI_VERSION_2_2)
+ onfi_version = 22;
+ else if (val & ONFI_VERSION_2_1)
+ onfi_version = 21;
+ else if (val & ONFI_VERSION_2_0)
+ onfi_version = 20;
+ else if (val & ONFI_VERSION_1_0)
+ onfi_version = 10;
+
+ if (!onfi_version) {
+ pr_info("unsupported ONFI version: %d\n", val);
+ goto free_onfi_param_page;
+ }
+
+ sanitize_string(p->manufacturer, sizeof(p->manufacturer));
+ sanitize_string(p->model, sizeof(p->model));
+ chip->parameters.model = kstrdup(p->model, GFP_KERNEL);
+ if (!chip->parameters.model) {
+ ret = -ENOMEM;
+ goto free_onfi_param_page;
+ }
+
+ mtd->writesize = le32_to_cpu(p->byte_per_page);
+
+ /*
+ * pages_per_block and blocks_per_lun may not be a power-of-2 size
+ * (don't ask me who thought of this...). MTD assumes that these
+ * dimensions will be power-of-2, so just truncate the remaining area.
+ */
+ mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
+ mtd->erasesize *= mtd->writesize;
+
+ mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
+
+ /* See erasesize comment */
+ chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
+ chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
+ chip->bits_per_cell = p->bits_per_cell;
+
+ chip->max_bb_per_die = le16_to_cpu(p->bb_per_lun);
+ chip->blocks_per_die = le32_to_cpu(p->blocks_per_lun);
+
+ if (le16_to_cpu(p->features) & ONFI_FEATURE_16_BIT_BUS)
+ chip->options |= NAND_BUSWIDTH_16;
+
+ if (p->ecc_bits != 0xff) {
+ chip->ecc_strength_ds = p->ecc_bits;
+ chip->ecc_step_ds = 512;
+ } else if (onfi_version >= 21 &&
+ (le16_to_cpu(p->features) & ONFI_FEATURE_EXT_PARAM_PAGE)) {
+
+ /*
+ * The nand_flash_detect_ext_param_page() uses the
+ * Change Read Column command which maybe not supported
+ * by the chip->legacy.cmdfunc. So try to update the
+ * chip->legacy.cmdfunc now. We do not replace user supplied
+ * command function.
+ */
+ nand_legacy_adjust_cmdfunc(chip);
+
+ /* The Extended Parameter Page is supported since ONFI 2.1. */
+ if (nand_flash_detect_ext_param_page(chip, p))
+ pr_warn("Failed to detect ONFI extended param page\n");
+ } else {
+ pr_warn("Could not retrieve ONFI ECC requirements\n");
+ }
+
+ /* Save some parameters from the parameter page for future use */
+ if (le16_to_cpu(p->opt_cmd) & ONFI_OPT_CMD_SET_GET_FEATURES) {
+ chip->parameters.supports_set_get_features = true;
+ bitmap_set(chip->parameters.get_feature_list,
+ ONFI_FEATURE_ADDR_TIMING_MODE, 1);
+ bitmap_set(chip->parameters.set_feature_list,
+ ONFI_FEATURE_ADDR_TIMING_MODE, 1);
+ }
+
+ onfi = kzalloc(sizeof(*onfi), GFP_KERNEL);
+ if (!onfi) {
+ ret = -ENOMEM;
+ goto free_model;
+ }
+
+ onfi->version = onfi_version;
+ onfi->tPROG = le16_to_cpu(p->t_prog);
+ 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->vendor_revision = le16_to_cpu(p->vendor_revision);
+ memcpy(onfi->vendor, p->vendor, sizeof(p->vendor));
+ chip->parameters.onfi = onfi;
+
+ /* Identification done, free the full ONFI parameter page and exit */
+ kfree(p);
+
+ return 1;
+
+free_model:
+ kfree(chip->parameters.model);
+free_onfi_param_page:
+ kfree(p);
+
+ return ret;
+}
diff --git a/drivers/mtd/nand/raw/nand_samsung.c b/drivers/mtd/nand/raw/nand_samsung.c
index ef022f62f74c..e46d4c492ad8 100644
--- a/drivers/mtd/nand/raw/nand_samsung.c
+++ b/drivers/mtd/nand/raw/nand_samsung.c
@@ -15,7 +15,7 @@
* GNU General Public License for more details.
*/
-#include <linux/mtd/rawnand.h>
+#include "internals.h"
static void samsung_nand_decode_id(struct nand_chip *chip)
{
diff --git a/drivers/mtd/nand/raw/nand_timings.c b/drivers/mtd/nand/raw/nand_timings.c
index ebc7b5f76f77..bea3062d71d6 100644
--- a/drivers/mtd/nand/raw/nand_timings.c
+++ b/drivers/mtd/nand/raw/nand_timings.c
@@ -11,7 +11,8 @@
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/export.h>
-#include <linux/mtd/rawnand.h>
+
+#include "internals.h"
#define ONFI_DYN_TIMING_MAX U16_MAX
@@ -271,20 +272,6 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
};
/**
- * onfi_async_timing_mode_to_sdr_timings - [NAND Interface] Retrieve NAND
- * timings according to the given ONFI timing mode
- * @mode: ONFI timing mode
- */
-const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode)
-{
- if (mode < 0 || mode >= ARRAY_SIZE(onfi_sdr_timings))
- return ERR_PTR(-EINVAL);
-
- return &onfi_sdr_timings[mode].timings.sdr;
-}
-EXPORT_SYMBOL(onfi_async_timing_mode_to_sdr_timings);
-
-/**
* onfi_fill_data_interface - [NAND Interface] Initialize a data interface from
* given ONFI mode
* @mode: The ONFI timing mode
@@ -339,4 +326,3 @@ int onfi_fill_data_interface(struct nand_chip *chip,
return 0;
}
-EXPORT_SYMBOL(onfi_fill_data_interface);
diff --git a/drivers/mtd/nand/raw/nand_toshiba.c b/drivers/mtd/nand/raw/nand_toshiba.c
index ab43f027cd23..d068163b64b3 100644
--- a/drivers/mtd/nand/raw/nand_toshiba.c
+++ b/drivers/mtd/nand/raw/nand_toshiba.c
@@ -15,7 +15,88 @@
* GNU General Public License for more details.
*/
-#include <linux/mtd/rawnand.h>
+#include "internals.h"
+
+/* Bit for detecting BENAND */
+#define TOSHIBA_NAND_ID4_IS_BENAND BIT(7)
+
+/* Recommended to rewrite for BENAND */
+#define TOSHIBA_NAND_STATUS_REWRITE_RECOMMENDED BIT(3)
+
+static int toshiba_nand_benand_eccstatus(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ int ret;
+ unsigned int max_bitflips = 0;
+ u8 status;
+
+ /* Check Status */
+ ret = nand_status_op(chip, &status);
+ if (ret)
+ return ret;
+
+ if (status & NAND_STATUS_FAIL) {
+ /* uncorrected */
+ mtd->ecc_stats.failed++;
+ } else if (status & TOSHIBA_NAND_STATUS_REWRITE_RECOMMENDED) {
+ /* corrected */
+ max_bitflips = mtd->bitflip_threshold;
+ mtd->ecc_stats.corrected += max_bitflips;
+ }
+
+ return max_bitflips;
+}
+
+static int
+toshiba_nand_read_page_benand(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
+{
+ int ret;
+
+ ret = nand_read_page_raw(chip, buf, oob_required, page);
+ if (ret)
+ return ret;
+
+ return toshiba_nand_benand_eccstatus(chip);
+}
+
+static int
+toshiba_nand_read_subpage_benand(struct nand_chip *chip, uint32_t data_offs,
+ uint32_t readlen, uint8_t *bufpoi, int page)
+{
+ int ret;
+
+ ret = nand_read_page_op(chip, page, data_offs,
+ bufpoi + data_offs, readlen);
+ if (ret)
+ return ret;
+
+ return toshiba_nand_benand_eccstatus(chip);
+}
+
+static void toshiba_nand_benand_init(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
+ /*
+ * On BENAND, the entire OOB region can be used by the MTD user.
+ * The calculated ECC bytes are stored into other isolated
+ * area which is not accessible to users.
+ * This is why chip->ecc.bytes = 0.
+ */
+ chip->ecc.bytes = 0;
+ chip->ecc.size = 512;
+ chip->ecc.strength = 8;
+ chip->ecc.read_page = toshiba_nand_read_page_benand;
+ chip->ecc.read_subpage = toshiba_nand_read_subpage_benand;
+ chip->ecc.write_page = nand_write_page_raw;
+ chip->ecc.read_page_raw = nand_read_page_raw_notsupp;
+ chip->ecc.write_page_raw = nand_write_page_raw_notsupp;
+
+ chip->options |= NAND_SUBPAGE_READ;
+
+ mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
+}
static void toshiba_nand_decode_id(struct nand_chip *chip)
{
@@ -68,6 +149,11 @@ static int toshiba_nand_init(struct nand_chip *chip)
if (nand_is_slc(chip))
chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
+ /* Check that chip is BENAND and ECC mode is on-die */
+ if (nand_is_slc(chip) && chip->ecc.mode == NAND_ECC_ON_DIE &&
+ chip->id.data[4] & TOSHIBA_NAND_ID4_IS_BENAND)
+ toshiba_nand_benand_init(chip);
+
return 0;
}
diff --git a/drivers/mtd/nand/raw/nandsim.c b/drivers/mtd/nand/raw/nandsim.c
index 71ac034aee9c..c452819f6123 100644
--- a/drivers/mtd/nand/raw/nandsim.c
+++ b/drivers/mtd/nand/raw/nandsim.c
@@ -656,7 +656,7 @@ static int __init init_nandsim(struct mtd_info *mtd)
}
/* Force mtd to not do delays */
- chip->chip_delay = 0;
+ chip->legacy.chip_delay = 0;
/* Initialize the NAND flash parameters */
ns->busw = chip->options & NAND_BUSWIDTH_16 ? 16 : 8;
@@ -1872,9 +1872,8 @@ static void switch_state(struct nandsim *ns)
}
}
-static u_char ns_nand_read_byte(struct mtd_info *mtd)
+static u_char ns_nand_read_byte(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct nandsim *ns = nand_get_controller_data(chip);
u_char outb = 0x00;
@@ -1934,9 +1933,8 @@ static u_char ns_nand_read_byte(struct mtd_info *mtd)
return outb;
}
-static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
+static void ns_nand_write_byte(struct nand_chip *chip, u_char byte)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct nandsim *ns = nand_get_controller_data(chip);
/* Sanity and correctness checks */
@@ -2089,9 +2087,8 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
return;
}
-static void ns_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int bitmask)
+static void ns_hwcontrol(struct nand_chip *chip, int cmd, unsigned int bitmask)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct nandsim *ns = nand_get_controller_data(chip);
ns->lines.cle = bitmask & NAND_CLE ? 1 : 0;
@@ -2099,27 +2096,18 @@ static void ns_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int bitmask)
ns->lines.ce = bitmask & NAND_NCE ? 1 : 0;
if (cmd != NAND_CMD_NONE)
- ns_nand_write_byte(mtd, cmd);
+ ns_nand_write_byte(chip, cmd);
}
-static int ns_device_ready(struct mtd_info *mtd)
+static int ns_device_ready(struct nand_chip *chip)
{
NS_DBG("device_ready\n");
return 1;
}
-static uint16_t ns_nand_read_word(struct mtd_info *mtd)
+static void ns_nand_write_buf(struct nand_chip *chip, const u_char *buf,
+ int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
-
- NS_DBG("read_word\n");
-
- return chip->read_byte(mtd) | (chip->read_byte(mtd) << 8);
-}
-
-static void ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct nandsim *ns = nand_get_controller_data(chip);
/* Check that chip is expecting data input */
@@ -2145,9 +2133,8 @@ static void ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
}
}
-static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void ns_nand_read_buf(struct nand_chip *chip, u_char *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct nandsim *ns = nand_get_controller_data(chip);
/* Sanity and correctness checks */
@@ -2169,7 +2156,7 @@ static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
int i;
for (i = 0; i < len; i++)
- buf[i] = mtd_to_nand(mtd)->read_byte(mtd);
+ buf[i] = chip->legacy.read_byte(chip);
return;
}
@@ -2262,12 +2249,11 @@ static int __init ns_init_module(void)
/*
* Register simulator's callbacks.
*/
- chip->cmd_ctrl = ns_hwcontrol;
- chip->read_byte = ns_nand_read_byte;
- chip->dev_ready = ns_device_ready;
- chip->write_buf = ns_nand_write_buf;
- chip->read_buf = ns_nand_read_buf;
- chip->read_word = ns_nand_read_word;
+ chip->legacy.cmd_ctrl = ns_hwcontrol;
+ chip->legacy.read_byte = ns_nand_read_byte;
+ chip->legacy.dev_ready = ns_device_ready;
+ chip->legacy.write_buf = ns_nand_write_buf;
+ chip->legacy.read_buf = ns_nand_read_buf;
chip->ecc.mode = NAND_ECC_SOFT;
chip->ecc.algo = NAND_ECC_HAMMING;
/* The NAND_SKIP_BBTSCAN option is necessary for 'overridesize' */
@@ -2319,7 +2305,7 @@ static int __init ns_init_module(void)
goto error;
chip->dummy_controller.ops = &ns_controller_ops;
- retval = nand_scan(nsmtd, 1);
+ retval = nand_scan(chip, 1);
if (retval) {
NS_ERR("Could not scan NAND Simulator device\n");
goto error;
@@ -2364,7 +2350,7 @@ static int __init ns_init_module(void)
err_exit:
free_nandsim(nand);
- nand_release(nsmtd);
+ nand_release(chip);
for (i = 0;i < ARRAY_SIZE(nand->partitions); ++i)
kfree(nand->partitions[i].name);
error:
@@ -2386,7 +2372,7 @@ static void __exit ns_cleanup_module(void)
int i;
free_nandsim(ns); /* Free nandsim private resources */
- nand_release(nsmtd); /* Unregister driver */
+ nand_release(chip); /* Unregister driver */
for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i)
kfree(ns->partitions[i].name);
kfree(mtd_to_nand(nsmtd)); /* Free other structures */
diff --git a/drivers/mtd/nand/raw/ndfc.c b/drivers/mtd/nand/raw/ndfc.c
index 540fa1a0ea24..d49a7a17146c 100644
--- a/drivers/mtd/nand/raw/ndfc.c
+++ b/drivers/mtd/nand/raw/ndfc.c
@@ -44,10 +44,9 @@ struct ndfc_controller {
static struct ndfc_controller ndfc_ctrl[NDFC_MAX_CS];
-static void ndfc_select_chip(struct mtd_info *mtd, int chip)
+static void ndfc_select_chip(struct nand_chip *nchip, int chip)
{
uint32_t ccr;
- struct nand_chip *nchip = mtd_to_nand(mtd);
struct ndfc_controller *ndfc = nand_get_controller_data(nchip);
ccr = in_be32(ndfc->ndfcbase + NDFC_CCR);
@@ -59,9 +58,8 @@ static void ndfc_select_chip(struct mtd_info *mtd, int chip)
out_be32(ndfc->ndfcbase + NDFC_CCR, ccr);
}
-static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+static void ndfc_hwcontrol(struct nand_chip *chip, int cmd, unsigned int ctrl)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct ndfc_controller *ndfc = nand_get_controller_data(chip);
if (cmd == NAND_CMD_NONE)
@@ -73,18 +71,16 @@ static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
writel(cmd & 0xFF, ndfc->ndfcbase + NDFC_ALE);
}
-static int ndfc_ready(struct mtd_info *mtd)
+static int ndfc_ready(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct ndfc_controller *ndfc = nand_get_controller_data(chip);
return in_be32(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY;
}
-static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode)
+static void ndfc_enable_hwecc(struct nand_chip *chip, int mode)
{
uint32_t ccr;
- struct nand_chip *chip = mtd_to_nand(mtd);
struct ndfc_controller *ndfc = nand_get_controller_data(chip);
ccr = in_be32(ndfc->ndfcbase + NDFC_CCR);
@@ -93,10 +89,9 @@ static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode)
wmb();
}
-static int ndfc_calculate_ecc(struct mtd_info *mtd,
+static int ndfc_calculate_ecc(struct nand_chip *chip,
const u_char *dat, u_char *ecc_code)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct ndfc_controller *ndfc = nand_get_controller_data(chip);
uint32_t ecc;
uint8_t *p = (uint8_t *)&ecc;
@@ -118,9 +113,8 @@ static int ndfc_calculate_ecc(struct mtd_info *mtd,
* functions. No further checking, as nand_base will always read/write
* page aligned.
*/
-static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void ndfc_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct ndfc_controller *ndfc = nand_get_controller_data(chip);
uint32_t *p = (uint32_t *) buf;
@@ -128,9 +122,8 @@ static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
*p++ = in_be32(ndfc->ndfcbase + NDFC_DATA);
}
-static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+static void ndfc_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct ndfc_controller *ndfc = nand_get_controller_data(chip);
uint32_t *p = (uint32_t *) buf;
@@ -149,15 +142,15 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc,
struct mtd_info *mtd = nand_to_mtd(chip);
int ret;
- chip->IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA;
- chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA;
- chip->cmd_ctrl = ndfc_hwcontrol;
- chip->dev_ready = ndfc_ready;
+ chip->legacy.IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA;
+ chip->legacy.IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA;
+ chip->legacy.cmd_ctrl = ndfc_hwcontrol;
+ chip->legacy.dev_ready = ndfc_ready;
chip->select_chip = ndfc_select_chip;
- chip->chip_delay = 50;
+ chip->legacy.chip_delay = 50;
chip->controller = &ndfc->ndfc_control;
- chip->read_buf = ndfc_read_buf;
- chip->write_buf = ndfc_write_buf;
+ chip->legacy.read_buf = ndfc_read_buf;
+ chip->legacy.write_buf = ndfc_write_buf;
chip->ecc.correct = nand_correct_data;
chip->ecc.hwctl = ndfc_enable_hwecc;
chip->ecc.calculate = ndfc_calculate_ecc;
@@ -174,14 +167,14 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc,
return -ENODEV;
nand_set_flash_node(chip, flash_np);
- mtd->name = kasprintf(GFP_KERNEL, "%s.%s", dev_name(&ndfc->ofdev->dev),
- flash_np->name);
+ mtd->name = kasprintf(GFP_KERNEL, "%s.%pOFn", dev_name(&ndfc->ofdev->dev),
+ flash_np);
if (!mtd->name) {
ret = -ENOMEM;
goto err;
}
- ret = nand_scan(mtd, 1);
+ ret = nand_scan(chip, 1);
if (ret)
goto err;
@@ -258,7 +251,7 @@ static int ndfc_remove(struct platform_device *ofdev)
struct ndfc_controller *ndfc = dev_get_drvdata(&ofdev->dev);
struct mtd_info *mtd = nand_to_mtd(&ndfc->chip);
- nand_release(mtd);
+ nand_release(&ndfc->chip);
kfree(mtd->name);
return 0;
diff --git a/drivers/mtd/nand/raw/nuc900_nand.c b/drivers/mtd/nand/raw/nuc900_nand.c
index af5b32c9a791..38b1994e7ed3 100644
--- a/drivers/mtd/nand/raw/nuc900_nand.c
+++ b/drivers/mtd/nand/raw/nuc900_nand.c
@@ -79,31 +79,31 @@ static const struct mtd_partition partitions[] = {
}
};
-static unsigned char nuc900_nand_read_byte(struct mtd_info *mtd)
+static unsigned char nuc900_nand_read_byte(struct nand_chip *chip)
{
unsigned char ret;
- struct nuc900_nand *nand = mtd_to_nuc900(mtd);
+ struct nuc900_nand *nand = mtd_to_nuc900(nand_to_mtd(chip));
ret = (unsigned char)read_data_reg(nand);
return ret;
}
-static void nuc900_nand_read_buf(struct mtd_info *mtd,
+static void nuc900_nand_read_buf(struct nand_chip *chip,
unsigned char *buf, int len)
{
int i;
- struct nuc900_nand *nand = mtd_to_nuc900(mtd);
+ struct nuc900_nand *nand = mtd_to_nuc900(nand_to_mtd(chip));
for (i = 0; i < len; i++)
buf[i] = (unsigned char)read_data_reg(nand);
}
-static void nuc900_nand_write_buf(struct mtd_info *mtd,
+static void nuc900_nand_write_buf(struct nand_chip *chip,
const unsigned char *buf, int len)
{
int i;
- struct nuc900_nand *nand = mtd_to_nuc900(mtd);
+ struct nuc900_nand *nand = mtd_to_nuc900(nand_to_mtd(chip));
for (i = 0; i < len; i++)
write_data_reg(nand, buf[i]);
@@ -120,19 +120,20 @@ static int nuc900_check_rb(struct nuc900_nand *nand)
return val;
}
-static int nuc900_nand_devready(struct mtd_info *mtd)
+static int nuc900_nand_devready(struct nand_chip *chip)
{
- struct nuc900_nand *nand = mtd_to_nuc900(mtd);
+ struct nuc900_nand *nand = mtd_to_nuc900(nand_to_mtd(chip));
int ready;
ready = (nuc900_check_rb(nand)) ? 1 : 0;
return ready;
}
-static void nuc900_nand_command_lp(struct mtd_info *mtd, unsigned int command,
+static void nuc900_nand_command_lp(struct nand_chip *chip,
+ unsigned int command,
int column, int page_addr)
{
- register struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct nuc900_nand *nand = mtd_to_nuc900(mtd);
if (command == NAND_CMD_READOOB) {
@@ -174,9 +175,9 @@ static void nuc900_nand_command_lp(struct mtd_info *mtd, unsigned int command,
return;
case NAND_CMD_RESET:
- if (chip->dev_ready)
+ if (chip->legacy.dev_ready)
break;
- udelay(chip->chip_delay);
+ udelay(chip->legacy.chip_delay);
write_cmd_reg(nand, NAND_CMD_STATUS);
write_cmd_reg(nand, command);
@@ -195,8 +196,8 @@ static void nuc900_nand_command_lp(struct mtd_info *mtd, unsigned int command,
write_cmd_reg(nand, NAND_CMD_READSTART);
default:
- if (!chip->dev_ready) {
- udelay(chip->chip_delay);
+ if (!chip->legacy.dev_ready) {
+ udelay(chip->legacy.chip_delay);
return;
}
}
@@ -205,7 +206,7 @@ static void nuc900_nand_command_lp(struct mtd_info *mtd, unsigned int command,
* any case on any machine. */
ndelay(100);
- while (!chip->dev_ready(mtd))
+ while (!chip->legacy.dev_ready(chip))
;
}
@@ -253,12 +254,12 @@ static int nuc900_nand_probe(struct platform_device *pdev)
return -ENOENT;
clk_enable(nuc900_nand->clk);
- chip->cmdfunc = nuc900_nand_command_lp;
- chip->dev_ready = nuc900_nand_devready;
- chip->read_byte = nuc900_nand_read_byte;
- chip->write_buf = nuc900_nand_write_buf;
- chip->read_buf = nuc900_nand_read_buf;
- chip->chip_delay = 50;
+ chip->legacy.cmdfunc = nuc900_nand_command_lp;
+ chip->legacy.dev_ready = nuc900_nand_devready;
+ chip->legacy.read_byte = nuc900_nand_read_byte;
+ chip->legacy.write_buf = nuc900_nand_write_buf;
+ chip->legacy.read_buf = nuc900_nand_read_buf;
+ chip->legacy.chip_delay = 50;
chip->options = 0;
chip->ecc.mode = NAND_ECC_SOFT;
chip->ecc.algo = NAND_ECC_HAMMING;
@@ -270,7 +271,7 @@ static int nuc900_nand_probe(struct platform_device *pdev)
nuc900_nand_enable(nuc900_nand);
- if (nand_scan(mtd, 1))
+ if (nand_scan(chip, 1))
return -ENXIO;
mtd_device_register(mtd, partitions, ARRAY_SIZE(partitions));
@@ -284,7 +285,7 @@ static int nuc900_nand_remove(struct platform_device *pdev)
{
struct nuc900_nand *nuc900_nand = platform_get_drvdata(pdev);
- nand_release(nand_to_mtd(&nuc900_nand->chip));
+ nand_release(&nuc900_nand->chip);
clk_disable(nuc900_nand->clk);
return 0;
diff --git a/drivers/mtd/nand/raw/omap2.c b/drivers/mtd/nand/raw/omap2.c
index 4546ac0bed4a..886d05c391ef 100644
--- a/drivers/mtd/nand/raw/omap2.c
+++ b/drivers/mtd/nand/raw/omap2.c
@@ -240,7 +240,7 @@ static int omap_prefetch_reset(int cs, struct omap_nand_info *info)
/**
* omap_hwcontrol - hardware specific access to control-lines
- * @mtd: MTD device structure
+ * @chip: NAND chip object
* @cmd: command to device
* @ctrl:
* NAND_NCE: bit 0 -> don't care
@@ -249,9 +249,9 @@ static int omap_prefetch_reset(int cs, struct omap_nand_info *info)
*
* NOTE: boards may use different bits for these!!
*/
-static void omap_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+static void omap_hwcontrol(struct nand_chip *chip, int cmd, unsigned int ctrl)
{
- struct omap_nand_info *info = mtd_to_omap(mtd);
+ struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));
if (cmd != NAND_CMD_NONE) {
if (ctrl & NAND_CLE)
@@ -275,7 +275,7 @@ static void omap_read_buf8(struct mtd_info *mtd, u_char *buf, int len)
{
struct nand_chip *nand = mtd_to_nand(mtd);
- ioread8_rep(nand->IO_ADDR_R, buf, len);
+ ioread8_rep(nand->legacy.IO_ADDR_R, buf, len);
}
/**
@@ -291,7 +291,7 @@ static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len)
bool status;
while (len--) {
- iowrite8(*p++, info->nand.IO_ADDR_W);
+ iowrite8(*p++, info->nand.legacy.IO_ADDR_W);
/* wait until buffer is available for write */
do {
status = info->ops->nand_writebuffer_empty();
@@ -309,7 +309,7 @@ static void omap_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
{
struct nand_chip *nand = mtd_to_nand(mtd);
- ioread16_rep(nand->IO_ADDR_R, buf, len / 2);
+ ioread16_rep(nand->legacy.IO_ADDR_R, buf, len / 2);
}
/**
@@ -327,7 +327,7 @@ static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len)
len >>= 1;
while (len--) {
- iowrite16(*p++, info->nand.IO_ADDR_W);
+ iowrite16(*p++, info->nand.legacy.IO_ADDR_W);
/* wait until buffer is available for write */
do {
status = info->ops->nand_writebuffer_empty();
@@ -337,12 +337,13 @@ static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len)
/**
* omap_read_buf_pref - read data from NAND controller into buffer
- * @mtd: MTD device structure
+ * @chip: NAND chip object
* @buf: buffer to store date
* @len: number of bytes to read
*/
-static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
+static void omap_read_buf_pref(struct nand_chip *chip, u_char *buf, int len)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct omap_nand_info *info = mtd_to_omap(mtd);
uint32_t r_count = 0;
int ret = 0;
@@ -372,7 +373,7 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
r_count = readl(info->reg.gpmc_prefetch_status);
r_count = PREFETCH_STATUS_FIFO_CNT(r_count);
r_count = r_count >> 2;
- ioread32_rep(info->nand.IO_ADDR_R, p, r_count);
+ ioread32_rep(info->nand.legacy.IO_ADDR_R, p, r_count);
p += r_count;
len -= r_count << 2;
} while (len);
@@ -383,13 +384,14 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
/**
* omap_write_buf_pref - write buffer to NAND controller
- * @mtd: MTD device structure
+ * @chip: NAND chip object
* @buf: data buffer
* @len: number of bytes to write
*/
-static void omap_write_buf_pref(struct mtd_info *mtd,
- const u_char *buf, int len)
+static void omap_write_buf_pref(struct nand_chip *chip, const u_char *buf,
+ int len)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct omap_nand_info *info = mtd_to_omap(mtd);
uint32_t w_count = 0;
int i = 0, ret = 0;
@@ -399,7 +401,7 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
/* take care of subpage writes */
if (len % 2 != 0) {
- writeb(*buf, info->nand.IO_ADDR_W);
+ writeb(*buf, info->nand.legacy.IO_ADDR_W);
p = (u16 *)(buf + 1);
len--;
}
@@ -419,7 +421,7 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
w_count = PREFETCH_STATUS_FIFO_CNT(w_count);
w_count = w_count >> 1;
for (i = 0; (i < w_count) && len; i++, len -= 2)
- iowrite16(*p++, info->nand.IO_ADDR_W);
+ iowrite16(*p++, info->nand.legacy.IO_ADDR_W);
}
/* wait for data to flushed-out before reset the prefetch */
tim = 0;
@@ -528,14 +530,17 @@ out_copy:
/**
* omap_read_buf_dma_pref - read data from NAND controller into buffer
- * @mtd: MTD device structure
+ * @chip: NAND chip object
* @buf: buffer to store date
* @len: number of bytes to read
*/
-static void omap_read_buf_dma_pref(struct mtd_info *mtd, u_char *buf, int len)
+static void omap_read_buf_dma_pref(struct nand_chip *chip, u_char *buf,
+ int len)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
if (len <= mtd->oobsize)
- omap_read_buf_pref(mtd, buf, len);
+ omap_read_buf_pref(chip, buf, len);
else
/* start transfer in DMA mode */
omap_nand_dma_transfer(mtd, buf, len, 0x0);
@@ -543,18 +548,20 @@ static void omap_read_buf_dma_pref(struct mtd_info *mtd, u_char *buf, int len)
/**
* omap_write_buf_dma_pref - write buffer to NAND controller
- * @mtd: MTD device structure
+ * @chip: NAND chip object
* @buf: data buffer
* @len: number of bytes to write
*/
-static void omap_write_buf_dma_pref(struct mtd_info *mtd,
- const u_char *buf, int len)
+static void omap_write_buf_dma_pref(struct nand_chip *chip, const u_char *buf,
+ int len)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
if (len <= mtd->oobsize)
- omap_write_buf_pref(mtd, buf, len);
+ omap_write_buf_pref(chip, buf, len);
else
/* start transfer in DMA mode */
- omap_nand_dma_transfer(mtd, (u_char *) buf, len, 0x1);
+ omap_nand_dma_transfer(mtd, (u_char *)buf, len, 0x1);
}
/*
@@ -578,14 +585,14 @@ static irqreturn_t omap_nand_irq(int this_irq, void *dev)
bytes = info->buf_len;
else if (!info->buf_len)
bytes = 0;
- iowrite32_rep(info->nand.IO_ADDR_W,
- (u32 *)info->buf, bytes >> 2);
+ iowrite32_rep(info->nand.legacy.IO_ADDR_W, (u32 *)info->buf,
+ bytes >> 2);
info->buf = info->buf + bytes;
info->buf_len -= bytes;
} else {
- ioread32_rep(info->nand.IO_ADDR_R,
- (u32 *)info->buf, bytes >> 2);
+ ioread32_rep(info->nand.legacy.IO_ADDR_R, (u32 *)info->buf,
+ bytes >> 2);
info->buf = info->buf + bytes;
if (this_irq == info->gpmc_irq_count)
@@ -605,17 +612,19 @@ done:
/*
* omap_read_buf_irq_pref - read data from NAND controller into buffer
- * @mtd: MTD device structure
+ * @chip: NAND chip object
* @buf: buffer to store date
* @len: number of bytes to read
*/
-static void omap_read_buf_irq_pref(struct mtd_info *mtd, u_char *buf, int len)
+static void omap_read_buf_irq_pref(struct nand_chip *chip, u_char *buf,
+ int len)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct omap_nand_info *info = mtd_to_omap(mtd);
int ret = 0;
if (len <= mtd->oobsize) {
- omap_read_buf_pref(mtd, buf, len);
+ omap_read_buf_pref(chip, buf, len);
return;
}
@@ -651,20 +660,21 @@ out_copy:
/*
* omap_write_buf_irq_pref - write buffer to NAND controller
- * @mtd: MTD device structure
+ * @chip: NAND chip object
* @buf: data buffer
* @len: number of bytes to write
*/
-static void omap_write_buf_irq_pref(struct mtd_info *mtd,
- const u_char *buf, int len)
+static void omap_write_buf_irq_pref(struct nand_chip *chip, const u_char *buf,
+ int len)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct omap_nand_info *info = mtd_to_omap(mtd);
int ret = 0;
unsigned long tim, limit;
u32 val;
if (len <= mtd->oobsize) {
- omap_write_buf_pref(mtd, buf, len);
+ omap_write_buf_pref(chip, buf, len);
return;
}
@@ -857,7 +867,7 @@ static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */
/**
* omap_correct_data - Compares the ECC read with HW generated ECC
- * @mtd: MTD device structure
+ * @chip: NAND chip object
* @dat: page data
* @read_ecc: ecc read from nand flash
* @calc_ecc: ecc read from HW ECC registers
@@ -869,10 +879,10 @@ static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */
* corrected errors is returned. If uncorrectable errors exist, %-1 is
* returned.
*/
-static int omap_correct_data(struct mtd_info *mtd, u_char *dat,
- u_char *read_ecc, u_char *calc_ecc)
+static int omap_correct_data(struct nand_chip *chip, u_char *dat,
+ u_char *read_ecc, u_char *calc_ecc)
{
- struct omap_nand_info *info = mtd_to_omap(mtd);
+ struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));
int blockCnt = 0, i = 0, ret = 0;
int stat = 0;
@@ -900,7 +910,7 @@ static int omap_correct_data(struct mtd_info *mtd, u_char *dat,
/**
* omap_calcuate_ecc - Generate non-inverted ECC bytes.
- * @mtd: MTD device structure
+ * @chip: NAND chip object
* @dat: The pointer to data on which ecc is computed
* @ecc_code: The ecc_code buffer
*
@@ -910,10 +920,10 @@ static int omap_correct_data(struct mtd_info *mtd, u_char *dat,
* an erased page will produce an ECC mismatch between generated and read
* ECC bytes that has to be dealt with separately.
*/
-static int omap_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
- u_char *ecc_code)
+static int omap_calculate_ecc(struct nand_chip *chip, const u_char *dat,
+ u_char *ecc_code)
{
- struct omap_nand_info *info = mtd_to_omap(mtd);
+ struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));
u32 val;
val = readl(info->reg.gpmc_ecc_config);
@@ -935,10 +945,9 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
* @mtd: MTD device structure
* @mode: Read/Write mode
*/
-static void omap_enable_hwecc(struct mtd_info *mtd, int mode)
+static void omap_enable_hwecc(struct nand_chip *chip, int mode)
{
- struct omap_nand_info *info = mtd_to_omap(mtd);
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));
unsigned int dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0;
u32 val;
@@ -972,8 +981,7 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int mode)
/**
* omap_wait - wait until the command is done
- * @mtd: MTD device structure
- * @chip: NAND Chip structure
+ * @this: NAND Chip structure
*
* Wait function is called during Program and erase operations and
* the way it is called from MTD layer, we should wait till the NAND
@@ -982,10 +990,9 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int mode)
* Erase can take up to 400ms and program up to 20ms according to
* general NAND and SmartMedia specs
*/
-static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
+static int omap_wait(struct nand_chip *this)
{
- struct nand_chip *this = mtd_to_nand(mtd);
- struct omap_nand_info *info = mtd_to_omap(mtd);
+ struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(this));
unsigned long timeo = jiffies;
int status, state = this->state;
@@ -1012,9 +1019,9 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
*
* Returns true if ready and false if busy.
*/
-static int omap_dev_ready(struct mtd_info *mtd)
+static int omap_dev_ready(struct nand_chip *chip)
{
- struct omap_nand_info *info = mtd_to_omap(mtd);
+ struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));
return gpiod_get_value(info->ready_gpiod);
}
@@ -1030,13 +1037,13 @@ static int omap_dev_ready(struct mtd_info *mtd)
* eccsize0 = 0 (no additional protected byte in spare area)
* eccsize1 = 32 (skip 32 nibbles = 16 bytes per sector in spare area)
*/
-static void __maybe_unused omap_enable_hwecc_bch(struct mtd_info *mtd, int mode)
+static void __maybe_unused omap_enable_hwecc_bch(struct nand_chip *chip,
+ int mode)
{
unsigned int bch_type;
unsigned int dev_width, nsectors;
- struct omap_nand_info *info = mtd_to_omap(mtd);
+ struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));
enum omap_ecc ecc_opt = info->ecc_opt;
- struct nand_chip *chip = mtd_to_nand(mtd);
u32 val, wr_mode;
unsigned int ecc_size1, ecc_size0;
@@ -1256,7 +1263,7 @@ static int _omap_calculate_ecc_bch(struct mtd_info *mtd,
/**
* omap_calculate_ecc_bch_sw - ECC generator for sector for SW based correction
- * @mtd: MTD device structure
+ * @chip: NAND chip object
* @dat: The pointer to data on which ecc is computed
* @ecc_code: The ecc_code buffer
*
@@ -1264,10 +1271,10 @@ static int _omap_calculate_ecc_bch(struct mtd_info *mtd,
* when SW based correction is required as ECC is required for one sector
* at a time.
*/
-static int omap_calculate_ecc_bch_sw(struct mtd_info *mtd,
+static int omap_calculate_ecc_bch_sw(struct nand_chip *chip,
const u_char *dat, u_char *ecc_calc)
{
- return _omap_calculate_ecc_bch(mtd, dat, ecc_calc, 0);
+ return _omap_calculate_ecc_bch(nand_to_mtd(chip), dat, ecc_calc, 0);
}
/**
@@ -1339,7 +1346,7 @@ static int erased_sector_bitflips(u_char *data, u_char *oob,
/**
* omap_elm_correct_data - corrects page data area in case error reported
- * @mtd: MTD device structure
+ * @chip: NAND chip object
* @data: page data
* @read_ecc: ecc read from nand flash
* @calc_ecc: ecc read from HW ECC registers
@@ -1348,10 +1355,10 @@ static int erased_sector_bitflips(u_char *data, u_char *oob,
* In case of non-zero ecc vector, first filter out erased-pages, and
* then process data via ELM to detect bit-flips.
*/
-static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
- u_char *read_ecc, u_char *calc_ecc)
+static int omap_elm_correct_data(struct nand_chip *chip, u_char *data,
+ u_char *read_ecc, u_char *calc_ecc)
{
- struct omap_nand_info *info = mtd_to_omap(mtd);
+ 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 i , j, stat = 0;
@@ -1512,7 +1519,6 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
/**
* omap_write_page_bch - BCH ecc based write page function for entire page
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: data buffer
* @oob_required: must write chip->oob_poi to OOB
@@ -1520,19 +1526,20 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
*
* Custom write page method evolved to support multi sector writing in one shot
*/
-static int omap_write_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required, int page)
+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;
uint8_t *ecc_calc = chip->ecc.calc_buf;
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
/* Enable GPMC ecc engine */
- chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+ chip->ecc.hwctl(chip, NAND_ECC_WRITE);
/* Write data */
- chip->write_buf(mtd, buf, mtd->writesize);
+ chip->legacy.write_buf(chip, buf, mtd->writesize);
/* Update ecc vector from GPMC result registers */
omap_calculate_ecc_bch_multi(mtd, buf, &ecc_calc[0]);
@@ -1543,14 +1550,13 @@ static int omap_write_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
return ret;
/* Write ecc vector to OOB area */
- chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize);
return nand_prog_page_end_op(chip);
}
/**
* omap_write_subpage_bch - BCH hardware ECC based subpage write
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @offset: column address of subpage within the page
* @data_len: data length
@@ -1560,11 +1566,11 @@ static int omap_write_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
*
* OMAP optimized subpage write method.
*/
-static int omap_write_subpage_bch(struct mtd_info *mtd,
- struct nand_chip *chip, u32 offset,
+static int omap_write_subpage_bch(struct nand_chip *chip, u32 offset,
u32 data_len, const u8 *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
u8 *ecc_calc = chip->ecc.calc_buf;
int ecc_size = chip->ecc.size;
int ecc_bytes = chip->ecc.bytes;
@@ -1582,10 +1588,10 @@ static int omap_write_subpage_bch(struct mtd_info *mtd,
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
/* Enable GPMC ECC engine */
- chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+ chip->ecc.hwctl(chip, NAND_ECC_WRITE);
/* Write data */
- chip->write_buf(mtd, buf, mtd->writesize);
+ chip->legacy.write_buf(chip, buf, mtd->writesize);
for (step = 0; step < ecc_steps; step++) {
/* mask ECC of un-touched subpages by padding 0xFF */
@@ -1610,14 +1616,13 @@ static int omap_write_subpage_bch(struct mtd_info *mtd,
return ret;
/* write OOB buffer to NAND device */
- chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize);
return nand_prog_page_end_op(chip);
}
/**
* omap_read_page_bch - BCH ecc based page read function for entire page
- * @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
* @oob_required: caller requires OOB data read to chip->oob_poi
@@ -1630,9 +1635,10 @@ static int omap_write_subpage_bch(struct mtd_info *mtd,
* ecc engine enabled. ecc vector updated after read of OOB data.
* For non error pages ecc vector reported as zero.
*/
-static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+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);
uint8_t *ecc_calc = chip->ecc.calc_buf;
uint8_t *ecc_code = chip->ecc.code_buf;
int stat, ret;
@@ -1641,10 +1647,10 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
nand_read_page_op(chip, page, 0, NULL, 0);
/* Enable GPMC ecc engine */
- chip->ecc.hwctl(mtd, NAND_ECC_READ);
+ chip->ecc.hwctl(chip, NAND_ECC_READ);
/* Read data */
- chip->read_buf(mtd, buf, mtd->writesize);
+ chip->legacy.read_buf(chip, buf, mtd->writesize);
/* Read oob bytes */
nand_change_read_column_op(chip,
@@ -1660,7 +1666,7 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
if (ret)
return ret;
- stat = chip->ecc.correct(mtd, buf, ecc_code, ecc_calc);
+ stat = chip->ecc.correct(chip, buf, ecc_code, ecc_calc);
if (stat < 0) {
mtd->ecc_stats.failed++;
@@ -1927,8 +1933,8 @@ static int omap_nand_attach_chip(struct nand_chip *chip)
/* Re-populate low-level callbacks based on xfer modes */
switch (info->xfer_type) {
case NAND_OMAP_PREFETCH_POLLED:
- chip->read_buf = omap_read_buf_pref;
- chip->write_buf = omap_write_buf_pref;
+ chip->legacy.read_buf = omap_read_buf_pref;
+ chip->legacy.write_buf = omap_write_buf_pref;
break;
case NAND_OMAP_POLLED:
@@ -1960,8 +1966,8 @@ static int omap_nand_attach_chip(struct nand_chip *chip)
err);
return err;
}
- chip->read_buf = omap_read_buf_dma_pref;
- chip->write_buf = omap_write_buf_dma_pref;
+ chip->legacy.read_buf = omap_read_buf_dma_pref;
+ chip->legacy.write_buf = omap_write_buf_dma_pref;
}
break;
@@ -1996,8 +2002,8 @@ static int omap_nand_attach_chip(struct nand_chip *chip)
return err;
}
- chip->read_buf = omap_read_buf_irq_pref;
- chip->write_buf = omap_write_buf_irq_pref;
+ chip->legacy.read_buf = omap_read_buf_irq_pref;
+ chip->legacy.write_buf = omap_write_buf_irq_pref;
break;
@@ -2215,16 +2221,16 @@ static int omap_nand_probe(struct platform_device *pdev)
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- nand_chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(nand_chip->IO_ADDR_R))
- return PTR_ERR(nand_chip->IO_ADDR_R);
+ nand_chip->legacy.IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(nand_chip->legacy.IO_ADDR_R))
+ return PTR_ERR(nand_chip->legacy.IO_ADDR_R);
info->phys_base = res->start;
nand_chip->controller = &omap_gpmc_controller;
- nand_chip->IO_ADDR_W = nand_chip->IO_ADDR_R;
- nand_chip->cmd_ctrl = omap_hwcontrol;
+ nand_chip->legacy.IO_ADDR_W = nand_chip->legacy.IO_ADDR_R;
+ nand_chip->legacy.cmd_ctrl = omap_hwcontrol;
info->ready_gpiod = devm_gpiod_get_optional(&pdev->dev, "rb",
GPIOD_IN);
@@ -2241,11 +2247,11 @@ static int omap_nand_probe(struct platform_device *pdev)
* device and read status register until you get a failure or success
*/
if (info->ready_gpiod) {
- nand_chip->dev_ready = omap_dev_ready;
- nand_chip->chip_delay = 0;
+ nand_chip->legacy.dev_ready = omap_dev_ready;
+ nand_chip->legacy.chip_delay = 0;
} else {
- nand_chip->waitfunc = omap_wait;
- nand_chip->chip_delay = 50;
+ nand_chip->legacy.waitfunc = omap_wait;
+ nand_chip->legacy.chip_delay = 50;
}
if (info->flash_bbt)
@@ -2254,7 +2260,7 @@ static int omap_nand_probe(struct platform_device *pdev)
/* scan NAND device connected to chip controller */
nand_chip->options |= info->devsize & NAND_BUSWIDTH_16;
- err = nand_scan(mtd, 1);
+ err = nand_scan(nand_chip, 1);
if (err)
goto return_error;
@@ -2290,7 +2296,7 @@ static int omap_nand_remove(struct platform_device *pdev)
}
if (info->dma)
dma_release_channel(info->dma);
- nand_release(mtd);
+ nand_release(nand_chip);
return 0;
}
diff --git a/drivers/mtd/nand/raw/orion_nand.c b/drivers/mtd/nand/raw/orion_nand.c
index 52d435285a3f..d27b39a7223c 100644
--- a/drivers/mtd/nand/raw/orion_nand.c
+++ b/drivers/mtd/nand/raw/orion_nand.c
@@ -26,9 +26,9 @@ struct orion_nand_info {
struct clk *clk;
};
-static void orion_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+static void orion_nand_cmd_ctrl(struct nand_chip *nc, int cmd,
+ unsigned int ctrl)
{
- struct nand_chip *nc = mtd_to_nand(mtd);
struct orion_nand_data *board = nand_get_controller_data(nc);
u32 offs;
@@ -45,13 +45,12 @@ static void orion_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl
if (nc->options & NAND_BUSWIDTH_16)
offs <<= 1;
- writeb(cmd, nc->IO_ADDR_W + offs);
+ writeb(cmd, nc->legacy.IO_ADDR_W + offs);
}
-static void orion_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void orion_nand_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
- void __iomem *io_base = chip->IO_ADDR_R;
+ void __iomem *io_base = chip->legacy.IO_ADDR_R;
#if defined(__LINUX_ARM_ARCH__) && __LINUX_ARM_ARCH__ >= 5
uint64_t *buf64;
#endif
@@ -137,14 +136,14 @@ static int __init orion_nand_probe(struct platform_device *pdev)
nand_set_controller_data(nc, board);
nand_set_flash_node(nc, pdev->dev.of_node);
- nc->IO_ADDR_R = nc->IO_ADDR_W = io_base;
- nc->cmd_ctrl = orion_nand_cmd_ctrl;
- nc->read_buf = orion_nand_read_buf;
+ nc->legacy.IO_ADDR_R = nc->legacy.IO_ADDR_W = io_base;
+ nc->legacy.cmd_ctrl = orion_nand_cmd_ctrl;
+ nc->legacy.read_buf = orion_nand_read_buf;
nc->ecc.mode = NAND_ECC_SOFT;
nc->ecc.algo = NAND_ECC_HAMMING;
if (board->chip_delay)
- nc->chip_delay = board->chip_delay;
+ nc->legacy.chip_delay = board->chip_delay;
WARN(board->width > 16,
"%d bit bus width out of range",
@@ -174,14 +173,14 @@ static int __init orion_nand_probe(struct platform_device *pdev)
return ret;
}
- ret = nand_scan(mtd, 1);
+ ret = nand_scan(nc, 1);
if (ret)
goto no_dev;
mtd->name = "orion_nand";
ret = mtd_device_register(mtd, board->parts, board->nr_parts);
if (ret) {
- nand_release(mtd);
+ nand_release(nc);
goto no_dev;
}
@@ -196,9 +195,8 @@ static int orion_nand_remove(struct platform_device *pdev)
{
struct orion_nand_info *info = platform_get_drvdata(pdev);
struct nand_chip *chip = &info->chip;
- struct mtd_info *mtd = nand_to_mtd(chip);
- nand_release(mtd);
+ nand_release(chip);
clk_disable_unprepare(info->clk);
diff --git a/drivers/mtd/nand/raw/oxnas_nand.c b/drivers/mtd/nand/raw/oxnas_nand.c
index 01b00bb69c1e..0e52dc29141c 100644
--- a/drivers/mtd/nand/raw/oxnas_nand.c
+++ b/drivers/mtd/nand/raw/oxnas_nand.c
@@ -38,35 +38,32 @@ struct oxnas_nand_ctrl {
struct nand_chip *chips[OXNAS_NAND_MAX_CHIPS];
};
-static uint8_t oxnas_nand_read_byte(struct mtd_info *mtd)
+static uint8_t oxnas_nand_read_byte(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
return readb(oxnas->io_base);
}
-static void oxnas_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+static void oxnas_nand_read_buf(struct nand_chip *chip, u8 *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
ioread8_rep(oxnas->io_base, buf, len);
}
-static void oxnas_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+static void oxnas_nand_write_buf(struct nand_chip *chip, const u8 *buf,
+ int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
iowrite8_rep(oxnas->io_base, buf, len);
}
/* Single CS command control */
-static void oxnas_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+static void oxnas_nand_cmd_ctrl(struct nand_chip *chip, int cmd,
unsigned int ctrl)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
if (ctrl & NAND_CLE)
@@ -135,20 +132,20 @@ static int oxnas_nand_probe(struct platform_device *pdev)
mtd->dev.parent = &pdev->dev;
mtd->priv = chip;
- chip->cmd_ctrl = oxnas_nand_cmd_ctrl;
- chip->read_buf = oxnas_nand_read_buf;
- chip->read_byte = oxnas_nand_read_byte;
- chip->write_buf = oxnas_nand_write_buf;
- chip->chip_delay = 30;
+ chip->legacy.cmd_ctrl = oxnas_nand_cmd_ctrl;
+ chip->legacy.read_buf = oxnas_nand_read_buf;
+ chip->legacy.read_byte = oxnas_nand_read_byte;
+ chip->legacy.write_buf = oxnas_nand_write_buf;
+ chip->legacy.chip_delay = 30;
/* Scan to find existence of the device */
- err = nand_scan(mtd, 1);
+ err = nand_scan(chip, 1);
if (err)
goto err_clk_unprepare;
err = mtd_device_register(mtd, NULL, 0);
if (err) {
- nand_release(mtd);
+ nand_release(chip);
goto err_clk_unprepare;
}
@@ -176,7 +173,7 @@ static int oxnas_nand_remove(struct platform_device *pdev)
struct oxnas_nand_ctrl *oxnas = platform_get_drvdata(pdev);
if (oxnas->chips[0])
- nand_release(nand_to_mtd(oxnas->chips[0]));
+ nand_release(oxnas->chips[0]);
clk_disable_unprepare(oxnas->clk);
diff --git a/drivers/mtd/nand/raw/pasemi_nand.c b/drivers/mtd/nand/raw/pasemi_nand.c
index a47a7e4bd25a..643cd22af009 100644
--- a/drivers/mtd/nand/raw/pasemi_nand.c
+++ b/drivers/mtd/nand/raw/pasemi_nand.c
@@ -43,49 +43,44 @@ static unsigned int lpcctl;
static struct mtd_info *pasemi_nand_mtd;
static const char driver_name[] = "pasemi-nand";
-static void pasemi_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void pasemi_read_buf(struct nand_chip *chip, u_char *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
-
while (len > 0x800) {
- memcpy_fromio(buf, chip->IO_ADDR_R, 0x800);
+ memcpy_fromio(buf, chip->legacy.IO_ADDR_R, 0x800);
buf += 0x800;
len -= 0x800;
}
- memcpy_fromio(buf, chip->IO_ADDR_R, len);
+ memcpy_fromio(buf, chip->legacy.IO_ADDR_R, len);
}
-static void pasemi_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+static void pasemi_write_buf(struct nand_chip *chip, const u_char *buf,
+ int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
-
while (len > 0x800) {
- memcpy_toio(chip->IO_ADDR_R, buf, 0x800);
+ memcpy_toio(chip->legacy.IO_ADDR_R, buf, 0x800);
buf += 0x800;
len -= 0x800;
}
- memcpy_toio(chip->IO_ADDR_R, buf, len);
+ memcpy_toio(chip->legacy.IO_ADDR_R, buf, len);
}
-static void pasemi_hwcontrol(struct mtd_info *mtd, int cmd,
+static void pasemi_hwcontrol(struct nand_chip *chip, int cmd,
unsigned int ctrl)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
-
if (cmd == NAND_CMD_NONE)
return;
if (ctrl & NAND_CLE)
- out_8(chip->IO_ADDR_W + (1 << CLE_PIN_CTL), cmd);
+ out_8(chip->legacy.IO_ADDR_W + (1 << CLE_PIN_CTL), cmd);
else
- out_8(chip->IO_ADDR_W + (1 << ALE_PIN_CTL), cmd);
+ out_8(chip->legacy.IO_ADDR_W + (1 << ALE_PIN_CTL), cmd);
/* Push out posted writes */
eieio();
inl(lpcctl);
}
-int pasemi_device_ready(struct mtd_info *mtd)
+int pasemi_device_ready(struct nand_chip *chip)
{
return !!(inl(lpcctl) & LBICTRL_LPCCTL_NR);
}
@@ -122,10 +117,10 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
/* Link the private data with the MTD structure */
pasemi_nand_mtd->dev.parent = dev;
- chip->IO_ADDR_R = of_iomap(np, 0);
- chip->IO_ADDR_W = chip->IO_ADDR_R;
+ chip->legacy.IO_ADDR_R = of_iomap(np, 0);
+ chip->legacy.IO_ADDR_W = chip->legacy.IO_ADDR_R;
- if (!chip->IO_ADDR_R) {
+ if (!chip->legacy.IO_ADDR_R) {
err = -EIO;
goto out_mtd;
}
@@ -144,11 +139,11 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
goto out_ior;
}
- chip->cmd_ctrl = pasemi_hwcontrol;
- chip->dev_ready = pasemi_device_ready;
- chip->read_buf = pasemi_read_buf;
- chip->write_buf = pasemi_write_buf;
- chip->chip_delay = 0;
+ chip->legacy.cmd_ctrl = pasemi_hwcontrol;
+ chip->legacy.dev_ready = pasemi_device_ready;
+ chip->legacy.read_buf = pasemi_read_buf;
+ chip->legacy.write_buf = pasemi_write_buf;
+ chip->legacy.chip_delay = 0;
chip->ecc.mode = NAND_ECC_SOFT;
chip->ecc.algo = NAND_ECC_HAMMING;
@@ -156,7 +151,7 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
chip->bbt_options = NAND_BBT_USE_FLASH;
/* Scan to find existence of the device */
- err = nand_scan(pasemi_nand_mtd, 1);
+ err = nand_scan(chip, 1);
if (err)
goto out_lpc;
@@ -174,7 +169,7 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
out_lpc:
release_region(lpcctl, 4);
out_ior:
- iounmap(chip->IO_ADDR_R);
+ iounmap(chip->legacy.IO_ADDR_R);
out_mtd:
kfree(chip);
out:
@@ -191,11 +186,11 @@ static int pasemi_nand_remove(struct platform_device *ofdev)
chip = mtd_to_nand(pasemi_nand_mtd);
/* Release resources, unregister device */
- nand_release(pasemi_nand_mtd);
+ nand_release(chip);
release_region(lpcctl, 4);
- iounmap(chip->IO_ADDR_R);
+ iounmap(chip->legacy.IO_ADDR_R);
/* Free the MTD device structure */
kfree(chip);
diff --git a/drivers/mtd/nand/raw/plat_nand.c b/drivers/mtd/nand/raw/plat_nand.c
index 222626df4b96..86c536ddaf24 100644
--- a/drivers/mtd/nand/raw/plat_nand.c
+++ b/drivers/mtd/nand/raw/plat_nand.c
@@ -15,8 +15,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
+#include <linux/mtd/platnand.h>
struct plat_nand_data {
struct nand_chip chip;
@@ -60,14 +59,14 @@ static int plat_nand_probe(struct platform_device *pdev)
mtd = nand_to_mtd(&data->chip);
mtd->dev.parent = &pdev->dev;
- data->chip.IO_ADDR_R = data->io_base;
- data->chip.IO_ADDR_W = data->io_base;
- data->chip.cmd_ctrl = pdata->ctrl.cmd_ctrl;
- data->chip.dev_ready = pdata->ctrl.dev_ready;
+ data->chip.legacy.IO_ADDR_R = data->io_base;
+ data->chip.legacy.IO_ADDR_W = data->io_base;
+ data->chip.legacy.cmd_ctrl = pdata->ctrl.cmd_ctrl;
+ data->chip.legacy.dev_ready = pdata->ctrl.dev_ready;
data->chip.select_chip = pdata->ctrl.select_chip;
- data->chip.write_buf = pdata->ctrl.write_buf;
- data->chip.read_buf = pdata->ctrl.read_buf;
- data->chip.chip_delay = pdata->chip.chip_delay;
+ data->chip.legacy.write_buf = pdata->ctrl.write_buf;
+ data->chip.legacy.read_buf = pdata->ctrl.read_buf;
+ data->chip.legacy.chip_delay = pdata->chip.chip_delay;
data->chip.options |= pdata->chip.options;
data->chip.bbt_options |= pdata->chip.bbt_options;
@@ -84,7 +83,7 @@ static int plat_nand_probe(struct platform_device *pdev)
}
/* Scan to find existence of the device */
- err = nand_scan(mtd, pdata->chip.nr_chips);
+ err = nand_scan(&data->chip, pdata->chip.nr_chips);
if (err)
goto out;
@@ -97,7 +96,7 @@ static int plat_nand_probe(struct platform_device *pdev)
if (!err)
return err;
- nand_release(mtd);
+ nand_release(&data->chip);
out:
if (pdata->ctrl.remove)
pdata->ctrl.remove(pdev);
@@ -112,7 +111,7 @@ static int plat_nand_remove(struct platform_device *pdev)
struct plat_nand_data *data = platform_get_drvdata(pdev);
struct platform_nand_data *pdata = dev_get_platdata(&pdev->dev);
- nand_release(nand_to_mtd(&data->chip));
+ nand_release(&data->chip);
if (pdata->ctrl.remove)
pdata->ctrl.remove(pdev);
diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c
index d1d470bb32e4..ef75dfa62a4f 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -23,7 +23,6 @@
#include <linux/of_device.h>
#include <linux/delay.h>
#include <linux/dma/qcom_bam_dma.h>
-#include <linux/dma-direct.h> /* XXX: drivers shall never use this directly! */
/* NANDc reg offsets */
#define NAND_FLASH_CMD 0x00
@@ -350,7 +349,8 @@ struct nandc_regs {
* @data_buffer: our local DMA buffer for page read/writes,
* used when we can't use the buffer provided
* by upper layers directly
- * @buf_size/count/start: markers for chip->read_buf/write_buf functions
+ * @buf_size/count/start: markers for chip->legacy.read_buf/write_buf
+ * functions
* @reg_read_buf: local buffer for reading back registers via DMA
* @reg_read_dma: contains dma address for register read buffer
* @reg_read_pos: marker for data read in reg_read_buf
@@ -1155,8 +1155,8 @@ static void config_nand_cw_write(struct qcom_nand_controller *nandc)
}
/*
- * the following functions are used within chip->cmdfunc() to perform different
- * NAND_CMD_* commands
+ * the following functions are used within chip->legacy.cmdfunc() to
+ * perform different NAND_CMD_* commands
*/
/* sets up descriptors for NAND_CMD_PARAM */
@@ -1436,15 +1436,14 @@ static void post_command(struct qcom_nand_host *host, int command)
}
/*
- * Implements chip->cmdfunc. It's only used for a limited set of commands.
- * The rest of the commands wouldn't be called by upper layers. For example,
- * NAND_CMD_READOOB would never be called because we have our own versions
- * of read_oob ops for nand_ecc_ctrl.
+ * Implements chip->legacy.cmdfunc. It's only used for a limited set of
+ * commands. The rest of the commands wouldn't be called by upper layers.
+ * For example, NAND_CMD_READOOB would never be called because we have our own
+ * versions of read_oob ops for nand_ecc_ctrl.
*/
-static void qcom_nandc_command(struct mtd_info *mtd, unsigned int command,
+static void qcom_nandc_command(struct nand_chip *chip, unsigned int command,
int column, int page_addr)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct qcom_nand_host *host = to_qcom_nand_host(chip);
struct nand_ecc_ctrl *ecc = &chip->ecc;
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
@@ -1949,8 +1948,8 @@ static int copy_last_cw(struct qcom_nand_host *host, int page)
}
/* implements ecc->read_page() */
-static int qcom_nandc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+static int qcom_nandc_read_page(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
struct qcom_nand_host *host = to_qcom_nand_host(chip);
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
@@ -1966,10 +1965,10 @@ static int qcom_nandc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
}
/* implements ecc->read_page_raw() */
-static int qcom_nandc_read_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip, uint8_t *buf,
+static int qcom_nandc_read_page_raw(struct nand_chip *chip, uint8_t *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct qcom_nand_host *host = to_qcom_nand_host(chip);
struct nand_ecc_ctrl *ecc = &chip->ecc;
int cw, ret;
@@ -1989,8 +1988,7 @@ static int qcom_nandc_read_page_raw(struct mtd_info *mtd,
}
/* implements ecc->read_oob() */
-static int qcom_nandc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int qcom_nandc_read_oob(struct nand_chip *chip, int page)
{
struct qcom_nand_host *host = to_qcom_nand_host(chip);
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
@@ -2007,8 +2005,8 @@ static int qcom_nandc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
}
/* implements ecc->write_page() */
-static int qcom_nandc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required, int page)
+static int qcom_nandc_write_page(struct nand_chip *chip, const uint8_t *buf,
+ int oob_required, int page)
{
struct qcom_nand_host *host = to_qcom_nand_host(chip);
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
@@ -2077,10 +2075,11 @@ static int qcom_nandc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
}
/* implements ecc->write_page_raw() */
-static int qcom_nandc_write_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip, const uint8_t *buf,
- int oob_required, int page)
+static int qcom_nandc_write_page_raw(struct nand_chip *chip,
+ const uint8_t *buf, int oob_required,
+ int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct qcom_nand_host *host = to_qcom_nand_host(chip);
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
struct nand_ecc_ctrl *ecc = &chip->ecc;
@@ -2155,9 +2154,9 @@ static int qcom_nandc_write_page_raw(struct mtd_info *mtd,
* since ECC is calculated for the combined codeword. So update the OOB from
* chip->oob_poi, and pad the data area with OxFF before writing.
*/
-static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int qcom_nandc_write_oob(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct qcom_nand_host *host = to_qcom_nand_host(chip);
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
struct nand_ecc_ctrl *ecc = &chip->ecc;
@@ -2197,9 +2196,9 @@ static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
return nand_prog_page_end_op(chip);
}
-static int qcom_nandc_block_bad(struct mtd_info *mtd, loff_t ofs)
+static int qcom_nandc_block_bad(struct nand_chip *chip, loff_t ofs)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct qcom_nand_host *host = to_qcom_nand_host(chip);
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
struct nand_ecc_ctrl *ecc = &chip->ecc;
@@ -2235,9 +2234,8 @@ err:
return bad;
}
-static int qcom_nandc_block_markbad(struct mtd_info *mtd, loff_t ofs)
+static int qcom_nandc_block_markbad(struct nand_chip *chip, loff_t ofs)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct qcom_nand_host *host = to_qcom_nand_host(chip);
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
struct nand_ecc_ctrl *ecc = &chip->ecc;
@@ -2278,14 +2276,13 @@ static int qcom_nandc_block_markbad(struct mtd_info *mtd, loff_t ofs)
}
/*
- * the three functions below implement chip->read_byte(), chip->read_buf()
- * and chip->write_buf() respectively. these aren't used for
- * reading/writing page data, they are used for smaller data like reading
- * id, status etc
+ * the three functions below implement chip->legacy.read_byte(),
+ * chip->legacy.read_buf() and chip->legacy.write_buf() respectively. these
+ * aren't used for reading/writing page data, they are used for smaller data
+ * like reading id, status etc
*/
-static uint8_t qcom_nandc_read_byte(struct mtd_info *mtd)
+static uint8_t qcom_nandc_read_byte(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct qcom_nand_host *host = to_qcom_nand_host(chip);
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
u8 *buf = nandc->data_buffer;
@@ -2305,9 +2302,8 @@ static uint8_t qcom_nandc_read_byte(struct mtd_info *mtd)
return ret;
}
-static void qcom_nandc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void qcom_nandc_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
@@ -2315,10 +2311,9 @@ static void qcom_nandc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
nandc->buf_start += real_len;
}
-static void qcom_nandc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
+static void qcom_nandc_write_buf(struct nand_chip *chip, const uint8_t *buf,
int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
@@ -2328,9 +2323,8 @@ static void qcom_nandc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
}
/* we support only one external chip for now */
-static void qcom_nandc_select_chip(struct mtd_info *mtd, int chipnr)
+static void qcom_nandc_select_chip(struct nand_chip *chip, int chipnr)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
if (chipnr <= 0)
@@ -2809,13 +2803,13 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc,
mtd->owner = THIS_MODULE;
mtd->dev.parent = dev;
- chip->cmdfunc = qcom_nandc_command;
+ chip->legacy.cmdfunc = qcom_nandc_command;
chip->select_chip = qcom_nandc_select_chip;
- chip->read_byte = qcom_nandc_read_byte;
- chip->read_buf = qcom_nandc_read_buf;
- chip->write_buf = qcom_nandc_write_buf;
- chip->set_features = nand_get_set_features_notsupp;
- chip->get_features = nand_get_set_features_notsupp;
+ chip->legacy.read_byte = qcom_nandc_read_byte;
+ chip->legacy.read_buf = qcom_nandc_read_buf;
+ chip->legacy.write_buf = qcom_nandc_write_buf;
+ chip->legacy.set_features = nand_get_set_features_notsupp;
+ chip->legacy.get_features = nand_get_set_features_notsupp;
/*
* the bad block marker is readable only when we read the last codeword
@@ -2825,8 +2819,8 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc,
* and block_markbad helpers until we permanently switch to using
* MTD_OPS_RAW for all drivers (with the help of badblockbits)
*/
- chip->block_bad = qcom_nandc_block_bad;
- chip->block_markbad = qcom_nandc_block_markbad;
+ chip->legacy.block_bad = qcom_nandc_block_bad;
+ chip->legacy.block_markbad = qcom_nandc_block_markbad;
chip->controller = &nandc->controller;
chip->options |= NAND_NO_SUBPAGE_WRITE | NAND_USE_BOUNCE_BUFFER |
@@ -2835,7 +2829,7 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc,
/* set up initial status value */
host->status = NAND_STATUS_READY | NAND_STATUS_WP;
- ret = nand_scan(mtd, 1);
+ ret = nand_scan(chip, 1);
if (ret)
return ret;
@@ -3000,7 +2994,7 @@ static int qcom_nandc_remove(struct platform_device *pdev)
struct qcom_nand_host *host;
list_for_each_entry(host, &nandc->host_list, node)
- nand_release(nand_to_mtd(&host->chip));
+ nand_release(&host->chip);
qcom_nandc_unalloc(nandc);
diff --git a/drivers/mtd/nand/raw/r852.c b/drivers/mtd/nand/raw/r852.c
index dcdeb0660e5e..39be65b35ac2 100644
--- a/drivers/mtd/nand/raw/r852.c
+++ b/drivers/mtd/nand/raw/r852.c
@@ -232,9 +232,9 @@ static void r852_do_dma(struct r852_device *dev, uint8_t *buf, int do_read)
/*
* Program data lines of the nand chip to send data to it
*/
-static void r852_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+static void r852_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
{
- struct r852_device *dev = r852_get_dev(mtd);
+ struct r852_device *dev = r852_get_dev(nand_to_mtd(chip));
uint32_t reg;
/* Don't allow any access to hardware if we suspect card removal */
@@ -266,9 +266,9 @@ static void r852_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
/*
* Read data lines of the nand chip to retrieve data
*/
-static void r852_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void r852_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
{
- struct r852_device *dev = r852_get_dev(mtd);
+ struct r852_device *dev = r852_get_dev(nand_to_mtd(chip));
uint32_t reg;
if (dev->card_unstable) {
@@ -303,9 +303,9 @@ static void r852_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
/*
* Read one byte from nand chip
*/
-static uint8_t r852_read_byte(struct mtd_info *mtd)
+static uint8_t r852_read_byte(struct nand_chip *chip)
{
- struct r852_device *dev = r852_get_dev(mtd);
+ struct r852_device *dev = r852_get_dev(nand_to_mtd(chip));
/* Same problem as in r852_read_buf.... */
if (dev->card_unstable)
@@ -317,9 +317,9 @@ static uint8_t r852_read_byte(struct mtd_info *mtd)
/*
* Control several chip lines & send commands
*/
-static void r852_cmdctl(struct mtd_info *mtd, int dat, unsigned int ctrl)
+static void r852_cmdctl(struct nand_chip *chip, int dat, unsigned int ctrl)
{
- struct r852_device *dev = r852_get_dev(mtd);
+ struct r852_device *dev = r852_get_dev(nand_to_mtd(chip));
if (dev->card_unstable)
return;
@@ -362,7 +362,7 @@ static void r852_cmdctl(struct mtd_info *mtd, int dat, unsigned int ctrl)
* Wait till card is ready.
* based on nand_wait, but returns errors on DMA error
*/
-static int r852_wait(struct mtd_info *mtd, struct nand_chip *chip)
+static int r852_wait(struct nand_chip *chip)
{
struct r852_device *dev = nand_get_controller_data(chip);
@@ -373,7 +373,7 @@ static int r852_wait(struct mtd_info *mtd, struct nand_chip *chip)
msecs_to_jiffies(400) : msecs_to_jiffies(20));
while (time_before(jiffies, timeout))
- if (chip->dev_ready(mtd))
+ if (chip->legacy.dev_ready(chip))
break;
nand_status_op(chip, &status);
@@ -390,9 +390,9 @@ static int r852_wait(struct mtd_info *mtd, struct nand_chip *chip)
* Check if card is ready
*/
-static int r852_ready(struct mtd_info *mtd)
+static int r852_ready(struct nand_chip *chip)
{
- struct r852_device *dev = r852_get_dev(mtd);
+ struct r852_device *dev = r852_get_dev(nand_to_mtd(chip));
return !(r852_read_reg(dev, R852_CARD_STA) & R852_CARD_STA_BUSY);
}
@@ -401,9 +401,9 @@ static int r852_ready(struct mtd_info *mtd)
* Set ECC engine mode
*/
-static void r852_ecc_hwctl(struct mtd_info *mtd, int mode)
+static void r852_ecc_hwctl(struct nand_chip *chip, int mode)
{
- struct r852_device *dev = r852_get_dev(mtd);
+ struct r852_device *dev = r852_get_dev(nand_to_mtd(chip));
if (dev->card_unstable)
return;
@@ -433,10 +433,10 @@ static void r852_ecc_hwctl(struct mtd_info *mtd, int mode)
* Calculate ECC, only used for writes
*/
-static int r852_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat,
- uint8_t *ecc_code)
+static int r852_ecc_calculate(struct nand_chip *chip, const uint8_t *dat,
+ uint8_t *ecc_code)
{
- struct r852_device *dev = r852_get_dev(mtd);
+ struct r852_device *dev = r852_get_dev(nand_to_mtd(chip));
struct sm_oob *oob = (struct sm_oob *)ecc_code;
uint32_t ecc1, ecc2;
@@ -465,14 +465,14 @@ static int r852_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat,
* Correct the data using ECC, hw did almost everything for us
*/
-static int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat,
- uint8_t *read_ecc, uint8_t *calc_ecc)
+static int r852_ecc_correct(struct nand_chip *chip, uint8_t *dat,
+ uint8_t *read_ecc, uint8_t *calc_ecc)
{
uint32_t ecc_reg;
uint8_t ecc_status, err_byte;
int i, error = 0;
- struct r852_device *dev = r852_get_dev(mtd);
+ struct r852_device *dev = r852_get_dev(nand_to_mtd(chip));
if (dev->card_unstable)
return 0;
@@ -521,9 +521,10 @@ exit:
* This is copy of nand_read_oob_std
* nand_read_oob_syndrome assumes we can send column address - we can't
*/
-static int r852_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int r852_read_oob(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
return nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
}
@@ -636,7 +637,7 @@ static int r852_register_nand_device(struct r852_device *dev)
{
struct mtd_info *mtd = nand_to_mtd(dev->chip);
- WARN_ON(dev->card_registred);
+ WARN_ON(dev->card_registered);
mtd->dev.parent = &dev->pci_dev->dev;
@@ -653,10 +654,10 @@ static int r852_register_nand_device(struct r852_device *dev)
goto error3;
}
- dev->card_registred = 1;
+ dev->card_registered = 1;
return 0;
error3:
- nand_release(mtd);
+ nand_release(dev->chip);
error1:
/* Force card redetect */
dev->card_detected = 0;
@@ -671,13 +672,13 @@ static void r852_unregister_nand_device(struct r852_device *dev)
{
struct mtd_info *mtd = nand_to_mtd(dev->chip);
- if (!dev->card_registred)
+ if (!dev->card_registered)
return;
device_remove_file(&mtd->dev, &dev_attr_media_type);
- nand_release(mtd);
+ nand_release(dev->chip);
r852_engine_disable(dev);
- dev->card_registred = 0;
+ dev->card_registered = 0;
}
/* Card state updater */
@@ -691,7 +692,7 @@ static void r852_card_detect_work(struct work_struct *work)
dev->card_unstable = 0;
/* False alarm */
- if (dev->card_detected == dev->card_registred)
+ if (dev->card_detected == dev->card_registered)
goto exit;
/* Read media properties */
@@ -852,14 +853,14 @@ static int r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
goto error4;
/* commands */
- chip->cmd_ctrl = r852_cmdctl;
- chip->waitfunc = r852_wait;
- chip->dev_ready = r852_ready;
+ chip->legacy.cmd_ctrl = r852_cmdctl;
+ chip->legacy.waitfunc = r852_wait;
+ chip->legacy.dev_ready = r852_ready;
/* I/O */
- chip->read_byte = r852_read_byte;
- chip->read_buf = r852_read_buf;
- chip->write_buf = r852_write_buf;
+ chip->legacy.read_byte = r852_read_byte;
+ chip->legacy.read_buf = r852_read_buf;
+ chip->legacy.write_buf = r852_write_buf;
/* ecc */
chip->ecc.mode = NAND_ECC_HW_SYNDROME;
@@ -1025,7 +1026,6 @@ static int r852_suspend(struct device *device)
static int r852_resume(struct device *device)
{
struct r852_device *dev = pci_get_drvdata(to_pci_dev(device));
- struct mtd_info *mtd = nand_to_mtd(dev->chip);
r852_disable_irqs(dev);
r852_card_update_present(dev);
@@ -1033,7 +1033,7 @@ static int r852_resume(struct device *device)
/* If card status changed, just do the work */
- if (dev->card_detected != dev->card_registred) {
+ if (dev->card_detected != dev->card_registered) {
dbg("card was %s during low power state",
dev->card_detected ? "added" : "removed");
@@ -1043,11 +1043,11 @@ static int r852_resume(struct device *device)
}
/* Otherwise, initialize the card */
- if (dev->card_registred) {
+ if (dev->card_registered) {
r852_engine_enable(dev);
- dev->chip->select_chip(mtd, 0);
+ dev->chip->select_chip(dev->chip, 0);
nand_reset_op(dev->chip);
- dev->chip->select_chip(mtd, -1);
+ dev->chip->select_chip(dev->chip, -1);
}
/* Program card detection IRQ */
diff --git a/drivers/mtd/nand/raw/r852.h b/drivers/mtd/nand/raw/r852.h
index 1eed2fc2fa42..bc67f5bf67e8 100644
--- a/drivers/mtd/nand/raw/r852.h
+++ b/drivers/mtd/nand/raw/r852.h
@@ -129,7 +129,7 @@ struct r852_device {
/* card status area */
struct delayed_work card_detect_work;
struct workqueue_struct *card_workqueue;
- int card_registred; /* card registered with mtd */
+ int card_registered; /* card registered with mtd */
int card_detected; /* card detected in slot */
int card_unstable; /* whenever the card is inserted,
is not known yet */
diff --git a/drivers/mtd/nand/raw/s3c2410.c b/drivers/mtd/nand/raw/s3c2410.c
index c21e8892394a..d2e42e9d0e8c 100644
--- a/drivers/mtd/nand/raw/s3c2410.c
+++ b/drivers/mtd/nand/raw/s3c2410.c
@@ -404,7 +404,7 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info)
/**
* s3c2410_nand_select_chip - select the given nand chip
- * @mtd: The MTD instance for this chip.
+ * @this: NAND chip object.
* @chip: The chip number.
*
* This is called by the MTD layer to either select a given chip for the
@@ -415,11 +415,10 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info)
* platform specific selection code is called to route nFCE to the specific
* chip.
*/
-static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
+static void s3c2410_nand_select_chip(struct nand_chip *this, int chip)
{
struct s3c2410_nand_info *info;
struct s3c2410_nand_mtd *nmtd;
- struct nand_chip *this = mtd_to_nand(mtd);
unsigned long cur;
nmtd = nand_get_controller_data(this);
@@ -457,9 +456,10 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
* Issue command and address cycles to the chip
*/
-static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd,
+static void s3c2410_nand_hwcontrol(struct nand_chip *chip, int cmd,
unsigned int ctrl)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
if (cmd == NAND_CMD_NONE)
@@ -473,9 +473,10 @@ static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd,
/* command and control functions */
-static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd,
+static void s3c2440_nand_hwcontrol(struct nand_chip *chip, int cmd,
unsigned int ctrl)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
if (cmd == NAND_CMD_NONE)
@@ -492,29 +493,33 @@ static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd,
* returns 0 if the nand is busy, 1 if it is ready
*/
-static int s3c2410_nand_devready(struct mtd_info *mtd)
+static int s3c2410_nand_devready(struct nand_chip *chip)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY;
}
-static int s3c2440_nand_devready(struct mtd_info *mtd)
+static int s3c2440_nand_devready(struct nand_chip *chip)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY;
}
-static int s3c2412_nand_devready(struct mtd_info *mtd)
+static int s3c2412_nand_devready(struct nand_chip *chip)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
return readb(info->regs + S3C2412_NFSTAT) & S3C2412_NFSTAT_READY;
}
/* ECC handling functions */
-static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
+static int s3c2410_nand_correct_data(struct nand_chip *chip, u_char *dat,
u_char *read_ecc, u_char *calc_ecc)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
unsigned int diff0, diff1, diff2;
unsigned int bit, byte;
@@ -591,38 +596,42 @@ static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
* generator block to ECC the data as it passes through]
*/
-static void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+static void s3c2410_nand_enable_hwecc(struct nand_chip *chip, int mode)
{
- struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+ struct s3c2410_nand_info *info;
unsigned long ctrl;
+ info = s3c2410_nand_mtd_toinfo(nand_to_mtd(chip));
ctrl = readl(info->regs + S3C2410_NFCONF);
ctrl |= S3C2410_NFCONF_INITECC;
writel(ctrl, info->regs + S3C2410_NFCONF);
}
-static void s3c2412_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+static void s3c2412_nand_enable_hwecc(struct nand_chip *chip, int mode)
{
- struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+ struct s3c2410_nand_info *info;
unsigned long ctrl;
+ info = s3c2410_nand_mtd_toinfo(nand_to_mtd(chip));
ctrl = readl(info->regs + S3C2440_NFCONT);
writel(ctrl | S3C2412_NFCONT_INIT_MAIN_ECC,
info->regs + S3C2440_NFCONT);
}
-static void s3c2440_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+static void s3c2440_nand_enable_hwecc(struct nand_chip *chip, int mode)
{
- struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+ struct s3c2410_nand_info *info;
unsigned long ctrl;
+ info = s3c2410_nand_mtd_toinfo(nand_to_mtd(chip));
ctrl = readl(info->regs + S3C2440_NFCONT);
writel(ctrl | S3C2440_NFCONT_INITECC, info->regs + S3C2440_NFCONT);
}
-static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
- u_char *ecc_code)
+static int s3c2410_nand_calculate_ecc(struct nand_chip *chip,
+ const u_char *dat, u_char *ecc_code)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
ecc_code[0] = readb(info->regs + S3C2410_NFECC + 0);
@@ -634,9 +643,10 @@ static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
return 0;
}
-static int s3c2412_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
- u_char *ecc_code)
+static int s3c2412_nand_calculate_ecc(struct nand_chip *chip,
+ const u_char *dat, u_char *ecc_code)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
unsigned long ecc = readl(info->regs + S3C2412_NFMECC0);
@@ -649,9 +659,10 @@ static int s3c2412_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
return 0;
}
-static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
- u_char *ecc_code)
+static int s3c2440_nand_calculate_ecc(struct nand_chip *chip,
+ const u_char *dat, u_char *ecc_code)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
unsigned long ecc = readl(info->regs + S3C2440_NFMECC0);
@@ -668,14 +679,14 @@ static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
* use read/write block to move the data buffers to/from the controller
*/
-static void s3c2410_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void s3c2410_nand_read_buf(struct nand_chip *this, u_char *buf, int len)
{
- struct nand_chip *this = mtd_to_nand(mtd);
- readsb(this->IO_ADDR_R, buf, len);
+ readsb(this->legacy.IO_ADDR_R, buf, len);
}
-static void s3c2440_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void s3c2440_nand_read_buf(struct nand_chip *this, u_char *buf, int len)
{
+ struct mtd_info *mtd = nand_to_mtd(this);
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
readsl(info->regs + S3C2440_NFDATA, buf, len >> 2);
@@ -689,16 +700,16 @@ static void s3c2440_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
}
}
-static void s3c2410_nand_write_buf(struct mtd_info *mtd, const u_char *buf,
+static void s3c2410_nand_write_buf(struct nand_chip *this, const u_char *buf,
int len)
{
- struct nand_chip *this = mtd_to_nand(mtd);
- writesb(this->IO_ADDR_W, buf, len);
+ writesb(this->legacy.IO_ADDR_W, buf, len);
}
-static void s3c2440_nand_write_buf(struct mtd_info *mtd, const u_char *buf,
+static void s3c2440_nand_write_buf(struct nand_chip *this, const u_char *buf,
int len)
{
+ struct mtd_info *mtd = nand_to_mtd(this);
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
writesl(info->regs + S3C2440_NFDATA, buf, len >> 2);
@@ -781,7 +792,7 @@ static int s3c24xx_nand_remove(struct platform_device *pdev)
for (mtdno = 0; mtdno < info->mtd_count; mtdno++, ptr++) {
pr_debug("releasing mtd %d (%p)\n", mtdno, ptr);
- nand_release(nand_to_mtd(&ptr->chip));
+ nand_release(&ptr->chip);
}
}
@@ -809,9 +820,10 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
return -ENODEV;
}
-static int s3c2410_nand_setup_data_interface(struct mtd_info *mtd, int csline,
+static int s3c2410_nand_setup_data_interface(struct nand_chip *chip, int csline,
const struct nand_data_interface *conf)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
struct s3c2410_platform_nand *pdata = info->platform;
const struct nand_sdr_timings *timings;
@@ -852,10 +864,10 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
nand_set_flash_node(chip, set->of_node);
- chip->write_buf = s3c2410_nand_write_buf;
- chip->read_buf = s3c2410_nand_read_buf;
+ chip->legacy.write_buf = s3c2410_nand_write_buf;
+ chip->legacy.read_buf = s3c2410_nand_read_buf;
chip->select_chip = s3c2410_nand_select_chip;
- chip->chip_delay = 50;
+ chip->legacy.chip_delay = 50;
nand_set_controller_data(chip, nmtd);
chip->options = set->options;
chip->controller = &info->controller;
@@ -869,29 +881,29 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
switch (info->cpu_type) {
case TYPE_S3C2410:
- chip->IO_ADDR_W = regs + S3C2410_NFDATA;
+ chip->legacy.IO_ADDR_W = regs + S3C2410_NFDATA;
info->sel_reg = regs + S3C2410_NFCONF;
info->sel_bit = S3C2410_NFCONF_nFCE;
- chip->cmd_ctrl = s3c2410_nand_hwcontrol;
- chip->dev_ready = s3c2410_nand_devready;
+ chip->legacy.cmd_ctrl = s3c2410_nand_hwcontrol;
+ chip->legacy.dev_ready = s3c2410_nand_devready;
break;
case TYPE_S3C2440:
- chip->IO_ADDR_W = regs + S3C2440_NFDATA;
+ chip->legacy.IO_ADDR_W = regs + S3C2440_NFDATA;
info->sel_reg = regs + S3C2440_NFCONT;
info->sel_bit = S3C2440_NFCONT_nFCE;
- chip->cmd_ctrl = s3c2440_nand_hwcontrol;
- chip->dev_ready = s3c2440_nand_devready;
- chip->read_buf = s3c2440_nand_read_buf;
- chip->write_buf = s3c2440_nand_write_buf;
+ chip->legacy.cmd_ctrl = s3c2440_nand_hwcontrol;
+ chip->legacy.dev_ready = s3c2440_nand_devready;
+ chip->legacy.read_buf = s3c2440_nand_read_buf;
+ chip->legacy.write_buf = s3c2440_nand_write_buf;
break;
case TYPE_S3C2412:
- chip->IO_ADDR_W = regs + S3C2440_NFDATA;
+ chip->legacy.IO_ADDR_W = regs + S3C2440_NFDATA;
info->sel_reg = regs + S3C2440_NFCONT;
info->sel_bit = S3C2412_NFCONT_nFCE0;
- chip->cmd_ctrl = s3c2440_nand_hwcontrol;
- chip->dev_ready = s3c2412_nand_devready;
+ chip->legacy.cmd_ctrl = s3c2440_nand_hwcontrol;
+ chip->legacy.dev_ready = s3c2412_nand_devready;
if (readl(regs + S3C2410_NFCONF) & S3C2412_NFCONF_NANDBOOT)
dev_info(info->device, "System booted from NAND\n");
@@ -899,7 +911,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
break;
}
- chip->IO_ADDR_R = chip->IO_ADDR_W;
+ chip->legacy.IO_ADDR_R = chip->legacy.IO_ADDR_W;
nmtd->info = info;
nmtd->set = set;
@@ -1170,7 +1182,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
mtd->dev.parent = &pdev->dev;
s3c2410_nand_init_chip(info, nmtd, sets);
- err = nand_scan(mtd, sets ? sets->nr_chips : 1);
+ err = nand_scan(&nmtd->chip, sets ? sets->nr_chips : 1);
if (err)
goto exit_error;
diff --git a/drivers/mtd/nand/raw/sh_flctl.c b/drivers/mtd/nand/raw/sh_flctl.c
index bb8866e05ff7..4d20d033de7b 100644
--- a/drivers/mtd/nand/raw/sh_flctl.c
+++ b/drivers/mtd/nand/raw/sh_flctl.c
@@ -480,7 +480,7 @@ static void read_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
/* initiate DMA transfer */
if (flctl->chan_fifo0_rx && rlen >= 32 &&
- flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_DEV_TO_MEM) > 0)
+ flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_FROM_DEVICE) > 0)
goto convert; /* DMA success */
/* do polling transfer */
@@ -539,7 +539,7 @@ static void write_ec_fiforeg(struct sh_flctl *flctl, int rlen,
/* initiate DMA transfer */
if (flctl->chan_fifo0_tx && rlen >= 32 &&
- flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_MEM_TO_DEV) > 0)
+ flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_TO_DEVICE) > 0)
return; /* DMA success */
/* do polling transfer */
@@ -611,21 +611,24 @@ static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_va
writel(flcmcdr_val, FLCMCDR(flctl));
}
-static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+static int flctl_read_page_hwecc(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
nand_read_page_op(chip, page, 0, buf, mtd->writesize);
if (oob_required)
- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize);
return 0;
}
-static int flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required,
- int page)
+static int flctl_write_page_hwecc(struct nand_chip *chip, const uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
- chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize);
return nand_prog_page_end_op(chip);
}
@@ -747,9 +750,10 @@ static void execmd_write_oob(struct mtd_info *mtd)
}
}
-static void flctl_cmdfunc(struct mtd_info *mtd, unsigned int command,
+static void flctl_cmdfunc(struct nand_chip *chip, unsigned int command,
int column, int page_addr)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct sh_flctl *flctl = mtd_to_flctl(mtd);
uint32_t read_cmd = 0;
@@ -923,9 +927,9 @@ runtime_exit:
return;
}
-static void flctl_select_chip(struct mtd_info *mtd, int chipnr)
+static void flctl_select_chip(struct nand_chip *chip, int chipnr)
{
- struct sh_flctl *flctl = mtd_to_flctl(mtd);
+ struct sh_flctl *flctl = mtd_to_flctl(nand_to_mtd(chip));
int ret;
switch (chipnr) {
@@ -967,17 +971,17 @@ static void flctl_select_chip(struct mtd_info *mtd, int chipnr)
}
}
-static void flctl_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+static void flctl_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
{
- struct sh_flctl *flctl = mtd_to_flctl(mtd);
+ struct sh_flctl *flctl = mtd_to_flctl(nand_to_mtd(chip));
memcpy(&flctl->done_buff[flctl->index], buf, len);
flctl->index += len;
}
-static uint8_t flctl_read_byte(struct mtd_info *mtd)
+static uint8_t flctl_read_byte(struct nand_chip *chip)
{
- struct sh_flctl *flctl = mtd_to_flctl(mtd);
+ struct sh_flctl *flctl = mtd_to_flctl(nand_to_mtd(chip));
uint8_t data;
data = flctl->done_buff[flctl->index];
@@ -985,18 +989,9 @@ static uint8_t flctl_read_byte(struct mtd_info *mtd)
return data;
}
-static uint16_t flctl_read_word(struct mtd_info *mtd)
+static void flctl_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
{
- struct sh_flctl *flctl = mtd_to_flctl(mtd);
- uint16_t *buf = (uint16_t *)&flctl->done_buff[flctl->index];
-
- flctl->index += 2;
- return *buf;
-}
-
-static void flctl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
-{
- struct sh_flctl *flctl = mtd_to_flctl(mtd);
+ struct sh_flctl *flctl = mtd_to_flctl(nand_to_mtd(chip));
memcpy(buf, &flctl->done_buff[flctl->index], len);
flctl->index += len;
@@ -1183,16 +1178,15 @@ static int flctl_probe(struct platform_device *pdev)
/* Set address of hardware control function */
/* 20 us command delay time */
- nand->chip_delay = 20;
+ nand->legacy.chip_delay = 20;
- nand->read_byte = flctl_read_byte;
- nand->read_word = flctl_read_word;
- nand->write_buf = flctl_write_buf;
- nand->read_buf = flctl_read_buf;
+ nand->legacy.read_byte = flctl_read_byte;
+ nand->legacy.write_buf = flctl_write_buf;
+ nand->legacy.read_buf = flctl_read_buf;
nand->select_chip = flctl_select_chip;
- nand->cmdfunc = flctl_cmdfunc;
- nand->set_features = nand_get_set_features_notsupp;
- nand->get_features = nand_get_set_features_notsupp;
+ nand->legacy.cmdfunc = flctl_cmdfunc;
+ nand->legacy.set_features = nand_get_set_features_notsupp;
+ nand->legacy.get_features = nand_get_set_features_notsupp;
if (pdata->flcmncr_val & SEL_16BIT)
nand->options |= NAND_BUSWIDTH_16;
@@ -1203,7 +1197,7 @@ static int flctl_probe(struct platform_device *pdev)
flctl_setup_dma(flctl);
nand->dummy_controller.ops = &flctl_nand_controller_ops;
- ret = nand_scan(flctl_mtd, 1);
+ ret = nand_scan(nand, 1);
if (ret)
goto err_chip;
@@ -1226,7 +1220,7 @@ static int flctl_remove(struct platform_device *pdev)
struct sh_flctl *flctl = platform_get_drvdata(pdev);
flctl_release_dma(flctl);
- nand_release(nand_to_mtd(&flctl->chip));
+ nand_release(&flctl->chip);
pm_runtime_disable(&pdev->dev);
return 0;
diff --git a/drivers/mtd/nand/raw/sharpsl.c b/drivers/mtd/nand/raw/sharpsl.c
index fc171b17a39b..c82f26c8b58c 100644
--- a/drivers/mtd/nand/raw/sharpsl.c
+++ b/drivers/mtd/nand/raw/sharpsl.c
@@ -59,11 +59,10 @@ static inline struct sharpsl_nand *mtd_to_sharpsl(struct mtd_info *mtd)
* NAND_ALE: bit 2 -> bit 2
*
*/
-static void sharpsl_nand_hwcontrol(struct mtd_info *mtd, int cmd,
+static void sharpsl_nand_hwcontrol(struct nand_chip *chip, int cmd,
unsigned int ctrl)
{
- struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct sharpsl_nand *sharpsl = mtd_to_sharpsl(nand_to_mtd(chip));
if (ctrl & NAND_CTRL_CHANGE) {
unsigned char bits = ctrl & 0x07;
@@ -76,24 +75,25 @@ static void sharpsl_nand_hwcontrol(struct mtd_info *mtd, int cmd,
}
if (cmd != NAND_CMD_NONE)
- writeb(cmd, chip->IO_ADDR_W);
+ writeb(cmd, chip->legacy.IO_ADDR_W);
}
-static int sharpsl_nand_dev_ready(struct mtd_info *mtd)
+static int sharpsl_nand_dev_ready(struct nand_chip *chip)
{
- struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
+ struct sharpsl_nand *sharpsl = mtd_to_sharpsl(nand_to_mtd(chip));
return !((readb(sharpsl->io + FLASHCTL) & FLRYBY) == 0);
}
-static void sharpsl_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+static void sharpsl_nand_enable_hwecc(struct nand_chip *chip, int mode)
{
- struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
+ struct sharpsl_nand *sharpsl = mtd_to_sharpsl(nand_to_mtd(chip));
writeb(0, sharpsl->io + ECCCLRR);
}
-static int sharpsl_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat, u_char * ecc_code)
+static int sharpsl_nand_calculate_ecc(struct nand_chip *chip,
+ const u_char * dat, u_char * ecc_code)
{
- struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
+ struct sharpsl_nand *sharpsl = mtd_to_sharpsl(nand_to_mtd(chip));
ecc_code[0] = ~readb(sharpsl->io + ECCLPUB);
ecc_code[1] = ~readb(sharpsl->io + ECCLPLB);
ecc_code[2] = (~readb(sharpsl->io + ECCCP) << 2) | 0x03;
@@ -153,13 +153,13 @@ static int sharpsl_nand_probe(struct platform_device *pdev)
writeb(readb(sharpsl->io + FLASHCTL) | FLWP, sharpsl->io + FLASHCTL);
/* Set address of NAND IO lines */
- this->IO_ADDR_R = sharpsl->io + FLASHIO;
- this->IO_ADDR_W = sharpsl->io + FLASHIO;
+ this->legacy.IO_ADDR_R = sharpsl->io + FLASHIO;
+ this->legacy.IO_ADDR_W = sharpsl->io + FLASHIO;
/* Set address of hardware control function */
- this->cmd_ctrl = sharpsl_nand_hwcontrol;
- this->dev_ready = sharpsl_nand_dev_ready;
+ this->legacy.cmd_ctrl = sharpsl_nand_hwcontrol;
+ this->legacy.dev_ready = sharpsl_nand_dev_ready;
/* 15 us command delay time */
- this->chip_delay = 15;
+ this->legacy.chip_delay = 15;
/* set eccmode using hardware ECC */
this->ecc.mode = NAND_ECC_HW;
this->ecc.size = 256;
@@ -171,7 +171,7 @@ static int sharpsl_nand_probe(struct platform_device *pdev)
this->ecc.correct = nand_correct_data;
/* Scan to find existence of the device */
- err = nand_scan(mtd, 1);
+ err = nand_scan(this, 1);
if (err)
goto err_scan;
@@ -187,7 +187,7 @@ static int sharpsl_nand_probe(struct platform_device *pdev)
return 0;
err_add:
- nand_release(mtd);
+ nand_release(this);
err_scan:
iounmap(sharpsl->io);
@@ -205,7 +205,7 @@ static int sharpsl_nand_remove(struct platform_device *pdev)
struct sharpsl_nand *sharpsl = platform_get_drvdata(pdev);
/* Release resources, unregister device */
- nand_release(nand_to_mtd(&sharpsl->chip));
+ nand_release(&sharpsl->chip);
iounmap(sharpsl->io);
diff --git a/drivers/mtd/nand/raw/sm_common.c b/drivers/mtd/nand/raw/sm_common.c
index 73aafe8c3ef3..6f063ef57640 100644
--- a/drivers/mtd/nand/raw/sm_common.c
+++ b/drivers/mtd/nand/raw/sm_common.c
@@ -99,8 +99,9 @@ static const struct mtd_ooblayout_ops oob_sm_small_ops = {
.free = oob_sm_small_ooblayout_free,
};
-static int sm_block_markbad(struct mtd_info *mtd, loff_t ofs)
+static int sm_block_markbad(struct nand_chip *chip, loff_t ofs)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct mtd_oob_ops ops;
struct sm_oob oob;
int ret;
@@ -167,7 +168,7 @@ static int sm_attach_chip(struct nand_chip *chip)
/* Bad block marker position */
chip->badblockpos = 0x05;
chip->badblockbits = 7;
- chip->block_markbad = sm_block_markbad;
+ chip->legacy.block_markbad = sm_block_markbad;
/* ECC layout */
if (mtd->writesize == SM_SECTOR_SIZE)
@@ -195,7 +196,7 @@ int sm_register_device(struct mtd_info *mtd, int smartmedia)
/* Scan for card properties */
chip->dummy_controller.ops = &sm_controller_ops;
flash_ids = smartmedia ? nand_smartmedia_flash_ids : nand_xd_flash_ids;
- ret = nand_scan_with_ids(mtd, 1, flash_ids);
+ ret = nand_scan_with_ids(chip, 1, flash_ids);
if (ret)
return ret;
diff --git a/drivers/mtd/nand/raw/socrates_nand.c b/drivers/mtd/nand/raw/socrates_nand.c
index 9824a9923583..8be9a50c7880 100644
--- a/drivers/mtd/nand/raw/socrates_nand.c
+++ b/drivers/mtd/nand/raw/socrates_nand.c
@@ -34,15 +34,14 @@ struct socrates_nand_host {
/**
* socrates_nand_write_buf - write buffer to chip
- * @mtd: MTD device structure
+ * @this: NAND chip object
* @buf: data buffer
* @len: number of bytes to write
*/
-static void socrates_nand_write_buf(struct mtd_info *mtd,
- const uint8_t *buf, int len)
+static void socrates_nand_write_buf(struct nand_chip *this, const uint8_t *buf,
+ int len)
{
int i;
- struct nand_chip *this = mtd_to_nand(mtd);
struct socrates_nand_host *host = nand_get_controller_data(this);
for (i = 0; i < len; i++) {
@@ -54,14 +53,14 @@ static void socrates_nand_write_buf(struct mtd_info *mtd,
/**
* socrates_nand_read_buf - read chip data into buffer
- * @mtd: MTD device structure
+ * @this: NAND chip object
* @buf: buffer to store date
* @len: number of bytes to read
*/
-static void socrates_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void socrates_nand_read_buf(struct nand_chip *this, uint8_t *buf,
+ int len)
{
int i;
- struct nand_chip *this = mtd_to_nand(mtd);
struct socrates_nand_host *host = nand_get_controller_data(this);
uint32_t val;
@@ -78,31 +77,19 @@ static void socrates_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
* socrates_nand_read_byte - read one byte from the chip
* @mtd: MTD device structure
*/
-static uint8_t socrates_nand_read_byte(struct mtd_info *mtd)
+static uint8_t socrates_nand_read_byte(struct nand_chip *this)
{
uint8_t byte;
- socrates_nand_read_buf(mtd, &byte, sizeof(byte));
+ socrates_nand_read_buf(this, &byte, sizeof(byte));
return byte;
}
-/**
- * socrates_nand_read_word - read one word from the chip
- * @mtd: MTD device structure
- */
-static uint16_t socrates_nand_read_word(struct mtd_info *mtd)
-{
- uint16_t word;
- socrates_nand_read_buf(mtd, (uint8_t *)&word, sizeof(word));
- return word;
-}
-
/*
* Hardware specific access to control-lines
*/
-static void socrates_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
- unsigned int ctrl)
+static void socrates_nand_cmd_ctrl(struct nand_chip *nand_chip, int cmd,
+ unsigned int ctrl)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct socrates_nand_host *host = nand_get_controller_data(nand_chip);
uint32_t val;
@@ -125,9 +112,8 @@ static void socrates_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
/*
* Read the Device Ready pin.
*/
-static int socrates_nand_device_ready(struct mtd_info *mtd)
+static int socrates_nand_device_ready(struct nand_chip *nand_chip)
{
- struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct socrates_nand_host *host = nand_get_controller_data(nand_chip);
if (in_be32(host->io_base) & FPGA_NAND_BUSY)
@@ -166,26 +152,21 @@ static int socrates_nand_probe(struct platform_device *ofdev)
mtd->name = "socrates_nand";
mtd->dev.parent = &ofdev->dev;
- /*should never be accessed directly */
- nand_chip->IO_ADDR_R = (void *)0xdeadbeef;
- nand_chip->IO_ADDR_W = (void *)0xdeadbeef;
-
- nand_chip->cmd_ctrl = socrates_nand_cmd_ctrl;
- nand_chip->read_byte = socrates_nand_read_byte;
- nand_chip->read_word = socrates_nand_read_word;
- nand_chip->write_buf = socrates_nand_write_buf;
- nand_chip->read_buf = socrates_nand_read_buf;
- nand_chip->dev_ready = socrates_nand_device_ready;
+ nand_chip->legacy.cmd_ctrl = socrates_nand_cmd_ctrl;
+ nand_chip->legacy.read_byte = socrates_nand_read_byte;
+ nand_chip->legacy.write_buf = socrates_nand_write_buf;
+ nand_chip->legacy.read_buf = socrates_nand_read_buf;
+ nand_chip->legacy.dev_ready = socrates_nand_device_ready;
nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */
nand_chip->ecc.algo = NAND_ECC_HAMMING;
/* TODO: I have no idea what real delay is. */
- nand_chip->chip_delay = 20; /* 20us command delay time */
+ nand_chip->legacy.chip_delay = 20; /* 20us command delay time */
dev_set_drvdata(&ofdev->dev, host);
- res = nand_scan(mtd, 1);
+ res = nand_scan(nand_chip, 1);
if (res)
goto out;
@@ -193,7 +174,7 @@ static int socrates_nand_probe(struct platform_device *ofdev)
if (!res)
return res;
- nand_release(mtd);
+ nand_release(nand_chip);
out:
iounmap(host->io_base);
@@ -206,9 +187,8 @@ out:
static int socrates_nand_remove(struct platform_device *ofdev)
{
struct socrates_nand_host *host = dev_get_drvdata(&ofdev->dev);
- struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
- nand_release(mtd);
+ nand_release(&host->nand_chip);
iounmap(host->io_base);
diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c
index 1f0b7ee38df5..51b1a548064b 100644
--- a/drivers/mtd/nand/raw/sunxi_nand.c
+++ b/drivers/mtd/nand/raw/sunxi_nand.c
@@ -400,9 +400,8 @@ static void sunxi_nfc_dma_op_cleanup(struct mtd_info *mtd,
nfc->regs + NFC_REG_CTL);
}
-static int sunxi_nfc_dev_ready(struct mtd_info *mtd)
+static int sunxi_nfc_dev_ready(struct nand_chip *nand)
{
- struct nand_chip *nand = mtd_to_nand(mtd);
struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
u32 mask;
@@ -420,9 +419,9 @@ static int sunxi_nfc_dev_ready(struct mtd_info *mtd)
return !!(readl(nfc->regs + NFC_REG_ST) & mask);
}
-static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip)
+static void sunxi_nfc_select_chip(struct nand_chip *nand, int chip)
{
- struct nand_chip *nand = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(nand);
struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
struct sunxi_nand_chip_sel *sel;
@@ -443,9 +442,9 @@ static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip)
ctl |= NFC_CE_SEL(sel->cs) | NFC_EN |
NFC_PAGE_SHIFT(nand->page_shift);
if (sel->rb < 0) {
- nand->dev_ready = NULL;
+ nand->legacy.dev_ready = NULL;
} else {
- nand->dev_ready = sunxi_nfc_dev_ready;
+ nand->legacy.dev_ready = sunxi_nfc_dev_ready;
ctl |= NFC_RB_SEL(sel->rb);
}
@@ -464,9 +463,8 @@ static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip)
sunxi_nand->selected = chip;
}
-static void sunxi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void sunxi_nfc_read_buf(struct nand_chip *nand, uint8_t *buf, int len)
{
- struct nand_chip *nand = mtd_to_nand(mtd);
struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
int ret;
@@ -502,10 +500,9 @@ static void sunxi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
}
}
-static void sunxi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
+static void sunxi_nfc_write_buf(struct nand_chip *nand, const uint8_t *buf,
int len)
{
- struct nand_chip *nand = mtd_to_nand(mtd);
struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
int ret;
@@ -540,19 +537,18 @@ static void sunxi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
}
}
-static uint8_t sunxi_nfc_read_byte(struct mtd_info *mtd)
+static uint8_t sunxi_nfc_read_byte(struct nand_chip *nand)
{
uint8_t ret = 0;
- sunxi_nfc_read_buf(mtd, &ret, 1);
+ sunxi_nfc_read_buf(nand, &ret, 1);
return ret;
}
-static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat,
+static void sunxi_nfc_cmd_ctrl(struct nand_chip *nand, int dat,
unsigned int ctrl)
{
- struct nand_chip *nand = mtd_to_nand(mtd);
struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
int ret;
@@ -761,7 +757,7 @@ static void sunxi_nfc_randomizer_write_buf(struct mtd_info *mtd,
{
sunxi_nfc_randomizer_config(mtd, page, ecc);
sunxi_nfc_randomizer_enable(mtd);
- sunxi_nfc_write_buf(mtd, buf, len);
+ sunxi_nfc_write_buf(mtd_to_nand(mtd), buf, len);
sunxi_nfc_randomizer_disable(mtd);
}
@@ -770,7 +766,7 @@ static void sunxi_nfc_randomizer_read_buf(struct mtd_info *mtd, uint8_t *buf,
{
sunxi_nfc_randomizer_config(mtd, page, ecc);
sunxi_nfc_randomizer_enable(mtd);
- sunxi_nfc_read_buf(mtd, buf, len);
+ sunxi_nfc_read_buf(mtd_to_nand(mtd), buf, len);
sunxi_nfc_randomizer_disable(mtd);
}
@@ -995,7 +991,7 @@ static void sunxi_nfc_hw_ecc_read_extra_oob(struct mtd_info *mtd,
false);
if (!randomize)
- sunxi_nfc_read_buf(mtd, oob + offset, len);
+ sunxi_nfc_read_buf(nand, oob + offset, len);
else
sunxi_nfc_randomizer_read_buf(mtd, oob + offset, len,
false, page);
@@ -1189,10 +1185,10 @@ static void sunxi_nfc_hw_ecc_write_extra_oob(struct mtd_info *mtd,
*cur_off = mtd->oobsize + mtd->writesize;
}
-static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd,
- struct nand_chip *chip, uint8_t *buf,
+static int sunxi_nfc_hw_ecc_read_page(struct nand_chip *chip, uint8_t *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_ecc_ctrl *ecc = &chip->ecc;
unsigned int max_bitflips = 0;
int ret, i, cur_off = 0;
@@ -1227,10 +1223,10 @@ static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd,
return max_bitflips;
}
-static int sunxi_nfc_hw_ecc_read_page_dma(struct mtd_info *mtd,
- struct nand_chip *chip, u8 *buf,
+static int sunxi_nfc_hw_ecc_read_page_dma(struct nand_chip *chip, u8 *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int ret;
nand_read_page_op(chip, page, 0, NULL, 0);
@@ -1241,14 +1237,14 @@ static int sunxi_nfc_hw_ecc_read_page_dma(struct mtd_info *mtd,
return ret;
/* Fallback to PIO mode */
- return sunxi_nfc_hw_ecc_read_page(mtd, chip, buf, oob_required, page);
+ return sunxi_nfc_hw_ecc_read_page(chip, buf, oob_required, page);
}
-static int sunxi_nfc_hw_ecc_read_subpage(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int sunxi_nfc_hw_ecc_read_subpage(struct nand_chip *chip,
u32 data_offs, u32 readlen,
u8 *bufpoi, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_ecc_ctrl *ecc = &chip->ecc;
int ret, i, cur_off = 0;
unsigned int max_bitflips = 0;
@@ -1278,11 +1274,11 @@ static int sunxi_nfc_hw_ecc_read_subpage(struct mtd_info *mtd,
return max_bitflips;
}
-static int sunxi_nfc_hw_ecc_read_subpage_dma(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int sunxi_nfc_hw_ecc_read_subpage_dma(struct nand_chip *chip,
u32 data_offs, u32 readlen,
u8 *buf, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int nchunks = DIV_ROUND_UP(data_offs + readlen, chip->ecc.size);
int ret;
@@ -1293,15 +1289,15 @@ static int sunxi_nfc_hw_ecc_read_subpage_dma(struct mtd_info *mtd,
return ret;
/* Fallback to PIO mode */
- return sunxi_nfc_hw_ecc_read_subpage(mtd, chip, data_offs, readlen,
+ return sunxi_nfc_hw_ecc_read_subpage(chip, data_offs, readlen,
buf, page);
}
-static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int sunxi_nfc_hw_ecc_write_page(struct nand_chip *chip,
const uint8_t *buf, int oob_required,
int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_ecc_ctrl *ecc = &chip->ecc;
int ret, i, cur_off = 0;
@@ -1331,12 +1327,12 @@ static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd,
return nand_prog_page_end_op(chip);
}
-static int sunxi_nfc_hw_ecc_write_subpage(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int sunxi_nfc_hw_ecc_write_subpage(struct nand_chip *chip,
u32 data_offs, u32 data_len,
const u8 *buf, int oob_required,
int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_ecc_ctrl *ecc = &chip->ecc;
int ret, i, cur_off = 0;
@@ -1363,12 +1359,12 @@ static int sunxi_nfc_hw_ecc_write_subpage(struct mtd_info *mtd,
return nand_prog_page_end_op(chip);
}
-static int sunxi_nfc_hw_ecc_write_page_dma(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int sunxi_nfc_hw_ecc_write_page_dma(struct nand_chip *chip,
const u8 *buf,
int oob_required,
int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_chip *nand = mtd_to_nand(mtd);
struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
struct nand_ecc_ctrl *ecc = &nand->ecc;
@@ -1425,28 +1421,25 @@ static int sunxi_nfc_hw_ecc_write_page_dma(struct mtd_info *mtd,
return nand_prog_page_end_op(chip);
pio_fallback:
- return sunxi_nfc_hw_ecc_write_page(mtd, chip, buf, oob_required, page);
+ return sunxi_nfc_hw_ecc_write_page(chip, buf, oob_required, page);
}
-static int sunxi_nfc_hw_ecc_read_oob(struct mtd_info *mtd,
- struct nand_chip *chip,
- int page)
+static int sunxi_nfc_hw_ecc_read_oob(struct nand_chip *chip, int page)
{
chip->pagebuf = -1;
- return chip->ecc.read_page(mtd, chip, chip->data_buf, 1, page);
+ return chip->ecc.read_page(chip, chip->data_buf, 1, page);
}
-static int sunxi_nfc_hw_ecc_write_oob(struct mtd_info *mtd,
- struct nand_chip *chip,
- int page)
+static int sunxi_nfc_hw_ecc_write_oob(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
int ret;
chip->pagebuf = -1;
memset(chip->data_buf, 0xff, mtd->writesize);
- ret = chip->ecc.write_page(mtd, chip, chip->data_buf, 1, page);
+ ret = chip->ecc.write_page(chip, chip->data_buf, 1, page);
if (ret)
return ret;
@@ -1475,10 +1468,9 @@ static int _sunxi_nand_lookup_timing(const s32 *lut, int lut_size, u32 duration,
#define sunxi_nand_lookup_timing(l, p, c) \
_sunxi_nand_lookup_timing(l, ARRAY_SIZE(l), p, c)
-static int sunxi_nfc_setup_data_interface(struct mtd_info *mtd, int csline,
+static int sunxi_nfc_setup_data_interface(struct nand_chip *nand, int csline,
const struct nand_data_interface *conf)
{
- struct nand_chip *nand = mtd_to_nand(mtd);
struct sunxi_nand_chip *chip = to_sunxi_nand(nand);
struct sunxi_nfc *nfc = to_sunxi_nfc(chip->nand.controller);
const struct nand_sdr_timings *timings;
@@ -1920,7 +1912,7 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
nand = &chip->nand;
/* Default tR value specified in the ONFI spec (chapter 4.15.1) */
- nand->chip_delay = 200;
+ nand->legacy.chip_delay = 200;
nand->controller = &nfc->controller;
nand->controller->ops = &sunxi_nand_controller_ops;
@@ -1931,23 +1923,23 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
nand->ecc.mode = NAND_ECC_HW;
nand_set_flash_node(nand, np);
nand->select_chip = sunxi_nfc_select_chip;
- nand->cmd_ctrl = sunxi_nfc_cmd_ctrl;
- nand->read_buf = sunxi_nfc_read_buf;
- nand->write_buf = sunxi_nfc_write_buf;
- nand->read_byte = sunxi_nfc_read_byte;
+ nand->legacy.cmd_ctrl = sunxi_nfc_cmd_ctrl;
+ nand->legacy.read_buf = sunxi_nfc_read_buf;
+ nand->legacy.write_buf = sunxi_nfc_write_buf;
+ nand->legacy.read_byte = sunxi_nfc_read_byte;
nand->setup_data_interface = sunxi_nfc_setup_data_interface;
mtd = nand_to_mtd(nand);
mtd->dev.parent = dev;
- ret = nand_scan(mtd, nsels);
+ ret = nand_scan(nand, nsels);
if (ret)
return ret;
ret = mtd_device_register(mtd, NULL, 0);
if (ret) {
dev_err(dev, "failed to register mtd device: %d\n", ret);
- nand_release(mtd);
+ nand_release(nand);
return ret;
}
@@ -1986,7 +1978,7 @@ static void sunxi_nand_chips_cleanup(struct sunxi_nfc *nfc)
while (!list_empty(&nfc->chips)) {
chip = list_first_entry(&nfc->chips, struct sunxi_nand_chip,
node);
- nand_release(nand_to_mtd(&chip->nand));
+ nand_release(&chip->nand);
sunxi_nand_ecc_cleanup(&chip->nand.ecc);
list_del(&chip->node);
}
diff --git a/drivers/mtd/nand/raw/tango_nand.c b/drivers/mtd/nand/raw/tango_nand.c
index 72698691727d..8818f893f300 100644
--- a/drivers/mtd/nand/raw/tango_nand.c
+++ b/drivers/mtd/nand/raw/tango_nand.c
@@ -116,9 +116,9 @@ struct tango_chip {
#define TIMING(t0, t1, t2, t3) ((t0) << 24 | (t1) << 16 | (t2) << 8 | (t3))
-static void tango_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
+static void tango_cmd_ctrl(struct nand_chip *chip, int dat, unsigned int ctrl)
{
- struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+ struct tango_chip *tchip = to_tango_chip(chip);
if (ctrl & NAND_CLE)
writeb_relaxed(dat, tchip->base + PBUS_CMD);
@@ -127,38 +127,36 @@ static void tango_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
writeb_relaxed(dat, tchip->base + PBUS_ADDR);
}
-static int tango_dev_ready(struct mtd_info *mtd)
+static int tango_dev_ready(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct tango_nfc *nfc = to_tango_nfc(chip->controller);
return readl_relaxed(nfc->pbus_base + PBUS_CS_CTRL) & PBUS_IORDY;
}
-static u8 tango_read_byte(struct mtd_info *mtd)
+static u8 tango_read_byte(struct nand_chip *chip)
{
- struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+ struct tango_chip *tchip = to_tango_chip(chip);
return readb_relaxed(tchip->base + PBUS_DATA);
}
-static void tango_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+static void tango_read_buf(struct nand_chip *chip, u8 *buf, int len)
{
- struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+ struct tango_chip *tchip = to_tango_chip(chip);
ioread8_rep(tchip->base + PBUS_DATA, buf, len);
}
-static void tango_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+static void tango_write_buf(struct nand_chip *chip, const u8 *buf, int len)
{
- struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
+ struct tango_chip *tchip = to_tango_chip(chip);
iowrite8_rep(tchip->base + PBUS_DATA, buf, len);
}
-static void tango_select_chip(struct mtd_info *mtd, int idx)
+static void tango_select_chip(struct nand_chip *chip, int idx)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct tango_nfc *nfc = to_tango_nfc(chip->controller);
struct tango_chip *tchip = to_tango_chip(chip);
@@ -277,14 +275,15 @@ dma_unmap:
return err;
}
-static int tango_read_page(struct mtd_info *mtd, struct nand_chip *chip,
- u8 *buf, int oob_required, int page)
+static int tango_read_page(struct nand_chip *chip, u8 *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct tango_nfc *nfc = to_tango_nfc(chip->controller);
int err, res, len = mtd->writesize;
if (oob_required)
- chip->ecc.read_oob(mtd, chip, page);
+ chip->ecc.read_oob(chip, page);
err = do_dma(nfc, DMA_FROM_DEVICE, NFC_READ, buf, len, page);
if (err)
@@ -292,16 +291,17 @@ static int tango_read_page(struct mtd_info *mtd, struct nand_chip *chip,
res = decode_error_report(chip);
if (res < 0) {
- chip->ecc.read_oob_raw(mtd, chip, page);
+ chip->ecc.read_oob_raw(chip, page);
res = check_erased_page(chip, buf);
}
return res;
}
-static int tango_write_page(struct mtd_info *mtd, struct nand_chip *chip,
- const u8 *buf, int oob_required, int page)
+static int tango_write_page(struct nand_chip *chip, const u8 *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct tango_nfc *nfc = to_tango_nfc(chip->controller);
int err, status, len = mtd->writesize;
@@ -314,7 +314,7 @@ static int tango_write_page(struct mtd_info *mtd, struct nand_chip *chip,
if (err)
return err;
- status = chip->waitfunc(mtd, chip);
+ status = chip->legacy.waitfunc(chip);
if (status & NAND_STATUS_FAIL)
return -EIO;
@@ -323,30 +323,26 @@ static int tango_write_page(struct mtd_info *mtd, struct nand_chip *chip,
static void aux_read(struct nand_chip *chip, u8 **buf, int len, int *pos)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
-
*pos += len;
if (!*buf) {
/* skip over "len" bytes */
nand_change_read_column_op(chip, *pos, NULL, 0, false);
} else {
- tango_read_buf(mtd, *buf, len);
+ tango_read_buf(chip, *buf, len);
*buf += len;
}
}
static void aux_write(struct nand_chip *chip, const u8 **buf, int len, int *pos)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
-
*pos += len;
if (!*buf) {
/* skip over "len" bytes */
nand_change_write_column_op(chip, *pos, NULL, 0, false);
} else {
- tango_write_buf(mtd, *buf, len);
+ tango_write_buf(chip, *buf, len);
*buf += len;
}
}
@@ -424,32 +420,30 @@ static void raw_write(struct nand_chip *chip, const u8 *buf, const u8 *oob)
aux_write(chip, &oob, ecc_size, &pos);
}
-static int tango_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- u8 *buf, int oob_required, int page)
+static int tango_read_page_raw(struct nand_chip *chip, u8 *buf,
+ int oob_required, int page)
{
nand_read_page_op(chip, page, 0, NULL, 0);
raw_read(chip, buf, chip->oob_poi);
return 0;
}
-static int tango_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- const u8 *buf, int oob_required, int page)
+static int tango_write_page_raw(struct nand_chip *chip, const u8 *buf,
+ int oob_required, int page)
{
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
raw_write(chip, buf, chip->oob_poi);
return nand_prog_page_end_op(chip);
}
-static int tango_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int tango_read_oob(struct nand_chip *chip, int page)
{
nand_read_page_op(chip, page, 0, NULL, 0);
raw_read(chip, NULL, chip->oob_poi);
return 0;
}
-static int tango_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int tango_write_oob(struct nand_chip *chip, int page)
{
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
raw_write(chip, NULL, chip->oob_poi);
@@ -485,11 +479,10 @@ static u32 to_ticks(int kHz, int ps)
return DIV_ROUND_UP_ULL((u64)kHz * ps, NSEC_PER_SEC);
}
-static int tango_set_timings(struct mtd_info *mtd, int csline,
+static int tango_set_timings(struct nand_chip *chip, int csline,
const struct nand_data_interface *conf)
{
const struct nand_sdr_timings *sdr = nand_get_sdr_timings(conf);
- struct nand_chip *chip = mtd_to_nand(mtd);
struct tango_nfc *nfc = to_tango_nfc(chip->controller);
struct tango_chip *tchip = to_tango_chip(chip);
u32 Trdy, Textw, Twc, Twpw, Tacc, Thold, Trpw, Textr;
@@ -571,12 +564,12 @@ static int chip_init(struct device *dev, struct device_node *np)
ecc = &chip->ecc;
mtd = nand_to_mtd(chip);
- chip->read_byte = tango_read_byte;
- chip->write_buf = tango_write_buf;
- chip->read_buf = tango_read_buf;
+ chip->legacy.read_byte = tango_read_byte;
+ chip->legacy.write_buf = tango_write_buf;
+ chip->legacy.read_buf = tango_read_buf;
chip->select_chip = tango_select_chip;
- chip->cmd_ctrl = tango_cmd_ctrl;
- chip->dev_ready = tango_dev_ready;
+ chip->legacy.cmd_ctrl = tango_cmd_ctrl;
+ chip->legacy.dev_ready = tango_dev_ready;
chip->setup_data_interface = tango_set_timings;
chip->options = NAND_USE_BOUNCE_BUFFER |
NAND_NO_SUBPAGE_WRITE |
@@ -588,7 +581,7 @@ static int chip_init(struct device *dev, struct device_node *np)
mtd_set_ooblayout(mtd, &tango_nand_ooblayout_ops);
mtd->dev.parent = dev;
- err = nand_scan(mtd, 1);
+ err = nand_scan(chip, 1);
if (err)
return err;
@@ -617,7 +610,7 @@ static int tango_nand_remove(struct platform_device *pdev)
for (cs = 0; cs < MAX_CS; ++cs) {
if (nfc->chips[cs])
- nand_release(nand_to_mtd(&nfc->chips[cs]->nand_chip));
+ nand_release(&nfc->chips[cs]->nand_chip);
}
return 0;
diff --git a/drivers/mtd/nand/raw/tegra_nand.c b/drivers/mtd/nand/raw/tegra_nand.c
index 79da1efc88d1..9767e29d74e2 100644
--- a/drivers/mtd/nand/raw/tegra_nand.c
+++ b/drivers/mtd/nand/raw/tegra_nand.c
@@ -462,9 +462,8 @@ static int tegra_nand_exec_op(struct nand_chip *chip,
check_only);
}
-static void tegra_nand_select_chip(struct mtd_info *mtd, int die_nr)
+static void tegra_nand_select_chip(struct nand_chip *chip, int die_nr)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct tegra_nand_chip *nand = to_tegra_chip(chip);
struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller);
@@ -615,44 +614,46 @@ err_unmap_dma_page:
return ret;
}
-static int tegra_nand_read_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip, u8 *buf,
+static int tegra_nand_read_page_raw(struct nand_chip *chip, u8 *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
void *oob_buf = oob_required ? chip->oob_poi : NULL;
return tegra_nand_page_xfer(mtd, chip, buf, oob_buf,
mtd->oobsize, page, true);
}
-static int tegra_nand_write_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip, const u8 *buf,
+static int tegra_nand_write_page_raw(struct nand_chip *chip, const u8 *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
void *oob_buf = oob_required ? chip->oob_poi : NULL;
return tegra_nand_page_xfer(mtd, chip, (void *)buf, oob_buf,
mtd->oobsize, page, false);
}
-static int tegra_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int tegra_nand_read_oob(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
return tegra_nand_page_xfer(mtd, chip, NULL, chip->oob_poi,
mtd->oobsize, page, true);
}
-static int tegra_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int tegra_nand_write_oob(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
return tegra_nand_page_xfer(mtd, chip, NULL, chip->oob_poi,
mtd->oobsize, page, false);
}
-static int tegra_nand_read_page_hwecc(struct mtd_info *mtd,
- struct nand_chip *chip, u8 *buf,
+static int tegra_nand_read_page_hwecc(struct nand_chip *chip, u8 *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller);
struct tegra_nand_chip *nand = to_tegra_chip(chip);
void *oob_buf = oob_required ? chip->oob_poi : NULL;
@@ -716,7 +717,7 @@ static int tegra_nand_read_page_hwecc(struct mtd_info *mtd,
* erased or if error correction just failed for all sub-
* pages.
*/
- ret = tegra_nand_read_oob(mtd, chip, page);
+ ret = tegra_nand_read_oob(chip, page);
if (ret < 0)
return ret;
@@ -759,10 +760,10 @@ static int tegra_nand_read_page_hwecc(struct mtd_info *mtd,
}
}
-static int tegra_nand_write_page_hwecc(struct mtd_info *mtd,
- struct nand_chip *chip, const u8 *buf,
+static int tegra_nand_write_page_hwecc(struct nand_chip *chip, const u8 *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller);
void *oob_buf = oob_required ? chip->oob_poi : NULL;
int ret;
@@ -813,10 +814,9 @@ static void tegra_nand_setup_timing(struct tegra_nand_controller *ctrl,
writel_relaxed(reg, ctrl->regs + TIMING_2);
}
-static int tegra_nand_setup_data_interface(struct mtd_info *mtd, int csline,
+static int tegra_nand_setup_data_interface(struct nand_chip *chip, int csline,
const struct nand_data_interface *conf)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller);
const struct nand_sdr_timings *timings;
@@ -1119,7 +1119,7 @@ static int tegra_nand_chips_init(struct device *dev,
chip->select_chip = tegra_nand_select_chip;
chip->setup_data_interface = tegra_nand_setup_data_interface;
- ret = nand_scan(mtd, 1);
+ ret = nand_scan(chip, 1);
if (ret)
return ret;
diff --git a/drivers/mtd/nand/raw/tmio_nand.c b/drivers/mtd/nand/raw/tmio_nand.c
index dcaa924502de..f3b59e649b7d 100644
--- a/drivers/mtd/nand/raw/tmio_nand.c
+++ b/drivers/mtd/nand/raw/tmio_nand.c
@@ -126,11 +126,10 @@ static inline struct tmio_nand *mtd_to_tmio(struct mtd_info *mtd)
/*--------------------------------------------------------------------------*/
-static void tmio_nand_hwcontrol(struct mtd_info *mtd, int cmd,
- unsigned int ctrl)
+static void tmio_nand_hwcontrol(struct nand_chip *chip, int cmd,
+ unsigned int ctrl)
{
- struct tmio_nand *tmio = mtd_to_tmio(mtd);
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip));
if (ctrl & NAND_CTRL_CHANGE) {
u8 mode;
@@ -156,12 +155,12 @@ static void tmio_nand_hwcontrol(struct mtd_info *mtd, int cmd,
}
if (cmd != NAND_CMD_NONE)
- tmio_iowrite8(cmd, chip->IO_ADDR_W);
+ tmio_iowrite8(cmd, chip->legacy.IO_ADDR_W);
}
-static int tmio_nand_dev_ready(struct mtd_info *mtd)
+static int tmio_nand_dev_ready(struct nand_chip *chip)
{
- struct tmio_nand *tmio = mtd_to_tmio(mtd);
+ struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip));
return !(tmio_ioread8(tmio->fcr + FCR_STATUS) & FCR_STATUS_BUSY);
}
@@ -187,10 +186,9 @@ static irqreturn_t tmio_irq(int irq, void *__tmio)
*erase and write, we enable it to wake us up. The irq handler
*disables the interrupt.
*/
-static int
-tmio_nand_wait(struct mtd_info *mtd, struct nand_chip *nand_chip)
+static int tmio_nand_wait(struct nand_chip *nand_chip)
{
- struct tmio_nand *tmio = mtd_to_tmio(mtd);
+ struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(nand_chip));
long timeout;
u8 status;
@@ -199,10 +197,10 @@ tmio_nand_wait(struct mtd_info *mtd, struct nand_chip *nand_chip)
tmio_iowrite8(0x81, tmio->fcr + FCR_IMR);
timeout = wait_event_timeout(nand_chip->controller->wq,
- tmio_nand_dev_ready(mtd),
+ tmio_nand_dev_ready(nand_chip),
msecs_to_jiffies(nand_chip->state == FL_ERASING ? 400 : 20));
- if (unlikely(!tmio_nand_dev_ready(mtd))) {
+ if (unlikely(!tmio_nand_dev_ready(nand_chip))) {
tmio_iowrite8(0x00, tmio->fcr + FCR_IMR);
dev_warn(&tmio->dev->dev, "still busy with %s after %d ms\n",
nand_chip->state == FL_ERASING ? "erase" : "program",
@@ -225,9 +223,9 @@ tmio_nand_wait(struct mtd_info *mtd, struct nand_chip *nand_chip)
*To prevent stale data from being read, tmio_nand_hwcontrol() clears
*tmio->read_good.
*/
-static u_char tmio_nand_read_byte(struct mtd_info *mtd)
+static u_char tmio_nand_read_byte(struct nand_chip *chip)
{
- struct tmio_nand *tmio = mtd_to_tmio(mtd);
+ struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip));
unsigned int data;
if (tmio->read_good--)
@@ -245,33 +243,33 @@ static u_char tmio_nand_read_byte(struct mtd_info *mtd)
*buffer functions.
*/
static void
-tmio_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+tmio_nand_write_buf(struct nand_chip *chip, const u_char *buf, int len)
{
- struct tmio_nand *tmio = mtd_to_tmio(mtd);
+ struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip));
tmio_iowrite16_rep(tmio->fcr + FCR_DATA, buf, len >> 1);
}
-static void tmio_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void tmio_nand_read_buf(struct nand_chip *chip, u_char *buf, int len)
{
- struct tmio_nand *tmio = mtd_to_tmio(mtd);
+ struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip));
tmio_ioread16_rep(tmio->fcr + FCR_DATA, buf, len >> 1);
}
-static void tmio_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+static void tmio_nand_enable_hwecc(struct nand_chip *chip, int mode)
{
- struct tmio_nand *tmio = mtd_to_tmio(mtd);
+ struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip));
tmio_iowrite8(FCR_MODE_HWECC_RESET, tmio->fcr + FCR_MODE);
tmio_ioread8(tmio->fcr + FCR_DATA); /* dummy read */
tmio_iowrite8(FCR_MODE_HWECC_CALC, tmio->fcr + FCR_MODE);
}
-static int tmio_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
- u_char *ecc_code)
+static int tmio_nand_calculate_ecc(struct nand_chip *chip, const u_char *dat,
+ u_char *ecc_code)
{
- struct tmio_nand *tmio = mtd_to_tmio(mtd);
+ struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip));
unsigned int ecc;
tmio_iowrite8(FCR_MODE_HWECC_RESULT, tmio->fcr + FCR_MODE);
@@ -290,16 +288,18 @@ static int tmio_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
return 0;
}
-static int tmio_nand_correct_data(struct mtd_info *mtd, unsigned char *buf,
- unsigned char *read_ecc, unsigned char *calc_ecc)
+static int tmio_nand_correct_data(struct nand_chip *chip, unsigned char *buf,
+ unsigned char *read_ecc,
+ unsigned char *calc_ecc)
{
int r0, r1;
/* assume ecc.size = 512 and ecc.bytes = 6 */
- r0 = __nand_correct_data(buf, read_ecc, calc_ecc, 256);
+ r0 = __nand_correct_data(buf, read_ecc, calc_ecc, 256, false);
if (r0 < 0)
return r0;
- r1 = __nand_correct_data(buf + 256, read_ecc + 3, calc_ecc + 3, 256);
+ r1 = __nand_correct_data(buf + 256, read_ecc + 3, calc_ecc + 3, 256,
+ false);
if (r1 < 0)
return r1;
return r0 + r1;
@@ -400,15 +400,15 @@ static int tmio_probe(struct platform_device *dev)
return retval;
/* Set address of NAND IO lines */
- nand_chip->IO_ADDR_R = tmio->fcr;
- nand_chip->IO_ADDR_W = tmio->fcr;
+ nand_chip->legacy.IO_ADDR_R = tmio->fcr;
+ nand_chip->legacy.IO_ADDR_W = tmio->fcr;
/* Set address of hardware control function */
- nand_chip->cmd_ctrl = tmio_nand_hwcontrol;
- nand_chip->dev_ready = tmio_nand_dev_ready;
- nand_chip->read_byte = tmio_nand_read_byte;
- nand_chip->write_buf = tmio_nand_write_buf;
- nand_chip->read_buf = tmio_nand_read_buf;
+ nand_chip->legacy.cmd_ctrl = tmio_nand_hwcontrol;
+ nand_chip->legacy.dev_ready = tmio_nand_dev_ready;
+ nand_chip->legacy.read_byte = tmio_nand_read_byte;
+ nand_chip->legacy.write_buf = tmio_nand_write_buf;
+ nand_chip->legacy.read_buf = tmio_nand_read_buf;
/* set eccmode using hardware ECC */
nand_chip->ecc.mode = NAND_ECC_HW;
@@ -423,7 +423,7 @@ static int tmio_probe(struct platform_device *dev)
nand_chip->badblock_pattern = data->badblock_pattern;
/* 15 us command delay time */
- nand_chip->chip_delay = 15;
+ nand_chip->legacy.chip_delay = 15;
retval = devm_request_irq(&dev->dev, irq, &tmio_irq, 0,
dev_name(&dev->dev), tmio);
@@ -433,10 +433,10 @@ static int tmio_probe(struct platform_device *dev)
}
tmio->irq = irq;
- nand_chip->waitfunc = tmio_nand_wait;
+ nand_chip->legacy.waitfunc = tmio_nand_wait;
/* Scan to find existence of the device */
- retval = nand_scan(mtd, 1);
+ retval = nand_scan(nand_chip, 1);
if (retval)
goto err_irq;
@@ -449,7 +449,7 @@ static int tmio_probe(struct platform_device *dev)
if (!retval)
return retval;
- nand_release(mtd);
+ nand_release(nand_chip);
err_irq:
tmio_hw_stop(dev, tmio);
@@ -460,7 +460,7 @@ static int tmio_remove(struct platform_device *dev)
{
struct tmio_nand *tmio = platform_get_drvdata(dev);
- nand_release(nand_to_mtd(&tmio->chip));
+ nand_release(&tmio->chip);
tmio_hw_stop(dev, tmio);
return 0;
}
diff --git a/drivers/mtd/nand/raw/txx9ndfmc.c b/drivers/mtd/nand/raw/txx9ndfmc.c
index 4d61a14fcb65..ddf0420c0997 100644
--- a/drivers/mtd/nand/raw/txx9ndfmc.c
+++ b/drivers/mtd/nand/raw/txx9ndfmc.c
@@ -102,17 +102,17 @@ static void txx9ndfmc_write(struct platform_device *dev,
__raw_writel(val, ndregaddr(dev, reg));
}
-static uint8_t txx9ndfmc_read_byte(struct mtd_info *mtd)
+static uint8_t txx9ndfmc_read_byte(struct nand_chip *chip)
{
- struct platform_device *dev = mtd_to_platdev(mtd);
+ struct platform_device *dev = mtd_to_platdev(nand_to_mtd(chip));
return txx9ndfmc_read(dev, TXX9_NDFDTR);
}
-static void txx9ndfmc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
+static void txx9ndfmc_write_buf(struct nand_chip *chip, const uint8_t *buf,
int len)
{
- struct platform_device *dev = mtd_to_platdev(mtd);
+ struct platform_device *dev = mtd_to_platdev(nand_to_mtd(chip));
void __iomem *ndfdtr = ndregaddr(dev, TXX9_NDFDTR);
u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR);
@@ -122,19 +122,18 @@ static void txx9ndfmc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
txx9ndfmc_write(dev, mcr, TXX9_NDFMCR);
}
-static void txx9ndfmc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void txx9ndfmc_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
{
- struct platform_device *dev = mtd_to_platdev(mtd);
+ struct platform_device *dev = mtd_to_platdev(nand_to_mtd(chip));
void __iomem *ndfdtr = ndregaddr(dev, TXX9_NDFDTR);
while (len--)
*buf++ = __raw_readl(ndfdtr);
}
-static void txx9ndfmc_cmd_ctrl(struct mtd_info *mtd, int cmd,
+static void txx9ndfmc_cmd_ctrl(struct nand_chip *chip, int cmd,
unsigned int ctrl)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct txx9ndfmc_priv *txx9_priv = nand_get_controller_data(chip);
struct platform_device *dev = txx9_priv->dev;
struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev);
@@ -163,18 +162,17 @@ static void txx9ndfmc_cmd_ctrl(struct mtd_info *mtd, int cmd,
mmiowb();
}
-static int txx9ndfmc_dev_ready(struct mtd_info *mtd)
+static int txx9ndfmc_dev_ready(struct nand_chip *chip)
{
- struct platform_device *dev = mtd_to_platdev(mtd);
+ struct platform_device *dev = mtd_to_platdev(nand_to_mtd(chip));
return !(txx9ndfmc_read(dev, TXX9_NDFSR) & TXX9_NDFSR_BUSY);
}
-static int txx9ndfmc_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
+static int txx9ndfmc_calculate_ecc(struct nand_chip *chip, const uint8_t *dat,
uint8_t *ecc_code)
{
- struct platform_device *dev = mtd_to_platdev(mtd);
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct platform_device *dev = mtd_to_platdev(nand_to_mtd(chip));
int eccbytes;
u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR);
@@ -191,16 +189,17 @@ static int txx9ndfmc_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
return 0;
}
-static int txx9ndfmc_correct_data(struct mtd_info *mtd, unsigned char *buf,
- unsigned char *read_ecc, unsigned char *calc_ecc)
+static int txx9ndfmc_correct_data(struct nand_chip *chip, unsigned char *buf,
+ unsigned char *read_ecc,
+ unsigned char *calc_ecc)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
int eccsize;
int corrected = 0;
int stat;
for (eccsize = chip->ecc.size; eccsize > 0; eccsize -= 256) {
- stat = __nand_correct_data(buf, read_ecc, calc_ecc, 256);
+ stat = __nand_correct_data(buf, read_ecc, calc_ecc, 256,
+ false);
if (stat < 0)
return stat;
corrected += stat;
@@ -211,9 +210,9 @@ static int txx9ndfmc_correct_data(struct mtd_info *mtd, unsigned char *buf,
return corrected;
}
-static void txx9ndfmc_enable_hwecc(struct mtd_info *mtd, int mode)
+static void txx9ndfmc_enable_hwecc(struct nand_chip *chip, int mode)
{
- struct platform_device *dev = mtd_to_platdev(mtd);
+ struct platform_device *dev = mtd_to_platdev(nand_to_mtd(chip));
u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR);
mcr &= ~TXX9_NDFMCR_ECC_ALL;
@@ -326,17 +325,17 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
mtd = nand_to_mtd(chip);
mtd->dev.parent = &dev->dev;
- chip->read_byte = txx9ndfmc_read_byte;
- chip->read_buf = txx9ndfmc_read_buf;
- chip->write_buf = txx9ndfmc_write_buf;
- chip->cmd_ctrl = txx9ndfmc_cmd_ctrl;
- chip->dev_ready = txx9ndfmc_dev_ready;
+ chip->legacy.read_byte = txx9ndfmc_read_byte;
+ chip->legacy.read_buf = txx9ndfmc_read_buf;
+ chip->legacy.write_buf = txx9ndfmc_write_buf;
+ chip->legacy.cmd_ctrl = txx9ndfmc_cmd_ctrl;
+ chip->legacy.dev_ready = txx9ndfmc_dev_ready;
chip->ecc.calculate = txx9ndfmc_calculate_ecc;
chip->ecc.correct = txx9ndfmc_correct_data;
chip->ecc.hwctl = txx9ndfmc_enable_hwecc;
chip->ecc.mode = NAND_ECC_HW;
chip->ecc.strength = 1;
- chip->chip_delay = 100;
+ chip->legacy.chip_delay = 100;
chip->controller = &drvdata->controller;
nand_set_controller_data(chip, txx9_priv);
@@ -359,7 +358,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
if (plat->wide_mask & (1 << i))
chip->options |= NAND_BUSWIDTH_16;
- if (nand_scan(mtd, 1)) {
+ if (nand_scan(chip, 1)) {
kfree(txx9_priv->mtdname);
kfree(txx9_priv);
continue;
@@ -390,7 +389,7 @@ static int __exit txx9ndfmc_remove(struct platform_device *dev)
chip = mtd_to_nand(mtd);
txx9_priv = nand_get_controller_data(chip);
- nand_release(mtd);
+ nand_release(chip);
kfree(txx9_priv->mtdname);
kfree(txx9_priv);
}
diff --git a/drivers/mtd/nand/raw/vf610_nfc.c b/drivers/mtd/nand/raw/vf610_nfc.c
index 6f6dcbf9095b..9814fd4a84cf 100644
--- a/drivers/mtd/nand/raw/vf610_nfc.c
+++ b/drivers/mtd/nand/raw/vf610_nfc.c
@@ -498,9 +498,9 @@ static int vf610_nfc_exec_op(struct nand_chip *chip,
/*
* This function supports Vybrid only (MPC5125 would have full RB and four CS)
*/
-static void vf610_nfc_select_chip(struct mtd_info *mtd, int chip)
+static void vf610_nfc_select_chip(struct nand_chip *chip, int cs)
{
- struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+ struct vf610_nfc *nfc = mtd_to_nfc(nand_to_mtd(chip));
u32 tmp = vf610_nfc_read(nfc, NFC_ROW_ADDR);
/* Vybrid only (MPC5125 would have full RB and four CS) */
@@ -509,9 +509,9 @@ static void vf610_nfc_select_chip(struct mtd_info *mtd, int chip)
tmp &= ~(ROW_ADDR_CHIP_SEL_RB_MASK | ROW_ADDR_CHIP_SEL_MASK);
- if (chip >= 0) {
+ if (cs >= 0) {
tmp |= 1 << ROW_ADDR_CHIP_SEL_RB_SHIFT;
- tmp |= BIT(chip) << ROW_ADDR_CHIP_SEL_SHIFT;
+ tmp |= BIT(cs) << ROW_ADDR_CHIP_SEL_SHIFT;
}
vf610_nfc_write(nfc, NFC_ROW_ADDR, tmp);
@@ -557,9 +557,10 @@ static void vf610_nfc_fill_row(struct nand_chip *chip, int page, u32 *code,
}
}
-static int vf610_nfc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
+static int vf610_nfc_read_page(struct nand_chip *chip, uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct vf610_nfc *nfc = mtd_to_nfc(mtd);
int trfr_sz = mtd->writesize + mtd->oobsize;
u32 row = 0, cmd1 = 0, cmd2 = 0, code = 0;
@@ -602,9 +603,10 @@ static int vf610_nfc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
}
}
-static int vf610_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required, int page)
+static int vf610_nfc_write_page(struct nand_chip *chip, const uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct vf610_nfc *nfc = mtd_to_nfc(mtd);
int trfr_sz = mtd->writesize + mtd->oobsize;
u32 row = 0, cmd1 = 0, cmd2 = 0, code = 0;
@@ -643,24 +645,24 @@ static int vf610_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
return 0;
}
-static int vf610_nfc_read_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip, u8 *buf,
+static int vf610_nfc_read_page_raw(struct nand_chip *chip, u8 *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct vf610_nfc *nfc = mtd_to_nfc(mtd);
int ret;
nfc->data_access = true;
- ret = nand_read_page_raw(mtd, chip, buf, oob_required, page);
+ ret = nand_read_page_raw(chip, buf, oob_required, page);
nfc->data_access = false;
return ret;
}
-static int vf610_nfc_write_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip, const u8 *buf,
+static int vf610_nfc_write_page_raw(struct nand_chip *chip, const u8 *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct vf610_nfc *nfc = mtd_to_nfc(mtd);
int ret;
@@ -677,22 +679,21 @@ static int vf610_nfc_write_page_raw(struct mtd_info *mtd,
return nand_prog_page_end_op(chip);
}
-static int vf610_nfc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int vf610_nfc_read_oob(struct nand_chip *chip, int page)
{
- struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+ struct vf610_nfc *nfc = mtd_to_nfc(nand_to_mtd(chip));
int ret;
nfc->data_access = true;
- ret = nand_read_oob_std(mtd, chip, page);
+ ret = nand_read_oob_std(chip, page);
nfc->data_access = false;
return ret;
}
-static int vf610_nfc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int vf610_nfc_write_oob(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct vf610_nfc *nfc = mtd_to_nfc(mtd);
int ret;
@@ -892,7 +893,7 @@ static int vf610_nfc_probe(struct platform_device *pdev)
/* Scan the NAND chip */
chip->dummy_controller.ops = &vf610_nfc_controller_ops;
- err = nand_scan(mtd, 1);
+ err = nand_scan(chip, 1);
if (err)
goto err_disable_clk;
@@ -916,7 +917,7 @@ static int vf610_nfc_remove(struct platform_device *pdev)
struct mtd_info *mtd = platform_get_drvdata(pdev);
struct vf610_nfc *nfc = mtd_to_nfc(mtd);
- nand_release(mtd);
+ nand_release(mtd_to_nand(mtd));
clk_disable_unprepare(nfc->clk);
return 0;
}
diff --git a/drivers/mtd/nand/raw/xway_nand.c b/drivers/mtd/nand/raw/xway_nand.c
index 9926b4e3d69d..a234a5cb4868 100644
--- a/drivers/mtd/nand/raw/xway_nand.c
+++ b/drivers/mtd/nand/raw/xway_nand.c
@@ -85,9 +85,8 @@ static void xway_writeb(struct mtd_info *mtd, int op, u8 value)
writeb(value, data->nandaddr + op);
}
-static void xway_select_chip(struct mtd_info *mtd, int select)
+static void xway_select_chip(struct nand_chip *chip, int select)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct xway_nand_data *data = nand_get_controller_data(chip);
switch (select) {
@@ -106,8 +105,10 @@ static void xway_select_chip(struct mtd_info *mtd, int select)
}
}
-static void xway_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+static void xway_cmd_ctrl(struct nand_chip *chip, int cmd, unsigned int ctrl)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
if (cmd == NAND_CMD_NONE)
return;
@@ -120,30 +121,30 @@ static void xway_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
;
}
-static int xway_dev_ready(struct mtd_info *mtd)
+static int xway_dev_ready(struct nand_chip *chip)
{
return ltq_ebu_r32(EBU_NAND_WAIT) & NAND_WAIT_RD;
}
-static unsigned char xway_read_byte(struct mtd_info *mtd)
+static unsigned char xway_read_byte(struct nand_chip *chip)
{
- return xway_readb(mtd, NAND_READ_DATA);
+ return xway_readb(nand_to_mtd(chip), NAND_READ_DATA);
}
-static void xway_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void xway_read_buf(struct nand_chip *chip, u_char *buf, int len)
{
int i;
for (i = 0; i < len; i++)
- buf[i] = xway_readb(mtd, NAND_WRITE_DATA);
+ buf[i] = xway_readb(nand_to_mtd(chip), NAND_WRITE_DATA);
}
-static void xway_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+static void xway_write_buf(struct nand_chip *chip, const u_char *buf, int len)
{
int i;
for (i = 0; i < len; i++)
- xway_writeb(mtd, NAND_WRITE_DATA, buf[i]);
+ xway_writeb(nand_to_mtd(chip), NAND_WRITE_DATA, buf[i]);
}
/*
@@ -173,13 +174,13 @@ static int xway_nand_probe(struct platform_device *pdev)
mtd = nand_to_mtd(&data->chip);
mtd->dev.parent = &pdev->dev;
- data->chip.cmd_ctrl = xway_cmd_ctrl;
- data->chip.dev_ready = xway_dev_ready;
+ data->chip.legacy.cmd_ctrl = xway_cmd_ctrl;
+ data->chip.legacy.dev_ready = xway_dev_ready;
data->chip.select_chip = xway_select_chip;
- data->chip.write_buf = xway_write_buf;
- data->chip.read_buf = xway_read_buf;
- data->chip.read_byte = xway_read_byte;
- data->chip.chip_delay = 30;
+ data->chip.legacy.write_buf = xway_write_buf;
+ data->chip.legacy.read_buf = xway_read_buf;
+ data->chip.legacy.read_byte = xway_read_byte;
+ data->chip.legacy.chip_delay = 30;
data->chip.ecc.mode = NAND_ECC_SOFT;
data->chip.ecc.algo = NAND_ECC_HAMMING;
@@ -205,13 +206,13 @@ static int xway_nand_probe(struct platform_device *pdev)
| cs_flag, EBU_NAND_CON);
/* Scan to find existence of the device */
- err = nand_scan(mtd, 1);
+ err = nand_scan(&data->chip, 1);
if (err)
return err;
err = mtd_device_register(mtd, NULL, 0);
if (err)
- nand_release(mtd);
+ nand_release(&data->chip);
return err;
}
@@ -223,7 +224,7 @@ static int xway_nand_remove(struct platform_device *pdev)
{
struct xway_nand_data *data = platform_get_drvdata(pdev);
- nand_release(nand_to_mtd(&data->chip));
+ nand_release(&data->chip);
return 0;
}
diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c
index f3bd86e13603..89227b1d036a 100644
--- a/drivers/mtd/sm_ftl.c
+++ b/drivers/mtd/sm_ftl.c
@@ -221,14 +221,18 @@ static int sm_correct_sector(uint8_t *buffer, struct sm_oob *oob)
{
uint8_t ecc[3];
- __nand_calculate_ecc(buffer, SM_SMALL_PAGE, ecc);
- if (__nand_correct_data(buffer, ecc, oob->ecc1, SM_SMALL_PAGE) < 0)
+ __nand_calculate_ecc(buffer, SM_SMALL_PAGE, ecc,
+ IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
+ if (__nand_correct_data(buffer, ecc, oob->ecc1, SM_SMALL_PAGE,
+ IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC)) < 0)
return -EIO;
buffer += SM_SMALL_PAGE;
- __nand_calculate_ecc(buffer, SM_SMALL_PAGE, ecc);
- if (__nand_correct_data(buffer, ecc, oob->ecc2, SM_SMALL_PAGE) < 0)
+ __nand_calculate_ecc(buffer, SM_SMALL_PAGE, ecc,
+ IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
+ if (__nand_correct_data(buffer, ecc, oob->ecc2, SM_SMALL_PAGE,
+ IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC)) < 0)
return -EIO;
return 0;
}
@@ -393,11 +397,13 @@ restart:
}
if (ftl->smallpagenand) {
- __nand_calculate_ecc(buf + boffset,
- SM_SMALL_PAGE, oob.ecc1);
+ __nand_calculate_ecc(buf + boffset, SM_SMALL_PAGE,
+ oob.ecc1,
+ IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
__nand_calculate_ecc(buf + boffset + SM_SMALL_PAGE,
- SM_SMALL_PAGE, oob.ecc2);
+ SM_SMALL_PAGE, oob.ecc2,
+ IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
}
if (!sm_write_sector(ftl, zone, block, boffset,
buf + boffset, &oob))
diff --git a/drivers/mtd/spi-nor/cadence-quadspi.c b/drivers/mtd/spi-nor/cadence-quadspi.c
index 8e714fbfa521..d846428ef038 100644
--- a/drivers/mtd/spi-nor/cadence-quadspi.c
+++ b/drivers/mtd/spi-nor/cadence-quadspi.c
@@ -959,7 +959,7 @@ static int cqspi_direct_read_execute(struct spi_nor *nor, u_char *buf,
return 0;
}
- dma_dst = dma_map_single(nor->dev, buf, len, DMA_DEV_TO_MEM);
+ dma_dst = dma_map_single(nor->dev, buf, len, DMA_FROM_DEVICE);
if (dma_mapping_error(nor->dev, dma_dst)) {
dev_err(nor->dev, "dma mapping failed\n");
return -ENOMEM;
@@ -994,9 +994,9 @@ static int cqspi_direct_read_execute(struct spi_nor *nor, u_char *buf,
}
err_unmap:
- dma_unmap_single(nor->dev, dma_dst, len, DMA_DEV_TO_MEM);
+ dma_unmap_single(nor->dev, dma_dst, len, DMA_FROM_DEVICE);
- return 0;
+ return ret;
}
static ssize_t cqspi_read(struct spi_nor *nor, loff_t from,
diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c
index 7d9620c7ff6c..1ff3430f82c8 100644
--- a/drivers/mtd/spi-nor/fsl-quadspi.c
+++ b/drivers/mtd/spi-nor/fsl-quadspi.c
@@ -478,6 +478,7 @@ static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd)
{
switch (cmd) {
case SPINOR_OP_READ_1_1_4:
+ case SPINOR_OP_READ_1_1_4_4B:
return SEQID_READ;
case SPINOR_OP_WREN:
return SEQID_WREN;
@@ -543,6 +544,9 @@ fsl_qspi_runcmd(struct fsl_qspi *q, u8 cmd, unsigned int addr, int len)
/* trigger the LUT now */
seqid = fsl_qspi_get_seqid(q, cmd);
+ if (seqid < 0)
+ return seqid;
+
qspi_writel(q, (seqid << QUADSPI_IPCR_SEQID_SHIFT) | len,
base + QUADSPI_IPCR);
@@ -671,7 +675,7 @@ static void fsl_qspi_set_map_addr(struct fsl_qspi *q)
* causes the controller to clear the buffer, and use the sequence pointed
* by the QUADSPI_BFGENCR[SEQID] to initiate a read from the flash.
*/
-static void fsl_qspi_init_ahb_read(struct fsl_qspi *q)
+static int fsl_qspi_init_ahb_read(struct fsl_qspi *q)
{
void __iomem *base = q->iobase;
int seqid;
@@ -696,8 +700,13 @@ static void fsl_qspi_init_ahb_read(struct fsl_qspi *q)
/* Set the default lut sequence for AHB Read. */
seqid = fsl_qspi_get_seqid(q, q->nor[0].read_opcode);
+ if (seqid < 0)
+ return seqid;
+
qspi_writel(q, seqid << QUADSPI_BFGENCR_SEQID_SHIFT,
q->iobase + QUADSPI_BFGENCR);
+
+ return 0;
}
/* This function was used to prepare and enable QSPI clock */
@@ -805,9 +814,7 @@ static int fsl_qspi_nor_setup_last(struct fsl_qspi *q)
fsl_qspi_init_lut(q);
/* Init for AHB read */
- fsl_qspi_init_ahb_read(q);
-
- return 0;
+ return fsl_qspi_init_ahb_read(q);
}
static const struct of_device_id fsl_qspi_dt_ids[] = {
diff --git a/drivers/mtd/spi-nor/intel-spi-pci.c b/drivers/mtd/spi-nor/intel-spi-pci.c
index c0976f2e3dd1..872b40922608 100644
--- a/drivers/mtd/spi-nor/intel-spi-pci.c
+++ b/drivers/mtd/spi-nor/intel-spi-pci.c
@@ -65,6 +65,7 @@ static void intel_spi_pci_remove(struct pci_dev *pdev)
static const struct pci_device_id intel_spi_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x18e0), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x19e0), (unsigned long)&bxt_info },
+ { PCI_VDEVICE(INTEL, 0x34a4), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0xa1a4), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0xa224), (unsigned long)&bxt_info },
{ },
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index f028277fb1ce..3e54e31889c7 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -18,6 +18,7 @@
#include <linux/math64.h>
#include <linux/sizes.h>
#include <linux/slab.h>
+#include <linux/sort.h>
#include <linux/mtd/mtd.h>
#include <linux/of_platform.h>
@@ -260,6 +261,18 @@ static void spi_nor_set_4byte_opcodes(struct spi_nor *nor,
nor->read_opcode = spi_nor_convert_3to4_read(nor->read_opcode);
nor->program_opcode = spi_nor_convert_3to4_program(nor->program_opcode);
nor->erase_opcode = spi_nor_convert_3to4_erase(nor->erase_opcode);
+
+ if (!spi_nor_has_uniform_erase(nor)) {
+ struct spi_nor_erase_map *map = &nor->erase_map;
+ struct spi_nor_erase_type *erase;
+ int i;
+
+ for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) {
+ erase = &map->erase_type[i];
+ erase->opcode =
+ spi_nor_convert_3to4_erase(erase->opcode);
+ }
+ }
}
/* Enable/disable 4-byte addressing mode. */
@@ -497,6 +510,277 @@ static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr)
return nor->write_reg(nor, nor->erase_opcode, buf, nor->addr_width);
}
+/**
+ * spi_nor_div_by_erase_size() - calculate remainder and update new dividend
+ * @erase: pointer to a structure that describes a SPI NOR erase type
+ * @dividend: dividend value
+ * @remainder: pointer to u32 remainder (will be updated)
+ *
+ * Return: the result of the division
+ */
+static u64 spi_nor_div_by_erase_size(const struct spi_nor_erase_type *erase,
+ u64 dividend, u32 *remainder)
+{
+ /* JEDEC JESD216B Standard imposes erase sizes to be power of 2. */
+ *remainder = (u32)dividend & erase->size_mask;
+ return dividend >> erase->size_shift;
+}
+
+/**
+ * spi_nor_find_best_erase_type() - find the best erase type for the given
+ * offset in the serial flash memory and the
+ * number of bytes to erase. The region in
+ * which the address fits is expected to be
+ * provided.
+ * @map: the erase map of the SPI NOR
+ * @region: pointer to a structure that describes a SPI NOR erase region
+ * @addr: offset in the serial flash memory
+ * @len: number of bytes to erase
+ *
+ * Return: a pointer to the best fitted erase type, NULL otherwise.
+ */
+static const struct spi_nor_erase_type *
+spi_nor_find_best_erase_type(const struct spi_nor_erase_map *map,
+ const struct spi_nor_erase_region *region,
+ u64 addr, u32 len)
+{
+ const struct spi_nor_erase_type *erase;
+ u32 rem;
+ int i;
+ u8 erase_mask = region->offset & SNOR_ERASE_TYPE_MASK;
+
+ /*
+ * Erase types are ordered by size, with the biggest erase type at
+ * index 0.
+ */
+ for (i = SNOR_ERASE_TYPE_MAX - 1; i >= 0; i--) {
+ /* Does the erase region support the tested erase type? */
+ if (!(erase_mask & BIT(i)))
+ continue;
+
+ erase = &map->erase_type[i];
+
+ /* Don't erase more than what the user has asked for. */
+ if (erase->size > len)
+ continue;
+
+ /* Alignment is not mandatory for overlaid regions */
+ if (region->offset & SNOR_OVERLAID_REGION)
+ return erase;
+
+ spi_nor_div_by_erase_size(erase, addr, &rem);
+ if (rem)
+ continue;
+ else
+ return erase;
+ }
+
+ return NULL;
+}
+
+/**
+ * spi_nor_region_next() - get the next spi nor region
+ * @region: pointer to a structure that describes a SPI NOR erase region
+ *
+ * Return: the next spi nor region or NULL if last region.
+ */
+static struct spi_nor_erase_region *
+spi_nor_region_next(struct spi_nor_erase_region *region)
+{
+ if (spi_nor_region_is_last(region))
+ return NULL;
+ region++;
+ return region;
+}
+
+/**
+ * spi_nor_find_erase_region() - find the region of the serial flash memory in
+ * which the offset fits
+ * @map: the erase map of the SPI NOR
+ * @addr: offset in the serial flash memory
+ *
+ * Return: a pointer to the spi_nor_erase_region struct, ERR_PTR(-errno)
+ * otherwise.
+ */
+static struct spi_nor_erase_region *
+spi_nor_find_erase_region(const struct spi_nor_erase_map *map, u64 addr)
+{
+ struct spi_nor_erase_region *region = map->regions;
+ u64 region_start = region->offset & ~SNOR_ERASE_FLAGS_MASK;
+ u64 region_end = region_start + region->size;
+
+ while (addr < region_start || addr >= region_end) {
+ region = spi_nor_region_next(region);
+ if (!region)
+ return ERR_PTR(-EINVAL);
+
+ region_start = region->offset & ~SNOR_ERASE_FLAGS_MASK;
+ region_end = region_start + region->size;
+ }
+
+ return region;
+}
+
+/**
+ * spi_nor_init_erase_cmd() - initialize an erase command
+ * @region: pointer to a structure that describes a SPI NOR erase region
+ * @erase: pointer to a structure that describes a SPI NOR erase type
+ *
+ * Return: the pointer to the allocated erase command, ERR_PTR(-errno)
+ * otherwise.
+ */
+static struct spi_nor_erase_command *
+spi_nor_init_erase_cmd(const struct spi_nor_erase_region *region,
+ const struct spi_nor_erase_type *erase)
+{
+ struct spi_nor_erase_command *cmd;
+
+ cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd)
+ return ERR_PTR(-ENOMEM);
+
+ INIT_LIST_HEAD(&cmd->list);
+ cmd->opcode = erase->opcode;
+ cmd->count = 1;
+
+ if (region->offset & SNOR_OVERLAID_REGION)
+ cmd->size = region->size;
+ else
+ cmd->size = erase->size;
+
+ return cmd;
+}
+
+/**
+ * spi_nor_destroy_erase_cmd_list() - destroy erase command list
+ * @erase_list: list of erase commands
+ */
+static void spi_nor_destroy_erase_cmd_list(struct list_head *erase_list)
+{
+ struct spi_nor_erase_command *cmd, *next;
+
+ list_for_each_entry_safe(cmd, next, erase_list, list) {
+ list_del(&cmd->list);
+ kfree(cmd);
+ }
+}
+
+/**
+ * spi_nor_init_erase_cmd_list() - initialize erase command list
+ * @nor: pointer to a 'struct spi_nor'
+ * @erase_list: list of erase commands to be executed once we validate that the
+ * erase can be performed
+ * @addr: offset in the serial flash memory
+ * @len: number of bytes to erase
+ *
+ * Builds the list of best fitted erase commands and verifies if the erase can
+ * be performed.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_init_erase_cmd_list(struct spi_nor *nor,
+ struct list_head *erase_list,
+ u64 addr, u32 len)
+{
+ const struct spi_nor_erase_map *map = &nor->erase_map;
+ const struct spi_nor_erase_type *erase, *prev_erase = NULL;
+ struct spi_nor_erase_region *region;
+ struct spi_nor_erase_command *cmd = NULL;
+ u64 region_end;
+ int ret = -EINVAL;
+
+ region = spi_nor_find_erase_region(map, addr);
+ if (IS_ERR(region))
+ return PTR_ERR(region);
+
+ region_end = spi_nor_region_end(region);
+
+ while (len) {
+ erase = spi_nor_find_best_erase_type(map, region, addr, len);
+ if (!erase)
+ goto destroy_erase_cmd_list;
+
+ if (prev_erase != erase ||
+ region->offset & SNOR_OVERLAID_REGION) {
+ cmd = spi_nor_init_erase_cmd(region, erase);
+ if (IS_ERR(cmd)) {
+ ret = PTR_ERR(cmd);
+ goto destroy_erase_cmd_list;
+ }
+
+ list_add_tail(&cmd->list, erase_list);
+ } else {
+ cmd->count++;
+ }
+
+ addr += cmd->size;
+ len -= cmd->size;
+
+ if (len && addr >= region_end) {
+ region = spi_nor_region_next(region);
+ if (!region)
+ goto destroy_erase_cmd_list;
+ region_end = spi_nor_region_end(region);
+ }
+
+ prev_erase = erase;
+ }
+
+ return 0;
+
+destroy_erase_cmd_list:
+ spi_nor_destroy_erase_cmd_list(erase_list);
+ return ret;
+}
+
+/**
+ * spi_nor_erase_multi_sectors() - perform a non-uniform erase
+ * @nor: pointer to a 'struct spi_nor'
+ * @addr: offset in the serial flash memory
+ * @len: number of bytes to erase
+ *
+ * Build a list of best fitted erase commands and execute it once we validate
+ * that the erase can be performed.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_erase_multi_sectors(struct spi_nor *nor, u64 addr, u32 len)
+{
+ LIST_HEAD(erase_list);
+ struct spi_nor_erase_command *cmd, *next;
+ int ret;
+
+ ret = spi_nor_init_erase_cmd_list(nor, &erase_list, addr, len);
+ if (ret)
+ return ret;
+
+ list_for_each_entry_safe(cmd, next, &erase_list, list) {
+ nor->erase_opcode = cmd->opcode;
+ while (cmd->count) {
+ write_enable(nor);
+
+ ret = spi_nor_erase_sector(nor, addr);
+ if (ret)
+ goto destroy_erase_cmd_list;
+
+ addr += cmd->size;
+ cmd->count--;
+
+ ret = spi_nor_wait_till_ready(nor);
+ if (ret)
+ goto destroy_erase_cmd_list;
+ }
+ list_del(&cmd->list);
+ kfree(cmd);
+ }
+
+ return 0;
+
+destroy_erase_cmd_list:
+ spi_nor_destroy_erase_cmd_list(&erase_list);
+ return ret;
+}
+
/*
* Erase an address range on the nor chip. The address range may extend
* one or more erase sectors. Return an error is there is a problem erasing.
@@ -511,9 +795,11 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
dev_dbg(nor->dev, "at 0x%llx, len %lld\n", (long long)instr->addr,
(long long)instr->len);
- div_u64_rem(instr->len, mtd->erasesize, &rem);
- if (rem)
- return -EINVAL;
+ if (spi_nor_has_uniform_erase(nor)) {
+ div_u64_rem(instr->len, mtd->erasesize, &rem);
+ if (rem)
+ return -EINVAL;
+ }
addr = instr->addr;
len = instr->len;
@@ -552,7 +838,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
*/
/* "sector"-at-a-time erase */
- } else {
+ } else if (spi_nor_has_uniform_erase(nor)) {
while (len) {
write_enable(nor);
@@ -567,6 +853,12 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
if (ret)
goto erase_err;
}
+
+ /* erase multiple sectors */
+ } else {
+ ret = spi_nor_erase_multi_sectors(nor, addr, len);
+ if (ret)
+ goto erase_err;
}
write_disable(nor);
@@ -1464,13 +1756,6 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
goto write_err;
*retlen += written;
i += written;
- if (written != page_remain) {
- dev_err(nor->dev,
- "While writing %zu bytes written %zd bytes\n",
- page_remain, written);
- ret = -EIO;
- goto write_err;
- }
}
write_err:
@@ -1864,6 +2149,36 @@ spi_nor_set_pp_settings(struct spi_nor_pp_command *pp,
*/
/**
+ * spi_nor_read_raw() - raw read of serial flash memory. read_opcode,
+ * addr_width and read_dummy members of the struct spi_nor
+ * should be previously
+ * set.
+ * @nor: pointer to a 'struct spi_nor'
+ * @addr: offset in the serial flash memory
+ * @len: number of bytes to read
+ * @buf: buffer where the data is copied into
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_read_raw(struct spi_nor *nor, u32 addr, size_t len, u8 *buf)
+{
+ int ret;
+
+ while (len) {
+ ret = nor->read(nor, addr, len, buf);
+ if (!ret || ret > len)
+ return -EIO;
+ if (ret < 0)
+ return ret;
+
+ buf += ret;
+ addr += ret;
+ len -= ret;
+ }
+ return 0;
+}
+
+/**
* spi_nor_read_sfdp() - read Serial Flash Discoverable Parameters.
* @nor: pointer to a 'struct spi_nor'
* @addr: offset in the SFDP area to start reading data from
@@ -1890,22 +2205,8 @@ static int spi_nor_read_sfdp(struct spi_nor *nor, u32 addr,
nor->addr_width = 3;
nor->read_dummy = 8;
- while (len) {
- ret = nor->read(nor, addr, len, (u8 *)buf);
- if (!ret || ret > len) {
- ret = -EIO;
- goto read_err;
- }
- if (ret < 0)
- goto read_err;
-
- buf += ret;
- addr += ret;
- len -= ret;
- }
- ret = 0;
+ ret = spi_nor_read_raw(nor, addr, len, buf);
-read_err:
nor->read_opcode = read_opcode;
nor->addr_width = addr_width;
nor->read_dummy = read_dummy;
@@ -2166,6 +2467,116 @@ static const struct sfdp_bfpt_erase sfdp_bfpt_erases[] = {
static int spi_nor_hwcaps_read2cmd(u32 hwcaps);
/**
+ * spi_nor_set_erase_type() - set a SPI NOR erase type
+ * @erase: pointer to a structure that describes a SPI NOR erase type
+ * @size: the size of the sector/block erased by the erase type
+ * @opcode: the SPI command op code to erase the sector/block
+ */
+static void spi_nor_set_erase_type(struct spi_nor_erase_type *erase,
+ u32 size, u8 opcode)
+{
+ erase->size = size;
+ erase->opcode = opcode;
+ /* JEDEC JESD216B Standard imposes erase sizes to be power of 2. */
+ erase->size_shift = ffs(erase->size) - 1;
+ erase->size_mask = (1 << erase->size_shift) - 1;
+}
+
+/**
+ * spi_nor_set_erase_settings_from_bfpt() - set erase type settings from BFPT
+ * @erase: pointer to a structure that describes a SPI NOR erase type
+ * @size: the size of the sector/block erased by the erase type
+ * @opcode: the SPI command op code to erase the sector/block
+ * @i: erase type index as sorted in the Basic Flash Parameter Table
+ *
+ * The supported Erase Types will be sorted at init in ascending order, with
+ * the smallest Erase Type size being the first member in the erase_type array
+ * of the spi_nor_erase_map structure. Save the Erase Type index as sorted in
+ * the Basic Flash Parameter Table since it will be used later on to
+ * synchronize with the supported Erase Types defined in SFDP optional tables.
+ */
+static void
+spi_nor_set_erase_settings_from_bfpt(struct spi_nor_erase_type *erase,
+ u32 size, u8 opcode, u8 i)
+{
+ erase->idx = i;
+ spi_nor_set_erase_type(erase, size, opcode);
+}
+
+/**
+ * spi_nor_map_cmp_erase_type() - compare the map's erase types by size
+ * @l: member in the left half of the map's erase_type array
+ * @r: member in the right half of the map's erase_type array
+ *
+ * Comparison function used in the sort() call to sort in ascending order the
+ * map's erase types, the smallest erase type size being the first member in the
+ * sorted erase_type array.
+ *
+ * Return: the result of @l->size - @r->size
+ */
+static int spi_nor_map_cmp_erase_type(const void *l, const void *r)
+{
+ const struct spi_nor_erase_type *left = l, *right = r;
+
+ return left->size - right->size;
+}
+
+/**
+ * spi_nor_regions_sort_erase_types() - sort erase types in each region
+ * @map: the erase map of the SPI NOR
+ *
+ * Function assumes that the erase types defined in the erase map are already
+ * sorted in ascending order, with the smallest erase type size being the first
+ * member in the erase_type array. It replicates the sort done for the map's
+ * erase types. Each region's erase bitmask will indicate which erase types are
+ * supported from the sorted erase types defined in the erase map.
+ * Sort the all region's erase type at init in order to speed up the process of
+ * finding the best erase command at runtime.
+ */
+static void spi_nor_regions_sort_erase_types(struct spi_nor_erase_map *map)
+{
+ struct spi_nor_erase_region *region = map->regions;
+ struct spi_nor_erase_type *erase_type = map->erase_type;
+ int i;
+ u8 region_erase_mask, sorted_erase_mask;
+
+ while (region) {
+ region_erase_mask = region->offset & SNOR_ERASE_TYPE_MASK;
+
+ /* Replicate the sort done for the map's erase types. */
+ sorted_erase_mask = 0;
+ for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++)
+ if (erase_type[i].size &&
+ region_erase_mask & BIT(erase_type[i].idx))
+ sorted_erase_mask |= BIT(i);
+
+ /* Overwrite erase mask. */
+ region->offset = (region->offset & ~SNOR_ERASE_TYPE_MASK) |
+ sorted_erase_mask;
+
+ region = spi_nor_region_next(region);
+ }
+}
+
+/**
+ * spi_nor_init_uniform_erase_map() - Initialize uniform erase map
+ * @map: the erase map of the SPI NOR
+ * @erase_mask: bitmask encoding erase types that can erase the entire
+ * flash memory
+ * @flash_size: the spi nor flash memory size
+ */
+static void spi_nor_init_uniform_erase_map(struct spi_nor_erase_map *map,
+ u8 erase_mask, u64 flash_size)
+{
+ /* Offset 0 with erase_mask and SNOR_LAST_REGION bit set */
+ map->uniform_region.offset = (erase_mask & SNOR_ERASE_TYPE_MASK) |
+ SNOR_LAST_REGION;
+ map->uniform_region.size = flash_size;
+ map->regions = &map->uniform_region;
+ map->uniform_erase_type = erase_mask;
+}
+
+/**
* spi_nor_parse_bfpt() - read and parse the Basic Flash Parameter Table.
* @nor: pointer to a 'struct spi_nor'
* @bfpt_header: pointer to the 'struct sfdp_parameter_header' describing
@@ -2199,12 +2610,14 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
const struct sfdp_parameter_header *bfpt_header,
struct spi_nor_flash_parameter *params)
{
- struct mtd_info *mtd = &nor->mtd;
+ struct spi_nor_erase_map *map = &nor->erase_map;
+ struct spi_nor_erase_type *erase_type = map->erase_type;
struct sfdp_bfpt bfpt;
size_t len;
int i, cmd, err;
u32 addr;
u16 half;
+ u8 erase_mask;
/* JESD216 Basic Flash Parameter Table length is at least 9 DWORDs. */
if (bfpt_header->length < BFPT_DWORD_MAX_JESD216)
@@ -2273,7 +2686,12 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
spi_nor_set_read_settings_from_bfpt(read, half, rd->proto);
}
- /* Sector Erase settings. */
+ /*
+ * Sector Erase settings. Reinitialize the uniform erase map using the
+ * Erase Types defined in the bfpt table.
+ */
+ erase_mask = 0;
+ memset(&nor->erase_map, 0, sizeof(nor->erase_map));
for (i = 0; i < ARRAY_SIZE(sfdp_bfpt_erases); i++) {
const struct sfdp_bfpt_erase *er = &sfdp_bfpt_erases[i];
u32 erasesize;
@@ -2288,18 +2706,25 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
erasesize = 1U << erasesize;
opcode = (half >> 8) & 0xff;
-#ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
- if (erasesize == SZ_4K) {
- nor->erase_opcode = opcode;
- mtd->erasesize = erasesize;
- break;
- }
-#endif
- if (!mtd->erasesize || mtd->erasesize < erasesize) {
- nor->erase_opcode = opcode;
- mtd->erasesize = erasesize;
- }
+ erase_mask |= BIT(i);
+ spi_nor_set_erase_settings_from_bfpt(&erase_type[i], erasesize,
+ opcode, i);
}
+ spi_nor_init_uniform_erase_map(map, erase_mask, params->size);
+ /*
+ * Sort all the map's Erase Types in ascending order with the smallest
+ * erase size being the first member in the erase_type array.
+ */
+ sort(erase_type, SNOR_ERASE_TYPE_MAX, sizeof(erase_type[0]),
+ spi_nor_map_cmp_erase_type, NULL);
+ /*
+ * Sort the erase types in the uniform region in order to update the
+ * uniform_erase_type bitmask. The bitmask will be used later on when
+ * selecting the uniform erase.
+ */
+ spi_nor_regions_sort_erase_types(map);
+ map->uniform_erase_type = map->uniform_region.offset &
+ SNOR_ERASE_TYPE_MASK;
/* Stop here if not JESD216 rev A or later. */
if (bfpt_header->length < BFPT_DWORD_MAX)
@@ -2341,6 +2766,277 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
return 0;
}
+#define SMPT_CMD_ADDRESS_LEN_MASK GENMASK(23, 22)
+#define SMPT_CMD_ADDRESS_LEN_0 (0x0UL << 22)
+#define SMPT_CMD_ADDRESS_LEN_3 (0x1UL << 22)
+#define SMPT_CMD_ADDRESS_LEN_4 (0x2UL << 22)
+#define SMPT_CMD_ADDRESS_LEN_USE_CURRENT (0x3UL << 22)
+
+#define SMPT_CMD_READ_DUMMY_MASK GENMASK(19, 16)
+#define SMPT_CMD_READ_DUMMY_SHIFT 16
+#define SMPT_CMD_READ_DUMMY(_cmd) \
+ (((_cmd) & SMPT_CMD_READ_DUMMY_MASK) >> SMPT_CMD_READ_DUMMY_SHIFT)
+#define SMPT_CMD_READ_DUMMY_IS_VARIABLE 0xfUL
+
+#define SMPT_CMD_READ_DATA_MASK GENMASK(31, 24)
+#define SMPT_CMD_READ_DATA_SHIFT 24
+#define SMPT_CMD_READ_DATA(_cmd) \
+ (((_cmd) & SMPT_CMD_READ_DATA_MASK) >> SMPT_CMD_READ_DATA_SHIFT)
+
+#define SMPT_CMD_OPCODE_MASK GENMASK(15, 8)
+#define SMPT_CMD_OPCODE_SHIFT 8
+#define SMPT_CMD_OPCODE(_cmd) \
+ (((_cmd) & SMPT_CMD_OPCODE_MASK) >> SMPT_CMD_OPCODE_SHIFT)
+
+#define SMPT_MAP_REGION_COUNT_MASK GENMASK(23, 16)
+#define SMPT_MAP_REGION_COUNT_SHIFT 16
+#define SMPT_MAP_REGION_COUNT(_header) \
+ ((((_header) & SMPT_MAP_REGION_COUNT_MASK) >> \
+ SMPT_MAP_REGION_COUNT_SHIFT) + 1)
+
+#define SMPT_MAP_ID_MASK GENMASK(15, 8)
+#define SMPT_MAP_ID_SHIFT 8
+#define SMPT_MAP_ID(_header) \
+ (((_header) & SMPT_MAP_ID_MASK) >> SMPT_MAP_ID_SHIFT)
+
+#define SMPT_MAP_REGION_SIZE_MASK GENMASK(31, 8)
+#define SMPT_MAP_REGION_SIZE_SHIFT 8
+#define SMPT_MAP_REGION_SIZE(_region) \
+ (((((_region) & SMPT_MAP_REGION_SIZE_MASK) >> \
+ SMPT_MAP_REGION_SIZE_SHIFT) + 1) * 256)
+
+#define SMPT_MAP_REGION_ERASE_TYPE_MASK GENMASK(3, 0)
+#define SMPT_MAP_REGION_ERASE_TYPE(_region) \
+ ((_region) & SMPT_MAP_REGION_ERASE_TYPE_MASK)
+
+#define SMPT_DESC_TYPE_MAP BIT(1)
+#define SMPT_DESC_END BIT(0)
+
+/**
+ * spi_nor_smpt_addr_width() - return the address width used in the
+ * configuration detection command.
+ * @nor: pointer to a 'struct spi_nor'
+ * @settings: configuration detection command descriptor, dword1
+ */
+static u8 spi_nor_smpt_addr_width(const struct spi_nor *nor, const u32 settings)
+{
+ switch (settings & SMPT_CMD_ADDRESS_LEN_MASK) {
+ case SMPT_CMD_ADDRESS_LEN_0:
+ return 0;
+ case SMPT_CMD_ADDRESS_LEN_3:
+ return 3;
+ case SMPT_CMD_ADDRESS_LEN_4:
+ return 4;
+ case SMPT_CMD_ADDRESS_LEN_USE_CURRENT:
+ /* fall through */
+ default:
+ return nor->addr_width;
+ }
+}
+
+/**
+ * spi_nor_smpt_read_dummy() - return the configuration detection command read
+ * latency, in clock cycles.
+ * @nor: pointer to a 'struct spi_nor'
+ * @settings: configuration detection command descriptor, dword1
+ *
+ * Return: the number of dummy cycles for an SMPT read
+ */
+static u8 spi_nor_smpt_read_dummy(const struct spi_nor *nor, const u32 settings)
+{
+ u8 read_dummy = SMPT_CMD_READ_DUMMY(settings);
+
+ if (read_dummy == SMPT_CMD_READ_DUMMY_IS_VARIABLE)
+ return nor->read_dummy;
+ return read_dummy;
+}
+
+/**
+ * spi_nor_get_map_in_use() - get the configuration map in use
+ * @nor: pointer to a 'struct spi_nor'
+ * @smpt: pointer to the sector map parameter table
+ */
+static const u32 *spi_nor_get_map_in_use(struct spi_nor *nor, const u32 *smpt)
+{
+ const u32 *ret = NULL;
+ u32 i, addr;
+ int err;
+ u8 addr_width, read_opcode, read_dummy;
+ u8 read_data_mask, data_byte, map_id;
+
+ addr_width = nor->addr_width;
+ read_dummy = nor->read_dummy;
+ read_opcode = nor->read_opcode;
+
+ map_id = 0;
+ i = 0;
+ /* Determine if there are any optional Detection Command Descriptors */
+ while (!(smpt[i] & SMPT_DESC_TYPE_MAP)) {
+ read_data_mask = SMPT_CMD_READ_DATA(smpt[i]);
+ nor->addr_width = spi_nor_smpt_addr_width(nor, smpt[i]);
+ nor->read_dummy = spi_nor_smpt_read_dummy(nor, smpt[i]);
+ nor->read_opcode = SMPT_CMD_OPCODE(smpt[i]);
+ addr = smpt[i + 1];
+
+ err = spi_nor_read_raw(nor, addr, 1, &data_byte);
+ if (err)
+ goto out;
+
+ /*
+ * Build an index value that is used to select the Sector Map
+ * Configuration that is currently in use.
+ */
+ map_id = map_id << 1 | !!(data_byte & read_data_mask);
+ i = i + 2;
+ }
+
+ /* Find the matching configuration map */
+ while (SMPT_MAP_ID(smpt[i]) != map_id) {
+ if (smpt[i] & SMPT_DESC_END)
+ goto out;
+ /* increment the table index to the next map */
+ i += SMPT_MAP_REGION_COUNT(smpt[i]) + 1;
+ }
+
+ ret = smpt + i;
+ /* fall through */
+out:
+ nor->addr_width = addr_width;
+ nor->read_dummy = read_dummy;
+ nor->read_opcode = read_opcode;
+ return ret;
+}
+
+/**
+ * spi_nor_region_check_overlay() - set overlay bit when the region is overlaid
+ * @region: pointer to a structure that describes a SPI NOR erase region
+ * @erase: pointer to a structure that describes a SPI NOR erase type
+ * @erase_type: erase type bitmask
+ */
+static void
+spi_nor_region_check_overlay(struct spi_nor_erase_region *region,
+ const struct spi_nor_erase_type *erase,
+ const u8 erase_type)
+{
+ int i;
+
+ for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) {
+ if (!(erase_type & BIT(i)))
+ continue;
+ if (region->size & erase[i].size_mask) {
+ spi_nor_region_mark_overlay(region);
+ return;
+ }
+ }
+}
+
+/**
+ * spi_nor_init_non_uniform_erase_map() - initialize the non-uniform erase map
+ * @nor: pointer to a 'struct spi_nor'
+ * @smpt: pointer to the sector map parameter table
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_init_non_uniform_erase_map(struct spi_nor *nor,
+ const u32 *smpt)
+{
+ struct spi_nor_erase_map *map = &nor->erase_map;
+ const struct spi_nor_erase_type *erase = map->erase_type;
+ struct spi_nor_erase_region *region;
+ u64 offset;
+ u32 region_count;
+ int i, j;
+ u8 erase_type;
+
+ region_count = SMPT_MAP_REGION_COUNT(*smpt);
+ /*
+ * The regions will be freed when the driver detaches from the
+ * device.
+ */
+ region = devm_kcalloc(nor->dev, region_count, sizeof(*region),
+ GFP_KERNEL);
+ if (!region)
+ return -ENOMEM;
+ map->regions = region;
+
+ map->uniform_erase_type = 0xff;
+ offset = 0;
+ /* Populate regions. */
+ for (i = 0; i < region_count; i++) {
+ j = i + 1; /* index for the region dword */
+ region[i].size = SMPT_MAP_REGION_SIZE(smpt[j]);
+ erase_type = SMPT_MAP_REGION_ERASE_TYPE(smpt[j]);
+ region[i].offset = offset | erase_type;
+
+ spi_nor_region_check_overlay(&region[i], erase, erase_type);
+
+ /*
+ * Save the erase types that are supported in all regions and
+ * can erase the entire flash memory.
+ */
+ map->uniform_erase_type &= erase_type;
+
+ offset = (region[i].offset & ~SNOR_ERASE_FLAGS_MASK) +
+ region[i].size;
+ }
+
+ spi_nor_region_mark_end(&region[i - 1]);
+
+ return 0;
+}
+
+/**
+ * spi_nor_parse_smpt() - parse Sector Map Parameter Table
+ * @nor: pointer to a 'struct spi_nor'
+ * @smpt_header: sector map parameter table header
+ *
+ * This table is optional, but when available, we parse it to identify the
+ * location and size of sectors within the main data array of the flash memory
+ * device and to identify which Erase Types are supported by each sector.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_parse_smpt(struct spi_nor *nor,
+ const struct sfdp_parameter_header *smpt_header)
+{
+ const u32 *sector_map;
+ u32 *smpt;
+ size_t len;
+ u32 addr;
+ int i, ret;
+
+ /* Read the Sector Map Parameter Table. */
+ len = smpt_header->length * sizeof(*smpt);
+ smpt = kzalloc(len, GFP_KERNEL);
+ if (!smpt)
+ return -ENOMEM;
+
+ addr = SFDP_PARAM_HEADER_PTP(smpt_header);
+ ret = spi_nor_read_sfdp(nor, addr, len, smpt);
+ if (ret)
+ goto out;
+
+ /* Fix endianness of the SMPT DWORDs. */
+ for (i = 0; i < smpt_header->length; i++)
+ smpt[i] = le32_to_cpu(smpt[i]);
+
+ sector_map = spi_nor_get_map_in_use(nor, smpt);
+ if (!sector_map) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = spi_nor_init_non_uniform_erase_map(nor, sector_map);
+ if (ret)
+ goto out;
+
+ spi_nor_regions_sort_erase_types(&nor->erase_map);
+ /* fall through */
+out:
+ kfree(smpt);
+ return ret;
+}
+
/**
* spi_nor_parse_sfdp() - parse the Serial Flash Discoverable Parameters.
* @nor: pointer to a 'struct spi_nor'
@@ -2435,7 +3131,7 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor,
switch (SFDP_PARAM_HEADER_ID(param_header)) {
case SFDP_SECTOR_MAP_ID:
- dev_info(dev, "non-uniform erase sector maps are not supported yet.\n");
+ err = spi_nor_parse_smpt(nor, param_header);
break;
default:
@@ -2455,6 +3151,9 @@ static int spi_nor_init_params(struct spi_nor *nor,
const struct flash_info *info,
struct spi_nor_flash_parameter *params)
{
+ struct spi_nor_erase_map *map = &nor->erase_map;
+ u8 i, erase_mask;
+
/* Set legacy flash parameters as default. */
memset(params, 0, sizeof(*params));
@@ -2494,6 +3193,28 @@ static int spi_nor_init_params(struct spi_nor *nor,
spi_nor_set_pp_settings(&params->page_programs[SNOR_CMD_PP],
SPINOR_OP_PP, SNOR_PROTO_1_1_1);
+ /*
+ * Sector Erase settings. Sort Erase Types in ascending order, with the
+ * smallest erase size starting at BIT(0).
+ */
+ erase_mask = 0;
+ i = 0;
+ if (info->flags & SECT_4K_PMC) {
+ erase_mask |= BIT(i);
+ spi_nor_set_erase_type(&map->erase_type[i], 4096u,
+ SPINOR_OP_BE_4K_PMC);
+ i++;
+ } else if (info->flags & SECT_4K) {
+ erase_mask |= BIT(i);
+ spi_nor_set_erase_type(&map->erase_type[i], 4096u,
+ SPINOR_OP_BE_4K);
+ i++;
+ }
+ erase_mask |= BIT(i);
+ spi_nor_set_erase_type(&map->erase_type[i], info->sector_size,
+ SPINOR_OP_SE);
+ spi_nor_init_uniform_erase_map(map, erase_mask, params->size);
+
/* Select the procedure to set the Quad Enable bit. */
if (params->hwcaps.mask & (SNOR_HWCAPS_READ_QUAD |
SNOR_HWCAPS_PP_QUAD)) {
@@ -2521,17 +3242,19 @@ static int spi_nor_init_params(struct spi_nor *nor,
params->quad_enable = info->quad_enable;
}
- /* Override the parameters with data read from SFDP tables. */
- nor->addr_width = 0;
- nor->mtd.erasesize = 0;
if ((info->flags & (SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)) &&
!(info->flags & SPI_NOR_SKIP_SFDP)) {
struct spi_nor_flash_parameter sfdp_params;
+ struct spi_nor_erase_map prev_map;
memcpy(&sfdp_params, params, sizeof(sfdp_params));
+ memcpy(&prev_map, &nor->erase_map, sizeof(prev_map));
+
if (spi_nor_parse_sfdp(nor, &sfdp_params)) {
nor->addr_width = 0;
- nor->mtd.erasesize = 0;
+ /* restore previous erase map */
+ memcpy(&nor->erase_map, &prev_map,
+ sizeof(nor->erase_map));
} else {
memcpy(params, &sfdp_params, sizeof(*params));
}
@@ -2643,29 +3366,103 @@ static int spi_nor_select_pp(struct spi_nor *nor,
return 0;
}
-static int spi_nor_select_erase(struct spi_nor *nor,
- const struct flash_info *info)
+/**
+ * spi_nor_select_uniform_erase() - select optimum uniform erase type
+ * @map: the erase map of the SPI NOR
+ * @wanted_size: the erase type size to search for. Contains the value of
+ * info->sector_size or of the "small sector" size in case
+ * CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is defined.
+ *
+ * Once the optimum uniform sector erase command is found, disable all the
+ * other.
+ *
+ * Return: pointer to erase type on success, NULL otherwise.
+ */
+static const struct spi_nor_erase_type *
+spi_nor_select_uniform_erase(struct spi_nor_erase_map *map,
+ const u32 wanted_size)
{
- struct mtd_info *mtd = &nor->mtd;
+ const struct spi_nor_erase_type *tested_erase, *erase = NULL;
+ int i;
+ u8 uniform_erase_type = map->uniform_erase_type;
- /* Do nothing if already configured from SFDP. */
- if (mtd->erasesize)
- return 0;
+ for (i = SNOR_ERASE_TYPE_MAX - 1; i >= 0; i--) {
+ if (!(uniform_erase_type & BIT(i)))
+ continue;
+
+ tested_erase = &map->erase_type[i];
+
+ /*
+ * If the current erase size is the one, stop here:
+ * we have found the right uniform Sector Erase command.
+ */
+ if (tested_erase->size == wanted_size) {
+ erase = tested_erase;
+ break;
+ }
+
+ /*
+ * Otherwise, the current erase size is still a valid canditate.
+ * Select the biggest valid candidate.
+ */
+ if (!erase && tested_erase->size)
+ erase = tested_erase;
+ /* keep iterating to find the wanted_size */
+ }
+
+ if (!erase)
+ return NULL;
+ /* Disable all other Sector Erase commands. */
+ map->uniform_erase_type &= ~SNOR_ERASE_TYPE_MASK;
+ map->uniform_erase_type |= BIT(erase - map->erase_type);
+ return erase;
+}
+
+static int spi_nor_select_erase(struct spi_nor *nor, u32 wanted_size)
+{
+ struct spi_nor_erase_map *map = &nor->erase_map;
+ const struct spi_nor_erase_type *erase = NULL;
+ struct mtd_info *mtd = &nor->mtd;
+ int i;
+
+ /*
+ * The previous implementation handling Sector Erase commands assumed
+ * that the SPI flash memory has an uniform layout then used only one
+ * of the supported erase sizes for all Sector Erase commands.
+ * So to be backward compatible, the new implementation also tries to
+ * manage the SPI flash memory as uniform with a single erase sector
+ * size, when possible.
+ */
#ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
/* prefer "small sector" erase if possible */
- if (info->flags & SECT_4K) {
- nor->erase_opcode = SPINOR_OP_BE_4K;
- mtd->erasesize = 4096;
- } else if (info->flags & SECT_4K_PMC) {
- nor->erase_opcode = SPINOR_OP_BE_4K_PMC;
- mtd->erasesize = 4096;
- } else
+ wanted_size = 4096u;
#endif
- {
- nor->erase_opcode = SPINOR_OP_SE;
- mtd->erasesize = info->sector_size;
+
+ if (spi_nor_has_uniform_erase(nor)) {
+ erase = spi_nor_select_uniform_erase(map, wanted_size);
+ if (!erase)
+ return -EINVAL;
+ nor->erase_opcode = erase->opcode;
+ mtd->erasesize = erase->size;
+ return 0;
}
+
+ /*
+ * For non-uniform SPI flash memory, set mtd->erasesize to the
+ * maximum erase sector size. No need to set nor->erase_opcode.
+ */
+ for (i = SNOR_ERASE_TYPE_MAX - 1; i >= 0; i--) {
+ if (map->erase_type[i].size) {
+ erase = &map->erase_type[i];
+ break;
+ }
+ }
+
+ if (!erase)
+ return -EINVAL;
+
+ mtd->erasesize = erase->size;
return 0;
}
@@ -2712,7 +3509,7 @@ static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info,
}
/* Select the Sector Erase command. */
- err = spi_nor_select_erase(nor, info);
+ err = spi_nor_select_erase(nor, info->sector_size);
if (err) {
dev_err(nor->dev,
"can't select erase settings supported by both the SPI controller and memory.\n");
diff --git a/drivers/mtd/tests/mtd_nandecctest.c b/drivers/mtd/tests/mtd_nandecctest.c
index 88b6c81cebbe..c71523e94580 100644
--- a/drivers/mtd/tests/mtd_nandecctest.c
+++ b/drivers/mtd/tests/mtd_nandecctest.c
@@ -121,8 +121,10 @@ static int no_bit_error_verify(void *error_data, void *error_ecc,
unsigned char calc_ecc[3];
int ret;
- __nand_calculate_ecc(error_data, size, calc_ecc);
- ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size);
+ __nand_calculate_ecc(error_data, size, calc_ecc,
+ IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
+ ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size,
+ IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
if (ret == 0 && !memcmp(correct_data, error_data, size))
return 0;
@@ -149,8 +151,10 @@ static int single_bit_error_correct(void *error_data, void *error_ecc,
unsigned char calc_ecc[3];
int ret;
- __nand_calculate_ecc(error_data, size, calc_ecc);
- ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size);
+ __nand_calculate_ecc(error_data, size, calc_ecc,
+ IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
+ ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size,
+ IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
if (ret == 1 && !memcmp(correct_data, error_data, size))
return 0;
@@ -184,8 +188,10 @@ static int double_bit_error_detect(void *error_data, void *error_ecc,
unsigned char calc_ecc[3];
int ret;
- __nand_calculate_ecc(error_data, size, calc_ecc);
- ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size);
+ __nand_calculate_ecc(error_data, size, calc_ecc,
+ IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
+ ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size,
+ IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
return (ret == -EBADMSG) ? 0 : -EINVAL;
}
@@ -259,7 +265,8 @@ static int nand_ecc_test_run(const size_t size)
}
prandom_bytes(correct_data, size);
- __nand_calculate_ecc(correct_data, size, correct_ecc);
+ __nand_calculate_ecc(correct_data, size, correct_ecc,
+ IS_ENABLED(CONFIG_MTD_NAND_ECC_SMC));
for (i = 0; i < ARRAY_SIZE(nand_ecc_test); i++) {
nand_ecc_test[i].prepare(error_data, error_ecc,
diff --git a/drivers/mtd/ubi/attach.c b/drivers/mtd/ubi/attach.c
index 93ceea4f27d5..e294d3986ba9 100644
--- a/drivers/mtd/ubi/attach.c
+++ b/drivers/mtd/ubi/attach.c
@@ -1072,6 +1072,7 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
* be a result of power cut during erasure.
*/
ai->maybe_bad_peb_count += 1;
+ /* fall through */
case UBI_IO_BAD_HDR:
/*
* If we're facing a bad VID header we have to drop *all*
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index d2a726654ff1..a4e3454133a4 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -1334,8 +1334,10 @@ static int bytes_str_to_int(const char *str)
switch (*endp) {
case 'G':
result *= 1024;
+ /* fall through */
case 'M':
result *= 1024;
+ /* fall through */
case 'K':
result *= 1024;
if (endp[1] == 'i' && endp[2] == 'B')
diff --git a/drivers/mux/adgs1408.c b/drivers/mux/adgs1408.c
index 0f7cf54e3234..89096f10f4c4 100644
--- a/drivers/mux/adgs1408.c
+++ b/drivers/mux/adgs1408.c
@@ -128,4 +128,4 @@ module_spi_driver(adgs1408_driver);
MODULE_AUTHOR("Mircea Caprioru <mircea.caprioru@analog.com>");
MODULE_DESCRIPTION("Analog Devices ADGS1408 MUX driver");
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mux/gpio.c b/drivers/mux/gpio.c
index 6fdd9316db8b..02c1f2c014e8 100644
--- a/drivers/mux/gpio.c
+++ b/drivers/mux/gpio.c
@@ -17,20 +17,18 @@
struct mux_gpio {
struct gpio_descs *gpios;
- int *val;
};
static int mux_gpio_set(struct mux_control *mux, int state)
{
struct mux_gpio *mux_gpio = mux_chip_priv(mux->chip);
- int i;
+ DECLARE_BITMAP(values, BITS_PER_TYPE(state));
- for (i = 0; i < mux_gpio->gpios->ndescs; i++)
- mux_gpio->val[i] = (state >> i) & 1;
+ values[0] = state;
gpiod_set_array_value_cansleep(mux_gpio->gpios->ndescs,
mux_gpio->gpios->desc,
- mux_gpio->val);
+ mux_gpio->gpios->info, values);
return 0;
}
@@ -58,13 +56,11 @@ static int mux_gpio_probe(struct platform_device *pdev)
if (pins < 0)
return pins;
- mux_chip = devm_mux_chip_alloc(dev, 1, sizeof(*mux_gpio) +
- pins * sizeof(*mux_gpio->val));
+ mux_chip = devm_mux_chip_alloc(dev, 1, sizeof(*mux_gpio));
if (IS_ERR(mux_chip))
return PTR_ERR(mux_chip);
mux_gpio = mux_chip_priv(mux_chip);
- mux_gpio->val = (int *)(mux_gpio + 1);
mux_chip->ops = &mux_gpio_ops;
mux_gpio->gpios = devm_gpiod_get_array(dev, "mux", GPIOD_OUT_LOW);
diff --git a/drivers/net/arcnet/arc-rimi.c b/drivers/net/arcnet/arc-rimi.c
index a07e24970be4..11c5bad95226 100644
--- a/drivers/net/arcnet/arc-rimi.c
+++ b/drivers/net/arcnet/arc-rimi.c
@@ -33,7 +33,7 @@
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
-#include <linux/bootmem.h>
+#include <linux/memblock.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
diff --git a/drivers/net/arcnet/com20020-isa.c b/drivers/net/arcnet/com20020-isa.c
index 38fa60ddaf2e..28510e33924f 100644
--- a/drivers/net/arcnet/com20020-isa.c
+++ b/drivers/net/arcnet/com20020-isa.c
@@ -38,7 +38,7 @@
#include <linux/netdevice.h>
#include <linux/init.h>
#include <linux/interrupt.h>
-#include <linux/bootmem.h>
+#include <linux/memblock.h>
#include <linux/io.h>
#include "arcdevice.h"
diff --git a/drivers/net/arcnet/com90io.c b/drivers/net/arcnet/com90io.c
index 4e56aaf2b984..2c546013a980 100644
--- a/drivers/net/arcnet/com90io.c
+++ b/drivers/net/arcnet/com90io.c
@@ -34,7 +34,7 @@
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
-#include <linux/bootmem.h>
+#include <linux/memblock.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 0d87e11e7f1d..333387f1f1fe 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -210,6 +210,7 @@ static void bond_get_stats(struct net_device *bond_dev,
static void bond_slave_arr_handler(struct work_struct *work);
static bool bond_time_in_interval(struct bonding *bond, unsigned long last_act,
int mod);
+static void bond_netdev_notify_work(struct work_struct *work);
/*---------------------------- General routines -----------------------------*/
@@ -962,7 +963,8 @@ static inline void slave_disable_netpoll(struct slave *slave)
return;
slave->np = NULL;
- __netpoll_free_async(np);
+
+ __netpoll_free(np);
}
static void bond_poll_controller(struct net_device *bond_dev)
@@ -1170,9 +1172,27 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb)
}
}
- /* don't change skb->dev for link-local packets */
- if (is_link_local_ether_addr(eth_hdr(skb)->h_dest))
+ /* Link-local multicast packets should be passed to the
+ * stack on the link they arrive as well as pass them to the
+ * bond-master device. These packets are mostly usable when
+ * stack receives it with the link on which they arrive
+ * (e.g. LLDP) they also must be available on master. Some of
+ * the use cases include (but are not limited to): LLDP agents
+ * that must be able to operate both on enslaved interfaces as
+ * well as on bonds themselves; linux bridges that must be able
+ * to process/pass BPDUs from attached bonds when any kind of
+ * STP version is enabled on the network.
+ */
+ if (is_link_local_ether_addr(eth_hdr(skb)->h_dest)) {
+ struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC);
+
+ if (nskb) {
+ nskb->dev = bond->dev;
+ nskb->queue_mapping = 0;
+ netif_rx(nskb);
+ }
return RX_HANDLER_PASS;
+ }
if (bond_should_deliver_exact_match(skb, slave, bond))
return RX_HANDLER_EXACT;
@@ -1269,6 +1289,8 @@ static struct slave *bond_alloc_slave(struct bonding *bond)
return NULL;
}
}
+ INIT_DELAYED_WORK(&slave->notify_work, bond_netdev_notify_work);
+
return slave;
}
@@ -1276,6 +1298,7 @@ static void bond_free_slave(struct slave *slave)
{
struct bonding *bond = bond_get_bond_by_slave(slave);
+ cancel_delayed_work_sync(&slave->notify_work);
if (BOND_MODE(bond) == BOND_MODE_8023AD)
kfree(SLAVE_AD_INFO(slave));
@@ -1297,39 +1320,26 @@ static void bond_fill_ifslave(struct slave *slave, struct ifslave *info)
info->link_failure_count = slave->link_failure_count;
}
-static void bond_netdev_notify(struct net_device *dev,
- struct netdev_bonding_info *info)
-{
- rtnl_lock();
- netdev_bonding_info_change(dev, info);
- rtnl_unlock();
-}
-
static void bond_netdev_notify_work(struct work_struct *_work)
{
- struct netdev_notify_work *w =
- container_of(_work, struct netdev_notify_work, work.work);
+ struct slave *slave = container_of(_work, struct slave,
+ notify_work.work);
+
+ if (rtnl_trylock()) {
+ struct netdev_bonding_info binfo;
- bond_netdev_notify(w->dev, &w->bonding_info);
- dev_put(w->dev);
- kfree(w);
+ bond_fill_ifslave(slave, &binfo.slave);
+ bond_fill_ifbond(slave->bond, &binfo.master);
+ netdev_bonding_info_change(slave->dev, &binfo);
+ rtnl_unlock();
+ } else {
+ queue_delayed_work(slave->bond->wq, &slave->notify_work, 1);
+ }
}
void bond_queue_slave_event(struct slave *slave)
{
- struct bonding *bond = slave->bond;
- struct netdev_notify_work *nnw = kzalloc(sizeof(*nnw), GFP_ATOMIC);
-
- if (!nnw)
- return;
-
- dev_hold(slave->dev);
- nnw->dev = slave->dev;
- bond_fill_ifslave(slave, &nnw->bonding_info.slave);
- bond_fill_ifbond(bond, &nnw->bonding_info.master);
- INIT_DELAYED_WORK(&nnw->work, bond_netdev_notify_work);
-
- queue_delayed_work(slave->bond->wq, &nnw->work, 0);
+ queue_delayed_work(slave->bond->wq, &slave->notify_work, 0);
}
void bond_lower_state_changed(struct slave *slave)
@@ -3102,13 +3112,13 @@ static int bond_slave_netdev_event(unsigned long event,
case NETDEV_CHANGE:
/* For 802.3ad mode only:
* Getting invalid Speed/Duplex values here will put slave
- * in weird state. So mark it as link-down for the time
+ * in weird state. So mark it as link-fail for the time
* being and let link-monitoring (miimon) set it right when
* correct speeds/duplex are available.
*/
if (bond_update_speed_duplex(slave) &&
BOND_MODE(bond) == BOND_MODE_8023AD)
- slave->link = BOND_LINK_DOWN;
+ slave->link = BOND_LINK_FAIL;
if (BOND_MODE(bond) == BOND_MODE_8023AD)
bond_3ad_adapter_speed_duplex_changed(slave);
diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c
index 9697977b80f0..6b9ad8673218 100644
--- a/drivers/net/bonding/bond_netlink.c
+++ b/drivers/net/bonding/bond_netlink.c
@@ -638,8 +638,7 @@ static int bond_fill_info(struct sk_buff *skb,
goto nla_put_failure;
if (nla_put(skb, IFLA_BOND_AD_ACTOR_SYSTEM,
- sizeof(bond->params.ad_actor_system),
- &bond->params.ad_actor_system))
+ ETH_ALEN, &bond->params.ad_actor_system))
goto nla_put_failure;
}
if (!bond_3ad_get_active_agg_info(bond, &info)) {
diff --git a/drivers/net/can/rx-offload.c b/drivers/net/can/rx-offload.c
index d94dae216820..c7d05027a7a0 100644
--- a/drivers/net/can/rx-offload.c
+++ b/drivers/net/can/rx-offload.c
@@ -79,7 +79,7 @@ static int can_rx_offload_napi_poll(struct napi_struct *napi, int quota)
static inline void __skb_queue_add_sort(struct sk_buff_head *head, struct sk_buff *new,
int (*compare)(struct sk_buff *a, struct sk_buff *b))
{
- struct sk_buff *pos, *insert = (struct sk_buff *)head;
+ struct sk_buff *pos, *insert = NULL;
skb_queue_reverse_walk(head, pos) {
const struct can_rx_offload_cb *cb_pos, *cb_new;
@@ -99,8 +99,10 @@ static inline void __skb_queue_add_sort(struct sk_buff_head *head, struct sk_buf
insert = pos;
break;
}
-
- __skb_queue_after(head, insert, new);
+ if (!insert)
+ __skb_queue_head(head, new);
+ else
+ __skb_queue_after(head, insert, new);
}
static int can_rx_offload_compare(struct sk_buff *a, struct sk_buff *b)
diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig
index d3ce1e4cb4d3..71bb3aebded4 100644
--- a/drivers/net/dsa/Kconfig
+++ b/drivers/net/dsa/Kconfig
@@ -23,6 +23,14 @@ config NET_DSA_LOOP
This enables support for a fake mock-up switch chip which
exercises the DSA APIs.
+config NET_DSA_LANTIQ_GSWIP
+ tristate "Lantiq / Intel GSWIP"
+ depends on HAS_IOMEM && NET_DSA
+ select NET_DSA_TAG_GSWIP
+ ---help---
+ This enables support for the Lantiq / Intel GSWIP 2.1 found in
+ the xrx200 / VR9 SoC.
+
config NET_DSA_MT7530
tristate "Mediatek MT7530 Ethernet switch support"
depends on NET_DSA
diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile
index 46c1cba91ffe..82e5d794c41f 100644
--- a/drivers/net/dsa/Makefile
+++ b/drivers/net/dsa/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_NET_DSA_LOOP) += dsa_loop.o
ifdef CONFIG_NET_DSA_LOOP
obj-$(CONFIG_FIXED_PHY) += dsa_loop_bdinfo.o
endif
+obj-$(CONFIG_NET_DSA_LANTIQ_GSWIP) += lantiq_gswip.o
obj-$(CONFIG_NET_DSA_MT7530) += mt7530.o
obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o
obj-$(CONFIG_NET_DSA_QCA8K) += qca8k.o
diff --git a/drivers/net/dsa/b53/Kconfig b/drivers/net/dsa/b53/Kconfig
index 2f988216dab9..d32469283f97 100644
--- a/drivers/net/dsa/b53/Kconfig
+++ b/drivers/net/dsa/b53/Kconfig
@@ -23,6 +23,7 @@ config B53_MDIO_DRIVER
config B53_MMAP_DRIVER
tristate "B53 MMAP connected switch driver"
depends on B53 && HAS_IOMEM
+ default BCM63XX || BMIPS_GENERIC
help
Select to enable support for memory-mapped switches like the BCM63XX
integrated switches.
@@ -30,6 +31,15 @@ config B53_MMAP_DRIVER
config B53_SRAB_DRIVER
tristate "B53 SRAB connected switch driver"
depends on B53 && HAS_IOMEM
+ depends on B53_SERDES || !B53_SERDES
+ default ARCH_BCM_IPROC
help
Select to enable support for memory-mapped Switch Register Access
Bridge Registers (SRAB) like it is found on the BCM53010
+
+config B53_SERDES
+ tristate "B53 SerDes support"
+ depends on B53
+ default ARCH_BCM_NSP
+ help
+ Select to enable support for SerDes on e.g: Northstar Plus SoCs.
diff --git a/drivers/net/dsa/b53/Makefile b/drivers/net/dsa/b53/Makefile
index 4256fb42a4dd..b1be13023ae4 100644
--- a/drivers/net/dsa/b53/Makefile
+++ b/drivers/net/dsa/b53/Makefile
@@ -5,3 +5,4 @@ obj-$(CONFIG_B53_SPI_DRIVER) += b53_spi.o
obj-$(CONFIG_B53_MDIO_DRIVER) += b53_mdio.o
obj-$(CONFIG_B53_MMAP_DRIVER) += b53_mmap.o
obj-$(CONFIG_B53_SRAB_DRIVER) += b53_srab.o
+obj-$(CONFIG_B53_SERDES) += b53_serdes.o
diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c
index d93c790bfbe8..0e4bbdcc614f 100644
--- a/drivers/net/dsa/b53/b53_common.c
+++ b/drivers/net/dsa/b53/b53_common.c
@@ -26,6 +26,7 @@
#include <linux/module.h>
#include <linux/platform_data/b53.h>
#include <linux/phy.h>
+#include <linux/phylink.h>
#include <linux/etherdevice.h>
#include <linux/if_bridge.h>
#include <net/dsa.h>
@@ -502,8 +503,14 @@ int b53_enable_port(struct dsa_switch *ds, int port, struct phy_device *phy)
{
struct b53_device *dev = ds->priv;
unsigned int cpu_port = ds->ports[port].cpu_dp->index;
+ int ret = 0;
u16 pvlan;
+ if (dev->ops->irq_enable)
+ ret = dev->ops->irq_enable(dev, port);
+ if (ret)
+ return ret;
+
/* Clear the Rx and Tx disable bits and set to no spanning tree */
b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(port), 0);
@@ -536,6 +543,9 @@ void b53_disable_port(struct dsa_switch *ds, int port, struct phy_device *phy)
b53_read8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(port), &reg);
reg |= PORT_CTRL_RX_DISABLE | PORT_CTRL_TX_DISABLE;
b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(port), reg);
+
+ if (dev->ops->irq_disable)
+ dev->ops->irq_disable(dev, port);
}
EXPORT_SYMBOL(b53_disable_port);
@@ -755,6 +765,8 @@ static int b53_reset_switch(struct b53_device *priv)
memset(priv->vlans, 0, sizeof(*priv->vlans) * priv->num_vlans);
memset(priv->ports, 0, sizeof(*priv->ports) * priv->num_ports);
+ priv->serdes_lane = B53_INVALID_LANE;
+
return b53_switch_reset(priv);
}
@@ -938,33 +950,50 @@ static int b53_setup(struct dsa_switch *ds)
return ret;
}
-static void b53_adjust_link(struct dsa_switch *ds, int port,
- struct phy_device *phydev)
+static void b53_force_link(struct b53_device *dev, int port, int link)
{
- struct b53_device *dev = ds->priv;
- struct ethtool_eee *p = &dev->ports[port].eee;
- u8 rgmii_ctrl = 0, reg = 0, off;
-
- if (!phy_is_pseudo_fixed_link(phydev))
- return;
+ u8 reg, val, off;
/* Override the port settings */
if (port == dev->cpu_port) {
off = B53_PORT_OVERRIDE_CTRL;
- reg = PORT_OVERRIDE_EN;
+ val = PORT_OVERRIDE_EN;
} else {
off = B53_GMII_PORT_OVERRIDE_CTRL(port);
- reg = GMII_PO_EN;
+ val = GMII_PO_EN;
}
- /* Set the link UP */
- if (phydev->link)
+ b53_read8(dev, B53_CTRL_PAGE, off, &reg);
+ reg |= val;
+ if (link)
reg |= PORT_OVERRIDE_LINK;
+ else
+ reg &= ~PORT_OVERRIDE_LINK;
+ b53_write8(dev, B53_CTRL_PAGE, off, reg);
+}
- if (phydev->duplex == DUPLEX_FULL)
+static void b53_force_port_config(struct b53_device *dev, int port,
+ int speed, int duplex, int pause)
+{
+ u8 reg, val, off;
+
+ /* Override the port settings */
+ if (port == dev->cpu_port) {
+ off = B53_PORT_OVERRIDE_CTRL;
+ val = PORT_OVERRIDE_EN;
+ } else {
+ off = B53_GMII_PORT_OVERRIDE_CTRL(port);
+ val = GMII_PO_EN;
+ }
+
+ b53_read8(dev, B53_CTRL_PAGE, off, &reg);
+ reg |= val;
+ if (duplex == DUPLEX_FULL)
reg |= PORT_OVERRIDE_FULL_DUPLEX;
+ else
+ reg &= ~PORT_OVERRIDE_FULL_DUPLEX;
- switch (phydev->speed) {
+ switch (speed) {
case 2000:
reg |= PORT_OVERRIDE_SPEED_2000M;
/* fallthrough */
@@ -978,21 +1007,41 @@ static void b53_adjust_link(struct dsa_switch *ds, int port,
reg |= PORT_OVERRIDE_SPEED_10M;
break;
default:
- dev_err(ds->dev, "unknown speed: %d\n", phydev->speed);
+ dev_err(dev->dev, "unknown speed: %d\n", speed);
return;
}
+ if (pause & MLO_PAUSE_RX)
+ reg |= PORT_OVERRIDE_RX_FLOW;
+ if (pause & MLO_PAUSE_TX)
+ reg |= PORT_OVERRIDE_TX_FLOW;
+
+ b53_write8(dev, B53_CTRL_PAGE, off, reg);
+}
+
+static void b53_adjust_link(struct dsa_switch *ds, int port,
+ struct phy_device *phydev)
+{
+ struct b53_device *dev = ds->priv;
+ struct ethtool_eee *p = &dev->ports[port].eee;
+ u8 rgmii_ctrl = 0, reg = 0, off;
+ int pause = 0;
+
+ if (!phy_is_pseudo_fixed_link(phydev))
+ return;
+
/* Enable flow control on BCM5301x's CPU port */
if (is5301x(dev) && port == dev->cpu_port)
- reg |= PORT_OVERRIDE_RX_FLOW | PORT_OVERRIDE_TX_FLOW;
+ pause = MLO_PAUSE_TXRX_MASK;
if (phydev->pause) {
if (phydev->asym_pause)
- reg |= PORT_OVERRIDE_TX_FLOW;
- reg |= PORT_OVERRIDE_RX_FLOW;
+ pause |= MLO_PAUSE_TX;
+ pause |= MLO_PAUSE_RX;
}
- b53_write8(dev, B53_CTRL_PAGE, off, reg);
+ b53_force_port_config(dev, port, phydev->speed, phydev->duplex, pause);
+ b53_force_link(dev, port, phydev->link);
if (is531x5(dev) && phy_interface_is_rgmii(phydev)) {
if (port == 8)
@@ -1052,16 +1101,9 @@ static void b53_adjust_link(struct dsa_switch *ds, int port,
}
} else if (is5301x(dev)) {
if (port != dev->cpu_port) {
- u8 po_reg = B53_GMII_PORT_OVERRIDE_CTRL(dev->cpu_port);
- u8 gmii_po;
-
- b53_read8(dev, B53_CTRL_PAGE, po_reg, &gmii_po);
- gmii_po |= GMII_PO_LINK |
- GMII_PO_RX_FLOW |
- GMII_PO_TX_FLOW |
- GMII_PO_EN |
- GMII_PO_SPEED_2000M;
- b53_write8(dev, B53_CTRL_PAGE, po_reg, gmii_po);
+ b53_force_port_config(dev, dev->cpu_port, 2000,
+ DUPLEX_FULL, MLO_PAUSE_TXRX_MASK);
+ b53_force_link(dev, dev->cpu_port, 1);
}
}
@@ -1069,6 +1111,148 @@ static void b53_adjust_link(struct dsa_switch *ds, int port,
p->eee_enabled = b53_eee_init(ds, port, phydev);
}
+void b53_port_event(struct dsa_switch *ds, int port)
+{
+ struct b53_device *dev = ds->priv;
+ bool link;
+ u16 sts;
+
+ b53_read16(dev, B53_STAT_PAGE, B53_LINK_STAT, &sts);
+ link = !!(sts & BIT(port));
+ dsa_port_phylink_mac_change(ds, port, link);
+}
+EXPORT_SYMBOL(b53_port_event);
+
+void b53_phylink_validate(struct dsa_switch *ds, int port,
+ unsigned long *supported,
+ struct phylink_link_state *state)
+{
+ struct b53_device *dev = ds->priv;
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
+
+ if (dev->ops->serdes_phylink_validate)
+ dev->ops->serdes_phylink_validate(dev, port, mask, state);
+
+ /* Allow all the expected bits */
+ phylink_set(mask, Autoneg);
+ phylink_set_port_modes(mask);
+ phylink_set(mask, Pause);
+ phylink_set(mask, Asym_Pause);
+
+ /* With the exclusion of 5325/5365, MII, Reverse MII and 802.3z, we
+ * support Gigabit, including Half duplex.
+ */
+ if (state->interface != PHY_INTERFACE_MODE_MII &&
+ state->interface != PHY_INTERFACE_MODE_REVMII &&
+ !phy_interface_mode_is_8023z(state->interface) &&
+ !(is5325(dev) || is5365(dev))) {
+ phylink_set(mask, 1000baseT_Full);
+ phylink_set(mask, 1000baseT_Half);
+ }
+
+ if (!phy_interface_mode_is_8023z(state->interface)) {
+ 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);
+
+ phylink_helper_basex_speed(state);
+}
+EXPORT_SYMBOL(b53_phylink_validate);
+
+int b53_phylink_mac_link_state(struct dsa_switch *ds, int port,
+ struct phylink_link_state *state)
+{
+ struct b53_device *dev = ds->priv;
+ int ret = -EOPNOTSUPP;
+
+ if ((phy_interface_mode_is_8023z(state->interface) ||
+ state->interface == PHY_INTERFACE_MODE_SGMII) &&
+ dev->ops->serdes_link_state)
+ ret = dev->ops->serdes_link_state(dev, port, state);
+
+ return ret;
+}
+EXPORT_SYMBOL(b53_phylink_mac_link_state);
+
+void b53_phylink_mac_config(struct dsa_switch *ds, int port,
+ unsigned int mode,
+ const struct phylink_link_state *state)
+{
+ struct b53_device *dev = ds->priv;
+
+ if (mode == MLO_AN_PHY)
+ return;
+
+ if (mode == MLO_AN_FIXED) {
+ b53_force_port_config(dev, port, state->speed,
+ state->duplex, state->pause);
+ return;
+ }
+
+ if ((phy_interface_mode_is_8023z(state->interface) ||
+ state->interface == PHY_INTERFACE_MODE_SGMII) &&
+ dev->ops->serdes_config)
+ dev->ops->serdes_config(dev, port, mode, state);
+}
+EXPORT_SYMBOL(b53_phylink_mac_config);
+
+void b53_phylink_mac_an_restart(struct dsa_switch *ds, int port)
+{
+ struct b53_device *dev = ds->priv;
+
+ if (dev->ops->serdes_an_restart)
+ dev->ops->serdes_an_restart(dev, port);
+}
+EXPORT_SYMBOL(b53_phylink_mac_an_restart);
+
+void b53_phylink_mac_link_down(struct dsa_switch *ds, int port,
+ unsigned int mode,
+ phy_interface_t interface)
+{
+ struct b53_device *dev = ds->priv;
+
+ if (mode == MLO_AN_PHY)
+ return;
+
+ if (mode == MLO_AN_FIXED) {
+ b53_force_link(dev, port, false);
+ return;
+ }
+
+ if (phy_interface_mode_is_8023z(interface) &&
+ dev->ops->serdes_link_set)
+ dev->ops->serdes_link_set(dev, port, mode, interface, false);
+}
+EXPORT_SYMBOL(b53_phylink_mac_link_down);
+
+void b53_phylink_mac_link_up(struct dsa_switch *ds, int port,
+ unsigned int mode,
+ phy_interface_t interface,
+ struct phy_device *phydev)
+{
+ struct b53_device *dev = ds->priv;
+
+ if (mode == MLO_AN_PHY)
+ return;
+
+ if (mode == MLO_AN_FIXED) {
+ b53_force_link(dev, port, true);
+ return;
+ }
+
+ if (phy_interface_mode_is_8023z(interface) &&
+ dev->ops->serdes_link_set)
+ dev->ops->serdes_link_set(dev, port, mode, interface, true);
+}
+EXPORT_SYMBOL(b53_phylink_mac_link_up);
+
int b53_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering)
{
return 0;
@@ -1107,7 +1291,7 @@ void b53_vlan_add(struct dsa_switch *ds, int port,
b53_get_vlan_entry(dev, vid, vl);
vl->members |= BIT(port);
- if (untagged)
+ if (untagged && !dsa_is_cpu_port(ds, port))
vl->untag |= BIT(port);
else
vl->untag &= ~BIT(port);
@@ -1149,7 +1333,7 @@ int b53_vlan_del(struct dsa_switch *ds, int port,
pvid = 0;
}
- if (untagged)
+ if (untagged && !dsa_is_cpu_port(ds, port))
vl->untag &= ~(BIT(port));
b53_set_vlan_entry(dev, vid, vl);
@@ -1710,6 +1894,12 @@ static const struct dsa_switch_ops b53_switch_ops = {
.phy_read = b53_phy_read16,
.phy_write = b53_phy_write16,
.adjust_link = b53_adjust_link,
+ .phylink_validate = b53_phylink_validate,
+ .phylink_mac_link_state = b53_phylink_mac_link_state,
+ .phylink_mac_config = b53_phylink_mac_config,
+ .phylink_mac_an_restart = b53_phylink_mac_an_restart,
+ .phylink_mac_link_down = b53_phylink_mac_link_down,
+ .phylink_mac_link_up = b53_phylink_mac_link_up,
.port_enable = b53_enable_port,
.port_disable = b53_disable_port,
.get_mac_eee = b53_get_mac_eee,
diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h
index df149756c282..ec796482792d 100644
--- a/drivers/net/dsa/b53/b53_priv.h
+++ b/drivers/net/dsa/b53/b53_priv.h
@@ -29,6 +29,7 @@
struct b53_device;
struct net_device;
+struct phylink_link_state;
struct b53_io_ops {
int (*read8)(struct b53_device *dev, u8 page, u8 reg, u8 *value);
@@ -43,8 +44,25 @@ struct b53_io_ops {
int (*write64)(struct b53_device *dev, u8 page, u8 reg, u64 value);
int (*phy_read16)(struct b53_device *dev, int addr, int reg, u16 *value);
int (*phy_write16)(struct b53_device *dev, int addr, int reg, u16 value);
+ int (*irq_enable)(struct b53_device *dev, int port);
+ void (*irq_disable)(struct b53_device *dev, int port);
+ u8 (*serdes_map_lane)(struct b53_device *dev, int port);
+ int (*serdes_link_state)(struct b53_device *dev, int port,
+ struct phylink_link_state *state);
+ void (*serdes_config)(struct b53_device *dev, int port,
+ unsigned int mode,
+ const struct phylink_link_state *state);
+ void (*serdes_an_restart)(struct b53_device *dev, int port);
+ void (*serdes_link_set)(struct b53_device *dev, int port,
+ unsigned int mode, phy_interface_t interface,
+ bool link_up);
+ void (*serdes_phylink_validate)(struct b53_device *dev, int port,
+ unsigned long *supported,
+ struct phylink_link_state *state);
};
+#define B53_INVALID_LANE 0xff
+
enum {
BCM5325_DEVICE_ID = 0x25,
BCM5365_DEVICE_ID = 0x65,
@@ -107,6 +125,7 @@ struct b53_device {
/* connect specific data */
u8 current_page;
struct device *dev;
+ u8 serdes_lane;
/* Master MDIO bus we got probed from */
struct mii_bus *bus;
@@ -298,6 +317,23 @@ int b53_br_join(struct dsa_switch *ds, int port, struct net_device *bridge);
void b53_br_leave(struct dsa_switch *ds, int port, struct net_device *bridge);
void b53_br_set_stp_state(struct dsa_switch *ds, int port, u8 state);
void b53_br_fast_age(struct dsa_switch *ds, int port);
+void b53_port_event(struct dsa_switch *ds, int port);
+void b53_phylink_validate(struct dsa_switch *ds, int port,
+ unsigned long *supported,
+ struct phylink_link_state *state);
+int b53_phylink_mac_link_state(struct dsa_switch *ds, int port,
+ struct phylink_link_state *state);
+void b53_phylink_mac_config(struct dsa_switch *ds, int port,
+ unsigned int mode,
+ const struct phylink_link_state *state);
+void b53_phylink_mac_an_restart(struct dsa_switch *ds, int port);
+void b53_phylink_mac_link_down(struct dsa_switch *ds, int port,
+ unsigned int mode,
+ phy_interface_t interface);
+void b53_phylink_mac_link_up(struct dsa_switch *ds, int port,
+ unsigned int mode,
+ phy_interface_t interface,
+ struct phy_device *phydev);
int b53_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering);
int b53_vlan_prepare(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_vlan *vlan);
diff --git a/drivers/net/dsa/b53/b53_serdes.c b/drivers/net/dsa/b53/b53_serdes.c
new file mode 100644
index 000000000000..629bf14128a2
--- /dev/null
+++ b/drivers/net/dsa/b53/b53_serdes.c
@@ -0,0 +1,214 @@
+// SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause
+/*
+ * Northstar Plus switch SerDes/SGMII PHY main logic
+ *
+ * Copyright (C) 2018 Florian Fainelli <f.fainelli@gmail.com>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/phy.h>
+#include <linux/phylink.h>
+#include <net/dsa.h>
+
+#include "b53_priv.h"
+#include "b53_serdes.h"
+#include "b53_regs.h"
+
+static void b53_serdes_write_blk(struct b53_device *dev, u8 offset, u16 block,
+ u16 value)
+{
+ b53_write16(dev, B53_SERDES_PAGE, B53_SERDES_BLKADDR, block);
+ b53_write16(dev, B53_SERDES_PAGE, offset, value);
+}
+
+static u16 b53_serdes_read_blk(struct b53_device *dev, u8 offset, u16 block)
+{
+ u16 value;
+
+ b53_write16(dev, B53_SERDES_PAGE, B53_SERDES_BLKADDR, block);
+ b53_read16(dev, B53_SERDES_PAGE, offset, &value);
+
+ return value;
+}
+
+static void b53_serdes_set_lane(struct b53_device *dev, u8 lane)
+{
+ if (dev->serdes_lane == lane)
+ return;
+
+ WARN_ON(lane > 1);
+
+ b53_serdes_write_blk(dev, B53_SERDES_LANE,
+ SERDES_XGXSBLK0_BLOCKADDRESS, lane);
+ dev->serdes_lane = lane;
+}
+
+static void b53_serdes_write(struct b53_device *dev, u8 lane,
+ u8 offset, u16 block, u16 value)
+{
+ b53_serdes_set_lane(dev, lane);
+ b53_serdes_write_blk(dev, offset, block, value);
+}
+
+static u16 b53_serdes_read(struct b53_device *dev, u8 lane,
+ u8 offset, u16 block)
+{
+ b53_serdes_set_lane(dev, lane);
+ return b53_serdes_read_blk(dev, offset, block);
+}
+
+void b53_serdes_config(struct b53_device *dev, int port, unsigned int mode,
+ const struct phylink_link_state *state)
+{
+ u8 lane = b53_serdes_map_lane(dev, port);
+ u16 reg;
+
+ if (lane == B53_INVALID_LANE)
+ return;
+
+ reg = b53_serdes_read(dev, lane, B53_SERDES_DIGITAL_CONTROL(1),
+ SERDES_DIGITAL_BLK);
+ if (state->interface == PHY_INTERFACE_MODE_1000BASEX)
+ reg |= FIBER_MODE_1000X;
+ else
+ reg &= ~FIBER_MODE_1000X;
+ b53_serdes_write(dev, lane, B53_SERDES_DIGITAL_CONTROL(1),
+ SERDES_DIGITAL_BLK, reg);
+}
+EXPORT_SYMBOL(b53_serdes_config);
+
+void b53_serdes_an_restart(struct b53_device *dev, int port)
+{
+ u8 lane = b53_serdes_map_lane(dev, port);
+ u16 reg;
+
+ if (lane == B53_INVALID_LANE)
+ return;
+
+ reg = b53_serdes_read(dev, lane, B53_SERDES_MII_REG(MII_BMCR),
+ SERDES_MII_BLK);
+ reg |= BMCR_ANRESTART;
+ b53_serdes_write(dev, lane, B53_SERDES_MII_REG(MII_BMCR),
+ SERDES_MII_BLK, reg);
+}
+EXPORT_SYMBOL(b53_serdes_an_restart);
+
+int b53_serdes_link_state(struct b53_device *dev, int port,
+ struct phylink_link_state *state)
+{
+ u8 lane = b53_serdes_map_lane(dev, port);
+ u16 dig, bmsr;
+
+ if (lane == B53_INVALID_LANE)
+ return 1;
+
+ dig = b53_serdes_read(dev, lane, B53_SERDES_DIGITAL_STATUS,
+ SERDES_DIGITAL_BLK);
+ bmsr = b53_serdes_read(dev, lane, B53_SERDES_MII_REG(MII_BMSR),
+ SERDES_MII_BLK);
+
+ switch ((dig >> SPEED_STATUS_SHIFT) & SPEED_STATUS_MASK) {
+ case SPEED_STATUS_10:
+ state->speed = SPEED_10;
+ break;
+ case SPEED_STATUS_100:
+ state->speed = SPEED_100;
+ break;
+ case SPEED_STATUS_1000:
+ state->speed = SPEED_1000;
+ break;
+ default:
+ case SPEED_STATUS_2500:
+ state->speed = SPEED_2500;
+ break;
+ }
+
+ state->duplex = dig & DUPLEX_STATUS ? DUPLEX_FULL : DUPLEX_HALF;
+ state->an_complete = !!(bmsr & BMSR_ANEGCOMPLETE);
+ state->link = !!(dig & LINK_STATUS);
+ if (dig & PAUSE_RESOLUTION_RX_SIDE)
+ state->pause |= MLO_PAUSE_RX;
+ if (dig & PAUSE_RESOLUTION_TX_SIDE)
+ state->pause |= MLO_PAUSE_TX;
+
+ return 0;
+}
+EXPORT_SYMBOL(b53_serdes_link_state);
+
+void b53_serdes_link_set(struct b53_device *dev, int port, unsigned int mode,
+ phy_interface_t interface, bool link_up)
+{
+ u8 lane = b53_serdes_map_lane(dev, port);
+ u16 reg;
+
+ if (lane == B53_INVALID_LANE)
+ return;
+
+ reg = b53_serdes_read(dev, lane, B53_SERDES_MII_REG(MII_BMCR),
+ SERDES_MII_BLK);
+ if (link_up)
+ reg &= ~BMCR_PDOWN;
+ else
+ reg |= BMCR_PDOWN;
+ b53_serdes_write(dev, lane, B53_SERDES_MII_REG(MII_BMCR),
+ SERDES_MII_BLK, reg);
+}
+EXPORT_SYMBOL(b53_serdes_link_set);
+
+void b53_serdes_phylink_validate(struct b53_device *dev, int port,
+ unsigned long *supported,
+ struct phylink_link_state *state)
+{
+ u8 lane = b53_serdes_map_lane(dev, port);
+
+ if (lane == B53_INVALID_LANE)
+ return;
+
+ switch (lane) {
+ case 0:
+ phylink_set(supported, 2500baseX_Full);
+ /* fallthrough */
+ case 1:
+ phylink_set(supported, 1000baseX_Full);
+ break;
+ default:
+ break;
+ }
+}
+EXPORT_SYMBOL(b53_serdes_phylink_validate);
+
+int b53_serdes_init(struct b53_device *dev, int port)
+{
+ u8 lane = b53_serdes_map_lane(dev, port);
+ u16 id0, msb, lsb;
+
+ if (lane == B53_INVALID_LANE)
+ return -EINVAL;
+
+ id0 = b53_serdes_read(dev, lane, B53_SERDES_ID0, SERDES_ID0);
+ msb = b53_serdes_read(dev, lane, B53_SERDES_MII_REG(MII_PHYSID1),
+ SERDES_MII_BLK);
+ lsb = b53_serdes_read(dev, lane, B53_SERDES_MII_REG(MII_PHYSID2),
+ SERDES_MII_BLK);
+ if (id0 == 0 || id0 == 0xffff) {
+ dev_err(dev->dev, "SerDes not initialized, check settings\n");
+ return -ENODEV;
+ }
+
+ dev_info(dev->dev,
+ "SerDes lane %d, model: %d, rev %c%d (OUI: 0x%08x)\n",
+ lane, id0 & SERDES_ID0_MODEL_MASK,
+ (id0 >> SERDES_ID0_REV_LETTER_SHIFT) + 0x41,
+ (id0 >> SERDES_ID0_REV_NUM_SHIFT) & SERDES_ID0_REV_NUM_MASK,
+ (u32)msb << 16 | lsb);
+
+ return 0;
+}
+EXPORT_SYMBOL(b53_serdes_init);
+
+MODULE_AUTHOR("Florian Fainelli <f.fainelli@gmail.com>");
+MODULE_DESCRIPTION("B53 Switch SerDes driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/dsa/b53/b53_serdes.h b/drivers/net/dsa/b53/b53_serdes.h
new file mode 100644
index 000000000000..3bb4f91aec9e
--- /dev/null
+++ b/drivers/net/dsa/b53/b53_serdes.h
@@ -0,0 +1,128 @@
+/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause
+ *
+ * Northstar Plus switch SerDes/SGMII PHY definitions
+ *
+ * Copyright (C) 2018 Florian Fainelli <f.fainelli@gmail.com>
+ */
+
+#include <linux/phy.h>
+#include <linux/types.h>
+
+/* Non-standard page used to access SerDes PHY registers on NorthStar Plus */
+#define B53_SERDES_PAGE 0x16
+#define B53_SERDES_BLKADDR 0x3e
+#define B53_SERDES_LANE 0x3c
+
+#define B53_SERDES_ID0 0x20
+#define SERDES_ID0_MODEL_MASK 0x3f
+#define SERDES_ID0_REV_NUM_SHIFT 11
+#define SERDES_ID0_REV_NUM_MASK 0x7
+#define SERDES_ID0_REV_LETTER_SHIFT 14
+
+#define B53_SERDES_MII_REG(x) (0x20 + (x) * 2)
+#define B53_SERDES_DIGITAL_CONTROL(x) (0x1e + (x) * 2)
+#define B53_SERDES_DIGITAL_STATUS 0x28
+
+/* SERDES_DIGITAL_CONTROL1 */
+#define FIBER_MODE_1000X BIT(0)
+#define TBI_INTERFACE BIT(1)
+#define SIGNAL_DETECT_EN BIT(2)
+#define INVERT_SIGNAL_DETECT BIT(3)
+#define AUTODET_EN BIT(4)
+#define SGMII_MASTER_MODE BIT(5)
+#define DISABLE_DLL_PWRDOWN BIT(6)
+#define CRC_CHECKER_DIS BIT(7)
+#define COMMA_DET_EN BIT(8)
+#define ZERO_COMMA_DET_EN BIT(9)
+#define REMOTE_LOOPBACK BIT(10)
+#define SEL_RX_PKTS_FOR_CNTR BIT(11)
+#define MASTER_MDIO_PHY_SEL BIT(13)
+#define DISABLE_SIGNAL_DETECT_FLT BIT(14)
+
+/* SERDES_DIGITAL_CONTROL2 */
+#define EN_PARALLEL_DET BIT(0)
+#define DIS_FALSE_LINK BIT(1)
+#define FLT_FORCE_LINK BIT(2)
+#define EN_AUTONEG_ERR_TIMER BIT(3)
+#define DIS_REMOTE_FAULT_SENSING BIT(4)
+#define FORCE_XMIT_DATA BIT(5)
+#define AUTONEG_FAST_TIMERS BIT(6)
+#define DIS_CARRIER_EXTEND BIT(7)
+#define DIS_TRRR_GENERATION BIT(8)
+#define BYPASS_PCS_RX BIT(9)
+#define BYPASS_PCS_TX BIT(10)
+#define TEST_CNTR_EN BIT(11)
+#define TX_PACKET_SEQ_TEST BIT(12)
+#define TX_IDLE_JAM_SEQ_TEST BIT(13)
+#define CLR_BER_CNTR BIT(14)
+
+/* SERDES_DIGITAL_CONTROL3 */
+#define TX_FIFO_RST BIT(0)
+#define FIFO_ELAST_TX_RX_SHIFT 1
+#define FIFO_ELAST_TX_RX_5K 0
+#define FIFO_ELAST_TX_RX_10K 1
+#define FIFO_ELAST_TX_RX_13_5K 2
+#define FIFO_ELAST_TX_RX_18_5K 3
+#define BLOCK_TXEN_MODE BIT(9)
+#define JAM_FALSE_CARRIER_MODE BIT(10)
+#define EXT_PHY_CRS_MODE BIT(11)
+#define INVERT_EXT_PHY_CRS BIT(12)
+#define DISABLE_TX_CRS BIT(13)
+
+/* SERDES_DIGITAL_STATUS */
+#define SGMII_MODE BIT(0)
+#define LINK_STATUS BIT(1)
+#define DUPLEX_STATUS BIT(2)
+#define SPEED_STATUS_SHIFT 3
+#define SPEED_STATUS_10 0
+#define SPEED_STATUS_100 1
+#define SPEED_STATUS_1000 2
+#define SPEED_STATUS_2500 3
+#define SPEED_STATUS_MASK SPEED_STATUS_2500
+#define PAUSE_RESOLUTION_TX_SIDE BIT(5)
+#define PAUSE_RESOLUTION_RX_SIDE BIT(6)
+#define LINK_STATUS_CHANGE BIT(7)
+#define EARLY_END_EXT_DET BIT(8)
+#define CARRIER_EXT_ERR_DET BIT(9)
+#define RX_ERR_DET BIT(10)
+#define TX_ERR_DET BIT(11)
+#define CRC_ERR_DET BIT(12)
+#define FALSE_CARRIER_ERR_DET BIT(13)
+#define RXFIFO_ERR_DET BIT(14)
+#define TXFIFO_ERR_DET BIT(15)
+
+/* Block offsets */
+#define SERDES_DIGITAL_BLK 0x8300
+#define SERDES_ID0 0x8310
+#define SERDES_MII_BLK 0xffe0
+#define SERDES_XGXSBLK0_BLOCKADDRESS 0xffd0
+
+struct phylink_link_state;
+
+static inline u8 b53_serdes_map_lane(struct b53_device *dev, int port)
+{
+ if (!dev->ops->serdes_map_lane)
+ return B53_INVALID_LANE;
+
+ return dev->ops->serdes_map_lane(dev, port);
+}
+
+int b53_serdes_get_link(struct b53_device *dev, int port);
+int b53_serdes_link_state(struct b53_device *dev, int port,
+ struct phylink_link_state *state);
+void b53_serdes_config(struct b53_device *dev, int port, unsigned int mode,
+ const struct phylink_link_state *state);
+void b53_serdes_an_restart(struct b53_device *dev, int port);
+void b53_serdes_link_set(struct b53_device *dev, int port, unsigned int mode,
+ phy_interface_t interface, bool link_up);
+void b53_serdes_phylink_validate(struct b53_device *dev, int port,
+ unsigned long *supported,
+ struct phylink_link_state *state);
+#if IS_ENABLED(CONFIG_B53_SERDES)
+int b53_serdes_init(struct b53_device *dev, int port);
+#else
+static inline int b53_serdes_init(struct b53_device *dev, int port)
+{
+ return -ENODEV;
+}
+#endif
diff --git a/drivers/net/dsa/b53/b53_srab.c b/drivers/net/dsa/b53/b53_srab.c
index 91de2ba99ad1..90f514252987 100644
--- a/drivers/net/dsa/b53/b53_srab.c
+++ b/drivers/net/dsa/b53/b53_srab.c
@@ -19,11 +19,13 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
+#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/platform_data/b53.h>
#include <linux/of.h>
#include "b53_priv.h"
+#include "b53_serdes.h"
/* command and status register of the SRAB */
#define B53_SRAB_CMDSTAT 0x2c
@@ -47,6 +49,7 @@
/* command and status register of the SRAB */
#define B53_SRAB_CTRLS 0x40
+#define B53_SRAB_CTRLS_HOST_INTR BIT(1)
#define B53_SRAB_CTRLS_RCAREQ BIT(3)
#define B53_SRAB_CTRLS_RCAGNT BIT(4)
#define B53_SRAB_CTRLS_SW_INIT_DONE BIT(6)
@@ -60,8 +63,29 @@
#define B53_SRAB_P7_SLEEP_TIMER BIT(11)
#define B53_SRAB_IMP0_SLEEP_TIMER BIT(12)
+/* Port mux configuration registers */
+#define B53_MUX_CONFIG_P5 0x00
+#define MUX_CONFIG_SGMII 0
+#define MUX_CONFIG_MII_LITE 1
+#define MUX_CONFIG_RGMII 2
+#define MUX_CONFIG_GMII 3
+#define MUX_CONFIG_GPHY 4
+#define MUX_CONFIG_INTERNAL 5
+#define MUX_CONFIG_MASK 0x7
+#define B53_MUX_CONFIG_P4 0x04
+
+struct b53_srab_port_priv {
+ int irq;
+ bool irq_enabled;
+ struct b53_device *dev;
+ unsigned int num;
+ phy_interface_t mode;
+};
+
struct b53_srab_priv {
void __iomem *regs;
+ void __iomem *mux_config;
+ struct b53_srab_port_priv port_intrs[B53_N_PORTS];
};
static int b53_srab_request_grant(struct b53_device *dev)
@@ -344,6 +368,81 @@ err:
return ret;
}
+static irqreturn_t b53_srab_port_thread(int irq, void *dev_id)
+{
+ struct b53_srab_port_priv *port = dev_id;
+ struct b53_device *dev = port->dev;
+
+ if (port->mode == PHY_INTERFACE_MODE_SGMII)
+ b53_port_event(dev->ds, port->num);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t b53_srab_port_isr(int irq, void *dev_id)
+{
+ struct b53_srab_port_priv *port = dev_id;
+ struct b53_device *dev = port->dev;
+ struct b53_srab_priv *priv = dev->priv;
+
+ /* Acknowledge the interrupt */
+ writel(BIT(port->num), priv->regs + B53_SRAB_INTR);
+
+ return IRQ_WAKE_THREAD;
+}
+
+#if IS_ENABLED(CONFIG_B53_SERDES)
+static u8 b53_srab_serdes_map_lane(struct b53_device *dev, int port)
+{
+ struct b53_srab_priv *priv = dev->priv;
+ struct b53_srab_port_priv *p = &priv->port_intrs[port];
+
+ if (p->mode != PHY_INTERFACE_MODE_SGMII)
+ return B53_INVALID_LANE;
+
+ switch (port) {
+ case 5:
+ return 0;
+ case 4:
+ return 1;
+ default:
+ return B53_INVALID_LANE;
+ }
+}
+#endif
+
+static int b53_srab_irq_enable(struct b53_device *dev, int port)
+{
+ struct b53_srab_priv *priv = dev->priv;
+ struct b53_srab_port_priv *p = &priv->port_intrs[port];
+ int ret = 0;
+
+ /* Interrupt is optional and was not specified, do not make
+ * this fatal
+ */
+ if (p->irq == -ENXIO)
+ return ret;
+
+ ret = request_threaded_irq(p->irq, b53_srab_port_isr,
+ b53_srab_port_thread, 0,
+ dev_name(dev->dev), p);
+ if (!ret)
+ p->irq_enabled = true;
+
+ return ret;
+}
+
+static void b53_srab_irq_disable(struct b53_device *dev, int port)
+{
+ struct b53_srab_priv *priv = dev->priv;
+ struct b53_srab_port_priv *p = &priv->port_intrs[port];
+
+ if (p->irq_enabled) {
+ free_irq(p->irq, p);
+ p->irq_enabled = false;
+ }
+}
+
static const struct b53_io_ops b53_srab_ops = {
.read8 = b53_srab_read8,
.read16 = b53_srab_read16,
@@ -355,6 +454,16 @@ static const struct b53_io_ops b53_srab_ops = {
.write32 = b53_srab_write32,
.write48 = b53_srab_write48,
.write64 = b53_srab_write64,
+ .irq_enable = b53_srab_irq_enable,
+ .irq_disable = b53_srab_irq_disable,
+#if IS_ENABLED(CONFIG_B53_SERDES)
+ .serdes_map_lane = b53_srab_serdes_map_lane,
+ .serdes_link_state = b53_serdes_link_state,
+ .serdes_config = b53_serdes_config,
+ .serdes_an_restart = b53_serdes_an_restart,
+ .serdes_link_set = b53_serdes_link_set,
+ .serdes_phylink_validate = b53_serdes_phylink_validate,
+#endif
};
static const struct of_device_id b53_srab_of_match[] = {
@@ -379,6 +488,107 @@ static const struct of_device_id b53_srab_of_match[] = {
};
MODULE_DEVICE_TABLE(of, b53_srab_of_match);
+static void b53_srab_intr_set(struct b53_srab_priv *priv, bool set)
+{
+ u32 reg;
+
+ reg = readl(priv->regs + B53_SRAB_CTRLS);
+ if (set)
+ reg |= B53_SRAB_CTRLS_HOST_INTR;
+ else
+ reg &= ~B53_SRAB_CTRLS_HOST_INTR;
+ writel(reg, priv->regs + B53_SRAB_CTRLS);
+}
+
+static void b53_srab_prepare_irq(struct platform_device *pdev)
+{
+ struct b53_device *dev = platform_get_drvdata(pdev);
+ struct b53_srab_priv *priv = dev->priv;
+ struct b53_srab_port_priv *port;
+ unsigned int i;
+ char *name;
+
+ /* Clear all pending interrupts */
+ writel(0xffffffff, priv->regs + B53_SRAB_INTR);
+
+ if (dev->pdata && dev->pdata->chip_id != BCM58XX_DEVICE_ID)
+ return;
+
+ for (i = 0; i < B53_N_PORTS; i++) {
+ port = &priv->port_intrs[i];
+
+ /* There is no port 6 */
+ if (i == 6)
+ continue;
+
+ name = kasprintf(GFP_KERNEL, "link_state_p%d", i);
+ if (!name)
+ return;
+
+ port->num = i;
+ port->dev = dev;
+ port->irq = platform_get_irq_byname(pdev, name);
+ kfree(name);
+ }
+
+ b53_srab_intr_set(priv, true);
+}
+
+static void b53_srab_mux_init(struct platform_device *pdev)
+{
+ struct b53_device *dev = platform_get_drvdata(pdev);
+ struct b53_srab_priv *priv = dev->priv;
+ struct b53_srab_port_priv *p;
+ struct resource *r;
+ unsigned int port;
+ u32 reg, off = 0;
+ int ret;
+
+ if (dev->pdata && dev->pdata->chip_id != BCM58XX_DEVICE_ID)
+ return;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ priv->mux_config = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(priv->mux_config))
+ return;
+
+ /* Obtain the port mux configuration so we know which lanes
+ * actually map to SerDes lanes
+ */
+ for (port = 5; port > 3; port--, off += 4) {
+ p = &priv->port_intrs[port];
+
+ reg = readl(priv->mux_config + B53_MUX_CONFIG_P5 + off);
+ switch (reg & MUX_CONFIG_MASK) {
+ case MUX_CONFIG_SGMII:
+ p->mode = PHY_INTERFACE_MODE_SGMII;
+ ret = b53_serdes_init(dev, port);
+ if (ret)
+ continue;
+ break;
+ case MUX_CONFIG_MII_LITE:
+ p->mode = PHY_INTERFACE_MODE_MII;
+ break;
+ case MUX_CONFIG_GMII:
+ p->mode = PHY_INTERFACE_MODE_GMII;
+ break;
+ case MUX_CONFIG_RGMII:
+ p->mode = PHY_INTERFACE_MODE_RGMII;
+ break;
+ case MUX_CONFIG_INTERNAL:
+ p->mode = PHY_INTERFACE_MODE_INTERNAL;
+ break;
+ default:
+ p->mode = PHY_INTERFACE_MODE_NA;
+ break;
+ }
+
+ if (p->mode != PHY_INTERFACE_MODE_NA)
+ dev_info(&pdev->dev, "Port %d mode: %s\n",
+ port, phy_modes(p->mode));
+ }
+}
+
static int b53_srab_probe(struct platform_device *pdev)
{
struct b53_platform_data *pdata = pdev->dev.platform_data;
@@ -417,13 +627,18 @@ static int b53_srab_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, dev);
+ b53_srab_prepare_irq(pdev);
+ b53_srab_mux_init(pdev);
+
return b53_switch_register(dev);
}
static int b53_srab_remove(struct platform_device *pdev)
{
struct b53_device *dev = platform_get_drvdata(pdev);
+ struct b53_srab_priv *priv = dev->priv;
+ b53_srab_intr_set(priv, false);
if (dev)
b53_switch_remove(dev);
diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
index e0066adcd2f3..2eb68769562c 100644
--- a/drivers/net/dsa/bcm_sf2.c
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -465,8 +465,7 @@ static int bcm_sf2_mdio_register(struct dsa_switch *ds)
static void bcm_sf2_mdio_unregister(struct bcm_sf2_priv *priv)
{
mdiobus_unregister(priv->slave_mii_bus);
- if (priv->master_mii_dn)
- of_node_put(priv->master_mii_dn);
+ of_node_put(priv->master_mii_dn);
}
static u32 bcm_sf2_sw_get_phy_flags(struct dsa_switch *ds, int port)
@@ -703,7 +702,6 @@ static int bcm_sf2_sw_suspend(struct dsa_switch *ds)
static int bcm_sf2_sw_resume(struct dsa_switch *ds)
{
struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
- unsigned int port;
int ret;
ret = bcm_sf2_sw_rst(priv);
@@ -715,14 +713,7 @@ static int bcm_sf2_sw_resume(struct dsa_switch *ds)
if (priv->hw_params.num_gphy == 1)
bcm_sf2_gphy_enable_set(ds, true);
- for (port = 0; port < DSA_MAX_PORTS; port++) {
- if (dsa_is_user_port(ds, port))
- bcm_sf2_port_setup(ds, port, NULL);
- else if (dsa_is_cpu_port(ds, port))
- bcm_sf2_imp_setup(ds, port);
- }
-
- bcm_sf2_enable_acb(ds);
+ ds->ops->setup(ds);
return 0;
}
@@ -1173,10 +1164,10 @@ static int bcm_sf2_sw_remove(struct platform_device *pdev)
{
struct bcm_sf2_priv *priv = platform_get_drvdata(pdev);
- /* Disable all ports and interrupts */
priv->wol_ports_mask = 0;
- bcm_sf2_sw_suspend(priv->dev->ds);
dsa_unregister_switch(priv->dev->ds);
+ /* Disable all ports and interrupts */
+ bcm_sf2_sw_suspend(priv->dev->ds);
bcm_sf2_mdio_unregister(priv);
return 0;
@@ -1199,16 +1190,14 @@ static void bcm_sf2_sw_shutdown(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP
static int bcm_sf2_suspend(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct bcm_sf2_priv *priv = platform_get_drvdata(pdev);
+ struct bcm_sf2_priv *priv = dev_get_drvdata(dev);
return dsa_switch_suspend(priv->dev->ds);
}
static int bcm_sf2_resume(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct bcm_sf2_priv *priv = platform_get_drvdata(pdev);
+ struct bcm_sf2_priv *priv = dev_get_drvdata(dev);
return dsa_switch_resume(priv->dev->ds);
}
diff --git a/drivers/net/dsa/lantiq_gswip.c b/drivers/net/dsa/lantiq_gswip.c
new file mode 100644
index 000000000000..693a67f45bef
--- /dev/null
+++ b/drivers/net/dsa/lantiq_gswip.c
@@ -0,0 +1,1167 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Lantiq / Intel GSWIP switch driver for VRX200 SoCs
+ *
+ * Copyright (C) 2010 Lantiq Deutschland
+ * Copyright (C) 2012 John Crispin <john@phrozen.org>
+ * Copyright (C) 2017 - 2018 Hauke Mehrtens <hauke@hauke-m.de>
+ */
+
+#include <linux/clk.h>
+#include <linux/etherdevice.h>
+#include <linux/firmware.h>
+#include <linux/if_bridge.h>
+#include <linux/if_vlan.h>
+#include <linux/iopoll.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_mdio.h>
+#include <linux/of_net.h>
+#include <linux/of_platform.h>
+#include <linux/phy.h>
+#include <linux/phylink.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <net/dsa.h>
+#include <dt-bindings/mips/lantiq_rcu_gphy.h>
+
+#include "lantiq_pce.h"
+
+/* GSWIP MDIO Registers */
+#define GSWIP_MDIO_GLOB 0x00
+#define GSWIP_MDIO_GLOB_ENABLE BIT(15)
+#define GSWIP_MDIO_CTRL 0x08
+#define GSWIP_MDIO_CTRL_BUSY BIT(12)
+#define GSWIP_MDIO_CTRL_RD BIT(11)
+#define GSWIP_MDIO_CTRL_WR BIT(10)
+#define GSWIP_MDIO_CTRL_PHYAD_MASK 0x1f
+#define GSWIP_MDIO_CTRL_PHYAD_SHIFT 5
+#define GSWIP_MDIO_CTRL_REGAD_MASK 0x1f
+#define GSWIP_MDIO_READ 0x09
+#define GSWIP_MDIO_WRITE 0x0A
+#define GSWIP_MDIO_MDC_CFG0 0x0B
+#define GSWIP_MDIO_MDC_CFG1 0x0C
+#define GSWIP_MDIO_PHYp(p) (0x15 - (p))
+#define GSWIP_MDIO_PHY_LINK_MASK 0x6000
+#define GSWIP_MDIO_PHY_LINK_AUTO 0x0000
+#define GSWIP_MDIO_PHY_LINK_DOWN 0x4000
+#define GSWIP_MDIO_PHY_LINK_UP 0x2000
+#define GSWIP_MDIO_PHY_SPEED_MASK 0x1800
+#define GSWIP_MDIO_PHY_SPEED_AUTO 0x1800
+#define GSWIP_MDIO_PHY_SPEED_M10 0x0000
+#define GSWIP_MDIO_PHY_SPEED_M100 0x0800
+#define GSWIP_MDIO_PHY_SPEED_G1 0x1000
+#define GSWIP_MDIO_PHY_FDUP_MASK 0x0600
+#define GSWIP_MDIO_PHY_FDUP_AUTO 0x0000
+#define GSWIP_MDIO_PHY_FDUP_EN 0x0200
+#define GSWIP_MDIO_PHY_FDUP_DIS 0x0600
+#define GSWIP_MDIO_PHY_FCONTX_MASK 0x0180
+#define GSWIP_MDIO_PHY_FCONTX_AUTO 0x0000
+#define GSWIP_MDIO_PHY_FCONTX_EN 0x0100
+#define GSWIP_MDIO_PHY_FCONTX_DIS 0x0180
+#define GSWIP_MDIO_PHY_FCONRX_MASK 0x0060
+#define GSWIP_MDIO_PHY_FCONRX_AUTO 0x0000
+#define GSWIP_MDIO_PHY_FCONRX_EN 0x0020
+#define GSWIP_MDIO_PHY_FCONRX_DIS 0x0060
+#define GSWIP_MDIO_PHY_ADDR_MASK 0x001f
+#define GSWIP_MDIO_PHY_MASK (GSWIP_MDIO_PHY_ADDR_MASK | \
+ GSWIP_MDIO_PHY_FCONRX_MASK | \
+ GSWIP_MDIO_PHY_FCONTX_MASK | \
+ GSWIP_MDIO_PHY_LINK_MASK | \
+ GSWIP_MDIO_PHY_SPEED_MASK | \
+ GSWIP_MDIO_PHY_FDUP_MASK)
+
+/* GSWIP MII Registers */
+#define GSWIP_MII_CFG0 0x00
+#define GSWIP_MII_CFG1 0x02
+#define GSWIP_MII_CFG5 0x04
+#define GSWIP_MII_CFG_EN BIT(14)
+#define GSWIP_MII_CFG_LDCLKDIS BIT(12)
+#define GSWIP_MII_CFG_MODE_MIIP 0x0
+#define GSWIP_MII_CFG_MODE_MIIM 0x1
+#define GSWIP_MII_CFG_MODE_RMIIP 0x2
+#define GSWIP_MII_CFG_MODE_RMIIM 0x3
+#define GSWIP_MII_CFG_MODE_RGMII 0x4
+#define GSWIP_MII_CFG_MODE_MASK 0xf
+#define GSWIP_MII_CFG_RATE_M2P5 0x00
+#define GSWIP_MII_CFG_RATE_M25 0x10
+#define GSWIP_MII_CFG_RATE_M125 0x20
+#define GSWIP_MII_CFG_RATE_M50 0x30
+#define GSWIP_MII_CFG_RATE_AUTO 0x40
+#define GSWIP_MII_CFG_RATE_MASK 0x70
+#define GSWIP_MII_PCDU0 0x01
+#define GSWIP_MII_PCDU1 0x03
+#define GSWIP_MII_PCDU5 0x05
+#define GSWIP_MII_PCDU_TXDLY_MASK GENMASK(2, 0)
+#define GSWIP_MII_PCDU_RXDLY_MASK GENMASK(9, 7)
+
+/* GSWIP Core Registers */
+#define GSWIP_SWRES 0x000
+#define GSWIP_SWRES_R1 BIT(1) /* GSWIP Software reset */
+#define GSWIP_SWRES_R0 BIT(0) /* GSWIP Hardware reset */
+#define GSWIP_VERSION 0x013
+#define GSWIP_VERSION_REV_SHIFT 0
+#define GSWIP_VERSION_REV_MASK GENMASK(7, 0)
+#define GSWIP_VERSION_MOD_SHIFT 8
+#define GSWIP_VERSION_MOD_MASK GENMASK(15, 8)
+#define GSWIP_VERSION_2_0 0x100
+#define GSWIP_VERSION_2_1 0x021
+#define GSWIP_VERSION_2_2 0x122
+#define GSWIP_VERSION_2_2_ETC 0x022
+
+#define GSWIP_BM_RAM_VAL(x) (0x043 - (x))
+#define GSWIP_BM_RAM_ADDR 0x044
+#define GSWIP_BM_RAM_CTRL 0x045
+#define GSWIP_BM_RAM_CTRL_BAS BIT(15)
+#define GSWIP_BM_RAM_CTRL_OPMOD BIT(5)
+#define GSWIP_BM_RAM_CTRL_ADDR_MASK GENMASK(4, 0)
+#define GSWIP_BM_QUEUE_GCTRL 0x04A
+#define GSWIP_BM_QUEUE_GCTRL_GL_MOD BIT(10)
+/* buffer management Port Configuration Register */
+#define GSWIP_BM_PCFGp(p) (0x080 + ((p) * 2))
+#define GSWIP_BM_PCFG_CNTEN BIT(0) /* RMON Counter Enable */
+#define GSWIP_BM_PCFG_IGCNT BIT(1) /* Ingres Special Tag RMON count */
+/* buffer management Port Control Register */
+#define GSWIP_BM_RMON_CTRLp(p) (0x81 + ((p) * 2))
+#define GSWIP_BM_CTRL_RMON_RAM1_RES BIT(0) /* Software Reset for RMON RAM 1 */
+#define GSWIP_BM_CTRL_RMON_RAM2_RES BIT(1) /* Software Reset for RMON RAM 2 */
+
+/* PCE */
+#define GSWIP_PCE_TBL_KEY(x) (0x447 - (x))
+#define GSWIP_PCE_TBL_MASK 0x448
+#define GSWIP_PCE_TBL_VAL(x) (0x44D - (x))
+#define GSWIP_PCE_TBL_ADDR 0x44E
+#define GSWIP_PCE_TBL_CTRL 0x44F
+#define GSWIP_PCE_TBL_CTRL_BAS BIT(15)
+#define GSWIP_PCE_TBL_CTRL_TYPE BIT(13)
+#define GSWIP_PCE_TBL_CTRL_VLD BIT(12)
+#define GSWIP_PCE_TBL_CTRL_KEYFORM BIT(11)
+#define GSWIP_PCE_TBL_CTRL_GMAP_MASK GENMASK(10, 7)
+#define GSWIP_PCE_TBL_CTRL_OPMOD_MASK GENMASK(6, 5)
+#define GSWIP_PCE_TBL_CTRL_OPMOD_ADRD 0x00
+#define GSWIP_PCE_TBL_CTRL_OPMOD_ADWR 0x20
+#define GSWIP_PCE_TBL_CTRL_OPMOD_KSRD 0x40
+#define GSWIP_PCE_TBL_CTRL_OPMOD_KSWR 0x60
+#define GSWIP_PCE_TBL_CTRL_ADDR_MASK GENMASK(4, 0)
+#define GSWIP_PCE_PMAP1 0x453 /* Monitoring port map */
+#define GSWIP_PCE_PMAP2 0x454 /* Default Multicast port map */
+#define GSWIP_PCE_PMAP3 0x455 /* Default Unknown Unicast port map */
+#define GSWIP_PCE_GCTRL_0 0x456
+#define GSWIP_PCE_GCTRL_0_MC_VALID BIT(3)
+#define GSWIP_PCE_GCTRL_0_VLAN BIT(14) /* VLAN aware Switching */
+#define GSWIP_PCE_GCTRL_1 0x457
+#define GSWIP_PCE_GCTRL_1_MAC_GLOCK BIT(2) /* MAC Address table lock */
+#define GSWIP_PCE_GCTRL_1_MAC_GLOCK_MOD BIT(3) /* Mac address table lock forwarding mode */
+#define GSWIP_PCE_PCTRL_0p(p) (0x480 + ((p) * 0xA))
+#define GSWIP_PCE_PCTRL_0_INGRESS BIT(11)
+#define GSWIP_PCE_PCTRL_0_PSTATE_LISTEN 0x0
+#define GSWIP_PCE_PCTRL_0_PSTATE_RX 0x1
+#define GSWIP_PCE_PCTRL_0_PSTATE_TX 0x2
+#define GSWIP_PCE_PCTRL_0_PSTATE_LEARNING 0x3
+#define GSWIP_PCE_PCTRL_0_PSTATE_FORWARDING 0x7
+#define GSWIP_PCE_PCTRL_0_PSTATE_MASK GENMASK(2, 0)
+
+#define GSWIP_MAC_FLEN 0x8C5
+#define GSWIP_MAC_CTRL_2p(p) (0x905 + ((p) * 0xC))
+#define GSWIP_MAC_CTRL_2_MLEN BIT(3) /* Maximum Untagged Frame Lnegth */
+
+/* Ethernet Switch Fetch DMA Port Control Register */
+#define GSWIP_FDMA_PCTRLp(p) (0xA80 + ((p) * 0x6))
+#define GSWIP_FDMA_PCTRL_EN BIT(0) /* FDMA Port Enable */
+#define GSWIP_FDMA_PCTRL_STEN BIT(1) /* Special Tag Insertion Enable */
+#define GSWIP_FDMA_PCTRL_VLANMOD_MASK GENMASK(4, 3) /* VLAN Modification Control */
+#define GSWIP_FDMA_PCTRL_VLANMOD_SHIFT 3 /* VLAN Modification Control */
+#define GSWIP_FDMA_PCTRL_VLANMOD_DIS (0x0 << GSWIP_FDMA_PCTRL_VLANMOD_SHIFT)
+#define GSWIP_FDMA_PCTRL_VLANMOD_PRIO (0x1 << GSWIP_FDMA_PCTRL_VLANMOD_SHIFT)
+#define GSWIP_FDMA_PCTRL_VLANMOD_ID (0x2 << GSWIP_FDMA_PCTRL_VLANMOD_SHIFT)
+#define GSWIP_FDMA_PCTRL_VLANMOD_BOTH (0x3 << GSWIP_FDMA_PCTRL_VLANMOD_SHIFT)
+
+/* Ethernet Switch Store DMA Port Control Register */
+#define GSWIP_SDMA_PCTRLp(p) (0xBC0 + ((p) * 0x6))
+#define GSWIP_SDMA_PCTRL_EN BIT(0) /* SDMA Port Enable */
+#define GSWIP_SDMA_PCTRL_FCEN BIT(1) /* Flow Control Enable */
+#define GSWIP_SDMA_PCTRL_PAUFWD BIT(1) /* Pause Frame Forwarding */
+
+#define XRX200_GPHY_FW_ALIGN (16 * 1024)
+
+struct gswip_hw_info {
+ int max_ports;
+ int cpu_port;
+};
+
+struct xway_gphy_match_data {
+ char *fe_firmware_name;
+ char *ge_firmware_name;
+};
+
+struct gswip_gphy_fw {
+ struct clk *clk_gate;
+ struct reset_control *reset;
+ u32 fw_addr_offset;
+ char *fw_name;
+};
+
+struct gswip_priv {
+ __iomem void *gswip;
+ __iomem void *mdio;
+ __iomem void *mii;
+ const struct gswip_hw_info *hw_info;
+ const struct xway_gphy_match_data *gphy_fw_name_cfg;
+ struct dsa_switch *ds;
+ struct device *dev;
+ struct regmap *rcu_regmap;
+ int num_gphy_fw;
+ struct gswip_gphy_fw *gphy_fw;
+};
+
+struct gswip_rmon_cnt_desc {
+ unsigned int size;
+ unsigned int offset;
+ const char *name;
+};
+
+#define MIB_DESC(_size, _offset, _name) {.size = _size, .offset = _offset, .name = _name}
+
+static const struct gswip_rmon_cnt_desc gswip_rmon_cnt[] = {
+ /** Receive Packet Count (only packets that are accepted and not discarded). */
+ MIB_DESC(1, 0x1F, "RxGoodPkts"),
+ MIB_DESC(1, 0x23, "RxUnicastPkts"),
+ MIB_DESC(1, 0x22, "RxMulticastPkts"),
+ MIB_DESC(1, 0x21, "RxFCSErrorPkts"),
+ MIB_DESC(1, 0x1D, "RxUnderSizeGoodPkts"),
+ MIB_DESC(1, 0x1E, "RxUnderSizeErrorPkts"),
+ MIB_DESC(1, 0x1B, "RxOversizeGoodPkts"),
+ MIB_DESC(1, 0x1C, "RxOversizeErrorPkts"),
+ MIB_DESC(1, 0x20, "RxGoodPausePkts"),
+ MIB_DESC(1, 0x1A, "RxAlignErrorPkts"),
+ MIB_DESC(1, 0x12, "Rx64BytePkts"),
+ MIB_DESC(1, 0x13, "Rx127BytePkts"),
+ MIB_DESC(1, 0x14, "Rx255BytePkts"),
+ MIB_DESC(1, 0x15, "Rx511BytePkts"),
+ MIB_DESC(1, 0x16, "Rx1023BytePkts"),
+ /** Receive Size 1024-1522 (or more, if configured) Packet Count. */
+ MIB_DESC(1, 0x17, "RxMaxBytePkts"),
+ MIB_DESC(1, 0x18, "RxDroppedPkts"),
+ MIB_DESC(1, 0x19, "RxFilteredPkts"),
+ MIB_DESC(2, 0x24, "RxGoodBytes"),
+ MIB_DESC(2, 0x26, "RxBadBytes"),
+ MIB_DESC(1, 0x11, "TxAcmDroppedPkts"),
+ MIB_DESC(1, 0x0C, "TxGoodPkts"),
+ MIB_DESC(1, 0x06, "TxUnicastPkts"),
+ MIB_DESC(1, 0x07, "TxMulticastPkts"),
+ MIB_DESC(1, 0x00, "Tx64BytePkts"),
+ MIB_DESC(1, 0x01, "Tx127BytePkts"),
+ MIB_DESC(1, 0x02, "Tx255BytePkts"),
+ MIB_DESC(1, 0x03, "Tx511BytePkts"),
+ MIB_DESC(1, 0x04, "Tx1023BytePkts"),
+ /** Transmit Size 1024-1522 (or more, if configured) Packet Count. */
+ MIB_DESC(1, 0x05, "TxMaxBytePkts"),
+ MIB_DESC(1, 0x08, "TxSingleCollCount"),
+ MIB_DESC(1, 0x09, "TxMultCollCount"),
+ MIB_DESC(1, 0x0A, "TxLateCollCount"),
+ MIB_DESC(1, 0x0B, "TxExcessCollCount"),
+ MIB_DESC(1, 0x0D, "TxPauseCount"),
+ MIB_DESC(1, 0x10, "TxDroppedPkts"),
+ MIB_DESC(2, 0x0E, "TxGoodBytes"),
+};
+
+static u32 gswip_switch_r(struct gswip_priv *priv, u32 offset)
+{
+ return __raw_readl(priv->gswip + (offset * 4));
+}
+
+static void gswip_switch_w(struct gswip_priv *priv, u32 val, u32 offset)
+{
+ __raw_writel(val, priv->gswip + (offset * 4));
+}
+
+static void gswip_switch_mask(struct gswip_priv *priv, u32 clear, u32 set,
+ u32 offset)
+{
+ u32 val = gswip_switch_r(priv, offset);
+
+ val &= ~(clear);
+ val |= set;
+ gswip_switch_w(priv, val, offset);
+}
+
+static u32 gswip_switch_r_timeout(struct gswip_priv *priv, u32 offset,
+ u32 cleared)
+{
+ u32 val;
+
+ return readx_poll_timeout(__raw_readl, priv->gswip + (offset * 4), val,
+ (val & cleared) == 0, 20, 50000);
+}
+
+static u32 gswip_mdio_r(struct gswip_priv *priv, u32 offset)
+{
+ return __raw_readl(priv->mdio + (offset * 4));
+}
+
+static void gswip_mdio_w(struct gswip_priv *priv, u32 val, u32 offset)
+{
+ __raw_writel(val, priv->mdio + (offset * 4));
+}
+
+static void gswip_mdio_mask(struct gswip_priv *priv, u32 clear, u32 set,
+ u32 offset)
+{
+ u32 val = gswip_mdio_r(priv, offset);
+
+ val &= ~(clear);
+ val |= set;
+ gswip_mdio_w(priv, val, offset);
+}
+
+static u32 gswip_mii_r(struct gswip_priv *priv, u32 offset)
+{
+ return __raw_readl(priv->mii + (offset * 4));
+}
+
+static void gswip_mii_w(struct gswip_priv *priv, u32 val, u32 offset)
+{
+ __raw_writel(val, priv->mii + (offset * 4));
+}
+
+static void gswip_mii_mask(struct gswip_priv *priv, u32 clear, u32 set,
+ u32 offset)
+{
+ u32 val = gswip_mii_r(priv, offset);
+
+ val &= ~(clear);
+ val |= set;
+ gswip_mii_w(priv, val, offset);
+}
+
+static void gswip_mii_mask_cfg(struct gswip_priv *priv, u32 clear, u32 set,
+ int port)
+{
+ switch (port) {
+ case 0:
+ gswip_mii_mask(priv, clear, set, GSWIP_MII_CFG0);
+ break;
+ case 1:
+ gswip_mii_mask(priv, clear, set, GSWIP_MII_CFG1);
+ break;
+ case 5:
+ gswip_mii_mask(priv, clear, set, GSWIP_MII_CFG5);
+ break;
+ }
+}
+
+static void gswip_mii_mask_pcdu(struct gswip_priv *priv, u32 clear, u32 set,
+ int port)
+{
+ switch (port) {
+ case 0:
+ gswip_mii_mask(priv, clear, set, GSWIP_MII_PCDU0);
+ break;
+ case 1:
+ gswip_mii_mask(priv, clear, set, GSWIP_MII_PCDU1);
+ break;
+ case 5:
+ gswip_mii_mask(priv, clear, set, GSWIP_MII_PCDU5);
+ break;
+ }
+}
+
+static int gswip_mdio_poll(struct gswip_priv *priv)
+{
+ int cnt = 100;
+
+ while (likely(cnt--)) {
+ u32 ctrl = gswip_mdio_r(priv, GSWIP_MDIO_CTRL);
+
+ if ((ctrl & GSWIP_MDIO_CTRL_BUSY) == 0)
+ return 0;
+ usleep_range(20, 40);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int gswip_mdio_wr(struct mii_bus *bus, int addr, int reg, u16 val)
+{
+ struct gswip_priv *priv = bus->priv;
+ int err;
+
+ err = gswip_mdio_poll(priv);
+ if (err) {
+ dev_err(&bus->dev, "waiting for MDIO bus busy timed out\n");
+ return err;
+ }
+
+ gswip_mdio_w(priv, val, GSWIP_MDIO_WRITE);
+ gswip_mdio_w(priv, GSWIP_MDIO_CTRL_BUSY | GSWIP_MDIO_CTRL_WR |
+ ((addr & GSWIP_MDIO_CTRL_PHYAD_MASK) << GSWIP_MDIO_CTRL_PHYAD_SHIFT) |
+ (reg & GSWIP_MDIO_CTRL_REGAD_MASK),
+ GSWIP_MDIO_CTRL);
+
+ return 0;
+}
+
+static int gswip_mdio_rd(struct mii_bus *bus, int addr, int reg)
+{
+ struct gswip_priv *priv = bus->priv;
+ int err;
+
+ err = gswip_mdio_poll(priv);
+ if (err) {
+ dev_err(&bus->dev, "waiting for MDIO bus busy timed out\n");
+ return err;
+ }
+
+ gswip_mdio_w(priv, GSWIP_MDIO_CTRL_BUSY | GSWIP_MDIO_CTRL_RD |
+ ((addr & GSWIP_MDIO_CTRL_PHYAD_MASK) << GSWIP_MDIO_CTRL_PHYAD_SHIFT) |
+ (reg & GSWIP_MDIO_CTRL_REGAD_MASK),
+ GSWIP_MDIO_CTRL);
+
+ err = gswip_mdio_poll(priv);
+ if (err) {
+ dev_err(&bus->dev, "waiting for MDIO bus busy timed out\n");
+ return err;
+ }
+
+ return gswip_mdio_r(priv, GSWIP_MDIO_READ);
+}
+
+static int gswip_mdio(struct gswip_priv *priv, struct device_node *mdio_np)
+{
+ struct dsa_switch *ds = priv->ds;
+
+ ds->slave_mii_bus = devm_mdiobus_alloc(priv->dev);
+ if (!ds->slave_mii_bus)
+ return -ENOMEM;
+
+ ds->slave_mii_bus->priv = priv;
+ ds->slave_mii_bus->read = gswip_mdio_rd;
+ ds->slave_mii_bus->write = gswip_mdio_wr;
+ ds->slave_mii_bus->name = "lantiq,xrx200-mdio";
+ snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "%s-mii",
+ dev_name(priv->dev));
+ ds->slave_mii_bus->parent = priv->dev;
+ ds->slave_mii_bus->phy_mask = ~ds->phys_mii_mask;
+
+ return of_mdiobus_register(ds->slave_mii_bus, mdio_np);
+}
+
+static int gswip_port_enable(struct dsa_switch *ds, int port,
+ struct phy_device *phydev)
+{
+ struct gswip_priv *priv = ds->priv;
+
+ /* RMON Counter Enable for port */
+ gswip_switch_w(priv, GSWIP_BM_PCFG_CNTEN, GSWIP_BM_PCFGp(port));
+
+ /* enable port fetch/store dma & VLAN Modification */
+ gswip_switch_mask(priv, 0, GSWIP_FDMA_PCTRL_EN |
+ GSWIP_FDMA_PCTRL_VLANMOD_BOTH,
+ GSWIP_FDMA_PCTRLp(port));
+ gswip_switch_mask(priv, 0, GSWIP_SDMA_PCTRL_EN,
+ GSWIP_SDMA_PCTRLp(port));
+ gswip_switch_mask(priv, 0, GSWIP_PCE_PCTRL_0_INGRESS,
+ GSWIP_PCE_PCTRL_0p(port));
+
+ if (!dsa_is_cpu_port(ds, port)) {
+ u32 macconf = GSWIP_MDIO_PHY_LINK_AUTO |
+ GSWIP_MDIO_PHY_SPEED_AUTO |
+ GSWIP_MDIO_PHY_FDUP_AUTO |
+ GSWIP_MDIO_PHY_FCONTX_AUTO |
+ GSWIP_MDIO_PHY_FCONRX_AUTO |
+ (phydev->mdio.addr & GSWIP_MDIO_PHY_ADDR_MASK);
+
+ gswip_mdio_w(priv, macconf, GSWIP_MDIO_PHYp(port));
+ /* Activate MDIO auto polling */
+ gswip_mdio_mask(priv, 0, BIT(port), GSWIP_MDIO_MDC_CFG0);
+ }
+
+ return 0;
+}
+
+static void gswip_port_disable(struct dsa_switch *ds, int port,
+ struct phy_device *phy)
+{
+ struct gswip_priv *priv = ds->priv;
+
+ if (!dsa_is_cpu_port(ds, port)) {
+ gswip_mdio_mask(priv, GSWIP_MDIO_PHY_LINK_DOWN,
+ GSWIP_MDIO_PHY_LINK_MASK,
+ GSWIP_MDIO_PHYp(port));
+ /* Deactivate MDIO auto polling */
+ gswip_mdio_mask(priv, BIT(port), 0, GSWIP_MDIO_MDC_CFG0);
+ }
+
+ gswip_switch_mask(priv, GSWIP_FDMA_PCTRL_EN, 0,
+ GSWIP_FDMA_PCTRLp(port));
+ gswip_switch_mask(priv, GSWIP_SDMA_PCTRL_EN, 0,
+ GSWIP_SDMA_PCTRLp(port));
+}
+
+static int gswip_pce_load_microcode(struct gswip_priv *priv)
+{
+ int i;
+ int err;
+
+ gswip_switch_mask(priv, GSWIP_PCE_TBL_CTRL_ADDR_MASK |
+ GSWIP_PCE_TBL_CTRL_OPMOD_MASK,
+ GSWIP_PCE_TBL_CTRL_OPMOD_ADWR, GSWIP_PCE_TBL_CTRL);
+ gswip_switch_w(priv, 0, GSWIP_PCE_TBL_MASK);
+
+ for (i = 0; i < ARRAY_SIZE(gswip_pce_microcode); i++) {
+ gswip_switch_w(priv, i, GSWIP_PCE_TBL_ADDR);
+ gswip_switch_w(priv, gswip_pce_microcode[i].val_0,
+ GSWIP_PCE_TBL_VAL(0));
+ gswip_switch_w(priv, gswip_pce_microcode[i].val_1,
+ GSWIP_PCE_TBL_VAL(1));
+ gswip_switch_w(priv, gswip_pce_microcode[i].val_2,
+ GSWIP_PCE_TBL_VAL(2));
+ gswip_switch_w(priv, gswip_pce_microcode[i].val_3,
+ GSWIP_PCE_TBL_VAL(3));
+
+ /* start the table access: */
+ gswip_switch_mask(priv, 0, GSWIP_PCE_TBL_CTRL_BAS,
+ GSWIP_PCE_TBL_CTRL);
+ err = gswip_switch_r_timeout(priv, GSWIP_PCE_TBL_CTRL,
+ GSWIP_PCE_TBL_CTRL_BAS);
+ if (err)
+ return err;
+ }
+
+ /* tell the switch that the microcode is loaded */
+ gswip_switch_mask(priv, 0, GSWIP_PCE_GCTRL_0_MC_VALID,
+ GSWIP_PCE_GCTRL_0);
+
+ return 0;
+}
+
+static int gswip_setup(struct dsa_switch *ds)
+{
+ struct gswip_priv *priv = ds->priv;
+ unsigned int cpu_port = priv->hw_info->cpu_port;
+ int i;
+ int err;
+
+ gswip_switch_w(priv, GSWIP_SWRES_R0, GSWIP_SWRES);
+ usleep_range(5000, 10000);
+ gswip_switch_w(priv, 0, GSWIP_SWRES);
+
+ /* disable port fetch/store dma on all ports */
+ for (i = 0; i < priv->hw_info->max_ports; i++)
+ gswip_port_disable(ds, i, NULL);
+
+ /* enable Switch */
+ gswip_mdio_mask(priv, 0, GSWIP_MDIO_GLOB_ENABLE, GSWIP_MDIO_GLOB);
+
+ err = gswip_pce_load_microcode(priv);
+ if (err) {
+ dev_err(priv->dev, "writing PCE microcode failed, %i", err);
+ return err;
+ }
+
+ /* Default unknown Broadcast/Multicast/Unicast port maps */
+ gswip_switch_w(priv, BIT(cpu_port), GSWIP_PCE_PMAP1);
+ gswip_switch_w(priv, BIT(cpu_port), GSWIP_PCE_PMAP2);
+ gswip_switch_w(priv, BIT(cpu_port), GSWIP_PCE_PMAP3);
+
+ /* disable PHY auto polling */
+ gswip_mdio_w(priv, 0x0, GSWIP_MDIO_MDC_CFG0);
+ /* Configure the MDIO Clock 2.5 MHz */
+ gswip_mdio_mask(priv, 0xff, 0x09, GSWIP_MDIO_MDC_CFG1);
+
+ /* Disable the xMII link */
+ gswip_mii_mask_cfg(priv, GSWIP_MII_CFG_EN, 0, 0);
+ gswip_mii_mask_cfg(priv, GSWIP_MII_CFG_EN, 0, 1);
+ gswip_mii_mask_cfg(priv, GSWIP_MII_CFG_EN, 0, 5);
+
+ /* enable special tag insertion on cpu port */
+ gswip_switch_mask(priv, 0, GSWIP_FDMA_PCTRL_STEN,
+ GSWIP_FDMA_PCTRLp(cpu_port));
+
+ gswip_switch_mask(priv, 0, GSWIP_MAC_CTRL_2_MLEN,
+ GSWIP_MAC_CTRL_2p(cpu_port));
+ gswip_switch_w(priv, VLAN_ETH_FRAME_LEN + 8, GSWIP_MAC_FLEN);
+ gswip_switch_mask(priv, 0, GSWIP_BM_QUEUE_GCTRL_GL_MOD,
+ GSWIP_BM_QUEUE_GCTRL);
+
+ /* VLAN aware Switching */
+ gswip_switch_mask(priv, 0, GSWIP_PCE_GCTRL_0_VLAN, GSWIP_PCE_GCTRL_0);
+
+ /* Mac Address Table Lock */
+ gswip_switch_mask(priv, 0, GSWIP_PCE_GCTRL_1_MAC_GLOCK |
+ GSWIP_PCE_GCTRL_1_MAC_GLOCK_MOD,
+ GSWIP_PCE_GCTRL_1);
+
+ gswip_port_enable(ds, cpu_port, NULL);
+ return 0;
+}
+
+static enum dsa_tag_protocol gswip_get_tag_protocol(struct dsa_switch *ds,
+ int port)
+{
+ return DSA_TAG_PROTO_GSWIP;
+}
+
+static void gswip_phylink_validate(struct dsa_switch *ds, int port,
+ unsigned long *supported,
+ struct phylink_link_state *state)
+{
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
+
+ switch (port) {
+ case 0:
+ case 1:
+ if (!phy_interface_mode_is_rgmii(state->interface) &&
+ state->interface != PHY_INTERFACE_MODE_MII &&
+ state->interface != PHY_INTERFACE_MODE_REVMII &&
+ state->interface != PHY_INTERFACE_MODE_RMII)
+ goto unsupported;
+ break;
+ case 2:
+ case 3:
+ case 4:
+ if (state->interface != PHY_INTERFACE_MODE_INTERNAL)
+ goto unsupported;
+ break;
+ case 5:
+ if (!phy_interface_mode_is_rgmii(state->interface) &&
+ state->interface != PHY_INTERFACE_MODE_INTERNAL)
+ goto unsupported;
+ break;
+ default:
+ bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
+ dev_err(ds->dev, "Unsupported port: %i\n", port);
+ return;
+ }
+
+ /* Allow all the expected bits */
+ phylink_set(mask, Autoneg);
+ phylink_set_port_modes(mask);
+ phylink_set(mask, Pause);
+ phylink_set(mask, Asym_Pause);
+
+ /* With the exclusion of MII and Reverse MII, we support Gigabit,
+ * including Half duplex
+ */
+ if (state->interface != PHY_INTERFACE_MODE_MII &&
+ state->interface != PHY_INTERFACE_MODE_REVMII) {
+ phylink_set(mask, 1000baseT_Full);
+ phylink_set(mask, 1000baseT_Half);
+ }
+
+ 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: %d\n", state->interface);
+ return;
+}
+
+static void gswip_phylink_mac_config(struct dsa_switch *ds, int port,
+ unsigned int mode,
+ const struct phylink_link_state *state)
+{
+ struct gswip_priv *priv = ds->priv;
+ u32 miicfg = 0;
+
+ miicfg |= GSWIP_MII_CFG_LDCLKDIS;
+
+ switch (state->interface) {
+ case PHY_INTERFACE_MODE_MII:
+ case PHY_INTERFACE_MODE_INTERNAL:
+ miicfg |= GSWIP_MII_CFG_MODE_MIIM;
+ break;
+ case PHY_INTERFACE_MODE_REVMII:
+ miicfg |= GSWIP_MII_CFG_MODE_MIIP;
+ break;
+ case PHY_INTERFACE_MODE_RMII:
+ miicfg |= GSWIP_MII_CFG_MODE_RMIIM;
+ break;
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ miicfg |= GSWIP_MII_CFG_MODE_RGMII;
+ break;
+ default:
+ dev_err(ds->dev,
+ "Unsupported interface: %d\n", state->interface);
+ return;
+ }
+ gswip_mii_mask_cfg(priv, GSWIP_MII_CFG_MODE_MASK, miicfg, port);
+
+ switch (state->interface) {
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ gswip_mii_mask_pcdu(priv, GSWIP_MII_PCDU_TXDLY_MASK |
+ GSWIP_MII_PCDU_RXDLY_MASK, 0, port);
+ break;
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ gswip_mii_mask_pcdu(priv, GSWIP_MII_PCDU_RXDLY_MASK, 0, port);
+ break;
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ gswip_mii_mask_pcdu(priv, GSWIP_MII_PCDU_TXDLY_MASK, 0, port);
+ break;
+ default:
+ break;
+ }
+}
+
+static void gswip_phylink_mac_link_down(struct dsa_switch *ds, int port,
+ unsigned int mode,
+ phy_interface_t interface)
+{
+ struct gswip_priv *priv = ds->priv;
+
+ gswip_mii_mask_cfg(priv, GSWIP_MII_CFG_EN, 0, port);
+}
+
+static void gswip_phylink_mac_link_up(struct dsa_switch *ds, int port,
+ unsigned int mode,
+ phy_interface_t interface,
+ struct phy_device *phydev)
+{
+ struct gswip_priv *priv = ds->priv;
+
+ /* Enable the xMII interface only for the external PHY */
+ if (interface != PHY_INTERFACE_MODE_INTERNAL)
+ gswip_mii_mask_cfg(priv, 0, GSWIP_MII_CFG_EN, port);
+}
+
+static void gswip_get_strings(struct dsa_switch *ds, int port, u32 stringset,
+ uint8_t *data)
+{
+ int i;
+
+ if (stringset != ETH_SS_STATS)
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(gswip_rmon_cnt); i++)
+ strncpy(data + i * ETH_GSTRING_LEN, gswip_rmon_cnt[i].name,
+ ETH_GSTRING_LEN);
+}
+
+static u32 gswip_bcm_ram_entry_read(struct gswip_priv *priv, u32 table,
+ u32 index)
+{
+ u32 result;
+ int err;
+
+ gswip_switch_w(priv, index, GSWIP_BM_RAM_ADDR);
+ gswip_switch_mask(priv, GSWIP_BM_RAM_CTRL_ADDR_MASK |
+ GSWIP_BM_RAM_CTRL_OPMOD,
+ table | GSWIP_BM_RAM_CTRL_BAS,
+ GSWIP_BM_RAM_CTRL);
+
+ err = gswip_switch_r_timeout(priv, GSWIP_BM_RAM_CTRL,
+ GSWIP_BM_RAM_CTRL_BAS);
+ if (err) {
+ dev_err(priv->dev, "timeout while reading table: %u, index: %u",
+ table, index);
+ return 0;
+ }
+
+ result = gswip_switch_r(priv, GSWIP_BM_RAM_VAL(0));
+ result |= gswip_switch_r(priv, GSWIP_BM_RAM_VAL(1)) << 16;
+
+ return result;
+}
+
+static void gswip_get_ethtool_stats(struct dsa_switch *ds, int port,
+ uint64_t *data)
+{
+ struct gswip_priv *priv = ds->priv;
+ const struct gswip_rmon_cnt_desc *rmon_cnt;
+ int i;
+ u64 high;
+
+ for (i = 0; i < ARRAY_SIZE(gswip_rmon_cnt); i++) {
+ rmon_cnt = &gswip_rmon_cnt[i];
+
+ data[i] = gswip_bcm_ram_entry_read(priv, port,
+ rmon_cnt->offset);
+ if (rmon_cnt->size == 2) {
+ high = gswip_bcm_ram_entry_read(priv, port,
+ rmon_cnt->offset + 1);
+ data[i] |= high << 32;
+ }
+ }
+}
+
+static int gswip_get_sset_count(struct dsa_switch *ds, int port, int sset)
+{
+ if (sset != ETH_SS_STATS)
+ return 0;
+
+ return ARRAY_SIZE(gswip_rmon_cnt);
+}
+
+static const struct dsa_switch_ops gswip_switch_ops = {
+ .get_tag_protocol = gswip_get_tag_protocol,
+ .setup = gswip_setup,
+ .port_enable = gswip_port_enable,
+ .port_disable = gswip_port_disable,
+ .phylink_validate = gswip_phylink_validate,
+ .phylink_mac_config = gswip_phylink_mac_config,
+ .phylink_mac_link_down = gswip_phylink_mac_link_down,
+ .phylink_mac_link_up = gswip_phylink_mac_link_up,
+ .get_strings = gswip_get_strings,
+ .get_ethtool_stats = gswip_get_ethtool_stats,
+ .get_sset_count = gswip_get_sset_count,
+};
+
+static const struct xway_gphy_match_data xrx200a1x_gphy_data = {
+ .fe_firmware_name = "lantiq/xrx200_phy22f_a14.bin",
+ .ge_firmware_name = "lantiq/xrx200_phy11g_a14.bin",
+};
+
+static const struct xway_gphy_match_data xrx200a2x_gphy_data = {
+ .fe_firmware_name = "lantiq/xrx200_phy22f_a22.bin",
+ .ge_firmware_name = "lantiq/xrx200_phy11g_a22.bin",
+};
+
+static const struct xway_gphy_match_data xrx300_gphy_data = {
+ .fe_firmware_name = "lantiq/xrx300_phy22f_a21.bin",
+ .ge_firmware_name = "lantiq/xrx300_phy11g_a21.bin",
+};
+
+static const struct of_device_id xway_gphy_match[] = {
+ { .compatible = "lantiq,xrx200-gphy-fw", .data = NULL },
+ { .compatible = "lantiq,xrx200a1x-gphy-fw", .data = &xrx200a1x_gphy_data },
+ { .compatible = "lantiq,xrx200a2x-gphy-fw", .data = &xrx200a2x_gphy_data },
+ { .compatible = "lantiq,xrx300-gphy-fw", .data = &xrx300_gphy_data },
+ { .compatible = "lantiq,xrx330-gphy-fw", .data = &xrx300_gphy_data },
+ {},
+};
+
+static int gswip_gphy_fw_load(struct gswip_priv *priv, struct gswip_gphy_fw *gphy_fw)
+{
+ struct device *dev = priv->dev;
+ const struct firmware *fw;
+ void *fw_addr;
+ dma_addr_t dma_addr;
+ dma_addr_t dev_addr;
+ size_t size;
+ int ret;
+
+ ret = clk_prepare_enable(gphy_fw->clk_gate);
+ if (ret)
+ return ret;
+
+ reset_control_assert(gphy_fw->reset);
+
+ ret = request_firmware(&fw, gphy_fw->fw_name, dev);
+ if (ret) {
+ dev_err(dev, "failed to load firmware: %s, error: %i\n",
+ gphy_fw->fw_name, ret);
+ return ret;
+ }
+
+ /* GPHY cores need the firmware code in a persistent and contiguous
+ * memory area with a 16 kB boundary aligned start address.
+ */
+ size = fw->size + XRX200_GPHY_FW_ALIGN;
+
+ fw_addr = dmam_alloc_coherent(dev, size, &dma_addr, GFP_KERNEL);
+ if (fw_addr) {
+ fw_addr = PTR_ALIGN(fw_addr, XRX200_GPHY_FW_ALIGN);
+ dev_addr = ALIGN(dma_addr, XRX200_GPHY_FW_ALIGN);
+ memcpy(fw_addr, fw->data, fw->size);
+ } else {
+ dev_err(dev, "failed to alloc firmware memory\n");
+ release_firmware(fw);
+ return -ENOMEM;
+ }
+
+ release_firmware(fw);
+
+ ret = regmap_write(priv->rcu_regmap, gphy_fw->fw_addr_offset, dev_addr);
+ if (ret)
+ return ret;
+
+ reset_control_deassert(gphy_fw->reset);
+
+ return ret;
+}
+
+static int gswip_gphy_fw_probe(struct gswip_priv *priv,
+ struct gswip_gphy_fw *gphy_fw,
+ struct device_node *gphy_fw_np, int i)
+{
+ struct device *dev = priv->dev;
+ u32 gphy_mode;
+ int ret;
+ char gphyname[10];
+
+ snprintf(gphyname, sizeof(gphyname), "gphy%d", i);
+
+ gphy_fw->clk_gate = devm_clk_get(dev, gphyname);
+ if (IS_ERR(gphy_fw->clk_gate)) {
+ dev_err(dev, "Failed to lookup gate clock\n");
+ return PTR_ERR(gphy_fw->clk_gate);
+ }
+
+ ret = of_property_read_u32(gphy_fw_np, "reg", &gphy_fw->fw_addr_offset);
+ if (ret)
+ return ret;
+
+ ret = of_property_read_u32(gphy_fw_np, "lantiq,gphy-mode", &gphy_mode);
+ /* Default to GE mode */
+ if (ret)
+ gphy_mode = GPHY_MODE_GE;
+
+ switch (gphy_mode) {
+ case GPHY_MODE_FE:
+ gphy_fw->fw_name = priv->gphy_fw_name_cfg->fe_firmware_name;
+ break;
+ case GPHY_MODE_GE:
+ gphy_fw->fw_name = priv->gphy_fw_name_cfg->ge_firmware_name;
+ break;
+ default:
+ dev_err(dev, "Unknown GPHY mode %d\n", gphy_mode);
+ return -EINVAL;
+ }
+
+ gphy_fw->reset = of_reset_control_array_get_exclusive(gphy_fw_np);
+ if (IS_ERR(gphy_fw->reset)) {
+ if (PTR_ERR(gphy_fw->reset) != -EPROBE_DEFER)
+ dev_err(dev, "Failed to lookup gphy reset\n");
+ return PTR_ERR(gphy_fw->reset);
+ }
+
+ return gswip_gphy_fw_load(priv, gphy_fw);
+}
+
+static void gswip_gphy_fw_remove(struct gswip_priv *priv,
+ struct gswip_gphy_fw *gphy_fw)
+{
+ int ret;
+
+ /* check if the device was fully probed */
+ if (!gphy_fw->fw_name)
+ return;
+
+ ret = regmap_write(priv->rcu_regmap, gphy_fw->fw_addr_offset, 0);
+ if (ret)
+ dev_err(priv->dev, "can not reset GPHY FW pointer");
+
+ clk_disable_unprepare(gphy_fw->clk_gate);
+
+ reset_control_put(gphy_fw->reset);
+}
+
+static int gswip_gphy_fw_list(struct gswip_priv *priv,
+ struct device_node *gphy_fw_list_np, u32 version)
+{
+ struct device *dev = priv->dev;
+ struct device_node *gphy_fw_np;
+ const struct of_device_id *match;
+ int err;
+ int i = 0;
+
+ /* The VRX200 rev 1.1 uses the GSWIP 2.0 and needs the older
+ * GPHY firmware. The VRX200 rev 1.2 uses the GSWIP 2.1 and also
+ * needs a different GPHY firmware.
+ */
+ if (of_device_is_compatible(gphy_fw_list_np, "lantiq,xrx200-gphy-fw")) {
+ switch (version) {
+ case GSWIP_VERSION_2_0:
+ priv->gphy_fw_name_cfg = &xrx200a1x_gphy_data;
+ break;
+ case GSWIP_VERSION_2_1:
+ priv->gphy_fw_name_cfg = &xrx200a2x_gphy_data;
+ break;
+ default:
+ dev_err(dev, "unknown GSWIP version: 0x%x", version);
+ return -ENOENT;
+ }
+ }
+
+ match = of_match_node(xway_gphy_match, gphy_fw_list_np);
+ if (match && match->data)
+ priv->gphy_fw_name_cfg = match->data;
+
+ if (!priv->gphy_fw_name_cfg) {
+ dev_err(dev, "GPHY compatible type not supported");
+ return -ENOENT;
+ }
+
+ priv->num_gphy_fw = of_get_available_child_count(gphy_fw_list_np);
+ if (!priv->num_gphy_fw)
+ return -ENOENT;
+
+ priv->rcu_regmap = syscon_regmap_lookup_by_phandle(gphy_fw_list_np,
+ "lantiq,rcu");
+ if (IS_ERR(priv->rcu_regmap))
+ return PTR_ERR(priv->rcu_regmap);
+
+ priv->gphy_fw = devm_kmalloc_array(dev, priv->num_gphy_fw,
+ sizeof(*priv->gphy_fw),
+ GFP_KERNEL | __GFP_ZERO);
+ if (!priv->gphy_fw)
+ return -ENOMEM;
+
+ for_each_available_child_of_node(gphy_fw_list_np, gphy_fw_np) {
+ err = gswip_gphy_fw_probe(priv, &priv->gphy_fw[i],
+ gphy_fw_np, i);
+ if (err)
+ goto remove_gphy;
+ i++;
+ }
+
+ return 0;
+
+remove_gphy:
+ for (i = 0; i < priv->num_gphy_fw; i++)
+ gswip_gphy_fw_remove(priv, &priv->gphy_fw[i]);
+ return err;
+}
+
+static int gswip_probe(struct platform_device *pdev)
+{
+ struct gswip_priv *priv;
+ struct resource *gswip_res, *mdio_res, *mii_res;
+ struct device_node *mdio_np, *gphy_fw_np;
+ struct device *dev = &pdev->dev;
+ int err;
+ int i;
+ u32 version;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ gswip_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->gswip = devm_ioremap_resource(dev, gswip_res);
+ if (IS_ERR(priv->gswip))
+ return PTR_ERR(priv->gswip);
+
+ mdio_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ priv->mdio = devm_ioremap_resource(dev, mdio_res);
+ if (IS_ERR(priv->mdio))
+ return PTR_ERR(priv->mdio);
+
+ mii_res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ priv->mii = devm_ioremap_resource(dev, mii_res);
+ if (IS_ERR(priv->mii))
+ return PTR_ERR(priv->mii);
+
+ priv->hw_info = of_device_get_match_data(dev);
+ if (!priv->hw_info)
+ return -EINVAL;
+
+ priv->ds = dsa_switch_alloc(dev, priv->hw_info->max_ports);
+ if (!priv->ds)
+ return -ENOMEM;
+
+ priv->ds->priv = priv;
+ priv->ds->ops = &gswip_switch_ops;
+ priv->dev = dev;
+ version = gswip_switch_r(priv, GSWIP_VERSION);
+
+ /* bring up the mdio bus */
+ gphy_fw_np = of_find_compatible_node(pdev->dev.of_node, NULL,
+ "lantiq,gphy-fw");
+ if (gphy_fw_np) {
+ err = gswip_gphy_fw_list(priv, gphy_fw_np, version);
+ if (err) {
+ dev_err(dev, "gphy fw probe failed\n");
+ return err;
+ }
+ }
+
+ /* bring up the mdio bus */
+ mdio_np = of_find_compatible_node(pdev->dev.of_node, NULL,
+ "lantiq,xrx200-mdio");
+ if (mdio_np) {
+ err = gswip_mdio(priv, mdio_np);
+ if (err) {
+ dev_err(dev, "mdio probe failed\n");
+ goto gphy_fw;
+ }
+ }
+
+ err = dsa_register_switch(priv->ds);
+ if (err) {
+ dev_err(dev, "dsa switch register failed: %i\n", err);
+ goto mdio_bus;
+ }
+ if (!dsa_is_cpu_port(priv->ds, priv->hw_info->cpu_port)) {
+ dev_err(dev, "wrong CPU port defined, HW only supports port: %i",
+ priv->hw_info->cpu_port);
+ err = -EINVAL;
+ goto mdio_bus;
+ }
+
+ platform_set_drvdata(pdev, priv);
+
+ dev_info(dev, "probed GSWIP version %lx mod %lx\n",
+ (version & GSWIP_VERSION_REV_MASK) >> GSWIP_VERSION_REV_SHIFT,
+ (version & GSWIP_VERSION_MOD_MASK) >> GSWIP_VERSION_MOD_SHIFT);
+ return 0;
+
+mdio_bus:
+ if (mdio_np)
+ mdiobus_unregister(priv->ds->slave_mii_bus);
+gphy_fw:
+ for (i = 0; i < priv->num_gphy_fw; i++)
+ gswip_gphy_fw_remove(priv, &priv->gphy_fw[i]);
+ return err;
+}
+
+static int gswip_remove(struct platform_device *pdev)
+{
+ struct gswip_priv *priv = platform_get_drvdata(pdev);
+ int i;
+
+ if (!priv)
+ return 0;
+
+ /* disable the switch */
+ gswip_mdio_mask(priv, GSWIP_MDIO_GLOB_ENABLE, 0, GSWIP_MDIO_GLOB);
+
+ dsa_unregister_switch(priv->ds);
+
+ if (priv->ds->slave_mii_bus)
+ mdiobus_unregister(priv->ds->slave_mii_bus);
+
+ for (i = 0; i < priv->num_gphy_fw; i++)
+ gswip_gphy_fw_remove(priv, &priv->gphy_fw[i]);
+
+ return 0;
+}
+
+static const struct gswip_hw_info gswip_xrx200 = {
+ .max_ports = 7,
+ .cpu_port = 6,
+};
+
+static const struct of_device_id gswip_of_match[] = {
+ { .compatible = "lantiq,xrx200-gswip", .data = &gswip_xrx200 },
+ {},
+};
+MODULE_DEVICE_TABLE(of, gswip_of_match);
+
+static struct platform_driver gswip_driver = {
+ .probe = gswip_probe,
+ .remove = gswip_remove,
+ .driver = {
+ .name = "gswip",
+ .of_match_table = gswip_of_match,
+ },
+};
+
+module_platform_driver(gswip_driver);
+
+MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>");
+MODULE_DESCRIPTION("Lantiq / Intel GSWIP driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/dsa/lantiq_pce.h b/drivers/net/dsa/lantiq_pce.h
new file mode 100644
index 000000000000..180663138e75
--- /dev/null
+++ b/drivers/net/dsa/lantiq_pce.h
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PCE microcode extracted from UGW 7.1.1 switch api
+ *
+ * Copyright (c) 2012, 2014, 2015 Lantiq Deutschland GmbH
+ * Copyright (C) 2012 John Crispin <john@phrozen.org>
+ * Copyright (C) 2017 - 2018 Hauke Mehrtens <hauke@hauke-m.de>
+ */
+
+enum {
+ OUT_MAC0 = 0,
+ OUT_MAC1,
+ OUT_MAC2,
+ OUT_MAC3,
+ OUT_MAC4,
+ OUT_MAC5,
+ OUT_ETHTYP,
+ OUT_VTAG0,
+ OUT_VTAG1,
+ OUT_ITAG0,
+ OUT_ITAG1, /*10 */
+ OUT_ITAG2,
+ OUT_ITAG3,
+ OUT_IP0,
+ OUT_IP1,
+ OUT_IP2,
+ OUT_IP3,
+ OUT_SIP0,
+ OUT_SIP1,
+ OUT_SIP2,
+ OUT_SIP3, /*20*/
+ OUT_SIP4,
+ OUT_SIP5,
+ OUT_SIP6,
+ OUT_SIP7,
+ OUT_DIP0,
+ OUT_DIP1,
+ OUT_DIP2,
+ OUT_DIP3,
+ OUT_DIP4,
+ OUT_DIP5, /*30*/
+ OUT_DIP6,
+ OUT_DIP7,
+ OUT_SESID,
+ OUT_PROT,
+ OUT_APP0,
+ OUT_APP1,
+ OUT_IGMP0,
+ OUT_IGMP1,
+ OUT_IPOFF, /*39*/
+ OUT_NONE = 63,
+};
+
+/* parser's microcode length type */
+#define INSTR 0
+#define IPV6 1
+#define LENACCU 2
+
+/* parser's microcode flag type */
+enum {
+ FLAG_ITAG = 0,
+ FLAG_VLAN,
+ FLAG_SNAP,
+ FLAG_PPPOE,
+ FLAG_IPV6,
+ FLAG_IPV6FL,
+ FLAG_IPV4,
+ FLAG_IGMP,
+ FLAG_TU,
+ FLAG_HOP,
+ FLAG_NN1, /*10 */
+ FLAG_NN2,
+ FLAG_END,
+ FLAG_NO, /*13*/
+};
+
+struct gswip_pce_microcode {
+ u16 val_3;
+ u16 val_2;
+ u16 val_1;
+ u16 val_0;
+};
+
+#define MC_ENTRY(val, msk, ns, out, len, type, flags, ipv4_len) \
+ { val, msk, ((ns) << 10 | (out) << 4 | (len) >> 1),\
+ ((len) & 1) << 15 | (type) << 13 | (flags) << 9 | (ipv4_len) << 8 }
+static const struct gswip_pce_microcode gswip_pce_microcode[] = {
+ /* value mask ns fields L type flags ipv4_len */
+ MC_ENTRY(0x88c3, 0xFFFF, 1, OUT_ITAG0, 4, INSTR, FLAG_ITAG, 0),
+ MC_ENTRY(0x8100, 0xFFFF, 2, OUT_VTAG0, 2, INSTR, FLAG_VLAN, 0),
+ MC_ENTRY(0x88A8, 0xFFFF, 1, OUT_VTAG0, 2, INSTR, FLAG_VLAN, 0),
+ MC_ENTRY(0x8100, 0xFFFF, 1, OUT_VTAG0, 2, INSTR, FLAG_VLAN, 0),
+ MC_ENTRY(0x8864, 0xFFFF, 17, OUT_ETHTYP, 1, INSTR, FLAG_NO, 0),
+ MC_ENTRY(0x0800, 0xFFFF, 21, OUT_ETHTYP, 1, INSTR, FLAG_NO, 0),
+ MC_ENTRY(0x86DD, 0xFFFF, 22, OUT_ETHTYP, 1, INSTR, FLAG_NO, 0),
+ MC_ENTRY(0x8863, 0xFFFF, 16, OUT_ETHTYP, 1, INSTR, FLAG_NO, 0),
+ MC_ENTRY(0x0000, 0xF800, 10, OUT_NONE, 0, INSTR, FLAG_NO, 0),
+ MC_ENTRY(0x0000, 0x0000, 40, OUT_ETHTYP, 1, INSTR, FLAG_NO, 0),
+ MC_ENTRY(0x0600, 0x0600, 40, OUT_ETHTYP, 1, INSTR, FLAG_NO, 0),
+ MC_ENTRY(0x0000, 0x0000, 12, OUT_NONE, 1, INSTR, FLAG_NO, 0),
+ MC_ENTRY(0xAAAA, 0xFFFF, 14, OUT_NONE, 1, INSTR, FLAG_NO, 0),
+ MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_NO, 0),
+ MC_ENTRY(0x0300, 0xFF00, 41, OUT_NONE, 0, INSTR, FLAG_SNAP, 0),
+ MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_NO, 0),
+ MC_ENTRY(0x0000, 0x0000, 41, OUT_DIP7, 3, INSTR, FLAG_NO, 0),
+ MC_ENTRY(0x0000, 0x0000, 18, OUT_DIP7, 3, INSTR, FLAG_PPPOE, 0),
+ MC_ENTRY(0x0021, 0xFFFF, 21, OUT_NONE, 1, INSTR, FLAG_NO, 0),
+ MC_ENTRY(0x0057, 0xFFFF, 22, OUT_NONE, 1, INSTR, FLAG_NO, 0),
+ MC_ENTRY(0x0000, 0x0000, 40, OUT_NONE, 0, INSTR, FLAG_NO, 0),
+ MC_ENTRY(0x4000, 0xF000, 24, OUT_IP0, 4, INSTR, FLAG_IPV4, 1),
+ MC_ENTRY(0x6000, 0xF000, 27, OUT_IP0, 3, INSTR, FLAG_IPV6, 0),
+ MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_NO, 0),
+ MC_ENTRY(0x0000, 0x0000, 25, OUT_IP3, 2, INSTR, FLAG_NO, 0),
+ MC_ENTRY(0x0000, 0x0000, 26, OUT_SIP0, 4, INSTR, FLAG_NO, 0),
+ MC_ENTRY(0x0000, 0x0000, 40, OUT_NONE, 0, LENACCU, FLAG_NO, 0),
+ MC_ENTRY(0x1100, 0xFF00, 39, OUT_PROT, 1, INSTR, FLAG_NO, 0),
+ MC_ENTRY(0x0600, 0xFF00, 39, OUT_PROT, 1, INSTR, FLAG_NO, 0),
+ MC_ENTRY(0x0000, 0xFF00, 33, OUT_IP3, 17, INSTR, FLAG_HOP, 0),
+ MC_ENTRY(0x2B00, 0xFF00, 33, OUT_IP3, 17, INSTR, FLAG_NN1, 0),
+ MC_ENTRY(0x3C00, 0xFF00, 33, OUT_IP3, 17, INSTR, FLAG_NN2, 0),
+ MC_ENTRY(0x0000, 0x0000, 39, OUT_PROT, 1, INSTR, FLAG_NO, 0),
+ MC_ENTRY(0x0000, 0x00E0, 35, OUT_NONE, 0, INSTR, FLAG_NO, 0),
+ MC_ENTRY(0x0000, 0x0000, 40, OUT_NONE, 0, INSTR, FLAG_NO, 0),
+ MC_ENTRY(0x0000, 0xFF00, 33, OUT_NONE, 0, IPV6, FLAG_HOP, 0),
+ MC_ENTRY(0x2B00, 0xFF00, 33, OUT_NONE, 0, IPV6, FLAG_NN1, 0),
+ MC_ENTRY(0x3C00, 0xFF00, 33, OUT_NONE, 0, IPV6, FLAG_NN2, 0),
+ MC_ENTRY(0x0000, 0x0000, 40, OUT_PROT, 1, IPV6, FLAG_NO, 0),
+ MC_ENTRY(0x0000, 0x0000, 40, OUT_SIP0, 16, INSTR, FLAG_NO, 0),
+ MC_ENTRY(0x0000, 0x0000, 41, OUT_APP0, 4, INSTR, FLAG_IGMP, 0),
+ MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0),
+ MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0),
+ MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0),
+ MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0),
+ MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0),
+ MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0),
+ MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0),
+ MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0),
+ MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0),
+ MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0),
+ MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0),
+ MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0),
+ MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0),
+ MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0),
+ MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0),
+ MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0),
+ MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0),
+ MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0),
+ MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0),
+ MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0),
+ MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0),
+ MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0),
+ MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE, 0, INSTR, FLAG_END, 0),
+};
diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c
index 54e0ca6ed730..86b6464b4525 100644
--- a/drivers/net/dsa/microchip/ksz_common.c
+++ b/drivers/net/dsa/microchip/ksz_common.c
@@ -1117,11 +1117,6 @@ static int ksz_switch_init(struct ksz_device *dev)
{
int i;
- mutex_init(&dev->reg_mutex);
- mutex_init(&dev->stats_mutex);
- mutex_init(&dev->alu_mutex);
- mutex_init(&dev->vlan_mutex);
-
dev->ds->ops = &ksz_switch_ops;
for (i = 0; i < ARRAY_SIZE(ksz_switch_chips); i++) {
@@ -1206,6 +1201,11 @@ int ksz_switch_register(struct ksz_device *dev)
if (dev->pdata)
dev->chip_id = dev->pdata->chip_id;
+ mutex_init(&dev->reg_mutex);
+ mutex_init(&dev->stats_mutex);
+ mutex_init(&dev->alu_mutex);
+ mutex_init(&dev->vlan_mutex);
+
if (ksz_switch_detect(dev))
return -EINVAL;
diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
index 62e486652e62..a5de9bffe5be 100644
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -658,11 +658,7 @@ static void mt7530_adjust_link(struct dsa_switch *ds, int port,
if (phydev->asym_pause)
rmt_adv |= LPA_PAUSE_ASYM;
- if (phydev->advertising & ADVERTISED_Pause)
- lcl_adv |= ADVERTISE_PAUSE_CAP;
- if (phydev->advertising & ADVERTISED_Asym_Pause)
- lcl_adv |= ADVERTISE_PAUSE_ASYM;
-
+ lcl_adv = ethtool_adv_to_lcl_adv_t(phydev->advertising);
flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
if (flowctrl & FLOW_CTRL_TX)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 8da3d39e3218..e05d4eddc935 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -434,7 +434,7 @@ static int mv88e6xxx_g1_irq_setup(struct mv88e6xxx_chip *chip)
err = request_threaded_irq(chip->irq, NULL,
mv88e6xxx_g1_irq_thread_fn,
- IRQF_ONESHOT,
+ IRQF_ONESHOT | IRQF_SHARED,
dev_name(chip->dev), chip);
if (err)
mv88e6xxx_g1_irq_free_common(chip);
@@ -575,6 +575,13 @@ restore_link:
return err;
}
+static int mv88e6xxx_phy_is_internal(struct dsa_switch *ds, int port)
+{
+ struct mv88e6xxx_chip *chip = ds->priv;
+
+ return port < chip->info->num_internal_phys;
+}
+
/* We expect the switch to perform auto negotiation if there is a real
* phy. However, in the case of a fixed link phy, we force the port
* settings from the fixed link settings.
@@ -585,7 +592,8 @@ static void mv88e6xxx_adjust_link(struct dsa_switch *ds, int port,
struct mv88e6xxx_chip *chip = ds->priv;
int err;
- if (!phy_is_pseudo_fixed_link(phydev))
+ if (!phy_is_pseudo_fixed_link(phydev) &&
+ mv88e6xxx_phy_is_internal(ds, port))
return;
mutex_lock(&chip->reg_lock);
@@ -709,13 +717,17 @@ static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port,
struct mv88e6xxx_chip *chip = ds->priv;
int speed, duplex, link, pause, err;
- if (mode == MLO_AN_PHY)
+ if ((mode == MLO_AN_PHY) && mv88e6xxx_phy_is_internal(ds, port))
return;
if (mode == MLO_AN_FIXED) {
link = LINK_FORCED_UP;
speed = state->speed;
duplex = state->duplex;
+ } else if (!mv88e6xxx_phy_is_internal(ds, port)) {
+ link = state->link;
+ speed = state->speed;
+ duplex = state->duplex;
} else {
speed = SPEED_UNFORCED;
duplex = DUPLEX_UNFORCED;
@@ -2895,7 +2907,7 @@ static const struct mv88e6xxx_ops mv88e6141_ops = {
.port_set_link = mv88e6xxx_port_set_link,
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
- .port_set_speed = mv88e6390_port_set_speed,
+ .port_set_speed = mv88e6341_port_set_speed,
.port_tag_remap = mv88e6095_port_tag_remap,
.port_set_frame_mode = mv88e6351_port_set_frame_mode,
.port_set_egress_floods = mv88e6352_port_set_egress_floods,
@@ -3160,6 +3172,8 @@ static const struct mv88e6xxx_ops mv88e6176_ops = {
.vtu_getnext = mv88e6352_g1_vtu_getnext,
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
.serdes_power = mv88e6352_serdes_power,
+ .serdes_irq_setup = mv88e6352_serdes_irq_setup,
+ .serdes_irq_free = mv88e6352_serdes_irq_free,
.gpio_ops = &mv88e6352_gpio_ops,
.phylink_validate = mv88e6352_phylink_validate,
};
@@ -3366,6 +3380,8 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
.vtu_getnext = mv88e6352_g1_vtu_getnext,
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
.serdes_power = mv88e6352_serdes_power,
+ .serdes_irq_setup = mv88e6352_serdes_irq_setup,
+ .serdes_irq_free = mv88e6352_serdes_irq_free,
.gpio_ops = &mv88e6352_gpio_ops,
.avb_ops = &mv88e6352_avb_ops,
.ptp_ops = &mv88e6352_ptp_ops,
@@ -3512,7 +3528,7 @@ static const struct mv88e6xxx_ops mv88e6341_ops = {
.port_set_link = mv88e6xxx_port_set_link,
.port_set_duplex = mv88e6xxx_port_set_duplex,
.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
- .port_set_speed = mv88e6390_port_set_speed,
+ .port_set_speed = mv88e6341_port_set_speed,
.port_tag_remap = mv88e6095_port_tag_remap,
.port_set_frame_mode = mv88e6351_port_set_frame_mode,
.port_set_egress_floods = mv88e6352_port_set_egress_floods,
@@ -3664,6 +3680,8 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
.vtu_getnext = mv88e6352_g1_vtu_getnext,
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
.serdes_power = mv88e6352_serdes_power,
+ .serdes_irq_setup = mv88e6352_serdes_irq_setup,
+ .serdes_irq_free = mv88e6352_serdes_irq_free,
.gpio_ops = &mv88e6352_gpio_ops,
.avb_ops = &mv88e6352_avb_ops,
.ptp_ops = &mv88e6352_ptp_ops,
diff --git a/drivers/net/dsa/mv88e6xxx/global1.c b/drivers/net/dsa/mv88e6xxx/global1.c
index d721ccf7d8be..38e399e0f30e 100644
--- a/drivers/net/dsa/mv88e6xxx/global1.c
+++ b/drivers/net/dsa/mv88e6xxx/global1.c
@@ -567,6 +567,8 @@ int mv88e6xxx_g1_stats_clear(struct mv88e6xxx_chip *chip)
if (err)
return err;
+ /* Keep the histogram mode bits */
+ val &= MV88E6XXX_G1_STATS_OP_HIST_RX_TX;
val |= MV88E6XXX_G1_STATS_OP_BUSY | MV88E6XXX_G1_STATS_OP_FLUSH_ALL;
err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_STATS_OP, val);
diff --git a/drivers/net/dsa/mv88e6xxx/phy.c b/drivers/net/dsa/mv88e6xxx/phy.c
index 46af8052e535..152a65d46e0b 100644
--- a/drivers/net/dsa/mv88e6xxx/phy.c
+++ b/drivers/net/dsa/mv88e6xxx/phy.c
@@ -110,6 +110,9 @@ int mv88e6xxx_phy_page_write(struct mv88e6xxx_chip *chip, int phy,
err = mv88e6xxx_phy_page_get(chip, phy, page);
if (!err) {
err = mv88e6xxx_phy_write(chip, phy, MV88E6XXX_PHY_PAGE, page);
+ if (!err)
+ err = mv88e6xxx_phy_write(chip, phy, reg, val);
+
mv88e6xxx_phy_page_put(chip, phy);
}
diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c
index 92945841c8e8..cd7db60a508b 100644
--- a/drivers/net/dsa/mv88e6xxx/port.c
+++ b/drivers/net/dsa/mv88e6xxx/port.c
@@ -228,8 +228,11 @@ static int mv88e6xxx_port_set_speed(struct mv88e6xxx_chip *chip, int port,
ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_1000;
break;
case 2500:
- ctrl = MV88E6390_PORT_MAC_CTL_SPEED_10000 |
- MV88E6390_PORT_MAC_CTL_ALTSPEED;
+ if (alt_bit)
+ ctrl = MV88E6390_PORT_MAC_CTL_SPEED_10000 |
+ MV88E6390_PORT_MAC_CTL_ALTSPEED;
+ else
+ ctrl = MV88E6390_PORT_MAC_CTL_SPEED_10000;
break;
case 10000:
/* all bits set, fall through... */
@@ -291,6 +294,24 @@ int mv88e6185_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed)
return mv88e6xxx_port_set_speed(chip, port, speed, false, false);
}
+/* Support 10, 100, 200, 1000, 2500 Mbps (e.g. 88E6341) */
+int mv88e6341_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed)
+{
+ if (speed == SPEED_MAX)
+ speed = port < 5 ? 1000 : 2500;
+
+ if (speed > 2500)
+ return -EOPNOTSUPP;
+
+ if (speed == 200 && port != 0)
+ return -EOPNOTSUPP;
+
+ if (speed == 2500 && port < 5)
+ return -EOPNOTSUPP;
+
+ return mv88e6xxx_port_set_speed(chip, port, speed, !port, true);
+}
+
/* Support 10, 100, 200, 1000 Mbps (e.g. 88E6352 family) */
int mv88e6352_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed)
{
diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h
index f32f56af8e35..36904c9bf955 100644
--- a/drivers/net/dsa/mv88e6xxx/port.h
+++ b/drivers/net/dsa/mv88e6xxx/port.h
@@ -269,6 +269,7 @@ int mv88e6xxx_port_set_duplex(struct mv88e6xxx_chip *chip, int port, int dup);
int mv88e6065_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed);
int mv88e6185_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed);
+int mv88e6341_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed);
int mv88e6352_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed);
int mv88e6390_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed);
int mv88e6390x_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed);
diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c
index e82983975754..bb69650ff772 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.c
+++ b/drivers/net/dsa/mv88e6xxx/serdes.c
@@ -185,6 +185,111 @@ int mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
return ARRAY_SIZE(mv88e6352_serdes_hw_stats);
}
+static void mv88e6352_serdes_irq_link(struct mv88e6xxx_chip *chip, int port)
+{
+ struct dsa_switch *ds = chip->ds;
+ u16 status;
+ bool up;
+
+ mv88e6352_serdes_read(chip, MII_BMSR, &status);
+
+ /* Status must be read twice in order to give the current link
+ * status. Otherwise the change in link status since the last
+ * read of the register is returned.
+ */
+ mv88e6352_serdes_read(chip, MII_BMSR, &status);
+
+ up = status & BMSR_LSTATUS;
+
+ dsa_port_phylink_mac_change(ds, port, up);
+}
+
+static irqreturn_t mv88e6352_serdes_thread_fn(int irq, void *dev_id)
+{
+ struct mv88e6xxx_port *port = dev_id;
+ struct mv88e6xxx_chip *chip = port->chip;
+ irqreturn_t ret = IRQ_NONE;
+ u16 status;
+ int err;
+
+ mutex_lock(&chip->reg_lock);
+
+ err = mv88e6352_serdes_read(chip, MV88E6352_SERDES_INT_STATUS, &status);
+ if (err)
+ goto out;
+
+ if (status & MV88E6352_SERDES_INT_LINK_CHANGE) {
+ ret = IRQ_HANDLED;
+ mv88e6352_serdes_irq_link(chip, port->port);
+ }
+out:
+ mutex_unlock(&chip->reg_lock);
+
+ return ret;
+}
+
+static int mv88e6352_serdes_irq_enable(struct mv88e6xxx_chip *chip)
+{
+ return mv88e6352_serdes_write(chip, MV88E6352_SERDES_INT_ENABLE,
+ MV88E6352_SERDES_INT_LINK_CHANGE);
+}
+
+static int mv88e6352_serdes_irq_disable(struct mv88e6xxx_chip *chip)
+{
+ return mv88e6352_serdes_write(chip, MV88E6352_SERDES_INT_ENABLE, 0);
+}
+
+int mv88e6352_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port)
+{
+ int err;
+
+ if (!mv88e6352_port_has_serdes(chip, port))
+ return 0;
+
+ chip->ports[port].serdes_irq = irq_find_mapping(chip->g2_irq.domain,
+ MV88E6352_SERDES_IRQ);
+ if (chip->ports[port].serdes_irq < 0) {
+ dev_err(chip->dev, "Unable to map SERDES irq: %d\n",
+ chip->ports[port].serdes_irq);
+ return chip->ports[port].serdes_irq;
+ }
+
+ /* Requesting the IRQ will trigger irq callbacks. So we cannot
+ * hold the reg_lock.
+ */
+ mutex_unlock(&chip->reg_lock);
+ err = request_threaded_irq(chip->ports[port].serdes_irq, NULL,
+ mv88e6352_serdes_thread_fn,
+ IRQF_ONESHOT, "mv88e6xxx-serdes",
+ &chip->ports[port]);
+ mutex_lock(&chip->reg_lock);
+
+ if (err) {
+ dev_err(chip->dev, "Unable to request SERDES interrupt: %d\n",
+ err);
+ return err;
+ }
+
+ return mv88e6352_serdes_irq_enable(chip);
+}
+
+void mv88e6352_serdes_irq_free(struct mv88e6xxx_chip *chip, int port)
+{
+ if (!mv88e6352_port_has_serdes(chip, port))
+ return;
+
+ mv88e6352_serdes_irq_disable(chip);
+
+ /* Freeing the IRQ will trigger irq callbacks. So we cannot
+ * hold the reg_lock.
+ */
+ mutex_unlock(&chip->reg_lock);
+ free_irq(chip->ports[port].serdes_irq, &chip->ports[port]);
+ mutex_lock(&chip->reg_lock);
+
+ chip->ports[port].serdes_irq = 0;
+}
+
/* Return the SERDES lane address a port is using. Only Ports 9 and 10
* have SERDES lanes. Returns -ENODEV if a port does not have a lane.
*/
diff --git a/drivers/net/dsa/mv88e6xxx/serdes.h b/drivers/net/dsa/mv88e6xxx/serdes.h
index b1496de9c6fe..7870c5a9ef12 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.h
+++ b/drivers/net/dsa/mv88e6xxx/serdes.h
@@ -18,6 +18,19 @@
#define MV88E6352_ADDR_SERDES 0x0f
#define MV88E6352_SERDES_PAGE_FIBER 0x01
+#define MV88E6352_SERDES_IRQ 0x0b
+#define MV88E6352_SERDES_INT_ENABLE 0x12
+#define MV88E6352_SERDES_INT_SPEED_CHANGE BIT(14)
+#define MV88E6352_SERDES_INT_DUPLEX_CHANGE BIT(13)
+#define MV88E6352_SERDES_INT_PAGE_RX BIT(12)
+#define MV88E6352_SERDES_INT_AN_COMPLETE BIT(11)
+#define MV88E6352_SERDES_INT_LINK_CHANGE BIT(10)
+#define MV88E6352_SERDES_INT_SYMBOL_ERROR BIT(9)
+#define MV88E6352_SERDES_INT_FALSE_CARRIER BIT(8)
+#define MV88E6352_SERDES_INT_FIFO_OVER_UNDER BIT(7)
+#define MV88E6352_SERDES_INT_FIBRE_ENERGY BIT(4)
+#define MV88E6352_SERDES_INT_STATUS 0x13
+
#define MV88E6341_ADDR_SERDES 0x15
@@ -73,5 +86,8 @@ int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port,
int lane);
int mv88e6390_serdes_irq_disable(struct mv88e6xxx_chip *chip, int port,
int lane);
+int mv88e6352_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port);
+void mv88e6352_serdes_irq_free(struct mv88e6xxx_chip *chip, int port);
+
#endif
diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c
index cdcde7f8e0b2..7e97e620bd44 100644
--- a/drivers/net/dsa/qca8k.c
+++ b/drivers/net/dsa/qca8k.c
@@ -955,8 +955,7 @@ qca8k_set_pm(struct qca8k_priv *priv, int enable)
static int qca8k_suspend(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct qca8k_priv *priv = platform_get_drvdata(pdev);
+ struct qca8k_priv *priv = dev_get_drvdata(dev);
qca8k_set_pm(priv, 0);
@@ -965,8 +964,7 @@ static int qca8k_suspend(struct device *dev)
static int qca8k_resume(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct qca8k_priv *priv = platform_get_drvdata(pdev);
+ struct qca8k_priv *priv = dev_get_drvdata(dev);
qca8k_set_pm(priv, 1);
diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c
index 2a0ddec1dd56..3dcc61821ed5 100644
--- a/drivers/net/ethernet/8390/ax88796.c
+++ b/drivers/net/ethernet/8390/ax88796.c
@@ -377,9 +377,7 @@ static int ax_mii_probe(struct net_device *dev)
return ret;
}
- /* mask with MAC supported features */
- phy_dev->supported &= PHY_BASIC_FEATURES;
- phy_dev->advertising = phy_dev->supported;
+ phy_set_max_speed(phy_dev, SPEED_100);
netdev_info(dev, "PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n",
phy_dev->drv->name, phydev_name(phy_dev), phy_dev->irq);
diff --git a/drivers/net/ethernet/8390/etherh.c b/drivers/net/ethernet/8390/etherh.c
index 32e9627e3880..77191a281866 100644
--- a/drivers/net/ethernet/8390/etherh.c
+++ b/drivers/net/ethernet/8390/etherh.c
@@ -564,26 +564,29 @@ static void etherh_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *i
sizeof(info->bus_info));
}
-static int etherh_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int etherh_get_link_ksettings(struct net_device *dev,
+ struct ethtool_link_ksettings *cmd)
{
- cmd->supported = etherh_priv(dev)->supported;
- ethtool_cmd_speed_set(cmd, SPEED_10);
- cmd->duplex = DUPLEX_HALF;
- cmd->port = dev->if_port == IF_PORT_10BASET ? PORT_TP : PORT_BNC;
- cmd->autoneg = (dev->flags & IFF_AUTOMEDIA ?
- AUTONEG_ENABLE : AUTONEG_DISABLE);
+ ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
+ etherh_priv(dev)->supported);
+ cmd->base.speed = SPEED_10;
+ cmd->base.duplex = DUPLEX_HALF;
+ cmd->base.port = dev->if_port == IF_PORT_10BASET ? PORT_TP : PORT_BNC;
+ cmd->base.autoneg = (dev->flags & IFF_AUTOMEDIA ? AUTONEG_ENABLE :
+ AUTONEG_DISABLE);
return 0;
}
-static int etherh_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int etherh_set_link_ksettings(struct net_device *dev,
+ const struct ethtool_link_ksettings *cmd)
{
- switch (cmd->autoneg) {
+ switch (cmd->base.autoneg) {
case AUTONEG_ENABLE:
dev->flags |= IFF_AUTOMEDIA;
break;
case AUTONEG_DISABLE:
- switch (cmd->port) {
+ switch (cmd->base.port) {
case PORT_TP:
dev->if_port = IF_PORT_10BASET;
break;
@@ -622,12 +625,12 @@ static void etherh_set_msglevel(struct net_device *dev, u32 v)
}
static const struct ethtool_ops etherh_ethtool_ops = {
- .get_settings = etherh_get_settings,
- .set_settings = etherh_set_settings,
- .get_drvinfo = etherh_get_drvinfo,
- .get_ts_info = ethtool_op_get_ts_info,
- .get_msglevel = etherh_get_msglevel,
- .set_msglevel = etherh_set_msglevel,
+ .get_drvinfo = etherh_get_drvinfo,
+ .get_ts_info = ethtool_op_get_ts_info,
+ .get_msglevel = etherh_get_msglevel,
+ .set_msglevel = etherh_set_msglevel,
+ .get_link_ksettings = etherh_get_link_ksettings,
+ .set_link_ksettings = etherh_set_link_ksettings,
};
static const struct net_device_ops etherh_netdev_ops = {
diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index 6fde68aa13a4..885e00d17807 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -108,6 +108,13 @@ config LANTIQ_ETOP
---help---
Support for the MII0 inside the Lantiq SoC
+config LANTIQ_XRX200
+ tristate "Lantiq / Intel xRX200 PMAC network driver"
+ depends on SOC_TYPE_XWAY
+ ---help---
+ Support for the PMAC of the Gigabit switch (GSWIP) inside the
+ Lantiq / Intel VRX200 VDSL SoC
+
source "drivers/net/ethernet/marvell/Kconfig"
source "drivers/net/ethernet/mediatek/Kconfig"
source "drivers/net/ethernet/mellanox/Kconfig"
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
index b45d5f626b59..7b5bf9682066 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -49,6 +49,7 @@ obj-$(CONFIG_NET_VENDOR_XSCALE) += xscale/
obj-$(CONFIG_JME) += jme.o
obj-$(CONFIG_KORINA) += korina.o
obj-$(CONFIG_LANTIQ_ETOP) += lantiq_etop.o
+obj-$(CONFIG_LANTIQ_XRX200) += lantiq_xrx200.o
obj-$(CONFIG_NET_VENDOR_MARVELL) += marvell/
obj-$(CONFIG_NET_VENDOR_MEDIATEK) += mediatek/
obj-$(CONFIG_NET_VENDOR_MELLANOX) += mellanox/
diff --git a/drivers/net/ethernet/aeroflex/greth.c b/drivers/net/ethernet/aeroflex/greth.c
index 4309be3724ad..7c9348a26cbb 100644
--- a/drivers/net/ethernet/aeroflex/greth.c
+++ b/drivers/net/ethernet/aeroflex/greth.c
@@ -1279,9 +1279,9 @@ static int greth_mdio_probe(struct net_device *dev)
}
if (greth->gbit_mac)
- phy->supported &= PHY_GBIT_FEATURES;
+ phy_set_max_speed(phy, SPEED_1000);
else
- phy->supported &= PHY_BASIC_FEATURES;
+ phy_set_max_speed(phy, SPEED_100);
phy->advertising = phy->supported;
diff --git a/drivers/net/ethernet/agere/et131x.c b/drivers/net/ethernet/agere/et131x.c
index 48220b6c600d..ea34bcb868b5 100644
--- a/drivers/net/ethernet/agere/et131x.c
+++ b/drivers/net/ethernet/agere/et131x.c
@@ -3258,19 +3258,11 @@ static int et131x_mii_probe(struct net_device *netdev)
return PTR_ERR(phydev);
}
- phydev->supported &= (SUPPORTED_10baseT_Half |
- SUPPORTED_10baseT_Full |
- SUPPORTED_100baseT_Half |
- SUPPORTED_100baseT_Full |
- SUPPORTED_Autoneg |
- SUPPORTED_MII |
- SUPPORTED_TP);
+ phy_set_max_speed(phydev, SPEED_100);
if (adapter->pdev->device != ET131X_PCI_DEVICE_ID_FAST)
- phydev->supported |= SUPPORTED_1000baseT_Half |
- SUPPORTED_1000baseT_Full;
+ phy_set_max_speed(phydev, SPEED_1000);
- phydev->advertising = phydev->supported;
phydev->autoneg = AUTONEG_ENABLE;
phy_attached_info(phydev);
diff --git a/drivers/net/ethernet/alacritech/slic.h b/drivers/net/ethernet/alacritech/slic.h
index d0c388cfd52f..3add305d34b4 100644
--- a/drivers/net/ethernet/alacritech/slic.h
+++ b/drivers/net/ethernet/alacritech/slic.h
@@ -8,7 +8,6 @@
#include <linux/spinlock_types.h>
#include <linux/dma-mapping.h>
#include <linux/pci.h>
-#include <linux/netdevice.h>
#include <linux/list.h>
#include <linux/u64_stats_sync.h>
diff --git a/drivers/net/ethernet/allwinner/sun4i-emac.c b/drivers/net/ethernet/allwinner/sun4i-emac.c
index 3143de45baaa..e1acafa82214 100644
--- a/drivers/net/ethernet/allwinner/sun4i-emac.c
+++ b/drivers/net/ethernet/allwinner/sun4i-emac.c
@@ -172,8 +172,7 @@ static int emac_mdio_probe(struct net_device *dev)
}
/* mask with MAC supported features */
- phydev->supported &= PHY_BASIC_FEATURES;
- phydev->advertising = phydev->supported;
+ phy_set_max_speed(phydev, SPEED_100);
db->link = 0;
db->speed = 0;
diff --git a/drivers/net/ethernet/altera/altera_tse_main.c b/drivers/net/ethernet/altera/altera_tse_main.c
index baca8f704a45..02921d877c08 100644
--- a/drivers/net/ethernet/altera/altera_tse_main.c
+++ b/drivers/net/ethernet/altera/altera_tse_main.c
@@ -835,13 +835,10 @@ static int init_phy(struct net_device *dev)
}
/* Stop Advertising 1000BASE Capability if interface is not GMII
- * Note: Checkpatch throws CHECKs for the camel case defines below,
- * it's ok to ignore.
*/
if ((priv->phy_iface == PHY_INTERFACE_MODE_MII) ||
(priv->phy_iface == PHY_INTERFACE_MODE_RMII))
- phydev->advertising &= ~(SUPPORTED_1000baseT_Half |
- SUPPORTED_1000baseT_Full);
+ phy_set_max_speed(phydev, SPEED_100);
/* Broken HW is sometimes missing the pull-up resistor on the
* MDIO line, which results in reads to non-existent devices returning
diff --git a/drivers/net/ethernet/amazon/Kconfig b/drivers/net/ethernet/amazon/Kconfig
index 99b30353541a..9e87d7b8360f 100644
--- a/drivers/net/ethernet/amazon/Kconfig
+++ b/drivers/net/ethernet/amazon/Kconfig
@@ -17,7 +17,7 @@ if NET_VENDOR_AMAZON
config ENA_ETHERNET
tristate "Elastic Network Adapter (ENA) support"
- depends on (PCI_MSI && X86)
+ depends on PCI_MSI && !CPU_BIG_ENDIAN
---help---
This driver supports Elastic Network Adapter (ENA)"
diff --git a/drivers/net/ethernet/amazon/ena/ena_admin_defs.h b/drivers/net/ethernet/amazon/ena/ena_admin_defs.h
index 4532e574ebcd..9f80b73f90b1 100644
--- a/drivers/net/ethernet/amazon/ena/ena_admin_defs.h
+++ b/drivers/net/ethernet/amazon/ena/ena_admin_defs.h
@@ -32,115 +32,81 @@
#ifndef _ENA_ADMIN_H_
#define _ENA_ADMIN_H_
-enum ena_admin_aq_opcode {
- ENA_ADMIN_CREATE_SQ = 1,
-
- ENA_ADMIN_DESTROY_SQ = 2,
-
- ENA_ADMIN_CREATE_CQ = 3,
-
- ENA_ADMIN_DESTROY_CQ = 4,
- ENA_ADMIN_GET_FEATURE = 8,
-
- ENA_ADMIN_SET_FEATURE = 9,
-
- ENA_ADMIN_GET_STATS = 11,
+enum ena_admin_aq_opcode {
+ ENA_ADMIN_CREATE_SQ = 1,
+ ENA_ADMIN_DESTROY_SQ = 2,
+ ENA_ADMIN_CREATE_CQ = 3,
+ ENA_ADMIN_DESTROY_CQ = 4,
+ ENA_ADMIN_GET_FEATURE = 8,
+ ENA_ADMIN_SET_FEATURE = 9,
+ ENA_ADMIN_GET_STATS = 11,
};
enum ena_admin_aq_completion_status {
- ENA_ADMIN_SUCCESS = 0,
-
- ENA_ADMIN_RESOURCE_ALLOCATION_FAILURE = 1,
-
- ENA_ADMIN_BAD_OPCODE = 2,
-
- ENA_ADMIN_UNSUPPORTED_OPCODE = 3,
-
- ENA_ADMIN_MALFORMED_REQUEST = 4,
-
+ ENA_ADMIN_SUCCESS = 0,
+ ENA_ADMIN_RESOURCE_ALLOCATION_FAILURE = 1,
+ ENA_ADMIN_BAD_OPCODE = 2,
+ ENA_ADMIN_UNSUPPORTED_OPCODE = 3,
+ ENA_ADMIN_MALFORMED_REQUEST = 4,
/* Additional status is provided in ACQ entry extended_status */
- ENA_ADMIN_ILLEGAL_PARAMETER = 5,
-
- ENA_ADMIN_UNKNOWN_ERROR = 6,
+ ENA_ADMIN_ILLEGAL_PARAMETER = 5,
+ ENA_ADMIN_UNKNOWN_ERROR = 6,
+ ENA_ADMIN_RESOURCE_BUSY = 7,
};
enum ena_admin_aq_feature_id {
- ENA_ADMIN_DEVICE_ATTRIBUTES = 1,
-
- ENA_ADMIN_MAX_QUEUES_NUM = 2,
-
- ENA_ADMIN_HW_HINTS = 3,
-
- ENA_ADMIN_RSS_HASH_FUNCTION = 10,
-
- ENA_ADMIN_STATELESS_OFFLOAD_CONFIG = 11,
-
- ENA_ADMIN_RSS_REDIRECTION_TABLE_CONFIG = 12,
-
- ENA_ADMIN_MTU = 14,
-
- ENA_ADMIN_RSS_HASH_INPUT = 18,
-
- ENA_ADMIN_INTERRUPT_MODERATION = 20,
-
- ENA_ADMIN_AENQ_CONFIG = 26,
-
- ENA_ADMIN_LINK_CONFIG = 27,
-
- ENA_ADMIN_HOST_ATTR_CONFIG = 28,
-
- ENA_ADMIN_FEATURES_OPCODE_NUM = 32,
+ ENA_ADMIN_DEVICE_ATTRIBUTES = 1,
+ ENA_ADMIN_MAX_QUEUES_NUM = 2,
+ ENA_ADMIN_HW_HINTS = 3,
+ ENA_ADMIN_LLQ = 4,
+ ENA_ADMIN_RSS_HASH_FUNCTION = 10,
+ ENA_ADMIN_STATELESS_OFFLOAD_CONFIG = 11,
+ ENA_ADMIN_RSS_REDIRECTION_TABLE_CONFIG = 12,
+ ENA_ADMIN_MTU = 14,
+ ENA_ADMIN_RSS_HASH_INPUT = 18,
+ ENA_ADMIN_INTERRUPT_MODERATION = 20,
+ ENA_ADMIN_AENQ_CONFIG = 26,
+ ENA_ADMIN_LINK_CONFIG = 27,
+ ENA_ADMIN_HOST_ATTR_CONFIG = 28,
+ ENA_ADMIN_FEATURES_OPCODE_NUM = 32,
};
enum ena_admin_placement_policy_type {
/* descriptors and headers are in host memory */
- ENA_ADMIN_PLACEMENT_POLICY_HOST = 1,
-
+ ENA_ADMIN_PLACEMENT_POLICY_HOST = 1,
/* descriptors and headers are in device memory (a.k.a Low Latency
* Queue)
*/
- ENA_ADMIN_PLACEMENT_POLICY_DEV = 3,
+ ENA_ADMIN_PLACEMENT_POLICY_DEV = 3,
};
enum ena_admin_link_types {
- ENA_ADMIN_LINK_SPEED_1G = 0x1,
-
- ENA_ADMIN_LINK_SPEED_2_HALF_G = 0x2,
-
- ENA_ADMIN_LINK_SPEED_5G = 0x4,
-
- ENA_ADMIN_LINK_SPEED_10G = 0x8,
-
- ENA_ADMIN_LINK_SPEED_25G = 0x10,
-
- ENA_ADMIN_LINK_SPEED_40G = 0x20,
-
- ENA_ADMIN_LINK_SPEED_50G = 0x40,
-
- ENA_ADMIN_LINK_SPEED_100G = 0x80,
-
- ENA_ADMIN_LINK_SPEED_200G = 0x100,
-
- ENA_ADMIN_LINK_SPEED_400G = 0x200,
+ ENA_ADMIN_LINK_SPEED_1G = 0x1,
+ ENA_ADMIN_LINK_SPEED_2_HALF_G = 0x2,
+ ENA_ADMIN_LINK_SPEED_5G = 0x4,
+ ENA_ADMIN_LINK_SPEED_10G = 0x8,
+ ENA_ADMIN_LINK_SPEED_25G = 0x10,
+ ENA_ADMIN_LINK_SPEED_40G = 0x20,
+ ENA_ADMIN_LINK_SPEED_50G = 0x40,
+ ENA_ADMIN_LINK_SPEED_100G = 0x80,
+ ENA_ADMIN_LINK_SPEED_200G = 0x100,
+ ENA_ADMIN_LINK_SPEED_400G = 0x200,
};
enum ena_admin_completion_policy_type {
/* completion queue entry for each sq descriptor */
- ENA_ADMIN_COMPLETION_POLICY_DESC = 0,
-
+ ENA_ADMIN_COMPLETION_POLICY_DESC = 0,
/* completion queue entry upon request in sq descriptor */
- ENA_ADMIN_COMPLETION_POLICY_DESC_ON_DEMAND = 1,
-
+ ENA_ADMIN_COMPLETION_POLICY_DESC_ON_DEMAND = 1,
/* current queue head pointer is updated in OS memory upon sq
* descriptor request
*/
- ENA_ADMIN_COMPLETION_POLICY_HEAD_ON_DEMAND = 2,
-
+ ENA_ADMIN_COMPLETION_POLICY_HEAD_ON_DEMAND = 2,
/* current queue head pointer is updated in OS memory for each sq
* descriptor
*/
- ENA_ADMIN_COMPLETION_POLICY_HEAD = 3,
+ ENA_ADMIN_COMPLETION_POLICY_HEAD = 3,
};
/* basic stats return ena_admin_basic_stats while extanded stats return a
@@ -148,15 +114,13 @@ enum ena_admin_completion_policy_type {
* device id
*/
enum ena_admin_get_stats_type {
- ENA_ADMIN_GET_STATS_TYPE_BASIC = 0,
-
- ENA_ADMIN_GET_STATS_TYPE_EXTENDED = 1,
+ ENA_ADMIN_GET_STATS_TYPE_BASIC = 0,
+ ENA_ADMIN_GET_STATS_TYPE_EXTENDED = 1,
};
enum ena_admin_get_stats_scope {
- ENA_ADMIN_SPECIFIC_QUEUE = 0,
-
- ENA_ADMIN_ETH_TRAFFIC = 1,
+ ENA_ADMIN_SPECIFIC_QUEUE = 0,
+ ENA_ADMIN_ETH_TRAFFIC = 1,
};
struct ena_admin_aq_common_desc {
@@ -227,7 +191,9 @@ struct ena_admin_acq_common_desc {
u16 extended_status;
- /* serves as a hint what AQ entries can be revoked */
+ /* indicates to the driver which AQ entry has been consumed by the
+ * device and could be reused
+ */
u16 sq_head_indx;
};
@@ -296,9 +262,8 @@ struct ena_admin_aq_create_sq_cmd {
};
enum ena_admin_sq_direction {
- ENA_ADMIN_SQ_DIRECTION_TX = 1,
-
- ENA_ADMIN_SQ_DIRECTION_RX = 2,
+ ENA_ADMIN_SQ_DIRECTION_TX = 1,
+ ENA_ADMIN_SQ_DIRECTION_RX = 2,
};
struct ena_admin_acq_create_sq_resp_desc {
@@ -483,8 +448,85 @@ struct ena_admin_device_attr_feature_desc {
u32 max_mtu;
};
+enum ena_admin_llq_header_location {
+ /* header is in descriptor list */
+ ENA_ADMIN_INLINE_HEADER = 1,
+ /* header in a separate ring, implies 16B descriptor list entry */
+ ENA_ADMIN_HEADER_RING = 2,
+};
+
+enum ena_admin_llq_ring_entry_size {
+ ENA_ADMIN_LIST_ENTRY_SIZE_128B = 1,
+ ENA_ADMIN_LIST_ENTRY_SIZE_192B = 2,
+ ENA_ADMIN_LIST_ENTRY_SIZE_256B = 4,
+};
+
+enum ena_admin_llq_num_descs_before_header {
+ ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_0 = 0,
+ ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_1 = 1,
+ ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_2 = 2,
+ ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_4 = 4,
+ ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_8 = 8,
+};
+
+/* packet descriptor list entry always starts with one or more descriptors,
+ * followed by a header. The rest of the descriptors are located in the
+ * beginning of the subsequent entry. Stride refers to how the rest of the
+ * descriptors are placed. This field is relevant only for inline header
+ * mode
+ */
+enum ena_admin_llq_stride_ctrl {
+ ENA_ADMIN_SINGLE_DESC_PER_ENTRY = 1,
+ ENA_ADMIN_MULTIPLE_DESCS_PER_ENTRY = 2,
+};
+
+struct ena_admin_feature_llq_desc {
+ u32 max_llq_num;
+
+ u32 max_llq_depth;
+
+ /* specify the header locations the device supports. bitfield of
+ * enum ena_admin_llq_header_location.
+ */
+ u16 header_location_ctrl_supported;
+
+ /* the header location the driver selected to use. */
+ u16 header_location_ctrl_enabled;
+
+ /* if inline header is specified - this is the size of descriptor
+ * list entry. If header in a separate ring is specified - this is
+ * the size of header ring entry. bitfield of enum
+ * ena_admin_llq_ring_entry_size. specify the entry sizes the device
+ * supports
+ */
+ u16 entry_size_ctrl_supported;
+
+ /* the entry size the driver selected to use. */
+ u16 entry_size_ctrl_enabled;
+
+ /* valid only if inline header is specified. First entry associated
+ * with the packet includes descriptors and header. Rest of the
+ * entries occupied by descriptors. This parameter defines the max
+ * number of descriptors precedding the header in the first entry.
+ * The field is bitfield of enum
+ * ena_admin_llq_num_descs_before_header and specify the values the
+ * device supports
+ */
+ u16 desc_num_before_header_supported;
+
+ /* the desire field the driver selected to use */
+ u16 desc_num_before_header_enabled;
+
+ /* valid only if inline was chosen. bitfield of enum
+ * ena_admin_llq_stride_ctrl
+ */
+ u16 descriptors_stride_ctrl_supported;
+
+ /* the stride control the driver selected to use */
+ u16 descriptors_stride_ctrl_enabled;
+};
+
struct ena_admin_queue_feature_desc {
- /* including LLQs */
u32 max_sq_num;
u32 max_sq_depth;
@@ -493,9 +535,9 @@ struct ena_admin_queue_feature_desc {
u32 max_cq_depth;
- u32 max_llq_num;
+ u32 max_legacy_llq_num;
- u32 max_llq_depth;
+ u32 max_legacy_llq_depth;
u32 max_header_size;
@@ -583,9 +625,8 @@ struct ena_admin_feature_offload_desc {
};
enum ena_admin_hash_functions {
- ENA_ADMIN_TOEPLITZ = 1,
-
- ENA_ADMIN_CRC32 = 2,
+ ENA_ADMIN_TOEPLITZ = 1,
+ ENA_ADMIN_CRC32 = 2,
};
struct ena_admin_feature_rss_flow_hash_control {
@@ -611,50 +652,35 @@ struct ena_admin_feature_rss_flow_hash_function {
/* RSS flow hash protocols */
enum ena_admin_flow_hash_proto {
- ENA_ADMIN_RSS_TCP4 = 0,
-
- ENA_ADMIN_RSS_UDP4 = 1,
-
- ENA_ADMIN_RSS_TCP6 = 2,
-
- ENA_ADMIN_RSS_UDP6 = 3,
-
- ENA_ADMIN_RSS_IP4 = 4,
-
- ENA_ADMIN_RSS_IP6 = 5,
-
- ENA_ADMIN_RSS_IP4_FRAG = 6,
-
- ENA_ADMIN_RSS_NOT_IP = 7,
-
+ ENA_ADMIN_RSS_TCP4 = 0,
+ ENA_ADMIN_RSS_UDP4 = 1,
+ ENA_ADMIN_RSS_TCP6 = 2,
+ ENA_ADMIN_RSS_UDP6 = 3,
+ ENA_ADMIN_RSS_IP4 = 4,
+ ENA_ADMIN_RSS_IP6 = 5,
+ ENA_ADMIN_RSS_IP4_FRAG = 6,
+ ENA_ADMIN_RSS_NOT_IP = 7,
/* TCPv6 with extension header */
- ENA_ADMIN_RSS_TCP6_EX = 8,
-
+ ENA_ADMIN_RSS_TCP6_EX = 8,
/* IPv6 with extension header */
- ENA_ADMIN_RSS_IP6_EX = 9,
-
- ENA_ADMIN_RSS_PROTO_NUM = 16,
+ ENA_ADMIN_RSS_IP6_EX = 9,
+ ENA_ADMIN_RSS_PROTO_NUM = 16,
};
/* RSS flow hash fields */
enum ena_admin_flow_hash_fields {
/* Ethernet Dest Addr */
- ENA_ADMIN_RSS_L2_DA = BIT(0),
-
+ ENA_ADMIN_RSS_L2_DA = BIT(0),
/* Ethernet Src Addr */
- ENA_ADMIN_RSS_L2_SA = BIT(1),
-
+ ENA_ADMIN_RSS_L2_SA = BIT(1),
/* ipv4/6 Dest Addr */
- ENA_ADMIN_RSS_L3_DA = BIT(2),
-
+ ENA_ADMIN_RSS_L3_DA = BIT(2),
/* ipv4/6 Src Addr */
- ENA_ADMIN_RSS_L3_SA = BIT(3),
-
+ ENA_ADMIN_RSS_L3_SA = BIT(3),
/* tcp/udp Dest Port */
- ENA_ADMIN_RSS_L4_DP = BIT(4),
-
+ ENA_ADMIN_RSS_L4_DP = BIT(4),
/* tcp/udp Src Port */
- ENA_ADMIN_RSS_L4_SP = BIT(5),
+ ENA_ADMIN_RSS_L4_SP = BIT(5),
};
struct ena_admin_proto_input {
@@ -693,15 +719,13 @@ struct ena_admin_feature_rss_flow_hash_input {
};
enum ena_admin_os_type {
- ENA_ADMIN_OS_LINUX = 1,
-
- ENA_ADMIN_OS_WIN = 2,
-
- ENA_ADMIN_OS_DPDK = 3,
-
- ENA_ADMIN_OS_FREEBSD = 4,
-
- ENA_ADMIN_OS_IPXE = 5,
+ ENA_ADMIN_OS_LINUX = 1,
+ ENA_ADMIN_OS_WIN = 2,
+ ENA_ADMIN_OS_DPDK = 3,
+ ENA_ADMIN_OS_FREEBSD = 4,
+ ENA_ADMIN_OS_IPXE = 5,
+ ENA_ADMIN_OS_ESXI = 6,
+ ENA_ADMIN_OS_GROUPS_NUM = 6,
};
struct ena_admin_host_info {
@@ -723,11 +747,27 @@ struct ena_admin_host_info {
/* 7:0 : major
* 15:8 : minor
* 23:16 : sub_minor
+ * 31:24 : module_type
*/
u32 driver_version;
/* features bitmap */
- u32 supported_network_features[4];
+ u32 supported_network_features[2];
+
+ /* ENA spec version of driver */
+ u16 ena_spec_version;
+
+ /* ENA device's Bus, Device and Function
+ * 2:0 : function
+ * 7:3 : device
+ * 15:8 : bus
+ */
+ u16 bdf;
+
+ /* Number of CPUs */
+ u16 num_cpus;
+
+ u16 reserved;
};
struct ena_admin_rss_ind_table_entry {
@@ -800,6 +840,8 @@ struct ena_admin_get_feat_resp {
struct ena_admin_device_attr_feature_desc dev_attr;
+ struct ena_admin_feature_llq_desc llq;
+
struct ena_admin_queue_feature_desc max_queue;
struct ena_admin_feature_aenq_desc aenq;
@@ -847,6 +889,9 @@ struct ena_admin_set_feat_cmd {
/* rss indirection table */
struct ena_admin_feature_rss_ind_table ind_table;
+
+ /* LLQ configuration */
+ struct ena_admin_feature_llq_desc llq;
} u;
};
@@ -875,25 +920,18 @@ struct ena_admin_aenq_common_desc {
/* asynchronous event notification groups */
enum ena_admin_aenq_group {
- ENA_ADMIN_LINK_CHANGE = 0,
-
- ENA_ADMIN_FATAL_ERROR = 1,
-
- ENA_ADMIN_WARNING = 2,
-
- ENA_ADMIN_NOTIFICATION = 3,
-
- ENA_ADMIN_KEEP_ALIVE = 4,
-
- ENA_ADMIN_AENQ_GROUPS_NUM = 5,
+ ENA_ADMIN_LINK_CHANGE = 0,
+ ENA_ADMIN_FATAL_ERROR = 1,
+ ENA_ADMIN_WARNING = 2,
+ ENA_ADMIN_NOTIFICATION = 3,
+ ENA_ADMIN_KEEP_ALIVE = 4,
+ ENA_ADMIN_AENQ_GROUPS_NUM = 5,
};
enum ena_admin_aenq_notification_syndrom {
- ENA_ADMIN_SUSPEND = 0,
-
- ENA_ADMIN_RESUME = 1,
-
- ENA_ADMIN_UPDATE_HINTS = 2,
+ ENA_ADMIN_SUSPEND = 0,
+ ENA_ADMIN_RESUME = 1,
+ ENA_ADMIN_UPDATE_HINTS = 2,
};
struct ena_admin_aenq_entry {
@@ -928,27 +966,27 @@ struct ena_admin_ena_mmio_req_read_less_resp {
};
/* aq_common_desc */
-#define ENA_ADMIN_AQ_COMMON_DESC_COMMAND_ID_MASK GENMASK(11, 0)
-#define ENA_ADMIN_AQ_COMMON_DESC_PHASE_MASK BIT(0)
-#define ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_SHIFT 1
-#define ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_MASK BIT(1)
-#define ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_INDIRECT_SHIFT 2
-#define ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_INDIRECT_MASK BIT(2)
+#define ENA_ADMIN_AQ_COMMON_DESC_COMMAND_ID_MASK GENMASK(11, 0)
+#define ENA_ADMIN_AQ_COMMON_DESC_PHASE_MASK BIT(0)
+#define ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_SHIFT 1
+#define ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_MASK BIT(1)
+#define ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_INDIRECT_SHIFT 2
+#define ENA_ADMIN_AQ_COMMON_DESC_CTRL_DATA_INDIRECT_MASK BIT(2)
/* sq */
-#define ENA_ADMIN_SQ_SQ_DIRECTION_SHIFT 5
-#define ENA_ADMIN_SQ_SQ_DIRECTION_MASK GENMASK(7, 5)
+#define ENA_ADMIN_SQ_SQ_DIRECTION_SHIFT 5
+#define ENA_ADMIN_SQ_SQ_DIRECTION_MASK GENMASK(7, 5)
/* acq_common_desc */
-#define ENA_ADMIN_ACQ_COMMON_DESC_COMMAND_ID_MASK GENMASK(11, 0)
-#define ENA_ADMIN_ACQ_COMMON_DESC_PHASE_MASK BIT(0)
+#define ENA_ADMIN_ACQ_COMMON_DESC_COMMAND_ID_MASK GENMASK(11, 0)
+#define ENA_ADMIN_ACQ_COMMON_DESC_PHASE_MASK BIT(0)
/* aq_create_sq_cmd */
-#define ENA_ADMIN_AQ_CREATE_SQ_CMD_SQ_DIRECTION_SHIFT 5
-#define ENA_ADMIN_AQ_CREATE_SQ_CMD_SQ_DIRECTION_MASK GENMASK(7, 5)
-#define ENA_ADMIN_AQ_CREATE_SQ_CMD_PLACEMENT_POLICY_MASK GENMASK(3, 0)
-#define ENA_ADMIN_AQ_CREATE_SQ_CMD_COMPLETION_POLICY_SHIFT 4
-#define ENA_ADMIN_AQ_CREATE_SQ_CMD_COMPLETION_POLICY_MASK GENMASK(6, 4)
+#define ENA_ADMIN_AQ_CREATE_SQ_CMD_SQ_DIRECTION_SHIFT 5
+#define ENA_ADMIN_AQ_CREATE_SQ_CMD_SQ_DIRECTION_MASK GENMASK(7, 5)
+#define ENA_ADMIN_AQ_CREATE_SQ_CMD_PLACEMENT_POLICY_MASK GENMASK(3, 0)
+#define ENA_ADMIN_AQ_CREATE_SQ_CMD_COMPLETION_POLICY_SHIFT 4
+#define ENA_ADMIN_AQ_CREATE_SQ_CMD_COMPLETION_POLICY_MASK GENMASK(6, 4)
#define ENA_ADMIN_AQ_CREATE_SQ_CMD_IS_PHYSICALLY_CONTIGUOUS_MASK BIT(0)
/* aq_create_cq_cmd */
@@ -957,12 +995,12 @@ struct ena_admin_ena_mmio_req_read_less_resp {
#define ENA_ADMIN_AQ_CREATE_CQ_CMD_CQ_ENTRY_SIZE_WORDS_MASK GENMASK(4, 0)
/* get_set_feature_common_desc */
-#define ENA_ADMIN_GET_SET_FEATURE_COMMON_DESC_SELECT_MASK GENMASK(1, 0)
+#define ENA_ADMIN_GET_SET_FEATURE_COMMON_DESC_SELECT_MASK GENMASK(1, 0)
/* get_feature_link_desc */
-#define ENA_ADMIN_GET_FEATURE_LINK_DESC_AUTONEG_MASK BIT(0)
-#define ENA_ADMIN_GET_FEATURE_LINK_DESC_DUPLEX_SHIFT 1
-#define ENA_ADMIN_GET_FEATURE_LINK_DESC_DUPLEX_MASK BIT(1)
+#define ENA_ADMIN_GET_FEATURE_LINK_DESC_AUTONEG_MASK BIT(0)
+#define ENA_ADMIN_GET_FEATURE_LINK_DESC_DUPLEX_SHIFT 1
+#define ENA_ADMIN_GET_FEATURE_LINK_DESC_DUPLEX_MASK BIT(1)
/* feature_offload_desc */
#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L3_CSUM_IPV4_MASK BIT(0)
@@ -974,19 +1012,19 @@ struct ena_admin_ena_mmio_req_read_less_resp {
#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV6_CSUM_PART_MASK BIT(3)
#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV6_CSUM_FULL_SHIFT 4
#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TX_L4_IPV6_CSUM_FULL_MASK BIT(4)
-#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV4_SHIFT 5
-#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV4_MASK BIT(5)
-#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV6_SHIFT 6
-#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV6_MASK BIT(6)
-#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_ECN_SHIFT 7
-#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_ECN_MASK BIT(7)
+#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV4_SHIFT 5
+#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV4_MASK BIT(5)
+#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV6_SHIFT 6
+#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_IPV6_MASK BIT(6)
+#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_ECN_SHIFT 7
+#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_TSO_ECN_MASK BIT(7)
#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L3_CSUM_IPV4_MASK BIT(0)
#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L4_IPV4_CSUM_SHIFT 1
#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L4_IPV4_CSUM_MASK BIT(1)
#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L4_IPV6_CSUM_SHIFT 2
#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_L4_IPV6_CSUM_MASK BIT(2)
-#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_HASH_SHIFT 3
-#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_HASH_MASK BIT(3)
+#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_HASH_SHIFT 3
+#define ENA_ADMIN_FEATURE_OFFLOAD_DESC_RX_HASH_MASK BIT(3)
/* feature_rss_flow_hash_function */
#define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_FUNCTION_FUNCS_MASK GENMASK(7, 0)
@@ -994,25 +1032,32 @@ struct ena_admin_ena_mmio_req_read_less_resp {
/* feature_rss_flow_hash_input */
#define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_L3_SORT_SHIFT 1
-#define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_L3_SORT_MASK BIT(1)
+#define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_L3_SORT_MASK BIT(1)
#define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_L4_SORT_SHIFT 2
-#define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_L4_SORT_MASK BIT(2)
+#define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_L4_SORT_MASK BIT(2)
#define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_ENABLE_L3_SORT_SHIFT 1
#define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_ENABLE_L3_SORT_MASK BIT(1)
#define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_ENABLE_L4_SORT_SHIFT 2
#define ENA_ADMIN_FEATURE_RSS_FLOW_HASH_INPUT_ENABLE_L4_SORT_MASK BIT(2)
/* host_info */
-#define ENA_ADMIN_HOST_INFO_MAJOR_MASK GENMASK(7, 0)
-#define ENA_ADMIN_HOST_INFO_MINOR_SHIFT 8
-#define ENA_ADMIN_HOST_INFO_MINOR_MASK GENMASK(15, 8)
-#define ENA_ADMIN_HOST_INFO_SUB_MINOR_SHIFT 16
-#define ENA_ADMIN_HOST_INFO_SUB_MINOR_MASK GENMASK(23, 16)
+#define ENA_ADMIN_HOST_INFO_MAJOR_MASK GENMASK(7, 0)
+#define ENA_ADMIN_HOST_INFO_MINOR_SHIFT 8
+#define ENA_ADMIN_HOST_INFO_MINOR_MASK GENMASK(15, 8)
+#define ENA_ADMIN_HOST_INFO_SUB_MINOR_SHIFT 16
+#define ENA_ADMIN_HOST_INFO_SUB_MINOR_MASK GENMASK(23, 16)
+#define ENA_ADMIN_HOST_INFO_MODULE_TYPE_SHIFT 24
+#define ENA_ADMIN_HOST_INFO_MODULE_TYPE_MASK GENMASK(31, 24)
+#define ENA_ADMIN_HOST_INFO_FUNCTION_MASK GENMASK(2, 0)
+#define ENA_ADMIN_HOST_INFO_DEVICE_SHIFT 3
+#define ENA_ADMIN_HOST_INFO_DEVICE_MASK GENMASK(7, 3)
+#define ENA_ADMIN_HOST_INFO_BUS_SHIFT 8
+#define ENA_ADMIN_HOST_INFO_BUS_MASK GENMASK(15, 8)
/* aenq_common_desc */
-#define ENA_ADMIN_AENQ_COMMON_DESC_PHASE_MASK BIT(0)
+#define ENA_ADMIN_AENQ_COMMON_DESC_PHASE_MASK BIT(0)
/* aenq_link_change_desc */
-#define ENA_ADMIN_AENQ_LINK_CHANGE_DESC_LINK_STATUS_MASK BIT(0)
+#define ENA_ADMIN_AENQ_LINK_CHANGE_DESC_LINK_STATUS_MASK BIT(0)
#endif /*_ENA_ADMIN_H_ */
diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c
index 7635c38e77dd..420cede41ca4 100644
--- a/drivers/net/ethernet/amazon/ena/ena_com.c
+++ b/drivers/net/ethernet/amazon/ena/ena_com.c
@@ -41,9 +41,6 @@
#define ENA_ASYNC_QUEUE_DEPTH 16
#define ENA_ADMIN_QUEUE_DEPTH 32
-#define MIN_ENA_VER (((ENA_COMMON_SPEC_VERSION_MAJOR) << \
- ENA_REGS_VERSION_MAJOR_VERSION_SHIFT) \
- | (ENA_COMMON_SPEC_VERSION_MINOR))
#define ENA_CTRL_MAJOR 0
#define ENA_CTRL_MINOR 0
@@ -61,6 +58,8 @@
#define ENA_MMIO_READ_TIMEOUT 0xFFFFFFFF
+#define ENA_COM_BOUNCE_BUFFER_CNTRL_CNT 4
+
#define ENA_REGS_ADMIN_INTR_MASK 1
#define ENA_POLL_MS 5
@@ -236,7 +235,7 @@ static struct ena_comp_ctx *__ena_com_submit_admin_cmd(struct ena_com_admin_queu
tail_masked = admin_queue->sq.tail & queue_size_mask;
/* In case of queue FULL */
- cnt = atomic_read(&admin_queue->outstanding_cmds);
+ cnt = (u16)atomic_read(&admin_queue->outstanding_cmds);
if (cnt >= admin_queue->q_depth) {
pr_debug("admin queue is full.\n");
admin_queue->stats.out_of_space++;
@@ -305,7 +304,7 @@ static struct ena_comp_ctx *ena_com_submit_admin_cmd(struct ena_com_admin_queue
struct ena_admin_acq_entry *comp,
size_t comp_size_in_bytes)
{
- unsigned long flags;
+ unsigned long flags = 0;
struct ena_comp_ctx *comp_ctx;
spin_lock_irqsave(&admin_queue->q_lock, flags);
@@ -333,7 +332,7 @@ static int ena_com_init_io_sq(struct ena_com_dev *ena_dev,
memset(&io_sq->desc_addr, 0x0, sizeof(io_sq->desc_addr));
- io_sq->dma_addr_bits = ena_dev->dma_addr_bits;
+ io_sq->dma_addr_bits = (u8)ena_dev->dma_addr_bits;
io_sq->desc_entry_size =
(io_sq->direction == ENA_COM_IO_QUEUE_DIRECTION_TX) ?
sizeof(struct ena_eth_io_tx_desc) :
@@ -355,21 +354,48 @@ static int ena_com_init_io_sq(struct ena_com_dev *ena_dev,
&io_sq->desc_addr.phys_addr,
GFP_KERNEL);
}
- } else {
+
+ if (!io_sq->desc_addr.virt_addr) {
+ pr_err("memory allocation failed");
+ return -ENOMEM;
+ }
+ }
+
+ if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) {
+ /* Allocate bounce buffers */
+ io_sq->bounce_buf_ctrl.buffer_size =
+ ena_dev->llq_info.desc_list_entry_size;
+ io_sq->bounce_buf_ctrl.buffers_num =
+ ENA_COM_BOUNCE_BUFFER_CNTRL_CNT;
+ io_sq->bounce_buf_ctrl.next_to_use = 0;
+
+ size = io_sq->bounce_buf_ctrl.buffer_size *
+ io_sq->bounce_buf_ctrl.buffers_num;
+
dev_node = dev_to_node(ena_dev->dmadev);
set_dev_node(ena_dev->dmadev, ctx->numa_node);
- io_sq->desc_addr.virt_addr =
+ io_sq->bounce_buf_ctrl.base_buffer =
devm_kzalloc(ena_dev->dmadev, size, GFP_KERNEL);
set_dev_node(ena_dev->dmadev, dev_node);
- if (!io_sq->desc_addr.virt_addr) {
- io_sq->desc_addr.virt_addr =
+ if (!io_sq->bounce_buf_ctrl.base_buffer)
+ io_sq->bounce_buf_ctrl.base_buffer =
devm_kzalloc(ena_dev->dmadev, size, GFP_KERNEL);
+
+ if (!io_sq->bounce_buf_ctrl.base_buffer) {
+ pr_err("bounce buffer memory allocation failed");
+ return -ENOMEM;
}
- }
- if (!io_sq->desc_addr.virt_addr) {
- pr_err("memory allocation failed");
- return -ENOMEM;
+ memcpy(&io_sq->llq_info, &ena_dev->llq_info,
+ sizeof(io_sq->llq_info));
+
+ /* Initiate the first bounce buffer */
+ io_sq->llq_buf_ctrl.curr_bounce_buf =
+ ena_com_get_next_bounce_buffer(&io_sq->bounce_buf_ctrl);
+ memset(io_sq->llq_buf_ctrl.curr_bounce_buf,
+ 0x0, io_sq->llq_info.desc_list_entry_size);
+ io_sq->llq_buf_ctrl.descs_left_in_line =
+ io_sq->llq_info.descs_num_before_header;
}
io_sq->tail = 0;
@@ -460,7 +486,7 @@ static void ena_com_handle_admin_completion(struct ena_com_admin_queue *admin_qu
/* Go over all the completions */
while ((READ_ONCE(cqe->acq_common_descriptor.flags) &
- ENA_ADMIN_ACQ_COMMON_DESC_PHASE_MASK) == phase) {
+ ENA_ADMIN_ACQ_COMMON_DESC_PHASE_MASK) == phase) {
/* Do not read the rest of the completion entry before the
* phase bit was validated
*/
@@ -511,7 +537,8 @@ static int ena_com_comp_status_to_errno(u8 comp_status)
static int ena_com_wait_and_process_admin_cq_polling(struct ena_comp_ctx *comp_ctx,
struct ena_com_admin_queue *admin_queue)
{
- unsigned long flags, timeout;
+ unsigned long flags = 0;
+ unsigned long timeout;
int ret;
timeout = jiffies + usecs_to_jiffies(admin_queue->completion_timeout);
@@ -557,10 +584,160 @@ err:
return ret;
}
+/**
+ * Set the LLQ configurations of the firmware
+ *
+ * The driver provides only the enabled feature values to the device,
+ * which in turn, checks if they are supported.
+ */
+static int ena_com_set_llq(struct ena_com_dev *ena_dev)
+{
+ struct ena_com_admin_queue *admin_queue;
+ struct ena_admin_set_feat_cmd cmd;
+ struct ena_admin_set_feat_resp resp;
+ struct ena_com_llq_info *llq_info = &ena_dev->llq_info;
+ int ret;
+
+ memset(&cmd, 0x0, sizeof(cmd));
+ admin_queue = &ena_dev->admin_queue;
+
+ cmd.aq_common_descriptor.opcode = ENA_ADMIN_SET_FEATURE;
+ cmd.feat_common.feature_id = ENA_ADMIN_LLQ;
+
+ cmd.u.llq.header_location_ctrl_enabled = llq_info->header_location_ctrl;
+ cmd.u.llq.entry_size_ctrl_enabled = llq_info->desc_list_entry_size_ctrl;
+ cmd.u.llq.desc_num_before_header_enabled = llq_info->descs_num_before_header;
+ cmd.u.llq.descriptors_stride_ctrl_enabled = llq_info->desc_stride_ctrl;
+
+ ret = ena_com_execute_admin_command(admin_queue,
+ (struct ena_admin_aq_entry *)&cmd,
+ sizeof(cmd),
+ (struct ena_admin_acq_entry *)&resp,
+ sizeof(resp));
+
+ if (unlikely(ret))
+ pr_err("Failed to set LLQ configurations: %d\n", ret);
+
+ return ret;
+}
+
+static int ena_com_config_llq_info(struct ena_com_dev *ena_dev,
+ struct ena_admin_feature_llq_desc *llq_features,
+ struct ena_llq_configurations *llq_default_cfg)
+{
+ struct ena_com_llq_info *llq_info = &ena_dev->llq_info;
+ u16 supported_feat;
+ int rc;
+
+ memset(llq_info, 0, sizeof(*llq_info));
+
+ supported_feat = llq_features->header_location_ctrl_supported;
+
+ if (likely(supported_feat & llq_default_cfg->llq_header_location)) {
+ llq_info->header_location_ctrl =
+ llq_default_cfg->llq_header_location;
+ } else {
+ pr_err("Invalid header location control, supported: 0x%x\n",
+ supported_feat);
+ return -EINVAL;
+ }
+
+ if (likely(llq_info->header_location_ctrl == ENA_ADMIN_INLINE_HEADER)) {
+ supported_feat = llq_features->descriptors_stride_ctrl_supported;
+ if (likely(supported_feat & llq_default_cfg->llq_stride_ctrl)) {
+ llq_info->desc_stride_ctrl = llq_default_cfg->llq_stride_ctrl;
+ } else {
+ if (supported_feat & ENA_ADMIN_MULTIPLE_DESCS_PER_ENTRY) {
+ llq_info->desc_stride_ctrl = ENA_ADMIN_MULTIPLE_DESCS_PER_ENTRY;
+ } else if (supported_feat & ENA_ADMIN_SINGLE_DESC_PER_ENTRY) {
+ llq_info->desc_stride_ctrl = ENA_ADMIN_SINGLE_DESC_PER_ENTRY;
+ } else {
+ pr_err("Invalid desc_stride_ctrl, supported: 0x%x\n",
+ supported_feat);
+ return -EINVAL;
+ }
+
+ pr_err("Default llq stride ctrl is not supported, performing fallback, default: 0x%x, supported: 0x%x, used: 0x%x\n",
+ llq_default_cfg->llq_stride_ctrl, supported_feat,
+ llq_info->desc_stride_ctrl);
+ }
+ } else {
+ llq_info->desc_stride_ctrl = 0;
+ }
+
+ supported_feat = llq_features->entry_size_ctrl_supported;
+ if (likely(supported_feat & llq_default_cfg->llq_ring_entry_size)) {
+ llq_info->desc_list_entry_size_ctrl = llq_default_cfg->llq_ring_entry_size;
+ llq_info->desc_list_entry_size = llq_default_cfg->llq_ring_entry_size_value;
+ } else {
+ if (supported_feat & ENA_ADMIN_LIST_ENTRY_SIZE_128B) {
+ llq_info->desc_list_entry_size_ctrl = ENA_ADMIN_LIST_ENTRY_SIZE_128B;
+ llq_info->desc_list_entry_size = 128;
+ } else if (supported_feat & ENA_ADMIN_LIST_ENTRY_SIZE_192B) {
+ llq_info->desc_list_entry_size_ctrl = ENA_ADMIN_LIST_ENTRY_SIZE_192B;
+ llq_info->desc_list_entry_size = 192;
+ } else if (supported_feat & ENA_ADMIN_LIST_ENTRY_SIZE_256B) {
+ llq_info->desc_list_entry_size_ctrl = ENA_ADMIN_LIST_ENTRY_SIZE_256B;
+ llq_info->desc_list_entry_size = 256;
+ } else {
+ pr_err("Invalid entry_size_ctrl, supported: 0x%x\n",
+ supported_feat);
+ return -EINVAL;
+ }
+
+ pr_err("Default llq ring entry size is not supported, performing fallback, default: 0x%x, supported: 0x%x, used: 0x%x\n",
+ llq_default_cfg->llq_ring_entry_size, supported_feat,
+ llq_info->desc_list_entry_size);
+ }
+ if (unlikely(llq_info->desc_list_entry_size & 0x7)) {
+ /* The desc list entry size should be whole multiply of 8
+ * This requirement comes from __iowrite64_copy()
+ */
+ pr_err("illegal entry size %d\n",
+ llq_info->desc_list_entry_size);
+ return -EINVAL;
+ }
+
+ if (llq_info->desc_stride_ctrl == ENA_ADMIN_MULTIPLE_DESCS_PER_ENTRY)
+ llq_info->descs_per_entry = llq_info->desc_list_entry_size /
+ sizeof(struct ena_eth_io_tx_desc);
+ else
+ llq_info->descs_per_entry = 1;
+
+ supported_feat = llq_features->desc_num_before_header_supported;
+ if (likely(supported_feat & llq_default_cfg->llq_num_decs_before_header)) {
+ llq_info->descs_num_before_header = llq_default_cfg->llq_num_decs_before_header;
+ } else {
+ if (supported_feat & ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_2) {
+ llq_info->descs_num_before_header = ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_2;
+ } else if (supported_feat & ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_1) {
+ llq_info->descs_num_before_header = ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_1;
+ } else if (supported_feat & ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_4) {
+ llq_info->descs_num_before_header = ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_4;
+ } else if (supported_feat & ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_8) {
+ llq_info->descs_num_before_header = ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_8;
+ } else {
+ pr_err("Invalid descs_num_before_header, supported: 0x%x\n",
+ supported_feat);
+ return -EINVAL;
+ }
+
+ pr_err("Default llq num descs before header is not supported, performing fallback, default: 0x%x, supported: 0x%x, used: 0x%x\n",
+ llq_default_cfg->llq_num_decs_before_header,
+ supported_feat, llq_info->descs_num_before_header);
+ }
+
+ rc = ena_com_set_llq(ena_dev);
+ if (rc)
+ pr_err("Cannot set LLQ configuration: %d\n", rc);
+
+ return 0;
+}
+
static int ena_com_wait_and_process_admin_cq_interrupts(struct ena_comp_ctx *comp_ctx,
struct ena_com_admin_queue *admin_queue)
{
- unsigned long flags;
+ unsigned long flags = 0;
int ret;
wait_for_completion_timeout(&comp_ctx->wait_event,
@@ -606,7 +783,7 @@ static u32 ena_com_reg_bar_read32(struct ena_com_dev *ena_dev, u16 offset)
volatile struct ena_admin_ena_mmio_req_read_less_resp *read_resp =
mmio_read->read_resp;
u32 mmio_read_reg, ret, i;
- unsigned long flags;
+ unsigned long flags = 0;
u32 timeout = mmio_read->reg_read_to;
might_sleep();
@@ -728,15 +905,17 @@ static void ena_com_io_queue_free(struct ena_com_dev *ena_dev,
if (io_sq->desc_addr.virt_addr) {
size = io_sq->desc_entry_size * io_sq->q_depth;
- if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST)
- dma_free_coherent(ena_dev->dmadev, size,
- io_sq->desc_addr.virt_addr,
- io_sq->desc_addr.phys_addr);
- else
- devm_kfree(ena_dev->dmadev, io_sq->desc_addr.virt_addr);
+ dma_free_coherent(ena_dev->dmadev, size,
+ io_sq->desc_addr.virt_addr,
+ io_sq->desc_addr.phys_addr);
io_sq->desc_addr.virt_addr = NULL;
}
+
+ if (io_sq->bounce_buf_ctrl.base_buffer) {
+ devm_kfree(ena_dev->dmadev, io_sq->bounce_buf_ctrl.base_buffer);
+ io_sq->bounce_buf_ctrl.base_buffer = NULL;
+ }
}
static int wait_for_reset_state(struct ena_com_dev *ena_dev, u32 timeout,
@@ -1248,7 +1427,7 @@ void ena_com_abort_admin_commands(struct ena_com_dev *ena_dev)
void ena_com_wait_for_abort_completion(struct ena_com_dev *ena_dev)
{
struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue;
- unsigned long flags;
+ unsigned long flags = 0;
spin_lock_irqsave(&admin_queue->q_lock, flags);
while (atomic_read(&admin_queue->outstanding_cmds) != 0) {
@@ -1292,7 +1471,7 @@ bool ena_com_get_admin_running_state(struct ena_com_dev *ena_dev)
void ena_com_set_admin_running_state(struct ena_com_dev *ena_dev, bool state)
{
struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue;
- unsigned long flags;
+ unsigned long flags = 0;
spin_lock_irqsave(&admin_queue->q_lock, flags);
ena_dev->admin_queue.running_state = state;
@@ -1326,7 +1505,7 @@ int ena_com_set_aenq_config(struct ena_com_dev *ena_dev, u32 groups_flag)
}
if ((get_resp.u.aenq.supported_groups & groups_flag) != groups_flag) {
- pr_warn("Trying to set unsupported aenq events. supported flag: %x asked flag: %x\n",
+ pr_warn("Trying to set unsupported aenq events. supported flag: 0x%x asked flag: 0x%x\n",
get_resp.u.aenq.supported_groups, groups_flag);
return -EOPNOTSUPP;
}
@@ -1400,11 +1579,6 @@ int ena_com_validate_version(struct ena_com_dev *ena_dev)
ENA_REGS_VERSION_MAJOR_VERSION_SHIFT,
ver & ENA_REGS_VERSION_MINOR_VERSION_MASK);
- if (ver < MIN_ENA_VER) {
- pr_err("ENA version is lower than the minimal version the driver supports\n");
- return -1;
- }
-
pr_info("ena controller version: %d.%d.%d implementation version %d\n",
(ctrl_ver & ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_MASK) >>
ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_SHIFT,
@@ -1479,7 +1653,7 @@ int ena_com_mmio_reg_read_request_init(struct ena_com_dev *ena_dev)
sizeof(*mmio_read->read_resp),
&mmio_read->read_resp_dma_addr, GFP_KERNEL);
if (unlikely(!mmio_read->read_resp))
- return -ENOMEM;
+ goto err;
ena_com_mmio_reg_read_request_write_dev_addr(ena_dev);
@@ -1488,6 +1662,10 @@ int ena_com_mmio_reg_read_request_init(struct ena_com_dev *ena_dev)
mmio_read->readless_supported = true;
return 0;
+
+err:
+
+ return -ENOMEM;
}
void ena_com_set_mmio_read_mode(struct ena_com_dev *ena_dev, bool readless_supported)
@@ -1523,8 +1701,7 @@ void ena_com_mmio_reg_read_request_write_dev_addr(struct ena_com_dev *ena_dev)
}
int ena_com_admin_init(struct ena_com_dev *ena_dev,
- struct ena_aenq_handlers *aenq_handlers,
- bool init_spinlock)
+ struct ena_aenq_handlers *aenq_handlers)
{
struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue;
u32 aq_caps, acq_caps, dev_sts, addr_low, addr_high;
@@ -1550,8 +1727,7 @@ int ena_com_admin_init(struct ena_com_dev *ena_dev,
atomic_set(&admin_queue->outstanding_cmds, 0);
- if (init_spinlock)
- spin_lock_init(&admin_queue->q_lock);
+ spin_lock_init(&admin_queue->q_lock);
ret = ena_com_init_comp_ctxt(admin_queue);
if (ret)
@@ -1748,6 +1924,15 @@ int ena_com_get_dev_attr_feat(struct ena_com_dev *ena_dev,
else
return rc;
+ rc = ena_com_get_feature(ena_dev, &get_resp, ENA_ADMIN_LLQ);
+ if (!rc)
+ memcpy(&get_feat_ctx->llq, &get_resp.u.llq,
+ sizeof(get_resp.u.llq));
+ else if (rc == -EOPNOTSUPP)
+ memset(&get_feat_ctx->llq, 0x0, sizeof(get_feat_ctx->llq));
+ else
+ return rc;
+
return 0;
}
@@ -1779,6 +1964,7 @@ void ena_com_aenq_intr_handler(struct ena_com_dev *dev, void *data)
struct ena_admin_aenq_entry *aenq_e;
struct ena_admin_aenq_common_desc *aenq_common;
struct ena_com_aenq *aenq = &dev->aenq;
+ unsigned long long timestamp;
ena_aenq_handler handler_cb;
u16 masked_head, processed = 0;
u8 phase;
@@ -1796,10 +1982,11 @@ void ena_com_aenq_intr_handler(struct ena_com_dev *dev, void *data)
*/
dma_rmb();
+ timestamp =
+ (unsigned long long)aenq_common->timestamp_low |
+ ((unsigned long long)aenq_common->timestamp_high << 32);
pr_debug("AENQ! Group[%x] Syndrom[%x] timestamp: [%llus]\n",
- aenq_common->group, aenq_common->syndrom,
- (u64)aenq_common->timestamp_low +
- ((u64)aenq_common->timestamp_high << 32));
+ aenq_common->group, aenq_common->syndrom, timestamp);
/* Handle specific event*/
handler_cb = ena_com_get_specific_aenq_cb(dev,
@@ -2441,6 +2628,10 @@ int ena_com_allocate_host_info(struct ena_com_dev *ena_dev)
if (unlikely(!host_attr->host_info))
return -ENOMEM;
+ host_attr->host_info->ena_spec_version = ((ENA_COMMON_SPEC_VERSION_MAJOR <<
+ ENA_REGS_VERSION_MAJOR_VERSION_SHIFT) |
+ (ENA_COMMON_SPEC_VERSION_MINOR));
+
return 0;
}
@@ -2712,3 +2903,34 @@ void ena_com_get_intr_moderation_entry(struct ena_com_dev *ena_dev,
intr_moder_tbl[level].pkts_per_interval;
entry->bytes_per_interval = intr_moder_tbl[level].bytes_per_interval;
}
+
+int ena_com_config_dev_mode(struct ena_com_dev *ena_dev,
+ struct ena_admin_feature_llq_desc *llq_features,
+ struct ena_llq_configurations *llq_default_cfg)
+{
+ int rc;
+ int size;
+
+ if (!llq_features->max_llq_num) {
+ ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST;
+ return 0;
+ }
+
+ rc = ena_com_config_llq_info(ena_dev, llq_features, llq_default_cfg);
+ if (rc)
+ return rc;
+
+ /* Validate the descriptor is not too big */
+ size = ena_dev->tx_max_header_size;
+ size += ena_dev->llq_info.descs_num_before_header *
+ sizeof(struct ena_eth_io_tx_desc);
+
+ if (unlikely(ena_dev->llq_info.desc_list_entry_size < size)) {
+ pr_err("the size of the LLQ entry is smaller than needed\n");
+ return -EINVAL;
+ }
+
+ ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_DEV;
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/amazon/ena/ena_com.h b/drivers/net/ethernet/amazon/ena/ena_com.h
index 7b784f8a06a6..078d6f2b4f39 100644
--- a/drivers/net/ethernet/amazon/ena/ena_com.h
+++ b/drivers/net/ethernet/amazon/ena/ena_com.h
@@ -37,6 +37,8 @@
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/gfp.h>
+#include <linux/io.h>
+#include <linux/prefetch.h>
#include <linux/sched.h>
#include <linux/sizes.h>
#include <linux/spinlock.h>
@@ -108,6 +110,14 @@ enum ena_intr_moder_level {
ENA_INTR_MAX_NUM_OF_LEVELS,
};
+struct ena_llq_configurations {
+ enum ena_admin_llq_header_location llq_header_location;
+ enum ena_admin_llq_ring_entry_size llq_ring_entry_size;
+ enum ena_admin_llq_stride_ctrl llq_stride_ctrl;
+ enum ena_admin_llq_num_descs_before_header llq_num_decs_before_header;
+ u16 llq_ring_entry_size_value;
+};
+
struct ena_intr_moder_entry {
unsigned int intr_moder_interval;
unsigned int pkts_per_interval;
@@ -142,6 +152,15 @@ struct ena_com_tx_meta {
u16 l4_hdr_len; /* In words */
};
+struct ena_com_llq_info {
+ u16 header_location_ctrl;
+ u16 desc_stride_ctrl;
+ u16 desc_list_entry_size_ctrl;
+ u16 desc_list_entry_size;
+ u16 descs_num_before_header;
+ u16 descs_per_entry;
+};
+
struct ena_com_io_cq {
struct ena_com_io_desc_addr cdesc_addr;
@@ -179,6 +198,20 @@ struct ena_com_io_cq {
} ____cacheline_aligned;
+struct ena_com_io_bounce_buffer_control {
+ u8 *base_buffer;
+ u16 next_to_use;
+ u16 buffer_size;
+ u16 buffers_num; /* Must be a power of 2 */
+};
+
+/* This struct is to keep tracking the current location of the next llq entry */
+struct ena_com_llq_pkt_ctrl {
+ u8 *curr_bounce_buf;
+ u16 idx;
+ u16 descs_left_in_line;
+};
+
struct ena_com_io_sq {
struct ena_com_io_desc_addr desc_addr;
@@ -190,6 +223,9 @@ struct ena_com_io_sq {
u32 msix_vector;
struct ena_com_tx_meta cached_tx_meta;
+ struct ena_com_llq_info llq_info;
+ struct ena_com_llq_pkt_ctrl llq_buf_ctrl;
+ struct ena_com_io_bounce_buffer_control bounce_buf_ctrl;
u16 q_depth;
u16 qid;
@@ -197,6 +233,7 @@ struct ena_com_io_sq {
u16 idx;
u16 tail;
u16 next_to_comp;
+ u16 llq_last_copy_tail;
u32 tx_max_header_size;
u8 phase;
u8 desc_entry_size;
@@ -334,6 +371,8 @@ struct ena_com_dev {
u16 intr_delay_resolution;
u32 intr_moder_tx_interval;
struct ena_intr_moder_entry *intr_moder_tbl;
+
+ struct ena_com_llq_info llq_info;
};
struct ena_com_dev_get_features_ctx {
@@ -342,6 +381,7 @@ struct ena_com_dev_get_features_ctx {
struct ena_admin_feature_aenq_desc aenq;
struct ena_admin_feature_offload_desc offload;
struct ena_admin_ena_hw_hints hw_hints;
+ struct ena_admin_feature_llq_desc llq;
};
struct ena_com_create_io_ctx {
@@ -397,8 +437,6 @@ void ena_com_mmio_reg_read_request_destroy(struct ena_com_dev *ena_dev);
/* ena_com_admin_init - Init the admin and the async queues
* @ena_dev: ENA communication layer struct
* @aenq_handlers: Those handlers to be called upon event.
- * @init_spinlock: Indicate if this method should init the admin spinlock or
- * the spinlock was init before (for example, in a case of FLR).
*
* Initialize the admin submission and completion queues.
* Initialize the asynchronous events notification queues.
@@ -406,8 +444,7 @@ void ena_com_mmio_reg_read_request_destroy(struct ena_com_dev *ena_dev);
* @return - 0 on success, negative value on failure.
*/
int ena_com_admin_init(struct ena_com_dev *ena_dev,
- struct ena_aenq_handlers *aenq_handlers,
- bool init_spinlock);
+ struct ena_aenq_handlers *aenq_handlers);
/* ena_com_admin_destroy - Destroy the admin and the async events queues.
* @ena_dev: ENA communication layer struct
@@ -935,6 +972,16 @@ void ena_com_get_intr_moderation_entry(struct ena_com_dev *ena_dev,
enum ena_intr_moder_level level,
struct ena_intr_moder_entry *entry);
+/* ena_com_config_dev_mode - Configure the placement policy of the device.
+ * @ena_dev: ENA communication layer struct
+ * @llq_features: LLQ feature descriptor, retrieve via
+ * ena_com_get_dev_attr_feat.
+ * @ena_llq_config: The default driver LLQ parameters configurations
+ */
+int ena_com_config_dev_mode(struct ena_com_dev *ena_dev,
+ struct ena_admin_feature_llq_desc *llq_features,
+ struct ena_llq_configurations *llq_default_config);
+
static inline bool ena_com_get_adaptive_moderation_enabled(struct ena_com_dev *ena_dev)
{
return ena_dev->adaptive_coalescing;
@@ -1044,4 +1091,21 @@ static inline void ena_com_update_intr_reg(struct ena_eth_io_intr_reg *intr_reg,
intr_reg->intr_control |= ENA_ETH_IO_INTR_REG_INTR_UNMASK_MASK;
}
+static inline u8 *ena_com_get_next_bounce_buffer(struct ena_com_io_bounce_buffer_control *bounce_buf_ctrl)
+{
+ u16 size, buffers_num;
+ u8 *buf;
+
+ size = bounce_buf_ctrl->buffer_size;
+ buffers_num = bounce_buf_ctrl->buffers_num;
+
+ buf = bounce_buf_ctrl->base_buffer +
+ (bounce_buf_ctrl->next_to_use++ & (buffers_num - 1)) * size;
+
+ prefetchw(bounce_buf_ctrl->base_buffer +
+ (bounce_buf_ctrl->next_to_use & (buffers_num - 1)) * size);
+
+ return buf;
+}
+
#endif /* !(ENA_COM) */
diff --git a/drivers/net/ethernet/amazon/ena/ena_common_defs.h b/drivers/net/ethernet/amazon/ena/ena_common_defs.h
index bb8d73676eab..23beb7e7ed7b 100644
--- a/drivers/net/ethernet/amazon/ena/ena_common_defs.h
+++ b/drivers/net/ethernet/amazon/ena/ena_common_defs.h
@@ -32,8 +32,8 @@
#ifndef _ENA_COMMON_H_
#define _ENA_COMMON_H_
-#define ENA_COMMON_SPEC_VERSION_MAJOR 0 /* */
-#define ENA_COMMON_SPEC_VERSION_MINOR 10 /* */
+#define ENA_COMMON_SPEC_VERSION_MAJOR 2
+#define ENA_COMMON_SPEC_VERSION_MINOR 0
/* ENA operates with 48-bit memory addresses. ena_mem_addr_t */
struct ena_common_mem_addr {
diff --git a/drivers/net/ethernet/amazon/ena/ena_eth_com.c b/drivers/net/ethernet/amazon/ena/ena_eth_com.c
index 1c682b76190f..f6c2d3855be8 100644
--- a/drivers/net/ethernet/amazon/ena/ena_eth_com.c
+++ b/drivers/net/ethernet/amazon/ena/ena_eth_com.c
@@ -59,16 +59,7 @@ static inline struct ena_eth_io_rx_cdesc_base *ena_com_get_next_rx_cdesc(
return cdesc;
}
-static inline void ena_com_cq_inc_head(struct ena_com_io_cq *io_cq)
-{
- io_cq->head++;
-
- /* Switch phase bit in case of wrap around */
- if (unlikely((io_cq->head & (io_cq->q_depth - 1)) == 0))
- io_cq->phase ^= 1;
-}
-
-static inline void *get_sq_desc(struct ena_com_io_sq *io_sq)
+static inline void *get_sq_desc_regular_queue(struct ena_com_io_sq *io_sq)
{
u16 tail_masked;
u32 offset;
@@ -80,45 +71,159 @@ static inline void *get_sq_desc(struct ena_com_io_sq *io_sq)
return (void *)((uintptr_t)io_sq->desc_addr.virt_addr + offset);
}
-static inline void ena_com_copy_curr_sq_desc_to_dev(struct ena_com_io_sq *io_sq)
+static inline int ena_com_write_bounce_buffer_to_dev(struct ena_com_io_sq *io_sq,
+ u8 *bounce_buffer)
{
- u16 tail_masked = io_sq->tail & (io_sq->q_depth - 1);
- u32 offset = tail_masked * io_sq->desc_entry_size;
+ struct ena_com_llq_info *llq_info = &io_sq->llq_info;
- /* In case this queue isn't a LLQ */
- if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST)
- return;
+ u16 dst_tail_mask;
+ u32 dst_offset;
- memcpy_toio(io_sq->desc_addr.pbuf_dev_addr + offset,
- io_sq->desc_addr.virt_addr + offset,
- io_sq->desc_entry_size);
-}
+ dst_tail_mask = io_sq->tail & (io_sq->q_depth - 1);
+ dst_offset = dst_tail_mask * llq_info->desc_list_entry_size;
+
+ /* Make sure everything was written into the bounce buffer before
+ * writing the bounce buffer to the device
+ */
+ wmb();
+
+ /* The line is completed. Copy it to dev */
+ __iowrite64_copy(io_sq->desc_addr.pbuf_dev_addr + dst_offset,
+ bounce_buffer, (llq_info->desc_list_entry_size) / 8);
-static inline void ena_com_sq_update_tail(struct ena_com_io_sq *io_sq)
-{
io_sq->tail++;
/* Switch phase bit in case of wrap around */
if (unlikely((io_sq->tail & (io_sq->q_depth - 1)) == 0))
io_sq->phase ^= 1;
+
+ return 0;
}
-static inline int ena_com_write_header(struct ena_com_io_sq *io_sq,
- u8 *head_src, u16 header_len)
+static inline int ena_com_write_header_to_bounce(struct ena_com_io_sq *io_sq,
+ u8 *header_src,
+ u16 header_len)
{
- u16 tail_masked = io_sq->tail & (io_sq->q_depth - 1);
- u8 __iomem *dev_head_addr =
- io_sq->header_addr + (tail_masked * io_sq->tx_max_header_size);
+ struct ena_com_llq_pkt_ctrl *pkt_ctrl = &io_sq->llq_buf_ctrl;
+ struct ena_com_llq_info *llq_info = &io_sq->llq_info;
+ u8 *bounce_buffer = pkt_ctrl->curr_bounce_buf;
+ u16 header_offset;
- if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST)
+ if (unlikely(io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST))
return 0;
- if (unlikely(!io_sq->header_addr)) {
- pr_err("Push buffer header ptr is NULL\n");
- return -EINVAL;
+ header_offset =
+ llq_info->descs_num_before_header * io_sq->desc_entry_size;
+
+ if (unlikely((header_offset + header_len) >
+ llq_info->desc_list_entry_size)) {
+ pr_err("trying to write header larger than llq entry can accommodate\n");
+ return -EFAULT;
+ }
+
+ if (unlikely(!bounce_buffer)) {
+ pr_err("bounce buffer is NULL\n");
+ return -EFAULT;
+ }
+
+ memcpy(bounce_buffer + header_offset, header_src, header_len);
+
+ return 0;
+}
+
+static inline void *get_sq_desc_llq(struct ena_com_io_sq *io_sq)
+{
+ struct ena_com_llq_pkt_ctrl *pkt_ctrl = &io_sq->llq_buf_ctrl;
+ u8 *bounce_buffer;
+ void *sq_desc;
+
+ bounce_buffer = pkt_ctrl->curr_bounce_buf;
+
+ if (unlikely(!bounce_buffer)) {
+ pr_err("bounce buffer is NULL\n");
+ return NULL;
+ }
+
+ sq_desc = bounce_buffer + pkt_ctrl->idx * io_sq->desc_entry_size;
+ pkt_ctrl->idx++;
+ pkt_ctrl->descs_left_in_line--;
+
+ return sq_desc;
+}
+
+static inline int ena_com_close_bounce_buffer(struct ena_com_io_sq *io_sq)
+{
+ struct ena_com_llq_pkt_ctrl *pkt_ctrl = &io_sq->llq_buf_ctrl;
+ struct ena_com_llq_info *llq_info = &io_sq->llq_info;
+ int rc;
+
+ if (unlikely(io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST))
+ return 0;
+
+ /* bounce buffer was used, so write it and get a new one */
+ if (pkt_ctrl->idx) {
+ rc = ena_com_write_bounce_buffer_to_dev(io_sq,
+ pkt_ctrl->curr_bounce_buf);
+ if (unlikely(rc))
+ return rc;
+
+ pkt_ctrl->curr_bounce_buf =
+ ena_com_get_next_bounce_buffer(&io_sq->bounce_buf_ctrl);
+ memset(io_sq->llq_buf_ctrl.curr_bounce_buf,
+ 0x0, llq_info->desc_list_entry_size);
+ }
+
+ pkt_ctrl->idx = 0;
+ pkt_ctrl->descs_left_in_line = llq_info->descs_num_before_header;
+ return 0;
+}
+
+static inline void *get_sq_desc(struct ena_com_io_sq *io_sq)
+{
+ if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV)
+ return get_sq_desc_llq(io_sq);
+
+ return get_sq_desc_regular_queue(io_sq);
+}
+
+static inline int ena_com_sq_update_llq_tail(struct ena_com_io_sq *io_sq)
+{
+ struct ena_com_llq_pkt_ctrl *pkt_ctrl = &io_sq->llq_buf_ctrl;
+ struct ena_com_llq_info *llq_info = &io_sq->llq_info;
+ int rc;
+
+ 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))
+ return rc;
+
+ pkt_ctrl->curr_bounce_buf =
+ ena_com_get_next_bounce_buffer(&io_sq->bounce_buf_ctrl);
+ memset(io_sq->llq_buf_ctrl.curr_bounce_buf,
+ 0x0, llq_info->desc_list_entry_size);
+
+ pkt_ctrl->idx = 0;
+ if (unlikely(llq_info->desc_stride_ctrl == ENA_ADMIN_SINGLE_DESC_PER_ENTRY))
+ pkt_ctrl->descs_left_in_line = 1;
+ else
+ pkt_ctrl->descs_left_in_line =
+ llq_info->desc_list_entry_size / io_sq->desc_entry_size;
}
- memcpy_toio(dev_head_addr, head_src, header_len);
+ return 0;
+}
+
+static inline int ena_com_sq_update_tail(struct ena_com_io_sq *io_sq)
+{
+ if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV)
+ return ena_com_sq_update_llq_tail(io_sq);
+
+ io_sq->tail++;
+
+ /* Switch phase bit in case of wrap around */
+ if (unlikely((io_sq->tail & (io_sq->q_depth - 1)) == 0))
+ io_sq->phase ^= 1;
return 0;
}
@@ -186,8 +291,8 @@ static inline bool ena_com_meta_desc_changed(struct ena_com_io_sq *io_sq,
return false;
}
-static inline void ena_com_create_and_store_tx_meta_desc(struct ena_com_io_sq *io_sq,
- struct ena_com_tx_ctx *ena_tx_ctx)
+static inline int ena_com_create_and_store_tx_meta_desc(struct ena_com_io_sq *io_sq,
+ struct ena_com_tx_ctx *ena_tx_ctx)
{
struct ena_eth_io_tx_meta_desc *meta_desc = NULL;
struct ena_com_tx_meta *ena_meta = &ena_tx_ctx->ena_meta;
@@ -232,8 +337,7 @@ static inline void ena_com_create_and_store_tx_meta_desc(struct ena_com_io_sq *i
memcpy(&io_sq->cached_tx_meta, ena_meta,
sizeof(struct ena_com_tx_meta));
- ena_com_copy_curr_sq_desc_to_dev(io_sq);
- ena_com_sq_update_tail(io_sq);
+ return ena_com_sq_update_tail(io_sq);
}
static inline void ena_com_rx_set_flags(struct ena_com_rx_ctx *ena_rx_ctx,
@@ -245,11 +349,14 @@ static inline void ena_com_rx_set_flags(struct ena_com_rx_ctx *ena_rx_ctx,
(cdesc->status & ENA_ETH_IO_RX_CDESC_BASE_L4_PROTO_IDX_MASK) >>
ENA_ETH_IO_RX_CDESC_BASE_L4_PROTO_IDX_SHIFT;
ena_rx_ctx->l3_csum_err =
- (cdesc->status & ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM_ERR_MASK) >>
- ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM_ERR_SHIFT;
+ !!((cdesc->status & ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM_ERR_MASK) >>
+ ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM_ERR_SHIFT);
ena_rx_ctx->l4_csum_err =
- (cdesc->status & ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_ERR_MASK) >>
- ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_ERR_SHIFT;
+ !!((cdesc->status & ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_ERR_MASK) >>
+ ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_ERR_SHIFT);
+ ena_rx_ctx->l4_csum_checked =
+ !!((cdesc->status & ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_CHECKED_MASK) >>
+ ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_CHECKED_SHIFT);
ena_rx_ctx->hash = cdesc->hash;
ena_rx_ctx->frag =
(cdesc->status & ENA_ETH_IO_RX_CDESC_BASE_IPV4_FRAG_MASK) >>
@@ -271,18 +378,19 @@ int ena_com_prepare_tx(struct ena_com_io_sq *io_sq,
{
struct ena_eth_io_tx_desc *desc = NULL;
struct ena_com_buf *ena_bufs = ena_tx_ctx->ena_bufs;
- void *push_header = ena_tx_ctx->push_header;
+ void *buffer_to_push = ena_tx_ctx->push_header;
u16 header_len = ena_tx_ctx->header_len;
u16 num_bufs = ena_tx_ctx->num_bufs;
- int total_desc, i, rc;
+ u16 start_tail = io_sq->tail;
+ int i, rc;
bool have_meta;
u64 addr_hi;
WARN(io_sq->direction != ENA_COM_IO_QUEUE_DIRECTION_TX, "wrong Q type");
/* num_bufs +1 for potential meta desc */
- if (ena_com_sq_empty_space(io_sq) < (num_bufs + 1)) {
- pr_err("Not enough space in the tx queue\n");
+ if (unlikely(!ena_com_sq_have_enough_space(io_sq, num_bufs + 1))) {
+ pr_debug("Not enough space in the tx queue\n");
return -ENOMEM;
}
@@ -292,23 +400,32 @@ int ena_com_prepare_tx(struct ena_com_io_sq *io_sq,
return -EINVAL;
}
- /* start with pushing the header (if needed) */
- rc = ena_com_write_header(io_sq, push_header, header_len);
+ if (unlikely(io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV &&
+ !buffer_to_push))
+ return -EINVAL;
+
+ rc = ena_com_write_header_to_bounce(io_sq, buffer_to_push, header_len);
if (unlikely(rc))
return rc;
have_meta = ena_tx_ctx->meta_valid && ena_com_meta_desc_changed(io_sq,
ena_tx_ctx);
- if (have_meta)
- ena_com_create_and_store_tx_meta_desc(io_sq, ena_tx_ctx);
+ if (have_meta) {
+ rc = ena_com_create_and_store_tx_meta_desc(io_sq, ena_tx_ctx);
+ if (unlikely(rc))
+ return rc;
+ }
- /* If the caller doesn't want send packets */
+ /* If the caller doesn't want to send packets */
if (unlikely(!num_bufs && !header_len)) {
- *nb_hw_desc = have_meta ? 0 : 1;
- return 0;
+ rc = ena_com_close_bounce_buffer(io_sq);
+ *nb_hw_desc = io_sq->tail - start_tail;
+ return rc;
}
desc = get_sq_desc(io_sq);
+ if (unlikely(!desc))
+ return -EFAULT;
memset(desc, 0x0, sizeof(struct ena_eth_io_tx_desc));
/* Set first desc when we don't have meta descriptor */
@@ -360,10 +477,14 @@ int ena_com_prepare_tx(struct ena_com_io_sq *io_sq,
for (i = 0; i < num_bufs; i++) {
/* The first desc share the same desc as the header */
if (likely(i != 0)) {
- ena_com_copy_curr_sq_desc_to_dev(io_sq);
- ena_com_sq_update_tail(io_sq);
+ rc = ena_com_sq_update_tail(io_sq);
+ if (unlikely(rc))
+ return rc;
desc = get_sq_desc(io_sq);
+ if (unlikely(!desc))
+ return -EFAULT;
+
memset(desc, 0x0, sizeof(struct ena_eth_io_tx_desc));
desc->len_ctrl |= (io_sq->phase <<
@@ -386,15 +507,14 @@ int ena_com_prepare_tx(struct ena_com_io_sq *io_sq,
/* set the last desc indicator */
desc->len_ctrl |= ENA_ETH_IO_TX_DESC_LAST_MASK;
- ena_com_copy_curr_sq_desc_to_dev(io_sq);
-
- ena_com_sq_update_tail(io_sq);
+ rc = ena_com_sq_update_tail(io_sq);
+ if (unlikely(rc))
+ return rc;
- total_desc = max_t(u16, num_bufs, 1);
- total_desc += have_meta ? 1 : 0;
+ rc = ena_com_close_bounce_buffer(io_sq);
- *nb_hw_desc = total_desc;
- return 0;
+ *nb_hw_desc = io_sq->tail - start_tail;
+ return rc;
}
int ena_com_rx_pkt(struct ena_com_io_cq *io_cq,
@@ -453,15 +573,18 @@ int ena_com_add_single_rx_desc(struct ena_com_io_sq *io_sq,
WARN(io_sq->direction != ENA_COM_IO_QUEUE_DIRECTION_RX, "wrong Q type");
- if (unlikely(ena_com_sq_empty_space(io_sq) == 0))
+ if (unlikely(!ena_com_sq_have_enough_space(io_sq, 1)))
return -ENOSPC;
desc = get_sq_desc(io_sq);
+ if (unlikely(!desc))
+ return -EFAULT;
+
memset(desc, 0x0, sizeof(struct ena_eth_io_rx_desc));
desc->length = ena_buf->len;
- desc->ctrl |= ENA_ETH_IO_RX_DESC_FIRST_MASK;
+ desc->ctrl = ENA_ETH_IO_RX_DESC_FIRST_MASK;
desc->ctrl |= ENA_ETH_IO_RX_DESC_LAST_MASK;
desc->ctrl |= io_sq->phase & ENA_ETH_IO_RX_DESC_PHASE_MASK;
desc->ctrl |= ENA_ETH_IO_RX_DESC_COMP_REQ_MASK;
@@ -472,43 +595,7 @@ int ena_com_add_single_rx_desc(struct ena_com_io_sq *io_sq,
desc->buff_addr_hi =
((ena_buf->paddr & GENMASK_ULL(io_sq->dma_addr_bits - 1, 32)) >> 32);
- ena_com_sq_update_tail(io_sq);
-
- return 0;
-}
-
-int ena_com_tx_comp_req_id_get(struct ena_com_io_cq *io_cq, u16 *req_id)
-{
- u8 expected_phase, cdesc_phase;
- struct ena_eth_io_tx_cdesc *cdesc;
- u16 masked_head;
-
- masked_head = io_cq->head & (io_cq->q_depth - 1);
- expected_phase = io_cq->phase;
-
- cdesc = (struct ena_eth_io_tx_cdesc *)
- ((uintptr_t)io_cq->cdesc_addr.virt_addr +
- (masked_head * io_cq->cdesc_entry_size_in_bytes));
-
- /* When the current completion descriptor phase isn't the same as the
- * expected, it mean that the device still didn't update
- * this completion.
- */
- cdesc_phase = READ_ONCE(cdesc->flags) & ENA_ETH_IO_TX_CDESC_PHASE_MASK;
- if (cdesc_phase != expected_phase)
- return -EAGAIN;
-
- dma_rmb();
- if (unlikely(cdesc->req_id >= io_cq->q_depth)) {
- pr_err("Invalid req id %d\n", cdesc->req_id);
- return -EINVAL;
- }
-
- ena_com_cq_inc_head(io_cq);
-
- *req_id = READ_ONCE(cdesc->req_id);
-
- return 0;
+ return ena_com_sq_update_tail(io_sq);
}
bool ena_com_cq_empty(struct ena_com_io_cq *io_cq)
diff --git a/drivers/net/ethernet/amazon/ena/ena_eth_com.h b/drivers/net/ethernet/amazon/ena/ena_eth_com.h
index 2f7657227cfe..340d02b64ca6 100644
--- a/drivers/net/ethernet/amazon/ena/ena_eth_com.h
+++ b/drivers/net/ethernet/amazon/ena/ena_eth_com.h
@@ -67,6 +67,7 @@ struct ena_com_rx_ctx {
enum ena_eth_io_l4_proto_index l4_proto;
bool l3_csum_err;
bool l4_csum_err;
+ u8 l4_csum_checked;
/* fragmented packet */
bool frag;
u32 hash;
@@ -86,8 +87,6 @@ int ena_com_add_single_rx_desc(struct ena_com_io_sq *io_sq,
struct ena_com_buf *ena_buf,
u16 req_id);
-int ena_com_tx_comp_req_id_get(struct ena_com_io_cq *io_cq, u16 *req_id);
-
bool ena_com_cq_empty(struct ena_com_io_cq *io_cq);
static inline void ena_com_unmask_intr(struct ena_com_io_cq *io_cq,
@@ -96,7 +95,7 @@ static inline void ena_com_unmask_intr(struct ena_com_io_cq *io_cq,
writel(intr_reg->intr_control, io_cq->unmask_reg);
}
-static inline int ena_com_sq_empty_space(struct ena_com_io_sq *io_sq)
+static inline int ena_com_free_desc(struct ena_com_io_sq *io_sq)
{
u16 tail, next_to_comp, cnt;
@@ -107,11 +106,28 @@ static inline int ena_com_sq_empty_space(struct ena_com_io_sq *io_sq)
return io_sq->q_depth - 1 - cnt;
}
-static inline int ena_com_write_sq_doorbell(struct ena_com_io_sq *io_sq)
+/* Check if the submission queue has enough space to hold required_buffers */
+static inline bool ena_com_sq_have_enough_space(struct ena_com_io_sq *io_sq,
+ u16 required_buffers)
{
- u16 tail;
+ int temp;
- tail = io_sq->tail;
+ if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST)
+ return ena_com_free_desc(io_sq) >= required_buffers;
+
+ /* This calculation doesn't need to be 100% accurate. So to reduce
+ * the calculation overhead just Subtract 2 lines from the free descs
+ * (one for the header line and one to compensate the devision
+ * down calculation.
+ */
+ temp = required_buffers / io_sq->llq_info.descs_per_entry + 2;
+
+ return ena_com_free_desc(io_sq) > temp;
+}
+
+static inline int ena_com_write_sq_doorbell(struct ena_com_io_sq *io_sq)
+{
+ u16 tail = io_sq->tail;
pr_debug("write submission queue doorbell for queue: %d tail: %d\n",
io_sq->qid, tail);
@@ -159,4 +175,48 @@ static inline void ena_com_comp_ack(struct ena_com_io_sq *io_sq, u16 elem)
io_sq->next_to_comp += elem;
}
+static inline void ena_com_cq_inc_head(struct ena_com_io_cq *io_cq)
+{
+ io_cq->head++;
+
+ /* Switch phase bit in case of wrap around */
+ if (unlikely((io_cq->head & (io_cq->q_depth - 1)) == 0))
+ io_cq->phase ^= 1;
+}
+
+static inline int ena_com_tx_comp_req_id_get(struct ena_com_io_cq *io_cq,
+ u16 *req_id)
+{
+ u8 expected_phase, cdesc_phase;
+ struct ena_eth_io_tx_cdesc *cdesc;
+ u16 masked_head;
+
+ masked_head = io_cq->head & (io_cq->q_depth - 1);
+ expected_phase = io_cq->phase;
+
+ cdesc = (struct ena_eth_io_tx_cdesc *)
+ ((uintptr_t)io_cq->cdesc_addr.virt_addr +
+ (masked_head * io_cq->cdesc_entry_size_in_bytes));
+
+ /* When the current completion descriptor phase isn't the same as the
+ * expected, it mean that the device still didn't update
+ * this completion.
+ */
+ cdesc_phase = READ_ONCE(cdesc->flags) & ENA_ETH_IO_TX_CDESC_PHASE_MASK;
+ if (cdesc_phase != expected_phase)
+ return -EAGAIN;
+
+ dma_rmb();
+
+ *req_id = READ_ONCE(cdesc->req_id);
+ if (unlikely(*req_id >= io_cq->q_depth)) {
+ pr_err("Invalid req id %d\n", cdesc->req_id);
+ return -EINVAL;
+ }
+
+ ena_com_cq_inc_head(io_cq);
+
+ return 0;
+}
+
#endif /* ENA_ETH_COM_H_ */
diff --git a/drivers/net/ethernet/amazon/ena/ena_eth_io_defs.h b/drivers/net/ethernet/amazon/ena/ena_eth_io_defs.h
index f320c58793a5..00e0f056a741 100644
--- a/drivers/net/ethernet/amazon/ena/ena_eth_io_defs.h
+++ b/drivers/net/ethernet/amazon/ena/ena_eth_io_defs.h
@@ -33,25 +33,18 @@
#define _ENA_ETH_IO_H_
enum ena_eth_io_l3_proto_index {
- ENA_ETH_IO_L3_PROTO_UNKNOWN = 0,
-
- ENA_ETH_IO_L3_PROTO_IPV4 = 8,
-
- ENA_ETH_IO_L3_PROTO_IPV6 = 11,
-
- ENA_ETH_IO_L3_PROTO_FCOE = 21,
-
- ENA_ETH_IO_L3_PROTO_ROCE = 22,
+ ENA_ETH_IO_L3_PROTO_UNKNOWN = 0,
+ ENA_ETH_IO_L3_PROTO_IPV4 = 8,
+ ENA_ETH_IO_L3_PROTO_IPV6 = 11,
+ ENA_ETH_IO_L3_PROTO_FCOE = 21,
+ ENA_ETH_IO_L3_PROTO_ROCE = 22,
};
enum ena_eth_io_l4_proto_index {
- ENA_ETH_IO_L4_PROTO_UNKNOWN = 0,
-
- ENA_ETH_IO_L4_PROTO_TCP = 12,
-
- ENA_ETH_IO_L4_PROTO_UDP = 13,
-
- ENA_ETH_IO_L4_PROTO_ROUTEABLE_ROCE = 23,
+ ENA_ETH_IO_L4_PROTO_UNKNOWN = 0,
+ ENA_ETH_IO_L4_PROTO_TCP = 12,
+ ENA_ETH_IO_L4_PROTO_UDP = 13,
+ ENA_ETH_IO_L4_PROTO_ROUTEABLE_ROCE = 23,
};
struct ena_eth_io_tx_desc {
@@ -242,9 +235,13 @@ struct ena_eth_io_rx_cdesc_base {
* checksum error detected, or, the controller didn't
* validate the checksum. This bit is valid only when
* l4_proto_idx indicates TCP/UDP packet, and,
- * ipv4_frag is not set
+ * ipv4_frag is not set. This bit is valid only when
+ * l4_csum_checked below is set.
* 15 : ipv4_frag - Indicates IPv4 fragmented packet
- * 23:16 : reserved16
+ * 16 : l4_csum_checked - L4 checksum was verified
+ * (could be OK or error), when cleared the status of
+ * checksum is unknown
+ * 23:17 : reserved17 - MBZ
* 24 : phase
* 25 : l3_csum2 - second checksum engine result
* 26 : first - Indicates first descriptor in
@@ -303,114 +300,116 @@ struct ena_eth_io_numa_node_cfg_reg {
};
/* tx_desc */
-#define ENA_ETH_IO_TX_DESC_LENGTH_MASK GENMASK(15, 0)
-#define ENA_ETH_IO_TX_DESC_REQ_ID_HI_SHIFT 16
-#define ENA_ETH_IO_TX_DESC_REQ_ID_HI_MASK GENMASK(21, 16)
-#define ENA_ETH_IO_TX_DESC_META_DESC_SHIFT 23
-#define ENA_ETH_IO_TX_DESC_META_DESC_MASK BIT(23)
-#define ENA_ETH_IO_TX_DESC_PHASE_SHIFT 24
-#define ENA_ETH_IO_TX_DESC_PHASE_MASK BIT(24)
-#define ENA_ETH_IO_TX_DESC_FIRST_SHIFT 26
-#define ENA_ETH_IO_TX_DESC_FIRST_MASK BIT(26)
-#define ENA_ETH_IO_TX_DESC_LAST_SHIFT 27
-#define ENA_ETH_IO_TX_DESC_LAST_MASK BIT(27)
-#define ENA_ETH_IO_TX_DESC_COMP_REQ_SHIFT 28
-#define ENA_ETH_IO_TX_DESC_COMP_REQ_MASK BIT(28)
-#define ENA_ETH_IO_TX_DESC_L3_PROTO_IDX_MASK GENMASK(3, 0)
-#define ENA_ETH_IO_TX_DESC_DF_SHIFT 4
-#define ENA_ETH_IO_TX_DESC_DF_MASK BIT(4)
-#define ENA_ETH_IO_TX_DESC_TSO_EN_SHIFT 7
-#define ENA_ETH_IO_TX_DESC_TSO_EN_MASK BIT(7)
-#define ENA_ETH_IO_TX_DESC_L4_PROTO_IDX_SHIFT 8
-#define ENA_ETH_IO_TX_DESC_L4_PROTO_IDX_MASK GENMASK(12, 8)
-#define ENA_ETH_IO_TX_DESC_L3_CSUM_EN_SHIFT 13
-#define ENA_ETH_IO_TX_DESC_L3_CSUM_EN_MASK BIT(13)
-#define ENA_ETH_IO_TX_DESC_L4_CSUM_EN_SHIFT 14
-#define ENA_ETH_IO_TX_DESC_L4_CSUM_EN_MASK BIT(14)
-#define ENA_ETH_IO_TX_DESC_ETHERNET_FCS_DIS_SHIFT 15
-#define ENA_ETH_IO_TX_DESC_ETHERNET_FCS_DIS_MASK BIT(15)
-#define ENA_ETH_IO_TX_DESC_L4_CSUM_PARTIAL_SHIFT 17
-#define ENA_ETH_IO_TX_DESC_L4_CSUM_PARTIAL_MASK BIT(17)
-#define ENA_ETH_IO_TX_DESC_REQ_ID_LO_SHIFT 22
-#define ENA_ETH_IO_TX_DESC_REQ_ID_LO_MASK GENMASK(31, 22)
-#define ENA_ETH_IO_TX_DESC_ADDR_HI_MASK GENMASK(15, 0)
-#define ENA_ETH_IO_TX_DESC_HEADER_LENGTH_SHIFT 24
-#define ENA_ETH_IO_TX_DESC_HEADER_LENGTH_MASK GENMASK(31, 24)
+#define ENA_ETH_IO_TX_DESC_LENGTH_MASK GENMASK(15, 0)
+#define ENA_ETH_IO_TX_DESC_REQ_ID_HI_SHIFT 16
+#define ENA_ETH_IO_TX_DESC_REQ_ID_HI_MASK GENMASK(21, 16)
+#define ENA_ETH_IO_TX_DESC_META_DESC_SHIFT 23
+#define ENA_ETH_IO_TX_DESC_META_DESC_MASK BIT(23)
+#define ENA_ETH_IO_TX_DESC_PHASE_SHIFT 24
+#define ENA_ETH_IO_TX_DESC_PHASE_MASK BIT(24)
+#define ENA_ETH_IO_TX_DESC_FIRST_SHIFT 26
+#define ENA_ETH_IO_TX_DESC_FIRST_MASK BIT(26)
+#define ENA_ETH_IO_TX_DESC_LAST_SHIFT 27
+#define ENA_ETH_IO_TX_DESC_LAST_MASK BIT(27)
+#define ENA_ETH_IO_TX_DESC_COMP_REQ_SHIFT 28
+#define ENA_ETH_IO_TX_DESC_COMP_REQ_MASK BIT(28)
+#define ENA_ETH_IO_TX_DESC_L3_PROTO_IDX_MASK GENMASK(3, 0)
+#define ENA_ETH_IO_TX_DESC_DF_SHIFT 4
+#define ENA_ETH_IO_TX_DESC_DF_MASK BIT(4)
+#define ENA_ETH_IO_TX_DESC_TSO_EN_SHIFT 7
+#define ENA_ETH_IO_TX_DESC_TSO_EN_MASK BIT(7)
+#define ENA_ETH_IO_TX_DESC_L4_PROTO_IDX_SHIFT 8
+#define ENA_ETH_IO_TX_DESC_L4_PROTO_IDX_MASK GENMASK(12, 8)
+#define ENA_ETH_IO_TX_DESC_L3_CSUM_EN_SHIFT 13
+#define ENA_ETH_IO_TX_DESC_L3_CSUM_EN_MASK BIT(13)
+#define ENA_ETH_IO_TX_DESC_L4_CSUM_EN_SHIFT 14
+#define ENA_ETH_IO_TX_DESC_L4_CSUM_EN_MASK BIT(14)
+#define ENA_ETH_IO_TX_DESC_ETHERNET_FCS_DIS_SHIFT 15
+#define ENA_ETH_IO_TX_DESC_ETHERNET_FCS_DIS_MASK BIT(15)
+#define ENA_ETH_IO_TX_DESC_L4_CSUM_PARTIAL_SHIFT 17
+#define ENA_ETH_IO_TX_DESC_L4_CSUM_PARTIAL_MASK BIT(17)
+#define ENA_ETH_IO_TX_DESC_REQ_ID_LO_SHIFT 22
+#define ENA_ETH_IO_TX_DESC_REQ_ID_LO_MASK GENMASK(31, 22)
+#define ENA_ETH_IO_TX_DESC_ADDR_HI_MASK GENMASK(15, 0)
+#define ENA_ETH_IO_TX_DESC_HEADER_LENGTH_SHIFT 24
+#define ENA_ETH_IO_TX_DESC_HEADER_LENGTH_MASK GENMASK(31, 24)
/* tx_meta_desc */
-#define ENA_ETH_IO_TX_META_DESC_REQ_ID_LO_MASK GENMASK(9, 0)
-#define ENA_ETH_IO_TX_META_DESC_EXT_VALID_SHIFT 14
-#define ENA_ETH_IO_TX_META_DESC_EXT_VALID_MASK BIT(14)
-#define ENA_ETH_IO_TX_META_DESC_MSS_HI_SHIFT 16
-#define ENA_ETH_IO_TX_META_DESC_MSS_HI_MASK GENMASK(19, 16)
-#define ENA_ETH_IO_TX_META_DESC_ETH_META_TYPE_SHIFT 20
-#define ENA_ETH_IO_TX_META_DESC_ETH_META_TYPE_MASK BIT(20)
-#define ENA_ETH_IO_TX_META_DESC_META_STORE_SHIFT 21
-#define ENA_ETH_IO_TX_META_DESC_META_STORE_MASK BIT(21)
-#define ENA_ETH_IO_TX_META_DESC_META_DESC_SHIFT 23
-#define ENA_ETH_IO_TX_META_DESC_META_DESC_MASK BIT(23)
-#define ENA_ETH_IO_TX_META_DESC_PHASE_SHIFT 24
-#define ENA_ETH_IO_TX_META_DESC_PHASE_MASK BIT(24)
-#define ENA_ETH_IO_TX_META_DESC_FIRST_SHIFT 26
-#define ENA_ETH_IO_TX_META_DESC_FIRST_MASK BIT(26)
-#define ENA_ETH_IO_TX_META_DESC_LAST_SHIFT 27
-#define ENA_ETH_IO_TX_META_DESC_LAST_MASK BIT(27)
-#define ENA_ETH_IO_TX_META_DESC_COMP_REQ_SHIFT 28
-#define ENA_ETH_IO_TX_META_DESC_COMP_REQ_MASK BIT(28)
-#define ENA_ETH_IO_TX_META_DESC_REQ_ID_HI_MASK GENMASK(5, 0)
-#define ENA_ETH_IO_TX_META_DESC_L3_HDR_LEN_MASK GENMASK(7, 0)
-#define ENA_ETH_IO_TX_META_DESC_L3_HDR_OFF_SHIFT 8
-#define ENA_ETH_IO_TX_META_DESC_L3_HDR_OFF_MASK GENMASK(15, 8)
-#define ENA_ETH_IO_TX_META_DESC_L4_HDR_LEN_IN_WORDS_SHIFT 16
-#define ENA_ETH_IO_TX_META_DESC_L4_HDR_LEN_IN_WORDS_MASK GENMASK(21, 16)
-#define ENA_ETH_IO_TX_META_DESC_MSS_LO_SHIFT 22
-#define ENA_ETH_IO_TX_META_DESC_MSS_LO_MASK GENMASK(31, 22)
+#define ENA_ETH_IO_TX_META_DESC_REQ_ID_LO_MASK GENMASK(9, 0)
+#define ENA_ETH_IO_TX_META_DESC_EXT_VALID_SHIFT 14
+#define ENA_ETH_IO_TX_META_DESC_EXT_VALID_MASK BIT(14)
+#define ENA_ETH_IO_TX_META_DESC_MSS_HI_SHIFT 16
+#define ENA_ETH_IO_TX_META_DESC_MSS_HI_MASK GENMASK(19, 16)
+#define ENA_ETH_IO_TX_META_DESC_ETH_META_TYPE_SHIFT 20
+#define ENA_ETH_IO_TX_META_DESC_ETH_META_TYPE_MASK BIT(20)
+#define ENA_ETH_IO_TX_META_DESC_META_STORE_SHIFT 21
+#define ENA_ETH_IO_TX_META_DESC_META_STORE_MASK BIT(21)
+#define ENA_ETH_IO_TX_META_DESC_META_DESC_SHIFT 23
+#define ENA_ETH_IO_TX_META_DESC_META_DESC_MASK BIT(23)
+#define ENA_ETH_IO_TX_META_DESC_PHASE_SHIFT 24
+#define ENA_ETH_IO_TX_META_DESC_PHASE_MASK BIT(24)
+#define ENA_ETH_IO_TX_META_DESC_FIRST_SHIFT 26
+#define ENA_ETH_IO_TX_META_DESC_FIRST_MASK BIT(26)
+#define ENA_ETH_IO_TX_META_DESC_LAST_SHIFT 27
+#define ENA_ETH_IO_TX_META_DESC_LAST_MASK BIT(27)
+#define ENA_ETH_IO_TX_META_DESC_COMP_REQ_SHIFT 28
+#define ENA_ETH_IO_TX_META_DESC_COMP_REQ_MASK BIT(28)
+#define ENA_ETH_IO_TX_META_DESC_REQ_ID_HI_MASK GENMASK(5, 0)
+#define ENA_ETH_IO_TX_META_DESC_L3_HDR_LEN_MASK GENMASK(7, 0)
+#define ENA_ETH_IO_TX_META_DESC_L3_HDR_OFF_SHIFT 8
+#define ENA_ETH_IO_TX_META_DESC_L3_HDR_OFF_MASK GENMASK(15, 8)
+#define ENA_ETH_IO_TX_META_DESC_L4_HDR_LEN_IN_WORDS_SHIFT 16
+#define ENA_ETH_IO_TX_META_DESC_L4_HDR_LEN_IN_WORDS_MASK GENMASK(21, 16)
+#define ENA_ETH_IO_TX_META_DESC_MSS_LO_SHIFT 22
+#define ENA_ETH_IO_TX_META_DESC_MSS_LO_MASK GENMASK(31, 22)
/* tx_cdesc */
-#define ENA_ETH_IO_TX_CDESC_PHASE_MASK BIT(0)
+#define ENA_ETH_IO_TX_CDESC_PHASE_MASK BIT(0)
/* rx_desc */
-#define ENA_ETH_IO_RX_DESC_PHASE_MASK BIT(0)
-#define ENA_ETH_IO_RX_DESC_FIRST_SHIFT 2
-#define ENA_ETH_IO_RX_DESC_FIRST_MASK BIT(2)
-#define ENA_ETH_IO_RX_DESC_LAST_SHIFT 3
-#define ENA_ETH_IO_RX_DESC_LAST_MASK BIT(3)
-#define ENA_ETH_IO_RX_DESC_COMP_REQ_SHIFT 4
-#define ENA_ETH_IO_RX_DESC_COMP_REQ_MASK BIT(4)
+#define ENA_ETH_IO_RX_DESC_PHASE_MASK BIT(0)
+#define ENA_ETH_IO_RX_DESC_FIRST_SHIFT 2
+#define ENA_ETH_IO_RX_DESC_FIRST_MASK BIT(2)
+#define ENA_ETH_IO_RX_DESC_LAST_SHIFT 3
+#define ENA_ETH_IO_RX_DESC_LAST_MASK BIT(3)
+#define ENA_ETH_IO_RX_DESC_COMP_REQ_SHIFT 4
+#define ENA_ETH_IO_RX_DESC_COMP_REQ_MASK BIT(4)
/* rx_cdesc_base */
-#define ENA_ETH_IO_RX_CDESC_BASE_L3_PROTO_IDX_MASK GENMASK(4, 0)
-#define ENA_ETH_IO_RX_CDESC_BASE_SRC_VLAN_CNT_SHIFT 5
-#define ENA_ETH_IO_RX_CDESC_BASE_SRC_VLAN_CNT_MASK GENMASK(6, 5)
-#define ENA_ETH_IO_RX_CDESC_BASE_L4_PROTO_IDX_SHIFT 8
-#define ENA_ETH_IO_RX_CDESC_BASE_L4_PROTO_IDX_MASK GENMASK(12, 8)
-#define ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM_ERR_SHIFT 13
-#define ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM_ERR_MASK BIT(13)
-#define ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_ERR_SHIFT 14
-#define ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_ERR_MASK BIT(14)
-#define ENA_ETH_IO_RX_CDESC_BASE_IPV4_FRAG_SHIFT 15
-#define ENA_ETH_IO_RX_CDESC_BASE_IPV4_FRAG_MASK BIT(15)
-#define ENA_ETH_IO_RX_CDESC_BASE_PHASE_SHIFT 24
-#define ENA_ETH_IO_RX_CDESC_BASE_PHASE_MASK BIT(24)
-#define ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM2_SHIFT 25
-#define ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM2_MASK BIT(25)
-#define ENA_ETH_IO_RX_CDESC_BASE_FIRST_SHIFT 26
-#define ENA_ETH_IO_RX_CDESC_BASE_FIRST_MASK BIT(26)
-#define ENA_ETH_IO_RX_CDESC_BASE_LAST_SHIFT 27
-#define ENA_ETH_IO_RX_CDESC_BASE_LAST_MASK BIT(27)
-#define ENA_ETH_IO_RX_CDESC_BASE_BUFFER_SHIFT 30
-#define ENA_ETH_IO_RX_CDESC_BASE_BUFFER_MASK BIT(30)
+#define ENA_ETH_IO_RX_CDESC_BASE_L3_PROTO_IDX_MASK GENMASK(4, 0)
+#define ENA_ETH_IO_RX_CDESC_BASE_SRC_VLAN_CNT_SHIFT 5
+#define ENA_ETH_IO_RX_CDESC_BASE_SRC_VLAN_CNT_MASK GENMASK(6, 5)
+#define ENA_ETH_IO_RX_CDESC_BASE_L4_PROTO_IDX_SHIFT 8
+#define ENA_ETH_IO_RX_CDESC_BASE_L4_PROTO_IDX_MASK GENMASK(12, 8)
+#define ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM_ERR_SHIFT 13
+#define ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM_ERR_MASK BIT(13)
+#define ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_ERR_SHIFT 14
+#define ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_ERR_MASK BIT(14)
+#define ENA_ETH_IO_RX_CDESC_BASE_IPV4_FRAG_SHIFT 15
+#define ENA_ETH_IO_RX_CDESC_BASE_IPV4_FRAG_MASK BIT(15)
+#define ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_CHECKED_SHIFT 16
+#define ENA_ETH_IO_RX_CDESC_BASE_L4_CSUM_CHECKED_MASK BIT(16)
+#define ENA_ETH_IO_RX_CDESC_BASE_PHASE_SHIFT 24
+#define ENA_ETH_IO_RX_CDESC_BASE_PHASE_MASK BIT(24)
+#define ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM2_SHIFT 25
+#define ENA_ETH_IO_RX_CDESC_BASE_L3_CSUM2_MASK BIT(25)
+#define ENA_ETH_IO_RX_CDESC_BASE_FIRST_SHIFT 26
+#define ENA_ETH_IO_RX_CDESC_BASE_FIRST_MASK BIT(26)
+#define ENA_ETH_IO_RX_CDESC_BASE_LAST_SHIFT 27
+#define ENA_ETH_IO_RX_CDESC_BASE_LAST_MASK BIT(27)
+#define ENA_ETH_IO_RX_CDESC_BASE_BUFFER_SHIFT 30
+#define ENA_ETH_IO_RX_CDESC_BASE_BUFFER_MASK BIT(30)
/* intr_reg */
-#define ENA_ETH_IO_INTR_REG_RX_INTR_DELAY_MASK GENMASK(14, 0)
-#define ENA_ETH_IO_INTR_REG_TX_INTR_DELAY_SHIFT 15
-#define ENA_ETH_IO_INTR_REG_TX_INTR_DELAY_MASK GENMASK(29, 15)
-#define ENA_ETH_IO_INTR_REG_INTR_UNMASK_SHIFT 30
-#define ENA_ETH_IO_INTR_REG_INTR_UNMASK_MASK BIT(30)
+#define ENA_ETH_IO_INTR_REG_RX_INTR_DELAY_MASK GENMASK(14, 0)
+#define ENA_ETH_IO_INTR_REG_TX_INTR_DELAY_SHIFT 15
+#define ENA_ETH_IO_INTR_REG_TX_INTR_DELAY_MASK GENMASK(29, 15)
+#define ENA_ETH_IO_INTR_REG_INTR_UNMASK_SHIFT 30
+#define ENA_ETH_IO_INTR_REG_INTR_UNMASK_MASK BIT(30)
/* numa_node_cfg_reg */
-#define ENA_ETH_IO_NUMA_NODE_CFG_REG_NUMA_MASK GENMASK(7, 0)
-#define ENA_ETH_IO_NUMA_NODE_CFG_REG_ENABLED_SHIFT 31
-#define ENA_ETH_IO_NUMA_NODE_CFG_REG_ENABLED_MASK BIT(31)
+#define ENA_ETH_IO_NUMA_NODE_CFG_REG_NUMA_MASK GENMASK(7, 0)
+#define ENA_ETH_IO_NUMA_NODE_CFG_REG_ENABLED_SHIFT 31
+#define ENA_ETH_IO_NUMA_NODE_CFG_REG_ENABLED_MASK BIT(31)
#endif /*_ENA_ETH_IO_H_ */
diff --git a/drivers/net/ethernet/amazon/ena/ena_ethtool.c b/drivers/net/ethernet/amazon/ena/ena_ethtool.c
index 521607bc4393..f3a5a384e6e8 100644
--- a/drivers/net/ethernet/amazon/ena/ena_ethtool.c
+++ b/drivers/net/ethernet/amazon/ena/ena_ethtool.c
@@ -81,6 +81,7 @@ static const struct ena_stats ena_stats_tx_strings[] = {
ENA_STAT_TX_ENTRY(doorbells),
ENA_STAT_TX_ENTRY(prepare_ctx_err),
ENA_STAT_TX_ENTRY(bad_req_id),
+ ENA_STAT_TX_ENTRY(llq_buffer_copy),
ENA_STAT_TX_ENTRY(missed_tx),
};
@@ -96,6 +97,7 @@ static const struct ena_stats ena_stats_rx_strings[] = {
ENA_STAT_RX_ENTRY(rx_copybreak_pkt),
ENA_STAT_RX_ENTRY(bad_req_id),
ENA_STAT_RX_ENTRY(empty_rx_ring),
+ ENA_STAT_RX_ENTRY(csum_unchecked),
};
static const struct ena_stats ena_stats_ena_com_strings[] = {
diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c
index 29b5774dd32d..18956e7604a3 100644
--- a/drivers/net/ethernet/amazon/ena/ena_netdev.c
+++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c
@@ -39,7 +39,6 @@
#include <linux/if_vlan.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/numa.h>
#include <linux/pci.h>
#include <linux/utsname.h>
@@ -238,6 +237,17 @@ static int ena_setup_tx_resources(struct ena_adapter *adapter, int qid)
}
}
+ size = tx_ring->tx_max_header_size;
+ tx_ring->push_buf_intermediate_buf = vzalloc_node(size, node);
+ if (!tx_ring->push_buf_intermediate_buf) {
+ tx_ring->push_buf_intermediate_buf = vzalloc(size);
+ if (!tx_ring->push_buf_intermediate_buf) {
+ vfree(tx_ring->tx_buffer_info);
+ vfree(tx_ring->free_tx_ids);
+ return -ENOMEM;
+ }
+ }
+
/* Req id ring for TX out of order completions */
for (i = 0; i < tx_ring->ring_size; i++)
tx_ring->free_tx_ids[i] = i;
@@ -266,6 +276,9 @@ static void ena_free_tx_resources(struct ena_adapter *adapter, int qid)
vfree(tx_ring->free_tx_ids);
tx_ring->free_tx_ids = NULL;
+
+ vfree(tx_ring->push_buf_intermediate_buf);
+ tx_ring->push_buf_intermediate_buf = NULL;
}
/* ena_setup_all_tx_resources - allocate I/O Tx queues resources for All queues
@@ -603,6 +616,36 @@ static void ena_free_all_rx_bufs(struct ena_adapter *adapter)
ena_free_rx_bufs(adapter, i);
}
+static inline void ena_unmap_tx_skb(struct ena_ring *tx_ring,
+ struct ena_tx_buffer *tx_info)
+{
+ struct ena_com_buf *ena_buf;
+ u32 cnt;
+ int i;
+
+ ena_buf = tx_info->bufs;
+ cnt = tx_info->num_of_bufs;
+
+ if (unlikely(!cnt))
+ return;
+
+ if (tx_info->map_linear_data) {
+ dma_unmap_single(tx_ring->dev,
+ dma_unmap_addr(ena_buf, paddr),
+ dma_unmap_len(ena_buf, len),
+ DMA_TO_DEVICE);
+ ena_buf++;
+ cnt--;
+ }
+
+ /* unmap remaining mapped pages */
+ for (i = 0; i < cnt; i++) {
+ dma_unmap_page(tx_ring->dev, dma_unmap_addr(ena_buf, paddr),
+ dma_unmap_len(ena_buf, len), DMA_TO_DEVICE);
+ ena_buf++;
+ }
+}
+
/* ena_free_tx_bufs - Free Tx Buffers per Queue
* @tx_ring: TX ring for which buffers be freed
*/
@@ -613,9 +656,6 @@ static void ena_free_tx_bufs(struct ena_ring *tx_ring)
for (i = 0; i < tx_ring->ring_size; i++) {
struct ena_tx_buffer *tx_info = &tx_ring->tx_buffer_info[i];
- struct ena_com_buf *ena_buf;
- int nr_frags;
- int j;
if (!tx_info->skb)
continue;
@@ -631,21 +671,7 @@ static void ena_free_tx_bufs(struct ena_ring *tx_ring)
tx_ring->qid, i);
}
- ena_buf = tx_info->bufs;
- dma_unmap_single(tx_ring->dev,
- ena_buf->paddr,
- ena_buf->len,
- DMA_TO_DEVICE);
-
- /* unmap remaining mapped pages */
- nr_frags = tx_info->num_of_bufs - 1;
- for (j = 0; j < nr_frags; j++) {
- ena_buf++;
- dma_unmap_page(tx_ring->dev,
- ena_buf->paddr,
- ena_buf->len,
- DMA_TO_DEVICE);
- }
+ ena_unmap_tx_skb(tx_ring, tx_info);
dev_kfree_skb_any(tx_info->skb);
}
@@ -736,8 +762,6 @@ static int ena_clean_tx_irq(struct ena_ring *tx_ring, u32 budget)
while (tx_pkts < budget) {
struct ena_tx_buffer *tx_info;
struct sk_buff *skb;
- struct ena_com_buf *ena_buf;
- int i, nr_frags;
rc = ena_com_tx_comp_req_id_get(tx_ring->ena_com_io_cq,
&req_id);
@@ -757,24 +781,7 @@ static int ena_clean_tx_irq(struct ena_ring *tx_ring, u32 budget)
tx_info->skb = NULL;
tx_info->last_jiffies = 0;
- if (likely(tx_info->num_of_bufs != 0)) {
- ena_buf = tx_info->bufs;
-
- dma_unmap_single(tx_ring->dev,
- dma_unmap_addr(ena_buf, paddr),
- dma_unmap_len(ena_buf, len),
- DMA_TO_DEVICE);
-
- /* unmap remaining mapped pages */
- nr_frags = tx_info->num_of_bufs - 1;
- for (i = 0; i < nr_frags; i++) {
- ena_buf++;
- dma_unmap_page(tx_ring->dev,
- dma_unmap_addr(ena_buf, paddr),
- dma_unmap_len(ena_buf, len),
- DMA_TO_DEVICE);
- }
- }
+ ena_unmap_tx_skb(tx_ring, tx_info);
netif_dbg(tx_ring->adapter, tx_done, tx_ring->netdev,
"tx_poll: q %d skb %p completed\n", tx_ring->qid,
@@ -805,12 +812,13 @@ static int ena_clean_tx_irq(struct ena_ring *tx_ring, u32 budget)
*/
smp_mb();
- above_thresh = ena_com_sq_empty_space(tx_ring->ena_com_io_sq) >
- ENA_TX_WAKEUP_THRESH;
+ above_thresh = ena_com_sq_have_enough_space(tx_ring->ena_com_io_sq,
+ ENA_TX_WAKEUP_THRESH);
if (unlikely(netif_tx_queue_stopped(txq) && above_thresh)) {
__netif_tx_lock(txq, smp_processor_id());
- above_thresh = ena_com_sq_empty_space(tx_ring->ena_com_io_sq) >
- ENA_TX_WAKEUP_THRESH;
+ above_thresh =
+ ena_com_sq_have_enough_space(tx_ring->ena_com_io_sq,
+ ENA_TX_WAKEUP_THRESH);
if (netif_tx_queue_stopped(txq) && above_thresh) {
netif_tx_wake_queue(txq);
u64_stats_update_begin(&tx_ring->syncp);
@@ -986,8 +994,19 @@ static inline void ena_rx_checksum(struct ena_ring *rx_ring,
return;
}
- skb->ip_summed = CHECKSUM_UNNECESSARY;
+ if (likely(ena_rx_ctx->l4_csum_checked)) {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ } else {
+ u64_stats_update_begin(&rx_ring->syncp);
+ rx_ring->rx_stats.csum_unchecked++;
+ u64_stats_update_end(&rx_ring->syncp);
+ skb->ip_summed = CHECKSUM_NONE;
+ }
+ } else {
+ skb->ip_summed = CHECKSUM_NONE;
+ return;
}
+
}
static void ena_set_rx_hash(struct ena_ring *rx_ring,
@@ -1102,8 +1121,10 @@ static int ena_clean_rx_irq(struct ena_ring *rx_ring, struct napi_struct *napi,
rx_ring->next_to_clean = next_to_clean;
- refill_required = ena_com_sq_empty_space(rx_ring->ena_com_io_sq);
- refill_threshold = rx_ring->ring_size / ENA_RX_REFILL_THRESH_DIVIDER;
+ refill_required = ena_com_free_desc(rx_ring->ena_com_io_sq);
+ refill_threshold =
+ min_t(int, rx_ring->ring_size / ENA_RX_REFILL_THRESH_DIVIDER,
+ ENA_RX_REFILL_THRESH_PACKET);
/* Optimization, try to batch new rx buffers */
if (refill_required > refill_threshold) {
@@ -1300,7 +1321,6 @@ static int ena_enable_msix(struct ena_adapter *adapter, int num_queues)
/* Reserved the max msix vectors we might need */
msix_vecs = ENA_MAX_MSIX_VEC(num_queues);
-
netif_dbg(adapter, probe, adapter->netdev,
"trying to enable MSI-X, vectors %d\n", msix_vecs);
@@ -1575,8 +1595,6 @@ static int ena_up_complete(struct ena_adapter *adapter)
if (rc)
return rc;
- ena_init_napi(adapter);
-
ena_change_mtu(adapter->netdev, adapter->netdev->mtu);
ena_refill_all_rx_bufs(adapter);
@@ -1593,7 +1611,7 @@ static int ena_up_complete(struct ena_adapter *adapter)
static int ena_create_io_tx_queue(struct ena_adapter *adapter, int qid)
{
- struct ena_com_create_io_ctx ctx = { 0 };
+ struct ena_com_create_io_ctx ctx;
struct ena_com_dev *ena_dev;
struct ena_ring *tx_ring;
u32 msix_vector;
@@ -1606,6 +1624,8 @@ static int ena_create_io_tx_queue(struct ena_adapter *adapter, int qid)
msix_vector = ENA_IO_IRQ_IDX(qid);
ena_qid = ENA_IO_TXQ_IDX(qid);
+ memset(&ctx, 0x0, sizeof(ctx));
+
ctx.direction = ENA_COM_IO_QUEUE_DIRECTION_TX;
ctx.qid = ena_qid;
ctx.mem_queue_type = ena_dev->tx_mem_queue_type;
@@ -1659,7 +1679,7 @@ create_err:
static int ena_create_io_rx_queue(struct ena_adapter *adapter, int qid)
{
struct ena_com_dev *ena_dev;
- struct ena_com_create_io_ctx ctx = { 0 };
+ struct ena_com_create_io_ctx ctx;
struct ena_ring *rx_ring;
u32 msix_vector;
u16 ena_qid;
@@ -1671,6 +1691,8 @@ static int ena_create_io_rx_queue(struct ena_adapter *adapter, int qid)
msix_vector = ENA_IO_IRQ_IDX(qid);
ena_qid = ENA_IO_RXQ_IDX(qid);
+ memset(&ctx, 0x0, sizeof(ctx));
+
ctx.qid = ena_qid;
ctx.direction = ENA_COM_IO_QUEUE_DIRECTION_RX;
ctx.mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST;
@@ -1730,6 +1752,13 @@ static int ena_up(struct ena_adapter *adapter)
ena_setup_io_intr(adapter);
+ /* napi poll functions should be initialized before running
+ * request_irq(), to handle a rare condition where there is a pending
+ * interrupt, causing the ISR to fire immediately while the poll
+ * function wasn't set yet, causing a null dereference
+ */
+ ena_init_napi(adapter);
+
rc = ena_request_io_irq(adapter);
if (rc)
goto err_req_irq;
@@ -1981,73 +2010,70 @@ static int ena_check_and_linearize_skb(struct ena_ring *tx_ring,
return rc;
}
-/* Called with netif_tx_lock. */
-static netdev_tx_t ena_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static int ena_tx_map_skb(struct ena_ring *tx_ring,
+ struct ena_tx_buffer *tx_info,
+ struct sk_buff *skb,
+ void **push_hdr,
+ u16 *header_len)
{
- struct ena_adapter *adapter = netdev_priv(dev);
- struct ena_tx_buffer *tx_info;
- struct ena_com_tx_ctx ena_tx_ctx;
- struct ena_ring *tx_ring;
- struct netdev_queue *txq;
+ struct ena_adapter *adapter = tx_ring->adapter;
struct ena_com_buf *ena_buf;
- void *push_hdr;
- u32 len, last_frag;
- u16 next_to_use;
- u16 req_id;
- u16 push_len;
- u16 header_len;
dma_addr_t dma;
- int qid, rc, nb_hw_desc;
- int i = -1;
-
- netif_dbg(adapter, tx_queued, dev, "%s skb %p\n", __func__, skb);
- /* Determine which tx ring we will be placed on */
- qid = skb_get_queue_mapping(skb);
- tx_ring = &adapter->tx_ring[qid];
- txq = netdev_get_tx_queue(dev, qid);
-
- rc = ena_check_and_linearize_skb(tx_ring, skb);
- if (unlikely(rc))
- goto error_drop_packet;
+ u32 skb_head_len, frag_len, last_frag;
+ u16 push_len = 0;
+ u16 delta = 0;
+ int i = 0;
- skb_tx_timestamp(skb);
- len = skb_headlen(skb);
-
- next_to_use = tx_ring->next_to_use;
- req_id = tx_ring->free_tx_ids[next_to_use];
- tx_info = &tx_ring->tx_buffer_info[req_id];
- tx_info->num_of_bufs = 0;
-
- WARN(tx_info->skb, "SKB isn't NULL req_id %d\n", req_id);
- ena_buf = tx_info->bufs;
+ skb_head_len = skb_headlen(skb);
tx_info->skb = skb;
+ ena_buf = tx_info->bufs;
if (tx_ring->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) {
- /* prepared the push buffer */
- push_len = min_t(u32, len, tx_ring->tx_max_header_size);
- header_len = push_len;
- push_hdr = skb->data;
+ /* When the device is LLQ mode, the driver will copy
+ * the header into the device memory space.
+ * the ena_com layer assume the header is in a linear
+ * memory space.
+ * This assumption might be wrong since part of the header
+ * can be in the fragmented buffers.
+ * Use skb_header_pointer to make sure the header is in a
+ * linear memory space.
+ */
+
+ push_len = min_t(u32, skb->len, tx_ring->tx_max_header_size);
+ *push_hdr = skb_header_pointer(skb, 0, push_len,
+ tx_ring->push_buf_intermediate_buf);
+ *header_len = push_len;
+ if (unlikely(skb->data != *push_hdr)) {
+ u64_stats_update_begin(&tx_ring->syncp);
+ tx_ring->tx_stats.llq_buffer_copy++;
+ u64_stats_update_end(&tx_ring->syncp);
+
+ delta = push_len - skb_head_len;
+ }
} else {
- push_len = 0;
- header_len = min_t(u32, len, tx_ring->tx_max_header_size);
- push_hdr = NULL;
+ *push_hdr = NULL;
+ *header_len = min_t(u32, skb_head_len,
+ tx_ring->tx_max_header_size);
}
- netif_dbg(adapter, tx_queued, dev,
+ netif_dbg(adapter, tx_queued, adapter->netdev,
"skb: %p header_buf->vaddr: %p push_len: %d\n", skb,
- push_hdr, push_len);
+ *push_hdr, push_len);
- if (len > push_len) {
+ if (skb_head_len > push_len) {
dma = dma_map_single(tx_ring->dev, skb->data + push_len,
- len - push_len, DMA_TO_DEVICE);
- if (dma_mapping_error(tx_ring->dev, dma))
+ skb_head_len - push_len, DMA_TO_DEVICE);
+ if (unlikely(dma_mapping_error(tx_ring->dev, dma)))
goto error_report_dma_error;
ena_buf->paddr = dma;
- ena_buf->len = len - push_len;
+ ena_buf->len = skb_head_len - push_len;
ena_buf++;
tx_info->num_of_bufs++;
+ tx_info->map_linear_data = 1;
+ } else {
+ tx_info->map_linear_data = 0;
}
last_frag = skb_shinfo(skb)->nr_frags;
@@ -2055,18 +2081,75 @@ static netdev_tx_t ena_start_xmit(struct sk_buff *skb, struct net_device *dev)
for (i = 0; i < last_frag; i++) {
const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- len = skb_frag_size(frag);
- dma = skb_frag_dma_map(tx_ring->dev, frag, 0, len,
- DMA_TO_DEVICE);
- if (dma_mapping_error(tx_ring->dev, dma))
+ frag_len = skb_frag_size(frag);
+
+ if (unlikely(delta >= frag_len)) {
+ delta -= frag_len;
+ continue;
+ }
+
+ dma = skb_frag_dma_map(tx_ring->dev, frag, delta,
+ frag_len - delta, DMA_TO_DEVICE);
+ if (unlikely(dma_mapping_error(tx_ring->dev, dma)))
goto error_report_dma_error;
ena_buf->paddr = dma;
- ena_buf->len = len;
+ ena_buf->len = frag_len - delta;
ena_buf++;
+ tx_info->num_of_bufs++;
+ delta = 0;
}
- tx_info->num_of_bufs += last_frag;
+ return 0;
+
+error_report_dma_error:
+ u64_stats_update_begin(&tx_ring->syncp);
+ tx_ring->tx_stats.dma_mapping_err++;
+ u64_stats_update_end(&tx_ring->syncp);
+ netdev_warn(adapter->netdev, "failed to map skb\n");
+
+ tx_info->skb = NULL;
+
+ tx_info->num_of_bufs += i;
+ ena_unmap_tx_skb(tx_ring, tx_info);
+
+ return -EINVAL;
+}
+
+/* Called with netif_tx_lock. */
+static netdev_tx_t ena_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct ena_adapter *adapter = netdev_priv(dev);
+ struct ena_tx_buffer *tx_info;
+ struct ena_com_tx_ctx ena_tx_ctx;
+ struct ena_ring *tx_ring;
+ struct netdev_queue *txq;
+ void *push_hdr;
+ u16 next_to_use, req_id, header_len;
+ int qid, rc, nb_hw_desc;
+
+ netif_dbg(adapter, tx_queued, dev, "%s skb %p\n", __func__, skb);
+ /* Determine which tx ring we will be placed on */
+ qid = skb_get_queue_mapping(skb);
+ tx_ring = &adapter->tx_ring[qid];
+ txq = netdev_get_tx_queue(dev, qid);
+
+ rc = ena_check_and_linearize_skb(tx_ring, skb);
+ if (unlikely(rc))
+ goto error_drop_packet;
+
+ skb_tx_timestamp(skb);
+
+ next_to_use = tx_ring->next_to_use;
+ req_id = tx_ring->free_tx_ids[next_to_use];
+ tx_info = &tx_ring->tx_buffer_info[req_id];
+ tx_info->num_of_bufs = 0;
+
+ WARN(tx_info->skb, "SKB isn't NULL req_id %d\n", req_id);
+
+ rc = ena_tx_map_skb(tx_ring, tx_info, skb, &push_hdr, &header_len);
+ if (unlikely(rc))
+ goto error_drop_packet;
memset(&ena_tx_ctx, 0x0, sizeof(struct ena_com_tx_ctx));
ena_tx_ctx.ena_bufs = tx_info->bufs;
@@ -2082,14 +2165,22 @@ static netdev_tx_t ena_start_xmit(struct sk_buff *skb, struct net_device *dev)
rc = ena_com_prepare_tx(tx_ring->ena_com_io_sq, &ena_tx_ctx,
&nb_hw_desc);
+ /* ena_com_prepare_tx() can't fail due to overflow of tx queue,
+ * since the number of free descriptors in the queue is checked
+ * after sending the previous packet. In case there isn't enough
+ * space in the queue for the next packet, it is stopped
+ * until there is again enough available space in the queue.
+ * All other failure reasons of ena_com_prepare_tx() are fatal
+ * and therefore require a device reset.
+ */
if (unlikely(rc)) {
netif_err(adapter, tx_queued, dev,
"failed to prepare tx bufs\n");
u64_stats_update_begin(&tx_ring->syncp);
- tx_ring->tx_stats.queue_stop++;
tx_ring->tx_stats.prepare_ctx_err++;
u64_stats_update_end(&tx_ring->syncp);
- netif_tx_stop_queue(txq);
+ adapter->reset_reason = ENA_REGS_RESET_DRIVER_INVALID_STATE;
+ set_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags);
goto error_unmap_dma;
}
@@ -2111,8 +2202,8 @@ static netdev_tx_t ena_start_xmit(struct sk_buff *skb, struct net_device *dev)
* to sgl_size + 2. one for the meta descriptor and one for header
* (if the header is larger than tx_max_header_size).
*/
- if (unlikely(ena_com_sq_empty_space(tx_ring->ena_com_io_sq) <
- (tx_ring->sgl_size + 2))) {
+ if (unlikely(!ena_com_sq_have_enough_space(tx_ring->ena_com_io_sq,
+ tx_ring->sgl_size + 2))) {
netif_dbg(adapter, tx_queued, dev, "%s stop queue %d\n",
__func__, qid);
@@ -2131,8 +2222,8 @@ static netdev_tx_t ena_start_xmit(struct sk_buff *skb, struct net_device *dev)
*/
smp_mb();
- if (ena_com_sq_empty_space(tx_ring->ena_com_io_sq)
- > ENA_TX_WAKEUP_THRESH) {
+ if (ena_com_sq_have_enough_space(tx_ring->ena_com_io_sq,
+ ENA_TX_WAKEUP_THRESH)) {
netif_tx_wake_queue(txq);
u64_stats_update_begin(&tx_ring->syncp);
tx_ring->tx_stats.queue_wakeup++;
@@ -2152,58 +2243,15 @@ static netdev_tx_t ena_start_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK;
-error_report_dma_error:
- u64_stats_update_begin(&tx_ring->syncp);
- tx_ring->tx_stats.dma_mapping_err++;
- u64_stats_update_end(&tx_ring->syncp);
- netdev_warn(adapter->netdev, "failed to map skb\n");
-
- tx_info->skb = NULL;
-
error_unmap_dma:
- if (i >= 0) {
- /* save value of frag that failed */
- last_frag = i;
-
- /* start back at beginning and unmap skb */
- tx_info->skb = NULL;
- ena_buf = tx_info->bufs;
- dma_unmap_single(tx_ring->dev, dma_unmap_addr(ena_buf, paddr),
- dma_unmap_len(ena_buf, len), DMA_TO_DEVICE);
-
- /* unmap remaining mapped pages */
- for (i = 0; i < last_frag; i++) {
- ena_buf++;
- dma_unmap_page(tx_ring->dev, dma_unmap_addr(ena_buf, paddr),
- dma_unmap_len(ena_buf, len), DMA_TO_DEVICE);
- }
- }
+ ena_unmap_tx_skb(tx_ring, tx_info);
+ tx_info->skb = NULL;
error_drop_packet:
-
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void ena_netpoll(struct net_device *netdev)
-{
- struct ena_adapter *adapter = netdev_priv(netdev);
- int i;
-
- /* Dont schedule NAPI if the driver is in the middle of reset
- * or netdev is down.
- */
-
- if (!test_bit(ENA_FLAG_DEV_UP, &adapter->flags) ||
- test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags))
- return;
-
- for (i = 0; i < adapter->num_queues; i++)
- napi_schedule(&adapter->ena_napi[i].napi);
-}
-#endif /* CONFIG_NET_POLL_CONTROLLER */
-
static u16 ena_select_queue(struct net_device *dev, struct sk_buff *skb,
struct net_device *sb_dev,
select_queue_fallback_t fallback)
@@ -2221,7 +2269,8 @@ static u16 ena_select_queue(struct net_device *dev, struct sk_buff *skb,
return qid;
}
-static void ena_config_host_info(struct ena_com_dev *ena_dev)
+static void ena_config_host_info(struct ena_com_dev *ena_dev,
+ struct pci_dev *pdev)
{
struct ena_admin_host_info *host_info;
int rc;
@@ -2235,6 +2284,7 @@ static void ena_config_host_info(struct ena_com_dev *ena_dev)
host_info = ena_dev->host_attr.host_info;
+ host_info->bdf = (pdev->bus->number << 8) | pdev->devfn;
host_info->os_type = ENA_ADMIN_OS_LINUX;
host_info->kernel_ver = LINUX_VERSION_CODE;
strncpy(host_info->kernel_ver_str, utsname()->version,
@@ -2245,7 +2295,9 @@ static void ena_config_host_info(struct ena_com_dev *ena_dev)
host_info->driver_version =
(DRV_MODULE_VER_MAJOR) |
(DRV_MODULE_VER_MINOR << ENA_ADMIN_HOST_INFO_MINOR_SHIFT) |
- (DRV_MODULE_VER_SUBMINOR << ENA_ADMIN_HOST_INFO_SUB_MINOR_SHIFT);
+ (DRV_MODULE_VER_SUBMINOR << ENA_ADMIN_HOST_INFO_SUB_MINOR_SHIFT) |
+ ("K"[0] << ENA_ADMIN_HOST_INFO_MODULE_TYPE_SHIFT);
+ host_info->num_cpus = num_online_cpus();
rc = ena_com_set_host_attributes(ena_dev);
if (rc) {
@@ -2369,9 +2421,6 @@ static const struct net_device_ops ena_netdev_ops = {
.ndo_change_mtu = ena_change_mtu,
.ndo_set_mac_address = NULL,
.ndo_validate_addr = eth_validate_addr,
-#ifdef CONFIG_NET_POLL_CONTROLLER
- .ndo_poll_controller = ena_netpoll,
-#endif /* CONFIG_NET_POLL_CONTROLLER */
};
static int ena_device_validate_params(struct ena_adapter *adapter,
@@ -2459,7 +2508,7 @@ static int ena_device_init(struct ena_com_dev *ena_dev, struct pci_dev *pdev,
}
/* ENA admin level init */
- rc = ena_com_admin_init(ena_dev, &aenq_handlers, true);
+ rc = ena_com_admin_init(ena_dev, &aenq_handlers);
if (rc) {
dev_err(dev,
"Can not initialize ena admin queue with device\n");
@@ -2472,7 +2521,7 @@ static int ena_device_init(struct ena_com_dev *ena_dev, struct pci_dev *pdev,
*/
ena_com_set_admin_polling_mode(ena_dev, true);
- ena_config_host_info(ena_dev);
+ ena_config_host_info(ena_dev, pdev);
/* Get Device Attributes*/
rc = ena_com_get_dev_attr_feat(ena_dev, get_feat_ctx);
@@ -2557,15 +2606,14 @@ static void ena_destroy_device(struct ena_adapter *adapter, bool graceful)
dev_up = test_bit(ENA_FLAG_DEV_UP, &adapter->flags);
adapter->dev_up_before_reset = dev_up;
-
if (!graceful)
ena_com_set_admin_running_state(ena_dev, false);
if (test_bit(ENA_FLAG_DEV_UP, &adapter->flags))
ena_down(adapter);
- /* Before releasing the ENA resources, a device reset is required.
- * (to prevent the device from accessing them).
+ /* Stop the device from sending AENQ events (in case reset flag is set
+ * and device is up, ena_close already reset the device
* In case the reset flag is set and the device is up, ena_down()
* already perform the reset, so it can be skipped.
*/
@@ -2634,14 +2682,20 @@ static int ena_restore_device(struct ena_adapter *adapter)
set_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags);
mod_timer(&adapter->timer_service, round_jiffies(jiffies + HZ));
- dev_err(&pdev->dev, "Device reset completed successfully\n");
+ dev_err(&pdev->dev,
+ "Device reset completed successfully, Driver info: %s\n",
+ version);
return rc;
err_disable_msix:
ena_free_mgmnt_irq(adapter);
ena_disable_msix(adapter);
err_device_destroy:
+ ena_com_abort_admin_commands(ena_dev);
+ ena_com_wait_for_abort_completion(ena_dev);
ena_com_admin_destroy(ena_dev);
+ ena_com_mmio_reg_read_request_destroy(ena_dev);
+ ena_com_dev_reset(ena_dev, ENA_REGS_RESET_DRIVER_INVALID_STATE);
err:
clear_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags);
clear_bit(ENA_FLAG_ONGOING_RESET, &adapter->flags);
@@ -2823,7 +2877,7 @@ static void check_for_empty_rx_ring(struct ena_adapter *adapter)
rx_ring = &adapter->rx_ring[i];
refill_required =
- ena_com_sq_empty_space(rx_ring->ena_com_io_sq);
+ ena_com_free_desc(rx_ring->ena_com_io_sq);
if (unlikely(refill_required == (rx_ring->ring_size - 1))) {
rx_ring->empty_rx_queue++;
@@ -2968,20 +3022,10 @@ static int ena_calc_io_queue_num(struct pci_dev *pdev,
int io_sq_num, io_queue_num;
/* In case of LLQ use the llq number in the get feature cmd */
- if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) {
- io_sq_num = get_feat_ctx->max_queues.max_llq_num;
-
- if (io_sq_num == 0) {
- dev_err(&pdev->dev,
- "Trying to use LLQ but llq_num is 0. Fall back into regular queues\n");
-
- ena_dev->tx_mem_queue_type =
- ENA_ADMIN_PLACEMENT_POLICY_HOST;
- io_sq_num = get_feat_ctx->max_queues.max_sq_num;
- }
- } else {
+ if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV)
+ io_sq_num = get_feat_ctx->llq.max_llq_num;
+ else
io_sq_num = get_feat_ctx->max_queues.max_sq_num;
- }
io_queue_num = min_t(int, num_online_cpus(), ENA_MAX_NUM_IO_QUEUES);
io_queue_num = min_t(int, io_queue_num, io_sq_num);
@@ -2997,18 +3041,52 @@ static int ena_calc_io_queue_num(struct pci_dev *pdev,
return io_queue_num;
}
-static void ena_set_push_mode(struct pci_dev *pdev, struct ena_com_dev *ena_dev,
- struct ena_com_dev_get_features_ctx *get_feat_ctx)
+static int ena_set_queues_placement_policy(struct pci_dev *pdev,
+ struct ena_com_dev *ena_dev,
+ struct ena_admin_feature_llq_desc *llq,
+ struct ena_llq_configurations *llq_default_configurations)
{
bool has_mem_bar;
+ int rc;
+ u32 llq_feature_mask;
+
+ llq_feature_mask = 1 << ENA_ADMIN_LLQ;
+ if (!(ena_dev->supported_features & llq_feature_mask)) {
+ dev_err(&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;
+ }
has_mem_bar = pci_select_bars(pdev, IORESOURCE_MEM) & BIT(ENA_MEM_BAR);
- /* Enable push mode if device supports LLQ */
- if (has_mem_bar && (get_feat_ctx->max_queues.max_llq_num > 0))
- ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_DEV;
- else
+ rc = ena_com_config_dev_mode(ena_dev, llq, llq_default_configurations);
+ if (unlikely(rc)) {
+ dev_err(&pdev->dev,
+ "Failed to configure the device mode. Fallback to host mode policy.\n");
ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST;
+ return 0;
+ }
+
+ /* Nothing to config, exit */
+ if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST)
+ return 0;
+
+ if (!has_mem_bar) {
+ dev_err(&pdev->dev,
+ "ENA device does not expose LLQ bar. Fallback to host mode policy.\n");
+ ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST;
+ return 0;
+ }
+
+ ena_dev->mem_bar = devm_ioremap_wc(&pdev->dev,
+ pci_resource_start(pdev, ENA_MEM_BAR),
+ pci_resource_len(pdev, ENA_MEM_BAR));
+
+ if (!ena_dev->mem_bar)
+ return -EFAULT;
+
+ return 0;
}
static void ena_set_dev_offloads(struct ena_com_dev_get_features_ctx *feat,
@@ -3121,18 +3199,20 @@ err_rss_init:
static void ena_release_bars(struct ena_com_dev *ena_dev, struct pci_dev *pdev)
{
- int release_bars;
-
- if (ena_dev->mem_bar)
- devm_iounmap(&pdev->dev, ena_dev->mem_bar);
-
- if (ena_dev->reg_bar)
- devm_iounmap(&pdev->dev, ena_dev->reg_bar);
+ int release_bars = pci_select_bars(pdev, IORESOURCE_MEM) & ENA_BAR_MASK;
- release_bars = pci_select_bars(pdev, IORESOURCE_MEM) & ENA_BAR_MASK;
pci_release_selected_regions(pdev, release_bars);
}
+static inline void set_default_llq_configurations(struct ena_llq_configurations *llq_config)
+{
+ llq_config->llq_header_location = ENA_ADMIN_INLINE_HEADER;
+ llq_config->llq_ring_entry_size = ENA_ADMIN_LIST_ENTRY_SIZE_128B;
+ llq_config->llq_stride_ctrl = ENA_ADMIN_MULTIPLE_DESCS_PER_ENTRY;
+ llq_config->llq_num_decs_before_header = ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_2;
+ llq_config->llq_ring_entry_size_value = 128;
+}
+
static int ena_calc_queue_size(struct pci_dev *pdev,
struct ena_com_dev *ena_dev,
u16 *max_tx_sgl_size,
@@ -3148,7 +3228,7 @@ static int ena_calc_queue_size(struct pci_dev *pdev,
if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV)
queue_size = min_t(u32, queue_size,
- get_feat_ctx->max_queues.max_llq_depth);
+ get_feat_ctx->llq.max_llq_depth);
queue_size = rounddown_pow_of_two(queue_size);
@@ -3181,7 +3261,9 @@ static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
static int version_printed;
struct net_device *netdev;
struct ena_adapter *adapter;
+ struct ena_llq_configurations llq_config;
struct ena_com_dev *ena_dev = NULL;
+ char *queue_type_str;
static int adapters_found;
int io_queue_num, bars, rc;
int queue_size;
@@ -3235,16 +3317,13 @@ static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_free_region;
}
- ena_set_push_mode(pdev, ena_dev, &get_feat_ctx);
+ set_default_llq_configurations(&llq_config);
- if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) {
- ena_dev->mem_bar = devm_ioremap_wc(&pdev->dev,
- pci_resource_start(pdev, ENA_MEM_BAR),
- pci_resource_len(pdev, ENA_MEM_BAR));
- if (!ena_dev->mem_bar) {
- rc = -EFAULT;
- goto err_device_destroy;
- }
+ rc = ena_set_queues_placement_policy(pdev, ena_dev, &get_feat_ctx.llq,
+ &llq_config);
+ if (rc) {
+ dev_err(&pdev->dev, "ena device init failed\n");
+ goto err_device_destroy;
}
/* initial Tx interrupt delay, Assumes 1 usec granularity.
@@ -3259,8 +3338,10 @@ static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_device_destroy;
}
- dev_info(&pdev->dev, "creating %d io queues. queue size: %d\n",
- io_queue_num, queue_size);
+ dev_info(&pdev->dev, "creating %d io queues. queue size: %d. LLQ is %s\n",
+ io_queue_num, queue_size,
+ (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) ?
+ "ENABLED" : "DISABLED");
/* dev zeroed in init_etherdev */
netdev = alloc_etherdev_mq(sizeof(struct ena_adapter), io_queue_num);
@@ -3350,9 +3431,15 @@ static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
timer_setup(&adapter->timer_service, ena_timer_service, 0);
mod_timer(&adapter->timer_service, round_jiffies(jiffies + HZ));
- dev_info(&pdev->dev, "%s found at mem %lx, mac addr %pM Queues %d\n",
+ if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_HOST)
+ queue_type_str = "Regular";
+ else
+ queue_type_str = "Low Latency";
+
+ dev_info(&pdev->dev,
+ "%s found at mem %lx, mac addr %pM Queues %d, Placement policy: %s\n",
DEVICE_NAME, (long)pci_resource_start(pdev, 0),
- netdev->dev_addr, io_queue_num);
+ netdev->dev_addr, io_queue_num, queue_type_str);
set_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags);
diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.h b/drivers/net/ethernet/amazon/ena/ena_netdev.h
index 7c7ae56c52cf..521873642339 100644
--- a/drivers/net/ethernet/amazon/ena/ena_netdev.h
+++ b/drivers/net/ethernet/amazon/ena/ena_netdev.h
@@ -43,9 +43,9 @@
#include "ena_com.h"
#include "ena_eth_com.h"
-#define DRV_MODULE_VER_MAJOR 1
-#define DRV_MODULE_VER_MINOR 5
-#define DRV_MODULE_VER_SUBMINOR 0
+#define DRV_MODULE_VER_MAJOR 2
+#define DRV_MODULE_VER_MINOR 0
+#define DRV_MODULE_VER_SUBMINOR 1
#define DRV_MODULE_NAME "ena"
#ifndef DRV_MODULE_VERSION
@@ -61,6 +61,17 @@
#define ENA_ADMIN_MSIX_VEC 1
#define ENA_MAX_MSIX_VEC(io_queues) (ENA_ADMIN_MSIX_VEC + (io_queues))
+/* The ENA buffer length fields is 16 bit long. So when PAGE_SIZE == 64kB the
+ * driver passes 0.
+ * Since the max packet size the ENA handles is ~9kB limit the buffer length to
+ * 16kB.
+ */
+#if PAGE_SIZE > SZ_16K
+#define ENA_PAGE_SIZE SZ_16K
+#else
+#define ENA_PAGE_SIZE PAGE_SIZE
+#endif
+
#define ENA_MIN_MSIX_VEC 2
#define ENA_REG_BAR 0
@@ -70,7 +81,7 @@
#define ENA_DEFAULT_RING_SIZE (1024)
#define ENA_TX_WAKEUP_THRESH (MAX_SKB_FRAGS + 2)
-#define ENA_DEFAULT_RX_COPYBREAK (128 - NET_IP_ALIGN)
+#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
@@ -95,10 +106,11 @@
*/
#define ENA_TX_POLL_BUDGET_DIVIDER 4
-/* Refill Rx queue when number of available descriptors is below
- * QUEUE_SIZE / ENA_RX_REFILL_THRESH_DIVIDER
+/* Refill Rx queue when number of required descriptors is above
+ * QUEUE_SIZE / ENA_RX_REFILL_THRESH_DIVIDER or ENA_RX_REFILL_THRESH_PACKET
*/
#define ENA_RX_REFILL_THRESH_DIVIDER 8
+#define ENA_RX_REFILL_THRESH_PACKET 256
/* Number of queues to check for missing queues per timer service */
#define ENA_MONITORED_TX_QUEUES 4
@@ -151,6 +163,9 @@ struct ena_tx_buffer {
/* num of buffers used by this skb */
u32 num_of_bufs;
+ /* Indicate if bufs[0] map the linear data of the skb. */
+ u8 map_linear_data;
+
/* Used for detect missing tx packets to limit the number of prints */
u32 print_once;
/* Save the last jiffies to detect missing tx packets
@@ -186,6 +201,7 @@ struct ena_stats_tx {
u64 tx_poll;
u64 doorbells;
u64 bad_req_id;
+ u64 llq_buffer_copy;
u64 missed_tx;
};
@@ -201,6 +217,7 @@ struct ena_stats_rx {
u64 rx_copybreak_pkt;
u64 bad_req_id;
u64 empty_rx_ring;
+ u64 csum_unchecked;
};
struct ena_ring {
@@ -257,6 +274,8 @@ struct ena_ring {
struct ena_stats_tx tx_stats;
struct ena_stats_rx rx_stats;
};
+
+ u8 *push_buf_intermediate_buf;
int empty_rx_queue;
} ____cacheline_aligned;
@@ -355,15 +374,4 @@ void ena_dump_stats_to_buf(struct ena_adapter *adapter, u8 *buf);
int ena_get_sset_count(struct net_device *netdev, int sset);
-/* The ENA buffer length fields is 16 bit long. So when PAGE_SIZE == 64kB the
- * driver passas 0.
- * Since the max packet size the ENA handles is ~9kB limit the buffer length to
- * 16kB.
- */
-#if PAGE_SIZE > SZ_16K
-#define ENA_PAGE_SIZE SZ_16K
-#else
-#define ENA_PAGE_SIZE PAGE_SIZE
-#endif
-
#endif /* !(ENA_H) */
diff --git a/drivers/net/ethernet/amazon/ena/ena_regs_defs.h b/drivers/net/ethernet/amazon/ena/ena_regs_defs.h
index 48ca97fbe7bc..04fcafcc059c 100644
--- a/drivers/net/ethernet/amazon/ena/ena_regs_defs.h
+++ b/drivers/net/ethernet/amazon/ena/ena_regs_defs.h
@@ -33,137 +33,125 @@
#define _ENA_REGS_H_
enum ena_regs_reset_reason_types {
- ENA_REGS_RESET_NORMAL = 0,
-
- ENA_REGS_RESET_KEEP_ALIVE_TO = 1,
-
- ENA_REGS_RESET_ADMIN_TO = 2,
-
- ENA_REGS_RESET_MISS_TX_CMPL = 3,
-
- ENA_REGS_RESET_INV_RX_REQ_ID = 4,
-
- ENA_REGS_RESET_INV_TX_REQ_ID = 5,
-
- ENA_REGS_RESET_TOO_MANY_RX_DESCS = 6,
-
- ENA_REGS_RESET_INIT_ERR = 7,
-
- ENA_REGS_RESET_DRIVER_INVALID_STATE = 8,
-
- ENA_REGS_RESET_OS_TRIGGER = 9,
-
- ENA_REGS_RESET_OS_NETDEV_WD = 10,
-
- ENA_REGS_RESET_SHUTDOWN = 11,
-
- ENA_REGS_RESET_USER_TRIGGER = 12,
-
- ENA_REGS_RESET_GENERIC = 13,
-
- ENA_REGS_RESET_MISS_INTERRUPT = 14,
+ ENA_REGS_RESET_NORMAL = 0,
+ ENA_REGS_RESET_KEEP_ALIVE_TO = 1,
+ ENA_REGS_RESET_ADMIN_TO = 2,
+ ENA_REGS_RESET_MISS_TX_CMPL = 3,
+ ENA_REGS_RESET_INV_RX_REQ_ID = 4,
+ ENA_REGS_RESET_INV_TX_REQ_ID = 5,
+ ENA_REGS_RESET_TOO_MANY_RX_DESCS = 6,
+ ENA_REGS_RESET_INIT_ERR = 7,
+ ENA_REGS_RESET_DRIVER_INVALID_STATE = 8,
+ ENA_REGS_RESET_OS_TRIGGER = 9,
+ ENA_REGS_RESET_OS_NETDEV_WD = 10,
+ ENA_REGS_RESET_SHUTDOWN = 11,
+ ENA_REGS_RESET_USER_TRIGGER = 12,
+ ENA_REGS_RESET_GENERIC = 13,
+ ENA_REGS_RESET_MISS_INTERRUPT = 14,
};
/* ena_registers offsets */
-#define ENA_REGS_VERSION_OFF 0x0
-#define ENA_REGS_CONTROLLER_VERSION_OFF 0x4
-#define ENA_REGS_CAPS_OFF 0x8
-#define ENA_REGS_CAPS_EXT_OFF 0xc
-#define ENA_REGS_AQ_BASE_LO_OFF 0x10
-#define ENA_REGS_AQ_BASE_HI_OFF 0x14
-#define ENA_REGS_AQ_CAPS_OFF 0x18
-#define ENA_REGS_ACQ_BASE_LO_OFF 0x20
-#define ENA_REGS_ACQ_BASE_HI_OFF 0x24
-#define ENA_REGS_ACQ_CAPS_OFF 0x28
-#define ENA_REGS_AQ_DB_OFF 0x2c
-#define ENA_REGS_ACQ_TAIL_OFF 0x30
-#define ENA_REGS_AENQ_CAPS_OFF 0x34
-#define ENA_REGS_AENQ_BASE_LO_OFF 0x38
-#define ENA_REGS_AENQ_BASE_HI_OFF 0x3c
-#define ENA_REGS_AENQ_HEAD_DB_OFF 0x40
-#define ENA_REGS_AENQ_TAIL_OFF 0x44
-#define ENA_REGS_INTR_MASK_OFF 0x4c
-#define ENA_REGS_DEV_CTL_OFF 0x54
-#define ENA_REGS_DEV_STS_OFF 0x58
-#define ENA_REGS_MMIO_REG_READ_OFF 0x5c
-#define ENA_REGS_MMIO_RESP_LO_OFF 0x60
-#define ENA_REGS_MMIO_RESP_HI_OFF 0x64
-#define ENA_REGS_RSS_IND_ENTRY_UPDATE_OFF 0x68
+
+/* 0 base */
+#define ENA_REGS_VERSION_OFF 0x0
+#define ENA_REGS_CONTROLLER_VERSION_OFF 0x4
+#define ENA_REGS_CAPS_OFF 0x8
+#define ENA_REGS_CAPS_EXT_OFF 0xc
+#define ENA_REGS_AQ_BASE_LO_OFF 0x10
+#define ENA_REGS_AQ_BASE_HI_OFF 0x14
+#define ENA_REGS_AQ_CAPS_OFF 0x18
+#define ENA_REGS_ACQ_BASE_LO_OFF 0x20
+#define ENA_REGS_ACQ_BASE_HI_OFF 0x24
+#define ENA_REGS_ACQ_CAPS_OFF 0x28
+#define ENA_REGS_AQ_DB_OFF 0x2c
+#define ENA_REGS_ACQ_TAIL_OFF 0x30
+#define ENA_REGS_AENQ_CAPS_OFF 0x34
+#define ENA_REGS_AENQ_BASE_LO_OFF 0x38
+#define ENA_REGS_AENQ_BASE_HI_OFF 0x3c
+#define ENA_REGS_AENQ_HEAD_DB_OFF 0x40
+#define ENA_REGS_AENQ_TAIL_OFF 0x44
+#define ENA_REGS_INTR_MASK_OFF 0x4c
+#define ENA_REGS_DEV_CTL_OFF 0x54
+#define ENA_REGS_DEV_STS_OFF 0x58
+#define ENA_REGS_MMIO_REG_READ_OFF 0x5c
+#define ENA_REGS_MMIO_RESP_LO_OFF 0x60
+#define ENA_REGS_MMIO_RESP_HI_OFF 0x64
+#define ENA_REGS_RSS_IND_ENTRY_UPDATE_OFF 0x68
/* version register */
-#define ENA_REGS_VERSION_MINOR_VERSION_MASK 0xff
-#define ENA_REGS_VERSION_MAJOR_VERSION_SHIFT 8
-#define ENA_REGS_VERSION_MAJOR_VERSION_MASK 0xff00
+#define ENA_REGS_VERSION_MINOR_VERSION_MASK 0xff
+#define ENA_REGS_VERSION_MAJOR_VERSION_SHIFT 8
+#define ENA_REGS_VERSION_MAJOR_VERSION_MASK 0xff00
/* controller_version register */
-#define ENA_REGS_CONTROLLER_VERSION_SUBMINOR_VERSION_MASK 0xff
-#define ENA_REGS_CONTROLLER_VERSION_MINOR_VERSION_SHIFT 8
-#define ENA_REGS_CONTROLLER_VERSION_MINOR_VERSION_MASK 0xff00
-#define ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_SHIFT 16
-#define ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_MASK 0xff0000
-#define ENA_REGS_CONTROLLER_VERSION_IMPL_ID_SHIFT 24
-#define ENA_REGS_CONTROLLER_VERSION_IMPL_ID_MASK 0xff000000
+#define ENA_REGS_CONTROLLER_VERSION_SUBMINOR_VERSION_MASK 0xff
+#define ENA_REGS_CONTROLLER_VERSION_MINOR_VERSION_SHIFT 8
+#define ENA_REGS_CONTROLLER_VERSION_MINOR_VERSION_MASK 0xff00
+#define ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_SHIFT 16
+#define ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_MASK 0xff0000
+#define ENA_REGS_CONTROLLER_VERSION_IMPL_ID_SHIFT 24
+#define ENA_REGS_CONTROLLER_VERSION_IMPL_ID_MASK 0xff000000
/* caps register */
-#define ENA_REGS_CAPS_CONTIGUOUS_QUEUE_REQUIRED_MASK 0x1
-#define ENA_REGS_CAPS_RESET_TIMEOUT_SHIFT 1
-#define ENA_REGS_CAPS_RESET_TIMEOUT_MASK 0x3e
-#define ENA_REGS_CAPS_DMA_ADDR_WIDTH_SHIFT 8
-#define ENA_REGS_CAPS_DMA_ADDR_WIDTH_MASK 0xff00
-#define ENA_REGS_CAPS_ADMIN_CMD_TO_SHIFT 16
-#define ENA_REGS_CAPS_ADMIN_CMD_TO_MASK 0xf0000
+#define ENA_REGS_CAPS_CONTIGUOUS_QUEUE_REQUIRED_MASK 0x1
+#define ENA_REGS_CAPS_RESET_TIMEOUT_SHIFT 1
+#define ENA_REGS_CAPS_RESET_TIMEOUT_MASK 0x3e
+#define ENA_REGS_CAPS_DMA_ADDR_WIDTH_SHIFT 8
+#define ENA_REGS_CAPS_DMA_ADDR_WIDTH_MASK 0xff00
+#define ENA_REGS_CAPS_ADMIN_CMD_TO_SHIFT 16
+#define ENA_REGS_CAPS_ADMIN_CMD_TO_MASK 0xf0000
/* aq_caps register */
-#define ENA_REGS_AQ_CAPS_AQ_DEPTH_MASK 0xffff
-#define ENA_REGS_AQ_CAPS_AQ_ENTRY_SIZE_SHIFT 16
-#define ENA_REGS_AQ_CAPS_AQ_ENTRY_SIZE_MASK 0xffff0000
+#define ENA_REGS_AQ_CAPS_AQ_DEPTH_MASK 0xffff
+#define ENA_REGS_AQ_CAPS_AQ_ENTRY_SIZE_SHIFT 16
+#define ENA_REGS_AQ_CAPS_AQ_ENTRY_SIZE_MASK 0xffff0000
/* acq_caps register */
-#define ENA_REGS_ACQ_CAPS_ACQ_DEPTH_MASK 0xffff
-#define ENA_REGS_ACQ_CAPS_ACQ_ENTRY_SIZE_SHIFT 16
-#define ENA_REGS_ACQ_CAPS_ACQ_ENTRY_SIZE_MASK 0xffff0000
+#define ENA_REGS_ACQ_CAPS_ACQ_DEPTH_MASK 0xffff
+#define ENA_REGS_ACQ_CAPS_ACQ_ENTRY_SIZE_SHIFT 16
+#define ENA_REGS_ACQ_CAPS_ACQ_ENTRY_SIZE_MASK 0xffff0000
/* aenq_caps register */
-#define ENA_REGS_AENQ_CAPS_AENQ_DEPTH_MASK 0xffff
-#define ENA_REGS_AENQ_CAPS_AENQ_ENTRY_SIZE_SHIFT 16
-#define ENA_REGS_AENQ_CAPS_AENQ_ENTRY_SIZE_MASK 0xffff0000
+#define ENA_REGS_AENQ_CAPS_AENQ_DEPTH_MASK 0xffff
+#define ENA_REGS_AENQ_CAPS_AENQ_ENTRY_SIZE_SHIFT 16
+#define ENA_REGS_AENQ_CAPS_AENQ_ENTRY_SIZE_MASK 0xffff0000
/* dev_ctl register */
-#define ENA_REGS_DEV_CTL_DEV_RESET_MASK 0x1
-#define ENA_REGS_DEV_CTL_AQ_RESTART_SHIFT 1
-#define ENA_REGS_DEV_CTL_AQ_RESTART_MASK 0x2
-#define ENA_REGS_DEV_CTL_QUIESCENT_SHIFT 2
-#define ENA_REGS_DEV_CTL_QUIESCENT_MASK 0x4
-#define ENA_REGS_DEV_CTL_IO_RESUME_SHIFT 3
-#define ENA_REGS_DEV_CTL_IO_RESUME_MASK 0x8
-#define ENA_REGS_DEV_CTL_RESET_REASON_SHIFT 28
-#define ENA_REGS_DEV_CTL_RESET_REASON_MASK 0xf0000000
+#define ENA_REGS_DEV_CTL_DEV_RESET_MASK 0x1
+#define ENA_REGS_DEV_CTL_AQ_RESTART_SHIFT 1
+#define ENA_REGS_DEV_CTL_AQ_RESTART_MASK 0x2
+#define ENA_REGS_DEV_CTL_QUIESCENT_SHIFT 2
+#define ENA_REGS_DEV_CTL_QUIESCENT_MASK 0x4
+#define ENA_REGS_DEV_CTL_IO_RESUME_SHIFT 3
+#define ENA_REGS_DEV_CTL_IO_RESUME_MASK 0x8
+#define ENA_REGS_DEV_CTL_RESET_REASON_SHIFT 28
+#define ENA_REGS_DEV_CTL_RESET_REASON_MASK 0xf0000000
/* dev_sts register */
-#define ENA_REGS_DEV_STS_READY_MASK 0x1
-#define ENA_REGS_DEV_STS_AQ_RESTART_IN_PROGRESS_SHIFT 1
-#define ENA_REGS_DEV_STS_AQ_RESTART_IN_PROGRESS_MASK 0x2
-#define ENA_REGS_DEV_STS_AQ_RESTART_FINISHED_SHIFT 2
-#define ENA_REGS_DEV_STS_AQ_RESTART_FINISHED_MASK 0x4
-#define ENA_REGS_DEV_STS_RESET_IN_PROGRESS_SHIFT 3
-#define ENA_REGS_DEV_STS_RESET_IN_PROGRESS_MASK 0x8
-#define ENA_REGS_DEV_STS_RESET_FINISHED_SHIFT 4
-#define ENA_REGS_DEV_STS_RESET_FINISHED_MASK 0x10
-#define ENA_REGS_DEV_STS_FATAL_ERROR_SHIFT 5
-#define ENA_REGS_DEV_STS_FATAL_ERROR_MASK 0x20
-#define ENA_REGS_DEV_STS_QUIESCENT_STATE_IN_PROGRESS_SHIFT 6
-#define ENA_REGS_DEV_STS_QUIESCENT_STATE_IN_PROGRESS_MASK 0x40
-#define ENA_REGS_DEV_STS_QUIESCENT_STATE_ACHIEVED_SHIFT 7
-#define ENA_REGS_DEV_STS_QUIESCENT_STATE_ACHIEVED_MASK 0x80
+#define ENA_REGS_DEV_STS_READY_MASK 0x1
+#define ENA_REGS_DEV_STS_AQ_RESTART_IN_PROGRESS_SHIFT 1
+#define ENA_REGS_DEV_STS_AQ_RESTART_IN_PROGRESS_MASK 0x2
+#define ENA_REGS_DEV_STS_AQ_RESTART_FINISHED_SHIFT 2
+#define ENA_REGS_DEV_STS_AQ_RESTART_FINISHED_MASK 0x4
+#define ENA_REGS_DEV_STS_RESET_IN_PROGRESS_SHIFT 3
+#define ENA_REGS_DEV_STS_RESET_IN_PROGRESS_MASK 0x8
+#define ENA_REGS_DEV_STS_RESET_FINISHED_SHIFT 4
+#define ENA_REGS_DEV_STS_RESET_FINISHED_MASK 0x10
+#define ENA_REGS_DEV_STS_FATAL_ERROR_SHIFT 5
+#define ENA_REGS_DEV_STS_FATAL_ERROR_MASK 0x20
+#define ENA_REGS_DEV_STS_QUIESCENT_STATE_IN_PROGRESS_SHIFT 6
+#define ENA_REGS_DEV_STS_QUIESCENT_STATE_IN_PROGRESS_MASK 0x40
+#define ENA_REGS_DEV_STS_QUIESCENT_STATE_ACHIEVED_SHIFT 7
+#define ENA_REGS_DEV_STS_QUIESCENT_STATE_ACHIEVED_MASK 0x80
/* mmio_reg_read register */
-#define ENA_REGS_MMIO_REG_READ_REQ_ID_MASK 0xffff
-#define ENA_REGS_MMIO_REG_READ_REG_OFF_SHIFT 16
-#define ENA_REGS_MMIO_REG_READ_REG_OFF_MASK 0xffff0000
+#define ENA_REGS_MMIO_REG_READ_REQ_ID_MASK 0xffff
+#define ENA_REGS_MMIO_REG_READ_REG_OFF_SHIFT 16
+#define ENA_REGS_MMIO_REG_READ_REG_OFF_MASK 0xffff0000
/* rss_ind_entry_update register */
-#define ENA_REGS_RSS_IND_ENTRY_UPDATE_INDEX_MASK 0xffff
-#define ENA_REGS_RSS_IND_ENTRY_UPDATE_CQ_IDX_SHIFT 16
-#define ENA_REGS_RSS_IND_ENTRY_UPDATE_CQ_IDX_MASK 0xffff0000
+#define ENA_REGS_RSS_IND_ENTRY_UPDATE_INDEX_MASK 0xffff
+#define ENA_REGS_RSS_IND_ENTRY_UPDATE_CQ_IDX_SHIFT 16
+#define ENA_REGS_RSS_IND_ENTRY_UPDATE_CQ_IDX_MASK 0xffff0000
#endif /*_ENA_REGS_H_ */
diff --git a/drivers/net/ethernet/amd/am79c961a.c b/drivers/net/ethernet/amd/am79c961a.c
index 01d132c02ff9..265039c57023 100644
--- a/drivers/net/ethernet/amd/am79c961a.c
+++ b/drivers/net/ethernet/amd/am79c961a.c
@@ -440,7 +440,7 @@ static void am79c961_timeout(struct net_device *dev)
/*
* Transmit a packet
*/
-static int
+static netdev_tx_t
am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev)
{
struct dev_priv *priv = netdev_priv(dev);
diff --git a/drivers/net/ethernet/amd/atarilance.c b/drivers/net/ethernet/amd/atarilance.c
index c5b81268c284..d3d44e07afbc 100644
--- a/drivers/net/ethernet/amd/atarilance.c
+++ b/drivers/net/ethernet/amd/atarilance.c
@@ -339,7 +339,8 @@ static unsigned long lance_probe1( struct net_device *dev, struct lance_addr
*init_rec );
static int lance_open( struct net_device *dev );
static void lance_init_ring( struct net_device *dev );
-static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev );
+static netdev_tx_t lance_start_xmit(struct sk_buff *skb,
+ struct net_device *dev);
static irqreturn_t lance_interrupt( int irq, void *dev_id );
static int lance_rx( struct net_device *dev );
static int lance_close( struct net_device *dev );
@@ -769,7 +770,8 @@ static void lance_tx_timeout (struct net_device *dev)
/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
-static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
+static netdev_tx_t
+lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct lance_private *lp = netdev_priv(dev);
struct lance_ioreg *IO = lp->iobase;
diff --git a/drivers/net/ethernet/amd/au1000_eth.c b/drivers/net/ethernet/amd/au1000_eth.c
index 73ca8879ada7..7c1eb304c27e 100644
--- a/drivers/net/ethernet/amd/au1000_eth.c
+++ b/drivers/net/ethernet/amd/au1000_eth.c
@@ -564,17 +564,7 @@ static int au1000_mii_probe(struct net_device *dev)
return PTR_ERR(phydev);
}
- /* mask with MAC supported features */
- phydev->supported &= (SUPPORTED_10baseT_Half
- | SUPPORTED_10baseT_Full
- | SUPPORTED_100baseT_Half
- | SUPPORTED_100baseT_Full
- | SUPPORTED_Autoneg
- /* | SUPPORTED_Pause | SUPPORTED_Asym_Pause */
- | SUPPORTED_MII
- | SUPPORTED_TP);
-
- phydev->advertising = phydev->supported;
+ phy_set_max_speed(phydev, SPEED_100);
aup->old_link = 0;
aup->old_speed = 0;
diff --git a/drivers/net/ethernet/amd/declance.c b/drivers/net/ethernet/amd/declance.c
index 116997a8b593..9f23703dd509 100644
--- a/drivers/net/ethernet/amd/declance.c
+++ b/drivers/net/ethernet/amd/declance.c
@@ -894,7 +894,7 @@ static void lance_tx_timeout(struct net_device *dev)
netif_wake_queue(dev);
}
-static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct lance_private *lp = netdev_priv(dev);
volatile struct lance_regs *ll = lp->ll;
@@ -1031,6 +1031,7 @@ static int dec_lance_probe(struct device *bdev, const int type)
int i, ret;
unsigned long esar_base;
unsigned char *esar;
+ const char *desc;
if (dec_lance_debug && version_printed++ == 0)
printk(version);
@@ -1216,19 +1217,20 @@ static int dec_lance_probe(struct device *bdev, const int type)
*/
switch (type) {
case ASIC_LANCE:
- printk("%s: IOASIC onboard LANCE", name);
+ desc = "IOASIC onboard LANCE";
break;
case PMAD_LANCE:
- printk("%s: PMAD-AA", name);
+ desc = "PMAD-AA";
break;
case PMAX_LANCE:
- printk("%s: PMAX onboard LANCE", name);
+ desc = "PMAX onboard LANCE";
break;
}
for (i = 0; i < 6; i++)
dev->dev_addr[i] = esar[i * 4];
- printk(", addr = %pM, irq = %d\n", dev->dev_addr, dev->irq);
+ printk("%s: %s, addr = %pM, irq = %d\n",
+ name, desc, dev->dev_addr, dev->irq);
dev->netdev_ops = &lance_netdev_ops;
dev->watchdog_timeo = 5*HZ;
diff --git a/drivers/net/ethernet/amd/ni65.c b/drivers/net/ethernet/amd/ni65.c
index e248d1ab3e47..8931ce6bab7b 100644
--- a/drivers/net/ethernet/amd/ni65.c
+++ b/drivers/net/ethernet/amd/ni65.c
@@ -435,10 +435,8 @@ static int __init ni65_probe1(struct net_device *dev,int ioaddr)
}
if(cards[i].vendor_id) {
for(j=0;j<3;j++)
- if(inb(ioaddr+cards[i].addr_offset+j) != cards[i].vendor_id[j]) {
+ if(inb(ioaddr+cards[i].addr_offset+j) != cards[i].vendor_id[j])
release_region(ioaddr, cards[i].total_size);
- continue;
- }
}
break;
}
diff --git a/drivers/net/ethernet/amd/sun3lance.c b/drivers/net/ethernet/amd/sun3lance.c
index 77b1db267730..da7e3d4f4166 100644
--- a/drivers/net/ethernet/amd/sun3lance.c
+++ b/drivers/net/ethernet/amd/sun3lance.c
@@ -236,7 +236,8 @@ struct lance_private {
static int lance_probe( struct net_device *dev);
static int lance_open( struct net_device *dev );
static void lance_init_ring( struct net_device *dev );
-static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev );
+static netdev_tx_t lance_start_xmit(struct sk_buff *skb,
+ struct net_device *dev);
static irqreturn_t lance_interrupt( int irq, void *dev_id);
static int lance_rx( struct net_device *dev );
static int lance_close( struct net_device *dev );
@@ -511,7 +512,8 @@ static void lance_init_ring( struct net_device *dev )
}
-static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
+static netdev_tx_t
+lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct lance_private *lp = netdev_priv(dev);
int entry, len;
diff --git a/drivers/net/ethernet/amd/sunlance.c b/drivers/net/ethernet/amd/sunlance.c
index cdd7a611479b..b4fc0ed5bce8 100644
--- a/drivers/net/ethernet/amd/sunlance.c
+++ b/drivers/net/ethernet/amd/sunlance.c
@@ -1106,7 +1106,7 @@ static void lance_tx_timeout(struct net_device *dev)
netif_wake_queue(dev);
}
-static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct lance_private *lp = netdev_priv(dev);
int entry, skblen, len;
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
index 24f1053b8785..0cc911f928b1 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
@@ -119,7 +119,6 @@
#include <linux/tcp.h>
#include <linux/if_vlan.h>
#include <linux/interrupt.h>
-#include <net/busy_poll.h>
#include <linux/clk.h>
#include <linux/if_ether.h>
#include <linux/net_tstamp.h>
@@ -2009,7 +2008,7 @@ static int xgbe_close(struct net_device *netdev)
return 0;
}
-static int xgbe_xmit(struct sk_buff *skb, struct net_device *netdev)
+static netdev_tx_t xgbe_xmit(struct sk_buff *skb, struct net_device *netdev)
{
struct xgbe_prv_data *pdata = netdev_priv(netdev);
struct xgbe_hw_if *hw_if = &pdata->hw_if;
@@ -2018,7 +2017,7 @@ static int xgbe_xmit(struct sk_buff *skb, struct net_device *netdev)
struct xgbe_ring *ring;
struct xgbe_packet_data *packet;
struct netdev_queue *txq;
- int ret;
+ netdev_tx_t ret;
DBGPR("-->xgbe_xmit: skb->len = %d\n", skb->len);
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c
index 3ceb4f95ca7c..151bdb629e8a 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c
@@ -878,9 +878,10 @@ static bool xgbe_phy_finisar_phy_quirks(struct xgbe_prv_data *pdata)
phy_write(phy_data->phydev, 0x04, 0x0d01);
phy_write(phy_data->phydev, 0x00, 0x9140);
- phy_data->phydev->supported = PHY_GBIT_FEATURES;
- phy_data->phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
- phy_data->phydev->advertising = phy_data->phydev->supported;
+ phy_data->phydev->supported = PHY_10BT_FEATURES |
+ PHY_100BT_FEATURES |
+ PHY_1000BT_FEATURES;
+ phy_support_asym_pause(phy_data->phydev);
netif_dbg(pdata, drv, pdata->netdev,
"Finisar PHY quirk in place\n");
@@ -950,9 +951,10 @@ static bool xgbe_phy_belfuse_phy_quirks(struct xgbe_prv_data *pdata)
reg = phy_read(phy_data->phydev, 0x00);
phy_write(phy_data->phydev, 0x00, reg & ~0x00800);
- phy_data->phydev->supported = PHY_GBIT_FEATURES;
- phy_data->phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
- phy_data->phydev->advertising = phy_data->phydev->supported;
+ phy_data->phydev->supported = (PHY_10BT_FEATURES |
+ PHY_100BT_FEATURES |
+ PHY_1000BT_FEATURES);
+ phy_support_asym_pause(phy_data->phydev);
netif_dbg(pdata, drv, pdata->netdev,
"BelFuse PHY quirk in place\n");
@@ -1495,10 +1497,7 @@ static void xgbe_phy_phydev_flowctrl(struct xgbe_prv_data *pdata)
if (!phy_data->phydev)
return;
- if (phy_data->phydev->advertising & ADVERTISED_Pause)
- lcl_adv |= ADVERTISE_PAUSE_CAP;
- if (phy_data->phydev->advertising & ADVERTISED_Asym_Pause)
- lcl_adv |= ADVERTISE_PAUSE_ASYM;
+ lcl_adv = ethtool_adv_to_lcl_adv_t(phy_data->phydev->advertising);
if (phy_data->phydev->pause) {
XGBE_SET_LP_ADV(lks, Pause);
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c
index 4f50f11718f4..78dd09b5beeb 100644
--- a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c
+++ b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c
@@ -306,45 +306,25 @@ static int xgene_set_pauseparam(struct net_device *ndev,
{
struct xgene_enet_pdata *pdata = netdev_priv(ndev);
struct phy_device *phydev = ndev->phydev;
- u32 oldadv, newadv;
if (phy_interface_mode_is_rgmii(pdata->phy_mode) ||
pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) {
if (!phydev)
return -EINVAL;
- if (!(phydev->supported & SUPPORTED_Pause) ||
- (!(phydev->supported & SUPPORTED_Asym_Pause) &&
- pp->rx_pause != pp->tx_pause))
+ if (!phy_validate_pause(phydev, pp))
return -EINVAL;
pdata->pause_autoneg = pp->autoneg;
pdata->tx_pause = pp->tx_pause;
pdata->rx_pause = pp->rx_pause;
- oldadv = phydev->advertising;
- newadv = oldadv & ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause);
+ phy_set_asym_pause(phydev, pp->rx_pause, pp->tx_pause);
- if (pp->rx_pause)
- newadv |= ADVERTISED_Pause | ADVERTISED_Asym_Pause;
-
- if (pp->tx_pause)
- newadv ^= ADVERTISED_Asym_Pause;
-
- if (oldadv ^ newadv) {
- phydev->advertising = newadv;
-
- if (phydev->autoneg)
- return phy_start_aneg(phydev);
-
- if (!pp->autoneg) {
- pdata->mac_ops->flowctl_tx(pdata,
- pdata->tx_pause);
- pdata->mac_ops->flowctl_rx(pdata,
- pdata->rx_pause);
- }
+ if (!pp->autoneg) {
+ pdata->mac_ops->flowctl_tx(pdata, pdata->tx_pause);
+ pdata->mac_ops->flowctl_rx(pdata, pdata->rx_pause);
}
-
} else {
if (pp->autoneg)
return -EINVAL;
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
index 078a04dc1182..e3560311711a 100644
--- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
+++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
@@ -895,12 +895,10 @@ int xgene_enet_phy_connect(struct net_device *ndev)
}
pdata->phy_speed = SPEED_UNKNOWN;
- phy_dev->supported &= ~SUPPORTED_10baseT_Half &
- ~SUPPORTED_100baseT_Half &
- ~SUPPORTED_1000baseT_Half;
- phy_dev->supported |= SUPPORTED_Pause |
- SUPPORTED_Asym_Pause;
- phy_dev->advertising = phy_dev->supported;
+ phy_remove_link_mode(phy_dev, ETHTOOL_LINK_MODE_10baseT_Half_BIT);
+ phy_remove_link_mode(phy_dev, ETHTOOL_LINK_MODE_100baseT_Half_BIT);
+ phy_remove_link_mode(phy_dev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
+ phy_support_asym_pause(phy_dev);
return 0;
}
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_common.h b/drivers/net/ethernet/aquantia/atlantic/aq_common.h
index d52b088ff8f0..becb578211ed 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_common.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_common.h
@@ -57,4 +57,9 @@
#define AQ_NIC_RATE_1G BIT(4)
#define AQ_NIC_RATE_100M BIT(5)
+#define AQ_NIC_RATE_EEE_10G BIT(6)
+#define AQ_NIC_RATE_EEE_5G BIT(7)
+#define AQ_NIC_RATE_EEE_2GS BIT(8)
+#define AQ_NIC_RATE_EEE_1G BIT(9)
+
#endif /* AQ_COMMON_H */
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
index 08c9fa6ca71f..99ef1daaa4d8 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
@@ -98,8 +98,8 @@ static void aq_ethtool_stats(struct net_device *ndev,
struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
memset(data, 0, (ARRAY_SIZE(aq_ethtool_stat_names) +
- ARRAY_SIZE(aq_ethtool_queue_stat_names) *
- cfg->vecs) * sizeof(u64));
+ ARRAY_SIZE(aq_ethtool_queue_stat_names) *
+ cfg->vecs) * sizeof(u64));
aq_nic_get_stats(aq_nic, data);
}
@@ -285,6 +285,111 @@ static int aq_ethtool_set_coalesce(struct net_device *ndev,
return aq_nic_update_interrupt_moderation_settings(aq_nic);
}
+static void aq_ethtool_get_wol(struct net_device *ndev,
+ struct ethtool_wolinfo *wol)
+{
+ struct aq_nic_s *aq_nic = netdev_priv(ndev);
+ struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
+
+ wol->supported = WAKE_MAGIC;
+ wol->wolopts = 0;
+
+ if (cfg->wol)
+ wol->wolopts |= WAKE_MAGIC;
+}
+
+static int aq_ethtool_set_wol(struct net_device *ndev,
+ struct ethtool_wolinfo *wol)
+{
+ struct pci_dev *pdev = to_pci_dev(ndev->dev.parent);
+ struct aq_nic_s *aq_nic = netdev_priv(ndev);
+ struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
+ int err = 0;
+
+ if (wol->wolopts & WAKE_MAGIC)
+ cfg->wol |= AQ_NIC_WOL_ENABLED;
+ else
+ cfg->wol &= ~AQ_NIC_WOL_ENABLED;
+ err = device_set_wakeup_enable(&pdev->dev, wol->wolopts);
+
+ return err;
+}
+
+static enum hw_atl_fw2x_rate eee_mask_to_ethtool_mask(u32 speed)
+{
+ u32 rate = 0;
+
+ if (speed & AQ_NIC_RATE_EEE_10G)
+ rate |= SUPPORTED_10000baseT_Full;
+
+ if (speed & AQ_NIC_RATE_EEE_2GS)
+ rate |= SUPPORTED_2500baseX_Full;
+
+ if (speed & AQ_NIC_RATE_EEE_1G)
+ rate |= SUPPORTED_1000baseT_Full;
+
+ return rate;
+}
+
+static int aq_ethtool_get_eee(struct net_device *ndev, struct ethtool_eee *eee)
+{
+ struct aq_nic_s *aq_nic = netdev_priv(ndev);
+ u32 rate, supported_rates;
+ int err = 0;
+
+ if (!aq_nic->aq_fw_ops->get_eee_rate)
+ return -EOPNOTSUPP;
+
+ err = aq_nic->aq_fw_ops->get_eee_rate(aq_nic->aq_hw, &rate,
+ &supported_rates);
+ if (err < 0)
+ return err;
+
+ eee->supported = eee_mask_to_ethtool_mask(supported_rates);
+
+ if (aq_nic->aq_nic_cfg.eee_speeds)
+ eee->advertised = eee->supported;
+
+ eee->lp_advertised = eee_mask_to_ethtool_mask(rate);
+
+ eee->eee_enabled = !!eee->advertised;
+
+ eee->tx_lpi_enabled = eee->eee_enabled;
+ if (eee->advertised & eee->lp_advertised)
+ eee->eee_active = true;
+
+ return 0;
+}
+
+static int aq_ethtool_set_eee(struct net_device *ndev, struct ethtool_eee *eee)
+{
+ struct aq_nic_s *aq_nic = netdev_priv(ndev);
+ u32 rate, supported_rates;
+ struct aq_nic_cfg_s *cfg;
+ int err = 0;
+
+ cfg = aq_nic_get_cfg(aq_nic);
+
+ if (unlikely(!aq_nic->aq_fw_ops->get_eee_rate ||
+ !aq_nic->aq_fw_ops->set_eee_rate))
+ return -EOPNOTSUPP;
+
+ err = aq_nic->aq_fw_ops->get_eee_rate(aq_nic->aq_hw, &rate,
+ &supported_rates);
+ if (err < 0)
+ return err;
+
+ if (eee->eee_enabled) {
+ rate = supported_rates;
+ cfg->eee_speeds = rate;
+ } else {
+ rate = 0;
+ cfg->eee_speeds = 0;
+ }
+
+ return aq_nic->aq_fw_ops->set_eee_rate(aq_nic->aq_hw, rate);
+}
+
static int aq_ethtool_nway_reset(struct net_device *ndev)
{
struct aq_nic_s *aq_nic = netdev_priv(ndev);
@@ -302,13 +407,13 @@ static void aq_ethtool_get_pauseparam(struct net_device *ndev,
struct ethtool_pauseparam *pause)
{
struct aq_nic_s *aq_nic = netdev_priv(ndev);
+ u32 fc = aq_nic->aq_nic_cfg.flow_control;
pause->autoneg = 0;
- if (aq_nic->aq_hw->aq_nic_cfg->flow_control & AQ_NIC_FC_RX)
- pause->rx_pause = 1;
- if (aq_nic->aq_hw->aq_nic_cfg->flow_control & AQ_NIC_FC_TX)
- pause->tx_pause = 1;
+ pause->rx_pause = !!(fc & AQ_NIC_FC_RX);
+ pause->tx_pause = !!(fc & AQ_NIC_FC_TX);
+
}
static int aq_ethtool_set_pauseparam(struct net_device *ndev,
@@ -403,9 +508,13 @@ const struct ethtool_ops aq_ethtool_ops = {
.get_drvinfo = aq_ethtool_get_drvinfo,
.get_strings = aq_ethtool_get_strings,
.get_rxfh_indir_size = aq_ethtool_get_rss_indir_size,
+ .get_wol = aq_ethtool_get_wol,
+ .set_wol = aq_ethtool_set_wol,
.nway_reset = aq_ethtool_nway_reset,
.get_ringparam = aq_get_ringparam,
.set_ringparam = aq_set_ringparam,
+ .get_eee = aq_ethtool_get_eee,
+ .set_eee = aq_ethtool_set_eee,
.get_pauseparam = aq_ethtool_get_pauseparam,
.set_pauseparam = aq_ethtool_set_pauseparam,
.get_rxfh_key_size = aq_ethtool_get_rss_key_size,
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
index 5c00671f248d..a1e70da358ca 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h
@@ -112,7 +112,7 @@ struct aq_hw_s {
const struct aq_fw_ops *aq_fw_ops;
void __iomem *mmio;
struct aq_hw_link_status_s aq_link_status;
- struct hw_aq_atl_utils_mbox mbox;
+ struct hw_atl_utils_mbox mbox;
struct hw_atl_stats_s last_stats;
struct aq_stats_s curr_stats;
u64 speed;
@@ -124,7 +124,7 @@ struct aq_hw_s {
u32 mbox_addr;
u32 rpc_addr;
u32 rpc_tid;
- struct hw_aq_atl_utils_fw_rpc rpc;
+ struct hw_atl_utils_fw_rpc rpc;
};
struct aq_ring_s;
@@ -204,7 +204,10 @@ struct aq_hw_ops {
int (*hw_get_fw_version)(struct aq_hw_s *self, u32 *fw_version);
- int (*hw_set_power)(struct aq_hw_s *self, unsigned int power_state);
+ int (*hw_set_offload)(struct aq_hw_s *self,
+ struct aq_nic_cfg_s *aq_nic_cfg);
+
+ int (*hw_set_fc)(struct aq_hw_s *self, u32 fc, u32 tc);
};
struct aq_fw_ops {
@@ -227,7 +230,17 @@ struct aq_fw_ops {
int (*update_stats)(struct aq_hw_s *self);
+ u32 (*get_flow_control)(struct aq_hw_s *self, u32 *fcmode);
+
int (*set_flow_control)(struct aq_hw_s *self);
+
+ int (*set_power)(struct aq_hw_s *self, unsigned int power_state,
+ u8 *mac);
+
+ int (*set_eee_rate)(struct aq_hw_s *self, u32 speed);
+
+ int (*get_eee_rate)(struct aq_hw_s *self, u32 *rate,
+ u32 *supported_rates);
};
#endif /* AQ_HW_H */
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_main.c b/drivers/net/ethernet/aquantia/atlantic/aq_main.c
index e3ae29e523f0..7c07eef275eb 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_main.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_main.c
@@ -99,8 +99,11 @@ static int aq_ndev_set_features(struct net_device *ndev,
struct aq_nic_s *aq_nic = netdev_priv(ndev);
struct aq_nic_cfg_s *aq_cfg = aq_nic_get_cfg(aq_nic);
bool is_lro = false;
+ int err = 0;
+
+ aq_cfg->features = features;
- if (aq_cfg->hw_features & NETIF_F_LRO) {
+ if (aq_cfg->aq_hw_caps->hw_features & NETIF_F_LRO) {
is_lro = features & NETIF_F_LRO;
if (aq_cfg->is_lro != is_lro) {
@@ -112,8 +115,11 @@ static int aq_ndev_set_features(struct net_device *ndev,
}
}
}
+ if ((aq_nic->ndev->features ^ features) & NETIF_F_RXCSUM)
+ err = aq_nic->aq_hw_ops->hw_set_offload(aq_nic->aq_hw,
+ aq_cfg);
- return 0;
+ return err;
}
static int aq_ndev_set_mac_address(struct net_device *ndev, void *addr)
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
index 26dc6782b475..7abdc0952425 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
@@ -118,12 +118,13 @@ void aq_nic_cfg_start(struct aq_nic_s *self)
}
cfg->link_speed_msk &= cfg->aq_hw_caps->link_speed_msk;
- cfg->hw_features = cfg->aq_hw_caps->hw_features;
+ cfg->features = cfg->aq_hw_caps->hw_features;
}
static int aq_nic_update_link_status(struct aq_nic_s *self)
{
int err = self->aq_fw_ops->update_link_status(self->aq_hw);
+ u32 fc = 0;
if (err)
return err;
@@ -133,6 +134,15 @@ static int aq_nic_update_link_status(struct aq_nic_s *self)
AQ_CFG_DRV_NAME, self->link_status.mbps,
self->aq_hw->aq_link_status.mbps);
aq_nic_update_interrupt_moderation_settings(self);
+
+ /* Driver has to update flow control settings on RX block
+ * on any link event.
+ * We should query FW whether it negotiated FC.
+ */
+ if (self->aq_fw_ops->get_flow_control)
+ self->aq_fw_ops->get_flow_control(self->aq_hw, &fc);
+ if (self->aq_hw_ops->hw_set_fc)
+ self->aq_hw_ops->hw_set_fc(self->aq_hw, fc, 0);
}
self->link_status = self->aq_hw->aq_link_status;
@@ -189,7 +199,7 @@ static void aq_nic_polling_timer_cb(struct timer_list *t)
aq_vec_isr(i, (void *)aq_vec);
mod_timer(&self->polling_timer, jiffies +
- AQ_CFG_POLLING_TIMER_INTERVAL);
+ AQ_CFG_POLLING_TIMER_INTERVAL);
}
int aq_nic_ndev_register(struct aq_nic_s *self)
@@ -301,13 +311,13 @@ int aq_nic_start(struct aq_nic_s *self)
unsigned int i = 0U;
err = self->aq_hw_ops->hw_multicast_list_set(self->aq_hw,
- self->mc_list.ar,
- self->mc_list.count);
+ self->mc_list.ar,
+ self->mc_list.count);
if (err < 0)
goto err_exit;
err = self->aq_hw_ops->hw_packet_filter_set(self->aq_hw,
- self->packet_filter);
+ self->packet_filter);
if (err < 0)
goto err_exit;
@@ -327,7 +337,7 @@ int aq_nic_start(struct aq_nic_s *self)
goto err_exit;
timer_setup(&self->service_timer, aq_nic_service_timer_cb, 0);
mod_timer(&self->service_timer, jiffies +
- AQ_CFG_SERVICE_TIMER_INTERVAL);
+ AQ_CFG_SERVICE_TIMER_INTERVAL);
if (self->aq_nic_cfg.is_polling) {
timer_setup(&self->polling_timer, aq_nic_polling_timer_cb, 0);
@@ -344,7 +354,7 @@ int aq_nic_start(struct aq_nic_s *self)
}
err = self->aq_hw_ops->hw_irq_enable(self->aq_hw,
- AQ_CFG_IRQ_MASK);
+ AQ_CFG_IRQ_MASK);
if (err < 0)
goto err_exit;
}
@@ -590,7 +600,7 @@ int aq_nic_set_multicast_list(struct aq_nic_s *self, struct net_device *ndev)
}
}
- if (i > 0 && i < AQ_HW_MULTICAST_ADDRESS_MAX) {
+ if (i > 0 && i <= AQ_HW_MULTICAST_ADDRESS_MAX) {
packet_filter |= IFF_MULTICAST;
self->mc_list.count = i;
self->aq_hw_ops->hw_multicast_list_set(self->aq_hw,
@@ -772,7 +782,9 @@ void aq_nic_get_link_ksettings(struct aq_nic_s *self,
ethtool_link_ksettings_add_link_mode(cmd, advertising,
Pause);
- if (self->aq_nic_cfg.flow_control & AQ_NIC_FC_TX)
+ /* Asym is when either RX or TX, but not both */
+ if (!!(self->aq_nic_cfg.flow_control & AQ_NIC_FC_TX) ^
+ !!(self->aq_nic_cfg.flow_control & AQ_NIC_FC_RX))
ethtool_link_ksettings_add_link_mode(cmd, advertising,
Asym_Pause);
@@ -889,11 +901,13 @@ void aq_nic_deinit(struct aq_nic_s *self)
self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i])
aq_vec_deinit(aq_vec);
- if (self->power_state == AQ_HW_POWER_STATE_D0) {
- (void)self->aq_fw_ops->deinit(self->aq_hw);
- } else {
- (void)self->aq_hw_ops->hw_set_power(self->aq_hw,
- self->power_state);
+ self->aq_fw_ops->deinit(self->aq_hw);
+
+ if (self->power_state != AQ_HW_POWER_STATE_D0 ||
+ self->aq_hw->aq_nic_cfg->wol) {
+ self->aq_fw_ops->set_power(self->aq_hw,
+ self->power_state,
+ self->ndev->dev_addr);
}
err_exit:;
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h
index fecfc401f95d..44ec47a3d60a 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h
@@ -23,7 +23,7 @@ struct aq_vec_s;
struct aq_nic_cfg_s {
const struct aq_hw_caps_s *aq_hw_caps;
- u64 hw_features;
+ u64 features;
u32 rxds; /* rx ring size, descriptors # */
u32 txds; /* tx ring size, descriptors # */
u32 vecs; /* vecs==allocated irqs */
@@ -36,6 +36,7 @@ struct aq_nic_cfg_s {
u32 flow_control;
u32 link_speed_msk;
u32 vlan_id;
+ u32 wol;
u16 is_mc_list_enabled;
u16 mc_list_count;
bool is_autoneg;
@@ -44,6 +45,7 @@ struct aq_nic_cfg_s {
bool is_lro;
u8 tcs;
struct aq_rss_parameters aq_rss;
+ u32 eee_speeds;
};
#define AQ_NIC_FLAG_STARTED 0x00000004U
@@ -54,6 +56,8 @@ struct aq_nic_cfg_s {
#define AQ_NIC_FLAG_ERR_UNPLUG 0x40000000U
#define AQ_NIC_FLAG_ERR_HW 0x80000000U
+#define AQ_NIC_WOL_ENABLED BIT(0)
+
#define AQ_NIC_TCVEC2RING(_NIC_, _TC_, _VEC_) \
((_TC_) * AQ_CFG_TCS_MAX + (_VEC_))
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c
index 750007513f9d..1d5d6b8df855 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c
@@ -84,7 +84,7 @@ static int aq_pci_probe_get_hw_by_id(struct pci_dev *pdev,
const struct aq_hw_ops **ops,
const struct aq_hw_caps_s **caps)
{
- int i = 0;
+ int i;
if (pdev->vendor != PCI_VENDOR_ID_AQUANTIA)
return -EINVAL;
@@ -107,7 +107,7 @@ static int aq_pci_probe_get_hw_by_id(struct pci_dev *pdev,
int aq_pci_func_init(struct pci_dev *pdev)
{
- int err = 0;
+ int err;
err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
if (!err) {
@@ -141,7 +141,7 @@ int aq_pci_func_alloc_irq(struct aq_nic_s *self, unsigned int i,
char *name, void *aq_vec, cpumask_t *affinity_mask)
{
struct pci_dev *pdev = self->pdev;
- int err = 0;
+ int err;
if (pdev->msix_enabled || pdev->msi_enabled)
err = request_irq(pci_irq_vector(pdev, i), aq_vec_isr, 0,
@@ -164,7 +164,7 @@ int aq_pci_func_alloc_irq(struct aq_nic_s *self, unsigned int i,
void aq_pci_func_free_irqs(struct aq_nic_s *self)
{
struct pci_dev *pdev = self->pdev;
- unsigned int i = 0U;
+ unsigned int i;
for (i = 32U; i--;) {
if (!((1U << i) & self->msix_entry_mask))
@@ -194,8 +194,8 @@ static void aq_pci_free_irq_vectors(struct aq_nic_s *self)
static int aq_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *pci_id)
{
- struct aq_nic_s *self = NULL;
- int err = 0;
+ struct aq_nic_s *self;
+ int err;
struct net_device *ndev;
resource_size_t mmio_pa;
u32 bar;
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
index d1e1a0ba8615..74550ccc7a20 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
@@ -29,8 +29,8 @@ static struct aq_ring_s *aq_ring_alloc(struct aq_ring_s *self,
goto err_exit;
}
self->dx_ring = dma_alloc_coherent(aq_nic_get_dev(aq_nic),
- self->size * self->dx_size,
- &self->dx_ring_pa, GFP_KERNEL);
+ self->size * self->dx_size,
+ &self->dx_ring_pa, GFP_KERNEL);
if (!self->dx_ring) {
err = -ENOMEM;
goto err_exit;
@@ -172,6 +172,27 @@ bool aq_ring_tx_clean(struct aq_ring_s *self)
return !!budget;
}
+static void aq_rx_checksum(struct aq_ring_s *self,
+ struct aq_ring_buff_s *buff,
+ struct sk_buff *skb)
+{
+ if (!(self->aq_nic->ndev->features & NETIF_F_RXCSUM))
+ return;
+
+ if (unlikely(buff->is_cso_err)) {
+ ++self->stats.rx.errors;
+ skb->ip_summed = CHECKSUM_NONE;
+ return;
+ }
+ if (buff->is_ip_cso) {
+ __skb_incr_checksum_unnecessary(skb);
+ if (buff->is_udp_cso || buff->is_tcp_cso)
+ __skb_incr_checksum_unnecessary(skb);
+ } else {
+ skb->ip_summed = CHECKSUM_NONE;
+ }
+}
+
#define AQ_SKB_ALIGN SKB_DATA_ALIGN(sizeof(struct skb_shared_info))
int aq_ring_rx_clean(struct aq_ring_s *self,
struct napi_struct *napi,
@@ -267,18 +288,8 @@ int aq_ring_rx_clean(struct aq_ring_s *self,
}
skb->protocol = eth_type_trans(skb, ndev);
- if (unlikely(buff->is_cso_err)) {
- ++self->stats.rx.errors;
- skb->ip_summed = CHECKSUM_NONE;
- } else {
- if (buff->is_ip_cso) {
- __skb_incr_checksum_unnecessary(skb);
- if (buff->is_udp_cso || buff->is_tcp_cso)
- __skb_incr_checksum_unnecessary(skb);
- } else {
- skb->ip_summed = CHECKSUM_NONE;
- }
- }
+
+ aq_rx_checksum(self, buff, skb);
skb_set_hash(skb, buff->rss_hash,
buff->is_hash_l4 ? PKT_HASH_TYPE_L4 :
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
index 97addfa6f895..2469ed4d86b9 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c
@@ -49,37 +49,37 @@
const struct aq_hw_caps_s hw_atl_a0_caps_aqc100 = {
DEFAULT_A0_BOARD_BASIC_CAPABILITIES,
.media_type = AQ_HW_MEDIA_TYPE_FIBRE,
- .link_speed_msk = HW_ATL_A0_RATE_5G |
- HW_ATL_A0_RATE_2G5 |
- HW_ATL_A0_RATE_1G |
- HW_ATL_A0_RATE_100M,
+ .link_speed_msk = AQ_NIC_RATE_5G |
+ AQ_NIC_RATE_2GS |
+ AQ_NIC_RATE_1G |
+ AQ_NIC_RATE_100M,
};
const struct aq_hw_caps_s hw_atl_a0_caps_aqc107 = {
DEFAULT_A0_BOARD_BASIC_CAPABILITIES,
.media_type = AQ_HW_MEDIA_TYPE_TP,
- .link_speed_msk = HW_ATL_A0_RATE_10G |
- HW_ATL_A0_RATE_5G |
- HW_ATL_A0_RATE_2G5 |
- HW_ATL_A0_RATE_1G |
- HW_ATL_A0_RATE_100M,
+ .link_speed_msk = AQ_NIC_RATE_10G |
+ AQ_NIC_RATE_5G |
+ AQ_NIC_RATE_2GS |
+ AQ_NIC_RATE_1G |
+ AQ_NIC_RATE_100M,
};
const struct aq_hw_caps_s hw_atl_a0_caps_aqc108 = {
DEFAULT_A0_BOARD_BASIC_CAPABILITIES,
.media_type = AQ_HW_MEDIA_TYPE_TP,
- .link_speed_msk = HW_ATL_A0_RATE_5G |
- HW_ATL_A0_RATE_2G5 |
- HW_ATL_A0_RATE_1G |
- HW_ATL_A0_RATE_100M,
+ .link_speed_msk = AQ_NIC_RATE_5G |
+ AQ_NIC_RATE_2GS |
+ AQ_NIC_RATE_1G |
+ AQ_NIC_RATE_100M,
};
const struct aq_hw_caps_s hw_atl_a0_caps_aqc109 = {
DEFAULT_A0_BOARD_BASIC_CAPABILITIES,
.media_type = AQ_HW_MEDIA_TYPE_TP,
- .link_speed_msk = HW_ATL_A0_RATE_2G5 |
- HW_ATL_A0_RATE_1G |
- HW_ATL_A0_RATE_100M,
+ .link_speed_msk = AQ_NIC_RATE_2GS |
+ AQ_NIC_RATE_1G |
+ AQ_NIC_RATE_100M,
};
static int hw_atl_a0_hw_reset(struct aq_hw_s *self)
@@ -284,7 +284,7 @@ static int hw_atl_a0_hw_init_rx_path(struct aq_hw_s *self)
/* RSS Ring selection */
hw_atl_reg_rx_flr_rss_control1set(self, cfg->is_rss ?
- 0xB3333333U : 0x00000000U);
+ 0xB3333333U : 0x00000000U);
/* Multicast filters */
for (i = HW_ATL_A0_MAC_MAX; i--;) {
@@ -325,7 +325,7 @@ static int hw_atl_a0_hw_mac_addr_set(struct aq_hw_s *self, u8 *mac_addr)
}
h = (mac_addr[0] << 8) | (mac_addr[1]);
l = (mac_addr[2] << 24) | (mac_addr[3] << 16) |
- (mac_addr[4] << 8) | mac_addr[5];
+ (mac_addr[4] << 8) | mac_addr[5];
hw_atl_rpfl2_uc_flr_en_set(self, 0U, HW_ATL_A0_MAC);
hw_atl_rpfl2unicast_dest_addresslsw_set(self, l, HW_ATL_A0_MAC);
@@ -519,7 +519,7 @@ static int hw_atl_a0_hw_ring_rx_init(struct aq_hw_s *self,
hw_atl_rdm_rx_desc_data_buff_size_set(self,
AQ_CFG_RX_FRAME_MAX / 1024U,
- aq_ring->idx);
+ aq_ring->idx);
hw_atl_rdm_rx_desc_head_buff_size_set(self, 0U, aq_ring->idx);
hw_atl_rdm_rx_desc_head_splitting_set(self, 0U, aq_ring->idx);
@@ -758,7 +758,7 @@ static int hw_atl_a0_hw_packet_filter_set(struct aq_hw_s *self,
hw_atl_rpfl2_uc_flr_en_set(self,
(self->aq_nic_cfg->is_mc_list_enabled &&
(i <= self->aq_nic_cfg->mc_list_count)) ?
- 1U : 0U, i);
+ 1U : 0U, i);
return aq_hw_err_from_flags(self);
}
@@ -877,7 +877,6 @@ static int hw_atl_a0_hw_ring_rx_stop(struct aq_hw_s *self,
const struct aq_hw_ops hw_atl_ops_a0 = {
.hw_set_mac_address = hw_atl_a0_hw_mac_addr_set,
.hw_init = hw_atl_a0_hw_init,
- .hw_set_power = hw_atl_utils_hw_set_power,
.hw_reset = hw_atl_a0_hw_reset,
.hw_start = hw_atl_a0_hw_start,
.hw_ring_tx_start = hw_atl_a0_hw_ring_tx_start,
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0_internal.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0_internal.h
index 3c94cff57876..a021dc431ef7 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0_internal.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0_internal.h
@@ -62,12 +62,6 @@
#define HW_ATL_A0_MPI_SPEED_MSK 0xFFFFU
#define HW_ATL_A0_MPI_SPEED_SHIFT 16U
-#define HW_ATL_A0_RATE_10G BIT(0)
-#define HW_ATL_A0_RATE_5G BIT(1)
-#define HW_ATL_A0_RATE_2G5 BIT(3)
-#define HW_ATL_A0_RATE_1G BIT(4)
-#define HW_ATL_A0_RATE_100M BIT(5)
-
#define HW_ATL_A0_TXBUF_MAX 160U
#define HW_ATL_A0_RXBUF_MAX 320U
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
index 1d44a386e7d3..f02592f43fe3 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
@@ -51,38 +51,38 @@
const struct aq_hw_caps_s hw_atl_b0_caps_aqc100 = {
DEFAULT_B0_BOARD_BASIC_CAPABILITIES,
.media_type = AQ_HW_MEDIA_TYPE_FIBRE,
- .link_speed_msk = HW_ATL_B0_RATE_10G |
- HW_ATL_B0_RATE_5G |
- HW_ATL_B0_RATE_2G5 |
- HW_ATL_B0_RATE_1G |
- HW_ATL_B0_RATE_100M,
+ .link_speed_msk = AQ_NIC_RATE_10G |
+ AQ_NIC_RATE_5G |
+ AQ_NIC_RATE_2GS |
+ AQ_NIC_RATE_1G |
+ AQ_NIC_RATE_100M,
};
const struct aq_hw_caps_s hw_atl_b0_caps_aqc107 = {
DEFAULT_B0_BOARD_BASIC_CAPABILITIES,
.media_type = AQ_HW_MEDIA_TYPE_TP,
- .link_speed_msk = HW_ATL_B0_RATE_10G |
- HW_ATL_B0_RATE_5G |
- HW_ATL_B0_RATE_2G5 |
- HW_ATL_B0_RATE_1G |
- HW_ATL_B0_RATE_100M,
+ .link_speed_msk = AQ_NIC_RATE_10G |
+ AQ_NIC_RATE_5G |
+ AQ_NIC_RATE_2GS |
+ AQ_NIC_RATE_1G |
+ AQ_NIC_RATE_100M,
};
const struct aq_hw_caps_s hw_atl_b0_caps_aqc108 = {
DEFAULT_B0_BOARD_BASIC_CAPABILITIES,
.media_type = AQ_HW_MEDIA_TYPE_TP,
- .link_speed_msk = HW_ATL_B0_RATE_5G |
- HW_ATL_B0_RATE_2G5 |
- HW_ATL_B0_RATE_1G |
- HW_ATL_B0_RATE_100M,
+ .link_speed_msk = AQ_NIC_RATE_5G |
+ AQ_NIC_RATE_2GS |
+ AQ_NIC_RATE_1G |
+ AQ_NIC_RATE_100M,
};
const struct aq_hw_caps_s hw_atl_b0_caps_aqc109 = {
DEFAULT_B0_BOARD_BASIC_CAPABILITIES,
.media_type = AQ_HW_MEDIA_TYPE_TP,
- .link_speed_msk = HW_ATL_B0_RATE_2G5 |
- HW_ATL_B0_RATE_1G |
- HW_ATL_B0_RATE_100M,
+ .link_speed_msk = AQ_NIC_RATE_2GS |
+ AQ_NIC_RATE_1G |
+ AQ_NIC_RATE_100M,
};
static int hw_atl_b0_hw_reset(struct aq_hw_s *self)
@@ -100,12 +100,17 @@ static int hw_atl_b0_hw_reset(struct aq_hw_s *self)
return err;
}
+static int hw_atl_b0_set_fc(struct aq_hw_s *self, u32 fc, u32 tc)
+{
+ hw_atl_rpb_rx_xoff_en_per_tc_set(self, !!(fc & AQ_NIC_FC_RX), tc);
+ return 0;
+}
+
static int hw_atl_b0_hw_qos_set(struct aq_hw_s *self)
{
u32 tc = 0U;
u32 buff_size = 0U;
unsigned int i_priority = 0U;
- bool is_rx_flow_control = false;
/* TPS Descriptor rate init */
hw_atl_tps_tx_pkt_shed_desc_rate_curr_time_res_set(self, 0x0U);
@@ -138,7 +143,6 @@ static int hw_atl_b0_hw_qos_set(struct aq_hw_s *self)
/* QoS Rx buf size per TC */
tc = 0;
- is_rx_flow_control = (AQ_NIC_FC_RX & self->aq_nic_cfg->flow_control);
buff_size = HW_ATL_B0_RXBUF_MAX;
hw_atl_rpb_rx_pkt_buff_size_per_tc_set(self, buff_size, tc);
@@ -150,7 +154,8 @@ static int hw_atl_b0_hw_qos_set(struct aq_hw_s *self)
(buff_size *
(1024U / 32U) * 50U) /
100U, tc);
- hw_atl_rpb_rx_xoff_en_per_tc_set(self, is_rx_flow_control ? 1U : 0U, tc);
+
+ hw_atl_b0_set_fc(self, self->aq_nic_cfg->flow_control, tc);
/* QoS 802.1p priority -> TC mapping */
for (i_priority = 8U; i_priority--;)
@@ -229,8 +234,10 @@ static int hw_atl_b0_hw_offload_set(struct aq_hw_s *self,
hw_atl_tpo_tcp_udp_crc_offload_en_set(self, 1);
/* RX checksums offloads*/
- hw_atl_rpo_ipv4header_crc_offload_en_set(self, 1);
- hw_atl_rpo_tcp_udp_crc_offload_en_set(self, 1);
+ hw_atl_rpo_ipv4header_crc_offload_en_set(self, !!(aq_nic_cfg->features &
+ NETIF_F_RXCSUM));
+ hw_atl_rpo_tcp_udp_crc_offload_en_set(self, !!(aq_nic_cfg->features &
+ NETIF_F_RXCSUM));
/* LSO offloads*/
hw_atl_tdm_large_send_offload_en_set(self, 0xFFFFFFFFU);
@@ -655,9 +662,9 @@ static int hw_atl_b0_hw_ring_rx_receive(struct aq_hw_s *self,
struct hw_atl_rxd_wb_s *rxd_wb = (struct hw_atl_rxd_wb_s *)
&ring->dx_ring[ring->hw_head * HW_ATL_B0_RXD_SIZE];
- unsigned int is_err = 1U;
unsigned int is_rx_check_sum_enabled = 0U;
unsigned int pkt_type = 0U;
+ u8 rx_stat = 0U;
if (!(rxd_wb->status & 0x1U)) { /* RxD is not done */
break;
@@ -665,35 +672,35 @@ static int hw_atl_b0_hw_ring_rx_receive(struct aq_hw_s *self,
buff = &ring->buff_ring[ring->hw_head];
- is_err = (0x0000003CU & rxd_wb->status);
+ rx_stat = (0x0000003CU & rxd_wb->status) >> 2;
is_rx_check_sum_enabled = (rxd_wb->type) & (0x3U << 19);
- is_err &= ~0x20U; /* exclude validity bit */
pkt_type = 0xFFU & (rxd_wb->type >> 4);
- if (is_rx_check_sum_enabled) {
- if (0x0U == (pkt_type & 0x3U))
- buff->is_ip_cso = (is_err & 0x08U) ? 0U : 1U;
+ if (is_rx_check_sum_enabled & BIT(0) &&
+ (0x0U == (pkt_type & 0x3U)))
+ buff->is_ip_cso = (rx_stat & BIT(1)) ? 0U : 1U;
+ if (is_rx_check_sum_enabled & BIT(1)) {
if (0x4U == (pkt_type & 0x1CU))
- buff->is_udp_cso = buff->is_cso_err ? 0U : 1U;
+ buff->is_udp_cso = (rx_stat & BIT(2)) ? 0U :
+ !!(rx_stat & BIT(3));
else if (0x0U == (pkt_type & 0x1CU))
- buff->is_tcp_cso = buff->is_cso_err ? 0U : 1U;
-
- /* Checksum offload workaround for small packets */
- if (rxd_wb->pkt_len <= 60) {
- buff->is_ip_cso = 0U;
- buff->is_cso_err = 0U;
- }
+ buff->is_tcp_cso = (rx_stat & BIT(2)) ? 0U :
+ !!(rx_stat & BIT(3));
+ }
+ buff->is_cso_err = !!(rx_stat & 0x6);
+ /* Checksum offload workaround for small packets */
+ if (unlikely(rxd_wb->pkt_len <= 60)) {
+ buff->is_ip_cso = 0U;
+ buff->is_cso_err = 0U;
}
-
- is_err &= ~0x18U;
dma_unmap_page(ndev, buff->pa, buff->len, DMA_FROM_DEVICE);
- if (is_err || rxd_wb->type & 0x1000U) {
- /* status error or DMA error */
+ if ((rx_stat & BIT(0)) || rxd_wb->type & 0x1000U) {
+ /* MAC error or DMA error */
buff->is_error = 1U;
} else {
if (self->aq_nic_cfg->is_rss) {
@@ -915,6 +922,12 @@ static int hw_atl_b0_hw_interrupt_moderation_set(struct aq_hw_s *self)
static int hw_atl_b0_hw_stop(struct aq_hw_s *self)
{
hw_atl_b0_hw_irq_disable(self, HW_ATL_B0_INT_MASK);
+
+ /* Invalidate Descriptor Cache to prevent writing to the cached
+ * descriptors and to the data pointer of those descriptors
+ */
+ hw_atl_rdm_rx_dma_desc_cache_init_set(self, 1);
+
return aq_hw_err_from_flags(self);
}
@@ -935,7 +948,6 @@ static int hw_atl_b0_hw_ring_rx_stop(struct aq_hw_s *self,
const struct aq_hw_ops hw_atl_ops_b0 = {
.hw_set_mac_address = hw_atl_b0_hw_mac_addr_set,
.hw_init = hw_atl_b0_hw_init,
- .hw_set_power = hw_atl_utils_hw_set_power,
.hw_reset = hw_atl_b0_hw_reset,
.hw_start = hw_atl_b0_hw_start,
.hw_ring_tx_start = hw_atl_b0_hw_ring_tx_start,
@@ -964,4 +976,6 @@ const struct aq_hw_ops hw_atl_ops_b0 = {
.hw_get_regs = hw_atl_utils_hw_get_regs,
.hw_get_hw_stats = hw_atl_utils_get_hw_stats,
.hw_get_fw_version = hw_atl_utils_get_fw_version,
+ .hw_set_offload = hw_atl_b0_hw_offload_set,
+ .hw_set_fc = hw_atl_b0_set_fc,
};
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0_internal.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0_internal.h
index 28568f5fa74b..b318eefd36ae 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0_internal.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0_internal.h
@@ -67,12 +67,6 @@
#define HW_ATL_B0_MPI_SPEED_MSK 0xFFFFU
#define HW_ATL_B0_MPI_SPEED_SHIFT 16U
-#define HW_ATL_B0_RATE_10G BIT(0)
-#define HW_ATL_B0_RATE_5G BIT(1)
-#define HW_ATL_B0_RATE_2G5 BIT(3)
-#define HW_ATL_B0_RATE_1G BIT(4)
-#define HW_ATL_B0_RATE_100M BIT(5)
-
#define HW_ATL_B0_TXBUF_MAX 160U
#define HW_ATL_B0_RXBUF_MAX 320U
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c
index 10ba035dadb1..5502ec5f0f69 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c
@@ -619,6 +619,14 @@ void hw_atl_rpb_rx_flow_ctl_mode_set(struct aq_hw_s *aq_hw, u32 rx_flow_ctl_mode
HW_ATL_RPB_RX_FC_MODE_SHIFT, rx_flow_ctl_mode);
}
+void hw_atl_rdm_rx_dma_desc_cache_init_set(struct aq_hw_s *aq_hw, u32 init)
+{
+ aq_hw_write_reg_bit(aq_hw, HW_ATL_RDM_RX_DMA_DESC_CACHE_INIT_ADR,
+ HW_ATL_RDM_RX_DMA_DESC_CACHE_INIT_MSK,
+ HW_ATL_RDM_RX_DMA_DESC_CACHE_INIT_SHIFT,
+ init);
+}
+
void hw_atl_rpb_rx_pkt_buff_size_per_tc_set(struct aq_hw_s *aq_hw,
u32 rx_pkt_buff_size_per_tc, u32 buffer)
{
@@ -1460,3 +1468,11 @@ void hw_atl_reg_glb_cpu_scratch_scp_set(struct aq_hw_s *aq_hw,
aq_hw_write_reg(aq_hw, HW_ATL_GLB_CPU_SCRATCH_SCP_ADR(scratch_scp),
glb_cpu_scratch_scp);
}
+
+void hw_atl_mcp_up_force_intr_set(struct aq_hw_s *aq_hw, u32 up_force_intr)
+{
+ aq_hw_write_reg_bit(aq_hw, HW_ATL_MCP_UP_FORCE_INTERRUPT_ADR,
+ HW_ATL_MCP_UP_FORCE_INTERRUPT_MSK,
+ HW_ATL_MCP_UP_FORCE_INTERRUPT_SHIFT,
+ up_force_intr);
+}
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h
index dfb426f2dc2c..41f239928c15 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h
@@ -325,6 +325,9 @@ void hw_atl_rpb_rx_pkt_buff_size_per_tc_set(struct aq_hw_s *aq_hw,
u32 rx_pkt_buff_size_per_tc,
u32 buffer);
+/* set rdm rx dma descriptor cache init */
+void hw_atl_rdm_rx_dma_desc_cache_init_set(struct aq_hw_s *aq_hw, u32 init);
+
/* set rx xoff enable (per tc) */
void hw_atl_rpb_rx_xoff_en_per_tc_set(struct aq_hw_s *aq_hw, u32 rx_xoff_en_per_tc,
u32 buffer);
@@ -698,4 +701,7 @@ void hw_atl_msm_reg_wr_strobe_set(struct aq_hw_s *aq_hw, u32 reg_wr_strobe);
/* set pci register reset disable */
void hw_atl_pci_pci_reg_res_dis_set(struct aq_hw_s *aq_hw, u32 pci_reg_res_dis);
+/* set uP Force Interrupt */
+void hw_atl_mcp_up_force_intr_set(struct aq_hw_s *aq_hw, u32 up_force_intr);
+
#endif /* HW_ATL_LLH_H */
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h
index e0cf70120f1d..a715fa317b1c 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h
@@ -293,6 +293,24 @@
/* default value of bitfield desc{d}_reset */
#define HW_ATL_RDM_DESCDRESET_DEFAULT 0x0
+/* rdm_desc_init_i bitfield definitions
+ * preprocessor definitions for the bitfield rdm_desc_init_i.
+ * port="pif_rdm_desc_init_i"
+ */
+
+/* register address for bitfield rdm_desc_init_i */
+#define HW_ATL_RDM_RX_DMA_DESC_CACHE_INIT_ADR 0x00005a00
+/* bitmask for bitfield rdm_desc_init_i */
+#define HW_ATL_RDM_RX_DMA_DESC_CACHE_INIT_MSK 0xffffffff
+/* inverted bitmask for bitfield rdm_desc_init_i */
+#define HW_ATL_RDM_RX_DMA_DESC_CACHE_INIT_MSKN 0x00000000
+/* lower bit position of bitfield rdm_desc_init_i */
+#define HW_ATL_RDM_RX_DMA_DESC_CACHE_INIT_SHIFT 0
+/* width of bitfield rdm_desc_init_i */
+#define HW_ATL_RDM_RX_DMA_DESC_CACHE_INIT_WIDTH 32
+/* default value of bitfield rdm_desc_init_i */
+#define HW_ATL_RDM_RX_DMA_DESC_CACHE_INIT_DEFAULT 0x0
+
/* rx int_desc_wrb_en bitfield definitions
* preprocessor definitions for the bitfield "int_desc_wrb_en".
* port="pif_rdm_int_desc_wrb_en_i"
@@ -2387,4 +2405,17 @@
#define HW_ATL_GLB_CPU_SCRATCH_SCP_ADR(scratch_scp) \
(0x00000300u + (scratch_scp) * 0x4)
+/* register address for bitfield uP Force Interrupt */
+#define HW_ATL_MCP_UP_FORCE_INTERRUPT_ADR 0x00000404
+/* bitmask for bitfield uP Force Interrupt */
+#define HW_ATL_MCP_UP_FORCE_INTERRUPT_MSK 0x00000002
+/* inverted bitmask for bitfield uP Force Interrupt */
+#define HW_ATL_MCP_UP_FORCE_INTERRUPT_MSKN 0xFFFFFFFD
+/* lower bit position of bitfield uP Force Interrupt */
+#define HW_ATL_MCP_UP_FORCE_INTERRUPT_SHIFT 1
+/* width of bitfield uP Force Interrupt */
+#define HW_ATL_MCP_UP_FORCE_INTERRUPT_WIDTH 1
+/* default value of bitfield uP Force Interrupt */
+#define HW_ATL_MCP_UP_FORCE_INTERRUPT_DEFAULT 0x0
+
#endif /* HW_ATL_LLH_INTERNAL_H */
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
index c965e65d07db..7def1cb8ab9d 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
@@ -49,6 +49,7 @@
#define FORCE_FLASHLESS 0
static int hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual);
+
static int hw_atl_utils_mpi_set_state(struct aq_hw_s *self,
enum hal_atl_utils_fw_state_e state);
@@ -69,10 +70,10 @@ int hw_atl_utils_initfw(struct aq_hw_s *self, const struct aq_fw_ops **fw_ops)
self->fw_ver_actual) == 0) {
*fw_ops = &aq_fw_1x_ops;
} else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_2X,
- self->fw_ver_actual) == 0) {
+ self->fw_ver_actual) == 0) {
*fw_ops = &aq_fw_2x_ops;
} else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_3X,
- self->fw_ver_actual) == 0) {
+ self->fw_ver_actual) == 0) {
*fw_ops = &aq_fw_2x_ops;
} else {
aq_pr_err("Bad FW version detected: %x\n",
@@ -260,7 +261,7 @@ int hw_atl_utils_soft_reset(struct aq_hw_s *self)
hw_atl_utils_mpi_set_state(self, MPI_DEINIT);
AQ_HW_WAIT_FOR((aq_hw_read_reg(self, HW_ATL_MPI_STATE_ADR) &
- HW_ATL_MPI_STATE_MSK) == MPI_DEINIT,
+ HW_ATL_MPI_STATE_MSK) == MPI_DEINIT,
10, 1000U);
}
@@ -277,7 +278,7 @@ int hw_atl_utils_fw_downld_dwords(struct aq_hw_s *self, u32 a,
AQ_HW_WAIT_FOR(hw_atl_reg_glb_cpu_sem_get(self,
HW_ATL_FW_SM_RAM) == 1U,
- 1U, 10000U);
+ 1U, 10000U);
if (err < 0) {
bool is_locked;
@@ -325,17 +326,31 @@ static int hw_atl_utils_fw_upload_dwords(struct aq_hw_s *self, u32 a, u32 *p,
err = -ETIME;
goto err_exit;
}
+ if (IS_CHIP_FEATURE(REVISION_B1)) {
+ u32 offset = 0;
+
+ for (; offset < cnt; ++offset) {
+ aq_hw_write_reg(self, 0x328, p[offset]);
+ aq_hw_write_reg(self, 0x32C,
+ (0x80000000 | (0xFFFF & (offset * 4))));
+ hw_atl_mcp_up_force_intr_set(self, 1);
+ /* 1000 times by 10us = 10ms */
+ AQ_HW_WAIT_FOR((aq_hw_read_reg(self,
+ 0x32C) & 0xF0000000) !=
+ 0x80000000,
+ 10, 1000);
+ }
+ } else {
+ u32 offset = 0;
- aq_hw_write_reg(self, 0x00000208U, a);
-
- for (++cnt; --cnt;) {
- u32 i = 0U;
+ aq_hw_write_reg(self, 0x208, a);
- aq_hw_write_reg(self, 0x0000020CU, *(p++));
- aq_hw_write_reg(self, 0x00000200U, 0xC000U);
+ for (; offset < cnt; ++offset) {
+ aq_hw_write_reg(self, 0x20C, p[offset]);
+ aq_hw_write_reg(self, 0x200, 0xC000);
- for (i = 1024U;
- (0x100U & aq_hw_read_reg(self, 0x00000200U)) && --i;) {
+ AQ_HW_WAIT_FOR((aq_hw_read_reg(self, 0x200U) &
+ 0x100) == 0, 10, 1000);
}
}
@@ -379,7 +394,7 @@ static int hw_atl_utils_init_ucp(struct aq_hw_s *self,
/* check 10 times by 1ms */
AQ_HW_WAIT_FOR(0U != (self->mbox_addr =
- aq_hw_read_reg(self, 0x360U)), 1000U, 10U);
+ aq_hw_read_reg(self, 0x360U)), 1000U, 10U);
return err;
}
@@ -399,7 +414,7 @@ struct aq_hw_atl_utils_fw_rpc_tid_s {
#define hw_atl_utils_fw_rpc_init(_H_) hw_atl_utils_fw_rpc_wait(_H_, NULL)
-static int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned int rpc_size)
+int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned int rpc_size)
{
int err = 0;
struct aq_hw_atl_utils_fw_rpc_tid_s sw;
@@ -411,7 +426,7 @@ static int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned int rpc_size)
err = hw_atl_utils_fw_upload_dwords(self, self->rpc_addr,
(u32 *)(void *)&self->rpc,
(rpc_size + sizeof(u32) -
- sizeof(u8)) / sizeof(u32));
+ sizeof(u8)) / sizeof(u32));
if (err < 0)
goto err_exit;
@@ -423,8 +438,8 @@ err_exit:
return err;
}
-static int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self,
- struct hw_aq_atl_utils_fw_rpc **rpc)
+int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self,
+ struct hw_atl_utils_fw_rpc **rpc)
{
int err = 0;
struct aq_hw_atl_utils_fw_rpc_tid_s sw;
@@ -436,7 +451,7 @@ static int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self,
self->rpc_tid = sw.tid;
AQ_HW_WAIT_FOR(sw.tid ==
- (fw.val =
+ (fw.val =
aq_hw_read_reg(self, HW_ATL_RPC_STATE_ADR),
fw.tid), 1000U, 100U);
if (err < 0)
@@ -459,7 +474,7 @@ static int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self,
(u32 *)(void *)
&self->rpc,
(fw.len + sizeof(u32) -
- sizeof(u8)) /
+ sizeof(u8)) /
sizeof(u32));
if (err < 0)
goto err_exit;
@@ -489,16 +504,16 @@ err_exit:
}
int hw_atl_utils_mpi_read_mbox(struct aq_hw_s *self,
- struct hw_aq_atl_utils_mbox_header *pmbox)
+ struct hw_atl_utils_mbox_header *pmbox)
{
return hw_atl_utils_fw_downld_dwords(self,
- self->mbox_addr,
- (u32 *)(void *)pmbox,
- sizeof(*pmbox) / sizeof(u32));
+ self->mbox_addr,
+ (u32 *)(void *)pmbox,
+ sizeof(*pmbox) / sizeof(u32));
}
void hw_atl_utils_mpi_read_stats(struct aq_hw_s *self,
- struct hw_aq_atl_utils_mbox *pmbox)
+ struct hw_atl_utils_mbox *pmbox)
{
int err = 0;
@@ -538,7 +553,7 @@ static int hw_atl_utils_mpi_set_state(struct aq_hw_s *self,
{
int err = 0;
u32 transaction_id = 0;
- struct hw_aq_atl_utils_mbox_header mbox;
+ struct hw_atl_utils_mbox_header mbox;
u32 val = aq_hw_read_reg(self, HW_ATL_MPI_CONTROL_ADR);
if (state == MPI_RESET) {
@@ -547,8 +562,8 @@ static int hw_atl_utils_mpi_set_state(struct aq_hw_s *self,
transaction_id = mbox.transaction_id;
AQ_HW_WAIT_FOR(transaction_id !=
- (hw_atl_utils_mpi_read_mbox(self, &mbox),
- mbox.transaction_id),
+ (hw_atl_utils_mpi_read_mbox(self, &mbox),
+ mbox.transaction_id),
1000U, 100U);
if (err < 0)
goto err_exit;
@@ -645,9 +660,9 @@ int hw_atl_utils_get_mac_permanent(struct aq_hw_s *self,
if ((mac[0] & 0x01U) || ((mac[0] | mac[1] | mac[2]) == 0x00U)) {
/* chip revision */
- l = 0xE3000000U
- | (0xFFFFU & aq_hw_read_reg(self, HW_ATL_UCP_0X370_REG))
- | (0x00 << 16);
+ l = 0xE3000000U |
+ (0xFFFFU & aq_hw_read_reg(self, HW_ATL_UCP_0X370_REG)) |
+ (0x00 << 16);
h = 0x8001300EU;
mac[5] = (u8)(0xFFU & l);
@@ -730,17 +745,9 @@ static int hw_atl_fw1x_deinit(struct aq_hw_s *self)
return 0;
}
-int hw_atl_utils_hw_set_power(struct aq_hw_s *self,
- unsigned int power_state)
-{
- hw_atl_utils_mpi_set_speed(self, 0);
- hw_atl_utils_mpi_set_state(self, MPI_POWER);
- return 0;
-}
-
int hw_atl_utils_update_stats(struct aq_hw_s *self)
{
- struct hw_aq_atl_utils_mbox mbox;
+ struct hw_atl_utils_mbox mbox;
hw_atl_utils_mpi_read_stats(self, &mbox);
@@ -825,6 +832,81 @@ int hw_atl_utils_get_fw_version(struct aq_hw_s *self, u32 *fw_version)
return 0;
}
+static int aq_fw1x_set_wol(struct aq_hw_s *self, bool wol_enabled, u8 *mac)
+{
+ struct hw_atl_utils_fw_rpc *prpc = NULL;
+ unsigned int rpc_size = 0U;
+ int err = 0;
+
+ err = hw_atl_utils_fw_rpc_wait(self, &prpc);
+ if (err < 0)
+ goto err_exit;
+
+ memset(prpc, 0, sizeof(*prpc));
+
+ if (wol_enabled) {
+ rpc_size = sizeof(prpc->msg_id) + sizeof(prpc->msg_wol);
+
+ prpc->msg_id = HAL_ATLANTIC_UTILS_FW_MSG_WOL_ADD;
+ prpc->msg_wol.priority =
+ HAL_ATLANTIC_UTILS_FW_MSG_WOL_PRIOR;
+ prpc->msg_wol.pattern_id =
+ HAL_ATLANTIC_UTILS_FW_MSG_WOL_PATTERN;
+ prpc->msg_wol.wol_packet_type =
+ HAL_ATLANTIC_UTILS_FW_MSG_WOL_MAG_PKT;
+
+ ether_addr_copy((u8 *)&prpc->msg_wol.wol_pattern, mac);
+ } else {
+ rpc_size = sizeof(prpc->msg_id) + sizeof(prpc->msg_del_id);
+
+ prpc->msg_id = HAL_ATLANTIC_UTILS_FW_MSG_WOL_DEL;
+ prpc->msg_wol.pattern_id =
+ HAL_ATLANTIC_UTILS_FW_MSG_WOL_PATTERN;
+ }
+
+ err = hw_atl_utils_fw_rpc_call(self, rpc_size);
+
+err_exit:
+ return err;
+}
+
+static int aq_fw1x_set_power(struct aq_hw_s *self, unsigned int power_state,
+ u8 *mac)
+{
+ struct hw_atl_utils_fw_rpc *prpc = NULL;
+ unsigned int rpc_size = 0U;
+ int err = 0;
+
+ if (self->aq_nic_cfg->wol & AQ_NIC_WOL_ENABLED) {
+ err = aq_fw1x_set_wol(self, 1, mac);
+
+ if (err < 0)
+ goto err_exit;
+
+ rpc_size = sizeof(prpc->msg_id) +
+ sizeof(prpc->msg_enable_wakeup);
+
+ err = hw_atl_utils_fw_rpc_wait(self, &prpc);
+
+ if (err < 0)
+ goto err_exit;
+
+ memset(prpc, 0, rpc_size);
+
+ prpc->msg_id = HAL_ATLANTIC_UTILS_FW_MSG_ENABLE_WAKEUP;
+ prpc->msg_enable_wakeup.pattern_mask = 0x00000002;
+
+ err = hw_atl_utils_fw_rpc_call(self, rpc_size);
+ if (err < 0)
+ goto err_exit;
+ }
+ hw_atl_utils_mpi_set_speed(self, 0);
+ hw_atl_utils_mpi_set_state(self, MPI_POWER);
+
+err_exit:
+ return err;
+}
+
const struct aq_fw_ops aq_fw_1x_ops = {
.init = hw_atl_utils_mpi_create,
.deinit = hw_atl_fw1x_deinit,
@@ -834,5 +916,8 @@ const struct aq_fw_ops aq_fw_1x_ops = {
.set_state = hw_atl_utils_mpi_set_state,
.update_link_status = hw_atl_utils_mpi_get_link_status,
.update_stats = hw_atl_utils_update_stats,
+ .set_power = aq_fw1x_set_power,
+ .set_eee_rate = NULL,
+ .get_eee_rate = NULL,
.set_flow_control = NULL,
};
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
index b875590efcbd..3613fca64b58 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
@@ -75,7 +75,7 @@ union __packed ip_addr {
} v4;
};
-struct __packed hw_aq_atl_utils_fw_rpc {
+struct __packed hw_atl_utils_fw_rpc {
u32 msg_id;
union {
@@ -101,8 +101,6 @@ struct __packed hw_aq_atl_utils_fw_rpc {
struct {
u32 priority;
u32 wol_packet_type;
- u16 friendly_name_len;
- u16 friendly_name[65];
u32 pattern_id;
u32 next_wol_pattern_offset;
@@ -134,25 +132,112 @@ struct __packed hw_aq_atl_utils_fw_rpc {
u32 pattern_offset;
u32 pattern_size;
} wol_bit_map_pattern;
+
+ struct {
+ u8 mac_addr[ETH_ALEN];
+ } wol_magic_packet_patter;
} wol_pattern;
} msg_wol;
struct {
- u32 is_wake_on_link_down;
- u32 is_wake_on_link_up;
- } msg_wolink;
+ union {
+ u32 pattern_mask;
+
+ struct {
+ u32 reason_arp_v4_pkt : 1;
+ u32 reason_ipv4_ping_pkt : 1;
+ u32 reason_ipv6_ns_pkt : 1;
+ u32 reason_ipv6_ping_pkt : 1;
+ u32 reason_link_up : 1;
+ u32 reason_link_down : 1;
+ u32 reason_maximum : 1;
+ };
+ };
+
+ union {
+ u32 offload_mask;
+ };
+ } msg_enable_wakeup;
+
+ struct {
+ u32 id;
+ } msg_del_id;
};
};
-struct __packed hw_aq_atl_utils_mbox_header {
+struct __packed hw_atl_utils_mbox_header {
u32 version;
u32 transaction_id;
u32 error;
};
-struct __packed hw_aq_atl_utils_mbox {
- struct hw_aq_atl_utils_mbox_header header;
+struct __packed hw_aq_info {
+ u8 reserved[6];
+ u16 phy_fault_code;
+ u16 phy_temperature;
+ u8 cable_len;
+ u8 reserved1;
+ u32 cable_diag_data[4];
+ u8 reserved2[32];
+ u32 caps_lo;
+ u32 caps_hi;
+};
+
+struct __packed hw_atl_utils_mbox {
+ struct hw_atl_utils_mbox_header header;
struct hw_atl_stats_s stats;
+ struct hw_aq_info info;
+};
+
+/* fw2x */
+typedef u32 fw_offset_t;
+
+struct __packed offload_ip_info {
+ u8 v4_local_addr_count;
+ u8 v4_addr_count;
+ u8 v6_local_addr_count;
+ u8 v6_addr_count;
+ fw_offset_t v4_addr;
+ fw_offset_t v4_prefix;
+ fw_offset_t v6_addr;
+ fw_offset_t v6_prefix;
+};
+
+struct __packed offload_port_info {
+ u16 udp_port_count;
+ u16 tcp_port_count;
+ fw_offset_t udp_port;
+ fw_offset_t tcp_port;
+};
+
+struct __packed offload_ka_info {
+ u16 v4_ka_count;
+ u16 v6_ka_count;
+ u32 retry_count;
+ u32 retry_interval;
+ fw_offset_t v4_ka;
+ fw_offset_t v6_ka;
+};
+
+struct __packed offload_rr_info {
+ u32 rr_count;
+ u32 rr_buf_len;
+ fw_offset_t rr_id_x;
+ fw_offset_t rr_buf;
+};
+
+struct __packed offload_info {
+ u32 version;
+ u32 len;
+ u8 mac_addr[ETH_ALEN];
+
+ u8 reserved[2];
+
+ struct offload_ip_info ips;
+ struct offload_port_info ports;
+ struct offload_ka_info kas;
+ struct offload_rr_info rrs;
+ u8 buf[0];
};
#define HAL_ATLANTIC_UTILS_CHIP_MIPS 0x00000001U
@@ -181,6 +266,21 @@ enum hal_atl_utils_fw_state_e {
#define HAL_ATLANTIC_RATE_100M BIT(5)
#define HAL_ATLANTIC_RATE_INVALID BIT(6)
+#define HAL_ATLANTIC_UTILS_FW_MSG_PING 0x1U
+#define HAL_ATLANTIC_UTILS_FW_MSG_ARP 0x2U
+#define HAL_ATLANTIC_UTILS_FW_MSG_INJECT 0x3U
+#define HAL_ATLANTIC_UTILS_FW_MSG_WOL_ADD 0x4U
+#define HAL_ATLANTIC_UTILS_FW_MSG_WOL_PRIOR 0x10000000U
+#define HAL_ATLANTIC_UTILS_FW_MSG_WOL_PATTERN 0x1U
+#define HAL_ATLANTIC_UTILS_FW_MSG_WOL_MAG_PKT 0x2U
+#define HAL_ATLANTIC_UTILS_FW_MSG_WOL_DEL 0x5U
+#define HAL_ATLANTIC_UTILS_FW_MSG_ENABLE_WAKEUP 0x6U
+#define HAL_ATLANTIC_UTILS_FW_MSG_MSM_PFC 0x7U
+#define HAL_ATLANTIC_UTILS_FW_MSG_PROVISIONING 0x8U
+#define HAL_ATLANTIC_UTILS_FW_MSG_OFFLOAD_ADD 0x9U
+#define HAL_ATLANTIC_UTILS_FW_MSG_OFFLOAD_DEL 0xAU
+#define HAL_ATLANTIC_UTILS_FW_MSG_CABLE_DIAG 0xDU
+
enum hw_atl_fw2x_rate {
FW2X_RATE_100M = 0x20,
FW2X_RATE_1G = 0x100,
@@ -286,10 +386,10 @@ int hw_atl_utils_soft_reset(struct aq_hw_s *self);
void hw_atl_utils_hw_chip_features_init(struct aq_hw_s *self, u32 *p);
int hw_atl_utils_mpi_read_mbox(struct aq_hw_s *self,
- struct hw_aq_atl_utils_mbox_header *pmbox);
+ struct hw_atl_utils_mbox_header *pmbox);
void hw_atl_utils_mpi_read_stats(struct aq_hw_s *self,
- struct hw_aq_atl_utils_mbox *pmbox);
+ struct hw_atl_utils_mbox *pmbox);
void hw_atl_utils_mpi_set(struct aq_hw_s *self,
enum hal_atl_utils_fw_state_e state,
@@ -316,9 +416,17 @@ int hw_atl_utils_get_fw_version(struct aq_hw_s *self, u32 *fw_version);
int hw_atl_utils_update_stats(struct aq_hw_s *self);
struct aq_stats_s *hw_atl_utils_get_hw_stats(struct aq_hw_s *self);
+
int hw_atl_utils_fw_downld_dwords(struct aq_hw_s *self, u32 a,
u32 *p, u32 cnt);
+int hw_atl_utils_fw_set_wol(struct aq_hw_s *self, bool wol_enabled, u8 *mac);
+
+int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned int rpc_size);
+
+int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self,
+ struct hw_atl_utils_fw_rpc **rpc);
+
extern const struct aq_fw_ops aq_fw_1x_ops;
extern const struct aq_fw_ops aq_fw_2x_ops;
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
index e37943760a58..7de3220d9cab 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
@@ -16,11 +16,13 @@
#include "../aq_pci_func.h"
#include "../aq_ring.h"
#include "../aq_vec.h"
+#include "../aq_nic.h"
#include "hw_atl_utils.h"
#include "hw_atl_llh.h"
#define HW_ATL_FW2X_MPI_EFUSE_ADDR 0x364
#define HW_ATL_FW2X_MPI_MBOX_ADDR 0x360
+#define HW_ATL_FW2X_MPI_RPC_ADDR 0x334
#define HW_ATL_FW2X_MPI_CONTROL_ADDR 0x368
#define HW_ATL_FW2X_MPI_CONTROL2_ADDR 0x36C
@@ -28,6 +30,44 @@
#define HW_ATL_FW2X_MPI_STATE_ADDR 0x370
#define HW_ATL_FW2X_MPI_STATE2_ADDR 0x374
+#define HW_ATL_FW2X_CAP_PAUSE BIT(CAPS_HI_PAUSE)
+#define HW_ATL_FW2X_CAP_ASYM_PAUSE BIT(CAPS_HI_ASYMMETRIC_PAUSE)
+#define HW_ATL_FW2X_CAP_SLEEP_PROXY BIT(CAPS_HI_SLEEP_PROXY)
+#define HW_ATL_FW2X_CAP_WOL BIT(CAPS_HI_WOL)
+
+#define HW_ATL_FW2X_CTRL_SLEEP_PROXY BIT(CTRL_SLEEP_PROXY)
+#define HW_ATL_FW2X_CTRL_WOL BIT(CTRL_WOL)
+#define HW_ATL_FW2X_CTRL_LINK_DROP BIT(CTRL_LINK_DROP)
+#define HW_ATL_FW2X_CTRL_PAUSE BIT(CTRL_PAUSE)
+#define HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE BIT(CTRL_ASYMMETRIC_PAUSE)
+#define HW_ATL_FW2X_CTRL_FORCE_RECONNECT BIT(CTRL_FORCE_RECONNECT)
+
+#define HW_ATL_FW2X_CAP_EEE_1G_MASK BIT(CAPS_HI_1000BASET_FD_EEE)
+#define HW_ATL_FW2X_CAP_EEE_2G5_MASK BIT(CAPS_HI_2P5GBASET_FD_EEE)
+#define HW_ATL_FW2X_CAP_EEE_5G_MASK BIT(CAPS_HI_5GBASET_FD_EEE)
+#define HW_ATL_FW2X_CAP_EEE_10G_MASK BIT(CAPS_HI_10GBASET_FD_EEE)
+
+#define HAL_ATLANTIC_WOL_FILTERS_COUNT 8
+#define HAL_ATLANTIC_UTILS_FW2X_MSG_WOL 0x0E
+
+struct __packed fw2x_msg_wol_pattern {
+ u8 mask[16];
+ u32 crc;
+};
+
+struct __packed fw2x_msg_wol {
+ u32 msg_id;
+ u8 hw_addr[ETH_ALEN];
+ u8 magic_packet_enabled;
+ u8 filter_count;
+ struct fw2x_msg_wol_pattern filter[HAL_ATLANTIC_WOL_FILTERS_COUNT];
+ u8 link_up_enabled;
+ u8 link_down_enabled;
+ u16 reserved;
+ u32 link_up_timeout;
+ u32 link_down_timeout;
+};
+
static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed);
static int aq_fw2x_set_state(struct aq_hw_s *self,
enum hal_atl_utils_fw_state_e state);
@@ -38,8 +78,12 @@ static int aq_fw2x_init(struct aq_hw_s *self)
/* check 10 times by 1ms */
AQ_HW_WAIT_FOR(0U != (self->mbox_addr =
- aq_hw_read_reg(self, HW_ATL_FW2X_MPI_MBOX_ADDR)),
+ aq_hw_read_reg(self, HW_ATL_FW2X_MPI_MBOX_ADDR)),
1000U, 10U);
+ AQ_HW_WAIT_FOR(0U != (self->rpc_addr =
+ aq_hw_read_reg(self, HW_ATL_FW2X_MPI_RPC_ADDR)),
+ 1000U, 100U);
+
return err;
}
@@ -78,6 +122,38 @@ static enum hw_atl_fw2x_rate link_speed_mask_2fw2x_ratemask(u32 speed)
return rate;
}
+static u32 fw2x_to_eee_mask(u32 speed)
+{
+ u32 rate = 0;
+
+ if (speed & HW_ATL_FW2X_CAP_EEE_10G_MASK)
+ rate |= AQ_NIC_RATE_EEE_10G;
+ if (speed & HW_ATL_FW2X_CAP_EEE_5G_MASK)
+ rate |= AQ_NIC_RATE_EEE_5G;
+ if (speed & HW_ATL_FW2X_CAP_EEE_2G5_MASK)
+ rate |= AQ_NIC_RATE_EEE_2GS;
+ if (speed & HW_ATL_FW2X_CAP_EEE_1G_MASK)
+ rate |= AQ_NIC_RATE_EEE_1G;
+
+ return rate;
+}
+
+static u32 eee_mask_to_fw2x(u32 speed)
+{
+ u32 rate = 0;
+
+ if (speed & AQ_NIC_RATE_EEE_10G)
+ rate |= HW_ATL_FW2X_CAP_EEE_10G_MASK;
+ if (speed & AQ_NIC_RATE_EEE_5G)
+ rate |= HW_ATL_FW2X_CAP_EEE_5G_MASK;
+ if (speed & AQ_NIC_RATE_EEE_2GS)
+ rate |= HW_ATL_FW2X_CAP_EEE_2G5_MASK;
+ if (speed & AQ_NIC_RATE_EEE_1G)
+ rate |= HW_ATL_FW2X_CAP_EEE_1G_MASK;
+
+ return rate;
+}
+
static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed)
{
u32 val = link_speed_mask_2fw2x_ratemask(speed);
@@ -100,14 +176,27 @@ static void aq_fw2x_set_mpi_flow_control(struct aq_hw_s *self, u32 *mpi_state)
*mpi_state &= ~BIT(CAPS_HI_ASYMMETRIC_PAUSE);
}
+static void aq_fw2x_upd_eee_rate_bits(struct aq_hw_s *self, u32 *mpi_opts,
+ u32 eee_speeds)
+{
+ *mpi_opts &= ~(HW_ATL_FW2X_CAP_EEE_1G_MASK |
+ HW_ATL_FW2X_CAP_EEE_2G5_MASK |
+ HW_ATL_FW2X_CAP_EEE_5G_MASK |
+ HW_ATL_FW2X_CAP_EEE_10G_MASK);
+
+ *mpi_opts |= eee_mask_to_fw2x(eee_speeds);
+}
+
static int aq_fw2x_set_state(struct aq_hw_s *self,
enum hal_atl_utils_fw_state_e state)
{
u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
+ struct aq_nic_cfg_s *cfg = self->aq_nic_cfg;
switch (state) {
case MPI_INIT:
mpi_state &= ~BIT(CAPS_HI_LINK_DROP);
+ aq_fw2x_upd_eee_rate_bits(self, &mpi_state, cfg->eee_speeds);
aq_fw2x_set_mpi_flow_control(self, &mpi_state);
break;
case MPI_DEINIT:
@@ -126,7 +215,7 @@ static int aq_fw2x_update_link_status(struct aq_hw_s *self)
{
u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE_ADDR);
u32 speed = mpi_state & (FW2X_RATE_100M | FW2X_RATE_1G |
- FW2X_RATE_2G5 | FW2X_RATE_5G | FW2X_RATE_10G);
+ FW2X_RATE_2G5 | FW2X_RATE_5G | FW2X_RATE_10G);
struct aq_hw_link_status_s *link_status = &self->aq_link_status;
if (speed) {
@@ -175,9 +264,7 @@ static int aq_fw2x_get_mac_permanent(struct aq_hw_s *self, u8 *mac)
get_random_bytes(&rnd, sizeof(unsigned int));
- l = 0xE3000000U
- | (0xFFFFU & rnd)
- | (0x00 << 16);
+ l = 0xE3000000U | (0xFFFFU & rnd) | (0x00 << 16);
h = 0x8001300EU;
mac[5] = (u8)(0xFFU & l);
@@ -207,7 +294,7 @@ static int aq_fw2x_update_stats(struct aq_hw_s *self)
/* Wait FW to report back */
AQ_HW_WAIT_FOR(orig_stats_val !=
(aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR) &
- BIT(CAPS_HI_STATISTICS)),
+ BIT(CAPS_HI_STATISTICS)),
1U, 10000U);
if (err)
return err;
@@ -215,6 +302,135 @@ static int aq_fw2x_update_stats(struct aq_hw_s *self)
return hw_atl_utils_update_stats(self);
}
+static int aq_fw2x_set_sleep_proxy(struct aq_hw_s *self, u8 *mac)
+{
+ struct hw_atl_utils_fw_rpc *rpc = NULL;
+ struct offload_info *cfg = NULL;
+ unsigned int rpc_size = 0U;
+ u32 mpi_opts;
+ int err = 0;
+
+ rpc_size = sizeof(rpc->msg_id) + sizeof(*cfg);
+
+ err = hw_atl_utils_fw_rpc_wait(self, &rpc);
+ if (err < 0)
+ goto err_exit;
+
+ memset(rpc, 0, rpc_size);
+ cfg = (struct offload_info *)(&rpc->msg_id + 1);
+
+ memcpy(cfg->mac_addr, mac, ETH_ALEN);
+ cfg->len = sizeof(*cfg);
+
+ /* Clear bit 0x36C.23 and 0x36C.22 */
+ mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
+ mpi_opts &= ~HW_ATL_FW2X_CTRL_SLEEP_PROXY;
+ mpi_opts &= ~HW_ATL_FW2X_CTRL_LINK_DROP;
+
+ aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
+
+ err = hw_atl_utils_fw_rpc_call(self, rpc_size);
+ if (err < 0)
+ goto err_exit;
+
+ /* Set bit 0x36C.23 */
+ mpi_opts |= HW_ATL_FW2X_CTRL_SLEEP_PROXY;
+ aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
+
+ AQ_HW_WAIT_FOR((aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR) &
+ HW_ATL_FW2X_CTRL_SLEEP_PROXY), 1U, 10000U);
+
+err_exit:
+ return err;
+}
+
+static int aq_fw2x_set_wol_params(struct aq_hw_s *self, u8 *mac)
+{
+ struct hw_atl_utils_fw_rpc *rpc = NULL;
+ struct fw2x_msg_wol *msg = NULL;
+ u32 mpi_opts;
+ int err = 0;
+
+ err = hw_atl_utils_fw_rpc_wait(self, &rpc);
+ if (err < 0)
+ goto err_exit;
+
+ msg = (struct fw2x_msg_wol *)rpc;
+
+ msg->msg_id = HAL_ATLANTIC_UTILS_FW2X_MSG_WOL;
+ msg->magic_packet_enabled = true;
+ memcpy(msg->hw_addr, mac, ETH_ALEN);
+
+ mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
+ mpi_opts &= ~(HW_ATL_FW2X_CTRL_SLEEP_PROXY | HW_ATL_FW2X_CTRL_WOL);
+
+ aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
+
+ err = hw_atl_utils_fw_rpc_call(self, sizeof(*msg));
+ if (err < 0)
+ goto err_exit;
+
+ /* Set bit 0x36C.24 */
+ mpi_opts |= HW_ATL_FW2X_CTRL_WOL;
+ aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
+
+ AQ_HW_WAIT_FOR((aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR) &
+ HW_ATL_FW2X_CTRL_WOL), 1U, 10000U);
+
+err_exit:
+ return err;
+}
+
+static int aq_fw2x_set_power(struct aq_hw_s *self, unsigned int power_state,
+ u8 *mac)
+{
+ int err = 0;
+
+ if (self->aq_nic_cfg->wol & AQ_NIC_WOL_ENABLED) {
+ err = aq_fw2x_set_sleep_proxy(self, mac);
+ if (err < 0)
+ goto err_exit;
+ err = aq_fw2x_set_wol_params(self, mac);
+ }
+
+err_exit:
+ return err;
+}
+
+static int aq_fw2x_set_eee_rate(struct aq_hw_s *self, u32 speed)
+{
+ u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
+
+ aq_fw2x_upd_eee_rate_bits(self, &mpi_opts, speed);
+
+ aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
+
+ return 0;
+}
+
+static int aq_fw2x_get_eee_rate(struct aq_hw_s *self, u32 *rate,
+ u32 *supported_rates)
+{
+ u32 mpi_state;
+ u32 caps_hi;
+ int err = 0;
+ u32 addr = self->mbox_addr + offsetof(struct hw_atl_utils_mbox, info) +
+ offsetof(struct hw_aq_info, caps_hi);
+
+ err = hw_atl_utils_fw_downld_dwords(self, addr, &caps_hi,
+ sizeof(caps_hi) / sizeof(u32));
+
+ if (err)
+ return err;
+
+ *supported_rates = fw2x_to_eee_mask(caps_hi);
+
+ mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR);
+ *rate = fw2x_to_eee_mask(mpi_state);
+
+ return err;
+}
+
static int aq_fw2x_renegotiate(struct aq_hw_s *self)
{
u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
@@ -237,6 +453,24 @@ static int aq_fw2x_set_flow_control(struct aq_hw_s *self)
return 0;
}
+static u32 aq_fw2x_get_flow_control(struct aq_hw_s *self, u32 *fcmode)
+{
+ u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR);
+
+ if (mpi_state & HW_ATL_FW2X_CAP_PAUSE)
+ if (mpi_state & HW_ATL_FW2X_CAP_ASYM_PAUSE)
+ *fcmode = AQ_NIC_FC_RX;
+ else
+ *fcmode = AQ_NIC_FC_RX | AQ_NIC_FC_TX;
+ else
+ if (mpi_state & HW_ATL_FW2X_CAP_ASYM_PAUSE)
+ *fcmode = AQ_NIC_FC_TX;
+ else
+ *fcmode = 0;
+
+ return 0;
+}
+
const struct aq_fw_ops aq_fw_2x_ops = {
.init = aq_fw2x_init,
.deinit = aq_fw2x_deinit,
@@ -247,5 +481,9 @@ const struct aq_fw_ops aq_fw_2x_ops = {
.set_state = aq_fw2x_set_state,
.update_link_status = aq_fw2x_update_link_status,
.update_stats = aq_fw2x_update_stats,
- .set_flow_control = aq_fw2x_set_flow_control,
+ .set_power = aq_fw2x_set_power,
+ .set_eee_rate = aq_fw2x_set_eee_rate,
+ .get_eee_rate = aq_fw2x_get_eee_rate,
+ .set_flow_control = aq_fw2x_set_flow_control,
+ .get_flow_control = aq_fw2x_get_flow_control
};
diff --git a/drivers/net/ethernet/aquantia/atlantic/ver.h b/drivers/net/ethernet/aquantia/atlantic/ver.h
index 94efc6477bdc..b48260114da3 100644
--- a/drivers/net/ethernet/aquantia/atlantic/ver.h
+++ b/drivers/net/ethernet/aquantia/atlantic/ver.h
@@ -12,7 +12,7 @@
#define NIC_MAJOR_DRIVER_VERSION 2
#define NIC_MINOR_DRIVER_VERSION 0
-#define NIC_BUILD_DRIVER_VERSION 3
+#define NIC_BUILD_DRIVER_VERSION 4
#define NIC_REVISION_DRIVER_VERSION 0
#define AQ_CFG_DRV_VERSION_SUFFIX "-kern"
diff --git a/drivers/net/ethernet/atheros/alx/alx.h b/drivers/net/ethernet/atheros/alx/alx.h
index 78c5de467426..9d0e74f6b089 100644
--- a/drivers/net/ethernet/atheros/alx/alx.h
+++ b/drivers/net/ethernet/atheros/alx/alx.h
@@ -140,6 +140,5 @@ struct alx_priv {
};
extern const struct ethtool_ops alx_ethtool_ops;
-extern const char alx_drv_name[];
#endif
diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c
index 6d3221134927..c131cfc1b79d 100644
--- a/drivers/net/ethernet/atheros/alx/main.c
+++ b/drivers/net/ethernet/atheros/alx/main.c
@@ -49,7 +49,7 @@
#include "hw.h"
#include "reg.h"
-const char alx_drv_name[] = "alx";
+static const char alx_drv_name[] = "alx";
static void alx_free_txbuf(struct alx_tx_queue *txq, int entry)
{
@@ -1964,8 +1964,6 @@ 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:
- pci_cleanup_aer_uncorrect_error_status(pdev);
-
rtnl_unlock();
return rc;
diff --git a/drivers/net/ethernet/atheros/atlx/atl1.c b/drivers/net/ethernet/atheros/atlx/atl1.c
index b81fbf119bce..63edc5706c09 100644
--- a/drivers/net/ethernet/atheros/atlx/atl1.c
+++ b/drivers/net/ethernet/atheros/atlx/atl1.c
@@ -63,7 +63,6 @@
#include <linux/jiffies.h>
#include <linux/mii.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/net.h>
#include <linux/netdevice.h>
#include <linux/pci.h>
@@ -3278,7 +3277,6 @@ static int atl1_set_link_ksettings(struct net_device *netdev,
u16 phy_data;
int ret_val = 0;
u16 old_media_type = hw->media_type;
- u32 advertising;
if (netif_running(adapter->netdev)) {
if (netif_msg_link(adapter))
@@ -3312,25 +3310,7 @@ static int atl1_set_link_ksettings(struct net_device *netdev,
hw->media_type = MEDIA_TYPE_10M_HALF;
}
}
- switch (hw->media_type) {
- case MEDIA_TYPE_AUTO_SENSOR:
- advertising =
- ADVERTISED_10baseT_Half |
- ADVERTISED_10baseT_Full |
- ADVERTISED_100baseT_Half |
- ADVERTISED_100baseT_Full |
- ADVERTISED_1000baseT_Full |
- ADVERTISED_Autoneg | ADVERTISED_TP;
- break;
- case MEDIA_TYPE_1000M_FULL:
- advertising =
- ADVERTISED_1000baseT_Full |
- ADVERTISED_Autoneg | ADVERTISED_TP;
- break;
- default:
- advertising = 0;
- break;
- }
+
if (atl1_phy_setup_autoneg_adv(hw)) {
ret_val = -EINVAL;
if (netif_msg_link(adapter))
diff --git a/drivers/net/ethernet/aurora/nb8800.c b/drivers/net/ethernet/aurora/nb8800.c
index c8d1f8fa4713..6f56276015a4 100644
--- a/drivers/net/ethernet/aurora/nb8800.c
+++ b/drivers/net/ethernet/aurora/nb8800.c
@@ -935,18 +935,11 @@ static void nb8800_pause_adv(struct net_device *dev)
{
struct nb8800_priv *priv = netdev_priv(dev);
struct phy_device *phydev = dev->phydev;
- u32 adv = 0;
if (!phydev)
return;
- if (priv->pause_rx)
- adv |= ADVERTISED_Pause | ADVERTISED_Asym_Pause;
- if (priv->pause_tx)
- adv ^= ADVERTISED_Asym_Pause;
-
- phydev->supported |= adv;
- phydev->advertising |= adv;
+ phy_set_asym_pause(phydev, priv->pause_rx, priv->pause_tx);
}
static int nb8800_open(struct net_device *dev)
diff --git a/drivers/net/ethernet/broadcom/bcm63xx_enet.c b/drivers/net/ethernet/broadcom/bcm63xx_enet.c
index 897302adc38e..6bae973d4dce 100644
--- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c
+++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c
@@ -568,12 +568,13 @@ static irqreturn_t bcm_enet_isr_dma(int irq, void *dev_id)
/*
* tx request callback
*/
-static int bcm_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t
+bcm_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct bcm_enet_priv *priv;
struct bcm_enet_desc *desc;
u32 len_stat;
- int ret;
+ netdev_tx_t ret;
priv = netdev_priv(dev);
@@ -890,19 +891,10 @@ static int bcm_enet_open(struct net_device *dev)
}
/* mask with MAC supported features */
- phydev->supported &= (SUPPORTED_10baseT_Half |
- SUPPORTED_10baseT_Full |
- SUPPORTED_100baseT_Half |
- SUPPORTED_100baseT_Full |
- SUPPORTED_Autoneg |
- SUPPORTED_Pause |
- SUPPORTED_MII);
- phydev->advertising = phydev->supported;
-
- if (priv->pause_auto && priv->pause_rx && priv->pause_tx)
- phydev->advertising |= SUPPORTED_Pause;
- else
- phydev->advertising &= ~SUPPORTED_Pause;
+ phy_support_sym_pause(phydev);
+ phy_set_max_speed(phydev, SPEED_100);
+ phy_set_sym_pause(phydev, priv->pause_rx, priv->pause_rx,
+ priv->pause_auto);
phy_attached_info(phydev);
diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c
index 147045757b10..0e2d99c737e3 100644
--- a/drivers/net/ethernet/broadcom/bcmsysport.c
+++ b/drivers/net/ethernet/broadcom/bcmsysport.c
@@ -126,8 +126,8 @@ static inline void tdma_port_write_desc_addr(struct bcm_sysport_priv *priv,
}
/* Ethtool operations */
-static int bcm_sysport_set_rx_csum(struct net_device *dev,
- netdev_features_t wanted)
+static void bcm_sysport_set_rx_csum(struct net_device *dev,
+ netdev_features_t wanted)
{
struct bcm_sysport_priv *priv = netdev_priv(dev);
u32 reg;
@@ -157,12 +157,10 @@ static int bcm_sysport_set_rx_csum(struct net_device *dev,
reg &= ~RXCHK_BRCM_TAG_EN;
rxchk_writel(priv, reg, RXCHK_CONTROL);
-
- return 0;
}
-static int bcm_sysport_set_tx_csum(struct net_device *dev,
- netdev_features_t wanted)
+static void bcm_sysport_set_tx_csum(struct net_device *dev,
+ netdev_features_t wanted)
{
struct bcm_sysport_priv *priv = netdev_priv(dev);
u32 reg;
@@ -177,23 +175,24 @@ static int bcm_sysport_set_tx_csum(struct net_device *dev,
else
reg &= ~tdma_control_bit(priv, TSB_EN);
tdma_writel(priv, reg, TDMA_CONTROL);
-
- return 0;
}
static int bcm_sysport_set_features(struct net_device *dev,
netdev_features_t features)
{
- netdev_features_t changed = features ^ dev->features;
- netdev_features_t wanted = dev->wanted_features;
- int ret = 0;
+ struct bcm_sysport_priv *priv = netdev_priv(dev);
+
+ /* Read CRC forward */
+ if (!priv->is_lite)
+ priv->crc_fwd = !!(umac_readl(priv, UMAC_CMD) & CMD_CRC_FWD);
+ else
+ priv->crc_fwd = !((gib_readl(priv, GIB_CONTROL) &
+ GIB_FCS_STRIP) >> GIB_FCS_STRIP_SHIFT);
- if (changed & NETIF_F_RXCSUM)
- ret = bcm_sysport_set_rx_csum(dev, wanted);
- if (changed & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM))
- ret = bcm_sysport_set_tx_csum(dev, wanted);
+ bcm_sysport_set_rx_csum(dev, features);
+ bcm_sysport_set_tx_csum(dev, features);
- return ret;
+ return 0;
}
/* Hardware counters must be kept in sync because the order/offset
@@ -285,6 +284,8 @@ static const struct bcm_sysport_stats bcm_sysport_gstrings_stats[] = {
STAT_MIB_SOFT("alloc_rx_buff_failed", mib.alloc_rx_buff_failed),
STAT_MIB_SOFT("rx_dma_failed", mib.rx_dma_failed),
STAT_MIB_SOFT("tx_dma_failed", mib.tx_dma_failed),
+ STAT_MIB_SOFT("tx_realloc_tsb", mib.tx_realloc_tsb),
+ STAT_MIB_SOFT("tx_realloc_tsb_failed", mib.tx_realloc_tsb_failed),
/* Per TX-queue statistics are dynamically appended */
};
@@ -1069,9 +1070,6 @@ static void bcm_sysport_resume_from_wol(struct bcm_sysport_priv *priv)
{
u32 reg;
- /* Stop monitoring MPD interrupt */
- intrl2_0_mask_set(priv, INTRL2_0_MPD | INTRL2_0_BRCM_MATCH_TAG);
-
/* Disable RXCHK, active filters and Broadcom tag matching */
reg = rxchk_readl(priv, RXCHK_CONTROL);
reg &= ~(RXCHK_BRCM_TAG_MATCH_MASK <<
@@ -1081,6 +1079,17 @@ static void bcm_sysport_resume_from_wol(struct bcm_sysport_priv *priv)
/* Clear the MagicPacket detection logic */
mpd_enable_set(priv, false);
+ reg = intrl2_0_readl(priv, INTRL2_CPU_STATUS);
+ if (reg & INTRL2_0_MPD)
+ netdev_info(priv->netdev, "Wake-on-LAN (MPD) interrupt!\n");
+
+ if (reg & INTRL2_0_BRCM_MATCH_TAG) {
+ reg = rxchk_readl(priv, RXCHK_BRCM_TAG_MATCH_STATUS) &
+ RXCHK_BRCM_TAG_MATCH_MASK;
+ netdev_info(priv->netdev,
+ "Wake-on-LAN (filters 0x%02x) interrupt!\n", reg);
+ }
+
netif_dbg(priv, wol, priv->netdev, "resumed from WOL\n");
}
@@ -1105,7 +1114,6 @@ static irqreturn_t bcm_sysport_rx_isr(int irq, void *dev_id)
struct bcm_sysport_priv *priv = netdev_priv(dev);
struct bcm_sysport_tx_ring *txr;
unsigned int ring, ring_bit;
- u32 reg;
priv->irq0_stat = intrl2_0_readl(priv, INTRL2_CPU_STATUS) &
~intrl2_0_readl(priv, INTRL2_CPU_MASK_STATUS);
@@ -1131,16 +1139,6 @@ static irqreturn_t bcm_sysport_rx_isr(int irq, void *dev_id)
if (priv->irq0_stat & INTRL2_0_TX_RING_FULL)
bcm_sysport_tx_reclaim_all(priv);
- if (priv->irq0_stat & INTRL2_0_MPD)
- netdev_info(priv->netdev, "Wake-on-LAN (MPD) interrupt!\n");
-
- if (priv->irq0_stat & INTRL2_0_BRCM_MATCH_TAG) {
- reg = rxchk_readl(priv, RXCHK_BRCM_TAG_MATCH_STATUS) &
- RXCHK_BRCM_TAG_MATCH_MASK;
- netdev_info(priv->netdev,
- "Wake-on-LAN (filters 0x%02x) interrupt!\n", reg);
- }
-
if (!priv->is_lite)
goto out;
@@ -1221,6 +1219,7 @@ static void bcm_sysport_poll_controller(struct net_device *dev)
static struct sk_buff *bcm_sysport_insert_tsb(struct sk_buff *skb,
struct net_device *dev)
{
+ struct bcm_sysport_priv *priv = netdev_priv(dev);
struct sk_buff *nskb;
struct bcm_tsb *tsb;
u32 csum_info;
@@ -1231,13 +1230,16 @@ static struct sk_buff *bcm_sysport_insert_tsb(struct sk_buff *skb,
/* Re-allocate SKB if needed */
if (unlikely(skb_headroom(skb) < sizeof(*tsb))) {
nskb = skb_realloc_headroom(skb, sizeof(*tsb));
- dev_kfree_skb(skb);
if (!nskb) {
+ dev_kfree_skb_any(skb);
+ priv->mib.tx_realloc_tsb_failed++;
dev->stats.tx_errors++;
dev->stats.tx_dropped++;
return NULL;
}
+ dev_consume_skb_any(skb);
skb = nskb;
+ priv->mib.tx_realloc_tsb++;
}
tsb = skb_push(skb, sizeof(*tsb));
@@ -1900,9 +1902,6 @@ static void bcm_sysport_netif_start(struct net_device *dev)
intrl2_1_mask_clear(priv, 0xffffffff);
else
intrl2_0_mask_clear(priv, INTRL2_0_TDMA_MBDONE_MASK);
-
- /* Last call before we start the real business */
- netif_tx_start_all_queues(dev);
}
static void rbuf_init(struct bcm_sysport_priv *priv)
@@ -1973,16 +1972,14 @@ static int bcm_sysport_open(struct net_device *dev)
else
gib_set_pad_extension(priv);
+ /* Apply features again in case we changed them while interface was
+ * down
+ */
+ bcm_sysport_set_features(dev, dev->features);
+
/* Set MAC address */
umac_set_hw_addr(priv, dev->dev_addr);
- /* Read CRC forward */
- if (!priv->is_lite)
- priv->crc_fwd = !!(umac_readl(priv, UMAC_CMD) & CMD_CRC_FWD);
- else
- priv->crc_fwd = !((gib_readl(priv, GIB_CONTROL) &
- GIB_FCS_STRIP) >> GIB_FCS_STRIP_SHIFT);
-
phydev = of_phy_connect(dev, priv->phy_dn, bcm_sysport_adj_link,
0, priv->phy_interface);
if (!phydev) {
@@ -2048,6 +2045,8 @@ static int bcm_sysport_open(struct net_device *dev)
bcm_sysport_netif_start(dev);
+ netif_tx_start_all_queues(dev);
+
return 0;
out_clear_rx_int:
@@ -2071,7 +2070,7 @@ static void bcm_sysport_netif_stop(struct net_device *dev)
struct bcm_sysport_priv *priv = netdev_priv(dev);
/* stop all software from updating hardware */
- netif_tx_stop_all_queues(dev);
+ netif_tx_disable(dev);
napi_disable(&priv->napi);
cancel_work_sync(&priv->dim.dim.work);
phy_stop(dev->phydev);
@@ -2511,9 +2510,10 @@ static int bcm_sysport_probe(struct platform_device *pdev)
dev->netdev_ops = &bcm_sysport_netdev_ops;
netif_napi_add(dev, &priv->napi, bcm_sysport_poll, 64);
- /* HW supported features, none enabled by default */
- dev->hw_features |= NETIF_F_RXCSUM | NETIF_F_HIGHDMA |
- NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
+ dev->features |= NETIF_F_RXCSUM | NETIF_F_HIGHDMA |
+ NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
+ dev->hw_features |= dev->features;
+ dev->vlan_features |= dev->features;
/* Request the WOL interrupt and advertise suspend if available */
priv->wol_irq_disabled = 1;
@@ -2641,9 +2641,6 @@ static int bcm_sysport_suspend_to_wol(struct bcm_sysport_priv *priv)
/* UniMAC receive needs to be turned on */
umac_enable_set(priv, CMD_RX_EN, 1);
- /* Enable the interrupt wake-up source */
- intrl2_0_mask_clear(priv, INTRL2_0_MPD | INTRL2_0_BRCM_MATCH_TAG);
-
netif_dbg(priv, wol, ndev, "entered WOL mode\n");
return 0;
@@ -2660,12 +2657,12 @@ static int __maybe_unused bcm_sysport_suspend(struct device *d)
if (!netif_running(dev))
return 0;
+ netif_device_detach(dev);
+
bcm_sysport_netif_stop(dev);
phy_suspend(dev->phydev);
- netif_device_detach(dev);
-
/* Disable UniMAC RX */
umac_enable_set(priv, CMD_RX_EN, 0);
@@ -2716,7 +2713,6 @@ static int __maybe_unused bcm_sysport_resume(struct device *d)
struct net_device *dev = dev_get_drvdata(d);
struct bcm_sysport_priv *priv = netdev_priv(dev);
unsigned int i;
- u32 reg;
int ret;
if (!netif_running(dev))
@@ -2749,8 +2745,6 @@ static int __maybe_unused bcm_sysport_resume(struct device *d)
goto out_free_rx_ring;
}
- netif_device_attach(dev);
-
/* RX pipe enable */
topctrl_writel(priv, 0, RX_FLUSH_CNTL);
@@ -2760,12 +2754,8 @@ static int __maybe_unused bcm_sysport_resume(struct device *d)
goto out_free_rx_ring;
}
- /* Enable rxhck */
- if (priv->rx_chk_en) {
- reg = rxchk_readl(priv, RXCHK_CONTROL);
- reg |= RXCHK_EN;
- rxchk_writel(priv, reg, RXCHK_CONTROL);
- }
+ /* Restore enabled features */
+ bcm_sysport_set_features(dev, dev->features);
rbuf_init(priv);
@@ -2795,6 +2785,8 @@ static int __maybe_unused bcm_sysport_resume(struct device *d)
bcm_sysport_netif_start(dev);
+ netif_device_attach(dev);
+
return 0;
out_free_rx_ring:
diff --git a/drivers/net/ethernet/broadcom/bcmsysport.h b/drivers/net/ethernet/broadcom/bcmsysport.h
index 046c6c1d97fd..a7a230884a87 100644
--- a/drivers/net/ethernet/broadcom/bcmsysport.h
+++ b/drivers/net/ethernet/broadcom/bcmsysport.h
@@ -607,6 +607,8 @@ struct bcm_sysport_mib {
u32 alloc_rx_buff_failed;
u32 rx_dma_failed;
u32 tx_dma_failed;
+ u32 tx_realloc_tsb;
+ u32 tx_realloc_tsb_failed;
};
/* HW maintains a large list of counters */
diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c
index 4c94d9218bba..cabc8e49ad24 100644
--- a/drivers/net/ethernet/broadcom/bgmac.c
+++ b/drivers/net/ethernet/broadcom/bgmac.c
@@ -616,7 +616,6 @@ static int bgmac_dma_alloc(struct bgmac *bgmac)
static const u16 ring_base[] = { BGMAC_DMA_BASE0, BGMAC_DMA_BASE1,
BGMAC_DMA_BASE2, BGMAC_DMA_BASE3, };
int size; /* ring size: different for Tx and Rx */
- int err;
int i;
BUILD_BUG_ON(BGMAC_MAX_TX_RINGS > ARRAY_SIZE(ring_base));
@@ -666,7 +665,6 @@ static int bgmac_dma_alloc(struct bgmac *bgmac)
if (!ring->cpu_base) {
dev_err(bgmac->dev, "Allocation of RX ring 0x%X failed\n",
ring->mmio_base);
- err = -ENOMEM;
goto err_dma_free;
}
diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c
index 122fdb80a789..bbb247116045 100644
--- a/drivers/net/ethernet/broadcom/bnx2.c
+++ b/drivers/net/ethernet/broadcom/bnx2.c
@@ -8793,13 +8793,6 @@ static pci_ers_result_t bnx2_io_slot_reset(struct pci_dev *pdev)
if (!(bp->flags & BNX2_FLAG_AER_ENABLED))
return result;
- err = pci_cleanup_aer_uncorrect_error_status(pdev);
- if (err) {
- dev_err(&pdev->dev,
- "pci_cleanup_aer_uncorrect_error_status failed 0x%0x\n",
- err); /* non-fatal, continue */
- }
-
return result;
}
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
index 5a727d4729da..686899d7e555 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -27,7 +27,6 @@
#include <net/tcp.h>
#include <net/ipv6.h>
#include <net/ip6_checksum.h>
-#include <net/busy_poll.h>
#include <linux/prefetch.h>
#include "bnx2x_cmn.h"
#include "bnx2x_init.h"
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
index 0e508e5defce..142bc11b9fbb 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
@@ -494,6 +494,7 @@ int bnx2x_get_vf_config(struct net_device *dev, int vf,
int bnx2x_set_vf_mac(struct net_device *dev, int queue, u8 *mac);
int bnx2x_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos,
__be16 vlan_proto);
+int bnx2x_set_vf_spoofchk(struct net_device *dev, int idx, bool val);
/* select_queue callback */
u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb,
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index fcc2328bb0d9..95309b27c7d1 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -3536,6 +3536,16 @@ static void bnx2x_drv_info_iscsi_stat(struct bnx2x *bp)
*/
static void bnx2x_config_mf_bw(struct bnx2x *bp)
{
+ /* Workaround for MFW bug.
+ * MFW is not supposed to generate BW attention in
+ * single function mode.
+ */
+ if (!IS_MF(bp)) {
+ DP(BNX2X_MSG_MCP,
+ "Ignoring MF BW config in single function mode\n");
+ return;
+ }
+
if (bp->link_vars.link_up) {
bnx2x_cmng_fns_init(bp, true, CMNG_FNS_MINMAX);
bnx2x_link_sync_notify(bp);
@@ -13105,6 +13115,7 @@ static const struct net_device_ops bnx2x_netdev_ops = {
.ndo_set_vf_mac = bnx2x_set_vf_mac,
.ndo_set_vf_vlan = bnx2x_set_vf_vlan,
.ndo_get_vf_config = bnx2x_get_vf_config,
+ .ndo_set_vf_spoofchk = bnx2x_set_vf_spoofchk,
#endif
#ifdef NETDEV_FCOE_WWNN
.ndo_fcoe_get_wwn = bnx2x_fcoe_get_wwn,
@@ -14369,14 +14380,6 @@ static pci_ers_result_t bnx2x_io_slot_reset(struct pci_dev *pdev)
rtnl_unlock();
- /* If AER, perform cleanup of the PCIe registers */
- if (bp->flags & AER_ENABLED) {
- if (pci_cleanup_aer_uncorrect_error_status(pdev))
- BNX2X_ERR("pci_cleanup_aer_uncorrect_error_status failed\n");
- else
- DP(NETIF_MSG_HW, "pci_cleanup_aer_uncorrect_error_status succeeded\n");
- }
-
return PCI_ERS_RESULT_RECOVERED;
}
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
index 62da46537734..c835f6c7ecd0 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
@@ -209,7 +209,10 @@ void bnx2x_vfop_qctor_prep(struct bnx2x *bp,
*/
__set_bit(BNX2X_Q_FLG_TX_SWITCH, &setup_p->flags);
__set_bit(BNX2X_Q_FLG_TX_SEC, &setup_p->flags);
- __set_bit(BNX2X_Q_FLG_ANTI_SPOOF, &setup_p->flags);
+ if (vf->spoofchk)
+ __set_bit(BNX2X_Q_FLG_ANTI_SPOOF, &setup_p->flags);
+ else
+ __clear_bit(BNX2X_Q_FLG_ANTI_SPOOF, &setup_p->flags);
/* Setup-op rx parameters */
if (test_bit(BNX2X_Q_TYPE_HAS_RX, &q_type)) {
@@ -1269,6 +1272,8 @@ int bnx2x_iov_init_one(struct bnx2x *bp, int int_mode_param,
bnx2x_vf(bp, i, state) = VF_FREE;
mutex_init(&bnx2x_vf(bp, i, op_mutex));
bnx2x_vf(bp, i, op_current) = CHANNEL_TLV_NONE;
+ /* enable spoofchk by default */
+ bnx2x_vf(bp, i, spoofchk) = 1;
}
/* re-read the IGU CAM for VFs - index and abs_vfid must be set */
@@ -2632,7 +2637,8 @@ int bnx2x_get_vf_config(struct net_device *dev, int vfidx,
ivi->qos = 0;
ivi->max_tx_rate = 10000; /* always 10G. TBA take from link struct */
ivi->min_tx_rate = 0;
- ivi->spoofchk = 1; /*always enabled */
+ ivi->spoofchk = vf->spoofchk ? 1 : 0;
+ ivi->linkstate = vf->link_cfg;
if (vf->state == VF_ENABLED) {
/* mac and vlan are in vlan_mac objects */
if (bnx2x_validate_vf_sp_objs(bp, vf, false)) {
@@ -2950,6 +2956,77 @@ out:
return rc;
}
+int bnx2x_set_vf_spoofchk(struct net_device *dev, int idx, bool val)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ struct bnx2x_virtf *vf;
+ int i, rc = 0;
+
+ vf = BP_VF(bp, idx);
+ if (!vf)
+ return -EINVAL;
+
+ /* nothing to do */
+ if (vf->spoofchk == val)
+ return 0;
+
+ vf->spoofchk = val ? 1 : 0;
+
+ DP(BNX2X_MSG_IOV, "%s spoofchk for VF %d\n",
+ val ? "enabling" : "disabling", idx);
+
+ /* is vf initialized and queue set up? */
+ if (vf->state != VF_ENABLED ||
+ bnx2x_get_q_logical_state(bp, &bnx2x_leading_vfq(vf, sp_obj)) !=
+ BNX2X_Q_LOGICAL_STATE_ACTIVE)
+ return rc;
+
+ /* User should be able to see error in system logs */
+ if (!bnx2x_validate_vf_sp_objs(bp, vf, true))
+ return -EINVAL;
+
+ /* send queue update ramrods to configure spoofchk */
+ for_each_vfq(vf, i) {
+ struct bnx2x_queue_state_params q_params = {NULL};
+ struct bnx2x_queue_update_params *update_params;
+
+ q_params.q_obj = &bnx2x_vfq(vf, i, sp_obj);
+
+ /* validate the Q is UP */
+ if (bnx2x_get_q_logical_state(bp, q_params.q_obj) !=
+ BNX2X_Q_LOGICAL_STATE_ACTIVE)
+ continue;
+
+ __set_bit(RAMROD_COMP_WAIT, &q_params.ramrod_flags);
+ q_params.cmd = BNX2X_Q_CMD_UPDATE;
+ update_params = &q_params.params.update;
+ __set_bit(BNX2X_Q_UPDATE_ANTI_SPOOF_CHNG,
+ &update_params->update_flags);
+ if (val) {
+ __set_bit(BNX2X_Q_UPDATE_ANTI_SPOOF,
+ &update_params->update_flags);
+ } else {
+ __clear_bit(BNX2X_Q_UPDATE_ANTI_SPOOF,
+ &update_params->update_flags);
+ }
+
+ /* Update the Queue state */
+ rc = bnx2x_queue_state_change(bp, &q_params);
+ if (rc) {
+ BNX2X_ERR("Failed to %s spoofchk on VF %d - vfq %d\n",
+ val ? "enable" : "disable", idx, i);
+ goto out;
+ }
+ }
+out:
+ if (!rc)
+ DP(BNX2X_MSG_IOV,
+ "%s spoofchk for VF[%d]\n", val ? "Enabled" : "Disabled",
+ idx);
+
+ return rc;
+}
+
/* crc is the first field in the bulletin board. Compute the crc over the
* entire bulletin board excluding the crc field itself. Use the length field
* as the Bulletin Board was posted by a PF with possibly a different version
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
index eb814c65152f..b6ebd92ec565 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
@@ -142,6 +142,8 @@ struct bnx2x_virtf {
bool flr_clnup_stage; /* true during flr cleanup */
bool malicious; /* true if FW indicated so, until FLR */
+ /* 1(true) if spoof check is enabled */
+ u8 spoofchk;
/* dma */
dma_addr_t fw_stat_map;
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index 61957b0bbd8c..dd85d790f638 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -111,6 +111,7 @@ enum board_idx {
BCM57452,
BCM57454,
BCM5745x_NPAR,
+ BCM57508,
BCM58802,
BCM58804,
BCM58808,
@@ -152,6 +153,7 @@ static const struct {
[BCM57452] = { "Broadcom BCM57452 NetXtreme-E 10Gb/25Gb/40Gb/50Gb Ethernet" },
[BCM57454] = { "Broadcom BCM57454 NetXtreme-E 10Gb/25Gb/40Gb/50Gb/100Gb Ethernet" },
[BCM5745x_NPAR] = { "Broadcom BCM5745x NetXtreme-E Ethernet Partition" },
+ [BCM57508] = { "Broadcom BCM57508 NetXtreme-E 10Gb/25Gb/50Gb/100Gb/200Gb Ethernet" },
[BCM58802] = { "Broadcom BCM58802 NetXtreme-S 10Gb/25Gb/40Gb/50Gb Ethernet" },
[BCM58804] = { "Broadcom BCM58804 NetXtreme-S 10Gb/25Gb/40Gb/50Gb/100Gb Ethernet" },
[BCM58808] = { "Broadcom BCM58808 NetXtreme-S 10Gb/25Gb/40Gb/50Gb/100Gb Ethernet" },
@@ -196,6 +198,7 @@ static const struct pci_device_id bnxt_pci_tbl[] = {
{ PCI_VDEVICE(BROADCOM, 0x16ef), .driver_data = BCM57416_NPAR },
{ PCI_VDEVICE(BROADCOM, 0x16f0), .driver_data = BCM58808 },
{ PCI_VDEVICE(BROADCOM, 0x16f1), .driver_data = BCM57452 },
+ { PCI_VDEVICE(BROADCOM, 0x1750), .driver_data = BCM57508 },
{ PCI_VDEVICE(BROADCOM, 0xd802), .driver_data = BCM58802 },
{ PCI_VDEVICE(BROADCOM, 0xd804), .driver_data = BCM58804 },
#ifdef CONFIG_BNXT_SRIOV
@@ -241,15 +244,46 @@ static bool bnxt_vf_pciid(enum board_idx idx)
#define DB_CP_FLAGS (DB_KEY_CP | DB_IDX_VALID | DB_IRQ_DIS)
#define DB_CP_IRQ_DIS_FLAGS (DB_KEY_CP | DB_IRQ_DIS)
-#define BNXT_CP_DB_REARM(db, raw_cons) \
- writel(DB_CP_REARM_FLAGS | RING_CMP(raw_cons), db)
-
-#define BNXT_CP_DB(db, raw_cons) \
- writel(DB_CP_FLAGS | RING_CMP(raw_cons), db)
-
#define BNXT_CP_DB_IRQ_DIS(db) \
writel(DB_CP_IRQ_DIS_FLAGS, db)
+#define BNXT_DB_CQ(db, idx) \
+ writel(DB_CP_FLAGS | RING_CMP(idx), (db)->doorbell)
+
+#define BNXT_DB_NQ_P5(db, idx) \
+ writeq((db)->db_key64 | DBR_TYPE_NQ | RING_CMP(idx), (db)->doorbell)
+
+#define BNXT_DB_CQ_ARM(db, idx) \
+ writel(DB_CP_REARM_FLAGS | RING_CMP(idx), (db)->doorbell)
+
+#define BNXT_DB_NQ_ARM_P5(db, idx) \
+ writeq((db)->db_key64 | DBR_TYPE_NQ_ARM | RING_CMP(idx), (db)->doorbell)
+
+static void bnxt_db_nq(struct bnxt *bp, struct bnxt_db_info *db, u32 idx)
+{
+ if (bp->flags & BNXT_FLAG_CHIP_P5)
+ BNXT_DB_NQ_P5(db, idx);
+ else
+ BNXT_DB_CQ(db, idx);
+}
+
+static void bnxt_db_nq_arm(struct bnxt *bp, struct bnxt_db_info *db, u32 idx)
+{
+ if (bp->flags & BNXT_FLAG_CHIP_P5)
+ BNXT_DB_NQ_ARM_P5(db, idx);
+ else
+ BNXT_DB_CQ_ARM(db, idx);
+}
+
+static void bnxt_db_cq(struct bnxt *bp, struct bnxt_db_info *db, u32 idx)
+{
+ if (bp->flags & BNXT_FLAG_CHIP_P5)
+ writeq(db->db_key64 | DBR_TYPE_CQ_ARMALL | RING_CMP(idx),
+ db->doorbell);
+ else
+ BNXT_DB_CQ(db, idx);
+}
+
const u16 bnxt_lhint_arr[] = {
TX_BD_FLAGS_LHINT_512_AND_SMALLER,
TX_BD_FLAGS_LHINT_512_TO_1023,
@@ -341,6 +375,7 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)
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;
+ void __iomem *db = txr->tx_db.doorbell;
void *pdata = tx_push_buf->data;
u64 *end;
int j, push_len;
@@ -398,12 +433,11 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)
push_len = (length + sizeof(*tx_push) + 7) / 8;
if (push_len > 16) {
- __iowrite64_copy(txr->tx_doorbell, tx_push_buf, 16);
- __iowrite32_copy(txr->tx_doorbell + 4, tx_push_buf + 1,
+ __iowrite64_copy(db, tx_push_buf, 16);
+ __iowrite32_copy(db + 4, tx_push_buf + 1,
(push_len - 16) << 1);
} else {
- __iowrite64_copy(txr->tx_doorbell, tx_push_buf,
- push_len);
+ __iowrite64_copy(db, tx_push_buf, push_len);
}
goto tx_done;
@@ -505,7 +539,7 @@ normal_tx:
txr->tx_prod = prod;
if (!skb->xmit_more || netif_xmit_stopped(txq))
- bnxt_db_write(bp, txr->tx_doorbell, DB_KEY_TX | prod);
+ bnxt_db_write(bp, &txr->tx_db, prod);
tx_done:
@@ -513,7 +547,7 @@ tx_done:
if (unlikely(bnxt_tx_avail(bp, txr) <= MAX_SKB_FRAGS + 1)) {
if (skb->xmit_more && !tx_buf->is_push)
- bnxt_db_write(bp, txr->tx_doorbell, DB_KEY_TX | prod);
+ bnxt_db_write(bp, &txr->tx_db, prod);
netif_tx_stop_queue(txq);
@@ -776,11 +810,11 @@ static inline int bnxt_alloc_rx_page(struct bnxt *bp,
return 0;
}
-static void bnxt_reuse_rx_agg_bufs(struct bnxt_napi *bnapi, u16 cp_cons,
+static void bnxt_reuse_rx_agg_bufs(struct bnxt_cp_ring_info *cpr, u16 cp_cons,
u32 agg_bufs)
{
+ struct bnxt_napi *bnapi = cpr->bnapi;
struct bnxt *bp = bnapi->bp;
- struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
struct bnxt_rx_ring_info *rxr = bnapi->rx_ring;
u16 prod = rxr->rx_agg_prod;
u16 sw_prod = rxr->rx_sw_agg_prod;
@@ -903,12 +937,13 @@ static struct sk_buff *bnxt_rx_skb(struct bnxt *bp,
return skb;
}
-static struct sk_buff *bnxt_rx_pages(struct bnxt *bp, struct bnxt_napi *bnapi,
+static struct sk_buff *bnxt_rx_pages(struct bnxt *bp,
+ struct bnxt_cp_ring_info *cpr,
struct sk_buff *skb, u16 cp_cons,
u32 agg_bufs)
{
+ struct bnxt_napi *bnapi = cpr->bnapi;
struct pci_dev *pdev = bp->pdev;
- struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
struct bnxt_rx_ring_info *rxr = bnapi->rx_ring;
u16 prod = rxr->rx_agg_prod;
u32 i;
@@ -955,7 +990,7 @@ static struct sk_buff *bnxt_rx_pages(struct bnxt *bp, struct bnxt_napi *bnapi,
* allocated already.
*/
rxr->rx_agg_prod = prod;
- bnxt_reuse_rx_agg_bufs(bnapi, cp_cons, agg_bufs - i);
+ bnxt_reuse_rx_agg_bufs(cpr, cp_cons, agg_bufs - i);
return NULL;
}
@@ -1012,10 +1047,9 @@ static inline struct sk_buff *bnxt_copy_skb(struct bnxt_napi *bnapi, u8 *data,
return skb;
}
-static int bnxt_discard_rx(struct bnxt *bp, struct bnxt_napi *bnapi,
+static int bnxt_discard_rx(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
u32 *raw_cons, void *cmp)
{
- struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
struct rx_cmp *rxcmp = cmp;
u32 tmp_raw_cons = *raw_cons;
u8 cmp_type, agg_bufs = 0;
@@ -1141,11 +1175,11 @@ static void bnxt_tpa_start(struct bnxt *bp, struct bnxt_rx_ring_info *rxr,
cons_rx_buf->data = NULL;
}
-static void bnxt_abort_tpa(struct bnxt *bp, struct bnxt_napi *bnapi,
- u16 cp_cons, u32 agg_bufs)
+static void bnxt_abort_tpa(struct bnxt_cp_ring_info *cpr, u16 cp_cons,
+ u32 agg_bufs)
{
if (agg_bufs)
- bnxt_reuse_rx_agg_bufs(bnapi, cp_cons, agg_bufs);
+ bnxt_reuse_rx_agg_bufs(cpr, cp_cons, agg_bufs);
}
static struct sk_buff *bnxt_gro_func_5731x(struct bnxt_tpa_info *tpa_info,
@@ -1339,13 +1373,13 @@ static struct net_device *bnxt_get_pkt_dev(struct bnxt *bp, u16 cfa_code)
}
static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp,
- struct bnxt_napi *bnapi,
+ struct bnxt_cp_ring_info *cpr,
u32 *raw_cons,
struct rx_tpa_end_cmp *tpa_end,
struct rx_tpa_end_cmp_ext *tpa_end1,
u8 *event)
{
- struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
+ struct bnxt_napi *bnapi = cpr->bnapi;
struct bnxt_rx_ring_info *rxr = bnapi->rx_ring;
u8 agg_id = TPA_END_AGG_ID(tpa_end);
u8 *data_ptr, agg_bufs;
@@ -1357,7 +1391,7 @@ static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp,
void *data;
if (unlikely(bnapi->in_reset)) {
- int rc = bnxt_discard_rx(bp, bnapi, raw_cons, tpa_end);
+ int rc = bnxt_discard_rx(bp, cpr, raw_cons, tpa_end);
if (rc < 0)
return ERR_PTR(-EBUSY);
@@ -1383,7 +1417,7 @@ static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp,
}
if (unlikely(agg_bufs > MAX_SKB_FRAGS || TPA_END_ERRORS(tpa_end1))) {
- bnxt_abort_tpa(bp, bnapi, cp_cons, agg_bufs);
+ bnxt_abort_tpa(cpr, cp_cons, agg_bufs);
if (agg_bufs > MAX_SKB_FRAGS)
netdev_warn(bp->dev, "TPA frags %d exceeded MAX_SKB_FRAGS %d\n",
agg_bufs, (int)MAX_SKB_FRAGS);
@@ -1393,7 +1427,7 @@ static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp,
if (len <= bp->rx_copy_thresh) {
skb = bnxt_copy_skb(bnapi, data_ptr, len, mapping);
if (!skb) {
- bnxt_abort_tpa(bp, bnapi, cp_cons, agg_bufs);
+ bnxt_abort_tpa(cpr, cp_cons, agg_bufs);
return NULL;
}
} else {
@@ -1402,7 +1436,7 @@ static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp,
new_data = __bnxt_alloc_rx_data(bp, &new_mapping, GFP_ATOMIC);
if (!new_data) {
- bnxt_abort_tpa(bp, bnapi, cp_cons, agg_bufs);
+ bnxt_abort_tpa(cpr, cp_cons, agg_bufs);
return NULL;
}
@@ -1417,7 +1451,7 @@ static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp,
if (!skb) {
kfree(data);
- bnxt_abort_tpa(bp, bnapi, cp_cons, agg_bufs);
+ bnxt_abort_tpa(cpr, cp_cons, agg_bufs);
return NULL;
}
skb_reserve(skb, bp->rx_offset);
@@ -1425,7 +1459,7 @@ static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp,
}
if (agg_bufs) {
- skb = bnxt_rx_pages(bp, bnapi, skb, cp_cons, agg_bufs);
+ skb = bnxt_rx_pages(bp, cpr, skb, cp_cons, agg_bufs);
if (!skb) {
/* Page reuse already handled by bnxt_rx_pages(). */
return NULL;
@@ -1479,10 +1513,10 @@ static void bnxt_deliver_skb(struct bnxt *bp, struct bnxt_napi *bnapi,
* -ENOMEM - packet aborted due to out of memory
* -EIO - packet aborted due to hw error indicated in BD
*/
-static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_napi *bnapi, u32 *raw_cons,
- u8 *event)
+static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
+ u32 *raw_cons, u8 *event)
{
- struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
+ struct bnxt_napi *bnapi = cpr->bnapi;
struct bnxt_rx_ring_info *rxr = bnapi->rx_ring;
struct net_device *dev = bp->dev;
struct rx_cmp *rxcmp;
@@ -1521,7 +1555,7 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_napi *bnapi, u32 *raw_cons,
goto next_rx_no_prod_no_len;
} else if (cmp_type == CMP_TYPE_RX_L2_TPA_END_CMP) {
- skb = bnxt_tpa_end(bp, bnapi, &tmp_raw_cons,
+ skb = bnxt_tpa_end(bp, cpr, &tmp_raw_cons,
(struct rx_tpa_end_cmp *)rxcmp,
(struct rx_tpa_end_cmp_ext *)rxcmp1, event);
@@ -1542,7 +1576,7 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_napi *bnapi, u32 *raw_cons,
data = rx_buf->data;
data_ptr = rx_buf->data_ptr;
if (unlikely(cons != rxr->rx_next_cons)) {
- int rc1 = bnxt_discard_rx(bp, bnapi, raw_cons, rxcmp);
+ int rc1 = bnxt_discard_rx(bp, cpr, raw_cons, rxcmp);
bnxt_sched_reset(bp, rxr);
return rc1;
@@ -1565,7 +1599,7 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_napi *bnapi, u32 *raw_cons,
if (rxcmp1->rx_cmp_cfa_code_errors_v2 & RX_CMP_L2_ERRORS) {
bnxt_reuse_rx_data(rxr, cons, data);
if (agg_bufs)
- bnxt_reuse_rx_agg_bufs(bnapi, cp_cons, agg_bufs);
+ bnxt_reuse_rx_agg_bufs(cpr, cp_cons, agg_bufs);
rc = -EIO;
goto next_rx;
@@ -1602,7 +1636,7 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_napi *bnapi, u32 *raw_cons,
}
if (agg_bufs) {
- skb = bnxt_rx_pages(bp, bnapi, skb, cp_cons, agg_bufs);
+ skb = bnxt_rx_pages(bp, cpr, skb, cp_cons, agg_bufs);
if (!skb) {
rc = -ENOMEM;
goto next_rx;
@@ -1664,10 +1698,10 @@ next_rx_no_prod_no_len:
/* In netpoll mode, if we are using a combined completion ring, we need to
* discard the rx packets and recycle the buffers.
*/
-static int bnxt_force_rx_discard(struct bnxt *bp, struct bnxt_napi *bnapi,
+static int bnxt_force_rx_discard(struct bnxt *bp,
+ struct bnxt_cp_ring_info *cpr,
u32 *raw_cons, u8 *event)
{
- struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
u32 tmp_raw_cons = *raw_cons;
struct rx_cmp_ext *rxcmp1;
struct rx_cmp *rxcmp;
@@ -1697,7 +1731,7 @@ static int bnxt_force_rx_discard(struct bnxt *bp, struct bnxt_napi *bnapi,
tpa_end1->rx_tpa_end_cmp_errors_v2 |=
cpu_to_le32(RX_TPA_END_CMP_ERRORS);
}
- return bnxt_rx_pkt(bp, bnapi, raw_cons, event);
+ return bnxt_rx_pkt(bp, cpr, raw_cons, event);
}
#define BNXT_GET_EVENT_PORT(data) \
@@ -1848,7 +1882,7 @@ static irqreturn_t bnxt_inta(int irq, void *dev_instance)
}
/* disable ring IRQ */
- BNXT_CP_DB_IRQ_DIS(cpr->cp_doorbell);
+ BNXT_CP_DB_IRQ_DIS(cpr->cp_db.doorbell);
/* Return here if interrupt is shared and is disabled. */
if (unlikely(atomic_read(&bp->intr_sem) != 0))
@@ -1858,9 +1892,10 @@ static irqreturn_t bnxt_inta(int irq, void *dev_instance)
return IRQ_HANDLED;
}
-static int bnxt_poll_work(struct bnxt *bp, struct bnxt_napi *bnapi, int budget)
+static int __bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
+ int budget)
{
- struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
+ struct bnxt_napi *bnapi = cpr->bnapi;
u32 raw_cons = cpr->cp_raw_cons;
u32 cons;
int tx_pkts = 0;
@@ -1868,6 +1903,7 @@ static int bnxt_poll_work(struct bnxt *bp, struct bnxt_napi *bnapi, int budget)
u8 event = 0;
struct tx_cmp *txcmp;
+ cpr->has_more_work = 0;
while (1) {
int rc;
@@ -1881,16 +1917,22 @@ static int bnxt_poll_work(struct bnxt *bp, struct bnxt_napi *bnapi, int budget)
* reading any further.
*/
dma_rmb();
+ cpr->had_work_done = 1;
if (TX_CMP_TYPE(txcmp) == CMP_TYPE_TX_L2_CMP) {
tx_pkts++;
/* return full budget so NAPI will complete. */
- if (unlikely(tx_pkts > bp->tx_wake_thresh))
+ if (unlikely(tx_pkts > bp->tx_wake_thresh)) {
rx_pkts = budget;
+ raw_cons = NEXT_RAW_CMP(raw_cons);
+ if (budget)
+ cpr->has_more_work = 1;
+ break;
+ }
} else if ((TX_CMP_TYPE(txcmp) & 0x30) == 0x10) {
if (likely(budget))
- rc = bnxt_rx_pkt(bp, bnapi, &raw_cons, &event);
+ rc = bnxt_rx_pkt(bp, cpr, &raw_cons, &event);
else
- rc = bnxt_force_rx_discard(bp, bnapi, &raw_cons,
+ rc = bnxt_force_rx_discard(bp, cpr, &raw_cons,
&event);
if (likely(rc >= 0))
rx_pkts += rc;
@@ -1913,39 +1955,60 @@ static int bnxt_poll_work(struct bnxt *bp, struct bnxt_napi *bnapi, int budget)
}
raw_cons = NEXT_RAW_CMP(raw_cons);
- if (rx_pkts == budget)
+ if (rx_pkts && rx_pkts == budget) {
+ cpr->has_more_work = 1;
break;
+ }
}
if (event & BNXT_TX_EVENT) {
struct bnxt_tx_ring_info *txr = bnapi->tx_ring;
- void __iomem *db = txr->tx_doorbell;
u16 prod = txr->tx_prod;
/* Sync BD data before updating doorbell */
wmb();
- bnxt_db_write_relaxed(bp, db, DB_KEY_TX | prod);
+ bnxt_db_write_relaxed(bp, &txr->tx_db, prod);
}
cpr->cp_raw_cons = raw_cons;
- /* ACK completion ring before freeing tx ring and producing new
- * buffers in rx/agg rings to prevent overflowing the completion
- * ring.
- */
- BNXT_CP_DB(cpr->cp_doorbell, cpr->cp_raw_cons);
+ bnapi->tx_pkts += tx_pkts;
+ bnapi->events |= event;
+ return rx_pkts;
+}
- if (tx_pkts)
- bnapi->tx_int(bp, bnapi, tx_pkts);
+static void __bnxt_poll_work_done(struct bnxt *bp, struct bnxt_napi *bnapi)
+{
+ if (bnapi->tx_pkts) {
+ bnapi->tx_int(bp, bnapi, bnapi->tx_pkts);
+ bnapi->tx_pkts = 0;
+ }
- if (event & BNXT_RX_EVENT) {
+ if (bnapi->events & BNXT_RX_EVENT) {
struct bnxt_rx_ring_info *rxr = bnapi->rx_ring;
- bnxt_db_write(bp, rxr->rx_doorbell, DB_KEY_RX | rxr->rx_prod);
- if (event & BNXT_AGG_EVENT)
- bnxt_db_write(bp, rxr->rx_agg_doorbell,
- DB_KEY_RX | rxr->rx_agg_prod);
+ bnxt_db_write(bp, &rxr->rx_db, rxr->rx_prod);
+ if (bnapi->events & BNXT_AGG_EVENT)
+ bnxt_db_write(bp, &rxr->rx_agg_db, rxr->rx_agg_prod);
}
+ bnapi->events = 0;
+}
+
+static int bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
+ int budget)
+{
+ struct bnxt_napi *bnapi = cpr->bnapi;
+ int rx_pkts;
+
+ rx_pkts = __bnxt_poll_work(bp, cpr, budget);
+
+ /* ACK completion ring before freeing tx ring and producing new
+ * buffers in rx/agg rings to prevent overflowing the completion
+ * ring.
+ */
+ bnxt_db_cq(bp, &cpr->cp_db, cpr->cp_raw_cons);
+
+ __bnxt_poll_work_done(bp, bnapi);
return rx_pkts;
}
@@ -1984,7 +2047,7 @@ static int bnxt_poll_nitroa0(struct napi_struct *napi, int budget)
rxcmp1->rx_cmp_cfa_code_errors_v2 |=
cpu_to_le32(RX_CMPL_ERRORS_CRC_ERROR);
- rc = bnxt_rx_pkt(bp, bnapi, &raw_cons, &event);
+ rc = bnxt_rx_pkt(bp, cpr, &raw_cons, &event);
if (likely(rc == -EIO) && budget)
rx_pkts++;
else if (rc == -EBUSY) /* partial completion */
@@ -2003,16 +2066,15 @@ static int bnxt_poll_nitroa0(struct napi_struct *napi, int budget)
}
cpr->cp_raw_cons = raw_cons;
- BNXT_CP_DB(cpr->cp_doorbell, cpr->cp_raw_cons);
- bnxt_db_write(bp, rxr->rx_doorbell, DB_KEY_RX | rxr->rx_prod);
+ BNXT_DB_CQ(&cpr->cp_db, cpr->cp_raw_cons);
+ bnxt_db_write(bp, &rxr->rx_db, rxr->rx_prod);
if (event & BNXT_AGG_EVENT)
- bnxt_db_write(bp, rxr->rx_agg_doorbell,
- DB_KEY_RX | rxr->rx_agg_prod);
+ bnxt_db_write(bp, &rxr->rx_agg_db, rxr->rx_agg_prod);
if (!bnxt_has_work(bp, cpr) && rx_pkts < budget) {
napi_complete_done(napi, rx_pkts);
- BNXT_CP_DB_REARM(cpr->cp_doorbell, cpr->cp_raw_cons);
+ BNXT_DB_CQ_ARM(&cpr->cp_db, cpr->cp_raw_cons);
}
return rx_pkts;
}
@@ -2025,15 +2087,17 @@ static int bnxt_poll(struct napi_struct *napi, int budget)
int work_done = 0;
while (1) {
- work_done += bnxt_poll_work(bp, bnapi, budget - work_done);
+ work_done += bnxt_poll_work(bp, cpr, budget - work_done);
- if (work_done >= budget)
+ if (work_done >= budget) {
+ if (!budget)
+ BNXT_DB_CQ_ARM(&cpr->cp_db, cpr->cp_raw_cons);
break;
+ }
if (!bnxt_has_work(bp, cpr)) {
if (napi_complete_done(napi, work_done))
- BNXT_CP_DB_REARM(cpr->cp_doorbell,
- cpr->cp_raw_cons);
+ BNXT_DB_CQ_ARM(&cpr->cp_db, cpr->cp_raw_cons);
break;
}
}
@@ -2050,6 +2114,104 @@ static int bnxt_poll(struct napi_struct *napi, int budget)
return work_done;
}
+static int __bnxt_poll_cqs(struct bnxt *bp, struct bnxt_napi *bnapi, int budget)
+{
+ struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
+ int i, work_done = 0;
+
+ for (i = 0; i < 2; i++) {
+ struct bnxt_cp_ring_info *cpr2 = cpr->cp_ring_arr[i];
+
+ if (cpr2) {
+ work_done += __bnxt_poll_work(bp, cpr2,
+ budget - work_done);
+ cpr->has_more_work |= cpr2->has_more_work;
+ }
+ }
+ return work_done;
+}
+
+static void __bnxt_poll_cqs_done(struct bnxt *bp, struct bnxt_napi *bnapi,
+ u64 dbr_type, bool all)
+{
+ struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ struct bnxt_cp_ring_info *cpr2 = cpr->cp_ring_arr[i];
+ struct bnxt_db_info *db;
+
+ if (cpr2 && (all || cpr2->had_work_done)) {
+ db = &cpr2->cp_db;
+ writeq(db->db_key64 | dbr_type |
+ RING_CMP(cpr2->cp_raw_cons), db->doorbell);
+ cpr2->had_work_done = 0;
+ }
+ }
+ __bnxt_poll_work_done(bp, bnapi);
+}
+
+static int bnxt_poll_p5(struct napi_struct *napi, int budget)
+{
+ struct bnxt_napi *bnapi = container_of(napi, struct bnxt_napi, napi);
+ struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
+ u32 raw_cons = cpr->cp_raw_cons;
+ struct bnxt *bp = bnapi->bp;
+ struct nqe_cn *nqcmp;
+ int work_done = 0;
+ u32 cons;
+
+ if (cpr->has_more_work) {
+ cpr->has_more_work = 0;
+ work_done = __bnxt_poll_cqs(bp, bnapi, budget);
+ if (cpr->has_more_work) {
+ __bnxt_poll_cqs_done(bp, bnapi, DBR_TYPE_CQ, false);
+ return work_done;
+ }
+ __bnxt_poll_cqs_done(bp, bnapi, DBR_TYPE_CQ_ARMALL, true);
+ if (napi_complete_done(napi, work_done))
+ BNXT_DB_NQ_ARM_P5(&cpr->cp_db, cpr->cp_raw_cons);
+ return work_done;
+ }
+ while (1) {
+ cons = RING_CMP(raw_cons);
+ nqcmp = &cpr->nq_desc_ring[CP_RING(cons)][CP_IDX(cons)];
+
+ if (!NQ_CMP_VALID(nqcmp, raw_cons)) {
+ __bnxt_poll_cqs_done(bp, bnapi, DBR_TYPE_CQ_ARMALL,
+ false);
+ cpr->cp_raw_cons = raw_cons;
+ if (napi_complete_done(napi, work_done))
+ BNXT_DB_NQ_ARM_P5(&cpr->cp_db,
+ cpr->cp_raw_cons);
+ return work_done;
+ }
+
+ /* The valid test of the entry must be done first before
+ * reading any further.
+ */
+ dma_rmb();
+
+ if (nqcmp->type == cpu_to_le16(NQ_CN_TYPE_CQ_NOTIFICATION)) {
+ u32 idx = le32_to_cpu(nqcmp->cq_handle_low);
+ struct bnxt_cp_ring_info *cpr2;
+
+ cpr2 = cpr->cp_ring_arr[idx];
+ work_done += __bnxt_poll_work(bp, cpr2,
+ budget - work_done);
+ cpr->has_more_work = cpr2->has_more_work;
+ } else {
+ bnxt_hwrm_handler(bp, (struct tx_cmp *)nqcmp);
+ }
+ raw_cons = NEXT_RAW_CMP(raw_cons);
+ if (cpr->has_more_work)
+ break;
+ }
+ __bnxt_poll_cqs_done(bp, bnapi, DBR_TYPE_CQ, true);
+ cpr->cp_raw_cons = raw_cons;
+ return work_done;
+}
+
static void bnxt_free_tx_skbs(struct bnxt *bp)
{
int i, max_idx;
@@ -2195,60 +2357,73 @@ static void bnxt_free_skbs(struct bnxt *bp)
bnxt_free_rx_skbs(bp);
}
-static void bnxt_free_ring(struct bnxt *bp, struct bnxt_ring_struct *ring)
+static void bnxt_free_ring(struct bnxt *bp, struct bnxt_ring_mem_info *rmem)
{
struct pci_dev *pdev = bp->pdev;
int i;
- for (i = 0; i < ring->nr_pages; i++) {
- if (!ring->pg_arr[i])
+ for (i = 0; i < rmem->nr_pages; i++) {
+ if (!rmem->pg_arr[i])
continue;
- dma_free_coherent(&pdev->dev, ring->page_size,
- ring->pg_arr[i], ring->dma_arr[i]);
+ dma_free_coherent(&pdev->dev, rmem->page_size,
+ rmem->pg_arr[i], rmem->dma_arr[i]);
- ring->pg_arr[i] = NULL;
+ rmem->pg_arr[i] = NULL;
}
- if (ring->pg_tbl) {
- dma_free_coherent(&pdev->dev, ring->nr_pages * 8,
- ring->pg_tbl, ring->pg_tbl_map);
- ring->pg_tbl = NULL;
+ if (rmem->pg_tbl) {
+ dma_free_coherent(&pdev->dev, rmem->nr_pages * 8,
+ rmem->pg_tbl, rmem->pg_tbl_map);
+ rmem->pg_tbl = NULL;
}
- if (ring->vmem_size && *ring->vmem) {
- vfree(*ring->vmem);
- *ring->vmem = NULL;
+ if (rmem->vmem_size && *rmem->vmem) {
+ vfree(*rmem->vmem);
+ *rmem->vmem = NULL;
}
}
-static int bnxt_alloc_ring(struct bnxt *bp, struct bnxt_ring_struct *ring)
+static int bnxt_alloc_ring(struct bnxt *bp, struct bnxt_ring_mem_info *rmem)
{
- int i;
struct pci_dev *pdev = bp->pdev;
+ u64 valid_bit = 0;
+ int i;
- if (ring->nr_pages > 1) {
- ring->pg_tbl = dma_alloc_coherent(&pdev->dev,
- ring->nr_pages * 8,
- &ring->pg_tbl_map,
+ if (rmem->flags & (BNXT_RMEM_VALID_PTE_FLAG | BNXT_RMEM_RING_PTE_FLAG))
+ valid_bit = PTU_PTE_VALID;
+ if (rmem->nr_pages > 1) {
+ rmem->pg_tbl = dma_alloc_coherent(&pdev->dev,
+ rmem->nr_pages * 8,
+ &rmem->pg_tbl_map,
GFP_KERNEL);
- if (!ring->pg_tbl)
+ if (!rmem->pg_tbl)
return -ENOMEM;
}
- for (i = 0; i < ring->nr_pages; i++) {
- ring->pg_arr[i] = dma_alloc_coherent(&pdev->dev,
- ring->page_size,
- &ring->dma_arr[i],
+ for (i = 0; i < rmem->nr_pages; i++) {
+ u64 extra_bits = valid_bit;
+
+ rmem->pg_arr[i] = dma_alloc_coherent(&pdev->dev,
+ rmem->page_size,
+ &rmem->dma_arr[i],
GFP_KERNEL);
- if (!ring->pg_arr[i])
+ if (!rmem->pg_arr[i])
return -ENOMEM;
- if (ring->nr_pages > 1)
- ring->pg_tbl[i] = cpu_to_le64(ring->dma_arr[i]);
+ if (rmem->nr_pages > 1) {
+ if (i == rmem->nr_pages - 2 &&
+ (rmem->flags & BNXT_RMEM_RING_PTE_FLAG))
+ extra_bits |= PTU_PTE_NEXT_TO_LAST;
+ else if (i == rmem->nr_pages - 1 &&
+ (rmem->flags & BNXT_RMEM_RING_PTE_FLAG))
+ extra_bits |= PTU_PTE_LAST;
+ rmem->pg_tbl[i] =
+ cpu_to_le64(rmem->dma_arr[i] | extra_bits);
+ }
}
- if (ring->vmem_size) {
- *ring->vmem = vzalloc(ring->vmem_size);
- if (!(*ring->vmem))
+ if (rmem->vmem_size) {
+ *rmem->vmem = vzalloc(rmem->vmem_size);
+ if (!(*rmem->vmem))
return -ENOMEM;
}
return 0;
@@ -2278,10 +2453,10 @@ static void bnxt_free_rx_rings(struct bnxt *bp)
rxr->rx_agg_bmap = NULL;
ring = &rxr->rx_ring_struct;
- bnxt_free_ring(bp, ring);
+ bnxt_free_ring(bp, &ring->ring_mem);
ring = &rxr->rx_agg_ring_struct;
- bnxt_free_ring(bp, ring);
+ bnxt_free_ring(bp, &ring->ring_mem);
}
}
@@ -2308,15 +2483,16 @@ static int bnxt_alloc_rx_rings(struct bnxt *bp)
if (rc < 0)
return rc;
- rc = bnxt_alloc_ring(bp, ring);
+ rc = bnxt_alloc_ring(bp, &ring->ring_mem);
if (rc)
return rc;
+ ring->grp_idx = i;
if (agg_rings) {
u16 mem_size;
ring = &rxr->rx_agg_ring_struct;
- rc = bnxt_alloc_ring(bp, ring);
+ rc = bnxt_alloc_ring(bp, &ring->ring_mem);
if (rc)
return rc;
@@ -2359,7 +2535,7 @@ static void bnxt_free_tx_rings(struct bnxt *bp)
ring = &txr->tx_ring_struct;
- bnxt_free_ring(bp, ring);
+ bnxt_free_ring(bp, &ring->ring_mem);
}
}
@@ -2390,7 +2566,7 @@ static int bnxt_alloc_tx_rings(struct bnxt *bp)
ring = &txr->tx_ring_struct;
- rc = bnxt_alloc_ring(bp, ring);
+ rc = bnxt_alloc_ring(bp, &ring->ring_mem);
if (rc)
return rc;
@@ -2436,6 +2612,7 @@ static void bnxt_free_cp_rings(struct bnxt *bp)
struct bnxt_napi *bnapi = bp->bnapi[i];
struct bnxt_cp_ring_info *cpr;
struct bnxt_ring_struct *ring;
+ int j;
if (!bnapi)
continue;
@@ -2443,12 +2620,51 @@ static void bnxt_free_cp_rings(struct bnxt *bp)
cpr = &bnapi->cp_ring;
ring = &cpr->cp_ring_struct;
- bnxt_free_ring(bp, ring);
+ bnxt_free_ring(bp, &ring->ring_mem);
+
+ for (j = 0; j < 2; j++) {
+ struct bnxt_cp_ring_info *cpr2 = cpr->cp_ring_arr[j];
+
+ if (cpr2) {
+ ring = &cpr2->cp_ring_struct;
+ bnxt_free_ring(bp, &ring->ring_mem);
+ kfree(cpr2);
+ cpr->cp_ring_arr[j] = NULL;
+ }
+ }
}
}
+static struct bnxt_cp_ring_info *bnxt_alloc_cp_sub_ring(struct bnxt *bp)
+{
+ struct bnxt_ring_mem_info *rmem;
+ struct bnxt_ring_struct *ring;
+ struct bnxt_cp_ring_info *cpr;
+ int rc;
+
+ cpr = kzalloc(sizeof(*cpr), GFP_KERNEL);
+ if (!cpr)
+ return NULL;
+
+ ring = &cpr->cp_ring_struct;
+ rmem = &ring->ring_mem;
+ rmem->nr_pages = bp->cp_nr_pages;
+ rmem->page_size = HW_CMPD_RING_SIZE;
+ rmem->pg_arr = (void **)cpr->cp_desc_ring;
+ rmem->dma_arr = cpr->cp_desc_mapping;
+ rmem->flags = BNXT_RMEM_RING_PTE_FLAG;
+ rc = bnxt_alloc_ring(bp, rmem);
+ if (rc) {
+ bnxt_free_ring(bp, rmem);
+ kfree(cpr);
+ cpr = NULL;
+ }
+ return cpr;
+}
+
static int bnxt_alloc_cp_rings(struct bnxt *bp)
{
+ bool sh = !!(bp->flags & BNXT_FLAG_SHARED_RINGS);
int i, rc, ulp_base_vec, ulp_msix;
ulp_msix = bnxt_get_ulp_msix_num(bp);
@@ -2462,9 +2678,10 @@ static int bnxt_alloc_cp_rings(struct bnxt *bp)
continue;
cpr = &bnapi->cp_ring;
+ cpr->bnapi = bnapi;
ring = &cpr->cp_ring_struct;
- rc = bnxt_alloc_ring(bp, ring);
+ rc = bnxt_alloc_ring(bp, &ring->ring_mem);
if (rc)
return rc;
@@ -2472,6 +2689,29 @@ static int bnxt_alloc_cp_rings(struct bnxt *bp)
ring->map_idx = i + ulp_msix;
else
ring->map_idx = i;
+
+ if (!(bp->flags & BNXT_FLAG_CHIP_P5))
+ continue;
+
+ if (i < bp->rx_nr_rings) {
+ struct bnxt_cp_ring_info *cpr2 =
+ bnxt_alloc_cp_sub_ring(bp);
+
+ cpr->cp_ring_arr[BNXT_RX_HDL] = cpr2;
+ if (!cpr2)
+ return -ENOMEM;
+ cpr2->bnapi = bnapi;
+ }
+ if ((sh && i < bp->tx_nr_rings) ||
+ (!sh && i >= bp->rx_nr_rings)) {
+ struct bnxt_cp_ring_info *cpr2 =
+ bnxt_alloc_cp_sub_ring(bp);
+
+ cpr->cp_ring_arr[BNXT_TX_HDL] = cpr2;
+ if (!cpr2)
+ return -ENOMEM;
+ cpr2->bnapi = bnapi;
+ }
}
return 0;
}
@@ -2482,6 +2722,7 @@ static void bnxt_init_ring_struct(struct bnxt *bp)
for (i = 0; i < bp->cp_nr_rings; i++) {
struct bnxt_napi *bnapi = bp->bnapi[i];
+ struct bnxt_ring_mem_info *rmem;
struct bnxt_cp_ring_info *cpr;
struct bnxt_rx_ring_info *rxr;
struct bnxt_tx_ring_info *txr;
@@ -2492,31 +2733,34 @@ static void bnxt_init_ring_struct(struct bnxt *bp)
cpr = &bnapi->cp_ring;
ring = &cpr->cp_ring_struct;
- ring->nr_pages = bp->cp_nr_pages;
- ring->page_size = HW_CMPD_RING_SIZE;
- ring->pg_arr = (void **)cpr->cp_desc_ring;
- ring->dma_arr = cpr->cp_desc_mapping;
- ring->vmem_size = 0;
+ rmem = &ring->ring_mem;
+ rmem->nr_pages = bp->cp_nr_pages;
+ rmem->page_size = HW_CMPD_RING_SIZE;
+ rmem->pg_arr = (void **)cpr->cp_desc_ring;
+ rmem->dma_arr = cpr->cp_desc_mapping;
+ rmem->vmem_size = 0;
rxr = bnapi->rx_ring;
if (!rxr)
goto skip_rx;
ring = &rxr->rx_ring_struct;
- ring->nr_pages = bp->rx_nr_pages;
- ring->page_size = HW_RXBD_RING_SIZE;
- ring->pg_arr = (void **)rxr->rx_desc_ring;
- ring->dma_arr = rxr->rx_desc_mapping;
- ring->vmem_size = SW_RXBD_RING_SIZE * bp->rx_nr_pages;
- ring->vmem = (void **)&rxr->rx_buf_ring;
+ rmem = &ring->ring_mem;
+ rmem->nr_pages = bp->rx_nr_pages;
+ rmem->page_size = HW_RXBD_RING_SIZE;
+ rmem->pg_arr = (void **)rxr->rx_desc_ring;
+ rmem->dma_arr = rxr->rx_desc_mapping;
+ rmem->vmem_size = SW_RXBD_RING_SIZE * bp->rx_nr_pages;
+ rmem->vmem = (void **)&rxr->rx_buf_ring;
ring = &rxr->rx_agg_ring_struct;
- ring->nr_pages = bp->rx_agg_nr_pages;
- ring->page_size = HW_RXBD_RING_SIZE;
- ring->pg_arr = (void **)rxr->rx_agg_desc_ring;
- ring->dma_arr = rxr->rx_agg_desc_mapping;
- ring->vmem_size = SW_RXBD_AGG_RING_SIZE * bp->rx_agg_nr_pages;
- ring->vmem = (void **)&rxr->rx_agg_ring;
+ rmem = &ring->ring_mem;
+ rmem->nr_pages = bp->rx_agg_nr_pages;
+ rmem->page_size = HW_RXBD_RING_SIZE;
+ rmem->pg_arr = (void **)rxr->rx_agg_desc_ring;
+ rmem->dma_arr = rxr->rx_agg_desc_mapping;
+ rmem->vmem_size = SW_RXBD_AGG_RING_SIZE * bp->rx_agg_nr_pages;
+ rmem->vmem = (void **)&rxr->rx_agg_ring;
skip_rx:
txr = bnapi->tx_ring;
@@ -2524,12 +2768,13 @@ skip_rx:
continue;
ring = &txr->tx_ring_struct;
- ring->nr_pages = bp->tx_nr_pages;
- ring->page_size = HW_RXBD_RING_SIZE;
- ring->pg_arr = (void **)txr->tx_desc_ring;
- ring->dma_arr = txr->tx_desc_mapping;
- ring->vmem_size = SW_TXBD_RING_SIZE * bp->tx_nr_pages;
- ring->vmem = (void **)&txr->tx_buf_ring;
+ rmem = &ring->ring_mem;
+ rmem->nr_pages = bp->tx_nr_pages;
+ rmem->page_size = HW_RXBD_RING_SIZE;
+ rmem->pg_arr = (void **)txr->tx_desc_ring;
+ rmem->dma_arr = txr->tx_desc_mapping;
+ rmem->vmem_size = SW_TXBD_RING_SIZE * bp->tx_nr_pages;
+ rmem->vmem = (void **)&txr->tx_buf_ring;
}
}
@@ -2539,8 +2784,8 @@ static void bnxt_init_rxbd_pages(struct bnxt_ring_struct *ring, u32 type)
u32 prod;
struct rx_bd **rx_buf_ring;
- rx_buf_ring = (struct rx_bd **)ring->pg_arr;
- for (i = 0, prod = 0; i < ring->nr_pages; i++) {
+ rx_buf_ring = (struct rx_bd **)ring->ring_mem.pg_arr;
+ for (i = 0, prod = 0; i < ring->ring_mem.nr_pages; i++) {
int j;
struct rx_bd *rxbd;
@@ -2642,7 +2887,7 @@ static int bnxt_init_one_rx_ring(struct bnxt *bp, int ring_nr)
static void bnxt_init_cp_rings(struct bnxt *bp)
{
- int i;
+ int i, j;
for (i = 0; i < bp->cp_nr_rings; i++) {
struct bnxt_cp_ring_info *cpr = &bp->bnapi[i]->cp_ring;
@@ -2651,6 +2896,17 @@ static void bnxt_init_cp_rings(struct bnxt *bp)
ring->fw_ring_id = INVALID_HW_RING_ID;
cpr->rx_ring_coal.coal_ticks = bp->rx_coal.coal_ticks;
cpr->rx_ring_coal.coal_bufs = bp->rx_coal.coal_bufs;
+ for (j = 0; j < 2; j++) {
+ struct bnxt_cp_ring_info *cpr2 = cpr->cp_ring_arr[j];
+
+ if (!cpr2)
+ continue;
+
+ ring = &cpr2->cp_ring_struct;
+ ring->fw_ring_id = INVALID_HW_RING_ID;
+ cpr2->rx_ring_coal.coal_ticks = bp->rx_coal.coal_ticks;
+ cpr2->rx_ring_coal.coal_bufs = bp->rx_coal.coal_bufs;
+ }
}
}
@@ -2754,10 +3010,12 @@ static void bnxt_init_vnics(struct bnxt *bp)
for (i = 0; i < bp->nr_vnics; i++) {
struct bnxt_vnic_info *vnic = &bp->vnic_info[i];
+ int j;
vnic->fw_vnic_id = INVALID_HW_RING_ID;
- vnic->fw_rss_cos_lb_ctx[0] = INVALID_HW_RING_ID;
- vnic->fw_rss_cos_lb_ctx[1] = INVALID_HW_RING_ID;
+ for (j = 0; j < BNXT_MAX_CTX_PER_VNIC; j++)
+ vnic->fw_rss_cos_lb_ctx[j] = INVALID_HW_RING_ID;
+
vnic->fw_l2_ctx_id = INVALID_HW_RING_ID;
if (bp->vnic_info[i].rss_hash_key) {
@@ -2971,6 +3229,9 @@ static int bnxt_alloc_vnic_attributes(struct bnxt *bp)
}
}
+ if (bp->flags & BNXT_FLAG_CHIP_P5)
+ goto vnic_skip_grps;
+
if (vnic->flags & BNXT_VNIC_RSS_FLAG)
max_rings = bp->rx_nr_rings;
else
@@ -2981,7 +3242,7 @@ static int bnxt_alloc_vnic_attributes(struct bnxt *bp)
rc = -ENOMEM;
goto out;
}
-
+vnic_skip_grps:
if ((bp->flags & BNXT_FLAG_NEW_RSS_CAP) &&
!(vnic->flags & BNXT_VNIC_RSS_FLAG))
continue;
@@ -3010,10 +3271,11 @@ static void bnxt_free_hwrm_resources(struct bnxt *bp)
{
struct pci_dev *pdev = bp->pdev;
- dma_free_coherent(&pdev->dev, PAGE_SIZE, bp->hwrm_cmd_resp_addr,
- bp->hwrm_cmd_resp_dma_addr);
-
- bp->hwrm_cmd_resp_addr = NULL;
+ if (bp->hwrm_cmd_resp_addr) {
+ dma_free_coherent(&pdev->dev, PAGE_SIZE, bp->hwrm_cmd_resp_addr,
+ bp->hwrm_cmd_resp_dma_addr);
+ bp->hwrm_cmd_resp_addr = NULL;
+ }
}
static int bnxt_alloc_hwrm_resources(struct bnxt *bp)
@@ -3034,7 +3296,7 @@ static void bnxt_free_hwrm_short_cmd_req(struct bnxt *bp)
if (bp->hwrm_short_cmd_req_addr) {
struct pci_dev *pdev = bp->pdev;
- dma_free_coherent(&pdev->dev, BNXT_HWRM_MAX_REQ_LEN,
+ dma_free_coherent(&pdev->dev, bp->hwrm_max_ext_req_len,
bp->hwrm_short_cmd_req_addr,
bp->hwrm_short_cmd_req_dma_addr);
bp->hwrm_short_cmd_req_addr = NULL;
@@ -3046,7 +3308,7 @@ static int bnxt_alloc_hwrm_short_cmd_req(struct bnxt *bp)
struct pci_dev *pdev = bp->pdev;
bp->hwrm_short_cmd_req_addr =
- dma_alloc_coherent(&pdev->dev, BNXT_HWRM_MAX_REQ_LEN,
+ dma_alloc_coherent(&pdev->dev, bp->hwrm_max_ext_req_len,
&bp->hwrm_short_cmd_req_dma_addr,
GFP_KERNEL);
if (!bp->hwrm_short_cmd_req_addr)
@@ -3070,6 +3332,13 @@ static void bnxt_free_stats(struct bnxt *bp)
bp->hw_rx_port_stats = NULL;
}
+ if (bp->hw_tx_port_stats_ext) {
+ dma_free_coherent(&pdev->dev, sizeof(struct tx_port_stats_ext),
+ bp->hw_tx_port_stats_ext,
+ bp->hw_tx_port_stats_ext_map);
+ bp->hw_tx_port_stats_ext = NULL;
+ }
+
if (bp->hw_rx_port_stats_ext) {
dma_free_coherent(&pdev->dev, sizeof(struct rx_port_stats_ext),
bp->hw_rx_port_stats_ext,
@@ -3144,6 +3413,13 @@ static int bnxt_alloc_stats(struct bnxt *bp)
if (!bp->hw_rx_port_stats_ext)
return 0;
+ if (bp->hwrm_spec_code >= 0x10902) {
+ bp->hw_tx_port_stats_ext =
+ dma_zalloc_coherent(&pdev->dev,
+ sizeof(struct tx_port_stats_ext),
+ &bp->hw_tx_port_stats_ext_map,
+ GFP_KERNEL);
+ }
bp->flags |= BNXT_FLAG_PORT_STATS_EXT;
}
return 0;
@@ -3282,6 +3558,13 @@ static int bnxt_alloc_mem(struct bnxt *bp, bool irq_re_init)
bp->bnapi[i] = bnapi;
bp->bnapi[i]->index = i;
bp->bnapi[i]->bp = bp;
+ if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ struct bnxt_cp_ring_info *cpr =
+ &bp->bnapi[i]->cp_ring;
+
+ cpr->cp_ring_struct.ring_mem.flags =
+ BNXT_RMEM_RING_PTE_FLAG;
+ }
}
bp->rx_ring = kcalloc(bp->rx_nr_rings,
@@ -3291,7 +3574,15 @@ static int bnxt_alloc_mem(struct bnxt *bp, bool irq_re_init)
return -ENOMEM;
for (i = 0; i < bp->rx_nr_rings; i++) {
- bp->rx_ring[i].bnapi = bp->bnapi[i];
+ struct bnxt_rx_ring_info *rxr = &bp->rx_ring[i];
+
+ if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ rxr->rx_ring_struct.ring_mem.flags =
+ BNXT_RMEM_RING_PTE_FLAG;
+ rxr->rx_agg_ring_struct.ring_mem.flags =
+ BNXT_RMEM_RING_PTE_FLAG;
+ }
+ rxr->bnapi = bp->bnapi[i];
bp->bnapi[i]->rx_ring = &bp->rx_ring[i];
}
@@ -3313,12 +3604,16 @@ static int bnxt_alloc_mem(struct bnxt *bp, bool irq_re_init)
j = bp->rx_nr_rings;
for (i = 0; i < bp->tx_nr_rings; i++, j++) {
- bp->tx_ring[i].bnapi = bp->bnapi[j];
- bp->bnapi[j]->tx_ring = &bp->tx_ring[i];
+ struct bnxt_tx_ring_info *txr = &bp->tx_ring[i];
+
+ if (bp->flags & BNXT_FLAG_CHIP_P5)
+ txr->tx_ring_struct.ring_mem.flags =
+ BNXT_RMEM_RING_PTE_FLAG;
+ txr->bnapi = bp->bnapi[j];
+ bp->bnapi[j]->tx_ring = txr;
bp->tx_ring_map[i] = bp->tx_nr_rings_xdp + i;
if (i >= bp->tx_nr_rings_xdp) {
- bp->tx_ring[i].txq_index = i -
- bp->tx_nr_rings_xdp;
+ txr->txq_index = i - bp->tx_nr_rings_xdp;
bp->bnapi[j]->tx_int = bnxt_tx_int;
} else {
bp->bnapi[j]->flags |= BNXT_NAPI_FLAG_XDP;
@@ -3378,7 +3673,7 @@ static void bnxt_disable_int(struct bnxt *bp)
struct bnxt_ring_struct *ring = &cpr->cp_ring_struct;
if (ring->fw_ring_id != INVALID_HW_RING_ID)
- BNXT_CP_DB(cpr->cp_doorbell, cpr->cp_raw_cons);
+ bnxt_db_nq(bp, &cpr->cp_db, cpr->cp_raw_cons);
}
}
@@ -3414,7 +3709,7 @@ static void bnxt_enable_int(struct bnxt *bp)
struct bnxt_napi *bnapi = bp->bnapi[i];
struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
- BNXT_CP_DB_REARM(cpr->cp_doorbell, cpr->cp_raw_cons);
+ bnxt_db_nq_arm(bp, &cpr->cp_db, cpr->cp_raw_cons);
}
}
@@ -3447,12 +3742,27 @@ static int bnxt_hwrm_do_send_msg(struct bnxt *bp, void *msg, u32 msg_len,
cp_ring_id = le16_to_cpu(req->cmpl_ring);
intr_process = (cp_ring_id == INVALID_HW_RING_ID) ? 0 : 1;
- if (bp->fw_cap & BNXT_FW_CAP_SHORT_CMD) {
+ if (msg_len > BNXT_HWRM_MAX_REQ_LEN) {
+ if (msg_len > bp->hwrm_max_ext_req_len ||
+ !bp->hwrm_short_cmd_req_addr)
+ return -EINVAL;
+ }
+
+ if ((bp->fw_cap & BNXT_FW_CAP_SHORT_CMD) ||
+ msg_len > BNXT_HWRM_MAX_REQ_LEN) {
void *short_cmd_req = bp->hwrm_short_cmd_req_addr;
+ u16 max_msg_len;
+
+ /* Set boundary for maximum extended request length for short
+ * cmd format. If passed up from device use the max supported
+ * internal req length.
+ */
+ max_msg_len = bp->hwrm_max_ext_req_len;
memcpy(short_cmd_req, req, msg_len);
- memset(short_cmd_req + msg_len, 0, BNXT_HWRM_MAX_REQ_LEN -
- msg_len);
+ if (msg_len < max_msg_len)
+ memset(short_cmd_req + msg_len, 0,
+ max_msg_len - msg_len);
short_input.req_type = req->req_type;
short_input.signature =
@@ -3981,13 +4291,48 @@ static int bnxt_hwrm_vnic_set_tpa(struct bnxt *bp, u16 vnic_id, u32 tpa_flags)
return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
}
+static u16 bnxt_cp_ring_from_grp(struct bnxt *bp, struct bnxt_ring_struct *ring)
+{
+ struct bnxt_ring_grp_info *grp_info;
+
+ grp_info = &bp->grp_info[ring->grp_idx];
+ return grp_info->cp_fw_ring_id;
+}
+
+static u16 bnxt_cp_ring_for_rx(struct bnxt *bp, struct bnxt_rx_ring_info *rxr)
+{
+ if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ struct bnxt_napi *bnapi = rxr->bnapi;
+ struct bnxt_cp_ring_info *cpr;
+
+ cpr = bnapi->cp_ring.cp_ring_arr[BNXT_RX_HDL];
+ return cpr->cp_ring_struct.fw_ring_id;
+ } else {
+ return bnxt_cp_ring_from_grp(bp, &rxr->rx_ring_struct);
+ }
+}
+
+static u16 bnxt_cp_ring_for_tx(struct bnxt *bp, struct bnxt_tx_ring_info *txr)
+{
+ if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ struct bnxt_napi *bnapi = txr->bnapi;
+ struct bnxt_cp_ring_info *cpr;
+
+ cpr = bnapi->cp_ring.cp_ring_arr[BNXT_TX_HDL];
+ return cpr->cp_ring_struct.fw_ring_id;
+ } else {
+ return bnxt_cp_ring_from_grp(bp, &txr->tx_ring_struct);
+ }
+}
+
static int bnxt_hwrm_vnic_set_rss(struct bnxt *bp, u16 vnic_id, bool set_rss)
{
u32 i, j, max_rings;
struct bnxt_vnic_info *vnic = &bp->vnic_info[vnic_id];
struct hwrm_vnic_rss_cfg_input req = {0};
- if (vnic->fw_rss_cos_lb_ctx[0] == INVALID_HW_RING_ID)
+ if ((bp->flags & BNXT_FLAG_CHIP_P5) ||
+ vnic->fw_rss_cos_lb_ctx[0] == INVALID_HW_RING_ID)
return 0;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_VNIC_RSS_CFG, -1, -1);
@@ -4018,6 +4363,51 @@ static int bnxt_hwrm_vnic_set_rss(struct bnxt *bp, u16 vnic_id, bool set_rss)
return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
}
+static int bnxt_hwrm_vnic_set_rss_p5(struct bnxt *bp, u16 vnic_id, bool set_rss)
+{
+ struct bnxt_vnic_info *vnic = &bp->vnic_info[vnic_id];
+ u32 i, j, k, nr_ctxs, max_rings = bp->rx_nr_rings;
+ struct bnxt_rx_ring_info *rxr = &bp->rx_ring[0];
+ struct hwrm_vnic_rss_cfg_input req = {0};
+
+ bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_VNIC_RSS_CFG, -1, -1);
+ req.vnic_id = cpu_to_le16(vnic->fw_vnic_id);
+ if (!set_rss) {
+ hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
+ return 0;
+ }
+ req.hash_type = cpu_to_le32(bp->rss_hash_cfg);
+ req.hash_mode_flags = VNIC_RSS_CFG_REQ_HASH_MODE_FLAGS_DEFAULT;
+ req.ring_grp_tbl_addr = cpu_to_le64(vnic->rss_table_dma_addr);
+ req.hash_key_tbl_addr = cpu_to_le64(vnic->rss_hash_key_dma_addr);
+ nr_ctxs = DIV_ROUND_UP(bp->rx_nr_rings, 64);
+ for (i = 0, k = 0; i < nr_ctxs; i++) {
+ __le16 *ring_tbl = vnic->rss_table;
+ int rc;
+
+ req.ring_table_pair_index = i;
+ req.rss_ctx_idx = cpu_to_le16(vnic->fw_rss_cos_lb_ctx[i]);
+ for (j = 0; j < 64; j++) {
+ u16 ring_id;
+
+ ring_id = rxr->rx_ring_struct.fw_ring_id;
+ *ring_tbl++ = cpu_to_le16(ring_id);
+ ring_id = bnxt_cp_ring_for_rx(bp, rxr);
+ *ring_tbl++ = cpu_to_le16(ring_id);
+ rxr++;
+ k++;
+ if (k == max_rings) {
+ k = 0;
+ rxr = &bp->rx_ring[0];
+ }
+ }
+ rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
+ if (rc)
+ return -EIO;
+ }
+ return 0;
+}
+
static int bnxt_hwrm_vnic_set_hds(struct bnxt *bp, u16 vnic_id)
{
struct bnxt_vnic_info *vnic = &bp->vnic_info[vnic_id];
@@ -4101,6 +4491,18 @@ int bnxt_hwrm_vnic_cfg(struct bnxt *bp, u16 vnic_id)
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_VNIC_CFG, -1, -1);
+ if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ struct bnxt_rx_ring_info *rxr = &bp->rx_ring[0];
+
+ req.default_rx_ring_id =
+ cpu_to_le16(rxr->rx_ring_struct.fw_ring_id);
+ req.default_cmpl_ring_id =
+ cpu_to_le16(bnxt_cp_ring_for_rx(bp, rxr));
+ req.enables =
+ cpu_to_le32(VNIC_CFG_REQ_ENABLES_DEFAULT_RX_RING_ID |
+ VNIC_CFG_REQ_ENABLES_DEFAULT_CMPL_RING_ID);
+ goto vnic_mru;
+ }
req.enables = cpu_to_le32(VNIC_CFG_REQ_ENABLES_DFLT_RING_GRP);
/* Only RSS support for now TBD: COS & LB */
if (vnic->fw_rss_cos_lb_ctx[0] != INVALID_HW_RING_ID) {
@@ -4133,13 +4535,13 @@ int bnxt_hwrm_vnic_cfg(struct bnxt *bp, u16 vnic_id)
ring = bp->rx_nr_rings - 1;
grp_idx = bp->rx_ring[ring].bnapi->index;
- req.vnic_id = cpu_to_le16(vnic->fw_vnic_id);
req.dflt_ring_grp = cpu_to_le16(bp->grp_info[grp_idx].fw_grp_id);
-
req.lb_rule = cpu_to_le16(0xffff);
+vnic_mru:
req.mru = cpu_to_le16(bp->dev->mtu + ETH_HLEN + ETH_FCS_LEN +
VLAN_HLEN);
+ req.vnic_id = cpu_to_le16(vnic->fw_vnic_id);
#ifdef CONFIG_BNXT_SRIOV
if (BNXT_VF(bp))
def_vlan = bp->vf.vlan;
@@ -4187,6 +4589,10 @@ static int bnxt_hwrm_vnic_alloc(struct bnxt *bp, u16 vnic_id,
unsigned int i, j, grp_idx, end_idx = start_rx_ring_idx + nr_rings;
struct hwrm_vnic_alloc_input req = {0};
struct hwrm_vnic_alloc_output *resp = bp->hwrm_cmd_resp_addr;
+ struct bnxt_vnic_info *vnic = &bp->vnic_info[vnic_id];
+
+ if (bp->flags & BNXT_FLAG_CHIP_P5)
+ goto vnic_no_ring_grps;
/* map ring groups to this vnic */
for (i = start_rx_ring_idx, j = 0; i < end_idx; i++, j++) {
@@ -4196,12 +4602,12 @@ static int bnxt_hwrm_vnic_alloc(struct bnxt *bp, u16 vnic_id,
j, nr_rings);
break;
}
- bp->vnic_info[vnic_id].fw_grp_ids[j] =
- bp->grp_info[grp_idx].fw_grp_id;
+ vnic->fw_grp_ids[j] = bp->grp_info[grp_idx].fw_grp_id;
}
- bp->vnic_info[vnic_id].fw_rss_cos_lb_ctx[0] = INVALID_HW_RING_ID;
- bp->vnic_info[vnic_id].fw_rss_cos_lb_ctx[1] = INVALID_HW_RING_ID;
+vnic_no_ring_grps:
+ for (i = 0; i < BNXT_MAX_CTX_PER_VNIC; i++)
+ vnic->fw_rss_cos_lb_ctx[i] = INVALID_HW_RING_ID;
if (vnic_id == 0)
req.flags = cpu_to_le32(VNIC_ALLOC_REQ_FLAGS_DEFAULT);
@@ -4210,7 +4616,7 @@ static int bnxt_hwrm_vnic_alloc(struct bnxt *bp, u16 vnic_id,
mutex_lock(&bp->hwrm_cmd_lock);
rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (!rc)
- bp->vnic_info[vnic_id].fw_vnic_id = le32_to_cpu(resp->vnic_id);
+ vnic->fw_vnic_id = le32_to_cpu(resp->vnic_id);
mutex_unlock(&bp->hwrm_cmd_lock);
return rc;
}
@@ -4230,7 +4636,8 @@ static int bnxt_hwrm_vnic_qcaps(struct bnxt *bp)
if (!rc) {
u32 flags = le32_to_cpu(resp->flags);
- if (flags & VNIC_QCAPS_RESP_FLAGS_RSS_DFLT_CR_CAP)
+ if (!(bp->flags & BNXT_FLAG_CHIP_P5) &&
+ (flags & VNIC_QCAPS_RESP_FLAGS_RSS_DFLT_CR_CAP))
bp->flags |= BNXT_FLAG_NEW_RSS_CAP;
if (flags &
VNIC_QCAPS_RESP_FLAGS_ROCE_MIRRORING_CAPABLE_VNIC_CAP)
@@ -4245,6 +4652,9 @@ static int bnxt_hwrm_ring_grp_alloc(struct bnxt *bp)
u16 i;
u32 rc = 0;
+ if (bp->flags & BNXT_FLAG_CHIP_P5)
+ return 0;
+
mutex_lock(&bp->hwrm_cmd_lock);
for (i = 0; i < bp->rx_nr_rings; i++) {
struct hwrm_ring_grp_alloc_input req = {0};
@@ -4277,7 +4687,7 @@ static int bnxt_hwrm_ring_grp_free(struct bnxt *bp)
u32 rc = 0;
struct hwrm_ring_grp_free_input req = {0};
- if (!bp->grp_info)
+ if (!bp->grp_info || (bp->flags & BNXT_FLAG_CHIP_P5))
return 0;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_RING_GRP_FREE, -1, -1);
@@ -4306,45 +4716,90 @@ static int hwrm_ring_alloc_send_msg(struct bnxt *bp,
int rc = 0, err = 0;
struct hwrm_ring_alloc_input req = {0};
struct hwrm_ring_alloc_output *resp = bp->hwrm_cmd_resp_addr;
+ struct bnxt_ring_mem_info *rmem = &ring->ring_mem;
struct bnxt_ring_grp_info *grp_info;
u16 ring_id;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_RING_ALLOC, -1, -1);
req.enables = 0;
- if (ring->nr_pages > 1) {
- req.page_tbl_addr = cpu_to_le64(ring->pg_tbl_map);
+ if (rmem->nr_pages > 1) {
+ req.page_tbl_addr = cpu_to_le64(rmem->pg_tbl_map);
/* Page size is in log2 units */
req.page_size = BNXT_PAGE_SHIFT;
req.page_tbl_depth = 1;
} else {
- req.page_tbl_addr = cpu_to_le64(ring->dma_arr[0]);
+ req.page_tbl_addr = cpu_to_le64(rmem->dma_arr[0]);
}
req.fbo = 0;
/* Association of ring index with doorbell index and MSIX number */
req.logical_id = cpu_to_le16(map_index);
switch (ring_type) {
- case HWRM_RING_ALLOC_TX:
+ case HWRM_RING_ALLOC_TX: {
+ struct bnxt_tx_ring_info *txr;
+
+ txr = container_of(ring, struct bnxt_tx_ring_info,
+ tx_ring_struct);
req.ring_type = RING_ALLOC_REQ_RING_TYPE_TX;
/* Association of transmit ring with completion ring */
grp_info = &bp->grp_info[ring->grp_idx];
- req.cmpl_ring_id = cpu_to_le16(grp_info->cp_fw_ring_id);
+ req.cmpl_ring_id = cpu_to_le16(bnxt_cp_ring_for_tx(bp, txr));
req.length = cpu_to_le32(bp->tx_ring_mask + 1);
req.stat_ctx_id = cpu_to_le32(grp_info->fw_stats_ctx);
req.queue_id = cpu_to_le16(ring->queue_id);
break;
+ }
case HWRM_RING_ALLOC_RX:
req.ring_type = RING_ALLOC_REQ_RING_TYPE_RX;
req.length = cpu_to_le32(bp->rx_ring_mask + 1);
+ if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ u16 flags = 0;
+
+ /* Association of rx ring with stats context */
+ grp_info = &bp->grp_info[ring->grp_idx];
+ req.rx_buf_size = cpu_to_le16(bp->rx_buf_use_size);
+ req.stat_ctx_id = cpu_to_le32(grp_info->fw_stats_ctx);
+ req.enables |= cpu_to_le32(
+ RING_ALLOC_REQ_ENABLES_RX_BUF_SIZE_VALID);
+ if (NET_IP_ALIGN == 2)
+ flags = RING_ALLOC_REQ_FLAGS_RX_SOP_PAD;
+ req.flags = cpu_to_le16(flags);
+ }
break;
case HWRM_RING_ALLOC_AGG:
- req.ring_type = RING_ALLOC_REQ_RING_TYPE_RX;
+ if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ req.ring_type = RING_ALLOC_REQ_RING_TYPE_RX_AGG;
+ /* Association of agg ring with rx ring */
+ grp_info = &bp->grp_info[ring->grp_idx];
+ req.rx_ring_id = cpu_to_le16(grp_info->rx_fw_ring_id);
+ req.rx_buf_size = cpu_to_le16(BNXT_RX_PAGE_SIZE);
+ req.stat_ctx_id = cpu_to_le32(grp_info->fw_stats_ctx);
+ req.enables |= cpu_to_le32(
+ RING_ALLOC_REQ_ENABLES_RX_RING_ID_VALID |
+ RING_ALLOC_REQ_ENABLES_RX_BUF_SIZE_VALID);
+ } else {
+ req.ring_type = RING_ALLOC_REQ_RING_TYPE_RX;
+ }
req.length = cpu_to_le32(bp->rx_agg_ring_mask + 1);
break;
case HWRM_RING_ALLOC_CMPL:
req.ring_type = RING_ALLOC_REQ_RING_TYPE_L2_CMPL;
req.length = cpu_to_le32(bp->cp_ring_mask + 1);
+ if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ /* Association of cp ring with nq */
+ grp_info = &bp->grp_info[map_index];
+ req.nq_ring_id = cpu_to_le16(grp_info->cp_fw_ring_id);
+ req.cq_handle = cpu_to_le64(ring->handle);
+ req.enables |= cpu_to_le32(
+ RING_ALLOC_REQ_ENABLES_NQ_RING_ID_VALID);
+ } else if (bp->flags & BNXT_FLAG_USING_MSIX) {
+ req.int_mode = RING_ALLOC_REQ_INT_MODE_MSIX;
+ }
+ break;
+ case HWRM_RING_ALLOC_NQ:
+ req.ring_type = RING_ALLOC_REQ_RING_TYPE_NQ;
+ req.length = cpu_to_le32(bp->cp_ring_mask + 1);
if (bp->flags & BNXT_FLAG_USING_MSIX)
req.int_mode = RING_ALLOC_REQ_INT_MODE_MSIX;
break;
@@ -4393,22 +4848,67 @@ static int bnxt_hwrm_set_async_event_cr(struct bnxt *bp, int idx)
return rc;
}
+static void bnxt_set_db(struct bnxt *bp, struct bnxt_db_info *db, u32 ring_type,
+ u32 map_idx, u32 xid)
+{
+ if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ if (BNXT_PF(bp))
+ db->doorbell = bp->bar1 + 0x10000;
+ else
+ db->doorbell = bp->bar1 + 0x4000;
+ switch (ring_type) {
+ case HWRM_RING_ALLOC_TX:
+ db->db_key64 = DBR_PATH_L2 | DBR_TYPE_SQ;
+ break;
+ case HWRM_RING_ALLOC_RX:
+ case HWRM_RING_ALLOC_AGG:
+ db->db_key64 = DBR_PATH_L2 | DBR_TYPE_SRQ;
+ break;
+ case HWRM_RING_ALLOC_CMPL:
+ db->db_key64 = DBR_PATH_L2;
+ break;
+ case HWRM_RING_ALLOC_NQ:
+ db->db_key64 = DBR_PATH_L2;
+ break;
+ }
+ db->db_key64 |= (u64)xid << DBR_XID_SFT;
+ } else {
+ db->doorbell = bp->bar1 + map_idx * 0x80;
+ switch (ring_type) {
+ case HWRM_RING_ALLOC_TX:
+ db->db_key32 = DB_KEY_TX;
+ break;
+ case HWRM_RING_ALLOC_RX:
+ case HWRM_RING_ALLOC_AGG:
+ db->db_key32 = DB_KEY_RX;
+ break;
+ case HWRM_RING_ALLOC_CMPL:
+ db->db_key32 = DB_KEY_CP;
+ break;
+ }
+ }
+}
+
static int bnxt_hwrm_ring_alloc(struct bnxt *bp)
{
int i, rc = 0;
+ u32 type;
+ if (bp->flags & BNXT_FLAG_CHIP_P5)
+ type = HWRM_RING_ALLOC_NQ;
+ else
+ type = HWRM_RING_ALLOC_CMPL;
for (i = 0; i < bp->cp_nr_rings; i++) {
struct bnxt_napi *bnapi = bp->bnapi[i];
struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
struct bnxt_ring_struct *ring = &cpr->cp_ring_struct;
u32 map_idx = ring->map_idx;
- cpr->cp_doorbell = bp->bar1 + map_idx * 0x80;
- rc = hwrm_ring_alloc_send_msg(bp, ring, HWRM_RING_ALLOC_CMPL,
- map_idx);
+ rc = hwrm_ring_alloc_send_msg(bp, ring, type, map_idx);
if (rc)
goto err_out;
- BNXT_CP_DB(cpr->cp_doorbell, cpr->cp_raw_cons);
+ bnxt_set_db(bp, &cpr->cp_db, type, map_idx, ring->fw_ring_id);
+ bnxt_db_nq(bp, &cpr->cp_db, cpr->cp_raw_cons);
bp->grp_info[i].cp_fw_ring_id = ring->fw_ring_id;
if (!i) {
@@ -4418,33 +4918,69 @@ static int bnxt_hwrm_ring_alloc(struct bnxt *bp)
}
}
+ type = HWRM_RING_ALLOC_TX;
for (i = 0; i < bp->tx_nr_rings; i++) {
struct bnxt_tx_ring_info *txr = &bp->tx_ring[i];
- struct bnxt_ring_struct *ring = &txr->tx_ring_struct;
- u32 map_idx = i;
-
- rc = hwrm_ring_alloc_send_msg(bp, ring, HWRM_RING_ALLOC_TX,
- map_idx);
+ struct bnxt_ring_struct *ring;
+ u32 map_idx;
+
+ if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ struct bnxt_napi *bnapi = txr->bnapi;
+ struct bnxt_cp_ring_info *cpr, *cpr2;
+ u32 type2 = HWRM_RING_ALLOC_CMPL;
+
+ cpr = &bnapi->cp_ring;
+ cpr2 = cpr->cp_ring_arr[BNXT_TX_HDL];
+ ring = &cpr2->cp_ring_struct;
+ ring->handle = BNXT_TX_HDL;
+ map_idx = bnapi->index;
+ rc = hwrm_ring_alloc_send_msg(bp, ring, type2, map_idx);
+ if (rc)
+ goto err_out;
+ bnxt_set_db(bp, &cpr2->cp_db, type2, map_idx,
+ ring->fw_ring_id);
+ bnxt_db_cq(bp, &cpr2->cp_db, cpr2->cp_raw_cons);
+ }
+ ring = &txr->tx_ring_struct;
+ map_idx = i;
+ rc = hwrm_ring_alloc_send_msg(bp, ring, type, map_idx);
if (rc)
goto err_out;
- txr->tx_doorbell = bp->bar1 + map_idx * 0x80;
+ bnxt_set_db(bp, &txr->tx_db, type, map_idx, ring->fw_ring_id);
}
+ type = HWRM_RING_ALLOC_RX;
for (i = 0; i < bp->rx_nr_rings; i++) {
struct bnxt_rx_ring_info *rxr = &bp->rx_ring[i];
struct bnxt_ring_struct *ring = &rxr->rx_ring_struct;
- u32 map_idx = rxr->bnapi->index;
+ struct bnxt_napi *bnapi = rxr->bnapi;
+ u32 map_idx = bnapi->index;
- rc = hwrm_ring_alloc_send_msg(bp, ring, HWRM_RING_ALLOC_RX,
- map_idx);
+ rc = hwrm_ring_alloc_send_msg(bp, ring, type, map_idx);
if (rc)
goto err_out;
- rxr->rx_doorbell = bp->bar1 + map_idx * 0x80;
- writel(DB_KEY_RX | rxr->rx_prod, rxr->rx_doorbell);
+ bnxt_set_db(bp, &rxr->rx_db, type, map_idx, ring->fw_ring_id);
+ bnxt_db_write(bp, &rxr->rx_db, rxr->rx_prod);
bp->grp_info[map_idx].rx_fw_ring_id = ring->fw_ring_id;
+ if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
+ u32 type2 = HWRM_RING_ALLOC_CMPL;
+ struct bnxt_cp_ring_info *cpr2;
+
+ cpr2 = cpr->cp_ring_arr[BNXT_RX_HDL];
+ ring = &cpr2->cp_ring_struct;
+ ring->handle = BNXT_RX_HDL;
+ rc = hwrm_ring_alloc_send_msg(bp, ring, type2, map_idx);
+ if (rc)
+ goto err_out;
+ bnxt_set_db(bp, &cpr2->cp_db, type2, map_idx,
+ ring->fw_ring_id);
+ bnxt_db_cq(bp, &cpr2->cp_db, cpr2->cp_raw_cons);
+ }
}
if (bp->flags & BNXT_FLAG_AGG_RINGS) {
+ type = HWRM_RING_ALLOC_AGG;
for (i = 0; i < bp->rx_nr_rings; i++) {
struct bnxt_rx_ring_info *rxr = &bp->rx_ring[i];
struct bnxt_ring_struct *ring =
@@ -4452,15 +4988,13 @@ static int bnxt_hwrm_ring_alloc(struct bnxt *bp)
u32 grp_idx = ring->grp_idx;
u32 map_idx = grp_idx + bp->rx_nr_rings;
- rc = hwrm_ring_alloc_send_msg(bp, ring,
- HWRM_RING_ALLOC_AGG,
- map_idx);
+ rc = hwrm_ring_alloc_send_msg(bp, ring, type, map_idx);
if (rc)
goto err_out;
- rxr->rx_agg_doorbell = bp->bar1 + map_idx * 0x80;
- writel(DB_KEY_RX | rxr->rx_agg_prod,
- rxr->rx_agg_doorbell);
+ bnxt_set_db(bp, &rxr->rx_agg_db, type, map_idx,
+ ring->fw_ring_id);
+ bnxt_db_write(bp, &rxr->rx_agg_db, rxr->rx_agg_prod);
bp->grp_info[grp_idx].agg_fw_ring_id = ring->fw_ring_id;
}
}
@@ -4496,6 +5030,7 @@ static int hwrm_ring_free_send_msg(struct bnxt *bp,
static void bnxt_hwrm_ring_free(struct bnxt *bp, bool close_path)
{
+ u32 type;
int i;
if (!bp->bnapi)
@@ -4504,9 +5039,9 @@ static void bnxt_hwrm_ring_free(struct bnxt *bp, bool close_path)
for (i = 0; i < bp->tx_nr_rings; i++) {
struct bnxt_tx_ring_info *txr = &bp->tx_ring[i];
struct bnxt_ring_struct *ring = &txr->tx_ring_struct;
- u32 grp_idx = txr->bnapi->index;
- u32 cmpl_ring_id = bp->grp_info[grp_idx].cp_fw_ring_id;
+ u32 cmpl_ring_id;
+ cmpl_ring_id = bnxt_cp_ring_for_tx(bp, txr);
if (ring->fw_ring_id != INVALID_HW_RING_ID) {
hwrm_ring_free_send_msg(bp, ring,
RING_FREE_REQ_RING_TYPE_TX,
@@ -4520,8 +5055,9 @@ static void bnxt_hwrm_ring_free(struct bnxt *bp, bool close_path)
struct bnxt_rx_ring_info *rxr = &bp->rx_ring[i];
struct bnxt_ring_struct *ring = &rxr->rx_ring_struct;
u32 grp_idx = rxr->bnapi->index;
- u32 cmpl_ring_id = bp->grp_info[grp_idx].cp_fw_ring_id;
+ u32 cmpl_ring_id;
+ cmpl_ring_id = bnxt_cp_ring_for_rx(bp, rxr);
if (ring->fw_ring_id != INVALID_HW_RING_ID) {
hwrm_ring_free_send_msg(bp, ring,
RING_FREE_REQ_RING_TYPE_RX,
@@ -4533,15 +5069,19 @@ static void bnxt_hwrm_ring_free(struct bnxt *bp, bool close_path)
}
}
+ if (bp->flags & BNXT_FLAG_CHIP_P5)
+ type = RING_FREE_REQ_RING_TYPE_RX_AGG;
+ else
+ type = RING_FREE_REQ_RING_TYPE_RX;
for (i = 0; i < bp->rx_nr_rings; i++) {
struct bnxt_rx_ring_info *rxr = &bp->rx_ring[i];
struct bnxt_ring_struct *ring = &rxr->rx_agg_ring_struct;
u32 grp_idx = rxr->bnapi->index;
- u32 cmpl_ring_id = bp->grp_info[grp_idx].cp_fw_ring_id;
+ u32 cmpl_ring_id;
+ cmpl_ring_id = bnxt_cp_ring_for_rx(bp, rxr);
if (ring->fw_ring_id != INVALID_HW_RING_ID) {
- hwrm_ring_free_send_msg(bp, ring,
- RING_FREE_REQ_RING_TYPE_RX,
+ hwrm_ring_free_send_msg(bp, ring, type,
close_path ? cmpl_ring_id :
INVALID_HW_RING_ID);
ring->fw_ring_id = INVALID_HW_RING_ID;
@@ -4556,14 +5096,32 @@ static void bnxt_hwrm_ring_free(struct bnxt *bp, bool close_path)
*/
bnxt_disable_int_sync(bp);
+ if (bp->flags & BNXT_FLAG_CHIP_P5)
+ type = RING_FREE_REQ_RING_TYPE_NQ;
+ else
+ type = RING_FREE_REQ_RING_TYPE_L2_CMPL;
for (i = 0; i < bp->cp_nr_rings; i++) {
struct bnxt_napi *bnapi = bp->bnapi[i];
struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
- struct bnxt_ring_struct *ring = &cpr->cp_ring_struct;
+ struct bnxt_ring_struct *ring;
+ int j;
+
+ for (j = 0; j < 2; j++) {
+ struct bnxt_cp_ring_info *cpr2 = cpr->cp_ring_arr[j];
+ if (cpr2) {
+ ring = &cpr2->cp_ring_struct;
+ if (ring->fw_ring_id == INVALID_HW_RING_ID)
+ continue;
+ hwrm_ring_free_send_msg(bp, ring,
+ RING_FREE_REQ_RING_TYPE_L2_CMPL,
+ INVALID_HW_RING_ID);
+ ring->fw_ring_id = INVALID_HW_RING_ID;
+ }
+ }
+ ring = &cpr->cp_ring_struct;
if (ring->fw_ring_id != INVALID_HW_RING_ID) {
- hwrm_ring_free_send_msg(bp, ring,
- RING_FREE_REQ_RING_TYPE_L2_CMPL,
+ hwrm_ring_free_send_msg(bp, ring, type,
INVALID_HW_RING_ID);
ring->fw_ring_id = INVALID_HW_RING_ID;
bp->grp_info[i].cp_fw_ring_id = INVALID_HW_RING_ID;
@@ -4571,6 +5129,9 @@ static void bnxt_hwrm_ring_free(struct bnxt *bp, bool close_path)
}
}
+static int bnxt_trim_rings(struct bnxt *bp, int *rx, int *tx, int max,
+ bool shared);
+
static int bnxt_hwrm_get_rings(struct bnxt *bp)
{
struct hwrm_func_qcfg_output *resp = bp->hwrm_cmd_resp_addr;
@@ -4601,6 +5162,22 @@ static int bnxt_hwrm_get_rings(struct bnxt *bp)
cp = le16_to_cpu(resp->alloc_cmpl_rings);
stats = le16_to_cpu(resp->alloc_stat_ctx);
cp = min_t(u16, cp, stats);
+ if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ int rx = hw_resc->resv_rx_rings;
+ int tx = hw_resc->resv_tx_rings;
+
+ if (bp->flags & BNXT_FLAG_AGG_RINGS)
+ rx >>= 1;
+ if (cp < (rx + tx)) {
+ bnxt_trim_rings(bp, &rx, &tx, cp, false);
+ if (bp->flags & BNXT_FLAG_AGG_RINGS)
+ rx <<= 1;
+ hw_resc->resv_rx_rings = rx;
+ hw_resc->resv_tx_rings = tx;
+ }
+ cp = le16_to_cpu(resp->alloc_msix);
+ hw_resc->resv_hw_ring_grps = rx;
+ }
hw_resc->resv_cp_rings = cp;
}
mutex_unlock(&bp->hwrm_cmd_lock);
@@ -4626,6 +5203,8 @@ int __bnxt_hwrm_get_tx_rings(struct bnxt *bp, u16 fid, int *tx_rings)
return rc;
}
+static bool bnxt_rfs_supported(struct bnxt *bp);
+
static void
__bnxt_hwrm_reserve_pf_rings(struct bnxt *bp, struct hwrm_func_cfg_input *req,
int tx_rings, int rx_rings, int ring_grps,
@@ -4639,15 +5218,38 @@ __bnxt_hwrm_reserve_pf_rings(struct bnxt *bp, struct hwrm_func_cfg_input *req,
req->num_tx_rings = cpu_to_le16(tx_rings);
if (BNXT_NEW_RM(bp)) {
enables |= rx_rings ? FUNC_CFG_REQ_ENABLES_NUM_RX_RINGS : 0;
- enables |= cp_rings ? FUNC_CFG_REQ_ENABLES_NUM_CMPL_RINGS |
- FUNC_CFG_REQ_ENABLES_NUM_STAT_CTXS : 0;
- enables |= ring_grps ?
- FUNC_CFG_REQ_ENABLES_NUM_HW_RING_GRPS : 0;
- enables |= vnics ? FUNC_VF_CFG_REQ_ENABLES_NUM_VNICS : 0;
+ if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ enables |= cp_rings ? FUNC_CFG_REQ_ENABLES_NUM_MSIX : 0;
+ enables |= tx_rings + ring_grps ?
+ FUNC_CFG_REQ_ENABLES_NUM_CMPL_RINGS |
+ FUNC_CFG_REQ_ENABLES_NUM_STAT_CTXS : 0;
+ enables |= rx_rings ?
+ FUNC_CFG_REQ_ENABLES_NUM_RSSCOS_CTXS : 0;
+ } else {
+ enables |= cp_rings ?
+ FUNC_CFG_REQ_ENABLES_NUM_CMPL_RINGS |
+ FUNC_CFG_REQ_ENABLES_NUM_STAT_CTXS : 0;
+ enables |= ring_grps ?
+ FUNC_CFG_REQ_ENABLES_NUM_HW_RING_GRPS |
+ FUNC_CFG_REQ_ENABLES_NUM_RSSCOS_CTXS : 0;
+ }
+ enables |= vnics ? FUNC_CFG_REQ_ENABLES_NUM_VNICS : 0;
req->num_rx_rings = cpu_to_le16(rx_rings);
- req->num_hw_ring_grps = cpu_to_le16(ring_grps);
- req->num_cmpl_rings = cpu_to_le16(cp_rings);
+ if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ req->num_cmpl_rings = cpu_to_le16(tx_rings + ring_grps);
+ req->num_msix = cpu_to_le16(cp_rings);
+ req->num_rsscos_ctxs =
+ cpu_to_le16(DIV_ROUND_UP(ring_grps, 64));
+ } else {
+ req->num_cmpl_rings = cpu_to_le16(cp_rings);
+ req->num_hw_ring_grps = cpu_to_le16(ring_grps);
+ req->num_rsscos_ctxs = cpu_to_le16(1);
+ if (!(bp->flags & BNXT_FLAG_NEW_RSS_CAP) &&
+ bnxt_rfs_supported(bp))
+ req->num_rsscos_ctxs =
+ cpu_to_le16(ring_grps + 1);
+ }
req->num_stat_ctxs = req->num_cmpl_rings;
req->num_vnics = cpu_to_le16(vnics);
}
@@ -4664,16 +5266,33 @@ __bnxt_hwrm_reserve_vf_rings(struct bnxt *bp,
bnxt_hwrm_cmd_hdr_init(bp, req, HWRM_FUNC_VF_CFG, -1, -1);
enables |= tx_rings ? FUNC_VF_CFG_REQ_ENABLES_NUM_TX_RINGS : 0;
- enables |= rx_rings ? FUNC_VF_CFG_REQ_ENABLES_NUM_RX_RINGS : 0;
- enables |= cp_rings ? FUNC_VF_CFG_REQ_ENABLES_NUM_CMPL_RINGS |
- FUNC_VF_CFG_REQ_ENABLES_NUM_STAT_CTXS : 0;
- enables |= ring_grps ? FUNC_VF_CFG_REQ_ENABLES_NUM_HW_RING_GRPS : 0;
+ enables |= rx_rings ? FUNC_VF_CFG_REQ_ENABLES_NUM_RX_RINGS |
+ FUNC_VF_CFG_REQ_ENABLES_NUM_RSSCOS_CTXS : 0;
+ if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ enables |= tx_rings + ring_grps ?
+ FUNC_VF_CFG_REQ_ENABLES_NUM_CMPL_RINGS |
+ FUNC_VF_CFG_REQ_ENABLES_NUM_STAT_CTXS : 0;
+ } else {
+ enables |= cp_rings ?
+ FUNC_VF_CFG_REQ_ENABLES_NUM_CMPL_RINGS |
+ FUNC_VF_CFG_REQ_ENABLES_NUM_STAT_CTXS : 0;
+ enables |= ring_grps ?
+ FUNC_VF_CFG_REQ_ENABLES_NUM_HW_RING_GRPS : 0;
+ }
enables |= vnics ? FUNC_VF_CFG_REQ_ENABLES_NUM_VNICS : 0;
+ enables |= FUNC_VF_CFG_REQ_ENABLES_NUM_L2_CTXS;
+ req->num_l2_ctxs = cpu_to_le16(BNXT_VF_MAX_L2_CTX);
req->num_tx_rings = cpu_to_le16(tx_rings);
req->num_rx_rings = cpu_to_le16(rx_rings);
- req->num_hw_ring_grps = cpu_to_le16(ring_grps);
- req->num_cmpl_rings = cpu_to_le16(cp_rings);
+ if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ req->num_cmpl_rings = cpu_to_le16(tx_rings + ring_grps);
+ req->num_rsscos_ctxs = cpu_to_le16(DIV_ROUND_UP(ring_grps, 64));
+ } else {
+ req->num_cmpl_rings = cpu_to_le16(cp_rings);
+ req->num_hw_ring_grps = cpu_to_le16(ring_grps);
+ req->num_rsscos_ctxs = cpu_to_le16(BNXT_VF_MAX_RSS_CTX);
+ }
req->num_stat_ctxs = req->num_cmpl_rings;
req->num_vnics = cpu_to_le16(vnics);
@@ -4717,10 +5336,6 @@ bnxt_hwrm_reserve_vf_rings(struct bnxt *bp, int tx_rings, int rx_rings,
__bnxt_hwrm_reserve_vf_rings(bp, &req, tx_rings, rx_rings, ring_grps,
cp_rings, vnics);
- req.enables |= cpu_to_le32(FUNC_VF_CFG_REQ_ENABLES_NUM_RSSCOS_CTXS |
- FUNC_VF_CFG_REQ_ENABLES_NUM_L2_CTXS);
- req.num_rsscos_ctxs = cpu_to_le16(BNXT_VF_MAX_RSS_CTX);
- req.num_l2_ctxs = cpu_to_le16(BNXT_VF_MAX_L2_CTX);
rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (rc)
return -ENOMEM;
@@ -4766,20 +5381,19 @@ static bool bnxt_need_reserve_rings(struct bnxt *bp)
if (hw_resc->resv_tx_rings != bp->tx_nr_rings)
return true;
- if (bp->flags & BNXT_FLAG_RFS)
+ if ((bp->flags & BNXT_FLAG_RFS) && !(bp->flags & BNXT_FLAG_CHIP_P5))
vnic = rx + 1;
if (bp->flags & BNXT_FLAG_AGG_RINGS)
rx <<= 1;
if (BNXT_NEW_RM(bp) &&
(hw_resc->resv_rx_rings != rx || hw_resc->resv_cp_rings != cp ||
- hw_resc->resv_hw_ring_grps != grp || hw_resc->resv_vnics != vnic))
+ hw_resc->resv_vnics != vnic ||
+ (hw_resc->resv_hw_ring_grps != grp &&
+ !(bp->flags & BNXT_FLAG_CHIP_P5))))
return true;
return false;
}
-static int bnxt_trim_rings(struct bnxt *bp, int *rx, int *tx, int max,
- bool shared);
-
static int __bnxt_reserve_rings(struct bnxt *bp)
{
struct bnxt_hw_resc *hw_resc = &bp->hw_resc;
@@ -4795,7 +5409,7 @@ static int __bnxt_reserve_rings(struct bnxt *bp)
if (bp->flags & BNXT_FLAG_SHARED_RINGS)
sh = true;
- if (bp->flags & BNXT_FLAG_RFS)
+ if ((bp->flags & BNXT_FLAG_RFS) && !(bp->flags & BNXT_FLAG_CHIP_P5))
vnic = rx + 1;
if (bp->flags & BNXT_FLAG_AGG_RINGS)
rx <<= 1;
@@ -4858,9 +5472,11 @@ static int bnxt_hwrm_check_vf_rings(struct bnxt *bp, int tx_rings, int rx_rings,
flags = FUNC_VF_CFG_REQ_FLAGS_TX_ASSETS_TEST |
FUNC_VF_CFG_REQ_FLAGS_RX_ASSETS_TEST |
FUNC_VF_CFG_REQ_FLAGS_CMPL_ASSETS_TEST |
- FUNC_VF_CFG_REQ_FLAGS_RING_GRP_ASSETS_TEST |
FUNC_VF_CFG_REQ_FLAGS_STAT_CTX_ASSETS_TEST |
- FUNC_VF_CFG_REQ_FLAGS_VNIC_ASSETS_TEST;
+ FUNC_VF_CFG_REQ_FLAGS_VNIC_ASSETS_TEST |
+ FUNC_VF_CFG_REQ_FLAGS_RSSCOS_CTX_ASSETS_TEST;
+ if (!(bp->flags & BNXT_FLAG_CHIP_P5))
+ flags |= FUNC_VF_CFG_REQ_FLAGS_RING_GRP_ASSETS_TEST;
req.flags = cpu_to_le32(flags);
rc = hwrm_send_message_silent(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
@@ -4879,12 +5495,16 @@ static int bnxt_hwrm_check_pf_rings(struct bnxt *bp, int tx_rings, int rx_rings,
__bnxt_hwrm_reserve_pf_rings(bp, &req, tx_rings, rx_rings, ring_grps,
cp_rings, vnics);
flags = FUNC_CFG_REQ_FLAGS_TX_ASSETS_TEST;
- if (BNXT_NEW_RM(bp))
+ if (BNXT_NEW_RM(bp)) {
flags |= FUNC_CFG_REQ_FLAGS_RX_ASSETS_TEST |
FUNC_CFG_REQ_FLAGS_CMPL_ASSETS_TEST |
- FUNC_CFG_REQ_FLAGS_RING_GRP_ASSETS_TEST |
FUNC_CFG_REQ_FLAGS_STAT_CTX_ASSETS_TEST |
FUNC_CFG_REQ_FLAGS_VNIC_ASSETS_TEST;
+ if (bp->flags & BNXT_FLAG_CHIP_P5)
+ flags |= FUNC_CFG_REQ_FLAGS_RSSCOS_CTX_ASSETS_TEST;
+ else
+ flags |= FUNC_CFG_REQ_FLAGS_RING_GRP_ASSETS_TEST;
+ }
req.flags = cpu_to_le32(flags);
rc = hwrm_send_message_silent(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
@@ -4907,46 +5527,140 @@ static int bnxt_hwrm_check_rings(struct bnxt *bp, int tx_rings, int rx_rings,
cp_rings, vnics);
}
-static void bnxt_hwrm_set_coal_params(struct bnxt_coal *hw_coal,
+static void bnxt_hwrm_coal_params_qcaps(struct bnxt *bp)
+{
+ struct hwrm_ring_aggint_qcaps_output *resp = bp->hwrm_cmd_resp_addr;
+ struct bnxt_coal_cap *coal_cap = &bp->coal_cap;
+ struct hwrm_ring_aggint_qcaps_input req = {0};
+ int rc;
+
+ coal_cap->cmpl_params = BNXT_LEGACY_COAL_CMPL_PARAMS;
+ coal_cap->num_cmpl_dma_aggr_max = 63;
+ coal_cap->num_cmpl_dma_aggr_during_int_max = 63;
+ coal_cap->cmpl_aggr_dma_tmr_max = 65535;
+ coal_cap->cmpl_aggr_dma_tmr_during_int_max = 65535;
+ coal_cap->int_lat_tmr_min_max = 65535;
+ coal_cap->int_lat_tmr_max_max = 65535;
+ coal_cap->num_cmpl_aggr_int_max = 65535;
+ coal_cap->timer_units = 80;
+
+ if (bp->hwrm_spec_code < 0x10902)
+ return;
+
+ bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_RING_AGGINT_QCAPS, -1, -1);
+ mutex_lock(&bp->hwrm_cmd_lock);
+ rc = _hwrm_send_message_silent(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
+ if (!rc) {
+ coal_cap->cmpl_params = le32_to_cpu(resp->cmpl_params);
+ coal_cap->nq_params = le32_to_cpu(resp->nq_params);
+ coal_cap->num_cmpl_dma_aggr_max =
+ le16_to_cpu(resp->num_cmpl_dma_aggr_max);
+ coal_cap->num_cmpl_dma_aggr_during_int_max =
+ le16_to_cpu(resp->num_cmpl_dma_aggr_during_int_max);
+ coal_cap->cmpl_aggr_dma_tmr_max =
+ le16_to_cpu(resp->cmpl_aggr_dma_tmr_max);
+ coal_cap->cmpl_aggr_dma_tmr_during_int_max =
+ le16_to_cpu(resp->cmpl_aggr_dma_tmr_during_int_max);
+ coal_cap->int_lat_tmr_min_max =
+ le16_to_cpu(resp->int_lat_tmr_min_max);
+ coal_cap->int_lat_tmr_max_max =
+ le16_to_cpu(resp->int_lat_tmr_max_max);
+ coal_cap->num_cmpl_aggr_int_max =
+ le16_to_cpu(resp->num_cmpl_aggr_int_max);
+ coal_cap->timer_units = le16_to_cpu(resp->timer_units);
+ }
+ mutex_unlock(&bp->hwrm_cmd_lock);
+}
+
+static u16 bnxt_usec_to_coal_tmr(struct bnxt *bp, u16 usec)
+{
+ struct bnxt_coal_cap *coal_cap = &bp->coal_cap;
+
+ return usec * 1000 / coal_cap->timer_units;
+}
+
+static void bnxt_hwrm_set_coal_params(struct bnxt *bp,
+ struct bnxt_coal *hw_coal,
struct hwrm_ring_cmpl_ring_cfg_aggint_params_input *req)
{
- u16 val, tmr, max, flags;
+ struct bnxt_coal_cap *coal_cap = &bp->coal_cap;
+ u32 cmpl_params = coal_cap->cmpl_params;
+ u16 val, tmr, max, flags = 0;
max = hw_coal->bufs_per_record * 128;
if (hw_coal->budget)
max = hw_coal->bufs_per_record * hw_coal->budget;
+ max = min_t(u16, max, coal_cap->num_cmpl_aggr_int_max);
val = clamp_t(u16, hw_coal->coal_bufs, 1, max);
req->num_cmpl_aggr_int = cpu_to_le16(val);
- /* This is a 6-bit value and must not be 0, or we'll get non stop IRQ */
- val = min_t(u16, val, 63);
+ val = min_t(u16, val, coal_cap->num_cmpl_dma_aggr_max);
req->num_cmpl_dma_aggr = cpu_to_le16(val);
- /* This is a 6-bit value and must not be 0, or we'll get non stop IRQ */
- val = clamp_t(u16, hw_coal->coal_bufs_irq, 1, 63);
+ val = clamp_t(u16, hw_coal->coal_bufs_irq, 1,
+ coal_cap->num_cmpl_dma_aggr_during_int_max);
req->num_cmpl_dma_aggr_during_int = cpu_to_le16(val);
- tmr = BNXT_USEC_TO_COAL_TIMER(hw_coal->coal_ticks);
- tmr = max_t(u16, tmr, 1);
+ tmr = bnxt_usec_to_coal_tmr(bp, hw_coal->coal_ticks);
+ tmr = clamp_t(u16, tmr, 1, coal_cap->int_lat_tmr_max_max);
req->int_lat_tmr_max = cpu_to_le16(tmr);
/* min timer set to 1/2 of interrupt timer */
- val = tmr / 2;
- req->int_lat_tmr_min = cpu_to_le16(val);
+ if (cmpl_params & RING_AGGINT_QCAPS_RESP_CMPL_PARAMS_INT_LAT_TMR_MIN) {
+ val = tmr / 2;
+ val = clamp_t(u16, val, 1, coal_cap->int_lat_tmr_min_max);
+ req->int_lat_tmr_min = cpu_to_le16(val);
+ req->enables |= cpu_to_le16(BNXT_COAL_CMPL_MIN_TMR_ENABLE);
+ }
/* buf timer set to 1/4 of interrupt timer */
- val = max_t(u16, tmr / 4, 1);
+ val = clamp_t(u16, tmr / 4, 1, coal_cap->cmpl_aggr_dma_tmr_max);
req->cmpl_aggr_dma_tmr = cpu_to_le16(val);
- tmr = BNXT_USEC_TO_COAL_TIMER(hw_coal->coal_ticks_irq);
- tmr = max_t(u16, tmr, 1);
- req->cmpl_aggr_dma_tmr_during_int = cpu_to_le16(tmr);
+ if (cmpl_params &
+ RING_AGGINT_QCAPS_RESP_CMPL_PARAMS_NUM_CMPL_DMA_AGGR_DURING_INT) {
+ tmr = bnxt_usec_to_coal_tmr(bp, hw_coal->coal_ticks_irq);
+ val = clamp_t(u16, tmr, 1,
+ coal_cap->cmpl_aggr_dma_tmr_during_int_max);
+ req->cmpl_aggr_dma_tmr_during_int = cpu_to_le16(tmr);
+ req->enables |=
+ cpu_to_le16(BNXT_COAL_CMPL_AGGR_TMR_DURING_INT_ENABLE);
+ }
- flags = RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET;
- if (hw_coal->idle_thresh && hw_coal->coal_ticks < hw_coal->idle_thresh)
+ if (cmpl_params & RING_AGGINT_QCAPS_RESP_CMPL_PARAMS_TIMER_RESET)
+ flags |= RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET;
+ if ((cmpl_params & RING_AGGINT_QCAPS_RESP_CMPL_PARAMS_RING_IDLE) &&
+ hw_coal->idle_thresh && hw_coal->coal_ticks < hw_coal->idle_thresh)
flags |= RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_RING_IDLE;
req->flags = cpu_to_le16(flags);
+ req->enables |= cpu_to_le16(BNXT_COAL_CMPL_ENABLES);
+}
+
+/* Caller holds bp->hwrm_cmd_lock */
+static int __bnxt_hwrm_set_coal_nq(struct bnxt *bp, struct bnxt_napi *bnapi,
+ struct bnxt_coal *hw_coal)
+{
+ struct hwrm_ring_cmpl_ring_cfg_aggint_params_input req = {0};
+ struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
+ struct bnxt_coal_cap *coal_cap = &bp->coal_cap;
+ u32 nq_params = coal_cap->nq_params;
+ u16 tmr;
+
+ if (!(nq_params & RING_AGGINT_QCAPS_RESP_NQ_PARAMS_INT_LAT_TMR_MIN))
+ return 0;
+
+ bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS,
+ -1, -1);
+ req.ring_id = cpu_to_le16(cpr->cp_ring_struct.fw_ring_id);
+ req.flags =
+ cpu_to_le16(RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_IS_NQ);
+
+ tmr = bnxt_usec_to_coal_tmr(bp, hw_coal->coal_ticks) / 2;
+ tmr = clamp_t(u16, tmr, 1, coal_cap->int_lat_tmr_min_max);
+ req.int_lat_tmr_min = cpu_to_le16(tmr);
+ req.enables |= cpu_to_le16(BNXT_COAL_CMPL_MIN_TMR_ENABLE);
+ return _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
}
int bnxt_hwrm_set_ring_coal(struct bnxt *bp, struct bnxt_napi *bnapi)
@@ -4954,7 +5668,6 @@ int bnxt_hwrm_set_ring_coal(struct bnxt *bp, struct bnxt_napi *bnapi)
struct hwrm_ring_cmpl_ring_cfg_aggint_params_input req_rx = {0};
struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
struct bnxt_coal coal;
- unsigned int grp_idx;
/* Tick values in micro seconds.
* 1 coal_buf x bufs_per_record = 1 completion record.
@@ -4970,10 +5683,9 @@ int bnxt_hwrm_set_ring_coal(struct bnxt *bp, struct bnxt_napi *bnapi)
bnxt_hwrm_cmd_hdr_init(bp, &req_rx,
HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS, -1, -1);
- bnxt_hwrm_set_coal_params(&coal, &req_rx);
+ bnxt_hwrm_set_coal_params(bp, &coal, &req_rx);
- grp_idx = bnapi->index;
- req_rx.ring_id = cpu_to_le16(bp->grp_info[grp_idx].cp_fw_ring_id);
+ req_rx.ring_id = cpu_to_le16(bnxt_cp_ring_for_rx(bp, bnapi->rx_ring));
return hwrm_send_message(bp, &req_rx, sizeof(req_rx),
HWRM_CMD_TIMEOUT);
@@ -4990,22 +5702,46 @@ int bnxt_hwrm_set_coal(struct bnxt *bp)
bnxt_hwrm_cmd_hdr_init(bp, &req_tx,
HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS, -1, -1);
- bnxt_hwrm_set_coal_params(&bp->rx_coal, &req_rx);
- bnxt_hwrm_set_coal_params(&bp->tx_coal, &req_tx);
+ bnxt_hwrm_set_coal_params(bp, &bp->rx_coal, &req_rx);
+ bnxt_hwrm_set_coal_params(bp, &bp->tx_coal, &req_tx);
mutex_lock(&bp->hwrm_cmd_lock);
for (i = 0; i < bp->cp_nr_rings; i++) {
struct bnxt_napi *bnapi = bp->bnapi[i];
+ struct bnxt_coal *hw_coal;
+ u16 ring_id;
req = &req_rx;
- if (!bnapi->rx_ring)
+ if (!bnapi->rx_ring) {
+ ring_id = bnxt_cp_ring_for_tx(bp, bnapi->tx_ring);
req = &req_tx;
- req->ring_id = cpu_to_le16(bp->grp_info[i].cp_fw_ring_id);
+ } else {
+ ring_id = bnxt_cp_ring_for_rx(bp, bnapi->rx_ring);
+ }
+ req->ring_id = cpu_to_le16(ring_id);
rc = _hwrm_send_message(bp, req, sizeof(*req),
HWRM_CMD_TIMEOUT);
if (rc)
break;
+
+ if (!(bp->flags & BNXT_FLAG_CHIP_P5))
+ continue;
+
+ if (bnapi->rx_ring && bnapi->tx_ring) {
+ req = &req_tx;
+ ring_id = bnxt_cp_ring_for_tx(bp, bnapi->tx_ring);
+ req->ring_id = cpu_to_le16(ring_id);
+ rc = _hwrm_send_message(bp, req, sizeof(*req),
+ HWRM_CMD_TIMEOUT);
+ if (rc)
+ break;
+ }
+ if (bnapi->rx_ring)
+ hw_coal = &bp->rx_coal;
+ else
+ hw_coal = &bp->tx_coal;
+ __bnxt_hwrm_set_coal_nq(bp, bnapi, hw_coal);
}
mutex_unlock(&bp->hwrm_cmd_lock);
return rc;
@@ -5132,6 +5868,304 @@ func_qcfg_exit:
return rc;
}
+static int bnxt_hwrm_func_backing_store_qcaps(struct bnxt *bp)
+{
+ struct hwrm_func_backing_store_qcaps_input req = {0};
+ struct hwrm_func_backing_store_qcaps_output *resp =
+ bp->hwrm_cmd_resp_addr;
+ int rc;
+
+ if (bp->hwrm_spec_code < 0x10902 || BNXT_VF(bp) || bp->ctx)
+ return 0;
+
+ bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_BACKING_STORE_QCAPS, -1, -1);
+ mutex_lock(&bp->hwrm_cmd_lock);
+ rc = _hwrm_send_message_silent(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
+ if (!rc) {
+ struct bnxt_ctx_pg_info *ctx_pg;
+ struct bnxt_ctx_mem_info *ctx;
+ int i;
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx) {
+ rc = -ENOMEM;
+ goto ctx_err;
+ }
+ ctx_pg = kzalloc(sizeof(*ctx_pg) * (bp->max_q + 1), GFP_KERNEL);
+ if (!ctx_pg) {
+ kfree(ctx);
+ rc = -ENOMEM;
+ goto ctx_err;
+ }
+ for (i = 0; i < bp->max_q + 1; i++, ctx_pg++)
+ ctx->tqm_mem[i] = ctx_pg;
+
+ bp->ctx = ctx;
+ ctx->qp_max_entries = le32_to_cpu(resp->qp_max_entries);
+ ctx->qp_min_qp1_entries = le16_to_cpu(resp->qp_min_qp1_entries);
+ ctx->qp_max_l2_entries = le16_to_cpu(resp->qp_max_l2_entries);
+ ctx->qp_entry_size = le16_to_cpu(resp->qp_entry_size);
+ ctx->srq_max_l2_entries = le16_to_cpu(resp->srq_max_l2_entries);
+ ctx->srq_max_entries = le32_to_cpu(resp->srq_max_entries);
+ ctx->srq_entry_size = le16_to_cpu(resp->srq_entry_size);
+ ctx->cq_max_l2_entries = le16_to_cpu(resp->cq_max_l2_entries);
+ ctx->cq_max_entries = le32_to_cpu(resp->cq_max_entries);
+ ctx->cq_entry_size = le16_to_cpu(resp->cq_entry_size);
+ ctx->vnic_max_vnic_entries =
+ le16_to_cpu(resp->vnic_max_vnic_entries);
+ ctx->vnic_max_ring_table_entries =
+ le16_to_cpu(resp->vnic_max_ring_table_entries);
+ ctx->vnic_entry_size = le16_to_cpu(resp->vnic_entry_size);
+ ctx->stat_max_entries = le32_to_cpu(resp->stat_max_entries);
+ ctx->stat_entry_size = le16_to_cpu(resp->stat_entry_size);
+ ctx->tqm_entry_size = le16_to_cpu(resp->tqm_entry_size);
+ ctx->tqm_min_entries_per_ring =
+ le32_to_cpu(resp->tqm_min_entries_per_ring);
+ ctx->tqm_max_entries_per_ring =
+ le32_to_cpu(resp->tqm_max_entries_per_ring);
+ ctx->tqm_entries_multiple = resp->tqm_entries_multiple;
+ if (!ctx->tqm_entries_multiple)
+ ctx->tqm_entries_multiple = 1;
+ ctx->mrav_max_entries = le32_to_cpu(resp->mrav_max_entries);
+ ctx->mrav_entry_size = le16_to_cpu(resp->mrav_entry_size);
+ ctx->tim_entry_size = le16_to_cpu(resp->tim_entry_size);
+ ctx->tim_max_entries = le32_to_cpu(resp->tim_max_entries);
+ } else {
+ rc = 0;
+ }
+ctx_err:
+ mutex_unlock(&bp->hwrm_cmd_lock);
+ return rc;
+}
+
+static void bnxt_hwrm_set_pg_attr(struct bnxt_ring_mem_info *rmem, u8 *pg_attr,
+ __le64 *pg_dir)
+{
+ u8 pg_size = 0;
+
+ if (BNXT_PAGE_SHIFT == 13)
+ pg_size = 1 << 4;
+ else if (BNXT_PAGE_SIZE == 16)
+ pg_size = 2 << 4;
+
+ *pg_attr = pg_size;
+ if (rmem->nr_pages > 1) {
+ *pg_attr |= 1;
+ *pg_dir = cpu_to_le64(rmem->pg_tbl_map);
+ } else {
+ *pg_dir = cpu_to_le64(rmem->dma_arr[0]);
+ }
+}
+
+#define FUNC_BACKING_STORE_CFG_REQ_DFLT_ENABLES \
+ (FUNC_BACKING_STORE_CFG_REQ_ENABLES_QP | \
+ FUNC_BACKING_STORE_CFG_REQ_ENABLES_SRQ | \
+ FUNC_BACKING_STORE_CFG_REQ_ENABLES_CQ | \
+ FUNC_BACKING_STORE_CFG_REQ_ENABLES_VNIC | \
+ FUNC_BACKING_STORE_CFG_REQ_ENABLES_STAT)
+
+static int bnxt_hwrm_func_backing_store_cfg(struct bnxt *bp, u32 enables)
+{
+ struct hwrm_func_backing_store_cfg_input req = {0};
+ struct bnxt_ctx_mem_info *ctx = bp->ctx;
+ struct bnxt_ctx_pg_info *ctx_pg;
+ __le32 *num_entries;
+ __le64 *pg_dir;
+ u8 *pg_attr;
+ int i, rc;
+ u32 ena;
+
+ if (!ctx)
+ return 0;
+
+ bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_BACKING_STORE_CFG, -1, -1);
+ req.enables = cpu_to_le32(enables);
+
+ if (enables & FUNC_BACKING_STORE_CFG_REQ_ENABLES_QP) {
+ ctx_pg = &ctx->qp_mem;
+ req.qp_num_entries = cpu_to_le32(ctx_pg->entries);
+ req.qp_num_qp1_entries = cpu_to_le16(ctx->qp_min_qp1_entries);
+ req.qp_num_l2_entries = cpu_to_le16(ctx->qp_max_l2_entries);
+ req.qp_entry_size = cpu_to_le16(ctx->qp_entry_size);
+ bnxt_hwrm_set_pg_attr(&ctx_pg->ring_mem,
+ &req.qpc_pg_size_qpc_lvl,
+ &req.qpc_page_dir);
+ }
+ if (enables & FUNC_BACKING_STORE_CFG_REQ_ENABLES_SRQ) {
+ ctx_pg = &ctx->srq_mem;
+ req.srq_num_entries = cpu_to_le32(ctx_pg->entries);
+ req.srq_num_l2_entries = cpu_to_le16(ctx->srq_max_l2_entries);
+ req.srq_entry_size = cpu_to_le16(ctx->srq_entry_size);
+ bnxt_hwrm_set_pg_attr(&ctx_pg->ring_mem,
+ &req.srq_pg_size_srq_lvl,
+ &req.srq_page_dir);
+ }
+ if (enables & FUNC_BACKING_STORE_CFG_REQ_ENABLES_CQ) {
+ ctx_pg = &ctx->cq_mem;
+ req.cq_num_entries = cpu_to_le32(ctx_pg->entries);
+ req.cq_num_l2_entries = cpu_to_le16(ctx->cq_max_l2_entries);
+ req.cq_entry_size = cpu_to_le16(ctx->cq_entry_size);
+ bnxt_hwrm_set_pg_attr(&ctx_pg->ring_mem, &req.cq_pg_size_cq_lvl,
+ &req.cq_page_dir);
+ }
+ if (enables & FUNC_BACKING_STORE_CFG_REQ_ENABLES_VNIC) {
+ ctx_pg = &ctx->vnic_mem;
+ req.vnic_num_vnic_entries =
+ cpu_to_le16(ctx->vnic_max_vnic_entries);
+ req.vnic_num_ring_table_entries =
+ cpu_to_le16(ctx->vnic_max_ring_table_entries);
+ req.vnic_entry_size = cpu_to_le16(ctx->vnic_entry_size);
+ bnxt_hwrm_set_pg_attr(&ctx_pg->ring_mem,
+ &req.vnic_pg_size_vnic_lvl,
+ &req.vnic_page_dir);
+ }
+ if (enables & FUNC_BACKING_STORE_CFG_REQ_ENABLES_STAT) {
+ ctx_pg = &ctx->stat_mem;
+ req.stat_num_entries = cpu_to_le32(ctx->stat_max_entries);
+ req.stat_entry_size = cpu_to_le16(ctx->stat_entry_size);
+ bnxt_hwrm_set_pg_attr(&ctx_pg->ring_mem,
+ &req.stat_pg_size_stat_lvl,
+ &req.stat_page_dir);
+ }
+ for (i = 0, num_entries = &req.tqm_sp_num_entries,
+ pg_attr = &req.tqm_sp_pg_size_tqm_sp_lvl,
+ pg_dir = &req.tqm_sp_page_dir,
+ ena = FUNC_BACKING_STORE_CFG_REQ_ENABLES_TQM_SP;
+ i < 9; i++, num_entries++, pg_attr++, pg_dir++, ena <<= 1) {
+ if (!(enables & ena))
+ continue;
+
+ req.tqm_entry_size = cpu_to_le16(ctx->tqm_entry_size);
+ ctx_pg = ctx->tqm_mem[i];
+ *num_entries = cpu_to_le32(ctx_pg->entries);
+ bnxt_hwrm_set_pg_attr(&ctx_pg->ring_mem, pg_attr, pg_dir);
+ }
+ rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
+ if (rc)
+ rc = -EIO;
+ return rc;
+}
+
+static int bnxt_alloc_ctx_mem_blk(struct bnxt *bp,
+ struct bnxt_ctx_pg_info *ctx_pg, u32 mem_size)
+{
+ struct bnxt_ring_mem_info *rmem = &ctx_pg->ring_mem;
+
+ if (!mem_size)
+ return 0;
+
+ rmem->nr_pages = DIV_ROUND_UP(mem_size, BNXT_PAGE_SIZE);
+ if (rmem->nr_pages > MAX_CTX_PAGES) {
+ rmem->nr_pages = 0;
+ return -EINVAL;
+ }
+ rmem->page_size = BNXT_PAGE_SIZE;
+ rmem->pg_arr = ctx_pg->ctx_pg_arr;
+ rmem->dma_arr = ctx_pg->ctx_dma_arr;
+ rmem->flags = BNXT_RMEM_VALID_PTE_FLAG;
+ return bnxt_alloc_ring(bp, rmem);
+}
+
+static void bnxt_free_ctx_mem(struct bnxt *bp)
+{
+ struct bnxt_ctx_mem_info *ctx = bp->ctx;
+ int i;
+
+ if (!ctx)
+ return;
+
+ if (ctx->tqm_mem[0]) {
+ for (i = 0; i < bp->max_q + 1; i++)
+ bnxt_free_ring(bp, &ctx->tqm_mem[i]->ring_mem);
+ kfree(ctx->tqm_mem[0]);
+ ctx->tqm_mem[0] = NULL;
+ }
+
+ bnxt_free_ring(bp, &ctx->stat_mem.ring_mem);
+ bnxt_free_ring(bp, &ctx->vnic_mem.ring_mem);
+ bnxt_free_ring(bp, &ctx->cq_mem.ring_mem);
+ bnxt_free_ring(bp, &ctx->srq_mem.ring_mem);
+ bnxt_free_ring(bp, &ctx->qp_mem.ring_mem);
+ ctx->flags &= ~BNXT_CTX_FLAG_INITED;
+}
+
+static int bnxt_alloc_ctx_mem(struct bnxt *bp)
+{
+ struct bnxt_ctx_pg_info *ctx_pg;
+ struct bnxt_ctx_mem_info *ctx;
+ u32 mem_size, ena, entries;
+ int i, rc;
+
+ rc = bnxt_hwrm_func_backing_store_qcaps(bp);
+ if (rc) {
+ netdev_err(bp->dev, "Failed querying context mem capability, rc = %d.\n",
+ rc);
+ return rc;
+ }
+ ctx = bp->ctx;
+ if (!ctx || (ctx->flags & BNXT_CTX_FLAG_INITED))
+ return 0;
+
+ ctx_pg = &ctx->qp_mem;
+ ctx_pg->entries = ctx->qp_min_qp1_entries + ctx->qp_max_l2_entries;
+ mem_size = ctx->qp_entry_size * ctx_pg->entries;
+ rc = bnxt_alloc_ctx_mem_blk(bp, ctx_pg, mem_size);
+ if (rc)
+ return rc;
+
+ ctx_pg = &ctx->srq_mem;
+ ctx_pg->entries = ctx->srq_max_l2_entries;
+ mem_size = ctx->srq_entry_size * ctx_pg->entries;
+ rc = bnxt_alloc_ctx_mem_blk(bp, ctx_pg, mem_size);
+ if (rc)
+ return rc;
+
+ ctx_pg = &ctx->cq_mem;
+ ctx_pg->entries = ctx->cq_max_l2_entries;
+ mem_size = ctx->cq_entry_size * ctx_pg->entries;
+ rc = bnxt_alloc_ctx_mem_blk(bp, ctx_pg, mem_size);
+ if (rc)
+ return rc;
+
+ ctx_pg = &ctx->vnic_mem;
+ ctx_pg->entries = ctx->vnic_max_vnic_entries +
+ ctx->vnic_max_ring_table_entries;
+ mem_size = ctx->vnic_entry_size * ctx_pg->entries;
+ rc = bnxt_alloc_ctx_mem_blk(bp, ctx_pg, mem_size);
+ if (rc)
+ return rc;
+
+ ctx_pg = &ctx->stat_mem;
+ ctx_pg->entries = ctx->stat_max_entries;
+ mem_size = ctx->stat_entry_size * ctx_pg->entries;
+ rc = bnxt_alloc_ctx_mem_blk(bp, ctx_pg, mem_size);
+ if (rc)
+ return rc;
+
+ entries = ctx->qp_max_l2_entries;
+ entries = roundup(entries, ctx->tqm_entries_multiple);
+ entries = clamp_t(u32, entries, ctx->tqm_min_entries_per_ring,
+ ctx->tqm_max_entries_per_ring);
+ for (i = 0, ena = 0; i < bp->max_q + 1; i++) {
+ ctx_pg = ctx->tqm_mem[i];
+ ctx_pg->entries = entries;
+ mem_size = ctx->tqm_entry_size * entries;
+ rc = bnxt_alloc_ctx_mem_blk(bp, ctx_pg, mem_size);
+ if (rc)
+ return rc;
+ ena |= FUNC_BACKING_STORE_CFG_REQ_ENABLES_TQM_SP << i;
+ }
+ ena |= FUNC_BACKING_STORE_CFG_REQ_DFLT_ENABLES;
+ rc = bnxt_hwrm_func_backing_store_cfg(bp, ena);
+ if (rc)
+ netdev_err(bp->dev, "Failed configuring context mem, rc = %d.\n",
+ rc);
+ else
+ ctx->flags |= BNXT_CTX_FLAG_INITED;
+
+ return 0;
+}
+
int bnxt_hwrm_func_resc_qcaps(struct bnxt *bp, bool all)
{
struct hwrm_func_resource_qcaps_output *resp = bp->hwrm_cmd_resp_addr;
@@ -5170,6 +6204,13 @@ int bnxt_hwrm_func_resc_qcaps(struct bnxt *bp, bool all)
hw_resc->min_stat_ctxs = le16_to_cpu(resp->min_stat_ctx);
hw_resc->max_stat_ctxs = le16_to_cpu(resp->max_stat_ctx);
+ if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ u16 max_msix = le16_to_cpu(resp->max_msix);
+
+ hw_resc->max_irqs = min_t(u16, hw_resc->max_irqs, max_msix);
+ hw_resc->max_hw_ring_grps = hw_resc->max_rx_rings;
+ }
+
if (BNXT_PF(bp)) {
struct bnxt_pf_info *pf = &bp->pf;
@@ -5259,6 +6300,9 @@ static int bnxt_hwrm_func_qcaps(struct bnxt *bp)
if (rc)
return rc;
if (bp->hwrm_spec_code >= 0x10803) {
+ rc = bnxt_alloc_ctx_mem(bp);
+ if (rc)
+ return rc;
rc = bnxt_hwrm_func_resc_qcaps(bp, true);
if (!rc)
bp->fw_cap |= BNXT_FW_CAP_NEW_RM;
@@ -5303,13 +6347,15 @@ static int bnxt_hwrm_queue_qportcfg(struct bnxt *bp)
no_rdma = !(bp->flags & BNXT_FLAG_ROCE_CAP);
qptr = &resp->queue_id0;
for (i = 0, j = 0; i < bp->max_tc; i++) {
- bp->q_info[j].queue_id = *qptr++;
+ bp->q_info[j].queue_id = *qptr;
+ bp->q_ids[i] = *qptr++;
bp->q_info[j].queue_profile = *qptr++;
bp->tc_to_qidx[j] = j;
if (!BNXT_CNPQ(bp->q_info[j].queue_profile) ||
(no_rdma && BNXT_PF(bp)))
j++;
}
+ bp->max_q = bp->max_tc;
bp->max_tc = max_t(u8, j, 1);
if (resp->queue_cfg_info & QUEUE_QPORTCFG_RESP_QUEUE_CFG_INFO_ASYM_CFG)
@@ -5359,8 +6405,12 @@ static int bnxt_hwrm_ver_get(struct bnxt *bp)
if (!bp->hwrm_cmd_timeout)
bp->hwrm_cmd_timeout = DFLT_HWRM_CMD_TIMEOUT;
- if (resp->hwrm_intf_maj_8b >= 1)
+ if (resp->hwrm_intf_maj_8b >= 1) {
bp->hwrm_max_req_len = le16_to_cpu(resp->max_req_win_len);
+ bp->hwrm_max_ext_req_len = le16_to_cpu(resp->max_ext_req_len);
+ }
+ if (bp->hwrm_max_ext_req_len < HWRM_MAX_REQ_LEN)
+ bp->hwrm_max_ext_req_len = HWRM_MAX_REQ_LEN;
bp->chip_num = le16_to_cpu(resp->chip_num);
if (bp->chip_num == CHIP_NUM_58700 && !resp->chip_rev &&
@@ -5417,8 +6467,10 @@ static int bnxt_hwrm_port_qstats(struct bnxt *bp)
static int bnxt_hwrm_port_qstats_ext(struct bnxt *bp)
{
+ struct hwrm_port_qstats_ext_output *resp = bp->hwrm_cmd_resp_addr;
struct hwrm_port_qstats_ext_input req = {0};
struct bnxt_pf_info *pf = &bp->pf;
+ int rc;
if (!(bp->flags & BNXT_FLAG_PORT_STATS_EXT))
return 0;
@@ -5427,7 +6479,19 @@ static int bnxt_hwrm_port_qstats_ext(struct bnxt *bp)
req.port_id = cpu_to_le16(pf->port_id);
req.rx_stat_size = cpu_to_le16(sizeof(struct rx_port_stats_ext));
req.rx_stat_host_addr = cpu_to_le64(bp->hw_rx_port_stats_ext_map);
- return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
+ req.tx_stat_size = cpu_to_le16(sizeof(struct tx_port_stats_ext));
+ req.tx_stat_host_addr = cpu_to_le64(bp->hw_tx_port_stats_ext_map);
+ mutex_lock(&bp->hwrm_cmd_lock);
+ rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
+ if (!rc) {
+ bp->fw_rx_stats_ext_size = le16_to_cpu(resp->rx_stat_size) / 8;
+ bp->fw_tx_stats_ext_size = le16_to_cpu(resp->tx_stat_size) / 8;
+ } else {
+ bp->fw_rx_stats_ext_size = 0;
+ bp->fw_tx_stats_ext_size = 0;
+ }
+ mutex_unlock(&bp->hwrm_cmd_lock);
+ return rc;
}
static void bnxt_hwrm_free_tunnel_ports(struct bnxt *bp)
@@ -5532,7 +6596,7 @@ static int bnxt_hwrm_set_cache_line_size(struct bnxt *bp, int size)
return rc;
}
-static int bnxt_setup_vnic(struct bnxt *bp, u16 vnic_id)
+static int __bnxt_setup_vnic(struct bnxt *bp, u16 vnic_id)
{
struct bnxt_vnic_info *vnic = &bp->vnic_info[vnic_id];
int rc;
@@ -5588,6 +6652,53 @@ vnic_setup_err:
return rc;
}
+static int __bnxt_setup_vnic_p5(struct bnxt *bp, u16 vnic_id)
+{
+ int rc, i, nr_ctxs;
+
+ nr_ctxs = DIV_ROUND_UP(bp->rx_nr_rings, 64);
+ for (i = 0; i < nr_ctxs; i++) {
+ rc = bnxt_hwrm_vnic_ctx_alloc(bp, vnic_id, i);
+ if (rc) {
+ netdev_err(bp->dev, "hwrm vnic %d ctx %d alloc failure rc: %x\n",
+ vnic_id, i, rc);
+ break;
+ }
+ bp->rsscos_nr_ctxs++;
+ }
+ if (i < nr_ctxs)
+ return -ENOMEM;
+
+ rc = bnxt_hwrm_vnic_set_rss_p5(bp, vnic_id, true);
+ if (rc) {
+ netdev_err(bp->dev, "hwrm vnic %d set rss failure rc: %d\n",
+ vnic_id, rc);
+ return rc;
+ }
+ rc = bnxt_hwrm_vnic_cfg(bp, vnic_id);
+ if (rc) {
+ netdev_err(bp->dev, "hwrm vnic %d cfg failure rc: %x\n",
+ vnic_id, rc);
+ return rc;
+ }
+ if (bp->flags & BNXT_FLAG_AGG_RINGS) {
+ rc = bnxt_hwrm_vnic_set_hds(bp, vnic_id);
+ if (rc) {
+ netdev_err(bp->dev, "hwrm vnic %d set hds failure rc: %x\n",
+ vnic_id, rc);
+ }
+ }
+ return rc;
+}
+
+static int bnxt_setup_vnic(struct bnxt *bp, u16 vnic_id)
+{
+ if (bp->flags & BNXT_FLAG_CHIP_P5)
+ return __bnxt_setup_vnic_p5(bp, vnic_id);
+ else
+ return __bnxt_setup_vnic(bp, vnic_id);
+}
+
static int bnxt_alloc_rfs_vnics(struct bnxt *bp)
{
#ifdef CONFIG_RFS_ACCEL
@@ -6206,12 +7317,15 @@ static void bnxt_init_napi(struct bnxt *bp)
struct bnxt_napi *bnapi;
if (bp->flags & BNXT_FLAG_USING_MSIX) {
- if (BNXT_CHIP_TYPE_NITRO_A0(bp))
+ int (*poll_fn)(struct napi_struct *, int) = bnxt_poll;
+
+ if (bp->flags & BNXT_FLAG_CHIP_P5)
+ poll_fn = bnxt_poll_p5;
+ else if (BNXT_CHIP_TYPE_NITRO_A0(bp))
cp_nr_rings--;
for (i = 0; i < cp_nr_rings; i++) {
bnapi = bp->bnapi[i];
- netif_napi_add(bp->dev, &bnapi->napi,
- bnxt_poll, 64);
+ netif_napi_add(bp->dev, &bnapi->napi, poll_fn, 64);
}
if (BNXT_CHIP_TYPE_NITRO_A0(bp)) {
bnapi = bp->bnapi[cp_nr_rings];
@@ -6968,10 +8082,10 @@ static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)
netdev_err(bp->dev, "Failed to reserve default rings at open\n");
return rc;
}
- rc = bnxt_reserve_rings(bp);
- if (rc)
- return rc;
}
+ rc = bnxt_reserve_rings(bp);
+ if (rc)
+ return rc;
if ((bp->flags & BNXT_FLAG_RFS) &&
!(bp->flags & BNXT_FLAG_USING_MSIX)) {
/* disable RFS if falling back to INTA */
@@ -7443,6 +8557,8 @@ static bool bnxt_can_reserve_rings(struct bnxt *bp)
/* If the chip and firmware supports RFS */
static bool bnxt_rfs_supported(struct bnxt *bp)
{
+ if (bp->flags & BNXT_FLAG_CHIP_P5)
+ return false;
if (BNXT_PF(bp) && !BNXT_CHIP_TYPE_NITRO_A0(bp))
return true;
if (bp->flags & BNXT_FLAG_NEW_RSS_CAP)
@@ -7456,6 +8572,8 @@ static bool bnxt_rfs_capable(struct bnxt *bp)
#ifdef CONFIG_RFS_ACCEL
int vnics, max_vnics, max_rss_ctxs;
+ if (bp->flags & BNXT_FLAG_CHIP_P5)
+ return false;
if (!(bp->flags & BNXT_FLAG_MSIX_CAP) || !bnxt_can_reserve_rings(bp))
return false;
@@ -7976,6 +9094,9 @@ static int bnxt_init_board(struct pci_dev *pdev, struct net_device *dev)
INIT_WORK(&bp->sp_task, bnxt_sp_task);
spin_lock_init(&bp->ntp_fltr_lock);
+#if BITS_PER_LONG == 32
+ spin_lock_init(&bp->db_lock);
+#endif
bp->rx_ring_size = BNXT_DEFAULT_RX_RING_SIZE;
bp->tx_ring_size = BNXT_DEFAULT_TX_RING_SIZE;
@@ -8541,6 +9662,9 @@ static void bnxt_remove_one(struct pci_dev *pdev)
bnxt_dcb_free(bp);
kfree(bp->edev);
bp->edev = NULL;
+ bnxt_free_ctx_mem(bp);
+ kfree(bp->ctx);
+ bp->ctx = NULL;
bnxt_cleanup_pci(bp);
free_netdev(dev);
}
@@ -8614,7 +9738,7 @@ static void _bnxt_get_max_rings(struct bnxt *bp, int *max_rx, int *max_tx,
*max_tx = hw_resc->max_tx_rings;
*max_rx = hw_resc->max_rx_rings;
*max_cp = min_t(int, bnxt_get_max_func_cp_rings_for_en(bp),
- hw_resc->max_irqs);
+ hw_resc->max_irqs - bnxt_get_ulp_msix_num(bp));
*max_cp = min_t(int, *max_cp, hw_resc->max_stat_ctxs);
max_ring_grps = hw_resc->max_hw_ring_grps;
if (BNXT_CHIP_TYPE_NITRO_A0(bp) && BNXT_PF(bp)) {
@@ -8846,6 +9970,7 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
return -ENOMEM;
bp = netdev_priv(dev);
+ bnxt_set_max_func_irqs(bp, max_irqs);
if (bnxt_vf_pciid(ent->driver_data))
bp->flags |= BNXT_FLAG_VF;
@@ -8872,12 +9997,16 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc)
goto init_err_pci_clean;
- if (bp->fw_cap & BNXT_FW_CAP_SHORT_CMD) {
+ if ((bp->fw_cap & BNXT_FW_CAP_SHORT_CMD) ||
+ bp->hwrm_max_ext_req_len > BNXT_HWRM_MAX_REQ_LEN) {
rc = bnxt_alloc_hwrm_short_cmd_req(bp);
if (rc)
goto init_err_pci_clean;
}
+ if (BNXT_CHIP_P5(bp))
+ bp->flags |= BNXT_FLAG_CHIP_P5;
+
rc = bnxt_hwrm_func_reset(bp);
if (rc)
goto init_err_pci_clean;
@@ -8892,7 +10021,7 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
NETIF_F_GSO_PARTIAL | NETIF_F_RXHASH |
NETIF_F_RXCSUM | NETIF_F_GRO;
- if (!BNXT_CHIP_TYPE_NITRO_A0(bp))
+ if (BNXT_SUPPORTS_TPA(bp))
dev->hw_features |= NETIF_F_LRO;
dev->hw_enc_features =
@@ -8906,7 +10035,7 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
dev->vlan_features = dev->hw_features | NETIF_F_HIGHDMA;
dev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX |
NETIF_F_HW_VLAN_STAG_RX | NETIF_F_HW_VLAN_STAG_TX;
- if (!BNXT_CHIP_TYPE_NITRO_A0(bp))
+ if (BNXT_SUPPORTS_TPA(bp))
dev->hw_features |= NETIF_F_GRO_HW;
dev->features |= dev->hw_features | NETIF_F_HIGHDMA;
if (dev->features & NETIF_F_GRO_HW)
@@ -8917,10 +10046,12 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
init_waitqueue_head(&bp->sriov_cfg_wait);
mutex_init(&bp->sriov_lock);
#endif
- bp->gro_func = bnxt_gro_func_5730x;
- if (BNXT_CHIP_P4_PLUS(bp))
- bp->gro_func = bnxt_gro_func_5731x;
- else
+ if (BNXT_SUPPORTS_TPA(bp)) {
+ bp->gro_func = bnxt_gro_func_5730x;
+ if (BNXT_CHIP_P4(bp))
+ bp->gro_func = bnxt_gro_func_5731x;
+ }
+ if (!BNXT_CHIP_P4_PLUS(bp))
bp->flags |= BNXT_FLAG_DOUBLE_DB;
rc = bnxt_hwrm_func_drv_rgtr(bp);
@@ -8933,6 +10064,13 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
bp->ulp_probe = bnxt_ulp_probe;
+ rc = bnxt_hwrm_queue_qportcfg(bp);
+ if (rc) {
+ netdev_err(bp->dev, "hwrm query qportcfg failure rc: %x\n",
+ rc);
+ rc = -1;
+ goto init_err_pci_clean;
+ }
/* Get the MAX capabilities for this function */
rc = bnxt_hwrm_func_qcaps(bp);
if (rc) {
@@ -8947,13 +10085,6 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
rc = -EADDRNOTAVAIL;
goto init_err_pci_clean;
}
- rc = bnxt_hwrm_queue_qportcfg(bp);
- if (rc) {
- netdev_err(bp->dev, "hwrm query qportcfg failure rc: %x\n",
- rc);
- rc = -1;
- goto init_err_pci_clean;
- }
bnxt_hwrm_func_qcfg(bp);
bnxt_hwrm_port_led_qcaps(bp);
@@ -8971,7 +10102,6 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
bnxt_set_rx_skb_mode(bp, false);
bnxt_set_tpa_flags(bp);
bnxt_set_ring_params(bp);
- bnxt_set_max_func_irqs(bp, max_irqs);
rc = bnxt_set_dflt_rings(bp, true);
if (rc) {
netdev_err(bp->dev, "Not enough rings available.\n");
@@ -8984,7 +10114,7 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4 |
VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6 |
VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6;
- if (BNXT_CHIP_P4_PLUS(bp) && bp->hwrm_spec_code >= 0x10501) {
+ if (BNXT_CHIP_P4(bp) && bp->hwrm_spec_code >= 0x10501) {
bp->flags |= BNXT_FLAG_UDP_RSS_CAP;
bp->rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4 |
VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6;
@@ -9019,6 +10149,8 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
bnxt_hwrm_set_cache_line_size(bp, cache_line_size());
+ bnxt_hwrm_coal_params_qcaps(bp);
+
if (BNXT_PF(bp)) {
if (!bnxt_pf_wq) {
bnxt_pf_wq =
@@ -9050,6 +10182,10 @@ init_err_cleanup_tc:
bnxt_clear_int_mode(bp);
init_err_pci_clean:
+ bnxt_free_hwrm_resources(bp);
+ bnxt_free_ctx_mem(bp);
+ kfree(bp->ctx);
+ bp->ctx = NULL;
bnxt_cleanup_pci(bp);
init_err_free:
@@ -9218,13 +10354,6 @@ static pci_ers_result_t bnxt_io_slot_reset(struct pci_dev *pdev)
rtnl_unlock();
- err = pci_cleanup_aer_uncorrect_error_status(pdev);
- if (err) {
- dev_err(&pdev->dev,
- "pci_cleanup_aer_uncorrect_error_status failed 0x%0x\n",
- err); /* non-fatal, continue */
- }
-
return PCI_ERS_RESULT_RECOVERED;
}
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
index bde384630a75..498b373c992d 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
@@ -12,11 +12,11 @@
#define BNXT_H
#define DRV_MODULE_NAME "bnxt_en"
-#define DRV_MODULE_VERSION "1.9.2"
+#define DRV_MODULE_VERSION "1.10.0"
#define DRV_VER_MAJ 1
-#define DRV_VER_MIN 9
-#define DRV_VER_UPD 2
+#define DRV_VER_MIN 10
+#define DRV_VER_UPD 0
#include <linux/interrupt.h>
#include <linux/rhashtable.h>
@@ -403,6 +403,19 @@ struct rx_tpa_end_cmp_ext {
((rx_tpa_end_ext)->rx_tpa_end_cmp_errors_v2 & \
cpu_to_le32(RX_TPA_END_CMP_ERRORS))
+struct nqe_cn {
+ __le16 type;
+ #define NQ_CN_TYPE_MASK 0x3fUL
+ #define NQ_CN_TYPE_SFT 0
+ #define NQ_CN_TYPE_CQ_NOTIFICATION 0x30UL
+ #define NQ_CN_TYPE_LAST NQ_CN_TYPE_CQ_NOTIFICATION
+ __le16 reserved16;
+ __le32 cq_handle_low;
+ __le32 v;
+ #define NQ_CN_V 0x1UL
+ __le32 cq_handle_high;
+};
+
#define DB_IDX_MASK 0xffffff
#define DB_IDX_VALID (0x1 << 26)
#define DB_IRQ_DIS (0x1 << 27)
@@ -416,6 +429,25 @@ struct rx_tpa_end_cmp_ext {
#define BNXT_MIN_ROCE_CP_RINGS 2
#define BNXT_MIN_ROCE_STAT_CTXS 1
+/* 64-bit doorbell */
+#define DBR_INDEX_MASK 0x0000000000ffffffULL
+#define DBR_XID_MASK 0x000fffff00000000ULL
+#define DBR_XID_SFT 32
+#define DBR_PATH_L2 (0x1ULL << 56)
+#define DBR_TYPE_SQ (0x0ULL << 60)
+#define DBR_TYPE_RQ (0x1ULL << 60)
+#define DBR_TYPE_SRQ (0x2ULL << 60)
+#define DBR_TYPE_SRQ_ARM (0x3ULL << 60)
+#define DBR_TYPE_CQ (0x4ULL << 60)
+#define DBR_TYPE_CQ_ARMSE (0x5ULL << 60)
+#define DBR_TYPE_CQ_ARMALL (0x6ULL << 60)
+#define DBR_TYPE_CQ_ARMENA (0x7ULL << 60)
+#define DBR_TYPE_SRQ_ARMENA (0x8ULL << 60)
+#define DBR_TYPE_CQ_CUTOFF_ACK (0x9ULL << 60)
+#define DBR_TYPE_NQ (0xaULL << 60)
+#define DBR_TYPE_NQ_ARM (0xbULL << 60)
+#define DBR_TYPE_NULL (0xfULL << 60)
+
#define INVALID_HW_RING_ID ((u16)-1)
/* The hardware supports certain page sizes. Use the supported page sizes
@@ -505,6 +537,9 @@ struct rx_tpa_end_cmp_ext {
(!!((agg)->rx_agg_cmp_v & cpu_to_le32(RX_AGG_CMP_V)) == \
!((raw_cons) & bp->cp_bit))
+#define NQ_CMP_VALID(nqcmp, raw_cons) \
+ (!!((nqcmp)->v & cpu_to_le32(NQ_CN_V)) == !((raw_cons) & bp->cp_bit))
+
#define TX_CMP_TYPE(txcmp) \
(le32_to_cpu((txcmp)->tx_cmp_flags_type) & CMP_TYPE)
@@ -577,9 +612,13 @@ struct bnxt_sw_rx_agg_bd {
dma_addr_t mapping;
};
-struct bnxt_ring_struct {
+struct bnxt_ring_mem_info {
int nr_pages;
int page_size;
+ u32 flags;
+#define BNXT_RMEM_VALID_PTE_FLAG 1
+#define BNXT_RMEM_RING_PTE_FLAG 2
+
void **pg_arr;
dma_addr_t *dma_arr;
@@ -588,12 +627,17 @@ struct bnxt_ring_struct {
int vmem_size;
void **vmem;
+};
+
+struct bnxt_ring_struct {
+ struct bnxt_ring_mem_info ring_mem;
u16 fw_ring_id; /* Ring id filled by Chimp FW */
union {
u16 grp_idx;
u16 map_idx; /* Used by cmpl rings */
};
+ u32 handle;
u8 queue_id;
};
@@ -609,12 +653,20 @@ struct tx_push_buffer {
u32 data[25];
};
+struct bnxt_db_info {
+ void __iomem *doorbell;
+ union {
+ u64 db_key64;
+ u32 db_key32;
+ };
+};
+
struct bnxt_tx_ring_info {
struct bnxt_napi *bnapi;
u16 tx_prod;
u16 tx_cons;
u16 txq_index;
- void __iomem *tx_doorbell;
+ struct bnxt_db_info tx_db;
struct tx_bd *tx_desc_ring[MAX_TX_PAGES];
struct bnxt_sw_tx_bd *tx_buf_ring;
@@ -631,6 +683,42 @@ struct bnxt_tx_ring_info {
struct bnxt_ring_struct tx_ring_struct;
};
+#define BNXT_LEGACY_COAL_CMPL_PARAMS \
+ (RING_AGGINT_QCAPS_RESP_CMPL_PARAMS_INT_LAT_TMR_MIN | \
+ RING_AGGINT_QCAPS_RESP_CMPL_PARAMS_INT_LAT_TMR_MAX | \
+ RING_AGGINT_QCAPS_RESP_CMPL_PARAMS_TIMER_RESET | \
+ RING_AGGINT_QCAPS_RESP_CMPL_PARAMS_RING_IDLE | \
+ RING_AGGINT_QCAPS_RESP_CMPL_PARAMS_NUM_CMPL_DMA_AGGR | \
+ RING_AGGINT_QCAPS_RESP_CMPL_PARAMS_NUM_CMPL_DMA_AGGR_DURING_INT | \
+ RING_AGGINT_QCAPS_RESP_CMPL_PARAMS_CMPL_AGGR_DMA_TMR | \
+ RING_AGGINT_QCAPS_RESP_CMPL_PARAMS_CMPL_AGGR_DMA_TMR_DURING_INT | \
+ RING_AGGINT_QCAPS_RESP_CMPL_PARAMS_NUM_CMPL_AGGR_INT)
+
+#define BNXT_COAL_CMPL_ENABLES \
+ (RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_ENABLES_NUM_CMPL_DMA_AGGR | \
+ RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_ENABLES_CMPL_AGGR_DMA_TMR | \
+ RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_ENABLES_INT_LAT_TMR_MAX | \
+ RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_ENABLES_NUM_CMPL_AGGR_INT)
+
+#define BNXT_COAL_CMPL_MIN_TMR_ENABLE \
+ RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_ENABLES_INT_LAT_TMR_MIN
+
+#define BNXT_COAL_CMPL_AGGR_TMR_DURING_INT_ENABLE \
+ RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_ENABLES_NUM_CMPL_DMA_AGGR_DURING_INT
+
+struct bnxt_coal_cap {
+ u32 cmpl_params;
+ u32 nq_params;
+ u16 num_cmpl_dma_aggr_max;
+ u16 num_cmpl_dma_aggr_during_int_max;
+ u16 cmpl_aggr_dma_tmr_max;
+ u16 cmpl_aggr_dma_tmr_during_int_max;
+ u16 int_lat_tmr_min_max;
+ u16 int_lat_tmr_max_max;
+ u16 num_cmpl_aggr_int_max;
+ u16 timer_units;
+};
+
struct bnxt_coal {
u16 coal_ticks;
u16 coal_ticks_irq;
@@ -675,8 +763,8 @@ struct bnxt_rx_ring_info {
u16 rx_agg_prod;
u16 rx_sw_agg_prod;
u16 rx_next_cons;
- void __iomem *rx_doorbell;
- void __iomem *rx_agg_doorbell;
+ struct bnxt_db_info rx_db;
+ struct bnxt_db_info rx_agg_db;
struct bpf_prog *xdp_prog;
@@ -703,8 +791,12 @@ struct bnxt_rx_ring_info {
};
struct bnxt_cp_ring_info {
+ struct bnxt_napi *bnapi;
u32 cp_raw_cons;
- void __iomem *cp_doorbell;
+ struct bnxt_db_info cp_db;
+
+ u8 had_work_done:1;
+ u8 has_more_work:1;
struct bnxt_coal rx_ring_coal;
u64 rx_packets;
@@ -713,7 +805,10 @@ struct bnxt_cp_ring_info {
struct net_dim dim;
- struct tx_cmp *cp_desc_ring[MAX_CP_PAGES];
+ union {
+ struct tx_cmp *cp_desc_ring[MAX_CP_PAGES];
+ struct nqe_cn *nq_desc_ring[MAX_CP_PAGES];
+ };
dma_addr_t cp_desc_mapping[MAX_CP_PAGES];
@@ -723,6 +818,10 @@ struct bnxt_cp_ring_info {
u64 rx_l4_csum_errors;
struct bnxt_ring_struct cp_ring_struct;
+
+ struct bnxt_cp_ring_info *cp_ring_arr[2];
+#define BNXT_RX_HDL 0
+#define BNXT_TX_HDL 1
};
struct bnxt_napi {
@@ -736,6 +835,9 @@ struct bnxt_napi {
void (*tx_int)(struct bnxt *, struct bnxt_napi *,
int);
+ int tx_pkts;
+ u8 events;
+
u32 flags;
#define BNXT_NAPI_FLAG_XDP 0x1
@@ -755,6 +857,7 @@ struct bnxt_irq {
#define HWRM_RING_ALLOC_RX 0x2
#define HWRM_RING_ALLOC_AGG 0x4
#define HWRM_RING_ALLOC_CMPL 0x8
+#define HWRM_RING_ALLOC_NQ 0x10
#define INVALID_STATS_CTX_ID -1
@@ -768,7 +871,7 @@ struct bnxt_ring_grp_info {
struct bnxt_vnic_info {
u16 fw_vnic_id; /* returned by Chimp during alloc */
-#define BNXT_MAX_CTX_PER_VNIC 2
+#define BNXT_MAX_CTX_PER_VNIC 8
u16 fw_rss_cos_lb_ctx[BNXT_MAX_CTX_PER_VNIC];
u16 fw_l2_ctx_id;
#define BNXT_MAX_UC_ADDRS 4
@@ -1069,6 +1172,55 @@ struct bnxt_vf_rep {
struct bnxt_vf_rep_stats tx_stats;
};
+#define PTU_PTE_VALID 0x1UL
+#define PTU_PTE_LAST 0x2UL
+#define PTU_PTE_NEXT_TO_LAST 0x4UL
+
+#define MAX_CTX_PAGES (BNXT_PAGE_SIZE / 8)
+
+struct bnxt_ctx_pg_info {
+ u32 entries;
+ void *ctx_pg_arr[MAX_CTX_PAGES];
+ dma_addr_t ctx_dma_arr[MAX_CTX_PAGES];
+ struct bnxt_ring_mem_info ring_mem;
+};
+
+struct bnxt_ctx_mem_info {
+ u32 qp_max_entries;
+ u16 qp_min_qp1_entries;
+ u16 qp_max_l2_entries;
+ u16 qp_entry_size;
+ u16 srq_max_l2_entries;
+ u32 srq_max_entries;
+ u16 srq_entry_size;
+ u16 cq_max_l2_entries;
+ u32 cq_max_entries;
+ u16 cq_entry_size;
+ u16 vnic_max_vnic_entries;
+ u16 vnic_max_ring_table_entries;
+ u16 vnic_entry_size;
+ u32 stat_max_entries;
+ u16 stat_entry_size;
+ u16 tqm_entry_size;
+ u32 tqm_min_entries_per_ring;
+ u32 tqm_max_entries_per_ring;
+ u32 mrav_max_entries;
+ u16 mrav_entry_size;
+ u16 tim_entry_size;
+ u32 tim_max_entries;
+ u8 tqm_entries_multiple;
+
+ u32 flags;
+ #define BNXT_CTX_FLAG_INITED 0x01
+
+ struct bnxt_ctx_pg_info qp_mem;
+ struct bnxt_ctx_pg_info srq_mem;
+ struct bnxt_ctx_pg_info cq_mem;
+ struct bnxt_ctx_pg_info vnic_mem;
+ struct bnxt_ctx_pg_info stat_mem;
+ struct bnxt_ctx_pg_info *tqm_mem[9];
+};
+
struct bnxt {
void __iomem *bar0;
void __iomem *bar1;
@@ -1098,6 +1250,8 @@ struct bnxt {
#define CHIP_NUM_5745X 0xd730
+#define CHIP_NUM_57500 0x1750
+
#define CHIP_NUM_58802 0xd802
#define CHIP_NUM_58804 0xd804
#define CHIP_NUM_58808 0xd808
@@ -1144,6 +1298,7 @@ struct bnxt {
atomic_t intr_sem;
u32 flags;
+ #define BNXT_FLAG_CHIP_P5 0x1
#define BNXT_FLAG_VF 0x2
#define BNXT_FLAG_LRO 0x4
#ifdef CONFIG_INET
@@ -1190,15 +1345,24 @@ struct bnxt {
#define BNXT_SINGLE_PF(bp) (BNXT_PF(bp) && !BNXT_NPAR(bp) && !BNXT_MH(bp))
#define BNXT_CHIP_TYPE_NITRO_A0(bp) ((bp)->flags & BNXT_FLAG_CHIP_NITRO_A0)
#define BNXT_RX_PAGE_MODE(bp) ((bp)->flags & BNXT_FLAG_RX_PAGE_MODE)
+#define BNXT_SUPPORTS_TPA(bp) (!BNXT_CHIP_TYPE_NITRO_A0(bp) && \
+ !(bp->flags & BNXT_FLAG_CHIP_P5))
-/* Chip class phase 4 and later */
-#define BNXT_CHIP_P4_PLUS(bp) \
+/* Chip class phase 5 */
+#define BNXT_CHIP_P5(bp) \
+ ((bp)->chip_num == CHIP_NUM_57500)
+
+/* Chip class phase 4.x */
+#define BNXT_CHIP_P4(bp) \
(BNXT_CHIP_NUM_57X1X((bp)->chip_num) || \
BNXT_CHIP_NUM_5745X((bp)->chip_num) || \
BNXT_CHIP_NUM_588XX((bp)->chip_num) || \
(BNXT_CHIP_NUM_58700((bp)->chip_num) && \
!BNXT_CHIP_TYPE_NITRO_A0(bp)))
+#define BNXT_CHIP_P4_PLUS(bp) \
+ (BNXT_CHIP_P4(bp) || BNXT_CHIP_P5(bp))
+
struct bnxt_en_dev *edev;
struct bnxt_en_dev * (*ulp_probe)(struct net_device *);
@@ -1261,6 +1425,8 @@ struct bnxt {
u8 max_lltc; /* lossless TCs */
struct bnxt_queue_info q_info[BNXT_MAX_QUEUE];
u8 tc_to_qidx[BNXT_MAX_QUEUE];
+ u8 q_ids[BNXT_MAX_QUEUE];
+ u8 max_q;
unsigned int current_interval;
#define BNXT_TIMER_INTERVAL HZ
@@ -1305,12 +1471,17 @@ struct bnxt {
struct rx_port_stats *hw_rx_port_stats;
struct tx_port_stats *hw_tx_port_stats;
struct rx_port_stats_ext *hw_rx_port_stats_ext;
+ struct tx_port_stats_ext *hw_tx_port_stats_ext;
dma_addr_t hw_rx_port_stats_map;
dma_addr_t hw_tx_port_stats_map;
dma_addr_t hw_rx_port_stats_ext_map;
+ dma_addr_t hw_tx_port_stats_ext_map;
int hw_port_stats_size;
+ u16 fw_rx_stats_ext_size;
+ u16 fw_tx_stats_ext_size;
u16 hwrm_max_req_len;
+ u16 hwrm_max_ext_req_len;
int hwrm_cmd_timeout;
struct mutex hwrm_cmd_lock; /* serialize hwrm messages */
struct hwrm_ver_get_output ver_resp;
@@ -1328,11 +1499,10 @@ struct bnxt {
u8 port_count;
u16 br_mode;
+ struct bnxt_coal_cap coal_cap;
struct bnxt_coal rx_coal;
struct bnxt_coal tx_coal;
-#define BNXT_USEC_TO_COAL_TIMER(x) ((x) * 25 / 2)
-
u32 stats_coal_ticks;
#define BNXT_DEF_STATS_COAL_TICKS 1000000
#define BNXT_MIN_STATS_COAL_TICKS 250000
@@ -1360,6 +1530,7 @@ struct bnxt {
struct bnxt_hw_resc hw_resc;
struct bnxt_pf_info pf;
+ struct bnxt_ctx_mem_info *ctx;
#ifdef CONFIG_BNXT_SRIOV
int nr_vfs;
struct bnxt_vf_info vf;
@@ -1374,6 +1545,11 @@ struct bnxt {
struct mutex sriov_lock;
#endif
+#if BITS_PER_LONG == 32
+ /* ensure atomic 64-bit doorbell writes on 32-bit systems. */
+ spinlock_t db_lock;
+#endif
+
#define BNXT_NTP_FLTR_MAX_FLTR 4096
#define BNXT_NTP_FLTR_HASH_SIZE 512
#define BNXT_NTP_FLTR_HASH_MASK (BNXT_NTP_FLTR_HASH_SIZE - 1)
@@ -1425,6 +1601,9 @@ struct bnxt {
#define BNXT_RX_STATS_EXT_OFFSET(counter) \
(offsetof(struct rx_port_stats_ext, counter) / 8)
+#define BNXT_TX_STATS_EXT_OFFSET(counter) \
+ (offsetof(struct tx_port_stats_ext, counter) / 8)
+
#define I2C_DEV_ADDR_A0 0xa0
#define I2C_DEV_ADDR_A2 0xa2
#define SFF_DIAG_SUPPORT_OFFSET 0x5c
@@ -1443,21 +1622,46 @@ static inline u32 bnxt_tx_avail(struct bnxt *bp, struct bnxt_tx_ring_info *txr)
((txr->tx_prod - txr->tx_cons) & bp->tx_ring_mask);
}
+#if BITS_PER_LONG == 32
+#define writeq(val64, db) \
+do { \
+ spin_lock(&bp->db_lock); \
+ writel((val64) & 0xffffffff, db); \
+ writel((val64) >> 32, (db) + 4); \
+ spin_unlock(&bp->db_lock); \
+} while (0)
+
+#define writeq_relaxed writeq
+#endif
+
/* For TX and RX ring doorbells with no ordering guarantee*/
-static inline void bnxt_db_write_relaxed(struct bnxt *bp, void __iomem *db,
- u32 val)
+static inline void bnxt_db_write_relaxed(struct bnxt *bp,
+ struct bnxt_db_info *db, u32 idx)
{
- writel_relaxed(val, db);
- if (bp->flags & BNXT_FLAG_DOUBLE_DB)
- writel_relaxed(val, db);
+ if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ writeq_relaxed(db->db_key64 | idx, db->doorbell);
+ } else {
+ u32 db_val = db->db_key32 | idx;
+
+ writel_relaxed(db_val, db->doorbell);
+ if (bp->flags & BNXT_FLAG_DOUBLE_DB)
+ writel_relaxed(db_val, db->doorbell);
+ }
}
/* For TX and RX ring doorbells */
-static inline void bnxt_db_write(struct bnxt *bp, void __iomem *db, u32 val)
+static inline void bnxt_db_write(struct bnxt *bp, struct bnxt_db_info *db,
+ u32 idx)
{
- writel(val, db);
- if (bp->flags & BNXT_FLAG_DOUBLE_DB)
- writel(val, db);
+ if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ writeq(db->db_key64 | idx, db->doorbell);
+ } else {
+ u32 db_val = db->db_key32 | idx;
+
+ writel(db_val, db->doorbell);
+ if (bp->flags & BNXT_FLAG_DOUBLE_DB)
+ writel(db_val, db->doorbell);
+ }
}
extern const u16 bnxt_lhint_arr[];
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c
index ddc98c359488..a85d2be986af 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c
@@ -98,13 +98,13 @@ static int bnxt_hwrm_queue_cos2bw_cfg(struct bnxt *bp, struct ieee_ets *ets,
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_QUEUE_COS2BW_CFG, -1, -1);
for (i = 0; i < max_tc; i++) {
- u8 qidx;
+ u8 qidx = bp->tc_to_qidx[i];
req.enables |= cpu_to_le32(
- QUEUE_COS2BW_CFG_REQ_ENABLES_COS_QUEUE_ID0_VALID << i);
+ QUEUE_COS2BW_CFG_REQ_ENABLES_COS_QUEUE_ID0_VALID <<
+ qidx);
memset(&cos2bw, 0, sizeof(cos2bw));
- qidx = bp->tc_to_qidx[i];
cos2bw.queue_id = bp->q_info[qidx].queue_id;
if (ets->tc_tsa[i] == IEEE_8021QAZ_TSA_STRICT) {
cos2bw.tsa =
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c
index 790c684f08ab..140dbd62106d 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c
@@ -21,9 +21,22 @@ static const struct devlink_ops bnxt_dl_ops = {
#endif /* CONFIG_BNXT_SRIOV */
};
+enum bnxt_dl_param_id {
+ BNXT_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
+ BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK,
+};
+
static const struct bnxt_dl_nvm_param nvm_params[] = {
{DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV, NVM_OFF_ENABLE_SRIOV,
BNXT_NVM_SHARED_CFG, 1},
+ {DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI, NVM_OFF_IGNORE_ARI,
+ BNXT_NVM_SHARED_CFG, 1},
+ {DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX,
+ NVM_OFF_MSIX_VEC_PER_PF_MAX, BNXT_NVM_SHARED_CFG, 10},
+ {DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN,
+ NVM_OFF_MSIX_VEC_PER_PF_MIN, BNXT_NVM_SHARED_CFG, 7},
+ {BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK, NVM_OFF_DIS_GRE_VER_CHECK,
+ BNXT_NVM_SHARED_CFG, 1},
};
static int bnxt_hwrm_nvm_req(struct bnxt *bp, u32 param_id, void *msg,
@@ -55,8 +68,22 @@ static int bnxt_hwrm_nvm_req(struct bnxt *bp, u32 param_id, void *msg,
idx = bp->pf.fw_fid - BNXT_FIRST_PF_FID;
bytesize = roundup(nvm_param.num_bits, BITS_PER_BYTE) / BITS_PER_BYTE;
- if (nvm_param.num_bits == 1)
- buf = &val->vbool;
+ switch (bytesize) {
+ case 1:
+ if (nvm_param.num_bits == 1)
+ buf = &val->vbool;
+ else
+ buf = &val->vu8;
+ break;
+ case 2:
+ buf = &val->vu16;
+ break;
+ case 4:
+ buf = &val->vu32;
+ break;
+ default:
+ return -EFAULT;
+ }
data_addr = dma_zalloc_coherent(&bp->pdev->dev, bytesize,
&data_dma_addr, GFP_KERNEL);
@@ -78,8 +105,12 @@ static int bnxt_hwrm_nvm_req(struct bnxt *bp, u32 param_id, void *msg,
memcpy(buf, data_addr, bytesize);
dma_free_coherent(&bp->pdev->dev, bytesize, data_addr, data_dma_addr);
- if (rc)
+ if (rc == HWRM_ERR_CODE_RESOURCE_ACCESS_DENIED) {
+ netdev_err(bp->dev, "PF does not have admin privileges to modify NVM config\n");
+ return -EACCES;
+ } else if (rc) {
return -EIO;
+ }
return 0;
}
@@ -88,9 +119,15 @@ static int bnxt_dl_nvm_param_get(struct devlink *dl, u32 id,
{
struct hwrm_nvm_get_variable_input req = {0};
struct bnxt *bp = bnxt_get_bp_from_dl(dl);
+ int rc;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_GET_VARIABLE, -1, -1);
- return bnxt_hwrm_nvm_req(bp, id, &req, sizeof(req), &ctx->val);
+ rc = bnxt_hwrm_nvm_req(bp, id, &req, sizeof(req), &ctx->val);
+ if (!rc)
+ if (id == BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK)
+ ctx->val.vbool = !ctx->val.vbool;
+
+ return rc;
}
static int bnxt_dl_nvm_param_set(struct devlink *dl, u32 id,
@@ -100,14 +137,55 @@ static int bnxt_dl_nvm_param_set(struct devlink *dl, u32 id,
struct bnxt *bp = bnxt_get_bp_from_dl(dl);
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_SET_VARIABLE, -1, -1);
+
+ if (id == BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK)
+ ctx->val.vbool = !ctx->val.vbool;
+
return bnxt_hwrm_nvm_req(bp, id, &req, sizeof(req), &ctx->val);
}
+static int bnxt_dl_msix_validate(struct devlink *dl, u32 id,
+ union devlink_param_value val,
+ struct netlink_ext_ack *extack)
+{
+ int max_val = -1;
+
+ if (id == DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX)
+ max_val = BNXT_MSIX_VEC_MAX;
+
+ if (id == DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN)
+ max_val = BNXT_MSIX_VEC_MIN_MAX;
+
+ if (val.vu32 > max_val) {
+ NL_SET_ERR_MSG_MOD(extack, "MSIX value is exceeding the range");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static const struct devlink_param bnxt_dl_params[] = {
DEVLINK_PARAM_GENERIC(ENABLE_SRIOV,
BIT(DEVLINK_PARAM_CMODE_PERMANENT),
bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
NULL),
+ DEVLINK_PARAM_GENERIC(IGNORE_ARI,
+ BIT(DEVLINK_PARAM_CMODE_PERMANENT),
+ bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
+ NULL),
+ DEVLINK_PARAM_GENERIC(MSIX_VEC_PER_PF_MAX,
+ BIT(DEVLINK_PARAM_CMODE_PERMANENT),
+ bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
+ bnxt_dl_msix_validate),
+ DEVLINK_PARAM_GENERIC(MSIX_VEC_PER_PF_MIN,
+ BIT(DEVLINK_PARAM_CMODE_PERMANENT),
+ bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
+ bnxt_dl_msix_validate),
+ DEVLINK_PARAM_DRIVER(BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK,
+ "gre_ver_check", DEVLINK_PARAM_TYPE_BOOL,
+ BIT(DEVLINK_PARAM_CMODE_PERMANENT),
+ bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
+ NULL),
};
int bnxt_dl_register(struct bnxt *bp)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.h
index 2f68dc048390..5b6b2c7d97cf 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.h
@@ -33,8 +33,15 @@ static inline void bnxt_link_bp_to_dl(struct bnxt *bp, struct devlink *dl)
}
}
+#define NVM_OFF_MSIX_VEC_PER_PF_MAX 108
+#define NVM_OFF_MSIX_VEC_PER_PF_MIN 114
+#define NVM_OFF_IGNORE_ARI 164
+#define NVM_OFF_DIS_GRE_VER_CHECK 171
#define NVM_OFF_ENABLE_SRIOV 401
+#define BNXT_MSIX_VEC_MAX 1280
+#define BNXT_MSIX_VEC_MIN_MAX 128
+
enum bnxt_nvm_dir_type {
BNXT_NVM_SHARED_CFG = 40,
BNXT_NVM_PORT_CFG,
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
index e52d7af3ab3e..48078564f025 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
@@ -148,6 +148,65 @@ reset_coalesce:
#define BNXT_RX_STATS_EXT_ENTRY(counter) \
{ BNXT_RX_STATS_EXT_OFFSET(counter), __stringify(counter) }
+#define BNXT_TX_STATS_EXT_ENTRY(counter) \
+ { BNXT_TX_STATS_EXT_OFFSET(counter), __stringify(counter) }
+
+#define BNXT_RX_STATS_EXT_PFC_ENTRY(n) \
+ BNXT_RX_STATS_EXT_ENTRY(pfc_pri##n##_rx_duration_us), \
+ BNXT_RX_STATS_EXT_ENTRY(pfc_pri##n##_rx_transitions)
+
+#define BNXT_TX_STATS_EXT_PFC_ENTRY(n) \
+ BNXT_TX_STATS_EXT_ENTRY(pfc_pri##n##_tx_duration_us), \
+ BNXT_TX_STATS_EXT_ENTRY(pfc_pri##n##_tx_transitions)
+
+#define BNXT_RX_STATS_EXT_PFC_ENTRIES \
+ BNXT_RX_STATS_EXT_PFC_ENTRY(0), \
+ BNXT_RX_STATS_EXT_PFC_ENTRY(1), \
+ BNXT_RX_STATS_EXT_PFC_ENTRY(2), \
+ BNXT_RX_STATS_EXT_PFC_ENTRY(3), \
+ BNXT_RX_STATS_EXT_PFC_ENTRY(4), \
+ BNXT_RX_STATS_EXT_PFC_ENTRY(5), \
+ BNXT_RX_STATS_EXT_PFC_ENTRY(6), \
+ BNXT_RX_STATS_EXT_PFC_ENTRY(7)
+
+#define BNXT_TX_STATS_EXT_PFC_ENTRIES \
+ BNXT_TX_STATS_EXT_PFC_ENTRY(0), \
+ BNXT_TX_STATS_EXT_PFC_ENTRY(1), \
+ BNXT_TX_STATS_EXT_PFC_ENTRY(2), \
+ BNXT_TX_STATS_EXT_PFC_ENTRY(3), \
+ BNXT_TX_STATS_EXT_PFC_ENTRY(4), \
+ BNXT_TX_STATS_EXT_PFC_ENTRY(5), \
+ BNXT_TX_STATS_EXT_PFC_ENTRY(6), \
+ BNXT_TX_STATS_EXT_PFC_ENTRY(7)
+
+#define BNXT_RX_STATS_EXT_COS_ENTRY(n) \
+ BNXT_RX_STATS_EXT_ENTRY(rx_bytes_cos##n), \
+ BNXT_RX_STATS_EXT_ENTRY(rx_packets_cos##n)
+
+#define BNXT_TX_STATS_EXT_COS_ENTRY(n) \
+ BNXT_TX_STATS_EXT_ENTRY(tx_bytes_cos##n), \
+ BNXT_TX_STATS_EXT_ENTRY(tx_packets_cos##n)
+
+#define BNXT_RX_STATS_EXT_COS_ENTRIES \
+ BNXT_RX_STATS_EXT_COS_ENTRY(0), \
+ BNXT_RX_STATS_EXT_COS_ENTRY(1), \
+ BNXT_RX_STATS_EXT_COS_ENTRY(2), \
+ BNXT_RX_STATS_EXT_COS_ENTRY(3), \
+ BNXT_RX_STATS_EXT_COS_ENTRY(4), \
+ BNXT_RX_STATS_EXT_COS_ENTRY(5), \
+ BNXT_RX_STATS_EXT_COS_ENTRY(6), \
+ BNXT_RX_STATS_EXT_COS_ENTRY(7) \
+
+#define BNXT_TX_STATS_EXT_COS_ENTRIES \
+ BNXT_TX_STATS_EXT_COS_ENTRY(0), \
+ BNXT_TX_STATS_EXT_COS_ENTRY(1), \
+ BNXT_TX_STATS_EXT_COS_ENTRY(2), \
+ BNXT_TX_STATS_EXT_COS_ENTRY(3), \
+ BNXT_TX_STATS_EXT_COS_ENTRY(4), \
+ BNXT_TX_STATS_EXT_COS_ENTRY(5), \
+ BNXT_TX_STATS_EXT_COS_ENTRY(6), \
+ BNXT_TX_STATS_EXT_COS_ENTRY(7) \
+
enum {
RX_TOTAL_DISCARDS,
TX_TOTAL_DISCARDS,
@@ -256,11 +315,20 @@ static const struct {
BNXT_RX_STATS_EXT_ENTRY(resume_pause_events),
BNXT_RX_STATS_EXT_ENTRY(continuous_roce_pause_events),
BNXT_RX_STATS_EXT_ENTRY(resume_roce_pause_events),
+ BNXT_RX_STATS_EXT_COS_ENTRIES,
+ BNXT_RX_STATS_EXT_PFC_ENTRIES,
+};
+
+static const struct {
+ long offset;
+ char string[ETH_GSTRING_LEN];
+} bnxt_tx_port_stats_ext_arr[] = {
+ BNXT_TX_STATS_EXT_COS_ENTRIES,
+ BNXT_TX_STATS_EXT_PFC_ENTRIES,
};
#define BNXT_NUM_SW_FUNC_STATS ARRAY_SIZE(bnxt_sw_func_stats)
#define BNXT_NUM_PORT_STATS ARRAY_SIZE(bnxt_port_stats_arr)
-#define BNXT_NUM_PORT_STATS_EXT ARRAY_SIZE(bnxt_port_stats_ext_arr)
static int bnxt_get_num_stats(struct bnxt *bp)
{
@@ -272,7 +340,8 @@ static int bnxt_get_num_stats(struct bnxt *bp)
num_stats += BNXT_NUM_PORT_STATS;
if (bp->flags & BNXT_FLAG_PORT_STATS_EXT)
- num_stats += BNXT_NUM_PORT_STATS_EXT;
+ num_stats += bp->fw_rx_stats_ext_size +
+ bp->fw_tx_stats_ext_size;
return num_stats;
}
@@ -334,12 +403,17 @@ static void bnxt_get_ethtool_stats(struct net_device *dev,
}
}
if (bp->flags & BNXT_FLAG_PORT_STATS_EXT) {
- __le64 *port_stats_ext = (__le64 *)bp->hw_rx_port_stats_ext;
+ __le64 *rx_port_stats_ext = (__le64 *)bp->hw_rx_port_stats_ext;
+ __le64 *tx_port_stats_ext = (__le64 *)bp->hw_tx_port_stats_ext;
- for (i = 0; i < BNXT_NUM_PORT_STATS_EXT; i++, j++) {
- buf[j] = le64_to_cpu(*(port_stats_ext +
+ for (i = 0; i < bp->fw_rx_stats_ext_size; i++, j++) {
+ buf[j] = le64_to_cpu(*(rx_port_stats_ext +
bnxt_port_stats_ext_arr[i].offset));
}
+ for (i = 0; i < bp->fw_tx_stats_ext_size; i++, j++) {
+ buf[j] = le64_to_cpu(*(tx_port_stats_ext +
+ bnxt_tx_port_stats_ext_arr[i].offset));
+ }
}
}
@@ -407,10 +481,15 @@ static void bnxt_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
}
}
if (bp->flags & BNXT_FLAG_PORT_STATS_EXT) {
- for (i = 0; i < BNXT_NUM_PORT_STATS_EXT; i++) {
+ for (i = 0; i < bp->fw_rx_stats_ext_size; i++) {
strcpy(buf, bnxt_port_stats_ext_arr[i].string);
buf += ETH_GSTRING_LEN;
}
+ for (i = 0; i < bp->fw_tx_stats_ext_size; i++) {
+ strcpy(buf,
+ bnxt_tx_port_stats_ext_arr[i].string);
+ buf += ETH_GSTRING_LEN;
+ }
}
break;
case ETH_SS_TEST:
@@ -2419,11 +2498,11 @@ static int bnxt_hwrm_phy_loopback(struct bnxt *bp, bool enable, bool ext)
return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
}
-static int bnxt_rx_loopback(struct bnxt *bp, struct bnxt_napi *bnapi,
+static int bnxt_rx_loopback(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
u32 raw_cons, int pkt_size)
{
- struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
- struct bnxt_rx_ring_info *rxr = bnapi->rx_ring;
+ struct bnxt_napi *bnapi = cpr->bnapi;
+ struct bnxt_rx_ring_info *rxr;
struct bnxt_sw_rx_bd *rx_buf;
struct rx_cmp *rxcmp;
u16 cp_cons, cons;
@@ -2431,6 +2510,7 @@ static int bnxt_rx_loopback(struct bnxt *bp, struct bnxt_napi *bnapi,
u32 len;
int i;
+ rxr = bnapi->rx_ring;
cp_cons = RING_CMP(raw_cons);
rxcmp = (struct rx_cmp *)
&cpr->cp_desc_ring[CP_RING(cp_cons)][CP_IDX(cp_cons)];
@@ -2451,17 +2531,15 @@ static int bnxt_rx_loopback(struct bnxt *bp, struct bnxt_napi *bnapi,
return 0;
}
-static int bnxt_poll_loopback(struct bnxt *bp, int pkt_size)
+static int bnxt_poll_loopback(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
+ int pkt_size)
{
- struct bnxt_napi *bnapi = bp->bnapi[0];
- struct bnxt_cp_ring_info *cpr;
struct tx_cmp *txcmp;
int rc = -EIO;
u32 raw_cons;
u32 cons;
int i;
- cpr = &bnapi->cp_ring;
raw_cons = cpr->cp_raw_cons;
for (i = 0; i < 200; i++) {
cons = RING_CMP(raw_cons);
@@ -2477,7 +2555,7 @@ static int bnxt_poll_loopback(struct bnxt *bp, int pkt_size)
*/
dma_rmb();
if (TX_CMP_TYPE(txcmp) == CMP_TYPE_RX_L2_CMP) {
- rc = bnxt_rx_loopback(bp, bnapi, raw_cons, pkt_size);
+ rc = bnxt_rx_loopback(bp, cpr, raw_cons, pkt_size);
raw_cons = NEXT_RAW_CMP(raw_cons);
raw_cons = NEXT_RAW_CMP(raw_cons);
break;
@@ -2491,12 +2569,14 @@ static int bnxt_poll_loopback(struct bnxt *bp, int pkt_size)
static int bnxt_run_loopback(struct bnxt *bp)
{
struct bnxt_tx_ring_info *txr = &bp->tx_ring[0];
+ struct bnxt_cp_ring_info *cpr;
int pkt_size, i = 0;
struct sk_buff *skb;
dma_addr_t map;
u8 *data;
int rc;
+ cpr = &txr->bnapi->cp_ring;
pkt_size = min(bp->dev->mtu + ETH_HLEN, bp->rx_copy_thresh);
skb = netdev_alloc_skb(bp->dev, pkt_size);
if (!skb)
@@ -2520,8 +2600,8 @@ static int bnxt_run_loopback(struct bnxt *bp)
/* Sync BD data before updating doorbell */
wmb();
- bnxt_db_write(bp, txr->tx_doorbell, DB_KEY_TX | txr->tx_prod);
- rc = bnxt_poll_loopback(bp, pkt_size);
+ bnxt_db_write(bp, &txr->tx_db, txr->tx_prod);
+ rc = bnxt_poll_loopback(bp, cpr, pkt_size);
dma_unmap_single(&bp->pdev->dev, map, pkt_size, PCI_DMA_TODEVICE);
dev_kfree_skb(skb);
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h
index 971ace5d0d4a..5dd086059568 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h
@@ -37,6 +37,8 @@ struct hwrm_resp_hdr {
#define TLV_TYPE_HWRM_REQUEST 0x1UL
#define TLV_TYPE_HWRM_RESPONSE 0x2UL
#define TLV_TYPE_ROCE_SP_COMMAND 0x3UL
+#define TLV_TYPE_QUERY_ROCE_CC_GEN1 0x4UL
+#define TLV_TYPE_MODIFY_ROCE_CC_GEN1 0x5UL
#define TLV_TYPE_ENGINE_CKV_DEVICE_SERIAL_NUMBER 0x8001UL
#define TLV_TYPE_ENGINE_CKV_NONCE 0x8002UL
#define TLV_TYPE_ENGINE_CKV_IV 0x8003UL
@@ -186,6 +188,7 @@ struct cmd_nums {
#define HWRM_TUNNEL_DST_PORT_QUERY 0xa0UL
#define HWRM_TUNNEL_DST_PORT_ALLOC 0xa1UL
#define HWRM_TUNNEL_DST_PORT_FREE 0xa2UL
+ #define HWRM_STAT_CTX_ENG_QUERY 0xafUL
#define HWRM_STAT_CTX_ALLOC 0xb0UL
#define HWRM_STAT_CTX_FREE 0xb1UL
#define HWRM_STAT_CTX_QUERY 0xb2UL
@@ -235,6 +238,7 @@ struct cmd_nums {
#define HWRM_CFA_PAIR_INFO 0x10fUL
#define HWRM_FW_IPC_MSG 0x110UL
#define HWRM_CFA_REDIRECT_TUNNEL_TYPE_INFO 0x111UL
+ #define HWRM_CFA_REDIRECT_QUERY_TUNNEL_TYPE 0x112UL
#define HWRM_ENGINE_CKV_HELLO 0x12dUL
#define HWRM_ENGINE_CKV_STATUS 0x12eUL
#define HWRM_ENGINE_CKV_CKEK_ADD 0x12fUL
@@ -295,6 +299,7 @@ struct cmd_nums {
#define HWRM_DBG_COREDUMP_RETRIEVE 0xff19UL
#define HWRM_DBG_FW_CLI 0xff1aUL
#define HWRM_DBG_I2C_CMD 0xff1bUL
+ #define HWRM_DBG_RING_INFO_GET 0xff1cUL
#define HWRM_NVM_FACTORY_DEFAULTS 0xffeeUL
#define HWRM_NVM_VALIDATE_OPTION 0xffefUL
#define HWRM_NVM_FLUSH 0xfff0UL
@@ -320,20 +325,21 @@ struct cmd_nums {
/* ret_codes (size:64b/8B) */
struct ret_codes {
__le16 error_code;
- #define HWRM_ERR_CODE_SUCCESS 0x0UL
- #define HWRM_ERR_CODE_FAIL 0x1UL
- #define HWRM_ERR_CODE_INVALID_PARAMS 0x2UL
- #define HWRM_ERR_CODE_RESOURCE_ACCESS_DENIED 0x3UL
- #define HWRM_ERR_CODE_RESOURCE_ALLOC_ERROR 0x4UL
- #define HWRM_ERR_CODE_INVALID_FLAGS 0x5UL
- #define HWRM_ERR_CODE_INVALID_ENABLES 0x6UL
- #define HWRM_ERR_CODE_UNSUPPORTED_TLV 0x7UL
- #define HWRM_ERR_CODE_NO_BUFFER 0x8UL
- #define HWRM_ERR_CODE_UNSUPPORTED_OPTION_ERR 0x9UL
- #define HWRM_ERR_CODE_HWRM_ERROR 0xfUL
- #define HWRM_ERR_CODE_UNKNOWN_ERR 0xfffeUL
- #define HWRM_ERR_CODE_CMD_NOT_SUPPORTED 0xffffUL
- #define HWRM_ERR_CODE_LAST HWRM_ERR_CODE_CMD_NOT_SUPPORTED
+ #define HWRM_ERR_CODE_SUCCESS 0x0UL
+ #define HWRM_ERR_CODE_FAIL 0x1UL
+ #define HWRM_ERR_CODE_INVALID_PARAMS 0x2UL
+ #define HWRM_ERR_CODE_RESOURCE_ACCESS_DENIED 0x3UL
+ #define HWRM_ERR_CODE_RESOURCE_ALLOC_ERROR 0x4UL
+ #define HWRM_ERR_CODE_INVALID_FLAGS 0x5UL
+ #define HWRM_ERR_CODE_INVALID_ENABLES 0x6UL
+ #define HWRM_ERR_CODE_UNSUPPORTED_TLV 0x7UL
+ #define HWRM_ERR_CODE_NO_BUFFER 0x8UL
+ #define HWRM_ERR_CODE_UNSUPPORTED_OPTION_ERR 0x9UL
+ #define HWRM_ERR_CODE_HWRM_ERROR 0xfUL
+ #define HWRM_ERR_CODE_TLV_ENCAPSULATED_RESPONSE 0x8000UL
+ #define HWRM_ERR_CODE_UNKNOWN_ERR 0xfffeUL
+ #define HWRM_ERR_CODE_CMD_NOT_SUPPORTED 0xffffUL
+ #define HWRM_ERR_CODE_LAST HWRM_ERR_CODE_CMD_NOT_SUPPORTED
__le16 unused_0[3];
};
@@ -355,10 +361,10 @@ struct hwrm_err_output {
#define HW_HASH_KEY_SIZE 40
#define HWRM_RESP_VALID_KEY 1
#define HWRM_VERSION_MAJOR 1
-#define HWRM_VERSION_MINOR 9
-#define HWRM_VERSION_UPDATE 2
-#define HWRM_VERSION_RSVD 25
-#define HWRM_VERSION_STR "1.9.2.25"
+#define HWRM_VERSION_MINOR 10
+#define HWRM_VERSION_UPDATE 0
+#define HWRM_VERSION_RSVD 3
+#define HWRM_VERSION_STR "1.10.0.3"
/* hwrm_ver_get_input (size:192b/24B) */
struct hwrm_ver_get_input {
@@ -396,10 +402,15 @@ struct hwrm_ver_get_output {
u8 netctrl_fw_bld_8b;
u8 netctrl_fw_rsvd_8b;
__le32 dev_caps_cfg;
- #define VER_GET_RESP_DEV_CAPS_CFG_SECURE_FW_UPD_SUPPORTED 0x1UL
- #define VER_GET_RESP_DEV_CAPS_CFG_FW_DCBX_AGENT_SUPPORTED 0x2UL
- #define VER_GET_RESP_DEV_CAPS_CFG_SHORT_CMD_SUPPORTED 0x4UL
- #define VER_GET_RESP_DEV_CAPS_CFG_SHORT_CMD_REQUIRED 0x8UL
+ #define VER_GET_RESP_DEV_CAPS_CFG_SECURE_FW_UPD_SUPPORTED 0x1UL
+ #define VER_GET_RESP_DEV_CAPS_CFG_FW_DCBX_AGENT_SUPPORTED 0x2UL
+ #define VER_GET_RESP_DEV_CAPS_CFG_SHORT_CMD_SUPPORTED 0x4UL
+ #define VER_GET_RESP_DEV_CAPS_CFG_SHORT_CMD_REQUIRED 0x8UL
+ #define VER_GET_RESP_DEV_CAPS_CFG_KONG_MB_CHNL_SUPPORTED 0x10UL
+ #define VER_GET_RESP_DEV_CAPS_CFG_FLOW_HANDLE_64BIT_SUPPORTED 0x20UL
+ #define VER_GET_RESP_DEV_CAPS_CFG_L2_FILTER_TYPES_ROCE_OR_L2_SUPPORTED 0x40UL
+ #define VER_GET_RESP_DEV_CAPS_CFG_VIRTIO_VSWITCH_OFFLOAD_SUPPORTED 0x80UL
+ #define VER_GET_RESP_DEV_CAPS_CFG_TRUSTED_VF_SUPPORTED 0x100UL
u8 roce_fw_maj_8b;
u8 roce_fw_min_8b;
u8 roce_fw_bld_8b;
@@ -528,6 +539,7 @@ struct hwrm_async_event_cmpl {
#define ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CFG_NOT_ALLOWED 0x5UL
#define ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CFG_CHANGE 0x6UL
#define ASYNC_EVENT_CMPL_EVENT_ID_PORT_PHY_CFG_CHANGE 0x7UL
+ #define ASYNC_EVENT_CMPL_EVENT_ID_RESET_NOTIFY 0x8UL
#define ASYNC_EVENT_CMPL_EVENT_ID_FUNC_DRVR_UNLOAD 0x10UL
#define ASYNC_EVENT_CMPL_EVENT_ID_FUNC_DRVR_LOAD 0x11UL
#define ASYNC_EVENT_CMPL_EVENT_ID_FUNC_FLR_PROC_CMPLT 0x12UL
@@ -539,6 +551,7 @@ struct hwrm_async_event_cmpl {
#define ASYNC_EVENT_CMPL_EVENT_ID_VF_CFG_CHANGE 0x33UL
#define ASYNC_EVENT_CMPL_EVENT_ID_LLFC_PFC_CHANGE 0x34UL
#define ASYNC_EVENT_CMPL_EVENT_ID_DEFAULT_VNIC_CHANGE 0x35UL
+ #define ASYNC_EVENT_CMPL_EVENT_ID_HW_FLOW_AGED 0x36UL
#define ASYNC_EVENT_CMPL_EVENT_ID_HWRM_ERROR 0xffUL
#define ASYNC_EVENT_CMPL_EVENT_ID_LAST ASYNC_EVENT_CMPL_EVENT_ID_HWRM_ERROR
__le32 event_data2;
@@ -652,10 +665,11 @@ struct hwrm_async_event_cmpl_vf_cfg_change {
u8 timestamp_lo;
__le16 timestamp_hi;
__le32 event_data1;
- #define ASYNC_EVENT_CMPL_VF_CFG_CHANGE_EVENT_DATA1_MTU_CHANGE 0x1UL
- #define ASYNC_EVENT_CMPL_VF_CFG_CHANGE_EVENT_DATA1_MRU_CHANGE 0x2UL
- #define ASYNC_EVENT_CMPL_VF_CFG_CHANGE_EVENT_DATA1_DFLT_MAC_ADDR_CHANGE 0x4UL
- #define ASYNC_EVENT_CMPL_VF_CFG_CHANGE_EVENT_DATA1_DFLT_VLAN_CHANGE 0x8UL
+ #define ASYNC_EVENT_CMPL_VF_CFG_CHANGE_EVENT_DATA1_MTU_CHANGE 0x1UL
+ #define ASYNC_EVENT_CMPL_VF_CFG_CHANGE_EVENT_DATA1_MRU_CHANGE 0x2UL
+ #define ASYNC_EVENT_CMPL_VF_CFG_CHANGE_EVENT_DATA1_DFLT_MAC_ADDR_CHANGE 0x4UL
+ #define ASYNC_EVENT_CMPL_VF_CFG_CHANGE_EVENT_DATA1_DFLT_VLAN_CHANGE 0x8UL
+ #define ASYNC_EVENT_CMPL_VF_CFG_CHANGE_EVENT_DATA1_TRUSTED_VF_CFG_CHANGE 0x10UL
};
/* hwrm_func_reset_input (size:192b/24B) */
@@ -852,6 +866,7 @@ struct hwrm_func_qcaps_output {
#define FUNC_QCAPS_RESP_FLAGS_ADOPTED_PF_SUPPORTED 0x20000UL
#define FUNC_QCAPS_RESP_FLAGS_ADMIN_PF_SUPPORTED 0x40000UL
#define FUNC_QCAPS_RESP_FLAGS_LINK_ADMIN_STATUS_SUPPORTED 0x80000UL
+ #define FUNC_QCAPS_RESP_FLAGS_WCB_PUSH_MODE 0x100000UL
u8 mac_address[6];
__le16 max_rsscos_ctx;
__le16 max_cmpl_rings;
@@ -903,6 +918,7 @@ struct hwrm_func_qcfg_output {
#define FUNC_QCFG_RESP_FLAGS_STD_TX_RING_MODE_ENABLED 0x8UL
#define FUNC_QCFG_RESP_FLAGS_FW_LLDP_AGENT_ENABLED 0x10UL
#define FUNC_QCFG_RESP_FLAGS_MULTI_HOST 0x20UL
+ #define FUNC_QCFG_RESP_FLAGS_TRUSTED_VF 0x40UL
u8 mac_address[6];
__le16 pci_id;
__le16 alloc_rsscos_ctx;
@@ -1014,6 +1030,7 @@ struct hwrm_func_cfg_input {
#define FUNC_CFG_REQ_FLAGS_STAT_CTX_ASSETS_TEST 0x40000UL
#define FUNC_CFG_REQ_FLAGS_VNIC_ASSETS_TEST 0x80000UL
#define FUNC_CFG_REQ_FLAGS_L2_CTX_ASSETS_TEST 0x100000UL
+ #define FUNC_CFG_REQ_FLAGS_TRUSTED_VF_ENABLE 0x200000UL
__le32 enables;
#define FUNC_CFG_REQ_ENABLES_MTU 0x1UL
#define FUNC_CFG_REQ_ENABLES_MRU 0x2UL
@@ -1214,9 +1231,10 @@ 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_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
__le32 enables;
#define FUNC_DRV_RGTR_REQ_ENABLES_OS_TYPE 0x1UL
#define FUNC_DRV_RGTR_REQ_ENABLES_VER 0x2UL
@@ -1416,7 +1434,9 @@ struct hwrm_func_resource_qcaps_output {
__le16 min_hw_ring_grps;
__le16 max_hw_ring_grps;
__le16 max_tx_scheduler_inputs;
- u8 unused_0[7];
+ __le16 flags;
+ #define FUNC_RESOURCE_QCAPS_RESP_FLAGS_MIN_GUARANTEED 0x1UL
+ u8 unused_0[5];
u8 valid;
};
@@ -1445,7 +1465,9 @@ struct hwrm_func_vf_resource_cfg_input {
__le16 max_stat_ctx;
__le16 min_hw_ring_grps;
__le16 max_hw_ring_grps;
- u8 unused_0[4];
+ __le16 flags;
+ #define FUNC_VF_RESOURCE_CFG_REQ_FLAGS_MIN_GUARANTEED 0x1UL
+ u8 unused_0[2];
};
/* hwrm_func_vf_resource_cfg_output (size:256b/32B) */
@@ -1503,7 +1525,8 @@ struct hwrm_func_backing_store_qcaps_output {
__le16 mrav_entry_size;
__le16 tim_entry_size;
__le32 tim_max_entries;
- u8 unused_0[3];
+ u8 unused_0[2];
+ u8 tqm_entries_multiple;
u8 valid;
};
@@ -1917,6 +1940,7 @@ struct hwrm_port_phy_cfg_input {
#define PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_40GB 0x190UL
#define PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_50GB 0x1f4UL
#define PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_100GB 0x3e8UL
+ #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_200GB 0x7d0UL
#define PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_10MB 0xffffUL
#define PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_LAST PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_10MB
u8 auto_mode;
@@ -1947,6 +1971,7 @@ struct hwrm_port_phy_cfg_input {
#define PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_40GB 0x190UL
#define PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_50GB 0x1f4UL
#define PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_100GB 0x3e8UL
+ #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_200GB 0x7d0UL
#define PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_10MB 0xffffUL
#define PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_LAST PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_10MB
__le16 auto_link_speed_mask;
@@ -1964,6 +1989,7 @@ struct hwrm_port_phy_cfg_input {
#define PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_MASK_100GB 0x800UL
#define PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_MASK_10MBHD 0x1000UL
#define PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_MASK_10MB 0x2000UL
+ #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_MASK_200GB 0x4000UL
u8 wirespeed;
#define PORT_PHY_CFG_REQ_WIRESPEED_OFF 0x0UL
#define PORT_PHY_CFG_REQ_WIRESPEED_ON 0x1UL
@@ -2048,6 +2074,7 @@ struct hwrm_port_phy_qcfg_output {
#define PORT_PHY_QCFG_RESP_LINK_SPEED_40GB 0x190UL
#define PORT_PHY_QCFG_RESP_LINK_SPEED_50GB 0x1f4UL
#define PORT_PHY_QCFG_RESP_LINK_SPEED_100GB 0x3e8UL
+ #define PORT_PHY_QCFG_RESP_LINK_SPEED_200GB 0x7d0UL
#define PORT_PHY_QCFG_RESP_LINK_SPEED_10MB 0xffffUL
#define PORT_PHY_QCFG_RESP_LINK_SPEED_LAST PORT_PHY_QCFG_RESP_LINK_SPEED_10MB
u8 duplex_cfg;
@@ -2072,6 +2099,7 @@ struct hwrm_port_phy_qcfg_output {
#define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_100GB 0x800UL
#define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_10MBHD 0x1000UL
#define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_10MB 0x2000UL
+ #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_200GB 0x4000UL
__le16 force_link_speed;
#define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEED_100MB 0x1UL
#define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEED_1GB 0xaUL
@@ -2083,6 +2111,7 @@ struct hwrm_port_phy_qcfg_output {
#define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEED_40GB 0x190UL
#define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEED_50GB 0x1f4UL
#define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEED_100GB 0x3e8UL
+ #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEED_200GB 0x7d0UL
#define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEED_10MB 0xffffUL
#define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEED_LAST PORT_PHY_QCFG_RESP_FORCE_LINK_SPEED_10MB
u8 auto_mode;
@@ -2107,6 +2136,7 @@ struct hwrm_port_phy_qcfg_output {
#define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEED_40GB 0x190UL
#define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEED_50GB 0x1f4UL
#define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEED_100GB 0x3e8UL
+ #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEED_200GB 0x7d0UL
#define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEED_10MB 0xffffUL
#define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEED_LAST PORT_PHY_QCFG_RESP_AUTO_LINK_SPEED_10MB
__le16 auto_link_speed_mask;
@@ -2124,6 +2154,7 @@ struct hwrm_port_phy_qcfg_output {
#define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEED_MASK_100GB 0x800UL
#define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEED_MASK_10MBHD 0x1000UL
#define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEED_MASK_10MB 0x2000UL
+ #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEED_MASK_200GB 0x4000UL
u8 wirespeed;
#define PORT_PHY_QCFG_RESP_WIRESPEED_OFF 0x0UL
#define PORT_PHY_QCFG_RESP_WIRESPEED_ON 0x1UL
@@ -2178,7 +2209,11 @@ struct hwrm_port_phy_qcfg_output {
#define PORT_PHY_QCFG_RESP_PHY_TYPE_1G_BASET 0x19UL
#define PORT_PHY_QCFG_RESP_PHY_TYPE_1G_BASESX 0x1aUL
#define PORT_PHY_QCFG_RESP_PHY_TYPE_1G_BASECX 0x1bUL
- #define PORT_PHY_QCFG_RESP_PHY_TYPE_LAST PORT_PHY_QCFG_RESP_PHY_TYPE_1G_BASECX
+ #define PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASECR4 0x1cUL
+ #define PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASESR4 0x1dUL
+ #define PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASELR4 0x1eUL
+ #define PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASEER4 0x1fUL
+ #define PORT_PHY_QCFG_RESP_PHY_TYPE_LAST PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASEER4
u8 media_type;
#define PORT_PHY_QCFG_RESP_MEDIA_TYPE_UNKNOWN 0x0UL
#define PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP 0x1UL
@@ -2644,7 +2679,8 @@ struct hwrm_port_qstats_ext_output {
__le16 tx_stat_size;
__le16 rx_stat_size;
__le16 total_active_cos_queues;
- u8 unused_0;
+ u8 flags;
+ #define PORT_QSTATS_EXT_RESP_FLAGS_CLEAR_ROCE_COUNTERS_SUPPORTED 0x1UL
u8 valid;
};
@@ -2685,7 +2721,9 @@ struct hwrm_port_clr_stats_input {
__le16 target_id;
__le64 resp_addr;
__le16 port_id;
- u8 unused_0[6];
+ u8 flags;
+ #define PORT_CLR_STATS_REQ_FLAGS_ROCE_COUNTERS 0x1UL
+ u8 unused_0[5];
};
/* hwrm_port_clr_stats_output (size:128b/16B) */
@@ -4574,7 +4612,9 @@ struct hwrm_ring_alloc_input {
#define RING_ALLOC_REQ_RING_TYPE_RX_AGG 0x4UL
#define RING_ALLOC_REQ_RING_TYPE_NQ 0x5UL
#define RING_ALLOC_REQ_RING_TYPE_LAST RING_ALLOC_REQ_RING_TYPE_NQ
- u8 unused_0[3];
+ u8 unused_0;
+ __le16 flags;
+ #define RING_ALLOC_REQ_FLAGS_RX_SOP_PAD 0x1UL
__le64 page_tbl_addr;
__le32 fbo;
u8 page_size;
@@ -4838,13 +4878,19 @@ struct hwrm_cfa_l2_filter_alloc_input {
__le16 target_id;
__le64 resp_addr;
__le32 flags;
- #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_PATH 0x1UL
- #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_PATH_TX 0x0UL
- #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_PATH_RX 0x1UL
- #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_PATH_LAST CFA_L2_FILTER_ALLOC_REQ_FLAGS_PATH_RX
- #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_LOOPBACK 0x2UL
- #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_DROP 0x4UL
- #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_OUTERMOST 0x8UL
+ #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_PATH 0x1UL
+ #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_PATH_TX 0x0UL
+ #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_PATH_RX 0x1UL
+ #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_PATH_LAST CFA_L2_FILTER_ALLOC_REQ_FLAGS_PATH_RX
+ #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_LOOPBACK 0x2UL
+ #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_DROP 0x4UL
+ #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_OUTERMOST 0x8UL
+ #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_TRAFFIC_MASK 0x30UL
+ #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_TRAFFIC_SFT 4
+ #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_TRAFFIC_NO_ROCE_L2 (0x0UL << 4)
+ #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_TRAFFIC_L2 (0x1UL << 4)
+ #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_TRAFFIC_ROCE (0x2UL << 4)
+ #define CFA_L2_FILTER_ALLOC_REQ_FLAGS_TRAFFIC_LAST CFA_L2_FILTER_ALLOC_REQ_FLAGS_TRAFFIC_ROCE
__le32 enables;
#define CFA_L2_FILTER_ALLOC_REQ_ENABLES_L2_ADDR 0x1UL
#define CFA_L2_FILTER_ALLOC_REQ_ENABLES_L2_ADDR_MASK 0x2UL
@@ -4901,6 +4947,8 @@ struct hwrm_cfa_l2_filter_alloc_input {
#define CFA_L2_FILTER_ALLOC_REQ_TUNNEL_TYPE_STT 0x7UL
#define CFA_L2_FILTER_ALLOC_REQ_TUNNEL_TYPE_IPGRE 0x8UL
#define CFA_L2_FILTER_ALLOC_REQ_TUNNEL_TYPE_VXLAN_V4 0x9UL
+ #define CFA_L2_FILTER_ALLOC_REQ_TUNNEL_TYPE_IPGRE_V1 0xaUL
+ #define CFA_L2_FILTER_ALLOC_REQ_TUNNEL_TYPE_L2_ETYPE 0xbUL
#define CFA_L2_FILTER_ALLOC_REQ_TUNNEL_TYPE_ANYTUNNEL 0xffUL
#define CFA_L2_FILTER_ALLOC_REQ_TUNNEL_TYPE_LAST CFA_L2_FILTER_ALLOC_REQ_TUNNEL_TYPE_ANYTUNNEL
u8 unused_4;
@@ -4958,11 +5006,17 @@ struct hwrm_cfa_l2_filter_cfg_input {
__le16 target_id;
__le64 resp_addr;
__le32 flags;
- #define CFA_L2_FILTER_CFG_REQ_FLAGS_PATH 0x1UL
- #define CFA_L2_FILTER_CFG_REQ_FLAGS_PATH_TX 0x0UL
- #define CFA_L2_FILTER_CFG_REQ_FLAGS_PATH_RX 0x1UL
- #define CFA_L2_FILTER_CFG_REQ_FLAGS_PATH_LAST CFA_L2_FILTER_CFG_REQ_FLAGS_PATH_RX
- #define CFA_L2_FILTER_CFG_REQ_FLAGS_DROP 0x2UL
+ #define CFA_L2_FILTER_CFG_REQ_FLAGS_PATH 0x1UL
+ #define CFA_L2_FILTER_CFG_REQ_FLAGS_PATH_TX 0x0UL
+ #define CFA_L2_FILTER_CFG_REQ_FLAGS_PATH_RX 0x1UL
+ #define CFA_L2_FILTER_CFG_REQ_FLAGS_PATH_LAST CFA_L2_FILTER_CFG_REQ_FLAGS_PATH_RX
+ #define CFA_L2_FILTER_CFG_REQ_FLAGS_DROP 0x2UL
+ #define CFA_L2_FILTER_CFG_REQ_FLAGS_TRAFFIC_MASK 0xcUL
+ #define CFA_L2_FILTER_CFG_REQ_FLAGS_TRAFFIC_SFT 2
+ #define CFA_L2_FILTER_CFG_REQ_FLAGS_TRAFFIC_NO_ROCE_L2 (0x0UL << 2)
+ #define CFA_L2_FILTER_CFG_REQ_FLAGS_TRAFFIC_L2 (0x1UL << 2)
+ #define CFA_L2_FILTER_CFG_REQ_FLAGS_TRAFFIC_ROCE (0x2UL << 2)
+ #define CFA_L2_FILTER_CFG_REQ_FLAGS_TRAFFIC_LAST CFA_L2_FILTER_CFG_REQ_FLAGS_TRAFFIC_ROCE
__le32 enables;
#define CFA_L2_FILTER_CFG_REQ_ENABLES_DST_ID 0x1UL
#define CFA_L2_FILTER_CFG_REQ_ENABLES_NEW_MIRROR_VNIC_ID 0x2UL
@@ -5064,6 +5118,8 @@ struct hwrm_cfa_tunnel_filter_alloc_input {
#define CFA_TUNNEL_FILTER_ALLOC_REQ_TUNNEL_TYPE_STT 0x7UL
#define CFA_TUNNEL_FILTER_ALLOC_REQ_TUNNEL_TYPE_IPGRE 0x8UL
#define CFA_TUNNEL_FILTER_ALLOC_REQ_TUNNEL_TYPE_VXLAN_V4 0x9UL
+ #define CFA_TUNNEL_FILTER_ALLOC_REQ_TUNNEL_TYPE_IPGRE_V1 0xaUL
+ #define CFA_TUNNEL_FILTER_ALLOC_REQ_TUNNEL_TYPE_L2_ETYPE 0xbUL
#define CFA_TUNNEL_FILTER_ALLOC_REQ_TUNNEL_TYPE_ANYTUNNEL 0xffUL
#define CFA_TUNNEL_FILTER_ALLOC_REQ_TUNNEL_TYPE_LAST CFA_TUNNEL_FILTER_ALLOC_REQ_TUNNEL_TYPE_ANYTUNNEL
u8 tunnel_flags;
@@ -5140,7 +5196,7 @@ struct hwrm_vxlan_ipv6_hdr {
__be32 dest_ip_addr[4];
};
-/* hwrm_cfa_encap_data_vxlan (size:576b/72B) */
+/* hwrm_cfa_encap_data_vxlan (size:640b/80B) */
struct hwrm_cfa_encap_data_vxlan {
u8 src_mac_addr[6];
__le16 unused_0;
@@ -5159,6 +5215,10 @@ struct hwrm_cfa_encap_data_vxlan {
__be16 src_port;
__be16 dst_port;
__be32 vni;
+ u8 hdr_rsvd0[3];
+ u8 hdr_rsvd1;
+ u8 hdr_flags;
+ u8 unused[3];
};
/* hwrm_cfa_encap_record_alloc_input (size:832b/104B) */
@@ -5171,15 +5231,18 @@ struct hwrm_cfa_encap_record_alloc_input {
__le32 flags;
#define CFA_ENCAP_RECORD_ALLOC_REQ_FLAGS_LOOPBACK 0x1UL
u8 encap_type;
- #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_VXLAN 0x1UL
- #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_NVGRE 0x2UL
- #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_L2GRE 0x3UL
- #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_IPIP 0x4UL
- #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_GENEVE 0x5UL
- #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_MPLS 0x6UL
- #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_VLAN 0x7UL
- #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_IPGRE 0x8UL
- #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_LAST CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_IPGRE
+ #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_VXLAN 0x1UL
+ #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_NVGRE 0x2UL
+ #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_L2GRE 0x3UL
+ #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_IPIP 0x4UL
+ #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_GENEVE 0x5UL
+ #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_MPLS 0x6UL
+ #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_VLAN 0x7UL
+ #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_IPGRE 0x8UL
+ #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_VXLAN_V4 0x9UL
+ #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_IPGRE_V1 0xaUL
+ #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_L2_ETYPE 0xbUL
+ #define CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_LAST CFA_ENCAP_RECORD_ALLOC_REQ_ENCAP_TYPE_L2_ETYPE
u8 unused_0[3];
__le32 encap_data[20];
};
@@ -5273,6 +5336,8 @@ struct hwrm_cfa_ntuple_filter_alloc_input {
#define CFA_NTUPLE_FILTER_ALLOC_REQ_TUNNEL_TYPE_STT 0x7UL
#define CFA_NTUPLE_FILTER_ALLOC_REQ_TUNNEL_TYPE_IPGRE 0x8UL
#define CFA_NTUPLE_FILTER_ALLOC_REQ_TUNNEL_TYPE_VXLAN_V4 0x9UL
+ #define CFA_NTUPLE_FILTER_ALLOC_REQ_TUNNEL_TYPE_IPGRE_V1 0xaUL
+ #define CFA_NTUPLE_FILTER_ALLOC_REQ_TUNNEL_TYPE_L2_ETYPE 0xbUL
#define CFA_NTUPLE_FILTER_ALLOC_REQ_TUNNEL_TYPE_ANYTUNNEL 0xffUL
#define CFA_NTUPLE_FILTER_ALLOC_REQ_TUNNEL_TYPE_LAST CFA_NTUPLE_FILTER_ALLOC_REQ_TUNNEL_TYPE_ANYTUNNEL
u8 pri_hint;
@@ -5404,6 +5469,8 @@ struct hwrm_cfa_decap_filter_alloc_input {
#define CFA_DECAP_FILTER_ALLOC_REQ_TUNNEL_TYPE_STT 0x7UL
#define CFA_DECAP_FILTER_ALLOC_REQ_TUNNEL_TYPE_IPGRE 0x8UL
#define CFA_DECAP_FILTER_ALLOC_REQ_TUNNEL_TYPE_VXLAN_V4 0x9UL
+ #define CFA_DECAP_FILTER_ALLOC_REQ_TUNNEL_TYPE_IPGRE_V1 0xaUL
+ #define CFA_DECAP_FILTER_ALLOC_REQ_TUNNEL_TYPE_L2_ETYPE 0xbUL
#define CFA_DECAP_FILTER_ALLOC_REQ_TUNNEL_TYPE_ANYTUNNEL 0xffUL
#define CFA_DECAP_FILTER_ALLOC_REQ_TUNNEL_TYPE_LAST CFA_DECAP_FILTER_ALLOC_REQ_TUNNEL_TYPE_ANYTUNNEL
u8 unused_0;
@@ -5476,19 +5543,22 @@ struct hwrm_cfa_flow_alloc_input {
__le16 target_id;
__le64 resp_addr;
__le16 flags;
- #define CFA_FLOW_ALLOC_REQ_FLAGS_TUNNEL 0x1UL
- #define CFA_FLOW_ALLOC_REQ_FLAGS_NUM_VLAN_MASK 0x6UL
- #define CFA_FLOW_ALLOC_REQ_FLAGS_NUM_VLAN_SFT 1
- #define CFA_FLOW_ALLOC_REQ_FLAGS_NUM_VLAN_NONE (0x0UL << 1)
- #define CFA_FLOW_ALLOC_REQ_FLAGS_NUM_VLAN_ONE (0x1UL << 1)
- #define CFA_FLOW_ALLOC_REQ_FLAGS_NUM_VLAN_TWO (0x2UL << 1)
- #define CFA_FLOW_ALLOC_REQ_FLAGS_NUM_VLAN_LAST CFA_FLOW_ALLOC_REQ_FLAGS_NUM_VLAN_TWO
- #define CFA_FLOW_ALLOC_REQ_FLAGS_FLOWTYPE_MASK 0x38UL
- #define CFA_FLOW_ALLOC_REQ_FLAGS_FLOWTYPE_SFT 3
- #define CFA_FLOW_ALLOC_REQ_FLAGS_FLOWTYPE_L2 (0x0UL << 3)
- #define CFA_FLOW_ALLOC_REQ_FLAGS_FLOWTYPE_IPV4 (0x1UL << 3)
- #define CFA_FLOW_ALLOC_REQ_FLAGS_FLOWTYPE_IPV6 (0x2UL << 3)
- #define CFA_FLOW_ALLOC_REQ_FLAGS_FLOWTYPE_LAST CFA_FLOW_ALLOC_REQ_FLAGS_FLOWTYPE_IPV6
+ #define CFA_FLOW_ALLOC_REQ_FLAGS_TUNNEL 0x1UL
+ #define CFA_FLOW_ALLOC_REQ_FLAGS_NUM_VLAN_MASK 0x6UL
+ #define CFA_FLOW_ALLOC_REQ_FLAGS_NUM_VLAN_SFT 1
+ #define CFA_FLOW_ALLOC_REQ_FLAGS_NUM_VLAN_NONE (0x0UL << 1)
+ #define CFA_FLOW_ALLOC_REQ_FLAGS_NUM_VLAN_ONE (0x1UL << 1)
+ #define CFA_FLOW_ALLOC_REQ_FLAGS_NUM_VLAN_TWO (0x2UL << 1)
+ #define CFA_FLOW_ALLOC_REQ_FLAGS_NUM_VLAN_LAST CFA_FLOW_ALLOC_REQ_FLAGS_NUM_VLAN_TWO
+ #define CFA_FLOW_ALLOC_REQ_FLAGS_FLOWTYPE_MASK 0x38UL
+ #define CFA_FLOW_ALLOC_REQ_FLAGS_FLOWTYPE_SFT 3
+ #define CFA_FLOW_ALLOC_REQ_FLAGS_FLOWTYPE_L2 (0x0UL << 3)
+ #define CFA_FLOW_ALLOC_REQ_FLAGS_FLOWTYPE_IPV4 (0x1UL << 3)
+ #define CFA_FLOW_ALLOC_REQ_FLAGS_FLOWTYPE_IPV6 (0x2UL << 3)
+ #define CFA_FLOW_ALLOC_REQ_FLAGS_FLOWTYPE_LAST CFA_FLOW_ALLOC_REQ_FLAGS_FLOWTYPE_IPV6
+ #define CFA_FLOW_ALLOC_REQ_FLAGS_PATH_TX 0x40UL
+ #define CFA_FLOW_ALLOC_REQ_FLAGS_PATH_RX 0x80UL
+ #define CFA_FLOW_ALLOC_REQ_FLAGS_MATCH_VXLAN_IP_VNI 0x100UL
__le16 src_fid;
__le32 tunnel_handle;
__le16 action_flags;
@@ -5502,6 +5572,7 @@ struct hwrm_cfa_flow_alloc_input {
#define CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_NAT_IPV4_ADDRESS 0x80UL
#define CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_L2_HEADER_REWRITE 0x100UL
#define CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_TTL_DECREMENT 0x200UL
+ #define CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_TUNNEL_IP 0x400UL
__le16 dst_fid;
__be16 l2_rewrite_vlan_tpid;
__be16 l2_rewrite_vlan_tci;
@@ -5525,21 +5596,38 @@ struct hwrm_cfa_flow_alloc_input {
__be16 nat_port;
__be16 l2_rewrite_smac[3];
u8 ip_proto;
- u8 unused_0;
-};
-
-/* hwrm_cfa_flow_alloc_output (size:128b/16B) */
+ u8 tunnel_type;
+ #define CFA_FLOW_ALLOC_REQ_TUNNEL_TYPE_NONTUNNEL 0x0UL
+ #define CFA_FLOW_ALLOC_REQ_TUNNEL_TYPE_VXLAN 0x1UL
+ #define CFA_FLOW_ALLOC_REQ_TUNNEL_TYPE_NVGRE 0x2UL
+ #define CFA_FLOW_ALLOC_REQ_TUNNEL_TYPE_L2GRE 0x3UL
+ #define CFA_FLOW_ALLOC_REQ_TUNNEL_TYPE_IPIP 0x4UL
+ #define CFA_FLOW_ALLOC_REQ_TUNNEL_TYPE_GENEVE 0x5UL
+ #define CFA_FLOW_ALLOC_REQ_TUNNEL_TYPE_MPLS 0x6UL
+ #define CFA_FLOW_ALLOC_REQ_TUNNEL_TYPE_STT 0x7UL
+ #define CFA_FLOW_ALLOC_REQ_TUNNEL_TYPE_IPGRE 0x8UL
+ #define CFA_FLOW_ALLOC_REQ_TUNNEL_TYPE_VXLAN_V4 0x9UL
+ #define CFA_FLOW_ALLOC_REQ_TUNNEL_TYPE_IPGRE_V1 0xaUL
+ #define CFA_FLOW_ALLOC_REQ_TUNNEL_TYPE_L2_ETYPE 0xbUL
+ #define CFA_FLOW_ALLOC_REQ_TUNNEL_TYPE_ANYTUNNEL 0xffUL
+ #define CFA_FLOW_ALLOC_REQ_TUNNEL_TYPE_LAST CFA_FLOW_ALLOC_REQ_TUNNEL_TYPE_ANYTUNNEL
+};
+
+/* hwrm_cfa_flow_alloc_output (size:256b/32B) */
struct hwrm_cfa_flow_alloc_output {
__le16 error_code;
__le16 req_type;
__le16 seq_id;
__le16 resp_len;
__le16 flow_handle;
- u8 unused_0[5];
+ u8 unused_0[2];
+ __le32 flow_id;
+ __le64 ext_flow_handle;
+ u8 unused_1[7];
u8 valid;
};
-/* hwrm_cfa_flow_free_input (size:192b/24B) */
+/* hwrm_cfa_flow_free_input (size:256b/32B) */
struct hwrm_cfa_flow_free_input {
__le16 req_type;
__le16 cmpl_ring;
@@ -5548,6 +5636,7 @@ struct hwrm_cfa_flow_free_input {
__le64 resp_addr;
__le16 flow_handle;
u8 unused_0[6];
+ __le64 ext_flow_handle;
};
/* hwrm_cfa_flow_free_output (size:256b/32B) */
@@ -5562,7 +5651,7 @@ struct hwrm_cfa_flow_free_output {
u8 valid;
};
-/* hwrm_cfa_flow_stats_input (size:320b/40B) */
+/* hwrm_cfa_flow_stats_input (size:640b/80B) */
struct hwrm_cfa_flow_stats_input {
__le16 req_type;
__le16 cmpl_ring;
@@ -5581,6 +5670,16 @@ struct hwrm_cfa_flow_stats_input {
__le16 flow_handle_8;
__le16 flow_handle_9;
u8 unused_0[2];
+ __le32 flow_id_0;
+ __le32 flow_id_1;
+ __le32 flow_id_2;
+ __le32 flow_id_3;
+ __le32 flow_id_4;
+ __le32 flow_id_5;
+ __le32 flow_id_6;
+ __le32 flow_id_7;
+ __le32 flow_id_8;
+ __le32 flow_id_9;
};
/* hwrm_cfa_flow_stats_output (size:1408b/176B) */
@@ -5670,7 +5769,8 @@ struct hwrm_tunnel_dst_port_query_input {
#define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_GENEVE 0x5UL
#define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_VXLAN_V4 0x9UL
#define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_IPGRE_V1 0xaUL
- #define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_LAST TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_IPGRE_V1
+ #define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_L2_ETYPE 0xbUL
+ #define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_LAST TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_L2_ETYPE
u8 unused_0[7];
};
@@ -5698,7 +5798,8 @@ struct hwrm_tunnel_dst_port_alloc_input {
#define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_GENEVE 0x5UL
#define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_VXLAN_V4 0x9UL
#define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_IPGRE_V1 0xaUL
- #define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_LAST TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_IPGRE_V1
+ #define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_L2_ETYPE 0xbUL
+ #define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_LAST TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_L2_ETYPE
u8 unused_0;
__be16 tunnel_dst_port_val;
u8 unused_1[4];
@@ -5727,7 +5828,8 @@ struct hwrm_tunnel_dst_port_free_input {
#define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_GENEVE 0x5UL
#define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_VXLAN_V4 0x9UL
#define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_IPGRE_V1 0xaUL
- #define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_LAST TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_IPGRE_V1
+ #define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_L2_ETYPE 0xbUL
+ #define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_LAST TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_L2_ETYPE
u8 unused_0;
__le16 tunnel_dst_port_id;
u8 unused_1[4];
@@ -5932,10 +6034,11 @@ struct hwrm_fw_reset_input {
#define FW_RESET_REQ_EMBEDDED_PROC_TYPE_HOST_RESOURCE_REINIT 0x7UL
#define FW_RESET_REQ_EMBEDDED_PROC_TYPE_LAST FW_RESET_REQ_EMBEDDED_PROC_TYPE_HOST_RESOURCE_REINIT
u8 selfrst_status;
- #define FW_RESET_REQ_SELFRST_STATUS_SELFRSTNONE 0x0UL
- #define FW_RESET_REQ_SELFRST_STATUS_SELFRSTASAP 0x1UL
- #define FW_RESET_REQ_SELFRST_STATUS_SELFRSTPCIERST 0x2UL
- #define FW_RESET_REQ_SELFRST_STATUS_LAST FW_RESET_REQ_SELFRST_STATUS_SELFRSTPCIERST
+ #define FW_RESET_REQ_SELFRST_STATUS_SELFRSTNONE 0x0UL
+ #define FW_RESET_REQ_SELFRST_STATUS_SELFRSTASAP 0x1UL
+ #define FW_RESET_REQ_SELFRST_STATUS_SELFRSTPCIERST 0x2UL
+ #define FW_RESET_REQ_SELFRST_STATUS_SELFRSTIMMEDIATE 0x3UL
+ #define FW_RESET_REQ_SELFRST_STATUS_LAST FW_RESET_REQ_SELFRST_STATUS_SELFRSTIMMEDIATE
u8 host_idx;
u8 unused_0[5];
};
@@ -5947,10 +6050,11 @@ struct hwrm_fw_reset_output {
__le16 seq_id;
__le16 resp_len;
u8 selfrst_status;
- #define FW_RESET_RESP_SELFRST_STATUS_SELFRSTNONE 0x0UL
- #define FW_RESET_RESP_SELFRST_STATUS_SELFRSTASAP 0x1UL
- #define FW_RESET_RESP_SELFRST_STATUS_SELFRSTPCIERST 0x2UL
- #define FW_RESET_RESP_SELFRST_STATUS_LAST FW_RESET_RESP_SELFRST_STATUS_SELFRSTPCIERST
+ #define FW_RESET_RESP_SELFRST_STATUS_SELFRSTNONE 0x0UL
+ #define FW_RESET_RESP_SELFRST_STATUS_SELFRSTASAP 0x1UL
+ #define FW_RESET_RESP_SELFRST_STATUS_SELFRSTPCIERST 0x2UL
+ #define FW_RESET_RESP_SELFRST_STATUS_SELFRSTIMMEDIATE 0x3UL
+ #define FW_RESET_RESP_SELFRST_STATUS_LAST FW_RESET_RESP_SELFRST_STATUS_SELFRSTIMMEDIATE
u8 unused_0[6];
u8 valid;
};
@@ -6498,6 +6602,34 @@ struct hwrm_dbg_coredump_retrieve_output {
u8 valid;
};
+/* hwrm_dbg_ring_info_get_input (size:192b/24B) */
+struct hwrm_dbg_ring_info_get_input {
+ __le16 req_type;
+ __le16 cmpl_ring;
+ __le16 seq_id;
+ __le16 target_id;
+ __le64 resp_addr;
+ u8 ring_type;
+ #define DBG_RING_INFO_GET_REQ_RING_TYPE_L2_CMPL 0x0UL
+ #define DBG_RING_INFO_GET_REQ_RING_TYPE_TX 0x1UL
+ #define DBG_RING_INFO_GET_REQ_RING_TYPE_RX 0x2UL
+ #define DBG_RING_INFO_GET_REQ_RING_TYPE_LAST DBG_RING_INFO_GET_REQ_RING_TYPE_RX
+ u8 unused_0[3];
+ __le32 fw_ring_id;
+};
+
+/* hwrm_dbg_ring_info_get_output (size:192b/24B) */
+struct hwrm_dbg_ring_info_get_output {
+ __le16 error_code;
+ __le16 req_type;
+ __le16 seq_id;
+ __le16 resp_len;
+ __le32 producer_index;
+ __le32 consumer_index;
+ u8 unused_0[7];
+ u8 valid;
+};
+
/* hwrm_nvm_read_input (size:320b/40B) */
struct hwrm_nvm_read_input {
__le16 req_type;
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
index e1594c9df4c6..749f63beddd8 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
@@ -189,7 +189,6 @@ static int bnxt_tc_parse_flow(struct bnxt *bp,
struct bnxt_tc_flow *flow)
{
struct flow_dissector *dissector = tc_flow_cmd->dissector;
- u16 addr_type = 0;
/* KEY_CONTROL and KEY_BASIC are needed for forming a meaningful key */
if ((dissector->used_keys & BIT(FLOW_DISSECTOR_KEY_CONTROL)) == 0 ||
@@ -199,13 +198,6 @@ static int bnxt_tc_parse_flow(struct bnxt *bp,
return -EOPNOTSUPP;
}
- if (dissector_uses_key(dissector, FLOW_DISSECTOR_KEY_CONTROL)) {
- struct flow_dissector_key_control *key =
- GET_KEY(tc_flow_cmd, FLOW_DISSECTOR_KEY_CONTROL);
-
- addr_type = key->addr_type;
- }
-
if (dissector_uses_key(dissector, FLOW_DISSECTOR_KEY_BASIC)) {
struct flow_dissector_key_basic *key =
GET_KEY(tc_flow_cmd, FLOW_DISSECTOR_KEY_BASIC);
@@ -301,13 +293,6 @@ static int bnxt_tc_parse_flow(struct bnxt *bp,
flow->l4_mask.icmp.code = mask->code;
}
- if (dissector_uses_key(dissector, FLOW_DISSECTOR_KEY_ENC_CONTROL)) {
- struct flow_dissector_key_control *key =
- GET_KEY(tc_flow_cmd, FLOW_DISSECTOR_KEY_ENC_CONTROL);
-
- addr_type = key->addr_type;
- }
-
if (dissector_uses_key(dissector, FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS)) {
struct flow_dissector_key_ipv4_addrs *key =
GET_KEY(tc_flow_cmd, FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS);
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c
index e31f5d803c13..9a25c05aa571 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c
@@ -209,9 +209,7 @@ struct net_device *bnxt_get_vf_rep(struct bnxt *bp, u16 cfa_code)
void bnxt_vf_rep_rx(struct bnxt *bp, struct sk_buff *skb)
{
struct bnxt_vf_rep *vf_rep = netdev_priv(skb->dev);
- struct bnxt_vf_rep_stats *rx_stats;
- rx_stats = &vf_rep->rx_stats;
vf_rep->rx_stats.bytes += skb->len;
vf_rep->rx_stats.packets++;
@@ -523,7 +521,8 @@ int bnxt_dl_eswitch_mode_get(struct devlink *devlink, u16 *mode)
return 0;
}
-int bnxt_dl_eswitch_mode_set(struct devlink *devlink, u16 mode)
+int bnxt_dl_eswitch_mode_set(struct devlink *devlink, u16 mode,
+ struct netlink_ext_ack *extack)
{
struct bnxt *bp = bnxt_get_bp_from_dl(devlink);
int rc = 0;
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.h
index 38b9a75ad724..d7287651422f 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.h
@@ -30,7 +30,8 @@ static inline u16 bnxt_vf_rep_get_fid(struct net_device *dev)
bool bnxt_dev_is_vf_rep(struct net_device *dev);
int bnxt_dl_eswitch_mode_get(struct devlink *devlink, u16 *mode);
-int bnxt_dl_eswitch_mode_set(struct devlink *devlink, u16 mode);
+int bnxt_dl_eswitch_mode_set(struct devlink *devlink, u16 mode,
+ struct netlink_ext_ack *extack);
#else
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c
index 0584d07c8c33..bf6de02be396 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c
@@ -63,7 +63,7 @@ void bnxt_tx_int_xdp(struct bnxt *bp, struct bnxt_napi *bnapi, int nr_pkts)
tx_buf = &txr->tx_buf_ring[last_tx_cons];
rx_prod = tx_buf->rx_prod;
}
- bnxt_db_write(bp, rxr->rx_doorbell, DB_KEY_RX | rx_prod);
+ bnxt_db_write(bp, &rxr->rx_db, rx_prod);
}
/* returns the following:
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 20c1681bb1af..2d6f090bf644 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -2855,7 +2855,6 @@ static void bcmgenet_netif_start(struct net_device *dev)
umac_enable_set(priv, CMD_TX_EN | CMD_RX_EN, true);
- netif_tx_start_all_queues(dev);
bcmgenet_enable_tx_napi(priv);
/* Monitor link interrupts now */
@@ -2937,6 +2936,8 @@ static int bcmgenet_open(struct net_device *dev)
bcmgenet_netif_start(dev);
+ netif_tx_start_all_queues(dev);
+
return 0;
err_irq1:
@@ -2958,7 +2959,7 @@ static void bcmgenet_netif_stop(struct net_device *dev)
struct bcmgenet_priv *priv = netdev_priv(dev);
bcmgenet_disable_tx_napi(priv);
- netif_tx_stop_all_queues(dev);
+ netif_tx_disable(dev);
/* Disable MAC receive */
umac_enable_set(priv, CMD_RX_EN, false);
@@ -3620,13 +3621,13 @@ static int bcmgenet_suspend(struct device *d)
if (!netif_running(dev))
return 0;
+ netif_device_detach(dev);
+
bcmgenet_netif_stop(dev);
if (!device_may_wakeup(d))
phy_suspend(dev->phydev);
- netif_device_detach(dev);
-
/* Prepare the device for Wake-on-LAN and switch to the slow clock */
if (device_may_wakeup(d) && priv->wolopts) {
ret = bcmgenet_power_down(priv, GENET_POWER_WOL_MAGIC);
@@ -3700,8 +3701,6 @@ static int bcmgenet_resume(struct device *d)
/* Always enable ring 16 - descriptor ring */
bcmgenet_enable_dma(priv, dma_ctrl);
- netif_device_attach(dev);
-
if (!device_may_wakeup(d))
phy_resume(dev->phydev);
@@ -3710,6 +3709,8 @@ static int bcmgenet_resume(struct device *d)
bcmgenet_netif_start(dev);
+ netif_device_attach(dev);
+
return 0;
out_clk_disable:
diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c
index 4241ae928d4a..a6cbaca37e94 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmmii.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c
@@ -214,7 +214,7 @@ int bcmgenet_mii_config(struct net_device *dev, bool init)
case PHY_INTERFACE_MODE_MII:
phy_name = "external MII";
- phydev->supported &= PHY_BASIC_FEATURES;
+ phy_set_max_speed(phydev, SPEED_100);
bcmgenet_sys_writel(priv,
PORT_MODE_EXT_EPHY, SYS_PORT_CTRL);
break;
@@ -226,11 +226,10 @@ int bcmgenet_mii_config(struct net_device *dev, bool init)
* capabilities, use that knowledge to also configure the
* Reverse MII interface correctly.
*/
- if ((dev->phydev->supported & PHY_BASIC_FEATURES) ==
- PHY_BASIC_FEATURES)
- port_ctrl = PORT_MODE_EXT_RVMII_25;
- else
+ if (dev->phydev->supported & PHY_1000BT_FEATURES)
port_ctrl = PORT_MODE_EXT_RVMII_50;
+ else
+ port_ctrl = PORT_MODE_EXT_RVMII_25;
bcmgenet_sys_writel(priv, port_ctrl, SYS_PORT_CTRL);
break;
@@ -321,9 +320,12 @@ int bcmgenet_mii_probe(struct net_device *dev)
phydev->advertising = phydev->supported;
/* The internal PHY has its link interrupts routed to the
- * Ethernet MAC ISRs
+ * Ethernet MAC ISRs. On GENETv5 there is a hardware issue
+ * that prevents the signaling of link UP interrupts when
+ * the link operates at 10Mbps, so fallback to polling for
+ * those versions of GENET.
*/
- if (priv->internal_phy)
+ if (priv->internal_phy && !GENET_IS_V5(priv))
dev->phydev->irq = PHY_IGNORE_INTERRUPT;
return 0;
@@ -339,7 +341,7 @@ static struct device_node *bcmgenet_mii_of_find_mdio(struct bcmgenet_priv *priv)
if (!compat)
return NULL;
- priv->mdio_dn = of_find_compatible_node(dn, NULL, compat);
+ priv->mdio_dn = of_get_compatible_child(dn, compat);
kfree(compat);
if (!priv->mdio_dn) {
dev_err(kdev, "unable to find MDIO bus node\n");
diff --git a/drivers/net/ethernet/broadcom/sb1250-mac.c b/drivers/net/ethernet/broadcom/sb1250-mac.c
index ef4a0c326736..5db9f4158e62 100644
--- a/drivers/net/ethernet/broadcom/sb1250-mac.c
+++ b/drivers/net/ethernet/broadcom/sb1250-mac.c
@@ -156,7 +156,7 @@ enum sbmac_state {
(d)->sbdma_dscrtable : (d)->f+1)
-#define NUMCACHEBLKS(x) (((x)+SMP_CACHE_BYTES-1)/SMP_CACHE_BYTES)
+#define NUMCACHEBLKS(x) DIV_ROUND_UP(x, SMP_CACHE_BYTES)
#define SBMAC_MAX_TXDESCR 256
#define SBMAC_MAX_RXDESCR 256
@@ -299,7 +299,7 @@ static enum sbmac_state sbmac_set_channel_state(struct sbmac_softc *,
static void sbmac_promiscuous_mode(struct sbmac_softc *sc, int onoff);
static uint64_t sbmac_addr2reg(unsigned char *ptr);
static irqreturn_t sbmac_intr(int irq, void *dev_instance);
-static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev);
+static netdev_tx_t sbmac_start_tx(struct sk_buff *skb, struct net_device *dev);
static void sbmac_setmulti(struct sbmac_softc *sc);
static int sbmac_init(struct platform_device *pldev, long long base);
static int sbmac_set_speed(struct sbmac_softc *s, enum sbmac_speed speed);
@@ -2028,7 +2028,7 @@ static irqreturn_t sbmac_intr(int irq,void *dev_instance)
* Return value:
* nothing
********************************************************************* */
-static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t sbmac_start_tx(struct sk_buff *skb, struct net_device *dev)
{
struct sbmac_softc *sc = netdev_priv(dev);
unsigned long flags;
@@ -2357,21 +2357,11 @@ static int sbmac_mii_probe(struct net_device *dev)
}
/* Remove any features not supported by the controller */
- phy_dev->supported &= SUPPORTED_10baseT_Half |
- SUPPORTED_10baseT_Full |
- SUPPORTED_100baseT_Half |
- SUPPORTED_100baseT_Full |
- SUPPORTED_1000baseT_Half |
- SUPPORTED_1000baseT_Full |
- SUPPORTED_Autoneg |
- SUPPORTED_MII |
- SUPPORTED_Pause |
- SUPPORTED_Asym_Pause;
+ phy_set_max_speed(phy_dev, SPEED_1000);
+ phy_support_asym_pause(phy_dev);
phy_attached_info(phy_dev);
- phy_dev->advertising = phy_dev->supported;
-
sc->phy_dev = phy_dev;
return 0;
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index e6f28c7942ab..89295306f161 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -1598,7 +1598,7 @@ static int tg3_mdio_init(struct tg3 *tp)
phydev->dev_flags |= PHY_BRCM_EXT_IBND_RX_ENABLE;
if (tg3_flag(tp, RGMII_EXT_IBND_TX_EN))
phydev->dev_flags |= PHY_BRCM_EXT_IBND_TX_ENABLE;
- /* fallthru */
+ /* fall through */
case PHY_ID_RTL8211C:
phydev->interface = PHY_INTERFACE_MODE_RGMII;
break;
@@ -2122,16 +2122,14 @@ static int tg3_phy_init(struct tg3 *tp)
case PHY_INTERFACE_MODE_GMII:
case PHY_INTERFACE_MODE_RGMII:
if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY)) {
- phydev->supported &= (PHY_GBIT_FEATURES |
- SUPPORTED_Pause |
- SUPPORTED_Asym_Pause);
+ phy_set_max_speed(phydev, SPEED_1000);
+ phy_support_asym_pause(phydev);
break;
}
- /* fallthru */
+ /* fall through */
case PHY_INTERFACE_MODE_MII:
- phydev->supported &= (PHY_BASIC_FEATURES |
- SUPPORTED_Pause |
- SUPPORTED_Asym_Pause);
+ phy_set_max_speed(phydev, SPEED_100);
+ phy_support_asym_pause(phydev);
break;
default:
phy_disconnect(mdiobus_get_phy(tp->mdio_bus, tp->phy_addr));
@@ -2140,8 +2138,6 @@ static int tg3_phy_init(struct tg3 *tp)
tp->phy_flags |= TG3_PHYFLG_IS_CONNECTED;
- phydev->advertising = phydev->supported;
-
phy_attached_info(phydev);
return 0;
@@ -5215,7 +5211,7 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp,
if (ap->flags & (MR_AN_ENABLE | MR_RESTART_AN))
ap->state = ANEG_STATE_AN_ENABLE;
- /* fallthru */
+ /* fall through */
case ANEG_STATE_AN_ENABLE:
ap->flags &= ~(MR_AN_COMPLETE | MR_PAGE_RX);
if (ap->flags & MR_AN_ENABLE) {
@@ -5245,7 +5241,7 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp,
ret = ANEG_TIMER_ENAB;
ap->state = ANEG_STATE_RESTART;
- /* fallthru */
+ /* fall through */
case ANEG_STATE_RESTART:
delta = ap->cur_time - ap->link_time;
if (delta > ANEG_STATE_SETTLE_TIME)
@@ -5288,7 +5284,7 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp,
ap->state = ANEG_STATE_ACK_DETECT;
- /* fallthru */
+ /* fall through */
case ANEG_STATE_ACK_DETECT:
if (ap->ack_match != 0) {
if ((ap->rxconfig & ~ANEG_CFG_ACK) ==
@@ -12496,31 +12492,24 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam
tg3_warn_mgmt_link_flap(tp);
if (tg3_flag(tp, USE_PHYLIB)) {
- u32 newadv;
struct phy_device *phydev;
phydev = mdiobus_get_phy(tp->mdio_bus, tp->phy_addr);
- if (!(phydev->supported & SUPPORTED_Pause) ||
- (!(phydev->supported & SUPPORTED_Asym_Pause) &&
- (epause->rx_pause != epause->tx_pause)))
+ if (!phy_validate_pause(phydev, epause))
return -EINVAL;
tp->link_config.flowctrl = 0;
+ phy_set_asym_pause(phydev, epause->rx_pause, epause->tx_pause);
if (epause->rx_pause) {
tp->link_config.flowctrl |= FLOW_CTRL_RX;
if (epause->tx_pause) {
tp->link_config.flowctrl |= FLOW_CTRL_TX;
- newadv = ADVERTISED_Pause;
- } else
- newadv = ADVERTISED_Pause |
- ADVERTISED_Asym_Pause;
+ }
} else if (epause->tx_pause) {
tp->link_config.flowctrl |= FLOW_CTRL_TX;
- newadv = ADVERTISED_Asym_Pause;
- } else
- newadv = 0;
+ }
if (epause->autoneg)
tg3_flag_set(tp, PAUSE_AUTONEG);
@@ -12528,33 +12517,19 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam
tg3_flag_clear(tp, PAUSE_AUTONEG);
if (tp->phy_flags & TG3_PHYFLG_IS_CONNECTED) {
- u32 oldadv = phydev->advertising &
- (ADVERTISED_Pause | ADVERTISED_Asym_Pause);
- if (oldadv != newadv) {
- phydev->advertising &=
- ~(ADVERTISED_Pause |
- ADVERTISED_Asym_Pause);
- phydev->advertising |= newadv;
- if (phydev->autoneg) {
- /*
- * Always renegotiate the link to
- * inform our link partner of our
- * flow control settings, even if the
- * flow control is forced. Let
- * tg3_adjust_link() do the final
- * flow control setup.
- */
- return phy_start_aneg(phydev);
- }
+ if (phydev->autoneg) {
+ /* phy_set_asym_pause() will
+ * renegotiate the link to inform our
+ * link partner of our flow control
+ * settings, even if the flow control
+ * is forced. Let tg3_adjust_link()
+ * do the final flow control setup.
+ */
+ return 0;
}
if (!epause->autoneg)
tg3_setup_flow_control(tp, 0, 0);
- } else {
- tp->link_config.advertising &=
- ~(ADVERTISED_Pause |
- ADVERTISED_Asym_Pause);
- tp->link_config.advertising |= newadv;
}
} else {
int irq_sync = 0;
@@ -14013,7 +13988,7 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
case SIOCGMIIPHY:
data->phy_id = tp->phy_addr;
- /* fallthru */
+ /* fall through */
case SIOCGMIIREG: {
u32 mii_regval;
diff --git a/drivers/net/ethernet/brocade/bna/bna_enet.c b/drivers/net/ethernet/brocade/bna/bna_enet.c
index bba81735ce87..6d2d4527357c 100644
--- a/drivers/net/ethernet/brocade/bna/bna_enet.c
+++ b/drivers/net/ethernet/brocade/bna/bna_enet.c
@@ -1797,7 +1797,7 @@ bna_ucam_mod_init(struct bna_ucam_mod *ucam_mod, struct bna *bna,
/* A separate queue to allow synchronous setting of a list of MACs */
INIT_LIST_HEAD(&ucam_mod->del_q);
- for (i = i; i < (bna->ioceth.attr.num_ucmac * 2); i++)
+ for (; i < (bna->ioceth.attr.num_ucmac * 2); i++)
list_add_tail(&ucam_mod->ucmac[i].qe, &ucam_mod->del_q);
ucam_mod->bna = bna;
@@ -1832,7 +1832,7 @@ bna_mcam_mod_init(struct bna_mcam_mod *mcam_mod, struct bna *bna,
/* A separate queue to allow synchronous setting of a list of MACs */
INIT_LIST_HEAD(&mcam_mod->del_q);
- for (i = i; i < (bna->ioceth.attr.num_mcmac * 2); i++)
+ for (; i < (bna->ioceth.attr.num_mcmac * 2); i++)
list_add_tail(&mcam_mod->mcmac[i].qe, &mcam_mod->del_q);
mcam_mod->bna = bna;
diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
index f1a86b422617..1d86b4d5645a 100644
--- a/drivers/net/ethernet/cadence/macb_main.c
+++ b/drivers/net/ethernet/cadence/macb_main.c
@@ -544,14 +544,13 @@ static int macb_mii_probe(struct net_device *dev)
/* mask with MAC supported features */
if (macb_is_gem(bp) && bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE)
- phydev->supported &= PHY_GBIT_FEATURES;
+ phy_set_max_speed(phydev, SPEED_1000);
else
- phydev->supported &= PHY_BASIC_FEATURES;
+ phy_set_max_speed(phydev, SPEED_100);
if (bp->caps & MACB_CAPS_NO_GIGABIT_HALF)
- phydev->supported &= ~SUPPORTED_1000baseT_Half;
-
- phydev->advertising = phydev->supported;
+ phy_remove_link_mode(phydev,
+ ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
bp->link = 0;
bp->speed = 0;
@@ -1685,7 +1684,7 @@ static int macb_pad_and_fcs(struct sk_buff **skb, struct net_device *ndev)
padlen = 0;
/* No room for FCS, need to reallocate skb. */
else
- padlen = ETH_FCS_LEN - tailroom;
+ padlen = ETH_FCS_LEN;
} else {
/* Add room for FCS. */
padlen += ETH_FCS_LEN;
@@ -2160,6 +2159,7 @@ static void macb_configure_dma(struct macb *bp)
else
dmacfg &= ~GEM_BIT(TXCOEN);
+ dmacfg &= ~GEM_BIT(ADDR64);
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
if (bp->hw_dma_cap & HW_DMA_CAP_64B)
dmacfg |= GEM_BIT(ADDR64);
@@ -4156,8 +4156,7 @@ static int macb_remove(struct platform_device *pdev)
static int __maybe_unused macb_suspend(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct net_device *netdev = platform_get_drvdata(pdev);
+ struct net_device *netdev = dev_get_drvdata(dev);
struct macb *bp = netdev_priv(netdev);
netif_carrier_off(netdev);
@@ -4179,8 +4178,7 @@ static int __maybe_unused macb_suspend(struct device *dev)
static int __maybe_unused macb_resume(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct net_device *netdev = platform_get_drvdata(pdev);
+ struct net_device *netdev = dev_get_drvdata(dev);
struct macb *bp = netdev_priv(netdev);
if (bp->wol & MACB_WOL_ENABLED) {
diff --git a/drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c b/drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c
index 962bb62933db..fda49404968c 100644
--- a/drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c
+++ b/drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c
@@ -616,7 +616,7 @@ static void cn23xx_disable_vf_interrupt(struct octeon_device *oct, u8 intr_flag)
int cn23xx_setup_octeon_vf_device(struct octeon_device *oct)
{
struct octeon_cn23xx_vf *cn23xx = (struct octeon_cn23xx_vf *)oct->chip;
- u32 rings_per_vf, ring_flag;
+ u32 rings_per_vf;
u64 reg_val;
if (octeon_map_pci_barx(oct, 0, 0))
@@ -634,8 +634,6 @@ int cn23xx_setup_octeon_vf_device(struct octeon_device *oct)
rings_per_vf = reg_val & CN23XX_PKT_INPUT_CTL_RPVF_MASK;
- ring_flag = 0;
-
cn23xx->conf = oct_get_config_info(oct, LIO_23XX);
if (!cn23xx->conf) {
dev_err(&oct->pci_dev->dev, "%s No Config found for CN23XX\n",
diff --git a/drivers/net/ethernet/cavium/liquidio/lio_core.c b/drivers/net/ethernet/cavium/liquidio/lio_core.c
index 8093c5eafea2..825a28e5b544 100644
--- a/drivers/net/ethernet/cavium/liquidio/lio_core.c
+++ b/drivers/net/ethernet/cavium/liquidio/lio_core.c
@@ -32,38 +32,6 @@
#define OCTNIC_MAX_SG MAX_SKB_FRAGS
/**
- * \brief Callback for getting interface configuration
- * @param status status of request
- * @param buf pointer to resp structure
- */
-void lio_if_cfg_callback(struct octeon_device *oct,
- u32 status __attribute__((unused)), void *buf)
-{
- struct octeon_soft_command *sc = (struct octeon_soft_command *)buf;
- struct liquidio_if_cfg_context *ctx;
- struct liquidio_if_cfg_resp *resp;
-
- resp = (struct liquidio_if_cfg_resp *)sc->virtrptr;
- ctx = (struct liquidio_if_cfg_context *)sc->ctxptr;
-
- oct = lio_get_device(ctx->octeon_id);
- if (resp->status)
- dev_err(&oct->pci_dev->dev, "nic if cfg instruction failed. Status: %llx\n",
- CVM_CAST64(resp->status));
- WRITE_ONCE(ctx->cond, 1);
-
- snprintf(oct->fw_info.liquidio_firmware_version, 32, "%s",
- resp->cfg_info.liquidio_firmware_version);
-
- /* This barrier is required to be sure that the response has been
- * written fully before waking up the handler
- */
- wmb();
-
- wake_up_interruptible(&ctx->wc);
-}
-
-/**
* \brief Delete gather lists
* @param lio per-network private data
*/
@@ -198,14 +166,15 @@ int liquidio_set_feature(struct net_device *netdev, int cmd, u16 param1)
nctrl.ncmd.s.cmd = cmd;
nctrl.ncmd.s.param1 = param1;
nctrl.iq_no = lio->linfo.txpciq[0].s.q_no;
- nctrl.wait_time = 100;
nctrl.netpndev = (u64)netdev;
nctrl.cb_fn = liquidio_link_ctrl_cmd_completion;
ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl);
- if (ret < 0) {
+ if (ret) {
dev_err(&oct->pci_dev->dev, "Feature change failed in core (ret: 0x%x)\n",
ret);
+ if (ret > 0)
+ ret = -EIO;
}
return ret;
}
@@ -285,15 +254,7 @@ void liquidio_link_ctrl_cmd_completion(void *nctrl_ptr)
struct octeon_device *oct = lio->oct_dev;
u8 *mac;
- if (nctrl->completion && nctrl->response_code) {
- /* Signal whoever is interested that the response code from the
- * firmware has arrived.
- */
- WRITE_ONCE(*nctrl->response_code, nctrl->status);
- complete(nctrl->completion);
- }
-
- if (nctrl->status)
+ if (nctrl->sc_status)
return;
switch (nctrl->ncmd.s.cmd) {
@@ -464,56 +425,73 @@ void octeon_pf_changed_vf_macaddr(struct octeon_device *oct, u8 *mac)
*/
}
+void octeon_schedule_rxq_oom_work(struct octeon_device *oct,
+ struct octeon_droq *droq)
+{
+ struct net_device *netdev = oct->props[0].netdev;
+ struct lio *lio = GET_LIO(netdev);
+ struct cavium_wq *wq = &lio->rxq_status_wq[droq->q_no];
+
+ queue_delayed_work(wq->wq, &wq->wk.work,
+ msecs_to_jiffies(LIO_OOM_POLL_INTERVAL_MS));
+}
+
static void octnet_poll_check_rxq_oom_status(struct work_struct *work)
{
struct cavium_wk *wk = (struct cavium_wk *)work;
struct lio *lio = (struct lio *)wk->ctxptr;
struct octeon_device *oct = lio->oct_dev;
- struct octeon_droq *droq;
- int q, q_no = 0;
+ int q_no = wk->ctxul;
+ struct octeon_droq *droq = oct->droq[q_no];
- if (ifstate_check(lio, LIO_IFSTATE_RUNNING)) {
- for (q = 0; q < lio->linfo.num_rxpciq; q++) {
- q_no = lio->linfo.rxpciq[q].s.q_no;
- droq = oct->droq[q_no];
- if (!droq)
- continue;
- octeon_droq_check_oom(droq);
- }
- }
- queue_delayed_work(lio->rxq_status_wq.wq,
- &lio->rxq_status_wq.wk.work,
- msecs_to_jiffies(LIO_OOM_POLL_INTERVAL_MS));
+ if (!ifstate_check(lio, LIO_IFSTATE_RUNNING) || !droq)
+ return;
+
+ if (octeon_retry_droq_refill(droq))
+ octeon_schedule_rxq_oom_work(oct, droq);
}
int setup_rx_oom_poll_fn(struct net_device *netdev)
{
struct lio *lio = GET_LIO(netdev);
struct octeon_device *oct = lio->oct_dev;
+ struct cavium_wq *wq;
+ int q, q_no;
- lio->rxq_status_wq.wq = alloc_workqueue("rxq-oom-status",
- WQ_MEM_RECLAIM, 0);
- if (!lio->rxq_status_wq.wq) {
- dev_err(&oct->pci_dev->dev, "unable to create cavium rxq oom status wq\n");
- return -ENOMEM;
+ for (q = 0; q < oct->num_oqs; q++) {
+ q_no = lio->linfo.rxpciq[q].s.q_no;
+ wq = &lio->rxq_status_wq[q_no];
+ wq->wq = alloc_workqueue("rxq-oom-status",
+ WQ_MEM_RECLAIM, 0);
+ if (!wq->wq) {
+ dev_err(&oct->pci_dev->dev, "unable to create cavium rxq oom status wq\n");
+ return -ENOMEM;
+ }
+
+ INIT_DELAYED_WORK(&wq->wk.work,
+ octnet_poll_check_rxq_oom_status);
+ wq->wk.ctxptr = lio;
+ wq->wk.ctxul = q_no;
}
- INIT_DELAYED_WORK(&lio->rxq_status_wq.wk.work,
- octnet_poll_check_rxq_oom_status);
- lio->rxq_status_wq.wk.ctxptr = lio;
- queue_delayed_work(lio->rxq_status_wq.wq,
- &lio->rxq_status_wq.wk.work,
- msecs_to_jiffies(LIO_OOM_POLL_INTERVAL_MS));
+
return 0;
}
void cleanup_rx_oom_poll_fn(struct net_device *netdev)
{
struct lio *lio = GET_LIO(netdev);
-
- if (lio->rxq_status_wq.wq) {
- cancel_delayed_work_sync(&lio->rxq_status_wq.wk.work);
- flush_workqueue(lio->rxq_status_wq.wq);
- destroy_workqueue(lio->rxq_status_wq.wq);
+ struct octeon_device *oct = lio->oct_dev;
+ struct cavium_wq *wq;
+ int q_no;
+
+ for (q_no = 0; q_no < oct->num_oqs; q_no++) {
+ wq = &lio->rxq_status_wq[q_no];
+ if (wq->wq) {
+ cancel_delayed_work_sync(&wq->wk.work);
+ flush_workqueue(wq->wq);
+ destroy_workqueue(wq->wq);
+ wq->wq = NULL;
+ }
}
}
@@ -1218,30 +1196,6 @@ int octeon_setup_interrupt(struct octeon_device *oct, u32 num_ioqs)
return 0;
}
-static void liquidio_change_mtu_completion(struct octeon_device *oct,
- u32 status, void *buf)
-{
- struct octeon_soft_command *sc = (struct octeon_soft_command *)buf;
- struct liquidio_if_cfg_context *ctx;
-
- ctx = (struct liquidio_if_cfg_context *)sc->ctxptr;
-
- if (status) {
- dev_err(&oct->pci_dev->dev, "MTU change failed. Status: %llx\n",
- CVM_CAST64(status));
- WRITE_ONCE(ctx->cond, LIO_CHANGE_MTU_FAIL);
- } else {
- WRITE_ONCE(ctx->cond, LIO_CHANGE_MTU_SUCCESS);
- }
-
- /* This barrier is required to be sure that the response has been
- * written fully before waking up the handler
- */
- wmb();
-
- wake_up_interruptible(&ctx->wc);
-}
-
/**
* \brief Net device change_mtu
* @param netdev network device
@@ -1250,22 +1204,17 @@ int liquidio_change_mtu(struct net_device *netdev, int new_mtu)
{
struct lio *lio = GET_LIO(netdev);
struct octeon_device *oct = lio->oct_dev;
- struct liquidio_if_cfg_context *ctx;
struct octeon_soft_command *sc;
union octnet_cmd *ncmd;
- int ctx_size;
int ret = 0;
- ctx_size = sizeof(struct liquidio_if_cfg_context);
sc = (struct octeon_soft_command *)
- octeon_alloc_soft_command(oct, OCTNET_CMD_SIZE, 16, ctx_size);
+ octeon_alloc_soft_command(oct, OCTNET_CMD_SIZE, 16, 0);
ncmd = (union octnet_cmd *)sc->virtdptr;
- ctx = (struct liquidio_if_cfg_context *)sc->ctxptr;
- WRITE_ONCE(ctx->cond, 0);
- ctx->octeon_id = lio_get_device_id(oct);
- init_waitqueue_head(&ctx->wc);
+ init_completion(&sc->complete);
+ sc->sc_status = OCTEON_REQUEST_PENDING;
ncmd->u64 = 0;
ncmd->s.cmd = OCTNET_CMD_CHANGE_MTU;
@@ -1278,28 +1227,28 @@ int liquidio_change_mtu(struct net_device *netdev, int new_mtu)
octeon_prepare_soft_command(oct, sc, OPCODE_NIC,
OPCODE_NIC_CMD, 0, 0, 0);
- sc->callback = liquidio_change_mtu_completion;
- sc->callback_arg = sc;
- sc->wait_time = 100;
-
ret = octeon_send_soft_command(oct, sc);
if (ret == IQ_SEND_FAILED) {
netif_info(lio, rx_err, lio->netdev, "Failed to change MTU\n");
+ octeon_free_soft_command(oct, sc);
return -EINVAL;
}
/* Sleep on a wait queue till the cond flag indicates that the
* response arrived or timed-out.
*/
- if (sleep_cond(&ctx->wc, &ctx->cond) == -EINTR ||
- ctx->cond == LIO_CHANGE_MTU_FAIL) {
- octeon_free_soft_command(oct, sc);
+ ret = wait_for_sc_completion_timeout(oct, sc, 0);
+ if (ret)
+ return ret;
+
+ if (sc->sc_status) {
+ WRITE_ONCE(sc->caller_is_done, true);
return -EINVAL;
}
netdev->mtu = new_mtu;
lio->mtu = new_mtu;
- octeon_free_soft_command(oct, sc);
+ WRITE_ONCE(sc->caller_is_done, true);
return 0;
}
@@ -1333,8 +1282,6 @@ octnet_nic_stats_callback(struct octeon_device *oct_dev,
struct octeon_soft_command *sc = (struct octeon_soft_command *)ptr;
struct oct_nic_stats_resp *resp =
(struct oct_nic_stats_resp *)sc->virtrptr;
- struct oct_nic_stats_ctrl *ctrl =
- (struct oct_nic_stats_ctrl *)sc->ctxptr;
struct nic_rx_stats *rsp_rstats = &resp->stats.fromwire;
struct nic_tx_stats *rsp_tstats = &resp->stats.fromhost;
struct nic_rx_stats *rstats = &oct_dev->link_stats.fromwire;
@@ -1422,93 +1369,148 @@ octnet_nic_stats_callback(struct octeon_device *oct_dev,
resp->status = 1;
} else {
+ dev_err(&oct_dev->pci_dev->dev, "sc OPCODE_NIC_PORT_STATS command failed\n");
resp->status = -1;
}
- complete(&ctrl->complete);
}
-int octnet_get_link_stats(struct net_device *netdev)
+static int lio_fetch_vf_stats(struct lio *lio)
{
- struct lio *lio = GET_LIO(netdev);
struct octeon_device *oct_dev = lio->oct_dev;
struct octeon_soft_command *sc;
- struct oct_nic_stats_ctrl *ctrl;
- struct oct_nic_stats_resp *resp;
+ struct oct_nic_vf_stats_resp *resp;
+
int retval;
/* Alloc soft command */
sc = (struct octeon_soft_command *)
octeon_alloc_soft_command(oct_dev,
0,
- sizeof(struct oct_nic_stats_resp),
- sizeof(struct octnic_ctrl_pkt));
+ sizeof(struct oct_nic_vf_stats_resp),
+ 0);
- if (!sc)
- return -ENOMEM;
+ if (!sc) {
+ dev_err(&oct_dev->pci_dev->dev, "Soft command allocation failed\n");
+ retval = -ENOMEM;
+ goto lio_fetch_vf_stats_exit;
+ }
- resp = (struct oct_nic_stats_resp *)sc->virtrptr;
- memset(resp, 0, sizeof(struct oct_nic_stats_resp));
+ resp = (struct oct_nic_vf_stats_resp *)sc->virtrptr;
+ memset(resp, 0, sizeof(struct oct_nic_vf_stats_resp));
- ctrl = (struct oct_nic_stats_ctrl *)sc->ctxptr;
- memset(ctrl, 0, sizeof(struct oct_nic_stats_ctrl));
- ctrl->netdev = netdev;
- init_completion(&ctrl->complete);
+ init_completion(&sc->complete);
+ sc->sc_status = OCTEON_REQUEST_PENDING;
sc->iq_no = lio->linfo.txpciq[0].s.q_no;
octeon_prepare_soft_command(oct_dev, sc, OPCODE_NIC,
- OPCODE_NIC_PORT_STATS, 0, 0, 0);
-
- sc->callback = octnet_nic_stats_callback;
- sc->callback_arg = sc;
- sc->wait_time = 500; /*in milli seconds*/
+ OPCODE_NIC_VF_PORT_STATS, 0, 0, 0);
retval = octeon_send_soft_command(oct_dev, sc);
if (retval == IQ_SEND_FAILED) {
octeon_free_soft_command(oct_dev, sc);
- return -EINVAL;
+ goto lio_fetch_vf_stats_exit;
}
- wait_for_completion_timeout(&ctrl->complete, msecs_to_jiffies(1000));
+ retval =
+ wait_for_sc_completion_timeout(oct_dev, sc,
+ (2 * LIO_SC_MAX_TMO_MS));
+ if (retval) {
+ dev_err(&oct_dev->pci_dev->dev,
+ "sc OPCODE_NIC_VF_PORT_STATS command failed\n");
+ goto lio_fetch_vf_stats_exit;
+ }
- if (resp->status != 1) {
- octeon_free_soft_command(oct_dev, sc);
+ if (sc->sc_status != OCTEON_REQUEST_TIMEOUT && !resp->status) {
+ octeon_swap_8B_data((u64 *)&resp->spoofmac_cnt,
+ (sizeof(u64)) >> 3);
- return -EINVAL;
+ if (resp->spoofmac_cnt != 0) {
+ dev_warn(&oct_dev->pci_dev->dev,
+ "%llu Spoofed packets detected\n",
+ resp->spoofmac_cnt);
+ }
}
+ WRITE_ONCE(sc->caller_is_done, 1);
- octeon_free_soft_command(oct_dev, sc);
-
- return 0;
+lio_fetch_vf_stats_exit:
+ return retval;
}
-static void liquidio_nic_seapi_ctl_callback(struct octeon_device *oct,
- u32 status,
- void *buf)
+void lio_fetch_stats(struct work_struct *work)
{
- struct liquidio_nic_seapi_ctl_context *ctx;
- struct octeon_soft_command *sc = buf;
+ struct cavium_wk *wk = (struct cavium_wk *)work;
+ struct lio *lio = wk->ctxptr;
+ struct octeon_device *oct_dev = lio->oct_dev;
+ struct octeon_soft_command *sc;
+ struct oct_nic_stats_resp *resp;
+ unsigned long time_in_jiffies;
+ int retval;
+
+ if (OCTEON_CN23XX_PF(oct_dev)) {
+ /* report spoofchk every 2 seconds */
+ if (!(oct_dev->vfstats_poll % LIO_VFSTATS_POLL) &&
+ (oct_dev->fw_info.app_cap_flags & LIQUIDIO_SPOOFCHK_CAP) &&
+ oct_dev->sriov_info.num_vfs_alloced) {
+ lio_fetch_vf_stats(lio);
+ }
- ctx = sc->ctxptr;
+ oct_dev->vfstats_poll++;
+ }
+
+ /* Alloc soft command */
+ sc = (struct octeon_soft_command *)
+ octeon_alloc_soft_command(oct_dev,
+ 0,
+ sizeof(struct oct_nic_stats_resp),
+ 0);
+
+ if (!sc) {
+ dev_err(&oct_dev->pci_dev->dev, "Soft command allocation failed\n");
+ goto lio_fetch_stats_exit;
+ }
+
+ resp = (struct oct_nic_stats_resp *)sc->virtrptr;
+ memset(resp, 0, sizeof(struct oct_nic_stats_resp));
+
+ init_completion(&sc->complete);
+ sc->sc_status = OCTEON_REQUEST_PENDING;
- oct = lio_get_device(ctx->octeon_id);
- if (status) {
- dev_err(&oct->pci_dev->dev, "%s: instruction failed. Status: %llx\n",
- __func__,
- CVM_CAST64(status));
+ sc->iq_no = lio->linfo.txpciq[0].s.q_no;
+
+ octeon_prepare_soft_command(oct_dev, sc, OPCODE_NIC,
+ OPCODE_NIC_PORT_STATS, 0, 0, 0);
+
+ retval = octeon_send_soft_command(oct_dev, sc);
+ if (retval == IQ_SEND_FAILED) {
+ octeon_free_soft_command(oct_dev, sc);
+ goto lio_fetch_stats_exit;
+ }
+
+ retval = wait_for_sc_completion_timeout(oct_dev, sc,
+ (2 * LIO_SC_MAX_TMO_MS));
+ if (retval) {
+ dev_err(&oct_dev->pci_dev->dev, "sc OPCODE_NIC_PORT_STATS command failed\n");
+ goto lio_fetch_stats_exit;
}
- ctx->status = status;
- complete(&ctx->complete);
+
+ octnet_nic_stats_callback(oct_dev, sc->sc_status, sc);
+ WRITE_ONCE(sc->caller_is_done, true);
+
+lio_fetch_stats_exit:
+ time_in_jiffies = msecs_to_jiffies(LIQUIDIO_NDEV_STATS_POLL_TIME_MS);
+ if (ifstate_check(lio, LIO_IFSTATE_RUNNING))
+ schedule_delayed_work(&lio->stats_wk.work, time_in_jiffies);
+
+ return;
}
int liquidio_set_speed(struct lio *lio, int speed)
{
- struct liquidio_nic_seapi_ctl_context *ctx;
struct octeon_device *oct = lio->oct_dev;
struct oct_nic_seapi_resp *resp;
struct octeon_soft_command *sc;
union octnet_cmd *ncmd;
- u32 ctx_size;
int retval;
u32 var;
@@ -1521,21 +1523,18 @@ int liquidio_set_speed(struct lio *lio, int speed)
return -EOPNOTSUPP;
}
- ctx_size = sizeof(struct liquidio_nic_seapi_ctl_context);
sc = octeon_alloc_soft_command(oct, OCTNET_CMD_SIZE,
sizeof(struct oct_nic_seapi_resp),
- ctx_size);
+ 0);
if (!sc)
return -ENOMEM;
ncmd = sc->virtdptr;
- ctx = sc->ctxptr;
resp = sc->virtrptr;
memset(resp, 0, sizeof(struct oct_nic_seapi_resp));
- ctx->octeon_id = lio_get_device_id(oct);
- ctx->status = 0;
- init_completion(&ctx->complete);
+ init_completion(&sc->complete);
+ sc->sc_status = OCTEON_REQUEST_PENDING;
ncmd->u64 = 0;
ncmd->s.cmd = SEAPI_CMD_SPEED_SET;
@@ -1548,30 +1547,24 @@ int liquidio_set_speed(struct lio *lio, int speed)
octeon_prepare_soft_command(oct, sc, OPCODE_NIC,
OPCODE_NIC_UBOOT_CTL, 0, 0, 0);
- sc->callback = liquidio_nic_seapi_ctl_callback;
- sc->callback_arg = sc;
- sc->wait_time = 5000;
-
retval = octeon_send_soft_command(oct, sc);
if (retval == IQ_SEND_FAILED) {
dev_info(&oct->pci_dev->dev, "Failed to send soft command\n");
+ octeon_free_soft_command(oct, sc);
retval = -EBUSY;
} else {
/* Wait for response or timeout */
- if (wait_for_completion_timeout(&ctx->complete,
- msecs_to_jiffies(10000)) == 0) {
- dev_err(&oct->pci_dev->dev, "%s: sc timeout\n",
- __func__);
- octeon_free_soft_command(oct, sc);
- return -EINTR;
- }
+ retval = wait_for_sc_completion_timeout(oct, sc, 0);
+ if (retval)
+ return retval;
retval = resp->status;
if (retval) {
dev_err(&oct->pci_dev->dev, "%s failed, retval=%d\n",
__func__, retval);
- octeon_free_soft_command(oct, sc);
+ WRITE_ONCE(sc->caller_is_done, true);
+
return -EIO;
}
@@ -1583,38 +1576,32 @@ int liquidio_set_speed(struct lio *lio, int speed)
}
oct->speed_setting = var;
+ WRITE_ONCE(sc->caller_is_done, true);
}
- octeon_free_soft_command(oct, sc);
-
return retval;
}
int liquidio_get_speed(struct lio *lio)
{
- struct liquidio_nic_seapi_ctl_context *ctx;
struct octeon_device *oct = lio->oct_dev;
struct oct_nic_seapi_resp *resp;
struct octeon_soft_command *sc;
union octnet_cmd *ncmd;
- u32 ctx_size;
int retval;
- ctx_size = sizeof(struct liquidio_nic_seapi_ctl_context);
sc = octeon_alloc_soft_command(oct, OCTNET_CMD_SIZE,
sizeof(struct oct_nic_seapi_resp),
- ctx_size);
+ 0);
if (!sc)
return -ENOMEM;
ncmd = sc->virtdptr;
- ctx = sc->ctxptr;
resp = sc->virtrptr;
memset(resp, 0, sizeof(struct oct_nic_seapi_resp));
- ctx->octeon_id = lio_get_device_id(oct);
- ctx->status = 0;
- init_completion(&ctx->complete);
+ init_completion(&sc->complete);
+ sc->sc_status = OCTEON_REQUEST_PENDING;
ncmd->u64 = 0;
ncmd->s.cmd = SEAPI_CMD_SPEED_GET;
@@ -1626,37 +1613,20 @@ int liquidio_get_speed(struct lio *lio)
octeon_prepare_soft_command(oct, sc, OPCODE_NIC,
OPCODE_NIC_UBOOT_CTL, 0, 0, 0);
- sc->callback = liquidio_nic_seapi_ctl_callback;
- sc->callback_arg = sc;
- sc->wait_time = 5000;
-
retval = octeon_send_soft_command(oct, sc);
if (retval == IQ_SEND_FAILED) {
dev_info(&oct->pci_dev->dev, "Failed to send soft command\n");
- oct->no_speed_setting = 1;
- oct->speed_setting = 25;
-
- retval = -EBUSY;
+ octeon_free_soft_command(oct, sc);
+ retval = -EIO;
} else {
- if (wait_for_completion_timeout(&ctx->complete,
- msecs_to_jiffies(10000)) == 0) {
- dev_err(&oct->pci_dev->dev, "%s: sc timeout\n",
- __func__);
-
- oct->speed_setting = 25;
- oct->no_speed_setting = 1;
-
- octeon_free_soft_command(oct, sc);
+ retval = wait_for_sc_completion_timeout(oct, sc, 0);
+ if (retval)
+ return retval;
- return -EINTR;
- }
retval = resp->status;
if (retval) {
dev_err(&oct->pci_dev->dev,
"%s failed retval=%d\n", __func__, retval);
- oct->no_speed_setting = 1;
- oct->speed_setting = 25;
- octeon_free_soft_command(oct, sc);
retval = -EIO;
} else {
u32 var;
@@ -1664,16 +1634,171 @@ int liquidio_get_speed(struct lio *lio)
var = be32_to_cpu((__force __be32)resp->speed);
oct->speed_setting = var;
if (var == 0xffff) {
- oct->no_speed_setting = 1;
/* unable to access boot variables
* get the default value based on the NIC type
*/
- oct->speed_setting = 25;
+ if (oct->subsystem_id ==
+ OCTEON_CN2350_25GB_SUBSYS_ID ||
+ oct->subsystem_id ==
+ OCTEON_CN2360_25GB_SUBSYS_ID) {
+ oct->no_speed_setting = 1;
+ oct->speed_setting = 25;
+ } else {
+ oct->speed_setting = 10;
+ }
}
+
}
+ WRITE_ONCE(sc->caller_is_done, true);
+ }
+
+ return retval;
+}
+
+int liquidio_set_fec(struct lio *lio, int on_off)
+{
+ struct oct_nic_seapi_resp *resp;
+ struct octeon_soft_command *sc;
+ struct octeon_device *oct;
+ union octnet_cmd *ncmd;
+ int retval;
+ u32 var;
+
+ oct = lio->oct_dev;
+
+ if (oct->props[lio->ifidx].fec == on_off)
+ return 0;
+
+ if (!OCTEON_CN23XX_PF(oct)) {
+ dev_err(&oct->pci_dev->dev, "%s: SET FEC only for PF\n",
+ __func__);
+ return -1;
+ }
+
+ if (oct->speed_boot != 25) {
+ dev_err(&oct->pci_dev->dev,
+ "Set FEC only when link speed is 25G during insmod\n");
+ return -1;
+ }
+
+ sc = octeon_alloc_soft_command(oct, OCTNET_CMD_SIZE,
+ sizeof(struct oct_nic_seapi_resp), 0);
+
+ ncmd = sc->virtdptr;
+ resp = sc->virtrptr;
+ memset(resp, 0, sizeof(struct oct_nic_seapi_resp));
+
+ init_completion(&sc->complete);
+ sc->sc_status = OCTEON_REQUEST_PENDING;
+
+ ncmd->u64 = 0;
+ ncmd->s.cmd = SEAPI_CMD_FEC_SET;
+ ncmd->s.param1 = on_off;
+ /* SEAPI_CMD_FEC_DISABLE(0) or SEAPI_CMD_FEC_RS(1) */
+
+ octeon_swap_8B_data((u64 *)ncmd, (OCTNET_CMD_SIZE >> 3));
+
+ sc->iq_no = lio->linfo.txpciq[0].s.q_no;
+
+ octeon_prepare_soft_command(oct, sc, OPCODE_NIC,
+ OPCODE_NIC_UBOOT_CTL, 0, 0, 0);
+
+ retval = octeon_send_soft_command(oct, sc);
+ if (retval == IQ_SEND_FAILED) {
+ dev_info(&oct->pci_dev->dev, "Failed to send soft command\n");
+ octeon_free_soft_command(oct, sc);
+ return -EIO;
+ }
+
+ retval = wait_for_sc_completion_timeout(oct, sc, 0);
+ if (retval)
+ return (-EIO);
+
+ var = be32_to_cpu(resp->fec_setting);
+ resp->fec_setting = var;
+ if (var != on_off) {
+ dev_err(&oct->pci_dev->dev,
+ "Setting failed fec= %x, expect %x\n",
+ var, on_off);
+ oct->props[lio->ifidx].fec = var;
+ if (resp->fec_setting == SEAPI_CMD_FEC_SET_RS)
+ oct->props[lio->ifidx].fec = 1;
+ else
+ oct->props[lio->ifidx].fec = 0;
+ }
+
+ WRITE_ONCE(sc->caller_is_done, true);
+
+ if (oct->props[lio->ifidx].fec !=
+ oct->props[lio->ifidx].fec_boot) {
+ dev_dbg(&oct->pci_dev->dev,
+ "Reload driver to change fec to %s\n",
+ oct->props[lio->ifidx].fec ? "on" : "off");
+ }
+
+ return retval;
+}
+
+int liquidio_get_fec(struct lio *lio)
+{
+ struct oct_nic_seapi_resp *resp;
+ struct octeon_soft_command *sc;
+ struct octeon_device *oct;
+ union octnet_cmd *ncmd;
+ int retval;
+ u32 var;
+
+ oct = lio->oct_dev;
+
+ sc = octeon_alloc_soft_command(oct, OCTNET_CMD_SIZE,
+ sizeof(struct oct_nic_seapi_resp), 0);
+ if (!sc)
+ return -ENOMEM;
+
+ ncmd = sc->virtdptr;
+ resp = sc->virtrptr;
+ memset(resp, 0, sizeof(struct oct_nic_seapi_resp));
+
+ init_completion(&sc->complete);
+ sc->sc_status = OCTEON_REQUEST_PENDING;
+
+ ncmd->u64 = 0;
+ ncmd->s.cmd = SEAPI_CMD_FEC_GET;
+
+ octeon_swap_8B_data((u64 *)ncmd, (OCTNET_CMD_SIZE >> 3));
+
+ sc->iq_no = lio->linfo.txpciq[0].s.q_no;
+
+ octeon_prepare_soft_command(oct, sc, OPCODE_NIC,
+ OPCODE_NIC_UBOOT_CTL, 0, 0, 0);
+
+ retval = octeon_send_soft_command(oct, sc);
+ if (retval == IQ_SEND_FAILED) {
+ dev_info(&oct->pci_dev->dev,
+ "%s: Failed to send soft command\n", __func__);
+ octeon_free_soft_command(oct, sc);
+ return -EIO;
}
- octeon_free_soft_command(oct, sc);
+ retval = wait_for_sc_completion_timeout(oct, sc, 0);
+ if (retval)
+ return retval;
+
+ var = be32_to_cpu(resp->fec_setting);
+ resp->fec_setting = var;
+ if (resp->fec_setting == SEAPI_CMD_FEC_SET_RS)
+ oct->props[lio->ifidx].fec = 1;
+ else
+ oct->props[lio->ifidx].fec = 0;
+
+ WRITE_ONCE(sc->caller_is_done, true);
+
+ if (oct->props[lio->ifidx].fec !=
+ oct->props[lio->ifidx].fec_boot) {
+ dev_dbg(&oct->pci_dev->dev,
+ "Reload driver to change fec to %s\n",
+ oct->props[lio->ifidx].fec ? "on" : "off");
+ }
return retval;
}
diff --git a/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c b/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c
index 8e05afd5e39c..4c3925af53bc 100644
--- a/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c
+++ b/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c
@@ -33,25 +33,12 @@
static int lio_reset_queues(struct net_device *netdev, uint32_t num_qs);
-struct oct_intrmod_context {
- int octeon_id;
- wait_queue_head_t wc;
- int cond;
- int status;
-};
-
struct oct_intrmod_resp {
u64 rh;
struct oct_intrmod_cfg intrmod;
u64 status;
};
-struct oct_mdio_cmd_context {
- int octeon_id;
- wait_queue_head_t wc;
- int cond;
-};
-
struct oct_mdio_cmd_resp {
u64 rh;
struct oct_mdio_cmd resp;
@@ -257,6 +244,7 @@ static int lio_get_link_ksettings(struct net_device *netdev,
linfo->link.s.if_mode == INTERFACE_MODE_XLAUI ||
linfo->link.s.if_mode == INTERFACE_MODE_XFI) {
dev_dbg(&oct->pci_dev->dev, "ecmd->base.transceiver is XCVR_EXTERNAL\n");
+ ecmd->base.transceiver = XCVR_EXTERNAL;
} else {
dev_err(&oct->pci_dev->dev, "Unknown link interface mode: %d\n",
linfo->link.s.if_mode);
@@ -290,10 +278,12 @@ static int lio_get_link_ksettings(struct net_device *netdev,
10000baseCR_Full);
}
- if (oct->no_speed_setting == 0)
+ if (oct->no_speed_setting == 0) {
liquidio_get_speed(lio);
- else
+ liquidio_get_fec(lio);
+ } else {
oct->speed_setting = 25;
+ }
if (oct->speed_setting == 10) {
ethtool_link_ksettings_add_link_mode
@@ -317,6 +307,24 @@ static int lio_get_link_ksettings(struct net_device *netdev,
(ecmd, advertising,
25000baseCR_Full);
}
+
+ if (oct->no_speed_setting)
+ break;
+
+ ethtool_link_ksettings_add_link_mode
+ (ecmd, supported, FEC_RS);
+ ethtool_link_ksettings_add_link_mode
+ (ecmd, supported, FEC_NONE);
+ /*FEC_OFF*/
+ if (oct->props[lio->ifidx].fec == 1) {
+ /* ETHTOOL_FEC_RS */
+ ethtool_link_ksettings_add_link_mode
+ (ecmd, advertising, FEC_RS);
+ } else {
+ /* ETHTOOL_FEC_OFF */
+ ethtool_link_ksettings_add_link_mode
+ (ecmd, advertising, FEC_NONE);
+ }
} else { /* VF */
if (linfo->link.s.speed == 10000) {
ethtool_link_ksettings_add_link_mode
@@ -472,12 +480,11 @@ lio_send_queue_count_update(struct net_device *netdev, uint32_t num_queues)
nctrl.ncmd.s.param1 = num_queues;
nctrl.ncmd.s.param2 = num_queues;
nctrl.iq_no = lio->linfo.txpciq[0].s.q_no;
- nctrl.wait_time = 100;
nctrl.netpndev = (u64)netdev;
nctrl.cb_fn = liquidio_link_ctrl_cmd_completion;
ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl);
- if (ret < 0) {
+ if (ret) {
dev_err(&oct->pci_dev->dev, "Failed to send Queue reset command (ret: 0x%x)\n",
ret);
return -1;
@@ -708,13 +715,13 @@ static int octnet_gpio_access(struct net_device *netdev, int addr, int val)
nctrl.ncmd.s.param1 = addr;
nctrl.ncmd.s.param2 = val;
nctrl.iq_no = lio->linfo.txpciq[0].s.q_no;
- nctrl.wait_time = 100;
nctrl.netpndev = (u64)netdev;
nctrl.cb_fn = liquidio_link_ctrl_cmd_completion;
ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl);
- if (ret < 0) {
- dev_err(&oct->pci_dev->dev, "Failed to configure gpio value\n");
+ if (ret) {
+ dev_err(&oct->pci_dev->dev,
+ "Failed to configure gpio value, ret=%d\n", ret);
return -EINVAL;
}
@@ -734,41 +741,19 @@ static int octnet_id_active(struct net_device *netdev, int val)
nctrl.ncmd.s.cmd = OCTNET_CMD_ID_ACTIVE;
nctrl.ncmd.s.param1 = val;
nctrl.iq_no = lio->linfo.txpciq[0].s.q_no;
- nctrl.wait_time = 100;
nctrl.netpndev = (u64)netdev;
nctrl.cb_fn = liquidio_link_ctrl_cmd_completion;
ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl);
- if (ret < 0) {
- dev_err(&oct->pci_dev->dev, "Failed to configure gpio value\n");
+ if (ret) {
+ dev_err(&oct->pci_dev->dev,
+ "Failed to configure gpio value, ret=%d\n", ret);
return -EINVAL;
}
return 0;
}
-/* Callback for when mdio command response arrives
- */
-static void octnet_mdio_resp_callback(struct octeon_device *oct,
- u32 status,
- void *buf)
-{
- struct oct_mdio_cmd_context *mdio_cmd_ctx;
- struct octeon_soft_command *sc = (struct octeon_soft_command *)buf;
-
- mdio_cmd_ctx = (struct oct_mdio_cmd_context *)sc->ctxptr;
-
- oct = lio_get_device(mdio_cmd_ctx->octeon_id);
- if (status) {
- dev_err(&oct->pci_dev->dev, "MIDO instruction failed. Status: %llx\n",
- CVM_CAST64(status));
- WRITE_ONCE(mdio_cmd_ctx->cond, -1);
- } else {
- WRITE_ONCE(mdio_cmd_ctx->cond, 1);
- }
- wake_up_interruptible(&mdio_cmd_ctx->wc);
-}
-
/* This routine provides PHY access routines for
* mdio clause45 .
*/
@@ -778,25 +763,20 @@ octnet_mdio45_access(struct lio *lio, int op, int loc, int *value)
struct octeon_device *oct_dev = lio->oct_dev;
struct octeon_soft_command *sc;
struct oct_mdio_cmd_resp *mdio_cmd_rsp;
- struct oct_mdio_cmd_context *mdio_cmd_ctx;
struct oct_mdio_cmd *mdio_cmd;
int retval = 0;
sc = (struct octeon_soft_command *)
octeon_alloc_soft_command(oct_dev,
sizeof(struct oct_mdio_cmd),
- sizeof(struct oct_mdio_cmd_resp),
- sizeof(struct oct_mdio_cmd_context));
+ sizeof(struct oct_mdio_cmd_resp), 0);
if (!sc)
return -ENOMEM;
- mdio_cmd_ctx = (struct oct_mdio_cmd_context *)sc->ctxptr;
mdio_cmd_rsp = (struct oct_mdio_cmd_resp *)sc->virtrptr;
mdio_cmd = (struct oct_mdio_cmd *)sc->virtdptr;
- WRITE_ONCE(mdio_cmd_ctx->cond, 0);
- mdio_cmd_ctx->octeon_id = lio_get_device_id(oct_dev);
mdio_cmd->op = op;
mdio_cmd->mdio_addr = loc;
if (op)
@@ -808,42 +788,40 @@ octnet_mdio45_access(struct lio *lio, int op, int loc, int *value)
octeon_prepare_soft_command(oct_dev, sc, OPCODE_NIC, OPCODE_NIC_MDIO45,
0, 0, 0);
- sc->wait_time = 1000;
- sc->callback = octnet_mdio_resp_callback;
- sc->callback_arg = sc;
-
- init_waitqueue_head(&mdio_cmd_ctx->wc);
+ init_completion(&sc->complete);
+ sc->sc_status = OCTEON_REQUEST_PENDING;
retval = octeon_send_soft_command(oct_dev, sc);
-
if (retval == IQ_SEND_FAILED) {
dev_err(&oct_dev->pci_dev->dev,
"octnet_mdio45_access instruction failed status: %x\n",
retval);
- retval = -EBUSY;
+ octeon_free_soft_command(oct_dev, sc);
+ return -EBUSY;
} else {
/* Sleep on a wait queue till the cond flag indicates that the
* response arrived
*/
- sleep_cond(&mdio_cmd_ctx->wc, &mdio_cmd_ctx->cond);
+ retval = wait_for_sc_completion_timeout(oct_dev, sc, 0);
+ if (retval)
+ return retval;
+
retval = mdio_cmd_rsp->status;
if (retval) {
- dev_err(&oct_dev->pci_dev->dev, "octnet mdio45 access failed\n");
- retval = -EBUSY;
- } else {
- octeon_swap_8B_data((u64 *)(&mdio_cmd_rsp->resp),
- sizeof(struct oct_mdio_cmd) / 8);
-
- if (READ_ONCE(mdio_cmd_ctx->cond) == 1) {
- if (!op)
- *value = mdio_cmd_rsp->resp.value1;
- } else {
- retval = -EINVAL;
- }
+ dev_err(&oct_dev->pci_dev->dev,
+ "octnet mdio45 access failed: %x\n", retval);
+ WRITE_ONCE(sc->caller_is_done, true);
+ return -EBUSY;
}
- }
- octeon_free_soft_command(oct_dev, sc);
+ octeon_swap_8B_data((u64 *)(&mdio_cmd_rsp->resp),
+ sizeof(struct oct_mdio_cmd) / 8);
+
+ if (!op)
+ *value = mdio_cmd_rsp->resp.value1;
+
+ WRITE_ONCE(sc->caller_is_done, true);
+ }
return retval;
}
@@ -1007,8 +985,7 @@ lio_ethtool_get_ringparam(struct net_device *netdev,
static int lio_23xx_reconfigure_queue_count(struct lio *lio)
{
struct octeon_device *oct = lio->oct_dev;
- struct liquidio_if_cfg_context *ctx;
- u32 resp_size, ctx_size, data_size;
+ u32 resp_size, data_size;
struct liquidio_if_cfg_resp *resp;
struct octeon_soft_command *sc;
union oct_nic_if_cfg if_cfg;
@@ -1018,11 +995,10 @@ static int lio_23xx_reconfigure_queue_count(struct lio *lio)
int j;
resp_size = sizeof(struct liquidio_if_cfg_resp);
- ctx_size = sizeof(struct liquidio_if_cfg_context);
data_size = sizeof(struct lio_version);
sc = (struct octeon_soft_command *)
octeon_alloc_soft_command(oct, data_size,
- resp_size, ctx_size);
+ resp_size, 0);
if (!sc) {
dev_err(&oct->pci_dev->dev, "%s: Failed to allocate soft command\n",
__func__);
@@ -1030,7 +1006,6 @@ static int lio_23xx_reconfigure_queue_count(struct lio *lio)
}
resp = (struct liquidio_if_cfg_resp *)sc->virtrptr;
- ctx = (struct liquidio_if_cfg_context *)sc->ctxptr;
vdata = (struct lio_version *)sc->virtdptr;
vdata->major = (__force u16)cpu_to_be16(LIQUIDIO_BASE_MAJOR_VERSION);
@@ -1038,9 +1013,6 @@ static int lio_23xx_reconfigure_queue_count(struct lio *lio)
vdata->micro = (__force u16)cpu_to_be16(LIQUIDIO_BASE_MICRO_VERSION);
ifidx_or_pfnum = oct->pf_num;
- WRITE_ONCE(ctx->cond, 0);
- ctx->octeon_id = lio_get_device_id(oct);
- init_waitqueue_head(&ctx->wc);
if_cfg.u64 = 0;
if_cfg.s.num_iqueues = oct->sriov_info.num_pf_rings;
@@ -1052,27 +1024,29 @@ static int lio_23xx_reconfigure_queue_count(struct lio *lio)
octeon_prepare_soft_command(oct, sc, OPCODE_NIC,
OPCODE_NIC_QCOUNT_UPDATE, 0,
if_cfg.u64, 0);
- sc->callback = lio_if_cfg_callback;
- sc->callback_arg = sc;
- sc->wait_time = LIO_IFCFG_WAIT_TIME;
+
+ init_completion(&sc->complete);
+ sc->sc_status = OCTEON_REQUEST_PENDING;
retval = octeon_send_soft_command(oct, sc);
if (retval == IQ_SEND_FAILED) {
dev_err(&oct->pci_dev->dev,
- "iq/oq config failed status: %x\n",
+ "Sending iq/oq config failed status: %x\n",
retval);
- goto qcount_update_fail;
+ octeon_free_soft_command(oct, sc);
+ return -EIO;
}
- if (sleep_cond(&ctx->wc, &ctx->cond) == -EINTR) {
- dev_err(&oct->pci_dev->dev, "Wait interrupted\n");
- return -1;
- }
+ retval = wait_for_sc_completion_timeout(oct, sc, 0);
+ if (retval)
+ return retval;
retval = resp->status;
if (retval) {
- dev_err(&oct->pci_dev->dev, "iq/oq config failed\n");
- goto qcount_update_fail;
+ dev_err(&oct->pci_dev->dev,
+ "iq/oq config failed: %x\n", retval);
+ WRITE_ONCE(sc->caller_is_done, true);
+ return -1;
}
octeon_swap_8B_data((u64 *)(&resp->cfg_info),
@@ -1097,16 +1071,12 @@ static int lio_23xx_reconfigure_queue_count(struct lio *lio)
lio->txq = lio->linfo.txpciq[0].s.q_no;
lio->rxq = lio->linfo.rxpciq[0].s.q_no;
- octeon_free_soft_command(oct, sc);
dev_info(&oct->pci_dev->dev, "Queue count updated to %d\n",
lio->linfo.num_rxpciq);
- return 0;
-
-qcount_update_fail:
- octeon_free_soft_command(oct, sc);
+ WRITE_ONCE(sc->caller_is_done, true);
- return -1;
+ return 0;
}
static int lio_reset_queues(struct net_device *netdev, uint32_t num_qs)
@@ -1166,6 +1136,8 @@ static int lio_reset_queues(struct net_device *netdev, uint32_t num_qs)
* steps like updating sriov_info for the octeon device need to be done.
*/
if (queue_count_update) {
+ cleanup_rx_oom_poll_fn(netdev);
+
lio_delete_glists(lio);
/* Delete mbox for PF which is SRIOV disabled because sriov_info
@@ -1265,6 +1237,11 @@ static int lio_reset_queues(struct net_device *netdev, uint32_t num_qs)
return -1;
}
+ if (setup_rx_oom_poll_fn(netdev)) {
+ dev_err(&oct->pci_dev->dev, "lio_setup_rx_oom_poll_fn failed\n");
+ return 1;
+ }
+
/* Send firmware the information about new number of queues
* if the interface is a VF or a PF that is SRIOV enabled.
*/
@@ -1412,7 +1389,6 @@ lio_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause)
nctrl.ncmd.u64 = 0;
nctrl.ncmd.s.cmd = OCTNET_CMD_SET_FLOW_CTL;
nctrl.iq_no = lio->linfo.txpciq[0].s.q_no;
- nctrl.wait_time = 100;
nctrl.netpndev = (u64)netdev;
nctrl.cb_fn = liquidio_link_ctrl_cmd_completion;
@@ -1433,8 +1409,9 @@ lio_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause)
}
ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl);
- if (ret < 0) {
- dev_err(&oct->pci_dev->dev, "Failed to set pause parameter\n");
+ if (ret) {
+ dev_err(&oct->pci_dev->dev,
+ "Failed to set pause parameter, ret=%d\n", ret);
return -EINVAL;
}
@@ -1764,7 +1741,8 @@ static void lio_vf_get_ethtool_stats(struct net_device *netdev,
*/
data[i++] = lstats.rx_dropped;
/* sum of oct->instr_queue[iq_no]->stats.tx_dropped */
- data[i++] = lstats.tx_dropped;
+ data[i++] = lstats.tx_dropped +
+ oct_dev->link_stats.fromhost.fw_err_drop;
data[i++] = oct_dev->link_stats.fromwire.fw_total_mcast;
data[i++] = oct_dev->link_stats.fromhost.fw_total_mcast_sent;
@@ -2013,34 +1991,11 @@ static int lio_vf_get_sset_count(struct net_device *netdev, int sset)
}
}
-/* Callback function for intrmod */
-static void octnet_intrmod_callback(struct octeon_device *oct_dev,
- u32 status,
- void *ptr)
-{
- struct octeon_soft_command *sc = (struct octeon_soft_command *)ptr;
- struct oct_intrmod_context *ctx;
-
- ctx = (struct oct_intrmod_context *)sc->ctxptr;
-
- ctx->status = status;
-
- WRITE_ONCE(ctx->cond, 1);
-
- /* This barrier is required to be sure that the response has been
- * written fully before waking up the handler
- */
- wmb();
-
- wake_up_interruptible(&ctx->wc);
-}
-
/* get interrupt moderation parameters */
static int octnet_get_intrmod_cfg(struct lio *lio,
struct oct_intrmod_cfg *intr_cfg)
{
struct octeon_soft_command *sc;
- struct oct_intrmod_context *ctx;
struct oct_intrmod_resp *resp;
int retval;
struct octeon_device *oct_dev = lio->oct_dev;
@@ -2049,8 +2004,7 @@ static int octnet_get_intrmod_cfg(struct lio *lio,
sc = (struct octeon_soft_command *)
octeon_alloc_soft_command(oct_dev,
0,
- sizeof(struct oct_intrmod_resp),
- sizeof(struct oct_intrmod_context));
+ sizeof(struct oct_intrmod_resp), 0);
if (!sc)
return -ENOMEM;
@@ -2058,20 +2012,13 @@ static int octnet_get_intrmod_cfg(struct lio *lio,
resp = (struct oct_intrmod_resp *)sc->virtrptr;
memset(resp, 0, sizeof(struct oct_intrmod_resp));
- ctx = (struct oct_intrmod_context *)sc->ctxptr;
- memset(ctx, 0, sizeof(struct oct_intrmod_context));
- WRITE_ONCE(ctx->cond, 0);
- ctx->octeon_id = lio_get_device_id(oct_dev);
- init_waitqueue_head(&ctx->wc);
-
sc->iq_no = lio->linfo.txpciq[0].s.q_no;
octeon_prepare_soft_command(oct_dev, sc, OPCODE_NIC,
OPCODE_NIC_INTRMOD_PARAMS, 0, 0, 0);
- sc->callback = octnet_intrmod_callback;
- sc->callback_arg = sc;
- sc->wait_time = 1000;
+ init_completion(&sc->complete);
+ sc->sc_status = OCTEON_REQUEST_PENDING;
retval = octeon_send_soft_command(oct_dev, sc);
if (retval == IQ_SEND_FAILED) {
@@ -2082,32 +2029,23 @@ static int octnet_get_intrmod_cfg(struct lio *lio,
/* Sleep on a wait queue till the cond flag indicates that the
* response arrived or timed-out.
*/
- if (sleep_cond(&ctx->wc, &ctx->cond) == -EINTR) {
- dev_err(&oct_dev->pci_dev->dev, "Wait interrupted\n");
- goto intrmod_info_wait_intr;
- }
+ retval = wait_for_sc_completion_timeout(oct_dev, sc, 0);
+ if (retval)
+ return -ENODEV;
- retval = ctx->status || resp->status;
- if (retval) {
+ if (resp->status) {
dev_err(&oct_dev->pci_dev->dev,
"Get interrupt moderation parameters failed\n");
- goto intrmod_info_wait_fail;
+ WRITE_ONCE(sc->caller_is_done, true);
+ return -ENODEV;
}
octeon_swap_8B_data((u64 *)&resp->intrmod,
(sizeof(struct oct_intrmod_cfg)) / 8);
memcpy(intr_cfg, &resp->intrmod, sizeof(struct oct_intrmod_cfg));
- octeon_free_soft_command(oct_dev, sc);
+ WRITE_ONCE(sc->caller_is_done, true);
return 0;
-
-intrmod_info_wait_fail:
-
- octeon_free_soft_command(oct_dev, sc);
-
-intrmod_info_wait_intr:
-
- return -ENODEV;
}
/* Configure interrupt moderation parameters */
@@ -2115,7 +2053,6 @@ static int octnet_set_intrmod_cfg(struct lio *lio,
struct oct_intrmod_cfg *intr_cfg)
{
struct octeon_soft_command *sc;
- struct oct_intrmod_context *ctx;
struct oct_intrmod_cfg *cfg;
int retval;
struct octeon_device *oct_dev = lio->oct_dev;
@@ -2124,18 +2061,11 @@ static int octnet_set_intrmod_cfg(struct lio *lio,
sc = (struct octeon_soft_command *)
octeon_alloc_soft_command(oct_dev,
sizeof(struct oct_intrmod_cfg),
- 0,
- sizeof(struct oct_intrmod_context));
+ 16, 0);
if (!sc)
return -ENOMEM;
- ctx = (struct oct_intrmod_context *)sc->ctxptr;
-
- WRITE_ONCE(ctx->cond, 0);
- ctx->octeon_id = lio_get_device_id(oct_dev);
- init_waitqueue_head(&ctx->wc);
-
cfg = (struct oct_intrmod_cfg *)sc->virtdptr;
memcpy(cfg, intr_cfg, sizeof(struct oct_intrmod_cfg));
@@ -2146,9 +2076,8 @@ static int octnet_set_intrmod_cfg(struct lio *lio,
octeon_prepare_soft_command(oct_dev, sc, OPCODE_NIC,
OPCODE_NIC_INTRMOD_CFG, 0, 0, 0);
- sc->callback = octnet_intrmod_callback;
- sc->callback_arg = sc;
- sc->wait_time = 1000;
+ init_completion(&sc->complete);
+ sc->sc_status = OCTEON_REQUEST_PENDING;
retval = octeon_send_soft_command(oct_dev, sc);
if (retval == IQ_SEND_FAILED) {
@@ -2159,26 +2088,24 @@ static int octnet_set_intrmod_cfg(struct lio *lio,
/* Sleep on a wait queue till the cond flag indicates that the
* response arrived or timed-out.
*/
- if (sleep_cond(&ctx->wc, &ctx->cond) != -EINTR) {
- retval = ctx->status;
- if (retval)
- dev_err(&oct_dev->pci_dev->dev,
- "intrmod config failed. Status: %llx\n",
- CVM_CAST64(retval));
- else
- dev_info(&oct_dev->pci_dev->dev,
- "Rx-Adaptive Interrupt moderation %s\n",
- (intr_cfg->rx_enable) ?
- "enabled" : "disabled");
-
- octeon_free_soft_command(oct_dev, sc);
-
- return ((retval) ? -ENODEV : 0);
+ retval = wait_for_sc_completion_timeout(oct_dev, sc, 0);
+ if (retval)
+ return retval;
+
+ retval = sc->sc_status;
+ if (retval == 0) {
+ dev_info(&oct_dev->pci_dev->dev,
+ "Rx-Adaptive Interrupt moderation %s\n",
+ (intr_cfg->rx_enable) ?
+ "enabled" : "disabled");
+ WRITE_ONCE(sc->caller_is_done, true);
+ return 0;
}
- dev_err(&oct_dev->pci_dev->dev, "iq/oq config failed\n");
-
- return -EINTR;
+ dev_err(&oct_dev->pci_dev->dev,
+ "intrmod config failed. Status: %x\n", retval);
+ WRITE_ONCE(sc->caller_is_done, true);
+ return -ENODEV;
}
static int lio_get_intr_coalesce(struct net_device *netdev,
@@ -3123,9 +3050,60 @@ static int lio_set_priv_flags(struct net_device *netdev, u32 flags)
return 0;
}
+static int lio_get_fecparam(struct net_device *netdev,
+ struct ethtool_fecparam *fec)
+{
+ struct lio *lio = GET_LIO(netdev);
+ struct octeon_device *oct = lio->oct_dev;
+
+ fec->active_fec = ETHTOOL_FEC_NONE;
+ fec->fec = ETHTOOL_FEC_NONE;
+
+ if (oct->subsystem_id == OCTEON_CN2350_25GB_SUBSYS_ID ||
+ oct->subsystem_id == OCTEON_CN2360_25GB_SUBSYS_ID) {
+ if (oct->no_speed_setting == 1)
+ return 0;
+
+ liquidio_get_fec(lio);
+ fec->fec = (ETHTOOL_FEC_RS | ETHTOOL_FEC_OFF);
+ if (oct->props[lio->ifidx].fec == 1)
+ fec->active_fec = ETHTOOL_FEC_RS;
+ else
+ fec->active_fec = ETHTOOL_FEC_OFF;
+ }
+
+ return 0;
+}
+
+static int lio_set_fecparam(struct net_device *netdev,
+ struct ethtool_fecparam *fec)
+{
+ struct lio *lio = GET_LIO(netdev);
+ struct octeon_device *oct = lio->oct_dev;
+
+ if (oct->subsystem_id == OCTEON_CN2350_25GB_SUBSYS_ID ||
+ oct->subsystem_id == OCTEON_CN2360_25GB_SUBSYS_ID) {
+ if (oct->no_speed_setting == 1)
+ return -EOPNOTSUPP;
+
+ if (fec->fec & ETHTOOL_FEC_OFF)
+ liquidio_set_fec(lio, 0);
+ else if (fec->fec & ETHTOOL_FEC_RS)
+ liquidio_set_fec(lio, 1);
+ else
+ return -EOPNOTSUPP;
+ } else {
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
static const struct ethtool_ops lio_ethtool_ops = {
.get_link_ksettings = lio_get_link_ksettings,
.set_link_ksettings = lio_set_link_ksettings,
+ .get_fecparam = lio_get_fecparam,
+ .set_fecparam = lio_set_fecparam,
.get_link = ethtool_op_get_link,
.get_drvinfo = lio_get_drvinfo,
.get_ringparam = lio_ethtool_get_ringparam,
diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c
index 6fb13fa73b27..3d24133e5e49 100644
--- a/drivers/net/ethernet/cavium/liquidio/lio_main.c
+++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c
@@ -99,14 +99,6 @@ struct lio_trusted_vf_ctx {
int status;
};
-struct liquidio_rx_ctl_context {
- int octeon_id;
-
- wait_queue_head_t wc;
-
- int cond;
-};
-
struct oct_link_status_resp {
u64 rh;
struct oct_link_info link_info;
@@ -642,26 +634,6 @@ static inline void update_link_status(struct net_device *netdev,
}
/**
- * lio_sync_octeon_time_cb - callback that is invoked when soft command
- * sent by lio_sync_octeon_time() has completed successfully or failed
- *
- * @oct - octeon device structure
- * @status - indicates success or failure
- * @buf - pointer to the command that was sent to firmware
- **/
-static void lio_sync_octeon_time_cb(struct octeon_device *oct,
- u32 status, void *buf)
-{
- struct octeon_soft_command *sc = (struct octeon_soft_command *)buf;
-
- if (status)
- dev_err(&oct->pci_dev->dev,
- "Failed to sync time to octeon; error=%d\n", status);
-
- octeon_free_soft_command(oct, sc);
-}
-
-/**
* lio_sync_octeon_time - send latest localtime to octeon firmware so that
* firmware will correct it's time, in case there is a time skew
*
@@ -677,7 +649,7 @@ static void lio_sync_octeon_time(struct work_struct *work)
struct lio_time *lt;
int ret;
- sc = octeon_alloc_soft_command(oct, sizeof(struct lio_time), 0, 0);
+ sc = octeon_alloc_soft_command(oct, sizeof(struct lio_time), 16, 0);
if (!sc) {
dev_err(&oct->pci_dev->dev,
"Failed to sync time to octeon: soft command allocation failed\n");
@@ -696,15 +668,16 @@ static void lio_sync_octeon_time(struct work_struct *work)
octeon_prepare_soft_command(oct, sc, OPCODE_NIC,
OPCODE_NIC_SYNC_OCTEON_TIME, 0, 0, 0);
- sc->callback = lio_sync_octeon_time_cb;
- sc->callback_arg = sc;
- sc->wait_time = 1000;
+ init_completion(&sc->complete);
+ sc->sc_status = OCTEON_REQUEST_PENDING;
ret = octeon_send_soft_command(oct, sc);
if (ret == IQ_SEND_FAILED) {
dev_err(&oct->pci_dev->dev,
"Failed to sync time to octeon: failed to send soft command\n");
octeon_free_soft_command(oct, sc);
+ } else {
+ WRITE_ONCE(sc->caller_is_done, true);
}
queue_delayed_work(lio->sync_octeon_time_wq.wq,
@@ -1037,12 +1010,12 @@ static void octeon_destroy_resources(struct octeon_device *oct)
/* fallthrough */
case OCT_DEV_IO_QUEUES_DONE:
- if (wait_for_pending_requests(oct))
- dev_err(&oct->pci_dev->dev, "There were pending requests\n");
-
if (lio_wait_for_instr_fetch(oct))
dev_err(&oct->pci_dev->dev, "IQ had pending instructions\n");
+ if (wait_for_pending_requests(oct))
+ dev_err(&oct->pci_dev->dev, "There were pending requests\n");
+
/* Disable the input and output queues now. No more packets will
* arrive from Octeon, but we should wait for all packet
* processing to finish.
@@ -1052,6 +1025,31 @@ static void octeon_destroy_resources(struct octeon_device *oct)
if (lio_wait_for_oq_pkts(oct))
dev_err(&oct->pci_dev->dev, "OQ had pending packets\n");
+ /* Force all requests waiting to be fetched by OCTEON to
+ * complete.
+ */
+ for (i = 0; i < MAX_OCTEON_INSTR_QUEUES(oct); i++) {
+ struct octeon_instr_queue *iq;
+
+ if (!(oct->io_qmask.iq & BIT_ULL(i)))
+ continue;
+ iq = oct->instr_queue[i];
+
+ if (atomic_read(&iq->instr_pending)) {
+ spin_lock_bh(&iq->lock);
+ iq->fill_cnt = 0;
+ iq->octeon_read_index = iq->host_write_index;
+ iq->stats.instr_processed +=
+ atomic_read(&iq->instr_pending);
+ lio_process_iq_request_list(oct, iq, 0);
+ spin_unlock_bh(&iq->lock);
+ }
+ }
+
+ lio_process_ordered_list(oct, 1);
+ octeon_free_sc_done_list(oct);
+ octeon_free_sc_zombie_list(oct);
+
/* fallthrough */
case OCT_DEV_INTR_SET_DONE:
/* Disable interrupts */
@@ -1178,34 +1176,6 @@ static void octeon_destroy_resources(struct octeon_device *oct)
}
/**
- * \brief Callback for rx ctrl
- * @param status status of request
- * @param buf pointer to resp structure
- */
-static void rx_ctl_callback(struct octeon_device *oct,
- u32 status,
- void *buf)
-{
- struct octeon_soft_command *sc = (struct octeon_soft_command *)buf;
- struct liquidio_rx_ctl_context *ctx;
-
- ctx = (struct liquidio_rx_ctl_context *)sc->ctxptr;
-
- oct = lio_get_device(ctx->octeon_id);
- if (status)
- dev_err(&oct->pci_dev->dev, "rx ctl instruction failed. Status: %llx\n",
- CVM_CAST64(status));
- WRITE_ONCE(ctx->cond, 1);
-
- /* This barrier is required to be sure that the response has been
- * written fully before waking up the handler
- */
- wmb();
-
- wake_up_interruptible(&ctx->wc);
-}
-
-/**
* \brief Send Rx control command
* @param lio per-network private data
* @param start_stop whether to start or stop
@@ -1213,9 +1183,7 @@ static void rx_ctl_callback(struct octeon_device *oct,
static void send_rx_ctrl_cmd(struct lio *lio, int start_stop)
{
struct octeon_soft_command *sc;
- struct liquidio_rx_ctl_context *ctx;
union octnet_cmd *ncmd;
- int ctx_size = sizeof(struct liquidio_rx_ctl_context);
struct octeon_device *oct = (struct octeon_device *)lio->oct_dev;
int retval;
@@ -1224,14 +1192,9 @@ static void send_rx_ctrl_cmd(struct lio *lio, int start_stop)
sc = (struct octeon_soft_command *)
octeon_alloc_soft_command(oct, OCTNET_CMD_SIZE,
- 16, ctx_size);
+ 16, 0);
ncmd = (union octnet_cmd *)sc->virtdptr;
- ctx = (struct liquidio_rx_ctl_context *)sc->ctxptr;
-
- WRITE_ONCE(ctx->cond, 0);
- ctx->octeon_id = lio_get_device_id(oct);
- init_waitqueue_head(&ctx->wc);
ncmd->u64 = 0;
ncmd->s.cmd = OCTNET_CMD_RX_CTL;
@@ -1244,23 +1207,25 @@ static void send_rx_ctrl_cmd(struct lio *lio, int start_stop)
octeon_prepare_soft_command(oct, sc, OPCODE_NIC,
OPCODE_NIC_CMD, 0, 0, 0);
- sc->callback = rx_ctl_callback;
- sc->callback_arg = sc;
- sc->wait_time = 5000;
+ init_completion(&sc->complete);
+ sc->sc_status = OCTEON_REQUEST_PENDING;
retval = octeon_send_soft_command(oct, sc);
if (retval == IQ_SEND_FAILED) {
netif_info(lio, rx_err, lio->netdev, "Failed to send RX Control message\n");
+ octeon_free_soft_command(oct, sc);
+ return;
} else {
/* Sleep on a wait queue till the cond flag indicates that the
* response arrived or timed-out.
*/
- if (sleep_cond(&ctx->wc, &ctx->cond) == -EINTR)
+ retval = wait_for_sc_completion_timeout(oct, sc, 0);
+ if (retval)
return;
+
oct->props[lio->ifidx].rx_on = start_stop;
+ WRITE_ONCE(sc->caller_is_done, true);
}
-
- octeon_free_soft_command(oct, sc);
}
/**
@@ -1274,8 +1239,10 @@ static void send_rx_ctrl_cmd(struct lio *lio, int start_stop)
static void liquidio_destroy_nic_device(struct octeon_device *oct, int ifidx)
{
struct net_device *netdev = oct->props[ifidx].netdev;
- struct lio *lio;
+ struct octeon_device_priv *oct_priv =
+ (struct octeon_device_priv *)oct->priv;
struct napi_struct *napi, *n;
+ struct lio *lio;
if (!netdev) {
dev_err(&oct->pci_dev->dev, "%s No netdevice ptr for index %d\n",
@@ -1304,6 +1271,8 @@ static void liquidio_destroy_nic_device(struct octeon_device *oct, int ifidx)
list_for_each_entry_safe(napi, n, &netdev->napi_list, dev_list)
netif_napi_del(napi);
+ tasklet_enable(&oct_priv->droq_tasklet);
+
if (atomic_read(&lio->ifstate) & LIO_IFSTATE_REGISTERED)
unregister_netdev(netdev);
@@ -1840,9 +1809,13 @@ static int liquidio_open(struct net_device *netdev)
{
struct lio *lio = GET_LIO(netdev);
struct octeon_device *oct = lio->oct_dev;
+ struct octeon_device_priv *oct_priv =
+ (struct octeon_device_priv *)oct->priv;
struct napi_struct *napi, *n;
if (oct->props[lio->ifidx].napi_enabled == 0) {
+ tasklet_disable(&oct_priv->droq_tasklet);
+
list_for_each_entry_safe(napi, n, &netdev->napi_list, dev_list)
napi_enable(napi);
@@ -1876,6 +1849,12 @@ static int liquidio_open(struct net_device *netdev)
/* tell Octeon to start forwarding packets to host */
send_rx_ctrl_cmd(lio, 1);
+ /* start periodical statistics fetch */
+ INIT_DELAYED_WORK(&lio->stats_wk.work, lio_fetch_stats);
+ lio->stats_wk.ctxptr = lio;
+ schedule_delayed_work(&lio->stats_wk.work, msecs_to_jiffies
+ (LIQUIDIO_NDEV_STATS_POLL_TIME_MS));
+
dev_info(&oct->pci_dev->dev, "%s interface is opened\n",
netdev->name);
@@ -1890,6 +1869,8 @@ static int liquidio_stop(struct net_device *netdev)
{
struct lio *lio = GET_LIO(netdev);
struct octeon_device *oct = lio->oct_dev;
+ struct octeon_device_priv *oct_priv =
+ (struct octeon_device_priv *)oct->priv;
struct napi_struct *napi, *n;
ifstate_reset(lio, LIO_IFSTATE_RUNNING);
@@ -1916,6 +1897,8 @@ static int liquidio_stop(struct net_device *netdev)
cleanup_tx_poll_fn(netdev);
}
+ cancel_delayed_work_sync(&lio->stats_wk.work);
+
if (lio->ptp_clock) {
ptp_clock_unregister(lio->ptp_clock);
lio->ptp_clock = NULL;
@@ -1934,6 +1917,8 @@ static int liquidio_stop(struct net_device *netdev)
if (OCTEON_CN23XX_PF(oct))
oct->droq[0]->ops.poll_mode = 0;
+
+ tasklet_enable(&oct_priv->droq_tasklet);
}
dev_info(&oct->pci_dev->dev, "%s interface is stopped\n", netdev->name);
@@ -2014,10 +1999,9 @@ static void liquidio_set_mcast_list(struct net_device *netdev)
/* Apparently, any activity in this call from the kernel has to
* be atomic. So we won't wait for response.
*/
- nctrl.wait_time = 0;
ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl);
- if (ret < 0) {
+ if (ret) {
dev_err(&oct->pci_dev->dev, "DEVFLAGS change failed in core (ret: 0x%x)\n",
ret);
}
@@ -2046,8 +2030,6 @@ static int liquidio_set_mac(struct net_device *netdev, void *p)
nctrl.ncmd.s.more = 1;
nctrl.iq_no = lio->linfo.txpciq[0].s.q_no;
nctrl.netpndev = (u64)netdev;
- nctrl.cb_fn = liquidio_link_ctrl_cmd_completion;
- nctrl.wait_time = 100;
nctrl.udd[0] = 0;
/* The MAC Address is presented in network byte order. */
@@ -2058,6 +2040,14 @@ static int liquidio_set_mac(struct net_device *netdev, void *p)
dev_err(&oct->pci_dev->dev, "MAC Address change failed\n");
return -ENOMEM;
}
+
+ if (nctrl.sc_status) {
+ dev_err(&oct->pci_dev->dev,
+ "%s: MAC Address change failed. sc return=%x\n",
+ __func__, nctrl.sc_status);
+ return -EIO;
+ }
+
memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
memcpy(((u8 *)&lio->linfo.hw_addr) + 2, addr->sa_data, ETH_ALEN);
@@ -2111,7 +2101,6 @@ liquidio_get_stats64(struct net_device *netdev,
lstats->rx_packets = pkts;
lstats->rx_dropped = drop;
- octnet_get_link_stats(netdev);
lstats->multicast = oct->link_stats.fromwire.fw_total_mcast;
lstats->collisions = oct->link_stats.fromhost.total_collisions;
@@ -2324,7 +2313,7 @@ static inline int send_nic_timestamp_pkt(struct octeon_device *oct,
* @returns whether the packet was transmitted to the device okay or not
* (NETDEV_TX_OK or NETDEV_TX_BUSY)
*/
-static int liquidio_xmit(struct sk_buff *skb, struct net_device *netdev)
+static netdev_tx_t liquidio_xmit(struct sk_buff *skb, struct net_device *netdev)
{
struct lio *lio;
struct octnet_buf_free_info *finfo;
@@ -2598,14 +2587,15 @@ static int liquidio_vlan_rx_add_vid(struct net_device *netdev,
nctrl.ncmd.s.cmd = OCTNET_CMD_ADD_VLAN_FILTER;
nctrl.ncmd.s.param1 = vid;
nctrl.iq_no = lio->linfo.txpciq[0].s.q_no;
- nctrl.wait_time = 100;
nctrl.netpndev = (u64)netdev;
nctrl.cb_fn = liquidio_link_ctrl_cmd_completion;
ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl);
- if (ret < 0) {
+ if (ret) {
dev_err(&oct->pci_dev->dev, "Add VLAN filter failed in core (ret: 0x%x)\n",
ret);
+ if (ret > 0)
+ ret = -EIO;
}
return ret;
@@ -2626,14 +2616,15 @@ static int liquidio_vlan_rx_kill_vid(struct net_device *netdev,
nctrl.ncmd.s.cmd = OCTNET_CMD_DEL_VLAN_FILTER;
nctrl.ncmd.s.param1 = vid;
nctrl.iq_no = lio->linfo.txpciq[0].s.q_no;
- nctrl.wait_time = 100;
nctrl.netpndev = (u64)netdev;
nctrl.cb_fn = liquidio_link_ctrl_cmd_completion;
ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl);
- if (ret < 0) {
+ if (ret) {
dev_err(&oct->pci_dev->dev, "Del VLAN filter failed in core (ret: 0x%x)\n",
ret);
+ if (ret > 0)
+ ret = -EIO;
}
return ret;
}
@@ -2659,15 +2650,16 @@ static int liquidio_set_rxcsum_command(struct net_device *netdev, int command,
nctrl.ncmd.s.cmd = command;
nctrl.ncmd.s.param1 = rx_cmd;
nctrl.iq_no = lio->linfo.txpciq[0].s.q_no;
- nctrl.wait_time = 100;
nctrl.netpndev = (u64)netdev;
nctrl.cb_fn = liquidio_link_ctrl_cmd_completion;
ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl);
- if (ret < 0) {
+ if (ret) {
dev_err(&oct->pci_dev->dev,
"DEVFLAGS RXCSUM change failed in core(ret:0x%x)\n",
ret);
+ if (ret > 0)
+ ret = -EIO;
}
return ret;
}
@@ -2695,15 +2687,16 @@ static int liquidio_vxlan_port_command(struct net_device *netdev, int command,
nctrl.ncmd.s.more = vxlan_cmd_bit;
nctrl.ncmd.s.param1 = vxlan_port;
nctrl.iq_no = lio->linfo.txpciq[0].s.q_no;
- nctrl.wait_time = 100;
nctrl.netpndev = (u64)netdev;
nctrl.cb_fn = liquidio_link_ctrl_cmd_completion;
ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl);
- if (ret < 0) {
+ if (ret) {
dev_err(&oct->pci_dev->dev,
"VxLAN port add/delete failed in core (ret:0x%x)\n",
ret);
+ if (ret > 0)
+ ret = -EIO;
}
return ret;
}
@@ -2826,6 +2819,7 @@ static int __liquidio_set_vf_mac(struct net_device *netdev, int vfidx,
struct lio *lio = GET_LIO(netdev);
struct octeon_device *oct = lio->oct_dev;
struct octnic_ctrl_pkt nctrl;
+ int ret = 0;
if (!is_valid_ether_addr(mac))
return -EINVAL;
@@ -2839,12 +2833,13 @@ static int __liquidio_set_vf_mac(struct net_device *netdev, int vfidx,
nctrl.ncmd.s.cmd = OCTNET_CMD_CHANGE_MACADDR;
/* vfidx is 0 based, but vf_num (param1) is 1 based */
nctrl.ncmd.s.param1 = vfidx + 1;
- nctrl.ncmd.s.param2 = (is_admin_assigned ? 1 : 0);
nctrl.ncmd.s.more = 1;
nctrl.iq_no = lio->linfo.txpciq[0].s.q_no;
nctrl.netpndev = (u64)netdev;
- nctrl.cb_fn = liquidio_link_ctrl_cmd_completion;
- nctrl.wait_time = LIO_CMD_WAIT_TM;
+ if (is_admin_assigned) {
+ nctrl.ncmd.s.param2 = true;
+ nctrl.cb_fn = liquidio_link_ctrl_cmd_completion;
+ }
nctrl.udd[0] = 0;
/* The MAC Address is presented in network byte order. */
@@ -2852,9 +2847,11 @@ static int __liquidio_set_vf_mac(struct net_device *netdev, int vfidx,
oct->sriov_info.vf_macaddr[vfidx] = nctrl.udd[0];
- octnet_send_nic_ctrl_pkt(oct, &nctrl);
+ ret = octnet_send_nic_ctrl_pkt(oct, &nctrl);
+ if (ret > 0)
+ ret = -EIO;
- return 0;
+ return ret;
}
static int liquidio_set_vf_mac(struct net_device *netdev, int vfidx, u8 *mac)
@@ -2873,6 +2870,62 @@ static int liquidio_set_vf_mac(struct net_device *netdev, int vfidx, u8 *mac)
return retval;
}
+static int liquidio_set_vf_spoofchk(struct net_device *netdev, int vfidx,
+ bool enable)
+{
+ struct lio *lio = GET_LIO(netdev);
+ struct octeon_device *oct = lio->oct_dev;
+ struct octnic_ctrl_pkt nctrl;
+ int retval;
+
+ if (!(oct->fw_info.app_cap_flags & LIQUIDIO_SPOOFCHK_CAP)) {
+ netif_info(lio, drv, lio->netdev,
+ "firmware does not support spoofchk\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (vfidx < 0 || vfidx >= oct->sriov_info.num_vfs_alloced) {
+ netif_info(lio, drv, lio->netdev, "Invalid vfidx %d\n", vfidx);
+ return -EINVAL;
+ }
+
+ if (enable) {
+ if (oct->sriov_info.vf_spoofchk[vfidx])
+ return 0;
+ } else {
+ /* Clear */
+ if (!oct->sriov_info.vf_spoofchk[vfidx])
+ return 0;
+ }
+
+ memset(&nctrl, 0, sizeof(struct octnic_ctrl_pkt));
+ nctrl.ncmd.s.cmdgroup = OCTNET_CMD_GROUP1;
+ nctrl.ncmd.s.cmd = OCTNET_CMD_SET_VF_SPOOFCHK;
+ nctrl.ncmd.s.param1 =
+ vfidx + 1; /* vfidx is 0 based,
+ * but vf_num (param1) is 1 based
+ */
+ nctrl.ncmd.s.param2 = enable;
+ nctrl.ncmd.s.more = 0;
+ nctrl.iq_no = lio->linfo.txpciq[0].s.q_no;
+ nctrl.cb_fn = 0;
+
+ retval = octnet_send_nic_ctrl_pkt(oct, &nctrl);
+
+ if (retval) {
+ netif_info(lio, drv, lio->netdev,
+ "Failed to set VF %d spoofchk %s\n", vfidx,
+ enable ? "on" : "off");
+ return -1;
+ }
+
+ oct->sriov_info.vf_spoofchk[vfidx] = enable;
+ netif_info(lio, drv, lio->netdev, "VF %u spoofchk is %s\n", vfidx,
+ enable ? "on" : "off");
+
+ return 0;
+}
+
static int liquidio_set_vf_vlan(struct net_device *netdev, int vfidx,
u16 vlan, u8 qos, __be16 vlan_proto)
{
@@ -2880,6 +2933,7 @@ static int liquidio_set_vf_vlan(struct net_device *netdev, int vfidx,
struct octeon_device *oct = lio->oct_dev;
struct octnic_ctrl_pkt nctrl;
u16 vlantci;
+ int ret = 0;
if (vfidx < 0 || vfidx >= oct->sriov_info.num_vfs_alloced)
return -EINVAL;
@@ -2911,13 +2965,17 @@ static int liquidio_set_vf_vlan(struct net_device *netdev, int vfidx,
nctrl.ncmd.s.more = 0;
nctrl.iq_no = lio->linfo.txpciq[0].s.q_no;
nctrl.cb_fn = NULL;
- nctrl.wait_time = LIO_CMD_WAIT_TM;
- octnet_send_nic_ctrl_pkt(oct, &nctrl);
+ ret = octnet_send_nic_ctrl_pkt(oct, &nctrl);
+ if (ret) {
+ if (ret > 0)
+ ret = -EIO;
+ return ret;
+ }
oct->sriov_info.vf_vlantci[vfidx] = vlantci;
- return 0;
+ return ret;
}
static int liquidio_get_vf_config(struct net_device *netdev, int vfidx,
@@ -2930,6 +2988,8 @@ static int liquidio_get_vf_config(struct net_device *netdev, int vfidx,
if (vfidx < 0 || vfidx >= oct->sriov_info.num_vfs_alloced)
return -EINVAL;
+ memset(ivi, 0, sizeof(struct ifla_vf_info));
+
ivi->vf = vfidx;
macaddr = 2 + (u8 *)&oct->sriov_info.vf_macaddr[vfidx];
ether_addr_copy(&ivi->mac[0], macaddr);
@@ -2941,33 +3001,22 @@ static int liquidio_get_vf_config(struct net_device *netdev, int vfidx,
else
ivi->trusted = false;
ivi->linkstate = oct->sriov_info.vf_linkstate[vfidx];
- return 0;
-}
-
-static void trusted_vf_callback(struct octeon_device *oct_dev,
- u32 status, void *ptr)
-{
- struct octeon_soft_command *sc = (struct octeon_soft_command *)ptr;
- struct lio_trusted_vf_ctx *ctx;
+ ivi->spoofchk = oct->sriov_info.vf_spoofchk[vfidx];
+ ivi->max_tx_rate = lio->linfo.link.s.speed;
+ ivi->min_tx_rate = 0;
- ctx = (struct lio_trusted_vf_ctx *)sc->ctxptr;
- ctx->status = status;
-
- complete(&ctx->complete);
+ return 0;
}
static int liquidio_send_vf_trust_cmd(struct lio *lio, int vfidx, bool trusted)
{
struct octeon_device *oct = lio->oct_dev;
- struct lio_trusted_vf_ctx *ctx;
struct octeon_soft_command *sc;
- int ctx_size, retval;
-
- ctx_size = sizeof(struct lio_trusted_vf_ctx);
- sc = octeon_alloc_soft_command(oct, 0, 0, ctx_size);
+ int retval;
- ctx = (struct lio_trusted_vf_ctx *)sc->ctxptr;
- init_completion(&ctx->complete);
+ sc = octeon_alloc_soft_command(oct, 0, 16, 0);
+ if (!sc)
+ return -ENOMEM;
sc->iq_no = lio->linfo.txpciq[0].s.q_no;
@@ -2976,23 +3025,21 @@ static int liquidio_send_vf_trust_cmd(struct lio *lio, int vfidx, bool trusted)
OPCODE_NIC_SET_TRUSTED_VF, 0, vfidx + 1,
trusted);
- sc->callback = trusted_vf_callback;
- sc->callback_arg = sc;
- sc->wait_time = 1000;
+ init_completion(&sc->complete);
+ sc->sc_status = OCTEON_REQUEST_PENDING;
retval = octeon_send_soft_command(oct, sc);
if (retval == IQ_SEND_FAILED) {
+ octeon_free_soft_command(oct, sc);
retval = -1;
} else {
/* Wait for response or timeout */
- if (wait_for_completion_timeout(&ctx->complete,
- msecs_to_jiffies(2000)))
- retval = ctx->status;
- else
- retval = -1;
- }
+ retval = wait_for_sc_completion_timeout(oct, sc, 0);
+ if (retval)
+ return (retval);
- octeon_free_soft_command(oct, sc);
+ WRITE_ONCE(sc->caller_is_done, true);
+ }
return retval;
}
@@ -3055,6 +3102,7 @@ static int liquidio_set_vf_link_state(struct net_device *netdev, int vfidx,
struct lio *lio = GET_LIO(netdev);
struct octeon_device *oct = lio->oct_dev;
struct octnic_ctrl_pkt nctrl;
+ int ret = 0;
if (vfidx < 0 || vfidx >= oct->sriov_info.num_vfs_alloced)
return -EINVAL;
@@ -3070,13 +3118,15 @@ static int liquidio_set_vf_link_state(struct net_device *netdev, int vfidx,
nctrl.ncmd.s.more = 0;
nctrl.iq_no = lio->linfo.txpciq[0].s.q_no;
nctrl.cb_fn = NULL;
- nctrl.wait_time = LIO_CMD_WAIT_TM;
- octnet_send_nic_ctrl_pkt(oct, &nctrl);
+ ret = octnet_send_nic_ctrl_pkt(oct, &nctrl);
- oct->sriov_info.vf_linkstate[vfidx] = linkstate;
+ if (!ret)
+ oct->sriov_info.vf_linkstate[vfidx] = linkstate;
+ else if (ret > 0)
+ ret = -EIO;
- return 0;
+ return ret;
}
static int
@@ -3094,7 +3144,8 @@ liquidio_eswitch_mode_get(struct devlink *devlink, u16 *mode)
}
static int
-liquidio_eswitch_mode_set(struct devlink *devlink, u16 mode)
+liquidio_eswitch_mode_set(struct devlink *devlink, u16 mode,
+ struct netlink_ext_ack *extack)
{
struct lio_devlink_priv *priv;
struct octeon_device *oct;
@@ -3204,6 +3255,7 @@ static const struct net_device_ops lionetdevops = {
.ndo_set_vf_mac = liquidio_set_vf_mac,
.ndo_set_vf_vlan = liquidio_set_vf_vlan,
.ndo_get_vf_config = liquidio_get_vf_config,
+ .ndo_set_vf_spoofchk = liquidio_set_vf_spoofchk,
.ndo_set_vf_trust = liquidio_set_vf_trust,
.ndo_set_vf_link_state = liquidio_set_vf_link_state,
.ndo_get_vf_stats = liquidio_get_vf_stats,
@@ -3307,7 +3359,6 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
unsigned long micro;
u32 cur_ver;
struct octeon_soft_command *sc;
- struct liquidio_if_cfg_context *ctx;
struct liquidio_if_cfg_resp *resp;
struct octdev_props *props;
int retval, num_iqueues, num_oqueues;
@@ -3315,7 +3366,7 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
union oct_nic_if_cfg if_cfg;
unsigned int base_queue;
unsigned int gmx_port_id;
- u32 resp_size, ctx_size, data_size;
+ u32 resp_size, data_size;
u32 ifidx_or_pfnum;
struct lio_version *vdata;
struct devlink *devlink;
@@ -3340,13 +3391,11 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
for (i = 0; i < octeon_dev->ifcount; i++) {
resp_size = sizeof(struct liquidio_if_cfg_resp);
- ctx_size = sizeof(struct liquidio_if_cfg_context);
data_size = sizeof(struct lio_version);
sc = (struct octeon_soft_command *)
octeon_alloc_soft_command(octeon_dev, data_size,
- resp_size, ctx_size);
+ resp_size, 0);
resp = (struct liquidio_if_cfg_resp *)sc->virtrptr;
- ctx = (struct liquidio_if_cfg_context *)sc->ctxptr;
vdata = (struct lio_version *)sc->virtdptr;
*((u64 *)vdata) = 0;
@@ -3376,9 +3425,6 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
dev_dbg(&octeon_dev->pci_dev->dev,
"requesting config for interface %d, iqs %d, oqs %d\n",
ifidx_or_pfnum, num_iqueues, num_oqueues);
- WRITE_ONCE(ctx->cond, 0);
- ctx->octeon_id = lio_get_device_id(octeon_dev);
- init_waitqueue_head(&ctx->wc);
if_cfg.u64 = 0;
if_cfg.s.num_iqueues = num_iqueues;
@@ -3392,9 +3438,8 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
OPCODE_NIC_IF_CFG, 0,
if_cfg.u64, 0);
- sc->callback = lio_if_cfg_callback;
- sc->callback_arg = sc;
- sc->wait_time = LIO_IFCFG_WAIT_TIME;
+ init_completion(&sc->complete);
+ sc->sc_status = OCTEON_REQUEST_PENDING;
retval = octeon_send_soft_command(octeon_dev, sc);
if (retval == IQ_SEND_FAILED) {
@@ -3402,22 +3447,26 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
"iq/oq config failed status: %x\n",
retval);
/* Soft instr is freed by driver in case of failure. */
- goto setup_nic_dev_fail;
+ octeon_free_soft_command(octeon_dev, sc);
+ return(-EIO);
}
/* Sleep on a wait queue till the cond flag indicates that the
* response arrived or timed-out.
*/
- if (sleep_cond(&ctx->wc, &ctx->cond) == -EINTR) {
- dev_err(&octeon_dev->pci_dev->dev, "Wait interrupted\n");
- goto setup_nic_wait_intr;
- }
+ retval = wait_for_sc_completion_timeout(octeon_dev, sc, 0);
+ if (retval)
+ return retval;
retval = resp->status;
if (retval) {
dev_err(&octeon_dev->pci_dev->dev, "iq/oq config failed\n");
- goto setup_nic_dev_fail;
+ WRITE_ONCE(sc->caller_is_done, true);
+ goto setup_nic_dev_done;
}
+ snprintf(octeon_dev->fw_info.liquidio_firmware_version,
+ 32, "%s",
+ resp->cfg_info.liquidio_firmware_version);
/* Verify f/w version (in case of 'auto' loading from flash) */
fw_ver = octeon_dev->fw_info.liquidio_firmware_version;
@@ -3427,7 +3476,8 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
dev_err(&octeon_dev->pci_dev->dev,
"Unmatched firmware version. Expected %s.x, got %s.\n",
LIQUIDIO_BASE_VERSION, fw_ver);
- goto setup_nic_dev_fail;
+ WRITE_ONCE(sc->caller_is_done, true);
+ goto setup_nic_dev_done;
} else if (atomic_read(octeon_dev->adapter_fw_state) ==
FW_IS_PRELOADED) {
dev_info(&octeon_dev->pci_dev->dev,
@@ -3454,7 +3504,8 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
"Got bad iqueues (%016llx) or oqueues (%016llx) from firmware.\n",
resp->cfg_info.iqmask,
resp->cfg_info.oqmask);
- goto setup_nic_dev_fail;
+ WRITE_ONCE(sc->caller_is_done, true);
+ goto setup_nic_dev_done;
}
if (OCTEON_CN6XXX(octeon_dev)) {
@@ -3473,7 +3524,8 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
if (!netdev) {
dev_err(&octeon_dev->pci_dev->dev, "Device allocation failed\n");
- goto setup_nic_dev_fail;
+ WRITE_ONCE(sc->caller_is_done, true);
+ goto setup_nic_dev_done;
}
SET_NETDEV_DEV(netdev, &octeon_dev->pci_dev->dev);
@@ -3488,14 +3540,16 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
if (retval) {
dev_err(&octeon_dev->pci_dev->dev,
"setting real number rx failed\n");
- goto setup_nic_dev_fail;
+ WRITE_ONCE(sc->caller_is_done, true);
+ goto setup_nic_dev_free;
}
retval = netif_set_real_num_tx_queues(netdev, num_iqueues);
if (retval) {
dev_err(&octeon_dev->pci_dev->dev,
"setting real number tx failed\n");
- goto setup_nic_dev_fail;
+ WRITE_ONCE(sc->caller_is_done, true);
+ goto setup_nic_dev_free;
}
lio = GET_LIO(netdev);
@@ -3522,6 +3576,8 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
lio->linfo.gmxport = resp->cfg_info.linfo.gmxport;
lio->linfo.link.u64 = resp->cfg_info.linfo.link.u64;
+ WRITE_ONCE(sc->caller_is_done, true);
+
lio->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE);
if (OCTEON_CN23XX_PF(octeon_dev) ||
@@ -3588,7 +3644,7 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
dev_err(&octeon_dev->pci_dev->dev,
"Error setting VF%d MAC address\n",
j);
- goto setup_nic_dev_fail;
+ goto setup_nic_dev_free;
}
}
@@ -3610,7 +3666,7 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
lio->linfo.num_txpciq,
lio->linfo.num_rxpciq)) {
dev_err(&octeon_dev->pci_dev->dev, "I/O queues creation failed\n");
- goto setup_nic_dev_fail;
+ goto setup_nic_dev_free;
}
ifstate_set(lio, LIO_IFSTATE_DROQ_OPS);
@@ -3621,7 +3677,7 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
if (lio_setup_glists(octeon_dev, lio, num_iqueues)) {
dev_err(&octeon_dev->pci_dev->dev,
"Gather list allocation failed\n");
- goto setup_nic_dev_fail;
+ goto setup_nic_dev_free;
}
/* Register ethtool support */
@@ -3643,20 +3699,20 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
OCTNET_CMD_VERBOSE_ENABLE, 0);
if (setup_link_status_change_wq(netdev))
- goto setup_nic_dev_fail;
+ goto setup_nic_dev_free;
if ((octeon_dev->fw_info.app_cap_flags &
LIQUIDIO_TIME_SYNC_CAP) &&
setup_sync_octeon_time_wq(netdev))
- goto setup_nic_dev_fail;
+ goto setup_nic_dev_free;
if (setup_rx_oom_poll_fn(netdev))
- goto setup_nic_dev_fail;
+ goto setup_nic_dev_free;
/* Register the network device with the OS */
if (register_netdev(netdev)) {
dev_err(&octeon_dev->pci_dev->dev, "Device registration failed\n");
- goto setup_nic_dev_fail;
+ goto setup_nic_dev_free;
}
dev_dbg(&octeon_dev->pci_dev->dev,
@@ -3679,8 +3735,6 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
dev_dbg(&octeon_dev->pci_dev->dev,
"NIC ifidx:%d Setup successful\n", i);
- octeon_free_soft_command(octeon_dev, sc);
-
if (octeon_dev->subsystem_id ==
OCTEON_CN2350_25GB_SUBSYS_ID ||
octeon_dev->subsystem_id ==
@@ -3709,13 +3763,20 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
}
octeon_dev->speed_boot = octeon_dev->speed_setting;
+ /* don't read FEC setting if unsupported by f/w (see above) */
+ if (octeon_dev->speed_boot == 25 &&
+ !octeon_dev->no_speed_setting) {
+ liquidio_get_fec(lio);
+ octeon_dev->props[lio->ifidx].fec_boot =
+ octeon_dev->props[lio->ifidx].fec;
+ }
}
devlink = devlink_alloc(&liquidio_devlink_ops,
sizeof(struct lio_devlink_priv));
if (!devlink) {
dev_err(&octeon_dev->pci_dev->dev, "devlink alloc failed\n");
- goto setup_nic_wait_intr;
+ goto setup_nic_dev_free;
}
lio_devlink = devlink_priv(devlink);
@@ -3725,7 +3786,7 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
devlink_free(devlink);
dev_err(&octeon_dev->pci_dev->dev,
"devlink registration failed\n");
- goto setup_nic_wait_intr;
+ goto setup_nic_dev_free;
}
octeon_dev->devlink = devlink;
@@ -3733,17 +3794,16 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
return 0;
-setup_nic_dev_fail:
-
- octeon_free_soft_command(octeon_dev, sc);
-
-setup_nic_wait_intr:
+setup_nic_dev_free:
while (i--) {
dev_err(&octeon_dev->pci_dev->dev,
"NIC ifidx:%d Setup failed\n", i);
liquidio_destroy_nic_device(octeon_dev, i);
}
+
+setup_nic_dev_done:
+
return -ENODEV;
}
diff --git a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c
index b77835724dc8..54b245797d2e 100644
--- a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c
+++ b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c
@@ -40,14 +40,6 @@ MODULE_PARM_DESC(debug, "NETIF_MSG debug bits");
#define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK)
-struct liquidio_rx_ctl_context {
- int octeon_id;
-
- wait_queue_head_t wc;
-
- int cond;
-};
-
struct oct_timestamp_resp {
u64 rh;
u64 timestamp;
@@ -452,6 +444,8 @@ static void octeon_pci_flr(struct octeon_device *oct)
*/
static void octeon_destroy_resources(struct octeon_device *oct)
{
+ struct octeon_device_priv *oct_priv =
+ (struct octeon_device_priv *)oct->priv;
struct msix_entry *msix_entries;
int i;
@@ -471,12 +465,12 @@ static void octeon_destroy_resources(struct octeon_device *oct)
case OCT_DEV_HOST_OK:
/* fallthrough */
case OCT_DEV_IO_QUEUES_DONE:
- if (wait_for_pending_requests(oct))
- dev_err(&oct->pci_dev->dev, "There were pending requests\n");
-
if (lio_wait_for_instr_fetch(oct))
dev_err(&oct->pci_dev->dev, "IQ had pending instructions\n");
+ if (wait_for_pending_requests(oct))
+ dev_err(&oct->pci_dev->dev, "There were pending requests\n");
+
/* Disable the input and output queues now. No more packets will
* arrive from Octeon, but we should wait for all packet
* processing to finish.
@@ -485,7 +479,33 @@ static void octeon_destroy_resources(struct octeon_device *oct)
if (lio_wait_for_oq_pkts(oct))
dev_err(&oct->pci_dev->dev, "OQ had pending packets\n");
- /* fall through */
+
+ /* Force all requests waiting to be fetched by OCTEON to
+ * complete.
+ */
+ for (i = 0; i < MAX_OCTEON_INSTR_QUEUES(oct); i++) {
+ struct octeon_instr_queue *iq;
+
+ if (!(oct->io_qmask.iq & BIT_ULL(i)))
+ continue;
+ iq = oct->instr_queue[i];
+
+ if (atomic_read(&iq->instr_pending)) {
+ spin_lock_bh(&iq->lock);
+ iq->fill_cnt = 0;
+ iq->octeon_read_index = iq->host_write_index;
+ iq->stats.instr_processed +=
+ atomic_read(&iq->instr_pending);
+ lio_process_iq_request_list(oct, iq, 0);
+ spin_unlock_bh(&iq->lock);
+ }
+ }
+
+ lio_process_ordered_list(oct, 1);
+ octeon_free_sc_done_list(oct);
+ octeon_free_sc_zombie_list(oct);
+
+ /* fall through */
case OCT_DEV_INTR_SET_DONE:
/* Disable interrupts */
oct->fn_list.disable_interrupt(oct, OCTEON_ALL_INTR);
@@ -569,33 +589,8 @@ static void octeon_destroy_resources(struct octeon_device *oct)
/* Nothing to be done here either */
break;
}
-}
-
-/**
- * \brief Callback for rx ctrl
- * @param status status of request
- * @param buf pointer to resp structure
- */
-static void rx_ctl_callback(struct octeon_device *oct,
- u32 status, void *buf)
-{
- struct octeon_soft_command *sc = (struct octeon_soft_command *)buf;
- struct liquidio_rx_ctl_context *ctx;
-
- ctx = (struct liquidio_rx_ctl_context *)sc->ctxptr;
- oct = lio_get_device(ctx->octeon_id);
- if (status)
- dev_err(&oct->pci_dev->dev, "rx ctl instruction failed. Status: %llx\n",
- CVM_CAST64(status));
- WRITE_ONCE(ctx->cond, 1);
-
- /* This barrier is required to be sure that the response has been
- * written fully before waking up the handler
- */
- wmb();
-
- wake_up_interruptible(&ctx->wc);
+ tasklet_kill(&oct_priv->droq_tasklet);
}
/**
@@ -606,8 +601,6 @@ static void rx_ctl_callback(struct octeon_device *oct,
static void send_rx_ctrl_cmd(struct lio *lio, int start_stop)
{
struct octeon_device *oct = (struct octeon_device *)lio->oct_dev;
- int ctx_size = sizeof(struct liquidio_rx_ctl_context);
- struct liquidio_rx_ctl_context *ctx;
struct octeon_soft_command *sc;
union octnet_cmd *ncmd;
int retval;
@@ -617,14 +610,9 @@ static void send_rx_ctrl_cmd(struct lio *lio, int start_stop)
sc = (struct octeon_soft_command *)
octeon_alloc_soft_command(oct, OCTNET_CMD_SIZE,
- 16, ctx_size);
+ 16, 0);
ncmd = (union octnet_cmd *)sc->virtdptr;
- ctx = (struct liquidio_rx_ctl_context *)sc->ctxptr;
-
- WRITE_ONCE(ctx->cond, 0);
- ctx->octeon_id = lio_get_device_id(oct);
- init_waitqueue_head(&ctx->wc);
ncmd->u64 = 0;
ncmd->s.cmd = OCTNET_CMD_RX_CTL;
@@ -637,23 +625,24 @@ static void send_rx_ctrl_cmd(struct lio *lio, int start_stop)
octeon_prepare_soft_command(oct, sc, OPCODE_NIC,
OPCODE_NIC_CMD, 0, 0, 0);
- sc->callback = rx_ctl_callback;
- sc->callback_arg = sc;
- sc->wait_time = 5000;
+ init_completion(&sc->complete);
+ sc->sc_status = OCTEON_REQUEST_PENDING;
retval = octeon_send_soft_command(oct, sc);
if (retval == IQ_SEND_FAILED) {
netif_info(lio, rx_err, lio->netdev, "Failed to send RX Control message\n");
+ octeon_free_soft_command(oct, sc);
} else {
/* Sleep on a wait queue till the cond flag indicates that the
* response arrived or timed-out.
*/
- if (sleep_cond(&ctx->wc, &ctx->cond) == -EINTR)
+ retval = wait_for_sc_completion_timeout(oct, sc, 0);
+ if (retval)
return;
+
oct->props[lio->ifidx].rx_on = start_stop;
+ WRITE_ONCE(sc->caller_is_done, true);
}
-
- octeon_free_soft_command(oct, sc);
}
/**
@@ -667,6 +656,8 @@ static void send_rx_ctrl_cmd(struct lio *lio, int start_stop)
static void liquidio_destroy_nic_device(struct octeon_device *oct, int ifidx)
{
struct net_device *netdev = oct->props[ifidx].netdev;
+ struct octeon_device_priv *oct_priv =
+ (struct octeon_device_priv *)oct->priv;
struct napi_struct *napi, *n;
struct lio *lio;
@@ -696,6 +687,8 @@ static void liquidio_destroy_nic_device(struct octeon_device *oct, int ifidx)
list_for_each_entry_safe(napi, n, &netdev->napi_list, dev_list)
netif_napi_del(napi);
+ tasklet_enable(&oct_priv->droq_tasklet);
+
if (atomic_read(&lio->ifstate) & LIO_IFSTATE_REGISTERED)
unregister_netdev(netdev);
@@ -913,9 +906,13 @@ static int liquidio_open(struct net_device *netdev)
{
struct lio *lio = GET_LIO(netdev);
struct octeon_device *oct = lio->oct_dev;
+ struct octeon_device_priv *oct_priv =
+ (struct octeon_device_priv *)oct->priv;
struct napi_struct *napi, *n;
if (!oct->props[lio->ifidx].napi_enabled) {
+ tasklet_disable(&oct_priv->droq_tasklet);
+
list_for_each_entry_safe(napi, n, &netdev->napi_list, dev_list)
napi_enable(napi);
@@ -932,6 +929,11 @@ static int liquidio_open(struct net_device *netdev)
netif_info(lio, ifup, lio->netdev, "Interface Open, ready for traffic\n");
start_txqs(netdev);
+ INIT_DELAYED_WORK(&lio->stats_wk.work, lio_fetch_stats);
+ lio->stats_wk.ctxptr = lio;
+ schedule_delayed_work(&lio->stats_wk.work, msecs_to_jiffies
+ (LIQUIDIO_NDEV_STATS_POLL_TIME_MS));
+
/* tell Octeon to start forwarding packets to host */
send_rx_ctrl_cmd(lio, 1);
@@ -948,6 +950,8 @@ static int liquidio_stop(struct net_device *netdev)
{
struct lio *lio = GET_LIO(netdev);
struct octeon_device *oct = lio->oct_dev;
+ struct octeon_device_priv *oct_priv =
+ (struct octeon_device_priv *)oct->priv;
struct napi_struct *napi, *n;
/* tell Octeon to stop forwarding packets to host */
@@ -977,8 +981,12 @@ static int liquidio_stop(struct net_device *netdev)
oct->props[lio->ifidx].napi_enabled = 0;
oct->droq[0]->ops.poll_mode = 0;
+
+ tasklet_enable(&oct_priv->droq_tasklet);
}
+ cancel_delayed_work_sync(&lio->stats_wk.work);
+
dev_info(&oct->pci_dev->dev, "%s interface is stopped\n", netdev->name);
return 0;
@@ -1093,10 +1101,9 @@ static void liquidio_set_mcast_list(struct net_device *netdev)
/* Apparently, any activity in this call from the kernel has to
* be atomic. So we won't wait for response.
*/
- nctrl.wait_time = 0;
ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl);
- if (ret < 0) {
+ if (ret) {
dev_err(&oct->pci_dev->dev, "DEVFLAGS change failed in core (ret: 0x%x)\n",
ret);
}
@@ -1133,8 +1140,6 @@ static int liquidio_set_mac(struct net_device *netdev, void *p)
nctrl.ncmd.s.more = 1;
nctrl.iq_no = lio->linfo.txpciq[0].s.q_no;
nctrl.netpndev = (u64)netdev;
- nctrl.cb_fn = liquidio_link_ctrl_cmd_completion;
- nctrl.wait_time = 100;
nctrl.udd[0] = 0;
/* The MAC Address is presented in network byte order. */
@@ -1145,6 +1150,13 @@ static int liquidio_set_mac(struct net_device *netdev, void *p)
dev_err(&oct->pci_dev->dev, "MAC Address change failed\n");
return -ENOMEM;
}
+
+ if (nctrl.sc_status ==
+ FIRMWARE_STATUS_CODE(OCTEON_REQUEST_NO_PERMISSION)) {
+ dev_err(&oct->pci_dev->dev, "MAC Address change failed: no permission\n");
+ return -EPERM;
+ }
+
memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
ether_addr_copy(((u8 *)&lio->linfo.hw_addr) + 2, addr->sa_data);
@@ -1198,7 +1210,6 @@ liquidio_get_stats64(struct net_device *netdev,
lstats->rx_packets = pkts;
lstats->rx_dropped = drop;
- octnet_get_link_stats(netdev);
lstats->multicast = oct->link_stats.fromwire.fw_total_mcast;
/* detailed rx_errors: */
@@ -1390,7 +1401,7 @@ static int send_nic_timestamp_pkt(struct octeon_device *oct,
* @returns whether the packet was transmitted to the device okay or not
* (NETDEV_TX_OK or NETDEV_TX_BUSY)
*/
-static int liquidio_xmit(struct sk_buff *skb, struct net_device *netdev)
+static netdev_tx_t liquidio_xmit(struct sk_buff *skb, struct net_device *netdev)
{
struct octnet_buf_free_info *finfo;
union octnic_cmd_setup cmdsetup;
@@ -1638,8 +1649,6 @@ liquidio_vlan_rx_add_vid(struct net_device *netdev,
struct lio *lio = GET_LIO(netdev);
struct octeon_device *oct = lio->oct_dev;
struct octnic_ctrl_pkt nctrl;
- struct completion compl;
- u16 response_code;
int ret = 0;
memset(&nctrl, 0, sizeof(struct octnic_ctrl_pkt));
@@ -1648,26 +1657,15 @@ liquidio_vlan_rx_add_vid(struct net_device *netdev,
nctrl.ncmd.s.cmd = OCTNET_CMD_ADD_VLAN_FILTER;
nctrl.ncmd.s.param1 = vid;
nctrl.iq_no = lio->linfo.txpciq[0].s.q_no;
- nctrl.wait_time = 100;
nctrl.netpndev = (u64)netdev;
nctrl.cb_fn = liquidio_link_ctrl_cmd_completion;
- init_completion(&compl);
- nctrl.completion = &compl;
- nctrl.response_code = &response_code;
ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl);
- if (ret < 0) {
+ if (ret) {
dev_err(&oct->pci_dev->dev, "Add VLAN filter failed in core (ret: 0x%x)\n",
ret);
- return -EIO;
- }
-
- if (!wait_for_completion_timeout(&compl,
- msecs_to_jiffies(nctrl.wait_time)))
- return -EPERM;
-
- if (READ_ONCE(response_code))
return -EPERM;
+ }
return 0;
}
@@ -1687,14 +1685,15 @@ liquidio_vlan_rx_kill_vid(struct net_device *netdev,
nctrl.ncmd.s.cmd = OCTNET_CMD_DEL_VLAN_FILTER;
nctrl.ncmd.s.param1 = vid;
nctrl.iq_no = lio->linfo.txpciq[0].s.q_no;
- nctrl.wait_time = 100;
nctrl.netpndev = (u64)netdev;
nctrl.cb_fn = liquidio_link_ctrl_cmd_completion;
ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl);
- if (ret < 0) {
+ if (ret) {
dev_err(&oct->pci_dev->dev, "Del VLAN filter failed in core (ret: 0x%x)\n",
ret);
+ if (ret > 0)
+ ret = -EIO;
}
return ret;
}
@@ -1720,14 +1719,15 @@ static int liquidio_set_rxcsum_command(struct net_device *netdev, int command,
nctrl.ncmd.s.cmd = command;
nctrl.ncmd.s.param1 = rx_cmd;
nctrl.iq_no = lio->linfo.txpciq[0].s.q_no;
- nctrl.wait_time = 100;
nctrl.netpndev = (u64)netdev;
nctrl.cb_fn = liquidio_link_ctrl_cmd_completion;
ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl);
- if (ret < 0) {
+ if (ret) {
dev_err(&oct->pci_dev->dev, "DEVFLAGS RXCSUM change failed in core (ret:0x%x)\n",
ret);
+ if (ret > 0)
+ ret = -EIO;
}
return ret;
}
@@ -1755,15 +1755,16 @@ static int liquidio_vxlan_port_command(struct net_device *netdev, int command,
nctrl.ncmd.s.more = vxlan_cmd_bit;
nctrl.ncmd.s.param1 = vxlan_port;
nctrl.iq_no = lio->linfo.txpciq[0].s.q_no;
- nctrl.wait_time = 100;
nctrl.netpndev = (u64)netdev;
nctrl.cb_fn = liquidio_link_ctrl_cmd_completion;
ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl);
- if (ret < 0) {
+ if (ret) {
dev_err(&oct->pci_dev->dev,
"DEVFLAGS VxLAN port add/delete failed in core (ret : 0x%x)\n",
ret);
+ if (ret > 0)
+ ret = -EIO;
}
return ret;
}
@@ -1924,8 +1925,7 @@ nic_info_err:
static int setup_nic_devices(struct octeon_device *octeon_dev)
{
int retval, num_iqueues, num_oqueues;
- struct liquidio_if_cfg_context *ctx;
- u32 resp_size, ctx_size, data_size;
+ u32 resp_size, data_size;
struct liquidio_if_cfg_resp *resp;
struct octeon_soft_command *sc;
union oct_nic_if_cfg if_cfg;
@@ -1956,13 +1956,11 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
for (i = 0; i < octeon_dev->ifcount; i++) {
resp_size = sizeof(struct liquidio_if_cfg_resp);
- ctx_size = sizeof(struct liquidio_if_cfg_context);
data_size = sizeof(struct lio_version);
sc = (struct octeon_soft_command *)
octeon_alloc_soft_command(octeon_dev, data_size,
- resp_size, ctx_size);
+ resp_size, 0);
resp = (struct liquidio_if_cfg_resp *)sc->virtrptr;
- ctx = (struct liquidio_if_cfg_context *)sc->ctxptr;
vdata = (struct lio_version *)sc->virtdptr;
*((u64 *)vdata) = 0;
@@ -1970,10 +1968,6 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
vdata->minor = cpu_to_be16(LIQUIDIO_BASE_MINOR_VERSION);
vdata->micro = cpu_to_be16(LIQUIDIO_BASE_MICRO_VERSION);
- WRITE_ONCE(ctx->cond, 0);
- ctx->octeon_id = lio_get_device_id(octeon_dev);
- init_waitqueue_head(&ctx->wc);
-
if_cfg.u64 = 0;
if_cfg.s.num_iqueues = octeon_dev->sriov_info.rings_per_vf;
@@ -1986,32 +1980,37 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
OPCODE_NIC_IF_CFG, 0, if_cfg.u64,
0);
- sc->callback = lio_if_cfg_callback;
- sc->callback_arg = sc;
- sc->wait_time = 5000;
+ init_completion(&sc->complete);
+ sc->sc_status = OCTEON_REQUEST_PENDING;
retval = octeon_send_soft_command(octeon_dev, sc);
if (retval == IQ_SEND_FAILED) {
dev_err(&octeon_dev->pci_dev->dev,
"iq/oq config failed status: %x\n", retval);
/* Soft instr is freed by driver in case of failure. */
- goto setup_nic_dev_fail;
+ octeon_free_soft_command(octeon_dev, sc);
+ return(-EIO);
}
/* Sleep on a wait queue till the cond flag indicates that the
* response arrived or timed-out.
*/
- if (sleep_cond(&ctx->wc, &ctx->cond) == -EINTR) {
- dev_err(&octeon_dev->pci_dev->dev, "Wait interrupted\n");
- goto setup_nic_wait_intr;
- }
+ retval = wait_for_sc_completion_timeout(octeon_dev, sc, 0);
+ if (retval)
+ return retval;
retval = resp->status;
if (retval) {
- dev_err(&octeon_dev->pci_dev->dev, "iq/oq config failed\n");
- goto setup_nic_dev_fail;
+ dev_err(&octeon_dev->pci_dev->dev,
+ "iq/oq config failed, retval = %d\n", retval);
+ WRITE_ONCE(sc->caller_is_done, true);
+ return -EIO;
}
+ snprintf(octeon_dev->fw_info.liquidio_firmware_version,
+ 32, "%s",
+ resp->cfg_info.liquidio_firmware_version);
+
octeon_swap_8B_data((u64 *)(&resp->cfg_info),
(sizeof(struct liquidio_if_cfg_info)) >> 3);
@@ -2022,7 +2021,8 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
dev_err(&octeon_dev->pci_dev->dev,
"Got bad iqueues (%016llx) or oqueues (%016llx) from firmware.\n",
resp->cfg_info.iqmask, resp->cfg_info.oqmask);
- goto setup_nic_dev_fail;
+ WRITE_ONCE(sc->caller_is_done, true);
+ goto setup_nic_dev_done;
}
dev_dbg(&octeon_dev->pci_dev->dev,
"interface %d, iqmask %016llx, oqmask %016llx, numiqueues %d, numoqueues %d\n",
@@ -2033,7 +2033,8 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
if (!netdev) {
dev_err(&octeon_dev->pci_dev->dev, "Device allocation failed\n");
- goto setup_nic_dev_fail;
+ WRITE_ONCE(sc->caller_is_done, true);
+ goto setup_nic_dev_done;
}
SET_NETDEV_DEV(netdev, &octeon_dev->pci_dev->dev);
@@ -2070,6 +2071,8 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
lio->linfo.link.u64 = resp->cfg_info.linfo.link.u64;
lio->linfo.macaddr_is_admin_asgnd =
resp->cfg_info.linfo.macaddr_is_admin_asgnd;
+ lio->linfo.macaddr_spoofchk =
+ resp->cfg_info.linfo.macaddr_spoofchk;
lio->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE);
@@ -2109,6 +2112,8 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
netdev->min_mtu = LIO_MIN_MTU_SIZE;
netdev->max_mtu = LIO_MAX_MTU_SIZE;
+ WRITE_ONCE(sc->caller_is_done, true);
+
/* Point to the properties for octeon device to which this
* interface belongs.
*/
@@ -2132,7 +2137,7 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
lio->linfo.num_txpciq,
lio->linfo.num_rxpciq)) {
dev_err(&octeon_dev->pci_dev->dev, "I/O queues creation failed\n");
- goto setup_nic_dev_fail;
+ goto setup_nic_dev_free;
}
ifstate_set(lio, LIO_IFSTATE_DROQ_OPS);
@@ -2155,7 +2160,7 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
if (lio_setup_glists(octeon_dev, lio, num_iqueues)) {
dev_err(&octeon_dev->pci_dev->dev,
"Gather list allocation failed\n");
- goto setup_nic_dev_fail;
+ goto setup_nic_dev_free;
}
/* Register ethtool support */
@@ -2170,15 +2175,15 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
OCTNIC_LROIPV4 | OCTNIC_LROIPV6);
if (setup_link_status_change_wq(netdev))
- goto setup_nic_dev_fail;
+ goto setup_nic_dev_free;
if (setup_rx_oom_poll_fn(netdev))
- goto setup_nic_dev_fail;
+ goto setup_nic_dev_free;
/* Register the network device with the OS */
if (register_netdev(netdev)) {
dev_err(&octeon_dev->pci_dev->dev, "Device registration failed\n");
- goto setup_nic_dev_fail;
+ goto setup_nic_dev_free;
}
dev_dbg(&octeon_dev->pci_dev->dev,
@@ -2201,24 +2206,21 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
dev_dbg(&octeon_dev->pci_dev->dev,
"NIC ifidx:%d Setup successful\n", i);
- octeon_free_soft_command(octeon_dev, sc);
-
octeon_dev->no_speed_setting = 1;
}
return 0;
-setup_nic_dev_fail:
-
- octeon_free_soft_command(octeon_dev, sc);
-
-setup_nic_wait_intr:
+setup_nic_dev_free:
while (i--) {
dev_err(&octeon_dev->pci_dev->dev,
"NIC ifidx:%d Setup failed\n", i);
liquidio_destroy_nic_device(octeon_dev, i);
}
+
+setup_nic_dev_done:
+
return -ENODEV;
}
diff --git a/drivers/net/ethernet/cavium/liquidio/lio_vf_rep.c b/drivers/net/ethernet/cavium/liquidio/lio_vf_rep.c
index ddd7431579f4..ea9859e028d4 100644
--- a/drivers/net/ethernet/cavium/liquidio/lio_vf_rep.c
+++ b/drivers/net/ethernet/cavium/liquidio/lio_vf_rep.c
@@ -27,11 +27,11 @@
#include "octeon_network.h"
#include <net/switchdev.h>
#include "lio_vf_rep.h"
-#include "octeon_network.h"
static int lio_vf_rep_open(struct net_device *ndev);
static int lio_vf_rep_stop(struct net_device *ndev);
-static int lio_vf_rep_pkt_xmit(struct sk_buff *skb, struct net_device *ndev);
+static netdev_tx_t lio_vf_rep_pkt_xmit(struct sk_buff *skb,
+ struct net_device *ndev);
static void lio_vf_rep_tx_timeout(struct net_device *netdev);
static int lio_vf_rep_phys_port_name(struct net_device *dev,
char *buf, size_t len);
@@ -49,44 +49,25 @@ static const struct net_device_ops lio_vf_rep_ndev_ops = {
.ndo_change_mtu = lio_vf_rep_change_mtu,
};
-static void
-lio_vf_rep_send_sc_complete(struct octeon_device *oct,
- u32 status, void *ptr)
-{
- struct octeon_soft_command *sc = (struct octeon_soft_command *)ptr;
- struct lio_vf_rep_sc_ctx *ctx =
- (struct lio_vf_rep_sc_ctx *)sc->ctxptr;
- struct lio_vf_rep_resp *resp =
- (struct lio_vf_rep_resp *)sc->virtrptr;
-
- if (status != OCTEON_REQUEST_TIMEOUT && READ_ONCE(resp->status))
- WRITE_ONCE(resp->status, 0);
-
- complete(&ctx->complete);
-}
-
static int
lio_vf_rep_send_soft_command(struct octeon_device *oct,
void *req, int req_size,
void *resp, int resp_size)
{
int tot_resp_size = sizeof(struct lio_vf_rep_resp) + resp_size;
- int ctx_size = sizeof(struct lio_vf_rep_sc_ctx);
struct octeon_soft_command *sc = NULL;
struct lio_vf_rep_resp *rep_resp;
- struct lio_vf_rep_sc_ctx *ctx;
void *sc_req;
int err;
sc = (struct octeon_soft_command *)
octeon_alloc_soft_command(oct, req_size,
- tot_resp_size, ctx_size);
+ tot_resp_size, 0);
if (!sc)
return -ENOMEM;
- ctx = (struct lio_vf_rep_sc_ctx *)sc->ctxptr;
- memset(ctx, 0, ctx_size);
- init_completion(&ctx->complete);
+ init_completion(&sc->complete);
+ sc->sc_status = OCTEON_REQUEST_PENDING;
sc_req = (struct lio_vf_rep_req *)sc->virtdptr;
memcpy(sc_req, req, req_size);
@@ -98,23 +79,24 @@ lio_vf_rep_send_soft_command(struct octeon_device *oct,
sc->iq_no = 0;
octeon_prepare_soft_command(oct, sc, OPCODE_NIC,
OPCODE_NIC_VF_REP_CMD, 0, 0, 0);
- sc->callback = lio_vf_rep_send_sc_complete;
- sc->callback_arg = sc;
- sc->wait_time = LIO_VF_REP_REQ_TMO_MS;
err = octeon_send_soft_command(oct, sc);
if (err == IQ_SEND_FAILED)
goto free_buff;
- wait_for_completion_timeout(&ctx->complete,
- msecs_to_jiffies
- (2 * LIO_VF_REP_REQ_TMO_MS));
+ err = wait_for_sc_completion_timeout(oct, sc, 0);
+ if (err)
+ return err;
+
err = READ_ONCE(rep_resp->status) ? -EBUSY : 0;
if (err)
dev_err(&oct->pci_dev->dev, "VF rep send config failed\n");
-
- if (resp)
+ else if (resp)
memcpy(resp, (rep_resp + 1), resp_size);
+
+ WRITE_ONCE(sc->caller_is_done, true);
+ return err;
+
free_buff:
octeon_free_soft_command(oct, sc);
@@ -380,7 +362,7 @@ lio_vf_rep_packet_sent_callback(struct octeon_device *oct,
netif_wake_queue(ndev);
}
-static int
+static netdev_tx_t
lio_vf_rep_pkt_xmit(struct sk_buff *skb, struct net_device *ndev)
{
struct lio_vf_rep_desc *vf_rep = netdev_priv(ndev);
@@ -404,7 +386,7 @@ lio_vf_rep_pkt_xmit(struct sk_buff *skb, struct net_device *ndev)
}
sc = (struct octeon_soft_command *)
- octeon_alloc_soft_command(oct, 0, 0, 0);
+ octeon_alloc_soft_command(oct, 0, 16, 0);
if (!sc) {
dev_err(&oct->pci_dev->dev, "VF rep: Soft command alloc failed\n");
goto xmit_failed;
@@ -413,6 +395,7 @@ lio_vf_rep_pkt_xmit(struct sk_buff *skb, struct net_device *ndev)
/* Multiple buffers are not used for vf_rep packets. */
if (skb_shinfo(skb)->nr_frags != 0) {
dev_err(&oct->pci_dev->dev, "VF rep: nr_frags != 0. Dropping packet\n");
+ octeon_free_soft_command(oct, sc);
goto xmit_failed;
}
@@ -420,6 +403,7 @@ lio_vf_rep_pkt_xmit(struct sk_buff *skb, struct net_device *ndev)
skb->data, skb->len, DMA_TO_DEVICE);
if (dma_mapping_error(&oct->pci_dev->dev, sc->dmadptr)) {
dev_err(&oct->pci_dev->dev, "VF rep: DMA mapping failed\n");
+ octeon_free_soft_command(oct, sc);
goto xmit_failed;
}
@@ -440,6 +424,7 @@ lio_vf_rep_pkt_xmit(struct sk_buff *skb, struct net_device *ndev)
if (status == IQ_SEND_FAILED) {
dma_unmap_single(&oct->pci_dev->dev, sc->dmadptr,
sc->datasize, DMA_TO_DEVICE);
+ octeon_free_soft_command(oct, sc);
goto xmit_failed;
}
diff --git a/drivers/net/ethernet/cavium/liquidio/liquidio_common.h b/drivers/net/ethernet/cavium/liquidio/liquidio_common.h
index 7407fcd338e9..a5e0e9f17959 100644
--- a/drivers/net/ethernet/cavium/liquidio/liquidio_common.h
+++ b/drivers/net/ethernet/cavium/liquidio/liquidio_common.h
@@ -118,6 +118,10 @@ enum octeon_tag_type {
/* App specific capabilities from firmware to pf driver */
#define LIQUIDIO_TIME_SYNC_CAP 0x1
#define LIQUIDIO_SWITCHDEV_CAP 0x2
+#define LIQUIDIO_SPOOFCHK_CAP 0x4
+
+/* error status return from firmware */
+#define OCTEON_REQUEST_NO_PERMISSION 0xc
static inline u32 incr_index(u32 index, u32 count, u32 max)
{
@@ -241,6 +245,10 @@ static inline void add_sg_size(struct octeon_sg_entry *sg_entry,
#define OCTNET_CMD_QUEUE_COUNT_CTL 0x1f
+#define OCTNET_CMD_GROUP1 1
+#define OCTNET_CMD_SET_VF_SPOOFCHK 0x1
+#define OCTNET_GROUP1_LAST_CMD OCTNET_CMD_SET_VF_SPOOFCHK
+
#define OCTNET_CMD_VXLAN_PORT_ADD 0x0
#define OCTNET_CMD_VXLAN_PORT_DEL 0x1
#define OCTNET_CMD_RXCSUM_ENABLE 0x0
@@ -250,9 +258,18 @@ static inline void add_sg_size(struct octeon_sg_entry *sg_entry,
#define OCTNET_CMD_VLAN_FILTER_ENABLE 0x1
#define OCTNET_CMD_VLAN_FILTER_DISABLE 0x0
+#define OCTNET_CMD_FAIL 0x1
+
+#define SEAPI_CMD_FEC_SET 0x0
+#define SEAPI_CMD_FEC_SET_DISABLE 0x0
+#define SEAPI_CMD_FEC_SET_RS 0x1
+#define SEAPI_CMD_FEC_GET 0x1
+
#define SEAPI_CMD_SPEED_SET 0x2
#define SEAPI_CMD_SPEED_GET 0x3
+#define OPCODE_NIC_VF_PORT_STATS 0x22
+
#define LIO_CMD_WAIT_TM 100
/* RX(packets coming from wire) Checksum verification flags */
@@ -301,7 +318,8 @@ union octnet_cmd {
u64 more:6; /* How many udd words follow the command */
- u64 reserved:29;
+ u64 cmdgroup:8;
+ u64 reserved:21;
u64 param1:16;
@@ -313,7 +331,8 @@ union octnet_cmd {
u64 param1:16;
- u64 reserved:29;
+ u64 reserved:21;
+ u64 cmdgroup:8;
u64 more:6;
@@ -757,13 +776,17 @@ struct oct_link_info {
#ifdef __BIG_ENDIAN_BITFIELD
u64 gmxport:16;
u64 macaddr_is_admin_asgnd:1;
- u64 rsvd:31;
+ u64 rsvd:13;
+ u64 macaddr_spoofchk:1;
+ u64 rsvd1:17;
u64 num_txpciq:8;
u64 num_rxpciq:8;
#else
u64 num_rxpciq:8;
u64 num_txpciq:8;
- u64 rsvd:31;
+ u64 rsvd1:17;
+ u64 macaddr_spoofchk:1;
+ u64 rsvd:13;
u64 macaddr_is_admin_asgnd:1;
u64 gmxport:16;
#endif
diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_config.h b/drivers/net/ethernet/cavium/liquidio/octeon_config.h
index ceac74388e09..24c212001212 100644
--- a/drivers/net/ethernet/cavium/liquidio/octeon_config.h
+++ b/drivers/net/ethernet/cavium/liquidio/octeon_config.h
@@ -438,9 +438,10 @@ struct octeon_config {
#define MAX_BAR1_IOREMAP_SIZE (16 * OCTEON_BAR1_ENTRY_SIZE)
/* Response lists - 1 ordered, 1 unordered-blocking, 1 unordered-nonblocking
+ * 1 process done list, 1 zombie lists(timeouted sc list)
* NoResponse Lists are now maintained with each IQ. (Dec' 2007).
*/
-#define MAX_RESPONSE_LISTS 4
+#define MAX_RESPONSE_LISTS 6
/* Opcode hash bits. The opcode is hashed on the lower 6-bits to lookup the
* dispatch table.
diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_device.c b/drivers/net/ethernet/cavium/liquidio/octeon_device.c
index f878a552fef3..ce8c3f818666 100644
--- a/drivers/net/ethernet/cavium/liquidio/octeon_device.c
+++ b/drivers/net/ethernet/cavium/liquidio/octeon_device.c
@@ -1044,8 +1044,7 @@ void octeon_delete_dispatch_list(struct octeon_device *oct)
dispatch = &oct->dispatch.dlist[i].list;
while (dispatch->next != dispatch) {
temp = dispatch->next;
- list_del(temp);
- list_add_tail(temp, &freelist);
+ list_move_tail(temp, &freelist);
}
oct->dispatch.dlist[i].opcode = 0;
@@ -1440,18 +1439,15 @@ void lio_enable_irq(struct octeon_droq *droq, struct octeon_instr_queue *iq)
/* the whole thing needs to be atomic, ideally */
if (droq) {
pkts_pend = (u32)atomic_read(&droq->pkts_pending);
- spin_lock_bh(&droq->lock);
writel(droq->pkt_count - pkts_pend, droq->pkts_sent_reg);
droq->pkt_count = pkts_pend;
- /* this write needs to be flushed before we release the lock */
- mmiowb();
- spin_unlock_bh(&droq->lock);
oct = droq->oct_dev;
}
if (iq) {
spin_lock_bh(&iq->lock);
- writel(iq->pkt_in_done, iq->inst_cnt_reg);
- iq->pkt_in_done = 0;
+ writel(iq->pkts_processed, iq->inst_cnt_reg);
+ iq->pkt_in_done -= iq->pkts_processed;
+ iq->pkts_processed = 0;
/* this write needs to be flushed before we release the lock */
mmiowb();
spin_unlock_bh(&iq->lock);
diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_device.h b/drivers/net/ethernet/cavium/liquidio/octeon_device.h
index d99ca6ba23a4..3d01d3602d8f 100644
--- a/drivers/net/ethernet/cavium/liquidio/octeon_device.h
+++ b/drivers/net/ethernet/cavium/liquidio/octeon_device.h
@@ -316,6 +316,8 @@ struct octdev_props {
* device pointer (used for OS specific calls).
*/
int rx_on;
+ int fec;
+ int fec_boot;
int napi_enabled;
int gmxport;
struct net_device *netdev;
@@ -397,6 +399,8 @@ struct octeon_sriov_info {
int vf_linkstate[MAX_POSSIBLE_VFS];
+ bool vf_spoofchk[MAX_POSSIBLE_VFS];
+
u64 vf_drv_loaded_mask;
};
@@ -607,6 +611,9 @@ struct octeon_device {
u8 speed_boot;
u8 speed_setting;
u8 no_speed_setting;
+
+ u32 vfstats_poll;
+#define LIO_VFSTATS_POLL 10
};
#define OCT_DRV_ONLINE 1
diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_droq.c b/drivers/net/ethernet/cavium/liquidio/octeon_droq.c
index a71dbb7ab6af..a0c099f71524 100644
--- a/drivers/net/ethernet/cavium/liquidio/octeon_droq.c
+++ b/drivers/net/ethernet/cavium/liquidio/octeon_droq.c
@@ -301,8 +301,6 @@ int octeon_init_droq(struct octeon_device *oct,
dev_dbg(&oct->pci_dev->dev, "DROQ INIT: max_empty_descs: %d\n",
droq->max_empty_descs);
- spin_lock_init(&droq->lock);
-
INIT_LIST_HEAD(&droq->dispatch_list);
/* For 56xx Pass1, this function won't be called, so no checks. */
@@ -333,8 +331,6 @@ init_droq_fail:
* Returns:
* Success: Pointer to recv_info_t
* Failure: NULL.
- * Locks:
- * The droq->lock is held when this routine is called.
*/
static inline struct octeon_recv_info *octeon_create_recv_info(
struct octeon_device *octeon_dev,
@@ -433,8 +429,6 @@ octeon_droq_refill_pullup_descs(struct octeon_droq *droq,
* up buffers (that were not dispatched) to form a contiguous ring.
* Returns:
* No of descriptors refilled.
- * Locks:
- * This routine is called with droq->lock held.
*/
static u32
octeon_droq_refill(struct octeon_device *octeon_dev, struct octeon_droq *droq)
@@ -449,8 +443,7 @@ octeon_droq_refill(struct octeon_device *octeon_dev, struct octeon_droq *droq)
while (droq->refill_count && (desc_refilled < droq->max_count)) {
/* If a valid buffer exists (happens if there is no dispatch),
- * reuse
- * the buffer, else allocate.
+ * reuse the buffer, else allocate.
*/
if (!droq->recv_buf_list[droq->refill_idx].buffer) {
pg_info =
@@ -503,34 +496,37 @@ octeon_droq_refill(struct octeon_device *octeon_dev, struct octeon_droq *droq)
/** check if we can allocate packets to get out of oom.
* @param droq - Droq being checked.
- * @return does not return anything
+ * @return 1 if fails to refill minimum
*/
-void octeon_droq_check_oom(struct octeon_droq *droq)
+int octeon_retry_droq_refill(struct octeon_droq *droq)
{
- int desc_refilled;
struct octeon_device *oct = droq->oct_dev;
+ int desc_refilled, reschedule = 1;
+ u32 pkts_credit;
+
+ pkts_credit = readl(droq->pkts_credit_reg);
+ desc_refilled = octeon_droq_refill(oct, droq);
+ if (desc_refilled) {
+ /* Flush the droq descriptor data to memory to be sure
+ * that when we update the credits the data in memory
+ * is accurate.
+ */
+ wmb();
+ writel(desc_refilled, droq->pkts_credit_reg);
+ /* make sure mmio write completes */
+ mmiowb();
- if (readl(droq->pkts_credit_reg) <= CN23XX_SLI_DEF_BP) {
- spin_lock_bh(&droq->lock);
- desc_refilled = octeon_droq_refill(oct, droq);
- if (desc_refilled) {
- /* Flush the droq descriptor data to memory to be sure
- * that when we update the credits the data in memory
- * is accurate.
- */
- wmb();
- writel(desc_refilled, droq->pkts_credit_reg);
- /* make sure mmio write completes */
- mmiowb();
- }
- spin_unlock_bh(&droq->lock);
+ if (pkts_credit + desc_refilled >= CN23XX_SLI_DEF_BP)
+ reschedule = 0;
}
+
+ return reschedule;
}
static inline u32
octeon_droq_get_bufcount(u32 buf_size, u32 total_len)
{
- return ((total_len + buf_size - 1) / buf_size);
+ return DIV_ROUND_UP(total_len, buf_size);
}
static int
@@ -603,9 +599,9 @@ octeon_droq_fast_process_packets(struct octeon_device *oct,
struct octeon_droq *droq,
u32 pkts_to_process)
{
+ u32 pkt, total_len = 0, pkt_count, retval;
struct octeon_droq_info *info;
union octeon_rh *rh;
- u32 pkt, total_len = 0, pkt_count;
pkt_count = pkts_to_process;
@@ -709,30 +705,43 @@ octeon_droq_fast_process_packets(struct octeon_device *oct,
if (droq->refill_count >= droq->refill_threshold) {
int desc_refilled = octeon_droq_refill(oct, droq);
- /* Flush the droq descriptor data to memory to be sure
- * that when we update the credits the data in memory
- * is accurate.
- */
- wmb();
- writel((desc_refilled), droq->pkts_credit_reg);
- /* make sure mmio write completes */
- mmiowb();
+ if (desc_refilled) {
+ /* Flush the droq descriptor data to memory to
+ * be sure that when we update the credits the
+ * data in memory is accurate.
+ */
+ wmb();
+ writel(desc_refilled, droq->pkts_credit_reg);
+ /* make sure mmio write completes */
+ mmiowb();
+ }
}
-
} /* for (each packet)... */
/* Increment refill_count by the number of buffers processed. */
droq->stats.pkts_received += pkt;
droq->stats.bytes_received += total_len;
+ retval = pkt;
if ((droq->ops.drop_on_max) && (pkts_to_process - pkt)) {
octeon_droq_drop_packets(oct, droq, (pkts_to_process - pkt));
droq->stats.dropped_toomany += (pkts_to_process - pkt);
- return pkts_to_process;
+ retval = pkts_to_process;
+ }
+
+ atomic_sub(retval, &droq->pkts_pending);
+
+ if (droq->refill_count >= droq->refill_threshold &&
+ readl(droq->pkts_credit_reg) < CN23XX_SLI_DEF_BP) {
+ octeon_droq_check_hw_for_pkts(droq);
+
+ /* Make sure there are no pkts_pending */
+ if (!atomic_read(&droq->pkts_pending))
+ octeon_schedule_rxq_oom_work(oct, droq);
}
- return pkt;
+ return retval;
}
int
@@ -740,29 +749,19 @@ octeon_droq_process_packets(struct octeon_device *oct,
struct octeon_droq *droq,
u32 budget)
{
- u32 pkt_count = 0, pkts_processed = 0;
+ u32 pkt_count = 0;
struct list_head *tmp, *tmp2;
- /* Grab the droq lock */
- spin_lock(&droq->lock);
-
octeon_droq_check_hw_for_pkts(droq);
pkt_count = atomic_read(&droq->pkts_pending);
- if (!pkt_count) {
- spin_unlock(&droq->lock);
+ if (!pkt_count)
return 0;
- }
if (pkt_count > budget)
pkt_count = budget;
- pkts_processed = octeon_droq_fast_process_packets(oct, droq, pkt_count);
-
- atomic_sub(pkts_processed, &droq->pkts_pending);
-
- /* Release the spin lock */
- spin_unlock(&droq->lock);
+ octeon_droq_fast_process_packets(oct, droq, pkt_count);
list_for_each_safe(tmp, tmp2, &droq->dispatch_list) {
struct __dispatch *rdisp = (struct __dispatch *)tmp;
@@ -798,8 +797,6 @@ octeon_droq_process_poll_pkts(struct octeon_device *oct,
if (budget > droq->max_count)
budget = droq->max_count;
- spin_lock(&droq->lock);
-
while (total_pkts_processed < budget) {
octeon_droq_check_hw_for_pkts(droq);
@@ -813,13 +810,9 @@ octeon_droq_process_poll_pkts(struct octeon_device *oct,
octeon_droq_fast_process_packets(oct, droq,
pkts_available);
- atomic_sub(pkts_processed, &droq->pkts_pending);
-
total_pkts_processed += pkts_processed;
}
- spin_unlock(&droq->lock);
-
list_for_each_safe(tmp, tmp2, &droq->dispatch_list) {
struct __dispatch *rdisp = (struct __dispatch *)tmp;
@@ -879,9 +872,8 @@ octeon_enable_irq(struct octeon_device *oct, u32 q_no)
int octeon_register_droq_ops(struct octeon_device *oct, u32 q_no,
struct octeon_droq_ops *ops)
{
- struct octeon_droq *droq;
- unsigned long flags;
struct octeon_config *oct_cfg = NULL;
+ struct octeon_droq *droq;
oct_cfg = octeon_get_conf(oct);
@@ -901,21 +893,15 @@ int octeon_register_droq_ops(struct octeon_device *oct, u32 q_no,
}
droq = oct->droq[q_no];
-
- spin_lock_irqsave(&droq->lock, flags);
-
memcpy(&droq->ops, ops, sizeof(struct octeon_droq_ops));
- spin_unlock_irqrestore(&droq->lock, flags);
-
return 0;
}
int octeon_unregister_droq_ops(struct octeon_device *oct, u32 q_no)
{
- unsigned long flags;
- struct octeon_droq *droq;
struct octeon_config *oct_cfg = NULL;
+ struct octeon_droq *droq;
oct_cfg = octeon_get_conf(oct);
@@ -936,14 +922,10 @@ int octeon_unregister_droq_ops(struct octeon_device *oct, u32 q_no)
return 0;
}
- spin_lock_irqsave(&droq->lock, flags);
-
droq->ops.fptr = NULL;
droq->ops.farg = NULL;
droq->ops.drop_on_max = 0;
- spin_unlock_irqrestore(&droq->lock, flags);
-
return 0;
}
diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_droq.h b/drivers/net/ethernet/cavium/liquidio/octeon_droq.h
index f28f262d4ab6..c9b19e624dce 100644
--- a/drivers/net/ethernet/cavium/liquidio/octeon_droq.h
+++ b/drivers/net/ethernet/cavium/liquidio/octeon_droq.h
@@ -245,9 +245,6 @@ struct octeon_droq_ops {
* Octeon DROQ.
*/
struct octeon_droq {
- /** A spinlock to protect access to this ring. */
- spinlock_t lock;
-
u32 q_no;
u32 pkt_count;
@@ -414,6 +411,6 @@ int octeon_droq_process_poll_pkts(struct octeon_device *oct,
int octeon_enable_irq(struct octeon_device *oct, u32 q_no);
-void octeon_droq_check_oom(struct octeon_droq *droq);
+int octeon_retry_droq_refill(struct octeon_droq *droq);
#endif /*__OCTEON_DROQ_H__ */
diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_iq.h b/drivers/net/ethernet/cavium/liquidio/octeon_iq.h
index 2327062e8af6..bebf3bd349c6 100644
--- a/drivers/net/ethernet/cavium/liquidio/octeon_iq.h
+++ b/drivers/net/ethernet/cavium/liquidio/octeon_iq.h
@@ -94,6 +94,8 @@ struct octeon_instr_queue {
u32 pkt_in_done;
+ u32 pkts_processed;
+
/** A spinlock to protect access to the input ring.*/
spinlock_t iq_flush_running_lock;
@@ -290,13 +292,19 @@ struct octeon_soft_command {
u32 ctxsize;
/** Time out and callback */
- size_t wait_time;
- size_t timeout;
+ size_t expiry_time;
u32 iq_no;
void (*callback)(struct octeon_device *, u32, void *);
void *callback_arg;
+
+ int caller_is_done;
+ u32 sc_status;
+ struct completion complete;
};
+/* max timeout (in milli sec) for soft request */
+#define LIO_SC_MAX_TMO_MS 60000
+
/** Maximum number of buffers to allocate into soft command buffer pool
*/
#define MAX_SOFT_COMMAND_BUFFERS 256
@@ -317,6 +325,8 @@ struct octeon_sc_buffer_pool {
(((octeon_dev_ptr)->instr_queue[iq_no]->stats.field) += count)
int octeon_setup_sc_buffer_pool(struct octeon_device *oct);
+int octeon_free_sc_done_list(struct octeon_device *oct);
+int octeon_free_sc_zombie_list(struct octeon_device *oct);
int octeon_free_sc_buffer_pool(struct octeon_device *oct);
struct octeon_soft_command *
octeon_alloc_soft_command(struct octeon_device *oct,
@@ -368,6 +378,9 @@ int octeon_send_command(struct octeon_device *oct, u32 iq_no,
u32 force_db, void *cmd, void *buf,
u32 datasize, u32 reqtype);
+void octeon_dump_soft_command(struct octeon_device *oct,
+ struct octeon_soft_command *sc);
+
void octeon_prepare_soft_command(struct octeon_device *oct,
struct octeon_soft_command *sc,
u8 opcode, u8 subcode,
diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_main.h b/drivers/net/ethernet/cavium/liquidio/octeon_main.h
index c846eec11a45..073d0647b439 100644
--- a/drivers/net/ethernet/cavium/liquidio/octeon_main.h
+++ b/drivers/net/ethernet/cavium/liquidio/octeon_main.h
@@ -70,6 +70,10 @@ void octeon_update_tx_completion_counters(void *buf, int reqtype,
void octeon_report_tx_completion_to_bql(void *txq, unsigned int pkts_compl,
unsigned int bytes_compl);
void octeon_pf_changed_vf_macaddr(struct octeon_device *oct, u8 *mac);
+
+void octeon_schedule_rxq_oom_work(struct octeon_device *oct,
+ struct octeon_droq *droq);
+
/** Swap 8B blocks */
static inline void octeon_swap_8B_data(u64 *data, u32 blocks)
{
@@ -146,46 +150,70 @@ err_release_region:
return 1;
}
+/* input parameter:
+ * sc: pointer to a soft request
+ * timeout: milli sec which an application wants to wait for the
+ response of the request.
+ * 0: the request will wait until its response gets back
+ * from the firmware within LIO_SC_MAX_TMO_MS milli sec.
+ * It the response does not return within
+ * LIO_SC_MAX_TMO_MS milli sec, lio_process_ordered_list()
+ * will move the request to zombie response list.
+ *
+ * return value:
+ * 0: got the response from firmware for the sc request.
+ * errno -EINTR: user abort the command.
+ * errno -ETIME: user spefified timeout value has been expired.
+ * errno -EBUSY: the response of the request does not return in
+ * resonable time (LIO_SC_MAX_TMO_MS).
+ * the sc wll be move to zombie response list by
+ * lio_process_ordered_list()
+ *
+ * A request with non-zero return value, the sc->caller_is_done
+ * will be marked 1.
+ * When getting a request with zero return value, the requestor
+ * should mark sc->caller_is_done with 1 after examing the
+ * response of sc.
+ * lio_process_ordered_list() will free the soft command on behalf
+ * of the soft command requestor.
+ * This is to fix the possible race condition of both timeout process
+ * and lio_process_ordered_list()/callback function to free a
+ * sc strucutre.
+ */
static inline int
-sleep_cond(wait_queue_head_t *wait_queue, int *condition)
+wait_for_sc_completion_timeout(struct octeon_device *oct_dev,
+ struct octeon_soft_command *sc,
+ unsigned long timeout)
{
int errno = 0;
- wait_queue_entry_t we;
-
- init_waitqueue_entry(&we, current);
- add_wait_queue(wait_queue, &we);
- while (!(READ_ONCE(*condition))) {
- set_current_state(TASK_INTERRUPTIBLE);
- if (signal_pending(current)) {
- errno = -EINTR;
- goto out;
- }
- schedule();
+ long timeout_jiff;
+
+ if (timeout)
+ timeout_jiff = msecs_to_jiffies(timeout);
+ else
+ timeout_jiff = MAX_SCHEDULE_TIMEOUT;
+
+ timeout_jiff =
+ wait_for_completion_interruptible_timeout(&sc->complete,
+ timeout_jiff);
+ if (timeout_jiff == 0) {
+ dev_err(&oct_dev->pci_dev->dev, "%s: sc is timeout\n",
+ __func__);
+ WRITE_ONCE(sc->caller_is_done, true);
+ errno = -ETIME;
+ } else if (timeout_jiff == -ERESTARTSYS) {
+ dev_err(&oct_dev->pci_dev->dev, "%s: sc is interrupted\n",
+ __func__);
+ WRITE_ONCE(sc->caller_is_done, true);
+ errno = -EINTR;
+ } else if (sc->sc_status == OCTEON_REQUEST_TIMEOUT) {
+ dev_err(&oct_dev->pci_dev->dev, "%s: sc has fatal timeout\n",
+ __func__);
+ WRITE_ONCE(sc->caller_is_done, true);
+ errno = -EBUSY;
}
-out:
- set_current_state(TASK_RUNNING);
- remove_wait_queue(wait_queue, &we);
- return errno;
-}
-/* Gives up the CPU for a timeout period.
- * Check that the condition is not true before we go to sleep for a
- * timeout period.
- */
-static inline void
-sleep_timeout_cond(wait_queue_head_t *wait_queue,
- int *condition,
- int timeout)
-{
- wait_queue_entry_t we;
-
- init_waitqueue_entry(&we, current);
- add_wait_queue(wait_queue, &we);
- set_current_state(TASK_INTERRUPTIBLE);
- if (!(*condition))
- schedule_timeout(timeout);
- set_current_state(TASK_RUNNING);
- remove_wait_queue(wait_queue, &we);
+ return errno;
}
#ifndef ROUNDUP4
diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_network.h b/drivers/net/ethernet/cavium/liquidio/octeon_network.h
index d7a3916fe877..50201fc86dcf 100644
--- a/drivers/net/ethernet/cavium/liquidio/octeon_network.h
+++ b/drivers/net/ethernet/cavium/liquidio/octeon_network.h
@@ -35,12 +35,6 @@
#define LIO_IFSTATE_RX_TIMESTAMP_ENABLED 0x08
#define LIO_IFSTATE_RESETTING 0x10
-struct liquidio_if_cfg_context {
- u32 octeon_id;
- wait_queue_head_t wc;
- int cond;
-};
-
struct liquidio_if_cfg_resp {
u64 rh;
struct liquidio_if_cfg_info cfg_info;
@@ -48,6 +42,7 @@ struct liquidio_if_cfg_resp {
};
#define LIO_IFCFG_WAIT_TIME 3000 /* In milli seconds */
+#define LIQUIDIO_NDEV_STATS_POLL_TIME_MS 200
/* Structure of a node in list of gather components maintained by
* NIC driver for each network device.
@@ -76,6 +71,12 @@ struct oct_nic_stats_resp {
u64 status;
};
+struct oct_nic_vf_stats_resp {
+ u64 rh;
+ u64 spoofmac_cnt;
+ u64 status;
+};
+
struct oct_nic_stats_ctrl {
struct completion complete;
struct net_device *netdev;
@@ -83,16 +84,13 @@ struct oct_nic_stats_ctrl {
struct oct_nic_seapi_resp {
u64 rh;
- u32 speed;
+ union {
+ u32 fec_setting;
+ u32 speed;
+ };
u64 status;
};
-struct liquidio_nic_seapi_ctl_context {
- int octeon_id;
- u32 status;
- struct completion complete;
-};
-
/** LiquidIO per-interface network private data */
struct lio {
/** State of the interface. Rx/Tx happens only in the RUNNING state. */
@@ -178,7 +176,7 @@ struct lio {
struct cavium_wq txq_status_wq;
/* work queue for rxq oom status */
- struct cavium_wq rxq_status_wq;
+ struct cavium_wq rxq_status_wq[MAX_POSSIBLE_OCTEON_OUTPUT_QUEUES];
/* work queue for link status */
struct cavium_wq link_status_wq;
@@ -187,6 +185,7 @@ struct lio {
struct cavium_wq sync_octeon_time_wq;
int netdev_uc_count;
+ struct cavium_wk stats_wk;
};
#define LIO_SIZE (sizeof(struct lio))
@@ -225,7 +224,7 @@ irqreturn_t liquidio_msix_intr_handler(int irq __attribute__((unused)),
int octeon_setup_interrupt(struct octeon_device *oct, u32 num_ioqs);
-int octnet_get_link_stats(struct net_device *netdev);
+void lio_fetch_stats(struct work_struct *work);
int lio_wait_for_clean_oq(struct octeon_device *oct);
/**
@@ -234,16 +233,14 @@ int lio_wait_for_clean_oq(struct octeon_device *oct);
*/
void liquidio_set_ethtool_ops(struct net_device *netdev);
-void lio_if_cfg_callback(struct octeon_device *oct,
- u32 status __attribute__((unused)),
- void *buf);
-
void lio_delete_glists(struct lio *lio);
int lio_setup_glists(struct octeon_device *oct, struct lio *lio, int num_qs);
int liquidio_get_speed(struct lio *lio);
int liquidio_set_speed(struct lio *lio, int speed);
+int liquidio_get_fec(struct lio *lio);
+int liquidio_set_fec(struct lio *lio, int on_off);
/**
* \brief Net device change_mtu
diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_nic.c b/drivers/net/ethernet/cavium/liquidio/octeon_nic.c
index 150609bd8849..1a706f81bbb0 100644
--- a/drivers/net/ethernet/cavium/liquidio/octeon_nic.c
+++ b/drivers/net/ethernet/cavium/liquidio/octeon_nic.c
@@ -75,8 +75,7 @@ octeon_alloc_soft_command_resp(struct octeon_device *oct,
else
sc->cmd.cmd2.rptr = sc->dmarptr;
- sc->wait_time = 1000;
- sc->timeout = jiffies + sc->wait_time;
+ sc->expiry_time = jiffies + msecs_to_jiffies(LIO_SC_MAX_TMO_MS);
return sc;
}
@@ -92,29 +91,6 @@ int octnet_send_nic_data_pkt(struct octeon_device *oct,
ndata->reqtype);
}
-static void octnet_link_ctrl_callback(struct octeon_device *oct,
- u32 status,
- void *sc_ptr)
-{
- struct octeon_soft_command *sc = (struct octeon_soft_command *)sc_ptr;
- struct octnic_ctrl_pkt *nctrl;
-
- nctrl = (struct octnic_ctrl_pkt *)sc->ctxptr;
-
- /* Call the callback function if status is zero (meaning OK) or status
- * contains a firmware status code bigger than zero (meaning the
- * firmware is reporting an error).
- * If no response was expected, status is OK if the command was posted
- * successfully.
- */
- if ((!status || status > FIRMWARE_STATUS_CODE(0)) && nctrl->cb_fn) {
- nctrl->status = status;
- nctrl->cb_fn(nctrl);
- }
-
- octeon_free_soft_command(oct, sc);
-}
-
static inline struct octeon_soft_command
*octnic_alloc_ctrl_pkt_sc(struct octeon_device *oct,
struct octnic_ctrl_pkt *nctrl)
@@ -127,17 +103,14 @@ static inline struct octeon_soft_command
uddsize = (u32)(nctrl->ncmd.s.more * 8);
datasize = OCTNET_CMD_SIZE + uddsize;
- rdatasize = (nctrl->wait_time) ? 16 : 0;
+ rdatasize = 16;
sc = (struct octeon_soft_command *)
- octeon_alloc_soft_command(oct, datasize, rdatasize,
- sizeof(struct octnic_ctrl_pkt));
+ octeon_alloc_soft_command(oct, datasize, rdatasize, 0);
if (!sc)
return NULL;
- memcpy(sc->ctxptr, nctrl, sizeof(struct octnic_ctrl_pkt));
-
data = (u8 *)sc->virtdptr;
memcpy(data, &nctrl->ncmd, OCTNET_CMD_SIZE);
@@ -154,9 +127,8 @@ static inline struct octeon_soft_command
octeon_prepare_soft_command(oct, sc, OPCODE_NIC, OPCODE_NIC_CMD,
0, 0, 0);
- sc->callback = octnet_link_ctrl_callback;
- sc->callback_arg = sc;
- sc->wait_time = nctrl->wait_time;
+ init_completion(&sc->complete);
+ sc->sc_status = OCTEON_REQUEST_PENDING;
return sc;
}
@@ -199,5 +171,28 @@ octnet_send_nic_ctrl_pkt(struct octeon_device *oct,
}
spin_unlock_bh(&oct->cmd_resp_wqlock);
+
+ if (nctrl->ncmd.s.cmdgroup == 0) {
+ switch (nctrl->ncmd.s.cmd) {
+ /* caller holds lock, can not sleep */
+ case OCTNET_CMD_CHANGE_DEVFLAGS:
+ case OCTNET_CMD_SET_MULTI_LIST:
+ case OCTNET_CMD_SET_UC_LIST:
+ WRITE_ONCE(sc->caller_is_done, true);
+ return retval;
+ }
+ }
+
+ retval = wait_for_sc_completion_timeout(oct, sc, 0);
+ if (retval)
+ return (retval);
+
+ nctrl->sc_status = sc->sc_status;
+ retval = nctrl->sc_status;
+ if (nctrl->cb_fn)
+ nctrl->cb_fn(nctrl);
+
+ WRITE_ONCE(sc->caller_is_done, true);
+
return retval;
}
diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_nic.h b/drivers/net/ethernet/cavium/liquidio/octeon_nic.h
index de4130d26a98..87dd6f89ce51 100644
--- a/drivers/net/ethernet/cavium/liquidio/octeon_nic.h
+++ b/drivers/net/ethernet/cavium/liquidio/octeon_nic.h
@@ -52,20 +52,13 @@ struct octnic_ctrl_pkt {
/** Input queue to use to send this command. */
u64 iq_no;
- /** Time to wait for Octeon software to respond to this control command.
- * If wait_time is 0, OSI assumes no response is expected.
- */
- size_t wait_time;
-
/** The network device that issued the control command. */
u64 netpndev;
/** Callback function called when the command has been fetched */
octnic_ctrl_pkt_cb_fn_t cb_fn;
- u32 status;
- u16 *response_code;
- struct completion *completion;
+ u32 sc_status;
};
#define MAX_UDD_SIZE(nctrl) (sizeof((nctrl)->udd))
diff --git a/drivers/net/ethernet/cavium/liquidio/request_manager.c b/drivers/net/ethernet/cavium/liquidio/request_manager.c
index 8f746e1348d4..c6f4cbda040f 100644
--- a/drivers/net/ethernet/cavium/liquidio/request_manager.c
+++ b/drivers/net/ethernet/cavium/liquidio/request_manager.c
@@ -123,6 +123,7 @@ int octeon_init_instr_queue(struct octeon_device *oct,
iq->do_auto_flush = 1;
iq->db_timeout = (u32)conf->db_timeout;
atomic_set(&iq->instr_pending, 0);
+ iq->pkts_processed = 0;
/* Initialize the spinlock for this instruction queue */
spin_lock_init(&iq->lock);
@@ -379,7 +380,6 @@ lio_process_iq_request_list(struct octeon_device *oct,
u32 inst_count = 0;
unsigned int pkts_compl = 0, bytes_compl = 0;
struct octeon_soft_command *sc;
- struct octeon_instr_irh *irh;
unsigned long flags;
while (old != iq->octeon_read_index) {
@@ -401,40 +401,21 @@ lio_process_iq_request_list(struct octeon_device *oct,
case REQTYPE_RESP_NET:
case REQTYPE_SOFT_COMMAND:
sc = buf;
-
- if (OCTEON_CN23XX_PF(oct) || OCTEON_CN23XX_VF(oct))
- irh = (struct octeon_instr_irh *)
- &sc->cmd.cmd3.irh;
- else
- irh = (struct octeon_instr_irh *)
- &sc->cmd.cmd2.irh;
- if (irh->rflag) {
- /* We're expecting a response from Octeon.
- * It's up to lio_process_ordered_list() to
- * process sc. Add sc to the ordered soft
- * command response list because we expect
- * a response from Octeon.
- */
- spin_lock_irqsave
- (&oct->response_list
- [OCTEON_ORDERED_SC_LIST].lock,
- flags);
- atomic_inc(&oct->response_list
- [OCTEON_ORDERED_SC_LIST].
- pending_req_count);
- list_add_tail(&sc->node, &oct->response_list
- [OCTEON_ORDERED_SC_LIST].head);
- spin_unlock_irqrestore
- (&oct->response_list
- [OCTEON_ORDERED_SC_LIST].lock,
- flags);
- } else {
- if (sc->callback) {
- /* This callback must not sleep */
- sc->callback(oct, OCTEON_REQUEST_DONE,
- sc->callback_arg);
- }
- }
+ /* We're expecting a response from Octeon.
+ * It's up to lio_process_ordered_list() to
+ * process sc. Add sc to the ordered soft
+ * command response list because we expect
+ * a response from Octeon.
+ */
+ spin_lock_irqsave(&oct->response_list
+ [OCTEON_ORDERED_SC_LIST].lock, flags);
+ atomic_inc(&oct->response_list
+ [OCTEON_ORDERED_SC_LIST].pending_req_count);
+ list_add_tail(&sc->node, &oct->response_list
+ [OCTEON_ORDERED_SC_LIST].head);
+ spin_unlock_irqrestore(&oct->response_list
+ [OCTEON_ORDERED_SC_LIST].lock,
+ flags);
break;
default:
dev_err(&oct->pci_dev->dev,
@@ -459,7 +440,7 @@ lio_process_iq_request_list(struct octeon_device *oct,
if (atomic_read(&oct->response_list
[OCTEON_ORDERED_SC_LIST].pending_req_count))
- queue_delayed_work(cwq->wq, &cwq->wk.work, msecs_to_jiffies(1));
+ queue_work(cwq->wq, &cwq->wk.work.work);
return inst_count;
}
@@ -495,6 +476,7 @@ octeon_flush_iq(struct octeon_device *oct, struct octeon_instr_queue *iq,
lio_process_iq_request_list(oct, iq, 0);
if (inst_processed) {
+ iq->pkts_processed += inst_processed;
atomic_sub(inst_processed, &iq->instr_pending);
iq->stats.instr_processed += inst_processed;
}
@@ -753,8 +735,7 @@ int octeon_send_soft_command(struct octeon_device *oct,
len = (u32)ih2->dlengsz;
}
- if (sc->wait_time)
- sc->timeout = jiffies + sc->wait_time;
+ sc->expiry_time = jiffies + msecs_to_jiffies(LIO_SC_MAX_TMO_MS);
return (octeon_send_command(oct, sc->iq_no, 1, &sc->cmd, sc,
len, REQTYPE_SOFT_COMMAND));
@@ -789,11 +770,76 @@ int octeon_setup_sc_buffer_pool(struct octeon_device *oct)
return 0;
}
+int octeon_free_sc_done_list(struct octeon_device *oct)
+{
+ struct octeon_response_list *done_sc_list, *zombie_sc_list;
+ struct octeon_soft_command *sc;
+ struct list_head *tmp, *tmp2;
+ spinlock_t *sc_lists_lock; /* lock for response_list */
+
+ done_sc_list = &oct->response_list[OCTEON_DONE_SC_LIST];
+ zombie_sc_list = &oct->response_list[OCTEON_ZOMBIE_SC_LIST];
+
+ if (!atomic_read(&done_sc_list->pending_req_count))
+ return 0;
+
+ sc_lists_lock = &oct->response_list[OCTEON_ORDERED_SC_LIST].lock;
+
+ spin_lock_bh(sc_lists_lock);
+
+ list_for_each_safe(tmp, tmp2, &done_sc_list->head) {
+ sc = list_entry(tmp, struct octeon_soft_command, node);
+
+ if (READ_ONCE(sc->caller_is_done)) {
+ list_del(&sc->node);
+ atomic_dec(&done_sc_list->pending_req_count);
+
+ if (*sc->status_word == COMPLETION_WORD_INIT) {
+ /* timeout; move sc to zombie list */
+ list_add_tail(&sc->node, &zombie_sc_list->head);
+ atomic_inc(&zombie_sc_list->pending_req_count);
+ } else {
+ octeon_free_soft_command(oct, sc);
+ }
+ }
+ }
+
+ spin_unlock_bh(sc_lists_lock);
+
+ return 0;
+}
+
+int octeon_free_sc_zombie_list(struct octeon_device *oct)
+{
+ struct octeon_response_list *zombie_sc_list;
+ struct octeon_soft_command *sc;
+ struct list_head *tmp, *tmp2;
+ spinlock_t *sc_lists_lock; /* lock for response_list */
+
+ zombie_sc_list = &oct->response_list[OCTEON_ZOMBIE_SC_LIST];
+ sc_lists_lock = &oct->response_list[OCTEON_ORDERED_SC_LIST].lock;
+
+ spin_lock_bh(sc_lists_lock);
+
+ list_for_each_safe(tmp, tmp2, &zombie_sc_list->head) {
+ list_del(tmp);
+ atomic_dec(&zombie_sc_list->pending_req_count);
+ sc = list_entry(tmp, struct octeon_soft_command, node);
+ octeon_free_soft_command(oct, sc);
+ }
+
+ spin_unlock_bh(sc_lists_lock);
+
+ return 0;
+}
+
int octeon_free_sc_buffer_pool(struct octeon_device *oct)
{
struct list_head *tmp, *tmp2;
struct octeon_soft_command *sc;
+ octeon_free_sc_zombie_list(oct);
+
spin_lock_bh(&oct->sc_buf_pool.lock);
list_for_each_safe(tmp, tmp2, &oct->sc_buf_pool.head) {
@@ -822,6 +868,9 @@ struct octeon_soft_command *octeon_alloc_soft_command(struct octeon_device *oct,
struct octeon_soft_command *sc = NULL;
struct list_head *tmp;
+ if (!rdatasize)
+ rdatasize = 16;
+
WARN_ON((offset + datasize + rdatasize + ctxsize) >
SOFT_COMMAND_BUFFER_SIZE);
diff --git a/drivers/net/ethernet/cavium/liquidio/response_manager.c b/drivers/net/ethernet/cavium/liquidio/response_manager.c
index fe5b53700576..ac7747ccf56a 100644
--- a/drivers/net/ethernet/cavium/liquidio/response_manager.c
+++ b/drivers/net/ethernet/cavium/liquidio/response_manager.c
@@ -69,6 +69,8 @@ int lio_process_ordered_list(struct octeon_device *octeon_dev,
u32 status;
u64 status64;
+ octeon_free_sc_done_list(octeon_dev);
+
ordered_sc_list = &octeon_dev->response_list[OCTEON_ORDERED_SC_LIST];
do {
@@ -111,26 +113,88 @@ int lio_process_ordered_list(struct octeon_device *octeon_dev,
}
}
}
- } else if (force_quit || (sc->timeout &&
- time_after(jiffies, (unsigned long)sc->timeout))) {
- dev_err(&octeon_dev->pci_dev->dev, "%s: cmd failed, timeout (%ld, %ld)\n",
- __func__, (long)jiffies, (long)sc->timeout);
+ } else if (unlikely(force_quit) || (sc->expiry_time &&
+ time_after(jiffies, (unsigned long)sc->expiry_time))) {
+ struct octeon_instr_irh *irh =
+ (struct octeon_instr_irh *)&sc->cmd.cmd3.irh;
+
+ dev_err(&octeon_dev->pci_dev->dev, "%s: ", __func__);
+ dev_err(&octeon_dev->pci_dev->dev,
+ "cmd %x/%x/%llx/%llx failed, ",
+ irh->opcode, irh->subcode,
+ sc->cmd.cmd3.ossp[0], sc->cmd.cmd3.ossp[1]);
+ dev_err(&octeon_dev->pci_dev->dev,
+ "timeout (%ld, %ld)\n",
+ (long)jiffies, (long)sc->expiry_time);
status = OCTEON_REQUEST_TIMEOUT;
}
if (status != OCTEON_REQUEST_PENDING) {
+ sc->sc_status = status;
+
/* we have received a response or we have timed out */
/* remove node from linked list */
list_del(&sc->node);
atomic_dec(&octeon_dev->response_list
- [OCTEON_ORDERED_SC_LIST].
- pending_req_count);
- spin_unlock_bh
- (&ordered_sc_list->lock);
+ [OCTEON_ORDERED_SC_LIST].
+ pending_req_count);
+
+ if (!sc->callback) {
+ atomic_inc(&octeon_dev->response_list
+ [OCTEON_DONE_SC_LIST].
+ pending_req_count);
+ list_add_tail(&sc->node,
+ &octeon_dev->response_list
+ [OCTEON_DONE_SC_LIST].head);
+
+ if (unlikely(READ_ONCE(sc->caller_is_done))) {
+ /* caller does not wait for response
+ * from firmware
+ */
+ if (status != OCTEON_REQUEST_DONE) {
+ struct octeon_instr_irh *irh;
+
+ irh =
+ (struct octeon_instr_irh *)
+ &sc->cmd.cmd3.irh;
+ dev_dbg
+ (&octeon_dev->pci_dev->dev,
+ "%s: sc failed: opcode=%x, ",
+ __func__, irh->opcode);
+ dev_dbg
+ (&octeon_dev->pci_dev->dev,
+ "subcode=%x, ossp[0]=%llx, ",
+ irh->subcode,
+ sc->cmd.cmd3.ossp[0]);
+ dev_dbg
+ (&octeon_dev->pci_dev->dev,
+ "ossp[1]=%llx, status=%d\n",
+ sc->cmd.cmd3.ossp[1],
+ status);
+ }
+ } else {
+ complete(&sc->complete);
+ }
+
+ spin_unlock_bh(&ordered_sc_list->lock);
+ } else {
+ /* sc with callback function */
+ if (status == OCTEON_REQUEST_TIMEOUT) {
+ atomic_inc(&octeon_dev->response_list
+ [OCTEON_ZOMBIE_SC_LIST].
+ pending_req_count);
+ list_add_tail(&sc->node,
+ &octeon_dev->response_list
+ [OCTEON_ZOMBIE_SC_LIST].
+ head);
+ }
+
+ spin_unlock_bh(&ordered_sc_list->lock);
- if (sc->callback)
sc->callback(octeon_dev, status,
sc->callback_arg);
+ /* sc is freed by caller */
+ }
request_complete++;
diff --git a/drivers/net/ethernet/cavium/liquidio/response_manager.h b/drivers/net/ethernet/cavium/liquidio/response_manager.h
index 9169c2815dba..ed4020d26fae 100644
--- a/drivers/net/ethernet/cavium/liquidio/response_manager.h
+++ b/drivers/net/ethernet/cavium/liquidio/response_manager.h
@@ -53,7 +53,9 @@ enum {
OCTEON_ORDERED_LIST = 0,
OCTEON_UNORDERED_NONBLOCKING_LIST = 1,
OCTEON_UNORDERED_BLOCKING_LIST = 2,
- OCTEON_ORDERED_SC_LIST = 3
+ OCTEON_ORDERED_SC_LIST = 3,
+ OCTEON_DONE_SC_LIST = 4,
+ OCTEON_ZOMBIE_SC_LIST = 5
};
/** Response Order values for a Octeon Request. */
diff --git a/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c b/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c
index bb43ddb7539e..4b3aecf98f2a 100644
--- a/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c
+++ b/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c
@@ -1268,12 +1268,13 @@ static int octeon_mgmt_stop(struct net_device *netdev)
return 0;
}
-static int octeon_mgmt_xmit(struct sk_buff *skb, struct net_device *netdev)
+static netdev_tx_t
+octeon_mgmt_xmit(struct sk_buff *skb, struct net_device *netdev)
{
struct octeon_mgmt *p = netdev_priv(netdev);
union mgmt_port_ring_entry re;
unsigned long flags;
- int rv = NETDEV_TX_BUSY;
+ netdev_tx_t rv = NETDEV_TX_BUSY;
re.d64 = 0;
re.s.tstamp = ((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) != 0);
diff --git a/drivers/net/ethernet/chelsio/Kconfig b/drivers/net/ethernet/chelsio/Kconfig
index e2cdfa75673f..75c1c5ed2387 100644
--- a/drivers/net/ethernet/chelsio/Kconfig
+++ b/drivers/net/ethernet/chelsio/Kconfig
@@ -67,6 +67,7 @@ config CHELSIO_T3
config CHELSIO_T4
tristate "Chelsio Communications T4/T5/T6 Ethernet support"
depends on PCI && (IPV6 || IPV6=n)
+ depends on THERMAL || !THERMAL
select FW_LOADER
select MDIO
select ZLIB_DEFLATE
diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
index a19172dbe6be..1e82b9efe447 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
@@ -33,7 +33,6 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
@@ -2159,6 +2158,8 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
return -EPERM;
if (copy_from_user(&t, useraddr, sizeof(t)))
return -EFAULT;
+ if (t.cmd != CHELSIO_SET_QSET_PARAMS)
+ return -EINVAL;
if (t.qset_idx >= SGE_QSETS)
return -EINVAL;
if (!in_range(t.intr_lat, 0, M_NEWTIMER) ||
@@ -2258,6 +2259,9 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
if (copy_from_user(&t, useraddr, sizeof(t)))
return -EFAULT;
+ if (t.cmd != CHELSIO_GET_QSET_PARAMS)
+ return -EINVAL;
+
/* Display qsets for all ports when offload enabled */
if (test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) {
q1 = 0;
@@ -2303,6 +2307,8 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
return -EBUSY;
if (copy_from_user(&edata, useraddr, sizeof(edata)))
return -EFAULT;
+ if (edata.cmd != CHELSIO_SET_QSET_NUM)
+ return -EINVAL;
if (edata.val < 1 ||
(edata.val > 1 && !(adapter->flags & USING_MSIX)))
return -EINVAL;
@@ -2343,6 +2349,8 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
return -EPERM;
if (copy_from_user(&t, useraddr, sizeof(t)))
return -EFAULT;
+ if (t.cmd != CHELSIO_LOAD_FW)
+ return -EINVAL;
/* Check t.len sanity ? */
fw_data = memdup_user(useraddr + sizeof(t), t.len);
if (IS_ERR(fw_data))
@@ -2366,6 +2374,8 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
return -EBUSY;
if (copy_from_user(&m, useraddr, sizeof(m)))
return -EFAULT;
+ if (m.cmd != CHELSIO_SETMTUTAB)
+ return -EINVAL;
if (m.nmtus != NMTUS)
return -EINVAL;
if (m.mtus[0] < 81) /* accommodate SACK */
@@ -2407,6 +2417,8 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
return -EBUSY;
if (copy_from_user(&m, useraddr, sizeof(m)))
return -EFAULT;
+ if (m.cmd != CHELSIO_SET_PM)
+ return -EINVAL;
if (!is_power_of_2(m.rx_pg_sz) ||
!is_power_of_2(m.tx_pg_sz))
return -EINVAL; /* not power of 2 */
@@ -2440,6 +2452,8 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
return -EIO; /* need the memory controllers */
if (copy_from_user(&t, useraddr, sizeof(t)))
return -EFAULT;
+ if (t.cmd != CHELSIO_GET_MEM)
+ return -EINVAL;
if ((t.addr & 7) || (t.len & 7))
return -EINVAL;
if (t.mem_id == MEM_CM)
@@ -2492,6 +2506,8 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
return -EAGAIN;
if (copy_from_user(&t, useraddr, sizeof(t)))
return -EFAULT;
+ if (t.cmd != CHELSIO_SET_TRACE_FILTER)
+ return -EINVAL;
tp = (const struct trace_params *)&t.sip;
if (t.config_tx)
@@ -3423,8 +3439,7 @@ static void remove_one(struct pci_dev *pdev)
free_netdev(adapter->port[i]);
iounmap(adapter->regs);
- if (adapter->nofail_skb)
- kfree_skb(adapter->nofail_skb);
+ kfree_skb(adapter->nofail_skb);
kfree(adapter);
pci_release_regions(pdev);
pci_disable_device(pdev);
diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c
index 50cd660732c5..84604aff53ce 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c
@@ -1302,8 +1302,7 @@ void cxgb3_offload_deactivate(struct adapter *adapter)
rcu_read_unlock();
RCU_INIT_POINTER(tdev->l2opt, NULL);
call_rcu(&d->rcu_head, clean_l2_data);
- if (t->nofail_skb)
- kfree_skb(t->nofail_skb);
+ kfree_skb(t->nofail_skb);
kfree(t);
}
diff --git a/drivers/net/ethernet/chelsio/cxgb4/Makefile b/drivers/net/ethernet/chelsio/cxgb4/Makefile
index bea6a059a8f1..78e5d17a1d5f 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/Makefile
+++ b/drivers/net/ethernet/chelsio/cxgb4/Makefile
@@ -12,3 +12,6 @@ cxgb4-objs := cxgb4_main.o l2t.o smt.o t4_hw.o sge.o clip_tbl.o cxgb4_ethtool.o
cxgb4-$(CONFIG_CHELSIO_T4_DCB) += cxgb4_dcb.o
cxgb4-$(CONFIG_CHELSIO_T4_FCOE) += cxgb4_fcoe.o
cxgb4-$(CONFIG_DEBUG_FS) += cxgb4_debugfs.o
+ifdef CONFIG_THERMAL
+cxgb4-objs += cxgb4_thermal.o
+endif
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
index 36d25883d123..b2d617abcf49 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
@@ -315,6 +315,48 @@ struct cudbg_pbt_tables {
u32 pbt_data[CUDBG_PBT_DATA_ENTRIES];
};
+enum cudbg_qdesc_qtype {
+ CUDBG_QTYPE_UNKNOWN = 0,
+ CUDBG_QTYPE_NIC_TXQ,
+ CUDBG_QTYPE_NIC_RXQ,
+ CUDBG_QTYPE_NIC_FLQ,
+ CUDBG_QTYPE_CTRLQ,
+ CUDBG_QTYPE_FWEVTQ,
+ CUDBG_QTYPE_INTRQ,
+ CUDBG_QTYPE_PTP_TXQ,
+ CUDBG_QTYPE_OFLD_TXQ,
+ CUDBG_QTYPE_RDMA_RXQ,
+ CUDBG_QTYPE_RDMA_FLQ,
+ CUDBG_QTYPE_RDMA_CIQ,
+ CUDBG_QTYPE_ISCSI_RXQ,
+ CUDBG_QTYPE_ISCSI_FLQ,
+ CUDBG_QTYPE_ISCSIT_RXQ,
+ CUDBG_QTYPE_ISCSIT_FLQ,
+ CUDBG_QTYPE_CRYPTO_TXQ,
+ CUDBG_QTYPE_CRYPTO_RXQ,
+ CUDBG_QTYPE_CRYPTO_FLQ,
+ CUDBG_QTYPE_TLS_RXQ,
+ CUDBG_QTYPE_TLS_FLQ,
+ CUDBG_QTYPE_MAX,
+};
+
+#define CUDBG_QDESC_REV 1
+
+struct cudbg_qdesc_entry {
+ u32 data_size;
+ u32 qtype;
+ u32 qid;
+ u32 desc_size;
+ u32 num_desc;
+ u8 data[0]; /* Must be last */
+};
+
+struct cudbg_qdesc_info {
+ u32 qdesc_entry_size;
+ u32 num_queues;
+ u8 data[0]; /* Must be last */
+};
+
#define IREG_NUM_ELEM 4
static const u32 t6_tp_pio_array[][IREG_NUM_ELEM] = {
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h b/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
index 215fe6260fd7..dec63c15c0ba 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
@@ -81,7 +81,8 @@ enum cudbg_dbg_entity_type {
CUDBG_MBOX_LOG = 66,
CUDBG_HMA_INDIRECT = 67,
CUDBG_HMA = 68,
- CUDBG_MAX_ENTITY = 70,
+ CUDBG_QDESC = 70,
+ CUDBG_MAX_ENTITY = 71,
};
struct cudbg_init {
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
index d97e0d7e541a..7c49681407ad 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
@@ -19,6 +19,7 @@
#include "t4_regs.h"
#include "cxgb4.h"
+#include "cxgb4_cudbg.h"
#include "cudbg_if.h"
#include "cudbg_lib_common.h"
#include "cudbg_entity.h"
@@ -2890,3 +2891,240 @@ int cudbg_collect_hma_indirect(struct cudbg_init *pdbg_init,
}
return cudbg_write_and_release_buff(pdbg_init, &temp_buff, dbg_buff);
}
+
+void cudbg_fill_qdesc_num_and_size(const struct adapter *padap,
+ u32 *num, u32 *size)
+{
+ u32 tot_entries = 0, tot_size = 0;
+
+ /* NIC TXQ, RXQ, FLQ, and CTRLQ */
+ tot_entries += MAX_ETH_QSETS * 3;
+ tot_entries += MAX_CTRL_QUEUES;
+
+ tot_size += MAX_ETH_QSETS * MAX_TXQ_ENTRIES * MAX_TXQ_DESC_SIZE;
+ tot_size += MAX_ETH_QSETS * MAX_RSPQ_ENTRIES * MAX_RXQ_DESC_SIZE;
+ tot_size += MAX_ETH_QSETS * MAX_RX_BUFFERS * MAX_FL_DESC_SIZE;
+ tot_size += MAX_CTRL_QUEUES * MAX_CTRL_TXQ_ENTRIES *
+ MAX_CTRL_TXQ_DESC_SIZE;
+
+ /* FW_EVTQ and INTRQ */
+ tot_entries += INGQ_EXTRAS;
+ tot_size += INGQ_EXTRAS * MAX_RSPQ_ENTRIES * MAX_RXQ_DESC_SIZE;
+
+ /* PTP_TXQ */
+ tot_entries += 1;
+ tot_size += MAX_TXQ_ENTRIES * MAX_TXQ_DESC_SIZE;
+
+ /* ULD TXQ, RXQ, and FLQ */
+ tot_entries += CXGB4_TX_MAX * MAX_OFLD_QSETS;
+ tot_entries += CXGB4_ULD_MAX * MAX_ULD_QSETS * 2;
+
+ tot_size += CXGB4_TX_MAX * MAX_OFLD_QSETS * MAX_TXQ_ENTRIES *
+ MAX_TXQ_DESC_SIZE;
+ tot_size += CXGB4_ULD_MAX * MAX_ULD_QSETS * MAX_RSPQ_ENTRIES *
+ MAX_RXQ_DESC_SIZE;
+ tot_size += CXGB4_ULD_MAX * MAX_ULD_QSETS * MAX_RX_BUFFERS *
+ MAX_FL_DESC_SIZE;
+
+ /* ULD CIQ */
+ tot_entries += CXGB4_ULD_MAX * MAX_ULD_QSETS;
+ tot_size += CXGB4_ULD_MAX * MAX_ULD_QSETS * SGE_MAX_IQ_SIZE *
+ MAX_RXQ_DESC_SIZE;
+
+ tot_size += sizeof(struct cudbg_ver_hdr) +
+ sizeof(struct cudbg_qdesc_info) +
+ sizeof(struct cudbg_qdesc_entry) * tot_entries;
+
+ if (num)
+ *num = tot_entries;
+
+ if (size)
+ *size = tot_size;
+}
+
+int cudbg_collect_qdesc(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err)
+{
+ u32 num_queues = 0, tot_entries = 0, size = 0;
+ struct adapter *padap = pdbg_init->adap;
+ struct cudbg_buffer temp_buff = { 0 };
+ struct cudbg_qdesc_entry *qdesc_entry;
+ struct cudbg_qdesc_info *qdesc_info;
+ struct cudbg_ver_hdr *ver_hdr;
+ struct sge *s = &padap->sge;
+ u32 i, j, cur_off, tot_len;
+ u8 *data;
+ int rc;
+
+ cudbg_fill_qdesc_num_and_size(padap, &tot_entries, &size);
+ size = min_t(u32, size, CUDBG_DUMP_BUFF_SIZE);
+ tot_len = size;
+ data = kvzalloc(size, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ ver_hdr = (struct cudbg_ver_hdr *)data;
+ ver_hdr->signature = CUDBG_ENTITY_SIGNATURE;
+ ver_hdr->revision = CUDBG_QDESC_REV;
+ ver_hdr->size = sizeof(struct cudbg_qdesc_info);
+ size -= sizeof(*ver_hdr);
+
+ qdesc_info = (struct cudbg_qdesc_info *)(data +
+ sizeof(*ver_hdr));
+ size -= sizeof(*qdesc_info);
+ qdesc_entry = (struct cudbg_qdesc_entry *)qdesc_info->data;
+
+#define QDESC_GET(q, desc, type, label) do { \
+ if (size <= 0) { \
+ goto label; \
+ } \
+ if (desc) { \
+ cudbg_fill_qdesc_##q(q, type, qdesc_entry); \
+ size -= sizeof(*qdesc_entry) + qdesc_entry->data_size; \
+ num_queues++; \
+ qdesc_entry = cudbg_next_qdesc(qdesc_entry); \
+ } \
+} while (0)
+
+#define QDESC_GET_TXQ(q, type, label) do { \
+ struct sge_txq *txq = (struct sge_txq *)q; \
+ QDESC_GET(txq, txq->desc, type, label); \
+} while (0)
+
+#define QDESC_GET_RXQ(q, type, label) do { \
+ struct sge_rspq *rxq = (struct sge_rspq *)q; \
+ QDESC_GET(rxq, rxq->desc, type, label); \
+} while (0)
+
+#define QDESC_GET_FLQ(q, type, label) do { \
+ struct sge_fl *flq = (struct sge_fl *)q; \
+ QDESC_GET(flq, flq->desc, type, label); \
+} while (0)
+
+ /* NIC TXQ */
+ for (i = 0; i < s->ethqsets; i++)
+ QDESC_GET_TXQ(&s->ethtxq[i].q, CUDBG_QTYPE_NIC_TXQ, out);
+
+ /* NIC RXQ */
+ for (i = 0; i < s->ethqsets; i++)
+ QDESC_GET_RXQ(&s->ethrxq[i].rspq, CUDBG_QTYPE_NIC_RXQ, out);
+
+ /* NIC FLQ */
+ for (i = 0; i < s->ethqsets; i++)
+ QDESC_GET_FLQ(&s->ethrxq[i].fl, CUDBG_QTYPE_NIC_FLQ, out);
+
+ /* NIC CTRLQ */
+ for (i = 0; i < padap->params.nports; i++)
+ QDESC_GET_TXQ(&s->ctrlq[i].q, CUDBG_QTYPE_CTRLQ, out);
+
+ /* FW_EVTQ */
+ QDESC_GET_RXQ(&s->fw_evtq, CUDBG_QTYPE_FWEVTQ, out);
+
+ /* INTRQ */
+ QDESC_GET_RXQ(&s->intrq, CUDBG_QTYPE_INTRQ, out);
+
+ /* PTP_TXQ */
+ QDESC_GET_TXQ(&s->ptptxq.q, CUDBG_QTYPE_PTP_TXQ, out);
+
+ /* ULD Queues */
+ mutex_lock(&uld_mutex);
+
+ if (s->uld_txq_info) {
+ struct sge_uld_txq_info *utxq;
+
+ /* ULD TXQ */
+ for (j = 0; j < CXGB4_TX_MAX; j++) {
+ if (!s->uld_txq_info[j])
+ continue;
+
+ utxq = s->uld_txq_info[j];
+ for (i = 0; i < utxq->ntxq; i++)
+ QDESC_GET_TXQ(&utxq->uldtxq[i].q,
+ cudbg_uld_txq_to_qtype(j),
+ out_unlock);
+ }
+ }
+
+ if (s->uld_rxq_info) {
+ struct sge_uld_rxq_info *urxq;
+ u32 base;
+
+ /* ULD RXQ */
+ for (j = 0; j < CXGB4_ULD_MAX; j++) {
+ if (!s->uld_rxq_info[j])
+ continue;
+
+ urxq = s->uld_rxq_info[j];
+ for (i = 0; i < urxq->nrxq; i++)
+ QDESC_GET_RXQ(&urxq->uldrxq[i].rspq,
+ cudbg_uld_rxq_to_qtype(j),
+ out_unlock);
+ }
+
+ /* ULD FLQ */
+ for (j = 0; j < CXGB4_ULD_MAX; j++) {
+ if (!s->uld_rxq_info[j])
+ continue;
+
+ urxq = s->uld_rxq_info[j];
+ for (i = 0; i < urxq->nrxq; i++)
+ QDESC_GET_FLQ(&urxq->uldrxq[i].fl,
+ cudbg_uld_flq_to_qtype(j),
+ out_unlock);
+ }
+
+ /* ULD CIQ */
+ for (j = 0; j < CXGB4_ULD_MAX; j++) {
+ if (!s->uld_rxq_info[j])
+ continue;
+
+ urxq = s->uld_rxq_info[j];
+ base = urxq->nrxq;
+ for (i = 0; i < urxq->nciq; i++)
+ QDESC_GET_RXQ(&urxq->uldrxq[base + i].rspq,
+ cudbg_uld_ciq_to_qtype(j),
+ out_unlock);
+ }
+ }
+
+out_unlock:
+ mutex_unlock(&uld_mutex);
+
+out:
+ qdesc_info->qdesc_entry_size = sizeof(*qdesc_entry);
+ qdesc_info->num_queues = num_queues;
+ cur_off = 0;
+ while (tot_len) {
+ u32 chunk_size = min_t(u32, tot_len, CUDBG_CHUNK_SIZE);
+
+ rc = cudbg_get_buff(pdbg_init, dbg_buff, chunk_size,
+ &temp_buff);
+ if (rc) {
+ cudbg_err->sys_warn = CUDBG_STATUS_PARTIAL_DATA;
+ goto out_free;
+ }
+
+ memcpy(temp_buff.data, data + cur_off, chunk_size);
+ tot_len -= chunk_size;
+ cur_off += chunk_size;
+ rc = cudbg_write_and_release_buff(pdbg_init, &temp_buff,
+ dbg_buff);
+ if (rc) {
+ cudbg_put_buff(pdbg_init, &temp_buff);
+ cudbg_err->sys_warn = CUDBG_STATUS_PARTIAL_DATA;
+ goto out_free;
+ }
+ }
+
+out_free:
+ if (data)
+ kvfree(data);
+
+#undef QDESC_GET_FLQ
+#undef QDESC_GET_RXQ
+#undef QDESC_GET_TXQ
+#undef QDESC_GET
+
+ return rc;
+}
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
index eebefe7cd18e..f047a01a3e5b 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
@@ -171,6 +171,9 @@ int cudbg_collect_hma_indirect(struct cudbg_init *pdbg_init,
int cudbg_collect_hma_meminfo(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err);
+int cudbg_collect_qdesc(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err);
struct cudbg_entity_hdr *cudbg_get_entity_hdr(void *outbuf, int i);
void cudbg_align_debug_buffer(struct cudbg_buffer *dbg_buff,
@@ -182,4 +185,107 @@ int cudbg_fill_meminfo(struct adapter *padap,
struct cudbg_meminfo *meminfo_buff);
void cudbg_fill_le_tcam_info(struct adapter *padap,
struct cudbg_tcam *tcam_region);
+void cudbg_fill_qdesc_num_and_size(const struct adapter *padap,
+ u32 *num, u32 *size);
+
+static inline u32 cudbg_uld_txq_to_qtype(u32 uld)
+{
+ switch (uld) {
+ case CXGB4_TX_OFLD:
+ return CUDBG_QTYPE_OFLD_TXQ;
+ case CXGB4_TX_CRYPTO:
+ return CUDBG_QTYPE_CRYPTO_TXQ;
+ }
+
+ return CUDBG_QTYPE_UNKNOWN;
+}
+
+static inline u32 cudbg_uld_rxq_to_qtype(u32 uld)
+{
+ switch (uld) {
+ case CXGB4_ULD_RDMA:
+ return CUDBG_QTYPE_RDMA_RXQ;
+ case CXGB4_ULD_ISCSI:
+ return CUDBG_QTYPE_ISCSI_RXQ;
+ case CXGB4_ULD_ISCSIT:
+ return CUDBG_QTYPE_ISCSIT_RXQ;
+ case CXGB4_ULD_CRYPTO:
+ return CUDBG_QTYPE_CRYPTO_RXQ;
+ case CXGB4_ULD_TLS:
+ return CUDBG_QTYPE_TLS_RXQ;
+ }
+
+ return CUDBG_QTYPE_UNKNOWN;
+}
+
+static inline u32 cudbg_uld_flq_to_qtype(u32 uld)
+{
+ switch (uld) {
+ case CXGB4_ULD_RDMA:
+ return CUDBG_QTYPE_RDMA_FLQ;
+ case CXGB4_ULD_ISCSI:
+ return CUDBG_QTYPE_ISCSI_FLQ;
+ case CXGB4_ULD_ISCSIT:
+ return CUDBG_QTYPE_ISCSIT_FLQ;
+ case CXGB4_ULD_CRYPTO:
+ return CUDBG_QTYPE_CRYPTO_FLQ;
+ case CXGB4_ULD_TLS:
+ return CUDBG_QTYPE_TLS_FLQ;
+ }
+
+ return CUDBG_QTYPE_UNKNOWN;
+}
+
+static inline u32 cudbg_uld_ciq_to_qtype(u32 uld)
+{
+ switch (uld) {
+ case CXGB4_ULD_RDMA:
+ return CUDBG_QTYPE_RDMA_CIQ;
+ }
+
+ return CUDBG_QTYPE_UNKNOWN;
+}
+
+static inline void cudbg_fill_qdesc_txq(const struct sge_txq *txq,
+ enum cudbg_qdesc_qtype type,
+ struct cudbg_qdesc_entry *entry)
+{
+ entry->qtype = type;
+ entry->qid = txq->cntxt_id;
+ entry->desc_size = sizeof(struct tx_desc);
+ entry->num_desc = txq->size;
+ entry->data_size = txq->size * sizeof(struct tx_desc);
+ memcpy(entry->data, txq->desc, entry->data_size);
+}
+
+static inline void cudbg_fill_qdesc_rxq(const struct sge_rspq *rxq,
+ enum cudbg_qdesc_qtype type,
+ struct cudbg_qdesc_entry *entry)
+{
+ entry->qtype = type;
+ entry->qid = rxq->cntxt_id;
+ entry->desc_size = rxq->iqe_len;
+ entry->num_desc = rxq->size;
+ entry->data_size = rxq->size * rxq->iqe_len;
+ memcpy(entry->data, rxq->desc, entry->data_size);
+}
+
+static inline void cudbg_fill_qdesc_flq(const struct sge_fl *flq,
+ enum cudbg_qdesc_qtype type,
+ struct cudbg_qdesc_entry *entry)
+{
+ entry->qtype = type;
+ entry->qid = flq->cntxt_id;
+ entry->desc_size = sizeof(__be64);
+ entry->num_desc = flq->size;
+ entry->data_size = flq->size * sizeof(__be64);
+ memcpy(entry->data, flq->desc, entry->data_size);
+}
+
+static inline
+struct cudbg_qdesc_entry *cudbg_next_qdesc(struct cudbg_qdesc_entry *e)
+{
+ return (struct cudbg_qdesc_entry *)
+ ((u8 *)e + sizeof(*e) + e->data_size);
+}
#endif /* __CUDBG_LIB_H__ */
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
index 76d16747f513..b16f4b3ef4c5 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
@@ -52,6 +52,7 @@
#include <linux/ptp_clock_kernel.h>
#include <linux/ptp_classify.h>
#include <linux/crash_dump.h>
+#include <linux/thermal.h>
#include <asm/io.h>
#include "t4_chip_type.h"
#include "cxgb4_uld.h"
@@ -533,6 +534,13 @@ enum {
};
enum {
+ MAX_TXQ_DESC_SIZE = 64,
+ MAX_RXQ_DESC_SIZE = 128,
+ MAX_FL_DESC_SIZE = 8,
+ MAX_CTRL_TXQ_DESC_SIZE = 64,
+};
+
+enum {
INGQ_EXTRAS = 2, /* firmware event queue and */
/* forwarded interrupts */
MAX_INGQ = MAX_ETH_QSETS + INGQ_EXTRAS,
@@ -685,6 +693,7 @@ struct sge_eth_stats { /* Ethernet queue statistics */
unsigned long rx_cso; /* # of Rx checksum offloads */
unsigned long vlan_ex; /* # of Rx VLAN extractions */
unsigned long rx_drops; /* # of packets dropped due to no mem */
+ unsigned long bad_rx_pkts; /* # of packets with err_vec!=0 */
};
struct sge_eth_rxq { /* SW Ethernet Rx queue */
@@ -882,6 +891,14 @@ struct mps_encap_entry {
atomic_t refcnt;
};
+#if IS_ENABLED(CONFIG_THERMAL)
+struct ch_thermal {
+ struct thermal_zone_device *tzdev;
+ int trip_temp;
+ int trip_type;
+};
+#endif
+
struct adapter {
void __iomem *regs;
void __iomem *bar2;
@@ -1000,6 +1017,9 @@ struct adapter {
/* Dump buffer for collecting logs in kdump kernel */
struct vmcoredd_data vmcoredd;
+#if IS_ENABLED(CONFIG_THERMAL)
+ struct ch_thermal ch_thermal;
+#endif
};
/* Support for "sched-class" command to allow a TX Scheduling Class to be
@@ -1854,4 +1874,8 @@ void cxgb4_ring_tx_db(struct adapter *adap, struct sge_txq *q, int n);
int t4_set_vlan_acl(struct adapter *adap, unsigned int mbox, unsigned int vf,
u16 vlan);
int cxgb4_dcb_enabled(const struct net_device *dev);
+
+int cxgb4_thermal_init(struct adapter *adap);
+int cxgb4_thermal_remove(struct adapter *adap);
+
#endif /* __CXGB4_H__ */
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
index 5f01c0a7fd98..972f0a124714 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
@@ -30,6 +30,7 @@ static const struct cxgb4_collect_entity cxgb4_collect_mem_dump[] = {
static const struct cxgb4_collect_entity cxgb4_collect_hw_dump[] = {
{ CUDBG_MBOX_LOG, cudbg_collect_mbox_log },
+ { CUDBG_QDESC, cudbg_collect_qdesc },
{ CUDBG_DEV_LOG, cudbg_collect_fw_devlog },
{ CUDBG_REG_DUMP, cudbg_collect_reg_dump },
{ CUDBG_CIM_LA, cudbg_collect_cim_la },
@@ -311,6 +312,9 @@ static u32 cxgb4_get_entity_length(struct adapter *adap, u32 entity)
}
len = cudbg_mbytes_to_bytes(len);
break;
+ case CUDBG_QDESC:
+ cudbg_fill_qdesc_num_and_size(adap, NULL, &len);
+ break;
default:
break;
}
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c
index b34f0f077a31..9bd5f755a0e0 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c
@@ -114,6 +114,24 @@ void cxgb4_dcb_reset(struct net_device *dev)
cxgb4_dcb_state_init(dev);
}
+/* update the dcb port support, if version is IEEE then set it to
+ * FW_PORT_DCB_VER_IEEE and if DCB_CAP_DCBX_VER_CEE is already set then
+ * clear that. and if it is set to CEE then set dcb supported to
+ * DCB_CAP_DCBX_VER_CEE & if DCB_CAP_DCBX_VER_IEEE is set, clear it
+ */
+static inline void cxgb4_dcb_update_support(struct port_dcb_info *dcb)
+{
+ if (dcb->dcb_version == FW_PORT_DCB_VER_IEEE) {
+ if (dcb->supported & DCB_CAP_DCBX_VER_CEE)
+ dcb->supported &= ~DCB_CAP_DCBX_VER_CEE;
+ dcb->supported |= DCB_CAP_DCBX_VER_IEEE;
+ } else if (dcb->dcb_version == FW_PORT_DCB_VER_CEE1D01) {
+ if (dcb->supported & DCB_CAP_DCBX_VER_IEEE)
+ dcb->supported &= ~DCB_CAP_DCBX_VER_IEEE;
+ dcb->supported |= DCB_CAP_DCBX_VER_CEE;
+ }
+}
+
/* Finite State machine for Data Center Bridging.
*/
void cxgb4_dcb_state_fsm(struct net_device *dev,
@@ -165,6 +183,15 @@ void cxgb4_dcb_state_fsm(struct net_device *dev,
}
case CXGB4_DCB_STATE_FW_INCOMPLETE: {
+ if (transition_to != CXGB4_DCB_INPUT_FW_DISABLED) {
+ /* during this CXGB4_DCB_STATE_FW_INCOMPLETE state,
+ * check if the dcb version is changed (there can be
+ * mismatch in default config & the negotiated switch
+ * configuration at FW, so update the dcb support
+ * accordingly.
+ */
+ cxgb4_dcb_update_support(dcb);
+ }
switch (transition_to) {
case CXGB4_DCB_INPUT_FW_ENABLED: {
/* we're alreaady in firmware DCB mode */
@@ -273,8 +300,8 @@ void cxgb4_dcb_handle_fw_update(struct adapter *adap,
enum cxgb4_dcb_state_input input =
((pcmd->u.dcb.control.all_syncd_pkd &
FW_PORT_CMD_ALL_SYNCD_F)
- ? CXGB4_DCB_STATE_FW_ALLSYNCED
- : CXGB4_DCB_STATE_FW_INCOMPLETE);
+ ? CXGB4_DCB_INPUT_FW_ALLSYNCED
+ : CXGB4_DCB_INPUT_FW_INCOMPLETE);
if (dcb->dcb_version != FW_PORT_DCB_VER_UNKNOWN) {
dcb_running_version = FW_PORT_CMD_DCB_VERSION_G(
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h
index 02040b99c78a..484ee8290090 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h
@@ -67,7 +67,7 @@
do { \
if ((__dcb)->dcb_version == FW_PORT_DCB_VER_IEEE) \
cxgb4_dcb_state_fsm((__dev), \
- CXGB4_DCB_STATE_FW_ALLSYNCED); \
+ CXGB4_DCB_INPUT_FW_ALLSYNCED); \
} while (0)
/* States we can be in for a port's Data Center Bridging.
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
index 0f72f9c4ec74..cab492ec8f59 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
@@ -2784,6 +2784,7 @@ do { \
RL("LROmerged:", stats.lro_merged);
RL("LROpackets:", stats.lro_pkts);
RL("RxDrops:", stats.rx_drops);
+ RL("RxBadPkts:", stats.bad_rx_pkts);
TL("TSO:", tso);
TL("TxCSO:", tx_cso);
TL("VLANins:", vlan_ins);
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index 961e3087d1d3..05a46926016a 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -62,7 +62,6 @@
#include <net/netevent.h>
#include <net/addrconf.h>
#include <net/bonding.h>
-#include <net/addrconf.h>
#include <linux/uaccess.h>
#include <linux/crash_dump.h>
#include <net/udp_tunnel.h>
@@ -2749,6 +2748,27 @@ static int cxgb4_mgmt_set_vf_rate(struct net_device *dev, int vf,
return -EINVAL;
}
+ if (max_tx_rate == 0) {
+ /* unbind VF to to any Traffic Class */
+ fw_pfvf =
+ (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_PFVF) |
+ FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_PFVF_SCHEDCLASS_ETH));
+ fw_class = 0xffffffff;
+ ret = t4_set_params(adap, adap->mbox, adap->pf, vf + 1, 1,
+ &fw_pfvf, &fw_class);
+ if (ret) {
+ dev_err(adap->pdev_dev,
+ "Err %d in unbinding PF %d VF %d from TX Rate Limiting\n",
+ ret, adap->pf, vf);
+ return -EINVAL;
+ }
+ dev_info(adap->pdev_dev,
+ "PF %d VF %d is unbound from TX Rate Limiting\n",
+ adap->pf, vf);
+ adap->vfinfo[vf].tx_rate = 0;
+ return 0;
+ }
+
ret = t4_get_link_params(pi, &link_ok, &speed, &mtu);
if (ret != FW_SUCCESS) {
dev_err(adap->pdev_dev,
@@ -2798,8 +2818,8 @@ static int cxgb4_mgmt_set_vf_rate(struct net_device *dev, int vf,
&fw_class);
if (ret) {
dev_err(adap->pdev_dev,
- "Err %d in binding VF %d to Traffic Class %d\n",
- ret, vf, class_id);
+ "Err %d in binding PF %d VF %d to Traffic Class %d\n",
+ ret, adap->pf, vf, class_id);
return -EINVAL;
}
dev_info(adap->pdev_dev, "PF %d VF %d is bound to Class %d\n",
@@ -4747,7 +4767,6 @@ static pci_ers_result_t eeh_slot_reset(struct pci_dev *pdev)
pci_set_master(pdev);
pci_restore_state(pdev);
pci_save_state(pdev);
- pci_cleanup_aer_uncorrect_error_status(pdev);
if (t4_wait_dev_ready(adap->regs) < 0)
return PCI_ERS_RESULT_DISCONNECT;
@@ -5844,6 +5863,10 @@ fw_attach_fail:
if (!is_t4(adapter->params.chip))
cxgb4_ptp_init(adapter);
+ if (IS_ENABLED(CONFIG_THERMAL) &&
+ !is_t4(adapter->params.chip) && (adapter->flags & FW_OK))
+ cxgb4_thermal_init(adapter);
+
print_adapter_info(adapter);
return 0;
@@ -5909,6 +5932,8 @@ static void remove_one(struct pci_dev *pdev)
if (!is_t4(adapter->params.chip))
cxgb4_ptp_stop(adapter);
+ if (IS_ENABLED(CONFIG_THERMAL))
+ cxgb4_thermal_remove(adapter);
/* If we allocated filters, free up state associated with any
* valid filters ...
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_thermal.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_thermal.c
new file mode 100644
index 000000000000..28052e7504e5
--- /dev/null
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_thermal.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2017 Chelsio Communications. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Written by: Ganesh Goudar (ganeshgr@chelsio.com)
+ */
+
+#include "cxgb4.h"
+
+#define CXGB4_NUM_TRIPS 1
+
+static int cxgb4_thermal_get_temp(struct thermal_zone_device *tzdev,
+ int *temp)
+{
+ struct adapter *adap = tzdev->devdata;
+ u32 param, val;
+ int ret;
+
+ param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
+ FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_DIAG) |
+ FW_PARAMS_PARAM_Y_V(FW_PARAM_DEV_DIAG_TMP));
+
+ ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1,
+ &param, &val);
+ if (ret < 0 || val == 0)
+ return -1;
+
+ *temp = val * 1000;
+ return 0;
+}
+
+static int cxgb4_thermal_get_trip_type(struct thermal_zone_device *tzdev,
+ int trip, enum thermal_trip_type *type)
+{
+ struct adapter *adap = tzdev->devdata;
+
+ if (!adap->ch_thermal.trip_temp)
+ return -EINVAL;
+
+ *type = adap->ch_thermal.trip_type;
+ return 0;
+}
+
+static int cxgb4_thermal_get_trip_temp(struct thermal_zone_device *tzdev,
+ int trip, int *temp)
+{
+ struct adapter *adap = tzdev->devdata;
+
+ if (!adap->ch_thermal.trip_temp)
+ return -EINVAL;
+
+ *temp = adap->ch_thermal.trip_temp;
+ return 0;
+}
+
+static struct thermal_zone_device_ops cxgb4_thermal_ops = {
+ .get_temp = cxgb4_thermal_get_temp,
+ .get_trip_type = cxgb4_thermal_get_trip_type,
+ .get_trip_temp = cxgb4_thermal_get_trip_temp,
+};
+
+int cxgb4_thermal_init(struct adapter *adap)
+{
+ struct ch_thermal *ch_thermal = &adap->ch_thermal;
+ int num_trip = CXGB4_NUM_TRIPS;
+ u32 param, val;
+ int ret;
+
+ /* on older firmwares we may not get the trip temperature,
+ * set the num of trips to 0.
+ */
+ param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
+ FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_DIAG) |
+ FW_PARAMS_PARAM_Y_V(FW_PARAM_DEV_DIAG_MAXTMPTHRESH));
+
+ ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1,
+ &param, &val);
+ if (ret < 0) {
+ num_trip = 0; /* could not get trip temperature */
+ } else {
+ ch_thermal->trip_temp = val * 1000;
+ ch_thermal->trip_type = THERMAL_TRIP_CRITICAL;
+ }
+
+ ch_thermal->tzdev = thermal_zone_device_register("cxgb4", num_trip,
+ 0, adap,
+ &cxgb4_thermal_ops,
+ NULL, 0, 0);
+ if (IS_ERR(ch_thermal->tzdev)) {
+ ret = PTR_ERR(ch_thermal->tzdev);
+ dev_err(adap->pdev_dev, "Failed to register thermal zone\n");
+ ch_thermal->tzdev = NULL;
+ return ret;
+ }
+ return 0;
+}
+
+int cxgb4_thermal_remove(struct adapter *adap)
+{
+ if (adap->ch_thermal.tzdev)
+ thermal_zone_device_unregister(adap->ch_thermal.tzdev);
+ return 0;
+}
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c
index 4bc211093c98..9a6065a3fa46 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c
@@ -520,10 +520,20 @@ setup_sge_txq_uld(struct adapter *adap, unsigned int uld_type,
txq_info = kzalloc(sizeof(*txq_info), GFP_KERNEL);
if (!txq_info)
return -ENOMEM;
+ if (uld_type == CXGB4_ULD_CRYPTO) {
+ i = min_t(int, adap->vres.ncrypto_fc,
+ num_online_cpus());
+ txq_info->ntxq = rounddown(i, adap->params.nports);
+ if (txq_info->ntxq <= 0) {
+ dev_warn(adap->pdev_dev, "Crypto Tx Queues can't be zero\n");
+ kfree(txq_info);
+ return -EINVAL;
+ }
- i = min_t(int, uld_info->ntxq, num_online_cpus());
- txq_info->ntxq = roundup(i, adap->params.nports);
-
+ } else {
+ i = min_t(int, uld_info->ntxq, num_online_cpus());
+ txq_info->ntxq = roundup(i, adap->params.nports);
+ }
txq_info->uldtxq = kcalloc(txq_info->ntxq, sizeof(struct sge_uld_txq),
GFP_KERNEL);
if (!txq_info->uldtxq) {
@@ -546,11 +556,14 @@ static void uld_queue_init(struct adapter *adap, unsigned int uld_type,
struct cxgb4_lld_info *lli)
{
struct sge_uld_rxq_info *rxq_info = adap->sge.uld_rxq_info[uld_type];
+ int tx_uld_type = TX_ULD(uld_type);
+ struct sge_uld_txq_info *txq_info = adap->sge.uld_txq_info[tx_uld_type];
lli->rxq_ids = rxq_info->rspq_id;
lli->nrxq = rxq_info->nrxq;
lli->ciq_ids = rxq_info->rspq_id + rxq_info->nrxq;
lli->nciq = rxq_info->nciq;
+ lli->ntxq = txq_info->ntxq;
}
int t4_uld_mem_alloc(struct adapter *adap)
@@ -634,7 +647,6 @@ static void uld_init(struct adapter *adap, struct cxgb4_lld_info *lld)
lld->ports = adap->port;
lld->vr = &adap->vres;
lld->mtus = adap->params.mtus;
- lld->ntxq = adap->sge.ofldqsets;
lld->nchan = adap->params.nports;
lld->nports = adap->params.nports;
lld->wr_cred = adap->params.ofldq_wr_cred;
@@ -702,15 +714,14 @@ static void uld_attach(struct adapter *adap, unsigned int uld)
* about any presently available devices that support its type. Returns
* %-EBUSY if a ULD of the same type is already registered.
*/
-int cxgb4_register_uld(enum cxgb4_uld type,
- const struct cxgb4_uld_info *p)
+void cxgb4_register_uld(enum cxgb4_uld type,
+ const struct cxgb4_uld_info *p)
{
int ret = 0;
- unsigned int adap_idx = 0;
struct adapter *adap;
if (type >= CXGB4_ULD_MAX)
- return -EINVAL;
+ return;
mutex_lock(&uld_mutex);
list_for_each_entry(adap, &adapter_list, list_node) {
@@ -733,52 +744,29 @@ int cxgb4_register_uld(enum cxgb4_uld type,
}
if (adap->flags & FULL_INIT_DONE)
enable_rx_uld(adap, type);
- if (adap->uld[type].add) {
- ret = -EBUSY;
+ if (adap->uld[type].add)
goto free_irq;
- }
ret = setup_sge_txq_uld(adap, type, p);
if (ret)
goto free_irq;
adap->uld[type] = *p;
uld_attach(adap, type);
- adap_idx++;
- }
- mutex_unlock(&uld_mutex);
- return 0;
-
+ continue;
free_irq:
- if (adap->flags & FULL_INIT_DONE)
- quiesce_rx_uld(adap, type);
- if (adap->flags & USING_MSIX)
- free_msix_queue_irqs_uld(adap, type);
-free_rxq:
- free_sge_queues_uld(adap, type);
-free_queues:
- free_queues_uld(adap, type);
-out:
-
- list_for_each_entry(adap, &adapter_list, list_node) {
- if ((type == CXGB4_ULD_CRYPTO && !is_pci_uld(adap)) ||
- (type != CXGB4_ULD_CRYPTO && !is_offload(adap)))
- continue;
- if (type == CXGB4_ULD_ISCSIT && is_t4(adap->params.chip))
- continue;
- if (!adap_idx)
- break;
- adap->uld[type].handle = NULL;
- adap->uld[type].add = NULL;
- release_sge_txq_uld(adap, type);
if (adap->flags & FULL_INIT_DONE)
quiesce_rx_uld(adap, type);
if (adap->flags & USING_MSIX)
free_msix_queue_irqs_uld(adap, type);
+free_rxq:
free_sge_queues_uld(adap, type);
+free_queues:
free_queues_uld(adap, type);
- adap_idx--;
+out:
+ dev_warn(adap->pdev_dev,
+ "ULD registration failed for uld type %d\n", type);
}
mutex_unlock(&uld_mutex);
- return ret;
+ return;
}
EXPORT_SYMBOL(cxgb4_register_uld);
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
index de9ad311dacd..5fa9a2d5fc4b 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
@@ -384,7 +384,7 @@ struct cxgb4_uld_info {
int (*tx_handler)(struct sk_buff *skb, struct net_device *dev);
};
-int cxgb4_register_uld(enum cxgb4_uld type, const struct cxgb4_uld_info *p);
+void cxgb4_register_uld(enum cxgb4_uld type, const struct cxgb4_uld_info *p);
int cxgb4_unregister_uld(enum cxgb4_uld type);
int cxgb4_ofld_send(struct net_device *dev, struct sk_buff *skb);
int cxgb4_immdata_send(struct net_device *dev, unsigned int idx,
diff --git a/drivers/net/ethernet/chelsio/cxgb4/l2t.c b/drivers/net/ethernet/chelsio/cxgb4/l2t.c
index 301c4df8a566..99022c0898b5 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/l2t.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/l2t.c
@@ -433,10 +433,12 @@ struct l2t_entry *cxgb4_l2t_get(struct l2t_data *d, struct neighbour *neigh,
else
lport = netdev2pinfo(physdev)->lport;
- if (is_vlan_dev(neigh->dev))
+ if (is_vlan_dev(neigh->dev)) {
vlan = vlan_dev_vlan_id(neigh->dev);
- else
+ vlan |= vlan_dev_get_egress_qos_mask(neigh->dev, priority);
+ } else {
vlan = VLAN_NONE;
+ }
write_lock_bh(&d->lock);
for (e = d->l2tab[hash].first; e; e = e->next)
diff --git a/drivers/net/ethernet/chelsio/cxgb4/sched.c b/drivers/net/ethernet/chelsio/cxgb4/sched.c
index 7fc656680299..52edb688942b 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/sched.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/sched.c
@@ -38,7 +38,6 @@
#include "cxgb4.h"
#include "sched.h"
-/* Spinlock must be held by caller */
static int t4_sched_class_fw_cmd(struct port_info *pi,
struct ch_sched_params *p,
enum sched_fw_ops op)
@@ -67,7 +66,6 @@ static int t4_sched_class_fw_cmd(struct port_info *pi,
return err;
}
-/* Spinlock must be held by caller */
static int t4_sched_bind_unbind_op(struct port_info *pi, void *arg,
enum sched_bind_type type, bool bind)
{
@@ -163,7 +161,6 @@ static int t4_sched_queue_unbind(struct port_info *pi, struct ch_sched_queue *p)
if (e && index >= 0) {
int i = 0;
- spin_lock(&e->lock);
list_for_each_entry(qe, &e->queue_list, list) {
if (i == index)
break;
@@ -171,10 +168,8 @@ static int t4_sched_queue_unbind(struct port_info *pi, struct ch_sched_queue *p)
}
err = t4_sched_bind_unbind_op(pi, (void *)qe, SCHED_QUEUE,
false);
- if (err) {
- spin_unlock(&e->lock);
- goto out;
- }
+ if (err)
+ return err;
list_del(&qe->list);
kvfree(qe);
@@ -182,9 +177,7 @@ static int t4_sched_queue_unbind(struct port_info *pi, struct ch_sched_queue *p)
e->state = SCHED_STATE_UNUSED;
memset(&e->info, 0, sizeof(e->info));
}
- spin_unlock(&e->lock);
}
-out:
return err;
}
@@ -210,10 +203,8 @@ static int t4_sched_queue_bind(struct port_info *pi, struct ch_sched_queue *p)
/* Unbind queue from any existing class */
err = t4_sched_queue_unbind(pi, p);
- if (err) {
- kvfree(qe);
- goto out;
- }
+ if (err)
+ goto out_err;
/* Bind queue to specified class */
memset(qe, 0, sizeof(*qe));
@@ -221,18 +212,16 @@ static int t4_sched_queue_bind(struct port_info *pi, struct ch_sched_queue *p)
memcpy(&qe->param, p, sizeof(qe->param));
e = &s->tab[qe->param.class];
- spin_lock(&e->lock);
err = t4_sched_bind_unbind_op(pi, (void *)qe, SCHED_QUEUE, true);
- if (err) {
- kvfree(qe);
- spin_unlock(&e->lock);
- goto out;
- }
+ if (err)
+ goto out_err;
list_add_tail(&qe->list, &e->queue_list);
atomic_inc(&e->refcnt);
- spin_unlock(&e->lock);
-out:
+ return err;
+
+out_err:
+ kvfree(qe);
return err;
}
@@ -296,8 +285,6 @@ int cxgb4_sched_class_bind(struct net_device *dev, void *arg,
enum sched_bind_type type)
{
struct port_info *pi = netdev2pinfo(dev);
- struct sched_table *s;
- int err = 0;
u8 class_id;
if (!can_sched(dev))
@@ -323,12 +310,8 @@ int cxgb4_sched_class_bind(struct net_device *dev, void *arg,
if (class_id == SCHED_CLS_NONE)
return -ENOTSUPP;
- s = pi->sched_tbl;
- write_lock(&s->rw_lock);
- err = t4_sched_class_bind_unbind_op(pi, arg, type, true);
- write_unlock(&s->rw_lock);
+ return t4_sched_class_bind_unbind_op(pi, arg, type, true);
- return err;
}
/**
@@ -343,8 +326,6 @@ int cxgb4_sched_class_unbind(struct net_device *dev, void *arg,
enum sched_bind_type type)
{
struct port_info *pi = netdev2pinfo(dev);
- struct sched_table *s;
- int err = 0;
u8 class_id;
if (!can_sched(dev))
@@ -367,12 +348,7 @@ int cxgb4_sched_class_unbind(struct net_device *dev, void *arg,
if (!valid_class_id(dev, class_id))
return -EINVAL;
- s = pi->sched_tbl;
- write_lock(&s->rw_lock);
- err = t4_sched_class_bind_unbind_op(pi, arg, type, false);
- write_unlock(&s->rw_lock);
-
- return err;
+ return t4_sched_class_bind_unbind_op(pi, arg, type, false);
}
/* If @p is NULL, fetch any available unused class */
@@ -425,7 +401,6 @@ static struct sched_class *t4_sched_class_lookup(struct port_info *pi,
static struct sched_class *t4_sched_class_alloc(struct port_info *pi,
struct ch_sched_params *p)
{
- struct sched_table *s = pi->sched_tbl;
struct sched_class *e;
u8 class_id;
int err;
@@ -441,7 +416,6 @@ static struct sched_class *t4_sched_class_alloc(struct port_info *pi,
if (class_id != SCHED_CLS_NONE)
return NULL;
- write_lock(&s->rw_lock);
/* See if there's an exisiting class with same
* requested sched params
*/
@@ -452,27 +426,19 @@ static struct sched_class *t4_sched_class_alloc(struct port_info *pi,
/* Fetch any available unused class */
e = t4_sched_class_lookup(pi, NULL);
if (!e)
- goto out;
+ return NULL;
memcpy(&np, p, sizeof(np));
np.u.params.class = e->idx;
-
- spin_lock(&e->lock);
/* New class */
err = t4_sched_class_fw_cmd(pi, &np, SCHED_FW_OP_ADD);
- if (err) {
- spin_unlock(&e->lock);
- e = NULL;
- goto out;
- }
+ if (err)
+ return NULL;
memcpy(&e->info, &np, sizeof(e->info));
atomic_set(&e->refcnt, 0);
e->state = SCHED_STATE_ACTIVE;
- spin_unlock(&e->lock);
}
-out:
- write_unlock(&s->rw_lock);
return e;
}
@@ -517,14 +483,12 @@ struct sched_table *t4_init_sched(unsigned int sched_size)
return NULL;
s->sched_size = sched_size;
- rwlock_init(&s->rw_lock);
for (i = 0; i < s->sched_size; i++) {
memset(&s->tab[i], 0, sizeof(struct sched_class));
s->tab[i].idx = i;
s->tab[i].state = SCHED_STATE_UNUSED;
INIT_LIST_HEAD(&s->tab[i].queue_list);
- spin_lock_init(&s->tab[i].lock);
atomic_set(&s->tab[i].refcnt, 0);
}
return s;
@@ -545,11 +509,9 @@ void t4_cleanup_sched(struct adapter *adap)
for (i = 0; i < s->sched_size; i++) {
struct sched_class *e;
- write_lock(&s->rw_lock);
e = &s->tab[i];
if (e->state == SCHED_STATE_ACTIVE)
t4_sched_class_free(pi, e);
- write_unlock(&s->rw_lock);
}
kvfree(s);
}
diff --git a/drivers/net/ethernet/chelsio/cxgb4/sched.h b/drivers/net/ethernet/chelsio/cxgb4/sched.h
index 3a49e00a38a1..168fb4ce3759 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/sched.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/sched.h
@@ -69,13 +69,11 @@ struct sched_class {
u8 idx;
struct ch_sched_params info;
struct list_head queue_list;
- spinlock_t lock; /* Per class lock */
atomic_t refcnt;
};
struct sched_table { /* per port scheduling table */
u8 sched_size;
- rwlock_t rw_lock; /* Table lock */
struct sched_class tab[0];
};
diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c
index 6807bc3a44fb..b90188401d4a 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c
@@ -2830,6 +2830,10 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp,
csum_ok = pkt->csum_calc && !err_vec &&
(q->netdev->features & NETIF_F_RXCSUM);
+
+ if (err_vec)
+ rxq->stats.bad_rx_pkts++;
+
if (((pkt->l2info & htonl(RXF_TCP_F)) ||
tnl_hdr_len) &&
(q->netdev->features & NETIF_F_GRO) && csum_ok && !pkt->ip_frag) {
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
index 5fe5d16dee72..cb523949c812 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
@@ -3889,7 +3889,7 @@ int t4_fwcache(struct adapter *adap, enum fw_params_param_dev_fwcache op)
c.param[0].mnem =
cpu_to_be32(FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_FWCACHE));
- c.param[0].val = (__force __be32)op;
+ c.param[0].val = cpu_to_be32(op);
return t4_wr_mbox(adap, adap->mbox, &c, sizeof(c), NULL);
}
@@ -4204,6 +4204,7 @@ int t4_link_l1cfg_core(struct adapter *adapter, unsigned int mbox,
*/
int t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port)
{
+ unsigned int fw_caps = adap->params.fw_caps_support;
struct fw_port_cmd c;
memset(&c, 0, sizeof(c));
@@ -4211,9 +4212,14 @@ int t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port)
FW_CMD_REQUEST_F | FW_CMD_EXEC_F |
FW_PORT_CMD_PORTID_V(port));
c.action_to_len16 =
- cpu_to_be32(FW_PORT_CMD_ACTION_V(FW_PORT_ACTION_L1_CFG) |
+ cpu_to_be32(FW_PORT_CMD_ACTION_V(fw_caps == FW_CAPS16
+ ? FW_PORT_ACTION_L1_CFG
+ : FW_PORT_ACTION_L1_CFG32) |
FW_LEN16(c));
- c.u.l1cfg.rcap = cpu_to_be32(FW_PORT_CAP32_ANEG);
+ if (fw_caps == FW_CAPS16)
+ c.u.l1cfg.rcap = cpu_to_be32(FW_PORT_CAP_ANEG);
+ else
+ c.u.l1cfg32.rcap32 = cpu_to_be32(FW_PORT_CAP32_ANEG);
return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
}
@@ -10209,7 +10215,9 @@ int t4_set_vlan_acl(struct adapter *adap, unsigned int mbox, unsigned int vf,
FW_ACL_VLAN_CMD_VFN_V(vf));
vlan_cmd.en_to_len16 = cpu_to_be32(enable | FW_LEN16(vlan_cmd));
/* Drop all packets that donot match vlan id */
- vlan_cmd.dropnovlan_fm = FW_ACL_VLAN_CMD_FM_F;
+ vlan_cmd.dropnovlan_fm = (enable
+ ? (FW_ACL_VLAN_CMD_DROPNOVLAN_F |
+ FW_ACL_VLAN_CMD_FM_F) : 0);
if (enable != 0) {
vlan_cmd.nvlan = 1;
vlan_cmd.vlanid[0] = cpu_to_be16(vlan);
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
index 5dc6c4154af8..57584ab32043 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
@@ -1332,6 +1332,7 @@ enum fw_params_param_dev_phyfw {
enum fw_params_param_dev_diag {
FW_PARAM_DEV_DIAG_TMP = 0x00,
FW_PARAM_DEV_DIAG_VDD = 0x01,
+ FW_PARAM_DEV_DIAG_MAXTMPTHRESH = 0x02,
};
enum fw_params_param_dev_fwcache {
@@ -2464,6 +2465,7 @@ struct fw_acl_vlan_cmd {
#define FW_ACL_VLAN_CMD_DROPNOVLAN_S 7
#define FW_ACL_VLAN_CMD_DROPNOVLAN_V(x) ((x) << FW_ACL_VLAN_CMD_DROPNOVLAN_S)
+#define FW_ACL_VLAN_CMD_DROPNOVLAN_F FW_ACL_VLAN_CMD_DROPNOVLAN_V(1U)
#define FW_ACL_VLAN_CMD_FM_S 6
#define FW_ACL_VLAN_CMD_FM_M 0x1
diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c
index 1c9ad3630c77..ceec467f590d 100644
--- a/drivers/net/ethernet/cortina/gemini.c
+++ b/drivers/net/ethernet/cortina/gemini.c
@@ -372,9 +372,8 @@ static int gmac_setup_phy(struct net_device *netdev)
return -ENODEV;
netdev->phydev = phy;
- phy->supported &= PHY_GBIT_FEATURES;
- phy->supported |= SUPPORTED_Asym_Pause | SUPPORTED_Pause;
- phy->advertising = phy->supported;
+ phy_set_max_speed(phy, SPEED_1000);
+ phy_support_asym_pause(phy);
/* set PHY interface type */
switch (phy->interface) {
diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c
index 50222b7b81f3..0a82fcf16d35 100644
--- a/drivers/net/ethernet/davicom/dm9000.c
+++ b/drivers/net/ethernet/davicom/dm9000.c
@@ -1722,8 +1722,7 @@ out:
static int
dm9000_drv_suspend(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct net_device *ndev = platform_get_drvdata(pdev);
+ struct net_device *ndev = dev_get_drvdata(dev);
struct board_info *db;
if (ndev) {
@@ -1745,8 +1744,7 @@ dm9000_drv_suspend(struct device *dev)
static int
dm9000_drv_resume(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct net_device *ndev = platform_get_drvdata(pdev);
+ struct net_device *ndev = dev_get_drvdata(dev);
struct board_info *db = netdev_priv(ndev);
if (ndev) {
diff --git a/drivers/net/ethernet/dnet.c b/drivers/net/ethernet/dnet.c
index 5a847941c46b..79521e27f0d1 100644
--- a/drivers/net/ethernet/dnet.c
+++ b/drivers/net/ethernet/dnet.c
@@ -284,13 +284,11 @@ static int dnet_mii_probe(struct net_device *dev)
/* mask with MAC supported features */
if (bp->capabilities & DNET_HAS_GIGABIT)
- phydev->supported &= PHY_GBIT_FEATURES;
+ phy_set_max_speed(phydev, SPEED_1000);
else
- phydev->supported &= PHY_BASIC_FEATURES;
+ phy_set_max_speed(phydev, SPEED_100);
- phydev->supported |= SUPPORTED_Asym_Pause | SUPPORTED_Pause;
-
- phydev->advertising = phydev->supported;
+ phy_support_asym_pause(phydev);
bp->link = 0;
bp->speed = 0;
diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h
index 58bcee8f0a58..ce041c90adb0 100644
--- a/drivers/net/ethernet/emulex/benet/be.h
+++ b/drivers/net/ethernet/emulex/benet/be.h
@@ -185,6 +185,7 @@ static inline void queue_tail_inc(struct be_queue_info *q)
struct be_eq_obj {
struct be_queue_info q;
+ char desc[32];
struct be_adapter *adapter;
struct napi_struct napi;
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index 74d122616e76..c5ad7a4f4d83 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -3488,11 +3488,9 @@ static int be_msix_register(struct be_adapter *adapter)
int status, i, vec;
for_all_evt_queues(adapter, eqo, i) {
- char irq_name[IFNAMSIZ+4];
-
- snprintf(irq_name, sizeof(irq_name), "%s-q%d", netdev->name, i);
+ sprintf(eqo->desc, "%s-q%d", netdev->name, i);
vec = be_msix_vec_get(adapter, eqo);
- status = request_irq(vec, be_msix, 0, irq_name, eqo);
+ status = request_irq(vec, be_msix, 0, eqo->desc, eqo);
if (status)
goto err_msix;
@@ -4002,8 +4000,6 @@ static int be_enable_vxlan_offloads(struct be_adapter *adapter)
netdev->hw_enc_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
NETIF_F_TSO | NETIF_F_TSO6 |
NETIF_F_GSO_UDP_TUNNEL;
- netdev->hw_features |= NETIF_F_GSO_UDP_TUNNEL;
- netdev->features |= NETIF_F_GSO_UDP_TUNNEL;
dev_info(dev, "Enabled VxLAN offloads for UDP port %d\n",
be16_to_cpu(port));
@@ -4025,8 +4021,6 @@ static void be_disable_vxlan_offloads(struct be_adapter *adapter)
adapter->vxlan_port = 0;
netdev->hw_enc_features = 0;
- netdev->hw_features &= ~(NETIF_F_GSO_UDP_TUNNEL);
- netdev->features &= ~(NETIF_F_GSO_UDP_TUNNEL);
}
static void be_calculate_vf_res(struct be_adapter *adapter, u16 num_vfs,
@@ -5320,6 +5314,7 @@ static void be_netdev_init(struct net_device *netdev)
struct be_adapter *adapter = netdev_priv(netdev);
netdev->hw_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 |
+ NETIF_F_GSO_UDP_TUNNEL |
NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM |
NETIF_F_HW_VLAN_CTAG_TX;
if ((be_if_cap_flags(adapter) & BE_IF_FLAGS_RSS))
@@ -6151,7 +6146,6 @@ static pci_ers_result_t be_eeh_reset(struct pci_dev *pdev)
if (status)
return PCI_ERS_RESULT_DISCONNECT;
- pci_cleanup_aer_uncorrect_error_status(pdev);
be_clear_error(adapter, BE_CLEAR_ALL);
return PCI_ERS_RESULT_RECOVERED;
}
diff --git a/drivers/net/ethernet/ethoc.c b/drivers/net/ethernet/ethoc.c
index 60da0499ad66..0f3e7f21c6fa 100644
--- a/drivers/net/ethernet/ethoc.c
+++ b/drivers/net/ethernet/ethoc.c
@@ -721,10 +721,7 @@ static int ethoc_mdio_probe(struct net_device *dev)
return err;
}
- phy->advertising &= ~(ADVERTISED_1000baseT_Full |
- ADVERTISED_1000baseT_Half);
- phy->supported &= ~(SUPPORTED_1000baseT_Full |
- SUPPORTED_1000baseT_Half);
+ phy_set_max_speed(phy, SPEED_100);
return 0;
}
diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c
index ed6c76d20b45..4d673225ed3e 100644
--- a/drivers/net/ethernet/faraday/ftgmac100.c
+++ b/drivers/net/ethernet/faraday/ftgmac100.c
@@ -712,8 +712,8 @@ static bool ftgmac100_prep_tx_csum(struct sk_buff *skb, u32 *csum_vlan)
return skb_checksum_help(skb) == 0;
}
-static int ftgmac100_hard_start_xmit(struct sk_buff *skb,
- struct net_device *netdev)
+static netdev_tx_t ftgmac100_hard_start_xmit(struct sk_buff *skb,
+ struct net_device *netdev)
{
struct ftgmac100 *priv = netdev_priv(netdev);
struct ftgmac100_txdes *txdes, *first;
@@ -1079,8 +1079,7 @@ static int ftgmac100_mii_probe(struct ftgmac100 *priv, phy_interface_t intf)
/* Indicate that we support PAUSE frames (see comment in
* Documentation/networking/phy.txt)
*/
- phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
- phydev->advertising = phydev->supported;
+ phy_support_asym_pause(phydev);
/* Display what we found */
phy_attached_info(phydev);
@@ -1220,22 +1219,11 @@ static int ftgmac100_set_pauseparam(struct net_device *netdev,
priv->tx_pause = pause->tx_pause;
priv->rx_pause = pause->rx_pause;
- if (phydev) {
- phydev->advertising &= ~ADVERTISED_Pause;
- phydev->advertising &= ~ADVERTISED_Asym_Pause;
+ if (phydev)
+ phy_set_asym_pause(phydev, pause->rx_pause, pause->tx_pause);
- if (pause->rx_pause) {
- phydev->advertising |= ADVERTISED_Pause;
- phydev->advertising |= ADVERTISED_Asym_Pause;
- }
-
- if (pause->tx_pause)
- phydev->advertising ^= ADVERTISED_Asym_Pause;
- }
if (netif_running(netdev)) {
- if (phydev && priv->aneg_pause)
- phy_start_aneg(phydev);
- else
+ if (!(phydev && priv->aneg_pause))
ftgmac100_config_pause(priv);
}
diff --git a/drivers/net/ethernet/faraday/ftmac100.c b/drivers/net/ethernet/faraday/ftmac100.c
index a1197d3adbe0..570caeb8ee9e 100644
--- a/drivers/net/ethernet/faraday/ftmac100.c
+++ b/drivers/net/ethernet/faraday/ftmac100.c
@@ -634,8 +634,8 @@ static void ftmac100_tx_complete(struct ftmac100 *priv)
;
}
-static int ftmac100_xmit(struct ftmac100 *priv, struct sk_buff *skb,
- dma_addr_t map)
+static netdev_tx_t ftmac100_xmit(struct ftmac100 *priv, struct sk_buff *skb,
+ dma_addr_t map)
{
struct net_device *netdev = priv->netdev;
struct ftmac100_txdes *txdes;
@@ -1016,7 +1016,8 @@ static int ftmac100_stop(struct net_device *netdev)
return 0;
}
-static int ftmac100_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev)
+static netdev_tx_t
+ftmac100_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev)
{
struct ftmac100 *priv = netdev_priv(netdev);
dma_addr_t map;
diff --git a/drivers/net/ethernet/freescale/Kconfig b/drivers/net/ethernet/freescale/Kconfig
index a580a3dcbe59..d3a62bc1f1c6 100644
--- a/drivers/net/ethernet/freescale/Kconfig
+++ b/drivers/net/ethernet/freescale/Kconfig
@@ -96,5 +96,6 @@ config GIANFAR
on the 8540.
source "drivers/net/ethernet/freescale/dpaa/Kconfig"
+source "drivers/net/ethernet/freescale/dpaa2/Kconfig"
endif # NET_VENDOR_FREESCALE
diff --git a/drivers/net/ethernet/freescale/Makefile b/drivers/net/ethernet/freescale/Makefile
index 0914a3ea4405..3b4ff08e3841 100644
--- a/drivers/net/ethernet/freescale/Makefile
+++ b/drivers/net/ethernet/freescale/Makefile
@@ -21,3 +21,5 @@ ucc_geth_driver-objs := ucc_geth.o ucc_geth_ethtool.o
obj-$(CONFIG_FSL_FMAN) += fman/
obj-$(CONFIG_FSL_DPAA_ETH) += dpaa/
+
+obj-$(CONFIG_FSL_DPAA2_ETH) += dpaa2/
diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
index 65a22cd9aef2..6e0f47f2c8a3 100644
--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
@@ -1280,7 +1280,7 @@ static int dpaa_bman_release(const struct dpaa_bp *dpaa_bp,
err = bman_release(dpaa_bp->pool, bmb, cnt);
/* Should never occur, address anyway to avoid leaking the buffers */
- if (unlikely(WARN_ON(err)) && dpaa_bp->free_buf_cb)
+ if (WARN_ON(err) && dpaa_bp->free_buf_cb)
while (cnt-- > 0)
dpaa_bp->free_buf_cb(dpaa_bp, &bmb[cnt]);
@@ -1704,10 +1704,8 @@ static struct sk_buff *contig_fd_to_skb(const struct dpaa_priv *priv,
skb = build_skb(vaddr, dpaa_bp->size +
SKB_DATA_ALIGN(sizeof(struct skb_shared_info)));
- if (unlikely(!skb)) {
- WARN_ONCE(1, "Build skb failure on Rx\n");
+ if (WARN_ONCE(!skb, "Build skb failure on Rx\n"))
goto free_buffer;
- }
WARN_ON(fd_off != priv->rx_headroom);
skb_reserve(skb, fd_off);
skb_put(skb, qm_fd_get_length(fd));
@@ -1770,7 +1768,7 @@ static struct sk_buff *sg_fd_to_skb(const struct dpaa_priv *priv,
sz = dpaa_bp->size +
SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
skb = build_skb(sg_vaddr, sz);
- if (WARN_ON(unlikely(!skb)))
+ if (WARN_ON(!skb))
goto free_buffers;
skb->ip_summed = rx_csum_offload(priv, fd);
@@ -2046,7 +2044,8 @@ static inline int dpaa_xmit(struct dpaa_priv *priv,
return 0;
}
-static int dpaa_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
+static netdev_tx_t
+dpaa_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
{
const int queue_mapping = skb_get_queue_mapping(skb);
bool nonlinear = skb_is_nonlinear(skb);
@@ -2493,8 +2492,7 @@ static int dpaa_phy_init(struct net_device *net_dev)
/* Remove any features not supported by the controller */
phy_dev->supported &= mac_dev->if_support;
- phy_dev->supported |= (SUPPORTED_Pause | SUPPORTED_Asym_Pause);
- phy_dev->advertising = phy_dev->supported;
+ phy_support_asym_pause(phy_dev);
mac_dev->phy_dev = phy_dev;
net_dev->phydev = phy_dev;
@@ -2733,8 +2731,6 @@ out_error:
return err;
}
-static const struct of_device_id dpaa_match[];
-
static inline u16 dpaa_get_headroom(struct dpaa_buffer_layout *bl)
{
u16 headroom;
diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c b/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c
index 3184c8f7cdd0..13d6e2272ece 100644
--- a/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c
+++ b/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c
@@ -182,7 +182,6 @@ static int dpaa_set_pauseparam(struct net_device *net_dev,
struct phy_device *phydev;
bool rx_pause, tx_pause;
struct dpaa_priv *priv;
- u32 newadv, oldadv;
int err;
priv = netdev_priv(net_dev);
@@ -194,9 +193,7 @@ static int dpaa_set_pauseparam(struct net_device *net_dev,
return -ENODEV;
}
- if (!(phydev->supported & SUPPORTED_Pause) ||
- (!(phydev->supported & SUPPORTED_Asym_Pause) &&
- (epause->rx_pause != epause->tx_pause)))
+ if (!phy_validate_pause(phydev, epause))
return -EINVAL;
/* The MAC should know how to handle PAUSE frame autonegotiation before
@@ -210,29 +207,8 @@ static int dpaa_set_pauseparam(struct net_device *net_dev,
/* Determine the sym/asym advertised PAUSE capabilities from the desired
* rx/tx pause settings.
*/
- newadv = 0;
- if (epause->rx_pause)
- newadv = ADVERTISED_Pause | ADVERTISED_Asym_Pause;
- if (epause->tx_pause)
- newadv ^= ADVERTISED_Asym_Pause;
- oldadv = phydev->advertising &
- (ADVERTISED_Pause | ADVERTISED_Asym_Pause);
-
- /* If there are differences between the old and the new advertised
- * values, restart PHY autonegotiation and advertise the new values.
- */
- if (oldadv != newadv) {
- phydev->advertising &= ~(ADVERTISED_Pause
- | ADVERTISED_Asym_Pause);
- phydev->advertising |= newadv;
- if (phydev->autoneg) {
- err = phy_start_aneg(phydev);
- if (err < 0)
- netdev_err(net_dev, "phy_start_aneg() = %d\n",
- err);
- }
- }
+ phy_set_asym_pause(phydev, epause->rx_pause, epause->tx_pause);
fman_get_pause_cfg(mac_dev, &rx_pause, &tx_pause);
err = fman_set_mac_active_pause(mac_dev, rx_pause, tx_pause);
diff --git a/drivers/net/ethernet/freescale/dpaa2/Kconfig b/drivers/net/ethernet/freescale/dpaa2/Kconfig
new file mode 100644
index 000000000000..809a155eb193
--- /dev/null
+++ b/drivers/net/ethernet/freescale/dpaa2/Kconfig
@@ -0,0 +1,16 @@
+config FSL_DPAA2_ETH
+ tristate "Freescale DPAA2 Ethernet"
+ depends on FSL_MC_BUS && FSL_MC_DPIO
+ help
+ This is the DPAA2 Ethernet driver supporting Freescale SoCs
+ with DPAA2 (DataPath Acceleration Architecture v2).
+ The driver manages network objects discovered on the Freescale
+ MC bus.
+
+config FSL_DPAA2_PTP_CLOCK
+ tristate "Freescale DPAA2 PTP Clock"
+ depends on FSL_DPAA2_ETH && POSIX_TIMERS
+ select PTP_1588_CLOCK
+ help
+ This driver adds support for using the DPAA2 1588 timer module
+ as a PTP clock.
diff --git a/drivers/net/ethernet/freescale/dpaa2/Makefile b/drivers/net/ethernet/freescale/dpaa2/Makefile
new file mode 100644
index 000000000000..2f424e0a8225
--- /dev/null
+++ b/drivers/net/ethernet/freescale/dpaa2/Makefile
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the Freescale DPAA2 Ethernet controller
+#
+
+obj-$(CONFIG_FSL_DPAA2_ETH) += fsl-dpaa2-eth.o
+obj-$(CONFIG_FSL_DPAA2_PTP_CLOCK) += fsl-dpaa2-ptp.o
+
+fsl-dpaa2-eth-objs := dpaa2-eth.o dpaa2-ethtool.o dpni.o
+fsl-dpaa2-ptp-objs := dpaa2-ptp.o dprtc.o
+
+# Needed by the tracing framework
+CFLAGS_dpaa2-eth.o := -I$(src)
diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth-trace.h b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-trace.h
index 9801528db2a5..9801528db2a5 100644
--- a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth-trace.h
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-trace.h
diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
index 9329fcad95ac..88f7acce38dc 100644
--- a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
@@ -98,8 +98,7 @@ free_buf:
}
/* Build a linear skb based on a single-buffer frame descriptor */
-static struct sk_buff *build_linear_skb(struct dpaa2_eth_priv *priv,
- struct dpaa2_eth_channel *ch,
+static struct sk_buff *build_linear_skb(struct dpaa2_eth_channel *ch,
const struct dpaa2_fd *fd,
void *fd_vaddr)
{
@@ -233,7 +232,7 @@ static void dpaa2_eth_rx(struct dpaa2_eth_priv *priv,
percpu_extras = this_cpu_ptr(priv->percpu_extras);
if (fd_format == dpaa2_fd_single) {
- skb = build_linear_skb(priv, ch, fd, vaddr);
+ skb = build_linear_skb(ch, fd, vaddr);
} else if (fd_format == dpaa2_fd_sg) {
skb = build_frag_skb(priv, ch, buf_data);
skb_free_frag(vaddr);
@@ -289,10 +288,11 @@ err_frame_format:
*
* Observance of NAPI budget is not our concern, leaving that to the caller.
*/
-static int consume_frames(struct dpaa2_eth_channel *ch)
+static int consume_frames(struct dpaa2_eth_channel *ch,
+ enum dpaa2_eth_fq_type *type)
{
struct dpaa2_eth_priv *priv = ch->priv;
- struct dpaa2_eth_fq *fq;
+ struct dpaa2_eth_fq *fq = NULL;
struct dpaa2_dq *dq;
const struct dpaa2_fd *fd;
int cleaned = 0;
@@ -311,12 +311,23 @@ static int consume_frames(struct dpaa2_eth_channel *ch)
fd = dpaa2_dq_fd(dq);
fq = (struct dpaa2_eth_fq *)(uintptr_t)dpaa2_dq_fqd_ctx(dq);
- fq->stats.frames++;
fq->consume(priv, ch, fd, &ch->napi, fq->flowid);
cleaned++;
} while (!is_last);
+ if (!cleaned)
+ return 0;
+
+ fq->stats.frames += cleaned;
+ ch->stats.frames += cleaned;
+
+ /* A dequeue operation only pulls frames from a single queue
+ * into the store. Return the frame queue type as an out param.
+ */
+ if (type)
+ *type = fq->type;
+
return cleaned;
}
@@ -426,7 +437,7 @@ static int build_sg_fd(struct dpaa2_eth_priv *priv,
dpaa2_fd_set_format(fd, dpaa2_fd_sg);
dpaa2_fd_set_addr(fd, addr);
dpaa2_fd_set_len(fd, skb->len);
- dpaa2_fd_set_ctrl(fd, FD_CTRL_PTA | FD_CTRL_PTV1);
+ dpaa2_fd_set_ctrl(fd, FD_CTRL_PTA);
if (priv->tx_tstamp && skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)
enable_tx_tstamp(fd, sgt_buf);
@@ -479,7 +490,7 @@ static int build_single_fd(struct dpaa2_eth_priv *priv,
dpaa2_fd_set_offset(fd, (u16)(skb->data - buffer_start));
dpaa2_fd_set_len(fd, skb->len);
dpaa2_fd_set_format(fd, dpaa2_fd_single);
- dpaa2_fd_set_ctrl(fd, FD_CTRL_PTA | FD_CTRL_PTV1);
+ dpaa2_fd_set_ctrl(fd, FD_CTRL_PTA);
if (priv->tx_tstamp && skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)
enable_tx_tstamp(fd, buffer_start);
@@ -648,7 +659,7 @@ err_alloc_headroom:
/* Tx confirmation frame processing routine */
static void dpaa2_eth_tx_conf(struct dpaa2_eth_priv *priv,
- struct dpaa2_eth_channel *ch,
+ struct dpaa2_eth_channel *ch __always_unused,
const struct dpaa2_fd *fd,
struct napi_struct *napi __always_unused,
u16 queue_id __always_unused)
@@ -921,14 +932,16 @@ static int pull_channel(struct dpaa2_eth_channel *ch)
static int dpaa2_eth_poll(struct napi_struct *napi, int budget)
{
struct dpaa2_eth_channel *ch;
- int cleaned = 0, store_cleaned;
struct dpaa2_eth_priv *priv;
+ int rx_cleaned = 0, txconf_cleaned = 0;
+ enum dpaa2_eth_fq_type type = 0;
+ int store_cleaned;
int err;
ch = container_of(napi, struct dpaa2_eth_channel, napi);
priv = ch->priv;
- while (cleaned < budget) {
+ do {
err = pull_channel(ch);
if (unlikely(err))
break;
@@ -936,30 +949,32 @@ static int dpaa2_eth_poll(struct napi_struct *napi, int budget)
/* Refill pool if appropriate */
refill_pool(priv, ch, priv->bpid);
- store_cleaned = consume_frames(ch);
- cleaned += store_cleaned;
+ store_cleaned = consume_frames(ch, &type);
+ if (type == DPAA2_RX_FQ)
+ rx_cleaned += store_cleaned;
+ else
+ txconf_cleaned += store_cleaned;
- /* If we have enough budget left for a full store,
- * try a new pull dequeue, otherwise we're done here
+ /* If we either consumed the whole NAPI budget with Rx frames
+ * or we reached the Tx confirmations threshold, we're done.
*/
- if (store_cleaned == 0 ||
- cleaned > budget - DPAA2_ETH_STORE_SIZE)
- break;
- }
+ if (rx_cleaned >= budget ||
+ txconf_cleaned >= DPAA2_ETH_TXCONF_PER_NAPI)
+ return budget;
+ } while (store_cleaned);
- if (cleaned < budget && napi_complete_done(napi, cleaned)) {
- /* Re-enable data available notifications */
- do {
- err = dpaa2_io_service_rearm(ch->dpio, &ch->nctx);
- cpu_relax();
- } while (err == -EBUSY);
- WARN_ONCE(err, "CDAN notifications rearm failed on core %d",
- ch->nctx.desired_cpu);
- }
-
- ch->stats.frames += cleaned;
+ /* We didn't consume the entire budget, so finish napi and
+ * re-enable data availability notifications
+ */
+ napi_complete_done(napi, rx_cleaned);
+ do {
+ err = dpaa2_io_service_rearm(ch->dpio, &ch->nctx);
+ cpu_relax();
+ } while (err == -EBUSY);
+ WARN_ONCE(err, "CDAN notifications rearm failed on core %d",
+ ch->nctx.desired_cpu);
- return cleaned;
+ return max(rx_cleaned, 1);
}
static void enable_ch_napi(struct dpaa2_eth_priv *priv)
@@ -986,7 +1001,7 @@ static void disable_ch_napi(struct dpaa2_eth_priv *priv)
static int link_state_update(struct dpaa2_eth_priv *priv)
{
- struct dpni_link_state state;
+ struct dpni_link_state state = {0};
int err;
err = dpni_get_link_state(priv->mc_io, 0, priv->mc_token, &state);
@@ -1069,14 +1084,13 @@ enable_err:
/* The DPIO store must be empty when we call this,
* at the end of every NAPI cycle.
*/
-static u32 drain_channel(struct dpaa2_eth_priv *priv,
- struct dpaa2_eth_channel *ch)
+static u32 drain_channel(struct dpaa2_eth_channel *ch)
{
u32 drained = 0, total = 0;
do {
pull_channel(ch);
- drained = consume_frames(ch);
+ drained = consume_frames(ch, NULL);
total += drained;
} while (drained);
@@ -1091,7 +1105,7 @@ static u32 drain_ingress_frames(struct dpaa2_eth_priv *priv)
for (i = 0; i < priv->num_channels; i++) {
ch = priv->channel[i];
- drained += drain_channel(priv, ch);
+ drained += drain_channel(ch);
}
return drained;
@@ -1100,7 +1114,7 @@ static u32 drain_ingress_frames(struct dpaa2_eth_priv *priv)
static int dpaa2_eth_stop(struct net_device *net_dev)
{
struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
- int dpni_enabled;
+ int dpni_enabled = 0;
int retries = 10;
u32 drained;
@@ -1143,34 +1157,6 @@ static int dpaa2_eth_stop(struct net_device *net_dev)
return 0;
}
-static int dpaa2_eth_init(struct net_device *net_dev)
-{
- u64 supported = 0;
- u64 not_supported = 0;
- struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
- u32 options = priv->dpni_attrs.options;
-
- /* Capabilities listing */
- supported |= IFF_LIVE_ADDR_CHANGE;
-
- if (options & DPNI_OPT_NO_MAC_FILTER)
- not_supported |= IFF_UNICAST_FLT;
- else
- supported |= IFF_UNICAST_FLT;
-
- net_dev->priv_flags |= supported;
- net_dev->priv_flags &= ~not_supported;
-
- /* Features */
- net_dev->features = NETIF_F_RXCSUM |
- NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
- NETIF_F_SG | NETIF_F_HIGHDMA |
- NETIF_F_LLTX;
- net_dev->hw_features = net_dev->features;
-
- return 0;
-}
-
static int dpaa2_eth_set_addr(struct net_device *net_dev, void *addr)
{
struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
@@ -1418,7 +1404,6 @@ static const struct net_device_ops dpaa2_eth_ops = {
.ndo_open = dpaa2_eth_open,
.ndo_start_xmit = dpaa2_eth_tx,
.ndo_stop = dpaa2_eth_stop,
- .ndo_init = dpaa2_eth_init,
.ndo_set_mac_address = dpaa2_eth_set_addr,
.ndo_get_stats64 = dpaa2_eth_get_stats,
.ndo_set_rx_mode = dpaa2_eth_set_rx_mode,
@@ -1926,6 +1911,11 @@ static int setup_dpni(struct fsl_mc_device *ls_dev)
if (err)
goto close;
+ priv->cls_rules = devm_kzalloc(dev, sizeof(struct dpaa2_eth_cls_rule) *
+ dpaa2_eth_fs_count(priv), GFP_KERNEL);
+ if (!priv->cls_rules)
+ goto close;
+
return 0;
close:
@@ -2032,9 +2022,33 @@ static int setup_tx_flow(struct dpaa2_eth_priv *priv,
return 0;
}
-/* Hash key is a 5-tuple: IPsrc, IPdst, IPnextproto, L4src, L4dst */
-static const struct dpaa2_eth_hash_fields hash_fields[] = {
+/* Supported header fields for Rx hash distribution key */
+static const struct dpaa2_eth_dist_fields dist_fields[] = {
{
+ /* L2 header */
+ .rxnfc_field = RXH_L2DA,
+ .cls_prot = NET_PROT_ETH,
+ .cls_field = NH_FLD_ETH_DA,
+ .size = 6,
+ }, {
+ .cls_prot = NET_PROT_ETH,
+ .cls_field = NH_FLD_ETH_SA,
+ .size = 6,
+ }, {
+ /* This is the last ethertype field parsed:
+ * depending on frame format, it can be the MAC ethertype
+ * or the VLAN etype.
+ */
+ .cls_prot = NET_PROT_ETH,
+ .cls_field = NH_FLD_ETH_TYPE,
+ .size = 2,
+ }, {
+ /* VLAN header */
+ .rxnfc_field = RXH_VLAN,
+ .cls_prot = NET_PROT_VLAN,
+ .cls_field = NH_FLD_VLAN_TCI,
+ .size = 2,
+ }, {
/* IP header */
.rxnfc_field = RXH_IP_SRC,
.cls_prot = NET_PROT_IP,
@@ -2066,32 +2080,122 @@ static const struct dpaa2_eth_hash_fields hash_fields[] = {
},
};
-/* Set RX hash options
+/* Configure the Rx hash key using the legacy API */
+static int config_legacy_hash_key(struct dpaa2_eth_priv *priv, dma_addr_t key)
+{
+ struct device *dev = priv->net_dev->dev.parent;
+ struct dpni_rx_tc_dist_cfg dist_cfg;
+ int err;
+
+ memset(&dist_cfg, 0, sizeof(dist_cfg));
+
+ dist_cfg.key_cfg_iova = key;
+ dist_cfg.dist_size = dpaa2_eth_queue_count(priv);
+ dist_cfg.dist_mode = DPNI_DIST_MODE_HASH;
+
+ err = dpni_set_rx_tc_dist(priv->mc_io, 0, priv->mc_token, 0, &dist_cfg);
+ if (err)
+ dev_err(dev, "dpni_set_rx_tc_dist failed\n");
+
+ return err;
+}
+
+/* Configure the Rx hash key using the new API */
+static int config_hash_key(struct dpaa2_eth_priv *priv, dma_addr_t key)
+{
+ struct device *dev = priv->net_dev->dev.parent;
+ struct dpni_rx_dist_cfg dist_cfg;
+ int err;
+
+ memset(&dist_cfg, 0, sizeof(dist_cfg));
+
+ dist_cfg.key_cfg_iova = key;
+ dist_cfg.dist_size = dpaa2_eth_queue_count(priv);
+ dist_cfg.enable = 1;
+
+ err = dpni_set_rx_hash_dist(priv->mc_io, 0, priv->mc_token, &dist_cfg);
+ if (err)
+ dev_err(dev, "dpni_set_rx_hash_dist failed\n");
+
+ return err;
+}
+
+/* Configure the Rx flow classification key */
+static int config_cls_key(struct dpaa2_eth_priv *priv, dma_addr_t key)
+{
+ struct device *dev = priv->net_dev->dev.parent;
+ struct dpni_rx_dist_cfg dist_cfg;
+ int err;
+
+ memset(&dist_cfg, 0, sizeof(dist_cfg));
+
+ dist_cfg.key_cfg_iova = key;
+ dist_cfg.dist_size = dpaa2_eth_queue_count(priv);
+ dist_cfg.enable = 1;
+
+ err = dpni_set_rx_fs_dist(priv->mc_io, 0, priv->mc_token, &dist_cfg);
+ if (err)
+ dev_err(dev, "dpni_set_rx_fs_dist failed\n");
+
+ return err;
+}
+
+/* Size of the Rx flow classification key */
+int dpaa2_eth_cls_key_size(void)
+{
+ int i, size = 0;
+
+ for (i = 0; i < ARRAY_SIZE(dist_fields); i++)
+ size += dist_fields[i].size;
+
+ return size;
+}
+
+/* Offset of header field in Rx classification key */
+int dpaa2_eth_cls_fld_off(int prot, int field)
+{
+ int i, off = 0;
+
+ for (i = 0; i < ARRAY_SIZE(dist_fields); i++) {
+ if (dist_fields[i].cls_prot == prot &&
+ dist_fields[i].cls_field == field)
+ return off;
+ off += dist_fields[i].size;
+ }
+
+ WARN_ONCE(1, "Unsupported header field used for Rx flow cls\n");
+ return 0;
+}
+
+/* Set Rx distribution (hash or flow classification) key
* flags is a combination of RXH_ bits
*/
-static int dpaa2_eth_set_hash(struct net_device *net_dev, u64 flags)
+static int dpaa2_eth_set_dist_key(struct net_device *net_dev,
+ enum dpaa2_eth_rx_dist type, u64 flags)
{
struct device *dev = net_dev->dev.parent;
struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
struct dpkg_profile_cfg cls_cfg;
- struct dpni_rx_tc_dist_cfg dist_cfg;
+ u32 rx_hash_fields = 0;
+ dma_addr_t key_iova;
u8 *dma_mem;
int i;
int err = 0;
- if (!dpaa2_eth_hash_enabled(priv)) {
- dev_dbg(dev, "Hashing support is not enabled\n");
- return 0;
- }
-
memset(&cls_cfg, 0, sizeof(cls_cfg));
- for (i = 0; i < ARRAY_SIZE(hash_fields); i++) {
+ for (i = 0; i < ARRAY_SIZE(dist_fields); i++) {
struct dpkg_extract *key =
&cls_cfg.extracts[cls_cfg.num_extracts];
- if (!(flags & hash_fields[i].rxnfc_field))
- continue;
+ /* For Rx hashing key we set only the selected fields.
+ * For Rx flow classification key we set all supported fields
+ */
+ if (type == DPAA2_ETH_RX_DIST_HASH) {
+ if (!(flags & dist_fields[i].rxnfc_field))
+ continue;
+ rx_hash_fields |= dist_fields[i].rxnfc_field;
+ }
if (cls_cfg.num_extracts >= DPKG_MAX_NUM_OF_EXTRACTS) {
dev_err(dev, "error adding key extraction rule, too many rules?\n");
@@ -2099,12 +2203,10 @@ static int dpaa2_eth_set_hash(struct net_device *net_dev, u64 flags)
}
key->type = DPKG_EXTRACT_FROM_HDR;
- key->extract.from_hdr.prot = hash_fields[i].cls_prot;
+ key->extract.from_hdr.prot = dist_fields[i].cls_prot;
key->extract.from_hdr.type = DPKG_FULL_FIELD;
- key->extract.from_hdr.field = hash_fields[i].cls_field;
+ key->extract.from_hdr.field = dist_fields[i].cls_field;
cls_cfg.num_extracts++;
-
- priv->rx_hash_fields |= hash_fields[i].rxnfc_field;
}
dma_mem = kzalloc(DPAA2_CLASSIFIER_DMA_SIZE, GFP_KERNEL);
@@ -2114,36 +2216,73 @@ static int dpaa2_eth_set_hash(struct net_device *net_dev, u64 flags)
err = dpni_prepare_key_cfg(&cls_cfg, dma_mem);
if (err) {
dev_err(dev, "dpni_prepare_key_cfg error %d\n", err);
- goto err_prep_key;
+ goto free_key;
}
- memset(&dist_cfg, 0, sizeof(dist_cfg));
-
/* Prepare for setting the rx dist */
- dist_cfg.key_cfg_iova = dma_map_single(dev, dma_mem,
- DPAA2_CLASSIFIER_DMA_SIZE,
- DMA_TO_DEVICE);
- if (dma_mapping_error(dev, dist_cfg.key_cfg_iova)) {
+ key_iova = dma_map_single(dev, dma_mem, DPAA2_CLASSIFIER_DMA_SIZE,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, key_iova)) {
dev_err(dev, "DMA mapping failed\n");
err = -ENOMEM;
- goto err_dma_map;
+ goto free_key;
}
- dist_cfg.dist_size = dpaa2_eth_queue_count(priv);
- dist_cfg.dist_mode = DPNI_DIST_MODE_HASH;
+ if (type == DPAA2_ETH_RX_DIST_HASH) {
+ if (dpaa2_eth_has_legacy_dist(priv))
+ err = config_legacy_hash_key(priv, key_iova);
+ else
+ err = config_hash_key(priv, key_iova);
+ } else {
+ err = config_cls_key(priv, key_iova);
+ }
- err = dpni_set_rx_tc_dist(priv->mc_io, 0, priv->mc_token, 0, &dist_cfg);
- dma_unmap_single(dev, dist_cfg.key_cfg_iova,
- DPAA2_CLASSIFIER_DMA_SIZE, DMA_TO_DEVICE);
- if (err)
- dev_err(dev, "dpni_set_rx_tc_dist() error %d\n", err);
+ dma_unmap_single(dev, key_iova, DPAA2_CLASSIFIER_DMA_SIZE,
+ DMA_TO_DEVICE);
+ if (!err && type == DPAA2_ETH_RX_DIST_HASH)
+ priv->rx_hash_fields = rx_hash_fields;
-err_dma_map:
-err_prep_key:
+free_key:
kfree(dma_mem);
return err;
}
+int dpaa2_eth_set_hash(struct net_device *net_dev, u64 flags)
+{
+ struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
+
+ if (!dpaa2_eth_hash_enabled(priv))
+ return -EOPNOTSUPP;
+
+ return dpaa2_eth_set_dist_key(net_dev, DPAA2_ETH_RX_DIST_HASH, flags);
+}
+
+static int dpaa2_eth_set_cls(struct dpaa2_eth_priv *priv)
+{
+ struct device *dev = priv->net_dev->dev.parent;
+
+ /* Check if we actually support Rx flow classification */
+ if (dpaa2_eth_has_legacy_dist(priv)) {
+ dev_dbg(dev, "Rx cls not supported by current MC version\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (priv->dpni_attrs.options & DPNI_OPT_NO_FS ||
+ !(priv->dpni_attrs.options & DPNI_OPT_HAS_KEY_MASKING)) {
+ dev_dbg(dev, "Rx cls disabled in DPNI options\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (!dpaa2_eth_hash_enabled(priv)) {
+ dev_dbg(dev, "Rx cls disabled for single queue DPNIs\n");
+ return -EOPNOTSUPP;
+ }
+
+ priv->rx_cls_enabled = 1;
+
+ return dpaa2_eth_set_dist_key(priv->net_dev, DPAA2_ETH_RX_DIST_CLS, 0);
+}
+
/* Bind the DPNI to its needed objects and resources: buffer pool, DPIOs,
* frame queues and channels
*/
@@ -2170,9 +2309,16 @@ static int bind_dpni(struct dpaa2_eth_priv *priv)
* the default hash key
*/
err = dpaa2_eth_set_hash(net_dev, DPAA2_RXH_DEFAULT);
- if (err)
+ if (err && err != -EOPNOTSUPP)
dev_err(dev, "Failed to configure hashing\n");
+ /* Configure the flow classification key; it includes all
+ * supported header fields and cannot be modified at runtime
+ */
+ err = dpaa2_eth_set_cls(priv);
+ if (err && err != -EOPNOTSUPP)
+ dev_err(dev, "Failed to configure Rx classification key\n");
+
/* Configure handling of error frames */
err_cfg.errors = DPAA2_FAS_RX_ERR_MASK;
err_cfg.set_frame_annotation = 1;
@@ -2316,11 +2462,14 @@ static int netdev_init(struct net_device *net_dev)
{
struct device *dev = net_dev->dev.parent;
struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
+ u32 options = priv->dpni_attrs.options;
+ u64 supported = 0, not_supported = 0;
u8 bcast_addr[ETH_ALEN];
u8 num_queues;
int err;
net_dev->netdev_ops = &dpaa2_eth_ops;
+ net_dev->ethtool_ops = &dpaa2_ethtool_ops;
err = set_mac_addr(priv);
if (err)
@@ -2356,12 +2505,23 @@ static int netdev_init(struct net_device *net_dev)
return err;
}
- /* Our .ndo_init will be called herein */
- err = register_netdev(net_dev);
- if (err < 0) {
- dev_err(dev, "register_netdev() failed\n");
- return err;
- }
+ /* Capabilities listing */
+ supported |= IFF_LIVE_ADDR_CHANGE;
+
+ if (options & DPNI_OPT_NO_MAC_FILTER)
+ not_supported |= IFF_UNICAST_FLT;
+ else
+ supported |= IFF_UNICAST_FLT;
+
+ net_dev->priv_flags |= supported;
+ net_dev->priv_flags &= ~not_supported;
+
+ /* Features */
+ net_dev->features = NETIF_F_RXCSUM |
+ NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+ NETIF_F_SG | NETIF_F_HIGHDMA |
+ NETIF_F_LLTX;
+ net_dev->hw_features = net_dev->features;
return 0;
}
@@ -2561,28 +2721,36 @@ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev)
if (err)
goto err_alloc_rings;
- net_dev->ethtool_ops = &dpaa2_ethtool_ops;
-
err = setup_irqs(dpni_dev);
if (err) {
netdev_warn(net_dev, "Failed to set link interrupt, fall back to polling\n");
priv->poll_thread = kthread_run(poll_link_state, priv,
"%s_poll_link", net_dev->name);
if (IS_ERR(priv->poll_thread)) {
- netdev_err(net_dev, "Error starting polling thread\n");
+ dev_err(dev, "Error starting polling thread\n");
goto err_poll_thread;
}
priv->do_link_poll = true;
}
+ err = register_netdev(net_dev);
+ if (err < 0) {
+ dev_err(dev, "register_netdev() failed\n");
+ goto err_netdev_reg;
+ }
+
dev_info(dev, "Probed interface %s\n", net_dev->name);
return 0;
+err_netdev_reg:
+ if (priv->do_link_poll)
+ kthread_stop(priv->poll_thread);
+ else
+ fsl_mc_free_irqs(dpni_dev);
err_poll_thread:
free_rings(priv);
err_alloc_rings:
err_csum:
- unregister_netdev(net_dev);
err_netdev_init:
free_percpu(priv->percpu_extras);
err_alloc_percpu_extras:
diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
index d54cb0b99d08..452a8e9c4f0e 100644
--- a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
@@ -40,6 +40,11 @@
*/
#define DPAA2_ETH_TAILDROP_THRESH (64 * 1024)
+/* Maximum number of Tx confirmation frames to be processed
+ * in a single NAPI call
+ */
+#define DPAA2_ETH_TXCONF_PER_NAPI 256
+
/* Buffer quota per queue. Must be large enough such that for minimum sized
* frames taildrop kicks in before the bpool gets depleted, so we compute
* how many 64B frames fit inside the taildrop threshold and add a margin
@@ -290,13 +295,18 @@ struct dpaa2_eth_channel {
struct dpaa2_eth_ch_stats stats;
};
-struct dpaa2_eth_hash_fields {
+struct dpaa2_eth_dist_fields {
u64 rxnfc_field;
enum net_prot cls_prot;
int cls_field;
int size;
};
+struct dpaa2_eth_cls_rule {
+ struct ethtool_rx_flow_spec fs;
+ u8 in_use;
+};
+
/* Driver private data */
struct dpaa2_eth_priv {
struct net_device *net_dev;
@@ -340,6 +350,8 @@ struct dpaa2_eth_priv {
/* enabled ethtool hashing bits */
u64 rx_hash_fields;
+ struct dpaa2_eth_cls_rule *cls_rules;
+ u8 rx_cls_enabled;
};
#define DPAA2_RXH_SUPPORTED (RXH_L2DA | RXH_VLAN | RXH_L3_PROTO \
@@ -367,6 +379,24 @@ static inline int dpaa2_eth_cmp_dpni_ver(struct dpaa2_eth_priv *priv,
return priv->dpni_ver_major - ver_major;
}
+/* Minimum firmware version that supports a more flexible API
+ * for configuring the Rx flow hash key
+ */
+#define DPNI_RX_DIST_KEY_VER_MAJOR 7
+#define DPNI_RX_DIST_KEY_VER_MINOR 5
+
+#define dpaa2_eth_has_legacy_dist(priv) \
+ (dpaa2_eth_cmp_dpni_ver((priv), DPNI_RX_DIST_KEY_VER_MAJOR, \
+ DPNI_RX_DIST_KEY_VER_MINOR) < 0)
+
+#define dpaa2_eth_fs_count(priv) \
+ ((priv)->dpni_attrs.fs_entries)
+
+enum dpaa2_eth_rx_dist {
+ DPAA2_ETH_RX_DIST_HASH,
+ DPAA2_ETH_RX_DIST_CLS
+};
+
/* Hardware only sees DPAA2_ETH_RX_BUF_SIZE, but the skb built around
* the buffer also needs space for its shared info struct, and we need
* to allocate enough to accommodate hardware alignment restrictions
@@ -409,4 +439,8 @@ static int dpaa2_eth_queue_count(struct dpaa2_eth_priv *priv)
return priv->dpni_attrs.num_queues;
}
+int dpaa2_eth_set_hash(struct net_device *net_dev, u64 flags);
+int dpaa2_eth_cls_key_size(void);
+int dpaa2_eth_cls_fld_off(int prot, int field);
+
#endif /* __DPAA2_H */
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c
new file mode 100644
index 000000000000..26bd5a2bd8ed
--- /dev/null
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c
@@ -0,0 +1,630 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/* Copyright 2014-2016 Freescale Semiconductor Inc.
+ * Copyright 2016 NXP
+ */
+
+#include <linux/net_tstamp.h>
+
+#include "dpni.h" /* DPNI_LINK_OPT_* */
+#include "dpaa2-eth.h"
+
+/* To be kept in sync with DPNI statistics */
+static char dpaa2_ethtool_stats[][ETH_GSTRING_LEN] = {
+ "[hw] rx frames",
+ "[hw] rx bytes",
+ "[hw] rx mcast frames",
+ "[hw] rx mcast bytes",
+ "[hw] rx bcast frames",
+ "[hw] rx bcast bytes",
+ "[hw] tx frames",
+ "[hw] tx bytes",
+ "[hw] tx mcast frames",
+ "[hw] tx mcast bytes",
+ "[hw] tx bcast frames",
+ "[hw] tx bcast bytes",
+ "[hw] rx filtered frames",
+ "[hw] rx discarded frames",
+ "[hw] rx nobuffer discards",
+ "[hw] tx discarded frames",
+ "[hw] tx confirmed frames",
+};
+
+#define DPAA2_ETH_NUM_STATS ARRAY_SIZE(dpaa2_ethtool_stats)
+
+static char dpaa2_ethtool_extras[][ETH_GSTRING_LEN] = {
+ /* per-cpu stats */
+ "[drv] tx conf frames",
+ "[drv] tx conf bytes",
+ "[drv] tx sg frames",
+ "[drv] tx sg bytes",
+ "[drv] tx realloc frames",
+ "[drv] rx sg frames",
+ "[drv] rx sg bytes",
+ "[drv] enqueue portal busy",
+ /* Channel stats */
+ "[drv] dequeue portal busy",
+ "[drv] channel pull errors",
+ "[drv] cdan",
+};
+
+#define DPAA2_ETH_NUM_EXTRA_STATS ARRAY_SIZE(dpaa2_ethtool_extras)
+
+static void dpaa2_eth_get_drvinfo(struct net_device *net_dev,
+ struct ethtool_drvinfo *drvinfo)
+{
+ struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
+
+ strlcpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver));
+
+ snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
+ "%u.%u", priv->dpni_ver_major, priv->dpni_ver_minor);
+
+ strlcpy(drvinfo->bus_info, dev_name(net_dev->dev.parent->parent),
+ sizeof(drvinfo->bus_info));
+}
+
+static int
+dpaa2_eth_get_link_ksettings(struct net_device *net_dev,
+ struct ethtool_link_ksettings *link_settings)
+{
+ struct dpni_link_state state = {0};
+ int err = 0;
+ struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
+
+ err = dpni_get_link_state(priv->mc_io, 0, priv->mc_token, &state);
+ if (err) {
+ netdev_err(net_dev, "ERROR %d getting link state\n", err);
+ goto out;
+ }
+
+ /* At the moment, we have no way of interrogating the DPMAC
+ * from the DPNI side - and for that matter there may exist
+ * no DPMAC at all. So for now we just don't report anything
+ * beyond the DPNI attributes.
+ */
+ if (state.options & DPNI_LINK_OPT_AUTONEG)
+ link_settings->base.autoneg = AUTONEG_ENABLE;
+ if (!(state.options & DPNI_LINK_OPT_HALF_DUPLEX))
+ link_settings->base.duplex = DUPLEX_FULL;
+ link_settings->base.speed = state.rate;
+
+out:
+ return err;
+}
+
+#define DPNI_DYNAMIC_LINK_SET_VER_MAJOR 7
+#define DPNI_DYNAMIC_LINK_SET_VER_MINOR 1
+static int
+dpaa2_eth_set_link_ksettings(struct net_device *net_dev,
+ const struct ethtool_link_ksettings *link_settings)
+{
+ struct dpni_link_cfg cfg = {0};
+ struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
+ int err = 0;
+
+ /* If using an older MC version, the DPNI must be down
+ * in order to be able to change link settings. Taking steps to let
+ * the user know that.
+ */
+ if (dpaa2_eth_cmp_dpni_ver(priv, DPNI_DYNAMIC_LINK_SET_VER_MAJOR,
+ DPNI_DYNAMIC_LINK_SET_VER_MINOR) < 0) {
+ if (netif_running(net_dev)) {
+ netdev_info(net_dev, "Interface must be brought down first.\n");
+ return -EACCES;
+ }
+ }
+
+ cfg.rate = link_settings->base.speed;
+ if (link_settings->base.autoneg == AUTONEG_ENABLE)
+ cfg.options |= DPNI_LINK_OPT_AUTONEG;
+ else
+ cfg.options &= ~DPNI_LINK_OPT_AUTONEG;
+ if (link_settings->base.duplex == DUPLEX_HALF)
+ cfg.options |= DPNI_LINK_OPT_HALF_DUPLEX;
+ else
+ cfg.options &= ~DPNI_LINK_OPT_HALF_DUPLEX;
+
+ err = dpni_set_link_cfg(priv->mc_io, 0, priv->mc_token, &cfg);
+ if (err)
+ /* ethtool will be loud enough if we return an error; no point
+ * in putting our own error message on the console by default
+ */
+ netdev_dbg(net_dev, "ERROR %d setting link cfg\n", err);
+
+ return err;
+}
+
+static void dpaa2_eth_get_strings(struct net_device *netdev, u32 stringset,
+ u8 *data)
+{
+ u8 *p = data;
+ int i;
+
+ switch (stringset) {
+ case ETH_SS_STATS:
+ for (i = 0; i < DPAA2_ETH_NUM_STATS; i++) {
+ strlcpy(p, dpaa2_ethtool_stats[i], ETH_GSTRING_LEN);
+ p += ETH_GSTRING_LEN;
+ }
+ for (i = 0; i < DPAA2_ETH_NUM_EXTRA_STATS; i++) {
+ strlcpy(p, dpaa2_ethtool_extras[i], ETH_GSTRING_LEN);
+ p += ETH_GSTRING_LEN;
+ }
+ break;
+ }
+}
+
+static int dpaa2_eth_get_sset_count(struct net_device *net_dev, int sset)
+{
+ switch (sset) {
+ case ETH_SS_STATS: /* ethtool_get_stats(), ethtool_get_drvinfo() */
+ return DPAA2_ETH_NUM_STATS + DPAA2_ETH_NUM_EXTRA_STATS;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+/** Fill in hardware counters, as returned by MC.
+ */
+static void dpaa2_eth_get_ethtool_stats(struct net_device *net_dev,
+ struct ethtool_stats *stats,
+ u64 *data)
+{
+ int i = 0;
+ int j, k, err;
+ int num_cnt;
+ union dpni_statistics dpni_stats;
+ u64 cdan = 0;
+ u64 portal_busy = 0, pull_err = 0;
+ struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
+ struct dpaa2_eth_drv_stats *extras;
+ struct dpaa2_eth_ch_stats *ch_stats;
+
+ memset(data, 0,
+ sizeof(u64) * (DPAA2_ETH_NUM_STATS + DPAA2_ETH_NUM_EXTRA_STATS));
+
+ /* Print standard counters, from DPNI statistics */
+ for (j = 0; j <= 2; j++) {
+ err = dpni_get_statistics(priv->mc_io, 0, priv->mc_token,
+ j, &dpni_stats);
+ if (err != 0)
+ netdev_warn(net_dev, "dpni_get_stats(%d) failed\n", j);
+ switch (j) {
+ case 0:
+ num_cnt = sizeof(dpni_stats.page_0) / sizeof(u64);
+ break;
+ case 1:
+ num_cnt = sizeof(dpni_stats.page_1) / sizeof(u64);
+ break;
+ case 2:
+ num_cnt = sizeof(dpni_stats.page_2) / sizeof(u64);
+ break;
+ }
+ for (k = 0; k < num_cnt; k++)
+ *(data + i++) = dpni_stats.raw.counter[k];
+ }
+
+ /* Print per-cpu extra stats */
+ for_each_online_cpu(k) {
+ extras = per_cpu_ptr(priv->percpu_extras, k);
+ for (j = 0; j < sizeof(*extras) / sizeof(__u64); j++)
+ *((__u64 *)data + i + j) += *((__u64 *)extras + j);
+ }
+ i += j;
+
+ for (j = 0; j < priv->num_channels; j++) {
+ ch_stats = &priv->channel[j]->stats;
+ cdan += ch_stats->cdan;
+ portal_busy += ch_stats->dequeue_portal_busy;
+ pull_err += ch_stats->pull_err;
+ }
+
+ *(data + i++) = portal_busy;
+ *(data + i++) = pull_err;
+ *(data + i++) = cdan;
+}
+
+static int prep_eth_rule(struct ethhdr *eth_value, struct ethhdr *eth_mask,
+ void *key, void *mask)
+{
+ int off;
+
+ if (eth_mask->h_proto) {
+ off = dpaa2_eth_cls_fld_off(NET_PROT_ETH, NH_FLD_ETH_TYPE);
+ *(__be16 *)(key + off) = eth_value->h_proto;
+ *(__be16 *)(mask + off) = eth_mask->h_proto;
+ }
+
+ if (!is_zero_ether_addr(eth_mask->h_source)) {
+ off = dpaa2_eth_cls_fld_off(NET_PROT_ETH, NH_FLD_ETH_SA);
+ ether_addr_copy(key + off, eth_value->h_source);
+ ether_addr_copy(mask + off, eth_mask->h_source);
+ }
+
+ if (!is_zero_ether_addr(eth_mask->h_dest)) {
+ off = dpaa2_eth_cls_fld_off(NET_PROT_ETH, NH_FLD_ETH_DA);
+ ether_addr_copy(key + off, eth_value->h_dest);
+ ether_addr_copy(mask + off, eth_mask->h_dest);
+ }
+
+ return 0;
+}
+
+static int prep_uip_rule(struct ethtool_usrip4_spec *uip_value,
+ struct ethtool_usrip4_spec *uip_mask,
+ void *key, void *mask)
+{
+ int off;
+ u32 tmp_value, tmp_mask;
+
+ if (uip_mask->tos || uip_mask->ip_ver)
+ return -EOPNOTSUPP;
+
+ if (uip_mask->ip4src) {
+ off = dpaa2_eth_cls_fld_off(NET_PROT_IP, NH_FLD_IP_SRC);
+ *(__be32 *)(key + off) = uip_value->ip4src;
+ *(__be32 *)(mask + off) = uip_mask->ip4src;
+ }
+
+ if (uip_mask->ip4dst) {
+ off = dpaa2_eth_cls_fld_off(NET_PROT_IP, NH_FLD_IP_DST);
+ *(__be32 *)(key + off) = uip_value->ip4dst;
+ *(__be32 *)(mask + off) = uip_mask->ip4dst;
+ }
+
+ if (uip_mask->proto) {
+ off = dpaa2_eth_cls_fld_off(NET_PROT_IP, NH_FLD_IP_PROTO);
+ *(u8 *)(key + off) = uip_value->proto;
+ *(u8 *)(mask + off) = uip_mask->proto;
+ }
+
+ if (uip_mask->l4_4_bytes) {
+ tmp_value = be32_to_cpu(uip_value->l4_4_bytes);
+ tmp_mask = be32_to_cpu(uip_mask->l4_4_bytes);
+
+ off = dpaa2_eth_cls_fld_off(NET_PROT_UDP, NH_FLD_UDP_PORT_SRC);
+ *(__be16 *)(key + off) = htons(tmp_value >> 16);
+ *(__be16 *)(mask + off) = htons(tmp_mask >> 16);
+
+ off = dpaa2_eth_cls_fld_off(NET_PROT_UDP, NH_FLD_UDP_PORT_DST);
+ *(__be16 *)(key + off) = htons(tmp_value & 0xFFFF);
+ *(__be16 *)(mask + off) = htons(tmp_mask & 0xFFFF);
+ }
+
+ /* Only apply the rule for IPv4 frames */
+ off = dpaa2_eth_cls_fld_off(NET_PROT_ETH, NH_FLD_ETH_TYPE);
+ *(__be16 *)(key + off) = htons(ETH_P_IP);
+ *(__be16 *)(mask + off) = htons(0xFFFF);
+
+ return 0;
+}
+
+static int prep_l4_rule(struct ethtool_tcpip4_spec *l4_value,
+ struct ethtool_tcpip4_spec *l4_mask,
+ void *key, void *mask, u8 l4_proto)
+{
+ int off;
+
+ if (l4_mask->tos)
+ return -EOPNOTSUPP;
+
+ if (l4_mask->ip4src) {
+ off = dpaa2_eth_cls_fld_off(NET_PROT_IP, NH_FLD_IP_SRC);
+ *(__be32 *)(key + off) = l4_value->ip4src;
+ *(__be32 *)(mask + off) = l4_mask->ip4src;
+ }
+
+ if (l4_mask->ip4dst) {
+ off = dpaa2_eth_cls_fld_off(NET_PROT_IP, NH_FLD_IP_DST);
+ *(__be32 *)(key + off) = l4_value->ip4dst;
+ *(__be32 *)(mask + off) = l4_mask->ip4dst;
+ }
+
+ if (l4_mask->psrc) {
+ off = dpaa2_eth_cls_fld_off(NET_PROT_UDP, NH_FLD_UDP_PORT_SRC);
+ *(__be16 *)(key + off) = l4_value->psrc;
+ *(__be16 *)(mask + off) = l4_mask->psrc;
+ }
+
+ if (l4_mask->pdst) {
+ off = dpaa2_eth_cls_fld_off(NET_PROT_UDP, NH_FLD_UDP_PORT_DST);
+ *(__be16 *)(key + off) = l4_value->pdst;
+ *(__be16 *)(mask + off) = l4_mask->pdst;
+ }
+
+ /* Only apply the rule for IPv4 frames with the specified L4 proto */
+ off = dpaa2_eth_cls_fld_off(NET_PROT_ETH, NH_FLD_ETH_TYPE);
+ *(__be16 *)(key + off) = htons(ETH_P_IP);
+ *(__be16 *)(mask + off) = htons(0xFFFF);
+
+ off = dpaa2_eth_cls_fld_off(NET_PROT_IP, NH_FLD_IP_PROTO);
+ *(u8 *)(key + off) = l4_proto;
+ *(u8 *)(mask + off) = 0xFF;
+
+ return 0;
+}
+
+static int prep_ext_rule(struct ethtool_flow_ext *ext_value,
+ struct ethtool_flow_ext *ext_mask,
+ void *key, void *mask)
+{
+ int off;
+
+ if (ext_mask->vlan_etype)
+ return -EOPNOTSUPP;
+
+ if (ext_mask->vlan_tci) {
+ off = dpaa2_eth_cls_fld_off(NET_PROT_VLAN, NH_FLD_VLAN_TCI);
+ *(__be16 *)(key + off) = ext_value->vlan_tci;
+ *(__be16 *)(mask + off) = ext_mask->vlan_tci;
+ }
+
+ return 0;
+}
+
+static int prep_mac_ext_rule(struct ethtool_flow_ext *ext_value,
+ struct ethtool_flow_ext *ext_mask,
+ void *key, void *mask)
+{
+ int off;
+
+ if (!is_zero_ether_addr(ext_mask->h_dest)) {
+ off = dpaa2_eth_cls_fld_off(NET_PROT_ETH, NH_FLD_ETH_DA);
+ ether_addr_copy(key + off, ext_value->h_dest);
+ ether_addr_copy(mask + off, ext_mask->h_dest);
+ }
+
+ return 0;
+}
+
+static int prep_cls_rule(struct ethtool_rx_flow_spec *fs, void *key, void *mask)
+{
+ int err;
+
+ switch (fs->flow_type & 0xFF) {
+ case ETHER_FLOW:
+ err = prep_eth_rule(&fs->h_u.ether_spec, &fs->m_u.ether_spec,
+ key, mask);
+ break;
+ case IP_USER_FLOW:
+ err = prep_uip_rule(&fs->h_u.usr_ip4_spec,
+ &fs->m_u.usr_ip4_spec, key, mask);
+ break;
+ case TCP_V4_FLOW:
+ err = prep_l4_rule(&fs->h_u.tcp_ip4_spec, &fs->m_u.tcp_ip4_spec,
+ key, mask, IPPROTO_TCP);
+ break;
+ case UDP_V4_FLOW:
+ err = prep_l4_rule(&fs->h_u.udp_ip4_spec, &fs->m_u.udp_ip4_spec,
+ key, mask, IPPROTO_UDP);
+ break;
+ case SCTP_V4_FLOW:
+ err = prep_l4_rule(&fs->h_u.sctp_ip4_spec,
+ &fs->m_u.sctp_ip4_spec, key, mask,
+ IPPROTO_SCTP);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ if (err)
+ return err;
+
+ if (fs->flow_type & FLOW_EXT) {
+ err = prep_ext_rule(&fs->h_ext, &fs->m_ext, key, mask);
+ if (err)
+ return err;
+ }
+
+ if (fs->flow_type & FLOW_MAC_EXT) {
+ err = prep_mac_ext_rule(&fs->h_ext, &fs->m_ext, key, mask);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int do_cls_rule(struct net_device *net_dev,
+ struct ethtool_rx_flow_spec *fs,
+ bool add)
+{
+ struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
+ struct device *dev = net_dev->dev.parent;
+ struct dpni_rule_cfg rule_cfg = { 0 };
+ struct dpni_fs_action_cfg fs_act = { 0 };
+ dma_addr_t key_iova;
+ void *key_buf;
+ int err;
+
+ if (fs->ring_cookie != RX_CLS_FLOW_DISC &&
+ fs->ring_cookie >= dpaa2_eth_queue_count(priv))
+ return -EINVAL;
+
+ rule_cfg.key_size = dpaa2_eth_cls_key_size();
+
+ /* allocate twice the key size, for the actual key and for mask */
+ key_buf = kzalloc(rule_cfg.key_size * 2, GFP_KERNEL);
+ if (!key_buf)
+ return -ENOMEM;
+
+ /* Fill the key and mask memory areas */
+ err = prep_cls_rule(fs, key_buf, key_buf + rule_cfg.key_size);
+ if (err)
+ goto free_mem;
+
+ key_iova = dma_map_single(dev, key_buf, rule_cfg.key_size * 2,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, key_iova)) {
+ err = -ENOMEM;
+ goto free_mem;
+ }
+
+ rule_cfg.key_iova = key_iova;
+ rule_cfg.mask_iova = key_iova + rule_cfg.key_size;
+
+ if (add) {
+ if (fs->ring_cookie == RX_CLS_FLOW_DISC)
+ fs_act.options |= DPNI_FS_OPT_DISCARD;
+ else
+ fs_act.flow_id = fs->ring_cookie;
+ err = dpni_add_fs_entry(priv->mc_io, 0, priv->mc_token, 0,
+ fs->location, &rule_cfg, &fs_act);
+ } else {
+ err = dpni_remove_fs_entry(priv->mc_io, 0, priv->mc_token, 0,
+ &rule_cfg);
+ }
+
+ dma_unmap_single(dev, key_iova, rule_cfg.key_size * 2, DMA_TO_DEVICE);
+
+free_mem:
+ kfree(key_buf);
+
+ return err;
+}
+
+static int update_cls_rule(struct net_device *net_dev,
+ struct ethtool_rx_flow_spec *new_fs,
+ int location)
+{
+ struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
+ struct dpaa2_eth_cls_rule *rule;
+ int err = -EINVAL;
+
+ if (!priv->rx_cls_enabled)
+ return -EOPNOTSUPP;
+
+ if (location >= dpaa2_eth_fs_count(priv))
+ return -EINVAL;
+
+ rule = &priv->cls_rules[location];
+
+ /* If a rule is present at the specified location, delete it. */
+ if (rule->in_use) {
+ err = do_cls_rule(net_dev, &rule->fs, false);
+ if (err)
+ return err;
+
+ rule->in_use = 0;
+ }
+
+ /* If no new entry to add, return here */
+ if (!new_fs)
+ return err;
+
+ err = do_cls_rule(net_dev, new_fs, true);
+ if (err)
+ return err;
+
+ rule->in_use = 1;
+ rule->fs = *new_fs;
+
+ return 0;
+}
+
+static int dpaa2_eth_get_rxnfc(struct net_device *net_dev,
+ struct ethtool_rxnfc *rxnfc, u32 *rule_locs)
+{
+ struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
+ int max_rules = dpaa2_eth_fs_count(priv);
+ int i, j = 0;
+
+ switch (rxnfc->cmd) {
+ case ETHTOOL_GRXFH:
+ /* we purposely ignore cmd->flow_type for now, because the
+ * classifier only supports a single set of fields for all
+ * protocols
+ */
+ rxnfc->data = priv->rx_hash_fields;
+ break;
+ case ETHTOOL_GRXRINGS:
+ rxnfc->data = dpaa2_eth_queue_count(priv);
+ break;
+ case ETHTOOL_GRXCLSRLCNT:
+ rxnfc->rule_cnt = 0;
+ for (i = 0; i < max_rules; i++)
+ if (priv->cls_rules[i].in_use)
+ rxnfc->rule_cnt++;
+ rxnfc->data = max_rules;
+ break;
+ case ETHTOOL_GRXCLSRULE:
+ if (rxnfc->fs.location >= max_rules)
+ return -EINVAL;
+ if (!priv->cls_rules[rxnfc->fs.location].in_use)
+ return -EINVAL;
+ rxnfc->fs = priv->cls_rules[rxnfc->fs.location].fs;
+ break;
+ case ETHTOOL_GRXCLSRLALL:
+ for (i = 0; i < max_rules; i++) {
+ if (!priv->cls_rules[i].in_use)
+ continue;
+ if (j == rxnfc->rule_cnt)
+ return -EMSGSIZE;
+ rule_locs[j++] = i;
+ }
+ rxnfc->rule_cnt = j;
+ rxnfc->data = max_rules;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int dpaa2_eth_set_rxnfc(struct net_device *net_dev,
+ struct ethtool_rxnfc *rxnfc)
+{
+ int err = 0;
+
+ switch (rxnfc->cmd) {
+ case ETHTOOL_SRXFH:
+ if ((rxnfc->data & DPAA2_RXH_SUPPORTED) != rxnfc->data)
+ return -EOPNOTSUPP;
+ err = dpaa2_eth_set_hash(net_dev, rxnfc->data);
+ break;
+ case ETHTOOL_SRXCLSRLINS:
+ err = update_cls_rule(net_dev, &rxnfc->fs, rxnfc->fs.location);
+ break;
+ case ETHTOOL_SRXCLSRLDEL:
+ err = update_cls_rule(net_dev, NULL, rxnfc->fs.location);
+ break;
+ default:
+ err = -EOPNOTSUPP;
+ }
+
+ return err;
+}
+
+int dpaa2_phc_index = -1;
+EXPORT_SYMBOL(dpaa2_phc_index);
+
+static int dpaa2_eth_get_ts_info(struct net_device *dev,
+ struct ethtool_ts_info *info)
+{
+ info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
+ SOF_TIMESTAMPING_RX_HARDWARE |
+ SOF_TIMESTAMPING_RAW_HARDWARE;
+
+ info->phc_index = dpaa2_phc_index;
+
+ info->tx_types = (1 << HWTSTAMP_TX_OFF) |
+ (1 << HWTSTAMP_TX_ON);
+
+ info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
+ (1 << HWTSTAMP_FILTER_ALL);
+ return 0;
+}
+
+const struct ethtool_ops dpaa2_ethtool_ops = {
+ .get_drvinfo = dpaa2_eth_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+ .get_link_ksettings = dpaa2_eth_get_link_ksettings,
+ .set_link_ksettings = dpaa2_eth_set_link_ksettings,
+ .get_sset_count = dpaa2_eth_get_sset_count,
+ .get_ethtool_stats = dpaa2_eth_get_ethtool_stats,
+ .get_strings = dpaa2_eth_get_strings,
+ .get_rxnfc = dpaa2_eth_get_rxnfc,
+ .set_rxnfc = dpaa2_eth_set_rxnfc,
+ .get_ts_info = dpaa2_eth_get_ts_info,
+};
diff --git a/drivers/staging/fsl-dpaa2/rtc/rtc.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ptp.c
index 0d52cb85441f..84b942b1eccc 100644
--- a/drivers/staging/fsl-dpaa2/rtc/rtc.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ptp.c
@@ -9,10 +9,10 @@
#include <linux/ptp_clock_kernel.h>
#include <linux/fsl/mc.h>
-#include "rtc.h"
+#include "dpaa2-ptp.h"
struct ptp_dpaa2_priv {
- struct fsl_mc_device *rtc_mc_dev;
+ struct fsl_mc_device *ptp_mc_dev;
struct ptp_clock *clock;
struct ptp_clock_info caps;
u32 freq_comp;
@@ -23,7 +23,7 @@ static int ptp_dpaa2_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
{
struct ptp_dpaa2_priv *ptp_dpaa2 =
container_of(ptp, struct ptp_dpaa2_priv, caps);
- struct fsl_mc_device *mc_dev = ptp_dpaa2->rtc_mc_dev;
+ struct fsl_mc_device *mc_dev = ptp_dpaa2->ptp_mc_dev;
struct device *dev = &mc_dev->dev;
u64 adj;
u32 diff, tmr_add;
@@ -46,14 +46,14 @@ static int ptp_dpaa2_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
mc_dev->mc_handle, tmr_add);
if (err)
dev_err(dev, "dprtc_set_freq_compensation err %d\n", err);
- return 0;
+ return err;
}
static int ptp_dpaa2_adjtime(struct ptp_clock_info *ptp, s64 delta)
{
struct ptp_dpaa2_priv *ptp_dpaa2 =
container_of(ptp, struct ptp_dpaa2_priv, caps);
- struct fsl_mc_device *mc_dev = ptp_dpaa2->rtc_mc_dev;
+ struct fsl_mc_device *mc_dev = ptp_dpaa2->ptp_mc_dev;
struct device *dev = &mc_dev->dev;
s64 now;
int err = 0;
@@ -61,24 +61,22 @@ static int ptp_dpaa2_adjtime(struct ptp_clock_info *ptp, s64 delta)
err = dprtc_get_time(mc_dev->mc_io, 0, mc_dev->mc_handle, &now);
if (err) {
dev_err(dev, "dprtc_get_time err %d\n", err);
- return 0;
+ return err;
}
now += delta;
err = dprtc_set_time(mc_dev->mc_io, 0, mc_dev->mc_handle, now);
- if (err) {
+ if (err)
dev_err(dev, "dprtc_set_time err %d\n", err);
- return 0;
- }
- return 0;
+ return err;
}
static int ptp_dpaa2_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
{
struct ptp_dpaa2_priv *ptp_dpaa2 =
container_of(ptp, struct ptp_dpaa2_priv, caps);
- struct fsl_mc_device *mc_dev = ptp_dpaa2->rtc_mc_dev;
+ struct fsl_mc_device *mc_dev = ptp_dpaa2->ptp_mc_dev;
struct device *dev = &mc_dev->dev;
u64 ns;
u32 remainder;
@@ -87,12 +85,12 @@ static int ptp_dpaa2_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
err = dprtc_get_time(mc_dev->mc_io, 0, mc_dev->mc_handle, &ns);
if (err) {
dev_err(dev, "dprtc_get_time err %d\n", err);
- return 0;
+ return err;
}
ts->tv_sec = div_u64_rem(ns, 1000000000, &remainder);
ts->tv_nsec = remainder;
- return 0;
+ return err;
}
static int ptp_dpaa2_settime(struct ptp_clock_info *ptp,
@@ -100,7 +98,7 @@ static int ptp_dpaa2_settime(struct ptp_clock_info *ptp,
{
struct ptp_dpaa2_priv *ptp_dpaa2 =
container_of(ptp, struct ptp_dpaa2_priv, caps);
- struct fsl_mc_device *mc_dev = ptp_dpaa2->rtc_mc_dev;
+ struct fsl_mc_device *mc_dev = ptp_dpaa2->ptp_mc_dev;
struct device *dev = &mc_dev->dev;
u64 ns;
int err = 0;
@@ -111,10 +109,10 @@ static int ptp_dpaa2_settime(struct ptp_clock_info *ptp,
err = dprtc_set_time(mc_dev->mc_io, 0, mc_dev->mc_handle, ns);
if (err)
dev_err(dev, "dprtc_set_time err %d\n", err);
- return 0;
+ return err;
}
-static struct ptp_clock_info ptp_dpaa2_caps = {
+static const struct ptp_clock_info ptp_dpaa2_caps = {
.owner = THIS_MODULE,
.name = "DPAA2 PTP Clock",
.max_adj = 512000,
@@ -129,14 +127,14 @@ static struct ptp_clock_info ptp_dpaa2_caps = {
.settime64 = ptp_dpaa2_settime,
};
-static int rtc_probe(struct fsl_mc_device *mc_dev)
+static int dpaa2_ptp_probe(struct fsl_mc_device *mc_dev)
{
struct device *dev = &mc_dev->dev;
struct ptp_dpaa2_priv *ptp_dpaa2;
u32 tmr_add = 0;
int err;
- ptp_dpaa2 = kzalloc(sizeof(*ptp_dpaa2), GFP_KERNEL);
+ ptp_dpaa2 = devm_kzalloc(dev, sizeof(*ptp_dpaa2), GFP_KERNEL);
if (!ptp_dpaa2)
return -ENOMEM;
@@ -153,7 +151,7 @@ static int rtc_probe(struct fsl_mc_device *mc_dev)
goto err_free_mcp;
}
- ptp_dpaa2->rtc_mc_dev = mc_dev;
+ ptp_dpaa2->ptp_mc_dev = mc_dev;
err = dprtc_get_freq_compensation(mc_dev->mc_io, 0,
mc_dev->mc_handle, &tmr_add);
@@ -182,12 +180,10 @@ err_close:
err_free_mcp:
fsl_mc_portal_free(mc_dev->mc_io);
err_exit:
- kfree(ptp_dpaa2);
- dev_set_drvdata(dev, NULL);
return err;
}
-static int rtc_remove(struct fsl_mc_device *mc_dev)
+static int dpaa2_ptp_remove(struct fsl_mc_device *mc_dev)
{
struct ptp_dpaa2_priv *ptp_dpaa2;
struct device *dev = &mc_dev->dev;
@@ -198,32 +194,29 @@ static int rtc_remove(struct fsl_mc_device *mc_dev)
dprtc_close(mc_dev->mc_io, 0, mc_dev->mc_handle);
fsl_mc_portal_free(mc_dev->mc_io);
- kfree(ptp_dpaa2);
- dev_set_drvdata(dev, NULL);
-
return 0;
}
-static const struct fsl_mc_device_id rtc_match_id_table[] = {
+static const struct fsl_mc_device_id dpaa2_ptp_match_id_table[] = {
{
.vendor = FSL_MC_VENDOR_FREESCALE,
.obj_type = "dprtc",
},
{}
};
-MODULE_DEVICE_TABLE(fslmc, rtc_match_id_table);
+MODULE_DEVICE_TABLE(fslmc, dpaa2_ptp_match_id_table);
-static struct fsl_mc_driver rtc_drv = {
+static struct fsl_mc_driver dpaa2_ptp_drv = {
.driver = {
.name = KBUILD_MODNAME,
.owner = THIS_MODULE,
},
- .probe = rtc_probe,
- .remove = rtc_remove,
- .match_id_table = rtc_match_id_table,
+ .probe = dpaa2_ptp_probe,
+ .remove = dpaa2_ptp_remove,
+ .match_id_table = dpaa2_ptp_match_id_table,
};
-module_fsl_mc_driver(rtc_drv);
+module_fsl_mc_driver(dpaa2_ptp_drv);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("DPAA2 PTP Clock Driver");
diff --git a/drivers/staging/fsl-dpaa2/rtc/rtc.h b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ptp.h
index ff2e177395d4..ff2e177395d4 100644
--- a/drivers/staging/fsl-dpaa2/rtc/rtc.h
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ptp.h
diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpkg.h b/drivers/net/ethernet/freescale/dpaa2/dpkg.h
index 6de613b13e4d..6de613b13e4d 100644
--- a/drivers/staging/fsl-dpaa2/ethernet/dpkg.h
+++ b/drivers/net/ethernet/freescale/dpaa2/dpkg.h
diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpni-cmd.h b/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h
index 83698abce8b4..7b44d7d9b19a 100644
--- a/drivers/staging/fsl-dpaa2/ethernet/dpni-cmd.h
+++ b/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h
@@ -82,6 +82,9 @@
#define DPNI_CMDID_GET_OFFLOAD DPNI_CMD(0x26B)
#define DPNI_CMDID_SET_OFFLOAD DPNI_CMD(0x26C)
+#define DPNI_CMDID_SET_RX_FS_DIST DPNI_CMD(0x273)
+#define DPNI_CMDID_SET_RX_HASH_DIST DPNI_CMD(0x274)
+
/* Macros for accessing command fields smaller than 1byte */
#define DPNI_MASK(field) \
GENMASK(DPNI_##field##_SHIFT + DPNI_##field##_SIZE - 1, \
@@ -515,4 +518,52 @@ struct dpni_rsp_get_api_version {
__le16 minor;
};
+#define DPNI_RX_FS_DIST_ENABLE_SHIFT 0
+#define DPNI_RX_FS_DIST_ENABLE_SIZE 1
+struct dpni_cmd_set_rx_fs_dist {
+ __le16 dist_size;
+ u8 enable;
+ u8 tc;
+ __le16 miss_flow_id;
+ __le16 pad;
+ __le64 key_cfg_iova;
+};
+
+#define DPNI_RX_HASH_DIST_ENABLE_SHIFT 0
+#define DPNI_RX_HASH_DIST_ENABLE_SIZE 1
+struct dpni_cmd_set_rx_hash_dist {
+ __le16 dist_size;
+ u8 enable;
+ u8 tc;
+ __le32 pad;
+ __le64 key_cfg_iova;
+};
+
+struct dpni_cmd_add_fs_entry {
+ /* cmd word 0 */
+ __le16 options;
+ u8 tc_id;
+ u8 key_size;
+ __le16 index;
+ __le16 flow_id;
+ /* cmd word 1 */
+ __le64 key_iova;
+ /* cmd word 2 */
+ __le64 mask_iova;
+ /* cmd word 3 */
+ __le64 flc;
+};
+
+struct dpni_cmd_remove_fs_entry {
+ /* cmd word 0 */
+ __le16 pad0;
+ u8 tc_id;
+ u8 key_size;
+ __le32 pad1;
+ /* cmd word 1 */
+ __le64 key_iova;
+ /* cmd word 2 */
+ __le64 mask_iova;
+};
+
#endif /* _FSL_DPNI_CMD_H */
diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpni.c b/drivers/net/ethernet/freescale/dpaa2/dpni.c
index d6ac26797cec..220dfc806a24 100644
--- a/drivers/staging/fsl-dpaa2/ethernet/dpni.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpni.c
@@ -1598,3 +1598,155 @@ int dpni_get_api_version(struct fsl_mc_io *mc_io,
return 0;
}
+
+/**
+ * dpni_set_rx_fs_dist() - Set Rx flow steering distribution
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPNI object
+ * @cfg: Distribution configuration
+ *
+ * If the FS is already enabled with a previous call the classification
+ * key will be changed but all the table rules are kept. If the
+ * existing rules do not match the key the results will not be
+ * predictable. It is the user responsibility to keep key integrity.
+ * If cfg.enable is set to 1 the command will create a flow steering table
+ * and will classify packets according to this table. The packets that
+ * miss all the table rules will be classified according to settings
+ * made in dpni_set_rx_hash_dist()
+ * If cfg.enable is set to 0 the command will clear flow steering table.
+ * The packets will be classified according to settings made in
+ * dpni_set_rx_hash_dist()
+ */
+int dpni_set_rx_fs_dist(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ const struct dpni_rx_dist_cfg *cfg)
+{
+ struct dpni_cmd_set_rx_fs_dist *cmd_params;
+ struct fsl_mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_RX_FS_DIST,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpni_cmd_set_rx_fs_dist *)cmd.params;
+ cmd_params->dist_size = cpu_to_le16(cfg->dist_size);
+ dpni_set_field(cmd_params->enable, RX_FS_DIST_ENABLE, cfg->enable);
+ cmd_params->tc = cfg->tc;
+ cmd_params->miss_flow_id = cpu_to_le16(cfg->fs_miss_flow_id);
+ cmd_params->key_cfg_iova = cpu_to_le64(cfg->key_cfg_iova);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpni_set_rx_hash_dist() - Set Rx hash distribution
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPNI object
+ * @cfg: Distribution configuration
+ * If cfg.enable is set to 1 the packets will be classified using a hash
+ * function based on the key received in cfg.key_cfg_iova parameter.
+ * If cfg.enable is set to 0 the packets will be sent to the default queue
+ */
+int dpni_set_rx_hash_dist(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ const struct dpni_rx_dist_cfg *cfg)
+{
+ struct dpni_cmd_set_rx_hash_dist *cmd_params;
+ struct fsl_mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_RX_HASH_DIST,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpni_cmd_set_rx_hash_dist *)cmd.params;
+ cmd_params->dist_size = cpu_to_le16(cfg->dist_size);
+ dpni_set_field(cmd_params->enable, RX_HASH_DIST_ENABLE, cfg->enable);
+ cmd_params->tc = cfg->tc;
+ cmd_params->key_cfg_iova = cpu_to_le64(cfg->key_cfg_iova);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpni_add_fs_entry() - Add Flow Steering entry for a specific traffic class
+ * (to select a flow ID)
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPNI object
+ * @tc_id: Traffic class selection (0-7)
+ * @index: Location in the FS table where to insert the entry.
+ * Only relevant if MASKING is enabled for FS
+ * classification on this DPNI, it is ignored for exact match.
+ * @cfg: Flow steering rule to add
+ * @action: Action to be taken as result of a classification hit
+ *
+ * Return: '0' on Success; Error code otherwise.
+ */
+int dpni_add_fs_entry(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u8 tc_id,
+ u16 index,
+ const struct dpni_rule_cfg *cfg,
+ const struct dpni_fs_action_cfg *action)
+{
+ struct dpni_cmd_add_fs_entry *cmd_params;
+ struct fsl_mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_ADD_FS_ENT,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpni_cmd_add_fs_entry *)cmd.params;
+ cmd_params->tc_id = tc_id;
+ cmd_params->key_size = cfg->key_size;
+ cmd_params->index = cpu_to_le16(index);
+ cmd_params->key_iova = cpu_to_le64(cfg->key_iova);
+ cmd_params->mask_iova = cpu_to_le64(cfg->mask_iova);
+ cmd_params->options = cpu_to_le16(action->options);
+ cmd_params->flow_id = cpu_to_le16(action->flow_id);
+ cmd_params->flc = cpu_to_le64(action->flc);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpni_remove_fs_entry() - Remove Flow Steering entry from a specific
+ * traffic class
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPNI object
+ * @tc_id: Traffic class selection (0-7)
+ * @cfg: Flow steering rule to remove
+ *
+ * Return: '0' on Success; Error code otherwise.
+ */
+int dpni_remove_fs_entry(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u8 tc_id,
+ const struct dpni_rule_cfg *cfg)
+{
+ struct dpni_cmd_remove_fs_entry *cmd_params;
+ struct fsl_mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_REMOVE_FS_ENT,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpni_cmd_remove_fs_entry *)cmd.params;
+ cmd_params->tc_id = tc_id;
+ cmd_params->key_size = cfg->key_size;
+ cmd_params->key_iova = cpu_to_le64(cfg->key_iova);
+ cmd_params->mask_iova = cpu_to_le64(cfg->mask_iova);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpni.h b/drivers/net/ethernet/freescale/dpaa2/dpni.h
index b378a00c7c53..a521242e2353 100644
--- a/drivers/staging/fsl-dpaa2/ethernet/dpni.h
+++ b/drivers/net/ethernet/freescale/dpaa2/dpni.h
@@ -629,6 +629,45 @@ int dpni_set_rx_tc_dist(struct fsl_mc_io *mc_io,
const struct dpni_rx_tc_dist_cfg *cfg);
/**
+ * When used for fs_miss_flow_id in function dpni_set_rx_dist,
+ * will signal to dpni to drop all unclassified frames
+ */
+#define DPNI_FS_MISS_DROP ((uint16_t)-1)
+
+/**
+ * struct dpni_rx_dist_cfg - Rx distribution configuration
+ * @dist_size: distribution size
+ * @key_cfg_iova: I/O virtual address of 256 bytes DMA-able memory filled with
+ * the extractions to be used for the distribution key by calling
+ * dpni_prepare_key_cfg(); relevant only when enable!=0 otherwise
+ * it can be '0'
+ * @enable: enable/disable the distribution.
+ * @tc: TC id for which distribution is set
+ * @fs_miss_flow_id: when packet misses all rules from flow steering table and
+ * hash is disabled it will be put into this queue id; use
+ * DPNI_FS_MISS_DROP to drop frames. The value of this field is
+ * used only when flow steering distribution is enabled and hash
+ * distribution is disabled
+ */
+struct dpni_rx_dist_cfg {
+ u16 dist_size;
+ u64 key_cfg_iova;
+ u8 enable;
+ u8 tc;
+ u16 fs_miss_flow_id;
+};
+
+int dpni_set_rx_fs_dist(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ const struct dpni_rx_dist_cfg *cfg);
+
+int dpni_set_rx_hash_dist(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ const struct dpni_rx_dist_cfg *cfg);
+
+/**
* enum dpni_dest - DPNI destination types
* @DPNI_DEST_NONE: Unassigned destination; The queue is set in parked mode and
* does not generate FQDAN notifications; user is expected to
@@ -816,6 +855,64 @@ struct dpni_rule_cfg {
u8 key_size;
};
+/**
+ * Discard matching traffic. If set, this takes precedence over any other
+ * configuration and matching traffic is always discarded.
+ */
+ #define DPNI_FS_OPT_DISCARD 0x1
+
+/**
+ * Set FLC value. If set, flc member of struct dpni_fs_action_cfg is used to
+ * override the FLC value set per queue.
+ * For more details check the Frame Descriptor section in the hardware
+ * documentation.
+ */
+#define DPNI_FS_OPT_SET_FLC 0x2
+
+/**
+ * Indicates whether the 6 lowest significant bits of FLC are used for stash
+ * control. If set, the 6 least significant bits in value are interpreted as
+ * follows:
+ * - bits 0-1: indicates the number of 64 byte units of context that are
+ * stashed. FLC value is interpreted as a memory address in this case,
+ * excluding the 6 LS bits.
+ * - bits 2-3: indicates the number of 64 byte units of frame annotation
+ * to be stashed. Annotation is placed at FD[ADDR].
+ * - bits 4-5: indicates the number of 64 byte units of frame data to be
+ * stashed. Frame data is placed at FD[ADDR] + FD[OFFSET].
+ * This flag is ignored if DPNI_FS_OPT_SET_FLC is not specified.
+ */
+#define DPNI_FS_OPT_SET_STASH_CONTROL 0x4
+
+/**
+ * struct dpni_fs_action_cfg - Action configuration for table look-up
+ * @flc: FLC value for traffic matching this rule. Please check the
+ * Frame Descriptor section in the hardware documentation for
+ * more information.
+ * @flow_id: Identifies the Rx queue used for matching traffic. Supported
+ * values are in range 0 to num_queue-1.
+ * @options: Any combination of DPNI_FS_OPT_ values.
+ */
+struct dpni_fs_action_cfg {
+ u64 flc;
+ u16 flow_id;
+ u16 options;
+};
+
+int dpni_add_fs_entry(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u8 tc_id,
+ u16 index,
+ const struct dpni_rule_cfg *cfg,
+ const struct dpni_fs_action_cfg *action);
+
+int dpni_remove_fs_entry(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u8 tc_id,
+ const struct dpni_rule_cfg *cfg);
+
int dpni_get_api_version(struct fsl_mc_io *mc_io,
u32 cmd_flags,
u16 *major_ver,
diff --git a/drivers/net/ethernet/freescale/dpaa2/dprtc-cmd.h b/drivers/net/ethernet/freescale/dpaa2/dprtc-cmd.h
new file mode 100644
index 000000000000..9af4ac71f347
--- /dev/null
+++ b/drivers/net/ethernet/freescale/dpaa2/dprtc-cmd.h
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2013-2016 Freescale Semiconductor Inc.
+ * Copyright 2016-2018 NXP
+ */
+
+#ifndef _FSL_DPRTC_CMD_H
+#define _FSL_DPRTC_CMD_H
+
+/* Command versioning */
+#define DPRTC_CMD_BASE_VERSION 1
+#define DPRTC_CMD_ID_OFFSET 4
+
+#define DPRTC_CMD(id) (((id) << DPRTC_CMD_ID_OFFSET) | DPRTC_CMD_BASE_VERSION)
+
+/* Command IDs */
+#define DPRTC_CMDID_CLOSE DPRTC_CMD(0x800)
+#define DPRTC_CMDID_OPEN DPRTC_CMD(0x810)
+
+#define DPRTC_CMDID_SET_FREQ_COMPENSATION DPRTC_CMD(0x1d1)
+#define DPRTC_CMDID_GET_FREQ_COMPENSATION DPRTC_CMD(0x1d2)
+#define DPRTC_CMDID_GET_TIME DPRTC_CMD(0x1d3)
+#define DPRTC_CMDID_SET_TIME DPRTC_CMD(0x1d4)
+
+#pragma pack(push, 1)
+struct dprtc_cmd_open {
+ __le32 dprtc_id;
+};
+
+struct dprtc_get_freq_compensation {
+ __le32 freq_compensation;
+};
+
+struct dprtc_time {
+ __le64 time;
+};
+
+#pragma pack(pop)
+
+#endif /* _FSL_DPRTC_CMD_H */
diff --git a/drivers/net/ethernet/freescale/dpaa2/dprtc.c b/drivers/net/ethernet/freescale/dpaa2/dprtc.c
new file mode 100644
index 000000000000..c13e09bc7b9d
--- /dev/null
+++ b/drivers/net/ethernet/freescale/dpaa2/dprtc.c
@@ -0,0 +1,194 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2013-2016 Freescale Semiconductor Inc.
+ * Copyright 2016-2018 NXP
+ */
+
+#include <linux/fsl/mc.h>
+
+#include "dprtc.h"
+#include "dprtc-cmd.h"
+
+/**
+ * dprtc_open() - Open a control session for the specified object.
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @dprtc_id: DPRTC unique ID
+ * @token: Returned token; use in subsequent API calls
+ *
+ * This function can be used to open a control session for an
+ * already created object; an object may have been declared in
+ * the DPL or by calling the dprtc_create function.
+ * This function returns a unique authentication token,
+ * associated with the specific object ID and the specific MC
+ * portal; this token must be used in all subsequent commands for
+ * this specific object
+ *
+ * Return: '0' on Success; Error code otherwise.
+ */
+int dprtc_open(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ int dprtc_id,
+ u16 *token)
+{
+ struct dprtc_cmd_open *cmd_params;
+ struct fsl_mc_command cmd = { 0 };
+ int err;
+
+ cmd.header = mc_encode_cmd_header(DPRTC_CMDID_OPEN,
+ cmd_flags,
+ 0);
+ cmd_params = (struct dprtc_cmd_open *)cmd.params;
+ cmd_params->dprtc_id = cpu_to_le32(dprtc_id);
+
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ *token = mc_cmd_hdr_read_token(&cmd);
+
+ return 0;
+}
+
+/**
+ * dprtc_close() - Close the control session of the object
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPRTC object
+ *
+ * After this function is called, no further operations are
+ * allowed on the object without opening a new control session.
+ *
+ * Return: '0' on Success; Error code otherwise.
+ */
+int dprtc_close(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token)
+{
+ struct fsl_mc_command cmd = { 0 };
+
+ cmd.header = mc_encode_cmd_header(DPRTC_CMDID_CLOSE, cmd_flags,
+ token);
+
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dprtc_set_freq_compensation() - Sets a new frequency compensation value.
+ *
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPRTC object
+ * @freq_compensation: The new frequency compensation value to set.
+ *
+ * Return: '0' on Success; Error code otherwise.
+ */
+int dprtc_set_freq_compensation(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u32 freq_compensation)
+{
+ struct dprtc_get_freq_compensation *cmd_params;
+ struct fsl_mc_command cmd = { 0 };
+
+ cmd.header = mc_encode_cmd_header(DPRTC_CMDID_SET_FREQ_COMPENSATION,
+ cmd_flags,
+ token);
+ cmd_params = (struct dprtc_get_freq_compensation *)cmd.params;
+ cmd_params->freq_compensation = cpu_to_le32(freq_compensation);
+
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dprtc_get_freq_compensation() - Retrieves the frequency compensation value
+ *
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPRTC object
+ * @freq_compensation: Frequency compensation value
+ *
+ * Return: '0' on Success; Error code otherwise.
+ */
+int dprtc_get_freq_compensation(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u32 *freq_compensation)
+{
+ struct dprtc_get_freq_compensation *rsp_params;
+ struct fsl_mc_command cmd = { 0 };
+ int err;
+
+ cmd.header = mc_encode_cmd_header(DPRTC_CMDID_GET_FREQ_COMPENSATION,
+ cmd_flags,
+ token);
+
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ rsp_params = (struct dprtc_get_freq_compensation *)cmd.params;
+ *freq_compensation = le32_to_cpu(rsp_params->freq_compensation);
+
+ return 0;
+}
+
+/**
+ * dprtc_get_time() - Returns the current RTC time.
+ *
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPRTC object
+ * @time: Current RTC time.
+ *
+ * Return: '0' on Success; Error code otherwise.
+ */
+int dprtc_get_time(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ uint64_t *time)
+{
+ struct dprtc_time *rsp_params;
+ struct fsl_mc_command cmd = { 0 };
+ int err;
+
+ cmd.header = mc_encode_cmd_header(DPRTC_CMDID_GET_TIME,
+ cmd_flags,
+ token);
+
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ rsp_params = (struct dprtc_time *)cmd.params;
+ *time = le64_to_cpu(rsp_params->time);
+
+ return 0;
+}
+
+/**
+ * dprtc_set_time() - Updates current RTC time.
+ *
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPRTC object
+ * @time: New RTC time.
+ *
+ * Return: '0' on Success; Error code otherwise.
+ */
+int dprtc_set_time(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ uint64_t time)
+{
+ struct dprtc_time *cmd_params;
+ struct fsl_mc_command cmd = { 0 };
+
+ cmd.header = mc_encode_cmd_header(DPRTC_CMDID_SET_TIME,
+ cmd_flags,
+ token);
+ cmd_params = (struct dprtc_time *)cmd.params;
+ cmd_params->time = cpu_to_le64(time);
+
+ return mc_send_command(mc_io, &cmd);
+}
diff --git a/drivers/net/ethernet/freescale/dpaa2/dprtc.h b/drivers/net/ethernet/freescale/dpaa2/dprtc.h
new file mode 100644
index 000000000000..fe19618d6cdf
--- /dev/null
+++ b/drivers/net/ethernet/freescale/dpaa2/dprtc.h
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2013-2016 Freescale Semiconductor Inc.
+ * Copyright 2016-2018 NXP
+ */
+
+#ifndef __FSL_DPRTC_H
+#define __FSL_DPRTC_H
+
+/* Data Path Real Time Counter API
+ * Contains initialization APIs and runtime control APIs for RTC
+ */
+
+struct fsl_mc_io;
+
+int dprtc_open(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ int dprtc_id,
+ u16 *token);
+
+int dprtc_close(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token);
+
+int dprtc_set_freq_compensation(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u32 freq_compensation);
+
+int dprtc_get_freq_compensation(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u32 *freq_compensation);
+
+int dprtc_get_time(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ uint64_t *time);
+
+int dprtc_set_time(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ uint64_t time);
+
+#endif /* __FSL_DPRTC_H */
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 4778b663653e..bf80855dd0dd 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -452,6 +452,10 @@ struct bufdesc_ex {
* initialisation.
*/
#define FEC_QUIRK_MIB_CLEAR (1 << 15)
+/* Only i.MX25/i.MX27/i.MX28 controller supports FRBR,FRSR registers,
+ * those FIFO receive registers are resolved in other platforms.
+ */
+#define FEC_QUIRK_HAS_FRREG (1 << 16)
struct bufdesc_prop {
int qid;
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 2708297e7795..6db69ba30dcd 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -91,14 +91,16 @@ static struct platform_device_id fec_devtype[] = {
.driver_data = 0,
}, {
.name = "imx25-fec",
- .driver_data = FEC_QUIRK_USE_GASKET | FEC_QUIRK_MIB_CLEAR,
+ .driver_data = FEC_QUIRK_USE_GASKET | FEC_QUIRK_MIB_CLEAR |
+ FEC_QUIRK_HAS_FRREG,
}, {
.name = "imx27-fec",
- .driver_data = FEC_QUIRK_MIB_CLEAR,
+ .driver_data = FEC_QUIRK_MIB_CLEAR | FEC_QUIRK_HAS_FRREG,
}, {
.name = "imx28-fec",
.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME |
- FEC_QUIRK_SINGLE_MDIO | FEC_QUIRK_HAS_RACC,
+ FEC_QUIRK_SINGLE_MDIO | FEC_QUIRK_HAS_RACC |
+ FEC_QUIRK_HAS_FRREG,
}, {
.name = "imx6q-fec",
.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
@@ -1158,7 +1160,7 @@ static void fec_enet_timeout_work(struct work_struct *work)
napi_disable(&fep->napi);
netif_tx_lock_bh(ndev);
fec_restart(ndev);
- netif_wake_queue(ndev);
+ netif_tx_wake_all_queues(ndev);
netif_tx_unlock_bh(ndev);
napi_enable(&fep->napi);
}
@@ -1273,7 +1275,7 @@ skb_done:
/* Since we have freed up a buffer, the ring is no longer full
*/
- if (netif_queue_stopped(ndev)) {
+ if (netif_tx_queue_stopped(nq)) {
entries_free = fec_enet_get_free_txdesc_num(txq);
if (entries_free >= txq->tx_wake_threshold)
netif_tx_wake_queue(nq);
@@ -1746,7 +1748,7 @@ static void fec_enet_adjust_link(struct net_device *ndev)
napi_disable(&fep->napi);
netif_tx_lock_bh(ndev);
fec_restart(ndev);
- netif_wake_queue(ndev);
+ netif_tx_wake_all_queues(ndev);
netif_tx_unlock_bh(ndev);
napi_enable(&fep->napi);
}
@@ -1946,16 +1948,15 @@ static int fec_enet_mii_probe(struct net_device *ndev)
/* mask with MAC supported features */
if (fep->quirks & FEC_QUIRK_HAS_GBIT) {
- phy_dev->supported &= PHY_GBIT_FEATURES;
- phy_dev->supported &= ~SUPPORTED_1000baseT_Half;
+ phy_set_max_speed(phy_dev, 1000);
+ phy_remove_link_mode(phy_dev,
+ ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
#if !defined(CONFIG_M5272)
- phy_dev->supported |= SUPPORTED_Pause;
+ phy_support_sym_pause(phy_dev);
#endif
}
else
- phy_dev->supported &= PHY_BASIC_FEATURES;
-
- phy_dev->advertising = phy_dev->supported;
+ phy_set_max_speed(phy_dev, 100);
fep->link = 0;
fep->full_duplex = 0;
@@ -2055,8 +2056,7 @@ static int fec_enet_mii_init(struct platform_device *pdev)
node = of_get_child_by_name(pdev->dev.of_node, "mdio");
err = of_mdiobus_register(fep->mii_bus, node);
- if (node)
- of_node_put(node);
+ of_node_put(node);
if (err)
goto err_out_free_mdiobus;
@@ -2164,7 +2164,13 @@ static void fec_enet_get_regs(struct net_device *ndev,
memset(buf, 0, regs->len);
for (i = 0; i < ARRAY_SIZE(fec_enet_register_offset); i++) {
- off = fec_enet_register_offset[i] / 4;
+ off = fec_enet_register_offset[i];
+
+ if ((off == FEC_R_BOUND || off == FEC_R_FSTART) &&
+ !(fep->quirks & FEC_QUIRK_HAS_FRREG))
+ continue;
+
+ off >>= 2;
buf[off] = readl(&theregs[off]);
}
}
@@ -2230,13 +2236,8 @@ static int fec_enet_set_pauseparam(struct net_device *ndev,
fep->pause_flag |= pause->rx_pause ? FEC_PAUSE_FLAG_ENABLE : 0;
fep->pause_flag |= pause->autoneg ? FEC_PAUSE_FLAG_AUTONEG : 0;
- if (pause->rx_pause || pause->autoneg) {
- ndev->phydev->supported |= ADVERTISED_Pause;
- ndev->phydev->advertising |= ADVERTISED_Pause;
- } else {
- ndev->phydev->supported &= ~ADVERTISED_Pause;
- ndev->phydev->advertising &= ~ADVERTISED_Pause;
- }
+ phy_set_sym_pause(ndev->phydev, pause->rx_pause, pause->tx_pause,
+ pause->autoneg);
if (pause->autoneg) {
if (netif_running(ndev))
@@ -2247,7 +2248,7 @@ static int fec_enet_set_pauseparam(struct net_device *ndev,
napi_disable(&fep->napi);
netif_tx_lock_bh(ndev);
fec_restart(ndev);
- netif_wake_queue(ndev);
+ netif_tx_wake_all_queues(ndev);
netif_tx_unlock_bh(ndev);
napi_enable(&fep->napi);
}
diff --git a/drivers/net/ethernet/freescale/fec_mpc52xx.c b/drivers/net/ethernet/freescale/fec_mpc52xx.c
index 6d7269d87a85..b90bab72efdb 100644
--- a/drivers/net/ethernet/freescale/fec_mpc52xx.c
+++ b/drivers/net/ethernet/freescale/fec_mpc52xx.c
@@ -305,7 +305,8 @@ static int mpc52xx_fec_close(struct net_device *dev)
* invariant will hold if you make sure that the netif_*_queue()
* calls are done at the proper times.
*/
-static int mpc52xx_fec_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t
+mpc52xx_fec_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct mpc52xx_fec_priv *priv = netdev_priv(dev);
struct bcom_fec_bd *bd;
diff --git a/drivers/net/ethernet/freescale/fman/mac.c b/drivers/net/ethernet/freescale/fman/mac.c
index a847b9c3b31a..d79e4e009d63 100644
--- a/drivers/net/ethernet/freescale/fman/mac.c
+++ b/drivers/net/ethernet/freescale/fman/mac.c
@@ -393,11 +393,7 @@ void fman_get_pause_cfg(struct mac_device *mac_dev, bool *rx_pause,
*/
/* get local capabilities */
- lcl_adv = 0;
- if (phy_dev->advertising & ADVERTISED_Pause)
- lcl_adv |= ADVERTISE_PAUSE_CAP;
- if (phy_dev->advertising & ADVERTISED_Asym_Pause)
- lcl_adv |= ADVERTISE_PAUSE_ASYM;
+ lcl_adv = ethtool_adv_to_lcl_adv_t(phy_dev->advertising);
/* get link partner capabilities */
rmt_adv = 0;
diff --git a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
index 2c2976a2dda6..7c548ed535da 100644
--- a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
+++ b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
@@ -481,7 +481,8 @@ static struct sk_buff *tx_skb_align_workaround(struct net_device *dev,
}
#endif
-static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t
+fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
cbd_t __iomem *bdp;
diff --git a/drivers/net/ethernet/freescale/fsl_pq_mdio.c b/drivers/net/ethernet/freescale/fsl_pq_mdio.c
index ac2c3f6a12bc..82722d05fedb 100644
--- a/drivers/net/ethernet/freescale/fsl_pq_mdio.c
+++ b/drivers/net/ethernet/freescale/fsl_pq_mdio.c
@@ -446,8 +446,8 @@ static int fsl_pq_mdio_probe(struct platform_device *pdev)
goto error;
}
- snprintf(new_bus->id, MII_BUS_ID_SIZE, "%s@%llx", np->name,
- (unsigned long long)res.start);
+ snprintf(new_bus->id, MII_BUS_ID_SIZE, "%pOFn@%llx", np,
+ (unsigned long long)res.start);
priv->map = of_iomap(np, 0);
if (!priv->map) {
diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
index f27f9bae1a4a..3c8da1a18ba0 100644
--- a/drivers/net/ethernet/freescale/gianfar.c
+++ b/drivers/net/ethernet/freescale/gianfar.c
@@ -102,8 +102,6 @@
#include <linux/phy_fixed.h>
#include <linux/of.h>
#include <linux/of_net.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
#include "gianfar.h"
@@ -112,7 +110,7 @@
const char gfar_driver_version[] = "2.0";
static int gfar_enet_open(struct net_device *dev);
-static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static netdev_tx_t gfar_start_xmit(struct sk_buff *skb, struct net_device *dev);
static void gfar_reset_task(struct work_struct *work);
static void gfar_timeout(struct net_device *dev);
static int gfar_close(struct net_device *dev);
@@ -1814,8 +1812,8 @@ static int init_phy(struct net_device *dev)
phydev->supported &= (GFAR_SUPPORTED | gigabit_support);
phydev->advertising = phydev->supported;
- /* Add support for flow control, but don't advertise it by default */
- phydev->supported |= (SUPPORTED_Pause | SUPPORTED_Asym_Pause);
+ /* Add support for flow control */
+ phy_support_asym_pause(phydev);
/* disable EEE autoneg, EEE not supported by eTSEC */
memset(&edata, 0, sizeof(struct ethtool_eee));
@@ -2334,7 +2332,7 @@ static inline bool gfar_csum_errata_76(struct gfar_private *priv,
/* This is called by the kernel when a frame is ready for transmission.
* It is pointed to by the dev->hard_start_xmit function pointer
*/
-static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct gfar_private *priv = netdev_priv(dev);
struct gfar_priv_tx_q *tx_queue = NULL;
@@ -3658,12 +3656,7 @@ static u32 gfar_get_flowctrl_cfg(struct gfar_private *priv)
if (phydev->asym_pause)
rmt_adv |= LPA_PAUSE_ASYM;
- lcl_adv = 0;
- if (phydev->advertising & ADVERTISED_Pause)
- lcl_adv |= ADVERTISE_PAUSE_CAP;
- if (phydev->advertising & ADVERTISED_Asym_Pause)
- lcl_adv |= ADVERTISE_PAUSE_ASYM;
-
+ lcl_adv = ethtool_adv_to_lcl_adv_t(phydev->advertising);
flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
if (flowctrl & FLOW_CTRL_TX)
val |= MACCFG1_TX_FLOW;
diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c
index 395a5266ea30..0d76e15cd6dd 100644
--- a/drivers/net/ethernet/freescale/gianfar_ethtool.c
+++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c
@@ -230,7 +230,7 @@ static unsigned int gfar_usecs2ticks(struct gfar_private *priv,
/* Make sure we return a number greater than 0
* if usecs > 0 */
- return (usecs * 1000 + count - 1) / count;
+ return DIV_ROUND_UP(usecs * 1000, count);
}
/* Convert ethernet clock ticks to microseconds */
@@ -503,65 +503,44 @@ static int gfar_spauseparam(struct net_device *dev,
struct gfar_private *priv = netdev_priv(dev);
struct phy_device *phydev = dev->phydev;
struct gfar __iomem *regs = priv->gfargrp[0].regs;
- u32 oldadv, newadv;
if (!phydev)
return -ENODEV;
- if (!(phydev->supported & SUPPORTED_Pause) ||
- (!(phydev->supported & SUPPORTED_Asym_Pause) &&
- (epause->rx_pause != epause->tx_pause)))
+ if (!phy_validate_pause(phydev, epause))
return -EINVAL;
priv->rx_pause_en = priv->tx_pause_en = 0;
+ phy_set_asym_pause(phydev, epause->rx_pause, epause->tx_pause);
if (epause->rx_pause) {
priv->rx_pause_en = 1;
if (epause->tx_pause) {
priv->tx_pause_en = 1;
- /* FLOW_CTRL_RX & TX */
- newadv = ADVERTISED_Pause;
- } else /* FLOW_CTLR_RX */
- newadv = ADVERTISED_Pause | ADVERTISED_Asym_Pause;
+ }
} else if (epause->tx_pause) {
priv->tx_pause_en = 1;
- /* FLOW_CTLR_TX */
- newadv = ADVERTISED_Asym_Pause;
- } else
- newadv = 0;
+ }
if (epause->autoneg)
priv->pause_aneg_en = 1;
else
priv->pause_aneg_en = 0;
- oldadv = phydev->advertising &
- (ADVERTISED_Pause | ADVERTISED_Asym_Pause);
- if (oldadv != newadv) {
- phydev->advertising &=
- ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause);
- phydev->advertising |= newadv;
- if (phydev->autoneg)
- /* inform link partner of our
- * new flow ctrl settings
- */
- return phy_start_aneg(phydev);
-
- if (!epause->autoneg) {
- u32 tempval;
- tempval = gfar_read(&regs->maccfg1);
- tempval &= ~(MACCFG1_TX_FLOW | MACCFG1_RX_FLOW);
-
- priv->tx_actual_en = 0;
- if (priv->tx_pause_en) {
- priv->tx_actual_en = 1;
- tempval |= MACCFG1_TX_FLOW;
- }
+ if (!epause->autoneg) {
+ u32 tempval = gfar_read(&regs->maccfg1);
- if (priv->rx_pause_en)
- tempval |= MACCFG1_RX_FLOW;
- gfar_write(&regs->maccfg1, tempval);
+ tempval &= ~(MACCFG1_TX_FLOW | MACCFG1_RX_FLOW);
+
+ priv->tx_actual_en = 0;
+ if (priv->tx_pause_en) {
+ priv->tx_actual_en = 1;
+ tempval |= MACCFG1_TX_FLOW;
}
+
+ if (priv->rx_pause_en)
+ tempval |= MACCFG1_RX_FLOW;
+ gfar_write(&regs->maccfg1, tempval);
}
return 0;
diff --git a/drivers/net/ethernet/freescale/ucc_geth.c b/drivers/net/ethernet/freescale/ucc_geth.c
index 22a817da861e..32e02700feaa 100644
--- a/drivers/net/ethernet/freescale/ucc_geth.c
+++ b/drivers/net/ethernet/freescale/ucc_geth.c
@@ -1742,12 +1742,7 @@ static int init_phy(struct net_device *dev)
if (priv->phy_interface == PHY_INTERFACE_MODE_SGMII)
uec_configure_serdes(dev);
- phydev->supported &= (SUPPORTED_MII |
- SUPPORTED_Autoneg |
- ADVERTISED_10baseT_Half |
- ADVERTISED_10baseT_Full |
- ADVERTISED_100baseT_Half |
- ADVERTISED_100baseT_Full);
+ phy_set_max_speed(phydev, SPEED_100);
if (priv->max_speed == SPEED_1000)
phydev->supported |= ADVERTISED_1000baseT_Full;
@@ -3083,7 +3078,8 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
/* This is called by the kernel when a frame is ready for transmission. */
/* It is pointed to by the dev->hard_start_xmit function pointer */
-static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t
+ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ucc_geth_private *ugeth = netdev_priv(dev);
#ifdef CONFIG_UGETH_TX_ON_DEMAND
diff --git a/drivers/net/ethernet/hisilicon/hip04_eth.c b/drivers/net/ethernet/hisilicon/hip04_eth.c
index 14374a856d30..be268dcde8fa 100644
--- a/drivers/net/ethernet/hisilicon/hip04_eth.c
+++ b/drivers/net/ethernet/hisilicon/hip04_eth.c
@@ -422,7 +422,8 @@ static void hip04_start_tx_timer(struct hip04_priv *priv)
ns, HRTIMER_MODE_REL);
}
-static int hip04_mac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+static netdev_tx_t
+hip04_mac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{
struct hip04_priv *priv = netdev_priv(ndev);
struct net_device_stats *stats = &ndev->stats;
diff --git a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
index c5727003af8c..471805ea363b 100644
--- a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
+++ b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
@@ -736,7 +736,7 @@ static int hix5hd2_fill_sg_desc(struct hix5hd2_priv *priv,
return 0;
}
-static int hix5hd2_net_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t hix5hd2_net_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct hix5hd2_priv *priv = netdev_priv(dev);
struct hix5hd2_desc *desc;
diff --git a/drivers/net/ethernet/hisilicon/hns/hnae.c b/drivers/net/ethernet/hisilicon/hns/hnae.c
index a051e582d541..79d03f8ee7b1 100644
--- a/drivers/net/ethernet/hisilicon/hns/hnae.c
+++ b/drivers/net/ethernet/hisilicon/hns/hnae.c
@@ -84,7 +84,7 @@ static void hnae_unmap_buffer(struct hnae_ring *ring, struct hnae_desc_cb *cb)
if (cb->type == DESC_TYPE_SKB)
dma_unmap_single(ring_to_dev(ring), cb->dma, cb->length,
ring_to_dma_dir(ring));
- else
+ else if (cb->length)
dma_unmap_page(ring_to_dev(ring), cb->dma, cb->length,
ring_to_dma_dir(ring));
}
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c
index 09e4061d1fa6..aaf72c055711 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c
@@ -319,7 +319,7 @@ static void hns_gmac_set_promisc(void *mac_drv, u8 en)
hns_gmac_set_uc_match(mac_drv, en);
}
-int hns_gmac_wait_fifo_clean(void *mac_drv)
+static int hns_gmac_wait_fifo_clean(void *mac_drv)
{
struct mac_driver *drv = (struct mac_driver *)mac_drv;
int wait_cnt;
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
index 6ed6f142427e..3613e400e816 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
@@ -837,8 +837,8 @@ static int hns_mac_get_info(struct hns_mac_cb *mac_cb)
*/
put_device(&mac_cb->phy_dev->mdio.dev);
- dev_dbg(mac_cb->dev, "mac%d phy_node: %s\n",
- mac_cb->mac_id, np->name);
+ dev_dbg(mac_cb->dev, "mac%d phy_node: %pOFn\n",
+ mac_cb->mac_id, np);
}
of_node_put(np);
@@ -855,8 +855,8 @@ static int hns_mac_get_info(struct hns_mac_cb *mac_cb)
* if the phy_dev is found
*/
put_device(&mac_cb->phy_dev->mdio.dev);
- dev_dbg(mac_cb->dev, "mac%d phy_node: %s\n",
- mac_cb->mac_id, np->name);
+ dev_dbg(mac_cb->dev, "mac%d phy_node: %pOFn\n",
+ mac_cb->mac_id, np);
}
of_node_put(np);
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
index f56855e63c96..28e907831b0e 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
@@ -40,9 +40,9 @@
#define SKB_TMP_LEN(SKB) \
(((SKB)->transport_header - (SKB)->mac_header) + tcp_hdrlen(SKB))
-static void fill_v2_desc(struct hnae_ring *ring, void *priv,
- int size, dma_addr_t dma, int frag_end,
- int buf_num, enum hns_desc_type type, int mtu)
+static void fill_v2_desc_hw(struct hnae_ring *ring, void *priv, int size,
+ int send_sz, dma_addr_t dma, int frag_end,
+ int buf_num, enum hns_desc_type type, int mtu)
{
struct hnae_desc *desc = &ring->desc[ring->next_to_use];
struct hnae_desc_cb *desc_cb = &ring->desc_cb[ring->next_to_use];
@@ -64,7 +64,7 @@ static void fill_v2_desc(struct hnae_ring *ring, void *priv,
desc_cb->type = type;
desc->addr = cpu_to_le64(dma);
- desc->tx.send_size = cpu_to_le16((u16)size);
+ desc->tx.send_size = cpu_to_le16((u16)send_sz);
/* config bd buffer end */
hnae_set_bit(rrcfv, HNSV2_TXD_VLD_B, 1);
@@ -133,6 +133,14 @@ static void fill_v2_desc(struct hnae_ring *ring, void *priv,
ring_ptr_move_fw(ring, next_to_use);
}
+static void fill_v2_desc(struct hnae_ring *ring, void *priv,
+ int size, dma_addr_t dma, int frag_end,
+ int buf_num, enum hns_desc_type type, int mtu)
+{
+ fill_v2_desc_hw(ring, priv, size, size, dma, frag_end,
+ buf_num, type, mtu);
+}
+
static const struct acpi_device_id hns_enet_acpi_match[] = {
{ "HISI00C1", 0 },
{ "HISI00C2", 0 },
@@ -289,15 +297,15 @@ static void fill_tso_desc(struct hnae_ring *ring, void *priv,
/* when the frag size is bigger than hardware, split this frag */
for (k = 0; k < frag_buf_num; k++)
- fill_v2_desc(ring, priv,
- (k == frag_buf_num - 1) ?
+ fill_v2_desc_hw(ring, priv, k == 0 ? size : 0,
+ (k == frag_buf_num - 1) ?
sizeoflast : BD_MAX_SEND_SIZE,
- dma + BD_MAX_SEND_SIZE * k,
- frag_end && (k == frag_buf_num - 1) ? 1 : 0,
- buf_num,
- (type == DESC_TYPE_SKB && !k) ?
+ dma + BD_MAX_SEND_SIZE * k,
+ frag_end && (k == frag_buf_num - 1) ? 1 : 0,
+ buf_num,
+ (type == DESC_TYPE_SKB && !k) ?
DESC_TYPE_SKB : DESC_TYPE_PAGE,
- mtu);
+ mtu);
}
netdev_tx_t hns_nic_net_xmit_hw(struct net_device *ndev,
@@ -1495,21 +1503,6 @@ static int hns_nic_do_ioctl(struct net_device *netdev, struct ifreq *ifr,
return phy_mii_ioctl(phy_dev, ifr, cmd);
}
-/* use only for netconsole to poll with the device without interrupt */
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void hns_nic_poll_controller(struct net_device *ndev)
-{
- struct hns_nic_priv *priv = netdev_priv(ndev);
- unsigned long flags;
- int i;
-
- local_irq_save(flags);
- for (i = 0; i < priv->ae_handle->q_num * 2; i++)
- napi_schedule(&priv->ring_data[i].napi);
- local_irq_restore(flags);
-}
-#endif
-
static netdev_tx_t hns_nic_net_xmit(struct sk_buff *skb,
struct net_device *ndev)
{
@@ -1962,9 +1955,6 @@ static const struct net_device_ops hns_nic_netdev_ops = {
.ndo_set_features = hns_nic_set_features,
.ndo_fix_features = hns_nic_fix_features,
.ndo_get_stats64 = hns_nic_get_stats64,
-#ifdef CONFIG_NET_POLL_CONTROLLER
- .ndo_poll_controller = hns_nic_poll_controller,
-#endif
.ndo_set_rx_mode = hns_nic_set_rx_mode,
.ndo_select_queue = hns_nic_select_queue,
};
diff --git a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h
index be9dc08ccf67..038326cfda93 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h
@@ -46,9 +46,6 @@ enum hclge_mbx_mac_vlan_subcode {
HCLGE_MBX_MAC_VLAN_MC_MODIFY, /* modify MC mac addr */
HCLGE_MBX_MAC_VLAN_MC_ADD, /* add new MC mac addr */
HCLGE_MBX_MAC_VLAN_MC_REMOVE, /* remove MC mac addr */
- HCLGE_MBX_MAC_VLAN_MC_FUNC_MTA_ENABLE, /* config func MTA enable */
- HCLGE_MBX_MAC_VLAN_MTA_TYPE_READ, /* read func MTA type */
- HCLGE_MBX_MAC_VLAN_MTA_STATUS_UPDATE, /* update MTA status */
};
/* below are per-VF vlan cfg subcodes */
diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.c b/drivers/net/ethernet/hisilicon/hns3/hnae3.c
index fff5be8078ac..781e5dee3c70 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hnae3.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.c
@@ -29,8 +29,8 @@ static bool hnae3_client_match(enum hnae3_client_type client_type,
return false;
}
-static void hnae3_set_client_init_flag(struct hnae3_client *client,
- struct hnae3_ae_dev *ae_dev, int inited)
+void hnae3_set_client_init_flag(struct hnae3_client *client,
+ struct hnae3_ae_dev *ae_dev, int inited)
{
switch (client->type) {
case HNAE3_CLIENT_KNIC:
@@ -46,6 +46,7 @@ static void hnae3_set_client_init_flag(struct hnae3_client *client,
break;
}
}
+EXPORT_SYMBOL(hnae3_set_client_init_flag);
static int hnae3_get_client_init_flag(struct hnae3_client *client,
struct hnae3_ae_dev *ae_dev)
@@ -86,14 +87,11 @@ static int hnae3_match_n_instantiate(struct hnae3_client *client,
/* now, (un-)instantiate client by calling lower layer */
if (is_reg) {
ret = ae_dev->ops->init_client_instance(client, ae_dev);
- if (ret) {
+ if (ret)
dev_err(&ae_dev->pdev->dev,
"fail to instantiate client, ret = %d\n", ret);
- return ret;
- }
- hnae3_set_client_init_flag(client, ae_dev, 1);
- return 0;
+ return ret;
}
if (hnae3_get_client_init_flag(client, ae_dev)) {
diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h
index 67befff0bfc5..055b40606dbc 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h
@@ -51,6 +51,7 @@
#define HNAE3_KNIC_CLIENT_INITED_B 0x3
#define HNAE3_UNIC_CLIENT_INITED_B 0x4
#define HNAE3_ROCE_CLIENT_INITED_B 0x5
+#define HNAE3_DEV_SUPPORT_FD_B 0x6
#define HNAE3_DEV_SUPPORT_ROCE_DCB_BITS (BIT(HNAE3_DEV_SUPPORT_DCB_B) |\
BIT(HNAE3_DEV_SUPPORT_ROCE_B))
@@ -61,6 +62,9 @@
#define hnae3_dev_dcb_supported(hdev) \
hnae3_get_bit(hdev->ae_dev->flag, HNAE3_DEV_SUPPORT_DCB_B)
+#define hnae3_dev_fd_supported(hdev) \
+ hnae3_get_bit((hdev)->ae_dev->flag, HNAE3_DEV_SUPPORT_FD_B)
+
#define ring_ptr_move_fw(ring, p) \
((ring)->p = ((ring)->p + 1) % (ring)->desc_num)
#define ring_ptr_move_bw(ring, p) \
@@ -84,10 +88,11 @@ struct hnae3_queue {
/*hnae3 loop mode*/
enum hnae3_loop {
- HNAE3_MAC_INTER_LOOP_MAC,
- HNAE3_MAC_INTER_LOOP_SERDES,
- HNAE3_MAC_INTER_LOOP_PHY,
- HNAE3_MAC_LOOP_NONE,
+ HNAE3_LOOP_APP,
+ HNAE3_LOOP_SERIAL_SERDES,
+ HNAE3_LOOP_PARALLEL_SERDES,
+ HNAE3_LOOP_PHY,
+ HNAE3_LOOP_NONE,
};
enum hnae3_client_type {
@@ -107,6 +112,7 @@ enum hnae3_media_type {
HNAE3_MEDIA_TYPE_FIBER,
HNAE3_MEDIA_TYPE_COPPER,
HNAE3_MEDIA_TYPE_BACKPLANE,
+ HNAE3_MEDIA_TYPE_NONE,
};
enum hnae3_reset_notify_type {
@@ -173,6 +179,7 @@ struct hnae3_ae_dev {
struct list_head node;
u32 flag;
enum hnae3_dev_type dev_type;
+ enum hnae3_reset_type reset_type;
void *priv;
};
@@ -309,8 +316,8 @@ struct hnae3_ae_ops {
int (*set_loopback)(struct hnae3_handle *handle,
enum hnae3_loop loop_mode, bool en);
- void (*set_promisc_mode)(struct hnae3_handle *handle, bool en_uc_pmc,
- bool en_mc_pmc);
+ int (*set_promisc_mode)(struct hnae3_handle *handle, bool en_uc_pmc,
+ bool en_mc_pmc);
int (*set_mtu)(struct hnae3_handle *handle, int new_mtu);
void (*get_pauseparam)(struct hnae3_handle *handle,
@@ -337,6 +344,8 @@ struct hnae3_ae_ops {
void (*get_mac_addr)(struct hnae3_handle *handle, u8 *p);
int (*set_mac_addr)(struct hnae3_handle *handle, void *p,
bool is_first);
+ int (*do_ioctl)(struct hnae3_handle *handle,
+ struct ifreq *ifr, int cmd);
int (*add_uc_addr)(struct hnae3_handle *handle,
const unsigned char *addr);
int (*rm_uc_addr)(struct hnae3_handle *handle,
@@ -346,8 +355,6 @@ struct hnae3_ae_ops {
const unsigned char *addr);
int (*rm_mc_addr)(struct hnae3_handle *handle,
const unsigned char *addr);
- int (*update_mta_status)(struct hnae3_handle *handle);
-
void (*set_tso_stats)(struct hnae3_handle *handle, int enable);
void (*update_stats)(struct hnae3_handle *handle,
struct net_device_stats *net_stats);
@@ -384,7 +391,7 @@ struct hnae3_ae_ops {
int vector_num,
struct hnae3_ring_chain_node *vr_chain);
- void (*reset_queue)(struct hnae3_handle *handle, u16 queue_id);
+ int (*reset_queue)(struct hnae3_handle *handle, u16 queue_id);
u32 (*get_fw_version)(struct hnae3_handle *handle);
void (*get_mdix_mode)(struct hnae3_handle *handle,
u8 *tp_mdix_ctrl, u8 *tp_mdix);
@@ -395,11 +402,11 @@ struct hnae3_ae_ops {
int (*set_vf_vlan_filter)(struct hnae3_handle *handle, int vfid,
u16 vlan, u8 qos, __be16 proto);
int (*enable_hw_strip_rxvtag)(struct hnae3_handle *handle, bool enable);
- void (*reset_event)(struct hnae3_handle *handle);
+ void (*reset_event)(struct pci_dev *pdev, struct hnae3_handle *handle);
void (*get_channels)(struct hnae3_handle *handle,
struct ethtool_channels *ch);
void (*get_tqps_and_rss_info)(struct hnae3_handle *h,
- u16 *free_tqps, u16 *max_rss_size);
+ u16 *alloc_tqps, u16 *max_rss_size);
int (*set_channels)(struct hnae3_handle *handle, u32 new_tqps_num);
void (*get_flowctrl_adv)(struct hnae3_handle *handle,
u32 *flowctrl_adv);
@@ -408,7 +415,21 @@ struct hnae3_ae_ops {
void (*get_link_mode)(struct hnae3_handle *handle,
unsigned long *supported,
unsigned long *advertising);
- void (*get_port_type)(struct hnae3_handle *handle, u8 *port_type);
+ int (*add_fd_entry)(struct hnae3_handle *handle,
+ struct ethtool_rxnfc *cmd);
+ int (*del_fd_entry)(struct hnae3_handle *handle,
+ struct ethtool_rxnfc *cmd);
+ void (*del_all_fd_entries)(struct hnae3_handle *handle,
+ bool clear_list);
+ int (*get_fd_rule_cnt)(struct hnae3_handle *handle,
+ struct ethtool_rxnfc *cmd);
+ int (*get_fd_rule_info)(struct hnae3_handle *handle,
+ struct ethtool_rxnfc *cmd);
+ int (*get_fd_all_rules)(struct hnae3_handle *handle,
+ struct ethtool_rxnfc *cmd, u32 *rule_locs);
+ int (*restore_fd_rules)(struct hnae3_handle *handle);
+ void (*enable_fd)(struct hnae3_handle *handle, bool enable);
+ pci_ers_result_t (*process_hw_error)(struct hnae3_ae_dev *ae_dev);
};
struct hnae3_dcb_ops {
@@ -459,6 +480,7 @@ struct hnae3_knic_private_info {
const struct hnae3_dcb_ops *dcb_ops;
u16 int_rl_setting;
+ enum pkt_hash_types rss_type;
};
struct hnae3_roce_private_info {
@@ -476,10 +498,20 @@ struct hnae3_unic_private_info {
struct hnae3_queue **tqp; /* array base of all TQPs of this instance */
};
-#define HNAE3_SUPPORT_MAC_LOOPBACK BIT(0)
+#define HNAE3_SUPPORT_APP_LOOPBACK BIT(0)
#define HNAE3_SUPPORT_PHY_LOOPBACK BIT(1)
-#define HNAE3_SUPPORT_SERDES_LOOPBACK BIT(2)
+#define HNAE3_SUPPORT_SERDES_SERIAL_LOOPBACK BIT(2)
#define HNAE3_SUPPORT_VF BIT(3)
+#define HNAE3_SUPPORT_SERDES_PARALLEL_LOOPBACK BIT(4)
+
+#define HNAE3_USER_UPE BIT(0) /* unicast promisc enabled by user */
+#define HNAE3_USER_MPE BIT(1) /* mulitcast promisc enabled by user */
+#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)
struct hnae3_handle {
struct hnae3_client *client;
@@ -499,6 +531,8 @@ struct hnae3_handle {
};
u32 numa_node_mask; /* for multi-chip support */
+
+ u8 netdev_flags;
};
#define hnae3_set_field(origin, mask, shift, val) \
@@ -521,4 +555,7 @@ void hnae3_register_ae_algo(struct hnae3_ae_algo *ae_algo);
void hnae3_unregister_client(struct hnae3_client *client);
int hnae3_register_client(struct hnae3_client *client);
+
+void hnae3_set_client_init_flag(struct hnae3_client *client,
+ struct hnae3_ae_dev *ae_dev, int inited);
#endif
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
index 955c4ab18b03..20fcf0d1c2ce 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
@@ -9,6 +9,7 @@
#include <linux/ipv6.h>
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/aer.h>
#include <linux/skbuff.h>
#include <linux/sctp.h>
#include <linux/vermagic.h>
@@ -21,6 +22,7 @@
static void hns3_clear_all_ring(struct hnae3_handle *h);
static void hns3_force_clear_all_rx_ring(struct hnae3_handle *h);
+static void hns3_remove_hw_addr(struct net_device *netdev);
static const char hns3_driver_name[] = "hns3";
const char hns3_driver_version[] = VERMAGIC_STRING;
@@ -66,6 +68,23 @@ static irqreturn_t hns3_irq_handle(int irq, void *vector)
return IRQ_HANDLED;
}
+/* This callback function is used to set affinity changes to the irq affinity
+ * masks when the irq_set_affinity_notifier function is used.
+ */
+static void hns3_nic_irq_affinity_notify(struct irq_affinity_notify *notify,
+ const cpumask_t *mask)
+{
+ struct hns3_enet_tqp_vector *tqp_vectors =
+ container_of(notify, struct hns3_enet_tqp_vector,
+ affinity_notify);
+
+ tqp_vectors->affinity_mask = *mask;
+}
+
+static void hns3_nic_irq_affinity_release(struct kref *ref)
+{
+}
+
static void hns3_nic_uninit_irq(struct hns3_nic_priv *priv)
{
struct hns3_enet_tqp_vector *tqp_vectors;
@@ -77,6 +96,10 @@ static void hns3_nic_uninit_irq(struct hns3_nic_priv *priv)
if (tqp_vectors->irq_init_flag != HNS3_VECTOR_INITED)
continue;
+ /* clear the affinity notifier and affinity mask */
+ irq_set_affinity_notifier(tqp_vectors->vector_irq, NULL);
+ irq_set_affinity_hint(tqp_vectors->vector_irq, NULL);
+
/* release the irq resource */
free_irq(tqp_vectors->vector_irq, tqp_vectors);
tqp_vectors->irq_init_flag = HNS3_VECTOR_NOT_INITED;
@@ -127,6 +150,15 @@ static int hns3_nic_init_irq(struct hns3_nic_priv *priv)
return ret;
}
+ tqp_vectors->affinity_notify.notify =
+ hns3_nic_irq_affinity_notify;
+ tqp_vectors->affinity_notify.release =
+ hns3_nic_irq_affinity_release;
+ irq_set_affinity_notifier(tqp_vectors->vector_irq,
+ &tqp_vectors->affinity_notify);
+ irq_set_affinity_hint(tqp_vectors->vector_irq,
+ &tqp_vectors->affinity_mask);
+
tqp_vectors->irq_init_flag = HNS3_VECTOR_INITED;
}
@@ -195,8 +227,6 @@ void hns3_set_vector_coalesce_tx_gl(struct hns3_enet_tqp_vector *tqp_vector,
static void hns3_vector_gl_rl_init(struct hns3_enet_tqp_vector *tqp_vector,
struct hns3_nic_priv *priv)
{
- struct hnae3_handle *h = priv->ae_handle;
-
/* initialize the configuration for interrupt coalescing.
* 1. GL (Interrupt Gap Limiter)
* 2. RL (Interrupt Rate Limiter)
@@ -209,9 +239,6 @@ static void hns3_vector_gl_rl_init(struct hns3_enet_tqp_vector *tqp_vector,
tqp_vector->tx_group.coal.int_gl = HNS3_INT_GL_50K;
tqp_vector->rx_group.coal.int_gl = HNS3_INT_GL_50K;
- /* Default: disable RL */
- h->kinfo.int_rl_setting = 0;
-
tqp_vector->int_adapt_down = HNS3_INT_ADAPT_DOWN_START;
tqp_vector->rx_group.coal.flow_level = HNS3_FLOW_LOW;
tqp_vector->tx_group.coal.flow_level = HNS3_FLOW_LOW;
@@ -277,12 +304,12 @@ static int hns3_nic_set_real_num_queue(struct net_device *netdev)
static u16 hns3_get_max_available_channels(struct hnae3_handle *h)
{
- u16 free_tqps, max_rss_size, max_tqps;
+ u16 alloc_tqps, max_rss_size, rss_size;
- h->ae_algo->ops->get_tqps_and_rss_info(h, &free_tqps, &max_rss_size);
- max_tqps = h->kinfo.num_tc * max_rss_size;
+ h->ae_algo->ops->get_tqps_and_rss_info(h, &alloc_tqps, &max_rss_size);
+ rss_size = alloc_tqps / h->kinfo.num_tc;
- return min_t(u16, max_tqps, (free_tqps + h->kinfo.num_tqps));
+ return min_t(u16, rss_size, max_rss_size);
}
static int hns3_nic_net_up(struct net_device *netdev)
@@ -433,26 +460,83 @@ static int hns3_nic_mc_unsync(struct net_device *netdev,
return 0;
}
+static u8 hns3_get_netdev_flags(struct net_device *netdev)
+{
+ u8 flags = 0;
+
+ if (netdev->flags & IFF_PROMISC) {
+ flags = HNAE3_USER_UPE | HNAE3_USER_MPE;
+ } else {
+ flags |= HNAE3_VLAN_FLTR;
+ if (netdev->flags & IFF_ALLMULTI)
+ flags |= HNAE3_USER_MPE;
+ }
+
+ return flags;
+}
+
static void hns3_nic_set_rx_mode(struct net_device *netdev)
{
struct hnae3_handle *h = hns3_get_handle(netdev);
+ u8 new_flags;
+ int ret;
- if (h->ae_algo->ops->set_promisc_mode) {
- if (netdev->flags & IFF_PROMISC)
- h->ae_algo->ops->set_promisc_mode(h, true, true);
- else if (netdev->flags & IFF_ALLMULTI)
- h->ae_algo->ops->set_promisc_mode(h, false, true);
- else
- h->ae_algo->ops->set_promisc_mode(h, false, false);
- }
- if (__dev_uc_sync(netdev, hns3_nic_uc_sync, hns3_nic_uc_unsync))
+ new_flags = hns3_get_netdev_flags(netdev);
+
+ ret = __dev_uc_sync(netdev, hns3_nic_uc_sync, hns3_nic_uc_unsync);
+ if (ret) {
netdev_err(netdev, "sync uc address fail\n");
+ if (ret == -ENOSPC)
+ new_flags |= HNAE3_OVERFLOW_UPE;
+ }
+
if (netdev->flags & IFF_MULTICAST) {
- if (__dev_mc_sync(netdev, hns3_nic_mc_sync, hns3_nic_mc_unsync))
+ ret = __dev_mc_sync(netdev, hns3_nic_mc_sync,
+ hns3_nic_mc_unsync);
+ if (ret) {
netdev_err(netdev, "sync mc address fail\n");
+ if (ret == -ENOSPC)
+ new_flags |= HNAE3_OVERFLOW_MPE;
+ }
+ }
+
+ hns3_update_promisc_mode(netdev, new_flags);
+ /* User mode Promisc mode enable and vlan filtering is disabled to
+ * let all packets in. MAC-VLAN Table overflow Promisc enabled and
+ * vlan fitering is enabled
+ */
+ hns3_enable_vlan_filter(netdev, new_flags & HNAE3_VLAN_FLTR);
+ h->netdev_flags = new_flags;
+}
+
+int hns3_update_promisc_mode(struct net_device *netdev, u8 promisc_flags)
+{
+ struct hns3_nic_priv *priv = netdev_priv(netdev);
+ struct hnae3_handle *h = priv->ae_handle;
- if (h->ae_algo->ops->update_mta_status)
- h->ae_algo->ops->update_mta_status(h);
+ if (h->ae_algo->ops->set_promisc_mode) {
+ return h->ae_algo->ops->set_promisc_mode(h,
+ promisc_flags & HNAE3_UPE,
+ promisc_flags & HNAE3_MPE);
+ }
+
+ return 0;
+}
+
+void hns3_enable_vlan_filter(struct net_device *netdev, bool enable)
+{
+ struct hns3_nic_priv *priv = netdev_priv(netdev);
+ struct hnae3_handle *h = priv->ae_handle;
+ bool last_state;
+
+ if (h->pdev->revision >= 0x21 && 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);
+ }
}
}
@@ -896,35 +980,28 @@ static int hns3_fill_desc_vtags(struct sk_buff *skb,
}
static int hns3_fill_desc(struct hns3_enet_ring *ring, void *priv,
- int size, dma_addr_t dma, int frag_end,
- enum hns_desc_type type)
+ int size, int frag_end, enum hns_desc_type type)
{
struct hns3_desc_cb *desc_cb = &ring->desc_cb[ring->next_to_use];
struct hns3_desc *desc = &ring->desc[ring->next_to_use];
+ struct device *dev = ring_to_dev(ring);
u32 ol_type_vlan_len_msec = 0;
u16 bdtp_fe_sc_vld_ra_ri = 0;
+ struct skb_frag_struct *frag;
+ unsigned int frag_buf_num;
u32 type_cs_vlan_tso = 0;
struct sk_buff *skb;
u16 inner_vtag = 0;
u16 out_vtag = 0;
+ unsigned int k;
+ int sizeoflast;
u32 paylen = 0;
+ dma_addr_t dma;
u16 mss = 0;
u8 ol4_proto;
u8 il4_proto;
int ret;
- /* The txbd's baseinfo of DESC_TYPE_PAGE & DESC_TYPE_SKB */
- desc_cb->priv = priv;
- desc_cb->length = size;
- desc_cb->dma = dma;
- desc_cb->type = type;
-
- /* now, fill the descriptor */
- desc->addr = cpu_to_le64(dma);
- desc->tx.send_size = cpu_to_le16((u16)size);
- hns3_set_txbd_baseinfo(&bdtp_fe_sc_vld_ra_ri, frag_end);
- desc->tx.bdtp_fe_sc_vld_ra_ri = cpu_to_le16(bdtp_fe_sc_vld_ra_ri);
-
if (type == DESC_TYPE_SKB) {
skb = (struct sk_buff *)priv;
paylen = skb->len;
@@ -965,38 +1042,47 @@ static int hns3_fill_desc(struct hns3_enet_ring *ring, void *priv,
desc->tx.mss = cpu_to_le16(mss);
desc->tx.vlan_tag = cpu_to_le16(inner_vtag);
desc->tx.outer_vlan_tag = cpu_to_le16(out_vtag);
- }
- /* move ring pointer to next.*/
- ring_ptr_move_fw(ring, next_to_use);
+ dma = dma_map_single(dev, skb->data, size, DMA_TO_DEVICE);
+ } else {
+ frag = (struct skb_frag_struct *)priv;
+ dma = skb_frag_dma_map(dev, frag, 0, size, DMA_TO_DEVICE);
+ }
- return 0;
-}
+ if (dma_mapping_error(ring->dev, dma)) {
+ ring->stats.sw_err_cnt++;
+ return -ENOMEM;
+ }
-static int hns3_fill_desc_tso(struct hns3_enet_ring *ring, void *priv,
- int size, dma_addr_t dma, int frag_end,
- enum hns_desc_type type)
-{
- unsigned int frag_buf_num;
- unsigned int k;
- int sizeoflast;
- int ret;
+ desc_cb->length = size;
frag_buf_num = (size + HNS3_MAX_BD_SIZE - 1) / HNS3_MAX_BD_SIZE;
sizeoflast = size % HNS3_MAX_BD_SIZE;
sizeoflast = sizeoflast ? sizeoflast : HNS3_MAX_BD_SIZE;
- /* When the frag size is bigger than hardware, split this frag */
+ /* When frag size is bigger than hardware limit, split this frag */
for (k = 0; k < frag_buf_num; k++) {
- ret = hns3_fill_desc(ring, priv,
- (k == frag_buf_num - 1) ?
- sizeoflast : HNS3_MAX_BD_SIZE,
- dma + HNS3_MAX_BD_SIZE * k,
- frag_end && (k == frag_buf_num - 1) ? 1 : 0,
- (type == DESC_TYPE_SKB && !k) ?
- DESC_TYPE_SKB : DESC_TYPE_PAGE);
- if (ret)
- return ret;
+ /* The txbd's baseinfo of DESC_TYPE_PAGE & DESC_TYPE_SKB */
+ desc_cb->priv = priv;
+ desc_cb->dma = dma + HNS3_MAX_BD_SIZE * k;
+ desc_cb->type = (type == DESC_TYPE_SKB && !k) ?
+ DESC_TYPE_SKB : DESC_TYPE_PAGE;
+
+ /* now, fill the descriptor */
+ desc->addr = cpu_to_le64(dma + HNS3_MAX_BD_SIZE * k);
+ desc->tx.send_size = cpu_to_le16((k == frag_buf_num - 1) ?
+ (u16)sizeoflast : (u16)HNS3_MAX_BD_SIZE);
+ hns3_set_txbd_baseinfo(&bdtp_fe_sc_vld_ra_ri,
+ frag_end && (k == frag_buf_num - 1) ?
+ 1 : 0);
+ desc->tx.bdtp_fe_sc_vld_ra_ri =
+ cpu_to_le16(bdtp_fe_sc_vld_ra_ri);
+
+ /* move ring pointer to next.*/
+ ring_ptr_move_fw(ring, next_to_use);
+
+ desc_cb = &ring->desc_cb[ring->next_to_use];
+ desc = &ring->desc[ring->next_to_use];
}
return 0;
@@ -1044,7 +1130,7 @@ static int hns3_nic_maybe_stop_tx(struct sk_buff **out_skb, int *bnum,
/* No. of segments (plus a header) */
buf_num = skb_shinfo(skb)->nr_frags + 1;
- if (buf_num > ring_space(ring))
+ if (unlikely(ring_space(ring) < buf_num))
return -EBUSY;
*bnum = buf_num;
@@ -1052,7 +1138,7 @@ static int hns3_nic_maybe_stop_tx(struct sk_buff **out_skb, int *bnum,
return 0;
}
-static void hns_nic_dma_unmap(struct hns3_enet_ring *ring, int next_to_use_orig)
+static void hns3_clear_desc(struct hns3_enet_ring *ring, int next_to_use_orig)
{
struct device *dev = ring_to_dev(ring);
unsigned int i;
@@ -1068,12 +1154,14 @@ static void hns_nic_dma_unmap(struct hns3_enet_ring *ring, int next_to_use_orig)
ring->desc_cb[ring->next_to_use].dma,
ring->desc_cb[ring->next_to_use].length,
DMA_TO_DEVICE);
- else
+ 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,
DMA_TO_DEVICE);
+ ring->desc_cb[ring->next_to_use].length = 0;
+
/* rollback one */
ring_ptr_move_bw(ring, next_to_use);
}
@@ -1085,12 +1173,10 @@ netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb, struct net_device *netdev)
struct hns3_nic_ring_data *ring_data =
&tx_ring_data(priv, skb->queue_mapping);
struct hns3_enet_ring *ring = ring_data->ring;
- struct device *dev = priv->dev;
struct netdev_queue *dev_queue;
struct skb_frag_struct *frag;
int next_to_use_head;
int next_to_use_frag;
- dma_addr_t dma;
int buf_num;
int seg_num;
int size;
@@ -1125,35 +1211,23 @@ netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb, struct net_device *netdev)
next_to_use_head = ring->next_to_use;
- dma = dma_map_single(dev, skb->data, size, DMA_TO_DEVICE);
- if (dma_mapping_error(dev, dma)) {
- netdev_err(netdev, "TX head DMA map failed\n");
- ring->stats.sw_err_cnt++;
- goto out_err_tx_ok;
- }
-
- ret = priv->ops.fill_desc(ring, skb, size, dma, seg_num == 1 ? 1 : 0,
- DESC_TYPE_SKB);
+ ret = priv->ops.fill_desc(ring, skb, size, seg_num == 1 ? 1 : 0,
+ DESC_TYPE_SKB);
if (ret)
- goto head_dma_map_err;
+ goto head_fill_err;
next_to_use_frag = ring->next_to_use;
/* Fill the fragments */
for (i = 1; i < seg_num; i++) {
frag = &skb_shinfo(skb)->frags[i - 1];
size = skb_frag_size(frag);
- dma = skb_frag_dma_map(dev, frag, 0, size, DMA_TO_DEVICE);
- if (dma_mapping_error(dev, dma)) {
- netdev_err(netdev, "TX frag(%d) DMA map failed\n", i);
- ring->stats.sw_err_cnt++;
- goto frag_dma_map_err;
- }
- ret = priv->ops.fill_desc(ring, skb_frag_page(frag), size, dma,
- seg_num - 1 == i ? 1 : 0,
- DESC_TYPE_PAGE);
+
+ ret = priv->ops.fill_desc(ring, frag, size,
+ seg_num - 1 == i ? 1 : 0,
+ DESC_TYPE_PAGE);
if (ret)
- goto frag_dma_map_err;
+ goto frag_fill_err;
}
/* Complete translate all packets */
@@ -1166,11 +1240,11 @@ netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb, struct net_device *netdev)
return NETDEV_TX_OK;
-frag_dma_map_err:
- hns_nic_dma_unmap(ring, next_to_use_frag);
+frag_fill_err:
+ hns3_clear_desc(ring, next_to_use_frag);
-head_dma_map_err:
- hns_nic_dma_unmap(ring, next_to_use_head);
+head_fill_err:
+ hns3_clear_desc(ring, next_to_use_head);
out_err_tx_ok:
dev_kfree_skb_any(skb);
@@ -1209,6 +1283,20 @@ static int hns3_nic_net_set_mac_address(struct net_device *netdev, void *p)
return 0;
}
+static int hns3_nic_do_ioctl(struct net_device *netdev,
+ struct ifreq *ifr, int cmd)
+{
+ struct hnae3_handle *h = hns3_get_handle(netdev);
+
+ if (!netif_running(netdev))
+ return -EINVAL;
+
+ if (!h->ae_algo->ops->do_ioctl)
+ return -EOPNOTSUPP;
+
+ return h->ae_algo->ops->do_ioctl(h, ifr, cmd);
+}
+
static int hns3_nic_set_features(struct net_device *netdev,
netdev_features_t features)
{
@@ -1218,13 +1306,10 @@ static int hns3_nic_set_features(struct net_device *netdev,
int ret;
if (changed & (NETIF_F_TSO | NETIF_F_TSO6)) {
- if (features & (NETIF_F_TSO | NETIF_F_TSO6)) {
- priv->ops.fill_desc = hns3_fill_desc_tso;
+ if (features & (NETIF_F_TSO | NETIF_F_TSO6))
priv->ops.maybe_stop_tx = hns3_nic_maybe_stop_tso;
- } else {
- priv->ops.fill_desc = hns3_fill_desc;
+ else
priv->ops.maybe_stop_tx = hns3_nic_maybe_stop_tx;
- }
}
if ((changed & NETIF_F_HW_VLAN_CTAG_FILTER) &&
@@ -1246,6 +1331,13 @@ static int hns3_nic_set_features(struct net_device *netdev,
return ret;
}
+ if ((changed & NETIF_F_NTUPLE) && h->ae_algo->ops->enable_fd) {
+ if (features & NETIF_F_NTUPLE)
+ h->ae_algo->ops->enable_fd(h, true);
+ else
+ h->ae_algo->ops->enable_fd(h, false);
+ }
+
netdev->features = features;
return 0;
}
@@ -1404,18 +1496,22 @@ static int hns3_vlan_rx_kill_vid(struct net_device *netdev,
return ret;
}
-static void hns3_restore_vlan(struct net_device *netdev)
+static int hns3_restore_vlan(struct net_device *netdev)
{
struct hns3_nic_priv *priv = netdev_priv(netdev);
+ int ret = 0;
u16 vid;
- int ret;
for_each_set_bit(vid, priv->active_vlans, VLAN_N_VID) {
ret = hns3_vlan_rx_add_vid(netdev, htons(ETH_P_8021Q), vid);
- if (ret)
- netdev_warn(netdev, "Restore vlan: %d filter, ret:%d\n",
- vid, ret);
+ if (ret) {
+ netdev_err(netdev, "Restore vlan: %d filter, ret:%d\n",
+ vid, ret);
+ return ret;
+ }
}
+
+ return ret;
}
static int hns3_ndo_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan,
@@ -1447,13 +1543,11 @@ static int hns3_nic_change_mtu(struct net_device *netdev, int new_mtu)
}
ret = h->ae_algo->ops->set_mtu(h, new_mtu);
- if (ret) {
+ if (ret)
netdev_err(netdev, "failed to change MTU in hardware %d\n",
ret);
- return ret;
- }
-
- netdev->mtu = new_mtu;
+ else
+ netdev->mtu = new_mtu;
/* if the netdev was running earlier, bring it up again */
if (if_running && hns3_nic_net_open(netdev))
@@ -1526,7 +1620,7 @@ static void hns3_nic_net_timeout(struct net_device *ndev)
/* request the reset */
if (h->ae_algo->ops->reset_event)
- h->ae_algo->ops->reset_event(h);
+ h->ae_algo->ops->reset_event(h->pdev, h);
}
static const struct net_device_ops hns3_nic_netdev_ops = {
@@ -1535,6 +1629,7 @@ static const struct net_device_ops hns3_nic_netdev_ops = {
.ndo_start_xmit = hns3_nic_net_xmit,
.ndo_tx_timeout = hns3_nic_net_timeout,
.ndo_set_mac_address = hns3_nic_net_set_mac_address,
+ .ndo_do_ioctl = hns3_nic_do_ioctl,
.ndo_change_mtu = hns3_nic_change_mtu,
.ndo_set_features = hns3_nic_set_features,
.ndo_get_stats64 = hns3_nic_get_stats64,
@@ -1584,6 +1679,13 @@ static void hns3_disable_sriov(struct pci_dev *pdev)
pci_disable_sriov(pdev);
}
+static void hns3_get_dev_capability(struct pci_dev *pdev,
+ struct hnae3_ae_dev *ae_dev)
+{
+ if (pdev->revision >= 0x21)
+ hnae3_set_bit(ae_dev->flag, HNAE3_DEV_SUPPORT_FD_B, 1);
+}
+
/* hns3_probe - Device initialization routine
* @pdev: PCI device information struct
* @ent: entry in hns3_pci_tbl
@@ -1609,6 +1711,8 @@ static int hns3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
ae_dev->pdev = pdev;
ae_dev->flag = ent->driver_data;
ae_dev->dev_type = HNAE3_DEV_KNIC;
+ ae_dev->reset_type = HNAE3_NONE_RESET;
+ hns3_get_dev_capability(pdev, ae_dev);
pci_set_drvdata(pdev, ae_dev);
hnae3_register_ae_dev(ae_dev);
@@ -1662,12 +1766,72 @@ static int hns3_pci_sriov_configure(struct pci_dev *pdev, int num_vfs)
return 0;
}
+static void hns3_shutdown(struct pci_dev *pdev)
+{
+ struct hnae3_ae_dev *ae_dev = pci_get_drvdata(pdev);
+
+ hnae3_unregister_ae_dev(ae_dev);
+ devm_kfree(&pdev->dev, ae_dev);
+ pci_set_drvdata(pdev, NULL);
+
+ if (system_state == SYSTEM_POWER_OFF)
+ pci_set_power_state(pdev, PCI_D3hot);
+}
+
+static pci_ers_result_t hns3_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t state)
+{
+ struct hnae3_ae_dev *ae_dev = pci_get_drvdata(pdev);
+ pci_ers_result_t ret;
+
+ dev_info(&pdev->dev, "PCI error detected, state(=%d)!!\n", state);
+
+ if (state == pci_channel_io_perm_failure)
+ return PCI_ERS_RESULT_DISCONNECT;
+
+ if (!ae_dev) {
+ dev_err(&pdev->dev,
+ "Can't recover - error happened during device init\n");
+ return PCI_ERS_RESULT_NONE;
+ }
+
+ if (ae_dev->ops->process_hw_error)
+ ret = ae_dev->ops->process_hw_error(ae_dev);
+ else
+ return PCI_ERS_RESULT_NONE;
+
+ return ret;
+}
+
+static pci_ers_result_t hns3_slot_reset(struct pci_dev *pdev)
+{
+ struct hnae3_ae_dev *ae_dev = pci_get_drvdata(pdev);
+ struct device *dev = &pdev->dev;
+
+ dev_info(dev, "requesting reset due to PCI error\n");
+
+ /* request the reset */
+ if (ae_dev->ops->reset_event) {
+ ae_dev->ops->reset_event(pdev, NULL);
+ return PCI_ERS_RESULT_RECOVERED;
+ }
+
+ return PCI_ERS_RESULT_DISCONNECT;
+}
+
+static const struct pci_error_handlers hns3_err_handler = {
+ .error_detected = hns3_error_detected,
+ .slot_reset = hns3_slot_reset,
+};
+
static struct pci_driver hns3_driver = {
.name = hns3_driver_name,
.id_table = hns3_pci_tbl,
.probe = hns3_probe,
.remove = hns3_remove,
+ .shutdown = hns3_shutdown,
.sriov_configure = hns3_pci_sriov_configure,
+ .err_handler = &hns3_err_handler,
};
/* set default feature to hns3 */
@@ -1682,7 +1846,7 @@ static void hns3_set_default_feature(struct net_device *netdev)
NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO |
NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GSO_GRE |
NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL |
- NETIF_F_GSO_UDP_TUNNEL_CSUM;
+ NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC;
netdev->hw_enc_features |= NETIF_F_TSO_MANGLEID;
@@ -1694,24 +1858,30 @@ static void hns3_set_default_feature(struct net_device *netdev)
NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO |
NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GSO_GRE |
NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL |
- NETIF_F_GSO_UDP_TUNNEL_CSUM;
+ NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC;
netdev->vlan_features |=
NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM |
NETIF_F_SG | NETIF_F_GSO | NETIF_F_GRO |
NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GSO_GRE |
NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL |
- NETIF_F_GSO_UDP_TUNNEL_CSUM;
+ NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC;
netdev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX |
NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO |
NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GSO_GRE |
NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL |
- NETIF_F_GSO_UDP_TUNNEL_CSUM;
+ NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC;
- if (pdev->revision != 0x20)
+ if (pdev->revision >= 0x21) {
netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER;
+
+ if (!(h->flags & HNAE3_SUPPORT_VF)) {
+ netdev->hw_features |= NETIF_F_NTUPLE;
+ netdev->features |= NETIF_F_NTUPLE;
+ }
+ }
}
static int hns3_alloc_buffer(struct hns3_enet_ring *ring,
@@ -1749,7 +1919,7 @@ static int hns3_map_buffer(struct hns3_enet_ring *ring, struct hns3_desc_cb *cb)
cb->dma = dma_map_page(ring_to_dev(ring), cb->priv, 0,
cb->length, ring_to_dma_dir(ring));
- if (dma_mapping_error(ring_to_dev(ring), cb->dma))
+ if (unlikely(dma_mapping_error(ring_to_dev(ring), cb->dma)))
return -EIO;
return 0;
@@ -1761,7 +1931,7 @@ static void hns3_unmap_buffer(struct hns3_enet_ring *ring,
if (cb->type == DESC_TYPE_SKB)
dma_unmap_single(ring_to_dev(ring), cb->dma, cb->length,
ring_to_dma_dir(ring));
- else
+ else if (cb->length)
dma_unmap_page(ring_to_dev(ring), cb->dma, cb->length,
ring_to_dma_dir(ring));
}
@@ -1912,9 +2082,10 @@ static int is_valid_clean_head(struct hns3_enet_ring *ring, int h)
return u > c ? (h > c && h <= u) : (h > c || h <= u);
}
-bool hns3_clean_tx_ring(struct hns3_enet_ring *ring, int budget)
+void hns3_clean_tx_ring(struct hns3_enet_ring *ring)
{
struct net_device *netdev = ring->tqp->handle->kinfo.netdev;
+ struct hns3_nic_priv *priv = netdev_priv(netdev);
struct netdev_queue *dev_queue;
int bytes, pkts;
int head;
@@ -1923,7 +2094,7 @@ bool hns3_clean_tx_ring(struct hns3_enet_ring *ring, int budget)
rmb(); /* Make sure head is ready before touch any data */
if (is_ring_empty(ring) || head == ring->next_to_clean)
- return true; /* no data to poll */
+ return; /* no data to poll */
if (unlikely(!is_valid_clean_head(ring, head))) {
netdev_err(netdev, "wrong head (%d, %d-%d)\n", head,
@@ -1932,16 +2103,15 @@ bool hns3_clean_tx_ring(struct hns3_enet_ring *ring, int budget)
u64_stats_update_begin(&ring->syncp);
ring->stats.io_err_cnt++;
u64_stats_update_end(&ring->syncp);
- return true;
+ return;
}
bytes = 0;
pkts = 0;
- while (head != ring->next_to_clean && budget) {
+ while (head != ring->next_to_clean) {
hns3_nic_reclaim_one_desc(ring, &bytes, &pkts);
/* Issue prefetch for next Tx descriptor */
prefetch(&ring->desc_cb[ring->next_to_clean]);
- budget--;
}
ring->tqp_vector->tx_group.total_bytes += bytes;
@@ -1961,13 +2131,12 @@ bool hns3_clean_tx_ring(struct hns3_enet_ring *ring, int budget)
* sees the new next_to_clean.
*/
smp_mb();
- if (netif_tx_queue_stopped(dev_queue)) {
+ if (netif_tx_queue_stopped(dev_queue) &&
+ !test_bit(HNS3_NIC_STATE_DOWN, &priv->state)) {
netif_tx_wake_queue(dev_queue);
ring->stats.restart_queue++;
}
}
-
- return !!budget;
}
static int hns3_desc_unused(struct hns3_enet_ring *ring)
@@ -2092,7 +2261,6 @@ static void hns3_rx_checksum(struct hns3_enet_ring *ring, struct sk_buff *skb,
hnae3_get_bit(l234info, HNS3_RXD_L4E_B) ||
hnae3_get_bit(l234info, HNS3_RXD_OL3E_B) ||
hnae3_get_bit(l234info, HNS3_RXD_OL4E_B))) {
- netdev_err(netdev, "L3/L4 error pkt\n");
u64_stats_update_begin(&ring->syncp);
ring->stats.l3l4_csum_err++;
u64_stats_update_end(&ring->syncp);
@@ -2121,6 +2289,8 @@ static void hns3_rx_checksum(struct hns3_enet_ring *ring, struct sk_buff *skb,
l4_type == HNS3_L4_TYPE_SCTP))
skb->ip_summed = CHECKSUM_UNNECESSARY;
break;
+ default:
+ break;
}
}
@@ -2129,18 +2299,18 @@ static void hns3_rx_skb(struct hns3_enet_ring *ring, struct sk_buff *skb)
napi_gro_receive(&ring->tqp_vector->napi, skb);
}
-static u16 hns3_parse_vlan_tag(struct hns3_enet_ring *ring,
- struct hns3_desc *desc, u32 l234info)
+static bool hns3_parse_vlan_tag(struct hns3_enet_ring *ring,
+ struct hns3_desc *desc, u32 l234info,
+ u16 *vlan_tag)
{
struct pci_dev *pdev = ring->tqp->handle->pdev;
- u16 vlan_tag;
if (pdev->revision == 0x20) {
- vlan_tag = le16_to_cpu(desc->rx.ot_vlan_tag);
- if (!(vlan_tag & VLAN_VID_MASK))
- vlan_tag = le16_to_cpu(desc->rx.vlan_tag);
+ *vlan_tag = le16_to_cpu(desc->rx.ot_vlan_tag);
+ if (!(*vlan_tag & VLAN_VID_MASK))
+ *vlan_tag = le16_to_cpu(desc->rx.vlan_tag);
- return vlan_tag;
+ return (*vlan_tag != 0);
}
#define HNS3_STRP_OUTER_VLAN 0x1
@@ -2149,17 +2319,29 @@ static u16 hns3_parse_vlan_tag(struct hns3_enet_ring *ring,
switch (hnae3_get_field(l234info, HNS3_RXD_STRP_TAGP_M,
HNS3_RXD_STRP_TAGP_S)) {
case HNS3_STRP_OUTER_VLAN:
- vlan_tag = le16_to_cpu(desc->rx.ot_vlan_tag);
- break;
+ *vlan_tag = le16_to_cpu(desc->rx.ot_vlan_tag);
+ return true;
case HNS3_STRP_INNER_VLAN:
- vlan_tag = le16_to_cpu(desc->rx.vlan_tag);
- break;
+ *vlan_tag = le16_to_cpu(desc->rx.vlan_tag);
+ return true;
default:
- vlan_tag = 0;
- break;
+ return false;
}
+}
+
+static void hns3_set_rx_skb_rss_type(struct hns3_enet_ring *ring,
+ struct sk_buff *skb)
+{
+ struct hns3_desc *desc = &ring->desc[ring->next_to_clean];
+ struct hnae3_handle *handle = ring->tqp->handle;
+ enum pkt_hash_types rss_type;
- return vlan_tag;
+ if (le32_to_cpu(desc->rx.rss_hash))
+ rss_type = handle->kinfo.rss_type;
+ else
+ rss_type = PKT_HASH_TYPE_NONE;
+
+ skb_set_hash(skb, le32_to_cpu(desc->rx.rss_hash), rss_type);
}
static int hns3_handle_rx_bd(struct hns3_enet_ring *ring,
@@ -2261,16 +2443,13 @@ static int hns3_handle_rx_bd(struct hns3_enet_ring *ring,
if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) {
u16 vlan_tag;
- vlan_tag = hns3_parse_vlan_tag(ring, desc, l234info);
- if (vlan_tag & VLAN_VID_MASK)
+ if (hns3_parse_vlan_tag(ring, desc, l234info, &vlan_tag))
__vlan_hwaccel_put_tag(skb,
htons(ETH_P_8021Q),
vlan_tag);
}
if (unlikely(!hnae3_get_bit(bd_base_info, HNS3_RXD_VLD_B))) {
- netdev_err(netdev, "no valid bd,%016llx,%016llx\n",
- ((u64 *)desc)[0], ((u64 *)desc)[1]);
u64_stats_update_begin(&ring->syncp);
ring->stats.non_vld_descs++;
u64_stats_update_end(&ring->syncp);
@@ -2281,7 +2460,6 @@ static int hns3_handle_rx_bd(struct hns3_enet_ring *ring,
if (unlikely((!desc->rx.pkt_len) ||
hnae3_get_bit(l234info, HNS3_RXD_TRUNCAT_B))) {
- netdev_err(netdev, "truncated pkt\n");
u64_stats_update_begin(&ring->syncp);
ring->stats.err_pkt_len++;
u64_stats_update_end(&ring->syncp);
@@ -2291,7 +2469,6 @@ static int hns3_handle_rx_bd(struct hns3_enet_ring *ring,
}
if (unlikely(hnae3_get_bit(l234info, HNS3_RXD_L2E_B))) {
- netdev_err(netdev, "L2 error pkt\n");
u64_stats_update_begin(&ring->syncp);
ring->stats.l2_err++;
u64_stats_update_end(&ring->syncp);
@@ -2308,6 +2485,8 @@ static int hns3_handle_rx_bd(struct hns3_enet_ring *ring,
ring->tqp_vector->rx_group.total_bytes += skb->len;
hns3_rx_checksum(ring, skb, desc);
+ hns3_set_rx_skb_rss_type(ring, skb);
+
return 0;
}
@@ -2501,10 +2680,8 @@ static int hns3_nic_common_poll(struct napi_struct *napi, int budget)
/* Since the actual Tx work is minimal, we can give the Tx a larger
* budget and be more aggressive about cleaning up the Tx descriptors.
*/
- hns3_for_each_ring(ring, tqp_vector->tx_group) {
- if (!hns3_clean_tx_ring(ring, budget))
- clean_complete = false;
- }
+ hns3_for_each_ring(ring, tqp_vector->tx_group)
+ hns3_clean_tx_ring(ring);
/* make sure rx ring budget not smaller than 1 */
rx_budget = max(budget / tqp_vector->num_tqps, 1);
@@ -2556,7 +2733,7 @@ static int hns3_get_vector_ring_chain(struct hns3_enet_tqp_vector *tqp_vector,
chain = devm_kzalloc(&pdev->dev, sizeof(*chain),
GFP_KERNEL);
if (!chain)
- return -ENOMEM;
+ goto err_free_chain;
cur_chain->next = chain;
chain->tqp_index = tx_ring->tqp->tqp_index;
@@ -2586,7 +2763,7 @@ static int hns3_get_vector_ring_chain(struct hns3_enet_tqp_vector *tqp_vector,
while (rx_ring) {
chain = devm_kzalloc(&pdev->dev, sizeof(*chain), GFP_KERNEL);
if (!chain)
- return -ENOMEM;
+ goto err_free_chain;
cur_chain->next = chain;
chain->tqp_index = rx_ring->tqp->tqp_index;
@@ -2601,6 +2778,16 @@ static int hns3_get_vector_ring_chain(struct hns3_enet_tqp_vector *tqp_vector,
}
return 0;
+
+err_free_chain:
+ cur_chain = head->next;
+ while (cur_chain) {
+ chain = cur_chain->next;
+ devm_kfree(&pdev->dev, chain);
+ cur_chain = chain;
+ }
+
+ return -ENOMEM;
}
static void hns3_free_vector_ring_chain(struct hns3_enet_tqp_vector *tqp_vector,
@@ -2627,13 +2814,32 @@ static void hns3_add_ring_to_group(struct hns3_enet_ring_group *group,
group->count++;
}
+static void hns3_nic_set_cpumask(struct hns3_nic_priv *priv)
+{
+ struct pci_dev *pdev = priv->ae_handle->pdev;
+ struct hns3_enet_tqp_vector *tqp_vector;
+ int num_vectors = priv->vector_num;
+ int numa_node;
+ int vector_i;
+
+ numa_node = dev_to_node(&pdev->dev);
+
+ for (vector_i = 0; vector_i < num_vectors; vector_i++) {
+ tqp_vector = &priv->tqp_vector[vector_i];
+ cpumask_set_cpu(cpumask_local_spread(vector_i, numa_node),
+ &tqp_vector->affinity_mask);
+ }
+}
+
static int hns3_nic_init_vector_data(struct hns3_nic_priv *priv)
{
struct hnae3_ring_chain_node vector_ring_chain;
struct hnae3_handle *h = priv->ae_handle;
struct hns3_enet_tqp_vector *tqp_vector;
int ret = 0;
- u16 i;
+ int i;
+
+ hns3_nic_set_cpumask(priv);
for (i = 0; i < priv->vector_num; i++) {
tqp_vector = &priv->tqp_vector[i];
@@ -2678,13 +2884,19 @@ static int hns3_nic_init_vector_data(struct hns3_nic_priv *priv)
hns3_free_vector_ring_chain(tqp_vector, &vector_ring_chain);
if (ret)
- return ret;
+ goto map_ring_fail;
netif_napi_add(priv->netdev, &tqp_vector->napi,
hns3_nic_common_poll, NAPI_POLL_WEIGHT);
}
return 0;
+
+map_ring_fail:
+ while (i--)
+ netif_napi_del(&priv->tqp_vector[i].napi);
+
+ return ret;
}
static int hns3_nic_alloc_vector_data(struct hns3_nic_priv *priv)
@@ -2841,8 +3053,10 @@ static int hns3_queue_to_ring(struct hnae3_queue *tqp,
return ret;
ret = hns3_ring_get_cfg(tqp, priv, HNAE3_RING_TYPE_RX);
- if (ret)
+ if (ret) {
+ devm_kfree(priv->dev, priv->ring_data[tqp->tqp_index].ring);
return ret;
+ }
return 0;
}
@@ -2869,6 +3083,12 @@ static int hns3_get_ring_config(struct hns3_nic_priv *priv)
return 0;
err:
+ while (i--) {
+ devm_kfree(priv->dev, priv->ring_data[i].ring);
+ devm_kfree(priv->dev,
+ priv->ring_data[i + h->kinfo.num_tqps].ring);
+ }
+
devm_kfree(&pdev->dev, priv->ring_data);
return ret;
}
@@ -3036,9 +3256,6 @@ int hns3_uninit_all_ring(struct hns3_nic_priv *priv)
int i;
for (i = 0; i < h->kinfo.num_tqps; i++) {
- if (h->ae_algo->ops->reset_queue)
- h->ae_algo->ops->reset_queue(h, i);
-
hns3_fini_ring(priv->ring_data[i].ring);
hns3_fini_ring(priv->ring_data[i + h->kinfo.num_tqps].ring);
}
@@ -3046,11 +3263,12 @@ int hns3_uninit_all_ring(struct hns3_nic_priv *priv)
}
/* Set mac addr if it is configured. or leave it to the AE driver */
-static void hns3_init_mac_addr(struct net_device *netdev, bool init)
+static int hns3_init_mac_addr(struct net_device *netdev, bool init)
{
struct hns3_nic_priv *priv = netdev_priv(netdev);
struct hnae3_handle *h = priv->ae_handle;
u8 mac_addr_temp[ETH_ALEN];
+ int ret = 0;
if (h->ae_algo->ops->get_mac_addr && init) {
h->ae_algo->ops->get_mac_addr(h, mac_addr_temp);
@@ -3065,42 +3283,53 @@ static void hns3_init_mac_addr(struct net_device *netdev, bool init)
}
if (h->ae_algo->ops->set_mac_addr)
- h->ae_algo->ops->set_mac_addr(h, netdev->dev_addr, true);
+ ret = h->ae_algo->ops->set_mac_addr(h, netdev->dev_addr, true);
+ return ret;
}
-static void hns3_uninit_mac_addr(struct net_device *netdev)
+static int hns3_restore_fd_rules(struct net_device *netdev)
{
- struct hns3_nic_priv *priv = netdev_priv(netdev);
- struct hnae3_handle *h = priv->ae_handle;
+ struct hnae3_handle *h = hns3_get_handle(netdev);
+ int ret = 0;
- if (h->ae_algo->ops->rm_uc_addr)
- h->ae_algo->ops->rm_uc_addr(h, netdev->dev_addr);
+ if (h->ae_algo->ops->restore_fd_rules)
+ ret = h->ae_algo->ops->restore_fd_rules(h);
+
+ return ret;
+}
+
+static void hns3_del_all_fd_rules(struct net_device *netdev, bool clear_list)
+{
+ struct hnae3_handle *h = hns3_get_handle(netdev);
+
+ if (h->ae_algo->ops->del_all_fd_entries)
+ h->ae_algo->ops->del_all_fd_entries(h, clear_list);
}
static void hns3_nic_set_priv_ops(struct net_device *netdev)
{
struct hns3_nic_priv *priv = netdev_priv(netdev);
+ priv->ops.fill_desc = hns3_fill_desc;
if ((netdev->features & NETIF_F_TSO) ||
- (netdev->features & NETIF_F_TSO6)) {
- priv->ops.fill_desc = hns3_fill_desc_tso;
+ (netdev->features & NETIF_F_TSO6))
priv->ops.maybe_stop_tx = hns3_nic_maybe_stop_tso;
- } else {
- priv->ops.fill_desc = hns3_fill_desc;
+ else
priv->ops.maybe_stop_tx = hns3_nic_maybe_stop_tx;
- }
}
static int hns3_client_init(struct hnae3_handle *handle)
{
struct pci_dev *pdev = handle->pdev;
+ u16 alloc_tqps, max_rss_size;
struct hns3_nic_priv *priv;
struct net_device *netdev;
int ret;
- netdev = alloc_etherdev_mq(sizeof(struct hns3_nic_priv),
- hns3_get_max_available_channels(handle));
+ handle->ae_algo->ops->get_tqps_and_rss_info(handle, &alloc_tqps,
+ &max_rss_size);
+ netdev = alloc_etherdev_mq(sizeof(struct hns3_nic_priv), alloc_tqps);
if (!netdev)
return -ENOMEM;
@@ -3189,9 +3418,13 @@ static void hns3_client_uninit(struct hnae3_handle *handle, bool reset)
struct hns3_nic_priv *priv = netdev_priv(netdev);
int ret;
+ hns3_remove_hw_addr(netdev);
+
if (netdev->reg_state != NETREG_UNINITIALIZED)
unregister_netdev(netdev);
+ hns3_del_all_fd_rules(netdev, true);
+
hns3_force_clear_all_rx_ring(handle);
ret = hns3_nic_uninit_vector_data(priv);
@@ -3210,8 +3443,6 @@ static void hns3_client_uninit(struct hnae3_handle *handle, bool reset)
priv->ring_data = NULL;
- hns3_uninit_mac_addr(netdev);
-
free_netdev(netdev);
}
@@ -3267,20 +3498,48 @@ err_out:
return ret;
}
-static void hns3_recover_hw_addr(struct net_device *ndev)
+static int hns3_recover_hw_addr(struct net_device *ndev)
{
struct netdev_hw_addr_list *list;
struct netdev_hw_addr *ha, *tmp;
+ int ret = 0;
/* go through and sync uc_addr entries to the device */
list = &ndev->uc;
- list_for_each_entry_safe(ha, tmp, &list->list, list)
- hns3_nic_uc_sync(ndev, ha->addr);
+ list_for_each_entry_safe(ha, tmp, &list->list, list) {
+ ret = hns3_nic_uc_sync(ndev, ha->addr);
+ if (ret)
+ return ret;
+ }
/* go through and sync mc_addr entries to the device */
list = &ndev->mc;
+ list_for_each_entry_safe(ha, tmp, &list->list, list) {
+ ret = hns3_nic_mc_sync(ndev, ha->addr);
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+}
+
+static void hns3_remove_hw_addr(struct net_device *netdev)
+{
+ struct netdev_hw_addr_list *list;
+ struct netdev_hw_addr *ha, *tmp;
+
+ hns3_nic_uc_unsync(netdev, netdev->dev_addr);
+
+ /* go through and unsync uc_addr entries to the device */
+ list = &netdev->uc;
+ list_for_each_entry_safe(ha, tmp, &list->list, list)
+ hns3_nic_uc_unsync(netdev, ha->addr);
+
+ /* go through and unsync mc_addr entries to the device */
+ list = &netdev->mc;
list_for_each_entry_safe(ha, tmp, &list->list, list)
- hns3_nic_mc_sync(ndev, ha->addr);
+ if (ha->refcount > 1)
+ hns3_nic_mc_unsync(netdev, ha->addr);
}
static void hns3_clear_tx_ring(struct hns3_enet_ring *ring)
@@ -3388,7 +3647,10 @@ int hns3_nic_reset_all_ring(struct hnae3_handle *h)
int ret;
for (i = 0; i < h->kinfo.num_tqps; i++) {
- h->ae_algo->ops->reset_queue(h, i);
+ ret = h->ae_algo->ops->reset_queue(h, i);
+ if (ret)
+ return ret;
+
hns3_init_ring_hw(priv->ring_data[i].ring);
/* We need to clear tx ring here because self test will
@@ -3419,6 +3681,31 @@ int hns3_nic_reset_all_ring(struct hnae3_handle *h)
return 0;
}
+static void hns3_store_coal(struct hns3_nic_priv *priv)
+{
+ /* ethtool only support setting and querying one coal
+ * configuation for now, so save the vector 0' coal
+ * configuation here in order to restore it.
+ */
+ memcpy(&priv->tx_coal, &priv->tqp_vector[0].tx_group.coal,
+ sizeof(struct hns3_enet_coalesce));
+ memcpy(&priv->rx_coal, &priv->tqp_vector[0].rx_group.coal,
+ sizeof(struct hns3_enet_coalesce));
+}
+
+static void hns3_restore_coal(struct hns3_nic_priv *priv)
+{
+ u16 vector_num = priv->vector_num;
+ int i;
+
+ for (i = 0; i < vector_num; i++) {
+ memcpy(&priv->tqp_vector[i].tx_group.coal, &priv->tx_coal,
+ sizeof(struct hns3_enet_coalesce));
+ memcpy(&priv->tqp_vector[i].rx_group.coal, &priv->rx_coal,
+ sizeof(struct hns3_enet_coalesce));
+ }
+}
+
static int hns3_reset_notify_down_enet(struct hnae3_handle *handle)
{
struct hnae3_knic_private_info *kinfo = &handle->kinfo;
@@ -3452,19 +3739,40 @@ static int hns3_reset_notify_init_enet(struct hnae3_handle *handle)
{
struct net_device *netdev = handle->kinfo.netdev;
struct hns3_nic_priv *priv = netdev_priv(netdev);
+ bool vlan_filter_enable;
int ret;
- hns3_init_mac_addr(netdev, false);
- hns3_nic_set_rx_mode(netdev);
- hns3_recover_hw_addr(netdev);
+ ret = hns3_init_mac_addr(netdev, false);
+ if (ret)
+ return ret;
+
+ ret = hns3_recover_hw_addr(netdev);
+ if (ret)
+ return ret;
+
+ ret = hns3_update_promisc_mode(netdev, handle->netdev_flags);
+ if (ret)
+ return ret;
+
+ vlan_filter_enable = netdev->flags & IFF_PROMISC ? false : true;
+ hns3_enable_vlan_filter(netdev, vlan_filter_enable);
/* Hardware table is only clear when pf resets */
- if (!(handle->flags & HNAE3_SUPPORT_VF))
- hns3_restore_vlan(netdev);
+ if (!(handle->flags & HNAE3_SUPPORT_VF)) {
+ ret = hns3_restore_vlan(netdev);
+ if (ret)
+ return ret;
+ }
+
+ ret = hns3_restore_fd_rules(netdev);
+ if (ret)
+ return ret;
/* Carrier off reporting is important to ethtool even BEFORE open */
netif_carrier_off(netdev);
+ hns3_restore_coal(priv);
+
ret = hns3_nic_init_vector_data(priv);
if (ret)
return ret;
@@ -3480,6 +3788,7 @@ static int hns3_reset_notify_init_enet(struct hnae3_handle *handle)
static int hns3_reset_notify_uninit_enet(struct hnae3_handle *handle)
{
+ struct hnae3_ae_dev *ae_dev = pci_get_drvdata(handle->pdev);
struct net_device *netdev = handle->kinfo.netdev;
struct hns3_nic_priv *priv = netdev_priv(netdev);
int ret;
@@ -3492,11 +3801,20 @@ static int hns3_reset_notify_uninit_enet(struct hnae3_handle *handle)
return ret;
}
+ hns3_store_coal(priv);
+
ret = hns3_uninit_all_ring(priv);
if (ret)
netdev_err(netdev, "uninit ring error\n");
- hns3_uninit_mac_addr(netdev);
+ /* it is cumbersome for hardware to pick-and-choose entries for deletion
+ * from table space. Hence, for function reset software intervention is
+ * required to delete the entries
+ */
+ if (hns3_dev_ongoing_func_reset(ae_dev)) {
+ hns3_remove_hw_addr(netdev);
+ hns3_del_all_fd_rules(netdev, false);
+ }
return ret;
}
@@ -3526,24 +3844,7 @@ static int hns3_reset_notify(struct hnae3_handle *handle,
return ret;
}
-static void hns3_restore_coal(struct hns3_nic_priv *priv,
- struct hns3_enet_coalesce *tx,
- struct hns3_enet_coalesce *rx)
-{
- u16 vector_num = priv->vector_num;
- int i;
-
- for (i = 0; i < vector_num; i++) {
- memcpy(&priv->tqp_vector[i].tx_group.coal, tx,
- sizeof(struct hns3_enet_coalesce));
- memcpy(&priv->tqp_vector[i].rx_group.coal, rx,
- sizeof(struct hns3_enet_coalesce));
- }
-}
-
-static int hns3_modify_tqp_num(struct net_device *netdev, u16 new_tqp_num,
- struct hns3_enet_coalesce *tx,
- struct hns3_enet_coalesce *rx)
+static int hns3_modify_tqp_num(struct net_device *netdev, u16 new_tqp_num)
{
struct hns3_nic_priv *priv = netdev_priv(netdev);
struct hnae3_handle *h = hns3_get_handle(netdev);
@@ -3561,7 +3862,7 @@ static int hns3_modify_tqp_num(struct net_device *netdev, u16 new_tqp_num,
if (ret)
goto err_alloc_vector;
- hns3_restore_coal(priv, tx, rx);
+ hns3_restore_coal(priv);
ret = hns3_nic_init_vector_data(priv);
if (ret)
@@ -3593,7 +3894,6 @@ int hns3_set_channels(struct net_device *netdev,
struct hns3_nic_priv *priv = netdev_priv(netdev);
struct hnae3_handle *h = hns3_get_handle(netdev);
struct hnae3_knic_private_info *kinfo = &h->kinfo;
- struct hns3_enet_coalesce tx_coal, rx_coal;
bool if_running = netif_running(netdev);
u32 new_tqp_num = ch->combined_count;
u16 org_tqp_num;
@@ -3625,15 +3925,7 @@ int hns3_set_channels(struct net_device *netdev,
goto open_netdev;
}
- /* Changing the tqp num may also change the vector num,
- * ethtool only support setting and querying one coal
- * configuation for now, so save the vector 0' coal
- * configuation here in order to restore it.
- */
- memcpy(&tx_coal, &priv->tqp_vector[0].tx_group.coal,
- sizeof(struct hns3_enet_coalesce));
- memcpy(&rx_coal, &priv->tqp_vector[0].rx_group.coal,
- sizeof(struct hns3_enet_coalesce));
+ hns3_store_coal(priv);
hns3_nic_dealloc_vector_data(priv);
@@ -3641,10 +3933,9 @@ int hns3_set_channels(struct net_device *netdev,
hns3_put_ring_config(priv);
org_tqp_num = h->kinfo.num_tqps;
- ret = hns3_modify_tqp_num(netdev, new_tqp_num, &tx_coal, &rx_coal);
+ ret = hns3_modify_tqp_num(netdev, new_tqp_num);
if (ret) {
- ret = hns3_modify_tqp_num(netdev, org_tqp_num,
- &tx_coal, &rx_coal);
+ ret = hns3_modify_tqp_num(netdev, org_tqp_num);
if (ret) {
/* If revert to old tqp failed, fatal error occurred */
dev_err(&netdev->dev,
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h
index cb450d7ec8c1..d3636d088aa3 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h
@@ -419,8 +419,7 @@ struct hns3_nic_ring_data {
struct hns3_nic_ops {
int (*fill_desc)(struct hns3_enet_ring *ring, void *priv,
- int size, dma_addr_t dma, int frag_end,
- enum hns_desc_type type);
+ int size, int frag_end, enum hns_desc_type type);
int (*maybe_stop_tx)(struct sk_buff **out_skb,
int *bnum, struct hns3_enet_ring *ring);
void (*get_rxd_bnum)(u32 bnum_flag, int *out_bnum);
@@ -491,7 +490,9 @@ struct hns3_enet_tqp_vector {
struct hns3_enet_ring_group rx_group;
struct hns3_enet_ring_group tx_group;
+ cpumask_t affinity_mask;
u16 num_tqps; /* total number of tqps in TQP vector */
+ struct irq_affinity_notify affinity_notify;
char name[HNAE3_INT_NAME_LEN];
@@ -541,6 +542,8 @@ struct hns3_nic_priv {
/* Vxlan/Geneve information */
struct hns3_udp_tunnel udp_tnl[HNS3_UDP_TNL_MAX];
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
+ struct hns3_enet_coalesce tx_coal;
+ struct hns3_enet_coalesce rx_coal;
};
union l3_hdr_info {
@@ -581,6 +584,11 @@ static inline void hns3_write_reg(void __iomem *base, u32 reg, u32 value)
writel(value, reg_addr + reg);
}
+static inline bool hns3_dev_ongoing_func_reset(struct hnae3_ae_dev *ae_dev)
+{
+ return (ae_dev && (ae_dev->reset_type == HNAE3_FUNC_RESET));
+}
+
#define hns3_write_dev(a, reg, value) \
hns3_write_reg((a)->io_base, (reg), (value))
@@ -615,7 +623,7 @@ void hns3_ethtool_set_ops(struct net_device *netdev);
int hns3_set_channels(struct net_device *netdev,
struct ethtool_channels *ch);
-bool hns3_clean_tx_ring(struct hns3_enet_ring *ring, int budget);
+void hns3_clean_tx_ring(struct hns3_enet_ring *ring);
int hns3_init_all_ring(struct hns3_nic_priv *priv);
int hns3_uninit_all_ring(struct hns3_nic_priv *priv);
int hns3_nic_reset_all_ring(struct hnae3_handle *h);
@@ -631,6 +639,9 @@ void hns3_set_vector_coalesce_tx_gl(struct hns3_enet_tqp_vector *tqp_vector,
void hns3_set_vector_coalesce_rl(struct hns3_enet_tqp_vector *tqp_vector,
u32 rl_value);
+void hns3_enable_vlan_filter(struct net_device *netdev, bool enable);
+int hns3_update_promisc_mode(struct net_device *netdev, u8 promisc_flags);
+
#ifdef CONFIG_HNS3_DCB
void hns3_dcbnl_setup(struct hnae3_handle *handle);
#else
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
index f70ee6910ee2..a4762c2b8ba1 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
@@ -22,13 +22,13 @@ struct hns3_stats {
static const struct hns3_stats hns3_txq_stats[] = {
/* Tx per-queue statistics */
HNS3_TQP_STAT("io_err_cnt", io_err_cnt),
- HNS3_TQP_STAT("tx_dropped", sw_err_cnt),
+ HNS3_TQP_STAT("dropped", sw_err_cnt),
HNS3_TQP_STAT("seg_pkt_cnt", seg_pkt_cnt),
HNS3_TQP_STAT("packets", tx_pkts),
HNS3_TQP_STAT("bytes", tx_bytes),
HNS3_TQP_STAT("errors", tx_err_cnt),
- HNS3_TQP_STAT("tx_wake", restart_queue),
- HNS3_TQP_STAT("tx_busy", tx_busy),
+ HNS3_TQP_STAT("wake", restart_queue),
+ HNS3_TQP_STAT("busy", tx_busy),
};
#define HNS3_TXQ_STATS_COUNT ARRAY_SIZE(hns3_txq_stats)
@@ -36,7 +36,7 @@ static const struct hns3_stats hns3_txq_stats[] = {
static const struct hns3_stats hns3_rxq_stats[] = {
/* Rx per-queue statistics */
HNS3_TQP_STAT("io_err_cnt", io_err_cnt),
- HNS3_TQP_STAT("rx_dropped", sw_err_cnt),
+ HNS3_TQP_STAT("dropped", sw_err_cnt),
HNS3_TQP_STAT("seg_pkt_cnt", seg_pkt_cnt),
HNS3_TQP_STAT("packets", rx_pkts),
HNS3_TQP_STAT("bytes", rx_bytes),
@@ -53,7 +53,7 @@ static const struct hns3_stats hns3_rxq_stats[] = {
#define HNS3_TQP_STATS_COUNT (HNS3_TXQ_STATS_COUNT + HNS3_RXQ_STATS_COUNT)
-#define HNS3_SELF_TEST_TYPE_NUM 2
+#define HNS3_SELF_TEST_TYPE_NUM 3
#define HNS3_NIC_LB_TEST_PKT_NUM 1
#define HNS3_NIC_LB_TEST_RING_ID 0
#define HNS3_NIC_LB_TEST_PACKET_SIZE 128
@@ -71,6 +71,7 @@ struct hns3_link_mode_mapping {
static int hns3_lp_setup(struct net_device *ndev, enum hnae3_loop loop, bool en)
{
struct hnae3_handle *h = hns3_get_handle(ndev);
+ bool vlan_filter_enable;
int ret;
if (!h->ae_algo->ops->set_loopback ||
@@ -78,8 +79,9 @@ static int hns3_lp_setup(struct net_device *ndev, enum hnae3_loop loop, bool en)
return -EOPNOTSUPP;
switch (loop) {
- case HNAE3_MAC_INTER_LOOP_SERDES:
- case HNAE3_MAC_INTER_LOOP_MAC:
+ case HNAE3_LOOP_SERIAL_SERDES:
+ case HNAE3_LOOP_PARALLEL_SERDES:
+ case HNAE3_LOOP_APP:
ret = h->ae_algo->ops->set_loopback(h, loop, en);
break;
default:
@@ -90,7 +92,14 @@ static int hns3_lp_setup(struct net_device *ndev, enum hnae3_loop loop, bool en)
if (ret)
return ret;
- h->ae_algo->ops->set_promisc_mode(h, en, en);
+ if (en) {
+ h->ae_algo->ops->set_promisc_mode(h, true, true);
+ } else {
+ /* recover promisc mode before loopback test */
+ hns3_update_promisc_mode(ndev, h->netdev_flags);
+ vlan_filter_enable = ndev->flags & IFF_PROMISC ? false : true;
+ hns3_enable_vlan_filter(ndev, vlan_filter_enable);
+ }
return ret;
}
@@ -100,41 +109,26 @@ static int hns3_lp_up(struct net_device *ndev, enum hnae3_loop loop_mode)
struct hnae3_handle *h = hns3_get_handle(ndev);
int ret;
- if (!h->ae_algo->ops->start)
- return -EOPNOTSUPP;
-
ret = hns3_nic_reset_all_ring(h);
if (ret)
return ret;
- ret = h->ae_algo->ops->start(h);
- if (ret) {
- netdev_err(ndev,
- "hns3_lb_up ae start return error: %d\n", ret);
- return ret;
- }
-
ret = hns3_lp_setup(ndev, loop_mode, true);
usleep_range(10000, 20000);
- return ret;
+ return 0;
}
static int hns3_lp_down(struct net_device *ndev, enum hnae3_loop loop_mode)
{
- struct hnae3_handle *h = hns3_get_handle(ndev);
int ret;
- if (!h->ae_algo->ops->stop)
- return -EOPNOTSUPP;
-
ret = hns3_lp_setup(ndev, loop_mode, false);
if (ret) {
netdev_err(ndev, "lb_setup return error: %d\n", ret);
return ret;
}
- h->ae_algo->ops->stop(h);
usleep_range(10000, 20000);
return 0;
@@ -152,6 +146,7 @@ static void hns3_lp_setup_skb(struct sk_buff *skb)
packet = skb_put(skb, HNS3_NIC_LB_TEST_PACKET_SIZE);
memcpy(ethh->h_dest, ndev->dev_addr, ETH_ALEN);
+ ethh->h_dest[5] += 0x1f;
eth_zero_addr(ethh->h_source);
ethh->h_proto = htons(ETH_P_ARP);
skb_reset_mac_header(skb);
@@ -214,7 +209,7 @@ static void hns3_lb_clear_tx_ring(struct hns3_nic_priv *priv, u32 start_ringid,
for (i = start_ringid; i <= end_ringid; i++) {
struct hns3_enet_ring *ring = priv->ring_data[i].ring;
- hns3_clean_tx_ring(ring, budget);
+ hns3_clean_tx_ring(ring);
}
}
@@ -300,16 +295,21 @@ static void hns3_self_test(struct net_device *ndev,
if (eth_test->flags != ETH_TEST_FL_OFFLINE)
return;
- st_param[HNAE3_MAC_INTER_LOOP_MAC][0] = HNAE3_MAC_INTER_LOOP_MAC;
- st_param[HNAE3_MAC_INTER_LOOP_MAC][1] =
- h->flags & HNAE3_SUPPORT_MAC_LOOPBACK;
+ st_param[HNAE3_LOOP_APP][0] = HNAE3_LOOP_APP;
+ st_param[HNAE3_LOOP_APP][1] =
+ h->flags & HNAE3_SUPPORT_APP_LOOPBACK;
- st_param[HNAE3_MAC_INTER_LOOP_SERDES][0] = HNAE3_MAC_INTER_LOOP_SERDES;
- st_param[HNAE3_MAC_INTER_LOOP_SERDES][1] =
- h->flags & HNAE3_SUPPORT_SERDES_LOOPBACK;
+ st_param[HNAE3_LOOP_SERIAL_SERDES][0] = HNAE3_LOOP_SERIAL_SERDES;
+ st_param[HNAE3_LOOP_SERIAL_SERDES][1] =
+ h->flags & HNAE3_SUPPORT_SERDES_SERIAL_LOOPBACK;
+
+ st_param[HNAE3_LOOP_PARALLEL_SERDES][0] =
+ HNAE3_LOOP_PARALLEL_SERDES;
+ st_param[HNAE3_LOOP_PARALLEL_SERDES][1] =
+ h->flags & HNAE3_SUPPORT_SERDES_PARALLEL_LOOPBACK;
if (if_running)
- dev_close(ndev);
+ ndev->netdev_ops->ndo_stop(ndev);
#if IS_ENABLED(CONFIG_VLAN_8021Q)
/* Disable the vlan filter for selftest does not support it */
@@ -347,7 +347,7 @@ static void hns3_self_test(struct net_device *ndev,
#endif
if (if_running)
- dev_open(ndev);
+ ndev->netdev_ops->ndo_open(ndev);
}
static int hns3_get_sset_count(struct net_device *netdev, int stringset)
@@ -365,9 +365,10 @@ static int hns3_get_sset_count(struct net_device *netdev, int stringset)
case ETH_SS_TEST:
return ops->get_sset_count(h, stringset);
- }
- return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void *hns3_update_strings(u8 *data, const struct hns3_stats *stats,
@@ -383,7 +384,7 @@ static void *hns3_update_strings(u8 *data, const struct hns3_stats *stats,
data[ETH_GSTRING_LEN - 1] = '\0';
/* first, prepend the prefix string */
- n1 = snprintf(data, MAX_PREFIX_SIZE, "%s#%d_",
+ n1 = snprintf(data, MAX_PREFIX_SIZE, "%s%d_",
prefix, i);
n1 = min_t(uint, n1, MAX_PREFIX_SIZE - 1);
size_left = (ETH_GSTRING_LEN - 1) - n1;
@@ -431,6 +432,8 @@ static void hns3_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
case ETH_SS_TEST:
ops->get_strings(h, stringset, data);
break;
+ default:
+ break;
}
}
@@ -556,30 +559,72 @@ static int hns3_set_pauseparam(struct net_device *netdev,
return -EOPNOTSUPP;
}
+static void hns3_get_ksettings(struct hnae3_handle *h,
+ struct ethtool_link_ksettings *cmd)
+{
+ const struct hnae3_ae_ops *ops = h->ae_algo->ops;
+
+ /* 1.auto_neg & speed & duplex from cmd */
+ if (ops->get_ksettings_an_result)
+ ops->get_ksettings_an_result(h,
+ &cmd->base.autoneg,
+ &cmd->base.speed,
+ &cmd->base.duplex);
+
+ /* 2.get link mode*/
+ if (ops->get_link_mode)
+ ops->get_link_mode(h,
+ cmd->link_modes.supported,
+ cmd->link_modes.advertising);
+
+ /* 3.mdix_ctrl&mdix get from phy reg */
+ if (ops->get_mdix_mode)
+ ops->get_mdix_mode(h, &cmd->base.eth_tp_mdix_ctrl,
+ &cmd->base.eth_tp_mdix);
+}
+
static int hns3_get_link_ksettings(struct net_device *netdev,
struct ethtool_link_ksettings *cmd)
{
struct hnae3_handle *h = hns3_get_handle(netdev);
- u32 flowctrl_adv = 0;
+ const struct hnae3_ae_ops *ops;
+ u8 media_type;
u8 link_stat;
if (!h->ae_algo || !h->ae_algo->ops)
return -EOPNOTSUPP;
- /* 1.auto_neg & speed & duplex from cmd */
- if (netdev->phydev) {
+ ops = h->ae_algo->ops;
+ if (ops->get_media_type)
+ ops->get_media_type(h, &media_type);
+ else
+ return -EOPNOTSUPP;
+
+ switch (media_type) {
+ case HNAE3_MEDIA_TYPE_NONE:
+ cmd->base.port = PORT_NONE;
+ hns3_get_ksettings(h, cmd);
+ break;
+ case HNAE3_MEDIA_TYPE_FIBER:
+ cmd->base.port = PORT_FIBRE;
+ hns3_get_ksettings(h, cmd);
+ break;
+ case HNAE3_MEDIA_TYPE_COPPER:
+ if (!netdev->phydev)
+ return -EOPNOTSUPP;
+
+ cmd->base.port = PORT_TP;
phy_ethtool_ksettings_get(netdev->phydev, cmd);
+ break;
+ default:
+
+ netdev_warn(netdev, "Unknown media type");
return 0;
}
- if (h->ae_algo->ops->get_ksettings_an_result)
- h->ae_algo->ops->get_ksettings_an_result(h,
- &cmd->base.autoneg,
- &cmd->base.speed,
- &cmd->base.duplex);
- else
- return -EOPNOTSUPP;
+ /* mdio_support */
+ cmd->base.mdio_support = ETH_MDIO_SUPPORTS_C22;
link_stat = hns3_get_link(netdev);
if (!link_stat) {
@@ -587,36 +632,6 @@ static int hns3_get_link_ksettings(struct net_device *netdev,
cmd->base.duplex = DUPLEX_UNKNOWN;
}
- /* 2.get link mode and port type*/
- if (h->ae_algo->ops->get_link_mode)
- h->ae_algo->ops->get_link_mode(h,
- cmd->link_modes.supported,
- cmd->link_modes.advertising);
-
- cmd->base.port = PORT_NONE;
- if (h->ae_algo->ops->get_port_type)
- h->ae_algo->ops->get_port_type(h,
- &cmd->base.port);
-
- /* 3.mdix_ctrl&mdix get from phy reg */
- if (h->ae_algo->ops->get_mdix_mode)
- h->ae_algo->ops->get_mdix_mode(h, &cmd->base.eth_tp_mdix_ctrl,
- &cmd->base.eth_tp_mdix);
- /* 4.mdio_support */
- cmd->base.mdio_support = ETH_MDIO_SUPPORTS_C22;
-
- /* 5.get flow control setttings */
- if (h->ae_algo->ops->get_flowctrl_adv)
- h->ae_algo->ops->get_flowctrl_adv(h, &flowctrl_adv);
-
- if (flowctrl_adv & ADVERTISED_Pause)
- ethtool_link_ksettings_add_link_mode(cmd, advertising,
- Pause);
-
- if (flowctrl_adv & ADVERTISED_Asym_Pause)
- ethtool_link_ksettings_add_link_mode(cmd, advertising,
- Asym_Pause);
-
return 0;
}
@@ -671,12 +686,13 @@ static int hns3_set_rss(struct net_device *netdev, const u32 *indir,
if (!h->ae_algo || !h->ae_algo->ops || !h->ae_algo->ops->set_rss)
return -EOPNOTSUPP;
- /* currently we only support Toeplitz hash */
- if ((hfunc != ETH_RSS_HASH_NO_CHANGE) && (hfunc != ETH_RSS_HASH_TOP)) {
- netdev_err(netdev,
- "hash func not supported (only Toeplitz hash)\n");
+ if ((h->pdev->revision == 0x20 &&
+ hfunc != ETH_RSS_HASH_TOP) || (hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ hfunc != ETH_RSS_HASH_TOP && hfunc != ETH_RSS_HASH_XOR)) {
+ netdev_err(netdev, "hash func not supported\n");
return -EOPNOTSUPP;
}
+
if (!indir) {
netdev_err(netdev,
"set rss failed for indir is empty\n");
@@ -692,20 +708,33 @@ static int hns3_get_rxnfc(struct net_device *netdev,
{
struct hnae3_handle *h = hns3_get_handle(netdev);
- if (!h->ae_algo || !h->ae_algo->ops || !h->ae_algo->ops->get_rss_tuple)
+ if (!h->ae_algo || !h->ae_algo->ops)
return -EOPNOTSUPP;
switch (cmd->cmd) {
case ETHTOOL_GRXRINGS:
- cmd->data = h->kinfo.rss_size;
- break;
+ cmd->data = h->kinfo.num_tqps;
+ return 0;
case ETHTOOL_GRXFH:
- return h->ae_algo->ops->get_rss_tuple(h, cmd);
+ if (h->ae_algo->ops->get_rss_tuple)
+ return h->ae_algo->ops->get_rss_tuple(h, cmd);
+ return -EOPNOTSUPP;
+ case ETHTOOL_GRXCLSRLCNT:
+ if (h->ae_algo->ops->get_fd_rule_cnt)
+ return h->ae_algo->ops->get_fd_rule_cnt(h, cmd);
+ return -EOPNOTSUPP;
+ case ETHTOOL_GRXCLSRULE:
+ if (h->ae_algo->ops->get_fd_rule_info)
+ return h->ae_algo->ops->get_fd_rule_info(h, cmd);
+ return -EOPNOTSUPP;
+ case ETHTOOL_GRXCLSRLALL:
+ if (h->ae_algo->ops->get_fd_all_rules)
+ return h->ae_algo->ops->get_fd_all_rules(h, cmd,
+ rule_locs);
+ return -EOPNOTSUPP;
default:
return -EOPNOTSUPP;
}
-
- return 0;
}
static int hns3_change_all_ring_bd_num(struct hns3_nic_priv *priv,
@@ -788,12 +817,22 @@ static int hns3_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
{
struct hnae3_handle *h = hns3_get_handle(netdev);
- if (!h->ae_algo || !h->ae_algo->ops || !h->ae_algo->ops->set_rss_tuple)
+ if (!h->ae_algo || !h->ae_algo->ops)
return -EOPNOTSUPP;
switch (cmd->cmd) {
case ETHTOOL_SRXFH:
- return h->ae_algo->ops->set_rss_tuple(h, cmd);
+ if (h->ae_algo->ops->set_rss_tuple)
+ return h->ae_algo->ops->set_rss_tuple(h, cmd);
+ return -EOPNOTSUPP;
+ case ETHTOOL_SRXCLSRLINS:
+ if (h->ae_algo->ops->add_fd_entry)
+ return h->ae_algo->ops->add_fd_entry(h, cmd);
+ return -EOPNOTSUPP;
+ case ETHTOOL_SRXCLSRLDEL:
+ if (h->ae_algo->ops->del_fd_entry)
+ return h->ae_algo->ops->del_fd_entry(h, cmd);
+ return -EOPNOTSUPP;
default:
return -EOPNOTSUPP;
}
@@ -1047,6 +1086,7 @@ static const struct ethtool_ops hns3vf_ethtool_ops = {
.get_ethtool_stats = hns3_get_stats,
.get_sset_count = hns3_get_sset_count,
.get_rxnfc = hns3_get_rxnfc,
+ .set_rxnfc = hns3_set_rxnfc,
.get_rxfh_key_size = hns3_get_rss_key_size,
.get_rxfh_indir_size = hns3_get_rss_indir_size,
.get_rxfh = hns3_get_rss,
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/Makefile b/drivers/net/ethernet/hisilicon/hns3/hns3pf/Makefile
index cb8ddd043476..580e81743681 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/Makefile
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/Makefile
@@ -6,6 +6,6 @@
ccflags-y := -Idrivers/net/ethernet/hisilicon/hns3
obj-$(CONFIG_HNS3_HCLGE) += hclge.o
-hclge-objs = hclge_main.o hclge_cmd.o hclge_mdio.o hclge_tm.o hclge_mbx.o
+hclge-objs = hclge_main.o hclge_cmd.o hclge_mdio.o hclge_tm.o hclge_mbx.o hclge_err.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 ac13cb2b168e..690f62ed87dc 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c
@@ -24,15 +24,15 @@ static int hclge_ring_space(struct hclge_cmq_ring *ring)
return ring->desc_num - used - 1;
}
-static int is_valid_csq_clean_head(struct hclge_cmq_ring *ring, int h)
+static int is_valid_csq_clean_head(struct hclge_cmq_ring *ring, int head)
{
- int u = ring->next_to_use;
- int c = ring->next_to_clean;
+ int ntu = ring->next_to_use;
+ int ntc = ring->next_to_clean;
- if (unlikely(h >= ring->desc_num))
- return 0;
+ if (ntu > ntc)
+ return head >= ntc && head <= ntu;
- return u > c ? (h > c && h <= u) : (h > c || h <= u);
+ return head >= ntc || head <= ntu;
}
static int hclge_alloc_cmd_desc(struct hclge_cmq_ring *ring)
@@ -304,6 +304,10 @@ int hclge_cmd_queue_init(struct hclge_dev *hdev)
{
int ret;
+ /* Setup the lock for command queue */
+ spin_lock_init(&hdev->hw.cmq.csq.lock);
+ spin_lock_init(&hdev->hw.cmq.crq.lock);
+
/* Setup the queue entries for use cmd queue */
hdev->hw.cmq.csq.desc_num = HCLGE_NIC_CMQ_DESC_NUM;
hdev->hw.cmq.crq.desc_num = HCLGE_NIC_CMQ_DESC_NUM;
@@ -337,18 +341,20 @@ int hclge_cmd_init(struct hclge_dev *hdev)
u32 version;
int ret;
+ spin_lock_bh(&hdev->hw.cmq.csq.lock);
+ spin_lock_bh(&hdev->hw.cmq.crq.lock);
+
hdev->hw.cmq.csq.next_to_clean = 0;
hdev->hw.cmq.csq.next_to_use = 0;
hdev->hw.cmq.crq.next_to_clean = 0;
hdev->hw.cmq.crq.next_to_use = 0;
- /* Setup the lock for command queue */
- spin_lock_init(&hdev->hw.cmq.csq.lock);
- spin_lock_init(&hdev->hw.cmq.crq.lock);
-
hclge_cmd_init_regs(&hdev->hw);
clear_bit(HCLGE_STATE_CMD_DISABLE, &hdev->state);
+ spin_unlock_bh(&hdev->hw.cmq.crq.lock);
+ spin_unlock_bh(&hdev->hw.cmq.csq.lock);
+
ret = hclge_cmd_query_firmware_version(&hdev->hw, &version);
if (ret) {
dev_err(&hdev->pdev->dev,
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
index 821d4c2f84bd..872cd4bdd70d 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
@@ -175,21 +175,22 @@ enum hclge_opcode_type {
HCLGE_OPC_MAC_VLAN_REMOVE = 0x1001,
HCLGE_OPC_MAC_VLAN_TYPE_ID = 0x1002,
HCLGE_OPC_MAC_VLAN_INSERT = 0x1003,
+ HCLGE_OPC_MAC_VLAN_ALLOCATE = 0x1004,
HCLGE_OPC_MAC_ETHTYPE_ADD = 0x1010,
HCLGE_OPC_MAC_ETHTYPE_REMOVE = 0x1011,
- HCLGE_OPC_MAC_VLAN_MASK_SET = 0x1012,
-
- /* Multicast linear table commands */
- HCLGE_OPC_MTA_MAC_MODE_CFG = 0x1020,
- HCLGE_OPC_MTA_MAC_FUNC_CFG = 0x1021,
- HCLGE_OPC_MTA_TBL_ITEM_CFG = 0x1022,
- HCLGE_OPC_MTA_TBL_ITEM_QUERY = 0x1023,
/* VLAN commands */
HCLGE_OPC_VLAN_FILTER_CTRL = 0x1100,
HCLGE_OPC_VLAN_FILTER_PF_CFG = 0x1101,
HCLGE_OPC_VLAN_FILTER_VF_CFG = 0x1102,
+ /* Flow Director commands */
+ HCLGE_OPC_FD_MODE_CTRL = 0x1200,
+ HCLGE_OPC_FD_GET_ALLOCATION = 0x1201,
+ HCLGE_OPC_FD_KEY_CONFIG = 0x1202,
+ HCLGE_OPC_FD_TCAM_OP = 0x1203,
+ HCLGE_OPC_FD_AD_OP = 0x1204,
+
/* MDIO command */
HCLGE_OPC_MDIO_CONFIG = 0x1900,
@@ -208,6 +209,28 @@ enum hclge_opcode_type {
/* Led command */
HCLGE_OPC_LED_STATUS_CFG = 0xB000,
+
+ /* Error INT commands */
+ HCLGE_TM_SCH_ECC_INT_EN = 0x0829,
+ HCLGE_TM_SCH_ECC_ERR_RINT_CMD = 0x082d,
+ HCLGE_TM_SCH_ECC_ERR_RINT_CE = 0x082f,
+ HCLGE_TM_SCH_ECC_ERR_RINT_NFE = 0x0830,
+ HCLGE_TM_SCH_ECC_ERR_RINT_FE = 0x0831,
+ HCLGE_TM_SCH_MBIT_ECC_INFO_CMD = 0x0833,
+ HCLGE_COMMON_ECC_INT_CFG = 0x1505,
+ HCLGE_IGU_EGU_TNL_INT_QUERY = 0x1802,
+ HCLGE_IGU_EGU_TNL_INT_EN = 0x1803,
+ HCLGE_IGU_EGU_TNL_INT_CLR = 0x1804,
+ HCLGE_IGU_COMMON_INT_QUERY = 0x1805,
+ HCLGE_IGU_COMMON_INT_EN = 0x1806,
+ HCLGE_IGU_COMMON_INT_CLR = 0x1807,
+ HCLGE_TM_QCN_MEM_INT_CFG = 0x1A14,
+ HCLGE_TM_QCN_MEM_INT_INFO_CMD = 0x1A17,
+ HCLGE_PPP_CMD0_INT_CMD = 0x2100,
+ HCLGE_PPP_CMD1_INT_CMD = 0x2101,
+ HCLGE_NCSI_INT_QUERY = 0x2400,
+ HCLGE_NCSI_INT_EN = 0x2401,
+ HCLGE_NCSI_INT_CLR = 0x2402,
};
#define HCLGE_TQP_REG_OFFSET 0x80000
@@ -395,6 +418,8 @@ struct hclge_pf_res_cmd {
#define HCLGE_CFG_RSS_SIZE_M GENMASK(31, 24)
#define HCLGE_CFG_SPEED_ABILITY_S 0
#define HCLGE_CFG_SPEED_ABILITY_M GENMASK(7, 0)
+#define HCLGE_CFG_UMV_TBL_SPACE_S 16
+#define HCLGE_CFG_UMV_TBL_SPACE_M GENMASK(31, 16)
struct hclge_cfg_param_cmd {
__le32 offset;
@@ -584,13 +609,12 @@ struct hclge_mac_vlan_tbl_entry_cmd {
u8 rsv2[6];
};
-#define HCLGE_VLAN_MASK_EN_B 0
-struct hclge_mac_vlan_mask_entry_cmd {
- u8 rsv0[2];
- u8 vlan_mask;
- u8 rsv1;
- u8 mac_mask[6];
- u8 rsv2[14];
+#define HCLGE_UMV_SPC_ALC_B 0
+struct hclge_umv_spc_alc_cmd {
+ u8 allocate;
+ u8 rsv1[3];
+ __le32 space_size;
+ u8 rsv2[16];
};
#define HCLGE_MAC_MGR_MASK_VLAN_B BIT(0)
@@ -615,30 +639,6 @@ struct hclge_mac_mgr_tbl_entry_cmd {
u8 rsv3[2];
};
-#define HCLGE_CFG_MTA_MAC_SEL_S 0
-#define HCLGE_CFG_MTA_MAC_SEL_M GENMASK(1, 0)
-#define HCLGE_CFG_MTA_MAC_EN_B 7
-struct hclge_mta_filter_mode_cmd {
- u8 dmac_sel_en; /* Use lowest 2 bit as sel_mode, bit 7 as enable */
- u8 rsv[23];
-};
-
-#define HCLGE_CFG_FUNC_MTA_ACCEPT_B 0
-struct hclge_cfg_func_mta_filter_cmd {
- u8 accept; /* Only used lowest 1 bit */
- u8 function_id;
- u8 rsv[22];
-};
-
-#define HCLGE_CFG_MTA_ITEM_ACCEPT_B 0
-#define HCLGE_CFG_MTA_ITEM_IDX_S 0
-#define HCLGE_CFG_MTA_ITEM_IDX_M GENMASK(11, 0)
-struct hclge_cfg_func_mta_item_cmd {
- __le16 item_idx; /* Only used lowest 12 bit */
- u8 accept; /* Only used lowest 1 bit */
- u8 rsv[21];
-};
-
struct hclge_mac_vlan_add_cmd {
__le16 flags;
__le16 mac_addr_hi16;
@@ -778,6 +778,7 @@ struct hclge_reset_cmd {
};
#define HCLGE_CMD_SERDES_SERIAL_INNER_LOOP_B BIT(0)
+#define HCLGE_CMD_SERDES_PARALLEL_INNER_LOOP_B BIT(2)
#define HCLGE_CMD_SERDES_DONE_B BIT(0)
#define HCLGE_CMD_SERDES_SUCCESS_B BIT(1)
struct hclge_serdes_lb_cmd {
@@ -818,6 +819,76 @@ struct hclge_set_led_state_cmd {
u8 rsv2[20];
};
+struct hclge_get_fd_mode_cmd {
+ u8 mode;
+ u8 enable;
+ u8 rsv[22];
+};
+
+struct hclge_get_fd_allocation_cmd {
+ __le32 stage1_entry_num;
+ __le32 stage2_entry_num;
+ __le16 stage1_counter_num;
+ __le16 stage2_counter_num;
+ u8 rsv[12];
+};
+
+struct hclge_set_fd_key_config_cmd {
+ u8 stage;
+ u8 key_select;
+ u8 inner_sipv6_word_en;
+ u8 inner_dipv6_word_en;
+ u8 outer_sipv6_word_en;
+ u8 outer_dipv6_word_en;
+ u8 rsv1[2];
+ __le32 tuple_mask;
+ __le32 meta_data_mask;
+ u8 rsv2[8];
+};
+
+#define HCLGE_FD_EPORT_SW_EN_B 0
+struct hclge_fd_tcam_config_1_cmd {
+ u8 stage;
+ u8 xy_sel;
+ u8 port_info;
+ u8 rsv1[1];
+ __le32 index;
+ u8 entry_vld;
+ u8 rsv2[7];
+ u8 tcam_data[8];
+};
+
+struct hclge_fd_tcam_config_2_cmd {
+ u8 tcam_data[24];
+};
+
+struct hclge_fd_tcam_config_3_cmd {
+ u8 tcam_data[20];
+ u8 rsv[4];
+};
+
+#define HCLGE_FD_AD_DROP_B 0
+#define HCLGE_FD_AD_DIRECT_QID_B 1
+#define HCLGE_FD_AD_QID_S 2
+#define HCLGE_FD_AD_QID_M GENMASK(12, 2)
+#define HCLGE_FD_AD_USE_COUNTER_B 12
+#define HCLGE_FD_AD_COUNTER_NUM_S 13
+#define HCLGE_FD_AD_COUNTER_NUM_M GENMASK(20, 13)
+#define HCLGE_FD_AD_NXT_STEP_B 20
+#define HCLGE_FD_AD_NXT_KEY_S 21
+#define HCLGE_FD_AD_NXT_KEY_M GENMASK(26, 21)
+#define HCLGE_FD_AD_WR_RULE_ID_B 0
+#define HCLGE_FD_AD_RULE_ID_S 1
+#define HCLGE_FD_AD_RULE_ID_M GENMASK(13, 1)
+
+struct hclge_fd_ad_config_cmd {
+ u8 stage;
+ u8 rsv1[3];
+ __le32 index;
+ __le64 ad_data;
+ u8 rsv2[8];
+};
+
int hclge_cmd_init(struct hclge_dev *hdev);
static inline void hclge_write_reg(void __iomem *base, u32 reg, u32 value)
{
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c
index f08ebb7caaaf..e72f724123d7 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c
@@ -73,6 +73,7 @@ static int hclge_ieee_getets(struct hnae3_handle *h, struct ieee_ets *ets)
static int hclge_ets_validate(struct hclge_dev *hdev, struct ieee_ets *ets,
u8 *tc, bool *changed)
{
+ bool has_ets_tc = false;
u32 total_ets_bw = 0;
u8 max_tc = 0;
u8 i;
@@ -100,13 +101,14 @@ static int hclge_ets_validate(struct hclge_dev *hdev, struct ieee_ets *ets,
*changed = true;
total_ets_bw += ets->tc_tx_bw[i];
- break;
+ has_ets_tc = true;
+ break;
default:
return -EINVAL;
}
}
- if (total_ets_bw != BW_PERCENT)
+ if (has_ets_tc && total_ets_bw != BW_PERCENT)
return -EINVAL;
*tc = max_tc + 1;
@@ -182,7 +184,9 @@ static int hclge_ieee_setets(struct hnae3_handle *h, struct ieee_ets *ets)
if (ret)
return ret;
- hclge_tm_schd_info_update(hdev, num_tc);
+ ret = hclge_tm_schd_info_update(hdev, num_tc);
+ if (ret)
+ return ret;
ret = hclge_ieee_ets_to_tm_info(hdev, ets);
if (ret)
@@ -308,7 +312,9 @@ static int hclge_setup_tc(struct hnae3_handle *h, u8 tc, u8 *prio_tc)
return -EINVAL;
}
- hclge_tm_schd_info_update(hdev, tc);
+ ret = hclge_tm_schd_info_update(hdev, tc);
+ if (ret)
+ return ret;
ret = hclge_tm_prio_tc_info_update(hdev, prio_tc);
if (ret)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c
new file mode 100644
index 000000000000..123c37e653f3
--- /dev/null
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c
@@ -0,0 +1,1090 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Copyright (c) 2016-2017 Hisilicon Limited. */
+
+#include "hclge_err.h"
+
+static const struct hclge_hw_error hclge_imp_tcm_ecc_int[] = {
+ { .int_msk = BIT(0), .msg = "imp_itcm0_ecc_1bit_err" },
+ { .int_msk = BIT(1), .msg = "imp_itcm0_ecc_mbit_err" },
+ { .int_msk = BIT(2), .msg = "imp_itcm1_ecc_1bit_err" },
+ { .int_msk = BIT(3), .msg = "imp_itcm1_ecc_mbit_err" },
+ { .int_msk = BIT(4), .msg = "imp_itcm2_ecc_1bit_err" },
+ { .int_msk = BIT(5), .msg = "imp_itcm2_ecc_mbit_err" },
+ { .int_msk = BIT(6), .msg = "imp_itcm3_ecc_1bit_err" },
+ { .int_msk = BIT(7), .msg = "imp_itcm3_ecc_mbit_err" },
+ { .int_msk = BIT(8), .msg = "imp_dtcm0_mem0_ecc_1bit_err" },
+ { .int_msk = BIT(9), .msg = "imp_dtcm0_mem0_ecc_mbit_err" },
+ { .int_msk = BIT(10), .msg = "imp_dtcm0_mem1_ecc_1bit_err" },
+ { .int_msk = BIT(11), .msg = "imp_dtcm0_mem1_ecc_mbit_err" },
+ { .int_msk = BIT(12), .msg = "imp_dtcm1_mem0_ecc_1bit_err" },
+ { .int_msk = BIT(13), .msg = "imp_dtcm1_mem0_ecc_mbit_err" },
+ { .int_msk = BIT(14), .msg = "imp_dtcm1_mem1_ecc_1bit_err" },
+ { .int_msk = BIT(15), .msg = "imp_dtcm1_mem1_ecc_mbit_err" },
+ { /* sentinel */ }
+};
+
+static const struct hclge_hw_error hclge_imp_itcm4_ecc_int[] = {
+ { .int_msk = BIT(0), .msg = "imp_itcm4_ecc_1bit_err" },
+ { .int_msk = BIT(1), .msg = "imp_itcm4_ecc_mbit_err" },
+ { /* sentinel */ }
+};
+
+static const struct hclge_hw_error hclge_cmdq_nic_mem_ecc_int[] = {
+ { .int_msk = BIT(0), .msg = "cmdq_nic_rx_depth_ecc_1bit_err" },
+ { .int_msk = BIT(1), .msg = "cmdq_nic_rx_depth_ecc_mbit_err" },
+ { .int_msk = BIT(2), .msg = "cmdq_nic_tx_depth_ecc_1bit_err" },
+ { .int_msk = BIT(3), .msg = "cmdq_nic_tx_depth_ecc_mbit_err" },
+ { .int_msk = BIT(4), .msg = "cmdq_nic_rx_tail_ecc_1bit_err" },
+ { .int_msk = BIT(5), .msg = "cmdq_nic_rx_tail_ecc_mbit_err" },
+ { .int_msk = BIT(6), .msg = "cmdq_nic_tx_tail_ecc_1bit_err" },
+ { .int_msk = BIT(7), .msg = "cmdq_nic_tx_tail_ecc_mbit_err" },
+ { .int_msk = BIT(8), .msg = "cmdq_nic_rx_head_ecc_1bit_err" },
+ { .int_msk = BIT(9), .msg = "cmdq_nic_rx_head_ecc_mbit_err" },
+ { .int_msk = BIT(10), .msg = "cmdq_nic_tx_head_ecc_1bit_err" },
+ { .int_msk = BIT(11), .msg = "cmdq_nic_tx_head_ecc_mbit_err" },
+ { .int_msk = BIT(12), .msg = "cmdq_nic_rx_addr_ecc_1bit_err" },
+ { .int_msk = BIT(13), .msg = "cmdq_nic_rx_addr_ecc_mbit_err" },
+ { .int_msk = BIT(14), .msg = "cmdq_nic_tx_addr_ecc_1bit_err" },
+ { .int_msk = BIT(15), .msg = "cmdq_nic_tx_addr_ecc_mbit_err" },
+ { /* sentinel */ }
+};
+
+static const struct hclge_hw_error hclge_cmdq_rocee_mem_ecc_int[] = {
+ { .int_msk = BIT(0), .msg = "cmdq_rocee_rx_depth_ecc_1bit_err" },
+ { .int_msk = BIT(1), .msg = "cmdq_rocee_rx_depth_ecc_mbit_err" },
+ { .int_msk = BIT(2), .msg = "cmdq_rocee_tx_depth_ecc_1bit_err" },
+ { .int_msk = BIT(3), .msg = "cmdq_rocee_tx_depth_ecc_mbit_err" },
+ { .int_msk = BIT(4), .msg = "cmdq_rocee_rx_tail_ecc_1bit_err" },
+ { .int_msk = BIT(5), .msg = "cmdq_rocee_rx_tail_ecc_mbit_err" },
+ { .int_msk = BIT(6), .msg = "cmdq_rocee_tx_tail_ecc_1bit_err" },
+ { .int_msk = BIT(7), .msg = "cmdq_rocee_tx_tail_ecc_mbit_err" },
+ { .int_msk = BIT(8), .msg = "cmdq_rocee_rx_head_ecc_1bit_err" },
+ { .int_msk = BIT(9), .msg = "cmdq_rocee_rx_head_ecc_mbit_err" },
+ { .int_msk = BIT(10), .msg = "cmdq_rocee_tx_head_ecc_1bit_err" },
+ { .int_msk = BIT(11), .msg = "cmdq_rocee_tx_head_ecc_mbit_err" },
+ { .int_msk = BIT(12), .msg = "cmdq_rocee_rx_addr_ecc_1bit_err" },
+ { .int_msk = BIT(13), .msg = "cmdq_rocee_rx_addr_ecc_mbit_err" },
+ { .int_msk = BIT(14), .msg = "cmdq_rocee_tx_addr_ecc_1bit_err" },
+ { .int_msk = BIT(15), .msg = "cmdq_rocee_tx_addr_ecc_mbit_err" },
+ { /* sentinel */ }
+};
+
+static const struct hclge_hw_error hclge_tqp_int_ecc_int[] = {
+ { .int_msk = BIT(0), .msg = "tqp_int_cfg_even_ecc_1bit_err" },
+ { .int_msk = BIT(1), .msg = "tqp_int_cfg_odd_ecc_1bit_err" },
+ { .int_msk = BIT(2), .msg = "tqp_int_ctrl_even_ecc_1bit_err" },
+ { .int_msk = BIT(3), .msg = "tqp_int_ctrl_odd_ecc_1bit_err" },
+ { .int_msk = BIT(4), .msg = "tx_que_scan_int_ecc_1bit_err" },
+ { .int_msk = BIT(5), .msg = "rx_que_scan_int_ecc_1bit_err" },
+ { .int_msk = BIT(6), .msg = "tqp_int_cfg_even_ecc_mbit_err" },
+ { .int_msk = BIT(7), .msg = "tqp_int_cfg_odd_ecc_mbit_err" },
+ { .int_msk = BIT(8), .msg = "tqp_int_ctrl_even_ecc_mbit_err" },
+ { .int_msk = BIT(9), .msg = "tqp_int_ctrl_odd_ecc_mbit_err" },
+ { .int_msk = BIT(10), .msg = "tx_que_scan_int_ecc_mbit_err" },
+ { .int_msk = BIT(11), .msg = "rx_que_scan_int_ecc_mbit_err" },
+ { /* sentinel */ }
+};
+
+static const struct hclge_hw_error hclge_igu_com_err_int[] = {
+ { .int_msk = BIT(0), .msg = "igu_rx_buf0_ecc_mbit_err" },
+ { .int_msk = BIT(1), .msg = "igu_rx_buf0_ecc_1bit_err" },
+ { .int_msk = BIT(2), .msg = "igu_rx_buf1_ecc_mbit_err" },
+ { .int_msk = BIT(3), .msg = "igu_rx_buf1_ecc_1bit_err" },
+ { /* sentinel */ }
+};
+
+static const struct hclge_hw_error hclge_igu_egu_tnl_err_int[] = {
+ { .int_msk = BIT(0), .msg = "rx_buf_overflow" },
+ { .int_msk = BIT(1), .msg = "rx_stp_fifo_overflow" },
+ { .int_msk = BIT(2), .msg = "rx_stp_fifo_undeflow" },
+ { .int_msk = BIT(3), .msg = "tx_buf_overflow" },
+ { .int_msk = BIT(4), .msg = "tx_buf_underrun" },
+ { .int_msk = BIT(5), .msg = "rx_stp_buf_overflow" },
+ { /* sentinel */ }
+};
+
+static const struct hclge_hw_error hclge_ncsi_err_int[] = {
+ { .int_msk = BIT(0), .msg = "ncsi_tx_ecc_1bit_err" },
+ { .int_msk = BIT(1), .msg = "ncsi_tx_ecc_mbit_err" },
+ { /* sentinel */ }
+};
+
+static const struct hclge_hw_error hclge_ppp_mpf_int0[] = {
+ { .int_msk = BIT(0), .msg = "vf_vlan_ad_mem_ecc_1bit_err" },
+ { .int_msk = BIT(1), .msg = "umv_mcast_group_mem_ecc_1bit_err" },
+ { .int_msk = BIT(2), .msg = "umv_key_mem0_ecc_1bit_err" },
+ { .int_msk = BIT(3), .msg = "umv_key_mem1_ecc_1bit_err" },
+ { .int_msk = BIT(4), .msg = "umv_key_mem2_ecc_1bit_err" },
+ { .int_msk = BIT(5), .msg = "umv_key_mem3_ecc_1bit_err" },
+ { .int_msk = BIT(6), .msg = "umv_ad_mem_ecc_1bit_err" },
+ { .int_msk = BIT(7), .msg = "rss_tc_mode_mem_ecc_1bit_err" },
+ { .int_msk = BIT(8), .msg = "rss_idt_mem0_ecc_1bit_err" },
+ { .int_msk = BIT(9), .msg = "rss_idt_mem1_ecc_1bit_err" },
+ { .int_msk = BIT(10), .msg = "rss_idt_mem2_ecc_1bit_err" },
+ { .int_msk = BIT(11), .msg = "rss_idt_mem3_ecc_1bit_err" },
+ { .int_msk = BIT(12), .msg = "rss_idt_mem4_ecc_1bit_err" },
+ { .int_msk = BIT(13), .msg = "rss_idt_mem5_ecc_1bit_err" },
+ { .int_msk = BIT(14), .msg = "rss_idt_mem6_ecc_1bit_err" },
+ { .int_msk = BIT(15), .msg = "rss_idt_mem7_ecc_1bit_err" },
+ { .int_msk = BIT(16), .msg = "rss_idt_mem8_ecc_1bit_err" },
+ { .int_msk = BIT(17), .msg = "rss_idt_mem9_ecc_1bit_err" },
+ { .int_msk = BIT(18), .msg = "rss_idt_mem10_ecc_1bit_err" },
+ { .int_msk = BIT(19), .msg = "rss_idt_mem11_ecc_1bit_err" },
+ { .int_msk = BIT(20), .msg = "rss_idt_mem12_ecc_1bit_err" },
+ { .int_msk = BIT(21), .msg = "rss_idt_mem13_ecc_1bit_err" },
+ { .int_msk = BIT(22), .msg = "rss_idt_mem14_ecc_1bit_err" },
+ { .int_msk = BIT(23), .msg = "rss_idt_mem15_ecc_1bit_err" },
+ { .int_msk = BIT(24), .msg = "port_vlan_mem_ecc_1bit_err" },
+ { .int_msk = BIT(25), .msg = "mcast_linear_table_mem_ecc_1bit_err" },
+ { .int_msk = BIT(26), .msg = "mcast_result_mem_ecc_1bit_err" },
+ { .int_msk = BIT(27),
+ .msg = "flow_director_ad_mem0_ecc_1bit_err" },
+ { .int_msk = BIT(28),
+ .msg = "flow_director_ad_mem1_ecc_1bit_err" },
+ { .int_msk = BIT(29),
+ .msg = "rx_vlan_tag_memory_ecc_1bit_err" },
+ { .int_msk = BIT(30),
+ .msg = "Tx_UP_mapping_config_mem_ecc_1bit_err" },
+ { /* sentinel */ }
+};
+
+static const struct hclge_hw_error hclge_ppp_mpf_int1[] = {
+ { .int_msk = BIT(0), .msg = "vf_vlan_ad_mem_ecc_mbit_err" },
+ { .int_msk = BIT(1), .msg = "umv_mcast_group_mem_ecc_mbit_err" },
+ { .int_msk = BIT(2), .msg = "umv_key_mem0_ecc_mbit_err" },
+ { .int_msk = BIT(3), .msg = "umv_key_mem1_ecc_mbit_err" },
+ { .int_msk = BIT(4), .msg = "umv_key_mem2_ecc_mbit_err" },
+ { .int_msk = BIT(5), .msg = "umv_key_mem3_ecc_mbit_err" },
+ { .int_msk = BIT(6), .msg = "umv_ad_mem_ecc_mbit_erre" },
+ { .int_msk = BIT(7), .msg = "rss_tc_mode_mem_ecc_mbit_err" },
+ { .int_msk = BIT(8), .msg = "rss_idt_mem0_ecc_mbit_err" },
+ { .int_msk = BIT(9), .msg = "rss_idt_mem1_ecc_mbit_err" },
+ { .int_msk = BIT(10), .msg = "rss_idt_mem2_ecc_mbit_err" },
+ { .int_msk = BIT(11), .msg = "rss_idt_mem3_ecc_mbit_err" },
+ { .int_msk = BIT(12), .msg = "rss_idt_mem4_ecc_mbit_err" },
+ { .int_msk = BIT(13), .msg = "rss_idt_mem5_ecc_mbit_err" },
+ { .int_msk = BIT(14), .msg = "rss_idt_mem6_ecc_mbit_err" },
+ { .int_msk = BIT(15), .msg = "rss_idt_mem7_ecc_mbit_err" },
+ { .int_msk = BIT(16), .msg = "rss_idt_mem8_ecc_mbit_err" },
+ { .int_msk = BIT(17), .msg = "rss_idt_mem9_ecc_mbit_err" },
+ { .int_msk = BIT(18), .msg = "rss_idt_mem10_ecc_m1bit_err" },
+ { .int_msk = BIT(19), .msg = "rss_idt_mem11_ecc_mbit_err" },
+ { .int_msk = BIT(20), .msg = "rss_idt_mem12_ecc_mbit_err" },
+ { .int_msk = BIT(21), .msg = "rss_idt_mem13_ecc_mbit_err" },
+ { .int_msk = BIT(22), .msg = "rss_idt_mem14_ecc_mbit_err" },
+ { .int_msk = BIT(23), .msg = "rss_idt_mem15_ecc_mbit_err" },
+ { .int_msk = BIT(24), .msg = "port_vlan_mem_ecc_mbit_err" },
+ { .int_msk = BIT(25), .msg = "mcast_linear_table_mem_ecc_mbit_err" },
+ { .int_msk = BIT(26), .msg = "mcast_result_mem_ecc_mbit_err" },
+ { .int_msk = BIT(27),
+ .msg = "flow_director_ad_mem0_ecc_mbit_err" },
+ { .int_msk = BIT(28),
+ .msg = "flow_director_ad_mem1_ecc_mbit_err" },
+ { .int_msk = BIT(29),
+ .msg = "rx_vlan_tag_memory_ecc_mbit_err" },
+ { .int_msk = BIT(30),
+ .msg = "Tx_UP_mapping_config_mem_ecc_mbit_err" },
+ { /* sentinel */ }
+};
+
+static const struct hclge_hw_error hclge_ppp_pf_int[] = {
+ { .int_msk = BIT(0), .msg = "Tx_vlan_tag_err" },
+ { .int_msk = BIT(1), .msg = "rss_list_tc_unassigned_queue_err" },
+ { /* sentinel */ }
+};
+
+static const struct hclge_hw_error hclge_ppp_mpf_int2[] = {
+ { .int_msk = BIT(0), .msg = "hfs_fifo_mem_ecc_1bit_err" },
+ { .int_msk = BIT(1), .msg = "rslt_descr_fifo_mem_ecc_1bit_err" },
+ { .int_msk = BIT(2), .msg = "tx_vlan_tag_mem_ecc_1bit_err" },
+ { .int_msk = BIT(3), .msg = "FD_CN0_memory_ecc_1bit_err" },
+ { .int_msk = BIT(4), .msg = "FD_CN1_memory_ecc_1bit_err" },
+ { .int_msk = BIT(5), .msg = "GRO_AD_memory_ecc_1bit_err" },
+ { /* sentinel */ }
+};
+
+static const struct hclge_hw_error hclge_ppp_mpf_int3[] = {
+ { .int_msk = BIT(0), .msg = "hfs_fifo_mem_ecc_mbit_err" },
+ { .int_msk = BIT(1), .msg = "rslt_descr_fifo_mem_ecc_mbit_err" },
+ { .int_msk = BIT(2), .msg = "tx_vlan_tag_mem_ecc_mbit_err" },
+ { .int_msk = BIT(3), .msg = "FD_CN0_memory_ecc_mbit_err" },
+ { .int_msk = BIT(4), .msg = "FD_CN1_memory_ecc_mbit_err" },
+ { .int_msk = BIT(5), .msg = "GRO_AD_memory_ecc_mbit_err" },
+ { /* sentinel */ }
+};
+
+struct hclge_tm_sch_ecc_info {
+ const char *name;
+};
+
+static const struct hclge_tm_sch_ecc_info hclge_tm_sch_ecc_err[7][15] = {
+ {
+ { .name = "QSET_QUEUE_CTRL:PRI_LEN TAB" },
+ { .name = "QSET_QUEUE_CTRL:SPA_LEN TAB" },
+ { .name = "QSET_QUEUE_CTRL:SPB_LEN TAB" },
+ { .name = "QSET_QUEUE_CTRL:WRRA_LEN TAB" },
+ { .name = "QSET_QUEUE_CTRL:WRRB_LEN TAB" },
+ { .name = "QSET_QUEUE_CTRL:SPA_HPTR TAB" },
+ { .name = "QSET_QUEUE_CTRL:SPB_HPTR TAB" },
+ { .name = "QSET_QUEUE_CTRL:WRRA_HPTR TAB" },
+ { .name = "QSET_QUEUE_CTRL:WRRB_HPTR TAB" },
+ { .name = "QSET_QUEUE_CTRL:QS_LINKLIST TAB" },
+ { .name = "QSET_QUEUE_CTRL:SPA_TPTR TAB" },
+ { .name = "QSET_QUEUE_CTRL:SPB_TPTR TAB" },
+ { .name = "QSET_QUEUE_CTRL:WRRA_TPTR TAB" },
+ { .name = "QSET_QUEUE_CTRL:WRRB_TPTR TAB" },
+ { .name = "QSET_QUEUE_CTRL:QS_DEFICITCNT TAB" },
+ },
+ {
+ { .name = "ROCE_QUEUE_CTRL:QS_LEN TAB" },
+ { .name = "ROCE_QUEUE_CTRL:QS_TPTR TAB" },
+ { .name = "ROCE_QUEUE_CTRL:QS_HPTR TAB" },
+ { .name = "ROCE_QUEUE_CTRL:QLINKLIST TAB" },
+ { .name = "ROCE_QUEUE_CTRL:QCLEN TAB" },
+ },
+ {
+ { .name = "NIC_QUEUE_CTRL:QS_LEN TAB" },
+ { .name = "NIC_QUEUE_CTRL:QS_TPTR TAB" },
+ { .name = "NIC_QUEUE_CTRL:QS_HPTR TAB" },
+ { .name = "NIC_QUEUE_CTRL:QLINKLIST TAB" },
+ { .name = "NIC_QUEUE_CTRL:QCLEN TAB" },
+ },
+ {
+ { .name = "RAM_CFG_CTRL:CSHAP TAB" },
+ { .name = "RAM_CFG_CTRL:PSHAP TAB" },
+ },
+ {
+ { .name = "SHAPER_CTRL:PSHAP TAB" },
+ },
+ {
+ { .name = "MSCH_CTRL" },
+ },
+ {
+ { .name = "TOP_CTRL" },
+ },
+};
+
+static const struct hclge_hw_error hclge_tm_sch_err_int[] = {
+ { .int_msk = BIT(0), .msg = "tm_sch_ecc_1bit_err" },
+ { .int_msk = BIT(1), .msg = "tm_sch_ecc_mbit_err" },
+ { .int_msk = BIT(2), .msg = "tm_sch_port_shap_sub_fifo_wr_full_err" },
+ { .int_msk = BIT(3), .msg = "tm_sch_port_shap_sub_fifo_rd_empty_err" },
+ { .int_msk = BIT(4), .msg = "tm_sch_pg_pshap_sub_fifo_wr_full_err" },
+ { .int_msk = BIT(5), .msg = "tm_sch_pg_pshap_sub_fifo_rd_empty_err" },
+ { .int_msk = BIT(6), .msg = "tm_sch_pg_cshap_sub_fifo_wr_full_err" },
+ { .int_msk = BIT(7), .msg = "tm_sch_pg_cshap_sub_fifo_rd_empty_err" },
+ { .int_msk = BIT(8), .msg = "tm_sch_pri_pshap_sub_fifo_wr_full_err" },
+ { .int_msk = BIT(9), .msg = "tm_sch_pri_pshap_sub_fifo_rd_empty_err" },
+ { .int_msk = BIT(10), .msg = "tm_sch_pri_cshap_sub_fifo_wr_full_err" },
+ { .int_msk = BIT(11), .msg = "tm_sch_pri_cshap_sub_fifo_rd_empty_err" },
+ { .int_msk = BIT(12),
+ .msg = "tm_sch_port_shap_offset_fifo_wr_full_err" },
+ { .int_msk = BIT(13),
+ .msg = "tm_sch_port_shap_offset_fifo_rd_empty_err" },
+ { .int_msk = BIT(14),
+ .msg = "tm_sch_pg_pshap_offset_fifo_wr_full_err" },
+ { .int_msk = BIT(15),
+ .msg = "tm_sch_pg_pshap_offset_fifo_rd_empty_err" },
+ { .int_msk = BIT(16),
+ .msg = "tm_sch_pg_cshap_offset_fifo_wr_full_err" },
+ { .int_msk = BIT(17),
+ .msg = "tm_sch_pg_cshap_offset_fifo_rd_empty_err" },
+ { .int_msk = BIT(18),
+ .msg = "tm_sch_pri_pshap_offset_fifo_wr_full_err" },
+ { .int_msk = BIT(19),
+ .msg = "tm_sch_pri_pshap_offset_fifo_rd_empty_err" },
+ { .int_msk = BIT(20),
+ .msg = "tm_sch_pri_cshap_offset_fifo_wr_full_err" },
+ { .int_msk = BIT(21),
+ .msg = "tm_sch_pri_cshap_offset_fifo_rd_empty_err" },
+ { .int_msk = BIT(22), .msg = "tm_sch_rq_fifo_wr_full_err" },
+ { .int_msk = BIT(23), .msg = "tm_sch_rq_fifo_rd_empty_err" },
+ { .int_msk = BIT(24), .msg = "tm_sch_nq_fifo_wr_full_err" },
+ { .int_msk = BIT(25), .msg = "tm_sch_nq_fifo_rd_empty_err" },
+ { .int_msk = BIT(26), .msg = "tm_sch_roce_up_fifo_wr_full_err" },
+ { .int_msk = BIT(27), .msg = "tm_sch_roce_up_fifo_rd_empty_err" },
+ { .int_msk = BIT(28), .msg = "tm_sch_rcb_byte_fifo_wr_full_err" },
+ { .int_msk = BIT(29), .msg = "tm_sch_rcb_byte_fifo_rd_empty_err" },
+ { .int_msk = BIT(30), .msg = "tm_sch_ssu_byte_fifo_wr_full_err" },
+ { .int_msk = BIT(31), .msg = "tm_sch_ssu_byte_fifo_rd_empty_err" },
+ { /* sentinel */ }
+};
+
+static const struct hclge_hw_error hclge_qcn_ecc_err_int[] = {
+ { .int_msk = BIT(0), .msg = "qcn_byte_mem_ecc_1bit_err" },
+ { .int_msk = BIT(1), .msg = "qcn_byte_mem_ecc_mbit_err" },
+ { .int_msk = BIT(2), .msg = "qcn_time_mem_ecc_1bit_err" },
+ { .int_msk = BIT(3), .msg = "qcn_time_mem_ecc_mbit_err" },
+ { .int_msk = BIT(4), .msg = "qcn_fb_mem_ecc_1bit_err" },
+ { .int_msk = BIT(5), .msg = "qcn_fb_mem_ecc_mbit_err" },
+ { .int_msk = BIT(6), .msg = "qcn_link_mem_ecc_1bit_err" },
+ { .int_msk = BIT(7), .msg = "qcn_link_mem_ecc_mbit_err" },
+ { .int_msk = BIT(8), .msg = "qcn_rate_mem_ecc_1bit_err" },
+ { .int_msk = BIT(9), .msg = "qcn_rate_mem_ecc_mbit_err" },
+ { .int_msk = BIT(10), .msg = "qcn_tmplt_mem_ecc_1bit_err" },
+ { .int_msk = BIT(11), .msg = "qcn_tmplt_mem_ecc_mbit_err" },
+ { .int_msk = BIT(12), .msg = "qcn_shap_cfg_mem_ecc_1bit_err" },
+ { .int_msk = BIT(13), .msg = "qcn_shap_cfg_mem_ecc_mbit_err" },
+ { .int_msk = BIT(14), .msg = "qcn_gp0_barrel_mem_ecc_1bit_err" },
+ { .int_msk = BIT(15), .msg = "qcn_gp0_barrel_mem_ecc_mbit_err" },
+ { .int_msk = BIT(16), .msg = "qcn_gp1_barrel_mem_ecc_1bit_err" },
+ { .int_msk = BIT(17), .msg = "qcn_gp1_barrel_mem_ecc_mbit_err" },
+ { .int_msk = BIT(18), .msg = "qcn_gp2_barrel_mem_ecc_1bit_err" },
+ { .int_msk = BIT(19), .msg = "qcn_gp2_barrel_mem_ecc_mbit_err" },
+ { .int_msk = BIT(20), .msg = "qcn_gp3_barral_mem_ecc_1bit_err" },
+ { .int_msk = BIT(21), .msg = "qcn_gp3_barral_mem_ecc_mbit_err" },
+ { /* sentinel */ }
+};
+
+static void hclge_log_error(struct device *dev,
+ const struct hclge_hw_error *err_list,
+ u32 err_sts)
+{
+ const struct hclge_hw_error *err;
+ int i = 0;
+
+ while (err_list[i].msg) {
+ err = &err_list[i];
+ if (!(err->int_msk & err_sts)) {
+ i++;
+ continue;
+ }
+ dev_warn(dev, "%s [error status=0x%x] found\n",
+ err->msg, err_sts);
+ i++;
+ }
+}
+
+/* hclge_cmd_query_error: read the error information
+ * @hdev: pointer to struct hclge_dev
+ * @desc: descriptor for describing the command
+ * @cmd: command opcode
+ * @flag: flag for extended command structure
+ * @w_num: offset for setting the read interrupt type.
+ * @int_type: select which type of the interrupt for which the error
+ * info will be read(RAS-CE/RAS-NFE/RAS-FE etc).
+ *
+ * This function query the error info from hw register/s using command
+ */
+static int hclge_cmd_query_error(struct hclge_dev *hdev,
+ struct hclge_desc *desc, u32 cmd,
+ u16 flag, u8 w_num,
+ enum hclge_err_int_type int_type)
+{
+ struct device *dev = &hdev->pdev->dev;
+ int num = 1;
+ int ret;
+
+ hclge_cmd_setup_basic_desc(&desc[0], cmd, true);
+ if (flag) {
+ desc[0].flag |= cpu_to_le16(flag);
+ hclge_cmd_setup_basic_desc(&desc[1], cmd, true);
+ num = 2;
+ }
+ if (w_num)
+ desc[0].data[w_num] = cpu_to_le32(int_type);
+
+ ret = hclge_cmd_send(&hdev->hw, &desc[0], num);
+ if (ret)
+ dev_err(dev, "query error cmd failed (%d)\n", ret);
+
+ return ret;
+}
+
+/* hclge_cmd_clear_error: clear the error status
+ * @hdev: pointer to struct hclge_dev
+ * @desc: descriptor for describing the command
+ * @desc_src: prefilled descriptor from the previous command for reusing
+ * @cmd: command opcode
+ * @flag: flag for extended command structure
+ *
+ * This function clear the error status in the hw register/s using command
+ */
+static int hclge_cmd_clear_error(struct hclge_dev *hdev,
+ struct hclge_desc *desc,
+ struct hclge_desc *desc_src,
+ u32 cmd, u16 flag)
+{
+ struct device *dev = &hdev->pdev->dev;
+ int num = 1;
+ int ret, i;
+
+ if (cmd) {
+ hclge_cmd_setup_basic_desc(&desc[0], cmd, false);
+ if (flag) {
+ desc[0].flag |= cpu_to_le16(flag);
+ hclge_cmd_setup_basic_desc(&desc[1], cmd, false);
+ num = 2;
+ }
+ if (desc_src) {
+ for (i = 0; i < 6; i++) {
+ desc[0].data[i] = desc_src[0].data[i];
+ if (flag)
+ desc[1].data[i] = desc_src[1].data[i];
+ }
+ }
+ } else {
+ hclge_cmd_reuse_desc(&desc[0], false);
+ if (flag) {
+ desc[0].flag |= cpu_to_le16(flag);
+ hclge_cmd_reuse_desc(&desc[1], false);
+ num = 2;
+ }
+ }
+ ret = hclge_cmd_send(&hdev->hw, &desc[0], num);
+ if (ret)
+ dev_err(dev, "clear error cmd failed (%d)\n", ret);
+
+ return ret;
+}
+
+static int hclge_enable_common_error(struct hclge_dev *hdev, bool en)
+{
+ struct device *dev = &hdev->pdev->dev;
+ struct hclge_desc desc[2];
+ int ret;
+
+ hclge_cmd_setup_basic_desc(&desc[0], HCLGE_COMMON_ECC_INT_CFG, false);
+ desc[0].flag |= cpu_to_le16(HCLGE_CMD_FLAG_NEXT);
+ hclge_cmd_setup_basic_desc(&desc[1], HCLGE_COMMON_ECC_INT_CFG, false);
+
+ if (en) {
+ /* enable COMMON error interrupts */
+ desc[0].data[0] = cpu_to_le32(HCLGE_IMP_TCM_ECC_ERR_INT_EN);
+ desc[0].data[2] = cpu_to_le32(HCLGE_CMDQ_NIC_ECC_ERR_INT_EN |
+ HCLGE_CMDQ_ROCEE_ECC_ERR_INT_EN);
+ desc[0].data[3] = cpu_to_le32(HCLGE_IMP_RD_POISON_ERR_INT_EN);
+ desc[0].data[4] = cpu_to_le32(HCLGE_TQP_ECC_ERR_INT_EN);
+ desc[0].data[5] = cpu_to_le32(HCLGE_IMP_ITCM4_ECC_ERR_INT_EN);
+ } else {
+ /* disable COMMON error interrupts */
+ desc[0].data[0] = 0;
+ desc[0].data[2] = 0;
+ desc[0].data[3] = 0;
+ desc[0].data[4] = 0;
+ desc[0].data[5] = 0;
+ }
+ desc[1].data[0] = cpu_to_le32(HCLGE_IMP_TCM_ECC_ERR_INT_EN_MASK);
+ desc[1].data[2] = cpu_to_le32(HCLGE_CMDQ_NIC_ECC_ERR_INT_EN_MASK |
+ HCLGE_CMDQ_ROCEE_ECC_ERR_INT_EN_MASK);
+ desc[1].data[3] = cpu_to_le32(HCLGE_IMP_RD_POISON_ERR_INT_EN_MASK);
+ desc[1].data[4] = cpu_to_le32(HCLGE_TQP_ECC_ERR_INT_EN_MASK);
+ desc[1].data[5] = cpu_to_le32(HCLGE_IMP_ITCM4_ECC_ERR_INT_EN_MASK);
+
+ ret = hclge_cmd_send(&hdev->hw, &desc[0], 2);
+ if (ret)
+ dev_err(dev,
+ "failed(%d) to enable/disable COMMON err interrupts\n",
+ ret);
+
+ return ret;
+}
+
+static int hclge_enable_ncsi_error(struct hclge_dev *hdev, bool en)
+{
+ struct device *dev = &hdev->pdev->dev;
+ struct hclge_desc desc;
+ int ret;
+
+ if (hdev->pdev->revision < 0x21)
+ return 0;
+
+ /* enable/disable NCSI error interrupts */
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_NCSI_INT_EN, false);
+ if (en)
+ desc.data[0] = cpu_to_le32(HCLGE_NCSI_ERR_INT_EN);
+ else
+ desc.data[0] = 0;
+
+ ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ if (ret)
+ dev_err(dev,
+ "failed(%d) to enable/disable NCSI error interrupts\n",
+ ret);
+
+ return ret;
+}
+
+static int hclge_enable_igu_egu_error(struct hclge_dev *hdev, bool en)
+{
+ struct device *dev = &hdev->pdev->dev;
+ struct hclge_desc desc;
+ int ret;
+
+ /* enable/disable error interrupts */
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_IGU_COMMON_INT_EN, false);
+ if (en)
+ desc.data[0] = cpu_to_le32(HCLGE_IGU_ERR_INT_EN);
+ else
+ desc.data[0] = 0;
+ desc.data[1] = cpu_to_le32(HCLGE_IGU_ERR_INT_EN_MASK);
+
+ ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ if (ret) {
+ dev_err(dev,
+ "failed(%d) to enable/disable IGU common interrupts\n",
+ ret);
+ return ret;
+ }
+
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_IGU_EGU_TNL_INT_EN, false);
+ if (en)
+ desc.data[0] = cpu_to_le32(HCLGE_IGU_TNL_ERR_INT_EN);
+ else
+ desc.data[0] = 0;
+ desc.data[1] = cpu_to_le32(HCLGE_IGU_TNL_ERR_INT_EN_MASK);
+
+ ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ if (ret) {
+ dev_err(dev,
+ "failed(%d) to enable/disable IGU-EGU TNL interrupts\n",
+ ret);
+ return ret;
+ }
+
+ ret = hclge_enable_ncsi_error(hdev, en);
+ if (ret)
+ dev_err(dev, "fail(%d) to en/disable err int\n", ret);
+
+ return ret;
+}
+
+static int hclge_enable_ppp_error_interrupt(struct hclge_dev *hdev, u32 cmd,
+ bool en)
+{
+ struct device *dev = &hdev->pdev->dev;
+ struct hclge_desc desc[2];
+ int ret;
+
+ /* enable/disable PPP error interrupts */
+ hclge_cmd_setup_basic_desc(&desc[0], cmd, false);
+ desc[0].flag |= cpu_to_le16(HCLGE_CMD_FLAG_NEXT);
+ hclge_cmd_setup_basic_desc(&desc[1], cmd, false);
+
+ if (cmd == HCLGE_PPP_CMD0_INT_CMD) {
+ if (en) {
+ desc[0].data[0] =
+ cpu_to_le32(HCLGE_PPP_MPF_ECC_ERR_INT0_EN);
+ desc[0].data[1] =
+ cpu_to_le32(HCLGE_PPP_MPF_ECC_ERR_INT1_EN);
+ } else {
+ desc[0].data[0] = 0;
+ desc[0].data[1] = 0;
+ }
+ desc[1].data[0] =
+ cpu_to_le32(HCLGE_PPP_MPF_ECC_ERR_INT0_EN_MASK);
+ desc[1].data[1] =
+ cpu_to_le32(HCLGE_PPP_MPF_ECC_ERR_INT1_EN_MASK);
+ } else if (cmd == HCLGE_PPP_CMD1_INT_CMD) {
+ if (en) {
+ desc[0].data[0] =
+ cpu_to_le32(HCLGE_PPP_MPF_ECC_ERR_INT2_EN);
+ desc[0].data[1] =
+ cpu_to_le32(HCLGE_PPP_MPF_ECC_ERR_INT3_EN);
+ } else {
+ desc[0].data[0] = 0;
+ desc[0].data[1] = 0;
+ }
+ desc[1].data[0] =
+ cpu_to_le32(HCLGE_PPP_MPF_ECC_ERR_INT2_EN_MASK);
+ desc[1].data[1] =
+ cpu_to_le32(HCLGE_PPP_MPF_ECC_ERR_INT3_EN_MASK);
+ }
+
+ ret = hclge_cmd_send(&hdev->hw, &desc[0], 2);
+ if (ret)
+ dev_err(dev,
+ "failed(%d) to enable/disable PPP error interrupts\n",
+ ret);
+
+ return ret;
+}
+
+static int hclge_enable_ppp_error(struct hclge_dev *hdev, bool en)
+{
+ struct device *dev = &hdev->pdev->dev;
+ int ret;
+
+ ret = hclge_enable_ppp_error_interrupt(hdev, HCLGE_PPP_CMD0_INT_CMD,
+ en);
+ if (ret) {
+ dev_err(dev,
+ "failed(%d) to enable/disable PPP error intr 0,1\n",
+ ret);
+ return ret;
+ }
+
+ ret = hclge_enable_ppp_error_interrupt(hdev, HCLGE_PPP_CMD1_INT_CMD,
+ en);
+ if (ret)
+ dev_err(dev,
+ "failed(%d) to enable/disable PPP error intr 2,3\n",
+ ret);
+
+ return ret;
+}
+
+int hclge_enable_tm_hw_error(struct hclge_dev *hdev, bool en)
+{
+ struct device *dev = &hdev->pdev->dev;
+ struct hclge_desc desc;
+ int ret;
+
+ /* enable TM SCH hw errors */
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_TM_SCH_ECC_INT_EN, false);
+ if (en)
+ desc.data[0] = cpu_to_le32(HCLGE_TM_SCH_ECC_ERR_INT_EN);
+ else
+ desc.data[0] = 0;
+
+ ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ if (ret) {
+ dev_err(dev, "failed(%d) to configure TM SCH errors\n", ret);
+ return ret;
+ }
+
+ /* enable TM QCN hw errors */
+ ret = hclge_cmd_query_error(hdev, &desc, HCLGE_TM_QCN_MEM_INT_CFG,
+ 0, 0, 0);
+ if (ret) {
+ dev_err(dev, "failed(%d) to read TM QCN CFG status\n", ret);
+ return ret;
+ }
+
+ hclge_cmd_reuse_desc(&desc, false);
+ if (en)
+ desc.data[1] = cpu_to_le32(HCLGE_TM_QCN_MEM_ERR_INT_EN);
+ else
+ desc.data[1] = 0;
+
+ ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ if (ret)
+ dev_err(dev,
+ "failed(%d) to configure TM QCN mem errors\n", ret);
+
+ return ret;
+}
+
+static void hclge_process_common_error(struct hclge_dev *hdev,
+ enum hclge_err_int_type type)
+{
+ struct device *dev = &hdev->pdev->dev;
+ struct hclge_desc desc[2];
+ u32 err_sts;
+ int ret;
+
+ /* read err sts */
+ ret = hclge_cmd_query_error(hdev, &desc[0],
+ HCLGE_COMMON_ECC_INT_CFG,
+ HCLGE_CMD_FLAG_NEXT, 0, 0);
+ if (ret) {
+ dev_err(dev,
+ "failed(=%d) to query COMMON error interrupt status\n",
+ ret);
+ return;
+ }
+
+ /* log err */
+ err_sts = (le32_to_cpu(desc[0].data[0])) & HCLGE_IMP_TCM_ECC_INT_MASK;
+ hclge_log_error(dev, &hclge_imp_tcm_ecc_int[0], err_sts);
+
+ err_sts = (le32_to_cpu(desc[0].data[1])) & HCLGE_CMDQ_ECC_INT_MASK;
+ hclge_log_error(dev, &hclge_cmdq_nic_mem_ecc_int[0], err_sts);
+
+ err_sts = (le32_to_cpu(desc[0].data[1]) >> HCLGE_CMDQ_ROC_ECC_INT_SHIFT)
+ & HCLGE_CMDQ_ECC_INT_MASK;
+ hclge_log_error(dev, &hclge_cmdq_rocee_mem_ecc_int[0], err_sts);
+
+ if ((le32_to_cpu(desc[0].data[3])) & BIT(0))
+ dev_warn(dev, "imp_rd_data_poison_err found\n");
+
+ err_sts = (le32_to_cpu(desc[0].data[3]) >> HCLGE_TQP_ECC_INT_SHIFT) &
+ HCLGE_TQP_ECC_INT_MASK;
+ hclge_log_error(dev, &hclge_tqp_int_ecc_int[0], err_sts);
+
+ err_sts = (le32_to_cpu(desc[0].data[5])) &
+ HCLGE_IMP_ITCM4_ECC_INT_MASK;
+ hclge_log_error(dev, &hclge_imp_itcm4_ecc_int[0], err_sts);
+
+ /* clear error interrupts */
+ desc[1].data[0] = cpu_to_le32(HCLGE_IMP_TCM_ECC_CLR_MASK);
+ desc[1].data[1] = cpu_to_le32(HCLGE_CMDQ_NIC_ECC_CLR_MASK |
+ HCLGE_CMDQ_ROCEE_ECC_CLR_MASK);
+ desc[1].data[3] = cpu_to_le32(HCLGE_TQP_IMP_ERR_CLR_MASK);
+ desc[1].data[5] = cpu_to_le32(HCLGE_IMP_ITCM4_ECC_CLR_MASK);
+
+ ret = hclge_cmd_clear_error(hdev, &desc[0], NULL, 0,
+ HCLGE_CMD_FLAG_NEXT);
+ if (ret)
+ dev_err(dev,
+ "failed(%d) to clear COMMON error interrupt status\n",
+ ret);
+}
+
+static void hclge_process_ncsi_error(struct hclge_dev *hdev,
+ enum hclge_err_int_type type)
+{
+ struct device *dev = &hdev->pdev->dev;
+ struct hclge_desc desc_rd;
+ struct hclge_desc desc_wr;
+ u32 err_sts;
+ int ret;
+
+ if (hdev->pdev->revision < 0x21)
+ return;
+
+ /* read NCSI error status */
+ ret = hclge_cmd_query_error(hdev, &desc_rd, HCLGE_NCSI_INT_QUERY,
+ 0, 1, HCLGE_NCSI_ERR_INT_TYPE);
+ if (ret) {
+ dev_err(dev,
+ "failed(=%d) to query NCSI error interrupt status\n",
+ ret);
+ return;
+ }
+
+ /* log err */
+ err_sts = le32_to_cpu(desc_rd.data[0]);
+ hclge_log_error(dev, &hclge_ncsi_err_int[0], err_sts);
+
+ /* clear err int */
+ ret = hclge_cmd_clear_error(hdev, &desc_wr, &desc_rd,
+ HCLGE_NCSI_INT_CLR, 0);
+ if (ret)
+ dev_err(dev, "failed(=%d) to clear NCSI interrupt status\n",
+ ret);
+}
+
+static void hclge_process_igu_egu_error(struct hclge_dev *hdev,
+ enum hclge_err_int_type int_type)
+{
+ struct device *dev = &hdev->pdev->dev;
+ struct hclge_desc desc_rd;
+ struct hclge_desc desc_wr;
+ u32 err_sts;
+ int ret;
+
+ /* read IGU common err sts */
+ ret = hclge_cmd_query_error(hdev, &desc_rd,
+ HCLGE_IGU_COMMON_INT_QUERY,
+ 0, 1, int_type);
+ if (ret) {
+ dev_err(dev, "failed(=%d) to query IGU common int status\n",
+ ret);
+ return;
+ }
+
+ /* log err */
+ err_sts = le32_to_cpu(desc_rd.data[0]) &
+ HCLGE_IGU_COM_INT_MASK;
+ hclge_log_error(dev, &hclge_igu_com_err_int[0], err_sts);
+
+ /* clear err int */
+ ret = hclge_cmd_clear_error(hdev, &desc_wr, &desc_rd,
+ HCLGE_IGU_COMMON_INT_CLR, 0);
+ if (ret) {
+ dev_err(dev, "failed(=%d) to clear IGU common int status\n",
+ ret);
+ return;
+ }
+
+ /* read IGU-EGU TNL err sts */
+ ret = hclge_cmd_query_error(hdev, &desc_rd,
+ HCLGE_IGU_EGU_TNL_INT_QUERY,
+ 0, 1, int_type);
+ if (ret) {
+ dev_err(dev, "failed(=%d) to query IGU-EGU TNL int status\n",
+ ret);
+ return;
+ }
+
+ /* log err */
+ err_sts = le32_to_cpu(desc_rd.data[0]) &
+ HCLGE_IGU_EGU_TNL_INT_MASK;
+ hclge_log_error(dev, &hclge_igu_egu_tnl_err_int[0], err_sts);
+
+ /* clear err int */
+ ret = hclge_cmd_clear_error(hdev, &desc_wr, &desc_rd,
+ HCLGE_IGU_EGU_TNL_INT_CLR, 0);
+ if (ret) {
+ dev_err(dev, "failed(=%d) to clear IGU-EGU TNL int status\n",
+ ret);
+ return;
+ }
+
+ hclge_process_ncsi_error(hdev, HCLGE_ERR_INT_RAS_NFE);
+}
+
+static int hclge_log_and_clear_ppp_error(struct hclge_dev *hdev, u32 cmd,
+ enum hclge_err_int_type int_type)
+{
+ enum hnae3_reset_type reset_level = HNAE3_NONE_RESET;
+ struct device *dev = &hdev->pdev->dev;
+ const struct hclge_hw_error *hw_err_lst1, *hw_err_lst2, *hw_err_lst3;
+ struct hclge_desc desc[2];
+ u32 err_sts;
+ int ret;
+
+ /* read PPP INT sts */
+ ret = hclge_cmd_query_error(hdev, &desc[0], cmd,
+ HCLGE_CMD_FLAG_NEXT, 5, int_type);
+ if (ret) {
+ dev_err(dev, "failed(=%d) to query PPP interrupt status\n",
+ ret);
+ return -EIO;
+ }
+
+ /* log error */
+ if (cmd == HCLGE_PPP_CMD0_INT_CMD) {
+ hw_err_lst1 = &hclge_ppp_mpf_int0[0];
+ hw_err_lst2 = &hclge_ppp_mpf_int1[0];
+ hw_err_lst3 = &hclge_ppp_pf_int[0];
+ } else if (cmd == HCLGE_PPP_CMD1_INT_CMD) {
+ hw_err_lst1 = &hclge_ppp_mpf_int2[0];
+ hw_err_lst2 = &hclge_ppp_mpf_int3[0];
+ } else {
+ dev_err(dev, "invalid command(=%d)\n", cmd);
+ return -EINVAL;
+ }
+
+ err_sts = le32_to_cpu(desc[0].data[2]);
+ if (err_sts) {
+ hclge_log_error(dev, hw_err_lst1, err_sts);
+ reset_level = HNAE3_FUNC_RESET;
+ }
+
+ err_sts = le32_to_cpu(desc[0].data[3]);
+ if (err_sts) {
+ hclge_log_error(dev, hw_err_lst2, err_sts);
+ reset_level = HNAE3_FUNC_RESET;
+ }
+
+ if (cmd == HCLGE_PPP_CMD0_INT_CMD) {
+ err_sts = (le32_to_cpu(desc[0].data[4]) >> 8) & 0x3;
+ if (err_sts) {
+ hclge_log_error(dev, hw_err_lst3, err_sts);
+ reset_level = HNAE3_FUNC_RESET;
+ }
+ }
+
+ /* clear PPP INT */
+ ret = hclge_cmd_clear_error(hdev, &desc[0], NULL, 0,
+ HCLGE_CMD_FLAG_NEXT);
+ if (ret) {
+ dev_err(dev, "failed(=%d) to clear PPP interrupt status\n",
+ ret);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void hclge_process_ppp_error(struct hclge_dev *hdev,
+ enum hclge_err_int_type int_type)
+{
+ struct device *dev = &hdev->pdev->dev;
+ int ret;
+
+ /* read PPP INT0,1 sts */
+ ret = hclge_log_and_clear_ppp_error(hdev, HCLGE_PPP_CMD0_INT_CMD,
+ int_type);
+ if (ret < 0) {
+ dev_err(dev, "failed(=%d) to clear PPP interrupt 0,1 status\n",
+ ret);
+ return;
+ }
+
+ /* read err PPP INT2,3 sts */
+ ret = hclge_log_and_clear_ppp_error(hdev, HCLGE_PPP_CMD1_INT_CMD,
+ int_type);
+ if (ret < 0)
+ dev_err(dev, "failed(=%d) to clear PPP interrupt 2,3 status\n",
+ ret);
+}
+
+static void hclge_process_tm_sch_error(struct hclge_dev *hdev)
+{
+ struct device *dev = &hdev->pdev->dev;
+ const struct hclge_tm_sch_ecc_info *tm_sch_ecc_info;
+ struct hclge_desc desc;
+ u32 ecc_info;
+ u8 module_no;
+ u8 ram_no;
+ int ret;
+
+ /* read TM scheduler errors */
+ ret = hclge_cmd_query_error(hdev, &desc,
+ HCLGE_TM_SCH_MBIT_ECC_INFO_CMD, 0, 0, 0);
+ if (ret) {
+ dev_err(dev, "failed(%d) to read SCH mbit ECC err info\n", ret);
+ return;
+ }
+ ecc_info = le32_to_cpu(desc.data[0]);
+
+ ret = hclge_cmd_query_error(hdev, &desc,
+ HCLGE_TM_SCH_ECC_ERR_RINT_CMD, 0, 0, 0);
+ if (ret) {
+ dev_err(dev, "failed(%d) to read SCH ECC err status\n", ret);
+ return;
+ }
+
+ /* log TM scheduler errors */
+ if (le32_to_cpu(desc.data[0])) {
+ hclge_log_error(dev, &hclge_tm_sch_err_int[0],
+ le32_to_cpu(desc.data[0]));
+ if (le32_to_cpu(desc.data[0]) & 0x2) {
+ module_no = (ecc_info >> 20) & 0xF;
+ ram_no = (ecc_info >> 16) & 0xF;
+ tm_sch_ecc_info =
+ &hclge_tm_sch_ecc_err[module_no][ram_no];
+ dev_warn(dev, "ecc err module:ram=%s\n",
+ tm_sch_ecc_info->name);
+ dev_warn(dev, "ecc memory address = 0x%x\n",
+ ecc_info & 0xFFFF);
+ }
+ }
+
+ /* clear TM scheduler errors */
+ ret = hclge_cmd_clear_error(hdev, &desc, NULL, 0, 0);
+ if (ret) {
+ dev_err(dev, "failed(%d) to clear TM SCH error status\n", ret);
+ return;
+ }
+
+ ret = hclge_cmd_query_error(hdev, &desc,
+ HCLGE_TM_SCH_ECC_ERR_RINT_CE, 0, 0, 0);
+ if (ret) {
+ dev_err(dev, "failed(%d) to read SCH CE status\n", ret);
+ return;
+ }
+
+ ret = hclge_cmd_clear_error(hdev, &desc, NULL, 0, 0);
+ if (ret) {
+ dev_err(dev, "failed(%d) to clear TM SCH CE status\n", ret);
+ return;
+ }
+
+ ret = hclge_cmd_query_error(hdev, &desc,
+ HCLGE_TM_SCH_ECC_ERR_RINT_NFE, 0, 0, 0);
+ if (ret) {
+ dev_err(dev, "failed(%d) to read SCH NFE status\n", ret);
+ return;
+ }
+
+ ret = hclge_cmd_clear_error(hdev, &desc, NULL, 0, 0);
+ if (ret) {
+ dev_err(dev, "failed(%d) to clear TM SCH NFE status\n", ret);
+ return;
+ }
+
+ ret = hclge_cmd_query_error(hdev, &desc,
+ HCLGE_TM_SCH_ECC_ERR_RINT_FE, 0, 0, 0);
+ if (ret) {
+ dev_err(dev, "failed(%d) to read SCH FE status\n", ret);
+ return;
+ }
+
+ ret = hclge_cmd_clear_error(hdev, &desc, NULL, 0, 0);
+ if (ret)
+ dev_err(dev, "failed(%d) to clear TM SCH FE status\n", ret);
+}
+
+static void hclge_process_tm_qcn_error(struct hclge_dev *hdev)
+{
+ struct device *dev = &hdev->pdev->dev;
+ struct hclge_desc desc;
+ int ret;
+
+ /* read QCN errors */
+ ret = hclge_cmd_query_error(hdev, &desc,
+ HCLGE_TM_QCN_MEM_INT_INFO_CMD, 0, 0, 0);
+ if (ret) {
+ dev_err(dev, "failed(%d) to read QCN ECC err status\n", ret);
+ return;
+ }
+
+ /* log QCN errors */
+ if (le32_to_cpu(desc.data[0]))
+ hclge_log_error(dev, &hclge_qcn_ecc_err_int[0],
+ le32_to_cpu(desc.data[0]));
+
+ /* clear QCN errors */
+ ret = hclge_cmd_clear_error(hdev, &desc, NULL, 0, 0);
+ if (ret)
+ dev_err(dev, "failed(%d) to clear QCN error status\n", ret);
+}
+
+static void hclge_process_tm_error(struct hclge_dev *hdev,
+ enum hclge_err_int_type type)
+{
+ hclge_process_tm_sch_error(hdev);
+ hclge_process_tm_qcn_error(hdev);
+}
+
+static const struct hclge_hw_blk hw_blk[] = {
+ { .msk = BIT(0), .name = "IGU_EGU",
+ .enable_error = hclge_enable_igu_egu_error,
+ .process_error = hclge_process_igu_egu_error, },
+ { .msk = BIT(5), .name = "COMMON",
+ .enable_error = hclge_enable_common_error,
+ .process_error = hclge_process_common_error, },
+ { .msk = BIT(4), .name = "TM",
+ .enable_error = hclge_enable_tm_hw_error,
+ .process_error = hclge_process_tm_error, },
+ { .msk = BIT(1), .name = "PPP",
+ .enable_error = hclge_enable_ppp_error,
+ .process_error = hclge_process_ppp_error, },
+ { /* sentinel */ }
+};
+
+int hclge_hw_error_set_state(struct hclge_dev *hdev, bool state)
+{
+ struct device *dev = &hdev->pdev->dev;
+ int ret = 0;
+ int i = 0;
+
+ while (hw_blk[i].name) {
+ if (!hw_blk[i].enable_error) {
+ i++;
+ continue;
+ }
+ ret = hw_blk[i].enable_error(hdev, state);
+ if (ret) {
+ dev_err(dev, "fail(%d) to en/disable err int\n", ret);
+ return ret;
+ }
+ i++;
+ }
+
+ return ret;
+}
+
+pci_ers_result_t hclge_process_ras_hw_error(struct hnae3_ae_dev *ae_dev)
+{
+ struct hclge_dev *hdev = ae_dev->priv;
+ struct device *dev = &hdev->pdev->dev;
+ u32 sts, val;
+ int i = 0;
+
+ sts = hclge_read_dev(&hdev->hw, HCLGE_RAS_PF_OTHER_INT_STS_REG);
+
+ /* Processing Non-fatal errors */
+ if (sts & HCLGE_RAS_REG_NFE_MASK) {
+ val = (sts >> HCLGE_RAS_REG_NFE_SHIFT) & 0xFF;
+ i = 0;
+ while (hw_blk[i].name) {
+ if (!(hw_blk[i].msk & val)) {
+ i++;
+ continue;
+ }
+ dev_warn(dev, "%s ras non-fatal error identified\n",
+ hw_blk[i].name);
+ if (hw_blk[i].process_error)
+ hw_blk[i].process_error(hdev,
+ HCLGE_ERR_INT_RAS_NFE);
+ i++;
+ }
+ }
+
+ return PCI_ERS_RESULT_NEED_RESET;
+}
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h
new file mode 100644
index 000000000000..e0e3b5861495
--- /dev/null
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h
@@ -0,0 +1,83 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Copyright (c) 2016-2017 Hisilicon Limited. */
+
+#ifndef __HCLGE_ERR_H
+#define __HCLGE_ERR_H
+
+#include "hclge_main.h"
+
+#define HCLGE_RAS_PF_OTHER_INT_STS_REG 0x20B00
+#define HCLGE_RAS_REG_FE_MASK 0xFF
+#define HCLGE_RAS_REG_NFE_MASK 0xFF00
+#define HCLGE_RAS_REG_NFE_SHIFT 8
+
+#define HCLGE_IMP_TCM_ECC_ERR_INT_EN 0xFFFF0000
+#define HCLGE_IMP_TCM_ECC_ERR_INT_EN_MASK 0xFFFF0000
+#define HCLGE_IMP_ITCM4_ECC_ERR_INT_EN 0x300
+#define HCLGE_IMP_ITCM4_ECC_ERR_INT_EN_MASK 0x300
+#define HCLGE_CMDQ_NIC_ECC_ERR_INT_EN 0xFFFF
+#define HCLGE_CMDQ_NIC_ECC_ERR_INT_EN_MASK 0xFFFF
+#define HCLGE_CMDQ_ROCEE_ECC_ERR_INT_EN 0xFFFF0000
+#define HCLGE_CMDQ_ROCEE_ECC_ERR_INT_EN_MASK 0xFFFF0000
+#define HCLGE_IMP_RD_POISON_ERR_INT_EN 0x0100
+#define HCLGE_IMP_RD_POISON_ERR_INT_EN_MASK 0x0100
+#define HCLGE_TQP_ECC_ERR_INT_EN 0x0FFF
+#define HCLGE_TQP_ECC_ERR_INT_EN_MASK 0x0FFF
+#define HCLGE_IGU_ERR_INT_EN 0x0000066F
+#define HCLGE_IGU_ERR_INT_EN_MASK 0x000F
+#define HCLGE_IGU_TNL_ERR_INT_EN 0x0002AABF
+#define HCLGE_IGU_TNL_ERR_INT_EN_MASK 0x003F
+#define HCLGE_PPP_MPF_ECC_ERR_INT0_EN 0xFFFFFFFF
+#define HCLGE_PPP_MPF_ECC_ERR_INT0_EN_MASK 0xFFFFFFFF
+#define HCLGE_PPP_MPF_ECC_ERR_INT1_EN 0xFFFFFFFF
+#define HCLGE_PPP_MPF_ECC_ERR_INT1_EN_MASK 0xFFFFFFFF
+#define HCLGE_PPP_PF_ERR_INT_EN 0x0003
+#define HCLGE_PPP_PF_ERR_INT_EN_MASK 0x0003
+#define HCLGE_PPP_MPF_ECC_ERR_INT2_EN 0x003F
+#define HCLGE_PPP_MPF_ECC_ERR_INT2_EN_MASK 0x003F
+#define HCLGE_PPP_MPF_ECC_ERR_INT3_EN 0x003F
+#define HCLGE_PPP_MPF_ECC_ERR_INT3_EN_MASK 0x003F
+#define HCLGE_TM_SCH_ECC_ERR_INT_EN 0x3
+#define HCLGE_TM_QCN_MEM_ERR_INT_EN 0xFFFFFF
+#define HCLGE_NCSI_ERR_INT_EN 0x3
+#define HCLGE_NCSI_ERR_INT_TYPE 0x9
+
+#define HCLGE_IMP_TCM_ECC_INT_MASK 0xFFFF
+#define HCLGE_IMP_ITCM4_ECC_INT_MASK 0x3
+#define HCLGE_CMDQ_ECC_INT_MASK 0xFFFF
+#define HCLGE_CMDQ_ROC_ECC_INT_SHIFT 16
+#define HCLGE_TQP_ECC_INT_MASK 0xFFF
+#define HCLGE_TQP_ECC_INT_SHIFT 16
+#define HCLGE_IMP_TCM_ECC_CLR_MASK 0xFFFF
+#define HCLGE_IMP_ITCM4_ECC_CLR_MASK 0x3
+#define HCLGE_CMDQ_NIC_ECC_CLR_MASK 0xFFFF
+#define HCLGE_CMDQ_ROCEE_ECC_CLR_MASK 0xFFFF0000
+#define HCLGE_TQP_IMP_ERR_CLR_MASK 0x0FFF0001
+#define HCLGE_IGU_COM_INT_MASK 0xF
+#define HCLGE_IGU_EGU_TNL_INT_MASK 0x3F
+#define HCLGE_PPP_PF_INT_MASK 0x100
+
+enum hclge_err_int_type {
+ HCLGE_ERR_INT_MSIX = 0,
+ HCLGE_ERR_INT_RAS_CE = 1,
+ HCLGE_ERR_INT_RAS_NFE = 2,
+ HCLGE_ERR_INT_RAS_FE = 3,
+};
+
+struct hclge_hw_blk {
+ u32 msk;
+ const char *name;
+ int (*enable_error)(struct hclge_dev *hdev, bool en);
+ void (*process_error)(struct hclge_dev *hdev,
+ enum hclge_err_int_type type);
+};
+
+struct hclge_hw_error {
+ u32 int_msk;
+ const char *msg;
+};
+
+int hclge_hw_error_set_state(struct hclge_dev *hdev, bool state);
+int hclge_enable_tm_hw_error(struct hclge_dev *hdev, bool en);
+pci_ers_result_t hclge_process_ras_hw_error(struct hnae3_ae_dev *ae_dev);
+#endif
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
index 8577dfc799ad..ffdd96020860 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
@@ -19,20 +19,18 @@
#include "hclge_mbx.h"
#include "hclge_mdio.h"
#include "hclge_tm.h"
+#include "hclge_err.h"
#include "hnae3.h"
#define HCLGE_NAME "hclge"
#define HCLGE_STATS_READ(p, offset) (*((u64 *)((u8 *)(p) + (offset))))
#define HCLGE_MAC_STATS_FIELD_OFF(f) (offsetof(struct hclge_mac_stats, f))
-#define HCLGE_64BIT_STATS_FIELD_OFF(f) (offsetof(struct hclge_64_bit_stats, f))
-#define HCLGE_32BIT_STATS_FIELD_OFF(f) (offsetof(struct hclge_32_bit_stats, f))
-static int hclge_set_mta_filter_mode(struct hclge_dev *hdev,
- enum hclge_mta_dmac_sel_type mta_mac_sel,
- bool enable);
static int hclge_set_mtu(struct hnae3_handle *handle, int new_mtu);
static int hclge_init_vlan_config(struct hclge_dev *hdev);
static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev);
+static int hclge_set_umv_space(struct hclge_dev *hdev, u16 space_size,
+ u16 *allocated_size, bool is_alloc);
static struct hnae3_ae_algo ae_algo;
@@ -51,175 +49,12 @@ static const struct pci_device_id ae_algo_pci_tbl[] = {
MODULE_DEVICE_TABLE(pci, ae_algo_pci_tbl);
static const char hns3_nic_test_strs[][ETH_GSTRING_LEN] = {
- "Mac Loopback test",
- "Serdes Loopback test",
+ "App Loopback test",
+ "Serdes serial Loopback test",
+ "Serdes parallel Loopback test",
"Phy Loopback test"
};
-static const struct hclge_comm_stats_str g_all_64bit_stats_string[] = {
- {"igu_rx_oversize_pkt",
- HCLGE_64BIT_STATS_FIELD_OFF(igu_rx_oversize_pkt)},
- {"igu_rx_undersize_pkt",
- HCLGE_64BIT_STATS_FIELD_OFF(igu_rx_undersize_pkt)},
- {"igu_rx_out_all_pkt",
- HCLGE_64BIT_STATS_FIELD_OFF(igu_rx_out_all_pkt)},
- {"igu_rx_uni_pkt",
- HCLGE_64BIT_STATS_FIELD_OFF(igu_rx_uni_pkt)},
- {"igu_rx_multi_pkt",
- HCLGE_64BIT_STATS_FIELD_OFF(igu_rx_multi_pkt)},
- {"igu_rx_broad_pkt",
- HCLGE_64BIT_STATS_FIELD_OFF(igu_rx_broad_pkt)},
- {"egu_tx_out_all_pkt",
- HCLGE_64BIT_STATS_FIELD_OFF(egu_tx_out_all_pkt)},
- {"egu_tx_uni_pkt",
- HCLGE_64BIT_STATS_FIELD_OFF(egu_tx_uni_pkt)},
- {"egu_tx_multi_pkt",
- HCLGE_64BIT_STATS_FIELD_OFF(egu_tx_multi_pkt)},
- {"egu_tx_broad_pkt",
- HCLGE_64BIT_STATS_FIELD_OFF(egu_tx_broad_pkt)},
- {"ssu_ppp_mac_key_num",
- HCLGE_64BIT_STATS_FIELD_OFF(ssu_ppp_mac_key_num)},
- {"ssu_ppp_host_key_num",
- HCLGE_64BIT_STATS_FIELD_OFF(ssu_ppp_host_key_num)},
- {"ppp_ssu_mac_rlt_num",
- HCLGE_64BIT_STATS_FIELD_OFF(ppp_ssu_mac_rlt_num)},
- {"ppp_ssu_host_rlt_num",
- HCLGE_64BIT_STATS_FIELD_OFF(ppp_ssu_host_rlt_num)},
- {"ssu_tx_in_num",
- HCLGE_64BIT_STATS_FIELD_OFF(ssu_tx_in_num)},
- {"ssu_tx_out_num",
- HCLGE_64BIT_STATS_FIELD_OFF(ssu_tx_out_num)},
- {"ssu_rx_in_num",
- HCLGE_64BIT_STATS_FIELD_OFF(ssu_rx_in_num)},
- {"ssu_rx_out_num",
- HCLGE_64BIT_STATS_FIELD_OFF(ssu_rx_out_num)}
-};
-
-static const struct hclge_comm_stats_str g_all_32bit_stats_string[] = {
- {"igu_rx_err_pkt",
- HCLGE_32BIT_STATS_FIELD_OFF(igu_rx_err_pkt)},
- {"igu_rx_no_eof_pkt",
- HCLGE_32BIT_STATS_FIELD_OFF(igu_rx_no_eof_pkt)},
- {"igu_rx_no_sof_pkt",
- HCLGE_32BIT_STATS_FIELD_OFF(igu_rx_no_sof_pkt)},
- {"egu_tx_1588_pkt",
- HCLGE_32BIT_STATS_FIELD_OFF(egu_tx_1588_pkt)},
- {"ssu_full_drop_num",
- HCLGE_32BIT_STATS_FIELD_OFF(ssu_full_drop_num)},
- {"ssu_part_drop_num",
- HCLGE_32BIT_STATS_FIELD_OFF(ssu_part_drop_num)},
- {"ppp_key_drop_num",
- HCLGE_32BIT_STATS_FIELD_OFF(ppp_key_drop_num)},
- {"ppp_rlt_drop_num",
- HCLGE_32BIT_STATS_FIELD_OFF(ppp_rlt_drop_num)},
- {"ssu_key_drop_num",
- HCLGE_32BIT_STATS_FIELD_OFF(ssu_key_drop_num)},
- {"pkt_curr_buf_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(pkt_curr_buf_cnt)},
- {"qcn_fb_rcv_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(qcn_fb_rcv_cnt)},
- {"qcn_fb_drop_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(qcn_fb_drop_cnt)},
- {"qcn_fb_invaild_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(qcn_fb_invaild_cnt)},
- {"rx_packet_tc0_in_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(rx_packet_tc0_in_cnt)},
- {"rx_packet_tc1_in_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(rx_packet_tc1_in_cnt)},
- {"rx_packet_tc2_in_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(rx_packet_tc2_in_cnt)},
- {"rx_packet_tc3_in_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(rx_packet_tc3_in_cnt)},
- {"rx_packet_tc4_in_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(rx_packet_tc4_in_cnt)},
- {"rx_packet_tc5_in_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(rx_packet_tc5_in_cnt)},
- {"rx_packet_tc6_in_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(rx_packet_tc6_in_cnt)},
- {"rx_packet_tc7_in_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(rx_packet_tc7_in_cnt)},
- {"rx_packet_tc0_out_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(rx_packet_tc0_out_cnt)},
- {"rx_packet_tc1_out_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(rx_packet_tc1_out_cnt)},
- {"rx_packet_tc2_out_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(rx_packet_tc2_out_cnt)},
- {"rx_packet_tc3_out_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(rx_packet_tc3_out_cnt)},
- {"rx_packet_tc4_out_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(rx_packet_tc4_out_cnt)},
- {"rx_packet_tc5_out_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(rx_packet_tc5_out_cnt)},
- {"rx_packet_tc6_out_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(rx_packet_tc6_out_cnt)},
- {"rx_packet_tc7_out_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(rx_packet_tc7_out_cnt)},
- {"tx_packet_tc0_in_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(tx_packet_tc0_in_cnt)},
- {"tx_packet_tc1_in_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(tx_packet_tc1_in_cnt)},
- {"tx_packet_tc2_in_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(tx_packet_tc2_in_cnt)},
- {"tx_packet_tc3_in_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(tx_packet_tc3_in_cnt)},
- {"tx_packet_tc4_in_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(tx_packet_tc4_in_cnt)},
- {"tx_packet_tc5_in_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(tx_packet_tc5_in_cnt)},
- {"tx_packet_tc6_in_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(tx_packet_tc6_in_cnt)},
- {"tx_packet_tc7_in_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(tx_packet_tc7_in_cnt)},
- {"tx_packet_tc0_out_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(tx_packet_tc0_out_cnt)},
- {"tx_packet_tc1_out_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(tx_packet_tc1_out_cnt)},
- {"tx_packet_tc2_out_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(tx_packet_tc2_out_cnt)},
- {"tx_packet_tc3_out_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(tx_packet_tc3_out_cnt)},
- {"tx_packet_tc4_out_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(tx_packet_tc4_out_cnt)},
- {"tx_packet_tc5_out_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(tx_packet_tc5_out_cnt)},
- {"tx_packet_tc6_out_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(tx_packet_tc6_out_cnt)},
- {"tx_packet_tc7_out_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(tx_packet_tc7_out_cnt)},
- {"pkt_curr_buf_tc0_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(pkt_curr_buf_tc0_cnt)},
- {"pkt_curr_buf_tc1_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(pkt_curr_buf_tc1_cnt)},
- {"pkt_curr_buf_tc2_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(pkt_curr_buf_tc2_cnt)},
- {"pkt_curr_buf_tc3_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(pkt_curr_buf_tc3_cnt)},
- {"pkt_curr_buf_tc4_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(pkt_curr_buf_tc4_cnt)},
- {"pkt_curr_buf_tc5_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(pkt_curr_buf_tc5_cnt)},
- {"pkt_curr_buf_tc6_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(pkt_curr_buf_tc6_cnt)},
- {"pkt_curr_buf_tc7_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(pkt_curr_buf_tc7_cnt)},
- {"mb_uncopy_num",
- HCLGE_32BIT_STATS_FIELD_OFF(mb_uncopy_num)},
- {"lo_pri_unicast_rlt_drop_num",
- HCLGE_32BIT_STATS_FIELD_OFF(lo_pri_unicast_rlt_drop_num)},
- {"hi_pri_multicast_rlt_drop_num",
- HCLGE_32BIT_STATS_FIELD_OFF(hi_pri_multicast_rlt_drop_num)},
- {"lo_pri_multicast_rlt_drop_num",
- HCLGE_32BIT_STATS_FIELD_OFF(lo_pri_multicast_rlt_drop_num)},
- {"rx_oq_drop_pkt_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(rx_oq_drop_pkt_cnt)},
- {"tx_oq_drop_pkt_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(tx_oq_drop_pkt_cnt)},
- {"nic_l2_err_drop_pkt_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(nic_l2_err_drop_pkt_cnt)},
- {"roc_l2_err_drop_pkt_cnt",
- HCLGE_32BIT_STATS_FIELD_OFF(roc_l2_err_drop_pkt_cnt)}
-};
-
static const struct hclge_comm_stats_str g_mac_stats_string[] = {
{"mac_tx_mac_pause_num",
HCLGE_MAC_STATS_FIELD_OFF(mac_tx_mac_pause_num)},
@@ -394,109 +229,6 @@ static const struct hclge_mac_mgr_tbl_entry_cmd hclge_mgr_table[] = {
},
};
-static int hclge_64_bit_update_stats(struct hclge_dev *hdev)
-{
-#define HCLGE_64_BIT_CMD_NUM 5
-#define HCLGE_64_BIT_RTN_DATANUM 4
- u64 *data = (u64 *)(&hdev->hw_stats.all_64_bit_stats);
- struct hclge_desc desc[HCLGE_64_BIT_CMD_NUM];
- __le64 *desc_data;
- int i, k, n;
- int ret;
-
- hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_STATS_64_BIT, true);
- ret = hclge_cmd_send(&hdev->hw, desc, HCLGE_64_BIT_CMD_NUM);
- if (ret) {
- dev_err(&hdev->pdev->dev,
- "Get 64 bit pkt stats fail, status = %d.\n", ret);
- return ret;
- }
-
- for (i = 0; i < HCLGE_64_BIT_CMD_NUM; i++) {
- if (unlikely(i == 0)) {
- desc_data = (__le64 *)(&desc[i].data[0]);
- n = HCLGE_64_BIT_RTN_DATANUM - 1;
- } else {
- desc_data = (__le64 *)(&desc[i]);
- n = HCLGE_64_BIT_RTN_DATANUM;
- }
- for (k = 0; k < n; k++) {
- *data++ += le64_to_cpu(*desc_data);
- desc_data++;
- }
- }
-
- return 0;
-}
-
-static void hclge_reset_partial_32bit_counter(struct hclge_32_bit_stats *stats)
-{
- stats->pkt_curr_buf_cnt = 0;
- stats->pkt_curr_buf_tc0_cnt = 0;
- stats->pkt_curr_buf_tc1_cnt = 0;
- stats->pkt_curr_buf_tc2_cnt = 0;
- stats->pkt_curr_buf_tc3_cnt = 0;
- stats->pkt_curr_buf_tc4_cnt = 0;
- stats->pkt_curr_buf_tc5_cnt = 0;
- stats->pkt_curr_buf_tc6_cnt = 0;
- stats->pkt_curr_buf_tc7_cnt = 0;
-}
-
-static int hclge_32_bit_update_stats(struct hclge_dev *hdev)
-{
-#define HCLGE_32_BIT_CMD_NUM 8
-#define HCLGE_32_BIT_RTN_DATANUM 8
-
- struct hclge_desc desc[HCLGE_32_BIT_CMD_NUM];
- struct hclge_32_bit_stats *all_32_bit_stats;
- __le32 *desc_data;
- int i, k, n;
- u64 *data;
- int ret;
-
- all_32_bit_stats = &hdev->hw_stats.all_32_bit_stats;
- data = (u64 *)(&all_32_bit_stats->egu_tx_1588_pkt);
-
- hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_STATS_32_BIT, true);
- ret = hclge_cmd_send(&hdev->hw, desc, HCLGE_32_BIT_CMD_NUM);
- if (ret) {
- dev_err(&hdev->pdev->dev,
- "Get 32 bit pkt stats fail, status = %d.\n", ret);
-
- return ret;
- }
-
- hclge_reset_partial_32bit_counter(all_32_bit_stats);
- for (i = 0; i < HCLGE_32_BIT_CMD_NUM; i++) {
- if (unlikely(i == 0)) {
- __le16 *desc_data_16bit;
-
- all_32_bit_stats->igu_rx_err_pkt +=
- le32_to_cpu(desc[i].data[0]);
-
- desc_data_16bit = (__le16 *)&desc[i].data[1];
- all_32_bit_stats->igu_rx_no_eof_pkt +=
- le16_to_cpu(*desc_data_16bit);
-
- desc_data_16bit++;
- all_32_bit_stats->igu_rx_no_sof_pkt +=
- le16_to_cpu(*desc_data_16bit);
-
- desc_data = &desc[i].data[2];
- n = HCLGE_32_BIT_RTN_DATANUM - 4;
- } else {
- desc_data = (__le32 *)&desc[i];
- n = HCLGE_32_BIT_RTN_DATANUM;
- }
- for (k = 0; k < n; k++) {
- *data++ += le32_to_cpu(*desc_data);
- desc_data++;
- }
- }
-
- return 0;
-}
-
static int hclge_mac_update_stats(struct hclge_dev *hdev)
{
#define HCLGE_MAC_CMD_NUM 21
@@ -623,7 +355,7 @@ static u8 *hclge_tqps_get_strings(struct hnae3_handle *handle, u8 *data)
for (i = 0; i < kinfo->num_tqps; i++) {
struct hclge_tqp *tqp = container_of(handle->kinfo.tqp[i],
struct hclge_tqp, q);
- snprintf(buff, ETH_GSTRING_LEN, "txq#%d_pktnum_rcd",
+ snprintf(buff, ETH_GSTRING_LEN, "txq%d_pktnum_rcd",
tqp->index);
buff = buff + ETH_GSTRING_LEN;
}
@@ -631,7 +363,7 @@ static u8 *hclge_tqps_get_strings(struct hnae3_handle *handle, u8 *data)
for (i = 0; i < kinfo->num_tqps; i++) {
struct hclge_tqp *tqp = container_of(kinfo->tqp[i],
struct hclge_tqp, q);
- snprintf(buff, ETH_GSTRING_LEN, "rxq#%d_pktnum_rcd",
+ snprintf(buff, ETH_GSTRING_LEN, "rxq%d_pktnum_rcd",
tqp->index);
buff = buff + ETH_GSTRING_LEN;
}
@@ -675,14 +407,8 @@ static void hclge_update_netstat(struct hclge_hw_stats *hw_stats,
struct net_device_stats *net_stats)
{
net_stats->tx_dropped = 0;
- net_stats->rx_dropped = hw_stats->all_32_bit_stats.ssu_full_drop_num;
- net_stats->rx_dropped += hw_stats->all_32_bit_stats.ppp_key_drop_num;
- net_stats->rx_dropped += hw_stats->all_32_bit_stats.ssu_key_drop_num;
-
net_stats->rx_errors = hw_stats->mac_stats.mac_rx_oversize_pkt_num;
net_stats->rx_errors += hw_stats->mac_stats.mac_rx_undersize_pkt_num;
- net_stats->rx_errors += hw_stats->all_32_bit_stats.igu_rx_no_eof_pkt;
- net_stats->rx_errors += hw_stats->all_32_bit_stats.igu_rx_no_sof_pkt;
net_stats->rx_errors += hw_stats->mac_stats.mac_rx_fcs_err_pkt_num;
net_stats->multicast = hw_stats->mac_stats.mac_tx_multi_pkt_num;
@@ -717,12 +443,6 @@ static void hclge_update_stats_for_all(struct hclge_dev *hdev)
dev_err(&hdev->pdev->dev,
"Update MAC stats fail, status = %d.\n", status);
- status = hclge_32_bit_update_stats(hdev);
- if (status)
- dev_err(&hdev->pdev->dev,
- "Update 32 bit stats fail, status = %d.\n",
- status);
-
hclge_update_netstat(&hdev->hw_stats, &handle->kinfo.netdev->stats);
}
@@ -743,18 +463,6 @@ static void hclge_update_stats(struct hnae3_handle *handle,
"Update MAC stats fail, status = %d.\n",
status);
- status = hclge_32_bit_update_stats(hdev);
- if (status)
- dev_err(&hdev->pdev->dev,
- "Update 32 bit stats fail, status = %d.\n",
- status);
-
- status = hclge_64_bit_update_stats(hdev);
- if (status)
- dev_err(&hdev->pdev->dev,
- "Update 64 bit stats fail, status = %d.\n",
- status);
-
status = hclge_tqps_update_stats(handle);
if (status)
dev_err(&hdev->pdev->dev,
@@ -768,7 +476,10 @@ static void hclge_update_stats(struct hnae3_handle *handle,
static int hclge_get_sset_count(struct hnae3_handle *handle, int stringset)
{
-#define HCLGE_LOOPBACK_TEST_FLAGS 0x7
+#define HCLGE_LOOPBACK_TEST_FLAGS (HNAE3_SUPPORT_APP_LOOPBACK |\
+ HNAE3_SUPPORT_PHY_LOOPBACK |\
+ HNAE3_SUPPORT_SERDES_SERIAL_LOOPBACK |\
+ HNAE3_SUPPORT_SERDES_PARALLEL_LOOPBACK)
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
@@ -782,19 +493,19 @@ static int hclge_get_sset_count(struct hnae3_handle *handle, int stringset)
if (stringset == ETH_SS_TEST) {
/* clear loopback bit flags at first */
handle->flags = (handle->flags & (~HCLGE_LOOPBACK_TEST_FLAGS));
- if (hdev->hw.mac.speed == HCLGE_MAC_SPEED_10M ||
+ if (hdev->pdev->revision >= 0x21 ||
+ hdev->hw.mac.speed == HCLGE_MAC_SPEED_10M ||
hdev->hw.mac.speed == HCLGE_MAC_SPEED_100M ||
hdev->hw.mac.speed == HCLGE_MAC_SPEED_1G) {
count += 1;
- handle->flags |= HNAE3_SUPPORT_MAC_LOOPBACK;
+ handle->flags |= HNAE3_SUPPORT_APP_LOOPBACK;
}
- count++;
- handle->flags |= HNAE3_SUPPORT_SERDES_LOOPBACK;
+ count += 2;
+ handle->flags |= HNAE3_SUPPORT_SERDES_SERIAL_LOOPBACK;
+ handle->flags |= HNAE3_SUPPORT_SERDES_PARALLEL_LOOPBACK;
} else if (stringset == ETH_SS_STATS) {
count = ARRAY_SIZE(g_mac_stats_string) +
- ARRAY_SIZE(g_all_32bit_stats_string) +
- ARRAY_SIZE(g_all_64bit_stats_string) +
hclge_tqps_get_sset_count(handle, stringset);
}
@@ -814,33 +525,29 @@ static void hclge_get_strings(struct hnae3_handle *handle,
g_mac_stats_string,
size,
p);
- size = ARRAY_SIZE(g_all_32bit_stats_string);
- p = hclge_comm_get_strings(stringset,
- g_all_32bit_stats_string,
- size,
- p);
- size = ARRAY_SIZE(g_all_64bit_stats_string);
- p = hclge_comm_get_strings(stringset,
- g_all_64bit_stats_string,
- size,
- p);
p = hclge_tqps_get_strings(handle, p);
} else if (stringset == ETH_SS_TEST) {
- if (handle->flags & HNAE3_SUPPORT_MAC_LOOPBACK) {
+ if (handle->flags & HNAE3_SUPPORT_APP_LOOPBACK) {
memcpy(p,
- hns3_nic_test_strs[HNAE3_MAC_INTER_LOOP_MAC],
+ hns3_nic_test_strs[HNAE3_LOOP_APP],
ETH_GSTRING_LEN);
p += ETH_GSTRING_LEN;
}
- if (handle->flags & HNAE3_SUPPORT_SERDES_LOOPBACK) {
+ if (handle->flags & HNAE3_SUPPORT_SERDES_SERIAL_LOOPBACK) {
memcpy(p,
- hns3_nic_test_strs[HNAE3_MAC_INTER_LOOP_SERDES],
+ hns3_nic_test_strs[HNAE3_LOOP_SERIAL_SERDES],
+ ETH_GSTRING_LEN);
+ p += ETH_GSTRING_LEN;
+ }
+ if (handle->flags & HNAE3_SUPPORT_SERDES_PARALLEL_LOOPBACK) {
+ memcpy(p,
+ hns3_nic_test_strs[HNAE3_LOOP_PARALLEL_SERDES],
ETH_GSTRING_LEN);
p += ETH_GSTRING_LEN;
}
if (handle->flags & HNAE3_SUPPORT_PHY_LOOPBACK) {
memcpy(p,
- hns3_nic_test_strs[HNAE3_MAC_INTER_LOOP_PHY],
+ hns3_nic_test_strs[HNAE3_LOOP_PHY],
ETH_GSTRING_LEN);
p += ETH_GSTRING_LEN;
}
@@ -857,14 +564,6 @@ static void hclge_get_stats(struct hnae3_handle *handle, u64 *data)
g_mac_stats_string,
ARRAY_SIZE(g_mac_stats_string),
data);
- p = hclge_comm_get_stats(&hdev->hw_stats.all_32_bit_stats,
- g_all_32bit_stats_string,
- ARRAY_SIZE(g_all_32bit_stats_string),
- p);
- p = hclge_comm_get_stats(&hdev->hw_stats.all_64_bit_stats,
- g_all_64bit_stats_string,
- ARRAY_SIZE(g_all_64bit_stats_string),
- p);
p = hclge_tqps_get_stats(handle, p);
}
@@ -1079,6 +778,11 @@ static void hclge_parse_cfg(struct hclge_cfg *cfg, struct hclge_desc *desc)
cfg->speed_ability = hnae3_get_field(__le32_to_cpu(req->param[1]),
HCLGE_CFG_SPEED_ABILITY_M,
HCLGE_CFG_SPEED_ABILITY_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);
+ if (!cfg->umv_space)
+ cfg->umv_space = HCLGE_DEFAULT_UMV_SPACE_PER_PF;
}
/* hclge_get_cfg: query the static parameter from flash
@@ -1157,6 +861,7 @@ static int hclge_configure(struct hclge_dev *hdev)
hdev->tm_info.num_pg = 1;
hdev->tc_max = cfg.tc_num;
hdev->tm_info.hw_pfc_map = 0;
+ hdev->wanted_umv_size = cfg.umv_space;
ret = hclge_parse_speed(cfg.default_speed, &hdev->hw.mac.speed);
if (ret) {
@@ -1657,11 +1362,13 @@ static int hclge_tx_buffer_calc(struct hclge_dev *hdev,
static int hclge_rx_buffer_calc(struct hclge_dev *hdev,
struct hclge_pkt_buf_alloc *buf_alloc)
{
- u32 rx_all = hdev->pkt_buf_size;
+#define HCLGE_BUF_SIZE_UNIT 128
+ u32 rx_all = hdev->pkt_buf_size, aligned_mps;
int no_pfc_priv_num, pfc_priv_num;
struct hclge_priv_buf *priv;
int i;
+ aligned_mps = round_up(hdev->mps, HCLGE_BUF_SIZE_UNIT);
rx_all -= hclge_get_tx_buff_alloced(buf_alloc);
/* When DCB is not supported, rx private
@@ -1680,13 +1387,13 @@ static int hclge_rx_buffer_calc(struct hclge_dev *hdev,
if (hdev->hw_tc_map & BIT(i)) {
priv->enable = 1;
if (hdev->tm_info.hw_pfc_map & BIT(i)) {
- priv->wl.low = hdev->mps;
- priv->wl.high = priv->wl.low + hdev->mps;
+ priv->wl.low = aligned_mps;
+ priv->wl.high = priv->wl.low + aligned_mps;
priv->buf_size = priv->wl.high +
HCLGE_DEFAULT_DV;
} else {
priv->wl.low = 0;
- priv->wl.high = 2 * hdev->mps;
+ priv->wl.high = 2 * aligned_mps;
priv->buf_size = priv->wl.high;
}
} else {
@@ -1718,11 +1425,11 @@ static int hclge_rx_buffer_calc(struct hclge_dev *hdev,
if (hdev->tm_info.hw_pfc_map & BIT(i)) {
priv->wl.low = 128;
- priv->wl.high = priv->wl.low + hdev->mps;
+ priv->wl.high = priv->wl.low + aligned_mps;
priv->buf_size = priv->wl.high + HCLGE_DEFAULT_DV;
} else {
priv->wl.low = 0;
- priv->wl.high = hdev->mps;
+ priv->wl.high = aligned_mps;
priv->buf_size = priv->wl.high;
}
}
@@ -2066,19 +1773,17 @@ static int hclge_init_msi(struct hclge_dev *hdev)
return 0;
}
-static void hclge_check_speed_dup(struct hclge_dev *hdev, int duplex, int speed)
+static u8 hclge_check_speed_dup(u8 duplex, int speed)
{
- struct hclge_mac *mac = &hdev->hw.mac;
- if ((speed == HCLGE_MAC_SPEED_10M) || (speed == HCLGE_MAC_SPEED_100M))
- mac->duplex = (u8)duplex;
- else
- mac->duplex = HCLGE_MAC_FULL;
+ if (!(speed == HCLGE_MAC_SPEED_10M || speed == HCLGE_MAC_SPEED_100M))
+ duplex = HCLGE_MAC_FULL;
- mac->speed = speed;
+ return duplex;
}
-int hclge_cfg_mac_speed_dup(struct hclge_dev *hdev, int speed, u8 duplex)
+static int hclge_cfg_mac_speed_dup_hw(struct hclge_dev *hdev, int speed,
+ u8 duplex)
{
struct hclge_config_mac_speed_dup_cmd *req;
struct hclge_desc desc;
@@ -2138,7 +1843,23 @@ int hclge_cfg_mac_speed_dup(struct hclge_dev *hdev, int speed, u8 duplex)
return ret;
}
- hclge_check_speed_dup(hdev, duplex, speed);
+ return 0;
+}
+
+int hclge_cfg_mac_speed_dup(struct hclge_dev *hdev, int speed, u8 duplex)
+{
+ int ret;
+
+ duplex = hclge_check_speed_dup(duplex, speed);
+ if (hdev->hw.mac.speed == speed && hdev->hw.mac.duplex == duplex)
+ return 0;
+
+ ret = hclge_cfg_mac_speed_dup_hw(hdev, speed, duplex);
+ if (ret)
+ return ret;
+
+ hdev->hw.mac.speed = speed;
+ hdev->hw.mac.duplex = duplex;
return 0;
}
@@ -2224,42 +1945,17 @@ static int hclge_get_autoneg(struct hnae3_handle *handle)
return hdev->hw.mac.autoneg;
}
-static int hclge_set_default_mac_vlan_mask(struct hclge_dev *hdev,
- bool mask_vlan,
- u8 *mac_mask)
-{
- struct hclge_mac_vlan_mask_entry_cmd *req;
- struct hclge_desc desc;
- int status;
-
- req = (struct hclge_mac_vlan_mask_entry_cmd *)desc.data;
- hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MAC_VLAN_MASK_SET, false);
-
- hnae3_set_bit(req->vlan_mask, HCLGE_VLAN_MASK_EN_B,
- mask_vlan ? 1 : 0);
- ether_addr_copy(req->mac_mask, mac_mask);
-
- status = hclge_cmd_send(&hdev->hw, &desc, 1);
- if (status)
- dev_err(&hdev->pdev->dev,
- "Config mac_vlan_mask failed for cmd_send, ret =%d\n",
- status);
-
- return status;
-}
-
static int hclge_mac_init(struct hclge_dev *hdev)
{
struct hnae3_handle *handle = &hdev->vport[0].nic;
struct net_device *netdev = handle->kinfo.netdev;
struct hclge_mac *mac = &hdev->hw.mac;
- u8 mac_mask[ETH_ALEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
- struct hclge_vport *vport;
int mtu;
int ret;
- int i;
- ret = hclge_cfg_mac_speed_dup(hdev, hdev->hw.mac.speed, HCLGE_MAC_FULL);
+ hdev->hw.mac.duplex = HCLGE_MAC_FULL;
+ ret = hclge_cfg_mac_speed_dup_hw(hdev, hdev->hw.mac.speed,
+ hdev->hw.mac.duplex);
if (ret) {
dev_err(&hdev->pdev->dev,
"Config mac speed dup fail ret=%d\n", ret);
@@ -2268,39 +1964,6 @@ static int hclge_mac_init(struct hclge_dev *hdev)
mac->link = 0;
- /* Initialize the MTA table work mode */
- hdev->enable_mta = true;
- hdev->mta_mac_sel_type = HCLGE_MAC_ADDR_47_36;
-
- ret = hclge_set_mta_filter_mode(hdev,
- hdev->mta_mac_sel_type,
- hdev->enable_mta);
- if (ret) {
- dev_err(&hdev->pdev->dev, "set mta filter mode failed %d\n",
- ret);
- return ret;
- }
-
- for (i = 0; i < hdev->num_alloc_vport; i++) {
- vport = &hdev->vport[i];
- vport->accept_mta_mc = false;
-
- memset(vport->mta_shadow, 0, sizeof(vport->mta_shadow));
- ret = hclge_cfg_func_mta_filter(hdev, vport->vport_id, false);
- if (ret) {
- dev_err(&hdev->pdev->dev,
- "set mta filter mode fail ret=%d\n", ret);
- return ret;
- }
- }
-
- ret = hclge_set_default_mac_vlan_mask(hdev, true, mac_mask);
- if (ret) {
- dev_err(&hdev->pdev->dev,
- "set default mac_vlan_mask fail ret=%d\n", ret);
- return ret;
- }
-
if (netdev)
mtu = netdev->mtu;
else
@@ -2360,10 +2023,13 @@ static int hclge_get_mac_phy_link(struct hclge_dev *hdev)
int mac_state;
int link_stat;
+ if (test_bit(HCLGE_STATE_DOWN, &hdev->state))
+ return 0;
+
mac_state = hclge_get_mac_link_status(hdev);
if (hdev->hw.mac.phydev) {
- if (!genphy_read_status(hdev->hw.mac.phydev))
+ if (hdev->hw.mac.phydev->state == PHY_RUNNING)
link_stat = mac_state &
hdev->hw.mac.phydev->link;
else
@@ -2415,13 +2081,11 @@ static int hclge_update_speed_duplex(struct hclge_dev *hdev)
return ret;
}
- if ((mac.speed != speed) || (mac.duplex != duplex)) {
- ret = hclge_cfg_mac_speed_dup(hdev, speed, duplex);
- if (ret) {
- dev_err(&hdev->pdev->dev,
- "mac speed/duplex config failed %d\n", ret);
- return ret;
- }
+ ret = hclge_cfg_mac_speed_dup(hdev, speed, duplex);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "mac speed/duplex config failed %d\n", ret);
+ return ret;
}
return 0;
@@ -2520,6 +2184,8 @@ static void hclge_clear_event_cause(struct hclge_dev *hdev, u32 event_type,
case HCLGE_VECTOR0_EVENT_MBX:
hclge_write_dev(&hdev->hw, HCLGE_VECTOR0_CMDQ_SRC_REG, regclr);
break;
+ default:
+ break;
}
}
@@ -2570,7 +2236,7 @@ static irqreturn_t hclge_misc_irq_handle(int irq, void *data)
}
/* clear the source of interrupt if it is not cause by reset */
- if (event_cause != HCLGE_VECTOR0_EVENT_RST) {
+ if (event_cause == HCLGE_VECTOR0_EVENT_MBX) {
hclge_clear_event_cause(hdev, event_cause, clearval);
hclge_enable_vector(&hdev->misc_vector, true);
}
@@ -2793,20 +2459,28 @@ static void hclge_clear_reset_cause(struct hclge_dev *hdev)
static void hclge_reset(struct hclge_dev *hdev)
{
+ struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev);
struct hnae3_handle *handle;
+ /* Initialize ae_dev reset status as well, in case enet layer wants to
+ * know if device is undergoing reset
+ */
+ ae_dev->reset_type = hdev->reset_type;
/* perform reset of the stack & ae device for a client */
handle = &hdev->vport[0].nic;
rtnl_lock();
hclge_notify_client(hdev, HNAE3_DOWN_CLIENT);
+ rtnl_unlock();
if (!hclge_reset_wait(hdev)) {
+ rtnl_lock();
hclge_notify_client(hdev, HNAE3_UNINIT_CLIENT);
hclge_reset_ae_dev(hdev->ae_dev);
hclge_notify_client(hdev, HNAE3_INIT_CLIENT);
hclge_clear_reset_cause(hdev);
} else {
+ rtnl_lock();
/* schedule again to check pending resets later */
set_bit(hdev->reset_type, &hdev->reset_pending);
hclge_reset_task_schedule(hdev);
@@ -2815,14 +2489,21 @@ static void hclge_reset(struct hclge_dev *hdev)
hclge_notify_client(hdev, HNAE3_UP_CLIENT);
handle->last_reset_time = jiffies;
rtnl_unlock();
+ ae_dev->reset_type = HNAE3_NONE_RESET;
}
-static void hclge_reset_event(struct hnae3_handle *handle)
+static void hclge_reset_event(struct pci_dev *pdev, struct hnae3_handle *handle)
{
- struct hclge_vport *vport = hclge_get_vport(handle);
- struct hclge_dev *hdev = vport->back;
+ struct hnae3_ae_dev *ae_dev = pci_get_drvdata(pdev);
+ struct hclge_dev *hdev = ae_dev->priv;
- /* check if this is a new reset request and we are not here just because
+ /* We might end up getting called broadly because of 2 below cases:
+ * 1. Recoverable error was conveyed through APEI and only way to bring
+ * normalcy is to reset.
+ * 2. A new reset request from the stack due to timeout
+ *
+ * For the first case,error event might not have ae handle available.
+ * check if this is a new reset request and we are not here just because
* last reset attempt did not succeed and watchdog hit us again. We will
* know this if last reset request did not occur very recently (watchdog
* timer = 5*HZ, let us check after sufficiently large time, say 4*5*Hz)
@@ -2831,6 +2512,9 @@ static void hclge_reset_event(struct hnae3_handle *handle)
* want to make sure we throttle the reset request. Therefore, we will
* not allow it again before 3*HZ times.
*/
+ if (!handle)
+ handle = &hdev->vport[0].nic;
+
if (time_before(jiffies, (handle->last_reset_time + 3 * HZ)))
return;
else if (time_after(jiffies, (handle->last_reset_time + 4 * 5 * HZ)))
@@ -3102,6 +2786,22 @@ static int hclge_set_rss_tc_mode(struct hclge_dev *hdev, u16 *tc_valid,
return ret;
}
+static void hclge_get_rss_type(struct hclge_vport *vport)
+{
+ if (vport->rss_tuple_sets.ipv4_tcp_en ||
+ vport->rss_tuple_sets.ipv4_udp_en ||
+ vport->rss_tuple_sets.ipv4_sctp_en ||
+ vport->rss_tuple_sets.ipv6_tcp_en ||
+ vport->rss_tuple_sets.ipv6_udp_en ||
+ vport->rss_tuple_sets.ipv6_sctp_en)
+ vport->nic.kinfo.rss_type = PKT_HASH_TYPE_L4;
+ else if (vport->rss_tuple_sets.ipv4_fragment_en ||
+ vport->rss_tuple_sets.ipv6_fragment_en)
+ vport->nic.kinfo.rss_type = PKT_HASH_TYPE_L3;
+ else
+ vport->nic.kinfo.rss_type = PKT_HASH_TYPE_NONE;
+}
+
static int hclge_set_rss_input_tuple(struct hclge_dev *hdev)
{
struct hclge_rss_input_tuple_cmd *req;
@@ -3121,6 +2821,7 @@ static int hclge_set_rss_input_tuple(struct hclge_dev *hdev)
req->ipv6_udp_en = hdev->vport[0].rss_tuple_sets.ipv6_udp_en;
req->ipv6_sctp_en = hdev->vport[0].rss_tuple_sets.ipv6_sctp_en;
req->ipv6_fragment_en = hdev->vport[0].rss_tuple_sets.ipv6_fragment_en;
+ hclge_get_rss_type(&hdev->vport[0]);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret)
dev_err(&hdev->pdev->dev,
@@ -3135,8 +2836,19 @@ static int hclge_get_rss(struct hnae3_handle *handle, u32 *indir,
int i;
/* Get hash algorithm */
- if (hfunc)
- *hfunc = vport->rss_algo;
+ if (hfunc) {
+ switch (vport->rss_algo) {
+ case HCLGE_RSS_HASH_ALGO_TOEPLITZ:
+ *hfunc = ETH_RSS_HASH_TOP;
+ break;
+ case HCLGE_RSS_HASH_ALGO_SIMPLE:
+ *hfunc = ETH_RSS_HASH_XOR;
+ break;
+ default:
+ *hfunc = ETH_RSS_HASH_UNKNOWN;
+ break;
+ }
+ }
/* Get the RSS Key required by the user */
if (key)
@@ -3160,12 +2872,20 @@ static int hclge_set_rss(struct hnae3_handle *handle, const u32 *indir,
/* Set the RSS Hash Key if specififed by the user */
if (key) {
-
- if (hfunc == ETH_RSS_HASH_TOP ||
- hfunc == ETH_RSS_HASH_NO_CHANGE)
+ switch (hfunc) {
+ case ETH_RSS_HASH_TOP:
hash_algo = HCLGE_RSS_HASH_ALGO_TOEPLITZ;
- else
+ break;
+ case ETH_RSS_HASH_XOR:
+ hash_algo = HCLGE_RSS_HASH_ALGO_SIMPLE;
+ break;
+ case ETH_RSS_HASH_NO_CHANGE:
+ hash_algo = vport->rss_algo;
+ break;
+ default:
return -EINVAL;
+ }
+
ret = hclge_set_rss_algo_key(hdev, hash_algo, key);
if (ret)
return ret;
@@ -3283,6 +3003,7 @@ static int hclge_set_rss_tuple(struct hnae3_handle *handle,
vport->rss_tuple_sets.ipv6_udp_en = req->ipv6_udp_en;
vport->rss_tuple_sets.ipv6_sctp_en = req->ipv6_sctp_en;
vport->rss_tuple_sets.ipv6_fragment_en = req->ipv6_fragment_en;
+ hclge_get_rss_type(vport);
return 0;
}
@@ -3596,8 +3317,8 @@ void hclge_promisc_param_init(struct hclge_promisc_param *param, bool en_uc,
param->vf_id = vport_id;
}
-static void hclge_set_promisc_mode(struct hnae3_handle *handle, bool en_uc_pmc,
- bool en_mc_pmc)
+static int hclge_set_promisc_mode(struct hnae3_handle *handle, bool en_uc_pmc,
+ bool en_mc_pmc)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
@@ -3605,7 +3326,1282 @@ static void hclge_set_promisc_mode(struct hnae3_handle *handle, bool en_uc_pmc,
hclge_promisc_param_init(&param, en_uc_pmc, en_mc_pmc, true,
vport->vport_id);
- hclge_cmd_set_promisc_mode(hdev, &param);
+ return hclge_cmd_set_promisc_mode(hdev, &param);
+}
+
+static int hclge_get_fd_mode(struct hclge_dev *hdev, u8 *fd_mode)
+{
+ struct hclge_get_fd_mode_cmd *req;
+ struct hclge_desc desc;
+ int ret;
+
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_FD_MODE_CTRL, true);
+
+ req = (struct hclge_get_fd_mode_cmd *)desc.data;
+
+ ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ if (ret) {
+ dev_err(&hdev->pdev->dev, "get fd mode fail, ret=%d\n", ret);
+ return ret;
+ }
+
+ *fd_mode = req->mode;
+
+ return ret;
+}
+
+static int hclge_get_fd_allocation(struct hclge_dev *hdev,
+ u32 *stage1_entry_num,
+ u32 *stage2_entry_num,
+ u16 *stage1_counter_num,
+ u16 *stage2_counter_num)
+{
+ struct hclge_get_fd_allocation_cmd *req;
+ struct hclge_desc desc;
+ int ret;
+
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_FD_GET_ALLOCATION, true);
+
+ req = (struct hclge_get_fd_allocation_cmd *)desc.data;
+
+ ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ if (ret) {
+ dev_err(&hdev->pdev->dev, "query fd allocation fail, ret=%d\n",
+ ret);
+ return ret;
+ }
+
+ *stage1_entry_num = le32_to_cpu(req->stage1_entry_num);
+ *stage2_entry_num = le32_to_cpu(req->stage2_entry_num);
+ *stage1_counter_num = le16_to_cpu(req->stage1_counter_num);
+ *stage2_counter_num = le16_to_cpu(req->stage2_counter_num);
+
+ return ret;
+}
+
+static int hclge_set_fd_key_config(struct hclge_dev *hdev, int stage_num)
+{
+ struct hclge_set_fd_key_config_cmd *req;
+ struct hclge_fd_key_cfg *stage;
+ struct hclge_desc desc;
+ int ret;
+
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_FD_KEY_CONFIG, false);
+
+ req = (struct hclge_set_fd_key_config_cmd *)desc.data;
+ stage = &hdev->fd_cfg.key_cfg[stage_num];
+ req->stage = stage_num;
+ req->key_select = stage->key_sel;
+ req->inner_sipv6_word_en = stage->inner_sipv6_word_en;
+ req->inner_dipv6_word_en = stage->inner_dipv6_word_en;
+ req->outer_sipv6_word_en = stage->outer_sipv6_word_en;
+ req->outer_dipv6_word_en = stage->outer_dipv6_word_en;
+ req->tuple_mask = cpu_to_le32(~stage->tuple_active);
+ req->meta_data_mask = cpu_to_le32(~stage->meta_data_active);
+
+ ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ if (ret)
+ dev_err(&hdev->pdev->dev, "set fd key fail, ret=%d\n", ret);
+
+ return ret;
+}
+
+static int hclge_init_fd_config(struct hclge_dev *hdev)
+{
+#define LOW_2_WORDS 0x03
+ struct hclge_fd_key_cfg *key_cfg;
+ int ret;
+
+ if (!hnae3_dev_fd_supported(hdev))
+ return 0;
+
+ ret = hclge_get_fd_mode(hdev, &hdev->fd_cfg.fd_mode);
+ if (ret)
+ return ret;
+
+ switch (hdev->fd_cfg.fd_mode) {
+ case HCLGE_FD_MODE_DEPTH_2K_WIDTH_400B_STAGE_1:
+ hdev->fd_cfg.max_key_length = MAX_KEY_LENGTH;
+ break;
+ case HCLGE_FD_MODE_DEPTH_4K_WIDTH_200B_STAGE_1:
+ hdev->fd_cfg.max_key_length = MAX_KEY_LENGTH / 2;
+ break;
+ default:
+ dev_err(&hdev->pdev->dev,
+ "Unsupported flow director mode %d\n",
+ hdev->fd_cfg.fd_mode);
+ return -EOPNOTSUPP;
+ }
+
+ hdev->fd_cfg.fd_en = true;
+ hdev->fd_cfg.proto_support =
+ TCP_V4_FLOW | UDP_V4_FLOW | SCTP_V4_FLOW | TCP_V6_FLOW |
+ UDP_V6_FLOW | SCTP_V6_FLOW | IPV4_USER_FLOW | IPV6_USER_FLOW;
+ key_cfg = &hdev->fd_cfg.key_cfg[HCLGE_FD_STAGE_1];
+ key_cfg->key_sel = HCLGE_FD_KEY_BASE_ON_TUPLE,
+ key_cfg->inner_sipv6_word_en = LOW_2_WORDS;
+ key_cfg->inner_dipv6_word_en = LOW_2_WORDS;
+ key_cfg->outer_sipv6_word_en = 0;
+ key_cfg->outer_dipv6_word_en = 0;
+
+ key_cfg->tuple_active = BIT(INNER_VLAN_TAG_FST) | BIT(INNER_ETH_TYPE) |
+ BIT(INNER_IP_PROTO) | BIT(INNER_IP_TOS) |
+ BIT(INNER_SRC_IP) | BIT(INNER_DST_IP) |
+ BIT(INNER_SRC_PORT) | BIT(INNER_DST_PORT);
+
+ /* If use max 400bit key, we can support tuples for ether type */
+ if (hdev->fd_cfg.max_key_length == MAX_KEY_LENGTH) {
+ hdev->fd_cfg.proto_support |= ETHER_FLOW;
+ key_cfg->tuple_active |=
+ BIT(INNER_DST_MAC) | BIT(INNER_SRC_MAC);
+ }
+
+ /* roce_type is used to filter roce frames
+ * dst_vport is used to specify the rule
+ */
+ key_cfg->meta_data_active = BIT(ROCE_TYPE) | BIT(DST_VPORT);
+
+ ret = hclge_get_fd_allocation(hdev,
+ &hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1],
+ &hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_2],
+ &hdev->fd_cfg.cnt_num[HCLGE_FD_STAGE_1],
+ &hdev->fd_cfg.cnt_num[HCLGE_FD_STAGE_2]);
+ if (ret)
+ return ret;
+
+ return hclge_set_fd_key_config(hdev, HCLGE_FD_STAGE_1);
+}
+
+static int hclge_fd_tcam_config(struct hclge_dev *hdev, u8 stage, bool sel_x,
+ int loc, u8 *key, bool is_add)
+{
+ 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 ret;
+
+ hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_FD_TCAM_OP, false);
+ desc[0].flag |= cpu_to_le16(HCLGE_CMD_FLAG_NEXT);
+ hclge_cmd_setup_basic_desc(&desc[1], HCLGE_OPC_FD_TCAM_OP, false);
+ desc[1].flag |= cpu_to_le16(HCLGE_CMD_FLAG_NEXT);
+ hclge_cmd_setup_basic_desc(&desc[2], HCLGE_OPC_FD_TCAM_OP, false);
+
+ req1 = (struct hclge_fd_tcam_config_1_cmd *)desc[0].data;
+ 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->xy_sel = sel_x ? 1 : 0;
+ hnae3_set_bit(req1->port_info, HCLGE_FD_EPORT_SW_EN_B, 0);
+ req1->index = cpu_to_le32(loc);
+ req1->entry_vld = sel_x ? is_add : 0;
+
+ if (key) {
+ memcpy(req1->tcam_data, &key[0], sizeof(req1->tcam_data));
+ memcpy(req2->tcam_data, &key[sizeof(req1->tcam_data)],
+ sizeof(req2->tcam_data));
+ memcpy(req3->tcam_data, &key[sizeof(req1->tcam_data) +
+ sizeof(req2->tcam_data)], sizeof(req3->tcam_data));
+ }
+
+ ret = hclge_cmd_send(&hdev->hw, desc, 3);
+ if (ret)
+ dev_err(&hdev->pdev->dev,
+ "config tcam key fail, ret=%d\n",
+ ret);
+
+ return ret;
+}
+
+static int hclge_fd_ad_config(struct hclge_dev *hdev, u8 stage, int loc,
+ struct hclge_fd_ad_data *action)
+{
+ struct hclge_fd_ad_config_cmd *req;
+ struct hclge_desc desc;
+ u64 ad_data = 0;
+ int ret;
+
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_FD_AD_OP, false);
+
+ req = (struct hclge_fd_ad_config_cmd *)desc.data;
+ req->index = cpu_to_le32(loc);
+ req->stage = stage;
+
+ hnae3_set_bit(ad_data, HCLGE_FD_AD_WR_RULE_ID_B,
+ action->write_rule_id_to_bd);
+ hnae3_set_field(ad_data, HCLGE_FD_AD_RULE_ID_M, HCLGE_FD_AD_RULE_ID_S,
+ action->rule_id);
+ ad_data <<= 32;
+ hnae3_set_bit(ad_data, HCLGE_FD_AD_DROP_B, action->drop_packet);
+ hnae3_set_bit(ad_data, HCLGE_FD_AD_DIRECT_QID_B,
+ action->forward_to_direct_queue);
+ hnae3_set_field(ad_data, HCLGE_FD_AD_QID_M, HCLGE_FD_AD_QID_S,
+ action->queue_id);
+ hnae3_set_bit(ad_data, HCLGE_FD_AD_USE_COUNTER_B, action->use_counter);
+ hnae3_set_field(ad_data, HCLGE_FD_AD_COUNTER_NUM_M,
+ HCLGE_FD_AD_COUNTER_NUM_S, action->counter_id);
+ hnae3_set_bit(ad_data, HCLGE_FD_AD_NXT_STEP_B, action->use_next_stage);
+ hnae3_set_field(ad_data, HCLGE_FD_AD_NXT_KEY_M, HCLGE_FD_AD_NXT_KEY_S,
+ action->counter_id);
+
+ req->ad_data = cpu_to_le64(ad_data);
+ ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ if (ret)
+ dev_err(&hdev->pdev->dev, "fd ad config fail, ret=%d\n", ret);
+
+ return ret;
+}
+
+static bool hclge_fd_convert_tuple(u32 tuple_bit, u8 *key_x, u8 *key_y,
+ struct hclge_fd_rule *rule)
+{
+ u16 tmp_x_s, tmp_y_s;
+ u32 tmp_x_l, tmp_y_l;
+ int i;
+
+ if (rule->unused_tuple & tuple_bit)
+ return true;
+
+ switch (tuple_bit) {
+ case 0:
+ return false;
+ case BIT(INNER_DST_MAC):
+ for (i = 0; i < 6; i++) {
+ calc_x(key_x[5 - i], rule->tuples.dst_mac[i],
+ rule->tuples_mask.dst_mac[i]);
+ calc_y(key_y[5 - i], rule->tuples.dst_mac[i],
+ rule->tuples_mask.dst_mac[i]);
+ }
+
+ return true;
+ case BIT(INNER_SRC_MAC):
+ for (i = 0; i < 6; i++) {
+ calc_x(key_x[5 - i], rule->tuples.src_mac[i],
+ rule->tuples.src_mac[i]);
+ calc_y(key_y[5 - i], rule->tuples.src_mac[i],
+ rule->tuples.src_mac[i]);
+ }
+
+ return true;
+ case BIT(INNER_VLAN_TAG_FST):
+ calc_x(tmp_x_s, rule->tuples.vlan_tag1,
+ rule->tuples_mask.vlan_tag1);
+ calc_y(tmp_y_s, rule->tuples.vlan_tag1,
+ rule->tuples_mask.vlan_tag1);
+ *(__le16 *)key_x = cpu_to_le16(tmp_x_s);
+ *(__le16 *)key_y = cpu_to_le16(tmp_y_s);
+
+ return true;
+ case BIT(INNER_ETH_TYPE):
+ calc_x(tmp_x_s, rule->tuples.ether_proto,
+ rule->tuples_mask.ether_proto);
+ calc_y(tmp_y_s, rule->tuples.ether_proto,
+ rule->tuples_mask.ether_proto);
+ *(__le16 *)key_x = cpu_to_le16(tmp_x_s);
+ *(__le16 *)key_y = cpu_to_le16(tmp_y_s);
+
+ return true;
+ case BIT(INNER_IP_TOS):
+ calc_x(*key_x, rule->tuples.ip_tos, rule->tuples_mask.ip_tos);
+ calc_y(*key_y, rule->tuples.ip_tos, rule->tuples_mask.ip_tos);
+
+ return true;
+ case BIT(INNER_IP_PROTO):
+ calc_x(*key_x, rule->tuples.ip_proto,
+ rule->tuples_mask.ip_proto);
+ calc_y(*key_y, rule->tuples.ip_proto,
+ rule->tuples_mask.ip_proto);
+
+ return true;
+ case BIT(INNER_SRC_IP):
+ calc_x(tmp_x_l, rule->tuples.src_ip[3],
+ rule->tuples_mask.src_ip[3]);
+ calc_y(tmp_y_l, rule->tuples.src_ip[3],
+ rule->tuples_mask.src_ip[3]);
+ *(__le32 *)key_x = cpu_to_le32(tmp_x_l);
+ *(__le32 *)key_y = cpu_to_le32(tmp_y_l);
+
+ return true;
+ case BIT(INNER_DST_IP):
+ calc_x(tmp_x_l, rule->tuples.dst_ip[3],
+ rule->tuples_mask.dst_ip[3]);
+ calc_y(tmp_y_l, rule->tuples.dst_ip[3],
+ rule->tuples_mask.dst_ip[3]);
+ *(__le32 *)key_x = cpu_to_le32(tmp_x_l);
+ *(__le32 *)key_y = cpu_to_le32(tmp_y_l);
+
+ return true;
+ case BIT(INNER_SRC_PORT):
+ calc_x(tmp_x_s, rule->tuples.src_port,
+ rule->tuples_mask.src_port);
+ calc_y(tmp_y_s, rule->tuples.src_port,
+ rule->tuples_mask.src_port);
+ *(__le16 *)key_x = cpu_to_le16(tmp_x_s);
+ *(__le16 *)key_y = cpu_to_le16(tmp_y_s);
+
+ return true;
+ case BIT(INNER_DST_PORT):
+ calc_x(tmp_x_s, rule->tuples.dst_port,
+ rule->tuples_mask.dst_port);
+ calc_y(tmp_y_s, rule->tuples.dst_port,
+ rule->tuples_mask.dst_port);
+ *(__le16 *)key_x = cpu_to_le16(tmp_x_s);
+ *(__le16 *)key_y = cpu_to_le16(tmp_y_s);
+
+ return true;
+ default:
+ return false;
+ }
+}
+
+static u32 hclge_get_port_number(enum HLCGE_PORT_TYPE port_type, u8 pf_id,
+ u8 vf_id, u8 network_port_id)
+{
+ u32 port_number = 0;
+
+ if (port_type == HOST_PORT) {
+ hnae3_set_field(port_number, HCLGE_PF_ID_M, HCLGE_PF_ID_S,
+ pf_id);
+ hnae3_set_field(port_number, HCLGE_VF_ID_M, HCLGE_VF_ID_S,
+ vf_id);
+ hnae3_set_bit(port_number, HCLGE_PORT_TYPE_B, HOST_PORT);
+ } else {
+ hnae3_set_field(port_number, HCLGE_NETWORK_PORT_ID_M,
+ HCLGE_NETWORK_PORT_ID_S, network_port_id);
+ hnae3_set_bit(port_number, HCLGE_PORT_TYPE_B, NETWORK_PORT);
+ }
+
+ return port_number;
+}
+
+static void hclge_fd_convert_meta_data(struct hclge_fd_key_cfg *key_cfg,
+ __le32 *key_x, __le32 *key_y,
+ struct hclge_fd_rule *rule)
+{
+ u32 tuple_bit, meta_data = 0, tmp_x, tmp_y, port_number;
+ u8 cur_pos = 0, tuple_size, shift_bits;
+ int i;
+
+ for (i = 0; i < MAX_META_DATA; i++) {
+ tuple_size = meta_data_key_info[i].key_length;
+ tuple_bit = key_cfg->meta_data_active & BIT(i);
+
+ switch (tuple_bit) {
+ case BIT(ROCE_TYPE):
+ hnae3_set_bit(meta_data, cur_pos, NIC_PACKET);
+ cur_pos += tuple_size;
+ break;
+ case BIT(DST_VPORT):
+ port_number = hclge_get_port_number(HOST_PORT, 0,
+ rule->vf_id, 0);
+ hnae3_set_field(meta_data,
+ GENMASK(cur_pos + tuple_size, cur_pos),
+ cur_pos, port_number);
+ cur_pos += tuple_size;
+ break;
+ default:
+ break;
+ }
+ }
+
+ calc_x(tmp_x, meta_data, 0xFFFFFFFF);
+ calc_y(tmp_y, meta_data, 0xFFFFFFFF);
+ shift_bits = sizeof(meta_data) * 8 - cur_pos;
+
+ *key_x = cpu_to_le32(tmp_x << shift_bits);
+ *key_y = cpu_to_le32(tmp_y << shift_bits);
+}
+
+/* A complete key is combined with meta data key and tuple key.
+ * Meta data key is stored at the MSB region, and tuple key is stored at
+ * the LSB region, unused bits will be filled 0.
+ */
+static int hclge_config_key(struct hclge_dev *hdev, u8 stage,
+ struct hclge_fd_rule *rule)
+{
+ struct hclge_fd_key_cfg *key_cfg = &hdev->fd_cfg.key_cfg[stage];
+ u8 key_x[MAX_KEY_BYTES], key_y[MAX_KEY_BYTES];
+ u8 *cur_key_x, *cur_key_y;
+ int i, ret, tuple_size;
+ u8 meta_data_region;
+
+ memset(key_x, 0, sizeof(key_x));
+ memset(key_y, 0, sizeof(key_y));
+ cur_key_x = key_x;
+ cur_key_y = key_y;
+
+ for (i = 0 ; i < MAX_TUPLE; i++) {
+ bool tuple_valid;
+ u32 check_tuple;
+
+ tuple_size = tuple_key_info[i].key_length / 8;
+ check_tuple = key_cfg->tuple_active & BIT(i);
+
+ tuple_valid = hclge_fd_convert_tuple(check_tuple, cur_key_x,
+ cur_key_y, rule);
+ if (tuple_valid) {
+ cur_key_x += tuple_size;
+ cur_key_y += tuple_size;
+ }
+ }
+
+ meta_data_region = hdev->fd_cfg.max_key_length / 8 -
+ MAX_META_DATA_LENGTH / 8;
+
+ hclge_fd_convert_meta_data(key_cfg,
+ (__le32 *)(key_x + meta_data_region),
+ (__le32 *)(key_y + meta_data_region),
+ rule);
+
+ ret = hclge_fd_tcam_config(hdev, stage, false, rule->location, key_y,
+ true);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "fd key_y config fail, loc=%d, ret=%d\n",
+ rule->queue_id, ret);
+ return ret;
+ }
+
+ ret = hclge_fd_tcam_config(hdev, stage, true, rule->location, key_x,
+ true);
+ if (ret)
+ dev_err(&hdev->pdev->dev,
+ "fd key_x config fail, loc=%d, ret=%d\n",
+ rule->queue_id, ret);
+ return ret;
+}
+
+static int hclge_config_action(struct hclge_dev *hdev, u8 stage,
+ struct hclge_fd_rule *rule)
+{
+ struct hclge_fd_ad_data ad_data;
+
+ ad_data.ad_id = rule->location;
+
+ if (rule->action == HCLGE_FD_ACTION_DROP_PACKET) {
+ ad_data.drop_packet = true;
+ ad_data.forward_to_direct_queue = false;
+ ad_data.queue_id = 0;
+ } else {
+ ad_data.drop_packet = false;
+ ad_data.forward_to_direct_queue = true;
+ ad_data.queue_id = rule->queue_id;
+ }
+
+ ad_data.use_counter = false;
+ ad_data.counter_id = 0;
+
+ ad_data.use_next_stage = false;
+ ad_data.next_input_key = 0;
+
+ ad_data.write_rule_id_to_bd = true;
+ ad_data.rule_id = rule->location;
+
+ return hclge_fd_ad_config(hdev, stage, ad_data.ad_id, &ad_data);
+}
+
+static int hclge_fd_check_spec(struct hclge_dev *hdev,
+ struct ethtool_rx_flow_spec *fs, u32 *unused)
+{
+ struct ethtool_tcpip4_spec *tcp_ip4_spec;
+ struct ethtool_usrip4_spec *usr_ip4_spec;
+ struct ethtool_tcpip6_spec *tcp_ip6_spec;
+ struct ethtool_usrip6_spec *usr_ip6_spec;
+ struct ethhdr *ether_spec;
+
+ if (fs->location >= hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1])
+ return -EINVAL;
+
+ if (!(fs->flow_type & hdev->fd_cfg.proto_support))
+ return -EOPNOTSUPP;
+
+ if ((fs->flow_type & FLOW_EXT) &&
+ (fs->h_ext.data[0] != 0 || fs->h_ext.data[1] != 0)) {
+ dev_err(&hdev->pdev->dev, "user-def bytes are not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ switch (fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) {
+ case SCTP_V4_FLOW:
+ case TCP_V4_FLOW:
+ case UDP_V4_FLOW:
+ tcp_ip4_spec = &fs->h_u.tcp_ip4_spec;
+ *unused |= BIT(INNER_SRC_MAC) | BIT(INNER_DST_MAC);
+
+ if (!tcp_ip4_spec->ip4src)
+ *unused |= BIT(INNER_SRC_IP);
+
+ if (!tcp_ip4_spec->ip4dst)
+ *unused |= BIT(INNER_DST_IP);
+
+ if (!tcp_ip4_spec->psrc)
+ *unused |= BIT(INNER_SRC_PORT);
+
+ if (!tcp_ip4_spec->pdst)
+ *unused |= BIT(INNER_DST_PORT);
+
+ if (!tcp_ip4_spec->tos)
+ *unused |= BIT(INNER_IP_TOS);
+
+ break;
+ case IP_USER_FLOW:
+ usr_ip4_spec = &fs->h_u.usr_ip4_spec;
+ *unused |= BIT(INNER_SRC_MAC) | BIT(INNER_DST_MAC) |
+ BIT(INNER_SRC_PORT) | BIT(INNER_DST_PORT);
+
+ if (!usr_ip4_spec->ip4src)
+ *unused |= BIT(INNER_SRC_IP);
+
+ if (!usr_ip4_spec->ip4dst)
+ *unused |= BIT(INNER_DST_IP);
+
+ if (!usr_ip4_spec->tos)
+ *unused |= BIT(INNER_IP_TOS);
+
+ if (!usr_ip4_spec->proto)
+ *unused |= BIT(INNER_IP_PROTO);
+
+ if (usr_ip4_spec->l4_4_bytes)
+ return -EOPNOTSUPP;
+
+ if (usr_ip4_spec->ip_ver != ETH_RX_NFC_IP4)
+ return -EOPNOTSUPP;
+
+ break;
+ case SCTP_V6_FLOW:
+ case TCP_V6_FLOW:
+ case UDP_V6_FLOW:
+ tcp_ip6_spec = &fs->h_u.tcp_ip6_spec;
+ *unused |= BIT(INNER_SRC_MAC) | BIT(INNER_DST_MAC) |
+ BIT(INNER_IP_TOS);
+
+ if (!tcp_ip6_spec->ip6src[0] && !tcp_ip6_spec->ip6src[1] &&
+ !tcp_ip6_spec->ip6src[2] && !tcp_ip6_spec->ip6src[3])
+ *unused |= BIT(INNER_SRC_IP);
+
+ if (!tcp_ip6_spec->ip6dst[0] && !tcp_ip6_spec->ip6dst[1] &&
+ !tcp_ip6_spec->ip6dst[2] && !tcp_ip6_spec->ip6dst[3])
+ *unused |= BIT(INNER_DST_IP);
+
+ if (!tcp_ip6_spec->psrc)
+ *unused |= BIT(INNER_SRC_PORT);
+
+ if (!tcp_ip6_spec->pdst)
+ *unused |= BIT(INNER_DST_PORT);
+
+ if (tcp_ip6_spec->tclass)
+ return -EOPNOTSUPP;
+
+ break;
+ case IPV6_USER_FLOW:
+ usr_ip6_spec = &fs->h_u.usr_ip6_spec;
+ *unused |= BIT(INNER_SRC_MAC) | BIT(INNER_DST_MAC) |
+ BIT(INNER_IP_TOS) | BIT(INNER_SRC_PORT) |
+ BIT(INNER_DST_PORT);
+
+ if (!usr_ip6_spec->ip6src[0] && !usr_ip6_spec->ip6src[1] &&
+ !usr_ip6_spec->ip6src[2] && !usr_ip6_spec->ip6src[3])
+ *unused |= BIT(INNER_SRC_IP);
+
+ if (!usr_ip6_spec->ip6dst[0] && !usr_ip6_spec->ip6dst[1] &&
+ !usr_ip6_spec->ip6dst[2] && !usr_ip6_spec->ip6dst[3])
+ *unused |= BIT(INNER_DST_IP);
+
+ if (!usr_ip6_spec->l4_proto)
+ *unused |= BIT(INNER_IP_PROTO);
+
+ if (usr_ip6_spec->tclass)
+ return -EOPNOTSUPP;
+
+ if (usr_ip6_spec->l4_4_bytes)
+ return -EOPNOTSUPP;
+
+ break;
+ case ETHER_FLOW:
+ ether_spec = &fs->h_u.ether_spec;
+ *unused |= BIT(INNER_SRC_IP) | BIT(INNER_DST_IP) |
+ BIT(INNER_SRC_PORT) | BIT(INNER_DST_PORT) |
+ BIT(INNER_IP_TOS) | BIT(INNER_IP_PROTO);
+
+ if (is_zero_ether_addr(ether_spec->h_source))
+ *unused |= BIT(INNER_SRC_MAC);
+
+ if (is_zero_ether_addr(ether_spec->h_dest))
+ *unused |= BIT(INNER_DST_MAC);
+
+ if (!ether_spec->h_proto)
+ *unused |= BIT(INNER_ETH_TYPE);
+
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ if ((fs->flow_type & FLOW_EXT)) {
+ if (fs->h_ext.vlan_etype)
+ return -EOPNOTSUPP;
+ if (!fs->h_ext.vlan_tci)
+ *unused |= BIT(INNER_VLAN_TAG_FST);
+
+ if (fs->m_ext.vlan_tci) {
+ if (be16_to_cpu(fs->h_ext.vlan_tci) >= VLAN_N_VID)
+ return -EINVAL;
+ }
+ } else {
+ *unused |= BIT(INNER_VLAN_TAG_FST);
+ }
+
+ if (fs->flow_type & FLOW_MAC_EXT) {
+ if (!(hdev->fd_cfg.proto_support & ETHER_FLOW))
+ return -EOPNOTSUPP;
+
+ if (is_zero_ether_addr(fs->h_ext.h_dest))
+ *unused |= BIT(INNER_DST_MAC);
+ else
+ *unused &= ~(BIT(INNER_DST_MAC));
+ }
+
+ return 0;
+}
+
+static bool hclge_fd_rule_exist(struct hclge_dev *hdev, u16 location)
+{
+ struct hclge_fd_rule *rule = NULL;
+ struct hlist_node *node2;
+
+ hlist_for_each_entry_safe(rule, node2, &hdev->fd_rule_list, rule_node) {
+ if (rule->location >= location)
+ break;
+ }
+
+ return rule && rule->location == location;
+}
+
+static int hclge_fd_update_rule_list(struct hclge_dev *hdev,
+ struct hclge_fd_rule *new_rule,
+ u16 location,
+ bool is_add)
+{
+ struct hclge_fd_rule *rule = NULL, *parent = NULL;
+ struct hlist_node *node2;
+
+ if (is_add && !new_rule)
+ return -EINVAL;
+
+ hlist_for_each_entry_safe(rule, node2,
+ &hdev->fd_rule_list, rule_node) {
+ if (rule->location >= location)
+ break;
+ parent = rule;
+ }
+
+ if (rule && rule->location == location) {
+ hlist_del(&rule->rule_node);
+ kfree(rule);
+ hdev->hclge_fd_rule_num--;
+
+ if (!is_add)
+ return 0;
+
+ } else if (!is_add) {
+ dev_err(&hdev->pdev->dev,
+ "delete fail, rule %d is inexistent\n",
+ location);
+ return -EINVAL;
+ }
+
+ INIT_HLIST_NODE(&new_rule->rule_node);
+
+ if (parent)
+ hlist_add_behind(&new_rule->rule_node, &parent->rule_node);
+ else
+ hlist_add_head(&new_rule->rule_node, &hdev->fd_rule_list);
+
+ hdev->hclge_fd_rule_num++;
+
+ return 0;
+}
+
+static int hclge_fd_get_tuple(struct hclge_dev *hdev,
+ struct ethtool_rx_flow_spec *fs,
+ struct hclge_fd_rule *rule)
+{
+ u32 flow_type = fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT);
+
+ switch (flow_type) {
+ case SCTP_V4_FLOW:
+ case TCP_V4_FLOW:
+ case UDP_V4_FLOW:
+ rule->tuples.src_ip[3] =
+ be32_to_cpu(fs->h_u.tcp_ip4_spec.ip4src);
+ rule->tuples_mask.src_ip[3] =
+ be32_to_cpu(fs->m_u.tcp_ip4_spec.ip4src);
+
+ rule->tuples.dst_ip[3] =
+ be32_to_cpu(fs->h_u.tcp_ip4_spec.ip4dst);
+ rule->tuples_mask.dst_ip[3] =
+ be32_to_cpu(fs->m_u.tcp_ip4_spec.ip4dst);
+
+ rule->tuples.src_port = be16_to_cpu(fs->h_u.tcp_ip4_spec.psrc);
+ rule->tuples_mask.src_port =
+ be16_to_cpu(fs->m_u.tcp_ip4_spec.psrc);
+
+ rule->tuples.dst_port = be16_to_cpu(fs->h_u.tcp_ip4_spec.pdst);
+ rule->tuples_mask.dst_port =
+ be16_to_cpu(fs->m_u.tcp_ip4_spec.pdst);
+
+ rule->tuples.ip_tos = fs->h_u.tcp_ip4_spec.tos;
+ rule->tuples_mask.ip_tos = fs->m_u.tcp_ip4_spec.tos;
+
+ rule->tuples.ether_proto = ETH_P_IP;
+ rule->tuples_mask.ether_proto = 0xFFFF;
+
+ break;
+ case IP_USER_FLOW:
+ rule->tuples.src_ip[3] =
+ be32_to_cpu(fs->h_u.usr_ip4_spec.ip4src);
+ rule->tuples_mask.src_ip[3] =
+ be32_to_cpu(fs->m_u.usr_ip4_spec.ip4src);
+
+ rule->tuples.dst_ip[3] =
+ be32_to_cpu(fs->h_u.usr_ip4_spec.ip4dst);
+ rule->tuples_mask.dst_ip[3] =
+ be32_to_cpu(fs->m_u.usr_ip4_spec.ip4dst);
+
+ rule->tuples.ip_tos = fs->h_u.usr_ip4_spec.tos;
+ rule->tuples_mask.ip_tos = fs->m_u.usr_ip4_spec.tos;
+
+ rule->tuples.ip_proto = fs->h_u.usr_ip4_spec.proto;
+ rule->tuples_mask.ip_proto = fs->m_u.usr_ip4_spec.proto;
+
+ rule->tuples.ether_proto = ETH_P_IP;
+ rule->tuples_mask.ether_proto = 0xFFFF;
+
+ break;
+ case SCTP_V6_FLOW:
+ case TCP_V6_FLOW:
+ case UDP_V6_FLOW:
+ be32_to_cpu_array(rule->tuples.src_ip,
+ fs->h_u.tcp_ip6_spec.ip6src, 4);
+ be32_to_cpu_array(rule->tuples_mask.src_ip,
+ fs->m_u.tcp_ip6_spec.ip6src, 4);
+
+ be32_to_cpu_array(rule->tuples.dst_ip,
+ fs->h_u.tcp_ip6_spec.ip6dst, 4);
+ be32_to_cpu_array(rule->tuples_mask.dst_ip,
+ fs->m_u.tcp_ip6_spec.ip6dst, 4);
+
+ rule->tuples.src_port = be16_to_cpu(fs->h_u.tcp_ip6_spec.psrc);
+ rule->tuples_mask.src_port =
+ be16_to_cpu(fs->m_u.tcp_ip6_spec.psrc);
+
+ rule->tuples.dst_port = be16_to_cpu(fs->h_u.tcp_ip6_spec.pdst);
+ rule->tuples_mask.dst_port =
+ be16_to_cpu(fs->m_u.tcp_ip6_spec.pdst);
+
+ rule->tuples.ether_proto = ETH_P_IPV6;
+ rule->tuples_mask.ether_proto = 0xFFFF;
+
+ break;
+ case IPV6_USER_FLOW:
+ be32_to_cpu_array(rule->tuples.src_ip,
+ fs->h_u.usr_ip6_spec.ip6src, 4);
+ be32_to_cpu_array(rule->tuples_mask.src_ip,
+ fs->m_u.usr_ip6_spec.ip6src, 4);
+
+ be32_to_cpu_array(rule->tuples.dst_ip,
+ fs->h_u.usr_ip6_spec.ip6dst, 4);
+ be32_to_cpu_array(rule->tuples_mask.dst_ip,
+ fs->m_u.usr_ip6_spec.ip6dst, 4);
+
+ rule->tuples.ip_proto = fs->h_u.usr_ip6_spec.l4_proto;
+ rule->tuples_mask.ip_proto = fs->m_u.usr_ip6_spec.l4_proto;
+
+ rule->tuples.ether_proto = ETH_P_IPV6;
+ rule->tuples_mask.ether_proto = 0xFFFF;
+
+ break;
+ case ETHER_FLOW:
+ ether_addr_copy(rule->tuples.src_mac,
+ fs->h_u.ether_spec.h_source);
+ ether_addr_copy(rule->tuples_mask.src_mac,
+ fs->m_u.ether_spec.h_source);
+
+ ether_addr_copy(rule->tuples.dst_mac,
+ fs->h_u.ether_spec.h_dest);
+ ether_addr_copy(rule->tuples_mask.dst_mac,
+ fs->m_u.ether_spec.h_dest);
+
+ rule->tuples.ether_proto =
+ be16_to_cpu(fs->h_u.ether_spec.h_proto);
+ rule->tuples_mask.ether_proto =
+ be16_to_cpu(fs->m_u.ether_spec.h_proto);
+
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ switch (flow_type) {
+ case SCTP_V4_FLOW:
+ case SCTP_V6_FLOW:
+ rule->tuples.ip_proto = IPPROTO_SCTP;
+ rule->tuples_mask.ip_proto = 0xFF;
+ break;
+ case TCP_V4_FLOW:
+ case TCP_V6_FLOW:
+ rule->tuples.ip_proto = IPPROTO_TCP;
+ rule->tuples_mask.ip_proto = 0xFF;
+ break;
+ case UDP_V4_FLOW:
+ case UDP_V6_FLOW:
+ rule->tuples.ip_proto = IPPROTO_UDP;
+ rule->tuples_mask.ip_proto = 0xFF;
+ break;
+ default:
+ break;
+ }
+
+ if ((fs->flow_type & FLOW_EXT)) {
+ rule->tuples.vlan_tag1 = be16_to_cpu(fs->h_ext.vlan_tci);
+ rule->tuples_mask.vlan_tag1 = be16_to_cpu(fs->m_ext.vlan_tci);
+ }
+
+ if (fs->flow_type & FLOW_MAC_EXT) {
+ ether_addr_copy(rule->tuples.dst_mac, fs->h_ext.h_dest);
+ ether_addr_copy(rule->tuples_mask.dst_mac, fs->m_ext.h_dest);
+ }
+
+ return 0;
+}
+
+static int hclge_add_fd_entry(struct hnae3_handle *handle,
+ struct ethtool_rxnfc *cmd)
+{
+ struct hclge_vport *vport = hclge_get_vport(handle);
+ struct hclge_dev *hdev = vport->back;
+ u16 dst_vport_id = 0, q_index = 0;
+ struct ethtool_rx_flow_spec *fs;
+ struct hclge_fd_rule *rule;
+ u32 unused = 0;
+ u8 action;
+ int ret;
+
+ if (!hnae3_dev_fd_supported(hdev))
+ return -EOPNOTSUPP;
+
+ if (!hdev->fd_cfg.fd_en) {
+ dev_warn(&hdev->pdev->dev,
+ "Please enable flow director first\n");
+ return -EOPNOTSUPP;
+ }
+
+ fs = (struct ethtool_rx_flow_spec *)&cmd->fs;
+
+ ret = hclge_fd_check_spec(hdev, fs, &unused);
+ if (ret) {
+ dev_err(&hdev->pdev->dev, "Check fd spec failed\n");
+ return ret;
+ }
+
+ if (fs->ring_cookie == RX_CLS_FLOW_DISC) {
+ action = HCLGE_FD_ACTION_DROP_PACKET;
+ } else {
+ u32 ring = ethtool_get_flow_spec_ring(fs->ring_cookie);
+ u8 vf = ethtool_get_flow_spec_ring_vf(fs->ring_cookie);
+ u16 tqps;
+
+ dst_vport_id = vf ? hdev->vport[vf].vport_id : vport->vport_id;
+ tqps = vf ? hdev->vport[vf].alloc_tqps : vport->alloc_tqps;
+
+ if (ring >= tqps) {
+ dev_err(&hdev->pdev->dev,
+ "Error: queue id (%d) > max tqp num (%d)\n",
+ ring, tqps - 1);
+ return -EINVAL;
+ }
+
+ if (vf > hdev->num_req_vfs) {
+ dev_err(&hdev->pdev->dev,
+ "Error: vf id (%d) > max vf num (%d)\n",
+ vf, hdev->num_req_vfs);
+ return -EINVAL;
+ }
+
+ action = HCLGE_FD_ACTION_ACCEPT_PACKET;
+ q_index = ring;
+ }
+
+ rule = kzalloc(sizeof(*rule), GFP_KERNEL);
+ if (!rule)
+ return -ENOMEM;
+
+ ret = hclge_fd_get_tuple(hdev, fs, rule);
+ if (ret)
+ goto free_rule;
+
+ rule->flow_type = fs->flow_type;
+
+ rule->location = fs->location;
+ rule->unused_tuple = unused;
+ rule->vf_id = dst_vport_id;
+ rule->queue_id = q_index;
+ rule->action = action;
+
+ ret = hclge_config_action(hdev, HCLGE_FD_STAGE_1, rule);
+ if (ret)
+ goto free_rule;
+
+ ret = hclge_config_key(hdev, HCLGE_FD_STAGE_1, rule);
+ if (ret)
+ goto free_rule;
+
+ ret = hclge_fd_update_rule_list(hdev, rule, fs->location, true);
+ if (ret)
+ goto free_rule;
+
+ return ret;
+
+free_rule:
+ kfree(rule);
+ return ret;
+}
+
+static int hclge_del_fd_entry(struct hnae3_handle *handle,
+ struct ethtool_rxnfc *cmd)
+{
+ struct hclge_vport *vport = hclge_get_vport(handle);
+ struct hclge_dev *hdev = vport->back;
+ struct ethtool_rx_flow_spec *fs;
+ int ret;
+
+ if (!hnae3_dev_fd_supported(hdev))
+ return -EOPNOTSUPP;
+
+ fs = (struct ethtool_rx_flow_spec *)&cmd->fs;
+
+ if (fs->location >= hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1])
+ return -EINVAL;
+
+ if (!hclge_fd_rule_exist(hdev, fs->location)) {
+ dev_err(&hdev->pdev->dev,
+ "Delete fail, rule %d is inexistent\n",
+ fs->location);
+ return -ENOENT;
+ }
+
+ ret = hclge_fd_tcam_config(hdev, HCLGE_FD_STAGE_1, true,
+ fs->location, NULL, false);
+ if (ret)
+ return ret;
+
+ return hclge_fd_update_rule_list(hdev, NULL, fs->location,
+ false);
+}
+
+static void hclge_del_all_fd_entries(struct hnae3_handle *handle,
+ bool clear_list)
+{
+ struct hclge_vport *vport = hclge_get_vport(handle);
+ struct hclge_dev *hdev = vport->back;
+ struct hclge_fd_rule *rule;
+ struct hlist_node *node;
+
+ if (!hnae3_dev_fd_supported(hdev))
+ return;
+
+ if (clear_list) {
+ hlist_for_each_entry_safe(rule, node, &hdev->fd_rule_list,
+ rule_node) {
+ hclge_fd_tcam_config(hdev, HCLGE_FD_STAGE_1, true,
+ rule->location, NULL, false);
+ hlist_del(&rule->rule_node);
+ kfree(rule);
+ hdev->hclge_fd_rule_num--;
+ }
+ } else {
+ hlist_for_each_entry_safe(rule, node, &hdev->fd_rule_list,
+ rule_node)
+ hclge_fd_tcam_config(hdev, HCLGE_FD_STAGE_1, true,
+ rule->location, NULL, false);
+ }
+}
+
+static int hclge_restore_fd_entries(struct hnae3_handle *handle)
+{
+ struct hclge_vport *vport = hclge_get_vport(handle);
+ struct hclge_dev *hdev = vport->back;
+ struct hclge_fd_rule *rule;
+ struct hlist_node *node;
+ int ret;
+
+ if (!hnae3_dev_fd_supported(hdev))
+ return -EOPNOTSUPP;
+
+ hlist_for_each_entry_safe(rule, node, &hdev->fd_rule_list, rule_node) {
+ ret = hclge_config_action(hdev, HCLGE_FD_STAGE_1, rule);
+ if (!ret)
+ ret = hclge_config_key(hdev, HCLGE_FD_STAGE_1, rule);
+
+ if (ret) {
+ dev_warn(&hdev->pdev->dev,
+ "Restore rule %d failed, remove it\n",
+ rule->location);
+ hlist_del(&rule->rule_node);
+ kfree(rule);
+ hdev->hclge_fd_rule_num--;
+ }
+ }
+ return 0;
+}
+
+static int hclge_get_fd_rule_cnt(struct hnae3_handle *handle,
+ struct ethtool_rxnfc *cmd)
+{
+ struct hclge_vport *vport = hclge_get_vport(handle);
+ struct hclge_dev *hdev = vport->back;
+
+ if (!hnae3_dev_fd_supported(hdev))
+ return -EOPNOTSUPP;
+
+ cmd->rule_cnt = hdev->hclge_fd_rule_num;
+ cmd->data = hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1];
+
+ return 0;
+}
+
+static int hclge_get_fd_rule_info(struct hnae3_handle *handle,
+ struct ethtool_rxnfc *cmd)
+{
+ struct hclge_vport *vport = hclge_get_vport(handle);
+ struct hclge_fd_rule *rule = NULL;
+ struct hclge_dev *hdev = vport->back;
+ struct ethtool_rx_flow_spec *fs;
+ struct hlist_node *node2;
+
+ if (!hnae3_dev_fd_supported(hdev))
+ return -EOPNOTSUPP;
+
+ fs = (struct ethtool_rx_flow_spec *)&cmd->fs;
+
+ hlist_for_each_entry_safe(rule, node2, &hdev->fd_rule_list, rule_node) {
+ if (rule->location >= fs->location)
+ break;
+ }
+
+ if (!rule || fs->location != rule->location)
+ return -ENOENT;
+
+ fs->flow_type = rule->flow_type;
+ switch (fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) {
+ case SCTP_V4_FLOW:
+ case TCP_V4_FLOW:
+ case UDP_V4_FLOW:
+ fs->h_u.tcp_ip4_spec.ip4src =
+ cpu_to_be32(rule->tuples.src_ip[3]);
+ fs->m_u.tcp_ip4_spec.ip4src =
+ rule->unused_tuple & BIT(INNER_SRC_IP) ?
+ 0 : cpu_to_be32(rule->tuples_mask.src_ip[3]);
+
+ fs->h_u.tcp_ip4_spec.ip4dst =
+ cpu_to_be32(rule->tuples.dst_ip[3]);
+ fs->m_u.tcp_ip4_spec.ip4dst =
+ rule->unused_tuple & BIT(INNER_DST_IP) ?
+ 0 : cpu_to_be32(rule->tuples_mask.dst_ip[3]);
+
+ fs->h_u.tcp_ip4_spec.psrc = cpu_to_be16(rule->tuples.src_port);
+ fs->m_u.tcp_ip4_spec.psrc =
+ rule->unused_tuple & BIT(INNER_SRC_PORT) ?
+ 0 : cpu_to_be16(rule->tuples_mask.src_port);
+
+ fs->h_u.tcp_ip4_spec.pdst = cpu_to_be16(rule->tuples.dst_port);
+ fs->m_u.tcp_ip4_spec.pdst =
+ rule->unused_tuple & BIT(INNER_DST_PORT) ?
+ 0 : cpu_to_be16(rule->tuples_mask.dst_port);
+
+ fs->h_u.tcp_ip4_spec.tos = rule->tuples.ip_tos;
+ fs->m_u.tcp_ip4_spec.tos =
+ rule->unused_tuple & BIT(INNER_IP_TOS) ?
+ 0 : rule->tuples_mask.ip_tos;
+
+ break;
+ case IP_USER_FLOW:
+ fs->h_u.usr_ip4_spec.ip4src =
+ cpu_to_be32(rule->tuples.src_ip[3]);
+ fs->m_u.tcp_ip4_spec.ip4src =
+ rule->unused_tuple & BIT(INNER_SRC_IP) ?
+ 0 : cpu_to_be32(rule->tuples_mask.src_ip[3]);
+
+ fs->h_u.usr_ip4_spec.ip4dst =
+ cpu_to_be32(rule->tuples.dst_ip[3]);
+ fs->m_u.usr_ip4_spec.ip4dst =
+ rule->unused_tuple & BIT(INNER_DST_IP) ?
+ 0 : cpu_to_be32(rule->tuples_mask.dst_ip[3]);
+
+ fs->h_u.usr_ip4_spec.tos = rule->tuples.ip_tos;
+ fs->m_u.usr_ip4_spec.tos =
+ rule->unused_tuple & BIT(INNER_IP_TOS) ?
+ 0 : rule->tuples_mask.ip_tos;
+
+ fs->h_u.usr_ip4_spec.proto = rule->tuples.ip_proto;
+ fs->m_u.usr_ip4_spec.proto =
+ rule->unused_tuple & BIT(INNER_IP_PROTO) ?
+ 0 : rule->tuples_mask.ip_proto;
+
+ fs->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4;
+
+ break;
+ case SCTP_V6_FLOW:
+ case TCP_V6_FLOW:
+ case UDP_V6_FLOW:
+ cpu_to_be32_array(fs->h_u.tcp_ip6_spec.ip6src,
+ rule->tuples.src_ip, 4);
+ if (rule->unused_tuple & BIT(INNER_SRC_IP))
+ memset(fs->m_u.tcp_ip6_spec.ip6src, 0, sizeof(int) * 4);
+ else
+ cpu_to_be32_array(fs->m_u.tcp_ip6_spec.ip6src,
+ rule->tuples_mask.src_ip, 4);
+
+ cpu_to_be32_array(fs->h_u.tcp_ip6_spec.ip6dst,
+ rule->tuples.dst_ip, 4);
+ if (rule->unused_tuple & BIT(INNER_DST_IP))
+ memset(fs->m_u.tcp_ip6_spec.ip6dst, 0, sizeof(int) * 4);
+ else
+ cpu_to_be32_array(fs->m_u.tcp_ip6_spec.ip6dst,
+ rule->tuples_mask.dst_ip, 4);
+
+ fs->h_u.tcp_ip6_spec.psrc = cpu_to_be16(rule->tuples.src_port);
+ fs->m_u.tcp_ip6_spec.psrc =
+ rule->unused_tuple & BIT(INNER_SRC_PORT) ?
+ 0 : cpu_to_be16(rule->tuples_mask.src_port);
+
+ fs->h_u.tcp_ip6_spec.pdst = cpu_to_be16(rule->tuples.dst_port);
+ fs->m_u.tcp_ip6_spec.pdst =
+ rule->unused_tuple & BIT(INNER_DST_PORT) ?
+ 0 : cpu_to_be16(rule->tuples_mask.dst_port);
+
+ break;
+ case IPV6_USER_FLOW:
+ cpu_to_be32_array(fs->h_u.usr_ip6_spec.ip6src,
+ rule->tuples.src_ip, 4);
+ if (rule->unused_tuple & BIT(INNER_SRC_IP))
+ memset(fs->m_u.usr_ip6_spec.ip6src, 0, sizeof(int) * 4);
+ else
+ cpu_to_be32_array(fs->m_u.usr_ip6_spec.ip6src,
+ rule->tuples_mask.src_ip, 4);
+
+ cpu_to_be32_array(fs->h_u.usr_ip6_spec.ip6dst,
+ rule->tuples.dst_ip, 4);
+ if (rule->unused_tuple & BIT(INNER_DST_IP))
+ memset(fs->m_u.usr_ip6_spec.ip6dst, 0, sizeof(int) * 4);
+ else
+ cpu_to_be32_array(fs->m_u.usr_ip6_spec.ip6dst,
+ rule->tuples_mask.dst_ip, 4);
+
+ fs->h_u.usr_ip6_spec.l4_proto = rule->tuples.ip_proto;
+ fs->m_u.usr_ip6_spec.l4_proto =
+ rule->unused_tuple & BIT(INNER_IP_PROTO) ?
+ 0 : rule->tuples_mask.ip_proto;
+
+ break;
+ case ETHER_FLOW:
+ ether_addr_copy(fs->h_u.ether_spec.h_source,
+ rule->tuples.src_mac);
+ if (rule->unused_tuple & BIT(INNER_SRC_MAC))
+ eth_zero_addr(fs->m_u.ether_spec.h_source);
+ else
+ ether_addr_copy(fs->m_u.ether_spec.h_source,
+ rule->tuples_mask.src_mac);
+
+ ether_addr_copy(fs->h_u.ether_spec.h_dest,
+ rule->tuples.dst_mac);
+ if (rule->unused_tuple & BIT(INNER_DST_MAC))
+ eth_zero_addr(fs->m_u.ether_spec.h_dest);
+ else
+ ether_addr_copy(fs->m_u.ether_spec.h_dest,
+ rule->tuples_mask.dst_mac);
+
+ fs->h_u.ether_spec.h_proto =
+ cpu_to_be16(rule->tuples.ether_proto);
+ fs->m_u.ether_spec.h_proto =
+ rule->unused_tuple & BIT(INNER_ETH_TYPE) ?
+ 0 : cpu_to_be16(rule->tuples_mask.ether_proto);
+
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ if (fs->flow_type & FLOW_EXT) {
+ fs->h_ext.vlan_tci = cpu_to_be16(rule->tuples.vlan_tag1);
+ fs->m_ext.vlan_tci =
+ rule->unused_tuple & BIT(INNER_VLAN_TAG_FST) ?
+ cpu_to_be16(VLAN_VID_MASK) :
+ cpu_to_be16(rule->tuples_mask.vlan_tag1);
+ }
+
+ if (fs->flow_type & FLOW_MAC_EXT) {
+ ether_addr_copy(fs->h_ext.h_dest, rule->tuples.dst_mac);
+ if (rule->unused_tuple & BIT(INNER_DST_MAC))
+ eth_zero_addr(fs->m_u.ether_spec.h_dest);
+ else
+ ether_addr_copy(fs->m_u.ether_spec.h_dest,
+ rule->tuples_mask.dst_mac);
+ }
+
+ if (rule->action == HCLGE_FD_ACTION_DROP_PACKET) {
+ fs->ring_cookie = RX_CLS_FLOW_DISC;
+ } else {
+ u64 vf_id;
+
+ fs->ring_cookie = rule->queue_id;
+ vf_id = rule->vf_id;
+ vf_id <<= ETHTOOL_RX_FLOW_SPEC_RING_VF_OFF;
+ fs->ring_cookie |= vf_id;
+ }
+
+ return 0;
+}
+
+static int hclge_get_all_rules(struct hnae3_handle *handle,
+ struct ethtool_rxnfc *cmd, u32 *rule_locs)
+{
+ struct hclge_vport *vport = hclge_get_vport(handle);
+ struct hclge_dev *hdev = vport->back;
+ struct hclge_fd_rule *rule;
+ struct hlist_node *node2;
+ int cnt = 0;
+
+ if (!hnae3_dev_fd_supported(hdev))
+ return -EOPNOTSUPP;
+
+ cmd->data = hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1];
+
+ hlist_for_each_entry_safe(rule, node2,
+ &hdev->fd_rule_list, rule_node) {
+ if (cnt == cmd->rule_cnt)
+ return -EMSGSIZE;
+
+ rule_locs[cnt] = rule->location;
+ cnt++;
+ }
+
+ cmd->rule_cnt = cnt;
+
+ return 0;
+}
+
+static void hclge_enable_fd(struct hnae3_handle *handle, bool enable)
+{
+ struct hclge_vport *vport = hclge_get_vport(handle);
+ struct hclge_dev *hdev = vport->back;
+
+ hdev->fd_cfg.fd_en = enable;
+ if (!enable)
+ hclge_del_all_fd_entries(handle, false);
+ else
+ hclge_restore_fd_entries(handle);
}
static void hclge_cfg_mac_mode(struct hclge_dev *hdev, bool enable)
@@ -3639,7 +4635,7 @@ static void hclge_cfg_mac_mode(struct hclge_dev *hdev, bool enable)
"mac enable fail, ret =%d.\n", ret);
}
-static int hclge_set_mac_loopback(struct hclge_dev *hdev, bool en)
+static int hclge_set_app_loopback(struct hclge_dev *hdev, bool en)
{
struct hclge_config_mac_mode_cmd *req;
struct hclge_desc desc;
@@ -3659,6 +4655,8 @@ static int hclge_set_mac_loopback(struct hclge_dev *hdev, bool en)
/* 2 Then setup the loopback flag */
loop_en = le32_to_cpu(req->txrx_pad_fcs_loop_en);
hnae3_set_bit(loop_en, HCLGE_MAC_APP_LP_B, en ? 1 : 0);
+ hnae3_set_bit(loop_en, HCLGE_MAC_TX_EN_B, en ? 1 : 0);
+ hnae3_set_bit(loop_en, HCLGE_MAC_RX_EN_B, en ? 1 : 0);
req->txrx_pad_fcs_loop_en = cpu_to_le32(loop_en);
@@ -3673,22 +4671,37 @@ static int hclge_set_mac_loopback(struct hclge_dev *hdev, bool en)
return ret;
}
-static int hclge_set_serdes_loopback(struct hclge_dev *hdev, bool en)
+static int hclge_set_serdes_loopback(struct hclge_dev *hdev, bool en,
+ enum hnae3_loop loop_mode)
{
#define HCLGE_SERDES_RETRY_MS 10
#define HCLGE_SERDES_RETRY_NUM 100
struct hclge_serdes_lb_cmd *req;
struct hclge_desc desc;
int ret, i = 0;
+ u8 loop_mode_b;
- req = (struct hclge_serdes_lb_cmd *)&desc.data[0];
+ req = (struct hclge_serdes_lb_cmd *)desc.data;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_SERDES_LOOPBACK, false);
+ switch (loop_mode) {
+ case HNAE3_LOOP_SERIAL_SERDES:
+ loop_mode_b = HCLGE_CMD_SERDES_SERIAL_INNER_LOOP_B;
+ break;
+ case HNAE3_LOOP_PARALLEL_SERDES:
+ loop_mode_b = HCLGE_CMD_SERDES_PARALLEL_INNER_LOOP_B;
+ break;
+ default:
+ dev_err(&hdev->pdev->dev,
+ "unsupported serdes loopback mode %d\n", loop_mode);
+ return -ENOTSUPP;
+ }
+
if (en) {
- req->enable = HCLGE_CMD_SERDES_SERIAL_INNER_LOOP_B;
- req->mask = HCLGE_CMD_SERDES_SERIAL_INNER_LOOP_B;
+ req->enable = loop_mode_b;
+ req->mask = loop_mode_b;
} else {
- req->mask = HCLGE_CMD_SERDES_SERIAL_INNER_LOOP_B;
+ req->mask = loop_mode_b;
}
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
@@ -3719,33 +4732,10 @@ static int hclge_set_serdes_loopback(struct hclge_dev *hdev, bool en)
return -EIO;
}
+ hclge_cfg_mac_mode(hdev, en);
return 0;
}
-static int hclge_set_loopback(struct hnae3_handle *handle,
- enum hnae3_loop loop_mode, bool en)
-{
- struct hclge_vport *vport = hclge_get_vport(handle);
- struct hclge_dev *hdev = vport->back;
- int ret;
-
- switch (loop_mode) {
- case HNAE3_MAC_INTER_LOOP_MAC:
- ret = hclge_set_mac_loopback(hdev, en);
- break;
- case HNAE3_MAC_INTER_LOOP_SERDES:
- ret = hclge_set_serdes_loopback(hdev, en);
- break;
- default:
- ret = -ENOTSUPP;
- dev_err(&hdev->pdev->dev,
- "loop_mode %d is not supported\n", loop_mode);
- break;
- }
-
- return ret;
-}
-
static int hclge_tqp_enable(struct hclge_dev *hdev, int tqp_id,
int stream_id, bool enable)
{
@@ -3766,6 +4756,37 @@ static int hclge_tqp_enable(struct hclge_dev *hdev, int tqp_id,
return ret;
}
+static int hclge_set_loopback(struct hnae3_handle *handle,
+ enum hnae3_loop loop_mode, bool en)
+{
+ struct hclge_vport *vport = hclge_get_vport(handle);
+ struct hclge_dev *hdev = vport->back;
+ int i, ret;
+
+ switch (loop_mode) {
+ case HNAE3_LOOP_APP:
+ ret = hclge_set_app_loopback(hdev, en);
+ break;
+ case HNAE3_LOOP_SERIAL_SERDES:
+ case HNAE3_LOOP_PARALLEL_SERDES:
+ ret = hclge_set_serdes_loopback(hdev, en, loop_mode);
+ break;
+ default:
+ ret = -ENOTSUPP;
+ dev_err(&hdev->pdev->dev,
+ "loop_mode %d is not supported\n", loop_mode);
+ break;
+ }
+
+ for (i = 0; i < vport->alloc_tqps; i++) {
+ ret = hclge_tqp_enable(hdev, i, 0, en);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static void hclge_reset_tqp_stats(struct hnae3_handle *handle)
{
struct hclge_vport *vport = hclge_get_vport(handle);
@@ -3809,6 +4830,8 @@ static void hclge_ae_stop(struct hnae3_handle *handle)
struct hclge_dev *hdev = vport->back;
int i;
+ set_bit(HCLGE_STATE_DOWN, &hdev->state);
+
del_timer_sync(&hdev->service_timer);
cancel_work_sync(&hdev->service_task);
clear_bit(HCLGE_STATE_SERVICE_SCHED, &hdev->state);
@@ -3950,174 +4973,6 @@ static void hclge_prepare_mac_addr(struct hclge_mac_vlan_tbl_entry_cmd *new_req,
new_req->mac_addr_lo16 = cpu_to_le16(low_val & 0xffff);
}
-static u16 hclge_get_mac_addr_to_mta_index(struct hclge_vport *vport,
- const u8 *addr)
-{
- u16 high_val = addr[1] | (addr[0] << 8);
- struct hclge_dev *hdev = vport->back;
- u32 rsh = 4 - hdev->mta_mac_sel_type;
- u16 ret_val = (high_val >> rsh) & 0xfff;
-
- return ret_val;
-}
-
-static int hclge_set_mta_filter_mode(struct hclge_dev *hdev,
- enum hclge_mta_dmac_sel_type mta_mac_sel,
- bool enable)
-{
- struct hclge_mta_filter_mode_cmd *req;
- struct hclge_desc desc;
- int ret;
-
- req = (struct hclge_mta_filter_mode_cmd *)desc.data;
- hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MTA_MAC_MODE_CFG, false);
-
- hnae3_set_bit(req->dmac_sel_en, HCLGE_CFG_MTA_MAC_EN_B,
- enable);
- hnae3_set_field(req->dmac_sel_en, HCLGE_CFG_MTA_MAC_SEL_M,
- HCLGE_CFG_MTA_MAC_SEL_S, mta_mac_sel);
-
- ret = hclge_cmd_send(&hdev->hw, &desc, 1);
- if (ret)
- dev_err(&hdev->pdev->dev,
- "Config mat filter mode failed for cmd_send, ret =%d.\n",
- ret);
-
- return ret;
-}
-
-int hclge_cfg_func_mta_filter(struct hclge_dev *hdev,
- u8 func_id,
- bool enable)
-{
- struct hclge_cfg_func_mta_filter_cmd *req;
- struct hclge_desc desc;
- int ret;
-
- req = (struct hclge_cfg_func_mta_filter_cmd *)desc.data;
- hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MTA_MAC_FUNC_CFG, false);
-
- hnae3_set_bit(req->accept, HCLGE_CFG_FUNC_MTA_ACCEPT_B,
- enable);
- req->function_id = func_id;
-
- ret = hclge_cmd_send(&hdev->hw, &desc, 1);
- if (ret)
- dev_err(&hdev->pdev->dev,
- "Config func_id enable failed for cmd_send, ret =%d.\n",
- ret);
-
- return ret;
-}
-
-static int hclge_set_mta_table_item(struct hclge_vport *vport,
- u16 idx,
- bool enable)
-{
- struct hclge_dev *hdev = vport->back;
- struct hclge_cfg_func_mta_item_cmd *req;
- struct hclge_desc desc;
- u16 item_idx = 0;
- int ret;
-
- req = (struct hclge_cfg_func_mta_item_cmd *)desc.data;
- hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MTA_TBL_ITEM_CFG, false);
- hnae3_set_bit(req->accept, HCLGE_CFG_MTA_ITEM_ACCEPT_B, enable);
-
- hnae3_set_field(item_idx, HCLGE_CFG_MTA_ITEM_IDX_M,
- HCLGE_CFG_MTA_ITEM_IDX_S, idx);
- req->item_idx = cpu_to_le16(item_idx);
-
- ret = hclge_cmd_send(&hdev->hw, &desc, 1);
- if (ret) {
- dev_err(&hdev->pdev->dev,
- "Config mta table item failed for cmd_send, ret =%d.\n",
- ret);
- return ret;
- }
-
- if (enable)
- set_bit(idx, vport->mta_shadow);
- else
- clear_bit(idx, vport->mta_shadow);
-
- return 0;
-}
-
-static int hclge_update_mta_status(struct hnae3_handle *handle)
-{
- unsigned long mta_status[BITS_TO_LONGS(HCLGE_MTA_TBL_SIZE)];
- struct hclge_vport *vport = hclge_get_vport(handle);
- struct net_device *netdev = handle->kinfo.netdev;
- struct netdev_hw_addr *ha;
- u16 tbl_idx;
-
- memset(mta_status, 0, sizeof(mta_status));
-
- /* update mta_status from mc addr list */
- netdev_for_each_mc_addr(ha, netdev) {
- tbl_idx = hclge_get_mac_addr_to_mta_index(vport, ha->addr);
- set_bit(tbl_idx, mta_status);
- }
-
- return hclge_update_mta_status_common(vport, mta_status,
- 0, HCLGE_MTA_TBL_SIZE, true);
-}
-
-int hclge_update_mta_status_common(struct hclge_vport *vport,
- unsigned long *status,
- u16 idx,
- u16 count,
- bool update_filter)
-{
- struct hclge_dev *hdev = vport->back;
- u16 update_max = idx + count;
- u16 check_max;
- int ret = 0;
- bool used;
- u16 i;
-
- /* setup mta check range */
- if (update_filter) {
- i = 0;
- check_max = HCLGE_MTA_TBL_SIZE;
- } else {
- i = idx;
- check_max = update_max;
- }
-
- used = false;
- /* check and update all mta item */
- for (; i < check_max; i++) {
- /* ignore unused item */
- if (!test_bit(i, vport->mta_shadow))
- continue;
-
- /* if i in update range then update it */
- if (i >= idx && i < update_max)
- if (!test_bit(i - idx, status))
- hclge_set_mta_table_item(vport, i, false);
-
- if (!used && test_bit(i, vport->mta_shadow))
- used = true;
- }
-
- /* no longer use mta, disable it */
- if (vport->accept_mta_mc && update_filter && !used) {
- ret = hclge_cfg_func_mta_filter(hdev,
- vport->vport_id,
- false);
- if (ret)
- dev_err(&hdev->pdev->dev,
- "disable func mta filter fail ret=%d\n",
- ret);
- else
- vport->accept_mta_mc = false;
- }
-
- return ret;
-}
-
static int hclge_remove_mac_vlan_tbl(struct hclge_vport *vport,
struct hclge_mac_vlan_tbl_entry_cmd *req)
{
@@ -4241,6 +5096,118 @@ static int hclge_add_mac_vlan_tbl(struct hclge_vport *vport,
return cfg_status;
}
+static int hclge_init_umv_space(struct hclge_dev *hdev)
+{
+ u16 allocated_size = 0;
+ int ret;
+
+ ret = hclge_set_umv_space(hdev, hdev->wanted_umv_size, &allocated_size,
+ true);
+ if (ret)
+ return ret;
+
+ if (allocated_size < hdev->wanted_umv_size)
+ dev_warn(&hdev->pdev->dev,
+ "Alloc umv space failed, want %d, get %d\n",
+ hdev->wanted_umv_size, allocated_size);
+
+ mutex_init(&hdev->umv_mutex);
+ hdev->max_umv_size = allocated_size;
+ hdev->priv_umv_size = hdev->max_umv_size / (hdev->num_req_vfs + 2);
+ hdev->share_umv_size = hdev->priv_umv_size +
+ hdev->max_umv_size % (hdev->num_req_vfs + 2);
+
+ return 0;
+}
+
+static int hclge_uninit_umv_space(struct hclge_dev *hdev)
+{
+ int ret;
+
+ if (hdev->max_umv_size > 0) {
+ ret = hclge_set_umv_space(hdev, hdev->max_umv_size, NULL,
+ false);
+ if (ret)
+ return ret;
+ hdev->max_umv_size = 0;
+ }
+ mutex_destroy(&hdev->umv_mutex);
+
+ return 0;
+}
+
+static int hclge_set_umv_space(struct hclge_dev *hdev, u16 space_size,
+ u16 *allocated_size, bool is_alloc)
+{
+ struct hclge_umv_spc_alc_cmd *req;
+ struct hclge_desc desc;
+ int ret;
+
+ req = (struct hclge_umv_spc_alc_cmd *)desc.data;
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MAC_VLAN_ALLOCATE, false);
+ hnae3_set_bit(req->allocate, HCLGE_UMV_SPC_ALC_B, !is_alloc);
+ req->space_size = cpu_to_le32(space_size);
+
+ ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "%s umv space failed for cmd_send, ret =%d\n",
+ is_alloc ? "allocate" : "free", ret);
+ return ret;
+ }
+
+ if (is_alloc && allocated_size)
+ *allocated_size = le32_to_cpu(desc.data[1]);
+
+ return 0;
+}
+
+static void hclge_reset_umv_space(struct hclge_dev *hdev)
+{
+ struct hclge_vport *vport;
+ int i;
+
+ for (i = 0; i < hdev->num_alloc_vport; i++) {
+ vport = &hdev->vport[i];
+ vport->used_umv_num = 0;
+ }
+
+ mutex_lock(&hdev->umv_mutex);
+ hdev->share_umv_size = hdev->priv_umv_size +
+ hdev->max_umv_size % (hdev->num_req_vfs + 2);
+ mutex_unlock(&hdev->umv_mutex);
+}
+
+static bool hclge_is_umv_space_full(struct hclge_vport *vport)
+{
+ struct hclge_dev *hdev = vport->back;
+ bool is_full;
+
+ mutex_lock(&hdev->umv_mutex);
+ is_full = (vport->used_umv_num >= hdev->priv_umv_size &&
+ hdev->share_umv_size == 0);
+ mutex_unlock(&hdev->umv_mutex);
+
+ return is_full;
+}
+
+static void hclge_update_umv_space(struct hclge_vport *vport, bool is_free)
+{
+ struct hclge_dev *hdev = vport->back;
+
+ mutex_lock(&hdev->umv_mutex);
+ if (is_free) {
+ if (vport->used_umv_num > hdev->priv_umv_size)
+ hdev->share_umv_size++;
+ vport->used_umv_num--;
+ } else {
+ if (vport->used_umv_num >= hdev->priv_umv_size)
+ hdev->share_umv_size--;
+ vport->used_umv_num++;
+ }
+ mutex_unlock(&hdev->umv_mutex);
+}
+
static int hclge_add_uc_addr(struct hnae3_handle *handle,
const unsigned char *addr)
{
@@ -4286,8 +5253,19 @@ int hclge_add_uc_addr_common(struct hclge_vport *vport,
* is not allowed in the mac vlan table.
*/
ret = hclge_lookup_mac_vlan_tbl(vport, &req, &desc, false);
- if (ret == -ENOENT)
- return hclge_add_mac_vlan_tbl(vport, &req, NULL);
+ if (ret == -ENOENT) {
+ if (!hclge_is_umv_space_full(vport)) {
+ ret = hclge_add_mac_vlan_tbl(vport, &req, NULL);
+ if (!ret)
+ hclge_update_umv_space(vport, false);
+ return ret;
+ }
+
+ dev_err(&hdev->pdev->dev, "UC MAC table full(%u)\n",
+ hdev->priv_umv_size);
+
+ return -ENOSPC;
+ }
/* check if we just hit the duplicate */
if (!ret)
@@ -4330,6 +5308,8 @@ int hclge_rm_uc_addr_common(struct hclge_vport *vport,
hnae3_set_bit(req.entry_type, HCLGE_MAC_VLAN_BIT0_EN_B, 0);
hclge_prepare_mac_addr(&req, addr);
ret = hclge_remove_mac_vlan_tbl(vport, &req);
+ if (!ret)
+ hclge_update_umv_space(vport, true);
return ret;
}
@@ -4348,7 +5328,6 @@ int hclge_add_mc_addr_common(struct hclge_vport *vport,
struct hclge_dev *hdev = vport->back;
struct hclge_mac_vlan_tbl_entry_cmd req;
struct hclge_desc desc[3];
- u16 tbl_idx;
int status;
/* mac addr check */
@@ -4362,7 +5341,7 @@ int hclge_add_mc_addr_common(struct hclge_vport *vport,
hnae3_set_bit(req.flags, HCLGE_MAC_VLAN_BIT0_EN_B, 1);
hnae3_set_bit(req.entry_type, HCLGE_MAC_VLAN_BIT0_EN_B, 0);
hnae3_set_bit(req.entry_type, HCLGE_MAC_VLAN_BIT1_EN_B, 1);
- hnae3_set_bit(req.mc_mac_en, HCLGE_MAC_VLAN_BIT0_EN_B, 0);
+ hnae3_set_bit(req.mc_mac_en, HCLGE_MAC_VLAN_BIT0_EN_B, 1);
hclge_prepare_mac_addr(&req, addr);
status = hclge_lookup_mac_vlan_tbl(vport, &req, desc, true);
if (!status) {
@@ -4378,25 +5357,8 @@ int hclge_add_mc_addr_common(struct hclge_vport *vport,
status = hclge_add_mac_vlan_tbl(vport, &req, desc);
}
- /* If mc mac vlan table is full, use MTA table */
- if (status == -ENOSPC) {
- if (!vport->accept_mta_mc) {
- status = hclge_cfg_func_mta_filter(hdev,
- vport->vport_id,
- true);
- if (status) {
- dev_err(&hdev->pdev->dev,
- "set mta filter mode fail ret=%d\n",
- status);
- return status;
- }
- vport->accept_mta_mc = true;
- }
-
- /* Set MTA table for this MAC address */
- tbl_idx = hclge_get_mac_addr_to_mta_index(vport, addr);
- status = hclge_set_mta_table_item(vport, tbl_idx, true);
- }
+ if (status == -ENOSPC)
+ dev_err(&hdev->pdev->dev, "mc mac vlan table is full\n");
return status;
}
@@ -4429,7 +5391,7 @@ int hclge_rm_mc_addr_common(struct hclge_vport *vport,
hnae3_set_bit(req.flags, HCLGE_MAC_VLAN_BIT0_EN_B, 1);
hnae3_set_bit(req.entry_type, HCLGE_MAC_VLAN_BIT0_EN_B, 0);
hnae3_set_bit(req.entry_type, HCLGE_MAC_VLAN_BIT1_EN_B, 1);
- hnae3_set_bit(req.mc_mac_en, HCLGE_MAC_VLAN_BIT0_EN_B, 0);
+ hnae3_set_bit(req.mc_mac_en, HCLGE_MAC_VLAN_BIT0_EN_B, 1);
hclge_prepare_mac_addr(&req, addr);
status = hclge_lookup_mac_vlan_tbl(vport, &req, desc, true);
if (!status) {
@@ -4598,8 +5560,20 @@ static int hclge_set_mac_addr(struct hnae3_handle *handle, void *p,
return 0;
}
+static int hclge_do_ioctl(struct hnae3_handle *handle, struct ifreq *ifr,
+ int cmd)
+{
+ struct hclge_vport *vport = hclge_get_vport(handle);
+ struct hclge_dev *hdev = vport->back;
+
+ if (!hdev->hw.mac.phydev)
+ return -EOPNOTSUPP;
+
+ return phy_mii_ioctl(hdev->hw.mac.phydev, ifr, cmd);
+}
+
static int hclge_set_vlan_filter_ctrl(struct hclge_dev *hdev, u8 vlan_type,
- bool filter_en)
+ u8 fe_type, bool filter_en)
{
struct hclge_vlan_filter_ctrl_cmd *req;
struct hclge_desc desc;
@@ -4609,7 +5583,7 @@ static int hclge_set_vlan_filter_ctrl(struct hclge_dev *hdev, u8 vlan_type,
req = (struct hclge_vlan_filter_ctrl_cmd *)desc.data;
req->vlan_type = vlan_type;
- req->vlan_fe = filter_en;
+ req->vlan_fe = filter_en ? fe_type : 0;
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret)
@@ -4621,13 +5595,34 @@ static int hclge_set_vlan_filter_ctrl(struct hclge_dev *hdev, u8 vlan_type,
#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 void hclge_enable_vlan_filter(struct hnae3_handle *handle, bool enable)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
- hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_VF, enable);
+ if (hdev->pdev->revision >= 0x21) {
+ hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_VF,
+ HCLGE_FILTER_FE_EGRESS, enable);
+ hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_PORT,
+ HCLGE_FILTER_FE_INGRESS, enable);
+ } else {
+ hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_VF,
+ HCLGE_FILTER_FE_EGRESS_V1_B, enable);
+ }
+ if (enable)
+ handle->netdev_flags |= HNAE3_VLAN_FLTR;
+ else
+ handle->netdev_flags &= ~HNAE3_VLAN_FLTR;
}
static int hclge_set_vf_vlan_common(struct hclge_dev *hdev, int vfid,
@@ -4686,9 +5681,17 @@ static int hclge_set_vf_vlan_common(struct hclge_dev *hdev, int vfid,
"Add vf vlan filter fail, ret =%d.\n",
req0->resp_code);
} else {
+#define HCLGE_VF_VLAN_DEL_NO_FOUND 1
if (!req0->resp_code)
return 0;
+ if (req0->resp_code == HCLGE_VF_VLAN_DEL_NO_FOUND) {
+ dev_warn(&hdev->pdev->dev,
+ "vlan %d filter is not in vf vlan table\n",
+ vlan);
+ return 0;
+ }
+
dev_err(&hdev->pdev->dev,
"Kill vf vlan filter fail, ret =%d.\n",
req0->resp_code);
@@ -4732,6 +5735,9 @@ static int hclge_set_vlan_filter_hw(struct hclge_dev *hdev, __be16 proto,
u16 vport_idx, vport_num = 0;
int ret;
+ if (is_kill && !vlan_id)
+ return 0;
+
ret = hclge_set_vf_vlan_common(hdev, vport_id, is_kill, vlan_id,
0, proto);
if (ret) {
@@ -4761,7 +5767,7 @@ static int hclge_set_vlan_filter_hw(struct hclge_dev *hdev, __be16 proto,
return -EINVAL;
}
- for_each_set_bit(vport_idx, hdev->vlan_table[vlan_id], VLAN_N_VID)
+ for_each_set_bit(vport_idx, hdev->vlan_table[vlan_id], HCLGE_VPORT_NUM)
vport_num++;
if ((is_kill && vport_num == 0) || (!is_kill && vport_num == 1))
@@ -4896,7 +5902,7 @@ static int hclge_set_vlan_protocol_type(struct hclge_dev *hdev)
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MAC_VLAN_INSERT, false);
- tx_req = (struct hclge_tx_vlan_type_cfg_cmd *)&desc.data;
+ tx_req = (struct hclge_tx_vlan_type_cfg_cmd *)desc.data;
tx_req->ot_vlan_type = cpu_to_le16(hdev->vlan_type_cfg.tx_ot_vlan_type);
tx_req->in_vlan_type = cpu_to_le16(hdev->vlan_type_cfg.tx_in_vlan_type);
@@ -4913,18 +5919,30 @@ static int hclge_init_vlan_config(struct hclge_dev *hdev)
{
#define HCLGE_DEF_VLAN_TYPE 0x8100
- struct hnae3_handle *handle;
+ struct hnae3_handle *handle = &hdev->vport[0].nic;
struct hclge_vport *vport;
int ret;
int i;
- ret = hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_VF, true);
- if (ret)
- return ret;
+ if (hdev->pdev->revision >= 0x21) {
+ ret = hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_VF,
+ HCLGE_FILTER_FE_EGRESS, true);
+ if (ret)
+ return ret;
- ret = hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_PORT, true);
- if (ret)
- return ret;
+ ret = hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_PORT,
+ HCLGE_FILTER_FE_INGRESS, true);
+ if (ret)
+ return ret;
+ } else {
+ ret = hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_VF,
+ HCLGE_FILTER_FE_EGRESS_V1_B,
+ true);
+ if (ret)
+ 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;
@@ -4970,7 +5988,6 @@ static int hclge_init_vlan_config(struct hclge_dev *hdev)
return ret;
}
- handle = &hdev->vport[0].nic;
return hclge_set_vlan_filter(handle, htons(ETH_P_8021Q), 0, false);
}
@@ -5093,31 +6110,28 @@ static u16 hclge_covert_handle_qid_global(struct hnae3_handle *handle,
return tqp->index;
}
-void hclge_reset_tqp(struct hnae3_handle *handle, u16 queue_id)
+int hclge_reset_tqp(struct hnae3_handle *handle, u16 queue_id)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
int reset_try_times = 0;
int reset_status;
u16 queue_gid;
- int ret;
-
- if (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state))
- return;
+ int ret = 0;
queue_gid = hclge_covert_handle_qid_global(handle, queue_id);
ret = hclge_tqp_enable(hdev, queue_id, 0, false);
if (ret) {
- dev_warn(&hdev->pdev->dev, "Disable tqp fail, ret = %d\n", ret);
- return;
+ dev_err(&hdev->pdev->dev, "Disable tqp fail, ret = %d\n", ret);
+ return ret;
}
ret = hclge_send_reset_tqp_cmd(hdev, queue_gid, true);
if (ret) {
- dev_warn(&hdev->pdev->dev,
- "Send reset tqp cmd fail, ret = %d\n", ret);
- return;
+ dev_err(&hdev->pdev->dev,
+ "Send reset tqp cmd fail, ret = %d\n", ret);
+ return ret;
}
reset_try_times = 0;
@@ -5130,16 +6144,16 @@ void hclge_reset_tqp(struct hnae3_handle *handle, u16 queue_id)
}
if (reset_try_times >= HCLGE_TQP_RESET_TRY_TIMES) {
- dev_warn(&hdev->pdev->dev, "Reset TQP fail\n");
- return;
+ dev_err(&hdev->pdev->dev, "Reset TQP fail\n");
+ return ret;
}
ret = hclge_send_reset_tqp_cmd(hdev, queue_gid, false);
- if (ret) {
- dev_warn(&hdev->pdev->dev,
- "Deassert the soft reset fail, ret = %d\n", ret);
- return;
- }
+ if (ret)
+ dev_err(&hdev->pdev->dev,
+ "Deassert the soft reset fail, ret = %d\n", ret);
+
+ return ret;
}
void hclge_reset_vf_queue(struct hclge_vport *vport, u16 queue_id)
@@ -5187,20 +6201,6 @@ static u32 hclge_get_fw_version(struct hnae3_handle *handle)
return hdev->fw_version;
}
-static void hclge_get_flowctrl_adv(struct hnae3_handle *handle,
- u32 *flowctrl_adv)
-{
- struct hclge_vport *vport = hclge_get_vport(handle);
- struct hclge_dev *hdev = vport->back;
- struct phy_device *phydev = hdev->hw.mac.phydev;
-
- if (!phydev)
- return;
-
- *flowctrl_adv |= (phydev->advertising & ADVERTISED_Pause) |
- (phydev->advertising & ADVERTISED_Asym_Pause);
-}
-
static void hclge_set_flowctrl_adv(struct hclge_dev *hdev, u32 rx_en, u32 tx_en)
{
struct phy_device *phydev = hdev->hw.mac.phydev;
@@ -5208,13 +6208,7 @@ static void hclge_set_flowctrl_adv(struct hclge_dev *hdev, u32 rx_en, u32 tx_en)
if (!phydev)
return;
- phydev->advertising &= ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause);
-
- if (rx_en)
- phydev->advertising |= ADVERTISED_Pause | ADVERTISED_Asym_Pause;
-
- if (tx_en)
- phydev->advertising ^= ADVERTISED_Asym_Pause;
+ phy_set_asym_pause(phydev, rx_en, tx_en);
}
static int hclge_cfg_pauseparam(struct hclge_dev *hdev, u32 rx_en, u32 tx_en)
@@ -5256,11 +6250,7 @@ int hclge_cfg_flowctrl(struct hclge_dev *hdev)
if (!phydev->link || !phydev->autoneg)
return 0;
- if (phydev->advertising & ADVERTISED_Pause)
- local_advertising = ADVERTISE_PAUSE_CAP;
-
- if (phydev->advertising & ADVERTISED_Asym_Pause)
- local_advertising |= ADVERTISE_PAUSE_ASYM;
+ local_advertising = ethtool_adv_to_lcl_adv_t(phydev->advertising);
if (phydev->pause)
remote_advertising = LPA_PAUSE_CAP;
@@ -5444,26 +6434,31 @@ static int hclge_init_client_instance(struct hnae3_client *client,
vport->nic.client = client;
ret = client->ops->init_instance(&vport->nic);
if (ret)
- return ret;
+ goto clear_nic;
ret = hclge_init_instance_hw(hdev);
if (ret) {
client->ops->uninit_instance(&vport->nic,
0);
- return ret;
+ goto clear_nic;
}
+ hnae3_set_client_init_flag(client, ae_dev, 1);
+
if (hdev->roce_client &&
hnae3_dev_roce_supported(hdev)) {
struct hnae3_client *rc = hdev->roce_client;
ret = hclge_init_roce_base_info(vport);
if (ret)
- return ret;
+ goto clear_roce;
ret = rc->ops->init_instance(&vport->roce);
if (ret)
- return ret;
+ goto clear_roce;
+
+ hnae3_set_client_init_flag(hdev->roce_client,
+ ae_dev, 1);
}
break;
@@ -5473,7 +6468,9 @@ static int hclge_init_client_instance(struct hnae3_client *client,
ret = client->ops->init_instance(&vport->nic);
if (ret)
- return ret;
+ goto clear_nic;
+
+ hnae3_set_client_init_flag(client, ae_dev, 1);
break;
case HNAE3_CLIENT_ROCE:
@@ -5485,16 +6482,31 @@ static int hclge_init_client_instance(struct hnae3_client *client,
if (hdev->roce_client && hdev->nic_client) {
ret = hclge_init_roce_base_info(vport);
if (ret)
- return ret;
+ goto clear_roce;
ret = client->ops->init_instance(&vport->roce);
if (ret)
- return ret;
+ goto clear_roce;
+
+ hnae3_set_client_init_flag(client, ae_dev, 1);
}
+
+ break;
+ default:
+ return -EINVAL;
}
}
return 0;
+
+clear_nic:
+ hdev->nic_client = NULL;
+ vport->nic.client = NULL;
+ return ret;
+clear_roce:
+ hdev->roce_client = NULL;
+ vport->roce.client = NULL;
+ return ret;
}
static void hclge_uninit_client_instance(struct hnae3_client *client,
@@ -5514,7 +6526,7 @@ static void hclge_uninit_client_instance(struct hnae3_client *client,
}
if (client->type == HNAE3_CLIENT_ROCE)
return;
- if (client->ops->uninit_instance) {
+ if (hdev->nic_client && client->ops->uninit_instance) {
hclge_uninit_instance_hw(hdev);
client->ops->uninit_instance(&vport->nic, 0);
hdev->nic_client = NULL;
@@ -5697,6 +6709,12 @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev)
}
}
+ ret = hclge_init_umv_space(hdev);
+ if (ret) {
+ dev_err(&pdev->dev, "umv space init error, ret=%d.\n", ret);
+ goto err_msi_irq_uninit;
+ }
+
ret = hclge_mac_init(hdev);
if (ret) {
dev_err(&pdev->dev, "Mac init error, ret = %d\n", ret);
@@ -5734,6 +6752,20 @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev)
goto err_mdiobus_unreg;
}
+ ret = hclge_init_fd_config(hdev);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "fd table init fail, ret=%d\n", ret);
+ goto err_mdiobus_unreg;
+ }
+
+ ret = hclge_hw_error_set_state(hdev, true);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "hw error interrupts enable failed, ret =%d\n", ret);
+ goto err_mdiobus_unreg;
+ }
+
hclge_dcb_ops_set(hdev);
timer_setup(&hdev->service_timer, hclge_service_timer, 0);
@@ -5810,6 +6842,8 @@ static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev)
return ret;
}
+ hclge_reset_umv_space(hdev);
+
ret = hclge_mac_init(hdev);
if (ret) {
dev_err(&pdev->dev, "Mac init error, ret = %d\n", ret);
@@ -5840,6 +6874,19 @@ static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev)
return ret;
}
+ ret = hclge_init_fd_config(hdev);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "fd table init fail, ret=%d\n", ret);
+ return ret;
+ }
+
+ /* Re-enable the TM hw error interrupts because
+ * they get disabled on core/global reset.
+ */
+ if (hclge_enable_tm_hw_error(hdev, true))
+ dev_err(&pdev->dev, "failed to enable TM hw error interrupts\n");
+
dev_info(&pdev->dev, "Reset done, %s driver initialization finished.\n",
HCLGE_DRIVER_NAME);
@@ -5856,10 +6903,13 @@ static void hclge_uninit_ae_dev(struct hnae3_ae_dev *ae_dev)
if (mac->phydev)
mdiobus_unregister(mac->mdio_bus);
+ hclge_uninit_umv_space(hdev);
+
/* Disable MISC vector(vector0) */
hclge_enable_vector(&hdev->misc_vector, false);
synchronize_irq(hdev->misc_vector.vector_irq);
+ hclge_hw_error_set_state(hdev, false);
hclge_destroy_cmd_queue(&hdev->hw);
hclge_misc_irq_uninit(hdev);
hclge_pci_uninit(hdev);
@@ -5887,18 +6937,12 @@ static void hclge_get_channels(struct hnae3_handle *handle,
}
static void hclge_get_tqps_and_rss_info(struct hnae3_handle *handle,
- u16 *free_tqps, u16 *max_rss_size)
+ u16 *alloc_tqps, u16 *max_rss_size)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
- u16 temp_tqps = 0;
- int i;
- for (i = 0; i < hdev->num_tqps; i++) {
- if (!hdev->htqp[i].alloced)
- temp_tqps++;
- }
- *free_tqps = temp_tqps;
+ *alloc_tqps = vport->alloc_tqps;
*max_rss_size = hdev->rss_size_max;
}
@@ -6228,27 +7272,6 @@ static void hclge_get_link_mode(struct hnae3_handle *handle,
}
}
-static void hclge_get_port_type(struct hnae3_handle *handle,
- u8 *port_type)
-{
- struct hclge_vport *vport = hclge_get_vport(handle);
- struct hclge_dev *hdev = vport->back;
- u8 media_type = hdev->hw.mac.media_type;
-
- switch (media_type) {
- case HNAE3_MEDIA_TYPE_FIBER:
- *port_type = PORT_FIBRE;
- break;
- case HNAE3_MEDIA_TYPE_COPPER:
- *port_type = PORT_TP;
- break;
- case HNAE3_MEDIA_TYPE_UNKNOWN:
- default:
- *port_type = PORT_OTHER;
- break;
- }
-}
-
static const struct hnae3_ae_ops hclge_ops = {
.init_ae_dev = hclge_init_ae_dev,
.uninit_ae_dev = hclge_uninit_ae_dev,
@@ -6276,11 +7299,11 @@ static const struct hnae3_ae_ops hclge_ops = {
.get_tc_size = hclge_get_tc_size,
.get_mac_addr = hclge_get_mac_addr,
.set_mac_addr = hclge_set_mac_addr,
+ .do_ioctl = hclge_do_ioctl,
.add_uc_addr = hclge_add_uc_addr,
.rm_uc_addr = hclge_rm_uc_addr,
.add_mc_addr = hclge_add_mc_addr,
.rm_mc_addr = hclge_rm_mc_addr,
- .update_mta_status = hclge_update_mta_status,
.set_autoneg = hclge_set_autoneg,
.get_autoneg = hclge_get_autoneg,
.get_pauseparam = hclge_get_pauseparam,
@@ -6301,12 +7324,19 @@ static const struct hnae3_ae_ops hclge_ops = {
.get_tqps_and_rss_info = hclge_get_tqps_and_rss_info,
.set_channels = hclge_set_channels,
.get_channels = hclge_get_channels,
- .get_flowctrl_adv = hclge_get_flowctrl_adv,
.get_regs_len = hclge_get_regs_len,
.get_regs = hclge_get_regs,
.set_led_id = hclge_set_led_id,
.get_link_mode = hclge_get_link_mode,
- .get_port_type = hclge_get_port_type,
+ .add_fd_entry = hclge_add_fd_entry,
+ .del_fd_entry = hclge_del_fd_entry,
+ .del_all_fd_entries = hclge_del_all_fd_entries,
+ .get_fd_rule_cnt = hclge_get_fd_rule_cnt,
+ .get_fd_rule_info = hclge_get_fd_rule_info,
+ .get_fd_all_rules = hclge_get_all_rules,
+ .restore_fd_rules = hclge_restore_fd_entries,
+ .enable_fd = hclge_enable_fd,
+ .process_hw_error = hclge_process_ras_hw_error,
};
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 1528fb3fa6be..0d9215404269 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
@@ -14,6 +14,8 @@
#define HCLGE_MOD_VERSION "1.0"
#define HCLGE_DRIVER_NAME "hclge"
+#define HCLGE_MAX_PF_NUM 8
+
#define HCLGE_INVALID_VPORT 0xffff
#define HCLGE_PF_CFG_BLOCK_SIZE 32
@@ -53,7 +55,9 @@
#define HCLGE_RSS_TC_SIZE_6 64
#define HCLGE_RSS_TC_SIZE_7 128
-#define HCLGE_MTA_TBL_SIZE 4096
+#define HCLGE_UMV_TBL_SIZE 3072
+#define HCLGE_DEFAULT_UMV_SPACE_PER_PF \
+ (HCLGE_UMV_TBL_SIZE / HCLGE_MAX_PF_NUM)
#define HCLGE_TQP_RESET_TRY_TIMES 10
@@ -79,6 +83,19 @@
#define HCLGE_VF_NUM_PER_CMD 64
#define HCLGE_VF_NUM_PER_BYTE 8
+enum HLCGE_PORT_TYPE {
+ HOST_PORT,
+ NETWORK_PORT
+};
+
+#define HCLGE_PF_ID_S 0
+#define HCLGE_PF_ID_M GENMASK(2, 0)
+#define HCLGE_VF_ID_S 3
+#define HCLGE_VF_ID_M GENMASK(10, 3)
+#define HCLGE_PORT_TYPE_B 11
+#define HCLGE_NETWORK_PORT_ID_S 0
+#define HCLGE_NETWORK_PORT_ID_M GENMASK(3, 0)
+
/* Reset related Registers */
#define HCLGE_MISC_RESET_STS_REG 0x20700
#define HCLGE_MISC_VECTOR_INT_STS 0x20800
@@ -149,13 +166,6 @@ enum HCLGE_MAC_DUPLEX {
HCLGE_MAC_FULL
};
-enum hclge_mta_dmac_sel_type {
- HCLGE_MAC_ADDR_47_36,
- HCLGE_MAC_ADDR_46_35,
- HCLGE_MAC_ADDR_45_34,
- HCLGE_MAC_ADDR_44_33,
-};
-
struct hclge_mac {
u8 phy_addr;
u8 flag;
@@ -238,6 +248,7 @@ struct hclge_cfg {
u8 default_speed;
u32 numa_node_map;
u8 speed_ability;
+ u16 umv_space;
};
struct hclge_tm_info {
@@ -256,109 +267,6 @@ struct hclge_comm_stats_str {
unsigned long offset;
};
-/* all 64bit stats, opcode id: 0x0030 */
-struct hclge_64_bit_stats {
- /* query_igu_stat */
- u64 igu_rx_oversize_pkt;
- u64 igu_rx_undersize_pkt;
- u64 igu_rx_out_all_pkt;
- u64 igu_rx_uni_pkt;
- u64 igu_rx_multi_pkt;
- u64 igu_rx_broad_pkt;
- u64 rsv0;
-
- /* query_egu_stat */
- u64 egu_tx_out_all_pkt;
- u64 egu_tx_uni_pkt;
- u64 egu_tx_multi_pkt;
- u64 egu_tx_broad_pkt;
-
- /* ssu_ppp packet stats */
- u64 ssu_ppp_mac_key_num;
- u64 ssu_ppp_host_key_num;
- u64 ppp_ssu_mac_rlt_num;
- u64 ppp_ssu_host_rlt_num;
-
- /* ssu_tx_in_out_dfx_stats */
- u64 ssu_tx_in_num;
- u64 ssu_tx_out_num;
- /* ssu_rx_in_out_dfx_stats */
- u64 ssu_rx_in_num;
- u64 ssu_rx_out_num;
-};
-
-/* all 32bit stats, opcode id: 0x0031 */
-struct hclge_32_bit_stats {
- u64 igu_rx_err_pkt;
- u64 igu_rx_no_eof_pkt;
- u64 igu_rx_no_sof_pkt;
- u64 egu_tx_1588_pkt;
- u64 egu_tx_err_pkt;
- u64 ssu_full_drop_num;
- u64 ssu_part_drop_num;
- u64 ppp_key_drop_num;
- u64 ppp_rlt_drop_num;
- u64 ssu_key_drop_num;
- u64 pkt_curr_buf_cnt;
- u64 qcn_fb_rcv_cnt;
- u64 qcn_fb_drop_cnt;
- u64 qcn_fb_invaild_cnt;
- u64 rsv0;
- u64 rx_packet_tc0_in_cnt;
- u64 rx_packet_tc1_in_cnt;
- u64 rx_packet_tc2_in_cnt;
- u64 rx_packet_tc3_in_cnt;
- u64 rx_packet_tc4_in_cnt;
- u64 rx_packet_tc5_in_cnt;
- u64 rx_packet_tc6_in_cnt;
- u64 rx_packet_tc7_in_cnt;
- u64 rx_packet_tc0_out_cnt;
- u64 rx_packet_tc1_out_cnt;
- u64 rx_packet_tc2_out_cnt;
- u64 rx_packet_tc3_out_cnt;
- u64 rx_packet_tc4_out_cnt;
- u64 rx_packet_tc5_out_cnt;
- u64 rx_packet_tc6_out_cnt;
- u64 rx_packet_tc7_out_cnt;
-
- /* Tx packet level statistics */
- u64 tx_packet_tc0_in_cnt;
- u64 tx_packet_tc1_in_cnt;
- u64 tx_packet_tc2_in_cnt;
- u64 tx_packet_tc3_in_cnt;
- u64 tx_packet_tc4_in_cnt;
- u64 tx_packet_tc5_in_cnt;
- u64 tx_packet_tc6_in_cnt;
- u64 tx_packet_tc7_in_cnt;
- u64 tx_packet_tc0_out_cnt;
- u64 tx_packet_tc1_out_cnt;
- u64 tx_packet_tc2_out_cnt;
- u64 tx_packet_tc3_out_cnt;
- u64 tx_packet_tc4_out_cnt;
- u64 tx_packet_tc5_out_cnt;
- u64 tx_packet_tc6_out_cnt;
- u64 tx_packet_tc7_out_cnt;
-
- /* packet buffer statistics */
- u64 pkt_curr_buf_tc0_cnt;
- u64 pkt_curr_buf_tc1_cnt;
- u64 pkt_curr_buf_tc2_cnt;
- u64 pkt_curr_buf_tc3_cnt;
- u64 pkt_curr_buf_tc4_cnt;
- u64 pkt_curr_buf_tc5_cnt;
- u64 pkt_curr_buf_tc6_cnt;
- u64 pkt_curr_buf_tc7_cnt;
-
- u64 mb_uncopy_num;
- u64 lo_pri_unicast_rlt_drop_num;
- u64 hi_pri_multicast_rlt_drop_num;
- u64 lo_pri_multicast_rlt_drop_num;
- u64 rx_oq_drop_pkt_cnt;
- u64 tx_oq_drop_pkt_cnt;
- u64 nic_l2_err_drop_pkt_cnt;
- u64 roc_l2_err_drop_pkt_cnt;
-};
-
/* mac stats ,opcode id: 0x0032 */
struct hclge_mac_stats {
u64 mac_tx_mac_pause_num;
@@ -450,8 +358,6 @@ struct hclge_mac_stats {
#define HCLGE_STATS_TIMER_INTERVAL (60 * 5)
struct hclge_hw_stats {
struct hclge_mac_stats mac_stats;
- struct hclge_64_bit_stats all_64_bit_stats;
- struct hclge_32_bit_stats all_32_bit_stats;
u32 stats_timer;
};
@@ -464,6 +370,221 @@ struct hclge_vlan_type_cfg {
u16 tx_in_vlan_type;
};
+enum HCLGE_FD_MODE {
+ HCLGE_FD_MODE_DEPTH_2K_WIDTH_400B_STAGE_1,
+ HCLGE_FD_MODE_DEPTH_1K_WIDTH_400B_STAGE_2,
+ HCLGE_FD_MODE_DEPTH_4K_WIDTH_200B_STAGE_1,
+ HCLGE_FD_MODE_DEPTH_2K_WIDTH_200B_STAGE_2,
+};
+
+enum HCLGE_FD_KEY_TYPE {
+ HCLGE_FD_KEY_BASE_ON_PTYPE,
+ HCLGE_FD_KEY_BASE_ON_TUPLE,
+};
+
+enum HCLGE_FD_STAGE {
+ HCLGE_FD_STAGE_1,
+ HCLGE_FD_STAGE_2,
+};
+
+/* OUTER_XXX indicates tuples in tunnel header of tunnel packet
+ * INNER_XXX indicate tuples in tunneled header of tunnel packet or
+ * tuples of non-tunnel packet
+ */
+enum HCLGE_FD_TUPLE {
+ OUTER_DST_MAC,
+ OUTER_SRC_MAC,
+ OUTER_VLAN_TAG_FST,
+ OUTER_VLAN_TAG_SEC,
+ OUTER_ETH_TYPE,
+ OUTER_L2_RSV,
+ OUTER_IP_TOS,
+ OUTER_IP_PROTO,
+ OUTER_SRC_IP,
+ OUTER_DST_IP,
+ OUTER_L3_RSV,
+ OUTER_SRC_PORT,
+ OUTER_DST_PORT,
+ OUTER_L4_RSV,
+ OUTER_TUN_VNI,
+ OUTER_TUN_FLOW_ID,
+ INNER_DST_MAC,
+ INNER_SRC_MAC,
+ INNER_VLAN_TAG_FST,
+ INNER_VLAN_TAG_SEC,
+ INNER_ETH_TYPE,
+ INNER_L2_RSV,
+ INNER_IP_TOS,
+ INNER_IP_PROTO,
+ INNER_SRC_IP,
+ INNER_DST_IP,
+ INNER_L3_RSV,
+ INNER_SRC_PORT,
+ INNER_DST_PORT,
+ INNER_L4_RSV,
+ MAX_TUPLE,
+};
+
+enum HCLGE_FD_META_DATA {
+ PACKET_TYPE_ID,
+ IP_FRAGEMENT,
+ ROCE_TYPE,
+ NEXT_KEY,
+ VLAN_NUMBER,
+ SRC_VPORT,
+ DST_VPORT,
+ TUNNEL_PACKET,
+ MAX_META_DATA,
+};
+
+struct key_info {
+ u8 key_type;
+ u8 key_length;
+};
+
+static const struct key_info meta_data_key_info[] = {
+ { PACKET_TYPE_ID, 6},
+ { IP_FRAGEMENT, 1},
+ { ROCE_TYPE, 1},
+ { NEXT_KEY, 5},
+ { VLAN_NUMBER, 2},
+ { SRC_VPORT, 12},
+ { DST_VPORT, 12},
+ { TUNNEL_PACKET, 1},
+};
+
+static const struct key_info tuple_key_info[] = {
+ { OUTER_DST_MAC, 48},
+ { OUTER_SRC_MAC, 48},
+ { OUTER_VLAN_TAG_FST, 16},
+ { OUTER_VLAN_TAG_SEC, 16},
+ { OUTER_ETH_TYPE, 16},
+ { OUTER_L2_RSV, 16},
+ { OUTER_IP_TOS, 8},
+ { OUTER_IP_PROTO, 8},
+ { OUTER_SRC_IP, 32},
+ { OUTER_DST_IP, 32},
+ { OUTER_L3_RSV, 16},
+ { OUTER_SRC_PORT, 16},
+ { OUTER_DST_PORT, 16},
+ { OUTER_L4_RSV, 32},
+ { OUTER_TUN_VNI, 24},
+ { OUTER_TUN_FLOW_ID, 8},
+ { INNER_DST_MAC, 48},
+ { INNER_SRC_MAC, 48},
+ { INNER_VLAN_TAG_FST, 16},
+ { INNER_VLAN_TAG_SEC, 16},
+ { INNER_ETH_TYPE, 16},
+ { INNER_L2_RSV, 16},
+ { INNER_IP_TOS, 8},
+ { INNER_IP_PROTO, 8},
+ { INNER_SRC_IP, 32},
+ { INNER_DST_IP, 32},
+ { INNER_L3_RSV, 16},
+ { INNER_SRC_PORT, 16},
+ { INNER_DST_PORT, 16},
+ { INNER_L4_RSV, 32},
+};
+
+#define MAX_KEY_LENGTH 400
+#define MAX_KEY_DWORDS DIV_ROUND_UP(MAX_KEY_LENGTH / 8, 4)
+#define MAX_KEY_BYTES (MAX_KEY_DWORDS * 4)
+#define MAX_META_DATA_LENGTH 32
+
+enum HCLGE_FD_PACKET_TYPE {
+ NIC_PACKET,
+ ROCE_PACKET,
+};
+
+enum HCLGE_FD_ACTION {
+ HCLGE_FD_ACTION_ACCEPT_PACKET,
+ HCLGE_FD_ACTION_DROP_PACKET,
+};
+
+struct hclge_fd_key_cfg {
+ u8 key_sel;
+ u8 inner_sipv6_word_en;
+ u8 inner_dipv6_word_en;
+ u8 outer_sipv6_word_en;
+ u8 outer_dipv6_word_en;
+ u32 tuple_active;
+ u32 meta_data_active;
+};
+
+struct hclge_fd_cfg {
+ u8 fd_mode;
+ u8 fd_en;
+ u16 max_key_length;
+ u32 proto_support;
+ u32 rule_num[2]; /* rule entry number */
+ u16 cnt_num[2]; /* rule hit counter number */
+ struct hclge_fd_key_cfg key_cfg[2];
+};
+
+struct hclge_fd_rule_tuples {
+ u8 src_mac[6];
+ u8 dst_mac[6];
+ u32 src_ip[4];
+ u32 dst_ip[4];
+ u16 src_port;
+ u16 dst_port;
+ u16 vlan_tag1;
+ u16 ether_proto;
+ u8 ip_tos;
+ u8 ip_proto;
+};
+
+struct hclge_fd_rule {
+ struct hlist_node rule_node;
+ struct hclge_fd_rule_tuples tuples;
+ struct hclge_fd_rule_tuples tuples_mask;
+ u32 unused_tuple;
+ u32 flow_type;
+ u8 action;
+ u16 vf_id;
+ u16 queue_id;
+ u16 location;
+};
+
+struct hclge_fd_ad_data {
+ u16 ad_id;
+ u8 drop_packet;
+ u8 forward_to_direct_queue;
+ u16 queue_id;
+ u8 use_counter;
+ u8 counter_id;
+ u8 use_next_stage;
+ u8 write_rule_id_to_bd;
+ u8 next_input_key;
+ u16 rule_id;
+};
+
+/* For each bit of TCAM entry, it uses a pair of 'x' and
+ * 'y' to indicate which value to match, like below:
+ * ----------------------------------
+ * | bit x | bit y | search value |
+ * ----------------------------------
+ * | 0 | 0 | always hit |
+ * ----------------------------------
+ * | 1 | 0 | match '0' |
+ * ----------------------------------
+ * | 0 | 1 | match '1' |
+ * ----------------------------------
+ * | 1 | 1 | invalid |
+ * ----------------------------------
+ * Then for input key(k) and mask(v), we can calculate the value by
+ * the formulae:
+ * x = (~k) & v
+ * y = (k ^ ~v) & k
+ */
+#define calc_x(x, k, v) ((x) = (~(k) & (v)))
+#define calc_y(y, k, v) \
+ do { \
+ const typeof(k) _k_ = (k); \
+ const typeof(v) _v_ = (v); \
+ (y) = (_k_ ^ ~_v_) & (_k_); \
+ } while (0)
+
#define HCLGE_VPORT_NUM 256
struct hclge_dev {
struct pci_dev *pdev;
@@ -547,12 +668,22 @@ struct hclge_dev {
u32 pkt_buf_size; /* Total pf buf size for tx/rx */
u32 mps; /* Max packet size */
- enum hclge_mta_dmac_sel_type mta_mac_sel_type;
- bool enable_mta; /* Multicast filter enable */
-
struct hclge_vlan_type_cfg vlan_type_cfg;
unsigned long vlan_table[VLAN_N_VID][BITS_TO_LONGS(HCLGE_VPORT_NUM)];
+
+ struct hclge_fd_cfg fd_cfg;
+ struct hlist_head fd_rule_list;
+ u16 hclge_fd_rule_num;
+
+ u16 wanted_umv_size;
+ /* max available unicast mac vlan space */
+ u16 max_umv_size;
+ /* private unicast mac vlan space, it's same for PF and its VFs */
+ u16 priv_umv_size;
+ /* unicast mac vlan space shared by PF and its VFs */
+ u16 share_umv_size;
+ struct mutex umv_mutex; /* protect share_umv_size */
};
/* VPort level vlan tag configuration for TX direction */
@@ -605,13 +736,12 @@ struct hclge_vport {
struct hclge_tx_vtag_cfg txvlan_cfg;
struct hclge_rx_vtag_cfg rxvlan_cfg;
+ u16 used_umv_num;
+
int vport_id;
struct hclge_dev *back; /* Back reference to associated dev */
struct hnae3_handle nic;
struct hnae3_handle roce;
-
- bool accept_mta_mc; /* whether to accept mta filter multicast */
- unsigned long mta_shadow[BITS_TO_LONGS(HCLGE_MTA_TBL_SIZE)];
};
void hclge_promisc_param_init(struct hclge_promisc_param *param, bool en_uc,
@@ -626,15 +756,6 @@ int hclge_add_mc_addr_common(struct hclge_vport *vport,
int hclge_rm_mc_addr_common(struct hclge_vport *vport,
const unsigned char *addr);
-int hclge_cfg_func_mta_filter(struct hclge_dev *hdev,
- u8 func_id,
- bool enable);
-int hclge_update_mta_status_common(struct hclge_vport *vport,
- unsigned long *status,
- u16 idx,
- u16 count,
- bool update_filter);
-
struct hclge_vport *hclge_get_vport(struct hnae3_handle *handle);
int hclge_bind_ring_with_vector(struct hclge_vport *vport,
int vector_id, bool en,
@@ -657,7 +778,7 @@ int hclge_rss_init_hw(struct hclge_dev *hdev);
void hclge_rss_indir_init_cfg(struct hclge_dev *hdev);
void hclge_mbx_handler(struct hclge_dev *hdev);
-void hclge_reset_tqp(struct hnae3_handle *handle, u16 queue_id);
+int hclge_reset_tqp(struct hnae3_handle *handle, u16 queue_id);
void hclge_reset_vf_queue(struct hclge_vport *vport, u16 queue_id);
int hclge_cfg_flowctrl(struct hclge_dev *hdev);
int hclge_func_reset_cmd(struct hclge_dev *hdev, int func_id);
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c
index f34851c91eb3..f890022938d9 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c
@@ -233,43 +233,6 @@ static int hclge_set_vf_uc_mac_addr(struct hclge_vport *vport,
return 0;
}
-static int hclge_set_vf_mc_mta_status(struct hclge_vport *vport,
- u8 *msg, u8 idx, bool is_end)
-{
-#define HCLGE_MTA_STATUS_MSG_SIZE 13
-#define HCLGE_MTA_STATUS_MSG_BITS \
- (HCLGE_MTA_STATUS_MSG_SIZE * BITS_PER_BYTE)
-#define HCLGE_MTA_STATUS_MSG_END_BITS \
- (HCLGE_MTA_TBL_SIZE % HCLGE_MTA_STATUS_MSG_BITS)
- unsigned long status[BITS_TO_LONGS(HCLGE_MTA_STATUS_MSG_BITS)];
- u16 tbl_cnt;
- u16 tbl_idx;
- u8 msg_ofs;
- u8 msg_bit;
-
- tbl_cnt = is_end ? HCLGE_MTA_STATUS_MSG_END_BITS :
- HCLGE_MTA_STATUS_MSG_BITS;
-
- /* set msg field */
- msg_ofs = 0;
- msg_bit = 0;
- memset(status, 0, sizeof(status));
- for (tbl_idx = 0; tbl_idx < tbl_cnt; tbl_idx++) {
- if (msg[msg_ofs] & BIT(msg_bit))
- set_bit(tbl_idx, status);
-
- msg_bit++;
- if (msg_bit == BITS_PER_BYTE) {
- msg_bit = 0;
- msg_ofs++;
- }
- }
-
- return hclge_update_mta_status_common(vport,
- status, idx * HCLGE_MTA_STATUS_MSG_BITS,
- tbl_cnt, is_end);
-}
-
static int hclge_set_vf_mc_mac_addr(struct hclge_vport *vport,
struct hclge_mbx_vf_to_pf_cmd *mbx_req,
bool gen_resp)
@@ -284,27 +247,6 @@ static int hclge_set_vf_mc_mac_addr(struct hclge_vport *vport,
status = hclge_add_mc_addr_common(vport, mac_addr);
} else if (mbx_req->msg[1] == HCLGE_MBX_MAC_VLAN_MC_REMOVE) {
status = hclge_rm_mc_addr_common(vport, mac_addr);
- } else if (mbx_req->msg[1] == HCLGE_MBX_MAC_VLAN_MC_FUNC_MTA_ENABLE) {
- u8 func_id = vport->vport_id;
- bool enable = mbx_req->msg[2];
-
- status = hclge_cfg_func_mta_filter(hdev, func_id, enable);
- } else if (mbx_req->msg[1] == HCLGE_MBX_MAC_VLAN_MTA_TYPE_READ) {
- resp_data = hdev->mta_mac_sel_type;
- resp_len = sizeof(u8);
- gen_resp = true;
- status = 0;
- } else if (mbx_req->msg[1] == HCLGE_MBX_MAC_VLAN_MTA_STATUS_UPDATE) {
- /* mta status update msg format
- * msg[2.6 : 2.0] msg index
- * msg[2.7] msg is end
- * msg[15 : 3] mta status bits[103 : 0]
- */
- bool is_end = (mbx_req->msg[2] & 0x80) ? true : false;
-
- status = hclge_set_vf_mc_mta_status(vport, &mbx_req->msg[3],
- mbx_req->msg[2] & 0x7F,
- is_end);
} else {
dev_err(&hdev->pdev->dev,
"failed to set mcast mac addr, unknown subcode %d\n",
@@ -458,6 +400,12 @@ void hclge_mbx_handler(struct hclge_dev *hdev)
/* handle all the mailbox requests in the queue */
while (!hclge_cmd_crq_empty(&hdev->hw)) {
+ if (test_bit(HCLGE_STATE_CMD_DISABLE, &hdev->state)) {
+ dev_warn(&hdev->pdev->dev,
+ "command queue needs re-initializing\n");
+ return;
+ }
+
desc = &crq->desc[crq->next_to_use];
req = (struct hclge_mbx_vf_to_pf_cmd *)desc->data;
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c
index 398971a062f4..03018638f701 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c
@@ -10,8 +10,6 @@
#define HCLGE_PHY_SUPPORTED_FEATURES (SUPPORTED_Autoneg | \
SUPPORTED_TP | \
- SUPPORTED_Pause | \
- SUPPORTED_Asym_Pause | \
PHY_10BT_FEATURES | \
PHY_100BT_FEATURES | \
PHY_1000BT_FEATURES)
@@ -54,7 +52,7 @@ static int hclge_mdio_write(struct mii_bus *bus, int phyid, int regnum,
struct hclge_desc desc;
int ret;
- if (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state))
+ if (test_bit(HCLGE_STATE_CMD_DISABLE, &hdev->state))
return 0;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MDIO_CONFIG, false);
@@ -92,7 +90,7 @@ static int hclge_mdio_read(struct mii_bus *bus, int phyid, int regnum)
struct hclge_desc desc;
int ret;
- if (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state))
+ if (test_bit(HCLGE_STATE_CMD_DISABLE, &hdev->state))
return 0;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MDIO_CONFIG, true);
@@ -213,7 +211,7 @@ int hclge_mac_connect_phy(struct hclge_dev *hdev)
}
phydev->supported &= HCLGE_PHY_SUPPORTED_FEATURES;
- phydev->advertising = phydev->supported;
+ phy_support_asym_pause(phydev);
return 0;
}
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c
index 5db70a1451c5..494e562fe8c7 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c
@@ -172,7 +172,7 @@ static int hclge_pfc_pause_en_cfg(struct hclge_dev *hdev, u8 tx_rx_bitmap,
u8 pfc_bitmap)
{
struct hclge_desc desc;
- struct hclge_pfc_en_cmd *pfc = (struct hclge_pfc_en_cmd *)&desc.data;
+ struct hclge_pfc_en_cmd *pfc = (struct hclge_pfc_en_cmd *)desc.data;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CFG_PFC_PAUSE_EN, false);
@@ -188,11 +188,12 @@ static int hclge_pause_param_cfg(struct hclge_dev *hdev, const u8 *addr,
struct hclge_cfg_pause_param_cmd *pause_param;
struct hclge_desc desc;
- pause_param = (struct hclge_cfg_pause_param_cmd *)&desc.data;
+ pause_param = (struct hclge_cfg_pause_param_cmd *)desc.data;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CFG_MAC_PARA, false);
ether_addr_copy(pause_param->mac_addr, addr);
+ ether_addr_copy(pause_param->mac_addr_extra, addr);
pause_param->pause_trans_gap = pause_trans_gap;
pause_param->pause_trans_time = cpu_to_le16(pause_trans_time);
@@ -207,7 +208,7 @@ int hclge_pause_addr_cfg(struct hclge_dev *hdev, const u8 *mac_addr)
u8 trans_gap;
int ret;
- pause_param = (struct hclge_cfg_pause_param_cmd *)&desc.data;
+ pause_param = (struct hclge_cfg_pause_param_cmd *)desc.data;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CFG_MAC_PARA, true);
@@ -297,7 +298,7 @@ static int hclge_tm_qs_to_pri_map_cfg(struct hclge_dev *hdev,
}
static int hclge_tm_q_to_qs_map_cfg(struct hclge_dev *hdev,
- u8 q_id, u16 qs_id)
+ u16 q_id, u16 qs_id)
{
struct hclge_nq_to_qs_link_cmd *map;
struct hclge_desc desc;
@@ -1167,14 +1168,14 @@ static int hclge_pfc_setup_hw(struct hclge_dev *hdev)
*/
static int hclge_bp_setup_hw(struct hclge_dev *hdev, u8 tc)
{
- struct hclge_vport *vport = hdev->vport;
- u32 i, k, qs_bitmap;
- int ret;
+ int i;
for (i = 0; i < HCLGE_BP_GRP_NUM; i++) {
- qs_bitmap = 0;
+ u32 qs_bitmap = 0;
+ int k, ret;
for (k = 0; k < hdev->num_alloc_vport; k++) {
+ struct hclge_vport *vport = &hdev->vport[k];
u16 qs_id = vport->qs_offset + tc;
u8 grp, sub_grp;
@@ -1184,8 +1185,6 @@ static int hclge_bp_setup_hw(struct hclge_dev *hdev, u8 tc)
HCLGE_BP_SUB_GRP_ID_S);
if (i == grp)
qs_bitmap |= (1 << sub_grp);
-
- vport++;
}
ret = hclge_tm_qs_bp_cfg(hdev, tc, i, qs_bitmap);
@@ -1279,10 +1278,15 @@ int hclge_tm_prio_tc_info_update(struct hclge_dev *hdev, u8 *prio_tc)
return 0;
}
-void hclge_tm_schd_info_update(struct hclge_dev *hdev, u8 num_tc)
+int hclge_tm_schd_info_update(struct hclge_dev *hdev, u8 num_tc)
{
u8 i, bit_map = 0;
+ for (i = 0; i < hdev->num_alloc_vport; i++) {
+ if (num_tc > hdev->vport[i].alloc_tqps)
+ return -EINVAL;
+ }
+
hdev->tm_info.num_tc = num_tc;
for (i = 0; i < hdev->tm_info.num_tc; i++)
@@ -1296,6 +1300,8 @@ void hclge_tm_schd_info_update(struct hclge_dev *hdev, u8 num_tc)
hdev->hw_tc_map = bit_map;
hclge_tm_schd_info_init(hdev);
+
+ return 0;
}
int hclge_tm_init_hw(struct hclge_dev *hdev)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h
index dd4c194747c1..25eef13a3e14 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h
@@ -106,6 +106,10 @@ struct hclge_cfg_pause_param_cmd {
u8 pause_trans_gap;
u8 rsvd;
__le16 pause_trans_time;
+ u8 rsvd1[6];
+ /* extra mac address to do double check for pause frame */
+ u8 mac_addr_extra[ETH_ALEN];
+ u16 rsvd2;
};
struct hclge_pfc_stats_cmd {
@@ -128,7 +132,7 @@ int hclge_tm_schd_init(struct hclge_dev *hdev);
int hclge_pause_setup_hw(struct hclge_dev *hdev);
int hclge_tm_schd_mode_hw(struct hclge_dev *hdev);
int hclge_tm_prio_tc_info_update(struct hclge_dev *hdev, u8 *prio_tc);
-void hclge_tm_schd_info_update(struct hclge_dev *hdev, u8 num_tc);
+int hclge_tm_schd_info_update(struct hclge_dev *hdev, u8 num_tc);
int hclge_tm_dwrr_cfg(struct hclge_dev *hdev);
int hclge_tm_map_cfg(struct hclge_dev *hdev);
int hclge_tm_init_hw(struct hclge_dev *hdev);
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c
index fb471fe2c494..0d3b445f6799 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c
@@ -132,9 +132,9 @@ static int hclgevf_init_cmd_queue(struct hclgevf_dev *hdev,
reg_val |= HCLGEVF_NIC_CMQ_ENABLE;
hclgevf_write_dev(hw, HCLGEVF_NIC_CSQ_DEPTH_REG, reg_val);
- hclgevf_write_dev(hw, HCLGEVF_NIC_CSQ_TAIL_REG, 0);
hclgevf_write_dev(hw, HCLGEVF_NIC_CSQ_HEAD_REG, 0);
- break;
+ hclgevf_write_dev(hw, HCLGEVF_NIC_CSQ_TAIL_REG, 0);
+ return 0;
case HCLGEVF_TYPE_CRQ:
reg_val = (u32)ring->desc_dma_addr;
hclgevf_write_dev(hw, HCLGEVF_NIC_CRQ_BASEADDR_L_REG, reg_val);
@@ -145,12 +145,12 @@ static int hclgevf_init_cmd_queue(struct hclgevf_dev *hdev,
reg_val |= HCLGEVF_NIC_CMQ_ENABLE;
hclgevf_write_dev(hw, HCLGEVF_NIC_CRQ_DEPTH_REG, reg_val);
- hclgevf_write_dev(hw, HCLGEVF_NIC_CRQ_TAIL_REG, 0);
hclgevf_write_dev(hw, HCLGEVF_NIC_CRQ_HEAD_REG, 0);
- break;
+ hclgevf_write_dev(hw, HCLGEVF_NIC_CRQ_TAIL_REG, 0);
+ return 0;
+ default:
+ return -EINVAL;
}
-
- return 0;
}
void hclgevf_cmd_setup_basic_desc(struct hclgevf_desc *desc,
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h
index 19b32860309c..bc294b0c8b62 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h
@@ -89,6 +89,7 @@ enum hclgevf_opcode_type {
HCLGEVF_OPC_CFG_COM_TQP_QUEUE = 0x0B20,
/* RSS cmd */
HCLGEVF_OPC_RSS_GENERIC_CONFIG = 0x0D01,
+ HCLGEVF_OPC_RSS_INPUT_TUPLE = 0x0D02,
HCLGEVF_OPC_RSS_INDIR_TABLE = 0x0D07,
HCLGEVF_OPC_RSS_TC_MODE = 0x0D08,
/* Mailbox cmd */
@@ -148,7 +149,8 @@ struct hclgevf_query_res_cmd {
__le16 rsv[7];
};
-#define HCLGEVF_RSS_HASH_KEY_OFFSET 4
+#define HCLGEVF_RSS_DEFAULT_OUTPORT_B 4
+#define HCLGEVF_RSS_HASH_KEY_OFFSET_B 4
#define HCLGEVF_RSS_HASH_KEY_NUM 16
struct hclgevf_rss_config_cmd {
u8 hash_config;
@@ -159,11 +161,11 @@ struct hclgevf_rss_config_cmd {
struct hclgevf_rss_input_tuple_cmd {
u8 ipv4_tcp_en;
u8 ipv4_udp_en;
- u8 ipv4_stcp_en;
+ u8 ipv4_sctp_en;
u8 ipv4_fragment_en;
u8 ipv6_tcp_en;
u8 ipv6_udp_en;
- u8 ipv6_stcp_en;
+ u8 ipv6_sctp_en;
u8 ipv6_fragment_en;
u8 rsv[16];
};
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
index 9c0091f2addf..085edb945389 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
@@ -31,16 +31,15 @@ static inline struct hclgevf_dev *hclgevf_ae_get_hdev(
static int hclgevf_tqps_update_stats(struct hnae3_handle *handle)
{
+ struct hnae3_knic_private_info *kinfo = &handle->kinfo;
struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
- struct hnae3_queue *queue;
struct hclgevf_desc desc;
struct hclgevf_tqp *tqp;
int status;
int i;
- for (i = 0; i < hdev->num_tqps; i++) {
- queue = handle->kinfo.tqp[i];
- tqp = container_of(queue, struct hclgevf_tqp, q);
+ for (i = 0; i < kinfo->num_tqps; i++) {
+ tqp = container_of(kinfo->tqp[i], struct hclgevf_tqp, q);
hclgevf_cmd_setup_basic_desc(&desc,
HCLGEVF_OPC_QUERY_RX_STATUS,
true);
@@ -77,17 +76,16 @@ static int hclgevf_tqps_update_stats(struct hnae3_handle *handle)
static u64 *hclgevf_tqps_get_stats(struct hnae3_handle *handle, u64 *data)
{
struct hnae3_knic_private_info *kinfo = &handle->kinfo;
- struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
struct hclgevf_tqp *tqp;
u64 *buff = data;
int i;
- for (i = 0; i < hdev->num_tqps; i++) {
- tqp = container_of(handle->kinfo.tqp[i], struct hclgevf_tqp, q);
+ for (i = 0; i < kinfo->num_tqps; i++) {
+ tqp = container_of(kinfo->tqp[i], struct hclgevf_tqp, q);
*buff++ = tqp->tqp_stats.rcb_tx_ring_pktnum_rcd;
}
for (i = 0; i < kinfo->num_tqps; i++) {
- tqp = container_of(handle->kinfo.tqp[i], struct hclgevf_tqp, q);
+ tqp = container_of(kinfo->tqp[i], struct hclgevf_tqp, q);
*buff++ = tqp->tqp_stats.rcb_rx_ring_pktnum_rcd;
}
@@ -96,29 +94,29 @@ static u64 *hclgevf_tqps_get_stats(struct hnae3_handle *handle, u64 *data)
static int hclgevf_tqps_get_sset_count(struct hnae3_handle *handle, int strset)
{
- struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
+ struct hnae3_knic_private_info *kinfo = &handle->kinfo;
- return hdev->num_tqps * 2;
+ return kinfo->num_tqps * 2;
}
static u8 *hclgevf_tqps_get_strings(struct hnae3_handle *handle, u8 *data)
{
- struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
+ struct hnae3_knic_private_info *kinfo = &handle->kinfo;
u8 *buff = data;
int i = 0;
- for (i = 0; i < hdev->num_tqps; i++) {
- struct hclgevf_tqp *tqp = container_of(handle->kinfo.tqp[i],
- struct hclgevf_tqp, q);
- snprintf(buff, ETH_GSTRING_LEN, "txq#%d_pktnum_rcd",
+ for (i = 0; i < kinfo->num_tqps; i++) {
+ struct hclgevf_tqp *tqp = container_of(kinfo->tqp[i],
+ struct hclgevf_tqp, q);
+ snprintf(buff, ETH_GSTRING_LEN, "txq%d_pktnum_rcd",
tqp->index);
buff += ETH_GSTRING_LEN;
}
- for (i = 0; i < hdev->num_tqps; i++) {
- struct hclgevf_tqp *tqp = container_of(handle->kinfo.tqp[i],
- struct hclgevf_tqp, q);
- snprintf(buff, ETH_GSTRING_LEN, "rxq#%d_pktnum_rcd",
+ for (i = 0; i < kinfo->num_tqps; i++) {
+ struct hclgevf_tqp *tqp = container_of(kinfo->tqp[i],
+ struct hclgevf_tqp, q);
+ snprintf(buff, ETH_GSTRING_LEN, "rxq%d_pktnum_rcd",
tqp->index);
buff += ETH_GSTRING_LEN;
}
@@ -182,7 +180,7 @@ static int hclgevf_get_tc_info(struct hclgevf_dev *hdev)
return 0;
}
-static int hclge_get_queue_info(struct hclgevf_dev *hdev)
+static int hclgevf_get_queue_info(struct hclgevf_dev *hdev)
{
#define HCLGEVF_TQPS_RSS_INFO_LEN 8
u8 resp_msg[HCLGEVF_TQPS_RSS_INFO_LEN];
@@ -299,6 +297,9 @@ void hclgevf_update_link_status(struct hclgevf_dev *hdev, int link_state)
client = handle->client;
+ link_state =
+ test_bit(HCLGEVF_STATE_DOWN, &hdev->state) ? 0 : link_state;
+
if (link_state != hdev->hw.mac.link) {
client->ops->link_status_change(handle, !!link_state);
hdev->hw.mac.link = link_state;
@@ -385,6 +386,47 @@ static int hclgevf_get_vector_index(struct hclgevf_dev *hdev, int vector)
return -EINVAL;
}
+static int hclgevf_set_rss_algo_key(struct hclgevf_dev *hdev,
+ const u8 hfunc, const u8 *key)
+{
+ struct hclgevf_rss_config_cmd *req;
+ struct hclgevf_desc desc;
+ int key_offset;
+ int key_size;
+ int ret;
+
+ req = (struct hclgevf_rss_config_cmd *)desc.data;
+
+ for (key_offset = 0; key_offset < 3; key_offset++) {
+ hclgevf_cmd_setup_basic_desc(&desc,
+ HCLGEVF_OPC_RSS_GENERIC_CONFIG,
+ false);
+
+ req->hash_config |= (hfunc & HCLGEVF_RSS_HASH_ALGO_MASK);
+ req->hash_config |=
+ (key_offset << HCLGEVF_RSS_HASH_KEY_OFFSET_B);
+
+ if (key_offset == 2)
+ key_size =
+ HCLGEVF_RSS_KEY_SIZE - HCLGEVF_RSS_HASH_KEY_NUM * 2;
+ else
+ key_size = HCLGEVF_RSS_HASH_KEY_NUM;
+
+ memcpy(req->hash_key,
+ key + key_offset * HCLGEVF_RSS_HASH_KEY_NUM, key_size);
+
+ ret = hclgevf_cmd_send(&hdev->hw, &desc, 1);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "Configure RSS config fail, status = %d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
static u32 hclgevf_get_rss_key_size(struct hnae3_handle *handle)
{
return HCLGEVF_RSS_KEY_SIZE;
@@ -465,68 +507,40 @@ static int hclgevf_set_rss_tc_mode(struct hclgevf_dev *hdev, u16 rss_size)
return status;
}
-static int hclgevf_get_rss_hw_cfg(struct hnae3_handle *handle, u8 *hash,
- u8 *key)
+static int hclgevf_get_rss(struct hnae3_handle *handle, u32 *indir, u8 *key,
+ u8 *hfunc)
{
struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
- struct hclgevf_rss_config_cmd *req;
- int lkup_times = key ? 3 : 1;
- struct hclgevf_desc desc;
- int key_offset;
- int key_size;
- int status;
-
- req = (struct hclgevf_rss_config_cmd *)desc.data;
- lkup_times = (lkup_times == 3) ? 3 : ((hash) ? 1 : 0);
-
- for (key_offset = 0; key_offset < lkup_times; key_offset++) {
- hclgevf_cmd_setup_basic_desc(&desc,
- HCLGEVF_OPC_RSS_GENERIC_CONFIG,
- true);
- req->hash_config |= (key_offset << HCLGEVF_RSS_HASH_KEY_OFFSET);
+ struct hclgevf_rss_cfg *rss_cfg = &hdev->rss_cfg;
+ int i;
- status = hclgevf_cmd_send(&hdev->hw, &desc, 1);
- if (status) {
- dev_err(&hdev->pdev->dev,
- "failed to get hardware RSS cfg, status = %d\n",
- status);
- return status;
+ if (handle->pdev->revision >= 0x21) {
+ /* Get hash algorithm */
+ if (hfunc) {
+ switch (rss_cfg->hash_algo) {
+ case HCLGEVF_RSS_HASH_ALGO_TOEPLITZ:
+ *hfunc = ETH_RSS_HASH_TOP;
+ break;
+ case HCLGEVF_RSS_HASH_ALGO_SIMPLE:
+ *hfunc = ETH_RSS_HASH_XOR;
+ break;
+ default:
+ *hfunc = ETH_RSS_HASH_UNKNOWN;
+ break;
+ }
}
- if (key_offset == 2)
- key_size =
- HCLGEVF_RSS_KEY_SIZE - HCLGEVF_RSS_HASH_KEY_NUM * 2;
- else
- key_size = HCLGEVF_RSS_HASH_KEY_NUM;
-
+ /* Get the RSS Key required by the user */
if (key)
- memcpy(key + key_offset * HCLGEVF_RSS_HASH_KEY_NUM,
- req->hash_key,
- key_size);
+ memcpy(key, rss_cfg->rss_hash_key,
+ HCLGEVF_RSS_KEY_SIZE);
}
- if (hash) {
- if ((req->hash_config & 0xf) == HCLGEVF_RSS_HASH_ALGO_TOEPLITZ)
- *hash = ETH_RSS_HASH_TOP;
- else
- *hash = ETH_RSS_HASH_UNKNOWN;
- }
-
- return 0;
-}
-
-static int hclgevf_get_rss(struct hnae3_handle *handle, u32 *indir, u8 *key,
- u8 *hfunc)
-{
- struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
- struct hclgevf_rss_cfg *rss_cfg = &hdev->rss_cfg;
- int i;
-
if (indir)
for (i = 0; i < HCLGEVF_RSS_IND_TBL_SIZE; i++)
indir[i] = rss_cfg->rss_indirection_tbl[i];
- return hclgevf_get_rss_hw_cfg(handle, hfunc, key);
+ return 0;
}
static int hclgevf_set_rss(struct hnae3_handle *handle, const u32 *indir,
@@ -534,7 +548,36 @@ static int hclgevf_set_rss(struct hnae3_handle *handle, const u32 *indir,
{
struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
struct hclgevf_rss_cfg *rss_cfg = &hdev->rss_cfg;
- int i;
+ int ret, i;
+
+ if (handle->pdev->revision >= 0x21) {
+ /* Set the RSS Hash Key if specififed by the user */
+ if (key) {
+ switch (hfunc) {
+ case ETH_RSS_HASH_TOP:
+ rss_cfg->hash_algo =
+ HCLGEVF_RSS_HASH_ALGO_TOEPLITZ;
+ break;
+ case ETH_RSS_HASH_XOR:
+ rss_cfg->hash_algo =
+ HCLGEVF_RSS_HASH_ALGO_SIMPLE;
+ break;
+ case ETH_RSS_HASH_NO_CHANGE:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = hclgevf_set_rss_algo_key(hdev, rss_cfg->hash_algo,
+ key);
+ if (ret)
+ return ret;
+
+ /* Update the shadow RSS key with user specified qids */
+ memcpy(rss_cfg->rss_hash_key, key,
+ HCLGEVF_RSS_KEY_SIZE);
+ }
+ }
/* update the shadow RSS table with user specified qids */
for (i = 0; i < HCLGEVF_RSS_IND_TBL_SIZE; i++)
@@ -544,6 +587,193 @@ static int hclgevf_set_rss(struct hnae3_handle *handle, const u32 *indir,
return hclgevf_set_rss_indir_table(hdev);
}
+static u8 hclgevf_get_rss_hash_bits(struct ethtool_rxnfc *nfc)
+{
+ u8 hash_sets = nfc->data & RXH_L4_B_0_1 ? HCLGEVF_S_PORT_BIT : 0;
+
+ if (nfc->data & RXH_L4_B_2_3)
+ hash_sets |= HCLGEVF_D_PORT_BIT;
+ else
+ hash_sets &= ~HCLGEVF_D_PORT_BIT;
+
+ if (nfc->data & RXH_IP_SRC)
+ hash_sets |= HCLGEVF_S_IP_BIT;
+ else
+ hash_sets &= ~HCLGEVF_S_IP_BIT;
+
+ if (nfc->data & RXH_IP_DST)
+ hash_sets |= HCLGEVF_D_IP_BIT;
+ else
+ hash_sets &= ~HCLGEVF_D_IP_BIT;
+
+ if (nfc->flow_type == SCTP_V4_FLOW || nfc->flow_type == SCTP_V6_FLOW)
+ hash_sets |= HCLGEVF_V_TAG_BIT;
+
+ return hash_sets;
+}
+
+static int hclgevf_set_rss_tuple(struct hnae3_handle *handle,
+ struct ethtool_rxnfc *nfc)
+{
+ struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
+ struct hclgevf_rss_cfg *rss_cfg = &hdev->rss_cfg;
+ struct hclgevf_rss_input_tuple_cmd *req;
+ struct hclgevf_desc desc;
+ u8 tuple_sets;
+ int ret;
+
+ if (handle->pdev->revision == 0x20)
+ return -EOPNOTSUPP;
+
+ if (nfc->data &
+ ~(RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 | RXH_L4_B_2_3))
+ return -EINVAL;
+
+ req = (struct hclgevf_rss_input_tuple_cmd *)desc.data;
+ hclgevf_cmd_setup_basic_desc(&desc, HCLGEVF_OPC_RSS_INPUT_TUPLE, false);
+
+ req->ipv4_tcp_en = rss_cfg->rss_tuple_sets.ipv4_tcp_en;
+ req->ipv4_udp_en = rss_cfg->rss_tuple_sets.ipv4_udp_en;
+ req->ipv4_sctp_en = rss_cfg->rss_tuple_sets.ipv4_sctp_en;
+ req->ipv4_fragment_en = rss_cfg->rss_tuple_sets.ipv4_fragment_en;
+ req->ipv6_tcp_en = rss_cfg->rss_tuple_sets.ipv6_tcp_en;
+ req->ipv6_udp_en = rss_cfg->rss_tuple_sets.ipv6_udp_en;
+ req->ipv6_sctp_en = rss_cfg->rss_tuple_sets.ipv6_sctp_en;
+ req->ipv6_fragment_en = rss_cfg->rss_tuple_sets.ipv6_fragment_en;
+
+ tuple_sets = hclgevf_get_rss_hash_bits(nfc);
+ switch (nfc->flow_type) {
+ case TCP_V4_FLOW:
+ req->ipv4_tcp_en = tuple_sets;
+ break;
+ case TCP_V6_FLOW:
+ req->ipv6_tcp_en = tuple_sets;
+ break;
+ case UDP_V4_FLOW:
+ req->ipv4_udp_en = tuple_sets;
+ break;
+ case UDP_V6_FLOW:
+ req->ipv6_udp_en = tuple_sets;
+ break;
+ case SCTP_V4_FLOW:
+ req->ipv4_sctp_en = tuple_sets;
+ break;
+ case SCTP_V6_FLOW:
+ if ((nfc->data & RXH_L4_B_0_1) ||
+ (nfc->data & RXH_L4_B_2_3))
+ return -EINVAL;
+
+ req->ipv6_sctp_en = tuple_sets;
+ break;
+ case IPV4_FLOW:
+ req->ipv4_fragment_en = HCLGEVF_RSS_INPUT_TUPLE_OTHER;
+ break;
+ case IPV6_FLOW:
+ req->ipv6_fragment_en = HCLGEVF_RSS_INPUT_TUPLE_OTHER;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = hclgevf_cmd_send(&hdev->hw, &desc, 1);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "Set rss tuple fail, status = %d\n", ret);
+ return ret;
+ }
+
+ rss_cfg->rss_tuple_sets.ipv4_tcp_en = req->ipv4_tcp_en;
+ rss_cfg->rss_tuple_sets.ipv4_udp_en = req->ipv4_udp_en;
+ rss_cfg->rss_tuple_sets.ipv4_sctp_en = req->ipv4_sctp_en;
+ rss_cfg->rss_tuple_sets.ipv4_fragment_en = req->ipv4_fragment_en;
+ rss_cfg->rss_tuple_sets.ipv6_tcp_en = req->ipv6_tcp_en;
+ rss_cfg->rss_tuple_sets.ipv6_udp_en = req->ipv6_udp_en;
+ rss_cfg->rss_tuple_sets.ipv6_sctp_en = req->ipv6_sctp_en;
+ rss_cfg->rss_tuple_sets.ipv6_fragment_en = req->ipv6_fragment_en;
+ return 0;
+}
+
+static int hclgevf_get_rss_tuple(struct hnae3_handle *handle,
+ struct ethtool_rxnfc *nfc)
+{
+ struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
+ struct hclgevf_rss_cfg *rss_cfg = &hdev->rss_cfg;
+ u8 tuple_sets;
+
+ if (handle->pdev->revision == 0x20)
+ return -EOPNOTSUPP;
+
+ nfc->data = 0;
+
+ switch (nfc->flow_type) {
+ case TCP_V4_FLOW:
+ tuple_sets = rss_cfg->rss_tuple_sets.ipv4_tcp_en;
+ break;
+ case UDP_V4_FLOW:
+ tuple_sets = rss_cfg->rss_tuple_sets.ipv4_udp_en;
+ break;
+ case TCP_V6_FLOW:
+ tuple_sets = rss_cfg->rss_tuple_sets.ipv6_tcp_en;
+ break;
+ case UDP_V6_FLOW:
+ tuple_sets = rss_cfg->rss_tuple_sets.ipv6_udp_en;
+ break;
+ case SCTP_V4_FLOW:
+ tuple_sets = rss_cfg->rss_tuple_sets.ipv4_sctp_en;
+ break;
+ case SCTP_V6_FLOW:
+ tuple_sets = rss_cfg->rss_tuple_sets.ipv6_sctp_en;
+ break;
+ case IPV4_FLOW:
+ case IPV6_FLOW:
+ tuple_sets = HCLGEVF_S_IP_BIT | HCLGEVF_D_IP_BIT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (!tuple_sets)
+ return 0;
+
+ if (tuple_sets & HCLGEVF_D_PORT_BIT)
+ nfc->data |= RXH_L4_B_2_3;
+ if (tuple_sets & HCLGEVF_S_PORT_BIT)
+ nfc->data |= RXH_L4_B_0_1;
+ if (tuple_sets & HCLGEVF_D_IP_BIT)
+ nfc->data |= RXH_IP_DST;
+ if (tuple_sets & HCLGEVF_S_IP_BIT)
+ nfc->data |= RXH_IP_SRC;
+
+ return 0;
+}
+
+static int hclgevf_set_rss_input_tuple(struct hclgevf_dev *hdev,
+ struct hclgevf_rss_cfg *rss_cfg)
+{
+ struct hclgevf_rss_input_tuple_cmd *req;
+ struct hclgevf_desc desc;
+ int ret;
+
+ hclgevf_cmd_setup_basic_desc(&desc, HCLGEVF_OPC_RSS_INPUT_TUPLE, false);
+
+ req = (struct hclgevf_rss_input_tuple_cmd *)desc.data;
+
+ req->ipv4_tcp_en = rss_cfg->rss_tuple_sets.ipv4_tcp_en;
+ req->ipv4_udp_en = rss_cfg->rss_tuple_sets.ipv4_udp_en;
+ req->ipv4_sctp_en = rss_cfg->rss_tuple_sets.ipv4_sctp_en;
+ req->ipv4_fragment_en = rss_cfg->rss_tuple_sets.ipv4_fragment_en;
+ req->ipv6_tcp_en = rss_cfg->rss_tuple_sets.ipv6_tcp_en;
+ req->ipv6_udp_en = rss_cfg->rss_tuple_sets.ipv6_udp_en;
+ req->ipv6_sctp_en = rss_cfg->rss_tuple_sets.ipv6_sctp_en;
+ req->ipv6_fragment_en = rss_cfg->rss_tuple_sets.ipv6_fragment_en;
+
+ ret = hclgevf_cmd_send(&hdev->hw, &desc, 1);
+ if (ret)
+ dev_err(&hdev->pdev->dev,
+ "Configure rss input fail, status = %d\n", ret);
+ return ret;
+}
+
static int hclgevf_get_tc_size(struct hnae3_handle *handle)
{
struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
@@ -695,12 +925,12 @@ static int hclgevf_cmd_set_promisc_mode(struct hclgevf_dev *hdev,
return status;
}
-static void hclgevf_set_promisc_mode(struct hnae3_handle *handle,
- bool en_uc_pmc, bool en_mc_pmc)
+static int hclgevf_set_promisc_mode(struct hnae3_handle *handle,
+ bool en_uc_pmc, bool en_mc_pmc)
{
struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
- hclgevf_cmd_set_promisc_mode(hdev, en_uc_pmc, en_mc_pmc);
+ return hclgevf_cmd_set_promisc_mode(hdev, en_uc_pmc, en_mc_pmc);
}
static int hclgevf_tqp_enable(struct hclgevf_dev *hdev, int tqp_id,
@@ -735,138 +965,16 @@ static int hclgevf_get_queue_id(struct hnae3_queue *queue)
static void hclgevf_reset_tqp_stats(struct hnae3_handle *handle)
{
- struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
- struct hnae3_queue *queue;
+ struct hnae3_knic_private_info *kinfo = &handle->kinfo;
struct hclgevf_tqp *tqp;
int i;
- for (i = 0; i < hdev->num_tqps; i++) {
- queue = handle->kinfo.tqp[i];
- tqp = container_of(queue, struct hclgevf_tqp, q);
+ for (i = 0; i < kinfo->num_tqps; i++) {
+ tqp = container_of(kinfo->tqp[i], struct hclgevf_tqp, q);
memset(&tqp->tqp_stats, 0, sizeof(tqp->tqp_stats));
}
}
-static int hclgevf_cfg_func_mta_type(struct hclgevf_dev *hdev)
-{
- u8 resp_msg = HCLGEVF_MTA_TYPE_SEL_MAX;
- int ret;
-
- ret = hclgevf_send_mbx_msg(hdev, HCLGE_MBX_SET_MULTICAST,
- HCLGE_MBX_MAC_VLAN_MTA_TYPE_READ,
- NULL, 0, true, &resp_msg, sizeof(u8));
-
- if (ret) {
- dev_err(&hdev->pdev->dev,
- "Read mta type fail, ret=%d.\n", ret);
- return ret;
- }
-
- if (resp_msg > HCLGEVF_MTA_TYPE_SEL_MAX) {
- dev_err(&hdev->pdev->dev,
- "Read mta type invalid, resp=%d.\n", resp_msg);
- return -EINVAL;
- }
-
- hdev->mta_mac_sel_type = resp_msg;
-
- return 0;
-}
-
-static u16 hclgevf_get_mac_addr_to_mta_index(struct hclgevf_dev *hdev,
- const u8 *addr)
-{
- u32 rsh = HCLGEVF_MTA_TYPE_SEL_MAX - hdev->mta_mac_sel_type;
- u16 high_val = addr[1] | (addr[0] << 8);
-
- return (high_val >> rsh) & 0xfff;
-}
-
-static int hclgevf_do_update_mta_status(struct hclgevf_dev *hdev,
- unsigned long *status)
-{
-#define HCLGEVF_MTA_STATUS_MSG_SIZE 13
-#define HCLGEVF_MTA_STATUS_MSG_BITS \
- (HCLGEVF_MTA_STATUS_MSG_SIZE * BITS_PER_BYTE)
-#define HCLGEVF_MTA_STATUS_MSG_END_BITS \
- (HCLGEVF_MTA_TBL_SIZE % HCLGEVF_MTA_STATUS_MSG_BITS)
- u16 tbl_cnt;
- u16 tbl_idx;
- u8 msg_cnt;
- u8 msg_idx;
- int ret;
-
- msg_cnt = DIV_ROUND_UP(HCLGEVF_MTA_TBL_SIZE,
- HCLGEVF_MTA_STATUS_MSG_BITS);
- tbl_idx = 0;
- msg_idx = 0;
- while (msg_cnt--) {
- u8 msg[HCLGEVF_MTA_STATUS_MSG_SIZE + 1];
- u8 *p = &msg[1];
- u8 msg_ofs;
- u8 msg_bit;
-
- memset(msg, 0, sizeof(msg));
-
- /* set index field */
- msg[0] = 0x7F & msg_idx;
-
- /* set end flag field */
- if (msg_cnt == 0) {
- msg[0] |= 0x80;
- tbl_cnt = HCLGEVF_MTA_STATUS_MSG_END_BITS;
- } else {
- tbl_cnt = HCLGEVF_MTA_STATUS_MSG_BITS;
- }
-
- /* set status field */
- msg_ofs = 0;
- msg_bit = 0;
- while (tbl_cnt--) {
- if (test_bit(tbl_idx, status))
- p[msg_ofs] |= BIT(msg_bit);
-
- tbl_idx++;
-
- msg_bit++;
- if (msg_bit == BITS_PER_BYTE) {
- msg_bit = 0;
- msg_ofs++;
- }
- }
-
- ret = hclgevf_send_mbx_msg(hdev, HCLGE_MBX_SET_MULTICAST,
- HCLGE_MBX_MAC_VLAN_MTA_STATUS_UPDATE,
- msg, sizeof(msg), false, NULL, 0);
- if (ret)
- break;
-
- msg_idx++;
- }
-
- return ret;
-}
-
-static int hclgevf_update_mta_status(struct hnae3_handle *handle)
-{
- unsigned long mta_status[BITS_TO_LONGS(HCLGEVF_MTA_TBL_SIZE)];
- struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
- struct net_device *netdev = hdev->nic.kinfo.netdev;
- struct netdev_hw_addr *ha;
- u16 tbl_idx;
-
- /* clear status */
- memset(mta_status, 0, sizeof(mta_status));
-
- /* update status from mc addr list */
- netdev_for_each_mc_addr(ha, netdev) {
- tbl_idx = hclgevf_get_mac_addr_to_mta_index(hdev, ha->addr);
- set_bit(tbl_idx, mta_status);
- }
-
- return hclgevf_do_update_mta_status(hdev, mta_status);
-}
-
static void hclgevf_get_mac_addr(struct hnae3_handle *handle, u8 *p)
{
struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
@@ -972,7 +1080,7 @@ static int hclgevf_en_hw_strip_rxvtag(struct hnae3_handle *handle, bool enable)
1, false, NULL, 0);
}
-static void hclgevf_reset_tqp(struct hnae3_handle *handle, u16 queue_id)
+static int hclgevf_reset_tqp(struct hnae3_handle *handle, u16 queue_id)
{
struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
u8 msg_data[2];
@@ -983,10 +1091,10 @@ static void hclgevf_reset_tqp(struct hnae3_handle *handle, u16 queue_id)
/* disable vf queue before send queue reset msg to PF */
ret = hclgevf_tqp_enable(hdev, queue_id, 0, false);
if (ret)
- return;
+ return ret;
- hclgevf_send_mbx_msg(hdev, HCLGE_MBX_QUEUE_RESET, 0, msg_data,
- 2, true, NULL, 0);
+ return hclgevf_send_mbx_msg(hdev, HCLGE_MBX_QUEUE_RESET, 0, msg_data,
+ 2, true, NULL, 0);
}
static int hclgevf_notify_client(struct hclgevf_dev *hdev,
@@ -1062,6 +1170,8 @@ static int hclgevf_reset(struct hclgevf_dev *hdev)
/* bring down the nic to stop any ongoing TX/RX */
hclgevf_notify_client(hdev, HNAE3_DOWN_CLIENT);
+ rtnl_unlock();
+
/* check if VF could successfully fetch the hardware reset completion
* status from the hardware
*/
@@ -1073,12 +1183,15 @@ static int hclgevf_reset(struct hclgevf_dev *hdev)
ret);
dev_warn(&hdev->pdev->dev, "VF reset failed, disabling VF!\n");
+ rtnl_lock();
hclgevf_notify_client(hdev, HNAE3_UNINIT_CLIENT);
rtnl_unlock();
return ret;
}
+ rtnl_lock();
+
/* now, re-initialize the nic client and ae device*/
ret = hclgevf_reset_stack(hdev);
if (ret)
@@ -1106,7 +1219,8 @@ static int hclgevf_do_reset(struct hclgevf_dev *hdev)
return status;
}
-static void hclgevf_reset_event(struct hnae3_handle *handle)
+static void hclgevf_reset_event(struct pci_dev *pdev,
+ struct hnae3_handle *handle)
{
struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
@@ -1341,8 +1455,10 @@ static int hclgevf_configure(struct hclgevf_dev *hdev)
{
int ret;
+ hdev->hw.mac.media_type = HNAE3_MEDIA_TYPE_NONE;
+
/* get queue configuration from PF */
- ret = hclge_get_queue_info(hdev);
+ ret = hclgevf_get_queue_info(hdev);
if (ret)
return ret;
/* get tc configuration from PF */
@@ -1395,6 +1511,39 @@ static int hclgevf_rss_init_hw(struct hclgevf_dev *hdev)
rss_cfg->rss_size = hdev->rss_size_max;
+ if (hdev->pdev->revision >= 0x21) {
+ rss_cfg->hash_algo = HCLGEVF_RSS_HASH_ALGO_TOEPLITZ;
+ netdev_rss_key_fill(rss_cfg->rss_hash_key,
+ HCLGEVF_RSS_KEY_SIZE);
+
+ ret = hclgevf_set_rss_algo_key(hdev, rss_cfg->hash_algo,
+ rss_cfg->rss_hash_key);
+ if (ret)
+ return ret;
+
+ rss_cfg->rss_tuple_sets.ipv4_tcp_en =
+ HCLGEVF_RSS_INPUT_TUPLE_OTHER;
+ rss_cfg->rss_tuple_sets.ipv4_udp_en =
+ HCLGEVF_RSS_INPUT_TUPLE_OTHER;
+ rss_cfg->rss_tuple_sets.ipv4_sctp_en =
+ HCLGEVF_RSS_INPUT_TUPLE_SCTP;
+ rss_cfg->rss_tuple_sets.ipv4_fragment_en =
+ HCLGEVF_RSS_INPUT_TUPLE_OTHER;
+ rss_cfg->rss_tuple_sets.ipv6_tcp_en =
+ HCLGEVF_RSS_INPUT_TUPLE_OTHER;
+ rss_cfg->rss_tuple_sets.ipv6_udp_en =
+ HCLGEVF_RSS_INPUT_TUPLE_OTHER;
+ rss_cfg->rss_tuple_sets.ipv6_sctp_en =
+ HCLGEVF_RSS_INPUT_TUPLE_SCTP;
+ rss_cfg->rss_tuple_sets.ipv6_fragment_en =
+ HCLGEVF_RSS_INPUT_TUPLE_OTHER;
+
+ ret = hclgevf_set_rss_input_tuple(hdev, rss_cfg);
+ if (ret)
+ return ret;
+
+ }
+
/* Initialize RSS indirect table for each vport */
for (i = 0; i < HCLGEVF_RSS_IND_TBL_SIZE; i++)
rss_cfg->rss_indirection_tbl[i] = i % hdev->rss_size_max;
@@ -1417,12 +1566,13 @@ static int hclgevf_init_vlan_config(struct hclgevf_dev *hdev)
static int hclgevf_ae_start(struct hnae3_handle *handle)
{
+ struct hnae3_knic_private_info *kinfo = &handle->kinfo;
struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
int i, queue_id;
- for (i = 0; i < handle->kinfo.num_tqps; i++) {
+ for (i = 0; i < kinfo->num_tqps; i++) {
/* ring enable */
- queue_id = hclgevf_get_queue_id(handle->kinfo.tqp[i]);
+ queue_id = hclgevf_get_queue_id(kinfo->tqp[i]);
if (queue_id < 0) {
dev_warn(&hdev->pdev->dev,
"Get invalid queue id, ignore it\n");
@@ -1445,12 +1595,15 @@ static int hclgevf_ae_start(struct hnae3_handle *handle)
static void hclgevf_ae_stop(struct hnae3_handle *handle)
{
+ struct hnae3_knic_private_info *kinfo = &handle->kinfo;
struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
int i, queue_id;
- for (i = 0; i < hdev->num_tqps; i++) {
+ set_bit(HCLGEVF_STATE_DOWN, &hdev->state);
+
+ for (i = 0; i < kinfo->num_tqps; i++) {
/* Ring disable */
- queue_id = hclgevf_get_queue_id(handle->kinfo.tqp[i]);
+ queue_id = hclgevf_get_queue_id(kinfo->tqp[i]);
if (queue_id < 0) {
dev_warn(&hdev->pdev->dev,
"Get invalid queue id, ignore it\n");
@@ -1619,17 +1772,22 @@ static int hclgevf_init_client_instance(struct hnae3_client *client,
ret = client->ops->init_instance(&hdev->nic);
if (ret)
- return ret;
+ goto clear_nic;
+
+ hnae3_set_client_init_flag(client, ae_dev, 1);
if (hdev->roce_client && hnae3_dev_roce_supported(hdev)) {
struct hnae3_client *rc = hdev->roce_client;
ret = hclgevf_init_roce_base_info(hdev);
if (ret)
- return ret;
+ goto clear_roce;
ret = rc->ops->init_instance(&hdev->roce);
if (ret)
- return ret;
+ goto clear_roce;
+
+ hnae3_set_client_init_flag(hdev->roce_client, ae_dev,
+ 1);
}
break;
case HNAE3_CLIENT_UNIC:
@@ -1638,7 +1796,9 @@ static int hclgevf_init_client_instance(struct hnae3_client *client,
ret = client->ops->init_instance(&hdev->nic);
if (ret)
- return ret;
+ goto clear_nic;
+
+ hnae3_set_client_init_flag(client, ae_dev, 1);
break;
case HNAE3_CLIENT_ROCE:
if (hnae3_dev_roce_supported(hdev)) {
@@ -1649,15 +1809,29 @@ static int hclgevf_init_client_instance(struct hnae3_client *client,
if (hdev->roce_client && hdev->nic_client) {
ret = hclgevf_init_roce_base_info(hdev);
if (ret)
- return ret;
+ goto clear_roce;
ret = client->ops->init_instance(&hdev->roce);
if (ret)
- return ret;
+ goto clear_roce;
}
+
+ hnae3_set_client_init_flag(client, ae_dev, 1);
+ break;
+ default:
+ return -EINVAL;
}
return 0;
+
+clear_nic:
+ hdev->nic_client = NULL;
+ hdev->nic.client = NULL;
+ return ret;
+clear_roce:
+ hdev->roce_client = NULL;
+ hdev->roce.client = NULL;
+ return ret;
}
static void hclgevf_uninit_client_instance(struct hnae3_client *client,
@@ -1666,13 +1840,19 @@ static void hclgevf_uninit_client_instance(struct hnae3_client *client,
struct hclgevf_dev *hdev = ae_dev->priv;
/* un-init roce, if it exists */
- if (hdev->roce_client)
+ if (hdev->roce_client) {
hdev->roce_client->ops->uninit_instance(&hdev->roce, 0);
+ hdev->roce_client = NULL;
+ hdev->roce.client = NULL;
+ }
/* un-init nic/unic, if this was not called by roce client */
- if ((client->ops->uninit_instance) &&
- (client->type != HNAE3_CLIENT_ROCE))
+ if (client->ops->uninit_instance && hdev->nic_client &&
+ client->type != HNAE3_CLIENT_ROCE) {
client->ops->uninit_instance(&hdev->nic, 0);
+ hdev->nic_client = NULL;
+ hdev->nic.client = NULL;
+ }
}
static int hclgevf_pci_init(struct hclgevf_dev *hdev)
@@ -1839,14 +2019,6 @@ static int hclgevf_init_hdev(struct hclgevf_dev *hdev)
goto err_config;
}
- /* Initialize mta type for this VF */
- ret = hclgevf_cfg_func_mta_type(hdev);
- if (ret) {
- dev_err(&hdev->pdev->dev,
- "failed(%d) to initialize MTA type\n", ret);
- goto err_config;
- }
-
/* Initialize RSS for this VF */
ret = hclgevf_rss_init_hw(hdev);
if (ret) {
@@ -1943,11 +2115,11 @@ static void hclgevf_get_channels(struct hnae3_handle *handle,
}
static void hclgevf_get_tqps_and_rss_info(struct hnae3_handle *handle,
- u16 *free_tqps, u16 *max_rss_size)
+ u16 *alloc_tqps, u16 *max_rss_size)
{
struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
- *free_tqps = 0;
+ *alloc_tqps = hdev->num_tqps;
*max_rss_size = hdev->rss_size_max;
}
@@ -1979,6 +2151,14 @@ void hclgevf_update_speed_duplex(struct hclgevf_dev *hdev, u32 speed,
hdev->hw.mac.duplex = duplex;
}
+static void hclgevf_get_media_type(struct hnae3_handle *handle,
+ u8 *media_type)
+{
+ struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
+ if (media_type)
+ *media_type = hdev->hw.mac.media_type;
+}
+
static const struct hnae3_ae_ops hclgevf_ops = {
.init_ae_dev = hclgevf_init_ae_dev,
.uninit_ae_dev = hclgevf_uninit_ae_dev,
@@ -1998,7 +2178,6 @@ static const struct hnae3_ae_ops hclgevf_ops = {
.rm_uc_addr = hclgevf_rm_uc_addr,
.add_mc_addr = hclgevf_add_mc_addr,
.rm_mc_addr = hclgevf_rm_mc_addr,
- .update_mta_status = hclgevf_update_mta_status,
.get_stats = hclgevf_get_stats,
.update_stats = hclgevf_update_stats,
.get_strings = hclgevf_get_strings,
@@ -2007,6 +2186,8 @@ static const struct hnae3_ae_ops hclgevf_ops = {
.get_rss_indir_size = hclgevf_get_rss_indir_size,
.get_rss = hclgevf_get_rss,
.set_rss = hclgevf_set_rss,
+ .get_rss_tuple = hclgevf_get_rss_tuple,
+ .set_rss_tuple = hclgevf_set_rss_tuple,
.get_tc_size = hclgevf_get_tc_size,
.get_fw_version = hclgevf_get_fw_version,
.set_vlan_filter = hclgevf_set_vlan_filter,
@@ -2016,6 +2197,7 @@ static const struct hnae3_ae_ops hclgevf_ops = {
.get_tqps_and_rss_info = hclgevf_get_tqps_and_rss_info,
.get_status = hclgevf_get_status,
.get_ksettings_an_result = hclgevf_get_ksettings_an_result,
+ .get_media_type = hclgevf_get_media_type,
};
static struct hnae3_ae_algo ae_algovf = {
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h
index b23ba171473c..aed241e8ffab 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h
@@ -46,9 +46,13 @@
#define HCLGEVF_RSS_HASH_ALGO_MASK 0xf
#define HCLGEVF_RSS_CFG_TBL_NUM \
(HCLGEVF_RSS_IND_TBL_SIZE / HCLGEVF_RSS_CFG_TBL_SIZE)
-
-#define HCLGEVF_MTA_TBL_SIZE 4096
-#define HCLGEVF_MTA_TYPE_SEL_MAX 4
+#define HCLGEVF_RSS_INPUT_TUPLE_OTHER GENMASK(3, 0)
+#define HCLGEVF_RSS_INPUT_TUPLE_SCTP GENMASK(4, 0)
+#define HCLGEVF_D_PORT_BIT BIT(0)
+#define HCLGEVF_S_PORT_BIT BIT(1)
+#define HCLGEVF_D_IP_BIT BIT(2)
+#define HCLGEVF_S_IP_BIT BIT(3)
+#define HCLGEVF_V_TAG_BIT BIT(4)
/* states of hclgevf device & tasks */
enum hclgevf_states {
@@ -66,6 +70,7 @@ enum hclgevf_states {
#define HCLGEVF_MPF_ENBALE 1
struct hclgevf_mac {
+ u8 media_type;
u8 mac_addr[ETH_ALEN];
int link;
u8 duplex;
@@ -108,12 +113,24 @@ struct hclgevf_cfg {
u32 numa_node_map;
};
+struct hclgevf_rss_tuple_cfg {
+ u8 ipv4_tcp_en;
+ u8 ipv4_udp_en;
+ u8 ipv4_sctp_en;
+ u8 ipv4_fragment_en;
+ u8 ipv6_tcp_en;
+ u8 ipv6_udp_en;
+ u8 ipv6_sctp_en;
+ u8 ipv6_fragment_en;
+};
+
struct hclgevf_rss_cfg {
u8 rss_hash_key[HCLGEVF_RSS_KEY_SIZE]; /* user configured hash keys */
u32 hash_algo;
u32 rss_size;
u8 hw_tc_map;
u8 rss_indirection_tbl[HCLGEVF_RSS_IND_TBL_SIZE]; /* shadow table */
+ struct hclgevf_rss_tuple_cfg rss_tuple_sets;
};
struct hclgevf_misc_vector {
@@ -156,8 +173,6 @@ struct hclgevf_dev {
u16 *vector_status;
int *vector_irq;
- bool accept_mta_mc; /* whether to accept mta filter multicast */
- u8 mta_mac_sel_type;
bool mbx_event_pending;
struct hclgevf_mbx_resp_status mbx_resp; /* mailbox response */
struct hclgevf_mbx_arq_ring arq; /* mailbox async rx queue */
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h b/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h
index 0f5563f3b779..097b5502603f 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h
+++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h
@@ -58,6 +58,8 @@ enum hinic_port_cmd {
HINIC_PORT_CMD_GET_GLOBAL_QPN = 102,
+ HINIC_PORT_CMD_SET_TSO = 112,
+
HINIC_PORT_CMD_GET_CAP = 170,
};
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_qp.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_qp.c
index cb239627770f..bbf9bdd0ee3e 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_qp.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_qp.c
@@ -70,8 +70,6 @@
#define SQ_MASKED_IDX(sq, idx) ((idx) & (sq)->wq->mask)
#define RQ_MASKED_IDX(rq, idx) ((idx) & (rq)->wq->mask)
-#define TX_MAX_MSS_DEFAULT 0x3E00
-
enum sq_wqe_type {
SQ_NORMAL_WQE = 0,
};
@@ -494,33 +492,16 @@ static void sq_prepare_ctrl(struct hinic_sq_ctrl *ctrl, u16 prod_idx,
HINIC_SQ_CTRL_SET(SQ_NORMAL_WQE, DATA_FORMAT) |
HINIC_SQ_CTRL_SET(ctrl_size, LEN);
- ctrl->queue_info = HINIC_SQ_CTRL_SET(TX_MAX_MSS_DEFAULT,
- QUEUE_INFO_MSS);
+ ctrl->queue_info = HINIC_SQ_CTRL_SET(HINIC_MSS_DEFAULT,
+ QUEUE_INFO_MSS) |
+ HINIC_SQ_CTRL_SET(1, QUEUE_INFO_UC);
}
static void sq_prepare_task(struct hinic_sq_task *task)
{
- task->pkt_info0 =
- HINIC_SQ_TASK_INFO0_SET(0, L2HDR_LEN) |
- HINIC_SQ_TASK_INFO0_SET(HINIC_L4_OFF_DISABLE, L4_OFFLOAD) |
- HINIC_SQ_TASK_INFO0_SET(HINIC_OUTER_L3TYPE_UNKNOWN,
- INNER_L3TYPE) |
- HINIC_SQ_TASK_INFO0_SET(HINIC_VLAN_OFF_DISABLE,
- VLAN_OFFLOAD) |
- HINIC_SQ_TASK_INFO0_SET(HINIC_PKT_NOT_PARSED, PARSE_FLAG);
-
- task->pkt_info1 =
- HINIC_SQ_TASK_INFO1_SET(HINIC_MEDIA_UNKNOWN, MEDIA_TYPE) |
- HINIC_SQ_TASK_INFO1_SET(0, INNER_L4_LEN) |
- HINIC_SQ_TASK_INFO1_SET(0, INNER_L3_LEN);
-
- task->pkt_info2 =
- HINIC_SQ_TASK_INFO2_SET(0, TUNNEL_L4_LEN) |
- HINIC_SQ_TASK_INFO2_SET(0, OUTER_L3_LEN) |
- HINIC_SQ_TASK_INFO2_SET(HINIC_TUNNEL_L4TYPE_UNKNOWN,
- TUNNEL_L4TYPE) |
- HINIC_SQ_TASK_INFO2_SET(HINIC_OUTER_L3TYPE_UNKNOWN,
- OUTER_L3TYPE);
+ task->pkt_info0 = 0;
+ task->pkt_info1 = 0;
+ task->pkt_info2 = 0;
task->ufo_v6_identify = 0;
@@ -529,6 +510,86 @@ static void sq_prepare_task(struct hinic_sq_task *task)
task->zero_pad = 0;
}
+void hinic_task_set_l2hdr(struct hinic_sq_task *task, u32 len)
+{
+ task->pkt_info0 |= HINIC_SQ_TASK_INFO0_SET(len, L2HDR_LEN);
+}
+
+void hinic_task_set_outter_l3(struct hinic_sq_task *task,
+ enum hinic_l3_offload_type l3_type,
+ u32 network_len)
+{
+ task->pkt_info2 |= HINIC_SQ_TASK_INFO2_SET(l3_type, OUTER_L3TYPE) |
+ HINIC_SQ_TASK_INFO2_SET(network_len, OUTER_L3LEN);
+}
+
+void hinic_task_set_inner_l3(struct hinic_sq_task *task,
+ enum hinic_l3_offload_type l3_type,
+ u32 network_len)
+{
+ task->pkt_info0 |= HINIC_SQ_TASK_INFO0_SET(l3_type, INNER_L3TYPE);
+ task->pkt_info1 |= HINIC_SQ_TASK_INFO1_SET(network_len, INNER_L3LEN);
+}
+
+void hinic_task_set_tunnel_l4(struct hinic_sq_task *task,
+ enum hinic_l4_tunnel_type l4_type,
+ u32 tunnel_len)
+{
+ task->pkt_info2 |= HINIC_SQ_TASK_INFO2_SET(l4_type, TUNNEL_L4TYPE) |
+ HINIC_SQ_TASK_INFO2_SET(tunnel_len, TUNNEL_L4LEN);
+}
+
+void hinic_set_cs_inner_l4(struct hinic_sq_task *task, u32 *queue_info,
+ enum hinic_l4_offload_type l4_offload,
+ u32 l4_len, u32 offset)
+{
+ u32 tcp_udp_cs = 0, sctp = 0;
+ u32 mss = HINIC_MSS_DEFAULT;
+
+ if (l4_offload == TCP_OFFLOAD_ENABLE ||
+ l4_offload == UDP_OFFLOAD_ENABLE)
+ tcp_udp_cs = 1;
+ else if (l4_offload == SCTP_OFFLOAD_ENABLE)
+ sctp = 1;
+
+ task->pkt_info0 |= HINIC_SQ_TASK_INFO0_SET(l4_offload, L4_OFFLOAD);
+ task->pkt_info1 |= HINIC_SQ_TASK_INFO1_SET(l4_len, INNER_L4LEN);
+
+ *queue_info |= HINIC_SQ_CTRL_SET(offset, QUEUE_INFO_PLDOFF) |
+ HINIC_SQ_CTRL_SET(tcp_udp_cs, QUEUE_INFO_TCPUDP_CS) |
+ HINIC_SQ_CTRL_SET(sctp, QUEUE_INFO_SCTP);
+
+ *queue_info = HINIC_SQ_CTRL_CLEAR(*queue_info, QUEUE_INFO_MSS);
+ *queue_info |= HINIC_SQ_CTRL_SET(mss, QUEUE_INFO_MSS);
+}
+
+void hinic_set_tso_inner_l4(struct hinic_sq_task *task, u32 *queue_info,
+ enum hinic_l4_offload_type l4_offload,
+ u32 l4_len, u32 offset, u32 ip_ident, u32 mss)
+{
+ u32 tso = 0, ufo = 0;
+
+ if (l4_offload == TCP_OFFLOAD_ENABLE)
+ tso = 1;
+ else if (l4_offload == UDP_OFFLOAD_ENABLE)
+ ufo = 1;
+
+ task->ufo_v6_identify = ip_ident;
+
+ task->pkt_info0 |= HINIC_SQ_TASK_INFO0_SET(l4_offload, L4_OFFLOAD);
+ task->pkt_info0 |= HINIC_SQ_TASK_INFO0_SET(tso || ufo, TSO_FLAG);
+ task->pkt_info1 |= HINIC_SQ_TASK_INFO1_SET(l4_len, INNER_L4LEN);
+
+ *queue_info |= HINIC_SQ_CTRL_SET(offset, QUEUE_INFO_PLDOFF) |
+ HINIC_SQ_CTRL_SET(tso, QUEUE_INFO_TSO) |
+ HINIC_SQ_CTRL_SET(ufo, QUEUE_INFO_UFO) |
+ HINIC_SQ_CTRL_SET(!!l4_offload, QUEUE_INFO_TCPUDP_CS);
+
+ /* set MSS value */
+ *queue_info = HINIC_SQ_CTRL_CLEAR(*queue_info, QUEUE_INFO_MSS);
+ *queue_info |= HINIC_SQ_CTRL_SET(mss, QUEUE_INFO_MSS);
+}
+
/**
* hinic_sq_prepare_wqe - prepare wqe before insert to the queue
* @sq: send queue
@@ -613,6 +674,16 @@ struct hinic_sq_wqe *hinic_sq_get_wqe(struct hinic_sq *sq,
}
/**
+ * hinic_sq_return_wqe - return the wqe to the sq
+ * @sq: send queue
+ * @wqe_size: the size of the wqe
+ **/
+void hinic_sq_return_wqe(struct hinic_sq *sq, unsigned int wqe_size)
+{
+ hinic_return_wqe(sq->wq, wqe_size);
+}
+
+/**
* hinic_sq_write_wqe - write the wqe to the sq
* @sq: send queue
* @prod_idx: pi of the wqe
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_qp.h b/drivers/net/ethernet/huawei/hinic/hinic_hw_qp.h
index 6c84f83ec283..038522e202b6 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_qp.h
+++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_qp.h
@@ -149,6 +149,31 @@ int hinic_get_sq_free_wqebbs(struct hinic_sq *sq);
int hinic_get_rq_free_wqebbs(struct hinic_rq *rq);
+void hinic_task_set_l2hdr(struct hinic_sq_task *task, u32 len);
+
+void hinic_task_set_outter_l3(struct hinic_sq_task *task,
+ enum hinic_l3_offload_type l3_type,
+ u32 network_len);
+
+void hinic_task_set_inner_l3(struct hinic_sq_task *task,
+ enum hinic_l3_offload_type l3_type,
+ u32 network_len);
+
+void hinic_task_set_tunnel_l4(struct hinic_sq_task *task,
+ enum hinic_l4_tunnel_type l4_type,
+ u32 tunnel_len);
+
+void hinic_set_cs_inner_l4(struct hinic_sq_task *task,
+ u32 *queue_info,
+ enum hinic_l4_offload_type l4_offload,
+ u32 l4_len, u32 offset);
+
+void hinic_set_tso_inner_l4(struct hinic_sq_task *task,
+ u32 *queue_info,
+ enum hinic_l4_offload_type l4_offload,
+ u32 l4_len,
+ u32 offset, u32 ip_ident, u32 mss);
+
void hinic_sq_prepare_wqe(struct hinic_sq *sq, u16 prod_idx,
struct hinic_sq_wqe *wqe, struct hinic_sge *sges,
int nr_sges);
@@ -159,6 +184,8 @@ void hinic_sq_write_db(struct hinic_sq *sq, u16 prod_idx, unsigned int wqe_size,
struct hinic_sq_wqe *hinic_sq_get_wqe(struct hinic_sq *sq,
unsigned int wqe_size, u16 *prod_idx);
+void hinic_sq_return_wqe(struct hinic_sq *sq, unsigned int wqe_size);
+
void hinic_sq_write_wqe(struct hinic_sq *sq, u16 prod_idx,
struct hinic_sq_wqe *wqe, struct sk_buff *skb,
unsigned int wqe_size);
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_wq.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_wq.c
index 3e3181c089bd..f92f1bf3901a 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_wq.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_wq.c
@@ -775,6 +775,20 @@ struct hinic_hw_wqe *hinic_get_wqe(struct hinic_wq *wq, unsigned int wqe_size,
}
/**
+ * hinic_return_wqe - return the wqe when transmit failed
+ * @wq: wq to return wqe
+ * @wqe_size: wqe size
+ **/
+void hinic_return_wqe(struct hinic_wq *wq, unsigned int wqe_size)
+{
+ int num_wqebbs = ALIGN(wqe_size, wq->wqebb_size) / wq->wqebb_size;
+
+ atomic_sub(num_wqebbs, &wq->prod_idx);
+
+ atomic_add(num_wqebbs, &wq->delta);
+}
+
+/**
* hinic_put_wqe - return the wqe place to use for a new wqe
* @wq: wq to return wqe
* @wqe_size: wqe size
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_wq.h b/drivers/net/ethernet/huawei/hinic/hinic_hw_wq.h
index 9c030a0f035e..9b66545ba563 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_wq.h
+++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_wq.h
@@ -104,6 +104,8 @@ void hinic_wq_free(struct hinic_wqs *wqs, struct hinic_wq *wq);
struct hinic_hw_wqe *hinic_get_wqe(struct hinic_wq *wq, unsigned int wqe_size,
u16 *prod_idx);
+void hinic_return_wqe(struct hinic_wq *wq, unsigned int wqe_size);
+
void hinic_put_wqe(struct hinic_wq *wq, unsigned int wqe_size);
struct hinic_hw_wqe *hinic_read_wqe(struct hinic_wq *wq, unsigned int wqe_size,
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_wqe.h b/drivers/net/ethernet/huawei/hinic/hinic_hw_wqe.h
index bc73485483c5..9754d6ed5f4a 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_wqe.h
+++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_wqe.h
@@ -62,19 +62,33 @@
(((val) >> HINIC_CMDQ_WQE_HEADER_##member##_SHIFT) \
& HINIC_CMDQ_WQE_HEADER_##member##_MASK)
-#define HINIC_SQ_CTRL_BUFDESC_SECT_LEN_SHIFT 0
-#define HINIC_SQ_CTRL_TASKSECT_LEN_SHIFT 16
-#define HINIC_SQ_CTRL_DATA_FORMAT_SHIFT 22
-#define HINIC_SQ_CTRL_LEN_SHIFT 29
-
-#define HINIC_SQ_CTRL_BUFDESC_SECT_LEN_MASK 0xFF
-#define HINIC_SQ_CTRL_TASKSECT_LEN_MASK 0x1F
-#define HINIC_SQ_CTRL_DATA_FORMAT_MASK 0x1
-#define HINIC_SQ_CTRL_LEN_MASK 0x3
-
-#define HINIC_SQ_CTRL_QUEUE_INFO_MSS_SHIFT 13
-
-#define HINIC_SQ_CTRL_QUEUE_INFO_MSS_MASK 0x3FFF
+#define HINIC_SQ_CTRL_BUFDESC_SECT_LEN_SHIFT 0
+#define HINIC_SQ_CTRL_TASKSECT_LEN_SHIFT 16
+#define HINIC_SQ_CTRL_DATA_FORMAT_SHIFT 22
+#define HINIC_SQ_CTRL_LEN_SHIFT 29
+
+#define HINIC_SQ_CTRL_BUFDESC_SECT_LEN_MASK 0xFF
+#define HINIC_SQ_CTRL_TASKSECT_LEN_MASK 0x1F
+#define HINIC_SQ_CTRL_DATA_FORMAT_MASK 0x1
+#define HINIC_SQ_CTRL_LEN_MASK 0x3
+
+#define HINIC_SQ_CTRL_QUEUE_INFO_PLDOFF_SHIFT 2
+#define HINIC_SQ_CTRL_QUEUE_INFO_UFO_SHIFT 10
+#define HINIC_SQ_CTRL_QUEUE_INFO_TSO_SHIFT 11
+#define HINIC_SQ_CTRL_QUEUE_INFO_TCPUDP_CS_SHIFT 12
+#define HINIC_SQ_CTRL_QUEUE_INFO_MSS_SHIFT 13
+#define HINIC_SQ_CTRL_QUEUE_INFO_SCTP_SHIFT 27
+#define HINIC_SQ_CTRL_QUEUE_INFO_UC_SHIFT 28
+#define HINIC_SQ_CTRL_QUEUE_INFO_PRI_SHIFT 29
+
+#define HINIC_SQ_CTRL_QUEUE_INFO_PLDOFF_MASK 0xFF
+#define HINIC_SQ_CTRL_QUEUE_INFO_UFO_MASK 0x1
+#define HINIC_SQ_CTRL_QUEUE_INFO_TSO_MASK 0x1
+#define HINIC_SQ_CTRL_QUEUE_INFO_TCPUDP_CS_MASK 0x1
+#define HINIC_SQ_CTRL_QUEUE_INFO_MSS_MASK 0x3FFF
+#define HINIC_SQ_CTRL_QUEUE_INFO_SCTP_MASK 0x1
+#define HINIC_SQ_CTRL_QUEUE_INFO_UC_MASK 0x1
+#define HINIC_SQ_CTRL_QUEUE_INFO_PRI_MASK 0x7
#define HINIC_SQ_CTRL_SET(val, member) \
(((u32)(val) & HINIC_SQ_CTRL_##member##_MASK) \
@@ -84,6 +98,10 @@
(((val) >> HINIC_SQ_CTRL_##member##_SHIFT) \
& HINIC_SQ_CTRL_##member##_MASK)
+#define HINIC_SQ_CTRL_CLEAR(val, member) \
+ ((u32)(val) & (~(HINIC_SQ_CTRL_##member##_MASK \
+ << HINIC_SQ_CTRL_##member##_SHIFT)))
+
#define HINIC_SQ_TASK_INFO0_L2HDR_LEN_SHIFT 0
#define HINIC_SQ_TASK_INFO0_L4_OFFLOAD_SHIFT 8
#define HINIC_SQ_TASK_INFO0_INNER_L3TYPE_SHIFT 10
@@ -108,28 +126,28 @@
/* 8 bits reserved */
#define HINIC_SQ_TASK_INFO1_MEDIA_TYPE_SHIFT 8
-#define HINIC_SQ_TASK_INFO1_INNER_L4_LEN_SHIFT 16
-#define HINIC_SQ_TASK_INFO1_INNER_L3_LEN_SHIFT 24
+#define HINIC_SQ_TASK_INFO1_INNER_L4LEN_SHIFT 16
+#define HINIC_SQ_TASK_INFO1_INNER_L3LEN_SHIFT 24
/* 8 bits reserved */
#define HINIC_SQ_TASK_INFO1_MEDIA_TYPE_MASK 0xFF
-#define HINIC_SQ_TASK_INFO1_INNER_L4_LEN_MASK 0xFF
-#define HINIC_SQ_TASK_INFO1_INNER_L3_LEN_MASK 0xFF
+#define HINIC_SQ_TASK_INFO1_INNER_L4LEN_MASK 0xFF
+#define HINIC_SQ_TASK_INFO1_INNER_L3LEN_MASK 0xFF
#define HINIC_SQ_TASK_INFO1_SET(val, member) \
(((u32)(val) & HINIC_SQ_TASK_INFO1_##member##_MASK) << \
HINIC_SQ_TASK_INFO1_##member##_SHIFT)
-#define HINIC_SQ_TASK_INFO2_TUNNEL_L4_LEN_SHIFT 0
-#define HINIC_SQ_TASK_INFO2_OUTER_L3_LEN_SHIFT 12
-#define HINIC_SQ_TASK_INFO2_TUNNEL_L4TYPE_SHIFT 19
+#define HINIC_SQ_TASK_INFO2_TUNNEL_L4LEN_SHIFT 0
+#define HINIC_SQ_TASK_INFO2_OUTER_L3LEN_SHIFT 8
+#define HINIC_SQ_TASK_INFO2_TUNNEL_L4TYPE_SHIFT 16
/* 1 bit reserved */
-#define HINIC_SQ_TASK_INFO2_OUTER_L3TYPE_SHIFT 22
+#define HINIC_SQ_TASK_INFO2_OUTER_L3TYPE_SHIFT 24
/* 8 bits reserved */
-#define HINIC_SQ_TASK_INFO2_TUNNEL_L4_LEN_MASK 0xFFF
-#define HINIC_SQ_TASK_INFO2_OUTER_L3_LEN_MASK 0x7F
-#define HINIC_SQ_TASK_INFO2_TUNNEL_L4TYPE_MASK 0x3
+#define HINIC_SQ_TASK_INFO2_TUNNEL_L4LEN_MASK 0xFF
+#define HINIC_SQ_TASK_INFO2_OUTER_L3LEN_MASK 0xFF
+#define HINIC_SQ_TASK_INFO2_TUNNEL_L4TYPE_MASK 0x7
/* 1 bit reserved */
#define HINIC_SQ_TASK_INFO2_OUTER_L3TYPE_MASK 0x3
/* 8 bits reserved */
@@ -187,12 +205,15 @@
sizeof(struct hinic_sq_task) + \
(nr_sges) * sizeof(struct hinic_sq_bufdesc))
-#define HINIC_SCMD_DATA_LEN 16
+#define HINIC_SCMD_DATA_LEN 16
+
+#define HINIC_MAX_SQ_BUFDESCS 17
-#define HINIC_MAX_SQ_BUFDESCS 17
+#define HINIC_SQ_WQE_MAX_SIZE 320
+#define HINIC_RQ_WQE_SIZE 32
-#define HINIC_SQ_WQE_MAX_SIZE 320
-#define HINIC_RQ_WQE_SIZE 32
+#define HINIC_MSS_DEFAULT 0x3E00
+#define HINIC_MSS_MIN 0x50
enum hinic_l4offload_type {
HINIC_L4_OFF_DISABLE = 0,
@@ -211,6 +232,26 @@ enum hinic_pkt_parsed {
HINIC_PKT_PARSED = 1,
};
+enum hinic_l3_offload_type {
+ L3TYPE_UNKNOWN = 0,
+ IPV6_PKT = 1,
+ IPV4_PKT_NO_CHKSUM_OFFLOAD = 2,
+ IPV4_PKT_WITH_CHKSUM_OFFLOAD = 3,
+};
+
+enum hinic_l4_offload_type {
+ OFFLOAD_DISABLE = 0,
+ TCP_OFFLOAD_ENABLE = 1,
+ SCTP_OFFLOAD_ENABLE = 2,
+ UDP_OFFLOAD_ENABLE = 3,
+};
+
+enum hinic_l4_tunnel_type {
+ NOT_TUNNEL,
+ TUNNEL_UDP_NO_CSUM,
+ TUNNEL_UDP_CSUM,
+};
+
enum hinic_outer_l3type {
HINIC_OUTER_L3TYPE_UNKNOWN = 0,
HINIC_OUTER_L3TYPE_IPV6 = 1,
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_main.c b/drivers/net/ethernet/huawei/hinic/hinic_main.c
index 09e9da10b786..fdf2bdb6b0d0 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_main.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_main.c
@@ -789,23 +789,6 @@ static void hinic_get_stats64(struct net_device *netdev,
stats->tx_errors = nic_tx_stats->tx_dropped;
}
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void hinic_netpoll(struct net_device *netdev)
-{
- struct hinic_dev *nic_dev = netdev_priv(netdev);
- int i, num_qps;
-
- num_qps = hinic_hwdev_num_qps(nic_dev->hwdev);
- for (i = 0; i < num_qps; i++) {
- struct hinic_txq *txq = &nic_dev->txqs[i];
- struct hinic_rxq *rxq = &nic_dev->rxqs[i];
-
- napi_schedule(&txq->napi);
- napi_schedule(&rxq->napi);
- }
-}
-#endif
-
static const struct net_device_ops hinic_netdev_ops = {
.ndo_open = hinic_open,
.ndo_stop = hinic_close,
@@ -818,14 +801,12 @@ static const struct net_device_ops hinic_netdev_ops = {
.ndo_start_xmit = hinic_xmit_frame,
.ndo_tx_timeout = hinic_tx_timeout,
.ndo_get_stats64 = hinic_get_stats64,
-#ifdef CONFIG_NET_POLL_CONTROLLER
- .ndo_poll_controller = hinic_netpoll,
-#endif
};
static void netdev_features_init(struct net_device *netdev)
{
- netdev->hw_features = NETIF_F_SG | NETIF_F_HIGHDMA;
+ netdev->hw_features = NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_IP_CSUM |
+ NETIF_F_IPV6_CSUM | NETIF_F_TSO | NETIF_F_TSO6;
netdev->vlan_features = netdev->hw_features;
@@ -883,6 +864,20 @@ static void link_status_event_handler(void *handle, void *buf_in, u16 in_size,
*out_size = sizeof(*ret_link_status);
}
+static int set_features(struct hinic_dev *nic_dev,
+ netdev_features_t pre_features,
+ netdev_features_t features, bool force_change)
+{
+ netdev_features_t changed = force_change ? ~0 : pre_features ^ features;
+ int err = 0;
+
+ if (changed & NETIF_F_TSO)
+ err = hinic_port_set_tso(nic_dev, (features & NETIF_F_TSO) ?
+ HINIC_TSO_ENABLE : HINIC_TSO_DISABLE);
+
+ return err;
+}
+
/**
* nic_dev_init - Initialize the NIC device
* @pdev: the NIC pci device
@@ -983,7 +978,12 @@ static int nic_dev_init(struct pci_dev *pdev)
hinic_hwdev_cb_register(nic_dev->hwdev, HINIC_MGMT_MSG_CMD_LINK_STATUS,
nic_dev, link_status_event_handler);
+ err = set_features(nic_dev, 0, nic_dev->netdev->features, true);
+ if (err)
+ goto err_set_features;
+
SET_NETDEV_DEV(netdev, &pdev->dev);
+
err = register_netdev(netdev);
if (err) {
dev_err(&pdev->dev, "Failed to register netdev\n");
@@ -993,6 +993,7 @@ static int nic_dev_init(struct pci_dev *pdev)
return 0;
err_reg_netdev:
+err_set_features:
hinic_hwdev_cb_unregister(nic_dev->hwdev,
HINIC_MGMT_MSG_CMD_LINK_STATUS);
cancel_work_sync(&rx_mode_work->work);
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_port.c b/drivers/net/ethernet/huawei/hinic/hinic_port.c
index 4d4e3f05fb5f..7575a7d3bd9f 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_port.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_port.c
@@ -377,3 +377,35 @@ int hinic_port_get_cap(struct hinic_dev *nic_dev,
return 0;
}
+
+/**
+ * hinic_port_set_tso - set port tso configuration
+ * @nic_dev: nic device
+ * @state: the tso state to set
+ *
+ * Return 0 - Success, negative - Failure
+ **/
+int hinic_port_set_tso(struct hinic_dev *nic_dev, enum hinic_tso_state state)
+{
+ struct hinic_hwdev *hwdev = nic_dev->hwdev;
+ struct hinic_hwif *hwif = hwdev->hwif;
+ struct hinic_tso_config tso_cfg = {0};
+ struct pci_dev *pdev = hwif->pdev;
+ u16 out_size;
+ int err;
+
+ tso_cfg.func_id = HINIC_HWIF_FUNC_IDX(hwif);
+ tso_cfg.tso_en = state;
+
+ err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_SET_TSO,
+ &tso_cfg, sizeof(tso_cfg),
+ &tso_cfg, &out_size);
+ if (err || out_size != sizeof(tso_cfg) || tso_cfg.status) {
+ dev_err(&pdev->dev,
+ "Failed to set port tso, ret = %d\n",
+ tso_cfg.status);
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_port.h b/drivers/net/ethernet/huawei/hinic/hinic_port.h
index 9404365195dd..f6e3220fe28f 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_port.h
+++ b/drivers/net/ethernet/huawei/hinic/hinic_port.h
@@ -72,6 +72,11 @@ enum hinic_speed {
HINIC_SPEED_UNKNOWN = 0xFF,
};
+enum hinic_tso_state {
+ HINIC_TSO_DISABLE = 0,
+ HINIC_TSO_ENABLE = 1,
+};
+
struct hinic_port_mac_cmd {
u8 status;
u8 version;
@@ -167,6 +172,17 @@ struct hinic_port_cap {
u8 rsvd2[3];
};
+struct hinic_tso_config {
+ u8 status;
+ u8 version;
+ u8 rsvd0[6];
+
+ u16 func_id;
+ u16 rsvd1;
+ u8 tso_en;
+ u8 resv2[3];
+};
+
int hinic_port_add_mac(struct hinic_dev *nic_dev, const u8 *addr,
u16 vlan_id);
@@ -195,4 +211,6 @@ int hinic_port_set_func_state(struct hinic_dev *nic_dev,
int hinic_port_get_cap(struct hinic_dev *nic_dev,
struct hinic_port_cap *port_cap);
+int hinic_port_set_tso(struct hinic_dev *nic_dev, enum hinic_tso_state state);
+
#endif
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_tx.c b/drivers/net/ethernet/huawei/hinic/hinic_tx.c
index c5fca0356c9c..11e73e67358d 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_tx.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_tx.c
@@ -26,6 +26,13 @@
#include <linux/skbuff.h>
#include <linux/smp.h>
#include <asm/byteorder.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/sctp.h>
+#include <linux/ipv6.h>
+#include <net/ipv6.h>
+#include <net/checksum.h>
+#include <net/ip6_checksum.h>
#include "hinic_common.h"
#include "hinic_hw_if.h"
@@ -45,9 +52,31 @@
#define CI_UPDATE_NO_PENDING 0
#define CI_UPDATE_NO_COALESC 0
-#define HW_CONS_IDX(sq) be16_to_cpu(*(u16 *)((sq)->hw_ci_addr))
+#define HW_CONS_IDX(sq) be16_to_cpu(*(u16 *)((sq)->hw_ci_addr))
-#define MIN_SKB_LEN 64
+#define MIN_SKB_LEN 17
+
+#define MAX_PAYLOAD_OFFSET 221
+#define TRANSPORT_OFFSET(l4_hdr, skb) ((u32)((l4_hdr) - (skb)->data))
+
+union hinic_l3 {
+ struct iphdr *v4;
+ struct ipv6hdr *v6;
+ unsigned char *hdr;
+};
+
+union hinic_l4 {
+ struct tcphdr *tcp;
+ struct udphdr *udp;
+ unsigned char *hdr;
+};
+
+enum hinic_offload_type {
+ TX_OFFLOAD_TSO = BIT(0),
+ TX_OFFLOAD_CSUM = BIT(1),
+ TX_OFFLOAD_VLAN = BIT(2),
+ TX_OFFLOAD_INVALID = BIT(3),
+};
/**
* hinic_txq_clean_stats - Clean the statistics of specific queue
@@ -175,18 +204,263 @@ static void tx_unmap_skb(struct hinic_dev *nic_dev, struct sk_buff *skb,
DMA_TO_DEVICE);
}
+static void get_inner_l3_l4_type(struct sk_buff *skb, union hinic_l3 *ip,
+ union hinic_l4 *l4,
+ enum hinic_offload_type offload_type,
+ enum hinic_l3_offload_type *l3_type,
+ u8 *l4_proto)
+{
+ u8 *exthdr;
+
+ if (ip->v4->version == 4) {
+ *l3_type = (offload_type == TX_OFFLOAD_CSUM) ?
+ IPV4_PKT_NO_CHKSUM_OFFLOAD :
+ IPV4_PKT_WITH_CHKSUM_OFFLOAD;
+ *l4_proto = ip->v4->protocol;
+ } else if (ip->v4->version == 6) {
+ *l3_type = IPV6_PKT;
+ exthdr = ip->hdr + sizeof(*ip->v6);
+ *l4_proto = ip->v6->nexthdr;
+ if (exthdr != l4->hdr) {
+ int start = exthdr - skb->data;
+ __be16 frag_off;
+
+ ipv6_skip_exthdr(skb, start, l4_proto, &frag_off);
+ }
+ } else {
+ *l3_type = L3TYPE_UNKNOWN;
+ *l4_proto = 0;
+ }
+}
+
+static void get_inner_l4_info(struct sk_buff *skb, union hinic_l4 *l4,
+ enum hinic_offload_type offload_type, u8 l4_proto,
+ enum hinic_l4_offload_type *l4_offload,
+ u32 *l4_len, u32 *offset)
+{
+ *l4_offload = OFFLOAD_DISABLE;
+ *offset = 0;
+ *l4_len = 0;
+
+ switch (l4_proto) {
+ case IPPROTO_TCP:
+ *l4_offload = TCP_OFFLOAD_ENABLE;
+ /* doff in unit of 4B */
+ *l4_len = l4->tcp->doff * 4;
+ *offset = *l4_len + TRANSPORT_OFFSET(l4->hdr, skb);
+ break;
+
+ case IPPROTO_UDP:
+ *l4_offload = UDP_OFFLOAD_ENABLE;
+ *l4_len = sizeof(struct udphdr);
+ *offset = TRANSPORT_OFFSET(l4->hdr, skb);
+ break;
+
+ case IPPROTO_SCTP:
+ /* only csum offload support sctp */
+ if (offload_type != TX_OFFLOAD_CSUM)
+ break;
+
+ *l4_offload = SCTP_OFFLOAD_ENABLE;
+ *l4_len = sizeof(struct sctphdr);
+ *offset = TRANSPORT_OFFSET(l4->hdr, skb);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static __sum16 csum_magic(union hinic_l3 *ip, unsigned short proto)
+{
+ return (ip->v4->version == 4) ?
+ csum_tcpudp_magic(ip->v4->saddr, ip->v4->daddr, 0, proto, 0) :
+ csum_ipv6_magic(&ip->v6->saddr, &ip->v6->daddr, 0, proto, 0);
+}
+
+static int offload_tso(struct hinic_sq_task *task, u32 *queue_info,
+ struct sk_buff *skb)
+{
+ u32 offset, l4_len, ip_identify, network_hdr_len;
+ enum hinic_l3_offload_type l3_offload;
+ enum hinic_l4_offload_type l4_offload;
+ union hinic_l3 ip;
+ union hinic_l4 l4;
+ u8 l4_proto;
+
+ if (!skb_is_gso(skb))
+ return 0;
+
+ if (skb_cow_head(skb, 0) < 0)
+ return -EPROTONOSUPPORT;
+
+ if (skb->encapsulation) {
+ u32 gso_type = skb_shinfo(skb)->gso_type;
+ u32 tunnel_type = 0;
+ u32 l4_tunnel_len;
+
+ ip.hdr = skb_network_header(skb);
+ l4.hdr = skb_transport_header(skb);
+ network_hdr_len = skb_inner_network_header_len(skb);
+
+ if (ip.v4->version == 4) {
+ ip.v4->tot_len = 0;
+ l3_offload = IPV4_PKT_WITH_CHKSUM_OFFLOAD;
+ } else if (ip.v4->version == 6) {
+ l3_offload = IPV6_PKT;
+ } else {
+ l3_offload = 0;
+ }
+
+ hinic_task_set_outter_l3(task, l3_offload,
+ skb_network_header_len(skb));
+
+ if (gso_type & SKB_GSO_UDP_TUNNEL_CSUM) {
+ l4.udp->check = ~csum_magic(&ip, IPPROTO_UDP);
+ tunnel_type = TUNNEL_UDP_CSUM;
+ } else if (gso_type & SKB_GSO_UDP_TUNNEL) {
+ tunnel_type = TUNNEL_UDP_NO_CSUM;
+ }
+
+ l4_tunnel_len = skb_inner_network_offset(skb) -
+ skb_transport_offset(skb);
+ hinic_task_set_tunnel_l4(task, tunnel_type, l4_tunnel_len);
+
+ ip.hdr = skb_inner_network_header(skb);
+ l4.hdr = skb_inner_transport_header(skb);
+ } else {
+ ip.hdr = skb_network_header(skb);
+ l4.hdr = skb_transport_header(skb);
+ network_hdr_len = skb_network_header_len(skb);
+ }
+
+ /* initialize inner IP header fields */
+ if (ip.v4->version == 4)
+ ip.v4->tot_len = 0;
+ else
+ ip.v6->payload_len = 0;
+
+ get_inner_l3_l4_type(skb, &ip, &l4, TX_OFFLOAD_TSO, &l3_offload,
+ &l4_proto);
+
+ hinic_task_set_inner_l3(task, l3_offload, network_hdr_len);
+
+ ip_identify = 0;
+ if (l4_proto == IPPROTO_TCP)
+ l4.tcp->check = ~csum_magic(&ip, IPPROTO_TCP);
+
+ get_inner_l4_info(skb, &l4, TX_OFFLOAD_TSO, l4_proto, &l4_offload,
+ &l4_len, &offset);
+
+ hinic_set_tso_inner_l4(task, queue_info, l4_offload, l4_len, offset,
+ ip_identify, skb_shinfo(skb)->gso_size);
+
+ return 1;
+}
+
+static int offload_csum(struct hinic_sq_task *task, u32 *queue_info,
+ struct sk_buff *skb)
+{
+ enum hinic_l4_offload_type l4_offload;
+ u32 offset, l4_len, network_hdr_len;
+ enum hinic_l3_offload_type l3_type;
+ union hinic_l3 ip;
+ union hinic_l4 l4;
+ u8 l4_proto;
+
+ if (skb->ip_summed != CHECKSUM_PARTIAL)
+ return 0;
+
+ if (skb->encapsulation) {
+ u32 l4_tunnel_len;
+
+ ip.hdr = skb_network_header(skb);
+
+ if (ip.v4->version == 4)
+ l3_type = IPV4_PKT_NO_CHKSUM_OFFLOAD;
+ else if (ip.v4->version == 6)
+ l3_type = IPV6_PKT;
+ else
+ l3_type = L3TYPE_UNKNOWN;
+
+ hinic_task_set_outter_l3(task, l3_type,
+ skb_network_header_len(skb));
+
+ l4_tunnel_len = skb_inner_network_offset(skb) -
+ skb_transport_offset(skb);
+
+ hinic_task_set_tunnel_l4(task, TUNNEL_UDP_NO_CSUM,
+ l4_tunnel_len);
+
+ ip.hdr = skb_inner_network_header(skb);
+ l4.hdr = skb_inner_transport_header(skb);
+ network_hdr_len = skb_inner_network_header_len(skb);
+ } else {
+ ip.hdr = skb_network_header(skb);
+ l4.hdr = skb_transport_header(skb);
+ network_hdr_len = skb_network_header_len(skb);
+ }
+
+ get_inner_l3_l4_type(skb, &ip, &l4, TX_OFFLOAD_CSUM, &l3_type,
+ &l4_proto);
+
+ hinic_task_set_inner_l3(task, l3_type, network_hdr_len);
+
+ get_inner_l4_info(skb, &l4, TX_OFFLOAD_CSUM, l4_proto, &l4_offload,
+ &l4_len, &offset);
+
+ hinic_set_cs_inner_l4(task, queue_info, l4_offload, l4_len, offset);
+
+ return 1;
+}
+
+static int hinic_tx_offload(struct sk_buff *skb, struct hinic_sq_task *task,
+ u32 *queue_info)
+{
+ enum hinic_offload_type offload = 0;
+ int enabled;
+
+ enabled = offload_tso(task, queue_info, skb);
+ if (enabled > 0) {
+ offload |= TX_OFFLOAD_TSO;
+ } else if (enabled == 0) {
+ enabled = offload_csum(task, queue_info, skb);
+ if (enabled)
+ offload |= TX_OFFLOAD_CSUM;
+ } else {
+ return -EPROTONOSUPPORT;
+ }
+
+ if (offload)
+ hinic_task_set_l2hdr(task, skb_network_offset(skb));
+
+ /* payload offset should not more than 221 */
+ if (HINIC_SQ_CTRL_GET(*queue_info, QUEUE_INFO_PLDOFF) >
+ MAX_PAYLOAD_OFFSET) {
+ return -EPROTONOSUPPORT;
+ }
+
+ /* mss should not less than 80 */
+ if (HINIC_SQ_CTRL_GET(*queue_info, QUEUE_INFO_MSS) < HINIC_MSS_MIN) {
+ *queue_info = HINIC_SQ_CTRL_CLEAR(*queue_info, QUEUE_INFO_MSS);
+ *queue_info |= HINIC_SQ_CTRL_SET(HINIC_MSS_MIN, QUEUE_INFO_MSS);
+ }
+
+ return 0;
+}
+
netdev_tx_t hinic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
{
struct hinic_dev *nic_dev = netdev_priv(netdev);
+ u16 prod_idx, q_id = skb->queue_mapping;
struct netdev_queue *netdev_txq;
int nr_sges, err = NETDEV_TX_OK;
struct hinic_sq_wqe *sq_wqe;
unsigned int wqe_size;
struct hinic_txq *txq;
struct hinic_qp *qp;
- u16 prod_idx;
- txq = &nic_dev->txqs[skb->queue_mapping];
+ txq = &nic_dev->txqs[q_id];
qp = container_of(txq->sq, struct hinic_qp, sq);
if (skb->len < MIN_SKB_LEN) {
@@ -236,15 +510,23 @@ netdev_tx_t hinic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
process_sq_wqe:
hinic_sq_prepare_wqe(txq->sq, prod_idx, sq_wqe, txq->sges, nr_sges);
+ err = hinic_tx_offload(skb, &sq_wqe->task, &sq_wqe->ctrl.queue_info);
+ if (err)
+ goto offload_error;
+
hinic_sq_write_wqe(txq->sq, prod_idx, sq_wqe, skb, wqe_size);
flush_skbs:
- netdev_txq = netdev_get_tx_queue(netdev, skb->queue_mapping);
+ netdev_txq = netdev_get_tx_queue(netdev, q_id);
if ((!skb->xmit_more) || (netif_xmit_stopped(netdev_txq)))
hinic_sq_write_db(txq->sq, prod_idx, wqe_size, 0);
return err;
+offload_error:
+ hinic_sq_return_wqe(txq->sq, wqe_size);
+ tx_unmap_skb(nic_dev, skb, txq->sges);
+
skb_error:
dev_kfree_skb_any(skb);
@@ -252,7 +534,8 @@ update_error_stats:
u64_stats_update_begin(&txq->txq_stats.syncp);
txq->txq_stats.tx_dropped++;
u64_stats_update_end(&txq->txq_stats.syncp);
- return err;
+
+ return NETDEV_TX_OK;
}
/**
diff --git a/drivers/net/ethernet/ibm/ehea/ehea_main.c b/drivers/net/ethernet/ibm/ehea/ehea_main.c
index ba580bfae512..3baabdc89726 100644
--- a/drivers/net/ethernet/ibm/ehea/ehea_main.c
+++ b/drivers/net/ethernet/ibm/ehea/ehea_main.c
@@ -778,12 +778,11 @@ static void check_sqs(struct ehea_port *port)
{
struct ehea_swqe *swqe;
int swqe_index;
- int i, k;
+ int i;
for (i = 0; i < port->num_def_qps; i++) {
struct ehea_port_res *pr = &port->port_res[i];
int ret;
- k = 0;
swqe = ehea_get_swqe(pr->qp, &swqe_index);
memset(swqe, 0, SWQE_HEADER_SIZE);
atomic_dec(&pr->swqe_avail);
@@ -921,17 +920,6 @@ static int ehea_poll(struct napi_struct *napi, int budget)
return rx;
}
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void ehea_netpoll(struct net_device *dev)
-{
- struct ehea_port *port = netdev_priv(dev);
- int i;
-
- for (i = 0; i < port->num_def_qps; i++)
- napi_schedule(&port->port_res[i].napi);
-}
-#endif
-
static irqreturn_t ehea_recv_irq_handler(int irq, void *param)
{
struct ehea_port_res *pr = param;
@@ -2038,7 +2026,7 @@ static void ehea_xmit3(struct sk_buff *skb, struct net_device *dev,
dev_consume_skb_any(skb);
}
-static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ehea_port *port = netdev_priv(dev);
struct ehea_swqe *swqe;
@@ -2953,9 +2941,6 @@ static const struct net_device_ops ehea_netdev_ops = {
.ndo_open = ehea_open,
.ndo_stop = ehea_stop,
.ndo_start_xmit = ehea_start_xmit,
-#ifdef CONFIG_NET_POLL_CONTROLLER
- .ndo_poll_controller = ehea_netpoll,
-#endif
.ndo_get_stats64 = ehea_get_stats64,
.ndo_set_mac_address = ehea_set_mac_addr,
.ndo_validate_addr = eth_validate_addr,
diff --git a/drivers/net/ethernet/ibm/ehea/ehea_qmr.c b/drivers/net/ethernet/ibm/ehea/ehea_qmr.c
index a0820f72b25c..5e4e37132bf2 100644
--- a/drivers/net/ethernet/ibm/ehea/ehea_qmr.c
+++ b/drivers/net/ethernet/ibm/ehea/ehea_qmr.c
@@ -125,7 +125,7 @@ struct ehea_cq *ehea_create_cq(struct ehea_adapter *adapter,
struct ehea_cq *cq;
struct h_epa epa;
u64 *cq_handle_ref, hret, rpage;
- u32 act_nr_of_entries, act_pages, counter;
+ u32 counter;
int ret;
void *vpage;
@@ -140,8 +140,6 @@ struct ehea_cq *ehea_create_cq(struct ehea_adapter *adapter,
cq->adapter = adapter;
cq_handle_ref = &cq->fw_handle;
- act_nr_of_entries = 0;
- act_pages = 0;
hret = ehea_h_alloc_resource_cq(adapter->handle, &cq->attr,
&cq->fw_handle, &cq->epas);
diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c
index 129f4e9f38da..760b2ad8e295 100644
--- a/drivers/net/ethernet/ibm/emac/core.c
+++ b/drivers/net/ethernet/ibm/emac/core.c
@@ -423,7 +423,7 @@ static void emac_hash_mc(struct emac_instance *dev)
{
const int regs = EMAC_XAHT_REGS(dev);
u32 *gaht_base = emac_gaht_base(dev);
- u32 gaht_temp[regs];
+ u32 gaht_temp[EMAC_XAHT_MAX_REGS];
struct netdev_hw_addr *ha;
int i;
@@ -1409,7 +1409,7 @@ static inline u16 emac_tx_csum(struct emac_instance *dev,
return 0;
}
-static inline int emac_xmit_finish(struct emac_instance *dev, int len)
+static inline netdev_tx_t emac_xmit_finish(struct emac_instance *dev, int len)
{
struct emac_regs __iomem *p = dev->emacp;
struct net_device *ndev = dev->ndev;
@@ -1436,7 +1436,7 @@ static inline int emac_xmit_finish(struct emac_instance *dev, int len)
}
/* Tx lock BH */
-static int emac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+static netdev_tx_t emac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{
struct emac_instance *dev = netdev_priv(ndev);
unsigned int len = skb->len;
@@ -1494,7 +1494,8 @@ static inline int emac_xmit_split(struct emac_instance *dev, int slot,
}
/* Tx lock BH disabled (SG version for TAH equipped EMACs) */
-static int emac_start_xmit_sg(struct sk_buff *skb, struct net_device *ndev)
+static netdev_tx_t
+emac_start_xmit_sg(struct sk_buff *skb, struct net_device *ndev)
{
struct emac_instance *dev = netdev_priv(ndev);
int nr_frags = skb_shinfo(skb)->nr_frags;
@@ -2969,6 +2970,10 @@ static int emac_init_config(struct emac_instance *dev)
dev->xaht_width_shift = EMAC4_XAHT_WIDTH_SHIFT;
}
+ /* This should never happen */
+ if (WARN_ON(EMAC_XAHT_REGS(dev) > EMAC_XAHT_MAX_REGS))
+ return -ENXIO;
+
DBG(dev, "features : 0x%08x / 0x%08x\n", dev->features, EMAC_FTRS_POSSIBLE);
DBG(dev, "tx_fifo_size : %d (%d gige)\n", dev->tx_fifo_size, dev->tx_fifo_size_gige);
DBG(dev, "rx_fifo_size : %d (%d gige)\n", dev->rx_fifo_size, dev->rx_fifo_size_gige);
diff --git a/drivers/net/ethernet/ibm/emac/core.h b/drivers/net/ethernet/ibm/emac/core.h
index 369de2cfb15b..84caa4a3fc52 100644
--- a/drivers/net/ethernet/ibm/emac/core.h
+++ b/drivers/net/ethernet/ibm/emac/core.h
@@ -390,6 +390,9 @@ static inline int emac_has_feature(struct emac_instance *dev,
#define EMAC4SYNC_XAHT_SLOTS_SHIFT 8
#define EMAC4SYNC_XAHT_WIDTH_SHIFT 5
+/* The largest span between slots and widths above is 3 */
+#define EMAC_XAHT_MAX_REGS (1 << 3)
+
#define EMAC_XAHT_SLOTS(dev) (1 << (dev)->xaht_slots_shift)
#define EMAC_XAHT_WIDTH(dev) (1 << (dev)->xaht_width_shift)
#define EMAC_XAHT_REGS(dev) (1 << ((dev)->xaht_slots_shift - \
diff --git a/drivers/net/ethernet/ibm/emac/mal.h b/drivers/net/ethernet/ibm/emac/mal.h
index eeade2ea8334..e4c20f0024f6 100644
--- a/drivers/net/ethernet/ibm/emac/mal.h
+++ b/drivers/net/ethernet/ibm/emac/mal.h
@@ -136,7 +136,7 @@ static inline int mal_rx_size(int len)
static inline int mal_tx_chunks(int len)
{
- return (len + MAL_MAX_TX_SIZE - 1) / MAL_MAX_TX_SIZE;
+ return DIV_ROUND_UP(len, MAL_MAX_TX_SIZE);
}
#define MAL_CHAN_MASK(n) (0x80000000 >> (n))
diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
index 525d8b89187b..a4681780a55d 100644
--- a/drivers/net/ethernet/ibm/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c
@@ -24,7 +24,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/dma-mapping.h>
diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c
index 4f0daf67b18d..c9d5d0a7fbf1 100644
--- a/drivers/net/ethernet/ibm/ibmvnic.c
+++ b/drivers/net/ethernet/ibm/ibmvnic.c
@@ -1428,7 +1428,7 @@ static int ibmvnic_xmit_workarounds(struct sk_buff *skb,
return 0;
}
-static int ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev)
+static netdev_tx_t ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev)
{
struct ibmvnic_adapter *adapter = netdev_priv(netdev);
int queue_num = skb_get_queue_mapping(skb);
@@ -1452,7 +1452,7 @@ static int ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev)
u64 *handle_array;
int index = 0;
u8 proto = 0;
- int ret = 0;
+ netdev_tx_t ret = NETDEV_TX_OK;
if (adapter->resetting) {
if (!netif_subqueue_stopped(netdev, skb))
@@ -1545,7 +1545,7 @@ static int ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev)
tx_crq.v1.sge_len = cpu_to_be32(skb->len);
tx_crq.v1.ioba = cpu_to_be64(data_dma_addr);
- if (adapter->vlan_header_insertion) {
+ if (adapter->vlan_header_insertion && skb_vlan_tag_present(skb)) {
tx_crq.v1.flags2 |= IBMVNIC_TX_VLAN_INSERT;
tx_crq.v1.vlan_id = cpu_to_be16(skb->vlan_tci);
}
@@ -2207,19 +2207,6 @@ restart_poll:
return frames_processed;
}
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void ibmvnic_netpoll_controller(struct net_device *dev)
-{
- struct ibmvnic_adapter *adapter = netdev_priv(dev);
- int i;
-
- replenish_pools(netdev_priv(dev));
- for (i = 0; i < adapter->req_rx_queues; i++)
- ibmvnic_interrupt_rx(adapter->rx_scrq[i]->irq,
- adapter->rx_scrq[i]);
-}
-#endif
-
static int wait_for_reset(struct ibmvnic_adapter *adapter)
{
int rc, ret;
@@ -2292,9 +2279,6 @@ static const struct net_device_ops ibmvnic_netdev_ops = {
.ndo_set_mac_address = ibmvnic_set_mac,
.ndo_validate_addr = eth_validate_addr,
.ndo_tx_timeout = ibmvnic_tx_timeout,
-#ifdef CONFIG_NET_POLL_CONTROLLER
- .ndo_poll_controller = ibmvnic_netpoll_controller,
-#endif
.ndo_change_mtu = ibmvnic_change_mtu,
.ndo_features_check = ibmvnic_features_check,
};
@@ -2364,8 +2348,13 @@ static void ibmvnic_get_ringparam(struct net_device *netdev,
{
struct ibmvnic_adapter *adapter = netdev_priv(netdev);
- ring->rx_max_pending = adapter->max_rx_add_entries_per_subcrq;
- ring->tx_max_pending = adapter->max_tx_entries_per_subcrq;
+ if (adapter->priv_flags & IBMVNIC_USE_SERVER_MAXES) {
+ ring->rx_max_pending = adapter->max_rx_add_entries_per_subcrq;
+ ring->tx_max_pending = adapter->max_tx_entries_per_subcrq;
+ } else {
+ ring->rx_max_pending = IBMVNIC_MAX_QUEUE_SZ;
+ ring->tx_max_pending = IBMVNIC_MAX_QUEUE_SZ;
+ }
ring->rx_mini_max_pending = 0;
ring->rx_jumbo_max_pending = 0;
ring->rx_pending = adapter->req_rx_add_entries_per_subcrq;
@@ -2378,21 +2367,23 @@ static int ibmvnic_set_ringparam(struct net_device *netdev,
struct ethtool_ringparam *ring)
{
struct ibmvnic_adapter *adapter = netdev_priv(netdev);
+ int ret;
- if (ring->rx_pending > adapter->max_rx_add_entries_per_subcrq ||
- ring->tx_pending > adapter->max_tx_entries_per_subcrq) {
- netdev_err(netdev, "Invalid request.\n");
- netdev_err(netdev, "Max tx buffers = %llu\n",
- adapter->max_rx_add_entries_per_subcrq);
- netdev_err(netdev, "Max rx buffers = %llu\n",
- adapter->max_tx_entries_per_subcrq);
- return -EINVAL;
- }
-
+ ret = 0;
adapter->desired.rx_entries = ring->rx_pending;
adapter->desired.tx_entries = ring->tx_pending;
- return wait_for_reset(adapter);
+ ret = wait_for_reset(adapter);
+
+ if (!ret &&
+ (adapter->req_rx_add_entries_per_subcrq != ring->rx_pending ||
+ adapter->req_tx_entries_per_subcrq != ring->tx_pending))
+ netdev_info(netdev,
+ "Could not match full ringsize request. Requested: RX %d, TX %d; Allowed: RX %llu, TX %llu\n",
+ ring->rx_pending, ring->tx_pending,
+ adapter->req_rx_add_entries_per_subcrq,
+ adapter->req_tx_entries_per_subcrq);
+ return ret;
}
static void ibmvnic_get_channels(struct net_device *netdev,
@@ -2400,8 +2391,14 @@ static void ibmvnic_get_channels(struct net_device *netdev,
{
struct ibmvnic_adapter *adapter = netdev_priv(netdev);
- channels->max_rx = adapter->max_rx_queues;
- channels->max_tx = adapter->max_tx_queues;
+ if (adapter->priv_flags & IBMVNIC_USE_SERVER_MAXES) {
+ channels->max_rx = adapter->max_rx_queues;
+ channels->max_tx = adapter->max_tx_queues;
+ } else {
+ channels->max_rx = IBMVNIC_MAX_QUEUES;
+ channels->max_tx = IBMVNIC_MAX_QUEUES;
+ }
+
channels->max_other = 0;
channels->max_combined = 0;
channels->rx_count = adapter->req_rx_queues;
@@ -2414,11 +2411,23 @@ static int ibmvnic_set_channels(struct net_device *netdev,
struct ethtool_channels *channels)
{
struct ibmvnic_adapter *adapter = netdev_priv(netdev);
+ int ret;
+ ret = 0;
adapter->desired.rx_queues = channels->rx_count;
adapter->desired.tx_queues = channels->tx_count;
- return wait_for_reset(adapter);
+ ret = wait_for_reset(adapter);
+
+ if (!ret &&
+ (adapter->req_rx_queues != channels->rx_count ||
+ adapter->req_tx_queues != channels->tx_count))
+ netdev_info(netdev,
+ "Could not match full channels request. Requested: RX %d, TX %d; Allowed: RX %llu, TX %llu\n",
+ channels->rx_count, channels->tx_count,
+ adapter->req_rx_queues, adapter->req_tx_queues);
+ return ret;
+
}
static void ibmvnic_get_strings(struct net_device *dev, u32 stringset, u8 *data)
@@ -2426,32 +2435,43 @@ static void ibmvnic_get_strings(struct net_device *dev, u32 stringset, u8 *data)
struct ibmvnic_adapter *adapter = netdev_priv(dev);
int i;
- if (stringset != ETH_SS_STATS)
- return;
+ switch (stringset) {
+ case ETH_SS_STATS:
+ for (i = 0; i < ARRAY_SIZE(ibmvnic_stats);
+ i++, data += ETH_GSTRING_LEN)
+ memcpy(data, ibmvnic_stats[i].name, ETH_GSTRING_LEN);
- for (i = 0; i < ARRAY_SIZE(ibmvnic_stats); i++, data += ETH_GSTRING_LEN)
- memcpy(data, ibmvnic_stats[i].name, ETH_GSTRING_LEN);
+ for (i = 0; i < adapter->req_tx_queues; i++) {
+ snprintf(data, ETH_GSTRING_LEN, "tx%d_packets", i);
+ data += ETH_GSTRING_LEN;
- for (i = 0; i < adapter->req_tx_queues; i++) {
- snprintf(data, ETH_GSTRING_LEN, "tx%d_packets", i);
- data += ETH_GSTRING_LEN;
+ snprintf(data, ETH_GSTRING_LEN, "tx%d_bytes", i);
+ data += ETH_GSTRING_LEN;
- snprintf(data, ETH_GSTRING_LEN, "tx%d_bytes", i);
- data += ETH_GSTRING_LEN;
+ snprintf(data, ETH_GSTRING_LEN,
+ "tx%d_dropped_packets", i);
+ data += ETH_GSTRING_LEN;
+ }
- snprintf(data, ETH_GSTRING_LEN, "tx%d_dropped_packets", i);
- data += ETH_GSTRING_LEN;
- }
+ for (i = 0; i < adapter->req_rx_queues; i++) {
+ snprintf(data, ETH_GSTRING_LEN, "rx%d_packets", i);
+ data += ETH_GSTRING_LEN;
- for (i = 0; i < adapter->req_rx_queues; i++) {
- snprintf(data, ETH_GSTRING_LEN, "rx%d_packets", i);
- data += ETH_GSTRING_LEN;
+ snprintf(data, ETH_GSTRING_LEN, "rx%d_bytes", i);
+ data += ETH_GSTRING_LEN;
- snprintf(data, ETH_GSTRING_LEN, "rx%d_bytes", i);
- data += ETH_GSTRING_LEN;
+ snprintf(data, ETH_GSTRING_LEN, "rx%d_interrupts", i);
+ data += ETH_GSTRING_LEN;
+ }
+ break;
- snprintf(data, ETH_GSTRING_LEN, "rx%d_interrupts", i);
- data += ETH_GSTRING_LEN;
+ case ETH_SS_PRIV_FLAGS:
+ for (i = 0; i < ARRAY_SIZE(ibmvnic_priv_flags); i++)
+ strcpy(data + i * ETH_GSTRING_LEN,
+ ibmvnic_priv_flags[i]);
+ break;
+ default:
+ return;
}
}
@@ -2464,6 +2484,8 @@ static int ibmvnic_get_sset_count(struct net_device *dev, int sset)
return ARRAY_SIZE(ibmvnic_stats) +
adapter->req_tx_queues * NUM_TX_STATS +
adapter->req_rx_queues * NUM_RX_STATS;
+ case ETH_SS_PRIV_FLAGS:
+ return ARRAY_SIZE(ibmvnic_priv_flags);
default:
return -EOPNOTSUPP;
}
@@ -2514,6 +2536,25 @@ static void ibmvnic_get_ethtool_stats(struct net_device *dev,
}
}
+static u32 ibmvnic_get_priv_flags(struct net_device *netdev)
+{
+ struct ibmvnic_adapter *adapter = netdev_priv(netdev);
+
+ return adapter->priv_flags;
+}
+
+static int ibmvnic_set_priv_flags(struct net_device *netdev, u32 flags)
+{
+ struct ibmvnic_adapter *adapter = netdev_priv(netdev);
+ bool which_maxes = !!(flags & IBMVNIC_USE_SERVER_MAXES);
+
+ if (which_maxes)
+ adapter->priv_flags |= IBMVNIC_USE_SERVER_MAXES;
+ else
+ adapter->priv_flags &= ~IBMVNIC_USE_SERVER_MAXES;
+
+ return 0;
+}
static const struct ethtool_ops ibmvnic_ethtool_ops = {
.get_drvinfo = ibmvnic_get_drvinfo,
.get_msglevel = ibmvnic_get_msglevel,
@@ -2527,6 +2568,8 @@ static const struct ethtool_ops ibmvnic_ethtool_ops = {
.get_sset_count = ibmvnic_get_sset_count,
.get_ethtool_stats = ibmvnic_get_ethtool_stats,
.get_link_ksettings = ibmvnic_get_link_ksettings,
+ .get_priv_flags = ibmvnic_get_priv_flags,
+ .set_priv_flags = ibmvnic_set_priv_flags,
};
/* Routines for managing CRQs/sCRQs */
diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h
index f06eec145ca6..18103b811d4d 100644
--- a/drivers/net/ethernet/ibm/ibmvnic.h
+++ b/drivers/net/ethernet/ibm/ibmvnic.h
@@ -39,7 +39,8 @@
#define IBMVNIC_RX_WEIGHT 16
/* when changing this, update IBMVNIC_IO_ENTITLEMENT_DEFAULT */
#define IBMVNIC_BUFFS_PER_POOL 100
-#define IBMVNIC_MAX_QUEUES 10
+#define IBMVNIC_MAX_QUEUES 16
+#define IBMVNIC_MAX_QUEUE_SZ 4096
#define IBMVNIC_TSO_BUF_SZ 65536
#define IBMVNIC_TSO_BUFS 64
@@ -48,6 +49,11 @@
#define IBMVNIC_MAX_LTB_SIZE ((1 << (MAX_ORDER - 1)) * PAGE_SIZE)
#define IBMVNIC_BUFFER_HLEN 500
+static const char ibmvnic_priv_flags[][ETH_GSTRING_LEN] = {
+#define IBMVNIC_USE_SERVER_MAXES 0x1
+ "use-server-maxes"
+};
+
struct ibmvnic_login_buffer {
__be32 len;
__be32 version;
@@ -969,6 +975,7 @@ struct ibmvnic_adapter {
struct ibmvnic_control_ip_offload_buffer ip_offload_ctrl;
dma_addr_t ip_offload_ctrl_tok;
u32 msg_enable;
+ u32 priv_flags;
/* Vital Product Data (VPD) */
struct ibmvnic_vpd *vpd;
diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig
index 1ab613eb5796..59e1bc0f609e 100644
--- a/drivers/net/ethernet/intel/Kconfig
+++ b/drivers/net/ethernet/intel/Kconfig
@@ -68,6 +68,9 @@ config E1000E
<http://support.intel.com>
+ More specific information on configuring the driver is in
+ <file:Documentation/networking/e1000e.rst>.
+
To compile this driver as a module, choose M here. The module
will be called e1000e.
@@ -94,7 +97,7 @@ config IGB
<http://support.intel.com>
More specific information on configuring the driver is in
- <file:Documentation/networking/e1000.rst>.
+ <file:Documentation/networking/igb.rst>.
To compile this driver as a module, choose M here. The module
will be called igb.
@@ -130,7 +133,7 @@ config IGBVF
<http://support.intel.com>
More specific information on configuring the driver is in
- <file:Documentation/networking/e1000.rst>.
+ <file:Documentation/networking/igbvf.rst>.
To compile this driver as a module, choose M here. The module
will be called igbvf.
@@ -147,7 +150,7 @@ config IXGB
<http://support.intel.com>
More specific information on configuring the driver is in
- <file:Documentation/networking/ixgb.txt>.
+ <file:Documentation/networking/ixgb.rst>.
To compile this driver as a module, choose M here. The module
will be called ixgb.
@@ -164,6 +167,9 @@ config IXGBE
<http://support.intel.com>
+ More specific information on configuring the driver is in
+ <file:Documentation/networking/ixgbe.rst>.
+
To compile this driver as a module, choose M here. The module
will be called ixgbe.
@@ -194,6 +200,15 @@ config IXGBE_DCB
If unsure, say N.
+config IXGBE_IPSEC
+ bool "IPSec XFRM cryptography-offload acceleration"
+ depends on IXGBE
+ depends on XFRM_OFFLOAD
+ default y
+ select XFRM_ALGO
+ ---help---
+ Enable support for IPSec offload in ixgbe.ko
+
config IXGBEVF
tristate "Intel(R) 10GbE PCI Express Virtual Function Ethernet support"
depends on PCI_MSI
@@ -205,12 +220,21 @@ config IXGBEVF
<http://support.intel.com>
More specific information on configuring the driver is in
- <file:Documentation/networking/ixgbevf.txt>.
+ <file:Documentation/networking/ixgbevf.rst>.
To compile this driver as a module, choose M here. The module
will be called ixgbevf. MSI-X interrupt support is required
for this driver to work correctly.
+config IXGBEVF_IPSEC
+ bool "IPSec XFRM cryptography-offload acceleration"
+ depends on IXGBEVF
+ depends on XFRM_OFFLOAD
+ default y
+ select XFRM_ALGO
+ ---help---
+ Enable support for IPSec offload in ixgbevf.ko
+
config I40E
tristate "Intel(R) Ethernet Controller XL710 Family support"
imply PTP_1588_CLOCK
@@ -222,6 +246,9 @@ config I40E
<http://support.intel.com>
+ More specific information on configuring the driver is in
+ <file:Documentation/networking/i40e.rst>.
+
To compile this driver as a module, choose M here. The module
will be called i40e.
@@ -235,20 +262,30 @@ config I40E_DCB
If unsure, say N.
+# this is here to allow seamless migration from I40EVF --> IAVF name
+# so that CONFIG_IAVF symbol will always mirror the state of CONFIG_I40EVF
+config IAVF
+ tristate
config I40EVF
tristate "Intel(R) Ethernet Adaptive Virtual Function support"
+ select IAVF
depends on PCI_MSI
---help---
This driver supports virtual functions for Intel XL710,
- X710, X722, and all devices advertising support for Intel
- Ethernet Adaptive Virtual Function devices. For more
+ X710, X722, XXV710, and all devices advertising support for
+ Intel Ethernet Adaptive Virtual Function devices. For more
information on how to identify your adapter, go to the Adapter
& Driver ID Guide that can be located at:
- <http://support.intel.com>
+ <https://support.intel.com>
+
+ This driver was formerly named i40evf.
+
+ More specific information on configuring the driver is in
+ <file:Documentation/networking/iavf.rst>.
To compile this driver as a module, choose M here. The module
- will be called i40evf. MSI-X interrupt support is required
+ will be called iavf. MSI-X interrupt support is required
for this driver to work correctly.
config ICE
@@ -262,6 +299,9 @@ config ICE
<http://support.intel.com>
+ More specific information on configuring the driver is in
+ <file:Documentation/networking/ice.rst>.
+
To compile this driver as a module, choose M here. The module
will be called ice.
@@ -277,7 +317,26 @@ config FM10K
<http://support.intel.com>
+ More specific information on configuring the driver is in
+ <file:Documentation/networking/fm10k.rst>.
+
To compile this driver as a module, choose M here. The module
will be called fm10k. MSI-X interrupt support is required
+config IGC
+ tristate "Intel(R) Ethernet Controller I225-LM/I225-V support"
+ default n
+ depends on PCI
+ ---help---
+ This driver supports Intel(R) Ethernet Controller I225-LM/I225-V
+ family of adapters.
+
+ For more information on how to identify your adapter, go
+ to the Adapter & Driver ID Guide that can be located at:
+
+ <http://support.intel.com>
+
+ To compile this driver as a module, choose M here. The module
+ will be called igc.
+
endif # NET_VENDOR_INTEL
diff --git a/drivers/net/ethernet/intel/Makefile b/drivers/net/ethernet/intel/Makefile
index 807a4f8c7e4e..3075290063f6 100644
--- a/drivers/net/ethernet/intel/Makefile
+++ b/drivers/net/ethernet/intel/Makefile
@@ -7,11 +7,12 @@ obj-$(CONFIG_E100) += e100.o
obj-$(CONFIG_E1000) += e1000/
obj-$(CONFIG_E1000E) += e1000e/
obj-$(CONFIG_IGB) += igb/
+obj-$(CONFIG_IGC) += igc/
obj-$(CONFIG_IGBVF) += igbvf/
obj-$(CONFIG_IXGBE) += ixgbe/
obj-$(CONFIG_IXGBEVF) += ixgbevf/
obj-$(CONFIG_I40E) += i40e/
obj-$(CONFIG_IXGB) += ixgb/
-obj-$(CONFIG_I40EVF) += i40evf/
+obj-$(CONFIG_IAVF) += iavf/
obj-$(CONFIG_FM10K) += fm10k/
obj-$(CONFIG_ICE) += ice/
diff --git a/drivers/net/ethernet/intel/e100.c b/drivers/net/ethernet/intel/e100.c
index 27d5f27163d2..7c4b55482f72 100644
--- a/drivers/net/ethernet/intel/e100.c
+++ b/drivers/net/ethernet/intel/e100.c
@@ -164,7 +164,7 @@
MODULE_DESCRIPTION(DRV_DESCRIPTION);
MODULE_AUTHOR(DRV_COPYRIGHT);
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_VERSION(DRV_VERSION);
MODULE_FIRMWARE(FIRMWARE_D101M);
MODULE_FIRMWARE(FIRMWARE_D101S);
diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c
index 2110d5f2da19..43b6d3cec3b3 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_main.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
@@ -195,7 +195,7 @@ static struct pci_driver e1000_driver = {
MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
MODULE_DESCRIPTION("Intel(R) PRO/1000 Network Driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_VERSION(DRV_VERSION);
#define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV|NETIF_MSG_PROBE|NETIF_MSG_LINK)
@@ -2433,7 +2433,6 @@ static void e1000_watchdog(struct work_struct *work)
if (link) {
if (!netif_carrier_ok(netdev)) {
u32 ctrl;
- bool txb2b = true;
/* update snapshot of PHY registers on LSC */
e1000_get_speed_and_duplex(hw,
&adapter->link_speed,
@@ -2455,11 +2454,9 @@ static void e1000_watchdog(struct work_struct *work)
adapter->tx_timeout_factor = 1;
switch (adapter->link_speed) {
case SPEED_10:
- txb2b = false;
adapter->tx_timeout_factor = 16;
break;
case SPEED_100:
- txb2b = false;
/* maybe add some timeout factor ? */
break;
}
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index 3ba0c90e7055..16a73bd9f4cb 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -6854,8 +6854,6 @@ static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev)
result = PCI_ERS_RESULT_RECOVERED;
}
- pci_cleanup_aer_uncorrect_error_status(pdev);
-
return result;
}
@@ -7592,7 +7590,7 @@ module_exit(e1000_exit_module);
MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
MODULE_DESCRIPTION("Intel(R) PRO/1000 Network Driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_VERSION(DRV_VERSION);
/* netdev.c */
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_iov.c b/drivers/net/ethernet/intel/fm10k/fm10k_iov.c
index e707d717012f..5d4f1761dc0c 100644
--- a/drivers/net/ethernet/intel/fm10k/fm10k_iov.c
+++ b/drivers/net/ethernet/intel/fm10k/fm10k_iov.c
@@ -244,7 +244,8 @@ process_mbx:
}
/* guarantee we have free space in the SM mailbox */
- if (!hw->mbx.ops.tx_ready(&hw->mbx, FM10K_VFMBX_MSG_MTU)) {
+ if (hw->mbx.state == FM10K_STATE_OPEN &&
+ !hw->mbx.ops.tx_ready(&hw->mbx, FM10K_VFMBX_MSG_MTU)) {
/* keep track of how many times this occurs */
interface->hw_sm_mbx_full++;
@@ -302,6 +303,28 @@ void fm10k_iov_suspend(struct pci_dev *pdev)
}
}
+static void fm10k_mask_aer_comp_abort(struct pci_dev *pdev)
+{
+ u32 err_mask;
+ int pos;
+
+ pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR);
+ if (!pos)
+ return;
+
+ /* Mask the completion abort bit in the ERR_UNCOR_MASK register,
+ * preventing the device from reporting these errors to the upstream
+ * PCIe root device. This avoids bringing down platforms which upgrade
+ * non-fatal completer aborts into machine check exceptions. Completer
+ * aborts can occur whenever a VF reads a queue it doesn't own.
+ */
+ pci_read_config_dword(pdev, pos + PCI_ERR_UNCOR_MASK, &err_mask);
+ err_mask |= PCI_ERR_UNC_COMP_ABORT;
+ pci_write_config_dword(pdev, pos + PCI_ERR_UNCOR_MASK, err_mask);
+
+ mmiowb();
+}
+
int fm10k_iov_resume(struct pci_dev *pdev)
{
struct fm10k_intfc *interface = pci_get_drvdata(pdev);
@@ -317,6 +340,12 @@ int fm10k_iov_resume(struct pci_dev *pdev)
if (!iov_data)
return -ENOMEM;
+ /* Lower severity of completer abort error reporting as
+ * the VFs can trigger this any time they read a queue
+ * that they don't own.
+ */
+ fm10k_mask_aer_comp_abort(pdev);
+
/* allocate hardware resources for the VFs */
hw->iov.ops.assign_resources(hw, num_vfs, num_vfs);
@@ -460,20 +489,6 @@ void fm10k_iov_disable(struct pci_dev *pdev)
fm10k_iov_free_data(pdev);
}
-static void fm10k_disable_aer_comp_abort(struct pci_dev *pdev)
-{
- u32 err_sev;
- int pos;
-
- pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR);
- if (!pos)
- return;
-
- pci_read_config_dword(pdev, pos + PCI_ERR_UNCOR_SEVER, &err_sev);
- err_sev &= ~PCI_ERR_UNC_COMP_ABORT;
- pci_write_config_dword(pdev, pos + PCI_ERR_UNCOR_SEVER, err_sev);
-}
-
int fm10k_iov_configure(struct pci_dev *pdev, int num_vfs)
{
int current_vfs = pci_num_vf(pdev);
@@ -495,12 +510,6 @@ int fm10k_iov_configure(struct pci_dev *pdev, int num_vfs)
/* allocate VFs if not already allocated */
if (num_vfs && num_vfs != current_vfs) {
- /* Disable completer abort error reporting as
- * the VFs can trigger this any time they read a queue
- * that they don't own.
- */
- fm10k_disable_aer_comp_abort(pdev);
-
err = pci_enable_sriov(pdev, num_vfs);
if (err) {
dev_err(&pdev->dev,
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_main.c b/drivers/net/ethernet/intel/fm10k/fm10k_main.c
index 3f536541f45f..5b2a50e5798f 100644
--- a/drivers/net/ethernet/intel/fm10k/fm10k_main.c
+++ b/drivers/net/ethernet/intel/fm10k/fm10k_main.c
@@ -11,7 +11,7 @@
#include "fm10k.h"
-#define DRV_VERSION "0.23.4-k"
+#define DRV_VERSION "0.26.1-k"
#define DRV_SUMMARY "Intel(R) Ethernet Switch Host Interface Driver"
const char fm10k_driver_version[] = DRV_VERSION;
char fm10k_driver_name[] = "fm10k";
@@ -21,7 +21,7 @@ static const char fm10k_copyright[] =
MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
MODULE_DESCRIPTION(DRV_SUMMARY);
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_VERSION(DRV_VERSION);
/* single workqueue for entire fm10k driver */
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c
index c859ababeed5..e49fb51d3613 100644
--- a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c
+++ b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c
@@ -23,6 +23,8 @@ static const struct fm10k_info *fm10k_info_tbl[] = {
*/
static const struct pci_device_id fm10k_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, FM10K_DEV_ID_PF), fm10k_device_pf },
+ { PCI_VDEVICE(INTEL, FM10K_DEV_ID_SDI_FM10420_QDA2), fm10k_device_pf },
+ { PCI_VDEVICE(INTEL, FM10K_DEV_ID_SDI_FM10420_DA2), fm10k_device_pf },
{ PCI_VDEVICE(INTEL, FM10K_DEV_ID_VF), fm10k_device_vf },
/* required last entry */
{ 0, }
@@ -2440,8 +2442,6 @@ static pci_ers_result_t fm10k_io_slot_reset(struct pci_dev *pdev)
result = PCI_ERS_RESULT_RECOVERED;
}
- pci_cleanup_aer_uncorrect_error_status(pdev);
-
return result;
}
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_type.h b/drivers/net/ethernet/intel/fm10k/fm10k_type.h
index 3e608e493f9d..9fb9fca375e3 100644
--- a/drivers/net/ethernet/intel/fm10k/fm10k_type.h
+++ b/drivers/net/ethernet/intel/fm10k/fm10k_type.h
@@ -15,6 +15,8 @@ struct fm10k_hw;
#define FM10K_DEV_ID_PF 0x15A4
#define FM10K_DEV_ID_VF 0x15A5
+#define FM10K_DEV_ID_SDI_FM10420_QDA2 0x15D0
+#define FM10K_DEV_ID_SDI_FM10420_DA2 0x15D5
#define FM10K_MAX_QUEUES 256
#define FM10K_MAX_QUEUES_PF 128
diff --git a/drivers/net/ethernet/intel/i40e/Makefile b/drivers/net/ethernet/intel/i40e/Makefile
index 14397e7e9925..50590e8d1fd1 100644
--- a/drivers/net/ethernet/intel/i40e/Makefile
+++ b/drivers/net/ethernet/intel/i40e/Makefile
@@ -22,6 +22,7 @@ i40e-objs := i40e_main.o \
i40e_txrx.o \
i40e_ptp.o \
i40e_client.o \
- i40e_virtchnl_pf.o
+ i40e_virtchnl_pf.o \
+ i40e_xsk.o
i40e-$(CONFIG_I40E_DCB) += i40e_dcb.o i40e_dcb_nl.o
diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h
index 7a80652e2500..876cac317e79 100644
--- a/drivers/net/ethernet/intel/i40e/i40e.h
+++ b/drivers/net/ethernet/intel/i40e/i40e.h
@@ -786,6 +786,11 @@ struct i40e_vsi {
/* VSI specific handlers */
irqreturn_t (*irq_handler)(int irq, void *data);
+
+ /* AF_XDP zero-copy */
+ struct xdp_umem **xsk_umems;
+ u16 num_xsk_umems_used;
+ u16 num_xsk_umems;
} ____cacheline_internodealigned_in_smp;
struct i40e_netdev_priv {
@@ -1090,6 +1095,20 @@ static inline bool i40e_enabled_xdp_vsi(struct i40e_vsi *vsi)
return !!vsi->xdp_prog;
}
+static inline struct xdp_umem *i40e_xsk_umem(struct i40e_ring *ring)
+{
+ bool xdp_on = i40e_enabled_xdp_vsi(ring->vsi);
+ int qid = ring->queue_index;
+
+ if (ring_is_xdp(ring))
+ qid -= ring->vsi->alloc_queue_pairs;
+
+ if (!ring->vsi->xsk_umems || !ring->vsi->xsk_umems[qid] || !xdp_on)
+ return NULL;
+
+ return ring->vsi->xsk_umems[qid];
+}
+
int i40e_create_queue_channel(struct i40e_vsi *vsi, struct i40e_channel *ch);
int i40e_set_bw_limit(struct i40e_vsi *vsi, u16 seid, u64 max_tx_rate);
int i40e_add_del_cloud_filter(struct i40e_vsi *vsi,
diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
index 56b911a5dd8b..a20d1cf058ad 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
@@ -132,8 +132,6 @@ static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid)
dev_info(&pf->pdev->dev, " vlan_features = 0x%08lx\n",
(unsigned long int)nd->vlan_features);
}
- dev_info(&pf->pdev->dev, " active_vlans is %s\n",
- vsi->active_vlans ? "<valid>" : "<null>");
dev_info(&pf->pdev->dev,
" flags = 0x%08lx, netdev_registered = %i, current_netdev_flags = 0x%04x\n",
vsi->flags, vsi->netdev_registered, vsi->current_netdev_flags);
diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
index 5ff6caa83948..9f8464f80783 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
@@ -5,26 +5,227 @@
#include "i40e.h"
#include "i40e_diag.h"
+#include "i40e_txrx_common.h"
+/* ethtool statistics helpers */
+
+/**
+ * struct i40e_stats - definition for an ethtool statistic
+ * @stat_string: statistic name to display in ethtool -S output
+ * @sizeof_stat: the sizeof() the stat, must be no greater than sizeof(u64)
+ * @stat_offset: offsetof() the stat from a base pointer
+ *
+ * This structure defines a statistic to be added to the ethtool stats buffer.
+ * It defines a statistic as offset from a common base pointer. Stats should
+ * be defined in constant arrays using the I40E_STAT macro, with every element
+ * of the array using the same _type for calculating the sizeof_stat and
+ * stat_offset.
+ *
+ * The @sizeof_stat is expected to be sizeof(u8), sizeof(u16), sizeof(u32) or
+ * sizeof(u64). Other sizes are not expected and will produce a WARN_ONCE from
+ * the i40e_add_ethtool_stat() helper function.
+ *
+ * The @stat_string is interpreted as a format string, allowing formatted
+ * values to be inserted while looping over multiple structures for a given
+ * statistics array. Thus, every statistic string in an array should have the
+ * same type and number of format specifiers, to be formatted by variadic
+ * arguments to the i40e_add_stat_string() helper function.
+ **/
struct i40e_stats {
- /* The stat_string is expected to be a format string formatted using
- * vsnprintf by i40e_add_stat_strings. Every member of a stats array
- * should use the same format specifiers as they will be formatted
- * using the same variadic arguments.
- */
char stat_string[ETH_GSTRING_LEN];
int sizeof_stat;
int stat_offset;
};
+/* Helper macro to define an i40e_stat structure with proper size and type.
+ * Use this when defining constant statistics arrays. Note that @_type expects
+ * only a type name and is used multiple times.
+ */
#define I40E_STAT(_type, _name, _stat) { \
.stat_string = _name, \
.sizeof_stat = FIELD_SIZEOF(_type, _stat), \
.stat_offset = offsetof(_type, _stat) \
}
+/* Helper macro for defining some statistics directly copied from the netdev
+ * stats structure.
+ */
#define I40E_NETDEV_STAT(_net_stat) \
I40E_STAT(struct rtnl_link_stats64, #_net_stat, _net_stat)
+
+/* Helper macro for defining some statistics related to queues */
+#define I40E_QUEUE_STAT(_name, _stat) \
+ I40E_STAT(struct i40e_ring, _name, _stat)
+
+/* Stats associated with a Tx or Rx ring */
+static const struct i40e_stats i40e_gstrings_queue_stats[] = {
+ I40E_QUEUE_STAT("%s-%u.packets", stats.packets),
+ I40E_QUEUE_STAT("%s-%u.bytes", stats.bytes),
+};
+
+/**
+ * i40e_add_one_ethtool_stat - copy the stat into the supplied buffer
+ * @data: location to store the stat value
+ * @pointer: basis for where to copy from
+ * @stat: the stat definition
+ *
+ * Copies the stat data defined by the pointer and stat structure pair into
+ * the memory supplied as data. Used to implement i40e_add_ethtool_stats and
+ * i40e_add_queue_stats. If the pointer is null, data will be zero'd.
+ */
+static void
+i40e_add_one_ethtool_stat(u64 *data, void *pointer,
+ const struct i40e_stats *stat)
+{
+ char *p;
+
+ if (!pointer) {
+ /* ensure that the ethtool data buffer is zero'd for any stats
+ * which don't have a valid pointer.
+ */
+ *data = 0;
+ return;
+ }
+
+ p = (char *)pointer + stat->stat_offset;
+ switch (stat->sizeof_stat) {
+ case sizeof(u64):
+ *data = *((u64 *)p);
+ break;
+ case sizeof(u32):
+ *data = *((u32 *)p);
+ break;
+ case sizeof(u16):
+ *data = *((u16 *)p);
+ break;
+ case sizeof(u8):
+ *data = *((u8 *)p);
+ break;
+ default:
+ WARN_ONCE(1, "unexpected stat size for %s",
+ stat->stat_string);
+ *data = 0;
+ }
+}
+
+/**
+ * __i40e_add_ethtool_stats - copy stats into the ethtool supplied buffer
+ * @data: ethtool stats buffer
+ * @pointer: location to copy stats from
+ * @stats: array of stats to copy
+ * @size: the size of the stats definition
+ *
+ * Copy the stats defined by the stats array using the pointer as a base into
+ * the data buffer supplied by ethtool. Updates the data pointer to point to
+ * the next empty location for successive calls to __i40e_add_ethtool_stats.
+ * If pointer is null, set the data values to zero and update the pointer to
+ * skip these stats.
+ **/
+static void
+__i40e_add_ethtool_stats(u64 **data, void *pointer,
+ const struct i40e_stats stats[],
+ const unsigned int size)
+{
+ unsigned int i;
+
+ for (i = 0; i < size; i++)
+ i40e_add_one_ethtool_stat((*data)++, pointer, &stats[i]);
+}
+
+/**
+ * i40e_add_ethtool_stats - copy stats into ethtool supplied buffer
+ * @data: ethtool stats buffer
+ * @pointer: location where stats are stored
+ * @stats: static const array of stat definitions
+ *
+ * Macro to ease the use of __i40e_add_ethtool_stats by taking a static
+ * constant stats array and passing the ARRAY_SIZE(). This avoids typos by
+ * ensuring that we pass the size associated with the given stats array.
+ *
+ * The parameter @stats is evaluated twice, so parameters with side effects
+ * should be avoided.
+ **/
+#define i40e_add_ethtool_stats(data, pointer, stats) \
+ __i40e_add_ethtool_stats(data, pointer, stats, ARRAY_SIZE(stats))
+
+/**
+ * i40e_add_queue_stats - copy queue statistics into supplied buffer
+ * @data: ethtool stats buffer
+ * @ring: the ring to copy
+ *
+ * Queue statistics must be copied while protected by
+ * u64_stats_fetch_begin_irq, so we can't directly use i40e_add_ethtool_stats.
+ * Assumes that queue stats are defined in i40e_gstrings_queue_stats. If the
+ * ring pointer is null, zero out the queue stat values and update the data
+ * pointer. Otherwise safely copy the stats from the ring into the supplied
+ * buffer and update the data pointer when finished.
+ *
+ * This function expects to be called while under rcu_read_lock().
+ **/
+static void
+i40e_add_queue_stats(u64 **data, struct i40e_ring *ring)
+{
+ const unsigned int size = ARRAY_SIZE(i40e_gstrings_queue_stats);
+ const struct i40e_stats *stats = i40e_gstrings_queue_stats;
+ unsigned int start;
+ unsigned int i;
+
+ /* To avoid invalid statistics values, ensure that we keep retrying
+ * the copy until we get a consistent value according to
+ * u64_stats_fetch_retry_irq. But first, make sure our ring is
+ * non-null before attempting to access its syncp.
+ */
+ do {
+ start = !ring ? 0 : u64_stats_fetch_begin_irq(&ring->syncp);
+ for (i = 0; i < size; i++) {
+ i40e_add_one_ethtool_stat(&(*data)[i], ring,
+ &stats[i]);
+ }
+ } while (ring && u64_stats_fetch_retry_irq(&ring->syncp, start));
+
+ /* Once we successfully copy the stats in, update the data pointer */
+ *data += size;
+}
+
+/**
+ * __i40e_add_stat_strings - copy stat strings into ethtool buffer
+ * @p: ethtool supplied buffer
+ * @stats: stat definitions array
+ * @size: size of the stats array
+ *
+ * Format and copy the strings described by stats into the buffer pointed at
+ * by p.
+ **/
+static void __i40e_add_stat_strings(u8 **p, const struct i40e_stats stats[],
+ const unsigned int size, ...)
+{
+ unsigned int i;
+
+ for (i = 0; i < size; i++) {
+ va_list args;
+
+ va_start(args, size);
+ vsnprintf(*p, ETH_GSTRING_LEN, stats[i].stat_string, args);
+ *p += ETH_GSTRING_LEN;
+ va_end(args);
+ }
+}
+
+/**
+ * 40e_add_stat_strings - copy stat strings into ethtool buffer
+ * @p: ethtool supplied buffer
+ * @stats: stat definitions array
+ *
+ * Format and copy the strings described by the const static stats value into
+ * the buffer pointed at by p.
+ *
+ * The parameter @stats is evaluated twice, so parameters with side effects
+ * should be avoided. Additionally, stats must be an array such that
+ * ARRAY_SIZE can be called on it.
+ **/
+#define i40e_add_stat_strings(p, stats, ...) \
+ __i40e_add_stat_strings(p, stats, ARRAY_SIZE(stats), ## __VA_ARGS__)
+
#define I40E_PF_STAT(_name, _stat) \
I40E_STAT(struct i40e_pf, _name, _stat)
#define I40E_VSI_STAT(_name, _stat) \
@@ -33,6 +234,8 @@ struct i40e_stats {
I40E_STAT(struct i40e_veb, _name, _stat)
#define I40E_PFC_STAT(_name, _stat) \
I40E_STAT(struct i40e_pfc_stats, _name, _stat)
+#define I40E_QUEUE_STAT(_name, _stat) \
+ I40E_STAT(struct i40e_ring, _name, _stat)
static const struct i40e_stats i40e_gstrings_net_stats[] = {
I40E_NETDEV_STAT(rx_packets),
@@ -171,20 +374,11 @@ static const struct i40e_stats i40e_gstrings_pfc_stats[] = {
I40E_PFC_STAT("port.rx_priority_%u_xon_2_xoff", priority_xon_2_xoff),
};
-/* We use num_tx_queues here as a proxy for the maximum number of queues
- * available because we always allocate queues symmetrically.
- */
-#define I40E_MAX_NUM_QUEUES(n) ((n)->num_tx_queues)
-#define I40E_QUEUE_STATS_LEN(n) \
- (I40E_MAX_NUM_QUEUES(n) \
- * 2 /* Tx and Rx together */ \
- * (sizeof(struct i40e_queue_stats) / sizeof(u64)))
-#define I40E_GLOBAL_STATS_LEN ARRAY_SIZE(i40e_gstrings_stats)
#define I40E_NETDEV_STATS_LEN ARRAY_SIZE(i40e_gstrings_net_stats)
+
#define I40E_MISC_STATS_LEN ARRAY_SIZE(i40e_gstrings_misc_stats)
-#define I40E_VSI_STATS_LEN(n) (I40E_NETDEV_STATS_LEN + \
- I40E_MISC_STATS_LEN + \
- I40E_QUEUE_STATS_LEN((n)))
+
+#define I40E_VSI_STATS_LEN (I40E_NETDEV_STATS_LEN + I40E_MISC_STATS_LEN)
#define I40E_PFC_STATS_LEN (ARRAY_SIZE(i40e_gstrings_pfc_stats) * \
I40E_MAX_USER_PRIORITY)
@@ -193,10 +387,15 @@ static const struct i40e_stats i40e_gstrings_pfc_stats[] = {
(ARRAY_SIZE(i40e_gstrings_veb_tc_stats) * \
I40E_MAX_TRAFFIC_CLASS))
-#define I40E_PF_STATS_LEN(n) (I40E_GLOBAL_STATS_LEN + \
+#define I40E_GLOBAL_STATS_LEN ARRAY_SIZE(i40e_gstrings_stats)
+
+#define I40E_PF_STATS_LEN (I40E_GLOBAL_STATS_LEN + \
I40E_PFC_STATS_LEN + \
I40E_VEB_STATS_LEN + \
- I40E_VSI_STATS_LEN((n)))
+ I40E_VSI_STATS_LEN)
+
+/* Length of stats for a single queue */
+#define I40E_QUEUE_STATS_LEN ARRAY_SIZE(i40e_gstrings_queue_stats)
enum i40e_ethtool_test_id {
I40E_ETH_TEST_REG = 0,
@@ -1512,6 +1711,13 @@ static int i40e_set_ringparam(struct net_device *netdev,
(new_rx_count == vsi->rx_rings[0]->count))
return 0;
+ /* If there is a AF_XDP UMEM attached to any of Rx rings,
+ * disallow changing the number of descriptors -- regardless
+ * if the netdev is running or not.
+ */
+ if (i40e_xsk_any_rx_ring_enabled(vsi))
+ return -EBUSY;
+
while (test_and_set_bit(__I40E_CONFIG_BUSY, pf->state)) {
timeout--;
if (!timeout)
@@ -1701,11 +1907,30 @@ static int i40e_get_stats_count(struct net_device *netdev)
struct i40e_netdev_priv *np = netdev_priv(netdev);
struct i40e_vsi *vsi = np->vsi;
struct i40e_pf *pf = vsi->back;
+ int stats_len;
if (vsi == pf->vsi[pf->lan_vsi] && pf->hw.partition_id == 1)
- return I40E_PF_STATS_LEN(netdev);
+ stats_len = I40E_PF_STATS_LEN;
else
- return I40E_VSI_STATS_LEN(netdev);
+ stats_len = I40E_VSI_STATS_LEN;
+
+ /* The number of stats reported for a given net_device must remain
+ * constant throughout the life of that device.
+ *
+ * This is because the API for obtaining the size, strings, and stats
+ * is spread out over three separate ethtool ioctls. There is no safe
+ * way to lock the number of stats across these calls, so we must
+ * assume that they will never change.
+ *
+ * Due to this, we report the maximum number of queues, even if not
+ * every queue is currently configured. Since we always allocate
+ * queues in pairs, we'll just use netdev->num_tx_queues * 2. This
+ * works because the num_tx_queues is set at device creation and never
+ * changes.
+ */
+ stats_len += I40E_QUEUE_STATS_LEN * 2 * netdev->num_tx_queues;
+
+ return stats_len;
}
static int i40e_get_sset_count(struct net_device *netdev, int sset)
@@ -1728,89 +1953,6 @@ static int i40e_get_sset_count(struct net_device *netdev, int sset)
}
/**
- * i40e_add_one_ethtool_stat - copy the stat into the supplied buffer
- * @data: location to store the stat value
- * @pointer: basis for where to copy from
- * @stat: the stat definition
- *
- * Copies the stat data defined by the pointer and stat structure pair into
- * the memory supplied as data. Used to implement i40e_add_ethtool_stats.
- * If the pointer is null, data will be zero'd.
- */
-static inline void
-i40e_add_one_ethtool_stat(u64 *data, void *pointer,
- const struct i40e_stats *stat)
-{
- char *p;
-
- if (!pointer) {
- /* ensure that the ethtool data buffer is zero'd for any stats
- * which don't have a valid pointer.
- */
- *data = 0;
- return;
- }
-
- p = (char *)pointer + stat->stat_offset;
- switch (stat->sizeof_stat) {
- case sizeof(u64):
- *data = *((u64 *)p);
- break;
- case sizeof(u32):
- *data = *((u32 *)p);
- break;
- case sizeof(u16):
- *data = *((u16 *)p);
- break;
- case sizeof(u8):
- *data = *((u8 *)p);
- break;
- default:
- WARN_ONCE(1, "unexpected stat size for %s",
- stat->stat_string);
- *data = 0;
- }
-}
-
-/**
- * __i40e_add_ethtool_stats - copy stats into the ethtool supplied buffer
- * @data: ethtool stats buffer
- * @pointer: location to copy stats from
- * @stats: array of stats to copy
- * @size: the size of the stats definition
- *
- * Copy the stats defined by the stats array using the pointer as a base into
- * the data buffer supplied by ethtool. Updates the data pointer to point to
- * the next empty location for successive calls to __i40e_add_ethtool_stats.
- * If pointer is null, set the data values to zero and update the pointer to
- * skip these stats.
- **/
-static inline void
-__i40e_add_ethtool_stats(u64 **data, void *pointer,
- const struct i40e_stats stats[],
- const unsigned int size)
-{
- unsigned int i;
-
- for (i = 0; i < size; i++)
- i40e_add_one_ethtool_stat((*data)++, pointer, &stats[i]);
-}
-
-/**
- * i40e_add_ethtool_stats - copy stats into ethtool supplied buffer
- * @data: ethtool stats buffer
- * @pointer: location where stats are stored
- * @stats: static const array of stat definitions
- *
- * Macro to ease the use of __i40e_add_ethtool_stats by taking a static
- * constant stats array and passing the ARRAY_SIZE(). This avoids typos by
- * ensuring that we pass the size associated with the given stats array.
- * Assumes that stats is an array.
- **/
-#define i40e_add_ethtool_stats(data, pointer, stats) \
- __i40e_add_ethtool_stats(data, pointer, stats, ARRAY_SIZE(stats))
-
-/**
* i40e_get_pfc_stats - copy HW PFC statistics to formatted structure
* @pf: the PF device structure
* @i: the priority value to copy
@@ -1853,12 +1995,10 @@ static void i40e_get_ethtool_stats(struct net_device *netdev,
struct ethtool_stats *stats, u64 *data)
{
struct i40e_netdev_priv *np = netdev_priv(netdev);
- struct i40e_ring *tx_ring, *rx_ring;
struct i40e_vsi *vsi = np->vsi;
struct i40e_pf *pf = vsi->back;
struct i40e_veb *veb = pf->veb[pf->lan_veb];
unsigned int i;
- unsigned int start;
bool veb_stats;
u64 *p = data;
@@ -1870,38 +2010,12 @@ static void i40e_get_ethtool_stats(struct net_device *netdev,
i40e_add_ethtool_stats(&data, vsi, i40e_gstrings_misc_stats);
rcu_read_lock();
- for (i = 0; i < I40E_MAX_NUM_QUEUES(netdev) ; i++) {
- tx_ring = READ_ONCE(vsi->tx_rings[i]);
-
- if (!tx_ring) {
- /* Bump the stat counter to skip these stats, and make
- * sure the memory is zero'd
- */
- *(data++) = 0;
- *(data++) = 0;
- *(data++) = 0;
- *(data++) = 0;
- continue;
- }
-
- /* process Tx ring statistics */
- do {
- start = u64_stats_fetch_begin_irq(&tx_ring->syncp);
- data[0] = tx_ring->stats.packets;
- data[1] = tx_ring->stats.bytes;
- } while (u64_stats_fetch_retry_irq(&tx_ring->syncp, start));
- data += 2;
-
- /* Rx ring is the 2nd half of the queue pair */
- rx_ring = &tx_ring[1];
- do {
- start = u64_stats_fetch_begin_irq(&rx_ring->syncp);
- data[0] = rx_ring->stats.packets;
- data[1] = rx_ring->stats.bytes;
- } while (u64_stats_fetch_retry_irq(&rx_ring->syncp, start));
- data += 2;
+ for (i = 0; i < netdev->num_tx_queues; i++) {
+ i40e_add_queue_stats(&data, READ_ONCE(vsi->tx_rings[i]));
+ i40e_add_queue_stats(&data, READ_ONCE(vsi->rx_rings[i]));
}
rcu_read_unlock();
+
if (vsi != pf->vsi[pf->lan_vsi] || pf->hw.partition_id != 1)
goto check_data_pointer;
@@ -1933,42 +2047,6 @@ check_data_pointer:
}
/**
- * __i40e_add_stat_strings - copy stat strings into ethtool buffer
- * @p: ethtool supplied buffer
- * @stats: stat definitions array
- * @size: size of the stats array
- *
- * Format and copy the strings described by stats into the buffer pointed at
- * by p.
- **/
-static void __i40e_add_stat_strings(u8 **p, const struct i40e_stats stats[],
- const unsigned int size, ...)
-{
- unsigned int i;
-
- for (i = 0; i < size; i++) {
- va_list args;
-
- va_start(args, size);
- vsnprintf(*p, ETH_GSTRING_LEN, stats[i].stat_string, args);
- *p += ETH_GSTRING_LEN;
- va_end(args);
- }
-}
-
-/**
- * 40e_add_stat_strings - copy stat strings into ethtool buffer
- * @p: ethtool supplied buffer
- * @stats: stat definitions array
- *
- * Format and copy the strings described by the const static stats value into
- * the buffer pointed at by p. Assumes that stats can have ARRAY_SIZE called
- * for it.
- **/
-#define i40e_add_stat_strings(p, stats, ...) \
- __i40e_add_stat_strings(p, stats, ARRAY_SIZE(stats), ## __VA_ARGS__)
-
-/**
* i40e_get_stat_strings - copy stat strings into supplied buffer
* @netdev: the netdev to collect strings for
* @data: supplied buffer to copy strings into
@@ -1990,16 +2068,13 @@ static void i40e_get_stat_strings(struct net_device *netdev, u8 *data)
i40e_add_stat_strings(&data, i40e_gstrings_misc_stats);
- for (i = 0; i < I40E_MAX_NUM_QUEUES(netdev); i++) {
- snprintf(data, ETH_GSTRING_LEN, "tx-%u.tx_packets", i);
- data += ETH_GSTRING_LEN;
- snprintf(data, ETH_GSTRING_LEN, "tx-%u.tx_bytes", i);
- data += ETH_GSTRING_LEN;
- snprintf(data, ETH_GSTRING_LEN, "rx-%u.rx_packets", i);
- data += ETH_GSTRING_LEN;
- snprintf(data, ETH_GSTRING_LEN, "rx-%u.rx_bytes", i);
- data += ETH_GSTRING_LEN;
+ for (i = 0; i < netdev->num_tx_queues; i++) {
+ i40e_add_stat_strings(&data, i40e_gstrings_queue_stats,
+ "tx", i);
+ i40e_add_stat_strings(&data, i40e_gstrings_queue_stats,
+ "rx", i);
}
+
if (vsi != pf->vsi[pf->lan_vsi] || pf->hw.partition_id != 1)
return;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index ac685ad4d877..21c2688d6308 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -9,7 +9,9 @@
/* Local includes */
#include "i40e.h"
#include "i40e_diag.h"
+#include "i40e_xsk.h"
#include <net/udp_tunnel.h>
+#include <net/xdp_sock.h>
/* All i40e tracepoints are defined by the include below, which
* must be included exactly once across the whole kernel with
* CREATE_TRACE_POINTS defined
@@ -89,7 +91,7 @@ MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all), Debug mask (0x8XXXXXXX
MODULE_AUTHOR("Intel Corporation, <e1000-devel@lists.sourceforge.net>");
MODULE_DESCRIPTION("Intel(R) Ethernet Connection XL710 Network Driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_VERSION(DRV_VERSION);
static struct workqueue_struct *i40e_wq;
@@ -420,9 +422,9 @@ static void i40e_get_netdev_stats_struct(struct net_device *netdev,
struct rtnl_link_stats64 *stats)
{
struct i40e_netdev_priv *np = netdev_priv(netdev);
- struct i40e_ring *tx_ring, *rx_ring;
struct i40e_vsi *vsi = np->vsi;
struct rtnl_link_stats64 *vsi_stats = i40e_get_vsi_stats_struct(vsi);
+ struct i40e_ring *ring;
int i;
if (test_bit(__I40E_VSI_DOWN, vsi->state))
@@ -436,24 +438,26 @@ static void i40e_get_netdev_stats_struct(struct net_device *netdev,
u64 bytes, packets;
unsigned int start;
- tx_ring = READ_ONCE(vsi->tx_rings[i]);
- if (!tx_ring)
+ ring = READ_ONCE(vsi->tx_rings[i]);
+ if (!ring)
continue;
- i40e_get_netdev_stats_struct_tx(tx_ring, stats);
+ i40e_get_netdev_stats_struct_tx(ring, stats);
- rx_ring = &tx_ring[1];
+ if (i40e_enabled_xdp_vsi(vsi)) {
+ ring++;
+ i40e_get_netdev_stats_struct_tx(ring, stats);
+ }
+ ring++;
do {
- start = u64_stats_fetch_begin_irq(&rx_ring->syncp);
- packets = rx_ring->stats.packets;
- bytes = rx_ring->stats.bytes;
- } while (u64_stats_fetch_retry_irq(&rx_ring->syncp, start));
+ start = u64_stats_fetch_begin_irq(&ring->syncp);
+ packets = ring->stats.packets;
+ bytes = ring->stats.bytes;
+ } while (u64_stats_fetch_retry_irq(&ring->syncp, start));
stats->rx_packets += packets;
stats->rx_bytes += bytes;
- if (i40e_enabled_xdp_vsi(vsi))
- i40e_get_netdev_stats_struct_tx(&rx_ring[1], stats);
}
rcu_read_unlock();
@@ -1528,8 +1532,8 @@ static int i40e_set_mac(struct net_device *netdev, void *p)
return 0;
}
- if (test_bit(__I40E_VSI_DOWN, vsi->back->state) ||
- test_bit(__I40E_RESET_RECOVERY_PENDING, vsi->back->state))
+ if (test_bit(__I40E_DOWN, pf->state) ||
+ test_bit(__I40E_RESET_RECOVERY_PENDING, pf->state))
return -EADDRNOTAVAIL;
if (ether_addr_equal(hw->mac.addr, addr->sa_data))
@@ -1553,8 +1557,7 @@ static int i40e_set_mac(struct net_device *netdev, void *p)
if (vsi->type == I40E_VSI_MAIN) {
i40e_status ret;
- ret = i40e_aq_mac_address_write(&vsi->back->hw,
- I40E_AQC_WRITE_TYPE_LAA_WOL,
+ ret = i40e_aq_mac_address_write(hw, I40E_AQC_WRITE_TYPE_LAA_WOL,
addr->sa_data, NULL);
if (ret)
netdev_info(netdev, "Ignoring error from firmware on LAA update, status %s, AQ ret %s\n",
@@ -1565,7 +1568,7 @@ static int i40e_set_mac(struct net_device *netdev, void *p)
/* schedule our worker thread which will take care of
* applying the new filter changes
*/
- i40e_service_event_schedule(vsi->back);
+ i40e_service_event_schedule(pf);
return 0;
}
@@ -3072,6 +3075,9 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
i40e_status err = 0;
u32 qtx_ctl = 0;
+ if (ring_is_xdp(ring))
+ ring->xsk_umem = i40e_xsk_umem(ring);
+
/* some ATR related tx ring init */
if (vsi->back->flags & I40E_FLAG_FD_ATR_ENABLED) {
ring->atr_sample_rate = vsi->back->atr_sample_rate;
@@ -3181,13 +3187,46 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
struct i40e_hw *hw = &vsi->back->hw;
struct i40e_hmc_obj_rxq rx_ctx;
i40e_status err = 0;
+ bool ok;
+ int ret;
bitmap_zero(ring->state, __I40E_RING_STATE_NBITS);
/* clear the context structure first */
memset(&rx_ctx, 0, sizeof(rx_ctx));
- ring->rx_buf_len = vsi->rx_buf_len;
+ if (ring->vsi->type == I40E_VSI_MAIN)
+ xdp_rxq_info_unreg_mem_model(&ring->xdp_rxq);
+
+ ring->xsk_umem = i40e_xsk_umem(ring);
+ if (ring->xsk_umem) {
+ ring->rx_buf_len = ring->xsk_umem->chunk_size_nohr -
+ XDP_PACKET_HEADROOM;
+ /* 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;
+ ring->zca.free = i40e_zca_free;
+ ret = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
+ MEM_TYPE_ZERO_COPY,
+ &ring->zca);
+ if (ret)
+ return ret;
+ dev_info(&vsi->back->pdev->dev,
+ "Registered XDP mem model MEM_TYPE_ZERO_COPY on Rx ring %d\n",
+ ring->queue_index);
+
+ } else {
+ ring->rx_buf_len = vsi->rx_buf_len;
+ if (ring->vsi->type == I40E_VSI_MAIN) {
+ ret = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
+ MEM_TYPE_PAGE_SHARED,
+ NULL);
+ if (ret)
+ return ret;
+ }
+ }
rx_ctx.dbuff = DIV_ROUND_UP(ring->rx_buf_len,
BIT_ULL(I40E_RXQ_CTX_DBUFF_SHIFT));
@@ -3243,7 +3282,15 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
writel(0, ring->tail);
- i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
+ ok = ring->xsk_umem ?
+ i40e_alloc_rx_buffers_zc(ring, I40E_DESC_UNUSED(ring)) :
+ !i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
+ if (!ok) {
+ dev_info(&vsi->back->pdev->dev,
+ "Failed allocate some buffers on %sRx ring %d (pf_q %d)\n",
+ ring->xsk_umem ? "UMEM enabled " : "",
+ ring->queue_index, pf_q);
+ }
return 0;
}
@@ -6384,7 +6431,10 @@ void i40e_print_link_message(struct i40e_vsi *vsi, bool isup)
char *req_fec = "";
char *an = "";
- new_speed = pf->hw.phy.link_info.link_speed;
+ if (isup)
+ new_speed = pf->hw.phy.link_info.link_speed;
+ else
+ new_speed = I40E_LINK_SPEED_UNKNOWN;
if ((vsi->current_isup == isup) && (vsi->current_speed == new_speed))
return;
@@ -6568,6 +6618,24 @@ static i40e_status i40e_force_link_state(struct i40e_pf *pf, bool is_up)
struct i40e_hw *hw = &pf->hw;
i40e_status err;
u64 mask;
+ u8 speed;
+
+ /* Card might've been put in an unstable state by other drivers
+ * and applications, which causes incorrect speed values being
+ * set on startup. In order to clear speed registers, we call
+ * get_phy_capabilities twice, once to get initial state of
+ * available speeds, and once to get current PHY config.
+ */
+ err = i40e_aq_get_phy_capabilities(hw, false, true, &abilities,
+ NULL);
+ if (err) {
+ dev_err(&pf->pdev->dev,
+ "failed to get phy cap., ret = %s last_status = %s\n",
+ i40e_stat_str(hw, err),
+ i40e_aq_str(hw, hw->aq.asq_last_status));
+ return err;
+ }
+ speed = abilities.link_speed;
/* Get the current phy config */
err = i40e_aq_get_phy_capabilities(hw, false, false, &abilities,
@@ -6581,9 +6649,9 @@ static i40e_status i40e_force_link_state(struct i40e_pf *pf, bool is_up)
}
/* If link needs to go up, but was not forced to go down,
- * no need for a flap
+ * and its speed values are OK, no need for a flap
*/
- if (is_up && abilities.phy_type != 0)
+ if (is_up && abilities.phy_type != 0 && abilities.link_speed != 0)
return I40E_SUCCESS;
/* To force link we need to set bits for all supported PHY types,
@@ -6595,7 +6663,10 @@ static i40e_status i40e_force_link_state(struct i40e_pf *pf, bool is_up)
config.phy_type_ext = is_up ? (u8)((mask >> 32) & 0xff) : 0;
/* Copy the old settings, except of phy_type */
config.abilities = abilities.abilities;
- config.link_speed = abilities.link_speed;
+ if (abilities.link_speed != 0)
+ config.link_speed = abilities.link_speed;
+ else
+ config.link_speed = speed;
config.eee_capability = abilities.eee_capability;
config.eeer = abilities.eeer_val;
config.low_power_ctrl = abilities.d3_lpan;
@@ -8440,14 +8511,9 @@ static void i40e_link_event(struct i40e_pf *pf)
i40e_status status;
bool new_link, old_link;
- /* save off old link status information */
- pf->hw.phy.link_info_old = pf->hw.phy.link_info;
-
/* set this to force the get_link_status call to refresh state */
pf->hw.phy.get_link_info = true;
-
old_link = (pf->hw.phy.link_info_old.link_info & I40E_AQ_LINK_UP);
-
status = i40e_get_link_status(&pf->hw, &new_link);
/* On success, disable temp link polling */
@@ -11828,6 +11894,256 @@ static int i40e_xdp_setup(struct i40e_vsi *vsi,
}
/**
+ * i40e_enter_busy_conf - Enters busy config state
+ * @vsi: vsi
+ *
+ * Returns 0 on success, <0 for failure.
+ **/
+static int i40e_enter_busy_conf(struct i40e_vsi *vsi)
+{
+ struct i40e_pf *pf = vsi->back;
+ int timeout = 50;
+
+ while (test_and_set_bit(__I40E_CONFIG_BUSY, pf->state)) {
+ timeout--;
+ if (!timeout)
+ return -EBUSY;
+ usleep_range(1000, 2000);
+ }
+
+ return 0;
+}
+
+/**
+ * i40e_exit_busy_conf - Exits busy config state
+ * @vsi: vsi
+ **/
+static void i40e_exit_busy_conf(struct i40e_vsi *vsi)
+{
+ struct i40e_pf *pf = vsi->back;
+
+ clear_bit(__I40E_CONFIG_BUSY, pf->state);
+}
+
+/**
+ * i40e_queue_pair_reset_stats - Resets all statistics for a queue pair
+ * @vsi: vsi
+ * @queue_pair: queue pair
+ **/
+static void i40e_queue_pair_reset_stats(struct i40e_vsi *vsi, int queue_pair)
+{
+ memset(&vsi->rx_rings[queue_pair]->rx_stats, 0,
+ sizeof(vsi->rx_rings[queue_pair]->rx_stats));
+ memset(&vsi->tx_rings[queue_pair]->stats, 0,
+ sizeof(vsi->tx_rings[queue_pair]->stats));
+ if (i40e_enabled_xdp_vsi(vsi)) {
+ memset(&vsi->xdp_rings[queue_pair]->stats, 0,
+ sizeof(vsi->xdp_rings[queue_pair]->stats));
+ }
+}
+
+/**
+ * i40e_queue_pair_clean_rings - Cleans all the rings of a queue pair
+ * @vsi: vsi
+ * @queue_pair: queue pair
+ **/
+static void i40e_queue_pair_clean_rings(struct i40e_vsi *vsi, int queue_pair)
+{
+ i40e_clean_tx_ring(vsi->tx_rings[queue_pair]);
+ if (i40e_enabled_xdp_vsi(vsi))
+ i40e_clean_tx_ring(vsi->xdp_rings[queue_pair]);
+ i40e_clean_rx_ring(vsi->rx_rings[queue_pair]);
+}
+
+/**
+ * i40e_queue_pair_toggle_napi - Enables/disables NAPI for a queue pair
+ * @vsi: vsi
+ * @queue_pair: queue pair
+ * @enable: true for enable, false for disable
+ **/
+static void i40e_queue_pair_toggle_napi(struct i40e_vsi *vsi, int queue_pair,
+ bool enable)
+{
+ struct i40e_ring *rxr = vsi->rx_rings[queue_pair];
+ struct i40e_q_vector *q_vector = rxr->q_vector;
+
+ if (!vsi->netdev)
+ return;
+
+ /* All rings in a qp belong to the same qvector. */
+ if (q_vector->rx.ring || q_vector->tx.ring) {
+ if (enable)
+ napi_enable(&q_vector->napi);
+ else
+ napi_disable(&q_vector->napi);
+ }
+}
+
+/**
+ * i40e_queue_pair_toggle_rings - Enables/disables all rings for a queue pair
+ * @vsi: vsi
+ * @queue_pair: queue pair
+ * @enable: true for enable, false for disable
+ *
+ * Returns 0 on success, <0 on failure.
+ **/
+static int i40e_queue_pair_toggle_rings(struct i40e_vsi *vsi, int queue_pair,
+ bool enable)
+{
+ struct i40e_pf *pf = vsi->back;
+ int pf_q, ret = 0;
+
+ pf_q = vsi->base_queue + queue_pair;
+ ret = i40e_control_wait_tx_q(vsi->seid, pf, pf_q,
+ false /*is xdp*/, enable);
+ if (ret) {
+ dev_info(&pf->pdev->dev,
+ "VSI seid %d Tx ring %d %sable timeout\n",
+ vsi->seid, pf_q, (enable ? "en" : "dis"));
+ return ret;
+ }
+
+ i40e_control_rx_q(pf, pf_q, enable);
+ ret = i40e_pf_rxq_wait(pf, pf_q, enable);
+ if (ret) {
+ dev_info(&pf->pdev->dev,
+ "VSI seid %d Rx ring %d %sable timeout\n",
+ vsi->seid, pf_q, (enable ? "en" : "dis"));
+ return ret;
+ }
+
+ /* Due to HW errata, on Rx disable only, the register can
+ * indicate done before it really is. Needs 50ms to be sure
+ */
+ if (!enable)
+ mdelay(50);
+
+ if (!i40e_enabled_xdp_vsi(vsi))
+ return ret;
+
+ ret = i40e_control_wait_tx_q(vsi->seid, pf,
+ pf_q + vsi->alloc_queue_pairs,
+ true /*is xdp*/, enable);
+ if (ret) {
+ dev_info(&pf->pdev->dev,
+ "VSI seid %d XDP Tx ring %d %sable timeout\n",
+ vsi->seid, pf_q, (enable ? "en" : "dis"));
+ }
+
+ return ret;
+}
+
+/**
+ * i40e_queue_pair_enable_irq - Enables interrupts for a queue pair
+ * @vsi: vsi
+ * @queue_pair: queue_pair
+ **/
+static void i40e_queue_pair_enable_irq(struct i40e_vsi *vsi, int queue_pair)
+{
+ struct i40e_ring *rxr = vsi->rx_rings[queue_pair];
+ struct i40e_pf *pf = vsi->back;
+ struct i40e_hw *hw = &pf->hw;
+
+ /* All rings in a qp belong to the same qvector. */
+ if (pf->flags & I40E_FLAG_MSIX_ENABLED)
+ i40e_irq_dynamic_enable(vsi, rxr->q_vector->v_idx);
+ else
+ i40e_irq_dynamic_enable_icr0(pf);
+
+ i40e_flush(hw);
+}
+
+/**
+ * i40e_queue_pair_disable_irq - Disables interrupts for a queue pair
+ * @vsi: vsi
+ * @queue_pair: queue_pair
+ **/
+static void i40e_queue_pair_disable_irq(struct i40e_vsi *vsi, int queue_pair)
+{
+ struct i40e_ring *rxr = vsi->rx_rings[queue_pair];
+ struct i40e_pf *pf = vsi->back;
+ struct i40e_hw *hw = &pf->hw;
+
+ /* For simplicity, instead of removing the qp interrupt causes
+ * from the interrupt linked list, we simply disable the interrupt, and
+ * leave the list intact.
+ *
+ * All rings in a qp belong to the same qvector.
+ */
+ if (pf->flags & I40E_FLAG_MSIX_ENABLED) {
+ u32 intpf = vsi->base_vector + rxr->q_vector->v_idx;
+
+ wr32(hw, I40E_PFINT_DYN_CTLN(intpf - 1), 0);
+ i40e_flush(hw);
+ synchronize_irq(pf->msix_entries[intpf].vector);
+ } else {
+ /* Legacy and MSI mode - this stops all interrupt handling */
+ wr32(hw, I40E_PFINT_ICR0_ENA, 0);
+ wr32(hw, I40E_PFINT_DYN_CTL0, 0);
+ i40e_flush(hw);
+ synchronize_irq(pf->pdev->irq);
+ }
+}
+
+/**
+ * i40e_queue_pair_disable - Disables a queue pair
+ * @vsi: vsi
+ * @queue_pair: queue pair
+ *
+ * Returns 0 on success, <0 on failure.
+ **/
+int i40e_queue_pair_disable(struct i40e_vsi *vsi, int queue_pair)
+{
+ int err;
+
+ err = i40e_enter_busy_conf(vsi);
+ if (err)
+ return err;
+
+ i40e_queue_pair_disable_irq(vsi, queue_pair);
+ err = i40e_queue_pair_toggle_rings(vsi, queue_pair, false /* off */);
+ i40e_queue_pair_toggle_napi(vsi, queue_pair, false /* off */);
+ i40e_queue_pair_clean_rings(vsi, queue_pair);
+ i40e_queue_pair_reset_stats(vsi, queue_pair);
+
+ return err;
+}
+
+/**
+ * i40e_queue_pair_enable - Enables a queue pair
+ * @vsi: vsi
+ * @queue_pair: queue pair
+ *
+ * Returns 0 on success, <0 on failure.
+ **/
+int i40e_queue_pair_enable(struct i40e_vsi *vsi, int queue_pair)
+{
+ int err;
+
+ err = i40e_configure_tx_ring(vsi->tx_rings[queue_pair]);
+ if (err)
+ return err;
+
+ if (i40e_enabled_xdp_vsi(vsi)) {
+ err = i40e_configure_tx_ring(vsi->xdp_rings[queue_pair]);
+ if (err)
+ return err;
+ }
+
+ err = i40e_configure_rx_ring(vsi->rx_rings[queue_pair]);
+ if (err)
+ return err;
+
+ err = i40e_queue_pair_toggle_rings(vsi, queue_pair, true /* on */);
+ i40e_queue_pair_toggle_napi(vsi, queue_pair, true /* on */);
+ i40e_queue_pair_enable_irq(vsi, queue_pair);
+
+ i40e_exit_busy_conf(vsi);
+
+ return err;
+}
+
+/**
* i40e_xdp - implements ndo_bpf for i40e
* @dev: netdevice
* @xdp: XDP command
@@ -11847,6 +12163,12 @@ static int i40e_xdp(struct net_device *dev,
case XDP_QUERY_PROG:
xdp->prog_id = vsi->xdp_prog ? vsi->xdp_prog->aux->id : 0;
return 0;
+ case XDP_QUERY_XSK_UMEM:
+ return i40e_xsk_umem_query(vsi, &xdp->xsk.umem,
+ xdp->xsk.queue_id);
+ case XDP_SETUP_XSK_UMEM:
+ return i40e_xsk_umem_setup(vsi, xdp->xsk.umem,
+ xdp->xsk.queue_id);
default:
return -EINVAL;
}
@@ -11886,6 +12208,7 @@ static const struct net_device_ops i40e_netdev_ops = {
.ndo_bridge_setlink = i40e_ndo_bridge_setlink,
.ndo_bpf = i40e_xdp,
.ndo_xdp_xmit = i40e_xdp_xmit,
+ .ndo_xsk_async_xmit = i40e_xsk_async_xmit,
};
/**
@@ -11926,6 +12249,8 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
NETIF_F_GSO_GRE |
NETIF_F_GSO_GRE_CSUM |
NETIF_F_GSO_PARTIAL |
+ NETIF_F_GSO_IPXIP4 |
+ NETIF_F_GSO_IPXIP6 |
NETIF_F_GSO_UDP_TUNNEL |
NETIF_F_GSO_UDP_TUNNEL_CSUM |
NETIF_F_SCTP_CRC |
@@ -11943,13 +12268,13 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
/* record features VLANs can make use of */
netdev->vlan_features |= hw_enc_features | NETIF_F_TSO_MANGLEID;
- if (!(pf->flags & I40E_FLAG_MFP_ENABLED))
- netdev->hw_features |= NETIF_F_NTUPLE | NETIF_F_HW_TC;
-
hw_features = hw_enc_features |
NETIF_F_HW_VLAN_CTAG_TX |
NETIF_F_HW_VLAN_CTAG_RX;
+ if (!(pf->flags & I40E_FLAG_MFP_ENABLED))
+ hw_features |= NETIF_F_NTUPLE | NETIF_F_HW_TC;
+
netdev->hw_features |= hw_features;
netdev->features |= hw_features | NETIF_F_HW_VLAN_CTAG_FILTER;
@@ -13033,7 +13358,7 @@ struct i40e_veb *i40e_veb_setup(struct i40e_pf *pf, u16 flags,
for (vsi_idx = 0; vsi_idx < pf->num_alloc_vsi; vsi_idx++)
if (pf->vsi[vsi_idx] && pf->vsi[vsi_idx]->seid == vsi_seid)
break;
- if (vsi_idx >= pf->num_alloc_vsi && vsi_seid != 0) {
+ if (vsi_idx == pf->num_alloc_vsi && vsi_seid != 0) {
dev_info(&pf->pdev->dev, "vsi seid %d not found\n",
vsi_seid);
return NULL;
@@ -14159,6 +14484,7 @@ static void i40e_remove(struct pci_dev *pdev)
mutex_destroy(&hw->aq.asq_mutex);
/* Clear all dynamic memory lists of rings, q_vectors, and VSIs */
+ rtnl_lock();
i40e_clear_interrupt_scheme(pf);
for (i = 0; i < pf->num_alloc_vsi; i++) {
if (pf->vsi[i]) {
@@ -14167,6 +14493,7 @@ static void i40e_remove(struct pci_dev *pdev)
pf->vsi[i] = NULL;
}
}
+ rtnl_unlock();
for (i = 0; i < I40E_MAX_VEB; i++) {
kfree(pf->veb[i]);
@@ -14227,7 +14554,6 @@ static pci_ers_result_t i40e_pci_error_slot_reset(struct pci_dev *pdev)
{
struct i40e_pf *pf = pci_get_drvdata(pdev);
pci_ers_result_t result;
- int err;
u32 reg;
dev_dbg(&pdev->dev, "%s\n", __func__);
@@ -14248,14 +14574,6 @@ static pci_ers_result_t i40e_pci_error_slot_reset(struct pci_dev *pdev)
result = PCI_ERS_RESULT_DISCONNECT;
}
- err = pci_cleanup_aer_uncorrect_error_status(pdev);
- if (err) {
- dev_info(&pdev->dev,
- "pci_cleanup_aer_uncorrect_error_status failed 0x%0x\n",
- err);
- /* non-fatal, continue */
- }
-
return result;
}
@@ -14378,7 +14696,13 @@ static void i40e_shutdown(struct pci_dev *pdev)
wr32(hw, I40E_PFPM_WUFC,
(pf->wol_en ? I40E_PFPM_WUFC_MAG_MASK : 0));
+ /* Since we're going to destroy queues during the
+ * i40e_clear_interrupt_scheme() we should hold the RTNL lock for this
+ * whole section
+ */
+ rtnl_lock();
i40e_clear_interrupt_scheme(pf);
+ rtnl_unlock();
if (system_state == SYSTEM_POWER_OFF) {
pci_wake_from_d3(pdev, pf->wol_en);
diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c
index 35f2866b38c6..1199f0502d6d 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c
@@ -694,7 +694,8 @@ static long i40e_ptp_create_clock(struct i40e_pf *pf)
if (!IS_ERR_OR_NULL(pf->ptp_clock))
return 0;
- strncpy(pf->ptp_caps.name, i40e_driver_name, sizeof(pf->ptp_caps.name));
+ strncpy(pf->ptp_caps.name, i40e_driver_name,
+ sizeof(pf->ptp_caps.name) - 1);
pf->ptp_caps.owner = THIS_MODULE;
pf->ptp_caps.max_adj = 999999999;
pf->ptp_caps.n_ext_ts = 0;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
index b5042d1a63c0..aef3c89ee79c 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
@@ -2,22 +2,13 @@
/* Copyright(c) 2013 - 2018 Intel Corporation. */
#include <linux/prefetch.h>
-#include <net/busy_poll.h>
#include <linux/bpf_trace.h>
#include <net/xdp.h>
#include "i40e.h"
#include "i40e_trace.h"
#include "i40e_prototype.h"
-
-static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
- u32 td_tag)
-{
- return cpu_to_le64(I40E_TX_DESC_DTYPE_DATA |
- ((u64)td_cmd << I40E_TXD_QW1_CMD_SHIFT) |
- ((u64)td_offset << I40E_TXD_QW1_OFFSET_SHIFT) |
- ((u64)size << I40E_TXD_QW1_TX_BUF_SZ_SHIFT) |
- ((u64)td_tag << I40E_TXD_QW1_L2TAG1_SHIFT));
-}
+#include "i40e_txrx_common.h"
+#include "i40e_xsk.h"
#define I40E_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS)
/**
@@ -536,8 +527,8 @@ int i40e_add_del_fdir(struct i40e_vsi *vsi,
* This is used to verify if the FD programming or invalidation
* requested by SW to the HW is successful or not and take actions accordingly.
**/
-static void i40e_fd_handle_status(struct i40e_ring *rx_ring,
- union i40e_rx_desc *rx_desc, u8 prog_id)
+void i40e_fd_handle_status(struct i40e_ring *rx_ring,
+ union i40e_rx_desc *rx_desc, u8 prog_id)
{
struct i40e_pf *pf = rx_ring->vsi->back;
struct pci_dev *pdev = pf->pdev;
@@ -644,13 +635,18 @@ void i40e_clean_tx_ring(struct i40e_ring *tx_ring)
unsigned long bi_size;
u16 i;
- /* ring already cleared, nothing to do */
- if (!tx_ring->tx_bi)
- return;
+ if (ring_is_xdp(tx_ring) && tx_ring->xsk_umem) {
+ i40e_xsk_clean_tx_ring(tx_ring);
+ } else {
+ /* ring already cleared, nothing to do */
+ if (!tx_ring->tx_bi)
+ return;
- /* Free all the Tx ring sk_buffs */
- for (i = 0; i < tx_ring->count; i++)
- i40e_unmap_and_free_tx_resource(tx_ring, &tx_ring->tx_bi[i]);
+ /* Free all the Tx ring sk_buffs */
+ for (i = 0; i < tx_ring->count; i++)
+ i40e_unmap_and_free_tx_resource(tx_ring,
+ &tx_ring->tx_bi[i]);
+ }
bi_size = sizeof(struct i40e_tx_buffer) * tx_ring->count;
memset(tx_ring->tx_bi, 0, bi_size);
@@ -767,8 +763,6 @@ void i40e_detect_recover_hung(struct i40e_vsi *vsi)
}
}
-#define WB_STRIDE 4
-
/**
* i40e_clean_tx_irq - Reclaim resources after transmit completes
* @vsi: the VSI we care about
@@ -873,27 +867,8 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
i += tx_ring->count;
tx_ring->next_to_clean = i;
- u64_stats_update_begin(&tx_ring->syncp);
- tx_ring->stats.bytes += total_bytes;
- tx_ring->stats.packets += total_packets;
- u64_stats_update_end(&tx_ring->syncp);
- tx_ring->q_vector->tx.total_bytes += total_bytes;
- tx_ring->q_vector->tx.total_packets += total_packets;
-
- if (tx_ring->flags & I40E_TXR_FLAGS_WB_ON_ITR) {
- /* check to see if there are < 4 descriptors
- * waiting to be written back, then kick the hardware to force
- * them to be written back in case we stay in NAPI.
- * In this mode on X722 we do not enable Interrupt.
- */
- unsigned int j = i40e_get_tx_pending(tx_ring, false);
-
- if (budget &&
- ((j / WB_STRIDE) == 0) && (j > 0) &&
- !test_bit(__I40E_VSI_DOWN, vsi->state) &&
- (I40E_DESC_UNUSED(tx_ring) != tx_ring->count))
- tx_ring->arm_wb = true;
- }
+ i40e_update_tx_stats(tx_ring, total_packets, total_bytes);
+ i40e_arm_wb(tx_ring, vsi, budget);
if (ring_is_xdp(tx_ring))
return !!budget;
@@ -1244,6 +1219,11 @@ static void i40e_reuse_rx_page(struct i40e_ring *rx_ring,
new_buff->page = old_buff->page;
new_buff->page_offset = old_buff->page_offset;
new_buff->pagecnt_bias = old_buff->pagecnt_bias;
+
+ rx_ring->rx_stats.page_reuse_count++;
+
+ /* clear contents of buffer_info */
+ old_buff->page = NULL;
}
/**
@@ -1266,7 +1246,7 @@ static inline bool i40e_rx_is_programming_status(u64 qw)
}
/**
- * i40e_clean_programming_status - clean the programming status descriptor
+ * i40e_clean_programming_status - try clean the programming status descriptor
* @rx_ring: the rx ring that has this descriptor
* @rx_desc: the rx descriptor written back by HW
* @qw: qword representing status_error_len in CPU ordering
@@ -1275,15 +1255,22 @@ static inline bool i40e_rx_is_programming_status(u64 qw)
* status being successful or not and take actions accordingly. FCoE should
* handle its context/filter programming/invalidation status and take actions.
*
+ * Returns an i40e_rx_buffer to reuse if the cleanup occurred, otherwise NULL.
**/
-static void i40e_clean_programming_status(struct i40e_ring *rx_ring,
- union i40e_rx_desc *rx_desc,
- u64 qw)
+struct i40e_rx_buffer *i40e_clean_programming_status(
+ struct i40e_ring *rx_ring,
+ union i40e_rx_desc *rx_desc,
+ u64 qw)
{
struct i40e_rx_buffer *rx_buffer;
- u32 ntc = rx_ring->next_to_clean;
+ u32 ntc;
u8 id;
+ if (!i40e_rx_is_programming_status(qw))
+ return NULL;
+
+ ntc = rx_ring->next_to_clean;
+
/* fetch, update, and store next to clean */
rx_buffer = &rx_ring->rx_bi[ntc++];
ntc = (ntc < rx_ring->count) ? ntc : 0;
@@ -1291,18 +1278,13 @@ static void i40e_clean_programming_status(struct i40e_ring *rx_ring,
prefetch(I40E_RX_DESC(rx_ring, ntc));
- /* place unused page back on the ring */
- i40e_reuse_rx_page(rx_ring, rx_buffer);
- rx_ring->rx_stats.page_reuse_count++;
-
- /* clear contents of buffer_info */
- rx_buffer->page = NULL;
-
id = (qw & I40E_RX_PROG_STATUS_DESC_QW1_PROGID_MASK) >>
I40E_RX_PROG_STATUS_DESC_QW1_PROGID_SHIFT;
if (id == I40E_RX_PROG_STATUS_DESC_FD_FILTER_STATUS)
i40e_fd_handle_status(rx_ring, rx_desc, id);
+
+ return rx_buffer;
}
/**
@@ -1372,6 +1354,11 @@ void i40e_clean_rx_ring(struct i40e_ring *rx_ring)
rx_ring->skb = NULL;
}
+ if (rx_ring->xsk_umem) {
+ i40e_xsk_clean_rx_ring(rx_ring);
+ goto skip_free;
+ }
+
/* Free all the Rx ring sk_buffs */
for (i = 0; i < rx_ring->count; i++) {
struct i40e_rx_buffer *rx_bi = &rx_ring->rx_bi[i];
@@ -1400,6 +1387,7 @@ void i40e_clean_rx_ring(struct i40e_ring *rx_ring)
rx_bi->page_offset = 0;
}
+skip_free:
bi_size = sizeof(struct i40e_rx_buffer) * rx_ring->count;
memset(rx_ring->rx_bi, 0, bi_size);
@@ -1492,7 +1480,7 @@ err:
* @rx_ring: ring to bump
* @val: new head index
**/
-static inline void i40e_release_rx_desc(struct i40e_ring *rx_ring, u32 val)
+void i40e_release_rx_desc(struct i40e_ring *rx_ring, u32 val)
{
rx_ring->next_to_use = val;
@@ -1576,8 +1564,8 @@ static bool i40e_alloc_mapped_page(struct i40e_ring *rx_ring,
* @skb: packet to send up
* @vlan_tag: vlan tag for packet
**/
-static void i40e_receive_skb(struct i40e_ring *rx_ring,
- struct sk_buff *skb, u16 vlan_tag)
+void i40e_receive_skb(struct i40e_ring *rx_ring,
+ struct sk_buff *skb, u16 vlan_tag)
{
struct i40e_q_vector *q_vector = rx_ring->q_vector;
@@ -1804,7 +1792,6 @@ static inline void i40e_rx_hash(struct i40e_ring *ring,
* order to populate the hash, checksum, VLAN, protocol, and
* other fields within the skb.
**/
-static inline
void i40e_process_skb_fields(struct i40e_ring *rx_ring,
union i40e_rx_desc *rx_desc, struct sk_buff *skb,
u8 rx_ptype)
@@ -2152,7 +2139,6 @@ static void i40e_put_rx_buffer(struct i40e_ring *rx_ring,
if (i40e_can_reuse_rx_page(rx_buffer)) {
/* hand second half of page back to the ring */
i40e_reuse_rx_page(rx_ring, rx_buffer);
- rx_ring->rx_stats.page_reuse_count++;
} else {
/* we are not reusing the buffer so unmap it */
dma_unmap_page_attrs(rx_ring->dev, rx_buffer->dma,
@@ -2160,10 +2146,9 @@ static void i40e_put_rx_buffer(struct i40e_ring *rx_ring,
DMA_FROM_DEVICE, I40E_RX_DMA_ATTR);
__page_frag_cache_drain(rx_buffer->page,
rx_buffer->pagecnt_bias);
+ /* clear contents of buffer_info */
+ rx_buffer->page = NULL;
}
-
- /* clear contents of buffer_info */
- rx_buffer->page = NULL;
}
/**
@@ -2199,16 +2184,10 @@ static bool i40e_is_non_eop(struct i40e_ring *rx_ring,
return true;
}
-#define I40E_XDP_PASS 0
-#define I40E_XDP_CONSUMED BIT(0)
-#define I40E_XDP_TX BIT(1)
-#define I40E_XDP_REDIR BIT(2)
-
static int i40e_xmit_xdp_ring(struct xdp_frame *xdpf,
struct i40e_ring *xdp_ring);
-static int i40e_xmit_xdp_tx_ring(struct xdp_buff *xdp,
- struct i40e_ring *xdp_ring)
+int i40e_xmit_xdp_tx_ring(struct xdp_buff *xdp, struct i40e_ring *xdp_ring)
{
struct xdp_frame *xdpf = convert_to_xdp_frame(xdp);
@@ -2287,7 +2266,13 @@ static void i40e_rx_buffer_flip(struct i40e_ring *rx_ring,
#endif
}
-static inline void i40e_xdp_ring_update_tail(struct i40e_ring *xdp_ring)
+/**
+ * i40e_xdp_ring_update_tail - Updates the XDP Tx ring tail register
+ * @xdp_ring: XDP Tx ring
+ *
+ * This function updates the XDP Tx ring tail register.
+ **/
+void i40e_xdp_ring_update_tail(struct i40e_ring *xdp_ring)
{
/* Force memory writes to complete before letting h/w
* know there are new descriptors to fetch.
@@ -2297,6 +2282,48 @@ static inline void i40e_xdp_ring_update_tail(struct i40e_ring *xdp_ring)
}
/**
+ * i40e_update_rx_stats - Update Rx ring statistics
+ * @rx_ring: rx descriptor ring
+ * @total_rx_bytes: number of bytes received
+ * @total_rx_packets: number of packets received
+ *
+ * This function updates the Rx ring statistics.
+ **/
+void i40e_update_rx_stats(struct i40e_ring *rx_ring,
+ unsigned int total_rx_bytes,
+ unsigned int total_rx_packets)
+{
+ u64_stats_update_begin(&rx_ring->syncp);
+ rx_ring->stats.packets += total_rx_packets;
+ rx_ring->stats.bytes += total_rx_bytes;
+ u64_stats_update_end(&rx_ring->syncp);
+ rx_ring->q_vector->rx.total_packets += total_rx_packets;
+ rx_ring->q_vector->rx.total_bytes += total_rx_bytes;
+}
+
+/**
+ * i40e_finalize_xdp_rx - Bump XDP Tx tail and/or flush redirect map
+ * @rx_ring: Rx ring
+ * @xdp_res: Result of the receive batch
+ *
+ * This function bumps XDP Tx tail and/or flush redirect map, and
+ * should be called when a batch of packets has been processed in the
+ * napi loop.
+ **/
+void i40e_finalize_xdp_rx(struct i40e_ring *rx_ring, unsigned int xdp_res)
+{
+ if (xdp_res & I40E_XDP_REDIR)
+ xdp_do_flush_map();
+
+ if (xdp_res & I40E_XDP_TX) {
+ struct i40e_ring *xdp_ring =
+ rx_ring->vsi->xdp_rings[rx_ring->queue_index];
+
+ i40e_xdp_ring_update_tail(xdp_ring);
+ }
+}
+
+/**
* i40e_clean_rx_irq - Clean completed descriptors from Rx ring - bounce buf
* @rx_ring: rx descriptor ring to transact packets on
* @budget: Total limit on number of packets to process
@@ -2349,11 +2376,14 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
*/
dma_rmb();
- if (unlikely(i40e_rx_is_programming_status(qword))) {
- i40e_clean_programming_status(rx_ring, rx_desc, qword);
+ rx_buffer = i40e_clean_programming_status(rx_ring, rx_desc,
+ qword);
+ if (unlikely(rx_buffer)) {
+ i40e_reuse_rx_page(rx_ring, rx_buffer);
cleaned_count++;
continue;
}
+
size = (qword & I40E_RXD_QW1_LENGTH_PBUF_MASK) >>
I40E_RXD_QW1_LENGTH_PBUF_SHIFT;
if (!size)
@@ -2432,24 +2462,10 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
total_rx_packets++;
}
- if (xdp_xmit & I40E_XDP_REDIR)
- xdp_do_flush_map();
-
- if (xdp_xmit & I40E_XDP_TX) {
- struct i40e_ring *xdp_ring =
- rx_ring->vsi->xdp_rings[rx_ring->queue_index];
-
- i40e_xdp_ring_update_tail(xdp_ring);
- }
-
+ i40e_finalize_xdp_rx(rx_ring, xdp_xmit);
rx_ring->skb = skb;
- u64_stats_update_begin(&rx_ring->syncp);
- rx_ring->stats.packets += total_rx_packets;
- rx_ring->stats.bytes += total_rx_bytes;
- u64_stats_update_end(&rx_ring->syncp);
- rx_ring->q_vector->rx.total_packets += total_rx_packets;
- rx_ring->q_vector->rx.total_bytes += total_rx_bytes;
+ i40e_update_rx_stats(rx_ring, total_rx_bytes, total_rx_packets);
/* guarantee a trip back through this routine if there was a failure */
return failure ? budget : (int)total_rx_packets;
@@ -2587,7 +2603,11 @@ int i40e_napi_poll(struct napi_struct *napi, int budget)
* budget and be more aggressive about cleaning up the Tx descriptors.
*/
i40e_for_each_ring(ring, q_vector->tx) {
- if (!i40e_clean_tx_irq(vsi, ring, budget)) {
+ bool wd = ring->xsk_umem ?
+ i40e_clean_xdp_tx_irq(vsi, ring, budget) :
+ i40e_clean_tx_irq(vsi, ring, budget);
+
+ if (!wd) {
clean_complete = false;
continue;
}
@@ -2605,7 +2625,9 @@ int i40e_napi_poll(struct napi_struct *napi, int budget)
budget_per_ring = max(budget/q_vector->num_ringpairs, 1);
i40e_for_each_ring(ring, q_vector->rx) {
- int cleaned = i40e_clean_rx_irq(ring, budget_per_ring);
+ int cleaned = ring->xsk_umem ?
+ i40e_clean_rx_irq_zc(ring, budget_per_ring) :
+ i40e_clean_rx_irq(ring, budget_per_ring);
work_done += cleaned;
/* if we clean as many as budgeted, we must not be done */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h
index bb04f6a731fe..100e92d2982f 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h
@@ -296,13 +296,17 @@ struct i40e_tx_buffer {
struct i40e_rx_buffer {
dma_addr_t dma;
- struct page *page;
-#if (BITS_PER_LONG > 32) || (PAGE_SIZE >= 65536)
- __u32 page_offset;
-#else
- __u16 page_offset;
-#endif
- __u16 pagecnt_bias;
+ union {
+ struct {
+ struct page *page;
+ __u32 page_offset;
+ __u16 pagecnt_bias;
+ };
+ struct {
+ void *addr;
+ u64 handle;
+ };
+ };
};
struct i40e_queue_stats {
@@ -414,6 +418,8 @@ struct i40e_ring {
struct i40e_channel *ch;
struct xdp_rxq_info xdp_rxq;
+ struct xdp_umem *xsk_umem;
+ struct zero_copy_allocator zca; /* ZC allocator anchor */
} ____cacheline_internodealigned_in_smp;
static inline bool ring_uses_build_skb(struct i40e_ring *ring)
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx_common.h b/drivers/net/ethernet/intel/i40e/i40e_txrx_common.h
new file mode 100644
index 000000000000..09809dffe399
--- /dev/null
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx_common.h
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2018 Intel Corporation. */
+
+#ifndef I40E_TXRX_COMMON_
+#define I40E_TXRX_COMMON_
+
+void i40e_fd_handle_status(struct i40e_ring *rx_ring,
+ union i40e_rx_desc *rx_desc, u8 prog_id);
+int i40e_xmit_xdp_tx_ring(struct xdp_buff *xdp, struct i40e_ring *xdp_ring);
+struct i40e_rx_buffer *i40e_clean_programming_status(
+ struct i40e_ring *rx_ring,
+ union i40e_rx_desc *rx_desc,
+ u64 qw);
+void i40e_process_skb_fields(struct i40e_ring *rx_ring,
+ union i40e_rx_desc *rx_desc, struct sk_buff *skb,
+ u8 rx_ptype);
+void i40e_receive_skb(struct i40e_ring *rx_ring,
+ struct sk_buff *skb, u16 vlan_tag);
+void i40e_xdp_ring_update_tail(struct i40e_ring *xdp_ring);
+void i40e_update_rx_stats(struct i40e_ring *rx_ring,
+ unsigned int total_rx_bytes,
+ unsigned int total_rx_packets);
+void i40e_finalize_xdp_rx(struct i40e_ring *rx_ring, unsigned int xdp_res);
+void i40e_release_rx_desc(struct i40e_ring *rx_ring, u32 val);
+
+#define I40E_XDP_PASS 0
+#define I40E_XDP_CONSUMED BIT(0)
+#define I40E_XDP_TX BIT(1)
+#define I40E_XDP_REDIR BIT(2)
+
+/**
+ * build_ctob - Builds the Tx descriptor (cmd, offset and type) qword
+ **/
+static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
+ u32 td_tag)
+{
+ return cpu_to_le64(I40E_TX_DESC_DTYPE_DATA |
+ ((u64)td_cmd << I40E_TXD_QW1_CMD_SHIFT) |
+ ((u64)td_offset << I40E_TXD_QW1_OFFSET_SHIFT) |
+ ((u64)size << I40E_TXD_QW1_TX_BUF_SZ_SHIFT) |
+ ((u64)td_tag << I40E_TXD_QW1_L2TAG1_SHIFT));
+}
+
+/**
+ * i40e_update_tx_stats - Update the egress statistics for the Tx ring
+ * @tx_ring: Tx ring to update
+ * @total_packet: total packets sent
+ * @total_bytes: total bytes sent
+ **/
+static inline void i40e_update_tx_stats(struct i40e_ring *tx_ring,
+ unsigned int total_packets,
+ unsigned int total_bytes)
+{
+ u64_stats_update_begin(&tx_ring->syncp);
+ tx_ring->stats.bytes += total_bytes;
+ tx_ring->stats.packets += total_packets;
+ u64_stats_update_end(&tx_ring->syncp);
+ tx_ring->q_vector->tx.total_bytes += total_bytes;
+ tx_ring->q_vector->tx.total_packets += total_packets;
+}
+
+#define WB_STRIDE 4
+
+/**
+ * i40e_arm_wb - (Possibly) arms Tx write-back
+ * @tx_ring: Tx ring to update
+ * @vsi: the VSI
+ * @budget: the NAPI budget left
+ **/
+static inline void i40e_arm_wb(struct i40e_ring *tx_ring,
+ struct i40e_vsi *vsi,
+ int budget)
+{
+ if (tx_ring->flags & I40E_TXR_FLAGS_WB_ON_ITR) {
+ /* check to see if there are < 4 descriptors
+ * waiting to be written back, then kick the hardware to force
+ * them to be written back in case we stay in NAPI.
+ * In this mode on X722 we do not enable Interrupt.
+ */
+ unsigned int j = i40e_get_tx_pending(tx_ring, false);
+
+ if (budget &&
+ ((j / WB_STRIDE) == 0) && j > 0 &&
+ !test_bit(__I40E_VSI_DOWN, vsi->state) &&
+ (I40E_DESC_UNUSED(tx_ring) != tx_ring->count))
+ tx_ring->arm_wb = true;
+ }
+}
+
+void i40e_xsk_clean_rx_ring(struct i40e_ring *rx_ring);
+void i40e_xsk_clean_tx_ring(struct i40e_ring *tx_ring);
+bool i40e_xsk_any_rx_ring_enabled(struct i40e_vsi *vsi);
+
+#endif /* I40E_TXRX_COMMON_ */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
index c6d24eaede18..ac5698ed0b11 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
@@ -1084,6 +1084,136 @@ static int i40e_quiesce_vf_pci(struct i40e_vf *vf)
return -EIO;
}
+static inline int i40e_getnum_vf_vsi_vlan_filters(struct i40e_vsi *vsi);
+
+/**
+ * i40e_config_vf_promiscuous_mode
+ * @vf: pointer to the VF info
+ * @vsi_id: VSI id
+ * @allmulti: set MAC L2 layer multicast promiscuous enable/disable
+ * @alluni: set MAC L2 layer unicast promiscuous enable/disable
+ *
+ * Called from the VF to configure the promiscuous mode of
+ * VF vsis and from the VF reset path to reset promiscuous mode.
+ **/
+static i40e_status i40e_config_vf_promiscuous_mode(struct i40e_vf *vf,
+ u16 vsi_id,
+ bool allmulti,
+ bool alluni)
+{
+ struct i40e_pf *pf = vf->pf;
+ struct i40e_hw *hw = &pf->hw;
+ struct i40e_mac_filter *f;
+ i40e_status aq_ret = 0;
+ struct i40e_vsi *vsi;
+ int bkt;
+
+ vsi = i40e_find_vsi_from_id(pf, vsi_id);
+ if (!i40e_vc_isvalid_vsi_id(vf, vsi_id) || !vsi)
+ return I40E_ERR_PARAM;
+
+ if (!test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps)) {
+ dev_err(&pf->pdev->dev,
+ "Unprivileged VF %d is attempting to configure promiscuous mode\n",
+ vf->vf_id);
+ /* Lie to the VF on purpose. */
+ return 0;
+ }
+
+ if (vf->port_vlan_id) {
+ aq_ret = i40e_aq_set_vsi_mc_promisc_on_vlan(hw, vsi->seid,
+ allmulti,
+ vf->port_vlan_id,
+ NULL);
+ if (aq_ret) {
+ int aq_err = pf->hw.aq.asq_last_status;
+
+ dev_err(&pf->pdev->dev,
+ "VF %d failed to set multicast promiscuous mode err %s aq_err %s\n",
+ vf->vf_id,
+ i40e_stat_str(&pf->hw, aq_ret),
+ i40e_aq_str(&pf->hw, aq_err));
+ return aq_ret;
+ }
+
+ aq_ret = i40e_aq_set_vsi_uc_promisc_on_vlan(hw, vsi->seid,
+ alluni,
+ vf->port_vlan_id,
+ NULL);
+ if (aq_ret) {
+ int aq_err = pf->hw.aq.asq_last_status;
+
+ dev_err(&pf->pdev->dev,
+ "VF %d failed to set unicast promiscuous mode err %s aq_err %s\n",
+ vf->vf_id,
+ i40e_stat_str(&pf->hw, aq_ret),
+ i40e_aq_str(&pf->hw, aq_err));
+ }
+ return aq_ret;
+ } else if (i40e_getnum_vf_vsi_vlan_filters(vsi)) {
+ hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) {
+ if (f->vlan < 0 || f->vlan > I40E_MAX_VLANID)
+ continue;
+ aq_ret = i40e_aq_set_vsi_mc_promisc_on_vlan(hw,
+ vsi->seid,
+ allmulti,
+ f->vlan,
+ NULL);
+ if (aq_ret) {
+ int aq_err = pf->hw.aq.asq_last_status;
+
+ dev_err(&pf->pdev->dev,
+ "Could not add VLAN %d to multicast promiscuous domain err %s aq_err %s\n",
+ f->vlan,
+ i40e_stat_str(&pf->hw, aq_ret),
+ i40e_aq_str(&pf->hw, aq_err));
+ }
+
+ aq_ret = i40e_aq_set_vsi_uc_promisc_on_vlan(hw,
+ vsi->seid,
+ alluni,
+ f->vlan,
+ NULL);
+ if (aq_ret) {
+ int aq_err = pf->hw.aq.asq_last_status;
+
+ dev_err(&pf->pdev->dev,
+ "Could not add VLAN %d to Unicast promiscuous domain err %s aq_err %s\n",
+ f->vlan,
+ i40e_stat_str(&pf->hw, aq_ret),
+ i40e_aq_str(&pf->hw, aq_err));
+ }
+ }
+ return aq_ret;
+ }
+ aq_ret = i40e_aq_set_vsi_multicast_promiscuous(hw, vsi->seid, allmulti,
+ NULL);
+ if (aq_ret) {
+ int aq_err = pf->hw.aq.asq_last_status;
+
+ dev_err(&pf->pdev->dev,
+ "VF %d failed to set multicast promiscuous mode err %s aq_err %s\n",
+ vf->vf_id,
+ i40e_stat_str(&pf->hw, aq_ret),
+ i40e_aq_str(&pf->hw, aq_err));
+ return aq_ret;
+ }
+
+ aq_ret = i40e_aq_set_vsi_unicast_promiscuous(hw, vsi->seid, alluni,
+ NULL, true);
+ if (aq_ret) {
+ int aq_err = pf->hw.aq.asq_last_status;
+
+ dev_err(&pf->pdev->dev,
+ "VF %d failed to set unicast promiscuous mode err %s aq_err %s\n",
+ vf->vf_id,
+ i40e_stat_str(&pf->hw, aq_ret),
+ i40e_aq_str(&pf->hw, aq_err));
+ }
+
+ return aq_ret;
+}
+
/**
* i40e_trigger_vf_reset
* @vf: pointer to the VF structure
@@ -1145,6 +1275,9 @@ static void i40e_cleanup_reset_vf(struct i40e_vf *vf)
struct i40e_hw *hw = &pf->hw;
u32 reg;
+ /* disable promisc modes in case they were enabled */
+ i40e_config_vf_promiscuous_mode(vf, vf->lan_vsi_id, false, false);
+
/* free VF resources to begin resetting the VSI state */
i40e_free_vf_res(vf);
@@ -1840,143 +1973,55 @@ static inline int i40e_getnum_vf_vsi_vlan_filters(struct i40e_vsi *vsi)
* i40e_vc_config_promiscuous_mode_msg
* @vf: pointer to the VF info
* @msg: pointer to the msg buffer
- * @msglen: msg length
*
* called from the VF to configure the promiscuous mode of
* VF vsis
**/
-static int i40e_vc_config_promiscuous_mode_msg(struct i40e_vf *vf,
- u8 *msg, u16 msglen)
+static int i40e_vc_config_promiscuous_mode_msg(struct i40e_vf *vf, u8 *msg)
{
struct virtchnl_promisc_info *info =
(struct virtchnl_promisc_info *)msg;
struct i40e_pf *pf = vf->pf;
- struct i40e_hw *hw = &pf->hw;
- struct i40e_mac_filter *f;
i40e_status aq_ret = 0;
bool allmulti = false;
- struct i40e_vsi *vsi;
bool alluni = false;
- int aq_err = 0;
- int bkt;
- vsi = i40e_find_vsi_from_id(pf, info->vsi_id);
- if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) ||
- !i40e_vc_isvalid_vsi_id(vf, info->vsi_id) ||
- !vsi) {
- aq_ret = I40E_ERR_PARAM;
- goto error_param;
- }
- if (!test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps)) {
- dev_err(&pf->pdev->dev,
- "Unprivileged VF %d is attempting to configure promiscuous mode\n",
- vf->vf_id);
- /* Lie to the VF on purpose. */
- aq_ret = 0;
- goto error_param;
- }
+ if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states))
+ return I40E_ERR_PARAM;
+
/* Multicast promiscuous handling*/
if (info->flags & FLAG_VF_MULTICAST_PROMISC)
allmulti = true;
- if (vf->port_vlan_id) {
- aq_ret = i40e_aq_set_vsi_mc_promisc_on_vlan(hw, vsi->seid,
- allmulti,
- vf->port_vlan_id,
- NULL);
- } else if (i40e_getnum_vf_vsi_vlan_filters(vsi)) {
- hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) {
- if (f->vlan < 0 || f->vlan > I40E_MAX_VLANID)
- continue;
- aq_ret = i40e_aq_set_vsi_mc_promisc_on_vlan(hw,
- vsi->seid,
- allmulti,
- f->vlan,
- NULL);
- aq_err = pf->hw.aq.asq_last_status;
- if (aq_ret) {
- dev_err(&pf->pdev->dev,
- "Could not add VLAN %d to multicast promiscuous domain err %s aq_err %s\n",
- f->vlan,
- i40e_stat_str(&pf->hw, aq_ret),
- i40e_aq_str(&pf->hw, aq_err));
- break;
- }
- }
- } else {
- aq_ret = i40e_aq_set_vsi_multicast_promiscuous(hw, vsi->seid,
- allmulti, NULL);
- aq_err = pf->hw.aq.asq_last_status;
- if (aq_ret) {
- dev_err(&pf->pdev->dev,
- "VF %d failed to set multicast promiscuous mode err %s aq_err %s\n",
- vf->vf_id,
- i40e_stat_str(&pf->hw, aq_ret),
- i40e_aq_str(&pf->hw, aq_err));
- goto error_param;
- }
- }
-
+ if (info->flags & FLAG_VF_UNICAST_PROMISC)
+ alluni = true;
+ aq_ret = i40e_config_vf_promiscuous_mode(vf, info->vsi_id, allmulti,
+ alluni);
if (!aq_ret) {
- dev_info(&pf->pdev->dev,
- "VF %d successfully set multicast promiscuous mode\n",
- vf->vf_id);
- if (allmulti)
+ if (allmulti) {
+ dev_info(&pf->pdev->dev,
+ "VF %d successfully set multicast promiscuous mode\n",
+ vf->vf_id);
set_bit(I40E_VF_STATE_MC_PROMISC, &vf->vf_states);
- else
+ } else {
+ dev_info(&pf->pdev->dev,
+ "VF %d successfully unset multicast promiscuous mode\n",
+ vf->vf_id);
clear_bit(I40E_VF_STATE_MC_PROMISC, &vf->vf_states);
- }
-
- if (info->flags & FLAG_VF_UNICAST_PROMISC)
- alluni = true;
- if (vf->port_vlan_id) {
- aq_ret = i40e_aq_set_vsi_uc_promisc_on_vlan(hw, vsi->seid,
- alluni,
- vf->port_vlan_id,
- NULL);
- } else if (i40e_getnum_vf_vsi_vlan_filters(vsi)) {
- hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) {
- if (f->vlan < 0 || f->vlan > I40E_MAX_VLANID)
- continue;
- aq_ret = i40e_aq_set_vsi_uc_promisc_on_vlan(hw,
- vsi->seid,
- alluni,
- f->vlan,
- NULL);
- aq_err = pf->hw.aq.asq_last_status;
- if (aq_ret)
- dev_err(&pf->pdev->dev,
- "Could not add VLAN %d to Unicast promiscuous domain err %s aq_err %s\n",
- f->vlan,
- i40e_stat_str(&pf->hw, aq_ret),
- i40e_aq_str(&pf->hw, aq_err));
- }
- } else {
- aq_ret = i40e_aq_set_vsi_unicast_promiscuous(hw, vsi->seid,
- alluni, NULL,
- true);
- aq_err = pf->hw.aq.asq_last_status;
- if (aq_ret) {
- dev_err(&pf->pdev->dev,
- "VF %d failed to set unicast promiscuous mode %8.8x err %s aq_err %s\n",
- vf->vf_id, info->flags,
- i40e_stat_str(&pf->hw, aq_ret),
- i40e_aq_str(&pf->hw, aq_err));
- goto error_param;
}
- }
-
- if (!aq_ret) {
- dev_info(&pf->pdev->dev,
- "VF %d successfully set unicast promiscuous mode\n",
- vf->vf_id);
- if (alluni)
+ if (alluni) {
+ dev_info(&pf->pdev->dev,
+ "VF %d successfully set unicast promiscuous mode\n",
+ vf->vf_id);
set_bit(I40E_VF_STATE_UC_PROMISC, &vf->vf_states);
- else
+ } else {
+ dev_info(&pf->pdev->dev,
+ "VF %d successfully unset unicast promiscuous mode\n",
+ vf->vf_id);
clear_bit(I40E_VF_STATE_UC_PROMISC, &vf->vf_states);
+ }
}
-error_param:
/* send the response to the VF */
return i40e_vc_send_resp_to_vf(vf,
VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE,
@@ -1987,12 +2032,11 @@ error_param:
* i40e_vc_config_queues_msg
* @vf: pointer to the VF info
* @msg: pointer to the msg buffer
- * @msglen: msg length
*
* called from the VF to configure the rx/tx
* queues
**/
-static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
+static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg)
{
struct virtchnl_vsi_queue_config_info *qci =
(struct virtchnl_vsi_queue_config_info *)msg;
@@ -2105,12 +2149,11 @@ static int i40e_validate_queue_map(struct i40e_vf *vf, u16 vsi_id,
* i40e_vc_config_irq_map_msg
* @vf: pointer to the VF info
* @msg: pointer to the msg buffer
- * @msglen: msg length
*
* called from the VF to configure the irq to
* queue map
**/
-static int i40e_vc_config_irq_map_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
+static int i40e_vc_config_irq_map_msg(struct i40e_vf *vf, u8 *msg)
{
struct virtchnl_irq_map_info *irqmap_info =
(struct virtchnl_irq_map_info *)msg;
@@ -2202,11 +2245,10 @@ static int i40e_ctrl_vf_rx_rings(struct i40e_vsi *vsi, unsigned long q_map,
* i40e_vc_enable_queues_msg
* @vf: pointer to the VF info
* @msg: pointer to the msg buffer
- * @msglen: msg length
*
* called from the VF to enable all or specific queue(s)
**/
-static int i40e_vc_enable_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
+static int i40e_vc_enable_queues_msg(struct i40e_vf *vf, u8 *msg)
{
struct virtchnl_queue_select *vqs =
(struct virtchnl_queue_select *)msg;
@@ -2261,12 +2303,11 @@ error_param:
* i40e_vc_disable_queues_msg
* @vf: pointer to the VF info
* @msg: pointer to the msg buffer
- * @msglen: msg length
*
* called from the VF to disable all or specific
* queue(s)
**/
-static int i40e_vc_disable_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
+static int i40e_vc_disable_queues_msg(struct i40e_vf *vf, u8 *msg)
{
struct virtchnl_queue_select *vqs =
(struct virtchnl_queue_select *)msg;
@@ -2309,14 +2350,13 @@ error_param:
* i40e_vc_request_queues_msg
* @vf: pointer to the VF info
* @msg: pointer to the msg buffer
- * @msglen: msg length
*
* VFs get a default number of queues but can use this message to request a
* different number. If the request is successful, PF will reset the VF and
* return 0. If unsuccessful, PF will send message informing VF of number of
* available queues and return result of sending VF a message.
**/
-static int i40e_vc_request_queues_msg(struct i40e_vf *vf, u8 *msg, int msglen)
+static int i40e_vc_request_queues_msg(struct i40e_vf *vf, u8 *msg)
{
struct virtchnl_vf_res_request *vfres =
(struct virtchnl_vf_res_request *)msg;
@@ -2360,11 +2400,10 @@ static int i40e_vc_request_queues_msg(struct i40e_vf *vf, u8 *msg, int msglen)
* i40e_vc_get_stats_msg
* @vf: pointer to the VF info
* @msg: pointer to the msg buffer
- * @msglen: msg length
*
* called from the VF to get vsi stats
**/
-static int i40e_vc_get_stats_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
+static int i40e_vc_get_stats_msg(struct i40e_vf *vf, u8 *msg)
{
struct virtchnl_queue_select *vqs =
(struct virtchnl_queue_select *)msg;
@@ -2458,7 +2497,7 @@ static inline int i40e_check_vf_permission(struct i40e_vf *vf,
!is_multicast_ether_addr(addr) && vf->pf_set_mac &&
!ether_addr_equal(addr, vf->default_lan_addr.addr)) {
dev_err(&pf->pdev->dev,
- "VF attempting to override administratively set MAC address, reload the VF driver to resume normal operation\n");
+ "VF attempting to override administratively set MAC address, bring down and up the VF interface to resume normal operation\n");
return -EPERM;
}
}
@@ -2470,11 +2509,10 @@ static inline int i40e_check_vf_permission(struct i40e_vf *vf,
* i40e_vc_add_mac_addr_msg
* @vf: pointer to the VF info
* @msg: pointer to the msg buffer
- * @msglen: msg length
*
* add guest mac address filter
**/
-static int i40e_vc_add_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
+static int i40e_vc_add_mac_addr_msg(struct i40e_vf *vf, u8 *msg)
{
struct virtchnl_ether_addr_list *al =
(struct virtchnl_ether_addr_list *)msg;
@@ -2541,11 +2579,10 @@ error_param:
* i40e_vc_del_mac_addr_msg
* @vf: pointer to the VF info
* @msg: pointer to the msg buffer
- * @msglen: msg length
*
* remove guest mac address filter
**/
-static int i40e_vc_del_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
+static int i40e_vc_del_mac_addr_msg(struct i40e_vf *vf, u8 *msg)
{
struct virtchnl_ether_addr_list *al =
(struct virtchnl_ether_addr_list *)msg;
@@ -2569,6 +2606,16 @@ static int i40e_vc_del_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
ret = I40E_ERR_INVALID_MAC_ADDR;
goto error_param;
}
+
+ if (vf->pf_set_mac &&
+ ether_addr_equal(al->list[i].addr,
+ vf->default_lan_addr.addr)) {
+ dev_err(&pf->pdev->dev,
+ "MAC addr %pM has been set by PF, cannot delete it for VF %d, reset VF to change MAC addr\n",
+ vf->default_lan_addr.addr, vf->vf_id);
+ ret = I40E_ERR_PARAM;
+ goto error_param;
+ }
}
vsi = pf->vsi[vf->lan_vsi_idx];
@@ -2601,11 +2648,10 @@ error_param:
* i40e_vc_add_vlan_msg
* @vf: pointer to the VF info
* @msg: pointer to the msg buffer
- * @msglen: msg length
*
* program guest vlan id
**/
-static int i40e_vc_add_vlan_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
+static int i40e_vc_add_vlan_msg(struct i40e_vf *vf, u8 *msg)
{
struct virtchnl_vlan_filter_list *vfl =
(struct virtchnl_vlan_filter_list *)msg;
@@ -2674,11 +2720,10 @@ error_param:
* i40e_vc_remove_vlan_msg
* @vf: pointer to the VF info
* @msg: pointer to the msg buffer
- * @msglen: msg length
*
* remove programmed guest vlan id
**/
-static int i40e_vc_remove_vlan_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
+static int i40e_vc_remove_vlan_msg(struct i40e_vf *vf, u8 *msg)
{
struct virtchnl_vlan_filter_list *vfl =
(struct virtchnl_vlan_filter_list *)msg;
@@ -2761,13 +2806,11 @@ error_param:
* i40e_vc_iwarp_qvmap_msg
* @vf: pointer to the VF info
* @msg: pointer to the msg buffer
- * @msglen: msg length
* @config: config qvmap or release it
*
* called from the VF for the iwarp msgs
**/
-static int i40e_vc_iwarp_qvmap_msg(struct i40e_vf *vf, u8 *msg, u16 msglen,
- bool config)
+static int i40e_vc_iwarp_qvmap_msg(struct i40e_vf *vf, u8 *msg, bool config)
{
struct virtchnl_iwarp_qvlist_info *qvlist_info =
(struct virtchnl_iwarp_qvlist_info *)msg;
@@ -2798,11 +2841,10 @@ error_param:
* i40e_vc_config_rss_key
* @vf: pointer to the VF info
* @msg: pointer to the msg buffer
- * @msglen: msg length
*
* Configure the VF's RSS key
**/
-static int i40e_vc_config_rss_key(struct i40e_vf *vf, u8 *msg, u16 msglen)
+static int i40e_vc_config_rss_key(struct i40e_vf *vf, u8 *msg)
{
struct virtchnl_rss_key *vrk =
(struct virtchnl_rss_key *)msg;
@@ -2830,11 +2872,10 @@ err:
* i40e_vc_config_rss_lut
* @vf: pointer to the VF info
* @msg: pointer to the msg buffer
- * @msglen: msg length
*
* Configure the VF's RSS LUT
**/
-static int i40e_vc_config_rss_lut(struct i40e_vf *vf, u8 *msg, u16 msglen)
+static int i40e_vc_config_rss_lut(struct i40e_vf *vf, u8 *msg)
{
struct virtchnl_rss_lut *vrl =
(struct virtchnl_rss_lut *)msg;
@@ -2862,11 +2903,10 @@ err:
* i40e_vc_get_rss_hena
* @vf: pointer to the VF info
* @msg: pointer to the msg buffer
- * @msglen: msg length
*
* Return the RSS HENA bits allowed by the hardware
**/
-static int i40e_vc_get_rss_hena(struct i40e_vf *vf, u8 *msg, u16 msglen)
+static int i40e_vc_get_rss_hena(struct i40e_vf *vf, u8 *msg)
{
struct virtchnl_rss_hena *vrh = NULL;
struct i40e_pf *pf = vf->pf;
@@ -2898,11 +2938,10 @@ err:
* i40e_vc_set_rss_hena
* @vf: pointer to the VF info
* @msg: pointer to the msg buffer
- * @msglen: msg length
*
* Set the RSS HENA bits for the VF
**/
-static int i40e_vc_set_rss_hena(struct i40e_vf *vf, u8 *msg, u16 msglen)
+static int i40e_vc_set_rss_hena(struct i40e_vf *vf, u8 *msg)
{
struct virtchnl_rss_hena *vrh =
(struct virtchnl_rss_hena *)msg;
@@ -2927,12 +2966,10 @@ err:
* i40e_vc_enable_vlan_stripping
* @vf: pointer to the VF info
* @msg: pointer to the msg buffer
- * @msglen: msg length
*
* Enable vlan header stripping for the VF
**/
-static int i40e_vc_enable_vlan_stripping(struct i40e_vf *vf, u8 *msg,
- u16 msglen)
+static int i40e_vc_enable_vlan_stripping(struct i40e_vf *vf, u8 *msg)
{
struct i40e_vsi *vsi = vf->pf->vsi[vf->lan_vsi_idx];
i40e_status aq_ret = 0;
@@ -2954,12 +2991,10 @@ err:
* i40e_vc_disable_vlan_stripping
* @vf: pointer to the VF info
* @msg: pointer to the msg buffer
- * @msglen: msg length
*
* Disable vlan header stripping for the VF
**/
-static int i40e_vc_disable_vlan_stripping(struct i40e_vf *vf, u8 *msg,
- u16 msglen)
+static int i40e_vc_disable_vlan_stripping(struct i40e_vf *vf, u8 *msg)
{
struct i40e_vsi *vsi = vf->pf->vsi[vf->lan_vsi_idx];
i40e_status aq_ret = 0;
@@ -3639,7 +3674,7 @@ int i40e_vc_process_vf_msg(struct i40e_pf *pf, s16 vf_id, u32 v_opcode,
dev_err(&pf->pdev->dev, "Invalid message from VF %d, opcode %d, len %d\n",
local_vf_id, v_opcode, msglen);
switch (ret) {
- case VIRTCHNL_ERR_PARAM:
+ case VIRTCHNL_STATUS_ERR_PARAM:
return -EPERM;
default:
return -EINVAL;
@@ -3659,65 +3694,65 @@ int i40e_vc_process_vf_msg(struct i40e_pf *pf, s16 vf_id, u32 v_opcode,
ret = 0;
break;
case VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE:
- ret = i40e_vc_config_promiscuous_mode_msg(vf, msg, msglen);
+ ret = i40e_vc_config_promiscuous_mode_msg(vf, msg);
break;
case VIRTCHNL_OP_CONFIG_VSI_QUEUES:
- ret = i40e_vc_config_queues_msg(vf, msg, msglen);
+ ret = i40e_vc_config_queues_msg(vf, msg);
break;
case VIRTCHNL_OP_CONFIG_IRQ_MAP:
- ret = i40e_vc_config_irq_map_msg(vf, msg, msglen);
+ ret = i40e_vc_config_irq_map_msg(vf, msg);
break;
case VIRTCHNL_OP_ENABLE_QUEUES:
- ret = i40e_vc_enable_queues_msg(vf, msg, msglen);
+ ret = i40e_vc_enable_queues_msg(vf, msg);
i40e_vc_notify_vf_link_state(vf);
break;
case VIRTCHNL_OP_DISABLE_QUEUES:
- ret = i40e_vc_disable_queues_msg(vf, msg, msglen);
+ ret = i40e_vc_disable_queues_msg(vf, msg);
break;
case VIRTCHNL_OP_ADD_ETH_ADDR:
- ret = i40e_vc_add_mac_addr_msg(vf, msg, msglen);
+ ret = i40e_vc_add_mac_addr_msg(vf, msg);
break;
case VIRTCHNL_OP_DEL_ETH_ADDR:
- ret = i40e_vc_del_mac_addr_msg(vf, msg, msglen);
+ ret = i40e_vc_del_mac_addr_msg(vf, msg);
break;
case VIRTCHNL_OP_ADD_VLAN:
- ret = i40e_vc_add_vlan_msg(vf, msg, msglen);
+ ret = i40e_vc_add_vlan_msg(vf, msg);
break;
case VIRTCHNL_OP_DEL_VLAN:
- ret = i40e_vc_remove_vlan_msg(vf, msg, msglen);
+ ret = i40e_vc_remove_vlan_msg(vf, msg);
break;
case VIRTCHNL_OP_GET_STATS:
- ret = i40e_vc_get_stats_msg(vf, msg, msglen);
+ ret = i40e_vc_get_stats_msg(vf, msg);
break;
case VIRTCHNL_OP_IWARP:
ret = i40e_vc_iwarp_msg(vf, msg, msglen);
break;
case VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP:
- ret = i40e_vc_iwarp_qvmap_msg(vf, msg, msglen, true);
+ ret = i40e_vc_iwarp_qvmap_msg(vf, msg, true);
break;
case VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP:
- ret = i40e_vc_iwarp_qvmap_msg(vf, msg, msglen, false);
+ ret = i40e_vc_iwarp_qvmap_msg(vf, msg, false);
break;
case VIRTCHNL_OP_CONFIG_RSS_KEY:
- ret = i40e_vc_config_rss_key(vf, msg, msglen);
+ ret = i40e_vc_config_rss_key(vf, msg);
break;
case VIRTCHNL_OP_CONFIG_RSS_LUT:
- ret = i40e_vc_config_rss_lut(vf, msg, msglen);
+ ret = i40e_vc_config_rss_lut(vf, msg);
break;
case VIRTCHNL_OP_GET_RSS_HENA_CAPS:
- ret = i40e_vc_get_rss_hena(vf, msg, msglen);
+ ret = i40e_vc_get_rss_hena(vf, msg);
break;
case VIRTCHNL_OP_SET_RSS_HENA:
- ret = i40e_vc_set_rss_hena(vf, msg, msglen);
+ ret = i40e_vc_set_rss_hena(vf, msg);
break;
case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING:
- ret = i40e_vc_enable_vlan_stripping(vf, msg, msglen);
+ ret = i40e_vc_enable_vlan_stripping(vf, msg);
break;
case VIRTCHNL_OP_DISABLE_VLAN_STRIPPING:
- ret = i40e_vc_disable_vlan_stripping(vf, msg, msglen);
+ ret = i40e_vc_disable_vlan_stripping(vf, msg);
break;
case VIRTCHNL_OP_REQUEST_QUEUES:
- ret = i40e_vc_request_queues_msg(vf, msg, msglen);
+ ret = i40e_vc_request_queues_msg(vf, msg);
break;
case VIRTCHNL_OP_ENABLE_CHANNELS:
ret = i40e_vc_add_qch_msg(vf, msg);
@@ -3786,6 +3821,35 @@ int i40e_vc_process_vflr_event(struct i40e_pf *pf)
}
/**
+ * i40e_validate_vf
+ * @pf: the physical function
+ * @vf_id: VF identifier
+ *
+ * Check that the VF is enabled and the VSI exists.
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int i40e_validate_vf(struct i40e_pf *pf, int vf_id)
+{
+ struct i40e_vsi *vsi;
+ struct i40e_vf *vf;
+ int ret = 0;
+
+ if (vf_id >= pf->num_alloc_vfs) {
+ dev_err(&pf->pdev->dev,
+ "Invalid VF Identifier %d\n", vf_id);
+ ret = -EINVAL;
+ goto err_out;
+ }
+ vf = &pf->vf[vf_id];
+ vsi = i40e_find_vsi_from_id(pf, vf->lan_vsi_id);
+ if (!vsi)
+ ret = -EINVAL;
+err_out:
+ return ret;
+}
+
+/**
* i40e_ndo_set_vf_mac
* @netdev: network interface device structure
* @vf_id: VF identifier
@@ -3806,14 +3870,11 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
u8 i;
/* validate the request */
- if (vf_id >= pf->num_alloc_vfs) {
- dev_err(&pf->pdev->dev,
- "Invalid VF Identifier %d\n", vf_id);
- ret = -EINVAL;
+ ret = i40e_validate_vf(pf, vf_id);
+ if (ret)
goto error_param;
- }
- vf = &(pf->vf[vf_id]);
+ vf = &pf->vf[vf_id];
vsi = pf->vsi[vf->lan_vsi_idx];
/* When the VF is resetting wait until it is done.
@@ -3873,9 +3934,11 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
mac, vf_id);
}
- /* Force the VF driver stop so it has to reload with new MAC address */
+ /* Force the VF interface down so it has to bring up with new MAC
+ * address
+ */
i40e_vc_disable_vf(vf);
- dev_info(&pf->pdev->dev, "Reload the VF driver to make this change effective.\n");
+ dev_info(&pf->pdev->dev, "Bring down and up the VF interface to make this change effective.\n");
error_param:
return ret;
@@ -3930,11 +3993,9 @@ int i40e_ndo_set_vf_port_vlan(struct net_device *netdev, int vf_id,
int ret = 0;
/* validate the request */
- if (vf_id >= pf->num_alloc_vfs) {
- dev_err(&pf->pdev->dev, "Invalid VF Identifier %d\n", vf_id);
- ret = -EINVAL;
+ ret = i40e_validate_vf(pf, vf_id);
+ if (ret)
goto error_pvid;
- }
if ((vlan_id > I40E_MAX_VLANID) || (qos > 7)) {
dev_err(&pf->pdev->dev, "Invalid VF Parameters\n");
@@ -3948,7 +4009,7 @@ int i40e_ndo_set_vf_port_vlan(struct net_device *netdev, int vf_id,
goto error_pvid;
}
- vf = &(pf->vf[vf_id]);
+ vf = &pf->vf[vf_id];
vsi = pf->vsi[vf->lan_vsi_idx];
if (!test_bit(I40E_VF_STATE_INIT, &vf->vf_states)) {
dev_err(&pf->pdev->dev, "VF %d still in reset. Try again.\n",
@@ -4068,11 +4129,9 @@ int i40e_ndo_set_vf_bw(struct net_device *netdev, int vf_id, int min_tx_rate,
int ret = 0;
/* validate the request */
- if (vf_id >= pf->num_alloc_vfs) {
- dev_err(&pf->pdev->dev, "Invalid VF Identifier %d.\n", vf_id);
- ret = -EINVAL;
+ ret = i40e_validate_vf(pf, vf_id);
+ if (ret)
goto error;
- }
if (min_tx_rate) {
dev_err(&pf->pdev->dev, "Invalid min tx rate (%d) (greater than 0) specified for VF %d.\n",
@@ -4080,7 +4139,7 @@ int i40e_ndo_set_vf_bw(struct net_device *netdev, int vf_id, int min_tx_rate,
return -EINVAL;
}
- vf = &(pf->vf[vf_id]);
+ vf = &pf->vf[vf_id];
vsi = pf->vsi[vf->lan_vsi_idx];
if (!test_bit(I40E_VF_STATE_INIT, &vf->vf_states)) {
dev_err(&pf->pdev->dev, "VF %d still in reset. Try again.\n",
@@ -4116,13 +4175,11 @@ int i40e_ndo_get_vf_config(struct net_device *netdev,
int ret = 0;
/* validate the request */
- if (vf_id >= pf->num_alloc_vfs) {
- dev_err(&pf->pdev->dev, "Invalid VF Identifier %d\n", vf_id);
- ret = -EINVAL;
+ ret = i40e_validate_vf(pf, vf_id);
+ if (ret)
goto error_param;
- }
- vf = &(pf->vf[vf_id]);
+ vf = &pf->vf[vf_id];
/* first vsi is always the LAN vsi */
vsi = pf->vsi[vf->lan_vsi_idx];
if (!test_bit(I40E_VF_STATE_INIT, &vf->vf_states)) {
@@ -4199,7 +4256,7 @@ int i40e_ndo_set_vf_link_state(struct net_device *netdev, int vf_id, int link)
vf->link_forced = true;
vf->link_up = true;
pfe.event_data.link_event.link_status = true;
- pfe.event_data.link_event.link_speed = I40E_LINK_SPEED_40GB;
+ pfe.event_data.link_event.link_speed = VIRTCHNL_LINK_SPEED_40GB;
break;
case IFLA_VF_LINK_STATE_DISABLE:
vf->link_forced = true;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_xsk.c b/drivers/net/ethernet/intel/i40e/i40e_xsk.c
new file mode 100644
index 000000000000..add1e457886d
--- /dev/null
+++ b/drivers/net/ethernet/intel/i40e/i40e_xsk.c
@@ -0,0 +1,967 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2018 Intel Corporation. */
+
+#include <linux/bpf_trace.h>
+#include <net/xdp_sock.h>
+#include <net/xdp.h>
+
+#include "i40e.h"
+#include "i40e_txrx_common.h"
+#include "i40e_xsk.h"
+
+/**
+ * i40e_alloc_xsk_umems - Allocate an array to store per ring UMEMs
+ * @vsi: Current VSI
+ *
+ * Returns 0 on success, <0 on failure
+ **/
+static int i40e_alloc_xsk_umems(struct i40e_vsi *vsi)
+{
+ if (vsi->xsk_umems)
+ return 0;
+
+ vsi->num_xsk_umems_used = 0;
+ vsi->num_xsk_umems = vsi->alloc_queue_pairs;
+ vsi->xsk_umems = kcalloc(vsi->num_xsk_umems, sizeof(*vsi->xsk_umems),
+ GFP_KERNEL);
+ if (!vsi->xsk_umems) {
+ vsi->num_xsk_umems = 0;
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/**
+ * i40e_add_xsk_umem - Store an UMEM for a certain ring/qid
+ * @vsi: Current VSI
+ * @umem: UMEM to store
+ * @qid: Ring/qid to associate with the UMEM
+ *
+ * Returns 0 on success, <0 on failure
+ **/
+static int i40e_add_xsk_umem(struct i40e_vsi *vsi, struct xdp_umem *umem,
+ u16 qid)
+{
+ int err;
+
+ err = i40e_alloc_xsk_umems(vsi);
+ if (err)
+ return err;
+
+ vsi->xsk_umems[qid] = umem;
+ vsi->num_xsk_umems_used++;
+
+ return 0;
+}
+
+/**
+ * i40e_remove_xsk_umem - Remove an UMEM for a certain ring/qid
+ * @vsi: Current VSI
+ * @qid: Ring/qid associated with the UMEM
+ **/
+static void i40e_remove_xsk_umem(struct i40e_vsi *vsi, u16 qid)
+{
+ vsi->xsk_umems[qid] = NULL;
+ vsi->num_xsk_umems_used--;
+
+ if (vsi->num_xsk_umems == 0) {
+ kfree(vsi->xsk_umems);
+ vsi->xsk_umems = NULL;
+ vsi->num_xsk_umems = 0;
+ }
+}
+
+/**
+ * i40e_xsk_umem_dma_map - DMA maps all UMEM memory for the netdev
+ * @vsi: Current VSI
+ * @umem: UMEM to DMA map
+ *
+ * Returns 0 on success, <0 on failure
+ **/
+static int i40e_xsk_umem_dma_map(struct i40e_vsi *vsi, struct xdp_umem *umem)
+{
+ struct i40e_pf *pf = vsi->back;
+ struct device *dev;
+ unsigned int i, j;
+ dma_addr_t dma;
+
+ dev = &pf->pdev->dev;
+ for (i = 0; i < umem->npgs; i++) {
+ dma = dma_map_page_attrs(dev, umem->pgs[i], 0, PAGE_SIZE,
+ DMA_BIDIRECTIONAL, I40E_RX_DMA_ATTR);
+ if (dma_mapping_error(dev, dma))
+ goto out_unmap;
+
+ umem->pages[i].dma = dma;
+ }
+
+ return 0;
+
+out_unmap:
+ for (j = 0; j < i; j++) {
+ dma_unmap_page_attrs(dev, umem->pages[i].dma, PAGE_SIZE,
+ DMA_BIDIRECTIONAL, I40E_RX_DMA_ATTR);
+ umem->pages[i].dma = 0;
+ }
+
+ return -1;
+}
+
+/**
+ * i40e_xsk_umem_dma_unmap - DMA unmaps all UMEM memory for the netdev
+ * @vsi: Current VSI
+ * @umem: UMEM to DMA map
+ **/
+static void i40e_xsk_umem_dma_unmap(struct i40e_vsi *vsi, struct xdp_umem *umem)
+{
+ struct i40e_pf *pf = vsi->back;
+ struct device *dev;
+ unsigned int i;
+
+ dev = &pf->pdev->dev;
+
+ for (i = 0; i < umem->npgs; i++) {
+ dma_unmap_page_attrs(dev, umem->pages[i].dma, PAGE_SIZE,
+ DMA_BIDIRECTIONAL, I40E_RX_DMA_ATTR);
+
+ umem->pages[i].dma = 0;
+ }
+}
+
+/**
+ * i40e_xsk_umem_enable - Enable/associate an UMEM to a certain ring/qid
+ * @vsi: Current VSI
+ * @umem: UMEM
+ * @qid: Rx ring to associate UMEM to
+ *
+ * Returns 0 on success, <0 on failure
+ **/
+static int i40e_xsk_umem_enable(struct i40e_vsi *vsi, struct xdp_umem *umem,
+ u16 qid)
+{
+ struct xdp_umem_fq_reuse *reuseq;
+ bool if_running;
+ int err;
+
+ if (vsi->type != I40E_VSI_MAIN)
+ return -EINVAL;
+
+ if (qid >= vsi->num_queue_pairs)
+ return -EINVAL;
+
+ if (vsi->xsk_umems) {
+ if (qid >= vsi->num_xsk_umems)
+ return -EINVAL;
+ if (vsi->xsk_umems[qid])
+ return -EBUSY;
+ }
+
+ reuseq = xsk_reuseq_prepare(vsi->rx_rings[0]->count);
+ if (!reuseq)
+ return -ENOMEM;
+
+ xsk_reuseq_free(xsk_reuseq_swap(umem, reuseq));
+
+ err = i40e_xsk_umem_dma_map(vsi, umem);
+ if (err)
+ return err;
+
+ if_running = netif_running(vsi->netdev) && i40e_enabled_xdp_vsi(vsi);
+
+ if (if_running) {
+ err = i40e_queue_pair_disable(vsi, qid);
+ if (err)
+ return err;
+ }
+
+ err = i40e_add_xsk_umem(vsi, umem, qid);
+ if (err)
+ return err;
+
+ if (if_running) {
+ err = i40e_queue_pair_enable(vsi, qid);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+/**
+ * i40e_xsk_umem_disable - Diassociate an UMEM from a certain ring/qid
+ * @vsi: Current VSI
+ * @qid: Rx ring to associate UMEM to
+ *
+ * Returns 0 on success, <0 on failure
+ **/
+static int i40e_xsk_umem_disable(struct i40e_vsi *vsi, u16 qid)
+{
+ bool if_running;
+ int err;
+
+ if (!vsi->xsk_umems || qid >= vsi->num_xsk_umems ||
+ !vsi->xsk_umems[qid])
+ return -EINVAL;
+
+ if_running = netif_running(vsi->netdev) && i40e_enabled_xdp_vsi(vsi);
+
+ if (if_running) {
+ err = i40e_queue_pair_disable(vsi, qid);
+ if (err)
+ return err;
+ }
+
+ i40e_xsk_umem_dma_unmap(vsi, vsi->xsk_umems[qid]);
+ i40e_remove_xsk_umem(vsi, qid);
+
+ if (if_running) {
+ err = i40e_queue_pair_enable(vsi, qid);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+/**
+ * i40e_xsk_umem_query - Queries a certain ring/qid for its UMEM
+ * @vsi: Current VSI
+ * @umem: UMEM associated to the ring, if any
+ * @qid: Rx ring to associate UMEM to
+ *
+ * This function will store, if any, the UMEM associated to certain ring.
+ *
+ * Returns 0 on success, <0 on failure
+ **/
+int i40e_xsk_umem_query(struct i40e_vsi *vsi, struct xdp_umem **umem,
+ u16 qid)
+{
+ if (vsi->type != I40E_VSI_MAIN)
+ return -EINVAL;
+
+ if (qid >= vsi->num_queue_pairs)
+ return -EINVAL;
+
+ if (vsi->xsk_umems) {
+ if (qid >= vsi->num_xsk_umems)
+ return -EINVAL;
+ *umem = vsi->xsk_umems[qid];
+ return 0;
+ }
+
+ *umem = NULL;
+ return 0;
+}
+
+/**
+ * i40e_xsk_umem_query - Queries a certain ring/qid for its UMEM
+ * @vsi: Current VSI
+ * @umem: UMEM to enable/associate to a ring, or NULL to disable
+ * @qid: Rx ring to (dis)associate UMEM (from)to
+ *
+ * This function enables or disables an UMEM to a certain ring.
+ *
+ * Returns 0 on success, <0 on failure
+ **/
+int i40e_xsk_umem_setup(struct i40e_vsi *vsi, struct xdp_umem *umem,
+ u16 qid)
+{
+ return umem ? i40e_xsk_umem_enable(vsi, umem, qid) :
+ i40e_xsk_umem_disable(vsi, qid);
+}
+
+/**
+ * i40e_run_xdp_zc - Executes an XDP program on an xdp_buff
+ * @rx_ring: Rx ring
+ * @xdp: xdp_buff used as input to the XDP program
+ *
+ * This function enables or disables an UMEM to a certain ring.
+ *
+ * Returns any of I40E_XDP_{PASS, CONSUMED, TX, REDIR}
+ **/
+static int i40e_run_xdp_zc(struct i40e_ring *rx_ring, struct xdp_buff *xdp)
+{
+ int err, result = I40E_XDP_PASS;
+ struct i40e_ring *xdp_ring;
+ 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.
+ */
+ xdp_prog = READ_ONCE(rx_ring->xdp_prog);
+ act = bpf_prog_run_xdp(xdp_prog, xdp);
+ xdp->handle += xdp->data - xdp->data_hard_start;
+ switch (act) {
+ case XDP_PASS:
+ break;
+ case XDP_TX:
+ xdp_ring = rx_ring->vsi->xdp_rings[rx_ring->queue_index];
+ result = i40e_xmit_xdp_tx_ring(xdp, xdp_ring);
+ break;
+ case XDP_REDIRECT:
+ err = xdp_do_redirect(rx_ring->netdev, xdp, xdp_prog);
+ result = !err ? I40E_XDP_REDIR : I40E_XDP_CONSUMED;
+ break;
+ default:
+ bpf_warn_invalid_xdp_action(act);
+ case XDP_ABORTED:
+ trace_xdp_exception(rx_ring->netdev, xdp_prog, act);
+ /* fallthrough -- handle aborts by dropping packet */
+ case XDP_DROP:
+ result = I40E_XDP_CONSUMED;
+ break;
+ }
+ rcu_read_unlock();
+ return result;
+}
+
+/**
+ * i40e_alloc_buffer_zc - Allocates an i40e_rx_buffer
+ * @rx_ring: Rx ring
+ * @bi: Rx buffer to populate
+ *
+ * This function allocates an Rx buffer. The buffer can come from fill
+ * queue, or via the recycle queue (next_to_alloc).
+ *
+ * Returns true for a successful allocation, false otherwise
+ **/
+static bool i40e_alloc_buffer_zc(struct i40e_ring *rx_ring,
+ struct i40e_rx_buffer *bi)
+{
+ struct xdp_umem *umem = rx_ring->xsk_umem;
+ void *addr = bi->addr;
+ u64 handle, hr;
+
+ if (addr) {
+ rx_ring->rx_stats.page_reuse_count++;
+ return true;
+ }
+
+ if (!xsk_umem_peek_addr(umem, &handle)) {
+ rx_ring->rx_stats.alloc_page_failed++;
+ return false;
+ }
+
+ hr = umem->headroom + XDP_PACKET_HEADROOM;
+
+ bi->dma = xdp_umem_get_dma(umem, handle);
+ bi->dma += hr;
+
+ bi->addr = xdp_umem_get_data(umem, handle);
+ bi->addr += hr;
+
+ bi->handle = handle + umem->headroom;
+
+ xsk_umem_discard_addr(umem);
+ return true;
+}
+
+/**
+ * i40e_alloc_buffer_slow_zc - Allocates an i40e_rx_buffer
+ * @rx_ring: Rx ring
+ * @bi: Rx buffer to populate
+ *
+ * This function allocates an Rx buffer. The buffer can come from fill
+ * queue, or via the reuse queue.
+ *
+ * Returns true for a successful allocation, false otherwise
+ **/
+static bool i40e_alloc_buffer_slow_zc(struct i40e_ring *rx_ring,
+ struct i40e_rx_buffer *bi)
+{
+ struct xdp_umem *umem = rx_ring->xsk_umem;
+ u64 handle, hr;
+
+ if (!xsk_umem_peek_addr_rq(umem, &handle)) {
+ rx_ring->rx_stats.alloc_page_failed++;
+ return false;
+ }
+
+ handle &= rx_ring->xsk_umem->chunk_mask;
+
+ hr = umem->headroom + XDP_PACKET_HEADROOM;
+
+ bi->dma = xdp_umem_get_dma(umem, handle);
+ bi->dma += hr;
+
+ bi->addr = xdp_umem_get_data(umem, handle);
+ bi->addr += hr;
+
+ bi->handle = handle + umem->headroom;
+
+ xsk_umem_discard_addr_rq(umem);
+ return true;
+}
+
+static __always_inline bool
+__i40e_alloc_rx_buffers_zc(struct i40e_ring *rx_ring, u16 count,
+ bool alloc(struct i40e_ring *rx_ring,
+ struct i40e_rx_buffer *bi))
+{
+ u16 ntu = rx_ring->next_to_use;
+ union i40e_rx_desc *rx_desc;
+ struct i40e_rx_buffer *bi;
+ bool ok = true;
+
+ rx_desc = I40E_RX_DESC(rx_ring, ntu);
+ bi = &rx_ring->rx_bi[ntu];
+ do {
+ if (!alloc(rx_ring, bi)) {
+ ok = false;
+ goto no_buffers;
+ }
+
+ dma_sync_single_range_for_device(rx_ring->dev, bi->dma, 0,
+ rx_ring->rx_buf_len,
+ DMA_BIDIRECTIONAL);
+
+ rx_desc->read.pkt_addr = cpu_to_le64(bi->dma);
+
+ rx_desc++;
+ bi++;
+ ntu++;
+
+ if (unlikely(ntu == rx_ring->count)) {
+ rx_desc = I40E_RX_DESC(rx_ring, 0);
+ bi = rx_ring->rx_bi;
+ ntu = 0;
+ }
+
+ rx_desc->wb.qword1.status_error_len = 0;
+ count--;
+ } while (count);
+
+no_buffers:
+ if (rx_ring->next_to_use != ntu)
+ i40e_release_rx_desc(rx_ring, ntu);
+
+ return ok;
+}
+
+/**
+ * i40e_alloc_rx_buffers_zc - Allocates a number of Rx buffers
+ * @rx_ring: Rx ring
+ * @count: The number of buffers to allocate
+ *
+ * This function allocates a number of Rx buffers from the reuse queue
+ * or fill ring and places them on the Rx ring.
+ *
+ * Returns true for a successful allocation, false otherwise
+ **/
+bool i40e_alloc_rx_buffers_zc(struct i40e_ring *rx_ring, u16 count)
+{
+ return __i40e_alloc_rx_buffers_zc(rx_ring, count,
+ i40e_alloc_buffer_slow_zc);
+}
+
+/**
+ * i40e_alloc_rx_buffers_fast_zc - Allocates a number of Rx buffers
+ * @rx_ring: Rx ring
+ * @count: The number of buffers to allocate
+ *
+ * This function allocates a number of Rx buffers from the fill ring
+ * or the internal recycle mechanism and places them on the Rx ring.
+ *
+ * Returns true for a successful allocation, false otherwise
+ **/
+static bool i40e_alloc_rx_buffers_fast_zc(struct i40e_ring *rx_ring, u16 count)
+{
+ return __i40e_alloc_rx_buffers_zc(rx_ring, count,
+ i40e_alloc_buffer_zc);
+}
+
+/**
+ * i40e_get_rx_buffer_zc - Return the current Rx buffer
+ * @rx_ring: Rx ring
+ * @size: The size of the rx buffer (read from descriptor)
+ *
+ * This function returns the current, received Rx buffer, and also
+ * does DMA synchronization. the Rx ring.
+ *
+ * Returns the received Rx buffer
+ **/
+static struct i40e_rx_buffer *i40e_get_rx_buffer_zc(struct i40e_ring *rx_ring,
+ const unsigned int size)
+{
+ struct i40e_rx_buffer *bi;
+
+ bi = &rx_ring->rx_bi[rx_ring->next_to_clean];
+
+ /* we are reusing so sync this buffer for CPU use */
+ dma_sync_single_range_for_cpu(rx_ring->dev,
+ bi->dma, 0,
+ size,
+ DMA_BIDIRECTIONAL);
+
+ return bi;
+}
+
+/**
+ * i40e_reuse_rx_buffer_zc - Recycle an Rx buffer
+ * @rx_ring: Rx ring
+ * @old_bi: The Rx buffer to recycle
+ *
+ * This function recycles a finished Rx buffer, and places it on the
+ * recycle queue (next_to_alloc).
+ **/
+static void i40e_reuse_rx_buffer_zc(struct i40e_ring *rx_ring,
+ struct i40e_rx_buffer *old_bi)
+{
+ struct i40e_rx_buffer *new_bi = &rx_ring->rx_bi[rx_ring->next_to_alloc];
+ unsigned long mask = (unsigned long)rx_ring->xsk_umem->chunk_mask;
+ u64 hr = rx_ring->xsk_umem->headroom + XDP_PACKET_HEADROOM;
+ u16 nta = rx_ring->next_to_alloc;
+
+ /* update, and store next to alloc */
+ nta++;
+ rx_ring->next_to_alloc = (nta < rx_ring->count) ? nta : 0;
+
+ /* transfer page from old buffer to new buffer */
+ new_bi->dma = old_bi->dma & mask;
+ new_bi->dma += hr;
+
+ new_bi->addr = (void *)((unsigned long)old_bi->addr & mask);
+ new_bi->addr += hr;
+
+ new_bi->handle = old_bi->handle & mask;
+ new_bi->handle += rx_ring->xsk_umem->headroom;
+
+ old_bi->addr = NULL;
+}
+
+/**
+ * i40e_zca_free - Free callback for MEM_TYPE_ZERO_COPY allocations
+ * @alloc: Zero-copy allocator
+ * @handle: Buffer handle
+ **/
+void i40e_zca_free(struct zero_copy_allocator *alloc, unsigned long handle)
+{
+ struct i40e_rx_buffer *bi;
+ struct i40e_ring *rx_ring;
+ u64 hr, mask;
+ u16 nta;
+
+ rx_ring = container_of(alloc, struct i40e_ring, zca);
+ hr = rx_ring->xsk_umem->headroom + XDP_PACKET_HEADROOM;
+ mask = rx_ring->xsk_umem->chunk_mask;
+
+ nta = rx_ring->next_to_alloc;
+ bi = &rx_ring->rx_bi[nta];
+
+ nta++;
+ rx_ring->next_to_alloc = (nta < rx_ring->count) ? nta : 0;
+
+ handle &= mask;
+
+ bi->dma = xdp_umem_get_dma(rx_ring->xsk_umem, handle);
+ bi->dma += hr;
+
+ bi->addr = xdp_umem_get_data(rx_ring->xsk_umem, handle);
+ bi->addr += hr;
+
+ bi->handle = (u64)handle + rx_ring->xsk_umem->headroom;
+}
+
+/**
+ * i40e_construct_skb_zc - Create skbufff from zero-copy Rx buffer
+ * @rx_ring: Rx ring
+ * @bi: Rx buffer
+ * @xdp: xdp_buff
+ *
+ * This functions allocates a new skb from a zero-copy Rx buffer.
+ *
+ * Returns the skb, or NULL on failure.
+ **/
+static struct sk_buff *i40e_construct_skb_zc(struct i40e_ring *rx_ring,
+ struct i40e_rx_buffer *bi,
+ struct xdp_buff *xdp)
+{
+ unsigned int metasize = xdp->data - xdp->data_meta;
+ unsigned int datasize = xdp->data_end - xdp->data;
+ struct sk_buff *skb;
+
+ /* allocate a skb to store the frags */
+ skb = __napi_alloc_skb(&rx_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 - xdp->data_hard_start);
+ memcpy(__skb_put(skb, datasize), xdp->data, datasize);
+ if (metasize)
+ skb_metadata_set(skb, metasize);
+
+ i40e_reuse_rx_buffer_zc(rx_ring, bi);
+ return skb;
+}
+
+/**
+ * i40e_inc_ntc: Advance the next_to_clean index
+ * @rx_ring: Rx ring
+ **/
+static void i40e_inc_ntc(struct i40e_ring *rx_ring)
+{
+ u32 ntc = rx_ring->next_to_clean + 1;
+
+ ntc = (ntc < rx_ring->count) ? ntc : 0;
+ rx_ring->next_to_clean = ntc;
+ prefetch(I40E_RX_DESC(rx_ring, ntc));
+}
+
+/**
+ * i40e_clean_rx_irq_zc - Consumes Rx packets from the hardware ring
+ * @rx_ring: Rx ring
+ * @budget: NAPI budget
+ *
+ * Returns amount of work completed
+ **/
+int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget)
+{
+ unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+ u16 cleaned_count = I40E_DESC_UNUSED(rx_ring);
+ unsigned int xdp_res, xdp_xmit = 0;
+ bool failure = false;
+ struct sk_buff *skb;
+ struct xdp_buff xdp;
+
+ xdp.rxq = &rx_ring->xdp_rxq;
+
+ while (likely(total_rx_packets < (unsigned int)budget)) {
+ struct i40e_rx_buffer *bi;
+ union i40e_rx_desc *rx_desc;
+ unsigned int size;
+ u16 vlan_tag;
+ u8 rx_ptype;
+ u64 qword;
+
+ if (cleaned_count >= I40E_RX_BUFFER_WRITE) {
+ failure = failure ||
+ !i40e_alloc_rx_buffers_fast_zc(rx_ring,
+ cleaned_count);
+ cleaned_count = 0;
+ }
+
+ rx_desc = I40E_RX_DESC(rx_ring, rx_ring->next_to_clean);
+ qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len);
+
+ /* This memory barrier is needed to keep us from reading
+ * any other fields out of the rx_desc until we have
+ * verified the descriptor has been written back.
+ */
+ dma_rmb();
+
+ bi = i40e_clean_programming_status(rx_ring, rx_desc,
+ qword);
+ if (unlikely(bi)) {
+ i40e_reuse_rx_buffer_zc(rx_ring, bi);
+ cleaned_count++;
+ continue;
+ }
+
+ size = (qword & I40E_RXD_QW1_LENGTH_PBUF_MASK) >>
+ I40E_RXD_QW1_LENGTH_PBUF_SHIFT;
+ if (!size)
+ break;
+
+ bi = i40e_get_rx_buffer_zc(rx_ring, size);
+ xdp.data = bi->addr;
+ xdp.data_meta = xdp.data;
+ xdp.data_hard_start = xdp.data - XDP_PACKET_HEADROOM;
+ xdp.data_end = xdp.data + size;
+ xdp.handle = bi->handle;
+
+ xdp_res = i40e_run_xdp_zc(rx_ring, &xdp);
+ if (xdp_res) {
+ if (xdp_res & (I40E_XDP_TX | I40E_XDP_REDIR)) {
+ xdp_xmit |= xdp_res;
+ bi->addr = NULL;
+ } else {
+ i40e_reuse_rx_buffer_zc(rx_ring, bi);
+ }
+
+ total_rx_bytes += size;
+ total_rx_packets++;
+
+ cleaned_count++;
+ i40e_inc_ntc(rx_ring);
+ continue;
+ }
+
+ /* XDP_PASS path */
+
+ /* NB! We are not checking for errors using
+ * i40e_test_staterr with
+ * BIT(I40E_RXD_QW1_ERROR_SHIFT). This is due to that
+ * SBP is *not* set in PRT_SBPVSI (default not set).
+ */
+ skb = i40e_construct_skb_zc(rx_ring, bi, &xdp);
+ if (!skb) {
+ rx_ring->rx_stats.alloc_buff_failed++;
+ break;
+ }
+
+ cleaned_count++;
+ i40e_inc_ntc(rx_ring);
+
+ if (eth_skb_pad(skb))
+ continue;
+
+ total_rx_bytes += skb->len;
+ total_rx_packets++;
+
+ qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len);
+ rx_ptype = (qword & I40E_RXD_QW1_PTYPE_MASK) >>
+ I40E_RXD_QW1_PTYPE_SHIFT;
+ i40e_process_skb_fields(rx_ring, rx_desc, skb, rx_ptype);
+
+ vlan_tag = (qword & BIT(I40E_RX_DESC_STATUS_L2TAG1P_SHIFT)) ?
+ le16_to_cpu(rx_desc->wb.qword0.lo_dword.l2tag1) : 0;
+ i40e_receive_skb(rx_ring, skb, vlan_tag);
+ }
+
+ i40e_finalize_xdp_rx(rx_ring, xdp_xmit);
+ i40e_update_rx_stats(rx_ring, total_rx_bytes, total_rx_packets);
+ return failure ? budget : (int)total_rx_packets;
+}
+
+/**
+ * i40e_xmit_zc - Performs zero-copy Tx AF_XDP
+ * @xdp_ring: XDP Tx ring
+ * @budget: NAPI budget
+ *
+ * Returns true if the work is finished.
+ **/
+static bool i40e_xmit_zc(struct i40e_ring *xdp_ring, unsigned int budget)
+{
+ struct i40e_tx_desc *tx_desc = NULL;
+ struct i40e_tx_buffer *tx_bi;
+ bool work_done = true;
+ dma_addr_t dma;
+ u32 len;
+
+ while (budget-- > 0) {
+ if (!unlikely(I40E_DESC_UNUSED(xdp_ring))) {
+ xdp_ring->tx_stats.tx_busy++;
+ work_done = false;
+ break;
+ }
+
+ if (!xsk_umem_consume_tx(xdp_ring->xsk_umem, &dma, &len))
+ break;
+
+ dma_sync_single_for_device(xdp_ring->dev, dma, len,
+ DMA_BIDIRECTIONAL);
+
+ tx_bi = &xdp_ring->tx_bi[xdp_ring->next_to_use];
+ tx_bi->bytecount = len;
+
+ tx_desc = I40E_TX_DESC(xdp_ring, xdp_ring->next_to_use);
+ tx_desc->buffer_addr = cpu_to_le64(dma);
+ tx_desc->cmd_type_offset_bsz =
+ build_ctob(I40E_TX_DESC_CMD_ICRC
+ | I40E_TX_DESC_CMD_EOP,
+ 0, len, 0);
+
+ xdp_ring->next_to_use++;
+ if (xdp_ring->next_to_use == xdp_ring->count)
+ xdp_ring->next_to_use = 0;
+ }
+
+ if (tx_desc) {
+ /* Request an interrupt for the last frame and bump tail ptr. */
+ tx_desc->cmd_type_offset_bsz |= (I40E_TX_DESC_CMD_RS <<
+ I40E_TXD_QW1_CMD_SHIFT);
+ i40e_xdp_ring_update_tail(xdp_ring);
+
+ xsk_umem_consume_tx_done(xdp_ring->xsk_umem);
+ }
+
+ return !!budget && work_done;
+}
+
+/**
+ * i40e_clean_xdp_tx_buffer - Frees and unmaps an XDP Tx entry
+ * @tx_ring: XDP Tx ring
+ * @tx_bi: Tx buffer info to clean
+ **/
+static void i40e_clean_xdp_tx_buffer(struct i40e_ring *tx_ring,
+ struct i40e_tx_buffer *tx_bi)
+{
+ xdp_return_frame(tx_bi->xdpf);
+ dma_unmap_single(tx_ring->dev,
+ dma_unmap_addr(tx_bi, dma),
+ dma_unmap_len(tx_bi, len), DMA_TO_DEVICE);
+ dma_unmap_len_set(tx_bi, len, 0);
+}
+
+/**
+ * i40e_clean_xdp_tx_irq - Completes AF_XDP entries, and cleans XDP entries
+ * @tx_ring: XDP Tx ring
+ * @tx_bi: Tx buffer info to clean
+ *
+ * Returns true if cleanup/tranmission is done.
+ **/
+bool i40e_clean_xdp_tx_irq(struct i40e_vsi *vsi,
+ struct i40e_ring *tx_ring, int napi_budget)
+{
+ unsigned int ntc, total_bytes = 0, budget = vsi->work_limit;
+ u32 i, completed_frames, frames_ready, xsk_frames = 0;
+ struct xdp_umem *umem = tx_ring->xsk_umem;
+ u32 head_idx = i40e_get_head(tx_ring);
+ bool work_done = true, xmit_done;
+ struct i40e_tx_buffer *tx_bi;
+
+ if (head_idx < tx_ring->next_to_clean)
+ head_idx += tx_ring->count;
+ frames_ready = head_idx - tx_ring->next_to_clean;
+
+ if (frames_ready == 0) {
+ goto out_xmit;
+ } else if (frames_ready > budget) {
+ completed_frames = budget;
+ work_done = false;
+ } else {
+ completed_frames = frames_ready;
+ }
+
+ ntc = tx_ring->next_to_clean;
+
+ for (i = 0; i < completed_frames; i++) {
+ tx_bi = &tx_ring->tx_bi[ntc];
+
+ if (tx_bi->xdpf)
+ i40e_clean_xdp_tx_buffer(tx_ring, tx_bi);
+ else
+ xsk_frames++;
+
+ tx_bi->xdpf = NULL;
+ total_bytes += tx_bi->bytecount;
+
+ if (++ntc >= tx_ring->count)
+ ntc = 0;
+ }
+
+ tx_ring->next_to_clean += completed_frames;
+ if (unlikely(tx_ring->next_to_clean >= tx_ring->count))
+ tx_ring->next_to_clean -= tx_ring->count;
+
+ if (xsk_frames)
+ xsk_umem_complete_tx(umem, xsk_frames);
+
+ i40e_arm_wb(tx_ring, vsi, budget);
+ i40e_update_tx_stats(tx_ring, completed_frames, total_bytes);
+
+out_xmit:
+ xmit_done = i40e_xmit_zc(tx_ring, budget);
+
+ return work_done && xmit_done;
+}
+
+/**
+ * i40e_xsk_async_xmit - Implements the ndo_xsk_async_xmit
+ * @dev: the netdevice
+ * @queue_id: queue id to wake up
+ *
+ * Returns <0 for errors, 0 otherwise.
+ **/
+int i40e_xsk_async_xmit(struct net_device *dev, u32 queue_id)
+{
+ struct i40e_netdev_priv *np = netdev_priv(dev);
+ struct i40e_vsi *vsi = np->vsi;
+ struct i40e_ring *ring;
+
+ if (test_bit(__I40E_VSI_DOWN, vsi->state))
+ return -ENETDOWN;
+
+ if (!i40e_enabled_xdp_vsi(vsi))
+ return -ENXIO;
+
+ if (queue_id >= vsi->num_queue_pairs)
+ return -ENXIO;
+
+ if (!vsi->xdp_rings[queue_id]->xsk_umem)
+ return -ENXIO;
+
+ ring = vsi->xdp_rings[queue_id];
+
+ /* The idea here is that if NAPI is running, mark a miss, so
+ * it will run again. If not, trigger an interrupt and
+ * schedule the NAPI from interrupt context. If NAPI would be
+ * scheduled here, the interrupt affinity would not be
+ * honored.
+ */
+ if (!napi_if_scheduled_mark_missed(&ring->q_vector->napi))
+ i40e_force_wb(vsi, ring->q_vector);
+
+ return 0;
+}
+
+void i40e_xsk_clean_rx_ring(struct i40e_ring *rx_ring)
+{
+ u16 i;
+
+ for (i = 0; i < rx_ring->count; i++) {
+ struct i40e_rx_buffer *rx_bi = &rx_ring->rx_bi[i];
+
+ if (!rx_bi->addr)
+ continue;
+
+ xsk_umem_fq_reuse(rx_ring->xsk_umem, rx_bi->handle);
+ rx_bi->addr = NULL;
+ }
+}
+
+/**
+ * i40e_xsk_clean_xdp_ring - Clean the XDP Tx ring on shutdown
+ * @xdp_ring: XDP Tx ring
+ **/
+void i40e_xsk_clean_tx_ring(struct i40e_ring *tx_ring)
+{
+ u16 ntc = tx_ring->next_to_clean, ntu = tx_ring->next_to_use;
+ struct xdp_umem *umem = tx_ring->xsk_umem;
+ struct i40e_tx_buffer *tx_bi;
+ u32 xsk_frames = 0;
+
+ while (ntc != ntu) {
+ tx_bi = &tx_ring->tx_bi[ntc];
+
+ if (tx_bi->xdpf)
+ i40e_clean_xdp_tx_buffer(tx_ring, tx_bi);
+ else
+ xsk_frames++;
+
+ tx_bi->xdpf = NULL;
+
+ ntc++;
+ if (ntc >= tx_ring->count)
+ ntc = 0;
+ }
+
+ if (xsk_frames)
+ xsk_umem_complete_tx(umem, xsk_frames);
+}
+
+/**
+ * i40e_xsk_any_rx_ring_enabled - Checks if Rx rings have AF_XDP UMEM attached
+ * @vsi: vsi
+ *
+ * Returns true if any of the Rx rings has an AF_XDP UMEM attached
+ **/
+bool i40e_xsk_any_rx_ring_enabled(struct i40e_vsi *vsi)
+{
+ int i;
+
+ if (!vsi->xsk_umems)
+ return false;
+
+ for (i = 0; i < vsi->num_queue_pairs; i++) {
+ if (vsi->xsk_umems[i])
+ return true;
+ }
+
+ return false;
+}
diff --git a/drivers/net/ethernet/intel/i40e/i40e_xsk.h b/drivers/net/ethernet/intel/i40e/i40e_xsk.h
new file mode 100644
index 000000000000..9038c5d5cf08
--- /dev/null
+++ b/drivers/net/ethernet/intel/i40e/i40e_xsk.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2018 Intel Corporation. */
+
+#ifndef _I40E_XSK_H_
+#define _I40E_XSK_H_
+
+struct i40e_vsi;
+struct xdp_umem;
+struct zero_copy_allocator;
+
+int i40e_queue_pair_disable(struct i40e_vsi *vsi, int queue_pair);
+int i40e_queue_pair_enable(struct i40e_vsi *vsi, int queue_pair);
+int i40e_xsk_umem_query(struct i40e_vsi *vsi, struct xdp_umem **umem,
+ u16 qid);
+int i40e_xsk_umem_setup(struct i40e_vsi *vsi, struct xdp_umem *umem,
+ u16 qid);
+void i40e_zca_free(struct zero_copy_allocator *alloc, unsigned long handle);
+bool i40e_alloc_rx_buffers_zc(struct i40e_ring *rx_ring, u16 cleaned_count);
+int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget);
+
+bool i40e_clean_xdp_tx_irq(struct i40e_vsi *vsi,
+ struct i40e_ring *tx_ring, int napi_budget);
+int i40e_xsk_async_xmit(struct net_device *dev, u32 queue_id);
+
+#endif /* _I40E_XSK_H_ */
diff --git a/drivers/net/ethernet/intel/i40evf/Makefile b/drivers/net/ethernet/intel/i40evf/Makefile
deleted file mode 100644
index 3c5c6e962280..000000000000
--- a/drivers/net/ethernet/intel/i40evf/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-# Copyright(c) 2013 - 2018 Intel Corporation.
-
-#
-## Makefile for the Intel(R) 40GbE VF driver
-#
-#
-
-ccflags-y += -I$(src)
-subdir-ccflags-y += -I$(src)
-
-obj-$(CONFIG_I40EVF) += i40evf.o
-
-i40evf-objs := i40evf_main.o i40evf_ethtool.o i40evf_virtchnl.o \
- i40e_txrx.o i40e_common.o i40e_adminq.o i40evf_client.o
-
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
deleted file mode 100644
index 5fd8529465d4..000000000000
--- a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
+++ /dev/null
@@ -1,2717 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/* Copyright(c) 2013 - 2018 Intel Corporation. */
-
-#ifndef _I40E_ADMINQ_CMD_H_
-#define _I40E_ADMINQ_CMD_H_
-
-/* This header file defines the i40e Admin Queue commands and is shared between
- * i40e Firmware and Software.
- *
- * This file needs to comply with the Linux Kernel coding style.
- */
-
-#define I40E_FW_API_VERSION_MAJOR 0x0001
-#define I40E_FW_API_VERSION_MINOR_X722 0x0005
-#define I40E_FW_API_VERSION_MINOR_X710 0x0007
-
-#define I40E_FW_MINOR_VERSION(_h) ((_h)->mac.type == I40E_MAC_XL710 ? \
- I40E_FW_API_VERSION_MINOR_X710 : \
- I40E_FW_API_VERSION_MINOR_X722)
-
-/* API version 1.7 implements additional link and PHY-specific APIs */
-#define I40E_MINOR_VER_GET_LINK_INFO_XL710 0x0007
-
-struct i40e_aq_desc {
- __le16 flags;
- __le16 opcode;
- __le16 datalen;
- __le16 retval;
- __le32 cookie_high;
- __le32 cookie_low;
- union {
- struct {
- __le32 param0;
- __le32 param1;
- __le32 param2;
- __le32 param3;
- } internal;
- struct {
- __le32 param0;
- __le32 param1;
- __le32 addr_high;
- __le32 addr_low;
- } external;
- u8 raw[16];
- } params;
-};
-
-/* Flags sub-structure
- * |0 |1 |2 |3 |4 |5 |6 |7 |8 |9 |10 |11 |12 |13 |14 |15 |
- * |DD |CMP|ERR|VFE| * * RESERVED * * |LB |RD |VFC|BUF|SI |EI |FE |
- */
-
-/* command flags and offsets*/
-#define I40E_AQ_FLAG_DD_SHIFT 0
-#define I40E_AQ_FLAG_CMP_SHIFT 1
-#define I40E_AQ_FLAG_ERR_SHIFT 2
-#define I40E_AQ_FLAG_VFE_SHIFT 3
-#define I40E_AQ_FLAG_LB_SHIFT 9
-#define I40E_AQ_FLAG_RD_SHIFT 10
-#define I40E_AQ_FLAG_VFC_SHIFT 11
-#define I40E_AQ_FLAG_BUF_SHIFT 12
-#define I40E_AQ_FLAG_SI_SHIFT 13
-#define I40E_AQ_FLAG_EI_SHIFT 14
-#define I40E_AQ_FLAG_FE_SHIFT 15
-
-#define I40E_AQ_FLAG_DD BIT(I40E_AQ_FLAG_DD_SHIFT) /* 0x1 */
-#define I40E_AQ_FLAG_CMP BIT(I40E_AQ_FLAG_CMP_SHIFT) /* 0x2 */
-#define I40E_AQ_FLAG_ERR BIT(I40E_AQ_FLAG_ERR_SHIFT) /* 0x4 */
-#define I40E_AQ_FLAG_VFE BIT(I40E_AQ_FLAG_VFE_SHIFT) /* 0x8 */
-#define I40E_AQ_FLAG_LB BIT(I40E_AQ_FLAG_LB_SHIFT) /* 0x200 */
-#define I40E_AQ_FLAG_RD BIT(I40E_AQ_FLAG_RD_SHIFT) /* 0x400 */
-#define I40E_AQ_FLAG_VFC BIT(I40E_AQ_FLAG_VFC_SHIFT) /* 0x800 */
-#define I40E_AQ_FLAG_BUF BIT(I40E_AQ_FLAG_BUF_SHIFT) /* 0x1000 */
-#define I40E_AQ_FLAG_SI BIT(I40E_AQ_FLAG_SI_SHIFT) /* 0x2000 */
-#define I40E_AQ_FLAG_EI BIT(I40E_AQ_FLAG_EI_SHIFT) /* 0x4000 */
-#define I40E_AQ_FLAG_FE BIT(I40E_AQ_FLAG_FE_SHIFT) /* 0x8000 */
-
-/* error codes */
-enum i40e_admin_queue_err {
- I40E_AQ_RC_OK = 0, /* success */
- I40E_AQ_RC_EPERM = 1, /* Operation not permitted */
- I40E_AQ_RC_ENOENT = 2, /* No such element */
- I40E_AQ_RC_ESRCH = 3, /* Bad opcode */
- I40E_AQ_RC_EINTR = 4, /* operation interrupted */
- I40E_AQ_RC_EIO = 5, /* I/O error */
- I40E_AQ_RC_ENXIO = 6, /* No such resource */
- I40E_AQ_RC_E2BIG = 7, /* Arg too long */
- I40E_AQ_RC_EAGAIN = 8, /* Try again */
- I40E_AQ_RC_ENOMEM = 9, /* Out of memory */
- I40E_AQ_RC_EACCES = 10, /* Permission denied */
- I40E_AQ_RC_EFAULT = 11, /* Bad address */
- I40E_AQ_RC_EBUSY = 12, /* Device or resource busy */
- I40E_AQ_RC_EEXIST = 13, /* object already exists */
- I40E_AQ_RC_EINVAL = 14, /* Invalid argument */
- I40E_AQ_RC_ENOTTY = 15, /* Not a typewriter */
- I40E_AQ_RC_ENOSPC = 16, /* No space left or alloc failure */
- I40E_AQ_RC_ENOSYS = 17, /* Function not implemented */
- I40E_AQ_RC_ERANGE = 18, /* Parameter out of range */
- I40E_AQ_RC_EFLUSHED = 19, /* Cmd flushed due to prev cmd error */
- I40E_AQ_RC_BAD_ADDR = 20, /* Descriptor contains a bad pointer */
- I40E_AQ_RC_EMODE = 21, /* Op not allowed in current dev mode */
- I40E_AQ_RC_EFBIG = 22, /* File too large */
-};
-
-/* Admin Queue command opcodes */
-enum i40e_admin_queue_opc {
- /* aq commands */
- i40e_aqc_opc_get_version = 0x0001,
- i40e_aqc_opc_driver_version = 0x0002,
- i40e_aqc_opc_queue_shutdown = 0x0003,
- i40e_aqc_opc_set_pf_context = 0x0004,
-
- /* resource ownership */
- i40e_aqc_opc_request_resource = 0x0008,
- i40e_aqc_opc_release_resource = 0x0009,
-
- i40e_aqc_opc_list_func_capabilities = 0x000A,
- i40e_aqc_opc_list_dev_capabilities = 0x000B,
-
- /* Proxy commands */
- i40e_aqc_opc_set_proxy_config = 0x0104,
- i40e_aqc_opc_set_ns_proxy_table_entry = 0x0105,
-
- /* LAA */
- i40e_aqc_opc_mac_address_read = 0x0107,
- i40e_aqc_opc_mac_address_write = 0x0108,
-
- /* PXE */
- i40e_aqc_opc_clear_pxe_mode = 0x0110,
-
- /* WoL commands */
- i40e_aqc_opc_set_wol_filter = 0x0120,
- i40e_aqc_opc_get_wake_reason = 0x0121,
-
- /* internal switch commands */
- i40e_aqc_opc_get_switch_config = 0x0200,
- i40e_aqc_opc_add_statistics = 0x0201,
- i40e_aqc_opc_remove_statistics = 0x0202,
- i40e_aqc_opc_set_port_parameters = 0x0203,
- i40e_aqc_opc_get_switch_resource_alloc = 0x0204,
- i40e_aqc_opc_set_switch_config = 0x0205,
- i40e_aqc_opc_rx_ctl_reg_read = 0x0206,
- i40e_aqc_opc_rx_ctl_reg_write = 0x0207,
-
- i40e_aqc_opc_add_vsi = 0x0210,
- i40e_aqc_opc_update_vsi_parameters = 0x0211,
- i40e_aqc_opc_get_vsi_parameters = 0x0212,
-
- i40e_aqc_opc_add_pv = 0x0220,
- i40e_aqc_opc_update_pv_parameters = 0x0221,
- i40e_aqc_opc_get_pv_parameters = 0x0222,
-
- i40e_aqc_opc_add_veb = 0x0230,
- i40e_aqc_opc_update_veb_parameters = 0x0231,
- i40e_aqc_opc_get_veb_parameters = 0x0232,
-
- i40e_aqc_opc_delete_element = 0x0243,
-
- i40e_aqc_opc_add_macvlan = 0x0250,
- i40e_aqc_opc_remove_macvlan = 0x0251,
- i40e_aqc_opc_add_vlan = 0x0252,
- i40e_aqc_opc_remove_vlan = 0x0253,
- i40e_aqc_opc_set_vsi_promiscuous_modes = 0x0254,
- i40e_aqc_opc_add_tag = 0x0255,
- i40e_aqc_opc_remove_tag = 0x0256,
- i40e_aqc_opc_add_multicast_etag = 0x0257,
- i40e_aqc_opc_remove_multicast_etag = 0x0258,
- i40e_aqc_opc_update_tag = 0x0259,
- i40e_aqc_opc_add_control_packet_filter = 0x025A,
- i40e_aqc_opc_remove_control_packet_filter = 0x025B,
- i40e_aqc_opc_add_cloud_filters = 0x025C,
- i40e_aqc_opc_remove_cloud_filters = 0x025D,
- i40e_aqc_opc_clear_wol_switch_filters = 0x025E,
-
- i40e_aqc_opc_add_mirror_rule = 0x0260,
- i40e_aqc_opc_delete_mirror_rule = 0x0261,
-
- /* Dynamic Device Personalization */
- i40e_aqc_opc_write_personalization_profile = 0x0270,
- i40e_aqc_opc_get_personalization_profile_list = 0x0271,
-
- /* DCB commands */
- i40e_aqc_opc_dcb_ignore_pfc = 0x0301,
- i40e_aqc_opc_dcb_updated = 0x0302,
- i40e_aqc_opc_set_dcb_parameters = 0x0303,
-
- /* TX scheduler */
- i40e_aqc_opc_configure_vsi_bw_limit = 0x0400,
- i40e_aqc_opc_configure_vsi_ets_sla_bw_limit = 0x0406,
- i40e_aqc_opc_configure_vsi_tc_bw = 0x0407,
- i40e_aqc_opc_query_vsi_bw_config = 0x0408,
- i40e_aqc_opc_query_vsi_ets_sla_config = 0x040A,
- i40e_aqc_opc_configure_switching_comp_bw_limit = 0x0410,
-
- i40e_aqc_opc_enable_switching_comp_ets = 0x0413,
- i40e_aqc_opc_modify_switching_comp_ets = 0x0414,
- i40e_aqc_opc_disable_switching_comp_ets = 0x0415,
- i40e_aqc_opc_configure_switching_comp_ets_bw_limit = 0x0416,
- i40e_aqc_opc_configure_switching_comp_bw_config = 0x0417,
- i40e_aqc_opc_query_switching_comp_ets_config = 0x0418,
- i40e_aqc_opc_query_port_ets_config = 0x0419,
- i40e_aqc_opc_query_switching_comp_bw_config = 0x041A,
- i40e_aqc_opc_suspend_port_tx = 0x041B,
- i40e_aqc_opc_resume_port_tx = 0x041C,
- i40e_aqc_opc_configure_partition_bw = 0x041D,
- /* hmc */
- i40e_aqc_opc_query_hmc_resource_profile = 0x0500,
- i40e_aqc_opc_set_hmc_resource_profile = 0x0501,
-
- /* phy commands*/
- i40e_aqc_opc_get_phy_abilities = 0x0600,
- i40e_aqc_opc_set_phy_config = 0x0601,
- i40e_aqc_opc_set_mac_config = 0x0603,
- i40e_aqc_opc_set_link_restart_an = 0x0605,
- i40e_aqc_opc_get_link_status = 0x0607,
- i40e_aqc_opc_set_phy_int_mask = 0x0613,
- i40e_aqc_opc_get_local_advt_reg = 0x0614,
- i40e_aqc_opc_set_local_advt_reg = 0x0615,
- i40e_aqc_opc_get_partner_advt = 0x0616,
- i40e_aqc_opc_set_lb_modes = 0x0618,
- i40e_aqc_opc_get_phy_wol_caps = 0x0621,
- i40e_aqc_opc_set_phy_debug = 0x0622,
- i40e_aqc_opc_upload_ext_phy_fm = 0x0625,
- i40e_aqc_opc_run_phy_activity = 0x0626,
- i40e_aqc_opc_set_phy_register = 0x0628,
- i40e_aqc_opc_get_phy_register = 0x0629,
-
- /* NVM commands */
- i40e_aqc_opc_nvm_read = 0x0701,
- i40e_aqc_opc_nvm_erase = 0x0702,
- i40e_aqc_opc_nvm_update = 0x0703,
- i40e_aqc_opc_nvm_config_read = 0x0704,
- i40e_aqc_opc_nvm_config_write = 0x0705,
- i40e_aqc_opc_oem_post_update = 0x0720,
- i40e_aqc_opc_thermal_sensor = 0x0721,
-
- /* virtualization commands */
- i40e_aqc_opc_send_msg_to_pf = 0x0801,
- i40e_aqc_opc_send_msg_to_vf = 0x0802,
- i40e_aqc_opc_send_msg_to_peer = 0x0803,
-
- /* alternate structure */
- i40e_aqc_opc_alternate_write = 0x0900,
- i40e_aqc_opc_alternate_write_indirect = 0x0901,
- i40e_aqc_opc_alternate_read = 0x0902,
- i40e_aqc_opc_alternate_read_indirect = 0x0903,
- i40e_aqc_opc_alternate_write_done = 0x0904,
- i40e_aqc_opc_alternate_set_mode = 0x0905,
- i40e_aqc_opc_alternate_clear_port = 0x0906,
-
- /* LLDP commands */
- i40e_aqc_opc_lldp_get_mib = 0x0A00,
- i40e_aqc_opc_lldp_update_mib = 0x0A01,
- i40e_aqc_opc_lldp_add_tlv = 0x0A02,
- i40e_aqc_opc_lldp_update_tlv = 0x0A03,
- i40e_aqc_opc_lldp_delete_tlv = 0x0A04,
- i40e_aqc_opc_lldp_stop = 0x0A05,
- i40e_aqc_opc_lldp_start = 0x0A06,
-
- /* Tunnel commands */
- i40e_aqc_opc_add_udp_tunnel = 0x0B00,
- i40e_aqc_opc_del_udp_tunnel = 0x0B01,
- i40e_aqc_opc_set_rss_key = 0x0B02,
- i40e_aqc_opc_set_rss_lut = 0x0B03,
- i40e_aqc_opc_get_rss_key = 0x0B04,
- i40e_aqc_opc_get_rss_lut = 0x0B05,
-
- /* Async Events */
- i40e_aqc_opc_event_lan_overflow = 0x1001,
-
- /* OEM commands */
- i40e_aqc_opc_oem_parameter_change = 0xFE00,
- i40e_aqc_opc_oem_device_status_change = 0xFE01,
- i40e_aqc_opc_oem_ocsd_initialize = 0xFE02,
- i40e_aqc_opc_oem_ocbb_initialize = 0xFE03,
-
- /* debug commands */
- i40e_aqc_opc_debug_read_reg = 0xFF03,
- i40e_aqc_opc_debug_write_reg = 0xFF04,
- i40e_aqc_opc_debug_modify_reg = 0xFF07,
- i40e_aqc_opc_debug_dump_internals = 0xFF08,
-};
-
-/* command structures and indirect data structures */
-
-/* Structure naming conventions:
- * - no suffix for direct command descriptor structures
- * - _data for indirect sent data
- * - _resp for indirect return data (data which is both will use _data)
- * - _completion for direct return data
- * - _element_ for repeated elements (may also be _data or _resp)
- *
- * Command structures are expected to overlay the params.raw member of the basic
- * descriptor, and as such cannot exceed 16 bytes in length.
- */
-
-/* This macro is used to generate a compilation error if a structure
- * is not exactly the correct length. It gives a divide by zero error if the
- * structure is not of the correct size, otherwise it creates an enum that is
- * never used.
- */
-#define I40E_CHECK_STRUCT_LEN(n, X) enum i40e_static_assert_enum_##X \
- { i40e_static_assert_##X = (n)/((sizeof(struct X) == (n)) ? 1 : 0) }
-
-/* This macro is used extensively to ensure that command structures are 16
- * bytes in length as they have to map to the raw array of that size.
- */
-#define I40E_CHECK_CMD_LENGTH(X) I40E_CHECK_STRUCT_LEN(16, X)
-
-/* internal (0x00XX) commands */
-
-/* Get version (direct 0x0001) */
-struct i40e_aqc_get_version {
- __le32 rom_ver;
- __le32 fw_build;
- __le16 fw_major;
- __le16 fw_minor;
- __le16 api_major;
- __le16 api_minor;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_get_version);
-
-/* Send driver version (indirect 0x0002) */
-struct i40e_aqc_driver_version {
- u8 driver_major_ver;
- u8 driver_minor_ver;
- u8 driver_build_ver;
- u8 driver_subbuild_ver;
- u8 reserved[4];
- __le32 address_high;
- __le32 address_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_driver_version);
-
-/* Queue Shutdown (direct 0x0003) */
-struct i40e_aqc_queue_shutdown {
- __le32 driver_unloading;
-#define I40E_AQ_DRIVER_UNLOADING 0x1
- u8 reserved[12];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_queue_shutdown);
-
-/* Set PF context (0x0004, direct) */
-struct i40e_aqc_set_pf_context {
- u8 pf_id;
- u8 reserved[15];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_set_pf_context);
-
-/* Request resource ownership (direct 0x0008)
- * Release resource ownership (direct 0x0009)
- */
-#define I40E_AQ_RESOURCE_NVM 1
-#define I40E_AQ_RESOURCE_SDP 2
-#define I40E_AQ_RESOURCE_ACCESS_READ 1
-#define I40E_AQ_RESOURCE_ACCESS_WRITE 2
-#define I40E_AQ_RESOURCE_NVM_READ_TIMEOUT 3000
-#define I40E_AQ_RESOURCE_NVM_WRITE_TIMEOUT 180000
-
-struct i40e_aqc_request_resource {
- __le16 resource_id;
- __le16 access_type;
- __le32 timeout;
- __le32 resource_number;
- u8 reserved[4];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_request_resource);
-
-/* Get function capabilities (indirect 0x000A)
- * Get device capabilities (indirect 0x000B)
- */
-struct i40e_aqc_list_capabilites {
- u8 command_flags;
-#define I40E_AQ_LIST_CAP_PF_INDEX_EN 1
- u8 pf_index;
- u8 reserved[2];
- __le32 count;
- __le32 addr_high;
- __le32 addr_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_list_capabilites);
-
-struct i40e_aqc_list_capabilities_element_resp {
- __le16 id;
- u8 major_rev;
- u8 minor_rev;
- __le32 number;
- __le32 logical_id;
- __le32 phys_id;
- u8 reserved[16];
-};
-
-/* list of caps */
-
-#define I40E_AQ_CAP_ID_SWITCH_MODE 0x0001
-#define I40E_AQ_CAP_ID_MNG_MODE 0x0002
-#define I40E_AQ_CAP_ID_NPAR_ACTIVE 0x0003
-#define I40E_AQ_CAP_ID_OS2BMC_CAP 0x0004
-#define I40E_AQ_CAP_ID_FUNCTIONS_VALID 0x0005
-#define I40E_AQ_CAP_ID_ALTERNATE_RAM 0x0006
-#define I40E_AQ_CAP_ID_WOL_AND_PROXY 0x0008
-#define I40E_AQ_CAP_ID_SRIOV 0x0012
-#define I40E_AQ_CAP_ID_VF 0x0013
-#define I40E_AQ_CAP_ID_VMDQ 0x0014
-#define I40E_AQ_CAP_ID_8021QBG 0x0015
-#define I40E_AQ_CAP_ID_8021QBR 0x0016
-#define I40E_AQ_CAP_ID_VSI 0x0017
-#define I40E_AQ_CAP_ID_DCB 0x0018
-#define I40E_AQ_CAP_ID_FCOE 0x0021
-#define I40E_AQ_CAP_ID_ISCSI 0x0022
-#define I40E_AQ_CAP_ID_RSS 0x0040
-#define I40E_AQ_CAP_ID_RXQ 0x0041
-#define I40E_AQ_CAP_ID_TXQ 0x0042
-#define I40E_AQ_CAP_ID_MSIX 0x0043
-#define I40E_AQ_CAP_ID_VF_MSIX 0x0044
-#define I40E_AQ_CAP_ID_FLOW_DIRECTOR 0x0045
-#define I40E_AQ_CAP_ID_1588 0x0046
-#define I40E_AQ_CAP_ID_IWARP 0x0051
-#define I40E_AQ_CAP_ID_LED 0x0061
-#define I40E_AQ_CAP_ID_SDP 0x0062
-#define I40E_AQ_CAP_ID_MDIO 0x0063
-#define I40E_AQ_CAP_ID_WSR_PROT 0x0064
-#define I40E_AQ_CAP_ID_NVM_MGMT 0x0080
-#define I40E_AQ_CAP_ID_FLEX10 0x00F1
-#define I40E_AQ_CAP_ID_CEM 0x00F2
-
-/* Set CPPM Configuration (direct 0x0103) */
-struct i40e_aqc_cppm_configuration {
- __le16 command_flags;
-#define I40E_AQ_CPPM_EN_LTRC 0x0800
-#define I40E_AQ_CPPM_EN_DMCTH 0x1000
-#define I40E_AQ_CPPM_EN_DMCTLX 0x2000
-#define I40E_AQ_CPPM_EN_HPTC 0x4000
-#define I40E_AQ_CPPM_EN_DMARC 0x8000
- __le16 ttlx;
- __le32 dmacr;
- __le16 dmcth;
- u8 hptc;
- u8 reserved;
- __le32 pfltrc;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_cppm_configuration);
-
-/* Set ARP Proxy command / response (indirect 0x0104) */
-struct i40e_aqc_arp_proxy_data {
- __le16 command_flags;
-#define I40E_AQ_ARP_INIT_IPV4 0x0800
-#define I40E_AQ_ARP_UNSUP_CTL 0x1000
-#define I40E_AQ_ARP_ENA 0x2000
-#define I40E_AQ_ARP_ADD_IPV4 0x4000
-#define I40E_AQ_ARP_DEL_IPV4 0x8000
- __le16 table_id;
- __le32 enabled_offloads;
-#define I40E_AQ_ARP_DIRECTED_OFFLOAD_ENABLE 0x00000020
-#define I40E_AQ_ARP_OFFLOAD_ENABLE 0x00000800
- __le32 ip_addr;
- u8 mac_addr[6];
- u8 reserved[2];
-};
-
-I40E_CHECK_STRUCT_LEN(0x14, i40e_aqc_arp_proxy_data);
-
-/* Set NS Proxy Table Entry Command (indirect 0x0105) */
-struct i40e_aqc_ns_proxy_data {
- __le16 table_idx_mac_addr_0;
- __le16 table_idx_mac_addr_1;
- __le16 table_idx_ipv6_0;
- __le16 table_idx_ipv6_1;
- __le16 control;
-#define I40E_AQ_NS_PROXY_ADD_0 0x0001
-#define I40E_AQ_NS_PROXY_DEL_0 0x0002
-#define I40E_AQ_NS_PROXY_ADD_1 0x0004
-#define I40E_AQ_NS_PROXY_DEL_1 0x0008
-#define I40E_AQ_NS_PROXY_ADD_IPV6_0 0x0010
-#define I40E_AQ_NS_PROXY_DEL_IPV6_0 0x0020
-#define I40E_AQ_NS_PROXY_ADD_IPV6_1 0x0040
-#define I40E_AQ_NS_PROXY_DEL_IPV6_1 0x0080
-#define I40E_AQ_NS_PROXY_COMMAND_SEQ 0x0100
-#define I40E_AQ_NS_PROXY_INIT_IPV6_TBL 0x0200
-#define I40E_AQ_NS_PROXY_INIT_MAC_TBL 0x0400
-#define I40E_AQ_NS_PROXY_OFFLOAD_ENABLE 0x0800
-#define I40E_AQ_NS_PROXY_DIRECTED_OFFLOAD_ENABLE 0x1000
- u8 mac_addr_0[6];
- u8 mac_addr_1[6];
- u8 local_mac_addr[6];
- u8 ipv6_addr_0[16]; /* Warning! spec specifies BE byte order */
- u8 ipv6_addr_1[16];
-};
-
-I40E_CHECK_STRUCT_LEN(0x3c, i40e_aqc_ns_proxy_data);
-
-/* Manage LAA Command (0x0106) - obsolete */
-struct i40e_aqc_mng_laa {
- __le16 command_flags;
-#define I40E_AQ_LAA_FLAG_WR 0x8000
- u8 reserved[2];
- __le32 sal;
- __le16 sah;
- u8 reserved2[6];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_mng_laa);
-
-/* Manage MAC Address Read Command (indirect 0x0107) */
-struct i40e_aqc_mac_address_read {
- __le16 command_flags;
-#define I40E_AQC_LAN_ADDR_VALID 0x10
-#define I40E_AQC_SAN_ADDR_VALID 0x20
-#define I40E_AQC_PORT_ADDR_VALID 0x40
-#define I40E_AQC_WOL_ADDR_VALID 0x80
-#define I40E_AQC_MC_MAG_EN_VALID 0x100
-#define I40E_AQC_ADDR_VALID_MASK 0x3F0
- u8 reserved[6];
- __le32 addr_high;
- __le32 addr_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_mac_address_read);
-
-struct i40e_aqc_mac_address_read_data {
- u8 pf_lan_mac[6];
- u8 pf_san_mac[6];
- u8 port_mac[6];
- u8 pf_wol_mac[6];
-};
-
-I40E_CHECK_STRUCT_LEN(24, i40e_aqc_mac_address_read_data);
-
-/* Manage MAC Address Write Command (0x0108) */
-struct i40e_aqc_mac_address_write {
- __le16 command_flags;
-#define I40E_AQC_WRITE_TYPE_LAA_ONLY 0x0000
-#define I40E_AQC_WRITE_TYPE_LAA_WOL 0x4000
-#define I40E_AQC_WRITE_TYPE_PORT 0x8000
-#define I40E_AQC_WRITE_TYPE_UPDATE_MC_MAG 0xC000
-#define I40E_AQC_WRITE_TYPE_MASK 0xC000
-
- __le16 mac_sah;
- __le32 mac_sal;
- u8 reserved[8];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_mac_address_write);
-
-/* PXE commands (0x011x) */
-
-/* Clear PXE Command and response (direct 0x0110) */
-struct i40e_aqc_clear_pxe {
- u8 rx_cnt;
- u8 reserved[15];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_clear_pxe);
-
-/* Set WoL Filter (0x0120) */
-
-struct i40e_aqc_set_wol_filter {
- __le16 filter_index;
-#define I40E_AQC_MAX_NUM_WOL_FILTERS 8
-#define I40E_AQC_SET_WOL_FILTER_TYPE_MAGIC_SHIFT 15
-#define I40E_AQC_SET_WOL_FILTER_TYPE_MAGIC_MASK (0x1 << \
- I40E_AQC_SET_WOL_FILTER_TYPE_MAGIC_SHIFT)
-
-#define I40E_AQC_SET_WOL_FILTER_INDEX_SHIFT 0
-#define I40E_AQC_SET_WOL_FILTER_INDEX_MASK (0x7 << \
- I40E_AQC_SET_WOL_FILTER_INDEX_SHIFT)
- __le16 cmd_flags;
-#define I40E_AQC_SET_WOL_FILTER 0x8000
-#define I40E_AQC_SET_WOL_FILTER_NO_TCO_WOL 0x4000
-#define I40E_AQC_SET_WOL_FILTER_WOL_PRESERVE_ON_PFR 0x2000
-#define I40E_AQC_SET_WOL_FILTER_ACTION_CLEAR 0
-#define I40E_AQC_SET_WOL_FILTER_ACTION_SET 1
- __le16 valid_flags;
-#define I40E_AQC_SET_WOL_FILTER_ACTION_VALID 0x8000
-#define I40E_AQC_SET_WOL_FILTER_NO_TCO_ACTION_VALID 0x4000
- u8 reserved[2];
- __le32 address_high;
- __le32 address_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_set_wol_filter);
-
-struct i40e_aqc_set_wol_filter_data {
- u8 filter[128];
- u8 mask[16];
-};
-
-I40E_CHECK_STRUCT_LEN(0x90, i40e_aqc_set_wol_filter_data);
-
-/* Get Wake Reason (0x0121) */
-
-struct i40e_aqc_get_wake_reason_completion {
- u8 reserved_1[2];
- __le16 wake_reason;
-#define I40E_AQC_GET_WAKE_UP_REASON_WOL_REASON_MATCHED_INDEX_SHIFT 0
-#define I40E_AQC_GET_WAKE_UP_REASON_WOL_REASON_MATCHED_INDEX_MASK (0xFF << \
- I40E_AQC_GET_WAKE_UP_REASON_WOL_REASON_MATCHED_INDEX_SHIFT)
-#define I40E_AQC_GET_WAKE_UP_REASON_WOL_REASON_RESERVED_SHIFT 8
-#define I40E_AQC_GET_WAKE_UP_REASON_WOL_REASON_RESERVED_MASK (0xFF << \
- I40E_AQC_GET_WAKE_UP_REASON_WOL_REASON_RESERVED_SHIFT)
- u8 reserved_2[12];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_get_wake_reason_completion);
-
-/* Switch configuration commands (0x02xx) */
-
-/* Used by many indirect commands that only pass an seid and a buffer in the
- * command
- */
-struct i40e_aqc_switch_seid {
- __le16 seid;
- u8 reserved[6];
- __le32 addr_high;
- __le32 addr_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_switch_seid);
-
-/* Get Switch Configuration command (indirect 0x0200)
- * uses i40e_aqc_switch_seid for the descriptor
- */
-struct i40e_aqc_get_switch_config_header_resp {
- __le16 num_reported;
- __le16 num_total;
- u8 reserved[12];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_get_switch_config_header_resp);
-
-struct i40e_aqc_switch_config_element_resp {
- u8 element_type;
-#define I40E_AQ_SW_ELEM_TYPE_MAC 1
-#define I40E_AQ_SW_ELEM_TYPE_PF 2
-#define I40E_AQ_SW_ELEM_TYPE_VF 3
-#define I40E_AQ_SW_ELEM_TYPE_EMP 4
-#define I40E_AQ_SW_ELEM_TYPE_BMC 5
-#define I40E_AQ_SW_ELEM_TYPE_PV 16
-#define I40E_AQ_SW_ELEM_TYPE_VEB 17
-#define I40E_AQ_SW_ELEM_TYPE_PA 18
-#define I40E_AQ_SW_ELEM_TYPE_VSI 19
- u8 revision;
-#define I40E_AQ_SW_ELEM_REV_1 1
- __le16 seid;
- __le16 uplink_seid;
- __le16 downlink_seid;
- u8 reserved[3];
- u8 connection_type;
-#define I40E_AQ_CONN_TYPE_REGULAR 0x1
-#define I40E_AQ_CONN_TYPE_DEFAULT 0x2
-#define I40E_AQ_CONN_TYPE_CASCADED 0x3
- __le16 scheduler_id;
- __le16 element_info;
-};
-
-I40E_CHECK_STRUCT_LEN(0x10, i40e_aqc_switch_config_element_resp);
-
-/* Get Switch Configuration (indirect 0x0200)
- * an array of elements are returned in the response buffer
- * the first in the array is the header, remainder are elements
- */
-struct i40e_aqc_get_switch_config_resp {
- struct i40e_aqc_get_switch_config_header_resp header;
- struct i40e_aqc_switch_config_element_resp element[1];
-};
-
-I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_get_switch_config_resp);
-
-/* Add Statistics (direct 0x0201)
- * Remove Statistics (direct 0x0202)
- */
-struct i40e_aqc_add_remove_statistics {
- __le16 seid;
- __le16 vlan;
- __le16 stat_index;
- u8 reserved[10];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_statistics);
-
-/* Set Port Parameters command (direct 0x0203) */
-struct i40e_aqc_set_port_parameters {
- __le16 command_flags;
-#define I40E_AQ_SET_P_PARAMS_SAVE_BAD_PACKETS 1
-#define I40E_AQ_SET_P_PARAMS_PAD_SHORT_PACKETS 2 /* must set! */
-#define I40E_AQ_SET_P_PARAMS_DOUBLE_VLAN_ENA 4
- __le16 bad_frame_vsi;
-#define I40E_AQ_SET_P_PARAMS_BFRAME_SEID_SHIFT 0x0
-#define I40E_AQ_SET_P_PARAMS_BFRAME_SEID_MASK 0x3FF
- __le16 default_seid; /* reserved for command */
- u8 reserved[10];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_set_port_parameters);
-
-/* Get Switch Resource Allocation (indirect 0x0204) */
-struct i40e_aqc_get_switch_resource_alloc {
- u8 num_entries; /* reserved for command */
- u8 reserved[7];
- __le32 addr_high;
- __le32 addr_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_get_switch_resource_alloc);
-
-/* expect an array of these structs in the response buffer */
-struct i40e_aqc_switch_resource_alloc_element_resp {
- u8 resource_type;
-#define I40E_AQ_RESOURCE_TYPE_VEB 0x0
-#define I40E_AQ_RESOURCE_TYPE_VSI 0x1
-#define I40E_AQ_RESOURCE_TYPE_MACADDR 0x2
-#define I40E_AQ_RESOURCE_TYPE_STAG 0x3
-#define I40E_AQ_RESOURCE_TYPE_ETAG 0x4
-#define I40E_AQ_RESOURCE_TYPE_MULTICAST_HASH 0x5
-#define I40E_AQ_RESOURCE_TYPE_UNICAST_HASH 0x6
-#define I40E_AQ_RESOURCE_TYPE_VLAN 0x7
-#define I40E_AQ_RESOURCE_TYPE_VSI_LIST_ENTRY 0x8
-#define I40E_AQ_RESOURCE_TYPE_ETAG_LIST_ENTRY 0x9
-#define I40E_AQ_RESOURCE_TYPE_VLAN_STAT_POOL 0xA
-#define I40E_AQ_RESOURCE_TYPE_MIRROR_RULE 0xB
-#define I40E_AQ_RESOURCE_TYPE_QUEUE_SETS 0xC
-#define I40E_AQ_RESOURCE_TYPE_VLAN_FILTERS 0xD
-#define I40E_AQ_RESOURCE_TYPE_INNER_MAC_FILTERS 0xF
-#define I40E_AQ_RESOURCE_TYPE_IP_FILTERS 0x10
-#define I40E_AQ_RESOURCE_TYPE_GRE_VN_KEYS 0x11
-#define I40E_AQ_RESOURCE_TYPE_VN2_KEYS 0x12
-#define I40E_AQ_RESOURCE_TYPE_TUNNEL_PORTS 0x13
- u8 reserved1;
- __le16 guaranteed;
- __le16 total;
- __le16 used;
- __le16 total_unalloced;
- u8 reserved2[6];
-};
-
-I40E_CHECK_STRUCT_LEN(0x10, i40e_aqc_switch_resource_alloc_element_resp);
-
-/* Set Switch Configuration (direct 0x0205) */
-struct i40e_aqc_set_switch_config {
- __le16 flags;
-/* flags used for both fields below */
-#define I40E_AQ_SET_SWITCH_CFG_PROMISC 0x0001
-#define I40E_AQ_SET_SWITCH_CFG_L2_FILTER 0x0002
- __le16 valid_flags;
- /* The ethertype in switch_tag is dropped on ingress and used
- * internally by the switch. Set this to zero for the default
- * of 0x88a8 (802.1ad). Should be zero for firmware API
- * versions lower than 1.7.
- */
- __le16 switch_tag;
- /* The ethertypes in first_tag and second_tag are used to
- * match the outer and inner VLAN tags (respectively) when HW
- * double VLAN tagging is enabled via the set port parameters
- * AQ command. Otherwise these are both ignored. Set them to
- * zero for their defaults of 0x8100 (802.1Q). Should be zero
- * for firmware API versions lower than 1.7.
- */
- __le16 first_tag;
- __le16 second_tag;
- u8 reserved[6];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_set_switch_config);
-
-/* Read Receive control registers (direct 0x0206)
- * Write Receive control registers (direct 0x0207)
- * used for accessing Rx control registers that can be
- * slow and need special handling when under high Rx load
- */
-struct i40e_aqc_rx_ctl_reg_read_write {
- __le32 reserved1;
- __le32 address;
- __le32 reserved2;
- __le32 value;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_rx_ctl_reg_read_write);
-
-/* Add VSI (indirect 0x0210)
- * this indirect command uses struct i40e_aqc_vsi_properties_data
- * as the indirect buffer (128 bytes)
- *
- * Update VSI (indirect 0x211)
- * uses the same data structure as Add VSI
- *
- * Get VSI (indirect 0x0212)
- * uses the same completion and data structure as Add VSI
- */
-struct i40e_aqc_add_get_update_vsi {
- __le16 uplink_seid;
- u8 connection_type;
-#define I40E_AQ_VSI_CONN_TYPE_NORMAL 0x1
-#define I40E_AQ_VSI_CONN_TYPE_DEFAULT 0x2
-#define I40E_AQ_VSI_CONN_TYPE_CASCADED 0x3
- u8 reserved1;
- u8 vf_id;
- u8 reserved2;
- __le16 vsi_flags;
-#define I40E_AQ_VSI_TYPE_SHIFT 0x0
-#define I40E_AQ_VSI_TYPE_MASK (0x3 << I40E_AQ_VSI_TYPE_SHIFT)
-#define I40E_AQ_VSI_TYPE_VF 0x0
-#define I40E_AQ_VSI_TYPE_VMDQ2 0x1
-#define I40E_AQ_VSI_TYPE_PF 0x2
-#define I40E_AQ_VSI_TYPE_EMP_MNG 0x3
-#define I40E_AQ_VSI_FLAG_CASCADED_PV 0x4
- __le32 addr_high;
- __le32 addr_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_add_get_update_vsi);
-
-struct i40e_aqc_add_get_update_vsi_completion {
- __le16 seid;
- __le16 vsi_number;
- __le16 vsi_used;
- __le16 vsi_free;
- __le32 addr_high;
- __le32 addr_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_add_get_update_vsi_completion);
-
-struct i40e_aqc_vsi_properties_data {
- /* first 96 byte are written by SW */
- __le16 valid_sections;
-#define I40E_AQ_VSI_PROP_SWITCH_VALID 0x0001
-#define I40E_AQ_VSI_PROP_SECURITY_VALID 0x0002
-#define I40E_AQ_VSI_PROP_VLAN_VALID 0x0004
-#define I40E_AQ_VSI_PROP_CAS_PV_VALID 0x0008
-#define I40E_AQ_VSI_PROP_INGRESS_UP_VALID 0x0010
-#define I40E_AQ_VSI_PROP_EGRESS_UP_VALID 0x0020
-#define I40E_AQ_VSI_PROP_QUEUE_MAP_VALID 0x0040
-#define I40E_AQ_VSI_PROP_QUEUE_OPT_VALID 0x0080
-#define I40E_AQ_VSI_PROP_OUTER_UP_VALID 0x0100
-#define I40E_AQ_VSI_PROP_SCHED_VALID 0x0200
- /* switch section */
- __le16 switch_id; /* 12bit id combined with flags below */
-#define I40E_AQ_VSI_SW_ID_SHIFT 0x0000
-#define I40E_AQ_VSI_SW_ID_MASK (0xFFF << I40E_AQ_VSI_SW_ID_SHIFT)
-#define I40E_AQ_VSI_SW_ID_FLAG_NOT_STAG 0x1000
-#define I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB 0x2000
-#define I40E_AQ_VSI_SW_ID_FLAG_LOCAL_LB 0x4000
- u8 sw_reserved[2];
- /* security section */
- u8 sec_flags;
-#define I40E_AQ_VSI_SEC_FLAG_ALLOW_DEST_OVRD 0x01
-#define I40E_AQ_VSI_SEC_FLAG_ENABLE_VLAN_CHK 0x02
-#define I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK 0x04
- u8 sec_reserved;
- /* VLAN section */
- __le16 pvid; /* VLANS include priority bits */
- __le16 fcoe_pvid;
- u8 port_vlan_flags;
-#define I40E_AQ_VSI_PVLAN_MODE_SHIFT 0x00
-#define I40E_AQ_VSI_PVLAN_MODE_MASK (0x03 << \
- I40E_AQ_VSI_PVLAN_MODE_SHIFT)
-#define I40E_AQ_VSI_PVLAN_MODE_TAGGED 0x01
-#define I40E_AQ_VSI_PVLAN_MODE_UNTAGGED 0x02
-#define I40E_AQ_VSI_PVLAN_MODE_ALL 0x03
-#define I40E_AQ_VSI_PVLAN_INSERT_PVID 0x04
-#define I40E_AQ_VSI_PVLAN_EMOD_SHIFT 0x03
-#define I40E_AQ_VSI_PVLAN_EMOD_MASK (0x3 << \
- I40E_AQ_VSI_PVLAN_EMOD_SHIFT)
-#define I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH 0x0
-#define I40E_AQ_VSI_PVLAN_EMOD_STR_UP 0x08
-#define I40E_AQ_VSI_PVLAN_EMOD_STR 0x10
-#define I40E_AQ_VSI_PVLAN_EMOD_NOTHING 0x18
- u8 pvlan_reserved[3];
- /* ingress egress up sections */
- __le32 ingress_table; /* bitmap, 3 bits per up */
-#define I40E_AQ_VSI_UP_TABLE_UP0_SHIFT 0
-#define I40E_AQ_VSI_UP_TABLE_UP0_MASK (0x7 << \
- I40E_AQ_VSI_UP_TABLE_UP0_SHIFT)
-#define I40E_AQ_VSI_UP_TABLE_UP1_SHIFT 3
-#define I40E_AQ_VSI_UP_TABLE_UP1_MASK (0x7 << \
- I40E_AQ_VSI_UP_TABLE_UP1_SHIFT)
-#define I40E_AQ_VSI_UP_TABLE_UP2_SHIFT 6
-#define I40E_AQ_VSI_UP_TABLE_UP2_MASK (0x7 << \
- I40E_AQ_VSI_UP_TABLE_UP2_SHIFT)
-#define I40E_AQ_VSI_UP_TABLE_UP3_SHIFT 9
-#define I40E_AQ_VSI_UP_TABLE_UP3_MASK (0x7 << \
- I40E_AQ_VSI_UP_TABLE_UP3_SHIFT)
-#define I40E_AQ_VSI_UP_TABLE_UP4_SHIFT 12
-#define I40E_AQ_VSI_UP_TABLE_UP4_MASK (0x7 << \
- I40E_AQ_VSI_UP_TABLE_UP4_SHIFT)
-#define I40E_AQ_VSI_UP_TABLE_UP5_SHIFT 15
-#define I40E_AQ_VSI_UP_TABLE_UP5_MASK (0x7 << \
- I40E_AQ_VSI_UP_TABLE_UP5_SHIFT)
-#define I40E_AQ_VSI_UP_TABLE_UP6_SHIFT 18
-#define I40E_AQ_VSI_UP_TABLE_UP6_MASK (0x7 << \
- I40E_AQ_VSI_UP_TABLE_UP6_SHIFT)
-#define I40E_AQ_VSI_UP_TABLE_UP7_SHIFT 21
-#define I40E_AQ_VSI_UP_TABLE_UP7_MASK (0x7 << \
- I40E_AQ_VSI_UP_TABLE_UP7_SHIFT)
- __le32 egress_table; /* same defines as for ingress table */
- /* cascaded PV section */
- __le16 cas_pv_tag;
- u8 cas_pv_flags;
-#define I40E_AQ_VSI_CAS_PV_TAGX_SHIFT 0x00
-#define I40E_AQ_VSI_CAS_PV_TAGX_MASK (0x03 << \
- I40E_AQ_VSI_CAS_PV_TAGX_SHIFT)
-#define I40E_AQ_VSI_CAS_PV_TAGX_LEAVE 0x00
-#define I40E_AQ_VSI_CAS_PV_TAGX_REMOVE 0x01
-#define I40E_AQ_VSI_CAS_PV_TAGX_COPY 0x02
-#define I40E_AQ_VSI_CAS_PV_INSERT_TAG 0x10
-#define I40E_AQ_VSI_CAS_PV_ETAG_PRUNE 0x20
-#define I40E_AQ_VSI_CAS_PV_ACCEPT_HOST_TAG 0x40
- u8 cas_pv_reserved;
- /* queue mapping section */
- __le16 mapping_flags;
-#define I40E_AQ_VSI_QUE_MAP_CONTIG 0x0
-#define I40E_AQ_VSI_QUE_MAP_NONCONTIG 0x1
- __le16 queue_mapping[16];
-#define I40E_AQ_VSI_QUEUE_SHIFT 0x0
-#define I40E_AQ_VSI_QUEUE_MASK (0x7FF << I40E_AQ_VSI_QUEUE_SHIFT)
- __le16 tc_mapping[8];
-#define I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT 0
-#define I40E_AQ_VSI_TC_QUE_OFFSET_MASK (0x1FF << \
- I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT)
-#define I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT 9
-#define I40E_AQ_VSI_TC_QUE_NUMBER_MASK (0x7 << \
- I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT)
- /* queueing option section */
- u8 queueing_opt_flags;
-#define I40E_AQ_VSI_QUE_OPT_MULTICAST_UDP_ENA 0x04
-#define I40E_AQ_VSI_QUE_OPT_UNICAST_UDP_ENA 0x08
-#define I40E_AQ_VSI_QUE_OPT_TCP_ENA 0x10
-#define I40E_AQ_VSI_QUE_OPT_FCOE_ENA 0x20
-#define I40E_AQ_VSI_QUE_OPT_RSS_LUT_PF 0x00
-#define I40E_AQ_VSI_QUE_OPT_RSS_LUT_VSI 0x40
- u8 queueing_opt_reserved[3];
- /* scheduler section */
- u8 up_enable_bits;
- u8 sched_reserved;
- /* outer up section */
- __le32 outer_up_table; /* same structure and defines as ingress tbl */
- u8 cmd_reserved[8];
- /* last 32 bytes are written by FW */
- __le16 qs_handle[8];
-#define I40E_AQ_VSI_QS_HANDLE_INVALID 0xFFFF
- __le16 stat_counter_idx;
- __le16 sched_id;
- u8 resp_reserved[12];
-};
-
-I40E_CHECK_STRUCT_LEN(128, i40e_aqc_vsi_properties_data);
-
-/* Add Port Virtualizer (direct 0x0220)
- * also used for update PV (direct 0x0221) but only flags are used
- * (IS_CTRL_PORT only works on add PV)
- */
-struct i40e_aqc_add_update_pv {
- __le16 command_flags;
-#define I40E_AQC_PV_FLAG_PV_TYPE 0x1
-#define I40E_AQC_PV_FLAG_FWD_UNKNOWN_STAG_EN 0x2
-#define I40E_AQC_PV_FLAG_FWD_UNKNOWN_ETAG_EN 0x4
-#define I40E_AQC_PV_FLAG_IS_CTRL_PORT 0x8
- __le16 uplink_seid;
- __le16 connected_seid;
- u8 reserved[10];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_add_update_pv);
-
-struct i40e_aqc_add_update_pv_completion {
- /* reserved for update; for add also encodes error if rc == ENOSPC */
- __le16 pv_seid;
-#define I40E_AQC_PV_ERR_FLAG_NO_PV 0x1
-#define I40E_AQC_PV_ERR_FLAG_NO_SCHED 0x2
-#define I40E_AQC_PV_ERR_FLAG_NO_COUNTER 0x4
-#define I40E_AQC_PV_ERR_FLAG_NO_ENTRY 0x8
- u8 reserved[14];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_add_update_pv_completion);
-
-/* Get PV Params (direct 0x0222)
- * uses i40e_aqc_switch_seid for the descriptor
- */
-
-struct i40e_aqc_get_pv_params_completion {
- __le16 seid;
- __le16 default_stag;
- __le16 pv_flags; /* same flags as add_pv */
-#define I40E_AQC_GET_PV_PV_TYPE 0x1
-#define I40E_AQC_GET_PV_FRWD_UNKNOWN_STAG 0x2
-#define I40E_AQC_GET_PV_FRWD_UNKNOWN_ETAG 0x4
- u8 reserved[8];
- __le16 default_port_seid;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_get_pv_params_completion);
-
-/* Add VEB (direct 0x0230) */
-struct i40e_aqc_add_veb {
- __le16 uplink_seid;
- __le16 downlink_seid;
- __le16 veb_flags;
-#define I40E_AQC_ADD_VEB_FLOATING 0x1
-#define I40E_AQC_ADD_VEB_PORT_TYPE_SHIFT 1
-#define I40E_AQC_ADD_VEB_PORT_TYPE_MASK (0x3 << \
- I40E_AQC_ADD_VEB_PORT_TYPE_SHIFT)
-#define I40E_AQC_ADD_VEB_PORT_TYPE_DEFAULT 0x2
-#define I40E_AQC_ADD_VEB_PORT_TYPE_DATA 0x4
-#define I40E_AQC_ADD_VEB_ENABLE_L2_FILTER 0x8 /* deprecated */
-#define I40E_AQC_ADD_VEB_ENABLE_DISABLE_STATS 0x10
- u8 enable_tcs;
- u8 reserved[9];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_add_veb);
-
-struct i40e_aqc_add_veb_completion {
- u8 reserved[6];
- __le16 switch_seid;
- /* also encodes error if rc == ENOSPC; codes are the same as add_pv */
- __le16 veb_seid;
-#define I40E_AQC_VEB_ERR_FLAG_NO_VEB 0x1
-#define I40E_AQC_VEB_ERR_FLAG_NO_SCHED 0x2
-#define I40E_AQC_VEB_ERR_FLAG_NO_COUNTER 0x4
-#define I40E_AQC_VEB_ERR_FLAG_NO_ENTRY 0x8
- __le16 statistic_index;
- __le16 vebs_used;
- __le16 vebs_free;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_add_veb_completion);
-
-/* Get VEB Parameters (direct 0x0232)
- * uses i40e_aqc_switch_seid for the descriptor
- */
-struct i40e_aqc_get_veb_parameters_completion {
- __le16 seid;
- __le16 switch_id;
- __le16 veb_flags; /* only the first/last flags from 0x0230 is valid */
- __le16 statistic_index;
- __le16 vebs_used;
- __le16 vebs_free;
- u8 reserved[4];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_get_veb_parameters_completion);
-
-/* Delete Element (direct 0x0243)
- * uses the generic i40e_aqc_switch_seid
- */
-
-/* Add MAC-VLAN (indirect 0x0250) */
-
-/* used for the command for most vlan commands */
-struct i40e_aqc_macvlan {
- __le16 num_addresses;
- __le16 seid[3];
-#define I40E_AQC_MACVLAN_CMD_SEID_NUM_SHIFT 0
-#define I40E_AQC_MACVLAN_CMD_SEID_NUM_MASK (0x3FF << \
- I40E_AQC_MACVLAN_CMD_SEID_NUM_SHIFT)
-#define I40E_AQC_MACVLAN_CMD_SEID_VALID 0x8000
- __le32 addr_high;
- __le32 addr_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_macvlan);
-
-/* indirect data for command and response */
-struct i40e_aqc_add_macvlan_element_data {
- u8 mac_addr[6];
- __le16 vlan_tag;
- __le16 flags;
-#define I40E_AQC_MACVLAN_ADD_PERFECT_MATCH 0x0001
-#define I40E_AQC_MACVLAN_ADD_HASH_MATCH 0x0002
-#define I40E_AQC_MACVLAN_ADD_IGNORE_VLAN 0x0004
-#define I40E_AQC_MACVLAN_ADD_TO_QUEUE 0x0008
-#define I40E_AQC_MACVLAN_ADD_USE_SHARED_MAC 0x0010
- __le16 queue_number;
-#define I40E_AQC_MACVLAN_CMD_QUEUE_SHIFT 0
-#define I40E_AQC_MACVLAN_CMD_QUEUE_MASK (0x7FF << \
- I40E_AQC_MACVLAN_CMD_SEID_NUM_SHIFT)
- /* response section */
- u8 match_method;
-#define I40E_AQC_MM_PERFECT_MATCH 0x01
-#define I40E_AQC_MM_HASH_MATCH 0x02
-#define I40E_AQC_MM_ERR_NO_RES 0xFF
- u8 reserved1[3];
-};
-
-struct i40e_aqc_add_remove_macvlan_completion {
- __le16 perfect_mac_used;
- __le16 perfect_mac_free;
- __le16 unicast_hash_free;
- __le16 multicast_hash_free;
- __le32 addr_high;
- __le32 addr_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_macvlan_completion);
-
-/* Remove MAC-VLAN (indirect 0x0251)
- * uses i40e_aqc_macvlan for the descriptor
- * data points to an array of num_addresses of elements
- */
-
-struct i40e_aqc_remove_macvlan_element_data {
- u8 mac_addr[6];
- __le16 vlan_tag;
- u8 flags;
-#define I40E_AQC_MACVLAN_DEL_PERFECT_MATCH 0x01
-#define I40E_AQC_MACVLAN_DEL_HASH_MATCH 0x02
-#define I40E_AQC_MACVLAN_DEL_IGNORE_VLAN 0x08
-#define I40E_AQC_MACVLAN_DEL_ALL_VSIS 0x10
- u8 reserved[3];
- /* reply section */
- u8 error_code;
-#define I40E_AQC_REMOVE_MACVLAN_SUCCESS 0x0
-#define I40E_AQC_REMOVE_MACVLAN_FAIL 0xFF
- u8 reply_reserved[3];
-};
-
-/* Add VLAN (indirect 0x0252)
- * Remove VLAN (indirect 0x0253)
- * use the generic i40e_aqc_macvlan for the command
- */
-struct i40e_aqc_add_remove_vlan_element_data {
- __le16 vlan_tag;
- u8 vlan_flags;
-/* flags for add VLAN */
-#define I40E_AQC_ADD_VLAN_LOCAL 0x1
-#define I40E_AQC_ADD_PVLAN_TYPE_SHIFT 1
-#define I40E_AQC_ADD_PVLAN_TYPE_MASK (0x3 << I40E_AQC_ADD_PVLAN_TYPE_SHIFT)
-#define I40E_AQC_ADD_PVLAN_TYPE_REGULAR 0x0
-#define I40E_AQC_ADD_PVLAN_TYPE_PRIMARY 0x2
-#define I40E_AQC_ADD_PVLAN_TYPE_SECONDARY 0x4
-#define I40E_AQC_VLAN_PTYPE_SHIFT 3
-#define I40E_AQC_VLAN_PTYPE_MASK (0x3 << I40E_AQC_VLAN_PTYPE_SHIFT)
-#define I40E_AQC_VLAN_PTYPE_REGULAR_VSI 0x0
-#define I40E_AQC_VLAN_PTYPE_PROMISC_VSI 0x8
-#define I40E_AQC_VLAN_PTYPE_COMMUNITY_VSI 0x10
-#define I40E_AQC_VLAN_PTYPE_ISOLATED_VSI 0x18
-/* flags for remove VLAN */
-#define I40E_AQC_REMOVE_VLAN_ALL 0x1
- u8 reserved;
- u8 result;
-/* flags for add VLAN */
-#define I40E_AQC_ADD_VLAN_SUCCESS 0x0
-#define I40E_AQC_ADD_VLAN_FAIL_REQUEST 0xFE
-#define I40E_AQC_ADD_VLAN_FAIL_RESOURCE 0xFF
-/* flags for remove VLAN */
-#define I40E_AQC_REMOVE_VLAN_SUCCESS 0x0
-#define I40E_AQC_REMOVE_VLAN_FAIL 0xFF
- u8 reserved1[3];
-};
-
-struct i40e_aqc_add_remove_vlan_completion {
- u8 reserved[4];
- __le16 vlans_used;
- __le16 vlans_free;
- __le32 addr_high;
- __le32 addr_low;
-};
-
-/* Set VSI Promiscuous Modes (direct 0x0254) */
-struct i40e_aqc_set_vsi_promiscuous_modes {
- __le16 promiscuous_flags;
- __le16 valid_flags;
-/* flags used for both fields above */
-#define I40E_AQC_SET_VSI_PROMISC_UNICAST 0x01
-#define I40E_AQC_SET_VSI_PROMISC_MULTICAST 0x02
-#define I40E_AQC_SET_VSI_PROMISC_BROADCAST 0x04
-#define I40E_AQC_SET_VSI_DEFAULT 0x08
-#define I40E_AQC_SET_VSI_PROMISC_VLAN 0x10
-#define I40E_AQC_SET_VSI_PROMISC_TX 0x8000
- __le16 seid;
-#define I40E_AQC_VSI_PROM_CMD_SEID_MASK 0x3FF
- __le16 vlan_tag;
-#define I40E_AQC_SET_VSI_VLAN_MASK 0x0FFF
-#define I40E_AQC_SET_VSI_VLAN_VALID 0x8000
- u8 reserved[8];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_set_vsi_promiscuous_modes);
-
-/* Add S/E-tag command (direct 0x0255)
- * Uses generic i40e_aqc_add_remove_tag_completion for completion
- */
-struct i40e_aqc_add_tag {
- __le16 flags;
-#define I40E_AQC_ADD_TAG_FLAG_TO_QUEUE 0x0001
- __le16 seid;
-#define I40E_AQC_ADD_TAG_CMD_SEID_NUM_SHIFT 0
-#define I40E_AQC_ADD_TAG_CMD_SEID_NUM_MASK (0x3FF << \
- I40E_AQC_ADD_TAG_CMD_SEID_NUM_SHIFT)
- __le16 tag;
- __le16 queue_number;
- u8 reserved[8];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_add_tag);
-
-struct i40e_aqc_add_remove_tag_completion {
- u8 reserved[12];
- __le16 tags_used;
- __le16 tags_free;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_tag_completion);
-
-/* Remove S/E-tag command (direct 0x0256)
- * Uses generic i40e_aqc_add_remove_tag_completion for completion
- */
-struct i40e_aqc_remove_tag {
- __le16 seid;
-#define I40E_AQC_REMOVE_TAG_CMD_SEID_NUM_SHIFT 0
-#define I40E_AQC_REMOVE_TAG_CMD_SEID_NUM_MASK (0x3FF << \
- I40E_AQC_REMOVE_TAG_CMD_SEID_NUM_SHIFT)
- __le16 tag;
- u8 reserved[12];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_remove_tag);
-
-/* Add multicast E-Tag (direct 0x0257)
- * del multicast E-Tag (direct 0x0258) only uses pv_seid and etag fields
- * and no external data
- */
-struct i40e_aqc_add_remove_mcast_etag {
- __le16 pv_seid;
- __le16 etag;
- u8 num_unicast_etags;
- u8 reserved[3];
- __le32 addr_high; /* address of array of 2-byte s-tags */
- __le32 addr_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_mcast_etag);
-
-struct i40e_aqc_add_remove_mcast_etag_completion {
- u8 reserved[4];
- __le16 mcast_etags_used;
- __le16 mcast_etags_free;
- __le32 addr_high;
- __le32 addr_low;
-
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_mcast_etag_completion);
-
-/* Update S/E-Tag (direct 0x0259) */
-struct i40e_aqc_update_tag {
- __le16 seid;
-#define I40E_AQC_UPDATE_TAG_CMD_SEID_NUM_SHIFT 0
-#define I40E_AQC_UPDATE_TAG_CMD_SEID_NUM_MASK (0x3FF << \
- I40E_AQC_UPDATE_TAG_CMD_SEID_NUM_SHIFT)
- __le16 old_tag;
- __le16 new_tag;
- u8 reserved[10];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_update_tag);
-
-struct i40e_aqc_update_tag_completion {
- u8 reserved[12];
- __le16 tags_used;
- __le16 tags_free;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_update_tag_completion);
-
-/* Add Control Packet filter (direct 0x025A)
- * Remove Control Packet filter (direct 0x025B)
- * uses the i40e_aqc_add_oveb_cloud,
- * and the generic direct completion structure
- */
-struct i40e_aqc_add_remove_control_packet_filter {
- u8 mac[6];
- __le16 etype;
- __le16 flags;
-#define I40E_AQC_ADD_CONTROL_PACKET_FLAGS_IGNORE_MAC 0x0001
-#define I40E_AQC_ADD_CONTROL_PACKET_FLAGS_DROP 0x0002
-#define I40E_AQC_ADD_CONTROL_PACKET_FLAGS_TO_QUEUE 0x0004
-#define I40E_AQC_ADD_CONTROL_PACKET_FLAGS_TX 0x0008
-#define I40E_AQC_ADD_CONTROL_PACKET_FLAGS_RX 0x0000
- __le16 seid;
-#define I40E_AQC_ADD_CONTROL_PACKET_CMD_SEID_NUM_SHIFT 0
-#define I40E_AQC_ADD_CONTROL_PACKET_CMD_SEID_NUM_MASK (0x3FF << \
- I40E_AQC_ADD_CONTROL_PACKET_CMD_SEID_NUM_SHIFT)
- __le16 queue;
- u8 reserved[2];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_control_packet_filter);
-
-struct i40e_aqc_add_remove_control_packet_filter_completion {
- __le16 mac_etype_used;
- __le16 etype_used;
- __le16 mac_etype_free;
- __le16 etype_free;
- u8 reserved[8];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_control_packet_filter_completion);
-
-/* Add Cloud filters (indirect 0x025C)
- * Remove Cloud filters (indirect 0x025D)
- * uses the i40e_aqc_add_remove_cloud_filters,
- * and the generic indirect completion structure
- */
-struct i40e_aqc_add_remove_cloud_filters {
- u8 num_filters;
- u8 reserved;
- __le16 seid;
-#define I40E_AQC_ADD_CLOUD_CMD_SEID_NUM_SHIFT 0
-#define I40E_AQC_ADD_CLOUD_CMD_SEID_NUM_MASK (0x3FF << \
- I40E_AQC_ADD_CLOUD_CMD_SEID_NUM_SHIFT)
- u8 big_buffer_flag;
-#define I40E_AQC_ADD_CLOUD_CMD_BB 1
- u8 reserved2[3];
- __le32 addr_high;
- __le32 addr_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_cloud_filters);
-
-struct i40e_aqc_cloud_filters_element_data {
- u8 outer_mac[6];
- u8 inner_mac[6];
- __le16 inner_vlan;
- union {
- struct {
- u8 reserved[12];
- u8 data[4];
- } v4;
- struct {
- u8 data[16];
- } v6;
- struct {
- __le16 data[8];
- } raw_v6;
- } ipaddr;
- __le16 flags;
-#define I40E_AQC_ADD_CLOUD_FILTER_SHIFT 0
-#define I40E_AQC_ADD_CLOUD_FILTER_MASK (0x3F << \
- I40E_AQC_ADD_CLOUD_FILTER_SHIFT)
-/* 0x0000 reserved */
-#define I40E_AQC_ADD_CLOUD_FILTER_OIP 0x0001
-/* 0x0002 reserved */
-#define I40E_AQC_ADD_CLOUD_FILTER_IMAC_IVLAN 0x0003
-#define I40E_AQC_ADD_CLOUD_FILTER_IMAC_IVLAN_TEN_ID 0x0004
-/* 0x0005 reserved */
-#define I40E_AQC_ADD_CLOUD_FILTER_IMAC_TEN_ID 0x0006
-/* 0x0007 reserved */
-/* 0x0008 reserved */
-#define I40E_AQC_ADD_CLOUD_FILTER_OMAC 0x0009
-#define I40E_AQC_ADD_CLOUD_FILTER_IMAC 0x000A
-#define I40E_AQC_ADD_CLOUD_FILTER_OMAC_TEN_ID_IMAC 0x000B
-#define I40E_AQC_ADD_CLOUD_FILTER_IIP 0x000C
-/* 0x0010 to 0x0017 is for custom filters */
-#define I40E_AQC_ADD_CLOUD_FILTER_IP_PORT 0x0010 /* Dest IP + L4 Port */
-#define I40E_AQC_ADD_CLOUD_FILTER_MAC_PORT 0x0011 /* Dest MAC + L4 Port */
-#define I40E_AQC_ADD_CLOUD_FILTER_MAC_VLAN_PORT 0x0012 /* Dest MAC + VLAN + L4 Port */
-
-#define I40E_AQC_ADD_CLOUD_FLAGS_TO_QUEUE 0x0080
-#define I40E_AQC_ADD_CLOUD_VNK_SHIFT 6
-#define I40E_AQC_ADD_CLOUD_VNK_MASK 0x00C0
-#define I40E_AQC_ADD_CLOUD_FLAGS_IPV4 0
-#define I40E_AQC_ADD_CLOUD_FLAGS_IPV6 0x0100
-
-#define I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT 9
-#define I40E_AQC_ADD_CLOUD_TNL_TYPE_MASK 0x1E00
-#define I40E_AQC_ADD_CLOUD_TNL_TYPE_VXLAN 0
-#define I40E_AQC_ADD_CLOUD_TNL_TYPE_NVGRE_OMAC 1
-#define I40E_AQC_ADD_CLOUD_TNL_TYPE_GENEVE 2
-#define I40E_AQC_ADD_CLOUD_TNL_TYPE_IP 3
-#define I40E_AQC_ADD_CLOUD_TNL_TYPE_RESERVED 4
-#define I40E_AQC_ADD_CLOUD_TNL_TYPE_VXLAN_GPE 5
-
-#define I40E_AQC_ADD_CLOUD_FLAGS_SHARED_OUTER_MAC 0x2000
-#define I40E_AQC_ADD_CLOUD_FLAGS_SHARED_INNER_MAC 0x4000
-#define I40E_AQC_ADD_CLOUD_FLAGS_SHARED_OUTER_IP 0x8000
-
- __le32 tenant_id;
- u8 reserved[4];
- __le16 queue_number;
-#define I40E_AQC_ADD_CLOUD_QUEUE_SHIFT 0
-#define I40E_AQC_ADD_CLOUD_QUEUE_MASK (0x7FF << \
- I40E_AQC_ADD_CLOUD_QUEUE_SHIFT)
- u8 reserved2[14];
- /* response section */
- u8 allocation_result;
-#define I40E_AQC_ADD_CLOUD_FILTER_SUCCESS 0x0
-#define I40E_AQC_ADD_CLOUD_FILTER_FAIL 0xFF
- u8 response_reserved[7];
-};
-
-I40E_CHECK_STRUCT_LEN(0x40, i40e_aqc_cloud_filters_element_data);
-
-/* i40e_aqc_cloud_filters_element_bb is used when
- * I40E_AQC_ADD_CLOUD_CMD_BB flag is set.
- */
-struct i40e_aqc_cloud_filters_element_bb {
- struct i40e_aqc_cloud_filters_element_data element;
- u16 general_fields[32];
-#define I40E_AQC_ADD_CLOUD_FV_FLU_0X10_WORD0 0
-#define I40E_AQC_ADD_CLOUD_FV_FLU_0X10_WORD1 1
-#define I40E_AQC_ADD_CLOUD_FV_FLU_0X10_WORD2 2
-#define I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD0 3
-#define I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD1 4
-#define I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD2 5
-#define I40E_AQC_ADD_CLOUD_FV_FLU_0X12_WORD0 6
-#define I40E_AQC_ADD_CLOUD_FV_FLU_0X12_WORD1 7
-#define I40E_AQC_ADD_CLOUD_FV_FLU_0X12_WORD2 8
-#define I40E_AQC_ADD_CLOUD_FV_FLU_0X13_WORD0 9
-#define I40E_AQC_ADD_CLOUD_FV_FLU_0X13_WORD1 10
-#define I40E_AQC_ADD_CLOUD_FV_FLU_0X13_WORD2 11
-#define I40E_AQC_ADD_CLOUD_FV_FLU_0X14_WORD0 12
-#define I40E_AQC_ADD_CLOUD_FV_FLU_0X14_WORD1 13
-#define I40E_AQC_ADD_CLOUD_FV_FLU_0X14_WORD2 14
-#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD0 15
-#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD1 16
-#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD2 17
-#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD3 18
-#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD4 19
-#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD5 20
-#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD6 21
-#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD7 22
-#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD0 23
-#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD1 24
-#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD2 25
-#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD3 26
-#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD4 27
-#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD5 28
-#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD6 29
-#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD7 30
-};
-
-I40E_CHECK_STRUCT_LEN(0x80, i40e_aqc_cloud_filters_element_bb);
-
-struct i40e_aqc_remove_cloud_filters_completion {
- __le16 perfect_ovlan_used;
- __le16 perfect_ovlan_free;
- __le16 vlan_used;
- __le16 vlan_free;
- __le32 addr_high;
- __le32 addr_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_remove_cloud_filters_completion);
-
-/* Replace filter Command 0x025F
- * uses the i40e_aqc_replace_cloud_filters,
- * and the generic indirect completion structure
- */
-struct i40e_filter_data {
- u8 filter_type;
- u8 input[3];
-};
-
-I40E_CHECK_STRUCT_LEN(4, i40e_filter_data);
-
-struct i40e_aqc_replace_cloud_filters_cmd {
- u8 valid_flags;
-#define I40E_AQC_REPLACE_L1_FILTER 0x0
-#define I40E_AQC_REPLACE_CLOUD_FILTER 0x1
-#define I40E_AQC_GET_CLOUD_FILTERS 0x2
-#define I40E_AQC_MIRROR_CLOUD_FILTER 0x4
-#define I40E_AQC_HIGH_PRIORITY_CLOUD_FILTER 0x8
- u8 old_filter_type;
- u8 new_filter_type;
- u8 tr_bit;
- u8 reserved[4];
- __le32 addr_high;
- __le32 addr_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_replace_cloud_filters_cmd);
-
-struct i40e_aqc_replace_cloud_filters_cmd_buf {
- u8 data[32];
-/* Filter type INPUT codes*/
-#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_ENTRIES_MAX 3
-#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED BIT(7)
-
-/* Field Vector offsets */
-#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_MAC_DA 0
-#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG_ETH 6
-#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG 7
-#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_VLAN 8
-#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG_OVLAN 9
-#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG_IVLAN 10
-#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_TUNNLE_KEY 11
-#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_IMAC 12
-/* big FLU */
-#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_IP_DA 14
-/* big FLU */
-#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_OIP_DA 15
-
-#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_INNER_VLAN 37
- struct i40e_filter_data filters[8];
-};
-
-I40E_CHECK_STRUCT_LEN(0x40, i40e_aqc_replace_cloud_filters_cmd_buf);
-
-/* Add Mirror Rule (indirect or direct 0x0260)
- * Delete Mirror Rule (indirect or direct 0x0261)
- * note: some rule types (4,5) do not use an external buffer.
- * take care to set the flags correctly.
- */
-struct i40e_aqc_add_delete_mirror_rule {
- __le16 seid;
- __le16 rule_type;
-#define I40E_AQC_MIRROR_RULE_TYPE_SHIFT 0
-#define I40E_AQC_MIRROR_RULE_TYPE_MASK (0x7 << \
- I40E_AQC_MIRROR_RULE_TYPE_SHIFT)
-#define I40E_AQC_MIRROR_RULE_TYPE_VPORT_INGRESS 1
-#define I40E_AQC_MIRROR_RULE_TYPE_VPORT_EGRESS 2
-#define I40E_AQC_MIRROR_RULE_TYPE_VLAN 3
-#define I40E_AQC_MIRROR_RULE_TYPE_ALL_INGRESS 4
-#define I40E_AQC_MIRROR_RULE_TYPE_ALL_EGRESS 5
- __le16 num_entries;
- __le16 destination; /* VSI for add, rule id for delete */
- __le32 addr_high; /* address of array of 2-byte VSI or VLAN ids */
- __le32 addr_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_add_delete_mirror_rule);
-
-struct i40e_aqc_add_delete_mirror_rule_completion {
- u8 reserved[2];
- __le16 rule_id; /* only used on add */
- __le16 mirror_rules_used;
- __le16 mirror_rules_free;
- __le32 addr_high;
- __le32 addr_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_add_delete_mirror_rule_completion);
-
-/* Dynamic Device Personalization */
-struct i40e_aqc_write_personalization_profile {
- u8 flags;
- u8 reserved[3];
- __le32 profile_track_id;
- __le32 addr_high;
- __le32 addr_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_write_personalization_profile);
-
-struct i40e_aqc_write_ddp_resp {
- __le32 error_offset;
- __le32 error_info;
- __le32 addr_high;
- __le32 addr_low;
-};
-
-struct i40e_aqc_get_applied_profiles {
- u8 flags;
-#define I40E_AQC_GET_DDP_GET_CONF 0x1
-#define I40E_AQC_GET_DDP_GET_RDPU_CONF 0x2
- u8 rsv[3];
- __le32 reserved;
- __le32 addr_high;
- __le32 addr_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_get_applied_profiles);
-
-/* DCB 0x03xx*/
-
-/* PFC Ignore (direct 0x0301)
- * the command and response use the same descriptor structure
- */
-struct i40e_aqc_pfc_ignore {
- u8 tc_bitmap;
- u8 command_flags; /* unused on response */
-#define I40E_AQC_PFC_IGNORE_SET 0x80
-#define I40E_AQC_PFC_IGNORE_CLEAR 0x0
- u8 reserved[14];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_pfc_ignore);
-
-/* DCB Update (direct 0x0302) uses the i40e_aq_desc structure
- * with no parameters
- */
-
-/* TX scheduler 0x04xx */
-
-/* Almost all the indirect commands use
- * this generic struct to pass the SEID in param0
- */
-struct i40e_aqc_tx_sched_ind {
- __le16 vsi_seid;
- u8 reserved[6];
- __le32 addr_high;
- __le32 addr_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_tx_sched_ind);
-
-/* Several commands respond with a set of queue set handles */
-struct i40e_aqc_qs_handles_resp {
- __le16 qs_handles[8];
-};
-
-/* Configure VSI BW limits (direct 0x0400) */
-struct i40e_aqc_configure_vsi_bw_limit {
- __le16 vsi_seid;
- u8 reserved[2];
- __le16 credit;
- u8 reserved1[2];
- u8 max_credit; /* 0-3, limit = 2^max */
- u8 reserved2[7];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_configure_vsi_bw_limit);
-
-/* Configure VSI Bandwidth Limit per Traffic Type (indirect 0x0406)
- * responds with i40e_aqc_qs_handles_resp
- */
-struct i40e_aqc_configure_vsi_ets_sla_bw_data {
- u8 tc_valid_bits;
- u8 reserved[15];
- __le16 tc_bw_credits[8]; /* FW writesback QS handles here */
-
- /* 4 bits per tc 0-7, 4th bit is reserved, limit = 2^max */
- __le16 tc_bw_max[2];
- u8 reserved1[28];
-};
-
-I40E_CHECK_STRUCT_LEN(0x40, i40e_aqc_configure_vsi_ets_sla_bw_data);
-
-/* Configure VSI Bandwidth Allocation per Traffic Type (indirect 0x0407)
- * responds with i40e_aqc_qs_handles_resp
- */
-struct i40e_aqc_configure_vsi_tc_bw_data {
- u8 tc_valid_bits;
- u8 reserved[3];
- u8 tc_bw_credits[8];
- u8 reserved1[4];
- __le16 qs_handles[8];
-};
-
-I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_configure_vsi_tc_bw_data);
-
-/* Query vsi bw configuration (indirect 0x0408) */
-struct i40e_aqc_query_vsi_bw_config_resp {
- u8 tc_valid_bits;
- u8 tc_suspended_bits;
- u8 reserved[14];
- __le16 qs_handles[8];
- u8 reserved1[4];
- __le16 port_bw_limit;
- u8 reserved2[2];
- u8 max_bw; /* 0-3, limit = 2^max */
- u8 reserved3[23];
-};
-
-I40E_CHECK_STRUCT_LEN(0x40, i40e_aqc_query_vsi_bw_config_resp);
-
-/* Query VSI Bandwidth Allocation per Traffic Type (indirect 0x040A) */
-struct i40e_aqc_query_vsi_ets_sla_config_resp {
- u8 tc_valid_bits;
- u8 reserved[3];
- u8 share_credits[8];
- __le16 credits[8];
-
- /* 4 bits per tc 0-7, 4th bit is reserved, limit = 2^max */
- __le16 tc_bw_max[2];
-};
-
-I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_query_vsi_ets_sla_config_resp);
-
-/* Configure Switching Component Bandwidth Limit (direct 0x0410) */
-struct i40e_aqc_configure_switching_comp_bw_limit {
- __le16 seid;
- u8 reserved[2];
- __le16 credit;
- u8 reserved1[2];
- u8 max_bw; /* 0-3, limit = 2^max */
- u8 reserved2[7];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_configure_switching_comp_bw_limit);
-
-/* Enable Physical Port ETS (indirect 0x0413)
- * Modify Physical Port ETS (indirect 0x0414)
- * Disable Physical Port ETS (indirect 0x0415)
- */
-struct i40e_aqc_configure_switching_comp_ets_data {
- u8 reserved[4];
- u8 tc_valid_bits;
- u8 seepage;
-#define I40E_AQ_ETS_SEEPAGE_EN_MASK 0x1
- u8 tc_strict_priority_flags;
- u8 reserved1[17];
- u8 tc_bw_share_credits[8];
- u8 reserved2[96];
-};
-
-I40E_CHECK_STRUCT_LEN(0x80, i40e_aqc_configure_switching_comp_ets_data);
-
-/* Configure Switching Component Bandwidth Limits per Tc (indirect 0x0416) */
-struct i40e_aqc_configure_switching_comp_ets_bw_limit_data {
- u8 tc_valid_bits;
- u8 reserved[15];
- __le16 tc_bw_credit[8];
-
- /* 4 bits per tc 0-7, 4th bit is reserved, limit = 2^max */
- __le16 tc_bw_max[2];
- u8 reserved1[28];
-};
-
-I40E_CHECK_STRUCT_LEN(0x40,
- i40e_aqc_configure_switching_comp_ets_bw_limit_data);
-
-/* Configure Switching Component Bandwidth Allocation per Tc
- * (indirect 0x0417)
- */
-struct i40e_aqc_configure_switching_comp_bw_config_data {
- u8 tc_valid_bits;
- u8 reserved[2];
- u8 absolute_credits; /* bool */
- u8 tc_bw_share_credits[8];
- u8 reserved1[20];
-};
-
-I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_configure_switching_comp_bw_config_data);
-
-/* Query Switching Component Configuration (indirect 0x0418) */
-struct i40e_aqc_query_switching_comp_ets_config_resp {
- u8 tc_valid_bits;
- u8 reserved[35];
- __le16 port_bw_limit;
- u8 reserved1[2];
- u8 tc_bw_max; /* 0-3, limit = 2^max */
- u8 reserved2[23];
-};
-
-I40E_CHECK_STRUCT_LEN(0x40, i40e_aqc_query_switching_comp_ets_config_resp);
-
-/* Query PhysicalPort ETS Configuration (indirect 0x0419) */
-struct i40e_aqc_query_port_ets_config_resp {
- u8 reserved[4];
- u8 tc_valid_bits;
- u8 reserved1;
- u8 tc_strict_priority_bits;
- u8 reserved2;
- u8 tc_bw_share_credits[8];
- __le16 tc_bw_limits[8];
-
- /* 4 bits per tc 0-7, 4th bit reserved, limit = 2^max */
- __le16 tc_bw_max[2];
- u8 reserved3[32];
-};
-
-I40E_CHECK_STRUCT_LEN(0x44, i40e_aqc_query_port_ets_config_resp);
-
-/* Query Switching Component Bandwidth Allocation per Traffic Type
- * (indirect 0x041A)
- */
-struct i40e_aqc_query_switching_comp_bw_config_resp {
- u8 tc_valid_bits;
- u8 reserved[2];
- u8 absolute_credits_enable; /* bool */
- u8 tc_bw_share_credits[8];
- __le16 tc_bw_limits[8];
-
- /* 4 bits per tc 0-7, 4th bit is reserved, limit = 2^max */
- __le16 tc_bw_max[2];
-};
-
-I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_query_switching_comp_bw_config_resp);
-
-/* Suspend/resume port TX traffic
- * (direct 0x041B and 0x041C) uses the generic SEID struct
- */
-
-/* Configure partition BW
- * (indirect 0x041D)
- */
-struct i40e_aqc_configure_partition_bw_data {
- __le16 pf_valid_bits;
- u8 min_bw[16]; /* guaranteed bandwidth */
- u8 max_bw[16]; /* bandwidth limit */
-};
-
-I40E_CHECK_STRUCT_LEN(0x22, i40e_aqc_configure_partition_bw_data);
-
-/* Get and set the active HMC resource profile and status.
- * (direct 0x0500) and (direct 0x0501)
- */
-struct i40e_aq_get_set_hmc_resource_profile {
- u8 pm_profile;
- u8 pe_vf_enabled;
- u8 reserved[14];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aq_get_set_hmc_resource_profile);
-
-enum i40e_aq_hmc_profile {
- /* I40E_HMC_PROFILE_NO_CHANGE = 0, reserved */
- I40E_HMC_PROFILE_DEFAULT = 1,
- I40E_HMC_PROFILE_FAVOR_VF = 2,
- I40E_HMC_PROFILE_EQUAL = 3,
-};
-
-/* Get PHY Abilities (indirect 0x0600) uses the generic indirect struct */
-
-/* set in param0 for get phy abilities to report qualified modules */
-#define I40E_AQ_PHY_REPORT_QUALIFIED_MODULES 0x0001
-#define I40E_AQ_PHY_REPORT_INITIAL_VALUES 0x0002
-
-enum i40e_aq_phy_type {
- I40E_PHY_TYPE_SGMII = 0x0,
- I40E_PHY_TYPE_1000BASE_KX = 0x1,
- I40E_PHY_TYPE_10GBASE_KX4 = 0x2,
- I40E_PHY_TYPE_10GBASE_KR = 0x3,
- I40E_PHY_TYPE_40GBASE_KR4 = 0x4,
- I40E_PHY_TYPE_XAUI = 0x5,
- I40E_PHY_TYPE_XFI = 0x6,
- I40E_PHY_TYPE_SFI = 0x7,
- I40E_PHY_TYPE_XLAUI = 0x8,
- I40E_PHY_TYPE_XLPPI = 0x9,
- I40E_PHY_TYPE_40GBASE_CR4_CU = 0xA,
- I40E_PHY_TYPE_10GBASE_CR1_CU = 0xB,
- I40E_PHY_TYPE_10GBASE_AOC = 0xC,
- I40E_PHY_TYPE_40GBASE_AOC = 0xD,
- I40E_PHY_TYPE_UNRECOGNIZED = 0xE,
- I40E_PHY_TYPE_UNSUPPORTED = 0xF,
- I40E_PHY_TYPE_100BASE_TX = 0x11,
- I40E_PHY_TYPE_1000BASE_T = 0x12,
- I40E_PHY_TYPE_10GBASE_T = 0x13,
- I40E_PHY_TYPE_10GBASE_SR = 0x14,
- I40E_PHY_TYPE_10GBASE_LR = 0x15,
- I40E_PHY_TYPE_10GBASE_SFPP_CU = 0x16,
- I40E_PHY_TYPE_10GBASE_CR1 = 0x17,
- I40E_PHY_TYPE_40GBASE_CR4 = 0x18,
- I40E_PHY_TYPE_40GBASE_SR4 = 0x19,
- I40E_PHY_TYPE_40GBASE_LR4 = 0x1A,
- I40E_PHY_TYPE_1000BASE_SX = 0x1B,
- I40E_PHY_TYPE_1000BASE_LX = 0x1C,
- I40E_PHY_TYPE_1000BASE_T_OPTICAL = 0x1D,
- I40E_PHY_TYPE_20GBASE_KR2 = 0x1E,
- I40E_PHY_TYPE_25GBASE_KR = 0x1F,
- I40E_PHY_TYPE_25GBASE_CR = 0x20,
- I40E_PHY_TYPE_25GBASE_SR = 0x21,
- I40E_PHY_TYPE_25GBASE_LR = 0x22,
- I40E_PHY_TYPE_25GBASE_AOC = 0x23,
- I40E_PHY_TYPE_25GBASE_ACC = 0x24,
- I40E_PHY_TYPE_MAX,
- I40E_PHY_TYPE_NOT_SUPPORTED_HIGH_TEMP = 0xFD,
- I40E_PHY_TYPE_EMPTY = 0xFE,
- I40E_PHY_TYPE_DEFAULT = 0xFF,
-};
-
-#define I40E_LINK_SPEED_100MB_SHIFT 0x1
-#define I40E_LINK_SPEED_1000MB_SHIFT 0x2
-#define I40E_LINK_SPEED_10GB_SHIFT 0x3
-#define I40E_LINK_SPEED_40GB_SHIFT 0x4
-#define I40E_LINK_SPEED_20GB_SHIFT 0x5
-#define I40E_LINK_SPEED_25GB_SHIFT 0x6
-
-enum i40e_aq_link_speed {
- I40E_LINK_SPEED_UNKNOWN = 0,
- I40E_LINK_SPEED_100MB = BIT(I40E_LINK_SPEED_100MB_SHIFT),
- I40E_LINK_SPEED_1GB = BIT(I40E_LINK_SPEED_1000MB_SHIFT),
- I40E_LINK_SPEED_10GB = BIT(I40E_LINK_SPEED_10GB_SHIFT),
- I40E_LINK_SPEED_40GB = BIT(I40E_LINK_SPEED_40GB_SHIFT),
- I40E_LINK_SPEED_20GB = BIT(I40E_LINK_SPEED_20GB_SHIFT),
- I40E_LINK_SPEED_25GB = BIT(I40E_LINK_SPEED_25GB_SHIFT),
-};
-
-struct i40e_aqc_module_desc {
- u8 oui[3];
- u8 reserved1;
- u8 part_number[16];
- u8 revision[4];
- u8 reserved2[8];
-};
-
-I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_module_desc);
-
-struct i40e_aq_get_phy_abilities_resp {
- __le32 phy_type; /* bitmap using the above enum for offsets */
- u8 link_speed; /* bitmap using the above enum bit patterns */
- u8 abilities;
-#define I40E_AQ_PHY_FLAG_PAUSE_TX 0x01
-#define I40E_AQ_PHY_FLAG_PAUSE_RX 0x02
-#define I40E_AQ_PHY_FLAG_LOW_POWER 0x04
-#define I40E_AQ_PHY_LINK_ENABLED 0x08
-#define I40E_AQ_PHY_AN_ENABLED 0x10
-#define I40E_AQ_PHY_FLAG_MODULE_QUAL 0x20
-#define I40E_AQ_PHY_FEC_ABILITY_KR 0x40
-#define I40E_AQ_PHY_FEC_ABILITY_RS 0x80
- __le16 eee_capability;
-#define I40E_AQ_EEE_100BASE_TX 0x0002
-#define I40E_AQ_EEE_1000BASE_T 0x0004
-#define I40E_AQ_EEE_10GBASE_T 0x0008
-#define I40E_AQ_EEE_1000BASE_KX 0x0010
-#define I40E_AQ_EEE_10GBASE_KX4 0x0020
-#define I40E_AQ_EEE_10GBASE_KR 0x0040
- __le32 eeer_val;
- u8 d3_lpan;
-#define I40E_AQ_SET_PHY_D3_LPAN_ENA 0x01
- u8 phy_type_ext;
-#define I40E_AQ_PHY_TYPE_EXT_25G_KR 0X01
-#define I40E_AQ_PHY_TYPE_EXT_25G_CR 0X02
-#define I40E_AQ_PHY_TYPE_EXT_25G_SR 0x04
-#define I40E_AQ_PHY_TYPE_EXT_25G_LR 0x08
-#define I40E_AQ_PHY_TYPE_EXT_25G_AOC 0x10
-#define I40E_AQ_PHY_TYPE_EXT_25G_ACC 0x20
- u8 fec_cfg_curr_mod_ext_info;
-#define I40E_AQ_ENABLE_FEC_KR 0x01
-#define I40E_AQ_ENABLE_FEC_RS 0x02
-#define I40E_AQ_REQUEST_FEC_KR 0x04
-#define I40E_AQ_REQUEST_FEC_RS 0x08
-#define I40E_AQ_ENABLE_FEC_AUTO 0x10
-#define I40E_AQ_FEC
-#define I40E_AQ_MODULE_TYPE_EXT_MASK 0xE0
-#define I40E_AQ_MODULE_TYPE_EXT_SHIFT 5
-
- u8 ext_comp_code;
- u8 phy_id[4];
- u8 module_type[3];
- u8 qualified_module_count;
-#define I40E_AQ_PHY_MAX_QMS 16
- struct i40e_aqc_module_desc qualified_module[I40E_AQ_PHY_MAX_QMS];
-};
-
-I40E_CHECK_STRUCT_LEN(0x218, i40e_aq_get_phy_abilities_resp);
-
-/* Set PHY Config (direct 0x0601) */
-struct i40e_aq_set_phy_config { /* same bits as above in all */
- __le32 phy_type;
- u8 link_speed;
- u8 abilities;
-/* bits 0-2 use the values from get_phy_abilities_resp */
-#define I40E_AQ_PHY_ENABLE_LINK 0x08
-#define I40E_AQ_PHY_ENABLE_AN 0x10
-#define I40E_AQ_PHY_ENABLE_ATOMIC_LINK 0x20
- __le16 eee_capability;
- __le32 eeer;
- u8 low_power_ctrl;
- u8 phy_type_ext;
-#define I40E_AQ_PHY_TYPE_EXT_25G_KR 0X01
-#define I40E_AQ_PHY_TYPE_EXT_25G_CR 0X02
-#define I40E_AQ_PHY_TYPE_EXT_25G_SR 0x04
-#define I40E_AQ_PHY_TYPE_EXT_25G_LR 0x08
- u8 fec_config;
-#define I40E_AQ_SET_FEC_ABILITY_KR BIT(0)
-#define I40E_AQ_SET_FEC_ABILITY_RS BIT(1)
-#define I40E_AQ_SET_FEC_REQUEST_KR BIT(2)
-#define I40E_AQ_SET_FEC_REQUEST_RS BIT(3)
-#define I40E_AQ_SET_FEC_AUTO BIT(4)
-#define I40E_AQ_PHY_FEC_CONFIG_SHIFT 0x0
-#define I40E_AQ_PHY_FEC_CONFIG_MASK (0x1F << I40E_AQ_PHY_FEC_CONFIG_SHIFT)
- u8 reserved;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aq_set_phy_config);
-
-/* Set MAC Config command data structure (direct 0x0603) */
-struct i40e_aq_set_mac_config {
- __le16 max_frame_size;
- u8 params;
-#define I40E_AQ_SET_MAC_CONFIG_CRC_EN 0x04
-#define I40E_AQ_SET_MAC_CONFIG_PACING_MASK 0x78
-#define I40E_AQ_SET_MAC_CONFIG_PACING_SHIFT 3
-#define I40E_AQ_SET_MAC_CONFIG_PACING_NONE 0x0
-#define I40E_AQ_SET_MAC_CONFIG_PACING_1B_13TX 0xF
-#define I40E_AQ_SET_MAC_CONFIG_PACING_1DW_9TX 0x9
-#define I40E_AQ_SET_MAC_CONFIG_PACING_1DW_4TX 0x8
-#define I40E_AQ_SET_MAC_CONFIG_PACING_3DW_7TX 0x7
-#define I40E_AQ_SET_MAC_CONFIG_PACING_2DW_3TX 0x6
-#define I40E_AQ_SET_MAC_CONFIG_PACING_1DW_1TX 0x5
-#define I40E_AQ_SET_MAC_CONFIG_PACING_3DW_2TX 0x4
-#define I40E_AQ_SET_MAC_CONFIG_PACING_7DW_3TX 0x3
-#define I40E_AQ_SET_MAC_CONFIG_PACING_4DW_1TX 0x2
-#define I40E_AQ_SET_MAC_CONFIG_PACING_9DW_1TX 0x1
- u8 tx_timer_priority; /* bitmap */
- __le16 tx_timer_value;
- __le16 fc_refresh_threshold;
- u8 reserved[8];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aq_set_mac_config);
-
-/* Restart Auto-Negotiation (direct 0x605) */
-struct i40e_aqc_set_link_restart_an {
- u8 command;
-#define I40E_AQ_PHY_RESTART_AN 0x02
-#define I40E_AQ_PHY_LINK_ENABLE 0x04
- u8 reserved[15];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_set_link_restart_an);
-
-/* Get Link Status cmd & response data structure (direct 0x0607) */
-struct i40e_aqc_get_link_status {
- __le16 command_flags; /* only field set on command */
-#define I40E_AQ_LSE_MASK 0x3
-#define I40E_AQ_LSE_NOP 0x0
-#define I40E_AQ_LSE_DISABLE 0x2
-#define I40E_AQ_LSE_ENABLE 0x3
-/* only response uses this flag */
-#define I40E_AQ_LSE_IS_ENABLED 0x1
- u8 phy_type; /* i40e_aq_phy_type */
- u8 link_speed; /* i40e_aq_link_speed */
- u8 link_info;
-#define I40E_AQ_LINK_UP 0x01 /* obsolete */
-#define I40E_AQ_LINK_UP_FUNCTION 0x01
-#define I40E_AQ_LINK_FAULT 0x02
-#define I40E_AQ_LINK_FAULT_TX 0x04
-#define I40E_AQ_LINK_FAULT_RX 0x08
-#define I40E_AQ_LINK_FAULT_REMOTE 0x10
-#define I40E_AQ_LINK_UP_PORT 0x20
-#define I40E_AQ_MEDIA_AVAILABLE 0x40
-#define I40E_AQ_SIGNAL_DETECT 0x80
- u8 an_info;
-#define I40E_AQ_AN_COMPLETED 0x01
-#define I40E_AQ_LP_AN_ABILITY 0x02
-#define I40E_AQ_PD_FAULT 0x04
-#define I40E_AQ_FEC_EN 0x08
-#define I40E_AQ_PHY_LOW_POWER 0x10
-#define I40E_AQ_LINK_PAUSE_TX 0x20
-#define I40E_AQ_LINK_PAUSE_RX 0x40
-#define I40E_AQ_QUALIFIED_MODULE 0x80
- u8 ext_info;
-#define I40E_AQ_LINK_PHY_TEMP_ALARM 0x01
-#define I40E_AQ_LINK_XCESSIVE_ERRORS 0x02
-#define I40E_AQ_LINK_TX_SHIFT 0x02
-#define I40E_AQ_LINK_TX_MASK (0x03 << I40E_AQ_LINK_TX_SHIFT)
-#define I40E_AQ_LINK_TX_ACTIVE 0x00
-#define I40E_AQ_LINK_TX_DRAINED 0x01
-#define I40E_AQ_LINK_TX_FLUSHED 0x03
-#define I40E_AQ_LINK_FORCED_40G 0x10
-/* 25G Error Codes */
-#define I40E_AQ_25G_NO_ERR 0X00
-#define I40E_AQ_25G_NOT_PRESENT 0X01
-#define I40E_AQ_25G_NVM_CRC_ERR 0X02
-#define I40E_AQ_25G_SBUS_UCODE_ERR 0X03
-#define I40E_AQ_25G_SERDES_UCODE_ERR 0X04
-#define I40E_AQ_25G_NIMB_UCODE_ERR 0X05
- u8 loopback; /* use defines from i40e_aqc_set_lb_mode */
-/* Since firmware API 1.7 loopback field keeps power class info as well */
-#define I40E_AQ_LOOPBACK_MASK 0x07
-#define I40E_AQ_PWR_CLASS_SHIFT_LB 6
-#define I40E_AQ_PWR_CLASS_MASK_LB (0x03 << I40E_AQ_PWR_CLASS_SHIFT_LB)
- __le16 max_frame_size;
- u8 config;
-#define I40E_AQ_CONFIG_FEC_KR_ENA 0x01
-#define I40E_AQ_CONFIG_FEC_RS_ENA 0x02
-#define I40E_AQ_CONFIG_CRC_ENA 0x04
-#define I40E_AQ_CONFIG_PACING_MASK 0x78
- union {
- struct {
- u8 power_desc;
-#define I40E_AQ_LINK_POWER_CLASS_1 0x00
-#define I40E_AQ_LINK_POWER_CLASS_2 0x01
-#define I40E_AQ_LINK_POWER_CLASS_3 0x02
-#define I40E_AQ_LINK_POWER_CLASS_4 0x03
-#define I40E_AQ_PWR_CLASS_MASK 0x03
- u8 reserved[4];
- };
- struct {
- u8 link_type[4];
- u8 link_type_ext;
- };
- };
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_get_link_status);
-
-/* Set event mask command (direct 0x613) */
-struct i40e_aqc_set_phy_int_mask {
- u8 reserved[8];
- __le16 event_mask;
-#define I40E_AQ_EVENT_LINK_UPDOWN 0x0002
-#define I40E_AQ_EVENT_MEDIA_NA 0x0004
-#define I40E_AQ_EVENT_LINK_FAULT 0x0008
-#define I40E_AQ_EVENT_PHY_TEMP_ALARM 0x0010
-#define I40E_AQ_EVENT_EXCESSIVE_ERRORS 0x0020
-#define I40E_AQ_EVENT_SIGNAL_DETECT 0x0040
-#define I40E_AQ_EVENT_AN_COMPLETED 0x0080
-#define I40E_AQ_EVENT_MODULE_QUAL_FAIL 0x0100
-#define I40E_AQ_EVENT_PORT_TX_SUSPENDED 0x0200
- u8 reserved1[6];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_set_phy_int_mask);
-
-/* Get Local AN advt register (direct 0x0614)
- * Set Local AN advt register (direct 0x0615)
- * Get Link Partner AN advt register (direct 0x0616)
- */
-struct i40e_aqc_an_advt_reg {
- __le32 local_an_reg0;
- __le16 local_an_reg1;
- u8 reserved[10];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_an_advt_reg);
-
-/* Set Loopback mode (0x0618) */
-struct i40e_aqc_set_lb_mode {
- __le16 lb_mode;
-#define I40E_AQ_LB_PHY_LOCAL 0x01
-#define I40E_AQ_LB_PHY_REMOTE 0x02
-#define I40E_AQ_LB_MAC_LOCAL 0x04
- u8 reserved[14];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_set_lb_mode);
-
-/* Set PHY Debug command (0x0622) */
-struct i40e_aqc_set_phy_debug {
- u8 command_flags;
-#define I40E_AQ_PHY_DEBUG_RESET_INTERNAL 0x02
-#define I40E_AQ_PHY_DEBUG_RESET_EXTERNAL_SHIFT 2
-#define I40E_AQ_PHY_DEBUG_RESET_EXTERNAL_MASK (0x03 << \
- I40E_AQ_PHY_DEBUG_RESET_EXTERNAL_SHIFT)
-#define I40E_AQ_PHY_DEBUG_RESET_EXTERNAL_NONE 0x00
-#define I40E_AQ_PHY_DEBUG_RESET_EXTERNAL_HARD 0x01
-#define I40E_AQ_PHY_DEBUG_RESET_EXTERNAL_SOFT 0x02
-#define I40E_AQ_PHY_DEBUG_DISABLE_LINK_FW 0x10
- u8 reserved[15];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_set_phy_debug);
-
-enum i40e_aq_phy_reg_type {
- I40E_AQC_PHY_REG_INTERNAL = 0x1,
- I40E_AQC_PHY_REG_EXERNAL_BASET = 0x2,
- I40E_AQC_PHY_REG_EXERNAL_MODULE = 0x3
-};
-
-/* Run PHY Activity (0x0626) */
-struct i40e_aqc_run_phy_activity {
- __le16 activity_id;
- u8 flags;
- u8 reserved1;
- __le32 control;
- __le32 data;
- u8 reserved2[4];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_run_phy_activity);
-
-/* Set PHY Register command (0x0628) */
-/* Get PHY Register command (0x0629) */
-struct i40e_aqc_phy_register_access {
- u8 phy_interface;
-#define I40E_AQ_PHY_REG_ACCESS_INTERNAL 0
-#define I40E_AQ_PHY_REG_ACCESS_EXTERNAL 1
-#define I40E_AQ_PHY_REG_ACCESS_EXTERNAL_MODULE 2
- u8 dev_address;
- u8 reserved1[2];
- __le32 reg_address;
- __le32 reg_value;
- u8 reserved2[4];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_phy_register_access);
-
-/* NVM Read command (indirect 0x0701)
- * NVM Erase commands (direct 0x0702)
- * NVM Update commands (indirect 0x0703)
- */
-struct i40e_aqc_nvm_update {
- u8 command_flags;
-#define I40E_AQ_NVM_LAST_CMD 0x01
-#define I40E_AQ_NVM_REARRANGE_TO_FLAT 0x20
-#define I40E_AQ_NVM_REARRANGE_TO_STRUCT 0x40
-#define I40E_AQ_NVM_FLASH_ONLY 0x80
-#define I40E_AQ_NVM_PRESERVATION_FLAGS_SHIFT 1
-#define I40E_AQ_NVM_PRESERVATION_FLAGS_MASK 0x03
-#define I40E_AQ_NVM_PRESERVATION_FLAGS_SELECTED 0x03
-#define I40E_AQ_NVM_PRESERVATION_FLAGS_ALL 0x01
- u8 module_pointer;
- __le16 length;
- __le32 offset;
- __le32 addr_high;
- __le32 addr_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_nvm_update);
-
-/* NVM Config Read (indirect 0x0704) */
-struct i40e_aqc_nvm_config_read {
- __le16 cmd_flags;
-#define I40E_AQ_ANVM_SINGLE_OR_MULTIPLE_FEATURES_MASK 1
-#define I40E_AQ_ANVM_READ_SINGLE_FEATURE 0
-#define I40E_AQ_ANVM_READ_MULTIPLE_FEATURES 1
- __le16 element_count;
- __le16 element_id; /* Feature/field ID */
- __le16 element_id_msw; /* MSWord of field ID */
- __le32 address_high;
- __le32 address_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_nvm_config_read);
-
-/* NVM Config Write (indirect 0x0705) */
-struct i40e_aqc_nvm_config_write {
- __le16 cmd_flags;
- __le16 element_count;
- u8 reserved[4];
- __le32 address_high;
- __le32 address_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_nvm_config_write);
-
-/* Used for 0x0704 as well as for 0x0705 commands */
-#define I40E_AQ_ANVM_FEATURE_OR_IMMEDIATE_SHIFT 1
-#define I40E_AQ_ANVM_FEATURE_OR_IMMEDIATE_MASK \
- BIT(I40E_AQ_ANVM_FEATURE_OR_IMMEDIATE_SHIFT)
-#define I40E_AQ_ANVM_FEATURE 0
-#define I40E_AQ_ANVM_IMMEDIATE_FIELD BIT(FEATURE_OR_IMMEDIATE_SHIFT)
-struct i40e_aqc_nvm_config_data_feature {
- __le16 feature_id;
-#define I40E_AQ_ANVM_FEATURE_OPTION_OEM_ONLY 0x01
-#define I40E_AQ_ANVM_FEATURE_OPTION_DWORD_MAP 0x08
-#define I40E_AQ_ANVM_FEATURE_OPTION_POR_CSR 0x10
- __le16 feature_options;
- __le16 feature_selection;
-};
-
-I40E_CHECK_STRUCT_LEN(0x6, i40e_aqc_nvm_config_data_feature);
-
-struct i40e_aqc_nvm_config_data_immediate_field {
- __le32 field_id;
- __le32 field_value;
- __le16 field_options;
- __le16 reserved;
-};
-
-I40E_CHECK_STRUCT_LEN(0xc, i40e_aqc_nvm_config_data_immediate_field);
-
-/* OEM Post Update (indirect 0x0720)
- * no command data struct used
- */
- struct i40e_aqc_nvm_oem_post_update {
-#define I40E_AQ_NVM_OEM_POST_UPDATE_EXTERNAL_DATA 0x01
- u8 sel_data;
- u8 reserved[7];
-};
-
-I40E_CHECK_STRUCT_LEN(0x8, i40e_aqc_nvm_oem_post_update);
-
-struct i40e_aqc_nvm_oem_post_update_buffer {
- u8 str_len;
- u8 dev_addr;
- __le16 eeprom_addr;
- u8 data[36];
-};
-
-I40E_CHECK_STRUCT_LEN(0x28, i40e_aqc_nvm_oem_post_update_buffer);
-
-/* Thermal Sensor (indirect 0x0721)
- * read or set thermal sensor configs and values
- * takes a sensor and command specific data buffer, not detailed here
- */
-struct i40e_aqc_thermal_sensor {
- u8 sensor_action;
-#define I40E_AQ_THERMAL_SENSOR_READ_CONFIG 0
-#define I40E_AQ_THERMAL_SENSOR_SET_CONFIG 1
-#define I40E_AQ_THERMAL_SENSOR_READ_TEMP 2
- u8 reserved[7];
- __le32 addr_high;
- __le32 addr_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_thermal_sensor);
-
-/* Send to PF command (indirect 0x0801) id is only used by PF
- * Send to VF command (indirect 0x0802) id is only used by PF
- * Send to Peer PF command (indirect 0x0803)
- */
-struct i40e_aqc_pf_vf_message {
- __le32 id;
- u8 reserved[4];
- __le32 addr_high;
- __le32 addr_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_pf_vf_message);
-
-/* Alternate structure */
-
-/* Direct write (direct 0x0900)
- * Direct read (direct 0x0902)
- */
-struct i40e_aqc_alternate_write {
- __le32 address0;
- __le32 data0;
- __le32 address1;
- __le32 data1;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_alternate_write);
-
-/* Indirect write (indirect 0x0901)
- * Indirect read (indirect 0x0903)
- */
-
-struct i40e_aqc_alternate_ind_write {
- __le32 address;
- __le32 length;
- __le32 addr_high;
- __le32 addr_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_alternate_ind_write);
-
-/* Done alternate write (direct 0x0904)
- * uses i40e_aq_desc
- */
-struct i40e_aqc_alternate_write_done {
- __le16 cmd_flags;
-#define I40E_AQ_ALTERNATE_MODE_BIOS_MASK 1
-#define I40E_AQ_ALTERNATE_MODE_BIOS_LEGACY 0
-#define I40E_AQ_ALTERNATE_MODE_BIOS_UEFI 1
-#define I40E_AQ_ALTERNATE_RESET_NEEDED 2
- u8 reserved[14];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_alternate_write_done);
-
-/* Set OEM mode (direct 0x0905) */
-struct i40e_aqc_alternate_set_mode {
- __le32 mode;
-#define I40E_AQ_ALTERNATE_MODE_NONE 0
-#define I40E_AQ_ALTERNATE_MODE_OEM 1
- u8 reserved[12];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_alternate_set_mode);
-
-/* Clear port Alternate RAM (direct 0x0906) uses i40e_aq_desc */
-
-/* async events 0x10xx */
-
-/* Lan Queue Overflow Event (direct, 0x1001) */
-struct i40e_aqc_lan_overflow {
- __le32 prtdcb_rupto;
- __le32 otx_ctl;
- u8 reserved[8];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_lan_overflow);
-
-/* Get LLDP MIB (indirect 0x0A00) */
-struct i40e_aqc_lldp_get_mib {
- u8 type;
- u8 reserved1;
-#define I40E_AQ_LLDP_MIB_TYPE_MASK 0x3
-#define I40E_AQ_LLDP_MIB_LOCAL 0x0
-#define I40E_AQ_LLDP_MIB_REMOTE 0x1
-#define I40E_AQ_LLDP_MIB_LOCAL_AND_REMOTE 0x2
-#define I40E_AQ_LLDP_BRIDGE_TYPE_MASK 0xC
-#define I40E_AQ_LLDP_BRIDGE_TYPE_SHIFT 0x2
-#define I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE 0x0
-#define I40E_AQ_LLDP_BRIDGE_TYPE_NON_TPMR 0x1
-#define I40E_AQ_LLDP_TX_SHIFT 0x4
-#define I40E_AQ_LLDP_TX_MASK (0x03 << I40E_AQ_LLDP_TX_SHIFT)
-/* TX pause flags use I40E_AQ_LINK_TX_* above */
- __le16 local_len;
- __le16 remote_len;
- u8 reserved2[2];
- __le32 addr_high;
- __le32 addr_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_get_mib);
-
-/* Configure LLDP MIB Change Event (direct 0x0A01)
- * also used for the event (with type in the command field)
- */
-struct i40e_aqc_lldp_update_mib {
- u8 command;
-#define I40E_AQ_LLDP_MIB_UPDATE_ENABLE 0x0
-#define I40E_AQ_LLDP_MIB_UPDATE_DISABLE 0x1
- u8 reserved[7];
- __le32 addr_high;
- __le32 addr_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_update_mib);
-
-/* Add LLDP TLV (indirect 0x0A02)
- * Delete LLDP TLV (indirect 0x0A04)
- */
-struct i40e_aqc_lldp_add_tlv {
- u8 type; /* only nearest bridge and non-TPMR from 0x0A00 */
- u8 reserved1[1];
- __le16 len;
- u8 reserved2[4];
- __le32 addr_high;
- __le32 addr_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_add_tlv);
-
-/* Update LLDP TLV (indirect 0x0A03) */
-struct i40e_aqc_lldp_update_tlv {
- u8 type; /* only nearest bridge and non-TPMR from 0x0A00 */
- u8 reserved;
- __le16 old_len;
- __le16 new_offset;
- __le16 new_len;
- __le32 addr_high;
- __le32 addr_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_update_tlv);
-
-/* Stop LLDP (direct 0x0A05) */
-struct i40e_aqc_lldp_stop {
- u8 command;
-#define I40E_AQ_LLDP_AGENT_STOP 0x0
-#define I40E_AQ_LLDP_AGENT_SHUTDOWN 0x1
- u8 reserved[15];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_stop);
-
-/* Start LLDP (direct 0x0A06) */
-
-struct i40e_aqc_lldp_start {
- u8 command;
-#define I40E_AQ_LLDP_AGENT_START 0x1
- u8 reserved[15];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_start);
-
-/* Set DCB (direct 0x0303) */
-struct i40e_aqc_set_dcb_parameters {
- u8 command;
-#define I40E_AQ_DCB_SET_AGENT 0x1
-#define I40E_DCB_VALID 0x1
- u8 valid_flags;
- u8 reserved[14];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_set_dcb_parameters);
-
-/* Apply MIB changes (0x0A07)
- * uses the generic struc as it contains no data
- */
-
-/* Add Udp Tunnel command and completion (direct 0x0B00) */
-struct i40e_aqc_add_udp_tunnel {
- __le16 udp_port;
- u8 reserved0[3];
- u8 protocol_type;
-#define I40E_AQC_TUNNEL_TYPE_VXLAN 0x00
-#define I40E_AQC_TUNNEL_TYPE_NGE 0x01
-#define I40E_AQC_TUNNEL_TYPE_TEREDO 0x10
-#define I40E_AQC_TUNNEL_TYPE_VXLAN_GPE 0x11
- u8 reserved1[10];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_add_udp_tunnel);
-
-struct i40e_aqc_add_udp_tunnel_completion {
- __le16 udp_port;
- u8 filter_entry_index;
- u8 multiple_pfs;
-#define I40E_AQC_SINGLE_PF 0x0
-#define I40E_AQC_MULTIPLE_PFS 0x1
- u8 total_filters;
- u8 reserved[11];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_add_udp_tunnel_completion);
-
-/* remove UDP Tunnel command (0x0B01) */
-struct i40e_aqc_remove_udp_tunnel {
- u8 reserved[2];
- u8 index; /* 0 to 15 */
- u8 reserved2[13];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_remove_udp_tunnel);
-
-struct i40e_aqc_del_udp_tunnel_completion {
- __le16 udp_port;
- u8 index; /* 0 to 15 */
- u8 multiple_pfs;
- u8 total_filters_used;
- u8 reserved1[11];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_del_udp_tunnel_completion);
-
-struct i40e_aqc_get_set_rss_key {
-#define I40E_AQC_SET_RSS_KEY_VSI_VALID BIT(15)
-#define I40E_AQC_SET_RSS_KEY_VSI_ID_SHIFT 0
-#define I40E_AQC_SET_RSS_KEY_VSI_ID_MASK (0x3FF << \
- I40E_AQC_SET_RSS_KEY_VSI_ID_SHIFT)
- __le16 vsi_id;
- u8 reserved[6];
- __le32 addr_high;
- __le32 addr_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_get_set_rss_key);
-
-struct i40e_aqc_get_set_rss_key_data {
- u8 standard_rss_key[0x28];
- u8 extended_hash_key[0xc];
-};
-
-I40E_CHECK_STRUCT_LEN(0x34, i40e_aqc_get_set_rss_key_data);
-
-struct i40e_aqc_get_set_rss_lut {
-#define I40E_AQC_SET_RSS_LUT_VSI_VALID BIT(15)
-#define I40E_AQC_SET_RSS_LUT_VSI_ID_SHIFT 0
-#define I40E_AQC_SET_RSS_LUT_VSI_ID_MASK (0x3FF << \
- I40E_AQC_SET_RSS_LUT_VSI_ID_SHIFT)
- __le16 vsi_id;
-#define I40E_AQC_SET_RSS_LUT_TABLE_TYPE_SHIFT 0
-#define I40E_AQC_SET_RSS_LUT_TABLE_TYPE_MASK \
- BIT(I40E_AQC_SET_RSS_LUT_TABLE_TYPE_SHIFT)
-
-#define I40E_AQC_SET_RSS_LUT_TABLE_TYPE_VSI 0
-#define I40E_AQC_SET_RSS_LUT_TABLE_TYPE_PF 1
- __le16 flags;
- u8 reserved[4];
- __le32 addr_high;
- __le32 addr_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_get_set_rss_lut);
-
-/* tunnel key structure 0x0B10 */
-
-struct i40e_aqc_tunnel_key_structure_A0 {
- __le16 key1_off;
- __le16 key1_len;
- __le16 key2_off;
- __le16 key2_len;
- __le16 flags;
-#define I40E_AQC_TUNNEL_KEY_STRUCT_OVERRIDE 0x01
-/* response flags */
-#define I40E_AQC_TUNNEL_KEY_STRUCT_SUCCESS 0x01
-#define I40E_AQC_TUNNEL_KEY_STRUCT_MODIFIED 0x02
-#define I40E_AQC_TUNNEL_KEY_STRUCT_OVERRIDDEN 0x03
- u8 resreved[6];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_tunnel_key_structure_A0);
-
-struct i40e_aqc_tunnel_key_structure {
- u8 key1_off;
- u8 key2_off;
- u8 key1_len; /* 0 to 15 */
- u8 key2_len; /* 0 to 15 */
- u8 flags;
-#define I40E_AQC_TUNNEL_KEY_STRUCT_OVERRIDE 0x01
-/* response flags */
-#define I40E_AQC_TUNNEL_KEY_STRUCT_SUCCESS 0x01
-#define I40E_AQC_TUNNEL_KEY_STRUCT_MODIFIED 0x02
-#define I40E_AQC_TUNNEL_KEY_STRUCT_OVERRIDDEN 0x03
- u8 network_key_index;
-#define I40E_AQC_NETWORK_KEY_INDEX_VXLAN 0x0
-#define I40E_AQC_NETWORK_KEY_INDEX_NGE 0x1
-#define I40E_AQC_NETWORK_KEY_INDEX_FLEX_MAC_IN_UDP 0x2
-#define I40E_AQC_NETWORK_KEY_INDEX_GRE 0x3
- u8 reserved[10];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_tunnel_key_structure);
-
-/* OEM mode commands (direct 0xFE0x) */
-struct i40e_aqc_oem_param_change {
- __le32 param_type;
-#define I40E_AQ_OEM_PARAM_TYPE_PF_CTL 0
-#define I40E_AQ_OEM_PARAM_TYPE_BW_CTL 1
-#define I40E_AQ_OEM_PARAM_MAC 2
- __le32 param_value1;
- __le16 param_value2;
- u8 reserved[6];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_oem_param_change);
-
-struct i40e_aqc_oem_state_change {
- __le32 state;
-#define I40E_AQ_OEM_STATE_LINK_DOWN 0x0
-#define I40E_AQ_OEM_STATE_LINK_UP 0x1
- u8 reserved[12];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_oem_state_change);
-
-/* Initialize OCSD (0xFE02, direct) */
-struct i40e_aqc_opc_oem_ocsd_initialize {
- u8 type_status;
- u8 reserved1[3];
- __le32 ocsd_memory_block_addr_high;
- __le32 ocsd_memory_block_addr_low;
- __le32 requested_update_interval;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_opc_oem_ocsd_initialize);
-
-/* Initialize OCBB (0xFE03, direct) */
-struct i40e_aqc_opc_oem_ocbb_initialize {
- u8 type_status;
- u8 reserved1[3];
- __le32 ocbb_memory_block_addr_high;
- __le32 ocbb_memory_block_addr_low;
- u8 reserved2[4];
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_opc_oem_ocbb_initialize);
-
-/* debug commands */
-
-/* get device id (0xFF00) uses the generic structure */
-
-/* set test more (0xFF01, internal) */
-
-struct i40e_acq_set_test_mode {
- u8 mode;
-#define I40E_AQ_TEST_PARTIAL 0
-#define I40E_AQ_TEST_FULL 1
-#define I40E_AQ_TEST_NVM 2
- u8 reserved[3];
- u8 command;
-#define I40E_AQ_TEST_OPEN 0
-#define I40E_AQ_TEST_CLOSE 1
-#define I40E_AQ_TEST_INC 2
- u8 reserved2[3];
- __le32 address_high;
- __le32 address_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_acq_set_test_mode);
-
-/* Debug Read Register command (0xFF03)
- * Debug Write Register command (0xFF04)
- */
-struct i40e_aqc_debug_reg_read_write {
- __le32 reserved;
- __le32 address;
- __le32 value_high;
- __le32 value_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_debug_reg_read_write);
-
-/* Scatter/gather Reg Read (indirect 0xFF05)
- * Scatter/gather Reg Write (indirect 0xFF06)
- */
-
-/* i40e_aq_desc is used for the command */
-struct i40e_aqc_debug_reg_sg_element_data {
- __le32 address;
- __le32 value;
-};
-
-/* Debug Modify register (direct 0xFF07) */
-struct i40e_aqc_debug_modify_reg {
- __le32 address;
- __le32 value;
- __le32 clear_mask;
- __le32 set_mask;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_debug_modify_reg);
-
-/* dump internal data (0xFF08, indirect) */
-
-#define I40E_AQ_CLUSTER_ID_AUX 0
-#define I40E_AQ_CLUSTER_ID_SWITCH_FLU 1
-#define I40E_AQ_CLUSTER_ID_TXSCHED 2
-#define I40E_AQ_CLUSTER_ID_HMC 3
-#define I40E_AQ_CLUSTER_ID_MAC0 4
-#define I40E_AQ_CLUSTER_ID_MAC1 5
-#define I40E_AQ_CLUSTER_ID_MAC2 6
-#define I40E_AQ_CLUSTER_ID_MAC3 7
-#define I40E_AQ_CLUSTER_ID_DCB 8
-#define I40E_AQ_CLUSTER_ID_EMP_MEM 9
-#define I40E_AQ_CLUSTER_ID_PKT_BUF 10
-#define I40E_AQ_CLUSTER_ID_ALTRAM 11
-
-struct i40e_aqc_debug_dump_internals {
- u8 cluster_id;
- u8 table_id;
- __le16 data_size;
- __le32 idx;
- __le32 address_high;
- __le32 address_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_debug_dump_internals);
-
-struct i40e_aqc_debug_modify_internals {
- u8 cluster_id;
- u8 cluster_specific_params[7];
- __le32 address_high;
- __le32 address_low;
-};
-
-I40E_CHECK_CMD_LENGTH(i40e_aqc_debug_modify_internals);
-
-#endif /* _I40E_ADMINQ_CMD_H_ */
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_alloc.h b/drivers/net/ethernet/intel/i40evf/i40e_alloc.h
deleted file mode 100644
index cb8689222c8b..000000000000
--- a/drivers/net/ethernet/intel/i40evf/i40e_alloc.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/* Copyright(c) 2013 - 2018 Intel Corporation. */
-
-#ifndef _I40E_ALLOC_H_
-#define _I40E_ALLOC_H_
-
-struct i40e_hw;
-
-/* Memory allocation types */
-enum i40e_memory_type {
- i40e_mem_arq_buf = 0, /* ARQ indirect command buffer */
- i40e_mem_asq_buf = 1,
- i40e_mem_atq_buf = 2, /* ATQ indirect command buffer */
- i40e_mem_arq_ring = 3, /* ARQ descriptor ring */
- i40e_mem_atq_ring = 4, /* ATQ descriptor ring */
- i40e_mem_pd = 5, /* Page Descriptor */
- i40e_mem_bp = 6, /* Backing Page - 4KB */
- i40e_mem_bp_jumbo = 7, /* Backing Page - > 4KB */
- i40e_mem_reserved
-};
-
-/* prototype for functions used for dynamic memory allocation */
-i40e_status i40e_allocate_dma_mem(struct i40e_hw *hw,
- struct i40e_dma_mem *mem,
- enum i40e_memory_type type,
- u64 size, u32 alignment);
-i40e_status i40e_free_dma_mem(struct i40e_hw *hw,
- struct i40e_dma_mem *mem);
-i40e_status i40e_allocate_virt_mem(struct i40e_hw *hw,
- struct i40e_virt_mem *mem,
- u32 size);
-i40e_status i40e_free_virt_mem(struct i40e_hw *hw,
- struct i40e_virt_mem *mem);
-
-#endif /* _I40E_ALLOC_H_ */
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_common.c b/drivers/net/ethernet/intel/i40evf/i40e_common.c
deleted file mode 100644
index eea280ba411e..000000000000
--- a/drivers/net/ethernet/intel/i40evf/i40e_common.c
+++ /dev/null
@@ -1,1320 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* Copyright(c) 2013 - 2018 Intel Corporation. */
-
-#include "i40e_type.h"
-#include "i40e_adminq.h"
-#include "i40e_prototype.h"
-#include <linux/avf/virtchnl.h>
-
-/**
- * i40e_set_mac_type - Sets MAC type
- * @hw: pointer to the HW structure
- *
- * This function sets the mac type of the adapter based on the
- * vendor ID and device ID stored in the hw structure.
- **/
-i40e_status i40e_set_mac_type(struct i40e_hw *hw)
-{
- i40e_status status = 0;
-
- if (hw->vendor_id == PCI_VENDOR_ID_INTEL) {
- switch (hw->device_id) {
- case I40E_DEV_ID_SFP_XL710:
- case I40E_DEV_ID_QEMU:
- case I40E_DEV_ID_KX_B:
- case I40E_DEV_ID_KX_C:
- case I40E_DEV_ID_QSFP_A:
- case I40E_DEV_ID_QSFP_B:
- case I40E_DEV_ID_QSFP_C:
- case I40E_DEV_ID_10G_BASE_T:
- case I40E_DEV_ID_10G_BASE_T4:
- case I40E_DEV_ID_20G_KR2:
- case I40E_DEV_ID_20G_KR2_A:
- case I40E_DEV_ID_25G_B:
- case I40E_DEV_ID_25G_SFP28:
- hw->mac.type = I40E_MAC_XL710;
- break;
- case I40E_DEV_ID_SFP_X722:
- case I40E_DEV_ID_1G_BASE_T_X722:
- case I40E_DEV_ID_10G_BASE_T_X722:
- case I40E_DEV_ID_SFP_I_X722:
- hw->mac.type = I40E_MAC_X722;
- break;
- case I40E_DEV_ID_X722_VF:
- hw->mac.type = I40E_MAC_X722_VF;
- break;
- case I40E_DEV_ID_VF:
- case I40E_DEV_ID_VF_HV:
- case I40E_DEV_ID_ADAPTIVE_VF:
- hw->mac.type = I40E_MAC_VF;
- break;
- default:
- hw->mac.type = I40E_MAC_GENERIC;
- break;
- }
- } else {
- status = I40E_ERR_DEVICE_NOT_SUPPORTED;
- }
-
- hw_dbg(hw, "i40e_set_mac_type found mac: %d, returns: %d\n",
- hw->mac.type, status);
- return status;
-}
-
-/**
- * i40evf_aq_str - convert AQ err code to a string
- * @hw: pointer to the HW structure
- * @aq_err: the AQ error code to convert
- **/
-const char *i40evf_aq_str(struct i40e_hw *hw, enum i40e_admin_queue_err aq_err)
-{
- switch (aq_err) {
- case I40E_AQ_RC_OK:
- return "OK";
- case I40E_AQ_RC_EPERM:
- return "I40E_AQ_RC_EPERM";
- case I40E_AQ_RC_ENOENT:
- return "I40E_AQ_RC_ENOENT";
- case I40E_AQ_RC_ESRCH:
- return "I40E_AQ_RC_ESRCH";
- case I40E_AQ_RC_EINTR:
- return "I40E_AQ_RC_EINTR";
- case I40E_AQ_RC_EIO:
- return "I40E_AQ_RC_EIO";
- case I40E_AQ_RC_ENXIO:
- return "I40E_AQ_RC_ENXIO";
- case I40E_AQ_RC_E2BIG:
- return "I40E_AQ_RC_E2BIG";
- case I40E_AQ_RC_EAGAIN:
- return "I40E_AQ_RC_EAGAIN";
- case I40E_AQ_RC_ENOMEM:
- return "I40E_AQ_RC_ENOMEM";
- case I40E_AQ_RC_EACCES:
- return "I40E_AQ_RC_EACCES";
- case I40E_AQ_RC_EFAULT:
- return "I40E_AQ_RC_EFAULT";
- case I40E_AQ_RC_EBUSY:
- return "I40E_AQ_RC_EBUSY";
- case I40E_AQ_RC_EEXIST:
- return "I40E_AQ_RC_EEXIST";
- case I40E_AQ_RC_EINVAL:
- return "I40E_AQ_RC_EINVAL";
- case I40E_AQ_RC_ENOTTY:
- return "I40E_AQ_RC_ENOTTY";
- case I40E_AQ_RC_ENOSPC:
- return "I40E_AQ_RC_ENOSPC";
- case I40E_AQ_RC_ENOSYS:
- return "I40E_AQ_RC_ENOSYS";
- case I40E_AQ_RC_ERANGE:
- return "I40E_AQ_RC_ERANGE";
- case I40E_AQ_RC_EFLUSHED:
- return "I40E_AQ_RC_EFLUSHED";
- case I40E_AQ_RC_BAD_ADDR:
- return "I40E_AQ_RC_BAD_ADDR";
- case I40E_AQ_RC_EMODE:
- return "I40E_AQ_RC_EMODE";
- case I40E_AQ_RC_EFBIG:
- return "I40E_AQ_RC_EFBIG";
- }
-
- snprintf(hw->err_str, sizeof(hw->err_str), "%d", aq_err);
- return hw->err_str;
-}
-
-/**
- * i40evf_stat_str - convert status err code to a string
- * @hw: pointer to the HW structure
- * @stat_err: the status error code to convert
- **/
-const char *i40evf_stat_str(struct i40e_hw *hw, i40e_status stat_err)
-{
- switch (stat_err) {
- case 0:
- return "OK";
- case I40E_ERR_NVM:
- return "I40E_ERR_NVM";
- case I40E_ERR_NVM_CHECKSUM:
- return "I40E_ERR_NVM_CHECKSUM";
- case I40E_ERR_PHY:
- return "I40E_ERR_PHY";
- case I40E_ERR_CONFIG:
- return "I40E_ERR_CONFIG";
- case I40E_ERR_PARAM:
- return "I40E_ERR_PARAM";
- case I40E_ERR_MAC_TYPE:
- return "I40E_ERR_MAC_TYPE";
- case I40E_ERR_UNKNOWN_PHY:
- return "I40E_ERR_UNKNOWN_PHY";
- case I40E_ERR_LINK_SETUP:
- return "I40E_ERR_LINK_SETUP";
- case I40E_ERR_ADAPTER_STOPPED:
- return "I40E_ERR_ADAPTER_STOPPED";
- case I40E_ERR_INVALID_MAC_ADDR:
- return "I40E_ERR_INVALID_MAC_ADDR";
- case I40E_ERR_DEVICE_NOT_SUPPORTED:
- return "I40E_ERR_DEVICE_NOT_SUPPORTED";
- case I40E_ERR_MASTER_REQUESTS_PENDING:
- return "I40E_ERR_MASTER_REQUESTS_PENDING";
- case I40E_ERR_INVALID_LINK_SETTINGS:
- return "I40E_ERR_INVALID_LINK_SETTINGS";
- case I40E_ERR_AUTONEG_NOT_COMPLETE:
- return "I40E_ERR_AUTONEG_NOT_COMPLETE";
- case I40E_ERR_RESET_FAILED:
- return "I40E_ERR_RESET_FAILED";
- case I40E_ERR_SWFW_SYNC:
- return "I40E_ERR_SWFW_SYNC";
- case I40E_ERR_NO_AVAILABLE_VSI:
- return "I40E_ERR_NO_AVAILABLE_VSI";
- case I40E_ERR_NO_MEMORY:
- return "I40E_ERR_NO_MEMORY";
- case I40E_ERR_BAD_PTR:
- return "I40E_ERR_BAD_PTR";
- case I40E_ERR_RING_FULL:
- return "I40E_ERR_RING_FULL";
- case I40E_ERR_INVALID_PD_ID:
- return "I40E_ERR_INVALID_PD_ID";
- case I40E_ERR_INVALID_QP_ID:
- return "I40E_ERR_INVALID_QP_ID";
- case I40E_ERR_INVALID_CQ_ID:
- return "I40E_ERR_INVALID_CQ_ID";
- case I40E_ERR_INVALID_CEQ_ID:
- return "I40E_ERR_INVALID_CEQ_ID";
- case I40E_ERR_INVALID_AEQ_ID:
- return "I40E_ERR_INVALID_AEQ_ID";
- case I40E_ERR_INVALID_SIZE:
- return "I40E_ERR_INVALID_SIZE";
- case I40E_ERR_INVALID_ARP_INDEX:
- return "I40E_ERR_INVALID_ARP_INDEX";
- case I40E_ERR_INVALID_FPM_FUNC_ID:
- return "I40E_ERR_INVALID_FPM_FUNC_ID";
- case I40E_ERR_QP_INVALID_MSG_SIZE:
- return "I40E_ERR_QP_INVALID_MSG_SIZE";
- case I40E_ERR_QP_TOOMANY_WRS_POSTED:
- return "I40E_ERR_QP_TOOMANY_WRS_POSTED";
- case I40E_ERR_INVALID_FRAG_COUNT:
- return "I40E_ERR_INVALID_FRAG_COUNT";
- case I40E_ERR_QUEUE_EMPTY:
- return "I40E_ERR_QUEUE_EMPTY";
- case I40E_ERR_INVALID_ALIGNMENT:
- return "I40E_ERR_INVALID_ALIGNMENT";
- case I40E_ERR_FLUSHED_QUEUE:
- return "I40E_ERR_FLUSHED_QUEUE";
- case I40E_ERR_INVALID_PUSH_PAGE_INDEX:
- return "I40E_ERR_INVALID_PUSH_PAGE_INDEX";
- case I40E_ERR_INVALID_IMM_DATA_SIZE:
- return "I40E_ERR_INVALID_IMM_DATA_SIZE";
- case I40E_ERR_TIMEOUT:
- return "I40E_ERR_TIMEOUT";
- case I40E_ERR_OPCODE_MISMATCH:
- return "I40E_ERR_OPCODE_MISMATCH";
- case I40E_ERR_CQP_COMPL_ERROR:
- return "I40E_ERR_CQP_COMPL_ERROR";
- case I40E_ERR_INVALID_VF_ID:
- return "I40E_ERR_INVALID_VF_ID";
- case I40E_ERR_INVALID_HMCFN_ID:
- return "I40E_ERR_INVALID_HMCFN_ID";
- case I40E_ERR_BACKING_PAGE_ERROR:
- return "I40E_ERR_BACKING_PAGE_ERROR";
- case I40E_ERR_NO_PBLCHUNKS_AVAILABLE:
- return "I40E_ERR_NO_PBLCHUNKS_AVAILABLE";
- case I40E_ERR_INVALID_PBLE_INDEX:
- return "I40E_ERR_INVALID_PBLE_INDEX";
- case I40E_ERR_INVALID_SD_INDEX:
- return "I40E_ERR_INVALID_SD_INDEX";
- case I40E_ERR_INVALID_PAGE_DESC_INDEX:
- return "I40E_ERR_INVALID_PAGE_DESC_INDEX";
- case I40E_ERR_INVALID_SD_TYPE:
- return "I40E_ERR_INVALID_SD_TYPE";
- case I40E_ERR_MEMCPY_FAILED:
- return "I40E_ERR_MEMCPY_FAILED";
- case I40E_ERR_INVALID_HMC_OBJ_INDEX:
- return "I40E_ERR_INVALID_HMC_OBJ_INDEX";
- case I40E_ERR_INVALID_HMC_OBJ_COUNT:
- return "I40E_ERR_INVALID_HMC_OBJ_COUNT";
- case I40E_ERR_INVALID_SRQ_ARM_LIMIT:
- return "I40E_ERR_INVALID_SRQ_ARM_LIMIT";
- case I40E_ERR_SRQ_ENABLED:
- return "I40E_ERR_SRQ_ENABLED";
- case I40E_ERR_ADMIN_QUEUE_ERROR:
- return "I40E_ERR_ADMIN_QUEUE_ERROR";
- case I40E_ERR_ADMIN_QUEUE_TIMEOUT:
- return "I40E_ERR_ADMIN_QUEUE_TIMEOUT";
- case I40E_ERR_BUF_TOO_SHORT:
- return "I40E_ERR_BUF_TOO_SHORT";
- case I40E_ERR_ADMIN_QUEUE_FULL:
- return "I40E_ERR_ADMIN_QUEUE_FULL";
- case I40E_ERR_ADMIN_QUEUE_NO_WORK:
- return "I40E_ERR_ADMIN_QUEUE_NO_WORK";
- case I40E_ERR_BAD_IWARP_CQE:
- return "I40E_ERR_BAD_IWARP_CQE";
- case I40E_ERR_NVM_BLANK_MODE:
- return "I40E_ERR_NVM_BLANK_MODE";
- case I40E_ERR_NOT_IMPLEMENTED:
- return "I40E_ERR_NOT_IMPLEMENTED";
- case I40E_ERR_PE_DOORBELL_NOT_ENABLED:
- return "I40E_ERR_PE_DOORBELL_NOT_ENABLED";
- case I40E_ERR_DIAG_TEST_FAILED:
- return "I40E_ERR_DIAG_TEST_FAILED";
- case I40E_ERR_NOT_READY:
- return "I40E_ERR_NOT_READY";
- case I40E_NOT_SUPPORTED:
- return "I40E_NOT_SUPPORTED";
- case I40E_ERR_FIRMWARE_API_VERSION:
- return "I40E_ERR_FIRMWARE_API_VERSION";
- case I40E_ERR_ADMIN_QUEUE_CRITICAL_ERROR:
- return "I40E_ERR_ADMIN_QUEUE_CRITICAL_ERROR";
- }
-
- snprintf(hw->err_str, sizeof(hw->err_str), "%d", stat_err);
- return hw->err_str;
-}
-
-/**
- * i40evf_debug_aq
- * @hw: debug mask related to admin queue
- * @mask: debug mask
- * @desc: pointer to admin queue descriptor
- * @buffer: pointer to command buffer
- * @buf_len: max length of buffer
- *
- * Dumps debug log about adminq command with descriptor contents.
- **/
-void i40evf_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask, void *desc,
- void *buffer, u16 buf_len)
-{
- struct i40e_aq_desc *aq_desc = (struct i40e_aq_desc *)desc;
- u8 *buf = (u8 *)buffer;
-
- if ((!(mask & hw->debug_mask)) || (desc == NULL))
- return;
-
- i40e_debug(hw, mask,
- "AQ CMD: opcode 0x%04X, flags 0x%04X, datalen 0x%04X, retval 0x%04X\n",
- le16_to_cpu(aq_desc->opcode),
- le16_to_cpu(aq_desc->flags),
- le16_to_cpu(aq_desc->datalen),
- le16_to_cpu(aq_desc->retval));
- i40e_debug(hw, mask, "\tcookie (h,l) 0x%08X 0x%08X\n",
- le32_to_cpu(aq_desc->cookie_high),
- le32_to_cpu(aq_desc->cookie_low));
- i40e_debug(hw, mask, "\tparam (0,1) 0x%08X 0x%08X\n",
- le32_to_cpu(aq_desc->params.internal.param0),
- le32_to_cpu(aq_desc->params.internal.param1));
- i40e_debug(hw, mask, "\taddr (h,l) 0x%08X 0x%08X\n",
- le32_to_cpu(aq_desc->params.external.addr_high),
- le32_to_cpu(aq_desc->params.external.addr_low));
-
- if ((buffer != NULL) && (aq_desc->datalen != 0)) {
- u16 len = le16_to_cpu(aq_desc->datalen);
-
- i40e_debug(hw, mask, "AQ CMD Buffer:\n");
- if (buf_len < len)
- len = buf_len;
- /* write the full 16-byte chunks */
- if (hw->debug_mask & mask) {
- char prefix[27];
-
- snprintf(prefix, sizeof(prefix),
- "i40evf %02x:%02x.%x: \t0x",
- hw->bus.bus_id,
- hw->bus.device,
- hw->bus.func);
-
- print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_OFFSET,
- 16, 1, buf, len, false);
- }
- }
-}
-
-/**
- * i40evf_check_asq_alive
- * @hw: pointer to the hw struct
- *
- * Returns true if Queue is enabled else false.
- **/
-bool i40evf_check_asq_alive(struct i40e_hw *hw)
-{
- if (hw->aq.asq.len)
- return !!(rd32(hw, hw->aq.asq.len) &
- I40E_VF_ATQLEN1_ATQENABLE_MASK);
- else
- return false;
-}
-
-/**
- * i40evf_aq_queue_shutdown
- * @hw: pointer to the hw struct
- * @unloading: is the driver unloading itself
- *
- * Tell the Firmware that we're shutting down the AdminQ and whether
- * or not the driver is unloading as well.
- **/
-i40e_status i40evf_aq_queue_shutdown(struct i40e_hw *hw,
- bool unloading)
-{
- struct i40e_aq_desc desc;
- struct i40e_aqc_queue_shutdown *cmd =
- (struct i40e_aqc_queue_shutdown *)&desc.params.raw;
- i40e_status status;
-
- i40evf_fill_default_direct_cmd_desc(&desc,
- i40e_aqc_opc_queue_shutdown);
-
- if (unloading)
- cmd->driver_unloading = cpu_to_le32(I40E_AQ_DRIVER_UNLOADING);
- status = i40evf_asq_send_command(hw, &desc, NULL, 0, NULL);
-
- return status;
-}
-
-/**
- * i40e_aq_get_set_rss_lut
- * @hw: pointer to the hardware structure
- * @vsi_id: vsi fw index
- * @pf_lut: for PF table set true, for VSI table set false
- * @lut: pointer to the lut buffer provided by the caller
- * @lut_size: size of the lut buffer
- * @set: set true to set the table, false to get the table
- *
- * Internal function to get or set RSS look up table
- **/
-static i40e_status i40e_aq_get_set_rss_lut(struct i40e_hw *hw,
- u16 vsi_id, bool pf_lut,
- u8 *lut, u16 lut_size,
- bool set)
-{
- i40e_status status;
- struct i40e_aq_desc desc;
- struct i40e_aqc_get_set_rss_lut *cmd_resp =
- (struct i40e_aqc_get_set_rss_lut *)&desc.params.raw;
-
- if (set)
- i40evf_fill_default_direct_cmd_desc(&desc,
- i40e_aqc_opc_set_rss_lut);
- else
- i40evf_fill_default_direct_cmd_desc(&desc,
- i40e_aqc_opc_get_rss_lut);
-
- /* Indirect command */
- desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_BUF);
- desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_RD);
-
- cmd_resp->vsi_id =
- cpu_to_le16((u16)((vsi_id <<
- I40E_AQC_SET_RSS_LUT_VSI_ID_SHIFT) &
- I40E_AQC_SET_RSS_LUT_VSI_ID_MASK));
- cmd_resp->vsi_id |= cpu_to_le16((u16)I40E_AQC_SET_RSS_LUT_VSI_VALID);
-
- if (pf_lut)
- cmd_resp->flags |= cpu_to_le16((u16)
- ((I40E_AQC_SET_RSS_LUT_TABLE_TYPE_PF <<
- I40E_AQC_SET_RSS_LUT_TABLE_TYPE_SHIFT) &
- I40E_AQC_SET_RSS_LUT_TABLE_TYPE_MASK));
- else
- cmd_resp->flags |= cpu_to_le16((u16)
- ((I40E_AQC_SET_RSS_LUT_TABLE_TYPE_VSI <<
- I40E_AQC_SET_RSS_LUT_TABLE_TYPE_SHIFT) &
- I40E_AQC_SET_RSS_LUT_TABLE_TYPE_MASK));
-
- status = i40evf_asq_send_command(hw, &desc, lut, lut_size, NULL);
-
- return status;
-}
-
-/**
- * i40evf_aq_get_rss_lut
- * @hw: pointer to the hardware structure
- * @vsi_id: vsi fw index
- * @pf_lut: for PF table set true, for VSI table set false
- * @lut: pointer to the lut buffer provided by the caller
- * @lut_size: size of the lut buffer
- *
- * get the RSS lookup table, PF or VSI type
- **/
-i40e_status i40evf_aq_get_rss_lut(struct i40e_hw *hw, u16 vsi_id,
- bool pf_lut, u8 *lut, u16 lut_size)
-{
- return i40e_aq_get_set_rss_lut(hw, vsi_id, pf_lut, lut, lut_size,
- false);
-}
-
-/**
- * i40evf_aq_set_rss_lut
- * @hw: pointer to the hardware structure
- * @vsi_id: vsi fw index
- * @pf_lut: for PF table set true, for VSI table set false
- * @lut: pointer to the lut buffer provided by the caller
- * @lut_size: size of the lut buffer
- *
- * set the RSS lookup table, PF or VSI type
- **/
-i40e_status i40evf_aq_set_rss_lut(struct i40e_hw *hw, u16 vsi_id,
- bool pf_lut, u8 *lut, u16 lut_size)
-{
- return i40e_aq_get_set_rss_lut(hw, vsi_id, pf_lut, lut, lut_size, true);
-}
-
-/**
- * i40e_aq_get_set_rss_key
- * @hw: pointer to the hw struct
- * @vsi_id: vsi fw index
- * @key: pointer to key info struct
- * @set: set true to set the key, false to get the key
- *
- * get the RSS key per VSI
- **/
-static i40e_status i40e_aq_get_set_rss_key(struct i40e_hw *hw,
- u16 vsi_id,
- struct i40e_aqc_get_set_rss_key_data *key,
- bool set)
-{
- i40e_status status;
- struct i40e_aq_desc desc;
- struct i40e_aqc_get_set_rss_key *cmd_resp =
- (struct i40e_aqc_get_set_rss_key *)&desc.params.raw;
- u16 key_size = sizeof(struct i40e_aqc_get_set_rss_key_data);
-
- if (set)
- i40evf_fill_default_direct_cmd_desc(&desc,
- i40e_aqc_opc_set_rss_key);
- else
- i40evf_fill_default_direct_cmd_desc(&desc,
- i40e_aqc_opc_get_rss_key);
-
- /* Indirect command */
- desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_BUF);
- desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_RD);
-
- cmd_resp->vsi_id =
- cpu_to_le16((u16)((vsi_id <<
- I40E_AQC_SET_RSS_KEY_VSI_ID_SHIFT) &
- I40E_AQC_SET_RSS_KEY_VSI_ID_MASK));
- cmd_resp->vsi_id |= cpu_to_le16((u16)I40E_AQC_SET_RSS_KEY_VSI_VALID);
-
- status = i40evf_asq_send_command(hw, &desc, key, key_size, NULL);
-
- return status;
-}
-
-/**
- * i40evf_aq_get_rss_key
- * @hw: pointer to the hw struct
- * @vsi_id: vsi fw index
- * @key: pointer to key info struct
- *
- **/
-i40e_status i40evf_aq_get_rss_key(struct i40e_hw *hw,
- u16 vsi_id,
- struct i40e_aqc_get_set_rss_key_data *key)
-{
- return i40e_aq_get_set_rss_key(hw, vsi_id, key, false);
-}
-
-/**
- * i40evf_aq_set_rss_key
- * @hw: pointer to the hw struct
- * @vsi_id: vsi fw index
- * @key: pointer to key info struct
- *
- * set the RSS key per VSI
- **/
-i40e_status i40evf_aq_set_rss_key(struct i40e_hw *hw,
- u16 vsi_id,
- struct i40e_aqc_get_set_rss_key_data *key)
-{
- return i40e_aq_get_set_rss_key(hw, vsi_id, key, true);
-}
-
-
-/* The i40evf_ptype_lookup table is used to convert from the 8-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 i40evf_ptype_lookup[ptype].known
- * THEN
- * Packet is unknown
- * ELSE IF i40evf_ptype_lookup[ptype].outer_ip == I40E_RX_PTYPE_OUTER_IP
- * Use the rest of the fields to look at the tunnels, inner protocols, etc
- * ELSE
- * Use the enum i40e_rx_l2_ptype to decode the packet type
- * ENDIF
- */
-
-/* macro to make the table lines short */
-#define I40E_PTT(PTYPE, OUTER_IP, OUTER_IP_VER, OUTER_FRAG, T, TE, TEF, I, PL)\
- { PTYPE, \
- 1, \
- I40E_RX_PTYPE_OUTER_##OUTER_IP, \
- I40E_RX_PTYPE_OUTER_##OUTER_IP_VER, \
- I40E_RX_PTYPE_##OUTER_FRAG, \
- I40E_RX_PTYPE_TUNNEL_##T, \
- I40E_RX_PTYPE_TUNNEL_END_##TE, \
- I40E_RX_PTYPE_##TEF, \
- 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 }
-
-/* 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 i40evf_ptype_lookup[] = {
- /* L2 Packet types */
- I40E_PTT_UNUSED_ENTRY(0),
- I40E_PTT(1, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
- I40E_PTT(2, L2, NONE, NOF, NONE, NONE, NOF, TS, PAY2),
- I40E_PTT(3, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
- I40E_PTT_UNUSED_ENTRY(4),
- I40E_PTT_UNUSED_ENTRY(5),
- I40E_PTT(6, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
- I40E_PTT(7, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
- I40E_PTT_UNUSED_ENTRY(8),
- I40E_PTT_UNUSED_ENTRY(9),
- I40E_PTT(10, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
- I40E_PTT(11, L2, NONE, NOF, NONE, NONE, NOF, NONE, NONE),
- I40E_PTT(12, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
- I40E_PTT(13, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
- I40E_PTT(14, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
- I40E_PTT(15, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
- I40E_PTT(16, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
- I40E_PTT(17, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
- I40E_PTT(18, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
- I40E_PTT(19, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
- I40E_PTT(20, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
- I40E_PTT(21, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
-
- /* Non Tunneled IPv4 */
- I40E_PTT(22, IP, IPV4, FRG, NONE, NONE, NOF, NONE, PAY3),
- I40E_PTT(23, IP, IPV4, NOF, NONE, NONE, NOF, NONE, PAY3),
- I40E_PTT(24, IP, IPV4, NOF, NONE, NONE, NOF, UDP, PAY4),
- I40E_PTT_UNUSED_ENTRY(25),
- I40E_PTT(26, IP, IPV4, NOF, NONE, NONE, NOF, TCP, PAY4),
- I40E_PTT(27, IP, IPV4, NOF, NONE, NONE, NOF, SCTP, PAY4),
- I40E_PTT(28, IP, IPV4, NOF, NONE, NONE, NOF, ICMP, PAY4),
-
- /* IPv4 --> IPv4 */
- I40E_PTT(29, IP, IPV4, NOF, IP_IP, IPV4, FRG, NONE, PAY3),
- I40E_PTT(30, IP, IPV4, NOF, IP_IP, IPV4, NOF, NONE, PAY3),
- I40E_PTT(31, IP, IPV4, NOF, IP_IP, IPV4, NOF, UDP, PAY4),
- I40E_PTT_UNUSED_ENTRY(32),
- I40E_PTT(33, IP, IPV4, NOF, IP_IP, IPV4, NOF, TCP, PAY4),
- I40E_PTT(34, IP, IPV4, NOF, IP_IP, IPV4, NOF, SCTP, PAY4),
- I40E_PTT(35, IP, IPV4, NOF, IP_IP, IPV4, NOF, ICMP, PAY4),
-
- /* IPv4 --> IPv6 */
- I40E_PTT(36, IP, IPV4, NOF, IP_IP, IPV6, FRG, NONE, PAY3),
- I40E_PTT(37, IP, IPV4, NOF, IP_IP, IPV6, NOF, NONE, PAY3),
- I40E_PTT(38, IP, IPV4, NOF, IP_IP, IPV6, NOF, UDP, PAY4),
- I40E_PTT_UNUSED_ENTRY(39),
- I40E_PTT(40, IP, IPV4, NOF, IP_IP, IPV6, NOF, TCP, PAY4),
- I40E_PTT(41, IP, IPV4, NOF, IP_IP, IPV6, NOF, SCTP, PAY4),
- I40E_PTT(42, IP, IPV4, NOF, IP_IP, IPV6, NOF, ICMP, PAY4),
-
- /* IPv4 --> GRE/NAT */
- I40E_PTT(43, IP, IPV4, NOF, IP_GRENAT, NONE, NOF, NONE, PAY3),
-
- /* IPv4 --> GRE/NAT --> IPv4 */
- I40E_PTT(44, IP, IPV4, NOF, IP_GRENAT, IPV4, FRG, NONE, PAY3),
- I40E_PTT(45, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, NONE, PAY3),
- I40E_PTT(46, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, UDP, PAY4),
- I40E_PTT_UNUSED_ENTRY(47),
- I40E_PTT(48, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, TCP, PAY4),
- I40E_PTT(49, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, SCTP, PAY4),
- I40E_PTT(50, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, ICMP, PAY4),
-
- /* IPv4 --> GRE/NAT --> IPv6 */
- I40E_PTT(51, IP, IPV4, NOF, IP_GRENAT, IPV6, FRG, NONE, PAY3),
- I40E_PTT(52, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, NONE, PAY3),
- I40E_PTT(53, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, UDP, PAY4),
- I40E_PTT_UNUSED_ENTRY(54),
- I40E_PTT(55, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, TCP, PAY4),
- I40E_PTT(56, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, SCTP, PAY4),
- I40E_PTT(57, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, ICMP, PAY4),
-
- /* IPv4 --> GRE/NAT --> MAC */
- I40E_PTT(58, IP, IPV4, NOF, IP_GRENAT_MAC, NONE, NOF, NONE, PAY3),
-
- /* IPv4 --> GRE/NAT --> MAC --> IPv4 */
- I40E_PTT(59, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, FRG, NONE, PAY3),
- I40E_PTT(60, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, NONE, PAY3),
- I40E_PTT(61, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, UDP, PAY4),
- I40E_PTT_UNUSED_ENTRY(62),
- I40E_PTT(63, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, TCP, PAY4),
- I40E_PTT(64, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, SCTP, PAY4),
- I40E_PTT(65, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, ICMP, PAY4),
-
- /* IPv4 --> GRE/NAT -> MAC --> IPv6 */
- I40E_PTT(66, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, FRG, NONE, PAY3),
- I40E_PTT(67, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, NONE, PAY3),
- I40E_PTT(68, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, UDP, PAY4),
- I40E_PTT_UNUSED_ENTRY(69),
- I40E_PTT(70, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, TCP, PAY4),
- I40E_PTT(71, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, SCTP, PAY4),
- I40E_PTT(72, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, ICMP, PAY4),
-
- /* IPv4 --> GRE/NAT --> MAC/VLAN */
- I40E_PTT(73, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, NONE, NOF, NONE, PAY3),
-
- /* IPv4 ---> GRE/NAT -> MAC/VLAN --> IPv4 */
- I40E_PTT(74, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, FRG, NONE, PAY3),
- I40E_PTT(75, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, NONE, PAY3),
- I40E_PTT(76, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, UDP, PAY4),
- I40E_PTT_UNUSED_ENTRY(77),
- I40E_PTT(78, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, TCP, PAY4),
- I40E_PTT(79, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, SCTP, PAY4),
- I40E_PTT(80, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, ICMP, PAY4),
-
- /* IPv4 -> GRE/NAT -> MAC/VLAN --> IPv6 */
- I40E_PTT(81, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, FRG, NONE, PAY3),
- I40E_PTT(82, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, NONE, PAY3),
- I40E_PTT(83, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, UDP, PAY4),
- I40E_PTT_UNUSED_ENTRY(84),
- I40E_PTT(85, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, TCP, PAY4),
- I40E_PTT(86, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, SCTP, PAY4),
- I40E_PTT(87, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, ICMP, PAY4),
-
- /* Non Tunneled IPv6 */
- I40E_PTT(88, IP, IPV6, FRG, NONE, NONE, NOF, NONE, PAY3),
- I40E_PTT(89, IP, IPV6, NOF, NONE, NONE, NOF, NONE, PAY3),
- I40E_PTT(90, IP, IPV6, NOF, NONE, NONE, NOF, UDP, PAY3),
- I40E_PTT_UNUSED_ENTRY(91),
- I40E_PTT(92, IP, IPV6, NOF, NONE, NONE, NOF, TCP, PAY4),
- I40E_PTT(93, IP, IPV6, NOF, NONE, NONE, NOF, SCTP, PAY4),
- I40E_PTT(94, IP, IPV6, NOF, NONE, NONE, NOF, ICMP, PAY4),
-
- /* IPv6 --> IPv4 */
- I40E_PTT(95, IP, IPV6, NOF, IP_IP, IPV4, FRG, NONE, PAY3),
- I40E_PTT(96, IP, IPV6, NOF, IP_IP, IPV4, NOF, NONE, PAY3),
- I40E_PTT(97, IP, IPV6, NOF, IP_IP, IPV4, NOF, UDP, PAY4),
- I40E_PTT_UNUSED_ENTRY(98),
- I40E_PTT(99, IP, IPV6, NOF, IP_IP, IPV4, NOF, TCP, PAY4),
- I40E_PTT(100, IP, IPV6, NOF, IP_IP, IPV4, NOF, SCTP, PAY4),
- I40E_PTT(101, IP, IPV6, NOF, IP_IP, IPV4, NOF, ICMP, PAY4),
-
- /* IPv6 --> IPv6 */
- I40E_PTT(102, IP, IPV6, NOF, IP_IP, IPV6, FRG, NONE, PAY3),
- I40E_PTT(103, IP, IPV6, NOF, IP_IP, IPV6, NOF, NONE, PAY3),
- I40E_PTT(104, IP, IPV6, NOF, IP_IP, IPV6, NOF, UDP, PAY4),
- I40E_PTT_UNUSED_ENTRY(105),
- I40E_PTT(106, IP, IPV6, NOF, IP_IP, IPV6, NOF, TCP, PAY4),
- I40E_PTT(107, IP, IPV6, NOF, IP_IP, IPV6, NOF, SCTP, PAY4),
- I40E_PTT(108, IP, IPV6, NOF, IP_IP, IPV6, NOF, ICMP, PAY4),
-
- /* IPv6 --> GRE/NAT */
- I40E_PTT(109, IP, IPV6, NOF, IP_GRENAT, NONE, NOF, NONE, PAY3),
-
- /* IPv6 --> GRE/NAT -> IPv4 */
- I40E_PTT(110, IP, IPV6, NOF, IP_GRENAT, IPV4, FRG, NONE, PAY3),
- I40E_PTT(111, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, NONE, PAY3),
- I40E_PTT(112, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, UDP, PAY4),
- I40E_PTT_UNUSED_ENTRY(113),
- I40E_PTT(114, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, TCP, PAY4),
- I40E_PTT(115, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, SCTP, PAY4),
- I40E_PTT(116, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, ICMP, PAY4),
-
- /* IPv6 --> GRE/NAT -> IPv6 */
- I40E_PTT(117, IP, IPV6, NOF, IP_GRENAT, IPV6, FRG, NONE, PAY3),
- I40E_PTT(118, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, NONE, PAY3),
- I40E_PTT(119, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, UDP, PAY4),
- I40E_PTT_UNUSED_ENTRY(120),
- I40E_PTT(121, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, TCP, PAY4),
- I40E_PTT(122, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, SCTP, PAY4),
- I40E_PTT(123, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, ICMP, PAY4),
-
- /* IPv6 --> GRE/NAT -> MAC */
- I40E_PTT(124, IP, IPV6, NOF, IP_GRENAT_MAC, NONE, NOF, NONE, PAY3),
-
- /* IPv6 --> GRE/NAT -> MAC -> IPv4 */
- I40E_PTT(125, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, FRG, NONE, PAY3),
- I40E_PTT(126, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, NONE, PAY3),
- I40E_PTT(127, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, UDP, PAY4),
- I40E_PTT_UNUSED_ENTRY(128),
- I40E_PTT(129, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, TCP, PAY4),
- I40E_PTT(130, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, SCTP, PAY4),
- I40E_PTT(131, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, ICMP, PAY4),
-
- /* IPv6 --> GRE/NAT -> MAC -> IPv6 */
- I40E_PTT(132, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, FRG, NONE, PAY3),
- I40E_PTT(133, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, NONE, PAY3),
- I40E_PTT(134, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, UDP, PAY4),
- I40E_PTT_UNUSED_ENTRY(135),
- I40E_PTT(136, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, TCP, PAY4),
- I40E_PTT(137, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, SCTP, PAY4),
- I40E_PTT(138, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, ICMP, PAY4),
-
- /* IPv6 --> GRE/NAT -> MAC/VLAN */
- I40E_PTT(139, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, NONE, NOF, NONE, PAY3),
-
- /* IPv6 --> GRE/NAT -> MAC/VLAN --> IPv4 */
- I40E_PTT(140, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, FRG, NONE, PAY3),
- I40E_PTT(141, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, NONE, PAY3),
- I40E_PTT(142, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, UDP, PAY4),
- I40E_PTT_UNUSED_ENTRY(143),
- I40E_PTT(144, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, TCP, PAY4),
- I40E_PTT(145, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, SCTP, PAY4),
- I40E_PTT(146, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, ICMP, PAY4),
-
- /* IPv6 --> GRE/NAT -> MAC/VLAN --> IPv6 */
- I40E_PTT(147, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, FRG, NONE, PAY3),
- I40E_PTT(148, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, NONE, PAY3),
- I40E_PTT(149, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, UDP, PAY4),
- I40E_PTT_UNUSED_ENTRY(150),
- I40E_PTT(151, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, TCP, PAY4),
- I40E_PTT(152, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, SCTP, PAY4),
- 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)
-};
-
-/**
- * i40evf_aq_rx_ctl_read_register - use FW to read from an Rx control register
- * @hw: pointer to the hw struct
- * @reg_addr: register address
- * @reg_val: ptr to register value
- * @cmd_details: pointer to command details structure or NULL
- *
- * Use the firmware to read the Rx control register,
- * especially useful if the Rx unit is under heavy pressure
- **/
-i40e_status i40evf_aq_rx_ctl_read_register(struct i40e_hw *hw,
- u32 reg_addr, u32 *reg_val,
- struct i40e_asq_cmd_details *cmd_details)
-{
- struct i40e_aq_desc desc;
- struct i40e_aqc_rx_ctl_reg_read_write *cmd_resp =
- (struct i40e_aqc_rx_ctl_reg_read_write *)&desc.params.raw;
- i40e_status status;
-
- if (!reg_val)
- return I40E_ERR_PARAM;
-
- i40evf_fill_default_direct_cmd_desc(&desc,
- i40e_aqc_opc_rx_ctl_reg_read);
-
- cmd_resp->address = cpu_to_le32(reg_addr);
-
- status = i40evf_asq_send_command(hw, &desc, NULL, 0, cmd_details);
-
- if (status == 0)
- *reg_val = le32_to_cpu(cmd_resp->value);
-
- return status;
-}
-
-/**
- * i40evf_read_rx_ctl - read from an Rx control register
- * @hw: pointer to the hw struct
- * @reg_addr: register address
- **/
-u32 i40evf_read_rx_ctl(struct i40e_hw *hw, u32 reg_addr)
-{
- i40e_status status = 0;
- bool use_register;
- int retry = 5;
- u32 val = 0;
-
- use_register = (((hw->aq.api_maj_ver == 1) &&
- (hw->aq.api_min_ver < 5)) ||
- (hw->mac.type == I40E_MAC_X722));
- if (!use_register) {
-do_retry:
- status = i40evf_aq_rx_ctl_read_register(hw, reg_addr,
- &val, NULL);
- if (hw->aq.asq_last_status == I40E_AQ_RC_EAGAIN && retry) {
- usleep_range(1000, 2000);
- retry--;
- goto do_retry;
- }
- }
-
- /* if the AQ access failed, try the old-fashioned way */
- if (status || use_register)
- val = rd32(hw, reg_addr);
-
- return val;
-}
-
-/**
- * i40evf_aq_rx_ctl_write_register
- * @hw: pointer to the hw struct
- * @reg_addr: register address
- * @reg_val: register value
- * @cmd_details: pointer to command details structure or NULL
- *
- * Use the firmware to write to an Rx control register,
- * especially useful if the Rx unit is under heavy pressure
- **/
-i40e_status i40evf_aq_rx_ctl_write_register(struct i40e_hw *hw,
- u32 reg_addr, u32 reg_val,
- struct i40e_asq_cmd_details *cmd_details)
-{
- struct i40e_aq_desc desc;
- struct i40e_aqc_rx_ctl_reg_read_write *cmd =
- (struct i40e_aqc_rx_ctl_reg_read_write *)&desc.params.raw;
- i40e_status status;
-
- i40evf_fill_default_direct_cmd_desc(&desc,
- i40e_aqc_opc_rx_ctl_reg_write);
-
- cmd->address = cpu_to_le32(reg_addr);
- cmd->value = cpu_to_le32(reg_val);
-
- status = i40evf_asq_send_command(hw, &desc, NULL, 0, cmd_details);
-
- return status;
-}
-
-/**
- * i40evf_write_rx_ctl - write to an Rx control register
- * @hw: pointer to the hw struct
- * @reg_addr: register address
- * @reg_val: register value
- **/
-void i40evf_write_rx_ctl(struct i40e_hw *hw, u32 reg_addr, u32 reg_val)
-{
- i40e_status status = 0;
- bool use_register;
- int retry = 5;
-
- use_register = (((hw->aq.api_maj_ver == 1) &&
- (hw->aq.api_min_ver < 5)) ||
- (hw->mac.type == I40E_MAC_X722));
- if (!use_register) {
-do_retry:
- status = i40evf_aq_rx_ctl_write_register(hw, reg_addr,
- reg_val, NULL);
- if (hw->aq.asq_last_status == I40E_AQ_RC_EAGAIN && retry) {
- usleep_range(1000, 2000);
- retry--;
- goto do_retry;
- }
- }
-
- /* if the AQ access failed, try the old-fashioned way */
- if (status || use_register)
- wr32(hw, reg_addr, reg_val);
-}
-
-/**
- * i40e_aq_send_msg_to_pf
- * @hw: pointer to the hardware structure
- * @v_opcode: opcodes for VF-PF communication
- * @v_retval: return error code
- * @msg: pointer to the msg buffer
- * @msglen: msg length
- * @cmd_details: pointer to command details
- *
- * Send message to PF driver using admin queue. By default, this message
- * is sent asynchronously, i.e. i40evf_asq_send_command() does not wait for
- * completion before returning.
- **/
-i40e_status i40e_aq_send_msg_to_pf(struct i40e_hw *hw,
- enum virtchnl_ops v_opcode,
- i40e_status v_retval,
- u8 *msg, u16 msglen,
- struct i40e_asq_cmd_details *cmd_details)
-{
- struct i40e_aq_desc desc;
- struct i40e_asq_cmd_details details;
- i40e_status status;
-
- i40evf_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_send_msg_to_pf);
- desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_SI);
- desc.cookie_high = cpu_to_le32(v_opcode);
- desc.cookie_low = cpu_to_le32(v_retval);
- if (msglen) {
- desc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF
- | I40E_AQ_FLAG_RD));
- if (msglen > I40E_AQ_LARGE_BUF)
- desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB);
- desc.datalen = cpu_to_le16(msglen);
- }
- if (!cmd_details) {
- memset(&details, 0, sizeof(details));
- details.async = true;
- cmd_details = &details;
- }
- status = i40evf_asq_send_command(hw, &desc, msg, msglen, cmd_details);
- return status;
-}
-
-/**
- * i40e_vf_parse_hw_config
- * @hw: pointer to the hardware structure
- * @msg: pointer to the virtual channel VF resource structure
- *
- * Given a VF resource message from the PF, populate the hw struct
- * with appropriate information.
- **/
-void i40e_vf_parse_hw_config(struct i40e_hw *hw,
- struct virtchnl_vf_resource *msg)
-{
- struct virtchnl_vsi_resource *vsi_res;
- int i;
-
- vsi_res = &msg->vsi_res[0];
-
- hw->dev_caps.num_vsis = msg->num_vsis;
- hw->dev_caps.num_rx_qp = msg->num_queue_pairs;
- hw->dev_caps.num_tx_qp = msg->num_queue_pairs;
- hw->dev_caps.num_msix_vectors_vf = msg->max_vectors;
- hw->dev_caps.dcb = msg->vf_cap_flags &
- VIRTCHNL_VF_OFFLOAD_L2;
- hw->dev_caps.fcoe = 0;
- for (i = 0; i < msg->num_vsis; i++) {
- if (vsi_res->vsi_type == VIRTCHNL_VSI_SRIOV) {
- ether_addr_copy(hw->mac.perm_addr,
- vsi_res->default_mac_addr);
- ether_addr_copy(hw->mac.addr,
- vsi_res->default_mac_addr);
- }
- vsi_res++;
- }
-}
-
-/**
- * i40e_vf_reset
- * @hw: pointer to the hardware structure
- *
- * Send a VF_RESET message to the PF. Does not wait for response from PF
- * as none will be forthcoming. Immediately after calling this function,
- * the admin queue should be shut down and (optionally) reinitialized.
- **/
-i40e_status i40e_vf_reset(struct i40e_hw *hw)
-{
- return i40e_aq_send_msg_to_pf(hw, VIRTCHNL_OP_RESET_VF,
- 0, NULL, 0, NULL);
-}
-
-/**
- * i40evf_aq_write_ddp - Write dynamic device personalization (ddp)
- * @hw: pointer to the hw struct
- * @buff: command buffer (size in bytes = buff_size)
- * @buff_size: buffer size in bytes
- * @track_id: package tracking id
- * @error_offset: returns error offset
- * @error_info: returns error information
- * @cmd_details: pointer to command details structure or NULL
- **/
-enum
-i40e_status_code i40evf_aq_write_ddp(struct i40e_hw *hw, void *buff,
- u16 buff_size, u32 track_id,
- u32 *error_offset, u32 *error_info,
- struct i40e_asq_cmd_details *cmd_details)
-{
- struct i40e_aq_desc desc;
- struct i40e_aqc_write_personalization_profile *cmd =
- (struct i40e_aqc_write_personalization_profile *)
- &desc.params.raw;
- struct i40e_aqc_write_ddp_resp *resp;
- i40e_status status;
-
- i40evf_fill_default_direct_cmd_desc(&desc,
- i40e_aqc_opc_write_personalization_profile);
-
- desc.flags |= cpu_to_le16(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD);
- if (buff_size > I40E_AQ_LARGE_BUF)
- desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB);
-
- desc.datalen = cpu_to_le16(buff_size);
-
- cmd->profile_track_id = cpu_to_le32(track_id);
-
- status = i40evf_asq_send_command(hw, &desc, buff, buff_size, cmd_details);
- if (!status) {
- resp = (struct i40e_aqc_write_ddp_resp *)&desc.params.raw;
- if (error_offset)
- *error_offset = le32_to_cpu(resp->error_offset);
- if (error_info)
- *error_info = le32_to_cpu(resp->error_info);
- }
-
- return status;
-}
-
-/**
- * i40evf_aq_get_ddp_list - Read dynamic device personalization (ddp)
- * @hw: pointer to the hw struct
- * @buff: command buffer (size in bytes = buff_size)
- * @buff_size: buffer size in bytes
- * @flags: AdminQ command flags
- * @cmd_details: pointer to command details structure or NULL
- **/
-enum
-i40e_status_code i40evf_aq_get_ddp_list(struct i40e_hw *hw, void *buff,
- u16 buff_size, u8 flags,
- struct i40e_asq_cmd_details *cmd_details)
-{
- struct i40e_aq_desc desc;
- struct i40e_aqc_get_applied_profiles *cmd =
- (struct i40e_aqc_get_applied_profiles *)&desc.params.raw;
- i40e_status status;
-
- i40evf_fill_default_direct_cmd_desc(&desc,
- i40e_aqc_opc_get_personalization_profile_list);
-
- desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_BUF);
- if (buff_size > I40E_AQ_LARGE_BUF)
- desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB);
- desc.datalen = cpu_to_le16(buff_size);
-
- cmd->flags = flags;
-
- status = i40evf_asq_send_command(hw, &desc, buff, buff_size, cmd_details);
-
- return status;
-}
-
-/**
- * i40evf_find_segment_in_package
- * @segment_type: the segment type to search for (i.e., SEGMENT_TYPE_I40E)
- * @pkg_hdr: pointer to the package header to be searched
- *
- * This function searches a package file for a particular segment type. On
- * success it returns a pointer to the segment header, otherwise it will
- * return NULL.
- **/
-struct i40e_generic_seg_header *
-i40evf_find_segment_in_package(u32 segment_type,
- struct i40e_package_header *pkg_hdr)
-{
- struct i40e_generic_seg_header *segment;
- u32 i;
-
- /* Search all package segments for the requested segment type */
- for (i = 0; i < pkg_hdr->segment_count; i++) {
- segment =
- (struct i40e_generic_seg_header *)((u8 *)pkg_hdr +
- pkg_hdr->segment_offset[i]);
-
- if (segment->type == segment_type)
- return segment;
- }
-
- return NULL;
-}
-
-/**
- * i40evf_write_profile
- * @hw: pointer to the hardware structure
- * @profile: pointer to the profile segment of the package to be downloaded
- * @track_id: package tracking id
- *
- * Handles the download of a complete package.
- */
-enum i40e_status_code
-i40evf_write_profile(struct i40e_hw *hw, struct i40e_profile_segment *profile,
- u32 track_id)
-{
- i40e_status status = 0;
- struct i40e_section_table *sec_tbl;
- struct i40e_profile_section_header *sec = NULL;
- u32 dev_cnt;
- u32 vendor_dev_id;
- u32 *nvm;
- u32 section_size = 0;
- u32 offset = 0, info = 0;
- u32 i;
-
- dev_cnt = profile->device_table_count;
-
- for (i = 0; i < dev_cnt; i++) {
- vendor_dev_id = profile->device_table[i].vendor_dev_id;
- if ((vendor_dev_id >> 16) == PCI_VENDOR_ID_INTEL)
- if (hw->device_id == (vendor_dev_id & 0xFFFF))
- break;
- }
- if (i == dev_cnt) {
- i40e_debug(hw, I40E_DEBUG_PACKAGE, "Device doesn't support DDP");
- return I40E_ERR_DEVICE_NOT_SUPPORTED;
- }
-
- nvm = (u32 *)&profile->device_table[dev_cnt];
- sec_tbl = (struct i40e_section_table *)&nvm[nvm[0] + 1];
-
- for (i = 0; i < sec_tbl->section_count; i++) {
- sec = (struct i40e_profile_section_header *)((u8 *)profile +
- sec_tbl->section_offset[i]);
-
- /* Skip 'AQ', 'note' and 'name' sections */
- if (sec->section.type != SECTION_TYPE_MMIO)
- continue;
-
- section_size = sec->section.size +
- sizeof(struct i40e_profile_section_header);
-
- /* Write profile */
- status = i40evf_aq_write_ddp(hw, (void *)sec, (u16)section_size,
- track_id, &offset, &info, NULL);
- if (status) {
- i40e_debug(hw, I40E_DEBUG_PACKAGE,
- "Failed to write profile: offset %d, info %d",
- offset, info);
- break;
- }
- }
- return status;
-}
-
-/**
- * i40evf_add_pinfo_to_list
- * @hw: pointer to the hardware structure
- * @profile: pointer to the profile segment of the package
- * @profile_info_sec: buffer for information section
- * @track_id: package tracking id
- *
- * Register a profile to the list of loaded profiles.
- */
-enum i40e_status_code
-i40evf_add_pinfo_to_list(struct i40e_hw *hw,
- struct i40e_profile_segment *profile,
- u8 *profile_info_sec, u32 track_id)
-{
- i40e_status status = 0;
- struct i40e_profile_section_header *sec = NULL;
- struct i40e_profile_info *pinfo;
- u32 offset = 0, info = 0;
-
- sec = (struct i40e_profile_section_header *)profile_info_sec;
- sec->tbl_size = 1;
- sec->data_end = sizeof(struct i40e_profile_section_header) +
- sizeof(struct i40e_profile_info);
- sec->section.type = SECTION_TYPE_INFO;
- sec->section.offset = sizeof(struct i40e_profile_section_header);
- sec->section.size = sizeof(struct i40e_profile_info);
- pinfo = (struct i40e_profile_info *)(profile_info_sec +
- sec->section.offset);
- pinfo->track_id = track_id;
- pinfo->version = profile->version;
- pinfo->op = I40E_DDP_ADD_TRACKID;
- memcpy(pinfo->name, profile->name, I40E_DDP_NAME_SIZE);
-
- status = i40evf_aq_write_ddp(hw, (void *)sec, sec->data_end,
- track_id, &offset, &info, NULL);
- return status;
-}
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_devids.h b/drivers/net/ethernet/intel/i40evf/i40e_devids.h
deleted file mode 100644
index f300bf271824..000000000000
--- a/drivers/net/ethernet/intel/i40evf/i40e_devids.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/* Copyright(c) 2013 - 2018 Intel Corporation. */
-
-#ifndef _I40E_DEVIDS_H_
-#define _I40E_DEVIDS_H_
-
-/* Device IDs */
-#define I40E_DEV_ID_SFP_XL710 0x1572
-#define I40E_DEV_ID_QEMU 0x1574
-#define I40E_DEV_ID_KX_B 0x1580
-#define I40E_DEV_ID_KX_C 0x1581
-#define I40E_DEV_ID_QSFP_A 0x1583
-#define I40E_DEV_ID_QSFP_B 0x1584
-#define I40E_DEV_ID_QSFP_C 0x1585
-#define I40E_DEV_ID_10G_BASE_T 0x1586
-#define I40E_DEV_ID_20G_KR2 0x1587
-#define I40E_DEV_ID_20G_KR2_A 0x1588
-#define I40E_DEV_ID_10G_BASE_T4 0x1589
-#define I40E_DEV_ID_25G_B 0x158A
-#define I40E_DEV_ID_25G_SFP28 0x158B
-#define I40E_DEV_ID_VF 0x154C
-#define I40E_DEV_ID_VF_HV 0x1571
-#define I40E_DEV_ID_ADAPTIVE_VF 0x1889
-#define I40E_DEV_ID_SFP_X722 0x37D0
-#define I40E_DEV_ID_1G_BASE_T_X722 0x37D1
-#define I40E_DEV_ID_10G_BASE_T_X722 0x37D2
-#define I40E_DEV_ID_SFP_I_X722 0x37D3
-#define I40E_DEV_ID_X722_VF 0x37CD
-
-#define i40e_is_40G_device(d) ((d) == I40E_DEV_ID_QSFP_A || \
- (d) == I40E_DEV_ID_QSFP_B || \
- (d) == I40E_DEV_ID_QSFP_C)
-
-#endif /* _I40E_DEVIDS_H_ */
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_hmc.h b/drivers/net/ethernet/intel/i40evf/i40e_hmc.h
deleted file mode 100644
index 1c78de838857..000000000000
--- a/drivers/net/ethernet/intel/i40evf/i40e_hmc.h
+++ /dev/null
@@ -1,215 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/* Copyright(c) 2013 - 2018 Intel Corporation. */
-
-#ifndef _I40E_HMC_H_
-#define _I40E_HMC_H_
-
-#define I40E_HMC_MAX_BP_COUNT 512
-
-/* forward-declare the HW struct for the compiler */
-struct i40e_hw;
-
-#define I40E_HMC_INFO_SIGNATURE 0x484D5347 /* HMSG */
-#define I40E_HMC_PD_CNT_IN_SD 512
-#define I40E_HMC_DIRECT_BP_SIZE 0x200000 /* 2M */
-#define I40E_HMC_PAGED_BP_SIZE 4096
-#define I40E_HMC_PD_BP_BUF_ALIGNMENT 4096
-#define I40E_FIRST_VF_FPM_ID 16
-
-struct i40e_hmc_obj_info {
- u64 base; /* base addr in FPM */
- u32 max_cnt; /* max count available for this hmc func */
- u32 cnt; /* count of objects driver actually wants to create */
- u64 size; /* size in bytes of one object */
-};
-
-enum i40e_sd_entry_type {
- I40E_SD_TYPE_INVALID = 0,
- I40E_SD_TYPE_PAGED = 1,
- I40E_SD_TYPE_DIRECT = 2
-};
-
-struct i40e_hmc_bp {
- enum i40e_sd_entry_type entry_type;
- struct i40e_dma_mem addr; /* populate to be used by hw */
- u32 sd_pd_index;
- u32 ref_cnt;
-};
-
-struct i40e_hmc_pd_entry {
- struct i40e_hmc_bp bp;
- u32 sd_index;
- bool rsrc_pg;
- bool valid;
-};
-
-struct i40e_hmc_pd_table {
- struct i40e_dma_mem pd_page_addr; /* populate to be used by hw */
- struct i40e_hmc_pd_entry *pd_entry; /* [512] for sw book keeping */
- struct i40e_virt_mem pd_entry_virt_mem; /* virt mem for pd_entry */
-
- u32 ref_cnt;
- u32 sd_index;
-};
-
-struct i40e_hmc_sd_entry {
- enum i40e_sd_entry_type entry_type;
- bool valid;
-
- union {
- struct i40e_hmc_pd_table pd_table;
- struct i40e_hmc_bp bp;
- } u;
-};
-
-struct i40e_hmc_sd_table {
- struct i40e_virt_mem addr; /* used to track sd_entry allocations */
- u32 sd_cnt;
- u32 ref_cnt;
- struct i40e_hmc_sd_entry *sd_entry; /* (sd_cnt*512) entries max */
-};
-
-struct i40e_hmc_info {
- u32 signature;
- /* equals to pci func num for PF and dynamically allocated for VFs */
- u8 hmc_fn_id;
- u16 first_sd_index; /* index of the first available SD */
-
- /* hmc objects */
- struct i40e_hmc_obj_info *hmc_obj;
- struct i40e_virt_mem hmc_obj_virt_mem;
- struct i40e_hmc_sd_table sd_table;
-};
-
-#define I40E_INC_SD_REFCNT(sd_table) ((sd_table)->ref_cnt++)
-#define I40E_INC_PD_REFCNT(pd_table) ((pd_table)->ref_cnt++)
-#define I40E_INC_BP_REFCNT(bp) ((bp)->ref_cnt++)
-
-#define I40E_DEC_SD_REFCNT(sd_table) ((sd_table)->ref_cnt--)
-#define I40E_DEC_PD_REFCNT(pd_table) ((pd_table)->ref_cnt--)
-#define I40E_DEC_BP_REFCNT(bp) ((bp)->ref_cnt--)
-
-/**
- * I40E_SET_PF_SD_ENTRY - marks the sd entry as valid in the hardware
- * @hw: pointer to our hw struct
- * @pa: pointer to physical address
- * @sd_index: segment descriptor index
- * @type: if sd entry is direct or paged
- **/
-#define I40E_SET_PF_SD_ENTRY(hw, pa, sd_index, type) \
-{ \
- u32 val1, val2, val3; \
- val1 = (u32)(upper_32_bits(pa)); \
- val2 = (u32)(pa) | (I40E_HMC_MAX_BP_COUNT << \
- I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT) | \
- ((((type) == I40E_SD_TYPE_PAGED) ? 0 : 1) << \
- I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT) | \
- BIT(I40E_PFHMC_SDDATALOW_PMSDVALID_SHIFT); \
- val3 = (sd_index) | BIT_ULL(I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \
- wr32((hw), I40E_PFHMC_SDDATAHIGH, val1); \
- wr32((hw), I40E_PFHMC_SDDATALOW, val2); \
- wr32((hw), I40E_PFHMC_SDCMD, val3); \
-}
-
-/**
- * I40E_CLEAR_PF_SD_ENTRY - marks the sd entry as invalid in the hardware
- * @hw: pointer to our hw struct
- * @sd_index: segment descriptor index
- * @type: if sd entry is direct or paged
- **/
-#define I40E_CLEAR_PF_SD_ENTRY(hw, sd_index, type) \
-{ \
- u32 val2, val3; \
- val2 = (I40E_HMC_MAX_BP_COUNT << \
- I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT) | \
- ((((type) == I40E_SD_TYPE_PAGED) ? 0 : 1) << \
- I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT); \
- val3 = (sd_index) | BIT_ULL(I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \
- wr32((hw), I40E_PFHMC_SDDATAHIGH, 0); \
- wr32((hw), I40E_PFHMC_SDDATALOW, val2); \
- wr32((hw), I40E_PFHMC_SDCMD, val3); \
-}
-
-/**
- * I40E_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 I40E_INVALIDATE_PF_HMC_PD(hw, sd_idx, pd_idx) \
- wr32((hw), I40E_PFHMC_PDINV, \
- (((sd_idx) << I40E_PFHMC_PDINV_PMSDIDX_SHIFT) | \
- ((pd_idx) << I40E_PFHMC_PDINV_PMPDIDX_SHIFT)))
-
-/**
- * I40E_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
- * @index: 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 i40e_hmc_rsrc_type.
- **/
-#define I40E_FIND_SD_INDEX_LIMIT(hmc_info, type, index, cnt, sd_idx, sd_limit)\
-{ \
- u64 fpm_addr, fpm_limit; \
- fpm_addr = (hmc_info)->hmc_obj[(type)].base + \
- (hmc_info)->hmc_obj[(type)].size * (index); \
- fpm_limit = fpm_addr + (hmc_info)->hmc_obj[(type)].size * (cnt);\
- *(sd_idx) = (u32)(fpm_addr / I40E_HMC_DIRECT_BP_SIZE); \
- *(sd_limit) = (u32)((fpm_limit - 1) / I40E_HMC_DIRECT_BP_SIZE); \
- /* add one more to the limit to correct our range */ \
- *(sd_limit) += 1; \
-}
-
-/**
- * I40E_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_index: 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 i40e_hmc_rsrc_type.
- **/
-#define I40E_FIND_PD_INDEX_LIMIT(hmc_info, type, idx, cnt, pd_index, 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_index) = (u32)(fpm_adr / I40E_HMC_PAGED_BP_SIZE); \
- *(pd_limit) = (u32)((fpm_limit - 1) / I40E_HMC_PAGED_BP_SIZE); \
- /* add one more to the limit to correct our range */ \
- *(pd_limit) += 1; \
-}
-i40e_status i40e_add_sd_table_entry(struct i40e_hw *hw,
- struct i40e_hmc_info *hmc_info,
- u32 sd_index,
- enum i40e_sd_entry_type type,
- u64 direct_mode_sz);
-
-i40e_status i40e_add_pd_table_entry(struct i40e_hw *hw,
- struct i40e_hmc_info *hmc_info,
- u32 pd_index,
- struct i40e_dma_mem *rsrc_pg);
-i40e_status i40e_remove_pd_bp(struct i40e_hw *hw,
- struct i40e_hmc_info *hmc_info,
- u32 idx);
-i40e_status i40e_prep_remove_sd_bp(struct i40e_hmc_info *hmc_info,
- u32 idx);
-i40e_status i40e_remove_sd_bp_new(struct i40e_hw *hw,
- struct i40e_hmc_info *hmc_info,
- u32 idx, bool is_pf);
-i40e_status i40e_prep_remove_pd_page(struct i40e_hmc_info *hmc_info,
- u32 idx);
-i40e_status i40e_remove_pd_page_new(struct i40e_hw *hw,
- struct i40e_hmc_info *hmc_info,
- u32 idx, bool is_pf);
-
-#endif /* _I40E_HMC_H_ */
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_lan_hmc.h b/drivers/net/ethernet/intel/i40evf/i40e_lan_hmc.h
deleted file mode 100644
index 82b00f70a632..000000000000
--- a/drivers/net/ethernet/intel/i40evf/i40e_lan_hmc.h
+++ /dev/null
@@ -1,158 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/* Copyright(c) 2013 - 2018 Intel Corporation. */
-
-#ifndef _I40E_LAN_HMC_H_
-#define _I40E_LAN_HMC_H_
-
-/* forward-declare the HW struct for the compiler */
-struct i40e_hw;
-
-/* HMC element context information */
-
-/* Rx queue context data
- *
- * The sizes of the variables may be larger than needed due to crossing byte
- * boundaries. If we do not have the width of the variable set to the correct
- * size then we could end up shifting bits off the top of the variable when the
- * variable is at the top of a byte and crosses over into the next byte.
- */
-struct i40e_hmc_obj_rxq {
- u16 head;
- u16 cpuid; /* bigger than needed, see above for reason */
- u64 base;
- u16 qlen;
-#define I40E_RXQ_CTX_DBUFF_SHIFT 7
- u16 dbuff; /* bigger than needed, see above for reason */
-#define I40E_RXQ_CTX_HBUFF_SHIFT 6
- u16 hbuff; /* bigger than needed, see above for reason */
- u8 dtype;
- u8 dsize;
- u8 crcstrip;
- u8 fc_ena;
- u8 l2tsel;
- u8 hsplit_0;
- u8 hsplit_1;
- u8 showiv;
- u32 rxmax; /* bigger than needed, see above for reason */
- u8 tphrdesc_ena;
- u8 tphwdesc_ena;
- u8 tphdata_ena;
- u8 tphhead_ena;
- u16 lrxqthresh; /* bigger than needed, see above for reason */
- u8 prefena; /* NOTE: normally must be set to 1 at init */
-};
-
-/* Tx queue context data
-*
-* The sizes of the variables may be larger than needed due to crossing byte
-* boundaries. If we do not have the width of the variable set to the correct
-* size then we could end up shifting bits off the top of the variable when the
-* variable is at the top of a byte and crosses over into the next byte.
-*/
-struct i40e_hmc_obj_txq {
- u16 head;
- u8 new_context;
- u64 base;
- u8 fc_ena;
- u8 timesync_ena;
- u8 fd_ena;
- u8 alt_vlan_ena;
- u16 thead_wb;
- u8 cpuid;
- u8 head_wb_ena;
- u16 qlen;
- u8 tphrdesc_ena;
- u8 tphrpacket_ena;
- u8 tphwdesc_ena;
- u64 head_wb_addr;
- u32 crc;
- u16 rdylist;
- u8 rdylist_act;
-};
-
-/* for hsplit_0 field of Rx HMC context */
-enum i40e_hmc_obj_rx_hsplit_0 {
- I40E_HMC_OBJ_RX_HSPLIT_0_NO_SPLIT = 0,
- I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_L2 = 1,
- I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_IP = 2,
- I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_TCP_UDP = 4,
- I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_SCTP = 8,
-};
-
-/* fcoe_cntx and fcoe_filt are for debugging purpose only */
-struct i40e_hmc_obj_fcoe_cntx {
- u32 rsv[32];
-};
-
-struct i40e_hmc_obj_fcoe_filt {
- u32 rsv[8];
-};
-
-/* Context sizes for LAN objects */
-enum i40e_hmc_lan_object_size {
- I40E_HMC_LAN_OBJ_SZ_8 = 0x3,
- I40E_HMC_LAN_OBJ_SZ_16 = 0x4,
- I40E_HMC_LAN_OBJ_SZ_32 = 0x5,
- I40E_HMC_LAN_OBJ_SZ_64 = 0x6,
- I40E_HMC_LAN_OBJ_SZ_128 = 0x7,
- I40E_HMC_LAN_OBJ_SZ_256 = 0x8,
- I40E_HMC_LAN_OBJ_SZ_512 = 0x9,
-};
-
-#define I40E_HMC_L2OBJ_BASE_ALIGNMENT 512
-#define I40E_HMC_OBJ_SIZE_TXQ 128
-#define I40E_HMC_OBJ_SIZE_RXQ 32
-#define I40E_HMC_OBJ_SIZE_FCOE_CNTX 128
-#define I40E_HMC_OBJ_SIZE_FCOE_FILT 64
-
-enum i40e_hmc_lan_rsrc_type {
- I40E_HMC_LAN_FULL = 0,
- I40E_HMC_LAN_TX = 1,
- I40E_HMC_LAN_RX = 2,
- I40E_HMC_FCOE_CTX = 3,
- I40E_HMC_FCOE_FILT = 4,
- I40E_HMC_LAN_MAX = 5
-};
-
-enum i40e_hmc_model {
- I40E_HMC_MODEL_DIRECT_PREFERRED = 0,
- I40E_HMC_MODEL_DIRECT_ONLY = 1,
- I40E_HMC_MODEL_PAGED_ONLY = 2,
- I40E_HMC_MODEL_UNKNOWN,
-};
-
-struct i40e_hmc_lan_create_obj_info {
- struct i40e_hmc_info *hmc_info;
- u32 rsrc_type;
- u32 start_idx;
- u32 count;
- enum i40e_sd_entry_type entry_type;
- u64 direct_mode_sz;
-};
-
-struct i40e_hmc_lan_delete_obj_info {
- struct i40e_hmc_info *hmc_info;
- u32 rsrc_type;
- u32 start_idx;
- u32 count;
-};
-
-i40e_status i40e_init_lan_hmc(struct i40e_hw *hw, u32 txq_num,
- u32 rxq_num, u32 fcoe_cntx_num,
- u32 fcoe_filt_num);
-i40e_status i40e_configure_lan_hmc(struct i40e_hw *hw,
- enum i40e_hmc_model model);
-i40e_status i40e_shutdown_lan_hmc(struct i40e_hw *hw);
-
-i40e_status i40e_clear_lan_tx_queue_context(struct i40e_hw *hw,
- u16 queue);
-i40e_status i40e_set_lan_tx_queue_context(struct i40e_hw *hw,
- u16 queue,
- struct i40e_hmc_obj_txq *s);
-i40e_status i40e_clear_lan_rx_queue_context(struct i40e_hw *hw,
- u16 queue);
-i40e_status i40e_set_lan_rx_queue_context(struct i40e_hw *hw,
- u16 queue,
- struct i40e_hmc_obj_rxq *s);
-
-#endif /* _I40E_LAN_HMC_H_ */
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_prototype.h b/drivers/net/ethernet/intel/i40evf/i40e_prototype.h
deleted file mode 100644
index a358f4b9d5aa..000000000000
--- a/drivers/net/ethernet/intel/i40evf/i40e_prototype.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/* Copyright(c) 2013 - 2018 Intel Corporation. */
-
-#ifndef _I40E_PROTOTYPE_H_
-#define _I40E_PROTOTYPE_H_
-
-#include "i40e_type.h"
-#include "i40e_alloc.h"
-#include <linux/avf/virtchnl.h>
-
-/* Prototypes for shared code functions that are not in
- * the standard function pointer structures. These are
- * mostly because they are needed even before the init
- * has happened and will assist in the early SW and FW
- * setup.
- */
-
-/* adminq functions */
-i40e_status i40evf_init_adminq(struct i40e_hw *hw);
-i40e_status i40evf_shutdown_adminq(struct i40e_hw *hw);
-void i40e_adminq_init_ring_data(struct i40e_hw *hw);
-i40e_status i40evf_clean_arq_element(struct i40e_hw *hw,
- struct i40e_arq_event_info *e,
- u16 *events_pending);
-i40e_status i40evf_asq_send_command(struct i40e_hw *hw,
- struct i40e_aq_desc *desc,
- void *buff, /* can be NULL */
- u16 buff_size,
- struct i40e_asq_cmd_details *cmd_details);
-bool i40evf_asq_done(struct i40e_hw *hw);
-
-/* debug function for adminq */
-void i40evf_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask,
- void *desc, void *buffer, u16 buf_len);
-
-void i40e_idle_aq(struct i40e_hw *hw);
-void i40evf_resume_aq(struct i40e_hw *hw);
-bool i40evf_check_asq_alive(struct i40e_hw *hw);
-i40e_status i40evf_aq_queue_shutdown(struct i40e_hw *hw, bool unloading);
-const char *i40evf_aq_str(struct i40e_hw *hw, enum i40e_admin_queue_err aq_err);
-const char *i40evf_stat_str(struct i40e_hw *hw, i40e_status stat_err);
-
-i40e_status i40evf_aq_get_rss_lut(struct i40e_hw *hw, u16 seid,
- bool pf_lut, u8 *lut, u16 lut_size);
-i40e_status i40evf_aq_set_rss_lut(struct i40e_hw *hw, u16 seid,
- bool pf_lut, u8 *lut, u16 lut_size);
-i40e_status i40evf_aq_get_rss_key(struct i40e_hw *hw,
- u16 seid,
- struct i40e_aqc_get_set_rss_key_data *key);
-i40e_status i40evf_aq_set_rss_key(struct i40e_hw *hw,
- u16 seid,
- struct i40e_aqc_get_set_rss_key_data *key);
-
-i40e_status i40e_set_mac_type(struct i40e_hw *hw);
-
-extern struct i40e_rx_ptype_decoded i40evf_ptype_lookup[];
-
-static inline struct i40e_rx_ptype_decoded decode_rx_desc_ptype(u8 ptype)
-{
- return i40evf_ptype_lookup[ptype];
-}
-
-/* prototype for functions used for SW locks */
-
-/* i40e_common for VF drivers*/
-void i40e_vf_parse_hw_config(struct i40e_hw *hw,
- struct virtchnl_vf_resource *msg);
-i40e_status i40e_vf_reset(struct i40e_hw *hw);
-i40e_status i40e_aq_send_msg_to_pf(struct i40e_hw *hw,
- enum virtchnl_ops v_opcode,
- i40e_status v_retval,
- u8 *msg, u16 msglen,
- struct i40e_asq_cmd_details *cmd_details);
-i40e_status i40e_set_filter_control(struct i40e_hw *hw,
- struct i40e_filter_control_settings *settings);
-i40e_status i40e_aq_add_rem_control_packet_filter(struct i40e_hw *hw,
- u8 *mac_addr, u16 ethtype, u16 flags,
- u16 vsi_seid, u16 queue, bool is_add,
- struct i40e_control_filter_stats *stats,
- struct i40e_asq_cmd_details *cmd_details);
-void i40e_add_filter_to_drop_tx_flow_control_frames(struct i40e_hw *hw,
- u16 vsi_seid);
-i40e_status i40evf_aq_rx_ctl_read_register(struct i40e_hw *hw,
- u32 reg_addr, u32 *reg_val,
- struct i40e_asq_cmd_details *cmd_details);
-u32 i40evf_read_rx_ctl(struct i40e_hw *hw, u32 reg_addr);
-i40e_status i40evf_aq_rx_ctl_write_register(struct i40e_hw *hw,
- u32 reg_addr, u32 reg_val,
- struct i40e_asq_cmd_details *cmd_details);
-void i40evf_write_rx_ctl(struct i40e_hw *hw, u32 reg_addr, u32 reg_val);
-i40e_status i40e_aq_set_phy_register(struct i40e_hw *hw,
- u8 phy_select, u8 dev_addr,
- u32 reg_addr, u32 reg_val,
- struct i40e_asq_cmd_details *cmd_details);
-i40e_status i40e_aq_get_phy_register(struct i40e_hw *hw,
- u8 phy_select, u8 dev_addr,
- u32 reg_addr, u32 *reg_val,
- struct i40e_asq_cmd_details *cmd_details);
-
-i40e_status i40e_read_phy_register(struct i40e_hw *hw, u8 page,
- u16 reg, u8 phy_addr, u16 *value);
-i40e_status i40e_write_phy_register(struct i40e_hw *hw, u8 page,
- u16 reg, u8 phy_addr, u16 value);
-i40e_status i40e_read_phy_register(struct i40e_hw *hw, u8 page, u16 reg,
- u8 phy_addr, u16 *value);
-i40e_status i40e_write_phy_register(struct i40e_hw *hw, u8 page, u16 reg,
- u8 phy_addr, u16 value);
-u8 i40e_get_phy_address(struct i40e_hw *hw, u8 dev_num);
-i40e_status i40e_blink_phy_link_led(struct i40e_hw *hw,
- u32 time, u32 interval);
-i40e_status i40evf_aq_write_ddp(struct i40e_hw *hw, void *buff,
- u16 buff_size, u32 track_id,
- u32 *error_offset, u32 *error_info,
- struct i40e_asq_cmd_details *
- cmd_details);
-i40e_status i40evf_aq_get_ddp_list(struct i40e_hw *hw, void *buff,
- u16 buff_size, u8 flags,
- struct i40e_asq_cmd_details *
- cmd_details);
-struct i40e_generic_seg_header *
-i40evf_find_segment_in_package(u32 segment_type,
- struct i40e_package_header *pkg_header);
-enum i40e_status_code
-i40evf_write_profile(struct i40e_hw *hw, struct i40e_profile_segment *i40e_seg,
- u32 track_id);
-enum i40e_status_code
-i40evf_add_pinfo_to_list(struct i40e_hw *hw,
- struct i40e_profile_segment *profile,
- u8 *profile_info_sec, u32 track_id);
-#endif /* _I40E_PROTOTYPE_H_ */
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_register.h b/drivers/net/ethernet/intel/i40evf/i40e_register.h
deleted file mode 100644
index 49e1f57d99cc..000000000000
--- a/drivers/net/ethernet/intel/i40evf/i40e_register.h
+++ /dev/null
@@ -1,313 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/* Copyright(c) 2013 - 2018 Intel Corporation. */
-
-#ifndef _I40E_REGISTER_H_
-#define _I40E_REGISTER_H_
-
-#define I40E_VFMSIX_PBA1(_i) (0x00002000 + ((_i) * 4)) /* _i=0...19 */ /* Reset: VFLR */
-#define I40E_VFMSIX_PBA1_MAX_INDEX 19
-#define I40E_VFMSIX_PBA1_PENBIT_SHIFT 0
-#define I40E_VFMSIX_PBA1_PENBIT_MASK I40E_MASK(0xFFFFFFFF, I40E_VFMSIX_PBA1_PENBIT_SHIFT)
-#define I40E_VFMSIX_TADD1(_i) (0x00002100 + ((_i) * 16)) /* _i=0...639 */ /* Reset: VFLR */
-#define I40E_VFMSIX_TADD1_MAX_INDEX 639
-#define I40E_VFMSIX_TADD1_MSIXTADD10_SHIFT 0
-#define I40E_VFMSIX_TADD1_MSIXTADD10_MASK I40E_MASK(0x3, I40E_VFMSIX_TADD1_MSIXTADD10_SHIFT)
-#define I40E_VFMSIX_TADD1_MSIXTADD_SHIFT 2
-#define I40E_VFMSIX_TADD1_MSIXTADD_MASK I40E_MASK(0x3FFFFFFF, I40E_VFMSIX_TADD1_MSIXTADD_SHIFT)
-#define I40E_VFMSIX_TMSG1(_i) (0x00002108 + ((_i) * 16)) /* _i=0...639 */ /* Reset: VFLR */
-#define I40E_VFMSIX_TMSG1_MAX_INDEX 639
-#define I40E_VFMSIX_TMSG1_MSIXTMSG_SHIFT 0
-#define I40E_VFMSIX_TMSG1_MSIXTMSG_MASK I40E_MASK(0xFFFFFFFF, I40E_VFMSIX_TMSG1_MSIXTMSG_SHIFT)
-#define I40E_VFMSIX_TUADD1(_i) (0x00002104 + ((_i) * 16)) /* _i=0...639 */ /* Reset: VFLR */
-#define I40E_VFMSIX_TUADD1_MAX_INDEX 639
-#define I40E_VFMSIX_TUADD1_MSIXTUADD_SHIFT 0
-#define I40E_VFMSIX_TUADD1_MSIXTUADD_MASK I40E_MASK(0xFFFFFFFF, I40E_VFMSIX_TUADD1_MSIXTUADD_SHIFT)
-#define I40E_VFMSIX_TVCTRL1(_i) (0x0000210C + ((_i) * 16)) /* _i=0...639 */ /* Reset: VFLR */
-#define I40E_VFMSIX_TVCTRL1_MAX_INDEX 639
-#define I40E_VFMSIX_TVCTRL1_MASK_SHIFT 0
-#define I40E_VFMSIX_TVCTRL1_MASK_MASK I40E_MASK(0x1, I40E_VFMSIX_TVCTRL1_MASK_SHIFT)
-#define I40E_VF_ARQBAH1 0x00006000 /* Reset: EMPR */
-#define I40E_VF_ARQBAH1_ARQBAH_SHIFT 0
-#define I40E_VF_ARQBAH1_ARQBAH_MASK I40E_MASK(0xFFFFFFFF, I40E_VF_ARQBAH1_ARQBAH_SHIFT)
-#define I40E_VF_ARQBAL1 0x00006C00 /* Reset: EMPR */
-#define I40E_VF_ARQBAL1_ARQBAL_SHIFT 0
-#define I40E_VF_ARQBAL1_ARQBAL_MASK I40E_MASK(0xFFFFFFFF, I40E_VF_ARQBAL1_ARQBAL_SHIFT)
-#define I40E_VF_ARQH1 0x00007400 /* Reset: EMPR */
-#define I40E_VF_ARQH1_ARQH_SHIFT 0
-#define I40E_VF_ARQH1_ARQH_MASK I40E_MASK(0x3FF, I40E_VF_ARQH1_ARQH_SHIFT)
-#define I40E_VF_ARQLEN1 0x00008000 /* Reset: EMPR */
-#define I40E_VF_ARQLEN1_ARQLEN_SHIFT 0
-#define I40E_VF_ARQLEN1_ARQLEN_MASK I40E_MASK(0x3FF, I40E_VF_ARQLEN1_ARQLEN_SHIFT)
-#define I40E_VF_ARQLEN1_ARQVFE_SHIFT 28
-#define I40E_VF_ARQLEN1_ARQVFE_MASK I40E_MASK(0x1, I40E_VF_ARQLEN1_ARQVFE_SHIFT)
-#define I40E_VF_ARQLEN1_ARQOVFL_SHIFT 29
-#define I40E_VF_ARQLEN1_ARQOVFL_MASK I40E_MASK(0x1, I40E_VF_ARQLEN1_ARQOVFL_SHIFT)
-#define I40E_VF_ARQLEN1_ARQCRIT_SHIFT 30
-#define I40E_VF_ARQLEN1_ARQCRIT_MASK I40E_MASK(0x1, I40E_VF_ARQLEN1_ARQCRIT_SHIFT)
-#define I40E_VF_ARQLEN1_ARQENABLE_SHIFT 31
-#define I40E_VF_ARQLEN1_ARQENABLE_MASK I40E_MASK(0x1, I40E_VF_ARQLEN1_ARQENABLE_SHIFT)
-#define I40E_VF_ARQT1 0x00007000 /* Reset: EMPR */
-#define I40E_VF_ARQT1_ARQT_SHIFT 0
-#define I40E_VF_ARQT1_ARQT_MASK I40E_MASK(0x3FF, I40E_VF_ARQT1_ARQT_SHIFT)
-#define I40E_VF_ATQBAH1 0x00007800 /* Reset: EMPR */
-#define I40E_VF_ATQBAH1_ATQBAH_SHIFT 0
-#define I40E_VF_ATQBAH1_ATQBAH_MASK I40E_MASK(0xFFFFFFFF, I40E_VF_ATQBAH1_ATQBAH_SHIFT)
-#define I40E_VF_ATQBAL1 0x00007C00 /* Reset: EMPR */
-#define I40E_VF_ATQBAL1_ATQBAL_SHIFT 0
-#define I40E_VF_ATQBAL1_ATQBAL_MASK I40E_MASK(0xFFFFFFFF, I40E_VF_ATQBAL1_ATQBAL_SHIFT)
-#define I40E_VF_ATQH1 0x00006400 /* Reset: EMPR */
-#define I40E_VF_ATQH1_ATQH_SHIFT 0
-#define I40E_VF_ATQH1_ATQH_MASK I40E_MASK(0x3FF, I40E_VF_ATQH1_ATQH_SHIFT)
-#define I40E_VF_ATQLEN1 0x00006800 /* Reset: EMPR */
-#define I40E_VF_ATQLEN1_ATQLEN_SHIFT 0
-#define I40E_VF_ATQLEN1_ATQLEN_MASK I40E_MASK(0x3FF, I40E_VF_ATQLEN1_ATQLEN_SHIFT)
-#define I40E_VF_ATQLEN1_ATQVFE_SHIFT 28
-#define I40E_VF_ATQLEN1_ATQVFE_MASK I40E_MASK(0x1, I40E_VF_ATQLEN1_ATQVFE_SHIFT)
-#define I40E_VF_ATQLEN1_ATQOVFL_SHIFT 29
-#define I40E_VF_ATQLEN1_ATQOVFL_MASK I40E_MASK(0x1, I40E_VF_ATQLEN1_ATQOVFL_SHIFT)
-#define I40E_VF_ATQLEN1_ATQCRIT_SHIFT 30
-#define I40E_VF_ATQLEN1_ATQCRIT_MASK I40E_MASK(0x1, I40E_VF_ATQLEN1_ATQCRIT_SHIFT)
-#define I40E_VF_ATQLEN1_ATQENABLE_SHIFT 31
-#define I40E_VF_ATQLEN1_ATQENABLE_MASK I40E_MASK(0x1, I40E_VF_ATQLEN1_ATQENABLE_SHIFT)
-#define I40E_VF_ATQT1 0x00008400 /* Reset: EMPR */
-#define I40E_VF_ATQT1_ATQT_SHIFT 0
-#define I40E_VF_ATQT1_ATQT_MASK I40E_MASK(0x3FF, I40E_VF_ATQT1_ATQT_SHIFT)
-#define I40E_VFGEN_RSTAT 0x00008800 /* Reset: VFR */
-#define I40E_VFGEN_RSTAT_VFR_STATE_SHIFT 0
-#define I40E_VFGEN_RSTAT_VFR_STATE_MASK I40E_MASK(0x3, I40E_VFGEN_RSTAT_VFR_STATE_SHIFT)
-#define I40E_VFINT_DYN_CTL01 0x00005C00 /* Reset: VFR */
-#define I40E_VFINT_DYN_CTL01_INTENA_SHIFT 0
-#define I40E_VFINT_DYN_CTL01_INTENA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL01_INTENA_SHIFT)
-#define I40E_VFINT_DYN_CTL01_CLEARPBA_SHIFT 1
-#define I40E_VFINT_DYN_CTL01_CLEARPBA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL01_CLEARPBA_SHIFT)
-#define I40E_VFINT_DYN_CTL01_SWINT_TRIG_SHIFT 2
-#define I40E_VFINT_DYN_CTL01_SWINT_TRIG_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL01_SWINT_TRIG_SHIFT)
-#define I40E_VFINT_DYN_CTL01_ITR_INDX_SHIFT 3
-#define I40E_VFINT_DYN_CTL01_ITR_INDX_MASK I40E_MASK(0x3, I40E_VFINT_DYN_CTL01_ITR_INDX_SHIFT)
-#define I40E_VFINT_DYN_CTL01_INTERVAL_SHIFT 5
-#define I40E_VFINT_DYN_CTL01_INTERVAL_MASK I40E_MASK(0xFFF, I40E_VFINT_DYN_CTL01_INTERVAL_SHIFT)
-#define I40E_VFINT_DYN_CTL01_SW_ITR_INDX_ENA_SHIFT 24
-#define I40E_VFINT_DYN_CTL01_SW_ITR_INDX_ENA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL01_SW_ITR_INDX_ENA_SHIFT)
-#define I40E_VFINT_DYN_CTL01_SW_ITR_INDX_SHIFT 25
-#define I40E_VFINT_DYN_CTL01_SW_ITR_INDX_MASK I40E_MASK(0x3, I40E_VFINT_DYN_CTL01_SW_ITR_INDX_SHIFT)
-#define I40E_VFINT_DYN_CTL01_INTENA_MSK_SHIFT 31
-#define I40E_VFINT_DYN_CTL01_INTENA_MSK_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL01_INTENA_MSK_SHIFT)
-#define I40E_VFINT_DYN_CTLN1(_INTVF) (0x00003800 + ((_INTVF) * 4)) /* _i=0...15 */ /* Reset: VFR */
-#define I40E_VFINT_DYN_CTLN1_MAX_INDEX 15
-#define I40E_VFINT_DYN_CTLN1_INTENA_SHIFT 0
-#define I40E_VFINT_DYN_CTLN1_INTENA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN1_INTENA_SHIFT)
-#define I40E_VFINT_DYN_CTLN1_CLEARPBA_SHIFT 1
-#define I40E_VFINT_DYN_CTLN1_CLEARPBA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN1_CLEARPBA_SHIFT)
-#define I40E_VFINT_DYN_CTLN1_SWINT_TRIG_SHIFT 2
-#define I40E_VFINT_DYN_CTLN1_SWINT_TRIG_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN1_SWINT_TRIG_SHIFT)
-#define I40E_VFINT_DYN_CTLN1_ITR_INDX_SHIFT 3
-#define I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK I40E_MASK(0x3, I40E_VFINT_DYN_CTLN1_ITR_INDX_SHIFT)
-#define I40E_VFINT_DYN_CTLN1_INTERVAL_SHIFT 5
-#define I40E_VFINT_DYN_CTLN1_INTERVAL_MASK I40E_MASK(0xFFF, I40E_VFINT_DYN_CTLN1_INTERVAL_SHIFT)
-#define I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_SHIFT 24
-#define I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_SHIFT)
-#define I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_SHIFT 25
-#define I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_MASK I40E_MASK(0x3, I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_SHIFT)
-#define I40E_VFINT_DYN_CTLN1_INTENA_MSK_SHIFT 31
-#define I40E_VFINT_DYN_CTLN1_INTENA_MSK_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN1_INTENA_MSK_SHIFT)
-#define I40E_VFINT_ICR0_ENA1 0x00005000 /* Reset: CORER */
-#define I40E_VFINT_ICR0_ENA1_LINK_STAT_CHANGE_SHIFT 25
-#define I40E_VFINT_ICR0_ENA1_LINK_STAT_CHANGE_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_ENA1_LINK_STAT_CHANGE_SHIFT)
-#define I40E_VFINT_ICR0_ENA1_ADMINQ_SHIFT 30
-#define I40E_VFINT_ICR0_ENA1_ADMINQ_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_ENA1_ADMINQ_SHIFT)
-#define I40E_VFINT_ICR0_ENA1_RSVD_SHIFT 31
-#define I40E_VFINT_ICR0_ENA1_RSVD_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_ENA1_RSVD_SHIFT)
-#define I40E_VFINT_ICR01 0x00004800 /* Reset: CORER */
-#define I40E_VFINT_ICR01_INTEVENT_SHIFT 0
-#define I40E_VFINT_ICR01_INTEVENT_MASK I40E_MASK(0x1, I40E_VFINT_ICR01_INTEVENT_SHIFT)
-#define I40E_VFINT_ICR01_QUEUE_0_SHIFT 1
-#define I40E_VFINT_ICR01_QUEUE_0_MASK I40E_MASK(0x1, I40E_VFINT_ICR01_QUEUE_0_SHIFT)
-#define I40E_VFINT_ICR01_QUEUE_1_SHIFT 2
-#define I40E_VFINT_ICR01_QUEUE_1_MASK I40E_MASK(0x1, I40E_VFINT_ICR01_QUEUE_1_SHIFT)
-#define I40E_VFINT_ICR01_QUEUE_2_SHIFT 3
-#define I40E_VFINT_ICR01_QUEUE_2_MASK I40E_MASK(0x1, I40E_VFINT_ICR01_QUEUE_2_SHIFT)
-#define I40E_VFINT_ICR01_QUEUE_3_SHIFT 4
-#define I40E_VFINT_ICR01_QUEUE_3_MASK I40E_MASK(0x1, I40E_VFINT_ICR01_QUEUE_3_SHIFT)
-#define I40E_VFINT_ICR01_LINK_STAT_CHANGE_SHIFT 25
-#define I40E_VFINT_ICR01_LINK_STAT_CHANGE_MASK I40E_MASK(0x1, I40E_VFINT_ICR01_LINK_STAT_CHANGE_SHIFT)
-#define I40E_VFINT_ICR01_ADMINQ_SHIFT 30
-#define I40E_VFINT_ICR01_ADMINQ_MASK I40E_MASK(0x1, I40E_VFINT_ICR01_ADMINQ_SHIFT)
-#define I40E_VFINT_ICR01_SWINT_SHIFT 31
-#define I40E_VFINT_ICR01_SWINT_MASK I40E_MASK(0x1, I40E_VFINT_ICR01_SWINT_SHIFT)
-#define I40E_VFINT_ITR01(_i) (0x00004C00 + ((_i) * 4)) /* _i=0...2 */ /* Reset: VFR */
-#define I40E_VFINT_ITR01_MAX_INDEX 2
-#define I40E_VFINT_ITR01_INTERVAL_SHIFT 0
-#define I40E_VFINT_ITR01_INTERVAL_MASK I40E_MASK(0xFFF, I40E_VFINT_ITR01_INTERVAL_SHIFT)
-#define I40E_VFINT_ITRN1(_i, _INTVF) (0x00002800 + ((_i) * 64 + (_INTVF) * 4)) /* _i=0...2, _INTVF=0...15 */ /* Reset: VFR */
-#define I40E_VFINT_ITRN1_MAX_INDEX 2
-#define I40E_VFINT_ITRN1_INTERVAL_SHIFT 0
-#define I40E_VFINT_ITRN1_INTERVAL_MASK I40E_MASK(0xFFF, I40E_VFINT_ITRN1_INTERVAL_SHIFT)
-#define I40E_VFINT_STAT_CTL01 0x00005400 /* Reset: CORER */
-#define I40E_VFINT_STAT_CTL01_OTHER_ITR_INDX_SHIFT 2
-#define I40E_VFINT_STAT_CTL01_OTHER_ITR_INDX_MASK I40E_MASK(0x3, I40E_VFINT_STAT_CTL01_OTHER_ITR_INDX_SHIFT)
-#define I40E_QRX_TAIL1(_Q) (0x00002000 + ((_Q) * 4)) /* _i=0...15 */ /* Reset: CORER */
-#define I40E_QRX_TAIL1_MAX_INDEX 15
-#define I40E_QRX_TAIL1_TAIL_SHIFT 0
-#define I40E_QRX_TAIL1_TAIL_MASK I40E_MASK(0x1FFF, I40E_QRX_TAIL1_TAIL_SHIFT)
-#define I40E_QTX_TAIL1(_Q) (0x00000000 + ((_Q) * 4)) /* _i=0...15 */ /* Reset: PFR */
-#define I40E_QTX_TAIL1_MAX_INDEX 15
-#define I40E_QTX_TAIL1_TAIL_SHIFT 0
-#define I40E_QTX_TAIL1_TAIL_MASK I40E_MASK(0x1FFF, I40E_QTX_TAIL1_TAIL_SHIFT)
-#define I40E_VFMSIX_PBA 0x00002000 /* Reset: VFLR */
-#define I40E_VFMSIX_PBA_PENBIT_SHIFT 0
-#define I40E_VFMSIX_PBA_PENBIT_MASK I40E_MASK(0xFFFFFFFF, I40E_VFMSIX_PBA_PENBIT_SHIFT)
-#define I40E_VFMSIX_TADD(_i) (0x00000000 + ((_i) * 16)) /* _i=0...16 */ /* Reset: VFLR */
-#define I40E_VFMSIX_TADD_MAX_INDEX 16
-#define I40E_VFMSIX_TADD_MSIXTADD10_SHIFT 0
-#define I40E_VFMSIX_TADD_MSIXTADD10_MASK I40E_MASK(0x3, I40E_VFMSIX_TADD_MSIXTADD10_SHIFT)
-#define I40E_VFMSIX_TADD_MSIXTADD_SHIFT 2
-#define I40E_VFMSIX_TADD_MSIXTADD_MASK I40E_MASK(0x3FFFFFFF, I40E_VFMSIX_TADD_MSIXTADD_SHIFT)
-#define I40E_VFMSIX_TMSG(_i) (0x00000008 + ((_i) * 16)) /* _i=0...16 */ /* Reset: VFLR */
-#define I40E_VFMSIX_TMSG_MAX_INDEX 16
-#define I40E_VFMSIX_TMSG_MSIXTMSG_SHIFT 0
-#define I40E_VFMSIX_TMSG_MSIXTMSG_MASK I40E_MASK(0xFFFFFFFF, I40E_VFMSIX_TMSG_MSIXTMSG_SHIFT)
-#define I40E_VFMSIX_TUADD(_i) (0x00000004 + ((_i) * 16)) /* _i=0...16 */ /* Reset: VFLR */
-#define I40E_VFMSIX_TUADD_MAX_INDEX 16
-#define I40E_VFMSIX_TUADD_MSIXTUADD_SHIFT 0
-#define I40E_VFMSIX_TUADD_MSIXTUADD_MASK I40E_MASK(0xFFFFFFFF, I40E_VFMSIX_TUADD_MSIXTUADD_SHIFT)
-#define I40E_VFMSIX_TVCTRL(_i) (0x0000000C + ((_i) * 16)) /* _i=0...16 */ /* Reset: VFLR */
-#define I40E_VFMSIX_TVCTRL_MAX_INDEX 16
-#define I40E_VFMSIX_TVCTRL_MASK_SHIFT 0
-#define I40E_VFMSIX_TVCTRL_MASK_MASK I40E_MASK(0x1, I40E_VFMSIX_TVCTRL_MASK_SHIFT)
-#define I40E_VFCM_PE_ERRDATA 0x0000DC00 /* Reset: VFR */
-#define I40E_VFCM_PE_ERRDATA_ERROR_CODE_SHIFT 0
-#define I40E_VFCM_PE_ERRDATA_ERROR_CODE_MASK I40E_MASK(0xF, I40E_VFCM_PE_ERRDATA_ERROR_CODE_SHIFT)
-#define I40E_VFCM_PE_ERRDATA_Q_TYPE_SHIFT 4
-#define I40E_VFCM_PE_ERRDATA_Q_TYPE_MASK I40E_MASK(0x7, I40E_VFCM_PE_ERRDATA_Q_TYPE_SHIFT)
-#define I40E_VFCM_PE_ERRDATA_Q_NUM_SHIFT 8
-#define I40E_VFCM_PE_ERRDATA_Q_NUM_MASK I40E_MASK(0x3FFFF, I40E_VFCM_PE_ERRDATA_Q_NUM_SHIFT)
-#define I40E_VFCM_PE_ERRINFO 0x0000D800 /* Reset: VFR */
-#define I40E_VFCM_PE_ERRINFO_ERROR_VALID_SHIFT 0
-#define I40E_VFCM_PE_ERRINFO_ERROR_VALID_MASK I40E_MASK(0x1, I40E_VFCM_PE_ERRINFO_ERROR_VALID_SHIFT)
-#define I40E_VFCM_PE_ERRINFO_ERROR_INST_SHIFT 4
-#define I40E_VFCM_PE_ERRINFO_ERROR_INST_MASK I40E_MASK(0x7, I40E_VFCM_PE_ERRINFO_ERROR_INST_SHIFT)
-#define I40E_VFCM_PE_ERRINFO_DBL_ERROR_CNT_SHIFT 8
-#define I40E_VFCM_PE_ERRINFO_DBL_ERROR_CNT_MASK I40E_MASK(0xFF, I40E_VFCM_PE_ERRINFO_DBL_ERROR_CNT_SHIFT)
-#define I40E_VFCM_PE_ERRINFO_RLU_ERROR_CNT_SHIFT 16
-#define I40E_VFCM_PE_ERRINFO_RLU_ERROR_CNT_MASK I40E_MASK(0xFF, I40E_VFCM_PE_ERRINFO_RLU_ERROR_CNT_SHIFT)
-#define I40E_VFCM_PE_ERRINFO_RLS_ERROR_CNT_SHIFT 24
-#define I40E_VFCM_PE_ERRINFO_RLS_ERROR_CNT_MASK I40E_MASK(0xFF, I40E_VFCM_PE_ERRINFO_RLS_ERROR_CNT_SHIFT)
-#define I40E_VFQF_HENA(_i) (0x0000C400 + ((_i) * 4)) /* _i=0...1 */ /* Reset: CORER */
-#define I40E_VFQF_HENA_MAX_INDEX 1
-#define I40E_VFQF_HENA_PTYPE_ENA_SHIFT 0
-#define I40E_VFQF_HENA_PTYPE_ENA_MASK I40E_MASK(0xFFFFFFFF, I40E_VFQF_HENA_PTYPE_ENA_SHIFT)
-#define I40E_VFQF_HKEY(_i) (0x0000CC00 + ((_i) * 4)) /* _i=0...12 */ /* Reset: CORER */
-#define I40E_VFQF_HKEY_MAX_INDEX 12
-#define I40E_VFQF_HKEY_KEY_0_SHIFT 0
-#define I40E_VFQF_HKEY_KEY_0_MASK I40E_MASK(0xFF, I40E_VFQF_HKEY_KEY_0_SHIFT)
-#define I40E_VFQF_HKEY_KEY_1_SHIFT 8
-#define I40E_VFQF_HKEY_KEY_1_MASK I40E_MASK(0xFF, I40E_VFQF_HKEY_KEY_1_SHIFT)
-#define I40E_VFQF_HKEY_KEY_2_SHIFT 16
-#define I40E_VFQF_HKEY_KEY_2_MASK I40E_MASK(0xFF, I40E_VFQF_HKEY_KEY_2_SHIFT)
-#define I40E_VFQF_HKEY_KEY_3_SHIFT 24
-#define I40E_VFQF_HKEY_KEY_3_MASK I40E_MASK(0xFF, I40E_VFQF_HKEY_KEY_3_SHIFT)
-#define I40E_VFQF_HLUT(_i) (0x0000D000 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */
-#define I40E_VFQF_HLUT_MAX_INDEX 15
-#define I40E_VFQF_HLUT_LUT0_SHIFT 0
-#define I40E_VFQF_HLUT_LUT0_MASK I40E_MASK(0xF, I40E_VFQF_HLUT_LUT0_SHIFT)
-#define I40E_VFQF_HLUT_LUT1_SHIFT 8
-#define I40E_VFQF_HLUT_LUT1_MASK I40E_MASK(0xF, I40E_VFQF_HLUT_LUT1_SHIFT)
-#define I40E_VFQF_HLUT_LUT2_SHIFT 16
-#define I40E_VFQF_HLUT_LUT2_MASK I40E_MASK(0xF, I40E_VFQF_HLUT_LUT2_SHIFT)
-#define I40E_VFQF_HLUT_LUT3_SHIFT 24
-#define I40E_VFQF_HLUT_LUT3_MASK I40E_MASK(0xF, I40E_VFQF_HLUT_LUT3_SHIFT)
-#define I40E_VFQF_HREGION(_i) (0x0000D400 + ((_i) * 4)) /* _i=0...7 */ /* Reset: CORER */
-#define I40E_VFQF_HREGION_MAX_INDEX 7
-#define I40E_VFQF_HREGION_OVERRIDE_ENA_0_SHIFT 0
-#define I40E_VFQF_HREGION_OVERRIDE_ENA_0_MASK I40E_MASK(0x1, I40E_VFQF_HREGION_OVERRIDE_ENA_0_SHIFT)
-#define I40E_VFQF_HREGION_REGION_0_SHIFT 1
-#define I40E_VFQF_HREGION_REGION_0_MASK I40E_MASK(0x7, I40E_VFQF_HREGION_REGION_0_SHIFT)
-#define I40E_VFQF_HREGION_OVERRIDE_ENA_1_SHIFT 4
-#define I40E_VFQF_HREGION_OVERRIDE_ENA_1_MASK I40E_MASK(0x1, I40E_VFQF_HREGION_OVERRIDE_ENA_1_SHIFT)
-#define I40E_VFQF_HREGION_REGION_1_SHIFT 5
-#define I40E_VFQF_HREGION_REGION_1_MASK I40E_MASK(0x7, I40E_VFQF_HREGION_REGION_1_SHIFT)
-#define I40E_VFQF_HREGION_OVERRIDE_ENA_2_SHIFT 8
-#define I40E_VFQF_HREGION_OVERRIDE_ENA_2_MASK I40E_MASK(0x1, I40E_VFQF_HREGION_OVERRIDE_ENA_2_SHIFT)
-#define I40E_VFQF_HREGION_REGION_2_SHIFT 9
-#define I40E_VFQF_HREGION_REGION_2_MASK I40E_MASK(0x7, I40E_VFQF_HREGION_REGION_2_SHIFT)
-#define I40E_VFQF_HREGION_OVERRIDE_ENA_3_SHIFT 12
-#define I40E_VFQF_HREGION_OVERRIDE_ENA_3_MASK I40E_MASK(0x1, I40E_VFQF_HREGION_OVERRIDE_ENA_3_SHIFT)
-#define I40E_VFQF_HREGION_REGION_3_SHIFT 13
-#define I40E_VFQF_HREGION_REGION_3_MASK I40E_MASK(0x7, I40E_VFQF_HREGION_REGION_3_SHIFT)
-#define I40E_VFQF_HREGION_OVERRIDE_ENA_4_SHIFT 16
-#define I40E_VFQF_HREGION_OVERRIDE_ENA_4_MASK I40E_MASK(0x1, I40E_VFQF_HREGION_OVERRIDE_ENA_4_SHIFT)
-#define I40E_VFQF_HREGION_REGION_4_SHIFT 17
-#define I40E_VFQF_HREGION_REGION_4_MASK I40E_MASK(0x7, I40E_VFQF_HREGION_REGION_4_SHIFT)
-#define I40E_VFQF_HREGION_OVERRIDE_ENA_5_SHIFT 20
-#define I40E_VFQF_HREGION_OVERRIDE_ENA_5_MASK I40E_MASK(0x1, I40E_VFQF_HREGION_OVERRIDE_ENA_5_SHIFT)
-#define I40E_VFQF_HREGION_REGION_5_SHIFT 21
-#define I40E_VFQF_HREGION_REGION_5_MASK I40E_MASK(0x7, I40E_VFQF_HREGION_REGION_5_SHIFT)
-#define I40E_VFQF_HREGION_OVERRIDE_ENA_6_SHIFT 24
-#define I40E_VFQF_HREGION_OVERRIDE_ENA_6_MASK I40E_MASK(0x1, I40E_VFQF_HREGION_OVERRIDE_ENA_6_SHIFT)
-#define I40E_VFQF_HREGION_REGION_6_SHIFT 25
-#define I40E_VFQF_HREGION_REGION_6_MASK I40E_MASK(0x7, I40E_VFQF_HREGION_REGION_6_SHIFT)
-#define I40E_VFQF_HREGION_OVERRIDE_ENA_7_SHIFT 28
-#define I40E_VFQF_HREGION_OVERRIDE_ENA_7_MASK I40E_MASK(0x1, I40E_VFQF_HREGION_OVERRIDE_ENA_7_SHIFT)
-#define I40E_VFQF_HREGION_REGION_7_SHIFT 29
-#define I40E_VFQF_HREGION_REGION_7_MASK I40E_MASK(0x7, I40E_VFQF_HREGION_REGION_7_SHIFT)
-#define I40E_VFINT_DYN_CTL01_WB_ON_ITR_SHIFT 30
-#define I40E_VFINT_DYN_CTL01_WB_ON_ITR_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL01_WB_ON_ITR_SHIFT)
-#define I40E_VFINT_DYN_CTLN1_WB_ON_ITR_SHIFT 30
-#define I40E_VFINT_DYN_CTLN1_WB_ON_ITR_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN1_WB_ON_ITR_SHIFT)
-#define I40E_VFPE_AEQALLOC1 0x0000A400 /* Reset: VFR */
-#define I40E_VFPE_AEQALLOC1_AECOUNT_SHIFT 0
-#define I40E_VFPE_AEQALLOC1_AECOUNT_MASK I40E_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 I40E_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 I40E_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 I40E_MASK(0x1, I40E_VFPE_CCQPSTATUS1_CCQP_DONE_SHIFT)
-#define I40E_VFPE_CCQPSTATUS1_HMC_PROFILE_SHIFT 4
-#define I40E_VFPE_CCQPSTATUS1_HMC_PROFILE_MASK I40E_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 I40E_MASK(0x3F, I40E_VFPE_CCQPSTATUS1_RDMA_EN_VFS_SHIFT)
-#define I40E_VFPE_CCQPSTATUS1_CCQP_ERR_SHIFT 31
-#define I40E_VFPE_CCQPSTATUS1_CCQP_ERR_MASK I40E_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 I40E_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 I40E_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 I40E_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 I40E_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 I40E_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 I40E_MASK(0x7FF, I40E_VFPE_CQPTAIL1_WQTAIL_SHIFT)
-#define I40E_VFPE_CQPTAIL1_CQP_OP_ERR_SHIFT 31
-#define I40E_VFPE_CQPTAIL1_CQP_OP_ERR_MASK I40E_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 I40E_MASK(0xFFFF, I40E_VFPE_IPCONFIG01_PEIPID_SHIFT)
-#define I40E_VFPE_IPCONFIG01_USEENTIREIDRANGE_SHIFT 16
-#define I40E_VFPE_IPCONFIG01_USEENTIREIDRANGE_MASK I40E_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 I40E_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 I40E_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 I40E_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 I40E_MASK(0x3FFFF, I40E_VFPE_WQEALLOC1_PEQPID_SHIFT)
-#define I40E_VFPE_WQEALLOC1_WQE_DESC_INDEX_SHIFT 20
-#define I40E_VFPE_WQEALLOC1_WQE_DESC_INDEX_MASK I40E_MASK(0xFFF, I40E_VFPE_WQEALLOC1_WQE_DESC_INDEX_SHIFT)
-#endif /* _I40E_REGISTER_H_ */
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h
deleted file mode 100644
index 094387db3c11..000000000000
--- a/drivers/net/ethernet/intel/i40evf/i40e_type.h
+++ /dev/null
@@ -1,1496 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/* Copyright(c) 2013 - 2018 Intel Corporation. */
-
-#ifndef _I40E_TYPE_H_
-#define _I40E_TYPE_H_
-
-#include "i40e_status.h"
-#include "i40e_osdep.h"
-#include "i40e_register.h"
-#include "i40e_adminq.h"
-#include "i40e_hmc.h"
-#include "i40e_lan_hmc.h"
-#include "i40e_devids.h"
-
-/* I40E_MASK is a macro used on 32 bit registers */
-#define I40E_MASK(mask, shift) ((u32)(mask) << (shift))
-
-#define I40E_MAX_VSI_QP 16
-#define I40E_MAX_VF_VSI 3
-#define I40E_MAX_CHAINED_RX_BUFFERS 5
-#define I40E_MAX_PF_UDP_OFFLOAD_PORTS 16
-
-/* Max default timeout in ms, */
-#define I40E_MAX_NVM_TIMEOUT 18000
-
-/* Max timeout in ms for the phy to respond */
-#define I40E_MAX_PHY_TIMEOUT 500
-
-/* Switch from ms to the 1usec global time (this is the GTIME resolution) */
-#define I40E_MS_TO_GTIME(time) ((time) * 1000)
-
-/* forward declaration */
-struct i40e_hw;
-typedef void (*I40E_ADMINQ_CALLBACK)(struct i40e_hw *, struct i40e_aq_desc *);
-
-/* Data type manipulation macros. */
-
-#define I40E_DESC_UNUSED(R) \
- ((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \
- (R)->next_to_clean - (R)->next_to_use - 1)
-
-/* bitfields for Tx queue mapping in QTX_CTL */
-#define I40E_QTX_CTL_VF_QUEUE 0x0
-#define I40E_QTX_CTL_VM_QUEUE 0x1
-#define I40E_QTX_CTL_PF_QUEUE 0x2
-
-/* debug masks - set these bits in hw->debug_mask to control output */
-enum i40e_debug_mask {
- I40E_DEBUG_INIT = 0x00000001,
- I40E_DEBUG_RELEASE = 0x00000002,
-
- I40E_DEBUG_LINK = 0x00000010,
- I40E_DEBUG_PHY = 0x00000020,
- I40E_DEBUG_HMC = 0x00000040,
- I40E_DEBUG_NVM = 0x00000080,
- I40E_DEBUG_LAN = 0x00000100,
- I40E_DEBUG_FLOW = 0x00000200,
- I40E_DEBUG_DCB = 0x00000400,
- I40E_DEBUG_DIAG = 0x00000800,
- I40E_DEBUG_FD = 0x00001000,
- I40E_DEBUG_PACKAGE = 0x00002000,
-
- I40E_DEBUG_AQ_MESSAGE = 0x01000000,
- I40E_DEBUG_AQ_DESCRIPTOR = 0x02000000,
- I40E_DEBUG_AQ_DESC_BUFFER = 0x04000000,
- I40E_DEBUG_AQ_COMMAND = 0x06000000,
- I40E_DEBUG_AQ = 0x0F000000,
-
- I40E_DEBUG_USER = 0xF0000000,
-
- I40E_DEBUG_ALL = 0xFFFFFFFF
-};
-
-/* These are structs for managing the hardware information and the operations.
- * The structures of function pointers are filled out at init time when we
- * know for sure exactly which hardware we're working with. This gives us the
- * flexibility of using the same main driver code but adapting to slightly
- * different hardware needs as new parts are developed. For this architecture,
- * the Firmware and AdminQ are intended to insulate the driver from most of the
- * future changes, but these structures will also do part of the job.
- */
-enum i40e_mac_type {
- I40E_MAC_UNKNOWN = 0,
- I40E_MAC_XL710,
- I40E_MAC_VF,
- I40E_MAC_X722,
- I40E_MAC_X722_VF,
- I40E_MAC_GENERIC,
-};
-
-enum i40e_media_type {
- I40E_MEDIA_TYPE_UNKNOWN = 0,
- I40E_MEDIA_TYPE_FIBER,
- I40E_MEDIA_TYPE_BASET,
- I40E_MEDIA_TYPE_BACKPLANE,
- I40E_MEDIA_TYPE_CX4,
- I40E_MEDIA_TYPE_DA,
- I40E_MEDIA_TYPE_VIRTUAL
-};
-
-enum i40e_fc_mode {
- I40E_FC_NONE = 0,
- I40E_FC_RX_PAUSE,
- I40E_FC_TX_PAUSE,
- I40E_FC_FULL,
- I40E_FC_PFC,
- I40E_FC_DEFAULT
-};
-
-enum i40e_set_fc_aq_failures {
- I40E_SET_FC_AQ_FAIL_NONE = 0,
- I40E_SET_FC_AQ_FAIL_GET = 1,
- I40E_SET_FC_AQ_FAIL_SET = 2,
- I40E_SET_FC_AQ_FAIL_UPDATE = 4,
- I40E_SET_FC_AQ_FAIL_SET_UPDATE = 6
-};
-
-enum i40e_vsi_type {
- I40E_VSI_MAIN = 0,
- I40E_VSI_VMDQ1 = 1,
- I40E_VSI_VMDQ2 = 2,
- I40E_VSI_CTRL = 3,
- I40E_VSI_FCOE = 4,
- I40E_VSI_MIRROR = 5,
- I40E_VSI_SRIOV = 6,
- I40E_VSI_FDIR = 7,
- I40E_VSI_TYPE_UNKNOWN
-};
-
-enum i40e_queue_type {
- I40E_QUEUE_TYPE_RX = 0,
- I40E_QUEUE_TYPE_TX,
- I40E_QUEUE_TYPE_PE_CEQ,
- I40E_QUEUE_TYPE_UNKNOWN
-};
-
-struct i40e_link_status {
- enum i40e_aq_phy_type phy_type;
- enum i40e_aq_link_speed link_speed;
- u8 link_info;
- u8 an_info;
- u8 req_fec_info;
- u8 fec_info;
- u8 ext_info;
- u8 loopback;
- /* is Link Status Event notification to SW enabled */
- bool lse_enable;
- u16 max_frame_size;
- bool crc_enable;
- u8 pacing;
- u8 requested_speeds;
- u8 module_type[3];
- /* 1st byte: module identifier */
-#define I40E_MODULE_TYPE_SFP 0x03
-#define I40E_MODULE_TYPE_QSFP 0x0D
- /* 2nd byte: ethernet compliance codes for 10/40G */
-#define I40E_MODULE_TYPE_40G_ACTIVE 0x01
-#define I40E_MODULE_TYPE_40G_LR4 0x02
-#define I40E_MODULE_TYPE_40G_SR4 0x04
-#define I40E_MODULE_TYPE_40G_CR4 0x08
-#define I40E_MODULE_TYPE_10G_BASE_SR 0x10
-#define I40E_MODULE_TYPE_10G_BASE_LR 0x20
-#define I40E_MODULE_TYPE_10G_BASE_LRM 0x40
-#define I40E_MODULE_TYPE_10G_BASE_ER 0x80
- /* 3rd byte: ethernet compliance codes for 1G */
-#define I40E_MODULE_TYPE_1000BASE_SX 0x01
-#define I40E_MODULE_TYPE_1000BASE_LX 0x02
-#define I40E_MODULE_TYPE_1000BASE_CX 0x04
-#define I40E_MODULE_TYPE_1000BASE_T 0x08
-};
-
-struct i40e_phy_info {
- struct i40e_link_status link_info;
- struct i40e_link_status link_info_old;
- bool get_link_info;
- enum i40e_media_type media_type;
- /* all the phy types the NVM is capable of */
- u64 phy_types;
-};
-
-#define I40E_CAP_PHY_TYPE_SGMII BIT_ULL(I40E_PHY_TYPE_SGMII)
-#define I40E_CAP_PHY_TYPE_1000BASE_KX BIT_ULL(I40E_PHY_TYPE_1000BASE_KX)
-#define I40E_CAP_PHY_TYPE_10GBASE_KX4 BIT_ULL(I40E_PHY_TYPE_10GBASE_KX4)
-#define I40E_CAP_PHY_TYPE_10GBASE_KR BIT_ULL(I40E_PHY_TYPE_10GBASE_KR)
-#define I40E_CAP_PHY_TYPE_40GBASE_KR4 BIT_ULL(I40E_PHY_TYPE_40GBASE_KR4)
-#define I40E_CAP_PHY_TYPE_XAUI BIT_ULL(I40E_PHY_TYPE_XAUI)
-#define I40E_CAP_PHY_TYPE_XFI BIT_ULL(I40E_PHY_TYPE_XFI)
-#define I40E_CAP_PHY_TYPE_SFI BIT_ULL(I40E_PHY_TYPE_SFI)
-#define I40E_CAP_PHY_TYPE_XLAUI BIT_ULL(I40E_PHY_TYPE_XLAUI)
-#define I40E_CAP_PHY_TYPE_XLPPI BIT_ULL(I40E_PHY_TYPE_XLPPI)
-#define I40E_CAP_PHY_TYPE_40GBASE_CR4_CU BIT_ULL(I40E_PHY_TYPE_40GBASE_CR4_CU)
-#define I40E_CAP_PHY_TYPE_10GBASE_CR1_CU BIT_ULL(I40E_PHY_TYPE_10GBASE_CR1_CU)
-#define I40E_CAP_PHY_TYPE_10GBASE_AOC BIT_ULL(I40E_PHY_TYPE_10GBASE_AOC)
-#define I40E_CAP_PHY_TYPE_40GBASE_AOC BIT_ULL(I40E_PHY_TYPE_40GBASE_AOC)
-#define I40E_CAP_PHY_TYPE_100BASE_TX BIT_ULL(I40E_PHY_TYPE_100BASE_TX)
-#define I40E_CAP_PHY_TYPE_1000BASE_T BIT_ULL(I40E_PHY_TYPE_1000BASE_T)
-#define I40E_CAP_PHY_TYPE_10GBASE_T BIT_ULL(I40E_PHY_TYPE_10GBASE_T)
-#define I40E_CAP_PHY_TYPE_10GBASE_SR BIT_ULL(I40E_PHY_TYPE_10GBASE_SR)
-#define I40E_CAP_PHY_TYPE_10GBASE_LR BIT_ULL(I40E_PHY_TYPE_10GBASE_LR)
-#define I40E_CAP_PHY_TYPE_10GBASE_SFPP_CU BIT_ULL(I40E_PHY_TYPE_10GBASE_SFPP_CU)
-#define I40E_CAP_PHY_TYPE_10GBASE_CR1 BIT_ULL(I40E_PHY_TYPE_10GBASE_CR1)
-#define I40E_CAP_PHY_TYPE_40GBASE_CR4 BIT_ULL(I40E_PHY_TYPE_40GBASE_CR4)
-#define I40E_CAP_PHY_TYPE_40GBASE_SR4 BIT_ULL(I40E_PHY_TYPE_40GBASE_SR4)
-#define I40E_CAP_PHY_TYPE_40GBASE_LR4 BIT_ULL(I40E_PHY_TYPE_40GBASE_LR4)
-#define I40E_CAP_PHY_TYPE_1000BASE_SX BIT_ULL(I40E_PHY_TYPE_1000BASE_SX)
-#define I40E_CAP_PHY_TYPE_1000BASE_LX BIT_ULL(I40E_PHY_TYPE_1000BASE_LX)
-#define I40E_CAP_PHY_TYPE_1000BASE_T_OPTICAL \
- BIT_ULL(I40E_PHY_TYPE_1000BASE_T_OPTICAL)
-#define I40E_CAP_PHY_TYPE_20GBASE_KR2 BIT_ULL(I40E_PHY_TYPE_20GBASE_KR2)
-/* Defining the macro I40E_TYPE_OFFSET to implement a bit shift for some
- * PHY types. There is an unused bit (31) in the I40E_CAP_PHY_TYPE_* bit
- * fields but no corresponding gap in the i40e_aq_phy_type enumeration. So,
- * a shift is needed to adjust for this with values larger than 31. The
- * only affected values are I40E_PHY_TYPE_25GBASE_*.
- */
-#define I40E_PHY_TYPE_OFFSET 1
-#define I40E_CAP_PHY_TYPE_25GBASE_KR BIT_ULL(I40E_PHY_TYPE_25GBASE_KR + \
- I40E_PHY_TYPE_OFFSET)
-#define I40E_CAP_PHY_TYPE_25GBASE_CR BIT_ULL(I40E_PHY_TYPE_25GBASE_CR + \
- I40E_PHY_TYPE_OFFSET)
-#define I40E_CAP_PHY_TYPE_25GBASE_SR BIT_ULL(I40E_PHY_TYPE_25GBASE_SR + \
- I40E_PHY_TYPE_OFFSET)
-#define I40E_CAP_PHY_TYPE_25GBASE_LR BIT_ULL(I40E_PHY_TYPE_25GBASE_LR + \
- I40E_PHY_TYPE_OFFSET)
-#define I40E_HW_CAP_MAX_GPIO 30
-/* Capabilities of a PF or a VF or the whole device */
-struct i40e_hw_capabilities {
- u32 switch_mode;
-#define I40E_NVM_IMAGE_TYPE_EVB 0x0
-#define I40E_NVM_IMAGE_TYPE_CLOUD 0x2
-#define I40E_NVM_IMAGE_TYPE_UDP_CLOUD 0x3
-
- u32 management_mode;
- u32 mng_protocols_over_mctp;
-#define I40E_MNG_PROTOCOL_PLDM 0x2
-#define I40E_MNG_PROTOCOL_OEM_COMMANDS 0x4
-#define I40E_MNG_PROTOCOL_NCSI 0x8
- u32 npar_enable;
- u32 os2bmc;
- u32 valid_functions;
- bool sr_iov_1_1;
- bool vmdq;
- bool evb_802_1_qbg; /* Edge Virtual Bridging */
- bool evb_802_1_qbh; /* Bridge Port Extension */
- bool dcb;
- bool fcoe;
- bool iscsi; /* Indicates iSCSI enabled */
- bool flex10_enable;
- bool flex10_capable;
- u32 flex10_mode;
-#define I40E_FLEX10_MODE_UNKNOWN 0x0
-#define I40E_FLEX10_MODE_DCC 0x1
-#define I40E_FLEX10_MODE_DCI 0x2
-
- u32 flex10_status;
-#define I40E_FLEX10_STATUS_DCC_ERROR 0x1
-#define I40E_FLEX10_STATUS_VC_MODE 0x2
-
- bool sec_rev_disabled;
- bool update_disabled;
-#define I40E_NVM_MGMT_SEC_REV_DISABLED 0x1
-#define I40E_NVM_MGMT_UPDATE_DISABLED 0x2
-
- bool mgmt_cem;
- bool ieee_1588;
- bool iwarp;
- bool fd;
- u32 fd_filters_guaranteed;
- u32 fd_filters_best_effort;
- bool rss;
- u32 rss_table_size;
- u32 rss_table_entry_width;
- bool led[I40E_HW_CAP_MAX_GPIO];
- bool sdp[I40E_HW_CAP_MAX_GPIO];
- u32 nvm_image_type;
- u32 num_flow_director_filters;
- u32 num_vfs;
- u32 vf_base_id;
- u32 num_vsis;
- u32 num_rx_qp;
- u32 num_tx_qp;
- u32 base_queue;
- u32 num_msix_vectors;
- u32 num_msix_vectors_vf;
- u32 led_pin_num;
- u32 sdp_pin_num;
- u32 mdio_port_num;
- u32 mdio_port_mode;
- u8 rx_buf_chain_len;
- u32 enabled_tcmap;
- u32 maxtc;
- u64 wr_csr_prot;
-};
-
-struct i40e_mac_info {
- enum i40e_mac_type type;
- u8 addr[ETH_ALEN];
- u8 perm_addr[ETH_ALEN];
- u8 san_addr[ETH_ALEN];
- u16 max_fcoeq;
-};
-
-enum i40e_aq_resources_ids {
- I40E_NVM_RESOURCE_ID = 1
-};
-
-enum i40e_aq_resource_access_type {
- I40E_RESOURCE_READ = 1,
- I40E_RESOURCE_WRITE
-};
-
-struct i40e_nvm_info {
- u64 hw_semaphore_timeout; /* usec global time (GTIME resolution) */
- u32 timeout; /* [ms] */
- u16 sr_size; /* Shadow RAM size in words */
- bool blank_nvm_mode; /* is NVM empty (no FW present)*/
- u16 version; /* NVM package version */
- u32 eetrack; /* NVM data version */
- u32 oem_ver; /* OEM version info */
-};
-
-/* definitions used in NVM update support */
-
-enum i40e_nvmupd_cmd {
- I40E_NVMUPD_INVALID,
- I40E_NVMUPD_READ_CON,
- I40E_NVMUPD_READ_SNT,
- I40E_NVMUPD_READ_LCB,
- I40E_NVMUPD_READ_SA,
- I40E_NVMUPD_WRITE_ERA,
- I40E_NVMUPD_WRITE_CON,
- I40E_NVMUPD_WRITE_SNT,
- I40E_NVMUPD_WRITE_LCB,
- I40E_NVMUPD_WRITE_SA,
- I40E_NVMUPD_CSUM_CON,
- I40E_NVMUPD_CSUM_SA,
- I40E_NVMUPD_CSUM_LCB,
- I40E_NVMUPD_STATUS,
- I40E_NVMUPD_EXEC_AQ,
- I40E_NVMUPD_GET_AQ_RESULT,
- I40E_NVMUPD_GET_AQ_EVENT,
-};
-
-enum i40e_nvmupd_state {
- I40E_NVMUPD_STATE_INIT,
- I40E_NVMUPD_STATE_READING,
- I40E_NVMUPD_STATE_WRITING,
- I40E_NVMUPD_STATE_INIT_WAIT,
- I40E_NVMUPD_STATE_WRITE_WAIT,
- I40E_NVMUPD_STATE_ERROR
-};
-
-/* nvm_access definition and its masks/shifts need to be accessible to
- * application, core driver, and shared code. Where is the right file?
- */
-#define I40E_NVM_READ 0xB
-#define I40E_NVM_WRITE 0xC
-
-#define I40E_NVM_MOD_PNT_MASK 0xFF
-
-#define I40E_NVM_TRANS_SHIFT 8
-#define I40E_NVM_TRANS_MASK (0xf << I40E_NVM_TRANS_SHIFT)
-#define I40E_NVM_PRESERVATION_FLAGS_SHIFT 12
-#define I40E_NVM_PRESERVATION_FLAGS_MASK \
- (0x3 << I40E_NVM_PRESERVATION_FLAGS_SHIFT)
-#define I40E_NVM_PRESERVATION_FLAGS_SELECTED 0x01
-#define I40E_NVM_PRESERVATION_FLAGS_ALL 0x02
-#define I40E_NVM_CON 0x0
-#define I40E_NVM_SNT 0x1
-#define I40E_NVM_LCB 0x2
-#define I40E_NVM_SA (I40E_NVM_SNT | I40E_NVM_LCB)
-#define I40E_NVM_ERA 0x4
-#define I40E_NVM_CSUM 0x8
-#define I40E_NVM_AQE 0xe
-#define I40E_NVM_EXEC 0xf
-
-#define I40E_NVM_ADAPT_SHIFT 16
-#define I40E_NVM_ADAPT_MASK (0xffff << I40E_NVM_ADAPT_SHIFT)
-
-#define I40E_NVMUPD_MAX_DATA 4096
-#define I40E_NVMUPD_IFACE_TIMEOUT 2 /* seconds */
-
-struct i40e_nvm_access {
- u32 command;
- u32 config;
- u32 offset; /* in bytes */
- u32 data_size; /* in bytes */
- u8 data[1];
-};
-
-/* (Q)SFP module access definitions */
-#define I40E_I2C_EEPROM_DEV_ADDR 0xA0
-#define I40E_I2C_EEPROM_DEV_ADDR2 0xA2
-#define I40E_MODULE_TYPE_ADDR 0x00
-#define I40E_MODULE_REVISION_ADDR 0x01
-#define I40E_MODULE_SFF_8472_COMP 0x5E
-#define I40E_MODULE_SFF_8472_SWAP 0x5C
-#define I40E_MODULE_SFF_ADDR_MODE 0x04
-#define I40E_MODULE_TYPE_QSFP_PLUS 0x0D
-#define I40E_MODULE_TYPE_QSFP28 0x11
-#define I40E_MODULE_QSFP_MAX_LEN 640
-
-/* PCI bus types */
-enum i40e_bus_type {
- i40e_bus_type_unknown = 0,
- i40e_bus_type_pci,
- i40e_bus_type_pcix,
- i40e_bus_type_pci_express,
- i40e_bus_type_reserved
-};
-
-/* PCI bus speeds */
-enum i40e_bus_speed {
- i40e_bus_speed_unknown = 0,
- i40e_bus_speed_33 = 33,
- i40e_bus_speed_66 = 66,
- i40e_bus_speed_100 = 100,
- i40e_bus_speed_120 = 120,
- i40e_bus_speed_133 = 133,
- i40e_bus_speed_2500 = 2500,
- i40e_bus_speed_5000 = 5000,
- i40e_bus_speed_8000 = 8000,
- i40e_bus_speed_reserved
-};
-
-/* PCI bus widths */
-enum i40e_bus_width {
- i40e_bus_width_unknown = 0,
- i40e_bus_width_pcie_x1 = 1,
- i40e_bus_width_pcie_x2 = 2,
- i40e_bus_width_pcie_x4 = 4,
- i40e_bus_width_pcie_x8 = 8,
- i40e_bus_width_32 = 32,
- i40e_bus_width_64 = 64,
- i40e_bus_width_reserved
-};
-
-/* Bus parameters */
-struct i40e_bus_info {
- enum i40e_bus_speed speed;
- enum i40e_bus_width width;
- enum i40e_bus_type type;
-
- u16 func;
- u16 device;
- u16 lan_id;
- u16 bus_id;
-};
-
-/* Flow control (FC) parameters */
-struct i40e_fc_info {
- enum i40e_fc_mode current_mode; /* FC mode in effect */
- enum i40e_fc_mode requested_mode; /* FC mode requested by caller */
-};
-
-#define I40E_MAX_TRAFFIC_CLASS 8
-#define I40E_MAX_USER_PRIORITY 8
-#define I40E_DCBX_MAX_APPS 32
-#define I40E_LLDPDU_SIZE 1500
-
-/* IEEE 802.1Qaz ETS Configuration data */
-struct i40e_ieee_ets_config {
- u8 willing;
- u8 cbs;
- u8 maxtcs;
- u8 prioritytable[I40E_MAX_TRAFFIC_CLASS];
- u8 tcbwtable[I40E_MAX_TRAFFIC_CLASS];
- u8 tsatable[I40E_MAX_TRAFFIC_CLASS];
-};
-
-/* IEEE 802.1Qaz ETS Recommendation data */
-struct i40e_ieee_ets_recommend {
- u8 prioritytable[I40E_MAX_TRAFFIC_CLASS];
- u8 tcbwtable[I40E_MAX_TRAFFIC_CLASS];
- u8 tsatable[I40E_MAX_TRAFFIC_CLASS];
-};
-
-/* IEEE 802.1Qaz PFC Configuration data */
-struct i40e_ieee_pfc_config {
- u8 willing;
- u8 mbc;
- u8 pfccap;
- u8 pfcenable;
-};
-
-/* IEEE 802.1Qaz Application Priority data */
-struct i40e_ieee_app_priority_table {
- u8 priority;
- u8 selector;
- u16 protocolid;
-};
-
-struct i40e_dcbx_config {
- u32 numapps;
- u32 tlv_status; /* CEE mode TLV status */
- struct i40e_ieee_ets_config etscfg;
- struct i40e_ieee_ets_recommend etsrec;
- struct i40e_ieee_pfc_config pfc;
- struct i40e_ieee_app_priority_table app[I40E_DCBX_MAX_APPS];
-};
-
-/* Port hardware description */
-struct i40e_hw {
- u8 __iomem *hw_addr;
- void *back;
-
- /* subsystem structs */
- struct i40e_phy_info phy;
- struct i40e_mac_info mac;
- struct i40e_bus_info bus;
- struct i40e_nvm_info nvm;
- struct i40e_fc_info fc;
-
- /* pci info */
- u16 device_id;
- u16 vendor_id;
- u16 subsystem_device_id;
- u16 subsystem_vendor_id;
- u8 revision_id;
- u8 port;
- bool adapter_stopped;
-
- /* capabilities for entire device and PCI func */
- struct i40e_hw_capabilities dev_caps;
- struct i40e_hw_capabilities func_caps;
-
- /* Flow Director shared filter space */
- u16 fdir_shared_filter_count;
-
- /* device profile info */
- u8 pf_id;
- u16 main_vsi_seid;
-
- /* for multi-function MACs */
- u16 partition_id;
- u16 num_partitions;
- u16 num_ports;
-
- /* Closest numa node to the device */
- u16 numa_node;
-
- /* Admin Queue info */
- struct i40e_adminq_info aq;
-
- /* state of nvm update process */
- enum i40e_nvmupd_state nvmupd_state;
- struct i40e_aq_desc nvm_wb_desc;
- struct i40e_aq_desc nvm_aq_event_desc;
- struct i40e_virt_mem nvm_buff;
- bool nvm_release_on_done;
- u16 nvm_wait_opcode;
-
- /* HMC info */
- struct i40e_hmc_info hmc; /* HMC info struct */
-
- /* LLDP/DCBX Status */
- u16 dcbx_status;
-
-#define I40E_HW_FLAG_802_1AD_CAPABLE BIT_ULL(1)
-#define I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE BIT_ULL(2)
-
- /* DCBX info */
- struct i40e_dcbx_config local_dcbx_config; /* Oper/Local Cfg */
- struct i40e_dcbx_config remote_dcbx_config; /* Peer Cfg */
- struct i40e_dcbx_config desired_dcbx_config; /* CEE Desired Cfg */
-
- /* Used in set switch config AQ command */
- u16 switch_tag;
- u16 first_tag;
- u16 second_tag;
-
- /* debug mask */
- u32 debug_mask;
- char err_str[16];
-};
-
-static inline bool i40e_is_vf(struct i40e_hw *hw)
-{
- return (hw->mac.type == I40E_MAC_VF ||
- hw->mac.type == I40E_MAC_X722_VF);
-}
-
-struct i40e_driver_version {
- u8 major_version;
- u8 minor_version;
- u8 build_version;
- u8 subbuild_version;
- u8 driver_string[32];
-};
-
-/* RX Descriptors */
-union i40e_16byte_rx_desc {
- struct {
- __le64 pkt_addr; /* Packet buffer address */
- __le64 hdr_addr; /* Header buffer address */
- } read;
- struct {
- struct {
- struct {
- union {
- __le16 mirroring_status;
- __le16 fcoe_ctx_id;
- } mirr_fcoe;
- __le16 l2tag1;
- } lo_dword;
- union {
- __le32 rss; /* RSS Hash */
- __le32 fd_id; /* Flow director filter id */
- __le32 fcoe_param; /* FCoE DDP Context id */
- } hi_dword;
- } qword0;
- struct {
- /* ext status/error/pktype/length */
- __le64 status_error_len;
- } qword1;
- } wb; /* writeback */
-};
-
-union i40e_32byte_rx_desc {
- struct {
- __le64 pkt_addr; /* Packet buffer address */
- __le64 hdr_addr; /* Header buffer address */
- /* bit 0 of hdr_buffer_addr is DD bit */
- __le64 rsvd1;
- __le64 rsvd2;
- } read;
- struct {
- struct {
- struct {
- union {
- __le16 mirroring_status;
- __le16 fcoe_ctx_id;
- } mirr_fcoe;
- __le16 l2tag1;
- } lo_dword;
- union {
- __le32 rss; /* RSS Hash */
- __le32 fcoe_param; /* FCoE DDP Context id */
- /* Flow director filter id in case of
- * Programming status desc WB
- */
- __le32 fd_id;
- } hi_dword;
- } qword0;
- struct {
- /* status/error/pktype/length */
- __le64 status_error_len;
- } qword1;
- struct {
- __le16 ext_status; /* extended status */
- __le16 rsvd;
- __le16 l2tag2_1;
- __le16 l2tag2_2;
- } qword2;
- struct {
- union {
- __le32 flex_bytes_lo;
- __le32 pe_status;
- } lo_dword;
- union {
- __le32 flex_bytes_hi;
- __le32 fd_id;
- } hi_dword;
- } qword3;
- } wb; /* writeback */
-};
-
-enum i40e_rx_desc_status_bits {
- /* Note: These are predefined bit offsets */
- I40E_RX_DESC_STATUS_DD_SHIFT = 0,
- I40E_RX_DESC_STATUS_EOF_SHIFT = 1,
- I40E_RX_DESC_STATUS_L2TAG1P_SHIFT = 2,
- I40E_RX_DESC_STATUS_L3L4P_SHIFT = 3,
- I40E_RX_DESC_STATUS_CRCP_SHIFT = 4,
- I40E_RX_DESC_STATUS_TSYNINDX_SHIFT = 5, /* 2 BITS */
- I40E_RX_DESC_STATUS_TSYNVALID_SHIFT = 7,
- /* Note: Bit 8 is reserved in X710 and XL710 */
- I40E_RX_DESC_STATUS_EXT_UDP_0_SHIFT = 8,
- I40E_RX_DESC_STATUS_UMBCAST_SHIFT = 9, /* 2 BITS */
- I40E_RX_DESC_STATUS_FLM_SHIFT = 11,
- I40E_RX_DESC_STATUS_FLTSTAT_SHIFT = 12, /* 2 BITS */
- I40E_RX_DESC_STATUS_LPBK_SHIFT = 14,
- I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT = 15,
- I40E_RX_DESC_STATUS_RESERVED_SHIFT = 16, /* 2 BITS */
- /* Note: For non-tunnel packets INT_UDP_0 is the right status for
- * UDP header
- */
- I40E_RX_DESC_STATUS_INT_UDP_0_SHIFT = 18,
- I40E_RX_DESC_STATUS_LAST /* this entry must be last!!! */
-};
-
-#define I40E_RXD_QW1_STATUS_SHIFT 0
-#define I40E_RXD_QW1_STATUS_MASK ((BIT(I40E_RX_DESC_STATUS_LAST) - 1) \
- << I40E_RXD_QW1_STATUS_SHIFT)
-
-#define I40E_RXD_QW1_STATUS_TSYNINDX_SHIFT I40E_RX_DESC_STATUS_TSYNINDX_SHIFT
-#define I40E_RXD_QW1_STATUS_TSYNINDX_MASK (0x3UL << \
- I40E_RXD_QW1_STATUS_TSYNINDX_SHIFT)
-
-#define I40E_RXD_QW1_STATUS_TSYNVALID_SHIFT I40E_RX_DESC_STATUS_TSYNVALID_SHIFT
-#define I40E_RXD_QW1_STATUS_TSYNVALID_MASK \
- BIT_ULL(I40E_RXD_QW1_STATUS_TSYNVALID_SHIFT)
-
-enum i40e_rx_desc_fltstat_values {
- I40E_RX_DESC_FLTSTAT_NO_DATA = 0,
- I40E_RX_DESC_FLTSTAT_RSV_FD_ID = 1, /* 16byte desc? FD_ID : RSV */
- I40E_RX_DESC_FLTSTAT_RSV = 2,
- I40E_RX_DESC_FLTSTAT_RSS_HASH = 3,
-};
-
-#define I40E_RXD_QW1_ERROR_SHIFT 19
-#define I40E_RXD_QW1_ERROR_MASK (0xFFUL << I40E_RXD_QW1_ERROR_SHIFT)
-
-enum i40e_rx_desc_error_bits {
- /* Note: These are predefined bit offsets */
- I40E_RX_DESC_ERROR_RXE_SHIFT = 0,
- I40E_RX_DESC_ERROR_RECIPE_SHIFT = 1,
- I40E_RX_DESC_ERROR_HBO_SHIFT = 2,
- I40E_RX_DESC_ERROR_L3L4E_SHIFT = 3, /* 3 BITS */
- I40E_RX_DESC_ERROR_IPE_SHIFT = 3,
- I40E_RX_DESC_ERROR_L4E_SHIFT = 4,
- I40E_RX_DESC_ERROR_EIPE_SHIFT = 5,
- I40E_RX_DESC_ERROR_OVERSIZE_SHIFT = 6,
- I40E_RX_DESC_ERROR_PPRS_SHIFT = 7
-};
-
-enum i40e_rx_desc_error_l3l4e_fcoe_masks {
- I40E_RX_DESC_ERROR_L3L4E_NONE = 0,
- I40E_RX_DESC_ERROR_L3L4E_PROT = 1,
- I40E_RX_DESC_ERROR_L3L4E_FC = 2,
- I40E_RX_DESC_ERROR_L3L4E_DMAC_ERR = 3,
- I40E_RX_DESC_ERROR_L3L4E_DMAC_WARN = 4
-};
-
-#define I40E_RXD_QW1_PTYPE_SHIFT 30
-#define I40E_RXD_QW1_PTYPE_MASK (0xFFULL << I40E_RXD_QW1_PTYPE_SHIFT)
-
-/* Packet type non-ip values */
-enum i40e_rx_l2_ptype {
- I40E_RX_PTYPE_L2_RESERVED = 0,
- I40E_RX_PTYPE_L2_MAC_PAY2 = 1,
- I40E_RX_PTYPE_L2_TIMESYNC_PAY2 = 2,
- I40E_RX_PTYPE_L2_FIP_PAY2 = 3,
- I40E_RX_PTYPE_L2_OUI_PAY2 = 4,
- I40E_RX_PTYPE_L2_MACCNTRL_PAY2 = 5,
- I40E_RX_PTYPE_L2_LLDP_PAY2 = 6,
- I40E_RX_PTYPE_L2_ECP_PAY2 = 7,
- I40E_RX_PTYPE_L2_EVB_PAY2 = 8,
- I40E_RX_PTYPE_L2_QCN_PAY2 = 9,
- I40E_RX_PTYPE_L2_EAPOL_PAY2 = 10,
- I40E_RX_PTYPE_L2_ARP = 11,
- I40E_RX_PTYPE_L2_FCOE_PAY3 = 12,
- I40E_RX_PTYPE_L2_FCOE_FCDATA_PAY3 = 13,
- I40E_RX_PTYPE_L2_FCOE_FCRDY_PAY3 = 14,
- I40E_RX_PTYPE_L2_FCOE_FCRSP_PAY3 = 15,
- I40E_RX_PTYPE_L2_FCOE_FCOTHER_PA = 16,
- I40E_RX_PTYPE_L2_FCOE_VFT_PAY3 = 17,
- I40E_RX_PTYPE_L2_FCOE_VFT_FCDATA = 18,
- I40E_RX_PTYPE_L2_FCOE_VFT_FCRDY = 19,
- I40E_RX_PTYPE_L2_FCOE_VFT_FCRSP = 20,
- I40E_RX_PTYPE_L2_FCOE_VFT_FCOTHER = 21,
- I40E_RX_PTYPE_GRENAT4_MAC_PAY3 = 58,
- I40E_RX_PTYPE_GRENAT4_MACVLAN_IPV6_ICMP_PAY4 = 87,
- I40E_RX_PTYPE_GRENAT6_MAC_PAY3 = 124,
- I40E_RX_PTYPE_GRENAT6_MACVLAN_IPV6_ICMP_PAY4 = 153
-};
-
-struct i40e_rx_ptype_decoded {
- u32 ptype:8;
- u32 known:1;
- u32 outer_ip:1;
- u32 outer_ip_ver:1;
- u32 outer_frag:1;
- u32 tunnel_type:3;
- u32 tunnel_end_prot:2;
- u32 tunnel_end_frag:1;
- u32 inner_prot:4;
- u32 payload_layer:3;
-};
-
-enum i40e_rx_ptype_outer_ip {
- I40E_RX_PTYPE_OUTER_L2 = 0,
- I40E_RX_PTYPE_OUTER_IP = 1
-};
-
-enum i40e_rx_ptype_outer_ip_ver {
- I40E_RX_PTYPE_OUTER_NONE = 0,
- I40E_RX_PTYPE_OUTER_IPV4 = 0,
- I40E_RX_PTYPE_OUTER_IPV6 = 1
-};
-
-enum i40e_rx_ptype_outer_fragmented {
- I40E_RX_PTYPE_NOT_FRAG = 0,
- I40E_RX_PTYPE_FRAG = 1
-};
-
-enum i40e_rx_ptype_tunnel_type {
- I40E_RX_PTYPE_TUNNEL_NONE = 0,
- I40E_RX_PTYPE_TUNNEL_IP_IP = 1,
- I40E_RX_PTYPE_TUNNEL_IP_GRENAT = 2,
- I40E_RX_PTYPE_TUNNEL_IP_GRENAT_MAC = 3,
- I40E_RX_PTYPE_TUNNEL_IP_GRENAT_MAC_VLAN = 4,
-};
-
-enum i40e_rx_ptype_tunnel_end_prot {
- I40E_RX_PTYPE_TUNNEL_END_NONE = 0,
- I40E_RX_PTYPE_TUNNEL_END_IPV4 = 1,
- I40E_RX_PTYPE_TUNNEL_END_IPV6 = 2,
-};
-
-enum i40e_rx_ptype_inner_prot {
- I40E_RX_PTYPE_INNER_PROT_NONE = 0,
- I40E_RX_PTYPE_INNER_PROT_UDP = 1,
- I40E_RX_PTYPE_INNER_PROT_TCP = 2,
- I40E_RX_PTYPE_INNER_PROT_SCTP = 3,
- I40E_RX_PTYPE_INNER_PROT_ICMP = 4,
- I40E_RX_PTYPE_INNER_PROT_TIMESYNC = 5
-};
-
-enum i40e_rx_ptype_payload_layer {
- I40E_RX_PTYPE_PAYLOAD_LAYER_NONE = 0,
- I40E_RX_PTYPE_PAYLOAD_LAYER_PAY2 = 1,
- I40E_RX_PTYPE_PAYLOAD_LAYER_PAY3 = 2,
- I40E_RX_PTYPE_PAYLOAD_LAYER_PAY4 = 3,
-};
-
-#define I40E_RXD_QW1_LENGTH_PBUF_SHIFT 38
-#define I40E_RXD_QW1_LENGTH_PBUF_MASK (0x3FFFULL << \
- I40E_RXD_QW1_LENGTH_PBUF_SHIFT)
-
-#define I40E_RXD_QW1_LENGTH_HBUF_SHIFT 52
-#define I40E_RXD_QW1_LENGTH_HBUF_MASK (0x7FFULL << \
- I40E_RXD_QW1_LENGTH_HBUF_SHIFT)
-
-#define I40E_RXD_QW1_LENGTH_SPH_SHIFT 63
-#define I40E_RXD_QW1_LENGTH_SPH_MASK BIT_ULL(I40E_RXD_QW1_LENGTH_SPH_SHIFT)
-
-enum i40e_rx_desc_ext_status_bits {
- /* Note: These are predefined bit offsets */
- I40E_RX_DESC_EXT_STATUS_L2TAG2P_SHIFT = 0,
- I40E_RX_DESC_EXT_STATUS_L2TAG3P_SHIFT = 1,
- I40E_RX_DESC_EXT_STATUS_FLEXBL_SHIFT = 2, /* 2 BITS */
- I40E_RX_DESC_EXT_STATUS_FLEXBH_SHIFT = 4, /* 2 BITS */
- I40E_RX_DESC_EXT_STATUS_FDLONGB_SHIFT = 9,
- I40E_RX_DESC_EXT_STATUS_FCOELONGB_SHIFT = 10,
- I40E_RX_DESC_EXT_STATUS_PELONGB_SHIFT = 11,
-};
-
-enum i40e_rx_desc_pe_status_bits {
- /* Note: These are predefined bit offsets */
- I40E_RX_DESC_PE_STATUS_QPID_SHIFT = 0, /* 18 BITS */
- I40E_RX_DESC_PE_STATUS_L4PORT_SHIFT = 0, /* 16 BITS */
- I40E_RX_DESC_PE_STATUS_IPINDEX_SHIFT = 16, /* 8 BITS */
- I40E_RX_DESC_PE_STATUS_QPIDHIT_SHIFT = 24,
- I40E_RX_DESC_PE_STATUS_APBVTHIT_SHIFT = 25,
- I40E_RX_DESC_PE_STATUS_PORTV_SHIFT = 26,
- I40E_RX_DESC_PE_STATUS_URG_SHIFT = 27,
- I40E_RX_DESC_PE_STATUS_IPFRAG_SHIFT = 28,
- I40E_RX_DESC_PE_STATUS_IPOPT_SHIFT = 29
-};
-
-#define I40E_RX_PROG_STATUS_DESC_LENGTH_SHIFT 38
-#define I40E_RX_PROG_STATUS_DESC_LENGTH 0x2000000
-
-#define I40E_RX_PROG_STATUS_DESC_QW1_PROGID_SHIFT 2
-#define I40E_RX_PROG_STATUS_DESC_QW1_PROGID_MASK (0x7UL << \
- I40E_RX_PROG_STATUS_DESC_QW1_PROGID_SHIFT)
-
-#define I40E_RX_PROG_STATUS_DESC_QW1_ERROR_SHIFT 19
-#define I40E_RX_PROG_STATUS_DESC_QW1_ERROR_MASK (0x3FUL << \
- I40E_RX_PROG_STATUS_DESC_QW1_ERROR_SHIFT)
-
-enum i40e_rx_prog_status_desc_status_bits {
- /* Note: These are predefined bit offsets */
- I40E_RX_PROG_STATUS_DESC_DD_SHIFT = 0,
- I40E_RX_PROG_STATUS_DESC_PROG_ID_SHIFT = 2 /* 3 BITS */
-};
-
-enum i40e_rx_prog_status_desc_prog_id_masks {
- I40E_RX_PROG_STATUS_DESC_FD_FILTER_STATUS = 1,
- I40E_RX_PROG_STATUS_DESC_FCOE_CTXT_PROG_STATUS = 2,
- I40E_RX_PROG_STATUS_DESC_FCOE_CTXT_INVL_STATUS = 4,
-};
-
-enum i40e_rx_prog_status_desc_error_bits {
- /* Note: These are predefined bit offsets */
- I40E_RX_PROG_STATUS_DESC_FD_TBL_FULL_SHIFT = 0,
- I40E_RX_PROG_STATUS_DESC_NO_FD_ENTRY_SHIFT = 1,
- I40E_RX_PROG_STATUS_DESC_FCOE_TBL_FULL_SHIFT = 2,
- I40E_RX_PROG_STATUS_DESC_FCOE_CONFLICT_SHIFT = 3
-};
-
-/* TX Descriptor */
-struct i40e_tx_desc {
- __le64 buffer_addr; /* Address of descriptor's data buf */
- __le64 cmd_type_offset_bsz;
-};
-
-#define I40E_TXD_QW1_DTYPE_SHIFT 0
-#define I40E_TXD_QW1_DTYPE_MASK (0xFUL << I40E_TXD_QW1_DTYPE_SHIFT)
-
-enum i40e_tx_desc_dtype_value {
- I40E_TX_DESC_DTYPE_DATA = 0x0,
- I40E_TX_DESC_DTYPE_NOP = 0x1, /* same as Context desc */
- I40E_TX_DESC_DTYPE_CONTEXT = 0x1,
- I40E_TX_DESC_DTYPE_FCOE_CTX = 0x2,
- I40E_TX_DESC_DTYPE_FILTER_PROG = 0x8,
- I40E_TX_DESC_DTYPE_DDP_CTX = 0x9,
- I40E_TX_DESC_DTYPE_FLEX_DATA = 0xB,
- I40E_TX_DESC_DTYPE_FLEX_CTX_1 = 0xC,
- I40E_TX_DESC_DTYPE_FLEX_CTX_2 = 0xD,
- I40E_TX_DESC_DTYPE_DESC_DONE = 0xF
-};
-
-#define I40E_TXD_QW1_CMD_SHIFT 4
-#define I40E_TXD_QW1_CMD_MASK (0x3FFUL << I40E_TXD_QW1_CMD_SHIFT)
-
-enum i40e_tx_desc_cmd_bits {
- I40E_TX_DESC_CMD_EOP = 0x0001,
- I40E_TX_DESC_CMD_RS = 0x0002,
- I40E_TX_DESC_CMD_ICRC = 0x0004,
- I40E_TX_DESC_CMD_IL2TAG1 = 0x0008,
- I40E_TX_DESC_CMD_DUMMY = 0x0010,
- I40E_TX_DESC_CMD_IIPT_NONIP = 0x0000, /* 2 BITS */
- I40E_TX_DESC_CMD_IIPT_IPV6 = 0x0020, /* 2 BITS */
- I40E_TX_DESC_CMD_IIPT_IPV4 = 0x0040, /* 2 BITS */
- I40E_TX_DESC_CMD_IIPT_IPV4_CSUM = 0x0060, /* 2 BITS */
- I40E_TX_DESC_CMD_FCOET = 0x0080,
- I40E_TX_DESC_CMD_L4T_EOFT_UNK = 0x0000, /* 2 BITS */
- I40E_TX_DESC_CMD_L4T_EOFT_TCP = 0x0100, /* 2 BITS */
- I40E_TX_DESC_CMD_L4T_EOFT_SCTP = 0x0200, /* 2 BITS */
- I40E_TX_DESC_CMD_L4T_EOFT_UDP = 0x0300, /* 2 BITS */
- I40E_TX_DESC_CMD_L4T_EOFT_EOF_N = 0x0000, /* 2 BITS */
- I40E_TX_DESC_CMD_L4T_EOFT_EOF_T = 0x0100, /* 2 BITS */
- I40E_TX_DESC_CMD_L4T_EOFT_EOF_NI = 0x0200, /* 2 BITS */
- I40E_TX_DESC_CMD_L4T_EOFT_EOF_A = 0x0300, /* 2 BITS */
-};
-
-#define I40E_TXD_QW1_OFFSET_SHIFT 16
-#define I40E_TXD_QW1_OFFSET_MASK (0x3FFFFULL << \
- I40E_TXD_QW1_OFFSET_SHIFT)
-
-enum i40e_tx_desc_length_fields {
- /* Note: These are predefined bit offsets */
- I40E_TX_DESC_LENGTH_MACLEN_SHIFT = 0, /* 7 BITS */
- I40E_TX_DESC_LENGTH_IPLEN_SHIFT = 7, /* 7 BITS */
- I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT = 14 /* 4 BITS */
-};
-
-#define I40E_TXD_QW1_TX_BUF_SZ_SHIFT 34
-#define I40E_TXD_QW1_TX_BUF_SZ_MASK (0x3FFFULL << \
- I40E_TXD_QW1_TX_BUF_SZ_SHIFT)
-
-#define I40E_TXD_QW1_L2TAG1_SHIFT 48
-#define I40E_TXD_QW1_L2TAG1_MASK (0xFFFFULL << I40E_TXD_QW1_L2TAG1_SHIFT)
-
-/* Context descriptors */
-struct i40e_tx_context_desc {
- __le32 tunneling_params;
- __le16 l2tag2;
- __le16 rsvd;
- __le64 type_cmd_tso_mss;
-};
-
-#define I40E_TXD_CTX_QW1_DTYPE_SHIFT 0
-#define I40E_TXD_CTX_QW1_DTYPE_MASK (0xFUL << I40E_TXD_CTX_QW1_DTYPE_SHIFT)
-
-#define I40E_TXD_CTX_QW1_CMD_SHIFT 4
-#define I40E_TXD_CTX_QW1_CMD_MASK (0xFFFFUL << I40E_TXD_CTX_QW1_CMD_SHIFT)
-
-enum i40e_tx_ctx_desc_cmd_bits {
- I40E_TX_CTX_DESC_TSO = 0x01,
- I40E_TX_CTX_DESC_TSYN = 0x02,
- I40E_TX_CTX_DESC_IL2TAG2 = 0x04,
- I40E_TX_CTX_DESC_IL2TAG2_IL2H = 0x08,
- I40E_TX_CTX_DESC_SWTCH_NOTAG = 0x00,
- I40E_TX_CTX_DESC_SWTCH_UPLINK = 0x10,
- I40E_TX_CTX_DESC_SWTCH_LOCAL = 0x20,
- I40E_TX_CTX_DESC_SWTCH_VSI = 0x30,
- I40E_TX_CTX_DESC_SWPE = 0x40
-};
-
-#define I40E_TXD_CTX_QW1_TSO_LEN_SHIFT 30
-#define I40E_TXD_CTX_QW1_TSO_LEN_MASK (0x3FFFFULL << \
- I40E_TXD_CTX_QW1_TSO_LEN_SHIFT)
-
-#define I40E_TXD_CTX_QW1_MSS_SHIFT 50
-#define I40E_TXD_CTX_QW1_MSS_MASK (0x3FFFULL << \
- I40E_TXD_CTX_QW1_MSS_SHIFT)
-
-#define I40E_TXD_CTX_QW1_VSI_SHIFT 50
-#define I40E_TXD_CTX_QW1_VSI_MASK (0x1FFULL << I40E_TXD_CTX_QW1_VSI_SHIFT)
-
-#define I40E_TXD_CTX_QW0_EXT_IP_SHIFT 0
-#define I40E_TXD_CTX_QW0_EXT_IP_MASK (0x3ULL << \
- I40E_TXD_CTX_QW0_EXT_IP_SHIFT)
-
-enum i40e_tx_ctx_desc_eipt_offload {
- I40E_TX_CTX_EXT_IP_NONE = 0x0,
- I40E_TX_CTX_EXT_IP_IPV6 = 0x1,
- I40E_TX_CTX_EXT_IP_IPV4_NO_CSUM = 0x2,
- I40E_TX_CTX_EXT_IP_IPV4 = 0x3
-};
-
-#define I40E_TXD_CTX_QW0_EXT_IPLEN_SHIFT 2
-#define I40E_TXD_CTX_QW0_EXT_IPLEN_MASK (0x3FULL << \
- I40E_TXD_CTX_QW0_EXT_IPLEN_SHIFT)
-
-#define I40E_TXD_CTX_QW0_NATT_SHIFT 9
-#define I40E_TXD_CTX_QW0_NATT_MASK (0x3ULL << I40E_TXD_CTX_QW0_NATT_SHIFT)
-
-#define I40E_TXD_CTX_UDP_TUNNELING BIT_ULL(I40E_TXD_CTX_QW0_NATT_SHIFT)
-#define I40E_TXD_CTX_GRE_TUNNELING (0x2ULL << I40E_TXD_CTX_QW0_NATT_SHIFT)
-
-#define I40E_TXD_CTX_QW0_EIP_NOINC_SHIFT 11
-#define I40E_TXD_CTX_QW0_EIP_NOINC_MASK \
- BIT_ULL(I40E_TXD_CTX_QW0_EIP_NOINC_SHIFT)
-
-#define I40E_TXD_CTX_EIP_NOINC_IPID_CONST I40E_TXD_CTX_QW0_EIP_NOINC_MASK
-
-#define I40E_TXD_CTX_QW0_NATLEN_SHIFT 12
-#define I40E_TXD_CTX_QW0_NATLEN_MASK (0X7FULL << \
- I40E_TXD_CTX_QW0_NATLEN_SHIFT)
-
-#define I40E_TXD_CTX_QW0_DECTTL_SHIFT 19
-#define I40E_TXD_CTX_QW0_DECTTL_MASK (0xFULL << \
- I40E_TXD_CTX_QW0_DECTTL_SHIFT)
-
-#define I40E_TXD_CTX_QW0_L4T_CS_SHIFT 23
-#define I40E_TXD_CTX_QW0_L4T_CS_MASK BIT_ULL(I40E_TXD_CTX_QW0_L4T_CS_SHIFT)
-struct i40e_filter_program_desc {
- __le32 qindex_flex_ptype_vsi;
- __le32 rsvd;
- __le32 dtype_cmd_cntindex;
- __le32 fd_id;
-};
-#define I40E_TXD_FLTR_QW0_QINDEX_SHIFT 0
-#define I40E_TXD_FLTR_QW0_QINDEX_MASK (0x7FFUL << \
- I40E_TXD_FLTR_QW0_QINDEX_SHIFT)
-#define I40E_TXD_FLTR_QW0_FLEXOFF_SHIFT 11
-#define I40E_TXD_FLTR_QW0_FLEXOFF_MASK (0x7UL << \
- I40E_TXD_FLTR_QW0_FLEXOFF_SHIFT)
-#define I40E_TXD_FLTR_QW0_PCTYPE_SHIFT 17
-#define I40E_TXD_FLTR_QW0_PCTYPE_MASK (0x3FUL << \
- I40E_TXD_FLTR_QW0_PCTYPE_SHIFT)
-
-/* Packet Classifier Types for filters */
-enum i40e_filter_pctype {
- /* Note: Values 0-28 are reserved for future use.
- * Value 29, 30, 32 are not supported on XL710 and X710.
- */
- I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP = 29,
- I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP = 30,
- I40E_FILTER_PCTYPE_NONF_IPV4_UDP = 31,
- I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK = 32,
- I40E_FILTER_PCTYPE_NONF_IPV4_TCP = 33,
- I40E_FILTER_PCTYPE_NONF_IPV4_SCTP = 34,
- I40E_FILTER_PCTYPE_NONF_IPV4_OTHER = 35,
- I40E_FILTER_PCTYPE_FRAG_IPV4 = 36,
- /* Note: Values 37-38 are reserved for future use.
- * Value 39, 40, 42 are not supported on XL710 and X710.
- */
- I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP = 39,
- I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP = 40,
- I40E_FILTER_PCTYPE_NONF_IPV6_UDP = 41,
- I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK = 42,
- I40E_FILTER_PCTYPE_NONF_IPV6_TCP = 43,
- I40E_FILTER_PCTYPE_NONF_IPV6_SCTP = 44,
- I40E_FILTER_PCTYPE_NONF_IPV6_OTHER = 45,
- I40E_FILTER_PCTYPE_FRAG_IPV6 = 46,
- /* Note: Value 47 is reserved for future use */
- I40E_FILTER_PCTYPE_FCOE_OX = 48,
- I40E_FILTER_PCTYPE_FCOE_RX = 49,
- I40E_FILTER_PCTYPE_FCOE_OTHER = 50,
- /* Note: Values 51-62 are reserved for future use */
- I40E_FILTER_PCTYPE_L2_PAYLOAD = 63,
-};
-
-enum i40e_filter_program_desc_dest {
- I40E_FILTER_PROGRAM_DESC_DEST_DROP_PACKET = 0x0,
- I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX = 0x1,
- I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_OTHER = 0x2,
-};
-
-enum i40e_filter_program_desc_fd_status {
- I40E_FILTER_PROGRAM_DESC_FD_STATUS_NONE = 0x0,
- I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID = 0x1,
- I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID_4FLEX_BYTES = 0x2,
- I40E_FILTER_PROGRAM_DESC_FD_STATUS_8FLEX_BYTES = 0x3,
-};
-
-#define I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT 23
-#define I40E_TXD_FLTR_QW0_DEST_VSI_MASK (0x1FFUL << \
- I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT)
-
-#define I40E_TXD_FLTR_QW1_CMD_SHIFT 4
-#define I40E_TXD_FLTR_QW1_CMD_MASK (0xFFFFULL << \
- I40E_TXD_FLTR_QW1_CMD_SHIFT)
-
-#define I40E_TXD_FLTR_QW1_PCMD_SHIFT (0x0ULL + I40E_TXD_FLTR_QW1_CMD_SHIFT)
-#define I40E_TXD_FLTR_QW1_PCMD_MASK (0x7ULL << I40E_TXD_FLTR_QW1_PCMD_SHIFT)
-
-enum i40e_filter_program_desc_pcmd {
- I40E_FILTER_PROGRAM_DESC_PCMD_ADD_UPDATE = 0x1,
- I40E_FILTER_PROGRAM_DESC_PCMD_REMOVE = 0x2,
-};
-
-#define I40E_TXD_FLTR_QW1_DEST_SHIFT (0x3ULL + I40E_TXD_FLTR_QW1_CMD_SHIFT)
-#define I40E_TXD_FLTR_QW1_DEST_MASK (0x3ULL << I40E_TXD_FLTR_QW1_DEST_SHIFT)
-
-#define I40E_TXD_FLTR_QW1_CNT_ENA_SHIFT (0x7ULL + I40E_TXD_FLTR_QW1_CMD_SHIFT)
-#define I40E_TXD_FLTR_QW1_CNT_ENA_MASK BIT_ULL(I40E_TXD_FLTR_QW1_CNT_ENA_SHIFT)
-
-#define I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT (0x9ULL + \
- I40E_TXD_FLTR_QW1_CMD_SHIFT)
-#define I40E_TXD_FLTR_QW1_FD_STATUS_MASK (0x3ULL << \
- I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT)
-
-#define I40E_TXD_FLTR_QW1_CNTINDEX_SHIFT 20
-#define I40E_TXD_FLTR_QW1_CNTINDEX_MASK (0x1FFUL << \
- I40E_TXD_FLTR_QW1_CNTINDEX_SHIFT)
-
-enum i40e_filter_type {
- I40E_FLOW_DIRECTOR_FLTR = 0,
- I40E_PE_QUAD_HASH_FLTR = 1,
- I40E_ETHERTYPE_FLTR,
- I40E_FCOE_CTX_FLTR,
- I40E_MAC_VLAN_FLTR,
- I40E_HASH_FLTR
-};
-
-struct i40e_vsi_context {
- u16 seid;
- u16 uplink_seid;
- u16 vsi_number;
- u16 vsis_allocated;
- u16 vsis_unallocated;
- u16 flags;
- u8 pf_num;
- u8 vf_num;
- u8 connection_type;
- struct i40e_aqc_vsi_properties_data info;
-};
-
-struct i40e_veb_context {
- u16 seid;
- u16 uplink_seid;
- u16 veb_number;
- u16 vebs_allocated;
- u16 vebs_unallocated;
- u16 flags;
- struct i40e_aqc_get_veb_parameters_completion info;
-};
-
-/* Statistics collected by each port, VSI, VEB, and S-channel */
-struct i40e_eth_stats {
- u64 rx_bytes; /* gorc */
- u64 rx_unicast; /* uprc */
- u64 rx_multicast; /* mprc */
- u64 rx_broadcast; /* bprc */
- u64 rx_discards; /* rdpc */
- u64 rx_unknown_protocol; /* rupp */
- u64 tx_bytes; /* gotc */
- u64 tx_unicast; /* uptc */
- u64 tx_multicast; /* mptc */
- u64 tx_broadcast; /* bptc */
- u64 tx_discards; /* tdpc */
- u64 tx_errors; /* tepc */
-};
-
-/* Statistics collected per VEB per TC */
-struct i40e_veb_tc_stats {
- u64 tc_rx_packets[I40E_MAX_TRAFFIC_CLASS];
- u64 tc_rx_bytes[I40E_MAX_TRAFFIC_CLASS];
- u64 tc_tx_packets[I40E_MAX_TRAFFIC_CLASS];
- u64 tc_tx_bytes[I40E_MAX_TRAFFIC_CLASS];
-};
-
-/* Statistics collected by the MAC */
-struct i40e_hw_port_stats {
- /* eth stats collected by the port */
- struct i40e_eth_stats eth;
-
- /* additional port specific stats */
- u64 tx_dropped_link_down; /* tdold */
- u64 crc_errors; /* crcerrs */
- u64 illegal_bytes; /* illerrc */
- u64 error_bytes; /* errbc */
- u64 mac_local_faults; /* mlfc */
- u64 mac_remote_faults; /* mrfc */
- u64 rx_length_errors; /* rlec */
- u64 link_xon_rx; /* lxonrxc */
- u64 link_xoff_rx; /* lxoffrxc */
- u64 priority_xon_rx[8]; /* pxonrxc[8] */
- u64 priority_xoff_rx[8]; /* pxoffrxc[8] */
- u64 link_xon_tx; /* lxontxc */
- u64 link_xoff_tx; /* lxofftxc */
- u64 priority_xon_tx[8]; /* pxontxc[8] */
- u64 priority_xoff_tx[8]; /* pxofftxc[8] */
- u64 priority_xon_2_xoff[8]; /* pxon2offc[8] */
- u64 rx_size_64; /* prc64 */
- u64 rx_size_127; /* prc127 */
- u64 rx_size_255; /* prc255 */
- u64 rx_size_511; /* prc511 */
- u64 rx_size_1023; /* prc1023 */
- u64 rx_size_1522; /* prc1522 */
- u64 rx_size_big; /* prc9522 */
- u64 rx_undersize; /* ruc */
- u64 rx_fragments; /* rfc */
- u64 rx_oversize; /* roc */
- u64 rx_jabber; /* rjc */
- u64 tx_size_64; /* ptc64 */
- u64 tx_size_127; /* ptc127 */
- u64 tx_size_255; /* ptc255 */
- u64 tx_size_511; /* ptc511 */
- u64 tx_size_1023; /* ptc1023 */
- u64 tx_size_1522; /* ptc1522 */
- u64 tx_size_big; /* ptc9522 */
- u64 mac_short_packet_dropped; /* mspdc */
- u64 checksum_error; /* xec */
- /* flow director stats */
- u64 fd_atr_match;
- u64 fd_sb_match;
- u64 fd_atr_tunnel_match;
- u32 fd_atr_status;
- u32 fd_sb_status;
- /* EEE LPI */
- u32 tx_lpi_status;
- u32 rx_lpi_status;
- u64 tx_lpi_count; /* etlpic */
- u64 rx_lpi_count; /* erlpic */
-};
-
-/* Checksum and Shadow RAM pointers */
-#define I40E_SR_NVM_CONTROL_WORD 0x00
-#define I40E_EMP_MODULE_PTR 0x0F
-#define I40E_SR_EMP_MODULE_PTR 0x48
-#define I40E_NVM_OEM_VER_OFF 0x83
-#define I40E_SR_NVM_DEV_STARTER_VERSION 0x18
-#define I40E_SR_NVM_WAKE_ON_LAN 0x19
-#define I40E_SR_ALTERNATE_SAN_MAC_ADDRESS_PTR 0x27
-#define I40E_SR_NVM_EETRACK_LO 0x2D
-#define I40E_SR_NVM_EETRACK_HI 0x2E
-#define I40E_SR_VPD_PTR 0x2F
-#define I40E_SR_PCIE_ALT_AUTO_LOAD_PTR 0x3E
-#define I40E_SR_SW_CHECKSUM_WORD 0x3F
-
-/* Auxiliary field, mask and shift definition for Shadow RAM and NVM Flash */
-#define I40E_SR_VPD_MODULE_MAX_SIZE 1024
-#define I40E_SR_PCIE_ALT_MODULE_MAX_SIZE 1024
-#define I40E_SR_CONTROL_WORD_1_SHIFT 0x06
-#define I40E_SR_CONTROL_WORD_1_MASK (0x03 << I40E_SR_CONTROL_WORD_1_SHIFT)
-#define I40E_SR_CONTROL_WORD_1_NVM_BANK_VALID BIT(5)
-#define I40E_SR_NVM_MAP_STRUCTURE_TYPE BIT(12)
-#define I40E_PTR_TYPE BIT(15)
-
-/* Shadow RAM related */
-#define I40E_SR_SECTOR_SIZE_IN_WORDS 0x800
-#define I40E_SR_WORDS_IN_1KB 512
-/* Checksum should be calculated such that after adding all the words,
- * including the checksum word itself, the sum should be 0xBABA.
- */
-#define I40E_SR_SW_CHECKSUM_BASE 0xBABA
-
-#define I40E_SRRD_SRCTL_ATTEMPTS 100000
-
-enum i40e_switch_element_types {
- I40E_SWITCH_ELEMENT_TYPE_MAC = 1,
- I40E_SWITCH_ELEMENT_TYPE_PF = 2,
- I40E_SWITCH_ELEMENT_TYPE_VF = 3,
- I40E_SWITCH_ELEMENT_TYPE_EMP = 4,
- I40E_SWITCH_ELEMENT_TYPE_BMC = 6,
- I40E_SWITCH_ELEMENT_TYPE_PE = 16,
- I40E_SWITCH_ELEMENT_TYPE_VEB = 17,
- I40E_SWITCH_ELEMENT_TYPE_PA = 18,
- I40E_SWITCH_ELEMENT_TYPE_VSI = 19,
-};
-
-/* Supported EtherType filters */
-enum i40e_ether_type_index {
- I40E_ETHER_TYPE_1588 = 0,
- I40E_ETHER_TYPE_FIP = 1,
- I40E_ETHER_TYPE_OUI_EXTENDED = 2,
- I40E_ETHER_TYPE_MAC_CONTROL = 3,
- I40E_ETHER_TYPE_LLDP = 4,
- I40E_ETHER_TYPE_EVB_PROTOCOL1 = 5,
- I40E_ETHER_TYPE_EVB_PROTOCOL2 = 6,
- I40E_ETHER_TYPE_QCN_CNM = 7,
- I40E_ETHER_TYPE_8021X = 8,
- I40E_ETHER_TYPE_ARP = 9,
- I40E_ETHER_TYPE_RSV1 = 10,
- I40E_ETHER_TYPE_RSV2 = 11,
-};
-
-/* Filter context base size is 1K */
-#define I40E_HASH_FILTER_BASE_SIZE 1024
-/* Supported Hash filter values */
-enum i40e_hash_filter_size {
- I40E_HASH_FILTER_SIZE_1K = 0,
- I40E_HASH_FILTER_SIZE_2K = 1,
- I40E_HASH_FILTER_SIZE_4K = 2,
- I40E_HASH_FILTER_SIZE_8K = 3,
- I40E_HASH_FILTER_SIZE_16K = 4,
- I40E_HASH_FILTER_SIZE_32K = 5,
- I40E_HASH_FILTER_SIZE_64K = 6,
- I40E_HASH_FILTER_SIZE_128K = 7,
- I40E_HASH_FILTER_SIZE_256K = 8,
- I40E_HASH_FILTER_SIZE_512K = 9,
- I40E_HASH_FILTER_SIZE_1M = 10,
-};
-
-/* DMA context base size is 0.5K */
-#define I40E_DMA_CNTX_BASE_SIZE 512
-/* Supported DMA context values */
-enum i40e_dma_cntx_size {
- I40E_DMA_CNTX_SIZE_512 = 0,
- I40E_DMA_CNTX_SIZE_1K = 1,
- I40E_DMA_CNTX_SIZE_2K = 2,
- I40E_DMA_CNTX_SIZE_4K = 3,
- I40E_DMA_CNTX_SIZE_8K = 4,
- I40E_DMA_CNTX_SIZE_16K = 5,
- I40E_DMA_CNTX_SIZE_32K = 6,
- I40E_DMA_CNTX_SIZE_64K = 7,
- I40E_DMA_CNTX_SIZE_128K = 8,
- I40E_DMA_CNTX_SIZE_256K = 9,
-};
-
-/* Supported Hash look up table (LUT) sizes */
-enum i40e_hash_lut_size {
- I40E_HASH_LUT_SIZE_128 = 0,
- I40E_HASH_LUT_SIZE_512 = 1,
-};
-
-/* Structure to hold a per PF filter control settings */
-struct i40e_filter_control_settings {
- /* number of PE Quad Hash filter buckets */
- enum i40e_hash_filter_size pe_filt_num;
- /* number of PE Quad Hash contexts */
- enum i40e_dma_cntx_size pe_cntx_num;
- /* number of FCoE filter buckets */
- enum i40e_hash_filter_size fcoe_filt_num;
- /* number of FCoE DDP contexts */
- enum i40e_dma_cntx_size fcoe_cntx_num;
- /* size of the Hash LUT */
- enum i40e_hash_lut_size hash_lut_size;
- /* enable FDIR filters for PF and its VFs */
- bool enable_fdir;
- /* enable Ethertype filters for PF and its VFs */
- bool enable_ethtype;
- /* enable MAC/VLAN filters for PF and its VFs */
- bool enable_macvlan;
-};
-
-/* Structure to hold device level control filter counts */
-struct i40e_control_filter_stats {
- u16 mac_etype_used; /* Used perfect match MAC/EtherType filters */
- u16 etype_used; /* Used perfect EtherType filters */
- u16 mac_etype_free; /* Un-used perfect match MAC/EtherType filters */
- u16 etype_free; /* Un-used perfect EtherType filters */
-};
-
-enum i40e_reset_type {
- I40E_RESET_POR = 0,
- I40E_RESET_CORER = 1,
- I40E_RESET_GLOBR = 2,
- I40E_RESET_EMPR = 3,
-};
-
-/* IEEE 802.1AB LLDP Agent Variables from NVM */
-#define I40E_NVM_LLDP_CFG_PTR 0x06
-#define I40E_SR_LLDP_CFG_PTR 0x31
-
-/* RSS Hash Table Size */
-#define I40E_PFQF_CTL_0_HASHLUTSIZE_512 0x00010000
-
-/* INPUT SET MASK for RSS, flow director and flexible payload */
-#define I40E_FD_INSET_L3_SRC_SHIFT 47
-#define I40E_FD_INSET_L3_SRC_WORD_MASK (0x3ULL << \
- I40E_FD_INSET_L3_SRC_SHIFT)
-#define I40E_FD_INSET_L3_DST_SHIFT 35
-#define I40E_FD_INSET_L3_DST_WORD_MASK (0x3ULL << \
- I40E_FD_INSET_L3_DST_SHIFT)
-#define I40E_FD_INSET_L4_SRC_SHIFT 34
-#define I40E_FD_INSET_L4_SRC_WORD_MASK (0x1ULL << \
- I40E_FD_INSET_L4_SRC_SHIFT)
-#define I40E_FD_INSET_L4_DST_SHIFT 33
-#define I40E_FD_INSET_L4_DST_WORD_MASK (0x1ULL << \
- I40E_FD_INSET_L4_DST_SHIFT)
-#define I40E_FD_INSET_VERIFY_TAG_SHIFT 31
-#define I40E_FD_INSET_VERIFY_TAG_WORD_MASK (0x3ULL << \
- I40E_FD_INSET_VERIFY_TAG_SHIFT)
-
-#define I40E_FD_INSET_FLEX_WORD50_SHIFT 17
-#define I40E_FD_INSET_FLEX_WORD50_MASK (0x1ULL << \
- I40E_FD_INSET_FLEX_WORD50_SHIFT)
-#define I40E_FD_INSET_FLEX_WORD51_SHIFT 16
-#define I40E_FD_INSET_FLEX_WORD51_MASK (0x1ULL << \
- I40E_FD_INSET_FLEX_WORD51_SHIFT)
-#define I40E_FD_INSET_FLEX_WORD52_SHIFT 15
-#define I40E_FD_INSET_FLEX_WORD52_MASK (0x1ULL << \
- I40E_FD_INSET_FLEX_WORD52_SHIFT)
-#define I40E_FD_INSET_FLEX_WORD53_SHIFT 14
-#define I40E_FD_INSET_FLEX_WORD53_MASK (0x1ULL << \
- I40E_FD_INSET_FLEX_WORD53_SHIFT)
-#define I40E_FD_INSET_FLEX_WORD54_SHIFT 13
-#define I40E_FD_INSET_FLEX_WORD54_MASK (0x1ULL << \
- I40E_FD_INSET_FLEX_WORD54_SHIFT)
-#define I40E_FD_INSET_FLEX_WORD55_SHIFT 12
-#define I40E_FD_INSET_FLEX_WORD55_MASK (0x1ULL << \
- I40E_FD_INSET_FLEX_WORD55_SHIFT)
-#define I40E_FD_INSET_FLEX_WORD56_SHIFT 11
-#define I40E_FD_INSET_FLEX_WORD56_MASK (0x1ULL << \
- I40E_FD_INSET_FLEX_WORD56_SHIFT)
-#define I40E_FD_INSET_FLEX_WORD57_SHIFT 10
-#define I40E_FD_INSET_FLEX_WORD57_MASK (0x1ULL << \
- I40E_FD_INSET_FLEX_WORD57_SHIFT)
-
-/* Version format for Dynamic Device Personalization(DDP) */
-struct i40e_ddp_version {
- u8 major;
- u8 minor;
- u8 update;
- u8 draft;
-};
-
-#define I40E_DDP_NAME_SIZE 32
-
-/* Package header */
-struct i40e_package_header {
- struct i40e_ddp_version version;
- u32 segment_count;
- u32 segment_offset[1];
-};
-
-/* Generic segment header */
-struct i40e_generic_seg_header {
-#define SEGMENT_TYPE_METADATA 0x00000001
-#define SEGMENT_TYPE_NOTES 0x00000002
-#define SEGMENT_TYPE_I40E 0x00000011
-#define SEGMENT_TYPE_X722 0x00000012
- u32 type;
- struct i40e_ddp_version version;
- u32 size;
- char name[I40E_DDP_NAME_SIZE];
-};
-
-struct i40e_metadata_segment {
- struct i40e_generic_seg_header header;
- struct i40e_ddp_version version;
- u32 track_id;
- char name[I40E_DDP_NAME_SIZE];
-};
-
-struct i40e_device_id_entry {
- u32 vendor_dev_id;
- u32 sub_vendor_dev_id;
-};
-
-struct i40e_profile_segment {
- struct i40e_generic_seg_header header;
- struct i40e_ddp_version version;
- char name[I40E_DDP_NAME_SIZE];
- u32 device_table_count;
- struct i40e_device_id_entry device_table[1];
-};
-
-struct i40e_section_table {
- u32 section_count;
- u32 section_offset[1];
-};
-
-struct i40e_profile_section_header {
- u16 tbl_size;
- u16 data_end;
- struct {
-#define SECTION_TYPE_INFO 0x00000010
-#define SECTION_TYPE_MMIO 0x00000800
-#define SECTION_TYPE_AQ 0x00000801
-#define SECTION_TYPE_NOTE 0x80000000
-#define SECTION_TYPE_NAME 0x80000001
- u32 type;
- u32 offset;
- u32 size;
- } section;
-};
-
-struct i40e_profile_info {
- u32 track_id;
- struct i40e_ddp_version version;
- u8 op;
-#define I40E_DDP_ADD_TRACKID 0x01
-#define I40E_DDP_REMOVE_TRACKID 0x02
- u8 reserved[7];
- u8 name[I40E_DDP_NAME_SIZE];
-};
-#endif /* _I40E_TYPE_H_ */
diff --git a/drivers/net/ethernet/intel/i40evf/i40evf.h b/drivers/net/ethernet/intel/i40evf/i40evf.h
deleted file mode 100644
index 96e537a35000..000000000000
--- a/drivers/net/ethernet/intel/i40evf/i40evf.h
+++ /dev/null
@@ -1,427 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/* Copyright(c) 2013 - 2018 Intel Corporation. */
-
-#ifndef _I40EVF_H_
-#define _I40EVF_H_
-
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/aer.h>
-#include <linux/netdevice.h>
-#include <linux/vmalloc.h>
-#include <linux/interrupt.h>
-#include <linux/ethtool.h>
-#include <linux/if_vlan.h>
-#include <linux/ip.h>
-#include <linux/tcp.h>
-#include <linux/sctp.h>
-#include <linux/ipv6.h>
-#include <linux/kernel.h>
-#include <linux/bitops.h>
-#include <linux/timer.h>
-#include <linux/workqueue.h>
-#include <linux/wait.h>
-#include <linux/delay.h>
-#include <linux/gfp.h>
-#include <linux/skbuff.h>
-#include <linux/dma-mapping.h>
-#include <linux/etherdevice.h>
-#include <linux/socket.h>
-#include <linux/jiffies.h>
-#include <net/ip6_checksum.h>
-#include <net/pkt_cls.h>
-#include <net/udp.h>
-#include <net/tc_act/tc_gact.h>
-#include <net/tc_act/tc_mirred.h>
-
-#include "i40e_type.h"
-#include <linux/avf/virtchnl.h>
-#include "i40e_txrx.h"
-
-#define DEFAULT_DEBUG_LEVEL_SHIFT 3
-#define PFX "i40evf: "
-
-/* VSI state flags shared with common code */
-enum i40evf_vsi_state_t {
- __I40E_VSI_DOWN,
- /* This must be last as it determines the size of the BITMAP */
- __I40E_VSI_STATE_SIZE__,
-};
-
-/* dummy struct to make common code less painful */
-struct i40e_vsi {
- struct i40evf_adapter *back;
- struct net_device *netdev;
- unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
- u16 seid;
- u16 id;
- DECLARE_BITMAP(state, __I40E_VSI_STATE_SIZE__);
- int base_vector;
- u16 work_limit;
- u16 qs_handle;
- void *priv; /* client driver data reference. */
-};
-
-/* How many Rx Buffers do we bundle into one write to the hardware ? */
-#define I40EVF_RX_BUFFER_WRITE 16 /* Must be power of 2 */
-#define I40EVF_DEFAULT_TXD 512
-#define I40EVF_DEFAULT_RXD 512
-#define I40EVF_MAX_TXD 4096
-#define I40EVF_MIN_TXD 64
-#define I40EVF_MAX_RXD 4096
-#define I40EVF_MIN_RXD 64
-#define I40EVF_REQ_DESCRIPTOR_MULTIPLE 32
-#define I40EVF_MAX_AQ_BUF_SIZE 4096
-#define I40EVF_AQ_LEN 32
-#define I40EVF_AQ_MAX_ERR 20 /* times to try before resetting AQ */
-
-#define MAXIMUM_ETHERNET_VLAN_SIZE (VLAN_ETH_FRAME_LEN + ETH_FCS_LEN)
-
-#define I40E_RX_DESC(R, i) (&(((union i40e_32byte_rx_desc *)((R)->desc))[i]))
-#define I40E_TX_DESC(R, i) (&(((struct i40e_tx_desc *)((R)->desc))[i]))
-#define I40E_TX_CTXTDESC(R, i) \
- (&(((struct i40e_tx_context_desc *)((R)->desc))[i]))
-#define I40EVF_MAX_REQ_QUEUES 4
-
-#define I40EVF_HKEY_ARRAY_SIZE ((I40E_VFQF_HKEY_MAX_INDEX + 1) * 4)
-#define I40EVF_HLUT_ARRAY_SIZE ((I40E_VFQF_HLUT_MAX_INDEX + 1) * 4)
-#define I40EVF_MBPS_DIVISOR 125000 /* divisor to convert to Mbps */
-
-/* MAX_MSIX_Q_VECTORS of these are allocated,
- * but we only use one per queue-specific vector.
- */
-struct i40e_q_vector {
- struct i40evf_adapter *adapter;
- struct i40e_vsi *vsi;
- struct napi_struct napi;
- struct i40e_ring_container rx;
- struct i40e_ring_container tx;
- u32 ring_mask;
- u8 itr_countdown; /* when 0 should adjust adaptive ITR */
- u8 num_ringpairs; /* total number of ring pairs in vector */
- u16 v_idx; /* index in the vsi->q_vector array. */
- u16 reg_idx; /* register index of the interrupt */
- char name[IFNAMSIZ + 15];
- bool arm_wb_state;
- cpumask_t affinity_mask;
- struct irq_affinity_notify affinity_notify;
-};
-
-/* Helper macros to switch between ints/sec and what the register uses.
- * And yes, it's the same math going both ways. The lowest value
- * supported by all of the i40e hardware is 8.
- */
-#define EITR_INTS_PER_SEC_TO_REG(_eitr) \
- ((_eitr) ? (1000000000 / ((_eitr) * 256)) : 8)
-#define EITR_REG_TO_INTS_PER_SEC EITR_INTS_PER_SEC_TO_REG
-
-#define I40EVF_DESC_UNUSED(R) \
- ((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \
- (R)->next_to_clean - (R)->next_to_use - 1)
-
-#define I40EVF_RX_DESC_ADV(R, i) \
- (&(((union i40e_adv_rx_desc *)((R).desc))[i]))
-#define I40EVF_TX_DESC_ADV(R, i) \
- (&(((union i40e_adv_tx_desc *)((R).desc))[i]))
-#define I40EVF_TX_CTXTDESC_ADV(R, i) \
- (&(((struct i40e_adv_tx_context_desc *)((R).desc))[i]))
-
-#define OTHER_VECTOR 1
-#define NONQ_VECS (OTHER_VECTOR)
-
-#define MIN_MSIX_Q_VECTORS 1
-#define MIN_MSIX_COUNT (MIN_MSIX_Q_VECTORS + NONQ_VECS)
-
-#define I40EVF_QUEUE_END_OF_LIST 0x7FF
-#define I40EVF_FREE_VECTOR 0x7FFF
-struct i40evf_mac_filter {
- struct list_head list;
- u8 macaddr[ETH_ALEN];
- bool remove; /* filter needs to be removed */
- bool add; /* filter needs to be added */
-};
-
-struct i40evf_vlan_filter {
- struct list_head list;
- u16 vlan;
- bool remove; /* filter needs to be removed */
- bool add; /* filter needs to be added */
-};
-
-#define I40EVF_MAX_TRAFFIC_CLASS 4
-/* State of traffic class creation */
-enum i40evf_tc_state_t {
- __I40EVF_TC_INVALID, /* no traffic class, default state */
- __I40EVF_TC_RUNNING, /* traffic classes have been created */
-};
-
-/* channel info */
-struct i40evf_channel_config {
- struct virtchnl_channel_info ch_info[I40EVF_MAX_TRAFFIC_CLASS];
- enum i40evf_tc_state_t state;
- u8 total_qps;
-};
-
-/* State of cloud filter */
-enum i40evf_cloud_filter_state_t {
- __I40EVF_CF_INVALID, /* cloud filter not added */
- __I40EVF_CF_ADD_PENDING, /* cloud filter pending add by the PF */
- __I40EVF_CF_DEL_PENDING, /* cloud filter pending del by the PF */
- __I40EVF_CF_ACTIVE, /* cloud filter is active */
-};
-
-/* Driver state. The order of these is important! */
-enum i40evf_state_t {
- __I40EVF_STARTUP, /* driver loaded, probe complete */
- __I40EVF_REMOVE, /* driver is being unloaded */
- __I40EVF_INIT_VERSION_CHECK, /* aq msg sent, awaiting reply */
- __I40EVF_INIT_GET_RESOURCES, /* aq msg sent, awaiting reply */
- __I40EVF_INIT_SW, /* got resources, setting up structs */
- __I40EVF_RESETTING, /* in reset */
- /* Below here, watchdog is running */
- __I40EVF_DOWN, /* ready, can be opened */
- __I40EVF_DOWN_PENDING, /* descending, waiting for watchdog */
- __I40EVF_TESTING, /* in ethtool self-test */
- __I40EVF_RUNNING, /* opened, working */
-};
-
-enum i40evf_critical_section_t {
- __I40EVF_IN_CRITICAL_TASK, /* cannot be interrupted */
- __I40EVF_IN_CLIENT_TASK,
- __I40EVF_IN_REMOVE_TASK, /* device being removed */
-};
-
-#define I40EVF_CLOUD_FIELD_OMAC 0x01
-#define I40EVF_CLOUD_FIELD_IMAC 0x02
-#define I40EVF_CLOUD_FIELD_IVLAN 0x04
-#define I40EVF_CLOUD_FIELD_TEN_ID 0x08
-#define I40EVF_CLOUD_FIELD_IIP 0x10
-
-#define I40EVF_CF_FLAGS_OMAC I40EVF_CLOUD_FIELD_OMAC
-#define I40EVF_CF_FLAGS_IMAC I40EVF_CLOUD_FIELD_IMAC
-#define I40EVF_CF_FLAGS_IMAC_IVLAN (I40EVF_CLOUD_FIELD_IMAC |\
- I40EVF_CLOUD_FIELD_IVLAN)
-#define I40EVF_CF_FLAGS_IMAC_TEN_ID (I40EVF_CLOUD_FIELD_IMAC |\
- I40EVF_CLOUD_FIELD_TEN_ID)
-#define I40EVF_CF_FLAGS_OMAC_TEN_ID_IMAC (I40EVF_CLOUD_FIELD_OMAC |\
- I40EVF_CLOUD_FIELD_IMAC |\
- I40EVF_CLOUD_FIELD_TEN_ID)
-#define I40EVF_CF_FLAGS_IMAC_IVLAN_TEN_ID (I40EVF_CLOUD_FIELD_IMAC |\
- I40EVF_CLOUD_FIELD_IVLAN |\
- I40EVF_CLOUD_FIELD_TEN_ID)
-#define I40EVF_CF_FLAGS_IIP I40E_CLOUD_FIELD_IIP
-
-/* bookkeeping of cloud filters */
-struct i40evf_cloud_filter {
- enum i40evf_cloud_filter_state_t state;
- struct list_head list;
- struct virtchnl_filter f;
- unsigned long cookie;
- bool del; /* filter needs to be deleted */
- bool add; /* filter needs to be added */
-};
-
-/* board specific private data structure */
-struct i40evf_adapter {
- struct timer_list watchdog_timer;
- struct work_struct reset_task;
- struct work_struct adminq_task;
- struct delayed_work client_task;
- struct delayed_work init_task;
- wait_queue_head_t down_waitqueue;
- struct i40e_q_vector *q_vectors;
- struct list_head vlan_filter_list;
- struct list_head mac_filter_list;
- /* Lock to protect accesses to MAC and VLAN lists */
- spinlock_t mac_vlan_list_lock;
- char misc_vector_name[IFNAMSIZ + 9];
- int num_active_queues;
- int num_req_queues;
-
- /* TX */
- struct i40e_ring *tx_rings;
- u32 tx_timeout_count;
- u32 tx_desc_count;
-
- /* RX */
- struct i40e_ring *rx_rings;
- u64 hw_csum_rx_error;
- u32 rx_desc_count;
- int num_msix_vectors;
- int num_iwarp_msix;
- int iwarp_base_vector;
- u32 client_pending;
- struct i40e_client_instance *cinst;
- struct msix_entry *msix_entries;
-
- u32 flags;
-#define I40EVF_FLAG_RX_CSUM_ENABLED BIT(0)
-#define I40EVF_FLAG_PF_COMMS_FAILED BIT(3)
-#define I40EVF_FLAG_RESET_PENDING BIT(4)
-#define I40EVF_FLAG_RESET_NEEDED BIT(5)
-#define I40EVF_FLAG_WB_ON_ITR_CAPABLE BIT(6)
-#define I40EVF_FLAG_ADDR_SET_BY_PF BIT(8)
-#define I40EVF_FLAG_SERVICE_CLIENT_REQUESTED BIT(9)
-#define I40EVF_FLAG_CLIENT_NEEDS_OPEN BIT(10)
-#define I40EVF_FLAG_CLIENT_NEEDS_CLOSE BIT(11)
-#define I40EVF_FLAG_CLIENT_NEEDS_L2_PARAMS BIT(12)
-#define I40EVF_FLAG_PROMISC_ON BIT(13)
-#define I40EVF_FLAG_ALLMULTI_ON BIT(14)
-#define I40EVF_FLAG_LEGACY_RX BIT(15)
-#define I40EVF_FLAG_REINIT_ITR_NEEDED BIT(16)
-#define I40EVF_FLAG_QUEUES_DISABLED BIT(17)
-/* duplicates for common code */
-#define I40E_FLAG_DCB_ENABLED 0
-#define I40E_FLAG_RX_CSUM_ENABLED I40EVF_FLAG_RX_CSUM_ENABLED
-#define I40E_FLAG_LEGACY_RX I40EVF_FLAG_LEGACY_RX
- /* flags for admin queue service task */
- u32 aq_required;
-#define I40EVF_FLAG_AQ_ENABLE_QUEUES BIT(0)
-#define I40EVF_FLAG_AQ_DISABLE_QUEUES BIT(1)
-#define I40EVF_FLAG_AQ_ADD_MAC_FILTER BIT(2)
-#define I40EVF_FLAG_AQ_ADD_VLAN_FILTER BIT(3)
-#define I40EVF_FLAG_AQ_DEL_MAC_FILTER BIT(4)
-#define I40EVF_FLAG_AQ_DEL_VLAN_FILTER BIT(5)
-#define I40EVF_FLAG_AQ_CONFIGURE_QUEUES BIT(6)
-#define I40EVF_FLAG_AQ_MAP_VECTORS BIT(7)
-#define I40EVF_FLAG_AQ_HANDLE_RESET BIT(8)
-#define I40EVF_FLAG_AQ_CONFIGURE_RSS BIT(9) /* direct AQ config */
-#define I40EVF_FLAG_AQ_GET_CONFIG BIT(10)
-/* Newer style, RSS done by the PF so we can ignore hardware vagaries. */
-#define I40EVF_FLAG_AQ_GET_HENA BIT(11)
-#define I40EVF_FLAG_AQ_SET_HENA BIT(12)
-#define I40EVF_FLAG_AQ_SET_RSS_KEY BIT(13)
-#define I40EVF_FLAG_AQ_SET_RSS_LUT BIT(14)
-#define I40EVF_FLAG_AQ_REQUEST_PROMISC BIT(15)
-#define I40EVF_FLAG_AQ_RELEASE_PROMISC BIT(16)
-#define I40EVF_FLAG_AQ_REQUEST_ALLMULTI BIT(17)
-#define I40EVF_FLAG_AQ_RELEASE_ALLMULTI BIT(18)
-#define I40EVF_FLAG_AQ_ENABLE_VLAN_STRIPPING BIT(19)
-#define I40EVF_FLAG_AQ_DISABLE_VLAN_STRIPPING BIT(20)
-#define I40EVF_FLAG_AQ_ENABLE_CHANNELS BIT(21)
-#define I40EVF_FLAG_AQ_DISABLE_CHANNELS BIT(22)
-#define I40EVF_FLAG_AQ_ADD_CLOUD_FILTER BIT(23)
-#define I40EVF_FLAG_AQ_DEL_CLOUD_FILTER BIT(24)
-
- /* OS defined structs */
- struct net_device *netdev;
- struct pci_dev *pdev;
-
- struct i40e_hw hw; /* defined in i40e_type.h */
-
- enum i40evf_state_t state;
- unsigned long crit_section;
-
- struct work_struct watchdog_task;
- bool netdev_registered;
- bool link_up;
- enum virtchnl_link_speed link_speed;
- enum virtchnl_ops current_op;
-#define CLIENT_ALLOWED(_a) ((_a)->vf_res ? \
- (_a)->vf_res->vf_cap_flags & \
- VIRTCHNL_VF_OFFLOAD_IWARP : \
- 0)
-#define CLIENT_ENABLED(_a) ((_a)->cinst)
-/* RSS by the PF should be preferred over RSS via other methods. */
-#define RSS_PF(_a) ((_a)->vf_res->vf_cap_flags & \
- VIRTCHNL_VF_OFFLOAD_RSS_PF)
-#define RSS_AQ(_a) ((_a)->vf_res->vf_cap_flags & \
- VIRTCHNL_VF_OFFLOAD_RSS_AQ)
-#define RSS_REG(_a) (!((_a)->vf_res->vf_cap_flags & \
- (VIRTCHNL_VF_OFFLOAD_RSS_AQ | \
- VIRTCHNL_VF_OFFLOAD_RSS_PF)))
-#define VLAN_ALLOWED(_a) ((_a)->vf_res->vf_cap_flags & \
- VIRTCHNL_VF_OFFLOAD_VLAN)
- struct virtchnl_vf_resource *vf_res; /* incl. all VSIs */
- struct virtchnl_vsi_resource *vsi_res; /* our LAN VSI */
- struct virtchnl_version_info pf_version;
-#define PF_IS_V11(_a) (((_a)->pf_version.major == 1) && \
- ((_a)->pf_version.minor == 1))
- u16 msg_enable;
- struct i40e_eth_stats current_stats;
- struct i40e_vsi vsi;
- u32 aq_wait_count;
- /* RSS stuff */
- u64 hena;
- u16 rss_key_size;
- u16 rss_lut_size;
- u8 *rss_key;
- u8 *rss_lut;
- /* ADQ related members */
- struct i40evf_channel_config ch_config;
- u8 num_tc;
- struct list_head cloud_filter_list;
- /* lock to protest access to the cloud filter list */
- spinlock_t cloud_filter_list_lock;
- u16 num_cloud_filters;
-};
-
-
-/* Ethtool Private Flags */
-
-/* lan device */
-struct i40e_device {
- struct list_head list;
- struct i40evf_adapter *vf;
-};
-
-/* needed by i40evf_ethtool.c */
-extern char i40evf_driver_name[];
-extern const char i40evf_driver_version[];
-
-int i40evf_up(struct i40evf_adapter *adapter);
-void i40evf_down(struct i40evf_adapter *adapter);
-int i40evf_process_config(struct i40evf_adapter *adapter);
-void i40evf_schedule_reset(struct i40evf_adapter *adapter);
-void i40evf_reset(struct i40evf_adapter *adapter);
-void i40evf_set_ethtool_ops(struct net_device *netdev);
-void i40evf_update_stats(struct i40evf_adapter *adapter);
-void i40evf_reset_interrupt_capability(struct i40evf_adapter *adapter);
-int i40evf_init_interrupt_scheme(struct i40evf_adapter *adapter);
-void i40evf_irq_enable_queues(struct i40evf_adapter *adapter, u32 mask);
-void i40evf_free_all_tx_resources(struct i40evf_adapter *adapter);
-void i40evf_free_all_rx_resources(struct i40evf_adapter *adapter);
-
-void i40e_napi_add_all(struct i40evf_adapter *adapter);
-void i40e_napi_del_all(struct i40evf_adapter *adapter);
-
-int i40evf_send_api_ver(struct i40evf_adapter *adapter);
-int i40evf_verify_api_ver(struct i40evf_adapter *adapter);
-int i40evf_send_vf_config_msg(struct i40evf_adapter *adapter);
-int i40evf_get_vf_config(struct i40evf_adapter *adapter);
-void i40evf_irq_enable(struct i40evf_adapter *adapter, bool flush);
-void i40evf_configure_queues(struct i40evf_adapter *adapter);
-void i40evf_deconfigure_queues(struct i40evf_adapter *adapter);
-void i40evf_enable_queues(struct i40evf_adapter *adapter);
-void i40evf_disable_queues(struct i40evf_adapter *adapter);
-void i40evf_map_queues(struct i40evf_adapter *adapter);
-int i40evf_request_queues(struct i40evf_adapter *adapter, int num);
-void i40evf_add_ether_addrs(struct i40evf_adapter *adapter);
-void i40evf_del_ether_addrs(struct i40evf_adapter *adapter);
-void i40evf_add_vlans(struct i40evf_adapter *adapter);
-void i40evf_del_vlans(struct i40evf_adapter *adapter);
-void i40evf_set_promiscuous(struct i40evf_adapter *adapter, int flags);
-void i40evf_request_stats(struct i40evf_adapter *adapter);
-void i40evf_request_reset(struct i40evf_adapter *adapter);
-void i40evf_get_hena(struct i40evf_adapter *adapter);
-void i40evf_set_hena(struct i40evf_adapter *adapter);
-void i40evf_set_rss_key(struct i40evf_adapter *adapter);
-void i40evf_set_rss_lut(struct i40evf_adapter *adapter);
-void i40evf_enable_vlan_stripping(struct i40evf_adapter *adapter);
-void i40evf_disable_vlan_stripping(struct i40evf_adapter *adapter);
-void i40evf_virtchnl_completion(struct i40evf_adapter *adapter,
- enum virtchnl_ops v_opcode,
- i40e_status v_retval, u8 *msg, u16 msglen);
-int i40evf_config_rss(struct i40evf_adapter *adapter);
-int i40evf_lan_add_device(struct i40evf_adapter *adapter);
-int i40evf_lan_del_device(struct i40evf_adapter *adapter);
-void i40evf_client_subtask(struct i40evf_adapter *adapter);
-void i40evf_notify_client_message(struct i40e_vsi *vsi, u8 *msg, u16 len);
-void i40evf_notify_client_l2_params(struct i40e_vsi *vsi);
-void i40evf_notify_client_open(struct i40e_vsi *vsi);
-void i40evf_notify_client_close(struct i40e_vsi *vsi, bool reset);
-void i40evf_enable_channels(struct i40evf_adapter *adapter);
-void i40evf_disable_channels(struct i40evf_adapter *adapter);
-void i40evf_add_cloud_filter(struct i40evf_adapter *adapter);
-void i40evf_del_cloud_filter(struct i40evf_adapter *adapter);
-#endif /* _I40EVF_H_ */
diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c b/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c
deleted file mode 100644
index 69efe0aec76a..000000000000
--- a/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c
+++ /dev/null
@@ -1,820 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* Copyright(c) 2013 - 2018 Intel Corporation. */
-
-/* ethtool support for i40evf */
-#include "i40evf.h"
-
-#include <linux/uaccess.h>
-
-struct i40evf_stats {
- char stat_string[ETH_GSTRING_LEN];
- int stat_offset;
-};
-
-#define I40EVF_STAT(_name, _stat) { \
- .stat_string = _name, \
- .stat_offset = offsetof(struct i40evf_adapter, _stat) \
-}
-
-/* All stats are u64, so we don't need to track the size of the field. */
-static const struct i40evf_stats i40evf_gstrings_stats[] = {
- I40EVF_STAT("rx_bytes", current_stats.rx_bytes),
- I40EVF_STAT("rx_unicast", current_stats.rx_unicast),
- I40EVF_STAT("rx_multicast", current_stats.rx_multicast),
- I40EVF_STAT("rx_broadcast", current_stats.rx_broadcast),
- I40EVF_STAT("rx_discards", current_stats.rx_discards),
- I40EVF_STAT("rx_unknown_protocol", current_stats.rx_unknown_protocol),
- I40EVF_STAT("tx_bytes", current_stats.tx_bytes),
- I40EVF_STAT("tx_unicast", current_stats.tx_unicast),
- I40EVF_STAT("tx_multicast", current_stats.tx_multicast),
- I40EVF_STAT("tx_broadcast", current_stats.tx_broadcast),
- I40EVF_STAT("tx_discards", current_stats.tx_discards),
- I40EVF_STAT("tx_errors", current_stats.tx_errors),
-};
-
-#define I40EVF_GLOBAL_STATS_LEN ARRAY_SIZE(i40evf_gstrings_stats)
-#define I40EVF_QUEUE_STATS_LEN(_dev) \
- (((struct i40evf_adapter *)\
- netdev_priv(_dev))->num_active_queues \
- * 2 * (sizeof(struct i40e_queue_stats) / sizeof(u64)))
-#define I40EVF_STATS_LEN(_dev) \
- (I40EVF_GLOBAL_STATS_LEN + I40EVF_QUEUE_STATS_LEN(_dev))
-
-/* For now we have one and only one private flag and it is only defined
- * when we have support for the SKIP_CPU_SYNC DMA attribute. Instead
- * of leaving all this code sitting around empty we will strip it unless
- * our one private flag is actually available.
- */
-struct i40evf_priv_flags {
- char flag_string[ETH_GSTRING_LEN];
- u32 flag;
- bool read_only;
-};
-
-#define I40EVF_PRIV_FLAG(_name, _flag, _read_only) { \
- .flag_string = _name, \
- .flag = _flag, \
- .read_only = _read_only, \
-}
-
-static const struct i40evf_priv_flags i40evf_gstrings_priv_flags[] = {
- I40EVF_PRIV_FLAG("legacy-rx", I40EVF_FLAG_LEGACY_RX, 0),
-};
-
-#define I40EVF_PRIV_FLAGS_STR_LEN ARRAY_SIZE(i40evf_gstrings_priv_flags)
-
-/**
- * i40evf_get_link_ksettings - Get Link Speed and Duplex settings
- * @netdev: network interface device structure
- * @cmd: ethtool command
- *
- * Reports speed/duplex settings. Because this is a VF, we don't know what
- * kind of link we really have, so we fake it.
- **/
-static int i40evf_get_link_ksettings(struct net_device *netdev,
- struct ethtool_link_ksettings *cmd)
-{
- struct i40evf_adapter *adapter = netdev_priv(netdev);
-
- ethtool_link_ksettings_zero_link_mode(cmd, supported);
- cmd->base.autoneg = AUTONEG_DISABLE;
- cmd->base.port = PORT_NONE;
- /* Set speed and duplex */
- switch (adapter->link_speed) {
- case I40E_LINK_SPEED_40GB:
- cmd->base.speed = SPEED_40000;
- break;
- case I40E_LINK_SPEED_25GB:
-#ifdef SPEED_25000
- cmd->base.speed = SPEED_25000;
-#else
- netdev_info(netdev,
- "Speed is 25G, display not supported by this version of ethtool.\n");
-#endif
- break;
- case I40E_LINK_SPEED_20GB:
- cmd->base.speed = SPEED_20000;
- break;
- case I40E_LINK_SPEED_10GB:
- cmd->base.speed = SPEED_10000;
- break;
- case I40E_LINK_SPEED_1GB:
- cmd->base.speed = SPEED_1000;
- break;
- case I40E_LINK_SPEED_100MB:
- cmd->base.speed = SPEED_100;
- break;
- default:
- break;
- }
- cmd->base.duplex = DUPLEX_FULL;
-
- return 0;
-}
-
-/**
- * i40evf_get_sset_count - Get length of string set
- * @netdev: network interface device structure
- * @sset: id of string set
- *
- * Reports size of string table. This driver only supports
- * strings for statistics.
- **/
-static int i40evf_get_sset_count(struct net_device *netdev, int sset)
-{
- if (sset == ETH_SS_STATS)
- return I40EVF_STATS_LEN(netdev);
- else if (sset == ETH_SS_PRIV_FLAGS)
- return I40EVF_PRIV_FLAGS_STR_LEN;
- else
- return -EINVAL;
-}
-
-/**
- * i40evf_get_ethtool_stats - report device statistics
- * @netdev: network interface device structure
- * @stats: ethtool statistics structure
- * @data: pointer to data buffer
- *
- * All statistics are added to the data buffer as an array of u64.
- **/
-static void i40evf_get_ethtool_stats(struct net_device *netdev,
- struct ethtool_stats *stats, u64 *data)
-{
- struct i40evf_adapter *adapter = netdev_priv(netdev);
- unsigned int i, j;
- char *p;
-
- for (i = 0; i < I40EVF_GLOBAL_STATS_LEN; i++) {
- p = (char *)adapter + i40evf_gstrings_stats[i].stat_offset;
- data[i] = *(u64 *)p;
- }
- for (j = 0; j < adapter->num_active_queues; j++) {
- data[i++] = adapter->tx_rings[j].stats.packets;
- data[i++] = adapter->tx_rings[j].stats.bytes;
- }
- for (j = 0; j < adapter->num_active_queues; j++) {
- data[i++] = adapter->rx_rings[j].stats.packets;
- data[i++] = adapter->rx_rings[j].stats.bytes;
- }
-}
-
-/**
- * i40evf_get_strings - Get string set
- * @netdev: network interface device structure
- * @sset: id of string set
- * @data: buffer for string data
- *
- * Builds stats string table.
- **/
-static void i40evf_get_strings(struct net_device *netdev, u32 sset, u8 *data)
-{
- struct i40evf_adapter *adapter = netdev_priv(netdev);
- u8 *p = data;
- int i;
-
- if (sset == ETH_SS_STATS) {
- for (i = 0; i < (int)I40EVF_GLOBAL_STATS_LEN; i++) {
- memcpy(p, i40evf_gstrings_stats[i].stat_string,
- ETH_GSTRING_LEN);
- p += ETH_GSTRING_LEN;
- }
- for (i = 0; i < adapter->num_active_queues; i++) {
- snprintf(p, ETH_GSTRING_LEN, "tx-%u.packets", i);
- p += ETH_GSTRING_LEN;
- snprintf(p, ETH_GSTRING_LEN, "tx-%u.bytes", i);
- p += ETH_GSTRING_LEN;
- }
- for (i = 0; i < adapter->num_active_queues; i++) {
- snprintf(p, ETH_GSTRING_LEN, "rx-%u.packets", i);
- p += ETH_GSTRING_LEN;
- snprintf(p, ETH_GSTRING_LEN, "rx-%u.bytes", i);
- p += ETH_GSTRING_LEN;
- }
- } else if (sset == ETH_SS_PRIV_FLAGS) {
- for (i = 0; i < I40EVF_PRIV_FLAGS_STR_LEN; i++) {
- snprintf(p, ETH_GSTRING_LEN, "%s",
- i40evf_gstrings_priv_flags[i].flag_string);
- p += ETH_GSTRING_LEN;
- }
- }
-}
-
-/**
- * i40evf_get_priv_flags - report device private flags
- * @netdev: network interface device structure
- *
- * The get string set count and the string set should be matched for each
- * flag returned. Add new strings for each flag to the i40e_gstrings_priv_flags
- * array.
- *
- * Returns a u32 bitmap of flags.
- **/
-static u32 i40evf_get_priv_flags(struct net_device *netdev)
-{
- struct i40evf_adapter *adapter = netdev_priv(netdev);
- u32 i, ret_flags = 0;
-
- for (i = 0; i < I40EVF_PRIV_FLAGS_STR_LEN; i++) {
- const struct i40evf_priv_flags *priv_flags;
-
- priv_flags = &i40evf_gstrings_priv_flags[i];
-
- if (priv_flags->flag & adapter->flags)
- ret_flags |= BIT(i);
- }
-
- return ret_flags;
-}
-
-/**
- * i40evf_set_priv_flags - set private flags
- * @netdev: network interface device structure
- * @flags: bit flags to be set
- **/
-static int i40evf_set_priv_flags(struct net_device *netdev, u32 flags)
-{
- struct i40evf_adapter *adapter = netdev_priv(netdev);
- u32 orig_flags, new_flags, changed_flags;
- u32 i;
-
- orig_flags = READ_ONCE(adapter->flags);
- new_flags = orig_flags;
-
- for (i = 0; i < I40EVF_PRIV_FLAGS_STR_LEN; i++) {
- const struct i40evf_priv_flags *priv_flags;
-
- priv_flags = &i40evf_gstrings_priv_flags[i];
-
- if (flags & BIT(i))
- new_flags |= priv_flags->flag;
- else
- new_flags &= ~(priv_flags->flag);
-
- if (priv_flags->read_only &&
- ((orig_flags ^ new_flags) & ~BIT(i)))
- return -EOPNOTSUPP;
- }
-
- /* Before we finalize any flag changes, any checks which we need to
- * perform to determine if the new flags will be supported should go
- * here...
- */
-
- /* Compare and exchange the new flags into place. If we failed, that
- * is if cmpxchg returns anything but the old value, this means
- * something else must have modified the flags variable since we
- * copied it. We'll just punt with an error and log something in the
- * message buffer.
- */
- if (cmpxchg(&adapter->flags, orig_flags, new_flags) != orig_flags) {
- dev_warn(&adapter->pdev->dev,
- "Unable to update adapter->flags as it was modified by another thread...\n");
- return -EAGAIN;
- }
-
- changed_flags = orig_flags ^ new_flags;
-
- /* Process any additional changes needed as a result of flag changes.
- * The changed_flags value reflects the list of bits that were changed
- * in the code above.
- */
-
- /* issue a reset to force legacy-rx change to take effect */
- if (changed_flags & I40EVF_FLAG_LEGACY_RX) {
- if (netif_running(netdev)) {
- adapter->flags |= I40EVF_FLAG_RESET_NEEDED;
- schedule_work(&adapter->reset_task);
- }
- }
-
- return 0;
-}
-
-/**
- * i40evf_get_msglevel - Get debug message level
- * @netdev: network interface device structure
- *
- * Returns current debug message level.
- **/
-static u32 i40evf_get_msglevel(struct net_device *netdev)
-{
- struct i40evf_adapter *adapter = netdev_priv(netdev);
-
- return adapter->msg_enable;
-}
-
-/**
- * i40evf_set_msglevel - Set debug message level
- * @netdev: network interface device structure
- * @data: message level
- *
- * Set current debug message level. Higher values cause the driver to
- * be noisier.
- **/
-static void i40evf_set_msglevel(struct net_device *netdev, u32 data)
-{
- struct i40evf_adapter *adapter = netdev_priv(netdev);
-
- if (I40E_DEBUG_USER & data)
- adapter->hw.debug_mask = data;
- adapter->msg_enable = data;
-}
-
-/**
- * i40evf_get_drvinfo - Get driver info
- * @netdev: network interface device structure
- * @drvinfo: ethool driver info structure
- *
- * Returns information about the driver and device for display to the user.
- **/
-static void i40evf_get_drvinfo(struct net_device *netdev,
- struct ethtool_drvinfo *drvinfo)
-{
- struct i40evf_adapter *adapter = netdev_priv(netdev);
-
- strlcpy(drvinfo->driver, i40evf_driver_name, 32);
- strlcpy(drvinfo->version, i40evf_driver_version, 32);
- strlcpy(drvinfo->fw_version, "N/A", 4);
- strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
- drvinfo->n_priv_flags = I40EVF_PRIV_FLAGS_STR_LEN;
-}
-
-/**
- * i40evf_get_ringparam - Get ring parameters
- * @netdev: network interface device structure
- * @ring: ethtool ringparam structure
- *
- * Returns current ring parameters. TX and RX rings are reported separately,
- * but the number of rings is not reported.
- **/
-static void i40evf_get_ringparam(struct net_device *netdev,
- struct ethtool_ringparam *ring)
-{
- struct i40evf_adapter *adapter = netdev_priv(netdev);
-
- ring->rx_max_pending = I40EVF_MAX_RXD;
- ring->tx_max_pending = I40EVF_MAX_TXD;
- ring->rx_pending = adapter->rx_desc_count;
- ring->tx_pending = adapter->tx_desc_count;
-}
-
-/**
- * i40evf_set_ringparam - Set ring parameters
- * @netdev: network interface device structure
- * @ring: ethtool ringparam structure
- *
- * Sets ring parameters. TX and RX rings are controlled separately, but the
- * number of rings is not specified, so all rings get the same settings.
- **/
-static int i40evf_set_ringparam(struct net_device *netdev,
- struct ethtool_ringparam *ring)
-{
- struct i40evf_adapter *adapter = netdev_priv(netdev);
- u32 new_rx_count, new_tx_count;
-
- if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
- return -EINVAL;
-
- new_tx_count = clamp_t(u32, ring->tx_pending,
- I40EVF_MIN_TXD,
- I40EVF_MAX_TXD);
- new_tx_count = ALIGN(new_tx_count, I40EVF_REQ_DESCRIPTOR_MULTIPLE);
-
- new_rx_count = clamp_t(u32, ring->rx_pending,
- I40EVF_MIN_RXD,
- I40EVF_MAX_RXD);
- new_rx_count = ALIGN(new_rx_count, I40EVF_REQ_DESCRIPTOR_MULTIPLE);
-
- /* if nothing to do return success */
- if ((new_tx_count == adapter->tx_desc_count) &&
- (new_rx_count == adapter->rx_desc_count))
- return 0;
-
- adapter->tx_desc_count = new_tx_count;
- adapter->rx_desc_count = new_rx_count;
-
- if (netif_running(netdev)) {
- adapter->flags |= I40EVF_FLAG_RESET_NEEDED;
- schedule_work(&adapter->reset_task);
- }
-
- return 0;
-}
-
-/**
- * __i40evf_get_coalesce - get per-queue coalesce settings
- * @netdev: the netdev to check
- * @ec: ethtool coalesce data structure
- * @queue: which queue to pick
- *
- * Gets the per-queue settings for coalescence. Specifically Rx and Tx usecs
- * are per queue. If queue is <0 then we default to queue 0 as the
- * representative value.
- **/
-static int __i40evf_get_coalesce(struct net_device *netdev,
- struct ethtool_coalesce *ec,
- int queue)
-{
- struct i40evf_adapter *adapter = netdev_priv(netdev);
- struct i40e_vsi *vsi = &adapter->vsi;
- struct i40e_ring *rx_ring, *tx_ring;
-
- ec->tx_max_coalesced_frames = vsi->work_limit;
- ec->rx_max_coalesced_frames = vsi->work_limit;
-
- /* Rx and Tx usecs per queue value. If user doesn't specify the
- * queue, return queue 0's value to represent.
- */
- if (queue < 0)
- queue = 0;
- else if (queue >= adapter->num_active_queues)
- return -EINVAL;
-
- rx_ring = &adapter->rx_rings[queue];
- tx_ring = &adapter->tx_rings[queue];
-
- if (ITR_IS_DYNAMIC(rx_ring->itr_setting))
- ec->use_adaptive_rx_coalesce = 1;
-
- if (ITR_IS_DYNAMIC(tx_ring->itr_setting))
- ec->use_adaptive_tx_coalesce = 1;
-
- ec->rx_coalesce_usecs = rx_ring->itr_setting & ~I40E_ITR_DYNAMIC;
- ec->tx_coalesce_usecs = tx_ring->itr_setting & ~I40E_ITR_DYNAMIC;
-
- return 0;
-}
-
-/**
- * i40evf_get_coalesce - Get interrupt coalescing settings
- * @netdev: network interface device structure
- * @ec: ethtool coalesce structure
- *
- * Returns current coalescing settings. This is referred to elsewhere in the
- * driver as Interrupt Throttle Rate, as this is how the hardware describes
- * this functionality. Note that if per-queue settings have been modified this
- * only represents the settings of queue 0.
- **/
-static int i40evf_get_coalesce(struct net_device *netdev,
- struct ethtool_coalesce *ec)
-{
- return __i40evf_get_coalesce(netdev, ec, -1);
-}
-
-/**
- * i40evf_get_per_queue_coalesce - get coalesce values for specific queue
- * @netdev: netdev to read
- * @ec: coalesce settings from ethtool
- * @queue: the queue to read
- *
- * Read specific queue's coalesce settings.
- **/
-static int i40evf_get_per_queue_coalesce(struct net_device *netdev,
- u32 queue,
- struct ethtool_coalesce *ec)
-{
- return __i40evf_get_coalesce(netdev, ec, queue);
-}
-
-/**
- * i40evf_set_itr_per_queue - set ITR values for specific queue
- * @adapter: the VF adapter struct to set values for
- * @ec: coalesce settings from ethtool
- * @queue: the queue to modify
- *
- * Change the ITR settings for a specific queue.
- **/
-static void i40evf_set_itr_per_queue(struct i40evf_adapter *adapter,
- struct ethtool_coalesce *ec,
- int queue)
-{
- struct i40e_ring *rx_ring = &adapter->rx_rings[queue];
- struct i40e_ring *tx_ring = &adapter->tx_rings[queue];
- struct i40e_q_vector *q_vector;
-
- rx_ring->itr_setting = ITR_REG_ALIGN(ec->rx_coalesce_usecs);
- tx_ring->itr_setting = ITR_REG_ALIGN(ec->tx_coalesce_usecs);
-
- rx_ring->itr_setting |= I40E_ITR_DYNAMIC;
- if (!ec->use_adaptive_rx_coalesce)
- rx_ring->itr_setting ^= I40E_ITR_DYNAMIC;
-
- tx_ring->itr_setting |= I40E_ITR_DYNAMIC;
- if (!ec->use_adaptive_tx_coalesce)
- tx_ring->itr_setting ^= I40E_ITR_DYNAMIC;
-
- q_vector = rx_ring->q_vector;
- q_vector->rx.target_itr = ITR_TO_REG(rx_ring->itr_setting);
-
- q_vector = tx_ring->q_vector;
- q_vector->tx.target_itr = ITR_TO_REG(tx_ring->itr_setting);
-
- /* The interrupt handler itself will take care of programming
- * the Tx and Rx ITR values based on the values we have entered
- * into the q_vector, no need to write the values now.
- */
-}
-
-/**
- * __i40evf_set_coalesce - set coalesce settings for particular queue
- * @netdev: the netdev to change
- * @ec: ethtool coalesce settings
- * @queue: the queue to change
- *
- * Sets the coalesce settings for a particular queue.
- **/
-static int __i40evf_set_coalesce(struct net_device *netdev,
- struct ethtool_coalesce *ec,
- int queue)
-{
- struct i40evf_adapter *adapter = netdev_priv(netdev);
- struct i40e_vsi *vsi = &adapter->vsi;
- int i;
-
- if (ec->tx_max_coalesced_frames_irq || ec->rx_max_coalesced_frames_irq)
- vsi->work_limit = ec->tx_max_coalesced_frames_irq;
-
- if (ec->rx_coalesce_usecs == 0) {
- if (ec->use_adaptive_rx_coalesce)
- netif_info(adapter, drv, netdev, "rx-usecs=0, need to disable adaptive-rx for a complete disable\n");
- } else if ((ec->rx_coalesce_usecs < I40E_MIN_ITR) ||
- (ec->rx_coalesce_usecs > I40E_MAX_ITR)) {
- netif_info(adapter, drv, netdev, "Invalid value, rx-usecs range is 0-8160\n");
- return -EINVAL;
- }
-
- else
- if (ec->tx_coalesce_usecs == 0) {
- if (ec->use_adaptive_tx_coalesce)
- netif_info(adapter, drv, netdev, "tx-usecs=0, need to disable adaptive-tx for a complete disable\n");
- } else if ((ec->tx_coalesce_usecs < I40E_MIN_ITR) ||
- (ec->tx_coalesce_usecs > I40E_MAX_ITR)) {
- netif_info(adapter, drv, netdev, "Invalid value, tx-usecs range is 0-8160\n");
- return -EINVAL;
- }
-
- /* Rx and Tx usecs has per queue value. If user doesn't specify the
- * queue, apply to all queues.
- */
- if (queue < 0) {
- for (i = 0; i < adapter->num_active_queues; i++)
- i40evf_set_itr_per_queue(adapter, ec, i);
- } else if (queue < adapter->num_active_queues) {
- i40evf_set_itr_per_queue(adapter, ec, queue);
- } else {
- netif_info(adapter, drv, netdev, "Invalid queue value, queue range is 0 - %d\n",
- adapter->num_active_queues - 1);
- return -EINVAL;
- }
-
- return 0;
-}
-
-/**
- * i40evf_set_coalesce - Set interrupt coalescing settings
- * @netdev: network interface device structure
- * @ec: ethtool coalesce structure
- *
- * Change current coalescing settings for every queue.
- **/
-static int i40evf_set_coalesce(struct net_device *netdev,
- struct ethtool_coalesce *ec)
-{
- return __i40evf_set_coalesce(netdev, ec, -1);
-}
-
-/**
- * i40evf_set_per_queue_coalesce - set specific queue's coalesce settings
- * @netdev: the netdev to change
- * @ec: ethtool's coalesce settings
- * @queue: the queue to modify
- *
- * Modifies a specific queue's coalesce settings.
- */
-static int i40evf_set_per_queue_coalesce(struct net_device *netdev,
- u32 queue,
- struct ethtool_coalesce *ec)
-{
- return __i40evf_set_coalesce(netdev, ec, queue);
-}
-
-/**
- * i40evf_get_rxnfc - command to get RX flow classification rules
- * @netdev: network interface device structure
- * @cmd: ethtool rxnfc command
- * @rule_locs: pointer to store rule locations
- *
- * Returns Success if the command is supported.
- **/
-static int i40evf_get_rxnfc(struct net_device *netdev,
- struct ethtool_rxnfc *cmd,
- u32 *rule_locs)
-{
- struct i40evf_adapter *adapter = netdev_priv(netdev);
- int ret = -EOPNOTSUPP;
-
- switch (cmd->cmd) {
- case ETHTOOL_GRXRINGS:
- cmd->data = adapter->num_active_queues;
- ret = 0;
- break;
- case ETHTOOL_GRXFH:
- netdev_info(netdev,
- "RSS hash info is not available to vf, use pf.\n");
- break;
- default:
- break;
- }
-
- return ret;
-}
-/**
- * i40evf_get_channels: get the number of channels supported by the device
- * @netdev: network interface device structure
- * @ch: channel information structure
- *
- * For the purposes of our device, we only use combined channels, i.e. a tx/rx
- * queue pair. Report one extra channel to match our "other" MSI-X vector.
- **/
-static void i40evf_get_channels(struct net_device *netdev,
- struct ethtool_channels *ch)
-{
- struct i40evf_adapter *adapter = netdev_priv(netdev);
-
- /* Report maximum channels */
- ch->max_combined = I40EVF_MAX_REQ_QUEUES;
-
- ch->max_other = NONQ_VECS;
- ch->other_count = NONQ_VECS;
-
- ch->combined_count = adapter->num_active_queues;
-}
-
-/**
- * i40evf_set_channels: set the new channel count
- * @netdev: network interface device structure
- * @ch: channel information structure
- *
- * Negotiate a new number of channels with the PF then do a reset. During
- * reset we'll realloc queues and fix the RSS table. Returns 0 on success,
- * negative on failure.
- **/
-static int i40evf_set_channels(struct net_device *netdev,
- struct ethtool_channels *ch)
-{
- struct i40evf_adapter *adapter = netdev_priv(netdev);
- int num_req = ch->combined_count;
-
- if (num_req != adapter->num_active_queues &&
- !(adapter->vf_res->vf_cap_flags &
- VIRTCHNL_VF_OFFLOAD_REQ_QUEUES)) {
- dev_info(&adapter->pdev->dev, "PF is not capable of queue negotiation.\n");
- return -EINVAL;
- }
-
- if ((adapter->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_ADQ) &&
- adapter->num_tc) {
- dev_info(&adapter->pdev->dev, "Cannot set channels since ADq is enabled.\n");
- return -EINVAL;
- }
-
- /* All of these should have already been checked by ethtool before this
- * even gets to us, but just to be sure.
- */
- if (num_req <= 0 || num_req > I40EVF_MAX_REQ_QUEUES)
- return -EINVAL;
-
- if (ch->rx_count || ch->tx_count || ch->other_count != NONQ_VECS)
- return -EINVAL;
-
- adapter->num_req_queues = num_req;
- return i40evf_request_queues(adapter, num_req);
-}
-
-/**
- * i40evf_get_rxfh_key_size - get the RSS hash key size
- * @netdev: network interface device structure
- *
- * Returns the table size.
- **/
-static u32 i40evf_get_rxfh_key_size(struct net_device *netdev)
-{
- struct i40evf_adapter *adapter = netdev_priv(netdev);
-
- return adapter->rss_key_size;
-}
-
-/**
- * i40evf_get_rxfh_indir_size - get the rx flow hash indirection table size
- * @netdev: network interface device structure
- *
- * Returns the table size.
- **/
-static u32 i40evf_get_rxfh_indir_size(struct net_device *netdev)
-{
- struct i40evf_adapter *adapter = netdev_priv(netdev);
-
- return adapter->rss_lut_size;
-}
-
-/**
- * i40evf_get_rxfh - get the rx flow hash indirection table
- * @netdev: network interface device structure
- * @indir: indirection table
- * @key: hash key
- * @hfunc: hash function in use
- *
- * Reads the indirection table directly from the hardware. Always returns 0.
- **/
-static int i40evf_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
- u8 *hfunc)
-{
- struct i40evf_adapter *adapter = netdev_priv(netdev);
- u16 i;
-
- if (hfunc)
- *hfunc = ETH_RSS_HASH_TOP;
- if (!indir)
- return 0;
-
- memcpy(key, adapter->rss_key, adapter->rss_key_size);
-
- /* Each 32 bits pointed by 'indir' is stored with a lut entry */
- for (i = 0; i < adapter->rss_lut_size; i++)
- indir[i] = (u32)adapter->rss_lut[i];
-
- return 0;
-}
-
-/**
- * i40evf_set_rxfh - set the rx flow hash indirection table
- * @netdev: network interface device structure
- * @indir: indirection table
- * @key: hash key
- * @hfunc: hash function to use
- *
- * Returns -EINVAL if the table specifies an inavlid queue id, otherwise
- * returns 0 after programming the table.
- **/
-static int i40evf_set_rxfh(struct net_device *netdev, const u32 *indir,
- const u8 *key, const u8 hfunc)
-{
- struct i40evf_adapter *adapter = netdev_priv(netdev);
- u16 i;
-
- /* We do not allow change in unsupported parameters */
- if (key ||
- (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP))
- return -EOPNOTSUPP;
- if (!indir)
- return 0;
-
- if (key) {
- memcpy(adapter->rss_key, key, adapter->rss_key_size);
- }
-
- /* Each 32 bits pointed by 'indir' is stored with a lut entry */
- for (i = 0; i < adapter->rss_lut_size; i++)
- adapter->rss_lut[i] = (u8)(indir[i]);
-
- return i40evf_config_rss(adapter);
-}
-
-static const struct ethtool_ops i40evf_ethtool_ops = {
- .get_drvinfo = i40evf_get_drvinfo,
- .get_link = ethtool_op_get_link,
- .get_ringparam = i40evf_get_ringparam,
- .set_ringparam = i40evf_set_ringparam,
- .get_strings = i40evf_get_strings,
- .get_ethtool_stats = i40evf_get_ethtool_stats,
- .get_sset_count = i40evf_get_sset_count,
- .get_priv_flags = i40evf_get_priv_flags,
- .set_priv_flags = i40evf_set_priv_flags,
- .get_msglevel = i40evf_get_msglevel,
- .set_msglevel = i40evf_set_msglevel,
- .get_coalesce = i40evf_get_coalesce,
- .set_coalesce = i40evf_set_coalesce,
- .get_per_queue_coalesce = i40evf_get_per_queue_coalesce,
- .set_per_queue_coalesce = i40evf_set_per_queue_coalesce,
- .get_rxnfc = i40evf_get_rxnfc,
- .get_rxfh_indir_size = i40evf_get_rxfh_indir_size,
- .get_rxfh = i40evf_get_rxfh,
- .set_rxfh = i40evf_set_rxfh,
- .get_channels = i40evf_get_channels,
- .set_channels = i40evf_set_channels,
- .get_rxfh_key_size = i40evf_get_rxfh_key_size,
- .get_link_ksettings = i40evf_get_link_ksettings,
-};
-
-/**
- * i40evf_set_ethtool_ops - Initialize ethtool ops struct
- * @netdev: network interface device structure
- *
- * Sets ethtool ops struct in our netdev so that ethtool can call
- * our functions.
- **/
-void i40evf_set_ethtool_ops(struct net_device *netdev)
-{
- netdev->ethtool_ops = &i40evf_ethtool_ops;
-}
diff --git a/drivers/net/ethernet/intel/iavf/Makefile b/drivers/net/ethernet/intel/iavf/Makefile
new file mode 100644
index 000000000000..9cbb5743ed12
--- /dev/null
+++ b/drivers/net/ethernet/intel/iavf/Makefile
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright(c) 2013 - 2018 Intel Corporation.
+#
+# Makefile for the Intel(R) Ethernet Adaptive Virtual Function (iavf)
+# driver
+#
+#
+
+ccflags-y += -I$(src)
+subdir-ccflags-y += -I$(src)
+
+obj-$(CONFIG_IAVF) += iavf.o
+
+iavf-objs := iavf_main.o iavf_ethtool.o iavf_virtchnl.o \
+ iavf_txrx.o iavf_common.o i40e_adminq.o iavf_client.o
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c b/drivers/net/ethernet/intel/iavf/i40e_adminq.c
index 21a0dbf6ccf6..fca1ecfd9f71 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c
+++ b/drivers/net/ethernet/intel/iavf/i40e_adminq.c
@@ -1,21 +1,11 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2013 - 2018 Intel Corporation. */
-#include "i40e_status.h"
-#include "i40e_type.h"
-#include "i40e_register.h"
+#include "iavf_status.h"
+#include "iavf_type.h"
+#include "iavf_register.h"
#include "i40e_adminq.h"
-#include "i40e_prototype.h"
-
-/**
- * i40e_is_nvm_update_op - return true if this is an NVM update operation
- * @desc: API request descriptor
- **/
-static inline bool i40e_is_nvm_update_op(struct i40e_aq_desc *desc)
-{
- return (desc->opcode == i40e_aqc_opc_nvm_erase) ||
- (desc->opcode == i40e_aqc_opc_nvm_update);
-}
+#include "iavf_prototype.h"
/**
* i40e_adminq_init_regs - Initialize AdminQ registers
@@ -23,44 +13,42 @@ static inline bool i40e_is_nvm_update_op(struct i40e_aq_desc *desc)
*
* This assumes the alloc_asq and alloc_arq functions have already been called
**/
-static void i40e_adminq_init_regs(struct i40e_hw *hw)
+static void i40e_adminq_init_regs(struct iavf_hw *hw)
{
/* set head and tail registers in our local struct */
- if (i40e_is_vf(hw)) {
- hw->aq.asq.tail = I40E_VF_ATQT1;
- hw->aq.asq.head = I40E_VF_ATQH1;
- hw->aq.asq.len = I40E_VF_ATQLEN1;
- hw->aq.asq.bal = I40E_VF_ATQBAL1;
- hw->aq.asq.bah = I40E_VF_ATQBAH1;
- hw->aq.arq.tail = I40E_VF_ARQT1;
- hw->aq.arq.head = I40E_VF_ARQH1;
- hw->aq.arq.len = I40E_VF_ARQLEN1;
- hw->aq.arq.bal = I40E_VF_ARQBAL1;
- hw->aq.arq.bah = I40E_VF_ARQBAH1;
- }
+ hw->aq.asq.tail = IAVF_VF_ATQT1;
+ hw->aq.asq.head = IAVF_VF_ATQH1;
+ hw->aq.asq.len = IAVF_VF_ATQLEN1;
+ hw->aq.asq.bal = IAVF_VF_ATQBAL1;
+ hw->aq.asq.bah = IAVF_VF_ATQBAH1;
+ hw->aq.arq.tail = IAVF_VF_ARQT1;
+ hw->aq.arq.head = IAVF_VF_ARQH1;
+ hw->aq.arq.len = IAVF_VF_ARQLEN1;
+ hw->aq.arq.bal = IAVF_VF_ARQBAL1;
+ hw->aq.arq.bah = IAVF_VF_ARQBAH1;
}
/**
* i40e_alloc_adminq_asq_ring - Allocate Admin Queue send rings
* @hw: pointer to the hardware structure
**/
-static i40e_status i40e_alloc_adminq_asq_ring(struct i40e_hw *hw)
+static iavf_status i40e_alloc_adminq_asq_ring(struct iavf_hw *hw)
{
- i40e_status ret_code;
+ iavf_status ret_code;
- ret_code = i40e_allocate_dma_mem(hw, &hw->aq.asq.desc_buf,
+ ret_code = iavf_allocate_dma_mem(hw, &hw->aq.asq.desc_buf,
i40e_mem_atq_ring,
(hw->aq.num_asq_entries *
sizeof(struct i40e_aq_desc)),
- I40E_ADMINQ_DESC_ALIGNMENT);
+ IAVF_ADMINQ_DESC_ALIGNMENT);
if (ret_code)
return ret_code;
- ret_code = i40e_allocate_virt_mem(hw, &hw->aq.asq.cmd_buf,
+ ret_code = iavf_allocate_virt_mem(hw, &hw->aq.asq.cmd_buf,
(hw->aq.num_asq_entries *
sizeof(struct i40e_asq_cmd_details)));
if (ret_code) {
- i40e_free_dma_mem(hw, &hw->aq.asq.desc_buf);
+ iavf_free_dma_mem(hw, &hw->aq.asq.desc_buf);
return ret_code;
}
@@ -71,15 +59,15 @@ static i40e_status i40e_alloc_adminq_asq_ring(struct i40e_hw *hw)
* i40e_alloc_adminq_arq_ring - Allocate Admin Queue receive rings
* @hw: pointer to the hardware structure
**/
-static i40e_status i40e_alloc_adminq_arq_ring(struct i40e_hw *hw)
+static iavf_status i40e_alloc_adminq_arq_ring(struct iavf_hw *hw)
{
- i40e_status ret_code;
+ iavf_status ret_code;
- ret_code = i40e_allocate_dma_mem(hw, &hw->aq.arq.desc_buf,
+ ret_code = iavf_allocate_dma_mem(hw, &hw->aq.arq.desc_buf,
i40e_mem_arq_ring,
(hw->aq.num_arq_entries *
sizeof(struct i40e_aq_desc)),
- I40E_ADMINQ_DESC_ALIGNMENT);
+ IAVF_ADMINQ_DESC_ALIGNMENT);
return ret_code;
}
@@ -91,9 +79,9 @@ static i40e_status i40e_alloc_adminq_arq_ring(struct i40e_hw *hw)
* This assumes the posted send buffers have already been cleaned
* and de-allocated
**/
-static void i40e_free_adminq_asq(struct i40e_hw *hw)
+static void i40e_free_adminq_asq(struct iavf_hw *hw)
{
- i40e_free_dma_mem(hw, &hw->aq.asq.desc_buf);
+ iavf_free_dma_mem(hw, &hw->aq.asq.desc_buf);
}
/**
@@ -103,20 +91,20 @@ static void i40e_free_adminq_asq(struct i40e_hw *hw)
* This assumes the posted receive buffers have already been cleaned
* and de-allocated
**/
-static void i40e_free_adminq_arq(struct i40e_hw *hw)
+static void i40e_free_adminq_arq(struct iavf_hw *hw)
{
- i40e_free_dma_mem(hw, &hw->aq.arq.desc_buf);
+ iavf_free_dma_mem(hw, &hw->aq.arq.desc_buf);
}
/**
* i40e_alloc_arq_bufs - Allocate pre-posted buffers for the receive queue
* @hw: pointer to the hardware structure
**/
-static i40e_status i40e_alloc_arq_bufs(struct i40e_hw *hw)
+static iavf_status i40e_alloc_arq_bufs(struct iavf_hw *hw)
{
- i40e_status ret_code;
struct i40e_aq_desc *desc;
- struct i40e_dma_mem *bi;
+ struct iavf_dma_mem *bi;
+ iavf_status ret_code;
int i;
/* We'll be allocating the buffer info memory first, then we can
@@ -124,24 +112,25 @@ static i40e_status i40e_alloc_arq_bufs(struct i40e_hw *hw)
*/
/* buffer_info structures do not need alignment */
- ret_code = i40e_allocate_virt_mem(hw, &hw->aq.arq.dma_head,
- (hw->aq.num_arq_entries * sizeof(struct i40e_dma_mem)));
+ ret_code = iavf_allocate_virt_mem(hw, &hw->aq.arq.dma_head,
+ (hw->aq.num_arq_entries *
+ sizeof(struct iavf_dma_mem)));
if (ret_code)
goto alloc_arq_bufs;
- hw->aq.arq.r.arq_bi = (struct i40e_dma_mem *)hw->aq.arq.dma_head.va;
+ hw->aq.arq.r.arq_bi = (struct iavf_dma_mem *)hw->aq.arq.dma_head.va;
/* allocate the mapped buffers */
for (i = 0; i < hw->aq.num_arq_entries; i++) {
bi = &hw->aq.arq.r.arq_bi[i];
- ret_code = i40e_allocate_dma_mem(hw, bi,
+ ret_code = iavf_allocate_dma_mem(hw, bi,
i40e_mem_arq_buf,
hw->aq.arq_buf_size,
- I40E_ADMINQ_DESC_ALIGNMENT);
+ IAVF_ADMINQ_DESC_ALIGNMENT);
if (ret_code)
goto unwind_alloc_arq_bufs;
/* now configure the descriptors for use */
- desc = I40E_ADMINQ_DESC(hw->aq.arq, i);
+ desc = IAVF_ADMINQ_DESC(hw->aq.arq, i);
desc->flags = cpu_to_le16(I40E_AQ_FLAG_BUF);
if (hw->aq.arq_buf_size > I40E_AQ_LARGE_BUF)
@@ -169,8 +158,8 @@ unwind_alloc_arq_bufs:
/* don't try to free the one that failed... */
i--;
for (; i >= 0; i--)
- i40e_free_dma_mem(hw, &hw->aq.arq.r.arq_bi[i]);
- i40e_free_virt_mem(hw, &hw->aq.arq.dma_head);
+ iavf_free_dma_mem(hw, &hw->aq.arq.r.arq_bi[i]);
+ iavf_free_virt_mem(hw, &hw->aq.arq.dma_head);
return ret_code;
}
@@ -179,26 +168,27 @@ unwind_alloc_arq_bufs:
* i40e_alloc_asq_bufs - Allocate empty buffer structs for the send queue
* @hw: pointer to the hardware structure
**/
-static i40e_status i40e_alloc_asq_bufs(struct i40e_hw *hw)
+static iavf_status i40e_alloc_asq_bufs(struct iavf_hw *hw)
{
- i40e_status ret_code;
- struct i40e_dma_mem *bi;
+ struct iavf_dma_mem *bi;
+ iavf_status ret_code;
int i;
/* No mapped memory needed yet, just the buffer info structures */
- ret_code = i40e_allocate_virt_mem(hw, &hw->aq.asq.dma_head,
- (hw->aq.num_asq_entries * sizeof(struct i40e_dma_mem)));
+ ret_code = iavf_allocate_virt_mem(hw, &hw->aq.asq.dma_head,
+ (hw->aq.num_asq_entries *
+ sizeof(struct iavf_dma_mem)));
if (ret_code)
goto alloc_asq_bufs;
- hw->aq.asq.r.asq_bi = (struct i40e_dma_mem *)hw->aq.asq.dma_head.va;
+ hw->aq.asq.r.asq_bi = (struct iavf_dma_mem *)hw->aq.asq.dma_head.va;
/* allocate the mapped buffers */
for (i = 0; i < hw->aq.num_asq_entries; i++) {
bi = &hw->aq.asq.r.asq_bi[i];
- ret_code = i40e_allocate_dma_mem(hw, bi,
+ ret_code = iavf_allocate_dma_mem(hw, bi,
i40e_mem_asq_buf,
hw->aq.asq_buf_size,
- I40E_ADMINQ_DESC_ALIGNMENT);
+ IAVF_ADMINQ_DESC_ALIGNMENT);
if (ret_code)
goto unwind_alloc_asq_bufs;
}
@@ -209,8 +199,8 @@ unwind_alloc_asq_bufs:
/* don't try to free the one that failed... */
i--;
for (; i >= 0; i--)
- i40e_free_dma_mem(hw, &hw->aq.asq.r.asq_bi[i]);
- i40e_free_virt_mem(hw, &hw->aq.asq.dma_head);
+ iavf_free_dma_mem(hw, &hw->aq.asq.r.asq_bi[i]);
+ iavf_free_virt_mem(hw, &hw->aq.asq.dma_head);
return ret_code;
}
@@ -219,42 +209,42 @@ unwind_alloc_asq_bufs:
* i40e_free_arq_bufs - Free receive queue buffer info elements
* @hw: pointer to the hardware structure
**/
-static void i40e_free_arq_bufs(struct i40e_hw *hw)
+static void i40e_free_arq_bufs(struct iavf_hw *hw)
{
int i;
/* free descriptors */
for (i = 0; i < hw->aq.num_arq_entries; i++)
- i40e_free_dma_mem(hw, &hw->aq.arq.r.arq_bi[i]);
+ iavf_free_dma_mem(hw, &hw->aq.arq.r.arq_bi[i]);
/* free the descriptor memory */
- i40e_free_dma_mem(hw, &hw->aq.arq.desc_buf);
+ iavf_free_dma_mem(hw, &hw->aq.arq.desc_buf);
/* free the dma header */
- i40e_free_virt_mem(hw, &hw->aq.arq.dma_head);
+ iavf_free_virt_mem(hw, &hw->aq.arq.dma_head);
}
/**
* i40e_free_asq_bufs - Free send queue buffer info elements
* @hw: pointer to the hardware structure
**/
-static void i40e_free_asq_bufs(struct i40e_hw *hw)
+static void i40e_free_asq_bufs(struct iavf_hw *hw)
{
int i;
/* only unmap if the address is non-NULL */
for (i = 0; i < hw->aq.num_asq_entries; i++)
if (hw->aq.asq.r.asq_bi[i].pa)
- i40e_free_dma_mem(hw, &hw->aq.asq.r.asq_bi[i]);
+ iavf_free_dma_mem(hw, &hw->aq.asq.r.asq_bi[i]);
/* free the buffer info list */
- i40e_free_virt_mem(hw, &hw->aq.asq.cmd_buf);
+ iavf_free_virt_mem(hw, &hw->aq.asq.cmd_buf);
/* free the descriptor memory */
- i40e_free_dma_mem(hw, &hw->aq.asq.desc_buf);
+ iavf_free_dma_mem(hw, &hw->aq.asq.desc_buf);
/* free the dma header */
- i40e_free_virt_mem(hw, &hw->aq.asq.dma_head);
+ iavf_free_virt_mem(hw, &hw->aq.asq.dma_head);
}
/**
@@ -263,9 +253,9 @@ static void i40e_free_asq_bufs(struct i40e_hw *hw)
*
* Configure base address and length registers for the transmit queue
**/
-static i40e_status i40e_config_asq_regs(struct i40e_hw *hw)
+static iavf_status i40e_config_asq_regs(struct iavf_hw *hw)
{
- i40e_status ret_code = 0;
+ iavf_status ret_code = 0;
u32 reg = 0;
/* Clear Head and Tail */
@@ -274,7 +264,7 @@ static i40e_status i40e_config_asq_regs(struct i40e_hw *hw)
/* set starting point */
wr32(hw, hw->aq.asq.len, (hw->aq.num_asq_entries |
- I40E_VF_ATQLEN1_ATQENABLE_MASK));
+ IAVF_VF_ATQLEN1_ATQENABLE_MASK));
wr32(hw, hw->aq.asq.bal, lower_32_bits(hw->aq.asq.desc_buf.pa));
wr32(hw, hw->aq.asq.bah, upper_32_bits(hw->aq.asq.desc_buf.pa));
@@ -292,9 +282,9 @@ static i40e_status i40e_config_asq_regs(struct i40e_hw *hw)
*
* Configure base address and length registers for the receive (event queue)
**/
-static i40e_status i40e_config_arq_regs(struct i40e_hw *hw)
+static iavf_status i40e_config_arq_regs(struct iavf_hw *hw)
{
- i40e_status ret_code = 0;
+ iavf_status ret_code = 0;
u32 reg = 0;
/* Clear Head and Tail */
@@ -303,7 +293,7 @@ static i40e_status i40e_config_arq_regs(struct i40e_hw *hw)
/* set starting point */
wr32(hw, hw->aq.arq.len, (hw->aq.num_arq_entries |
- I40E_VF_ARQLEN1_ARQENABLE_MASK));
+ IAVF_VF_ARQLEN1_ARQENABLE_MASK));
wr32(hw, hw->aq.arq.bal, lower_32_bits(hw->aq.arq.desc_buf.pa));
wr32(hw, hw->aq.arq.bah, upper_32_bits(hw->aq.arq.desc_buf.pa));
@@ -331,9 +321,9 @@ static i40e_status i40e_config_arq_regs(struct i40e_hw *hw)
* Do *NOT* hold the lock when calling this as the memory allocation routines
* called are not going to be atomic context safe
**/
-static i40e_status i40e_init_asq(struct i40e_hw *hw)
+static iavf_status i40e_init_asq(struct iavf_hw *hw)
{
- i40e_status ret_code = 0;
+ iavf_status ret_code = 0;
if (hw->aq.asq.count > 0) {
/* queue already initialized */
@@ -390,9 +380,9 @@ init_adminq_exit:
* Do *NOT* hold the lock when calling this as the memory allocation routines
* called are not going to be atomic context safe
**/
-static i40e_status i40e_init_arq(struct i40e_hw *hw)
+static iavf_status i40e_init_arq(struct iavf_hw *hw)
{
- i40e_status ret_code = 0;
+ iavf_status ret_code = 0;
if (hw->aq.arq.count > 0) {
/* queue already initialized */
@@ -442,9 +432,9 @@ init_adminq_exit:
*
* The main shutdown routine for the Admin Send Queue
**/
-static i40e_status i40e_shutdown_asq(struct i40e_hw *hw)
+static iavf_status i40e_shutdown_asq(struct iavf_hw *hw)
{
- i40e_status ret_code = 0;
+ iavf_status ret_code = 0;
mutex_lock(&hw->aq.asq_mutex);
@@ -476,9 +466,9 @@ shutdown_asq_out:
*
* The main shutdown routine for the Admin Receive Queue
**/
-static i40e_status i40e_shutdown_arq(struct i40e_hw *hw)
+static iavf_status i40e_shutdown_arq(struct iavf_hw *hw)
{
- i40e_status ret_code = 0;
+ iavf_status ret_code = 0;
mutex_lock(&hw->aq.arq_mutex);
@@ -505,7 +495,7 @@ shutdown_arq_out:
}
/**
- * i40evf_init_adminq - main initialization routine for Admin Queue
+ * iavf_init_adminq - main initialization routine for Admin Queue
* @hw: pointer to the hardware structure
*
* Prior to calling this function, drivers *MUST* set the following fields
@@ -515,9 +505,9 @@ shutdown_arq_out:
* - hw->aq.arq_buf_size
* - hw->aq.asq_buf_size
**/
-i40e_status i40evf_init_adminq(struct i40e_hw *hw)
+iavf_status iavf_init_adminq(struct iavf_hw *hw)
{
- i40e_status ret_code;
+ iavf_status ret_code;
/* verify input for valid configuration */
if ((hw->aq.num_arq_entries == 0) ||
@@ -556,22 +546,19 @@ init_adminq_exit:
}
/**
- * i40evf_shutdown_adminq - shutdown routine for the Admin Queue
+ * iavf_shutdown_adminq - shutdown routine for the Admin Queue
* @hw: pointer to the hardware structure
**/
-i40e_status i40evf_shutdown_adminq(struct i40e_hw *hw)
+iavf_status iavf_shutdown_adminq(struct iavf_hw *hw)
{
- i40e_status ret_code = 0;
+ iavf_status ret_code = 0;
- if (i40evf_check_asq_alive(hw))
- i40evf_aq_queue_shutdown(hw, true);
+ if (iavf_check_asq_alive(hw))
+ iavf_aq_queue_shutdown(hw, true);
i40e_shutdown_asq(hw);
i40e_shutdown_arq(hw);
- if (hw->nvm_buff.va)
- i40e_free_virt_mem(hw, &hw->nvm_buff);
-
return ret_code;
}
@@ -581,18 +568,18 @@ i40e_status i40evf_shutdown_adminq(struct i40e_hw *hw)
*
* returns the number of free desc
**/
-static u16 i40e_clean_asq(struct i40e_hw *hw)
+static u16 i40e_clean_asq(struct iavf_hw *hw)
{
- struct i40e_adminq_ring *asq = &(hw->aq.asq);
+ struct iavf_adminq_ring *asq = &hw->aq.asq;
struct i40e_asq_cmd_details *details;
u16 ntc = asq->next_to_clean;
struct i40e_aq_desc desc_cb;
struct i40e_aq_desc *desc;
- desc = I40E_ADMINQ_DESC(*asq, ntc);
+ desc = IAVF_ADMINQ_DESC(*asq, ntc);
details = I40E_ADMINQ_DETAILS(*asq, ntc);
while (rd32(hw, hw->aq.asq.head) != ntc) {
- i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE,
+ iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE,
"ntc %d head %d.\n", ntc, rd32(hw, hw->aq.asq.head));
if (details->callback) {
@@ -607,33 +594,32 @@ static u16 i40e_clean_asq(struct i40e_hw *hw)
ntc++;
if (ntc == asq->count)
ntc = 0;
- desc = I40E_ADMINQ_DESC(*asq, ntc);
+ desc = IAVF_ADMINQ_DESC(*asq, ntc);
details = I40E_ADMINQ_DETAILS(*asq, ntc);
}
asq->next_to_clean = ntc;
- return I40E_DESC_UNUSED(asq);
+ return IAVF_DESC_UNUSED(asq);
}
/**
- * i40evf_asq_done - check if FW has processed the Admin Send Queue
+ * iavf_asq_done - check if FW has processed the Admin Send Queue
* @hw: pointer to the hw struct
*
* Returns true if the firmware has processed all descriptors on the
* admin send queue. Returns false if there are still requests pending.
**/
-bool i40evf_asq_done(struct i40e_hw *hw)
+bool iavf_asq_done(struct iavf_hw *hw)
{
/* AQ designers suggest use of head for better
* timing reliability than DD bit
*/
return rd32(hw, hw->aq.asq.head) == hw->aq.asq.next_to_use;
-
}
/**
- * i40evf_asq_send_command - send command to Admin Queue
+ * iavf_asq_send_command - send command to Admin Queue
* @hw: pointer to the hw struct
* @desc: prefilled descriptor describing the command (non DMA mem)
* @buff: buffer to use for indirect commands
@@ -643,24 +629,23 @@ bool i40evf_asq_done(struct i40e_hw *hw)
* This is the main send command driver routine for the Admin Queue send
* queue. It runs the queue, cleans the queue, etc
**/
-i40e_status i40evf_asq_send_command(struct i40e_hw *hw,
- struct i40e_aq_desc *desc,
- void *buff, /* can be NULL */
- u16 buff_size,
- struct i40e_asq_cmd_details *cmd_details)
+iavf_status iavf_asq_send_command(struct iavf_hw *hw, struct i40e_aq_desc *desc,
+ void *buff, /* can be NULL */
+ u16 buff_size,
+ struct i40e_asq_cmd_details *cmd_details)
{
- i40e_status status = 0;
- struct i40e_dma_mem *dma_buff = NULL;
+ struct iavf_dma_mem *dma_buff = NULL;
struct i40e_asq_cmd_details *details;
struct i40e_aq_desc *desc_on_ring;
bool cmd_completed = false;
+ iavf_status status = 0;
u16 retval = 0;
u32 val = 0;
mutex_lock(&hw->aq.asq_mutex);
if (hw->aq.asq.count == 0) {
- i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE,
+ iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE,
"AQTX: Admin queue not initialized.\n");
status = I40E_ERR_QUEUE_EMPTY;
goto asq_send_command_error;
@@ -670,7 +655,7 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw,
val = rd32(hw, hw->aq.asq.head);
if (val >= hw->aq.num_asq_entries) {
- i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE,
+ iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE,
"AQTX: head overrun at %d\n", val);
status = I40E_ERR_QUEUE_EMPTY;
goto asq_send_command_error;
@@ -699,8 +684,8 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw,
desc->flags |= cpu_to_le16(details->flags_ena);
if (buff_size > hw->aq.asq_buf_size) {
- i40e_debug(hw,
- I40E_DEBUG_AQ_MESSAGE,
+ iavf_debug(hw,
+ IAVF_DEBUG_AQ_MESSAGE,
"AQTX: Invalid buffer size: %d.\n",
buff_size);
status = I40E_ERR_INVALID_SIZE;
@@ -708,8 +693,8 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw,
}
if (details->postpone && !details->async) {
- i40e_debug(hw,
- I40E_DEBUG_AQ_MESSAGE,
+ iavf_debug(hw,
+ IAVF_DEBUG_AQ_MESSAGE,
"AQTX: Async flag not set along with postpone flag");
status = I40E_ERR_PARAM;
goto asq_send_command_error;
@@ -723,22 +708,22 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw,
* in case of asynchronous completions
*/
if (i40e_clean_asq(hw) == 0) {
- i40e_debug(hw,
- I40E_DEBUG_AQ_MESSAGE,
+ iavf_debug(hw,
+ IAVF_DEBUG_AQ_MESSAGE,
"AQTX: Error queue is full.\n");
status = I40E_ERR_ADMIN_QUEUE_FULL;
goto asq_send_command_error;
}
/* initialize the temp desc pointer with the right desc */
- desc_on_ring = I40E_ADMINQ_DESC(hw->aq.asq, hw->aq.asq.next_to_use);
+ desc_on_ring = IAVF_ADMINQ_DESC(hw->aq.asq, hw->aq.asq.next_to_use);
/* if the desc is available copy the temp desc to the right place */
*desc_on_ring = *desc;
/* if buff is not NULL assume indirect command */
- if (buff != NULL) {
- dma_buff = &(hw->aq.asq.r.asq_bi[hw->aq.asq.next_to_use]);
+ if (buff) {
+ dma_buff = &hw->aq.asq.r.asq_bi[hw->aq.asq.next_to_use];
/* copy the user buff into the respective DMA buff */
memcpy(dma_buff->va, buff, buff_size);
desc_on_ring->datalen = cpu_to_le16(buff_size);
@@ -753,9 +738,9 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw,
}
/* bump the tail */
- i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: desc and buffer:\n");
- i40evf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc_on_ring,
- buff, buff_size);
+ iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE, "AQTX: desc and buffer:\n");
+ iavf_debug_aq(hw, IAVF_DEBUG_AQ_COMMAND, (void *)desc_on_ring,
+ buff, buff_size);
(hw->aq.asq.next_to_use)++;
if (hw->aq.asq.next_to_use == hw->aq.asq.count)
hw->aq.asq.next_to_use = 0;
@@ -772,7 +757,7 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw,
/* AQ designers suggest use of head for better
* timing reliability than DD bit
*/
- if (i40evf_asq_done(hw))
+ if (iavf_asq_done(hw))
break;
udelay(50);
total_delay += 50;
@@ -780,14 +765,14 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw,
}
/* if ready, copy the desc back to temp */
- if (i40evf_asq_done(hw)) {
+ if (iavf_asq_done(hw)) {
*desc = *desc_on_ring;
- if (buff != NULL)
+ if (buff)
memcpy(buff, dma_buff->va, buff_size);
retval = le16_to_cpu(desc->retval);
if (retval != 0) {
- i40e_debug(hw,
- I40E_DEBUG_AQ_MESSAGE,
+ iavf_debug(hw,
+ IAVF_DEBUG_AQ_MESSAGE,
"AQTX: Command completed with error 0x%X.\n",
retval);
@@ -804,10 +789,9 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw,
hw->aq.asq_last_status = (enum i40e_admin_queue_err)retval;
}
- i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE,
+ iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE,
"AQTX: desc and buffer writeback:\n");
- i40evf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, buff,
- buff_size);
+ iavf_debug_aq(hw, IAVF_DEBUG_AQ_COMMAND, (void *)desc, buff, buff_size);
/* save writeback aq if requested */
if (details->wb_desc)
@@ -816,12 +800,12 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw,
/* update the error if time out occurred */
if ((!cmd_completed) &&
(!details->async && !details->postpone)) {
- if (rd32(hw, hw->aq.asq.len) & I40E_VF_ATQLEN1_ATQCRIT_MASK) {
- i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE,
+ if (rd32(hw, hw->aq.asq.len) & IAVF_VF_ATQLEN1_ATQCRIT_MASK) {
+ iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE,
"AQTX: AQ Critical error.\n");
status = I40E_ERR_ADMIN_QUEUE_CRITICAL_ERROR;
} else {
- i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE,
+ iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE,
"AQTX: Writeback timeout.\n");
status = I40E_ERR_ADMIN_QUEUE_TIMEOUT;
}
@@ -833,14 +817,13 @@ asq_send_command_error:
}
/**
- * i40evf_fill_default_direct_cmd_desc - AQ descriptor helper function
+ * iavf_fill_default_direct_cmd_desc - AQ descriptor helper function
* @desc: pointer to the temp descriptor (non DMA mem)
* @opcode: the opcode can be used to decide which flags to turn off or on
*
* Fill the desc with default values
**/
-void i40evf_fill_default_direct_cmd_desc(struct i40e_aq_desc *desc,
- u16 opcode)
+void iavf_fill_default_direct_cmd_desc(struct i40e_aq_desc *desc, u16 opcode)
{
/* zero out the desc */
memset((void *)desc, 0, sizeof(struct i40e_aq_desc));
@@ -849,7 +832,7 @@ void i40evf_fill_default_direct_cmd_desc(struct i40e_aq_desc *desc,
}
/**
- * i40evf_clean_arq_element
+ * iavf_clean_arq_element
* @hw: pointer to the hw struct
* @e: event info from the receive descriptor, includes any buffers
* @pending: number of events that could be left to process
@@ -858,14 +841,14 @@ void i40evf_fill_default_direct_cmd_desc(struct i40e_aq_desc *desc,
* the contents through e. It can also return how many events are
* left to process through 'pending'
**/
-i40e_status i40evf_clean_arq_element(struct i40e_hw *hw,
- struct i40e_arq_event_info *e,
- u16 *pending)
+iavf_status iavf_clean_arq_element(struct iavf_hw *hw,
+ struct i40e_arq_event_info *e,
+ u16 *pending)
{
- i40e_status ret_code = 0;
u16 ntc = hw->aq.arq.next_to_clean;
struct i40e_aq_desc *desc;
- struct i40e_dma_mem *bi;
+ iavf_status ret_code = 0;
+ struct iavf_dma_mem *bi;
u16 desc_idx;
u16 datalen;
u16 flags;
@@ -878,14 +861,14 @@ i40e_status i40evf_clean_arq_element(struct i40e_hw *hw,
mutex_lock(&hw->aq.arq_mutex);
if (hw->aq.arq.count == 0) {
- i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE,
+ iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE,
"AQRX: Admin queue not initialized.\n");
ret_code = I40E_ERR_QUEUE_EMPTY;
goto clean_arq_element_err;
}
/* set next_to_use to head */
- ntu = rd32(hw, hw->aq.arq.head) & I40E_VF_ARQH1_ARQH_MASK;
+ ntu = rd32(hw, hw->aq.arq.head) & IAVF_VF_ARQH1_ARQH_MASK;
if (ntu == ntc) {
/* nothing to do - shouldn't need to update ring's values */
ret_code = I40E_ERR_ADMIN_QUEUE_NO_WORK;
@@ -893,7 +876,7 @@ i40e_status i40evf_clean_arq_element(struct i40e_hw *hw,
}
/* now clean the next descriptor */
- desc = I40E_ADMINQ_DESC(hw->aq.arq, ntc);
+ desc = IAVF_ADMINQ_DESC(hw->aq.arq, ntc);
desc_idx = ntc;
hw->aq.arq_last_status =
@@ -901,8 +884,8 @@ i40e_status i40evf_clean_arq_element(struct i40e_hw *hw,
flags = le16_to_cpu(desc->flags);
if (flags & I40E_AQ_FLAG_ERR) {
ret_code = I40E_ERR_ADMIN_QUEUE_ERROR;
- i40e_debug(hw,
- I40E_DEBUG_AQ_MESSAGE,
+ iavf_debug(hw,
+ IAVF_DEBUG_AQ_MESSAGE,
"AQRX: Event received with error 0x%X.\n",
hw->aq.arq_last_status);
}
@@ -910,13 +893,13 @@ i40e_status i40evf_clean_arq_element(struct i40e_hw *hw,
e->desc = *desc;
datalen = le16_to_cpu(desc->datalen);
e->msg_len = min(datalen, e->buf_len);
- if (e->msg_buf != NULL && (e->msg_len != 0))
+ if (e->msg_buf && (e->msg_len != 0))
memcpy(e->msg_buf, hw->aq.arq.r.arq_bi[desc_idx].va,
e->msg_len);
- i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQRX: desc and buffer:\n");
- i40evf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, e->msg_buf,
- hw->aq.arq_buf_size);
+ iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE, "AQRX: desc and buffer:\n");
+ iavf_debug_aq(hw, IAVF_DEBUG_AQ_COMMAND, (void *)desc, e->msg_buf,
+ hw->aq.arq_buf_size);
/* Restore the original datalen and buffer address in the desc,
* FW updates datalen to indicate the event message
@@ -943,7 +926,7 @@ i40e_status i40evf_clean_arq_element(struct i40e_hw *hw,
clean_arq_element_out:
/* Set pending if needed, unlock and return */
- if (pending != NULL)
+ if (pending)
*pending = (ntc > ntu ? hw->aq.arq.count : 0) + (ntu - ntc);
clean_arq_element_err:
@@ -951,17 +934,3 @@ clean_arq_element_err:
return ret_code;
}
-
-void i40evf_resume_aq(struct i40e_hw *hw)
-{
- /* Registers are reset after PF reset */
- hw->aq.asq.next_to_use = 0;
- hw->aq.asq.next_to_clean = 0;
-
- i40e_config_asq_regs(hw);
-
- hw->aq.arq.next_to_use = 0;
- hw->aq.arq.next_to_clean = 0;
-
- i40e_config_arq_regs(hw);
-}
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq.h b/drivers/net/ethernet/intel/iavf/i40e_adminq.h
index 1f264b9b6805..ee983889eab0 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_adminq.h
+++ b/drivers/net/ethernet/intel/iavf/i40e_adminq.h
@@ -1,26 +1,26 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright(c) 2013 - 2018 Intel Corporation. */
-#ifndef _I40E_ADMINQ_H_
-#define _I40E_ADMINQ_H_
+#ifndef _IAVF_ADMINQ_H_
+#define _IAVF_ADMINQ_H_
-#include "i40e_osdep.h"
-#include "i40e_status.h"
+#include "iavf_osdep.h"
+#include "iavf_status.h"
#include "i40e_adminq_cmd.h"
-#define I40E_ADMINQ_DESC(R, i) \
+#define IAVF_ADMINQ_DESC(R, i) \
(&(((struct i40e_aq_desc *)((R).desc_buf.va))[i]))
-#define I40E_ADMINQ_DESC_ALIGNMENT 4096
+#define IAVF_ADMINQ_DESC_ALIGNMENT 4096
-struct i40e_adminq_ring {
- struct i40e_virt_mem dma_head; /* space for dma structures */
- struct i40e_dma_mem desc_buf; /* descriptor ring memory */
- struct i40e_virt_mem cmd_buf; /* command buffer memory */
+struct iavf_adminq_ring {
+ struct iavf_virt_mem dma_head; /* space for dma structures */
+ struct iavf_dma_mem desc_buf; /* descriptor ring memory */
+ struct iavf_virt_mem cmd_buf; /* command buffer memory */
union {
- struct i40e_dma_mem *asq_bi;
- struct i40e_dma_mem *arq_bi;
+ struct iavf_dma_mem *asq_bi;
+ struct iavf_dma_mem *arq_bi;
} r;
u16 count; /* Number of descriptors */
@@ -61,9 +61,9 @@ struct i40e_arq_event_info {
};
/* Admin Queue information */
-struct i40e_adminq_info {
- struct i40e_adminq_ring arq; /* receive queue */
- struct i40e_adminq_ring asq; /* send queue */
+struct iavf_adminq_info {
+ struct iavf_adminq_ring arq; /* receive queue */
+ struct iavf_adminq_ring asq; /* send queue */
u32 asq_cmd_timeout; /* send queue cmd write back timeout*/
u16 num_arq_entries; /* receive queue depth */
u16 num_asq_entries; /* send queue depth */
@@ -130,7 +130,6 @@ static inline int i40e_aq_rc_to_posix(int aq_ret, int aq_rc)
#define I40E_AQ_LARGE_BUF 512
#define I40E_ASQ_CMD_TIMEOUT 250000 /* usecs */
-void i40evf_fill_default_direct_cmd_desc(struct i40e_aq_desc *desc,
- u16 opcode);
+void iavf_fill_default_direct_cmd_desc(struct i40e_aq_desc *desc, u16 opcode);
-#endif /* _I40E_ADMINQ_H_ */
+#endif /* _IAVF_ADMINQ_H_ */
diff --git a/drivers/net/ethernet/intel/iavf/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/iavf/i40e_adminq_cmd.h
new file mode 100644
index 000000000000..af4f94a6541e
--- /dev/null
+++ b/drivers/net/ethernet/intel/iavf/i40e_adminq_cmd.h
@@ -0,0 +1,530 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
+
+#ifndef _I40E_ADMINQ_CMD_H_
+#define _I40E_ADMINQ_CMD_H_
+
+/* This header file defines the i40e Admin Queue commands and is shared between
+ * i40e Firmware and Software. Do not change the names in this file to IAVF
+ * because this file should be diff-able against the i40e version, even
+ * though many parts have been removed in this VF version.
+ *
+ * This file needs to comply with the Linux Kernel coding style.
+ */
+
+#define I40E_FW_API_VERSION_MAJOR 0x0001
+#define I40E_FW_API_VERSION_MINOR_X722 0x0005
+#define I40E_FW_API_VERSION_MINOR_X710 0x0007
+
+#define I40E_FW_MINOR_VERSION(_h) ((_h)->mac.type == I40E_MAC_XL710 ? \
+ I40E_FW_API_VERSION_MINOR_X710 : \
+ I40E_FW_API_VERSION_MINOR_X722)
+
+/* API version 1.7 implements additional link and PHY-specific APIs */
+#define I40E_MINOR_VER_GET_LINK_INFO_XL710 0x0007
+
+struct i40e_aq_desc {
+ __le16 flags;
+ __le16 opcode;
+ __le16 datalen;
+ __le16 retval;
+ __le32 cookie_high;
+ __le32 cookie_low;
+ union {
+ struct {
+ __le32 param0;
+ __le32 param1;
+ __le32 param2;
+ __le32 param3;
+ } internal;
+ struct {
+ __le32 param0;
+ __le32 param1;
+ __le32 addr_high;
+ __le32 addr_low;
+ } external;
+ u8 raw[16];
+ } params;
+};
+
+/* Flags sub-structure
+ * |0 |1 |2 |3 |4 |5 |6 |7 |8 |9 |10 |11 |12 |13 |14 |15 |
+ * |DD |CMP|ERR|VFE| * * RESERVED * * |LB |RD |VFC|BUF|SI |EI |FE |
+ */
+
+/* command flags and offsets*/
+#define I40E_AQ_FLAG_DD_SHIFT 0
+#define I40E_AQ_FLAG_CMP_SHIFT 1
+#define I40E_AQ_FLAG_ERR_SHIFT 2
+#define I40E_AQ_FLAG_VFE_SHIFT 3
+#define I40E_AQ_FLAG_LB_SHIFT 9
+#define I40E_AQ_FLAG_RD_SHIFT 10
+#define I40E_AQ_FLAG_VFC_SHIFT 11
+#define I40E_AQ_FLAG_BUF_SHIFT 12
+#define I40E_AQ_FLAG_SI_SHIFT 13
+#define I40E_AQ_FLAG_EI_SHIFT 14
+#define I40E_AQ_FLAG_FE_SHIFT 15
+
+#define I40E_AQ_FLAG_DD BIT(I40E_AQ_FLAG_DD_SHIFT) /* 0x1 */
+#define I40E_AQ_FLAG_CMP BIT(I40E_AQ_FLAG_CMP_SHIFT) /* 0x2 */
+#define I40E_AQ_FLAG_ERR BIT(I40E_AQ_FLAG_ERR_SHIFT) /* 0x4 */
+#define I40E_AQ_FLAG_VFE BIT(I40E_AQ_FLAG_VFE_SHIFT) /* 0x8 */
+#define I40E_AQ_FLAG_LB BIT(I40E_AQ_FLAG_LB_SHIFT) /* 0x200 */
+#define I40E_AQ_FLAG_RD BIT(I40E_AQ_FLAG_RD_SHIFT) /* 0x400 */
+#define I40E_AQ_FLAG_VFC BIT(I40E_AQ_FLAG_VFC_SHIFT) /* 0x800 */
+#define I40E_AQ_FLAG_BUF BIT(I40E_AQ_FLAG_BUF_SHIFT) /* 0x1000 */
+#define I40E_AQ_FLAG_SI BIT(I40E_AQ_FLAG_SI_SHIFT) /* 0x2000 */
+#define I40E_AQ_FLAG_EI BIT(I40E_AQ_FLAG_EI_SHIFT) /* 0x4000 */
+#define I40E_AQ_FLAG_FE BIT(I40E_AQ_FLAG_FE_SHIFT) /* 0x8000 */
+
+/* error codes */
+enum i40e_admin_queue_err {
+ I40E_AQ_RC_OK = 0, /* success */
+ I40E_AQ_RC_EPERM = 1, /* Operation not permitted */
+ I40E_AQ_RC_ENOENT = 2, /* No such element */
+ I40E_AQ_RC_ESRCH = 3, /* Bad opcode */
+ I40E_AQ_RC_EINTR = 4, /* operation interrupted */
+ I40E_AQ_RC_EIO = 5, /* I/O error */
+ I40E_AQ_RC_ENXIO = 6, /* No such resource */
+ I40E_AQ_RC_E2BIG = 7, /* Arg too long */
+ I40E_AQ_RC_EAGAIN = 8, /* Try again */
+ I40E_AQ_RC_ENOMEM = 9, /* Out of memory */
+ I40E_AQ_RC_EACCES = 10, /* Permission denied */
+ I40E_AQ_RC_EFAULT = 11, /* Bad address */
+ I40E_AQ_RC_EBUSY = 12, /* Device or resource busy */
+ I40E_AQ_RC_EEXIST = 13, /* object already exists */
+ I40E_AQ_RC_EINVAL = 14, /* Invalid argument */
+ I40E_AQ_RC_ENOTTY = 15, /* Not a typewriter */
+ I40E_AQ_RC_ENOSPC = 16, /* No space left or alloc failure */
+ I40E_AQ_RC_ENOSYS = 17, /* Function not implemented */
+ I40E_AQ_RC_ERANGE = 18, /* Parameter out of range */
+ I40E_AQ_RC_EFLUSHED = 19, /* Cmd flushed due to prev cmd error */
+ I40E_AQ_RC_BAD_ADDR = 20, /* Descriptor contains a bad pointer */
+ I40E_AQ_RC_EMODE = 21, /* Op not allowed in current dev mode */
+ I40E_AQ_RC_EFBIG = 22, /* File too large */
+};
+
+/* Admin Queue command opcodes */
+enum i40e_admin_queue_opc {
+ /* aq commands */
+ i40e_aqc_opc_get_version = 0x0001,
+ i40e_aqc_opc_driver_version = 0x0002,
+ i40e_aqc_opc_queue_shutdown = 0x0003,
+ i40e_aqc_opc_set_pf_context = 0x0004,
+
+ /* resource ownership */
+ i40e_aqc_opc_request_resource = 0x0008,
+ i40e_aqc_opc_release_resource = 0x0009,
+
+ i40e_aqc_opc_list_func_capabilities = 0x000A,
+ i40e_aqc_opc_list_dev_capabilities = 0x000B,
+
+ /* Proxy commands */
+ i40e_aqc_opc_set_proxy_config = 0x0104,
+ i40e_aqc_opc_set_ns_proxy_table_entry = 0x0105,
+
+ /* LAA */
+ i40e_aqc_opc_mac_address_read = 0x0107,
+ i40e_aqc_opc_mac_address_write = 0x0108,
+
+ /* PXE */
+ i40e_aqc_opc_clear_pxe_mode = 0x0110,
+
+ /* WoL commands */
+ i40e_aqc_opc_set_wol_filter = 0x0120,
+ i40e_aqc_opc_get_wake_reason = 0x0121,
+
+ /* internal switch commands */
+ i40e_aqc_opc_get_switch_config = 0x0200,
+ i40e_aqc_opc_add_statistics = 0x0201,
+ i40e_aqc_opc_remove_statistics = 0x0202,
+ i40e_aqc_opc_set_port_parameters = 0x0203,
+ i40e_aqc_opc_get_switch_resource_alloc = 0x0204,
+ i40e_aqc_opc_set_switch_config = 0x0205,
+ i40e_aqc_opc_rx_ctl_reg_read = 0x0206,
+ i40e_aqc_opc_rx_ctl_reg_write = 0x0207,
+
+ i40e_aqc_opc_add_vsi = 0x0210,
+ i40e_aqc_opc_update_vsi_parameters = 0x0211,
+ i40e_aqc_opc_get_vsi_parameters = 0x0212,
+
+ i40e_aqc_opc_add_pv = 0x0220,
+ i40e_aqc_opc_update_pv_parameters = 0x0221,
+ i40e_aqc_opc_get_pv_parameters = 0x0222,
+
+ i40e_aqc_opc_add_veb = 0x0230,
+ i40e_aqc_opc_update_veb_parameters = 0x0231,
+ i40e_aqc_opc_get_veb_parameters = 0x0232,
+
+ i40e_aqc_opc_delete_element = 0x0243,
+
+ i40e_aqc_opc_add_macvlan = 0x0250,
+ i40e_aqc_opc_remove_macvlan = 0x0251,
+ i40e_aqc_opc_add_vlan = 0x0252,
+ i40e_aqc_opc_remove_vlan = 0x0253,
+ i40e_aqc_opc_set_vsi_promiscuous_modes = 0x0254,
+ i40e_aqc_opc_add_tag = 0x0255,
+ i40e_aqc_opc_remove_tag = 0x0256,
+ i40e_aqc_opc_add_multicast_etag = 0x0257,
+ i40e_aqc_opc_remove_multicast_etag = 0x0258,
+ i40e_aqc_opc_update_tag = 0x0259,
+ i40e_aqc_opc_add_control_packet_filter = 0x025A,
+ i40e_aqc_opc_remove_control_packet_filter = 0x025B,
+ i40e_aqc_opc_add_cloud_filters = 0x025C,
+ i40e_aqc_opc_remove_cloud_filters = 0x025D,
+ i40e_aqc_opc_clear_wol_switch_filters = 0x025E,
+
+ i40e_aqc_opc_add_mirror_rule = 0x0260,
+ i40e_aqc_opc_delete_mirror_rule = 0x0261,
+
+ /* Dynamic Device Personalization */
+ i40e_aqc_opc_write_personalization_profile = 0x0270,
+ i40e_aqc_opc_get_personalization_profile_list = 0x0271,
+
+ /* DCB commands */
+ i40e_aqc_opc_dcb_ignore_pfc = 0x0301,
+ i40e_aqc_opc_dcb_updated = 0x0302,
+ i40e_aqc_opc_set_dcb_parameters = 0x0303,
+
+ /* TX scheduler */
+ i40e_aqc_opc_configure_vsi_bw_limit = 0x0400,
+ i40e_aqc_opc_configure_vsi_ets_sla_bw_limit = 0x0406,
+ i40e_aqc_opc_configure_vsi_tc_bw = 0x0407,
+ i40e_aqc_opc_query_vsi_bw_config = 0x0408,
+ i40e_aqc_opc_query_vsi_ets_sla_config = 0x040A,
+ i40e_aqc_opc_configure_switching_comp_bw_limit = 0x0410,
+
+ i40e_aqc_opc_enable_switching_comp_ets = 0x0413,
+ i40e_aqc_opc_modify_switching_comp_ets = 0x0414,
+ i40e_aqc_opc_disable_switching_comp_ets = 0x0415,
+ i40e_aqc_opc_configure_switching_comp_ets_bw_limit = 0x0416,
+ i40e_aqc_opc_configure_switching_comp_bw_config = 0x0417,
+ i40e_aqc_opc_query_switching_comp_ets_config = 0x0418,
+ i40e_aqc_opc_query_port_ets_config = 0x0419,
+ i40e_aqc_opc_query_switching_comp_bw_config = 0x041A,
+ i40e_aqc_opc_suspend_port_tx = 0x041B,
+ i40e_aqc_opc_resume_port_tx = 0x041C,
+ i40e_aqc_opc_configure_partition_bw = 0x041D,
+ /* hmc */
+ i40e_aqc_opc_query_hmc_resource_profile = 0x0500,
+ i40e_aqc_opc_set_hmc_resource_profile = 0x0501,
+
+ /* phy commands*/
+ i40e_aqc_opc_get_phy_abilities = 0x0600,
+ i40e_aqc_opc_set_phy_config = 0x0601,
+ i40e_aqc_opc_set_mac_config = 0x0603,
+ i40e_aqc_opc_set_link_restart_an = 0x0605,
+ i40e_aqc_opc_get_link_status = 0x0607,
+ i40e_aqc_opc_set_phy_int_mask = 0x0613,
+ i40e_aqc_opc_get_local_advt_reg = 0x0614,
+ i40e_aqc_opc_set_local_advt_reg = 0x0615,
+ i40e_aqc_opc_get_partner_advt = 0x0616,
+ i40e_aqc_opc_set_lb_modes = 0x0618,
+ i40e_aqc_opc_get_phy_wol_caps = 0x0621,
+ i40e_aqc_opc_set_phy_debug = 0x0622,
+ i40e_aqc_opc_upload_ext_phy_fm = 0x0625,
+ i40e_aqc_opc_run_phy_activity = 0x0626,
+ i40e_aqc_opc_set_phy_register = 0x0628,
+ i40e_aqc_opc_get_phy_register = 0x0629,
+
+ /* NVM commands */
+ i40e_aqc_opc_nvm_read = 0x0701,
+ i40e_aqc_opc_nvm_erase = 0x0702,
+ i40e_aqc_opc_nvm_update = 0x0703,
+ i40e_aqc_opc_nvm_config_read = 0x0704,
+ i40e_aqc_opc_nvm_config_write = 0x0705,
+ i40e_aqc_opc_oem_post_update = 0x0720,
+ i40e_aqc_opc_thermal_sensor = 0x0721,
+
+ /* virtualization commands */
+ i40e_aqc_opc_send_msg_to_pf = 0x0801,
+ i40e_aqc_opc_send_msg_to_vf = 0x0802,
+ i40e_aqc_opc_send_msg_to_peer = 0x0803,
+
+ /* alternate structure */
+ i40e_aqc_opc_alternate_write = 0x0900,
+ i40e_aqc_opc_alternate_write_indirect = 0x0901,
+ i40e_aqc_opc_alternate_read = 0x0902,
+ i40e_aqc_opc_alternate_read_indirect = 0x0903,
+ i40e_aqc_opc_alternate_write_done = 0x0904,
+ i40e_aqc_opc_alternate_set_mode = 0x0905,
+ i40e_aqc_opc_alternate_clear_port = 0x0906,
+
+ /* LLDP commands */
+ i40e_aqc_opc_lldp_get_mib = 0x0A00,
+ i40e_aqc_opc_lldp_update_mib = 0x0A01,
+ i40e_aqc_opc_lldp_add_tlv = 0x0A02,
+ i40e_aqc_opc_lldp_update_tlv = 0x0A03,
+ i40e_aqc_opc_lldp_delete_tlv = 0x0A04,
+ i40e_aqc_opc_lldp_stop = 0x0A05,
+ i40e_aqc_opc_lldp_start = 0x0A06,
+
+ /* Tunnel commands */
+ i40e_aqc_opc_add_udp_tunnel = 0x0B00,
+ i40e_aqc_opc_del_udp_tunnel = 0x0B01,
+ i40e_aqc_opc_set_rss_key = 0x0B02,
+ i40e_aqc_opc_set_rss_lut = 0x0B03,
+ i40e_aqc_opc_get_rss_key = 0x0B04,
+ i40e_aqc_opc_get_rss_lut = 0x0B05,
+
+ /* Async Events */
+ i40e_aqc_opc_event_lan_overflow = 0x1001,
+
+ /* OEM commands */
+ i40e_aqc_opc_oem_parameter_change = 0xFE00,
+ i40e_aqc_opc_oem_device_status_change = 0xFE01,
+ i40e_aqc_opc_oem_ocsd_initialize = 0xFE02,
+ i40e_aqc_opc_oem_ocbb_initialize = 0xFE03,
+
+ /* debug commands */
+ i40e_aqc_opc_debug_read_reg = 0xFF03,
+ i40e_aqc_opc_debug_write_reg = 0xFF04,
+ i40e_aqc_opc_debug_modify_reg = 0xFF07,
+ i40e_aqc_opc_debug_dump_internals = 0xFF08,
+};
+
+/* command structures and indirect data structures */
+
+/* Structure naming conventions:
+ * - no suffix for direct command descriptor structures
+ * - _data for indirect sent data
+ * - _resp for indirect return data (data which is both will use _data)
+ * - _completion for direct return data
+ * - _element_ for repeated elements (may also be _data or _resp)
+ *
+ * Command structures are expected to overlay the params.raw member of the basic
+ * descriptor, and as such cannot exceed 16 bytes in length.
+ */
+
+/* This macro is used to generate a compilation error if a structure
+ * is not exactly the correct length. It gives a divide by zero error if the
+ * structure is not of the correct size, otherwise it creates an enum that is
+ * never used.
+ */
+#define I40E_CHECK_STRUCT_LEN(n, X) enum i40e_static_assert_enum_##X \
+ { i40e_static_assert_##X = (n)/((sizeof(struct X) == (n)) ? 1 : 0) }
+
+/* This macro is used extensively to ensure that command structures are 16
+ * bytes in length as they have to map to the raw array of that size.
+ */
+#define I40E_CHECK_CMD_LENGTH(X) I40E_CHECK_STRUCT_LEN(16, X)
+
+/* Queue Shutdown (direct 0x0003) */
+struct i40e_aqc_queue_shutdown {
+ __le32 driver_unloading;
+#define I40E_AQ_DRIVER_UNLOADING 0x1
+ u8 reserved[12];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_queue_shutdown);
+
+struct i40e_aqc_vsi_properties_data {
+ /* first 96 byte are written by SW */
+ __le16 valid_sections;
+#define I40E_AQ_VSI_PROP_SWITCH_VALID 0x0001
+#define I40E_AQ_VSI_PROP_SECURITY_VALID 0x0002
+#define I40E_AQ_VSI_PROP_VLAN_VALID 0x0004
+#define I40E_AQ_VSI_PROP_CAS_PV_VALID 0x0008
+#define I40E_AQ_VSI_PROP_INGRESS_UP_VALID 0x0010
+#define I40E_AQ_VSI_PROP_EGRESS_UP_VALID 0x0020
+#define I40E_AQ_VSI_PROP_QUEUE_MAP_VALID 0x0040
+#define I40E_AQ_VSI_PROP_QUEUE_OPT_VALID 0x0080
+#define I40E_AQ_VSI_PROP_OUTER_UP_VALID 0x0100
+#define I40E_AQ_VSI_PROP_SCHED_VALID 0x0200
+ /* switch section */
+ __le16 switch_id; /* 12bit id combined with flags below */
+#define I40E_AQ_VSI_SW_ID_SHIFT 0x0000
+#define I40E_AQ_VSI_SW_ID_MASK (0xFFF << I40E_AQ_VSI_SW_ID_SHIFT)
+#define I40E_AQ_VSI_SW_ID_FLAG_NOT_STAG 0x1000
+#define I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB 0x2000
+#define I40E_AQ_VSI_SW_ID_FLAG_LOCAL_LB 0x4000
+ u8 sw_reserved[2];
+ /* security section */
+ u8 sec_flags;
+#define I40E_AQ_VSI_SEC_FLAG_ALLOW_DEST_OVRD 0x01
+#define I40E_AQ_VSI_SEC_FLAG_ENABLE_VLAN_CHK 0x02
+#define I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK 0x04
+ u8 sec_reserved;
+ /* VLAN section */
+ __le16 pvid; /* VLANS include priority bits */
+ __le16 fcoe_pvid;
+ u8 port_vlan_flags;
+#define I40E_AQ_VSI_PVLAN_MODE_SHIFT 0x00
+#define I40E_AQ_VSI_PVLAN_MODE_MASK (0x03 << \
+ I40E_AQ_VSI_PVLAN_MODE_SHIFT)
+#define I40E_AQ_VSI_PVLAN_MODE_TAGGED 0x01
+#define I40E_AQ_VSI_PVLAN_MODE_UNTAGGED 0x02
+#define I40E_AQ_VSI_PVLAN_MODE_ALL 0x03
+#define I40E_AQ_VSI_PVLAN_INSERT_PVID 0x04
+#define I40E_AQ_VSI_PVLAN_EMOD_SHIFT 0x03
+#define I40E_AQ_VSI_PVLAN_EMOD_MASK (0x3 << \
+ I40E_AQ_VSI_PVLAN_EMOD_SHIFT)
+#define I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH 0x0
+#define I40E_AQ_VSI_PVLAN_EMOD_STR_UP 0x08
+#define I40E_AQ_VSI_PVLAN_EMOD_STR 0x10
+#define I40E_AQ_VSI_PVLAN_EMOD_NOTHING 0x18
+ u8 pvlan_reserved[3];
+ /* ingress egress up sections */
+ __le32 ingress_table; /* bitmap, 3 bits per up */
+#define I40E_AQ_VSI_UP_TABLE_UP0_SHIFT 0
+#define I40E_AQ_VSI_UP_TABLE_UP0_MASK (0x7 << \
+ I40E_AQ_VSI_UP_TABLE_UP0_SHIFT)
+#define I40E_AQ_VSI_UP_TABLE_UP1_SHIFT 3
+#define I40E_AQ_VSI_UP_TABLE_UP1_MASK (0x7 << \
+ I40E_AQ_VSI_UP_TABLE_UP1_SHIFT)
+#define I40E_AQ_VSI_UP_TABLE_UP2_SHIFT 6
+#define I40E_AQ_VSI_UP_TABLE_UP2_MASK (0x7 << \
+ I40E_AQ_VSI_UP_TABLE_UP2_SHIFT)
+#define I40E_AQ_VSI_UP_TABLE_UP3_SHIFT 9
+#define I40E_AQ_VSI_UP_TABLE_UP3_MASK (0x7 << \
+ I40E_AQ_VSI_UP_TABLE_UP3_SHIFT)
+#define I40E_AQ_VSI_UP_TABLE_UP4_SHIFT 12
+#define I40E_AQ_VSI_UP_TABLE_UP4_MASK (0x7 << \
+ I40E_AQ_VSI_UP_TABLE_UP4_SHIFT)
+#define I40E_AQ_VSI_UP_TABLE_UP5_SHIFT 15
+#define I40E_AQ_VSI_UP_TABLE_UP5_MASK (0x7 << \
+ I40E_AQ_VSI_UP_TABLE_UP5_SHIFT)
+#define I40E_AQ_VSI_UP_TABLE_UP6_SHIFT 18
+#define I40E_AQ_VSI_UP_TABLE_UP6_MASK (0x7 << \
+ I40E_AQ_VSI_UP_TABLE_UP6_SHIFT)
+#define I40E_AQ_VSI_UP_TABLE_UP7_SHIFT 21
+#define I40E_AQ_VSI_UP_TABLE_UP7_MASK (0x7 << \
+ I40E_AQ_VSI_UP_TABLE_UP7_SHIFT)
+ __le32 egress_table; /* same defines as for ingress table */
+ /* cascaded PV section */
+ __le16 cas_pv_tag;
+ u8 cas_pv_flags;
+#define I40E_AQ_VSI_CAS_PV_TAGX_SHIFT 0x00
+#define I40E_AQ_VSI_CAS_PV_TAGX_MASK (0x03 << \
+ I40E_AQ_VSI_CAS_PV_TAGX_SHIFT)
+#define I40E_AQ_VSI_CAS_PV_TAGX_LEAVE 0x00
+#define I40E_AQ_VSI_CAS_PV_TAGX_REMOVE 0x01
+#define I40E_AQ_VSI_CAS_PV_TAGX_COPY 0x02
+#define I40E_AQ_VSI_CAS_PV_INSERT_TAG 0x10
+#define I40E_AQ_VSI_CAS_PV_ETAG_PRUNE 0x20
+#define I40E_AQ_VSI_CAS_PV_ACCEPT_HOST_TAG 0x40
+ u8 cas_pv_reserved;
+ /* queue mapping section */
+ __le16 mapping_flags;
+#define I40E_AQ_VSI_QUE_MAP_CONTIG 0x0
+#define I40E_AQ_VSI_QUE_MAP_NONCONTIG 0x1
+ __le16 queue_mapping[16];
+#define I40E_AQ_VSI_QUEUE_SHIFT 0x0
+#define I40E_AQ_VSI_QUEUE_MASK (0x7FF << I40E_AQ_VSI_QUEUE_SHIFT)
+ __le16 tc_mapping[8];
+#define I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT 0
+#define I40E_AQ_VSI_TC_QUE_OFFSET_MASK (0x1FF << \
+ I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT)
+#define I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT 9
+#define I40E_AQ_VSI_TC_QUE_NUMBER_MASK (0x7 << \
+ I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT)
+ /* queueing option section */
+ u8 queueing_opt_flags;
+#define I40E_AQ_VSI_QUE_OPT_MULTICAST_UDP_ENA 0x04
+#define I40E_AQ_VSI_QUE_OPT_UNICAST_UDP_ENA 0x08
+#define I40E_AQ_VSI_QUE_OPT_TCP_ENA 0x10
+#define I40E_AQ_VSI_QUE_OPT_FCOE_ENA 0x20
+#define I40E_AQ_VSI_QUE_OPT_RSS_LUT_PF 0x00
+#define I40E_AQ_VSI_QUE_OPT_RSS_LUT_VSI 0x40
+ u8 queueing_opt_reserved[3];
+ /* scheduler section */
+ u8 up_enable_bits;
+ u8 sched_reserved;
+ /* outer up section */
+ __le32 outer_up_table; /* same structure and defines as ingress tbl */
+ u8 cmd_reserved[8];
+ /* last 32 bytes are written by FW */
+ __le16 qs_handle[8];
+#define I40E_AQ_VSI_QS_HANDLE_INVALID 0xFFFF
+ __le16 stat_counter_idx;
+ __le16 sched_id;
+ u8 resp_reserved[12];
+};
+
+I40E_CHECK_STRUCT_LEN(128, i40e_aqc_vsi_properties_data);
+
+/* Get VEB Parameters (direct 0x0232)
+ * uses i40e_aqc_switch_seid for the descriptor
+ */
+struct i40e_aqc_get_veb_parameters_completion {
+ __le16 seid;
+ __le16 switch_id;
+ __le16 veb_flags; /* only the first/last flags from 0x0230 is valid */
+ __le16 statistic_index;
+ __le16 vebs_used;
+ __le16 vebs_free;
+ u8 reserved[4];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_get_veb_parameters_completion);
+
+#define I40E_LINK_SPEED_100MB_SHIFT 0x1
+#define I40E_LINK_SPEED_1000MB_SHIFT 0x2
+#define I40E_LINK_SPEED_10GB_SHIFT 0x3
+#define I40E_LINK_SPEED_40GB_SHIFT 0x4
+#define I40E_LINK_SPEED_20GB_SHIFT 0x5
+#define I40E_LINK_SPEED_25GB_SHIFT 0x6
+
+enum i40e_aq_link_speed {
+ I40E_LINK_SPEED_UNKNOWN = 0,
+ I40E_LINK_SPEED_100MB = BIT(I40E_LINK_SPEED_100MB_SHIFT),
+ I40E_LINK_SPEED_1GB = BIT(I40E_LINK_SPEED_1000MB_SHIFT),
+ I40E_LINK_SPEED_10GB = BIT(I40E_LINK_SPEED_10GB_SHIFT),
+ I40E_LINK_SPEED_40GB = BIT(I40E_LINK_SPEED_40GB_SHIFT),
+ I40E_LINK_SPEED_20GB = BIT(I40E_LINK_SPEED_20GB_SHIFT),
+ I40E_LINK_SPEED_25GB = BIT(I40E_LINK_SPEED_25GB_SHIFT),
+};
+
+/* Send to PF command (indirect 0x0801) id is only used by PF
+ * Send to VF command (indirect 0x0802) id is only used by PF
+ * Send to Peer PF command (indirect 0x0803)
+ */
+struct i40e_aqc_pf_vf_message {
+ __le32 id;
+ u8 reserved[4];
+ __le32 addr_high;
+ __le32 addr_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_pf_vf_message);
+
+struct i40e_aqc_get_set_rss_key {
+#define I40E_AQC_SET_RSS_KEY_VSI_VALID BIT(15)
+#define I40E_AQC_SET_RSS_KEY_VSI_ID_SHIFT 0
+#define I40E_AQC_SET_RSS_KEY_VSI_ID_MASK (0x3FF << \
+ I40E_AQC_SET_RSS_KEY_VSI_ID_SHIFT)
+ __le16 vsi_id;
+ u8 reserved[6];
+ __le32 addr_high;
+ __le32 addr_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_get_set_rss_key);
+
+struct i40e_aqc_get_set_rss_key_data {
+ u8 standard_rss_key[0x28];
+ u8 extended_hash_key[0xc];
+};
+
+I40E_CHECK_STRUCT_LEN(0x34, i40e_aqc_get_set_rss_key_data);
+
+struct i40e_aqc_get_set_rss_lut {
+#define I40E_AQC_SET_RSS_LUT_VSI_VALID BIT(15)
+#define I40E_AQC_SET_RSS_LUT_VSI_ID_SHIFT 0
+#define I40E_AQC_SET_RSS_LUT_VSI_ID_MASK (0x3FF << \
+ I40E_AQC_SET_RSS_LUT_VSI_ID_SHIFT)
+ __le16 vsi_id;
+#define I40E_AQC_SET_RSS_LUT_TABLE_TYPE_SHIFT 0
+#define I40E_AQC_SET_RSS_LUT_TABLE_TYPE_MASK \
+ BIT(I40E_AQC_SET_RSS_LUT_TABLE_TYPE_SHIFT)
+
+#define I40E_AQC_SET_RSS_LUT_TABLE_TYPE_VSI 0
+#define I40E_AQC_SET_RSS_LUT_TABLE_TYPE_PF 1
+ __le16 flags;
+ u8 reserved[4];
+ __le32 addr_high;
+ __le32 addr_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_get_set_rss_lut);
+#endif /* _I40E_ADMINQ_CMD_H_ */
diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h
new file mode 100644
index 000000000000..272d76b733aa
--- /dev/null
+++ b/drivers/net/ethernet/intel/iavf/iavf.h
@@ -0,0 +1,418 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
+
+#ifndef _IAVF_H_
+#define _IAVF_H_
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/aer.h>
+#include <linux/netdevice.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/sctp.h>
+#include <linux/ipv6.h>
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/gfp.h>
+#include <linux/skbuff.h>
+#include <linux/dma-mapping.h>
+#include <linux/etherdevice.h>
+#include <linux/socket.h>
+#include <linux/jiffies.h>
+#include <net/ip6_checksum.h>
+#include <net/pkt_cls.h>
+#include <net/udp.h>
+#include <net/tc_act/tc_gact.h>
+#include <net/tc_act/tc_mirred.h>
+
+#include "iavf_type.h"
+#include <linux/avf/virtchnl.h>
+#include "iavf_txrx.h"
+
+#define DEFAULT_DEBUG_LEVEL_SHIFT 3
+#define PFX "iavf: "
+
+/* VSI state flags shared with common code */
+enum iavf_vsi_state_t {
+ __IAVF_VSI_DOWN,
+ /* This must be last as it determines the size of the BITMAP */
+ __IAVF_VSI_STATE_SIZE__,
+};
+
+/* dummy struct to make common code less painful */
+struct iavf_vsi {
+ struct iavf_adapter *back;
+ struct net_device *netdev;
+ unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
+ u16 seid;
+ u16 id;
+ DECLARE_BITMAP(state, __IAVF_VSI_STATE_SIZE__);
+ int base_vector;
+ u16 work_limit;
+ u16 qs_handle;
+ void *priv; /* client driver data reference. */
+};
+
+/* How many Rx Buffers do we bundle into one write to the hardware ? */
+#define IAVF_RX_BUFFER_WRITE 16 /* Must be power of 2 */
+#define IAVF_DEFAULT_TXD 512
+#define IAVF_DEFAULT_RXD 512
+#define IAVF_MAX_TXD 4096
+#define IAVF_MIN_TXD 64
+#define IAVF_MAX_RXD 4096
+#define IAVF_MIN_RXD 64
+#define IAVF_REQ_DESCRIPTOR_MULTIPLE 32
+#define IAVF_MAX_AQ_BUF_SIZE 4096
+#define IAVF_AQ_LEN 32
+#define IAVF_AQ_MAX_ERR 20 /* times to try before resetting AQ */
+
+#define MAXIMUM_ETHERNET_VLAN_SIZE (VLAN_ETH_FRAME_LEN + ETH_FCS_LEN)
+
+#define IAVF_RX_DESC(R, i) (&(((union iavf_32byte_rx_desc *)((R)->desc))[i]))
+#define IAVF_TX_DESC(R, i) (&(((struct iavf_tx_desc *)((R)->desc))[i]))
+#define IAVF_TX_CTXTDESC(R, i) \
+ (&(((struct iavf_tx_context_desc *)((R)->desc))[i]))
+#define IAVF_MAX_REQ_QUEUES 4
+
+#define IAVF_HKEY_ARRAY_SIZE ((IAVF_VFQF_HKEY_MAX_INDEX + 1) * 4)
+#define IAVF_HLUT_ARRAY_SIZE ((IAVF_VFQF_HLUT_MAX_INDEX + 1) * 4)
+#define IAVF_MBPS_DIVISOR 125000 /* divisor to convert to Mbps */
+
+/* MAX_MSIX_Q_VECTORS of these are allocated,
+ * but we only use one per queue-specific vector.
+ */
+struct iavf_q_vector {
+ struct iavf_adapter *adapter;
+ struct iavf_vsi *vsi;
+ struct napi_struct napi;
+ struct iavf_ring_container rx;
+ struct iavf_ring_container tx;
+ u32 ring_mask;
+ u8 itr_countdown; /* when 0 should adjust adaptive ITR */
+ u8 num_ringpairs; /* total number of ring pairs in vector */
+ u16 v_idx; /* index in the vsi->q_vector array. */
+ u16 reg_idx; /* register index of the interrupt */
+ char name[IFNAMSIZ + 15];
+ bool arm_wb_state;
+ cpumask_t affinity_mask;
+ struct irq_affinity_notify affinity_notify;
+};
+
+/* Helper macros to switch between ints/sec and what the register uses.
+ * And yes, it's the same math going both ways. The lowest value
+ * supported by all of the i40e hardware is 8.
+ */
+#define EITR_INTS_PER_SEC_TO_REG(_eitr) \
+ ((_eitr) ? (1000000000 / ((_eitr) * 256)) : 8)
+#define EITR_REG_TO_INTS_PER_SEC EITR_INTS_PER_SEC_TO_REG
+
+#define IAVF_DESC_UNUSED(R) \
+ ((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \
+ (R)->next_to_clean - (R)->next_to_use - 1)
+
+#define OTHER_VECTOR 1
+#define NONQ_VECS (OTHER_VECTOR)
+
+#define MIN_MSIX_Q_VECTORS 1
+#define MIN_MSIX_COUNT (MIN_MSIX_Q_VECTORS + NONQ_VECS)
+
+#define IAVF_QUEUE_END_OF_LIST 0x7FF
+#define IAVF_FREE_VECTOR 0x7FFF
+struct iavf_mac_filter {
+ struct list_head list;
+ u8 macaddr[ETH_ALEN];
+ bool remove; /* filter needs to be removed */
+ bool add; /* filter needs to be added */
+};
+
+struct iavf_vlan_filter {
+ struct list_head list;
+ u16 vlan;
+ bool remove; /* filter needs to be removed */
+ bool add; /* filter needs to be added */
+};
+
+#define IAVF_MAX_TRAFFIC_CLASS 4
+/* State of traffic class creation */
+enum iavf_tc_state_t {
+ __IAVF_TC_INVALID, /* no traffic class, default state */
+ __IAVF_TC_RUNNING, /* traffic classes have been created */
+};
+
+/* channel info */
+struct iavf_channel_config {
+ struct virtchnl_channel_info ch_info[IAVF_MAX_TRAFFIC_CLASS];
+ enum iavf_tc_state_t state;
+ u8 total_qps;
+};
+
+/* State of cloud filter */
+enum iavf_cloud_filter_state_t {
+ __IAVF_CF_INVALID, /* cloud filter not added */
+ __IAVF_CF_ADD_PENDING, /* cloud filter pending add by the PF */
+ __IAVF_CF_DEL_PENDING, /* cloud filter pending del by the PF */
+ __IAVF_CF_ACTIVE, /* cloud filter is active */
+};
+
+/* Driver state. The order of these is important! */
+enum iavf_state_t {
+ __IAVF_STARTUP, /* driver loaded, probe complete */
+ __IAVF_REMOVE, /* driver is being unloaded */
+ __IAVF_INIT_VERSION_CHECK, /* aq msg sent, awaiting reply */
+ __IAVF_INIT_GET_RESOURCES, /* aq msg sent, awaiting reply */
+ __IAVF_INIT_SW, /* got resources, setting up structs */
+ __IAVF_RESETTING, /* in reset */
+ /* Below here, watchdog is running */
+ __IAVF_DOWN, /* ready, can be opened */
+ __IAVF_DOWN_PENDING, /* descending, waiting for watchdog */
+ __IAVF_TESTING, /* in ethtool self-test */
+ __IAVF_RUNNING, /* opened, working */
+};
+
+enum iavf_critical_section_t {
+ __IAVF_IN_CRITICAL_TASK, /* cannot be interrupted */
+ __IAVF_IN_CLIENT_TASK,
+ __IAVF_IN_REMOVE_TASK, /* device being removed */
+};
+
+#define IAVF_CLOUD_FIELD_OMAC 0x01
+#define IAVF_CLOUD_FIELD_IMAC 0x02
+#define IAVF_CLOUD_FIELD_IVLAN 0x04
+#define IAVF_CLOUD_FIELD_TEN_ID 0x08
+#define IAVF_CLOUD_FIELD_IIP 0x10
+
+#define IAVF_CF_FLAGS_OMAC IAVF_CLOUD_FIELD_OMAC
+#define IAVF_CF_FLAGS_IMAC IAVF_CLOUD_FIELD_IMAC
+#define IAVF_CF_FLAGS_IMAC_IVLAN (IAVF_CLOUD_FIELD_IMAC |\
+ IAVF_CLOUD_FIELD_IVLAN)
+#define IAVF_CF_FLAGS_IMAC_TEN_ID (IAVF_CLOUD_FIELD_IMAC |\
+ IAVF_CLOUD_FIELD_TEN_ID)
+#define IAVF_CF_FLAGS_OMAC_TEN_ID_IMAC (IAVF_CLOUD_FIELD_OMAC |\
+ IAVF_CLOUD_FIELD_IMAC |\
+ IAVF_CLOUD_FIELD_TEN_ID)
+#define IAVF_CF_FLAGS_IMAC_IVLAN_TEN_ID (IAVF_CLOUD_FIELD_IMAC |\
+ IAVF_CLOUD_FIELD_IVLAN |\
+ IAVF_CLOUD_FIELD_TEN_ID)
+#define IAVF_CF_FLAGS_IIP IAVF_CLOUD_FIELD_IIP
+
+/* bookkeeping of cloud filters */
+struct iavf_cloud_filter {
+ enum iavf_cloud_filter_state_t state;
+ struct list_head list;
+ struct virtchnl_filter f;
+ unsigned long cookie;
+ bool del; /* filter needs to be deleted */
+ bool add; /* filter needs to be added */
+};
+
+/* board specific private data structure */
+struct iavf_adapter {
+ struct timer_list watchdog_timer;
+ struct work_struct reset_task;
+ struct work_struct adminq_task;
+ struct delayed_work client_task;
+ struct delayed_work init_task;
+ wait_queue_head_t down_waitqueue;
+ struct iavf_q_vector *q_vectors;
+ struct list_head vlan_filter_list;
+ struct list_head mac_filter_list;
+ /* Lock to protect accesses to MAC and VLAN lists */
+ spinlock_t mac_vlan_list_lock;
+ char misc_vector_name[IFNAMSIZ + 9];
+ int num_active_queues;
+ int num_req_queues;
+
+ /* TX */
+ struct iavf_ring *tx_rings;
+ u32 tx_timeout_count;
+ u32 tx_desc_count;
+
+ /* RX */
+ struct iavf_ring *rx_rings;
+ u64 hw_csum_rx_error;
+ u32 rx_desc_count;
+ int num_msix_vectors;
+ int num_iwarp_msix;
+ int iwarp_base_vector;
+ u32 client_pending;
+ struct i40e_client_instance *cinst;
+ struct msix_entry *msix_entries;
+
+ u32 flags;
+#define IAVF_FLAG_RX_CSUM_ENABLED BIT(0)
+#define IAVF_FLAG_PF_COMMS_FAILED BIT(3)
+#define IAVF_FLAG_RESET_PENDING BIT(4)
+#define IAVF_FLAG_RESET_NEEDED BIT(5)
+#define IAVF_FLAG_WB_ON_ITR_CAPABLE BIT(6)
+#define IAVF_FLAG_ADDR_SET_BY_PF BIT(8)
+#define IAVF_FLAG_SERVICE_CLIENT_REQUESTED BIT(9)
+#define IAVF_FLAG_CLIENT_NEEDS_OPEN BIT(10)
+#define IAVF_FLAG_CLIENT_NEEDS_CLOSE BIT(11)
+#define IAVF_FLAG_CLIENT_NEEDS_L2_PARAMS BIT(12)
+#define IAVF_FLAG_PROMISC_ON BIT(13)
+#define IAVF_FLAG_ALLMULTI_ON BIT(14)
+#define IAVF_FLAG_LEGACY_RX BIT(15)
+#define IAVF_FLAG_REINIT_ITR_NEEDED BIT(16)
+#define IAVF_FLAG_QUEUES_DISABLED BIT(17)
+/* duplicates for common code */
+#define IAVF_FLAG_DCB_ENABLED 0
+ /* flags for admin queue service task */
+ u32 aq_required;
+#define IAVF_FLAG_AQ_ENABLE_QUEUES BIT(0)
+#define IAVF_FLAG_AQ_DISABLE_QUEUES BIT(1)
+#define IAVF_FLAG_AQ_ADD_MAC_FILTER BIT(2)
+#define IAVF_FLAG_AQ_ADD_VLAN_FILTER BIT(3)
+#define IAVF_FLAG_AQ_DEL_MAC_FILTER BIT(4)
+#define IAVF_FLAG_AQ_DEL_VLAN_FILTER BIT(5)
+#define IAVF_FLAG_AQ_CONFIGURE_QUEUES BIT(6)
+#define IAVF_FLAG_AQ_MAP_VECTORS BIT(7)
+#define IAVF_FLAG_AQ_HANDLE_RESET BIT(8)
+#define IAVF_FLAG_AQ_CONFIGURE_RSS BIT(9) /* direct AQ config */
+#define IAVF_FLAG_AQ_GET_CONFIG BIT(10)
+/* Newer style, RSS done by the PF so we can ignore hardware vagaries. */
+#define IAVF_FLAG_AQ_GET_HENA BIT(11)
+#define IAVF_FLAG_AQ_SET_HENA BIT(12)
+#define IAVF_FLAG_AQ_SET_RSS_KEY BIT(13)
+#define IAVF_FLAG_AQ_SET_RSS_LUT BIT(14)
+#define IAVF_FLAG_AQ_REQUEST_PROMISC BIT(15)
+#define IAVF_FLAG_AQ_RELEASE_PROMISC BIT(16)
+#define IAVF_FLAG_AQ_REQUEST_ALLMULTI BIT(17)
+#define IAVF_FLAG_AQ_RELEASE_ALLMULTI BIT(18)
+#define IAVF_FLAG_AQ_ENABLE_VLAN_STRIPPING BIT(19)
+#define IAVF_FLAG_AQ_DISABLE_VLAN_STRIPPING BIT(20)
+#define IAVF_FLAG_AQ_ENABLE_CHANNELS BIT(21)
+#define IAVF_FLAG_AQ_DISABLE_CHANNELS BIT(22)
+#define IAVF_FLAG_AQ_ADD_CLOUD_FILTER BIT(23)
+#define IAVF_FLAG_AQ_DEL_CLOUD_FILTER BIT(24)
+
+ /* OS defined structs */
+ struct net_device *netdev;
+ struct pci_dev *pdev;
+
+ struct iavf_hw hw; /* defined in iavf_type.h */
+
+ enum iavf_state_t state;
+ unsigned long crit_section;
+
+ struct work_struct watchdog_task;
+ bool netdev_registered;
+ bool link_up;
+ enum virtchnl_link_speed link_speed;
+ enum virtchnl_ops current_op;
+#define CLIENT_ALLOWED(_a) ((_a)->vf_res ? \
+ (_a)->vf_res->vf_cap_flags & \
+ VIRTCHNL_VF_OFFLOAD_IWARP : \
+ 0)
+#define CLIENT_ENABLED(_a) ((_a)->cinst)
+/* RSS by the PF should be preferred over RSS via other methods. */
+#define RSS_PF(_a) ((_a)->vf_res->vf_cap_flags & \
+ VIRTCHNL_VF_OFFLOAD_RSS_PF)
+#define RSS_AQ(_a) ((_a)->vf_res->vf_cap_flags & \
+ VIRTCHNL_VF_OFFLOAD_RSS_AQ)
+#define RSS_REG(_a) (!((_a)->vf_res->vf_cap_flags & \
+ (VIRTCHNL_VF_OFFLOAD_RSS_AQ | \
+ VIRTCHNL_VF_OFFLOAD_RSS_PF)))
+#define VLAN_ALLOWED(_a) ((_a)->vf_res->vf_cap_flags & \
+ VIRTCHNL_VF_OFFLOAD_VLAN)
+ struct virtchnl_vf_resource *vf_res; /* incl. all VSIs */
+ struct virtchnl_vsi_resource *vsi_res; /* our LAN VSI */
+ struct virtchnl_version_info pf_version;
+#define PF_IS_V11(_a) (((_a)->pf_version.major == 1) && \
+ ((_a)->pf_version.minor == 1))
+ u16 msg_enable;
+ struct iavf_eth_stats current_stats;
+ struct iavf_vsi vsi;
+ u32 aq_wait_count;
+ /* RSS stuff */
+ u64 hena;
+ u16 rss_key_size;
+ u16 rss_lut_size;
+ u8 *rss_key;
+ u8 *rss_lut;
+ /* ADQ related members */
+ struct iavf_channel_config ch_config;
+ u8 num_tc;
+ struct list_head cloud_filter_list;
+ /* lock to protect access to the cloud filter list */
+ spinlock_t cloud_filter_list_lock;
+ u16 num_cloud_filters;
+};
+
+
+/* Ethtool Private Flags */
+
+/* lan device, used by client interface */
+struct i40e_device {
+ struct list_head list;
+ struct iavf_adapter *vf;
+};
+
+/* needed by iavf_ethtool.c */
+extern char iavf_driver_name[];
+extern const char iavf_driver_version[];
+
+int iavf_up(struct iavf_adapter *adapter);
+void iavf_down(struct iavf_adapter *adapter);
+int iavf_process_config(struct iavf_adapter *adapter);
+void iavf_schedule_reset(struct iavf_adapter *adapter);
+void iavf_reset(struct iavf_adapter *adapter);
+void iavf_set_ethtool_ops(struct net_device *netdev);
+void iavf_update_stats(struct iavf_adapter *adapter);
+void iavf_reset_interrupt_capability(struct iavf_adapter *adapter);
+int iavf_init_interrupt_scheme(struct iavf_adapter *adapter);
+void iavf_irq_enable_queues(struct iavf_adapter *adapter, u32 mask);
+void iavf_free_all_tx_resources(struct iavf_adapter *adapter);
+void iavf_free_all_rx_resources(struct iavf_adapter *adapter);
+
+void iavf_napi_add_all(struct iavf_adapter *adapter);
+void iavf_napi_del_all(struct iavf_adapter *adapter);
+
+int iavf_send_api_ver(struct iavf_adapter *adapter);
+int iavf_verify_api_ver(struct iavf_adapter *adapter);
+int iavf_send_vf_config_msg(struct iavf_adapter *adapter);
+int iavf_get_vf_config(struct iavf_adapter *adapter);
+void iavf_irq_enable(struct iavf_adapter *adapter, bool flush);
+void iavf_configure_queues(struct iavf_adapter *adapter);
+void iavf_deconfigure_queues(struct iavf_adapter *adapter);
+void iavf_enable_queues(struct iavf_adapter *adapter);
+void iavf_disable_queues(struct iavf_adapter *adapter);
+void iavf_map_queues(struct iavf_adapter *adapter);
+int iavf_request_queues(struct iavf_adapter *adapter, int num);
+void iavf_add_ether_addrs(struct iavf_adapter *adapter);
+void iavf_del_ether_addrs(struct iavf_adapter *adapter);
+void iavf_add_vlans(struct iavf_adapter *adapter);
+void iavf_del_vlans(struct iavf_adapter *adapter);
+void iavf_set_promiscuous(struct iavf_adapter *adapter, int flags);
+void iavf_request_stats(struct iavf_adapter *adapter);
+void iavf_request_reset(struct iavf_adapter *adapter);
+void iavf_get_hena(struct iavf_adapter *adapter);
+void iavf_set_hena(struct iavf_adapter *adapter);
+void iavf_set_rss_key(struct iavf_adapter *adapter);
+void iavf_set_rss_lut(struct iavf_adapter *adapter);
+void iavf_enable_vlan_stripping(struct iavf_adapter *adapter);
+void iavf_disable_vlan_stripping(struct iavf_adapter *adapter);
+void iavf_virtchnl_completion(struct iavf_adapter *adapter,
+ enum virtchnl_ops v_opcode,
+ iavf_status v_retval, u8 *msg, u16 msglen);
+int iavf_config_rss(struct iavf_adapter *adapter);
+int iavf_lan_add_device(struct iavf_adapter *adapter);
+int iavf_lan_del_device(struct iavf_adapter *adapter);
+void iavf_client_subtask(struct iavf_adapter *adapter);
+void iavf_notify_client_message(struct iavf_vsi *vsi, u8 *msg, u16 len);
+void iavf_notify_client_l2_params(struct iavf_vsi *vsi);
+void iavf_notify_client_open(struct iavf_vsi *vsi);
+void iavf_notify_client_close(struct iavf_vsi *vsi, bool reset);
+void iavf_enable_channels(struct iavf_adapter *adapter);
+void iavf_disable_channels(struct iavf_adapter *adapter);
+void iavf_add_cloud_filter(struct iavf_adapter *adapter);
+void iavf_del_cloud_filter(struct iavf_adapter *adapter);
+#endif /* _IAVF_H_ */
diff --git a/drivers/net/ethernet/intel/iavf/iavf_alloc.h b/drivers/net/ethernet/intel/iavf/iavf_alloc.h
new file mode 100644
index 000000000000..bf2753146f30
--- /dev/null
+++ b/drivers/net/ethernet/intel/iavf/iavf_alloc.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
+
+#ifndef _IAVF_ALLOC_H_
+#define _IAVF_ALLOC_H_
+
+struct iavf_hw;
+
+/* Memory allocation types */
+enum iavf_memory_type {
+ iavf_mem_arq_buf = 0, /* ARQ indirect command buffer */
+ iavf_mem_asq_buf = 1,
+ iavf_mem_atq_buf = 2, /* ATQ indirect command buffer */
+ iavf_mem_arq_ring = 3, /* ARQ descriptor ring */
+ iavf_mem_atq_ring = 4, /* ATQ descriptor ring */
+ iavf_mem_pd = 5, /* Page Descriptor */
+ iavf_mem_bp = 6, /* Backing Page - 4KB */
+ iavf_mem_bp_jumbo = 7, /* Backing Page - > 4KB */
+ iavf_mem_reserved
+};
+
+/* prototype for functions used for dynamic memory allocation */
+iavf_status iavf_allocate_dma_mem(struct iavf_hw *hw, struct iavf_dma_mem *mem,
+ enum iavf_memory_type type,
+ u64 size, u32 alignment);
+iavf_status iavf_free_dma_mem(struct iavf_hw *hw, struct iavf_dma_mem *mem);
+iavf_status iavf_allocate_virt_mem(struct iavf_hw *hw,
+ struct iavf_virt_mem *mem, u32 size);
+iavf_status iavf_free_virt_mem(struct iavf_hw *hw, struct iavf_virt_mem *mem);
+
+#endif /* _IAVF_ALLOC_H_ */
diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_client.c b/drivers/net/ethernet/intel/iavf/iavf_client.c
index 3cc9d60d0d72..aea45364fd1c 100644
--- a/drivers/net/ethernet/intel/i40evf/i40evf_client.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_client.c
@@ -4,36 +4,36 @@
#include <linux/list.h>
#include <linux/errno.h>
-#include "i40evf.h"
-#include "i40e_prototype.h"
-#include "i40evf_client.h"
+#include "iavf.h"
+#include "iavf_prototype.h"
+#include "iavf_client.h"
static
-const char i40evf_client_interface_version_str[] = I40EVF_CLIENT_VERSION_STR;
+const char iavf_client_interface_version_str[] = IAVF_CLIENT_VERSION_STR;
static struct i40e_client *vf_registered_client;
-static LIST_HEAD(i40evf_devices);
-static DEFINE_MUTEX(i40evf_device_mutex);
+static LIST_HEAD(i40e_devices);
+static DEFINE_MUTEX(iavf_device_mutex);
-static u32 i40evf_client_virtchnl_send(struct i40e_info *ldev,
- struct i40e_client *client,
- u8 *msg, u16 len);
+static u32 iavf_client_virtchnl_send(struct i40e_info *ldev,
+ struct i40e_client *client,
+ u8 *msg, u16 len);
-static int i40evf_client_setup_qvlist(struct i40e_info *ldev,
- struct i40e_client *client,
- struct i40e_qvlist_info *qvlist_info);
+static int iavf_client_setup_qvlist(struct i40e_info *ldev,
+ struct i40e_client *client,
+ struct i40e_qvlist_info *qvlist_info);
-static struct i40e_ops i40evf_lan_ops = {
- .virtchnl_send = i40evf_client_virtchnl_send,
- .setup_qvlist = i40evf_client_setup_qvlist,
+static struct i40e_ops iavf_lan_ops = {
+ .virtchnl_send = iavf_client_virtchnl_send,
+ .setup_qvlist = iavf_client_setup_qvlist,
};
/**
- * i40evf_client_get_params - retrieve relevant client parameters
+ * iavf_client_get_params - retrieve relevant client parameters
* @vsi: VSI with parameters
* @params: client param struct
**/
static
-void i40evf_client_get_params(struct i40e_vsi *vsi, struct i40e_params *params)
+void iavf_client_get_params(struct iavf_vsi *vsi, struct i40e_params *params)
{
int i;
@@ -41,21 +41,21 @@ void i40evf_client_get_params(struct i40e_vsi *vsi, struct i40e_params *params)
params->mtu = vsi->netdev->mtu;
params->link_up = vsi->back->link_up;
- for (i = 0; i < I40E_MAX_USER_PRIORITY; i++) {
+ for (i = 0; i < IAVF_MAX_USER_PRIORITY; i++) {
params->qos.prio_qos[i].tc = 0;
params->qos.prio_qos[i].qs_handle = vsi->qs_handle;
}
}
/**
- * i40evf_notify_client_message - call the client message receive callback
+ * iavf_notify_client_message - call the client message receive callback
* @vsi: the VSI associated with this client
* @msg: message buffer
* @len: length of message
*
* If there is a client to this VSI, call the client
**/
-void i40evf_notify_client_message(struct i40e_vsi *vsi, u8 *msg, u16 len)
+void iavf_notify_client_message(struct iavf_vsi *vsi, u8 *msg, u16 len)
{
struct i40e_client_instance *cinst;
@@ -74,12 +74,12 @@ void i40evf_notify_client_message(struct i40e_vsi *vsi, u8 *msg, u16 len)
}
/**
- * i40evf_notify_client_l2_params - call the client notify callback
+ * iavf_notify_client_l2_params - call the client notify callback
* @vsi: the VSI with l2 param changes
*
* If there is a client to this VSI, call the client
**/
-void i40evf_notify_client_l2_params(struct i40e_vsi *vsi)
+void iavf_notify_client_l2_params(struct iavf_vsi *vsi)
{
struct i40e_client_instance *cinst;
struct i40e_params params;
@@ -95,21 +95,21 @@ void i40evf_notify_client_l2_params(struct i40e_vsi *vsi)
"Cannot locate client instance l2_param_change function\n");
return;
}
- i40evf_client_get_params(vsi, &params);
+ iavf_client_get_params(vsi, &params);
cinst->lan_info.params = params;
cinst->client->ops->l2_param_change(&cinst->lan_info, cinst->client,
&params);
}
/**
- * i40evf_notify_client_open - call the client open callback
+ * iavf_notify_client_open - call the client open callback
* @vsi: the VSI with netdev opened
*
* If there is a client to this netdev, call the client with open
**/
-void i40evf_notify_client_open(struct i40e_vsi *vsi)
+void iavf_notify_client_open(struct iavf_vsi *vsi)
{
- struct i40evf_adapter *adapter = vsi->back;
+ struct iavf_adapter *adapter = vsi->back;
struct i40e_client_instance *cinst = adapter->cinst;
int ret;
@@ -127,22 +127,22 @@ void i40evf_notify_client_open(struct i40e_vsi *vsi)
}
/**
- * i40evf_client_release_qvlist - send a message to the PF to release iwarp qv map
+ * iavf_client_release_qvlist - send a message to the PF to release iwarp qv map
* @ldev: pointer to L2 context.
*
* Return 0 on success or < 0 on error
**/
-static int i40evf_client_release_qvlist(struct i40e_info *ldev)
+static int iavf_client_release_qvlist(struct i40e_info *ldev)
{
- struct i40evf_adapter *adapter = ldev->vf;
- i40e_status err;
+ struct iavf_adapter *adapter = ldev->vf;
+ iavf_status err;
if (adapter->aq_required)
return -EAGAIN;
- err = i40e_aq_send_msg_to_pf(&adapter->hw,
- VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP,
- I40E_SUCCESS, NULL, 0, NULL);
+ err = iavf_aq_send_msg_to_pf(&adapter->hw,
+ VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP,
+ I40E_SUCCESS, NULL, 0, NULL);
if (err)
dev_err(&adapter->pdev->dev,
@@ -153,15 +153,15 @@ static int i40evf_client_release_qvlist(struct i40e_info *ldev)
}
/**
- * i40evf_notify_client_close - call the client close callback
+ * iavf_notify_client_close - call the client close callback
* @vsi: the VSI with netdev closed
* @reset: true when close called due to reset pending
*
* If there is a client to this netdev, call the client with close
**/
-void i40evf_notify_client_close(struct i40e_vsi *vsi, bool reset)
+void iavf_notify_client_close(struct iavf_vsi *vsi, bool reset)
{
- struct i40evf_adapter *adapter = vsi->back;
+ struct iavf_adapter *adapter = vsi->back;
struct i40e_client_instance *cinst = adapter->cinst;
if (!cinst || !cinst->client || !cinst->client->ops ||
@@ -171,21 +171,21 @@ void i40evf_notify_client_close(struct i40e_vsi *vsi, bool reset)
return;
}
cinst->client->ops->close(&cinst->lan_info, cinst->client, reset);
- i40evf_client_release_qvlist(&cinst->lan_info);
+ iavf_client_release_qvlist(&cinst->lan_info);
clear_bit(__I40E_CLIENT_INSTANCE_OPENED, &cinst->state);
}
/**
- * i40evf_client_add_instance - add a client instance to the instance list
+ * iavf_client_add_instance - add a client instance to the instance list
* @adapter: pointer to the board struct
*
* Returns cinst ptr on success, NULL on failure
**/
static struct i40e_client_instance *
-i40evf_client_add_instance(struct i40evf_adapter *adapter)
+iavf_client_add_instance(struct iavf_adapter *adapter)
{
struct i40e_client_instance *cinst = NULL;
- struct i40e_vsi *vsi = &adapter->vsi;
+ struct iavf_vsi *vsi = &adapter->vsi;
struct netdev_hw_addr *mac = NULL;
struct i40e_params params;
@@ -207,11 +207,11 @@ i40evf_client_add_instance(struct i40evf_adapter *adapter)
cinst->lan_info.fid = 0;
cinst->lan_info.ftype = I40E_CLIENT_FTYPE_VF;
cinst->lan_info.hw_addr = adapter->hw.hw_addr;
- cinst->lan_info.ops = &i40evf_lan_ops;
- cinst->lan_info.version.major = I40EVF_CLIENT_VERSION_MAJOR;
- cinst->lan_info.version.minor = I40EVF_CLIENT_VERSION_MINOR;
- cinst->lan_info.version.build = I40EVF_CLIENT_VERSION_BUILD;
- i40evf_client_get_params(vsi, &params);
+ cinst->lan_info.ops = &iavf_lan_ops;
+ cinst->lan_info.version.major = IAVF_CLIENT_VERSION_MAJOR;
+ cinst->lan_info.version.minor = IAVF_CLIENT_VERSION_MINOR;
+ cinst->lan_info.version.build = IAVF_CLIENT_VERSION_BUILD;
+ iavf_client_get_params(vsi, &params);
cinst->lan_info.params = params;
set_bit(__I40E_CLIENT_INSTANCE_NONE, &cinst->state);
@@ -233,28 +233,28 @@ out:
}
/**
- * i40evf_client_del_instance - removes a client instance from the list
+ * iavf_client_del_instance - removes a client instance from the list
* @adapter: pointer to the board struct
*
**/
static
-void i40evf_client_del_instance(struct i40evf_adapter *adapter)
+void iavf_client_del_instance(struct iavf_adapter *adapter)
{
kfree(adapter->cinst);
adapter->cinst = NULL;
}
/**
- * i40evf_client_subtask - client maintenance work
+ * iavf_client_subtask - client maintenance work
* @adapter: board private structure
**/
-void i40evf_client_subtask(struct i40evf_adapter *adapter)
+void iavf_client_subtask(struct iavf_adapter *adapter)
{
struct i40e_client *client = vf_registered_client;
struct i40e_client_instance *cinst;
int ret = 0;
- if (adapter->state < __I40EVF_DOWN)
+ if (adapter->state < __IAVF_DOWN)
return;
/* first check client is registered */
@@ -262,7 +262,7 @@ void i40evf_client_subtask(struct i40evf_adapter *adapter)
return;
/* Add the client instance to the instance list */
- cinst = i40evf_client_add_instance(adapter);
+ cinst = iavf_client_add_instance(adapter);
if (!cinst)
return;
@@ -279,23 +279,23 @@ void i40evf_client_subtask(struct i40evf_adapter *adapter)
&cinst->state);
else
/* remove client instance */
- i40evf_client_del_instance(adapter);
+ iavf_client_del_instance(adapter);
}
}
/**
- * i40evf_lan_add_device - add a lan device struct to the list of lan devices
+ * iavf_lan_add_device - add a lan device struct to the list of lan devices
* @adapter: pointer to the board struct
*
* Returns 0 on success or none 0 on error
**/
-int i40evf_lan_add_device(struct i40evf_adapter *adapter)
+int iavf_lan_add_device(struct iavf_adapter *adapter)
{
struct i40e_device *ldev;
int ret = 0;
- mutex_lock(&i40evf_device_mutex);
- list_for_each_entry(ldev, &i40evf_devices, list) {
+ mutex_lock(&iavf_device_mutex);
+ list_for_each_entry(ldev, &i40e_devices, list) {
if (ldev->vf == adapter) {
ret = -EEXIST;
goto out;
@@ -308,7 +308,7 @@ int i40evf_lan_add_device(struct i40evf_adapter *adapter)
}
ldev->vf = adapter;
INIT_LIST_HEAD(&ldev->list);
- list_add(&ldev->list, &i40evf_devices);
+ list_add(&ldev->list, &i40e_devices);
dev_info(&adapter->pdev->dev, "Added LAN device bus=0x%02x dev=0x%02x func=0x%02x\n",
adapter->hw.bus.bus_id, adapter->hw.bus.device,
adapter->hw.bus.func);
@@ -316,26 +316,26 @@ int i40evf_lan_add_device(struct i40evf_adapter *adapter)
/* Since in some cases register may have happened before a device gets
* added, we can schedule a subtask to go initiate the clients.
*/
- adapter->flags |= I40EVF_FLAG_SERVICE_CLIENT_REQUESTED;
+ adapter->flags |= IAVF_FLAG_SERVICE_CLIENT_REQUESTED;
out:
- mutex_unlock(&i40evf_device_mutex);
+ mutex_unlock(&iavf_device_mutex);
return ret;
}
/**
- * i40evf_lan_del_device - removes a lan device from the device list
+ * iavf_lan_del_device - removes a lan device from the device list
* @adapter: pointer to the board struct
*
* Returns 0 on success or non-0 on error
**/
-int i40evf_lan_del_device(struct i40evf_adapter *adapter)
+int iavf_lan_del_device(struct iavf_adapter *adapter)
{
struct i40e_device *ldev, *tmp;
int ret = -ENODEV;
- mutex_lock(&i40evf_device_mutex);
- list_for_each_entry_safe(ldev, tmp, &i40evf_devices, list) {
+ mutex_lock(&iavf_device_mutex);
+ list_for_each_entry_safe(ldev, tmp, &i40e_devices, list) {
if (ldev->vf == adapter) {
dev_info(&adapter->pdev->dev,
"Deleted LAN device bus=0x%02x dev=0x%02x func=0x%02x\n",
@@ -348,23 +348,23 @@ int i40evf_lan_del_device(struct i40evf_adapter *adapter)
}
}
- mutex_unlock(&i40evf_device_mutex);
+ mutex_unlock(&iavf_device_mutex);
return ret;
}
/**
- * i40evf_client_release - release client specific resources
+ * iavf_client_release - release client specific resources
* @client: pointer to the registered client
*
**/
-static void i40evf_client_release(struct i40e_client *client)
+static void iavf_client_release(struct i40e_client *client)
{
struct i40e_client_instance *cinst;
struct i40e_device *ldev;
- struct i40evf_adapter *adapter;
+ struct iavf_adapter *adapter;
- mutex_lock(&i40evf_device_mutex);
- list_for_each_entry(ldev, &i40evf_devices, list) {
+ mutex_lock(&iavf_device_mutex);
+ list_for_each_entry(ldev, &i40e_devices, list) {
adapter = ldev->vf;
cinst = adapter->cinst;
if (!cinst)
@@ -373,41 +373,41 @@ static void i40evf_client_release(struct i40e_client *client)
if (client->ops && client->ops->close)
client->ops->close(&cinst->lan_info, client,
false);
- i40evf_client_release_qvlist(&cinst->lan_info);
+ iavf_client_release_qvlist(&cinst->lan_info);
clear_bit(__I40E_CLIENT_INSTANCE_OPENED, &cinst->state);
dev_warn(&adapter->pdev->dev,
"Client %s instance closed\n", client->name);
}
/* delete the client instance */
- i40evf_client_del_instance(adapter);
+ iavf_client_del_instance(adapter);
dev_info(&adapter->pdev->dev, "Deleted client instance of Client %s\n",
client->name);
}
- mutex_unlock(&i40evf_device_mutex);
+ mutex_unlock(&iavf_device_mutex);
}
/**
- * i40evf_client_prepare - prepare client specific resources
+ * iavf_client_prepare - prepare client specific resources
* @client: pointer to the registered client
*
**/
-static void i40evf_client_prepare(struct i40e_client *client)
+static void iavf_client_prepare(struct i40e_client *client)
{
struct i40e_device *ldev;
- struct i40evf_adapter *adapter;
+ struct iavf_adapter *adapter;
- mutex_lock(&i40evf_device_mutex);
- list_for_each_entry(ldev, &i40evf_devices, list) {
+ mutex_lock(&iavf_device_mutex);
+ list_for_each_entry(ldev, &i40e_devices, list) {
adapter = ldev->vf;
/* Signal the watchdog to service the client */
- adapter->flags |= I40EVF_FLAG_SERVICE_CLIENT_REQUESTED;
+ adapter->flags |= IAVF_FLAG_SERVICE_CLIENT_REQUESTED;
}
- mutex_unlock(&i40evf_device_mutex);
+ mutex_unlock(&iavf_device_mutex);
}
/**
- * i40evf_client_virtchnl_send - send a message to the PF instance
+ * iavf_client_virtchnl_send - send a message to the PF instance
* @ldev: pointer to L2 context.
* @client: Client pointer.
* @msg: pointer to message buffer
@@ -415,17 +415,17 @@ static void i40evf_client_prepare(struct i40e_client *client)
*
* Return 0 on success or < 0 on error
**/
-static u32 i40evf_client_virtchnl_send(struct i40e_info *ldev,
- struct i40e_client *client,
- u8 *msg, u16 len)
+static u32 iavf_client_virtchnl_send(struct i40e_info *ldev,
+ struct i40e_client *client,
+ u8 *msg, u16 len)
{
- struct i40evf_adapter *adapter = ldev->vf;
- i40e_status err;
+ struct iavf_adapter *adapter = ldev->vf;
+ iavf_status err;
if (adapter->aq_required)
return -EAGAIN;
- err = i40e_aq_send_msg_to_pf(&adapter->hw, VIRTCHNL_OP_IWARP,
+ err = iavf_aq_send_msg_to_pf(&adapter->hw, VIRTCHNL_OP_IWARP,
I40E_SUCCESS, msg, len, NULL);
if (err)
dev_err(&adapter->pdev->dev, "Unable to send iWarp message to PF, error %d, aq status %d\n",
@@ -435,21 +435,21 @@ static u32 i40evf_client_virtchnl_send(struct i40e_info *ldev,
}
/**
- * i40evf_client_setup_qvlist - send a message to the PF to setup iwarp qv map
+ * iavf_client_setup_qvlist - send a message to the PF to setup iwarp qv map
* @ldev: pointer to L2 context.
* @client: Client pointer.
* @qvlist_info: queue and vector list
*
* Return 0 on success or < 0 on error
**/
-static int i40evf_client_setup_qvlist(struct i40e_info *ldev,
- struct i40e_client *client,
- struct i40e_qvlist_info *qvlist_info)
+static int iavf_client_setup_qvlist(struct i40e_info *ldev,
+ struct i40e_client *client,
+ struct i40e_qvlist_info *qvlist_info)
{
struct virtchnl_iwarp_qvlist_info *v_qvlist_info;
- struct i40evf_adapter *adapter = ldev->vf;
+ struct iavf_adapter *adapter = ldev->vf;
struct i40e_qv_info *qv_info;
- i40e_status err;
+ iavf_status err;
u32 v_idx, i;
u32 msg_size;
@@ -474,9 +474,9 @@ static int i40evf_client_setup_qvlist(struct i40e_info *ldev,
(v_qvlist_info->num_vectors - 1));
adapter->client_pending |= BIT(VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP);
- err = i40e_aq_send_msg_to_pf(&adapter->hw,
- VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP,
- I40E_SUCCESS, (u8 *)v_qvlist_info, msg_size, NULL);
+ err = iavf_aq_send_msg_to_pf(&adapter->hw,
+ VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP, I40E_SUCCESS,
+ (u8 *)v_qvlist_info, msg_size, NULL);
if (err) {
dev_err(&adapter->pdev->dev,
@@ -499,12 +499,12 @@ out:
}
/**
- * i40evf_register_client - Register a i40e client driver with the L2 driver
+ * iavf_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 i40evf_register_client(struct i40e_client *client)
+int iavf_register_client(struct i40e_client *client)
{
int ret = 0;
@@ -514,48 +514,48 @@ int i40evf_register_client(struct i40e_client *client)
}
if (strlen(client->name) == 0) {
- pr_info("i40evf: Failed to register client with no name\n");
+ pr_info("iavf: Failed to register client with no name\n");
ret = -EIO;
goto out;
}
if (vf_registered_client) {
- pr_info("i40evf: Client %s has already been registered!\n",
+ pr_info("iavf: Client %s has already been registered!\n",
client->name);
ret = -EEXIST;
goto out;
}
- if ((client->version.major != I40EVF_CLIENT_VERSION_MAJOR) ||
- (client->version.minor != I40EVF_CLIENT_VERSION_MINOR)) {
- pr_info("i40evf: Failed to register client %s due to mismatched client interface version\n",
+ if ((client->version.major != IAVF_CLIENT_VERSION_MAJOR) ||
+ (client->version.minor != IAVF_CLIENT_VERSION_MINOR)) {
+ pr_info("iavf: 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,
- i40evf_client_interface_version_str);
+ iavf_client_interface_version_str);
ret = -EIO;
goto out;
}
vf_registered_client = client;
- i40evf_client_prepare(client);
+ iavf_client_prepare(client);
- pr_info("i40evf: Registered client %s with return code %d\n",
+ pr_info("iavf: Registered client %s with return code %d\n",
client->name, ret);
out:
return ret;
}
-EXPORT_SYMBOL(i40evf_register_client);
+EXPORT_SYMBOL(iavf_register_client);
/**
- * i40evf_unregister_client - Unregister a i40e client driver with the L2 driver
+ * iavf_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 i40evf_unregister_client(struct i40e_client *client)
+int iavf_unregister_client(struct i40e_client *client)
{
int ret = 0;
@@ -563,17 +563,17 @@ int i40evf_unregister_client(struct i40e_client *client)
* a close for each of the client instances that were opened.
* client_release function is called to handle this.
*/
- i40evf_client_release(client);
+ iavf_client_release(client);
if (vf_registered_client != client) {
- pr_info("i40evf: Client %s has not been registered\n",
+ pr_info("iavf: Client %s has not been registered\n",
client->name);
ret = -ENODEV;
goto out;
}
vf_registered_client = NULL;
- pr_info("i40evf: Unregistered client %s\n", client->name);
+ pr_info("iavf: Unregistered client %s\n", client->name);
out:
return ret;
}
-EXPORT_SYMBOL(i40evf_unregister_client);
+EXPORT_SYMBOL(iavf_unregister_client);
diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_client.h b/drivers/net/ethernet/intel/iavf/iavf_client.h
index 5585f362048a..e216fc9dfd81 100644
--- a/drivers/net/ethernet/intel/i40evf/i40evf_client.h
+++ b/drivers/net/ethernet/intel/iavf/iavf_client.h
@@ -1,21 +1,21 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright(c) 2013 - 2018 Intel Corporation. */
-#ifndef _I40EVF_CLIENT_H_
-#define _I40EVF_CLIENT_H_
+#ifndef _IAVF_CLIENT_H_
+#define _IAVF_CLIENT_H_
-#define I40EVF_CLIENT_STR_LENGTH 10
+#define IAVF_CLIENT_STR_LENGTH 10
/* Client interface version should be updated anytime there is a change in the
* existing APIs or data structures.
*/
-#define I40EVF_CLIENT_VERSION_MAJOR 0
-#define I40EVF_CLIENT_VERSION_MINOR 01
-#define I40EVF_CLIENT_VERSION_BUILD 00
-#define I40EVF_CLIENT_VERSION_STR \
- __stringify(I40EVF_CLIENT_VERSION_MAJOR) "." \
- __stringify(I40EVF_CLIENT_VERSION_MINOR) "." \
- __stringify(I40EVF_CLIENT_VERSION_BUILD)
+#define IAVF_CLIENT_VERSION_MAJOR 0
+#define IAVF_CLIENT_VERSION_MINOR 01
+#define IAVF_CLIENT_VERSION_BUILD 00
+#define IAVF_CLIENT_VERSION_STR \
+ __stringify(IAVF_CLIENT_VERSION_MAJOR) "." \
+ __stringify(IAVF_CLIENT_VERSION_MINOR) "." \
+ __stringify(IAVF_CLIENT_VERSION_BUILD)
struct i40e_client_version {
u8 major;
@@ -90,7 +90,7 @@ struct i40e_info {
#define I40E_CLIENT_FTYPE_PF 0
#define I40E_CLIENT_FTYPE_VF 1
u8 ftype; /* function type, PF or VF */
- void *vf; /* cast to i40evf_adapter */
+ void *vf; /* cast to iavf_adapter */
/* All L2 params that could change during the life span of the device
* and needs to be communicated to the client when they change
@@ -151,7 +151,7 @@ struct i40e_client_instance {
struct i40e_client {
struct list_head list; /* list of registered clients */
- char name[I40EVF_CLIENT_STR_LENGTH];
+ char name[IAVF_CLIENT_STR_LENGTH];
struct i40e_client_version version;
unsigned long state; /* client state */
atomic_t ref_cnt; /* Count of all the client devices of this kind */
@@ -164,6 +164,6 @@ struct i40e_client {
};
/* used by clients */
-int i40evf_register_client(struct i40e_client *client);
-int i40evf_unregister_client(struct i40e_client *client);
-#endif /* _I40EVF_CLIENT_H_ */
+int iavf_register_client(struct i40e_client *client);
+int iavf_unregister_client(struct i40e_client *client);
+#endif /* _IAVF_CLIENT_H_ */
diff --git a/drivers/net/ethernet/intel/iavf/iavf_common.c b/drivers/net/ethernet/intel/iavf/iavf_common.c
new file mode 100644
index 000000000000..768369c89e77
--- /dev/null
+++ b/drivers/net/ethernet/intel/iavf/iavf_common.c
@@ -0,0 +1,955 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
+
+#include "iavf_type.h"
+#include "i40e_adminq.h"
+#include "iavf_prototype.h"
+#include <linux/avf/virtchnl.h>
+
+/**
+ * iavf_set_mac_type - Sets MAC type
+ * @hw: pointer to the HW structure
+ *
+ * This function sets the mac type of the adapter based on the
+ * vendor ID and device ID stored in the hw structure.
+ **/
+iavf_status iavf_set_mac_type(struct iavf_hw *hw)
+{
+ iavf_status status = 0;
+
+ if (hw->vendor_id == PCI_VENDOR_ID_INTEL) {
+ switch (hw->device_id) {
+ case IAVF_DEV_ID_X722_VF:
+ hw->mac.type = IAVF_MAC_X722_VF;
+ break;
+ case IAVF_DEV_ID_VF:
+ case IAVF_DEV_ID_VF_HV:
+ case IAVF_DEV_ID_ADAPTIVE_VF:
+ hw->mac.type = IAVF_MAC_VF;
+ break;
+ default:
+ hw->mac.type = IAVF_MAC_GENERIC;
+ break;
+ }
+ } else {
+ status = I40E_ERR_DEVICE_NOT_SUPPORTED;
+ }
+
+ hw_dbg(hw, "found mac: %d, returns: %d\n", hw->mac.type, status);
+ return status;
+}
+
+/**
+ * iavf_aq_str - convert AQ err code to a string
+ * @hw: pointer to the HW structure
+ * @aq_err: the AQ error code to convert
+ **/
+const char *iavf_aq_str(struct iavf_hw *hw, enum i40e_admin_queue_err aq_err)
+{
+ switch (aq_err) {
+ case I40E_AQ_RC_OK:
+ return "OK";
+ case I40E_AQ_RC_EPERM:
+ return "I40E_AQ_RC_EPERM";
+ case I40E_AQ_RC_ENOENT:
+ return "I40E_AQ_RC_ENOENT";
+ case I40E_AQ_RC_ESRCH:
+ return "I40E_AQ_RC_ESRCH";
+ case I40E_AQ_RC_EINTR:
+ return "I40E_AQ_RC_EINTR";
+ case I40E_AQ_RC_EIO:
+ return "I40E_AQ_RC_EIO";
+ case I40E_AQ_RC_ENXIO:
+ return "I40E_AQ_RC_ENXIO";
+ case I40E_AQ_RC_E2BIG:
+ return "I40E_AQ_RC_E2BIG";
+ case I40E_AQ_RC_EAGAIN:
+ return "I40E_AQ_RC_EAGAIN";
+ case I40E_AQ_RC_ENOMEM:
+ return "I40E_AQ_RC_ENOMEM";
+ case I40E_AQ_RC_EACCES:
+ return "I40E_AQ_RC_EACCES";
+ case I40E_AQ_RC_EFAULT:
+ return "I40E_AQ_RC_EFAULT";
+ case I40E_AQ_RC_EBUSY:
+ return "I40E_AQ_RC_EBUSY";
+ case I40E_AQ_RC_EEXIST:
+ return "I40E_AQ_RC_EEXIST";
+ case I40E_AQ_RC_EINVAL:
+ return "I40E_AQ_RC_EINVAL";
+ case I40E_AQ_RC_ENOTTY:
+ return "I40E_AQ_RC_ENOTTY";
+ case I40E_AQ_RC_ENOSPC:
+ return "I40E_AQ_RC_ENOSPC";
+ case I40E_AQ_RC_ENOSYS:
+ return "I40E_AQ_RC_ENOSYS";
+ case I40E_AQ_RC_ERANGE:
+ return "I40E_AQ_RC_ERANGE";
+ case I40E_AQ_RC_EFLUSHED:
+ return "I40E_AQ_RC_EFLUSHED";
+ case I40E_AQ_RC_BAD_ADDR:
+ return "I40E_AQ_RC_BAD_ADDR";
+ case I40E_AQ_RC_EMODE:
+ return "I40E_AQ_RC_EMODE";
+ case I40E_AQ_RC_EFBIG:
+ return "I40E_AQ_RC_EFBIG";
+ }
+
+ snprintf(hw->err_str, sizeof(hw->err_str), "%d", aq_err);
+ return hw->err_str;
+}
+
+/**
+ * iavf_stat_str - convert status err code to a string
+ * @hw: pointer to the HW structure
+ * @stat_err: the status error code to convert
+ **/
+const char *iavf_stat_str(struct iavf_hw *hw, iavf_status stat_err)
+{
+ switch (stat_err) {
+ case 0:
+ return "OK";
+ case I40E_ERR_NVM:
+ return "I40E_ERR_NVM";
+ case I40E_ERR_NVM_CHECKSUM:
+ return "I40E_ERR_NVM_CHECKSUM";
+ case I40E_ERR_PHY:
+ return "I40E_ERR_PHY";
+ case I40E_ERR_CONFIG:
+ return "I40E_ERR_CONFIG";
+ case I40E_ERR_PARAM:
+ return "I40E_ERR_PARAM";
+ case I40E_ERR_MAC_TYPE:
+ return "I40E_ERR_MAC_TYPE";
+ case I40E_ERR_UNKNOWN_PHY:
+ return "I40E_ERR_UNKNOWN_PHY";
+ case I40E_ERR_LINK_SETUP:
+ return "I40E_ERR_LINK_SETUP";
+ case I40E_ERR_ADAPTER_STOPPED:
+ return "I40E_ERR_ADAPTER_STOPPED";
+ case I40E_ERR_INVALID_MAC_ADDR:
+ return "I40E_ERR_INVALID_MAC_ADDR";
+ case I40E_ERR_DEVICE_NOT_SUPPORTED:
+ return "I40E_ERR_DEVICE_NOT_SUPPORTED";
+ case I40E_ERR_MASTER_REQUESTS_PENDING:
+ return "I40E_ERR_MASTER_REQUESTS_PENDING";
+ case I40E_ERR_INVALID_LINK_SETTINGS:
+ return "I40E_ERR_INVALID_LINK_SETTINGS";
+ case I40E_ERR_AUTONEG_NOT_COMPLETE:
+ return "I40E_ERR_AUTONEG_NOT_COMPLETE";
+ case I40E_ERR_RESET_FAILED:
+ return "I40E_ERR_RESET_FAILED";
+ case I40E_ERR_SWFW_SYNC:
+ return "I40E_ERR_SWFW_SYNC";
+ case I40E_ERR_NO_AVAILABLE_VSI:
+ return "I40E_ERR_NO_AVAILABLE_VSI";
+ case I40E_ERR_NO_MEMORY:
+ return "I40E_ERR_NO_MEMORY";
+ case I40E_ERR_BAD_PTR:
+ return "I40E_ERR_BAD_PTR";
+ case I40E_ERR_RING_FULL:
+ return "I40E_ERR_RING_FULL";
+ case I40E_ERR_INVALID_PD_ID:
+ return "I40E_ERR_INVALID_PD_ID";
+ case I40E_ERR_INVALID_QP_ID:
+ return "I40E_ERR_INVALID_QP_ID";
+ case I40E_ERR_INVALID_CQ_ID:
+ return "I40E_ERR_INVALID_CQ_ID";
+ case I40E_ERR_INVALID_CEQ_ID:
+ return "I40E_ERR_INVALID_CEQ_ID";
+ case I40E_ERR_INVALID_AEQ_ID:
+ return "I40E_ERR_INVALID_AEQ_ID";
+ case I40E_ERR_INVALID_SIZE:
+ return "I40E_ERR_INVALID_SIZE";
+ case I40E_ERR_INVALID_ARP_INDEX:
+ return "I40E_ERR_INVALID_ARP_INDEX";
+ case I40E_ERR_INVALID_FPM_FUNC_ID:
+ return "I40E_ERR_INVALID_FPM_FUNC_ID";
+ case I40E_ERR_QP_INVALID_MSG_SIZE:
+ return "I40E_ERR_QP_INVALID_MSG_SIZE";
+ case I40E_ERR_QP_TOOMANY_WRS_POSTED:
+ return "I40E_ERR_QP_TOOMANY_WRS_POSTED";
+ case I40E_ERR_INVALID_FRAG_COUNT:
+ return "I40E_ERR_INVALID_FRAG_COUNT";
+ case I40E_ERR_QUEUE_EMPTY:
+ return "I40E_ERR_QUEUE_EMPTY";
+ case I40E_ERR_INVALID_ALIGNMENT:
+ return "I40E_ERR_INVALID_ALIGNMENT";
+ case I40E_ERR_FLUSHED_QUEUE:
+ return "I40E_ERR_FLUSHED_QUEUE";
+ case I40E_ERR_INVALID_PUSH_PAGE_INDEX:
+ return "I40E_ERR_INVALID_PUSH_PAGE_INDEX";
+ case I40E_ERR_INVALID_IMM_DATA_SIZE:
+ return "I40E_ERR_INVALID_IMM_DATA_SIZE";
+ case I40E_ERR_TIMEOUT:
+ return "I40E_ERR_TIMEOUT";
+ case I40E_ERR_OPCODE_MISMATCH:
+ return "I40E_ERR_OPCODE_MISMATCH";
+ case I40E_ERR_CQP_COMPL_ERROR:
+ return "I40E_ERR_CQP_COMPL_ERROR";
+ case I40E_ERR_INVALID_VF_ID:
+ return "I40E_ERR_INVALID_VF_ID";
+ case I40E_ERR_INVALID_HMCFN_ID:
+ return "I40E_ERR_INVALID_HMCFN_ID";
+ case I40E_ERR_BACKING_PAGE_ERROR:
+ return "I40E_ERR_BACKING_PAGE_ERROR";
+ case I40E_ERR_NO_PBLCHUNKS_AVAILABLE:
+ return "I40E_ERR_NO_PBLCHUNKS_AVAILABLE";
+ case I40E_ERR_INVALID_PBLE_INDEX:
+ return "I40E_ERR_INVALID_PBLE_INDEX";
+ case I40E_ERR_INVALID_SD_INDEX:
+ return "I40E_ERR_INVALID_SD_INDEX";
+ case I40E_ERR_INVALID_PAGE_DESC_INDEX:
+ return "I40E_ERR_INVALID_PAGE_DESC_INDEX";
+ case I40E_ERR_INVALID_SD_TYPE:
+ return "I40E_ERR_INVALID_SD_TYPE";
+ case I40E_ERR_MEMCPY_FAILED:
+ return "I40E_ERR_MEMCPY_FAILED";
+ case I40E_ERR_INVALID_HMC_OBJ_INDEX:
+ return "I40E_ERR_INVALID_HMC_OBJ_INDEX";
+ case I40E_ERR_INVALID_HMC_OBJ_COUNT:
+ return "I40E_ERR_INVALID_HMC_OBJ_COUNT";
+ case I40E_ERR_INVALID_SRQ_ARM_LIMIT:
+ return "I40E_ERR_INVALID_SRQ_ARM_LIMIT";
+ case I40E_ERR_SRQ_ENABLED:
+ return "I40E_ERR_SRQ_ENABLED";
+ case I40E_ERR_ADMIN_QUEUE_ERROR:
+ return "I40E_ERR_ADMIN_QUEUE_ERROR";
+ case I40E_ERR_ADMIN_QUEUE_TIMEOUT:
+ return "I40E_ERR_ADMIN_QUEUE_TIMEOUT";
+ case I40E_ERR_BUF_TOO_SHORT:
+ return "I40E_ERR_BUF_TOO_SHORT";
+ case I40E_ERR_ADMIN_QUEUE_FULL:
+ return "I40E_ERR_ADMIN_QUEUE_FULL";
+ case I40E_ERR_ADMIN_QUEUE_NO_WORK:
+ return "I40E_ERR_ADMIN_QUEUE_NO_WORK";
+ case I40E_ERR_BAD_IWARP_CQE:
+ return "I40E_ERR_BAD_IWARP_CQE";
+ case I40E_ERR_NVM_BLANK_MODE:
+ return "I40E_ERR_NVM_BLANK_MODE";
+ case I40E_ERR_NOT_IMPLEMENTED:
+ return "I40E_ERR_NOT_IMPLEMENTED";
+ case I40E_ERR_PE_DOORBELL_NOT_ENABLED:
+ return "I40E_ERR_PE_DOORBELL_NOT_ENABLED";
+ case I40E_ERR_DIAG_TEST_FAILED:
+ return "I40E_ERR_DIAG_TEST_FAILED";
+ case I40E_ERR_NOT_READY:
+ return "I40E_ERR_NOT_READY";
+ case I40E_NOT_SUPPORTED:
+ return "I40E_NOT_SUPPORTED";
+ case I40E_ERR_FIRMWARE_API_VERSION:
+ return "I40E_ERR_FIRMWARE_API_VERSION";
+ case I40E_ERR_ADMIN_QUEUE_CRITICAL_ERROR:
+ return "I40E_ERR_ADMIN_QUEUE_CRITICAL_ERROR";
+ }
+
+ snprintf(hw->err_str, sizeof(hw->err_str), "%d", stat_err);
+ return hw->err_str;
+}
+
+/**
+ * iavf_debug_aq
+ * @hw: debug mask related to admin queue
+ * @mask: debug mask
+ * @desc: pointer to admin queue descriptor
+ * @buffer: pointer to command buffer
+ * @buf_len: max length of buffer
+ *
+ * Dumps debug log about adminq command with descriptor contents.
+ **/
+void iavf_debug_aq(struct iavf_hw *hw, enum iavf_debug_mask mask, void *desc,
+ void *buffer, u16 buf_len)
+{
+ struct i40e_aq_desc *aq_desc = (struct i40e_aq_desc *)desc;
+ u8 *buf = (u8 *)buffer;
+
+ if ((!(mask & hw->debug_mask)) || !desc)
+ return;
+
+ iavf_debug(hw, mask,
+ "AQ CMD: opcode 0x%04X, flags 0x%04X, datalen 0x%04X, retval 0x%04X\n",
+ le16_to_cpu(aq_desc->opcode),
+ le16_to_cpu(aq_desc->flags),
+ le16_to_cpu(aq_desc->datalen),
+ le16_to_cpu(aq_desc->retval));
+ iavf_debug(hw, mask, "\tcookie (h,l) 0x%08X 0x%08X\n",
+ le32_to_cpu(aq_desc->cookie_high),
+ le32_to_cpu(aq_desc->cookie_low));
+ iavf_debug(hw, mask, "\tparam (0,1) 0x%08X 0x%08X\n",
+ le32_to_cpu(aq_desc->params.internal.param0),
+ le32_to_cpu(aq_desc->params.internal.param1));
+ iavf_debug(hw, mask, "\taddr (h,l) 0x%08X 0x%08X\n",
+ le32_to_cpu(aq_desc->params.external.addr_high),
+ le32_to_cpu(aq_desc->params.external.addr_low));
+
+ if (buffer && aq_desc->datalen) {
+ u16 len = le16_to_cpu(aq_desc->datalen);
+
+ iavf_debug(hw, mask, "AQ CMD Buffer:\n");
+ if (buf_len < len)
+ len = buf_len;
+ /* write the full 16-byte chunks */
+ if (hw->debug_mask & mask) {
+ char prefix[27];
+
+ snprintf(prefix, sizeof(prefix),
+ "iavf %02x:%02x.%x: \t0x",
+ hw->bus.bus_id,
+ hw->bus.device,
+ hw->bus.func);
+
+ print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_OFFSET,
+ 16, 1, buf, len, false);
+ }
+ }
+}
+
+/**
+ * iavf_check_asq_alive
+ * @hw: pointer to the hw struct
+ *
+ * Returns true if Queue is enabled else false.
+ **/
+bool iavf_check_asq_alive(struct iavf_hw *hw)
+{
+ if (hw->aq.asq.len)
+ return !!(rd32(hw, hw->aq.asq.len) &
+ IAVF_VF_ATQLEN1_ATQENABLE_MASK);
+ else
+ return false;
+}
+
+/**
+ * iavf_aq_queue_shutdown
+ * @hw: pointer to the hw struct
+ * @unloading: is the driver unloading itself
+ *
+ * Tell the Firmware that we're shutting down the AdminQ and whether
+ * or not the driver is unloading as well.
+ **/
+iavf_status iavf_aq_queue_shutdown(struct iavf_hw *hw, bool unloading)
+{
+ struct i40e_aq_desc desc;
+ struct i40e_aqc_queue_shutdown *cmd =
+ (struct i40e_aqc_queue_shutdown *)&desc.params.raw;
+ iavf_status status;
+
+ iavf_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_queue_shutdown);
+
+ if (unloading)
+ cmd->driver_unloading = cpu_to_le32(I40E_AQ_DRIVER_UNLOADING);
+ status = iavf_asq_send_command(hw, &desc, NULL, 0, NULL);
+
+ return status;
+}
+
+/**
+ * iavf_aq_get_set_rss_lut
+ * @hw: pointer to the hardware structure
+ * @vsi_id: vsi fw index
+ * @pf_lut: for PF table set true, for VSI table set false
+ * @lut: pointer to the lut buffer provided by the caller
+ * @lut_size: size of the lut buffer
+ * @set: set true to set the table, false to get the table
+ *
+ * Internal function to get or set RSS look up table
+ **/
+static iavf_status iavf_aq_get_set_rss_lut(struct iavf_hw *hw,
+ u16 vsi_id, bool pf_lut,
+ u8 *lut, u16 lut_size,
+ bool set)
+{
+ iavf_status status;
+ struct i40e_aq_desc desc;
+ struct i40e_aqc_get_set_rss_lut *cmd_resp =
+ (struct i40e_aqc_get_set_rss_lut *)&desc.params.raw;
+
+ if (set)
+ iavf_fill_default_direct_cmd_desc(&desc,
+ i40e_aqc_opc_set_rss_lut);
+ else
+ iavf_fill_default_direct_cmd_desc(&desc,
+ i40e_aqc_opc_get_rss_lut);
+
+ /* Indirect command */
+ desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_BUF);
+ desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_RD);
+
+ cmd_resp->vsi_id =
+ cpu_to_le16((u16)((vsi_id <<
+ I40E_AQC_SET_RSS_LUT_VSI_ID_SHIFT) &
+ I40E_AQC_SET_RSS_LUT_VSI_ID_MASK));
+ cmd_resp->vsi_id |= cpu_to_le16((u16)I40E_AQC_SET_RSS_LUT_VSI_VALID);
+
+ if (pf_lut)
+ cmd_resp->flags |= cpu_to_le16((u16)
+ ((I40E_AQC_SET_RSS_LUT_TABLE_TYPE_PF <<
+ I40E_AQC_SET_RSS_LUT_TABLE_TYPE_SHIFT) &
+ I40E_AQC_SET_RSS_LUT_TABLE_TYPE_MASK));
+ else
+ cmd_resp->flags |= cpu_to_le16((u16)
+ ((I40E_AQC_SET_RSS_LUT_TABLE_TYPE_VSI <<
+ I40E_AQC_SET_RSS_LUT_TABLE_TYPE_SHIFT) &
+ I40E_AQC_SET_RSS_LUT_TABLE_TYPE_MASK));
+
+ status = iavf_asq_send_command(hw, &desc, lut, lut_size, NULL);
+
+ return status;
+}
+
+/**
+ * iavf_aq_get_rss_lut
+ * @hw: pointer to the hardware structure
+ * @vsi_id: vsi fw index
+ * @pf_lut: for PF table set true, for VSI table set false
+ * @lut: pointer to the lut buffer provided by the caller
+ * @lut_size: size of the lut buffer
+ *
+ * get the RSS lookup table, PF or VSI type
+ **/
+iavf_status iavf_aq_get_rss_lut(struct iavf_hw *hw, u16 vsi_id,
+ bool pf_lut, u8 *lut, u16 lut_size)
+{
+ return iavf_aq_get_set_rss_lut(hw, vsi_id, pf_lut, lut, lut_size,
+ false);
+}
+
+/**
+ * iavf_aq_set_rss_lut
+ * @hw: pointer to the hardware structure
+ * @vsi_id: vsi fw index
+ * @pf_lut: for PF table set true, for VSI table set false
+ * @lut: pointer to the lut buffer provided by the caller
+ * @lut_size: size of the lut buffer
+ *
+ * set the RSS lookup table, PF or VSI type
+ **/
+iavf_status iavf_aq_set_rss_lut(struct iavf_hw *hw, u16 vsi_id,
+ bool pf_lut, u8 *lut, u16 lut_size)
+{
+ return iavf_aq_get_set_rss_lut(hw, vsi_id, pf_lut, lut, lut_size, true);
+}
+
+/**
+ * iavf_aq_get_set_rss_key
+ * @hw: pointer to the hw struct
+ * @vsi_id: vsi fw index
+ * @key: pointer to key info struct
+ * @set: set true to set the key, false to get the key
+ *
+ * get the RSS key per VSI
+ **/
+static
+iavf_status iavf_aq_get_set_rss_key(struct iavf_hw *hw, u16 vsi_id,
+ struct i40e_aqc_get_set_rss_key_data *key,
+ bool set)
+{
+ iavf_status status;
+ struct i40e_aq_desc desc;
+ struct i40e_aqc_get_set_rss_key *cmd_resp =
+ (struct i40e_aqc_get_set_rss_key *)&desc.params.raw;
+ u16 key_size = sizeof(struct i40e_aqc_get_set_rss_key_data);
+
+ if (set)
+ iavf_fill_default_direct_cmd_desc(&desc,
+ i40e_aqc_opc_set_rss_key);
+ else
+ iavf_fill_default_direct_cmd_desc(&desc,
+ i40e_aqc_opc_get_rss_key);
+
+ /* Indirect command */
+ desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_BUF);
+ desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_RD);
+
+ cmd_resp->vsi_id =
+ cpu_to_le16((u16)((vsi_id <<
+ I40E_AQC_SET_RSS_KEY_VSI_ID_SHIFT) &
+ I40E_AQC_SET_RSS_KEY_VSI_ID_MASK));
+ cmd_resp->vsi_id |= cpu_to_le16((u16)I40E_AQC_SET_RSS_KEY_VSI_VALID);
+
+ status = iavf_asq_send_command(hw, &desc, key, key_size, NULL);
+
+ return status;
+}
+
+/**
+ * iavf_aq_get_rss_key
+ * @hw: pointer to the hw struct
+ * @vsi_id: vsi fw index
+ * @key: pointer to key info struct
+ *
+ **/
+iavf_status iavf_aq_get_rss_key(struct iavf_hw *hw, u16 vsi_id,
+ struct i40e_aqc_get_set_rss_key_data *key)
+{
+ return iavf_aq_get_set_rss_key(hw, vsi_id, key, false);
+}
+
+/**
+ * iavf_aq_set_rss_key
+ * @hw: pointer to the hw struct
+ * @vsi_id: vsi fw index
+ * @key: pointer to key info struct
+ *
+ * set the RSS key per VSI
+ **/
+iavf_status iavf_aq_set_rss_key(struct iavf_hw *hw, u16 vsi_id,
+ struct i40e_aqc_get_set_rss_key_data *key)
+{
+ return iavf_aq_get_set_rss_key(hw, vsi_id, key, true);
+}
+
+/* The iavf_ptype_lookup table is used to convert from the 8-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 iavf_ptype_lookup[ptype].known
+ * THEN
+ * Packet is unknown
+ * ELSE IF iavf_ptype_lookup[ptype].outer_ip == I40E_RX_PTYPE_OUTER_IP
+ * Use the rest of the fields to look at the tunnels, inner protocols, etc
+ * ELSE
+ * Use the enum iavf_rx_l2_ptype to decode the packet type
+ * ENDIF
+ */
+
+/* macro to make the table lines short */
+#define IAVF_PTT(PTYPE, OUTER_IP, OUTER_IP_VER, OUTER_FRAG, T, TE, TEF, I, PL)\
+ { PTYPE, \
+ 1, \
+ IAVF_RX_PTYPE_OUTER_##OUTER_IP, \
+ IAVF_RX_PTYPE_OUTER_##OUTER_IP_VER, \
+ IAVF_RX_PTYPE_##OUTER_FRAG, \
+ IAVF_RX_PTYPE_TUNNEL_##T, \
+ IAVF_RX_PTYPE_TUNNEL_END_##TE, \
+ IAVF_RX_PTYPE_##TEF, \
+ 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 }
+
+/* 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[] = {
+ /* L2 Packet types */
+ IAVF_PTT_UNUSED_ENTRY(0),
+ IAVF_PTT(1, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
+ IAVF_PTT(2, L2, NONE, NOF, NONE, NONE, NOF, TS, PAY2),
+ IAVF_PTT(3, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
+ IAVF_PTT_UNUSED_ENTRY(4),
+ IAVF_PTT_UNUSED_ENTRY(5),
+ IAVF_PTT(6, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
+ IAVF_PTT(7, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
+ IAVF_PTT_UNUSED_ENTRY(8),
+ IAVF_PTT_UNUSED_ENTRY(9),
+ IAVF_PTT(10, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
+ IAVF_PTT(11, L2, NONE, NOF, NONE, NONE, NOF, NONE, NONE),
+ IAVF_PTT(12, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+ IAVF_PTT(13, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+ IAVF_PTT(14, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+ IAVF_PTT(15, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+ IAVF_PTT(16, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+ IAVF_PTT(17, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+ IAVF_PTT(18, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+ IAVF_PTT(19, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+ IAVF_PTT(20, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+ IAVF_PTT(21, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+
+ /* Non Tunneled IPv4 */
+ IAVF_PTT(22, IP, IPV4, FRG, NONE, NONE, NOF, NONE, PAY3),
+ IAVF_PTT(23, IP, IPV4, NOF, NONE, NONE, NOF, NONE, PAY3),
+ IAVF_PTT(24, IP, IPV4, NOF, NONE, NONE, NOF, UDP, PAY4),
+ IAVF_PTT_UNUSED_ENTRY(25),
+ IAVF_PTT(26, IP, IPV4, NOF, NONE, NONE, NOF, TCP, PAY4),
+ IAVF_PTT(27, IP, IPV4, NOF, NONE, NONE, NOF, SCTP, PAY4),
+ IAVF_PTT(28, IP, IPV4, NOF, NONE, NONE, NOF, ICMP, PAY4),
+
+ /* IPv4 --> IPv4 */
+ IAVF_PTT(29, IP, IPV4, NOF, IP_IP, IPV4, FRG, NONE, PAY3),
+ IAVF_PTT(30, IP, IPV4, NOF, IP_IP, IPV4, NOF, NONE, PAY3),
+ IAVF_PTT(31, IP, IPV4, NOF, IP_IP, IPV4, NOF, UDP, PAY4),
+ IAVF_PTT_UNUSED_ENTRY(32),
+ IAVF_PTT(33, IP, IPV4, NOF, IP_IP, IPV4, NOF, TCP, PAY4),
+ IAVF_PTT(34, IP, IPV4, NOF, IP_IP, IPV4, NOF, SCTP, PAY4),
+ IAVF_PTT(35, IP, IPV4, NOF, IP_IP, IPV4, NOF, ICMP, PAY4),
+
+ /* IPv4 --> IPv6 */
+ IAVF_PTT(36, IP, IPV4, NOF, IP_IP, IPV6, FRG, NONE, PAY3),
+ IAVF_PTT(37, IP, IPV4, NOF, IP_IP, IPV6, NOF, NONE, PAY3),
+ IAVF_PTT(38, IP, IPV4, NOF, IP_IP, IPV6, NOF, UDP, PAY4),
+ IAVF_PTT_UNUSED_ENTRY(39),
+ IAVF_PTT(40, IP, IPV4, NOF, IP_IP, IPV6, NOF, TCP, PAY4),
+ IAVF_PTT(41, IP, IPV4, NOF, IP_IP, IPV6, NOF, SCTP, PAY4),
+ IAVF_PTT(42, IP, IPV4, NOF, IP_IP, IPV6, NOF, ICMP, PAY4),
+
+ /* IPv4 --> GRE/NAT */
+ IAVF_PTT(43, IP, IPV4, NOF, IP_GRENAT, NONE, NOF, NONE, PAY3),
+
+ /* IPv4 --> GRE/NAT --> IPv4 */
+ IAVF_PTT(44, IP, IPV4, NOF, IP_GRENAT, IPV4, FRG, NONE, PAY3),
+ IAVF_PTT(45, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, NONE, PAY3),
+ IAVF_PTT(46, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, UDP, PAY4),
+ IAVF_PTT_UNUSED_ENTRY(47),
+ IAVF_PTT(48, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, TCP, PAY4),
+ IAVF_PTT(49, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, SCTP, PAY4),
+ IAVF_PTT(50, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, ICMP, PAY4),
+
+ /* IPv4 --> GRE/NAT --> IPv6 */
+ IAVF_PTT(51, IP, IPV4, NOF, IP_GRENAT, IPV6, FRG, NONE, PAY3),
+ IAVF_PTT(52, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, NONE, PAY3),
+ IAVF_PTT(53, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, UDP, PAY4),
+ IAVF_PTT_UNUSED_ENTRY(54),
+ IAVF_PTT(55, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, TCP, PAY4),
+ IAVF_PTT(56, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, SCTP, PAY4),
+ IAVF_PTT(57, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, ICMP, PAY4),
+
+ /* IPv4 --> GRE/NAT --> MAC */
+ IAVF_PTT(58, IP, IPV4, NOF, IP_GRENAT_MAC, NONE, NOF, NONE, PAY3),
+
+ /* IPv4 --> GRE/NAT --> MAC --> IPv4 */
+ IAVF_PTT(59, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, FRG, NONE, PAY3),
+ IAVF_PTT(60, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, NONE, PAY3),
+ IAVF_PTT(61, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, UDP, PAY4),
+ IAVF_PTT_UNUSED_ENTRY(62),
+ IAVF_PTT(63, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, TCP, PAY4),
+ IAVF_PTT(64, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, SCTP, PAY4),
+ IAVF_PTT(65, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, ICMP, PAY4),
+
+ /* IPv4 --> GRE/NAT -> MAC --> IPv6 */
+ IAVF_PTT(66, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, FRG, NONE, PAY3),
+ IAVF_PTT(67, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, NONE, PAY3),
+ IAVF_PTT(68, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, UDP, PAY4),
+ IAVF_PTT_UNUSED_ENTRY(69),
+ IAVF_PTT(70, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, TCP, PAY4),
+ IAVF_PTT(71, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, SCTP, PAY4),
+ IAVF_PTT(72, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, ICMP, PAY4),
+
+ /* IPv4 --> GRE/NAT --> MAC/VLAN */
+ IAVF_PTT(73, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, NONE, NOF, NONE, PAY3),
+
+ /* IPv4 ---> GRE/NAT -> MAC/VLAN --> IPv4 */
+ IAVF_PTT(74, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, FRG, NONE, PAY3),
+ IAVF_PTT(75, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, NONE, PAY3),
+ IAVF_PTT(76, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, UDP, PAY4),
+ IAVF_PTT_UNUSED_ENTRY(77),
+ IAVF_PTT(78, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, TCP, PAY4),
+ IAVF_PTT(79, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, SCTP, PAY4),
+ IAVF_PTT(80, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, ICMP, PAY4),
+
+ /* IPv4 -> GRE/NAT -> MAC/VLAN --> IPv6 */
+ IAVF_PTT(81, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, FRG, NONE, PAY3),
+ IAVF_PTT(82, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, NONE, PAY3),
+ IAVF_PTT(83, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, UDP, PAY4),
+ IAVF_PTT_UNUSED_ENTRY(84),
+ IAVF_PTT(85, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, TCP, PAY4),
+ IAVF_PTT(86, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, SCTP, PAY4),
+ IAVF_PTT(87, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, ICMP, PAY4),
+
+ /* Non Tunneled IPv6 */
+ IAVF_PTT(88, IP, IPV6, FRG, NONE, NONE, NOF, NONE, PAY3),
+ IAVF_PTT(89, IP, IPV6, NOF, NONE, NONE, NOF, NONE, PAY3),
+ IAVF_PTT(90, IP, IPV6, NOF, NONE, NONE, NOF, UDP, PAY3),
+ IAVF_PTT_UNUSED_ENTRY(91),
+ IAVF_PTT(92, IP, IPV6, NOF, NONE, NONE, NOF, TCP, PAY4),
+ IAVF_PTT(93, IP, IPV6, NOF, NONE, NONE, NOF, SCTP, PAY4),
+ IAVF_PTT(94, IP, IPV6, NOF, NONE, NONE, NOF, ICMP, PAY4),
+
+ /* IPv6 --> IPv4 */
+ IAVF_PTT(95, IP, IPV6, NOF, IP_IP, IPV4, FRG, NONE, PAY3),
+ IAVF_PTT(96, IP, IPV6, NOF, IP_IP, IPV4, NOF, NONE, PAY3),
+ IAVF_PTT(97, IP, IPV6, NOF, IP_IP, IPV4, NOF, UDP, PAY4),
+ IAVF_PTT_UNUSED_ENTRY(98),
+ IAVF_PTT(99, IP, IPV6, NOF, IP_IP, IPV4, NOF, TCP, PAY4),
+ IAVF_PTT(100, IP, IPV6, NOF, IP_IP, IPV4, NOF, SCTP, PAY4),
+ IAVF_PTT(101, IP, IPV6, NOF, IP_IP, IPV4, NOF, ICMP, PAY4),
+
+ /* IPv6 --> IPv6 */
+ IAVF_PTT(102, IP, IPV6, NOF, IP_IP, IPV6, FRG, NONE, PAY3),
+ IAVF_PTT(103, IP, IPV6, NOF, IP_IP, IPV6, NOF, NONE, PAY3),
+ IAVF_PTT(104, IP, IPV6, NOF, IP_IP, IPV6, NOF, UDP, PAY4),
+ IAVF_PTT_UNUSED_ENTRY(105),
+ IAVF_PTT(106, IP, IPV6, NOF, IP_IP, IPV6, NOF, TCP, PAY4),
+ IAVF_PTT(107, IP, IPV6, NOF, IP_IP, IPV6, NOF, SCTP, PAY4),
+ IAVF_PTT(108, IP, IPV6, NOF, IP_IP, IPV6, NOF, ICMP, PAY4),
+
+ /* IPv6 --> GRE/NAT */
+ IAVF_PTT(109, IP, IPV6, NOF, IP_GRENAT, NONE, NOF, NONE, PAY3),
+
+ /* IPv6 --> GRE/NAT -> IPv4 */
+ IAVF_PTT(110, IP, IPV6, NOF, IP_GRENAT, IPV4, FRG, NONE, PAY3),
+ IAVF_PTT(111, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, NONE, PAY3),
+ IAVF_PTT(112, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, UDP, PAY4),
+ IAVF_PTT_UNUSED_ENTRY(113),
+ IAVF_PTT(114, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, TCP, PAY4),
+ IAVF_PTT(115, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, SCTP, PAY4),
+ IAVF_PTT(116, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, ICMP, PAY4),
+
+ /* IPv6 --> GRE/NAT -> IPv6 */
+ IAVF_PTT(117, IP, IPV6, NOF, IP_GRENAT, IPV6, FRG, NONE, PAY3),
+ IAVF_PTT(118, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, NONE, PAY3),
+ IAVF_PTT(119, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, UDP, PAY4),
+ IAVF_PTT_UNUSED_ENTRY(120),
+ IAVF_PTT(121, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, TCP, PAY4),
+ IAVF_PTT(122, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, SCTP, PAY4),
+ IAVF_PTT(123, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, ICMP, PAY4),
+
+ /* IPv6 --> GRE/NAT -> MAC */
+ IAVF_PTT(124, IP, IPV6, NOF, IP_GRENAT_MAC, NONE, NOF, NONE, PAY3),
+
+ /* IPv6 --> GRE/NAT -> MAC -> IPv4 */
+ IAVF_PTT(125, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, FRG, NONE, PAY3),
+ IAVF_PTT(126, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, NONE, PAY3),
+ IAVF_PTT(127, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, UDP, PAY4),
+ IAVF_PTT_UNUSED_ENTRY(128),
+ IAVF_PTT(129, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, TCP, PAY4),
+ IAVF_PTT(130, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, SCTP, PAY4),
+ IAVF_PTT(131, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, ICMP, PAY4),
+
+ /* IPv6 --> GRE/NAT -> MAC -> IPv6 */
+ IAVF_PTT(132, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, FRG, NONE, PAY3),
+ IAVF_PTT(133, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, NONE, PAY3),
+ IAVF_PTT(134, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, UDP, PAY4),
+ IAVF_PTT_UNUSED_ENTRY(135),
+ IAVF_PTT(136, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, TCP, PAY4),
+ IAVF_PTT(137, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, SCTP, PAY4),
+ IAVF_PTT(138, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, ICMP, PAY4),
+
+ /* IPv6 --> GRE/NAT -> MAC/VLAN */
+ IAVF_PTT(139, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, NONE, NOF, NONE, PAY3),
+
+ /* IPv6 --> GRE/NAT -> MAC/VLAN --> IPv4 */
+ IAVF_PTT(140, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, FRG, NONE, PAY3),
+ IAVF_PTT(141, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, NONE, PAY3),
+ IAVF_PTT(142, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, UDP, PAY4),
+ IAVF_PTT_UNUSED_ENTRY(143),
+ IAVF_PTT(144, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, TCP, PAY4),
+ IAVF_PTT(145, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, SCTP, PAY4),
+ IAVF_PTT(146, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, ICMP, PAY4),
+
+ /* IPv6 --> GRE/NAT -> MAC/VLAN --> IPv6 */
+ IAVF_PTT(147, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, FRG, NONE, PAY3),
+ IAVF_PTT(148, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, NONE, PAY3),
+ IAVF_PTT(149, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, UDP, PAY4),
+ IAVF_PTT_UNUSED_ENTRY(150),
+ IAVF_PTT(151, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, TCP, PAY4),
+ IAVF_PTT(152, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, SCTP, PAY4),
+ 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)
+};
+
+/**
+ * iavf_aq_send_msg_to_pf
+ * @hw: pointer to the hardware structure
+ * @v_opcode: opcodes for VF-PF communication
+ * @v_retval: return error code
+ * @msg: pointer to the msg buffer
+ * @msglen: msg length
+ * @cmd_details: pointer to command details
+ *
+ * Send message to PF driver using admin queue. By default, this message
+ * is sent asynchronously, i.e. iavf_asq_send_command() does not wait for
+ * completion before returning.
+ **/
+iavf_status iavf_aq_send_msg_to_pf(struct iavf_hw *hw,
+ enum virtchnl_ops v_opcode,
+ iavf_status v_retval, u8 *msg, u16 msglen,
+ struct i40e_asq_cmd_details *cmd_details)
+{
+ struct i40e_asq_cmd_details details;
+ struct i40e_aq_desc desc;
+ iavf_status status;
+
+ iavf_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_send_msg_to_pf);
+ desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_SI);
+ desc.cookie_high = cpu_to_le32(v_opcode);
+ desc.cookie_low = cpu_to_le32(v_retval);
+ if (msglen) {
+ desc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF
+ | I40E_AQ_FLAG_RD));
+ if (msglen > I40E_AQ_LARGE_BUF)
+ desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB);
+ desc.datalen = cpu_to_le16(msglen);
+ }
+ if (!cmd_details) {
+ memset(&details, 0, sizeof(details));
+ details.async = true;
+ cmd_details = &details;
+ }
+ status = iavf_asq_send_command(hw, &desc, msg, msglen, cmd_details);
+ return status;
+}
+
+/**
+ * iavf_vf_parse_hw_config
+ * @hw: pointer to the hardware structure
+ * @msg: pointer to the virtual channel VF resource structure
+ *
+ * Given a VF resource message from the PF, populate the hw struct
+ * with appropriate information.
+ **/
+void iavf_vf_parse_hw_config(struct iavf_hw *hw,
+ struct virtchnl_vf_resource *msg)
+{
+ struct virtchnl_vsi_resource *vsi_res;
+ int i;
+
+ vsi_res = &msg->vsi_res[0];
+
+ hw->dev_caps.num_vsis = msg->num_vsis;
+ hw->dev_caps.num_rx_qp = msg->num_queue_pairs;
+ hw->dev_caps.num_tx_qp = msg->num_queue_pairs;
+ hw->dev_caps.num_msix_vectors_vf = msg->max_vectors;
+ hw->dev_caps.dcb = msg->vf_cap_flags &
+ VIRTCHNL_VF_OFFLOAD_L2;
+ hw->dev_caps.fcoe = 0;
+ for (i = 0; i < msg->num_vsis; i++) {
+ if (vsi_res->vsi_type == VIRTCHNL_VSI_SRIOV) {
+ ether_addr_copy(hw->mac.perm_addr,
+ vsi_res->default_mac_addr);
+ ether_addr_copy(hw->mac.addr,
+ vsi_res->default_mac_addr);
+ }
+ vsi_res++;
+ }
+}
+
+/**
+ * iavf_vf_reset
+ * @hw: pointer to the hardware structure
+ *
+ * Send a VF_RESET message to the PF. Does not wait for response from PF
+ * as none will be forthcoming. Immediately after calling this function,
+ * the admin queue should be shut down and (optionally) reinitialized.
+ **/
+iavf_status iavf_vf_reset(struct iavf_hw *hw)
+{
+ return iavf_aq_send_msg_to_pf(hw, VIRTCHNL_OP_RESET_VF,
+ 0, NULL, 0, NULL);
+}
diff --git a/drivers/net/ethernet/intel/iavf/iavf_devids.h b/drivers/net/ethernet/intel/iavf/iavf_devids.h
new file mode 100644
index 000000000000..8eb7b697e96c
--- /dev/null
+++ b/drivers/net/ethernet/intel/iavf/iavf_devids.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
+
+#ifndef _IAVF_DEVIDS_H_
+#define _IAVF_DEVIDS_H_
+
+/* Device IDs for the VF driver */
+#define IAVF_DEV_ID_VF 0x154C
+#define IAVF_DEV_ID_VF_HV 0x1571
+#define IAVF_DEV_ID_ADAPTIVE_VF 0x1889
+#define IAVF_DEV_ID_X722_VF 0x37CD
+#endif /* _IAVF_DEVIDS_H_ */
diff --git a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c
new file mode 100644
index 000000000000..9f87304109fe
--- /dev/null
+++ b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c
@@ -0,0 +1,1036 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
+
+/* ethtool support for iavf */
+#include "iavf.h"
+
+#include <linux/uaccess.h>
+
+/* ethtool statistics helpers */
+
+/**
+ * struct iavf_stats - definition for an ethtool statistic
+ * @stat_string: statistic name to display in ethtool -S output
+ * @sizeof_stat: the sizeof() the stat, must be no greater than sizeof(u64)
+ * @stat_offset: offsetof() the stat from a base pointer
+ *
+ * This structure defines a statistic to be added to the ethtool stats buffer.
+ * It defines a statistic as offset from a common base pointer. Stats should
+ * be defined in constant arrays using the IAVF_STAT macro, with every element
+ * of the array using the same _type for calculating the sizeof_stat and
+ * stat_offset.
+ *
+ * The @sizeof_stat is expected to be sizeof(u8), sizeof(u16), sizeof(u32) or
+ * sizeof(u64). Other sizes are not expected and will produce a WARN_ONCE from
+ * the iavf_add_ethtool_stat() helper function.
+ *
+ * The @stat_string is interpreted as a format string, allowing formatted
+ * values to be inserted while looping over multiple structures for a given
+ * statistics array. Thus, every statistic string in an array should have the
+ * same type and number of format specifiers, to be formatted by variadic
+ * arguments to the iavf_add_stat_string() helper function.
+ **/
+struct iavf_stats {
+ char stat_string[ETH_GSTRING_LEN];
+ int sizeof_stat;
+ int stat_offset;
+};
+
+/* Helper macro to define an iavf_stat structure with proper size and type.
+ * Use this when defining constant statistics arrays. Note that @_type expects
+ * only a type name and is used multiple times.
+ */
+#define IAVF_STAT(_type, _name, _stat) { \
+ .stat_string = _name, \
+ .sizeof_stat = FIELD_SIZEOF(_type, _stat), \
+ .stat_offset = offsetof(_type, _stat) \
+}
+
+/* Helper macro for defining some statistics related to queues */
+#define IAVF_QUEUE_STAT(_name, _stat) \
+ IAVF_STAT(struct iavf_ring, _name, _stat)
+
+/* Stats associated with a Tx or Rx ring */
+static const struct iavf_stats iavf_gstrings_queue_stats[] = {
+ IAVF_QUEUE_STAT("%s-%u.packets", stats.packets),
+ IAVF_QUEUE_STAT("%s-%u.bytes", stats.bytes),
+};
+
+/**
+ * iavf_add_one_ethtool_stat - copy the stat into the supplied buffer
+ * @data: location to store the stat value
+ * @pointer: basis for where to copy from
+ * @stat: the stat definition
+ *
+ * Copies the stat data defined by the pointer and stat structure pair into
+ * the memory supplied as data. Used to implement iavf_add_ethtool_stats and
+ * iavf_add_queue_stats. If the pointer is null, data will be zero'd.
+ */
+static void
+iavf_add_one_ethtool_stat(u64 *data, void *pointer,
+ const struct iavf_stats *stat)
+{
+ char *p;
+
+ if (!pointer) {
+ /* ensure that the ethtool data buffer is zero'd for any stats
+ * which don't have a valid pointer.
+ */
+ *data = 0;
+ return;
+ }
+
+ p = (char *)pointer + stat->stat_offset;
+ switch (stat->sizeof_stat) {
+ case sizeof(u64):
+ *data = *((u64 *)p);
+ break;
+ case sizeof(u32):
+ *data = *((u32 *)p);
+ break;
+ case sizeof(u16):
+ *data = *((u16 *)p);
+ break;
+ case sizeof(u8):
+ *data = *((u8 *)p);
+ break;
+ default:
+ WARN_ONCE(1, "unexpected stat size for %s",
+ stat->stat_string);
+ *data = 0;
+ }
+}
+
+/**
+ * __iavf_add_ethtool_stats - copy stats into the ethtool supplied buffer
+ * @data: ethtool stats buffer
+ * @pointer: location to copy stats from
+ * @stats: array of stats to copy
+ * @size: the size of the stats definition
+ *
+ * Copy the stats defined by the stats array using the pointer as a base into
+ * the data buffer supplied by ethtool. Updates the data pointer to point to
+ * the next empty location for successive calls to __iavf_add_ethtool_stats.
+ * If pointer is null, set the data values to zero and update the pointer to
+ * skip these stats.
+ **/
+static void
+__iavf_add_ethtool_stats(u64 **data, void *pointer,
+ const struct iavf_stats stats[],
+ const unsigned int size)
+{
+ unsigned int i;
+
+ for (i = 0; i < size; i++)
+ iavf_add_one_ethtool_stat((*data)++, pointer, &stats[i]);
+}
+
+/**
+ * iavf_add_ethtool_stats - copy stats into ethtool supplied buffer
+ * @data: ethtool stats buffer
+ * @pointer: location where stats are stored
+ * @stats: static const array of stat definitions
+ *
+ * Macro to ease the use of __iavf_add_ethtool_stats by taking a static
+ * constant stats array and passing the ARRAY_SIZE(). This avoids typos by
+ * ensuring that we pass the size associated with the given stats array.
+ *
+ * The parameter @stats is evaluated twice, so parameters with side effects
+ * should be avoided.
+ **/
+#define iavf_add_ethtool_stats(data, pointer, stats) \
+ __iavf_add_ethtool_stats(data, pointer, stats, ARRAY_SIZE(stats))
+
+/**
+ * iavf_add_queue_stats - copy queue statistics into supplied buffer
+ * @data: ethtool stats buffer
+ * @ring: the ring to copy
+ *
+ * Queue statistics must be copied while protected by
+ * u64_stats_fetch_begin_irq, so we can't directly use iavf_add_ethtool_stats.
+ * Assumes that queue stats are defined in iavf_gstrings_queue_stats. If the
+ * ring pointer is null, zero out the queue stat values and update the data
+ * pointer. Otherwise safely copy the stats from the ring into the supplied
+ * buffer and update the data pointer when finished.
+ *
+ * This function expects to be called while under rcu_read_lock().
+ **/
+static void
+iavf_add_queue_stats(u64 **data, struct iavf_ring *ring)
+{
+ const unsigned int size = ARRAY_SIZE(iavf_gstrings_queue_stats);
+ const struct iavf_stats *stats = iavf_gstrings_queue_stats;
+ unsigned int start;
+ unsigned int i;
+
+ /* To avoid invalid statistics values, ensure that we keep retrying
+ * the copy until we get a consistent value according to
+ * u64_stats_fetch_retry_irq. But first, make sure our ring is
+ * non-null before attempting to access its syncp.
+ */
+ do {
+ start = !ring ? 0 : u64_stats_fetch_begin_irq(&ring->syncp);
+ for (i = 0; i < size; i++)
+ iavf_add_one_ethtool_stat(&(*data)[i], ring, &stats[i]);
+ } while (ring && u64_stats_fetch_retry_irq(&ring->syncp, start));
+
+ /* Once we successfully copy the stats in, update the data pointer */
+ *data += size;
+}
+
+/**
+ * __iavf_add_stat_strings - copy stat strings into ethtool buffer
+ * @p: ethtool supplied buffer
+ * @stats: stat definitions array
+ * @size: size of the stats array
+ *
+ * Format and copy the strings described by stats into the buffer pointed at
+ * by p.
+ **/
+static void __iavf_add_stat_strings(u8 **p, const struct iavf_stats stats[],
+ const unsigned int size, ...)
+{
+ unsigned int i;
+
+ for (i = 0; i < size; i++) {
+ va_list args;
+
+ va_start(args, size);
+ vsnprintf(*p, ETH_GSTRING_LEN, stats[i].stat_string, args);
+ *p += ETH_GSTRING_LEN;
+ va_end(args);
+ }
+}
+
+/**
+ * iavf_add_stat_strings - copy stat strings into ethtool buffer
+ * @p: ethtool supplied buffer
+ * @stats: stat definitions array
+ *
+ * Format and copy the strings described by the const static stats value into
+ * the buffer pointed at by p.
+ *
+ * The parameter @stats is evaluated twice, so parameters with side effects
+ * should be avoided. Additionally, stats must be an array such that
+ * ARRAY_SIZE can be called on it.
+ **/
+#define iavf_add_stat_strings(p, stats, ...) \
+ __iavf_add_stat_strings(p, stats, ARRAY_SIZE(stats), ## __VA_ARGS__)
+
+#define VF_STAT(_name, _stat) \
+ IAVF_STAT(struct iavf_adapter, _name, _stat)
+
+static const struct iavf_stats iavf_gstrings_stats[] = {
+ VF_STAT("rx_bytes", current_stats.rx_bytes),
+ VF_STAT("rx_unicast", current_stats.rx_unicast),
+ VF_STAT("rx_multicast", current_stats.rx_multicast),
+ VF_STAT("rx_broadcast", current_stats.rx_broadcast),
+ VF_STAT("rx_discards", current_stats.rx_discards),
+ VF_STAT("rx_unknown_protocol", current_stats.rx_unknown_protocol),
+ VF_STAT("tx_bytes", current_stats.tx_bytes),
+ VF_STAT("tx_unicast", current_stats.tx_unicast),
+ VF_STAT("tx_multicast", current_stats.tx_multicast),
+ VF_STAT("tx_broadcast", current_stats.tx_broadcast),
+ VF_STAT("tx_discards", current_stats.tx_discards),
+ VF_STAT("tx_errors", current_stats.tx_errors),
+};
+
+#define IAVF_STATS_LEN ARRAY_SIZE(iavf_gstrings_stats)
+
+#define IAVF_QUEUE_STATS_LEN ARRAY_SIZE(iavf_gstrings_queue_stats)
+
+/* For now we have one and only one private flag and it is only defined
+ * when we have support for the SKIP_CPU_SYNC DMA attribute. Instead
+ * of leaving all this code sitting around empty we will strip it unless
+ * our one private flag is actually available.
+ */
+struct iavf_priv_flags {
+ char flag_string[ETH_GSTRING_LEN];
+ u32 flag;
+ bool read_only;
+};
+
+#define IAVF_PRIV_FLAG(_name, _flag, _read_only) { \
+ .flag_string = _name, \
+ .flag = _flag, \
+ .read_only = _read_only, \
+}
+
+static const struct iavf_priv_flags iavf_gstrings_priv_flags[] = {
+ IAVF_PRIV_FLAG("legacy-rx", IAVF_FLAG_LEGACY_RX, 0),
+};
+
+#define IAVF_PRIV_FLAGS_STR_LEN ARRAY_SIZE(iavf_gstrings_priv_flags)
+
+/**
+ * iavf_get_link_ksettings - Get Link Speed and Duplex settings
+ * @netdev: network interface device structure
+ * @cmd: ethtool command
+ *
+ * Reports speed/duplex settings. Because this is a VF, we don't know what
+ * kind of link we really have, so we fake it.
+ **/
+static int iavf_get_link_ksettings(struct net_device *netdev,
+ struct ethtool_link_ksettings *cmd)
+{
+ struct iavf_adapter *adapter = netdev_priv(netdev);
+
+ ethtool_link_ksettings_zero_link_mode(cmd, supported);
+ cmd->base.autoneg = AUTONEG_DISABLE;
+ cmd->base.port = PORT_NONE;
+ /* Set speed and duplex */
+ switch (adapter->link_speed) {
+ case I40E_LINK_SPEED_40GB:
+ cmd->base.speed = SPEED_40000;
+ break;
+ case I40E_LINK_SPEED_25GB:
+#ifdef SPEED_25000
+ cmd->base.speed = SPEED_25000;
+#else
+ netdev_info(netdev,
+ "Speed is 25G, display not supported by this version of ethtool.\n");
+#endif
+ break;
+ case I40E_LINK_SPEED_20GB:
+ cmd->base.speed = SPEED_20000;
+ break;
+ case I40E_LINK_SPEED_10GB:
+ cmd->base.speed = SPEED_10000;
+ break;
+ case I40E_LINK_SPEED_1GB:
+ cmd->base.speed = SPEED_1000;
+ break;
+ case I40E_LINK_SPEED_100MB:
+ cmd->base.speed = SPEED_100;
+ break;
+ default:
+ break;
+ }
+ cmd->base.duplex = DUPLEX_FULL;
+
+ return 0;
+}
+
+/**
+ * iavf_get_sset_count - Get length of string set
+ * @netdev: network interface device structure
+ * @sset: id of string set
+ *
+ * Reports size of various string tables.
+ **/
+static int iavf_get_sset_count(struct net_device *netdev, int sset)
+{
+ if (sset == ETH_SS_STATS)
+ return IAVF_STATS_LEN +
+ (IAVF_QUEUE_STATS_LEN * 2 * IAVF_MAX_REQ_QUEUES);
+ else if (sset == ETH_SS_PRIV_FLAGS)
+ return IAVF_PRIV_FLAGS_STR_LEN;
+ else
+ return -EINVAL;
+}
+
+/**
+ * iavf_get_ethtool_stats - report device statistics
+ * @netdev: network interface device structure
+ * @stats: ethtool statistics structure
+ * @data: pointer to data buffer
+ *
+ * All statistics are added to the data buffer as an array of u64.
+ **/
+static void iavf_get_ethtool_stats(struct net_device *netdev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct iavf_adapter *adapter = netdev_priv(netdev);
+ unsigned int i;
+
+ iavf_add_ethtool_stats(&data, adapter, iavf_gstrings_stats);
+
+ rcu_read_lock();
+ for (i = 0; i < IAVF_MAX_REQ_QUEUES; i++) {
+ struct iavf_ring *ring;
+
+ /* Avoid accessing un-allocated queues */
+ ring = (i < adapter->num_active_queues ?
+ &adapter->tx_rings[i] : NULL);
+ iavf_add_queue_stats(&data, ring);
+
+ /* Avoid accessing un-allocated queues */
+ ring = (i < adapter->num_active_queues ?
+ &adapter->rx_rings[i] : NULL);
+ iavf_add_queue_stats(&data, ring);
+ }
+ rcu_read_unlock();
+}
+
+/**
+ * iavf_get_priv_flag_strings - Get private flag strings
+ * @netdev: network interface device structure
+ * @data: buffer for string data
+ *
+ * Builds the private flags string table
+ **/
+static void iavf_get_priv_flag_strings(struct net_device *netdev, u8 *data)
+{
+ unsigned int i;
+
+ for (i = 0; i < IAVF_PRIV_FLAGS_STR_LEN; i++) {
+ snprintf(data, ETH_GSTRING_LEN, "%s",
+ iavf_gstrings_priv_flags[i].flag_string);
+ data += ETH_GSTRING_LEN;
+ }
+}
+
+/**
+ * iavf_get_stat_strings - Get stat strings
+ * @netdev: network interface device structure
+ * @data: buffer for string data
+ *
+ * Builds the statistics string table
+ **/
+static void iavf_get_stat_strings(struct net_device *netdev, u8 *data)
+{
+ unsigned int i;
+
+ iavf_add_stat_strings(&data, iavf_gstrings_stats);
+
+ /* Queues are always allocated in pairs, so we just use num_tx_queues
+ * for both Tx and Rx queues.
+ */
+ for (i = 0; i < netdev->num_tx_queues; i++) {
+ iavf_add_stat_strings(&data, iavf_gstrings_queue_stats,
+ "tx", i);
+ iavf_add_stat_strings(&data, iavf_gstrings_queue_stats,
+ "rx", i);
+ }
+}
+
+/**
+ * iavf_get_strings - Get string set
+ * @netdev: network interface device structure
+ * @sset: id of string set
+ * @data: buffer for string data
+ *
+ * Builds string tables for various string sets
+ **/
+static void iavf_get_strings(struct net_device *netdev, u32 sset, u8 *data)
+{
+ switch (sset) {
+ case ETH_SS_STATS:
+ iavf_get_stat_strings(netdev, data);
+ break;
+ case ETH_SS_PRIV_FLAGS:
+ iavf_get_priv_flag_strings(netdev, data);
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * iavf_get_priv_flags - report device private flags
+ * @netdev: network interface device structure
+ *
+ * The get string set count and the string set should be matched for each
+ * flag returned. Add new strings for each flag to the iavf_gstrings_priv_flags
+ * array.
+ *
+ * Returns a u32 bitmap of flags.
+ **/
+static u32 iavf_get_priv_flags(struct net_device *netdev)
+{
+ struct iavf_adapter *adapter = netdev_priv(netdev);
+ u32 i, ret_flags = 0;
+
+ for (i = 0; i < IAVF_PRIV_FLAGS_STR_LEN; i++) {
+ const struct iavf_priv_flags *priv_flags;
+
+ priv_flags = &iavf_gstrings_priv_flags[i];
+
+ if (priv_flags->flag & adapter->flags)
+ ret_flags |= BIT(i);
+ }
+
+ return ret_flags;
+}
+
+/**
+ * iavf_set_priv_flags - set private flags
+ * @netdev: network interface device structure
+ * @flags: bit flags to be set
+ **/
+static int iavf_set_priv_flags(struct net_device *netdev, u32 flags)
+{
+ struct iavf_adapter *adapter = netdev_priv(netdev);
+ u32 orig_flags, new_flags, changed_flags;
+ u32 i;
+
+ orig_flags = READ_ONCE(adapter->flags);
+ new_flags = orig_flags;
+
+ for (i = 0; i < IAVF_PRIV_FLAGS_STR_LEN; i++) {
+ const struct iavf_priv_flags *priv_flags;
+
+ priv_flags = &iavf_gstrings_priv_flags[i];
+
+ if (flags & BIT(i))
+ new_flags |= priv_flags->flag;
+ else
+ new_flags &= ~(priv_flags->flag);
+
+ if (priv_flags->read_only &&
+ ((orig_flags ^ new_flags) & ~BIT(i)))
+ return -EOPNOTSUPP;
+ }
+
+ /* Before we finalize any flag changes, any checks which we need to
+ * perform to determine if the new flags will be supported should go
+ * here...
+ */
+
+ /* Compare and exchange the new flags into place. If we failed, that
+ * is if cmpxchg returns anything but the old value, this means
+ * something else must have modified the flags variable since we
+ * copied it. We'll just punt with an error and log something in the
+ * message buffer.
+ */
+ if (cmpxchg(&adapter->flags, orig_flags, new_flags) != orig_flags) {
+ dev_warn(&adapter->pdev->dev,
+ "Unable to update adapter->flags as it was modified by another thread...\n");
+ return -EAGAIN;
+ }
+
+ changed_flags = orig_flags ^ new_flags;
+
+ /* Process any additional changes needed as a result of flag changes.
+ * The changed_flags value reflects the list of bits that were changed
+ * in the code above.
+ */
+
+ /* issue a reset to force legacy-rx change to take effect */
+ if (changed_flags & IAVF_FLAG_LEGACY_RX) {
+ if (netif_running(netdev)) {
+ adapter->flags |= IAVF_FLAG_RESET_NEEDED;
+ schedule_work(&adapter->reset_task);
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * iavf_get_msglevel - Get debug message level
+ * @netdev: network interface device structure
+ *
+ * Returns current debug message level.
+ **/
+static u32 iavf_get_msglevel(struct net_device *netdev)
+{
+ struct iavf_adapter *adapter = netdev_priv(netdev);
+
+ return adapter->msg_enable;
+}
+
+/**
+ * iavf_set_msglevel - Set debug message level
+ * @netdev: network interface device structure
+ * @data: message level
+ *
+ * Set current debug message level. Higher values cause the driver to
+ * be noisier.
+ **/
+static void iavf_set_msglevel(struct net_device *netdev, u32 data)
+{
+ struct iavf_adapter *adapter = netdev_priv(netdev);
+
+ if (IAVF_DEBUG_USER & data)
+ adapter->hw.debug_mask = data;
+ adapter->msg_enable = data;
+}
+
+/**
+ * iavf_get_drvinfo - Get driver info
+ * @netdev: network interface device structure
+ * @drvinfo: ethool driver info structure
+ *
+ * Returns information about the driver and device for display to the user.
+ **/
+static void iavf_get_drvinfo(struct net_device *netdev,
+ struct ethtool_drvinfo *drvinfo)
+{
+ struct iavf_adapter *adapter = netdev_priv(netdev);
+
+ strlcpy(drvinfo->driver, iavf_driver_name, 32);
+ strlcpy(drvinfo->version, iavf_driver_version, 32);
+ strlcpy(drvinfo->fw_version, "N/A", 4);
+ strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
+ drvinfo->n_priv_flags = IAVF_PRIV_FLAGS_STR_LEN;
+}
+
+/**
+ * iavf_get_ringparam - Get ring parameters
+ * @netdev: network interface device structure
+ * @ring: ethtool ringparam structure
+ *
+ * Returns current ring parameters. TX and RX rings are reported separately,
+ * but the number of rings is not reported.
+ **/
+static void iavf_get_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring)
+{
+ struct iavf_adapter *adapter = netdev_priv(netdev);
+
+ ring->rx_max_pending = IAVF_MAX_RXD;
+ ring->tx_max_pending = IAVF_MAX_TXD;
+ ring->rx_pending = adapter->rx_desc_count;
+ ring->tx_pending = adapter->tx_desc_count;
+}
+
+/**
+ * iavf_set_ringparam - Set ring parameters
+ * @netdev: network interface device structure
+ * @ring: ethtool ringparam structure
+ *
+ * Sets ring parameters. TX and RX rings are controlled separately, but the
+ * number of rings is not specified, so all rings get the same settings.
+ **/
+static int iavf_set_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring)
+{
+ struct iavf_adapter *adapter = netdev_priv(netdev);
+ u32 new_rx_count, new_tx_count;
+
+ if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
+ return -EINVAL;
+
+ new_tx_count = clamp_t(u32, ring->tx_pending,
+ IAVF_MIN_TXD,
+ IAVF_MAX_TXD);
+ new_tx_count = ALIGN(new_tx_count, IAVF_REQ_DESCRIPTOR_MULTIPLE);
+
+ new_rx_count = clamp_t(u32, ring->rx_pending,
+ IAVF_MIN_RXD,
+ IAVF_MAX_RXD);
+ new_rx_count = ALIGN(new_rx_count, IAVF_REQ_DESCRIPTOR_MULTIPLE);
+
+ /* if nothing to do return success */
+ if ((new_tx_count == adapter->tx_desc_count) &&
+ (new_rx_count == adapter->rx_desc_count))
+ return 0;
+
+ adapter->tx_desc_count = new_tx_count;
+ adapter->rx_desc_count = new_rx_count;
+
+ if (netif_running(netdev)) {
+ adapter->flags |= IAVF_FLAG_RESET_NEEDED;
+ schedule_work(&adapter->reset_task);
+ }
+
+ return 0;
+}
+
+/**
+ * __iavf_get_coalesce - get per-queue coalesce settings
+ * @netdev: the netdev to check
+ * @ec: ethtool coalesce data structure
+ * @queue: which queue to pick
+ *
+ * Gets the per-queue settings for coalescence. Specifically Rx and Tx usecs
+ * are per queue. If queue is <0 then we default to queue 0 as the
+ * representative value.
+ **/
+static int __iavf_get_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *ec, int queue)
+{
+ struct iavf_adapter *adapter = netdev_priv(netdev);
+ struct iavf_vsi *vsi = &adapter->vsi;
+ struct iavf_ring *rx_ring, *tx_ring;
+
+ ec->tx_max_coalesced_frames = vsi->work_limit;
+ ec->rx_max_coalesced_frames = vsi->work_limit;
+
+ /* Rx and Tx usecs per queue value. If user doesn't specify the
+ * queue, return queue 0's value to represent.
+ */
+ if (queue < 0)
+ queue = 0;
+ else if (queue >= adapter->num_active_queues)
+ return -EINVAL;
+
+ rx_ring = &adapter->rx_rings[queue];
+ tx_ring = &adapter->tx_rings[queue];
+
+ if (ITR_IS_DYNAMIC(rx_ring->itr_setting))
+ ec->use_adaptive_rx_coalesce = 1;
+
+ if (ITR_IS_DYNAMIC(tx_ring->itr_setting))
+ ec->use_adaptive_tx_coalesce = 1;
+
+ ec->rx_coalesce_usecs = rx_ring->itr_setting & ~IAVF_ITR_DYNAMIC;
+ ec->tx_coalesce_usecs = tx_ring->itr_setting & ~IAVF_ITR_DYNAMIC;
+
+ return 0;
+}
+
+/**
+ * iavf_get_coalesce - Get interrupt coalescing settings
+ * @netdev: network interface device structure
+ * @ec: ethtool coalesce structure
+ *
+ * Returns current coalescing settings. This is referred to elsewhere in the
+ * driver as Interrupt Throttle Rate, as this is how the hardware describes
+ * this functionality. Note that if per-queue settings have been modified this
+ * only represents the settings of queue 0.
+ **/
+static int iavf_get_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *ec)
+{
+ return __iavf_get_coalesce(netdev, ec, -1);
+}
+
+/**
+ * iavf_get_per_queue_coalesce - get coalesce values for specific queue
+ * @netdev: netdev to read
+ * @ec: coalesce settings from ethtool
+ * @queue: the queue to read
+ *
+ * Read specific queue's coalesce settings.
+ **/
+static int iavf_get_per_queue_coalesce(struct net_device *netdev, u32 queue,
+ struct ethtool_coalesce *ec)
+{
+ return __iavf_get_coalesce(netdev, ec, queue);
+}
+
+/**
+ * iavf_set_itr_per_queue - set ITR values for specific queue
+ * @adapter: the VF adapter struct to set values for
+ * @ec: coalesce settings from ethtool
+ * @queue: the queue to modify
+ *
+ * Change the ITR settings for a specific queue.
+ **/
+static void iavf_set_itr_per_queue(struct iavf_adapter *adapter,
+ struct ethtool_coalesce *ec, int queue)
+{
+ struct iavf_ring *rx_ring = &adapter->rx_rings[queue];
+ struct iavf_ring *tx_ring = &adapter->tx_rings[queue];
+ struct iavf_q_vector *q_vector;
+
+ rx_ring->itr_setting = ITR_REG_ALIGN(ec->rx_coalesce_usecs);
+ tx_ring->itr_setting = ITR_REG_ALIGN(ec->tx_coalesce_usecs);
+
+ rx_ring->itr_setting |= IAVF_ITR_DYNAMIC;
+ if (!ec->use_adaptive_rx_coalesce)
+ rx_ring->itr_setting ^= IAVF_ITR_DYNAMIC;
+
+ tx_ring->itr_setting |= IAVF_ITR_DYNAMIC;
+ if (!ec->use_adaptive_tx_coalesce)
+ tx_ring->itr_setting ^= IAVF_ITR_DYNAMIC;
+
+ q_vector = rx_ring->q_vector;
+ q_vector->rx.target_itr = ITR_TO_REG(rx_ring->itr_setting);
+
+ q_vector = tx_ring->q_vector;
+ q_vector->tx.target_itr = ITR_TO_REG(tx_ring->itr_setting);
+
+ /* The interrupt handler itself will take care of programming
+ * the Tx and Rx ITR values based on the values we have entered
+ * into the q_vector, no need to write the values now.
+ */
+}
+
+/**
+ * __iavf_set_coalesce - set coalesce settings for particular queue
+ * @netdev: the netdev to change
+ * @ec: ethtool coalesce settings
+ * @queue: the queue to change
+ *
+ * Sets the coalesce settings for a particular queue.
+ **/
+static int __iavf_set_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *ec, int queue)
+{
+ struct iavf_adapter *adapter = netdev_priv(netdev);
+ struct iavf_vsi *vsi = &adapter->vsi;
+ int i;
+
+ if (ec->tx_max_coalesced_frames_irq || ec->rx_max_coalesced_frames_irq)
+ vsi->work_limit = ec->tx_max_coalesced_frames_irq;
+
+ if (ec->rx_coalesce_usecs == 0) {
+ if (ec->use_adaptive_rx_coalesce)
+ netif_info(adapter, drv, netdev, "rx-usecs=0, need to disable adaptive-rx for a complete disable\n");
+ } else if ((ec->rx_coalesce_usecs < IAVF_MIN_ITR) ||
+ (ec->rx_coalesce_usecs > IAVF_MAX_ITR)) {
+ netif_info(adapter, drv, netdev, "Invalid value, rx-usecs range is 0-8160\n");
+ return -EINVAL;
+ } else if (ec->tx_coalesce_usecs == 0) {
+ if (ec->use_adaptive_tx_coalesce)
+ netif_info(adapter, drv, netdev, "tx-usecs=0, need to disable adaptive-tx for a complete disable\n");
+ } else if ((ec->tx_coalesce_usecs < IAVF_MIN_ITR) ||
+ (ec->tx_coalesce_usecs > IAVF_MAX_ITR)) {
+ netif_info(adapter, drv, netdev, "Invalid value, tx-usecs range is 0-8160\n");
+ return -EINVAL;
+ }
+
+ /* Rx and Tx usecs has per queue value. If user doesn't specify the
+ * queue, apply to all queues.
+ */
+ if (queue < 0) {
+ for (i = 0; i < adapter->num_active_queues; i++)
+ iavf_set_itr_per_queue(adapter, ec, i);
+ } else if (queue < adapter->num_active_queues) {
+ iavf_set_itr_per_queue(adapter, ec, queue);
+ } else {
+ netif_info(adapter, drv, netdev, "Invalid queue value, queue range is 0 - %d\n",
+ adapter->num_active_queues - 1);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * iavf_set_coalesce - Set interrupt coalescing settings
+ * @netdev: network interface device structure
+ * @ec: ethtool coalesce structure
+ *
+ * Change current coalescing settings for every queue.
+ **/
+static int iavf_set_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *ec)
+{
+ return __iavf_set_coalesce(netdev, ec, -1);
+}
+
+/**
+ * iavf_set_per_queue_coalesce - set specific queue's coalesce settings
+ * @netdev: the netdev to change
+ * @ec: ethtool's coalesce settings
+ * @queue: the queue to modify
+ *
+ * Modifies a specific queue's coalesce settings.
+ */
+static int iavf_set_per_queue_coalesce(struct net_device *netdev, u32 queue,
+ struct ethtool_coalesce *ec)
+{
+ return __iavf_set_coalesce(netdev, ec, queue);
+}
+
+/**
+ * iavf_get_rxnfc - command to get RX flow classification rules
+ * @netdev: network interface device structure
+ * @cmd: ethtool rxnfc command
+ * @rule_locs: pointer to store rule locations
+ *
+ * Returns Success if the command is supported.
+ **/
+static int iavf_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd,
+ u32 *rule_locs)
+{
+ struct iavf_adapter *adapter = netdev_priv(netdev);
+ int ret = -EOPNOTSUPP;
+
+ switch (cmd->cmd) {
+ case ETHTOOL_GRXRINGS:
+ cmd->data = adapter->num_active_queues;
+ ret = 0;
+ break;
+ case ETHTOOL_GRXFH:
+ netdev_info(netdev,
+ "RSS hash info is not available to vf, use pf.\n");
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+/**
+ * iavf_get_channels: get the number of channels supported by the device
+ * @netdev: network interface device structure
+ * @ch: channel information structure
+ *
+ * For the purposes of our device, we only use combined channels, i.e. a tx/rx
+ * queue pair. Report one extra channel to match our "other" MSI-X vector.
+ **/
+static void iavf_get_channels(struct net_device *netdev,
+ struct ethtool_channels *ch)
+{
+ struct iavf_adapter *adapter = netdev_priv(netdev);
+
+ /* Report maximum channels */
+ ch->max_combined = IAVF_MAX_REQ_QUEUES;
+
+ ch->max_other = NONQ_VECS;
+ ch->other_count = NONQ_VECS;
+
+ ch->combined_count = adapter->num_active_queues;
+}
+
+/**
+ * iavf_set_channels: set the new channel count
+ * @netdev: network interface device structure
+ * @ch: channel information structure
+ *
+ * Negotiate a new number of channels with the PF then do a reset. During
+ * reset we'll realloc queues and fix the RSS table. Returns 0 on success,
+ * negative on failure.
+ **/
+static int iavf_set_channels(struct net_device *netdev,
+ struct ethtool_channels *ch)
+{
+ struct iavf_adapter *adapter = netdev_priv(netdev);
+ int num_req = ch->combined_count;
+
+ if (num_req != adapter->num_active_queues &&
+ !(adapter->vf_res->vf_cap_flags &
+ VIRTCHNL_VF_OFFLOAD_REQ_QUEUES)) {
+ dev_info(&adapter->pdev->dev, "PF is not capable of queue negotiation.\n");
+ return -EINVAL;
+ }
+
+ if ((adapter->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_ADQ) &&
+ adapter->num_tc) {
+ dev_info(&adapter->pdev->dev, "Cannot set channels since ADq is enabled.\n");
+ return -EINVAL;
+ }
+
+ /* All of these should have already been checked by ethtool before this
+ * even gets to us, but just to be sure.
+ */
+ if (num_req <= 0 || num_req > IAVF_MAX_REQ_QUEUES)
+ return -EINVAL;
+
+ if (ch->rx_count || ch->tx_count || ch->other_count != NONQ_VECS)
+ return -EINVAL;
+
+ adapter->num_req_queues = num_req;
+ return iavf_request_queues(adapter, num_req);
+}
+
+/**
+ * iavf_get_rxfh_key_size - get the RSS hash key size
+ * @netdev: network interface device structure
+ *
+ * Returns the table size.
+ **/
+static u32 iavf_get_rxfh_key_size(struct net_device *netdev)
+{
+ struct iavf_adapter *adapter = netdev_priv(netdev);
+
+ return adapter->rss_key_size;
+}
+
+/**
+ * iavf_get_rxfh_indir_size - get the rx flow hash indirection table size
+ * @netdev: network interface device structure
+ *
+ * Returns the table size.
+ **/
+static u32 iavf_get_rxfh_indir_size(struct net_device *netdev)
+{
+ struct iavf_adapter *adapter = netdev_priv(netdev);
+
+ return adapter->rss_lut_size;
+}
+
+/**
+ * iavf_get_rxfh - get the rx flow hash indirection table
+ * @netdev: network interface device structure
+ * @indir: indirection table
+ * @key: hash key
+ * @hfunc: hash function in use
+ *
+ * Reads the indirection table directly from the hardware. Always returns 0.
+ **/
+static int iavf_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
+ u8 *hfunc)
+{
+ struct iavf_adapter *adapter = netdev_priv(netdev);
+ u16 i;
+
+ if (hfunc)
+ *hfunc = ETH_RSS_HASH_TOP;
+ if (!indir)
+ return 0;
+
+ memcpy(key, adapter->rss_key, adapter->rss_key_size);
+
+ /* Each 32 bits pointed by 'indir' is stored with a lut entry */
+ for (i = 0; i < adapter->rss_lut_size; i++)
+ indir[i] = (u32)adapter->rss_lut[i];
+
+ return 0;
+}
+
+/**
+ * iavf_set_rxfh - set the rx flow hash indirection table
+ * @netdev: network interface device structure
+ * @indir: indirection table
+ * @key: hash key
+ * @hfunc: hash function to use
+ *
+ * Returns -EINVAL if the table specifies an inavlid queue id, otherwise
+ * returns 0 after programming the table.
+ **/
+static int iavf_set_rxfh(struct net_device *netdev, const u32 *indir,
+ const u8 *key, const u8 hfunc)
+{
+ struct iavf_adapter *adapter = netdev_priv(netdev);
+ u16 i;
+
+ /* We do not allow change in unsupported parameters */
+ if (key ||
+ (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP))
+ return -EOPNOTSUPP;
+ if (!indir)
+ return 0;
+
+ if (key)
+ memcpy(adapter->rss_key, key, adapter->rss_key_size);
+
+ /* Each 32 bits pointed by 'indir' is stored with a lut entry */
+ for (i = 0; i < adapter->rss_lut_size; i++)
+ adapter->rss_lut[i] = (u8)(indir[i]);
+
+ return iavf_config_rss(adapter);
+}
+
+static const struct ethtool_ops iavf_ethtool_ops = {
+ .get_drvinfo = iavf_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+ .get_ringparam = iavf_get_ringparam,
+ .set_ringparam = iavf_set_ringparam,
+ .get_strings = iavf_get_strings,
+ .get_ethtool_stats = iavf_get_ethtool_stats,
+ .get_sset_count = iavf_get_sset_count,
+ .get_priv_flags = iavf_get_priv_flags,
+ .set_priv_flags = iavf_set_priv_flags,
+ .get_msglevel = iavf_get_msglevel,
+ .set_msglevel = iavf_set_msglevel,
+ .get_coalesce = iavf_get_coalesce,
+ .set_coalesce = iavf_set_coalesce,
+ .get_per_queue_coalesce = iavf_get_per_queue_coalesce,
+ .set_per_queue_coalesce = iavf_set_per_queue_coalesce,
+ .get_rxnfc = iavf_get_rxnfc,
+ .get_rxfh_indir_size = iavf_get_rxfh_indir_size,
+ .get_rxfh = iavf_get_rxfh,
+ .set_rxfh = iavf_set_rxfh,
+ .get_channels = iavf_get_channels,
+ .set_channels = iavf_set_channels,
+ .get_rxfh_key_size = iavf_get_rxfh_key_size,
+ .get_link_ksettings = iavf_get_link_ksettings,
+};
+
+/**
+ * iavf_set_ethtool_ops - Initialize ethtool ops struct
+ * @netdev: network interface device structure
+ *
+ * Sets ethtool ops struct in our netdev so that ethtool can call
+ * our functions.
+ **/
+void iavf_set_ethtool_ops(struct net_device *netdev)
+{
+ netdev->ethtool_ops = &iavf_ethtool_ops;
+}
diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c
index fef6d892ed4c..9f2b7b7adf6b 100644
--- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_main.c
@@ -1,38 +1,38 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2013 - 2018 Intel Corporation. */
-#include "i40evf.h"
-#include "i40e_prototype.h"
-#include "i40evf_client.h"
-/* All i40evf tracepoints are defined by the include below, which must
+#include "iavf.h"
+#include "iavf_prototype.h"
+#include "iavf_client.h"
+/* All iavf tracepoints are defined by the include below, which must
* be included exactly once across the whole kernel with
* CREATE_TRACE_POINTS defined
*/
#define CREATE_TRACE_POINTS
-#include "i40e_trace.h"
+#include "iavf_trace.h"
-static int i40evf_setup_all_tx_resources(struct i40evf_adapter *adapter);
-static int i40evf_setup_all_rx_resources(struct i40evf_adapter *adapter);
-static int i40evf_close(struct net_device *netdev);
+static int iavf_setup_all_tx_resources(struct iavf_adapter *adapter);
+static int iavf_setup_all_rx_resources(struct iavf_adapter *adapter);
+static int iavf_close(struct net_device *netdev);
-char i40evf_driver_name[] = "i40evf";
-static const char i40evf_driver_string[] =
- "Intel(R) 40-10 Gigabit Virtual Function Network Driver";
+char iavf_driver_name[] = "iavf";
+static const char iavf_driver_string[] =
+ "Intel(R) Ethernet Adaptive Virtual Function Network Driver";
#define DRV_KERN "-k"
#define DRV_VERSION_MAJOR 3
#define DRV_VERSION_MINOR 2
-#define DRV_VERSION_BUILD 2
+#define DRV_VERSION_BUILD 3
#define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \
__stringify(DRV_VERSION_MINOR) "." \
__stringify(DRV_VERSION_BUILD) \
DRV_KERN
-const char i40evf_driver_version[] = DRV_VERSION;
-static const char i40evf_copyright[] =
- "Copyright (c) 2013 - 2015 Intel Corporation.";
+const char iavf_driver_version[] = DRV_VERSION;
+static const char iavf_copyright[] =
+ "Copyright (c) 2013 - 2018 Intel Corporation.";
-/* i40evf_pci_tbl - PCI Device ID Table
+/* iavf_pci_tbl - PCI Device ID Table
*
* Wildcard entries (PCI_ANY_ID) should come last
* Last entry must be all 0s
@@ -40,36 +40,37 @@ static const char i40evf_copyright[] =
* { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
* Class, Class Mask, private data (not used) }
*/
-static const struct pci_device_id i40evf_pci_tbl[] = {
- {PCI_VDEVICE(INTEL, I40E_DEV_ID_VF), 0},
- {PCI_VDEVICE(INTEL, I40E_DEV_ID_VF_HV), 0},
- {PCI_VDEVICE(INTEL, I40E_DEV_ID_X722_VF), 0},
- {PCI_VDEVICE(INTEL, I40E_DEV_ID_ADAPTIVE_VF), 0},
+static const struct pci_device_id iavf_pci_tbl[] = {
+ {PCI_VDEVICE(INTEL, IAVF_DEV_ID_VF), 0},
+ {PCI_VDEVICE(INTEL, IAVF_DEV_ID_VF_HV), 0},
+ {PCI_VDEVICE(INTEL, IAVF_DEV_ID_X722_VF), 0},
+ {PCI_VDEVICE(INTEL, IAVF_DEV_ID_ADAPTIVE_VF), 0},
/* required last entry */
{0, }
};
-MODULE_DEVICE_TABLE(pci, i40evf_pci_tbl);
+MODULE_DEVICE_TABLE(pci, iavf_pci_tbl);
+MODULE_ALIAS("i40evf");
MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
-MODULE_DESCRIPTION("Intel(R) XL710 X710 Virtual Function Network Driver");
-MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Intel(R) Ethernet Adaptive Virtual Function Network Driver");
+MODULE_LICENSE("GPL v2");
MODULE_VERSION(DRV_VERSION);
-static struct workqueue_struct *i40evf_wq;
+static struct workqueue_struct *iavf_wq;
/**
- * i40evf_allocate_dma_mem_d - OS specific memory alloc for shared code
+ * iavf_allocate_dma_mem_d - OS specific memory alloc for shared code
* @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
**/
-i40e_status i40evf_allocate_dma_mem_d(struct i40e_hw *hw,
- struct i40e_dma_mem *mem,
- u64 size, u32 alignment)
+iavf_status iavf_allocate_dma_mem_d(struct iavf_hw *hw,
+ struct iavf_dma_mem *mem,
+ u64 size, u32 alignment)
{
- struct i40evf_adapter *adapter = (struct i40evf_adapter *)hw->back;
+ struct iavf_adapter *adapter = (struct iavf_adapter *)hw->back;
if (!mem)
return I40E_ERR_PARAM;
@@ -84,13 +85,13 @@ i40e_status i40evf_allocate_dma_mem_d(struct i40e_hw *hw,
}
/**
- * i40evf_free_dma_mem_d - OS specific memory free for shared code
+ * iavf_free_dma_mem_d - OS specific memory free for shared code
* @hw: pointer to the HW structure
* @mem: ptr to mem struct to free
**/
-i40e_status i40evf_free_dma_mem_d(struct i40e_hw *hw, struct i40e_dma_mem *mem)
+iavf_status iavf_free_dma_mem_d(struct iavf_hw *hw, struct iavf_dma_mem *mem)
{
- struct i40evf_adapter *adapter = (struct i40evf_adapter *)hw->back;
+ struct iavf_adapter *adapter = (struct iavf_adapter *)hw->back;
if (!mem || !mem->va)
return I40E_ERR_PARAM;
@@ -100,13 +101,13 @@ i40e_status i40evf_free_dma_mem_d(struct i40e_hw *hw, struct i40e_dma_mem *mem)
}
/**
- * i40evf_allocate_virt_mem_d - OS specific memory alloc for shared code
+ * iavf_allocate_virt_mem_d - OS specific memory alloc for shared code
* @hw: pointer to the HW structure
* @mem: ptr to mem struct to fill out
* @size: size of memory requested
**/
-i40e_status i40evf_allocate_virt_mem_d(struct i40e_hw *hw,
- struct i40e_virt_mem *mem, u32 size)
+iavf_status iavf_allocate_virt_mem_d(struct iavf_hw *hw,
+ struct iavf_virt_mem *mem, u32 size)
{
if (!mem)
return I40E_ERR_PARAM;
@@ -121,12 +122,11 @@ i40e_status i40evf_allocate_virt_mem_d(struct i40e_hw *hw,
}
/**
- * i40evf_free_virt_mem_d - OS specific memory free for shared code
+ * iavf_free_virt_mem_d - OS specific memory free for shared code
* @hw: pointer to the HW structure
* @mem: ptr to mem struct to free
**/
-i40e_status i40evf_free_virt_mem_d(struct i40e_hw *hw,
- struct i40e_virt_mem *mem)
+iavf_status iavf_free_virt_mem_d(struct iavf_hw *hw, struct iavf_virt_mem *mem)
{
if (!mem)
return I40E_ERR_PARAM;
@@ -138,17 +138,17 @@ i40e_status i40evf_free_virt_mem_d(struct i40e_hw *hw,
}
/**
- * i40evf_debug_d - OS dependent version of debug printing
+ * iavf_debug_d - OS dependent version of debug printing
* @hw: pointer to the HW structure
* @mask: debug level mask
* @fmt_str: printf-type format description
**/
-void i40evf_debug_d(void *hw, u32 mask, char *fmt_str, ...)
+void iavf_debug_d(void *hw, u32 mask, char *fmt_str, ...)
{
char buf[512];
va_list argptr;
- if (!(mask & ((struct i40e_hw *)hw)->debug_mask))
+ if (!(mask & ((struct iavf_hw *)hw)->debug_mask))
return;
va_start(argptr, fmt_str);
@@ -160,134 +160,131 @@ void i40evf_debug_d(void *hw, u32 mask, char *fmt_str, ...)
}
/**
- * i40evf_schedule_reset - Set the flags and schedule a reset event
+ * iavf_schedule_reset - Set the flags and schedule a reset event
* @adapter: board private structure
**/
-void i40evf_schedule_reset(struct i40evf_adapter *adapter)
+void iavf_schedule_reset(struct iavf_adapter *adapter)
{
if (!(adapter->flags &
- (I40EVF_FLAG_RESET_PENDING | I40EVF_FLAG_RESET_NEEDED))) {
- adapter->flags |= I40EVF_FLAG_RESET_NEEDED;
+ (IAVF_FLAG_RESET_PENDING | IAVF_FLAG_RESET_NEEDED))) {
+ adapter->flags |= IAVF_FLAG_RESET_NEEDED;
schedule_work(&adapter->reset_task);
}
}
/**
- * i40evf_tx_timeout - Respond to a Tx Hang
+ * iavf_tx_timeout - Respond to a Tx Hang
* @netdev: network interface device structure
**/
-static void i40evf_tx_timeout(struct net_device *netdev)
+static void iavf_tx_timeout(struct net_device *netdev)
{
- struct i40evf_adapter *adapter = netdev_priv(netdev);
+ struct iavf_adapter *adapter = netdev_priv(netdev);
adapter->tx_timeout_count++;
- i40evf_schedule_reset(adapter);
+ iavf_schedule_reset(adapter);
}
/**
- * i40evf_misc_irq_disable - Mask off interrupt generation on the NIC
+ * iavf_misc_irq_disable - Mask off interrupt generation on the NIC
* @adapter: board private structure
**/
-static void i40evf_misc_irq_disable(struct i40evf_adapter *adapter)
+static void iavf_misc_irq_disable(struct iavf_adapter *adapter)
{
- struct i40e_hw *hw = &adapter->hw;
+ struct iavf_hw *hw = &adapter->hw;
if (!adapter->msix_entries)
return;
- wr32(hw, I40E_VFINT_DYN_CTL01, 0);
+ wr32(hw, IAVF_VFINT_DYN_CTL01, 0);
- /* read flush */
- rd32(hw, I40E_VFGEN_RSTAT);
+ iavf_flush(hw);
synchronize_irq(adapter->msix_entries[0].vector);
}
/**
- * i40evf_misc_irq_enable - Enable default interrupt generation settings
+ * iavf_misc_irq_enable - Enable default interrupt generation settings
* @adapter: board private structure
**/
-static void i40evf_misc_irq_enable(struct i40evf_adapter *adapter)
+static void iavf_misc_irq_enable(struct iavf_adapter *adapter)
{
- struct i40e_hw *hw = &adapter->hw;
+ struct iavf_hw *hw = &adapter->hw;
- wr32(hw, I40E_VFINT_DYN_CTL01, I40E_VFINT_DYN_CTL01_INTENA_MASK |
- I40E_VFINT_DYN_CTL01_ITR_INDX_MASK);
- wr32(hw, I40E_VFINT_ICR0_ENA1, I40E_VFINT_ICR0_ENA1_ADMINQ_MASK);
+ wr32(hw, IAVF_VFINT_DYN_CTL01, IAVF_VFINT_DYN_CTL01_INTENA_MASK |
+ IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
+ wr32(hw, IAVF_VFINT_ICR0_ENA1, IAVF_VFINT_ICR0_ENA1_ADMINQ_MASK);
- /* read flush */
- rd32(hw, I40E_VFGEN_RSTAT);
+ iavf_flush(hw);
}
/**
- * i40evf_irq_disable - Mask off interrupt generation on the NIC
+ * iavf_irq_disable - Mask off interrupt generation on the NIC
* @adapter: board private structure
**/
-static void i40evf_irq_disable(struct i40evf_adapter *adapter)
+static void iavf_irq_disable(struct iavf_adapter *adapter)
{
int i;
- struct i40e_hw *hw = &adapter->hw;
+ struct iavf_hw *hw = &adapter->hw;
if (!adapter->msix_entries)
return;
for (i = 1; i < adapter->num_msix_vectors; i++) {
- wr32(hw, I40E_VFINT_DYN_CTLN1(i - 1), 0);
+ wr32(hw, IAVF_VFINT_DYN_CTLN1(i - 1), 0);
synchronize_irq(adapter->msix_entries[i].vector);
}
- /* read flush */
- rd32(hw, I40E_VFGEN_RSTAT);
+ iavf_flush(hw);
}
/**
- * i40evf_irq_enable_queues - Enable interrupt for specified queues
+ * iavf_irq_enable_queues - Enable interrupt for specified queues
* @adapter: board private structure
* @mask: bitmap of queues to enable
**/
-void i40evf_irq_enable_queues(struct i40evf_adapter *adapter, u32 mask)
+void iavf_irq_enable_queues(struct iavf_adapter *adapter, u32 mask)
{
- struct i40e_hw *hw = &adapter->hw;
+ struct iavf_hw *hw = &adapter->hw;
int i;
for (i = 1; i < adapter->num_msix_vectors; i++) {
if (mask & BIT(i - 1)) {
- wr32(hw, I40E_VFINT_DYN_CTLN1(i - 1),
- I40E_VFINT_DYN_CTLN1_INTENA_MASK |
- I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK);
+ wr32(hw, IAVF_VFINT_DYN_CTLN1(i - 1),
+ IAVF_VFINT_DYN_CTLN1_INTENA_MASK |
+ IAVF_VFINT_DYN_CTLN1_ITR_INDX_MASK);
}
}
}
/**
- * i40evf_irq_enable - Enable default interrupt generation settings
+ * iavf_irq_enable - Enable default interrupt generation settings
* @adapter: board private structure
* @flush: boolean value whether to run rd32()
**/
-void i40evf_irq_enable(struct i40evf_adapter *adapter, bool flush)
+void iavf_irq_enable(struct iavf_adapter *adapter, bool flush)
{
- struct i40e_hw *hw = &adapter->hw;
+ struct iavf_hw *hw = &adapter->hw;
- i40evf_misc_irq_enable(adapter);
- i40evf_irq_enable_queues(adapter, ~0);
+ iavf_misc_irq_enable(adapter);
+ iavf_irq_enable_queues(adapter, ~0);
if (flush)
- rd32(hw, I40E_VFGEN_RSTAT);
+ iavf_flush(hw);
}
/**
- * i40evf_msix_aq - Interrupt handler for vector 0
+ * iavf_msix_aq - Interrupt handler for vector 0
* @irq: interrupt number
* @data: pointer to netdev
**/
-static irqreturn_t i40evf_msix_aq(int irq, void *data)
+static irqreturn_t iavf_msix_aq(int irq, void *data)
{
struct net_device *netdev = data;
- struct i40evf_adapter *adapter = netdev_priv(netdev);
- struct i40e_hw *hw = &adapter->hw;
+ struct iavf_adapter *adapter = netdev_priv(netdev);
+ struct iavf_hw *hw = &adapter->hw;
/* handle non-queue interrupts, these reads clear the registers */
- rd32(hw, I40E_VFINT_ICR01);
- rd32(hw, I40E_VFINT_ICR0_ENA1);
+ rd32(hw, IAVF_VFINT_ICR01);
+ rd32(hw, IAVF_VFINT_ICR0_ENA1);
/* schedule work on the private workqueue */
schedule_work(&adapter->adminq_task);
@@ -296,13 +293,13 @@ static irqreturn_t i40evf_msix_aq(int irq, void *data)
}
/**
- * i40evf_msix_clean_rings - MSIX mode Interrupt Handler
+ * iavf_msix_clean_rings - MSIX mode Interrupt Handler
* @irq: interrupt number
* @data: pointer to a q_vector
**/
-static irqreturn_t i40evf_msix_clean_rings(int irq, void *data)
+static irqreturn_t iavf_msix_clean_rings(int irq, void *data)
{
- struct i40e_q_vector *q_vector = data;
+ struct iavf_q_vector *q_vector = data;
if (!q_vector->tx.ring && !q_vector->rx.ring)
return IRQ_HANDLED;
@@ -313,17 +310,17 @@ static irqreturn_t i40evf_msix_clean_rings(int irq, void *data)
}
/**
- * i40evf_map_vector_to_rxq - associate irqs with rx queues
+ * iavf_map_vector_to_rxq - associate irqs with rx queues
* @adapter: board private structure
* @v_idx: interrupt number
* @r_idx: queue number
**/
static void
-i40evf_map_vector_to_rxq(struct i40evf_adapter *adapter, int v_idx, int r_idx)
+iavf_map_vector_to_rxq(struct iavf_adapter *adapter, int v_idx, int r_idx)
{
- struct i40e_q_vector *q_vector = &adapter->q_vectors[v_idx];
- struct i40e_ring *rx_ring = &adapter->rx_rings[r_idx];
- struct i40e_hw *hw = &adapter->hw;
+ struct iavf_q_vector *q_vector = &adapter->q_vectors[v_idx];
+ struct iavf_ring *rx_ring = &adapter->rx_rings[r_idx];
+ struct iavf_hw *hw = &adapter->hw;
rx_ring->q_vector = q_vector;
rx_ring->next = q_vector->rx.ring;
@@ -333,23 +330,23 @@ i40evf_map_vector_to_rxq(struct i40evf_adapter *adapter, int v_idx, int r_idx)
q_vector->rx.next_update = jiffies + 1;
q_vector->rx.target_itr = ITR_TO_REG(rx_ring->itr_setting);
q_vector->ring_mask |= BIT(r_idx);
- wr32(hw, I40E_VFINT_ITRN1(I40E_RX_ITR, q_vector->reg_idx),
+ wr32(hw, IAVF_VFINT_ITRN1(IAVF_RX_ITR, q_vector->reg_idx),
q_vector->rx.current_itr);
q_vector->rx.current_itr = q_vector->rx.target_itr;
}
/**
- * i40evf_map_vector_to_txq - associate irqs with tx queues
+ * iavf_map_vector_to_txq - associate irqs with tx queues
* @adapter: board private structure
* @v_idx: interrupt number
* @t_idx: queue number
**/
static void
-i40evf_map_vector_to_txq(struct i40evf_adapter *adapter, int v_idx, int t_idx)
+iavf_map_vector_to_txq(struct iavf_adapter *adapter, int v_idx, int t_idx)
{
- struct i40e_q_vector *q_vector = &adapter->q_vectors[v_idx];
- struct i40e_ring *tx_ring = &adapter->tx_rings[t_idx];
- struct i40e_hw *hw = &adapter->hw;
+ struct iavf_q_vector *q_vector = &adapter->q_vectors[v_idx];
+ struct iavf_ring *tx_ring = &adapter->tx_rings[t_idx];
+ struct iavf_hw *hw = &adapter->hw;
tx_ring->q_vector = q_vector;
tx_ring->next = q_vector->tx.ring;
@@ -359,13 +356,13 @@ i40evf_map_vector_to_txq(struct i40evf_adapter *adapter, int v_idx, int t_idx)
q_vector->tx.next_update = jiffies + 1;
q_vector->tx.target_itr = ITR_TO_REG(tx_ring->itr_setting);
q_vector->num_ringpairs++;
- wr32(hw, I40E_VFINT_ITRN1(I40E_TX_ITR, q_vector->reg_idx),
+ wr32(hw, IAVF_VFINT_ITRN1(IAVF_TX_ITR, q_vector->reg_idx),
q_vector->tx.target_itr);
q_vector->tx.current_itr = q_vector->tx.target_itr;
}
/**
- * i40evf_map_rings_to_vectors - Maps descriptor rings to vectors
+ * iavf_map_rings_to_vectors - Maps descriptor rings to vectors
* @adapter: board private structure to initialize
*
* This function maps descriptor rings to the queue-specific vectors
@@ -374,7 +371,7 @@ i40evf_map_vector_to_txq(struct i40evf_adapter *adapter, int v_idx, int t_idx)
* group the rings as "efficiently" as possible. You would add new
* mapping configurations in here.
**/
-static void i40evf_map_rings_to_vectors(struct i40evf_adapter *adapter)
+static void iavf_map_rings_to_vectors(struct iavf_adapter *adapter)
{
int rings_remaining = adapter->num_active_queues;
int ridx = 0, vidx = 0;
@@ -383,8 +380,8 @@ static void i40evf_map_rings_to_vectors(struct i40evf_adapter *adapter)
q_vectors = adapter->num_msix_vectors - NONQ_VECS;
for (; ridx < rings_remaining; ridx++) {
- i40evf_map_vector_to_rxq(adapter, vidx, ridx);
- i40evf_map_vector_to_txq(adapter, vidx, ridx);
+ iavf_map_vector_to_rxq(adapter, vidx, ridx);
+ iavf_map_vector_to_txq(adapter, vidx, ridx);
/* In the case where we have more queues than vectors, continue
* round-robin on vectors until all queues are mapped.
@@ -393,38 +390,38 @@ static void i40evf_map_rings_to_vectors(struct i40evf_adapter *adapter)
vidx = 0;
}
- adapter->aq_required |= I40EVF_FLAG_AQ_MAP_VECTORS;
+ adapter->aq_required |= IAVF_FLAG_AQ_MAP_VECTORS;
}
/**
- * i40evf_irq_affinity_notify - Callback for affinity changes
+ * iavf_irq_affinity_notify - Callback for affinity changes
* @notify: context as to what irq was changed
* @mask: the new affinity mask
*
* This is a callback function used by the irq_set_affinity_notifier function
* so that we may register to receive changes to the irq affinity masks.
**/
-static void i40evf_irq_affinity_notify(struct irq_affinity_notify *notify,
- const cpumask_t *mask)
+static void iavf_irq_affinity_notify(struct irq_affinity_notify *notify,
+ const cpumask_t *mask)
{
- struct i40e_q_vector *q_vector =
- container_of(notify, struct i40e_q_vector, affinity_notify);
+ struct iavf_q_vector *q_vector =
+ container_of(notify, struct iavf_q_vector, affinity_notify);
cpumask_copy(&q_vector->affinity_mask, mask);
}
/**
- * i40evf_irq_affinity_release - Callback for affinity notifier release
+ * iavf_irq_affinity_release - Callback for affinity notifier release
* @ref: internal core kernel usage
*
* This is a callback function used by the irq_set_affinity_notifier function
* to inform the current notification subscriber that they will no longer
* receive notifications.
**/
-static void i40evf_irq_affinity_release(struct kref *ref) {}
+static void iavf_irq_affinity_release(struct kref *ref) {}
/**
- * i40evf_request_traffic_irqs - Initialize MSI-X interrupts
+ * iavf_request_traffic_irqs - Initialize MSI-X interrupts
* @adapter: board private structure
* @basename: device basename
*
@@ -432,37 +429,38 @@ static void i40evf_irq_affinity_release(struct kref *ref) {}
* interrupts from the kernel.
**/
static int
-i40evf_request_traffic_irqs(struct i40evf_adapter *adapter, char *basename)
+iavf_request_traffic_irqs(struct iavf_adapter *adapter, char *basename)
{
unsigned int vector, q_vectors;
unsigned int rx_int_idx = 0, tx_int_idx = 0;
int irq_num, err;
int cpu;
- i40evf_irq_disable(adapter);
+ iavf_irq_disable(adapter);
/* Decrement for Other and TCP Timer vectors */
q_vectors = adapter->num_msix_vectors - NONQ_VECS;
for (vector = 0; vector < q_vectors; vector++) {
- struct i40e_q_vector *q_vector = &adapter->q_vectors[vector];
+ struct iavf_q_vector *q_vector = &adapter->q_vectors[vector];
+
irq_num = adapter->msix_entries[vector + NONQ_VECS].vector;
if (q_vector->tx.ring && q_vector->rx.ring) {
snprintf(q_vector->name, sizeof(q_vector->name),
- "i40evf-%s-TxRx-%d", basename, rx_int_idx++);
+ "iavf-%s-TxRx-%d", basename, rx_int_idx++);
tx_int_idx++;
} else if (q_vector->rx.ring) {
snprintf(q_vector->name, sizeof(q_vector->name),
- "i40evf-%s-rx-%d", basename, rx_int_idx++);
+ "iavf-%s-rx-%d", basename, rx_int_idx++);
} else if (q_vector->tx.ring) {
snprintf(q_vector->name, sizeof(q_vector->name),
- "i40evf-%s-tx-%d", basename, tx_int_idx++);
+ "iavf-%s-tx-%d", basename, tx_int_idx++);
} else {
/* skip this unused q_vector */
continue;
}
err = request_irq(irq_num,
- i40evf_msix_clean_rings,
+ iavf_msix_clean_rings,
0,
q_vector->name,
q_vector);
@@ -472,9 +470,9 @@ i40evf_request_traffic_irqs(struct i40evf_adapter *adapter, char *basename)
goto free_queue_irqs;
}
/* register for affinity change notifications */
- q_vector->affinity_notify.notify = i40evf_irq_affinity_notify;
+ q_vector->affinity_notify.notify = iavf_irq_affinity_notify;
q_vector->affinity_notify.release =
- i40evf_irq_affinity_release;
+ iavf_irq_affinity_release;
irq_set_affinity_notifier(irq_num, &q_vector->affinity_notify);
/* Spread the IRQ affinity hints across online CPUs. Note that
* get_cpu_mask returns a mask with a permanent lifetime so
@@ -498,23 +496,23 @@ free_queue_irqs:
}
/**
- * i40evf_request_misc_irq - Initialize MSI-X interrupts
+ * iavf_request_misc_irq - Initialize MSI-X interrupts
* @adapter: board private structure
*
* Allocates MSI-X vector 0 and requests interrupts from the kernel. This
* vector is only for the admin queue, and stays active even when the netdev
* is closed.
**/
-static int i40evf_request_misc_irq(struct i40evf_adapter *adapter)
+static int iavf_request_misc_irq(struct iavf_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
int err;
snprintf(adapter->misc_vector_name,
- sizeof(adapter->misc_vector_name) - 1, "i40evf-%s:mbx",
+ sizeof(adapter->misc_vector_name) - 1, "iavf-%s:mbx",
dev_name(&adapter->pdev->dev));
err = request_irq(adapter->msix_entries[0].vector,
- &i40evf_msix_aq, 0,
+ &iavf_msix_aq, 0,
adapter->misc_vector_name, netdev);
if (err) {
dev_err(&adapter->pdev->dev,
@@ -526,12 +524,12 @@ static int i40evf_request_misc_irq(struct i40evf_adapter *adapter)
}
/**
- * i40evf_free_traffic_irqs - Free MSI-X interrupts
+ * iavf_free_traffic_irqs - Free MSI-X interrupts
* @adapter: board private structure
*
* Frees all MSI-X vectors other than 0.
**/
-static void i40evf_free_traffic_irqs(struct i40evf_adapter *adapter)
+static void iavf_free_traffic_irqs(struct iavf_adapter *adapter)
{
int vector, irq_num, q_vectors;
@@ -549,12 +547,12 @@ static void i40evf_free_traffic_irqs(struct i40evf_adapter *adapter)
}
/**
- * i40evf_free_misc_irq - Free MSI-X miscellaneous vector
+ * iavf_free_misc_irq - Free MSI-X miscellaneous vector
* @adapter: board private structure
*
* Frees MSI-X vector 0.
**/
-static void i40evf_free_misc_irq(struct i40evf_adapter *adapter)
+static void iavf_free_misc_irq(struct iavf_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
@@ -565,58 +563,58 @@ static void i40evf_free_misc_irq(struct i40evf_adapter *adapter)
}
/**
- * i40evf_configure_tx - Configure Transmit Unit after Reset
+ * iavf_configure_tx - Configure Transmit Unit after Reset
* @adapter: board private structure
*
* Configure the Tx unit of the MAC after a reset.
**/
-static void i40evf_configure_tx(struct i40evf_adapter *adapter)
+static void iavf_configure_tx(struct iavf_adapter *adapter)
{
- struct i40e_hw *hw = &adapter->hw;
+ struct iavf_hw *hw = &adapter->hw;
int i;
for (i = 0; i < adapter->num_active_queues; i++)
- adapter->tx_rings[i].tail = hw->hw_addr + I40E_QTX_TAIL1(i);
+ adapter->tx_rings[i].tail = hw->hw_addr + IAVF_QTX_TAIL1(i);
}
/**
- * i40evf_configure_rx - Configure Receive Unit after Reset
+ * iavf_configure_rx - Configure Receive Unit after Reset
* @adapter: board private structure
*
* Configure the Rx unit of the MAC after a reset.
**/
-static void i40evf_configure_rx(struct i40evf_adapter *adapter)
+static void iavf_configure_rx(struct iavf_adapter *adapter)
{
- unsigned int rx_buf_len = I40E_RXBUFFER_2048;
- struct i40e_hw *hw = &adapter->hw;
+ unsigned int rx_buf_len = IAVF_RXBUFFER_2048;
+ struct iavf_hw *hw = &adapter->hw;
int i;
/* Legacy Rx will always default to a 2048 buffer size. */
#if (PAGE_SIZE < 8192)
- if (!(adapter->flags & I40EVF_FLAG_LEGACY_RX)) {
+ if (!(adapter->flags & IAVF_FLAG_LEGACY_RX)) {
struct net_device *netdev = adapter->netdev;
/* For jumbo frames on systems with 4K pages we have to use
* an order 1 page, so we might as well increase the size
* of our Rx buffer to make better use of the available space
*/
- rx_buf_len = I40E_RXBUFFER_3072;
+ rx_buf_len = IAVF_RXBUFFER_3072;
/* We use a 1536 buffer size for configurations with
* standard Ethernet mtu. On x86 this gives us enough room
* for shared info and 192 bytes of padding.
*/
- if (!I40E_2K_TOO_SMALL_WITH_PADDING &&
+ if (!IAVF_2K_TOO_SMALL_WITH_PADDING &&
(netdev->mtu <= ETH_DATA_LEN))
- rx_buf_len = I40E_RXBUFFER_1536 - NET_IP_ALIGN;
+ rx_buf_len = IAVF_RXBUFFER_1536 - NET_IP_ALIGN;
}
#endif
for (i = 0; i < adapter->num_active_queues; i++) {
- adapter->rx_rings[i].tail = hw->hw_addr + I40E_QRX_TAIL1(i);
+ adapter->rx_rings[i].tail = hw->hw_addr + IAVF_QRX_TAIL1(i);
adapter->rx_rings[i].rx_buf_len = rx_buf_len;
- if (adapter->flags & I40EVF_FLAG_LEGACY_RX)
+ if (adapter->flags & IAVF_FLAG_LEGACY_RX)
clear_ring_build_skb_enabled(&adapter->rx_rings[i]);
else
set_ring_build_skb_enabled(&adapter->rx_rings[i]);
@@ -624,7 +622,7 @@ static void i40evf_configure_rx(struct i40evf_adapter *adapter)
}
/**
- * i40evf_find_vlan - Search filter list for specific vlan filter
+ * iavf_find_vlan - Search filter list for specific vlan filter
* @adapter: board private structure
* @vlan: vlan tag
*
@@ -632,9 +630,9 @@ static void i40evf_configure_rx(struct i40evf_adapter *adapter)
* mac_vlan_list_lock.
**/
static struct
-i40evf_vlan_filter *i40evf_find_vlan(struct i40evf_adapter *adapter, u16 vlan)
+iavf_vlan_filter *iavf_find_vlan(struct iavf_adapter *adapter, u16 vlan)
{
- struct i40evf_vlan_filter *f;
+ struct iavf_vlan_filter *f;
list_for_each_entry(f, &adapter->vlan_filter_list, list) {
if (vlan == f->vlan)
@@ -644,20 +642,20 @@ i40evf_vlan_filter *i40evf_find_vlan(struct i40evf_adapter *adapter, u16 vlan)
}
/**
- * i40evf_add_vlan - Add a vlan filter to the list
+ * iavf_add_vlan - Add a vlan filter to the list
* @adapter: board private structure
* @vlan: VLAN tag
*
* Returns ptr to the filter object or NULL when no memory available.
**/
static struct
-i40evf_vlan_filter *i40evf_add_vlan(struct i40evf_adapter *adapter, u16 vlan)
+iavf_vlan_filter *iavf_add_vlan(struct iavf_adapter *adapter, u16 vlan)
{
- struct i40evf_vlan_filter *f = NULL;
+ struct iavf_vlan_filter *f = NULL;
spin_lock_bh(&adapter->mac_vlan_list_lock);
- f = i40evf_find_vlan(adapter, vlan);
+ f = iavf_find_vlan(adapter, vlan);
if (!f) {
f = kzalloc(sizeof(*f), GFP_KERNEL);
if (!f)
@@ -668,7 +666,7 @@ i40evf_vlan_filter *i40evf_add_vlan(struct i40evf_adapter *adapter, u16 vlan)
INIT_LIST_HEAD(&f->list);
list_add(&f->list, &adapter->vlan_filter_list);
f->add = true;
- adapter->aq_required |= I40EVF_FLAG_AQ_ADD_VLAN_FILTER;
+ adapter->aq_required |= IAVF_FLAG_AQ_ADD_VLAN_FILTER;
}
clearout:
@@ -677,63 +675,63 @@ clearout:
}
/**
- * i40evf_del_vlan - Remove a vlan filter from the list
+ * iavf_del_vlan - Remove a vlan filter from the list
* @adapter: board private structure
* @vlan: VLAN tag
**/
-static void i40evf_del_vlan(struct i40evf_adapter *adapter, u16 vlan)
+static void iavf_del_vlan(struct iavf_adapter *adapter, u16 vlan)
{
- struct i40evf_vlan_filter *f;
+ struct iavf_vlan_filter *f;
spin_lock_bh(&adapter->mac_vlan_list_lock);
- f = i40evf_find_vlan(adapter, vlan);
+ f = iavf_find_vlan(adapter, vlan);
if (f) {
f->remove = true;
- adapter->aq_required |= I40EVF_FLAG_AQ_DEL_VLAN_FILTER;
+ adapter->aq_required |= IAVF_FLAG_AQ_DEL_VLAN_FILTER;
}
spin_unlock_bh(&adapter->mac_vlan_list_lock);
}
/**
- * i40evf_vlan_rx_add_vid - Add a VLAN filter to a device
+ * iavf_vlan_rx_add_vid - Add a VLAN filter to a device
* @netdev: network device struct
* @proto: unused protocol data
* @vid: VLAN tag
**/
-static int i40evf_vlan_rx_add_vid(struct net_device *netdev,
- __always_unused __be16 proto, u16 vid)
+static int iavf_vlan_rx_add_vid(struct net_device *netdev,
+ __always_unused __be16 proto, u16 vid)
{
- struct i40evf_adapter *adapter = netdev_priv(netdev);
+ struct iavf_adapter *adapter = netdev_priv(netdev);
if (!VLAN_ALLOWED(adapter))
return -EIO;
- if (i40evf_add_vlan(adapter, vid) == NULL)
+ if (iavf_add_vlan(adapter, vid) == NULL)
return -ENOMEM;
return 0;
}
/**
- * i40evf_vlan_rx_kill_vid - Remove a VLAN filter from a device
+ * iavf_vlan_rx_kill_vid - Remove a VLAN filter from a device
* @netdev: network device struct
* @proto: unused protocol data
* @vid: VLAN tag
**/
-static int i40evf_vlan_rx_kill_vid(struct net_device *netdev,
- __always_unused __be16 proto, u16 vid)
+static int iavf_vlan_rx_kill_vid(struct net_device *netdev,
+ __always_unused __be16 proto, u16 vid)
{
- struct i40evf_adapter *adapter = netdev_priv(netdev);
+ struct iavf_adapter *adapter = netdev_priv(netdev);
if (VLAN_ALLOWED(adapter)) {
- i40evf_del_vlan(adapter, vid);
+ iavf_del_vlan(adapter, vid);
return 0;
}
return -EIO;
}
/**
- * i40evf_find_filter - Search filter list for specific mac filter
+ * iavf_find_filter - Search filter list for specific mac filter
* @adapter: board private structure
* @macaddr: the MAC address
*
@@ -741,10 +739,10 @@ static int i40evf_vlan_rx_kill_vid(struct net_device *netdev,
* mac_vlan_list_lock.
**/
static struct
-i40evf_mac_filter *i40evf_find_filter(struct i40evf_adapter *adapter,
- const u8 *macaddr)
+iavf_mac_filter *iavf_find_filter(struct iavf_adapter *adapter,
+ const u8 *macaddr)
{
- struct i40evf_mac_filter *f;
+ struct iavf_mac_filter *f;
if (!macaddr)
return NULL;
@@ -757,22 +755,22 @@ i40evf_mac_filter *i40evf_find_filter(struct i40evf_adapter *adapter,
}
/**
- * i40e_add_filter - Add a mac filter to the filter list
+ * iavf_add_filter - Add a mac filter to the filter list
* @adapter: board private structure
* @macaddr: the MAC address
*
* Returns ptr to the filter object or NULL when no memory available.
**/
static struct
-i40evf_mac_filter *i40evf_add_filter(struct i40evf_adapter *adapter,
- const u8 *macaddr)
+iavf_mac_filter *iavf_add_filter(struct iavf_adapter *adapter,
+ const u8 *macaddr)
{
- struct i40evf_mac_filter *f;
+ struct iavf_mac_filter *f;
if (!macaddr)
return NULL;
- f = i40evf_find_filter(adapter, macaddr);
+ f = iavf_find_filter(adapter, macaddr);
if (!f) {
f = kzalloc(sizeof(*f), GFP_ATOMIC);
if (!f)
@@ -782,7 +780,7 @@ i40evf_mac_filter *i40evf_add_filter(struct i40evf_adapter *adapter,
list_add_tail(&f->list, &adapter->mac_filter_list);
f->add = true;
- adapter->aq_required |= I40EVF_FLAG_AQ_ADD_MAC_FILTER;
+ adapter->aq_required |= IAVF_FLAG_AQ_ADD_MAC_FILTER;
} else {
f->remove = false;
}
@@ -791,17 +789,17 @@ i40evf_mac_filter *i40evf_add_filter(struct i40evf_adapter *adapter,
}
/**
- * i40evf_set_mac - NDO callback to set port mac address
+ * iavf_set_mac - NDO callback to set port mac address
* @netdev: network interface device structure
* @p: pointer to an address structure
*
* Returns 0 on success, negative on failure
**/
-static int i40evf_set_mac(struct net_device *netdev, void *p)
+static int iavf_set_mac(struct net_device *netdev, void *p)
{
- struct i40evf_adapter *adapter = netdev_priv(netdev);
- struct i40e_hw *hw = &adapter->hw;
- struct i40evf_mac_filter *f;
+ struct iavf_adapter *adapter = netdev_priv(netdev);
+ struct iavf_hw *hw = &adapter->hw;
+ struct iavf_mac_filter *f;
struct sockaddr *addr = p;
if (!is_valid_ether_addr(addr->sa_data))
@@ -810,18 +808,18 @@ static int i40evf_set_mac(struct net_device *netdev, void *p)
if (ether_addr_equal(netdev->dev_addr, addr->sa_data))
return 0;
- if (adapter->flags & I40EVF_FLAG_ADDR_SET_BY_PF)
+ if (adapter->flags & IAVF_FLAG_ADDR_SET_BY_PF)
return -EPERM;
spin_lock_bh(&adapter->mac_vlan_list_lock);
- f = i40evf_find_filter(adapter, hw->mac.addr);
+ f = iavf_find_filter(adapter, hw->mac.addr);
if (f) {
f->remove = true;
- adapter->aq_required |= I40EVF_FLAG_AQ_DEL_MAC_FILTER;
+ adapter->aq_required |= IAVF_FLAG_AQ_DEL_MAC_FILTER;
}
- f = i40evf_add_filter(adapter, addr->sa_data);
+ f = iavf_add_filter(adapter, addr->sa_data);
spin_unlock_bh(&adapter->mac_vlan_list_lock);
@@ -834,35 +832,35 @@ static int i40evf_set_mac(struct net_device *netdev, void *p)
}
/**
- * i40evf_addr_sync - Callback for dev_(mc|uc)_sync to add address
+ * iavf_addr_sync - Callback for dev_(mc|uc)_sync to add address
* @netdev: the netdevice
* @addr: address to add
*
* Called by __dev_(mc|uc)_sync when an address needs to be added. We call
* __dev_(uc|mc)_sync from .set_rx_mode and guarantee to hold the hash lock.
*/
-static int i40evf_addr_sync(struct net_device *netdev, const u8 *addr)
+static int iavf_addr_sync(struct net_device *netdev, const u8 *addr)
{
- struct i40evf_adapter *adapter = netdev_priv(netdev);
+ struct iavf_adapter *adapter = netdev_priv(netdev);
- if (i40evf_add_filter(adapter, addr))
+ if (iavf_add_filter(adapter, addr))
return 0;
else
return -ENOMEM;
}
/**
- * i40evf_addr_unsync - Callback for dev_(mc|uc)_sync to remove address
+ * iavf_addr_unsync - Callback for dev_(mc|uc)_sync to remove address
* @netdev: the netdevice
* @addr: address to add
*
* Called by __dev_(mc|uc)_sync when an address needs to be removed. We call
* __dev_(uc|mc)_sync from .set_rx_mode and guarantee to hold the hash lock.
*/
-static int i40evf_addr_unsync(struct net_device *netdev, const u8 *addr)
+static int iavf_addr_unsync(struct net_device *netdev, const u8 *addr)
{
- struct i40evf_adapter *adapter = netdev_priv(netdev);
- struct i40evf_mac_filter *f;
+ struct iavf_adapter *adapter = netdev_priv(netdev);
+ struct iavf_mac_filter *f;
/* Under some circumstances, we might receive a request to delete
* our own device address from our uc list. Because we store the
@@ -872,50 +870,50 @@ static int i40evf_addr_unsync(struct net_device *netdev, const u8 *addr)
if (ether_addr_equal(addr, netdev->dev_addr))
return 0;
- f = i40evf_find_filter(adapter, addr);
+ f = iavf_find_filter(adapter, addr);
if (f) {
f->remove = true;
- adapter->aq_required |= I40EVF_FLAG_AQ_DEL_MAC_FILTER;
+ adapter->aq_required |= IAVF_FLAG_AQ_DEL_MAC_FILTER;
}
return 0;
}
/**
- * i40evf_set_rx_mode - NDO callback to set the netdev filters
+ * iavf_set_rx_mode - NDO callback to set the netdev filters
* @netdev: network interface device structure
**/
-static void i40evf_set_rx_mode(struct net_device *netdev)
+static void iavf_set_rx_mode(struct net_device *netdev)
{
- struct i40evf_adapter *adapter = netdev_priv(netdev);
+ struct iavf_adapter *adapter = netdev_priv(netdev);
spin_lock_bh(&adapter->mac_vlan_list_lock);
- __dev_uc_sync(netdev, i40evf_addr_sync, i40evf_addr_unsync);
- __dev_mc_sync(netdev, i40evf_addr_sync, i40evf_addr_unsync);
+ __dev_uc_sync(netdev, iavf_addr_sync, iavf_addr_unsync);
+ __dev_mc_sync(netdev, iavf_addr_sync, iavf_addr_unsync);
spin_unlock_bh(&adapter->mac_vlan_list_lock);
if (netdev->flags & IFF_PROMISC &&
- !(adapter->flags & I40EVF_FLAG_PROMISC_ON))
- adapter->aq_required |= I40EVF_FLAG_AQ_REQUEST_PROMISC;
+ !(adapter->flags & IAVF_FLAG_PROMISC_ON))
+ adapter->aq_required |= IAVF_FLAG_AQ_REQUEST_PROMISC;
else if (!(netdev->flags & IFF_PROMISC) &&
- adapter->flags & I40EVF_FLAG_PROMISC_ON)
- adapter->aq_required |= I40EVF_FLAG_AQ_RELEASE_PROMISC;
+ adapter->flags & IAVF_FLAG_PROMISC_ON)
+ adapter->aq_required |= IAVF_FLAG_AQ_RELEASE_PROMISC;
if (netdev->flags & IFF_ALLMULTI &&
- !(adapter->flags & I40EVF_FLAG_ALLMULTI_ON))
- adapter->aq_required |= I40EVF_FLAG_AQ_REQUEST_ALLMULTI;
+ !(adapter->flags & IAVF_FLAG_ALLMULTI_ON))
+ adapter->aq_required |= IAVF_FLAG_AQ_REQUEST_ALLMULTI;
else if (!(netdev->flags & IFF_ALLMULTI) &&
- adapter->flags & I40EVF_FLAG_ALLMULTI_ON)
- adapter->aq_required |= I40EVF_FLAG_AQ_RELEASE_ALLMULTI;
+ adapter->flags & IAVF_FLAG_ALLMULTI_ON)
+ adapter->aq_required |= IAVF_FLAG_AQ_RELEASE_ALLMULTI;
}
/**
- * i40evf_napi_enable_all - enable NAPI on all queue vectors
+ * iavf_napi_enable_all - enable NAPI on all queue vectors
* @adapter: board private structure
**/
-static void i40evf_napi_enable_all(struct i40evf_adapter *adapter)
+static void iavf_napi_enable_all(struct iavf_adapter *adapter)
{
int q_idx;
- struct i40e_q_vector *q_vector;
+ struct iavf_q_vector *q_vector;
int q_vectors = adapter->num_msix_vectors - NONQ_VECS;
for (q_idx = 0; q_idx < q_vectors; q_idx++) {
@@ -928,13 +926,13 @@ static void i40evf_napi_enable_all(struct i40evf_adapter *adapter)
}
/**
- * i40evf_napi_disable_all - disable NAPI on all queue vectors
+ * iavf_napi_disable_all - disable NAPI on all queue vectors
* @adapter: board private structure
**/
-static void i40evf_napi_disable_all(struct i40evf_adapter *adapter)
+static void iavf_napi_disable_all(struct iavf_adapter *adapter)
{
int q_idx;
- struct i40e_q_vector *q_vector;
+ struct iavf_q_vector *q_vector;
int q_vectors = adapter->num_msix_vectors - NONQ_VECS;
for (q_idx = 0; q_idx < q_vectors; q_idx++) {
@@ -944,67 +942,67 @@ static void i40evf_napi_disable_all(struct i40evf_adapter *adapter)
}
/**
- * i40evf_configure - set up transmit and receive data structures
+ * iavf_configure - set up transmit and receive data structures
* @adapter: board private structure
**/
-static void i40evf_configure(struct i40evf_adapter *adapter)
+static void iavf_configure(struct iavf_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
int i;
- i40evf_set_rx_mode(netdev);
+ iavf_set_rx_mode(netdev);
- i40evf_configure_tx(adapter);
- i40evf_configure_rx(adapter);
- adapter->aq_required |= I40EVF_FLAG_AQ_CONFIGURE_QUEUES;
+ iavf_configure_tx(adapter);
+ iavf_configure_rx(adapter);
+ adapter->aq_required |= IAVF_FLAG_AQ_CONFIGURE_QUEUES;
for (i = 0; i < adapter->num_active_queues; i++) {
- struct i40e_ring *ring = &adapter->rx_rings[i];
+ struct iavf_ring *ring = &adapter->rx_rings[i];
- i40evf_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
+ iavf_alloc_rx_buffers(ring, IAVF_DESC_UNUSED(ring));
}
}
/**
- * i40evf_up_complete - Finish the last steps of bringing up a connection
+ * iavf_up_complete - Finish the last steps of bringing up a connection
* @adapter: board private structure
*
- * Expects to be called while holding the __I40EVF_IN_CRITICAL_TASK bit lock.
+ * Expects to be called while holding the __IAVF_IN_CRITICAL_TASK bit lock.
**/
-static void i40evf_up_complete(struct i40evf_adapter *adapter)
+static void iavf_up_complete(struct iavf_adapter *adapter)
{
- adapter->state = __I40EVF_RUNNING;
- clear_bit(__I40E_VSI_DOWN, adapter->vsi.state);
+ adapter->state = __IAVF_RUNNING;
+ clear_bit(__IAVF_VSI_DOWN, adapter->vsi.state);
- i40evf_napi_enable_all(adapter);
+ iavf_napi_enable_all(adapter);
- adapter->aq_required |= I40EVF_FLAG_AQ_ENABLE_QUEUES;
+ adapter->aq_required |= IAVF_FLAG_AQ_ENABLE_QUEUES;
if (CLIENT_ENABLED(adapter))
- adapter->flags |= I40EVF_FLAG_CLIENT_NEEDS_OPEN;
+ adapter->flags |= IAVF_FLAG_CLIENT_NEEDS_OPEN;
mod_timer_pending(&adapter->watchdog_timer, jiffies + 1);
}
/**
- * i40e_down - Shutdown the connection processing
+ * iavf_down - Shutdown the connection processing
* @adapter: board private structure
*
- * Expects to be called while holding the __I40EVF_IN_CRITICAL_TASK bit lock.
+ * Expects to be called while holding the __IAVF_IN_CRITICAL_TASK bit lock.
**/
-void i40evf_down(struct i40evf_adapter *adapter)
+void iavf_down(struct iavf_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
- struct i40evf_vlan_filter *vlf;
- struct i40evf_mac_filter *f;
- struct i40evf_cloud_filter *cf;
+ struct iavf_vlan_filter *vlf;
+ struct iavf_mac_filter *f;
+ struct iavf_cloud_filter *cf;
- if (adapter->state <= __I40EVF_DOWN_PENDING)
+ if (adapter->state <= __IAVF_DOWN_PENDING)
return;
netif_carrier_off(netdev);
netif_tx_disable(netdev);
adapter->link_up = false;
- i40evf_napi_disable_all(adapter);
- i40evf_irq_disable(adapter);
+ iavf_napi_disable_all(adapter);
+ iavf_irq_disable(adapter);
spin_lock_bh(&adapter->mac_vlan_list_lock);
@@ -1031,25 +1029,25 @@ void i40evf_down(struct i40evf_adapter *adapter)
}
spin_unlock_bh(&adapter->cloud_filter_list_lock);
- if (!(adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) &&
- adapter->state != __I40EVF_RESETTING) {
+ if (!(adapter->flags & IAVF_FLAG_PF_COMMS_FAILED) &&
+ adapter->state != __IAVF_RESETTING) {
/* cancel any current operation */
adapter->current_op = VIRTCHNL_OP_UNKNOWN;
/* Schedule operations to close down the HW. Don't wait
* here for this to complete. The watchdog is still running
* and it will take care of this.
*/
- adapter->aq_required = I40EVF_FLAG_AQ_DEL_MAC_FILTER;
- adapter->aq_required |= I40EVF_FLAG_AQ_DEL_VLAN_FILTER;
- adapter->aq_required |= I40EVF_FLAG_AQ_DEL_CLOUD_FILTER;
- adapter->aq_required |= I40EVF_FLAG_AQ_DISABLE_QUEUES;
+ adapter->aq_required = IAVF_FLAG_AQ_DEL_MAC_FILTER;
+ adapter->aq_required |= IAVF_FLAG_AQ_DEL_VLAN_FILTER;
+ adapter->aq_required |= IAVF_FLAG_AQ_DEL_CLOUD_FILTER;
+ adapter->aq_required |= IAVF_FLAG_AQ_DISABLE_QUEUES;
}
mod_timer_pending(&adapter->watchdog_timer, jiffies + 1);
}
/**
- * i40evf_acquire_msix_vectors - Setup the MSIX capability
+ * iavf_acquire_msix_vectors - Setup the MSIX capability
* @adapter: board private structure
* @vectors: number of vectors to request
*
@@ -1058,7 +1056,7 @@ void i40evf_down(struct i40evf_adapter *adapter)
* Returns 0 on success, negative on failure
**/
static int
-i40evf_acquire_msix_vectors(struct i40evf_adapter *adapter, int vectors)
+iavf_acquire_msix_vectors(struct iavf_adapter *adapter, int vectors)
{
int err, vector_threshold;
@@ -1092,12 +1090,12 @@ i40evf_acquire_msix_vectors(struct i40evf_adapter *adapter, int vectors)
}
/**
- * i40evf_free_queues - Free memory for all rings
+ * iavf_free_queues - Free memory for all rings
* @adapter: board private structure to initialize
*
* Free all of the memory associated with queue pairs.
**/
-static void i40evf_free_queues(struct i40evf_adapter *adapter)
+static void iavf_free_queues(struct iavf_adapter *adapter)
{
if (!adapter->vsi_res)
return;
@@ -1109,14 +1107,14 @@ static void i40evf_free_queues(struct i40evf_adapter *adapter)
}
/**
- * i40evf_alloc_queues - Allocate memory for all rings
+ * iavf_alloc_queues - Allocate memory for all rings
* @adapter: board private structure to initialize
*
* We allocate one ring per queue at run-time since we don't know the
* number of queues at compile-time. The polling_netdev array is
* intended for Multiqueue, but should work fine with a single queue.
**/
-static int i40evf_alloc_queues(struct i40evf_adapter *adapter)
+static int iavf_alloc_queues(struct iavf_adapter *adapter)
{
int i, num_active_queues;
@@ -1137,17 +1135,17 @@ static int i40evf_alloc_queues(struct i40evf_adapter *adapter)
adapter->tx_rings = kcalloc(num_active_queues,
- sizeof(struct i40e_ring), GFP_KERNEL);
+ sizeof(struct iavf_ring), GFP_KERNEL);
if (!adapter->tx_rings)
goto err_out;
adapter->rx_rings = kcalloc(num_active_queues,
- sizeof(struct i40e_ring), GFP_KERNEL);
+ sizeof(struct iavf_ring), GFP_KERNEL);
if (!adapter->rx_rings)
goto err_out;
for (i = 0; i < num_active_queues; i++) {
- struct i40e_ring *tx_ring;
- struct i40e_ring *rx_ring;
+ struct iavf_ring *tx_ring;
+ struct iavf_ring *rx_ring;
tx_ring = &adapter->tx_rings[i];
@@ -1155,16 +1153,16 @@ static int i40evf_alloc_queues(struct i40evf_adapter *adapter)
tx_ring->netdev = adapter->netdev;
tx_ring->dev = &adapter->pdev->dev;
tx_ring->count = adapter->tx_desc_count;
- tx_ring->itr_setting = I40E_ITR_TX_DEF;
- if (adapter->flags & I40EVF_FLAG_WB_ON_ITR_CAPABLE)
- tx_ring->flags |= I40E_TXR_FLAGS_WB_ON_ITR;
+ tx_ring->itr_setting = IAVF_ITR_TX_DEF;
+ if (adapter->flags & IAVF_FLAG_WB_ON_ITR_CAPABLE)
+ tx_ring->flags |= IAVF_TXR_FLAGS_WB_ON_ITR;
rx_ring = &adapter->rx_rings[i];
rx_ring->queue_index = i;
rx_ring->netdev = adapter->netdev;
rx_ring->dev = &adapter->pdev->dev;
rx_ring->count = adapter->rx_desc_count;
- rx_ring->itr_setting = I40E_ITR_RX_DEF;
+ rx_ring->itr_setting = IAVF_ITR_RX_DEF;
}
adapter->num_active_queues = num_active_queues;
@@ -1172,18 +1170,18 @@ static int i40evf_alloc_queues(struct i40evf_adapter *adapter)
return 0;
err_out:
- i40evf_free_queues(adapter);
+ iavf_free_queues(adapter);
return -ENOMEM;
}
/**
- * i40evf_set_interrupt_capability - set MSI-X or FAIL if not supported
+ * iavf_set_interrupt_capability - set MSI-X or FAIL if not supported
* @adapter: board private structure to initialize
*
* Attempt to configure the interrupts using the best available
* capabilities of the hardware and the kernel.
**/
-static int i40evf_set_interrupt_capability(struct i40evf_adapter *adapter)
+static int iavf_set_interrupt_capability(struct iavf_adapter *adapter)
{
int vector, v_budget;
int pairs = 0;
@@ -1213,7 +1211,7 @@ static int i40evf_set_interrupt_capability(struct i40evf_adapter *adapter)
for (vector = 0; vector < v_budget; vector++)
adapter->msix_entries[vector].entry = vector;
- err = i40evf_acquire_msix_vectors(adapter, v_budget);
+ err = iavf_acquire_msix_vectors(adapter, v_budget);
out:
netif_set_real_num_rx_queues(adapter->netdev, pairs);
@@ -1222,16 +1220,16 @@ out:
}
/**
- * i40e_config_rss_aq - Configure RSS keys and lut by using AQ commands
+ * iavf_config_rss_aq - Configure RSS keys and lut by using AQ commands
* @adapter: board private structure
*
* Return 0 on success, negative on failure
**/
-static int i40evf_config_rss_aq(struct i40evf_adapter *adapter)
+static int iavf_config_rss_aq(struct iavf_adapter *adapter)
{
struct i40e_aqc_get_set_rss_key_data *rss_key =
(struct i40e_aqc_get_set_rss_key_data *)adapter->rss_key;
- struct i40e_hw *hw = &adapter->hw;
+ struct iavf_hw *hw = &adapter->hw;
int ret = 0;
if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) {
@@ -1241,21 +1239,21 @@ static int i40evf_config_rss_aq(struct i40evf_adapter *adapter)
return -EBUSY;
}
- ret = i40evf_aq_set_rss_key(hw, adapter->vsi.id, rss_key);
+ ret = iavf_aq_set_rss_key(hw, adapter->vsi.id, rss_key);
if (ret) {
dev_err(&adapter->pdev->dev, "Cannot set RSS key, err %s aq_err %s\n",
- i40evf_stat_str(hw, ret),
- i40evf_aq_str(hw, hw->aq.asq_last_status));
+ iavf_stat_str(hw, ret),
+ iavf_aq_str(hw, hw->aq.asq_last_status));
return ret;
}
- ret = i40evf_aq_set_rss_lut(hw, adapter->vsi.id, false,
- adapter->rss_lut, adapter->rss_lut_size);
+ ret = iavf_aq_set_rss_lut(hw, adapter->vsi.id, false,
+ adapter->rss_lut, adapter->rss_lut_size);
if (ret) {
dev_err(&adapter->pdev->dev, "Cannot set RSS lut, err %s aq_err %s\n",
- i40evf_stat_str(hw, ret),
- i40evf_aq_str(hw, hw->aq.asq_last_status));
+ iavf_stat_str(hw, ret),
+ iavf_aq_str(hw, hw->aq.asq_last_status));
}
return ret;
@@ -1263,55 +1261,55 @@ static int i40evf_config_rss_aq(struct i40evf_adapter *adapter)
}
/**
- * i40evf_config_rss_reg - Configure RSS keys and lut by writing registers
+ * iavf_config_rss_reg - Configure RSS keys and lut by writing registers
* @adapter: board private structure
*
* Returns 0 on success, negative on failure
**/
-static int i40evf_config_rss_reg(struct i40evf_adapter *adapter)
+static int iavf_config_rss_reg(struct iavf_adapter *adapter)
{
- struct i40e_hw *hw = &adapter->hw;
+ struct iavf_hw *hw = &adapter->hw;
u32 *dw;
u16 i;
dw = (u32 *)adapter->rss_key;
for (i = 0; i <= adapter->rss_key_size / 4; i++)
- wr32(hw, I40E_VFQF_HKEY(i), dw[i]);
+ wr32(hw, IAVF_VFQF_HKEY(i), dw[i]);
dw = (u32 *)adapter->rss_lut;
for (i = 0; i <= adapter->rss_lut_size / 4; i++)
- wr32(hw, I40E_VFQF_HLUT(i), dw[i]);
+ wr32(hw, IAVF_VFQF_HLUT(i), dw[i]);
- i40e_flush(hw);
+ iavf_flush(hw);
return 0;
}
/**
- * i40evf_config_rss - Configure RSS keys and lut
+ * iavf_config_rss - Configure RSS keys and lut
* @adapter: board private structure
*
* Returns 0 on success, negative on failure
**/
-int i40evf_config_rss(struct i40evf_adapter *adapter)
+int iavf_config_rss(struct iavf_adapter *adapter)
{
if (RSS_PF(adapter)) {
- adapter->aq_required |= I40EVF_FLAG_AQ_SET_RSS_LUT |
- I40EVF_FLAG_AQ_SET_RSS_KEY;
+ adapter->aq_required |= IAVF_FLAG_AQ_SET_RSS_LUT |
+ IAVF_FLAG_AQ_SET_RSS_KEY;
return 0;
} else if (RSS_AQ(adapter)) {
- return i40evf_config_rss_aq(adapter);
+ return iavf_config_rss_aq(adapter);
} else {
- return i40evf_config_rss_reg(adapter);
+ return iavf_config_rss_reg(adapter);
}
}
/**
- * i40evf_fill_rss_lut - Fill the lut with default values
+ * iavf_fill_rss_lut - Fill the lut with default values
* @adapter: board private structure
**/
-static void i40evf_fill_rss_lut(struct i40evf_adapter *adapter)
+static void iavf_fill_rss_lut(struct iavf_adapter *adapter)
{
u16 i;
@@ -1320,47 +1318,46 @@ static void i40evf_fill_rss_lut(struct i40evf_adapter *adapter)
}
/**
- * i40evf_init_rss - Prepare for RSS
+ * iavf_init_rss - Prepare for RSS
* @adapter: board private structure
*
* Return 0 on success, negative on failure
**/
-static int i40evf_init_rss(struct i40evf_adapter *adapter)
+static int iavf_init_rss(struct iavf_adapter *adapter)
{
- struct i40e_hw *hw = &adapter->hw;
+ struct iavf_hw *hw = &adapter->hw;
int ret;
if (!RSS_PF(adapter)) {
/* Enable PCTYPES for RSS, TCP/UDP with IPv4/IPv6 */
if (adapter->vf_res->vf_cap_flags &
VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2)
- adapter->hena = I40E_DEFAULT_RSS_HENA_EXPANDED;
+ adapter->hena = IAVF_DEFAULT_RSS_HENA_EXPANDED;
else
- adapter->hena = I40E_DEFAULT_RSS_HENA;
+ adapter->hena = IAVF_DEFAULT_RSS_HENA;
- wr32(hw, I40E_VFQF_HENA(0), (u32)adapter->hena);
- wr32(hw, I40E_VFQF_HENA(1), (u32)(adapter->hena >> 32));
+ wr32(hw, IAVF_VFQF_HENA(0), (u32)adapter->hena);
+ wr32(hw, IAVF_VFQF_HENA(1), (u32)(adapter->hena >> 32));
}
- i40evf_fill_rss_lut(adapter);
-
+ iavf_fill_rss_lut(adapter);
netdev_rss_key_fill((void *)adapter->rss_key, adapter->rss_key_size);
- ret = i40evf_config_rss(adapter);
+ ret = iavf_config_rss(adapter);
return ret;
}
/**
- * i40evf_alloc_q_vectors - Allocate memory for interrupt vectors
+ * iavf_alloc_q_vectors - Allocate memory for interrupt vectors
* @adapter: board private structure to initialize
*
* We allocate one q_vector per queue interrupt. If allocation fails we
* return -ENOMEM.
**/
-static int i40evf_alloc_q_vectors(struct i40evf_adapter *adapter)
+static int iavf_alloc_q_vectors(struct iavf_adapter *adapter)
{
int q_idx = 0, num_q_vectors;
- struct i40e_q_vector *q_vector;
+ struct iavf_q_vector *q_vector;
num_q_vectors = adapter->num_msix_vectors - NONQ_VECS;
adapter->q_vectors = kcalloc(num_q_vectors, sizeof(*q_vector),
@@ -1376,21 +1373,21 @@ static int i40evf_alloc_q_vectors(struct i40evf_adapter *adapter)
q_vector->reg_idx = q_idx;
cpumask_copy(&q_vector->affinity_mask, cpu_possible_mask);
netif_napi_add(adapter->netdev, &q_vector->napi,
- i40evf_napi_poll, NAPI_POLL_WEIGHT);
+ iavf_napi_poll, NAPI_POLL_WEIGHT);
}
return 0;
}
/**
- * i40evf_free_q_vectors - Free memory allocated for interrupt vectors
+ * iavf_free_q_vectors - Free memory allocated for interrupt vectors
* @adapter: board private structure to initialize
*
* This function frees the memory allocated to the q_vectors. In addition if
* NAPI is enabled it will delete any references to the NAPI struct prior
* to freeing the q_vector.
**/
-static void i40evf_free_q_vectors(struct i40evf_adapter *adapter)
+static void iavf_free_q_vectors(struct iavf_adapter *adapter)
{
int q_idx, num_q_vectors;
int napi_vectors;
@@ -1402,7 +1399,8 @@ static void i40evf_free_q_vectors(struct i40evf_adapter *adapter)
napi_vectors = adapter->num_active_queues;
for (q_idx = 0; q_idx < num_q_vectors; q_idx++) {
- struct i40e_q_vector *q_vector = &adapter->q_vectors[q_idx];
+ struct iavf_q_vector *q_vector = &adapter->q_vectors[q_idx];
+
if (q_idx < napi_vectors)
netif_napi_del(&q_vector->napi);
}
@@ -1411,11 +1409,11 @@ static void i40evf_free_q_vectors(struct i40evf_adapter *adapter)
}
/**
- * i40evf_reset_interrupt_capability - Reset MSIX setup
+ * iavf_reset_interrupt_capability - Reset MSIX setup
* @adapter: board private structure
*
**/
-void i40evf_reset_interrupt_capability(struct i40evf_adapter *adapter)
+void iavf_reset_interrupt_capability(struct iavf_adapter *adapter)
{
if (!adapter->msix_entries)
return;
@@ -1426,15 +1424,15 @@ void i40evf_reset_interrupt_capability(struct i40evf_adapter *adapter)
}
/**
- * i40evf_init_interrupt_scheme - Determine if MSIX is supported and init
+ * iavf_init_interrupt_scheme - Determine if MSIX is supported and init
* @adapter: board private structure to initialize
*
**/
-int i40evf_init_interrupt_scheme(struct i40evf_adapter *adapter)
+int iavf_init_interrupt_scheme(struct iavf_adapter *adapter)
{
int err;
- err = i40evf_alloc_queues(adapter);
+ err = iavf_alloc_queues(adapter);
if (err) {
dev_err(&adapter->pdev->dev,
"Unable to allocate memory for queues\n");
@@ -1442,7 +1440,7 @@ int i40evf_init_interrupt_scheme(struct i40evf_adapter *adapter)
}
rtnl_lock();
- err = i40evf_set_interrupt_capability(adapter);
+ err = iavf_set_interrupt_capability(adapter);
rtnl_unlock();
if (err) {
dev_err(&adapter->pdev->dev,
@@ -1450,7 +1448,7 @@ int i40evf_init_interrupt_scheme(struct i40evf_adapter *adapter)
goto err_set_interrupt;
}
- err = i40evf_alloc_q_vectors(adapter);
+ err = iavf_alloc_q_vectors(adapter);
if (err) {
dev_err(&adapter->pdev->dev,
"Unable to allocate memory for queue vectors\n");
@@ -1473,18 +1471,18 @@ int i40evf_init_interrupt_scheme(struct i40evf_adapter *adapter)
return 0;
err_alloc_q_vectors:
- i40evf_reset_interrupt_capability(adapter);
+ iavf_reset_interrupt_capability(adapter);
err_set_interrupt:
- i40evf_free_queues(adapter);
+ iavf_free_queues(adapter);
err_alloc_queues:
return err;
}
/**
- * i40evf_free_rss - Free memory used by RSS structs
+ * iavf_free_rss - Free memory used by RSS structs
* @adapter: board private structure
**/
-static void i40evf_free_rss(struct i40evf_adapter *adapter)
+static void iavf_free_rss(struct iavf_adapter *adapter)
{
kfree(adapter->rss_key);
adapter->rss_key = NULL;
@@ -1494,52 +1492,52 @@ static void i40evf_free_rss(struct i40evf_adapter *adapter)
}
/**
- * i40evf_reinit_interrupt_scheme - Reallocate queues and vectors
+ * iavf_reinit_interrupt_scheme - Reallocate queues and vectors
* @adapter: board private structure
*
* Returns 0 on success, negative on failure
**/
-static int i40evf_reinit_interrupt_scheme(struct i40evf_adapter *adapter)
+static int iavf_reinit_interrupt_scheme(struct iavf_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
int err;
if (netif_running(netdev))
- i40evf_free_traffic_irqs(adapter);
- i40evf_free_misc_irq(adapter);
- i40evf_reset_interrupt_capability(adapter);
- i40evf_free_q_vectors(adapter);
- i40evf_free_queues(adapter);
+ iavf_free_traffic_irqs(adapter);
+ iavf_free_misc_irq(adapter);
+ iavf_reset_interrupt_capability(adapter);
+ iavf_free_q_vectors(adapter);
+ iavf_free_queues(adapter);
- err = i40evf_init_interrupt_scheme(adapter);
+ err = iavf_init_interrupt_scheme(adapter);
if (err)
goto err;
netif_tx_stop_all_queues(netdev);
- err = i40evf_request_misc_irq(adapter);
+ err = iavf_request_misc_irq(adapter);
if (err)
goto err;
- set_bit(__I40E_VSI_DOWN, adapter->vsi.state);
+ set_bit(__IAVF_VSI_DOWN, adapter->vsi.state);
- i40evf_map_rings_to_vectors(adapter);
+ iavf_map_rings_to_vectors(adapter);
if (RSS_AQ(adapter))
- adapter->aq_required |= I40EVF_FLAG_AQ_CONFIGURE_RSS;
+ adapter->aq_required |= IAVF_FLAG_AQ_CONFIGURE_RSS;
else
- err = i40evf_init_rss(adapter);
+ err = iavf_init_rss(adapter);
err:
return err;
}
/**
- * i40evf_watchdog_timer - Periodic call-back timer
+ * iavf_watchdog_timer - Periodic call-back timer
* @data: pointer to adapter disguised as unsigned long
**/
-static void i40evf_watchdog_timer(struct timer_list *t)
+static void iavf_watchdog_timer(struct timer_list *t)
{
- struct i40evf_adapter *adapter = from_timer(adapter, t,
+ struct iavf_adapter *adapter = from_timer(adapter, t,
watchdog_timer);
schedule_work(&adapter->watchdog_task);
@@ -1547,31 +1545,31 @@ static void i40evf_watchdog_timer(struct timer_list *t)
}
/**
- * i40evf_watchdog_task - Periodic call-back task
+ * iavf_watchdog_task - Periodic call-back task
* @work: pointer to work_struct
**/
-static void i40evf_watchdog_task(struct work_struct *work)
+static void iavf_watchdog_task(struct work_struct *work)
{
- struct i40evf_adapter *adapter = container_of(work,
- struct i40evf_adapter,
+ struct iavf_adapter *adapter = container_of(work,
+ struct iavf_adapter,
watchdog_task);
- struct i40e_hw *hw = &adapter->hw;
+ struct iavf_hw *hw = &adapter->hw;
u32 reg_val;
- if (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section))
+ if (test_and_set_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section))
goto restart_watchdog;
- if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) {
- reg_val = rd32(hw, I40E_VFGEN_RSTAT) &
- I40E_VFGEN_RSTAT_VFR_STATE_MASK;
+ if (adapter->flags & IAVF_FLAG_PF_COMMS_FAILED) {
+ reg_val = rd32(hw, IAVF_VFGEN_RSTAT) &
+ IAVF_VFGEN_RSTAT_VFR_STATE_MASK;
if ((reg_val == VIRTCHNL_VFR_VFACTIVE) ||
(reg_val == VIRTCHNL_VFR_COMPLETED)) {
/* A chance for redemption! */
dev_err(&adapter->pdev->dev, "Hardware came out of reset. Attempting reinit.\n");
- adapter->state = __I40EVF_STARTUP;
- adapter->flags &= ~I40EVF_FLAG_PF_COMMS_FAILED;
+ adapter->state = __IAVF_STARTUP;
+ adapter->flags &= ~IAVF_FLAG_PF_COMMS_FAILED;
schedule_delayed_work(&adapter->init_task, 10);
- clear_bit(__I40EVF_IN_CRITICAL_TASK,
+ clear_bit(__IAVF_IN_CRITICAL_TASK,
&adapter->crit_section);
/* Don't reschedule the watchdog, since we've restarted
* the init task. When init_task contacts the PF and
@@ -1585,15 +1583,15 @@ static void i40evf_watchdog_task(struct work_struct *work)
goto watchdog_done;
}
- if ((adapter->state < __I40EVF_DOWN) ||
- (adapter->flags & I40EVF_FLAG_RESET_PENDING))
+ if ((adapter->state < __IAVF_DOWN) ||
+ (adapter->flags & IAVF_FLAG_RESET_PENDING))
goto watchdog_done;
/* check for reset */
- reg_val = rd32(hw, I40E_VF_ARQLEN1) & I40E_VF_ARQLEN1_ARQENABLE_MASK;
- if (!(adapter->flags & I40EVF_FLAG_RESET_PENDING) && !reg_val) {
- adapter->state = __I40EVF_RESETTING;
- adapter->flags |= I40EVF_FLAG_RESET_PENDING;
+ reg_val = rd32(hw, IAVF_VF_ARQLEN1) & IAVF_VF_ARQLEN1_ARQENABLE_MASK;
+ if (!(adapter->flags & IAVF_FLAG_RESET_PENDING) && !reg_val) {
+ adapter->state = __IAVF_RESETTING;
+ adapter->flags |= IAVF_FLAG_RESET_PENDING;
dev_err(&adapter->pdev->dev, "Hardware reset detected\n");
schedule_work(&adapter->reset_task);
adapter->aq_required = 0;
@@ -1605,140 +1603,140 @@ static void i40evf_watchdog_task(struct work_struct *work)
* here so we don't race on the admin queue.
*/
if (adapter->current_op) {
- if (!i40evf_asq_done(hw)) {
+ if (!iavf_asq_done(hw)) {
dev_dbg(&adapter->pdev->dev, "Admin queue timeout\n");
- i40evf_send_api_ver(adapter);
+ iavf_send_api_ver(adapter);
}
goto watchdog_done;
}
- if (adapter->aq_required & I40EVF_FLAG_AQ_GET_CONFIG) {
- i40evf_send_vf_config_msg(adapter);
+ if (adapter->aq_required & IAVF_FLAG_AQ_GET_CONFIG) {
+ iavf_send_vf_config_msg(adapter);
goto watchdog_done;
}
- if (adapter->aq_required & I40EVF_FLAG_AQ_DISABLE_QUEUES) {
- i40evf_disable_queues(adapter);
+ if (adapter->aq_required & IAVF_FLAG_AQ_DISABLE_QUEUES) {
+ iavf_disable_queues(adapter);
goto watchdog_done;
}
- if (adapter->aq_required & I40EVF_FLAG_AQ_MAP_VECTORS) {
- i40evf_map_queues(adapter);
+ if (adapter->aq_required & IAVF_FLAG_AQ_MAP_VECTORS) {
+ iavf_map_queues(adapter);
goto watchdog_done;
}
- if (adapter->aq_required & I40EVF_FLAG_AQ_ADD_MAC_FILTER) {
- i40evf_add_ether_addrs(adapter);
+ if (adapter->aq_required & IAVF_FLAG_AQ_ADD_MAC_FILTER) {
+ iavf_add_ether_addrs(adapter);
goto watchdog_done;
}
- if (adapter->aq_required & I40EVF_FLAG_AQ_ADD_VLAN_FILTER) {
- i40evf_add_vlans(adapter);
+ if (adapter->aq_required & IAVF_FLAG_AQ_ADD_VLAN_FILTER) {
+ iavf_add_vlans(adapter);
goto watchdog_done;
}
- if (adapter->aq_required & I40EVF_FLAG_AQ_DEL_MAC_FILTER) {
- i40evf_del_ether_addrs(adapter);
+ if (adapter->aq_required & IAVF_FLAG_AQ_DEL_MAC_FILTER) {
+ iavf_del_ether_addrs(adapter);
goto watchdog_done;
}
- if (adapter->aq_required & I40EVF_FLAG_AQ_DEL_VLAN_FILTER) {
- i40evf_del_vlans(adapter);
+ if (adapter->aq_required & IAVF_FLAG_AQ_DEL_VLAN_FILTER) {
+ iavf_del_vlans(adapter);
goto watchdog_done;
}
- if (adapter->aq_required & I40EVF_FLAG_AQ_ENABLE_VLAN_STRIPPING) {
- i40evf_enable_vlan_stripping(adapter);
+ if (adapter->aq_required & IAVF_FLAG_AQ_ENABLE_VLAN_STRIPPING) {
+ iavf_enable_vlan_stripping(adapter);
goto watchdog_done;
}
- if (adapter->aq_required & I40EVF_FLAG_AQ_DISABLE_VLAN_STRIPPING) {
- i40evf_disable_vlan_stripping(adapter);
+ if (adapter->aq_required & IAVF_FLAG_AQ_DISABLE_VLAN_STRIPPING) {
+ iavf_disable_vlan_stripping(adapter);
goto watchdog_done;
}
- if (adapter->aq_required & I40EVF_FLAG_AQ_CONFIGURE_QUEUES) {
- i40evf_configure_queues(adapter);
+ if (adapter->aq_required & IAVF_FLAG_AQ_CONFIGURE_QUEUES) {
+ iavf_configure_queues(adapter);
goto watchdog_done;
}
- if (adapter->aq_required & I40EVF_FLAG_AQ_ENABLE_QUEUES) {
- i40evf_enable_queues(adapter);
+ if (adapter->aq_required & IAVF_FLAG_AQ_ENABLE_QUEUES) {
+ iavf_enable_queues(adapter);
goto watchdog_done;
}
- if (adapter->aq_required & I40EVF_FLAG_AQ_CONFIGURE_RSS) {
+ if (adapter->aq_required & IAVF_FLAG_AQ_CONFIGURE_RSS) {
/* This message goes straight to the firmware, not the
* PF, so we don't have to set current_op as we will
* not get a response through the ARQ.
*/
- i40evf_init_rss(adapter);
- adapter->aq_required &= ~I40EVF_FLAG_AQ_CONFIGURE_RSS;
+ iavf_init_rss(adapter);
+ adapter->aq_required &= ~IAVF_FLAG_AQ_CONFIGURE_RSS;
goto watchdog_done;
}
- if (adapter->aq_required & I40EVF_FLAG_AQ_GET_HENA) {
- i40evf_get_hena(adapter);
+ if (adapter->aq_required & IAVF_FLAG_AQ_GET_HENA) {
+ iavf_get_hena(adapter);
goto watchdog_done;
}
- if (adapter->aq_required & I40EVF_FLAG_AQ_SET_HENA) {
- i40evf_set_hena(adapter);
+ if (adapter->aq_required & IAVF_FLAG_AQ_SET_HENA) {
+ iavf_set_hena(adapter);
goto watchdog_done;
}
- if (adapter->aq_required & I40EVF_FLAG_AQ_SET_RSS_KEY) {
- i40evf_set_rss_key(adapter);
+ if (adapter->aq_required & IAVF_FLAG_AQ_SET_RSS_KEY) {
+ iavf_set_rss_key(adapter);
goto watchdog_done;
}
- if (adapter->aq_required & I40EVF_FLAG_AQ_SET_RSS_LUT) {
- i40evf_set_rss_lut(adapter);
+ if (adapter->aq_required & IAVF_FLAG_AQ_SET_RSS_LUT) {
+ iavf_set_rss_lut(adapter);
goto watchdog_done;
}
- if (adapter->aq_required & I40EVF_FLAG_AQ_REQUEST_PROMISC) {
- i40evf_set_promiscuous(adapter, FLAG_VF_UNICAST_PROMISC |
+ if (adapter->aq_required & IAVF_FLAG_AQ_REQUEST_PROMISC) {
+ iavf_set_promiscuous(adapter, FLAG_VF_UNICAST_PROMISC |
FLAG_VF_MULTICAST_PROMISC);
goto watchdog_done;
}
- if (adapter->aq_required & I40EVF_FLAG_AQ_REQUEST_ALLMULTI) {
- i40evf_set_promiscuous(adapter, FLAG_VF_MULTICAST_PROMISC);
+ if (adapter->aq_required & IAVF_FLAG_AQ_REQUEST_ALLMULTI) {
+ iavf_set_promiscuous(adapter, FLAG_VF_MULTICAST_PROMISC);
goto watchdog_done;
}
- if ((adapter->aq_required & I40EVF_FLAG_AQ_RELEASE_PROMISC) &&
- (adapter->aq_required & I40EVF_FLAG_AQ_RELEASE_ALLMULTI)) {
- i40evf_set_promiscuous(adapter, 0);
+ if ((adapter->aq_required & IAVF_FLAG_AQ_RELEASE_PROMISC) &&
+ (adapter->aq_required & IAVF_FLAG_AQ_RELEASE_ALLMULTI)) {
+ iavf_set_promiscuous(adapter, 0);
goto watchdog_done;
}
- if (adapter->aq_required & I40EVF_FLAG_AQ_ENABLE_CHANNELS) {
- i40evf_enable_channels(adapter);
+ if (adapter->aq_required & IAVF_FLAG_AQ_ENABLE_CHANNELS) {
+ iavf_enable_channels(adapter);
goto watchdog_done;
}
- if (adapter->aq_required & I40EVF_FLAG_AQ_DISABLE_CHANNELS) {
- i40evf_disable_channels(adapter);
+ if (adapter->aq_required & IAVF_FLAG_AQ_DISABLE_CHANNELS) {
+ iavf_disable_channels(adapter);
goto watchdog_done;
}
- if (adapter->aq_required & I40EVF_FLAG_AQ_ADD_CLOUD_FILTER) {
- i40evf_add_cloud_filter(adapter);
+ if (adapter->aq_required & IAVF_FLAG_AQ_ADD_CLOUD_FILTER) {
+ iavf_add_cloud_filter(adapter);
goto watchdog_done;
}
- if (adapter->aq_required & I40EVF_FLAG_AQ_DEL_CLOUD_FILTER) {
- i40evf_del_cloud_filter(adapter);
+ if (adapter->aq_required & IAVF_FLAG_AQ_DEL_CLOUD_FILTER) {
+ iavf_del_cloud_filter(adapter);
goto watchdog_done;
}
schedule_delayed_work(&adapter->client_task, msecs_to_jiffies(5));
- if (adapter->state == __I40EVF_RUNNING)
- i40evf_request_stats(adapter);
+ if (adapter->state == __IAVF_RUNNING)
+ iavf_request_stats(adapter);
watchdog_done:
- if (adapter->state == __I40EVF_RUNNING)
- i40evf_detect_recover_hung(&adapter->vsi);
- clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
+ if (adapter->state == __IAVF_RUNNING)
+ iavf_detect_recover_hung(&adapter->vsi);
+ clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section);
restart_watchdog:
- if (adapter->state == __I40EVF_REMOVE)
+ if (adapter->state == __IAVF_REMOVE)
return;
if (adapter->aq_required)
mod_timer(&adapter->watchdog_timer,
@@ -1748,28 +1746,28 @@ restart_watchdog:
schedule_work(&adapter->adminq_task);
}
-static void i40evf_disable_vf(struct i40evf_adapter *adapter)
+static void iavf_disable_vf(struct iavf_adapter *adapter)
{
- struct i40evf_mac_filter *f, *ftmp;
- struct i40evf_vlan_filter *fv, *fvtmp;
- struct i40evf_cloud_filter *cf, *cftmp;
+ struct iavf_mac_filter *f, *ftmp;
+ struct iavf_vlan_filter *fv, *fvtmp;
+ struct iavf_cloud_filter *cf, *cftmp;
- adapter->flags |= I40EVF_FLAG_PF_COMMS_FAILED;
+ adapter->flags |= IAVF_FLAG_PF_COMMS_FAILED;
/* We don't use netif_running() because it may be true prior to
* ndo_open() returning, so we can't assume it means all our open
* tasks have finished, since we're not holding the rtnl_lock here.
*/
- if (adapter->state == __I40EVF_RUNNING) {
- set_bit(__I40E_VSI_DOWN, adapter->vsi.state);
+ if (adapter->state == __IAVF_RUNNING) {
+ set_bit(__IAVF_VSI_DOWN, adapter->vsi.state);
netif_carrier_off(adapter->netdev);
netif_tx_disable(adapter->netdev);
adapter->link_up = false;
- i40evf_napi_disable_all(adapter);
- i40evf_irq_disable(adapter);
- i40evf_free_traffic_irqs(adapter);
- i40evf_free_all_tx_resources(adapter);
- i40evf_free_all_rx_resources(adapter);
+ iavf_napi_disable_all(adapter);
+ iavf_irq_disable(adapter);
+ iavf_free_traffic_irqs(adapter);
+ iavf_free_all_tx_resources(adapter);
+ iavf_free_all_rx_resources(adapter);
}
spin_lock_bh(&adapter->mac_vlan_list_lock);
@@ -1795,41 +1793,41 @@ static void i40evf_disable_vf(struct i40evf_adapter *adapter)
}
spin_unlock_bh(&adapter->cloud_filter_list_lock);
- i40evf_free_misc_irq(adapter);
- i40evf_reset_interrupt_capability(adapter);
- i40evf_free_queues(adapter);
- i40evf_free_q_vectors(adapter);
+ iavf_free_misc_irq(adapter);
+ iavf_reset_interrupt_capability(adapter);
+ iavf_free_queues(adapter);
+ iavf_free_q_vectors(adapter);
kfree(adapter->vf_res);
- i40evf_shutdown_adminq(&adapter->hw);
+ iavf_shutdown_adminq(&adapter->hw);
adapter->netdev->flags &= ~IFF_UP;
- clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
- adapter->flags &= ~I40EVF_FLAG_RESET_PENDING;
- adapter->state = __I40EVF_DOWN;
+ clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section);
+ adapter->flags &= ~IAVF_FLAG_RESET_PENDING;
+ adapter->state = __IAVF_DOWN;
wake_up(&adapter->down_waitqueue);
dev_info(&adapter->pdev->dev, "Reset task did not complete, VF disabled\n");
}
-#define I40EVF_RESET_WAIT_MS 10
-#define I40EVF_RESET_WAIT_COUNT 500
+#define IAVF_RESET_WAIT_MS 10
+#define IAVF_RESET_WAIT_COUNT 500
/**
- * i40evf_reset_task - Call-back task to handle hardware reset
+ * iavf_reset_task - Call-back task to handle hardware reset
* @work: pointer to work_struct
*
* During reset we need to shut down and reinitialize the admin queue
* before we can use it to communicate with the PF again. We also clear
* and reinit the rings because that context is lost as well.
**/
-static void i40evf_reset_task(struct work_struct *work)
+static void iavf_reset_task(struct work_struct *work)
{
- struct i40evf_adapter *adapter = container_of(work,
- struct i40evf_adapter,
+ struct iavf_adapter *adapter = container_of(work,
+ struct iavf_adapter,
reset_task);
struct virtchnl_vf_resource *vfres = adapter->vf_res;
struct net_device *netdev = adapter->netdev;
- struct i40e_hw *hw = &adapter->hw;
- struct i40evf_vlan_filter *vlf;
- struct i40evf_cloud_filter *cf;
- struct i40evf_mac_filter *f;
+ struct iavf_hw *hw = &adapter->hw;
+ struct iavf_vlan_filter *vlf;
+ struct iavf_cloud_filter *cf;
+ struct iavf_mac_filter *f;
u32 reg_val;
int i = 0, err;
bool running;
@@ -1837,63 +1835,63 @@ static void i40evf_reset_task(struct work_struct *work)
/* When device is being removed it doesn't make sense to run the reset
* task, just return in such a case.
*/
- if (test_bit(__I40EVF_IN_REMOVE_TASK, &adapter->crit_section))
+ if (test_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section))
return;
- while (test_and_set_bit(__I40EVF_IN_CLIENT_TASK,
+ while (test_and_set_bit(__IAVF_IN_CLIENT_TASK,
&adapter->crit_section))
usleep_range(500, 1000);
if (CLIENT_ENABLED(adapter)) {
- adapter->flags &= ~(I40EVF_FLAG_CLIENT_NEEDS_OPEN |
- I40EVF_FLAG_CLIENT_NEEDS_CLOSE |
- I40EVF_FLAG_CLIENT_NEEDS_L2_PARAMS |
- I40EVF_FLAG_SERVICE_CLIENT_REQUESTED);
+ adapter->flags &= ~(IAVF_FLAG_CLIENT_NEEDS_OPEN |
+ IAVF_FLAG_CLIENT_NEEDS_CLOSE |
+ IAVF_FLAG_CLIENT_NEEDS_L2_PARAMS |
+ IAVF_FLAG_SERVICE_CLIENT_REQUESTED);
cancel_delayed_work_sync(&adapter->client_task);
- i40evf_notify_client_close(&adapter->vsi, true);
+ iavf_notify_client_close(&adapter->vsi, true);
}
- i40evf_misc_irq_disable(adapter);
- if (adapter->flags & I40EVF_FLAG_RESET_NEEDED) {
- adapter->flags &= ~I40EVF_FLAG_RESET_NEEDED;
+ iavf_misc_irq_disable(adapter);
+ if (adapter->flags & IAVF_FLAG_RESET_NEEDED) {
+ adapter->flags &= ~IAVF_FLAG_RESET_NEEDED;
/* Restart the AQ here. If we have been reset but didn't
* detect it, or if the PF had to reinit, our AQ will be hosed.
*/
- i40evf_shutdown_adminq(hw);
- i40evf_init_adminq(hw);
- i40evf_request_reset(adapter);
+ iavf_shutdown_adminq(hw);
+ iavf_init_adminq(hw);
+ iavf_request_reset(adapter);
}
- adapter->flags |= I40EVF_FLAG_RESET_PENDING;
+ adapter->flags |= IAVF_FLAG_RESET_PENDING;
/* poll until we see the reset actually happen */
- for (i = 0; i < I40EVF_RESET_WAIT_COUNT; i++) {
- reg_val = rd32(hw, I40E_VF_ARQLEN1) &
- I40E_VF_ARQLEN1_ARQENABLE_MASK;
+ for (i = 0; i < IAVF_RESET_WAIT_COUNT; i++) {
+ reg_val = rd32(hw, IAVF_VF_ARQLEN1) &
+ IAVF_VF_ARQLEN1_ARQENABLE_MASK;
if (!reg_val)
break;
usleep_range(5000, 10000);
}
- if (i == I40EVF_RESET_WAIT_COUNT) {
+ if (i == IAVF_RESET_WAIT_COUNT) {
dev_info(&adapter->pdev->dev, "Never saw reset\n");
goto continue_reset; /* act like the reset happened */
}
/* wait until the reset is complete and the PF is responding to us */
- for (i = 0; i < I40EVF_RESET_WAIT_COUNT; i++) {
+ for (i = 0; i < IAVF_RESET_WAIT_COUNT; i++) {
/* sleep first to make sure a minimum wait time is met */
- msleep(I40EVF_RESET_WAIT_MS);
+ msleep(IAVF_RESET_WAIT_MS);
- reg_val = rd32(hw, I40E_VFGEN_RSTAT) &
- I40E_VFGEN_RSTAT_VFR_STATE_MASK;
+ reg_val = rd32(hw, IAVF_VFGEN_RSTAT) &
+ IAVF_VFGEN_RSTAT_VFR_STATE_MASK;
if (reg_val == VIRTCHNL_VFR_VFACTIVE)
break;
}
pci_set_master(adapter->pdev);
- if (i == I40EVF_RESET_WAIT_COUNT) {
+ if (i == IAVF_RESET_WAIT_COUNT) {
dev_err(&adapter->pdev->dev, "Reset never finished (%x)\n",
reg_val);
- i40evf_disable_vf(adapter);
- clear_bit(__I40EVF_IN_CLIENT_TASK, &adapter->crit_section);
+ iavf_disable_vf(adapter);
+ clear_bit(__IAVF_IN_CLIENT_TASK, &adapter->crit_section);
return; /* Do not attempt to reinit. It's dead, Jim. */
}
@@ -1902,44 +1900,44 @@ continue_reset:
* ndo_open() returning, so we can't assume it means all our open
* tasks have finished, since we're not holding the rtnl_lock here.
*/
- running = ((adapter->state == __I40EVF_RUNNING) ||
- (adapter->state == __I40EVF_RESETTING));
+ running = ((adapter->state == __IAVF_RUNNING) ||
+ (adapter->state == __IAVF_RESETTING));
if (running) {
netif_carrier_off(netdev);
netif_tx_stop_all_queues(netdev);
adapter->link_up = false;
- i40evf_napi_disable_all(adapter);
+ iavf_napi_disable_all(adapter);
}
- i40evf_irq_disable(adapter);
+ iavf_irq_disable(adapter);
- adapter->state = __I40EVF_RESETTING;
- adapter->flags &= ~I40EVF_FLAG_RESET_PENDING;
+ adapter->state = __IAVF_RESETTING;
+ adapter->flags &= ~IAVF_FLAG_RESET_PENDING;
/* free the Tx/Rx rings and descriptors, might be better to just
* re-use them sometime in the future
*/
- i40evf_free_all_rx_resources(adapter);
- i40evf_free_all_tx_resources(adapter);
+ iavf_free_all_rx_resources(adapter);
+ iavf_free_all_tx_resources(adapter);
- adapter->flags |= I40EVF_FLAG_QUEUES_DISABLED;
+ adapter->flags |= IAVF_FLAG_QUEUES_DISABLED;
/* kill and reinit the admin queue */
- i40evf_shutdown_adminq(hw);
+ iavf_shutdown_adminq(hw);
adapter->current_op = VIRTCHNL_OP_UNKNOWN;
- err = i40evf_init_adminq(hw);
+ err = iavf_init_adminq(hw);
if (err)
dev_info(&adapter->pdev->dev, "Failed to init adminq: %d\n",
err);
adapter->aq_required = 0;
- if (adapter->flags & I40EVF_FLAG_REINIT_ITR_NEEDED) {
- err = i40evf_reinit_interrupt_scheme(adapter);
+ if (adapter->flags & IAVF_FLAG_REINIT_ITR_NEEDED) {
+ err = iavf_reinit_interrupt_scheme(adapter);
if (err)
goto reset_err;
}
- adapter->aq_required |= I40EVF_FLAG_AQ_GET_CONFIG;
- adapter->aq_required |= I40EVF_FLAG_AQ_MAP_VECTORS;
+ adapter->aq_required |= IAVF_FLAG_AQ_GET_CONFIG;
+ adapter->aq_required |= IAVF_FLAG_AQ_MAP_VECTORS;
spin_lock_bh(&adapter->mac_vlan_list_lock);
@@ -1964,10 +1962,10 @@ continue_reset:
}
spin_unlock_bh(&adapter->cloud_filter_list_lock);
- adapter->aq_required |= I40EVF_FLAG_AQ_ADD_MAC_FILTER;
- adapter->aq_required |= I40EVF_FLAG_AQ_ADD_VLAN_FILTER;
- adapter->aq_required |= I40EVF_FLAG_AQ_ADD_CLOUD_FILTER;
- i40evf_misc_irq_enable(adapter);
+ adapter->aq_required |= IAVF_FLAG_AQ_ADD_MAC_FILTER;
+ adapter->aq_required |= IAVF_FLAG_AQ_ADD_VLAN_FILTER;
+ adapter->aq_required |= IAVF_FLAG_AQ_ADD_CLOUD_FILTER;
+ iavf_misc_irq_enable(adapter);
mod_timer(&adapter->watchdog_timer, jiffies + 2);
@@ -1976,84 +1974,83 @@ continue_reset:
*/
if (running) {
/* allocate transmit descriptors */
- err = i40evf_setup_all_tx_resources(adapter);
+ err = iavf_setup_all_tx_resources(adapter);
if (err)
goto reset_err;
/* allocate receive descriptors */
- err = i40evf_setup_all_rx_resources(adapter);
+ err = iavf_setup_all_rx_resources(adapter);
if (err)
goto reset_err;
- if (adapter->flags & I40EVF_FLAG_REINIT_ITR_NEEDED) {
- err = i40evf_request_traffic_irqs(adapter,
- netdev->name);
+ if (adapter->flags & IAVF_FLAG_REINIT_ITR_NEEDED) {
+ err = iavf_request_traffic_irqs(adapter, netdev->name);
if (err)
goto reset_err;
- adapter->flags &= ~I40EVF_FLAG_REINIT_ITR_NEEDED;
+ adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED;
}
- i40evf_configure(adapter);
+ iavf_configure(adapter);
- i40evf_up_complete(adapter);
+ iavf_up_complete(adapter);
- i40evf_irq_enable(adapter, true);
+ iavf_irq_enable(adapter, true);
} else {
- adapter->state = __I40EVF_DOWN;
+ adapter->state = __IAVF_DOWN;
wake_up(&adapter->down_waitqueue);
}
- clear_bit(__I40EVF_IN_CLIENT_TASK, &adapter->crit_section);
- clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
+ clear_bit(__IAVF_IN_CLIENT_TASK, &adapter->crit_section);
+ clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section);
return;
reset_err:
- clear_bit(__I40EVF_IN_CLIENT_TASK, &adapter->crit_section);
- clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
+ clear_bit(__IAVF_IN_CLIENT_TASK, &adapter->crit_section);
+ clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section);
dev_err(&adapter->pdev->dev, "failed to allocate resources during reinit\n");
- i40evf_close(netdev);
+ iavf_close(netdev);
}
/**
- * i40evf_adminq_task - worker thread to clean the admin queue
+ * iavf_adminq_task - worker thread to clean the admin queue
* @work: pointer to work_struct containing our data
**/
-static void i40evf_adminq_task(struct work_struct *work)
+static void iavf_adminq_task(struct work_struct *work)
{
- struct i40evf_adapter *adapter =
- container_of(work, struct i40evf_adapter, adminq_task);
- struct i40e_hw *hw = &adapter->hw;
+ struct iavf_adapter *adapter =
+ container_of(work, struct iavf_adapter, adminq_task);
+ struct iavf_hw *hw = &adapter->hw;
struct i40e_arq_event_info event;
enum virtchnl_ops v_op;
- i40e_status ret, v_ret;
+ iavf_status ret, v_ret;
u32 val, oldval;
u16 pending;
- if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED)
+ if (adapter->flags & IAVF_FLAG_PF_COMMS_FAILED)
goto out;
- event.buf_len = I40EVF_MAX_AQ_BUF_SIZE;
+ event.buf_len = IAVF_MAX_AQ_BUF_SIZE;
event.msg_buf = kzalloc(event.buf_len, GFP_KERNEL);
if (!event.msg_buf)
goto out;
do {
- ret = i40evf_clean_arq_element(hw, &event, &pending);
+ ret = iavf_clean_arq_element(hw, &event, &pending);
v_op = (enum virtchnl_ops)le32_to_cpu(event.desc.cookie_high);
- v_ret = (i40e_status)le32_to_cpu(event.desc.cookie_low);
+ v_ret = (iavf_status)le32_to_cpu(event.desc.cookie_low);
if (ret || !v_op)
break; /* No event to process or error cleaning ARQ */
- i40evf_virtchnl_completion(adapter, v_op, v_ret, event.msg_buf,
- event.msg_len);
+ iavf_virtchnl_completion(adapter, v_op, v_ret, event.msg_buf,
+ event.msg_len);
if (pending != 0)
- memset(event.msg_buf, 0, I40EVF_MAX_AQ_BUF_SIZE);
+ memset(event.msg_buf, 0, IAVF_MAX_AQ_BUF_SIZE);
} while (pending);
if ((adapter->flags &
- (I40EVF_FLAG_RESET_PENDING | I40EVF_FLAG_RESET_NEEDED)) ||
- adapter->state == __I40EVF_RESETTING)
+ (IAVF_FLAG_RESET_PENDING | IAVF_FLAG_RESET_NEEDED)) ||
+ adapter->state == __IAVF_RESETTING)
goto freedom;
/* check for error indications */
@@ -2061,34 +2058,34 @@ static void i40evf_adminq_task(struct work_struct *work)
if (val == 0xdeadbeef) /* indicates device in reset */
goto freedom;
oldval = val;
- if (val & I40E_VF_ARQLEN1_ARQVFE_MASK) {
+ if (val & IAVF_VF_ARQLEN1_ARQVFE_MASK) {
dev_info(&adapter->pdev->dev, "ARQ VF Error detected\n");
- val &= ~I40E_VF_ARQLEN1_ARQVFE_MASK;
+ val &= ~IAVF_VF_ARQLEN1_ARQVFE_MASK;
}
- if (val & I40E_VF_ARQLEN1_ARQOVFL_MASK) {
+ if (val & IAVF_VF_ARQLEN1_ARQOVFL_MASK) {
dev_info(&adapter->pdev->dev, "ARQ Overflow Error detected\n");
- val &= ~I40E_VF_ARQLEN1_ARQOVFL_MASK;
+ val &= ~IAVF_VF_ARQLEN1_ARQOVFL_MASK;
}
- if (val & I40E_VF_ARQLEN1_ARQCRIT_MASK) {
+ if (val & IAVF_VF_ARQLEN1_ARQCRIT_MASK) {
dev_info(&adapter->pdev->dev, "ARQ Critical Error detected\n");
- val &= ~I40E_VF_ARQLEN1_ARQCRIT_MASK;
+ val &= ~IAVF_VF_ARQLEN1_ARQCRIT_MASK;
}
if (oldval != val)
wr32(hw, hw->aq.arq.len, val);
val = rd32(hw, hw->aq.asq.len);
oldval = val;
- if (val & I40E_VF_ATQLEN1_ATQVFE_MASK) {
+ if (val & IAVF_VF_ATQLEN1_ATQVFE_MASK) {
dev_info(&adapter->pdev->dev, "ASQ VF Error detected\n");
- val &= ~I40E_VF_ATQLEN1_ATQVFE_MASK;
+ val &= ~IAVF_VF_ATQLEN1_ATQVFE_MASK;
}
- if (val & I40E_VF_ATQLEN1_ATQOVFL_MASK) {
+ if (val & IAVF_VF_ATQLEN1_ATQOVFL_MASK) {
dev_info(&adapter->pdev->dev, "ASQ Overflow Error detected\n");
- val &= ~I40E_VF_ATQLEN1_ATQOVFL_MASK;
+ val &= ~IAVF_VF_ATQLEN1_ATQOVFL_MASK;
}
- if (val & I40E_VF_ATQLEN1_ATQCRIT_MASK) {
+ if (val & IAVF_VF_ATQLEN1_ATQCRIT_MASK) {
dev_info(&adapter->pdev->dev, "ASQ Critical Error detected\n");
- val &= ~I40E_VF_ATQLEN1_ATQCRIT_MASK;
+ val &= ~IAVF_VF_ATQLEN1_ATQCRIT_MASK;
}
if (oldval != val)
wr32(hw, hw->aq.asq.len, val);
@@ -2097,58 +2094,58 @@ freedom:
kfree(event.msg_buf);
out:
/* re-enable Admin queue interrupt cause */
- i40evf_misc_irq_enable(adapter);
+ iavf_misc_irq_enable(adapter);
}
/**
- * i40evf_client_task - worker thread to perform client work
+ * iavf_client_task - worker thread to perform client work
* @work: pointer to work_struct containing our data
*
* This task handles client interactions. Because client calls can be
* reentrant, we can't handle them in the watchdog.
**/
-static void i40evf_client_task(struct work_struct *work)
+static void iavf_client_task(struct work_struct *work)
{
- struct i40evf_adapter *adapter =
- container_of(work, struct i40evf_adapter, client_task.work);
+ struct iavf_adapter *adapter =
+ container_of(work, struct iavf_adapter, client_task.work);
/* If we can't get the client bit, just give up. We'll be rescheduled
* later.
*/
- if (test_and_set_bit(__I40EVF_IN_CLIENT_TASK, &adapter->crit_section))
+ if (test_and_set_bit(__IAVF_IN_CLIENT_TASK, &adapter->crit_section))
return;
- if (adapter->flags & I40EVF_FLAG_SERVICE_CLIENT_REQUESTED) {
- i40evf_client_subtask(adapter);
- adapter->flags &= ~I40EVF_FLAG_SERVICE_CLIENT_REQUESTED;
+ if (adapter->flags & IAVF_FLAG_SERVICE_CLIENT_REQUESTED) {
+ iavf_client_subtask(adapter);
+ adapter->flags &= ~IAVF_FLAG_SERVICE_CLIENT_REQUESTED;
goto out;
}
- if (adapter->flags & I40EVF_FLAG_CLIENT_NEEDS_L2_PARAMS) {
- i40evf_notify_client_l2_params(&adapter->vsi);
- adapter->flags &= ~I40EVF_FLAG_CLIENT_NEEDS_L2_PARAMS;
+ if (adapter->flags & IAVF_FLAG_CLIENT_NEEDS_L2_PARAMS) {
+ iavf_notify_client_l2_params(&adapter->vsi);
+ adapter->flags &= ~IAVF_FLAG_CLIENT_NEEDS_L2_PARAMS;
goto out;
}
- if (adapter->flags & I40EVF_FLAG_CLIENT_NEEDS_CLOSE) {
- i40evf_notify_client_close(&adapter->vsi, false);
- adapter->flags &= ~I40EVF_FLAG_CLIENT_NEEDS_CLOSE;
+ if (adapter->flags & IAVF_FLAG_CLIENT_NEEDS_CLOSE) {
+ iavf_notify_client_close(&adapter->vsi, false);
+ adapter->flags &= ~IAVF_FLAG_CLIENT_NEEDS_CLOSE;
goto out;
}
- if (adapter->flags & I40EVF_FLAG_CLIENT_NEEDS_OPEN) {
- i40evf_notify_client_open(&adapter->vsi);
- adapter->flags &= ~I40EVF_FLAG_CLIENT_NEEDS_OPEN;
+ if (adapter->flags & IAVF_FLAG_CLIENT_NEEDS_OPEN) {
+ iavf_notify_client_open(&adapter->vsi);
+ adapter->flags &= ~IAVF_FLAG_CLIENT_NEEDS_OPEN;
}
out:
- clear_bit(__I40EVF_IN_CLIENT_TASK, &adapter->crit_section);
+ clear_bit(__IAVF_IN_CLIENT_TASK, &adapter->crit_section);
}
/**
- * i40evf_free_all_tx_resources - Free Tx Resources for All Queues
+ * iavf_free_all_tx_resources - Free Tx Resources for All Queues
* @adapter: board private structure
*
* Free all transmit software resources
**/
-void i40evf_free_all_tx_resources(struct i40evf_adapter *adapter)
+void iavf_free_all_tx_resources(struct iavf_adapter *adapter)
{
int i;
@@ -2157,11 +2154,11 @@ void i40evf_free_all_tx_resources(struct i40evf_adapter *adapter)
for (i = 0; i < adapter->num_active_queues; i++)
if (adapter->tx_rings[i].desc)
- i40evf_free_tx_resources(&adapter->tx_rings[i]);
+ iavf_free_tx_resources(&adapter->tx_rings[i]);
}
/**
- * i40evf_setup_all_tx_resources - allocate all queues Tx resources
+ * iavf_setup_all_tx_resources - allocate all queues Tx resources
* @adapter: board private structure
*
* If this function returns with an error, then it's possible one or
@@ -2170,13 +2167,13 @@ void i40evf_free_all_tx_resources(struct i40evf_adapter *adapter)
*
* Return 0 on success, negative on failure
**/
-static int i40evf_setup_all_tx_resources(struct i40evf_adapter *adapter)
+static int iavf_setup_all_tx_resources(struct iavf_adapter *adapter)
{
int i, err = 0;
for (i = 0; i < adapter->num_active_queues; i++) {
adapter->tx_rings[i].count = adapter->tx_desc_count;
- err = i40evf_setup_tx_descriptors(&adapter->tx_rings[i]);
+ err = iavf_setup_tx_descriptors(&adapter->tx_rings[i]);
if (!err)
continue;
dev_err(&adapter->pdev->dev,
@@ -2188,7 +2185,7 @@ static int i40evf_setup_all_tx_resources(struct i40evf_adapter *adapter)
}
/**
- * i40evf_setup_all_rx_resources - allocate all queues Rx resources
+ * iavf_setup_all_rx_resources - allocate all queues Rx resources
* @adapter: board private structure
*
* If this function returns with an error, then it's possible one or
@@ -2197,13 +2194,13 @@ static int i40evf_setup_all_tx_resources(struct i40evf_adapter *adapter)
*
* Return 0 on success, negative on failure
**/
-static int i40evf_setup_all_rx_resources(struct i40evf_adapter *adapter)
+static int iavf_setup_all_rx_resources(struct iavf_adapter *adapter)
{
int i, err = 0;
for (i = 0; i < adapter->num_active_queues; i++) {
adapter->rx_rings[i].count = adapter->rx_desc_count;
- err = i40evf_setup_rx_descriptors(&adapter->rx_rings[i]);
+ err = iavf_setup_rx_descriptors(&adapter->rx_rings[i]);
if (!err)
continue;
dev_err(&adapter->pdev->dev,
@@ -2214,12 +2211,12 @@ static int i40evf_setup_all_rx_resources(struct i40evf_adapter *adapter)
}
/**
- * i40evf_free_all_rx_resources - Free Rx Resources for All Queues
+ * iavf_free_all_rx_resources - Free Rx Resources for All Queues
* @adapter: board private structure
*
* Free all receive software resources
**/
-void i40evf_free_all_rx_resources(struct i40evf_adapter *adapter)
+void iavf_free_all_rx_resources(struct iavf_adapter *adapter)
{
int i;
@@ -2228,16 +2225,16 @@ void i40evf_free_all_rx_resources(struct i40evf_adapter *adapter)
for (i = 0; i < adapter->num_active_queues; i++)
if (adapter->rx_rings[i].desc)
- i40evf_free_rx_resources(&adapter->rx_rings[i]);
+ iavf_free_rx_resources(&adapter->rx_rings[i]);
}
/**
- * i40evf_validate_tx_bandwidth - validate the max Tx bandwidth
+ * iavf_validate_tx_bandwidth - validate the max Tx bandwidth
* @adapter: board private structure
* @max_tx_rate: max Tx bw for a tc
**/
-static int i40evf_validate_tx_bandwidth(struct i40evf_adapter *adapter,
- u64 max_tx_rate)
+static int iavf_validate_tx_bandwidth(struct iavf_adapter *adapter,
+ u64 max_tx_rate)
{
int speed = 0, ret = 0;
@@ -2274,7 +2271,7 @@ static int i40evf_validate_tx_bandwidth(struct i40evf_adapter *adapter,
}
/**
- * i40evf_validate_channel_config - validate queue mapping info
+ * iavf_validate_channel_config - validate queue mapping info
* @adapter: board private structure
* @mqprio_qopt: queue parameters
*
@@ -2282,15 +2279,15 @@ static int i40evf_validate_tx_bandwidth(struct i40evf_adapter *adapter,
* configure queue channels is valid or not. Returns 0 on a valid
* config.
**/
-static int i40evf_validate_ch_config(struct i40evf_adapter *adapter,
- struct tc_mqprio_qopt_offload *mqprio_qopt)
+static int iavf_validate_ch_config(struct iavf_adapter *adapter,
+ struct tc_mqprio_qopt_offload *mqprio_qopt)
{
u64 total_max_rate = 0;
int i, num_qps = 0;
u64 tx_rate = 0;
int ret = 0;
- if (mqprio_qopt->qopt.num_tc > I40EVF_MAX_TRAFFIC_CLASS ||
+ if (mqprio_qopt->qopt.num_tc > IAVF_MAX_TRAFFIC_CLASS ||
mqprio_qopt->qopt.num_tc < 1)
return -EINVAL;
@@ -2305,24 +2302,24 @@ static int i40evf_validate_ch_config(struct i40evf_adapter *adapter,
}
/*convert to Mbps */
tx_rate = div_u64(mqprio_qopt->max_rate[i],
- I40EVF_MBPS_DIVISOR);
+ IAVF_MBPS_DIVISOR);
total_max_rate += tx_rate;
num_qps += mqprio_qopt->qopt.count[i];
}
- if (num_qps > I40EVF_MAX_REQ_QUEUES)
+ if (num_qps > IAVF_MAX_REQ_QUEUES)
return -EINVAL;
- ret = i40evf_validate_tx_bandwidth(adapter, total_max_rate);
+ ret = iavf_validate_tx_bandwidth(adapter, total_max_rate);
return ret;
}
/**
- * i40evf_del_all_cloud_filters - delete all cloud filters
+ * iavf_del_all_cloud_filters - delete all cloud filters
* on the traffic classes
**/
-static void i40evf_del_all_cloud_filters(struct i40evf_adapter *adapter)
+static void iavf_del_all_cloud_filters(struct iavf_adapter *adapter)
{
- struct i40evf_cloud_filter *cf, *cftmp;
+ struct iavf_cloud_filter *cf, *cftmp;
spin_lock_bh(&adapter->cloud_filter_list_lock);
list_for_each_entry_safe(cf, cftmp, &adapter->cloud_filter_list,
@@ -2335,7 +2332,7 @@ static void i40evf_del_all_cloud_filters(struct i40evf_adapter *adapter)
}
/**
- * __i40evf_setup_tc - configure multiple traffic classes
+ * __iavf_setup_tc - configure multiple traffic classes
* @netdev: network interface device structure
* @type_date: tc offload data
*
@@ -2345,10 +2342,10 @@ static void i40evf_del_all_cloud_filters(struct i40evf_adapter *adapter)
*
* Returns 0 on success.
**/
-static int __i40evf_setup_tc(struct net_device *netdev, void *type_data)
+static int __iavf_setup_tc(struct net_device *netdev, void *type_data)
{
struct tc_mqprio_qopt_offload *mqprio_qopt = type_data;
- struct i40evf_adapter *adapter = netdev_priv(netdev);
+ struct iavf_adapter *adapter = netdev_priv(netdev);
struct virtchnl_vf_resource *vfres = adapter->vf_res;
u8 num_tc = 0, total_qps = 0;
int ret = 0, netdev_tc = 0;
@@ -2361,14 +2358,14 @@ static int __i40evf_setup_tc(struct net_device *netdev, void *type_data)
/* delete queue_channel */
if (!mqprio_qopt->qopt.hw) {
- if (adapter->ch_config.state == __I40EVF_TC_RUNNING) {
+ if (adapter->ch_config.state == __IAVF_TC_RUNNING) {
/* reset the tc configuration */
netdev_reset_tc(netdev);
adapter->num_tc = 0;
netif_tx_stop_all_queues(netdev);
netif_tx_disable(netdev);
- i40evf_del_all_cloud_filters(adapter);
- adapter->aq_required = I40EVF_FLAG_AQ_DISABLE_CHANNELS;
+ iavf_del_all_cloud_filters(adapter);
+ adapter->aq_required = IAVF_FLAG_AQ_DISABLE_CHANNELS;
goto exit;
} else {
return -EINVAL;
@@ -2381,12 +2378,12 @@ static int __i40evf_setup_tc(struct net_device *netdev, void *type_data)
dev_err(&adapter->pdev->dev, "ADq not supported\n");
return -EOPNOTSUPP;
}
- if (adapter->ch_config.state != __I40EVF_TC_INVALID) {
+ if (adapter->ch_config.state != __IAVF_TC_INVALID) {
dev_err(&adapter->pdev->dev, "TC configuration already exists\n");
return -EINVAL;
}
- ret = i40evf_validate_ch_config(adapter, mqprio_qopt);
+ ret = iavf_validate_ch_config(adapter, mqprio_qopt);
if (ret)
return ret;
/* Return if same TC config is requested */
@@ -2394,7 +2391,7 @@ static int __i40evf_setup_tc(struct net_device *netdev, void *type_data)
return 0;
adapter->num_tc = num_tc;
- for (i = 0; i < I40EVF_MAX_TRAFFIC_CLASS; i++) {
+ for (i = 0; i < IAVF_MAX_TRAFFIC_CLASS; i++) {
if (i < num_tc) {
adapter->ch_config.ch_info[i].count =
mqprio_qopt->qopt.count[i];
@@ -2404,7 +2401,7 @@ static int __i40evf_setup_tc(struct net_device *netdev, void *type_data)
max_tx_rate = mqprio_qopt->max_rate[i];
/* convert to Mbps */
max_tx_rate = div_u64(max_tx_rate,
- I40EVF_MBPS_DIVISOR);
+ IAVF_MBPS_DIVISOR);
adapter->ch_config.ch_info[i].max_tx_rate =
max_tx_rate;
} else {
@@ -2415,11 +2412,11 @@ static int __i40evf_setup_tc(struct net_device *netdev, void *type_data)
adapter->ch_config.total_qps = total_qps;
netif_tx_stop_all_queues(netdev);
netif_tx_disable(netdev);
- adapter->aq_required |= I40EVF_FLAG_AQ_ENABLE_CHANNELS;
+ adapter->aq_required |= IAVF_FLAG_AQ_ENABLE_CHANNELS;
netdev_reset_tc(netdev);
/* Report the tc mapping up the stack */
netdev_set_num_tc(adapter->netdev, num_tc);
- for (i = 0; i < I40EVF_MAX_TRAFFIC_CLASS; i++) {
+ for (i = 0; i < IAVF_MAX_TRAFFIC_CLASS; i++) {
u16 qcount = mqprio_qopt->qopt.count[i];
u16 qoffset = mqprio_qopt->qopt.offset[i];
@@ -2433,14 +2430,14 @@ exit:
}
/**
- * i40evf_parse_cls_flower - Parse tc flower filters provided by kernel
+ * iavf_parse_cls_flower - Parse tc flower filters provided by kernel
* @adapter: board private structure
* @cls_flower: pointer to struct tc_cls_flower_offload
* @filter: pointer to cloud filter structure
*/
-static int i40evf_parse_cls_flower(struct i40evf_adapter *adapter,
- struct tc_cls_flower_offload *f,
- struct i40evf_cloud_filter *filter)
+static int iavf_parse_cls_flower(struct iavf_adapter *adapter,
+ struct tc_cls_flower_offload *f,
+ struct iavf_cloud_filter *filter)
{
u16 n_proto_mask = 0;
u16 n_proto_key = 0;
@@ -2471,7 +2468,7 @@ static int i40evf_parse_cls_flower(struct i40evf_adapter *adapter,
f->mask);
if (mask->keyid != 0)
- field_flags |= I40EVF_CLOUD_FIELD_TEN_ID;
+ field_flags |= IAVF_CLOUD_FIELD_TEN_ID;
}
if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_BASIC)) {
@@ -2518,7 +2515,7 @@ static int i40evf_parse_cls_flower(struct i40evf_adapter *adapter,
/* use is_broadcast and is_zero to check for all 0xf or 0 */
if (!is_zero_ether_addr(mask->dst)) {
if (is_broadcast_ether_addr(mask->dst)) {
- field_flags |= I40EVF_CLOUD_FIELD_OMAC;
+ field_flags |= IAVF_CLOUD_FIELD_OMAC;
} else {
dev_err(&adapter->pdev->dev, "Bad ether dest mask %pM\n",
mask->dst);
@@ -2528,7 +2525,7 @@ static int i40evf_parse_cls_flower(struct i40evf_adapter *adapter,
if (!is_zero_ether_addr(mask->src)) {
if (is_broadcast_ether_addr(mask->src)) {
- field_flags |= I40EVF_CLOUD_FIELD_IMAC;
+ field_flags |= IAVF_CLOUD_FIELD_IMAC;
} else {
dev_err(&adapter->pdev->dev, "Bad ether src mask %pM\n",
mask->src);
@@ -2569,7 +2566,7 @@ static int i40evf_parse_cls_flower(struct i40evf_adapter *adapter,
if (mask->vlan_id) {
if (mask->vlan_id == VLAN_VID_MASK) {
- field_flags |= I40EVF_CLOUD_FIELD_IVLAN;
+ field_flags |= IAVF_CLOUD_FIELD_IVLAN;
} else {
dev_err(&adapter->pdev->dev, "Bad vlan mask %u\n",
mask->vlan_id);
@@ -2601,7 +2598,7 @@ static int i40evf_parse_cls_flower(struct i40evf_adapter *adapter,
if (mask->dst) {
if (mask->dst == cpu_to_be32(0xffffffff)) {
- field_flags |= I40EVF_CLOUD_FIELD_IIP;
+ field_flags |= IAVF_CLOUD_FIELD_IIP;
} else {
dev_err(&adapter->pdev->dev, "Bad ip dst mask 0x%08x\n",
be32_to_cpu(mask->dst));
@@ -2611,7 +2608,7 @@ static int i40evf_parse_cls_flower(struct i40evf_adapter *adapter,
if (mask->src) {
if (mask->src == cpu_to_be32(0xffffffff)) {
- field_flags |= I40EVF_CLOUD_FIELD_IIP;
+ field_flags |= IAVF_CLOUD_FIELD_IIP;
} else {
dev_err(&adapter->pdev->dev, "Bad ip src mask 0x%08x\n",
be32_to_cpu(mask->dst));
@@ -2619,7 +2616,7 @@ static int i40evf_parse_cls_flower(struct i40evf_adapter *adapter,
}
}
- if (field_flags & I40EVF_CLOUD_FIELD_TEN_ID) {
+ if (field_flags & IAVF_CLOUD_FIELD_TEN_ID) {
dev_info(&adapter->pdev->dev, "Tenant id not allowed for ip filter\n");
return I40E_ERR_CONFIG;
}
@@ -2660,7 +2657,7 @@ static int i40evf_parse_cls_flower(struct i40evf_adapter *adapter,
return I40E_ERR_CONFIG;
}
if (!ipv6_addr_any(&mask->dst) || !ipv6_addr_any(&mask->src))
- field_flags |= I40EVF_CLOUD_FIELD_IIP;
+ field_flags |= IAVF_CLOUD_FIELD_IIP;
for (i = 0; i < 4; i++)
vf->mask.tcp_spec.dst_ip[i] |= cpu_to_be32(0xffffffff);
@@ -2683,7 +2680,7 @@ static int i40evf_parse_cls_flower(struct i40evf_adapter *adapter,
if (mask->src) {
if (mask->src == cpu_to_be16(0xffff)) {
- field_flags |= I40EVF_CLOUD_FIELD_IIP;
+ field_flags |= IAVF_CLOUD_FIELD_IIP;
} else {
dev_err(&adapter->pdev->dev, "Bad src port mask %u\n",
be16_to_cpu(mask->src));
@@ -2693,7 +2690,7 @@ static int i40evf_parse_cls_flower(struct i40evf_adapter *adapter,
if (mask->dst) {
if (mask->dst == cpu_to_be16(0xffff)) {
- field_flags |= I40EVF_CLOUD_FIELD_IIP;
+ field_flags |= IAVF_CLOUD_FIELD_IIP;
} else {
dev_err(&adapter->pdev->dev, "Bad dst port mask %u\n",
be16_to_cpu(mask->dst));
@@ -2716,13 +2713,13 @@ static int i40evf_parse_cls_flower(struct i40evf_adapter *adapter,
}
/**
- * i40evf_handle_tclass - Forward to a traffic class on the device
+ * iavf_handle_tclass - Forward to a traffic class on the device
* @adapter: board private structure
* @tc: traffic class index on the device
* @filter: pointer to cloud filter structure
*/
-static int i40evf_handle_tclass(struct i40evf_adapter *adapter, u32 tc,
- struct i40evf_cloud_filter *filter)
+static int iavf_handle_tclass(struct iavf_adapter *adapter, u32 tc,
+ struct iavf_cloud_filter *filter)
{
if (tc == 0)
return 0;
@@ -2740,15 +2737,15 @@ static int i40evf_handle_tclass(struct i40evf_adapter *adapter, u32 tc,
}
/**
- * i40evf_configure_clsflower - Add tc flower filters
+ * iavf_configure_clsflower - Add tc flower filters
* @adapter: board private structure
* @cls_flower: Pointer to struct tc_cls_flower_offload
*/
-static int i40evf_configure_clsflower(struct i40evf_adapter *adapter,
- struct tc_cls_flower_offload *cls_flower)
+static int iavf_configure_clsflower(struct iavf_adapter *adapter,
+ struct tc_cls_flower_offload *cls_flower)
{
int tc = tc_classid_to_hwtc(adapter->netdev, cls_flower->classid);
- struct i40evf_cloud_filter *filter = NULL;
+ struct iavf_cloud_filter *filter = NULL;
int err = -EINVAL, count = 50;
if (tc < 0) {
@@ -2760,7 +2757,7 @@ static int i40evf_configure_clsflower(struct i40evf_adapter *adapter,
if (!filter)
return -ENOMEM;
- while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK,
+ while (test_and_set_bit(__IAVF_IN_CRITICAL_TASK,
&adapter->crit_section)) {
if (--count == 0)
goto err;
@@ -2773,11 +2770,11 @@ static int i40evf_configure_clsflower(struct i40evf_adapter *adapter,
memset(&filter->f.mask.tcp_spec, 0, sizeof(struct virtchnl_l4_spec));
/* start out with flow type and eth type IPv4 to begin with */
filter->f.flow_type = VIRTCHNL_TCP_V4_FLOW;
- err = i40evf_parse_cls_flower(adapter, cls_flower, filter);
+ err = iavf_parse_cls_flower(adapter, cls_flower, filter);
if (err < 0)
goto err;
- err = i40evf_handle_tclass(adapter, tc, filter);
+ err = iavf_handle_tclass(adapter, tc, filter);
if (err < 0)
goto err;
@@ -2786,27 +2783,27 @@ static int i40evf_configure_clsflower(struct i40evf_adapter *adapter,
list_add_tail(&filter->list, &adapter->cloud_filter_list);
adapter->num_cloud_filters++;
filter->add = true;
- adapter->aq_required |= I40EVF_FLAG_AQ_ADD_CLOUD_FILTER;
+ adapter->aq_required |= IAVF_FLAG_AQ_ADD_CLOUD_FILTER;
spin_unlock_bh(&adapter->cloud_filter_list_lock);
err:
if (err)
kfree(filter);
- clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
+ clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section);
return err;
}
-/* i40evf_find_cf - Find the cloud filter in the list
+/* iavf_find_cf - Find the cloud filter in the list
* @adapter: Board private structure
* @cookie: filter specific cookie
*
* Returns ptr to the filter object or NULL. Must be called while holding the
* cloud_filter_list_lock.
*/
-static struct i40evf_cloud_filter *i40evf_find_cf(struct i40evf_adapter *adapter,
- unsigned long *cookie)
+static struct iavf_cloud_filter *iavf_find_cf(struct iavf_adapter *adapter,
+ unsigned long *cookie)
{
- struct i40evf_cloud_filter *filter = NULL;
+ struct iavf_cloud_filter *filter = NULL;
if (!cookie)
return NULL;
@@ -2819,21 +2816,21 @@ static struct i40evf_cloud_filter *i40evf_find_cf(struct i40evf_adapter *adapter
}
/**
- * i40evf_delete_clsflower - Remove tc flower filters
+ * iavf_delete_clsflower - Remove tc flower filters
* @adapter: board private structure
* @cls_flower: Pointer to struct tc_cls_flower_offload
*/
-static int i40evf_delete_clsflower(struct i40evf_adapter *adapter,
- struct tc_cls_flower_offload *cls_flower)
+static int iavf_delete_clsflower(struct iavf_adapter *adapter,
+ struct tc_cls_flower_offload *cls_flower)
{
- struct i40evf_cloud_filter *filter = NULL;
+ struct iavf_cloud_filter *filter = NULL;
int err = 0;
spin_lock_bh(&adapter->cloud_filter_list_lock);
- filter = i40evf_find_cf(adapter, &cls_flower->cookie);
+ filter = iavf_find_cf(adapter, &cls_flower->cookie);
if (filter) {
filter->del = true;
- adapter->aq_required |= I40EVF_FLAG_AQ_DEL_CLOUD_FILTER;
+ adapter->aq_required |= IAVF_FLAG_AQ_DEL_CLOUD_FILTER;
} else {
err = -EINVAL;
}
@@ -2843,21 +2840,21 @@ static int i40evf_delete_clsflower(struct i40evf_adapter *adapter,
}
/**
- * i40evf_setup_tc_cls_flower - flower classifier offloads
+ * iavf_setup_tc_cls_flower - flower classifier offloads
* @netdev: net device to configure
* @type_data: offload data
*/
-static int i40evf_setup_tc_cls_flower(struct i40evf_adapter *adapter,
- struct tc_cls_flower_offload *cls_flower)
+static int iavf_setup_tc_cls_flower(struct iavf_adapter *adapter,
+ struct tc_cls_flower_offload *cls_flower)
{
if (cls_flower->common.chain_index)
return -EOPNOTSUPP;
switch (cls_flower->command) {
case TC_CLSFLOWER_REPLACE:
- return i40evf_configure_clsflower(adapter, cls_flower);
+ return iavf_configure_clsflower(adapter, cls_flower);
case TC_CLSFLOWER_DESTROY:
- return i40evf_delete_clsflower(adapter, cls_flower);
+ return iavf_delete_clsflower(adapter, cls_flower);
case TC_CLSFLOWER_STATS:
return -EOPNOTSUPP;
default:
@@ -2866,46 +2863,46 @@ static int i40evf_setup_tc_cls_flower(struct i40evf_adapter *adapter,
}
/**
- * i40evf_setup_tc_block_cb - block callback for tc
+ * iavf_setup_tc_block_cb - block callback for tc
* @type: type of offload
* @type_data: offload data
* @cb_priv:
*
* This function is the block callback for traffic classes
**/
-static int i40evf_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
- void *cb_priv)
+static int iavf_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
+ void *cb_priv)
{
switch (type) {
case TC_SETUP_CLSFLOWER:
- return i40evf_setup_tc_cls_flower(cb_priv, type_data);
+ return iavf_setup_tc_cls_flower(cb_priv, type_data);
default:
return -EOPNOTSUPP;
}
}
/**
- * i40evf_setup_tc_block - register callbacks for tc
+ * iavf_setup_tc_block - register callbacks for tc
* @netdev: network interface device structure
* @f: tc offload data
*
* This function registers block callbacks for tc
* offloads
**/
-static int i40evf_setup_tc_block(struct net_device *dev,
- struct tc_block_offload *f)
+static int iavf_setup_tc_block(struct net_device *dev,
+ struct tc_block_offload *f)
{
- struct i40evf_adapter *adapter = netdev_priv(dev);
+ struct iavf_adapter *adapter = netdev_priv(dev);
if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
return -EOPNOTSUPP;
switch (f->command) {
case TC_BLOCK_BIND:
- return tcf_block_cb_register(f->block, i40evf_setup_tc_block_cb,
+ return tcf_block_cb_register(f->block, iavf_setup_tc_block_cb,
adapter, adapter, f->extack);
case TC_BLOCK_UNBIND:
- tcf_block_cb_unregister(f->block, i40evf_setup_tc_block_cb,
+ tcf_block_cb_unregister(f->block, iavf_setup_tc_block_cb,
adapter);
return 0;
default:
@@ -2914,7 +2911,7 @@ static int i40evf_setup_tc_block(struct net_device *dev,
}
/**
- * i40evf_setup_tc - configure multiple traffic classes
+ * iavf_setup_tc - configure multiple traffic classes
* @netdev: network interface device structure
* @type: type of offload
* @type_date: tc offload data
@@ -2924,21 +2921,21 @@ static int i40evf_setup_tc_block(struct net_device *dev,
*
* Returns 0 on success
**/
-static int i40evf_setup_tc(struct net_device *netdev, enum tc_setup_type type,
- void *type_data)
+static int iavf_setup_tc(struct net_device *netdev, enum tc_setup_type type,
+ void *type_data)
{
switch (type) {
case TC_SETUP_QDISC_MQPRIO:
- return __i40evf_setup_tc(netdev, type_data);
+ return __iavf_setup_tc(netdev, type_data);
case TC_SETUP_BLOCK:
- return i40evf_setup_tc_block(netdev, type_data);
+ return iavf_setup_tc_block(netdev, type_data);
default:
return -EOPNOTSUPP;
}
}
/**
- * i40evf_open - Called when a network interface is made active
+ * iavf_open - Called when a network interface is made active
* @netdev: network interface device structure
*
* Returns 0 on success, negative value on failure
@@ -2949,71 +2946,71 @@ static int i40evf_setup_tc(struct net_device *netdev, enum tc_setup_type type,
* handler is registered with the OS, the watchdog timer is started,
* and the stack is notified that the interface is ready.
**/
-static int i40evf_open(struct net_device *netdev)
+static int iavf_open(struct net_device *netdev)
{
- struct i40evf_adapter *adapter = netdev_priv(netdev);
+ struct iavf_adapter *adapter = netdev_priv(netdev);
int err;
- if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) {
+ if (adapter->flags & IAVF_FLAG_PF_COMMS_FAILED) {
dev_err(&adapter->pdev->dev, "Unable to open device due to PF driver failure.\n");
return -EIO;
}
- while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK,
+ while (test_and_set_bit(__IAVF_IN_CRITICAL_TASK,
&adapter->crit_section))
usleep_range(500, 1000);
- if (adapter->state != __I40EVF_DOWN) {
+ if (adapter->state != __IAVF_DOWN) {
err = -EBUSY;
goto err_unlock;
}
/* allocate transmit descriptors */
- err = i40evf_setup_all_tx_resources(adapter);
+ err = iavf_setup_all_tx_resources(adapter);
if (err)
goto err_setup_tx;
/* allocate receive descriptors */
- err = i40evf_setup_all_rx_resources(adapter);
+ err = iavf_setup_all_rx_resources(adapter);
if (err)
goto err_setup_rx;
/* clear any pending interrupts, may auto mask */
- err = i40evf_request_traffic_irqs(adapter, netdev->name);
+ err = iavf_request_traffic_irqs(adapter, netdev->name);
if (err)
goto err_req_irq;
spin_lock_bh(&adapter->mac_vlan_list_lock);
- i40evf_add_filter(adapter, adapter->hw.mac.addr);
+ iavf_add_filter(adapter, adapter->hw.mac.addr);
spin_unlock_bh(&adapter->mac_vlan_list_lock);
- i40evf_configure(adapter);
+ iavf_configure(adapter);
- i40evf_up_complete(adapter);
+ iavf_up_complete(adapter);
- i40evf_irq_enable(adapter, true);
+ iavf_irq_enable(adapter, true);
- clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
+ clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section);
return 0;
err_req_irq:
- i40evf_down(adapter);
- i40evf_free_traffic_irqs(adapter);
+ iavf_down(adapter);
+ iavf_free_traffic_irqs(adapter);
err_setup_rx:
- i40evf_free_all_rx_resources(adapter);
+ iavf_free_all_rx_resources(adapter);
err_setup_tx:
- i40evf_free_all_tx_resources(adapter);
+ iavf_free_all_tx_resources(adapter);
err_unlock:
- clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
+ clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section);
return err;
}
/**
- * i40evf_close - Disables a network interface
+ * iavf_close - Disables a network interface
* @netdev: network interface device structure
*
* Returns 0, this is not allowed to fail
@@ -3023,41 +3020,41 @@ err_unlock:
* needs to be disabled. All IRQs except vector 0 (reserved for admin queue)
* are freed, along with all transmit and receive resources.
**/
-static int i40evf_close(struct net_device *netdev)
+static int iavf_close(struct net_device *netdev)
{
- struct i40evf_adapter *adapter = netdev_priv(netdev);
+ struct iavf_adapter *adapter = netdev_priv(netdev);
int status;
- if (adapter->state <= __I40EVF_DOWN_PENDING)
+ if (adapter->state <= __IAVF_DOWN_PENDING)
return 0;
- while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK,
+ while (test_and_set_bit(__IAVF_IN_CRITICAL_TASK,
&adapter->crit_section))
usleep_range(500, 1000);
- set_bit(__I40E_VSI_DOWN, adapter->vsi.state);
+ set_bit(__IAVF_VSI_DOWN, adapter->vsi.state);
if (CLIENT_ENABLED(adapter))
- adapter->flags |= I40EVF_FLAG_CLIENT_NEEDS_CLOSE;
+ adapter->flags |= IAVF_FLAG_CLIENT_NEEDS_CLOSE;
- i40evf_down(adapter);
- adapter->state = __I40EVF_DOWN_PENDING;
- i40evf_free_traffic_irqs(adapter);
+ iavf_down(adapter);
+ adapter->state = __IAVF_DOWN_PENDING;
+ iavf_free_traffic_irqs(adapter);
- clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
+ clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section);
/* We explicitly don't free resources here because the hardware is
* still active and can DMA into memory. Resources are cleared in
- * i40evf_virtchnl_completion() after we get confirmation from the PF
+ * iavf_virtchnl_completion() after we get confirmation from the PF
* driver that the rings have been stopped.
*
- * Also, we wait for state to transition to __I40EVF_DOWN before
- * returning. State change occurs in i40evf_virtchnl_completion() after
+ * Also, we wait for state to transition to __IAVF_DOWN before
+ * returning. State change occurs in iavf_virtchnl_completion() after
* VF resources are released (which occurs after PF driver processes and
* responds to admin queue commands).
*/
status = wait_event_timeout(adapter->down_waitqueue,
- adapter->state == __I40EVF_DOWN,
+ adapter->state == __IAVF_DOWN,
msecs_to_jiffies(200));
if (!status)
netdev_warn(netdev, "Device resources not yet released\n");
@@ -3065,64 +3062,65 @@ static int i40evf_close(struct net_device *netdev)
}
/**
- * i40evf_change_mtu - Change the Maximum Transfer Unit
+ * iavf_change_mtu - Change the Maximum Transfer Unit
* @netdev: network interface device structure
* @new_mtu: new value for maximum frame size
*
* Returns 0 on success, negative on failure
**/
-static int i40evf_change_mtu(struct net_device *netdev, int new_mtu)
+static int iavf_change_mtu(struct net_device *netdev, int new_mtu)
{
- struct i40evf_adapter *adapter = netdev_priv(netdev);
+ struct iavf_adapter *adapter = netdev_priv(netdev);
netdev->mtu = new_mtu;
if (CLIENT_ENABLED(adapter)) {
- i40evf_notify_client_l2_params(&adapter->vsi);
- adapter->flags |= I40EVF_FLAG_SERVICE_CLIENT_REQUESTED;
+ iavf_notify_client_l2_params(&adapter->vsi);
+ adapter->flags |= IAVF_FLAG_SERVICE_CLIENT_REQUESTED;
}
- adapter->flags |= I40EVF_FLAG_RESET_NEEDED;
+ adapter->flags |= IAVF_FLAG_RESET_NEEDED;
schedule_work(&adapter->reset_task);
return 0;
}
/**
- * i40e_set_features - set the netdev feature flags
+ * iavf_set_features - set the netdev feature flags
* @netdev: ptr to the netdev being adjusted
* @features: the feature set that the stack is suggesting
* Note: expects to be called while under rtnl_lock()
**/
-static int i40evf_set_features(struct net_device *netdev,
- netdev_features_t features)
+static int iavf_set_features(struct net_device *netdev,
+ netdev_features_t features)
{
- struct i40evf_adapter *adapter = netdev_priv(netdev);
+ struct iavf_adapter *adapter = netdev_priv(netdev);
- /* Don't allow changing VLAN_RX flag when VLAN is set for VF
- * and return an error in this case
+ /* Don't allow changing VLAN_RX flag when adapter is not capable
+ * of VLAN offload
*/
- if (VLAN_ALLOWED(adapter)) {
+ if (!VLAN_ALLOWED(adapter)) {
+ if ((netdev->features ^ features) & NETIF_F_HW_VLAN_CTAG_RX)
+ return -EINVAL;
+ } else if ((netdev->features ^ features) & NETIF_F_HW_VLAN_CTAG_RX) {
if (features & NETIF_F_HW_VLAN_CTAG_RX)
adapter->aq_required |=
- I40EVF_FLAG_AQ_ENABLE_VLAN_STRIPPING;
+ IAVF_FLAG_AQ_ENABLE_VLAN_STRIPPING;
else
adapter->aq_required |=
- I40EVF_FLAG_AQ_DISABLE_VLAN_STRIPPING;
- } else if ((netdev->features ^ features) & NETIF_F_HW_VLAN_CTAG_RX) {
- return -EINVAL;
+ IAVF_FLAG_AQ_DISABLE_VLAN_STRIPPING;
}
return 0;
}
/**
- * i40evf_features_check - Validate encapsulated packet conforms to limits
+ * iavf_features_check - Validate encapsulated packet conforms to limits
* @skb: skb buff
* @dev: This physical port's netdev
* @features: Offload features that the stack believes apply
**/
-static netdev_features_t i40evf_features_check(struct sk_buff *skb,
- struct net_device *dev,
- netdev_features_t features)
+static netdev_features_t iavf_features_check(struct sk_buff *skb,
+ struct net_device *dev,
+ netdev_features_t features)
{
size_t len;
@@ -3173,16 +3171,16 @@ out_err:
}
/**
- * i40evf_fix_features - fix up the netdev feature bits
+ * iavf_fix_features - fix up the netdev feature bits
* @netdev: our net device
* @features: desired feature bits
*
* Returns fixed-up features bits
**/
-static netdev_features_t i40evf_fix_features(struct net_device *netdev,
- netdev_features_t features)
+static netdev_features_t iavf_fix_features(struct net_device *netdev,
+ netdev_features_t features)
{
- struct i40evf_adapter *adapter = netdev_priv(netdev);
+ struct iavf_adapter *adapter = netdev_priv(netdev);
if (!(adapter->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_VLAN))
features &= ~(NETIF_F_HW_VLAN_CTAG_TX |
@@ -3192,37 +3190,37 @@ static netdev_features_t i40evf_fix_features(struct net_device *netdev,
return features;
}
-static const struct net_device_ops i40evf_netdev_ops = {
- .ndo_open = i40evf_open,
- .ndo_stop = i40evf_close,
- .ndo_start_xmit = i40evf_xmit_frame,
- .ndo_set_rx_mode = i40evf_set_rx_mode,
+static const struct net_device_ops iavf_netdev_ops = {
+ .ndo_open = iavf_open,
+ .ndo_stop = iavf_close,
+ .ndo_start_xmit = iavf_xmit_frame,
+ .ndo_set_rx_mode = iavf_set_rx_mode,
.ndo_validate_addr = eth_validate_addr,
- .ndo_set_mac_address = i40evf_set_mac,
- .ndo_change_mtu = i40evf_change_mtu,
- .ndo_tx_timeout = i40evf_tx_timeout,
- .ndo_vlan_rx_add_vid = i40evf_vlan_rx_add_vid,
- .ndo_vlan_rx_kill_vid = i40evf_vlan_rx_kill_vid,
- .ndo_features_check = i40evf_features_check,
- .ndo_fix_features = i40evf_fix_features,
- .ndo_set_features = i40evf_set_features,
- .ndo_setup_tc = i40evf_setup_tc,
+ .ndo_set_mac_address = iavf_set_mac,
+ .ndo_change_mtu = iavf_change_mtu,
+ .ndo_tx_timeout = iavf_tx_timeout,
+ .ndo_vlan_rx_add_vid = iavf_vlan_rx_add_vid,
+ .ndo_vlan_rx_kill_vid = iavf_vlan_rx_kill_vid,
+ .ndo_features_check = iavf_features_check,
+ .ndo_fix_features = iavf_fix_features,
+ .ndo_set_features = iavf_set_features,
+ .ndo_setup_tc = iavf_setup_tc,
};
/**
- * i40evf_check_reset_complete - check that VF reset is complete
+ * iavf_check_reset_complete - check that VF reset is complete
* @hw: pointer to hw struct
*
* Returns 0 if device is ready to use, or -EBUSY if it's in reset.
**/
-static int i40evf_check_reset_complete(struct i40e_hw *hw)
+static int iavf_check_reset_complete(struct iavf_hw *hw)
{
u32 rstat;
int i;
for (i = 0; i < 100; i++) {
- rstat = rd32(hw, I40E_VFGEN_RSTAT) &
- I40E_VFGEN_RSTAT_VFR_STATE_MASK;
+ rstat = rd32(hw, IAVF_VFGEN_RSTAT) &
+ IAVF_VFGEN_RSTAT_VFR_STATE_MASK;
if ((rstat == VIRTCHNL_VFR_VFACTIVE) ||
(rstat == VIRTCHNL_VFR_COMPLETED))
return 0;
@@ -3232,18 +3230,18 @@ static int i40evf_check_reset_complete(struct i40e_hw *hw)
}
/**
- * i40evf_process_config - Process the config information we got from the PF
+ * iavf_process_config - Process the config information we got from the PF
* @adapter: board private structure
*
* Verify that we have a valid config struct, and set up our netdev features
* and our VSI struct.
**/
-int i40evf_process_config(struct i40evf_adapter *adapter)
+int iavf_process_config(struct iavf_adapter *adapter)
{
struct virtchnl_vf_resource *vfres = adapter->vf_res;
int i, num_req_queues = adapter->num_req_queues;
struct net_device *netdev = adapter->netdev;
- struct i40e_vsi *vsi = &adapter->vsi;
+ struct iavf_vsi *vsi = &adapter->vsi;
netdev_features_t hw_enc_features;
netdev_features_t hw_features;
@@ -3267,9 +3265,9 @@ int i40evf_process_config(struct i40evf_adapter *adapter)
"Requested %d queues, but PF only gave us %d.\n",
num_req_queues,
adapter->vsi_res->num_queue_pairs);
- adapter->flags |= I40EVF_FLAG_REINIT_ITR_NEEDED;
+ adapter->flags |= IAVF_FLAG_REINIT_ITR_NEEDED;
adapter->num_req_queues = adapter->vsi_res->num_queue_pairs;
- i40evf_schedule_reset(adapter);
+ iavf_schedule_reset(adapter);
return -ENODEV;
}
adapter->num_req_queues = 0;
@@ -3332,6 +3330,8 @@ int i40evf_process_config(struct i40evf_adapter *adapter)
if (vfres->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_VLAN)
netdev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
+ netdev->priv_flags |= IFF_UNICAST_FLT;
+
/* Do not turn on offloads when they are requested to be turned off.
* TSO needs minimum 576 bytes to work correctly.
*/
@@ -3354,22 +3354,22 @@ int i40evf_process_config(struct i40evf_adapter *adapter)
adapter->vsi.back = adapter;
adapter->vsi.base_vector = 1;
- adapter->vsi.work_limit = I40E_DEFAULT_IRQ_WORK;
+ adapter->vsi.work_limit = IAVF_DEFAULT_IRQ_WORK;
vsi->netdev = adapter->netdev;
vsi->qs_handle = adapter->vsi_res->qset_handle;
if (vfres->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_RSS_PF) {
adapter->rss_key_size = vfres->rss_key_size;
adapter->rss_lut_size = vfres->rss_lut_size;
} else {
- adapter->rss_key_size = I40EVF_HKEY_ARRAY_SIZE;
- adapter->rss_lut_size = I40EVF_HLUT_ARRAY_SIZE;
+ adapter->rss_key_size = IAVF_HKEY_ARRAY_SIZE;
+ adapter->rss_lut_size = IAVF_HLUT_ARRAY_SIZE;
}
return 0;
}
/**
- * i40evf_init_task - worker thread to perform delayed initialization
+ * iavf_init_task - worker thread to perform delayed initialization
* @work: pointer to work_struct containing our data
*
* This task completes the work that was begun in probe. Due to the nature
@@ -3380,65 +3380,65 @@ int i40evf_process_config(struct i40evf_adapter *adapter)
* communications with the PF driver and set up our netdev, the watchdog
* takes over.
**/
-static void i40evf_init_task(struct work_struct *work)
+static void iavf_init_task(struct work_struct *work)
{
- struct i40evf_adapter *adapter = container_of(work,
- struct i40evf_adapter,
+ struct iavf_adapter *adapter = container_of(work,
+ struct iavf_adapter,
init_task.work);
struct net_device *netdev = adapter->netdev;
- struct i40e_hw *hw = &adapter->hw;
+ struct iavf_hw *hw = &adapter->hw;
struct pci_dev *pdev = adapter->pdev;
int err, bufsz;
switch (adapter->state) {
- case __I40EVF_STARTUP:
+ case __IAVF_STARTUP:
/* driver loaded, probe complete */
- adapter->flags &= ~I40EVF_FLAG_PF_COMMS_FAILED;
- adapter->flags &= ~I40EVF_FLAG_RESET_PENDING;
- err = i40e_set_mac_type(hw);
+ adapter->flags &= ~IAVF_FLAG_PF_COMMS_FAILED;
+ adapter->flags &= ~IAVF_FLAG_RESET_PENDING;
+ err = iavf_set_mac_type(hw);
if (err) {
dev_err(&pdev->dev, "Failed to set MAC type (%d)\n",
err);
goto err;
}
- err = i40evf_check_reset_complete(hw);
+ err = iavf_check_reset_complete(hw);
if (err) {
dev_info(&pdev->dev, "Device is still in reset (%d), retrying\n",
err);
goto err;
}
- hw->aq.num_arq_entries = I40EVF_AQ_LEN;
- hw->aq.num_asq_entries = I40EVF_AQ_LEN;
- hw->aq.arq_buf_size = I40EVF_MAX_AQ_BUF_SIZE;
- hw->aq.asq_buf_size = I40EVF_MAX_AQ_BUF_SIZE;
+ hw->aq.num_arq_entries = IAVF_AQ_LEN;
+ hw->aq.num_asq_entries = IAVF_AQ_LEN;
+ hw->aq.arq_buf_size = IAVF_MAX_AQ_BUF_SIZE;
+ hw->aq.asq_buf_size = IAVF_MAX_AQ_BUF_SIZE;
- err = i40evf_init_adminq(hw);
+ err = iavf_init_adminq(hw);
if (err) {
dev_err(&pdev->dev, "Failed to init Admin Queue (%d)\n",
err);
goto err;
}
- err = i40evf_send_api_ver(adapter);
+ err = iavf_send_api_ver(adapter);
if (err) {
dev_err(&pdev->dev, "Unable to send to PF (%d)\n", err);
- i40evf_shutdown_adminq(hw);
+ iavf_shutdown_adminq(hw);
goto err;
}
- adapter->state = __I40EVF_INIT_VERSION_CHECK;
+ adapter->state = __IAVF_INIT_VERSION_CHECK;
goto restart;
- case __I40EVF_INIT_VERSION_CHECK:
- if (!i40evf_asq_done(hw)) {
+ case __IAVF_INIT_VERSION_CHECK:
+ if (!iavf_asq_done(hw)) {
dev_err(&pdev->dev, "Admin queue command never completed\n");
- i40evf_shutdown_adminq(hw);
- adapter->state = __I40EVF_STARTUP;
+ iavf_shutdown_adminq(hw);
+ adapter->state = __IAVF_STARTUP;
goto err;
}
/* aq msg sent, awaiting reply */
- err = i40evf_verify_api_ver(adapter);
+ err = iavf_verify_api_ver(adapter);
if (err) {
if (err == I40E_ERR_ADMIN_QUEUE_NO_WORK)
- err = i40evf_send_api_ver(adapter);
+ err = iavf_send_api_ver(adapter);
else
dev_err(&pdev->dev, "Unsupported PF API version %d.%d, expected %d.%d\n",
adapter->pf_version.major,
@@ -3447,34 +3447,34 @@ static void i40evf_init_task(struct work_struct *work)
VIRTCHNL_VERSION_MINOR);
goto err;
}
- err = i40evf_send_vf_config_msg(adapter);
+ err = iavf_send_vf_config_msg(adapter);
if (err) {
dev_err(&pdev->dev, "Unable to send config request (%d)\n",
err);
goto err;
}
- adapter->state = __I40EVF_INIT_GET_RESOURCES;
+ adapter->state = __IAVF_INIT_GET_RESOURCES;
goto restart;
- case __I40EVF_INIT_GET_RESOURCES:
+ case __IAVF_INIT_GET_RESOURCES:
/* aq msg sent, awaiting reply */
if (!adapter->vf_res) {
bufsz = sizeof(struct virtchnl_vf_resource) +
- (I40E_MAX_VF_VSI *
+ (IAVF_MAX_VF_VSI *
sizeof(struct virtchnl_vsi_resource));
adapter->vf_res = kzalloc(bufsz, GFP_KERNEL);
if (!adapter->vf_res)
goto err;
}
- err = i40evf_get_vf_config(adapter);
+ err = iavf_get_vf_config(adapter);
if (err == I40E_ERR_ADMIN_QUEUE_NO_WORK) {
- err = i40evf_send_vf_config_msg(adapter);
+ err = iavf_send_vf_config_msg(adapter);
goto err;
} else if (err == I40E_ERR_PARAM) {
/* We only get ERR_PARAM if the device is in a very bad
* state or if we've been disabled for previous bad
* behavior. Either way, we're done now.
*/
- i40evf_shutdown_adminq(hw);
+ iavf_shutdown_adminq(hw);
dev_err(&pdev->dev, "Unable to get VF config due to PF error condition, not retrying\n");
return;
}
@@ -3483,25 +3483,25 @@ static void i40evf_init_task(struct work_struct *work)
err);
goto err_alloc;
}
- adapter->state = __I40EVF_INIT_SW;
+ adapter->state = __IAVF_INIT_SW;
break;
default:
goto err_alloc;
}
- if (i40evf_process_config(adapter))
+ if (iavf_process_config(adapter))
goto err_alloc;
adapter->current_op = VIRTCHNL_OP_UNKNOWN;
- adapter->flags |= I40EVF_FLAG_RX_CSUM_ENABLED;
+ adapter->flags |= IAVF_FLAG_RX_CSUM_ENABLED;
- netdev->netdev_ops = &i40evf_netdev_ops;
- i40evf_set_ethtool_ops(netdev);
+ netdev->netdev_ops = &iavf_netdev_ops;
+ iavf_set_ethtool_ops(netdev);
netdev->watchdog_timeo = 5 * HZ;
/* MTU range: 68 - 9710 */
netdev->min_mtu = ETH_MIN_MTU;
- netdev->max_mtu = I40E_MAX_RXBUFFER - I40E_PACKET_HDR_PAD;
+ netdev->max_mtu = IAVF_MAX_RXBUFFER - IAVF_PACKET_HDR_PAD;
if (!is_valid_ether_addr(adapter->hw.mac.addr)) {
dev_info(&pdev->dev, "Invalid MAC address %pM, using random\n",
@@ -3509,25 +3509,25 @@ static void i40evf_init_task(struct work_struct *work)
eth_hw_addr_random(netdev);
ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr);
} else {
- adapter->flags |= I40EVF_FLAG_ADDR_SET_BY_PF;
+ adapter->flags |= IAVF_FLAG_ADDR_SET_BY_PF;
ether_addr_copy(netdev->dev_addr, adapter->hw.mac.addr);
ether_addr_copy(netdev->perm_addr, adapter->hw.mac.addr);
}
- timer_setup(&adapter->watchdog_timer, i40evf_watchdog_timer, 0);
+ timer_setup(&adapter->watchdog_timer, iavf_watchdog_timer, 0);
mod_timer(&adapter->watchdog_timer, jiffies + 1);
- adapter->tx_desc_count = I40EVF_DEFAULT_TXD;
- adapter->rx_desc_count = I40EVF_DEFAULT_RXD;
- err = i40evf_init_interrupt_scheme(adapter);
+ adapter->tx_desc_count = IAVF_DEFAULT_TXD;
+ adapter->rx_desc_count = IAVF_DEFAULT_RXD;
+ err = iavf_init_interrupt_scheme(adapter);
if (err)
goto err_sw_init;
- i40evf_map_rings_to_vectors(adapter);
+ iavf_map_rings_to_vectors(adapter);
if (adapter->vf_res->vf_cap_flags &
VIRTCHNL_VF_OFFLOAD_WB_ON_ITR)
- adapter->flags |= I40EVF_FLAG_WB_ON_ITR_CAPABLE;
+ adapter->flags |= IAVF_FLAG_WB_ON_ITR_CAPABLE;
- err = i40evf_request_misc_irq(adapter);
+ err = iavf_request_misc_irq(adapter);
if (err)
goto err_sw_init;
@@ -3544,7 +3544,7 @@ static void i40evf_init_task(struct work_struct *work)
netif_tx_stop_all_queues(netdev);
if (CLIENT_ALLOWED(adapter)) {
- err = i40evf_lan_add_device(adapter);
+ err = iavf_lan_add_device(adapter);
if (err)
dev_info(&pdev->dev, "Failed to add VF to client API service list: %d\n",
err);
@@ -3554,9 +3554,9 @@ static void i40evf_init_task(struct work_struct *work)
if (netdev->features & NETIF_F_GRO)
dev_info(&pdev->dev, "GRO is enabled\n");
- adapter->state = __I40EVF_DOWN;
- set_bit(__I40E_VSI_DOWN, adapter->vsi.state);
- i40evf_misc_irq_enable(adapter);
+ adapter->state = __IAVF_DOWN;
+ set_bit(__IAVF_VSI_DOWN, adapter->vsi.state);
+ iavf_misc_irq_enable(adapter);
wake_up(&adapter->down_waitqueue);
adapter->rss_key = kzalloc(adapter->rss_key_size, GFP_KERNEL);
@@ -3565,31 +3565,31 @@ static void i40evf_init_task(struct work_struct *work)
goto err_mem;
if (RSS_AQ(adapter)) {
- adapter->aq_required |= I40EVF_FLAG_AQ_CONFIGURE_RSS;
+ adapter->aq_required |= IAVF_FLAG_AQ_CONFIGURE_RSS;
mod_timer_pending(&adapter->watchdog_timer, jiffies + 1);
} else {
- i40evf_init_rss(adapter);
+ iavf_init_rss(adapter);
}
return;
restart:
schedule_delayed_work(&adapter->init_task, msecs_to_jiffies(30));
return;
err_mem:
- i40evf_free_rss(adapter);
+ iavf_free_rss(adapter);
err_register:
- i40evf_free_misc_irq(adapter);
+ iavf_free_misc_irq(adapter);
err_sw_init:
- i40evf_reset_interrupt_capability(adapter);
+ iavf_reset_interrupt_capability(adapter);
err_alloc:
kfree(adapter->vf_res);
adapter->vf_res = NULL;
err:
/* Things went into the weeds, so try again later */
- if (++adapter->aq_wait_count > I40EVF_AQ_MAX_ERR) {
+ if (++adapter->aq_wait_count > IAVF_AQ_MAX_ERR) {
dev_err(&pdev->dev, "Failed to communicate with PF; waiting before retry\n");
- adapter->flags |= I40EVF_FLAG_PF_COMMS_FAILED;
- i40evf_shutdown_adminq(hw);
- adapter->state = __I40EVF_STARTUP;
+ adapter->flags |= IAVF_FLAG_PF_COMMS_FAILED;
+ iavf_shutdown_adminq(hw);
+ adapter->state = __IAVF_STARTUP;
schedule_delayed_work(&adapter->init_task, HZ * 5);
return;
}
@@ -3597,21 +3597,21 @@ err:
}
/**
- * i40evf_shutdown - Shutdown the device in preparation for a reboot
+ * iavf_shutdown - Shutdown the device in preparation for a reboot
* @pdev: pci device structure
**/
-static void i40evf_shutdown(struct pci_dev *pdev)
+static void iavf_shutdown(struct pci_dev *pdev)
{
struct net_device *netdev = pci_get_drvdata(pdev);
- struct i40evf_adapter *adapter = netdev_priv(netdev);
+ struct iavf_adapter *adapter = netdev_priv(netdev);
netif_device_detach(netdev);
if (netif_running(netdev))
- i40evf_close(netdev);
+ iavf_close(netdev);
/* Prevent the watchdog from running. */
- adapter->state = __I40EVF_REMOVE;
+ adapter->state = __IAVF_REMOVE;
adapter->aq_required = 0;
#ifdef CONFIG_PM
@@ -3622,21 +3622,21 @@ static void i40evf_shutdown(struct pci_dev *pdev)
}
/**
- * i40evf_probe - Device Initialization Routine
+ * iavf_probe - Device Initialization Routine
* @pdev: PCI device information struct
- * @ent: entry in i40evf_pci_tbl
+ * @ent: entry in iavf_pci_tbl
*
* Returns 0 on success, negative on failure
*
- * i40evf_probe initializes an adapter identified by a pci_dev structure.
+ * iavf_probe initializes an adapter identified by a pci_dev structure.
* The OS initialization, configuring of the adapter private structure,
* and a hardware reset occur.
**/
-static int i40evf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct net_device *netdev;
- struct i40evf_adapter *adapter = NULL;
- struct i40e_hw *hw = NULL;
+ struct iavf_adapter *adapter = NULL;
+ struct iavf_hw *hw = NULL;
int err;
err = pci_enable_device(pdev);
@@ -3653,7 +3653,7 @@ static int i40evf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
}
- err = pci_request_regions(pdev, i40evf_driver_name);
+ err = pci_request_regions(pdev, iavf_driver_name);
if (err) {
dev_err(&pdev->dev,
"pci_request_regions failed 0x%x\n", err);
@@ -3664,8 +3664,8 @@ static int i40evf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_master(pdev);
- netdev = alloc_etherdev_mq(sizeof(struct i40evf_adapter),
- I40EVF_MAX_REQ_QUEUES);
+ netdev = alloc_etherdev_mq(sizeof(struct iavf_adapter),
+ IAVF_MAX_REQ_QUEUES);
if (!netdev) {
err = -ENOMEM;
goto err_alloc_etherdev;
@@ -3683,7 +3683,7 @@ static int i40evf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
hw->back = adapter;
adapter->msg_enable = BIT(DEFAULT_DEBUG_LEVEL_SHIFT) - 1;
- adapter->state = __I40EVF_STARTUP;
+ adapter->state = __IAVF_STARTUP;
/* Call save state here because it relies on the adapter struct. */
pci_save_state(pdev);
@@ -3716,11 +3716,11 @@ static int i40evf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
INIT_LIST_HEAD(&adapter->vlan_filter_list);
INIT_LIST_HEAD(&adapter->cloud_filter_list);
- INIT_WORK(&adapter->reset_task, i40evf_reset_task);
- INIT_WORK(&adapter->adminq_task, i40evf_adminq_task);
- INIT_WORK(&adapter->watchdog_task, i40evf_watchdog_task);
- INIT_DELAYED_WORK(&adapter->client_task, i40evf_client_task);
- INIT_DELAYED_WORK(&adapter->init_task, i40evf_init_task);
+ INIT_WORK(&adapter->reset_task, iavf_reset_task);
+ INIT_WORK(&adapter->adminq_task, iavf_adminq_task);
+ INIT_WORK(&adapter->watchdog_task, iavf_watchdog_task);
+ INIT_DELAYED_WORK(&adapter->client_task, iavf_client_task);
+ INIT_DELAYED_WORK(&adapter->init_task, iavf_init_task);
schedule_delayed_work(&adapter->init_task,
msecs_to_jiffies(5 * (pdev->devfn & 0x07)));
@@ -3741,33 +3741,33 @@ err_dma:
#ifdef CONFIG_PM
/**
- * i40evf_suspend - Power management suspend routine
+ * iavf_suspend - Power management suspend routine
* @pdev: PCI device information struct
* @state: unused
*
* Called when the system (VM) is entering sleep/suspend.
**/
-static int i40evf_suspend(struct pci_dev *pdev, pm_message_t state)
+static int iavf_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct net_device *netdev = pci_get_drvdata(pdev);
- struct i40evf_adapter *adapter = netdev_priv(netdev);
+ struct iavf_adapter *adapter = netdev_priv(netdev);
int retval = 0;
netif_device_detach(netdev);
- while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK,
+ while (test_and_set_bit(__IAVF_IN_CRITICAL_TASK,
&adapter->crit_section))
usleep_range(500, 1000);
if (netif_running(netdev)) {
rtnl_lock();
- i40evf_down(adapter);
+ iavf_down(adapter);
rtnl_unlock();
}
- i40evf_free_misc_irq(adapter);
- i40evf_reset_interrupt_capability(adapter);
+ iavf_free_misc_irq(adapter);
+ iavf_reset_interrupt_capability(adapter);
- clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
+ clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section);
retval = pci_save_state(pdev);
if (retval)
@@ -3779,14 +3779,14 @@ static int i40evf_suspend(struct pci_dev *pdev, pm_message_t state)
}
/**
- * i40evf_resume - Power management resume routine
+ * iavf_resume - Power management resume routine
* @pdev: PCI device information struct
*
* Called when the system (VM) is resumed from sleep/suspend.
**/
-static int i40evf_resume(struct pci_dev *pdev)
+static int iavf_resume(struct pci_dev *pdev)
{
- struct i40evf_adapter *adapter = pci_get_drvdata(pdev);
+ struct iavf_adapter *adapter = pci_get_drvdata(pdev);
struct net_device *netdev = adapter->netdev;
u32 err;
@@ -3805,13 +3805,13 @@ static int i40evf_resume(struct pci_dev *pdev)
pci_set_master(pdev);
rtnl_lock();
- err = i40evf_set_interrupt_capability(adapter);
+ err = iavf_set_interrupt_capability(adapter);
if (err) {
rtnl_unlock();
dev_err(&pdev->dev, "Cannot enable MSI-X interrupts.\n");
return err;
}
- err = i40evf_request_misc_irq(adapter);
+ err = iavf_request_misc_irq(adapter);
rtnl_unlock();
if (err) {
dev_err(&pdev->dev, "Cannot get interrupt vector.\n");
@@ -3827,25 +3827,25 @@ static int i40evf_resume(struct pci_dev *pdev)
#endif /* CONFIG_PM */
/**
- * i40evf_remove - Device Removal Routine
+ * iavf_remove - Device Removal Routine
* @pdev: PCI device information struct
*
- * i40evf_remove is called by the PCI subsystem to alert the driver
+ * iavf_remove is called by the PCI subsystem to alert the driver
* that it should release a PCI device. The could be caused by a
* Hot-Plug event, or because the driver is going to be removed from
* memory.
**/
-static void i40evf_remove(struct pci_dev *pdev)
+static void iavf_remove(struct pci_dev *pdev)
{
struct net_device *netdev = pci_get_drvdata(pdev);
- struct i40evf_adapter *adapter = netdev_priv(netdev);
- struct i40evf_vlan_filter *vlf, *vlftmp;
- struct i40evf_mac_filter *f, *ftmp;
- struct i40evf_cloud_filter *cf, *cftmp;
- struct i40e_hw *hw = &adapter->hw;
+ struct iavf_adapter *adapter = netdev_priv(netdev);
+ struct iavf_vlan_filter *vlf, *vlftmp;
+ struct iavf_mac_filter *f, *ftmp;
+ struct iavf_cloud_filter *cf, *cftmp;
+ struct iavf_hw *hw = &adapter->hw;
int err;
/* Indicate we are in remove and not to run reset_task */
- set_bit(__I40EVF_IN_REMOVE_TASK, &adapter->crit_section);
+ set_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section);
cancel_delayed_work_sync(&adapter->init_task);
cancel_work_sync(&adapter->reset_task);
cancel_delayed_work_sync(&adapter->client_task);
@@ -3854,37 +3854,39 @@ static void i40evf_remove(struct pci_dev *pdev)
adapter->netdev_registered = false;
}
if (CLIENT_ALLOWED(adapter)) {
- err = i40evf_lan_del_device(adapter);
+ err = iavf_lan_del_device(adapter);
if (err)
dev_warn(&pdev->dev, "Failed to delete client device: %d\n",
err);
}
/* Shut down all the garbage mashers on the detention level */
- adapter->state = __I40EVF_REMOVE;
+ adapter->state = __IAVF_REMOVE;
adapter->aq_required = 0;
- adapter->flags &= ~I40EVF_FLAG_REINIT_ITR_NEEDED;
- i40evf_request_reset(adapter);
+ adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED;
+ iavf_request_reset(adapter);
msleep(50);
/* If the FW isn't responding, kick it once, but only once. */
- if (!i40evf_asq_done(hw)) {
- i40evf_request_reset(adapter);
+ if (!iavf_asq_done(hw)) {
+ iavf_request_reset(adapter);
msleep(50);
}
- i40evf_free_all_tx_resources(adapter);
- i40evf_free_all_rx_resources(adapter);
- i40evf_misc_irq_disable(adapter);
- i40evf_free_misc_irq(adapter);
- i40evf_reset_interrupt_capability(adapter);
- i40evf_free_q_vectors(adapter);
+ iavf_free_all_tx_resources(adapter);
+ iavf_free_all_rx_resources(adapter);
+ iavf_misc_irq_disable(adapter);
+ iavf_free_misc_irq(adapter);
+ iavf_reset_interrupt_capability(adapter);
+ iavf_free_q_vectors(adapter);
if (adapter->watchdog_timer.function)
del_timer_sync(&adapter->watchdog_timer);
- i40evf_free_rss(adapter);
+ cancel_work_sync(&adapter->adminq_task);
+
+ iavf_free_rss(adapter);
if (hw->aq.asq.count)
- i40evf_shutdown_adminq(hw);
+ iavf_shutdown_adminq(hw);
/* destroy the locks only once, here */
mutex_destroy(&hw->aq.arq_mutex);
@@ -3892,9 +3894,9 @@ static void i40evf_remove(struct pci_dev *pdev)
iounmap(hw->hw_addr);
pci_release_regions(pdev);
- i40evf_free_all_tx_resources(adapter);
- i40evf_free_all_rx_resources(adapter);
- i40evf_free_queues(adapter);
+ iavf_free_all_tx_resources(adapter);
+ iavf_free_all_rx_resources(adapter);
+ iavf_free_queues(adapter);
kfree(adapter->vf_res);
spin_lock_bh(&adapter->mac_vlan_list_lock);
/* If we got removed before an up/down sequence, we've got a filter
@@ -3926,57 +3928,57 @@ static void i40evf_remove(struct pci_dev *pdev)
pci_disable_device(pdev);
}
-static struct pci_driver i40evf_driver = {
- .name = i40evf_driver_name,
- .id_table = i40evf_pci_tbl,
- .probe = i40evf_probe,
- .remove = i40evf_remove,
+static struct pci_driver iavf_driver = {
+ .name = iavf_driver_name,
+ .id_table = iavf_pci_tbl,
+ .probe = iavf_probe,
+ .remove = iavf_remove,
#ifdef CONFIG_PM
- .suspend = i40evf_suspend,
- .resume = i40evf_resume,
+ .suspend = iavf_suspend,
+ .resume = iavf_resume,
#endif
- .shutdown = i40evf_shutdown,
+ .shutdown = iavf_shutdown,
};
/**
- * i40e_init_module - Driver Registration Routine
+ * iavf_init_module - Driver Registration Routine
*
- * i40e_init_module is the first routine called when the driver is
+ * iavf_init_module is the first routine called when the driver is
* loaded. All it does is register with the PCI subsystem.
**/
-static int __init i40evf_init_module(void)
+static int __init iavf_init_module(void)
{
int ret;
- pr_info("i40evf: %s - version %s\n", i40evf_driver_string,
- i40evf_driver_version);
+ pr_info("iavf: %s - version %s\n", iavf_driver_string,
+ iavf_driver_version);
- pr_info("%s\n", i40evf_copyright);
+ pr_info("%s\n", iavf_copyright);
- i40evf_wq = alloc_workqueue("%s", WQ_UNBOUND | WQ_MEM_RECLAIM, 1,
- i40evf_driver_name);
- if (!i40evf_wq) {
- pr_err("%s: Failed to create workqueue\n", i40evf_driver_name);
+ iavf_wq = alloc_workqueue("%s", WQ_UNBOUND | WQ_MEM_RECLAIM, 1,
+ iavf_driver_name);
+ if (!iavf_wq) {
+ pr_err("%s: Failed to create workqueue\n", iavf_driver_name);
return -ENOMEM;
}
- ret = pci_register_driver(&i40evf_driver);
+ ret = pci_register_driver(&iavf_driver);
return ret;
}
-module_init(i40evf_init_module);
+module_init(iavf_init_module);
/**
- * i40e_exit_module - Driver Exit Cleanup Routine
+ * iavf_exit_module - Driver Exit Cleanup Routine
*
- * i40e_exit_module is called just before the driver is removed
+ * iavf_exit_module is called just before the driver is removed
* from memory.
**/
-static void __exit i40evf_exit_module(void)
+static void __exit iavf_exit_module(void)
{
- pci_unregister_driver(&i40evf_driver);
- destroy_workqueue(i40evf_wq);
+ pci_unregister_driver(&iavf_driver);
+ destroy_workqueue(iavf_wq);
}
-module_exit(i40evf_exit_module);
+module_exit(iavf_exit_module);
-/* i40evf_main.c */
+/* iavf_main.c */
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_osdep.h b/drivers/net/ethernet/intel/iavf/iavf_osdep.h
index 3ddddb46455b..e6e0b0328706 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_osdep.h
+++ b/drivers/net/ethernet/intel/iavf/iavf_osdep.h
@@ -1,8 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright(c) 2013 - 2018 Intel Corporation. */
-#ifndef _I40E_OSDEP_H_
-#define _I40E_OSDEP_H_
+#ifndef _IAVF_OSDEP_H_
+#define _IAVF_OSDEP_H_
#include <linux/types.h>
#include <linux/if_ether.h>
@@ -24,29 +24,29 @@
#define wr64(a, reg, value) writeq((value), ((a)->hw_addr + (reg)))
#define rd64(a, reg) readq((a)->hw_addr + (reg))
-#define i40e_flush(a) readl((a)->hw_addr + I40E_VFGEN_RSTAT)
+#define iavf_flush(a) readl((a)->hw_addr + IAVF_VFGEN_RSTAT)
/* memory allocation tracking */
-struct i40e_dma_mem {
+struct iavf_dma_mem {
void *va;
dma_addr_t pa;
u32 size;
};
-#define i40e_allocate_dma_mem(h, m, unused, s, a) \
- i40evf_allocate_dma_mem_d(h, m, s, a)
-#define i40e_free_dma_mem(h, m) i40evf_free_dma_mem_d(h, m)
+#define iavf_allocate_dma_mem(h, m, unused, s, a) \
+ iavf_allocate_dma_mem_d(h, m, s, a)
+#define iavf_free_dma_mem(h, m) iavf_free_dma_mem_d(h, m)
-struct i40e_virt_mem {
+struct iavf_virt_mem {
void *va;
u32 size;
};
-#define i40e_allocate_virt_mem(h, m, s) i40evf_allocate_virt_mem_d(h, m, s)
-#define i40e_free_virt_mem(h, m) i40evf_free_virt_mem_d(h, m)
+#define iavf_allocate_virt_mem(h, m, s) iavf_allocate_virt_mem_d(h, m, s)
+#define iavf_free_virt_mem(h, m) iavf_free_virt_mem_d(h, m)
-#define i40e_debug(h, m, s, ...) i40evf_debug_d(h, m, s, ##__VA_ARGS__)
-extern void i40evf_debug_d(void *hw, u32 mask, char *fmt_str, ...)
+#define iavf_debug(h, m, s, ...) iavf_debug_d(h, m, s, ##__VA_ARGS__)
+extern void iavf_debug_d(void *hw, u32 mask, char *fmt_str, ...)
__attribute__ ((format(gnu_printf, 3, 4)));
-typedef enum i40e_status_code i40e_status;
-#endif /* _I40E_OSDEP_H_ */
+typedef enum iavf_status_code iavf_status;
+#endif /* _IAVF_OSDEP_H_ */
diff --git a/drivers/net/ethernet/intel/iavf/iavf_prototype.h b/drivers/net/ethernet/intel/iavf/iavf_prototype.h
new file mode 100644
index 000000000000..d6685103af39
--- /dev/null
+++ b/drivers/net/ethernet/intel/iavf/iavf_prototype.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
+
+#ifndef _IAVF_PROTOTYPE_H_
+#define _IAVF_PROTOTYPE_H_
+
+#include "iavf_type.h"
+#include "iavf_alloc.h"
+#include <linux/avf/virtchnl.h>
+
+/* Prototypes for shared code functions that are not in
+ * the standard function pointer structures. These are
+ * mostly because they are needed even before the init
+ * has happened and will assist in the early SW and FW
+ * setup.
+ */
+
+/* adminq functions */
+iavf_status iavf_init_adminq(struct iavf_hw *hw);
+iavf_status iavf_shutdown_adminq(struct iavf_hw *hw);
+void i40e_adminq_init_ring_data(struct iavf_hw *hw);
+iavf_status iavf_clean_arq_element(struct iavf_hw *hw,
+ struct i40e_arq_event_info *e,
+ u16 *events_pending);
+iavf_status iavf_asq_send_command(struct iavf_hw *hw, struct i40e_aq_desc *desc,
+ void *buff, /* can be NULL */
+ u16 buff_size,
+ struct i40e_asq_cmd_details *cmd_details);
+bool iavf_asq_done(struct iavf_hw *hw);
+
+/* debug function for adminq */
+void iavf_debug_aq(struct iavf_hw *hw, enum iavf_debug_mask mask,
+ void *desc, void *buffer, u16 buf_len);
+
+void i40e_idle_aq(struct iavf_hw *hw);
+void iavf_resume_aq(struct iavf_hw *hw);
+bool iavf_check_asq_alive(struct iavf_hw *hw);
+iavf_status iavf_aq_queue_shutdown(struct iavf_hw *hw, bool unloading);
+const char *iavf_aq_str(struct iavf_hw *hw, enum i40e_admin_queue_err aq_err);
+const char *iavf_stat_str(struct iavf_hw *hw, iavf_status stat_err);
+
+iavf_status iavf_aq_get_rss_lut(struct iavf_hw *hw, u16 seid,
+ bool pf_lut, u8 *lut, u16 lut_size);
+iavf_status iavf_aq_set_rss_lut(struct iavf_hw *hw, u16 seid,
+ bool pf_lut, u8 *lut, u16 lut_size);
+iavf_status iavf_aq_get_rss_key(struct iavf_hw *hw, u16 seid,
+ struct i40e_aqc_get_set_rss_key_data *key);
+iavf_status iavf_aq_set_rss_key(struct iavf_hw *hw, u16 seid,
+ struct i40e_aqc_get_set_rss_key_data *key);
+
+iavf_status iavf_set_mac_type(struct iavf_hw *hw);
+
+extern struct iavf_rx_ptype_decoded iavf_ptype_lookup[];
+
+static inline struct iavf_rx_ptype_decoded decode_rx_desc_ptype(u8 ptype)
+{
+ return iavf_ptype_lookup[ptype];
+}
+
+void iavf_vf_parse_hw_config(struct iavf_hw *hw,
+ struct virtchnl_vf_resource *msg);
+iavf_status iavf_vf_reset(struct iavf_hw *hw);
+iavf_status iavf_aq_send_msg_to_pf(struct iavf_hw *hw,
+ enum virtchnl_ops v_opcode,
+ iavf_status v_retval, u8 *msg, u16 msglen,
+ struct i40e_asq_cmd_details *cmd_details);
+#endif /* _IAVF_PROTOTYPE_H_ */
diff --git a/drivers/net/ethernet/intel/iavf/iavf_register.h b/drivers/net/ethernet/intel/iavf/iavf_register.h
new file mode 100644
index 000000000000..bf793332fc9d
--- /dev/null
+++ b/drivers/net/ethernet/intel/iavf/iavf_register.h
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
+
+#ifndef _IAVF_REGISTER_H_
+#define _IAVF_REGISTER_H_
+
+#define IAVF_VF_ARQBAH1 0x00006000 /* Reset: EMPR */
+#define IAVF_VF_ARQBAL1 0x00006C00 /* Reset: EMPR */
+#define IAVF_VF_ARQH1 0x00007400 /* Reset: EMPR */
+#define IAVF_VF_ARQH1_ARQH_SHIFT 0
+#define IAVF_VF_ARQH1_ARQH_MASK IAVF_MASK(0x3FF, IAVF_VF_ARQH1_ARQH_SHIFT)
+#define IAVF_VF_ARQLEN1 0x00008000 /* Reset: EMPR */
+#define IAVF_VF_ARQLEN1_ARQVFE_SHIFT 28
+#define IAVF_VF_ARQLEN1_ARQVFE_MASK IAVF_MASK(0x1, IAVF_VF_ARQLEN1_ARQVFE_SHIFT)
+#define IAVF_VF_ARQLEN1_ARQOVFL_SHIFT 29
+#define IAVF_VF_ARQLEN1_ARQOVFL_MASK IAVF_MASK(0x1, IAVF_VF_ARQLEN1_ARQOVFL_SHIFT)
+#define IAVF_VF_ARQLEN1_ARQCRIT_SHIFT 30
+#define IAVF_VF_ARQLEN1_ARQCRIT_MASK IAVF_MASK(0x1, IAVF_VF_ARQLEN1_ARQCRIT_SHIFT)
+#define IAVF_VF_ARQLEN1_ARQENABLE_SHIFT 31
+#define IAVF_VF_ARQLEN1_ARQENABLE_MASK IAVF_MASK(0x1, IAVF_VF_ARQLEN1_ARQENABLE_SHIFT)
+#define IAVF_VF_ARQT1 0x00007000 /* Reset: EMPR */
+#define IAVF_VF_ATQBAH1 0x00007800 /* Reset: EMPR */
+#define IAVF_VF_ATQBAL1 0x00007C00 /* Reset: EMPR */
+#define IAVF_VF_ATQH1 0x00006400 /* Reset: EMPR */
+#define IAVF_VF_ATQLEN1 0x00006800 /* Reset: EMPR */
+#define IAVF_VF_ATQLEN1_ATQVFE_SHIFT 28
+#define IAVF_VF_ATQLEN1_ATQVFE_MASK IAVF_MASK(0x1, IAVF_VF_ATQLEN1_ATQVFE_SHIFT)
+#define IAVF_VF_ATQLEN1_ATQOVFL_SHIFT 29
+#define IAVF_VF_ATQLEN1_ATQOVFL_MASK IAVF_MASK(0x1, IAVF_VF_ATQLEN1_ATQOVFL_SHIFT)
+#define IAVF_VF_ATQLEN1_ATQCRIT_SHIFT 30
+#define IAVF_VF_ATQLEN1_ATQCRIT_MASK IAVF_MASK(0x1, IAVF_VF_ATQLEN1_ATQCRIT_SHIFT)
+#define IAVF_VF_ATQLEN1_ATQENABLE_SHIFT 31
+#define IAVF_VF_ATQLEN1_ATQENABLE_MASK IAVF_MASK(0x1, IAVF_VF_ATQLEN1_ATQENABLE_SHIFT)
+#define IAVF_VF_ATQT1 0x00008400 /* Reset: EMPR */
+#define IAVF_VFGEN_RSTAT 0x00008800 /* Reset: VFR */
+#define IAVF_VFGEN_RSTAT_VFR_STATE_SHIFT 0
+#define IAVF_VFGEN_RSTAT_VFR_STATE_MASK IAVF_MASK(0x3, IAVF_VFGEN_RSTAT_VFR_STATE_SHIFT)
+#define IAVF_VFINT_DYN_CTL01 0x00005C00 /* Reset: VFR */
+#define IAVF_VFINT_DYN_CTL01_INTENA_SHIFT 0
+#define IAVF_VFINT_DYN_CTL01_INTENA_MASK IAVF_MASK(0x1, IAVF_VFINT_DYN_CTL01_INTENA_SHIFT)
+#define IAVF_VFINT_DYN_CTL01_ITR_INDX_SHIFT 3
+#define IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK IAVF_MASK(0x3, IAVF_VFINT_DYN_CTL01_ITR_INDX_SHIFT)
+#define IAVF_VFINT_DYN_CTLN1(_INTVF) (0x00003800 + ((_INTVF) * 4)) /* _i=0...15 */ /* Reset: VFR */
+#define IAVF_VFINT_DYN_CTLN1_INTENA_SHIFT 0
+#define IAVF_VFINT_DYN_CTLN1_INTENA_MASK IAVF_MASK(0x1, IAVF_VFINT_DYN_CTLN1_INTENA_SHIFT)
+#define IAVF_VFINT_DYN_CTLN1_SWINT_TRIG_SHIFT 2
+#define IAVF_VFINT_DYN_CTLN1_SWINT_TRIG_MASK IAVF_MASK(0x1, IAVF_VFINT_DYN_CTLN1_SWINT_TRIG_SHIFT)
+#define IAVF_VFINT_DYN_CTLN1_ITR_INDX_SHIFT 3
+#define IAVF_VFINT_DYN_CTLN1_ITR_INDX_MASK IAVF_MASK(0x3, IAVF_VFINT_DYN_CTLN1_ITR_INDX_SHIFT)
+#define IAVF_VFINT_DYN_CTLN1_INTERVAL_SHIFT 5
+#define IAVF_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_SHIFT 24
+#define IAVF_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_MASK IAVF_MASK(0x1, IAVF_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_SHIFT)
+#define IAVF_VFINT_ICR0_ENA1 0x00005000 /* Reset: CORER */
+#define IAVF_VFINT_ICR0_ENA1_ADMINQ_SHIFT 30
+#define IAVF_VFINT_ICR0_ENA1_ADMINQ_MASK IAVF_MASK(0x1, IAVF_VFINT_ICR0_ENA1_ADMINQ_SHIFT)
+#define IAVF_VFINT_ICR0_ENA1_RSVD_SHIFT 31
+#define IAVF_VFINT_ICR01 0x00004800 /* Reset: CORER */
+#define IAVF_VFINT_ITRN1(_i, _INTVF) (0x00002800 + ((_i) * 64 + (_INTVF) * 4)) /* _i=0...2, _INTVF=0...15 */ /* Reset: VFR */
+#define IAVF_QRX_TAIL1(_Q) (0x00002000 + ((_Q) * 4)) /* _i=0...15 */ /* Reset: CORER */
+#define IAVF_QTX_TAIL1(_Q) (0x00000000 + ((_Q) * 4)) /* _i=0...15 */ /* Reset: PFR */
+#define IAVF_VFQF_HENA(_i) (0x0000C400 + ((_i) * 4)) /* _i=0...1 */ /* Reset: CORER */
+#define IAVF_VFQF_HKEY(_i) (0x0000CC00 + ((_i) * 4)) /* _i=0...12 */ /* Reset: CORER */
+#define IAVF_VFQF_HKEY_MAX_INDEX 12
+#define IAVF_VFQF_HLUT(_i) (0x0000D000 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */
+#define IAVF_VFQF_HLUT_MAX_INDEX 15
+#define IAVF_VFINT_DYN_CTLN1_WB_ON_ITR_SHIFT 30
+#define IAVF_VFINT_DYN_CTLN1_WB_ON_ITR_MASK IAVF_MASK(0x1, IAVF_VFINT_DYN_CTLN1_WB_ON_ITR_SHIFT)
+#endif /* _IAVF_REGISTER_H_ */
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_status.h b/drivers/net/ethernet/intel/iavf/iavf_status.h
index 77be0702d07c..46742fab7b8c 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_status.h
+++ b/drivers/net/ethernet/intel/iavf/iavf_status.h
@@ -1,11 +1,11 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright(c) 2013 - 2018 Intel Corporation. */
-#ifndef _I40E_STATUS_H_
-#define _I40E_STATUS_H_
+#ifndef _IAVF_STATUS_H_
+#define _IAVF_STATUS_H_
/* Error Codes */
-enum i40e_status_code {
+enum iavf_status_code {
I40E_SUCCESS = 0,
I40E_ERR_NVM = -1,
I40E_ERR_NVM_CHECKSUM = -2,
@@ -75,4 +75,4 @@ enum i40e_status_code {
I40E_ERR_ADMIN_QUEUE_CRITICAL_ERROR = -66,
};
-#endif /* _I40E_STATUS_H_ */
+#endif /* _IAVF_STATUS_H_ */
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_trace.h b/drivers/net/ethernet/intel/iavf/iavf_trace.h
index d7a4e68820a8..1474f5539751 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_trace.h
+++ b/drivers/net/ethernet/intel/iavf/iavf_trace.h
@@ -3,16 +3,16 @@
/* Modeled on trace-events-sample.h */
-/* The trace subsystem name for i40evf will be "i40evf".
+/* The trace subsystem name for iavf will be "iavf".
*
- * This file is named i40e_trace.h.
+ * This file is named iavf_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 i40evf
+#define TRACE_SYSTEM iavf
/* See trace-events-sample.h for a detailed description of why this
* guard clause is different from most normal include files.
@@ -23,14 +23,14 @@
#include <linux/tracepoint.h>
/**
- * i40e_trace() macro enables shared code to refer to trace points
+ * iavf_trace() macro enables shared code to refer to trace points
* like:
*
- * trace_i40e{,vf}_example(args...)
+ * trace_iavf{,vf}_example(args...)
*
* ... as:
*
- * i40e_trace(example, args...)
+ * iavf_trace(example, args...)
*
* ... to resolve to the PF or VF version of the tracepoint without
* ifdefs, and to allow tracepoints to be disabled entirely at build
@@ -39,29 +39,29 @@
* Trace point should always be referred to in the driver via this
* macro.
*
- * Similarly, i40e_trace_enabled(trace_name) wraps references to
- * trace_i40e{,vf}_<trace_name>_enabled() functions.
+ * Similarly, iavf_trace_enabled(trace_name) wraps references to
+ * trace_iavf{,vf}_<trace_name>_enabled() functions.
*/
-#define _I40E_TRACE_NAME(trace_name) (trace_ ## i40evf ## _ ## trace_name)
-#define I40E_TRACE_NAME(trace_name) _I40E_TRACE_NAME(trace_name)
+#define _IAVF_TRACE_NAME(trace_name) (trace_ ## iavf ## _ ## trace_name)
+#define IAVF_TRACE_NAME(trace_name) _IAVF_TRACE_NAME(trace_name)
-#define i40e_trace(trace_name, args...) I40E_TRACE_NAME(trace_name)(args)
+#define iavf_trace(trace_name, args...) IAVF_TRACE_NAME(trace_name)(args)
-#define i40e_trace_enabled(trace_name) I40E_TRACE_NAME(trace_name##_enabled)()
+#define iavf_trace_enabled(trace_name) IAVF_TRACE_NAME(trace_name##_enabled)()
/* Events common to PF and VF. Corresponding versions will be defined
- * for both, named trace_i40e_* and trace_i40evf_*. The i40e_trace()
+ * for both, named trace_iavf_* and trace_iavf_*. The iavf_trace()
* macro above will select the right trace point name for the driver
* being built from shared code.
*/
/* Events related to a vsi & ring */
DECLARE_EVENT_CLASS(
- i40evf_tx_template,
+ iavf_tx_template,
- TP_PROTO(struct i40e_ring *ring,
- struct i40e_tx_desc *desc,
- struct i40e_tx_buffer *buf),
+ TP_PROTO(struct iavf_ring *ring,
+ struct iavf_tx_desc *desc,
+ struct iavf_tx_buffer *buf),
TP_ARGS(ring, desc, buf),
@@ -93,26 +93,26 @@ DECLARE_EVENT_CLASS(
);
DEFINE_EVENT(
- i40evf_tx_template, i40evf_clean_tx_irq,
- TP_PROTO(struct i40e_ring *ring,
- struct i40e_tx_desc *desc,
- struct i40e_tx_buffer *buf),
+ iavf_tx_template, iavf_clean_tx_irq,
+ TP_PROTO(struct iavf_ring *ring,
+ struct iavf_tx_desc *desc,
+ struct iavf_tx_buffer *buf),
TP_ARGS(ring, desc, buf));
DEFINE_EVENT(
- i40evf_tx_template, i40evf_clean_tx_irq_unmap,
- TP_PROTO(struct i40e_ring *ring,
- struct i40e_tx_desc *desc,
- struct i40e_tx_buffer *buf),
+ iavf_tx_template, iavf_clean_tx_irq_unmap,
+ TP_PROTO(struct iavf_ring *ring,
+ struct iavf_tx_desc *desc,
+ struct iavf_tx_buffer *buf),
TP_ARGS(ring, desc, buf));
DECLARE_EVENT_CLASS(
- i40evf_rx_template,
+ iavf_rx_template,
- TP_PROTO(struct i40e_ring *ring,
- union i40e_32byte_rx_desc *desc,
+ TP_PROTO(struct iavf_ring *ring,
+ union iavf_32byte_rx_desc *desc,
struct sk_buff *skb),
TP_ARGS(ring, desc, skb),
@@ -138,26 +138,26 @@ DECLARE_EVENT_CLASS(
);
DEFINE_EVENT(
- i40evf_rx_template, i40evf_clean_rx_irq,
- TP_PROTO(struct i40e_ring *ring,
- union i40e_32byte_rx_desc *desc,
+ iavf_rx_template, iavf_clean_rx_irq,
+ TP_PROTO(struct iavf_ring *ring,
+ union iavf_32byte_rx_desc *desc,
struct sk_buff *skb),
TP_ARGS(ring, desc, skb));
DEFINE_EVENT(
- i40evf_rx_template, i40evf_clean_rx_irq_rx,
- TP_PROTO(struct i40e_ring *ring,
- union i40e_32byte_rx_desc *desc,
+ iavf_rx_template, iavf_clean_rx_irq_rx,
+ TP_PROTO(struct iavf_ring *ring,
+ union iavf_32byte_rx_desc *desc,
struct sk_buff *skb),
TP_ARGS(ring, desc, skb));
DECLARE_EVENT_CLASS(
- i40evf_xmit_template,
+ iavf_xmit_template,
TP_PROTO(struct sk_buff *skb,
- struct i40e_ring *ring),
+ struct iavf_ring *ring),
TP_ARGS(skb, ring),
@@ -180,23 +180,23 @@ DECLARE_EVENT_CLASS(
);
DEFINE_EVENT(
- i40evf_xmit_template, i40evf_xmit_frame_ring,
+ iavf_xmit_template, iavf_xmit_frame_ring,
TP_PROTO(struct sk_buff *skb,
- struct i40e_ring *ring),
+ struct iavf_ring *ring),
TP_ARGS(skb, ring));
DEFINE_EVENT(
- i40evf_xmit_template, i40evf_xmit_frame_ring_drop,
+ iavf_xmit_template, iavf_xmit_frame_ring_drop,
TP_PROTO(struct sk_buff *skb,
- struct i40e_ring *ring),
+ struct iavf_ring *ring),
TP_ARGS(skb, ring));
/* Events unique to the VF. */
-#endif /* _I40E_TRACE_H_ */
-/* This must be outside ifdef _I40E_TRACE_H */
+#endif /* _IAVF_TRACE_H_ */
+/* This must be outside ifdef _IAVF_TRACE_H */
/* This trace include file is not located in the .../include/trace
* with the kernel tracepoint definitions, because we're a loadable
@@ -205,5 +205,5 @@ DEFINE_EVENT(
#undef TRACE_INCLUDE_PATH
#define TRACE_INCLUDE_PATH .
#undef TRACE_INCLUDE_FILE
-#define TRACE_INCLUDE_FILE i40e_trace
+#define TRACE_INCLUDE_FILE iavf_trace
#include <trace/define_trace.h>
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/iavf/iavf_txrx.c
index a9730711e257..fb9bfad96daf 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_txrx.c
@@ -2,34 +2,33 @@
/* Copyright(c) 2013 - 2018 Intel Corporation. */
#include <linux/prefetch.h>
-#include <net/busy_poll.h>
-#include "i40evf.h"
-#include "i40e_trace.h"
-#include "i40e_prototype.h"
+#include "iavf.h"
+#include "iavf_trace.h"
+#include "iavf_prototype.h"
static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
u32 td_tag)
{
- return cpu_to_le64(I40E_TX_DESC_DTYPE_DATA |
- ((u64)td_cmd << I40E_TXD_QW1_CMD_SHIFT) |
- ((u64)td_offset << I40E_TXD_QW1_OFFSET_SHIFT) |
- ((u64)size << I40E_TXD_QW1_TX_BUF_SZ_SHIFT) |
- ((u64)td_tag << I40E_TXD_QW1_L2TAG1_SHIFT));
+ return cpu_to_le64(IAVF_TX_DESC_DTYPE_DATA |
+ ((u64)td_cmd << IAVF_TXD_QW1_CMD_SHIFT) |
+ ((u64)td_offset << IAVF_TXD_QW1_OFFSET_SHIFT) |
+ ((u64)size << IAVF_TXD_QW1_TX_BUF_SZ_SHIFT) |
+ ((u64)td_tag << IAVF_TXD_QW1_L2TAG1_SHIFT));
}
-#define I40E_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS)
+#define IAVF_TXD_CMD (IAVF_TX_DESC_CMD_EOP | IAVF_TX_DESC_CMD_RS)
/**
- * i40e_unmap_and_free_tx_resource - Release a Tx buffer
+ * iavf_unmap_and_free_tx_resource - Release a Tx buffer
* @ring: the ring that owns the buffer
* @tx_buffer: the buffer to free
**/
-static void i40e_unmap_and_free_tx_resource(struct i40e_ring *ring,
- struct i40e_tx_buffer *tx_buffer)
+static void iavf_unmap_and_free_tx_resource(struct iavf_ring *ring,
+ struct iavf_tx_buffer *tx_buffer)
{
if (tx_buffer->skb) {
- if (tx_buffer->tx_flags & I40E_TX_FLAGS_FD_SB)
+ if (tx_buffer->tx_flags & IAVF_TX_FLAGS_FD_SB)
kfree(tx_buffer->raw_buf);
else
dev_kfree_skb_any(tx_buffer->skb);
@@ -52,10 +51,10 @@ static void i40e_unmap_and_free_tx_resource(struct i40e_ring *ring,
}
/**
- * i40evf_clean_tx_ring - Free any empty Tx buffers
+ * iavf_clean_tx_ring - Free any empty Tx buffers
* @tx_ring: ring to be cleaned
**/
-void i40evf_clean_tx_ring(struct i40e_ring *tx_ring)
+void iavf_clean_tx_ring(struct iavf_ring *tx_ring)
{
unsigned long bi_size;
u16 i;
@@ -66,9 +65,9 @@ void i40evf_clean_tx_ring(struct i40e_ring *tx_ring)
/* Free all the Tx ring sk_buffs */
for (i = 0; i < tx_ring->count; i++)
- i40e_unmap_and_free_tx_resource(tx_ring, &tx_ring->tx_bi[i]);
+ iavf_unmap_and_free_tx_resource(tx_ring, &tx_ring->tx_bi[i]);
- bi_size = sizeof(struct i40e_tx_buffer) * tx_ring->count;
+ bi_size = sizeof(struct iavf_tx_buffer) * tx_ring->count;
memset(tx_ring->tx_bi, 0, bi_size);
/* Zero out the descriptor ring */
@@ -85,14 +84,14 @@ void i40evf_clean_tx_ring(struct i40e_ring *tx_ring)
}
/**
- * i40evf_free_tx_resources - Free Tx resources per queue
+ * iavf_free_tx_resources - Free Tx resources per queue
* @tx_ring: Tx descriptor ring for a specific queue
*
* Free all transmit software resources
**/
-void i40evf_free_tx_resources(struct i40e_ring *tx_ring)
+void iavf_free_tx_resources(struct iavf_ring *tx_ring)
{
- i40evf_clean_tx_ring(tx_ring);
+ iavf_clean_tx_ring(tx_ring);
kfree(tx_ring->tx_bi);
tx_ring->tx_bi = NULL;
@@ -104,14 +103,14 @@ void i40evf_free_tx_resources(struct i40e_ring *tx_ring)
}
/**
- * i40evf_get_tx_pending - how many Tx descriptors not processed
+ * iavf_get_tx_pending - how many Tx descriptors not processed
* @ring: the ring of descriptors
* @in_sw: is tx_pending being checked in SW or HW
*
* Since there is no access to the ring head register
* in XL710, we need to use our local copies
**/
-u32 i40evf_get_tx_pending(struct i40e_ring *ring, bool in_sw)
+u32 iavf_get_tx_pending(struct iavf_ring *ring, bool in_sw)
{
u32 head, tail;
@@ -126,15 +125,15 @@ u32 i40evf_get_tx_pending(struct i40e_ring *ring, bool in_sw)
}
/**
- * i40evf_detect_recover_hung - Function to detect and recover hung_queues
+ * iavf_detect_recover_hung - Function to detect and recover hung_queues
* @vsi: pointer to vsi struct with tx queues
*
* VSI has netdev and netdev has TX queues. This function is to check each of
* those TX queues if they are hung, trigger recovery by issuing SW interrupt.
**/
-void i40evf_detect_recover_hung(struct i40e_vsi *vsi)
+void iavf_detect_recover_hung(struct iavf_vsi *vsi)
{
- struct i40e_ring *tx_ring = NULL;
+ struct iavf_ring *tx_ring = NULL;
struct net_device *netdev;
unsigned int i;
int packets;
@@ -142,7 +141,7 @@ void i40evf_detect_recover_hung(struct i40e_vsi *vsi)
if (!vsi)
return;
- if (test_bit(__I40E_VSI_DOWN, vsi->state))
+ if (test_bit(__IAVF_VSI_DOWN, vsi->state))
return;
netdev = vsi->netdev;
@@ -164,16 +163,16 @@ void i40evf_detect_recover_hung(struct i40e_vsi *vsi)
*/
packets = tx_ring->stats.packets & INT_MAX;
if (tx_ring->tx_stats.prev_pkt_ctr == packets) {
- i40evf_force_wb(vsi, tx_ring->q_vector);
+ iavf_force_wb(vsi, tx_ring->q_vector);
continue;
}
/* Memory barrier between read of packet count and call
- * to i40evf_get_tx_pending()
+ * to iavf_get_tx_pending()
*/
smp_rmb();
tx_ring->tx_stats.prev_pkt_ctr =
- i40evf_get_tx_pending(tx_ring, true) ? packets : -1;
+ iavf_get_tx_pending(tx_ring, true) ? packets : -1;
}
}
}
@@ -181,28 +180,28 @@ void i40evf_detect_recover_hung(struct i40e_vsi *vsi)
#define WB_STRIDE 4
/**
- * i40e_clean_tx_irq - Reclaim resources after transmit completes
+ * iavf_clean_tx_irq - Reclaim resources after transmit completes
* @vsi: the VSI we care about
* @tx_ring: Tx ring to clean
* @napi_budget: Used to determine if we are in netpoll
*
* Returns true if there's any budget left (e.g. the clean is finished)
**/
-static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
- struct i40e_ring *tx_ring, int napi_budget)
+static bool iavf_clean_tx_irq(struct iavf_vsi *vsi,
+ struct iavf_ring *tx_ring, int napi_budget)
{
u16 i = tx_ring->next_to_clean;
- struct i40e_tx_buffer *tx_buf;
- struct i40e_tx_desc *tx_desc;
+ struct iavf_tx_buffer *tx_buf;
+ struct iavf_tx_desc *tx_desc;
unsigned int total_bytes = 0, total_packets = 0;
unsigned int budget = vsi->work_limit;
tx_buf = &tx_ring->tx_bi[i];
- tx_desc = I40E_TX_DESC(tx_ring, i);
+ tx_desc = IAVF_TX_DESC(tx_ring, i);
i -= tx_ring->count;
do {
- struct i40e_tx_desc *eop_desc = tx_buf->next_to_watch;
+ struct iavf_tx_desc *eop_desc = tx_buf->next_to_watch;
/* if next_to_watch is not set then there is no work pending */
if (!eop_desc)
@@ -211,10 +210,10 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
/* prevent any other reads prior to eop_desc */
smp_rmb();
- i40e_trace(clean_tx_irq, tx_ring, tx_desc, tx_buf);
+ iavf_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(I40E_TX_DESC_DTYPE_DESC_DONE)))
+ cpu_to_le64(IAVF_TX_DESC_DTYPE_DESC_DONE)))
break;
/* clear next_to_watch to prevent false hangs */
@@ -239,7 +238,7 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
/* unmap remaining buffers */
while (tx_desc != eop_desc) {
- i40e_trace(clean_tx_irq_unmap,
+ iavf_trace(clean_tx_irq_unmap,
tx_ring, tx_desc, tx_buf);
tx_buf++;
@@ -248,7 +247,7 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
if (unlikely(!i)) {
i -= tx_ring->count;
tx_buf = tx_ring->tx_bi;
- tx_desc = I40E_TX_DESC(tx_ring, 0);
+ tx_desc = IAVF_TX_DESC(tx_ring, 0);
}
/* unmap any remaining paged data */
@@ -268,7 +267,7 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
if (unlikely(!i)) {
i -= tx_ring->count;
tx_buf = tx_ring->tx_bi;
- tx_desc = I40E_TX_DESC(tx_ring, 0);
+ tx_desc = IAVF_TX_DESC(tx_ring, 0);
}
prefetch(tx_desc);
@@ -286,18 +285,18 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
tx_ring->q_vector->tx.total_bytes += total_bytes;
tx_ring->q_vector->tx.total_packets += total_packets;
- if (tx_ring->flags & I40E_TXR_FLAGS_WB_ON_ITR) {
+ if (tx_ring->flags & IAVF_TXR_FLAGS_WB_ON_ITR) {
/* check to see if there are < 4 descriptors
* waiting to be written back, then kick the hardware to force
* them to be written back in case we stay in NAPI.
* In this mode on X722 we do not enable Interrupt.
*/
- unsigned int j = i40evf_get_tx_pending(tx_ring, false);
+ unsigned int j = iavf_get_tx_pending(tx_ring, false);
if (budget &&
((j / WB_STRIDE) == 0) && (j > 0) &&
- !test_bit(__I40E_VSI_DOWN, vsi->state) &&
- (I40E_DESC_UNUSED(tx_ring) != tx_ring->count))
+ !test_bit(__IAVF_VSI_DOWN, vsi->state) &&
+ (IAVF_DESC_UNUSED(tx_ring) != tx_ring->count))
tx_ring->arm_wb = true;
}
@@ -307,14 +306,14 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
#define TX_WAKE_THRESHOLD ((s16)(DESC_NEEDED * 2))
if (unlikely(total_packets && netif_carrier_ok(tx_ring->netdev) &&
- (I40E_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD))) {
+ (IAVF_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD))) {
/* Make sure that anybody stopping the queue after this
* sees the new next_to_clean.
*/
smp_mb();
if (__netif_subqueue_stopped(tx_ring->netdev,
tx_ring->queue_index) &&
- !test_bit(__I40E_VSI_DOWN, vsi->state)) {
+ !test_bit(__IAVF_VSI_DOWN, vsi->state)) {
netif_wake_subqueue(tx_ring->netdev,
tx_ring->queue_index);
++tx_ring->tx_stats.restart_queue;
@@ -325,75 +324,75 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
}
/**
- * i40evf_enable_wb_on_itr - Arm hardware to do a wb, interrupts are not enabled
+ * iavf_enable_wb_on_itr - Arm hardware to do a wb, interrupts are not enabled
* @vsi: the VSI we care about
* @q_vector: the vector on which to enable writeback
*
**/
-static void i40e_enable_wb_on_itr(struct i40e_vsi *vsi,
- struct i40e_q_vector *q_vector)
+static void iavf_enable_wb_on_itr(struct iavf_vsi *vsi,
+ struct iavf_q_vector *q_vector)
{
u16 flags = q_vector->tx.ring[0].flags;
u32 val;
- if (!(flags & I40E_TXR_FLAGS_WB_ON_ITR))
+ if (!(flags & IAVF_TXR_FLAGS_WB_ON_ITR))
return;
if (q_vector->arm_wb_state)
return;
- val = I40E_VFINT_DYN_CTLN1_WB_ON_ITR_MASK |
- I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK; /* set noitr */
+ val = IAVF_VFINT_DYN_CTLN1_WB_ON_ITR_MASK |
+ IAVF_VFINT_DYN_CTLN1_ITR_INDX_MASK; /* set noitr */
wr32(&vsi->back->hw,
- I40E_VFINT_DYN_CTLN1(q_vector->reg_idx), val);
+ IAVF_VFINT_DYN_CTLN1(q_vector->reg_idx), val);
q_vector->arm_wb_state = true;
}
/**
- * i40evf_force_wb - Issue SW Interrupt so HW does a wb
+ * iavf_force_wb - Issue SW Interrupt so HW does a wb
* @vsi: the VSI we care about
* @q_vector: the vector on which to force writeback
*
**/
-void i40evf_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector)
+void iavf_force_wb(struct iavf_vsi *vsi, struct iavf_q_vector *q_vector)
{
- u32 val = I40E_VFINT_DYN_CTLN1_INTENA_MASK |
- I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK | /* set noitr */
- I40E_VFINT_DYN_CTLN1_SWINT_TRIG_MASK |
- I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_MASK
+ u32 val = IAVF_VFINT_DYN_CTLN1_INTENA_MASK |
+ IAVF_VFINT_DYN_CTLN1_ITR_INDX_MASK | /* set noitr */
+ IAVF_VFINT_DYN_CTLN1_SWINT_TRIG_MASK |
+ IAVF_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_MASK
/* allow 00 to be written to the index */;
wr32(&vsi->back->hw,
- I40E_VFINT_DYN_CTLN1(q_vector->reg_idx),
+ IAVF_VFINT_DYN_CTLN1(q_vector->reg_idx),
val);
}
-static inline bool i40e_container_is_rx(struct i40e_q_vector *q_vector,
- struct i40e_ring_container *rc)
+static inline bool iavf_container_is_rx(struct iavf_q_vector *q_vector,
+ struct iavf_ring_container *rc)
{
return &q_vector->rx == rc;
}
-static inline unsigned int i40e_itr_divisor(struct i40e_q_vector *q_vector)
+static inline unsigned int iavf_itr_divisor(struct iavf_q_vector *q_vector)
{
unsigned int divisor;
switch (q_vector->adapter->link_speed) {
case I40E_LINK_SPEED_40GB:
- divisor = I40E_ITR_ADAPTIVE_MIN_INC * 1024;
+ divisor = IAVF_ITR_ADAPTIVE_MIN_INC * 1024;
break;
case I40E_LINK_SPEED_25GB:
case I40E_LINK_SPEED_20GB:
- divisor = I40E_ITR_ADAPTIVE_MIN_INC * 512;
+ divisor = IAVF_ITR_ADAPTIVE_MIN_INC * 512;
break;
default:
case I40E_LINK_SPEED_10GB:
- divisor = I40E_ITR_ADAPTIVE_MIN_INC * 256;
+ divisor = IAVF_ITR_ADAPTIVE_MIN_INC * 256;
break;
case I40E_LINK_SPEED_1GB:
case I40E_LINK_SPEED_100MB:
- divisor = I40E_ITR_ADAPTIVE_MIN_INC * 32;
+ divisor = IAVF_ITR_ADAPTIVE_MIN_INC * 32;
break;
}
@@ -401,7 +400,7 @@ static inline unsigned int i40e_itr_divisor(struct i40e_q_vector *q_vector)
}
/**
- * i40e_update_itr - update the dynamic ITR value based on statistics
+ * iavf_update_itr - update the dynamic ITR value based on statistics
* @q_vector: structure containing interrupt and ring information
* @rc: structure containing ring performance data
*
@@ -413,8 +412,8 @@ static inline unsigned int i40e_itr_divisor(struct i40e_q_vector *q_vector)
* on testing data as well as attempting to minimize response time
* while increasing bulk throughput.
**/
-static void i40e_update_itr(struct i40e_q_vector *q_vector,
- struct i40e_ring_container *rc)
+static void iavf_update_itr(struct iavf_q_vector *q_vector,
+ struct iavf_ring_container *rc)
{
unsigned int avg_wire_size, packets, bytes, itr;
unsigned long next_update = jiffies;
@@ -428,9 +427,9 @@ static void i40e_update_itr(struct i40e_q_vector *q_vector,
/* For Rx we want to push the delay up and default to low latency.
* for Tx we want to pull the delay down and default to high latency.
*/
- itr = i40e_container_is_rx(q_vector, rc) ?
- I40E_ITR_ADAPTIVE_MIN_USECS | I40E_ITR_ADAPTIVE_LATENCY :
- I40E_ITR_ADAPTIVE_MAX_USECS | I40E_ITR_ADAPTIVE_LATENCY;
+ itr = iavf_container_is_rx(q_vector, rc) ?
+ IAVF_ITR_ADAPTIVE_MIN_USECS | IAVF_ITR_ADAPTIVE_LATENCY :
+ IAVF_ITR_ADAPTIVE_MAX_USECS | IAVF_ITR_ADAPTIVE_LATENCY;
/* If we didn't update within up to 1 - 2 jiffies we can assume
* that either packets are coming in so slow there hasn't been
@@ -454,15 +453,15 @@ static void i40e_update_itr(struct i40e_q_vector *q_vector,
packets = rc->total_packets;
bytes = rc->total_bytes;
- if (i40e_container_is_rx(q_vector, rc)) {
+ if (iavf_container_is_rx(q_vector, rc)) {
/* If Rx there are 1 to 4 packets and bytes are less than
* 9000 assume insufficient data to use bulk rate limiting
* approach unless Tx is already in bulk rate limiting. We
* are likely latency driven.
*/
if (packets && packets < 4 && bytes < 9000 &&
- (q_vector->tx.target_itr & I40E_ITR_ADAPTIVE_LATENCY)) {
- itr = I40E_ITR_ADAPTIVE_LATENCY;
+ (q_vector->tx.target_itr & IAVF_ITR_ADAPTIVE_LATENCY)) {
+ itr = IAVF_ITR_ADAPTIVE_LATENCY;
goto adjust_by_size;
}
} else if (packets < 4) {
@@ -471,15 +470,15 @@ static void i40e_update_itr(struct i40e_q_vector *q_vector,
* reset the ITR_ADAPTIVE_LATENCY bit for latency mode so
* that the Rx can relax.
*/
- if (rc->target_itr == I40E_ITR_ADAPTIVE_MAX_USECS &&
- (q_vector->rx.target_itr & I40E_ITR_MASK) ==
- I40E_ITR_ADAPTIVE_MAX_USECS)
+ if (rc->target_itr == IAVF_ITR_ADAPTIVE_MAX_USECS &&
+ (q_vector->rx.target_itr & IAVF_ITR_MASK) ==
+ IAVF_ITR_ADAPTIVE_MAX_USECS)
goto clear_counts;
} else if (packets > 32) {
/* If we have processed over 32 packets in a single interrupt
* for Tx assume we need to switch over to "bulk" mode.
*/
- rc->target_itr &= ~I40E_ITR_ADAPTIVE_LATENCY;
+ rc->target_itr &= ~IAVF_ITR_ADAPTIVE_LATENCY;
}
/* We have no packets to actually measure against. This means
@@ -491,17 +490,17 @@ static void i40e_update_itr(struct i40e_q_vector *q_vector,
* fixed amount.
*/
if (packets < 56) {
- itr = rc->target_itr + I40E_ITR_ADAPTIVE_MIN_INC;
- if ((itr & I40E_ITR_MASK) > I40E_ITR_ADAPTIVE_MAX_USECS) {
- itr &= I40E_ITR_ADAPTIVE_LATENCY;
- itr += I40E_ITR_ADAPTIVE_MAX_USECS;
+ itr = rc->target_itr + IAVF_ITR_ADAPTIVE_MIN_INC;
+ if ((itr & IAVF_ITR_MASK) > IAVF_ITR_ADAPTIVE_MAX_USECS) {
+ itr &= IAVF_ITR_ADAPTIVE_LATENCY;
+ itr += IAVF_ITR_ADAPTIVE_MAX_USECS;
}
goto clear_counts;
}
if (packets <= 256) {
itr = min(q_vector->tx.current_itr, q_vector->rx.current_itr);
- itr &= I40E_ITR_MASK;
+ itr &= IAVF_ITR_MASK;
/* Between 56 and 112 is our "goldilocks" zone where we are
* working out "just right". Just report that our current
@@ -516,9 +515,9 @@ static void i40e_update_itr(struct i40e_q_vector *q_vector,
* in half per interrupt.
*/
itr /= 2;
- itr &= I40E_ITR_MASK;
- if (itr < I40E_ITR_ADAPTIVE_MIN_USECS)
- itr = I40E_ITR_ADAPTIVE_MIN_USECS;
+ itr &= IAVF_ITR_MASK;
+ if (itr < IAVF_ITR_ADAPTIVE_MIN_USECS)
+ itr = IAVF_ITR_ADAPTIVE_MIN_USECS;
goto clear_counts;
}
@@ -529,7 +528,7 @@ static void i40e_update_itr(struct i40e_q_vector *q_vector,
* though for smaller packet sizes there isn't much we can do as
* NAPI polling will likely be kicking in sooner rather than later.
*/
- itr = I40E_ITR_ADAPTIVE_BULK;
+ itr = IAVF_ITR_ADAPTIVE_BULK;
adjust_by_size:
/* If packet counts are 256 or greater we can assume we have a gross
@@ -577,7 +576,7 @@ adjust_by_size:
/* If we are in low latency mode halve our delay which doubles the
* rate to somewhere between 100K to 16K ints/sec
*/
- if (itr & I40E_ITR_ADAPTIVE_LATENCY)
+ if (itr & IAVF_ITR_ADAPTIVE_LATENCY)
avg_wire_size /= 2;
/* Resultant value is 256 times larger than it needs to be. This
@@ -587,12 +586,12 @@ adjust_by_size:
* Use addition as we have already recorded the new latency flag
* for the ITR value.
*/
- itr += DIV_ROUND_UP(avg_wire_size, i40e_itr_divisor(q_vector)) *
- I40E_ITR_ADAPTIVE_MIN_INC;
+ itr += DIV_ROUND_UP(avg_wire_size, iavf_itr_divisor(q_vector)) *
+ IAVF_ITR_ADAPTIVE_MIN_INC;
- if ((itr & I40E_ITR_MASK) > I40E_ITR_ADAPTIVE_MAX_USECS) {
- itr &= I40E_ITR_ADAPTIVE_LATENCY;
- itr += I40E_ITR_ADAPTIVE_MAX_USECS;
+ if ((itr & IAVF_ITR_MASK) > IAVF_ITR_ADAPTIVE_MAX_USECS) {
+ itr &= IAVF_ITR_ADAPTIVE_LATENCY;
+ itr += IAVF_ITR_ADAPTIVE_MAX_USECS;
}
clear_counts:
@@ -607,12 +606,12 @@ clear_counts:
}
/**
- * i40evf_setup_tx_descriptors - Allocate the Tx descriptors
+ * iavf_setup_tx_descriptors - Allocate the Tx descriptors
* @tx_ring: the tx ring to set up
*
* Return 0 on success, negative on error
**/
-int i40evf_setup_tx_descriptors(struct i40e_ring *tx_ring)
+int iavf_setup_tx_descriptors(struct iavf_ring *tx_ring)
{
struct device *dev = tx_ring->dev;
int bi_size;
@@ -622,13 +621,13 @@ int i40evf_setup_tx_descriptors(struct i40e_ring *tx_ring)
/* warn if we are about to overwrite the pointer */
WARN_ON(tx_ring->tx_bi);
- bi_size = sizeof(struct i40e_tx_buffer) * tx_ring->count;
+ bi_size = sizeof(struct iavf_tx_buffer) * tx_ring->count;
tx_ring->tx_bi = kzalloc(bi_size, GFP_KERNEL);
if (!tx_ring->tx_bi)
goto err;
/* round up to nearest 4K */
- tx_ring->size = tx_ring->count * sizeof(struct i40e_tx_desc);
+ tx_ring->size = tx_ring->count * sizeof(struct iavf_tx_desc);
tx_ring->size = ALIGN(tx_ring->size, 4096);
tx_ring->desc = dma_alloc_coherent(dev, tx_ring->size,
&tx_ring->dma, GFP_KERNEL);
@@ -650,10 +649,10 @@ err:
}
/**
- * i40evf_clean_rx_ring - Free Rx buffers
+ * iavf_clean_rx_ring - Free Rx buffers
* @rx_ring: ring to be cleaned
**/
-void i40evf_clean_rx_ring(struct i40e_ring *rx_ring)
+void iavf_clean_rx_ring(struct iavf_ring *rx_ring)
{
unsigned long bi_size;
u16 i;
@@ -669,7 +668,7 @@ void i40evf_clean_rx_ring(struct i40e_ring *rx_ring)
/* Free all the Rx ring sk_buffs */
for (i = 0; i < rx_ring->count; i++) {
- struct i40e_rx_buffer *rx_bi = &rx_ring->rx_bi[i];
+ struct iavf_rx_buffer *rx_bi = &rx_ring->rx_bi[i];
if (!rx_bi->page)
continue;
@@ -685,9 +684,9 @@ void i40evf_clean_rx_ring(struct i40e_ring *rx_ring)
/* free resources associated with mapping */
dma_unmap_page_attrs(rx_ring->dev, rx_bi->dma,
- i40e_rx_pg_size(rx_ring),
+ iavf_rx_pg_size(rx_ring),
DMA_FROM_DEVICE,
- I40E_RX_DMA_ATTR);
+ IAVF_RX_DMA_ATTR);
__page_frag_cache_drain(rx_bi->page, rx_bi->pagecnt_bias);
@@ -695,7 +694,7 @@ void i40evf_clean_rx_ring(struct i40e_ring *rx_ring)
rx_bi->page_offset = 0;
}
- bi_size = sizeof(struct i40e_rx_buffer) * rx_ring->count;
+ bi_size = sizeof(struct iavf_rx_buffer) * rx_ring->count;
memset(rx_ring->rx_bi, 0, bi_size);
/* Zero out the descriptor ring */
@@ -707,14 +706,14 @@ void i40evf_clean_rx_ring(struct i40e_ring *rx_ring)
}
/**
- * i40evf_free_rx_resources - Free Rx resources
+ * iavf_free_rx_resources - Free Rx resources
* @rx_ring: ring to clean the resources from
*
* Free all receive software resources
**/
-void i40evf_free_rx_resources(struct i40e_ring *rx_ring)
+void iavf_free_rx_resources(struct iavf_ring *rx_ring)
{
- i40evf_clean_rx_ring(rx_ring);
+ iavf_clean_rx_ring(rx_ring);
kfree(rx_ring->rx_bi);
rx_ring->rx_bi = NULL;
@@ -726,19 +725,19 @@ void i40evf_free_rx_resources(struct i40e_ring *rx_ring)
}
/**
- * i40evf_setup_rx_descriptors - Allocate Rx descriptors
+ * iavf_setup_rx_descriptors - Allocate Rx descriptors
* @rx_ring: Rx descriptor ring (for a specific queue) to setup
*
* Returns 0 on success, negative on failure
**/
-int i40evf_setup_rx_descriptors(struct i40e_ring *rx_ring)
+int iavf_setup_rx_descriptors(struct iavf_ring *rx_ring)
{
struct device *dev = rx_ring->dev;
int bi_size;
/* warn if we are about to overwrite the pointer */
WARN_ON(rx_ring->rx_bi);
- bi_size = sizeof(struct i40e_rx_buffer) * rx_ring->count;
+ bi_size = sizeof(struct iavf_rx_buffer) * rx_ring->count;
rx_ring->rx_bi = kzalloc(bi_size, GFP_KERNEL);
if (!rx_ring->rx_bi)
goto err;
@@ -746,7 +745,7 @@ int i40evf_setup_rx_descriptors(struct i40e_ring *rx_ring)
u64_stats_init(&rx_ring->syncp);
/* Round up to nearest 4K */
- rx_ring->size = rx_ring->count * sizeof(union i40e_32byte_rx_desc);
+ rx_ring->size = rx_ring->count * sizeof(union iavf_32byte_rx_desc);
rx_ring->size = ALIGN(rx_ring->size, 4096);
rx_ring->desc = dma_alloc_coherent(dev, rx_ring->size,
&rx_ring->dma, GFP_KERNEL);
@@ -769,11 +768,11 @@ err:
}
/**
- * i40e_release_rx_desc - Store the new tail and head values
+ * iavf_release_rx_desc - Store the new tail and head values
* @rx_ring: ring to bump
* @val: new head index
**/
-static inline void i40e_release_rx_desc(struct i40e_ring *rx_ring, u32 val)
+static inline void iavf_release_rx_desc(struct iavf_ring *rx_ring, u32 val)
{
rx_ring->next_to_use = val;
@@ -790,26 +789,26 @@ static inline void i40e_release_rx_desc(struct i40e_ring *rx_ring, u32 val)
}
/**
- * i40e_rx_offset - Return expected offset into page to access data
+ * iavf_rx_offset - Return expected offset into page to access data
* @rx_ring: Ring we are requesting offset of
*
* Returns the offset value for ring into the data buffer.
*/
-static inline unsigned int i40e_rx_offset(struct i40e_ring *rx_ring)
+static inline unsigned int iavf_rx_offset(struct iavf_ring *rx_ring)
{
- return ring_uses_build_skb(rx_ring) ? I40E_SKB_PAD : 0;
+ return ring_uses_build_skb(rx_ring) ? IAVF_SKB_PAD : 0;
}
/**
- * i40e_alloc_mapped_page - recycle or make a new page
+ * iavf_alloc_mapped_page - recycle or make a new page
* @rx_ring: ring to use
* @bi: rx_buffer struct to modify
*
* Returns true if the page was successfully allocated or
* reused.
**/
-static bool i40e_alloc_mapped_page(struct i40e_ring *rx_ring,
- struct i40e_rx_buffer *bi)
+static bool iavf_alloc_mapped_page(struct iavf_ring *rx_ring,
+ struct iavf_rx_buffer *bi)
{
struct page *page = bi->page;
dma_addr_t dma;
@@ -821,7 +820,7 @@ static bool i40e_alloc_mapped_page(struct i40e_ring *rx_ring,
}
/* alloc new page for storage */
- page = dev_alloc_pages(i40e_rx_pg_order(rx_ring));
+ page = dev_alloc_pages(iavf_rx_pg_order(rx_ring));
if (unlikely(!page)) {
rx_ring->rx_stats.alloc_page_failed++;
return false;
@@ -829,22 +828,22 @@ static bool i40e_alloc_mapped_page(struct i40e_ring *rx_ring,
/* map page for use */
dma = dma_map_page_attrs(rx_ring->dev, page, 0,
- i40e_rx_pg_size(rx_ring),
+ iavf_rx_pg_size(rx_ring),
DMA_FROM_DEVICE,
- I40E_RX_DMA_ATTR);
+ IAVF_RX_DMA_ATTR);
/* if mapping failed free memory back to system since
* there isn't much point in holding memory we can't use
*/
if (dma_mapping_error(rx_ring->dev, dma)) {
- __free_pages(page, i40e_rx_pg_order(rx_ring));
+ __free_pages(page, iavf_rx_pg_order(rx_ring));
rx_ring->rx_stats.alloc_page_failed++;
return false;
}
bi->dma = dma;
bi->page = page;
- bi->page_offset = i40e_rx_offset(rx_ring);
+ bi->page_offset = iavf_rx_offset(rx_ring);
/* initialize pagecnt_bias to 1 representing we fully own page */
bi->pagecnt_bias = 1;
@@ -853,15 +852,15 @@ static bool i40e_alloc_mapped_page(struct i40e_ring *rx_ring,
}
/**
- * i40e_receive_skb - Send a completed packet up the stack
+ * iavf_receive_skb - Send a completed packet up the stack
* @rx_ring: rx ring in play
* @skb: packet to send up
* @vlan_tag: vlan tag for packet
**/
-static void i40e_receive_skb(struct i40e_ring *rx_ring,
+static void iavf_receive_skb(struct iavf_ring *rx_ring,
struct sk_buff *skb, u16 vlan_tag)
{
- struct i40e_q_vector *q_vector = rx_ring->q_vector;
+ struct iavf_q_vector *q_vector = rx_ring->q_vector;
if ((rx_ring->netdev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
(vlan_tag & VLAN_VID_MASK))
@@ -871,27 +870,27 @@ static void i40e_receive_skb(struct i40e_ring *rx_ring,
}
/**
- * i40evf_alloc_rx_buffers - Replace used receive buffers
+ * iavf_alloc_rx_buffers - Replace used receive buffers
* @rx_ring: ring to place buffers on
* @cleaned_count: number of buffers to replace
*
* Returns false if all allocations were successful, true if any fail
**/
-bool i40evf_alloc_rx_buffers(struct i40e_ring *rx_ring, u16 cleaned_count)
+bool iavf_alloc_rx_buffers(struct iavf_ring *rx_ring, u16 cleaned_count)
{
u16 ntu = rx_ring->next_to_use;
- union i40e_rx_desc *rx_desc;
- struct i40e_rx_buffer *bi;
+ union iavf_rx_desc *rx_desc;
+ struct iavf_rx_buffer *bi;
/* do nothing if no valid netdev defined */
if (!rx_ring->netdev || !cleaned_count)
return false;
- rx_desc = I40E_RX_DESC(rx_ring, ntu);
+ rx_desc = IAVF_RX_DESC(rx_ring, ntu);
bi = &rx_ring->rx_bi[ntu];
do {
- if (!i40e_alloc_mapped_page(rx_ring, bi))
+ if (!iavf_alloc_mapped_page(rx_ring, bi))
goto no_buffers;
/* sync the buffer for use by the device */
@@ -909,7 +908,7 @@ bool i40evf_alloc_rx_buffers(struct i40e_ring *rx_ring, u16 cleaned_count)
bi++;
ntu++;
if (unlikely(ntu == rx_ring->count)) {
- rx_desc = I40E_RX_DESC(rx_ring, 0);
+ rx_desc = IAVF_RX_DESC(rx_ring, 0);
bi = rx_ring->rx_bi;
ntu = 0;
}
@@ -921,13 +920,13 @@ bool i40evf_alloc_rx_buffers(struct i40e_ring *rx_ring, u16 cleaned_count)
} while (cleaned_count);
if (rx_ring->next_to_use != ntu)
- i40e_release_rx_desc(rx_ring, ntu);
+ iavf_release_rx_desc(rx_ring, ntu);
return false;
no_buffers:
if (rx_ring->next_to_use != ntu)
- i40e_release_rx_desc(rx_ring, ntu);
+ iavf_release_rx_desc(rx_ring, ntu);
/* make sure to come back via polling to try again after
* allocation failure
@@ -936,27 +935,27 @@ no_buffers:
}
/**
- * i40e_rx_checksum - Indicate in skb if hw indicated a good cksum
+ * iavf_rx_checksum - Indicate in skb if hw indicated a good cksum
* @vsi: the VSI we care about
* @skb: skb currently being received and modified
* @rx_desc: the receive descriptor
**/
-static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
+static inline void iavf_rx_checksum(struct iavf_vsi *vsi,
struct sk_buff *skb,
- union i40e_rx_desc *rx_desc)
+ union iavf_rx_desc *rx_desc)
{
- struct i40e_rx_ptype_decoded decoded;
+ struct iavf_rx_ptype_decoded decoded;
u32 rx_error, rx_status;
bool ipv4, ipv6;
u8 ptype;
u64 qword;
qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len);
- ptype = (qword & I40E_RXD_QW1_PTYPE_MASK) >> I40E_RXD_QW1_PTYPE_SHIFT;
- rx_error = (qword & I40E_RXD_QW1_ERROR_MASK) >>
- I40E_RXD_QW1_ERROR_SHIFT;
- rx_status = (qword & I40E_RXD_QW1_STATUS_MASK) >>
- I40E_RXD_QW1_STATUS_SHIFT;
+ ptype = (qword & IAVF_RXD_QW1_PTYPE_MASK) >> IAVF_RXD_QW1_PTYPE_SHIFT;
+ rx_error = (qword & IAVF_RXD_QW1_ERROR_MASK) >>
+ IAVF_RXD_QW1_ERROR_SHIFT;
+ rx_status = (qword & IAVF_RXD_QW1_STATUS_MASK) >>
+ IAVF_RXD_QW1_STATUS_SHIFT;
decoded = decode_rx_desc_ptype(ptype);
skb->ip_summed = CHECKSUM_NONE;
@@ -968,45 +967,45 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
return;
/* did the hardware decode the packet and checksum? */
- if (!(rx_status & BIT(I40E_RX_DESC_STATUS_L3L4P_SHIFT)))
+ if (!(rx_status & BIT(IAVF_RX_DESC_STATUS_L3L4P_SHIFT)))
return;
/* both known and outer_ip must be set for the below code to work */
if (!(decoded.known && decoded.outer_ip))
return;
- ipv4 = (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP) &&
- (decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV4);
- ipv6 = (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP) &&
- (decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV6);
+ ipv4 = (decoded.outer_ip == IAVF_RX_PTYPE_OUTER_IP) &&
+ (decoded.outer_ip_ver == IAVF_RX_PTYPE_OUTER_IPV4);
+ ipv6 = (decoded.outer_ip == IAVF_RX_PTYPE_OUTER_IP) &&
+ (decoded.outer_ip_ver == IAVF_RX_PTYPE_OUTER_IPV6);
if (ipv4 &&
- (rx_error & (BIT(I40E_RX_DESC_ERROR_IPE_SHIFT) |
- BIT(I40E_RX_DESC_ERROR_EIPE_SHIFT))))
+ (rx_error & (BIT(IAVF_RX_DESC_ERROR_IPE_SHIFT) |
+ BIT(IAVF_RX_DESC_ERROR_EIPE_SHIFT))))
goto checksum_fail;
/* likely incorrect csum if alternate IP extension headers found */
if (ipv6 &&
- rx_status & BIT(I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT))
+ rx_status & BIT(IAVF_RX_DESC_STATUS_IPV6EXADD_SHIFT))
/* don't increment checksum err here, non-fatal err */
return;
/* there was some L4 error, count error and punt packet to the stack */
- if (rx_error & BIT(I40E_RX_DESC_ERROR_L4E_SHIFT))
+ if (rx_error & BIT(IAVF_RX_DESC_ERROR_L4E_SHIFT))
goto checksum_fail;
/* handle packets that were not able to be checksummed due
* to arrival speed, in this case the stack can compute
* the csum.
*/
- if (rx_error & BIT(I40E_RX_DESC_ERROR_PPRS_SHIFT))
+ if (rx_error & BIT(IAVF_RX_DESC_ERROR_PPRS_SHIFT))
return;
/* Only report checksum unnecessary for TCP, UDP, or SCTP */
switch (decoded.inner_prot) {
- case I40E_RX_PTYPE_INNER_PROT_TCP:
- case I40E_RX_PTYPE_INNER_PROT_UDP:
- case I40E_RX_PTYPE_INNER_PROT_SCTP:
+ case IAVF_RX_PTYPE_INNER_PROT_TCP:
+ case IAVF_RX_PTYPE_INNER_PROT_UDP:
+ case IAVF_RX_PTYPE_INNER_PROT_SCTP:
skb->ip_summed = CHECKSUM_UNNECESSARY;
/* fall though */
default:
@@ -1020,56 +1019,56 @@ checksum_fail:
}
/**
- * i40e_ptype_to_htype - get a hash type
+ * iavf_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
**/
-static inline int i40e_ptype_to_htype(u8 ptype)
+static inline int iavf_ptype_to_htype(u8 ptype)
{
- struct i40e_rx_ptype_decoded decoded = decode_rx_desc_ptype(ptype);
+ struct iavf_rx_ptype_decoded decoded = decode_rx_desc_ptype(ptype);
if (!decoded.known)
return PKT_HASH_TYPE_NONE;
- if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP &&
- decoded.payload_layer == I40E_RX_PTYPE_PAYLOAD_LAYER_PAY4)
+ if (decoded.outer_ip == IAVF_RX_PTYPE_OUTER_IP &&
+ decoded.payload_layer == IAVF_RX_PTYPE_PAYLOAD_LAYER_PAY4)
return PKT_HASH_TYPE_L4;
- else if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP &&
- decoded.payload_layer == I40E_RX_PTYPE_PAYLOAD_LAYER_PAY3)
+ else if (decoded.outer_ip == IAVF_RX_PTYPE_OUTER_IP &&
+ decoded.payload_layer == IAVF_RX_PTYPE_PAYLOAD_LAYER_PAY3)
return PKT_HASH_TYPE_L3;
else
return PKT_HASH_TYPE_L2;
}
/**
- * i40e_rx_hash - set the hash value in the skb
+ * iavf_rx_hash - set the hash value in the skb
* @ring: descriptor ring
* @rx_desc: specific descriptor
* @skb: skb currently being received and modified
* @rx_ptype: Rx packet type
**/
-static inline void i40e_rx_hash(struct i40e_ring *ring,
- union i40e_rx_desc *rx_desc,
+static inline void iavf_rx_hash(struct iavf_ring *ring,
+ union iavf_rx_desc *rx_desc,
struct sk_buff *skb,
u8 rx_ptype)
{
u32 hash;
const __le64 rss_mask =
- cpu_to_le64((u64)I40E_RX_DESC_FLTSTAT_RSS_HASH <<
- I40E_RX_DESC_STATUS_FLTSTAT_SHIFT);
+ cpu_to_le64((u64)IAVF_RX_DESC_FLTSTAT_RSS_HASH <<
+ IAVF_RX_DESC_STATUS_FLTSTAT_SHIFT);
if (ring->netdev->features & NETIF_F_RXHASH)
return;
if ((rx_desc->wb.qword1.status_error_len & rss_mask) == rss_mask) {
hash = le32_to_cpu(rx_desc->wb.qword0.hi_dword.rss);
- skb_set_hash(skb, hash, i40e_ptype_to_htype(rx_ptype));
+ skb_set_hash(skb, hash, iavf_ptype_to_htype(rx_ptype));
}
}
/**
- * i40evf_process_skb_fields - Populate skb header fields from Rx descriptor
+ * iavf_process_skb_fields - Populate skb header fields from Rx descriptor
* @rx_ring: rx descriptor ring packet is being transacted on
* @rx_desc: pointer to the EOP Rx descriptor
* @skb: pointer to current skb being populated
@@ -1080,13 +1079,13 @@ static inline void i40e_rx_hash(struct i40e_ring *ring,
* other fields within the skb.
**/
static inline
-void i40evf_process_skb_fields(struct i40e_ring *rx_ring,
- union i40e_rx_desc *rx_desc, struct sk_buff *skb,
- u8 rx_ptype)
+void iavf_process_skb_fields(struct iavf_ring *rx_ring,
+ union iavf_rx_desc *rx_desc, struct sk_buff *skb,
+ u8 rx_ptype)
{
- i40e_rx_hash(rx_ring, rx_desc, skb, rx_ptype);
+ iavf_rx_hash(rx_ring, rx_desc, skb, rx_ptype);
- i40e_rx_checksum(rx_ring->vsi, skb, rx_desc);
+ iavf_rx_checksum(rx_ring->vsi, skb, rx_desc);
skb_record_rx_queue(skb, rx_ring->queue_index);
@@ -1095,7 +1094,7 @@ void i40evf_process_skb_fields(struct i40e_ring *rx_ring,
}
/**
- * i40e_cleanup_headers - Correct empty headers
+ * iavf_cleanup_headers - Correct empty headers
* @rx_ring: rx descriptor ring packet is being transacted on
* @skb: pointer to current skb being fixed
*
@@ -1107,7 +1106,7 @@ void i40evf_process_skb_fields(struct i40e_ring *rx_ring,
*
* Returns true if an error was encountered and skb was freed.
**/
-static bool i40e_cleanup_headers(struct i40e_ring *rx_ring, struct sk_buff *skb)
+static bool iavf_cleanup_headers(struct iavf_ring *rx_ring, struct sk_buff *skb)
{
/* if eth_skb_pad returns an error the skb was freed */
if (eth_skb_pad(skb))
@@ -1117,16 +1116,16 @@ static bool i40e_cleanup_headers(struct i40e_ring *rx_ring, struct sk_buff *skb)
}
/**
- * i40e_reuse_rx_page - page flip buffer and store it back on the ring
+ * iavf_reuse_rx_page - page flip buffer and store it back on the ring
* @rx_ring: rx descriptor ring to store buffers on
* @old_buff: donor buffer to have page reused
*
* Synchronizes page for reuse by the adapter
**/
-static void i40e_reuse_rx_page(struct i40e_ring *rx_ring,
- struct i40e_rx_buffer *old_buff)
+static void iavf_reuse_rx_page(struct iavf_ring *rx_ring,
+ struct iavf_rx_buffer *old_buff)
{
- struct i40e_rx_buffer *new_buff;
+ struct iavf_rx_buffer *new_buff;
u16 nta = rx_ring->next_to_alloc;
new_buff = &rx_ring->rx_bi[nta];
@@ -1143,20 +1142,20 @@ static void i40e_reuse_rx_page(struct i40e_ring *rx_ring,
}
/**
- * i40e_page_is_reusable - check if any reuse is possible
+ * iavf_page_is_reusable - check if any reuse is possible
* @page: page struct to check
*
* A page is not reusable if it was allocated under low memory
* conditions, or it's not in the same NUMA node as this CPU.
*/
-static inline bool i40e_page_is_reusable(struct page *page)
+static inline bool iavf_page_is_reusable(struct page *page)
{
return (page_to_nid(page) == numa_mem_id()) &&
!page_is_pfmemalloc(page);
}
/**
- * i40e_can_reuse_rx_page - Determine if this page can be reused by
+ * iavf_can_reuse_rx_page - Determine if this page can be reused by
* the adapter for another receive
*
* @rx_buffer: buffer containing the page
@@ -1182,13 +1181,13 @@ static inline bool i40e_page_is_reusable(struct page *page)
*
* In either case, if the page is reusable its refcount is increased.
**/
-static bool i40e_can_reuse_rx_page(struct i40e_rx_buffer *rx_buffer)
+static bool iavf_can_reuse_rx_page(struct iavf_rx_buffer *rx_buffer)
{
unsigned int pagecnt_bias = rx_buffer->pagecnt_bias;
struct page *page = rx_buffer->page;
/* Is any reuse possible? */
- if (unlikely(!i40e_page_is_reusable(page)))
+ if (unlikely(!iavf_page_is_reusable(page)))
return false;
#if (PAGE_SIZE < 8192)
@@ -1196,9 +1195,9 @@ static bool i40e_can_reuse_rx_page(struct i40e_rx_buffer *rx_buffer)
if (unlikely((page_count(page) - pagecnt_bias) > 1))
return false;
#else
-#define I40E_LAST_OFFSET \
- (SKB_WITH_OVERHEAD(PAGE_SIZE) - I40E_RXBUFFER_2048)
- if (rx_buffer->page_offset > I40E_LAST_OFFSET)
+#define IAVF_LAST_OFFSET \
+ (SKB_WITH_OVERHEAD(PAGE_SIZE) - IAVF_RXBUFFER_2048)
+ if (rx_buffer->page_offset > IAVF_LAST_OFFSET)
return false;
#endif
@@ -1215,7 +1214,7 @@ static bool i40e_can_reuse_rx_page(struct i40e_rx_buffer *rx_buffer)
}
/**
- * i40e_add_rx_frag - Add contents of Rx buffer to sk_buff
+ * iavf_add_rx_frag - Add contents of Rx buffer to sk_buff
* @rx_ring: rx descriptor ring to transact packets on
* @rx_buffer: buffer containing page to add
* @skb: sk_buff to place the data into
@@ -1226,15 +1225,15 @@ static bool i40e_can_reuse_rx_page(struct i40e_rx_buffer *rx_buffer)
*
* The function will then update the page offset.
**/
-static void i40e_add_rx_frag(struct i40e_ring *rx_ring,
- struct i40e_rx_buffer *rx_buffer,
+static void iavf_add_rx_frag(struct iavf_ring *rx_ring,
+ struct iavf_rx_buffer *rx_buffer,
struct sk_buff *skb,
unsigned int size)
{
#if (PAGE_SIZE < 8192)
- unsigned int truesize = i40e_rx_pg_size(rx_ring) / 2;
+ unsigned int truesize = iavf_rx_pg_size(rx_ring) / 2;
#else
- unsigned int truesize = SKB_DATA_ALIGN(size + i40e_rx_offset(rx_ring));
+ unsigned int truesize = SKB_DATA_ALIGN(size + iavf_rx_offset(rx_ring));
#endif
skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, rx_buffer->page,
@@ -1249,17 +1248,17 @@ static void i40e_add_rx_frag(struct i40e_ring *rx_ring,
}
/**
- * i40e_get_rx_buffer - Fetch Rx buffer and synchronize data for use
+ * iavf_get_rx_buffer - Fetch Rx buffer and synchronize data for use
* @rx_ring: rx descriptor ring to transact packets on
* @size: size of buffer to add to skb
*
* This function will pull an Rx buffer from the ring and synchronize it
* for use by the CPU.
*/
-static struct i40e_rx_buffer *i40e_get_rx_buffer(struct i40e_ring *rx_ring,
+static struct iavf_rx_buffer *iavf_get_rx_buffer(struct iavf_ring *rx_ring,
const unsigned int size)
{
- struct i40e_rx_buffer *rx_buffer;
+ struct iavf_rx_buffer *rx_buffer;
rx_buffer = &rx_ring->rx_bi[rx_ring->next_to_clean];
prefetchw(rx_buffer->page);
@@ -1278,7 +1277,7 @@ static struct i40e_rx_buffer *i40e_get_rx_buffer(struct i40e_ring *rx_ring,
}
/**
- * i40e_construct_skb - Allocate skb and populate it
+ * iavf_construct_skb - Allocate skb and populate it
* @rx_ring: rx descriptor ring to transact packets on
* @rx_buffer: rx buffer to pull data from
* @size: size of buffer to add to skb
@@ -1287,13 +1286,13 @@ static struct i40e_rx_buffer *i40e_get_rx_buffer(struct i40e_ring *rx_ring,
* data from the current receive descriptor, taking care to set up the
* skb correctly.
*/
-static struct sk_buff *i40e_construct_skb(struct i40e_ring *rx_ring,
- struct i40e_rx_buffer *rx_buffer,
+static struct sk_buff *iavf_construct_skb(struct iavf_ring *rx_ring,
+ struct iavf_rx_buffer *rx_buffer,
unsigned int size)
{
void *va = page_address(rx_buffer->page) + rx_buffer->page_offset;
#if (PAGE_SIZE < 8192)
- unsigned int truesize = i40e_rx_pg_size(rx_ring) / 2;
+ unsigned int truesize = iavf_rx_pg_size(rx_ring) / 2;
#else
unsigned int truesize = SKB_DATA_ALIGN(size);
#endif
@@ -1308,15 +1307,15 @@ static struct sk_buff *i40e_construct_skb(struct i40e_ring *rx_ring,
/* allocate a skb to store the frags */
skb = __napi_alloc_skb(&rx_ring->q_vector->napi,
- I40E_RX_HDR_SIZE,
+ IAVF_RX_HDR_SIZE,
GFP_ATOMIC | __GFP_NOWARN);
if (unlikely(!skb))
return NULL;
/* Determine available headroom for copy */
headlen = size;
- if (headlen > I40E_RX_HDR_SIZE)
- headlen = eth_get_headlen(va, I40E_RX_HDR_SIZE);
+ if (headlen > IAVF_RX_HDR_SIZE)
+ headlen = eth_get_headlen(va, IAVF_RX_HDR_SIZE);
/* align pull length to size of long to optimize memcpy performance */
memcpy(__skb_put(skb, headlen), va, ALIGN(headlen, sizeof(long)));
@@ -1343,7 +1342,7 @@ static struct sk_buff *i40e_construct_skb(struct i40e_ring *rx_ring,
}
/**
- * i40e_build_skb - Build skb around an existing buffer
+ * iavf_build_skb - Build skb around an existing buffer
* @rx_ring: Rx descriptor ring to transact packets on
* @rx_buffer: Rx buffer to pull data from
* @size: size of buffer to add to skb
@@ -1351,16 +1350,16 @@ static struct sk_buff *i40e_construct_skb(struct i40e_ring *rx_ring,
* This function builds an skb around an existing Rx buffer, taking care
* to set up the skb correctly and avoid any memcpy overhead.
*/
-static struct sk_buff *i40e_build_skb(struct i40e_ring *rx_ring,
- struct i40e_rx_buffer *rx_buffer,
+static struct sk_buff *iavf_build_skb(struct iavf_ring *rx_ring,
+ struct iavf_rx_buffer *rx_buffer,
unsigned int size)
{
void *va = page_address(rx_buffer->page) + rx_buffer->page_offset;
#if (PAGE_SIZE < 8192)
- unsigned int truesize = i40e_rx_pg_size(rx_ring) / 2;
+ unsigned int truesize = iavf_rx_pg_size(rx_ring) / 2;
#else
unsigned int truesize = SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) +
- SKB_DATA_ALIGN(I40E_SKB_PAD + size);
+ SKB_DATA_ALIGN(IAVF_SKB_PAD + size);
#endif
struct sk_buff *skb;
@@ -1370,12 +1369,12 @@ static struct sk_buff *i40e_build_skb(struct i40e_ring *rx_ring,
prefetch(va + L1_CACHE_BYTES);
#endif
/* build an skb around the page buffer */
- skb = build_skb(va - I40E_SKB_PAD, truesize);
+ skb = build_skb(va - IAVF_SKB_PAD, truesize);
if (unlikely(!skb))
return NULL;
/* update pointers within the skb to store the data */
- skb_reserve(skb, I40E_SKB_PAD);
+ skb_reserve(skb, IAVF_SKB_PAD);
__skb_put(skb, size);
/* buffer is used by skb, update page_offset */
@@ -1389,25 +1388,25 @@ static struct sk_buff *i40e_build_skb(struct i40e_ring *rx_ring,
}
/**
- * i40e_put_rx_buffer - Clean up used buffer and either recycle or free
+ * iavf_put_rx_buffer - Clean up used buffer and either recycle or free
* @rx_ring: rx descriptor ring to transact packets on
* @rx_buffer: rx buffer to pull data from
*
* This function will clean up the contents of the rx_buffer. It will
* either recycle the buffer or unmap it and free the associated resources.
*/
-static void i40e_put_rx_buffer(struct i40e_ring *rx_ring,
- struct i40e_rx_buffer *rx_buffer)
+static void iavf_put_rx_buffer(struct iavf_ring *rx_ring,
+ struct iavf_rx_buffer *rx_buffer)
{
- if (i40e_can_reuse_rx_page(rx_buffer)) {
+ if (iavf_can_reuse_rx_page(rx_buffer)) {
/* hand second half of page back to the ring */
- i40e_reuse_rx_page(rx_ring, rx_buffer);
+ iavf_reuse_rx_page(rx_ring, rx_buffer);
rx_ring->rx_stats.page_reuse_count++;
} else {
/* we are not reusing the buffer so unmap it */
dma_unmap_page_attrs(rx_ring->dev, rx_buffer->dma,
- i40e_rx_pg_size(rx_ring),
- DMA_FROM_DEVICE, I40E_RX_DMA_ATTR);
+ iavf_rx_pg_size(rx_ring),
+ DMA_FROM_DEVICE, IAVF_RX_DMA_ATTR);
__page_frag_cache_drain(rx_buffer->page,
rx_buffer->pagecnt_bias);
}
@@ -1417,7 +1416,7 @@ static void i40e_put_rx_buffer(struct i40e_ring *rx_ring,
}
/**
- * i40e_is_non_eop - process handling of non-EOP buffers
+ * iavf_is_non_eop - process handling of non-EOP buffers
* @rx_ring: Rx ring being processed
* @rx_desc: Rx descriptor for current buffer
* @skb: Current socket buffer containing buffer in progress
@@ -1427,8 +1426,8 @@ static void i40e_put_rx_buffer(struct i40e_ring *rx_ring,
* sk_buff in the next buffer to be chained and return true indicating
* that this is in fact a non-EOP buffer.
**/
-static bool i40e_is_non_eop(struct i40e_ring *rx_ring,
- union i40e_rx_desc *rx_desc,
+static bool iavf_is_non_eop(struct iavf_ring *rx_ring,
+ union iavf_rx_desc *rx_desc,
struct sk_buff *skb)
{
u32 ntc = rx_ring->next_to_clean + 1;
@@ -1437,11 +1436,11 @@ static bool i40e_is_non_eop(struct i40e_ring *rx_ring,
ntc = (ntc < rx_ring->count) ? ntc : 0;
rx_ring->next_to_clean = ntc;
- prefetch(I40E_RX_DESC(rx_ring, ntc));
+ prefetch(IAVF_RX_DESC(rx_ring, ntc));
/* if we are the last buffer then there is nothing else to do */
-#define I40E_RXD_EOF BIT(I40E_RX_DESC_STATUS_EOF_SHIFT)
- if (likely(i40e_test_staterr(rx_desc, I40E_RXD_EOF)))
+#define IAVF_RXD_EOF BIT(IAVF_RX_DESC_STATUS_EOF_SHIFT)
+ if (likely(iavf_test_staterr(rx_desc, IAVF_RXD_EOF)))
return false;
rx_ring->rx_stats.non_eop_descs++;
@@ -1450,7 +1449,7 @@ static bool i40e_is_non_eop(struct i40e_ring *rx_ring,
}
/**
- * i40e_clean_rx_irq - Clean completed descriptors from Rx ring - bounce buf
+ * iavf_clean_rx_irq - Clean completed descriptors from Rx ring - bounce buf
* @rx_ring: rx descriptor ring to transact packets on
* @budget: Total limit on number of packets to process
*
@@ -1461,29 +1460,29 @@ static bool i40e_is_non_eop(struct i40e_ring *rx_ring,
*
* Returns amount of work completed
**/
-static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+static int iavf_clean_rx_irq(struct iavf_ring *rx_ring, int budget)
{
unsigned int total_rx_bytes = 0, total_rx_packets = 0;
struct sk_buff *skb = rx_ring->skb;
- u16 cleaned_count = I40E_DESC_UNUSED(rx_ring);
+ u16 cleaned_count = IAVF_DESC_UNUSED(rx_ring);
bool failure = false;
while (likely(total_rx_packets < (unsigned int)budget)) {
- struct i40e_rx_buffer *rx_buffer;
- union i40e_rx_desc *rx_desc;
+ struct iavf_rx_buffer *rx_buffer;
+ union iavf_rx_desc *rx_desc;
unsigned int size;
u16 vlan_tag;
u8 rx_ptype;
u64 qword;
/* return some buffers to hardware, one at a time is too slow */
- if (cleaned_count >= I40E_RX_BUFFER_WRITE) {
+ if (cleaned_count >= IAVF_RX_BUFFER_WRITE) {
failure = failure ||
- i40evf_alloc_rx_buffers(rx_ring, cleaned_count);
+ iavf_alloc_rx_buffers(rx_ring, cleaned_count);
cleaned_count = 0;
}
- rx_desc = I40E_RX_DESC(rx_ring, rx_ring->next_to_clean);
+ rx_desc = IAVF_RX_DESC(rx_ring, rx_ring->next_to_clean);
/* status_error_len will always be zero for unused descriptors
* because it's cleared in cleanup, and overlaps with hdr_addr
@@ -1498,21 +1497,21 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
*/
dma_rmb();
- size = (qword & I40E_RXD_QW1_LENGTH_PBUF_MASK) >>
- I40E_RXD_QW1_LENGTH_PBUF_SHIFT;
+ size = (qword & IAVF_RXD_QW1_LENGTH_PBUF_MASK) >>
+ IAVF_RXD_QW1_LENGTH_PBUF_SHIFT;
if (!size)
break;
- i40e_trace(clean_rx_irq, rx_ring, rx_desc, skb);
- rx_buffer = i40e_get_rx_buffer(rx_ring, size);
+ iavf_trace(clean_rx_irq, rx_ring, rx_desc, skb);
+ rx_buffer = iavf_get_rx_buffer(rx_ring, size);
/* retrieve a buffer from the ring */
if (skb)
- i40e_add_rx_frag(rx_ring, rx_buffer, skb, size);
+ iavf_add_rx_frag(rx_ring, rx_buffer, skb, size);
else if (ring_uses_build_skb(rx_ring))
- skb = i40e_build_skb(rx_ring, rx_buffer, size);
+ skb = iavf_build_skb(rx_ring, rx_buffer, size);
else
- skb = i40e_construct_skb(rx_ring, rx_buffer, size);
+ skb = iavf_construct_skb(rx_ring, rx_buffer, size);
/* exit if we failed to retrieve a buffer */
if (!skb) {
@@ -1521,24 +1520,24 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
break;
}
- i40e_put_rx_buffer(rx_ring, rx_buffer);
+ iavf_put_rx_buffer(rx_ring, rx_buffer);
cleaned_count++;
- if (i40e_is_non_eop(rx_ring, rx_desc, skb))
+ if (iavf_is_non_eop(rx_ring, rx_desc, skb))
continue;
/* ERR_MASK will only have valid bits if EOP set, and
* what we are doing here is actually checking
- * I40E_RX_DESC_ERROR_RXE_SHIFT, since it is the zeroth bit in
+ * IAVF_RX_DESC_ERROR_RXE_SHIFT, since it is the zeroth bit in
* the error field
*/
- if (unlikely(i40e_test_staterr(rx_desc, BIT(I40E_RXD_QW1_ERROR_SHIFT)))) {
+ if (unlikely(iavf_test_staterr(rx_desc, BIT(IAVF_RXD_QW1_ERROR_SHIFT)))) {
dev_kfree_skb_any(skb);
skb = NULL;
continue;
}
- if (i40e_cleanup_headers(rx_ring, skb)) {
+ if (iavf_cleanup_headers(rx_ring, skb)) {
skb = NULL;
continue;
}
@@ -1547,18 +1546,18 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
total_rx_bytes += skb->len;
qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len);
- rx_ptype = (qword & I40E_RXD_QW1_PTYPE_MASK) >>
- I40E_RXD_QW1_PTYPE_SHIFT;
+ rx_ptype = (qword & IAVF_RXD_QW1_PTYPE_MASK) >>
+ IAVF_RXD_QW1_PTYPE_SHIFT;
/* populate checksum, VLAN, and protocol */
- i40evf_process_skb_fields(rx_ring, rx_desc, skb, rx_ptype);
+ iavf_process_skb_fields(rx_ring, rx_desc, skb, rx_ptype);
- vlan_tag = (qword & BIT(I40E_RX_DESC_STATUS_L2TAG1P_SHIFT)) ?
+ vlan_tag = (qword & BIT(IAVF_RX_DESC_STATUS_L2TAG1P_SHIFT)) ?
le16_to_cpu(rx_desc->wb.qword0.lo_dword.l2tag1) : 0;
- i40e_trace(clean_rx_irq_rx, rx_ring, rx_desc, skb);
- i40e_receive_skb(rx_ring, skb, vlan_tag);
+ iavf_trace(clean_rx_irq_rx, rx_ring, rx_desc, skb);
+ iavf_receive_skb(rx_ring, skb, vlan_tag);
skb = NULL;
/* update budget accounting */
@@ -1578,7 +1577,7 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
return failure ? budget : (int)total_rx_packets;
}
-static inline u32 i40e_buildreg_itr(const int type, u16 itr)
+static inline u32 iavf_buildreg_itr(const int type, u16 itr)
{
u32 val;
@@ -1597,17 +1596,17 @@ static inline u32 i40e_buildreg_itr(const int type, u16 itr)
* only need to shift by the interval shift - 1 instead of the
* full value.
*/
- itr &= I40E_ITR_MASK;
+ itr &= IAVF_ITR_MASK;
- val = I40E_VFINT_DYN_CTLN1_INTENA_MASK |
- (type << I40E_VFINT_DYN_CTLN1_ITR_INDX_SHIFT) |
- (itr << (I40E_VFINT_DYN_CTLN1_INTERVAL_SHIFT - 1));
+ val = IAVF_VFINT_DYN_CTLN1_INTENA_MASK |
+ (type << IAVF_VFINT_DYN_CTLN1_ITR_INDX_SHIFT) |
+ (itr << (IAVF_VFINT_DYN_CTLN1_INTERVAL_SHIFT - 1));
return val;
}
/* a small macro to shorten up some long lines */
-#define INTREG I40E_VFINT_DYN_CTLN1
+#define INTREG IAVF_VFINT_DYN_CTLN1
/* The act of updating the ITR will cause it to immediately trigger. In order
* to prevent this from throwing off adaptive update statistics we defer the
@@ -1619,20 +1618,20 @@ static inline u32 i40e_buildreg_itr(const int type, u16 itr)
#define ITR_COUNTDOWN_START 3
/**
- * i40e_update_enable_itr - Update itr and re-enable MSIX interrupt
+ * iavf_update_enable_itr - Update itr and re-enable MSIX interrupt
* @vsi: the VSI we care about
* @q_vector: q_vector for which itr is being updated and interrupt enabled
*
**/
-static inline void i40e_update_enable_itr(struct i40e_vsi *vsi,
- struct i40e_q_vector *q_vector)
+static inline void iavf_update_enable_itr(struct iavf_vsi *vsi,
+ struct iavf_q_vector *q_vector)
{
- struct i40e_hw *hw = &vsi->back->hw;
+ struct iavf_hw *hw = &vsi->back->hw;
u32 intval;
/* These will do nothing if dynamic updates are not enabled */
- i40e_update_itr(q_vector, &q_vector->tx);
- i40e_update_itr(q_vector, &q_vector->rx);
+ iavf_update_itr(q_vector, &q_vector->tx);
+ iavf_update_itr(q_vector, &q_vector->rx);
/* This block of logic allows us to get away with only updating
* one ITR value with each interrupt. The idea is to perform a
@@ -1644,7 +1643,7 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi,
*/
if (q_vector->rx.target_itr < q_vector->rx.current_itr) {
/* Rx ITR needs to be reduced, this is highest priority */
- intval = i40e_buildreg_itr(I40E_RX_ITR,
+ intval = iavf_buildreg_itr(IAVF_RX_ITR,
q_vector->rx.target_itr);
q_vector->rx.current_itr = q_vector->rx.target_itr;
q_vector->itr_countdown = ITR_COUNTDOWN_START;
@@ -1654,29 +1653,29 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi,
/* Tx ITR needs to be reduced, this is second priority
* Tx ITR needs to be increased more than Rx, fourth priority
*/
- intval = i40e_buildreg_itr(I40E_TX_ITR,
+ intval = iavf_buildreg_itr(IAVF_TX_ITR,
q_vector->tx.target_itr);
q_vector->tx.current_itr = q_vector->tx.target_itr;
q_vector->itr_countdown = ITR_COUNTDOWN_START;
} else if (q_vector->rx.current_itr != q_vector->rx.target_itr) {
/* Rx ITR needs to be increased, third priority */
- intval = i40e_buildreg_itr(I40E_RX_ITR,
+ intval = iavf_buildreg_itr(IAVF_RX_ITR,
q_vector->rx.target_itr);
q_vector->rx.current_itr = q_vector->rx.target_itr;
q_vector->itr_countdown = ITR_COUNTDOWN_START;
} else {
/* No ITR update, lowest priority */
- intval = i40e_buildreg_itr(I40E_ITR_NONE, 0);
+ intval = iavf_buildreg_itr(IAVF_ITR_NONE, 0);
if (q_vector->itr_countdown)
q_vector->itr_countdown--;
}
- if (!test_bit(__I40E_VSI_DOWN, vsi->state))
+ if (!test_bit(__IAVF_VSI_DOWN, vsi->state))
wr32(hw, INTREG(q_vector->reg_idx), intval);
}
/**
- * i40evf_napi_poll - NAPI polling Rx/Tx cleanup routine
+ * iavf_napi_poll - NAPI polling Rx/Tx cleanup routine
* @napi: napi struct with our devices info in it
* @budget: amount of work driver is allowed to do this pass, in packets
*
@@ -1684,18 +1683,18 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi,
*
* Returns the amount of work done
**/
-int i40evf_napi_poll(struct napi_struct *napi, int budget)
+int iavf_napi_poll(struct napi_struct *napi, int budget)
{
- struct i40e_q_vector *q_vector =
- container_of(napi, struct i40e_q_vector, napi);
- struct i40e_vsi *vsi = q_vector->vsi;
- struct i40e_ring *ring;
+ struct iavf_q_vector *q_vector =
+ container_of(napi, struct iavf_q_vector, napi);
+ struct iavf_vsi *vsi = q_vector->vsi;
+ struct iavf_ring *ring;
bool clean_complete = true;
bool arm_wb = false;
int budget_per_ring;
int work_done = 0;
- if (test_bit(__I40E_VSI_DOWN, vsi->state)) {
+ if (test_bit(__IAVF_VSI_DOWN, vsi->state)) {
napi_complete(napi);
return 0;
}
@@ -1703,8 +1702,8 @@ int i40evf_napi_poll(struct napi_struct *napi, int budget)
/* Since the actual Tx work is minimal, we can give the Tx a larger
* budget and be more aggressive about cleaning up the Tx descriptors.
*/
- i40e_for_each_ring(ring, q_vector->tx) {
- if (!i40e_clean_tx_irq(vsi, ring, budget)) {
+ iavf_for_each_ring(ring, q_vector->tx) {
+ if (!iavf_clean_tx_irq(vsi, ring, budget)) {
clean_complete = false;
continue;
}
@@ -1721,8 +1720,8 @@ int i40evf_napi_poll(struct napi_struct *napi, int budget)
*/
budget_per_ring = max(budget/q_vector->num_ringpairs, 1);
- i40e_for_each_ring(ring, q_vector->rx) {
- int cleaned = i40e_clean_rx_irq(ring, budget_per_ring);
+ iavf_for_each_ring(ring, q_vector->rx) {
+ int cleaned = iavf_clean_rx_irq(ring, budget_per_ring);
work_done += cleaned;
/* if we clean as many as budgeted, we must not be done */
@@ -1746,7 +1745,7 @@ int i40evf_napi_poll(struct napi_struct *napi, int budget)
napi_complete_done(napi, work_done);
/* Force an interrupt */
- i40evf_force_wb(vsi, q_vector);
+ iavf_force_wb(vsi, q_vector);
/* Return budget-1 so that polling stops */
return budget - 1;
@@ -1754,24 +1753,24 @@ int i40evf_napi_poll(struct napi_struct *napi, int budget)
tx_only:
if (arm_wb) {
q_vector->tx.ring[0].tx_stats.tx_force_wb++;
- i40e_enable_wb_on_itr(vsi, q_vector);
+ iavf_enable_wb_on_itr(vsi, q_vector);
}
return budget;
}
- if (vsi->back->flags & I40E_TXR_FLAGS_WB_ON_ITR)
+ if (vsi->back->flags & IAVF_TXR_FLAGS_WB_ON_ITR)
q_vector->arm_wb_state = false;
/* Work is done so exit the polling mode and re-enable the interrupt */
napi_complete_done(napi, work_done);
- i40e_update_enable_itr(vsi, q_vector);
+ iavf_update_enable_itr(vsi, q_vector);
return min(work_done, budget - 1);
}
/**
- * i40evf_tx_prepare_vlan_flags - prepare generic TX VLAN tagging flags for HW
+ * iavf_tx_prepare_vlan_flags - prepare generic TX VLAN tagging flags for HW
* @skb: send buffer
* @tx_ring: ring to send buffer on
* @flags: the tx flags to be set
@@ -1782,9 +1781,9 @@ tx_only:
* Returns error code indicate the frame should be dropped upon error and the
* otherwise returns 0 to indicate the flags has been set properly.
**/
-static inline int i40evf_tx_prepare_vlan_flags(struct sk_buff *skb,
- struct i40e_ring *tx_ring,
- u32 *flags)
+static inline int iavf_tx_prepare_vlan_flags(struct sk_buff *skb,
+ struct iavf_ring *tx_ring,
+ u32 *flags)
{
__be16 protocol = skb->protocol;
u32 tx_flags = 0;
@@ -1804,8 +1803,8 @@ static inline int i40evf_tx_prepare_vlan_flags(struct sk_buff *skb,
/* if we have a HW VLAN tag being added, default to the HW one */
if (skb_vlan_tag_present(skb)) {
- tx_flags |= skb_vlan_tag_get(skb) << I40E_TX_FLAGS_VLAN_SHIFT;
- tx_flags |= I40E_TX_FLAGS_HW_VLAN;
+ tx_flags |= skb_vlan_tag_get(skb) << IAVF_TX_FLAGS_VLAN_SHIFT;
+ tx_flags |= IAVF_TX_FLAGS_HW_VLAN;
/* else if it is a SW VLAN, check the next protocol and store the tag */
} else if (protocol == htons(ETH_P_8021Q)) {
struct vlan_hdr *vhdr, _vhdr;
@@ -1815,8 +1814,8 @@ static inline int i40evf_tx_prepare_vlan_flags(struct sk_buff *skb,
return -EINVAL;
protocol = vhdr->h_vlan_encapsulated_proto;
- tx_flags |= ntohs(vhdr->h_vlan_TCI) << I40E_TX_FLAGS_VLAN_SHIFT;
- tx_flags |= I40E_TX_FLAGS_SW_VLAN;
+ tx_flags |= ntohs(vhdr->h_vlan_TCI) << IAVF_TX_FLAGS_VLAN_SHIFT;
+ tx_flags |= IAVF_TX_FLAGS_SW_VLAN;
}
out:
@@ -1825,14 +1824,14 @@ out:
}
/**
- * i40e_tso - set up the tso context descriptor
+ * iavf_tso - set up the tso context descriptor
* @first: pointer to first Tx buffer for xmit
* @hdr_len: ptr to the size of the packet header
* @cd_type_cmd_tso_mss: Quad Word 1
*
* Returns 0 if no TSO can happen, 1 if tso is going, or error
**/
-static int i40e_tso(struct i40e_tx_buffer *first, u8 *hdr_len,
+static int iavf_tso(struct iavf_tx_buffer *first, u8 *hdr_len,
u64 *cd_type_cmd_tso_mss)
{
struct sk_buff *skb = first->skb;
@@ -1923,17 +1922,17 @@ static int i40e_tso(struct i40e_tx_buffer *first, u8 *hdr_len,
first->bytecount += (first->gso_segs - 1) * *hdr_len;
/* find the field values */
- cd_cmd = I40E_TX_CTX_DESC_TSO;
+ cd_cmd = IAVF_TX_CTX_DESC_TSO;
cd_tso_len = skb->len - *hdr_len;
cd_mss = gso_size;
- *cd_type_cmd_tso_mss |= (cd_cmd << I40E_TXD_CTX_QW1_CMD_SHIFT) |
- (cd_tso_len << I40E_TXD_CTX_QW1_TSO_LEN_SHIFT) |
- (cd_mss << I40E_TXD_CTX_QW1_MSS_SHIFT);
+ *cd_type_cmd_tso_mss |= (cd_cmd << IAVF_TXD_CTX_QW1_CMD_SHIFT) |
+ (cd_tso_len << IAVF_TXD_CTX_QW1_TSO_LEN_SHIFT) |
+ (cd_mss << IAVF_TXD_CTX_QW1_MSS_SHIFT);
return 1;
}
/**
- * i40e_tx_enable_csum - Enable Tx checksum offloads
+ * iavf_tx_enable_csum - Enable Tx checksum offloads
* @skb: send buffer
* @tx_flags: pointer to Tx flags currently set
* @td_cmd: Tx descriptor command bits to set
@@ -1941,9 +1940,9 @@ static int i40e_tso(struct i40e_tx_buffer *first, u8 *hdr_len,
* @tx_ring: Tx descriptor ring
* @cd_tunneling: ptr to context desc bits
**/
-static int i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,
+static int iavf_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,
u32 *td_cmd, u32 *td_offset,
- struct i40e_ring *tx_ring,
+ struct iavf_ring *tx_ring,
u32 *cd_tunneling)
{
union {
@@ -1968,19 +1967,19 @@ static int i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,
l4.hdr = skb_transport_header(skb);
/* compute outer L2 header size */
- offset = ((ip.hdr - skb->data) / 2) << I40E_TX_DESC_LENGTH_MACLEN_SHIFT;
+ offset = ((ip.hdr - skb->data) / 2) << IAVF_TX_DESC_LENGTH_MACLEN_SHIFT;
if (skb->encapsulation) {
u32 tunnel = 0;
/* define outer network header type */
- if (*tx_flags & I40E_TX_FLAGS_IPV4) {
- tunnel |= (*tx_flags & I40E_TX_FLAGS_TSO) ?
- I40E_TX_CTX_EXT_IP_IPV4 :
- I40E_TX_CTX_EXT_IP_IPV4_NO_CSUM;
+ if (*tx_flags & IAVF_TX_FLAGS_IPV4) {
+ tunnel |= (*tx_flags & IAVF_TX_FLAGS_TSO) ?
+ IAVF_TX_CTX_EXT_IP_IPV4 :
+ IAVF_TX_CTX_EXT_IP_IPV4_NO_CSUM;
l4_proto = ip.v4->protocol;
- } else if (*tx_flags & I40E_TX_FLAGS_IPV6) {
- tunnel |= I40E_TX_CTX_EXT_IP_IPV6;
+ } else if (*tx_flags & IAVF_TX_FLAGS_IPV6) {
+ tunnel |= IAVF_TX_CTX_EXT_IP_IPV6;
exthdr = ip.hdr + sizeof(*ip.v6);
l4_proto = ip.v6->nexthdr;
@@ -1992,20 +1991,20 @@ static int i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,
/* define outer transport */
switch (l4_proto) {
case IPPROTO_UDP:
- tunnel |= I40E_TXD_CTX_UDP_TUNNELING;
- *tx_flags |= I40E_TX_FLAGS_VXLAN_TUNNEL;
+ tunnel |= IAVF_TXD_CTX_UDP_TUNNELING;
+ *tx_flags |= IAVF_TX_FLAGS_VXLAN_TUNNEL;
break;
case IPPROTO_GRE:
- tunnel |= I40E_TXD_CTX_GRE_TUNNELING;
- *tx_flags |= I40E_TX_FLAGS_VXLAN_TUNNEL;
+ tunnel |= IAVF_TXD_CTX_GRE_TUNNELING;
+ *tx_flags |= IAVF_TX_FLAGS_VXLAN_TUNNEL;
break;
case IPPROTO_IPIP:
case IPPROTO_IPV6:
- *tx_flags |= I40E_TX_FLAGS_VXLAN_TUNNEL;
+ *tx_flags |= IAVF_TX_FLAGS_VXLAN_TUNNEL;
l4.hdr = skb_inner_network_header(skb);
break;
default:
- if (*tx_flags & I40E_TX_FLAGS_TSO)
+ if (*tx_flags & IAVF_TX_FLAGS_TSO)
return -1;
skb_checksum_help(skb);
@@ -2014,20 +2013,20 @@ static int i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,
/* compute outer L3 header size */
tunnel |= ((l4.hdr - ip.hdr) / 4) <<
- I40E_TXD_CTX_QW0_EXT_IPLEN_SHIFT;
+ IAVF_TXD_CTX_QW0_EXT_IPLEN_SHIFT;
/* switch IP header pointer from outer to inner header */
ip.hdr = skb_inner_network_header(skb);
/* compute tunnel header size */
tunnel |= ((ip.hdr - l4.hdr) / 2) <<
- I40E_TXD_CTX_QW0_NATLEN_SHIFT;
+ IAVF_TXD_CTX_QW0_NATLEN_SHIFT;
/* indicate if we need to offload outer UDP header */
- if ((*tx_flags & I40E_TX_FLAGS_TSO) &&
+ if ((*tx_flags & IAVF_TX_FLAGS_TSO) &&
!(skb_shinfo(skb)->gso_type & SKB_GSO_PARTIAL) &&
(skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM))
- tunnel |= I40E_TXD_CTX_QW0_L4T_CS_MASK;
+ tunnel |= IAVF_TXD_CTX_QW0_L4T_CS_MASK;
/* record tunnel offload values */
*cd_tunneling |= tunnel;
@@ -2037,24 +2036,24 @@ static int i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,
l4_proto = 0;
/* reset type as we transition from outer to inner headers */
- *tx_flags &= ~(I40E_TX_FLAGS_IPV4 | I40E_TX_FLAGS_IPV6);
+ *tx_flags &= ~(IAVF_TX_FLAGS_IPV4 | IAVF_TX_FLAGS_IPV6);
if (ip.v4->version == 4)
- *tx_flags |= I40E_TX_FLAGS_IPV4;
+ *tx_flags |= IAVF_TX_FLAGS_IPV4;
if (ip.v6->version == 6)
- *tx_flags |= I40E_TX_FLAGS_IPV6;
+ *tx_flags |= IAVF_TX_FLAGS_IPV6;
}
/* Enable IP checksum offloads */
- if (*tx_flags & I40E_TX_FLAGS_IPV4) {
+ if (*tx_flags & IAVF_TX_FLAGS_IPV4) {
l4_proto = ip.v4->protocol;
/* the stack computes the IP header already, the only time we
* need the hardware to recompute it is in the case of TSO.
*/
- cmd |= (*tx_flags & I40E_TX_FLAGS_TSO) ?
- I40E_TX_DESC_CMD_IIPT_IPV4_CSUM :
- I40E_TX_DESC_CMD_IIPT_IPV4;
- } else if (*tx_flags & I40E_TX_FLAGS_IPV6) {
- cmd |= I40E_TX_DESC_CMD_IIPT_IPV6;
+ cmd |= (*tx_flags & IAVF_TX_FLAGS_TSO) ?
+ IAVF_TX_DESC_CMD_IIPT_IPV4_CSUM :
+ IAVF_TX_DESC_CMD_IIPT_IPV4;
+ } else if (*tx_flags & IAVF_TX_FLAGS_IPV6) {
+ cmd |= IAVF_TX_DESC_CMD_IIPT_IPV6;
exthdr = ip.hdr + sizeof(*ip.v6);
l4_proto = ip.v6->nexthdr;
@@ -2064,29 +2063,29 @@ static int i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,
}
/* compute inner L3 header size */
- offset |= ((l4.hdr - ip.hdr) / 4) << I40E_TX_DESC_LENGTH_IPLEN_SHIFT;
+ offset |= ((l4.hdr - ip.hdr) / 4) << IAVF_TX_DESC_LENGTH_IPLEN_SHIFT;
/* Enable L4 checksum offloads */
switch (l4_proto) {
case IPPROTO_TCP:
/* enable checksum offloads */
- cmd |= I40E_TX_DESC_CMD_L4T_EOFT_TCP;
- offset |= l4.tcp->doff << I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
+ cmd |= IAVF_TX_DESC_CMD_L4T_EOFT_TCP;
+ offset |= l4.tcp->doff << IAVF_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
break;
case IPPROTO_SCTP:
/* enable SCTP checksum offload */
- cmd |= I40E_TX_DESC_CMD_L4T_EOFT_SCTP;
+ cmd |= IAVF_TX_DESC_CMD_L4T_EOFT_SCTP;
offset |= (sizeof(struct sctphdr) >> 2) <<
- I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
+ IAVF_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
break;
case IPPROTO_UDP:
/* enable UDP checksum offload */
- cmd |= I40E_TX_DESC_CMD_L4T_EOFT_UDP;
+ cmd |= IAVF_TX_DESC_CMD_L4T_EOFT_UDP;
offset |= (sizeof(struct udphdr) >> 2) <<
- I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
+ IAVF_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
break;
default:
- if (*tx_flags & I40E_TX_FLAGS_TSO)
+ if (*tx_flags & IAVF_TX_FLAGS_TSO)
return -1;
skb_checksum_help(skb);
return 0;
@@ -2099,25 +2098,25 @@ static int i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,
}
/**
- * i40e_create_tx_ctx Build the Tx context descriptor
+ * iavf_create_tx_ctx Build the Tx context descriptor
* @tx_ring: ring to create the descriptor on
* @cd_type_cmd_tso_mss: Quad Word 1
* @cd_tunneling: Quad Word 0 - bits 0-31
* @cd_l2tag2: Quad Word 0 - bits 32-63
**/
-static void i40e_create_tx_ctx(struct i40e_ring *tx_ring,
+static void iavf_create_tx_ctx(struct iavf_ring *tx_ring,
const u64 cd_type_cmd_tso_mss,
const u32 cd_tunneling, const u32 cd_l2tag2)
{
- struct i40e_tx_context_desc *context_desc;
+ struct iavf_tx_context_desc *context_desc;
int i = tx_ring->next_to_use;
- if ((cd_type_cmd_tso_mss == I40E_TX_DESC_DTYPE_CONTEXT) &&
+ if ((cd_type_cmd_tso_mss == IAVF_TX_DESC_DTYPE_CONTEXT) &&
!cd_tunneling && !cd_l2tag2)
return;
/* grab the next descriptor */
- context_desc = I40E_TX_CTXTDESC(tx_ring, i);
+ context_desc = IAVF_TX_CTXTDESC(tx_ring, i);
i++;
tx_ring->next_to_use = (i < tx_ring->count) ? i : 0;
@@ -2130,7 +2129,7 @@ static void i40e_create_tx_ctx(struct i40e_ring *tx_ring,
}
/**
- * __i40evf_chk_linearize - Check if there are more than 8 buffers per packet
+ * __iavf_chk_linearize - Check if there are more than 8 buffers per packet
* @skb: send buffer
*
* Note: Our HW can't DMA more than 8 buffers to build a packet on the wire
@@ -2142,20 +2141,20 @@ static void i40e_create_tx_ctx(struct i40e_ring *tx_ring,
* the segment payload in the first descriptor, and another 7 for the
* fragments.
**/
-bool __i40evf_chk_linearize(struct sk_buff *skb)
+bool __iavf_chk_linearize(struct sk_buff *skb)
{
const struct skb_frag_struct *frag, *stale;
int nr_frags, sum;
/* no need to check if number of frags is less than 7 */
nr_frags = skb_shinfo(skb)->nr_frags;
- if (nr_frags < (I40E_MAX_BUFFER_TXD - 1))
+ if (nr_frags < (IAVF_MAX_BUFFER_TXD - 1))
return false;
/* We need to walk through the list and validate that each group
* of 6 fragments totals at least gso_size.
*/
- nr_frags -= I40E_MAX_BUFFER_TXD - 2;
+ nr_frags -= IAVF_MAX_BUFFER_TXD - 2;
frag = &skb_shinfo(skb)->frags[0];
/* Initialize size to the negative value of gso_size minus 1. We
@@ -2187,17 +2186,17 @@ bool __i40evf_chk_linearize(struct sk_buff *skb)
* figure out what the remainder would be in the last
* descriptor associated with the fragment.
*/
- if (stale_size > I40E_MAX_DATA_PER_TXD) {
+ if (stale_size > IAVF_MAX_DATA_PER_TXD) {
int align_pad = -(stale->page_offset) &
- (I40E_MAX_READ_REQ_SIZE - 1);
+ (IAVF_MAX_READ_REQ_SIZE - 1);
sum -= align_pad;
stale_size -= align_pad;
do {
- sum -= I40E_MAX_DATA_PER_TXD_ALIGNED;
- stale_size -= I40E_MAX_DATA_PER_TXD_ALIGNED;
- } while (stale_size > I40E_MAX_DATA_PER_TXD);
+ sum -= IAVF_MAX_DATA_PER_TXD_ALIGNED;
+ stale_size -= IAVF_MAX_DATA_PER_TXD_ALIGNED;
+ } while (stale_size > IAVF_MAX_DATA_PER_TXD);
}
/* if sum is negative we failed to make sufficient progress */
@@ -2214,20 +2213,20 @@ bool __i40evf_chk_linearize(struct sk_buff *skb)
}
/**
- * __i40evf_maybe_stop_tx - 2nd level check for tx stop conditions
+ * __iavf_maybe_stop_tx - 2nd level check for tx stop conditions
* @tx_ring: the ring to be checked
* @size: the size buffer we want to assure is available
*
* Returns -EBUSY if a stop is needed, else 0
**/
-int __i40evf_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
+int __iavf_maybe_stop_tx(struct iavf_ring *tx_ring, int size)
{
netif_stop_subqueue(tx_ring->netdev, tx_ring->queue_index);
/* Memory barrier before checking head and tail */
smp_mb();
/* Check again in a case another CPU has just made room available. */
- if (likely(I40E_DESC_UNUSED(tx_ring) < size))
+ if (likely(IAVF_DESC_UNUSED(tx_ring) < size))
return -EBUSY;
/* A reprieve! - use start_queue because it doesn't call schedule */
@@ -2237,7 +2236,7 @@ int __i40evf_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
}
/**
- * i40evf_tx_map - Build the Tx descriptor
+ * iavf_tx_map - Build the Tx descriptor
* @tx_ring: ring to send buffer on
* @skb: send buffer
* @first: first buffer info buffer to use
@@ -2246,34 +2245,34 @@ int __i40evf_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
* @td_cmd: the command field in the descriptor
* @td_offset: offset for checksum or crc
**/
-static inline void i40evf_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
- struct i40e_tx_buffer *first, u32 tx_flags,
- const u8 hdr_len, u32 td_cmd, u32 td_offset)
+static inline void iavf_tx_map(struct iavf_ring *tx_ring, struct sk_buff *skb,
+ struct iavf_tx_buffer *first, u32 tx_flags,
+ const u8 hdr_len, u32 td_cmd, u32 td_offset)
{
unsigned int data_len = skb->data_len;
unsigned int size = skb_headlen(skb);
struct skb_frag_struct *frag;
- struct i40e_tx_buffer *tx_bi;
- struct i40e_tx_desc *tx_desc;
+ struct iavf_tx_buffer *tx_bi;
+ struct iavf_tx_desc *tx_desc;
u16 i = tx_ring->next_to_use;
u32 td_tag = 0;
dma_addr_t dma;
- if (tx_flags & I40E_TX_FLAGS_HW_VLAN) {
- td_cmd |= I40E_TX_DESC_CMD_IL2TAG1;
- td_tag = (tx_flags & I40E_TX_FLAGS_VLAN_MASK) >>
- I40E_TX_FLAGS_VLAN_SHIFT;
+ if (tx_flags & IAVF_TX_FLAGS_HW_VLAN) {
+ td_cmd |= IAVF_TX_DESC_CMD_IL2TAG1;
+ td_tag = (tx_flags & IAVF_TX_FLAGS_VLAN_MASK) >>
+ IAVF_TX_FLAGS_VLAN_SHIFT;
}
first->tx_flags = tx_flags;
dma = dma_map_single(tx_ring->dev, skb->data, size, DMA_TO_DEVICE);
- tx_desc = I40E_TX_DESC(tx_ring, i);
+ tx_desc = IAVF_TX_DESC(tx_ring, i);
tx_bi = first;
for (frag = &skb_shinfo(skb)->frags[0];; frag++) {
- unsigned int max_data = I40E_MAX_DATA_PER_TXD_ALIGNED;
+ unsigned int max_data = IAVF_MAX_DATA_PER_TXD_ALIGNED;
if (dma_mapping_error(tx_ring->dev, dma))
goto dma_error;
@@ -2283,10 +2282,10 @@ static inline void i40evf_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
dma_unmap_addr_set(tx_bi, dma, dma);
/* align size to end of page */
- max_data += -dma & (I40E_MAX_READ_REQ_SIZE - 1);
+ max_data += -dma & (IAVF_MAX_READ_REQ_SIZE - 1);
tx_desc->buffer_addr = cpu_to_le64(dma);
- while (unlikely(size > I40E_MAX_DATA_PER_TXD)) {
+ while (unlikely(size > IAVF_MAX_DATA_PER_TXD)) {
tx_desc->cmd_type_offset_bsz =
build_ctob(td_cmd, td_offset,
max_data, td_tag);
@@ -2295,14 +2294,14 @@ static inline void i40evf_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
i++;
if (i == tx_ring->count) {
- tx_desc = I40E_TX_DESC(tx_ring, 0);
+ tx_desc = IAVF_TX_DESC(tx_ring, 0);
i = 0;
}
dma += max_data;
size -= max_data;
- max_data = I40E_MAX_DATA_PER_TXD_ALIGNED;
+ max_data = IAVF_MAX_DATA_PER_TXD_ALIGNED;
tx_desc->buffer_addr = cpu_to_le64(dma);
}
@@ -2316,7 +2315,7 @@ static inline void i40evf_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
i++;
if (i == tx_ring->count) {
- tx_desc = I40E_TX_DESC(tx_ring, 0);
+ tx_desc = IAVF_TX_DESC(tx_ring, 0);
i = 0;
}
@@ -2337,10 +2336,10 @@ static inline void i40evf_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
tx_ring->next_to_use = i;
- i40e_maybe_stop_tx(tx_ring, DESC_NEEDED);
+ iavf_maybe_stop_tx(tx_ring, DESC_NEEDED);
/* write last descriptor with RS and EOP bits */
- td_cmd |= I40E_TXD_CMD;
+ td_cmd |= IAVF_TXD_CMD;
tx_desc->cmd_type_offset_bsz =
build_ctob(td_cmd, td_offset, size, td_tag);
@@ -2373,7 +2372,7 @@ dma_error:
/* clear dma mappings for failed tx_bi map */
for (;;) {
tx_bi = &tx_ring->tx_bi[i];
- i40e_unmap_and_free_tx_resource(tx_ring, tx_bi);
+ iavf_unmap_and_free_tx_resource(tx_ring, tx_bi);
if (tx_bi == first)
break;
if (i == 0)
@@ -2385,18 +2384,18 @@ dma_error:
}
/**
- * i40e_xmit_frame_ring - Sends buffer on Tx ring
+ * iavf_xmit_frame_ring - Sends buffer on Tx ring
* @skb: send buffer
* @tx_ring: ring to send buffer on
*
* Returns NETDEV_TX_OK if sent, else an error code
**/
-static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
- struct i40e_ring *tx_ring)
+static netdev_tx_t iavf_xmit_frame_ring(struct sk_buff *skb,
+ struct iavf_ring *tx_ring)
{
- u64 cd_type_cmd_tso_mss = I40E_TX_DESC_DTYPE_CONTEXT;
+ u64 cd_type_cmd_tso_mss = IAVF_TX_DESC_DTYPE_CONTEXT;
u32 cd_tunneling = 0, cd_l2tag2 = 0;
- struct i40e_tx_buffer *first;
+ struct iavf_tx_buffer *first;
u32 td_offset = 0;
u32 tx_flags = 0;
__be16 protocol;
@@ -2407,25 +2406,25 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
/* prefetch the data, we'll need it later */
prefetch(skb->data);
- i40e_trace(xmit_frame_ring, skb, tx_ring);
+ iavf_trace(xmit_frame_ring, skb, tx_ring);
- count = i40e_xmit_descriptor_count(skb);
- if (i40e_chk_linearize(skb, count)) {
+ count = iavf_xmit_descriptor_count(skb);
+ if (iavf_chk_linearize(skb, count)) {
if (__skb_linearize(skb)) {
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
- count = i40e_txd_use_count(skb->len);
+ count = iavf_txd_use_count(skb->len);
tx_ring->tx_stats.tx_linearize++;
}
- /* need: 1 descriptor per page * PAGE_SIZE/I40E_MAX_DATA_PER_TXD,
- * + 1 desc for skb_head_len/I40E_MAX_DATA_PER_TXD,
+ /* need: 1 descriptor per page * PAGE_SIZE/IAVF_MAX_DATA_PER_TXD,
+ * + 1 desc for skb_head_len/IAVF_MAX_DATA_PER_TXD,
* + 4 desc gap to avoid the cache line where head is,
* + 1 desc for context descriptor,
* otherwise try next time
*/
- if (i40e_maybe_stop_tx(tx_ring, count + 4 + 1)) {
+ if (iavf_maybe_stop_tx(tx_ring, count + 4 + 1)) {
tx_ring->tx_stats.tx_busy++;
return NETDEV_TX_BUSY;
}
@@ -2437,7 +2436,7 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
first->gso_segs = 1;
/* prepare the xmit flags */
- if (i40evf_tx_prepare_vlan_flags(skb, tx_ring, &tx_flags))
+ if (iavf_tx_prepare_vlan_flags(skb, tx_ring, &tx_flags))
goto out_drop;
/* obtain protocol of skb */
@@ -2445,19 +2444,19 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
/* setup IPv4/IPv6 offloads */
if (protocol == htons(ETH_P_IP))
- tx_flags |= I40E_TX_FLAGS_IPV4;
+ tx_flags |= IAVF_TX_FLAGS_IPV4;
else if (protocol == htons(ETH_P_IPV6))
- tx_flags |= I40E_TX_FLAGS_IPV6;
+ tx_flags |= IAVF_TX_FLAGS_IPV6;
- tso = i40e_tso(first, &hdr_len, &cd_type_cmd_tso_mss);
+ tso = iavf_tso(first, &hdr_len, &cd_type_cmd_tso_mss);
if (tso < 0)
goto out_drop;
else if (tso)
- tx_flags |= I40E_TX_FLAGS_TSO;
+ tx_flags |= IAVF_TX_FLAGS_TSO;
/* Always offload the checksum, since it's in the data descriptor */
- tso = i40e_tx_enable_csum(skb, &tx_flags, &td_cmd, &td_offset,
+ tso = iavf_tx_enable_csum(skb, &tx_flags, &td_cmd, &td_offset,
tx_ring, &cd_tunneling);
if (tso < 0)
goto out_drop;
@@ -2465,44 +2464,44 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
skb_tx_timestamp(skb);
/* always enable CRC insertion offload */
- td_cmd |= I40E_TX_DESC_CMD_ICRC;
+ td_cmd |= IAVF_TX_DESC_CMD_ICRC;
- i40e_create_tx_ctx(tx_ring, cd_type_cmd_tso_mss,
+ iavf_create_tx_ctx(tx_ring, cd_type_cmd_tso_mss,
cd_tunneling, cd_l2tag2);
- i40evf_tx_map(tx_ring, skb, first, tx_flags, hdr_len,
- td_cmd, td_offset);
+ iavf_tx_map(tx_ring, skb, first, tx_flags, hdr_len,
+ td_cmd, td_offset);
return NETDEV_TX_OK;
out_drop:
- i40e_trace(xmit_frame_ring_drop, first->skb, tx_ring);
+ iavf_trace(xmit_frame_ring_drop, first->skb, tx_ring);
dev_kfree_skb_any(first->skb);
first->skb = NULL;
return NETDEV_TX_OK;
}
/**
- * i40evf_xmit_frame - Selects the correct VSI and Tx queue to send buffer
+ * iavf_xmit_frame - Selects the correct VSI and Tx queue to send buffer
* @skb: send buffer
* @netdev: network interface device structure
*
* Returns NETDEV_TX_OK if sent, else an error code
**/
-netdev_tx_t i40evf_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+netdev_tx_t iavf_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
{
- struct i40evf_adapter *adapter = netdev_priv(netdev);
- struct i40e_ring *tx_ring = &adapter->tx_rings[skb->queue_mapping];
+ struct iavf_adapter *adapter = netdev_priv(netdev);
+ struct iavf_ring *tx_ring = &adapter->tx_rings[skb->queue_mapping];
/* hardware can't handle really short frames, hardware padding works
* beyond this point
*/
- if (unlikely(skb->len < I40E_MIN_TX_LEN)) {
- if (skb_pad(skb, I40E_MIN_TX_LEN - skb->len))
+ if (unlikely(skb->len < IAVF_MIN_TX_LEN)) {
+ if (skb_pad(skb, IAVF_MIN_TX_LEN - skb->len))
return NETDEV_TX_OK;
- skb->len = I40E_MIN_TX_LEN;
- skb_set_tail_pointer(skb, I40E_MIN_TX_LEN);
+ skb->len = IAVF_MIN_TX_LEN;
+ skb_set_tail_pointer(skb, IAVF_MIN_TX_LEN);
}
- return i40e_xmit_frame_ring(skb, tx_ring);
+ return iavf_xmit_frame_ring(skb, tx_ring);
}
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.h b/drivers/net/ethernet/intel/iavf/iavf_txrx.h
index 3b5a63b3236e..71e7d090f8db 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.h
+++ b/drivers/net/ethernet/intel/iavf/iavf_txrx.h
@@ -1,11 +1,11 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright(c) 2013 - 2018 Intel Corporation. */
-#ifndef _I40E_TXRX_H_
-#define _I40E_TXRX_H_
+#ifndef _IAVF_TXRX_H_
+#define _IAVF_TXRX_H_
/* Interrupt Throttling and Rate Limiting Goodies */
-#define I40E_DEFAULT_IRQ_WORK 256
+#define IAVF_DEFAULT_IRQ_WORK 256
/* The datasheet for the X710 and XL710 indicate that the maximum value for
* the ITR is 8160usec which is then called out as 0xFF0 with a 2usec
@@ -13,80 +13,80 @@
* the register value which is divided by 2 lets use the actual values and
* avoid an excessive amount of translation.
*/
-#define I40E_ITR_DYNAMIC 0x8000 /* use top bit as a flag */
-#define I40E_ITR_MASK 0x1FFE /* mask for ITR register value */
-#define I40E_MIN_ITR 2 /* reg uses 2 usec resolution */
-#define I40E_ITR_100K 10 /* all values below must be even */
-#define I40E_ITR_50K 20
-#define I40E_ITR_20K 50
-#define I40E_ITR_18K 60
-#define I40E_ITR_8K 122
-#define I40E_MAX_ITR 8160 /* maximum value as per datasheet */
-#define ITR_TO_REG(setting) ((setting) & ~I40E_ITR_DYNAMIC)
-#define ITR_REG_ALIGN(setting) __ALIGN_MASK(setting, ~I40E_ITR_MASK)
-#define ITR_IS_DYNAMIC(setting) (!!((setting) & I40E_ITR_DYNAMIC))
-
-#define I40E_ITR_RX_DEF (I40E_ITR_20K | I40E_ITR_DYNAMIC)
-#define I40E_ITR_TX_DEF (I40E_ITR_20K | I40E_ITR_DYNAMIC)
+#define IAVF_ITR_DYNAMIC 0x8000 /* use top bit as a flag */
+#define IAVF_ITR_MASK 0x1FFE /* mask for ITR register value */
+#define IAVF_MIN_ITR 2 /* reg uses 2 usec resolution */
+#define IAVF_ITR_100K 10 /* all values below must be even */
+#define IAVF_ITR_50K 20
+#define IAVF_ITR_20K 50
+#define IAVF_ITR_18K 60
+#define IAVF_ITR_8K 122
+#define IAVF_MAX_ITR 8160 /* maximum value as per datasheet */
+#define ITR_TO_REG(setting) ((setting) & ~IAVF_ITR_DYNAMIC)
+#define ITR_REG_ALIGN(setting) __ALIGN_MASK(setting, ~IAVF_ITR_MASK)
+#define ITR_IS_DYNAMIC(setting) (!!((setting) & IAVF_ITR_DYNAMIC))
+
+#define IAVF_ITR_RX_DEF (IAVF_ITR_20K | IAVF_ITR_DYNAMIC)
+#define IAVF_ITR_TX_DEF (IAVF_ITR_20K | IAVF_ITR_DYNAMIC)
/* 0x40 is the enable bit for interrupt rate limiting, and must be set if
* the value of the rate limit is non-zero
*/
#define INTRL_ENA BIT(6)
-#define I40E_MAX_INTRL 0x3B /* reg uses 4 usec resolution */
+#define IAVF_MAX_INTRL 0x3B /* reg uses 4 usec resolution */
#define INTRL_REG_TO_USEC(intrl) ((intrl & ~INTRL_ENA) << 2)
#define INTRL_USEC_TO_REG(set) ((set) ? ((set) >> 2) | INTRL_ENA : 0)
-#define I40E_INTRL_8K 125 /* 8000 ints/sec */
-#define I40E_INTRL_62K 16 /* 62500 ints/sec */
-#define I40E_INTRL_83K 12 /* 83333 ints/sec */
+#define IAVF_INTRL_8K 125 /* 8000 ints/sec */
+#define IAVF_INTRL_62K 16 /* 62500 ints/sec */
+#define IAVF_INTRL_83K 12 /* 83333 ints/sec */
-#define I40E_QUEUE_END_OF_LIST 0x7FF
+#define IAVF_QUEUE_END_OF_LIST 0x7FF
/* this enum matches hardware bits and is meant to be used by DYN_CTLN
* registers and QINT registers or more generally anywhere in the manual
* mentioning ITR_INDX, ITR_NONE cannot be used as an index 'n' into any
* register but instead is a special value meaning "don't update" ITR0/1/2.
*/
-enum i40e_dyn_idx_t {
- I40E_IDX_ITR0 = 0,
- I40E_IDX_ITR1 = 1,
- I40E_IDX_ITR2 = 2,
- I40E_ITR_NONE = 3 /* ITR_NONE must not be used as an index */
+enum iavf_dyn_idx_t {
+ IAVF_IDX_ITR0 = 0,
+ IAVF_IDX_ITR1 = 1,
+ IAVF_IDX_ITR2 = 2,
+ IAVF_ITR_NONE = 3 /* ITR_NONE must not be used as an index */
};
/* these are indexes into ITRN registers */
-#define I40E_RX_ITR I40E_IDX_ITR0
-#define I40E_TX_ITR I40E_IDX_ITR1
-#define I40E_PE_ITR I40E_IDX_ITR2
+#define IAVF_RX_ITR IAVF_IDX_ITR0
+#define IAVF_TX_ITR IAVF_IDX_ITR1
+#define IAVF_PE_ITR IAVF_IDX_ITR2
/* Supported RSS offloads */
-#define I40E_DEFAULT_RSS_HENA ( \
- BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | \
- BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_SCTP) | \
- BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP) | \
- BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | \
- BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV4) | \
- BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | \
- BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP) | \
- BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) | \
- BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | \
- BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV6) | \
- BIT_ULL(I40E_FILTER_PCTYPE_L2_PAYLOAD))
-
-#define I40E_DEFAULT_RSS_HENA_EXPANDED (I40E_DEFAULT_RSS_HENA | \
- BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK) | \
- BIT_ULL(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP) | \
- BIT_ULL(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP) | \
- BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK) | \
- BIT_ULL(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP) | \
- BIT_ULL(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP))
+#define IAVF_DEFAULT_RSS_HENA ( \
+ BIT_ULL(IAVF_FILTER_PCTYPE_NONF_IPV4_UDP) | \
+ BIT_ULL(IAVF_FILTER_PCTYPE_NONF_IPV4_SCTP) | \
+ BIT_ULL(IAVF_FILTER_PCTYPE_NONF_IPV4_TCP) | \
+ BIT_ULL(IAVF_FILTER_PCTYPE_NONF_IPV4_OTHER) | \
+ BIT_ULL(IAVF_FILTER_PCTYPE_FRAG_IPV4) | \
+ BIT_ULL(IAVF_FILTER_PCTYPE_NONF_IPV6_UDP) | \
+ BIT_ULL(IAVF_FILTER_PCTYPE_NONF_IPV6_TCP) | \
+ BIT_ULL(IAVF_FILTER_PCTYPE_NONF_IPV6_SCTP) | \
+ BIT_ULL(IAVF_FILTER_PCTYPE_NONF_IPV6_OTHER) | \
+ BIT_ULL(IAVF_FILTER_PCTYPE_FRAG_IPV6) | \
+ BIT_ULL(IAVF_FILTER_PCTYPE_L2_PAYLOAD))
+
+#define IAVF_DEFAULT_RSS_HENA_EXPANDED (IAVF_DEFAULT_RSS_HENA | \
+ BIT_ULL(IAVF_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK) | \
+ BIT_ULL(IAVF_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP) | \
+ BIT_ULL(IAVF_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP) | \
+ BIT_ULL(IAVF_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK) | \
+ BIT_ULL(IAVF_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP) | \
+ BIT_ULL(IAVF_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP))
/* Supported Rx Buffer Sizes (a multiple of 128) */
-#define I40E_RXBUFFER_256 256
-#define I40E_RXBUFFER_1536 1536 /* 128B aligned standard Ethernet frame */
-#define I40E_RXBUFFER_2048 2048
-#define I40E_RXBUFFER_3072 3072 /* Used for large frames w/ padding */
-#define I40E_MAX_RXBUFFER 9728 /* largest size for single descriptor */
+#define IAVF_RXBUFFER_256 256
+#define IAVF_RXBUFFER_1536 1536 /* 128B aligned standard Ethernet frame */
+#define IAVF_RXBUFFER_2048 2048
+#define IAVF_RXBUFFER_3072 3072 /* Used for large frames w/ padding */
+#define IAVF_MAX_RXBUFFER 9728 /* largest size for single descriptor */
/* NOTE: netdev_alloc_skb reserves up to 64 bytes, NET_IP_ALIGN means we
* reserve 2 more, and skb_shared_info adds an additional 384 bytes more,
@@ -95,11 +95,11 @@ enum i40e_dyn_idx_t {
* i.e. RXBUFFER_256 --> 960 byte skb (size-1024 slab)
* i.e. RXBUFFER_512 --> 1216 byte skb (size-2048 slab)
*/
-#define I40E_RX_HDR_SIZE I40E_RXBUFFER_256
-#define I40E_PACKET_HDR_PAD (ETH_HLEN + ETH_FCS_LEN + (VLAN_HLEN * 2))
-#define i40e_rx_desc i40e_32byte_rx_desc
+#define IAVF_RX_HDR_SIZE IAVF_RXBUFFER_256
+#define IAVF_PACKET_HDR_PAD (ETH_HLEN + ETH_FCS_LEN + (VLAN_HLEN * 2))
+#define iavf_rx_desc iavf_32byte_rx_desc
-#define I40E_RX_DMA_ATTR \
+#define IAVF_RX_DMA_ATTR \
(DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_WEAK_ORDERING)
/* Attempt to maximize the headroom available for incoming frames. We
@@ -113,10 +113,10 @@ enum i40e_dyn_idx_t {
* receive path.
*/
#if (PAGE_SIZE < 8192)
-#define I40E_2K_TOO_SMALL_WITH_PADDING \
-((NET_SKB_PAD + I40E_RXBUFFER_1536) > SKB_WITH_OVERHEAD(I40E_RXBUFFER_2048))
+#define IAVF_2K_TOO_SMALL_WITH_PADDING \
+((NET_SKB_PAD + IAVF_RXBUFFER_1536) > SKB_WITH_OVERHEAD(IAVF_RXBUFFER_2048))
-static inline int i40e_compute_pad(int rx_buf_len)
+static inline int iavf_compute_pad(int rx_buf_len)
{
int page_size, pad_size;
@@ -126,7 +126,7 @@ static inline int i40e_compute_pad(int rx_buf_len)
return pad_size;
}
-static inline int i40e_skb_pad(void)
+static inline int iavf_skb_pad(void)
{
int rx_buf_len;
@@ -137,25 +137,25 @@ static inline int i40e_skb_pad(void)
* tailroom due to NET_IP_ALIGN possibly shifting us out of
* cache-line alignment.
*/
- if (I40E_2K_TOO_SMALL_WITH_PADDING)
- rx_buf_len = I40E_RXBUFFER_3072 + SKB_DATA_ALIGN(NET_IP_ALIGN);
+ if (IAVF_2K_TOO_SMALL_WITH_PADDING)
+ rx_buf_len = IAVF_RXBUFFER_3072 + SKB_DATA_ALIGN(NET_IP_ALIGN);
else
- rx_buf_len = I40E_RXBUFFER_1536;
+ rx_buf_len = IAVF_RXBUFFER_1536;
/* if needed make room for NET_IP_ALIGN */
rx_buf_len -= NET_IP_ALIGN;
- return i40e_compute_pad(rx_buf_len);
+ return iavf_compute_pad(rx_buf_len);
}
-#define I40E_SKB_PAD i40e_skb_pad()
+#define IAVF_SKB_PAD iavf_skb_pad()
#else
-#define I40E_2K_TOO_SMALL_WITH_PADDING false
-#define I40E_SKB_PAD (NET_SKB_PAD + NET_IP_ALIGN)
+#define IAVF_2K_TOO_SMALL_WITH_PADDING false
+#define IAVF_SKB_PAD (NET_SKB_PAD + NET_IP_ALIGN)
#endif
/**
- * i40e_test_staterr - tests bits in Rx descriptor status and error fields
+ * iavf_test_staterr - tests bits in Rx descriptor status and error fields
* @rx_desc: pointer to receive descriptor (in le64 format)
* @stat_err_bits: value to mask
*
@@ -164,7 +164,7 @@ static inline int i40e_skb_pad(void)
* The status_error_len doesn't need to be shifted because it begins
* at offset zero.
*/
-static inline bool i40e_test_staterr(union i40e_rx_desc *rx_desc,
+static inline bool iavf_test_staterr(union iavf_rx_desc *rx_desc,
const u64 stat_err_bits)
{
return !!(rx_desc->wb.qword1.status_error_len &
@@ -172,8 +172,7 @@ static inline bool i40e_test_staterr(union i40e_rx_desc *rx_desc,
}
/* How many Rx Buffers do we bundle into one write to the hardware ? */
-#define I40E_RX_BUFFER_WRITE 32 /* Must be power of 2 */
-#define I40E_RX_INCREMENT(r, i) \
+#define IAVF_RX_INCREMENT(r, i) \
do { \
(i)++; \
if ((i) == (r)->count) \
@@ -181,34 +180,34 @@ static inline bool i40e_test_staterr(union i40e_rx_desc *rx_desc,
r->next_to_clean = i; \
} while (0)
-#define I40E_RX_NEXT_DESC(r, i, n) \
+#define IAVF_RX_NEXT_DESC(r, i, n) \
do { \
(i)++; \
if ((i) == (r)->count) \
i = 0; \
- (n) = I40E_RX_DESC((r), (i)); \
+ (n) = IAVF_RX_DESC((r), (i)); \
} while (0)
-#define I40E_RX_NEXT_DESC_PREFETCH(r, i, n) \
+#define IAVF_RX_NEXT_DESC_PREFETCH(r, i, n) \
do { \
- I40E_RX_NEXT_DESC((r), (i), (n)); \
+ IAVF_RX_NEXT_DESC((r), (i), (n)); \
prefetch((n)); \
} while (0)
-#define I40E_MAX_BUFFER_TXD 8
-#define I40E_MIN_TX_LEN 17
+#define IAVF_MAX_BUFFER_TXD 8
+#define IAVF_MIN_TX_LEN 17
/* The size limit for a transmit buffer in a descriptor is (16K - 1).
* In order to align with the read requests we will align the value to
* the nearest 4K which represents our maximum read request size.
*/
-#define I40E_MAX_READ_REQ_SIZE 4096
-#define I40E_MAX_DATA_PER_TXD (16 * 1024 - 1)
-#define I40E_MAX_DATA_PER_TXD_ALIGNED \
- (I40E_MAX_DATA_PER_TXD & ~(I40E_MAX_READ_REQ_SIZE - 1))
+#define IAVF_MAX_READ_REQ_SIZE 4096
+#define IAVF_MAX_DATA_PER_TXD (16 * 1024 - 1)
+#define IAVF_MAX_DATA_PER_TXD_ALIGNED \
+ (IAVF_MAX_DATA_PER_TXD & ~(IAVF_MAX_READ_REQ_SIZE - 1))
/**
- * i40e_txd_use_count - estimate the number of descriptors needed for Tx
+ * iavf_txd_use_count - estimate the number of descriptors needed for Tx
* @size: transmit request size in bytes
*
* Due to hardware alignment restrictions (4K alignment), we need to
@@ -235,31 +234,31 @@ static inline bool i40e_test_staterr(union i40e_rx_desc *rx_desc,
* operations into:
* return ((size * 85) >> 20) + 1;
*/
-static inline unsigned int i40e_txd_use_count(unsigned int size)
+static inline unsigned int iavf_txd_use_count(unsigned int size)
{
return ((size * 85) >> 20) + 1;
}
/* Tx Descriptors needed, worst case */
#define DESC_NEEDED (MAX_SKB_FRAGS + 6)
-#define I40E_MIN_DESC_PENDING 4
-
-#define I40E_TX_FLAGS_HW_VLAN BIT(1)
-#define I40E_TX_FLAGS_SW_VLAN BIT(2)
-#define I40E_TX_FLAGS_TSO BIT(3)
-#define I40E_TX_FLAGS_IPV4 BIT(4)
-#define I40E_TX_FLAGS_IPV6 BIT(5)
-#define I40E_TX_FLAGS_FCCRC BIT(6)
-#define I40E_TX_FLAGS_FSO BIT(7)
-#define I40E_TX_FLAGS_FD_SB BIT(9)
-#define I40E_TX_FLAGS_VXLAN_TUNNEL BIT(10)
-#define I40E_TX_FLAGS_VLAN_MASK 0xffff0000
-#define I40E_TX_FLAGS_VLAN_PRIO_MASK 0xe0000000
-#define I40E_TX_FLAGS_VLAN_PRIO_SHIFT 29
-#define I40E_TX_FLAGS_VLAN_SHIFT 16
-
-struct i40e_tx_buffer {
- struct i40e_tx_desc *next_to_watch;
+#define IAVF_MIN_DESC_PENDING 4
+
+#define IAVF_TX_FLAGS_HW_VLAN BIT(1)
+#define IAVF_TX_FLAGS_SW_VLAN BIT(2)
+#define IAVF_TX_FLAGS_TSO BIT(3)
+#define IAVF_TX_FLAGS_IPV4 BIT(4)
+#define IAVF_TX_FLAGS_IPV6 BIT(5)
+#define IAVF_TX_FLAGS_FCCRC BIT(6)
+#define IAVF_TX_FLAGS_FSO BIT(7)
+#define IAVF_TX_FLAGS_FD_SB BIT(9)
+#define IAVF_TX_FLAGS_VXLAN_TUNNEL BIT(10)
+#define IAVF_TX_FLAGS_VLAN_MASK 0xffff0000
+#define IAVF_TX_FLAGS_VLAN_PRIO_MASK 0xe0000000
+#define IAVF_TX_FLAGS_VLAN_PRIO_SHIFT 29
+#define IAVF_TX_FLAGS_VLAN_SHIFT 16
+
+struct iavf_tx_buffer {
+ struct iavf_tx_desc *next_to_watch;
union {
struct sk_buff *skb;
void *raw_buf;
@@ -272,7 +271,7 @@ struct i40e_tx_buffer {
u32 tx_flags;
};
-struct i40e_rx_buffer {
+struct iavf_rx_buffer {
dma_addr_t dma;
struct page *page;
#if (BITS_PER_LONG > 32) || (PAGE_SIZE >= 65536)
@@ -283,12 +282,12 @@ struct i40e_rx_buffer {
__u16 pagecnt_bias;
};
-struct i40e_queue_stats {
+struct iavf_queue_stats {
u64 packets;
u64 bytes;
};
-struct i40e_tx_queue_stats {
+struct iavf_tx_queue_stats {
u64 restart_queue;
u64 tx_busy;
u64 tx_done_old;
@@ -298,7 +297,7 @@ struct i40e_tx_queue_stats {
u64 tx_lost_interrupt;
};
-struct i40e_rx_queue_stats {
+struct iavf_rx_queue_stats {
u64 non_eop_descs;
u64 alloc_page_failed;
u64 alloc_buff_failed;
@@ -306,34 +305,34 @@ struct i40e_rx_queue_stats {
u64 realloc_count;
};
-enum i40e_ring_state_t {
- __I40E_TX_FDIR_INIT_DONE,
- __I40E_TX_XPS_INIT_DONE,
- __I40E_RING_STATE_NBITS /* must be last */
+enum iavf_ring_state_t {
+ __IAVF_TX_FDIR_INIT_DONE,
+ __IAVF_TX_XPS_INIT_DONE,
+ __IAVF_RING_STATE_NBITS /* must be last */
};
/* some useful defines for virtchannel interface, which
* is the only remaining user of header split
*/
-#define I40E_RX_DTYPE_NO_SPLIT 0
-#define I40E_RX_DTYPE_HEADER_SPLIT 1
-#define I40E_RX_DTYPE_SPLIT_ALWAYS 2
-#define I40E_RX_SPLIT_L2 0x1
-#define I40E_RX_SPLIT_IP 0x2
-#define I40E_RX_SPLIT_TCP_UDP 0x4
-#define I40E_RX_SPLIT_SCTP 0x8
+#define IAVF_RX_DTYPE_NO_SPLIT 0
+#define IAVF_RX_DTYPE_HEADER_SPLIT 1
+#define IAVF_RX_DTYPE_SPLIT_ALWAYS 2
+#define IAVF_RX_SPLIT_L2 0x1
+#define IAVF_RX_SPLIT_IP 0x2
+#define IAVF_RX_SPLIT_TCP_UDP 0x4
+#define IAVF_RX_SPLIT_SCTP 0x8
/* struct that defines a descriptor ring, associated with a VSI */
-struct i40e_ring {
- struct i40e_ring *next; /* pointer to next ring in q_vector */
+struct iavf_ring {
+ struct iavf_ring *next; /* pointer to next ring in q_vector */
void *desc; /* Descriptor ring memory */
struct device *dev; /* Used for DMA mapping */
struct net_device *netdev; /* netdev ring maps to */
union {
- struct i40e_tx_buffer *tx_bi;
- struct i40e_rx_buffer *rx_bi;
+ struct iavf_tx_buffer *tx_bi;
+ struct iavf_rx_buffer *rx_bi;
};
- DECLARE_BITMAP(state, __I40E_RING_STATE_NBITS);
+ DECLARE_BITMAP(state, __IAVF_RING_STATE_NBITS);
u16 queue_index; /* Queue number of ring */
u8 dcb_tc; /* Traffic class of ring */
u8 __iomem *tail;
@@ -361,59 +360,59 @@ struct i40e_ring {
u8 packet_stride;
u16 flags;
-#define I40E_TXR_FLAGS_WB_ON_ITR BIT(0)
-#define I40E_RXR_FLAGS_BUILD_SKB_ENABLED BIT(1)
+#define IAVF_TXR_FLAGS_WB_ON_ITR BIT(0)
+#define IAVF_RXR_FLAGS_BUILD_SKB_ENABLED BIT(1)
/* stats structs */
- struct i40e_queue_stats stats;
+ struct iavf_queue_stats stats;
struct u64_stats_sync syncp;
union {
- struct i40e_tx_queue_stats tx_stats;
- struct i40e_rx_queue_stats rx_stats;
+ struct iavf_tx_queue_stats tx_stats;
+ struct iavf_rx_queue_stats rx_stats;
};
unsigned int size; /* length of descriptor ring in bytes */
dma_addr_t dma; /* physical address of ring */
- struct i40e_vsi *vsi; /* Backreference to associated VSI */
- struct i40e_q_vector *q_vector; /* Backreference to associated vector */
+ struct iavf_vsi *vsi; /* Backreference to associated VSI */
+ struct iavf_q_vector *q_vector; /* Backreference to associated vector */
struct rcu_head rcu; /* to avoid race on free */
u16 next_to_alloc;
- struct sk_buff *skb; /* When i40evf_clean_rx_ring_irq() must
+ struct sk_buff *skb; /* When iavf_clean_rx_ring_irq() must
* return before it sees the EOP for
* the current packet, we save that skb
* here and resume receiving this
* packet the next time
- * i40evf_clean_rx_ring_irq() is called
+ * iavf_clean_rx_ring_irq() is called
* for this ring.
*/
} ____cacheline_internodealigned_in_smp;
-static inline bool ring_uses_build_skb(struct i40e_ring *ring)
+static inline bool ring_uses_build_skb(struct iavf_ring *ring)
{
- return !!(ring->flags & I40E_RXR_FLAGS_BUILD_SKB_ENABLED);
+ return !!(ring->flags & IAVF_RXR_FLAGS_BUILD_SKB_ENABLED);
}
-static inline void set_ring_build_skb_enabled(struct i40e_ring *ring)
+static inline void set_ring_build_skb_enabled(struct iavf_ring *ring)
{
- ring->flags |= I40E_RXR_FLAGS_BUILD_SKB_ENABLED;
+ ring->flags |= IAVF_RXR_FLAGS_BUILD_SKB_ENABLED;
}
-static inline void clear_ring_build_skb_enabled(struct i40e_ring *ring)
+static inline void clear_ring_build_skb_enabled(struct iavf_ring *ring)
{
- ring->flags &= ~I40E_RXR_FLAGS_BUILD_SKB_ENABLED;
+ ring->flags &= ~IAVF_RXR_FLAGS_BUILD_SKB_ENABLED;
}
-#define I40E_ITR_ADAPTIVE_MIN_INC 0x0002
-#define I40E_ITR_ADAPTIVE_MIN_USECS 0x0002
-#define I40E_ITR_ADAPTIVE_MAX_USECS 0x007e
-#define I40E_ITR_ADAPTIVE_LATENCY 0x8000
-#define I40E_ITR_ADAPTIVE_BULK 0x0000
-#define ITR_IS_BULK(x) (!((x) & I40E_ITR_ADAPTIVE_LATENCY))
+#define IAVF_ITR_ADAPTIVE_MIN_INC 0x0002
+#define IAVF_ITR_ADAPTIVE_MIN_USECS 0x0002
+#define IAVF_ITR_ADAPTIVE_MAX_USECS 0x007e
+#define IAVF_ITR_ADAPTIVE_LATENCY 0x8000
+#define IAVF_ITR_ADAPTIVE_BULK 0x0000
+#define ITR_IS_BULK(x) (!((x) & IAVF_ITR_ADAPTIVE_LATENCY))
-struct i40e_ring_container {
- struct i40e_ring *ring; /* pointer to linked list of ring(s) */
+struct iavf_ring_container {
+ struct iavf_ring *ring; /* pointer to linked list of ring(s) */
unsigned long next_update; /* jiffies value of next update */
unsigned int total_bytes; /* total bytes processed this int */
unsigned int total_packets; /* total packets processed this int */
@@ -423,10 +422,10 @@ struct i40e_ring_container {
};
/* iterator for handling rings in ring container */
-#define i40e_for_each_ring(pos, head) \
+#define iavf_for_each_ring(pos, head) \
for (pos = (head).ring; pos != NULL; pos = pos->next)
-static inline unsigned int i40e_rx_pg_order(struct i40e_ring *ring)
+static inline unsigned int iavf_rx_pg_order(struct iavf_ring *ring)
{
#if (PAGE_SIZE < 8192)
if (ring->rx_buf_len > (PAGE_SIZE / 2))
@@ -435,25 +434,25 @@ static inline unsigned int i40e_rx_pg_order(struct i40e_ring *ring)
return 0;
}
-#define i40e_rx_pg_size(_ring) (PAGE_SIZE << i40e_rx_pg_order(_ring))
-
-bool i40evf_alloc_rx_buffers(struct i40e_ring *rxr, u16 cleaned_count);
-netdev_tx_t i40evf_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
-void i40evf_clean_tx_ring(struct i40e_ring *tx_ring);
-void i40evf_clean_rx_ring(struct i40e_ring *rx_ring);
-int i40evf_setup_tx_descriptors(struct i40e_ring *tx_ring);
-int i40evf_setup_rx_descriptors(struct i40e_ring *rx_ring);
-void i40evf_free_tx_resources(struct i40e_ring *tx_ring);
-void i40evf_free_rx_resources(struct i40e_ring *rx_ring);
-int i40evf_napi_poll(struct napi_struct *napi, int budget);
-void i40evf_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector);
-u32 i40evf_get_tx_pending(struct i40e_ring *ring, bool in_sw);
-void i40evf_detect_recover_hung(struct i40e_vsi *vsi);
-int __i40evf_maybe_stop_tx(struct i40e_ring *tx_ring, int size);
-bool __i40evf_chk_linearize(struct sk_buff *skb);
+#define iavf_rx_pg_size(_ring) (PAGE_SIZE << iavf_rx_pg_order(_ring))
+
+bool iavf_alloc_rx_buffers(struct iavf_ring *rxr, u16 cleaned_count);
+netdev_tx_t iavf_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
+void iavf_clean_tx_ring(struct iavf_ring *tx_ring);
+void iavf_clean_rx_ring(struct iavf_ring *rx_ring);
+int iavf_setup_tx_descriptors(struct iavf_ring *tx_ring);
+int iavf_setup_rx_descriptors(struct iavf_ring *rx_ring);
+void iavf_free_tx_resources(struct iavf_ring *tx_ring);
+void iavf_free_rx_resources(struct iavf_ring *rx_ring);
+int iavf_napi_poll(struct napi_struct *napi, int budget);
+void iavf_force_wb(struct iavf_vsi *vsi, struct iavf_q_vector *q_vector);
+u32 iavf_get_tx_pending(struct iavf_ring *ring, bool in_sw);
+void iavf_detect_recover_hung(struct iavf_vsi *vsi);
+int __iavf_maybe_stop_tx(struct iavf_ring *tx_ring, int size);
+bool __iavf_chk_linearize(struct sk_buff *skb);
/**
- * i40e_xmit_descriptor_count - calculate number of Tx descriptors needed
+ * iavf_xmit_descriptor_count - calculate number of Tx descriptors needed
* @skb: send buffer
* @tx_ring: ring to send buffer on
*
@@ -461,14 +460,14 @@ bool __i40evf_chk_linearize(struct sk_buff *skb);
* there is not enough descriptors available in this ring since we need at least
* one descriptor.
**/
-static inline int i40e_xmit_descriptor_count(struct sk_buff *skb)
+static inline int iavf_xmit_descriptor_count(struct sk_buff *skb)
{
const struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[0];
unsigned int nr_frags = skb_shinfo(skb)->nr_frags;
int count = 0, size = skb_headlen(skb);
for (;;) {
- count += i40e_txd_use_count(size);
+ count += iavf_txd_use_count(size);
if (!nr_frags--)
break;
@@ -480,21 +479,21 @@ static inline int i40e_xmit_descriptor_count(struct sk_buff *skb)
}
/**
- * i40e_maybe_stop_tx - 1st level check for Tx stop conditions
+ * iavf_maybe_stop_tx - 1st level check for Tx stop conditions
* @tx_ring: the ring to be checked
* @size: the size buffer we want to assure is available
*
* Returns 0 if stop is not needed
**/
-static inline int i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
+static inline int iavf_maybe_stop_tx(struct iavf_ring *tx_ring, int size)
{
- if (likely(I40E_DESC_UNUSED(tx_ring) >= size))
+ if (likely(IAVF_DESC_UNUSED(tx_ring) >= size))
return 0;
- return __i40evf_maybe_stop_tx(tx_ring, size);
+ return __iavf_maybe_stop_tx(tx_ring, size);
}
/**
- * i40e_chk_linearize - Check if there are more than 8 fragments per packet
+ * iavf_chk_linearize - Check if there are more than 8 fragments per packet
* @skb: send buffer
* @count: number of buffers used
*
@@ -502,23 +501,23 @@ static inline int i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
* a packet on the wire and so we need to figure out the cases where we
* need to linearize the skb.
**/
-static inline bool i40e_chk_linearize(struct sk_buff *skb, int count)
+static inline bool iavf_chk_linearize(struct sk_buff *skb, int count)
{
/* Both TSO and single send will work if count is less than 8 */
- if (likely(count < I40E_MAX_BUFFER_TXD))
+ if (likely(count < IAVF_MAX_BUFFER_TXD))
return false;
if (skb_is_gso(skb))
- return __i40evf_chk_linearize(skb);
+ return __iavf_chk_linearize(skb);
/* we can support up to 8 data buffers for a single send */
- return count != I40E_MAX_BUFFER_TXD;
+ return count != IAVF_MAX_BUFFER_TXD;
}
/**
* @ring: Tx ring to find the netdev equivalent of
**/
-static inline struct netdev_queue *txring_txq(const struct i40e_ring *ring)
+static inline struct netdev_queue *txring_txq(const struct iavf_ring *ring)
{
return netdev_get_tx_queue(ring->netdev, ring->queue_index);
}
-#endif /* _I40E_TXRX_H_ */
+#endif /* _IAVF_TXRX_H_ */
diff --git a/drivers/net/ethernet/intel/iavf/iavf_type.h b/drivers/net/ethernet/intel/iavf/iavf_type.h
new file mode 100644
index 000000000000..ca89583613fb
--- /dev/null
+++ b/drivers/net/ethernet/intel/iavf/iavf_type.h
@@ -0,0 +1,688 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
+
+#ifndef _IAVF_TYPE_H_
+#define _IAVF_TYPE_H_
+
+#include "iavf_status.h"
+#include "iavf_osdep.h"
+#include "iavf_register.h"
+#include "i40e_adminq.h"
+#include "iavf_devids.h"
+
+#define IAVF_RXQ_CTX_DBUFF_SHIFT 7
+
+/* IAVF_MASK is a macro used on 32 bit registers */
+#define IAVF_MASK(mask, shift) ((u32)(mask) << (shift))
+
+#define IAVF_MAX_VSI_QP 16
+#define IAVF_MAX_VF_VSI 3
+#define IAVF_MAX_CHAINED_RX_BUFFERS 5
+
+/* forward declaration */
+struct iavf_hw;
+typedef void (*I40E_ADMINQ_CALLBACK)(struct iavf_hw *, struct i40e_aq_desc *);
+
+/* Data type manipulation macros. */
+
+#define IAVF_DESC_UNUSED(R) \
+ ((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \
+ (R)->next_to_clean - (R)->next_to_use - 1)
+
+/* bitfields for Tx queue mapping in QTX_CTL */
+#define IAVF_QTX_CTL_VF_QUEUE 0x0
+#define IAVF_QTX_CTL_VM_QUEUE 0x1
+#define IAVF_QTX_CTL_PF_QUEUE 0x2
+
+/* debug masks - set these bits in hw->debug_mask to control output */
+enum iavf_debug_mask {
+ IAVF_DEBUG_INIT = 0x00000001,
+ IAVF_DEBUG_RELEASE = 0x00000002,
+
+ IAVF_DEBUG_LINK = 0x00000010,
+ IAVF_DEBUG_PHY = 0x00000020,
+ IAVF_DEBUG_HMC = 0x00000040,
+ IAVF_DEBUG_NVM = 0x00000080,
+ IAVF_DEBUG_LAN = 0x00000100,
+ IAVF_DEBUG_FLOW = 0x00000200,
+ IAVF_DEBUG_DCB = 0x00000400,
+ IAVF_DEBUG_DIAG = 0x00000800,
+ IAVF_DEBUG_FD = 0x00001000,
+ IAVF_DEBUG_PACKAGE = 0x00002000,
+
+ IAVF_DEBUG_AQ_MESSAGE = 0x01000000,
+ IAVF_DEBUG_AQ_DESCRIPTOR = 0x02000000,
+ IAVF_DEBUG_AQ_DESC_BUFFER = 0x04000000,
+ IAVF_DEBUG_AQ_COMMAND = 0x06000000,
+ IAVF_DEBUG_AQ = 0x0F000000,
+
+ IAVF_DEBUG_USER = 0xF0000000,
+
+ IAVF_DEBUG_ALL = 0xFFFFFFFF
+};
+
+/* These are structs for managing the hardware information and the operations.
+ * The structures of function pointers are filled out at init time when we
+ * know for sure exactly which hardware we're working with. This gives us the
+ * flexibility of using the same main driver code but adapting to slightly
+ * different hardware needs as new parts are developed. For this architecture,
+ * the Firmware and AdminQ are intended to insulate the driver from most of the
+ * future changes, but these structures will also do part of the job.
+ */
+enum iavf_mac_type {
+ IAVF_MAC_UNKNOWN = 0,
+ IAVF_MAC_XL710,
+ IAVF_MAC_VF,
+ IAVF_MAC_X722,
+ IAVF_MAC_X722_VF,
+ IAVF_MAC_GENERIC,
+};
+
+enum iavf_vsi_type {
+ IAVF_VSI_MAIN = 0,
+ IAVF_VSI_VMDQ1 = 1,
+ IAVF_VSI_VMDQ2 = 2,
+ IAVF_VSI_CTRL = 3,
+ IAVF_VSI_FCOE = 4,
+ IAVF_VSI_MIRROR = 5,
+ IAVF_VSI_SRIOV = 6,
+ IAVF_VSI_FDIR = 7,
+ IAVF_VSI_TYPE_UNKNOWN
+};
+
+enum iavf_queue_type {
+ IAVF_QUEUE_TYPE_RX = 0,
+ IAVF_QUEUE_TYPE_TX,
+ IAVF_QUEUE_TYPE_PE_CEQ,
+ IAVF_QUEUE_TYPE_UNKNOWN
+};
+
+#define IAVF_HW_CAP_MAX_GPIO 30
+/* Capabilities of a PF or a VF or the whole device */
+struct iavf_hw_capabilities {
+ bool dcb;
+ bool fcoe;
+ u32 num_vsis;
+ u32 num_rx_qp;
+ u32 num_tx_qp;
+ u32 base_queue;
+ u32 num_msix_vectors_vf;
+};
+
+struct iavf_mac_info {
+ enum iavf_mac_type type;
+ u8 addr[ETH_ALEN];
+ u8 perm_addr[ETH_ALEN];
+ u8 san_addr[ETH_ALEN];
+ u16 max_fcoeq;
+};
+
+/* PCI bus types */
+enum iavf_bus_type {
+ iavf_bus_type_unknown = 0,
+ iavf_bus_type_pci,
+ iavf_bus_type_pcix,
+ iavf_bus_type_pci_express,
+ iavf_bus_type_reserved
+};
+
+/* PCI bus speeds */
+enum iavf_bus_speed {
+ iavf_bus_speed_unknown = 0,
+ iavf_bus_speed_33 = 33,
+ iavf_bus_speed_66 = 66,
+ iavf_bus_speed_100 = 100,
+ iavf_bus_speed_120 = 120,
+ iavf_bus_speed_133 = 133,
+ iavf_bus_speed_2500 = 2500,
+ iavf_bus_speed_5000 = 5000,
+ iavf_bus_speed_8000 = 8000,
+ iavf_bus_speed_reserved
+};
+
+/* PCI bus widths */
+enum iavf_bus_width {
+ iavf_bus_width_unknown = 0,
+ iavf_bus_width_pcie_x1 = 1,
+ iavf_bus_width_pcie_x2 = 2,
+ iavf_bus_width_pcie_x4 = 4,
+ iavf_bus_width_pcie_x8 = 8,
+ iavf_bus_width_32 = 32,
+ iavf_bus_width_64 = 64,
+ iavf_bus_width_reserved
+};
+
+/* Bus parameters */
+struct iavf_bus_info {
+ enum iavf_bus_speed speed;
+ enum iavf_bus_width width;
+ enum iavf_bus_type type;
+
+ u16 func;
+ u16 device;
+ u16 lan_id;
+ u16 bus_id;
+};
+
+#define IAVF_MAX_USER_PRIORITY 8
+/* Port hardware description */
+struct iavf_hw {
+ u8 __iomem *hw_addr;
+ void *back;
+
+ /* subsystem structs */
+ struct iavf_mac_info mac;
+ struct iavf_bus_info bus;
+
+ /* pci info */
+ u16 device_id;
+ u16 vendor_id;
+ u16 subsystem_device_id;
+ u16 subsystem_vendor_id;
+ u8 revision_id;
+
+ /* capabilities for entire device and PCI func */
+ struct iavf_hw_capabilities dev_caps;
+
+ /* Admin Queue info */
+ struct iavf_adminq_info aq;
+
+ /* debug mask */
+ u32 debug_mask;
+ char err_str[16];
+};
+
+struct iavf_driver_version {
+ u8 major_version;
+ u8 minor_version;
+ u8 build_version;
+ u8 subbuild_version;
+ u8 driver_string[32];
+};
+
+/* RX Descriptors */
+union iavf_16byte_rx_desc {
+ struct {
+ __le64 pkt_addr; /* Packet buffer address */
+ __le64 hdr_addr; /* Header buffer address */
+ } read;
+ struct {
+ struct {
+ struct {
+ union {
+ __le16 mirroring_status;
+ __le16 fcoe_ctx_id;
+ } mirr_fcoe;
+ __le16 l2tag1;
+ } lo_dword;
+ union {
+ __le32 rss; /* RSS Hash */
+ __le32 fd_id; /* Flow director filter id */
+ __le32 fcoe_param; /* FCoE DDP Context id */
+ } hi_dword;
+ } qword0;
+ struct {
+ /* ext status/error/pktype/length */
+ __le64 status_error_len;
+ } qword1;
+ } wb; /* writeback */
+};
+
+union iavf_32byte_rx_desc {
+ struct {
+ __le64 pkt_addr; /* Packet buffer address */
+ __le64 hdr_addr; /* Header buffer address */
+ /* bit 0 of hdr_buffer_addr is DD bit */
+ __le64 rsvd1;
+ __le64 rsvd2;
+ } read;
+ struct {
+ struct {
+ struct {
+ union {
+ __le16 mirroring_status;
+ __le16 fcoe_ctx_id;
+ } mirr_fcoe;
+ __le16 l2tag1;
+ } lo_dword;
+ union {
+ __le32 rss; /* RSS Hash */
+ __le32 fcoe_param; /* FCoE DDP Context id */
+ /* Flow director filter id in case of
+ * Programming status desc WB
+ */
+ __le32 fd_id;
+ } hi_dword;
+ } qword0;
+ struct {
+ /* status/error/pktype/length */
+ __le64 status_error_len;
+ } qword1;
+ struct {
+ __le16 ext_status; /* extended status */
+ __le16 rsvd;
+ __le16 l2tag2_1;
+ __le16 l2tag2_2;
+ } qword2;
+ struct {
+ union {
+ __le32 flex_bytes_lo;
+ __le32 pe_status;
+ } lo_dword;
+ union {
+ __le32 flex_bytes_hi;
+ __le32 fd_id;
+ } hi_dword;
+ } qword3;
+ } wb; /* writeback */
+};
+
+enum iavf_rx_desc_status_bits {
+ /* Note: These are predefined bit offsets */
+ IAVF_RX_DESC_STATUS_DD_SHIFT = 0,
+ IAVF_RX_DESC_STATUS_EOF_SHIFT = 1,
+ IAVF_RX_DESC_STATUS_L2TAG1P_SHIFT = 2,
+ IAVF_RX_DESC_STATUS_L3L4P_SHIFT = 3,
+ IAVF_RX_DESC_STATUS_CRCP_SHIFT = 4,
+ IAVF_RX_DESC_STATUS_TSYNINDX_SHIFT = 5, /* 2 BITS */
+ IAVF_RX_DESC_STATUS_TSYNVALID_SHIFT = 7,
+ /* Note: Bit 8 is reserved in X710 and XL710 */
+ IAVF_RX_DESC_STATUS_EXT_UDP_0_SHIFT = 8,
+ IAVF_RX_DESC_STATUS_UMBCAST_SHIFT = 9, /* 2 BITS */
+ IAVF_RX_DESC_STATUS_FLM_SHIFT = 11,
+ IAVF_RX_DESC_STATUS_FLTSTAT_SHIFT = 12, /* 2 BITS */
+ IAVF_RX_DESC_STATUS_LPBK_SHIFT = 14,
+ IAVF_RX_DESC_STATUS_IPV6EXADD_SHIFT = 15,
+ IAVF_RX_DESC_STATUS_RESERVED_SHIFT = 16, /* 2 BITS */
+ /* Note: For non-tunnel packets INT_UDP_0 is the right status for
+ * UDP header
+ */
+ IAVF_RX_DESC_STATUS_INT_UDP_0_SHIFT = 18,
+ IAVF_RX_DESC_STATUS_LAST /* this entry must be last!!! */
+};
+
+#define IAVF_RXD_QW1_STATUS_SHIFT 0
+#define IAVF_RXD_QW1_STATUS_MASK ((BIT(IAVF_RX_DESC_STATUS_LAST) - 1) \
+ << IAVF_RXD_QW1_STATUS_SHIFT)
+
+#define IAVF_RXD_QW1_STATUS_TSYNINDX_SHIFT IAVF_RX_DESC_STATUS_TSYNINDX_SHIFT
+#define IAVF_RXD_QW1_STATUS_TSYNINDX_MASK (0x3UL << \
+ IAVF_RXD_QW1_STATUS_TSYNINDX_SHIFT)
+
+#define IAVF_RXD_QW1_STATUS_TSYNVALID_SHIFT IAVF_RX_DESC_STATUS_TSYNVALID_SHIFT
+#define IAVF_RXD_QW1_STATUS_TSYNVALID_MASK \
+ BIT_ULL(IAVF_RXD_QW1_STATUS_TSYNVALID_SHIFT)
+
+enum iavf_rx_desc_fltstat_values {
+ IAVF_RX_DESC_FLTSTAT_NO_DATA = 0,
+ IAVF_RX_DESC_FLTSTAT_RSV_FD_ID = 1, /* 16byte desc? FD_ID : RSV */
+ IAVF_RX_DESC_FLTSTAT_RSV = 2,
+ IAVF_RX_DESC_FLTSTAT_RSS_HASH = 3,
+};
+
+#define IAVF_RXD_QW1_ERROR_SHIFT 19
+#define IAVF_RXD_QW1_ERROR_MASK (0xFFUL << IAVF_RXD_QW1_ERROR_SHIFT)
+
+enum iavf_rx_desc_error_bits {
+ /* Note: These are predefined bit offsets */
+ IAVF_RX_DESC_ERROR_RXE_SHIFT = 0,
+ IAVF_RX_DESC_ERROR_RECIPE_SHIFT = 1,
+ IAVF_RX_DESC_ERROR_HBO_SHIFT = 2,
+ IAVF_RX_DESC_ERROR_L3L4E_SHIFT = 3, /* 3 BITS */
+ IAVF_RX_DESC_ERROR_IPE_SHIFT = 3,
+ IAVF_RX_DESC_ERROR_L4E_SHIFT = 4,
+ IAVF_RX_DESC_ERROR_EIPE_SHIFT = 5,
+ IAVF_RX_DESC_ERROR_OVERSIZE_SHIFT = 6,
+ IAVF_RX_DESC_ERROR_PPRS_SHIFT = 7
+};
+
+enum iavf_rx_desc_error_l3l4e_fcoe_masks {
+ IAVF_RX_DESC_ERROR_L3L4E_NONE = 0,
+ IAVF_RX_DESC_ERROR_L3L4E_PROT = 1,
+ IAVF_RX_DESC_ERROR_L3L4E_FC = 2,
+ IAVF_RX_DESC_ERROR_L3L4E_DMAC_ERR = 3,
+ IAVF_RX_DESC_ERROR_L3L4E_DMAC_WARN = 4
+};
+
+#define IAVF_RXD_QW1_PTYPE_SHIFT 30
+#define IAVF_RXD_QW1_PTYPE_MASK (0xFFULL << IAVF_RXD_QW1_PTYPE_SHIFT)
+
+/* Packet type non-ip values */
+enum iavf_rx_l2_ptype {
+ IAVF_RX_PTYPE_L2_RESERVED = 0,
+ IAVF_RX_PTYPE_L2_MAC_PAY2 = 1,
+ IAVF_RX_PTYPE_L2_TIMESYNC_PAY2 = 2,
+ IAVF_RX_PTYPE_L2_FIP_PAY2 = 3,
+ IAVF_RX_PTYPE_L2_OUI_PAY2 = 4,
+ IAVF_RX_PTYPE_L2_MACCNTRL_PAY2 = 5,
+ IAVF_RX_PTYPE_L2_LLDP_PAY2 = 6,
+ IAVF_RX_PTYPE_L2_ECP_PAY2 = 7,
+ IAVF_RX_PTYPE_L2_EVB_PAY2 = 8,
+ IAVF_RX_PTYPE_L2_QCN_PAY2 = 9,
+ IAVF_RX_PTYPE_L2_EAPOL_PAY2 = 10,
+ IAVF_RX_PTYPE_L2_ARP = 11,
+ IAVF_RX_PTYPE_L2_FCOE_PAY3 = 12,
+ IAVF_RX_PTYPE_L2_FCOE_FCDATA_PAY3 = 13,
+ IAVF_RX_PTYPE_L2_FCOE_FCRDY_PAY3 = 14,
+ IAVF_RX_PTYPE_L2_FCOE_FCRSP_PAY3 = 15,
+ IAVF_RX_PTYPE_L2_FCOE_FCOTHER_PA = 16,
+ IAVF_RX_PTYPE_L2_FCOE_VFT_PAY3 = 17,
+ IAVF_RX_PTYPE_L2_FCOE_VFT_FCDATA = 18,
+ IAVF_RX_PTYPE_L2_FCOE_VFT_FCRDY = 19,
+ IAVF_RX_PTYPE_L2_FCOE_VFT_FCRSP = 20,
+ IAVF_RX_PTYPE_L2_FCOE_VFT_FCOTHER = 21,
+ IAVF_RX_PTYPE_GRENAT4_MAC_PAY3 = 58,
+ IAVF_RX_PTYPE_GRENAT4_MACVLAN_IPV6_ICMP_PAY4 = 87,
+ IAVF_RX_PTYPE_GRENAT6_MAC_PAY3 = 124,
+ IAVF_RX_PTYPE_GRENAT6_MACVLAN_IPV6_ICMP_PAY4 = 153
+};
+
+struct iavf_rx_ptype_decoded {
+ u32 ptype:8;
+ u32 known:1;
+ u32 outer_ip:1;
+ u32 outer_ip_ver:1;
+ u32 outer_frag:1;
+ u32 tunnel_type:3;
+ u32 tunnel_end_prot:2;
+ u32 tunnel_end_frag:1;
+ u32 inner_prot:4;
+ u32 payload_layer:3;
+};
+
+enum iavf_rx_ptype_outer_ip {
+ IAVF_RX_PTYPE_OUTER_L2 = 0,
+ IAVF_RX_PTYPE_OUTER_IP = 1
+};
+
+enum iavf_rx_ptype_outer_ip_ver {
+ IAVF_RX_PTYPE_OUTER_NONE = 0,
+ IAVF_RX_PTYPE_OUTER_IPV4 = 0,
+ IAVF_RX_PTYPE_OUTER_IPV6 = 1
+};
+
+enum iavf_rx_ptype_outer_fragmented {
+ IAVF_RX_PTYPE_NOT_FRAG = 0,
+ IAVF_RX_PTYPE_FRAG = 1
+};
+
+enum iavf_rx_ptype_tunnel_type {
+ IAVF_RX_PTYPE_TUNNEL_NONE = 0,
+ IAVF_RX_PTYPE_TUNNEL_IP_IP = 1,
+ IAVF_RX_PTYPE_TUNNEL_IP_GRENAT = 2,
+ IAVF_RX_PTYPE_TUNNEL_IP_GRENAT_MAC = 3,
+ IAVF_RX_PTYPE_TUNNEL_IP_GRENAT_MAC_VLAN = 4,
+};
+
+enum iavf_rx_ptype_tunnel_end_prot {
+ IAVF_RX_PTYPE_TUNNEL_END_NONE = 0,
+ IAVF_RX_PTYPE_TUNNEL_END_IPV4 = 1,
+ IAVF_RX_PTYPE_TUNNEL_END_IPV6 = 2,
+};
+
+enum iavf_rx_ptype_inner_prot {
+ IAVF_RX_PTYPE_INNER_PROT_NONE = 0,
+ IAVF_RX_PTYPE_INNER_PROT_UDP = 1,
+ IAVF_RX_PTYPE_INNER_PROT_TCP = 2,
+ IAVF_RX_PTYPE_INNER_PROT_SCTP = 3,
+ IAVF_RX_PTYPE_INNER_PROT_ICMP = 4,
+ IAVF_RX_PTYPE_INNER_PROT_TIMESYNC = 5
+};
+
+enum iavf_rx_ptype_payload_layer {
+ IAVF_RX_PTYPE_PAYLOAD_LAYER_NONE = 0,
+ IAVF_RX_PTYPE_PAYLOAD_LAYER_PAY2 = 1,
+ IAVF_RX_PTYPE_PAYLOAD_LAYER_PAY3 = 2,
+ IAVF_RX_PTYPE_PAYLOAD_LAYER_PAY4 = 3,
+};
+
+#define IAVF_RXD_QW1_LENGTH_PBUF_SHIFT 38
+#define IAVF_RXD_QW1_LENGTH_PBUF_MASK (0x3FFFULL << \
+ IAVF_RXD_QW1_LENGTH_PBUF_SHIFT)
+
+#define IAVF_RXD_QW1_LENGTH_HBUF_SHIFT 52
+#define IAVF_RXD_QW1_LENGTH_HBUF_MASK (0x7FFULL << \
+ IAVF_RXD_QW1_LENGTH_HBUF_SHIFT)
+
+#define IAVF_RXD_QW1_LENGTH_SPH_SHIFT 63
+#define IAVF_RXD_QW1_LENGTH_SPH_MASK BIT_ULL(IAVF_RXD_QW1_LENGTH_SPH_SHIFT)
+
+enum iavf_rx_desc_ext_status_bits {
+ /* Note: These are predefined bit offsets */
+ IAVF_RX_DESC_EXT_STATUS_L2TAG2P_SHIFT = 0,
+ IAVF_RX_DESC_EXT_STATUS_L2TAG3P_SHIFT = 1,
+ IAVF_RX_DESC_EXT_STATUS_FLEXBL_SHIFT = 2, /* 2 BITS */
+ IAVF_RX_DESC_EXT_STATUS_FLEXBH_SHIFT = 4, /* 2 BITS */
+ IAVF_RX_DESC_EXT_STATUS_FDLONGB_SHIFT = 9,
+ IAVF_RX_DESC_EXT_STATUS_FCOELONGB_SHIFT = 10,
+ IAVF_RX_DESC_EXT_STATUS_PELONGB_SHIFT = 11,
+};
+
+enum iavf_rx_desc_pe_status_bits {
+ /* Note: These are predefined bit offsets */
+ IAVF_RX_DESC_PE_STATUS_QPID_SHIFT = 0, /* 18 BITS */
+ IAVF_RX_DESC_PE_STATUS_L4PORT_SHIFT = 0, /* 16 BITS */
+ IAVF_RX_DESC_PE_STATUS_IPINDEX_SHIFT = 16, /* 8 BITS */
+ IAVF_RX_DESC_PE_STATUS_QPIDHIT_SHIFT = 24,
+ IAVF_RX_DESC_PE_STATUS_APBVTHIT_SHIFT = 25,
+ IAVF_RX_DESC_PE_STATUS_PORTV_SHIFT = 26,
+ IAVF_RX_DESC_PE_STATUS_URG_SHIFT = 27,
+ IAVF_RX_DESC_PE_STATUS_IPFRAG_SHIFT = 28,
+ IAVF_RX_DESC_PE_STATUS_IPOPT_SHIFT = 29
+};
+
+#define IAVF_RX_PROG_STATUS_DESC_LENGTH_SHIFT 38
+#define IAVF_RX_PROG_STATUS_DESC_LENGTH 0x2000000
+
+#define IAVF_RX_PROG_STATUS_DESC_QW1_PROGID_SHIFT 2
+#define IAVF_RX_PROG_STATUS_DESC_QW1_PROGID_MASK (0x7UL << \
+ IAVF_RX_PROG_STATUS_DESC_QW1_PROGID_SHIFT)
+
+#define IAVF_RX_PROG_STATUS_DESC_QW1_ERROR_SHIFT 19
+#define IAVF_RX_PROG_STATUS_DESC_QW1_ERROR_MASK (0x3FUL << \
+ IAVF_RX_PROG_STATUS_DESC_QW1_ERROR_SHIFT)
+
+enum iavf_rx_prog_status_desc_status_bits {
+ /* Note: These are predefined bit offsets */
+ IAVF_RX_PROG_STATUS_DESC_DD_SHIFT = 0,
+ IAVF_RX_PROG_STATUS_DESC_PROG_ID_SHIFT = 2 /* 3 BITS */
+};
+
+enum iavf_rx_prog_status_desc_prog_id_masks {
+ IAVF_RX_PROG_STATUS_DESC_FD_FILTER_STATUS = 1,
+ IAVF_RX_PROG_STATUS_DESC_FCOE_CTXT_PROG_STATUS = 2,
+ IAVF_RX_PROG_STATUS_DESC_FCOE_CTXT_INVL_STATUS = 4,
+};
+
+enum iavf_rx_prog_status_desc_error_bits {
+ /* Note: These are predefined bit offsets */
+ IAVF_RX_PROG_STATUS_DESC_FD_TBL_FULL_SHIFT = 0,
+ IAVF_RX_PROG_STATUS_DESC_NO_FD_ENTRY_SHIFT = 1,
+ IAVF_RX_PROG_STATUS_DESC_FCOE_TBL_FULL_SHIFT = 2,
+ IAVF_RX_PROG_STATUS_DESC_FCOE_CONFLICT_SHIFT = 3
+};
+
+/* TX Descriptor */
+struct iavf_tx_desc {
+ __le64 buffer_addr; /* Address of descriptor's data buf */
+ __le64 cmd_type_offset_bsz;
+};
+
+#define IAVF_TXD_QW1_DTYPE_SHIFT 0
+#define IAVF_TXD_QW1_DTYPE_MASK (0xFUL << IAVF_TXD_QW1_DTYPE_SHIFT)
+
+enum iavf_tx_desc_dtype_value {
+ IAVF_TX_DESC_DTYPE_DATA = 0x0,
+ IAVF_TX_DESC_DTYPE_NOP = 0x1, /* same as Context desc */
+ IAVF_TX_DESC_DTYPE_CONTEXT = 0x1,
+ IAVF_TX_DESC_DTYPE_FCOE_CTX = 0x2,
+ IAVF_TX_DESC_DTYPE_FILTER_PROG = 0x8,
+ IAVF_TX_DESC_DTYPE_DDP_CTX = 0x9,
+ IAVF_TX_DESC_DTYPE_FLEX_DATA = 0xB,
+ IAVF_TX_DESC_DTYPE_FLEX_CTX_1 = 0xC,
+ IAVF_TX_DESC_DTYPE_FLEX_CTX_2 = 0xD,
+ IAVF_TX_DESC_DTYPE_DESC_DONE = 0xF
+};
+
+#define IAVF_TXD_QW1_CMD_SHIFT 4
+#define IAVF_TXD_QW1_CMD_MASK (0x3FFUL << IAVF_TXD_QW1_CMD_SHIFT)
+
+enum iavf_tx_desc_cmd_bits {
+ IAVF_TX_DESC_CMD_EOP = 0x0001,
+ IAVF_TX_DESC_CMD_RS = 0x0002,
+ IAVF_TX_DESC_CMD_ICRC = 0x0004,
+ IAVF_TX_DESC_CMD_IL2TAG1 = 0x0008,
+ IAVF_TX_DESC_CMD_DUMMY = 0x0010,
+ IAVF_TX_DESC_CMD_IIPT_NONIP = 0x0000, /* 2 BITS */
+ IAVF_TX_DESC_CMD_IIPT_IPV6 = 0x0020, /* 2 BITS */
+ IAVF_TX_DESC_CMD_IIPT_IPV4 = 0x0040, /* 2 BITS */
+ IAVF_TX_DESC_CMD_IIPT_IPV4_CSUM = 0x0060, /* 2 BITS */
+ IAVF_TX_DESC_CMD_FCOET = 0x0080,
+ IAVF_TX_DESC_CMD_L4T_EOFT_UNK = 0x0000, /* 2 BITS */
+ IAVF_TX_DESC_CMD_L4T_EOFT_TCP = 0x0100, /* 2 BITS */
+ IAVF_TX_DESC_CMD_L4T_EOFT_SCTP = 0x0200, /* 2 BITS */
+ IAVF_TX_DESC_CMD_L4T_EOFT_UDP = 0x0300, /* 2 BITS */
+ IAVF_TX_DESC_CMD_L4T_EOFT_EOF_N = 0x0000, /* 2 BITS */
+ IAVF_TX_DESC_CMD_L4T_EOFT_EOF_T = 0x0100, /* 2 BITS */
+ IAVF_TX_DESC_CMD_L4T_EOFT_EOF_NI = 0x0200, /* 2 BITS */
+ IAVF_TX_DESC_CMD_L4T_EOFT_EOF_A = 0x0300, /* 2 BITS */
+};
+
+#define IAVF_TXD_QW1_OFFSET_SHIFT 16
+#define IAVF_TXD_QW1_OFFSET_MASK (0x3FFFFULL << \
+ IAVF_TXD_QW1_OFFSET_SHIFT)
+
+enum iavf_tx_desc_length_fields {
+ /* Note: These are predefined bit offsets */
+ IAVF_TX_DESC_LENGTH_MACLEN_SHIFT = 0, /* 7 BITS */
+ IAVF_TX_DESC_LENGTH_IPLEN_SHIFT = 7, /* 7 BITS */
+ IAVF_TX_DESC_LENGTH_L4_FC_LEN_SHIFT = 14 /* 4 BITS */
+};
+
+#define IAVF_TXD_QW1_TX_BUF_SZ_SHIFT 34
+#define IAVF_TXD_QW1_TX_BUF_SZ_MASK (0x3FFFULL << \
+ IAVF_TXD_QW1_TX_BUF_SZ_SHIFT)
+
+#define IAVF_TXD_QW1_L2TAG1_SHIFT 48
+#define IAVF_TXD_QW1_L2TAG1_MASK (0xFFFFULL << IAVF_TXD_QW1_L2TAG1_SHIFT)
+
+/* Context descriptors */
+struct iavf_tx_context_desc {
+ __le32 tunneling_params;
+ __le16 l2tag2;
+ __le16 rsvd;
+ __le64 type_cmd_tso_mss;
+};
+
+#define IAVF_TXD_CTX_QW1_CMD_SHIFT 4
+#define IAVF_TXD_CTX_QW1_CMD_MASK (0xFFFFUL << IAVF_TXD_CTX_QW1_CMD_SHIFT)
+
+enum iavf_tx_ctx_desc_cmd_bits {
+ IAVF_TX_CTX_DESC_TSO = 0x01,
+ IAVF_TX_CTX_DESC_TSYN = 0x02,
+ IAVF_TX_CTX_DESC_IL2TAG2 = 0x04,
+ IAVF_TX_CTX_DESC_IL2TAG2_IL2H = 0x08,
+ IAVF_TX_CTX_DESC_SWTCH_NOTAG = 0x00,
+ IAVF_TX_CTX_DESC_SWTCH_UPLINK = 0x10,
+ IAVF_TX_CTX_DESC_SWTCH_LOCAL = 0x20,
+ IAVF_TX_CTX_DESC_SWTCH_VSI = 0x30,
+ IAVF_TX_CTX_DESC_SWPE = 0x40
+};
+
+/* Packet Classifier Types for filters */
+enum iavf_filter_pctype {
+ /* Note: Values 0-28 are reserved for future use.
+ * Value 29, 30, 32 are not supported on XL710 and X710.
+ */
+ IAVF_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP = 29,
+ IAVF_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP = 30,
+ IAVF_FILTER_PCTYPE_NONF_IPV4_UDP = 31,
+ IAVF_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK = 32,
+ IAVF_FILTER_PCTYPE_NONF_IPV4_TCP = 33,
+ IAVF_FILTER_PCTYPE_NONF_IPV4_SCTP = 34,
+ IAVF_FILTER_PCTYPE_NONF_IPV4_OTHER = 35,
+ IAVF_FILTER_PCTYPE_FRAG_IPV4 = 36,
+ /* Note: Values 37-38 are reserved for future use.
+ * Value 39, 40, 42 are not supported on XL710 and X710.
+ */
+ IAVF_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP = 39,
+ IAVF_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP = 40,
+ IAVF_FILTER_PCTYPE_NONF_IPV6_UDP = 41,
+ IAVF_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK = 42,
+ IAVF_FILTER_PCTYPE_NONF_IPV6_TCP = 43,
+ IAVF_FILTER_PCTYPE_NONF_IPV6_SCTP = 44,
+ IAVF_FILTER_PCTYPE_NONF_IPV6_OTHER = 45,
+ IAVF_FILTER_PCTYPE_FRAG_IPV6 = 46,
+ /* Note: Value 47 is reserved for future use */
+ IAVF_FILTER_PCTYPE_FCOE_OX = 48,
+ IAVF_FILTER_PCTYPE_FCOE_RX = 49,
+ IAVF_FILTER_PCTYPE_FCOE_OTHER = 50,
+ /* Note: Values 51-62 are reserved for future use */
+ IAVF_FILTER_PCTYPE_L2_PAYLOAD = 63,
+};
+
+#define IAVF_TXD_CTX_QW1_TSO_LEN_SHIFT 30
+#define IAVF_TXD_CTX_QW1_TSO_LEN_MASK (0x3FFFFULL << \
+ IAVF_TXD_CTX_QW1_TSO_LEN_SHIFT)
+
+#define IAVF_TXD_CTX_QW1_MSS_SHIFT 50
+#define IAVF_TXD_CTX_QW1_MSS_MASK (0x3FFFULL << \
+ IAVF_TXD_CTX_QW1_MSS_SHIFT)
+
+#define IAVF_TXD_CTX_QW1_VSI_SHIFT 50
+#define IAVF_TXD_CTX_QW1_VSI_MASK (0x1FFULL << IAVF_TXD_CTX_QW1_VSI_SHIFT)
+
+#define IAVF_TXD_CTX_QW0_EXT_IP_SHIFT 0
+#define IAVF_TXD_CTX_QW0_EXT_IP_MASK (0x3ULL << \
+ IAVF_TXD_CTX_QW0_EXT_IP_SHIFT)
+
+enum iavf_tx_ctx_desc_eipt_offload {
+ IAVF_TX_CTX_EXT_IP_NONE = 0x0,
+ IAVF_TX_CTX_EXT_IP_IPV6 = 0x1,
+ IAVF_TX_CTX_EXT_IP_IPV4_NO_CSUM = 0x2,
+ IAVF_TX_CTX_EXT_IP_IPV4 = 0x3
+};
+
+#define IAVF_TXD_CTX_QW0_EXT_IPLEN_SHIFT 2
+#define IAVF_TXD_CTX_QW0_EXT_IPLEN_MASK (0x3FULL << \
+ IAVF_TXD_CTX_QW0_EXT_IPLEN_SHIFT)
+
+#define IAVF_TXD_CTX_QW0_NATT_SHIFT 9
+#define IAVF_TXD_CTX_QW0_NATT_MASK (0x3ULL << IAVF_TXD_CTX_QW0_NATT_SHIFT)
+
+#define IAVF_TXD_CTX_UDP_TUNNELING BIT_ULL(IAVF_TXD_CTX_QW0_NATT_SHIFT)
+#define IAVF_TXD_CTX_GRE_TUNNELING (0x2ULL << IAVF_TXD_CTX_QW0_NATT_SHIFT)
+
+#define IAVF_TXD_CTX_QW0_EIP_NOINC_SHIFT 11
+#define IAVF_TXD_CTX_QW0_EIP_NOINC_MASK \
+ BIT_ULL(IAVF_TXD_CTX_QW0_EIP_NOINC_SHIFT)
+
+#define IAVF_TXD_CTX_EIP_NOINC_IPID_CONST IAVF_TXD_CTX_QW0_EIP_NOINC_MASK
+
+#define IAVF_TXD_CTX_QW0_NATLEN_SHIFT 12
+#define IAVF_TXD_CTX_QW0_NATLEN_MASK (0X7FULL << \
+ IAVF_TXD_CTX_QW0_NATLEN_SHIFT)
+
+#define IAVF_TXD_CTX_QW0_DECTTL_SHIFT 19
+#define IAVF_TXD_CTX_QW0_DECTTL_MASK (0xFULL << \
+ IAVF_TXD_CTX_QW0_DECTTL_SHIFT)
+
+#define IAVF_TXD_CTX_QW0_L4T_CS_SHIFT 23
+#define IAVF_TXD_CTX_QW0_L4T_CS_MASK BIT_ULL(IAVF_TXD_CTX_QW0_L4T_CS_SHIFT)
+
+/* Statistics collected by each port, VSI, VEB, and S-channel */
+struct iavf_eth_stats {
+ u64 rx_bytes; /* gorc */
+ u64 rx_unicast; /* uprc */
+ u64 rx_multicast; /* mprc */
+ u64 rx_broadcast; /* bprc */
+ u64 rx_discards; /* rdpc */
+ u64 rx_unknown_protocol; /* rupp */
+ u64 tx_bytes; /* gotc */
+ u64 tx_unicast; /* uptc */
+ u64 tx_multicast; /* mptc */
+ u64 tx_broadcast; /* bptc */
+ u64 tx_discards; /* tdpc */
+ u64 tx_errors; /* tepc */
+};
+#endif /* _IAVF_TYPE_H_ */
diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
index 565677de5ba3..e64751da0921 100644
--- a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
@@ -1,16 +1,16 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2013 - 2018 Intel Corporation. */
-#include "i40evf.h"
-#include "i40e_prototype.h"
-#include "i40evf_client.h"
+#include "iavf.h"
+#include "iavf_prototype.h"
+#include "iavf_client.h"
/* busy wait delay in msec */
-#define I40EVF_BUSY_WAIT_DELAY 10
-#define I40EVF_BUSY_WAIT_COUNT 50
+#define IAVF_BUSY_WAIT_DELAY 10
+#define IAVF_BUSY_WAIT_COUNT 50
/**
- * i40evf_send_pf_msg
+ * iavf_send_pf_msg
* @adapter: adapter structure
* @op: virtual channel opcode
* @msg: pointer to message buffer
@@ -18,44 +18,44 @@
*
* Send message to PF and print status if failure.
**/
-static int i40evf_send_pf_msg(struct i40evf_adapter *adapter,
- enum virtchnl_ops op, u8 *msg, u16 len)
+static int iavf_send_pf_msg(struct iavf_adapter *adapter,
+ enum virtchnl_ops op, u8 *msg, u16 len)
{
- struct i40e_hw *hw = &adapter->hw;
- i40e_status err;
+ struct iavf_hw *hw = &adapter->hw;
+ iavf_status err;
- if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED)
+ if (adapter->flags & IAVF_FLAG_PF_COMMS_FAILED)
return 0; /* nothing to see here, move along */
- err = i40e_aq_send_msg_to_pf(hw, op, 0, msg, len, NULL);
+ err = iavf_aq_send_msg_to_pf(hw, op, 0, msg, len, NULL);
if (err)
dev_dbg(&adapter->pdev->dev, "Unable to send opcode %d to PF, err %s, aq_err %s\n",
- op, i40evf_stat_str(hw, err),
- i40evf_aq_str(hw, hw->aq.asq_last_status));
+ op, iavf_stat_str(hw, err),
+ iavf_aq_str(hw, hw->aq.asq_last_status));
return err;
}
/**
- * i40evf_send_api_ver
+ * iavf_send_api_ver
* @adapter: adapter structure
*
* Send API version admin queue message to the PF. The reply is not checked
* in this function. Returns 0 if the message was successfully
* sent, or one of the I40E_ADMIN_QUEUE_ERROR_ statuses if not.
**/
-int i40evf_send_api_ver(struct i40evf_adapter *adapter)
+int iavf_send_api_ver(struct iavf_adapter *adapter)
{
struct virtchnl_version_info vvi;
vvi.major = VIRTCHNL_VERSION_MAJOR;
vvi.minor = VIRTCHNL_VERSION_MINOR;
- return i40evf_send_pf_msg(adapter, VIRTCHNL_OP_VERSION, (u8 *)&vvi,
- sizeof(vvi));
+ return iavf_send_pf_msg(adapter, VIRTCHNL_OP_VERSION, (u8 *)&vvi,
+ sizeof(vvi));
}
/**
- * i40evf_verify_api_ver
+ * iavf_verify_api_ver
* @adapter: adapter structure
*
* Compare API versions with the PF. Must be called after admin queue is
@@ -63,15 +63,15 @@ int i40evf_send_api_ver(struct i40evf_adapter *adapter)
* I40E_ERR_ADMIN_QUEUE_NO_WORK if the admin queue is empty, and any errors
* from the firmware are propagated.
**/
-int i40evf_verify_api_ver(struct i40evf_adapter *adapter)
+int iavf_verify_api_ver(struct iavf_adapter *adapter)
{
struct virtchnl_version_info *pf_vvi;
- struct i40e_hw *hw = &adapter->hw;
+ struct iavf_hw *hw = &adapter->hw;
struct i40e_arq_event_info event;
enum virtchnl_ops op;
- i40e_status err;
+ iavf_status err;
- event.buf_len = I40EVF_MAX_AQ_BUF_SIZE;
+ event.buf_len = IAVF_MAX_AQ_BUF_SIZE;
event.msg_buf = kzalloc(event.buf_len, GFP_KERNEL);
if (!event.msg_buf) {
err = -ENOMEM;
@@ -79,8 +79,8 @@ int i40evf_verify_api_ver(struct i40evf_adapter *adapter)
}
while (1) {
- err = i40evf_clean_arq_element(hw, &event, NULL);
- /* When the AQ is empty, i40evf_clean_arq_element will return
+ err = iavf_clean_arq_element(hw, &event, NULL);
+ /* When the AQ is empty, iavf_clean_arq_element will return
* nonzero and this loop will terminate.
*/
if (err)
@@ -92,7 +92,7 @@ int i40evf_verify_api_ver(struct i40evf_adapter *adapter)
}
- err = (i40e_status)le32_to_cpu(event.desc.cookie_low);
+ err = (iavf_status)le32_to_cpu(event.desc.cookie_low);
if (err)
goto out_alloc;
@@ -118,14 +118,14 @@ out:
}
/**
- * i40evf_send_vf_config_msg
+ * iavf_send_vf_config_msg
* @adapter: adapter structure
*
* Send VF configuration request admin queue message to the PF. The reply
* is not checked in this function. Returns 0 if the message was
* successfully sent, or one of the I40E_ADMIN_QUEUE_ERROR_ statuses if not.
**/
-int i40evf_send_vf_config_msg(struct i40evf_adapter *adapter)
+int iavf_send_vf_config_msg(struct iavf_adapter *adapter)
{
u32 caps;
@@ -142,19 +142,43 @@ int i40evf_send_vf_config_msg(struct i40evf_adapter *adapter)
VIRTCHNL_VF_OFFLOAD_ADQ;
adapter->current_op = VIRTCHNL_OP_GET_VF_RESOURCES;
- adapter->aq_required &= ~I40EVF_FLAG_AQ_GET_CONFIG;
+ adapter->aq_required &= ~IAVF_FLAG_AQ_GET_CONFIG;
if (PF_IS_V11(adapter))
- return i40evf_send_pf_msg(adapter,
- VIRTCHNL_OP_GET_VF_RESOURCES,
- (u8 *)&caps, sizeof(caps));
+ return iavf_send_pf_msg(adapter, VIRTCHNL_OP_GET_VF_RESOURCES,
+ (u8 *)&caps, sizeof(caps));
else
- return i40evf_send_pf_msg(adapter,
- VIRTCHNL_OP_GET_VF_RESOURCES,
- NULL, 0);
+ return iavf_send_pf_msg(adapter, VIRTCHNL_OP_GET_VF_RESOURCES,
+ NULL, 0);
}
/**
- * i40evf_get_vf_config
+ * iavf_validate_num_queues
+ * @adapter: adapter structure
+ *
+ * Validate that the number of queues the PF has sent in
+ * VIRTCHNL_OP_GET_VF_RESOURCES is not larger than the VF can handle.
+ **/
+static void iavf_validate_num_queues(struct iavf_adapter *adapter)
+{
+ if (adapter->vf_res->num_queue_pairs > IAVF_MAX_REQ_QUEUES) {
+ struct virtchnl_vsi_resource *vsi_res;
+ int i;
+
+ dev_info(&adapter->pdev->dev, "Received %d queues, but can only have a max of %d\n",
+ adapter->vf_res->num_queue_pairs,
+ IAVF_MAX_REQ_QUEUES);
+ dev_info(&adapter->pdev->dev, "Fixing by reducing queues to %d\n",
+ IAVF_MAX_REQ_QUEUES);
+ adapter->vf_res->num_queue_pairs = IAVF_MAX_REQ_QUEUES;
+ for (i = 0; i < adapter->vf_res->num_vsis; i++) {
+ vsi_res = &adapter->vf_res->vsi_res[i];
+ vsi_res->num_queue_pairs = IAVF_MAX_REQ_QUEUES;
+ }
+ }
+}
+
+/**
+ * iavf_get_vf_config
* @adapter: private adapter structure
*
* Get VF configuration from PF and populate hw structure. Must be called after
@@ -162,16 +186,16 @@ int i40evf_send_vf_config_msg(struct i40evf_adapter *adapter)
* with maximum timeout. Response from PF is returned in the buffer for further
* processing by the caller.
**/
-int i40evf_get_vf_config(struct i40evf_adapter *adapter)
+int iavf_get_vf_config(struct iavf_adapter *adapter)
{
- struct i40e_hw *hw = &adapter->hw;
+ struct iavf_hw *hw = &adapter->hw;
struct i40e_arq_event_info event;
enum virtchnl_ops op;
- i40e_status err;
+ iavf_status err;
u16 len;
len = sizeof(struct virtchnl_vf_resource) +
- I40E_MAX_VF_VSI * sizeof(struct virtchnl_vsi_resource);
+ IAVF_MAX_VF_VSI * sizeof(struct virtchnl_vsi_resource);
event.buf_len = len;
event.msg_buf = kzalloc(event.buf_len, GFP_KERNEL);
if (!event.msg_buf) {
@@ -180,10 +204,10 @@ int i40evf_get_vf_config(struct i40evf_adapter *adapter)
}
while (1) {
- /* When the AQ is empty, i40evf_clean_arq_element will return
+ /* When the AQ is empty, iavf_clean_arq_element will return
* nonzero and this loop will terminate.
*/
- err = i40evf_clean_arq_element(hw, &event, NULL);
+ err = iavf_clean_arq_element(hw, &event, NULL);
if (err)
goto out_alloc;
op =
@@ -192,10 +216,15 @@ int i40evf_get_vf_config(struct i40evf_adapter *adapter)
break;
}
- err = (i40e_status)le32_to_cpu(event.desc.cookie_low);
+ err = (iavf_status)le32_to_cpu(event.desc.cookie_low);
memcpy(adapter->vf_res, event.msg_buf, min(event.msg_len, len));
- i40e_vf_parse_hw_config(hw, adapter->vf_res);
+ /* some PFs send more queues than we should have so validate that
+ * we aren't getting too many queues
+ */
+ if (!err)
+ iavf_validate_num_queues(adapter);
+ iavf_vf_parse_hw_config(hw, adapter->vf_res);
out_alloc:
kfree(event.msg_buf);
out:
@@ -203,17 +232,17 @@ out:
}
/**
- * i40evf_configure_queues
+ * iavf_configure_queues
* @adapter: adapter structure
*
* Request that the PF set up our (previously allocated) queues.
**/
-void i40evf_configure_queues(struct i40evf_adapter *adapter)
+void iavf_configure_queues(struct iavf_adapter *adapter)
{
struct virtchnl_vsi_queue_config_info *vqci;
struct virtchnl_queue_pair_info *vqpi;
int pairs = adapter->num_active_queues;
- int i, len, max_frame = I40E_MAX_RXBUFFER;
+ int i, len, max_frame = IAVF_MAX_RXBUFFER;
if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) {
/* bail because we already have a command pending */
@@ -229,9 +258,9 @@ void i40evf_configure_queues(struct i40evf_adapter *adapter)
return;
/* Limit maximum frame size when jumbo frames is not enabled */
- if (!(adapter->flags & I40EVF_FLAG_LEGACY_RX) &&
+ if (!(adapter->flags & IAVF_FLAG_LEGACY_RX) &&
(adapter->netdev->mtu <= ETH_DATA_LEN))
- max_frame = I40E_RXBUFFER_1536 - NET_IP_ALIGN;
+ max_frame = IAVF_RXBUFFER_1536 - NET_IP_ALIGN;
vqci->vsi_id = adapter->vsi_res->vsi_id;
vqci->num_queue_pairs = pairs;
@@ -251,23 +280,23 @@ void i40evf_configure_queues(struct i40evf_adapter *adapter)
vqpi->rxq.max_pkt_size = max_frame;
vqpi->rxq.databuffer_size =
ALIGN(adapter->rx_rings[i].rx_buf_len,
- BIT_ULL(I40E_RXQ_CTX_DBUFF_SHIFT));
+ BIT_ULL(IAVF_RXQ_CTX_DBUFF_SHIFT));
vqpi++;
}
- adapter->aq_required &= ~I40EVF_FLAG_AQ_CONFIGURE_QUEUES;
- i40evf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_VSI_QUEUES,
- (u8 *)vqci, len);
+ adapter->aq_required &= ~IAVF_FLAG_AQ_CONFIGURE_QUEUES;
+ iavf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_VSI_QUEUES,
+ (u8 *)vqci, len);
kfree(vqci);
}
/**
- * i40evf_enable_queues
+ * iavf_enable_queues
* @adapter: adapter structure
*
* Request that the PF enable all of our queues.
**/
-void i40evf_enable_queues(struct i40evf_adapter *adapter)
+void iavf_enable_queues(struct iavf_adapter *adapter)
{
struct virtchnl_queue_select vqs;
@@ -281,18 +310,18 @@ void i40evf_enable_queues(struct i40evf_adapter *adapter)
vqs.vsi_id = adapter->vsi_res->vsi_id;
vqs.tx_queues = BIT(adapter->num_active_queues) - 1;
vqs.rx_queues = vqs.tx_queues;
- adapter->aq_required &= ~I40EVF_FLAG_AQ_ENABLE_QUEUES;
- i40evf_send_pf_msg(adapter, VIRTCHNL_OP_ENABLE_QUEUES,
- (u8 *)&vqs, sizeof(vqs));
+ adapter->aq_required &= ~IAVF_FLAG_AQ_ENABLE_QUEUES;
+ iavf_send_pf_msg(adapter, VIRTCHNL_OP_ENABLE_QUEUES,
+ (u8 *)&vqs, sizeof(vqs));
}
/**
- * i40evf_disable_queues
+ * iavf_disable_queues
* @adapter: adapter structure
*
* Request that the PF disable all of our queues.
**/
-void i40evf_disable_queues(struct i40evf_adapter *adapter)
+void iavf_disable_queues(struct iavf_adapter *adapter)
{
struct virtchnl_queue_select vqs;
@@ -306,24 +335,24 @@ void i40evf_disable_queues(struct i40evf_adapter *adapter)
vqs.vsi_id = adapter->vsi_res->vsi_id;
vqs.tx_queues = BIT(adapter->num_active_queues) - 1;
vqs.rx_queues = vqs.tx_queues;
- adapter->aq_required &= ~I40EVF_FLAG_AQ_DISABLE_QUEUES;
- i40evf_send_pf_msg(adapter, VIRTCHNL_OP_DISABLE_QUEUES,
- (u8 *)&vqs, sizeof(vqs));
+ adapter->aq_required &= ~IAVF_FLAG_AQ_DISABLE_QUEUES;
+ iavf_send_pf_msg(adapter, VIRTCHNL_OP_DISABLE_QUEUES,
+ (u8 *)&vqs, sizeof(vqs));
}
/**
- * i40evf_map_queues
+ * iavf_map_queues
* @adapter: adapter structure
*
* Request that the PF map queues to interrupt vectors. Misc causes, including
* admin queue, are always mapped to vector 0.
**/
-void i40evf_map_queues(struct i40evf_adapter *adapter)
+void iavf_map_queues(struct iavf_adapter *adapter)
{
struct virtchnl_irq_map_info *vimi;
struct virtchnl_vector_map *vecmap;
int v_idx, q_vectors, len;
- struct i40e_q_vector *q_vector;
+ struct iavf_q_vector *q_vector;
if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) {
/* bail because we already have a command pending */
@@ -352,8 +381,8 @@ void i40evf_map_queues(struct i40evf_adapter *adapter)
vecmap->vector_id = v_idx + NONQ_VECS;
vecmap->txq_map = q_vector->ring_mask;
vecmap->rxq_map = q_vector->ring_mask;
- vecmap->rxitr_idx = I40E_RX_ITR;
- vecmap->txitr_idx = I40E_TX_ITR;
+ vecmap->rxitr_idx = IAVF_RX_ITR;
+ vecmap->txitr_idx = IAVF_TX_ITR;
}
/* Misc vector last - this is only for AdminQ messages */
vecmap = &vimi->vecmap[v_idx];
@@ -362,21 +391,21 @@ void i40evf_map_queues(struct i40evf_adapter *adapter)
vecmap->txq_map = 0;
vecmap->rxq_map = 0;
- adapter->aq_required &= ~I40EVF_FLAG_AQ_MAP_VECTORS;
- i40evf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_IRQ_MAP,
- (u8 *)vimi, len);
+ adapter->aq_required &= ~IAVF_FLAG_AQ_MAP_VECTORS;
+ iavf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_IRQ_MAP,
+ (u8 *)vimi, len);
kfree(vimi);
}
/**
- * i40evf_request_queues
+ * iavf_request_queues
* @adapter: adapter structure
* @num: number of requested queues
*
* We get a default number of queues from the PF. This enables us to request a
* different number. Returns 0 on success, negative on failure
**/
-int i40evf_request_queues(struct i40evf_adapter *adapter, int num)
+int iavf_request_queues(struct iavf_adapter *adapter, int num)
{
struct virtchnl_vf_res_request vfres;
@@ -390,22 +419,22 @@ int i40evf_request_queues(struct i40evf_adapter *adapter, int num)
vfres.num_queue_pairs = num;
adapter->current_op = VIRTCHNL_OP_REQUEST_QUEUES;
- adapter->flags |= I40EVF_FLAG_REINIT_ITR_NEEDED;
- return i40evf_send_pf_msg(adapter, VIRTCHNL_OP_REQUEST_QUEUES,
- (u8 *)&vfres, sizeof(vfres));
+ adapter->flags |= IAVF_FLAG_REINIT_ITR_NEEDED;
+ return iavf_send_pf_msg(adapter, VIRTCHNL_OP_REQUEST_QUEUES,
+ (u8 *)&vfres, sizeof(vfres));
}
/**
- * i40evf_add_ether_addrs
+ * iavf_add_ether_addrs
* @adapter: adapter structure
*
* Request that the PF add one or more addresses to our filters.
**/
-void i40evf_add_ether_addrs(struct i40evf_adapter *adapter)
+void iavf_add_ether_addrs(struct iavf_adapter *adapter)
{
struct virtchnl_ether_addr_list *veal;
int len, i = 0, count = 0;
- struct i40evf_mac_filter *f;
+ struct iavf_mac_filter *f;
bool more = false;
if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) {
@@ -422,7 +451,7 @@ void i40evf_add_ether_addrs(struct i40evf_adapter *adapter)
count++;
}
if (!count) {
- adapter->aq_required &= ~I40EVF_FLAG_AQ_ADD_MAC_FILTER;
+ adapter->aq_required &= ~IAVF_FLAG_AQ_ADD_MAC_FILTER;
spin_unlock_bh(&adapter->mac_vlan_list_lock);
return;
}
@@ -430,9 +459,9 @@ void i40evf_add_ether_addrs(struct i40evf_adapter *adapter)
len = sizeof(struct virtchnl_ether_addr_list) +
(count * sizeof(struct virtchnl_ether_addr));
- if (len > I40EVF_MAX_AQ_BUF_SIZE) {
+ if (len > IAVF_MAX_AQ_BUF_SIZE) {
dev_warn(&adapter->pdev->dev, "Too many add MAC changes in one request\n");
- count = (I40EVF_MAX_AQ_BUF_SIZE -
+ count = (IAVF_MAX_AQ_BUF_SIZE -
sizeof(struct virtchnl_ether_addr_list)) /
sizeof(struct virtchnl_ether_addr);
len = sizeof(struct virtchnl_ether_addr_list) +
@@ -458,25 +487,24 @@ void i40evf_add_ether_addrs(struct i40evf_adapter *adapter)
}
}
if (!more)
- adapter->aq_required &= ~I40EVF_FLAG_AQ_ADD_MAC_FILTER;
+ adapter->aq_required &= ~IAVF_FLAG_AQ_ADD_MAC_FILTER;
spin_unlock_bh(&adapter->mac_vlan_list_lock);
- i40evf_send_pf_msg(adapter, VIRTCHNL_OP_ADD_ETH_ADDR,
- (u8 *)veal, len);
+ iavf_send_pf_msg(adapter, VIRTCHNL_OP_ADD_ETH_ADDR, (u8 *)veal, len);
kfree(veal);
}
/**
- * i40evf_del_ether_addrs
+ * iavf_del_ether_addrs
* @adapter: adapter structure
*
* Request that the PF remove one or more addresses from our filters.
**/
-void i40evf_del_ether_addrs(struct i40evf_adapter *adapter)
+void iavf_del_ether_addrs(struct iavf_adapter *adapter)
{
struct virtchnl_ether_addr_list *veal;
- struct i40evf_mac_filter *f, *ftmp;
+ struct iavf_mac_filter *f, *ftmp;
int len, i = 0, count = 0;
bool more = false;
@@ -494,7 +522,7 @@ void i40evf_del_ether_addrs(struct i40evf_adapter *adapter)
count++;
}
if (!count) {
- adapter->aq_required &= ~I40EVF_FLAG_AQ_DEL_MAC_FILTER;
+ adapter->aq_required &= ~IAVF_FLAG_AQ_DEL_MAC_FILTER;
spin_unlock_bh(&adapter->mac_vlan_list_lock);
return;
}
@@ -502,9 +530,9 @@ void i40evf_del_ether_addrs(struct i40evf_adapter *adapter)
len = sizeof(struct virtchnl_ether_addr_list) +
(count * sizeof(struct virtchnl_ether_addr));
- if (len > I40EVF_MAX_AQ_BUF_SIZE) {
+ if (len > IAVF_MAX_AQ_BUF_SIZE) {
dev_warn(&adapter->pdev->dev, "Too many delete MAC changes in one request\n");
- count = (I40EVF_MAX_AQ_BUF_SIZE -
+ count = (IAVF_MAX_AQ_BUF_SIZE -
sizeof(struct virtchnl_ether_addr_list)) /
sizeof(struct virtchnl_ether_addr);
len = sizeof(struct virtchnl_ether_addr_list) +
@@ -530,26 +558,25 @@ void i40evf_del_ether_addrs(struct i40evf_adapter *adapter)
}
}
if (!more)
- adapter->aq_required &= ~I40EVF_FLAG_AQ_DEL_MAC_FILTER;
+ adapter->aq_required &= ~IAVF_FLAG_AQ_DEL_MAC_FILTER;
spin_unlock_bh(&adapter->mac_vlan_list_lock);
- i40evf_send_pf_msg(adapter, VIRTCHNL_OP_DEL_ETH_ADDR,
- (u8 *)veal, len);
+ iavf_send_pf_msg(adapter, VIRTCHNL_OP_DEL_ETH_ADDR, (u8 *)veal, len);
kfree(veal);
}
/**
- * i40evf_add_vlans
+ * iavf_add_vlans
* @adapter: adapter structure
*
* Request that the PF add one or more VLAN filters to our VSI.
**/
-void i40evf_add_vlans(struct i40evf_adapter *adapter)
+void iavf_add_vlans(struct iavf_adapter *adapter)
{
struct virtchnl_vlan_filter_list *vvfl;
int len, i = 0, count = 0;
- struct i40evf_vlan_filter *f;
+ struct iavf_vlan_filter *f;
bool more = false;
if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) {
@@ -566,7 +593,7 @@ void i40evf_add_vlans(struct i40evf_adapter *adapter)
count++;
}
if (!count) {
- adapter->aq_required &= ~I40EVF_FLAG_AQ_ADD_VLAN_FILTER;
+ adapter->aq_required &= ~IAVF_FLAG_AQ_ADD_VLAN_FILTER;
spin_unlock_bh(&adapter->mac_vlan_list_lock);
return;
}
@@ -574,9 +601,9 @@ void i40evf_add_vlans(struct i40evf_adapter *adapter)
len = sizeof(struct virtchnl_vlan_filter_list) +
(count * sizeof(u16));
- if (len > I40EVF_MAX_AQ_BUF_SIZE) {
+ if (len > IAVF_MAX_AQ_BUF_SIZE) {
dev_warn(&adapter->pdev->dev, "Too many add VLAN changes in one request\n");
- count = (I40EVF_MAX_AQ_BUF_SIZE -
+ count = (IAVF_MAX_AQ_BUF_SIZE -
sizeof(struct virtchnl_vlan_filter_list)) /
sizeof(u16);
len = sizeof(struct virtchnl_vlan_filter_list) +
@@ -601,24 +628,24 @@ void i40evf_add_vlans(struct i40evf_adapter *adapter)
}
}
if (!more)
- adapter->aq_required &= ~I40EVF_FLAG_AQ_ADD_VLAN_FILTER;
+ adapter->aq_required &= ~IAVF_FLAG_AQ_ADD_VLAN_FILTER;
spin_unlock_bh(&adapter->mac_vlan_list_lock);
- i40evf_send_pf_msg(adapter, VIRTCHNL_OP_ADD_VLAN, (u8 *)vvfl, len);
+ iavf_send_pf_msg(adapter, VIRTCHNL_OP_ADD_VLAN, (u8 *)vvfl, len);
kfree(vvfl);
}
/**
- * i40evf_del_vlans
+ * iavf_del_vlans
* @adapter: adapter structure
*
* Request that the PF remove one or more VLAN filters from our VSI.
**/
-void i40evf_del_vlans(struct i40evf_adapter *adapter)
+void iavf_del_vlans(struct iavf_adapter *adapter)
{
struct virtchnl_vlan_filter_list *vvfl;
- struct i40evf_vlan_filter *f, *ftmp;
+ struct iavf_vlan_filter *f, *ftmp;
int len, i = 0, count = 0;
bool more = false;
@@ -636,7 +663,7 @@ void i40evf_del_vlans(struct i40evf_adapter *adapter)
count++;
}
if (!count) {
- adapter->aq_required &= ~I40EVF_FLAG_AQ_DEL_VLAN_FILTER;
+ adapter->aq_required &= ~IAVF_FLAG_AQ_DEL_VLAN_FILTER;
spin_unlock_bh(&adapter->mac_vlan_list_lock);
return;
}
@@ -644,9 +671,9 @@ void i40evf_del_vlans(struct i40evf_adapter *adapter)
len = sizeof(struct virtchnl_vlan_filter_list) +
(count * sizeof(u16));
- if (len > I40EVF_MAX_AQ_BUF_SIZE) {
+ if (len > IAVF_MAX_AQ_BUF_SIZE) {
dev_warn(&adapter->pdev->dev, "Too many delete VLAN changes in one request\n");
- count = (I40EVF_MAX_AQ_BUF_SIZE -
+ count = (IAVF_MAX_AQ_BUF_SIZE -
sizeof(struct virtchnl_vlan_filter_list)) /
sizeof(u16);
len = sizeof(struct virtchnl_vlan_filter_list) +
@@ -672,22 +699,22 @@ void i40evf_del_vlans(struct i40evf_adapter *adapter)
}
}
if (!more)
- adapter->aq_required &= ~I40EVF_FLAG_AQ_DEL_VLAN_FILTER;
+ adapter->aq_required &= ~IAVF_FLAG_AQ_DEL_VLAN_FILTER;
spin_unlock_bh(&adapter->mac_vlan_list_lock);
- i40evf_send_pf_msg(adapter, VIRTCHNL_OP_DEL_VLAN, (u8 *)vvfl, len);
+ iavf_send_pf_msg(adapter, VIRTCHNL_OP_DEL_VLAN, (u8 *)vvfl, len);
kfree(vvfl);
}
/**
- * i40evf_set_promiscuous
+ * iavf_set_promiscuous
* @adapter: adapter structure
* @flags: bitmask to control unicast/multicast promiscuous.
*
* Request that the PF enable promiscuous mode for our VSI.
**/
-void i40evf_set_promiscuous(struct i40evf_adapter *adapter, int flags)
+void iavf_set_promiscuous(struct iavf_adapter *adapter, int flags)
{
struct virtchnl_promisc_info vpi;
int promisc_all;
@@ -702,39 +729,39 @@ void i40evf_set_promiscuous(struct i40evf_adapter *adapter, int flags)
promisc_all = FLAG_VF_UNICAST_PROMISC |
FLAG_VF_MULTICAST_PROMISC;
if ((flags & promisc_all) == promisc_all) {
- adapter->flags |= I40EVF_FLAG_PROMISC_ON;
- adapter->aq_required &= ~I40EVF_FLAG_AQ_REQUEST_PROMISC;
+ adapter->flags |= IAVF_FLAG_PROMISC_ON;
+ adapter->aq_required &= ~IAVF_FLAG_AQ_REQUEST_PROMISC;
dev_info(&adapter->pdev->dev, "Entering promiscuous mode\n");
}
if (flags & FLAG_VF_MULTICAST_PROMISC) {
- adapter->flags |= I40EVF_FLAG_ALLMULTI_ON;
- adapter->aq_required &= ~I40EVF_FLAG_AQ_REQUEST_ALLMULTI;
+ adapter->flags |= IAVF_FLAG_ALLMULTI_ON;
+ adapter->aq_required &= ~IAVF_FLAG_AQ_REQUEST_ALLMULTI;
dev_info(&adapter->pdev->dev, "Entering multicast promiscuous mode\n");
}
if (!flags) {
- adapter->flags &= ~(I40EVF_FLAG_PROMISC_ON |
- I40EVF_FLAG_ALLMULTI_ON);
- adapter->aq_required &= ~(I40EVF_FLAG_AQ_RELEASE_PROMISC |
- I40EVF_FLAG_AQ_RELEASE_ALLMULTI);
+ adapter->flags &= ~(IAVF_FLAG_PROMISC_ON |
+ IAVF_FLAG_ALLMULTI_ON);
+ adapter->aq_required &= ~(IAVF_FLAG_AQ_RELEASE_PROMISC |
+ IAVF_FLAG_AQ_RELEASE_ALLMULTI);
dev_info(&adapter->pdev->dev, "Leaving promiscuous mode\n");
}
adapter->current_op = VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE;
vpi.vsi_id = adapter->vsi_res->vsi_id;
vpi.flags = flags;
- i40evf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE,
- (u8 *)&vpi, sizeof(vpi));
+ iavf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE,
+ (u8 *)&vpi, sizeof(vpi));
}
/**
- * i40evf_request_stats
+ * iavf_request_stats
* @adapter: adapter structure
*
* Request VSI statistics from PF.
**/
-void i40evf_request_stats(struct i40evf_adapter *adapter)
+void iavf_request_stats(struct iavf_adapter *adapter)
{
struct virtchnl_queue_select vqs;
@@ -745,19 +772,19 @@ void i40evf_request_stats(struct i40evf_adapter *adapter)
adapter->current_op = VIRTCHNL_OP_GET_STATS;
vqs.vsi_id = adapter->vsi_res->vsi_id;
/* queue maps are ignored for this message - only the vsi is used */
- if (i40evf_send_pf_msg(adapter, VIRTCHNL_OP_GET_STATS,
- (u8 *)&vqs, sizeof(vqs)))
+ if (iavf_send_pf_msg(adapter, VIRTCHNL_OP_GET_STATS, (u8 *)&vqs,
+ sizeof(vqs)))
/* if the request failed, don't lock out others */
adapter->current_op = VIRTCHNL_OP_UNKNOWN;
}
/**
- * i40evf_get_hena
+ * iavf_get_hena
* @adapter: adapter structure
*
* Request hash enable capabilities from PF
**/
-void i40evf_get_hena(struct i40evf_adapter *adapter)
+void iavf_get_hena(struct iavf_adapter *adapter)
{
if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) {
/* bail because we already have a command pending */
@@ -766,18 +793,17 @@ void i40evf_get_hena(struct i40evf_adapter *adapter)
return;
}
adapter->current_op = VIRTCHNL_OP_GET_RSS_HENA_CAPS;
- adapter->aq_required &= ~I40EVF_FLAG_AQ_GET_HENA;
- i40evf_send_pf_msg(adapter, VIRTCHNL_OP_GET_RSS_HENA_CAPS,
- NULL, 0);
+ adapter->aq_required &= ~IAVF_FLAG_AQ_GET_HENA;
+ iavf_send_pf_msg(adapter, VIRTCHNL_OP_GET_RSS_HENA_CAPS, NULL, 0);
}
/**
- * i40evf_set_hena
+ * iavf_set_hena
* @adapter: adapter structure
*
* Request the PF to set our RSS hash capabilities
**/
-void i40evf_set_hena(struct i40evf_adapter *adapter)
+void iavf_set_hena(struct iavf_adapter *adapter)
{
struct virtchnl_rss_hena vrh;
@@ -789,18 +815,18 @@ void i40evf_set_hena(struct i40evf_adapter *adapter)
}
vrh.hena = adapter->hena;
adapter->current_op = VIRTCHNL_OP_SET_RSS_HENA;
- adapter->aq_required &= ~I40EVF_FLAG_AQ_SET_HENA;
- i40evf_send_pf_msg(adapter, VIRTCHNL_OP_SET_RSS_HENA,
- (u8 *)&vrh, sizeof(vrh));
+ adapter->aq_required &= ~IAVF_FLAG_AQ_SET_HENA;
+ iavf_send_pf_msg(adapter, VIRTCHNL_OP_SET_RSS_HENA, (u8 *)&vrh,
+ sizeof(vrh));
}
/**
- * i40evf_set_rss_key
+ * iavf_set_rss_key
* @adapter: adapter structure
*
* Request the PF to set our RSS hash key
**/
-void i40evf_set_rss_key(struct i40evf_adapter *adapter)
+void iavf_set_rss_key(struct iavf_adapter *adapter)
{
struct virtchnl_rss_key *vrk;
int len;
@@ -821,19 +847,18 @@ void i40evf_set_rss_key(struct i40evf_adapter *adapter)
memcpy(vrk->key, adapter->rss_key, adapter->rss_key_size);
adapter->current_op = VIRTCHNL_OP_CONFIG_RSS_KEY;
- adapter->aq_required &= ~I40EVF_FLAG_AQ_SET_RSS_KEY;
- i40evf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_RSS_KEY,
- (u8 *)vrk, len);
+ adapter->aq_required &= ~IAVF_FLAG_AQ_SET_RSS_KEY;
+ iavf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_RSS_KEY, (u8 *)vrk, len);
kfree(vrk);
}
/**
- * i40evf_set_rss_lut
+ * iavf_set_rss_lut
* @adapter: adapter structure
*
* Request the PF to set our RSS lookup table
**/
-void i40evf_set_rss_lut(struct i40evf_adapter *adapter)
+void iavf_set_rss_lut(struct iavf_adapter *adapter)
{
struct virtchnl_rss_lut *vrl;
int len;
@@ -853,19 +878,18 @@ void i40evf_set_rss_lut(struct i40evf_adapter *adapter)
vrl->lut_entries = adapter->rss_lut_size;
memcpy(vrl->lut, adapter->rss_lut, adapter->rss_lut_size);
adapter->current_op = VIRTCHNL_OP_CONFIG_RSS_LUT;
- adapter->aq_required &= ~I40EVF_FLAG_AQ_SET_RSS_LUT;
- i40evf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_RSS_LUT,
- (u8 *)vrl, len);
+ adapter->aq_required &= ~IAVF_FLAG_AQ_SET_RSS_LUT;
+ iavf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_RSS_LUT, (u8 *)vrl, len);
kfree(vrl);
}
/**
- * i40evf_enable_vlan_stripping
+ * iavf_enable_vlan_stripping
* @adapter: adapter structure
*
* Request VLAN header stripping to be enabled
**/
-void i40evf_enable_vlan_stripping(struct i40evf_adapter *adapter)
+void iavf_enable_vlan_stripping(struct iavf_adapter *adapter)
{
if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) {
/* bail because we already have a command pending */
@@ -874,18 +898,17 @@ void i40evf_enable_vlan_stripping(struct i40evf_adapter *adapter)
return;
}
adapter->current_op = VIRTCHNL_OP_ENABLE_VLAN_STRIPPING;
- adapter->aq_required &= ~I40EVF_FLAG_AQ_ENABLE_VLAN_STRIPPING;
- i40evf_send_pf_msg(adapter, VIRTCHNL_OP_ENABLE_VLAN_STRIPPING,
- NULL, 0);
+ adapter->aq_required &= ~IAVF_FLAG_AQ_ENABLE_VLAN_STRIPPING;
+ iavf_send_pf_msg(adapter, VIRTCHNL_OP_ENABLE_VLAN_STRIPPING, NULL, 0);
}
/**
- * i40evf_disable_vlan_stripping
+ * iavf_disable_vlan_stripping
* @adapter: adapter structure
*
* Request VLAN header stripping to be disabled
**/
-void i40evf_disable_vlan_stripping(struct i40evf_adapter *adapter)
+void iavf_disable_vlan_stripping(struct iavf_adapter *adapter)
{
if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) {
/* bail because we already have a command pending */
@@ -894,18 +917,17 @@ void i40evf_disable_vlan_stripping(struct i40evf_adapter *adapter)
return;
}
adapter->current_op = VIRTCHNL_OP_DISABLE_VLAN_STRIPPING;
- adapter->aq_required &= ~I40EVF_FLAG_AQ_DISABLE_VLAN_STRIPPING;
- i40evf_send_pf_msg(adapter, VIRTCHNL_OP_DISABLE_VLAN_STRIPPING,
- NULL, 0);
+ adapter->aq_required &= ~IAVF_FLAG_AQ_DISABLE_VLAN_STRIPPING;
+ iavf_send_pf_msg(adapter, VIRTCHNL_OP_DISABLE_VLAN_STRIPPING, NULL, 0);
}
/**
- * i40evf_print_link_message - print link up or down
+ * iavf_print_link_message - print link up or down
* @adapter: adapter structure
*
* Log a message telling the world of our wonderous link status
*/
-static void i40evf_print_link_message(struct i40evf_adapter *adapter)
+static void iavf_print_link_message(struct iavf_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
char *speed = "Unknown ";
@@ -942,13 +964,13 @@ static void i40evf_print_link_message(struct i40evf_adapter *adapter)
}
/**
- * i40evf_enable_channel
+ * iavf_enable_channel
* @adapter: adapter structure
*
* Request that the PF enable channels as specified by
* the user via tc tool.
**/
-void i40evf_enable_channels(struct i40evf_adapter *adapter)
+void iavf_enable_channels(struct iavf_adapter *adapter)
{
struct virtchnl_tc_info *vti = NULL;
u16 len;
@@ -976,22 +998,21 @@ void i40evf_enable_channels(struct i40evf_adapter *adapter)
adapter->ch_config.ch_info[i].max_tx_rate;
}
- adapter->ch_config.state = __I40EVF_TC_RUNNING;
- adapter->flags |= I40EVF_FLAG_REINIT_ITR_NEEDED;
+ adapter->ch_config.state = __IAVF_TC_RUNNING;
+ adapter->flags |= IAVF_FLAG_REINIT_ITR_NEEDED;
adapter->current_op = VIRTCHNL_OP_ENABLE_CHANNELS;
- adapter->aq_required &= ~I40EVF_FLAG_AQ_ENABLE_CHANNELS;
- i40evf_send_pf_msg(adapter, VIRTCHNL_OP_ENABLE_CHANNELS,
- (u8 *)vti, len);
+ adapter->aq_required &= ~IAVF_FLAG_AQ_ENABLE_CHANNELS;
+ iavf_send_pf_msg(adapter, VIRTCHNL_OP_ENABLE_CHANNELS, (u8 *)vti, len);
kfree(vti);
}
/**
- * i40evf_disable_channel
+ * iavf_disable_channel
* @adapter: adapter structure
*
* Request that the PF disable channels that are configured
**/
-void i40evf_disable_channels(struct i40evf_adapter *adapter)
+void iavf_disable_channels(struct iavf_adapter *adapter)
{
if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) {
/* bail because we already have a command pending */
@@ -1000,23 +1021,22 @@ void i40evf_disable_channels(struct i40evf_adapter *adapter)
return;
}
- adapter->ch_config.state = __I40EVF_TC_INVALID;
- adapter->flags |= I40EVF_FLAG_REINIT_ITR_NEEDED;
+ adapter->ch_config.state = __IAVF_TC_INVALID;
+ adapter->flags |= IAVF_FLAG_REINIT_ITR_NEEDED;
adapter->current_op = VIRTCHNL_OP_DISABLE_CHANNELS;
- adapter->aq_required &= ~I40EVF_FLAG_AQ_DISABLE_CHANNELS;
- i40evf_send_pf_msg(adapter, VIRTCHNL_OP_DISABLE_CHANNELS,
- NULL, 0);
+ adapter->aq_required &= ~IAVF_FLAG_AQ_DISABLE_CHANNELS;
+ iavf_send_pf_msg(adapter, VIRTCHNL_OP_DISABLE_CHANNELS, NULL, 0);
}
/**
- * i40evf_print_cloud_filter
+ * iavf_print_cloud_filter
* @adapter: adapter structure
* @f: cloud filter to print
*
* Print the cloud filter
**/
-static void i40evf_print_cloud_filter(struct i40evf_adapter *adapter,
- struct virtchnl_filter *f)
+static void iavf_print_cloud_filter(struct iavf_adapter *adapter,
+ struct virtchnl_filter *f)
{
switch (f->flow_type) {
case VIRTCHNL_TCP_V4_FLOW:
@@ -1043,15 +1063,15 @@ static void i40evf_print_cloud_filter(struct i40evf_adapter *adapter,
}
/**
- * i40evf_add_cloud_filter
+ * iavf_add_cloud_filter
* @adapter: adapter structure
*
* Request that the PF add cloud filters as specified
* by the user via tc tool.
**/
-void i40evf_add_cloud_filter(struct i40evf_adapter *adapter)
+void iavf_add_cloud_filter(struct iavf_adapter *adapter)
{
- struct i40evf_cloud_filter *cf;
+ struct iavf_cloud_filter *cf;
struct virtchnl_filter *f;
int len = 0, count = 0;
@@ -1068,7 +1088,7 @@ void i40evf_add_cloud_filter(struct i40evf_adapter *adapter)
}
}
if (!count) {
- adapter->aq_required &= ~I40EVF_FLAG_AQ_ADD_CLOUD_FILTER;
+ adapter->aq_required &= ~IAVF_FLAG_AQ_ADD_CLOUD_FILTER;
return;
}
adapter->current_op = VIRTCHNL_OP_ADD_CLOUD_FILTER;
@@ -1082,25 +1102,24 @@ void i40evf_add_cloud_filter(struct i40evf_adapter *adapter)
if (cf->add) {
memcpy(f, &cf->f, sizeof(struct virtchnl_filter));
cf->add = false;
- cf->state = __I40EVF_CF_ADD_PENDING;
- i40evf_send_pf_msg(adapter,
- VIRTCHNL_OP_ADD_CLOUD_FILTER,
- (u8 *)f, len);
+ cf->state = __IAVF_CF_ADD_PENDING;
+ iavf_send_pf_msg(adapter, VIRTCHNL_OP_ADD_CLOUD_FILTER,
+ (u8 *)f, len);
}
}
kfree(f);
}
/**
- * i40evf_del_cloud_filter
+ * iavf_del_cloud_filter
* @adapter: adapter structure
*
* Request that the PF delete cloud filters as specified
* by the user via tc tool.
**/
-void i40evf_del_cloud_filter(struct i40evf_adapter *adapter)
+void iavf_del_cloud_filter(struct iavf_adapter *adapter)
{
- struct i40evf_cloud_filter *cf, *cftmp;
+ struct iavf_cloud_filter *cf, *cftmp;
struct virtchnl_filter *f;
int len = 0, count = 0;
@@ -1117,7 +1136,7 @@ void i40evf_del_cloud_filter(struct i40evf_adapter *adapter)
}
}
if (!count) {
- adapter->aq_required &= ~I40EVF_FLAG_AQ_DEL_CLOUD_FILTER;
+ adapter->aq_required &= ~IAVF_FLAG_AQ_DEL_CLOUD_FILTER;
return;
}
adapter->current_op = VIRTCHNL_OP_DEL_CLOUD_FILTER;
@@ -1131,30 +1150,29 @@ void i40evf_del_cloud_filter(struct i40evf_adapter *adapter)
if (cf->del) {
memcpy(f, &cf->f, sizeof(struct virtchnl_filter));
cf->del = false;
- cf->state = __I40EVF_CF_DEL_PENDING;
- i40evf_send_pf_msg(adapter,
- VIRTCHNL_OP_DEL_CLOUD_FILTER,
- (u8 *)f, len);
+ cf->state = __IAVF_CF_DEL_PENDING;
+ iavf_send_pf_msg(adapter, VIRTCHNL_OP_DEL_CLOUD_FILTER,
+ (u8 *)f, len);
}
}
kfree(f);
}
/**
- * i40evf_request_reset
+ * iavf_request_reset
* @adapter: adapter structure
*
* Request that the PF reset this VF. No response is expected.
**/
-void i40evf_request_reset(struct i40evf_adapter *adapter)
+void iavf_request_reset(struct iavf_adapter *adapter)
{
/* Don't check CURRENT_OP - this is always higher priority */
- i40evf_send_pf_msg(adapter, VIRTCHNL_OP_RESET_VF, NULL, 0);
+ iavf_send_pf_msg(adapter, VIRTCHNL_OP_RESET_VF, NULL, 0);
adapter->current_op = VIRTCHNL_OP_UNKNOWN;
}
/**
- * i40evf_virtchnl_completion
+ * iavf_virtchnl_completion
* @adapter: adapter structure
* @v_opcode: opcode sent by PF
* @v_retval: retval sent by PF
@@ -1165,10 +1183,9 @@ void i40evf_request_reset(struct i40evf_adapter *adapter)
* wait, we fire off our requests and assume that no errors will be returned.
* This function handles the reply messages.
**/
-void i40evf_virtchnl_completion(struct i40evf_adapter *adapter,
- enum virtchnl_ops v_opcode,
- i40e_status v_retval,
- u8 *msg, u16 msglen)
+void iavf_virtchnl_completion(struct iavf_adapter *adapter,
+ enum virtchnl_ops v_opcode, iavf_status v_retval,
+ u8 *msg, u16 msglen)
{
struct net_device *netdev = adapter->netdev;
@@ -1176,6 +1193,7 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter,
struct virtchnl_pf_event *vpe =
(struct virtchnl_pf_event *)msg;
bool link_up = vpe->event_data.link_event.link_status;
+
switch (vpe->event) {
case VIRTCHNL_EVENT_LINK_CHANGE:
adapter->link_speed =
@@ -1193,7 +1211,7 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter,
* after we enable queues and actually prepared
* to send traffic.
*/
- if (adapter->state != __I40EVF_RUNNING)
+ if (adapter->state != __IAVF_RUNNING)
break;
/* For ADq enabled VF, we reconfigure VSIs and
@@ -1201,7 +1219,7 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter,
* queues are enabled.
*/
if (adapter->flags &
- I40EVF_FLAG_QUEUES_DISABLED)
+ IAVF_FLAG_QUEUES_DISABLED)
break;
}
@@ -1213,12 +1231,12 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter,
netif_tx_stop_all_queues(netdev);
netif_carrier_off(netdev);
}
- i40evf_print_link_message(adapter);
+ iavf_print_link_message(adapter);
break;
case VIRTCHNL_EVENT_RESET_IMPENDING:
dev_info(&adapter->pdev->dev, "Reset warning received from the PF\n");
- if (!(adapter->flags & I40EVF_FLAG_RESET_PENDING)) {
- adapter->flags |= I40EVF_FLAG_RESET_PENDING;
+ if (!(adapter->flags & IAVF_FLAG_RESET_PENDING)) {
+ adapter->flags |= IAVF_FLAG_RESET_PENDING;
dev_info(&adapter->pdev->dev, "Scheduling reset task\n");
schedule_work(&adapter->reset_task);
}
@@ -1234,48 +1252,48 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter,
switch (v_opcode) {
case VIRTCHNL_OP_ADD_VLAN:
dev_err(&adapter->pdev->dev, "Failed to add VLAN filter, error %s\n",
- i40evf_stat_str(&adapter->hw, v_retval));
+ iavf_stat_str(&adapter->hw, v_retval));
break;
case VIRTCHNL_OP_ADD_ETH_ADDR:
dev_err(&adapter->pdev->dev, "Failed to add MAC filter, error %s\n",
- i40evf_stat_str(&adapter->hw, v_retval));
+ iavf_stat_str(&adapter->hw, v_retval));
break;
case VIRTCHNL_OP_DEL_VLAN:
dev_err(&adapter->pdev->dev, "Failed to delete VLAN filter, error %s\n",
- i40evf_stat_str(&adapter->hw, v_retval));
+ iavf_stat_str(&adapter->hw, v_retval));
break;
case VIRTCHNL_OP_DEL_ETH_ADDR:
dev_err(&adapter->pdev->dev, "Failed to delete MAC filter, error %s\n",
- i40evf_stat_str(&adapter->hw, v_retval));
+ iavf_stat_str(&adapter->hw, v_retval));
break;
case VIRTCHNL_OP_ENABLE_CHANNELS:
dev_err(&adapter->pdev->dev, "Failed to configure queue channels, error %s\n",
- i40evf_stat_str(&adapter->hw, v_retval));
- adapter->flags &= ~I40EVF_FLAG_REINIT_ITR_NEEDED;
- adapter->ch_config.state = __I40EVF_TC_INVALID;
+ iavf_stat_str(&adapter->hw, v_retval));
+ adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED;
+ adapter->ch_config.state = __IAVF_TC_INVALID;
netdev_reset_tc(netdev);
netif_tx_start_all_queues(netdev);
break;
case VIRTCHNL_OP_DISABLE_CHANNELS:
dev_err(&adapter->pdev->dev, "Failed to disable queue channels, error %s\n",
- i40evf_stat_str(&adapter->hw, v_retval));
- adapter->flags &= ~I40EVF_FLAG_REINIT_ITR_NEEDED;
- adapter->ch_config.state = __I40EVF_TC_RUNNING;
+ iavf_stat_str(&adapter->hw, v_retval));
+ adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED;
+ adapter->ch_config.state = __IAVF_TC_RUNNING;
netif_tx_start_all_queues(netdev);
break;
case VIRTCHNL_OP_ADD_CLOUD_FILTER: {
- struct i40evf_cloud_filter *cf, *cftmp;
+ struct iavf_cloud_filter *cf, *cftmp;
list_for_each_entry_safe(cf, cftmp,
&adapter->cloud_filter_list,
list) {
- if (cf->state == __I40EVF_CF_ADD_PENDING) {
- cf->state = __I40EVF_CF_INVALID;
+ if (cf->state == __IAVF_CF_ADD_PENDING) {
+ cf->state = __IAVF_CF_INVALID;
dev_info(&adapter->pdev->dev, "Failed to add cloud filter, error %s\n",
- i40evf_stat_str(&adapter->hw,
- v_retval));
- i40evf_print_cloud_filter(adapter,
- &cf->f);
+ iavf_stat_str(&adapter->hw,
+ v_retval));
+ iavf_print_cloud_filter(adapter,
+ &cf->f);
list_del(&cf->list);
kfree(cf);
adapter->num_cloud_filters--;
@@ -1284,32 +1302,31 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter,
}
break;
case VIRTCHNL_OP_DEL_CLOUD_FILTER: {
- struct i40evf_cloud_filter *cf;
+ struct iavf_cloud_filter *cf;
list_for_each_entry(cf, &adapter->cloud_filter_list,
list) {
- if (cf->state == __I40EVF_CF_DEL_PENDING) {
- cf->state = __I40EVF_CF_ACTIVE;
+ if (cf->state == __IAVF_CF_DEL_PENDING) {
+ cf->state = __IAVF_CF_ACTIVE;
dev_info(&adapter->pdev->dev, "Failed to del cloud filter, error %s\n",
- i40evf_stat_str(&adapter->hw,
- v_retval));
- i40evf_print_cloud_filter(adapter,
- &cf->f);
+ iavf_stat_str(&adapter->hw,
+ v_retval));
+ iavf_print_cloud_filter(adapter,
+ &cf->f);
}
}
}
break;
default:
dev_err(&adapter->pdev->dev, "PF returned error %d (%s) to our request %d\n",
- v_retval,
- i40evf_stat_str(&adapter->hw, v_retval),
+ v_retval, iavf_stat_str(&adapter->hw, v_retval),
v_opcode);
}
}
switch (v_opcode) {
case VIRTCHNL_OP_GET_STATS: {
- struct i40e_eth_stats *stats =
- (struct i40e_eth_stats *)msg;
+ struct iavf_eth_stats *stats =
+ (struct iavf_eth_stats *)msg;
netdev->stats.rx_packets = stats->rx_unicast +
stats->rx_multicast +
stats->rx_broadcast;
@@ -1326,25 +1343,33 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter,
break;
case VIRTCHNL_OP_GET_VF_RESOURCES: {
u16 len = sizeof(struct virtchnl_vf_resource) +
- I40E_MAX_VF_VSI *
+ IAVF_MAX_VF_VSI *
sizeof(struct virtchnl_vsi_resource);
memcpy(adapter->vf_res, msg, min(msglen, len));
- i40e_vf_parse_hw_config(&adapter->hw, adapter->vf_res);
- /* restore current mac address */
- ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr);
- i40evf_process_config(adapter);
+ iavf_validate_num_queues(adapter);
+ iavf_vf_parse_hw_config(&adapter->hw, adapter->vf_res);
+ if (is_zero_ether_addr(adapter->hw.mac.addr)) {
+ /* restore current mac address */
+ ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr);
+ } else {
+ /* refresh current mac address if changed */
+ ether_addr_copy(netdev->dev_addr, adapter->hw.mac.addr);
+ ether_addr_copy(netdev->perm_addr,
+ adapter->hw.mac.addr);
+ }
+ iavf_process_config(adapter);
}
break;
case VIRTCHNL_OP_ENABLE_QUEUES:
/* enable transmits */
- i40evf_irq_enable(adapter, true);
- adapter->flags &= ~I40EVF_FLAG_QUEUES_DISABLED;
+ iavf_irq_enable(adapter, true);
+ adapter->flags &= ~IAVF_FLAG_QUEUES_DISABLED;
break;
case VIRTCHNL_OP_DISABLE_QUEUES:
- i40evf_free_all_tx_resources(adapter);
- i40evf_free_all_rx_resources(adapter);
- if (adapter->state == __I40EVF_DOWN_PENDING) {
- adapter->state = __I40EVF_DOWN;
+ iavf_free_all_tx_resources(adapter);
+ iavf_free_all_rx_resources(adapter);
+ if (adapter->state == __IAVF_DOWN_PENDING) {
+ adapter->state = __IAVF_DOWN;
wake_up(&adapter->down_waitqueue);
}
break;
@@ -1363,8 +1388,7 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter,
* care about that.
*/
if (msglen && CLIENT_ENABLED(adapter))
- i40evf_notify_client_message(&adapter->vsi,
- msg, msglen);
+ iavf_notify_client_message(&adapter->vsi, msg, msglen);
break;
case VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP:
@@ -1373,6 +1397,7 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter,
break;
case VIRTCHNL_OP_GET_RSS_HENA_CAPS: {
struct virtchnl_rss_hena *vrh = (struct virtchnl_rss_hena *)msg;
+
if (msglen == sizeof(*vrh))
adapter->hena = vrh->hena;
else
@@ -1383,32 +1408,33 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter,
case VIRTCHNL_OP_REQUEST_QUEUES: {
struct virtchnl_vf_res_request *vfres =
(struct virtchnl_vf_res_request *)msg;
+
if (vfres->num_queue_pairs != adapter->num_req_queues) {
dev_info(&adapter->pdev->dev,
"Requested %d queues, PF can support %d\n",
adapter->num_req_queues,
vfres->num_queue_pairs);
adapter->num_req_queues = 0;
- adapter->flags &= ~I40EVF_FLAG_REINIT_ITR_NEEDED;
+ adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED;
}
}
break;
case VIRTCHNL_OP_ADD_CLOUD_FILTER: {
- struct i40evf_cloud_filter *cf;
+ struct iavf_cloud_filter *cf;
list_for_each_entry(cf, &adapter->cloud_filter_list, list) {
- if (cf->state == __I40EVF_CF_ADD_PENDING)
- cf->state = __I40EVF_CF_ACTIVE;
+ if (cf->state == __IAVF_CF_ADD_PENDING)
+ cf->state = __IAVF_CF_ACTIVE;
}
}
break;
case VIRTCHNL_OP_DEL_CLOUD_FILTER: {
- struct i40evf_cloud_filter *cf, *cftmp;
+ struct iavf_cloud_filter *cf, *cftmp;
list_for_each_entry_safe(cf, cftmp, &adapter->cloud_filter_list,
list) {
- if (cf->state == __I40EVF_CF_DEL_PENDING) {
- cf->state = __I40EVF_CF_INVALID;
+ if (cf->state == __IAVF_CF_DEL_PENDING) {
+ cf->state = __IAVF_CF_INVALID;
list_del(&cf->list);
kfree(cf);
adapter->num_cloud_filters--;
diff --git a/drivers/net/ethernet/intel/ice/Makefile b/drivers/net/ethernet/intel/ice/Makefile
index 4058673fd853..e5d6f684437e 100644
--- a/drivers/net/ethernet/intel/ice/Makefile
+++ b/drivers/net/ethernet/intel/ice/Makefile
@@ -13,5 +13,7 @@ ice-y := ice_main.o \
ice_nvm.o \
ice_switch.o \
ice_sched.o \
+ ice_lib.o \
ice_txrx.o \
ice_ethtool.o
+ice-$(CONFIG_PCI_IOV) += ice_virtchnl_pf.o ice_sriov.o
diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h
index 868f4a1d0f72..b8548370f1c7 100644
--- a/drivers/net/ethernet/intel/ice/ice.h
+++ b/drivers/net/ethernet/intel/ice/ice.h
@@ -28,6 +28,7 @@
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/if_bridge.h>
+#include <linux/avf/virtchnl.h>
#include <net/ipv6.h>
#include "ice_devids.h"
#include "ice_type.h"
@@ -35,17 +36,20 @@
#include "ice_switch.h"
#include "ice_common.h"
#include "ice_sched.h"
+#include "ice_virtchnl_pf.h"
+#include "ice_sriov.h"
extern const char ice_drv_ver[];
#define ICE_BAR0 0
#define ICE_DFLT_NUM_DESC 128
-#define ICE_MIN_NUM_DESC 8
-#define ICE_MAX_NUM_DESC 8160
#define ICE_REQ_DESC_MULTIPLE 32
+#define ICE_MIN_NUM_DESC ICE_REQ_DESC_MULTIPLE
+#define ICE_MAX_NUM_DESC 8160
#define ICE_DFLT_TRAFFIC_CLASS BIT(0)
#define ICE_INT_NAME_STR_LEN (IFNAMSIZ + 16)
#define ICE_ETHTOOL_FWVER_LEN 32
#define ICE_AQ_LEN 64
+#define ICE_MBXQ_LEN 64
#define ICE_MIN_MSIX 2
#define ICE_NO_VSI 0xffff
#define ICE_MAX_VSI_ALLOC 130
@@ -62,6 +66,17 @@ extern const char ice_drv_ver[];
#define ICE_RES_VALID_BIT 0x8000
#define ICE_RES_MISC_VEC_ID (ICE_RES_VALID_BIT - 1)
#define ICE_INVAL_Q_INDEX 0xffff
+#define ICE_INVAL_VFID 256
+#define ICE_MAX_VF_COUNT 256
+#define ICE_MAX_QS_PER_VF 256
+#define ICE_MIN_QS_PER_VF 1
+#define ICE_DFLT_QS_PER_VF 4
+#define ICE_MAX_BASE_QS_PER_VF 16
+#define ICE_MAX_INTR_PER_VF 65
+#define ICE_MIN_INTR_PER_VF (ICE_MIN_QS_PER_VF + 1)
+#define ICE_DFLT_INTR_PER_VF (ICE_DFLT_QS_PER_VF + 1)
+
+#define ICE_MAX_RESET_WAIT 20
#define ICE_VSIQF_HKEY_ARRAY_SIZE ((VSIQF_HKEY_MAX_INDEX + 1) * 4)
@@ -122,7 +137,8 @@ struct ice_sw {
enum ice_state {
__ICE_DOWN,
__ICE_NEEDS_RESTART,
- __ICE_RESET_RECOVERY_PENDING, /* set by driver when reset starts */
+ __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 */
@@ -131,10 +147,24 @@ enum ice_state {
__ICE_EMPR_RECV, /* set by OICR handler */
__ICE_SUSPENDED, /* set on module remove path */
__ICE_RESET_FAILED, /* set by reset/rebuild */
+ /* When checking for the PF to be in a nominal operating state, the
+ * bits that are grouped at the beginning of the list need to be
+ * checked. Bits occurring before __ICE_STATE_NOMINAL_CHECK_BITS will
+ * be checked. If you need to add a bit into consideration for nominal
+ * operating state, it must be added before
+ * __ICE_STATE_NOMINAL_CHECK_BITS. Do not move this entry's position
+ * without appropriate consideration.
+ */
+ __ICE_STATE_NOMINAL_CHECK_BITS,
__ICE_ADMINQ_EVENT_PENDING,
+ __ICE_MAILBOXQ_EVENT_PENDING,
+ __ICE_MDD_EVENT_PENDING,
+ __ICE_VFLR_EVENT_PENDING,
__ICE_FLTR_OVERFLOW_PROMISC,
+ __ICE_VF_DIS,
__ICE_CFG_BUSY,
__ICE_SERVICE_SCHED,
+ __ICE_SERVICE_DIS,
__ICE_STATE_NBITS /* must be last */
};
@@ -161,14 +191,14 @@ struct ice_vsi {
u64 tx_linearize;
DECLARE_BITMAP(state, __ICE_STATE_NBITS);
DECLARE_BITMAP(flags, ICE_VSI_FLAG_NBITS);
- unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
unsigned int current_netdev_flags;
u32 tx_restart;
u32 tx_busy;
u32 rx_buf_failed;
u32 rx_page_failed;
int num_q_vectors;
- int base_vector;
+ int sw_base_vector; /* Irq base for OS reserved vectors */
+ int hw_base_vector; /* HW (absolute) index of a vector */
enum ice_vsi_type type;
u16 vsi_num; /* HW (absolute) index of this VSI */
u16 idx; /* software index in pf->vsi[] */
@@ -176,6 +206,8 @@ struct ice_vsi {
/* Interrupt thresholds */
u16 work_lmt;
+ s16 vf_id; /* VF ID for SR-IOV VSIs */
+
/* RSS config */
u16 rss_table_size; /* HW RSS table size */
u16 rss_size; /* Allocated RSS queues */
@@ -225,21 +257,39 @@ struct ice_q_vector {
u8 num_ring_tx; /* total number of tx rings in vector */
u8 num_ring_rx; /* total number of rx rings in vector */
char name[ICE_INT_NAME_STR_LEN];
+ /* in usecs, need to use ice_intrl_to_usecs_reg() before writing this
+ * value to the device
+ */
+ u8 intrl;
} ____cacheline_internodealigned_in_smp;
enum ice_pf_flags {
ICE_FLAG_MSIX_ENA,
ICE_FLAG_FLTR_SYNC,
ICE_FLAG_RSS_ENA,
+ ICE_FLAG_SRIOV_ENA,
+ ICE_FLAG_SRIOV_CAPABLE,
ICE_PF_FLAGS_NBITS /* must be last */
};
struct ice_pf {
struct pci_dev *pdev;
+
+ /* OS reserved IRQ details */
struct msix_entry *msix_entries;
- struct ice_res_tracker *irq_tracker;
+ struct ice_res_tracker *sw_irq_tracker;
+
+ /* HW reserved Interrupts for this PF */
+ struct ice_res_tracker *hw_irq_tracker;
+
struct ice_vsi **vsi; /* VSIs created by the driver */
struct ice_sw *first_sw; /* first switch created by firmware */
+ /* Virtchnl/SR-IOV config info */
+ struct ice_vf *vf;
+ int num_alloc_vfs; /* actual number of VFs allocated */
+ u16 num_vfs_supported; /* num VFs supported for this PF */
+ u16 num_vf_qps; /* num queue pairs per VF */
+ u16 num_vf_msix; /* num vectors per VF */
DECLARE_BITMAP(state, __ICE_STATE_NBITS);
DECLARE_BITMAP(avail_txqs, ICE_MAX_TXQS);
DECLARE_BITMAP(avail_rxqs, ICE_MAX_RXQS);
@@ -252,9 +302,11 @@ struct ice_pf {
struct mutex sw_mutex; /* lock for protecting VSI alloc flow */
u32 msg_enable;
u32 hw_csum_rx_error;
- u32 oicr_idx; /* Other interrupt cause vector index */
+ u32 sw_oicr_idx; /* Other interrupt cause SW vector index */
+ u32 num_avail_sw_msix; /* remaining MSIX SW vectors left unclaimed */
+ u32 hw_oicr_idx; /* Other interrupt cause vector HW index */
+ u32 num_avail_hw_msix; /* remaining HW MSIX vectors left unclaimed */
u32 num_lan_msix; /* Total MSIX vectors for base driver */
- u32 num_avail_msix; /* remaining MSIX vectors left unclaimed */
u16 num_lan_tx; /* num lan tx queues setup */
u16 num_lan_rx; /* num lan rx queues setup */
u16 q_left_tx; /* remaining num tx queues left unclaimed */
@@ -270,6 +322,9 @@ struct ice_pf {
struct ice_hw_port_stats stats_prev;
struct ice_hw hw;
u8 stat_prev_loaded; /* has previous stats been loaded */
+ u32 tx_timeout_count;
+ unsigned long tx_timeout_last_recovery;
+ u32 tx_timeout_recovery_level;
char int_name[ICE_INT_NAME_STR_LEN];
};
@@ -286,8 +341,8 @@ struct ice_netdev_priv {
static inline void ice_irq_dynamic_ena(struct ice_hw *hw, struct ice_vsi *vsi,
struct ice_q_vector *q_vector)
{
- u32 vector = (vsi && q_vector) ? vsi->base_vector + q_vector->v_idx :
- ((struct ice_pf *)hw->back)->oicr_idx;
+ u32 vector = (vsi && q_vector) ? vsi->hw_base_vector + q_vector->v_idx :
+ ((struct ice_pf *)hw->back)->hw_oicr_idx;
int itr = ICE_ITR_NONE;
u32 val;
@@ -315,5 +370,6 @@ int ice_set_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size);
int ice_get_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size);
void ice_fill_rss_lut(u8 *lut, u16 rss_table_size, u16 rss_size);
void ice_print_link_msg(struct ice_vsi *vsi, bool isup);
+void ice_napi_del(struct ice_vsi *vsi);
#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 a0614f472658..6653555f55dd 100644
--- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
+++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
@@ -87,6 +87,8 @@ struct ice_aqc_list_caps {
/* Device/Function buffer entry, repeated per reported capability */
struct ice_aqc_list_caps_elem {
__le16 cap;
+#define ICE_AQC_CAPS_SRIOV 0x0012
+#define ICE_AQC_CAPS_VF 0x0013
#define ICE_AQC_CAPS_VSI 0x0017
#define ICE_AQC_CAPS_RSS 0x0040
#define ICE_AQC_CAPS_RXQS 0x0041
@@ -443,6 +445,8 @@ struct ice_aqc_vsi_props {
u8 reserved[24];
};
+#define ICE_MAX_NUM_RECIPES 64
+
/* Add/Update/Remove/Get switch rules (indirect 0x02A0, 0x02A1, 0x02A2, 0x02A3)
*/
struct ice_aqc_sw_rules {
@@ -734,6 +738,10 @@ struct ice_aqc_add_elem {
struct ice_aqc_txsched_elem_data generic[1];
};
+struct ice_aqc_get_elem {
+ struct ice_aqc_txsched_elem_data generic[1];
+};
+
struct ice_aqc_get_topo_elem {
struct ice_aqc_txsched_topo_grp_info_hdr hdr;
struct ice_aqc_txsched_elem_data
@@ -771,9 +779,8 @@ struct ice_aqc_layer_props {
u8 chunk_size;
__le16 max_device_nodes;
__le16 max_pf_nodes;
- u8 rsvd0[2];
- __le16 max_shared_rate_lmtr;
- __le16 max_children;
+ u8 rsvd0[4];
+ __le16 max_sibl_grp_sz;
__le16 max_cir_rl_profiles;
__le16 max_eir_rl_profiles;
__le16 max_srl_profiles;
@@ -919,9 +926,11 @@ struct ice_aqc_set_phy_cfg_data {
u8 caps;
#define ICE_AQ_PHY_ENA_TX_PAUSE_ABILITY BIT(0)
#define ICE_AQ_PHY_ENA_RX_PAUSE_ABILITY BIT(1)
-#define ICE_AQ_PHY_ENA_LOW_POWER BIT(2)
-#define ICE_AQ_PHY_ENA_LINK BIT(3)
-#define ICE_AQ_PHY_ENA_ATOMIC_LINK BIT(5)
+#define ICE_AQ_PHY_ENA_LOW_POWER BIT(2)
+#define ICE_AQ_PHY_ENA_LINK BIT(3)
+#define ICE_AQ_PHY_ENA_AUTO_LINK_UPDT BIT(5)
+#define ICE_AQ_PHY_ENA_LESM BIT(6)
+#define ICE_AQ_PHY_ENA_AUTO_FEC BIT(7)
u8 low_power_ctrl;
__le16 eee_cap; /* Value from ice_aqc_get_phy_caps */
__le16 eeer_value;
@@ -1068,6 +1077,19 @@ struct ice_aqc_nvm {
__le32 addr_low;
};
+/**
+ * Send to PF command (indirect 0x0801) id is only used by PF
+ *
+ * Send to VF command (indirect 0x0802) id is only used by PF
+ *
+ */
+struct ice_aqc_pf_vf_msg {
+ __le32 id;
+ u32 reserved;
+ __le32 addr_high;
+ __le32 addr_low;
+};
+
/* Get/Set RSS key (indirect 0x0B04/0x0B02) */
struct ice_aqc_get_set_rss_key {
#define ICE_AQC_GSET_RSS_KEY_VSI_VALID BIT(15)
@@ -1203,6 +1225,84 @@ struct ice_aqc_dis_txq {
struct ice_aqc_dis_txq_item qgrps[1];
};
+/* Configure Firmware Logging Command (indirect 0xFF09)
+ * Logging Information Read Response (indirect 0xFF10)
+ * Note: The 0xFF10 command has no input parameters.
+ */
+struct ice_aqc_fw_logging {
+ u8 log_ctrl;
+#define ICE_AQC_FW_LOG_AQ_EN BIT(0)
+#define ICE_AQC_FW_LOG_UART_EN BIT(1)
+ u8 rsvd0;
+ u8 log_ctrl_valid; /* Not used by 0xFF10 Response */
+#define ICE_AQC_FW_LOG_AQ_VALID BIT(0)
+#define ICE_AQC_FW_LOG_UART_VALID BIT(1)
+ u8 rsvd1[5];
+ __le32 addr_high;
+ __le32 addr_low;
+};
+
+enum ice_aqc_fw_logging_mod {
+ ICE_AQC_FW_LOG_ID_GENERAL = 0,
+ ICE_AQC_FW_LOG_ID_CTRL,
+ ICE_AQC_FW_LOG_ID_LINK,
+ ICE_AQC_FW_LOG_ID_LINK_TOPO,
+ ICE_AQC_FW_LOG_ID_DNL,
+ ICE_AQC_FW_LOG_ID_I2C,
+ ICE_AQC_FW_LOG_ID_SDP,
+ ICE_AQC_FW_LOG_ID_MDIO,
+ ICE_AQC_FW_LOG_ID_ADMINQ,
+ ICE_AQC_FW_LOG_ID_HDMA,
+ ICE_AQC_FW_LOG_ID_LLDP,
+ ICE_AQC_FW_LOG_ID_DCBX,
+ ICE_AQC_FW_LOG_ID_DCB,
+ ICE_AQC_FW_LOG_ID_NETPROXY,
+ ICE_AQC_FW_LOG_ID_NVM,
+ ICE_AQC_FW_LOG_ID_AUTH,
+ ICE_AQC_FW_LOG_ID_VPD,
+ ICE_AQC_FW_LOG_ID_IOSF,
+ ICE_AQC_FW_LOG_ID_PARSER,
+ ICE_AQC_FW_LOG_ID_SW,
+ ICE_AQC_FW_LOG_ID_SCHEDULER,
+ ICE_AQC_FW_LOG_ID_TXQ,
+ ICE_AQC_FW_LOG_ID_RSVD,
+ ICE_AQC_FW_LOG_ID_POST,
+ ICE_AQC_FW_LOG_ID_WATCHDOG,
+ ICE_AQC_FW_LOG_ID_TASK_DISPATCH,
+ ICE_AQC_FW_LOG_ID_MNG,
+ ICE_AQC_FW_LOG_ID_MAX,
+};
+
+/* This is the buffer for both of the logging commands.
+ * The entry array size depends on the datalen parameter in the descriptor.
+ * There will be a total of datalen / 2 entries.
+ */
+struct ice_aqc_fw_logging_data {
+ __le16 entry[1];
+#define ICE_AQC_FW_LOG_ID_S 0
+#define ICE_AQC_FW_LOG_ID_M (0xFFF << ICE_AQC_FW_LOG_ID_S)
+
+#define ICE_AQC_FW_LOG_CONF_SUCCESS 0 /* Used by response */
+#define ICE_AQC_FW_LOG_CONF_BAD_INDX BIT(12) /* Used by response */
+
+#define ICE_AQC_FW_LOG_EN_S 12
+#define ICE_AQC_FW_LOG_EN_M (0xF << ICE_AQC_FW_LOG_EN_S)
+#define ICE_AQC_FW_LOG_INFO_EN BIT(12) /* Used by command */
+#define ICE_AQC_FW_LOG_INIT_EN BIT(13) /* Used by command */
+#define ICE_AQC_FW_LOG_FLOW_EN BIT(14) /* Used by command */
+#define ICE_AQC_FW_LOG_ERR_EN BIT(15) /* Used by command */
+};
+
+/* Get/Clear FW Log (indirect 0xFF11) */
+struct ice_aqc_get_clear_fw_log {
+ u8 flags;
+#define ICE_AQC_FW_LOG_CLEAR BIT(0)
+#define ICE_AQC_FW_LOG_MORE_DATA_AVAIL BIT(1)
+ u8 rsvd1[7];
+ __le32 addr_high;
+ __le32 addr_low;
+};
+
/**
* struct ice_aq_desc - Admin Queue (AQ) descriptor
* @flags: ICE_AQ_FLAG_* flags
@@ -1247,11 +1347,15 @@ struct ice_aq_desc {
struct ice_aqc_query_txsched_res query_sched_res;
struct ice_aqc_add_move_delete_elem add_move_delete_elem;
struct ice_aqc_nvm nvm;
+ struct ice_aqc_pf_vf_msg virt;
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_add_txqs add_txqs;
struct ice_aqc_dis_txqs dis_txqs;
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_alloc_free_res_cmd sw_res_ctrl;
struct ice_aqc_set_event_mask set_event_mask;
struct ice_aqc_get_link_status get_link_status;
@@ -1325,6 +1429,7 @@ enum ice_adminq_opc {
/* transmit scheduler commands */
ice_aqc_opc_get_dflt_topo = 0x0400,
ice_aqc_opc_add_sched_elems = 0x0401,
+ ice_aqc_opc_get_sched_elems = 0x0404,
ice_aqc_opc_suspend_sched_elems = 0x0409,
ice_aqc_opc_resume_sched_elems = 0x040A,
ice_aqc_opc_delete_sched_elems = 0x040F,
@@ -1340,6 +1445,10 @@ enum ice_adminq_opc {
/* NVM commands */
ice_aqc_opc_nvm_read = 0x0701,
+ /* PF/VF mailbox commands */
+ ice_mbx_opc_send_msg_to_pf = 0x0801,
+ ice_mbx_opc_send_msg_to_vf = 0x0802,
+
/* RSS commands */
ice_aqc_opc_set_rss_key = 0x0B02,
ice_aqc_opc_set_rss_lut = 0x0B03,
@@ -1349,6 +1458,9 @@ enum ice_adminq_opc {
/* TX queue handling commands/events */
ice_aqc_opc_add_txqs = 0x0C30,
ice_aqc_opc_dis_txqs = 0x0C31,
+
+ /* debug commands */
+ ice_aqc_opc_fw_logging = 0xFF09,
};
#endif /* _ICE_ADMINQ_CMD_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c
index 661beea6af79..554fd707a6d6 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.c
+++ b/drivers/net/ethernet/intel/ice/ice_common.c
@@ -7,16 +7,16 @@
#define ICE_PF_RESET_WAIT_COUNT 200
-#define ICE_NIC_FLX_ENTRY(hw, mdid, idx) \
- wr32((hw), GLFLXP_RXDID_FLX_WRD_##idx(ICE_RXDID_FLEX_NIC), \
+#define ICE_PROG_FLEX_ENTRY(hw, rxdid, mdid, idx) \
+ wr32((hw), GLFLXP_RXDID_FLX_WRD_##idx(rxdid), \
((ICE_RX_OPC_MDID << \
GLFLXP_RXDID_FLX_WRD_##idx##_RXDID_OPCODE_S) & \
GLFLXP_RXDID_FLX_WRD_##idx##_RXDID_OPCODE_M) | \
(((mdid) << GLFLXP_RXDID_FLX_WRD_##idx##_PROT_MDID_S) & \
GLFLXP_RXDID_FLX_WRD_##idx##_PROT_MDID_M))
-#define ICE_NIC_FLX_FLG_ENTRY(hw, flg_0, flg_1, flg_2, flg_3, idx) \
- wr32((hw), GLFLXP_RXDID_FLAGS(ICE_RXDID_FLEX_NIC, idx), \
+#define ICE_PROG_FLG_ENTRY(hw, rxdid, flg_0, flg_1, flg_2, flg_3, idx) \
+ wr32((hw), GLFLXP_RXDID_FLAGS(rxdid, idx), \
(((flg_0) << GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_S) & \
GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_M) | \
(((flg_1) << GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_1_S) & \
@@ -43,6 +43,23 @@ static enum ice_status ice_set_mac_type(struct ice_hw *hw)
}
/**
+ * ice_dev_onetime_setup - Temporary HW/FW workarounds
+ * @hw: pointer to the HW structure
+ *
+ * This function provides temporary workarounds for certain issues
+ * that are expected to be fixed in the HW/FW.
+ */
+void ice_dev_onetime_setup(struct ice_hw *hw)
+{
+ /* configure Rx - set non pxe mode */
+ wr32(hw, GLLAN_RCTL_0, 0x1);
+
+#define MBX_PF_VT_PFALLOC 0x00231E80
+ /* set VFs per PF */
+ wr32(hw, MBX_PF_VT_PFALLOC, rd32(hw, PF_VT_PFALLOC_HIF));
+}
+
+/**
* ice_clear_pf_cfg - Clear PF configuration
* @hw: pointer to the hardware structure
*
@@ -125,7 +142,7 @@ ice_aq_manage_mac_read(struct ice_hw *hw, void *buf, u16 buf_size,
*
* Returns the various PHY capabilities supported on the Port (0x0600)
*/
-static enum ice_status
+enum ice_status
ice_aq_get_phy_caps(struct ice_port_info *pi, bool qual_mods, u8 report_mode,
struct ice_aqc_get_phy_caps_data *pcaps,
struct ice_sq_cd *cd)
@@ -218,7 +235,7 @@ static enum ice_media_type ice_get_media_type(struct ice_port_info *pi)
*
* Get Link Status (0x607). Returns the link status of the adapter.
*/
-enum ice_status
+static enum ice_status
ice_aq_get_link_info(struct ice_port_info *pi, bool ena_lse,
struct ice_link_status *link, struct ice_sq_cd *cd)
{
@@ -290,30 +307,85 @@ ice_aq_get_link_info(struct ice_port_info *pi, bool ena_lse,
}
/**
- * ice_init_flex_parser - initialize rx flex parser
+ * ice_init_flex_flags
* @hw: pointer to the hardware structure
+ * @prof_id: Rx Descriptor Builder profile ID
*
- * Function to initialize flex descriptors
+ * Function to initialize Rx flex flags
*/
-static void ice_init_flex_parser(struct ice_hw *hw)
+static void ice_init_flex_flags(struct ice_hw *hw, enum ice_rxdid prof_id)
{
u8 idx = 0;
- ICE_NIC_FLX_ENTRY(hw, ICE_RX_MDID_HASH_LOW, 0);
- ICE_NIC_FLX_ENTRY(hw, ICE_RX_MDID_HASH_HIGH, 1);
- ICE_NIC_FLX_ENTRY(hw, ICE_RX_MDID_FLOW_ID_LOWER, 2);
- ICE_NIC_FLX_ENTRY(hw, ICE_RX_MDID_FLOW_ID_HIGH, 3);
- ICE_NIC_FLX_FLG_ENTRY(hw, ICE_RXFLG_PKT_FRG, ICE_RXFLG_UDP_GRE,
- ICE_RXFLG_PKT_DSI, ICE_RXFLG_FIN, idx++);
- ICE_NIC_FLX_FLG_ENTRY(hw, ICE_RXFLG_SYN, ICE_RXFLG_RST,
- ICE_RXFLG_PKT_DSI, ICE_RXFLG_PKT_DSI, idx++);
- ICE_NIC_FLX_FLG_ENTRY(hw, ICE_RXFLG_PKT_DSI, ICE_RXFLG_PKT_DSI,
- ICE_RXFLG_EVLAN_x8100, ICE_RXFLG_EVLAN_x9100,
- idx++);
- ICE_NIC_FLX_FLG_ENTRY(hw, ICE_RXFLG_VLAN_x8100, ICE_RXFLG_TNL_VLAN,
- ICE_RXFLG_TNL_MAC, ICE_RXFLG_TNL0, idx++);
- ICE_NIC_FLX_FLG_ENTRY(hw, ICE_RXFLG_TNL1, ICE_RXFLG_TNL2,
- ICE_RXFLG_PKT_DSI, ICE_RXFLG_PKT_DSI, idx);
+ /* Flex-flag fields (0-2) are programmed with FLG64 bits with layout:
+ * flexiflags0[5:0] - TCP flags, is_packet_fragmented, is_packet_UDP_GRE
+ * flexiflags1[3:0] - Not used for flag programming
+ * flexiflags2[7:0] - Tunnel and VLAN types
+ * 2 invalid fields in last index
+ */
+ switch (prof_id) {
+ /* Rx flex flags are currently programmed for the NIC profiles only.
+ * Different flag bit programming configurations can be added per
+ * profile as needed.
+ */
+ case ICE_RXDID_FLEX_NIC:
+ case ICE_RXDID_FLEX_NIC_2:
+ ICE_PROG_FLG_ENTRY(hw, prof_id, ICE_RXFLG_PKT_FRG,
+ ICE_RXFLG_UDP_GRE, ICE_RXFLG_PKT_DSI,
+ ICE_RXFLG_FIN, idx++);
+ /* flex flag 1 is not used for flexi-flag programming, skipping
+ * these four FLG64 bits.
+ */
+ ICE_PROG_FLG_ENTRY(hw, prof_id, ICE_RXFLG_SYN, ICE_RXFLG_RST,
+ ICE_RXFLG_PKT_DSI, ICE_RXFLG_PKT_DSI, idx++);
+ ICE_PROG_FLG_ENTRY(hw, prof_id, ICE_RXFLG_PKT_DSI,
+ ICE_RXFLG_PKT_DSI, ICE_RXFLG_EVLAN_x8100,
+ ICE_RXFLG_EVLAN_x9100, idx++);
+ ICE_PROG_FLG_ENTRY(hw, prof_id, ICE_RXFLG_VLAN_x8100,
+ ICE_RXFLG_TNL_VLAN, ICE_RXFLG_TNL_MAC,
+ ICE_RXFLG_TNL0, idx++);
+ ICE_PROG_FLG_ENTRY(hw, prof_id, ICE_RXFLG_TNL1, ICE_RXFLG_TNL2,
+ ICE_RXFLG_PKT_DSI, ICE_RXFLG_PKT_DSI, idx);
+ break;
+
+ default:
+ ice_debug(hw, ICE_DBG_INIT,
+ "Flag programming for profile ID %d not supported\n",
+ prof_id);
+ }
+}
+
+/**
+ * ice_init_flex_flds
+ * @hw: pointer to the hardware structure
+ * @prof_id: Rx Descriptor Builder profile ID
+ *
+ * Function to initialize flex descriptors
+ */
+static void ice_init_flex_flds(struct ice_hw *hw, enum ice_rxdid prof_id)
+{
+ enum ice_flex_rx_mdid mdid;
+
+ switch (prof_id) {
+ case ICE_RXDID_FLEX_NIC:
+ case ICE_RXDID_FLEX_NIC_2:
+ ICE_PROG_FLEX_ENTRY(hw, prof_id, ICE_RX_MDID_HASH_LOW, 0);
+ ICE_PROG_FLEX_ENTRY(hw, prof_id, ICE_RX_MDID_HASH_HIGH, 1);
+ ICE_PROG_FLEX_ENTRY(hw, prof_id, ICE_RX_MDID_FLOW_ID_LOWER, 2);
+
+ mdid = (prof_id == ICE_RXDID_FLEX_NIC_2) ?
+ ICE_RX_MDID_SRC_VSI : ICE_RX_MDID_FLOW_ID_HIGH;
+
+ ICE_PROG_FLEX_ENTRY(hw, prof_id, mdid, 3);
+
+ ice_init_flex_flags(hw, prof_id);
+ break;
+
+ default:
+ ice_debug(hw, ICE_DBG_INIT,
+ "Field init for profile ID %d not supported\n",
+ prof_id);
+ }
}
/**
@@ -333,20 +405,7 @@ static enum ice_status ice_init_fltr_mgmt_struct(struct ice_hw *hw)
INIT_LIST_HEAD(&sw->vsi_list_map_head);
- mutex_init(&sw->mac_list_lock);
- INIT_LIST_HEAD(&sw->mac_list_head);
-
- mutex_init(&sw->vlan_list_lock);
- INIT_LIST_HEAD(&sw->vlan_list_head);
-
- mutex_init(&sw->eth_m_list_lock);
- INIT_LIST_HEAD(&sw->eth_m_list_head);
-
- mutex_init(&sw->promisc_list_lock);
- INIT_LIST_HEAD(&sw->promisc_list_head);
-
- mutex_init(&sw->mac_vlan_list_lock);
- INIT_LIST_HEAD(&sw->mac_vlan_list_head);
+ ice_init_def_sw_recp(hw);
return 0;
}
@@ -360,20 +419,232 @@ static void ice_cleanup_fltr_mgmt_struct(struct ice_hw *hw)
struct ice_switch_info *sw = hw->switch_info;
struct ice_vsi_list_map_info *v_pos_map;
struct ice_vsi_list_map_info *v_tmp_map;
+ struct ice_sw_recipe *recps;
+ u8 i;
list_for_each_entry_safe(v_pos_map, v_tmp_map, &sw->vsi_list_map_head,
list_entry) {
list_del(&v_pos_map->list_entry);
devm_kfree(ice_hw_to_dev(hw), v_pos_map);
}
+ recps = hw->switch_info->recp_list;
+ for (i = 0; i < ICE_SW_LKUP_LAST; i++) {
+ struct ice_fltr_mgmt_list_entry *lst_itr, *tmp_entry;
+
+ recps[i].root_rid = i;
+ mutex_destroy(&recps[i].filt_rule_lock);
+ list_for_each_entry_safe(lst_itr, tmp_entry,
+ &recps[i].filt_rules, list_entry) {
+ list_del(&lst_itr->list_entry);
+ devm_kfree(ice_hw_to_dev(hw), lst_itr);
+ }
+ }
+ ice_rm_all_sw_replay_rule_info(hw);
+ devm_kfree(ice_hw_to_dev(hw), sw->recp_list);
+ devm_kfree(ice_hw_to_dev(hw), sw);
+}
- mutex_destroy(&sw->mac_list_lock);
- mutex_destroy(&sw->vlan_list_lock);
- mutex_destroy(&sw->eth_m_list_lock);
- mutex_destroy(&sw->promisc_list_lock);
- mutex_destroy(&sw->mac_vlan_list_lock);
+#define ICE_FW_LOG_DESC_SIZE(n) (sizeof(struct ice_aqc_fw_logging_data) + \
+ (((n) - 1) * sizeof(((struct ice_aqc_fw_logging_data *)0)->entry)))
+#define ICE_FW_LOG_DESC_SIZE_MAX \
+ ICE_FW_LOG_DESC_SIZE(ICE_AQC_FW_LOG_ID_MAX)
- devm_kfree(ice_hw_to_dev(hw), sw);
+/**
+ * ice_cfg_fw_log - configure FW logging
+ * @hw: pointer to the hw struct
+ * @enable: enable certain FW logging events if true, disable all if false
+ *
+ * This function enables/disables the FW logging via Rx CQ events and a UART
+ * port based on predetermined configurations. FW logging via the Rx CQ can be
+ * enabled/disabled for individual PF's. However, FW logging via the UART can
+ * only be enabled/disabled for all PFs on the same device.
+ *
+ * To enable overall FW logging, the "cq_en" and "uart_en" enable bits in
+ * hw->fw_log need to be set accordingly, e.g. based on user-provided input,
+ * before initializing the device.
+ *
+ * When re/configuring FW logging, callers need to update the "cfg" elements of
+ * the hw->fw_log.evnts array with the desired logging event configurations for
+ * modules of interest. When disabling FW logging completely, the callers can
+ * just pass false in the "enable" parameter. On completion, the function will
+ * update the "cur" element of the hw->fw_log.evnts array with the resulting
+ * logging event configurations of the modules that are being re/configured. FW
+ * logging modules that are not part of a reconfiguration operation retain their
+ * previous states.
+ *
+ * Before resetting the device, it is recommended that the driver disables FW
+ * logging before shutting down the control queue. When disabling FW logging
+ * ("enable" = false), the latest configurations of FW logging events stored in
+ * hw->fw_log.evnts[] are not overridden to allow them to be reconfigured after
+ * a device reset.
+ *
+ * When enabling FW logging to emit log messages via the Rx CQ during the
+ * device's initialization phase, a mechanism alternative to interrupt handlers
+ * needs to be used to extract FW log messages from the Rx CQ periodically and
+ * to prevent the Rx CQ from being full and stalling other types of control
+ * messages from FW to SW. Interrupts are typically disabled during the device's
+ * initialization phase.
+ */
+static enum ice_status ice_cfg_fw_log(struct ice_hw *hw, bool enable)
+{
+ struct ice_aqc_fw_logging_data *data = NULL;
+ struct ice_aqc_fw_logging *cmd;
+ enum ice_status status = 0;
+ u16 i, chgs = 0, len = 0;
+ struct ice_aq_desc desc;
+ u8 actv_evnts = 0;
+ void *buf = NULL;
+
+ if (!hw->fw_log.cq_en && !hw->fw_log.uart_en)
+ return 0;
+
+ /* Disable FW logging only when the control queue is still responsive */
+ if (!enable &&
+ (!hw->fw_log.actv_evnts || !ice_check_sq_alive(hw, &hw->adminq)))
+ return 0;
+
+ ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_fw_logging);
+ cmd = &desc.params.fw_logging;
+
+ /* Indicate which controls are valid */
+ if (hw->fw_log.cq_en)
+ cmd->log_ctrl_valid |= ICE_AQC_FW_LOG_AQ_VALID;
+
+ if (hw->fw_log.uart_en)
+ cmd->log_ctrl_valid |= ICE_AQC_FW_LOG_UART_VALID;
+
+ if (enable) {
+ /* Fill in an array of entries with FW logging modules and
+ * logging events being reconfigured.
+ */
+ for (i = 0; i < ICE_AQC_FW_LOG_ID_MAX; i++) {
+ u16 val;
+
+ /* Keep track of enabled event types */
+ actv_evnts |= hw->fw_log.evnts[i].cfg;
+
+ if (hw->fw_log.evnts[i].cfg == hw->fw_log.evnts[i].cur)
+ continue;
+
+ if (!data) {
+ data = devm_kzalloc(ice_hw_to_dev(hw),
+ ICE_FW_LOG_DESC_SIZE_MAX,
+ GFP_KERNEL);
+ if (!data)
+ return ICE_ERR_NO_MEMORY;
+ }
+
+ val = i << ICE_AQC_FW_LOG_ID_S;
+ val |= hw->fw_log.evnts[i].cfg << ICE_AQC_FW_LOG_EN_S;
+ data->entry[chgs++] = cpu_to_le16(val);
+ }
+
+ /* Only enable FW logging if at least one module is specified.
+ * If FW logging is currently enabled but all modules are not
+ * enabled to emit log messages, disable FW logging altogether.
+ */
+ if (actv_evnts) {
+ /* Leave if there is effectively no change */
+ if (!chgs)
+ goto out;
+
+ if (hw->fw_log.cq_en)
+ cmd->log_ctrl |= ICE_AQC_FW_LOG_AQ_EN;
+
+ if (hw->fw_log.uart_en)
+ cmd->log_ctrl |= ICE_AQC_FW_LOG_UART_EN;
+
+ buf = data;
+ len = ICE_FW_LOG_DESC_SIZE(chgs);
+ desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
+ }
+ }
+
+ status = ice_aq_send_cmd(hw, &desc, buf, len, NULL);
+ if (!status) {
+ /* Update the current configuration to reflect events enabled.
+ * hw->fw_log.cq_en and hw->fw_log.uart_en indicate if the FW
+ * logging mode is enabled for the device. They do not reflect
+ * actual modules being enabled to emit log messages. So, their
+ * values remain unchanged even when all modules are disabled.
+ */
+ u16 cnt = enable ? chgs : (u16)ICE_AQC_FW_LOG_ID_MAX;
+
+ hw->fw_log.actv_evnts = actv_evnts;
+ for (i = 0; i < cnt; i++) {
+ u16 v, m;
+
+ if (!enable) {
+ /* When disabling all FW logging events as part
+ * of device's de-initialization, the original
+ * configurations are retained, and can be used
+ * to reconfigure FW logging later if the device
+ * is re-initialized.
+ */
+ hw->fw_log.evnts[i].cur = 0;
+ continue;
+ }
+
+ v = le16_to_cpu(data->entry[i]);
+ m = (v & ICE_AQC_FW_LOG_ID_M) >> ICE_AQC_FW_LOG_ID_S;
+ hw->fw_log.evnts[m].cur = hw->fw_log.evnts[m].cfg;
+ }
+ }
+
+out:
+ if (data)
+ devm_kfree(ice_hw_to_dev(hw), data);
+
+ return status;
+}
+
+/**
+ * ice_output_fw_log
+ * @hw: pointer to the hw struct
+ * @desc: pointer to the AQ message descriptor
+ * @buf: pointer to the buffer accompanying the AQ message
+ *
+ * Formats a FW Log message and outputs it via the standard driver logs.
+ */
+void ice_output_fw_log(struct ice_hw *hw, struct ice_aq_desc *desc, void *buf)
+{
+ ice_debug(hw, ICE_DBG_AQ_MSG, "[ FW Log Msg Start ]\n");
+ ice_debug_array(hw, ICE_DBG_AQ_MSG, 16, 1, (u8 *)buf,
+ le16_to_cpu(desc->datalen));
+ ice_debug(hw, ICE_DBG_AQ_MSG, "[ FW Log Msg End ]\n");
+}
+
+/**
+ * ice_get_itr_intrl_gran - determine int/intrl granularity
+ * @hw: pointer to the hw struct
+ *
+ * Determines the itr/intrl granularities based on the maximum aggregate
+ * bandwidth according to the device's configuration during power-on.
+ */
+static enum ice_status ice_get_itr_intrl_gran(struct ice_hw *hw)
+{
+ u8 max_agg_bw = (rd32(hw, GL_PWR_MODE_CTL) &
+ GL_PWR_MODE_CTL_CAR_MAX_BW_M) >>
+ GL_PWR_MODE_CTL_CAR_MAX_BW_S;
+
+ switch (max_agg_bw) {
+ case ICE_MAX_AGG_BW_200G:
+ case ICE_MAX_AGG_BW_100G:
+ case ICE_MAX_AGG_BW_50G:
+ hw->itr_gran = ICE_ITR_GRAN_ABOVE_25;
+ hw->intrl_gran = ICE_INTRL_GRAN_ABOVE_25;
+ break;
+ case ICE_MAX_AGG_BW_25G:
+ hw->itr_gran = ICE_ITR_GRAN_MAX_25;
+ hw->intrl_gran = ICE_INTRL_GRAN_MAX_25;
+ break;
+ default:
+ ice_debug(hw, ICE_DBG_INIT,
+ "Failed to determine itr/intrl granularity\n");
+ return ICE_ERR_CFG;
+ }
+
+ return 0;
}
/**
@@ -400,16 +671,19 @@ enum ice_status ice_init_hw(struct ice_hw *hw)
if (status)
return status;
- /* set these values to minimum allowed */
- hw->itr_gran_200 = ICE_ITR_GRAN_MIN_200;
- hw->itr_gran_100 = ICE_ITR_GRAN_MIN_100;
- hw->itr_gran_50 = ICE_ITR_GRAN_MIN_50;
- hw->itr_gran_25 = ICE_ITR_GRAN_MIN_25;
+ status = ice_get_itr_intrl_gran(hw);
+ if (status)
+ return status;
status = ice_init_all_ctrlq(hw);
if (status)
goto err_unroll_cqinit;
+ /* Enable FW logging. Not fatal if this fails. */
+ status = ice_cfg_fw_log(hw, true);
+ if (status)
+ ice_debug(hw, ICE_DBG_INIT, "Failed to enable FW logging.\n");
+
status = ice_clear_pf_cfg(hw);
if (status)
goto err_unroll_cqinit;
@@ -472,10 +746,19 @@ enum ice_status ice_init_hw(struct ice_hw *hw)
if (status)
goto err_unroll_sched;
+ /* need a valid SW entry point to build a Tx tree */
+ if (!hw->sw_entry_point_layer) {
+ ice_debug(hw, ICE_DBG_SCHED, "invalid sw entry point\n");
+ status = ICE_ERR_CFG;
+ goto err_unroll_sched;
+ }
+
status = ice_init_fltr_mgmt_struct(hw);
if (status)
goto err_unroll_sched;
+ ice_dev_onetime_setup(hw);
+
/* Get MAC information */
/* A single port can report up to two (LAN and WoL) addresses */
mac_buf = devm_kcalloc(ice_hw_to_dev(hw), 2,
@@ -494,7 +777,8 @@ enum ice_status ice_init_hw(struct ice_hw *hw)
if (status)
goto err_unroll_fltr_mgmt_struct;
- ice_init_flex_parser(hw);
+ ice_init_flex_flds(hw, ICE_RXDID_FLEX_NIC);
+ ice_init_flex_flds(hw, ICE_RXDID_FLEX_NIC_2);
return 0;
@@ -515,15 +799,21 @@ err_unroll_cqinit:
*/
void ice_deinit_hw(struct ice_hw *hw)
{
+ ice_cleanup_fltr_mgmt_struct(hw);
+
ice_sched_cleanup_all(hw);
- ice_shutdown_all_ctrlq(hw);
if (hw->port_info) {
devm_kfree(ice_hw_to_dev(hw), hw->port_info);
hw->port_info = NULL;
}
- ice_cleanup_fltr_mgmt_struct(hw);
+ /* Attempt to disable FW logging before shutting down control queues */
+ ice_cfg_fw_log(hw, false);
+ ice_shutdown_all_ctrlq(hw);
+
+ /* Clear VSI contexts if not already cleared */
+ ice_clear_all_vsi_ctx(hw);
}
/**
@@ -652,6 +942,8 @@ enum ice_status ice_reset(struct ice_hw *hw, enum ice_reset_req req)
ice_debug(hw, ICE_DBG_INIT, "GlobalR requested\n");
val = GLGEN_RTRIG_GLOBR_M;
break;
+ default:
+ return ICE_ERR_PARAM;
}
val |= rd32(hw, GLGEN_RTRIG);
@@ -904,7 +1196,22 @@ enum ice_status ice_aq_q_shutdown(struct ice_hw *hw, bool unloading)
* @timeout: the maximum time in ms that the driver may hold the resource
* @cd: pointer to command details structure or NULL
*
- * requests common resource using the admin queue commands (0x0008)
+ * Requests common resource using the admin queue commands (0x0008).
+ * When attempting to acquire the Global Config Lock, the driver can
+ * learn of three states:
+ * 1) ICE_SUCCESS - acquired lock, and can perform download package
+ * 2) ICE_ERR_AQ_ERROR - did not get lock, driver should fail to load
+ * 3) ICE_ERR_AQ_NO_WORK - did not get lock, but another driver has
+ * successfully downloaded the package; the driver does
+ * not have to download the package and can continue
+ * loading
+ *
+ * Note that if the caller is in an acquire lock, perform action, release lock
+ * phase of operation, it is possible that the FW may detect a timeout and issue
+ * a CORER. In this case, the driver will receive a CORER interrupt and will
+ * have to determine its cause. The calling thread that is handling this flow
+ * will likely get an error propagated back to it indicating the Download
+ * Package, Update Package or the Release Resource AQ commands timed out.
*/
static enum ice_status
ice_aq_req_res(struct ice_hw *hw, enum ice_aq_res_ids res,
@@ -922,13 +1229,43 @@ ice_aq_req_res(struct ice_hw *hw, enum ice_aq_res_ids res,
cmd_resp->res_id = cpu_to_le16(res);
cmd_resp->access_type = cpu_to_le16(access);
cmd_resp->res_number = cpu_to_le32(sdp_number);
+ cmd_resp->timeout = cpu_to_le32(*timeout);
+ *timeout = 0;
status = ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
+
/* The completion specifies the maximum time in ms that the driver
* may hold the resource in the Timeout field.
- * If the resource is held by someone else, the command completes with
- * busy return value and the timeout field indicates the maximum time
- * the current owner of the resource has to free it.
+ */
+
+ /* Global config lock response utilizes an additional status field.
+ *
+ * If the Global config lock resource is held by some other driver, the
+ * command completes with ICE_AQ_RES_GLBL_IN_PROG in the status field
+ * and the timeout field indicates the maximum time the current owner
+ * of the resource has to free it.
+ */
+ if (res == ICE_GLOBAL_CFG_LOCK_RES_ID) {
+ if (le16_to_cpu(cmd_resp->status) == ICE_AQ_RES_GLBL_SUCCESS) {
+ *timeout = le32_to_cpu(cmd_resp->timeout);
+ return 0;
+ } else if (le16_to_cpu(cmd_resp->status) ==
+ ICE_AQ_RES_GLBL_IN_PROG) {
+ *timeout = le32_to_cpu(cmd_resp->timeout);
+ return ICE_ERR_AQ_ERROR;
+ } else if (le16_to_cpu(cmd_resp->status) ==
+ ICE_AQ_RES_GLBL_DONE) {
+ return ICE_ERR_AQ_NO_WORK;
+ }
+
+ /* invalid FW response, force a timeout immediately */
+ *timeout = 0;
+ return ICE_ERR_AQ_ERROR;
+ }
+
+ /* If the resource is held by some other driver, the command completes
+ * with a busy return value and the timeout field indicates the maximum
+ * time the current owner of the resource has to free it.
*/
if (!status || hw->adminq.sq_last_status == ICE_AQ_RC_EBUSY)
*timeout = le32_to_cpu(cmd_resp->timeout);
@@ -967,30 +1304,28 @@ ice_aq_release_res(struct ice_hw *hw, enum ice_aq_res_ids res, u8 sdp_number,
* @hw: pointer to the HW structure
* @res: resource id
* @access: access type (read or write)
+ * @timeout: timeout in milliseconds
*
* This function will attempt to acquire the ownership of a resource.
*/
enum ice_status
ice_acquire_res(struct ice_hw *hw, enum ice_aq_res_ids res,
- enum ice_aq_res_access_type access)
+ enum ice_aq_res_access_type access, u32 timeout)
{
#define ICE_RES_POLLING_DELAY_MS 10
u32 delay = ICE_RES_POLLING_DELAY_MS;
+ u32 time_left = timeout;
enum ice_status status;
- u32 time_left = 0;
- u32 timeout;
status = ice_aq_req_res(hw, res, access, 0, &time_left, NULL);
- /* An admin queue return code of ICE_AQ_RC_EEXIST means that another
- * driver has previously acquired the resource and performed any
- * necessary updates; in this case the caller does not obtain the
- * resource and has no further work to do.
+ /* A return code of ICE_ERR_AQ_NO_WORK means that another driver has
+ * previously acquired the resource and performed any necessary updates;
+ * in this case the caller does not obtain the resource and has no
+ * further work to do.
*/
- if (hw->adminq.sq_last_status == ICE_AQ_RC_EEXIST) {
- status = ICE_ERR_AQ_NO_WORK;
+ if (status == ICE_ERR_AQ_NO_WORK)
goto ice_acquire_res_exit;
- }
if (status)
ice_debug(hw, ICE_DBG_RES,
@@ -1003,11 +1338,9 @@ ice_acquire_res(struct ice_hw *hw, enum ice_aq_res_ids res,
timeout = (timeout > delay) ? timeout - delay : 0;
status = ice_aq_req_res(hw, res, access, 0, &time_left, NULL);
- if (hw->adminq.sq_last_status == ICE_AQ_RC_EEXIST) {
+ if (status == ICE_ERR_AQ_NO_WORK)
/* lock free, but no work to do */
- status = ICE_ERR_AQ_NO_WORK;
break;
- }
if (!status)
/* lock acquired */
@@ -1095,6 +1428,28 @@ ice_parse_caps(struct ice_hw *hw, void *buf, u32 cap_count,
u16 cap = le16_to_cpu(cap_resp->cap);
switch (cap) {
+ case ICE_AQC_CAPS_SRIOV:
+ caps->sr_iov_1_1 = (number == 1);
+ ice_debug(hw, ICE_DBG_INIT,
+ "HW caps: SR-IOV = %d\n", caps->sr_iov_1_1);
+ break;
+ case ICE_AQC_CAPS_VF:
+ if (dev_p) {
+ dev_p->num_vfs_exposed = number;
+ ice_debug(hw, ICE_DBG_INIT,
+ "HW caps: VFs exposed = %d\n",
+ dev_p->num_vfs_exposed);
+ } else if (func_p) {
+ func_p->num_allocd_vfs = number;
+ func_p->vf_base_id = logical_id;
+ ice_debug(hw, ICE_DBG_INIT,
+ "HW caps: VFs allocated = %d\n",
+ func_p->num_allocd_vfs);
+ ice_debug(hw, ICE_DBG_INIT,
+ "HW caps: VF base_id = %d\n",
+ func_p->vf_base_id);
+ }
+ break;
case ICE_AQC_CAPS_VSI:
if (dev_p) {
dev_p->num_vsi_allocd_to_host = number;
@@ -1171,7 +1526,7 @@ ice_parse_caps(struct ice_hw *hw, void *buf, u32 cap_count,
* @hw: pointer to the hw struct
* @buf: a virtual buffer to hold the capabilities
* @buf_size: Size of the virtual buffer
- * @data_size: Size of the returned data, or buf size needed if AQ err==ENOMEM
+ * @cap_count: cap count needed if AQ err==ENOMEM
* @opc: capabilities type to discover - pass in the command opcode
* @cd: pointer to command details structure or NULL
*
@@ -1179,7 +1534,7 @@ ice_parse_caps(struct ice_hw *hw, void *buf, u32 cap_count,
* the firmware.
*/
static enum ice_status
-ice_aq_discover_caps(struct ice_hw *hw, void *buf, u16 buf_size, u16 *data_size,
+ice_aq_discover_caps(struct ice_hw *hw, void *buf, u16 buf_size, u32 *cap_count,
enum ice_adminq_opc opc, struct ice_sq_cd *cd)
{
struct ice_aqc_list_caps *cmd;
@@ -1197,59 +1552,75 @@ ice_aq_discover_caps(struct ice_hw *hw, void *buf, u16 buf_size, u16 *data_size,
status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
if (!status)
ice_parse_caps(hw, buf, le32_to_cpu(cmd->count), opc);
- *data_size = le16_to_cpu(desc.datalen);
-
+ else if (hw->adminq.sq_last_status == ICE_AQ_RC_ENOMEM)
+ *cap_count = le32_to_cpu(cmd->count);
return status;
}
/**
- * ice_get_caps - get info about the HW
+ * ice_discover_caps - get info about the HW
* @hw: pointer to the hardware structure
+ * @opc: capabilities type to discover - pass in the command opcode
*/
-enum ice_status ice_get_caps(struct ice_hw *hw)
+static enum ice_status ice_discover_caps(struct ice_hw *hw,
+ enum ice_adminq_opc opc)
{
enum ice_status status;
- u16 data_size = 0;
+ u32 cap_count;
u16 cbuf_len;
u8 retries;
/* The driver doesn't know how many capabilities the device will return
* so the buffer size required isn't known ahead of time. The driver
* starts with cbuf_len and if this turns out to be insufficient, the
- * device returns ICE_AQ_RC_ENOMEM and also the buffer size it needs.
- * The driver then allocates the buffer of this size and retries the
- * operation. So it follows that the retry count is 2.
+ * device returns ICE_AQ_RC_ENOMEM and also the cap_count it needs.
+ * The driver then allocates the buffer based on the count and retries
+ * the operation. So it follows that the retry count is 2.
*/
#define ICE_GET_CAP_BUF_COUNT 40
#define ICE_GET_CAP_RETRY_COUNT 2
- cbuf_len = ICE_GET_CAP_BUF_COUNT *
- sizeof(struct ice_aqc_list_caps_elem);
-
+ cap_count = ICE_GET_CAP_BUF_COUNT;
retries = ICE_GET_CAP_RETRY_COUNT;
do {
void *cbuf;
+ cbuf_len = (u16)(cap_count *
+ sizeof(struct ice_aqc_list_caps_elem));
cbuf = devm_kzalloc(ice_hw_to_dev(hw), cbuf_len, GFP_KERNEL);
if (!cbuf)
return ICE_ERR_NO_MEMORY;
- status = ice_aq_discover_caps(hw, cbuf, cbuf_len, &data_size,
- ice_aqc_opc_list_func_caps, NULL);
+ status = ice_aq_discover_caps(hw, cbuf, cbuf_len, &cap_count,
+ opc, NULL);
devm_kfree(ice_hw_to_dev(hw), cbuf);
if (!status || hw->adminq.sq_last_status != ICE_AQ_RC_ENOMEM)
break;
/* If ENOMEM is returned, try again with bigger buffer */
- cbuf_len = data_size;
} while (--retries);
return status;
}
/**
+ * ice_get_caps - get info about the HW
+ * @hw: pointer to the hardware structure
+ */
+enum ice_status ice_get_caps(struct ice_hw *hw)
+{
+ enum ice_status status;
+
+ status = ice_discover_caps(hw, ice_aqc_opc_list_dev_caps);
+ if (!status)
+ status = ice_discover_caps(hw, ice_aqc_opc_list_func_caps);
+
+ return status;
+}
+
+/**
* ice_aq_manage_mac_write - manage MAC address write command
* @hw: pointer to the hw struct
* @mac_addr: MAC address to be written as LAA/LAA+WoL/Port address
@@ -1307,6 +1678,110 @@ void ice_clear_pxe_mode(struct ice_hw *hw)
}
/**
+ * ice_get_link_speed_based_on_phy_type - returns link speed
+ * @phy_type_low: lower part of phy_type
+ *
+ * This helper function will convert a phy_type_low to its corresponding link
+ * speed.
+ * Note: In the structure of phy_type_low, there should be one bit set, as
+ * this function will convert one phy type to its speed.
+ * If no bit gets set, ICE_LINK_SPEED_UNKNOWN will be returned
+ * If more than one bit gets set, ICE_LINK_SPEED_UNKNOWN will be returned
+ */
+static u16
+ice_get_link_speed_based_on_phy_type(u64 phy_type_low)
+{
+ u16 speed_phy_type_low = ICE_AQ_LINK_SPEED_UNKNOWN;
+
+ switch (phy_type_low) {
+ case ICE_PHY_TYPE_LOW_100BASE_TX:
+ case ICE_PHY_TYPE_LOW_100M_SGMII:
+ speed_phy_type_low = ICE_AQ_LINK_SPEED_100MB;
+ break;
+ case ICE_PHY_TYPE_LOW_1000BASE_T:
+ case ICE_PHY_TYPE_LOW_1000BASE_SX:
+ case ICE_PHY_TYPE_LOW_1000BASE_LX:
+ case ICE_PHY_TYPE_LOW_1000BASE_KX:
+ case ICE_PHY_TYPE_LOW_1G_SGMII:
+ speed_phy_type_low = ICE_AQ_LINK_SPEED_1000MB;
+ break;
+ case ICE_PHY_TYPE_LOW_2500BASE_T:
+ case ICE_PHY_TYPE_LOW_2500BASE_X:
+ case ICE_PHY_TYPE_LOW_2500BASE_KX:
+ speed_phy_type_low = ICE_AQ_LINK_SPEED_2500MB;
+ break;
+ case ICE_PHY_TYPE_LOW_5GBASE_T:
+ case ICE_PHY_TYPE_LOW_5GBASE_KR:
+ speed_phy_type_low = ICE_AQ_LINK_SPEED_5GB;
+ break;
+ case ICE_PHY_TYPE_LOW_10GBASE_T:
+ case ICE_PHY_TYPE_LOW_10G_SFI_DA:
+ case ICE_PHY_TYPE_LOW_10GBASE_SR:
+ case ICE_PHY_TYPE_LOW_10GBASE_LR:
+ case ICE_PHY_TYPE_LOW_10GBASE_KR_CR1:
+ case ICE_PHY_TYPE_LOW_10G_SFI_AOC_ACC:
+ case ICE_PHY_TYPE_LOW_10G_SFI_C2C:
+ speed_phy_type_low = ICE_AQ_LINK_SPEED_10GB;
+ break;
+ case ICE_PHY_TYPE_LOW_25GBASE_T:
+ case ICE_PHY_TYPE_LOW_25GBASE_CR:
+ case ICE_PHY_TYPE_LOW_25GBASE_CR_S:
+ case ICE_PHY_TYPE_LOW_25GBASE_CR1:
+ case ICE_PHY_TYPE_LOW_25GBASE_SR:
+ case ICE_PHY_TYPE_LOW_25GBASE_LR:
+ case ICE_PHY_TYPE_LOW_25GBASE_KR:
+ case ICE_PHY_TYPE_LOW_25GBASE_KR_S:
+ case ICE_PHY_TYPE_LOW_25GBASE_KR1:
+ case ICE_PHY_TYPE_LOW_25G_AUI_AOC_ACC:
+ case ICE_PHY_TYPE_LOW_25G_AUI_C2C:
+ speed_phy_type_low = ICE_AQ_LINK_SPEED_25GB;
+ break;
+ case ICE_PHY_TYPE_LOW_40GBASE_CR4:
+ case ICE_PHY_TYPE_LOW_40GBASE_SR4:
+ case ICE_PHY_TYPE_LOW_40GBASE_LR4:
+ case ICE_PHY_TYPE_LOW_40GBASE_KR4:
+ case ICE_PHY_TYPE_LOW_40G_XLAUI_AOC_ACC:
+ case ICE_PHY_TYPE_LOW_40G_XLAUI:
+ speed_phy_type_low = ICE_AQ_LINK_SPEED_40GB;
+ break;
+ default:
+ speed_phy_type_low = ICE_AQ_LINK_SPEED_UNKNOWN;
+ break;
+ }
+
+ return speed_phy_type_low;
+}
+
+/**
+ * ice_update_phy_type
+ * @phy_type_low: pointer to the lower part of phy_type
+ * @link_speeds_bitmap: targeted link speeds bitmap
+ *
+ * Note: For the link_speeds_bitmap structure, you can check it at
+ * [ice_aqc_get_link_status->link_speed]. Caller can pass in
+ * link_speeds_bitmap include multiple speeds.
+ *
+ * The value of phy_type_low will present a certain link speed. This helper
+ * function will turn on bits in the phy_type_low based on the value of
+ * link_speeds_bitmap input parameter.
+ */
+void ice_update_phy_type(u64 *phy_type_low, u16 link_speeds_bitmap)
+{
+ u16 speed = ICE_AQ_LINK_SPEED_UNKNOWN;
+ u64 pt_low;
+ int index;
+
+ /* We first check with low part of phy_type */
+ for (index = 0; index <= ICE_PHY_TYPE_LOW_MAX_INDEX; index++) {
+ pt_low = BIT_ULL(index);
+ speed = ice_get_link_speed_based_on_phy_type(pt_low);
+
+ if (link_speeds_bitmap & speed)
+ *phy_type_low |= BIT_ULL(index);
+ }
+}
+
+/**
* ice_aq_set_phy_cfg
* @hw: pointer to the hw struct
* @lport: logical port number
@@ -1318,19 +1793,18 @@ void ice_clear_pxe_mode(struct ice_hw *hw)
* mode as the PF may not have the privilege to set some of the PHY Config
* parameters. This status will be indicated by the command response (0x0601).
*/
-static enum ice_status
+enum ice_status
ice_aq_set_phy_cfg(struct ice_hw *hw, u8 lport,
struct ice_aqc_set_phy_cfg_data *cfg, struct ice_sq_cd *cd)
{
- struct ice_aqc_set_phy_cfg *cmd;
struct ice_aq_desc desc;
if (!cfg)
return ICE_ERR_PARAM;
- cmd = &desc.params.set_phy;
ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_phy_cfg);
- cmd->lport_num = lport;
+ desc.params.set_phy.lport_num = lport;
+ desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
return ice_aq_send_cmd(hw, &desc, cfg, sizeof(*cfg), cd);
}
@@ -1339,8 +1813,7 @@ ice_aq_set_phy_cfg(struct ice_hw *hw, u8 lport,
* ice_update_link_info - update status of the HW network link
* @pi: port info structure of the interested logical port
*/
-static enum ice_status
-ice_update_link_info(struct ice_port_info *pi)
+enum ice_status ice_update_link_info(struct ice_port_info *pi)
{
struct ice_aqc_get_phy_caps_data *pcaps;
struct ice_phy_info *phy_info;
@@ -1379,12 +1852,12 @@ out:
* ice_set_fc
* @pi: port information structure
* @aq_failures: pointer to status code, specific to ice_set_fc routine
- * @atomic_restart: enable automatic link update
+ * @ena_auto_link_update: enable automatic link update
*
* Set the requested flow control mode.
*/
enum ice_status
-ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool atomic_restart)
+ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool ena_auto_link_update)
{
struct ice_aqc_set_phy_cfg_data cfg = { 0 };
struct ice_aqc_get_phy_caps_data *pcaps;
@@ -1434,8 +1907,8 @@ ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool atomic_restart)
int retry_count, retry_max = 10;
/* Auto restart link so settings take effect */
- if (atomic_restart)
- cfg.caps |= ICE_AQ_PHY_ENA_ATOMIC_LINK;
+ if (ena_auto_link_update)
+ cfg.caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT;
/* Copy over all the old settings */
cfg.phy_type_low = pcaps->phy_type_low;
cfg.low_power_ctrl = pcaps->low_power_ctrl;
@@ -1535,33 +2008,6 @@ ice_aq_set_link_restart_an(struct ice_port_info *pi, bool ena_link,
}
/**
- * ice_aq_set_event_mask
- * @hw: pointer to the hw struct
- * @port_num: port number of the physical function
- * @mask: event mask to be set
- * @cd: pointer to command details structure or NULL
- *
- * Set event mask (0x0613)
- */
-enum ice_status
-ice_aq_set_event_mask(struct ice_hw *hw, u8 port_num, u16 mask,
- struct ice_sq_cd *cd)
-{
- struct ice_aqc_set_event_mask *cmd;
- struct ice_aq_desc desc;
-
- cmd = &desc.params.set_event_mask;
-
- ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_event_mask);
-
- cmd->lport_num = port_num;
-
- cmd->event_mask = cpu_to_le16(mask);
-
- return ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
-}
-
-/**
* __ice_aq_get_set_rss_lut
* @hw: pointer to the hardware structure
* @vsi_id: VSI FW index
@@ -1654,7 +2100,7 @@ ice_aq_get_set_rss_lut_exit:
/**
* ice_aq_get_rss_lut
* @hw: pointer to the hardware structure
- * @vsi_id: VSI FW index
+ * @vsi_handle: software VSI handle
* @lut_type: LUT table type
* @lut: pointer to the LUT buffer provided by the caller
* @lut_size: size of the LUT buffer
@@ -1662,17 +2108,20 @@ ice_aq_get_set_rss_lut_exit:
* get the RSS lookup table, PF or VSI type
*/
enum ice_status
-ice_aq_get_rss_lut(struct ice_hw *hw, u16 vsi_id, u8 lut_type, u8 *lut,
- u16 lut_size)
+ice_aq_get_rss_lut(struct ice_hw *hw, u16 vsi_handle, u8 lut_type,
+ u8 *lut, u16 lut_size)
{
- return __ice_aq_get_set_rss_lut(hw, vsi_id, lut_type, lut, lut_size, 0,
- false);
+ if (!ice_is_vsi_valid(hw, vsi_handle) || !lut)
+ return ICE_ERR_PARAM;
+
+ return __ice_aq_get_set_rss_lut(hw, ice_get_hw_vsi_num(hw, vsi_handle),
+ lut_type, lut, lut_size, 0, false);
}
/**
* ice_aq_set_rss_lut
* @hw: pointer to the hardware structure
- * @vsi_id: VSI FW index
+ * @vsi_handle: software VSI handle
* @lut_type: LUT table type
* @lut: pointer to the LUT buffer provided by the caller
* @lut_size: size of the LUT buffer
@@ -1680,11 +2129,14 @@ ice_aq_get_rss_lut(struct ice_hw *hw, u16 vsi_id, u8 lut_type, u8 *lut,
* set the RSS lookup table, PF or VSI type
*/
enum ice_status
-ice_aq_set_rss_lut(struct ice_hw *hw, u16 vsi_id, u8 lut_type, u8 *lut,
- u16 lut_size)
+ice_aq_set_rss_lut(struct ice_hw *hw, u16 vsi_handle, u8 lut_type,
+ u8 *lut, u16 lut_size)
{
- return __ice_aq_get_set_rss_lut(hw, vsi_id, lut_type, lut, lut_size, 0,
- true);
+ if (!ice_is_vsi_valid(hw, vsi_handle) || !lut)
+ return ICE_ERR_PARAM;
+
+ return __ice_aq_get_set_rss_lut(hw, ice_get_hw_vsi_num(hw, vsi_handle),
+ lut_type, lut, lut_size, 0, true);
}
/**
@@ -1725,31 +2177,39 @@ ice_status __ice_aq_get_set_rss_key(struct ice_hw *hw, u16 vsi_id,
/**
* ice_aq_get_rss_key
* @hw: pointer to the hw struct
- * @vsi_id: VSI FW index
+ * @vsi_handle: software VSI handle
* @key: pointer to key info struct
*
* get the RSS key per VSI
*/
enum ice_status
-ice_aq_get_rss_key(struct ice_hw *hw, u16 vsi_id,
+ice_aq_get_rss_key(struct ice_hw *hw, u16 vsi_handle,
struct ice_aqc_get_set_rss_keys *key)
{
- return __ice_aq_get_set_rss_key(hw, vsi_id, key, false);
+ if (!ice_is_vsi_valid(hw, vsi_handle) || !key)
+ return ICE_ERR_PARAM;
+
+ return __ice_aq_get_set_rss_key(hw, ice_get_hw_vsi_num(hw, vsi_handle),
+ key, false);
}
/**
* ice_aq_set_rss_key
* @hw: pointer to the hw struct
- * @vsi_id: VSI FW index
+ * @vsi_handle: software VSI handle
* @keys: pointer to key info struct
*
* set the RSS key per VSI
*/
enum ice_status
-ice_aq_set_rss_key(struct ice_hw *hw, u16 vsi_id,
+ice_aq_set_rss_key(struct ice_hw *hw, u16 vsi_handle,
struct ice_aqc_get_set_rss_keys *keys)
{
- return __ice_aq_get_set_rss_key(hw, vsi_id, keys, true);
+ if (!ice_is_vsi_valid(hw, vsi_handle) || !keys)
+ return ICE_ERR_PARAM;
+
+ return __ice_aq_get_set_rss_key(hw, ice_get_hw_vsi_num(hw, vsi_handle),
+ keys, true);
}
/**
@@ -1820,6 +2280,8 @@ ice_aq_add_lan_txq(struct ice_hw *hw, u8 num_qgrps,
* @num_qgrps: number of groups in the list
* @qg_list: the list of groups to disable
* @buf_size: the total size of the qg_list buffer in bytes
+ * @rst_src: if called due to reset, specifies the RST source
+ * @vmvf_num: the relative VM or VF number that is undergoing the reset
* @cd: pointer to command details structure or NULL
*
* Disable LAN Tx queue (0x0C31)
@@ -1827,6 +2289,7 @@ ice_aq_add_lan_txq(struct ice_hw *hw, u8 num_qgrps,
static enum ice_status
ice_aq_dis_lan_txq(struct ice_hw *hw, u8 num_qgrps,
struct ice_aqc_dis_txq_item *qg_list, u16 buf_size,
+ enum ice_disq_rst_src rst_src, u16 vmvf_num,
struct ice_sq_cd *cd)
{
struct ice_aqc_dis_txqs *cmd;
@@ -1836,14 +2299,45 @@ ice_aq_dis_lan_txq(struct ice_hw *hw, u8 num_qgrps,
cmd = &desc.params.dis_txqs;
ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_dis_txqs);
- if (!qg_list)
+ /* qg_list can be NULL only in VM/VF reset flow */
+ if (!qg_list && !rst_src)
return ICE_ERR_PARAM;
if (num_qgrps > ICE_LAN_TXQ_MAX_QGRPS)
return ICE_ERR_PARAM;
- desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
+
cmd->num_entries = num_qgrps;
+ cmd->vmvf_and_timeout = cpu_to_le16((5 << ICE_AQC_Q_DIS_TIMEOUT_S) &
+ ICE_AQC_Q_DIS_TIMEOUT_M);
+
+ switch (rst_src) {
+ case ICE_VM_RESET:
+ cmd->cmd_type = ICE_AQC_Q_DIS_CMD_VM_RESET;
+ cmd->vmvf_and_timeout |=
+ cpu_to_le16(vmvf_num & ICE_AQC_Q_DIS_VMVF_NUM_M);
+ break;
+ case ICE_VF_RESET:
+ cmd->cmd_type = ICE_AQC_Q_DIS_CMD_VF_RESET;
+ /* In this case, FW expects vmvf_num to be absolute VF id */
+ cmd->vmvf_and_timeout |=
+ cpu_to_le16((vmvf_num + hw->func_caps.vf_base_id) &
+ ICE_AQC_Q_DIS_VMVF_NUM_M);
+ break;
+ case ICE_NO_RESET:
+ default:
+ break;
+ }
+
+ /* If no queue group info, we are in a reset flow. Issue the AQ */
+ if (!qg_list)
+ goto do_aq;
+
+ /* set RD bit to indicate that command buffer is provided by the driver
+ * and it needs to be read by the firmware
+ */
+ desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
+
for (i = 0; i < num_qgrps; ++i) {
/* Calculate the size taken up by the queue IDs in this group */
sz += qg_list[i].num_qs * sizeof(qg_list[i].q_id);
@@ -1859,6 +2353,7 @@ ice_aq_dis_lan_txq(struct ice_hw *hw, u8 num_qgrps,
if (buf_size != sz)
return ICE_ERR_PARAM;
+do_aq:
return ice_aq_send_cmd(hw, &desc, qg_list, buf_size, cd);
}
@@ -2088,7 +2583,7 @@ ice_set_ctx(u8 *src_ctx, u8 *dest_ctx, const struct ice_ctx_ele *ce_info)
/**
* ice_ena_vsi_txq
* @pi: port information structure
- * @vsi_id: VSI id
+ * @vsi_handle: software VSI handle
* @tc: tc number
* @num_qgrps: Number of added queue groups
* @buf: list of queue groups to be added
@@ -2098,7 +2593,7 @@ ice_set_ctx(u8 *src_ctx, u8 *dest_ctx, const struct ice_ctx_ele *ce_info)
* This function adds one lan q
*/
enum ice_status
-ice_ena_vsi_txq(struct ice_port_info *pi, u16 vsi_id, u8 tc, u8 num_qgrps,
+ice_ena_vsi_txq(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u8 num_qgrps,
struct ice_aqc_add_tx_qgrp *buf, u16 buf_size,
struct ice_sq_cd *cd)
{
@@ -2115,15 +2610,19 @@ ice_ena_vsi_txq(struct ice_port_info *pi, u16 vsi_id, u8 tc, u8 num_qgrps,
hw = pi->hw;
+ if (!ice_is_vsi_valid(hw, vsi_handle))
+ return ICE_ERR_PARAM;
+
mutex_lock(&pi->sched_lock);
/* find a parent node */
- parent = ice_sched_get_free_qparent(pi, vsi_id, tc,
+ parent = ice_sched_get_free_qparent(pi, vsi_handle, tc,
ICE_SCHED_NODE_OWNER_LAN);
if (!parent) {
status = ICE_ERR_PARAM;
goto ena_txq_exit;
}
+
buf->parent_teid = parent->info.node_teid;
node.parent_teid = parent->info.node_teid;
/* Mark that the values in the "generic" section as valid. The default
@@ -2161,13 +2660,16 @@ ena_txq_exit:
* @num_queues: number of queues
* @q_ids: pointer to the q_id array
* @q_teids: pointer to queue node teids
+ * @rst_src: if called due to reset, specifies the RST source
+ * @vmvf_num: the relative VM or VF number that is undergoing the reset
* @cd: pointer to command details structure or NULL
*
* This function removes queues and their corresponding nodes in SW DB
*/
enum ice_status
ice_dis_vsi_txq(struct ice_port_info *pi, u8 num_queues, u16 *q_ids,
- u32 *q_teids, struct ice_sq_cd *cd)
+ u32 *q_teids, enum ice_disq_rst_src rst_src, u16 vmvf_num,
+ struct ice_sq_cd *cd)
{
enum ice_status status = ICE_ERR_DOES_NOT_EXIST;
struct ice_aqc_dis_txq_item qg_list;
@@ -2176,6 +2678,15 @@ ice_dis_vsi_txq(struct ice_port_info *pi, u8 num_queues, u16 *q_ids,
if (!pi || pi->port_state != ICE_SCHED_PORT_STATE_READY)
return ICE_ERR_CFG;
+ /* if queue is disabled already yet the disable queue command has to be
+ * sent to complete the VF reset, then call ice_aq_dis_lan_txq without
+ * any queue information
+ */
+
+ if (!num_queues && rst_src)
+ return ice_aq_dis_lan_txq(pi->hw, 0, NULL, 0, rst_src, vmvf_num,
+ NULL);
+
mutex_lock(&pi->sched_lock);
for (i = 0; i < num_queues; i++) {
@@ -2188,7 +2699,8 @@ ice_dis_vsi_txq(struct ice_port_info *pi, u8 num_queues, u16 *q_ids,
qg_list.num_qs = 1;
qg_list.q_id[0] = cpu_to_le16(q_ids[i]);
status = ice_aq_dis_lan_txq(pi->hw, 1, &qg_list,
- sizeof(qg_list), cd);
+ sizeof(qg_list), rst_src, vmvf_num,
+ cd);
if (status)
break;
@@ -2201,7 +2713,7 @@ ice_dis_vsi_txq(struct ice_port_info *pi, u8 num_queues, u16 *q_ids,
/**
* ice_cfg_vsi_qs - configure the new/exisiting VSI queues
* @pi: port information structure
- * @vsi_id: VSI Id
+ * @vsi_handle: software VSI handle
* @tc_bitmap: TC bitmap
* @maxqs: max queues array per TC
* @owner: lan or rdma
@@ -2209,7 +2721,7 @@ ice_dis_vsi_txq(struct ice_port_info *pi, u8 num_queues, u16 *q_ids,
* This function adds/updates the VSI queues per TC.
*/
static enum ice_status
-ice_cfg_vsi_qs(struct ice_port_info *pi, u16 vsi_id, u8 tc_bitmap,
+ice_cfg_vsi_qs(struct ice_port_info *pi, u16 vsi_handle, u8 tc_bitmap,
u16 *maxqs, u8 owner)
{
enum ice_status status = 0;
@@ -2218,6 +2730,9 @@ ice_cfg_vsi_qs(struct ice_port_info *pi, u16 vsi_id, u8 tc_bitmap,
if (!pi || pi->port_state != ICE_SCHED_PORT_STATE_READY)
return ICE_ERR_CFG;
+ if (!ice_is_vsi_valid(pi->hw, vsi_handle))
+ return ICE_ERR_PARAM;
+
mutex_lock(&pi->sched_lock);
for (i = 0; i < ICE_MAX_TRAFFIC_CLASS; i++) {
@@ -2225,7 +2740,7 @@ ice_cfg_vsi_qs(struct ice_port_info *pi, u16 vsi_id, u8 tc_bitmap,
if (!ice_sched_get_tc_node(pi, i))
continue;
- status = ice_sched_cfg_vsi(pi, vsi_id, i, maxqs[i], owner,
+ status = ice_sched_cfg_vsi(pi, vsi_handle, i, maxqs[i], owner,
ice_is_tc_ena(tc_bitmap, i));
if (status)
break;
@@ -2238,16 +2753,140 @@ ice_cfg_vsi_qs(struct ice_port_info *pi, u16 vsi_id, u8 tc_bitmap,
/**
* ice_cfg_vsi_lan - configure VSI lan queues
* @pi: port information structure
- * @vsi_id: VSI Id
+ * @vsi_handle: software VSI handle
* @tc_bitmap: TC bitmap
* @max_lanqs: max lan queues array per TC
*
* This function adds/updates the VSI lan queues per TC.
*/
enum ice_status
-ice_cfg_vsi_lan(struct ice_port_info *pi, u16 vsi_id, u8 tc_bitmap,
+ice_cfg_vsi_lan(struct ice_port_info *pi, u16 vsi_handle, u8 tc_bitmap,
u16 *max_lanqs)
{
- return ice_cfg_vsi_qs(pi, vsi_id, tc_bitmap, max_lanqs,
+ return ice_cfg_vsi_qs(pi, vsi_handle, tc_bitmap, max_lanqs,
ICE_SCHED_NODE_OWNER_LAN);
}
+
+/**
+ * ice_replay_pre_init - replay pre initialization
+ * @hw: pointer to the hw struct
+ *
+ * Initializes required config data for VSI, FD, ACL, and RSS before replay.
+ */
+static enum ice_status ice_replay_pre_init(struct ice_hw *hw)
+{
+ struct ice_switch_info *sw = hw->switch_info;
+ u8 i;
+
+ /* Delete old entries from replay filter list head if there is any */
+ ice_rm_all_sw_replay_rule_info(hw);
+ /* In start of replay, move entries into replay_rules list, it
+ * will allow adding rules entries back to filt_rules list,
+ * which is operational list.
+ */
+ for (i = 0; i < ICE_SW_LKUP_LAST; i++)
+ list_replace_init(&sw->recp_list[i].filt_rules,
+ &sw->recp_list[i].filt_replay_rules);
+
+ return 0;
+}
+
+/**
+ * ice_replay_vsi - replay VSI configuration
+ * @hw: pointer to the hw struct
+ * @vsi_handle: driver VSI handle
+ *
+ * Restore all VSI configuration after reset. It is required to call this
+ * function with main VSI first.
+ */
+enum ice_status ice_replay_vsi(struct ice_hw *hw, u16 vsi_handle)
+{
+ enum ice_status status;
+
+ if (!ice_is_vsi_valid(hw, vsi_handle))
+ return ICE_ERR_PARAM;
+
+ /* Replay pre-initialization if there is any */
+ if (vsi_handle == ICE_MAIN_VSI_HANDLE) {
+ status = ice_replay_pre_init(hw);
+ if (status)
+ return status;
+ }
+
+ /* Replay per VSI all filters */
+ status = ice_replay_vsi_all_fltr(hw, vsi_handle);
+ return status;
+}
+
+/**
+ * ice_replay_post - post replay configuration cleanup
+ * @hw: pointer to the hw struct
+ *
+ * Post replay cleanup.
+ */
+void ice_replay_post(struct ice_hw *hw)
+{
+ /* Delete old entries from replay filter list head */
+ ice_rm_all_sw_replay_rule_info(hw);
+}
+
+/**
+ * ice_stat_update40 - read 40 bit stat from the chip and update stat values
+ * @hw: ptr to the hardware info
+ * @hireg: high 32 bit HW register to read from
+ * @loreg: low 32 bit HW register to read from
+ * @prev_stat_loaded: bool to specify if previous stats are loaded
+ * @prev_stat: ptr to previous loaded stat value
+ * @cur_stat: ptr to current stat value
+ */
+void ice_stat_update40(struct ice_hw *hw, u32 hireg, u32 loreg,
+ bool prev_stat_loaded, u64 *prev_stat, u64 *cur_stat)
+{
+ u64 new_data;
+
+ new_data = rd32(hw, loreg);
+ new_data |= ((u64)(rd32(hw, hireg) & 0xFFFF)) << 32;
+
+ /* device stats are not reset at PFR, they likely will not be zeroed
+ * when the driver starts. So save the first values read and use them as
+ * offsets to be subtracted from the raw values in order to report stats
+ * that count from zero.
+ */
+ if (!prev_stat_loaded)
+ *prev_stat = new_data;
+ if (new_data >= *prev_stat)
+ *cur_stat = new_data - *prev_stat;
+ else
+ /* to manage the potential roll-over */
+ *cur_stat = (new_data + BIT_ULL(40)) - *prev_stat;
+ *cur_stat &= 0xFFFFFFFFFFULL;
+}
+
+/**
+ * ice_stat_update32 - read 32 bit stat from the chip and update stat values
+ * @hw: ptr to the hardware info
+ * @reg: HW register to read from
+ * @prev_stat_loaded: bool to specify if previous stats are loaded
+ * @prev_stat: ptr to previous loaded stat value
+ * @cur_stat: ptr to current stat value
+ */
+void ice_stat_update32(struct ice_hw *hw, u32 reg, bool prev_stat_loaded,
+ u64 *prev_stat, u64 *cur_stat)
+{
+ u32 new_data;
+
+ new_data = rd32(hw, reg);
+
+ /* device stats are not reset at PFR, they likely will not be zeroed
+ * when the driver starts. So save the first values read and use them as
+ * offsets to be subtracted from the raw values in order to report stats
+ * that count from zero.
+ */
+ if (!prev_stat_loaded)
+ *prev_stat = new_data;
+ if (new_data >= *prev_stat)
+ *cur_stat = new_data - *prev_stat;
+ else
+ /* to manage the potential roll-over */
+ *cur_stat = (new_data + BIT_ULL(32)) - *prev_stat;
+}
diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h
index 9a5519130af1..cf760c24a6aa 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.h
+++ b/drivers/net/ethernet/intel/ice/ice_common.h
@@ -7,6 +7,7 @@
#include "ice.h"
#include "ice_type.h"
#include "ice_switch.h"
+#include <linux/avf/virtchnl.h>
void ice_debug_cq(struct ice_hw *hw, u32 mask, void *desc, void *buf,
u16 buf_len);
@@ -21,9 +22,10 @@ ice_clean_rq_elem(struct ice_hw *hw, struct ice_ctl_q_info *cq,
struct ice_rq_event_info *e, u16 *pending);
enum ice_status
ice_get_link_status(struct ice_port_info *pi, bool *link_up);
+enum ice_status ice_update_link_info(struct ice_port_info *pi);
enum ice_status
ice_acquire_res(struct ice_hw *hw, enum ice_aq_res_ids res,
- enum ice_aq_res_access_type access);
+ enum ice_aq_res_access_type access, u32 timeout);
void ice_release_res(struct ice_hw *hw, enum ice_aq_res_ids res);
enum ice_status ice_init_nvm(struct ice_hw *hw);
enum ice_status
@@ -32,22 +34,26 @@ ice_sq_send_cmd(struct ice_hw *hw, struct ice_ctl_q_info *cq,
struct ice_sq_cd *cd);
void ice_clear_pxe_mode(struct ice_hw *hw);
enum ice_status ice_get_caps(struct ice_hw *hw);
+
+void ice_dev_onetime_setup(struct ice_hw *hw);
+
enum ice_status
ice_write_rxq_ctx(struct ice_hw *hw, struct ice_rlan_ctx *rlan_ctx,
u32 rxq_index);
enum ice_status
-ice_aq_get_rss_lut(struct ice_hw *hw, u16 vsi_id, u8 lut_type, u8 *lut,
+ice_aq_get_rss_lut(struct ice_hw *hw, u16 vsi_handle, u8 lut_type, u8 *lut,
u16 lut_size);
enum ice_status
-ice_aq_set_rss_lut(struct ice_hw *hw, u16 vsi_id, u8 lut_type, u8 *lut,
+ice_aq_set_rss_lut(struct ice_hw *hw, u16 vsi_handle, u8 lut_type, u8 *lut,
u16 lut_size);
enum ice_status
-ice_aq_get_rss_key(struct ice_hw *hw, u16 vsi_id,
+ice_aq_get_rss_key(struct ice_hw *hw, u16 vsi_handle,
struct ice_aqc_get_set_rss_keys *keys);
enum ice_status
-ice_aq_set_rss_key(struct ice_hw *hw, u16 vsi_id,
+ice_aq_set_rss_key(struct ice_hw *hw, u16 vsi_handle,
struct ice_aqc_get_set_rss_keys *keys);
+
bool ice_check_sq_alive(struct ice_hw *hw, struct ice_ctl_q_info *cq);
enum ice_status ice_aq_q_shutdown(struct ice_hw *hw, bool unloading);
void ice_fill_dflt_direct_cmd_desc(struct ice_aq_desc *desc, u16 opcode);
@@ -58,29 +64,43 @@ enum ice_status
ice_aq_send_cmd(struct ice_hw *hw, struct ice_aq_desc *desc,
void *buf, u16 buf_size, struct ice_sq_cd *cd);
enum ice_status ice_aq_get_fw_ver(struct ice_hw *hw, struct ice_sq_cd *cd);
+
+enum ice_status
+ice_aq_get_phy_caps(struct ice_port_info *pi, bool qual_mods, u8 report_mode,
+ struct ice_aqc_get_phy_caps_data *caps,
+ struct ice_sq_cd *cd);
+void
+ice_update_phy_type(u64 *phy_type_low, u16 link_speeds_bitmap);
enum ice_status
ice_aq_manage_mac_write(struct ice_hw *hw, u8 *mac_addr, u8 flags,
struct ice_sq_cd *cd);
enum ice_status ice_clear_pf_cfg(struct ice_hw *hw);
enum ice_status
-ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool atomic_restart);
+ice_aq_set_phy_cfg(struct ice_hw *hw, u8 lport,
+ struct ice_aqc_set_phy_cfg_data *cfg, struct ice_sq_cd *cd);
+enum ice_status
+ice_set_fc(struct ice_port_info *pi, u8 *aq_failures,
+ bool ena_auto_link_update);
+
enum ice_status
ice_aq_set_link_restart_an(struct ice_port_info *pi, bool ena_link,
struct ice_sq_cd *cd);
enum ice_status
-ice_aq_get_link_info(struct ice_port_info *pi, bool ena_lse,
- struct ice_link_status *link, struct ice_sq_cd *cd);
-enum ice_status
-ice_aq_set_event_mask(struct ice_hw *hw, u8 port_num, u16 mask,
- struct ice_sq_cd *cd);
-enum ice_status
ice_dis_vsi_txq(struct ice_port_info *pi, u8 num_queues, u16 *q_ids,
- u32 *q_teids, struct ice_sq_cd *cmd_details);
+ u32 *q_teids, enum ice_disq_rst_src rst_src, u16 vmvf_num,
+ struct ice_sq_cd *cmd_details);
enum ice_status
-ice_cfg_vsi_lan(struct ice_port_info *pi, u16 vsi_id, u8 tc_bitmap,
+ice_cfg_vsi_lan(struct ice_port_info *pi, u16 vsi_handle, u8 tc_bitmap,
u16 *max_lanqs);
enum ice_status
-ice_ena_vsi_txq(struct ice_port_info *pi, u16 vsi_id, u8 tc, u8 num_qgrps,
+ice_ena_vsi_txq(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u8 num_qgrps,
struct ice_aqc_add_tx_qgrp *buf, u16 buf_size,
struct ice_sq_cd *cd);
+enum ice_status ice_replay_vsi(struct ice_hw *hw, u16 vsi_handle);
+void ice_replay_post(struct ice_hw *hw);
+void ice_output_fw_log(struct ice_hw *hw, struct ice_aq_desc *desc, void *buf);
+void ice_stat_update40(struct ice_hw *hw, u32 hireg, u32 loreg,
+ bool prev_stat_loaded, u64 *prev_stat, u64 *cur_stat);
+void ice_stat_update32(struct ice_hw *hw, u32 reg, bool prev_stat_loaded,
+ u64 *prev_stat, u64 *cur_stat);
#endif /* _ICE_COMMON_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_controlq.c b/drivers/net/ethernet/intel/ice/ice_controlq.c
index 62be72fdc8f3..84c967294eaf 100644
--- a/drivers/net/ethernet/intel/ice/ice_controlq.c
+++ b/drivers/net/ethernet/intel/ice/ice_controlq.c
@@ -33,6 +33,36 @@ static void ice_adminq_init_regs(struct ice_hw *hw)
}
/**
+ * ice_mailbox_init_regs - Initialize Mailbox registers
+ * @hw: pointer to the hardware structure
+ *
+ * This assumes the alloc_sq and alloc_rq functions have already been called
+ */
+static void ice_mailbox_init_regs(struct ice_hw *hw)
+{
+ struct ice_ctl_q_info *cq = &hw->mailboxq;
+
+ /* set head and tail registers in our local struct */
+ cq->sq.head = PF_MBX_ATQH;
+ cq->sq.tail = PF_MBX_ATQT;
+ cq->sq.len = PF_MBX_ATQLEN;
+ cq->sq.bah = PF_MBX_ATQBAH;
+ cq->sq.bal = PF_MBX_ATQBAL;
+ cq->sq.len_mask = PF_MBX_ATQLEN_ATQLEN_M;
+ cq->sq.len_ena_mask = PF_MBX_ATQLEN_ATQENABLE_M;
+ cq->sq.head_mask = PF_MBX_ATQH_ATQH_M;
+
+ cq->rq.head = PF_MBX_ARQH;
+ cq->rq.tail = PF_MBX_ARQT;
+ cq->rq.len = PF_MBX_ARQLEN;
+ cq->rq.bah = PF_MBX_ARQBAH;
+ cq->rq.bal = PF_MBX_ARQBAL;
+ cq->rq.len_mask = PF_MBX_ARQLEN_ARQLEN_M;
+ cq->rq.len_ena_mask = PF_MBX_ARQLEN_ARQENABLE_M;
+ cq->rq.head_mask = PF_MBX_ARQH_ARQH_M;
+}
+
+/**
* ice_check_sq_alive
* @hw: pointer to the hw struct
* @cq: pointer to the specific Control queue
@@ -518,22 +548,31 @@ shutdown_sq_out:
/**
* ice_aq_ver_check - Check the reported AQ API version.
- * @fw_branch: The "branch" of FW, typically describes the device type
- * @fw_major: The major version of the FW API
- * @fw_minor: The minor version increment of the FW API
+ * @hw: pointer to the hardware structure
*
* Checks if the driver should load on a given AQ API version.
*
* Return: 'true' iff the driver should attempt to load. 'false' otherwise.
*/
-static bool ice_aq_ver_check(u8 fw_branch, u8 fw_major, u8 fw_minor)
+static bool ice_aq_ver_check(struct ice_hw *hw)
{
- if (fw_branch != EXP_FW_API_VER_BRANCH)
- return false;
- if (fw_major != EXP_FW_API_VER_MAJOR)
- return false;
- if (fw_minor != EXP_FW_API_VER_MINOR)
+ if (hw->api_maj_ver > EXP_FW_API_VER_MAJOR) {
+ /* Major API version is newer than expected, don't load */
+ dev_warn(ice_hw_to_dev(hw),
+ "The driver for the device stopped because the NVM image is newer than expected. You must install the most recent version of the network driver.\n");
return false;
+ } else if (hw->api_maj_ver == EXP_FW_API_VER_MAJOR) {
+ if (hw->api_min_ver > (EXP_FW_API_VER_MINOR + 2))
+ dev_info(ice_hw_to_dev(hw),
+ "The driver for the device detected a newer version of the NVM image than expected. Please install the most recent version of the network driver.\n");
+ else if ((hw->api_min_ver + 2) < EXP_FW_API_VER_MINOR)
+ dev_info(ice_hw_to_dev(hw),
+ "The driver for the device detected an older version of the NVM image than expected. Please update the NVM image.\n");
+ } else {
+ /* Major API version is older than expected, log a warning */
+ dev_info(ice_hw_to_dev(hw),
+ "The driver for the device detected an older version of the NVM image than expected. Please update the NVM image.\n");
+ }
return true;
}
@@ -588,8 +627,7 @@ static enum ice_status ice_init_check_adminq(struct ice_hw *hw)
if (status)
goto init_ctrlq_free_rq;
- if (!ice_aq_ver_check(hw->api_branch, hw->api_maj_ver,
- hw->api_min_ver)) {
+ if (!ice_aq_ver_check(hw)) {
status = ICE_ERR_FW_API_VER;
goto init_ctrlq_free_rq;
}
@@ -597,11 +635,11 @@ static enum ice_status ice_init_check_adminq(struct ice_hw *hw)
return 0;
init_ctrlq_free_rq:
- if (cq->rq.head) {
+ if (cq->rq.count) {
ice_shutdown_rq(hw, cq);
mutex_destroy(&cq->rq_lock);
}
- if (cq->sq.head) {
+ if (cq->sq.count) {
ice_shutdown_sq(hw, cq);
mutex_destroy(&cq->sq_lock);
}
@@ -631,6 +669,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_MAILBOX:
+ ice_mailbox_init_regs(hw);
+ cq = &hw->mailboxq;
+ break;
default:
return ICE_ERR_PARAM;
}
@@ -688,7 +730,12 @@ enum ice_status ice_init_all_ctrlq(struct ice_hw *hw)
if (ret_code)
return ret_code;
- return ice_init_check_adminq(hw);
+ ret_code = ice_init_check_adminq(hw);
+ if (ret_code)
+ return ret_code;
+
+ /* Init Mailbox queue */
+ return ice_init_ctrlq(hw, ICE_CTL_Q_MAILBOX);
}
/**
@@ -706,15 +753,18 @@ 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_MAILBOX:
+ cq = &hw->mailboxq;
+ break;
default:
return;
}
- if (cq->sq.head) {
+ if (cq->sq.count) {
ice_shutdown_sq(hw, cq);
mutex_destroy(&cq->sq_lock);
}
- if (cq->rq.head) {
+ if (cq->rq.count) {
ice_shutdown_rq(hw, cq);
mutex_destroy(&cq->rq_lock);
}
@@ -728,6 +778,8 @@ void ice_shutdown_all_ctrlq(struct ice_hw *hw)
{
/* Shutdown FW admin queue */
ice_shutdown_ctrlq(hw, ICE_CTL_Q_ADMIN);
+ /* Shutdown PF-VF Mailbox */
+ ice_shutdown_ctrlq(hw, ICE_CTL_Q_MAILBOX);
}
/**
@@ -806,6 +858,9 @@ ice_sq_send_cmd(struct ice_hw *hw, struct ice_ctl_q_info *cq,
u16 retval = 0;
u32 val = 0;
+ /* if reset is in progress return a soft error */
+ if (hw->reset_ongoing)
+ return ICE_ERR_RESET_ONGOING;
mutex_lock(&cq->sq_lock);
cq->sq_last_status = ICE_AQ_RC_OK;
@@ -847,7 +902,7 @@ ice_sq_send_cmd(struct ice_hw *hw, struct ice_ctl_q_info *cq,
details = ICE_CTL_Q_DETAILS(cq->sq, cq->sq.next_to_use);
if (cd)
- memcpy(details, cd, sizeof(*details));
+ *details = *cd;
else
memset(details, 0, sizeof(*details));
diff --git a/drivers/net/ethernet/intel/ice/ice_controlq.h b/drivers/net/ethernet/intel/ice/ice_controlq.h
index ea02b89243e2..0038a4109c99 100644
--- a/drivers/net/ethernet/intel/ice/ice_controlq.h
+++ b/drivers/net/ethernet/intel/ice/ice_controlq.h
@@ -8,6 +8,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_CTL_Q_DESC(R, i) \
(&(((struct ice_aq_desc *)((R).desc_buf.va))[i]))
@@ -18,16 +19,16 @@
/* Defines that help manage the driver vs FW API checks.
* Take a look at ice_aq_ver_check in ice_controlq.c for actual usage.
- *
*/
#define EXP_FW_API_VER_BRANCH 0x00
-#define EXP_FW_API_VER_MAJOR 0x00
-#define EXP_FW_API_VER_MINOR 0x01
+#define EXP_FW_API_VER_MAJOR 0x01
+#define EXP_FW_API_VER_MINOR 0x03
/* Different control queue types: These are mainly for SW consumption. */
enum ice_ctl_q {
ICE_CTL_Q_UNKNOWN = 0,
ICE_CTL_Q_ADMIN,
+ ICE_CTL_Q_MAILBOX,
};
/* Control Queue default settings */
diff --git a/drivers/net/ethernet/intel/ice/ice_devids.h b/drivers/net/ethernet/intel/ice/ice_devids.h
index 0e14d7215a6e..f8d5c661d0ba 100644
--- a/drivers/net/ethernet/intel/ice/ice_devids.h
+++ b/drivers/net/ethernet/intel/ice/ice_devids.h
@@ -5,15 +5,11 @@
#define _ICE_DEVIDS_H_
/* Device IDs */
-/* Intel(R) Ethernet Controller C810 for backplane */
-#define ICE_DEV_ID_C810_BACKPLANE 0x1591
-/* Intel(R) Ethernet Controller C810 for QSFP */
-#define ICE_DEV_ID_C810_QSFP 0x1592
-/* Intel(R) Ethernet Controller C810 for SFP */
-#define ICE_DEV_ID_C810_SFP 0x1593
-/* Intel(R) Ethernet Controller C810/X557-AT 10GBASE-T */
-#define ICE_DEV_ID_C810_10G_BASE_T 0x1594
-/* Intel(R) Ethernet Controller C810 1GbE */
-#define ICE_DEV_ID_C810_SGMII 0x1595
+/* Intel(R) Ethernet Controller E810-C for backplane */
+#define ICE_DEV_ID_E810C_BACKPLANE 0x1591
+/* Intel(R) Ethernet Controller E810-C for QSFP */
+#define ICE_DEV_ID_E810C_QSFP 0x1592
+/* Intel(R) Ethernet Controller E810-C for SFP */
+#define ICE_DEV_ID_E810C_SFP 0x1593
#endif /* _ICE_DEVIDS_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c
index c71a9b528d6d..648acdb4c644 100644
--- a/drivers/net/ethernet/intel/ice/ice_ethtool.c
+++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c
@@ -332,58 +332,473 @@ ice_get_ethtool_stats(struct net_device *netdev,
}
}
-static int
-ice_get_link_ksettings(struct net_device *netdev,
- struct ethtool_link_ksettings *ks)
+/**
+ * ice_phy_type_to_ethtool - convert the phy_types to ethtool link modes
+ * @netdev: network interface device structure
+ * @ks: ethtool link ksettings struct to fill out
+ */
+static void ice_phy_type_to_ethtool(struct net_device *netdev,
+ struct ethtool_link_ksettings *ks)
{
struct ice_netdev_priv *np = netdev_priv(netdev);
struct ice_link_status *hw_link_info;
struct ice_vsi *vsi = np->vsi;
- bool link_up;
+ u64 phy_types_low;
hw_link_info = &vsi->port_info->phy.link_info;
- link_up = hw_link_info->link_info & ICE_AQ_LINK_UP;
+ phy_types_low = vsi->port_info->phy.phy_type_low;
+
+ ethtool_link_ksettings_zero_link_mode(ks, supported);
+ ethtool_link_ksettings_zero_link_mode(ks, advertising);
+
+ if (phy_types_low & ICE_PHY_TYPE_LOW_100BASE_TX ||
+ phy_types_low & ICE_PHY_TYPE_LOW_100M_SGMII) {
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 100baseT_Full);
+ if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_100MB)
+ ethtool_link_ksettings_add_link_mode(ks, advertising,
+ 100baseT_Full);
+ }
+ if (phy_types_low & ICE_PHY_TYPE_LOW_1000BASE_T ||
+ phy_types_low & ICE_PHY_TYPE_LOW_1G_SGMII) {
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 1000baseT_Full);
+ if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_1000MB)
+ ethtool_link_ksettings_add_link_mode(ks, advertising,
+ 1000baseT_Full);
+ }
+ if (phy_types_low & ICE_PHY_TYPE_LOW_1000BASE_KX) {
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 1000baseKX_Full);
+ if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_1000MB)
+ ethtool_link_ksettings_add_link_mode(ks, advertising,
+ 1000baseKX_Full);
+ }
+ if (phy_types_low & ICE_PHY_TYPE_LOW_1000BASE_SX ||
+ phy_types_low & ICE_PHY_TYPE_LOW_1000BASE_LX) {
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 1000baseX_Full);
+ if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_1000MB)
+ ethtool_link_ksettings_add_link_mode(ks, advertising,
+ 1000baseX_Full);
+ }
+ if (phy_types_low & ICE_PHY_TYPE_LOW_2500BASE_T) {
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 2500baseT_Full);
+ if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_2500MB)
+ ethtool_link_ksettings_add_link_mode(ks, advertising,
+ 2500baseT_Full);
+ }
+ if (phy_types_low & ICE_PHY_TYPE_LOW_2500BASE_X ||
+ phy_types_low & ICE_PHY_TYPE_LOW_2500BASE_KX) {
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 2500baseX_Full);
+ if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_2500MB)
+ ethtool_link_ksettings_add_link_mode(ks, advertising,
+ 2500baseX_Full);
+ }
+ if (phy_types_low & ICE_PHY_TYPE_LOW_5GBASE_T ||
+ phy_types_low & ICE_PHY_TYPE_LOW_5GBASE_KR) {
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 5000baseT_Full);
+ if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_5GB)
+ ethtool_link_ksettings_add_link_mode(ks, advertising,
+ 5000baseT_Full);
+ }
+ if (phy_types_low & ICE_PHY_TYPE_LOW_10GBASE_T ||
+ phy_types_low & ICE_PHY_TYPE_LOW_10G_SFI_DA ||
+ phy_types_low & ICE_PHY_TYPE_LOW_10G_SFI_AOC_ACC ||
+ phy_types_low & ICE_PHY_TYPE_LOW_10G_SFI_C2C) {
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 10000baseT_Full);
+ if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_10GB)
+ ethtool_link_ksettings_add_link_mode(ks, advertising,
+ 10000baseT_Full);
+ }
+ if (phy_types_low & ICE_PHY_TYPE_LOW_10GBASE_KR_CR1) {
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 10000baseKR_Full);
+ if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_10GB)
+ ethtool_link_ksettings_add_link_mode(ks, advertising,
+ 10000baseKR_Full);
+ }
+ if (phy_types_low & ICE_PHY_TYPE_LOW_10GBASE_SR) {
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 10000baseSR_Full);
+ if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_10GB)
+ ethtool_link_ksettings_add_link_mode(ks, advertising,
+ 10000baseSR_Full);
+ }
+ if (phy_types_low & ICE_PHY_TYPE_LOW_10GBASE_LR) {
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 10000baseLR_Full);
+ if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_10GB)
+ ethtool_link_ksettings_add_link_mode(ks, advertising,
+ 10000baseLR_Full);
+ }
+ if (phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_T ||
+ phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_CR ||
+ phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_CR_S ||
+ phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_CR1 ||
+ phy_types_low & ICE_PHY_TYPE_LOW_25G_AUI_AOC_ACC ||
+ phy_types_low & ICE_PHY_TYPE_LOW_25G_AUI_C2C) {
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 25000baseCR_Full);
+ if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_25GB)
+ ethtool_link_ksettings_add_link_mode(ks, advertising,
+ 25000baseCR_Full);
+ }
+ if (phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_SR ||
+ phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_LR) {
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 25000baseSR_Full);
+ if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_25GB)
+ ethtool_link_ksettings_add_link_mode(ks, advertising,
+ 25000baseSR_Full);
+ }
+ if (phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_KR ||
+ phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_KR_S ||
+ phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_KR1) {
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 25000baseKR_Full);
+ if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_25GB)
+ ethtool_link_ksettings_add_link_mode(ks, advertising,
+ 25000baseKR_Full);
+ }
+ if (phy_types_low & ICE_PHY_TYPE_LOW_40GBASE_KR4) {
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 40000baseKR4_Full);
+ if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_40GB)
+ ethtool_link_ksettings_add_link_mode(ks, advertising,
+ 40000baseKR4_Full);
+ }
+ if (phy_types_low & ICE_PHY_TYPE_LOW_40GBASE_CR4 ||
+ phy_types_low & ICE_PHY_TYPE_LOW_40G_XLAUI_AOC_ACC ||
+ phy_types_low & ICE_PHY_TYPE_LOW_40G_XLAUI) {
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 40000baseCR4_Full);
+ if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_40GB)
+ ethtool_link_ksettings_add_link_mode(ks, advertising,
+ 40000baseCR4_Full);
+ }
+ if (phy_types_low & ICE_PHY_TYPE_LOW_40GBASE_SR4) {
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 40000baseSR4_Full);
+ if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_40GB)
+ ethtool_link_ksettings_add_link_mode(ks, advertising,
+ 40000baseSR4_Full);
+ }
+ if (phy_types_low & ICE_PHY_TYPE_LOW_40GBASE_LR4) {
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 40000baseLR4_Full);
+ if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_40GB)
+ ethtool_link_ksettings_add_link_mode(ks, advertising,
+ 40000baseLR4_Full);
+ }
- ethtool_link_ksettings_add_link_mode(ks, supported,
- 10000baseT_Full);
- ethtool_link_ksettings_add_link_mode(ks, advertising,
- 10000baseT_Full);
+ /* Autoneg PHY types */
+ if (phy_types_low & ICE_PHY_TYPE_LOW_100BASE_TX ||
+ phy_types_low & ICE_PHY_TYPE_LOW_1000BASE_T ||
+ phy_types_low & ICE_PHY_TYPE_LOW_1000BASE_KX ||
+ phy_types_low & ICE_PHY_TYPE_LOW_2500BASE_T ||
+ phy_types_low & ICE_PHY_TYPE_LOW_2500BASE_KX ||
+ phy_types_low & ICE_PHY_TYPE_LOW_5GBASE_T ||
+ phy_types_low & ICE_PHY_TYPE_LOW_5GBASE_KR ||
+ phy_types_low & ICE_PHY_TYPE_LOW_10GBASE_T ||
+ phy_types_low & ICE_PHY_TYPE_LOW_10GBASE_KR_CR1 ||
+ phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_T ||
+ phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_CR ||
+ phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_CR_S ||
+ phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_CR1 ||
+ phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_KR ||
+ phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_KR_S ||
+ phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_KR1 ||
+ phy_types_low & ICE_PHY_TYPE_LOW_40GBASE_CR4 ||
+ phy_types_low & ICE_PHY_TYPE_LOW_40GBASE_KR4) {
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ Autoneg);
+ ethtool_link_ksettings_add_link_mode(ks, advertising,
+ Autoneg);
+ }
+}
- /* set speed and duplex */
- if (link_up) {
- switch (hw_link_info->link_speed) {
- case ICE_AQ_LINK_SPEED_100MB:
- ks->base.speed = SPEED_100;
- break;
- case ICE_AQ_LINK_SPEED_2500MB:
- ks->base.speed = SPEED_2500;
- break;
- case ICE_AQ_LINK_SPEED_5GB:
- ks->base.speed = SPEED_5000;
- break;
- case ICE_AQ_LINK_SPEED_10GB:
- ks->base.speed = SPEED_10000;
- break;
- case ICE_AQ_LINK_SPEED_25GB:
- ks->base.speed = SPEED_25000;
- break;
- case ICE_AQ_LINK_SPEED_40GB:
- ks->base.speed = SPEED_40000;
- break;
- default:
- ks->base.speed = SPEED_UNKNOWN;
- break;
- }
+#define TEST_SET_BITS_TIMEOUT 50
+#define TEST_SET_BITS_SLEEP_MAX 2000
+#define TEST_SET_BITS_SLEEP_MIN 1000
- ks->base.duplex = DUPLEX_FULL;
- } else {
- ks->base.speed = SPEED_UNKNOWN;
- ks->base.duplex = DUPLEX_UNKNOWN;
+/**
+ * ice_get_settings_link_up - Get Link settings for when link is up
+ * @ks: ethtool ksettings to fill in
+ * @netdev: network interface device structure
+ */
+static void ice_get_settings_link_up(struct ethtool_link_ksettings *ks,
+ struct net_device *netdev)
+{
+ struct ice_netdev_priv *np = netdev_priv(netdev);
+ struct ethtool_link_ksettings cap_ksettings;
+ struct ice_link_status *link_info;
+ struct ice_vsi *vsi = np->vsi;
+ bool unrecog_phy_low = false;
+
+ link_info = &vsi->port_info->phy.link_info;
+
+ /* Initialize supported and advertised settings based on phy settings */
+ switch (link_info->phy_type_low) {
+ case ICE_PHY_TYPE_LOW_100BASE_TX:
+ ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 100baseT_Full);
+ ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
+ ethtool_link_ksettings_add_link_mode(ks, advertising,
+ 100baseT_Full);
+ break;
+ case ICE_PHY_TYPE_LOW_100M_SGMII:
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 100baseT_Full);
+ break;
+ case ICE_PHY_TYPE_LOW_1000BASE_T:
+ ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 1000baseT_Full);
+ ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
+ ethtool_link_ksettings_add_link_mode(ks, advertising,
+ 1000baseT_Full);
+ break;
+ case ICE_PHY_TYPE_LOW_1G_SGMII:
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 1000baseT_Full);
+ break;
+ case ICE_PHY_TYPE_LOW_1000BASE_SX:
+ case ICE_PHY_TYPE_LOW_1000BASE_LX:
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 1000baseX_Full);
+ break;
+ case ICE_PHY_TYPE_LOW_1000BASE_KX:
+ ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 1000baseKX_Full);
+ ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
+ ethtool_link_ksettings_add_link_mode(ks, advertising,
+ 1000baseKX_Full);
+ break;
+ case ICE_PHY_TYPE_LOW_2500BASE_T:
+ ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
+ ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 2500baseT_Full);
+ ethtool_link_ksettings_add_link_mode(ks, advertising,
+ 2500baseT_Full);
+ break;
+ case ICE_PHY_TYPE_LOW_2500BASE_X:
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 2500baseX_Full);
+ break;
+ case ICE_PHY_TYPE_LOW_2500BASE_KX:
+ ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 2500baseX_Full);
+ ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
+ ethtool_link_ksettings_add_link_mode(ks, advertising,
+ 2500baseX_Full);
+ break;
+ case ICE_PHY_TYPE_LOW_5GBASE_T:
+ case ICE_PHY_TYPE_LOW_5GBASE_KR:
+ ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 5000baseT_Full);
+ ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
+ ethtool_link_ksettings_add_link_mode(ks, advertising,
+ 5000baseT_Full);
+ break;
+ case ICE_PHY_TYPE_LOW_10GBASE_T:
+ ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 10000baseT_Full);
+ ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
+ ethtool_link_ksettings_add_link_mode(ks, advertising,
+ 10000baseT_Full);
+ break;
+ case ICE_PHY_TYPE_LOW_10G_SFI_DA:
+ case ICE_PHY_TYPE_LOW_10G_SFI_AOC_ACC:
+ case ICE_PHY_TYPE_LOW_10G_SFI_C2C:
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 10000baseT_Full);
+ break;
+ case ICE_PHY_TYPE_LOW_10GBASE_SR:
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 10000baseSR_Full);
+ break;
+ case ICE_PHY_TYPE_LOW_10GBASE_LR:
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 10000baseLR_Full);
+ break;
+ case ICE_PHY_TYPE_LOW_10GBASE_KR_CR1:
+ ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 10000baseKR_Full);
+ ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
+ ethtool_link_ksettings_add_link_mode(ks, advertising,
+ 10000baseKR_Full);
+ break;
+ case ICE_PHY_TYPE_LOW_25GBASE_T:
+ case ICE_PHY_TYPE_LOW_25GBASE_CR:
+ case ICE_PHY_TYPE_LOW_25GBASE_CR_S:
+ case ICE_PHY_TYPE_LOW_25GBASE_CR1:
+ ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 25000baseCR_Full);
+ ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
+ ethtool_link_ksettings_add_link_mode(ks, advertising,
+ 25000baseCR_Full);
+ break;
+ case ICE_PHY_TYPE_LOW_25G_AUI_AOC_ACC:
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 25000baseCR_Full);
+ break;
+ case ICE_PHY_TYPE_LOW_25GBASE_SR:
+ case ICE_PHY_TYPE_LOW_25GBASE_LR:
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 25000baseSR_Full);
+ break;
+ case ICE_PHY_TYPE_LOW_25GBASE_KR:
+ case ICE_PHY_TYPE_LOW_25GBASE_KR1:
+ case ICE_PHY_TYPE_LOW_25GBASE_KR_S:
+ ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 25000baseKR_Full);
+ ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
+ ethtool_link_ksettings_add_link_mode(ks, advertising,
+ 25000baseKR_Full);
+ break;
+ case ICE_PHY_TYPE_LOW_40GBASE_CR4:
+ ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 40000baseCR4_Full);
+ ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
+ ethtool_link_ksettings_add_link_mode(ks, advertising,
+ 40000baseCR4_Full);
+ break;
+ case ICE_PHY_TYPE_LOW_40G_XLAUI_AOC_ACC:
+ case ICE_PHY_TYPE_LOW_40G_XLAUI:
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 40000baseCR4_Full);
+ break;
+ case ICE_PHY_TYPE_LOW_40GBASE_SR4:
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 40000baseSR4_Full);
+ break;
+ case ICE_PHY_TYPE_LOW_40GBASE_LR4:
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 40000baseLR4_Full);
+ break;
+ case ICE_PHY_TYPE_LOW_40GBASE_KR4:
+ ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
+ ethtool_link_ksettings_add_link_mode(ks, supported,
+ 40000baseKR4_Full);
+ ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
+ ethtool_link_ksettings_add_link_mode(ks, advertising,
+ 40000baseKR4_Full);
+ break;
+ default:
+ unrecog_phy_low = true;
+ }
+
+ if (unrecog_phy_low) {
+ /* if we got here and link is up something bad is afoot */
+ netdev_info(netdev, "WARNING: Unrecognized PHY_Low (0x%llx).\n",
+ (u64)link_info->phy_type_low);
+ }
+
+ /* Now that we've worked out everything that could be supported by the
+ * current PHY type, get what is supported by the NVM and intersect
+ * them to get what is truly supported
+ */
+ memset(&cap_ksettings, 0, sizeof(struct ethtool_link_ksettings));
+ ice_phy_type_to_ethtool(netdev, &cap_ksettings);
+ ethtool_intersect_link_masks(ks, &cap_ksettings);
+
+ switch (link_info->link_speed) {
+ case ICE_AQ_LINK_SPEED_40GB:
+ ks->base.speed = SPEED_40000;
+ break;
+ case ICE_AQ_LINK_SPEED_25GB:
+ ks->base.speed = SPEED_25000;
+ break;
+ case ICE_AQ_LINK_SPEED_20GB:
+ ks->base.speed = SPEED_20000;
+ break;
+ case ICE_AQ_LINK_SPEED_10GB:
+ ks->base.speed = SPEED_10000;
+ break;
+ case ICE_AQ_LINK_SPEED_5GB:
+ ks->base.speed = SPEED_5000;
+ break;
+ case ICE_AQ_LINK_SPEED_2500MB:
+ ks->base.speed = SPEED_2500;
+ break;
+ case ICE_AQ_LINK_SPEED_1000MB:
+ ks->base.speed = SPEED_1000;
+ break;
+ case ICE_AQ_LINK_SPEED_100MB:
+ ks->base.speed = SPEED_100;
+ break;
+ default:
+ netdev_info(netdev,
+ "WARNING: Unrecognized link_speed (0x%x).\n",
+ link_info->link_speed);
+ break;
}
+ ks->base.duplex = DUPLEX_FULL;
+}
+
+/**
+ * ice_get_settings_link_down - Get the Link settings when link is down
+ * @ks: ethtool ksettings to fill in
+ * @netdev: network interface device structure
+ *
+ * Reports link settings that can be determined when link is down
+ */
+static void
+ice_get_settings_link_down(struct ethtool_link_ksettings *ks,
+ struct net_device __always_unused *netdev)
+{
+ /* link is down and the driver needs to fall back on
+ * supported phy types to figure out what info to display
+ */
+ ice_phy_type_to_ethtool(netdev, ks);
+
+ /* With no link, speed and duplex are unknown */
+ ks->base.speed = SPEED_UNKNOWN;
+ ks->base.duplex = DUPLEX_UNKNOWN;
+}
+
+/**
+ * ice_get_link_ksettings - Get Link Speed and Duplex settings
+ * @netdev: network interface device structure
+ * @ks: ethtool ksettings
+ *
+ * Reports speed/duplex settings based on media_type
+ */
+static int ice_get_link_ksettings(struct net_device *netdev,
+ struct ethtool_link_ksettings *ks)
+{
+ struct ice_netdev_priv *np = netdev_priv(netdev);
+ struct ice_link_status *hw_link_info;
+ struct ice_vsi *vsi = np->vsi;
+
+ ethtool_link_ksettings_zero_link_mode(ks, supported);
+ ethtool_link_ksettings_zero_link_mode(ks, advertising);
+ hw_link_info = &vsi->port_info->phy.link_info;
+
+ /* set speed and duplex */
+ if (hw_link_info->link_info & ICE_AQ_LINK_UP)
+ ice_get_settings_link_up(ks, netdev);
+ else
+ ice_get_settings_link_down(ks, netdev);
/* set autoneg settings */
- ks->base.autoneg = ((hw_link_info->an_info & ICE_AQ_AN_COMPLETED) ?
- AUTONEG_ENABLE : AUTONEG_DISABLE);
+ ks->base.autoneg = (hw_link_info->an_info & ICE_AQ_AN_COMPLETED) ?
+ AUTONEG_ENABLE : AUTONEG_DISABLE;
/* set media type settings */
switch (vsi->port_info->phy.media_type) {
@@ -442,6 +857,311 @@ ice_get_link_ksettings(struct net_device *netdev,
}
/**
+ * ice_ksettings_find_adv_link_speed - Find advertising link speed
+ * @ks: ethtool ksettings
+ */
+static u16
+ice_ksettings_find_adv_link_speed(const struct ethtool_link_ksettings *ks)
+{
+ u16 adv_link_speed = 0;
+
+ if (ethtool_link_ksettings_test_link_mode(ks, advertising,
+ 100baseT_Full))
+ adv_link_speed |= ICE_AQ_LINK_SPEED_100MB;
+ if (ethtool_link_ksettings_test_link_mode(ks, advertising,
+ 1000baseX_Full))
+ adv_link_speed |= ICE_AQ_LINK_SPEED_1000MB;
+ if (ethtool_link_ksettings_test_link_mode(ks, advertising,
+ 1000baseT_Full) ||
+ ethtool_link_ksettings_test_link_mode(ks, advertising,
+ 1000baseKX_Full))
+ adv_link_speed |= ICE_AQ_LINK_SPEED_1000MB;
+ if (ethtool_link_ksettings_test_link_mode(ks, advertising,
+ 2500baseT_Full))
+ adv_link_speed |= ICE_AQ_LINK_SPEED_2500MB;
+ if (ethtool_link_ksettings_test_link_mode(ks, advertising,
+ 2500baseX_Full))
+ adv_link_speed |= ICE_AQ_LINK_SPEED_2500MB;
+ if (ethtool_link_ksettings_test_link_mode(ks, advertising,
+ 5000baseT_Full))
+ adv_link_speed |= ICE_AQ_LINK_SPEED_5GB;
+ if (ethtool_link_ksettings_test_link_mode(ks, advertising,
+ 10000baseT_Full) ||
+ ethtool_link_ksettings_test_link_mode(ks, advertising,
+ 10000baseKR_Full))
+ adv_link_speed |= ICE_AQ_LINK_SPEED_10GB;
+ if (ethtool_link_ksettings_test_link_mode(ks, advertising,
+ 10000baseSR_Full) ||
+ ethtool_link_ksettings_test_link_mode(ks, advertising,
+ 10000baseLR_Full))
+ adv_link_speed |= ICE_AQ_LINK_SPEED_10GB;
+ if (ethtool_link_ksettings_test_link_mode(ks, advertising,
+ 25000baseCR_Full) ||
+ ethtool_link_ksettings_test_link_mode(ks, advertising,
+ 25000baseSR_Full) ||
+ ethtool_link_ksettings_test_link_mode(ks, advertising,
+ 25000baseKR_Full))
+ adv_link_speed |= ICE_AQ_LINK_SPEED_25GB;
+ if (ethtool_link_ksettings_test_link_mode(ks, advertising,
+ 40000baseCR4_Full) ||
+ ethtool_link_ksettings_test_link_mode(ks, advertising,
+ 40000baseSR4_Full) ||
+ ethtool_link_ksettings_test_link_mode(ks, advertising,
+ 40000baseLR4_Full) ||
+ ethtool_link_ksettings_test_link_mode(ks, advertising,
+ 40000baseKR4_Full))
+ adv_link_speed |= ICE_AQ_LINK_SPEED_40GB;
+
+ return adv_link_speed;
+}
+
+/**
+ * ice_setup_autoneg
+ * @p: port info
+ * @ks: ethtool_link_ksettings
+ * @config: configuration that will be sent down to FW
+ * @autoneg_enabled: autonegotiation is enabled or not
+ * @autoneg_changed: will there a change in autonegotiation
+ * @netdev: network interface device structure
+ *
+ * Setup PHY autonegotiation feature
+ */
+static int
+ice_setup_autoneg(struct ice_port_info *p, struct ethtool_link_ksettings *ks,
+ struct ice_aqc_set_phy_cfg_data *config,
+ u8 autoneg_enabled, u8 *autoneg_changed,
+ struct net_device *netdev)
+{
+ int err = 0;
+
+ *autoneg_changed = 0;
+
+ /* Check autoneg */
+ if (autoneg_enabled == AUTONEG_ENABLE) {
+ /* If autoneg was not already enabled */
+ if (!(p->phy.link_info.an_info & ICE_AQ_AN_COMPLETED)) {
+ /* If autoneg is not supported, return error */
+ if (!ethtool_link_ksettings_test_link_mode(ks,
+ supported,
+ Autoneg)) {
+ netdev_info(netdev, "Autoneg not supported on this phy.\n");
+ err = -EINVAL;
+ } else {
+ /* Autoneg is allowed to change */
+ config->caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT;
+ *autoneg_changed = 1;
+ }
+ }
+ } else {
+ /* If autoneg is currently enabled */
+ if (p->phy.link_info.an_info & ICE_AQ_AN_COMPLETED) {
+ /* If autoneg is supported 10GBASE_T is the only phy
+ * that can disable it, so otherwise return error
+ */
+ if (ethtool_link_ksettings_test_link_mode(ks,
+ supported,
+ Autoneg)) {
+ netdev_info(netdev, "Autoneg cannot be disabled on this phy\n");
+ err = -EINVAL;
+ } else {
+ /* Autoneg is allowed to change */
+ config->caps &= ~ICE_AQ_PHY_ENA_AUTO_LINK_UPDT;
+ *autoneg_changed = 1;
+ }
+ }
+ }
+
+ return err;
+}
+
+/**
+ * ice_set_link_ksettings - Set Speed and Duplex
+ * @netdev: network interface device structure
+ * @ks: ethtool ksettings
+ *
+ * Set speed/duplex per media_types advertised/forced
+ */
+static int ice_set_link_ksettings(struct net_device *netdev,
+ const struct ethtool_link_ksettings *ks)
+{
+ u8 autoneg, timeout = TEST_SET_BITS_TIMEOUT, lport = 0;
+ struct ice_netdev_priv *np = netdev_priv(netdev);
+ struct ethtool_link_ksettings safe_ks, copy_ks;
+ struct ice_aqc_get_phy_caps_data *abilities;
+ u16 adv_link_speed, curr_link_speed, idx;
+ struct ice_aqc_set_phy_cfg_data config;
+ struct ice_pf *pf = np->vsi->back;
+ struct ice_port_info *p;
+ u8 autoneg_changed = 0;
+ enum ice_status status;
+ u64 phy_type_low;
+ int err = 0;
+ bool linkup;
+
+ p = np->vsi->port_info;
+
+ if (!p)
+ return -EOPNOTSUPP;
+
+ /* Check if this is lan vsi */
+ for (idx = 0 ; idx < pf->num_alloc_vsi ; idx++) {
+ if (pf->vsi[idx]->type == ICE_VSI_PF) {
+ if (np->vsi != pf->vsi[idx])
+ return -EOPNOTSUPP;
+ break;
+ }
+ }
+
+ if (p->phy.media_type != ICE_MEDIA_BASET &&
+ p->phy.media_type != ICE_MEDIA_FIBER &&
+ p->phy.media_type != ICE_MEDIA_BACKPLANE &&
+ p->phy.media_type != ICE_MEDIA_DA &&
+ p->phy.link_info.link_info & ICE_AQ_LINK_UP)
+ return -EOPNOTSUPP;
+
+ /* copy the ksettings to copy_ks to avoid modifying the original */
+ memcpy(&copy_ks, ks, sizeof(struct ethtool_link_ksettings));
+
+ /* save autoneg out of ksettings */
+ autoneg = copy_ks.base.autoneg;
+
+ memset(&safe_ks, 0, sizeof(safe_ks));
+
+ /* Get link modes supported by hardware.*/
+ ice_phy_type_to_ethtool(netdev, &safe_ks);
+
+ /* and check against modes requested by user.
+ * Return an error if unsupported mode was set.
+ */
+ if (!bitmap_subset(copy_ks.link_modes.advertising,
+ safe_ks.link_modes.supported,
+ __ETHTOOL_LINK_MODE_MASK_NBITS))
+ return -EINVAL;
+
+ /* get our own copy of the bits to check against */
+ memset(&safe_ks, 0, sizeof(struct ethtool_link_ksettings));
+ safe_ks.base.cmd = copy_ks.base.cmd;
+ safe_ks.base.link_mode_masks_nwords =
+ copy_ks.base.link_mode_masks_nwords;
+ ice_get_link_ksettings(netdev, &safe_ks);
+
+ /* set autoneg back to what it currently is */
+ copy_ks.base.autoneg = safe_ks.base.autoneg;
+ /* we don't compare the speed */
+ copy_ks.base.speed = safe_ks.base.speed;
+
+ /* If copy_ks.base and safe_ks.base are not the same now, then they are
+ * trying to set something that we do not support.
+ */
+ if (memcmp(&copy_ks.base, &safe_ks.base,
+ sizeof(struct ethtool_link_settings)))
+ return -EOPNOTSUPP;
+
+ while (test_and_set_bit(__ICE_CFG_BUSY, pf->state)) {
+ timeout--;
+ if (!timeout)
+ return -EBUSY;
+ usleep_range(TEST_SET_BITS_SLEEP_MIN, TEST_SET_BITS_SLEEP_MAX);
+ }
+
+ abilities = devm_kzalloc(&pf->pdev->dev, sizeof(*abilities),
+ GFP_KERNEL);
+ if (!abilities)
+ return -ENOMEM;
+
+ /* Get the current phy config */
+ status = ice_aq_get_phy_caps(p, false, ICE_AQC_REPORT_SW_CFG, abilities,
+ NULL);
+ if (status) {
+ err = -EAGAIN;
+ goto done;
+ }
+
+ /* Copy abilities to config in case autoneg is not set below */
+ memset(&config, 0, sizeof(struct ice_aqc_set_phy_cfg_data));
+ config.caps = abilities->caps & ~ICE_AQC_PHY_AN_MODE;
+ if (abilities->caps & ICE_AQC_PHY_AN_MODE)
+ config.caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT;
+
+ /* Check autoneg */
+ err = ice_setup_autoneg(p, &safe_ks, &config, autoneg, &autoneg_changed,
+ netdev);
+
+ if (err)
+ goto done;
+
+ /* Call to get the current link speed */
+ p->phy.get_link_info = true;
+ status = ice_get_link_status(p, &linkup);
+ if (status) {
+ err = -EAGAIN;
+ goto done;
+ }
+
+ curr_link_speed = p->phy.link_info.link_speed;
+ adv_link_speed = ice_ksettings_find_adv_link_speed(ks);
+
+ /* If speed didn't get set, set it to what it currently is.
+ * This is needed because if advertise is 0 (as it is when autoneg
+ * is disabled) then speed won't get set.
+ */
+ if (!adv_link_speed)
+ adv_link_speed = curr_link_speed;
+
+ /* Convert the advertise link speeds to their corresponded PHY_TYPE */
+ ice_update_phy_type(&phy_type_low, adv_link_speed);
+
+ if (!autoneg_changed && adv_link_speed == curr_link_speed) {
+ netdev_info(netdev, "Nothing changed, exiting without setting anything.\n");
+ goto done;
+ }
+
+ /* copy over the rest of the abilities */
+ config.low_power_ctrl = abilities->low_power_ctrl;
+ config.eee_cap = abilities->eee_cap;
+ config.eeer_value = abilities->eeer_value;
+ config.link_fec_opt = abilities->link_fec_options;
+
+ /* save the requested speeds */
+ p->phy.link_info.req_speeds = adv_link_speed;
+
+ /* set link and auto negotiation so changes take effect */
+ config.caps |= ICE_AQ_PHY_ENA_LINK;
+
+ if (phy_type_low) {
+ config.phy_type_low = cpu_to_le64(phy_type_low) &
+ abilities->phy_type_low;
+ } else {
+ err = -EAGAIN;
+ netdev_info(netdev, "Nothing changed. No PHY_TYPE is corresponded to advertised link speed.\n");
+ goto done;
+ }
+
+ /* If link is up put link down */
+ if (p->phy.link_info.link_info & ICE_AQ_LINK_UP) {
+ /* Tell the OS link is going down, the link will go
+ * back up when fw says it is ready asynchronously
+ */
+ ice_print_link_msg(np->vsi, false);
+ netif_carrier_off(netdev);
+ netif_tx_stop_all_queues(netdev);
+ }
+
+ /* make the aq call */
+ status = ice_aq_set_phy_cfg(&pf->hw, lport, &config, NULL);
+ if (status) {
+ netdev_info(netdev, "Set phy config failed,\n");
+ err = -EAGAIN;
+ }
+
+done:
+ devm_kfree(&pf->pdev->dev, abilities);
+ clear_bit(__ICE_CFG_BUSY, pf->state);
+
+ return err;
+}
+
+/**
* ice_get_rxnfc - command to get RX flow classification rules
* @netdev: network interface device structure
* @cmd: ethtool rxnfc command
@@ -478,9 +1198,11 @@ ice_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring)
ring->tx_max_pending = ICE_MAX_NUM_DESC;
ring->rx_pending = vsi->rx_rings[0]->count;
ring->tx_pending = vsi->tx_rings[0]->count;
- ring->rx_mini_pending = ICE_MIN_NUM_DESC;
+
+ /* Rx mini and jumbo rings are not supported */
ring->rx_mini_max_pending = 0;
ring->rx_jumbo_max_pending = 0;
+ ring->rx_mini_pending = 0;
ring->rx_jumbo_pending = 0;
}
@@ -498,14 +1220,23 @@ ice_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring)
ring->tx_pending < ICE_MIN_NUM_DESC ||
ring->rx_pending > ICE_MAX_NUM_DESC ||
ring->rx_pending < ICE_MIN_NUM_DESC) {
- netdev_err(netdev, "Descriptors requested (Tx: %d / Rx: %d) out of range [%d-%d]\n",
+ netdev_err(netdev, "Descriptors requested (Tx: %d / Rx: %d) out of range [%d-%d] (increment %d)\n",
ring->tx_pending, ring->rx_pending,
- ICE_MIN_NUM_DESC, ICE_MAX_NUM_DESC);
+ ICE_MIN_NUM_DESC, ICE_MAX_NUM_DESC,
+ ICE_REQ_DESC_MULTIPLE);
return -EINVAL;
}
new_tx_cnt = ALIGN(ring->tx_pending, ICE_REQ_DESC_MULTIPLE);
+ if (new_tx_cnt != ring->tx_pending)
+ netdev_info(netdev,
+ "Requested Tx descriptor count rounded up to %d\n",
+ new_tx_cnt);
new_rx_cnt = ALIGN(ring->rx_pending, ICE_REQ_DESC_MULTIPLE);
+ if (new_rx_cnt != ring->rx_pending)
+ netdev_info(netdev,
+ "Requested Rx descriptor count rounded up to %d\n",
+ new_rx_cnt);
/* if nothing to do return success */
if (new_tx_cnt == vsi->tx_rings[0]->count &&
@@ -786,10 +1517,15 @@ ice_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause)
}
if (!test_bit(__ICE_DOWN, pf->state)) {
- /* Give it a little more time to try to come back */
+ /* Give it a little more time to try to come back. If still
+ * down, restart autoneg link or reinitialize the interface.
+ */
msleep(75);
if (!test_bit(__ICE_DOWN, pf->state))
return ice_nway_reset(netdev);
+
+ ice_down(vsi);
+ ice_up(vsi);
}
return err;
@@ -933,6 +1669,7 @@ static int ice_set_rxfh(struct net_device *netdev, const u32 *indir,
static const struct ethtool_ops ice_ethtool_ops = {
.get_link_ksettings = ice_get_link_ksettings,
+ .set_link_ksettings = ice_set_link_ksettings,
.get_drvinfo = ice_get_drvinfo,
.get_regs_len = ice_get_regs_len,
.get_regs = ice_get_regs,
diff --git a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h
index 6076fc87df9d..596b9fb1c510 100644
--- a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h
+++ b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h
@@ -6,251 +6,333 @@
#ifndef _ICE_HW_AUTOGEN_H_
#define _ICE_HW_AUTOGEN_H_
-#define QTX_COMM_DBELL(_DBQM) (0x002C0000 + ((_DBQM) * 4))
-#define PF_FW_ARQBAH 0x00080180
-#define PF_FW_ARQBAL 0x00080080
-#define PF_FW_ARQH 0x00080380
-#define PF_FW_ARQH_ARQH_S 0
-#define PF_FW_ARQH_ARQH_M ICE_M(0x3FF, PF_FW_ARQH_ARQH_S)
-#define PF_FW_ARQLEN 0x00080280
-#define PF_FW_ARQLEN_ARQLEN_S 0
-#define PF_FW_ARQLEN_ARQLEN_M ICE_M(0x3FF, PF_FW_ARQLEN_ARQLEN_S)
-#define PF_FW_ARQLEN_ARQVFE_S 28
-#define PF_FW_ARQLEN_ARQVFE_M BIT(PF_FW_ARQLEN_ARQVFE_S)
-#define PF_FW_ARQLEN_ARQOVFL_S 29
-#define PF_FW_ARQLEN_ARQOVFL_M BIT(PF_FW_ARQLEN_ARQOVFL_S)
-#define PF_FW_ARQLEN_ARQCRIT_S 30
-#define PF_FW_ARQLEN_ARQCRIT_M BIT(PF_FW_ARQLEN_ARQCRIT_S)
-#define PF_FW_ARQLEN_ARQENABLE_S 31
-#define PF_FW_ARQLEN_ARQENABLE_M BIT(PF_FW_ARQLEN_ARQENABLE_S)
-#define PF_FW_ARQT 0x00080480
-#define PF_FW_ATQBAH 0x00080100
-#define PF_FW_ATQBAL 0x00080000
-#define PF_FW_ATQH 0x00080300
-#define PF_FW_ATQH_ATQH_S 0
-#define PF_FW_ATQH_ATQH_M ICE_M(0x3FF, PF_FW_ATQH_ATQH_S)
-#define PF_FW_ATQLEN 0x00080200
-#define PF_FW_ATQLEN_ATQLEN_S 0
-#define PF_FW_ATQLEN_ATQLEN_M ICE_M(0x3FF, PF_FW_ATQLEN_ATQLEN_S)
-#define PF_FW_ATQLEN_ATQVFE_S 28
-#define PF_FW_ATQLEN_ATQVFE_M BIT(PF_FW_ATQLEN_ATQVFE_S)
-#define PF_FW_ATQLEN_ATQOVFL_S 29
-#define PF_FW_ATQLEN_ATQOVFL_M BIT(PF_FW_ATQLEN_ATQOVFL_S)
-#define PF_FW_ATQLEN_ATQCRIT_S 30
-#define PF_FW_ATQLEN_ATQCRIT_M BIT(PF_FW_ATQLEN_ATQCRIT_S)
-#define PF_FW_ATQLEN_ATQENABLE_S 31
-#define PF_FW_ATQLEN_ATQENABLE_M BIT(PF_FW_ATQLEN_ATQENABLE_S)
-#define PF_FW_ATQT 0x00080400
-
+#define QTX_COMM_DBELL(_DBQM) (0x002C0000 + ((_DBQM) * 4))
+#define PF_FW_ARQBAH 0x00080180
+#define PF_FW_ARQBAL 0x00080080
+#define PF_FW_ARQH 0x00080380
+#define PF_FW_ARQH_ARQH_M ICE_M(0x3FF, 0)
+#define PF_FW_ARQLEN 0x00080280
+#define PF_FW_ARQLEN_ARQLEN_M ICE_M(0x3FF, 0)
+#define PF_FW_ARQLEN_ARQVFE_M BIT(28)
+#define PF_FW_ARQLEN_ARQOVFL_M BIT(29)
+#define PF_FW_ARQLEN_ARQCRIT_M BIT(30)
+#define PF_FW_ARQLEN_ARQENABLE_M BIT(31)
+#define PF_FW_ARQT 0x00080480
+#define PF_FW_ATQBAH 0x00080100
+#define PF_FW_ATQBAL 0x00080000
+#define PF_FW_ATQH 0x00080300
+#define PF_FW_ATQH_ATQH_M ICE_M(0x3FF, 0)
+#define PF_FW_ATQLEN 0x00080200
+#define PF_FW_ATQLEN_ATQLEN_M ICE_M(0x3FF, 0)
+#define PF_FW_ATQLEN_ATQVFE_M BIT(28)
+#define PF_FW_ATQLEN_ATQOVFL_M BIT(29)
+#define PF_FW_ATQLEN_ATQCRIT_M BIT(30)
+#define PF_FW_ATQLEN_ATQENABLE_M BIT(31)
+#define PF_FW_ATQT 0x00080400
+#define PF_MBX_ARQBAH 0x0022E400
+#define PF_MBX_ARQBAL 0x0022E380
+#define PF_MBX_ARQH 0x0022E500
+#define PF_MBX_ARQH_ARQH_M ICE_M(0x3FF, 0)
+#define PF_MBX_ARQLEN 0x0022E480
+#define PF_MBX_ARQLEN_ARQLEN_M ICE_M(0x3FF, 0)
+#define PF_MBX_ARQLEN_ARQENABLE_M BIT(31)
+#define PF_MBX_ARQT 0x0022E580
+#define PF_MBX_ATQBAH 0x0022E180
+#define PF_MBX_ATQBAL 0x0022E100
+#define PF_MBX_ATQH 0x0022E280
+#define PF_MBX_ATQH_ATQH_M ICE_M(0x3FF, 0)
+#define PF_MBX_ATQLEN 0x0022E200
+#define PF_MBX_ATQLEN_ATQLEN_M ICE_M(0x3FF, 0)
+#define PF_MBX_ATQLEN_ATQENABLE_M BIT(31)
+#define PF_MBX_ATQT 0x0022E300
#define GLFLXP_RXDID_FLAGS(_i, _j) (0x0045D000 + ((_i) * 4 + (_j) * 256))
#define GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_S 0
-#define GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_M ICE_M(0x3F, GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_S)
+#define GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_M ICE_M(0x3F, 0)
#define GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_1_S 8
-#define GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_1_M ICE_M(0x3F, GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_1_S)
+#define GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_1_M ICE_M(0x3F, 8)
#define GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_2_S 16
-#define GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_2_M ICE_M(0x3F, GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_2_S)
+#define GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_2_M ICE_M(0x3F, 16)
#define GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_3_S 24
-#define GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_3_M ICE_M(0x3F, GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_3_S)
+#define GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_3_M ICE_M(0x3F, 24)
#define GLFLXP_RXDID_FLX_WRD_0(_i) (0x0045c800 + ((_i) * 4))
#define GLFLXP_RXDID_FLX_WRD_0_PROT_MDID_S 0
-#define GLFLXP_RXDID_FLX_WRD_0_PROT_MDID_M ICE_M(0xFF, GLFLXP_RXDID_FLX_WRD_0_PROT_MDID_S)
+#define GLFLXP_RXDID_FLX_WRD_0_PROT_MDID_M ICE_M(0xFF, 0)
#define GLFLXP_RXDID_FLX_WRD_0_RXDID_OPCODE_S 30
-#define GLFLXP_RXDID_FLX_WRD_0_RXDID_OPCODE_M ICE_M(0x3, GLFLXP_RXDID_FLX_WRD_0_RXDID_OPCODE_S)
+#define GLFLXP_RXDID_FLX_WRD_0_RXDID_OPCODE_M ICE_M(0x3, 30)
#define GLFLXP_RXDID_FLX_WRD_1(_i) (0x0045c900 + ((_i) * 4))
#define GLFLXP_RXDID_FLX_WRD_1_PROT_MDID_S 0
-#define GLFLXP_RXDID_FLX_WRD_1_PROT_MDID_M ICE_M(0xFF, GLFLXP_RXDID_FLX_WRD_1_PROT_MDID_S)
+#define GLFLXP_RXDID_FLX_WRD_1_PROT_MDID_M ICE_M(0xFF, 0)
#define GLFLXP_RXDID_FLX_WRD_1_RXDID_OPCODE_S 30
-#define GLFLXP_RXDID_FLX_WRD_1_RXDID_OPCODE_M ICE_M(0x3, GLFLXP_RXDID_FLX_WRD_1_RXDID_OPCODE_S)
+#define GLFLXP_RXDID_FLX_WRD_1_RXDID_OPCODE_M ICE_M(0x3, 30)
#define GLFLXP_RXDID_FLX_WRD_2(_i) (0x0045ca00 + ((_i) * 4))
#define GLFLXP_RXDID_FLX_WRD_2_PROT_MDID_S 0
-#define GLFLXP_RXDID_FLX_WRD_2_PROT_MDID_M ICE_M(0xFF, GLFLXP_RXDID_FLX_WRD_2_PROT_MDID_S)
+#define GLFLXP_RXDID_FLX_WRD_2_PROT_MDID_M ICE_M(0xFF, 0)
#define GLFLXP_RXDID_FLX_WRD_2_RXDID_OPCODE_S 30
-#define GLFLXP_RXDID_FLX_WRD_2_RXDID_OPCODE_M ICE_M(0x3, GLFLXP_RXDID_FLX_WRD_2_RXDID_OPCODE_S)
+#define GLFLXP_RXDID_FLX_WRD_2_RXDID_OPCODE_M ICE_M(0x3, 30)
#define GLFLXP_RXDID_FLX_WRD_3(_i) (0x0045cb00 + ((_i) * 4))
#define GLFLXP_RXDID_FLX_WRD_3_PROT_MDID_S 0
-#define GLFLXP_RXDID_FLX_WRD_3_PROT_MDID_M ICE_M(0xFF, GLFLXP_RXDID_FLX_WRD_3_PROT_MDID_S)
+#define GLFLXP_RXDID_FLX_WRD_3_PROT_MDID_M ICE_M(0xFF, 0)
#define GLFLXP_RXDID_FLX_WRD_3_RXDID_OPCODE_S 30
-#define GLFLXP_RXDID_FLX_WRD_3_RXDID_OPCODE_M ICE_M(0x3, GLFLXP_RXDID_FLX_WRD_3_RXDID_OPCODE_S)
-
-#define QRXFLXP_CNTXT(_QRX) (0x00480000 + ((_QRX) * 4))
-#define QRXFLXP_CNTXT_RXDID_IDX_S 0
-#define QRXFLXP_CNTXT_RXDID_IDX_M ICE_M(0x3F, QRXFLXP_CNTXT_RXDID_IDX_S)
-#define QRXFLXP_CNTXT_RXDID_PRIO_S 8
-#define QRXFLXP_CNTXT_RXDID_PRIO_M ICE_M(0x7, QRXFLXP_CNTXT_RXDID_PRIO_S)
-#define QRXFLXP_CNTXT_TS_S 11
-#define QRXFLXP_CNTXT_TS_M BIT(QRXFLXP_CNTXT_TS_S)
-#define GLGEN_RSTAT 0x000B8188
-#define GLGEN_RSTAT_DEVSTATE_S 0
-#define GLGEN_RSTAT_DEVSTATE_M ICE_M(0x3, GLGEN_RSTAT_DEVSTATE_S)
-#define GLGEN_RSTCTL 0x000B8180
-#define GLGEN_RSTCTL_GRSTDEL_S 0
-#define GLGEN_RSTCTL_GRSTDEL_M ICE_M(0x3F, GLGEN_RSTCTL_GRSTDEL_S)
-#define GLGEN_RSTAT_RESET_TYPE_S 2
-#define GLGEN_RSTAT_RESET_TYPE_M ICE_M(0x3, GLGEN_RSTAT_RESET_TYPE_S)
-#define GLGEN_RTRIG 0x000B8190
-#define GLGEN_RTRIG_CORER_S 0
-#define GLGEN_RTRIG_CORER_M BIT(GLGEN_RTRIG_CORER_S)
-#define GLGEN_RTRIG_GLOBR_S 1
-#define GLGEN_RTRIG_GLOBR_M BIT(GLGEN_RTRIG_GLOBR_S)
-#define GLGEN_STAT 0x000B612C
-#define PFGEN_CTRL 0x00091000
-#define PFGEN_CTRL_PFSWR_S 0
-#define PFGEN_CTRL_PFSWR_M BIT(PFGEN_CTRL_PFSWR_S)
-#define PFGEN_STATE 0x00088000
-#define PRTGEN_STATUS 0x000B8100
-#define PFHMC_ERRORDATA 0x00520500
-#define PFHMC_ERRORINFO 0x00520400
-#define GLINT_DYN_CTL(_INT) (0x00160000 + ((_INT) * 4))
-#define GLINT_DYN_CTL_INTENA_S 0
-#define GLINT_DYN_CTL_INTENA_M BIT(GLINT_DYN_CTL_INTENA_S)
-#define GLINT_DYN_CTL_CLEARPBA_S 1
-#define GLINT_DYN_CTL_CLEARPBA_M BIT(GLINT_DYN_CTL_CLEARPBA_S)
-#define GLINT_DYN_CTL_SWINT_TRIG_S 2
-#define GLINT_DYN_CTL_SWINT_TRIG_M BIT(GLINT_DYN_CTL_SWINT_TRIG_S)
-#define GLINT_DYN_CTL_ITR_INDX_S 3
-#define GLINT_DYN_CTL_SW_ITR_INDX_S 25
-#define GLINT_DYN_CTL_SW_ITR_INDX_M ICE_M(0x3, GLINT_DYN_CTL_SW_ITR_INDX_S)
-#define GLINT_DYN_CTL_INTENA_MSK_S 31
-#define GLINT_DYN_CTL_INTENA_MSK_M BIT(GLINT_DYN_CTL_INTENA_MSK_S)
-#define GLINT_ITR(_i, _INT) (0x00154000 + ((_i) * 8192 + (_INT) * 4))
-#define PFINT_FW_CTL 0x0016C800
-#define PFINT_FW_CTL_MSIX_INDX_S 0
-#define PFINT_FW_CTL_MSIX_INDX_M ICE_M(0x7FF, PFINT_FW_CTL_MSIX_INDX_S)
-#define PFINT_FW_CTL_ITR_INDX_S 11
-#define PFINT_FW_CTL_ITR_INDX_M ICE_M(0x3, PFINT_FW_CTL_ITR_INDX_S)
-#define PFINT_FW_CTL_CAUSE_ENA_S 30
-#define PFINT_FW_CTL_CAUSE_ENA_M BIT(PFINT_FW_CTL_CAUSE_ENA_S)
-#define PFINT_OICR 0x0016CA00
-#define PFINT_OICR_ECC_ERR_S 16
-#define PFINT_OICR_ECC_ERR_M BIT(PFINT_OICR_ECC_ERR_S)
-#define PFINT_OICR_MAL_DETECT_S 19
-#define PFINT_OICR_MAL_DETECT_M BIT(PFINT_OICR_MAL_DETECT_S)
-#define PFINT_OICR_GRST_S 20
-#define PFINT_OICR_GRST_M BIT(PFINT_OICR_GRST_S)
-#define PFINT_OICR_PCI_EXCEPTION_S 21
-#define PFINT_OICR_PCI_EXCEPTION_M BIT(PFINT_OICR_PCI_EXCEPTION_S)
-#define PFINT_OICR_HMC_ERR_S 26
-#define PFINT_OICR_HMC_ERR_M BIT(PFINT_OICR_HMC_ERR_S)
-#define PFINT_OICR_PE_CRITERR_S 28
-#define PFINT_OICR_PE_CRITERR_M BIT(PFINT_OICR_PE_CRITERR_S)
-#define PFINT_OICR_CTL 0x0016CA80
-#define PFINT_OICR_CTL_MSIX_INDX_S 0
-#define PFINT_OICR_CTL_MSIX_INDX_M ICE_M(0x7FF, PFINT_OICR_CTL_MSIX_INDX_S)
-#define PFINT_OICR_CTL_ITR_INDX_S 11
-#define PFINT_OICR_CTL_ITR_INDX_M ICE_M(0x3, PFINT_OICR_CTL_ITR_INDX_S)
-#define PFINT_OICR_CTL_CAUSE_ENA_S 30
-#define PFINT_OICR_CTL_CAUSE_ENA_M BIT(PFINT_OICR_CTL_CAUSE_ENA_S)
-#define PFINT_OICR_ENA 0x0016C900
-#define QINT_RQCTL(_QRX) (0x00150000 + ((_QRX) * 4))
-#define QINT_RQCTL_MSIX_INDX_S 0
-#define QINT_RQCTL_ITR_INDX_S 11
-#define QINT_RQCTL_CAUSE_ENA_S 30
-#define QINT_RQCTL_CAUSE_ENA_M BIT(QINT_RQCTL_CAUSE_ENA_S)
-#define QINT_TQCTL(_DBQM) (0x00140000 + ((_DBQM) * 4))
-#define QINT_TQCTL_MSIX_INDX_S 0
-#define QINT_TQCTL_ITR_INDX_S 11
-#define QINT_TQCTL_CAUSE_ENA_S 30
-#define QINT_TQCTL_CAUSE_ENA_M BIT(QINT_TQCTL_CAUSE_ENA_S)
-#define GLLAN_RCTL_0 0x002941F8
-#define QRX_CONTEXT(_i, _QRX) (0x00280000 + ((_i) * 8192 + (_QRX) * 4))
-#define QRX_CTRL(_QRX) (0x00120000 + ((_QRX) * 4))
-#define QRX_CTRL_MAX_INDEX 2047
-#define QRX_CTRL_QENA_REQ_S 0
-#define QRX_CTRL_QENA_REQ_M BIT(QRX_CTRL_QENA_REQ_S)
-#define QRX_CTRL_QENA_STAT_S 2
-#define QRX_CTRL_QENA_STAT_M BIT(QRX_CTRL_QENA_STAT_S)
-#define QRX_ITR(_QRX) (0x00292000 + ((_QRX) * 4))
-#define QRX_TAIL(_QRX) (0x00290000 + ((_QRX) * 4))
-#define GLNVM_FLA 0x000B6108
-#define GLNVM_FLA_LOCKED_S 6
-#define GLNVM_FLA_LOCKED_M BIT(GLNVM_FLA_LOCKED_S)
-#define GLNVM_GENS 0x000B6100
-#define GLNVM_GENS_SR_SIZE_S 5
-#define GLNVM_GENS_SR_SIZE_M ICE_M(0x7, GLNVM_GENS_SR_SIZE_S)
-#define GLNVM_ULD 0x000B6008
-#define GLNVM_ULD_CORER_DONE_S 3
-#define GLNVM_ULD_CORER_DONE_M BIT(GLNVM_ULD_CORER_DONE_S)
-#define GLNVM_ULD_GLOBR_DONE_S 4
-#define GLNVM_ULD_GLOBR_DONE_M BIT(GLNVM_ULD_GLOBR_DONE_S)
-#define PF_FUNC_RID 0x0009E880
-#define PF_FUNC_RID_FUNC_NUM_S 0
-#define PF_FUNC_RID_FUNC_NUM_M ICE_M(0x7, PF_FUNC_RID_FUNC_NUM_S)
-#define GLPRT_BPRCH(_i) (0x00381384 + ((_i) * 8))
-#define GLPRT_BPRCL(_i) (0x00381380 + ((_i) * 8))
-#define GLPRT_BPTCH(_i) (0x00381244 + ((_i) * 8))
-#define GLPRT_BPTCL(_i) (0x00381240 + ((_i) * 8))
-#define GLPRT_CRCERRS(_i) (0x00380100 + ((_i) * 8))
-#define GLPRT_GORCH(_i) (0x00380004 + ((_i) * 8))
-#define GLPRT_GORCL(_i) (0x00380000 + ((_i) * 8))
-#define GLPRT_GOTCH(_i) (0x00380B44 + ((_i) * 8))
-#define GLPRT_GOTCL(_i) (0x00380B40 + ((_i) * 8))
-#define GLPRT_ILLERRC(_i) (0x003801C0 + ((_i) * 8))
-#define GLPRT_LXOFFRXC(_i) (0x003802C0 + ((_i) * 8))
-#define GLPRT_LXOFFTXC(_i) (0x00381180 + ((_i) * 8))
-#define GLPRT_LXONRXC(_i) (0x00380280 + ((_i) * 8))
-#define GLPRT_LXONTXC(_i) (0x00381140 + ((_i) * 8))
-#define GLPRT_MLFC(_i) (0x00380040 + ((_i) * 8))
-#define GLPRT_MPRCH(_i) (0x00381344 + ((_i) * 8))
-#define GLPRT_MPRCL(_i) (0x00381340 + ((_i) * 8))
-#define GLPRT_MPTCH(_i) (0x00381204 + ((_i) * 8))
-#define GLPRT_MPTCL(_i) (0x00381200 + ((_i) * 8))
-#define GLPRT_MRFC(_i) (0x00380080 + ((_i) * 8))
-#define GLPRT_PRC1023H(_i) (0x00380A04 + ((_i) * 8))
-#define GLPRT_PRC1023L(_i) (0x00380A00 + ((_i) * 8))
-#define GLPRT_PRC127H(_i) (0x00380944 + ((_i) * 8))
-#define GLPRT_PRC127L(_i) (0x00380940 + ((_i) * 8))
-#define GLPRT_PRC1522H(_i) (0x00380A44 + ((_i) * 8))
-#define GLPRT_PRC1522L(_i) (0x00380A40 + ((_i) * 8))
-#define GLPRT_PRC255H(_i) (0x00380984 + ((_i) * 8))
-#define GLPRT_PRC255L(_i) (0x00380980 + ((_i) * 8))
-#define GLPRT_PRC511H(_i) (0x003809C4 + ((_i) * 8))
-#define GLPRT_PRC511L(_i) (0x003809C0 + ((_i) * 8))
-#define GLPRT_PRC64H(_i) (0x00380904 + ((_i) * 8))
-#define GLPRT_PRC64L(_i) (0x00380900 + ((_i) * 8))
-#define GLPRT_PRC9522H(_i) (0x00380A84 + ((_i) * 8))
-#define GLPRT_PRC9522L(_i) (0x00380A80 + ((_i) * 8))
-#define GLPRT_PTC1023H(_i) (0x00380C84 + ((_i) * 8))
-#define GLPRT_PTC1023L(_i) (0x00380C80 + ((_i) * 8))
-#define GLPRT_PTC127H(_i) (0x00380BC4 + ((_i) * 8))
-#define GLPRT_PTC127L(_i) (0x00380BC0 + ((_i) * 8))
-#define GLPRT_PTC1522H(_i) (0x00380CC4 + ((_i) * 8))
-#define GLPRT_PTC1522L(_i) (0x00380CC0 + ((_i) * 8))
-#define GLPRT_PTC255H(_i) (0x00380C04 + ((_i) * 8))
-#define GLPRT_PTC255L(_i) (0x00380C00 + ((_i) * 8))
-#define GLPRT_PTC511H(_i) (0x00380C44 + ((_i) * 8))
-#define GLPRT_PTC511L(_i) (0x00380C40 + ((_i) * 8))
-#define GLPRT_PTC64H(_i) (0x00380B84 + ((_i) * 8))
-#define GLPRT_PTC64L(_i) (0x00380B80 + ((_i) * 8))
-#define GLPRT_PTC9522H(_i) (0x00380D04 + ((_i) * 8))
-#define GLPRT_PTC9522L(_i) (0x00380D00 + ((_i) * 8))
-#define GLPRT_RFC(_i) (0x00380AC0 + ((_i) * 8))
-#define GLPRT_RJC(_i) (0x00380B00 + ((_i) * 8))
-#define GLPRT_RLEC(_i) (0x00380140 + ((_i) * 8))
-#define GLPRT_ROC(_i) (0x00380240 + ((_i) * 8))
-#define GLPRT_RUC(_i) (0x00380200 + ((_i) * 8))
-#define GLPRT_TDOLD(_i) (0x00381280 + ((_i) * 8))
-#define GLPRT_UPRCH(_i) (0x00381304 + ((_i) * 8))
-#define GLPRT_UPRCL(_i) (0x00381300 + ((_i) * 8))
-#define GLPRT_UPTCH(_i) (0x003811C4 + ((_i) * 8))
-#define GLPRT_UPTCL(_i) (0x003811C0 + ((_i) * 8))
-#define GLV_BPRCH(_i) (0x003B6004 + ((_i) * 8))
-#define GLV_BPRCL(_i) (0x003B6000 + ((_i) * 8))
-#define GLV_BPTCH(_i) (0x0030E004 + ((_i) * 8))
-#define GLV_BPTCL(_i) (0x0030E000 + ((_i) * 8))
-#define GLV_GORCH(_i) (0x003B0004 + ((_i) * 8))
-#define GLV_GORCL(_i) (0x003B0000 + ((_i) * 8))
-#define GLV_GOTCH(_i) (0x00300004 + ((_i) * 8))
-#define GLV_GOTCL(_i) (0x00300000 + ((_i) * 8))
-#define GLV_MPRCH(_i) (0x003B4004 + ((_i) * 8))
-#define GLV_MPRCL(_i) (0x003B4000 + ((_i) * 8))
-#define GLV_MPTCH(_i) (0x0030C004 + ((_i) * 8))
-#define GLV_MPTCL(_i) (0x0030C000 + ((_i) * 8))
-#define GLV_RDPC(_i) (0x00294C04 + ((_i) * 4))
-#define GLV_TEPC(_VSI) (0x00312000 + ((_VSI) * 4))
-#define GLV_UPRCH(_i) (0x003B2004 + ((_i) * 8))
-#define GLV_UPRCL(_i) (0x003B2000 + ((_i) * 8))
-#define GLV_UPTCH(_i) (0x0030A004 + ((_i) * 8))
-#define GLV_UPTCL(_i) (0x0030A000 + ((_i) * 8))
-#define VSIQF_HKEY_MAX_INDEX 12
+#define GLFLXP_RXDID_FLX_WRD_3_RXDID_OPCODE_M ICE_M(0x3, 30)
+#define QRXFLXP_CNTXT(_QRX) (0x00480000 + ((_QRX) * 4))
+#define QRXFLXP_CNTXT_RXDID_IDX_S 0
+#define QRXFLXP_CNTXT_RXDID_IDX_M ICE_M(0x3F, 0)
+#define QRXFLXP_CNTXT_RXDID_PRIO_S 8
+#define QRXFLXP_CNTXT_RXDID_PRIO_M ICE_M(0x7, 8)
+#define GLGEN_RSTAT 0x000B8188
+#define GLGEN_RSTAT_DEVSTATE_M ICE_M(0x3, 0)
+#define GLGEN_RSTCTL 0x000B8180
+#define GLGEN_RSTCTL_GRSTDEL_S 0
+#define GLGEN_RSTCTL_GRSTDEL_M ICE_M(0x3F, GLGEN_RSTCTL_GRSTDEL_S)
+#define GLGEN_RSTAT_RESET_TYPE_S 2
+#define GLGEN_RSTAT_RESET_TYPE_M ICE_M(0x3, 2)
+#define GLGEN_RTRIG 0x000B8190
+#define GLGEN_RTRIG_CORER_M BIT(0)
+#define GLGEN_RTRIG_GLOBR_M BIT(1)
+#define GLGEN_STAT 0x000B612C
+#define GLGEN_VFLRSTAT(_i) (0x00093A04 + ((_i) * 4))
+#define PFGEN_CTRL 0x00091000
+#define PFGEN_CTRL_PFSWR_M BIT(0)
+#define PFGEN_STATE 0x00088000
+#define PRTGEN_STATUS 0x000B8100
+#define VFGEN_RSTAT(_VF) (0x00074000 + ((_VF) * 4))
+#define VPGEN_VFRSTAT(_VF) (0x00090800 + ((_VF) * 4))
+#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_DYN_CTL(_INT) (0x00160000 + ((_INT) * 4))
+#define GLINT_DYN_CTL_INTENA_M BIT(0)
+#define GLINT_DYN_CTL_CLEARPBA_M BIT(1)
+#define GLINT_DYN_CTL_SWINT_TRIG_M BIT(2)
+#define GLINT_DYN_CTL_ITR_INDX_S 3
+#define GLINT_DYN_CTL_SW_ITR_INDX_M ICE_M(0x3, 25)
+#define GLINT_DYN_CTL_INTENA_MSK_M BIT(31)
+#define GLINT_ITR(_i, _INT) (0x00154000 + ((_i) * 8192 + (_INT) * 4))
+#define GLINT_RATE(_INT) (0x0015A000 + ((_INT) * 4))
+#define GLINT_RATE_INTRL_ENA_M BIT(6)
+#define GLINT_VECT2FUNC(_INT) (0x00162000 + ((_INT) * 4))
+#define GLINT_VECT2FUNC_VF_NUM_S 0
+#define GLINT_VECT2FUNC_VF_NUM_M ICE_M(0xFF, 0)
+#define GLINT_VECT2FUNC_PF_NUM_S 12
+#define GLINT_VECT2FUNC_PF_NUM_M ICE_M(0x7, 12)
+#define GLINT_VECT2FUNC_IS_PF_S 16
+#define GLINT_VECT2FUNC_IS_PF_M BIT(16)
+#define PFINT_FW_CTL 0x0016C800
+#define PFINT_FW_CTL_MSIX_INDX_M ICE_M(0x7FF, 0)
+#define PFINT_FW_CTL_ITR_INDX_S 11
+#define PFINT_FW_CTL_ITR_INDX_M ICE_M(0x3, 11)
+#define PFINT_FW_CTL_CAUSE_ENA_M BIT(30)
+#define PFINT_MBX_CTL 0x0016B280
+#define PFINT_MBX_CTL_MSIX_INDX_M ICE_M(0x7FF, 0)
+#define PFINT_MBX_CTL_ITR_INDX_S 11
+#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_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_CRITERR_M BIT(28)
+#define PFINT_OICR_VFLR_M BIT(29)
+#define PFINT_OICR_CTL 0x0016CA80
+#define PFINT_OICR_CTL_MSIX_INDX_M ICE_M(0x7FF, 0)
+#define PFINT_OICR_CTL_ITR_INDX_S 11
+#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 QINT_RQCTL(_QRX) (0x00150000 + ((_QRX) * 4))
+#define QINT_RQCTL_MSIX_INDX_S 0
+#define QINT_RQCTL_ITR_INDX_S 11
+#define QINT_RQCTL_CAUSE_ENA_M BIT(30)
+#define QINT_TQCTL(_DBQM) (0x00140000 + ((_DBQM) * 4))
+#define QINT_TQCTL_MSIX_INDX_S 0
+#define QINT_TQCTL_ITR_INDX_S 11
+#define QINT_TQCTL_CAUSE_ENA_M BIT(30)
+#define VPINT_ALLOC(_VF) (0x001D1000 + ((_VF) * 4))
+#define VPINT_ALLOC_FIRST_S 0
+#define VPINT_ALLOC_FIRST_M ICE_M(0x7FF, 0)
+#define VPINT_ALLOC_LAST_S 12
+#define VPINT_ALLOC_LAST_M ICE_M(0x7FF, 12)
+#define VPINT_ALLOC_VALID_M BIT(31)
+#define VPINT_ALLOC_PCI(_VF) (0x0009D000 + ((_VF) * 4))
+#define VPINT_ALLOC_PCI_FIRST_S 0
+#define VPINT_ALLOC_PCI_FIRST_M ICE_M(0x7FF, 0)
+#define VPINT_ALLOC_PCI_LAST_S 12
+#define VPINT_ALLOC_PCI_LAST_M ICE_M(0x7FF, 12)
+#define VPINT_ALLOC_PCI_VALID_M BIT(31)
+#define GLLAN_RCTL_0 0x002941F8
+#define QRX_CONTEXT(_i, _QRX) (0x00280000 + ((_i) * 8192 + (_QRX) * 4))
+#define QRX_CTRL(_QRX) (0x00120000 + ((_QRX) * 4))
+#define QRX_CTRL_MAX_INDEX 2047
+#define QRX_CTRL_QENA_REQ_S 0
+#define QRX_CTRL_QENA_REQ_M BIT(0)
+#define QRX_CTRL_QENA_STAT_S 2
+#define QRX_CTRL_QENA_STAT_M BIT(2)
+#define QRX_ITR(_QRX) (0x00292000 + ((_QRX) * 4))
+#define QRX_TAIL(_QRX) (0x00290000 + ((_QRX) * 4))
+#define QRX_TAIL_MAX_INDEX 2047
+#define QRX_TAIL_TAIL_S 0
+#define QRX_TAIL_TAIL_M ICE_M(0x1FFF, 0)
+#define VPLAN_RX_QBASE(_VF) (0x00072000 + ((_VF) * 4))
+#define VPLAN_RX_QBASE_VFFIRSTQ_S 0
+#define VPLAN_RX_QBASE_VFFIRSTQ_M ICE_M(0x7FF, 0)
+#define VPLAN_RX_QBASE_VFNUMQ_S 16
+#define VPLAN_RX_QBASE_VFNUMQ_M ICE_M(0xFF, 16)
+#define VPLAN_RXQ_MAPENA(_VF) (0x00073000 + ((_VF) * 4))
+#define VPLAN_RXQ_MAPENA_RX_ENA_M BIT(0)
+#define VPLAN_TX_QBASE(_VF) (0x001D1800 + ((_VF) * 4))
+#define VPLAN_TX_QBASE_VFFIRSTQ_S 0
+#define VPLAN_TX_QBASE_VFFIRSTQ_M ICE_M(0x3FFF, 0)
+#define VPLAN_TX_QBASE_VFNUMQ_S 16
+#define VPLAN_TX_QBASE_VFNUMQ_M ICE_M(0xFF, 16)
+#define VPLAN_TXQ_MAPENA(_VF) (0x00073800 + ((_VF) * 4))
+#define VPLAN_TXQ_MAPENA_TX_ENA_M BIT(0)
+#define GL_MDET_RX 0x00294C00
+#define GL_MDET_RX_QNUM_S 0
+#define GL_MDET_RX_QNUM_M ICE_M(0x7FFF, 0)
+#define GL_MDET_RX_VF_NUM_S 15
+#define GL_MDET_RX_VF_NUM_M ICE_M(0xFF, 15)
+#define GL_MDET_RX_PF_NUM_S 23
+#define GL_MDET_RX_PF_NUM_M ICE_M(0x7, 23)
+#define GL_MDET_RX_MAL_TYPE_S 26
+#define GL_MDET_RX_MAL_TYPE_M ICE_M(0x1F, 26)
+#define GL_MDET_RX_VALID_M BIT(31)
+#define GL_MDET_TX_PQM 0x002D2E00
+#define GL_MDET_TX_PQM_PF_NUM_S 0
+#define GL_MDET_TX_PQM_PF_NUM_M ICE_M(0x7, 0)
+#define GL_MDET_TX_PQM_VF_NUM_S 4
+#define GL_MDET_TX_PQM_VF_NUM_M ICE_M(0xFF, 4)
+#define GL_MDET_TX_PQM_QNUM_S 12
+#define GL_MDET_TX_PQM_QNUM_M ICE_M(0x3FFF, 12)
+#define GL_MDET_TX_PQM_MAL_TYPE_S 26
+#define GL_MDET_TX_PQM_MAL_TYPE_M ICE_M(0x1F, 26)
+#define GL_MDET_TX_PQM_VALID_M BIT(31)
+#define GL_MDET_TX_TCLAN 0x000FC068
+#define GL_MDET_TX_TCLAN_QNUM_S 0
+#define GL_MDET_TX_TCLAN_QNUM_M ICE_M(0x7FFF, 0)
+#define GL_MDET_TX_TCLAN_VF_NUM_S 15
+#define GL_MDET_TX_TCLAN_VF_NUM_M ICE_M(0xFF, 15)
+#define GL_MDET_TX_TCLAN_PF_NUM_S 23
+#define GL_MDET_TX_TCLAN_PF_NUM_M ICE_M(0x7, 23)
+#define GL_MDET_TX_TCLAN_MAL_TYPE_S 26
+#define GL_MDET_TX_TCLAN_MAL_TYPE_M ICE_M(0x1F, 26)
+#define GL_MDET_TX_TCLAN_VALID_M BIT(31)
+#define PF_MDET_RX 0x00294280
+#define PF_MDET_RX_VALID_M BIT(0)
+#define PF_MDET_TX_PQM 0x002D2C80
+#define PF_MDET_TX_PQM_VALID_M BIT(0)
+#define PF_MDET_TX_TCLAN 0x000FC000
+#define PF_MDET_TX_TCLAN_VALID_M BIT(0)
+#define VP_MDET_RX(_VF) (0x00294400 + ((_VF) * 4))
+#define VP_MDET_RX_VALID_M BIT(0)
+#define VP_MDET_TX_PQM(_VF) (0x002D2000 + ((_VF) * 4))
+#define VP_MDET_TX_PQM_VALID_M BIT(0)
+#define VP_MDET_TX_TCLAN(_VF) (0x000FB800 + ((_VF) * 4))
+#define VP_MDET_TX_TCLAN_VALID_M BIT(0)
+#define VP_MDET_TX_TDPU(_VF) (0x00040000 + ((_VF) * 4))
+#define VP_MDET_TX_TDPU_VALID_M BIT(0)
+#define GLNVM_FLA 0x000B6108
+#define GLNVM_FLA_LOCKED_M BIT(6)
+#define GLNVM_GENS 0x000B6100
+#define GLNVM_GENS_SR_SIZE_S 5
+#define GLNVM_GENS_SR_SIZE_M ICE_M(0x7, 5)
+#define GLNVM_ULD 0x000B6008
+#define GLNVM_ULD_CORER_DONE_M BIT(3)
+#define GLNVM_ULD_GLOBR_DONE_M BIT(4)
+#define GLPCI_CNF2 0x000BE004
+#define GLPCI_CNF2_CACHELINE_SIZE_M BIT(1)
+#define PF_FUNC_RID 0x0009E880
+#define PF_FUNC_RID_FUNC_NUM_S 0
+#define PF_FUNC_RID_FUNC_NUM_M ICE_M(0x7, 0)
+#define PF_PCI_CIAA 0x0009E580
+#define PF_PCI_CIAA_VF_NUM_S 12
+#define PF_PCI_CIAD 0x0009E500
+#define GL_PWR_MODE_CTL 0x000B820C
+#define GL_PWR_MODE_CTL_CAR_MAX_BW_S 30
+#define GL_PWR_MODE_CTL_CAR_MAX_BW_M ICE_M(0x3, 30)
+#define GLPRT_BPRCH(_i) (0x00381384 + ((_i) * 8))
+#define GLPRT_BPRCL(_i) (0x00381380 + ((_i) * 8))
+#define GLPRT_BPTCH(_i) (0x00381244 + ((_i) * 8))
+#define GLPRT_BPTCL(_i) (0x00381240 + ((_i) * 8))
+#define GLPRT_CRCERRS(_i) (0x00380100 + ((_i) * 8))
+#define GLPRT_GORCH(_i) (0x00380004 + ((_i) * 8))
+#define GLPRT_GORCL(_i) (0x00380000 + ((_i) * 8))
+#define GLPRT_GOTCH(_i) (0x00380B44 + ((_i) * 8))
+#define GLPRT_GOTCL(_i) (0x00380B40 + ((_i) * 8))
+#define GLPRT_ILLERRC(_i) (0x003801C0 + ((_i) * 8))
+#define GLPRT_LXOFFRXC(_i) (0x003802C0 + ((_i) * 8))
+#define GLPRT_LXOFFTXC(_i) (0x00381180 + ((_i) * 8))
+#define GLPRT_LXONRXC(_i) (0x00380280 + ((_i) * 8))
+#define GLPRT_LXONTXC(_i) (0x00381140 + ((_i) * 8))
+#define GLPRT_MLFC(_i) (0x00380040 + ((_i) * 8))
+#define GLPRT_MPRCH(_i) (0x00381344 + ((_i) * 8))
+#define GLPRT_MPRCL(_i) (0x00381340 + ((_i) * 8))
+#define GLPRT_MPTCH(_i) (0x00381204 + ((_i) * 8))
+#define GLPRT_MPTCL(_i) (0x00381200 + ((_i) * 8))
+#define GLPRT_MRFC(_i) (0x00380080 + ((_i) * 8))
+#define GLPRT_PRC1023H(_i) (0x00380A04 + ((_i) * 8))
+#define GLPRT_PRC1023L(_i) (0x00380A00 + ((_i) * 8))
+#define GLPRT_PRC127H(_i) (0x00380944 + ((_i) * 8))
+#define GLPRT_PRC127L(_i) (0x00380940 + ((_i) * 8))
+#define GLPRT_PRC1522H(_i) (0x00380A44 + ((_i) * 8))
+#define GLPRT_PRC1522L(_i) (0x00380A40 + ((_i) * 8))
+#define GLPRT_PRC255H(_i) (0x00380984 + ((_i) * 8))
+#define GLPRT_PRC255L(_i) (0x00380980 + ((_i) * 8))
+#define GLPRT_PRC511H(_i) (0x003809C4 + ((_i) * 8))
+#define GLPRT_PRC511L(_i) (0x003809C0 + ((_i) * 8))
+#define GLPRT_PRC64H(_i) (0x00380904 + ((_i) * 8))
+#define GLPRT_PRC64L(_i) (0x00380900 + ((_i) * 8))
+#define GLPRT_PRC9522H(_i) (0x00380A84 + ((_i) * 8))
+#define GLPRT_PRC9522L(_i) (0x00380A80 + ((_i) * 8))
+#define GLPRT_PTC1023H(_i) (0x00380C84 + ((_i) * 8))
+#define GLPRT_PTC1023L(_i) (0x00380C80 + ((_i) * 8))
+#define GLPRT_PTC127H(_i) (0x00380BC4 + ((_i) * 8))
+#define GLPRT_PTC127L(_i) (0x00380BC0 + ((_i) * 8))
+#define GLPRT_PTC1522H(_i) (0x00380CC4 + ((_i) * 8))
+#define GLPRT_PTC1522L(_i) (0x00380CC0 + ((_i) * 8))
+#define GLPRT_PTC255H(_i) (0x00380C04 + ((_i) * 8))
+#define GLPRT_PTC255L(_i) (0x00380C00 + ((_i) * 8))
+#define GLPRT_PTC511H(_i) (0x00380C44 + ((_i) * 8))
+#define GLPRT_PTC511L(_i) (0x00380C40 + ((_i) * 8))
+#define GLPRT_PTC64H(_i) (0x00380B84 + ((_i) * 8))
+#define GLPRT_PTC64L(_i) (0x00380B80 + ((_i) * 8))
+#define GLPRT_PTC9522H(_i) (0x00380D04 + ((_i) * 8))
+#define GLPRT_PTC9522L(_i) (0x00380D00 + ((_i) * 8))
+#define GLPRT_RFC(_i) (0x00380AC0 + ((_i) * 8))
+#define GLPRT_RJC(_i) (0x00380B00 + ((_i) * 8))
+#define GLPRT_RLEC(_i) (0x00380140 + ((_i) * 8))
+#define GLPRT_ROC(_i) (0x00380240 + ((_i) * 8))
+#define GLPRT_RUC(_i) (0x00380200 + ((_i) * 8))
+#define GLPRT_TDOLD(_i) (0x00381280 + ((_i) * 8))
+#define GLPRT_UPRCH(_i) (0x00381304 + ((_i) * 8))
+#define GLPRT_UPRCL(_i) (0x00381300 + ((_i) * 8))
+#define GLPRT_UPTCH(_i) (0x003811C4 + ((_i) * 8))
+#define GLPRT_UPTCL(_i) (0x003811C0 + ((_i) * 8))
+#define GLV_BPRCH(_i) (0x003B6004 + ((_i) * 8))
+#define GLV_BPRCL(_i) (0x003B6000 + ((_i) * 8))
+#define GLV_BPTCH(_i) (0x0030E004 + ((_i) * 8))
+#define GLV_BPTCL(_i) (0x0030E000 + ((_i) * 8))
+#define GLV_GORCH(_i) (0x003B0004 + ((_i) * 8))
+#define GLV_GORCL(_i) (0x003B0000 + ((_i) * 8))
+#define GLV_GOTCH(_i) (0x00300004 + ((_i) * 8))
+#define GLV_GOTCL(_i) (0x00300000 + ((_i) * 8))
+#define GLV_MPRCH(_i) (0x003B4004 + ((_i) * 8))
+#define GLV_MPRCL(_i) (0x003B4000 + ((_i) * 8))
+#define GLV_MPTCH(_i) (0x0030C004 + ((_i) * 8))
+#define GLV_MPTCL(_i) (0x0030C000 + ((_i) * 8))
+#define GLV_RDPC(_i) (0x00294C04 + ((_i) * 4))
+#define GLV_TEPC(_VSI) (0x00312000 + ((_VSI) * 4))
+#define GLV_UPRCH(_i) (0x003B2004 + ((_i) * 8))
+#define GLV_UPRCL(_i) (0x003B2000 + ((_i) * 8))
+#define GLV_UPTCH(_i) (0x0030A004 + ((_i) * 8))
+#define GLV_UPTCL(_i) (0x0030A000 + ((_i) * 8))
+#define PF_VT_PFALLOC_HIF 0x0009DD80
+#define VSIQF_HKEY_MAX_INDEX 12
+#define VSIQF_HLUT_MAX_INDEX 15
+#define VFINT_DYN_CTLN(_i) (0x00003800 + ((_i) * 4))
+#define VFINT_DYN_CTLN_CLEARPBA_M BIT(1)
#endif /* _ICE_HW_AUTOGEN_H_ */
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 068dbc740b76..7d2a66739e3f 100644
--- a/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h
+++ b/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h
@@ -188,23 +188,25 @@ struct ice_32b_rx_flex_desc_nic {
* with a specific metadata (profile 7 reserved for HW)
*/
enum ice_rxdid {
- ICE_RXDID_START = 0,
- ICE_RXDID_LEGACY_0 = ICE_RXDID_START,
- ICE_RXDID_LEGACY_1,
- ICE_RXDID_FLX_START,
- ICE_RXDID_FLEX_NIC = ICE_RXDID_FLX_START,
- ICE_RXDID_FLX_LAST = 63,
- ICE_RXDID_LAST = ICE_RXDID_FLX_LAST
+ ICE_RXDID_LEGACY_0 = 0,
+ ICE_RXDID_LEGACY_1 = 1,
+ ICE_RXDID_FLEX_NIC = 2,
+ ICE_RXDID_FLEX_NIC_2 = 6,
+ ICE_RXDID_HW = 7,
+ ICE_RXDID_LAST = 63,
};
/* Receive Flex Descriptor Rx opcode values */
#define ICE_RX_OPC_MDID 0x01
/* Receive Descriptor MDID values */
-#define ICE_RX_MDID_FLOW_ID_LOWER 5
-#define ICE_RX_MDID_FLOW_ID_HIGH 6
-#define ICE_RX_MDID_HASH_LOW 56
-#define ICE_RX_MDID_HASH_HIGH 57
+enum ice_flex_rx_mdid {
+ ICE_RX_MDID_FLOW_ID_LOWER = 5,
+ ICE_RX_MDID_FLOW_ID_HIGH,
+ ICE_RX_MDID_SRC_VSI = 19,
+ ICE_RX_MDID_HASH_LOW = 56,
+ ICE_RX_MDID_HASH_HIGH,
+};
/* Rx Flag64 packet flag bits */
enum ice_rx_flg64_bits {
@@ -416,6 +418,7 @@ struct ice_tlan_ctx {
u8 pf_num;
u16 vmvf_num;
u8 vmvf_type;
+#define ICE_TLAN_CTX_VMVF_TYPE_VF 0
#define ICE_TLAN_CTX_VMVF_TYPE_VMQ 1
#define ICE_TLAN_CTX_VMVF_TYPE_PF 2
u16 src_vsi;
@@ -471,4 +474,16 @@ static inline struct ice_rx_ptype_decoded ice_decode_rx_desc_ptype(u16 ptype)
{
return ice_ptype_lkup[ptype];
}
+
+#define ICE_LINK_SPEED_UNKNOWN 0
+#define ICE_LINK_SPEED_10MBPS 10
+#define ICE_LINK_SPEED_100MBPS 100
+#define ICE_LINK_SPEED_1000MBPS 1000
+#define ICE_LINK_SPEED_2500MBPS 2500
+#define ICE_LINK_SPEED_5000MBPS 5000
+#define ICE_LINK_SPEED_10000MBPS 10000
+#define ICE_LINK_SPEED_20000MBPS 20000
+#define ICE_LINK_SPEED_25000MBPS 25000
+#define ICE_LINK_SPEED_40000MBPS 40000
+
#endif /* _ICE_LAN_TX_RX_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
new file mode 100644
index 000000000000..1041fa2a7767
--- /dev/null
+++ b/drivers/net/ethernet/intel/ice/ice_lib.c
@@ -0,0 +1,2621 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2018, Intel Corporation. */
+
+#include "ice.h"
+#include "ice_lib.h"
+
+/**
+ * ice_setup_rx_ctx - Configure a receive ring context
+ * @ring: The Rx ring to configure
+ *
+ * Configure the Rx descriptor ring in RLAN context.
+ */
+static int ice_setup_rx_ctx(struct ice_ring *ring)
+{
+ struct ice_vsi *vsi = ring->vsi;
+ struct ice_hw *hw = &vsi->back->hw;
+ u32 rxdid = ICE_RXDID_FLEX_NIC;
+ struct ice_rlan_ctx rlan_ctx;
+ u32 regval;
+ u16 pf_q;
+ int err;
+
+ /* what is RX queue number in global space of 2K Rx queues */
+ pf_q = vsi->rxq_map[ring->q_index];
+
+ /* clear the context structure first */
+ memset(&rlan_ctx, 0, sizeof(rlan_ctx));
+
+ rlan_ctx.base = ring->dma >> 7;
+
+ rlan_ctx.qlen = ring->count;
+
+ /* Receive Packet Data Buffer Size.
+ * The Packet Data Buffer Size is defined in 128 byte units.
+ */
+ rlan_ctx.dbuf = vsi->rx_buf_len >> ICE_RLAN_CTX_DBUF_S;
+
+ /* use 32 byte descriptors */
+ rlan_ctx.dsize = 1;
+
+ /* Strip the Ethernet CRC bytes before the packet is posted to host
+ * memory.
+ */
+ rlan_ctx.crcstrip = 1;
+
+ /* L2TSEL flag defines the reported L2 Tags in the receive descriptor */
+ rlan_ctx.l2tsel = 1;
+
+ rlan_ctx.dtype = ICE_RX_DTYPE_NO_SPLIT;
+ rlan_ctx.hsplit_0 = ICE_RLAN_RX_HSPLIT_0_NO_SPLIT;
+ rlan_ctx.hsplit_1 = ICE_RLAN_RX_HSPLIT_1_NO_SPLIT;
+
+ /* This controls whether VLAN is stripped from inner headers
+ * The VLAN in the inner L2 header is stripped to the receive
+ * descriptor if enabled by this flag.
+ */
+ rlan_ctx.showiv = 0;
+
+ /* Max packet size for this queue - must not be set to a larger value
+ * than 5 x DBUF
+ */
+ rlan_ctx.rxmax = min_t(u16, vsi->max_frame,
+ ICE_MAX_CHAINED_RX_BUFS * vsi->rx_buf_len);
+
+ /* Rx queue threshold in units of 64 */
+ rlan_ctx.lrxqthresh = 1;
+
+ /* Enable Flexible Descriptors in the queue context which
+ * allows this driver to select a specific receive descriptor format
+ */
+ if (vsi->type != ICE_VSI_VF) {
+ regval = rd32(hw, QRXFLXP_CNTXT(pf_q));
+ regval |= (rxdid << QRXFLXP_CNTXT_RXDID_IDX_S) &
+ QRXFLXP_CNTXT_RXDID_IDX_M;
+
+ /* increasing context priority to pick up profile id;
+ * default is 0x01; setting to 0x03 to ensure profile
+ * is programming if prev context is of same priority
+ */
+ regval |= (0x03 << QRXFLXP_CNTXT_RXDID_PRIO_S) &
+ QRXFLXP_CNTXT_RXDID_PRIO_M;
+
+ wr32(hw, QRXFLXP_CNTXT(pf_q), regval);
+ }
+
+ /* Absolute queue number out of 2K needs to be passed */
+ err = ice_write_rxq_ctx(hw, &rlan_ctx, pf_q);
+ if (err) {
+ dev_err(&vsi->back->pdev->dev,
+ "Failed to set LAN Rx queue context for absolute Rx queue %d error: %d\n",
+ pf_q, err);
+ return -EIO;
+ }
+
+ if (vsi->type == ICE_VSI_VF)
+ return 0;
+
+ /* init queue specific tail register */
+ ring->tail = hw->hw_addr + QRX_TAIL(pf_q);
+ writel(0, ring->tail);
+ ice_alloc_rx_bufs(ring, ICE_DESC_UNUSED(ring));
+
+ return 0;
+}
+
+/**
+ * ice_setup_tx_ctx - setup a struct ice_tlan_ctx instance
+ * @ring: The Tx ring to configure
+ * @tlan_ctx: Pointer to the Tx LAN queue context structure to be initialized
+ * @pf_q: queue index in the PF space
+ *
+ * Configure the Tx descriptor ring in TLAN context.
+ */
+static void
+ice_setup_tx_ctx(struct ice_ring *ring, struct ice_tlan_ctx *tlan_ctx, u16 pf_q)
+{
+ struct ice_vsi *vsi = ring->vsi;
+ struct ice_hw *hw = &vsi->back->hw;
+
+ tlan_ctx->base = ring->dma >> ICE_TLAN_CTX_BASE_S;
+
+ tlan_ctx->port_num = vsi->port_info->lport;
+
+ /* Transmit Queue Length */
+ tlan_ctx->qlen = ring->count;
+
+ /* PF number */
+ tlan_ctx->pf_num = hw->pf_id;
+
+ /* queue belongs to a specific VSI type
+ * VF / VM index should be programmed per vmvf_type setting:
+ * for vmvf_type = VF, it is VF number between 0-256
+ * for vmvf_type = VM, it is VM number between 0-767
+ * for PF or EMP this field should be set to zero
+ */
+ switch (vsi->type) {
+ case ICE_VSI_PF:
+ tlan_ctx->vmvf_type = ICE_TLAN_CTX_VMVF_TYPE_PF;
+ break;
+ case ICE_VSI_VF:
+ /* Firmware expects vmvf_num to be absolute VF id */
+ tlan_ctx->vmvf_num = hw->func_caps.vf_base_id + vsi->vf_id;
+ tlan_ctx->vmvf_type = ICE_TLAN_CTX_VMVF_TYPE_VF;
+ break;
+ default:
+ return;
+ }
+
+ /* make sure the context is associated with the right VSI */
+ tlan_ctx->src_vsi = ice_get_hw_vsi_num(hw, vsi->idx);
+
+ tlan_ctx->tso_ena = ICE_TX_LEGACY;
+ tlan_ctx->tso_qnum = pf_q;
+
+ /* Legacy or Advanced Host Interface:
+ * 0: Advanced Host Interface
+ * 1: Legacy Host Interface
+ */
+ tlan_ctx->legacy_int = ICE_TX_LEGACY;
+}
+
+/**
+ * ice_pf_rxq_wait - Wait for a PF's Rx queue to be enabled or disabled
+ * @pf: the PF being configured
+ * @pf_q: the PF queue
+ * @ena: enable or disable state of the queue
+ *
+ * This routine will wait for the given Rx queue of the PF to reach the
+ * enabled or disabled state.
+ * Returns -ETIMEDOUT in case of failing to reach the requested state after
+ * multiple retries; else will return 0 in case of success.
+ */
+static int ice_pf_rxq_wait(struct ice_pf *pf, int pf_q, bool ena)
+{
+ int i;
+
+ for (i = 0; i < ICE_Q_WAIT_RETRY_LIMIT; i++) {
+ u32 rx_reg = rd32(&pf->hw, QRX_CTRL(pf_q));
+
+ if (ena == !!(rx_reg & QRX_CTRL_QENA_STAT_M))
+ break;
+
+ usleep_range(10, 20);
+ }
+ if (i >= ICE_Q_WAIT_RETRY_LIMIT)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+/**
+ * ice_vsi_ctrl_rx_rings - Start or stop a VSI's Rx rings
+ * @vsi: the VSI being configured
+ * @ena: start or stop the Rx rings
+ */
+static int ice_vsi_ctrl_rx_rings(struct ice_vsi *vsi, bool ena)
+{
+ struct ice_pf *pf = vsi->back;
+ struct ice_hw *hw = &pf->hw;
+ int i, j, ret = 0;
+
+ for (i = 0; i < vsi->num_rxq; i++) {
+ int pf_q = vsi->rxq_map[i];
+ u32 rx_reg;
+
+ for (j = 0; j < ICE_Q_WAIT_MAX_RETRY; j++) {
+ rx_reg = rd32(hw, QRX_CTRL(pf_q));
+ if (((rx_reg >> QRX_CTRL_QENA_REQ_S) & 1) ==
+ ((rx_reg >> QRX_CTRL_QENA_STAT_S) & 1))
+ break;
+ usleep_range(1000, 2000);
+ }
+
+ /* Skip if the queue is already in the requested state */
+ if (ena == !!(rx_reg & QRX_CTRL_QENA_STAT_M))
+ continue;
+
+ /* turn on/off the queue */
+ if (ena)
+ rx_reg |= QRX_CTRL_QENA_REQ_M;
+ else
+ rx_reg &= ~QRX_CTRL_QENA_REQ_M;
+ wr32(hw, QRX_CTRL(pf_q), rx_reg);
+
+ /* wait for the change to finish */
+ ret = ice_pf_rxq_wait(pf, pf_q, ena);
+ if (ret) {
+ dev_err(&pf->pdev->dev,
+ "VSI idx %d Rx ring %d %sable timeout\n",
+ vsi->idx, pf_q, (ena ? "en" : "dis"));
+ break;
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * ice_vsi_alloc_arrays - Allocate queue and vector pointer arrays for the VSI
+ * @vsi: VSI pointer
+ * @alloc_qvectors: a bool to specify if q_vectors need to be allocated.
+ *
+ * On error: returns error code (negative)
+ * On success: returns 0
+ */
+static int ice_vsi_alloc_arrays(struct ice_vsi *vsi, bool alloc_qvectors)
+{
+ struct ice_pf *pf = vsi->back;
+
+ /* allocate memory for both Tx and Rx ring pointers */
+ vsi->tx_rings = devm_kcalloc(&pf->pdev->dev, vsi->alloc_txq,
+ sizeof(struct ice_ring *), GFP_KERNEL);
+ if (!vsi->tx_rings)
+ goto err_txrings;
+
+ vsi->rx_rings = devm_kcalloc(&pf->pdev->dev, vsi->alloc_rxq,
+ sizeof(struct ice_ring *), GFP_KERNEL);
+ if (!vsi->rx_rings)
+ goto err_rxrings;
+
+ if (alloc_qvectors) {
+ /* allocate memory for q_vector pointers */
+ vsi->q_vectors = devm_kcalloc(&pf->pdev->dev,
+ vsi->num_q_vectors,
+ sizeof(struct ice_q_vector *),
+ GFP_KERNEL);
+ if (!vsi->q_vectors)
+ goto err_vectors;
+ }
+
+ return 0;
+
+err_vectors:
+ devm_kfree(&pf->pdev->dev, vsi->rx_rings);
+err_rxrings:
+ devm_kfree(&pf->pdev->dev, vsi->tx_rings);
+err_txrings:
+ return -ENOMEM;
+}
+
+/**
+ * ice_vsi_set_num_qs - Set num queues, descriptors and vectors for a VSI
+ * @vsi: the VSI being configured
+ *
+ * Return 0 on success and a negative value on error
+ */
+static void ice_vsi_set_num_qs(struct ice_vsi *vsi)
+{
+ struct ice_pf *pf = vsi->back;
+
+ switch (vsi->type) {
+ case ICE_VSI_PF:
+ vsi->alloc_txq = pf->num_lan_tx;
+ vsi->alloc_rxq = pf->num_lan_rx;
+ vsi->num_desc = ALIGN(ICE_DFLT_NUM_DESC, ICE_REQ_DESC_MULTIPLE);
+ vsi->num_q_vectors = max_t(int, pf->num_lan_rx, pf->num_lan_tx);
+ break;
+ case ICE_VSI_VF:
+ vsi->alloc_txq = pf->num_vf_qps;
+ vsi->alloc_rxq = pf->num_vf_qps;
+ /* pf->num_vf_msix includes (VF miscellaneous vector +
+ * data queue interrupts). Since vsi->num_q_vectors is number
+ * of queues vectors, subtract 1 from the original vector
+ * count
+ */
+ vsi->num_q_vectors = pf->num_vf_msix - 1;
+ break;
+ default:
+ dev_warn(&vsi->back->pdev->dev, "Unknown VSI type %d\n",
+ vsi->type);
+ break;
+ }
+}
+
+/**
+ * ice_get_free_slot - get the next non-NULL location index in array
+ * @array: array to search
+ * @size: size of the array
+ * @curr: last known occupied index to be used as a search hint
+ *
+ * void * is being used to keep the functionality generic. This lets us use this
+ * function on any array of pointers.
+ */
+static int ice_get_free_slot(void *array, int size, int curr)
+{
+ int **tmp_array = (int **)array;
+ int next;
+
+ if (curr < (size - 1) && !tmp_array[curr + 1]) {
+ next = curr + 1;
+ } else {
+ int i = 0;
+
+ while ((i < size) && (tmp_array[i]))
+ i++;
+ if (i == size)
+ next = ICE_NO_VSI;
+ else
+ next = i;
+ }
+ return next;
+}
+
+/**
+ * ice_vsi_delete - delete a VSI from the switch
+ * @vsi: pointer to VSI being removed
+ */
+void ice_vsi_delete(struct ice_vsi *vsi)
+{
+ struct ice_pf *pf = vsi->back;
+ struct ice_vsi_ctx ctxt;
+ enum ice_status status;
+
+ if (vsi->type == ICE_VSI_VF)
+ ctxt.vf_num = vsi->vf_id;
+ ctxt.vsi_num = vsi->vsi_num;
+
+ memcpy(&ctxt.info, &vsi->info, sizeof(struct ice_aqc_vsi_props));
+
+ status = ice_free_vsi(&pf->hw, vsi->idx, &ctxt, false, NULL);
+ if (status)
+ dev_err(&pf->pdev->dev, "Failed to delete VSI %i in FW\n",
+ vsi->vsi_num);
+}
+
+/**
+ * ice_vsi_free_arrays - clean up VSI resources
+ * @vsi: pointer to VSI being cleared
+ * @free_qvectors: bool to specify if q_vectors should be deallocated
+ */
+static void ice_vsi_free_arrays(struct ice_vsi *vsi, bool free_qvectors)
+{
+ struct ice_pf *pf = vsi->back;
+
+ /* free the ring and vector containers */
+ if (free_qvectors && vsi->q_vectors) {
+ devm_kfree(&pf->pdev->dev, vsi->q_vectors);
+ vsi->q_vectors = NULL;
+ }
+ if (vsi->tx_rings) {
+ devm_kfree(&pf->pdev->dev, vsi->tx_rings);
+ vsi->tx_rings = NULL;
+ }
+ if (vsi->rx_rings) {
+ devm_kfree(&pf->pdev->dev, vsi->rx_rings);
+ vsi->rx_rings = NULL;
+ }
+}
+
+/**
+ * ice_vsi_clear - clean up and deallocate the provided VSI
+ * @vsi: pointer to VSI being cleared
+ *
+ * This deallocates the VSI's queue resources, removes it from the PF's
+ * VSI array if necessary, and deallocates the VSI
+ *
+ * Returns 0 on success, negative on failure
+ */
+int ice_vsi_clear(struct ice_vsi *vsi)
+{
+ struct ice_pf *pf = NULL;
+
+ if (!vsi)
+ return 0;
+
+ if (!vsi->back)
+ return -EINVAL;
+
+ pf = vsi->back;
+
+ if (!pf->vsi[vsi->idx] || pf->vsi[vsi->idx] != vsi) {
+ dev_dbg(&pf->pdev->dev, "vsi does not exist at pf->vsi[%d]\n",
+ vsi->idx);
+ return -EINVAL;
+ }
+
+ mutex_lock(&pf->sw_mutex);
+ /* updates the PF for this cleared VSI */
+
+ pf->vsi[vsi->idx] = NULL;
+ if (vsi->idx < pf->next_vsi)
+ pf->next_vsi = vsi->idx;
+
+ ice_vsi_free_arrays(vsi, true);
+ mutex_unlock(&pf->sw_mutex);
+ devm_kfree(&pf->pdev->dev, vsi);
+
+ return 0;
+}
+
+/**
+ * ice_msix_clean_rings - MSIX mode Interrupt Handler
+ * @irq: interrupt number
+ * @data: pointer to a q_vector
+ */
+static irqreturn_t ice_msix_clean_rings(int __always_unused irq, void *data)
+{
+ struct ice_q_vector *q_vector = (struct ice_q_vector *)data;
+
+ if (!q_vector->tx.ring && !q_vector->rx.ring)
+ return IRQ_HANDLED;
+
+ napi_schedule(&q_vector->napi);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * ice_vsi_alloc - Allocates the next available struct VSI in the PF
+ * @pf: board private structure
+ * @type: type of VSI
+ *
+ * returns a pointer to a VSI on success, NULL on failure.
+ */
+static struct ice_vsi *ice_vsi_alloc(struct ice_pf *pf, enum ice_vsi_type type)
+{
+ struct ice_vsi *vsi = NULL;
+
+ /* Need to protect the allocation of the VSIs at the PF level */
+ mutex_lock(&pf->sw_mutex);
+
+ /* If we have already allocated our maximum number of VSIs,
+ * pf->next_vsi will be ICE_NO_VSI. If not, pf->next_vsi index
+ * is available to be populated
+ */
+ if (pf->next_vsi == ICE_NO_VSI) {
+ dev_dbg(&pf->pdev->dev, "out of VSI slots!\n");
+ goto unlock_pf;
+ }
+
+ vsi = devm_kzalloc(&pf->pdev->dev, sizeof(*vsi), GFP_KERNEL);
+ if (!vsi)
+ goto unlock_pf;
+
+ vsi->type = type;
+ vsi->back = pf;
+ set_bit(__ICE_DOWN, vsi->state);
+ vsi->idx = pf->next_vsi;
+ vsi->work_lmt = ICE_DFLT_IRQ_WORK;
+
+ ice_vsi_set_num_qs(vsi);
+
+ switch (vsi->type) {
+ case ICE_VSI_PF:
+ if (ice_vsi_alloc_arrays(vsi, true))
+ goto err_rings;
+
+ /* Setup default MSIX irq handler for VSI */
+ vsi->irq_handler = ice_msix_clean_rings;
+ break;
+ case ICE_VSI_VF:
+ if (ice_vsi_alloc_arrays(vsi, true))
+ goto err_rings;
+ break;
+ default:
+ dev_warn(&pf->pdev->dev, "Unknown VSI type %d\n", vsi->type);
+ goto unlock_pf;
+ }
+
+ /* fill VSI slot in the PF struct */
+ pf->vsi[pf->next_vsi] = vsi;
+
+ /* prepare pf->next_vsi for next use */
+ pf->next_vsi = ice_get_free_slot(pf->vsi, pf->num_alloc_vsi,
+ pf->next_vsi);
+ goto unlock_pf;
+
+err_rings:
+ devm_kfree(&pf->pdev->dev, vsi);
+ vsi = NULL;
+unlock_pf:
+ mutex_unlock(&pf->sw_mutex);
+ return vsi;
+}
+
+/**
+ * ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
+ * @vsi: the VSI getting queues
+ *
+ * Return 0 on success and a negative value on error
+ */
+static int ice_vsi_get_qs_contig(struct ice_vsi *vsi)
+{
+ struct ice_pf *pf = vsi->back;
+ int offset, ret = 0;
+
+ mutex_lock(&pf->avail_q_mutex);
+ /* look for contiguous block of queues for Tx */
+ offset = bitmap_find_next_zero_area(pf->avail_txqs, ICE_MAX_TXQS,
+ 0, vsi->alloc_txq, 0);
+ if (offset < ICE_MAX_TXQS) {
+ int i;
+
+ bitmap_set(pf->avail_txqs, offset, vsi->alloc_txq);
+ for (i = 0; i < vsi->alloc_txq; i++)
+ vsi->txq_map[i] = i + offset;
+ } else {
+ ret = -ENOMEM;
+ vsi->tx_mapping_mode = ICE_VSI_MAP_SCATTER;
+ }
+
+ /* look for contiguous block of queues for Rx */
+ offset = bitmap_find_next_zero_area(pf->avail_rxqs, ICE_MAX_RXQS,
+ 0, vsi->alloc_rxq, 0);
+ if (offset < ICE_MAX_RXQS) {
+ int i;
+
+ bitmap_set(pf->avail_rxqs, offset, vsi->alloc_rxq);
+ for (i = 0; i < vsi->alloc_rxq; i++)
+ vsi->rxq_map[i] = i + offset;
+ } else {
+ ret = -ENOMEM;
+ vsi->rx_mapping_mode = ICE_VSI_MAP_SCATTER;
+ }
+ mutex_unlock(&pf->avail_q_mutex);
+
+ return ret;
+}
+
+/**
+ * ice_vsi_get_qs_scatter - Assign a scattered queues to VSI
+ * @vsi: the VSI getting queues
+ *
+ * Return 0 on success and a negative value on error
+ */
+static int ice_vsi_get_qs_scatter(struct ice_vsi *vsi)
+{
+ struct ice_pf *pf = vsi->back;
+ int i, index = 0;
+
+ mutex_lock(&pf->avail_q_mutex);
+
+ if (vsi->tx_mapping_mode == ICE_VSI_MAP_SCATTER) {
+ for (i = 0; i < vsi->alloc_txq; i++) {
+ index = find_next_zero_bit(pf->avail_txqs,
+ ICE_MAX_TXQS, index);
+ if (index < ICE_MAX_TXQS) {
+ set_bit(index, pf->avail_txqs);
+ vsi->txq_map[i] = index;
+ } else {
+ goto err_scatter_tx;
+ }
+ }
+ }
+
+ if (vsi->rx_mapping_mode == ICE_VSI_MAP_SCATTER) {
+ for (i = 0; i < vsi->alloc_rxq; i++) {
+ index = find_next_zero_bit(pf->avail_rxqs,
+ ICE_MAX_RXQS, index);
+ if (index < ICE_MAX_RXQS) {
+ set_bit(index, pf->avail_rxqs);
+ vsi->rxq_map[i] = index;
+ } else {
+ goto err_scatter_rx;
+ }
+ }
+ }
+
+ mutex_unlock(&pf->avail_q_mutex);
+ return 0;
+
+err_scatter_rx:
+ /* unflag any queues we have grabbed (i is failed position) */
+ for (index = 0; index < i; index++) {
+ clear_bit(vsi->rxq_map[index], pf->avail_rxqs);
+ vsi->rxq_map[index] = 0;
+ }
+ i = vsi->alloc_txq;
+err_scatter_tx:
+ /* i is either position of failed attempt or vsi->alloc_txq */
+ for (index = 0; index < i; index++) {
+ clear_bit(vsi->txq_map[index], pf->avail_txqs);
+ vsi->txq_map[index] = 0;
+ }
+
+ mutex_unlock(&pf->avail_q_mutex);
+ return -ENOMEM;
+}
+
+/**
+ * ice_vsi_get_qs - Assign queues from PF to VSI
+ * @vsi: the VSI to assign queues to
+ *
+ * Returns 0 on success and a negative value on error
+ */
+static int ice_vsi_get_qs(struct ice_vsi *vsi)
+{
+ int ret = 0;
+
+ vsi->tx_mapping_mode = ICE_VSI_MAP_CONTIG;
+ vsi->rx_mapping_mode = ICE_VSI_MAP_CONTIG;
+
+ /* NOTE: ice_vsi_get_qs_contig() will set the Rx/Tx mapping
+ * modes individually to scatter if assigning contiguous queues
+ * to Rx or Tx fails
+ */
+ ret = ice_vsi_get_qs_contig(vsi);
+ if (ret < 0) {
+ if (vsi->tx_mapping_mode == ICE_VSI_MAP_SCATTER)
+ vsi->alloc_txq = max_t(u16, vsi->alloc_txq,
+ ICE_MAX_SCATTER_TXQS);
+ if (vsi->rx_mapping_mode == ICE_VSI_MAP_SCATTER)
+ vsi->alloc_rxq = max_t(u16, vsi->alloc_rxq,
+ ICE_MAX_SCATTER_RXQS);
+ ret = ice_vsi_get_qs_scatter(vsi);
+ }
+
+ return ret;
+}
+
+/**
+ * ice_vsi_put_qs - Release queues from VSI to PF
+ * @vsi: the VSI that is going to release queues
+ */
+void ice_vsi_put_qs(struct ice_vsi *vsi)
+{
+ struct ice_pf *pf = vsi->back;
+ int i;
+
+ mutex_lock(&pf->avail_q_mutex);
+
+ for (i = 0; i < vsi->alloc_txq; i++) {
+ clear_bit(vsi->txq_map[i], pf->avail_txqs);
+ vsi->txq_map[i] = ICE_INVAL_Q_INDEX;
+ }
+
+ for (i = 0; i < vsi->alloc_rxq; i++) {
+ clear_bit(vsi->rxq_map[i], pf->avail_rxqs);
+ vsi->rxq_map[i] = ICE_INVAL_Q_INDEX;
+ }
+
+ mutex_unlock(&pf->avail_q_mutex);
+}
+
+/**
+ * ice_rss_clean - Delete RSS related VSI structures that hold user inputs
+ * @vsi: the VSI being removed
+ */
+static void ice_rss_clean(struct ice_vsi *vsi)
+{
+ struct ice_pf *pf;
+
+ pf = vsi->back;
+
+ if (vsi->rss_hkey_user)
+ devm_kfree(&pf->pdev->dev, vsi->rss_hkey_user);
+ if (vsi->rss_lut_user)
+ devm_kfree(&pf->pdev->dev, vsi->rss_lut_user);
+}
+
+/**
+ * ice_vsi_set_rss_params - Setup RSS capabilities per VSI type
+ * @vsi: the VSI being configured
+ */
+static void ice_vsi_set_rss_params(struct ice_vsi *vsi)
+{
+ struct ice_hw_common_caps *cap;
+ struct ice_pf *pf = vsi->back;
+
+ if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) {
+ vsi->rss_size = 1;
+ return;
+ }
+
+ cap = &pf->hw.func_caps.common_cap;
+ switch (vsi->type) {
+ case ICE_VSI_PF:
+ /* PF VSI will inherit RSS instance of PF */
+ vsi->rss_table_size = cap->rss_table_size;
+ vsi->rss_size = min_t(int, num_online_cpus(),
+ BIT(cap->rss_table_entry_width));
+ vsi->rss_lut_type = ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_PF;
+ break;
+ case ICE_VSI_VF:
+ /* VF VSI will gets a small RSS table
+ * For VSI_LUT, LUT size should be set to 64 bytes
+ */
+ vsi->rss_table_size = ICE_VSIQF_HLUT_ARRAY_SIZE;
+ vsi->rss_size = min_t(int, num_online_cpus(),
+ BIT(cap->rss_table_entry_width));
+ vsi->rss_lut_type = ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_VSI;
+ break;
+ default:
+ dev_warn(&pf->pdev->dev, "Unknown VSI type %d\n",
+ vsi->type);
+ break;
+ }
+}
+
+/**
+ * ice_set_dflt_vsi_ctx - Set default VSI context before adding a VSI
+ * @ctxt: the VSI context being set
+ *
+ * This initializes a default VSI context for all sections except the Queues.
+ */
+static void ice_set_dflt_vsi_ctx(struct ice_vsi_ctx *ctxt)
+{
+ u32 table = 0;
+
+ memset(&ctxt->info, 0, sizeof(ctxt->info));
+ /* VSI's should be allocated from shared pool */
+ ctxt->alloc_from_pool = true;
+ /* Src pruning enabled by default */
+ ctxt->info.sw_flags = ICE_AQ_VSI_SW_FLAG_SRC_PRUNE;
+ /* Traffic from VSI can be sent to LAN */
+ ctxt->info.sw_flags2 = ICE_AQ_VSI_SW_FLAG_LAN_ENA;
+ /* By default bits 3 and 4 in vlan_flags are 0's which results in legacy
+ * behavior (show VLAN, DEI, and UP) in descriptor. Also, allow all
+ * packets untagged/tagged.
+ */
+ ctxt->info.vlan_flags = ((ICE_AQ_VSI_VLAN_MODE_ALL &
+ ICE_AQ_VSI_VLAN_MODE_M) >>
+ ICE_AQ_VSI_VLAN_MODE_S);
+ /* Have 1:1 UP mapping for both ingress/egress tables */
+ table |= ICE_UP_TABLE_TRANSLATE(0, 0);
+ table |= ICE_UP_TABLE_TRANSLATE(1, 1);
+ table |= ICE_UP_TABLE_TRANSLATE(2, 2);
+ table |= ICE_UP_TABLE_TRANSLATE(3, 3);
+ table |= ICE_UP_TABLE_TRANSLATE(4, 4);
+ table |= ICE_UP_TABLE_TRANSLATE(5, 5);
+ table |= ICE_UP_TABLE_TRANSLATE(6, 6);
+ table |= ICE_UP_TABLE_TRANSLATE(7, 7);
+ ctxt->info.ingress_table = cpu_to_le32(table);
+ ctxt->info.egress_table = cpu_to_le32(table);
+ /* Have 1:1 UP mapping for outer to inner UP table */
+ ctxt->info.outer_up_table = cpu_to_le32(table);
+ /* No Outer tag support outer_tag_flags remains to zero */
+}
+
+/**
+ * ice_vsi_setup_q_map - Setup a VSI queue map
+ * @vsi: the VSI being configured
+ * @ctxt: VSI context structure
+ */
+static void ice_vsi_setup_q_map(struct ice_vsi *vsi, struct ice_vsi_ctx *ctxt)
+{
+ u16 offset = 0, qmap = 0, numq_tc;
+ u16 pow = 0, max_rss = 0, qcount;
+ u16 qcount_tx = vsi->alloc_txq;
+ u16 qcount_rx = vsi->alloc_rxq;
+ bool ena_tc0 = false;
+ int i;
+
+ /* at least TC0 should be enabled by default */
+ if (vsi->tc_cfg.numtc) {
+ if (!(vsi->tc_cfg.ena_tc & BIT(0)))
+ ena_tc0 = true;
+ } else {
+ ena_tc0 = true;
+ }
+
+ if (ena_tc0) {
+ vsi->tc_cfg.numtc++;
+ vsi->tc_cfg.ena_tc |= 1;
+ }
+
+ numq_tc = qcount_rx / vsi->tc_cfg.numtc;
+
+ /* TC mapping is a function of the number of Rx queues assigned to the
+ * VSI for each traffic class and the offset of these queues.
+ * The first 10 bits are for queue offset for TC0, next 4 bits for no:of
+ * queues allocated to TC0. No:of queues is a power-of-2.
+ *
+ * If TC is not enabled, the queue offset is set to 0, and allocate one
+ * queue, this way, traffic for the given TC will be sent to the default
+ * queue.
+ *
+ * Setup number and offset of Rx queues for all TCs for the VSI
+ */
+
+ qcount = numq_tc;
+ /* qcount will change if RSS is enabled */
+ if (test_bit(ICE_FLAG_RSS_ENA, vsi->back->flags)) {
+ if (vsi->type == ICE_VSI_PF || vsi->type == ICE_VSI_VF) {
+ if (vsi->type == ICE_VSI_PF)
+ max_rss = ICE_MAX_LG_RSS_QS;
+ else
+ max_rss = ICE_MAX_SMALL_RSS_QS;
+ qcount = min_t(int, numq_tc, max_rss);
+ qcount = min_t(int, qcount, vsi->rss_size);
+ }
+ }
+
+ /* find the (rounded up) power-of-2 of qcount */
+ pow = order_base_2(qcount);
+
+ for (i = 0; i < ICE_MAX_TRAFFIC_CLASS; i++) {
+ if (!(vsi->tc_cfg.ena_tc & BIT(i))) {
+ /* TC is not enabled */
+ vsi->tc_cfg.tc_info[i].qoffset = 0;
+ vsi->tc_cfg.tc_info[i].qcount = 1;
+ ctxt->info.tc_mapping[i] = 0;
+ continue;
+ }
+
+ /* TC is enabled */
+ vsi->tc_cfg.tc_info[i].qoffset = offset;
+ vsi->tc_cfg.tc_info[i].qcount = qcount;
+
+ qmap = ((offset << ICE_AQ_VSI_TC_Q_OFFSET_S) &
+ ICE_AQ_VSI_TC_Q_OFFSET_M) |
+ ((pow << ICE_AQ_VSI_TC_Q_NUM_S) &
+ ICE_AQ_VSI_TC_Q_NUM_M);
+ offset += qcount;
+ ctxt->info.tc_mapping[i] = cpu_to_le16(qmap);
+ }
+
+ vsi->num_txq = qcount_tx;
+ vsi->num_rxq = offset;
+
+ if (vsi->type == ICE_VSI_VF && vsi->num_txq != vsi->num_rxq) {
+ dev_dbg(&vsi->back->pdev->dev, "VF VSI should have same number of Tx and Rx queues. Hence making them equal\n");
+ /* since there is a chance that num_rxq could have been changed
+ * in the above for loop, make num_txq equal to num_rxq.
+ */
+ vsi->num_txq = vsi->num_rxq;
+ }
+
+ /* Rx queue mapping */
+ ctxt->info.mapping_flags |= cpu_to_le16(ICE_AQ_VSI_Q_MAP_CONTIG);
+ /* q_mapping buffer holds the info for the first queue allocated for
+ * this VSI in the PF space and also the number of queues associated
+ * with this VSI.
+ */
+ ctxt->info.q_mapping[0] = cpu_to_le16(vsi->rxq_map[0]);
+ ctxt->info.q_mapping[1] = cpu_to_le16(vsi->num_rxq);
+}
+
+/**
+ * ice_set_rss_vsi_ctx - Set RSS VSI context before adding a VSI
+ * @ctxt: the VSI context being set
+ * @vsi: the VSI being configured
+ */
+static void ice_set_rss_vsi_ctx(struct ice_vsi_ctx *ctxt, struct ice_vsi *vsi)
+{
+ u8 lut_type, hash_type;
+
+ switch (vsi->type) {
+ case ICE_VSI_PF:
+ /* PF VSI will inherit RSS instance of PF */
+ lut_type = ICE_AQ_VSI_Q_OPT_RSS_LUT_PF;
+ hash_type = ICE_AQ_VSI_Q_OPT_RSS_TPLZ;
+ break;
+ case ICE_VSI_VF:
+ /* VF VSI will gets a small RSS table which is a VSI LUT type */
+ lut_type = ICE_AQ_VSI_Q_OPT_RSS_LUT_VSI;
+ hash_type = ICE_AQ_VSI_Q_OPT_RSS_TPLZ;
+ break;
+ default:
+ dev_warn(&vsi->back->pdev->dev, "Unknown VSI type %d\n",
+ vsi->type);
+ return;
+ }
+
+ ctxt->info.q_opt_rss = ((lut_type << ICE_AQ_VSI_Q_OPT_RSS_LUT_S) &
+ ICE_AQ_VSI_Q_OPT_RSS_LUT_M) |
+ ((hash_type << ICE_AQ_VSI_Q_OPT_RSS_HASH_S) &
+ ICE_AQ_VSI_Q_OPT_RSS_HASH_M);
+}
+
+/**
+ * ice_vsi_init - Create and initialize a VSI
+ * @vsi: the VSI being configured
+ *
+ * This initializes a VSI context depending on the VSI type to be added and
+ * passes it down to the add_vsi aq command to create a new VSI.
+ */
+static int ice_vsi_init(struct ice_vsi *vsi)
+{
+ struct ice_vsi_ctx ctxt = { 0 };
+ struct ice_pf *pf = vsi->back;
+ struct ice_hw *hw = &pf->hw;
+ int ret = 0;
+
+ switch (vsi->type) {
+ case ICE_VSI_PF:
+ ctxt.flags = ICE_AQ_VSI_TYPE_PF;
+ break;
+ case ICE_VSI_VF:
+ ctxt.flags = ICE_AQ_VSI_TYPE_VF;
+ /* VF number here is the absolute VF number (0-255) */
+ ctxt.vf_num = vsi->vf_id + hw->func_caps.vf_base_id;
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ ice_set_dflt_vsi_ctx(&ctxt);
+ /* if the switch is in VEB mode, allow VSI loopback */
+ if (vsi->vsw->bridge_mode == BRIDGE_MODE_VEB)
+ ctxt.info.sw_flags |= ICE_AQ_VSI_SW_FLAG_ALLOW_LB;
+
+ /* Set LUT type and HASH type if RSS is enabled */
+ if (test_bit(ICE_FLAG_RSS_ENA, pf->flags))
+ ice_set_rss_vsi_ctx(&ctxt, vsi);
+
+ ctxt.info.sw_id = vsi->port_info->sw_id;
+ ice_vsi_setup_q_map(vsi, &ctxt);
+
+ ret = ice_add_vsi(hw, vsi->idx, &ctxt, NULL);
+ if (ret) {
+ dev_err(&pf->pdev->dev,
+ "Add VSI failed, err %d\n", ret);
+ return -EIO;
+ }
+
+ /* keep context for update VSI operations */
+ vsi->info = ctxt.info;
+
+ /* record VSI number returned */
+ vsi->vsi_num = ctxt.vsi_num;
+
+ return ret;
+}
+
+/**
+ * ice_free_q_vector - Free memory allocated for a specific interrupt vector
+ * @vsi: VSI having the memory freed
+ * @v_idx: index of the vector to be freed
+ */
+static void ice_free_q_vector(struct ice_vsi *vsi, int v_idx)
+{
+ struct ice_q_vector *q_vector;
+ struct ice_ring *ring;
+
+ if (!vsi->q_vectors[v_idx]) {
+ dev_dbg(&vsi->back->pdev->dev, "Queue vector at index %d not found\n",
+ v_idx);
+ return;
+ }
+ q_vector = vsi->q_vectors[v_idx];
+
+ ice_for_each_ring(ring, q_vector->tx)
+ ring->q_vector = NULL;
+ ice_for_each_ring(ring, q_vector->rx)
+ ring->q_vector = NULL;
+
+ /* only VSI with an associated netdev is set up with NAPI */
+ if (vsi->netdev)
+ netif_napi_del(&q_vector->napi);
+
+ devm_kfree(&vsi->back->pdev->dev, q_vector);
+ vsi->q_vectors[v_idx] = NULL;
+}
+
+/**
+ * ice_vsi_free_q_vectors - Free memory allocated for interrupt vectors
+ * @vsi: the VSI having memory freed
+ */
+void ice_vsi_free_q_vectors(struct ice_vsi *vsi)
+{
+ int v_idx;
+
+ for (v_idx = 0; v_idx < vsi->num_q_vectors; v_idx++)
+ ice_free_q_vector(vsi, v_idx);
+}
+
+/**
+ * ice_vsi_alloc_q_vector - Allocate memory for a single interrupt vector
+ * @vsi: the VSI being configured
+ * @v_idx: index of the vector in the VSI struct
+ *
+ * We allocate one q_vector. If allocation fails we return -ENOMEM.
+ */
+static int ice_vsi_alloc_q_vector(struct ice_vsi *vsi, int v_idx)
+{
+ struct ice_pf *pf = vsi->back;
+ struct ice_q_vector *q_vector;
+
+ /* allocate q_vector */
+ q_vector = devm_kzalloc(&pf->pdev->dev, sizeof(*q_vector), GFP_KERNEL);
+ if (!q_vector)
+ return -ENOMEM;
+
+ q_vector->vsi = vsi;
+ q_vector->v_idx = v_idx;
+ if (vsi->type == ICE_VSI_VF)
+ goto out;
+ /* only set affinity_mask if the CPU is online */
+ if (cpu_online(v_idx))
+ cpumask_set_cpu(v_idx, &q_vector->affinity_mask);
+
+ /* This will not be called in the driver load path because the netdev
+ * will not be created yet. All other cases with register the NAPI
+ * handler here (i.e. resume, reset/rebuild, etc.)
+ */
+ if (vsi->netdev)
+ netif_napi_add(vsi->netdev, &q_vector->napi, ice_napi_poll,
+ NAPI_POLL_WEIGHT);
+
+out:
+ /* tie q_vector and VSI together */
+ vsi->q_vectors[v_idx] = q_vector;
+
+ return 0;
+}
+
+/**
+ * ice_vsi_alloc_q_vectors - Allocate memory for interrupt vectors
+ * @vsi: the VSI being configured
+ *
+ * We allocate one q_vector per queue interrupt. If allocation fails we
+ * return -ENOMEM.
+ */
+static int ice_vsi_alloc_q_vectors(struct ice_vsi *vsi)
+{
+ struct ice_pf *pf = vsi->back;
+ int v_idx = 0, num_q_vectors;
+ int err;
+
+ if (vsi->q_vectors[0]) {
+ dev_dbg(&pf->pdev->dev, "VSI %d has existing q_vectors\n",
+ vsi->vsi_num);
+ return -EEXIST;
+ }
+
+ if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) {
+ num_q_vectors = vsi->num_q_vectors;
+ } else {
+ err = -EINVAL;
+ goto err_out;
+ }
+
+ for (v_idx = 0; v_idx < num_q_vectors; v_idx++) {
+ err = ice_vsi_alloc_q_vector(vsi, v_idx);
+ if (err)
+ goto err_out;
+ }
+
+ return 0;
+
+err_out:
+ while (v_idx--)
+ ice_free_q_vector(vsi, v_idx);
+
+ dev_err(&pf->pdev->dev,
+ "Failed to allocate %d q_vector for VSI %d, ret=%d\n",
+ vsi->num_q_vectors, vsi->vsi_num, err);
+ vsi->num_q_vectors = 0;
+ return err;
+}
+
+/**
+ * ice_vsi_setup_vector_base - Set up the base vector for the given VSI
+ * @vsi: ptr to the VSI
+ *
+ * This should only be called after ice_vsi_alloc() which allocates the
+ * corresponding SW VSI structure and initializes num_queue_pairs for the
+ * newly allocated VSI.
+ *
+ * Returns 0 on success or negative on failure
+ */
+static int ice_vsi_setup_vector_base(struct ice_vsi *vsi)
+{
+ struct ice_pf *pf = vsi->back;
+ int num_q_vectors = 0;
+
+ if (vsi->sw_base_vector || vsi->hw_base_vector) {
+ dev_dbg(&pf->pdev->dev, "VSI %d has non-zero HW base vector %d or SW base vector %d\n",
+ vsi->vsi_num, vsi->hw_base_vector, vsi->sw_base_vector);
+ return -EEXIST;
+ }
+
+ if (!test_bit(ICE_FLAG_MSIX_ENA, pf->flags))
+ return -ENOENT;
+
+ switch (vsi->type) {
+ case ICE_VSI_PF:
+ num_q_vectors = vsi->num_q_vectors;
+ /* reserve slots from OS requested IRQs */
+ vsi->sw_base_vector = ice_get_res(pf, pf->sw_irq_tracker,
+ num_q_vectors, vsi->idx);
+ if (vsi->sw_base_vector < 0) {
+ dev_err(&pf->pdev->dev,
+ "Failed to get tracking for %d SW vectors for VSI %d, err=%d\n",
+ num_q_vectors, vsi->vsi_num,
+ vsi->sw_base_vector);
+ return -ENOENT;
+ }
+ pf->num_avail_sw_msix -= num_q_vectors;
+
+ /* reserve slots from HW interrupts */
+ vsi->hw_base_vector = ice_get_res(pf, pf->hw_irq_tracker,
+ num_q_vectors, vsi->idx);
+ break;
+ case ICE_VSI_VF:
+ /* take VF misc vector and data vectors into account */
+ num_q_vectors = pf->num_vf_msix;
+ /* For VF VSI, reserve slots only from HW interrupts */
+ vsi->hw_base_vector = ice_get_res(pf, pf->hw_irq_tracker,
+ num_q_vectors, vsi->idx);
+ break;
+ default:
+ dev_warn(&vsi->back->pdev->dev, "Unknown VSI type %d\n",
+ vsi->type);
+ break;
+ }
+
+ if (vsi->hw_base_vector < 0) {
+ dev_err(&pf->pdev->dev,
+ "Failed to get tracking for %d HW vectors for VSI %d, err=%d\n",
+ num_q_vectors, vsi->vsi_num, vsi->hw_base_vector);
+ if (vsi->type != ICE_VSI_VF) {
+ ice_free_res(vsi->back->sw_irq_tracker,
+ vsi->sw_base_vector, vsi->idx);
+ pf->num_avail_sw_msix += num_q_vectors;
+ }
+ return -ENOENT;
+ }
+
+ pf->num_avail_hw_msix -= num_q_vectors;
+
+ return 0;
+}
+
+/**
+ * ice_vsi_clear_rings - Deallocates the Tx and Rx rings for VSI
+ * @vsi: the VSI having rings deallocated
+ */
+static void ice_vsi_clear_rings(struct ice_vsi *vsi)
+{
+ int i;
+
+ if (vsi->tx_rings) {
+ for (i = 0; i < vsi->alloc_txq; i++) {
+ if (vsi->tx_rings[i]) {
+ kfree_rcu(vsi->tx_rings[i], rcu);
+ vsi->tx_rings[i] = NULL;
+ }
+ }
+ }
+ if (vsi->rx_rings) {
+ for (i = 0; i < vsi->alloc_rxq; i++) {
+ if (vsi->rx_rings[i]) {
+ kfree_rcu(vsi->rx_rings[i], rcu);
+ vsi->rx_rings[i] = NULL;
+ }
+ }
+ }
+}
+
+/**
+ * ice_vsi_alloc_rings - Allocates Tx and Rx rings for the VSI
+ * @vsi: VSI which is having rings allocated
+ */
+static int ice_vsi_alloc_rings(struct ice_vsi *vsi)
+{
+ struct ice_pf *pf = vsi->back;
+ int i;
+
+ /* Allocate tx_rings */
+ for (i = 0; i < vsi->alloc_txq; i++) {
+ struct ice_ring *ring;
+
+ /* allocate with kzalloc(), free with kfree_rcu() */
+ ring = kzalloc(sizeof(*ring), GFP_KERNEL);
+
+ if (!ring)
+ goto err_out;
+
+ ring->q_index = i;
+ ring->reg_idx = vsi->txq_map[i];
+ ring->ring_active = false;
+ ring->vsi = vsi;
+ ring->dev = &pf->pdev->dev;
+ ring->count = vsi->num_desc;
+ vsi->tx_rings[i] = ring;
+ }
+
+ /* Allocate rx_rings */
+ for (i = 0; i < vsi->alloc_rxq; i++) {
+ struct ice_ring *ring;
+
+ /* allocate with kzalloc(), free with kfree_rcu() */
+ ring = kzalloc(sizeof(*ring), GFP_KERNEL);
+ if (!ring)
+ goto err_out;
+
+ ring->q_index = i;
+ ring->reg_idx = vsi->rxq_map[i];
+ ring->ring_active = false;
+ ring->vsi = vsi;
+ ring->netdev = vsi->netdev;
+ ring->dev = &pf->pdev->dev;
+ ring->count = vsi->num_desc;
+ vsi->rx_rings[i] = ring;
+ }
+
+ return 0;
+
+err_out:
+ ice_vsi_clear_rings(vsi);
+ return -ENOMEM;
+}
+
+/**
+ * ice_vsi_map_rings_to_vectors - Map VSI rings to interrupt vectors
+ * @vsi: the VSI being configured
+ *
+ * This function maps descriptor rings to the queue-specific vectors allotted
+ * through the MSI-X enabling code. On a constrained vector budget, we map Tx
+ * and Rx rings to the vector as "efficiently" as possible.
+ */
+static void ice_vsi_map_rings_to_vectors(struct ice_vsi *vsi)
+{
+ int q_vectors = vsi->num_q_vectors;
+ int tx_rings_rem, rx_rings_rem;
+ int v_id;
+
+ /* initially assigning remaining rings count to VSIs num queue value */
+ tx_rings_rem = vsi->num_txq;
+ rx_rings_rem = vsi->num_rxq;
+
+ for (v_id = 0; v_id < q_vectors; v_id++) {
+ struct ice_q_vector *q_vector = vsi->q_vectors[v_id];
+ int tx_rings_per_v, rx_rings_per_v, q_id, q_base;
+
+ /* Tx rings mapping to vector */
+ tx_rings_per_v = DIV_ROUND_UP(tx_rings_rem, q_vectors - v_id);
+ q_vector->num_ring_tx = tx_rings_per_v;
+ q_vector->tx.ring = NULL;
+ q_vector->tx.itr_idx = ICE_TX_ITR;
+ q_base = vsi->num_txq - tx_rings_rem;
+
+ for (q_id = q_base; q_id < (q_base + tx_rings_per_v); q_id++) {
+ struct ice_ring *tx_ring = vsi->tx_rings[q_id];
+
+ tx_ring->q_vector = q_vector;
+ tx_ring->next = q_vector->tx.ring;
+ q_vector->tx.ring = tx_ring;
+ }
+ tx_rings_rem -= tx_rings_per_v;
+
+ /* Rx rings mapping to vector */
+ rx_rings_per_v = DIV_ROUND_UP(rx_rings_rem, q_vectors - v_id);
+ q_vector->num_ring_rx = rx_rings_per_v;
+ q_vector->rx.ring = NULL;
+ q_vector->rx.itr_idx = ICE_RX_ITR;
+ q_base = vsi->num_rxq - rx_rings_rem;
+
+ for (q_id = q_base; q_id < (q_base + rx_rings_per_v); q_id++) {
+ struct ice_ring *rx_ring = vsi->rx_rings[q_id];
+
+ rx_ring->q_vector = q_vector;
+ rx_ring->next = q_vector->rx.ring;
+ q_vector->rx.ring = rx_ring;
+ }
+ rx_rings_rem -= rx_rings_per_v;
+ }
+}
+
+/**
+ * ice_vsi_manage_rss_lut - disable/enable RSS
+ * @vsi: the VSI being changed
+ * @ena: boolean value indicating if this is an enable or disable request
+ *
+ * In the event of disable request for RSS, this function will zero out RSS
+ * LUT, while in the event of enable request for RSS, it will reconfigure RSS
+ * LUT.
+ */
+int ice_vsi_manage_rss_lut(struct ice_vsi *vsi, bool ena)
+{
+ int err = 0;
+ u8 *lut;
+
+ lut = devm_kzalloc(&vsi->back->pdev->dev, vsi->rss_table_size,
+ GFP_KERNEL);
+ if (!lut)
+ return -ENOMEM;
+
+ if (ena) {
+ if (vsi->rss_lut_user)
+ memcpy(lut, vsi->rss_lut_user, vsi->rss_table_size);
+ else
+ ice_fill_rss_lut(lut, vsi->rss_table_size,
+ vsi->rss_size);
+ }
+
+ err = ice_set_rss(vsi, NULL, lut, vsi->rss_table_size);
+ devm_kfree(&vsi->back->pdev->dev, lut);
+ return err;
+}
+
+/**
+ * ice_vsi_cfg_rss_lut_key - Configure RSS params for a VSI
+ * @vsi: VSI to be configured
+ */
+static int ice_vsi_cfg_rss_lut_key(struct ice_vsi *vsi)
+{
+ u8 seed[ICE_AQC_GET_SET_RSS_KEY_DATA_RSS_KEY_SIZE];
+ struct ice_aqc_get_set_rss_keys *key;
+ struct ice_pf *pf = vsi->back;
+ enum ice_status status;
+ int err = 0;
+ u8 *lut;
+
+ vsi->rss_size = min_t(int, vsi->rss_size, vsi->num_rxq);
+
+ lut = devm_kzalloc(&pf->pdev->dev, vsi->rss_table_size, GFP_KERNEL);
+ if (!lut)
+ return -ENOMEM;
+
+ if (vsi->rss_lut_user)
+ memcpy(lut, vsi->rss_lut_user, vsi->rss_table_size);
+ else
+ ice_fill_rss_lut(lut, vsi->rss_table_size, vsi->rss_size);
+
+ status = ice_aq_set_rss_lut(&pf->hw, vsi->idx, vsi->rss_lut_type, lut,
+ vsi->rss_table_size);
+
+ if (status) {
+ dev_err(&vsi->back->pdev->dev,
+ "set_rss_lut failed, error %d\n", status);
+ err = -EIO;
+ goto ice_vsi_cfg_rss_exit;
+ }
+
+ key = devm_kzalloc(&vsi->back->pdev->dev, sizeof(*key), GFP_KERNEL);
+ if (!key) {
+ err = -ENOMEM;
+ goto ice_vsi_cfg_rss_exit;
+ }
+
+ if (vsi->rss_hkey_user)
+ memcpy(seed, vsi->rss_hkey_user,
+ ICE_AQC_GET_SET_RSS_KEY_DATA_RSS_KEY_SIZE);
+ else
+ netdev_rss_key_fill((void *)seed,
+ ICE_AQC_GET_SET_RSS_KEY_DATA_RSS_KEY_SIZE);
+ memcpy(&key->standard_rss_key, seed,
+ ICE_AQC_GET_SET_RSS_KEY_DATA_RSS_KEY_SIZE);
+
+ status = ice_aq_set_rss_key(&pf->hw, vsi->idx, key);
+
+ if (status) {
+ dev_err(&vsi->back->pdev->dev, "set_rss_key failed, error %d\n",
+ status);
+ err = -EIO;
+ }
+
+ devm_kfree(&pf->pdev->dev, key);
+ice_vsi_cfg_rss_exit:
+ devm_kfree(&pf->pdev->dev, lut);
+ return err;
+}
+
+/**
+ * ice_add_mac_to_list - Add a mac address filter entry to the list
+ * @vsi: the VSI to be forwarded to
+ * @add_list: pointer to the list which contains MAC filter entries
+ * @macaddr: the MAC address to be added.
+ *
+ * Adds mac address filter entry to the temp list
+ *
+ * Returns 0 on success or ENOMEM on failure.
+ */
+int ice_add_mac_to_list(struct ice_vsi *vsi, struct list_head *add_list,
+ const u8 *macaddr)
+{
+ struct ice_fltr_list_entry *tmp;
+ struct ice_pf *pf = vsi->back;
+
+ tmp = devm_kzalloc(&pf->pdev->dev, sizeof(*tmp), GFP_ATOMIC);
+ if (!tmp)
+ return -ENOMEM;
+
+ tmp->fltr_info.flag = ICE_FLTR_TX;
+ tmp->fltr_info.src_id = ICE_SRC_ID_VSI;
+ tmp->fltr_info.lkup_type = ICE_SW_LKUP_MAC;
+ tmp->fltr_info.fltr_act = ICE_FWD_TO_VSI;
+ tmp->fltr_info.vsi_handle = vsi->idx;
+ ether_addr_copy(tmp->fltr_info.l_data.mac.mac_addr, macaddr);
+
+ INIT_LIST_HEAD(&tmp->list_entry);
+ list_add(&tmp->list_entry, add_list);
+
+ return 0;
+}
+
+/**
+ * ice_update_eth_stats - Update VSI-specific ethernet statistics counters
+ * @vsi: the VSI to be updated
+ */
+void ice_update_eth_stats(struct ice_vsi *vsi)
+{
+ struct ice_eth_stats *prev_es, *cur_es;
+ struct ice_hw *hw = &vsi->back->hw;
+ u16 vsi_num = vsi->vsi_num; /* HW absolute index of a VSI */
+
+ prev_es = &vsi->eth_stats_prev;
+ cur_es = &vsi->eth_stats;
+
+ ice_stat_update40(hw, GLV_GORCH(vsi_num), GLV_GORCL(vsi_num),
+ vsi->stat_offsets_loaded, &prev_es->rx_bytes,
+ &cur_es->rx_bytes);
+
+ ice_stat_update40(hw, GLV_UPRCH(vsi_num), GLV_UPRCL(vsi_num),
+ vsi->stat_offsets_loaded, &prev_es->rx_unicast,
+ &cur_es->rx_unicast);
+
+ ice_stat_update40(hw, GLV_MPRCH(vsi_num), GLV_MPRCL(vsi_num),
+ vsi->stat_offsets_loaded, &prev_es->rx_multicast,
+ &cur_es->rx_multicast);
+
+ ice_stat_update40(hw, GLV_BPRCH(vsi_num), GLV_BPRCL(vsi_num),
+ vsi->stat_offsets_loaded, &prev_es->rx_broadcast,
+ &cur_es->rx_broadcast);
+
+ ice_stat_update32(hw, GLV_RDPC(vsi_num), vsi->stat_offsets_loaded,
+ &prev_es->rx_discards, &cur_es->rx_discards);
+
+ ice_stat_update40(hw, GLV_GOTCH(vsi_num), GLV_GOTCL(vsi_num),
+ vsi->stat_offsets_loaded, &prev_es->tx_bytes,
+ &cur_es->tx_bytes);
+
+ ice_stat_update40(hw, GLV_UPTCH(vsi_num), GLV_UPTCL(vsi_num),
+ vsi->stat_offsets_loaded, &prev_es->tx_unicast,
+ &cur_es->tx_unicast);
+
+ ice_stat_update40(hw, GLV_MPTCH(vsi_num), GLV_MPTCL(vsi_num),
+ vsi->stat_offsets_loaded, &prev_es->tx_multicast,
+ &cur_es->tx_multicast);
+
+ ice_stat_update40(hw, GLV_BPTCH(vsi_num), GLV_BPTCL(vsi_num),
+ vsi->stat_offsets_loaded, &prev_es->tx_broadcast,
+ &cur_es->tx_broadcast);
+
+ ice_stat_update32(hw, GLV_TEPC(vsi_num), vsi->stat_offsets_loaded,
+ &prev_es->tx_errors, &cur_es->tx_errors);
+
+ vsi->stat_offsets_loaded = true;
+}
+
+/**
+ * ice_free_fltr_list - free filter lists helper
+ * @dev: pointer to the device struct
+ * @h: pointer to the list head to be freed
+ *
+ * Helper function to free filter lists previously created using
+ * ice_add_mac_to_list
+ */
+void ice_free_fltr_list(struct device *dev, struct list_head *h)
+{
+ struct ice_fltr_list_entry *e, *tmp;
+
+ list_for_each_entry_safe(e, tmp, h, list_entry) {
+ list_del(&e->list_entry);
+ devm_kfree(dev, e);
+ }
+}
+
+/**
+ * ice_vsi_add_vlan - Add VSI membership for given VLAN
+ * @vsi: the VSI being configured
+ * @vid: VLAN id to be added
+ */
+int ice_vsi_add_vlan(struct ice_vsi *vsi, u16 vid)
+{
+ struct ice_fltr_list_entry *tmp;
+ struct ice_pf *pf = vsi->back;
+ LIST_HEAD(tmp_add_list);
+ enum ice_status status;
+ int err = 0;
+
+ tmp = devm_kzalloc(&pf->pdev->dev, sizeof(*tmp), GFP_KERNEL);
+ if (!tmp)
+ return -ENOMEM;
+
+ tmp->fltr_info.lkup_type = ICE_SW_LKUP_VLAN;
+ tmp->fltr_info.fltr_act = ICE_FWD_TO_VSI;
+ tmp->fltr_info.flag = ICE_FLTR_TX;
+ tmp->fltr_info.src_id = ICE_SRC_ID_VSI;
+ tmp->fltr_info.vsi_handle = vsi->idx;
+ tmp->fltr_info.l_data.vlan.vlan_id = vid;
+
+ INIT_LIST_HEAD(&tmp->list_entry);
+ list_add(&tmp->list_entry, &tmp_add_list);
+
+ status = ice_add_vlan(&pf->hw, &tmp_add_list);
+ if (status) {
+ err = -ENODEV;
+ dev_err(&pf->pdev->dev, "Failure Adding VLAN %d on VSI %i\n",
+ vid, vsi->vsi_num);
+ }
+
+ ice_free_fltr_list(&pf->pdev->dev, &tmp_add_list);
+ return err;
+}
+
+/**
+ * ice_vsi_kill_vlan - Remove VSI membership for a given VLAN
+ * @vsi: the VSI being configured
+ * @vid: VLAN id to be removed
+ *
+ * Returns 0 on success and negative on failure
+ */
+int ice_vsi_kill_vlan(struct ice_vsi *vsi, u16 vid)
+{
+ struct ice_fltr_list_entry *list;
+ struct ice_pf *pf = vsi->back;
+ LIST_HEAD(tmp_add_list);
+ int status = 0;
+
+ list = devm_kzalloc(&pf->pdev->dev, sizeof(*list), GFP_KERNEL);
+ if (!list)
+ return -ENOMEM;
+
+ list->fltr_info.lkup_type = ICE_SW_LKUP_VLAN;
+ list->fltr_info.vsi_handle = vsi->idx;
+ list->fltr_info.fltr_act = ICE_FWD_TO_VSI;
+ list->fltr_info.l_data.vlan.vlan_id = vid;
+ list->fltr_info.flag = ICE_FLTR_TX;
+ list->fltr_info.src_id = ICE_SRC_ID_VSI;
+
+ INIT_LIST_HEAD(&list->list_entry);
+ list_add(&list->list_entry, &tmp_add_list);
+
+ if (ice_remove_vlan(&pf->hw, &tmp_add_list)) {
+ dev_err(&pf->pdev->dev, "Error removing VLAN %d on vsi %i\n",
+ vid, vsi->vsi_num);
+ status = -EIO;
+ }
+
+ ice_free_fltr_list(&pf->pdev->dev, &tmp_add_list);
+ return status;
+}
+
+/**
+ * ice_vsi_cfg_rxqs - Configure the VSI for Rx
+ * @vsi: the VSI being configured
+ *
+ * Return 0 on success and a negative value on error
+ * Configure the Rx VSI for operation.
+ */
+int ice_vsi_cfg_rxqs(struct ice_vsi *vsi)
+{
+ int err = 0;
+ u16 i;
+
+ if (vsi->type == ICE_VSI_VF)
+ goto setup_rings;
+
+ if (vsi->netdev && vsi->netdev->mtu > ETH_DATA_LEN)
+ vsi->max_frame = vsi->netdev->mtu +
+ ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;
+ else
+ vsi->max_frame = ICE_RXBUF_2048;
+
+ vsi->rx_buf_len = ICE_RXBUF_2048;
+setup_rings:
+ /* set up individual rings */
+ for (i = 0; i < vsi->num_rxq && !err; i++)
+ err = ice_setup_rx_ctx(vsi->rx_rings[i]);
+
+ if (err) {
+ dev_err(&vsi->back->pdev->dev, "ice_setup_rx_ctx failed\n");
+ return -EIO;
+ }
+ return err;
+}
+
+/**
+ * ice_vsi_cfg_txqs - Configure the VSI for Tx
+ * @vsi: the VSI being configured
+ *
+ * Return 0 on success and a negative value on error
+ * Configure the Tx VSI for operation.
+ */
+int ice_vsi_cfg_txqs(struct ice_vsi *vsi)
+{
+ struct ice_aqc_add_tx_qgrp *qg_buf;
+ struct ice_aqc_add_txqs_perq *txq;
+ struct ice_pf *pf = vsi->back;
+ enum ice_status status;
+ u16 buf_len, i, pf_q;
+ int err = 0, tc = 0;
+ u8 num_q_grps;
+
+ buf_len = sizeof(struct ice_aqc_add_tx_qgrp);
+ qg_buf = devm_kzalloc(&pf->pdev->dev, buf_len, GFP_KERNEL);
+ if (!qg_buf)
+ return -ENOMEM;
+
+ if (vsi->num_txq > ICE_MAX_TXQ_PER_TXQG) {
+ err = -EINVAL;
+ goto err_cfg_txqs;
+ }
+ qg_buf->num_txqs = 1;
+ num_q_grps = 1;
+
+ /* set up and configure the Tx queues */
+ ice_for_each_txq(vsi, i) {
+ struct ice_tlan_ctx tlan_ctx = { 0 };
+
+ pf_q = vsi->txq_map[i];
+ ice_setup_tx_ctx(vsi->tx_rings[i], &tlan_ctx, pf_q);
+ /* copy context contents into the qg_buf */
+ qg_buf->txqs[0].txq_id = cpu_to_le16(pf_q);
+ ice_set_ctx((u8 *)&tlan_ctx, qg_buf->txqs[0].txq_ctx,
+ ice_tlan_ctx_info);
+
+ /* init queue specific tail reg. It is referred as transmit
+ * comm scheduler queue doorbell.
+ */
+ vsi->tx_rings[i]->tail = pf->hw.hw_addr + QTX_COMM_DBELL(pf_q);
+ status = ice_ena_vsi_txq(vsi->port_info, vsi->idx, tc,
+ num_q_grps, qg_buf, buf_len, NULL);
+ if (status) {
+ dev_err(&vsi->back->pdev->dev,
+ "Failed to set LAN Tx queue context, error: %d\n",
+ status);
+ err = -ENODEV;
+ goto err_cfg_txqs;
+ }
+
+ /* Add Tx Queue TEID into the VSI Tx ring from the response
+ * This will complete configuring and enabling the queue.
+ */
+ txq = &qg_buf->txqs[0];
+ if (pf_q == le16_to_cpu(txq->txq_id))
+ vsi->tx_rings[i]->txq_teid =
+ le32_to_cpu(txq->q_teid);
+ }
+err_cfg_txqs:
+ devm_kfree(&pf->pdev->dev, qg_buf);
+ return err;
+}
+
+/**
+ * ice_intrl_usec_to_reg - convert interrupt rate limit to register value
+ * @intrl: interrupt rate limit in usecs
+ * @gran: interrupt rate limit granularity in usecs
+ *
+ * This function converts a decimal interrupt rate limit in usecs to the format
+ * expected by firmware.
+ */
+static u32 ice_intrl_usec_to_reg(u8 intrl, u8 gran)
+{
+ u32 val = intrl / gran;
+
+ if (val)
+ return val | GLINT_RATE_INTRL_ENA_M;
+ return 0;
+}
+
+/**
+ * ice_cfg_itr - configure the initial interrupt throttle values
+ * @hw: pointer to the HW structure
+ * @q_vector: interrupt vector that's being configured
+ * @vector: HW vector index to apply the interrupt throttling to
+ *
+ * Configure interrupt throttling values for the ring containers that are
+ * associated with the interrupt vector passed in.
+ */
+static void
+ice_cfg_itr(struct ice_hw *hw, struct ice_q_vector *q_vector, u16 vector)
+{
+ u8 itr_gran = hw->itr_gran;
+
+ if (q_vector->num_ring_rx) {
+ struct ice_ring_container *rc = &q_vector->rx;
+
+ rc->itr = ITR_TO_REG(ICE_DFLT_RX_ITR, itr_gran);
+ rc->latency_range = ICE_LOW_LATENCY;
+ wr32(hw, GLINT_ITR(rc->itr_idx, vector), rc->itr);
+ }
+
+ if (q_vector->num_ring_tx) {
+ struct ice_ring_container *rc = &q_vector->tx;
+
+ rc->itr = ITR_TO_REG(ICE_DFLT_TX_ITR, itr_gran);
+ rc->latency_range = ICE_LOW_LATENCY;
+ wr32(hw, GLINT_ITR(rc->itr_idx, vector), rc->itr);
+ }
+}
+
+/**
+ * ice_vsi_cfg_msix - MSIX mode Interrupt Config in the HW
+ * @vsi: the VSI being configured
+ */
+void ice_vsi_cfg_msix(struct ice_vsi *vsi)
+{
+ struct ice_pf *pf = vsi->back;
+ u16 vector = vsi->hw_base_vector;
+ struct ice_hw *hw = &pf->hw;
+ u32 txq = 0, rxq = 0;
+ int i, q;
+
+ for (i = 0; i < vsi->num_q_vectors; i++, vector++) {
+ struct ice_q_vector *q_vector = vsi->q_vectors[i];
+
+ ice_cfg_itr(hw, q_vector, vector);
+
+ wr32(hw, GLINT_RATE(vector),
+ ice_intrl_usec_to_reg(q_vector->intrl, hw->intrl_gran));
+
+ /* Both Transmit Queue Interrupt Cause Control register
+ * and Receive Queue Interrupt Cause control register
+ * expects MSIX_INDX field to be the vector index
+ * within the function space and not the absolute
+ * vector index across PF or across device.
+ * For SR-IOV VF VSIs queue vector index always starts
+ * with 1 since first vector index(0) is used for OICR
+ * in VF space. Since VMDq and other PF VSIs are within
+ * the PF function space, use the vector index that is
+ * tracked for this PF.
+ */
+ for (q = 0; q < q_vector->num_ring_tx; q++) {
+ int itr_idx = q_vector->tx.itr_idx;
+ u32 val;
+
+ if (vsi->type == ICE_VSI_VF)
+ val = QINT_TQCTL_CAUSE_ENA_M |
+ (itr_idx << QINT_TQCTL_ITR_INDX_S) |
+ ((i + 1) << QINT_TQCTL_MSIX_INDX_S);
+ else
+ val = QINT_TQCTL_CAUSE_ENA_M |
+ (itr_idx << QINT_TQCTL_ITR_INDX_S) |
+ (vector << QINT_TQCTL_MSIX_INDX_S);
+ wr32(hw, QINT_TQCTL(vsi->txq_map[txq]), val);
+ txq++;
+ }
+
+ for (q = 0; q < q_vector->num_ring_rx; q++) {
+ int itr_idx = q_vector->rx.itr_idx;
+ u32 val;
+
+ if (vsi->type == ICE_VSI_VF)
+ val = QINT_RQCTL_CAUSE_ENA_M |
+ (itr_idx << QINT_RQCTL_ITR_INDX_S) |
+ ((i + 1) << QINT_RQCTL_MSIX_INDX_S);
+ else
+ val = QINT_RQCTL_CAUSE_ENA_M |
+ (itr_idx << QINT_RQCTL_ITR_INDX_S) |
+ (vector << QINT_RQCTL_MSIX_INDX_S);
+ wr32(hw, QINT_RQCTL(vsi->rxq_map[rxq]), val);
+ rxq++;
+ }
+ }
+
+ ice_flush(hw);
+}
+
+/**
+ * ice_vsi_manage_vlan_insertion - Manage VLAN insertion for the VSI for Tx
+ * @vsi: the VSI being changed
+ */
+int ice_vsi_manage_vlan_insertion(struct ice_vsi *vsi)
+{
+ struct device *dev = &vsi->back->pdev->dev;
+ struct ice_hw *hw = &vsi->back->hw;
+ struct ice_vsi_ctx ctxt = { 0 };
+ enum ice_status status;
+
+ /* Here we are configuring the VSI to let the driver add VLAN tags by
+ * setting vlan_flags to ICE_AQ_VSI_VLAN_MODE_ALL. The actual VLAN tag
+ * insertion happens in the Tx hot path, in ice_tx_map.
+ */
+ ctxt.info.vlan_flags = ICE_AQ_VSI_VLAN_MODE_ALL;
+
+ ctxt.info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID);
+
+ status = ice_update_vsi(hw, vsi->idx, &ctxt, NULL);
+ if (status) {
+ dev_err(dev, "update VSI for VLAN insert failed, err %d aq_err %d\n",
+ status, hw->adminq.sq_last_status);
+ return -EIO;
+ }
+
+ vsi->info.vlan_flags = ctxt.info.vlan_flags;
+ return 0;
+}
+
+/**
+ * ice_vsi_manage_vlan_stripping - Manage VLAN stripping for the VSI for Rx
+ * @vsi: the VSI being changed
+ * @ena: boolean value indicating if this is a enable or disable request
+ */
+int ice_vsi_manage_vlan_stripping(struct ice_vsi *vsi, bool ena)
+{
+ struct device *dev = &vsi->back->pdev->dev;
+ struct ice_hw *hw = &vsi->back->hw;
+ struct ice_vsi_ctx ctxt = { 0 };
+ enum ice_status status;
+
+ /* Here we are configuring what the VSI should do with the VLAN tag in
+ * the Rx packet. We can either leave the tag in the packet or put it in
+ * the Rx descriptor.
+ */
+ if (ena) {
+ /* Strip VLAN tag from Rx packet and put it in the desc */
+ ctxt.info.vlan_flags = ICE_AQ_VSI_VLAN_EMOD_STR_BOTH;
+ } else {
+ /* Disable stripping. Leave tag in packet */
+ ctxt.info.vlan_flags = ICE_AQ_VSI_VLAN_EMOD_NOTHING;
+ }
+
+ /* Allow all packets untagged/tagged */
+ ctxt.info.vlan_flags |= ICE_AQ_VSI_VLAN_MODE_ALL;
+
+ ctxt.info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID);
+
+ status = ice_update_vsi(hw, vsi->idx, &ctxt, NULL);
+ if (status) {
+ dev_err(dev, "update VSI for VLAN strip failed, ena = %d err %d aq_err %d\n",
+ ena, status, hw->adminq.sq_last_status);
+ return -EIO;
+ }
+
+ vsi->info.vlan_flags = ctxt.info.vlan_flags;
+ return 0;
+}
+
+/**
+ * ice_vsi_start_rx_rings - start VSI's Rx rings
+ * @vsi: the VSI whose rings are to be started
+ *
+ * Returns 0 on success and a negative value on error
+ */
+int ice_vsi_start_rx_rings(struct ice_vsi *vsi)
+{
+ return ice_vsi_ctrl_rx_rings(vsi, true);
+}
+
+/**
+ * ice_vsi_stop_rx_rings - stop VSI's Rx rings
+ * @vsi: the VSI
+ *
+ * Returns 0 on success and a negative value on error
+ */
+int ice_vsi_stop_rx_rings(struct ice_vsi *vsi)
+{
+ return ice_vsi_ctrl_rx_rings(vsi, false);
+}
+
+/**
+ * ice_vsi_stop_tx_rings - Disable Tx rings
+ * @vsi: the VSI being configured
+ * @rst_src: reset source
+ * @rel_vmvf_num: Relative id of VF/VM
+ */
+int ice_vsi_stop_tx_rings(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src,
+ u16 rel_vmvf_num)
+{
+ struct ice_pf *pf = vsi->back;
+ struct ice_hw *hw = &pf->hw;
+ enum ice_status status;
+ u32 *q_teids, val;
+ u16 *q_ids, i;
+ int err = 0;
+
+ if (vsi->num_txq > ICE_LAN_TXQ_MAX_QDIS)
+ return -EINVAL;
+
+ q_teids = devm_kcalloc(&pf->pdev->dev, vsi->num_txq, sizeof(*q_teids),
+ GFP_KERNEL);
+ if (!q_teids)
+ return -ENOMEM;
+
+ q_ids = devm_kcalloc(&pf->pdev->dev, vsi->num_txq, sizeof(*q_ids),
+ GFP_KERNEL);
+ if (!q_ids) {
+ err = -ENOMEM;
+ goto err_alloc_q_ids;
+ }
+
+ /* set up the Tx queue list to be disabled */
+ ice_for_each_txq(vsi, i) {
+ u16 v_idx;
+
+ if (!vsi->tx_rings || !vsi->tx_rings[i]) {
+ err = -EINVAL;
+ goto err_out;
+ }
+
+ q_ids[i] = vsi->txq_map[i];
+ q_teids[i] = vsi->tx_rings[i]->txq_teid;
+
+ /* clear cause_ena bit for disabled queues */
+ val = rd32(hw, QINT_TQCTL(vsi->tx_rings[i]->reg_idx));
+ val &= ~QINT_TQCTL_CAUSE_ENA_M;
+ wr32(hw, QINT_TQCTL(vsi->tx_rings[i]->reg_idx), val);
+
+ /* software is expected to wait for 100 ns */
+ ndelay(100);
+
+ /* trigger a software interrupt for the vector associated to
+ * the queue to schedule NAPI handler
+ */
+ v_idx = vsi->tx_rings[i]->q_vector->v_idx;
+ wr32(hw, GLINT_DYN_CTL(vsi->hw_base_vector + v_idx),
+ GLINT_DYN_CTL_SWINT_TRIG_M | GLINT_DYN_CTL_INTENA_MSK_M);
+ }
+ status = ice_dis_vsi_txq(vsi->port_info, vsi->num_txq, q_ids, q_teids,
+ rst_src, rel_vmvf_num, NULL);
+ /* if the disable queue command was exercised during an active reset
+ * flow, ICE_ERR_RESET_ONGOING is returned. This is not an error as
+ * the reset operation disables queues at the hardware level anyway.
+ */
+ if (status == ICE_ERR_RESET_ONGOING) {
+ dev_info(&pf->pdev->dev,
+ "Reset in progress. LAN Tx queues already disabled\n");
+ } else if (status) {
+ dev_err(&pf->pdev->dev,
+ "Failed to disable LAN Tx queues, error: %d\n",
+ status);
+ err = -ENODEV;
+ }
+
+err_out:
+ devm_kfree(&pf->pdev->dev, q_ids);
+
+err_alloc_q_ids:
+ devm_kfree(&pf->pdev->dev, q_teids);
+
+ return err;
+}
+
+/**
+ * ice_cfg_vlan_pruning - enable or disable VLAN pruning on the VSI
+ * @vsi: VSI to enable or disable VLAN pruning on
+ * @ena: set to true to enable VLAN pruning and false to disable it
+ *
+ * returns 0 if VSI is updated, negative otherwise
+ */
+int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena)
+{
+ struct ice_vsi_ctx *ctxt;
+ struct device *dev;
+ int status;
+
+ if (!vsi)
+ return -EINVAL;
+
+ dev = &vsi->back->pdev->dev;
+ ctxt = devm_kzalloc(dev, sizeof(*ctxt), GFP_KERNEL);
+ if (!ctxt)
+ return -ENOMEM;
+
+ ctxt->info = vsi->info;
+
+ if (ena) {
+ ctxt->info.sec_flags |=
+ ICE_AQ_VSI_SEC_TX_VLAN_PRUNE_ENA <<
+ ICE_AQ_VSI_SEC_TX_PRUNE_ENA_S;
+ ctxt->info.sw_flags2 |= ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA;
+ } else {
+ ctxt->info.sec_flags &=
+ ~(ICE_AQ_VSI_SEC_TX_VLAN_PRUNE_ENA <<
+ ICE_AQ_VSI_SEC_TX_PRUNE_ENA_S);
+ ctxt->info.sw_flags2 &= ~ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA;
+ }
+
+ ctxt->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_SECURITY_VALID |
+ ICE_AQ_VSI_PROP_SW_VALID);
+
+ status = ice_update_vsi(&vsi->back->hw, vsi->idx, ctxt, NULL);
+ if (status) {
+ netdev_err(vsi->netdev, "%sabling VLAN pruning on VSI handle: %d, VSI HW ID: %d failed, err = %d, aq_err = %d\n",
+ ena ? "En" : "Dis", vsi->idx, vsi->vsi_num, status,
+ vsi->back->hw.adminq.sq_last_status);
+ goto err_out;
+ }
+
+ vsi->info.sec_flags = ctxt->info.sec_flags;
+ vsi->info.sw_flags2 = ctxt->info.sw_flags2;
+
+ devm_kfree(dev, ctxt);
+ return 0;
+
+err_out:
+ devm_kfree(dev, ctxt);
+ return -EIO;
+}
+
+/**
+ * ice_vsi_setup - Set up a VSI by a given type
+ * @pf: board private structure
+ * @pi: pointer to the port_info instance
+ * @type: VSI type
+ * @vf_id: defines VF id to which this VSI connects. This field is meant to be
+ * used only for ICE_VSI_VF VSI type. For other VSI types, should
+ * fill-in ICE_INVAL_VFID as input.
+ *
+ * This allocates the sw VSI structure and its queue resources.
+ *
+ * Returns pointer to the successfully allocated and configured VSI sw struct on
+ * success, NULL on failure.
+ */
+struct ice_vsi *
+ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi,
+ enum ice_vsi_type type, u16 vf_id)
+{
+ u16 max_txqs[ICE_MAX_TRAFFIC_CLASS] = { 0 };
+ struct device *dev = &pf->pdev->dev;
+ struct ice_vsi *vsi;
+ int ret, i;
+
+ vsi = ice_vsi_alloc(pf, type);
+ if (!vsi) {
+ dev_err(dev, "could not allocate VSI\n");
+ return NULL;
+ }
+
+ vsi->port_info = pi;
+ vsi->vsw = pf->first_sw;
+ if (vsi->type == ICE_VSI_VF)
+ vsi->vf_id = vf_id;
+
+ if (ice_vsi_get_qs(vsi)) {
+ dev_err(dev, "Failed to allocate queues. vsi->idx = %d\n",
+ vsi->idx);
+ goto unroll_get_qs;
+ }
+
+ /* set RSS capabilities */
+ ice_vsi_set_rss_params(vsi);
+
+ /* create the VSI */
+ ret = ice_vsi_init(vsi);
+ if (ret)
+ goto unroll_get_qs;
+
+ switch (vsi->type) {
+ case ICE_VSI_PF:
+ ret = ice_vsi_alloc_q_vectors(vsi);
+ if (ret)
+ goto unroll_vsi_init;
+
+ ret = ice_vsi_setup_vector_base(vsi);
+ if (ret)
+ goto unroll_alloc_q_vector;
+
+ ret = ice_vsi_alloc_rings(vsi);
+ if (ret)
+ goto unroll_vector_base;
+
+ ice_vsi_map_rings_to_vectors(vsi);
+
+ /* Do not exit if configuring RSS had an issue, at least
+ * receive traffic on first queue. Hence no need to capture
+ * return value
+ */
+ if (test_bit(ICE_FLAG_RSS_ENA, pf->flags))
+ ice_vsi_cfg_rss_lut_key(vsi);
+ break;
+ case ICE_VSI_VF:
+ /* VF driver will take care of creating netdev for this type and
+ * map queues to vectors through Virtchnl, PF driver only
+ * creates a VSI and corresponding structures for bookkeeping
+ * purpose
+ */
+ ret = ice_vsi_alloc_q_vectors(vsi);
+ if (ret)
+ goto unroll_vsi_init;
+
+ ret = ice_vsi_alloc_rings(vsi);
+ if (ret)
+ goto unroll_alloc_q_vector;
+
+ /* Setup Vector base only during VF init phase or when VF asks
+ * for more vectors than assigned number. In all other cases,
+ * assign hw_base_vector to the value given earlier.
+ */
+ if (test_bit(ICE_VF_STATE_CFG_INTR, pf->vf[vf_id].vf_states)) {
+ ret = ice_vsi_setup_vector_base(vsi);
+ if (ret)
+ goto unroll_vector_base;
+ } else {
+ vsi->hw_base_vector = pf->vf[vf_id].first_vector_idx;
+ }
+ pf->q_left_tx -= vsi->alloc_txq;
+ pf->q_left_rx -= vsi->alloc_rxq;
+ break;
+ default:
+ /* if VSI type is not recognized, clean up the resources and
+ * exit
+ */
+ goto unroll_vsi_init;
+ }
+
+ ice_vsi_set_tc_cfg(vsi);
+
+ /* configure VSI nodes based on number of queues and TC's */
+ for (i = 0; i < vsi->tc_cfg.numtc; i++)
+ max_txqs[i] = vsi->num_txq;
+
+ ret = ice_cfg_vsi_lan(vsi->port_info, vsi->idx, vsi->tc_cfg.ena_tc,
+ max_txqs);
+ if (ret) {
+ dev_info(&pf->pdev->dev, "Failed VSI lan queue config\n");
+ goto unroll_vector_base;
+ }
+
+ return vsi;
+
+unroll_vector_base:
+ /* reclaim SW interrupts back to the common pool */
+ ice_free_res(vsi->back->sw_irq_tracker, vsi->sw_base_vector, vsi->idx);
+ pf->num_avail_sw_msix += vsi->num_q_vectors;
+ /* reclaim HW interrupt back to the common pool */
+ ice_free_res(vsi->back->hw_irq_tracker, vsi->hw_base_vector, vsi->idx);
+ pf->num_avail_hw_msix += vsi->num_q_vectors;
+unroll_alloc_q_vector:
+ ice_vsi_free_q_vectors(vsi);
+unroll_vsi_init:
+ ice_vsi_delete(vsi);
+unroll_get_qs:
+ ice_vsi_put_qs(vsi);
+ pf->q_left_tx += vsi->alloc_txq;
+ pf->q_left_rx += vsi->alloc_rxq;
+ ice_vsi_clear(vsi);
+
+ return NULL;
+}
+
+/**
+ * ice_vsi_release_msix - Clear the queue to Interrupt mapping in HW
+ * @vsi: the VSI being cleaned up
+ */
+static void ice_vsi_release_msix(struct ice_vsi *vsi)
+{
+ struct ice_pf *pf = vsi->back;
+ u16 vector = vsi->hw_base_vector;
+ struct ice_hw *hw = &pf->hw;
+ u32 txq = 0;
+ u32 rxq = 0;
+ int i, q;
+
+ for (i = 0; i < vsi->num_q_vectors; i++, vector++) {
+ struct ice_q_vector *q_vector = vsi->q_vectors[i];
+
+ wr32(hw, GLINT_ITR(ICE_IDX_ITR0, vector), 0);
+ wr32(hw, GLINT_ITR(ICE_IDX_ITR1, vector), 0);
+ for (q = 0; q < q_vector->num_ring_tx; q++) {
+ wr32(hw, QINT_TQCTL(vsi->txq_map[txq]), 0);
+ txq++;
+ }
+
+ for (q = 0; q < q_vector->num_ring_rx; q++) {
+ wr32(hw, QINT_RQCTL(vsi->rxq_map[rxq]), 0);
+ rxq++;
+ }
+ }
+
+ ice_flush(hw);
+}
+
+/**
+ * ice_vsi_free_irq - Free the IRQ association with the OS
+ * @vsi: the VSI being configured
+ */
+void ice_vsi_free_irq(struct ice_vsi *vsi)
+{
+ struct ice_pf *pf = vsi->back;
+ int base = vsi->sw_base_vector;
+
+ if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) {
+ int i;
+
+ if (!vsi->q_vectors || !vsi->irqs_ready)
+ return;
+
+ ice_vsi_release_msix(vsi);
+ if (vsi->type == ICE_VSI_VF)
+ return;
+
+ vsi->irqs_ready = false;
+ for (i = 0; i < vsi->num_q_vectors; i++) {
+ u16 vector = i + base;
+ int irq_num;
+
+ irq_num = pf->msix_entries[vector].vector;
+
+ /* free only the irqs that were actually requested */
+ if (!vsi->q_vectors[i] ||
+ !(vsi->q_vectors[i]->num_ring_tx ||
+ vsi->q_vectors[i]->num_ring_rx))
+ continue;
+
+ /* clear the affinity notifier in the IRQ descriptor */
+ irq_set_affinity_notifier(irq_num, NULL);
+
+ /* clear the affinity_mask in the IRQ descriptor */
+ irq_set_affinity_hint(irq_num, NULL);
+ synchronize_irq(irq_num);
+ devm_free_irq(&pf->pdev->dev, irq_num,
+ vsi->q_vectors[i]);
+ }
+ }
+}
+
+/**
+ * ice_vsi_free_tx_rings - Free Tx resources for VSI queues
+ * @vsi: the VSI having resources freed
+ */
+void ice_vsi_free_tx_rings(struct ice_vsi *vsi)
+{
+ int i;
+
+ if (!vsi->tx_rings)
+ return;
+
+ ice_for_each_txq(vsi, i)
+ if (vsi->tx_rings[i] && vsi->tx_rings[i]->desc)
+ ice_free_tx_ring(vsi->tx_rings[i]);
+}
+
+/**
+ * ice_vsi_free_rx_rings - Free Rx resources for VSI queues
+ * @vsi: the VSI having resources freed
+ */
+void ice_vsi_free_rx_rings(struct ice_vsi *vsi)
+{
+ int i;
+
+ if (!vsi->rx_rings)
+ return;
+
+ ice_for_each_rxq(vsi, i)
+ if (vsi->rx_rings[i] && vsi->rx_rings[i]->desc)
+ ice_free_rx_ring(vsi->rx_rings[i]);
+}
+
+/**
+ * ice_vsi_close - Shut down a VSI
+ * @vsi: the VSI being shut down
+ */
+void ice_vsi_close(struct ice_vsi *vsi)
+{
+ if (!test_and_set_bit(__ICE_DOWN, vsi->state))
+ ice_down(vsi);
+
+ ice_vsi_free_irq(vsi);
+ ice_vsi_free_tx_rings(vsi);
+ ice_vsi_free_rx_rings(vsi);
+}
+
+/**
+ * ice_free_res - free a block of resources
+ * @res: pointer to the resource
+ * @index: starting index previously returned by ice_get_res
+ * @id: identifier to track owner
+ *
+ * Returns number of resources freed
+ */
+int ice_free_res(struct ice_res_tracker *res, u16 index, u16 id)
+{
+ int count = 0;
+ int i;
+
+ if (!res || index >= res->num_entries)
+ return -EINVAL;
+
+ id |= ICE_RES_VALID_BIT;
+ for (i = index; i < res->num_entries && res->list[i] == id; i++) {
+ res->list[i] = 0;
+ count++;
+ }
+
+ return count;
+}
+
+/**
+ * ice_search_res - Search the tracker for a block of resources
+ * @res: pointer to the resource
+ * @needed: size of the block needed
+ * @id: identifier to track owner
+ *
+ * Returns the base item index of the block, or -ENOMEM for error
+ */
+static int ice_search_res(struct ice_res_tracker *res, u16 needed, u16 id)
+{
+ int start = res->search_hint;
+ int end = start;
+
+ if ((start + needed) > res->num_entries)
+ return -ENOMEM;
+
+ id |= ICE_RES_VALID_BIT;
+
+ do {
+ /* skip already allocated entries */
+ if (res->list[end++] & ICE_RES_VALID_BIT) {
+ start = end;
+ if ((start + needed) > res->num_entries)
+ break;
+ }
+
+ if (end == (start + needed)) {
+ int i = start;
+
+ /* there was enough, so assign it to the requestor */
+ while (i != end)
+ res->list[i++] = id;
+
+ if (end == res->num_entries)
+ end = 0;
+
+ res->search_hint = end;
+ return start;
+ }
+ } while (1);
+
+ return -ENOMEM;
+}
+
+/**
+ * ice_get_res - get a block of resources
+ * @pf: board private structure
+ * @res: pointer to the resource
+ * @needed: size of the block needed
+ * @id: identifier to track owner
+ *
+ * Returns the base item index of the block, or -ENOMEM for error
+ * The search_hint trick and lack of advanced fit-finding only works
+ * because we're highly likely to have all the same sized requests.
+ * Linear search time and any fragmentation should be minimal.
+ */
+int
+ice_get_res(struct ice_pf *pf, struct ice_res_tracker *res, u16 needed, u16 id)
+{
+ int ret;
+
+ if (!res || !pf)
+ return -EINVAL;
+
+ if (!needed || needed > res->num_entries || id >= ICE_RES_VALID_BIT) {
+ dev_err(&pf->pdev->dev,
+ "param err: needed=%d, num_entries = %d id=0x%04x\n",
+ needed, res->num_entries, id);
+ return -EINVAL;
+ }
+
+ /* search based on search_hint */
+ ret = ice_search_res(res, needed, id);
+
+ if (ret < 0) {
+ /* previous search failed. Reset search hint and try again */
+ res->search_hint = 0;
+ ret = ice_search_res(res, needed, id);
+ }
+
+ return ret;
+}
+
+/**
+ * ice_vsi_dis_irq - Mask off queue interrupt generation on the VSI
+ * @vsi: the VSI being un-configured
+ */
+void ice_vsi_dis_irq(struct ice_vsi *vsi)
+{
+ int base = vsi->sw_base_vector;
+ struct ice_pf *pf = vsi->back;
+ struct ice_hw *hw = &pf->hw;
+ u32 val;
+ int i;
+
+ /* disable interrupt causation from each queue */
+ if (vsi->tx_rings) {
+ ice_for_each_txq(vsi, i) {
+ if (vsi->tx_rings[i]) {
+ u16 reg;
+
+ reg = vsi->tx_rings[i]->reg_idx;
+ val = rd32(hw, QINT_TQCTL(reg));
+ val &= ~QINT_TQCTL_CAUSE_ENA_M;
+ wr32(hw, QINT_TQCTL(reg), val);
+ }
+ }
+ }
+
+ if (vsi->rx_rings) {
+ ice_for_each_rxq(vsi, i) {
+ if (vsi->rx_rings[i]) {
+ u16 reg;
+
+ reg = vsi->rx_rings[i]->reg_idx;
+ val = rd32(hw, QINT_RQCTL(reg));
+ val &= ~QINT_RQCTL_CAUSE_ENA_M;
+ wr32(hw, QINT_RQCTL(reg), val);
+ }
+ }
+ }
+
+ /* disable each interrupt */
+ if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) {
+ for (i = vsi->hw_base_vector;
+ i < (vsi->num_q_vectors + vsi->hw_base_vector); i++)
+ wr32(hw, GLINT_DYN_CTL(i), 0);
+
+ ice_flush(hw);
+ for (i = 0; i < vsi->num_q_vectors; i++)
+ synchronize_irq(pf->msix_entries[i + base].vector);
+ }
+}
+
+/**
+ * ice_vsi_release - Delete a VSI and free its resources
+ * @vsi: the VSI being removed
+ *
+ * Returns 0 on success or < 0 on error
+ */
+int ice_vsi_release(struct ice_vsi *vsi)
+{
+ struct ice_pf *pf;
+ struct ice_vf *vf;
+
+ if (!vsi->back)
+ return -ENODEV;
+ pf = vsi->back;
+ vf = &pf->vf[vsi->vf_id];
+ /* do not unregister and free netdevs while driver is in the reset
+ * recovery pending state. Since reset/rebuild happens through PF
+ * service task workqueue, its not a good idea to unregister netdev
+ * that is associated to the PF that is running the work queue items
+ * currently. This is done to avoid check_flush_dependency() warning
+ * on this wq
+ */
+ if (vsi->netdev && !ice_is_reset_in_progress(pf->state)) {
+ ice_napi_del(vsi);
+ unregister_netdev(vsi->netdev);
+ free_netdev(vsi->netdev);
+ vsi->netdev = NULL;
+ }
+
+ if (test_bit(ICE_FLAG_RSS_ENA, pf->flags))
+ ice_rss_clean(vsi);
+
+ /* Disable VSI and free resources */
+ ice_vsi_dis_irq(vsi);
+ ice_vsi_close(vsi);
+
+ /* reclaim interrupt vectors back to PF */
+ if (vsi->type != ICE_VSI_VF) {
+ /* reclaim SW interrupts back to the common pool */
+ ice_free_res(vsi->back->sw_irq_tracker, vsi->sw_base_vector,
+ vsi->idx);
+ pf->num_avail_sw_msix += vsi->num_q_vectors;
+ /* reclaim HW interrupts back to the common pool */
+ ice_free_res(vsi->back->hw_irq_tracker, vsi->hw_base_vector,
+ vsi->idx);
+ pf->num_avail_hw_msix += vsi->num_q_vectors;
+ } else if (test_bit(ICE_VF_STATE_CFG_INTR, vf->vf_states)) {
+ /* Reclaim VF resources back only while freeing all VFs or
+ * vector reassignment is requested
+ */
+ ice_free_res(vsi->back->hw_irq_tracker, vf->first_vector_idx,
+ vsi->idx);
+ pf->num_avail_hw_msix += pf->num_vf_msix;
+ }
+
+ ice_remove_vsi_fltr(&pf->hw, vsi->idx);
+ ice_vsi_delete(vsi);
+ ice_vsi_free_q_vectors(vsi);
+ ice_vsi_clear_rings(vsi);
+
+ ice_vsi_put_qs(vsi);
+ pf->q_left_tx += vsi->alloc_txq;
+ pf->q_left_rx += vsi->alloc_rxq;
+
+ /* retain SW VSI data structure since it is needed to unregister and
+ * free VSI netdev when PF is not in reset recovery pending state,\
+ * for ex: during rmmod.
+ */
+ if (!ice_is_reset_in_progress(pf->state))
+ ice_vsi_clear(vsi);
+
+ return 0;
+}
+
+/**
+ * ice_vsi_rebuild - Rebuild VSI after reset
+ * @vsi: VSI to be rebuild
+ *
+ * Returns 0 on success and negative value on failure
+ */
+int ice_vsi_rebuild(struct ice_vsi *vsi)
+{
+ u16 max_txqs[ICE_MAX_TRAFFIC_CLASS] = { 0 };
+ int ret, i;
+
+ if (!vsi)
+ return -EINVAL;
+
+ ice_vsi_free_q_vectors(vsi);
+ ice_free_res(vsi->back->sw_irq_tracker, vsi->sw_base_vector, vsi->idx);
+ ice_free_res(vsi->back->hw_irq_tracker, vsi->hw_base_vector, vsi->idx);
+ vsi->sw_base_vector = 0;
+ vsi->hw_base_vector = 0;
+ ice_vsi_clear_rings(vsi);
+ ice_vsi_free_arrays(vsi, false);
+ ice_dev_onetime_setup(&vsi->back->hw);
+ ice_vsi_set_num_qs(vsi);
+
+ /* Initialize VSI struct elements and create VSI in FW */
+ ret = ice_vsi_init(vsi);
+ if (ret < 0)
+ goto err_vsi;
+
+ ret = ice_vsi_alloc_arrays(vsi, false);
+ if (ret < 0)
+ goto err_vsi;
+
+ switch (vsi->type) {
+ case ICE_VSI_PF:
+ ret = ice_vsi_alloc_q_vectors(vsi);
+ if (ret)
+ goto err_rings;
+
+ ret = ice_vsi_setup_vector_base(vsi);
+ if (ret)
+ goto err_vectors;
+
+ ret = ice_vsi_alloc_rings(vsi);
+ if (ret)
+ goto err_vectors;
+
+ ice_vsi_map_rings_to_vectors(vsi);
+ break;
+ case ICE_VSI_VF:
+ ret = ice_vsi_alloc_q_vectors(vsi);
+ if (ret)
+ goto err_rings;
+
+ ret = ice_vsi_setup_vector_base(vsi);
+ if (ret)
+ goto err_vectors;
+
+ ret = ice_vsi_alloc_rings(vsi);
+ if (ret)
+ goto err_vectors;
+
+ vsi->back->q_left_tx -= vsi->alloc_txq;
+ vsi->back->q_left_rx -= vsi->alloc_rxq;
+ break;
+ default:
+ break;
+ }
+
+ ice_vsi_set_tc_cfg(vsi);
+
+ /* configure VSI nodes based on number of queues and TC's */
+ for (i = 0; i < vsi->tc_cfg.numtc; i++)
+ max_txqs[i] = vsi->num_txq;
+
+ ret = ice_cfg_vsi_lan(vsi->port_info, vsi->idx, vsi->tc_cfg.ena_tc,
+ max_txqs);
+ if (ret) {
+ dev_info(&vsi->back->pdev->dev,
+ "Failed VSI lan queue config\n");
+ goto err_vectors;
+ }
+ return 0;
+
+err_vectors:
+ ice_vsi_free_q_vectors(vsi);
+err_rings:
+ if (vsi->netdev) {
+ vsi->current_netdev_flags = 0;
+ unregister_netdev(vsi->netdev);
+ free_netdev(vsi->netdev);
+ vsi->netdev = NULL;
+ }
+err_vsi:
+ ice_vsi_clear(vsi);
+ set_bit(__ICE_RESET_FAILED, vsi->back->state);
+ return ret;
+}
+
+/**
+ * ice_is_reset_in_progress - check for a reset in progress
+ * @state: pf state field
+ */
+bool ice_is_reset_in_progress(unsigned long *state)
+{
+ return test_bit(__ICE_RESET_OICR_RECV, state) ||
+ test_bit(__ICE_PFR_REQ, state) ||
+ test_bit(__ICE_CORER_REQ, state) ||
+ test_bit(__ICE_GLOBR_REQ, state);
+}
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h
new file mode 100644
index 000000000000..3831b4f0960a
--- /dev/null
+++ b/drivers/net/ethernet/intel/ice/ice_lib.h
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2018, Intel Corporation. */
+
+#ifndef _ICE_LIB_H_
+#define _ICE_LIB_H_
+
+#include "ice.h"
+
+int ice_add_mac_to_list(struct ice_vsi *vsi, struct list_head *add_list,
+ const u8 *macaddr);
+
+void ice_free_fltr_list(struct device *dev, struct list_head *h);
+
+void ice_update_eth_stats(struct ice_vsi *vsi);
+
+int ice_vsi_cfg_rxqs(struct ice_vsi *vsi);
+
+int ice_vsi_cfg_txqs(struct ice_vsi *vsi);
+
+void ice_vsi_cfg_msix(struct ice_vsi *vsi);
+
+int ice_vsi_add_vlan(struct ice_vsi *vsi, u16 vid);
+
+int ice_vsi_kill_vlan(struct ice_vsi *vsi, u16 vid);
+
+int ice_vsi_manage_vlan_insertion(struct ice_vsi *vsi);
+
+int ice_vsi_manage_vlan_stripping(struct ice_vsi *vsi, bool ena);
+
+int ice_vsi_start_rx_rings(struct ice_vsi *vsi);
+
+int ice_vsi_stop_rx_rings(struct ice_vsi *vsi);
+
+int ice_vsi_stop_tx_rings(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src,
+ u16 rel_vmvf_num);
+
+int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena);
+
+void ice_vsi_delete(struct ice_vsi *vsi);
+
+int ice_vsi_clear(struct ice_vsi *vsi);
+
+struct ice_vsi *
+ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi,
+ enum ice_vsi_type type, u16 vf_id);
+
+int ice_vsi_release(struct ice_vsi *vsi);
+
+void ice_vsi_close(struct ice_vsi *vsi);
+
+int ice_free_res(struct ice_res_tracker *res, u16 index, u16 id);
+
+int
+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 ice_is_reset_in_progress(unsigned long *state);
+
+void ice_vsi_free_q_vectors(struct ice_vsi *vsi);
+
+void ice_vsi_put_qs(struct ice_vsi *vsi);
+
+void ice_vsi_dis_irq(struct ice_vsi *vsi);
+
+void ice_vsi_free_irq(struct ice_vsi *vsi);
+
+void ice_vsi_free_rx_rings(struct ice_vsi *vsi);
+
+void ice_vsi_free_tx_rings(struct ice_vsi *vsi);
+
+int ice_vsi_cfg_tc(struct ice_vsi *vsi, u8 ena_tc);
+
+int ice_vsi_manage_rss_lut(struct ice_vsi *vsi, bool ena);
+
+#endif /* !_ICE_LIB_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index 3f047bb43348..333312a1d595 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -6,8 +6,9 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include "ice.h"
+#include "ice_lib.h"
-#define DRV_VERSION "ice-0.7.0-k"
+#define DRV_VERSION "0.7.2-k"
#define DRV_SUMMARY "Intel(R) Ethernet Connection E800 Series Linux Driver"
const char ice_drv_ver[] = DRV_VERSION;
static const char ice_driver_string[] = DRV_SUMMARY;
@@ -15,7 +16,7 @@ static const char ice_copyright[] = "Copyright (c) 2018, Intel Corporation.";
MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
MODULE_DESCRIPTION(DRV_SUMMARY);
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_VERSION(DRV_VERSION);
static int debug = -1;
@@ -31,173 +32,84 @@ static const struct net_device_ops ice_netdev_ops;
static void ice_pf_dis_all_vsi(struct ice_pf *pf);
static void ice_rebuild(struct ice_pf *pf);
-static int ice_vsi_release(struct ice_vsi *vsi);
+
+static void ice_vsi_release_all(struct ice_pf *pf);
static void ice_update_vsi_stats(struct ice_vsi *vsi);
static void ice_update_pf_stats(struct ice_pf *pf);
/**
- * ice_get_free_slot - get the next non-NULL location index in array
- * @array: array to search
- * @size: size of the array
- * @curr: last known occupied index to be used as a search hint
- *
- * void * is being used to keep the functionality generic. This lets us use this
- * function on any array of pointers.
+ * ice_get_tx_pending - returns number of Tx descriptors not processed
+ * @ring: the ring of descriptors
*/
-static int ice_get_free_slot(void *array, int size, int curr)
+static u32 ice_get_tx_pending(struct ice_ring *ring)
{
- int **tmp_array = (int **)array;
- int next;
+ u32 head, tail;
- if (curr < (size - 1) && !tmp_array[curr + 1]) {
- next = curr + 1;
- } else {
- int i = 0;
+ head = ring->next_to_clean;
+ tail = readl(ring->tail);
- while ((i < size) && (tmp_array[i]))
- i++;
- if (i == size)
- next = ICE_NO_VSI;
- else
- next = i;
- }
- return next;
+ if (head != tail)
+ return (head < tail) ?
+ tail - head : (tail + ring->count - head);
+ return 0;
}
/**
- * ice_search_res - Search the tracker for a block of resources
- * @res: pointer to the resource
- * @needed: size of the block needed
- * @id: identifier to track owner
- * Returns the base item index of the block, or -ENOMEM for error
+ * ice_check_for_hang_subtask - check for and recover hung queues
+ * @pf: pointer to PF struct
*/
-static int ice_search_res(struct ice_res_tracker *res, u16 needed, u16 id)
+static void ice_check_for_hang_subtask(struct ice_pf *pf)
{
- int start = res->search_hint;
- int end = start;
-
- id |= ICE_RES_VALID_BIT;
+ struct ice_vsi *vsi = NULL;
+ unsigned int i;
+ u32 v, v_idx;
+ int packets;
- do {
- /* skip already allocated entries */
- if (res->list[end++] & ICE_RES_VALID_BIT) {
- start = end;
- if ((start + needed) > res->num_entries)
- break;
+ ice_for_each_vsi(pf, v)
+ if (pf->vsi[v] && pf->vsi[v]->type == ICE_VSI_PF) {
+ vsi = pf->vsi[v];
+ break;
}
- if (end == (start + needed)) {
- int i = start;
+ if (!vsi || test_bit(__ICE_DOWN, vsi->state))
+ return;
- /* there was enough, so assign it to the requestor */
- while (i != end)
- res->list[i++] = id;
+ if (!(vsi->netdev && netif_carrier_ok(vsi->netdev)))
+ return;
- if (end == res->num_entries)
- end = 0;
+ for (i = 0; i < vsi->num_txq; i++) {
+ struct ice_ring *tx_ring = vsi->tx_rings[i];
+
+ if (tx_ring && tx_ring->desc) {
+ int itr = ICE_ITR_NONE;
+
+ /* If packet counter has not changed the queue is
+ * likely stalled, so force an interrupt for this
+ * queue.
+ *
+ * prev_pkt would be negative if there was no
+ * pending work.
+ */
+ packets = tx_ring->stats.pkts & INT_MAX;
+ if (tx_ring->tx_stats.prev_pkt == packets) {
+ /* Trigger sw interrupt to revive the queue */
+ v_idx = tx_ring->q_vector->v_idx;
+ wr32(&vsi->back->hw,
+ GLINT_DYN_CTL(vsi->hw_base_vector + v_idx),
+ (itr << GLINT_DYN_CTL_ITR_INDX_S) |
+ GLINT_DYN_CTL_SWINT_TRIG_M |
+ GLINT_DYN_CTL_INTENA_MSK_M);
+ continue;
+ }
- res->search_hint = end;
- return start;
+ /* Memory barrier between read of packet count and call
+ * to ice_get_tx_pending()
+ */
+ smp_rmb();
+ tx_ring->tx_stats.prev_pkt =
+ ice_get_tx_pending(tx_ring) ? packets : -1;
}
- } while (1);
-
- return -ENOMEM;
-}
-
-/**
- * ice_get_res - get a block of resources
- * @pf: board private structure
- * @res: pointer to the resource
- * @needed: size of the block needed
- * @id: identifier to track owner
- *
- * Returns the base item index of the block, or -ENOMEM for error
- * The search_hint trick and lack of advanced fit-finding only works
- * because we're highly likely to have all the same sized requests.
- * Linear search time and any fragmentation should be minimal.
- */
-static int
-ice_get_res(struct ice_pf *pf, struct ice_res_tracker *res, u16 needed, u16 id)
-{
- int ret;
-
- if (!res || !pf)
- return -EINVAL;
-
- if (!needed || needed > res->num_entries || id >= ICE_RES_VALID_BIT) {
- dev_err(&pf->pdev->dev,
- "param err: needed=%d, num_entries = %d id=0x%04x\n",
- needed, res->num_entries, id);
- return -EINVAL;
}
-
- /* search based on search_hint */
- ret = ice_search_res(res, needed, id);
-
- if (ret < 0) {
- /* previous search failed. Reset search hint and try again */
- res->search_hint = 0;
- ret = ice_search_res(res, needed, id);
- }
-
- return ret;
-}
-
-/**
- * ice_free_res - free a block of resources
- * @res: pointer to the resource
- * @index: starting index previously returned by ice_get_res
- * @id: identifier to track owner
- * Returns number of resources freed
- */
-static int ice_free_res(struct ice_res_tracker *res, u16 index, u16 id)
-{
- int count = 0;
- int i;
-
- if (!res || index >= res->num_entries)
- return -EINVAL;
-
- id |= ICE_RES_VALID_BIT;
- for (i = index; i < res->num_entries && res->list[i] == id; i++) {
- res->list[i] = 0;
- count++;
- }
-
- return count;
-}
-
-/**
- * ice_add_mac_to_list - Add a mac address filter entry to the list
- * @vsi: the VSI to be forwarded to
- * @add_list: pointer to the list which contains MAC filter entries
- * @macaddr: the MAC address to be added.
- *
- * Adds mac address filter entry to the temp list
- *
- * Returns 0 on success or ENOMEM on failure.
- */
-static int ice_add_mac_to_list(struct ice_vsi *vsi, struct list_head *add_list,
- const u8 *macaddr)
-{
- struct ice_fltr_list_entry *tmp;
- struct ice_pf *pf = vsi->back;
-
- tmp = devm_kzalloc(&pf->pdev->dev, sizeof(*tmp), GFP_ATOMIC);
- if (!tmp)
- return -ENOMEM;
-
- tmp->fltr_info.flag = ICE_FLTR_TX;
- tmp->fltr_info.src = vsi->vsi_num;
- tmp->fltr_info.lkup_type = ICE_SW_LKUP_MAC;
- tmp->fltr_info.fltr_act = ICE_FWD_TO_VSI;
- tmp->fltr_info.fwd_id.vsi_id = vsi->vsi_num;
- ether_addr_copy(tmp->fltr_info.l_data.mac.mac_addr, macaddr);
-
- INIT_LIST_HEAD(&tmp->list_entry);
- list_add(&tmp->list_entry, add_list);
-
- return 0;
}
/**
@@ -243,24 +155,6 @@ static int ice_add_mac_to_unsync_list(struct net_device *netdev, const u8 *addr)
}
/**
- * ice_free_fltr_list - free filter lists helper
- * @dev: pointer to the device struct
- * @h: pointer to the list head to be freed
- *
- * Helper function to free filter lists previously created using
- * ice_add_mac_to_list
- */
-static void ice_free_fltr_list(struct device *dev, struct list_head *h)
-{
- struct ice_fltr_list_entry *e, *tmp;
-
- list_for_each_entry_safe(e, tmp, h, list_entry) {
- list_del(&e->list_entry);
- devm_kfree(dev, e);
- }
-}
-
-/**
* ice_vsi_fltr_changed - check if filter state changed
* @vsi: VSI to be checked
*
@@ -359,7 +253,7 @@ static int ice_vsi_sync_fltr(struct ice_vsi *vsi)
clear_bit(ICE_VSI_FLAG_PROMISC_CHANGED, vsi->flags);
if (vsi->current_netdev_flags & IFF_PROMISC) {
/* Apply TX filter rule to get traffic from VMs */
- status = ice_cfg_dflt_vsi(hw, vsi->vsi_num, true,
+ status = ice_cfg_dflt_vsi(hw, vsi->idx, true,
ICE_FLTR_TX);
if (status) {
netdev_err(netdev, "Error setting default VSI %i tx rule\n",
@@ -369,7 +263,7 @@ static int ice_vsi_sync_fltr(struct ice_vsi *vsi)
goto out_promisc;
}
/* Apply RX filter rule to get traffic from wire */
- status = ice_cfg_dflt_vsi(hw, vsi->vsi_num, true,
+ status = ice_cfg_dflt_vsi(hw, vsi->idx, true,
ICE_FLTR_RX);
if (status) {
netdev_err(netdev, "Error setting default VSI %i rx rule\n",
@@ -380,7 +274,7 @@ static int ice_vsi_sync_fltr(struct ice_vsi *vsi)
}
} else {
/* Clear TX filter rule to stop traffic from VMs */
- status = ice_cfg_dflt_vsi(hw, vsi->vsi_num, false,
+ status = ice_cfg_dflt_vsi(hw, vsi->idx, false,
ICE_FLTR_TX);
if (status) {
netdev_err(netdev, "Error clearing default VSI %i tx rule\n",
@@ -389,8 +283,8 @@ static int ice_vsi_sync_fltr(struct ice_vsi *vsi)
err = -EIO;
goto out_promisc;
}
- /* Clear filter RX to remove traffic from wire */
- status = ice_cfg_dflt_vsi(hw, vsi->vsi_num, false,
+ /* Clear RX filter to remove traffic from wire */
+ status = ice_cfg_dflt_vsi(hw, vsi->idx, false,
ICE_FLTR_RX);
if (status) {
netdev_err(netdev, "Error clearing default VSI %i rx rule\n",
@@ -438,15 +332,6 @@ static void ice_sync_fltr_subtask(struct ice_pf *pf)
}
/**
- * ice_is_reset_recovery_pending - schedule a reset
- * @state: pf state field
- */
-static bool ice_is_reset_recovery_pending(unsigned long int *state)
-{
- return test_bit(__ICE_RESET_RECOVERY_PENDING, state);
-}
-
-/**
* ice_prepare_for_reset - prep for the core to reset
* @pf: board private structure
*
@@ -456,23 +341,17 @@ static void
ice_prepare_for_reset(struct ice_pf *pf)
{
struct ice_hw *hw = &pf->hw;
- u32 v;
-
- ice_for_each_vsi(pf, v)
- if (pf->vsi[v])
- ice_remove_vsi_fltr(hw, pf->vsi[v]->vsi_num);
- dev_dbg(&pf->pdev->dev, "Tearing down internal switch for reset\n");
+ /* Notify VFs of impending reset */
+ if (ice_check_sq_alive(hw, &hw->mailboxq))
+ ice_vc_notify_reset(pf);
/* disable the VSIs and their queues that are not already DOWN */
- /* pf_dis_all_vsi modifies netdev structures -rtnl_lock needed */
ice_pf_dis_all_vsi(pf);
- ice_for_each_vsi(pf, v)
- if (pf->vsi[v])
- pf->vsi[v]->vsi_num = 0;
-
ice_shutdown_all_ctrlq(hw);
+
+ set_bit(__ICE_PREPARED_FOR_RESET, pf->state);
}
/**
@@ -489,27 +368,29 @@ static void ice_do_reset(struct ice_pf *pf, enum ice_reset_req reset_type)
dev_dbg(dev, "reset_type 0x%x requested\n", reset_type);
WARN_ON(in_interrupt());
- /* PFR is a bit of a special case because it doesn't result in an OICR
- * interrupt. So for PFR, we prepare for reset, issue the reset and
- * rebuild sequentially.
- */
- if (reset_type == ICE_RESET_PFR) {
- set_bit(__ICE_RESET_RECOVERY_PENDING, pf->state);
- ice_prepare_for_reset(pf);
- }
+ ice_prepare_for_reset(pf);
/* trigger the reset */
if (ice_reset(hw, reset_type)) {
dev_err(dev, "reset %d failed\n", reset_type);
set_bit(__ICE_RESET_FAILED, pf->state);
- clear_bit(__ICE_RESET_RECOVERY_PENDING, pf->state);
+ clear_bit(__ICE_RESET_OICR_RECV, pf->state);
+ clear_bit(__ICE_PREPARED_FOR_RESET, pf->state);
+ clear_bit(__ICE_PFR_REQ, pf->state);
+ clear_bit(__ICE_CORER_REQ, pf->state);
+ clear_bit(__ICE_GLOBR_REQ, pf->state);
return;
}
+ /* PFR is a bit of a special case because it doesn't result in an OICR
+ * interrupt. So for PFR, rebuild after the reset and clear the reset-
+ * associated state bits.
+ */
if (reset_type == ICE_RESET_PFR) {
pf->pfr_count++;
ice_rebuild(pf);
- clear_bit(__ICE_RESET_RECOVERY_PENDING, pf->state);
+ clear_bit(__ICE_PREPARED_FOR_RESET, pf->state);
+ clear_bit(__ICE_PFR_REQ, pf->state);
}
}
@@ -519,77 +400,60 @@ static void ice_do_reset(struct ice_pf *pf, enum ice_reset_req reset_type)
*/
static void ice_reset_subtask(struct ice_pf *pf)
{
- enum ice_reset_req reset_type;
-
- rtnl_lock();
+ enum ice_reset_req reset_type = ICE_RESET_INVAL;
/* When a CORER/GLOBR/EMPR is about to happen, the hardware triggers an
- * OICR interrupt. The OICR handler (ice_misc_intr) determines what
- * type of reset happened and sets __ICE_RESET_RECOVERY_PENDING bit in
- * pf->state. So if reset/recovery is pending (as indicated by this bit)
- * we do a rebuild and return.
+ * OICR interrupt. The OICR handler (ice_misc_intr) determines what type
+ * of reset is pending and sets bits in pf->state indicating the reset
+ * type and __ICE_RESET_OICR_RECV. So, if the latter bit is set
+ * prepare for pending reset if not already (for PF software-initiated
+ * global resets the software should already be prepared for it as
+ * indicated by __ICE_PREPARED_FOR_RESET; for global resets initiated
+ * by firmware or software on other PFs, that bit is not set so prepare
+ * for the reset now), poll for reset done, rebuild and return.
*/
- if (ice_is_reset_recovery_pending(pf->state)) {
+ if (test_bit(__ICE_RESET_OICR_RECV, pf->state)) {
clear_bit(__ICE_GLOBR_RECV, pf->state);
clear_bit(__ICE_CORER_RECV, pf->state);
- ice_prepare_for_reset(pf);
+ if (!test_bit(__ICE_PREPARED_FOR_RESET, pf->state))
+ ice_prepare_for_reset(pf);
/* make sure we are ready to rebuild */
- if (ice_check_reset(&pf->hw))
+ if (ice_check_reset(&pf->hw)) {
set_bit(__ICE_RESET_FAILED, pf->state);
- else
+ } else {
+ /* done with reset. start rebuild */
+ pf->hw.reset_ongoing = false;
ice_rebuild(pf);
- clear_bit(__ICE_RESET_RECOVERY_PENDING, pf->state);
- goto unlock;
+ /* clear bit to resume normal operations, but
+ * ICE_NEEDS_RESTART bit is set incase rebuild failed
+ */
+ clear_bit(__ICE_RESET_OICR_RECV, pf->state);
+ clear_bit(__ICE_PREPARED_FOR_RESET, pf->state);
+ clear_bit(__ICE_PFR_REQ, pf->state);
+ clear_bit(__ICE_CORER_REQ, pf->state);
+ clear_bit(__ICE_GLOBR_REQ, pf->state);
+ }
+
+ return;
}
/* No pending resets to finish processing. Check for new resets */
- if (test_and_clear_bit(__ICE_GLOBR_REQ, pf->state))
- reset_type = ICE_RESET_GLOBR;
- else if (test_and_clear_bit(__ICE_CORER_REQ, pf->state))
- reset_type = ICE_RESET_CORER;
- else if (test_and_clear_bit(__ICE_PFR_REQ, pf->state))
+ if (test_bit(__ICE_PFR_REQ, pf->state))
reset_type = ICE_RESET_PFR;
- else
- goto unlock;
+ if (test_bit(__ICE_CORER_REQ, pf->state))
+ reset_type = ICE_RESET_CORER;
+ if (test_bit(__ICE_GLOBR_REQ, pf->state))
+ reset_type = ICE_RESET_GLOBR;
+ /* If no valid reset type requested just return */
+ if (reset_type == ICE_RESET_INVAL)
+ return;
- /* reset if not already down or resetting */
+ /* reset if not already down or busy */
if (!test_bit(__ICE_DOWN, pf->state) &&
!test_bit(__ICE_CFG_BUSY, pf->state)) {
ice_do_reset(pf, reset_type);
}
-
-unlock:
- rtnl_unlock();
-}
-
-/**
- * ice_watchdog_subtask - periodic tasks not using event driven scheduling
- * @pf: board private structure
- */
-static void ice_watchdog_subtask(struct ice_pf *pf)
-{
- int i;
-
- /* if interface is down do nothing */
- if (test_bit(__ICE_DOWN, pf->state) ||
- test_bit(__ICE_CFG_BUSY, pf->state))
- return;
-
- /* make sure we don't do these things too often */
- if (time_before(jiffies,
- pf->serv_tmr_prev + pf->serv_tmr_period))
- return;
-
- pf->serv_tmr_prev = jiffies;
-
- /* Update the stats for active netdevs so the network stack
- * can look at updated numbers whenever it cares to
- */
- ice_update_pf_stats(pf);
- for (i = 0; i < pf->num_alloc_vsi; i++)
- if (pf->vsi[i] && pf->vsi[i]->netdev)
- ice_update_vsi_stats(pf->vsi[i]);
}
/**
@@ -662,36 +526,6 @@ void ice_print_link_msg(struct ice_vsi *vsi, bool isup)
}
/**
- * ice_init_link_events - enable/initialize link events
- * @pi: pointer to the port_info instance
- *
- * Returns -EIO on failure, 0 on success
- */
-static int ice_init_link_events(struct ice_port_info *pi)
-{
- u16 mask;
-
- mask = ~((u16)(ICE_AQ_LINK_EVENT_UPDOWN | ICE_AQ_LINK_EVENT_MEDIA_NA |
- ICE_AQ_LINK_EVENT_MODULE_QUAL_FAIL));
-
- if (ice_aq_set_event_mask(pi->hw, pi->lport, mask, NULL)) {
- dev_dbg(ice_hw_to_dev(pi->hw),
- "Failed to set link event mask for port %d\n",
- pi->lport);
- return -EIO;
- }
-
- if (ice_aq_get_link_info(pi, true, NULL, NULL)) {
- dev_dbg(ice_hw_to_dev(pi->hw),
- "Failed to enable link events for port %d\n",
- pi->lport);
- return -EIO;
- }
-
- return 0;
-}
-
-/**
* ice_vsi_link_event - update the vsi's netdev
* @vsi: the vsi on which the link event occurred
* @link_up: whether or not the vsi needs to be set up or down
@@ -772,31 +606,41 @@ ice_link_event(struct ice_pf *pf, struct ice_port_info *pi)
}
}
+ ice_vc_notify_link_state(pf);
+
return 0;
}
/**
- * ice_handle_link_event - handle link event via ARQ
- * @pf: pf that the link event is associated with
- *
- * Return -EINVAL if port_info is null
- * Return status on succes
+ * ice_watchdog_subtask - periodic tasks not using event driven scheduling
+ * @pf: board private structure
*/
-static int ice_handle_link_event(struct ice_pf *pf)
+static void ice_watchdog_subtask(struct ice_pf *pf)
{
- struct ice_port_info *port_info;
- int status;
+ int i;
- port_info = pf->hw.port_info;
- if (!port_info)
- return -EINVAL;
+ /* if interface is down do nothing */
+ if (test_bit(__ICE_DOWN, pf->state) ||
+ test_bit(__ICE_CFG_BUSY, pf->state))
+ return;
- status = ice_link_event(pf, port_info);
- if (status)
- dev_dbg(&pf->pdev->dev,
- "Could not process link event, error %d\n", status);
+ /* make sure we don't do these things too often */
+ if (time_before(jiffies,
+ pf->serv_tmr_prev + pf->serv_tmr_period))
+ return;
- return status;
+ pf->serv_tmr_prev = jiffies;
+
+ if (ice_link_event(pf, pf->hw.port_info))
+ dev_dbg(&pf->pdev->dev, "ice_link_event failed\n");
+
+ /* Update the stats for active netdevs so the network stack
+ * can look at updated numbers whenever it cares to
+ */
+ ice_update_pf_stats(pf);
+ for (i = 0; i < pf->num_alloc_vsi; i++)
+ if (pf->vsi[i] && pf->vsi[i]->netdev)
+ ice_update_vsi_stats(pf->vsi[i]);
}
/**
@@ -822,6 +666,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_MAILBOX:
+ cq = &hw->mailboxq;
+ qtype = "Mailbox";
+ break;
default:
dev_warn(&pf->pdev->dev, "Unknown control queue type 0x%x\n",
q_type);
@@ -898,10 +746,11 @@ static int __ice_clean_ctrlq(struct ice_pf *pf, enum ice_ctl_q q_type)
opcode = le16_to_cpu(event.desc.opcode);
switch (opcode) {
- case ice_aqc_opc_get_link_status:
- if (ice_handle_link_event(pf))
- dev_err(&pf->pdev->dev,
- "Could not handle link event\n");
+ case ice_mbx_opc_send_msg_to_pf:
+ ice_vc_process_vf_msg(pf, &event);
+ break;
+ case ice_aqc_opc_fw_logging:
+ ice_output_fw_log(hw, &event.desc, event.msg_buf);
break;
default:
dev_dbg(&pf->pdev->dev,
@@ -959,6 +808,28 @@ static void ice_clean_adminq_subtask(struct ice_pf *pf)
}
/**
+ * ice_clean_mailboxq_subtask - clean the MailboxQ rings
+ * @pf: board private structure
+ */
+static void ice_clean_mailboxq_subtask(struct ice_pf *pf)
+{
+ struct ice_hw *hw = &pf->hw;
+
+ if (!test_bit(__ICE_MAILBOXQ_EVENT_PENDING, pf->state))
+ return;
+
+ if (__ice_clean_ctrlq(pf, ICE_CTL_Q_MAILBOX))
+ return;
+
+ clear_bit(__ICE_MAILBOXQ_EVENT_PENDING, pf->state);
+
+ if (ice_ctrlq_pending(hw, &hw->mailboxq))
+ __ice_clean_ctrlq(pf, ICE_CTL_Q_MAILBOX);
+
+ ice_flush(hw);
+}
+
+/**
* ice_service_task_schedule - schedule the service task to wake up
* @pf: board private structure
*
@@ -966,8 +837,9 @@ static void ice_clean_adminq_subtask(struct ice_pf *pf)
*/
static void ice_service_task_schedule(struct ice_pf *pf)
{
- if (!test_bit(__ICE_DOWN, pf->state) &&
- !test_and_set_bit(__ICE_SERVICE_SCHED, pf->state))
+ if (!test_bit(__ICE_SERVICE_DIS, pf->state) &&
+ !test_and_set_bit(__ICE_SERVICE_SCHED, pf->state) &&
+ !test_bit(__ICE_NEEDS_RESTART, pf->state))
queue_work(ice_wq, &pf->serv_task);
}
@@ -985,6 +857,22 @@ static void ice_service_task_complete(struct ice_pf *pf)
}
/**
+ * ice_service_task_stop - stop service task and cancel works
+ * @pf: board private structure
+ */
+static void ice_service_task_stop(struct ice_pf *pf)
+{
+ set_bit(__ICE_SERVICE_DIS, pf->state);
+
+ if (pf->serv_tmr.function)
+ del_timer_sync(&pf->serv_tmr);
+ if (pf->serv_task.func)
+ cancel_work_sync(&pf->serv_task);
+
+ clear_bit(__ICE_SERVICE_SCHED, pf->state);
+}
+
+/**
* ice_service_timer - timer callback to schedule service task
* @t: pointer to timer_list
*/
@@ -997,6 +885,160 @@ static void ice_service_timer(struct timer_list *t)
}
/**
+ * ice_handle_mdd_event - handle malicious driver detect event
+ * @pf: pointer to the PF structure
+ *
+ * Called from service task. OICR interrupt handler indicates MDD event
+ */
+static void ice_handle_mdd_event(struct ice_pf *pf)
+{
+ struct ice_hw *hw = &pf->hw;
+ bool mdd_detected = false;
+ u32 reg;
+ int i;
+
+ if (!test_bit(__ICE_MDD_EVENT_PENDING, pf->state))
+ return;
+
+ /* find what triggered the MDD event */
+ reg = rd32(hw, GL_MDET_TX_PQM);
+ if (reg & GL_MDET_TX_PQM_VALID_M) {
+ u8 pf_num = (reg & GL_MDET_TX_PQM_PF_NUM_M) >>
+ GL_MDET_TX_PQM_PF_NUM_S;
+ u16 vf_num = (reg & GL_MDET_TX_PQM_VF_NUM_M) >>
+ GL_MDET_TX_PQM_VF_NUM_S;
+ u8 event = (reg & GL_MDET_TX_PQM_MAL_TYPE_M) >>
+ GL_MDET_TX_PQM_MAL_TYPE_S;
+ u16 queue = ((reg & GL_MDET_TX_PQM_QNUM_M) >>
+ GL_MDET_TX_PQM_QNUM_S);
+
+ if (netif_msg_tx_err(pf))
+ dev_info(&pf->pdev->dev, "Malicious Driver Detection event %d on TX queue %d PF# %d VF# %d\n",
+ event, queue, pf_num, vf_num);
+ wr32(hw, GL_MDET_TX_PQM, 0xffffffff);
+ mdd_detected = true;
+ }
+
+ reg = rd32(hw, GL_MDET_TX_TCLAN);
+ if (reg & GL_MDET_TX_TCLAN_VALID_M) {
+ u8 pf_num = (reg & GL_MDET_TX_TCLAN_PF_NUM_M) >>
+ GL_MDET_TX_TCLAN_PF_NUM_S;
+ u16 vf_num = (reg & GL_MDET_TX_TCLAN_VF_NUM_M) >>
+ GL_MDET_TX_TCLAN_VF_NUM_S;
+ u8 event = (reg & GL_MDET_TX_TCLAN_MAL_TYPE_M) >>
+ GL_MDET_TX_TCLAN_MAL_TYPE_S;
+ u16 queue = ((reg & GL_MDET_TX_TCLAN_QNUM_M) >>
+ GL_MDET_TX_TCLAN_QNUM_S);
+
+ if (netif_msg_rx_err(pf))
+ dev_info(&pf->pdev->dev, "Malicious Driver Detection event %d on TX queue %d PF# %d VF# %d\n",
+ event, queue, pf_num, vf_num);
+ wr32(hw, GL_MDET_TX_TCLAN, 0xffffffff);
+ mdd_detected = true;
+ }
+
+ reg = rd32(hw, GL_MDET_RX);
+ if (reg & GL_MDET_RX_VALID_M) {
+ u8 pf_num = (reg & GL_MDET_RX_PF_NUM_M) >>
+ GL_MDET_RX_PF_NUM_S;
+ u16 vf_num = (reg & GL_MDET_RX_VF_NUM_M) >>
+ GL_MDET_RX_VF_NUM_S;
+ u8 event = (reg & GL_MDET_RX_MAL_TYPE_M) >>
+ GL_MDET_RX_MAL_TYPE_S;
+ u16 queue = ((reg & GL_MDET_RX_QNUM_M) >>
+ GL_MDET_RX_QNUM_S);
+
+ if (netif_msg_rx_err(pf))
+ dev_info(&pf->pdev->dev, "Malicious Driver Detection event %d on RX queue %d PF# %d VF# %d\n",
+ event, queue, pf_num, vf_num);
+ wr32(hw, GL_MDET_RX, 0xffffffff);
+ mdd_detected = true;
+ }
+
+ if (mdd_detected) {
+ bool pf_mdd_detected = false;
+
+ reg = rd32(hw, PF_MDET_TX_PQM);
+ if (reg & PF_MDET_TX_PQM_VALID_M) {
+ wr32(hw, PF_MDET_TX_PQM, 0xFFFF);
+ dev_info(&pf->pdev->dev, "TX driver issue detected, PF reset issued\n");
+ pf_mdd_detected = true;
+ }
+
+ reg = rd32(hw, PF_MDET_TX_TCLAN);
+ if (reg & PF_MDET_TX_TCLAN_VALID_M) {
+ wr32(hw, PF_MDET_TX_TCLAN, 0xFFFF);
+ dev_info(&pf->pdev->dev, "TX driver issue detected, PF reset issued\n");
+ pf_mdd_detected = true;
+ }
+
+ reg = rd32(hw, PF_MDET_RX);
+ if (reg & PF_MDET_RX_VALID_M) {
+ wr32(hw, PF_MDET_RX, 0xFFFF);
+ dev_info(&pf->pdev->dev, "RX driver issue detected, PF reset issued\n");
+ pf_mdd_detected = true;
+ }
+ /* Queue belongs to the PF initiate a reset */
+ if (pf_mdd_detected) {
+ set_bit(__ICE_NEEDS_RESTART, pf->state);
+ ice_service_task_schedule(pf);
+ }
+ }
+
+ /* see if one of the VFs needs to be reset */
+ for (i = 0; i < pf->num_alloc_vfs && mdd_detected; i++) {
+ struct ice_vf *vf = &pf->vf[i];
+
+ reg = rd32(hw, VP_MDET_TX_PQM(i));
+ if (reg & VP_MDET_TX_PQM_VALID_M) {
+ wr32(hw, VP_MDET_TX_PQM(i), 0xFFFF);
+ vf->num_mdd_events++;
+ dev_info(&pf->pdev->dev, "TX driver issue detected on VF %d\n",
+ i);
+ }
+
+ reg = rd32(hw, VP_MDET_TX_TCLAN(i));
+ if (reg & VP_MDET_TX_TCLAN_VALID_M) {
+ wr32(hw, VP_MDET_TX_TCLAN(i), 0xFFFF);
+ vf->num_mdd_events++;
+ dev_info(&pf->pdev->dev, "TX driver issue detected on VF %d\n",
+ i);
+ }
+
+ reg = rd32(hw, VP_MDET_TX_TDPU(i));
+ if (reg & VP_MDET_TX_TDPU_VALID_M) {
+ wr32(hw, VP_MDET_TX_TDPU(i), 0xFFFF);
+ vf->num_mdd_events++;
+ dev_info(&pf->pdev->dev, "TX driver issue detected on VF %d\n",
+ i);
+ }
+
+ reg = rd32(hw, VP_MDET_RX(i));
+ if (reg & VP_MDET_RX_VALID_M) {
+ wr32(hw, VP_MDET_RX(i), 0xFFFF);
+ vf->num_mdd_events++;
+ dev_info(&pf->pdev->dev, "RX driver issue detected on VF %d\n",
+ i);
+ }
+
+ if (vf->num_mdd_events > ICE_DFLT_NUM_MDD_EVENTS_ALLOWED) {
+ dev_info(&pf->pdev->dev,
+ "Too many MDD events on VF %d, disabled\n", i);
+ dev_info(&pf->pdev->dev,
+ "Use PF Control I/F to re-enable the VF\n");
+ set_bit(ICE_VF_STATE_DIS, vf->vf_states);
+ }
+ }
+
+ /* re-enable MDD interrupt cause */
+ clear_bit(__ICE_MDD_EVENT_PENDING, pf->state);
+ reg = rd32(hw, PFINT_OICR_ENA);
+ reg |= PFINT_OICR_MAL_DETECT_M;
+ wr32(hw, PFINT_OICR_ENA, reg);
+ ice_flush(hw);
+}
+
+/**
* ice_service_task - manage and run subtasks
* @work: pointer to work_struct contained by the PF struct
*/
@@ -1010,16 +1052,21 @@ static void ice_service_task(struct work_struct *work)
/* process reset requests first */
ice_reset_subtask(pf);
- /* bail if a reset/recovery cycle is pending */
- if (ice_is_reset_recovery_pending(pf->state) ||
- test_bit(__ICE_SUSPENDED, pf->state)) {
+ /* bail if a reset/recovery cycle is pending or rebuild failed */
+ if (ice_is_reset_in_progress(pf->state) ||
+ test_bit(__ICE_SUSPENDED, pf->state) ||
+ test_bit(__ICE_NEEDS_RESTART, pf->state)) {
ice_service_task_complete(pf);
return;
}
+ ice_check_for_hang_subtask(pf);
ice_sync_fltr_subtask(pf);
+ ice_handle_mdd_event(pf);
+ ice_process_vflr_event(pf);
ice_watchdog_subtask(pf);
ice_clean_adminq_subtask(pf);
+ ice_clean_mailboxq_subtask(pf);
/* Clear __ICE_SERVICE_SCHED flag to allow scheduling next event */
ice_service_task_complete(pf);
@@ -1029,6 +1076,9 @@ static void ice_service_task(struct work_struct *work)
* schedule the service task now.
*/
if (time_after(jiffies, (start_time + pf->serv_tmr_period)) ||
+ test_bit(__ICE_MDD_EVENT_PENDING, pf->state) ||
+ test_bit(__ICE_VFLR_EVENT_PENDING, pf->state) ||
+ test_bit(__ICE_MAILBOXQ_EVENT_PENDING, pf->state) ||
test_bit(__ICE_ADMINQ_EVENT_PENDING, pf->state))
mod_timer(&pf->serv_tmr, jiffies);
}
@@ -1043,6 +1093,10 @@ static void ice_set_ctrlq_len(struct ice_hw *hw)
hw->adminq.num_sq_entries = ICE_AQ_LEN;
hw->adminq.rq_buf_size = ICE_AQ_MAX_BUF_LEN;
hw->adminq.sq_buf_size = ICE_AQ_MAX_BUF_LEN;
+ hw->mailboxq.num_rq_entries = ICE_MBXQ_LEN;
+ hw->mailboxq.num_sq_entries = ICE_MBXQ_LEN;
+ hw->mailboxq.rq_buf_size = ICE_MBXQ_MAX_BUF_LEN;
+ hw->mailboxq.sq_buf_size = ICE_MBXQ_MAX_BUF_LEN;
}
/**
@@ -1073,57 +1127,6 @@ static void ice_irq_affinity_notify(struct irq_affinity_notify *notify,
static void ice_irq_affinity_release(struct kref __always_unused *ref) {}
/**
- * ice_vsi_dis_irq - Mask off queue interrupt generation on the VSI
- * @vsi: the VSI being un-configured
- */
-static void ice_vsi_dis_irq(struct ice_vsi *vsi)
-{
- struct ice_pf *pf = vsi->back;
- struct ice_hw *hw = &pf->hw;
- int base = vsi->base_vector;
- u32 val;
- int i;
-
- /* disable interrupt causation from each queue */
- if (vsi->tx_rings) {
- ice_for_each_txq(vsi, i) {
- if (vsi->tx_rings[i]) {
- u16 reg;
-
- reg = vsi->tx_rings[i]->reg_idx;
- val = rd32(hw, QINT_TQCTL(reg));
- val &= ~QINT_TQCTL_CAUSE_ENA_M;
- wr32(hw, QINT_TQCTL(reg), val);
- }
- }
- }
-
- if (vsi->rx_rings) {
- ice_for_each_rxq(vsi, i) {
- if (vsi->rx_rings[i]) {
- u16 reg;
-
- reg = vsi->rx_rings[i]->reg_idx;
- val = rd32(hw, QINT_RQCTL(reg));
- val &= ~QINT_RQCTL_CAUSE_ENA_M;
- wr32(hw, QINT_RQCTL(reg), val);
- }
- }
- }
-
- /* disable each interrupt */
- if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) {
- for (i = vsi->base_vector;
- i < (vsi->num_q_vectors + vsi->base_vector); i++)
- wr32(hw, GLINT_DYN_CTL(i), 0);
-
- ice_flush(hw);
- for (i = 0; i < vsi->num_q_vectors; i++)
- synchronize_irq(pf->msix_entries[i + base].vector);
- }
-}
-
-/**
* ice_vsi_ena_irq - Enable IRQ for the given VSI
* @vsi: the VSI being configured
*/
@@ -1144,26 +1147,6 @@ static int ice_vsi_ena_irq(struct ice_vsi *vsi)
}
/**
- * ice_vsi_delete - delete a VSI from the switch
- * @vsi: pointer to VSI being removed
- */
-static void ice_vsi_delete(struct ice_vsi *vsi)
-{
- struct ice_pf *pf = vsi->back;
- struct ice_vsi_ctx ctxt;
- enum ice_status status;
-
- ctxt.vsi_num = vsi->vsi_num;
-
- memcpy(&ctxt.info, &vsi->info, sizeof(struct ice_aqc_vsi_props));
-
- status = ice_aq_free_vsi(&pf->hw, &ctxt, false, NULL);
- if (status)
- dev_err(&pf->pdev->dev, "Failed to delete VSI %i in FW\n",
- vsi->vsi_num);
-}
-
-/**
* ice_vsi_req_irq_msix - get MSI-X vectors from the OS for the VSI
* @vsi: the VSI being configured
* @basename: name for the vector
@@ -1172,7 +1155,7 @@ static int ice_vsi_req_irq_msix(struct ice_vsi *vsi, char *basename)
{
int q_vectors = vsi->num_q_vectors;
struct ice_pf *pf = vsi->back;
- int base = vsi->base_vector;
+ int base = vsi->sw_base_vector;
int rx_int_idx = 0;
int tx_int_idx = 0;
int vector, err;
@@ -1231,467 +1214,6 @@ free_q_irqs:
}
/**
- * ice_vsi_set_rss_params - Setup RSS capabilities per VSI type
- * @vsi: the VSI being configured
- */
-static void ice_vsi_set_rss_params(struct ice_vsi *vsi)
-{
- struct ice_hw_common_caps *cap;
- struct ice_pf *pf = vsi->back;
-
- if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) {
- vsi->rss_size = 1;
- return;
- }
-
- cap = &pf->hw.func_caps.common_cap;
- switch (vsi->type) {
- case ICE_VSI_PF:
- /* PF VSI will inherit RSS instance of PF */
- vsi->rss_table_size = cap->rss_table_size;
- vsi->rss_size = min_t(int, num_online_cpus(),
- BIT(cap->rss_table_entry_width));
- vsi->rss_lut_type = ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_PF;
- break;
- default:
- dev_warn(&pf->pdev->dev, "Unknown VSI type %d\n", vsi->type);
- break;
- }
-}
-
-/**
- * ice_vsi_setup_q_map - Setup a VSI queue map
- * @vsi: the VSI being configured
- * @ctxt: VSI context structure
- */
-static void ice_vsi_setup_q_map(struct ice_vsi *vsi, struct ice_vsi_ctx *ctxt)
-{
- u16 offset = 0, qmap = 0, numq_tc;
- u16 pow = 0, max_rss = 0, qcount;
- u16 qcount_tx = vsi->alloc_txq;
- u16 qcount_rx = vsi->alloc_rxq;
- bool ena_tc0 = false;
- int i;
-
- /* at least TC0 should be enabled by default */
- if (vsi->tc_cfg.numtc) {
- if (!(vsi->tc_cfg.ena_tc & BIT(0)))
- ena_tc0 = true;
- } else {
- ena_tc0 = true;
- }
-
- if (ena_tc0) {
- vsi->tc_cfg.numtc++;
- vsi->tc_cfg.ena_tc |= 1;
- }
-
- numq_tc = qcount_rx / vsi->tc_cfg.numtc;
-
- /* TC mapping is a function of the number of Rx queues assigned to the
- * VSI for each traffic class and the offset of these queues.
- * The first 10 bits are for queue offset for TC0, next 4 bits for no:of
- * queues allocated to TC0. No:of queues is a power-of-2.
- *
- * If TC is not enabled, the queue offset is set to 0, and allocate one
- * queue, this way, traffic for the given TC will be sent to the default
- * queue.
- *
- * Setup number and offset of Rx queues for all TCs for the VSI
- */
-
- /* qcount will change if RSS is enabled */
- if (test_bit(ICE_FLAG_RSS_ENA, vsi->back->flags)) {
- if (vsi->type == ICE_VSI_PF)
- max_rss = ICE_MAX_LG_RSS_QS;
- else
- max_rss = ICE_MAX_SMALL_RSS_QS;
-
- qcount = min_t(int, numq_tc, max_rss);
- qcount = min_t(int, qcount, vsi->rss_size);
- } else {
- qcount = numq_tc;
- }
-
- /* find the (rounded up) power-of-2 of qcount */
- pow = order_base_2(qcount);
-
- for (i = 0; i < ICE_MAX_TRAFFIC_CLASS; i++) {
- if (!(vsi->tc_cfg.ena_tc & BIT(i))) {
- /* TC is not enabled */
- vsi->tc_cfg.tc_info[i].qoffset = 0;
- vsi->tc_cfg.tc_info[i].qcount = 1;
- ctxt->info.tc_mapping[i] = 0;
- continue;
- }
-
- /* TC is enabled */
- vsi->tc_cfg.tc_info[i].qoffset = offset;
- vsi->tc_cfg.tc_info[i].qcount = qcount;
-
- qmap = ((offset << ICE_AQ_VSI_TC_Q_OFFSET_S) &
- ICE_AQ_VSI_TC_Q_OFFSET_M) |
- ((pow << ICE_AQ_VSI_TC_Q_NUM_S) &
- ICE_AQ_VSI_TC_Q_NUM_M);
- offset += qcount;
- ctxt->info.tc_mapping[i] = cpu_to_le16(qmap);
- }
-
- vsi->num_txq = qcount_tx;
- vsi->num_rxq = offset;
-
- /* Rx queue mapping */
- ctxt->info.mapping_flags |= cpu_to_le16(ICE_AQ_VSI_Q_MAP_CONTIG);
- /* q_mapping buffer holds the info for the first queue allocated for
- * this VSI in the PF space and also the number of queues associated
- * with this VSI.
- */
- ctxt->info.q_mapping[0] = cpu_to_le16(vsi->rxq_map[0]);
- ctxt->info.q_mapping[1] = cpu_to_le16(vsi->num_rxq);
-}
-
-/**
- * ice_set_dflt_vsi_ctx - Set default VSI context before adding a VSI
- * @ctxt: the VSI context being set
- *
- * This initializes a default VSI context for all sections except the Queues.
- */
-static void ice_set_dflt_vsi_ctx(struct ice_vsi_ctx *ctxt)
-{
- u32 table = 0;
-
- memset(&ctxt->info, 0, sizeof(ctxt->info));
- /* VSI's should be allocated from shared pool */
- ctxt->alloc_from_pool = true;
- /* Src pruning enabled by default */
- ctxt->info.sw_flags = ICE_AQ_VSI_SW_FLAG_SRC_PRUNE;
- /* Traffic from VSI can be sent to LAN */
- ctxt->info.sw_flags2 = ICE_AQ_VSI_SW_FLAG_LAN_ENA;
-
- /* By default bits 3 and 4 in vlan_flags are 0's which results in legacy
- * behavior (show VLAN, DEI, and UP) in descriptor. Also, allow all
- * packets untagged/tagged.
- */
- ctxt->info.vlan_flags = ((ICE_AQ_VSI_VLAN_MODE_ALL &
- ICE_AQ_VSI_VLAN_MODE_M) >>
- ICE_AQ_VSI_VLAN_MODE_S);
-
- /* Have 1:1 UP mapping for both ingress/egress tables */
- table |= ICE_UP_TABLE_TRANSLATE(0, 0);
- table |= ICE_UP_TABLE_TRANSLATE(1, 1);
- table |= ICE_UP_TABLE_TRANSLATE(2, 2);
- table |= ICE_UP_TABLE_TRANSLATE(3, 3);
- table |= ICE_UP_TABLE_TRANSLATE(4, 4);
- table |= ICE_UP_TABLE_TRANSLATE(5, 5);
- table |= ICE_UP_TABLE_TRANSLATE(6, 6);
- table |= ICE_UP_TABLE_TRANSLATE(7, 7);
- ctxt->info.ingress_table = cpu_to_le32(table);
- ctxt->info.egress_table = cpu_to_le32(table);
- /* Have 1:1 UP mapping for outer to inner UP table */
- ctxt->info.outer_up_table = cpu_to_le32(table);
- /* No Outer tag support outer_tag_flags remains to zero */
-}
-
-/**
- * ice_set_rss_vsi_ctx - Set RSS VSI context before adding a VSI
- * @ctxt: the VSI context being set
- * @vsi: the VSI being configured
- */
-static void ice_set_rss_vsi_ctx(struct ice_vsi_ctx *ctxt, struct ice_vsi *vsi)
-{
- u8 lut_type, hash_type;
-
- switch (vsi->type) {
- case ICE_VSI_PF:
- /* PF VSI will inherit RSS instance of PF */
- lut_type = ICE_AQ_VSI_Q_OPT_RSS_LUT_PF;
- hash_type = ICE_AQ_VSI_Q_OPT_RSS_TPLZ;
- break;
- default:
- dev_warn(&vsi->back->pdev->dev, "Unknown VSI type %d\n",
- vsi->type);
- return;
- }
-
- ctxt->info.q_opt_rss = ((lut_type << ICE_AQ_VSI_Q_OPT_RSS_LUT_S) &
- ICE_AQ_VSI_Q_OPT_RSS_LUT_M) |
- ((hash_type << ICE_AQ_VSI_Q_OPT_RSS_HASH_S) &
- ICE_AQ_VSI_Q_OPT_RSS_HASH_M);
-}
-
-/**
- * ice_vsi_add - Create a new VSI or fetch preallocated VSI
- * @vsi: the VSI being configured
- *
- * This initializes a VSI context depending on the VSI type to be added and
- * passes it down to the add_vsi aq command to create a new VSI.
- */
-static int ice_vsi_add(struct ice_vsi *vsi)
-{
- struct ice_vsi_ctx ctxt = { 0 };
- struct ice_pf *pf = vsi->back;
- struct ice_hw *hw = &pf->hw;
- int ret = 0;
-
- switch (vsi->type) {
- case ICE_VSI_PF:
- ctxt.flags = ICE_AQ_VSI_TYPE_PF;
- break;
- default:
- return -ENODEV;
- }
-
- ice_set_dflt_vsi_ctx(&ctxt);
- /* if the switch is in VEB mode, allow VSI loopback */
- if (vsi->vsw->bridge_mode == BRIDGE_MODE_VEB)
- ctxt.info.sw_flags |= ICE_AQ_VSI_SW_FLAG_ALLOW_LB;
-
- /* Set LUT type and HASH type if RSS is enabled */
- if (test_bit(ICE_FLAG_RSS_ENA, pf->flags))
- ice_set_rss_vsi_ctx(&ctxt, vsi);
-
- ctxt.info.sw_id = vsi->port_info->sw_id;
- ice_vsi_setup_q_map(vsi, &ctxt);
-
- ret = ice_aq_add_vsi(hw, &ctxt, NULL);
- if (ret) {
- dev_err(&vsi->back->pdev->dev,
- "Add VSI AQ call failed, err %d\n", ret);
- return -EIO;
- }
- vsi->info = ctxt.info;
- vsi->vsi_num = ctxt.vsi_num;
-
- return ret;
-}
-
-/**
- * ice_vsi_release_msix - Clear the queue to Interrupt mapping in HW
- * @vsi: the VSI being cleaned up
- */
-static void ice_vsi_release_msix(struct ice_vsi *vsi)
-{
- struct ice_pf *pf = vsi->back;
- u16 vector = vsi->base_vector;
- struct ice_hw *hw = &pf->hw;
- u32 txq = 0;
- u32 rxq = 0;
- int i, q;
-
- for (i = 0; i < vsi->num_q_vectors; i++, vector++) {
- struct ice_q_vector *q_vector = vsi->q_vectors[i];
-
- wr32(hw, GLINT_ITR(ICE_RX_ITR, vector), 0);
- wr32(hw, GLINT_ITR(ICE_TX_ITR, vector), 0);
- for (q = 0; q < q_vector->num_ring_tx; q++) {
- wr32(hw, QINT_TQCTL(vsi->txq_map[txq]), 0);
- txq++;
- }
-
- for (q = 0; q < q_vector->num_ring_rx; q++) {
- wr32(hw, QINT_RQCTL(vsi->rxq_map[rxq]), 0);
- rxq++;
- }
- }
-
- ice_flush(hw);
-}
-
-/**
- * ice_vsi_clear_rings - Deallocates the Tx and Rx rings for VSI
- * @vsi: the VSI having rings deallocated
- */
-static void ice_vsi_clear_rings(struct ice_vsi *vsi)
-{
- int i;
-
- if (vsi->tx_rings) {
- for (i = 0; i < vsi->alloc_txq; i++) {
- if (vsi->tx_rings[i]) {
- kfree_rcu(vsi->tx_rings[i], rcu);
- vsi->tx_rings[i] = NULL;
- }
- }
- }
- if (vsi->rx_rings) {
- for (i = 0; i < vsi->alloc_rxq; i++) {
- if (vsi->rx_rings[i]) {
- kfree_rcu(vsi->rx_rings[i], rcu);
- vsi->rx_rings[i] = NULL;
- }
- }
- }
-}
-
-/**
- * ice_vsi_alloc_rings - Allocates Tx and Rx rings for the VSI
- * @vsi: VSI which is having rings allocated
- */
-static int ice_vsi_alloc_rings(struct ice_vsi *vsi)
-{
- struct ice_pf *pf = vsi->back;
- int i;
-
- /* Allocate tx_rings */
- for (i = 0; i < vsi->alloc_txq; i++) {
- struct ice_ring *ring;
-
- /* allocate with kzalloc(), free with kfree_rcu() */
- ring = kzalloc(sizeof(*ring), GFP_KERNEL);
-
- if (!ring)
- goto err_out;
-
- ring->q_index = i;
- ring->reg_idx = vsi->txq_map[i];
- ring->ring_active = false;
- ring->vsi = vsi;
- ring->netdev = vsi->netdev;
- ring->dev = &pf->pdev->dev;
- ring->count = vsi->num_desc;
-
- vsi->tx_rings[i] = ring;
- }
-
- /* Allocate rx_rings */
- for (i = 0; i < vsi->alloc_rxq; i++) {
- struct ice_ring *ring;
-
- /* allocate with kzalloc(), free with kfree_rcu() */
- ring = kzalloc(sizeof(*ring), GFP_KERNEL);
- if (!ring)
- goto err_out;
-
- ring->q_index = i;
- ring->reg_idx = vsi->rxq_map[i];
- ring->ring_active = false;
- ring->vsi = vsi;
- ring->netdev = vsi->netdev;
- ring->dev = &pf->pdev->dev;
- ring->count = vsi->num_desc;
- vsi->rx_rings[i] = ring;
- }
-
- return 0;
-
-err_out:
- ice_vsi_clear_rings(vsi);
- return -ENOMEM;
-}
-
-/**
- * ice_vsi_free_irq - Free the irq association with the OS
- * @vsi: the VSI being configured
- */
-static void ice_vsi_free_irq(struct ice_vsi *vsi)
-{
- struct ice_pf *pf = vsi->back;
- int base = vsi->base_vector;
-
- if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) {
- int i;
-
- if (!vsi->q_vectors || !vsi->irqs_ready)
- return;
-
- vsi->irqs_ready = false;
- for (i = 0; i < vsi->num_q_vectors; i++) {
- u16 vector = i + base;
- int irq_num;
-
- irq_num = pf->msix_entries[vector].vector;
-
- /* free only the irqs that were actually requested */
- if (!vsi->q_vectors[i] ||
- !(vsi->q_vectors[i]->num_ring_tx ||
- vsi->q_vectors[i]->num_ring_rx))
- continue;
-
- /* clear the affinity notifier in the IRQ descriptor */
- irq_set_affinity_notifier(irq_num, NULL);
-
- /* clear the affinity_mask in the IRQ descriptor */
- irq_set_affinity_hint(irq_num, NULL);
- synchronize_irq(irq_num);
- devm_free_irq(&pf->pdev->dev, irq_num,
- vsi->q_vectors[i]);
- }
- ice_vsi_release_msix(vsi);
- }
-}
-
-/**
- * ice_vsi_cfg_msix - MSIX mode Interrupt Config in the HW
- * @vsi: the VSI being configured
- */
-static void ice_vsi_cfg_msix(struct ice_vsi *vsi)
-{
- struct ice_pf *pf = vsi->back;
- u16 vector = vsi->base_vector;
- struct ice_hw *hw = &pf->hw;
- u32 txq = 0, rxq = 0;
- int i, q, itr;
- u8 itr_gran;
-
- for (i = 0; i < vsi->num_q_vectors; i++, vector++) {
- struct ice_q_vector *q_vector = vsi->q_vectors[i];
-
- itr_gran = hw->itr_gran_200;
-
- if (q_vector->num_ring_rx) {
- q_vector->rx.itr =
- ITR_TO_REG(vsi->rx_rings[rxq]->rx_itr_setting,
- itr_gran);
- q_vector->rx.latency_range = ICE_LOW_LATENCY;
- }
-
- if (q_vector->num_ring_tx) {
- q_vector->tx.itr =
- ITR_TO_REG(vsi->tx_rings[txq]->tx_itr_setting,
- itr_gran);
- q_vector->tx.latency_range = ICE_LOW_LATENCY;
- }
- wr32(hw, GLINT_ITR(ICE_RX_ITR, vector), q_vector->rx.itr);
- wr32(hw, GLINT_ITR(ICE_TX_ITR, vector), q_vector->tx.itr);
-
- /* Both Transmit Queue Interrupt Cause Control register
- * and Receive Queue Interrupt Cause control register
- * expects MSIX_INDX field to be the vector index
- * within the function space and not the absolute
- * vector index across PF or across device.
- * For SR-IOV VF VSIs queue vector index always starts
- * with 1 since first vector index(0) is used for OICR
- * in VF space. Since VMDq and other PF VSIs are withtin
- * the PF function space, use the vector index thats
- * tracked for this PF.
- */
- for (q = 0; q < q_vector->num_ring_tx; q++) {
- u32 val;
-
- itr = ICE_TX_ITR;
- val = QINT_TQCTL_CAUSE_ENA_M |
- (itr << QINT_TQCTL_ITR_INDX_S) |
- (vector << QINT_TQCTL_MSIX_INDX_S);
- wr32(hw, QINT_TQCTL(vsi->txq_map[txq]), val);
- txq++;
- }
-
- for (q = 0; q < q_vector->num_ring_rx; q++) {
- u32 val;
-
- itr = ICE_RX_ITR;
- val = QINT_RQCTL_CAUSE_ENA_M |
- (itr << QINT_RQCTL_ITR_INDX_S) |
- (vector << QINT_RQCTL_MSIX_INDX_S);
- wr32(hw, QINT_RQCTL(vsi->rxq_map[rxq]), val);
- rxq++;
- }
- }
-
- ice_flush(hw);
-}
-
-/**
* ice_ena_misc_vector - enable the non-queue interrupts
* @pf: board private structure
*/
@@ -1708,13 +1230,14 @@ static void ice_ena_misc_vector(struct ice_pf *pf)
PFINT_OICR_MAL_DETECT_M |
PFINT_OICR_GRST_M |
PFINT_OICR_PCI_EXCEPTION_M |
+ PFINT_OICR_VFLR_M |
PFINT_OICR_HMC_ERR_M |
PFINT_OICR_PE_CRITERR_M);
wr32(hw, PFINT_OICR_ENA, val);
/* SW_ITR_IDX = 0, but don't change INTENA */
- wr32(hw, GLINT_DYN_CTL(pf->oicr_idx),
+ wr32(hw, GLINT_DYN_CTL(pf->hw_oicr_idx),
GLINT_DYN_CTL_SW_ITR_INDX_M | GLINT_DYN_CTL_INTENA_MSK_M);
}
@@ -1731,12 +1254,23 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data)
u32 oicr, ena_mask;
set_bit(__ICE_ADMINQ_EVENT_PENDING, pf->state);
+ set_bit(__ICE_MAILBOXQ_EVENT_PENDING, pf->state);
oicr = rd32(hw, PFINT_OICR);
ena_mask = rd32(hw, PFINT_OICR_ENA);
+ if (oicr & PFINT_OICR_MAL_DETECT_M) {
+ ena_mask &= ~PFINT_OICR_MAL_DETECT_M;
+ set_bit(__ICE_MDD_EVENT_PENDING, pf->state);
+ }
+ if (oicr & PFINT_OICR_VFLR_M) {
+ ena_mask &= ~PFINT_OICR_VFLR_M;
+ set_bit(__ICE_VFLR_EVENT_PENDING, pf->state);
+ }
+
if (oicr & PFINT_OICR_GRST_M) {
u32 reset;
+
/* we have a reset warning */
ena_mask &= ~PFINT_OICR_GRST_M;
reset = (rd32(hw, GLGEN_RSTAT) & GLGEN_RSTAT_RESET_TYPE_M) >>
@@ -1746,15 +1280,18 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data)
pf->corer_count++;
else if (reset == ICE_RESET_GLOBR)
pf->globr_count++;
- else
+ else if (reset == ICE_RESET_EMPR)
pf->empr_count++;
+ else
+ dev_dbg(&pf->pdev->dev, "Invalid reset type %d\n",
+ reset);
/* 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_bit(__ICE_RESET_RECOVERY_PENDING, pf->state)) {
+ if (!test_and_set_bit(__ICE_RESET_OICR_RECV, pf->state)) {
if (reset == ICE_RESET_CORER)
set_bit(__ICE_CORER_RECV, pf->state);
else if (reset == ICE_RESET_GLOBR)
@@ -1762,7 +1299,20 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data)
else
set_bit(__ICE_EMPR_RECV, pf->state);
- set_bit(__ICE_RESET_RECOVERY_PENDING, pf->state);
+ /* There are couple of different bits at play here.
+ * hw->reset_ongoing indicates whether the hardware is
+ * in reset. This is set to true when a reset interrupt
+ * is received and set back to false after the driver
+ * has determined that the hardware is out of reset.
+ *
+ * __ICE_RESET_OICR_RECV in pf->state indicates
+ * that a post reset rebuild is required before the
+ * driver is operational again. This is set above.
+ *
+ * As this is the start of the reset/rebuild cycle, set
+ * both to indicate that.
+ */
+ hw->reset_ongoing = true;
}
}
@@ -1803,208 +1353,6 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data)
}
/**
- * ice_vsi_map_rings_to_vectors - Map VSI rings to interrupt vectors
- * @vsi: the VSI being configured
- *
- * This function maps descriptor rings to the queue-specific vectors allotted
- * through the MSI-X enabling code. On a constrained vector budget, we map Tx
- * and Rx rings to the vector as "efficiently" as possible.
- */
-static void ice_vsi_map_rings_to_vectors(struct ice_vsi *vsi)
-{
- int q_vectors = vsi->num_q_vectors;
- int tx_rings_rem, rx_rings_rem;
- int v_id;
-
- /* initially assigning remaining rings count to VSIs num queue value */
- tx_rings_rem = vsi->num_txq;
- rx_rings_rem = vsi->num_rxq;
-
- for (v_id = 0; v_id < q_vectors; v_id++) {
- struct ice_q_vector *q_vector = vsi->q_vectors[v_id];
- int tx_rings_per_v, rx_rings_per_v, q_id, q_base;
-
- /* Tx rings mapping to vector */
- tx_rings_per_v = DIV_ROUND_UP(tx_rings_rem, q_vectors - v_id);
- q_vector->num_ring_tx = tx_rings_per_v;
- q_vector->tx.ring = NULL;
- q_base = vsi->num_txq - tx_rings_rem;
-
- for (q_id = q_base; q_id < (q_base + tx_rings_per_v); q_id++) {
- struct ice_ring *tx_ring = vsi->tx_rings[q_id];
-
- tx_ring->q_vector = q_vector;
- tx_ring->next = q_vector->tx.ring;
- q_vector->tx.ring = tx_ring;
- }
- tx_rings_rem -= tx_rings_per_v;
-
- /* Rx rings mapping to vector */
- rx_rings_per_v = DIV_ROUND_UP(rx_rings_rem, q_vectors - v_id);
- q_vector->num_ring_rx = rx_rings_per_v;
- q_vector->rx.ring = NULL;
- q_base = vsi->num_rxq - rx_rings_rem;
-
- for (q_id = q_base; q_id < (q_base + rx_rings_per_v); q_id++) {
- struct ice_ring *rx_ring = vsi->rx_rings[q_id];
-
- rx_ring->q_vector = q_vector;
- rx_ring->next = q_vector->rx.ring;
- q_vector->rx.ring = rx_ring;
- }
- rx_rings_rem -= rx_rings_per_v;
- }
-}
-
-/**
- * ice_vsi_set_num_qs - Set num queues, descriptors and vectors for a VSI
- * @vsi: the VSI being configured
- *
- * Return 0 on success and a negative value on error
- */
-static void ice_vsi_set_num_qs(struct ice_vsi *vsi)
-{
- struct ice_pf *pf = vsi->back;
-
- switch (vsi->type) {
- case ICE_VSI_PF:
- vsi->alloc_txq = pf->num_lan_tx;
- vsi->alloc_rxq = pf->num_lan_rx;
- vsi->num_desc = ALIGN(ICE_DFLT_NUM_DESC, ICE_REQ_DESC_MULTIPLE);
- vsi->num_q_vectors = max_t(int, pf->num_lan_rx, pf->num_lan_tx);
- break;
- default:
- dev_warn(&vsi->back->pdev->dev, "Unknown VSI type %d\n",
- vsi->type);
- break;
- }
-}
-
-/**
- * ice_vsi_alloc_arrays - Allocate queue and vector pointer arrays for the vsi
- * @vsi: VSI pointer
- * @alloc_qvectors: a bool to specify if q_vectors need to be allocated.
- *
- * On error: returns error code (negative)
- * On success: returns 0
- */
-static int ice_vsi_alloc_arrays(struct ice_vsi *vsi, bool alloc_qvectors)
-{
- struct ice_pf *pf = vsi->back;
-
- /* allocate memory for both Tx and Rx ring pointers */
- vsi->tx_rings = devm_kcalloc(&pf->pdev->dev, vsi->alloc_txq,
- sizeof(struct ice_ring *), GFP_KERNEL);
- if (!vsi->tx_rings)
- goto err_txrings;
-
- vsi->rx_rings = devm_kcalloc(&pf->pdev->dev, vsi->alloc_rxq,
- sizeof(struct ice_ring *), GFP_KERNEL);
- if (!vsi->rx_rings)
- goto err_rxrings;
-
- if (alloc_qvectors) {
- /* allocate memory for q_vector pointers */
- vsi->q_vectors = devm_kcalloc(&pf->pdev->dev,
- vsi->num_q_vectors,
- sizeof(struct ice_q_vector *),
- GFP_KERNEL);
- if (!vsi->q_vectors)
- goto err_vectors;
- }
-
- return 0;
-
-err_vectors:
- devm_kfree(&pf->pdev->dev, vsi->rx_rings);
-err_rxrings:
- devm_kfree(&pf->pdev->dev, vsi->tx_rings);
-err_txrings:
- return -ENOMEM;
-}
-
-/**
- * ice_msix_clean_rings - MSIX mode Interrupt Handler
- * @irq: interrupt number
- * @data: pointer to a q_vector
- */
-static irqreturn_t ice_msix_clean_rings(int __always_unused irq, void *data)
-{
- struct ice_q_vector *q_vector = (struct ice_q_vector *)data;
-
- if (!q_vector->tx.ring && !q_vector->rx.ring)
- return IRQ_HANDLED;
-
- napi_schedule(&q_vector->napi);
-
- return IRQ_HANDLED;
-}
-
-/**
- * ice_vsi_alloc - Allocates the next available struct vsi in the PF
- * @pf: board private structure
- * @type: type of VSI
- *
- * returns a pointer to a VSI on success, NULL on failure.
- */
-static struct ice_vsi *ice_vsi_alloc(struct ice_pf *pf, enum ice_vsi_type type)
-{
- struct ice_vsi *vsi = NULL;
-
- /* Need to protect the allocation of the VSIs at the PF level */
- mutex_lock(&pf->sw_mutex);
-
- /* If we have already allocated our maximum number of VSIs,
- * pf->next_vsi will be ICE_NO_VSI. If not, pf->next_vsi index
- * is available to be populated
- */
- if (pf->next_vsi == ICE_NO_VSI) {
- dev_dbg(&pf->pdev->dev, "out of VSI slots!\n");
- goto unlock_pf;
- }
-
- vsi = devm_kzalloc(&pf->pdev->dev, sizeof(*vsi), GFP_KERNEL);
- if (!vsi)
- goto unlock_pf;
-
- vsi->type = type;
- vsi->back = pf;
- set_bit(__ICE_DOWN, vsi->state);
- vsi->idx = pf->next_vsi;
- vsi->work_lmt = ICE_DFLT_IRQ_WORK;
-
- ice_vsi_set_num_qs(vsi);
-
- switch (vsi->type) {
- case ICE_VSI_PF:
- if (ice_vsi_alloc_arrays(vsi, true))
- goto err_rings;
-
- /* Setup default MSIX irq handler for VSI */
- vsi->irq_handler = ice_msix_clean_rings;
- break;
- default:
- dev_warn(&pf->pdev->dev, "Unknown VSI type %d\n", vsi->type);
- goto unlock_pf;
- }
-
- /* fill VSI slot in the PF struct */
- pf->vsi[pf->next_vsi] = vsi;
-
- /* prepare pf->next_vsi for next use */
- pf->next_vsi = ice_get_free_slot(pf->vsi, pf->num_alloc_vsi,
- pf->next_vsi);
- goto unlock_pf;
-
-err_rings:
- devm_kfree(&pf->pdev->dev, vsi);
- vsi = NULL;
-unlock_pf:
- mutex_unlock(&pf->sw_mutex);
- return vsi;
-}
-
-/**
* ice_free_irq_msix_misc - Unroll misc vector setup
* @pf: board private structure
*/
@@ -2015,12 +1363,15 @@ static void ice_free_irq_msix_misc(struct ice_pf *pf)
ice_flush(&pf->hw);
if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags) && pf->msix_entries) {
- synchronize_irq(pf->msix_entries[pf->oicr_idx].vector);
+ synchronize_irq(pf->msix_entries[pf->sw_oicr_idx].vector);
devm_free_irq(&pf->pdev->dev,
- pf->msix_entries[pf->oicr_idx].vector, pf);
+ pf->msix_entries[pf->sw_oicr_idx].vector, pf);
}
- ice_free_res(pf->irq_tracker, pf->oicr_idx, ICE_RES_MISC_VEC_ID);
+ pf->num_avail_sw_msix += 1;
+ ice_free_res(pf->sw_irq_tracker, pf->sw_oicr_idx, ICE_RES_MISC_VEC_ID);
+ pf->num_avail_hw_msix += 1;
+ ice_free_res(pf->hw_irq_tracker, pf->hw_oicr_idx, ICE_RES_MISC_VEC_ID);
}
/**
@@ -2047,42 +1398,61 @@ static int ice_req_irq_msix_misc(struct ice_pf *pf)
* lost during reset. Note that this function is called only during
* rebuild path and not while reset is in progress.
*/
- if (ice_is_reset_recovery_pending(pf->state))
+ if (ice_is_reset_in_progress(pf->state))
goto skip_req_irq;
- /* reserve one vector in irq_tracker for misc interrupts */
- oicr_idx = ice_get_res(pf, pf->irq_tracker, 1, ICE_RES_MISC_VEC_ID);
+ /* reserve one vector in sw_irq_tracker for misc interrupts */
+ oicr_idx = ice_get_res(pf, pf->sw_irq_tracker, 1, ICE_RES_MISC_VEC_ID);
if (oicr_idx < 0)
return oicr_idx;
- pf->oicr_idx = oicr_idx;
+ pf->num_avail_sw_msix -= 1;
+ pf->sw_oicr_idx = oicr_idx;
+
+ /* reserve one vector in hw_irq_tracker for misc interrupts */
+ oicr_idx = ice_get_res(pf, pf->hw_irq_tracker, 1, ICE_RES_MISC_VEC_ID);
+ if (oicr_idx < 0) {
+ ice_free_res(pf->sw_irq_tracker, 1, ICE_RES_MISC_VEC_ID);
+ pf->num_avail_sw_msix += 1;
+ return oicr_idx;
+ }
+ pf->num_avail_hw_msix -= 1;
+ pf->hw_oicr_idx = oicr_idx;
err = devm_request_irq(&pf->pdev->dev,
- pf->msix_entries[pf->oicr_idx].vector,
+ pf->msix_entries[pf->sw_oicr_idx].vector,
ice_misc_intr, 0, pf->int_name, pf);
if (err) {
dev_err(&pf->pdev->dev,
"devm_request_irq for %s failed: %d\n",
pf->int_name, err);
- ice_free_res(pf->irq_tracker, 1, ICE_RES_MISC_VEC_ID);
+ ice_free_res(pf->sw_irq_tracker, 1, ICE_RES_MISC_VEC_ID);
+ pf->num_avail_sw_msix += 1;
+ ice_free_res(pf->hw_irq_tracker, 1, ICE_RES_MISC_VEC_ID);
+ pf->num_avail_hw_msix += 1;
return err;
}
skip_req_irq:
ice_ena_misc_vector(pf);
- val = ((pf->oicr_idx & PFINT_OICR_CTL_MSIX_INDX_M) |
+ val = ((pf->hw_oicr_idx & PFINT_OICR_CTL_MSIX_INDX_M) |
PFINT_OICR_CTL_CAUSE_ENA_M);
wr32(hw, PFINT_OICR_CTL, val);
/* This enables Admin queue Interrupt causes */
- val = ((pf->oicr_idx & PFINT_FW_CTL_MSIX_INDX_M) |
+ val = ((pf->hw_oicr_idx & PFINT_FW_CTL_MSIX_INDX_M) |
PFINT_FW_CTL_CAUSE_ENA_M);
wr32(hw, PFINT_FW_CTL, val);
- itr_gran = hw->itr_gran_200;
+ /* This enables Mailbox queue Interrupt causes */
+ val = ((pf->hw_oicr_idx & PFINT_MBX_CTL_MSIX_INDX_M) |
+ PFINT_MBX_CTL_CAUSE_ENA_M);
+ wr32(hw, PFINT_MBX_CTL, val);
- wr32(hw, GLINT_ITR(ICE_RX_ITR, pf->oicr_idx),
+ itr_gran = hw->itr_gran;
+
+ wr32(hw, GLINT_ITR(ICE_RX_ITR, pf->hw_oicr_idx),
ITR_TO_REG(ICE_ITR_8K, itr_gran));
ice_flush(hw);
@@ -2092,209 +1462,43 @@ skip_req_irq:
}
/**
- * ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
- * @vsi: the VSI getting queues
- *
- * Return 0 on success and a negative value on error
+ * ice_napi_del - Remove NAPI handler for the VSI
+ * @vsi: VSI for which NAPI handler is to be removed
*/
-static int ice_vsi_get_qs_contig(struct ice_vsi *vsi)
+void ice_napi_del(struct ice_vsi *vsi)
{
- struct ice_pf *pf = vsi->back;
- int offset, ret = 0;
-
- mutex_lock(&pf->avail_q_mutex);
- /* look for contiguous block of queues for tx */
- offset = bitmap_find_next_zero_area(pf->avail_txqs, ICE_MAX_TXQS,
- 0, vsi->alloc_txq, 0);
- if (offset < ICE_MAX_TXQS) {
- int i;
-
- bitmap_set(pf->avail_txqs, offset, vsi->alloc_txq);
- for (i = 0; i < vsi->alloc_txq; i++)
- vsi->txq_map[i] = i + offset;
- } else {
- ret = -ENOMEM;
- vsi->tx_mapping_mode = ICE_VSI_MAP_SCATTER;
- }
-
- /* look for contiguous block of queues for rx */
- offset = bitmap_find_next_zero_area(pf->avail_rxqs, ICE_MAX_RXQS,
- 0, vsi->alloc_rxq, 0);
- if (offset < ICE_MAX_RXQS) {
- int i;
-
- bitmap_set(pf->avail_rxqs, offset, vsi->alloc_rxq);
- for (i = 0; i < vsi->alloc_rxq; i++)
- vsi->rxq_map[i] = i + offset;
- } else {
- ret = -ENOMEM;
- vsi->rx_mapping_mode = ICE_VSI_MAP_SCATTER;
- }
- mutex_unlock(&pf->avail_q_mutex);
-
- return ret;
-}
-
-/**
- * ice_vsi_get_qs_scatter - Assign a scattered queues to VSI
- * @vsi: the VSI getting queues
- *
- * Return 0 on success and a negative value on error
- */
-static int ice_vsi_get_qs_scatter(struct ice_vsi *vsi)
-{
- struct ice_pf *pf = vsi->back;
- int i, index = 0;
-
- mutex_lock(&pf->avail_q_mutex);
-
- if (vsi->tx_mapping_mode == ICE_VSI_MAP_SCATTER) {
- for (i = 0; i < vsi->alloc_txq; i++) {
- index = find_next_zero_bit(pf->avail_txqs,
- ICE_MAX_TXQS, index);
- if (index < ICE_MAX_TXQS) {
- set_bit(index, pf->avail_txqs);
- vsi->txq_map[i] = index;
- } else {
- goto err_scatter_tx;
- }
- }
- }
-
- if (vsi->rx_mapping_mode == ICE_VSI_MAP_SCATTER) {
- for (i = 0; i < vsi->alloc_rxq; i++) {
- index = find_next_zero_bit(pf->avail_rxqs,
- ICE_MAX_RXQS, index);
- if (index < ICE_MAX_RXQS) {
- set_bit(index, pf->avail_rxqs);
- vsi->rxq_map[i] = index;
- } else {
- goto err_scatter_rx;
- }
- }
- }
-
- mutex_unlock(&pf->avail_q_mutex);
- return 0;
+ int v_idx;
-err_scatter_rx:
- /* unflag any queues we have grabbed (i is failed position) */
- for (index = 0; index < i; index++) {
- clear_bit(vsi->rxq_map[index], pf->avail_rxqs);
- vsi->rxq_map[index] = 0;
- }
- i = vsi->alloc_txq;
-err_scatter_tx:
- /* i is either position of failed attempt or vsi->alloc_txq */
- for (index = 0; index < i; index++) {
- clear_bit(vsi->txq_map[index], pf->avail_txqs);
- vsi->txq_map[index] = 0;
- }
+ if (!vsi->netdev)
+ return;
- mutex_unlock(&pf->avail_q_mutex);
- return -ENOMEM;
+ for (v_idx = 0; v_idx < vsi->num_q_vectors; v_idx++)
+ netif_napi_del(&vsi->q_vectors[v_idx]->napi);
}
/**
- * ice_vsi_get_qs - Assign queues from PF to VSI
- * @vsi: the VSI to assign queues to
+ * ice_napi_add - register NAPI handler for the VSI
+ * @vsi: VSI for which NAPI handler is to be registered
*
- * Returns 0 on success and a negative value on error
+ * This function is only called in the driver's load path. Registering the NAPI
+ * handler is done in ice_vsi_alloc_q_vector() for all other cases (i.e. resume,
+ * reset/rebuild, etc.)
*/
-static int ice_vsi_get_qs(struct ice_vsi *vsi)
+static void ice_napi_add(struct ice_vsi *vsi)
{
- int ret = 0;
-
- vsi->tx_mapping_mode = ICE_VSI_MAP_CONTIG;
- vsi->rx_mapping_mode = ICE_VSI_MAP_CONTIG;
-
- /* NOTE: ice_vsi_get_qs_contig() will set the rx/tx mapping
- * modes individually to scatter if assigning contiguous queues
- * to rx or tx fails
- */
- ret = ice_vsi_get_qs_contig(vsi);
- if (ret < 0) {
- if (vsi->tx_mapping_mode == ICE_VSI_MAP_SCATTER)
- vsi->alloc_txq = max_t(u16, vsi->alloc_txq,
- ICE_MAX_SCATTER_TXQS);
- if (vsi->rx_mapping_mode == ICE_VSI_MAP_SCATTER)
- vsi->alloc_rxq = max_t(u16, vsi->alloc_rxq,
- ICE_MAX_SCATTER_RXQS);
- ret = ice_vsi_get_qs_scatter(vsi);
- }
-
- return ret;
-}
-
-/**
- * ice_vsi_put_qs - Release queues from VSI to PF
- * @vsi: the VSI thats going to release queues
- */
-static void ice_vsi_put_qs(struct ice_vsi *vsi)
-{
- struct ice_pf *pf = vsi->back;
- int i;
-
- mutex_lock(&pf->avail_q_mutex);
-
- for (i = 0; i < vsi->alloc_txq; i++) {
- clear_bit(vsi->txq_map[i], pf->avail_txqs);
- vsi->txq_map[i] = ICE_INVAL_Q_INDEX;
- }
-
- for (i = 0; i < vsi->alloc_rxq; i++) {
- clear_bit(vsi->rxq_map[i], pf->avail_rxqs);
- vsi->rxq_map[i] = ICE_INVAL_Q_INDEX;
- }
-
- mutex_unlock(&pf->avail_q_mutex);
-}
-
-/**
- * ice_free_q_vector - Free memory allocated for a specific interrupt vector
- * @vsi: VSI having the memory freed
- * @v_idx: index of the vector to be freed
- */
-static void ice_free_q_vector(struct ice_vsi *vsi, int v_idx)
-{
- struct ice_q_vector *q_vector;
- struct ice_ring *ring;
+ int v_idx;
- if (!vsi->q_vectors[v_idx]) {
- dev_dbg(&vsi->back->pdev->dev, "Queue vector at index %d not found\n",
- v_idx);
+ if (!vsi->netdev)
return;
- }
- q_vector = vsi->q_vectors[v_idx];
-
- ice_for_each_ring(ring, q_vector->tx)
- ring->q_vector = NULL;
- ice_for_each_ring(ring, q_vector->rx)
- ring->q_vector = NULL;
-
- /* only VSI with an associated netdev is set up with NAPI */
- if (vsi->netdev)
- netif_napi_del(&q_vector->napi);
-
- devm_kfree(&vsi->back->pdev->dev, q_vector);
- vsi->q_vectors[v_idx] = NULL;
-}
-
-/**
- * ice_vsi_free_q_vectors - Free memory allocated for interrupt vectors
- * @vsi: the VSI having memory freed
- */
-static void ice_vsi_free_q_vectors(struct ice_vsi *vsi)
-{
- int v_idx;
for (v_idx = 0; v_idx < vsi->num_q_vectors; v_idx++)
- ice_free_q_vector(vsi, v_idx);
+ netif_napi_add(vsi->netdev, &vsi->q_vectors[v_idx]->napi,
+ ice_napi_poll, NAPI_POLL_WEIGHT);
}
/**
- * ice_cfg_netdev - Setup the netdev flags
- * @vsi: the VSI being configured
+ * ice_cfg_netdev - Allocate, configure and register a netdev
+ * @vsi: the VSI associated with the new netdev
*
* Returns 0 on success, negative value on failure
*/
@@ -2307,6 +1511,7 @@ static int ice_cfg_netdev(struct ice_vsi *vsi)
struct ice_netdev_priv *np;
struct net_device *netdev;
u8 mac_addr[ETH_ALEN];
+ int err;
netdev = alloc_etherdev_mqs(sizeof(struct ice_netdev_priv),
vsi->alloc_txq, vsi->alloc_rxq);
@@ -2364,195 +1569,14 @@ static int ice_cfg_netdev(struct ice_vsi *vsi)
netdev->min_mtu = ETH_MIN_MTU;
netdev->max_mtu = ICE_MAX_MTU;
- return 0;
-}
-
-/**
- * ice_vsi_free_arrays - clean up vsi resources
- * @vsi: pointer to VSI being cleared
- * @free_qvectors: bool to specify if q_vectors should be deallocated
- */
-static void ice_vsi_free_arrays(struct ice_vsi *vsi, bool free_qvectors)
-{
- struct ice_pf *pf = vsi->back;
-
- /* free the ring and vector containers */
- if (free_qvectors && vsi->q_vectors) {
- devm_kfree(&pf->pdev->dev, vsi->q_vectors);
- vsi->q_vectors = NULL;
- }
- if (vsi->tx_rings) {
- devm_kfree(&pf->pdev->dev, vsi->tx_rings);
- vsi->tx_rings = NULL;
- }
- if (vsi->rx_rings) {
- devm_kfree(&pf->pdev->dev, vsi->rx_rings);
- vsi->rx_rings = NULL;
- }
-}
-
-/**
- * ice_vsi_clear - clean up and deallocate the provided vsi
- * @vsi: pointer to VSI being cleared
- *
- * This deallocates the vsi's queue resources, removes it from the PF's
- * VSI array if necessary, and deallocates the VSI
- *
- * Returns 0 on success, negative on failure
- */
-static int ice_vsi_clear(struct ice_vsi *vsi)
-{
- struct ice_pf *pf = NULL;
-
- if (!vsi)
- return 0;
-
- if (!vsi->back)
- return -EINVAL;
-
- pf = vsi->back;
-
- if (!pf->vsi[vsi->idx] || pf->vsi[vsi->idx] != vsi) {
- dev_dbg(&pf->pdev->dev, "vsi does not exist at pf->vsi[%d]\n",
- vsi->idx);
- return -EINVAL;
- }
-
- mutex_lock(&pf->sw_mutex);
- /* updates the PF for this cleared vsi */
-
- pf->vsi[vsi->idx] = NULL;
- if (vsi->idx < pf->next_vsi)
- pf->next_vsi = vsi->idx;
-
- ice_vsi_free_arrays(vsi, true);
- mutex_unlock(&pf->sw_mutex);
- devm_kfree(&pf->pdev->dev, vsi);
-
- return 0;
-}
-
-/**
- * ice_vsi_alloc_q_vector - Allocate memory for a single interrupt vector
- * @vsi: the VSI being configured
- * @v_idx: index of the vector in the vsi struct
- *
- * We allocate one q_vector. If allocation fails we return -ENOMEM.
- */
-static int ice_vsi_alloc_q_vector(struct ice_vsi *vsi, int v_idx)
-{
- struct ice_pf *pf = vsi->back;
- struct ice_q_vector *q_vector;
-
- /* allocate q_vector */
- q_vector = devm_kzalloc(&pf->pdev->dev, sizeof(*q_vector), GFP_KERNEL);
- if (!q_vector)
- return -ENOMEM;
-
- q_vector->vsi = vsi;
- q_vector->v_idx = v_idx;
- /* only set affinity_mask if the CPU is online */
- if (cpu_online(v_idx))
- cpumask_set_cpu(v_idx, &q_vector->affinity_mask);
-
- if (vsi->netdev)
- netif_napi_add(vsi->netdev, &q_vector->napi, ice_napi_poll,
- NAPI_POLL_WEIGHT);
- /* tie q_vector and vsi together */
- vsi->q_vectors[v_idx] = q_vector;
-
- return 0;
-}
-
-/**
- * ice_vsi_alloc_q_vectors - Allocate memory for interrupt vectors
- * @vsi: the VSI being configured
- *
- * We allocate one q_vector per queue interrupt. If allocation fails we
- * return -ENOMEM.
- */
-static int ice_vsi_alloc_q_vectors(struct ice_vsi *vsi)
-{
- struct ice_pf *pf = vsi->back;
- int v_idx = 0, num_q_vectors;
- int err;
-
- if (vsi->q_vectors[0]) {
- dev_dbg(&pf->pdev->dev, "VSI %d has existing q_vectors\n",
- vsi->vsi_num);
- return -EEXIST;
- }
-
- if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) {
- num_q_vectors = vsi->num_q_vectors;
- } else {
- err = -EINVAL;
- goto err_out;
- }
-
- for (v_idx = 0; v_idx < num_q_vectors; v_idx++) {
- err = ice_vsi_alloc_q_vector(vsi, v_idx);
- if (err)
- goto err_out;
- }
-
- return 0;
-
-err_out:
- while (v_idx--)
- ice_free_q_vector(vsi, v_idx);
-
- dev_err(&pf->pdev->dev,
- "Failed to allocate %d q_vector for VSI %d, ret=%d\n",
- vsi->num_q_vectors, vsi->vsi_num, err);
- vsi->num_q_vectors = 0;
- return err;
-}
-
-/**
- * ice_vsi_setup_vector_base - Set up the base vector for the given VSI
- * @vsi: ptr to the VSI
- *
- * This should only be called after ice_vsi_alloc() which allocates the
- * corresponding SW VSI structure and initializes num_queue_pairs for the
- * newly allocated VSI.
- *
- * Returns 0 on success or negative on failure
- */
-static int ice_vsi_setup_vector_base(struct ice_vsi *vsi)
-{
- struct ice_pf *pf = vsi->back;
- int num_q_vectors = 0;
-
- if (vsi->base_vector) {
- dev_dbg(&pf->pdev->dev, "VSI %d has non-zero base vector %d\n",
- vsi->vsi_num, vsi->base_vector);
- return -EEXIST;
- }
-
- if (!test_bit(ICE_FLAG_MSIX_ENA, pf->flags))
- return -ENOENT;
-
- switch (vsi->type) {
- case ICE_VSI_PF:
- num_q_vectors = vsi->num_q_vectors;
- break;
- default:
- dev_warn(&vsi->back->pdev->dev, "Unknown VSI type %d\n",
- vsi->type);
- break;
- }
+ err = register_netdev(vsi->netdev);
+ if (err)
+ return err;
- if (num_q_vectors)
- vsi->base_vector = ice_get_res(pf, pf->irq_tracker,
- num_q_vectors, vsi->idx);
+ netif_carrier_off(vsi->netdev);
- if (vsi->base_vector < 0) {
- dev_err(&pf->pdev->dev,
- "Failed to get tracking for %d vectors for VSI %d, err=%d\n",
- num_q_vectors, vsi->vsi_num, vsi->base_vector);
- return -ENOENT;
- }
+ /* make sure transmit queues start off as stopped */
+ netif_tx_stop_all_queues(vsi->netdev);
return 0;
}
@@ -2572,327 +1596,17 @@ void ice_fill_rss_lut(u8 *lut, u16 rss_table_size, u16 rss_size)
}
/**
- * ice_vsi_cfg_rss - Configure RSS params for a VSI
- * @vsi: VSI to be configured
- */
-static int ice_vsi_cfg_rss(struct ice_vsi *vsi)
-{
- u8 seed[ICE_AQC_GET_SET_RSS_KEY_DATA_RSS_KEY_SIZE];
- struct ice_aqc_get_set_rss_keys *key;
- struct ice_pf *pf = vsi->back;
- enum ice_status status;
- int err = 0;
- u8 *lut;
-
- vsi->rss_size = min_t(int, vsi->rss_size, vsi->num_rxq);
-
- lut = devm_kzalloc(&pf->pdev->dev, vsi->rss_table_size, GFP_KERNEL);
- if (!lut)
- return -ENOMEM;
-
- if (vsi->rss_lut_user)
- memcpy(lut, vsi->rss_lut_user, vsi->rss_table_size);
- else
- ice_fill_rss_lut(lut, vsi->rss_table_size, vsi->rss_size);
-
- status = ice_aq_set_rss_lut(&pf->hw, vsi->vsi_num, vsi->rss_lut_type,
- lut, vsi->rss_table_size);
-
- if (status) {
- dev_err(&vsi->back->pdev->dev,
- "set_rss_lut failed, error %d\n", status);
- err = -EIO;
- goto ice_vsi_cfg_rss_exit;
- }
-
- key = devm_kzalloc(&vsi->back->pdev->dev, sizeof(*key), GFP_KERNEL);
- if (!key) {
- err = -ENOMEM;
- goto ice_vsi_cfg_rss_exit;
- }
-
- if (vsi->rss_hkey_user)
- memcpy(seed, vsi->rss_hkey_user,
- ICE_AQC_GET_SET_RSS_KEY_DATA_RSS_KEY_SIZE);
- else
- netdev_rss_key_fill((void *)seed,
- ICE_AQC_GET_SET_RSS_KEY_DATA_RSS_KEY_SIZE);
- memcpy(&key->standard_rss_key, seed,
- ICE_AQC_GET_SET_RSS_KEY_DATA_RSS_KEY_SIZE);
-
- status = ice_aq_set_rss_key(&pf->hw, vsi->vsi_num, key);
-
- if (status) {
- dev_err(&vsi->back->pdev->dev, "set_rss_key failed, error %d\n",
- status);
- err = -EIO;
- }
-
- devm_kfree(&pf->pdev->dev, key);
-ice_vsi_cfg_rss_exit:
- devm_kfree(&pf->pdev->dev, lut);
- return err;
-}
-
-/**
- * ice_vsi_reinit_setup - return resource and reallocate resource for a VSI
- * @vsi: pointer to the ice_vsi
- *
- * This reallocates the VSIs queue resources
- *
- * Returns 0 on success and negative value on failure
- */
-static int ice_vsi_reinit_setup(struct ice_vsi *vsi)
-{
- u16 max_txqs[ICE_MAX_TRAFFIC_CLASS] = { 0 };
- int ret, i;
-
- if (!vsi)
- return -EINVAL;
-
- ice_vsi_free_q_vectors(vsi);
- ice_free_res(vsi->back->irq_tracker, vsi->base_vector, vsi->idx);
- vsi->base_vector = 0;
- ice_vsi_clear_rings(vsi);
- ice_vsi_free_arrays(vsi, false);
- ice_vsi_set_num_qs(vsi);
-
- /* Initialize VSI struct elements and create VSI in FW */
- ret = ice_vsi_add(vsi);
- if (ret < 0)
- goto err_vsi;
-
- ret = ice_vsi_alloc_arrays(vsi, false);
- if (ret < 0)
- goto err_vsi;
-
- switch (vsi->type) {
- case ICE_VSI_PF:
- if (!vsi->netdev) {
- ret = ice_cfg_netdev(vsi);
- if (ret)
- goto err_rings;
-
- ret = register_netdev(vsi->netdev);
- if (ret)
- goto err_rings;
-
- netif_carrier_off(vsi->netdev);
- netif_tx_stop_all_queues(vsi->netdev);
- }
-
- ret = ice_vsi_alloc_q_vectors(vsi);
- if (ret)
- goto err_rings;
-
- ret = ice_vsi_setup_vector_base(vsi);
- if (ret)
- goto err_vectors;
-
- ret = ice_vsi_alloc_rings(vsi);
- if (ret)
- goto err_vectors;
-
- ice_vsi_map_rings_to_vectors(vsi);
- break;
- default:
- break;
- }
-
- ice_vsi_set_tc_cfg(vsi);
-
- /* configure VSI nodes based on number of queues and TC's */
- for (i = 0; i < vsi->tc_cfg.numtc; i++)
- max_txqs[i] = vsi->num_txq;
-
- ret = ice_cfg_vsi_lan(vsi->port_info, vsi->vsi_num,
- vsi->tc_cfg.ena_tc, max_txqs);
- if (ret) {
- dev_info(&vsi->back->pdev->dev,
- "Failed VSI lan queue config\n");
- goto err_vectors;
- }
- return 0;
-
-err_vectors:
- ice_vsi_free_q_vectors(vsi);
-err_rings:
- if (vsi->netdev) {
- vsi->current_netdev_flags = 0;
- unregister_netdev(vsi->netdev);
- free_netdev(vsi->netdev);
- vsi->netdev = NULL;
- }
-err_vsi:
- ice_vsi_clear(vsi);
- set_bit(__ICE_RESET_FAILED, vsi->back->state);
- return ret;
-}
-
-/**
- * ice_vsi_setup - Set up a VSI by a given type
+ * ice_pf_vsi_setup - Set up a PF VSI
* @pf: board private structure
- * @type: VSI type
* @pi: pointer to the port_info instance
*
- * This allocates the sw VSI structure and its queue resources.
- *
- * Returns pointer to the successfully allocated and configure VSI sw struct on
- * success, otherwise returns NULL on failure.
+ * Returns pointer to the successfully allocated VSI sw struct on success,
+ * otherwise returns NULL on failure.
*/
static struct ice_vsi *
-ice_vsi_setup(struct ice_pf *pf, enum ice_vsi_type type,
- struct ice_port_info *pi)
-{
- u16 max_txqs[ICE_MAX_TRAFFIC_CLASS] = { 0 };
- struct device *dev = &pf->pdev->dev;
- struct ice_vsi_ctx ctxt = { 0 };
- struct ice_vsi *vsi;
- int ret, i;
-
- vsi = ice_vsi_alloc(pf, type);
- if (!vsi) {
- dev_err(dev, "could not allocate VSI\n");
- return NULL;
- }
-
- vsi->port_info = pi;
- vsi->vsw = pf->first_sw;
-
- if (ice_vsi_get_qs(vsi)) {
- dev_err(dev, "Failed to allocate queues. vsi->idx = %d\n",
- vsi->idx);
- goto err_get_qs;
- }
-
- /* set RSS capabilities */
- ice_vsi_set_rss_params(vsi);
-
- /* create the VSI */
- ret = ice_vsi_add(vsi);
- if (ret)
- goto err_vsi;
-
- ctxt.vsi_num = vsi->vsi_num;
-
- switch (vsi->type) {
- case ICE_VSI_PF:
- ret = ice_cfg_netdev(vsi);
- if (ret)
- goto err_cfg_netdev;
-
- ret = register_netdev(vsi->netdev);
- if (ret)
- goto err_register_netdev;
-
- netif_carrier_off(vsi->netdev);
-
- /* make sure transmit queues start off as stopped */
- netif_tx_stop_all_queues(vsi->netdev);
- ret = ice_vsi_alloc_q_vectors(vsi);
- if (ret)
- goto err_msix;
-
- ret = ice_vsi_setup_vector_base(vsi);
- if (ret)
- goto err_rings;
-
- ret = ice_vsi_alloc_rings(vsi);
- if (ret)
- goto err_rings;
-
- ice_vsi_map_rings_to_vectors(vsi);
-
- /* Do not exit if configuring RSS had an issue, at least
- * receive traffic on first queue. Hence no need to capture
- * return value
- */
- if (test_bit(ICE_FLAG_RSS_ENA, pf->flags))
- ice_vsi_cfg_rss(vsi);
- break;
- default:
- /* if vsi type is not recognized, clean up the resources and
- * exit
- */
- goto err_rings;
- }
-
- ice_vsi_set_tc_cfg(vsi);
-
- /* configure VSI nodes based on number of queues and TC's */
- for (i = 0; i < vsi->tc_cfg.numtc; i++)
- max_txqs[i] = vsi->num_txq;
-
- ret = ice_cfg_vsi_lan(vsi->port_info, vsi->vsi_num,
- vsi->tc_cfg.ena_tc, max_txqs);
- if (ret) {
- dev_info(&pf->pdev->dev, "Failed VSI lan queue config\n");
- goto err_rings;
- }
-
- return vsi;
-
-err_rings:
- ice_vsi_free_q_vectors(vsi);
-err_msix:
- if (vsi->netdev && vsi->netdev->reg_state == NETREG_REGISTERED)
- unregister_netdev(vsi->netdev);
-err_register_netdev:
- if (vsi->netdev) {
- free_netdev(vsi->netdev);
- vsi->netdev = NULL;
- }
-err_cfg_netdev:
- ret = ice_aq_free_vsi(&pf->hw, &ctxt, false, NULL);
- if (ret)
- dev_err(&vsi->back->pdev->dev,
- "Free VSI AQ call failed, err %d\n", ret);
-err_vsi:
- ice_vsi_put_qs(vsi);
-err_get_qs:
- pf->q_left_tx += vsi->alloc_txq;
- pf->q_left_rx += vsi->alloc_rxq;
- ice_vsi_clear(vsi);
-
- return NULL;
-}
-
-/**
- * ice_vsi_add_vlan - Add vsi membership for given vlan
- * @vsi: the vsi being configured
- * @vid: vlan id to be added
- */
-static int ice_vsi_add_vlan(struct ice_vsi *vsi, u16 vid)
+ice_pf_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi)
{
- struct ice_fltr_list_entry *tmp;
- struct ice_pf *pf = vsi->back;
- LIST_HEAD(tmp_add_list);
- enum ice_status status;
- int err = 0;
-
- tmp = devm_kzalloc(&pf->pdev->dev, sizeof(*tmp), GFP_KERNEL);
- if (!tmp)
- return -ENOMEM;
-
- tmp->fltr_info.lkup_type = ICE_SW_LKUP_VLAN;
- tmp->fltr_info.fltr_act = ICE_FWD_TO_VSI;
- tmp->fltr_info.flag = ICE_FLTR_TX;
- tmp->fltr_info.src = vsi->vsi_num;
- tmp->fltr_info.fwd_id.vsi_id = vsi->vsi_num;
- tmp->fltr_info.l_data.vlan.vlan_id = vid;
-
- INIT_LIST_HEAD(&tmp->list_entry);
- list_add(&tmp->list_entry, &tmp_add_list);
-
- status = ice_add_vlan(&pf->hw, &tmp_add_list);
- if (status) {
- err = -ENODEV;
- dev_err(&pf->pdev->dev, "Failure Adding VLAN %d on VSI %i\n",
- vid, vsi->vsi_num);
- }
-
- ice_free_fltr_list(&pf->pdev->dev, &tmp_add_list);
- return err;
+ return ice_vsi_setup(pf, pi, ICE_VSI_PF, ICE_INVAL_VFID);
}
/**
@@ -2908,7 +1622,6 @@ static int ice_vlan_rx_add_vid(struct net_device *netdev,
{
struct ice_netdev_priv *np = netdev_priv(netdev);
struct ice_vsi *vsi = np->vsi;
- int ret = 0;
if (vid >= VLAN_N_VID) {
netdev_err(netdev, "VLAN id requested %d is out of range %d\n",
@@ -2919,48 +1632,19 @@ static int ice_vlan_rx_add_vid(struct net_device *netdev,
if (vsi->info.pvid)
return -EINVAL;
+ /* Enable VLAN pruning when VLAN 0 is added */
+ if (unlikely(!vid)) {
+ int ret = ice_cfg_vlan_pruning(vsi, true);
+
+ if (ret)
+ return ret;
+ }
+
/* Add all VLAN ids including 0 to the switch filter. VLAN id 0 is
* needed to continue allowing all untagged packets since VLAN prune
* list is applied to all packets by the switch
*/
- ret = ice_vsi_add_vlan(vsi, vid);
-
- if (!ret)
- set_bit(vid, vsi->active_vlans);
-
- return ret;
-}
-
-/**
- * ice_vsi_kill_vlan - Remove VSI membership for a given VLAN
- * @vsi: the VSI being configured
- * @vid: VLAN id to be removed
- */
-static void ice_vsi_kill_vlan(struct ice_vsi *vsi, u16 vid)
-{
- struct ice_fltr_list_entry *list;
- struct ice_pf *pf = vsi->back;
- LIST_HEAD(tmp_add_list);
-
- list = devm_kzalloc(&pf->pdev->dev, sizeof(*list), GFP_KERNEL);
- if (!list)
- return;
-
- list->fltr_info.lkup_type = ICE_SW_LKUP_VLAN;
- list->fltr_info.fwd_id.vsi_id = vsi->vsi_num;
- list->fltr_info.fltr_act = ICE_FWD_TO_VSI;
- list->fltr_info.l_data.vlan.vlan_id = vid;
- list->fltr_info.flag = ICE_FLTR_TX;
- list->fltr_info.src = vsi->vsi_num;
-
- INIT_LIST_HEAD(&list->list_entry);
- list_add(&list->list_entry, &tmp_add_list);
-
- if (ice_remove_vlan(&pf->hw, &tmp_add_list))
- dev_err(&pf->pdev->dev, "Error removing VLAN %d on vsi %i\n",
- vid, vsi->vsi_num);
-
- ice_free_fltr_list(&pf->pdev->dev, &tmp_add_list);
+ return ice_vsi_add_vlan(vsi, vid);
}
/**
@@ -2976,19 +1660,23 @@ static int ice_vlan_rx_kill_vid(struct net_device *netdev,
{
struct ice_netdev_priv *np = netdev_priv(netdev);
struct ice_vsi *vsi = np->vsi;
+ int status;
if (vsi->info.pvid)
return -EINVAL;
- /* return code is ignored as there is nothing a user
- * can do about failure to remove and a log message was
- * already printed from the other function
+ /* Make sure ice_vsi_kill_vlan is successful before updating VLAN
+ * information
*/
- ice_vsi_kill_vlan(vsi, vid);
+ status = ice_vsi_kill_vlan(vsi, vid);
+ if (status)
+ return status;
- clear_bit(vid, vsi->active_vlans);
+ /* Disable VLAN pruning when VLAN 0 is removed */
+ if (unlikely(!vid))
+ status = ice_cfg_vlan_pruning(vsi, false);
- return 0;
+ return status;
}
/**
@@ -3004,59 +1692,73 @@ static int ice_setup_pf_sw(struct ice_pf *pf)
struct ice_vsi *vsi;
int status = 0;
- if (!ice_is_reset_recovery_pending(pf->state)) {
- vsi = ice_vsi_setup(pf, ICE_VSI_PF, pf->hw.port_info);
- if (!vsi) {
- status = -ENOMEM;
- goto error_exit;
- }
- } else {
- vsi = pf->vsi[0];
- status = ice_vsi_reinit_setup(vsi);
- if (status < 0)
- return -EIO;
+ if (ice_is_reset_in_progress(pf->state))
+ return -EBUSY;
+
+ vsi = ice_pf_vsi_setup(pf, pf->hw.port_info);
+ if (!vsi) {
+ status = -ENOMEM;
+ goto unroll_vsi_setup;
+ }
+
+ status = ice_cfg_netdev(vsi);
+ if (status) {
+ status = -ENODEV;
+ goto unroll_vsi_setup;
}
- /* tmp_add_list contains a list of MAC addresses for which MAC
- * filters need to be programmed. Add the VSI's unicast MAC to
- * this list
+ /* registering the NAPI handler requires both the queues and
+ * netdev to be created, which are done in ice_pf_vsi_setup()
+ * and ice_cfg_netdev() respectively
+ */
+ ice_napi_add(vsi);
+
+ /* To add a MAC filter, first add the MAC to a list and then
+ * pass the list to ice_add_mac.
*/
+
+ /* Add a unicast MAC filter so the VSI can get its packets */
status = ice_add_mac_to_list(vsi, &tmp_add_list,
vsi->port_info->mac.perm_addr);
if (status)
- goto error_exit;
+ goto unroll_napi_add;
/* VSI needs to receive broadcast traffic, so add the broadcast
- * MAC address to the list.
+ * MAC address to the list as well.
*/
eth_broadcast_addr(broadcast);
status = ice_add_mac_to_list(vsi, &tmp_add_list, broadcast);
if (status)
- goto error_exit;
+ goto free_mac_list;
/* program MAC filters for entries in tmp_add_list */
status = ice_add_mac(&pf->hw, &tmp_add_list);
if (status) {
dev_err(&pf->pdev->dev, "Could not add MAC filters\n");
status = -ENOMEM;
- goto error_exit;
+ goto free_mac_list;
}
ice_free_fltr_list(&pf->pdev->dev, &tmp_add_list);
return status;
-error_exit:
+free_mac_list:
ice_free_fltr_list(&pf->pdev->dev, &tmp_add_list);
+unroll_napi_add:
if (vsi) {
- ice_vsi_free_q_vectors(vsi);
- if (vsi->netdev && vsi->netdev->reg_state == NETREG_REGISTERED)
- unregister_netdev(vsi->netdev);
+ ice_napi_del(vsi);
if (vsi->netdev) {
+ if (vsi->netdev->reg_state == NETREG_REGISTERED)
+ unregister_netdev(vsi->netdev);
free_netdev(vsi->netdev);
vsi->netdev = NULL;
}
+ }
+unroll_vsi_setup:
+ if (vsi) {
+ ice_vsi_free_q_vectors(vsi);
ice_vsi_delete(vsi);
ice_vsi_put_qs(vsi);
pf->q_left_tx += vsi->alloc_txq;
@@ -3097,10 +1799,7 @@ static void ice_determine_q_usage(struct ice_pf *pf)
*/
static void ice_deinit_pf(struct ice_pf *pf)
{
- if (pf->serv_tmr.function)
- del_timer_sync(&pf->serv_tmr);
- if (pf->serv_task.func)
- cancel_work_sync(&pf->serv_task);
+ ice_service_task_stop(pf);
mutex_destroy(&pf->sw_mutex);
mutex_destroy(&pf->avail_q_mutex);
}
@@ -3113,6 +1812,15 @@ static void ice_init_pf(struct ice_pf *pf)
{
bitmap_zero(pf->flags, ICE_PF_FLAGS_NBITS);
set_bit(ICE_FLAG_MSIX_ENA, pf->flags);
+#ifdef CONFIG_PCI_IOV
+ if (pf->hw.func_caps.common_cap.sr_iov_1_1) {
+ struct ice_hw *hw = &pf->hw;
+
+ set_bit(ICE_FLAG_SRIOV_CAPABLE, pf->flags);
+ pf->num_vfs_supported = min_t(int, hw->func_caps.num_allocd_vfs,
+ ICE_MAX_VF_COUNT);
+ }
+#endif /* CONFIG_PCI_IOV */
mutex_init(&pf->sw_mutex);
mutex_init(&pf->avail_q_mutex);
@@ -3155,6 +1863,7 @@ static int ice_ena_msix_range(struct ice_pf *pf)
/* reserve vectors for LAN traffic */
pf->num_lan_msix = min_t(int, num_online_cpus(), v_left);
v_budget += pf->num_lan_msix;
+ v_left -= pf->num_lan_msix;
pf->msix_entries = devm_kcalloc(&pf->pdev->dev, v_budget,
sizeof(struct msix_entry), GFP_KERNEL);
@@ -3182,10 +1891,11 @@ static int ice_ena_msix_range(struct ice_pf *pf)
"not enough vectors. requested = %d, obtained = %d\n",
v_budget, v_actual);
if (v_actual >= (pf->num_lan_msix + 1)) {
- pf->num_avail_msix = v_actual - (pf->num_lan_msix + 1);
+ pf->num_avail_sw_msix = v_actual -
+ (pf->num_lan_msix + 1);
} else if (v_actual >= 2) {
pf->num_lan_msix = 1;
- pf->num_avail_msix = v_actual - 2;
+ pf->num_avail_sw_msix = v_actual - 2;
} else {
pci_disable_msix(pf->pdev);
err = -ERANGE;
@@ -3218,12 +1928,32 @@ static void ice_dis_msix(struct ice_pf *pf)
}
/**
+ * ice_clear_interrupt_scheme - Undo things done by ice_init_interrupt_scheme
+ * @pf: board private structure
+ */
+static void ice_clear_interrupt_scheme(struct ice_pf *pf)
+{
+ if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags))
+ ice_dis_msix(pf);
+
+ if (pf->sw_irq_tracker) {
+ devm_kfree(&pf->pdev->dev, pf->sw_irq_tracker);
+ pf->sw_irq_tracker = NULL;
+ }
+
+ if (pf->hw_irq_tracker) {
+ devm_kfree(&pf->pdev->dev, pf->hw_irq_tracker);
+ pf->hw_irq_tracker = NULL;
+ }
+}
+
+/**
* ice_init_interrupt_scheme - Determine proper interrupt scheme
* @pf: board private structure to initialize
*/
static int ice_init_interrupt_scheme(struct ice_pf *pf)
{
- int vectors = 0;
+ int vectors = 0, hw_vectors = 0;
ssize_t size;
if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags))
@@ -3237,30 +1967,47 @@ static int ice_init_interrupt_scheme(struct ice_pf *pf)
/* set up vector assignment tracking */
size = sizeof(struct ice_res_tracker) + (sizeof(u16) * vectors);
- pf->irq_tracker = devm_kzalloc(&pf->pdev->dev, size, GFP_KERNEL);
- if (!pf->irq_tracker) {
+ pf->sw_irq_tracker = devm_kzalloc(&pf->pdev->dev, size, GFP_KERNEL);
+ if (!pf->sw_irq_tracker) {
ice_dis_msix(pf);
return -ENOMEM;
}
- pf->irq_tracker->num_entries = vectors;
+ /* populate SW interrupts pool with number of OS granted IRQs. */
+ pf->num_avail_sw_msix = vectors;
+ pf->sw_irq_tracker->num_entries = vectors;
+
+ /* set up HW vector assignment tracking */
+ hw_vectors = pf->hw.func_caps.common_cap.num_msix_vectors;
+ size = sizeof(struct ice_res_tracker) + (sizeof(u16) * hw_vectors);
+
+ pf->hw_irq_tracker = devm_kzalloc(&pf->pdev->dev, size, GFP_KERNEL);
+ if (!pf->hw_irq_tracker) {
+ ice_clear_interrupt_scheme(pf);
+ return -ENOMEM;
+ }
+
+ /* populate HW interrupts pool with number of HW supported irqs. */
+ pf->num_avail_hw_msix = hw_vectors;
+ pf->hw_irq_tracker->num_entries = hw_vectors;
return 0;
}
/**
- * ice_clear_interrupt_scheme - Undo things done by ice_init_interrupt_scheme
- * @pf: board private structure
+ * ice_verify_cacheline_size - verify driver's assumption of 64 Byte cache lines
+ * @pf: pointer to the PF structure
+ *
+ * There is no error returned here because the driver should be able to handle
+ * 128 Byte cache lines, so we only print a warning in case issues are seen,
+ * specifically with Tx.
*/
-static void ice_clear_interrupt_scheme(struct ice_pf *pf)
+static void ice_verify_cacheline_size(struct ice_pf *pf)
{
- if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags))
- ice_dis_msix(pf);
-
- if (pf->irq_tracker) {
- devm_kfree(&pf->pdev->dev, pf->irq_tracker);
- pf->irq_tracker = NULL;
- }
+ if (rd32(&pf->hw, GLPCI_CNF2) & GLPCI_CNF2_CACHELINE_SIZE_M)
+ dev_warn(&pf->pdev->dev,
+ "%d Byte cache line assumption is invalid, driver may have Tx timeouts!\n",
+ ICE_CACHE_LINE_BYTES);
}
/**
@@ -3307,6 +2054,8 @@ static int ice_probe(struct pci_dev *pdev,
pf->pdev = pdev;
pci_set_drvdata(pdev, pf);
set_bit(__ICE_DOWN, pf->state);
+ /* Disable service task until DOWN bit is cleared */
+ set_bit(__ICE_SERVICE_DIS, pf->state);
hw = &pf->hw;
hw->hw_addr = pcim_iomap_table(pdev)[ICE_BAR0];
@@ -3364,6 +2113,9 @@ static int ice_probe(struct pci_dev *pdev,
goto err_init_interrupt_unroll;
}
+ /* Driver is mostly up */
+ clear_bit(__ICE_DOWN, pf->state);
+
/* In case of MSIX we are going to setup the misc vector right here
* to handle admin queue events etc. In case of legacy and MSI
* the misc functionality and queue processing is combined in
@@ -3386,7 +2138,11 @@ static int ice_probe(struct pci_dev *pdev,
goto err_msix_misc_unroll;
}
- pf->first_sw->bridge_mode = BRIDGE_MODE_VEB;
+ if (hw->evb_veb)
+ pf->first_sw->bridge_mode = BRIDGE_MODE_VEB;
+ else
+ pf->first_sw->bridge_mode = BRIDGE_MODE_VEPA;
+
pf->first_sw->pf = pf;
/* record the sw_id available for later use */
@@ -3399,21 +2155,17 @@ static int ice_probe(struct pci_dev *pdev,
goto err_alloc_sw_unroll;
}
- /* Driver is mostly up */
- clear_bit(__ICE_DOWN, pf->state);
+ clear_bit(__ICE_SERVICE_DIS, pf->state);
/* since everything is good, start the service timer */
mod_timer(&pf->serv_tmr, round_jiffies(jiffies + pf->serv_tmr_period));
- err = ice_init_link_events(pf->hw.port_info);
- if (err) {
- dev_err(&pdev->dev, "ice_init_link_events failed: %d\n", err);
- goto err_alloc_sw_unroll;
- }
+ ice_verify_cacheline_size(pf);
return 0;
err_alloc_sw_unroll:
+ set_bit(__ICE_SERVICE_DIS, pf->state);
set_bit(__ICE_DOWN, pf->state);
devm_kfree(&pf->pdev->dev, pf->first_sw);
err_msix_misc_unroll:
@@ -3436,25 +2188,29 @@ err_exit_unroll:
static void ice_remove(struct pci_dev *pdev)
{
struct ice_pf *pf = pci_get_drvdata(pdev);
- int i = 0;
- int err;
+ int i;
if (!pf)
return;
+ for (i = 0; i < ICE_MAX_RESET_WAIT; i++) {
+ if (!ice_is_reset_in_progress(pf->state))
+ break;
+ msleep(100);
+ }
+
set_bit(__ICE_DOWN, pf->state);
+ ice_service_task_stop(pf);
- for (i = 0; i < pf->num_alloc_vsi; i++) {
+ if (test_bit(ICE_FLAG_SRIOV_ENA, pf->flags))
+ ice_free_vfs(pf);
+ ice_vsi_release_all(pf);
+ ice_free_irq_msix_misc(pf);
+ ice_for_each_vsi(pf, i) {
if (!pf->vsi[i])
continue;
-
- err = ice_vsi_release(pf->vsi[i]);
- if (err)
- dev_dbg(&pf->pdev->dev, "Failed to release VSI index %d (err %d)\n",
- i, err);
+ ice_vsi_free_q_vectors(pf->vsi[i]);
}
-
- ice_free_irq_msix_misc(pf);
ice_clear_interrupt_scheme(pf);
ice_deinit_pf(pf);
ice_deinit_hw(&pf->hw);
@@ -3470,11 +2226,9 @@ static void ice_remove(struct pci_dev *pdev)
* Class, Class Mask, private data (not used) }
*/
static const struct pci_device_id ice_pci_tbl[] = {
- { PCI_VDEVICE(INTEL, ICE_DEV_ID_C810_BACKPLANE), 0 },
- { PCI_VDEVICE(INTEL, ICE_DEV_ID_C810_QSFP), 0 },
- { PCI_VDEVICE(INTEL, ICE_DEV_ID_C810_SFP), 0 },
- { PCI_VDEVICE(INTEL, ICE_DEV_ID_C810_10G_BASE_T), 0 },
- { PCI_VDEVICE(INTEL, ICE_DEV_ID_C810_SGMII), 0 },
+ { PCI_VDEVICE(INTEL, ICE_DEV_ID_E810C_BACKPLANE), 0 },
+ { PCI_VDEVICE(INTEL, ICE_DEV_ID_E810C_QSFP), 0 },
+ { PCI_VDEVICE(INTEL, ICE_DEV_ID_E810C_SFP), 0 },
/* required last entry */
{ 0, }
};
@@ -3485,6 +2239,7 @@ static struct pci_driver ice_driver = {
.id_table = ice_pci_tbl,
.probe = ice_probe,
.remove = ice_remove,
+ .sriov_configure = ice_sriov_configure,
};
/**
@@ -3500,7 +2255,7 @@ static int __init ice_module_init(void)
pr_info("%s - version %s\n", ice_driver_string, ice_drv_ver);
pr_info("%s\n", ice_copyright);
- ice_wq = alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, KBUILD_MODNAME);
+ ice_wq = alloc_workqueue("%s", WQ_MEM_RECLAIM, 0, KBUILD_MODNAME);
if (!ice_wq) {
pr_err("Failed to create workqueue\n");
return -ENOMEM;
@@ -3562,7 +2317,7 @@ static int ice_set_mac_address(struct net_device *netdev, void *pi)
}
if (test_bit(__ICE_DOWN, pf->state) ||
- ice_is_reset_recovery_pending(pf->state)) {
+ ice_is_reset_in_progress(pf->state)) {
netdev_err(netdev, "can't set mac %pM. device not ready\n",
mac);
return -EBUSY;
@@ -3722,78 +2477,6 @@ static int ice_fdb_del(struct ndmsg *ndm, __always_unused struct nlattr *tb[],
}
/**
- * ice_vsi_manage_vlan_insertion - Manage VLAN insertion for the VSI for Tx
- * @vsi: the vsi being changed
- */
-static int ice_vsi_manage_vlan_insertion(struct ice_vsi *vsi)
-{
- struct device *dev = &vsi->back->pdev->dev;
- struct ice_hw *hw = &vsi->back->hw;
- struct ice_vsi_ctx ctxt = { 0 };
- enum ice_status status;
-
- /* Here we are configuring the VSI to let the driver add VLAN tags by
- * setting vlan_flags to ICE_AQ_VSI_VLAN_MODE_ALL. The actual VLAN tag
- * insertion happens in the Tx hot path, in ice_tx_map.
- */
- ctxt.info.vlan_flags = ICE_AQ_VSI_VLAN_MODE_ALL;
-
- ctxt.info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID);
- ctxt.vsi_num = vsi->vsi_num;
-
- status = ice_aq_update_vsi(hw, &ctxt, NULL);
- if (status) {
- dev_err(dev, "update VSI for VLAN insert failed, err %d aq_err %d\n",
- status, hw->adminq.sq_last_status);
- return -EIO;
- }
-
- vsi->info.vlan_flags = ctxt.info.vlan_flags;
- return 0;
-}
-
-/**
- * ice_vsi_manage_vlan_stripping - Manage VLAN stripping for the VSI for Rx
- * @vsi: the vsi being changed
- * @ena: boolean value indicating if this is a enable or disable request
- */
-static int ice_vsi_manage_vlan_stripping(struct ice_vsi *vsi, bool ena)
-{
- struct device *dev = &vsi->back->pdev->dev;
- struct ice_hw *hw = &vsi->back->hw;
- struct ice_vsi_ctx ctxt = { 0 };
- enum ice_status status;
-
- /* Here we are configuring what the VSI should do with the VLAN tag in
- * the Rx packet. We can either leave the tag in the packet or put it in
- * the Rx descriptor.
- */
- if (ena) {
- /* Strip VLAN tag from Rx packet and put it in the desc */
- ctxt.info.vlan_flags = ICE_AQ_VSI_VLAN_EMOD_STR_BOTH;
- } else {
- /* Disable stripping. Leave tag in packet */
- ctxt.info.vlan_flags = ICE_AQ_VSI_VLAN_EMOD_NOTHING;
- }
-
- /* Allow all packets untagged/tagged */
- ctxt.info.vlan_flags |= ICE_AQ_VSI_VLAN_MODE_ALL;
-
- ctxt.info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID);
- ctxt.vsi_num = vsi->vsi_num;
-
- status = ice_aq_update_vsi(hw, &ctxt, NULL);
- if (status) {
- dev_err(dev, "update VSI for VALN strip failed, ena = %d err %d aq_err %d\n",
- ena, status, hw->adminq.sq_last_status);
- return -EIO;
- }
-
- vsi->info.vlan_flags = ctxt.info.vlan_flags;
- return 0;
-}
-
-/**
* ice_set_features - set the netdev feature flags
* @netdev: ptr to the netdev being adjusted
* @features: the feature set that the stack is suggesting
@@ -3805,6 +2488,12 @@ static int ice_set_features(struct net_device *netdev,
struct ice_vsi *vsi = np->vsi;
int ret = 0;
+ if (features & NETIF_F_RXHASH && !(netdev->features & NETIF_F_RXHASH))
+ ret = ice_vsi_manage_rss_lut(vsi, true);
+ else if (!(features & NETIF_F_RXHASH) &&
+ netdev->features & NETIF_F_RXHASH)
+ ret = ice_vsi_manage_rss_lut(vsi, false);
+
if ((features & NETIF_F_HW_VLAN_CTAG_RX) &&
!(netdev->features & NETIF_F_HW_VLAN_CTAG_RX))
ret = ice_vsi_manage_vlan_stripping(vsi, true);
@@ -3838,273 +2527,6 @@ static int ice_vsi_vlan_setup(struct ice_vsi *vsi)
}
/**
- * ice_restore_vlan - Reinstate VLANs when vsi/netdev comes back up
- * @vsi: the VSI being brought back up
- */
-static int ice_restore_vlan(struct ice_vsi *vsi)
-{
- int err;
- u16 vid;
-
- if (!vsi->netdev)
- return -EINVAL;
-
- err = ice_vsi_vlan_setup(vsi);
- if (err)
- return err;
-
- for_each_set_bit(vid, vsi->active_vlans, VLAN_N_VID) {
- err = ice_vlan_rx_add_vid(vsi->netdev, htons(ETH_P_8021Q), vid);
- if (err)
- break;
- }
-
- return err;
-}
-
-/**
- * ice_setup_tx_ctx - setup a struct ice_tlan_ctx instance
- * @ring: The Tx ring to configure
- * @tlan_ctx: Pointer to the Tx LAN queue context structure to be initialized
- * @pf_q: queue index in the PF space
- *
- * Configure the Tx descriptor ring in TLAN context.
- */
-static void
-ice_setup_tx_ctx(struct ice_ring *ring, struct ice_tlan_ctx *tlan_ctx, u16 pf_q)
-{
- struct ice_vsi *vsi = ring->vsi;
- struct ice_hw *hw = &vsi->back->hw;
-
- tlan_ctx->base = ring->dma >> ICE_TLAN_CTX_BASE_S;
-
- tlan_ctx->port_num = vsi->port_info->lport;
-
- /* Transmit Queue Length */
- tlan_ctx->qlen = ring->count;
-
- /* PF number */
- tlan_ctx->pf_num = hw->pf_id;
-
- /* queue belongs to a specific VSI type
- * VF / VM index should be programmed per vmvf_type setting:
- * for vmvf_type = VF, it is VF number between 0-256
- * for vmvf_type = VM, it is VM number between 0-767
- * for PF or EMP this field should be set to zero
- */
- switch (vsi->type) {
- case ICE_VSI_PF:
- tlan_ctx->vmvf_type = ICE_TLAN_CTX_VMVF_TYPE_PF;
- break;
- default:
- return;
- }
-
- /* make sure the context is associated with the right VSI */
- tlan_ctx->src_vsi = vsi->vsi_num;
-
- tlan_ctx->tso_ena = ICE_TX_LEGACY;
- tlan_ctx->tso_qnum = pf_q;
-
- /* Legacy or Advanced Host Interface:
- * 0: Advanced Host Interface
- * 1: Legacy Host Interface
- */
- tlan_ctx->legacy_int = ICE_TX_LEGACY;
-}
-
-/**
- * ice_vsi_cfg_txqs - Configure the VSI for Tx
- * @vsi: the VSI being configured
- *
- * Return 0 on success and a negative value on error
- * Configure the Tx VSI for operation.
- */
-static int ice_vsi_cfg_txqs(struct ice_vsi *vsi)
-{
- struct ice_aqc_add_tx_qgrp *qg_buf;
- struct ice_aqc_add_txqs_perq *txq;
- struct ice_pf *pf = vsi->back;
- enum ice_status status;
- u16 buf_len, i, pf_q;
- int err = 0, tc = 0;
- u8 num_q_grps;
-
- buf_len = sizeof(struct ice_aqc_add_tx_qgrp);
- qg_buf = devm_kzalloc(&pf->pdev->dev, buf_len, GFP_KERNEL);
- if (!qg_buf)
- return -ENOMEM;
-
- if (vsi->num_txq > ICE_MAX_TXQ_PER_TXQG) {
- err = -EINVAL;
- goto err_cfg_txqs;
- }
- qg_buf->num_txqs = 1;
- num_q_grps = 1;
-
- /* set up and configure the tx queues */
- ice_for_each_txq(vsi, i) {
- struct ice_tlan_ctx tlan_ctx = { 0 };
-
- pf_q = vsi->txq_map[i];
- ice_setup_tx_ctx(vsi->tx_rings[i], &tlan_ctx, pf_q);
- /* copy context contents into the qg_buf */
- qg_buf->txqs[0].txq_id = cpu_to_le16(pf_q);
- ice_set_ctx((u8 *)&tlan_ctx, qg_buf->txqs[0].txq_ctx,
- ice_tlan_ctx_info);
-
- /* init queue specific tail reg. It is referred as transmit
- * comm scheduler queue doorbell.
- */
- vsi->tx_rings[i]->tail = pf->hw.hw_addr + QTX_COMM_DBELL(pf_q);
- status = ice_ena_vsi_txq(vsi->port_info, vsi->vsi_num, tc,
- num_q_grps, qg_buf, buf_len, NULL);
- if (status) {
- dev_err(&vsi->back->pdev->dev,
- "Failed to set LAN Tx queue context, error: %d\n",
- status);
- err = -ENODEV;
- goto err_cfg_txqs;
- }
-
- /* Add Tx Queue TEID into the VSI tx ring from the response
- * This will complete configuring and enabling the queue.
- */
- txq = &qg_buf->txqs[0];
- if (pf_q == le16_to_cpu(txq->txq_id))
- vsi->tx_rings[i]->txq_teid =
- le32_to_cpu(txq->q_teid);
- }
-err_cfg_txqs:
- devm_kfree(&pf->pdev->dev, qg_buf);
- return err;
-}
-
-/**
- * ice_setup_rx_ctx - Configure a receive ring context
- * @ring: The Rx ring to configure
- *
- * Configure the Rx descriptor ring in RLAN context.
- */
-static int ice_setup_rx_ctx(struct ice_ring *ring)
-{
- struct ice_vsi *vsi = ring->vsi;
- struct ice_hw *hw = &vsi->back->hw;
- u32 rxdid = ICE_RXDID_FLEX_NIC;
- struct ice_rlan_ctx rlan_ctx;
- u32 regval;
- u16 pf_q;
- int err;
-
- /* what is RX queue number in global space of 2K rx queues */
- pf_q = vsi->rxq_map[ring->q_index];
-
- /* clear the context structure first */
- memset(&rlan_ctx, 0, sizeof(rlan_ctx));
-
- rlan_ctx.base = ring->dma >> ICE_RLAN_BASE_S;
-
- rlan_ctx.qlen = ring->count;
-
- /* Receive Packet Data Buffer Size.
- * The Packet Data Buffer Size is defined in 128 byte units.
- */
- rlan_ctx.dbuf = vsi->rx_buf_len >> ICE_RLAN_CTX_DBUF_S;
-
- /* use 32 byte descriptors */
- rlan_ctx.dsize = 1;
-
- /* Strip the Ethernet CRC bytes before the packet is posted to host
- * memory.
- */
- rlan_ctx.crcstrip = 1;
-
- /* L2TSEL flag defines the reported L2 Tags in the receive descriptor */
- rlan_ctx.l2tsel = 1;
-
- rlan_ctx.dtype = ICE_RX_DTYPE_NO_SPLIT;
- rlan_ctx.hsplit_0 = ICE_RLAN_RX_HSPLIT_0_NO_SPLIT;
- rlan_ctx.hsplit_1 = ICE_RLAN_RX_HSPLIT_1_NO_SPLIT;
-
- /* This controls whether VLAN is stripped from inner headers
- * The VLAN in the inner L2 header is stripped to the receive
- * descriptor if enabled by this flag.
- */
- rlan_ctx.showiv = 0;
-
- /* Max packet size for this queue - must not be set to a larger value
- * than 5 x DBUF
- */
- rlan_ctx.rxmax = min_t(u16, vsi->max_frame,
- ICE_MAX_CHAINED_RX_BUFS * vsi->rx_buf_len);
-
- /* Rx queue threshold in units of 64 */
- rlan_ctx.lrxqthresh = 1;
-
- /* Enable Flexible Descriptors in the queue context which
- * allows this driver to select a specific receive descriptor format
- */
- regval = rd32(hw, QRXFLXP_CNTXT(pf_q));
- regval |= (rxdid << QRXFLXP_CNTXT_RXDID_IDX_S) &
- QRXFLXP_CNTXT_RXDID_IDX_M;
-
- /* increasing context priority to pick up profile id;
- * default is 0x01; setting to 0x03 to ensure profile
- * is programming if prev context is of same priority
- */
- regval |= (0x03 << QRXFLXP_CNTXT_RXDID_PRIO_S) &
- QRXFLXP_CNTXT_RXDID_PRIO_M;
-
- wr32(hw, QRXFLXP_CNTXT(pf_q), regval);
-
- /* Absolute queue number out of 2K needs to be passed */
- err = ice_write_rxq_ctx(hw, &rlan_ctx, pf_q);
- if (err) {
- dev_err(&vsi->back->pdev->dev,
- "Failed to set LAN Rx queue context for absolute Rx queue %d error: %d\n",
- pf_q, err);
- return -EIO;
- }
-
- /* init queue specific tail register */
- ring->tail = hw->hw_addr + QRX_TAIL(pf_q);
- writel(0, ring->tail);
- ice_alloc_rx_bufs(ring, ICE_DESC_UNUSED(ring));
-
- return 0;
-}
-
-/**
- * ice_vsi_cfg_rxqs - Configure the VSI for Rx
- * @vsi: the VSI being configured
- *
- * Return 0 on success and a negative value on error
- * Configure the Rx VSI for operation.
- */
-static int ice_vsi_cfg_rxqs(struct ice_vsi *vsi)
-{
- int err = 0;
- u16 i;
-
- if (vsi->netdev && vsi->netdev->mtu > ETH_DATA_LEN)
- vsi->max_frame = vsi->netdev->mtu +
- ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;
- else
- vsi->max_frame = ICE_RXBUF_2048;
-
- vsi->rx_buf_len = ICE_RXBUF_2048;
- /* set up individual rings */
- for (i = 0; i < vsi->num_rxq && !err; i++)
- err = ice_setup_rx_ctx(vsi->rx_rings[i]);
-
- if (err) {
- dev_err(&vsi->back->pdev->dev, "ice_setup_rx_ctx failed\n");
- return -EIO;
- }
- return err;
-}
-
-/**
* ice_vsi_cfg - Setup the VSI
* @vsi: the VSI being configured
*
@@ -4116,7 +2538,9 @@ static int ice_vsi_cfg(struct ice_vsi *vsi)
if (vsi->netdev) {
ice_set_rx_mode(vsi->netdev);
- err = ice_restore_vlan(vsi);
+
+ err = ice_vsi_vlan_setup(vsi);
+
if (err)
return err;
}
@@ -4129,200 +2553,6 @@ static int ice_vsi_cfg(struct ice_vsi *vsi)
}
/**
- * ice_vsi_stop_tx_rings - Disable Tx rings
- * @vsi: the VSI being configured
- */
-static int ice_vsi_stop_tx_rings(struct ice_vsi *vsi)
-{
- struct ice_pf *pf = vsi->back;
- struct ice_hw *hw = &pf->hw;
- enum ice_status status;
- u32 *q_teids, val;
- u16 *q_ids, i;
- int err = 0;
-
- if (vsi->num_txq > ICE_LAN_TXQ_MAX_QDIS)
- return -EINVAL;
-
- q_teids = devm_kcalloc(&pf->pdev->dev, vsi->num_txq, sizeof(*q_teids),
- GFP_KERNEL);
- if (!q_teids)
- return -ENOMEM;
-
- q_ids = devm_kcalloc(&pf->pdev->dev, vsi->num_txq, sizeof(*q_ids),
- GFP_KERNEL);
- if (!q_ids) {
- err = -ENOMEM;
- goto err_alloc_q_ids;
- }
-
- /* set up the tx queue list to be disabled */
- ice_for_each_txq(vsi, i) {
- u16 v_idx;
-
- if (!vsi->tx_rings || !vsi->tx_rings[i]) {
- err = -EINVAL;
- goto err_out;
- }
-
- q_ids[i] = vsi->txq_map[i];
- q_teids[i] = vsi->tx_rings[i]->txq_teid;
-
- /* clear cause_ena bit for disabled queues */
- val = rd32(hw, QINT_TQCTL(vsi->tx_rings[i]->reg_idx));
- val &= ~QINT_TQCTL_CAUSE_ENA_M;
- wr32(hw, QINT_TQCTL(vsi->tx_rings[i]->reg_idx), val);
-
- /* software is expected to wait for 100 ns */
- ndelay(100);
-
- /* trigger a software interrupt for the vector associated to
- * the queue to schedule napi handler
- */
- v_idx = vsi->tx_rings[i]->q_vector->v_idx;
- wr32(hw, GLINT_DYN_CTL(vsi->base_vector + v_idx),
- GLINT_DYN_CTL_SWINT_TRIG_M | GLINT_DYN_CTL_INTENA_MSK_M);
- }
- status = ice_dis_vsi_txq(vsi->port_info, vsi->num_txq, q_ids, q_teids,
- NULL);
- if (status) {
- dev_err(&pf->pdev->dev,
- "Failed to disable LAN Tx queues, error: %d\n",
- status);
- err = -ENODEV;
- }
-
-err_out:
- devm_kfree(&pf->pdev->dev, q_ids);
-
-err_alloc_q_ids:
- devm_kfree(&pf->pdev->dev, q_teids);
-
- return err;
-}
-
-/**
- * ice_pf_rxq_wait - Wait for a PF's Rx queue to be enabled or disabled
- * @pf: the PF being configured
- * @pf_q: the PF queue
- * @ena: enable or disable state of the queue
- *
- * This routine will wait for the given Rx queue of the PF to reach the
- * enabled or disabled state.
- * Returns -ETIMEDOUT in case of failing to reach the requested state after
- * multiple retries; else will return 0 in case of success.
- */
-static int ice_pf_rxq_wait(struct ice_pf *pf, int pf_q, bool ena)
-{
- int i;
-
- for (i = 0; i < ICE_Q_WAIT_RETRY_LIMIT; i++) {
- u32 rx_reg = rd32(&pf->hw, QRX_CTRL(pf_q));
-
- if (ena == !!(rx_reg & QRX_CTRL_QENA_STAT_M))
- break;
-
- usleep_range(10, 20);
- }
- if (i >= ICE_Q_WAIT_RETRY_LIMIT)
- return -ETIMEDOUT;
-
- return 0;
-}
-
-/**
- * ice_vsi_ctrl_rx_rings - Start or stop a VSI's rx rings
- * @vsi: the VSI being configured
- * @ena: start or stop the rx rings
- */
-static int ice_vsi_ctrl_rx_rings(struct ice_vsi *vsi, bool ena)
-{
- struct ice_pf *pf = vsi->back;
- struct ice_hw *hw = &pf->hw;
- int i, j, ret = 0;
-
- for (i = 0; i < vsi->num_rxq; i++) {
- int pf_q = vsi->rxq_map[i];
- u32 rx_reg;
-
- for (j = 0; j < ICE_Q_WAIT_MAX_RETRY; j++) {
- rx_reg = rd32(hw, QRX_CTRL(pf_q));
- if (((rx_reg >> QRX_CTRL_QENA_REQ_S) & 1) ==
- ((rx_reg >> QRX_CTRL_QENA_STAT_S) & 1))
- break;
- usleep_range(1000, 2000);
- }
-
- /* Skip if the queue is already in the requested state */
- if (ena == !!(rx_reg & QRX_CTRL_QENA_STAT_M))
- continue;
-
- /* turn on/off the queue */
- if (ena)
- rx_reg |= QRX_CTRL_QENA_REQ_M;
- else
- rx_reg &= ~QRX_CTRL_QENA_REQ_M;
- wr32(hw, QRX_CTRL(pf_q), rx_reg);
-
- /* wait for the change to finish */
- ret = ice_pf_rxq_wait(pf, pf_q, ena);
- if (ret) {
- dev_err(&pf->pdev->dev,
- "VSI idx %d Rx ring %d %sable timeout\n",
- vsi->idx, pf_q, (ena ? "en" : "dis"));
- break;
- }
- }
-
- return ret;
-}
-
-/**
- * ice_vsi_start_rx_rings - start VSI's rx rings
- * @vsi: the VSI whose rings are to be started
- *
- * Returns 0 on success and a negative value on error
- */
-static int ice_vsi_start_rx_rings(struct ice_vsi *vsi)
-{
- return ice_vsi_ctrl_rx_rings(vsi, true);
-}
-
-/**
- * ice_vsi_stop_rx_rings - stop VSI's rx rings
- * @vsi: the VSI
- *
- * Returns 0 on success and a negative value on error
- */
-static int ice_vsi_stop_rx_rings(struct ice_vsi *vsi)
-{
- return ice_vsi_ctrl_rx_rings(vsi, false);
-}
-
-/**
- * ice_vsi_stop_tx_rx_rings - stop VSI's tx and rx rings
- * @vsi: the VSI
- * Returns 0 on success and a negative value on error
- */
-static int ice_vsi_stop_tx_rx_rings(struct ice_vsi *vsi)
-{
- int err_tx, err_rx;
-
- err_tx = ice_vsi_stop_tx_rings(vsi);
- if (err_tx)
- dev_dbg(&vsi->back->pdev->dev, "Failed to disable Tx rings\n");
-
- err_rx = ice_vsi_stop_rx_rings(vsi);
- if (err_rx)
- dev_dbg(&vsi->back->pdev->dev, "Failed to disable Rx rings\n");
-
- if (err_tx || err_rx)
- return -EIO;
-
- return 0;
-}
-
-/**
* ice_napi_enable_all - Enable NAPI for all q_vectors in the VSI
* @vsi: the VSI being configured
*/
@@ -4419,122 +2649,6 @@ static void ice_fetch_u64_stats_per_ring(struct ice_ring *ring, u64 *pkts,
}
/**
- * ice_stat_update40 - read 40 bit stat from the chip and update stat values
- * @hw: ptr to the hardware info
- * @hireg: high 32 bit HW register to read from
- * @loreg: low 32 bit HW register to read from
- * @prev_stat_loaded: bool to specify if previous stats are loaded
- * @prev_stat: ptr to previous loaded stat value
- * @cur_stat: ptr to current stat value
- */
-static void ice_stat_update40(struct ice_hw *hw, u32 hireg, u32 loreg,
- bool prev_stat_loaded, u64 *prev_stat,
- u64 *cur_stat)
-{
- u64 new_data;
-
- new_data = rd32(hw, loreg);
- new_data |= ((u64)(rd32(hw, hireg) & 0xFFFF)) << 32;
-
- /* device stats are not reset at PFR, they likely will not be zeroed
- * when the driver starts. So save the first values read and use them as
- * offsets to be subtracted from the raw values in order to report stats
- * that count from zero.
- */
- if (!prev_stat_loaded)
- *prev_stat = new_data;
- if (likely(new_data >= *prev_stat))
- *cur_stat = new_data - *prev_stat;
- else
- /* to manage the potential roll-over */
- *cur_stat = (new_data + BIT_ULL(40)) - *prev_stat;
- *cur_stat &= 0xFFFFFFFFFFULL;
-}
-
-/**
- * ice_stat_update32 - read 32 bit stat from the chip and update stat values
- * @hw: ptr to the hardware info
- * @reg: HW register to read from
- * @prev_stat_loaded: bool to specify if previous stats are loaded
- * @prev_stat: ptr to previous loaded stat value
- * @cur_stat: ptr to current stat value
- */
-static void ice_stat_update32(struct ice_hw *hw, u32 reg, bool prev_stat_loaded,
- u64 *prev_stat, u64 *cur_stat)
-{
- u32 new_data;
-
- new_data = rd32(hw, reg);
-
- /* device stats are not reset at PFR, they likely will not be zeroed
- * when the driver starts. So save the first values read and use them as
- * offsets to be subtracted from the raw values in order to report stats
- * that count from zero.
- */
- if (!prev_stat_loaded)
- *prev_stat = new_data;
- if (likely(new_data >= *prev_stat))
- *cur_stat = new_data - *prev_stat;
- else
- /* to manage the potential roll-over */
- *cur_stat = (new_data + BIT_ULL(32)) - *prev_stat;
-}
-
-/**
- * ice_update_eth_stats - Update VSI-specific ethernet statistics counters
- * @vsi: the VSI to be updated
- */
-static void ice_update_eth_stats(struct ice_vsi *vsi)
-{
- struct ice_eth_stats *prev_es, *cur_es;
- struct ice_hw *hw = &vsi->back->hw;
- u16 vsi_num = vsi->vsi_num; /* HW absolute index of a VSI */
-
- prev_es = &vsi->eth_stats_prev;
- cur_es = &vsi->eth_stats;
-
- ice_stat_update40(hw, GLV_GORCH(vsi_num), GLV_GORCL(vsi_num),
- vsi->stat_offsets_loaded, &prev_es->rx_bytes,
- &cur_es->rx_bytes);
-
- ice_stat_update40(hw, GLV_UPRCH(vsi_num), GLV_UPRCL(vsi_num),
- vsi->stat_offsets_loaded, &prev_es->rx_unicast,
- &cur_es->rx_unicast);
-
- ice_stat_update40(hw, GLV_MPRCH(vsi_num), GLV_MPRCL(vsi_num),
- vsi->stat_offsets_loaded, &prev_es->rx_multicast,
- &cur_es->rx_multicast);
-
- ice_stat_update40(hw, GLV_BPRCH(vsi_num), GLV_BPRCL(vsi_num),
- vsi->stat_offsets_loaded, &prev_es->rx_broadcast,
- &cur_es->rx_broadcast);
-
- ice_stat_update32(hw, GLV_RDPC(vsi_num), vsi->stat_offsets_loaded,
- &prev_es->rx_discards, &cur_es->rx_discards);
-
- ice_stat_update40(hw, GLV_GOTCH(vsi_num), GLV_GOTCL(vsi_num),
- vsi->stat_offsets_loaded, &prev_es->tx_bytes,
- &cur_es->tx_bytes);
-
- ice_stat_update40(hw, GLV_UPTCH(vsi_num), GLV_UPTCL(vsi_num),
- vsi->stat_offsets_loaded, &prev_es->tx_unicast,
- &cur_es->tx_unicast);
-
- ice_stat_update40(hw, GLV_MPTCH(vsi_num), GLV_MPTCL(vsi_num),
- vsi->stat_offsets_loaded, &prev_es->tx_multicast,
- &cur_es->tx_multicast);
-
- ice_stat_update40(hw, GLV_BPTCH(vsi_num), GLV_BPTCL(vsi_num),
- vsi->stat_offsets_loaded, &prev_es->tx_broadcast,
- &cur_es->tx_broadcast);
-
- ice_stat_update32(hw, GLV_TEPC(vsi_num), vsi->stat_offsets_loaded,
- &prev_es->tx_errors, &cur_es->tx_errors);
-
- vsi->stat_offsets_loaded = true;
-}
-
-/**
* ice_update_vsi_ring_stats - Update VSI stats counters
* @vsi: the VSI to be updated
*/
@@ -4827,7 +2941,7 @@ static void ice_napi_disable_all(struct ice_vsi *vsi)
*/
int ice_down(struct ice_vsi *vsi)
{
- int i, err;
+ int i, tx_err, rx_err;
/* Caller of this function is expected to set the
* vsi->state __ICE_DOWN bit
@@ -4838,7 +2952,18 @@ int ice_down(struct ice_vsi *vsi)
}
ice_vsi_dis_irq(vsi);
- err = ice_vsi_stop_tx_rx_rings(vsi);
+ tx_err = ice_vsi_stop_tx_rings(vsi, ICE_NO_RESET, 0);
+ if (tx_err)
+ netdev_err(vsi->netdev,
+ "Failed stop Tx rings, VSI %d error %d\n",
+ vsi->vsi_num, tx_err);
+
+ rx_err = ice_vsi_stop_rx_rings(vsi);
+ if (rx_err)
+ netdev_err(vsi->netdev,
+ "Failed stop Rx rings, VSI %d error %d\n",
+ vsi->vsi_num, rx_err);
+
ice_napi_disable_all(vsi);
ice_for_each_txq(vsi, i)
@@ -4847,10 +2972,14 @@ int ice_down(struct ice_vsi *vsi)
ice_for_each_rxq(vsi, i)
ice_clean_rx_ring(vsi->rx_rings[i]);
- if (err)
- netdev_err(vsi->netdev, "Failed to close VSI 0x%04X on switch 0x%04X\n",
+ if (tx_err || rx_err) {
+ netdev_err(vsi->netdev,
+ "Failed to close VSI 0x%04X on switch 0x%04X\n",
vsi->vsi_num, vsi->vsw->sw_id);
- return err;
+ return -EIO;
+ }
+
+ return 0;
}
/**
@@ -4870,6 +2999,7 @@ static int ice_vsi_setup_tx_rings(struct ice_vsi *vsi)
}
ice_for_each_txq(vsi, i) {
+ vsi->tx_rings[i]->netdev = vsi->netdev;
err = ice_setup_tx_ring(vsi->tx_rings[i]);
if (err)
break;
@@ -4895,6 +3025,7 @@ static int ice_vsi_setup_rx_rings(struct ice_vsi *vsi)
}
ice_for_each_rxq(vsi, i) {
+ vsi->rx_rings[i]->netdev = vsi->netdev;
err = ice_setup_rx_ring(vsi->rx_rings[i]);
if (err)
break;
@@ -4922,38 +3053,6 @@ static int ice_vsi_req_irq(struct ice_vsi *vsi, char *basename)
}
/**
- * ice_vsi_free_tx_rings - Free Tx resources for VSI queues
- * @vsi: the VSI having resources freed
- */
-static void ice_vsi_free_tx_rings(struct ice_vsi *vsi)
-{
- int i;
-
- if (!vsi->tx_rings)
- return;
-
- ice_for_each_txq(vsi, i)
- if (vsi->tx_rings[i] && vsi->tx_rings[i]->desc)
- ice_free_tx_ring(vsi->tx_rings[i]);
-}
-
-/**
- * ice_vsi_free_rx_rings - Free Rx resources for VSI queues
- * @vsi: the VSI having resources freed
- */
-static void ice_vsi_free_rx_rings(struct ice_vsi *vsi)
-{
- int i;
-
- if (!vsi->rx_rings)
- return;
-
- ice_for_each_rxq(vsi, i)
- if (vsi->rx_rings[i] && vsi->rx_rings[i]->desc)
- ice_free_rx_ring(vsi->rx_rings[i]);
-}
-
-/**
* ice_vsi_open - Called when a network interface is made active
* @vsi: the VSI to open
*
@@ -5014,78 +3113,26 @@ err_setup_tx:
}
/**
- * ice_vsi_close - Shut down a VSI
- * @vsi: the VSI being shut down
+ * ice_vsi_release_all - Delete all VSIs
+ * @pf: PF from which all VSIs are being removed
*/
-static void ice_vsi_close(struct ice_vsi *vsi)
+static void ice_vsi_release_all(struct ice_pf *pf)
{
- if (!test_and_set_bit(__ICE_DOWN, vsi->state))
- ice_down(vsi);
-
- ice_vsi_free_irq(vsi);
- ice_vsi_free_tx_rings(vsi);
- ice_vsi_free_rx_rings(vsi);
-}
-
-/**
- * ice_rss_clean - Delete RSS related VSI structures that hold user inputs
- * @vsi: the VSI being removed
- */
-static void ice_rss_clean(struct ice_vsi *vsi)
-{
- struct ice_pf *pf;
+ int err, i;
- pf = vsi->back;
-
- if (vsi->rss_hkey_user)
- devm_kfree(&pf->pdev->dev, vsi->rss_hkey_user);
- if (vsi->rss_lut_user)
- devm_kfree(&pf->pdev->dev, vsi->rss_lut_user);
-}
-
-/**
- * ice_vsi_release - Delete a VSI and free its resources
- * @vsi: the VSI being removed
- *
- * Returns 0 on success or < 0 on error
- */
-static int ice_vsi_release(struct ice_vsi *vsi)
-{
- struct ice_pf *pf;
+ if (!pf->vsi)
+ return;
- if (!vsi->back)
- return -ENODEV;
- pf = vsi->back;
+ for (i = 0; i < pf->num_alloc_vsi; i++) {
+ if (!pf->vsi[i])
+ continue;
- if (vsi->netdev) {
- unregister_netdev(vsi->netdev);
- free_netdev(vsi->netdev);
- vsi->netdev = NULL;
+ err = ice_vsi_release(pf->vsi[i]);
+ if (err)
+ dev_dbg(&pf->pdev->dev,
+ "Failed to release pf->vsi[%d], err %d, vsi_num = %d\n",
+ i, err, pf->vsi[i]->vsi_num);
}
-
- if (test_bit(ICE_FLAG_RSS_ENA, pf->flags))
- ice_rss_clean(vsi);
-
- /* Disable VSI and free resources */
- ice_vsi_dis_irq(vsi);
- ice_vsi_close(vsi);
-
- /* reclaim interrupt vectors back to PF */
- ice_free_res(vsi->back->irq_tracker, vsi->base_vector, vsi->idx);
- pf->num_avail_msix += vsi->num_q_vectors;
-
- ice_remove_vsi_fltr(&pf->hw, vsi->vsi_num);
- ice_vsi_delete(vsi);
- ice_vsi_free_q_vectors(vsi);
- ice_vsi_clear_rings(vsi);
-
- ice_vsi_put_qs(vsi);
- pf->q_left_tx += vsi->alloc_txq;
- pf->q_left_rx += vsi->alloc_rxq;
-
- ice_vsi_clear(vsi);
-
- return 0;
}
/**
@@ -5099,28 +3146,37 @@ static void ice_dis_vsi(struct ice_vsi *vsi)
set_bit(__ICE_NEEDS_RESTART, vsi->state);
- if (vsi->netdev && netif_running(vsi->netdev) &&
- vsi->type == ICE_VSI_PF)
- vsi->netdev->netdev_ops->ndo_stop(vsi->netdev);
-
- ice_vsi_close(vsi);
+ if (vsi->type == ICE_VSI_PF && vsi->netdev) {
+ if (netif_running(vsi->netdev)) {
+ rtnl_lock();
+ vsi->netdev->netdev_ops->ndo_stop(vsi->netdev);
+ rtnl_unlock();
+ } else {
+ ice_vsi_close(vsi);
+ }
+ }
}
/**
* ice_ena_vsi - resume a VSI
* @vsi: the VSI being resume
*/
-static void ice_ena_vsi(struct ice_vsi *vsi)
+static int ice_ena_vsi(struct ice_vsi *vsi)
{
- if (!test_and_clear_bit(__ICE_NEEDS_RESTART, vsi->state))
- return;
+ int err = 0;
+
+ if (test_and_clear_bit(__ICE_NEEDS_RESTART, vsi->state) &&
+ vsi->netdev) {
+ if (netif_running(vsi->netdev)) {
+ rtnl_lock();
+ err = vsi->netdev->netdev_ops->ndo_open(vsi->netdev);
+ rtnl_unlock();
+ } else {
+ err = ice_vsi_open(vsi);
+ }
+ }
- if (vsi->netdev && netif_running(vsi->netdev))
- vsi->netdev->netdev_ops->ndo_open(vsi->netdev);
- else if (ice_vsi_open(vsi))
- /* this clears the DOWN bit */
- dev_dbg(&vsi->back->pdev->dev, "Failed open VSI 0x%04X on switch 0x%04X\n",
- vsi->vsi_num, vsi->vsw->sw_id);
+ return err;
}
/**
@@ -5140,13 +3196,89 @@ static void ice_pf_dis_all_vsi(struct ice_pf *pf)
* ice_pf_ena_all_vsi - Resume all VSIs on a PF
* @pf: the PF
*/
-static void ice_pf_ena_all_vsi(struct ice_pf *pf)
+static int ice_pf_ena_all_vsi(struct ice_pf *pf)
{
int v;
ice_for_each_vsi(pf, v)
if (pf->vsi[v])
- ice_ena_vsi(pf->vsi[v]);
+ if (ice_ena_vsi(pf->vsi[v]))
+ return -EIO;
+
+ return 0;
+}
+
+/**
+ * ice_vsi_rebuild_all - rebuild all VSIs in pf
+ * @pf: the PF
+ */
+static int ice_vsi_rebuild_all(struct ice_pf *pf)
+{
+ int i;
+
+ /* loop through pf->vsi array and reinit the VSI if found */
+ for (i = 0; i < pf->num_alloc_vsi; i++) {
+ int err;
+
+ if (!pf->vsi[i])
+ continue;
+
+ /* VF VSI rebuild isn't supported yet */
+ if (pf->vsi[i]->type == ICE_VSI_VF)
+ continue;
+
+ err = ice_vsi_rebuild(pf->vsi[i]);
+ if (err) {
+ dev_err(&pf->pdev->dev,
+ "VSI at index %d rebuild failed\n",
+ pf->vsi[i]->idx);
+ return err;
+ }
+
+ dev_info(&pf->pdev->dev,
+ "VSI at index %d rebuilt. vsi_num = 0x%x\n",
+ pf->vsi[i]->idx, pf->vsi[i]->vsi_num);
+ }
+
+ return 0;
+}
+
+/**
+ * ice_vsi_replay_all - replay all VSIs configuration in the PF
+ * @pf: the PF
+ */
+static int ice_vsi_replay_all(struct ice_pf *pf)
+{
+ struct ice_hw *hw = &pf->hw;
+ enum ice_status ret;
+ int i;
+
+ /* loop through pf->vsi array and replay the VSI if found */
+ for (i = 0; i < pf->num_alloc_vsi; i++) {
+ if (!pf->vsi[i])
+ continue;
+
+ ret = ice_replay_vsi(hw, pf->vsi[i]->idx);
+ if (ret) {
+ dev_err(&pf->pdev->dev,
+ "VSI at index %d replay failed %d\n",
+ pf->vsi[i]->idx, ret);
+ return -EIO;
+ }
+
+ /* Re-map HW VSI number, using VSI handle that has been
+ * previously validated in ice_replay_vsi() call above
+ */
+ pf->vsi[i]->vsi_num = ice_get_hw_vsi_num(hw, pf->vsi[i]->idx);
+
+ dev_info(&pf->pdev->dev,
+ "VSI at index %d filter replayed successfully - vsi_num %i\n",
+ pf->vsi[i]->idx, pf->vsi[i]->vsi_num);
+ }
+
+ /* Clean up replay filter after successful re-configuration */
+ ice_replay_post(hw);
+ return 0;
}
/**
@@ -5158,7 +3290,7 @@ static void ice_rebuild(struct ice_pf *pf)
struct device *dev = &pf->pdev->dev;
struct ice_hw *hw = &pf->hw;
enum ice_status ret;
- int err;
+ int err, i;
if (test_bit(__ICE_DOWN, pf->state))
goto clear_recovery;
@@ -5168,13 +3300,13 @@ static void ice_rebuild(struct ice_pf *pf)
ret = ice_init_all_ctrlq(hw);
if (ret) {
dev_err(dev, "control queues init failed %d\n", ret);
- goto fail_reset;
+ goto err_init_ctrlq;
}
ret = ice_clear_pf_cfg(hw);
if (ret) {
dev_err(dev, "clear PF configuration failed %d\n", ret);
- goto fail_reset;
+ goto err_init_ctrlq;
}
ice_clear_pxe_mode(hw);
@@ -5182,14 +3314,34 @@ static void ice_rebuild(struct ice_pf *pf)
ret = ice_get_caps(hw);
if (ret) {
dev_err(dev, "ice_get_caps failed %d\n", ret);
- goto fail_reset;
+ goto err_init_ctrlq;
}
- /* basic nic switch setup */
- err = ice_setup_pf_sw(pf);
+ err = ice_sched_init_port(hw->port_info);
+ if (err)
+ goto err_sched_init_port;
+
+ /* reset search_hint of irq_trackers to 0 since interrupts are
+ * reclaimed and could be allocated from beginning during VSI rebuild
+ */
+ pf->sw_irq_tracker->search_hint = 0;
+ pf->hw_irq_tracker->search_hint = 0;
+
+ err = ice_vsi_rebuild_all(pf);
if (err) {
- dev_err(dev, "ice_setup_pf_sw failed\n");
- goto fail_reset;
+ dev_err(dev, "ice_vsi_rebuild_all failed\n");
+ goto err_vsi_rebuild;
+ }
+
+ err = ice_update_link_info(hw->port_info);
+ if (err)
+ dev_err(&pf->pdev->dev, "Get link status error %d\n", err);
+
+ /* Replay all VSIs Configuration, including filters after reset */
+ if (ice_vsi_replay_all(pf)) {
+ dev_err(&pf->pdev->dev,
+ "error replaying VSI configurations with switch filter rules\n");
+ goto err_vsi_rebuild;
}
/* start misc vector */
@@ -5197,20 +3349,52 @@ static void ice_rebuild(struct ice_pf *pf)
err = ice_req_irq_msix_misc(pf);
if (err) {
dev_err(dev, "misc vector setup failed: %d\n", err);
- goto fail_reset;
+ goto err_vsi_rebuild;
}
}
/* restart the VSIs that were rebuilt and running before the reset */
- ice_pf_ena_all_vsi(pf);
+ err = ice_pf_ena_all_vsi(pf);
+ if (err) {
+ dev_err(&pf->pdev->dev, "error enabling VSIs\n");
+ /* no need to disable VSIs in tear down path in ice_rebuild()
+ * since its already taken care in ice_vsi_open()
+ */
+ goto err_vsi_rebuild;
+ }
+
+ ice_reset_all_vfs(pf, true);
+ for (i = 0; i < pf->num_alloc_vsi; i++) {
+ bool link_up;
+
+ if (!pf->vsi[i] || pf->vsi[i]->type != ICE_VSI_PF)
+ continue;
+ ice_get_link_status(pf->vsi[i]->port_info, &link_up);
+ if (link_up) {
+ netif_carrier_on(pf->vsi[i]->netdev);
+ netif_tx_wake_all_queues(pf->vsi[i]->netdev);
+ } else {
+ netif_carrier_off(pf->vsi[i]->netdev);
+ netif_tx_stop_all_queues(pf->vsi[i]->netdev);
+ }
+ }
+
+ /* if we get here, reset flow is successful */
+ clear_bit(__ICE_RESET_FAILED, pf->state);
return;
-fail_reset:
+err_vsi_rebuild:
+ ice_vsi_release_all(pf);
+err_sched_init_port:
+ ice_sched_cleanup_all(hw);
+err_init_ctrlq:
ice_shutdown_all_ctrlq(hw);
set_bit(__ICE_RESET_FAILED, pf->state);
clear_recovery:
- set_bit(__ICE_RESET_RECOVERY_PENDING, pf->state);
+ /* set this bit in PF state to control service task scheduling */
+ set_bit(__ICE_NEEDS_RESTART, pf->state);
+ dev_err(dev, "Rebuild failed, unload and reload driver\n");
}
/**
@@ -5243,7 +3427,7 @@ static int ice_change_mtu(struct net_device *netdev, int new_mtu)
}
/* if a reset is in progress, wait for some time for it to complete */
do {
- if (ice_is_reset_recovery_pending(pf->state)) {
+ if (ice_is_reset_in_progress(pf->state)) {
count++;
usleep_range(1000, 2000);
} else {
@@ -5299,7 +3483,7 @@ int ice_set_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size)
struct ice_aqc_get_set_rss_keys *buf =
(struct ice_aqc_get_set_rss_keys *)seed;
- status = ice_aq_set_rss_key(hw, vsi->vsi_num, buf);
+ status = ice_aq_set_rss_key(hw, vsi->idx, buf);
if (status) {
dev_err(&pf->pdev->dev,
@@ -5310,8 +3494,8 @@ int ice_set_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size)
}
if (lut) {
- status = ice_aq_set_rss_lut(hw, vsi->vsi_num,
- vsi->rss_lut_type, lut, lut_size);
+ status = ice_aq_set_rss_lut(hw, vsi->idx, vsi->rss_lut_type,
+ lut, lut_size);
if (status) {
dev_err(&pf->pdev->dev,
"Cannot set RSS lut, err %d aq_err %d\n",
@@ -5342,7 +3526,7 @@ int ice_get_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size)
struct ice_aqc_get_set_rss_keys *buf =
(struct ice_aqc_get_set_rss_keys *)seed;
- status = ice_aq_get_rss_key(hw, vsi->vsi_num, buf);
+ status = ice_aq_get_rss_key(hw, vsi->idx, buf);
if (status) {
dev_err(&pf->pdev->dev,
"Cannot get RSS key, err %d aq_err %d\n",
@@ -5352,8 +3536,8 @@ int ice_get_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size)
}
if (lut) {
- status = ice_aq_get_rss_lut(hw, vsi->vsi_num,
- vsi->rss_lut_type, lut, lut_size);
+ status = ice_aq_get_rss_lut(hw, vsi->idx, vsi->rss_lut_type,
+ lut, lut_size);
if (status) {
dev_err(&pf->pdev->dev,
"Cannot get RSS lut, err %d aq_err %d\n",
@@ -5366,6 +3550,232 @@ int ice_get_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size)
}
/**
+ * ice_bridge_getlink - Get the hardware bridge mode
+ * @skb: skb buff
+ * @pid: process id
+ * @seq: RTNL message seq
+ * @dev: the netdev being configured
+ * @filter_mask: filter mask passed in
+ * @nlflags: netlink flags passed in
+ *
+ * Return the bridge mode (VEB/VEPA)
+ */
+static int
+ice_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
+ struct net_device *dev, u32 filter_mask, int nlflags)
+{
+ struct ice_netdev_priv *np = netdev_priv(dev);
+ struct ice_vsi *vsi = np->vsi;
+ struct ice_pf *pf = vsi->back;
+ u16 bmode;
+
+ bmode = pf->first_sw->bridge_mode;
+
+ return ndo_dflt_bridge_getlink(skb, pid, seq, dev, bmode, 0, 0, nlflags,
+ filter_mask, NULL);
+}
+
+/**
+ * ice_vsi_update_bridge_mode - Update VSI for switching bridge mode (VEB/VEPA)
+ * @vsi: Pointer to VSI structure
+ * @bmode: Hardware bridge mode (VEB/VEPA)
+ *
+ * Returns 0 on success, negative on failure
+ */
+static int ice_vsi_update_bridge_mode(struct ice_vsi *vsi, u16 bmode)
+{
+ struct device *dev = &vsi->back->pdev->dev;
+ struct ice_aqc_vsi_props *vsi_props;
+ struct ice_hw *hw = &vsi->back->hw;
+ struct ice_vsi_ctx ctxt = { 0 };
+ enum ice_status status;
+
+ vsi_props = &vsi->info;
+ ctxt.info = vsi->info;
+
+ if (bmode == BRIDGE_MODE_VEB)
+ /* change from VEPA to VEB mode */
+ ctxt.info.sw_flags |= ICE_AQ_VSI_SW_FLAG_ALLOW_LB;
+ else
+ /* change from VEB to VEPA mode */
+ ctxt.info.sw_flags &= ~ICE_AQ_VSI_SW_FLAG_ALLOW_LB;
+ ctxt.info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_SW_VALID);
+
+ status = ice_update_vsi(hw, vsi->idx, &ctxt, NULL);
+ if (status) {
+ dev_err(dev, "update VSI for bridge mode failed, bmode = %d err %d aq_err %d\n",
+ bmode, status, hw->adminq.sq_last_status);
+ return -EIO;
+ }
+ /* Update sw flags for book keeping */
+ vsi_props->sw_flags = ctxt.info.sw_flags;
+
+ return 0;
+}
+
+/**
+ * ice_bridge_setlink - Set the hardware bridge mode
+ * @dev: the netdev being configured
+ * @nlh: RTNL message
+ * @flags: bridge setlink flags
+ *
+ * Sets the bridge mode (VEB/VEPA) of the switch to which the netdev (VSI) is
+ * hooked up to. Iterates through the PF VSI list and sets the loopback mode (if
+ * not already set for all VSIs connected to this switch. And also update the
+ * unicast switch filter rules for the corresponding switch of the netdev.
+ */
+static int
+ice_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh,
+ u16 __always_unused flags)
+{
+ struct ice_netdev_priv *np = netdev_priv(dev);
+ struct ice_pf *pf = np->vsi->back;
+ struct nlattr *attr, *br_spec;
+ struct ice_hw *hw = &pf->hw;
+ enum ice_status status;
+ struct ice_sw *pf_sw;
+ int rem, v, err = 0;
+
+ pf_sw = pf->first_sw;
+ /* find the attribute in the netlink message */
+ br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
+
+ nla_for_each_nested(attr, br_spec, rem) {
+ __u16 mode;
+
+ if (nla_type(attr) != IFLA_BRIDGE_MODE)
+ continue;
+ mode = nla_get_u16(attr);
+ if (mode != BRIDGE_MODE_VEPA && mode != BRIDGE_MODE_VEB)
+ return -EINVAL;
+ /* Continue if bridge mode is not being flipped */
+ if (mode == pf_sw->bridge_mode)
+ continue;
+ /* Iterates through the PF VSI list and update the loopback
+ * mode of the VSI
+ */
+ ice_for_each_vsi(pf, v) {
+ if (!pf->vsi[v])
+ continue;
+ err = ice_vsi_update_bridge_mode(pf->vsi[v], mode);
+ if (err)
+ return err;
+ }
+
+ hw->evb_veb = (mode == BRIDGE_MODE_VEB);
+ /* Update the unicast switch filter rules for the corresponding
+ * switch of the netdev
+ */
+ status = ice_update_sw_rule_bridge_mode(hw);
+ if (status) {
+ netdev_err(dev, "update SW_RULE for bridge mode failed, = %d err %d aq_err %d\n",
+ mode, status, hw->adminq.sq_last_status);
+ /* revert hw->evb_veb */
+ hw->evb_veb = (pf_sw->bridge_mode == BRIDGE_MODE_VEB);
+ return -EIO;
+ }
+
+ pf_sw->bridge_mode = mode;
+ }
+
+ return 0;
+}
+
+/**
+ * ice_tx_timeout - Respond to a Tx Hang
+ * @netdev: network interface device structure
+ */
+static void ice_tx_timeout(struct net_device *netdev)
+{
+ struct ice_netdev_priv *np = netdev_priv(netdev);
+ struct ice_ring *tx_ring = NULL;
+ struct ice_vsi *vsi = np->vsi;
+ struct ice_pf *pf = vsi->back;
+ u32 head, val = 0, i;
+ int hung_queue = -1;
+
+ pf->tx_timeout_count++;
+
+ /* find the stopped queue the same way the stack does */
+ for (i = 0; i < netdev->num_tx_queues; i++) {
+ struct netdev_queue *q;
+ unsigned long trans_start;
+
+ q = netdev_get_tx_queue(netdev, i);
+ trans_start = q->trans_start;
+ if (netif_xmit_stopped(q) &&
+ time_after(jiffies,
+ (trans_start + netdev->watchdog_timeo))) {
+ hung_queue = i;
+ break;
+ }
+ }
+
+ if (i == netdev->num_tx_queues) {
+ netdev_info(netdev, "tx_timeout: no netdev hung queue found\n");
+ } else {
+ /* now that we have an index, find the tx_ring struct */
+ for (i = 0; i < vsi->num_txq; i++) {
+ if (vsi->tx_rings[i] && vsi->tx_rings[i]->desc) {
+ if (hung_queue ==
+ vsi->tx_rings[i]->q_index) {
+ tx_ring = vsi->tx_rings[i];
+ break;
+ }
+ }
+ }
+ }
+
+ /* Reset recovery level if enough time has elapsed after last timeout.
+ * Also ensure no new reset action happens before next timeout period.
+ */
+ if (time_after(jiffies, (pf->tx_timeout_last_recovery + HZ * 20)))
+ pf->tx_timeout_recovery_level = 1;
+ else if (time_before(jiffies, (pf->tx_timeout_last_recovery +
+ netdev->watchdog_timeo)))
+ return;
+
+ if (tx_ring) {
+ head = tx_ring->next_to_clean;
+ /* Read interrupt register */
+ if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags))
+ val = rd32(&pf->hw,
+ GLINT_DYN_CTL(tx_ring->q_vector->v_idx +
+ tx_ring->vsi->hw_base_vector));
+
+ netdev_info(netdev, "tx_timeout: VSI_num: %d, Q %d, NTC: 0x%x, HWB: 0x%x, NTU: 0x%x, TAIL: 0x%x, INT: 0x%x\n",
+ vsi->vsi_num, hung_queue, tx_ring->next_to_clean,
+ head, tx_ring->next_to_use,
+ readl(tx_ring->tail), val);
+ }
+
+ pf->tx_timeout_last_recovery = jiffies;
+ netdev_info(netdev, "tx_timeout recovery level %d, hung_queue %d\n",
+ pf->tx_timeout_recovery_level, hung_queue);
+
+ switch (pf->tx_timeout_recovery_level) {
+ case 1:
+ set_bit(__ICE_PFR_REQ, pf->state);
+ break;
+ case 2:
+ set_bit(__ICE_CORER_REQ, pf->state);
+ break;
+ case 3:
+ set_bit(__ICE_GLOBR_REQ, pf->state);
+ break;
+ default:
+ netdev_err(netdev, "tx_timeout recovery unsuccessful, device is in unrecoverable state.\n");
+ set_bit(__ICE_DOWN, pf->state);
+ set_bit(__ICE_NEEDS_RESTART, vsi->state);
+ set_bit(__ICE_SERVICE_DIS, pf->state);
+ break;
+ }
+
+ ice_service_task_schedule(pf);
+ pf->tx_timeout_recovery_level++;
+}
+
+/**
* ice_open - Called when a network interface becomes active
* @netdev: network interface device structure
*
@@ -5383,6 +3793,11 @@ static int ice_open(struct net_device *netdev)
struct ice_vsi *vsi = np->vsi;
int err;
+ if (test_bit(__ICE_NEEDS_RESTART, vsi->back->state)) {
+ netdev_err(netdev, "driver needs to be unloaded and reloaded\n");
+ return -EIO;
+ }
+
netif_carrier_off(netdev);
err = ice_vsi_open(vsi);
@@ -5473,9 +3888,18 @@ static const struct net_device_ops ice_netdev_ops = {
.ndo_validate_addr = eth_validate_addr,
.ndo_change_mtu = ice_change_mtu,
.ndo_get_stats64 = ice_get_stats64,
+ .ndo_set_vf_spoofchk = ice_set_vf_spoofchk,
+ .ndo_set_vf_mac = ice_set_vf_mac,
+ .ndo_get_vf_config = ice_get_vf_cfg,
+ .ndo_set_vf_trust = ice_set_vf_trust,
+ .ndo_set_vf_vlan = ice_set_vf_port_vlan,
+ .ndo_set_vf_link_state = ice_set_vf_link_state,
.ndo_vlan_rx_add_vid = ice_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = ice_vlan_rx_kill_vid,
.ndo_set_features = ice_set_features,
+ .ndo_bridge_getlink = ice_bridge_getlink,
+ .ndo_bridge_setlink = ice_bridge_setlink,
.ndo_fdb_add = ice_fdb_add,
.ndo_fdb_del = ice_fdb_del,
+ .ndo_tx_timeout = ice_tx_timeout,
};
diff --git a/drivers/net/ethernet/intel/ice/ice_nvm.c b/drivers/net/ethernet/intel/ice/ice_nvm.c
index 295a8cd87fc1..3274c543283c 100644
--- a/drivers/net/ethernet/intel/ice/ice_nvm.c
+++ b/drivers/net/ethernet/intel/ice/ice_nvm.c
@@ -137,7 +137,7 @@ ice_acquire_nvm(struct ice_hw *hw, enum ice_aq_res_access_type access)
if (hw->nvm.blank_nvm_mode)
return 0;
- return ice_acquire_res(hw, ICE_NVM_RES_ID, access);
+ return ice_acquire_res(hw, ICE_NVM_RES_ID, access, ICE_NVM_TIMEOUT);
}
/**
diff --git a/drivers/net/ethernet/intel/ice/ice_sched.c b/drivers/net/ethernet/intel/ice/ice_sched.c
index eeae199469b6..7cc8aa18a22b 100644
--- a/drivers/net/ethernet/intel/ice/ice_sched.c
+++ b/drivers/net/ethernet/intel/ice/ice_sched.c
@@ -17,7 +17,6 @@ ice_sched_add_root_node(struct ice_port_info *pi,
{
struct ice_sched_node *root;
struct ice_hw *hw;
- u16 max_children;
if (!pi)
return ICE_ERR_PARAM;
@@ -28,8 +27,8 @@ ice_sched_add_root_node(struct ice_port_info *pi,
if (!root)
return ICE_ERR_NO_MEMORY;
- max_children = le16_to_cpu(hw->layer_info[0].max_children);
- root->children = devm_kcalloc(ice_hw_to_dev(hw), max_children,
+ /* coverity[suspicious_sizeof] */
+ root->children = devm_kcalloc(ice_hw_to_dev(hw), hw->max_children[0],
sizeof(*root), GFP_KERNEL);
if (!root->children) {
devm_kfree(ice_hw_to_dev(hw), root);
@@ -86,6 +85,62 @@ ice_sched_find_node_by_teid(struct ice_sched_node *start_node, u32 teid)
}
/**
+ * ice_aq_query_sched_elems - query scheduler elements
+ * @hw: pointer to the hw struct
+ * @elems_req: number of elements to query
+ * @buf: pointer to buffer
+ * @buf_size: buffer size in bytes
+ * @elems_ret: returns total number of elements returned
+ * @cd: pointer to command details structure or NULL
+ *
+ * Query scheduling elements (0x0404)
+ */
+static enum ice_status
+ice_aq_query_sched_elems(struct ice_hw *hw, u16 elems_req,
+ struct ice_aqc_get_elem *buf, u16 buf_size,
+ u16 *elems_ret, struct ice_sq_cd *cd)
+{
+ struct ice_aqc_get_cfg_elem *cmd;
+ struct ice_aq_desc desc;
+ enum ice_status status;
+
+ cmd = &desc.params.get_update_elem;
+ ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_sched_elems);
+ cmd->num_elem_req = cpu_to_le16(elems_req);
+ desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
+ status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
+ if (!status && elems_ret)
+ *elems_ret = le16_to_cpu(cmd->num_elem_resp);
+
+ return status;
+}
+
+/**
+ * ice_sched_query_elem - query element information from hw
+ * @hw: pointer to the hw struct
+ * @node_teid: node teid to be queried
+ * @buf: buffer to element information
+ *
+ * This function queries HW element information
+ */
+static enum ice_status
+ice_sched_query_elem(struct ice_hw *hw, u32 node_teid,
+ struct ice_aqc_get_elem *buf)
+{
+ u16 buf_size, num_elem_ret = 0;
+ enum ice_status status;
+
+ buf_size = sizeof(*buf);
+ memset(buf, 0, buf_size);
+ buf->generic[0].node_teid = cpu_to_le32(node_teid);
+ status = ice_aq_query_sched_elems(hw, 1, buf, buf_size, &num_elem_ret,
+ NULL);
+ if (status || num_elem_ret != 1)
+ ice_debug(hw, ICE_DBG_SCHED, "query element failed\n");
+ return status;
+}
+
+/**
* ice_sched_add_node - Insert the Tx scheduler node in SW DB
* @pi: port information structure
* @layer: Scheduler layer of the node
@@ -98,9 +153,10 @@ ice_sched_add_node(struct ice_port_info *pi, u8 layer,
struct ice_aqc_txsched_elem_data *info)
{
struct ice_sched_node *parent;
+ struct ice_aqc_get_elem elem;
struct ice_sched_node *node;
+ enum ice_status status;
struct ice_hw *hw;
- u16 max_children;
if (!pi)
return ICE_ERR_PARAM;
@@ -117,12 +173,20 @@ ice_sched_add_node(struct ice_port_info *pi, u8 layer,
return ICE_ERR_PARAM;
}
+ /* query the current node information from FW before additing it
+ * to the SW DB
+ */
+ status = ice_sched_query_elem(hw, le32_to_cpu(info->node_teid), &elem);
+ if (status)
+ return status;
+
node = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*node), GFP_KERNEL);
if (!node)
return ICE_ERR_NO_MEMORY;
- max_children = le16_to_cpu(hw->layer_info[layer].max_children);
- if (max_children) {
- node->children = devm_kcalloc(ice_hw_to_dev(hw), max_children,
+ if (hw->max_children[layer]) {
+ /* coverity[suspicious_sizeof] */
+ node->children = devm_kcalloc(ice_hw_to_dev(hw),
+ hw->max_children[layer],
sizeof(*node), GFP_KERNEL);
if (!node->children) {
devm_kfree(ice_hw_to_dev(hw), node);
@@ -134,7 +198,7 @@ ice_sched_add_node(struct ice_port_info *pi, u8 layer,
node->parent = parent;
node->tx_sched_layer = layer;
parent->children[parent->num_children++] = node;
- memcpy(&node->info, info, sizeof(*info));
+ memcpy(&node->info, &elem.generic[0], sizeof(node->info));
return 0;
}
@@ -192,14 +256,17 @@ ice_sched_remove_elems(struct ice_hw *hw, struct ice_sched_node *parent,
buf = devm_kzalloc(ice_hw_to_dev(hw), buf_size, GFP_KERNEL);
if (!buf)
return ICE_ERR_NO_MEMORY;
+
buf->hdr.parent_teid = parent->info.node_teid;
buf->hdr.num_elems = cpu_to_le16(num_nodes);
for (i = 0; i < num_nodes; i++)
buf->teid[i] = cpu_to_le32(node_teids[i]);
+
status = ice_aq_delete_sched_elems(hw, 1, buf, buf_size,
&num_groups_removed, NULL);
if (status || num_groups_removed != 1)
ice_debug(hw, ICE_DBG_SCHED, "remove elements failed\n");
+
devm_kfree(ice_hw_to_dev(hw), buf);
return status;
}
@@ -532,9 +599,7 @@ ice_sched_suspend_resume_elems(struct ice_hw *hw, u8 num_nodes, u32 *node_teids,
static void ice_sched_clear_tx_topo(struct ice_port_info *pi)
{
struct ice_sched_agg_info *agg_info;
- struct ice_sched_vsi_info *vsi_elem;
struct ice_sched_agg_info *atmp;
- struct ice_sched_vsi_info *tmp;
struct ice_hw *hw;
if (!pi)
@@ -553,13 +618,6 @@ static void ice_sched_clear_tx_topo(struct ice_port_info *pi)
}
}
- /* remove the vsi list */
- list_for_each_entry_safe(vsi_elem, tmp, &pi->vsi_info_list,
- list_entry) {
- list_del(&vsi_elem->list_entry);
- devm_kfree(ice_hw_to_dev(hw), vsi_elem);
- }
-
if (pi->root) {
ice_free_sched_node(pi, pi->root);
pi->root = NULL;
@@ -592,13 +650,16 @@ static void ice_sched_clear_port(struct ice_port_info *pi)
*/
void ice_sched_cleanup_all(struct ice_hw *hw)
{
- if (!hw || !hw->port_info)
+ if (!hw)
return;
- if (hw->layer_info)
+ if (hw->layer_info) {
devm_kfree(ice_hw_to_dev(hw), hw->layer_info);
+ hw->layer_info = NULL;
+ }
- ice_sched_clear_port(hw->port_info);
+ if (hw->port_info)
+ ice_sched_clear_port(hw->port_info);
hw->num_tx_sched_layers = 0;
hw->num_tx_sched_phys_layers = 0;
@@ -607,31 +668,6 @@ void ice_sched_cleanup_all(struct ice_hw *hw)
}
/**
- * ice_sched_create_vsi_info_entry - create an empty new VSI entry
- * @pi: port information structure
- * @vsi_id: VSI Id
- *
- * This function creates a new VSI entry and adds it to list
- */
-static struct ice_sched_vsi_info *
-ice_sched_create_vsi_info_entry(struct ice_port_info *pi, u16 vsi_id)
-{
- struct ice_sched_vsi_info *vsi_elem;
-
- if (!pi)
- return NULL;
-
- vsi_elem = devm_kzalloc(ice_hw_to_dev(pi->hw), sizeof(*vsi_elem),
- GFP_KERNEL);
- if (!vsi_elem)
- return NULL;
-
- list_add(&vsi_elem->list_entry, &pi->vsi_info_list);
- vsi_elem->vsi_id = vsi_id;
- return vsi_elem;
-}
-
-/**
* ice_sched_add_elems - add nodes to hw and SW DB
* @pi: port information structure
* @tc_node: pointer to the branch node
@@ -671,9 +707,13 @@ ice_sched_add_elems(struct ice_port_info *pi, struct ice_sched_node *tc_node,
ICE_AQC_ELEM_VALID_EIR;
buf->generic[i].data.generic = 0;
buf->generic[i].data.cir_bw.bw_profile_idx =
- ICE_SCHED_DFLT_RL_PROF_ID;
+ cpu_to_le16(ICE_SCHED_DFLT_RL_PROF_ID);
+ buf->generic[i].data.cir_bw.bw_alloc =
+ cpu_to_le16(ICE_SCHED_DFLT_BW_WT);
buf->generic[i].data.eir_bw.bw_profile_idx =
- ICE_SCHED_DFLT_RL_PROF_ID;
+ cpu_to_le16(ICE_SCHED_DFLT_RL_PROF_ID);
+ buf->generic[i].data.eir_bw.bw_alloc =
+ cpu_to_le16(ICE_SCHED_DFLT_BW_WT);
}
status = ice_aq_add_sched_elems(hw, 1, buf, buf_size,
@@ -697,7 +737,6 @@ ice_sched_add_elems(struct ice_port_info *pi, struct ice_sched_node *tc_node,
teid = le32_to_cpu(buf->generic[i].node_teid);
new_node = ice_sched_find_node_by_teid(parent, teid);
-
if (!new_node) {
ice_debug(hw, ICE_DBG_SCHED,
"Node is missing for teid =%d\n", teid);
@@ -710,7 +749,6 @@ ice_sched_add_elems(struct ice_port_info *pi, struct ice_sched_node *tc_node,
/* add it to previous node sibling pointer */
/* Note: siblings are not linked across branches */
prev = ice_sched_get_first_node(hw, tc_node, layer);
-
if (prev && prev != new_node) {
while (prev->sibling)
prev = prev->sibling;
@@ -760,8 +798,7 @@ ice_sched_add_nodes_to_layer(struct ice_port_info *pi,
return ICE_ERR_PARAM;
/* max children per node per layer */
- max_child_nodes =
- le16_to_cpu(hw->layer_info[parent->tx_sched_layer].max_children);
+ max_child_nodes = hw->max_children[parent->tx_sched_layer];
/* current number of children + required nodes exceed max children ? */
if ((parent->num_children + num_nodes) > max_child_nodes) {
@@ -851,78 +888,6 @@ static u8 ice_sched_get_vsi_layer(struct ice_hw *hw)
}
/**
- * ice_sched_get_num_nodes_per_layer - Get the total number of nodes per layer
- * @pi: pointer to the port info struct
- * @layer: layer number
- *
- * This function calculates the number of nodes present in the scheduler tree
- * including all the branches for a given layer
- */
-static u16
-ice_sched_get_num_nodes_per_layer(struct ice_port_info *pi, u8 layer)
-{
- struct ice_hw *hw;
- u16 num_nodes = 0;
- u8 i;
-
- if (!pi)
- return num_nodes;
-
- hw = pi->hw;
-
- /* Calculate the number of nodes for all TCs */
- for (i = 0; i < pi->root->num_children; i++) {
- struct ice_sched_node *tc_node, *node;
-
- tc_node = pi->root->children[i];
-
- /* Get the first node */
- node = ice_sched_get_first_node(hw, tc_node, layer);
- if (!node)
- continue;
-
- /* count the siblings */
- while (node) {
- num_nodes++;
- node = node->sibling;
- }
- }
-
- return num_nodes;
-}
-
-/**
- * ice_sched_val_max_nodes - check max number of nodes reached or not
- * @pi: port information structure
- * @new_num_nodes_per_layer: pointer to the new number of nodes array
- *
- * This function checks whether the scheduler tree layers have enough space to
- * add new nodes
- */
-static enum ice_status
-ice_sched_validate_for_max_nodes(struct ice_port_info *pi,
- u16 *new_num_nodes_per_layer)
-{
- struct ice_hw *hw = pi->hw;
- u8 i, qg_layer;
- u16 num_nodes;
-
- qg_layer = ice_sched_get_qgrp_layer(hw);
-
- /* walk through all the layers from SW entry point to qgroup layer */
- for (i = hw->sw_entry_point_layer; i <= qg_layer; i++) {
- num_nodes = ice_sched_get_num_nodes_per_layer(pi, i);
- if (num_nodes + new_num_nodes_per_layer[i] >
- le16_to_cpu(hw->layer_info[i].max_pf_nodes)) {
- ice_debug(hw, ICE_DBG_SCHED,
- "max nodes reached for layer = %d\n", i);
- return ICE_ERR_CFG;
- }
- }
- return 0;
-}
-
-/**
* ice_rm_dflt_leaf_node - remove the default leaf node in the tree
* @pi: port information structure
*
@@ -1003,14 +968,12 @@ enum ice_status ice_sched_init_port(struct ice_port_info *pi)
hw = pi->hw;
/* Query the Default Topology from FW */
- buf = devm_kcalloc(ice_hw_to_dev(hw), ICE_TXSCHED_MAX_BRANCHES,
- sizeof(*buf), GFP_KERNEL);
+ buf = devm_kzalloc(ice_hw_to_dev(hw), ICE_AQ_MAX_BUF_LEN, GFP_KERNEL);
if (!buf)
return ICE_ERR_NO_MEMORY;
/* Query default scheduling tree topology */
- status = ice_aq_get_dflt_topo(hw, pi->lport, buf,
- sizeof(*buf) * ICE_TXSCHED_MAX_BRANCHES,
+ status = ice_aq_get_dflt_topo(hw, pi->lport, buf, ICE_AQ_MAX_BUF_LEN,
&num_branches, NULL);
if (status)
goto err_init_port;
@@ -1075,7 +1038,6 @@ enum ice_status ice_sched_init_port(struct ice_port_info *pi)
pi->port_state = ICE_SCHED_PORT_STATE_READY;
mutex_init(&pi->sched_lock);
INIT_LIST_HEAD(&pi->agg_list);
- INIT_LIST_HEAD(&pi->vsi_info_list);
err_init_port:
if (status && pi->root) {
@@ -1097,6 +1059,8 @@ enum ice_status ice_sched_query_res_alloc(struct ice_hw *hw)
{
struct ice_aqc_query_txsched_res_resp *buf;
enum ice_status status = 0;
+ __le16 max_sibl;
+ u8 i;
if (hw->layer_info)
return status;
@@ -1115,7 +1079,20 @@ enum ice_status ice_sched_query_res_alloc(struct ice_hw *hw)
hw->flattened_layers = buf->sched_props.flattening_bitmap;
hw->max_cgds = buf->sched_props.max_pf_cgds;
- hw->layer_info = devm_kmemdup(ice_hw_to_dev(hw), buf->layer_props,
+ /* max sibling group size of current layer refers to the max children
+ * of the below layer node.
+ * layer 1 node max children will be layer 2 max sibling group size
+ * layer 2 node max children will be layer 3 max sibling group size
+ * and so on. This array will be populated from root (index 0) to
+ * qgroup layer 7. Leaf node has no children.
+ */
+ for (i = 0; i < hw->num_tx_sched_layers; i++) {
+ max_sibl = buf->layer_props[i].max_sibl_grp_sz;
+ hw->max_children[i] = le16_to_cpu(max_sibl);
+ }
+
+ hw->layer_info = (struct ice_aqc_layer_props *)
+ devm_kmemdup(ice_hw_to_dev(hw), buf->layer_props,
(hw->num_tx_sched_layers *
sizeof(*hw->layer_info)),
GFP_KERNEL);
@@ -1130,27 +1107,6 @@ sched_query_out:
}
/**
- * ice_sched_get_vsi_info_entry - Get the vsi entry list for given vsi_id
- * @pi: port information structure
- * @vsi_id: vsi id
- *
- * This function retrieves the vsi list for the given vsi id
- */
-static struct ice_sched_vsi_info *
-ice_sched_get_vsi_info_entry(struct ice_port_info *pi, u16 vsi_id)
-{
- struct ice_sched_vsi_info *list_elem;
-
- if (!pi)
- return NULL;
-
- list_for_each_entry(list_elem, &pi->vsi_info_list, list_entry)
- if (list_elem->vsi_id == vsi_id)
- return list_elem;
- return NULL;
-}
-
-/**
* ice_sched_find_node_in_subtree - Find node in part of base node subtree
* @hw: pointer to the hw struct
* @base: pointer to the base node
@@ -1186,30 +1142,28 @@ ice_sched_find_node_in_subtree(struct ice_hw *hw, struct ice_sched_node *base,
/**
* ice_sched_get_free_qparent - Get a free lan or rdma q group node
* @pi: port information structure
- * @vsi_id: vsi id
+ * @vsi_handle: software VSI handle
* @tc: branch number
* @owner: lan or rdma
*
* This function retrieves a free lan or rdma q group node
*/
struct ice_sched_node *
-ice_sched_get_free_qparent(struct ice_port_info *pi, u16 vsi_id, u8 tc,
+ice_sched_get_free_qparent(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
u8 owner)
{
struct ice_sched_node *vsi_node, *qgrp_node = NULL;
- struct ice_sched_vsi_info *list_elem;
+ struct ice_vsi_ctx *vsi_ctx;
u16 max_children;
u8 qgrp_layer;
qgrp_layer = ice_sched_get_qgrp_layer(pi->hw);
- max_children = le16_to_cpu(pi->hw->layer_info[qgrp_layer].max_children);
-
- list_elem = ice_sched_get_vsi_info_entry(pi, vsi_id);
- if (!list_elem)
- goto lan_q_exit;
-
- vsi_node = list_elem->vsi_node[tc];
+ max_children = pi->hw->max_children[qgrp_layer];
+ vsi_ctx = ice_get_vsi_ctx(pi->hw, vsi_handle);
+ if (!vsi_ctx)
+ return NULL;
+ vsi_node = vsi_ctx->sched.vsi_node[tc];
/* validate invalid VSI id */
if (!vsi_node)
goto lan_q_exit;
@@ -1233,14 +1187,14 @@ lan_q_exit:
* ice_sched_get_vsi_node - Get a VSI node based on VSI id
* @hw: pointer to the hw struct
* @tc_node: pointer to the TC node
- * @vsi_id: VSI id
+ * @vsi_handle: software VSI handle
*
* This function retrieves a VSI node for a given VSI id from a given
* TC branch
*/
static struct ice_sched_node *
ice_sched_get_vsi_node(struct ice_hw *hw, struct ice_sched_node *tc_node,
- u16 vsi_id)
+ u16 vsi_handle)
{
struct ice_sched_node *node;
u8 vsi_layer;
@@ -1250,7 +1204,7 @@ ice_sched_get_vsi_node(struct ice_hw *hw, struct ice_sched_node *tc_node,
/* Check whether it already exists */
while (node) {
- if (node->vsi_id == vsi_id)
+ if (node->vsi_handle == vsi_handle)
return node;
node = node->sibling;
}
@@ -1278,10 +1232,8 @@ ice_sched_calc_vsi_child_nodes(struct ice_hw *hw, u16 num_qs, u16 *num_nodes)
/* calculate num nodes from q group to VSI layer */
for (i = qgl; i > vsil; i--) {
- u16 max_children = le16_to_cpu(hw->layer_info[i].max_children);
-
/* round to the next integer if there is a remainder */
- num = DIV_ROUND_UP(num, max_children);
+ num = DIV_ROUND_UP(num, hw->max_children[i]);
/* need at least one node */
num_nodes[i] = num ? num : 1;
@@ -1291,7 +1243,7 @@ ice_sched_calc_vsi_child_nodes(struct ice_hw *hw, u16 num_qs, u16 *num_nodes)
/**
* ice_sched_add_vsi_child_nodes - add VSI child nodes to tree
* @pi: port information structure
- * @vsi_id: VSI id
+ * @vsi_handle: software VSI handle
* @tc_node: pointer to the TC node
* @num_nodes: pointer to the num nodes that needs to be added per layer
* @owner: node owner (lan or rdma)
@@ -1300,7 +1252,7 @@ ice_sched_calc_vsi_child_nodes(struct ice_hw *hw, u16 num_qs, u16 *num_nodes)
* lan and rdma separately.
*/
static enum ice_status
-ice_sched_add_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_id,
+ice_sched_add_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_handle,
struct ice_sched_node *tc_node, u16 *num_nodes,
u8 owner)
{
@@ -1311,16 +1263,13 @@ ice_sched_add_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_id,
u16 num_added = 0;
u8 i, qgl, vsil;
- status = ice_sched_validate_for_max_nodes(pi, num_nodes);
- if (status)
- return status;
-
qgl = ice_sched_get_qgrp_layer(hw);
vsil = ice_sched_get_vsi_layer(hw);
- parent = ice_sched_get_vsi_node(hw, tc_node, vsi_id);
+ parent = ice_sched_get_vsi_node(hw, tc_node, vsi_handle);
for (i = vsil + 1; i <= qgl; i++) {
if (!parent)
return ICE_ERR_CFG;
+
status = ice_sched_add_nodes_to_layer(pi, tc_node, parent, i,
num_nodes[i],
&first_node_teid,
@@ -1398,8 +1347,8 @@ ice_sched_calc_vsi_support_nodes(struct ice_hw *hw,
struct ice_sched_node *tc_node, u16 *num_nodes)
{
struct ice_sched_node *node;
- u16 max_child;
- u8 i, vsil;
+ u8 vsil;
+ int i;
vsil = ice_sched_get_vsi_layer(hw);
for (i = vsil; i >= hw->sw_entry_point_layer; i--)
@@ -1412,12 +1361,10 @@ ice_sched_calc_vsi_support_nodes(struct ice_hw *hw,
/* If intermediate nodes are reached max children
* then add a new one.
*/
- node = ice_sched_get_first_node(hw, tc_node, i);
- max_child = le16_to_cpu(hw->layer_info[i].max_children);
-
+ node = ice_sched_get_first_node(hw, tc_node, (u8)i);
/* scan all the siblings */
while (node) {
- if (node->num_children < max_child)
+ if (node->num_children < hw->max_children[i])
break;
node = node->sibling;
}
@@ -1431,7 +1378,7 @@ ice_sched_calc_vsi_support_nodes(struct ice_hw *hw,
/**
* ice_sched_add_vsi_support_nodes - add VSI supported nodes into tx tree
* @pi: port information structure
- * @vsi_id: VSI Id
+ * @vsi_handle: software VSI handle
* @tc_node: pointer to TC node
* @num_nodes: pointer to num nodes array
*
@@ -1439,7 +1386,7 @@ ice_sched_calc_vsi_support_nodes(struct ice_hw *hw,
* VSI, its parent and intermediate nodes in below layers
*/
static enum ice_status
-ice_sched_add_vsi_support_nodes(struct ice_port_info *pi, u16 vsi_id,
+ice_sched_add_vsi_support_nodes(struct ice_port_info *pi, u16 vsi_handle,
struct ice_sched_node *tc_node, u16 *num_nodes)
{
struct ice_sched_node *parent = tc_node;
@@ -1451,10 +1398,6 @@ ice_sched_add_vsi_support_nodes(struct ice_port_info *pi, u16 vsi_id,
if (!pi)
return ICE_ERR_PARAM;
- status = ice_sched_validate_for_max_nodes(pi, num_nodes);
- if (status)
- return status;
-
vsil = ice_sched_get_vsi_layer(pi->hw);
for (i = pi->hw->sw_entry_point_layer; i <= vsil; i++) {
status = ice_sched_add_nodes_to_layer(pi, tc_node, parent,
@@ -1477,21 +1420,22 @@ ice_sched_add_vsi_support_nodes(struct ice_port_info *pi, u16 vsi_id,
return ICE_ERR_CFG;
if (i == vsil)
- parent->vsi_id = vsi_id;
+ parent->vsi_handle = vsi_handle;
}
+
return 0;
}
/**
* ice_sched_add_vsi_to_topo - add a new VSI into tree
* @pi: port information structure
- * @vsi_id: VSI Id
+ * @vsi_handle: software VSI handle
* @tc: TC number
*
* This function adds a new VSI into scheduler tree
*/
static enum ice_status
-ice_sched_add_vsi_to_topo(struct ice_port_info *pi, u16 vsi_id, u8 tc)
+ice_sched_add_vsi_to_topo(struct ice_port_info *pi, u16 vsi_handle, u8 tc)
{
u16 num_nodes[ICE_AQC_TOPO_MAX_LEVEL_NUM] = { 0 };
struct ice_sched_node *tc_node;
@@ -1505,13 +1449,14 @@ ice_sched_add_vsi_to_topo(struct ice_port_info *pi, u16 vsi_id, u8 tc)
ice_sched_calc_vsi_support_nodes(hw, tc_node, num_nodes);
/* add vsi supported nodes to tc subtree */
- return ice_sched_add_vsi_support_nodes(pi, vsi_id, tc_node, num_nodes);
+ return ice_sched_add_vsi_support_nodes(pi, vsi_handle, tc_node,
+ num_nodes);
}
/**
* ice_sched_update_vsi_child_nodes - update VSI child nodes
* @pi: port information structure
- * @vsi_id: VSI Id
+ * @vsi_handle: software VSI handle
* @tc: TC number
* @new_numqs: new number of max queues
* @owner: owner of this subtree
@@ -1519,14 +1464,14 @@ ice_sched_add_vsi_to_topo(struct ice_port_info *pi, u16 vsi_id, u8 tc)
* This function updates the VSI child nodes based on the number of queues
*/
static enum ice_status
-ice_sched_update_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_id, u8 tc,
- u16 new_numqs, u8 owner)
+ice_sched_update_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_handle,
+ u8 tc, u16 new_numqs, u8 owner)
{
u16 prev_num_nodes[ICE_AQC_TOPO_MAX_LEVEL_NUM] = { 0 };
u16 new_num_nodes[ICE_AQC_TOPO_MAX_LEVEL_NUM] = { 0 };
struct ice_sched_node *vsi_node;
struct ice_sched_node *tc_node;
- struct ice_sched_vsi_info *vsi;
+ struct ice_vsi_ctx *vsi_ctx;
enum ice_status status = 0;
struct ice_hw *hw = pi->hw;
u16 prev_numqs;
@@ -1536,16 +1481,16 @@ ice_sched_update_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_id, u8 tc,
if (!tc_node)
return ICE_ERR_CFG;
- vsi_node = ice_sched_get_vsi_node(hw, tc_node, vsi_id);
+ vsi_node = ice_sched_get_vsi_node(hw, tc_node, vsi_handle);
if (!vsi_node)
return ICE_ERR_CFG;
- vsi = ice_sched_get_vsi_info_entry(pi, vsi_id);
- if (!vsi)
- return ICE_ERR_CFG;
+ vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle);
+ if (!vsi_ctx)
+ return ICE_ERR_PARAM;
if (owner == ICE_SCHED_NODE_OWNER_LAN)
- prev_numqs = vsi->max_lanq[tc];
+ prev_numqs = vsi_ctx->sched.max_lanq[tc];
else
return ICE_ERR_PARAM;
@@ -1570,13 +1515,13 @@ ice_sched_update_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_id, u8 tc,
for (i = 0; i < ICE_AQC_TOPO_MAX_LEVEL_NUM; i++)
new_num_nodes[i] -= prev_num_nodes[i];
- status = ice_sched_add_vsi_child_nodes(pi, vsi_id, tc_node,
+ status = ice_sched_add_vsi_child_nodes(pi, vsi_handle, tc_node,
new_num_nodes, owner);
if (status)
return status;
}
- vsi->max_lanq[tc] = new_numqs;
+ vsi_ctx->sched.max_lanq[tc] = new_numqs;
return status;
}
@@ -1584,7 +1529,7 @@ ice_sched_update_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_id, u8 tc,
/**
* ice_sched_cfg_vsi - configure the new/exisiting VSI
* @pi: port information structure
- * @vsi_id: VSI Id
+ * @vsi_handle: software VSI handle
* @tc: TC number
* @maxqs: max number of queues
* @owner: lan or rdma
@@ -1595,25 +1540,21 @@ ice_sched_update_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_id, u8 tc,
* disabled then suspend the VSI if it is not already.
*/
enum ice_status
-ice_sched_cfg_vsi(struct ice_port_info *pi, u16 vsi_id, u8 tc, u16 maxqs,
+ice_sched_cfg_vsi(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u16 maxqs,
u8 owner, bool enable)
{
struct ice_sched_node *vsi_node, *tc_node;
- struct ice_sched_vsi_info *vsi;
+ struct ice_vsi_ctx *vsi_ctx;
enum ice_status status = 0;
struct ice_hw *hw = pi->hw;
tc_node = ice_sched_get_tc_node(pi, tc);
if (!tc_node)
return ICE_ERR_PARAM;
-
- vsi = ice_sched_get_vsi_info_entry(pi, vsi_id);
- if (!vsi)
- vsi = ice_sched_create_vsi_info_entry(pi, vsi_id);
- if (!vsi)
- return ICE_ERR_NO_MEMORY;
-
- vsi_node = ice_sched_get_vsi_node(hw, tc_node, vsi_id);
+ vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle);
+ if (!vsi_ctx)
+ return ICE_ERR_PARAM;
+ vsi_node = ice_sched_get_vsi_node(hw, tc_node, vsi_handle);
/* suspend the VSI if tc is not enabled */
if (!enable) {
@@ -1630,18 +1571,26 @@ ice_sched_cfg_vsi(struct ice_port_info *pi, u16 vsi_id, u8 tc, u16 maxqs,
/* TC is enabled, if it is a new VSI then add it to the tree */
if (!vsi_node) {
- status = ice_sched_add_vsi_to_topo(pi, vsi_id, tc);
+ status = ice_sched_add_vsi_to_topo(pi, vsi_handle, tc);
if (status)
return status;
- vsi_node = ice_sched_get_vsi_node(hw, tc_node, vsi_id);
+
+ vsi_node = ice_sched_get_vsi_node(hw, tc_node, vsi_handle);
if (!vsi_node)
return ICE_ERR_CFG;
- vsi->vsi_node[tc] = vsi_node;
+
+ vsi_ctx->sched.vsi_node[tc] = vsi_node;
vsi_node->in_use = true;
+ /* invalidate the max queues whenever VSI gets added first time
+ * into the scheduler tree (boot or after reset). We need to
+ * recreate the child nodes all the time in these cases.
+ */
+ vsi_ctx->sched.max_lanq[tc] = 0;
}
/* update the VSI child nodes */
- status = ice_sched_update_vsi_child_nodes(pi, vsi_id, tc, maxqs, owner);
+ status = ice_sched_update_vsi_child_nodes(pi, vsi_handle, tc, maxqs,
+ owner);
if (status)
return status;
diff --git a/drivers/net/ethernet/intel/ice/ice_sched.h b/drivers/net/ethernet/intel/ice/ice_sched.h
index badadcc120d3..5dc9cfa04c58 100644
--- a/drivers/net/ethernet/intel/ice/ice_sched.h
+++ b/drivers/net/ethernet/intel/ice/ice_sched.h
@@ -12,7 +12,6 @@
struct ice_sched_agg_vsi_info {
struct list_head list_entry;
DECLARE_BITMAP(tc_bitmap, ICE_MAX_TRAFFIC_CLASS);
- u16 vsi_id;
};
struct ice_sched_agg_info {
@@ -35,9 +34,9 @@ ice_sched_add_node(struct ice_port_info *pi, u8 layer,
void ice_free_sched_node(struct ice_port_info *pi, struct ice_sched_node *node);
struct ice_sched_node *ice_sched_get_tc_node(struct ice_port_info *pi, u8 tc);
struct ice_sched_node *
-ice_sched_get_free_qparent(struct ice_port_info *pi, u16 vsi_id, u8 tc,
+ice_sched_get_free_qparent(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
u8 owner);
enum ice_status
-ice_sched_cfg_vsi(struct ice_port_info *pi, u16 vsi_id, u8 tc, u16 maxqs,
+ice_sched_cfg_vsi(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u16 maxqs,
u8 owner, bool enable);
#endif /* _ICE_SCHED_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_sriov.c b/drivers/net/ethernet/intel/ice/ice_sriov.c
new file mode 100644
index 000000000000..027eba4e13f8
--- /dev/null
+++ b/drivers/net/ethernet/intel/ice/ice_sriov.c
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2018, Intel Corporation. */
+
+#include "ice_common.h"
+#include "ice_adminq_cmd.h"
+#include "ice_sriov.h"
+
+/**
+ * ice_aq_send_msg_to_vf
+ * @hw: pointer to the hardware structure
+ * @vfid: VF ID to send msg
+ * @v_opcode: opcodes for VF-PF communication
+ * @v_retval: return error code
+ * @msg: pointer to the msg buffer
+ * @msglen: msg length
+ * @cd: pointer to command details
+ *
+ * Send message to VF driver (0x0802) using mailbox
+ * queue and asynchronously sending message via
+ * ice_sq_send_cmd() function
+ */
+enum ice_status
+ice_aq_send_msg_to_vf(struct ice_hw *hw, u16 vfid, u32 v_opcode, u32 v_retval,
+ u8 *msg, u16 msglen, struct ice_sq_cd *cd)
+{
+ struct ice_aqc_pf_vf_msg *cmd;
+ struct ice_aq_desc desc;
+
+ ice_fill_dflt_direct_cmd_desc(&desc, ice_mbx_opc_send_msg_to_vf);
+
+ cmd = &desc.params.virt;
+ cmd->id = cpu_to_le32(vfid);
+
+ desc.cookie_high = cpu_to_le32(v_opcode);
+ desc.cookie_low = cpu_to_le32(v_retval);
+
+ if (msglen)
+ desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
+
+ return ice_sq_send_cmd(hw, &hw->mailboxq, &desc, msg, msglen, cd);
+}
+
+/**
+ * ice_conv_link_speed_to_virtchnl
+ * @adv_link_support: determines the format of the returned link speed
+ * @link_speed: variable containing the link_speed to be converted
+ *
+ * Convert link speed supported by HW to link speed supported by virtchnl.
+ * If adv_link_support is true, then return link speed in Mbps. Else return
+ * link speed as a VIRTCHNL_LINK_SPEED_* casted to a u32. Note that the caller
+ * needs to cast back to an enum virtchnl_link_speed in the case where
+ * adv_link_support is false, but when adv_link_support is true the caller can
+ * expect the speed in Mbps.
+ */
+u32 ice_conv_link_speed_to_virtchnl(bool adv_link_support, u16 link_speed)
+{
+ u32 speed;
+
+ if (adv_link_support)
+ switch (link_speed) {
+ case ICE_AQ_LINK_SPEED_10MB:
+ speed = ICE_LINK_SPEED_10MBPS;
+ break;
+ case ICE_AQ_LINK_SPEED_100MB:
+ speed = ICE_LINK_SPEED_100MBPS;
+ break;
+ case ICE_AQ_LINK_SPEED_1000MB:
+ speed = ICE_LINK_SPEED_1000MBPS;
+ break;
+ case ICE_AQ_LINK_SPEED_2500MB:
+ speed = ICE_LINK_SPEED_2500MBPS;
+ break;
+ case ICE_AQ_LINK_SPEED_5GB:
+ speed = ICE_LINK_SPEED_5000MBPS;
+ break;
+ case ICE_AQ_LINK_SPEED_10GB:
+ speed = ICE_LINK_SPEED_10000MBPS;
+ break;
+ case ICE_AQ_LINK_SPEED_20GB:
+ speed = ICE_LINK_SPEED_20000MBPS;
+ break;
+ case ICE_AQ_LINK_SPEED_25GB:
+ speed = ICE_LINK_SPEED_25000MBPS;
+ break;
+ case ICE_AQ_LINK_SPEED_40GB:
+ speed = ICE_LINK_SPEED_40000MBPS;
+ break;
+ default:
+ speed = ICE_LINK_SPEED_UNKNOWN;
+ break;
+ }
+ else
+ /* Virtchnl speeds are not defined for every speed supported in
+ * the hardware. To maintain compatibility with older AVF
+ * drivers, while reporting the speed the new speed values are
+ * resolved to the closest known virtchnl speeds
+ */
+ switch (link_speed) {
+ case ICE_AQ_LINK_SPEED_10MB:
+ case ICE_AQ_LINK_SPEED_100MB:
+ speed = (u32)VIRTCHNL_LINK_SPEED_100MB;
+ break;
+ case ICE_AQ_LINK_SPEED_1000MB:
+ case ICE_AQ_LINK_SPEED_2500MB:
+ case ICE_AQ_LINK_SPEED_5GB:
+ speed = (u32)VIRTCHNL_LINK_SPEED_1GB;
+ break;
+ case ICE_AQ_LINK_SPEED_10GB:
+ speed = (u32)VIRTCHNL_LINK_SPEED_10GB;
+ break;
+ case ICE_AQ_LINK_SPEED_20GB:
+ speed = (u32)VIRTCHNL_LINK_SPEED_20GB;
+ break;
+ case ICE_AQ_LINK_SPEED_25GB:
+ speed = (u32)VIRTCHNL_LINK_SPEED_25GB;
+ break;
+ case ICE_AQ_LINK_SPEED_40GB:
+ /* fall through */
+ speed = (u32)VIRTCHNL_LINK_SPEED_40GB;
+ break;
+ default:
+ speed = (u32)VIRTCHNL_LINK_SPEED_UNKNOWN;
+ break;
+ }
+
+ return speed;
+}
diff --git a/drivers/net/ethernet/intel/ice/ice_sriov.h b/drivers/net/ethernet/intel/ice/ice_sriov.h
new file mode 100644
index 000000000000..3d78a0795138
--- /dev/null
+++ b/drivers/net/ethernet/intel/ice/ice_sriov.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2018, Intel Corporation. */
+
+#ifndef _ICE_SRIOV_H_
+#define _ICE_SRIOV_H_
+
+#include "ice_common.h"
+
+#ifdef CONFIG_PCI_IOV
+enum ice_status
+ice_aq_send_msg_to_vf(struct ice_hw *hw, u16 vfid, u32 v_opcode, u32 v_retval,
+ u8 *msg, u16 msglen, struct ice_sq_cd *cd);
+
+u32 ice_conv_link_speed_to_virtchnl(bool adv_link_support, u16 link_speed);
+#else /* CONFIG_PCI_IOV */
+static inline enum ice_status
+ice_aq_send_msg_to_vf(struct ice_hw __always_unused *hw,
+ u16 __always_unused vfid, u32 __always_unused v_opcode,
+ u32 __always_unused v_retval, u8 __always_unused *msg,
+ u16 __always_unused msglen,
+ struct ice_sq_cd __always_unused *cd)
+{
+ return 0;
+}
+
+static inline u32
+ice_conv_link_speed_to_virtchnl(bool __always_unused adv_link_support,
+ u16 __always_unused link_speed)
+{
+ return 0;
+}
+
+#endif /* CONFIG_PCI_IOV */
+#endif /* _ICE_SRIOV_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_status.h b/drivers/net/ethernet/intel/ice/ice_status.h
index 9a95c4ffd7d7..f49f299ddf2c 100644
--- a/drivers/net/ethernet/intel/ice/ice_status.h
+++ b/drivers/net/ethernet/intel/ice/ice_status.h
@@ -6,6 +6,9 @@
/* Error Codes */
enum ice_status {
+ ICE_SUCCESS = 0,
+
+ /* Generic codes : Range -1..-49 */
ICE_ERR_PARAM = -1,
ICE_ERR_NOT_IMPL = -2,
ICE_ERR_NOT_READY = -3,
@@ -20,6 +23,7 @@ enum ice_status {
ICE_ERR_ALREADY_EXISTS = -14,
ICE_ERR_DOES_NOT_EXIST = -15,
ICE_ERR_MAX_LIMIT = -17,
+ ICE_ERR_RESET_ONGOING = -18,
ICE_ERR_BUF_TOO_SHORT = -52,
ICE_ERR_NVM_BLANK_MODE = -53,
ICE_ERR_AQ_ERROR = -100,
diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c
index 6b7ec2ae5ad6..40c9c6558956 100644
--- a/drivers/net/ethernet/intel/ice/ice_switch.c
+++ b/drivers/net/ethernet/intel/ice/ice_switch.c
@@ -86,6 +86,36 @@ ice_aq_alloc_free_res(struct ice_hw *hw, u16 num_entries,
}
/**
+ * ice_init_def_sw_recp - initialize the recipe book keeping tables
+ * @hw: pointer to the hw struct
+ *
+ * Allocate memory for the entire recipe table and initialize the structures/
+ * entries corresponding to basic recipes.
+ */
+enum ice_status
+ice_init_def_sw_recp(struct ice_hw *hw)
+{
+ struct ice_sw_recipe *recps;
+ u8 i;
+
+ recps = devm_kcalloc(ice_hw_to_dev(hw), ICE_MAX_NUM_RECIPES,
+ sizeof(struct ice_sw_recipe), GFP_KERNEL);
+ if (!recps)
+ return ICE_ERR_NO_MEMORY;
+
+ for (i = 0; i < ICE_SW_LKUP_LAST; i++) {
+ recps[i].root_rid = i;
+ INIT_LIST_HEAD(&recps[i].filt_rules);
+ INIT_LIST_HEAD(&recps[i].filt_replay_rules);
+ mutex_init(&recps[i].filt_rule_lock);
+ }
+
+ hw->switch_info->recp_list = recps;
+
+ return 0;
+}
+
+/**
* ice_aq_get_sw_cfg - get switch configuration
* @hw: pointer to the hardware structure
* @buf: pointer to the result buffer
@@ -140,23 +170,24 @@ ice_aq_get_sw_cfg(struct ice_hw *hw, struct ice_aqc_get_sw_cfg_resp *buf,
*
* Add a VSI context to the hardware (0x0210)
*/
-enum ice_status
+static enum ice_status
ice_aq_add_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,
struct ice_sq_cd *cd)
{
struct ice_aqc_add_update_free_vsi_resp *res;
struct ice_aqc_add_get_update_free_vsi *cmd;
- enum ice_status status;
struct ice_aq_desc desc;
+ enum ice_status status;
cmd = &desc.params.vsi_cmd;
- res = (struct ice_aqc_add_update_free_vsi_resp *)&desc.params.raw;
+ res = &desc.params.add_update_free_vsi_res;
ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_add_vsi);
if (!vsi_ctx->alloc_from_pool)
cmd->vsi_num = cpu_to_le16(vsi_ctx->vsi_num |
ICE_AQ_VSI_IS_VALID);
+ cmd->vf_id = vsi_ctx->vf_num;
cmd->vsi_flags = cpu_to_le16(vsi_ctx->flags);
@@ -175,6 +206,42 @@ ice_aq_add_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,
}
/**
+ * ice_aq_free_vsi
+ * @hw: pointer to the hw struct
+ * @vsi_ctx: pointer to a VSI context struct
+ * @keep_vsi_alloc: keep VSI allocation as part of this PF's resources
+ * @cd: pointer to command details structure or NULL
+ *
+ * Free VSI context info from hardware (0x0213)
+ */
+static enum ice_status
+ice_aq_free_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,
+ bool keep_vsi_alloc, struct ice_sq_cd *cd)
+{
+ struct ice_aqc_add_update_free_vsi_resp *resp;
+ struct ice_aqc_add_get_update_free_vsi *cmd;
+ struct ice_aq_desc desc;
+ enum ice_status status;
+
+ cmd = &desc.params.vsi_cmd;
+ resp = &desc.params.add_update_free_vsi_res;
+
+ ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_free_vsi);
+
+ cmd->vsi_num = cpu_to_le16(vsi_ctx->vsi_num | ICE_AQ_VSI_IS_VALID);
+ if (keep_vsi_alloc)
+ cmd->cmd_flags = cpu_to_le16(ICE_AQ_VSI_KEEP_ALLOC);
+
+ status = ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
+ if (!status) {
+ vsi_ctx->vsis_allocd = le16_to_cpu(resp->vsi_used);
+ vsi_ctx->vsis_unallocated = le16_to_cpu(resp->vsi_free);
+ }
+
+ return status;
+}
+
+/**
* ice_aq_update_vsi
* @hw: pointer to the hw struct
* @vsi_ctx: pointer to a VSI context struct
@@ -182,7 +249,7 @@ ice_aq_add_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,
*
* Update VSI context in the hardware (0x0211)
*/
-enum ice_status
+static enum ice_status
ice_aq_update_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,
struct ice_sq_cd *cd)
{
@@ -192,7 +259,7 @@ ice_aq_update_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,
enum ice_status status;
cmd = &desc.params.vsi_cmd;
- resp = (struct ice_aqc_add_update_free_vsi_resp *)&desc.params.raw;
+ resp = &desc.params.add_update_free_vsi_res;
ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_update_vsi);
@@ -212,42 +279,174 @@ ice_aq_update_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,
}
/**
- * ice_aq_free_vsi
+ * ice_is_vsi_valid - check whether the VSI is valid or not
+ * @hw: pointer to the hw struct
+ * @vsi_handle: VSI handle
+ *
+ * check whether the VSI is valid or not
+ */
+bool ice_is_vsi_valid(struct ice_hw *hw, u16 vsi_handle)
+{
+ return vsi_handle < ICE_MAX_VSI && hw->vsi_ctx[vsi_handle];
+}
+
+/**
+ * ice_get_hw_vsi_num - return the hw VSI number
+ * @hw: pointer to the hw struct
+ * @vsi_handle: VSI handle
+ *
+ * return the hw VSI number
+ * Caution: call this function only if VSI is valid (ice_is_vsi_valid)
+ */
+u16 ice_get_hw_vsi_num(struct ice_hw *hw, u16 vsi_handle)
+{
+ return hw->vsi_ctx[vsi_handle]->vsi_num;
+}
+
+/**
+ * ice_get_vsi_ctx - return the VSI context entry for a given VSI handle
+ * @hw: pointer to the hw struct
+ * @vsi_handle: VSI handle
+ *
+ * return the VSI context entry for a given VSI handle
+ */
+struct ice_vsi_ctx *ice_get_vsi_ctx(struct ice_hw *hw, u16 vsi_handle)
+{
+ return (vsi_handle >= ICE_MAX_VSI) ? NULL : hw->vsi_ctx[vsi_handle];
+}
+
+/**
+ * ice_save_vsi_ctx - save the VSI context for a given VSI handle
+ * @hw: pointer to the hw struct
+ * @vsi_handle: VSI handle
+ * @vsi: VSI context pointer
+ *
+ * save the VSI context entry for a given VSI handle
+ */
+static void ice_save_vsi_ctx(struct ice_hw *hw, u16 vsi_handle,
+ struct ice_vsi_ctx *vsi)
+{
+ hw->vsi_ctx[vsi_handle] = vsi;
+}
+
+/**
+ * ice_clear_vsi_ctx - clear the VSI context entry
+ * @hw: pointer to the hw struct
+ * @vsi_handle: VSI handle
+ *
+ * clear the VSI context entry
+ */
+static void ice_clear_vsi_ctx(struct ice_hw *hw, u16 vsi_handle)
+{
+ struct ice_vsi_ctx *vsi;
+
+ vsi = ice_get_vsi_ctx(hw, vsi_handle);
+ if (vsi) {
+ devm_kfree(ice_hw_to_dev(hw), vsi);
+ hw->vsi_ctx[vsi_handle] = NULL;
+ }
+}
+
+/**
+ * ice_clear_all_vsi_ctx - clear all the VSI context entries
+ * @hw: pointer to the hw struct
+ */
+void ice_clear_all_vsi_ctx(struct ice_hw *hw)
+{
+ u16 i;
+
+ for (i = 0; i < ICE_MAX_VSI; i++)
+ ice_clear_vsi_ctx(hw, i);
+}
+
+/**
+ * ice_add_vsi - add VSI context to the hardware and VSI handle list
* @hw: pointer to the hw struct
+ * @vsi_handle: unique VSI handle provided by drivers
* @vsi_ctx: pointer to a VSI context struct
- * @keep_vsi_alloc: keep VSI allocation as part of this PF's resources
* @cd: pointer to command details structure or NULL
*
- * Get VSI context info from hardware (0x0213)
+ * Add a VSI context to the hardware also add it into the VSI handle list.
+ * If this function gets called after reset for existing VSIs then update
+ * with the new HW VSI number in the corresponding VSI handle list entry.
*/
enum ice_status
-ice_aq_free_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,
- bool keep_vsi_alloc, struct ice_sq_cd *cd)
+ice_add_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx,
+ struct ice_sq_cd *cd)
{
- struct ice_aqc_add_update_free_vsi_resp *resp;
- struct ice_aqc_add_get_update_free_vsi *cmd;
- struct ice_aq_desc desc;
+ struct ice_vsi_ctx *tmp_vsi_ctx;
enum ice_status status;
- cmd = &desc.params.vsi_cmd;
- resp = (struct ice_aqc_add_update_free_vsi_resp *)&desc.params.raw;
-
- ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_free_vsi);
+ if (vsi_handle >= ICE_MAX_VSI)
+ return ICE_ERR_PARAM;
+ status = ice_aq_add_vsi(hw, vsi_ctx, cd);
+ if (status)
+ return status;
+ tmp_vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle);
+ if (!tmp_vsi_ctx) {
+ /* Create a new vsi context */
+ tmp_vsi_ctx = devm_kzalloc(ice_hw_to_dev(hw),
+ sizeof(*tmp_vsi_ctx), GFP_KERNEL);
+ if (!tmp_vsi_ctx) {
+ ice_aq_free_vsi(hw, vsi_ctx, false, cd);
+ return ICE_ERR_NO_MEMORY;
+ }
+ *tmp_vsi_ctx = *vsi_ctx;
+ ice_save_vsi_ctx(hw, vsi_handle, tmp_vsi_ctx);
+ } else {
+ /* update with new HW VSI num */
+ if (tmp_vsi_ctx->vsi_num != vsi_ctx->vsi_num)
+ tmp_vsi_ctx->vsi_num = vsi_ctx->vsi_num;
+ }
- cmd->vsi_num = cpu_to_le16(vsi_ctx->vsi_num | ICE_AQ_VSI_IS_VALID);
- if (keep_vsi_alloc)
- cmd->cmd_flags = cpu_to_le16(ICE_AQ_VSI_KEEP_ALLOC);
+ return status;
+}
- status = ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
- if (!status) {
- vsi_ctx->vsis_allocd = le16_to_cpu(resp->vsi_used);
- vsi_ctx->vsis_unallocated = le16_to_cpu(resp->vsi_free);
- }
+/**
+ * ice_free_vsi- free VSI context from hardware and VSI handle list
+ * @hw: pointer to the hw struct
+ * @vsi_handle: unique VSI handle
+ * @vsi_ctx: pointer to a VSI context struct
+ * @keep_vsi_alloc: keep VSI allocation as part of this PF's resources
+ * @cd: pointer to command details structure or NULL
+ *
+ * Free VSI context info from hardware as well as from VSI handle list
+ */
+enum ice_status
+ice_free_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx,
+ bool keep_vsi_alloc, struct ice_sq_cd *cd)
+{
+ enum ice_status status;
+ if (!ice_is_vsi_valid(hw, vsi_handle))
+ return ICE_ERR_PARAM;
+ vsi_ctx->vsi_num = ice_get_hw_vsi_num(hw, vsi_handle);
+ status = ice_aq_free_vsi(hw, vsi_ctx, keep_vsi_alloc, cd);
+ if (!status)
+ ice_clear_vsi_ctx(hw, vsi_handle);
return status;
}
/**
+ * ice_update_vsi
+ * @hw: pointer to the hw struct
+ * @vsi_handle: unique VSI handle
+ * @vsi_ctx: pointer to a VSI context struct
+ * @cd: pointer to command details structure or NULL
+ *
+ * Update VSI context in the hardware
+ */
+enum ice_status
+ice_update_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx,
+ struct ice_sq_cd *cd)
+{
+ if (!ice_is_vsi_valid(hw, vsi_handle))
+ return ICE_ERR_PARAM;
+ vsi_ctx->vsi_num = ice_get_hw_vsi_num(hw, vsi_handle);
+ return ice_aq_update_vsi(hw, vsi_ctx, cd);
+}
+
+/**
* ice_aq_alloc_free_vsi_list
* @hw: pointer to the hw struct
* @vsi_list_id: VSI list id returned or used for lookup
@@ -464,10 +663,12 @@ ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info,
struct ice_aqc_sw_rules_elem *s_rule, enum ice_adminq_opc opc)
{
u16 vlan_id = ICE_MAX_VLAN_ID + 1;
- u8 eth_hdr[DUMMY_ETH_HDR_LEN];
void *daddr = NULL;
+ u16 eth_hdr_sz;
+ u8 *eth_hdr;
u32 act = 0;
__be16 *off;
+ u8 q_rgn;
if (opc == ice_aqc_opc_remove_sw_rules) {
s_rule->pdata.lkup_tx_rx.act = 0;
@@ -477,13 +678,16 @@ ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info,
return;
}
+ eth_hdr_sz = sizeof(dummy_eth_header);
+ eth_hdr = s_rule->pdata.lkup_tx_rx.hdr;
+
/* initialize the ether header with a dummy header */
- memcpy(eth_hdr, dummy_eth_header, sizeof(dummy_eth_header));
+ memcpy(eth_hdr, dummy_eth_header, eth_hdr_sz);
ice_fill_sw_info(hw, f_info);
switch (f_info->fltr_act) {
case ICE_FWD_TO_VSI:
- act |= (f_info->fwd_id.vsi_id << ICE_SINGLE_ACT_VSI_ID_S) &
+ act |= (f_info->fwd_id.hw_vsi_id << ICE_SINGLE_ACT_VSI_ID_S) &
ICE_SINGLE_ACT_VSI_ID_M;
if (f_info->lkup_type != ICE_SW_LKUP_VLAN)
act |= ICE_SINGLE_ACT_VSI_FORWARDING |
@@ -503,14 +707,19 @@ ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info,
act |= (f_info->fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) &
ICE_SINGLE_ACT_Q_INDEX_M;
break;
+ case ICE_DROP_PACKET:
+ act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_DROP |
+ ICE_SINGLE_ACT_VALID_BIT;
+ break;
case ICE_FWD_TO_QGRP:
+ q_rgn = f_info->qgrp_size > 0 ?
+ (u8)ilog2(f_info->qgrp_size) : 0;
act |= ICE_SINGLE_ACT_TO_Q;
- act |= (f_info->qgrp_size << ICE_SINGLE_ACT_Q_REGION_S) &
+ act |= (f_info->fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) &
+ ICE_SINGLE_ACT_Q_INDEX_M;
+ act |= (q_rgn << ICE_SINGLE_ACT_Q_REGION_S) &
ICE_SINGLE_ACT_Q_REGION_M;
break;
- case ICE_DROP_PACKET:
- act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_DROP;
- break;
default:
return;
}
@@ -536,7 +745,7 @@ ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info,
daddr = f_info->l_data.ethertype_mac.mac_addr;
/* fall-through */
case ICE_SW_LKUP_ETHERTYPE:
- off = (__be16 *)&eth_hdr[ICE_ETH_ETHTYPE_OFFSET];
+ off = (__be16 *)(eth_hdr + ICE_ETH_ETHTYPE_OFFSET);
*off = cpu_to_be16(f_info->l_data.ethertype_mac.ethertype);
break;
case ICE_SW_LKUP_MAC_VLAN:
@@ -563,18 +772,16 @@ ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info,
s_rule->pdata.lkup_tx_rx.act = cpu_to_le32(act);
if (daddr)
- ether_addr_copy(&eth_hdr[ICE_ETH_DA_OFFSET], daddr);
+ ether_addr_copy(eth_hdr + ICE_ETH_DA_OFFSET, daddr);
if (!(vlan_id > ICE_MAX_VLAN_ID)) {
- off = (__be16 *)&eth_hdr[ICE_ETH_VLAN_TCI_OFFSET];
+ off = (__be16 *)(eth_hdr + ICE_ETH_VLAN_TCI_OFFSET);
*off = cpu_to_be16(vlan_id);
}
/* Create the switch rule with the final dummy Ethernet header */
if (opc != ice_aqc_opc_update_sw_rules)
- s_rule->pdata.lkup_tx_rx.hdr_len = cpu_to_le16(sizeof(eth_hdr));
-
- memcpy(s_rule->pdata.lkup_tx_rx.hdr, eth_hdr, sizeof(eth_hdr));
+ s_rule->pdata.lkup_tx_rx.hdr_len = cpu_to_le16(eth_hdr_sz);
}
/**
@@ -601,8 +808,8 @@ ice_add_marker_act(struct ice_hw *hw, struct ice_fltr_mgmt_list_entry *m_ent,
enum ice_status status;
u16 lg_act_size;
u16 rules_size;
- u16 vsi_info;
u32 act;
+ u16 id;
if (m_ent->fltr_info.lkup_type != ICE_SW_LKUP_MAC)
return ICE_ERR_PARAM;
@@ -628,12 +835,11 @@ ice_add_marker_act(struct ice_hw *hw, struct ice_fltr_mgmt_list_entry *m_ent,
/* First action VSI forwarding or VSI list forwarding depending on how
* many VSIs
*/
- vsi_info = (m_ent->vsi_count > 1) ?
- m_ent->fltr_info.fwd_id.vsi_list_id :
- m_ent->fltr_info.fwd_id.vsi_id;
+ id = (m_ent->vsi_count > 1) ? m_ent->fltr_info.fwd_id.vsi_list_id :
+ m_ent->fltr_info.fwd_id.hw_vsi_id;
act = ICE_LG_ACT_VSI_FORWARDING | ICE_LG_ACT_VALID_BIT;
- act |= (vsi_info << ICE_LG_ACT_VSI_LIST_ID_S) &
+ act |= (id << ICE_LG_ACT_VSI_LIST_ID_S) &
ICE_LG_ACT_VSI_LIST_ID_M;
if (m_ent->vsi_count > 1)
act |= ICE_LG_ACT_VSI_LIST;
@@ -686,15 +892,15 @@ ice_add_marker_act(struct ice_hw *hw, struct ice_fltr_mgmt_list_entry *m_ent,
/**
* ice_create_vsi_list_map
* @hw: pointer to the hardware structure
- * @vsi_array: array of VSIs to form a VSI list
- * @num_vsi: num VSI in the array
+ * @vsi_handle_arr: array of VSI handles to set in the VSI mapping
+ * @num_vsi: number of VSI handles in the array
* @vsi_list_id: VSI list id generated as part of allocate resource
*
* Helper function to create a new entry of VSI list id to VSI mapping
* using the given VSI list id
*/
static struct ice_vsi_list_map_info *
-ice_create_vsi_list_map(struct ice_hw *hw, u16 *vsi_array, u16 num_vsi,
+ice_create_vsi_list_map(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi,
u16 vsi_list_id)
{
struct ice_switch_info *sw = hw->switch_info;
@@ -706,9 +912,9 @@ ice_create_vsi_list_map(struct ice_hw *hw, u16 *vsi_array, u16 num_vsi,
return NULL;
v_map->vsi_list_id = vsi_list_id;
-
+ v_map->ref_cnt = 1;
for (i = 0; i < num_vsi; i++)
- set_bit(vsi_array[i], v_map->vsi_map);
+ set_bit(vsi_handle_arr[i], v_map->vsi_map);
list_add(&v_map->list_entry, &sw->vsi_list_map_head);
return v_map;
@@ -717,8 +923,8 @@ ice_create_vsi_list_map(struct ice_hw *hw, u16 *vsi_array, u16 num_vsi,
/**
* ice_update_vsi_list_rule
* @hw: pointer to the hardware structure
- * @vsi_array: array of VSIs to form a VSI list
- * @num_vsi: num VSI in the array
+ * @vsi_handle_arr: array of VSI handles to form a VSI list
+ * @num_vsi: number of VSI handles in the array
* @vsi_list_id: VSI list id generated as part of allocate resource
* @remove: Boolean value to indicate if this is a remove action
* @opc: switch rules population command type - pass in the command opcode
@@ -728,7 +934,7 @@ ice_create_vsi_list_map(struct ice_hw *hw, u16 *vsi_array, u16 num_vsi,
* using the given VSI list id
*/
static enum ice_status
-ice_update_vsi_list_rule(struct ice_hw *hw, u16 *vsi_array, u16 num_vsi,
+ice_update_vsi_list_rule(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi,
u16 vsi_list_id, bool remove, enum ice_adminq_opc opc,
enum ice_sw_lkup_type lkup_type)
{
@@ -759,9 +965,15 @@ ice_update_vsi_list_rule(struct ice_hw *hw, u16 *vsi_array, u16 num_vsi,
s_rule = devm_kzalloc(ice_hw_to_dev(hw), s_rule_size, GFP_KERNEL);
if (!s_rule)
return ICE_ERR_NO_MEMORY;
-
- for (i = 0; i < num_vsi; i++)
- s_rule->pdata.vsi_list.vsi[i] = cpu_to_le16(vsi_array[i]);
+ for (i = 0; i < num_vsi; i++) {
+ if (!ice_is_vsi_valid(hw, vsi_handle_arr[i])) {
+ status = ICE_ERR_PARAM;
+ goto exit;
+ }
+ /* AQ call requires hw_vsi_id(s) */
+ s_rule->pdata.vsi_list.vsi[i] =
+ cpu_to_le16(ice_get_hw_vsi_num(hw, vsi_handle_arr[i]));
+ }
s_rule->type = cpu_to_le16(type);
s_rule->pdata.vsi_list.number_vsi = cpu_to_le16(num_vsi);
@@ -769,6 +981,7 @@ ice_update_vsi_list_rule(struct ice_hw *hw, u16 *vsi_array, u16 num_vsi,
status = ice_aq_sw_rules(hw, s_rule, s_rule_size, 1, opc, NULL);
+exit:
devm_kfree(ice_hw_to_dev(hw), s_rule);
return status;
}
@@ -776,21 +989,16 @@ ice_update_vsi_list_rule(struct ice_hw *hw, u16 *vsi_array, u16 num_vsi,
/**
* ice_create_vsi_list_rule - Creates and populates a VSI list rule
* @hw: pointer to the hw struct
- * @vsi_array: array of VSIs to form a VSI list
- * @num_vsi: number of VSIs in the array
+ * @vsi_handle_arr: array of VSI handles to form a VSI list
+ * @num_vsi: number of VSI handles in the array
* @vsi_list_id: stores the ID of the VSI list to be created
* @lkup_type: switch rule filter's lookup type
*/
static enum ice_status
-ice_create_vsi_list_rule(struct ice_hw *hw, u16 *vsi_array, u16 num_vsi,
+ice_create_vsi_list_rule(struct ice_hw *hw, u16 *vsi_handle_arr, u16 num_vsi,
u16 *vsi_list_id, enum ice_sw_lkup_type lkup_type)
{
enum ice_status status;
- int i;
-
- for (i = 0; i < num_vsi; i++)
- if (vsi_array[i] >= ICE_MAX_VSI)
- return ICE_ERR_OUT_OF_RANGE;
status = ice_aq_alloc_free_vsi_list(hw, vsi_list_id, lkup_type,
ice_aqc_opc_alloc_res);
@@ -798,9 +1006,9 @@ ice_create_vsi_list_rule(struct ice_hw *hw, u16 *vsi_array, u16 num_vsi,
return status;
/* Update the newly created VSI list to include the specified VSIs */
- return ice_update_vsi_list_rule(hw, vsi_array, num_vsi, *vsi_list_id,
- false, ice_aqc_opc_add_sw_rules,
- lkup_type);
+ return ice_update_vsi_list_rule(hw, vsi_handle_arr, num_vsi,
+ *vsi_list_id, false,
+ ice_aqc_opc_add_sw_rules, lkup_type);
}
/**
@@ -816,10 +1024,10 @@ static enum ice_status
ice_create_pkt_fwd_rule(struct ice_hw *hw,
struct ice_fltr_list_entry *f_entry)
{
- struct ice_switch_info *sw = hw->switch_info;
struct ice_fltr_mgmt_list_entry *fm_entry;
struct ice_aqc_sw_rules_elem *s_rule;
enum ice_sw_lkup_type l_type;
+ struct ice_sw_recipe *recp;
enum ice_status status;
s_rule = devm_kzalloc(ice_hw_to_dev(hw),
@@ -860,31 +1068,9 @@ ice_create_pkt_fwd_rule(struct ice_hw *hw,
* calls remove filter AQ command
*/
l_type = fm_entry->fltr_info.lkup_type;
- if (l_type == ICE_SW_LKUP_MAC) {
- mutex_lock(&sw->mac_list_lock);
- list_add(&fm_entry->list_entry, &sw->mac_list_head);
- mutex_unlock(&sw->mac_list_lock);
- } else if (l_type == ICE_SW_LKUP_VLAN) {
- mutex_lock(&sw->vlan_list_lock);
- list_add(&fm_entry->list_entry, &sw->vlan_list_head);
- mutex_unlock(&sw->vlan_list_lock);
- } else if (l_type == ICE_SW_LKUP_ETHERTYPE ||
- l_type == ICE_SW_LKUP_ETHERTYPE_MAC) {
- mutex_lock(&sw->eth_m_list_lock);
- list_add(&fm_entry->list_entry, &sw->eth_m_list_head);
- mutex_unlock(&sw->eth_m_list_lock);
- } else if (l_type == ICE_SW_LKUP_PROMISC ||
- l_type == ICE_SW_LKUP_PROMISC_VLAN) {
- mutex_lock(&sw->promisc_list_lock);
- list_add(&fm_entry->list_entry, &sw->promisc_list_head);
- mutex_unlock(&sw->promisc_list_lock);
- } else if (fm_entry->fltr_info.lkup_type == ICE_SW_LKUP_MAC_VLAN) {
- mutex_lock(&sw->mac_vlan_list_lock);
- list_add(&fm_entry->list_entry, &sw->mac_vlan_list_head);
- mutex_unlock(&sw->mac_vlan_list_lock);
- } else {
- status = ICE_ERR_NOT_IMPL;
- }
+ recp = &hw->switch_info->recp_list[l_type];
+ list_add(&fm_entry->list_entry, &recp->filt_rules);
+
ice_create_pkt_fwd_rule_exit:
devm_kfree(ice_hw_to_dev(hw), s_rule);
return status;
@@ -893,19 +1079,15 @@ ice_create_pkt_fwd_rule_exit:
/**
* ice_update_pkt_fwd_rule
* @hw: pointer to the hardware structure
- * @rule_id: rule of previously created switch rule to update
- * @vsi_list_id: VSI list id to be updated with
- * @f_info: ice_fltr_info to pull other information for switch rule
+ * @f_info: filter information for switch rule
*
* Call AQ command to update a previously created switch rule with a
* VSI list id
*/
static enum ice_status
-ice_update_pkt_fwd_rule(struct ice_hw *hw, u16 rule_id, u16 vsi_list_id,
- struct ice_fltr_info f_info)
+ice_update_pkt_fwd_rule(struct ice_hw *hw, struct ice_fltr_info *f_info)
{
struct ice_aqc_sw_rules_elem *s_rule;
- struct ice_fltr_info tmp_fltr;
enum ice_status status;
s_rule = devm_kzalloc(ice_hw_to_dev(hw),
@@ -913,14 +1095,9 @@ ice_update_pkt_fwd_rule(struct ice_hw *hw, u16 rule_id, u16 vsi_list_id,
if (!s_rule)
return ICE_ERR_NO_MEMORY;
- tmp_fltr = f_info;
- tmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST;
- tmp_fltr.fwd_id.vsi_list_id = vsi_list_id;
-
- ice_fill_sw_rule(hw, &tmp_fltr, s_rule,
- ice_aqc_opc_update_sw_rules);
+ ice_fill_sw_rule(hw, f_info, s_rule, ice_aqc_opc_update_sw_rules);
- s_rule->pdata.lkup_tx_rx.index = cpu_to_le16(rule_id);
+ s_rule->pdata.lkup_tx_rx.index = cpu_to_le16(f_info->fltr_rule_id);
/* Update switch rule with new rule set to forward VSI list */
status = ice_aq_sw_rules(hw, s_rule, ICE_SW_RULE_RX_TX_ETH_HDR_SIZE, 1,
@@ -931,7 +1108,48 @@ ice_update_pkt_fwd_rule(struct ice_hw *hw, u16 rule_id, u16 vsi_list_id,
}
/**
- * ice_handle_vsi_list_mgmt
+ * ice_update_sw_rule_bridge_mode
+ * @hw: pointer to the hw struct
+ *
+ * Updates unicast switch filter rules based on VEB/VEPA mode
+ */
+enum ice_status ice_update_sw_rule_bridge_mode(struct ice_hw *hw)
+{
+ struct ice_switch_info *sw = hw->switch_info;
+ struct ice_fltr_mgmt_list_entry *fm_entry;
+ enum ice_status status = 0;
+ struct list_head *rule_head;
+ struct mutex *rule_lock; /* Lock to protect filter rule list */
+
+ rule_lock = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rule_lock;
+ rule_head = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rules;
+
+ mutex_lock(rule_lock);
+ list_for_each_entry(fm_entry, rule_head, list_entry) {
+ struct ice_fltr_info *fi = &fm_entry->fltr_info;
+ u8 *addr = fi->l_data.mac.mac_addr;
+
+ /* Update unicast Tx rules to reflect the selected
+ * VEB/VEPA mode
+ */
+ if ((fi->flag & ICE_FLTR_TX) && is_unicast_ether_addr(addr) &&
+ (fi->fltr_act == ICE_FWD_TO_VSI ||
+ fi->fltr_act == ICE_FWD_TO_VSI_LIST ||
+ fi->fltr_act == ICE_FWD_TO_Q ||
+ fi->fltr_act == ICE_FWD_TO_QGRP)) {
+ status = ice_update_pkt_fwd_rule(hw, fi);
+ if (status)
+ break;
+ }
+ }
+
+ mutex_unlock(rule_lock);
+
+ return status;
+}
+
+/**
+ * ice_add_update_vsi_list
* @hw: pointer to the hardware structure
* @m_entry: pointer to current filter management list entry
* @cur_fltr: filter information from the book keeping entry
@@ -952,10 +1170,10 @@ ice_update_pkt_fwd_rule(struct ice_hw *hw, u16 rule_id, u16 vsi_list_id,
* using the update switch rule command
*/
static enum ice_status
-ice_handle_vsi_list_mgmt(struct ice_hw *hw,
- struct ice_fltr_mgmt_list_entry *m_entry,
- struct ice_fltr_info *cur_fltr,
- struct ice_fltr_info *new_fltr)
+ice_add_update_vsi_list(struct ice_hw *hw,
+ struct ice_fltr_mgmt_list_entry *m_entry,
+ struct ice_fltr_info *cur_fltr,
+ struct ice_fltr_info *new_fltr)
{
enum ice_status status = 0;
u16 vsi_list_id = 0;
@@ -975,34 +1193,36 @@ ice_handle_vsi_list_mgmt(struct ice_hw *hw,
* a part of a VSI list. So, create a VSI list with the old and
* new VSIs.
*/
- u16 vsi_id_arr[2];
- u16 fltr_rule;
+ struct ice_fltr_info tmp_fltr;
+ u16 vsi_handle_arr[2];
/* A rule already exists with the new VSI being added */
- if (cur_fltr->fwd_id.vsi_id == new_fltr->fwd_id.vsi_id)
+ if (cur_fltr->fwd_id.hw_vsi_id == new_fltr->fwd_id.hw_vsi_id)
return ICE_ERR_ALREADY_EXISTS;
- vsi_id_arr[0] = cur_fltr->fwd_id.vsi_id;
- vsi_id_arr[1] = new_fltr->fwd_id.vsi_id;
- status = ice_create_vsi_list_rule(hw, &vsi_id_arr[0], 2,
+ vsi_handle_arr[0] = cur_fltr->vsi_handle;
+ vsi_handle_arr[1] = new_fltr->vsi_handle;
+ status = ice_create_vsi_list_rule(hw, &vsi_handle_arr[0], 2,
&vsi_list_id,
new_fltr->lkup_type);
if (status)
return status;
- fltr_rule = cur_fltr->fltr_rule_id;
+ tmp_fltr = *new_fltr;
+ tmp_fltr.fltr_rule_id = cur_fltr->fltr_rule_id;
+ tmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST;
+ tmp_fltr.fwd_id.vsi_list_id = vsi_list_id;
/* Update the previous switch rule of "MAC forward to VSI" to
* "MAC fwd to VSI list"
*/
- status = ice_update_pkt_fwd_rule(hw, fltr_rule, vsi_list_id,
- *new_fltr);
+ status = ice_update_pkt_fwd_rule(hw, &tmp_fltr);
if (status)
return status;
cur_fltr->fwd_id.vsi_list_id = vsi_list_id;
cur_fltr->fltr_act = ICE_FWD_TO_VSI_LIST;
m_entry->vsi_list_info =
- ice_create_vsi_list_map(hw, &vsi_id_arr[0], 2,
+ ice_create_vsi_list_map(hw, &vsi_handle_arr[0], 2,
vsi_list_id);
/* If this entry was large action then the large action needs
@@ -1014,11 +1234,11 @@ ice_handle_vsi_list_mgmt(struct ice_hw *hw,
m_entry->sw_marker_id,
m_entry->lg_act_idx);
} else {
- u16 vsi_id = new_fltr->fwd_id.vsi_id;
+ u16 vsi_handle = new_fltr->vsi_handle;
enum ice_adminq_opc opcode;
/* A rule already exists with the new VSI being added */
- if (test_bit(vsi_id, m_entry->vsi_list_info->vsi_map))
+ if (test_bit(vsi_handle, m_entry->vsi_list_info->vsi_map))
return 0;
/* Update the previously created VSI list set with
@@ -1027,12 +1247,12 @@ ice_handle_vsi_list_mgmt(struct ice_hw *hw,
vsi_list_id = cur_fltr->fwd_id.vsi_list_id;
opcode = ice_aqc_opc_update_sw_rules;
- status = ice_update_vsi_list_rule(hw, &vsi_id, 1, vsi_list_id,
- false, opcode,
+ status = ice_update_vsi_list_rule(hw, &vsi_handle, 1,
+ vsi_list_id, false, opcode,
new_fltr->lkup_type);
/* update VSI list mapping info with new VSI id */
if (!status)
- set_bit(vsi_id, m_entry->vsi_list_info->vsi_map);
+ set_bit(vsi_handle, m_entry->vsi_list_info->vsi_map);
}
if (!status)
m_entry->vsi_count++;
@@ -1040,54 +1260,313 @@ ice_handle_vsi_list_mgmt(struct ice_hw *hw,
}
/**
- * ice_find_mac_entry
+ * ice_find_rule_entry - Search a rule entry
* @hw: pointer to the hardware structure
- * @mac_addr: MAC address to search for
+ * @recp_id: lookup type for which the specified rule needs to be searched
+ * @f_info: rule information
*
- * Helper function to search for a MAC entry using a given MAC address
- * Returns pointer to the entry if found.
+ * Helper function to search for a given rule entry
+ * Returns pointer to entry storing the rule if found
*/
static struct ice_fltr_mgmt_list_entry *
-ice_find_mac_entry(struct ice_hw *hw, u8 *mac_addr)
+ice_find_rule_entry(struct ice_hw *hw, u8 recp_id, struct ice_fltr_info *f_info)
{
- struct ice_fltr_mgmt_list_entry *m_list_itr, *mac_ret = NULL;
+ struct ice_fltr_mgmt_list_entry *list_itr, *ret = NULL;
struct ice_switch_info *sw = hw->switch_info;
-
- mutex_lock(&sw->mac_list_lock);
- list_for_each_entry(m_list_itr, &sw->mac_list_head, list_entry) {
- u8 *buf = &m_list_itr->fltr_info.l_data.mac.mac_addr[0];
-
- if (ether_addr_equal(buf, mac_addr)) {
- mac_ret = m_list_itr;
+ struct list_head *list_head;
+
+ list_head = &sw->recp_list[recp_id].filt_rules;
+ list_for_each_entry(list_itr, list_head, list_entry) {
+ if (!memcmp(&f_info->l_data, &list_itr->fltr_info.l_data,
+ sizeof(f_info->l_data)) &&
+ f_info->flag == list_itr->fltr_info.flag) {
+ ret = list_itr;
break;
}
}
- mutex_unlock(&sw->mac_list_lock);
- return mac_ret;
+ return ret;
+}
+
+/**
+ * ice_find_vsi_list_entry - Search VSI list map with VSI count 1
+ * @hw: pointer to the hardware structure
+ * @recp_id: lookup type for which VSI lists needs to be searched
+ * @vsi_handle: VSI handle to be found in VSI list
+ * @vsi_list_id: VSI list id found containing vsi_handle
+ *
+ * Helper function to search a VSI list with single entry containing given VSI
+ * handle element. This can be extended further to search VSI list with more
+ * than 1 vsi_count. Returns pointer to VSI list entry if found.
+ */
+static struct ice_vsi_list_map_info *
+ice_find_vsi_list_entry(struct ice_hw *hw, u8 recp_id, u16 vsi_handle,
+ u16 *vsi_list_id)
+{
+ struct ice_vsi_list_map_info *map_info = NULL;
+ struct ice_switch_info *sw = hw->switch_info;
+ struct ice_fltr_mgmt_list_entry *list_itr;
+ struct list_head *list_head;
+
+ list_head = &sw->recp_list[recp_id].filt_rules;
+ list_for_each_entry(list_itr, list_head, list_entry) {
+ if (list_itr->vsi_count == 1 && list_itr->vsi_list_info) {
+ map_info = list_itr->vsi_list_info;
+ if (test_bit(vsi_handle, map_info->vsi_map)) {
+ *vsi_list_id = map_info->vsi_list_id;
+ return map_info;
+ }
+ }
+ }
+ return NULL;
}
/**
- * ice_add_shared_mac - Add one MAC shared filter rule
+ * ice_add_rule_internal - add rule for a given lookup type
* @hw: pointer to the hardware structure
+ * @recp_id: lookup type (recipe id) for which rule has to be added
* @f_entry: structure containing MAC forwarding information
*
- * Adds or updates the book keeping list for the MAC addresses
+ * Adds or updates the rule lists for a given recipe
*/
static enum ice_status
-ice_add_shared_mac(struct ice_hw *hw, struct ice_fltr_list_entry *f_entry)
+ice_add_rule_internal(struct ice_hw *hw, u8 recp_id,
+ struct ice_fltr_list_entry *f_entry)
{
+ struct ice_switch_info *sw = hw->switch_info;
struct ice_fltr_info *new_fltr, *cur_fltr;
struct ice_fltr_mgmt_list_entry *m_entry;
+ struct mutex *rule_lock; /* Lock to protect filter rule list */
+ enum ice_status status = 0;
- new_fltr = &f_entry->fltr_info;
+ if (!ice_is_vsi_valid(hw, f_entry->fltr_info.vsi_handle))
+ return ICE_ERR_PARAM;
+ f_entry->fltr_info.fwd_id.hw_vsi_id =
+ ice_get_hw_vsi_num(hw, f_entry->fltr_info.vsi_handle);
- m_entry = ice_find_mac_entry(hw, &new_fltr->l_data.mac.mac_addr[0]);
- if (!m_entry)
+ rule_lock = &sw->recp_list[recp_id].filt_rule_lock;
+
+ mutex_lock(rule_lock);
+ new_fltr = &f_entry->fltr_info;
+ if (new_fltr->flag & ICE_FLTR_RX)
+ new_fltr->src = hw->port_info->lport;
+ else if (new_fltr->flag & ICE_FLTR_TX)
+ new_fltr->src = f_entry->fltr_info.fwd_id.hw_vsi_id;
+
+ m_entry = ice_find_rule_entry(hw, recp_id, new_fltr);
+ if (!m_entry) {
+ mutex_unlock(rule_lock);
return ice_create_pkt_fwd_rule(hw, f_entry);
+ }
cur_fltr = &m_entry->fltr_info;
+ status = ice_add_update_vsi_list(hw, m_entry, cur_fltr, new_fltr);
+ mutex_unlock(rule_lock);
+
+ return status;
+}
+
+/**
+ * ice_remove_vsi_list_rule
+ * @hw: pointer to the hardware structure
+ * @vsi_list_id: VSI list id generated as part of allocate resource
+ * @lkup_type: switch rule filter lookup type
+ *
+ * The VSI list should be emptied before this function is called to remove the
+ * VSI list.
+ */
+static enum ice_status
+ice_remove_vsi_list_rule(struct ice_hw *hw, u16 vsi_list_id,
+ enum ice_sw_lkup_type lkup_type)
+{
+ struct ice_aqc_sw_rules_elem *s_rule;
+ enum ice_status status;
+ u16 s_rule_size;
+
+ s_rule_size = (u16)ICE_SW_RULE_VSI_LIST_SIZE(0);
+ s_rule = devm_kzalloc(ice_hw_to_dev(hw), s_rule_size, GFP_KERNEL);
+ if (!s_rule)
+ return ICE_ERR_NO_MEMORY;
+
+ s_rule->type = cpu_to_le16(ICE_AQC_SW_RULES_T_VSI_LIST_CLEAR);
+ s_rule->pdata.vsi_list.index = cpu_to_le16(vsi_list_id);
+
+ /* Free the vsi_list resource that we allocated. It is assumed that the
+ * list is empty at this point.
+ */
+ status = ice_aq_alloc_free_vsi_list(hw, &vsi_list_id, lkup_type,
+ ice_aqc_opc_free_res);
- return ice_handle_vsi_list_mgmt(hw, m_entry, cur_fltr, new_fltr);
+ devm_kfree(ice_hw_to_dev(hw), s_rule);
+ return status;
+}
+
+/**
+ * ice_rem_update_vsi_list
+ * @hw: pointer to the hardware structure
+ * @vsi_handle: VSI handle of the VSI to remove
+ * @fm_list: filter management entry for which the VSI list management needs to
+ * be done
+ */
+static enum ice_status
+ice_rem_update_vsi_list(struct ice_hw *hw, u16 vsi_handle,
+ struct ice_fltr_mgmt_list_entry *fm_list)
+{
+ enum ice_sw_lkup_type lkup_type;
+ enum ice_status status = 0;
+ u16 vsi_list_id;
+
+ if (fm_list->fltr_info.fltr_act != ICE_FWD_TO_VSI_LIST ||
+ fm_list->vsi_count == 0)
+ return ICE_ERR_PARAM;
+
+ /* A rule with the VSI being removed does not exist */
+ if (!test_bit(vsi_handle, fm_list->vsi_list_info->vsi_map))
+ return ICE_ERR_DOES_NOT_EXIST;
+
+ lkup_type = fm_list->fltr_info.lkup_type;
+ vsi_list_id = fm_list->fltr_info.fwd_id.vsi_list_id;
+ status = ice_update_vsi_list_rule(hw, &vsi_handle, 1, vsi_list_id, true,
+ ice_aqc_opc_update_sw_rules,
+ lkup_type);
+ if (status)
+ return status;
+
+ fm_list->vsi_count--;
+ clear_bit(vsi_handle, fm_list->vsi_list_info->vsi_map);
+
+ if (fm_list->vsi_count == 1 && lkup_type != ICE_SW_LKUP_VLAN) {
+ struct ice_fltr_info tmp_fltr_info = fm_list->fltr_info;
+ struct ice_vsi_list_map_info *vsi_list_info =
+ fm_list->vsi_list_info;
+ u16 rem_vsi_handle;
+
+ rem_vsi_handle = find_first_bit(vsi_list_info->vsi_map,
+ ICE_MAX_VSI);
+ if (!ice_is_vsi_valid(hw, rem_vsi_handle))
+ return ICE_ERR_OUT_OF_RANGE;
+
+ /* Make sure VSI list is empty before removing it below */
+ status = ice_update_vsi_list_rule(hw, &rem_vsi_handle, 1,
+ vsi_list_id, true,
+ ice_aqc_opc_update_sw_rules,
+ lkup_type);
+ if (status)
+ return status;
+
+ tmp_fltr_info.fltr_act = ICE_FWD_TO_VSI;
+ tmp_fltr_info.fwd_id.hw_vsi_id =
+ ice_get_hw_vsi_num(hw, rem_vsi_handle);
+ tmp_fltr_info.vsi_handle = rem_vsi_handle;
+ status = ice_update_pkt_fwd_rule(hw, &tmp_fltr_info);
+ if (status) {
+ ice_debug(hw, ICE_DBG_SW,
+ "Failed to update pkt fwd rule to FWD_TO_VSI on HW VSI %d, error %d\n",
+ tmp_fltr_info.fwd_id.hw_vsi_id, status);
+ return status;
+ }
+
+ fm_list->fltr_info = tmp_fltr_info;
+ }
+
+ if ((fm_list->vsi_count == 1 && lkup_type != ICE_SW_LKUP_VLAN) ||
+ (fm_list->vsi_count == 0 && lkup_type == ICE_SW_LKUP_VLAN)) {
+ struct ice_vsi_list_map_info *vsi_list_info =
+ fm_list->vsi_list_info;
+
+ /* Remove the VSI list since it is no longer used */
+ status = ice_remove_vsi_list_rule(hw, vsi_list_id, lkup_type);
+ if (status) {
+ ice_debug(hw, ICE_DBG_SW,
+ "Failed to remove VSI list %d, error %d\n",
+ vsi_list_id, status);
+ return status;
+ }
+
+ list_del(&vsi_list_info->list_entry);
+ devm_kfree(ice_hw_to_dev(hw), vsi_list_info);
+ fm_list->vsi_list_info = NULL;
+ }
+
+ return status;
+}
+
+/**
+ * ice_remove_rule_internal - Remove a filter rule of a given type
+ * @hw: pointer to the hardware structure
+ * @recp_id: recipe id for which the rule needs to removed
+ * @f_entry: rule entry containing filter information
+ */
+static enum ice_status
+ice_remove_rule_internal(struct ice_hw *hw, u8 recp_id,
+ struct ice_fltr_list_entry *f_entry)
+{
+ struct ice_switch_info *sw = hw->switch_info;
+ struct ice_fltr_mgmt_list_entry *list_elem;
+ struct mutex *rule_lock; /* Lock to protect filter rule list */
+ enum ice_status status = 0;
+ bool remove_rule = false;
+ u16 vsi_handle;
+
+ if (!ice_is_vsi_valid(hw, f_entry->fltr_info.vsi_handle))
+ return ICE_ERR_PARAM;
+ f_entry->fltr_info.fwd_id.hw_vsi_id =
+ ice_get_hw_vsi_num(hw, f_entry->fltr_info.vsi_handle);
+
+ rule_lock = &sw->recp_list[recp_id].filt_rule_lock;
+ mutex_lock(rule_lock);
+ list_elem = ice_find_rule_entry(hw, recp_id, &f_entry->fltr_info);
+ if (!list_elem) {
+ status = ICE_ERR_DOES_NOT_EXIST;
+ goto exit;
+ }
+
+ if (list_elem->fltr_info.fltr_act != ICE_FWD_TO_VSI_LIST) {
+ remove_rule = true;
+ } else if (!list_elem->vsi_list_info) {
+ status = ICE_ERR_DOES_NOT_EXIST;
+ goto exit;
+ } else {
+ if (list_elem->vsi_list_info->ref_cnt > 1)
+ list_elem->vsi_list_info->ref_cnt--;
+ vsi_handle = f_entry->fltr_info.vsi_handle;
+ status = ice_rem_update_vsi_list(hw, vsi_handle, list_elem);
+ if (status)
+ goto exit;
+ /* if vsi count goes to zero after updating the vsi list */
+ if (list_elem->vsi_count == 0)
+ remove_rule = true;
+ }
+
+ if (remove_rule) {
+ /* Remove the lookup rule */
+ struct ice_aqc_sw_rules_elem *s_rule;
+
+ s_rule = devm_kzalloc(ice_hw_to_dev(hw),
+ ICE_SW_RULE_RX_TX_NO_HDR_SIZE,
+ GFP_KERNEL);
+ if (!s_rule) {
+ status = ICE_ERR_NO_MEMORY;
+ goto exit;
+ }
+
+ ice_fill_sw_rule(hw, &list_elem->fltr_info, s_rule,
+ ice_aqc_opc_remove_sw_rules);
+
+ status = ice_aq_sw_rules(hw, s_rule,
+ ICE_SW_RULE_RX_TX_NO_HDR_SIZE, 1,
+ ice_aqc_opc_remove_sw_rules, NULL);
+ if (status)
+ goto exit;
+
+ /* Remove a book keeping from the list */
+ devm_kfree(ice_hw_to_dev(hw), s_rule);
+
+ list_del(&list_elem->list_entry);
+ devm_kfree(ice_hw_to_dev(hw), list_elem);
+ }
+exit:
+ mutex_unlock(rule_lock);
+ return status;
}
/**
@@ -1106,7 +1585,10 @@ ice_add_mac(struct ice_hw *hw, struct list_head *m_list)
{
struct ice_aqc_sw_rules_elem *s_rule, *r_iter;
struct ice_fltr_list_entry *m_list_itr;
+ struct list_head *rule_head;
u16 elem_sent, total_elem_left;
+ struct ice_switch_info *sw;
+ struct mutex *rule_lock; /* Lock to protect filter rule list */
enum ice_status status = 0;
u16 num_unicast = 0;
u16 s_rule_size;
@@ -1114,48 +1596,73 @@ ice_add_mac(struct ice_hw *hw, struct list_head *m_list)
if (!m_list || !hw)
return ICE_ERR_PARAM;
+ s_rule = NULL;
+ sw = hw->switch_info;
+ rule_lock = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rule_lock;
list_for_each_entry(m_list_itr, m_list, list_entry) {
u8 *add = &m_list_itr->fltr_info.l_data.mac.mac_addr[0];
+ u16 vsi_handle;
+ u16 hw_vsi_id;
- if (m_list_itr->fltr_info.lkup_type != ICE_SW_LKUP_MAC)
+ m_list_itr->fltr_info.flag = ICE_FLTR_TX;
+ vsi_handle = m_list_itr->fltr_info.vsi_handle;
+ if (!ice_is_vsi_valid(hw, vsi_handle))
return ICE_ERR_PARAM;
- if (is_zero_ether_addr(add))
+ hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
+ m_list_itr->fltr_info.fwd_id.hw_vsi_id = hw_vsi_id;
+ /* update the src in case it is vsi num */
+ if (m_list_itr->fltr_info.src_id != ICE_SRC_ID_VSI)
+ return ICE_ERR_PARAM;
+ m_list_itr->fltr_info.src = hw_vsi_id;
+ if (m_list_itr->fltr_info.lkup_type != ICE_SW_LKUP_MAC ||
+ is_zero_ether_addr(add))
return ICE_ERR_PARAM;
if (is_unicast_ether_addr(add) && !hw->ucast_shared) {
/* Don't overwrite the unicast address */
- if (ice_find_mac_entry(hw, add))
+ mutex_lock(rule_lock);
+ if (ice_find_rule_entry(hw, ICE_SW_LKUP_MAC,
+ &m_list_itr->fltr_info)) {
+ mutex_unlock(rule_lock);
return ICE_ERR_ALREADY_EXISTS;
+ }
+ mutex_unlock(rule_lock);
num_unicast++;
} else if (is_multicast_ether_addr(add) ||
(is_unicast_ether_addr(add) && hw->ucast_shared)) {
- status = ice_add_shared_mac(hw, m_list_itr);
- if (status) {
- m_list_itr->status = ICE_FLTR_STATUS_FW_FAIL;
- return status;
- }
- m_list_itr->status = ICE_FLTR_STATUS_FW_SUCCESS;
+ m_list_itr->status =
+ ice_add_rule_internal(hw, ICE_SW_LKUP_MAC,
+ m_list_itr);
+ if (m_list_itr->status)
+ return m_list_itr->status;
}
}
+ mutex_lock(rule_lock);
/* Exit if no suitable entries were found for adding bulk switch rule */
- if (!num_unicast)
- return 0;
+ if (!num_unicast) {
+ status = 0;
+ goto ice_add_mac_exit;
+ }
+
+ rule_head = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rules;
/* Allocate switch rule buffer for the bulk update for unicast */
s_rule_size = ICE_SW_RULE_RX_TX_ETH_HDR_SIZE;
s_rule = devm_kcalloc(ice_hw_to_dev(hw), num_unicast, s_rule_size,
GFP_KERNEL);
- if (!s_rule)
- return ICE_ERR_NO_MEMORY;
+ if (!s_rule) {
+ status = ICE_ERR_NO_MEMORY;
+ goto ice_add_mac_exit;
+ }
r_iter = s_rule;
list_for_each_entry(m_list_itr, m_list, list_entry) {
struct ice_fltr_info *f_info = &m_list_itr->fltr_info;
- u8 *addr = &f_info->l_data.mac.mac_addr[0];
+ u8 *mac_addr = &f_info->l_data.mac.mac_addr[0];
- if (is_unicast_ether_addr(addr)) {
- ice_fill_sw_rule(hw, &m_list_itr->fltr_info,
- r_iter, ice_aqc_opc_add_sw_rules);
+ if (is_unicast_ether_addr(mac_addr)) {
+ ice_fill_sw_rule(hw, &m_list_itr->fltr_info, r_iter,
+ ice_aqc_opc_add_sw_rules);
r_iter = (struct ice_aqc_sw_rules_elem *)
((u8 *)r_iter + s_rule_size);
}
@@ -1183,11 +1690,10 @@ ice_add_mac(struct ice_hw *hw, struct list_head *m_list)
r_iter = s_rule;
list_for_each_entry(m_list_itr, m_list, list_entry) {
struct ice_fltr_info *f_info = &m_list_itr->fltr_info;
- u8 *addr = &f_info->l_data.mac.mac_addr[0];
- struct ice_switch_info *sw = hw->switch_info;
+ u8 *mac_addr = &f_info->l_data.mac.mac_addr[0];
struct ice_fltr_mgmt_list_entry *fm_entry;
- if (is_unicast_ether_addr(addr)) {
+ if (is_unicast_ether_addr(mac_addr)) {
f_info->fltr_rule_id =
le16_to_cpu(r_iter->pdata.lkup_tx_rx.index);
f_info->fltr_act = ICE_FWD_TO_VSI;
@@ -1203,46 +1709,21 @@ ice_add_mac(struct ice_hw *hw, struct list_head *m_list)
/* The book keeping entries will get removed when
* base driver calls remove filter AQ command
*/
- mutex_lock(&sw->mac_list_lock);
- list_add(&fm_entry->list_entry, &sw->mac_list_head);
- mutex_unlock(&sw->mac_list_lock);
+ list_add(&fm_entry->list_entry, rule_head);
r_iter = (struct ice_aqc_sw_rules_elem *)
((u8 *)r_iter + s_rule_size);
}
}
ice_add_mac_exit:
- devm_kfree(ice_hw_to_dev(hw), s_rule);
+ mutex_unlock(rule_lock);
+ if (s_rule)
+ devm_kfree(ice_hw_to_dev(hw), s_rule);
return status;
}
/**
- * ice_find_vlan_entry
- * @hw: pointer to the hardware structure
- * @vlan_id: VLAN id to search for
- *
- * Helper function to search for a VLAN entry using a given VLAN id
- * Returns pointer to the entry if found.
- */
-static struct ice_fltr_mgmt_list_entry *
-ice_find_vlan_entry(struct ice_hw *hw, u16 vlan_id)
-{
- struct ice_fltr_mgmt_list_entry *vlan_list_itr, *vlan_ret = NULL;
- struct ice_switch_info *sw = hw->switch_info;
-
- mutex_lock(&sw->vlan_list_lock);
- list_for_each_entry(vlan_list_itr, &sw->vlan_list_head, list_entry)
- if (vlan_list_itr->fltr_info.l_data.vlan.vlan_id == vlan_id) {
- vlan_ret = vlan_list_itr;
- break;
- }
-
- mutex_unlock(&sw->vlan_list_lock);
- return vlan_ret;
-}
-
-/**
* ice_add_vlan_internal - Add one VLAN based filter rule
* @hw: pointer to the hardware structure
* @f_entry: filter entry containing one VLAN information
@@ -1250,53 +1731,150 @@ ice_find_vlan_entry(struct ice_hw *hw, u16 vlan_id)
static enum ice_status
ice_add_vlan_internal(struct ice_hw *hw, struct ice_fltr_list_entry *f_entry)
{
- struct ice_fltr_info *new_fltr, *cur_fltr;
+ struct ice_switch_info *sw = hw->switch_info;
struct ice_fltr_mgmt_list_entry *v_list_itr;
- u16 vlan_id;
+ struct ice_fltr_info *new_fltr, *cur_fltr;
+ enum ice_sw_lkup_type lkup_type;
+ u16 vsi_list_id = 0, vsi_handle;
+ struct mutex *rule_lock; /* Lock to protect filter rule list */
+ enum ice_status status = 0;
+ if (!ice_is_vsi_valid(hw, f_entry->fltr_info.vsi_handle))
+ return ICE_ERR_PARAM;
+
+ f_entry->fltr_info.fwd_id.hw_vsi_id =
+ ice_get_hw_vsi_num(hw, f_entry->fltr_info.vsi_handle);
new_fltr = &f_entry->fltr_info;
+
/* VLAN id should only be 12 bits */
if (new_fltr->l_data.vlan.vlan_id > ICE_MAX_VLAN_ID)
return ICE_ERR_PARAM;
- vlan_id = new_fltr->l_data.vlan.vlan_id;
- v_list_itr = ice_find_vlan_entry(hw, vlan_id);
+ if (new_fltr->src_id != ICE_SRC_ID_VSI)
+ return ICE_ERR_PARAM;
+
+ new_fltr->src = new_fltr->fwd_id.hw_vsi_id;
+ lkup_type = new_fltr->lkup_type;
+ vsi_handle = new_fltr->vsi_handle;
+ rule_lock = &sw->recp_list[ICE_SW_LKUP_VLAN].filt_rule_lock;
+ mutex_lock(rule_lock);
+ v_list_itr = ice_find_rule_entry(hw, ICE_SW_LKUP_VLAN, new_fltr);
if (!v_list_itr) {
- u16 vsi_id = ICE_VSI_INVAL_ID;
- enum ice_status status;
- u16 vsi_list_id = 0;
+ struct ice_vsi_list_map_info *map_info = NULL;
if (new_fltr->fltr_act == ICE_FWD_TO_VSI) {
- enum ice_sw_lkup_type lkup_type = new_fltr->lkup_type;
-
- /* All VLAN pruning rules use a VSI list.
- * Convert the action to forwarding to a VSI list.
+ /* All VLAN pruning rules use a VSI list. Check if
+ * there is already a VSI list containing VSI that we
+ * want to add. If found, use the same vsi_list_id for
+ * this new VLAN rule or else create a new list.
*/
- vsi_id = new_fltr->fwd_id.vsi_id;
- status = ice_create_vsi_list_rule(hw, &vsi_id, 1,
- &vsi_list_id,
- lkup_type);
- if (status)
- return status;
+ map_info = ice_find_vsi_list_entry(hw, ICE_SW_LKUP_VLAN,
+ vsi_handle,
+ &vsi_list_id);
+ if (!map_info) {
+ status = ice_create_vsi_list_rule(hw,
+ &vsi_handle,
+ 1,
+ &vsi_list_id,
+ lkup_type);
+ if (status)
+ goto exit;
+ }
+ /* Convert the action to forwarding to a VSI list. */
new_fltr->fltr_act = ICE_FWD_TO_VSI_LIST;
new_fltr->fwd_id.vsi_list_id = vsi_list_id;
}
status = ice_create_pkt_fwd_rule(hw, f_entry);
- if (!status && vsi_id != ICE_VSI_INVAL_ID) {
- v_list_itr = ice_find_vlan_entry(hw, vlan_id);
- if (!v_list_itr)
- return ICE_ERR_DOES_NOT_EXIST;
- v_list_itr->vsi_list_info =
- ice_create_vsi_list_map(hw, &vsi_id, 1,
- vsi_list_id);
+ if (!status) {
+ v_list_itr = ice_find_rule_entry(hw, ICE_SW_LKUP_VLAN,
+ new_fltr);
+ if (!v_list_itr) {
+ status = ICE_ERR_DOES_NOT_EXIST;
+ goto exit;
+ }
+ /* reuse VSI list for new rule and increment ref_cnt */
+ if (map_info) {
+ v_list_itr->vsi_list_info = map_info;
+ map_info->ref_cnt++;
+ } else {
+ v_list_itr->vsi_list_info =
+ ice_create_vsi_list_map(hw, &vsi_handle,
+ 1, vsi_list_id);
+ }
}
+ } else if (v_list_itr->vsi_list_info->ref_cnt == 1) {
+ /* Update existing VSI list to add new VSI id only if it used
+ * by one VLAN rule.
+ */
+ cur_fltr = &v_list_itr->fltr_info;
+ status = ice_add_update_vsi_list(hw, v_list_itr, cur_fltr,
+ new_fltr);
+ } else {
+ /* If VLAN rule exists and VSI list being used by this rule is
+ * referenced by more than 1 VLAN rule. Then create a new VSI
+ * list appending previous VSI with new VSI and update existing
+ * VLAN rule to point to new VSI list id
+ */
+ struct ice_fltr_info tmp_fltr;
+ u16 vsi_handle_arr[2];
+ u16 cur_handle;
- return status;
+ /* Current implementation only supports reusing VSI list with
+ * one VSI count. We should never hit below condition
+ */
+ if (v_list_itr->vsi_count > 1 &&
+ v_list_itr->vsi_list_info->ref_cnt > 1) {
+ ice_debug(hw, ICE_DBG_SW,
+ "Invalid configuration: Optimization to reuse VSI list with more than one VSI is not being done yet\n");
+ status = ICE_ERR_CFG;
+ goto exit;
+ }
+
+ cur_handle =
+ find_first_bit(v_list_itr->vsi_list_info->vsi_map,
+ ICE_MAX_VSI);
+
+ /* A rule already exists with the new VSI being added */
+ if (cur_handle == vsi_handle) {
+ status = ICE_ERR_ALREADY_EXISTS;
+ goto exit;
+ }
+
+ vsi_handle_arr[0] = cur_handle;
+ vsi_handle_arr[1] = vsi_handle;
+ status = ice_create_vsi_list_rule(hw, &vsi_handle_arr[0], 2,
+ &vsi_list_id, lkup_type);
+ if (status)
+ goto exit;
+
+ tmp_fltr = v_list_itr->fltr_info;
+ tmp_fltr.fltr_rule_id = v_list_itr->fltr_info.fltr_rule_id;
+ tmp_fltr.fwd_id.vsi_list_id = vsi_list_id;
+ tmp_fltr.fltr_act = ICE_FWD_TO_VSI_LIST;
+ /* Update the previous switch rule to a new VSI list which
+ * includes current VSI thats requested
+ */
+ status = ice_update_pkt_fwd_rule(hw, &tmp_fltr);
+ if (status)
+ goto exit;
+
+ /* before overriding VSI list map info. decrement ref_cnt of
+ * previous VSI list
+ */
+ v_list_itr->vsi_list_info->ref_cnt--;
+
+ /* now update to newly created list */
+ v_list_itr->fltr_info.fwd_id.vsi_list_id = vsi_list_id;
+ v_list_itr->vsi_list_info =
+ ice_create_vsi_list_map(hw, &vsi_handle_arr[0], 2,
+ vsi_list_id);
+ v_list_itr->vsi_count++;
}
- cur_fltr = &v_list_itr->fltr_info;
- return ice_handle_vsi_list_mgmt(hw, v_list_itr, cur_fltr, new_fltr);
+exit:
+ mutex_unlock(rule_lock);
+ return status;
}
/**
@@ -1313,335 +1891,58 @@ ice_add_vlan(struct ice_hw *hw, struct list_head *v_list)
return ICE_ERR_PARAM;
list_for_each_entry(v_list_itr, v_list, list_entry) {
- enum ice_status status;
-
if (v_list_itr->fltr_info.lkup_type != ICE_SW_LKUP_VLAN)
return ICE_ERR_PARAM;
-
- status = ice_add_vlan_internal(hw, v_list_itr);
- if (status) {
- v_list_itr->status = ICE_FLTR_STATUS_FW_FAIL;
- return status;
- }
- v_list_itr->status = ICE_FLTR_STATUS_FW_SUCCESS;
+ v_list_itr->fltr_info.flag = ICE_FLTR_TX;
+ v_list_itr->status = ice_add_vlan_internal(hw, v_list_itr);
+ if (v_list_itr->status)
+ return v_list_itr->status;
}
return 0;
}
/**
- * ice_remove_vsi_list_rule
- * @hw: pointer to the hardware structure
- * @vsi_list_id: VSI list id generated as part of allocate resource
- * @lkup_type: switch rule filter lookup type
- */
-static enum ice_status
-ice_remove_vsi_list_rule(struct ice_hw *hw, u16 vsi_list_id,
- enum ice_sw_lkup_type lkup_type)
-{
- struct ice_aqc_sw_rules_elem *s_rule;
- enum ice_status status;
- u16 s_rule_size;
-
- s_rule_size = (u16)ICE_SW_RULE_VSI_LIST_SIZE(0);
- s_rule = devm_kzalloc(ice_hw_to_dev(hw), s_rule_size, GFP_KERNEL);
- if (!s_rule)
- return ICE_ERR_NO_MEMORY;
-
- s_rule->type = cpu_to_le16(ICE_AQC_SW_RULES_T_VSI_LIST_CLEAR);
- s_rule->pdata.vsi_list.index = cpu_to_le16(vsi_list_id);
- /* FW expects number of VSIs in vsi_list resource to be 0 for clear
- * command. Since memory is zero'ed out during initialization, it's not
- * necessary to explicitly initialize the variable to 0.
- */
-
- status = ice_aq_sw_rules(hw, s_rule, s_rule_size, 1,
- ice_aqc_opc_remove_sw_rules, NULL);
- if (!status)
- /* Free the vsi_list resource that we allocated */
- status = ice_aq_alloc_free_vsi_list(hw, &vsi_list_id, lkup_type,
- ice_aqc_opc_free_res);
-
- devm_kfree(ice_hw_to_dev(hw), s_rule);
- return status;
-}
-
-/**
- * ice_handle_rem_vsi_list_mgmt
+ * ice_rem_sw_rule_info
* @hw: pointer to the hardware structure
- * @vsi_id: ID of the VSI to remove
- * @fm_list_itr: filter management entry for which the VSI list management
- * needs to be done
+ * @rule_head: pointer to the switch list structure that we want to delete
*/
-static enum ice_status
-ice_handle_rem_vsi_list_mgmt(struct ice_hw *hw, u16 vsi_id,
- struct ice_fltr_mgmt_list_entry *fm_list_itr)
+static void
+ice_rem_sw_rule_info(struct ice_hw *hw, struct list_head *rule_head)
{
- struct ice_switch_info *sw = hw->switch_info;
- enum ice_status status = 0;
- enum ice_sw_lkup_type lkup_type;
- bool is_last_elem = true;
- bool conv_list = false;
- bool del_list = false;
- u16 vsi_list_id;
-
- lkup_type = fm_list_itr->fltr_info.lkup_type;
- vsi_list_id = fm_list_itr->fltr_info.fwd_id.vsi_list_id;
-
- if (fm_list_itr->vsi_count > 1) {
- status = ice_update_vsi_list_rule(hw, &vsi_id, 1, vsi_list_id,
- true,
- ice_aqc_opc_update_sw_rules,
- lkup_type);
- if (status)
- return status;
- fm_list_itr->vsi_count--;
- is_last_elem = false;
- clear_bit(vsi_id, fm_list_itr->vsi_list_info->vsi_map);
- }
-
- /* For non-VLAN rules that forward packets to a VSI list, convert them
- * to forwarding packets to a VSI if there is only one VSI left in the
- * list. Unused lists are then removed.
- * VLAN rules need to use VSI lists even with only one VSI.
- */
- if (fm_list_itr->fltr_info.fltr_act == ICE_FWD_TO_VSI_LIST) {
- if (lkup_type == ICE_SW_LKUP_VLAN) {
- del_list = is_last_elem;
- } else if (fm_list_itr->vsi_count == 1) {
- conv_list = true;
- del_list = true;
- }
- }
+ if (!list_empty(rule_head)) {
+ struct ice_fltr_mgmt_list_entry *entry;
+ struct ice_fltr_mgmt_list_entry *tmp;
- if (del_list) {
- /* Remove the VSI list since it is no longer used */
- struct ice_vsi_list_map_info *vsi_list_info =
- fm_list_itr->vsi_list_info;
-
- status = ice_remove_vsi_list_rule(hw, vsi_list_id, lkup_type);
- if (status)
- return status;
-
- if (conv_list) {
- u16 rem_vsi_id;
-
- rem_vsi_id = find_first_bit(vsi_list_info->vsi_map,
- ICE_MAX_VSI);
-
- /* Error out when the expected last element is not in
- * the VSI list map
- */
- if (rem_vsi_id == ICE_MAX_VSI)
- return ICE_ERR_OUT_OF_RANGE;
-
- /* Change the list entry action from VSI_LIST to VSI */
- fm_list_itr->fltr_info.fltr_act = ICE_FWD_TO_VSI;
- fm_list_itr->fltr_info.fwd_id.vsi_id = rem_vsi_id;
+ list_for_each_entry_safe(entry, tmp, rule_head, list_entry) {
+ list_del(&entry->list_entry);
+ devm_kfree(ice_hw_to_dev(hw), entry);
}
-
- list_del(&vsi_list_info->list_entry);
- devm_kfree(ice_hw_to_dev(hw), vsi_list_info);
- fm_list_itr->vsi_list_info = NULL;
- }
-
- if (conv_list) {
- /* Convert the rule's forward action to forwarding packets to
- * a VSI
- */
- struct ice_aqc_sw_rules_elem *s_rule;
-
- s_rule = devm_kzalloc(ice_hw_to_dev(hw),
- ICE_SW_RULE_RX_TX_ETH_HDR_SIZE,
- GFP_KERNEL);
- if (!s_rule)
- return ICE_ERR_NO_MEMORY;
-
- ice_fill_sw_rule(hw, &fm_list_itr->fltr_info, s_rule,
- ice_aqc_opc_update_sw_rules);
-
- s_rule->pdata.lkup_tx_rx.index =
- cpu_to_le16(fm_list_itr->fltr_info.fltr_rule_id);
-
- status = ice_aq_sw_rules(hw, s_rule,
- ICE_SW_RULE_RX_TX_ETH_HDR_SIZE, 1,
- ice_aqc_opc_update_sw_rules, NULL);
- devm_kfree(ice_hw_to_dev(hw), s_rule);
- if (status)
- return status;
- }
-
- if (is_last_elem) {
- /* Remove the lookup rule */
- struct ice_aqc_sw_rules_elem *s_rule;
-
- s_rule = devm_kzalloc(ice_hw_to_dev(hw),
- ICE_SW_RULE_RX_TX_NO_HDR_SIZE,
- GFP_KERNEL);
- if (!s_rule)
- return ICE_ERR_NO_MEMORY;
-
- ice_fill_sw_rule(hw, &fm_list_itr->fltr_info, s_rule,
- ice_aqc_opc_remove_sw_rules);
-
- status = ice_aq_sw_rules(hw, s_rule,
- ICE_SW_RULE_RX_TX_NO_HDR_SIZE, 1,
- ice_aqc_opc_remove_sw_rules, NULL);
- if (status)
- return status;
-
- /* Remove a book keeping entry from the MAC address list */
- mutex_lock(&sw->mac_list_lock);
- list_del(&fm_list_itr->list_entry);
- mutex_unlock(&sw->mac_list_lock);
- devm_kfree(ice_hw_to_dev(hw), fm_list_itr);
- devm_kfree(ice_hw_to_dev(hw), s_rule);
}
- return status;
-}
-
-/**
- * ice_remove_mac_entry
- * @hw: pointer to the hardware structure
- * @f_entry: structure containing MAC forwarding information
- */
-static enum ice_status
-ice_remove_mac_entry(struct ice_hw *hw, struct ice_fltr_list_entry *f_entry)
-{
- struct ice_fltr_mgmt_list_entry *m_entry;
- u16 vsi_id;
- u8 *add;
-
- add = &f_entry->fltr_info.l_data.mac.mac_addr[0];
-
- m_entry = ice_find_mac_entry(hw, add);
- if (!m_entry)
- return ICE_ERR_PARAM;
-
- vsi_id = f_entry->fltr_info.fwd_id.vsi_id;
- return ice_handle_rem_vsi_list_mgmt(hw, vsi_id, m_entry);
}
/**
- * ice_remove_mac - remove a MAC address based filter rule
+ * ice_cfg_dflt_vsi - change state of VSI to set/clear default
* @hw: pointer to the hardware structure
- * @m_list: list of MAC addresses and forwarding information
- *
- * This function removes either a MAC filter rule or a specific VSI from a
- * VSI list for a multicast MAC address.
- *
- * Returns ICE_ERR_DOES_NOT_EXIST if a given entry was not added by
- * ice_add_mac. Caller should be aware that this call will only work if all
- * the entries passed into m_list were added previously. It will not attempt to
- * do a partial remove of entries that were found.
- */
-enum ice_status
-ice_remove_mac(struct ice_hw *hw, struct list_head *m_list)
-{
- struct ice_aqc_sw_rules_elem *s_rule, *r_iter;
- u8 s_rule_size = ICE_SW_RULE_RX_TX_NO_HDR_SIZE;
- struct ice_switch_info *sw = hw->switch_info;
- struct ice_fltr_mgmt_list_entry *m_entry;
- struct ice_fltr_list_entry *m_list_itr;
- u16 elem_sent, total_elem_left;
- enum ice_status status = 0;
- u16 num_unicast = 0;
-
- if (!m_list)
- return ICE_ERR_PARAM;
-
- list_for_each_entry(m_list_itr, m_list, list_entry) {
- u8 *addr = m_list_itr->fltr_info.l_data.mac.mac_addr;
-
- if (is_unicast_ether_addr(addr) && !hw->ucast_shared)
- num_unicast++;
- else if (is_multicast_ether_addr(addr) ||
- (is_unicast_ether_addr(addr) && hw->ucast_shared))
- ice_remove_mac_entry(hw, m_list_itr);
- }
-
- /* Exit if no unicast addresses found. Multicast switch rules
- * were added individually
- */
- if (!num_unicast)
- return 0;
-
- /* Allocate switch rule buffer for the bulk update for unicast */
- s_rule = devm_kcalloc(ice_hw_to_dev(hw), num_unicast, s_rule_size,
- GFP_KERNEL);
- if (!s_rule)
- return ICE_ERR_NO_MEMORY;
-
- r_iter = s_rule;
- list_for_each_entry(m_list_itr, m_list, list_entry) {
- u8 *addr = m_list_itr->fltr_info.l_data.mac.mac_addr;
-
- if (is_unicast_ether_addr(addr)) {
- m_entry = ice_find_mac_entry(hw, addr);
- if (!m_entry) {
- status = ICE_ERR_DOES_NOT_EXIST;
- goto ice_remove_mac_exit;
- }
-
- ice_fill_sw_rule(hw, &m_entry->fltr_info,
- r_iter, ice_aqc_opc_remove_sw_rules);
- r_iter = (struct ice_aqc_sw_rules_elem *)
- ((u8 *)r_iter + s_rule_size);
- }
- }
-
- /* Call AQ bulk switch rule update for all unicast addresses */
- r_iter = s_rule;
- /* Call AQ switch rule in AQ_MAX chunk */
- for (total_elem_left = num_unicast; total_elem_left > 0;
- total_elem_left -= elem_sent) {
- struct ice_aqc_sw_rules_elem *entry = r_iter;
-
- elem_sent = min(total_elem_left,
- (u16)(ICE_AQ_MAX_BUF_LEN / s_rule_size));
- status = ice_aq_sw_rules(hw, entry, elem_sent * s_rule_size,
- elem_sent, ice_aqc_opc_remove_sw_rules,
- NULL);
- if (status)
- break;
- r_iter = (struct ice_aqc_sw_rules_elem *)
- ((u8 *)r_iter + s_rule_size);
- }
-
- list_for_each_entry(m_list_itr, m_list, list_entry) {
- u8 *addr = m_list_itr->fltr_info.l_data.mac.mac_addr;
-
- if (is_unicast_ether_addr(addr)) {
- m_entry = ice_find_mac_entry(hw, addr);
- if (!m_entry)
- return ICE_ERR_OUT_OF_RANGE;
- mutex_lock(&sw->mac_list_lock);
- list_del(&m_entry->list_entry);
- mutex_unlock(&sw->mac_list_lock);
- devm_kfree(ice_hw_to_dev(hw), m_entry);
- }
- }
-
-ice_remove_mac_exit:
- devm_kfree(ice_hw_to_dev(hw), s_rule);
- return status;
-}
-
-/**
- * ice_cfg_dflt_vsi - add filter rule to set/unset given VSI as default
- * VSI for the switch (represented by swid)
- * @hw: pointer to the hardware structure
- * @vsi_id: number of VSI to set as default
+ * @vsi_handle: VSI handle to set as default
* @set: true to add the above mentioned switch rule, false to remove it
* @direction: ICE_FLTR_RX or ICE_FLTR_TX
+ *
+ * add filter rule to set/unset given VSI as default VSI for the switch
+ * (represented by swid)
*/
enum ice_status
-ice_cfg_dflt_vsi(struct ice_hw *hw, u16 vsi_id, bool set, u8 direction)
+ice_cfg_dflt_vsi(struct ice_hw *hw, u16 vsi_handle, bool set, u8 direction)
{
struct ice_aqc_sw_rules_elem *s_rule;
struct ice_fltr_info f_info;
enum ice_adminq_opc opcode;
enum ice_status status;
u16 s_rule_size;
+ u16 hw_vsi_id;
+
+ if (!ice_is_vsi_valid(hw, vsi_handle))
+ return ICE_ERR_PARAM;
+ hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
s_rule_size = set ? ICE_SW_RULE_RX_TX_ETH_HDR_SIZE :
ICE_SW_RULE_RX_TX_NO_HDR_SIZE;
@@ -1654,15 +1955,17 @@ ice_cfg_dflt_vsi(struct ice_hw *hw, u16 vsi_id, bool set, u8 direction)
f_info.lkup_type = ICE_SW_LKUP_DFLT;
f_info.flag = direction;
f_info.fltr_act = ICE_FWD_TO_VSI;
- f_info.fwd_id.vsi_id = vsi_id;
+ f_info.fwd_id.hw_vsi_id = hw_vsi_id;
if (f_info.flag & ICE_FLTR_RX) {
f_info.src = hw->port_info->lport;
+ f_info.src_id = ICE_SRC_ID_LPORT;
if (!set)
f_info.fltr_rule_id =
hw->port_info->dflt_rx_vsi_rule_id;
} else if (f_info.flag & ICE_FLTR_TX) {
- f_info.src = vsi_id;
+ f_info.src_id = ICE_SRC_ID_VSI;
+ f_info.src = hw_vsi_id;
if (!set)
f_info.fltr_rule_id =
hw->port_info->dflt_tx_vsi_rule_id;
@@ -1682,10 +1985,10 @@ ice_cfg_dflt_vsi(struct ice_hw *hw, u16 vsi_id, bool set, u8 direction)
u16 index = le16_to_cpu(s_rule->pdata.lkup_tx_rx.index);
if (f_info.flag & ICE_FLTR_TX) {
- hw->port_info->dflt_tx_vsi_num = vsi_id;
+ hw->port_info->dflt_tx_vsi_num = hw_vsi_id;
hw->port_info->dflt_tx_vsi_rule_id = index;
} else if (f_info.flag & ICE_FLTR_RX) {
- hw->port_info->dflt_rx_vsi_num = vsi_id;
+ hw->port_info->dflt_rx_vsi_num = hw_vsi_id;
hw->port_info->dflt_rx_vsi_rule_id = index;
}
} else {
@@ -1704,26 +2007,38 @@ out:
}
/**
- * ice_remove_vlan_internal - Remove one VLAN based filter rule
+ * ice_remove_mac - remove a MAC address based filter rule
* @hw: pointer to the hardware structure
- * @f_entry: filter entry containing one VLAN information
+ * @m_list: list of MAC addresses and forwarding information
+ *
+ * This function removes either a MAC filter rule or a specific VSI from a
+ * VSI list for a multicast MAC address.
+ *
+ * Returns ICE_ERR_DOES_NOT_EXIST if a given entry was not added by
+ * ice_add_mac. Caller should be aware that this call will only work if all
+ * the entries passed into m_list were added previously. It will not attempt to
+ * do a partial remove of entries that were found.
*/
-static enum ice_status
-ice_remove_vlan_internal(struct ice_hw *hw,
- struct ice_fltr_list_entry *f_entry)
+enum ice_status
+ice_remove_mac(struct ice_hw *hw, struct list_head *m_list)
{
- struct ice_fltr_info *new_fltr;
- struct ice_fltr_mgmt_list_entry *v_list_elem;
- u16 vsi_id;
-
- new_fltr = &f_entry->fltr_info;
+ struct ice_fltr_list_entry *list_itr, *tmp;
- v_list_elem = ice_find_vlan_entry(hw, new_fltr->l_data.vlan.vlan_id);
- if (!v_list_elem)
+ if (!m_list)
return ICE_ERR_PARAM;
- vsi_id = f_entry->fltr_info.fwd_id.vsi_id;
- return ice_handle_rem_vsi_list_mgmt(hw, vsi_id, v_list_elem);
+ list_for_each_entry_safe(list_itr, tmp, m_list, list_entry) {
+ enum ice_sw_lkup_type l_type = list_itr->fltr_info.lkup_type;
+
+ if (l_type != ICE_SW_LKUP_MAC)
+ return ICE_ERR_PARAM;
+ list_itr->status = ice_remove_rule_internal(hw,
+ ICE_SW_LKUP_MAC,
+ list_itr);
+ if (list_itr->status)
+ return list_itr->status;
+ }
+ return 0;
}
/**
@@ -1734,131 +2049,169 @@ ice_remove_vlan_internal(struct ice_hw *hw,
enum ice_status
ice_remove_vlan(struct ice_hw *hw, struct list_head *v_list)
{
- struct ice_fltr_list_entry *v_list_itr;
- enum ice_status status = 0;
+ struct ice_fltr_list_entry *v_list_itr, *tmp;
if (!v_list || !hw)
return ICE_ERR_PARAM;
- list_for_each_entry(v_list_itr, v_list, list_entry) {
- status = ice_remove_vlan_internal(hw, v_list_itr);
- if (status) {
- v_list_itr->status = ICE_FLTR_STATUS_FW_FAIL;
- return status;
- }
- v_list_itr->status = ICE_FLTR_STATUS_FW_SUCCESS;
+ list_for_each_entry_safe(v_list_itr, tmp, v_list, list_entry) {
+ enum ice_sw_lkup_type l_type = v_list_itr->fltr_info.lkup_type;
+
+ if (l_type != ICE_SW_LKUP_VLAN)
+ return ICE_ERR_PARAM;
+ v_list_itr->status = ice_remove_rule_internal(hw,
+ ICE_SW_LKUP_VLAN,
+ v_list_itr);
+ if (v_list_itr->status)
+ return v_list_itr->status;
}
- return status;
+ return 0;
+}
+
+/**
+ * ice_vsi_uses_fltr - Determine if given VSI uses specified filter
+ * @fm_entry: filter entry to inspect
+ * @vsi_handle: VSI handle to compare with filter info
+ */
+static bool
+ice_vsi_uses_fltr(struct ice_fltr_mgmt_list_entry *fm_entry, u16 vsi_handle)
+{
+ return ((fm_entry->fltr_info.fltr_act == ICE_FWD_TO_VSI &&
+ fm_entry->fltr_info.vsi_handle == vsi_handle) ||
+ (fm_entry->fltr_info.fltr_act == ICE_FWD_TO_VSI_LIST &&
+ (test_bit(vsi_handle, fm_entry->vsi_list_info->vsi_map))));
+}
+
+/**
+ * ice_add_entry_to_vsi_fltr_list - Add copy of fltr_list_entry to remove list
+ * @hw: pointer to the hardware structure
+ * @vsi_handle: VSI handle to remove filters from
+ * @vsi_list_head: pointer to the list to add entry to
+ * @fi: pointer to fltr_info of filter entry to copy & add
+ *
+ * Helper function, used when creating a list of filters to remove from
+ * a specific VSI. The entry added to vsi_list_head is a COPY of the
+ * original filter entry, with the exception of fltr_info.fltr_act and
+ * fltr_info.fwd_id fields. These are set such that later logic can
+ * extract which VSI to remove the fltr from, and pass on that information.
+ */
+static enum ice_status
+ice_add_entry_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_handle,
+ struct list_head *vsi_list_head,
+ struct ice_fltr_info *fi)
+{
+ struct ice_fltr_list_entry *tmp;
+
+ /* this memory is freed up in the caller function
+ * once filters for this VSI are removed
+ */
+ tmp = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*tmp), GFP_KERNEL);
+ if (!tmp)
+ return ICE_ERR_NO_MEMORY;
+
+ tmp->fltr_info = *fi;
+
+ /* Overwrite these fields to indicate which VSI to remove filter from,
+ * so find and remove logic can extract the information from the
+ * list entries. Note that original entries will still have proper
+ * values.
+ */
+ tmp->fltr_info.fltr_act = ICE_FWD_TO_VSI;
+ tmp->fltr_info.vsi_handle = vsi_handle;
+ tmp->fltr_info.fwd_id.hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
+
+ list_add(&tmp->list_entry, vsi_list_head);
+
+ return 0;
}
/**
* ice_add_to_vsi_fltr_list - Add VSI filters to the list
* @hw: pointer to the hardware structure
- * @vsi_id: ID of VSI to remove filters from
+ * @vsi_handle: VSI handle to remove filters from
* @lkup_list_head: pointer to the list that has certain lookup type filters
- * @vsi_list_head: pointer to the list pertaining to VSI with vsi_id
+ * @vsi_list_head: pointer to the list pertaining to VSI with vsi_handle
+ *
+ * Locates all filters in lkup_list_head that are used by the given VSI,
+ * and adds COPIES of those entries to vsi_list_head (intended to be used
+ * to remove the listed filters).
+ * Note that this means all entries in vsi_list_head must be explicitly
+ * deallocated by the caller when done with list.
*/
static enum ice_status
-ice_add_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_id,
+ice_add_to_vsi_fltr_list(struct ice_hw *hw, u16 vsi_handle,
struct list_head *lkup_list_head,
struct list_head *vsi_list_head)
{
struct ice_fltr_mgmt_list_entry *fm_entry;
+ enum ice_status status = 0;
/* check to make sure VSI id is valid and within boundary */
- if (vsi_id >=
- (sizeof(fm_entry->vsi_list_info->vsi_map) * BITS_PER_BYTE - 1))
+ if (!ice_is_vsi_valid(hw, vsi_handle))
return ICE_ERR_PARAM;
list_for_each_entry(fm_entry, lkup_list_head, list_entry) {
struct ice_fltr_info *fi;
fi = &fm_entry->fltr_info;
- if ((fi->fltr_act == ICE_FWD_TO_VSI &&
- fi->fwd_id.vsi_id == vsi_id) ||
- (fi->fltr_act == ICE_FWD_TO_VSI_LIST &&
- (test_bit(vsi_id, fm_entry->vsi_list_info->vsi_map)))) {
- struct ice_fltr_list_entry *tmp;
-
- /* this memory is freed up in the caller function
- * ice_remove_vsi_lkup_fltr() once filters for
- * this VSI are removed
- */
- tmp = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*tmp),
- GFP_KERNEL);
- if (!tmp)
- return ICE_ERR_NO_MEMORY;
-
- memcpy(&tmp->fltr_info, fi, sizeof(*fi));
-
- /* Expected below fields to be set to ICE_FWD_TO_VSI and
- * the particular VSI id since we are only removing this
- * one VSI
- */
- if (fi->fltr_act == ICE_FWD_TO_VSI_LIST) {
- tmp->fltr_info.fltr_act = ICE_FWD_TO_VSI;
- tmp->fltr_info.fwd_id.vsi_id = vsi_id;
- }
+ if (!fi || !ice_vsi_uses_fltr(fm_entry, vsi_handle))
+ continue;
- list_add(&tmp->list_entry, vsi_list_head);
- }
+ status = ice_add_entry_to_vsi_fltr_list(hw, vsi_handle,
+ vsi_list_head, fi);
+ if (status)
+ return status;
}
- return 0;
+ return status;
}
/**
* ice_remove_vsi_lkup_fltr - Remove lookup type filters for a VSI
* @hw: pointer to the hardware structure
- * @vsi_id: ID of VSI to remove filters from
+ * @vsi_handle: VSI handle to remove filters from
* @lkup: switch rule filter lookup type
*/
static void
-ice_remove_vsi_lkup_fltr(struct ice_hw *hw, u16 vsi_id,
+ice_remove_vsi_lkup_fltr(struct ice_hw *hw, u16 vsi_handle,
enum ice_sw_lkup_type lkup)
{
struct ice_switch_info *sw = hw->switch_info;
struct ice_fltr_list_entry *fm_entry;
struct list_head remove_list_head;
+ struct list_head *rule_head;
struct ice_fltr_list_entry *tmp;
+ struct mutex *rule_lock; /* Lock to protect filter rule list */
enum ice_status status;
INIT_LIST_HEAD(&remove_list_head);
+ rule_lock = &sw->recp_list[lkup].filt_rule_lock;
+ rule_head = &sw->recp_list[lkup].filt_rules;
+ mutex_lock(rule_lock);
+ status = ice_add_to_vsi_fltr_list(hw, vsi_handle, rule_head,
+ &remove_list_head);
+ mutex_unlock(rule_lock);
+ if (status)
+ return;
+
switch (lkup) {
case ICE_SW_LKUP_MAC:
- mutex_lock(&sw->mac_list_lock);
- status = ice_add_to_vsi_fltr_list(hw, vsi_id,
- &sw->mac_list_head,
- &remove_list_head);
- mutex_unlock(&sw->mac_list_lock);
- if (!status) {
- ice_remove_mac(hw, &remove_list_head);
- goto free_fltr_list;
- }
+ ice_remove_mac(hw, &remove_list_head);
break;
case ICE_SW_LKUP_VLAN:
- mutex_lock(&sw->vlan_list_lock);
- status = ice_add_to_vsi_fltr_list(hw, vsi_id,
- &sw->vlan_list_head,
- &remove_list_head);
- mutex_unlock(&sw->vlan_list_lock);
- if (!status) {
- ice_remove_vlan(hw, &remove_list_head);
- goto free_fltr_list;
- }
+ ice_remove_vlan(hw, &remove_list_head);
break;
case ICE_SW_LKUP_MAC_VLAN:
case ICE_SW_LKUP_ETHERTYPE:
case ICE_SW_LKUP_ETHERTYPE_MAC:
case ICE_SW_LKUP_PROMISC:
- case ICE_SW_LKUP_PROMISC_VLAN:
case ICE_SW_LKUP_DFLT:
- ice_debug(hw, ICE_DBG_SW,
- "Remove filters for this lookup type hasn't been implemented yet\n");
+ case ICE_SW_LKUP_PROMISC_VLAN:
+ case ICE_SW_LKUP_LAST:
+ default:
+ ice_debug(hw, ICE_DBG_SW, "Unsupported lookup type %d\n", lkup);
break;
}
- return;
-free_fltr_list:
list_for_each_entry_safe(fm_entry, tmp, &remove_list_head, list_entry) {
list_del(&fm_entry->list_entry);
devm_kfree(ice_hw_to_dev(hw), fm_entry);
@@ -1868,16 +2221,121 @@ free_fltr_list:
/**
* ice_remove_vsi_fltr - Remove all filters for a VSI
* @hw: pointer to the hardware structure
- * @vsi_id: ID of VSI to remove filters from
+ * @vsi_handle: VSI handle to remove filters from
*/
-void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_id)
+void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_handle)
{
- ice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_MAC);
- ice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_MAC_VLAN);
- ice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_PROMISC);
- ice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_VLAN);
- ice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_DFLT);
- ice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_ETHERTYPE);
- ice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_ETHERTYPE_MAC);
- ice_remove_vsi_lkup_fltr(hw, vsi_id, ICE_SW_LKUP_PROMISC_VLAN);
+ ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_MAC);
+ ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_MAC_VLAN);
+ ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_PROMISC);
+ ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_VLAN);
+ ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_DFLT);
+ ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_ETHERTYPE);
+ ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_ETHERTYPE_MAC);
+ ice_remove_vsi_lkup_fltr(hw, vsi_handle, ICE_SW_LKUP_PROMISC_VLAN);
+}
+
+/**
+ * ice_replay_vsi_fltr - Replay filters for requested VSI
+ * @hw: pointer to the hardware structure
+ * @vsi_handle: driver VSI handle
+ * @recp_id: Recipe id for which rules need to be replayed
+ * @list_head: list for which filters need to be replayed
+ *
+ * Replays the filter of recipe recp_id for a VSI represented via vsi_handle.
+ * It is required to pass valid VSI handle.
+ */
+static enum ice_status
+ice_replay_vsi_fltr(struct ice_hw *hw, u16 vsi_handle, u8 recp_id,
+ struct list_head *list_head)
+{
+ struct ice_fltr_mgmt_list_entry *itr;
+ enum ice_status status = 0;
+ u16 hw_vsi_id;
+
+ if (list_empty(list_head))
+ return status;
+ hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
+
+ list_for_each_entry(itr, list_head, list_entry) {
+ struct ice_fltr_list_entry f_entry;
+
+ f_entry.fltr_info = itr->fltr_info;
+ if (itr->vsi_count < 2 && recp_id != ICE_SW_LKUP_VLAN &&
+ itr->fltr_info.vsi_handle == vsi_handle) {
+ /* update the src in case it is vsi num */
+ if (f_entry.fltr_info.src_id == ICE_SRC_ID_VSI)
+ f_entry.fltr_info.src = hw_vsi_id;
+ status = ice_add_rule_internal(hw, recp_id, &f_entry);
+ if (status)
+ goto end;
+ continue;
+ }
+ if (!itr->vsi_list_info ||
+ !test_bit(vsi_handle, itr->vsi_list_info->vsi_map))
+ continue;
+ /* Clearing it so that the logic can add it back */
+ clear_bit(vsi_handle, itr->vsi_list_info->vsi_map);
+ f_entry.fltr_info.vsi_handle = vsi_handle;
+ f_entry.fltr_info.fltr_act = ICE_FWD_TO_VSI;
+ /* update the src in case it is vsi num */
+ if (f_entry.fltr_info.src_id == ICE_SRC_ID_VSI)
+ f_entry.fltr_info.src = hw_vsi_id;
+ if (recp_id == ICE_SW_LKUP_VLAN)
+ status = ice_add_vlan_internal(hw, &f_entry);
+ else
+ status = ice_add_rule_internal(hw, recp_id, &f_entry);
+ if (status)
+ goto end;
+ }
+end:
+ return status;
+}
+
+/**
+ * ice_replay_vsi_all_fltr - replay all filters stored in bookkeeping lists
+ * @hw: pointer to the hardware structure
+ * @vsi_handle: driver VSI handle
+ *
+ * Replays filters for requested VSI via vsi_handle.
+ */
+enum ice_status ice_replay_vsi_all_fltr(struct ice_hw *hw, u16 vsi_handle)
+{
+ struct ice_switch_info *sw = hw->switch_info;
+ enum ice_status status = 0;
+ u8 i;
+
+ for (i = 0; i < ICE_SW_LKUP_LAST; i++) {
+ struct list_head *head;
+
+ head = &sw->recp_list[i].filt_replay_rules;
+ status = ice_replay_vsi_fltr(hw, vsi_handle, i, head);
+ if (status)
+ return status;
+ }
+ return status;
+}
+
+/**
+ * ice_rm_all_sw_replay_rule_info - deletes filter replay rules
+ * @hw: pointer to the hw struct
+ *
+ * Deletes the filter replay rules.
+ */
+void ice_rm_all_sw_replay_rule_info(struct ice_hw *hw)
+{
+ struct ice_switch_info *sw = hw->switch_info;
+ u8 i;
+
+ if (!sw)
+ return;
+
+ for (i = 0; i < ICE_SW_LKUP_LAST; i++) {
+ if (!list_empty(&sw->recp_list[i].filt_replay_rules)) {
+ struct list_head *l_head;
+
+ l_head = &sw->recp_list[i].filt_replay_rules;
+ ice_rem_sw_rule_info(hw, l_head);
+ }
+ }
}
diff --git a/drivers/net/ethernet/intel/ice/ice_switch.h b/drivers/net/ethernet/intel/ice/ice_switch.h
index 9b8ec128ee31..d5ef0bd58bf9 100644
--- a/drivers/net/ethernet/intel/ice/ice_switch.h
+++ b/drivers/net/ethernet/intel/ice/ice_switch.h
@@ -17,7 +17,9 @@ struct ice_vsi_ctx {
u16 vsis_unallocated;
u16 flags;
struct ice_aqc_vsi_props info;
+ struct ice_sched_vsi_info sched;
u8 alloc_from_pool;
+ u8 vf_num;
};
enum ice_sw_fwd_act_type {
@@ -39,6 +41,15 @@ enum ice_sw_lkup_type {
ICE_SW_LKUP_DFLT = 5,
ICE_SW_LKUP_ETHERTYPE_MAC = 8,
ICE_SW_LKUP_PROMISC_VLAN = 9,
+ ICE_SW_LKUP_LAST
+};
+
+/* type of filter src id */
+enum ice_src_id {
+ ICE_SRC_ID_UNKNOWN = 0,
+ ICE_SRC_ID_VSI,
+ ICE_SRC_ID_QUEUE,
+ ICE_SRC_ID_LPORT,
};
struct ice_fltr_info {
@@ -55,6 +66,7 @@ struct ice_fltr_info {
/* Source VSI for LOOKUP_TX or source port for LOOKUP_RX */
u16 src;
+ enum ice_src_id src_id;
union {
struct {
@@ -76,7 +88,10 @@ struct ice_fltr_info {
u16 ethertype;
u8 mac_addr[ETH_ALEN]; /* optional */
} ethertype_mac;
- } l_data;
+ } l_data; /* Make sure to zero out the memory of l_data before using
+ * it or only set the data associated with lookup match
+ * rest everything should be zero
+ */
/* Depending on filter action */
union {
@@ -84,12 +99,16 @@ struct ice_fltr_info {
* queue id in case of ICE_FWD_TO_QGRP.
*/
u16 q_id:11;
- u16 vsi_id:10;
+ u16 hw_vsi_id:10;
u16 vsi_list_id:10;
} fwd_id;
+ /* Sw VSI handle */
+ u16 vsi_handle;
+
/* Set to num_queues if action is ICE_FWD_TO_QGRP. This field
- * determines the range of queues the packet needs to be forwarded to
+ * determines the range of queues the packet needs to be forwarded to.
+ * Note that qgrp_size must be set to a power of 2.
*/
u8 qgrp_size;
@@ -98,29 +117,52 @@ struct ice_fltr_info {
u8 lan_en; /* Indicate if packet can be forwarded to the uplink */
};
+struct ice_sw_recipe {
+ struct list_head l_entry;
+
+ /* To protect modification of filt_rule list
+ * defined below
+ */
+ struct mutex filt_rule_lock;
+
+ /* List of type ice_fltr_mgmt_list_entry */
+ struct list_head filt_rules;
+ struct list_head filt_replay_rules;
+
+ /* linked list of type recipe_list_entry */
+ struct list_head rg_list;
+ /* linked list of type ice_sw_fv_list_entry*/
+ struct list_head fv_list;
+ struct ice_aqc_recipe_data_elem *r_buf;
+ u8 recp_count;
+ u8 root_rid;
+ u8 num_profs;
+ u8 *prof_ids;
+
+ /* recipe bitmap: what all recipes makes this recipe */
+ DECLARE_BITMAP(r_bitmap, ICE_MAX_NUM_RECIPES);
+};
+
/* Bookkeeping structure to hold bitmap of VSIs corresponding to VSI list id */
struct ice_vsi_list_map_info {
struct list_head list_entry;
DECLARE_BITMAP(vsi_map, ICE_MAX_VSI);
u16 vsi_list_id;
-};
-
-enum ice_sw_fltr_status {
- ICE_FLTR_STATUS_NEW = 0,
- ICE_FLTR_STATUS_FW_SUCCESS,
- ICE_FLTR_STATUS_FW_FAIL,
+ /* counter to track how many rules are reusing this VSI list */
+ u16 ref_cnt;
};
struct ice_fltr_list_entry {
struct list_head list_entry;
- enum ice_sw_fltr_status status;
+ enum ice_status status;
struct ice_fltr_info fltr_info;
};
/* This defines an entry in the list that maintains MAC or VLAN membership
* to HW list mapping, since multiple VSIs can subscribe to the same MAC or
* VLAN. As an optimization the VSI list should be created only when a
- * second VSI becomes a subscriber to the VLAN address.
+ * second VSI becomes a subscriber to the same MAC address. VSI lists are always
+ * used for VLAN membership.
*/
struct ice_fltr_mgmt_list_entry {
/* back pointer to VSI list id to VSI list mapping */
@@ -138,24 +180,35 @@ struct ice_fltr_mgmt_list_entry {
/* VSI related commands */
enum ice_status
-ice_aq_add_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,
- struct ice_sq_cd *cd);
+ice_add_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx,
+ struct ice_sq_cd *cd);
enum ice_status
-ice_aq_update_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,
- struct ice_sq_cd *cd);
+ice_free_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx,
+ bool keep_vsi_alloc, struct ice_sq_cd *cd);
enum ice_status
-ice_aq_free_vsi(struct ice_hw *hw, struct ice_vsi_ctx *vsi_ctx,
- bool keep_vsi_alloc, struct ice_sq_cd *cd);
-
+ice_update_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx,
+ struct ice_sq_cd *cd);
+bool ice_is_vsi_valid(struct ice_hw *hw, u16 vsi_handle);
+struct ice_vsi_ctx *ice_get_vsi_ctx(struct ice_hw *hw, u16 vsi_handle);
+void ice_clear_all_vsi_ctx(struct ice_hw *hw);
+/* Switch config */
enum ice_status ice_get_initial_sw_cfg(struct ice_hw *hw);
/* Switch/bridge related commands */
+enum ice_status ice_update_sw_rule_bridge_mode(struct ice_hw *hw);
enum ice_status ice_add_mac(struct ice_hw *hw, struct list_head *m_lst);
enum ice_status ice_remove_mac(struct ice_hw *hw, struct list_head *m_lst);
-void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_id);
+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);
enum ice_status ice_remove_vlan(struct ice_hw *hw, struct list_head *v_list);
enum ice_status
-ice_cfg_dflt_vsi(struct ice_hw *hw, u16 vsi_id, bool set, u8 direction);
+ice_cfg_dflt_vsi(struct ice_hw *hw, u16 vsi_handle, bool set, u8 direction);
+
+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);
#endif /* _ICE_SWITCH_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c
index 6481e3d86374..fe5bbabbb41e 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx.c
+++ b/drivers/net/ethernet/intel/ice/ice_txrx.c
@@ -251,6 +251,7 @@ int ice_setup_tx_ring(struct ice_ring *tx_ring)
tx_ring->next_to_use = 0;
tx_ring->next_to_clean = 0;
+ tx_ring->tx_stats.prev_pkt = -1;
return 0;
err:
@@ -1519,7 +1520,7 @@ int ice_tso(struct ice_tx_buf *first, struct ice_tx_offload_params *off)
/* update gso_segs and bytecount */
first->gso_segs = skb_shinfo(skb)->gso_segs;
- first->bytecount = (first->gso_segs - 1) * off->header_len;
+ first->bytecount += (first->gso_segs - 1) * off->header_len;
cd_tso_len = skb->len - off->header_len;
cd_mss = skb_shinfo(skb)->gso_size;
@@ -1555,15 +1556,15 @@ int ice_tso(struct ice_tx_buf *first, struct ice_tx_offload_params *off)
* magnitude greater than our largest possible GSO size.
*
* This would then be implemented as:
- * return (((size >> 12) * 85) >> 8) + 1;
+ * return (((size >> 12) * 85) >> 8) + ICE_DESCS_FOR_SKB_DATA_PTR;
*
* Since multiplication and division are commutative, we can reorder
* operations into:
- * return ((size * 85) >> 20) + 1;
+ * return ((size * 85) >> 20) + ICE_DESCS_FOR_SKB_DATA_PTR;
*/
static unsigned int ice_txd_use_count(unsigned int size)
{
- return ((size * 85) >> 20) + 1;
+ return ((size * 85) >> 20) + ICE_DESCS_FOR_SKB_DATA_PTR;
}
/**
@@ -1705,7 +1706,8 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_ring *tx_ring)
* + 1 desc for context descriptor,
* otherwise try next time
*/
- if (ice_maybe_stop_tx(tx_ring, count + 4 + 1)) {
+ if (ice_maybe_stop_tx(tx_ring, count + ICE_DESCS_PER_CACHE_LINE +
+ ICE_DESCS_FOR_CTX_DESC)) {
tx_ring->tx_stats.tx_busy++;
return NETDEV_TX_BUSY;
}
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h
index 31bc998fe200..75d0eaf6c9dd 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx.h
+++ b/drivers/net/ethernet/intel/ice/ice_txrx.h
@@ -22,8 +22,21 @@
#define ICE_RX_BUF_WRITE 16 /* Must be power of 2 */
#define ICE_MAX_TXQ_PER_TXQG 128
-/* Tx Descriptors needed, worst case */
-#define DESC_NEEDED (MAX_SKB_FRAGS + 4)
+/* We are assuming that the cache line is always 64 Bytes here for ice.
+ * In order to make sure that is a correct assumption there is a check in probe
+ * to print a warning if the read from GLPCI_CNF2 tells us that the cache line
+ * size is 128 bytes. We do it this way because we do not want to read the
+ * GLPCI_CNF2 register or a variable containing the value on every pass through
+ * the Tx path.
+ */
+#define ICE_CACHE_LINE_BYTES 64
+#define ICE_DESCS_PER_CACHE_LINE (ICE_CACHE_LINE_BYTES / \
+ sizeof(struct ice_tx_desc))
+#define ICE_DESCS_FOR_CTX_DESC 1
+#define ICE_DESCS_FOR_SKB_DATA_PTR 1
+/* Tx descriptors needed, worst case */
+#define DESC_NEEDED (MAX_SKB_FRAGS + ICE_DESCS_FOR_CTX_DESC + \
+ ICE_DESCS_PER_CACHE_LINE + ICE_DESCS_FOR_SKB_DATA_PTR)
#define ICE_DESC_UNUSED(R) \
((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \
(R)->next_to_clean - (R)->next_to_use - 1)
@@ -71,6 +84,7 @@ struct ice_txq_stats {
u64 restart_q;
u64 tx_busy;
u64 tx_linearize;
+ int prev_pkt; /* negative if no pending Tx descriptors */
};
struct ice_rxq_stats {
@@ -103,10 +117,17 @@ enum ice_rx_dtype {
#define ICE_RX_ITR ICE_IDX_ITR0
#define ICE_TX_ITR ICE_IDX_ITR1
#define ICE_ITR_DYNAMIC 0x8000 /* use top bit as a flag */
-#define ICE_ITR_8K 0x003E
+#define ICE_ITR_8K 125
+#define ICE_ITR_20K 50
+#define ICE_DFLT_TX_ITR ICE_ITR_20K
+#define ICE_DFLT_RX_ITR ICE_ITR_20K
+/* apply ITR granularity translation to program the register. itr_gran is either
+ * 2 or 4 usecs so we need to divide by 2 first then shift by that value
+ */
+#define ITR_TO_REG(val, itr_gran) (((val) & ~ICE_ITR_DYNAMIC) >> \
+ ((itr_gran) / 2))
-/* apply ITR HW granularity translation to program the HW registers */
-#define ITR_TO_REG(val, itr_gran) (((val) & ~ICE_ITR_DYNAMIC) >> (itr_gran))
+#define ICE_DFLT_INTRL 0
/* Legacy or Advanced Mode Queue */
#define ICE_TX_ADVANCED 0
@@ -128,14 +149,6 @@ struct ice_ring {
u16 q_index; /* Queue number of ring */
u32 txq_teid; /* Added Tx queue TEID */
- /* high bit set means dynamic, use accessor routines to read/write.
- * hardware supports 2us/1us resolution for the ITR registers.
- * these values always store the USER setting, and must be converted
- * before programming to a register.
- */
- u16 rx_itr_setting;
- u16 tx_itr_setting;
-
u16 count; /* Number of descriptors */
u16 reg_idx; /* HW register index of the ring */
@@ -172,6 +185,7 @@ struct ice_ring_container {
unsigned int total_bytes; /* total bytes processed this int */
unsigned int total_pkts; /* total packets processed this int */
enum ice_latency_range latency_range;
+ int itr_idx; /* index in the interrupt vector */
u16 itr;
};
diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h
index 97c366e0ca59..f4dbc81c1988 100644
--- a/drivers/net/ethernet/intel/ice/ice_type.h
+++ b/drivers/net/ethernet/intel/ice/ice_type.h
@@ -18,6 +18,9 @@ static inline bool ice_is_tc_ena(u8 bitmap, u8 tc)
return test_bit(tc, (unsigned long *)&bitmap);
}
+/* Driver always calls main vsi_handle first */
+#define ICE_MAIN_VSI_HANDLE 0
+
/* debug masks - set these bits in hw->debug_mask to control output */
#define ICE_DBG_INIT BIT_ULL(1)
#define ICE_DBG_LINK BIT_ULL(4)
@@ -34,10 +37,15 @@ static inline bool ice_is_tc_ena(u8 bitmap, u8 tc)
enum ice_aq_res_ids {
ICE_NVM_RES_ID = 1,
ICE_SPD_RES_ID,
- ICE_GLOBAL_CFG_LOCK_RES_ID,
- ICE_CHANGE_LOCK_RES_ID
+ ICE_CHANGE_LOCK_RES_ID,
+ ICE_GLOBAL_CFG_LOCK_RES_ID
};
+/* 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
+
enum ice_aq_res_access_type {
ICE_RES_READ = 1,
ICE_RES_WRITE
@@ -76,6 +84,7 @@ enum ice_media_type {
enum ice_vsi_type {
ICE_VSI_PF = 0,
+ ICE_VSI_VF,
};
struct ice_link_status {
@@ -83,18 +92,27 @@ struct ice_link_status {
u64 phy_type_low;
u16 max_frame_size;
u16 link_speed;
+ u16 req_speeds;
u8 lse_ena; /* Link Status Event notification */
u8 link_info;
u8 an_info;
u8 ext_info;
u8 pacing;
- u8 req_speeds;
/* Refer to #define from module_type[ICE_MODULE_TYPE_TOTAL_BYTE] of
* ice_aqc_get_phy_caps structure
*/
u8 module_type[ICE_MODULE_TYPE_TOTAL_BYTE];
};
+/* Different reset sources for which a disable queue AQ call has to be made in
+ * order to clean the TX scheduler as a part of the reset
+ */
+enum ice_disq_rst_src {
+ ICE_NO_RESET = 0,
+ ICE_VM_RESET,
+ ICE_VF_RESET,
+};
+
/* PHY info such as phy_type, etc... */
struct ice_phy_info {
struct ice_link_status link_info;
@@ -119,6 +137,9 @@ struct ice_hw_common_caps {
/* Max MTU for function or device */
u16 max_mtu;
+ /* Virtualization support */
+ u8 sr_iov_1_1; /* SR-IOV enabled */
+
/* RSS related capabilities */
u16 rss_table_size; /* 512 for PFs and 64 for VFs */
u8 rss_table_entry_width; /* RSS Entry width in bits */
@@ -127,12 +148,15 @@ struct ice_hw_common_caps {
/* Function specific capabilities */
struct ice_hw_func_caps {
struct ice_hw_common_caps common_cap;
+ u32 num_allocd_vfs; /* Number of allocated VFs */
+ u32 vf_base_id; /* Logical ID of the first VF */
u32 guaranteed_num_vsi;
};
/* Device wide capabilities */
struct ice_hw_dev_caps {
struct ice_hw_common_caps common_cap;
+ u32 num_vfs_exposed; /* Total number of VFs exposed */
u32 num_vsi_allocd_to_host; /* Excluding EMP VSI */
};
@@ -142,11 +166,18 @@ struct ice_mac_info {
u8 perm_addr[ETH_ALEN];
};
-/* Various RESET request, These are not tied with HW reset types */
+/* Reset types used to determine which kind of reset was requested. These
+ * defines match what the RESET_TYPE field of the GLGEN_RSTAT register.
+ * ICE_RESET_PFR does not match any RESET_TYPE field in the GLGEN_RSTAT register
+ * because its reset source is different than the other types listed.
+ */
enum ice_reset_req {
- ICE_RESET_PFR = 0,
+ ICE_RESET_POR = 0,
+ ICE_RESET_INVAL = 0,
ICE_RESET_CORER = 1,
ICE_RESET_GLOBR = 2,
+ ICE_RESET_EMPR = 3,
+ ICE_RESET_PFR = 4,
};
/* Bus parameters */
@@ -180,7 +211,7 @@ struct ice_sched_node {
struct ice_sched_node **children;
struct ice_aqc_txsched_elem_data info;
u32 agg_id; /* aggregator group id */
- u16 vsi_id;
+ u16 vsi_handle;
u8 in_use; /* suspended or in use */
u8 tx_sched_layer; /* Logical Layer (1-9) */
u8 num_children;
@@ -204,6 +235,7 @@ enum ice_agg_type {
};
#define ICE_SCHED_DFLT_RL_PROF_ID 0
+#define ICE_SCHED_DFLT_BW_WT 1
/* vsi type list entry to locate corresponding vsi/ag nodes */
struct ice_sched_vsi_info {
@@ -238,8 +270,6 @@ struct ice_port_info {
struct ice_mac_info mac;
struct ice_phy_info phy;
struct mutex sched_lock; /* protect access to TXSched tree */
- struct ice_sched_tx_policy sched_policy;
- struct list_head vsi_info_list;
struct list_head agg_list; /* lists all aggregator */
u8 lport;
#define ICE_LPORT_MASK 0xff
@@ -247,19 +277,26 @@ struct ice_port_info {
};
struct ice_switch_info {
- /* Switch VSI lists to MAC/VLAN translation */
- struct mutex mac_list_lock; /* protect MAC list */
- struct list_head mac_list_head;
- struct mutex vlan_list_lock; /* protect VLAN list */
- struct list_head vlan_list_head;
- struct mutex eth_m_list_lock; /* protect ethtype list */
- struct list_head eth_m_list_head;
- struct mutex promisc_list_lock; /* protect promisc mode list */
- struct list_head promisc_list_head;
- struct mutex mac_vlan_list_lock; /* protect MAC-VLAN list */
- struct list_head mac_vlan_list_head;
-
struct list_head vsi_list_map_head;
+ struct ice_sw_recipe *recp_list;
+};
+
+/* FW logging configuration */
+struct ice_fw_log_evnt {
+ u8 cfg : 4; /* New event enables to configure */
+ u8 cur : 4; /* Current/active event enables */
+};
+
+struct ice_fw_log_cfg {
+ u8 cq_en : 1; /* FW logging is enabled via the control queue */
+ u8 uart_en : 1; /* FW logging is enabled via UART for all PFs */
+ u8 actv_evnts; /* Cumulation of currently enabled log events */
+
+#define ICE_FW_LOG_EVNT_INFO (ICE_AQC_FW_LOG_INFO_EN >> ICE_AQC_FW_LOG_EN_S)
+#define ICE_FW_LOG_EVNT_INIT (ICE_AQC_FW_LOG_INIT_EN >> ICE_AQC_FW_LOG_EN_S)
+#define ICE_FW_LOG_EVNT_FLOW (ICE_AQC_FW_LOG_FLOW_EN >> ICE_AQC_FW_LOG_EN_S)
+#define ICE_FW_LOG_EVNT_ERR (ICE_AQC_FW_LOG_ERR_EN >> ICE_AQC_FW_LOG_EN_S)
+ struct ice_fw_log_evnt evnts[ICE_AQC_FW_LOG_ID_MAX];
};
/* Port hardware description */
@@ -286,8 +323,11 @@ struct ice_hw {
u8 flattened_layers;
u8 max_cgds;
u8 sw_entry_point_layer;
+ u16 max_children[ICE_AQC_TOPO_MAX_LEVEL_NUM];
+ struct ice_vsi_ctx *vsi_ctx[ICE_MAX_VSI];
u8 evb_veb; /* true for VEB, false for VEPA */
+ u8 reset_ongoing; /* true if hw is in reset, false otherwise */
struct ice_bus_info bus;
struct ice_nvm_info nvm;
struct ice_hw_dev_caps dev_caps; /* device capabilities */
@@ -297,6 +337,7 @@ struct ice_hw {
/* Control Queue info */
struct ice_ctl_q_info adminq;
+ struct ice_ctl_q_info mailboxq;
u8 api_branch; /* API branch version */
u8 api_maj_ver; /* API major version */
@@ -308,16 +349,27 @@ struct ice_hw {
u8 fw_patch; /* firmware patch version */
u32 fw_build; /* firmware build number */
- /* minimum allowed value for different speeds */
-#define ICE_ITR_GRAN_MIN_200 1
-#define ICE_ITR_GRAN_MIN_100 1
-#define ICE_ITR_GRAN_MIN_50 2
-#define ICE_ITR_GRAN_MIN_25 4
+ struct ice_fw_log_cfg fw_log;
+
+/* Device max aggregate bandwidths corresponding to the GL_PWR_MODE_CTL
+ * register. Used for determining the itr/intrl granularity during
+ * initialization.
+ */
+#define ICE_MAX_AGG_BW_200G 0x0
+#define ICE_MAX_AGG_BW_100G 0X1
+#define ICE_MAX_AGG_BW_50G 0x2
+#define ICE_MAX_AGG_BW_25G 0x3
+ /* ITR granularity for different speeds */
+#define ICE_ITR_GRAN_ABOVE_25 2
+#define ICE_ITR_GRAN_MAX_25 4
/* ITR granularity in 1 us */
- u8 itr_gran_200;
- u8 itr_gran_100;
- u8 itr_gran_50;
- u8 itr_gran_25;
+ u8 itr_gran;
+ /* INTRL granularity for different speeds */
+#define ICE_INTRL_GRAN_ABOVE_25 4
+#define ICE_INTRL_GRAN_MAX_25 8
+ /* INTRL granularity in 1 us */
+ u8 intrl_gran;
+
u8 ucast_shared; /* true if VSIs can share unicast addr */
};
@@ -391,4 +443,7 @@ struct ice_hw_port_stats {
#define ICE_SR_SECTOR_SIZE_IN_WORDS 0x800
#define ICE_SR_WORDS_IN_1KB 512
+/* Hash redirection LUT for VSI - maximum array size */
+#define ICE_VSIQF_HLUT_ARRAY_SIZE ((VSIQF_HLUT_MAX_INDEX + 1) * 4)
+
#endif /* _ICE_TYPE_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c
new file mode 100644
index 000000000000..e71065f9d391
--- /dev/null
+++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c
@@ -0,0 +1,2673 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2018, Intel Corporation. */
+
+#include "ice.h"
+#include "ice_lib.h"
+
+/**
+ * ice_vc_vf_broadcast - Broadcast a message to all VFs on PF
+ * @pf: pointer to the PF structure
+ * @v_opcode: operation code
+ * @v_retval: return value
+ * @msg: pointer to the msg buffer
+ * @msglen: msg length
+ */
+static void
+ice_vc_vf_broadcast(struct ice_pf *pf, enum virtchnl_ops v_opcode,
+ enum ice_status v_retval, u8 *msg, u16 msglen)
+{
+ struct ice_hw *hw = &pf->hw;
+ struct ice_vf *vf = pf->vf;
+ int i;
+
+ for (i = 0; i < pf->num_alloc_vfs; i++, vf++) {
+ /* Not all vfs are enabled so skip the ones that are not */
+ if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states) &&
+ !test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states))
+ continue;
+
+ /* Ignore return value on purpose - a given VF may fail, but
+ * we need to keep going and send to all of them
+ */
+ ice_aq_send_msg_to_vf(hw, vf->vf_id, v_opcode, v_retval, msg,
+ msglen, NULL);
+ }
+}
+
+/**
+ * ice_set_pfe_link - Set the link speed/status of the virtchnl_pf_event
+ * @vf: pointer to the VF structure
+ * @pfe: pointer to the virtchnl_pf_event to set link speed/status for
+ * @ice_link_speed: link speed specified by ICE_AQ_LINK_SPEED_*
+ * @link_up: whether or not to set the link up/down
+ */
+static void
+ice_set_pfe_link(struct ice_vf *vf, struct virtchnl_pf_event *pfe,
+ int ice_link_speed, bool link_up)
+{
+ if (vf->driver_caps & VIRTCHNL_VF_CAP_ADV_LINK_SPEED) {
+ pfe->event_data.link_event_adv.link_status = link_up;
+ /* Speed in Mbps */
+ pfe->event_data.link_event_adv.link_speed =
+ ice_conv_link_speed_to_virtchnl(true, ice_link_speed);
+ } else {
+ pfe->event_data.link_event.link_status = link_up;
+ /* Legacy method for virtchnl link speeds */
+ pfe->event_data.link_event.link_speed =
+ (enum virtchnl_link_speed)
+ ice_conv_link_speed_to_virtchnl(false, ice_link_speed);
+ }
+}
+
+/**
+ * ice_set_pfe_link_forced - Force the virtchnl_pf_event link speed/status
+ * @vf: pointer to the VF structure
+ * @pfe: pointer to the virtchnl_pf_event to set link speed/status for
+ * @link_up: whether or not to set the link up/down
+ */
+static void
+ice_set_pfe_link_forced(struct ice_vf *vf, struct virtchnl_pf_event *pfe,
+ bool link_up)
+{
+ u16 link_speed;
+
+ if (link_up)
+ link_speed = ICE_AQ_LINK_SPEED_40GB;
+ else
+ link_speed = ICE_AQ_LINK_SPEED_UNKNOWN;
+
+ ice_set_pfe_link(vf, pfe, link_speed, link_up);
+}
+
+/**
+ * ice_vc_notify_vf_link_state - Inform a VF of link status
+ * @vf: pointer to the VF structure
+ *
+ * send a link status message to a single VF
+ */
+static void ice_vc_notify_vf_link_state(struct ice_vf *vf)
+{
+ struct virtchnl_pf_event pfe = { 0 };
+ struct ice_link_status *ls;
+ struct ice_pf *pf = vf->pf;
+ struct ice_hw *hw;
+
+ hw = &pf->hw;
+ ls = &hw->port_info->phy.link_info;
+
+ pfe.event = VIRTCHNL_EVENT_LINK_CHANGE;
+ pfe.severity = PF_EVENT_SEVERITY_INFO;
+
+ if (vf->link_forced)
+ ice_set_pfe_link_forced(vf, &pfe, vf->link_up);
+ else
+ ice_set_pfe_link(vf, &pfe, ls->link_speed, ls->link_info &
+ ICE_AQ_LINK_UP);
+
+ ice_aq_send_msg_to_vf(hw, vf->vf_id, VIRTCHNL_OP_EVENT, 0, (u8 *)&pfe,
+ sizeof(pfe), NULL);
+}
+
+/**
+ * ice_get_vf_vector - get VF interrupt vector register offset
+ * @vf_msix: number of MSIx vector per VF on a PF
+ * @vf_id: VF identifier
+ * @i: index of MSIx vector
+ */
+static u32 ice_get_vf_vector(int vf_msix, int vf_id, int i)
+{
+ return ((i == 0) ? VFINT_DYN_CTLN(vf_id) :
+ VFINT_DYN_CTLN(((vf_msix - 1) * (vf_id)) + (i - 1)));
+}
+
+/**
+ * ice_free_vf_res - Free a VF's resources
+ * @vf: pointer to the VF info
+ */
+static void ice_free_vf_res(struct ice_vf *vf)
+{
+ struct ice_pf *pf = vf->pf;
+ int i, pf_vf_msix;
+
+ /* First, disable VF's configuration API to prevent OS from
+ * accessing the VF's VSI after it's freed or invalidated.
+ */
+ clear_bit(ICE_VF_STATE_INIT, vf->vf_states);
+
+ /* free vsi & disconnect it from the parent uplink */
+ if (vf->lan_vsi_idx) {
+ ice_vsi_release(pf->vsi[vf->lan_vsi_idx]);
+ vf->lan_vsi_idx = 0;
+ vf->lan_vsi_num = 0;
+ vf->num_mac = 0;
+ }
+
+ pf_vf_msix = pf->num_vf_msix;
+ /* Disable interrupts so that VF starts in a known state */
+ for (i = 0; i < pf_vf_msix; i++) {
+ u32 reg_idx;
+
+ reg_idx = ice_get_vf_vector(pf_vf_msix, vf->vf_id, i);
+ wr32(&pf->hw, reg_idx, VFINT_DYN_CTLN_CLEARPBA_M);
+ ice_flush(&pf->hw);
+ }
+ /* reset some of the state variables keeping track of the resources */
+ clear_bit(ICE_VF_STATE_MC_PROMISC, vf->vf_states);
+ clear_bit(ICE_VF_STATE_UC_PROMISC, vf->vf_states);
+}
+
+/***********************enable_vf routines*****************************/
+
+/**
+ * ice_dis_vf_mappings
+ * @vf: pointer to the VF structure
+ */
+static void ice_dis_vf_mappings(struct ice_vf *vf)
+{
+ struct ice_pf *pf = vf->pf;
+ struct ice_vsi *vsi;
+ int first, last, v;
+ struct ice_hw *hw;
+
+ hw = &pf->hw;
+ vsi = pf->vsi[vf->lan_vsi_idx];
+
+ wr32(hw, VPINT_ALLOC(vf->vf_id), 0);
+ wr32(hw, VPINT_ALLOC_PCI(vf->vf_id), 0);
+
+ first = vf->first_vector_idx;
+ last = first + pf->num_vf_msix - 1;
+ for (v = first; v <= last; v++) {
+ u32 reg;
+
+ reg = (((1 << GLINT_VECT2FUNC_IS_PF_S) &
+ GLINT_VECT2FUNC_IS_PF_M) |
+ ((hw->pf_id << GLINT_VECT2FUNC_PF_NUM_S) &
+ GLINT_VECT2FUNC_PF_NUM_M));
+ wr32(hw, GLINT_VECT2FUNC(v), reg);
+ }
+
+ if (vsi->tx_mapping_mode == ICE_VSI_MAP_CONTIG)
+ wr32(hw, VPLAN_TX_QBASE(vf->vf_id), 0);
+ else
+ dev_err(&pf->pdev->dev,
+ "Scattered mode for VF Tx queues is not yet implemented\n");
+
+ if (vsi->rx_mapping_mode == ICE_VSI_MAP_CONTIG)
+ wr32(hw, VPLAN_RX_QBASE(vf->vf_id), 0);
+ else
+ dev_err(&pf->pdev->dev,
+ "Scattered mode for VF Rx queues is not yet implemented\n");
+}
+
+/**
+ * ice_free_vfs - Free all VFs
+ * @pf: pointer to the PF structure
+ */
+void ice_free_vfs(struct ice_pf *pf)
+{
+ struct ice_hw *hw = &pf->hw;
+ int tmp, i;
+
+ if (!pf->vf)
+ return;
+
+ while (test_and_set_bit(__ICE_VF_DIS, pf->state))
+ usleep_range(1000, 2000);
+
+ /* Avoid wait time by stopping all VFs at the same time */
+ for (i = 0; i < pf->num_alloc_vfs; i++) {
+ if (!test_bit(ICE_VF_STATE_ENA, pf->vf[i].vf_states))
+ continue;
+
+ /* stop rings without wait time */
+ ice_vsi_stop_tx_rings(pf->vsi[pf->vf[i].lan_vsi_idx],
+ ICE_NO_RESET, i);
+ ice_vsi_stop_rx_rings(pf->vsi[pf->vf[i].lan_vsi_idx]);
+
+ clear_bit(ICE_VF_STATE_ENA, pf->vf[i].vf_states);
+ }
+
+ /* Disable IOV before freeing resources. This lets any VF drivers
+ * running in the host get themselves cleaned up before we yank
+ * the carpet out from underneath their feet.
+ */
+ if (!pci_vfs_assigned(pf->pdev))
+ pci_disable_sriov(pf->pdev);
+ else
+ dev_warn(&pf->pdev->dev, "VFs are assigned - not disabling SR-IOV\n");
+
+ tmp = pf->num_alloc_vfs;
+ pf->num_vf_qps = 0;
+ pf->num_alloc_vfs = 0;
+ for (i = 0; i < tmp; i++) {
+ if (test_bit(ICE_VF_STATE_INIT, pf->vf[i].vf_states)) {
+ /* disable VF qp mappings */
+ ice_dis_vf_mappings(&pf->vf[i]);
+
+ /* Set this state so that assigned VF vectors can be
+ * reclaimed by PF for reuse in ice_vsi_release(). No
+ * need to clear this bit since pf->vf array is being
+ * freed anyways after this for loop
+ */
+ set_bit(ICE_VF_STATE_CFG_INTR, pf->vf[i].vf_states);
+ ice_free_vf_res(&pf->vf[i]);
+ }
+ }
+
+ devm_kfree(&pf->pdev->dev, pf->vf);
+ pf->vf = NULL;
+
+ /* This check is for when the driver is unloaded while VFs are
+ * assigned. Setting the number of VFs to 0 through sysfs is caught
+ * before this function ever gets called.
+ */
+ if (!pci_vfs_assigned(pf->pdev)) {
+ int vf_id;
+
+ /* Acknowledge VFLR for all VFs. Without this, VFs will fail to
+ * work correctly when SR-IOV gets re-enabled.
+ */
+ for (vf_id = 0; vf_id < tmp; vf_id++) {
+ u32 reg_idx, bit_idx;
+
+ reg_idx = (hw->func_caps.vf_base_id + vf_id) / 32;
+ bit_idx = (hw->func_caps.vf_base_id + vf_id) % 32;
+ wr32(hw, GLGEN_VFLRSTAT(reg_idx), BIT(bit_idx));
+ }
+ }
+ clear_bit(__ICE_VF_DIS, pf->state);
+ clear_bit(ICE_FLAG_SRIOV_ENA, pf->flags);
+}
+
+/**
+ * ice_trigger_vf_reset - Reset a VF on HW
+ * @vf: pointer to the VF structure
+ * @is_vflr: true if VFLR was issued, false if not
+ *
+ * Trigger hardware to start a reset for a particular VF. Expects the caller
+ * to wait the proper amount of time to allow hardware to reset the VF before
+ * it cleans up and restores VF functionality.
+ */
+static void ice_trigger_vf_reset(struct ice_vf *vf, bool is_vflr)
+{
+ struct ice_pf *pf = vf->pf;
+ u32 reg, reg_idx, bit_idx;
+ struct ice_hw *hw;
+ int vf_abs_id, i;
+
+ hw = &pf->hw;
+ vf_abs_id = vf->vf_id + hw->func_caps.vf_base_id;
+
+ /* Inform VF that it is no longer active, as a warning */
+ clear_bit(ICE_VF_STATE_ACTIVE, vf->vf_states);
+
+ /* Disable VF's configuration API during reset. The flag is re-enabled
+ * in ice_alloc_vf_res(), when it's safe again to access VF's VSI.
+ * It's normally disabled in ice_free_vf_res(), but it's safer
+ * to do it earlier to give some time to finish to any VF config
+ * functions that may still be running at this point.
+ */
+ clear_bit(ICE_VF_STATE_INIT, vf->vf_states);
+
+ /* In the case of a VFLR, the HW has already reset the VF and we
+ * just need to clean up, so don't hit the VFRTRIG register.
+ */
+ if (!is_vflr) {
+ /* reset VF using VPGEN_VFRTRIG reg */
+ reg = rd32(hw, VPGEN_VFRTRIG(vf->vf_id));
+ reg |= VPGEN_VFRTRIG_VFSWR_M;
+ wr32(hw, VPGEN_VFRTRIG(vf->vf_id), reg);
+ }
+ /* clear the VFLR bit in GLGEN_VFLRSTAT */
+ reg_idx = (vf_abs_id) / 32;
+ bit_idx = (vf_abs_id) % 32;
+ wr32(hw, GLGEN_VFLRSTAT(reg_idx), BIT(bit_idx));
+ ice_flush(hw);
+
+ wr32(hw, PF_PCI_CIAA,
+ VF_DEVICE_STATUS | (vf_abs_id << PF_PCI_CIAA_VF_NUM_S));
+ for (i = 0; i < 100; i++) {
+ reg = rd32(hw, PF_PCI_CIAD);
+ if ((reg & VF_TRANS_PENDING_M) != 0)
+ dev_err(&pf->pdev->dev,
+ "VF %d PCI transactions stuck\n", vf->vf_id);
+ udelay(1);
+ }
+}
+
+/**
+ * ice_vsi_set_pvid - Set port VLAN id for the VSI
+ * @vsi: the VSI being changed
+ * @vid: the VLAN id to set as a PVID
+ */
+static int ice_vsi_set_pvid(struct ice_vsi *vsi, u16 vid)
+{
+ struct device *dev = &vsi->back->pdev->dev;
+ struct ice_hw *hw = &vsi->back->hw;
+ struct ice_vsi_ctx ctxt = { 0 };
+ enum ice_status status;
+
+ ctxt.info.vlan_flags = ICE_AQ_VSI_VLAN_MODE_UNTAGGED |
+ ICE_AQ_VSI_PVLAN_INSERT_PVID |
+ ICE_AQ_VSI_VLAN_EMOD_STR;
+ ctxt.info.pvid = cpu_to_le16(vid);
+ ctxt.info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID);
+
+ status = ice_update_vsi(hw, vsi->idx, &ctxt, NULL);
+ if (status) {
+ dev_info(dev, "update VSI for VLAN insert failed, err %d aq_err %d\n",
+ status, hw->adminq.sq_last_status);
+ return -EIO;
+ }
+
+ vsi->info.pvid = ctxt.info.pvid;
+ vsi->info.vlan_flags = ctxt.info.vlan_flags;
+ return 0;
+}
+
+/**
+ * ice_vsi_kill_pvid - Remove port VLAN id from the VSI
+ * @vsi: the VSI being changed
+ */
+static int ice_vsi_kill_pvid(struct ice_vsi *vsi)
+{
+ struct ice_pf *pf = vsi->back;
+
+ if (ice_vsi_manage_vlan_stripping(vsi, false)) {
+ dev_err(&pf->pdev->dev, "Error removing Port VLAN on VSI %i\n",
+ vsi->vsi_num);
+ return -ENODEV;
+ }
+
+ vsi->info.pvid = 0;
+ return 0;
+}
+
+/**
+ * ice_vf_vsi_setup - Set up a VF VSI
+ * @pf: board private structure
+ * @pi: pointer to the port_info instance
+ * @vf_id: defines VF id to which this VSI connects.
+ *
+ * Returns pointer to the successfully allocated VSI struct on success,
+ * otherwise returns NULL on failure.
+ */
+static struct ice_vsi *
+ice_vf_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi, u16 vf_id)
+{
+ return ice_vsi_setup(pf, pi, ICE_VSI_VF, vf_id);
+}
+
+/**
+ * ice_alloc_vsi_res - Setup VF VSI and its resources
+ * @vf: pointer to the VF structure
+ *
+ * Returns 0 on success, negative value on failure
+ */
+static int ice_alloc_vsi_res(struct ice_vf *vf)
+{
+ struct ice_pf *pf = vf->pf;
+ LIST_HEAD(tmp_add_list);
+ u8 broadcast[ETH_ALEN];
+ struct ice_vsi *vsi;
+ int status = 0;
+
+ vsi = ice_vf_vsi_setup(pf, pf->hw.port_info, vf->vf_id);
+
+ if (!vsi) {
+ dev_err(&pf->pdev->dev, "Failed to create VF VSI\n");
+ return -ENOMEM;
+ }
+
+ vf->lan_vsi_idx = vsi->idx;
+ vf->lan_vsi_num = vsi->vsi_num;
+
+ /* first vector index is the VFs OICR index */
+ vf->first_vector_idx = vsi->hw_base_vector;
+ /* Since hw_base_vector holds the vector where data queue interrupts
+ * starts, increment by 1 since VFs allocated vectors include OICR intr
+ * as well.
+ */
+ vsi->hw_base_vector += 1;
+
+ /* Check if port VLAN exist before, and restore it accordingly */
+ if (vf->port_vlan_id)
+ ice_vsi_set_pvid(vsi, vf->port_vlan_id);
+
+ eth_broadcast_addr(broadcast);
+
+ status = ice_add_mac_to_list(vsi, &tmp_add_list, broadcast);
+ if (status)
+ goto ice_alloc_vsi_res_exit;
+
+ if (is_valid_ether_addr(vf->dflt_lan_addr.addr)) {
+ status = ice_add_mac_to_list(vsi, &tmp_add_list,
+ vf->dflt_lan_addr.addr);
+ if (status)
+ goto ice_alloc_vsi_res_exit;
+ }
+
+ status = ice_add_mac(&pf->hw, &tmp_add_list);
+ if (status)
+ dev_err(&pf->pdev->dev, "could not add mac filters\n");
+
+ /* Clear this bit after VF initialization since we shouldn't reclaim
+ * and reassign interrupts for synchronous or asynchronous VFR events.
+ * We don't want to reconfigure interrupts since AVF driver doesn't
+ * expect vector assignment to be changed unless there is a request for
+ * more vectors.
+ */
+ clear_bit(ICE_VF_STATE_CFG_INTR, vf->vf_states);
+ice_alloc_vsi_res_exit:
+ ice_free_fltr_list(&pf->pdev->dev, &tmp_add_list);
+ return status;
+}
+
+/**
+ * ice_alloc_vf_res - Allocate VF resources
+ * @vf: pointer to the VF structure
+ */
+static int ice_alloc_vf_res(struct ice_vf *vf)
+{
+ int status;
+
+ /* setup VF VSI and necessary resources */
+ status = ice_alloc_vsi_res(vf);
+ if (status)
+ goto ice_alloc_vf_res_exit;
+
+ if (vf->trusted)
+ set_bit(ICE_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps);
+ else
+ clear_bit(ICE_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps);
+
+ /* VF is now completely initialized */
+ set_bit(ICE_VF_STATE_INIT, vf->vf_states);
+
+ return status;
+
+ice_alloc_vf_res_exit:
+ ice_free_vf_res(vf);
+ return status;
+}
+
+/**
+ * ice_ena_vf_mappings
+ * @vf: pointer to the VF structure
+ *
+ * Enable VF vectors and queues allocation by writing the details into
+ * respective registers.
+ */
+static void ice_ena_vf_mappings(struct ice_vf *vf)
+{
+ struct ice_pf *pf = vf->pf;
+ struct ice_vsi *vsi;
+ int first, last, v;
+ struct ice_hw *hw;
+ int abs_vf_id;
+ u32 reg;
+
+ hw = &pf->hw;
+ vsi = pf->vsi[vf->lan_vsi_idx];
+ first = vf->first_vector_idx;
+ last = (first + pf->num_vf_msix) - 1;
+ abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id;
+
+ /* VF Vector allocation */
+ reg = (((first << VPINT_ALLOC_FIRST_S) & VPINT_ALLOC_FIRST_M) |
+ ((last << VPINT_ALLOC_LAST_S) & VPINT_ALLOC_LAST_M) |
+ VPINT_ALLOC_VALID_M);
+ wr32(hw, VPINT_ALLOC(vf->vf_id), reg);
+
+ reg = (((first << VPINT_ALLOC_PCI_FIRST_S) & VPINT_ALLOC_PCI_FIRST_M) |
+ ((last << VPINT_ALLOC_PCI_LAST_S) & VPINT_ALLOC_PCI_LAST_M) |
+ VPINT_ALLOC_PCI_VALID_M);
+ wr32(hw, VPINT_ALLOC_PCI(vf->vf_id), reg);
+ /* map the interrupts to its functions */
+ for (v = first; v <= last; v++) {
+ reg = (((abs_vf_id << GLINT_VECT2FUNC_VF_NUM_S) &
+ GLINT_VECT2FUNC_VF_NUM_M) |
+ ((hw->pf_id << GLINT_VECT2FUNC_PF_NUM_S) &
+ GLINT_VECT2FUNC_PF_NUM_M));
+ wr32(hw, GLINT_VECT2FUNC(v), reg);
+ }
+
+ /* set regardless of mapping mode */
+ wr32(hw, VPLAN_TXQ_MAPENA(vf->vf_id), VPLAN_TXQ_MAPENA_TX_ENA_M);
+
+ /* VF Tx queues allocation */
+ if (vsi->tx_mapping_mode == ICE_VSI_MAP_CONTIG) {
+ /* set the VF PF Tx queue range
+ * VFNUMQ value should be set to (number of queues - 1). A value
+ * of 0 means 1 queue and a value of 255 means 256 queues
+ */
+ reg = (((vsi->txq_map[0] << VPLAN_TX_QBASE_VFFIRSTQ_S) &
+ VPLAN_TX_QBASE_VFFIRSTQ_M) |
+ (((vsi->alloc_txq - 1) << VPLAN_TX_QBASE_VFNUMQ_S) &
+ VPLAN_TX_QBASE_VFNUMQ_M));
+ wr32(hw, VPLAN_TX_QBASE(vf->vf_id), reg);
+ } else {
+ dev_err(&pf->pdev->dev,
+ "Scattered mode for VF Tx queues is not yet implemented\n");
+ }
+
+ /* set regardless of mapping mode */
+ wr32(hw, VPLAN_RXQ_MAPENA(vf->vf_id), VPLAN_RXQ_MAPENA_RX_ENA_M);
+
+ /* VF Rx queues allocation */
+ if (vsi->rx_mapping_mode == ICE_VSI_MAP_CONTIG) {
+ /* set the VF PF Rx queue range
+ * VFNUMQ value should be set to (number of queues - 1). A value
+ * of 0 means 1 queue and a value of 255 means 256 queues
+ */
+ reg = (((vsi->rxq_map[0] << VPLAN_RX_QBASE_VFFIRSTQ_S) &
+ VPLAN_RX_QBASE_VFFIRSTQ_M) |
+ (((vsi->alloc_txq - 1) << VPLAN_RX_QBASE_VFNUMQ_S) &
+ VPLAN_RX_QBASE_VFNUMQ_M));
+ wr32(hw, VPLAN_RX_QBASE(vf->vf_id), reg);
+ } else {
+ dev_err(&pf->pdev->dev,
+ "Scattered mode for VF Rx queues is not yet implemented\n");
+ }
+}
+
+/**
+ * ice_determine_res
+ * @pf: pointer to the PF structure
+ * @avail_res: available resources in the PF structure
+ * @max_res: maximum resources that can be given per VF
+ * @min_res: minimum resources that can be given per VF
+ *
+ * Returns non-zero value if resources (queues/vectors) are available or
+ * returns zero if PF cannot accommodate for all num_alloc_vfs.
+ */
+static int
+ice_determine_res(struct ice_pf *pf, u16 avail_res, u16 max_res, u16 min_res)
+{
+ bool checked_min_res = false;
+ int res;
+
+ /* start by checking if PF can assign max number of resources for
+ * all num_alloc_vfs.
+ * if yes, return number per VF
+ * If no, divide by 2 and roundup, check again
+ * repeat the loop till we reach a point where even minimum resources
+ * are not available, in that case return 0
+ */
+ res = max_res;
+ while ((res >= min_res) && !checked_min_res) {
+ int num_all_res;
+
+ num_all_res = pf->num_alloc_vfs * res;
+ if (num_all_res <= avail_res)
+ return res;
+
+ if (res == min_res)
+ checked_min_res = true;
+
+ res = DIV_ROUND_UP(res, 2);
+ }
+ return 0;
+}
+
+/**
+ * ice_check_avail_res - check if vectors and queues are available
+ * @pf: pointer to the PF structure
+ *
+ * This function is where we calculate actual number of resources for VF VSIs,
+ * we don't reserve ahead of time during probe. Returns success if vectors and
+ * queues resources are available, otherwise returns error code
+ */
+static int ice_check_avail_res(struct ice_pf *pf)
+{
+ u16 num_msix, num_txq, num_rxq;
+
+ if (!pf->num_alloc_vfs)
+ return -EINVAL;
+
+ /* Grab from HW interrupts common pool
+ * Note: By the time the user decides it needs more vectors in a VF
+ * its already too late since one must decide this prior to creating the
+ * VF interface. So the best we can do is take a guess as to what the
+ * user might want.
+ *
+ * We have two policies for vector allocation:
+ * 1. if num_alloc_vfs is from 1 to 16, then we consider this as small
+ * number of NFV VFs used for NFV appliances, since this is a special
+ * case, we try to assign maximum vectors per VF (65) as much as
+ * possible, based on determine_resources algorithm.
+ * 2. if num_alloc_vfs is from 17 to 256, then its large number of
+ * regular VFs which are not used for any special purpose. Hence try to
+ * grab default interrupt vectors (5 as supported by AVF driver).
+ */
+ if (pf->num_alloc_vfs <= 16) {
+ num_msix = ice_determine_res(pf, pf->num_avail_hw_msix,
+ ICE_MAX_INTR_PER_VF,
+ ICE_MIN_INTR_PER_VF);
+ } else if (pf->num_alloc_vfs <= ICE_MAX_VF_COUNT) {
+ num_msix = ice_determine_res(pf, pf->num_avail_hw_msix,
+ ICE_DFLT_INTR_PER_VF,
+ ICE_MIN_INTR_PER_VF);
+ } else {
+ dev_err(&pf->pdev->dev,
+ "Number of VFs %d exceeds max VF count %d\n",
+ pf->num_alloc_vfs, ICE_MAX_VF_COUNT);
+ return -EIO;
+ }
+
+ if (!num_msix)
+ return -EIO;
+
+ /* Grab from the common pool
+ * start by requesting Default queues (4 as supported by AVF driver),
+ * Note that, the main difference between queues and vectors is, latter
+ * can only be reserved at init time but queues can be requested by VF
+ * at runtime through Virtchnl, that is the reason we start by reserving
+ * few queues.
+ */
+ num_txq = ice_determine_res(pf, pf->q_left_tx, ICE_DFLT_QS_PER_VF,
+ ICE_MIN_QS_PER_VF);
+
+ num_rxq = ice_determine_res(pf, pf->q_left_rx, ICE_DFLT_QS_PER_VF,
+ ICE_MIN_QS_PER_VF);
+
+ if (!num_txq || !num_rxq)
+ return -EIO;
+
+ /* since AVF driver works with only queue pairs which means, it expects
+ * to have equal number of Rx and Tx queues, so take the minimum of
+ * available Tx or Rx queues
+ */
+ pf->num_vf_qps = min_t(int, num_txq, num_rxq);
+ pf->num_vf_msix = num_msix;
+
+ return 0;
+}
+
+/**
+ * ice_cleanup_and_realloc_vf - Clean up VF and reallocate resources after reset
+ * @vf: pointer to the VF structure
+ *
+ * Cleanup a VF after the hardware reset is finished. Expects the caller to
+ * have verified whether the reset is finished properly, and ensure the
+ * minimum amount of wait time has passed. Reallocate VF resources back to make
+ * VF state active
+ */
+static void ice_cleanup_and_realloc_vf(struct ice_vf *vf)
+{
+ struct ice_pf *pf = vf->pf;
+ struct ice_hw *hw;
+ u32 reg;
+
+ hw = &pf->hw;
+
+ /* PF software completes the flow by notifying VF that reset flow is
+ * completed. This is done by enabling hardware by clearing the reset
+ * bit in the VPGEN_VFRTRIG reg and setting VFR_STATE in the VFGEN_RSTAT
+ * register to VFR completed (done at the end of this function)
+ * By doing this we allow HW to access VF memory at any point. If we
+ * did it any sooner, HW could access memory while it was being freed
+ * in ice_free_vf_res(), causing an IOMMU fault.
+ *
+ * On the other hand, this needs to be done ASAP, because the VF driver
+ * is waiting for this to happen and may report a timeout. It's
+ * harmless, but it gets logged into Guest OS kernel log, so best avoid
+ * it.
+ */
+ reg = rd32(hw, VPGEN_VFRTRIG(vf->vf_id));
+ reg &= ~VPGEN_VFRTRIG_VFSWR_M;
+ wr32(hw, VPGEN_VFRTRIG(vf->vf_id), reg);
+
+ /* reallocate VF resources to finish resetting the VSI state */
+ if (!ice_alloc_vf_res(vf)) {
+ ice_ena_vf_mappings(vf);
+ set_bit(ICE_VF_STATE_ACTIVE, vf->vf_states);
+ clear_bit(ICE_VF_STATE_DIS, vf->vf_states);
+ vf->num_vlan = 0;
+ }
+
+ /* Tell the VF driver the reset is done. This needs to be done only
+ * after VF has been fully initialized, because the VF driver may
+ * request resources immediately after setting this flag.
+ */
+ wr32(hw, VFGEN_RSTAT(vf->vf_id), VIRTCHNL_VFR_VFACTIVE);
+}
+
+/**
+ * ice_reset_all_vfs - reset all allocated VFs in one go
+ * @pf: pointer to the PF structure
+ * @is_vflr: true if VFLR was issued, false if not
+ *
+ * First, tell the hardware to reset each VF, then do all the waiting in one
+ * chunk, and finally finish restoring each VF after the wait. This is useful
+ * during PF routines which need to reset all VFs, as otherwise it must perform
+ * these resets in a serialized fashion.
+ *
+ * Returns true if any VFs were reset, and false otherwise.
+ */
+bool ice_reset_all_vfs(struct ice_pf *pf, bool is_vflr)
+{
+ struct ice_hw *hw = &pf->hw;
+ int v, i;
+
+ /* If we don't have any VFs, then there is nothing to reset */
+ if (!pf->num_alloc_vfs)
+ return false;
+
+ /* If VFs have been disabled, there is no need to reset */
+ if (test_and_set_bit(__ICE_VF_DIS, pf->state))
+ return false;
+
+ /* Begin reset on all VFs at once */
+ for (v = 0; v < pf->num_alloc_vfs; v++)
+ ice_trigger_vf_reset(&pf->vf[v], is_vflr);
+
+ /* Call Disable LAN Tx queue AQ call with VFR bit set and 0
+ * queues to inform Firmware about VF reset.
+ */
+ for (v = 0; v < pf->num_alloc_vfs; v++)
+ ice_dis_vsi_txq(pf->vsi[0]->port_info, 0, NULL, NULL,
+ ICE_VF_RESET, v, NULL);
+
+ /* HW requires some time to make sure it can flush the FIFO for a VF
+ * when it resets it. Poll the VPGEN_VFRSTAT register for each VF in
+ * sequence to make sure that it has completed. We'll keep track of
+ * the VFs using a simple iterator that increments once that VF has
+ * finished resetting.
+ */
+ for (i = 0, v = 0; i < 10 && v < pf->num_alloc_vfs; i++) {
+ usleep_range(10000, 20000);
+
+ /* Check each VF in sequence */
+ while (v < pf->num_alloc_vfs) {
+ struct ice_vf *vf = &pf->vf[v];
+ u32 reg;
+
+ reg = rd32(hw, VPGEN_VFRSTAT(vf->vf_id));
+ if (!(reg & VPGEN_VFRSTAT_VFRD_M))
+ break;
+
+ /* If the current VF has finished resetting, move on
+ * to the next VF in sequence.
+ */
+ v++;
+ }
+ }
+
+ /* Display a warning if at least one VF didn't manage to reset in
+ * time, but continue on with the operation.
+ */
+ if (v < pf->num_alloc_vfs)
+ dev_warn(&pf->pdev->dev, "VF reset check timeout\n");
+ usleep_range(10000, 20000);
+
+ /* free VF resources to begin resetting the VSI state */
+ for (v = 0; v < pf->num_alloc_vfs; v++)
+ ice_free_vf_res(&pf->vf[v]);
+
+ if (ice_check_avail_res(pf)) {
+ dev_err(&pf->pdev->dev,
+ "Cannot allocate VF resources, try with fewer number of VFs\n");
+ return false;
+ }
+
+ /* Finish the reset on each VF */
+ for (v = 0; v < pf->num_alloc_vfs; v++)
+ ice_cleanup_and_realloc_vf(&pf->vf[v]);
+
+ ice_flush(hw);
+ clear_bit(__ICE_VF_DIS, pf->state);
+
+ return true;
+}
+
+/**
+ * ice_reset_vf - Reset a particular VF
+ * @vf: pointer to the VF structure
+ * @is_vflr: true if VFLR was issued, false if not
+ *
+ * Returns true if the VF is reset, false otherwise.
+ */
+static bool ice_reset_vf(struct ice_vf *vf, bool is_vflr)
+{
+ struct ice_pf *pf = vf->pf;
+ struct ice_hw *hw = &pf->hw;
+ bool rsd = false;
+ u32 reg;
+ int i;
+
+ /* If the VFs have been disabled, this means something else is
+ * resetting the VF, so we shouldn't continue.
+ */
+ if (test_and_set_bit(__ICE_VF_DIS, pf->state))
+ return false;
+
+ ice_trigger_vf_reset(vf, is_vflr);
+
+ if (test_bit(ICE_VF_STATE_ENA, vf->vf_states)) {
+ ice_vsi_stop_tx_rings(pf->vsi[vf->lan_vsi_idx], ICE_VF_RESET,
+ vf->vf_id);
+ ice_vsi_stop_rx_rings(pf->vsi[vf->lan_vsi_idx]);
+ clear_bit(ICE_VF_STATE_ENA, vf->vf_states);
+ } else {
+ /* Call Disable LAN Tx queue AQ call even when queues are not
+ * enabled. This is needed for successful completiom of VFR
+ */
+ ice_dis_vsi_txq(pf->vsi[vf->lan_vsi_idx]->port_info, 0,
+ NULL, NULL, ICE_VF_RESET, vf->vf_id, NULL);
+ }
+
+ /* poll VPGEN_VFRSTAT reg to make sure
+ * that reset is complete
+ */
+ for (i = 0; i < 10; i++) {
+ /* VF reset requires driver to first reset the VF and then
+ * poll the status register to make sure that the reset
+ * completed successfully.
+ */
+ usleep_range(10000, 20000);
+ reg = rd32(hw, VPGEN_VFRSTAT(vf->vf_id));
+ if (reg & VPGEN_VFRSTAT_VFRD_M) {
+ rsd = true;
+ break;
+ }
+ }
+
+ /* Display a warning if VF didn't manage to reset in time, but need to
+ * continue on with the operation.
+ */
+ if (!rsd)
+ dev_warn(&pf->pdev->dev, "VF reset check timeout on VF %d\n",
+ vf->vf_id);
+
+ usleep_range(10000, 20000);
+
+ /* free VF resources to begin resetting the VSI state */
+ ice_free_vf_res(vf);
+
+ ice_cleanup_and_realloc_vf(vf);
+
+ ice_flush(hw);
+ clear_bit(__ICE_VF_DIS, pf->state);
+
+ return true;
+}
+
+/**
+ * ice_vc_notify_link_state - Inform all VFs on a PF of link status
+ * @pf: pointer to the PF structure
+ */
+void ice_vc_notify_link_state(struct ice_pf *pf)
+{
+ int i;
+
+ for (i = 0; i < pf->num_alloc_vfs; i++)
+ ice_vc_notify_vf_link_state(&pf->vf[i]);
+}
+
+/**
+ * ice_vc_notify_reset - Send pending reset message to all VFs
+ * @pf: pointer to the PF structure
+ *
+ * indicate a pending reset to all VFs on a given PF
+ */
+void ice_vc_notify_reset(struct ice_pf *pf)
+{
+ struct virtchnl_pf_event pfe;
+
+ if (!pf->num_alloc_vfs)
+ return;
+
+ pfe.event = VIRTCHNL_EVENT_RESET_IMPENDING;
+ pfe.severity = PF_EVENT_SEVERITY_CERTAIN_DOOM;
+ ice_vc_vf_broadcast(pf, VIRTCHNL_OP_EVENT, ICE_SUCCESS,
+ (u8 *)&pfe, sizeof(struct virtchnl_pf_event));
+}
+
+/**
+ * ice_vc_notify_vf_reset - Notify VF of a reset event
+ * @vf: pointer to the VF structure
+ */
+static void ice_vc_notify_vf_reset(struct ice_vf *vf)
+{
+ struct virtchnl_pf_event pfe;
+
+ /* validate the request */
+ if (!vf || vf->vf_id >= vf->pf->num_alloc_vfs)
+ return;
+
+ /* verify if the VF is in either init or active before proceeding */
+ if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states) &&
+ !test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states))
+ return;
+
+ pfe.event = VIRTCHNL_EVENT_RESET_IMPENDING;
+ pfe.severity = PF_EVENT_SEVERITY_CERTAIN_DOOM;
+ ice_aq_send_msg_to_vf(&vf->pf->hw, vf->vf_id, VIRTCHNL_OP_EVENT, 0,
+ (u8 *)&pfe, sizeof(pfe), NULL);
+}
+
+/**
+ * ice_alloc_vfs - Allocate and set up VFs resources
+ * @pf: pointer to the PF structure
+ * @num_alloc_vfs: number of VFs to allocate
+ */
+static int ice_alloc_vfs(struct ice_pf *pf, u16 num_alloc_vfs)
+{
+ struct ice_hw *hw = &pf->hw;
+ struct ice_vf *vfs;
+ int i, ret;
+
+ /* Disable global interrupt 0 so we don't try to handle the VFLR. */
+ wr32(hw, GLINT_DYN_CTL(pf->hw_oicr_idx),
+ ICE_ITR_NONE << GLINT_DYN_CTL_ITR_INDX_S);
+
+ ice_flush(hw);
+
+ ret = pci_enable_sriov(pf->pdev, num_alloc_vfs);
+ if (ret) {
+ pf->num_alloc_vfs = 0;
+ goto err_unroll_intr;
+ }
+ /* allocate memory */
+ vfs = devm_kcalloc(&pf->pdev->dev, num_alloc_vfs, sizeof(*vfs),
+ GFP_KERNEL);
+ if (!vfs) {
+ ret = -ENOMEM;
+ goto err_unroll_sriov;
+ }
+ pf->vf = vfs;
+
+ /* apply default profile */
+ for (i = 0; i < num_alloc_vfs; i++) {
+ vfs[i].pf = pf;
+ vfs[i].vf_sw_id = pf->first_sw;
+ vfs[i].vf_id = i;
+
+ /* assign default capabilities */
+ set_bit(ICE_VIRTCHNL_VF_CAP_L2, &vfs[i].vf_caps);
+ vfs[i].spoofchk = true;
+
+ /* Set this state so that PF driver does VF vector assignment */
+ set_bit(ICE_VF_STATE_CFG_INTR, vfs[i].vf_states);
+ }
+ pf->num_alloc_vfs = num_alloc_vfs;
+
+ /* VF resources get allocated during reset */
+ if (!ice_reset_all_vfs(pf, false))
+ goto err_unroll_sriov;
+
+ goto err_unroll_intr;
+
+err_unroll_sriov:
+ pci_disable_sriov(pf->pdev);
+err_unroll_intr:
+ /* rearm interrupts here */
+ ice_irq_dynamic_ena(hw, NULL, NULL);
+ return ret;
+}
+
+/**
+ * ice_pf_state_is_nominal - checks the pf for nominal state
+ * @pf: pointer to pf to check
+ *
+ * Check the PF's state for a collection of bits that would indicate
+ * the PF is in a state that would inhibit normal operation for
+ * driver functionality.
+ *
+ * Returns true if PF is in a nominal state.
+ * Returns false otherwise
+ */
+static bool ice_pf_state_is_nominal(struct ice_pf *pf)
+{
+ DECLARE_BITMAP(check_bits, __ICE_STATE_NBITS) = { 0 };
+
+ if (!pf)
+ return false;
+
+ bitmap_set(check_bits, 0, __ICE_STATE_NOMINAL_CHECK_BITS);
+ if (bitmap_intersects(pf->state, check_bits, __ICE_STATE_NBITS))
+ return false;
+
+ return true;
+}
+
+/**
+ * ice_pci_sriov_ena - Enable or change number of VFs
+ * @pf: pointer to the PF structure
+ * @num_vfs: number of VFs to allocate
+ */
+static int ice_pci_sriov_ena(struct ice_pf *pf, int num_vfs)
+{
+ int pre_existing_vfs = pci_num_vf(pf->pdev);
+ struct device *dev = &pf->pdev->dev;
+ int err;
+
+ if (!ice_pf_state_is_nominal(pf)) {
+ dev_err(dev, "Cannot enable SR-IOV, device not ready\n");
+ return -EBUSY;
+ }
+
+ if (!test_bit(ICE_FLAG_SRIOV_CAPABLE, pf->flags)) {
+ dev_err(dev, "This device is not capable of SR-IOV\n");
+ return -ENODEV;
+ }
+
+ if (pre_existing_vfs && pre_existing_vfs != num_vfs)
+ ice_free_vfs(pf);
+ else if (pre_existing_vfs && pre_existing_vfs == num_vfs)
+ return num_vfs;
+
+ if (num_vfs > pf->num_vfs_supported) {
+ dev_err(dev, "Can't enable %d VFs, max VFs supported is %d\n",
+ num_vfs, pf->num_vfs_supported);
+ return -ENOTSUPP;
+ }
+
+ dev_info(dev, "Allocating %d VFs\n", num_vfs);
+ err = ice_alloc_vfs(pf, num_vfs);
+ if (err) {
+ dev_err(dev, "Failed to enable SR-IOV: %d\n", err);
+ return err;
+ }
+
+ set_bit(ICE_FLAG_SRIOV_ENA, pf->flags);
+ return num_vfs;
+}
+
+/**
+ * ice_sriov_configure - Enable or change number of VFs via sysfs
+ * @pdev: pointer to a pci_dev structure
+ * @num_vfs: number of VFs to allocate
+ *
+ * This function is called when the user updates the number of VFs in sysfs.
+ */
+int ice_sriov_configure(struct pci_dev *pdev, int num_vfs)
+{
+ struct ice_pf *pf = pci_get_drvdata(pdev);
+
+ if (num_vfs)
+ return ice_pci_sriov_ena(pf, num_vfs);
+
+ if (!pci_vfs_assigned(pdev)) {
+ ice_free_vfs(pf);
+ } else {
+ dev_err(&pf->pdev->dev,
+ "can't free VFs because some are assigned to VMs.\n");
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+/**
+ * ice_process_vflr_event - Free VF resources via IRQ calls
+ * @pf: pointer to the PF structure
+ *
+ * called from the VLFR IRQ handler to
+ * free up VF resources and state variables
+ */
+void ice_process_vflr_event(struct ice_pf *pf)
+{
+ struct ice_hw *hw = &pf->hw;
+ int vf_id;
+ u32 reg;
+
+ if (!test_bit(__ICE_VFLR_EVENT_PENDING, pf->state) ||
+ !pf->num_alloc_vfs)
+ return;
+
+ /* Re-enable the VFLR interrupt cause here, before looking for which
+ * VF got reset. Otherwise, if another VF gets a reset while the
+ * first one is being processed, that interrupt will be lost, and
+ * that VF will be stuck in reset forever.
+ */
+ reg = rd32(hw, PFINT_OICR_ENA);
+ reg |= PFINT_OICR_VFLR_M;
+ wr32(hw, PFINT_OICR_ENA, reg);
+ ice_flush(hw);
+
+ clear_bit(__ICE_VFLR_EVENT_PENDING, pf->state);
+ for (vf_id = 0; vf_id < pf->num_alloc_vfs; vf_id++) {
+ struct ice_vf *vf = &pf->vf[vf_id];
+ u32 reg_idx, bit_idx;
+
+ reg_idx = (hw->func_caps.vf_base_id + vf_id) / 32;
+ bit_idx = (hw->func_caps.vf_base_id + vf_id) % 32;
+ /* read GLGEN_VFLRSTAT register to find out the flr VFs */
+ reg = rd32(hw, GLGEN_VFLRSTAT(reg_idx));
+ if (reg & BIT(bit_idx))
+ /* GLGEN_VFLRSTAT bit will be cleared in ice_reset_vf */
+ ice_reset_vf(vf, true);
+ }
+}
+
+/**
+ * ice_vc_dis_vf - Disable a given VF via SW reset
+ * @vf: pointer to the VF info
+ *
+ * Disable the VF through a SW reset
+ */
+static void ice_vc_dis_vf(struct ice_vf *vf)
+{
+ ice_vc_notify_vf_reset(vf);
+ ice_reset_vf(vf, false);
+}
+
+/**
+ * ice_vc_send_msg_to_vf - Send message to VF
+ * @vf: pointer to the VF info
+ * @v_opcode: virtual channel opcode
+ * @v_retval: virtual channel return value
+ * @msg: pointer to the msg buffer
+ * @msglen: msg length
+ *
+ * send msg to VF
+ */
+static int ice_vc_send_msg_to_vf(struct ice_vf *vf, u32 v_opcode,
+ enum ice_status v_retval, u8 *msg, u16 msglen)
+{
+ enum ice_status aq_ret;
+ struct ice_pf *pf;
+
+ /* validate the request */
+ if (!vf || vf->vf_id >= vf->pf->num_alloc_vfs)
+ return -EINVAL;
+
+ pf = vf->pf;
+
+ /* single place to detect unsuccessful return values */
+ if (v_retval) {
+ vf->num_inval_msgs++;
+ dev_info(&pf->pdev->dev, "VF %d failed opcode %d, retval: %d\n",
+ vf->vf_id, v_opcode, v_retval);
+ if (vf->num_inval_msgs > ICE_DFLT_NUM_INVAL_MSGS_ALLOWED) {
+ dev_err(&pf->pdev->dev,
+ "Number of invalid messages exceeded for VF %d\n",
+ vf->vf_id);
+ dev_err(&pf->pdev->dev, "Use PF Control I/F to enable the VF\n");
+ set_bit(ICE_VF_STATE_DIS, vf->vf_states);
+ return -EIO;
+ }
+ } else {
+ vf->num_valid_msgs++;
+ /* reset the invalid counter, if a valid message is received. */
+ vf->num_inval_msgs = 0;
+ }
+
+ aq_ret = ice_aq_send_msg_to_vf(&pf->hw, vf->vf_id, v_opcode, v_retval,
+ msg, msglen, NULL);
+ if (aq_ret) {
+ dev_info(&pf->pdev->dev,
+ "Unable to send the message to VF %d aq_err %d\n",
+ vf->vf_id, pf->hw.mailboxq.sq_last_status);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/**
+ * ice_vc_get_ver_msg
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * called from the VF to request the API version used by the PF
+ */
+static int ice_vc_get_ver_msg(struct ice_vf *vf, u8 *msg)
+{
+ struct virtchnl_version_info info = {
+ VIRTCHNL_VERSION_MAJOR, VIRTCHNL_VERSION_MINOR
+ };
+
+ vf->vf_ver = *(struct virtchnl_version_info *)msg;
+ /* VFs running the 1.0 API expect to get 1.0 back or they will cry. */
+ if (VF_IS_V10(&vf->vf_ver))
+ info.minor = VIRTCHNL_VERSION_MINOR_NO_VF_CAPS;
+
+ return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_VERSION, ICE_SUCCESS,
+ (u8 *)&info,
+ sizeof(struct virtchnl_version_info));
+}
+
+/**
+ * ice_vc_get_vf_res_msg
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * called from the VF to request its resources
+ */
+static int ice_vc_get_vf_res_msg(struct ice_vf *vf, u8 *msg)
+{
+ struct virtchnl_vf_resource *vfres = NULL;
+ enum ice_status aq_ret = 0;
+ struct ice_pf *pf = vf->pf;
+ struct ice_vsi *vsi;
+ int len = 0;
+ int ret;
+
+ if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states)) {
+ aq_ret = ICE_ERR_PARAM;
+ goto err;
+ }
+
+ len = sizeof(struct virtchnl_vf_resource);
+
+ vfres = devm_kzalloc(&pf->pdev->dev, len, GFP_KERNEL);
+ if (!vfres) {
+ aq_ret = ICE_ERR_NO_MEMORY;
+ len = 0;
+ goto err;
+ }
+ if (VF_IS_V11(&vf->vf_ver))
+ vf->driver_caps = *(u32 *)msg;
+ else
+ vf->driver_caps = VIRTCHNL_VF_OFFLOAD_L2 |
+ VIRTCHNL_VF_OFFLOAD_RSS_REG |
+ VIRTCHNL_VF_OFFLOAD_VLAN;
+
+ vfres->vf_cap_flags = VIRTCHNL_VF_OFFLOAD_L2;
+ vsi = pf->vsi[vf->lan_vsi_idx];
+ if (!vsi->info.pvid)
+ vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_VLAN;
+
+ if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_PF) {
+ vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_PF;
+ } else {
+ if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_AQ)
+ vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_AQ;
+ else
+ vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_REG;
+ }
+
+ if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2)
+ vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2;
+
+ if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_ENCAP)
+ vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_ENCAP;
+
+ if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM)
+ vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM;
+
+ if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RX_POLLING)
+ vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RX_POLLING;
+
+ if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_WB_ON_ITR)
+ vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_WB_ON_ITR;
+
+ if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_REQ_QUEUES)
+ vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_REQ_QUEUES;
+
+ if (vf->driver_caps & VIRTCHNL_VF_CAP_ADV_LINK_SPEED)
+ vfres->vf_cap_flags |= VIRTCHNL_VF_CAP_ADV_LINK_SPEED;
+
+ vfres->num_vsis = 1;
+ /* Tx and Rx queue are equal for VF */
+ vfres->num_queue_pairs = vsi->num_txq;
+ vfres->max_vectors = pf->num_vf_msix;
+ vfres->rss_key_size = ICE_VSIQF_HKEY_ARRAY_SIZE;
+ vfres->rss_lut_size = ICE_VSIQF_HLUT_ARRAY_SIZE;
+
+ vfres->vsi_res[0].vsi_id = vf->lan_vsi_num;
+ 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);
+
+ set_bit(ICE_VF_STATE_ACTIVE, vf->vf_states);
+
+err:
+ /* send the response back to the VF */
+ ret = ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_GET_VF_RESOURCES, aq_ret,
+ (u8 *)vfres, len);
+
+ devm_kfree(&pf->pdev->dev, vfres);
+ return ret;
+}
+
+/**
+ * ice_vc_reset_vf_msg
+ * @vf: pointer to the VF info
+ *
+ * called from the VF to reset itself,
+ * unlike other virtchnl messages, PF driver
+ * doesn't send the response back to the VF
+ */
+static void ice_vc_reset_vf_msg(struct ice_vf *vf)
+{
+ if (test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states))
+ ice_reset_vf(vf, false);
+}
+
+/**
+ * ice_find_vsi_from_id
+ * @pf: the pf structure to search for the VSI
+ * @id: id of the VSI it is searching for
+ *
+ * searches for the VSI with the given id
+ */
+static struct ice_vsi *ice_find_vsi_from_id(struct ice_pf *pf, u16 id)
+{
+ int i;
+
+ for (i = 0; i < pf->num_alloc_vsi; i++)
+ if (pf->vsi[i] && pf->vsi[i]->vsi_num == id)
+ return pf->vsi[i];
+
+ return NULL;
+}
+
+/**
+ * ice_vc_isvalid_vsi_id
+ * @vf: pointer to the VF info
+ * @vsi_id: VF relative VSI id
+ *
+ * check for the valid VSI id
+ */
+static bool ice_vc_isvalid_vsi_id(struct ice_vf *vf, u16 vsi_id)
+{
+ struct ice_pf *pf = vf->pf;
+ struct ice_vsi *vsi;
+
+ vsi = ice_find_vsi_from_id(pf, vsi_id);
+
+ return (vsi && (vsi->vf_id == vf->vf_id));
+}
+
+/**
+ * ice_vc_isvalid_q_id
+ * @vf: pointer to the VF info
+ * @vsi_id: VSI id
+ * @qid: VSI relative queue id
+ *
+ * check for the valid queue id
+ */
+static bool ice_vc_isvalid_q_id(struct ice_vf *vf, u16 vsi_id, u8 qid)
+{
+ struct ice_vsi *vsi = ice_find_vsi_from_id(vf->pf, vsi_id);
+ /* allocated Tx and Rx queues should be always equal for VF VSI */
+ return (vsi && (qid < vsi->alloc_txq));
+}
+
+/**
+ * ice_vc_config_rss_key
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * Configure the VF's RSS key
+ */
+static int ice_vc_config_rss_key(struct ice_vf *vf, u8 *msg)
+{
+ struct virtchnl_rss_key *vrk =
+ (struct virtchnl_rss_key *)msg;
+ struct ice_vsi *vsi = NULL;
+ enum ice_status aq_ret;
+ int ret;
+
+ if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+
+ if (!ice_vc_isvalid_vsi_id(vf, vrk->vsi_id)) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+
+ vsi = ice_find_vsi_from_id(vf->pf, vrk->vsi_id);
+ if (!vsi) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+
+ if (vrk->key_len != ICE_VSIQF_HKEY_ARRAY_SIZE) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+
+ if (!test_bit(ICE_FLAG_RSS_ENA, vf->pf->flags)) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+
+ ret = ice_set_rss(vsi, vrk->key, NULL, 0);
+ aq_ret = ret ? ICE_ERR_PARAM : ICE_SUCCESS;
+error_param:
+ return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_RSS_KEY, aq_ret,
+ NULL, 0);
+}
+
+/**
+ * ice_vc_config_rss_lut
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * Configure the VF's RSS LUT
+ */
+static int ice_vc_config_rss_lut(struct ice_vf *vf, u8 *msg)
+{
+ struct virtchnl_rss_lut *vrl = (struct virtchnl_rss_lut *)msg;
+ struct ice_vsi *vsi = NULL;
+ enum ice_status aq_ret;
+ int ret;
+
+ if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+
+ if (!ice_vc_isvalid_vsi_id(vf, vrl->vsi_id)) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+
+ vsi = ice_find_vsi_from_id(vf->pf, vrl->vsi_id);
+ if (!vsi) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+
+ if (vrl->lut_entries != ICE_VSIQF_HLUT_ARRAY_SIZE) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+
+ if (!test_bit(ICE_FLAG_RSS_ENA, vf->pf->flags)) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+
+ ret = ice_set_rss(vsi, NULL, vrl->lut, ICE_VSIQF_HLUT_ARRAY_SIZE);
+ aq_ret = ret ? ICE_ERR_PARAM : ICE_SUCCESS;
+error_param:
+ return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_RSS_LUT, aq_ret,
+ NULL, 0);
+}
+
+/**
+ * ice_vc_get_stats_msg
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * called from the VF to get VSI stats
+ */
+static int ice_vc_get_stats_msg(struct ice_vf *vf, u8 *msg)
+{
+ struct virtchnl_queue_select *vqs =
+ (struct virtchnl_queue_select *)msg;
+ enum ice_status aq_ret = 0;
+ struct ice_eth_stats stats;
+ struct ice_vsi *vsi;
+
+ if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+
+ if (!ice_vc_isvalid_vsi_id(vf, vqs->vsi_id)) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+
+ vsi = ice_find_vsi_from_id(vf->pf, vqs->vsi_id);
+ if (!vsi) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+
+ memset(&stats, 0, sizeof(struct ice_eth_stats));
+ ice_update_eth_stats(vsi);
+
+ stats = vsi->eth_stats;
+
+error_param:
+ /* send the response to the VF */
+ return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_GET_STATS, aq_ret,
+ (u8 *)&stats, sizeof(stats));
+}
+
+/**
+ * ice_vc_ena_qs_msg
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * called from the VF to enable all or specific queue(s)
+ */
+static int ice_vc_ena_qs_msg(struct ice_vf *vf, u8 *msg)
+{
+ struct virtchnl_queue_select *vqs =
+ (struct virtchnl_queue_select *)msg;
+ enum ice_status aq_ret = 0;
+ struct ice_vsi *vsi;
+
+ if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+
+ if (!ice_vc_isvalid_vsi_id(vf, vqs->vsi_id)) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+
+ if (!vqs->rx_queues && !vqs->tx_queues) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+
+ vsi = ice_find_vsi_from_id(vf->pf, vqs->vsi_id);
+ if (!vsi) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+
+ /* Enable only Rx rings, Tx rings were enabled by the FW when the
+ * Tx queue group list was configured and the context bits were
+ * programmed using ice_vsi_cfg_txqs
+ */
+ if (ice_vsi_start_rx_rings(vsi))
+ aq_ret = ICE_ERR_PARAM;
+
+ /* Set flag to indicate that queues are enabled */
+ if (!aq_ret)
+ set_bit(ICE_VF_STATE_ENA, vf->vf_states);
+
+error_param:
+ /* send the response to the VF */
+ return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_ENABLE_QUEUES, aq_ret,
+ NULL, 0);
+}
+
+/**
+ * ice_vc_dis_qs_msg
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * called from the VF to disable all or specific
+ * queue(s)
+ */
+static int ice_vc_dis_qs_msg(struct ice_vf *vf, u8 *msg)
+{
+ struct virtchnl_queue_select *vqs =
+ (struct virtchnl_queue_select *)msg;
+ enum ice_status aq_ret = 0;
+ struct ice_vsi *vsi;
+
+ if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states) &&
+ !test_bit(ICE_VF_STATE_ENA, vf->vf_states)) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+
+ if (!ice_vc_isvalid_vsi_id(vf, vqs->vsi_id)) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+
+ if (!vqs->rx_queues && !vqs->tx_queues) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+
+ vsi = ice_find_vsi_from_id(vf->pf, vqs->vsi_id);
+ if (!vsi) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+
+ if (ice_vsi_stop_tx_rings(vsi, ICE_NO_RESET, vf->vf_id)) {
+ dev_err(&vsi->back->pdev->dev,
+ "Failed to stop tx rings on VSI %d\n",
+ vsi->vsi_num);
+ aq_ret = ICE_ERR_PARAM;
+ }
+
+ if (ice_vsi_stop_rx_rings(vsi)) {
+ dev_err(&vsi->back->pdev->dev,
+ "Failed to stop rx rings on VSI %d\n",
+ vsi->vsi_num);
+ aq_ret = ICE_ERR_PARAM;
+ }
+
+ /* Clear enabled queues flag */
+ if (!aq_ret)
+ clear_bit(ICE_VF_STATE_ENA, vf->vf_states);
+
+error_param:
+ /* send the response to the VF */
+ return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_DISABLE_QUEUES, aq_ret,
+ NULL, 0);
+}
+
+/**
+ * ice_vc_cfg_irq_map_msg
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * called from the VF to configure the IRQ to queue map
+ */
+static int ice_vc_cfg_irq_map_msg(struct ice_vf *vf, u8 *msg)
+{
+ struct virtchnl_irq_map_info *irqmap_info =
+ (struct virtchnl_irq_map_info *)msg;
+ u16 vsi_id, vsi_q_id, vector_id;
+ struct virtchnl_vector_map *map;
+ struct ice_vsi *vsi = NULL;
+ struct ice_pf *pf = vf->pf;
+ enum ice_status aq_ret = 0;
+ unsigned long qmap;
+ int i;
+
+ if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+
+ for (i = 0; i < irqmap_info->num_vectors; i++) {
+ map = &irqmap_info->vecmap[i];
+
+ vector_id = map->vector_id;
+ vsi_id = map->vsi_id;
+ /* validate msg params */
+ if (!(vector_id < pf->hw.func_caps.common_cap
+ .num_msix_vectors) || !ice_vc_isvalid_vsi_id(vf, vsi_id)) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+
+ vsi = ice_find_vsi_from_id(vf->pf, vsi_id);
+ if (!vsi) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+
+ /* lookout for the invalid queue index */
+ qmap = map->rxq_map;
+ for_each_set_bit(vsi_q_id, &qmap, ICE_MAX_BASE_QS_PER_VF) {
+ struct ice_q_vector *q_vector;
+
+ if (!ice_vc_isvalid_q_id(vf, vsi_id, vsi_q_id)) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+ q_vector = vsi->q_vectors[i];
+ q_vector->num_ring_rx++;
+ q_vector->rx.itr_idx = map->rxitr_idx;
+ vsi->rx_rings[vsi_q_id]->q_vector = q_vector;
+ }
+
+ qmap = map->txq_map;
+ for_each_set_bit(vsi_q_id, &qmap, ICE_MAX_BASE_QS_PER_VF) {
+ struct ice_q_vector *q_vector;
+
+ if (!ice_vc_isvalid_q_id(vf, vsi_id, vsi_q_id)) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+ q_vector = vsi->q_vectors[i];
+ q_vector->num_ring_tx++;
+ q_vector->tx.itr_idx = map->txitr_idx;
+ vsi->tx_rings[vsi_q_id]->q_vector = q_vector;
+ }
+ }
+
+ if (vsi)
+ ice_vsi_cfg_msix(vsi);
+error_param:
+ /* send the response to the VF */
+ return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_IRQ_MAP, aq_ret,
+ NULL, 0);
+}
+
+/**
+ * ice_vc_cfg_qs_msg
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * called from the VF to configure the Rx/Tx queues
+ */
+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;
+ enum ice_status aq_ret = 0;
+ struct ice_vsi *vsi;
+ int i;
+
+ if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+
+ if (!ice_vc_isvalid_vsi_id(vf, qci->vsi_id)) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+
+ vsi = ice_find_vsi_from_id(vf->pf, qci->vsi_id);
+ if (!vsi) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+
+ for (i = 0; i < qci->num_queue_pairs; i++) {
+ qpi = &qci->qpair[i];
+ if (qpi->txq.vsi_id != qci->vsi_id ||
+ qpi->rxq.vsi_id != qci->vsi_id ||
+ qpi->rxq.queue_id != qpi->txq.queue_id ||
+ !ice_vc_isvalid_q_id(vf, qci->vsi_id, qpi->txq.queue_id)) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+ /* copy Tx queue info from VF into VSI */
+ vsi->tx_rings[i]->dma = qpi->txq.dma_ring_addr;
+ vsi->tx_rings[i]->count = qpi->txq.ring_len;
+ /* copy Rx queue info from VF into vsi */
+ vsi->rx_rings[i]->dma = qpi->rxq.dma_ring_addr;
+ vsi->rx_rings[i]->count = qpi->rxq.ring_len;
+ if (qpi->rxq.databuffer_size > ((16 * 1024) - 128)) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+ vsi->rx_buf_len = qpi->rxq.databuffer_size;
+ if (qpi->rxq.max_pkt_size >= (16 * 1024) ||
+ qpi->rxq.max_pkt_size < 64) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+ vsi->max_frame = qpi->rxq.max_pkt_size;
+ }
+
+ /* VF can request to configure less than allocated queues
+ * or default allocated queues. So update the VSI with new number
+ */
+ vsi->num_txq = qci->num_queue_pairs;
+ vsi->num_rxq = qci->num_queue_pairs;
+
+ if (!ice_vsi_cfg_txqs(vsi) && !ice_vsi_cfg_rxqs(vsi))
+ aq_ret = 0;
+ else
+ aq_ret = ICE_ERR_PARAM;
+
+error_param:
+ /* send the response to the VF */
+ return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_VSI_QUEUES, aq_ret,
+ NULL, 0);
+}
+
+/**
+ * ice_is_vf_trusted
+ * @vf: pointer to the VF info
+ */
+static bool ice_is_vf_trusted(struct ice_vf *vf)
+{
+ return test_bit(ICE_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps);
+}
+
+/**
+ * ice_can_vf_change_mac
+ * @vf: pointer to the VF info
+ *
+ * Return true if the VF is allowed to change its MAC filters, false otherwise
+ */
+static bool ice_can_vf_change_mac(struct ice_vf *vf)
+{
+ /* If the VF MAC address has been set administratively (via the
+ * ndo_set_vf_mac command), then deny permission to the VF to
+ * add/delete unicast MAC addresses, unless the VF is trusted
+ */
+ if (vf->pf_set_mac && !ice_is_vf_trusted(vf))
+ return false;
+
+ return true;
+}
+
+/**
+ * ice_vc_handle_mac_addr_msg
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ * @set: true if mac filters are being set, false otherwise
+ *
+ * add guest mac address filter
+ */
+static int
+ice_vc_handle_mac_addr_msg(struct ice_vf *vf, u8 *msg, bool set)
+{
+ struct virtchnl_ether_addr_list *al =
+ (struct virtchnl_ether_addr_list *)msg;
+ struct ice_pf *pf = vf->pf;
+ enum virtchnl_ops vc_op;
+ enum ice_status ret;
+ LIST_HEAD(mac_list);
+ struct ice_vsi *vsi;
+ int mac_count = 0;
+ int i;
+
+ if (set)
+ vc_op = VIRTCHNL_OP_ADD_ETH_ADDR;
+ else
+ vc_op = VIRTCHNL_OP_DEL_ETH_ADDR;
+
+ if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states) ||
+ !ice_vc_isvalid_vsi_id(vf, al->vsi_id)) {
+ ret = ICE_ERR_PARAM;
+ goto handle_mac_exit;
+ }
+
+ if (set && !ice_is_vf_trusted(vf) &&
+ (vf->num_mac + al->num_elements) > ICE_MAX_MACADDR_PER_VF) {
+ dev_err(&pf->pdev->dev,
+ "Can't add more MAC addresses, because VF is not trusted, switch the VF to trusted mode in order to add more functionalities\n");
+ ret = ICE_ERR_PARAM;
+ goto handle_mac_exit;
+ }
+
+ vsi = pf->vsi[vf->lan_vsi_idx];
+
+ for (i = 0; i < al->num_elements; i++) {
+ u8 *maddr = al->list[i].addr;
+
+ if (ether_addr_equal(maddr, vf->dflt_lan_addr.addr) ||
+ is_broadcast_ether_addr(maddr)) {
+ if (set) {
+ /* VF is trying to add filters that the PF
+ * already added. Just continue.
+ */
+ dev_info(&pf->pdev->dev,
+ "mac %pM already set for VF %d\n",
+ maddr, vf->vf_id);
+ continue;
+ } else {
+ /* VF can't remove dflt_lan_addr/bcast mac */
+ dev_err(&pf->pdev->dev,
+ "can't remove mac %pM for VF %d\n",
+ maddr, vf->vf_id);
+ ret = ICE_ERR_PARAM;
+ goto handle_mac_exit;
+ }
+ }
+
+ /* check for the invalid cases and bail if necessary */
+ if (is_zero_ether_addr(maddr)) {
+ dev_err(&pf->pdev->dev,
+ "invalid mac %pM provided for VF %d\n",
+ maddr, vf->vf_id);
+ ret = ICE_ERR_PARAM;
+ goto handle_mac_exit;
+ }
+
+ if (is_unicast_ether_addr(maddr) &&
+ !ice_can_vf_change_mac(vf)) {
+ dev_err(&pf->pdev->dev,
+ "can't change unicast mac for untrusted VF %d\n",
+ vf->vf_id);
+ ret = ICE_ERR_PARAM;
+ goto handle_mac_exit;
+ }
+
+ /* get here if maddr is multicast or if VF can change mac */
+ if (ice_add_mac_to_list(vsi, &mac_list, al->list[i].addr)) {
+ ret = ICE_ERR_NO_MEMORY;
+ goto handle_mac_exit;
+ }
+ mac_count++;
+ }
+
+ /* program the updated filter list */
+ if (set)
+ ret = ice_add_mac(&pf->hw, &mac_list);
+ else
+ ret = ice_remove_mac(&pf->hw, &mac_list);
+
+ if (ret) {
+ dev_err(&pf->pdev->dev,
+ "can't update mac filters for VF %d, error %d\n",
+ vf->vf_id, ret);
+ } else {
+ if (set)
+ vf->num_mac += mac_count;
+ else
+ vf->num_mac -= mac_count;
+ }
+
+handle_mac_exit:
+ ice_free_fltr_list(&pf->pdev->dev, &mac_list);
+ /* send the response to the VF */
+ return ice_vc_send_msg_to_vf(vf, vc_op, ret, NULL, 0);
+}
+
+/**
+ * ice_vc_add_mac_addr_msg
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * add guest MAC address filter
+ */
+static int ice_vc_add_mac_addr_msg(struct ice_vf *vf, u8 *msg)
+{
+ return ice_vc_handle_mac_addr_msg(vf, msg, true);
+}
+
+/**
+ * ice_vc_del_mac_addr_msg
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * remove guest MAC address filter
+ */
+static int ice_vc_del_mac_addr_msg(struct ice_vf *vf, u8 *msg)
+{
+ return ice_vc_handle_mac_addr_msg(vf, msg, false);
+}
+
+/**
+ * ice_vc_request_qs_msg
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * VFs get a default number of queues but can use this message to request a
+ * different number. If the request is successful, PF will reset the VF and
+ * return 0. If unsuccessful, PF will send message informing VF of number of
+ * available queue pairs via virtchnl message response to VF.
+ */
+static int ice_vc_request_qs_msg(struct ice_vf *vf, u8 *msg)
+{
+ struct virtchnl_vf_res_request *vfres =
+ (struct virtchnl_vf_res_request *)msg;
+ int req_queues = vfres->num_queue_pairs;
+ enum ice_status aq_ret = 0;
+ struct ice_pf *pf = vf->pf;
+ int tx_rx_queue_left;
+ int cur_queues;
+
+ if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+
+ cur_queues = pf->num_vf_qps;
+ tx_rx_queue_left = min_t(int, pf->q_left_tx, pf->q_left_rx);
+ if (req_queues <= 0) {
+ dev_err(&pf->pdev->dev,
+ "VF %d tried to request %d queues. Ignoring.\n",
+ vf->vf_id, req_queues);
+ } else if (req_queues > ICE_MAX_QS_PER_VF) {
+ dev_err(&pf->pdev->dev,
+ "VF %d tried to request more than %d queues.\n",
+ vf->vf_id, ICE_MAX_QS_PER_VF);
+ vfres->num_queue_pairs = ICE_MAX_QS_PER_VF;
+ } else if (req_queues - cur_queues > tx_rx_queue_left) {
+ dev_warn(&pf->pdev->dev,
+ "VF %d requested %d more queues, but only %d left.\n",
+ vf->vf_id, req_queues - cur_queues, tx_rx_queue_left);
+ vfres->num_queue_pairs = tx_rx_queue_left + cur_queues;
+ } else {
+ /* request is successful, then reset VF */
+ vf->num_req_qs = req_queues;
+ ice_vc_dis_vf(vf);
+ dev_info(&pf->pdev->dev,
+ "VF %d granted request of %d queues.\n",
+ vf->vf_id, req_queues);
+ return 0;
+ }
+
+error_param:
+ /* send the response to the VF */
+ return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_REQUEST_QUEUES,
+ aq_ret, (u8 *)vfres, sizeof(*vfres));
+}
+
+/**
+ * ice_set_vf_port_vlan
+ * @netdev: network interface device structure
+ * @vf_id: VF identifier
+ * @vlan_id: VLAN id being set
+ * @qos: priority setting
+ * @vlan_proto: VLAN protocol
+ *
+ * program VF Port VLAN id and/or qos
+ */
+int
+ice_set_vf_port_vlan(struct net_device *netdev, int vf_id, u16 vlan_id, u8 qos,
+ __be16 vlan_proto)
+{
+ u16 vlanprio = vlan_id | (qos << ICE_VLAN_PRIORITY_S);
+ struct ice_netdev_priv *np = netdev_priv(netdev);
+ struct ice_pf *pf = np->vsi->back;
+ struct ice_vsi *vsi;
+ struct ice_vf *vf;
+ int ret = 0;
+
+ /* validate the request */
+ if (vf_id >= pf->num_alloc_vfs) {
+ dev_err(&pf->pdev->dev, "invalid VF id: %d\n", vf_id);
+ return -EINVAL;
+ }
+
+ if (vlan_id > ICE_MAX_VLANID || qos > 7) {
+ dev_err(&pf->pdev->dev, "Invalid VF Parameters\n");
+ return -EINVAL;
+ }
+
+ if (vlan_proto != htons(ETH_P_8021Q)) {
+ dev_err(&pf->pdev->dev, "VF VLAN protocol is not supported\n");
+ return -EPROTONOSUPPORT;
+ }
+
+ vf = &pf->vf[vf_id];
+ vsi = pf->vsi[vf->lan_vsi_idx];
+ if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states)) {
+ dev_err(&pf->pdev->dev, "VF %d in reset. Try again.\n", vf_id);
+ return -EBUSY;
+ }
+
+ if (le16_to_cpu(vsi->info.pvid) == vlanprio) {
+ /* duplicate request, so just return success */
+ dev_info(&pf->pdev->dev,
+ "Duplicate pvid %d request\n", vlanprio);
+ return ret;
+ }
+
+ /* If pvid, then remove all filters on the old VLAN */
+ if (vsi->info.pvid)
+ ice_vsi_kill_vlan(vsi, (le16_to_cpu(vsi->info.pvid) &
+ VLAN_VID_MASK));
+
+ if (vlan_id || qos) {
+ ret = ice_vsi_set_pvid(vsi, vlanprio);
+ if (ret)
+ goto error_set_pvid;
+ } else {
+ ice_vsi_kill_pvid(vsi);
+ }
+
+ if (vlan_id) {
+ dev_info(&pf->pdev->dev, "Setting VLAN %d, QOS 0x%x on VF %d\n",
+ vlan_id, qos, vf_id);
+
+ /* add new VLAN filter for each MAC */
+ ret = ice_vsi_add_vlan(vsi, vlan_id);
+ if (ret)
+ goto error_set_pvid;
+ }
+
+ /* The Port VLAN needs to be saved across resets the same as the
+ * default LAN MAC address.
+ */
+ vf->port_vlan_id = le16_to_cpu(vsi->info.pvid);
+
+error_set_pvid:
+ return ret;
+}
+
+/**
+ * ice_vc_process_vlan_msg
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ * @add_v: Add VLAN if true, otherwise delete VLAN
+ *
+ * Process virtchnl op to add or remove programmed guest VLAN id
+ */
+static int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v)
+{
+ struct virtchnl_vlan_filter_list *vfl =
+ (struct virtchnl_vlan_filter_list *)msg;
+ enum ice_status aq_ret = 0;
+ struct ice_pf *pf = vf->pf;
+ struct ice_vsi *vsi;
+ int i;
+
+ if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+
+ if (!ice_vc_isvalid_vsi_id(vf, vfl->vsi_id)) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+
+ if (add_v && !ice_is_vf_trusted(vf) &&
+ vf->num_vlan >= ICE_MAX_VLAN_PER_VF) {
+ dev_info(&pf->pdev->dev,
+ "VF is not trusted, switch the VF to trusted mode, in order to add more VLAN addresses\n");
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+
+ for (i = 0; i < vfl->num_elements; i++) {
+ if (vfl->vlan_id[i] > ICE_MAX_VLANID) {
+ aq_ret = ICE_ERR_PARAM;
+ dev_err(&pf->pdev->dev,
+ "invalid VF VLAN id %d\n", vfl->vlan_id[i]);
+ goto error_param;
+ }
+ }
+
+ vsi = ice_find_vsi_from_id(vf->pf, vfl->vsi_id);
+ if (!vsi) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+
+ if (vsi->info.pvid) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+
+ if (ice_vsi_manage_vlan_stripping(vsi, add_v)) {
+ dev_err(&pf->pdev->dev,
+ "%sable VLAN stripping failed for VSI %i\n",
+ add_v ? "en" : "dis", vsi->vsi_num);
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+
+ if (add_v) {
+ for (i = 0; i < vfl->num_elements; i++) {
+ u16 vid = vfl->vlan_id[i];
+
+ if (!ice_vsi_add_vlan(vsi, vid)) {
+ vf->num_vlan++;
+
+ /* Enable VLAN pruning when VLAN 0 is added */
+ if (unlikely(!vid))
+ if (ice_cfg_vlan_pruning(vsi, true))
+ aq_ret = ICE_ERR_PARAM;
+ } else {
+ aq_ret = ICE_ERR_PARAM;
+ }
+ }
+ } else {
+ for (i = 0; i < vfl->num_elements; i++) {
+ u16 vid = vfl->vlan_id[i];
+
+ /* Make sure ice_vsi_kill_vlan is successful before
+ * updating VLAN information
+ */
+ if (!ice_vsi_kill_vlan(vsi, vid)) {
+ vf->num_vlan--;
+
+ /* Disable VLAN pruning when removing VLAN 0 */
+ if (unlikely(!vid))
+ ice_cfg_vlan_pruning(vsi, false);
+ }
+ }
+ }
+
+error_param:
+ /* send the response to the VF */
+ if (add_v)
+ return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_ADD_VLAN, aq_ret,
+ NULL, 0);
+ else
+ return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_DEL_VLAN, aq_ret,
+ NULL, 0);
+}
+
+/**
+ * ice_vc_add_vlan_msg
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * Add and program guest VLAN id
+ */
+static int ice_vc_add_vlan_msg(struct ice_vf *vf, u8 *msg)
+{
+ return ice_vc_process_vlan_msg(vf, msg, true);
+}
+
+/**
+ * ice_vc_remove_vlan_msg
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * remove programmed guest VLAN id
+ */
+static int ice_vc_remove_vlan_msg(struct ice_vf *vf, u8 *msg)
+{
+ return ice_vc_process_vlan_msg(vf, msg, false);
+}
+
+/**
+ * ice_vc_ena_vlan_stripping
+ * @vf: pointer to the VF info
+ *
+ * Enable VLAN header stripping for a given VF
+ */
+static int ice_vc_ena_vlan_stripping(struct ice_vf *vf)
+{
+ enum ice_status aq_ret = 0;
+ struct ice_pf *pf = vf->pf;
+ struct ice_vsi *vsi;
+
+ if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+
+ vsi = pf->vsi[vf->lan_vsi_idx];
+ if (ice_vsi_manage_vlan_stripping(vsi, true))
+ aq_ret = ICE_ERR_AQ_ERROR;
+
+error_param:
+ return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_ENABLE_VLAN_STRIPPING,
+ aq_ret, NULL, 0);
+}
+
+/**
+ * ice_vc_dis_vlan_stripping
+ * @vf: pointer to the VF info
+ *
+ * Disable VLAN header stripping for a given VF
+ */
+static int ice_vc_dis_vlan_stripping(struct ice_vf *vf)
+{
+ enum ice_status aq_ret = 0;
+ struct ice_pf *pf = vf->pf;
+ struct ice_vsi *vsi;
+
+ if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) {
+ aq_ret = ICE_ERR_PARAM;
+ goto error_param;
+ }
+
+ vsi = pf->vsi[vf->lan_vsi_idx];
+ if (ice_vsi_manage_vlan_stripping(vsi, false))
+ aq_ret = ICE_ERR_AQ_ERROR;
+
+error_param:
+ return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_DISABLE_VLAN_STRIPPING,
+ aq_ret, NULL, 0);
+}
+
+/**
+ * ice_vc_process_vf_msg - Process request from VF
+ * @pf: pointer to the PF structure
+ * @event: pointer to the AQ event
+ *
+ * called from the common asq/arq handler to
+ * process request from VF
+ */
+void ice_vc_process_vf_msg(struct ice_pf *pf, struct ice_rq_event_info *event)
+{
+ u32 v_opcode = le32_to_cpu(event->desc.cookie_high);
+ s16 vf_id = le16_to_cpu(event->desc.retval);
+ u16 msglen = event->msg_len;
+ u8 *msg = event->msg_buf;
+ struct ice_vf *vf = NULL;
+ int err = 0;
+
+ if (vf_id >= pf->num_alloc_vfs) {
+ err = -EINVAL;
+ goto error_handler;
+ }
+
+ vf = &pf->vf[vf_id];
+
+ /* Check if VF is disabled. */
+ if (test_bit(ICE_VF_STATE_DIS, vf->vf_states)) {
+ err = -EPERM;
+ goto error_handler;
+ }
+
+ /* Perform basic checks on the msg */
+ err = virtchnl_vc_validate_vf_msg(&vf->vf_ver, v_opcode, msg, msglen);
+ if (err) {
+ if (err == VIRTCHNL_ERR_PARAM)
+ err = -EPERM;
+ else
+ err = -EINVAL;
+ goto error_handler;
+ }
+
+ /* Perform additional checks specific to RSS and Virtchnl */
+ if (v_opcode == VIRTCHNL_OP_CONFIG_RSS_KEY) {
+ struct virtchnl_rss_key *vrk = (struct virtchnl_rss_key *)msg;
+
+ if (vrk->key_len != ICE_VSIQF_HKEY_ARRAY_SIZE)
+ err = -EINVAL;
+ } else if (v_opcode == VIRTCHNL_OP_CONFIG_RSS_LUT) {
+ struct virtchnl_rss_lut *vrl = (struct virtchnl_rss_lut *)msg;
+
+ if (vrl->lut_entries != ICE_VSIQF_HLUT_ARRAY_SIZE)
+ err = -EINVAL;
+ }
+
+error_handler:
+ if (err) {
+ ice_vc_send_msg_to_vf(vf, v_opcode, ICE_ERR_PARAM, NULL, 0);
+ dev_err(&pf->pdev->dev, "Invalid message from VF %d, opcode %d, len %d, error %d\n",
+ vf_id, v_opcode, msglen, err);
+ return;
+ }
+
+ switch (v_opcode) {
+ case VIRTCHNL_OP_VERSION:
+ err = ice_vc_get_ver_msg(vf, msg);
+ break;
+ case VIRTCHNL_OP_GET_VF_RESOURCES:
+ err = ice_vc_get_vf_res_msg(vf, msg);
+ break;
+ case VIRTCHNL_OP_RESET_VF:
+ ice_vc_reset_vf_msg(vf);
+ break;
+ case VIRTCHNL_OP_ADD_ETH_ADDR:
+ err = ice_vc_add_mac_addr_msg(vf, msg);
+ break;
+ case VIRTCHNL_OP_DEL_ETH_ADDR:
+ err = ice_vc_del_mac_addr_msg(vf, msg);
+ break;
+ case VIRTCHNL_OP_CONFIG_VSI_QUEUES:
+ err = ice_vc_cfg_qs_msg(vf, msg);
+ break;
+ case VIRTCHNL_OP_ENABLE_QUEUES:
+ err = ice_vc_ena_qs_msg(vf, msg);
+ ice_vc_notify_vf_link_state(vf);
+ break;
+ case VIRTCHNL_OP_DISABLE_QUEUES:
+ err = ice_vc_dis_qs_msg(vf, msg);
+ break;
+ case VIRTCHNL_OP_REQUEST_QUEUES:
+ err = ice_vc_request_qs_msg(vf, msg);
+ break;
+ case VIRTCHNL_OP_CONFIG_IRQ_MAP:
+ err = ice_vc_cfg_irq_map_msg(vf, msg);
+ break;
+ case VIRTCHNL_OP_CONFIG_RSS_KEY:
+ err = ice_vc_config_rss_key(vf, msg);
+ break;
+ case VIRTCHNL_OP_CONFIG_RSS_LUT:
+ err = ice_vc_config_rss_lut(vf, msg);
+ break;
+ case VIRTCHNL_OP_GET_STATS:
+ err = ice_vc_get_stats_msg(vf, msg);
+ break;
+ case VIRTCHNL_OP_ADD_VLAN:
+ err = ice_vc_add_vlan_msg(vf, msg);
+ break;
+ case VIRTCHNL_OP_DEL_VLAN:
+ err = ice_vc_remove_vlan_msg(vf, msg);
+ break;
+ case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING:
+ err = ice_vc_ena_vlan_stripping(vf);
+ break;
+ case VIRTCHNL_OP_DISABLE_VLAN_STRIPPING:
+ err = ice_vc_dis_vlan_stripping(vf);
+ break;
+ case VIRTCHNL_OP_UNKNOWN:
+ default:
+ dev_err(&pf->pdev->dev, "Unsupported opcode %d from VF %d\n",
+ v_opcode, vf_id);
+ err = ice_vc_send_msg_to_vf(vf, v_opcode, ICE_ERR_NOT_IMPL,
+ NULL, 0);
+ break;
+ }
+ if (err) {
+ /* Helper function cares less about error return values here
+ * as it is busy with pending work.
+ */
+ dev_info(&pf->pdev->dev,
+ "PF failed to honor VF %d, opcode %d\n, error %d\n",
+ vf_id, v_opcode, err);
+ }
+}
+
+/**
+ * ice_get_vf_cfg
+ * @netdev: network interface device structure
+ * @vf_id: VF identifier
+ * @ivi: VF configuration structure
+ *
+ * return VF configuration
+ */
+int ice_get_vf_cfg(struct net_device *netdev, int vf_id,
+ struct ifla_vf_info *ivi)
+{
+ struct ice_netdev_priv *np = netdev_priv(netdev);
+ struct ice_vsi *vsi = np->vsi;
+ struct ice_pf *pf = vsi->back;
+ struct ice_vf *vf;
+
+ /* validate the request */
+ if (vf_id >= pf->num_alloc_vfs) {
+ netdev_err(netdev, "invalid VF id: %d\n", vf_id);
+ return -EINVAL;
+ }
+
+ vf = &pf->vf[vf_id];
+ vsi = pf->vsi[vf->lan_vsi_idx];
+
+ if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states)) {
+ netdev_err(netdev, "VF %d in reset. Try again.\n", vf_id);
+ return -EBUSY;
+ }
+
+ ivi->vf = vf_id;
+ ether_addr_copy(ivi->mac, vf->dflt_lan_addr.addr);
+
+ /* VF configuration for VLAN and applicable QoS */
+ ivi->vlan = le16_to_cpu(vsi->info.pvid) & ICE_VLAN_M;
+ ivi->qos = (le16_to_cpu(vsi->info.pvid) & ICE_PRIORITY_M) >>
+ ICE_VLAN_PRIORITY_S;
+
+ ivi->trusted = vf->trusted;
+ ivi->spoofchk = vf->spoofchk;
+ if (!vf->link_forced)
+ ivi->linkstate = IFLA_VF_LINK_STATE_AUTO;
+ else if (vf->link_up)
+ ivi->linkstate = IFLA_VF_LINK_STATE_ENABLE;
+ else
+ ivi->linkstate = IFLA_VF_LINK_STATE_DISABLE;
+ ivi->max_tx_rate = vf->tx_rate;
+ ivi->min_tx_rate = 0;
+ return 0;
+}
+
+/**
+ * ice_set_vf_spoofchk
+ * @netdev: network interface device structure
+ * @vf_id: VF identifier
+ * @ena: flag to enable or disable feature
+ *
+ * Enable or disable VF spoof checking
+ */
+int ice_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool ena)
+{
+ struct ice_netdev_priv *np = netdev_priv(netdev);
+ struct ice_vsi_ctx ctx = { 0 };
+ struct ice_vsi *vsi = np->vsi;
+ struct ice_pf *pf = vsi->back;
+ struct ice_vf *vf;
+ int status;
+
+ /* validate the request */
+ if (vf_id >= pf->num_alloc_vfs) {
+ netdev_err(netdev, "invalid VF id: %d\n", vf_id);
+ return -EINVAL;
+ }
+
+ vf = &pf->vf[vf_id];
+ if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states)) {
+ netdev_err(netdev, "VF %d in reset. Try again.\n", vf_id);
+ return -EBUSY;
+ }
+
+ if (ena == vf->spoofchk) {
+ dev_dbg(&pf->pdev->dev, "VF spoofchk already %s\n",
+ ena ? "ON" : "OFF");
+ return 0;
+ }
+
+ ctx.info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_SECURITY_VALID);
+
+ if (ena) {
+ ctx.info.sec_flags |= ICE_AQ_VSI_SEC_FLAG_ENA_MAC_ANTI_SPOOF;
+ ctx.info.sw_flags2 |= ICE_AQ_VSI_SW_FLAG_RX_PRUNE_EN_M;
+ }
+
+ status = ice_update_vsi(&pf->hw, vsi->idx, &ctx, NULL);
+ if (status) {
+ dev_dbg(&pf->pdev->dev,
+ "Error %d, failed to update VSI* parameters\n", status);
+ return -EIO;
+ }
+
+ vf->spoofchk = ena;
+ vsi->info.sec_flags = ctx.info.sec_flags;
+ vsi->info.sw_flags2 = ctx.info.sw_flags2;
+
+ return status;
+}
+
+/**
+ * ice_set_vf_mac
+ * @netdev: network interface device structure
+ * @vf_id: VF identifier
+ * @mac: mac address
+ *
+ * program VF mac address
+ */
+int ice_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
+{
+ struct ice_netdev_priv *np = netdev_priv(netdev);
+ struct ice_vsi *vsi = np->vsi;
+ struct ice_pf *pf = vsi->back;
+ struct ice_vf *vf;
+ int ret = 0;
+
+ /* validate the request */
+ if (vf_id >= pf->num_alloc_vfs) {
+ netdev_err(netdev, "invalid VF id: %d\n", vf_id);
+ return -EINVAL;
+ }
+
+ vf = &pf->vf[vf_id];
+ if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states)) {
+ netdev_err(netdev, "VF %d in reset. Try again.\n", vf_id);
+ return -EBUSY;
+ }
+
+ if (is_zero_ether_addr(mac) || is_multicast_ether_addr(mac)) {
+ netdev_err(netdev, "%pM not a valid unicast address\n", mac);
+ return -EINVAL;
+ }
+
+ /* copy mac into dflt_lan_addr and trigger a VF reset. The reset
+ * flow will use the updated dflt_lan_addr and add a MAC filter
+ * using ice_add_mac. Also set pf_set_mac to indicate that the PF has
+ * set the MAC address for this VF.
+ */
+ ether_addr_copy(vf->dflt_lan_addr.addr, mac);
+ vf->pf_set_mac = true;
+ netdev_info(netdev,
+ "mac on VF %d set to %pM\n. VF driver will be reinitialized\n",
+ vf_id, mac);
+
+ ice_vc_dis_vf(vf);
+ return ret;
+}
+
+/**
+ * ice_set_vf_trust
+ * @netdev: network interface device structure
+ * @vf_id: VF identifier
+ * @trusted: Boolean value to enable/disable trusted VF
+ *
+ * Enable or disable a given VF as trusted
+ */
+int ice_set_vf_trust(struct net_device *netdev, int vf_id, bool trusted)
+{
+ struct ice_netdev_priv *np = netdev_priv(netdev);
+ struct ice_vsi *vsi = np->vsi;
+ struct ice_pf *pf = vsi->back;
+ struct ice_vf *vf;
+
+ /* validate the request */
+ if (vf_id >= pf->num_alloc_vfs) {
+ dev_err(&pf->pdev->dev, "invalid VF id: %d\n", vf_id);
+ return -EINVAL;
+ }
+
+ vf = &pf->vf[vf_id];
+ if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states)) {
+ dev_err(&pf->pdev->dev, "VF %d in reset. Try again.\n", vf_id);
+ return -EBUSY;
+ }
+
+ /* Check if already trusted */
+ if (trusted == vf->trusted)
+ return 0;
+
+ vf->trusted = trusted;
+ ice_vc_dis_vf(vf);
+ dev_info(&pf->pdev->dev, "VF %u is now %strusted\n",
+ vf_id, trusted ? "" : "un");
+
+ return 0;
+}
+
+/**
+ * ice_set_vf_link_state
+ * @netdev: network interface device structure
+ * @vf_id: VF identifier
+ * @link_state: required link state
+ *
+ * Set VF's link state, irrespective of physical link state status
+ */
+int ice_set_vf_link_state(struct net_device *netdev, int vf_id, int link_state)
+{
+ struct ice_netdev_priv *np = netdev_priv(netdev);
+ struct ice_pf *pf = np->vsi->back;
+ struct virtchnl_pf_event pfe = { 0 };
+ struct ice_link_status *ls;
+ struct ice_vf *vf;
+ struct ice_hw *hw;
+
+ if (vf_id >= pf->num_alloc_vfs) {
+ dev_err(&pf->pdev->dev, "Invalid VF Identifier %d\n", vf_id);
+ return -EINVAL;
+ }
+
+ vf = &pf->vf[vf_id];
+ hw = &pf->hw;
+ ls = &pf->hw.port_info->phy.link_info;
+
+ if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states)) {
+ dev_err(&pf->pdev->dev, "vf %d in reset. Try again.\n", vf_id);
+ return -EBUSY;
+ }
+
+ pfe.event = VIRTCHNL_EVENT_LINK_CHANGE;
+ pfe.severity = PF_EVENT_SEVERITY_INFO;
+
+ switch (link_state) {
+ case IFLA_VF_LINK_STATE_AUTO:
+ vf->link_forced = false;
+ vf->link_up = ls->link_info & ICE_AQ_LINK_UP;
+ break;
+ case IFLA_VF_LINK_STATE_ENABLE:
+ vf->link_forced = true;
+ vf->link_up = true;
+ break;
+ case IFLA_VF_LINK_STATE_DISABLE:
+ vf->link_forced = true;
+ vf->link_up = false;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (vf->link_forced)
+ ice_set_pfe_link_forced(vf, &pfe, vf->link_up);
+ else
+ ice_set_pfe_link(vf, &pfe, ls->link_speed, vf->link_up);
+
+ /* Notify the VF of its new link state */
+ ice_aq_send_msg_to_vf(hw, vf->vf_id, VIRTCHNL_OP_EVENT, 0, (u8 *)&pfe,
+ sizeof(pfe), NULL);
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h
new file mode 100644
index 000000000000..10131e0180f9
--- /dev/null
+++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h
@@ -0,0 +1,173 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2018, Intel Corporation. */
+
+#ifndef _ICE_VIRTCHNL_PF_H_
+#define _ICE_VIRTCHNL_PF_H_
+#include "ice.h"
+
+#define ICE_MAX_VLANID 4095
+#define ICE_VLAN_PRIORITY_S 12
+#define ICE_VLAN_M 0xFFF
+#define ICE_PRIORITY_M 0x7000
+
+/* Restrict number of MAC Addr and VLAN that non-trusted VF can programmed */
+#define ICE_MAX_VLAN_PER_VF 8
+#define ICE_MAX_MACADDR_PER_VF 12
+
+/* Malicious Driver Detection */
+#define ICE_DFLT_NUM_MDD_EVENTS_ALLOWED 3
+#define ICE_DFLT_NUM_INVAL_MSGS_ALLOWED 10
+
+/* Static VF transaction/status register def */
+#define VF_DEVICE_STATUS 0xAA
+#define VF_TRANS_PENDING_M 0x20
+
+/* Specific VF states */
+enum ice_vf_states {
+ ICE_VF_STATE_INIT = 0,
+ ICE_VF_STATE_ACTIVE,
+ ICE_VF_STATE_ENA,
+ ICE_VF_STATE_DIS,
+ ICE_VF_STATE_MC_PROMISC,
+ ICE_VF_STATE_UC_PROMISC,
+ /* state to indicate if PF needs to do vector assignment for VF.
+ * This needs to be set during first time VF initialization or later
+ * when VF asks for more Vectors through virtchnl OP.
+ */
+ ICE_VF_STATE_CFG_INTR,
+ ICE_VF_STATES_NBITS
+};
+
+/* VF capabilities */
+enum ice_virtchnl_cap {
+ ICE_VIRTCHNL_VF_CAP_L2 = 0,
+ ICE_VIRTCHNL_VF_CAP_PRIVILEGE,
+};
+
+/* VF information structure */
+struct ice_vf {
+ struct ice_pf *pf;
+
+ s16 vf_id; /* VF id in the PF space */
+ u32 driver_caps; /* reported by VF driver */
+ int first_vector_idx; /* first vector index of this VF */
+ struct ice_sw *vf_sw_id; /* switch id the VF VSIs connect to */
+ struct virtchnl_version_info vf_ver;
+ struct virtchnl_ether_addr dflt_lan_addr;
+ u16 port_vlan_id;
+ u8 pf_set_mac; /* VF MAC address set by VMM admin */
+ u8 trusted;
+ u16 lan_vsi_idx; /* index into PF struct */
+ u16 lan_vsi_num; /* ID as used by firmware */
+ u64 num_mdd_events; /* number of mdd events detected */
+ u64 num_inval_msgs; /* number of continuous invalid msgs */
+ u64 num_valid_msgs; /* number of valid msgs detected */
+ unsigned long vf_caps; /* vf's adv. capabilities */
+ DECLARE_BITMAP(vf_states, ICE_VF_STATES_NBITS); /* VF runtime states */
+ unsigned int tx_rate; /* Tx bandwidth limit in Mbps */
+ u8 link_forced;
+ u8 link_up; /* only valid if VF link is forced */
+ u8 spoofchk;
+ u16 num_mac;
+ u16 num_vlan;
+ u8 num_req_qs; /* num of queue pairs requested by VF */
+};
+
+#ifdef CONFIG_PCI_IOV
+void ice_process_vflr_event(struct ice_pf *pf);
+int ice_sriov_configure(struct pci_dev *pdev, int num_vfs);
+int ice_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac);
+int ice_get_vf_cfg(struct net_device *netdev, int vf_id,
+ struct ifla_vf_info *ivi);
+
+void ice_free_vfs(struct ice_pf *pf);
+void ice_vc_process_vf_msg(struct ice_pf *pf, struct ice_rq_event_info *event);
+void ice_vc_notify_link_state(struct ice_pf *pf);
+void ice_vc_notify_reset(struct ice_pf *pf);
+bool ice_reset_all_vfs(struct ice_pf *pf, bool is_vflr);
+
+int ice_set_vf_port_vlan(struct net_device *netdev, int vf_id,
+ u16 vlan_id, u8 qos, __be16 vlan_proto);
+
+int ice_set_vf_bw(struct net_device *netdev, int vf_id, int min_tx_rate,
+ int max_tx_rate);
+
+int ice_set_vf_trust(struct net_device *netdev, int vf_id, bool trusted);
+
+int ice_set_vf_link_state(struct net_device *netdev, int vf_id, int link_state);
+
+int ice_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool ena);
+#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)
+
+static inline bool
+ice_reset_all_vfs(struct ice_pf __always_unused *pf,
+ bool __always_unused is_vflr)
+{
+ return true;
+}
+
+static inline int
+ice_sriov_configure(struct pci_dev __always_unused *pdev,
+ int __always_unused num_vfs)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int
+ice_set_vf_mac(struct net_device __always_unused *netdev,
+ int __always_unused vf_id, u8 __always_unused *mac)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int
+ice_get_vf_cfg(struct net_device __always_unused *netdev,
+ int __always_unused vf_id,
+ struct ifla_vf_info __always_unused *ivi)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int
+ice_set_vf_trust(struct net_device __always_unused *netdev,
+ int __always_unused vf_id, bool __always_unused trusted)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int
+ice_set_vf_port_vlan(struct net_device __always_unused *netdev,
+ int __always_unused vf_id, u16 __always_unused vid,
+ u8 __always_unused qos, __be16 __always_unused v_proto)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int
+ice_set_vf_spoofchk(struct net_device __always_unused *netdev,
+ int __always_unused vf_id, bool __always_unused ena)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int
+ice_set_vf_link_state(struct net_device __always_unused *netdev,
+ int __always_unused vf_id, int __always_unused link_state)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int
+ice_set_vf_bw(struct net_device __always_unused *netdev,
+ int __always_unused vf_id, int __always_unused min_tx_rate,
+ int __always_unused max_tx_rate)
+{
+ return -EOPNOTSUPP;
+}
+#endif /* CONFIG_PCI_IOV */
+#endif /* _ICE_VIRTCHNL_PF_H_ */
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 0796cef96fa3..5df88ad8ac81 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -239,7 +239,7 @@ static struct pci_driver igb_driver = {
MODULE_AUTHOR("Intel Corporation, <e1000-devel@lists.sourceforge.net>");
MODULE_DESCRIPTION("Intel(R) Gigabit Ethernet Network Driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_VERSION(DRV_VERSION);
#define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV|NETIF_MSG_PROBE|NETIF_MSG_LINK)
@@ -9086,7 +9086,6 @@ static pci_ers_result_t igb_io_slot_reset(struct pci_dev *pdev)
struct igb_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
pci_ers_result_t result;
- int err;
if (pci_enable_device_mem(pdev)) {
dev_err(&pdev->dev,
@@ -9110,14 +9109,6 @@ static pci_ers_result_t igb_io_slot_reset(struct pci_dev *pdev)
result = PCI_ERS_RESULT_RECOVERED;
}
- err = pci_cleanup_aer_uncorrect_error_status(pdev);
- if (err) {
- dev_err(&pdev->dev,
- "pci_cleanup_aer_uncorrect_error_status failed 0x%0x\n",
- err);
- /* non-fatal, continue */
- }
-
return result;
}
diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c
index 9f4d700e09df..2b95dc9c7a6a 100644
--- a/drivers/net/ethernet/intel/igb/igb_ptp.c
+++ b/drivers/net/ethernet/intel/igb/igb_ptp.c
@@ -51,9 +51,17 @@
*
* The 40 bit 82580 SYSTIM overflows every
* 2^40 * 10^-9 / 60 = 18.3 minutes.
+ *
+ * SYSTIM is converted to real time using a timecounter. As
+ * timecounter_cyc2time() allows old timestamps, the timecounter needs
+ * to be updated at least once per half of the SYSTIM interval.
+ * Scheduling of delayed work is not very accurate, and also the NIC
+ * clock can be adjusted to run up to 6% faster and the system clock
+ * up to 10% slower, so we aim for 6 minutes to be sure the actual
+ * interval in the NIC time is shorter than 9.16 minutes.
*/
-#define IGB_SYSTIM_OVERFLOW_PERIOD (HZ * 60 * 9)
+#define IGB_SYSTIM_OVERFLOW_PERIOD (HZ * 60 * 6)
#define IGB_PTP_TX_TIMEOUT (HZ * 15)
#define INCPERIOD_82576 BIT(E1000_TIMINCA_16NS_SHIFT)
#define INCVALUE_82576_MASK GENMASK(E1000_TIMINCA_16NS_SHIFT - 1, 0)
diff --git a/drivers/net/ethernet/intel/igbvf/netdev.c b/drivers/net/ethernet/intel/igbvf/netdev.c
index e0c989ffb2b3..820d49eb41ab 100644
--- a/drivers/net/ethernet/intel/igbvf/netdev.c
+++ b/drivers/net/ethernet/intel/igbvf/netdev.c
@@ -3011,7 +3011,7 @@ module_exit(igbvf_exit_module);
MODULE_AUTHOR("Intel Corporation, <e1000-devel@lists.sourceforge.net>");
MODULE_DESCRIPTION("Intel(R) Gigabit Virtual Function Network Driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_VERSION(DRV_VERSION);
/* netdev.c */
diff --git a/drivers/net/ethernet/intel/igc/Makefile b/drivers/net/ethernet/intel/igc/Makefile
new file mode 100644
index 000000000000..4387f6ba8e67
--- /dev/null
+++ b/drivers/net/ethernet/intel/igc/Makefile
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2018 Intel Corporation
+
+#
+# Intel(R) I225-LM/I225-V 2.5G Ethernet Controller
+#
+
+obj-$(CONFIG_IGC) += igc.o
+
+igc-objs := igc_main.o igc_mac.o igc_i225.o igc_base.o igc_nvm.o igc_phy.o
diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h
new file mode 100644
index 000000000000..cdf18a5d9e08
--- /dev/null
+++ b/drivers/net/ethernet/intel/igc/igc.h
@@ -0,0 +1,443 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2018 Intel Corporation */
+
+#ifndef _IGC_H_
+#define _IGC_H_
+
+#include <linux/kobject.h>
+
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/vmalloc.h>
+
+#include <linux/ethtool.h>
+
+#include <linux/sctp.h>
+
+#define IGC_ERR(args...) pr_err("igc: " args)
+
+#define PFX "igc: "
+
+#include <linux/timecounter.h>
+#include <linux/net_tstamp.h>
+#include <linux/ptp_clock_kernel.h>
+
+#include "igc_hw.h"
+
+/* main */
+extern char igc_driver_name[];
+extern char igc_driver_version[];
+
+/* Interrupt defines */
+#define IGC_START_ITR 648 /* ~6000 ints/sec */
+#define IGC_FLAG_HAS_MSI BIT(0)
+#define IGC_FLAG_QUEUE_PAIRS BIT(4)
+#define IGC_FLAG_NEED_LINK_UPDATE BIT(9)
+#define IGC_FLAG_MEDIA_RESET BIT(10)
+#define IGC_FLAG_MAS_ENABLE BIT(12)
+#define IGC_FLAG_HAS_MSIX BIT(13)
+#define IGC_FLAG_VLAN_PROMISC BIT(15)
+
+#define IGC_START_ITR 648 /* ~6000 ints/sec */
+#define IGC_4K_ITR 980
+#define IGC_20K_ITR 196
+#define IGC_70K_ITR 56
+
+#define IGC_DEFAULT_ITR 3 /* dynamic */
+#define IGC_MAX_ITR_USECS 10000
+#define IGC_MIN_ITR_USECS 10
+#define NON_Q_VECTORS 1
+#define MAX_MSIX_ENTRIES 10
+
+/* TX/RX descriptor defines */
+#define IGC_DEFAULT_TXD 256
+#define IGC_DEFAULT_TX_WORK 128
+#define IGC_MIN_TXD 80
+#define IGC_MAX_TXD 4096
+
+#define IGC_DEFAULT_RXD 256
+#define IGC_MIN_RXD 80
+#define IGC_MAX_RXD 4096
+
+/* Transmit and receive queues */
+#define IGC_MAX_RX_QUEUES 4
+#define IGC_MAX_TX_QUEUES 4
+
+#define MAX_Q_VECTORS 8
+#define MAX_STD_JUMBO_FRAME_SIZE 9216
+
+/* Supported Rx Buffer Sizes */
+#define IGC_RXBUFFER_256 256
+#define IGC_RXBUFFER_2048 2048
+#define IGC_RXBUFFER_3072 3072
+
+#define IGC_RX_HDR_LEN IGC_RXBUFFER_256
+
+/* RX and TX descriptor control thresholds.
+ * PTHRESH - MAC will consider prefetch if it has fewer than this number of
+ * descriptors available in its onboard memory.
+ * Setting this to 0 disables RX descriptor prefetch.
+ * HTHRESH - MAC will only prefetch if there are at least this many descriptors
+ * available in host memory.
+ * If PTHRESH is 0, this should also be 0.
+ * WTHRESH - RX descriptor writeback threshold - MAC will delay writing back
+ * descriptors until either it has this many to write back, or the
+ * ITR timer expires.
+ */
+#define IGC_RX_PTHRESH 8
+#define IGC_RX_HTHRESH 8
+#define IGC_TX_PTHRESH 8
+#define IGC_TX_HTHRESH 1
+#define IGC_RX_WTHRESH 4
+#define IGC_TX_WTHRESH 16
+
+#define IGC_RX_DMA_ATTR \
+ (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_WEAK_ORDERING)
+
+#define IGC_TS_HDR_LEN 16
+
+#define IGC_SKB_PAD (NET_SKB_PAD + NET_IP_ALIGN)
+
+#if (PAGE_SIZE < 8192)
+#define IGC_MAX_FRAME_BUILD_SKB \
+ (SKB_WITH_OVERHEAD(IGC_RXBUFFER_2048) - IGC_SKB_PAD - IGC_TS_HDR_LEN)
+#else
+#define IGC_MAX_FRAME_BUILD_SKB (IGC_RXBUFFER_2048 - IGC_TS_HDR_LEN)
+#endif
+
+/* How many Rx Buffers do we bundle into one write to the hardware ? */
+#define IGC_RX_BUFFER_WRITE 16 /* Must be power of 2 */
+
+/* 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,
+ const u32 stat_err_bits)
+{
+ return rx_desc->wb.upper.status_error & cpu_to_le32(stat_err_bits);
+}
+
+enum igc_state_t {
+ __IGC_TESTING,
+ __IGC_RESETTING,
+ __IGC_DOWN,
+ __IGC_PTP_TX_IN_PROGRESS,
+};
+
+enum igc_tx_flags {
+ /* cmd_type flags */
+ IGC_TX_FLAGS_VLAN = 0x01,
+ IGC_TX_FLAGS_TSO = 0x02,
+ IGC_TX_FLAGS_TSTAMP = 0x04,
+
+ /* olinfo flags */
+ IGC_TX_FLAGS_IPV4 = 0x10,
+ IGC_TX_FLAGS_CSUM = 0x20,
+};
+
+enum igc_boards {
+ board_base,
+};
+
+/* The largest size we can write to the descriptor is 65535. In order to
+ * maintain a power of two alignment we have to limit ourselves to 32K.
+ */
+#define IGC_MAX_TXD_PWR 15
+#define IGC_MAX_DATA_PER_TXD BIT(IGC_MAX_TXD_PWR)
+
+/* Tx Descriptors needed, worst case */
+#define TXD_USE_COUNT(S) DIV_ROUND_UP((S), IGC_MAX_DATA_PER_TXD)
+#define DESC_NEEDED (MAX_SKB_FRAGS + 4)
+
+/* 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;
+ struct sk_buff *skb;
+ unsigned int bytecount;
+ u16 gso_segs;
+ __be16 protocol;
+
+ DEFINE_DMA_UNMAP_ADDR(dma);
+ DEFINE_DMA_UNMAP_LEN(len);
+ u32 tx_flags;
+};
+
+struct igc_rx_buffer {
+ dma_addr_t dma;
+ struct page *page;
+#if (BITS_PER_LONG > 32) || (PAGE_SIZE >= 65536)
+ __u32 page_offset;
+#else
+ __u16 page_offset;
+#endif
+ __u16 pagecnt_bias;
+};
+
+struct igc_tx_queue_stats {
+ u64 packets;
+ u64 bytes;
+ u64 restart_queue;
+ u64 restart_queue2;
+};
+
+struct igc_rx_queue_stats {
+ u64 packets;
+ u64 bytes;
+ u64 drops;
+ u64 csum_err;
+ u64 alloc_failed;
+};
+
+struct igc_rx_packet_stats {
+ u64 ipv4_packets; /* IPv4 headers processed */
+ u64 ipv4e_packets; /* IPv4E headers with extensions processed */
+ u64 ipv6_packets; /* IPv6 headers processed */
+ u64 ipv6e_packets; /* IPv6E headers with extensions processed */
+ u64 tcp_packets; /* TCP headers processed */
+ u64 udp_packets; /* UDP headers processed */
+ u64 sctp_packets; /* SCTP headers processed */
+ u64 nfs_packets; /* NFS headers processe */
+ u64 other_packets;
+};
+
+struct igc_ring_container {
+ struct igc_ring *ring; /* pointer to linked list of rings */
+ unsigned int total_bytes; /* total bytes processed this int */
+ unsigned int total_packets; /* total packets processed this int */
+ u16 work_limit; /* total work allowed per interrupt */
+ u8 count; /* total number of rings in vector */
+ u8 itr; /* current ITR setting for ring */
+};
+
+struct igc_ring {
+ struct igc_q_vector *q_vector; /* backlink to q_vector */
+ struct net_device *netdev; /* back pointer to net_device */
+ struct device *dev; /* device for dma mapping */
+ union { /* array of buffer info structs */
+ struct igc_tx_buffer *tx_buffer_info;
+ struct igc_rx_buffer *rx_buffer_info;
+ };
+ void *desc; /* descriptor ring memory */
+ unsigned long flags; /* ring specific flags */
+ void __iomem *tail; /* pointer to ring tail register */
+ dma_addr_t dma; /* phys address of the ring */
+ unsigned int size; /* length of desc. ring in bytes */
+
+ u16 count; /* number of desc. in the ring */
+ u8 queue_index; /* logical index of the ring*/
+ u8 reg_idx; /* physical index of the ring */
+
+ /* everything past this point are written often */
+ u16 next_to_clean;
+ u16 next_to_use;
+ u16 next_to_alloc;
+
+ union {
+ /* TX */
+ struct {
+ struct igc_tx_queue_stats tx_stats;
+ struct u64_stats_sync tx_syncp;
+ struct u64_stats_sync tx_syncp2;
+ };
+ /* RX */
+ struct {
+ struct igc_rx_queue_stats rx_stats;
+ struct igc_rx_packet_stats pkt_stats;
+ struct u64_stats_sync rx_syncp;
+ struct sk_buff *skb;
+ };
+ };
+} ____cacheline_internodealigned_in_smp;
+
+struct igc_q_vector {
+ struct igc_adapter *adapter; /* backlink */
+ void __iomem *itr_register;
+ u32 eims_value; /* EIMS mask value */
+
+ u16 itr_val;
+ u8 set_itr;
+
+ struct igc_ring_container rx, tx;
+
+ struct napi_struct napi;
+
+ struct rcu_head rcu; /* to avoid race with update stats on free */
+ char name[IFNAMSIZ + 9];
+ struct net_device poll_dev;
+
+ /* for dynamic allocation of rings associated with this q_vector */
+ struct igc_ring ring[0] ____cacheline_internodealigned_in_smp;
+};
+
+struct igc_mac_addr {
+ u8 addr[ETH_ALEN];
+ u8 queue;
+ u8 state; /* bitmask */
+};
+
+#define IGC_MAC_STATE_DEFAULT 0x1
+#define IGC_MAC_STATE_MODIFIED 0x2
+#define IGC_MAC_STATE_IN_USE 0x4
+
+/* Board specific private data structure */
+struct igc_adapter {
+ struct net_device *netdev;
+
+ unsigned long state;
+ unsigned int flags;
+ unsigned int num_q_vectors;
+
+ struct msix_entry *msix_entries;
+
+ /* TX */
+ u16 tx_work_limit;
+ u32 tx_timeout_count;
+ int num_tx_queues;
+ struct igc_ring *tx_ring[IGC_MAX_TX_QUEUES];
+
+ /* RX */
+ int num_rx_queues;
+ struct igc_ring *rx_ring[IGC_MAX_RX_QUEUES];
+
+ struct timer_list watchdog_timer;
+ struct timer_list dma_err_timer;
+ struct timer_list phy_info_timer;
+
+ u16 link_speed;
+ u16 link_duplex;
+
+ u8 port_num;
+
+ u8 __iomem *io_addr;
+ /* Interrupt Throttle Rate */
+ u32 rx_itr_setting;
+ u32 tx_itr_setting;
+
+ struct work_struct reset_task;
+ struct work_struct watchdog_task;
+ struct work_struct dma_err_task;
+ bool fc_autoneg;
+
+ u8 tx_timeout_factor;
+
+ int msg_enable;
+ u32 max_frame_size;
+ u32 min_frame_size;
+
+ /* OS defined structs */
+ struct pci_dev *pdev;
+ /* lock for statistics */
+ spinlock_t stats64_lock;
+ struct rtnl_link_stats64 stats64;
+
+ /* structs defined in igc_hw.h */
+ struct igc_hw hw;
+ struct igc_hw_stats stats;
+
+ struct igc_q_vector *q_vector[MAX_Q_VECTORS];
+ u32 eims_enable_mask;
+ u32 eims_other;
+
+ u16 tx_ring_count;
+ u16 rx_ring_count;
+
+ u32 *shadow_vfta;
+
+ u32 rss_queues;
+
+ /* lock for RX network flow classification filter */
+ spinlock_t nfc_lock;
+
+ struct igc_mac_addr *mac_table;
+
+ unsigned long link_check_timeout;
+ struct igc_info ei;
+};
+
+/* igc_desc_unused - calculate if we have unused descriptors */
+static inline u16 igc_desc_unused(const struct igc_ring *ring)
+{
+ u16 ntc = ring->next_to_clean;
+ u16 ntu = ring->next_to_use;
+
+ return ((ntc > ntu) ? 0 : ring->count) + ntc - ntu - 1;
+}
+
+static inline s32 igc_get_phy_info(struct igc_hw *hw)
+{
+ if (hw->phy.ops.get_phy_info)
+ return hw->phy.ops.get_phy_info(hw);
+
+ return 0;
+}
+
+static inline s32 igc_reset_phy(struct igc_hw *hw)
+{
+ if (hw->phy.ops.reset)
+ return hw->phy.ops.reset(hw);
+
+ return 0;
+}
+
+static inline struct netdev_queue *txring_txq(const struct igc_ring *tx_ring)
+{
+ return netdev_get_tx_queue(tx_ring->netdev, tx_ring->queue_index);
+}
+
+enum igc_ring_flags_t {
+ IGC_RING_FLAG_RX_3K_BUFFER,
+ IGC_RING_FLAG_RX_BUILD_SKB_ENABLED,
+ 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
+};
+
+#define ring_uses_large_buffer(ring) \
+ test_bit(IGC_RING_FLAG_RX_3K_BUFFER, &(ring)->flags)
+
+#define ring_uses_build_skb(ring) \
+ test_bit(IGC_RING_FLAG_RX_BUILD_SKB_ENABLED, &(ring)->flags)
+
+static inline unsigned int igc_rx_bufsz(struct igc_ring *ring)
+{
+#if (PAGE_SIZE < 8192)
+ if (ring_uses_large_buffer(ring))
+ return IGC_RXBUFFER_3072;
+
+ if (ring_uses_build_skb(ring))
+ return IGC_MAX_FRAME_BUILD_SKB + IGC_TS_HDR_LEN;
+#endif
+ return IGC_RXBUFFER_2048;
+}
+
+static inline unsigned int igc_rx_pg_order(struct igc_ring *ring)
+{
+#if (PAGE_SIZE < 8192)
+ if (ring_uses_large_buffer(ring))
+ return 1;
+#endif
+ return 0;
+}
+
+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;
+}
+
+#define igc_rx_pg_size(_ring) (PAGE_SIZE << igc_rx_pg_order(_ring))
+
+#define IGC_TXD_DCMD (IGC_ADVTXD_DCMD_EOP | IGC_ADVTXD_DCMD_RS)
+
+#define IGC_RX_DESC(R, i) \
+ (&(((union igc_adv_rx_desc *)((R)->desc))[i]))
+#define IGC_TX_DESC(R, i) \
+ (&(((union igc_adv_tx_desc *)((R)->desc))[i]))
+#define IGC_TX_CTXTDESC(R, i) \
+ (&(((struct igc_adv_tx_context_desc *)((R)->desc))[i]))
+
+#endif /* _IGC_H_ */
diff --git a/drivers/net/ethernet/intel/igc/igc_base.c b/drivers/net/ethernet/intel/igc/igc_base.c
new file mode 100644
index 000000000000..832da609d9a7
--- /dev/null
+++ b/drivers/net/ethernet/intel/igc/igc_base.c
@@ -0,0 +1,541 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2018 Intel Corporation */
+
+#include <linux/delay.h>
+
+#include "igc_hw.h"
+#include "igc_i225.h"
+#include "igc_mac.h"
+#include "igc_base.h"
+#include "igc.h"
+
+/**
+ * igc_set_pcie_completion_timeout - set pci-e completion timeout
+ * @hw: pointer to the HW structure
+ */
+static s32 igc_set_pcie_completion_timeout(struct igc_hw *hw)
+{
+ u32 gcr = rd32(IGC_GCR);
+ u16 pcie_devctl2;
+ s32 ret_val = 0;
+
+ /* only take action if timeout value is defaulted to 0 */
+ if (gcr & IGC_GCR_CMPL_TMOUT_MASK)
+ goto out;
+
+ /* if capabilities version is type 1 we can write the
+ * timeout of 10ms to 200ms through the GCR register
+ */
+ if (!(gcr & IGC_GCR_CAP_VER2)) {
+ gcr |= IGC_GCR_CMPL_TMOUT_10ms;
+ goto out;
+ }
+
+ /* for version 2 capabilities we need to write the config space
+ * directly in order to set the completion timeout value for
+ * 16ms to 55ms
+ */
+ ret_val = igc_read_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2,
+ &pcie_devctl2);
+ if (ret_val)
+ goto out;
+
+ pcie_devctl2 |= PCIE_DEVICE_CONTROL2_16ms;
+
+ ret_val = igc_write_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2,
+ &pcie_devctl2);
+out:
+ /* disable completion timeout resend */
+ gcr &= ~IGC_GCR_CMPL_TMOUT_RESEND;
+
+ wr32(IGC_GCR, gcr);
+
+ return ret_val;
+}
+
+/**
+ * igc_check_for_link_base - Check for link
+ * @hw: pointer to the HW structure
+ *
+ * If sgmii is enabled, then use the pcs register to determine link, otherwise
+ * use the generic interface for determining link.
+ */
+static s32 igc_check_for_link_base(struct igc_hw *hw)
+{
+ s32 ret_val = 0;
+
+ ret_val = igc_check_for_copper_link(hw);
+
+ return ret_val;
+}
+
+/**
+ * igc_reset_hw_base - Reset hardware
+ * @hw: pointer to the HW structure
+ *
+ * This resets the hardware into a known state. This is a
+ * function pointer entry point called by the api module.
+ */
+static s32 igc_reset_hw_base(struct igc_hw *hw)
+{
+ s32 ret_val;
+ u32 ctrl;
+
+ /* Prevent the PCI-E bus from sticking if there is no TLP connection
+ * on the last TLP read/write transaction when MAC is reset.
+ */
+ ret_val = igc_disable_pcie_master(hw);
+ if (ret_val)
+ hw_dbg("PCI-E Master disable polling has failed.\n");
+
+ /* set the completion timeout for interface */
+ ret_val = igc_set_pcie_completion_timeout(hw);
+ if (ret_val)
+ hw_dbg("PCI-E Set completion timeout has failed.\n");
+
+ hw_dbg("Masking off all interrupts\n");
+ wr32(IGC_IMC, 0xffffffff);
+
+ wr32(IGC_RCTL, 0);
+ wr32(IGC_TCTL, IGC_TCTL_PSP);
+ wrfl();
+
+ usleep_range(10000, 20000);
+
+ ctrl = rd32(IGC_CTRL);
+
+ hw_dbg("Issuing a global reset to MAC\n");
+ wr32(IGC_CTRL, ctrl | IGC_CTRL_RST);
+
+ ret_val = igc_get_auto_rd_done(hw);
+ if (ret_val) {
+ /* When auto config read does not complete, do not
+ * return with an error. This can happen in situations
+ * where there is no eeprom and prevents getting link.
+ */
+ hw_dbg("Auto Read Done did not complete\n");
+ }
+
+ /* Clear any pending interrupt events. */
+ wr32(IGC_IMC, 0xffffffff);
+ rd32(IGC_ICR);
+
+ return ret_val;
+}
+
+/**
+ * igc_get_phy_id_base - Retrieve PHY addr and id
+ * @hw: pointer to the HW structure
+ *
+ * Retrieves the PHY address and ID for both PHY's which do and do not use
+ * sgmi interface.
+ */
+static s32 igc_get_phy_id_base(struct igc_hw *hw)
+{
+ s32 ret_val = 0;
+
+ ret_val = igc_get_phy_id(hw);
+
+ return ret_val;
+}
+
+/**
+ * igc_init_nvm_params_base - Init NVM func ptrs.
+ * @hw: pointer to the HW structure
+ */
+static s32 igc_init_nvm_params_base(struct igc_hw *hw)
+{
+ struct igc_nvm_info *nvm = &hw->nvm;
+ u32 eecd = rd32(IGC_EECD);
+ u16 size;
+
+ size = (u16)((eecd & IGC_EECD_SIZE_EX_MASK) >>
+ IGC_EECD_SIZE_EX_SHIFT);
+
+ /* Added to a constant, "size" becomes the left-shift value
+ * for setting word_size.
+ */
+ size += NVM_WORD_SIZE_BASE_SHIFT;
+
+ /* Just in case size is out of range, cap it to the largest
+ * EEPROM size supported
+ */
+ if (size > 15)
+ size = 15;
+
+ nvm->word_size = BIT(size);
+ nvm->opcode_bits = 8;
+ nvm->delay_usec = 1;
+
+ nvm->page_size = eecd & IGC_EECD_ADDR_BITS ? 32 : 8;
+ nvm->address_bits = eecd & IGC_EECD_ADDR_BITS ?
+ 16 : 8;
+
+ if (nvm->word_size == BIT(15))
+ nvm->page_size = 128;
+
+ return 0;
+}
+
+/**
+ * igc_setup_copper_link_base - Configure copper link settings
+ * @hw: pointer to the HW structure
+ *
+ * Configures the link for auto-neg or forced speed and duplex. Then we check
+ * for link, once link is established calls to configure collision distance
+ * and flow control are called.
+ */
+static s32 igc_setup_copper_link_base(struct igc_hw *hw)
+{
+ s32 ret_val = 0;
+ u32 ctrl;
+
+ ctrl = rd32(IGC_CTRL);
+ ctrl |= IGC_CTRL_SLU;
+ ctrl &= ~(IGC_CTRL_FRCSPD | IGC_CTRL_FRCDPX);
+ wr32(IGC_CTRL, ctrl);
+
+ ret_val = igc_setup_copper_link(hw);
+
+ return ret_val;
+}
+
+/**
+ * igc_init_mac_params_base - Init MAC func ptrs.
+ * @hw: pointer to the HW structure
+ */
+static s32 igc_init_mac_params_base(struct igc_hw *hw)
+{
+ struct igc_dev_spec_base *dev_spec = &hw->dev_spec._base;
+ struct igc_mac_info *mac = &hw->mac;
+
+ /* Set mta register count */
+ mac->mta_reg_count = 128;
+ mac->rar_entry_count = IGC_RAR_ENTRIES;
+
+ /* reset */
+ mac->ops.reset_hw = igc_reset_hw_base;
+
+ mac->ops.acquire_swfw_sync = igc_acquire_swfw_sync_i225;
+ mac->ops.release_swfw_sync = igc_release_swfw_sync_i225;
+
+ /* Allow a single clear of the SW semaphore on I225 */
+ if (mac->type == igc_i225)
+ dev_spec->clear_semaphore_once = true;
+
+ /* physical interface link setup */
+ mac->ops.setup_physical_interface = igc_setup_copper_link_base;
+
+ return 0;
+}
+
+/**
+ * igc_init_phy_params_base - Init PHY func ptrs.
+ * @hw: pointer to the HW structure
+ */
+static s32 igc_init_phy_params_base(struct igc_hw *hw)
+{
+ struct igc_phy_info *phy = &hw->phy;
+ s32 ret_val = 0;
+ u32 ctrl_ext;
+
+ if (hw->phy.media_type != igc_media_type_copper) {
+ phy->type = igc_phy_none;
+ goto out;
+ }
+
+ phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT_2500;
+ phy->reset_delay_us = 100;
+
+ ctrl_ext = rd32(IGC_CTRL_EXT);
+
+ /* set lan id */
+ hw->bus.func = (rd32(IGC_STATUS) & IGC_STATUS_FUNC_MASK) >>
+ IGC_STATUS_FUNC_SHIFT;
+
+ /* Make sure the PHY is in a good state. Several people have reported
+ * firmware leaving the PHY's page select register set to something
+ * other than the default of zero, which causes the PHY ID read to
+ * access something other than the intended register.
+ */
+ ret_val = hw->phy.ops.reset(hw);
+ if (ret_val) {
+ hw_dbg("Error resetting the PHY.\n");
+ goto out;
+ }
+
+ ret_val = igc_get_phy_id_base(hw);
+ if (ret_val)
+ return ret_val;
+
+ igc_check_for_link_base(hw);
+
+ /* Verify phy id and set remaining function pointers */
+ switch (phy->id) {
+ case I225_I_PHY_ID:
+ phy->type = igc_phy_i225;
+ break;
+ default:
+ ret_val = -IGC_ERR_PHY;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+static s32 igc_get_invariants_base(struct igc_hw *hw)
+{
+ struct igc_mac_info *mac = &hw->mac;
+ u32 link_mode = 0;
+ u32 ctrl_ext = 0;
+ s32 ret_val = 0;
+
+ switch (hw->device_id) {
+ case IGC_DEV_ID_I225_LM:
+ case IGC_DEV_ID_I225_V:
+ mac->type = igc_i225;
+ break;
+ default:
+ return -IGC_ERR_MAC_INIT;
+ }
+
+ hw->phy.media_type = igc_media_type_copper;
+
+ ctrl_ext = rd32(IGC_CTRL_EXT);
+ link_mode = ctrl_ext & IGC_CTRL_EXT_LINK_MODE_MASK;
+
+ /* mac initialization and operations */
+ ret_val = igc_init_mac_params_base(hw);
+ if (ret_val)
+ goto out;
+
+ /* NVM initialization */
+ ret_val = igc_init_nvm_params_base(hw);
+ switch (hw->mac.type) {
+ case igc_i225:
+ ret_val = igc_init_nvm_params_i225(hw);
+ break;
+ default:
+ break;
+ }
+
+ /* setup PHY parameters */
+ ret_val = igc_init_phy_params_base(hw);
+ if (ret_val)
+ goto out;
+
+out:
+ return ret_val;
+}
+
+/**
+ * igc_acquire_phy_base - Acquire rights to access PHY
+ * @hw: pointer to the HW structure
+ *
+ * Acquire access rights to the correct PHY. This is a
+ * function pointer entry point called by the api module.
+ */
+static s32 igc_acquire_phy_base(struct igc_hw *hw)
+{
+ u16 mask = IGC_SWFW_PHY0_SM;
+
+ return hw->mac.ops.acquire_swfw_sync(hw, mask);
+}
+
+/**
+ * igc_release_phy_base - Release rights to access PHY
+ * @hw: pointer to the HW structure
+ *
+ * A wrapper to release access rights to the correct PHY. This is a
+ * function pointer entry point called by the api module.
+ */
+static void igc_release_phy_base(struct igc_hw *hw)
+{
+ u16 mask = IGC_SWFW_PHY0_SM;
+
+ hw->mac.ops.release_swfw_sync(hw, mask);
+}
+
+/**
+ * igc_get_link_up_info_base - Get link speed/duplex info
+ * @hw: pointer to the HW structure
+ * @speed: stores the current speed
+ * @duplex: stores the current duplex
+ *
+ * This is a wrapper function, if using the serial gigabit media independent
+ * interface, use PCS to retrieve the link speed and duplex information.
+ * Otherwise, use the generic function to get the link speed and duplex info.
+ */
+static s32 igc_get_link_up_info_base(struct igc_hw *hw, u16 *speed,
+ u16 *duplex)
+{
+ s32 ret_val;
+
+ ret_val = igc_get_speed_and_duplex_copper(hw, speed, duplex);
+
+ return ret_val;
+}
+
+/**
+ * igc_init_hw_base - Initialize hardware
+ * @hw: pointer to the HW structure
+ *
+ * This inits the hardware readying it for operation.
+ */
+static s32 igc_init_hw_base(struct igc_hw *hw)
+{
+ struct igc_mac_info *mac = &hw->mac;
+ u16 i, rar_count = mac->rar_entry_count;
+ s32 ret_val = 0;
+
+ /* Setup the receive address */
+ igc_init_rx_addrs(hw, rar_count);
+
+ /* Zero out the Multicast HASH table */
+ hw_dbg("Zeroing the MTA\n");
+ for (i = 0; i < mac->mta_reg_count; i++)
+ array_wr32(IGC_MTA, i, 0);
+
+ /* Zero out the Unicast HASH table */
+ hw_dbg("Zeroing the UTA\n");
+ for (i = 0; i < mac->uta_reg_count; i++)
+ array_wr32(IGC_UTA, i, 0);
+
+ /* Setup link and flow control */
+ ret_val = igc_setup_link(hw);
+
+ /* Clear all of the statistics registers (clear on read). It is
+ * important that we do this after we have tried to establish link
+ * because the symbol error count will increment wildly if there
+ * is no link.
+ */
+ igc_clear_hw_cntrs_base(hw);
+
+ return ret_val;
+}
+
+/**
+ * igc_read_mac_addr_base - Read device MAC address
+ * @hw: pointer to the HW structure
+ */
+static s32 igc_read_mac_addr_base(struct igc_hw *hw)
+{
+ s32 ret_val = 0;
+
+ ret_val = igc_read_mac_addr(hw);
+
+ return ret_val;
+}
+
+/**
+ * igc_power_down_phy_copper_base - Remove link during PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of a PHY power down to save power, or to turn off link during a
+ * driver unload, or wake on lan is not enabled, remove the link.
+ */
+void igc_power_down_phy_copper_base(struct igc_hw *hw)
+{
+ /* If the management interface is not enabled, then power down */
+ if (!(igc_enable_mng_pass_thru(hw) || igc_check_reset_block(hw)))
+ igc_power_down_phy_copper(hw);
+}
+
+/**
+ * igc_rx_fifo_flush_base - Clean rx fifo after Rx enable
+ * @hw: pointer to the HW structure
+ *
+ * After Rx enable, if manageability is enabled then there is likely some
+ * bad data at the start of the fifo and possibly in the DMA fifo. This
+ * function clears the fifos and flushes any packets that came in as rx was
+ * being enabled.
+ */
+void igc_rx_fifo_flush_base(struct igc_hw *hw)
+{
+ u32 rctl, rlpml, rxdctl[4], rfctl, temp_rctl, rx_enabled;
+ int i, ms_wait;
+
+ /* disable IPv6 options as per hardware errata */
+ rfctl = rd32(IGC_RFCTL);
+ rfctl |= IGC_RFCTL_IPV6_EX_DIS;
+ wr32(IGC_RFCTL, rfctl);
+
+ if (!(rd32(IGC_MANC) & IGC_MANC_RCV_TCO_EN))
+ return;
+
+ /* Disable all Rx queues */
+ for (i = 0; i < 4; i++) {
+ rxdctl[i] = rd32(IGC_RXDCTL(i));
+ wr32(IGC_RXDCTL(i),
+ rxdctl[i] & ~IGC_RXDCTL_QUEUE_ENABLE);
+ }
+ /* Poll all queues to verify they have shut down */
+ for (ms_wait = 0; ms_wait < 10; ms_wait++) {
+ usleep_range(1000, 2000);
+ rx_enabled = 0;
+ for (i = 0; i < 4; i++)
+ rx_enabled |= rd32(IGC_RXDCTL(i));
+ if (!(rx_enabled & IGC_RXDCTL_QUEUE_ENABLE))
+ break;
+ }
+
+ if (ms_wait == 10)
+ pr_debug("Queue disable timed out after 10ms\n");
+
+ /* Clear RLPML, RCTL.SBP, RFCTL.LEF, and set RCTL.LPE so that all
+ * incoming packets are rejected. Set enable and wait 2ms so that
+ * any packet that was coming in as RCTL.EN was set is flushed
+ */
+ wr32(IGC_RFCTL, rfctl & ~IGC_RFCTL_LEF);
+
+ rlpml = rd32(IGC_RLPML);
+ wr32(IGC_RLPML, 0);
+
+ rctl = rd32(IGC_RCTL);
+ temp_rctl = rctl & ~(IGC_RCTL_EN | IGC_RCTL_SBP);
+ temp_rctl |= IGC_RCTL_LPE;
+
+ wr32(IGC_RCTL, temp_rctl);
+ wr32(IGC_RCTL, temp_rctl | IGC_RCTL_EN);
+ wrfl();
+ usleep_range(2000, 3000);
+
+ /* Enable Rx queues that were previously enabled and restore our
+ * previous state
+ */
+ for (i = 0; i < 4; i++)
+ wr32(IGC_RXDCTL(i), rxdctl[i]);
+ wr32(IGC_RCTL, rctl);
+ wrfl();
+
+ wr32(IGC_RLPML, rlpml);
+ wr32(IGC_RFCTL, rfctl);
+
+ /* Flush receive errors generated by workaround */
+ rd32(IGC_ROC);
+ rd32(IGC_RNBC);
+ rd32(IGC_MPC);
+}
+
+static struct igc_mac_operations igc_mac_ops_base = {
+ .init_hw = igc_init_hw_base,
+ .check_for_link = igc_check_for_link_base,
+ .rar_set = igc_rar_set,
+ .read_mac_addr = igc_read_mac_addr_base,
+ .get_speed_and_duplex = igc_get_link_up_info_base,
+};
+
+static const struct igc_phy_operations igc_phy_ops_base = {
+ .acquire = igc_acquire_phy_base,
+ .release = igc_release_phy_base,
+ .reset = igc_phy_hw_reset,
+ .read_reg = igc_read_phy_reg_gpy,
+ .write_reg = igc_write_phy_reg_gpy,
+};
+
+const struct igc_info igc_base_info = {
+ .get_invariants = igc_get_invariants_base,
+ .mac_ops = &igc_mac_ops_base,
+ .phy_ops = &igc_phy_ops_base,
+};
diff --git a/drivers/net/ethernet/intel/igc/igc_base.h b/drivers/net/ethernet/intel/igc/igc_base.h
new file mode 100644
index 000000000000..35588fa7b8c5
--- /dev/null
+++ b/drivers/net/ethernet/intel/igc/igc_base.h
@@ -0,0 +1,107 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2018 Intel Corporation */
+
+#ifndef _IGC_BASE_H
+#define _IGC_BASE_H
+
+/* forward declaration */
+void igc_rx_fifo_flush_base(struct igc_hw *hw);
+void igc_power_down_phy_copper_base(struct igc_hw *hw);
+
+/* Transmit Descriptor - Advanced */
+union igc_adv_tx_desc {
+ struct {
+ __le64 buffer_addr; /* Address of descriptor's data buf */
+ __le32 cmd_type_len;
+ __le32 olinfo_status;
+ } read;
+ struct {
+ __le64 rsvd; /* Reserved */
+ __le32 nxtseq_seed;
+ __le32 status;
+ } wb;
+};
+
+/* Adv Transmit Descriptor Config Masks */
+#define IGC_ADVTXD_MAC_TSTAMP 0x00080000 /* IEEE1588 Timestamp packet */
+#define IGC_ADVTXD_DTYP_CTXT 0x00200000 /* Advanced Context Descriptor */
+#define IGC_ADVTXD_DTYP_DATA 0x00300000 /* Advanced Data Descriptor */
+#define IGC_ADVTXD_DCMD_EOP 0x01000000 /* End of Packet */
+#define IGC_ADVTXD_DCMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */
+#define IGC_ADVTXD_DCMD_RS 0x08000000 /* Report Status */
+#define IGC_ADVTXD_DCMD_DEXT 0x20000000 /* Descriptor extension (1=Adv) */
+#define IGC_ADVTXD_DCMD_VLE 0x40000000 /* VLAN pkt enable */
+#define IGC_ADVTXD_DCMD_TSE 0x80000000 /* TCP Seg enable */
+#define IGC_ADVTXD_PAYLEN_SHIFT 14 /* Adv desc PAYLEN shift */
+
+#define IGC_RAR_ENTRIES 16
+
+struct igc_adv_data_desc {
+ __le64 buffer_addr; /* Address of the descriptor's data buffer */
+ union {
+ u32 data;
+ struct {
+ u32 datalen:16; /* Data buffer length */
+ u32 rsvd:4;
+ u32 dtyp:4; /* Descriptor type */
+ u32 dcmd:8; /* Descriptor command */
+ } config;
+ } lower;
+ union {
+ u32 data;
+ struct {
+ u32 status:4; /* Descriptor status */
+ u32 idx:4;
+ u32 popts:6; /* Packet Options */
+ u32 paylen:18; /* Payload length */
+ } options;
+ } upper;
+};
+
+/* Receive Descriptor - Advanced */
+union igc_adv_rx_desc {
+ struct {
+ __le64 pkt_addr; /* Packet buffer address */
+ __le64 hdr_addr; /* Header buffer address */
+ } read;
+ struct {
+ struct {
+ union {
+ __le32 data;
+ struct {
+ __le16 pkt_info; /*RSS type, Pkt type*/
+ /* Split Header, header buffer len */
+ __le16 hdr_info;
+ } hs_rss;
+ } lo_dword;
+ union {
+ __le32 rss; /* RSS Hash */
+ struct {
+ __le16 ip_id; /* IP id */
+ __le16 csum; /* Packet Checksum */
+ } csum_ip;
+ } hi_dword;
+ } lower;
+ struct {
+ __le32 status_error; /* ext status/error */
+ __le16 length; /* Packet length */
+ __le16 vlan; /* VLAN tag */
+ } upper;
+ } wb; /* writeback */
+};
+
+/* Adv Transmit Descriptor Config Masks */
+#define IGC_ADVTXD_PAYLEN_SHIFT 14 /* Adv desc PAYLEN shift */
+
+/* Additional Transmit Descriptor Control definitions */
+#define IGC_TXDCTL_QUEUE_ENABLE 0x02000000 /* Ena specific Tx Queue */
+
+/* Additional Receive Descriptor Control definitions */
+#define IGC_RXDCTL_QUEUE_ENABLE 0x02000000 /* Ena specific Rx Queue */
+
+/* SRRCTL bit definitions */
+#define IGC_SRRCTL_BSIZEPKT_SHIFT 10 /* Shift _right_ */
+#define IGC_SRRCTL_BSIZEHDRSIZE_SHIFT 2 /* Shift _left_ */
+#define IGC_SRRCTL_DESCTYPE_ADV_ONEBUF 0x02000000
+
+#endif /* _IGC_BASE_H */
diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h
new file mode 100644
index 000000000000..8740754ea1fd
--- /dev/null
+++ b/drivers/net/ethernet/intel/igc/igc_defines.h
@@ -0,0 +1,389 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2018 Intel Corporation */
+
+#ifndef _IGC_DEFINES_H_
+#define _IGC_DEFINES_H_
+
+#define IGC_CTRL_EXT_DRV_LOAD 0x10000000 /* Drv loaded bit for FW */
+
+/* PCI Bus Info */
+#define PCIE_DEVICE_CONTROL2 0x28
+#define PCIE_DEVICE_CONTROL2_16ms 0x0005
+
+/* Physical Func Reset Done Indication */
+#define IGC_CTRL_EXT_LINK_MODE_MASK 0x00C00000
+
+/* Loop limit on how long we wait for auto-negotiation to complete */
+#define COPPER_LINK_UP_LIMIT 10
+#define PHY_AUTO_NEG_LIMIT 45
+#define PHY_FORCE_LIMIT 20
+
+/* Number of 100 microseconds we wait for PCI Express master disable */
+#define MASTER_DISABLE_TIMEOUT 800
+/*Blocks new Master requests */
+#define IGC_CTRL_GIO_MASTER_DISABLE 0x00000004
+/* Status of Master requests. */
+#define IGC_STATUS_GIO_MASTER_ENABLE 0x00080000
+
+/* PCI Express Control */
+#define IGC_GCR_CMPL_TMOUT_MASK 0x0000F000
+#define IGC_GCR_CMPL_TMOUT_10ms 0x00001000
+#define IGC_GCR_CMPL_TMOUT_RESEND 0x00010000
+#define IGC_GCR_CAP_VER2 0x00040000
+
+/* Receive Address
+ * Number of high/low register pairs in the RAR. The RAR (Receive Address
+ * Registers) holds the directed and multicast addresses that we monitor.
+ * Technically, we have 16 spots. However, we reserve one of these spots
+ * (RAR[15]) for our directed address used by controllers with
+ * manageability enabled, allowing us room for 15 multicast addresses.
+ */
+#define IGC_RAH_AV 0x80000000 /* Receive descriptor valid */
+#define IGC_RAH_POOL_1 0x00040000
+#define IGC_RAL_MAC_ADDR_LEN 4
+#define IGC_RAH_MAC_ADDR_LEN 2
+
+/* Error Codes */
+#define IGC_SUCCESS 0
+#define IGC_ERR_NVM 1
+#define IGC_ERR_PHY 2
+#define IGC_ERR_CONFIG 3
+#define IGC_ERR_PARAM 4
+#define IGC_ERR_MAC_INIT 5
+#define IGC_ERR_RESET 9
+#define IGC_ERR_MASTER_REQUESTS_PENDING 10
+#define IGC_ERR_BLK_PHY_RESET 12
+#define IGC_ERR_SWFW_SYNC 13
+
+/* Device Control */
+#define IGC_CTRL_RST 0x04000000 /* Global reset */
+
+#define IGC_CTRL_PHY_RST 0x80000000 /* PHY Reset */
+#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_RFCE 0x08000000 /* Receive Flow Control enable */
+#define IGC_CTRL_TFCE 0x10000000 /* Transmit flow control enable */
+
+#define IGC_CONNSW_AUTOSENSE_EN 0x1
+
+/* PBA constants */
+#define IGC_PBA_34K 0x0022
+
+/* SW Semaphore Register */
+#define IGC_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */
+#define IGC_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */
+
+/* SWFW_SYNC Definitions */
+#define IGC_SWFW_EEP_SM 0x1
+#define IGC_SWFW_PHY0_SM 0x2
+
+/* Autoneg Advertisement Register */
+#define NWAY_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */
+#define NWAY_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */
+#define NWAY_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */
+#define NWAY_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */
+#define NWAY_AR_PAUSE 0x0400 /* Pause operation desired */
+#define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */
+
+/* Link Partner Ability Register (Base Page) */
+#define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */
+#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 */
+
+/* 1000BASE-T Status Register */
+#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
+#define SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */
+
+/* PHY GPY 211 registers */
+#define STANDARD_AN_REG_MASK 0x0007 /* MMD */
+#define ANEG_MULTIGBT_AN_CTRL 0x0020 /* MULTI GBT AN Control Register */
+#define MMD_DEVADDR_SHIFT 16 /* Shift MMD to higher bits */
+#define CR_2500T_FD_CAPS 0x0080 /* Advertise 2500T FD capability */
+
+/* NVM Control */
+/* Number of milliseconds for NVM auto read done after MAC reset. */
+#define AUTO_READ_DONE_TIMEOUT 10
+#define IGC_EECD_AUTO_RD 0x00000200 /* NVM Auto Read done */
+#define IGC_EECD_REQ 0x00000040 /* NVM Access Request */
+#define IGC_EECD_GNT 0x00000080 /* NVM Access Grant */
+/* NVM Addressing bits based on type 0=small, 1=large */
+#define IGC_EECD_ADDR_BITS 0x00000400
+#define IGC_NVM_GRANT_ATTEMPTS 1000 /* NVM # attempts to gain grant */
+#define IGC_EECD_SIZE_EX_MASK 0x00007800 /* NVM Size */
+#define IGC_EECD_SIZE_EX_SHIFT 11
+#define IGC_EECD_FLUPD_I225 0x00800000 /* Update FLASH */
+#define IGC_EECD_FLUDONE_I225 0x04000000 /* Update FLASH done*/
+#define IGC_EECD_FLASH_DETECTED_I225 0x00080000 /* FLASH detected */
+#define IGC_FLUDONE_ATTEMPTS 20000
+#define IGC_EERD_EEWR_MAX_COUNT 512 /* buffered EEPROM words rw */
+
+/* Offset to data in NVM read/write registers */
+#define IGC_NVM_RW_REG_DATA 16
+#define IGC_NVM_RW_REG_DONE 2 /* Offset to READ/WRITE done bit */
+#define IGC_NVM_RW_REG_START 1 /* Start operation */
+#define IGC_NVM_RW_ADDR_SHIFT 2 /* Shift to the address bits */
+#define IGC_NVM_POLL_READ 0 /* Flag for polling for read complete */
+
+/* NVM Word Offsets */
+#define NVM_CHECKSUM_REG 0x003F
+
+/* For checksumming, the sum of all words in the NVM should equal 0xBABA. */
+#define NVM_SUM 0xBABA
+
+#define NVM_PBA_OFFSET_0 8
+#define NVM_PBA_OFFSET_1 9
+#define NVM_RESERVED_WORD 0xFFFF
+#define NVM_PBA_PTR_GUARD 0xFAFA
+#define NVM_WORD_SIZE_BASE_SHIFT 6
+
+/* Collision related configuration parameters */
+#define IGC_COLLISION_THRESHOLD 15
+#define IGC_CT_SHIFT 4
+#define IGC_COLLISION_DISTANCE 63
+#define IGC_COLD_SHIFT 12
+
+/* Device Status */
+#define IGC_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */
+#define IGC_STATUS_LU 0x00000002 /* Link up.0=no,1=link */
+#define IGC_STATUS_FUNC_MASK 0x0000000C /* PCI Function Mask */
+#define IGC_STATUS_FUNC_SHIFT 2
+#define IGC_STATUS_FUNC_1 0x00000004 /* Function 1 */
+#define IGC_STATUS_TXOFF 0x00000010 /* transmission paused */
+#define IGC_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */
+#define IGC_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */
+#define IGC_STATUS_SPEED_2500 0x00400000 /* Speed 2.5Gb/s */
+
+#define SPEED_10 10
+#define SPEED_100 100
+#define SPEED_1000 1000
+#define SPEED_2500 2500
+#define HALF_DUPLEX 1
+#define FULL_DUPLEX 2
+
+/* 1Gbps and 2.5Gbps half duplex is not supported, nor spec-compliant. */
+#define ADVERTISE_10_HALF 0x0001
+#define ADVERTISE_10_FULL 0x0002
+#define ADVERTISE_100_HALF 0x0004
+#define ADVERTISE_100_FULL 0x0008
+#define ADVERTISE_1000_HALF 0x0010 /* Not used, just FYI */
+#define ADVERTISE_1000_FULL 0x0020
+#define ADVERTISE_2500_HALF 0x0040 /* Not used, just FYI */
+#define ADVERTISE_2500_FULL 0x0080
+
+#define IGC_ALL_SPEED_DUPLEX_2500 ( \
+ ADVERTISE_10_HALF | ADVERTISE_10_FULL | ADVERTISE_100_HALF | \
+ ADVERTISE_100_FULL | ADVERTISE_1000_FULL | ADVERTISE_2500_FULL)
+
+#define AUTONEG_ADVERTISE_SPEED_DEFAULT_2500 IGC_ALL_SPEED_DUPLEX_2500
+
+/* Interrupt Cause Read */
+#define IGC_ICR_TXDW BIT(0) /* Transmit desc written back */
+#define IGC_ICR_TXQE BIT(1) /* Transmit Queue empty */
+#define IGC_ICR_LSC BIT(2) /* Link Status Change */
+#define IGC_ICR_RXSEQ BIT(3) /* Rx sequence error */
+#define IGC_ICR_RXDMT0 BIT(4) /* Rx desc min. threshold (0) */
+#define IGC_ICR_RXO BIT(6) /* Rx overrun */
+#define IGC_ICR_RXT0 BIT(7) /* Rx timer intr (ring 0) */
+#define IGC_ICR_DRSTA BIT(30) /* Device Reset Asserted */
+
+/* If this bit asserted, the driver should claim the interrupt */
+#define IGC_ICR_INT_ASSERTED BIT(31)
+
+#define IGC_ICS_RXT0 IGC_ICR_RXT0 /* Rx timer intr */
+
+#define IMS_ENABLE_MASK ( \
+ IGC_IMS_RXT0 | \
+ IGC_IMS_TXDW | \
+ IGC_IMS_RXDMT0 | \
+ IGC_IMS_RXSEQ | \
+ IGC_IMS_LSC)
+
+/* Interrupt Mask Set */
+#define IGC_IMS_TXDW IGC_ICR_TXDW /* Tx desc written back */
+#define IGC_IMS_RXSEQ IGC_ICR_RXSEQ /* Rx sequence error */
+#define IGC_IMS_LSC IGC_ICR_LSC /* Link Status Change */
+#define IGC_IMS_DOUTSYNC IGC_ICR_DOUTSYNC /* NIC DMA out of sync */
+#define IGC_IMS_DRSTA IGC_ICR_DRSTA /* Device Reset Asserted */
+#define IGC_IMS_RXT0 IGC_ICR_RXT0 /* Rx timer intr */
+#define IGC_IMS_RXDMT0 IGC_ICR_RXDMT0 /* Rx desc min. threshold */
+
+#define IGC_QVECTOR_MASK 0x7FFC /* Q-vector mask */
+#define IGC_ITR_VAL_MASK 0x04 /* ITR value mask */
+
+/* Interrupt Cause Set */
+#define IGC_ICS_LSC IGC_ICR_LSC /* Link Status Change */
+#define IGC_ICS_RXDMT0 IGC_ICR_RXDMT0 /* rx desc min. threshold */
+#define IGC_ICS_DRSTA IGC_ICR_DRSTA /* Device Reset Aserted */
+
+#define IGC_ICR_DOUTSYNC 0x10000000 /* NIC DMA out of sync */
+#define IGC_EITR_CNT_IGNR 0x80000000 /* Don't reset counters on write */
+#define IGC_IVAR_VALID 0x80
+#define IGC_GPIE_NSICR 0x00000001
+#define IGC_GPIE_MSIX_MODE 0x00000010
+#define IGC_GPIE_EIAME 0x40000000
+#define IGC_GPIE_PBA 0x80000000
+
+/* Transmit Descriptor bit definitions */
+#define IGC_TXD_DTYP_D 0x00100000 /* Data Descriptor */
+#define IGC_TXD_DTYP_C 0x00000000 /* Context Descriptor */
+#define IGC_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */
+#define IGC_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */
+#define IGC_TXD_CMD_EOP 0x01000000 /* End of Packet */
+#define IGC_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */
+#define IGC_TXD_CMD_IC 0x04000000 /* Insert Checksum */
+#define IGC_TXD_CMD_RS 0x08000000 /* Report Status */
+#define IGC_TXD_CMD_RPS 0x10000000 /* Report Packet Sent */
+#define IGC_TXD_CMD_DEXT 0x20000000 /* Desc extension (0 = legacy) */
+#define IGC_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */
+#define IGC_TXD_CMD_IDE 0x80000000 /* Enable Tidv register */
+#define IGC_TXD_STAT_DD 0x00000001 /* Descriptor Done */
+#define IGC_TXD_STAT_EC 0x00000002 /* Excess Collisions */
+#define IGC_TXD_STAT_LC 0x00000004 /* Late Collisions */
+#define IGC_TXD_STAT_TU 0x00000008 /* Transmit underrun */
+#define IGC_TXD_CMD_TCP 0x01000000 /* TCP packet */
+#define IGC_TXD_CMD_IP 0x02000000 /* IP packet */
+#define IGC_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */
+#define IGC_TXD_STAT_TC 0x00000004 /* Tx Underrun */
+#define IGC_TXD_EXTCMD_TSTAMP 0x00000010 /* IEEE1588 Timestamp packet */
+
+/* Transmit Control */
+#define IGC_TCTL_EN 0x00000002 /* enable Tx */
+#define IGC_TCTL_PSP 0x00000008 /* pad short packets */
+#define IGC_TCTL_CT 0x00000ff0 /* collision threshold */
+#define IGC_TCTL_COLD 0x003ff000 /* collision distance */
+#define IGC_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */
+#define IGC_TCTL_MULR 0x10000000 /* Multiple request support */
+
+#define IGC_CT_SHIFT 4
+#define IGC_COLLISION_THRESHOLD 15
+
+/* Flow Control Constants */
+#define FLOW_CONTROL_ADDRESS_LOW 0x00C28001
+#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100
+#define FLOW_CONTROL_TYPE 0x8808
+/* Enable XON frame transmission */
+#define IGC_FCRTL_XONE 0x80000000
+
+/* Management Control */
+#define IGC_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */
+#define IGC_MANC_BLK_PHY_RST_ON_IDE 0x00040000 /* Block phy resets */
+
+/* Receive Control */
+#define IGC_RCTL_RST 0x00000001 /* Software reset */
+#define IGC_RCTL_EN 0x00000002 /* enable */
+#define IGC_RCTL_SBP 0x00000004 /* store bad packet */
+#define IGC_RCTL_UPE 0x00000008 /* unicast promisc enable */
+#define IGC_RCTL_MPE 0x00000010 /* multicast promisc enable */
+#define IGC_RCTL_LPE 0x00000020 /* long packet enable */
+#define IGC_RCTL_LBM_MAC 0x00000040 /* MAC loopback mode */
+#define IGC_RCTL_LBM_TCVR 0x000000C0 /* tcvr loopback mode */
+
+#define IGC_RCTL_RDMTS_HALF 0x00000000 /* Rx desc min thresh size */
+#define IGC_RCTL_BAM 0x00008000 /* broadcast enable */
+
+/* Receive Descriptor bit definitions */
+#define IGC_RXD_STAT_EOP 0x02 /* End of Packet */
+
+#define IGC_RXDEXT_STATERR_CE 0x01000000
+#define IGC_RXDEXT_STATERR_SE 0x02000000
+#define IGC_RXDEXT_STATERR_SEQ 0x04000000
+#define IGC_RXDEXT_STATERR_CXE 0x10000000
+#define IGC_RXDEXT_STATERR_TCPE 0x20000000
+#define IGC_RXDEXT_STATERR_IPE 0x40000000
+#define IGC_RXDEXT_STATERR_RXE 0x80000000
+
+/* Same mask, but for extended and packet split descriptors */
+#define IGC_RXDEXT_ERR_FRAME_ERR_MASK ( \
+ IGC_RXDEXT_STATERR_CE | \
+ IGC_RXDEXT_STATERR_SE | \
+ IGC_RXDEXT_STATERR_SEQ | \
+ IGC_RXDEXT_STATERR_CXE | \
+ IGC_RXDEXT_STATERR_RXE)
+
+/* Header split receive */
+#define IGC_RFCTL_IPV6_EX_DIS 0x00010000
+#define IGC_RFCTL_LEF 0x00040000
+
+#define IGC_RCTL_SZ_256 0x00030000 /* Rx buffer size 256 */
+
+#define IGC_RCTL_MO_SHIFT 12 /* multicast offset shift */
+#define IGC_RCTL_CFIEN 0x00080000 /* canonical form enable */
+#define IGC_RCTL_DPF 0x00400000 /* discard pause frames */
+#define IGC_RCTL_PMCF 0x00800000 /* pass MAC control frames */
+#define IGC_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */
+
+#define I225_RXPBSIZE_DEFAULT 0x000000A2 /* RXPBSIZE default */
+#define I225_TXPBSIZE_DEFAULT 0x04000014 /* TXPBSIZE default */
+
+/* GPY211 - I225 defines */
+#define GPY_MMD_MASK 0xFFFF0000
+#define GPY_MMD_SHIFT 16
+#define GPY_REG_MASK 0x0000FFFF
+
+#define IGC_MMDAC_FUNC_DATA 0x4000 /* Data, no post increment */
+
+/* MAC definitions */
+#define IGC_FACTPS_MNGCG 0x20000000
+#define IGC_FWSM_MODE_MASK 0xE
+#define IGC_FWSM_MODE_SHIFT 1
+
+/* Management Control */
+#define IGC_MANC_SMBUS_EN 0x00000001 /* SMBus Enabled - RO */
+#define IGC_MANC_ASF_EN 0x00000002 /* ASF Enabled - RO */
+
+/* PHY */
+#define PHY_REVISION_MASK 0xFFFFFFF0
+#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */
+#define IGC_GEN_POLL_TIMEOUT 1920
+
+/* PHY Control Register */
+#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */
+#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */
+#define MII_CR_POWER_DOWN 0x0800 /* Power down */
+#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */
+#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */
+#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */
+#define MII_CR_SPEED_1000 0x0040
+#define MII_CR_SPEED_100 0x2000
+#define MII_CR_SPEED_10 0x0000
+
+/* PHY Status Register */
+#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */
+#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */
+
+/* PHY 1000 MII Register/Bit Definitions */
+/* PHY Registers defined by IEEE */
+#define PHY_CONTROL 0x00 /* Control Register */
+#define PHY_STATUS 0x01 /* Status Register */
+#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */
+#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */
+#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */
+#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */
+#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */
+#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
+
+/* Bit definitions for valid PHY IDs. I = Integrated E = External */
+#define I225_I_PHY_ID 0x67C9DC00
+
+/* MDI Control */
+#define IGC_MDIC_DATA_MASK 0x0000FFFF
+#define IGC_MDIC_REG_MASK 0x001F0000
+#define IGC_MDIC_REG_SHIFT 16
+#define IGC_MDIC_PHY_MASK 0x03E00000
+#define IGC_MDIC_PHY_SHIFT 21
+#define IGC_MDIC_OP_WRITE 0x04000000
+#define IGC_MDIC_OP_READ 0x08000000
+#define IGC_MDIC_READY 0x10000000
+#define IGC_MDIC_INT_EN 0x20000000
+#define IGC_MDIC_ERROR 0x40000000
+#define IGC_MDIC_DEST 0x80000000
+
+#define IGC_N0_QUEUE -1
+
+#endif /* _IGC_DEFINES_H_ */
diff --git a/drivers/net/ethernet/intel/igc/igc_hw.h b/drivers/net/ethernet/intel/igc/igc_hw.h
new file mode 100644
index 000000000000..c50414f48f0d
--- /dev/null
+++ b/drivers/net/ethernet/intel/igc/igc_hw.h
@@ -0,0 +1,321 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2018 Intel Corporation */
+
+#ifndef _IGC_HW_H_
+#define _IGC_HW_H_
+
+#include <linux/types.h>
+#include <linux/if_ether.h>
+#include <linux/netdevice.h>
+
+#include "igc_regs.h"
+#include "igc_defines.h"
+#include "igc_mac.h"
+#include "igc_phy.h"
+#include "igc_nvm.h"
+#include "igc_i225.h"
+#include "igc_base.h"
+
+#define IGC_DEV_ID_I225_LM 0x15F2
+#define IGC_DEV_ID_I225_V 0x15F3
+
+#define IGC_FUNC_0 0
+
+/* Function pointers for the MAC. */
+struct igc_mac_operations {
+ s32 (*check_for_link)(struct igc_hw *hw);
+ s32 (*reset_hw)(struct igc_hw *hw);
+ s32 (*init_hw)(struct igc_hw *hw);
+ s32 (*setup_physical_interface)(struct igc_hw *hw);
+ void (*rar_set)(struct igc_hw *hw, u8 *address, u32 index);
+ s32 (*read_mac_addr)(struct igc_hw *hw);
+ s32 (*get_speed_and_duplex)(struct igc_hw *hw, u16 *speed,
+ u16 *duplex);
+ s32 (*acquire_swfw_sync)(struct igc_hw *hw, u16 mask);
+ void (*release_swfw_sync)(struct igc_hw *hw, u16 mask);
+};
+
+enum igc_mac_type {
+ igc_undefined = 0,
+ igc_i225,
+ igc_num_macs /* List is 1-based, so subtract 1 for true count. */
+};
+
+enum igc_phy_type {
+ igc_phy_unknown = 0,
+ igc_phy_none,
+ igc_phy_i225,
+};
+
+enum igc_media_type {
+ igc_media_type_unknown = 0,
+ igc_media_type_copper = 1,
+ igc_num_media_types
+};
+
+enum igc_nvm_type {
+ igc_nvm_unknown = 0,
+ igc_nvm_flash_hw,
+ igc_nvm_invm,
+};
+
+struct igc_info {
+ s32 (*get_invariants)(struct igc_hw *hw);
+ struct igc_mac_operations *mac_ops;
+ const struct igc_phy_operations *phy_ops;
+ struct igc_nvm_operations *nvm_ops;
+};
+
+extern const struct igc_info igc_base_info;
+
+struct igc_mac_info {
+ struct igc_mac_operations ops;
+
+ u8 addr[ETH_ALEN];
+ u8 perm_addr[ETH_ALEN];
+
+ enum igc_mac_type type;
+
+ u32 collision_delta;
+ u32 ledctl_default;
+ u32 ledctl_mode1;
+ u32 ledctl_mode2;
+ u32 mc_filter_type;
+ u32 tx_packet_delta;
+ u32 txcw;
+
+ u16 mta_reg_count;
+ u16 uta_reg_count;
+
+ u16 rar_entry_count;
+
+ u8 forced_speed_duplex;
+
+ bool adaptive_ifs;
+ bool has_fwsm;
+ bool asf_firmware_present;
+ bool arc_subsystem_valid;
+
+ bool autoneg;
+ bool autoneg_failed;
+ bool get_link_status;
+};
+
+struct igc_nvm_operations {
+ s32 (*acquire)(struct igc_hw *hw);
+ s32 (*read)(struct igc_hw *hw, u16 offset, u16 i, u16 *data);
+ void (*release)(struct igc_hw *hw);
+ s32 (*write)(struct igc_hw *hw, u16 offset, u16 i, u16 *data);
+ s32 (*update)(struct igc_hw *hw);
+ s32 (*validate)(struct igc_hw *hw);
+ s32 (*valid_led_default)(struct igc_hw *hw, u16 *data);
+};
+
+struct igc_phy_operations {
+ s32 (*acquire)(struct igc_hw *hw);
+ s32 (*check_polarity)(struct igc_hw *hw);
+ s32 (*check_reset_block)(struct igc_hw *hw);
+ s32 (*force_speed_duplex)(struct igc_hw *hw);
+ s32 (*get_cfg_done)(struct igc_hw *hw);
+ s32 (*get_cable_length)(struct igc_hw *hw);
+ s32 (*get_phy_info)(struct igc_hw *hw);
+ s32 (*read_reg)(struct igc_hw *hw, u32 address, u16 *data);
+ void (*release)(struct igc_hw *hw);
+ s32 (*reset)(struct igc_hw *hw);
+ s32 (*write_reg)(struct igc_hw *hw, u32 address, u16 data);
+};
+
+struct igc_nvm_info {
+ struct igc_nvm_operations ops;
+ enum igc_nvm_type type;
+
+ u32 flash_bank_size;
+ u32 flash_base_addr;
+
+ u16 word_size;
+ u16 delay_usec;
+ u16 address_bits;
+ u16 opcode_bits;
+ u16 page_size;
+};
+
+struct igc_phy_info {
+ struct igc_phy_operations ops;
+
+ enum igc_phy_type type;
+
+ u32 addr;
+ u32 id;
+ u32 reset_delay_us; /* in usec */
+ u32 revision;
+
+ enum igc_media_type media_type;
+
+ u16 autoneg_advertised;
+ u16 autoneg_mask;
+ u16 cable_length;
+ u16 max_cable_length;
+ u16 min_cable_length;
+ u16 pair_length[4];
+
+ u8 mdix;
+
+ bool disable_polarity_correction;
+ bool is_mdix;
+ bool polarity_correction;
+ bool reset_disable;
+ bool speed_downgraded;
+ bool autoneg_wait_to_complete;
+};
+
+struct igc_bus_info {
+ u16 func;
+ u16 pci_cmd_word;
+};
+
+enum igc_fc_mode {
+ igc_fc_none = 0,
+ igc_fc_rx_pause,
+ igc_fc_tx_pause,
+ igc_fc_full,
+ igc_fc_default = 0xFF
+};
+
+struct igc_fc_info {
+ u32 high_water; /* Flow control high-water mark */
+ u32 low_water; /* Flow control low-water mark */
+ u16 pause_time; /* Flow control pause timer */
+ bool send_xon; /* Flow control send XON */
+ bool strict_ieee; /* Strict IEEE mode */
+ enum igc_fc_mode current_mode; /* Type of flow control */
+ enum igc_fc_mode requested_mode;
+};
+
+struct igc_dev_spec_base {
+ bool global_device_reset;
+ bool eee_disable;
+ bool clear_semaphore_once;
+ bool module_plugged;
+ u8 media_port;
+ bool mas_capable;
+};
+
+struct igc_hw {
+ void *back;
+
+ u8 __iomem *hw_addr;
+ unsigned long io_base;
+
+ struct igc_mac_info mac;
+ struct igc_fc_info fc;
+ struct igc_nvm_info nvm;
+ struct igc_phy_info phy;
+
+ struct igc_bus_info bus;
+
+ union {
+ struct igc_dev_spec_base _base;
+ } dev_spec;
+
+ u16 device_id;
+ u16 subsystem_vendor_id;
+ u16 subsystem_device_id;
+ u16 vendor_id;
+
+ u8 revision_id;
+};
+
+/* Statistics counters collected by the MAC */
+struct igc_hw_stats {
+ u64 crcerrs;
+ u64 algnerrc;
+ u64 symerrs;
+ u64 rxerrc;
+ u64 mpc;
+ u64 scc;
+ u64 ecol;
+ u64 mcc;
+ u64 latecol;
+ u64 colc;
+ u64 dc;
+ u64 tncrs;
+ u64 sec;
+ u64 cexterr;
+ u64 rlec;
+ u64 xonrxc;
+ u64 xontxc;
+ u64 xoffrxc;
+ u64 xofftxc;
+ u64 fcruc;
+ u64 prc64;
+ u64 prc127;
+ u64 prc255;
+ u64 prc511;
+ u64 prc1023;
+ u64 prc1522;
+ u64 gprc;
+ u64 bprc;
+ u64 mprc;
+ u64 gptc;
+ u64 gorc;
+ u64 gotc;
+ u64 rnbc;
+ u64 ruc;
+ u64 rfc;
+ u64 roc;
+ u64 rjc;
+ u64 mgprc;
+ u64 mgpdc;
+ u64 mgptc;
+ u64 tor;
+ u64 tot;
+ u64 tpr;
+ u64 tpt;
+ u64 ptc64;
+ u64 ptc127;
+ u64 ptc255;
+ u64 ptc511;
+ u64 ptc1023;
+ u64 ptc1522;
+ u64 mptc;
+ u64 bptc;
+ u64 tsctc;
+ u64 tsctfc;
+ u64 iac;
+ u64 icrxptc;
+ u64 icrxatc;
+ u64 ictxptc;
+ u64 ictxatc;
+ u64 ictxqec;
+ u64 ictxqmtc;
+ u64 icrxdmtc;
+ u64 icrxoc;
+ u64 cbtmpc;
+ u64 htdpmc;
+ u64 cbrdpc;
+ u64 cbrmpc;
+ u64 rpthc;
+ u64 hgptc;
+ u64 htcbdpc;
+ u64 hgorc;
+ u64 hgotc;
+ u64 lenerrs;
+ u64 scvpc;
+ u64 hrmpc;
+ u64 doosync;
+ u64 o2bgptc;
+ u64 o2bspc;
+ u64 b2ospc;
+ u64 b2ogprc;
+};
+
+struct net_device *igc_get_hw_dev(struct igc_hw *hw);
+#define hw_dbg(format, arg...) \
+ netdev_dbg(igc_get_hw_dev(hw), format, ##arg)
+
+s32 igc_read_pcie_cap_reg(struct igc_hw *hw, u32 reg, u16 *value);
+s32 igc_write_pcie_cap_reg(struct igc_hw *hw, u32 reg, u16 *value);
+void igc_read_pci_cfg(struct igc_hw *hw, u32 reg, u16 *value);
+void igc_write_pci_cfg(struct igc_hw *hw, u32 reg, u16 *value);
+
+#endif /* _IGC_HW_H_ */
diff --git a/drivers/net/ethernet/intel/igc/igc_i225.c b/drivers/net/ethernet/intel/igc/igc_i225.c
new file mode 100644
index 000000000000..c25f555aaf82
--- /dev/null
+++ b/drivers/net/ethernet/intel/igc/igc_i225.c
@@ -0,0 +1,490 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2018 Intel Corporation */
+
+#include <linux/delay.h>
+
+#include "igc_hw.h"
+
+/**
+ * igc_get_hw_semaphore_i225 - Acquire hardware semaphore
+ * @hw: pointer to the HW structure
+ *
+ * Acquire the necessary semaphores for exclusive access to the EEPROM.
+ * Set the EEPROM access request bit and wait for EEPROM access grant bit.
+ * Return successful if access grant bit set, else clear the request for
+ * EEPROM access and return -IGC_ERR_NVM (-1).
+ */
+static s32 igc_acquire_nvm_i225(struct igc_hw *hw)
+{
+ return igc_acquire_swfw_sync_i225(hw, IGC_SWFW_EEP_SM);
+}
+
+/**
+ * igc_release_nvm_i225 - Release exclusive access to EEPROM
+ * @hw: pointer to the HW structure
+ *
+ * Stop any current commands to the EEPROM and clear the EEPROM request bit,
+ * then release the semaphores acquired.
+ */
+static void igc_release_nvm_i225(struct igc_hw *hw)
+{
+ igc_release_swfw_sync_i225(hw, IGC_SWFW_EEP_SM);
+}
+
+/**
+ * igc_get_hw_semaphore_i225 - Acquire hardware semaphore
+ * @hw: pointer to the HW structure
+ *
+ * Acquire the HW semaphore to access the PHY or NVM
+ */
+static s32 igc_get_hw_semaphore_i225(struct igc_hw *hw)
+{
+ s32 timeout = hw->nvm.word_size + 1;
+ s32 i = 0;
+ u32 swsm;
+
+ /* Get the SW semaphore */
+ while (i < timeout) {
+ swsm = rd32(IGC_SWSM);
+ if (!(swsm & IGC_SWSM_SMBI))
+ break;
+
+ usleep_range(500, 600);
+ i++;
+ }
+
+ if (i == timeout) {
+ /* In rare circumstances, the SW semaphore may already be held
+ * unintentionally. Clear the semaphore once before giving up.
+ */
+ if (hw->dev_spec._base.clear_semaphore_once) {
+ hw->dev_spec._base.clear_semaphore_once = false;
+ igc_put_hw_semaphore(hw);
+ for (i = 0; i < timeout; i++) {
+ swsm = rd32(IGC_SWSM);
+ if (!(swsm & IGC_SWSM_SMBI))
+ break;
+
+ usleep_range(500, 600);
+ }
+ }
+
+ /* If we do not have the semaphore here, we have to give up. */
+ if (i == timeout) {
+ hw_dbg("Driver can't access device - SMBI bit is set.\n");
+ return -IGC_ERR_NVM;
+ }
+ }
+
+ /* Get the FW semaphore. */
+ for (i = 0; i < timeout; i++) {
+ swsm = rd32(IGC_SWSM);
+ wr32(IGC_SWSM, swsm | IGC_SWSM_SWESMBI);
+
+ /* Semaphore acquired if bit latched */
+ if (rd32(IGC_SWSM) & IGC_SWSM_SWESMBI)
+ break;
+
+ usleep_range(500, 600);
+ }
+
+ if (i == timeout) {
+ /* Release semaphores */
+ igc_put_hw_semaphore(hw);
+ hw_dbg("Driver can't access the NVM\n");
+ return -IGC_ERR_NVM;
+ }
+
+ return 0;
+}
+
+/**
+ * igc_acquire_swfw_sync_i225 - Acquire SW/FW semaphore
+ * @hw: pointer to the HW structure
+ * @mask: specifies which semaphore to acquire
+ *
+ * Acquire the SW/FW semaphore to access the PHY or NVM. The mask
+ * will also specify which port we're acquiring the lock for.
+ */
+s32 igc_acquire_swfw_sync_i225(struct igc_hw *hw, u16 mask)
+{
+ s32 i = 0, timeout = 200;
+ u32 fwmask = mask << 16;
+ u32 swmask = mask;
+ s32 ret_val = 0;
+ u32 swfw_sync;
+
+ while (i < timeout) {
+ if (igc_get_hw_semaphore_i225(hw)) {
+ ret_val = -IGC_ERR_SWFW_SYNC;
+ goto out;
+ }
+
+ swfw_sync = rd32(IGC_SW_FW_SYNC);
+ if (!(swfw_sync & (fwmask | swmask)))
+ break;
+
+ /* Firmware currently using resource (fwmask) */
+ igc_put_hw_semaphore(hw);
+ mdelay(5);
+ i++;
+ }
+
+ if (i == timeout) {
+ hw_dbg("Driver can't access resource, SW_FW_SYNC timeout.\n");
+ ret_val = -IGC_ERR_SWFW_SYNC;
+ goto out;
+ }
+
+ swfw_sync |= swmask;
+ wr32(IGC_SW_FW_SYNC, swfw_sync);
+
+ igc_put_hw_semaphore(hw);
+out:
+ return ret_val;
+}
+
+/**
+ * igc_release_swfw_sync_i225 - Release SW/FW semaphore
+ * @hw: pointer to the HW structure
+ * @mask: specifies which semaphore to acquire
+ *
+ * Release the SW/FW semaphore used to access the PHY or NVM. The mask
+ * will also specify which port we're releasing the lock for.
+ */
+void igc_release_swfw_sync_i225(struct igc_hw *hw, u16 mask)
+{
+ u32 swfw_sync;
+
+ while (igc_get_hw_semaphore_i225(hw))
+ ; /* Empty */
+
+ swfw_sync = rd32(IGC_SW_FW_SYNC);
+ swfw_sync &= ~mask;
+ wr32(IGC_SW_FW_SYNC, swfw_sync);
+
+ igc_put_hw_semaphore(hw);
+}
+
+/**
+ * igc_read_nvm_srrd_i225 - Reads Shadow Ram using EERD register
+ * @hw: pointer to the HW structure
+ * @offset: offset of word in the Shadow Ram to read
+ * @words: number of words to read
+ * @data: word read from the Shadow Ram
+ *
+ * Reads a 16 bit word from the Shadow Ram using the EERD register.
+ * Uses necessary synchronization semaphores.
+ */
+static s32 igc_read_nvm_srrd_i225(struct igc_hw *hw, u16 offset, u16 words,
+ u16 *data)
+{
+ s32 status = 0;
+ u16 i, count;
+
+ /* We cannot hold synchronization semaphores for too long,
+ * because of forceful takeover procedure. However it is more efficient
+ * to read in bursts than synchronizing access for each word.
+ */
+ for (i = 0; i < words; i += IGC_EERD_EEWR_MAX_COUNT) {
+ count = (words - i) / IGC_EERD_EEWR_MAX_COUNT > 0 ?
+ IGC_EERD_EEWR_MAX_COUNT : (words - i);
+
+ status = hw->nvm.ops.acquire(hw);
+ if (status)
+ break;
+
+ status = igc_read_nvm_eerd(hw, offset, count, data + i);
+ hw->nvm.ops.release(hw);
+ if (status)
+ break;
+ }
+
+ return status;
+}
+
+/**
+ * igc_write_nvm_srwr - Write to Shadow Ram using EEWR
+ * @hw: pointer to the HW structure
+ * @offset: offset within the Shadow Ram to be written to
+ * @words: number of words to write
+ * @data: 16 bit word(s) to be written to the Shadow Ram
+ *
+ * Writes data to Shadow Ram at offset using EEWR register.
+ *
+ * If igc_update_nvm_checksum is not called after this function , the
+ * Shadow Ram will most likely contain an invalid checksum.
+ */
+static s32 igc_write_nvm_srwr(struct igc_hw *hw, u16 offset, u16 words,
+ u16 *data)
+{
+ struct igc_nvm_info *nvm = &hw->nvm;
+ u32 attempts = 100000;
+ u32 i, k, eewr = 0;
+ s32 ret_val = 0;
+
+ /* A check for invalid values: offset too large, too many words,
+ * too many words for the offset, and not enough words.
+ */
+ if (offset >= nvm->word_size || (words > (nvm->word_size - offset)) ||
+ words == 0) {
+ hw_dbg("nvm parameter(s) out of bounds\n");
+ ret_val = -IGC_ERR_NVM;
+ goto out;
+ }
+
+ for (i = 0; i < words; i++) {
+ eewr = ((offset + i) << IGC_NVM_RW_ADDR_SHIFT) |
+ (data[i] << IGC_NVM_RW_REG_DATA) |
+ IGC_NVM_RW_REG_START;
+
+ wr32(IGC_SRWR, eewr);
+
+ for (k = 0; k < attempts; k++) {
+ if (IGC_NVM_RW_REG_DONE &
+ rd32(IGC_SRWR)) {
+ ret_val = 0;
+ break;
+ }
+ udelay(5);
+ }
+
+ if (ret_val) {
+ hw_dbg("Shadow RAM write EEWR timed out\n");
+ break;
+ }
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * igc_write_nvm_srwr_i225 - Write to Shadow RAM using EEWR
+ * @hw: pointer to the HW structure
+ * @offset: offset within the Shadow RAM to be written to
+ * @words: number of words to write
+ * @data: 16 bit word(s) to be written to the Shadow RAM
+ *
+ * Writes data to Shadow RAM at offset using EEWR register.
+ *
+ * If igc_update_nvm_checksum is not called after this function , the
+ * data will not be committed to FLASH and also Shadow RAM will most likely
+ * contain an invalid checksum.
+ *
+ * If error code is returned, data and Shadow RAM may be inconsistent - buffer
+ * partially written.
+ */
+static s32 igc_write_nvm_srwr_i225(struct igc_hw *hw, u16 offset, u16 words,
+ u16 *data)
+{
+ s32 status = 0;
+ u16 i, count;
+
+ /* We cannot hold synchronization semaphores for too long,
+ * because of forceful takeover procedure. However it is more efficient
+ * to write in bursts than synchronizing access for each word.
+ */
+ for (i = 0; i < words; i += IGC_EERD_EEWR_MAX_COUNT) {
+ count = (words - i) / IGC_EERD_EEWR_MAX_COUNT > 0 ?
+ IGC_EERD_EEWR_MAX_COUNT : (words - i);
+
+ status = hw->nvm.ops.acquire(hw);
+ if (status)
+ break;
+
+ status = igc_write_nvm_srwr(hw, offset, count, data + i);
+ hw->nvm.ops.release(hw);
+ if (status)
+ break;
+ }
+
+ return status;
+}
+
+/**
+ * igc_validate_nvm_checksum_i225 - Validate EEPROM checksum
+ * @hw: pointer to the HW structure
+ *
+ * Calculates the EEPROM checksum by reading/adding each word of the EEPROM
+ * and then verifies that the sum of the EEPROM is equal to 0xBABA.
+ */
+static s32 igc_validate_nvm_checksum_i225(struct igc_hw *hw)
+{
+ s32 (*read_op_ptr)(struct igc_hw *hw, u16 offset, u16 count,
+ u16 *data);
+ s32 status = 0;
+
+ status = hw->nvm.ops.acquire(hw);
+ if (status)
+ goto out;
+
+ /* Replace the read function with semaphore grabbing with
+ * the one that skips this for a while.
+ * We have semaphore taken already here.
+ */
+ read_op_ptr = hw->nvm.ops.read;
+ hw->nvm.ops.read = igc_read_nvm_eerd;
+
+ status = igc_validate_nvm_checksum(hw);
+
+ /* Revert original read operation. */
+ hw->nvm.ops.read = read_op_ptr;
+
+ hw->nvm.ops.release(hw);
+
+out:
+ return status;
+}
+
+/**
+ * igc_pool_flash_update_done_i225 - Pool FLUDONE status
+ * @hw: pointer to the HW structure
+ */
+static s32 igc_pool_flash_update_done_i225(struct igc_hw *hw)
+{
+ s32 ret_val = -IGC_ERR_NVM;
+ u32 i, reg;
+
+ for (i = 0; i < IGC_FLUDONE_ATTEMPTS; i++) {
+ reg = rd32(IGC_EECD);
+ if (reg & IGC_EECD_FLUDONE_I225) {
+ ret_val = 0;
+ break;
+ }
+ udelay(5);
+ }
+
+ return ret_val;
+}
+
+/**
+ * igc_update_flash_i225 - Commit EEPROM to the flash
+ * @hw: pointer to the HW structure
+ */
+static s32 igc_update_flash_i225(struct igc_hw *hw)
+{
+ s32 ret_val = 0;
+ u32 flup;
+
+ ret_val = igc_pool_flash_update_done_i225(hw);
+ if (ret_val == -IGC_ERR_NVM) {
+ hw_dbg("Flash update time out\n");
+ goto out;
+ }
+
+ flup = rd32(IGC_EECD) | IGC_EECD_FLUPD_I225;
+ wr32(IGC_EECD, flup);
+
+ ret_val = igc_pool_flash_update_done_i225(hw);
+ if (ret_val)
+ hw_dbg("Flash update time out\n");
+ else
+ hw_dbg("Flash update complete\n");
+
+out:
+ return ret_val;
+}
+
+/**
+ * igc_update_nvm_checksum_i225 - Update EEPROM checksum
+ * @hw: pointer to the HW structure
+ *
+ * Updates the EEPROM checksum by reading/adding each word of the EEPROM
+ * up to the checksum. Then calculates the EEPROM checksum and writes the
+ * value to the EEPROM. Next commit EEPROM data onto the Flash.
+ */
+static s32 igc_update_nvm_checksum_i225(struct igc_hw *hw)
+{
+ u16 checksum = 0;
+ s32 ret_val = 0;
+ u16 i, nvm_data;
+
+ /* Read the first word from the EEPROM. If this times out or fails, do
+ * not continue or we could be in for a very long wait while every
+ * EEPROM read fails
+ */
+ ret_val = igc_read_nvm_eerd(hw, 0, 1, &nvm_data);
+ if (ret_val) {
+ hw_dbg("EEPROM read failed\n");
+ goto out;
+ }
+
+ ret_val = hw->nvm.ops.acquire(hw);
+ if (ret_val)
+ goto out;
+
+ /* Do not use hw->nvm.ops.write, hw->nvm.ops.read
+ * because we do not want to take the synchronization
+ * semaphores twice here.
+ */
+
+ for (i = 0; i < NVM_CHECKSUM_REG; i++) {
+ ret_val = igc_read_nvm_eerd(hw, i, 1, &nvm_data);
+ if (ret_val) {
+ hw->nvm.ops.release(hw);
+ hw_dbg("NVM Read Error while updating checksum.\n");
+ goto out;
+ }
+ checksum += nvm_data;
+ }
+ checksum = (u16)NVM_SUM - checksum;
+ ret_val = igc_write_nvm_srwr(hw, NVM_CHECKSUM_REG, 1,
+ &checksum);
+ if (ret_val) {
+ hw->nvm.ops.release(hw);
+ hw_dbg("NVM Write Error while updating checksum.\n");
+ goto out;
+ }
+
+ hw->nvm.ops.release(hw);
+
+ ret_val = igc_update_flash_i225(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * igc_get_flash_presence_i225 - Check if flash device is detected
+ * @hw: pointer to the HW structure
+ */
+bool igc_get_flash_presence_i225(struct igc_hw *hw)
+{
+ bool ret_val = false;
+ u32 eec = 0;
+
+ eec = rd32(IGC_EECD);
+ if (eec & IGC_EECD_FLASH_DETECTED_I225)
+ ret_val = true;
+
+ return ret_val;
+}
+
+/**
+ * igc_init_nvm_params_i225 - Init NVM func ptrs.
+ * @hw: pointer to the HW structure
+ */
+s32 igc_init_nvm_params_i225(struct igc_hw *hw)
+{
+ struct igc_nvm_info *nvm = &hw->nvm;
+
+ nvm->ops.acquire = igc_acquire_nvm_i225;
+ nvm->ops.release = igc_release_nvm_i225;
+
+ /* NVM Function Pointers */
+ if (igc_get_flash_presence_i225(hw)) {
+ hw->nvm.type = igc_nvm_flash_hw;
+ nvm->ops.read = igc_read_nvm_srrd_i225;
+ nvm->ops.write = igc_write_nvm_srwr_i225;
+ nvm->ops.validate = igc_validate_nvm_checksum_i225;
+ nvm->ops.update = igc_update_nvm_checksum_i225;
+ } else {
+ hw->nvm.type = igc_nvm_invm;
+ nvm->ops.read = igc_read_nvm_eerd;
+ nvm->ops.write = NULL;
+ nvm->ops.validate = NULL;
+ nvm->ops.update = NULL;
+ }
+ return 0;
+}
diff --git a/drivers/net/ethernet/intel/igc/igc_i225.h b/drivers/net/ethernet/intel/igc/igc_i225.h
new file mode 100644
index 000000000000..7b66e1f9c0e6
--- /dev/null
+++ b/drivers/net/ethernet/intel/igc/igc_i225.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2018 Intel Corporation */
+
+#ifndef _IGC_I225_H_
+#define _IGC_I225_H_
+
+s32 igc_acquire_swfw_sync_i225(struct igc_hw *hw, u16 mask);
+void igc_release_swfw_sync_i225(struct igc_hw *hw, u16 mask);
+
+s32 igc_init_nvm_params_i225(struct igc_hw *hw);
+bool igc_get_flash_presence_i225(struct igc_hw *hw);
+
+#endif
diff --git a/drivers/net/ethernet/intel/igc/igc_mac.c b/drivers/net/ethernet/intel/igc/igc_mac.c
new file mode 100644
index 000000000000..f7683d3ae47c
--- /dev/null
+++ b/drivers/net/ethernet/intel/igc/igc_mac.c
@@ -0,0 +1,806 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2018 Intel Corporation */
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include "igc_mac.h"
+#include "igc_hw.h"
+
+/* forward declaration */
+static s32 igc_set_default_fc(struct igc_hw *hw);
+static s32 igc_set_fc_watermarks(struct igc_hw *hw);
+
+/**
+ * igc_disable_pcie_master - Disables PCI-express master access
+ * @hw: pointer to the HW structure
+ *
+ * Returns 0 (0) if successful, else returns -10
+ * (-IGC_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not caused
+ * the master requests to be disabled.
+ *
+ * Disables PCI-Express master access and verifies there are no pending
+ * requests.
+ */
+s32 igc_disable_pcie_master(struct igc_hw *hw)
+{
+ s32 timeout = MASTER_DISABLE_TIMEOUT;
+ s32 ret_val = 0;
+ u32 ctrl;
+
+ ctrl = rd32(IGC_CTRL);
+ ctrl |= IGC_CTRL_GIO_MASTER_DISABLE;
+ wr32(IGC_CTRL, ctrl);
+
+ while (timeout) {
+ if (!(rd32(IGC_STATUS) &
+ IGC_STATUS_GIO_MASTER_ENABLE))
+ break;
+ usleep_range(2000, 3000);
+ timeout--;
+ }
+
+ if (!timeout) {
+ hw_dbg("Master requests are pending.\n");
+ ret_val = -IGC_ERR_MASTER_REQUESTS_PENDING;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * igc_init_rx_addrs - Initialize receive addresses
+ * @hw: pointer to the HW structure
+ * @rar_count: receive address registers
+ *
+ * Setup the receive address registers by setting the base receive address
+ * register to the devices MAC address and clearing all the other receive
+ * address registers to 0.
+ */
+void igc_init_rx_addrs(struct igc_hw *hw, u16 rar_count)
+{
+ u8 mac_addr[ETH_ALEN] = {0};
+ u32 i;
+
+ /* Setup the receive address */
+ hw_dbg("Programming MAC Address into RAR[0]\n");
+
+ hw->mac.ops.rar_set(hw, hw->mac.addr, 0);
+
+ /* Zero out the other (rar_entry_count - 1) receive addresses */
+ hw_dbg("Clearing RAR[1-%u]\n", rar_count - 1);
+ for (i = 1; i < rar_count; i++)
+ hw->mac.ops.rar_set(hw, mac_addr, i);
+}
+
+/**
+ * igc_setup_link - Setup flow control and link settings
+ * @hw: pointer to the HW structure
+ *
+ * Determines which flow control settings to use, then configures flow
+ * control. Calls the appropriate media-specific link configuration
+ * function. Assuming the adapter has a valid link partner, a valid link
+ * should be established. Assumes the hardware has previously been reset
+ * and the transmitter and receiver are not enabled.
+ */
+s32 igc_setup_link(struct igc_hw *hw)
+{
+ s32 ret_val = 0;
+
+ /* In the case of the phy reset being blocked, we already have a link.
+ * We do not need to set it up again.
+ */
+ if (igc_check_reset_block(hw))
+ goto out;
+
+ /* If requested flow control is set to default, set flow control
+ * based on the EEPROM flow control settings.
+ */
+ if (hw->fc.requested_mode == igc_fc_default) {
+ ret_val = igc_set_default_fc(hw);
+ if (ret_val)
+ goto out;
+ }
+
+ /* We want to save off the original Flow Control configuration just
+ * in case we get disconnected and then reconnected into a different
+ * hub or switch with different Flow Control capabilities.
+ */
+ hw->fc.current_mode = hw->fc.requested_mode;
+
+ hw_dbg("After fix-ups FlowControl is now = %x\n", hw->fc.current_mode);
+
+ /* Call the necessary media_type subroutine to configure the link. */
+ ret_val = hw->mac.ops.setup_physical_interface(hw);
+ if (ret_val)
+ goto out;
+
+ /* Initialize the flow control address, type, and PAUSE timer
+ * registers to their default values. This is done even if flow
+ * control is disabled, because it does not hurt anything to
+ * initialize these registers.
+ */
+ hw_dbg("Initializing the Flow Control address, type and timer regs\n");
+ wr32(IGC_FCT, FLOW_CONTROL_TYPE);
+ wr32(IGC_FCAH, FLOW_CONTROL_ADDRESS_HIGH);
+ wr32(IGC_FCAL, FLOW_CONTROL_ADDRESS_LOW);
+
+ wr32(IGC_FCTTV, hw->fc.pause_time);
+
+ ret_val = igc_set_fc_watermarks(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * igc_set_default_fc - Set flow control default values
+ * @hw: pointer to the HW structure
+ *
+ * Read the EEPROM for the default values for flow control and store the
+ * values.
+ */
+static s32 igc_set_default_fc(struct igc_hw *hw)
+{
+ hw->fc.requested_mode = igc_fc_full;
+ return 0;
+}
+
+/**
+ * igc_force_mac_fc - Force the MAC's flow control settings
+ * @hw: pointer to the HW structure
+ *
+ * Force the MAC's flow control settings. Sets the TFCE and RFCE bits in the
+ * device control register to reflect the adapter settings. TFCE and RFCE
+ * need to be explicitly set by software when a copper PHY is used because
+ * autonegotiation is managed by the PHY rather than the MAC. Software must
+ * also configure these bits when link is forced on a fiber connection.
+ */
+s32 igc_force_mac_fc(struct igc_hw *hw)
+{
+ s32 ret_val = 0;
+ u32 ctrl;
+
+ ctrl = rd32(IGC_CTRL);
+
+ /* Because we didn't get link via the internal auto-negotiation
+ * mechanism (we either forced link or we got link via PHY
+ * auto-neg), we have to manually enable/disable transmit an
+ * receive flow control.
+ *
+ * The "Case" statement below enables/disable flow control
+ * according to the "hw->fc.current_mode" parameter.
+ *
+ * The possible values of the "fc" parameter are:
+ * 0: Flow control is completely disabled
+ * 1: Rx flow control is enabled (we can receive pause
+ * frames but not send pause frames).
+ * 2: Tx flow control is enabled (we can send pause frames
+ * frames but we do not receive pause frames).
+ * 3: Both Rx and TX flow control (symmetric) is enabled.
+ * other: No other values should be possible at this point.
+ */
+ hw_dbg("hw->fc.current_mode = %u\n", hw->fc.current_mode);
+
+ switch (hw->fc.current_mode) {
+ case igc_fc_none:
+ ctrl &= (~(IGC_CTRL_TFCE | IGC_CTRL_RFCE));
+ break;
+ case igc_fc_rx_pause:
+ ctrl &= (~IGC_CTRL_TFCE);
+ ctrl |= IGC_CTRL_RFCE;
+ break;
+ case igc_fc_tx_pause:
+ ctrl &= (~IGC_CTRL_RFCE);
+ ctrl |= IGC_CTRL_TFCE;
+ break;
+ case igc_fc_full:
+ ctrl |= (IGC_CTRL_TFCE | IGC_CTRL_RFCE);
+ break;
+ default:
+ hw_dbg("Flow control param set incorrectly\n");
+ ret_val = -IGC_ERR_CONFIG;
+ goto out;
+ }
+
+ wr32(IGC_CTRL, ctrl);
+
+out:
+ return ret_val;
+}
+
+/**
+ * igc_set_fc_watermarks - Set flow control high/low watermarks
+ * @hw: pointer to the HW structure
+ *
+ * Sets the flow control high/low threshold (watermark) registers. If
+ * flow control XON frame transmission is enabled, then set XON frame
+ * transmission as well.
+ */
+static s32 igc_set_fc_watermarks(struct igc_hw *hw)
+{
+ u32 fcrtl = 0, fcrth = 0;
+
+ /* Set the flow control receive threshold registers. Normally,
+ * these registers will be set to a default threshold that may be
+ * adjusted later by the driver's runtime code. However, if the
+ * ability to transmit pause frames is not enabled, then these
+ * registers will be set to 0.
+ */
+ if (hw->fc.current_mode & igc_fc_tx_pause) {
+ /* We need to set up the Receive Threshold high and low water
+ * marks as well as (optionally) enabling the transmission of
+ * XON frames.
+ */
+ fcrtl = hw->fc.low_water;
+ if (hw->fc.send_xon)
+ fcrtl |= IGC_FCRTL_XONE;
+
+ fcrth = hw->fc.high_water;
+ }
+ wr32(IGC_FCRTL, fcrtl);
+ wr32(IGC_FCRTH, fcrth);
+
+ return 0;
+}
+
+/**
+ * igc_clear_hw_cntrs_base - Clear base hardware counters
+ * @hw: pointer to the HW structure
+ *
+ * Clears the base hardware counters by reading the counter registers.
+ */
+void igc_clear_hw_cntrs_base(struct igc_hw *hw)
+{
+ rd32(IGC_CRCERRS);
+ rd32(IGC_SYMERRS);
+ rd32(IGC_MPC);
+ rd32(IGC_SCC);
+ rd32(IGC_ECOL);
+ rd32(IGC_MCC);
+ rd32(IGC_LATECOL);
+ rd32(IGC_COLC);
+ rd32(IGC_DC);
+ rd32(IGC_SEC);
+ rd32(IGC_RLEC);
+ rd32(IGC_XONRXC);
+ rd32(IGC_XONTXC);
+ rd32(IGC_XOFFRXC);
+ rd32(IGC_XOFFTXC);
+ rd32(IGC_FCRUC);
+ rd32(IGC_GPRC);
+ rd32(IGC_BPRC);
+ rd32(IGC_MPRC);
+ rd32(IGC_GPTC);
+ rd32(IGC_GORCL);
+ rd32(IGC_GORCH);
+ rd32(IGC_GOTCL);
+ rd32(IGC_GOTCH);
+ rd32(IGC_RNBC);
+ rd32(IGC_RUC);
+ rd32(IGC_RFC);
+ rd32(IGC_ROC);
+ rd32(IGC_RJC);
+ rd32(IGC_TORL);
+ rd32(IGC_TORH);
+ rd32(IGC_TOTL);
+ rd32(IGC_TOTH);
+ rd32(IGC_TPR);
+ rd32(IGC_TPT);
+ rd32(IGC_MPTC);
+ rd32(IGC_BPTC);
+
+ rd32(IGC_PRC64);
+ rd32(IGC_PRC127);
+ rd32(IGC_PRC255);
+ rd32(IGC_PRC511);
+ rd32(IGC_PRC1023);
+ rd32(IGC_PRC1522);
+ rd32(IGC_PTC64);
+ rd32(IGC_PTC127);
+ rd32(IGC_PTC255);
+ rd32(IGC_PTC511);
+ rd32(IGC_PTC1023);
+ rd32(IGC_PTC1522);
+
+ rd32(IGC_ALGNERRC);
+ rd32(IGC_RXERRC);
+ rd32(IGC_TNCRS);
+ rd32(IGC_CEXTERR);
+ rd32(IGC_TSCTC);
+ rd32(IGC_TSCTFC);
+
+ rd32(IGC_MGTPRC);
+ rd32(IGC_MGTPDC);
+ rd32(IGC_MGTPTC);
+
+ rd32(IGC_IAC);
+ rd32(IGC_ICRXOC);
+
+ rd32(IGC_ICRXPTC);
+ rd32(IGC_ICRXATC);
+ rd32(IGC_ICTXPTC);
+ rd32(IGC_ICTXATC);
+ rd32(IGC_ICTXQEC);
+ rd32(IGC_ICTXQMTC);
+ rd32(IGC_ICRXDMTC);
+
+ rd32(IGC_CBTMPC);
+ rd32(IGC_HTDPMC);
+ rd32(IGC_CBRMPC);
+ rd32(IGC_RPTHC);
+ rd32(IGC_HGPTC);
+ rd32(IGC_HTCBDPC);
+ rd32(IGC_HGORCL);
+ rd32(IGC_HGORCH);
+ rd32(IGC_HGOTCL);
+ rd32(IGC_HGOTCH);
+ rd32(IGC_LENERRS);
+}
+
+/**
+ * igc_rar_set - Set receive address register
+ * @hw: pointer to the HW structure
+ * @addr: pointer to the receive address
+ * @index: receive address array register
+ *
+ * Sets the receive address array register at index to the address passed
+ * in by addr.
+ */
+void igc_rar_set(struct igc_hw *hw, u8 *addr, u32 index)
+{
+ u32 rar_low, rar_high;
+
+ /* HW expects these in little endian so we reverse the byte order
+ * from network order (big endian) to little endian
+ */
+ rar_low = ((u32)addr[0] |
+ ((u32)addr[1] << 8) |
+ ((u32)addr[2] << 16) | ((u32)addr[3] << 24));
+
+ rar_high = ((u32)addr[4] | ((u32)addr[5] << 8));
+
+ /* If MAC address zero, no need to set the AV bit */
+ if (rar_low || rar_high)
+ rar_high |= IGC_RAH_AV;
+
+ /* Some bridges will combine consecutive 32-bit writes into
+ * a single burst write, which will malfunction on some parts.
+ * The flushes avoid this.
+ */
+ wr32(IGC_RAL(index), rar_low);
+ wrfl();
+ wr32(IGC_RAH(index), rar_high);
+ wrfl();
+}
+
+/**
+ * igc_check_for_copper_link - Check for link (Copper)
+ * @hw: pointer to the HW structure
+ *
+ * Checks to see of the link status of the hardware has changed. If a
+ * change in link status has been detected, then we read the PHY registers
+ * to get the current speed/duplex if link exists.
+ */
+s32 igc_check_for_copper_link(struct igc_hw *hw)
+{
+ struct igc_mac_info *mac = &hw->mac;
+ s32 ret_val;
+ bool link;
+
+ /* We only want to go out to the PHY registers to see if Auto-Neg
+ * has completed and/or if our link status has changed. The
+ * get_link_status flag is set upon receiving a Link Status
+ * Change or Rx Sequence Error interrupt.
+ */
+ if (!mac->get_link_status) {
+ ret_val = 0;
+ goto out;
+ }
+
+ /* First we want to see if the MII Status Register reports
+ * link. If so, then we want to get the current speed/duplex
+ * of the PHY.
+ */
+ ret_val = igc_phy_has_link(hw, 1, 0, &link);
+ if (ret_val)
+ goto out;
+
+ if (!link)
+ goto out; /* No link detected */
+
+ mac->get_link_status = false;
+
+ /* Check if there was DownShift, must be checked
+ * immediately after link-up
+ */
+ igc_check_downshift(hw);
+
+ /* If we are forcing speed/duplex, then we simply return since
+ * we have already determined whether we have link or not.
+ */
+ if (!mac->autoneg) {
+ ret_val = -IGC_ERR_CONFIG;
+ goto out;
+ }
+
+ /* Auto-Neg is enabled. Auto Speed Detection takes care
+ * of MAC speed/duplex configuration. So we only need to
+ * configure Collision Distance in the MAC.
+ */
+ igc_config_collision_dist(hw);
+
+ /* Configure Flow Control now that Auto-Neg has completed.
+ * First, we need to restore the desired flow control
+ * settings because we may have had to re-autoneg with a
+ * different link partner.
+ */
+ ret_val = igc_config_fc_after_link_up(hw);
+ if (ret_val)
+ hw_dbg("Error configuring flow control\n");
+
+out:
+ return ret_val;
+}
+
+/**
+ * igc_config_collision_dist - Configure collision distance
+ * @hw: pointer to the HW structure
+ *
+ * Configures the collision distance to the default value and is used
+ * during link setup. Currently no func pointer exists and all
+ * implementations are handled in the generic version of this function.
+ */
+void igc_config_collision_dist(struct igc_hw *hw)
+{
+ u32 tctl;
+
+ tctl = rd32(IGC_TCTL);
+
+ tctl &= ~IGC_TCTL_COLD;
+ tctl |= IGC_COLLISION_DISTANCE << IGC_COLD_SHIFT;
+
+ wr32(IGC_TCTL, tctl);
+ wrfl();
+}
+
+/**
+ * igc_config_fc_after_link_up - Configures flow control after link
+ * @hw: pointer to the HW structure
+ *
+ * Checks the status of auto-negotiation after link up to ensure that the
+ * speed and duplex were not forced. If the link needed to be forced, then
+ * flow control needs to be forced also. If auto-negotiation is enabled
+ * and did not fail, then we configure flow control based on our link
+ * partner.
+ */
+s32 igc_config_fc_after_link_up(struct igc_hw *hw)
+{
+ u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg;
+ struct igc_mac_info *mac = &hw->mac;
+ u16 speed, duplex;
+ s32 ret_val = 0;
+
+ /* Check for the case where we have fiber media and auto-neg failed
+ * so we had to force link. In this case, we need to force the
+ * configuration of the MAC to match the "fc" parameter.
+ */
+ if (mac->autoneg_failed) {
+ if (hw->phy.media_type == igc_media_type_copper)
+ ret_val = igc_force_mac_fc(hw);
+ }
+
+ if (ret_val) {
+ hw_dbg("Error forcing flow control settings\n");
+ goto out;
+ }
+
+ /* Check for the case where we have copper media and auto-neg is
+ * enabled. In this case, we need to check and see if Auto-Neg
+ * has completed, and if so, how the PHY and link partner has
+ * flow control configured.
+ */
+ if (hw->phy.media_type == igc_media_type_copper && mac->autoneg) {
+ /* Read the MII Status Register and check to see if AutoNeg
+ * has completed. We read this twice because this reg has
+ * some "sticky" (latched) bits.
+ */
+ ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS,
+ &mii_status_reg);
+ if (ret_val)
+ goto out;
+ ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS,
+ &mii_status_reg);
+ if (ret_val)
+ goto out;
+
+ if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) {
+ hw_dbg("Copper PHY and Auto Neg has not completed.\n");
+ goto out;
+ }
+
+ /* The AutoNeg process has completed, so we now need to
+ * read both the Auto Negotiation Advertisement
+ * Register (Address 4) and the Auto_Negotiation Base
+ * Page Ability Register (Address 5) to determine how
+ * flow control was negotiated.
+ */
+ ret_val = hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV,
+ &mii_nway_adv_reg);
+ if (ret_val)
+ goto out;
+ ret_val = hw->phy.ops.read_reg(hw, PHY_LP_ABILITY,
+ &mii_nway_lp_ability_reg);
+ if (ret_val)
+ goto out;
+ /* Two bits in the Auto Negotiation Advertisement Register
+ * (Address 4) and two bits in the Auto Negotiation Base
+ * Page Ability Register (Address 5) determine flow control
+ * for both the PHY and the link partner. The following
+ * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
+ * 1999, describes these PAUSE resolution bits and how flow
+ * control is determined based upon these settings.
+ * NOTE: DC = Don't Care
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
+ *-------|---------|-------|---------|--------------------
+ * 0 | 0 | DC | DC | igc_fc_none
+ * 0 | 1 | 0 | DC | igc_fc_none
+ * 0 | 1 | 1 | 0 | igc_fc_none
+ * 0 | 1 | 1 | 1 | igc_fc_tx_pause
+ * 1 | 0 | 0 | DC | igc_fc_none
+ * 1 | DC | 1 | DC | igc_fc_full
+ * 1 | 1 | 0 | 0 | igc_fc_none
+ * 1 | 1 | 0 | 1 | igc_fc_rx_pause
+ *
+ * Are both PAUSE bits set to 1? If so, this implies
+ * Symmetric Flow Control is enabled at both ends. The
+ * ASM_DIR bits are irrelevant per the spec.
+ *
+ * For Symmetric Flow Control:
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+ *-------|---------|-------|---------|--------------------
+ * 1 | DC | 1 | DC | IGC_fc_full
+ *
+ */
+ if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
+ /* Now we need to check if the user selected RX ONLY
+ * of pause frames. In this case, we had to advertise
+ * FULL flow control because we could not advertise RX
+ * ONLY. Hence, we must now check to see if we need to
+ * turn OFF the TRANSMISSION of PAUSE frames.
+ */
+ if (hw->fc.requested_mode == igc_fc_full) {
+ hw->fc.current_mode = igc_fc_full;
+ hw_dbg("Flow Control = FULL.\n");
+ } else {
+ hw->fc.current_mode = igc_fc_rx_pause;
+ hw_dbg("Flow Control = RX PAUSE frames only.\n");
+ }
+ }
+
+ /* For receiving PAUSE frames ONLY.
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+ *-------|---------|-------|---------|--------------------
+ * 0 | 1 | 1 | 1 | igc_fc_tx_pause
+ */
+ else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+ (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+ hw->fc.current_mode = igc_fc_tx_pause;
+ hw_dbg("Flow Control = TX PAUSE frames only.\n");
+ }
+ /* For transmitting PAUSE frames ONLY.
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+ *-------|---------|-------|---------|--------------------
+ * 1 | 1 | 0 | 1 | igc_fc_rx_pause
+ */
+ else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+ (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+ !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+ hw->fc.current_mode = igc_fc_rx_pause;
+ hw_dbg("Flow Control = RX PAUSE frames only.\n");
+ }
+ /* Per the IEEE spec, at this point flow control should be
+ * disabled. However, we want to consider that we could
+ * be connected to a legacy switch that doesn't advertise
+ * desired flow control, but can be forced on the link
+ * partner. So if we advertised no flow control, that is
+ * what we will resolve to. If we advertised some kind of
+ * receive capability (Rx Pause Only or Full Flow Control)
+ * and the link partner advertised none, we will configure
+ * ourselves to enable Rx Flow Control only. We can do
+ * this safely for two reasons: If the link partner really
+ * didn't want flow control enabled, and we enable Rx, no
+ * harm done since we won't be receiving any PAUSE frames
+ * anyway. If the intent on the link partner was to have
+ * flow control enabled, then by us enabling RX only, we
+ * can at least receive pause frames and process them.
+ * This is a good idea because in most cases, since we are
+ * predominantly a server NIC, more times than not we will
+ * be asked to delay transmission of packets than asking
+ * our link partner to pause transmission of frames.
+ */
+ else if ((hw->fc.requested_mode == igc_fc_none) ||
+ (hw->fc.requested_mode == igc_fc_tx_pause) ||
+ (hw->fc.strict_ieee)) {
+ hw->fc.current_mode = igc_fc_none;
+ hw_dbg("Flow Control = NONE.\n");
+ } else {
+ hw->fc.current_mode = igc_fc_rx_pause;
+ hw_dbg("Flow Control = RX PAUSE frames only.\n");
+ }
+
+ /* Now we need to do one last check... If we auto-
+ * negotiated to HALF DUPLEX, flow control should not be
+ * enabled per IEEE 802.3 spec.
+ */
+ ret_val = hw->mac.ops.get_speed_and_duplex(hw, &speed, &duplex);
+ if (ret_val) {
+ hw_dbg("Error getting link speed and duplex\n");
+ goto out;
+ }
+
+ if (duplex == HALF_DUPLEX)
+ hw->fc.current_mode = igc_fc_none;
+
+ /* Now we call a subroutine to actually force the MAC
+ * controller to use the correct flow control settings.
+ */
+ ret_val = igc_force_mac_fc(hw);
+ if (ret_val) {
+ hw_dbg("Error forcing flow control settings\n");
+ goto out;
+ }
+ }
+
+out:
+ return 0;
+}
+
+/**
+ * igc_get_auto_rd_done - Check for auto read completion
+ * @hw: pointer to the HW structure
+ *
+ * Check EEPROM for Auto Read done bit.
+ */
+s32 igc_get_auto_rd_done(struct igc_hw *hw)
+{
+ s32 ret_val = 0;
+ s32 i = 0;
+
+ while (i < AUTO_READ_DONE_TIMEOUT) {
+ if (rd32(IGC_EECD) & IGC_EECD_AUTO_RD)
+ break;
+ usleep_range(1000, 2000);
+ i++;
+ }
+
+ if (i == AUTO_READ_DONE_TIMEOUT) {
+ hw_dbg("Auto read by HW from NVM has not completed.\n");
+ ret_val = -IGC_ERR_RESET;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * igc_get_speed_and_duplex_copper - Retrieve current speed/duplex
+ * @hw: pointer to the HW structure
+ * @speed: stores the current speed
+ * @duplex: stores the current duplex
+ *
+ * Read the status register for the current speed/duplex and store the current
+ * speed and duplex for copper connections.
+ */
+s32 igc_get_speed_and_duplex_copper(struct igc_hw *hw, u16 *speed,
+ u16 *duplex)
+{
+ u32 status;
+
+ status = rd32(IGC_STATUS);
+ if (status & IGC_STATUS_SPEED_1000) {
+ /* For I225, STATUS will indicate 1G speed in both 1 Gbps
+ * and 2.5 Gbps link modes. An additional bit is used
+ * to differentiate between 1 Gbps and 2.5 Gbps.
+ */
+ if (hw->mac.type == igc_i225 &&
+ (status & IGC_STATUS_SPEED_2500)) {
+ *speed = SPEED_2500;
+ hw_dbg("2500 Mbs, ");
+ } else {
+ *speed = SPEED_1000;
+ hw_dbg("1000 Mbs, ");
+ }
+ } else if (status & IGC_STATUS_SPEED_100) {
+ *speed = SPEED_100;
+ hw_dbg("100 Mbs, ");
+ } else {
+ *speed = SPEED_10;
+ hw_dbg("10 Mbs, ");
+ }
+
+ if (status & IGC_STATUS_FD) {
+ *duplex = FULL_DUPLEX;
+ hw_dbg("Full Duplex\n");
+ } else {
+ *duplex = HALF_DUPLEX;
+ hw_dbg("Half Duplex\n");
+ }
+
+ return 0;
+}
+
+/**
+ * igc_put_hw_semaphore - Release hardware semaphore
+ * @hw: pointer to the HW structure
+ *
+ * Release hardware semaphore used to access the PHY or NVM
+ */
+void igc_put_hw_semaphore(struct igc_hw *hw)
+{
+ u32 swsm;
+
+ swsm = rd32(IGC_SWSM);
+
+ swsm &= ~(IGC_SWSM_SMBI | IGC_SWSM_SWESMBI);
+
+ wr32(IGC_SWSM, swsm);
+}
+
+/**
+ * igc_enable_mng_pass_thru - Enable processing of ARP's
+ * @hw: pointer to the HW structure
+ *
+ * Verifies the hardware needs to leave interface enabled so that frames can
+ * be directed to and from the management interface.
+ */
+bool igc_enable_mng_pass_thru(struct igc_hw *hw)
+{
+ bool ret_val = false;
+ u32 fwsm, factps;
+ u32 manc;
+
+ if (!hw->mac.asf_firmware_present)
+ goto out;
+
+ manc = rd32(IGC_MANC);
+
+ if (!(manc & IGC_MANC_RCV_TCO_EN))
+ goto out;
+
+ if (hw->mac.arc_subsystem_valid) {
+ fwsm = rd32(IGC_FWSM);
+ factps = rd32(IGC_FACTPS);
+
+ if (!(factps & IGC_FACTPS_MNGCG) &&
+ ((fwsm & IGC_FWSM_MODE_MASK) ==
+ (igc_mng_mode_pt << IGC_FWSM_MODE_SHIFT))) {
+ ret_val = true;
+ goto out;
+ }
+ } else {
+ if ((manc & IGC_MANC_SMBUS_EN) &&
+ !(manc & IGC_MANC_ASF_EN)) {
+ ret_val = true;
+ goto out;
+ }
+ }
+
+out:
+ return ret_val;
+}
diff --git a/drivers/net/ethernet/intel/igc/igc_mac.h b/drivers/net/ethernet/intel/igc/igc_mac.h
new file mode 100644
index 000000000000..782bc995badc
--- /dev/null
+++ b/drivers/net/ethernet/intel/igc/igc_mac.h
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2018 Intel Corporation */
+
+#ifndef _IGC_MAC_H_
+#define _IGC_MAC_H_
+
+#include "igc_hw.h"
+#include "igc_phy.h"
+#include "igc_defines.h"
+
+#ifndef IGC_REMOVED
+#define IGC_REMOVED(a) (0)
+#endif /* IGC_REMOVED */
+
+/* forward declaration */
+s32 igc_disable_pcie_master(struct igc_hw *hw);
+s32 igc_check_for_copper_link(struct igc_hw *hw);
+s32 igc_config_fc_after_link_up(struct igc_hw *hw);
+s32 igc_force_mac_fc(struct igc_hw *hw);
+void igc_init_rx_addrs(struct igc_hw *hw, u16 rar_count);
+s32 igc_setup_link(struct igc_hw *hw);
+void igc_clear_hw_cntrs_base(struct igc_hw *hw);
+s32 igc_get_auto_rd_done(struct igc_hw *hw);
+void igc_put_hw_semaphore(struct igc_hw *hw);
+void igc_rar_set(struct igc_hw *hw, u8 *addr, u32 index);
+void igc_config_collision_dist(struct igc_hw *hw);
+
+s32 igc_get_speed_and_duplex_copper(struct igc_hw *hw, u16 *speed,
+ u16 *duplex);
+
+bool igc_enable_mng_pass_thru(struct igc_hw *hw);
+
+enum igc_mng_mode {
+ igc_mng_mode_none = 0,
+ igc_mng_mode_asf,
+ igc_mng_mode_pt,
+ igc_mng_mode_ipmi,
+ igc_mng_mode_host_if_only
+};
+
+#endif
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
new file mode 100644
index 000000000000..9d85707e8a81
--- /dev/null
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -0,0 +1,3901 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2018 Intel Corporation */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/if_vlan.h>
+#include <linux/aer.h>
+
+#include "igc.h"
+#include "igc_hw.h"
+
+#define DRV_VERSION "0.0.1-k"
+#define DRV_SUMMARY "Intel(R) 2.5G Ethernet Linux Driver"
+
+static int debug = -1;
+
+MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
+MODULE_DESCRIPTION(DRV_SUMMARY);
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(DRV_VERSION);
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
+
+char igc_driver_name[] = "igc";
+char igc_driver_version[] = DRV_VERSION;
+static const char igc_driver_string[] = DRV_SUMMARY;
+static const char igc_copyright[] =
+ "Copyright(c) 2018 Intel Corporation.";
+
+static const struct igc_info *igc_info_tbl[] = {
+ [board_base] = &igc_base_info,
+};
+
+static const struct pci_device_id igc_pci_tbl[] = {
+ { PCI_VDEVICE(INTEL, IGC_DEV_ID_I225_LM), board_base },
+ { PCI_VDEVICE(INTEL, IGC_DEV_ID_I225_V), board_base },
+ /* required last entry */
+ {0, }
+};
+
+MODULE_DEVICE_TABLE(pci, igc_pci_tbl);
+
+/* forward declaration */
+static void igc_clean_tx_ring(struct igc_ring *tx_ring);
+static int igc_sw_init(struct igc_adapter *);
+static void igc_configure(struct igc_adapter *adapter);
+static void igc_power_down_link(struct igc_adapter *adapter);
+static void igc_set_default_mac_filter(struct igc_adapter *adapter);
+static void igc_set_rx_mode(struct net_device *netdev);
+static void igc_write_itr(struct igc_q_vector *q_vector);
+static void igc_assign_vector(struct igc_q_vector *q_vector, int msix_vector);
+static void igc_free_q_vector(struct igc_adapter *adapter, int v_idx);
+static void igc_set_interrupt_capability(struct igc_adapter *adapter,
+ bool msix);
+static void igc_free_q_vectors(struct igc_adapter *adapter);
+static void igc_irq_disable(struct igc_adapter *adapter);
+static void igc_irq_enable(struct igc_adapter *adapter);
+static void igc_configure_msix(struct igc_adapter *adapter);
+static bool igc_alloc_mapped_page(struct igc_ring *rx_ring,
+ struct igc_rx_buffer *bi);
+
+enum latency_range {
+ lowest_latency = 0,
+ low_latency = 1,
+ bulk_latency = 2,
+ latency_invalid = 255
+};
+
+static void igc_reset(struct igc_adapter *adapter)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ struct igc_hw *hw = &adapter->hw;
+
+ hw->mac.ops.reset_hw(hw);
+
+ if (hw->mac.ops.init_hw(hw))
+ dev_err(&pdev->dev, "Hardware Error\n");
+
+ if (!netif_running(adapter->netdev))
+ igc_power_down_link(adapter);
+
+ igc_get_phy_info(hw);
+}
+
+/**
+ * igc_power_up_link - Power up the phy/serdes link
+ * @adapter: address of board private structure
+ */
+static void igc_power_up_link(struct igc_adapter *adapter)
+{
+ igc_reset_phy(&adapter->hw);
+
+ if (adapter->hw.phy.media_type == igc_media_type_copper)
+ igc_power_up_phy_copper(&adapter->hw);
+
+ igc_setup_link(&adapter->hw);
+}
+
+/**
+ * igc_power_down_link - Power down the phy/serdes link
+ * @adapter: address of board private structure
+ */
+static void igc_power_down_link(struct igc_adapter *adapter)
+{
+ if (adapter->hw.phy.media_type == igc_media_type_copper)
+ igc_power_down_phy_copper_base(&adapter->hw);
+}
+
+/**
+ * igc_release_hw_control - release control of the h/w to f/w
+ * @adapter: address of board private structure
+ *
+ * igc_release_hw_control resets CTRL_EXT:DRV_LOAD bit.
+ * For ASF and Pass Through versions of f/w this means that the
+ * driver is no longer loaded.
+ */
+static void igc_release_hw_control(struct igc_adapter *adapter)
+{
+ struct igc_hw *hw = &adapter->hw;
+ u32 ctrl_ext;
+
+ /* Let firmware take over control of h/w */
+ ctrl_ext = rd32(IGC_CTRL_EXT);
+ wr32(IGC_CTRL_EXT,
+ ctrl_ext & ~IGC_CTRL_EXT_DRV_LOAD);
+}
+
+/**
+ * igc_get_hw_control - get control of the h/w from f/w
+ * @adapter: address of board private structure
+ *
+ * igc_get_hw_control sets CTRL_EXT:DRV_LOAD bit.
+ * For ASF and Pass Through versions of f/w this means that
+ * the driver is loaded.
+ */
+static void igc_get_hw_control(struct igc_adapter *adapter)
+{
+ struct igc_hw *hw = &adapter->hw;
+ u32 ctrl_ext;
+
+ /* Let firmware know the driver has taken over */
+ ctrl_ext = rd32(IGC_CTRL_EXT);
+ wr32(IGC_CTRL_EXT,
+ ctrl_ext | IGC_CTRL_EXT_DRV_LOAD);
+}
+
+/**
+ * igc_free_tx_resources - Free Tx Resources per Queue
+ * @tx_ring: Tx descriptor ring for a specific queue
+ *
+ * Free all transmit software resources
+ */
+static void igc_free_tx_resources(struct igc_ring *tx_ring)
+{
+ igc_clean_tx_ring(tx_ring);
+
+ vfree(tx_ring->tx_buffer_info);
+ tx_ring->tx_buffer_info = NULL;
+
+ /* if not set, then don't free */
+ if (!tx_ring->desc)
+ return;
+
+ dma_free_coherent(tx_ring->dev, tx_ring->size,
+ tx_ring->desc, tx_ring->dma);
+
+ tx_ring->desc = NULL;
+}
+
+/**
+ * igc_free_all_tx_resources - Free Tx Resources for All Queues
+ * @adapter: board private structure
+ *
+ * Free all transmit software resources
+ */
+static void igc_free_all_tx_resources(struct igc_adapter *adapter)
+{
+ int i;
+
+ for (i = 0; i < adapter->num_tx_queues; i++)
+ igc_free_tx_resources(adapter->tx_ring[i]);
+}
+
+/**
+ * igc_clean_tx_ring - Free Tx Buffers
+ * @tx_ring: ring to be cleaned
+ */
+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];
+
+ while (i != tx_ring->next_to_use) {
+ union igc_adv_tx_desc *eop_desc, *tx_desc;
+
+ /* Free all the Tx ring sk_buffs */
+ 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);
+
+ /* check for eop_desc to determine the end of the packet */
+ eop_desc = tx_buffer->next_to_watch;
+ tx_desc = IGC_TX_DESC(tx_ring, i);
+
+ /* unmap remaining buffers */
+ while (tx_desc != eop_desc) {
+ tx_buffer++;
+ tx_desc++;
+ i++;
+ if (unlikely(i == tx_ring->count)) {
+ i = 0;
+ tx_buffer = tx_ring->tx_buffer_info;
+ tx_desc = IGC_TX_DESC(tx_ring, 0);
+ }
+
+ /* 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);
+ }
+
+ /* move us one more past the eop_desc for start of next pkt */
+ tx_buffer++;
+ i++;
+ if (unlikely(i == tx_ring->count)) {
+ i = 0;
+ tx_buffer = tx_ring->tx_buffer_info;
+ }
+ }
+
+ /* reset BQL for queue */
+ netdev_tx_reset_queue(txring_txq(tx_ring));
+
+ /* reset next_to_use and next_to_clean */
+ tx_ring->next_to_use = 0;
+ tx_ring->next_to_clean = 0;
+}
+
+/**
+ * igc_clean_all_tx_rings - Free Tx Buffers for all queues
+ * @adapter: board private structure
+ */
+static void igc_clean_all_tx_rings(struct igc_adapter *adapter)
+{
+ int i;
+
+ for (i = 0; i < adapter->num_tx_queues; i++)
+ if (adapter->tx_ring[i])
+ igc_clean_tx_ring(adapter->tx_ring[i]);
+}
+
+/**
+ * igc_setup_tx_resources - allocate Tx resources (Descriptors)
+ * @tx_ring: tx descriptor ring (for a specific queue) to setup
+ *
+ * Return 0 on success, negative on failure
+ */
+static int igc_setup_tx_resources(struct igc_ring *tx_ring)
+{
+ struct device *dev = tx_ring->dev;
+ int size = 0;
+
+ size = sizeof(struct igc_tx_buffer) * tx_ring->count;
+ tx_ring->tx_buffer_info = vzalloc(size);
+ if (!tx_ring->tx_buffer_info)
+ goto err;
+
+ /* round up to nearest 4K */
+ tx_ring->size = tx_ring->count * sizeof(union igc_adv_tx_desc);
+ tx_ring->size = ALIGN(tx_ring->size, 4096);
+
+ tx_ring->desc = dma_alloc_coherent(dev, tx_ring->size,
+ &tx_ring->dma, GFP_KERNEL);
+
+ if (!tx_ring->desc)
+ goto err;
+
+ tx_ring->next_to_use = 0;
+ tx_ring->next_to_clean = 0;
+
+ return 0;
+
+err:
+ vfree(tx_ring->tx_buffer_info);
+ dev_err(dev,
+ "Unable to allocate memory for the transmit descriptor ring\n");
+ return -ENOMEM;
+}
+
+/**
+ * igc_setup_all_tx_resources - wrapper to allocate Tx resources for all queues
+ * @adapter: board private structure
+ *
+ * Return 0 on success, negative on failure
+ */
+static int igc_setup_all_tx_resources(struct igc_adapter *adapter)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ int i, err = 0;
+
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ err = igc_setup_tx_resources(adapter->tx_ring[i]);
+ if (err) {
+ dev_err(&pdev->dev,
+ "Allocation for Tx Queue %u failed\n", i);
+ for (i--; i >= 0; i--)
+ igc_free_tx_resources(adapter->tx_ring[i]);
+ break;
+ }
+ }
+
+ 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)
+{
+ u16 i = rx_ring->next_to_clean;
+
+ if (rx_ring->skb)
+ dev_kfree_skb(rx_ring->skb);
+ rx_ring->skb = NULL;
+
+ /* Free all the Rx ring sk_buffs */
+ while (i != rx_ring->next_to_alloc) {
+ struct igc_rx_buffer *buffer_info = &rx_ring->rx_buffer_info[i];
+
+ /* Invalidate cache lines that may have been written to by
+ * device so that we avoid corrupting memory.
+ */
+ dma_sync_single_range_for_cpu(rx_ring->dev,
+ buffer_info->dma,
+ buffer_info->page_offset,
+ igc_rx_bufsz(rx_ring),
+ DMA_FROM_DEVICE);
+
+ /* free resources associated with mapping */
+ dma_unmap_page_attrs(rx_ring->dev,
+ buffer_info->dma,
+ igc_rx_pg_size(rx_ring),
+ DMA_FROM_DEVICE,
+ IGC_RX_DMA_ATTR);
+ __page_frag_cache_drain(buffer_info->page,
+ buffer_info->pagecnt_bias);
+
+ i++;
+ if (i == rx_ring->count)
+ i = 0;
+ }
+
+ rx_ring->next_to_alloc = 0;
+ rx_ring->next_to_clean = 0;
+ rx_ring->next_to_use = 0;
+}
+
+/**
+ * igc_clean_all_rx_rings - Free Rx Buffers for all queues
+ * @adapter: board private structure
+ */
+static void igc_clean_all_rx_rings(struct igc_adapter *adapter)
+{
+ int i;
+
+ for (i = 0; i < adapter->num_rx_queues; i++)
+ if (adapter->rx_ring[i])
+ igc_clean_rx_ring(adapter->rx_ring[i]);
+}
+
+/**
+ * igc_free_rx_resources - Free Rx Resources
+ * @rx_ring: ring to clean the resources from
+ *
+ * Free all receive software resources
+ */
+static void igc_free_rx_resources(struct igc_ring *rx_ring)
+{
+ igc_clean_rx_ring(rx_ring);
+
+ vfree(rx_ring->rx_buffer_info);
+ rx_ring->rx_buffer_info = NULL;
+
+ /* if not set, then don't free */
+ if (!rx_ring->desc)
+ return;
+
+ dma_free_coherent(rx_ring->dev, rx_ring->size,
+ rx_ring->desc, rx_ring->dma);
+
+ rx_ring->desc = NULL;
+}
+
+/**
+ * igc_free_all_rx_resources - Free Rx Resources for All Queues
+ * @adapter: board private structure
+ *
+ * Free all receive software resources
+ */
+static void igc_free_all_rx_resources(struct igc_adapter *adapter)
+{
+ int i;
+
+ for (i = 0; i < adapter->num_rx_queues; i++)
+ igc_free_rx_resources(adapter->rx_ring[i]);
+}
+
+/**
+ * igc_setup_rx_resources - allocate Rx resources (Descriptors)
+ * @rx_ring: rx descriptor ring (for a specific queue) to setup
+ *
+ * Returns 0 on success, negative on failure
+ */
+static int igc_setup_rx_resources(struct igc_ring *rx_ring)
+{
+ struct device *dev = rx_ring->dev;
+ int size, desc_len;
+
+ size = sizeof(struct igc_rx_buffer) * rx_ring->count;
+ rx_ring->rx_buffer_info = vzalloc(size);
+ if (!rx_ring->rx_buffer_info)
+ goto err;
+
+ desc_len = sizeof(union igc_adv_rx_desc);
+
+ /* Round up to nearest 4K */
+ rx_ring->size = rx_ring->count * desc_len;
+ rx_ring->size = ALIGN(rx_ring->size, 4096);
+
+ rx_ring->desc = dma_alloc_coherent(dev, rx_ring->size,
+ &rx_ring->dma, GFP_KERNEL);
+
+ if (!rx_ring->desc)
+ goto err;
+
+ rx_ring->next_to_alloc = 0;
+ rx_ring->next_to_clean = 0;
+ rx_ring->next_to_use = 0;
+
+ return 0;
+
+err:
+ vfree(rx_ring->rx_buffer_info);
+ rx_ring->rx_buffer_info = NULL;
+ dev_err(dev,
+ "Unable to allocate memory for the receive descriptor ring\n");
+ return -ENOMEM;
+}
+
+/**
+ * igc_setup_all_rx_resources - wrapper to allocate Rx resources
+ * (Descriptors) for all queues
+ * @adapter: board private structure
+ *
+ * Return 0 on success, negative on failure
+ */
+static int igc_setup_all_rx_resources(struct igc_adapter *adapter)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ int i, err = 0;
+
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ err = igc_setup_rx_resources(adapter->rx_ring[i]);
+ if (err) {
+ dev_err(&pdev->dev,
+ "Allocation for Rx Queue %u failed\n", i);
+ for (i--; i >= 0; i--)
+ igc_free_rx_resources(adapter->rx_ring[i]);
+ break;
+ }
+ }
+
+ return err;
+}
+
+/**
+ * igc_configure_rx_ring - Configure a receive ring after Reset
+ * @adapter: board private structure
+ * @ring: receive ring to be configured
+ *
+ * Configure the Rx unit of the MAC after a reset.
+ */
+static void igc_configure_rx_ring(struct igc_adapter *adapter,
+ struct igc_ring *ring)
+{
+ struct igc_hw *hw = &adapter->hw;
+ union igc_adv_rx_desc *rx_desc;
+ int reg_idx = ring->reg_idx;
+ u32 srrctl = 0, rxdctl = 0;
+ u64 rdba = ring->dma;
+
+ /* disable the queue */
+ wr32(IGC_RXDCTL(reg_idx), 0);
+
+ /* Set DMA base address registers */
+ wr32(IGC_RDBAL(reg_idx),
+ rdba & 0x00000000ffffffffULL);
+ wr32(IGC_RDBAH(reg_idx), rdba >> 32);
+ wr32(IGC_RDLEN(reg_idx),
+ ring->count * sizeof(union igc_adv_rx_desc));
+
+ /* initialize head and tail */
+ ring->tail = adapter->io_addr + IGC_RDT(reg_idx);
+ wr32(IGC_RDH(reg_idx), 0);
+ writel(0, ring->tail);
+
+ /* reset next-to- use/clean to place SW in sync with hardware */
+ 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;
+ else
+ srrctl |= IGC_RXBUFFER_2048 >> IGC_SRRCTL_BSIZEPKT_SHIFT;
+ srrctl |= IGC_SRRCTL_DESCTYPE_ADV_ONEBUF;
+
+ wr32(IGC_SRRCTL(reg_idx), srrctl);
+
+ rxdctl |= IGC_RX_PTHRESH;
+ rxdctl |= IGC_RX_HTHRESH << 8;
+ rxdctl |= IGC_RX_WTHRESH << 16;
+
+ /* initialize rx_buffer_info */
+ memset(ring->rx_buffer_info, 0,
+ sizeof(struct igc_rx_buffer) * ring->count);
+
+ /* initialize Rx descriptor 0 */
+ rx_desc = IGC_RX_DESC(ring, 0);
+ rx_desc->wb.upper.length = 0;
+
+ /* enable receive descriptor fetching */
+ rxdctl |= IGC_RXDCTL_QUEUE_ENABLE;
+
+ wr32(IGC_RXDCTL(reg_idx), rxdctl);
+}
+
+/**
+ * igc_configure_rx - Configure receive Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Rx unit of the MAC after a reset.
+ */
+static void igc_configure_rx(struct igc_adapter *adapter)
+{
+ int i;
+
+ /* Setup the HW Rx Head and Tail Descriptor Pointers and
+ * the Base and Length of the Rx Descriptor Ring
+ */
+ for (i = 0; i < adapter->num_rx_queues; i++)
+ igc_configure_rx_ring(adapter, adapter->rx_ring[i]);
+}
+
+/**
+ * igc_configure_tx_ring - Configure transmit ring after Reset
+ * @adapter: board private structure
+ * @ring: tx ring to configure
+ *
+ * Configure a transmit ring after a reset.
+ */
+static void igc_configure_tx_ring(struct igc_adapter *adapter,
+ struct igc_ring *ring)
+{
+ struct igc_hw *hw = &adapter->hw;
+ int reg_idx = ring->reg_idx;
+ u64 tdba = ring->dma;
+ u32 txdctl = 0;
+
+ /* disable the queue */
+ wr32(IGC_TXDCTL(reg_idx), 0);
+ wrfl();
+ mdelay(10);
+
+ wr32(IGC_TDLEN(reg_idx),
+ ring->count * sizeof(union igc_adv_tx_desc));
+ wr32(IGC_TDBAL(reg_idx),
+ tdba & 0x00000000ffffffffULL);
+ wr32(IGC_TDBAH(reg_idx), tdba >> 32);
+
+ ring->tail = adapter->io_addr + IGC_TDT(reg_idx);
+ wr32(IGC_TDH(reg_idx), 0);
+ writel(0, ring->tail);
+
+ txdctl |= IGC_TX_PTHRESH;
+ txdctl |= IGC_TX_HTHRESH << 8;
+ txdctl |= IGC_TX_WTHRESH << 16;
+
+ txdctl |= IGC_TXDCTL_QUEUE_ENABLE;
+ wr32(IGC_TXDCTL(reg_idx), txdctl);
+}
+
+/**
+ * igc_configure_tx - Configure transmit Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Tx unit of the MAC after a reset.
+ */
+static void igc_configure_tx(struct igc_adapter *adapter)
+{
+ int i;
+
+ for (i = 0; i < adapter->num_tx_queues; i++)
+ igc_configure_tx_ring(adapter, adapter->tx_ring[i]);
+}
+
+/**
+ * igc_setup_mrqc - configure the multiple receive queue control registers
+ * @adapter: Board private structure
+ */
+static void igc_setup_mrqc(struct igc_adapter *adapter)
+{
+}
+
+/**
+ * igc_setup_rctl - configure the receive control registers
+ * @adapter: Board private structure
+ */
+static void igc_setup_rctl(struct igc_adapter *adapter)
+{
+ struct igc_hw *hw = &adapter->hw;
+ u32 rctl;
+
+ rctl = rd32(IGC_RCTL);
+
+ rctl &= ~(3 << IGC_RCTL_MO_SHIFT);
+ rctl &= ~(IGC_RCTL_LBM_TCVR | IGC_RCTL_LBM_MAC);
+
+ rctl |= IGC_RCTL_EN | IGC_RCTL_BAM | IGC_RCTL_RDMTS_HALF |
+ (hw->mac.mc_filter_type << IGC_RCTL_MO_SHIFT);
+
+ /* enable stripping of CRC. Newer features require
+ * that the HW strips the CRC.
+ */
+ rctl |= IGC_RCTL_SECRC;
+
+ /* disable store bad packets and clear size bits. */
+ rctl &= ~(IGC_RCTL_SBP | IGC_RCTL_SZ_256);
+
+ /* enable LPE to allow for reception of jumbo frames */
+ rctl |= IGC_RCTL_LPE;
+
+ /* disable queue 0 to prevent tail write w/o re-config */
+ wr32(IGC_RXDCTL(0), 0);
+
+ /* This is useful for sniffing bad packets. */
+ if (adapter->netdev->features & NETIF_F_RXALL) {
+ /* UPE and MPE will be handled by normal PROMISC logic
+ * in set_rx_mode
+ */
+ rctl |= (IGC_RCTL_SBP | /* Receive bad packets */
+ IGC_RCTL_BAM | /* RX All Bcast Pkts */
+ IGC_RCTL_PMCF); /* RX All MAC Ctrl Pkts */
+
+ rctl &= ~(IGC_RCTL_DPF | /* Allow filtered pause */
+ IGC_RCTL_CFIEN); /* Disable VLAN CFIEN Filter */
+ }
+
+ wr32(IGC_RCTL, rctl);
+}
+
+/**
+ * igc_setup_tctl - configure the transmit control registers
+ * @adapter: Board private structure
+ */
+static void igc_setup_tctl(struct igc_adapter *adapter)
+{
+ struct igc_hw *hw = &adapter->hw;
+ u32 tctl;
+
+ /* disable queue 0 which icould be enabled by default */
+ wr32(IGC_TXDCTL(0), 0);
+
+ /* Program the Transmit Control Register */
+ tctl = rd32(IGC_TCTL);
+ tctl &= ~IGC_TCTL_CT;
+ tctl |= IGC_TCTL_PSP | IGC_TCTL_RTLC |
+ (IGC_COLLISION_THRESHOLD << IGC_CT_SHIFT);
+
+ /* Enable transmits */
+ tctl |= IGC_TCTL_EN;
+
+ wr32(IGC_TCTL, tctl);
+}
+
+/**
+ * igc_set_mac - Change the Ethernet Address of the NIC
+ * @netdev: network interface device structure
+ * @p: pointer to an address structure
+ *
+ * Returns 0 on success, negative on failure
+ */
+static int igc_set_mac(struct net_device *netdev, void *p)
+{
+ struct igc_adapter *adapter = netdev_priv(netdev);
+ struct igc_hw *hw = &adapter->hw;
+ struct sockaddr *addr = p;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+ memcpy(hw->mac.addr, addr->sa_data, netdev->addr_len);
+
+ /* set the correct pool for the new PF MAC address in entry 0 */
+ igc_set_default_mac_filter(adapter);
+
+ return 0;
+}
+
+static void igc_tx_csum(struct igc_ring *tx_ring, struct igc_tx_buffer *first)
+{
+}
+
+static int __igc_maybe_stop_tx(struct igc_ring *tx_ring, const u16 size)
+{
+ struct net_device *netdev = tx_ring->netdev;
+
+ netif_stop_subqueue(netdev, tx_ring->queue_index);
+
+ /* memory barriier comment */
+ smp_mb();
+
+ /* We need to check again in a case another CPU has just
+ * made room available.
+ */
+ if (igc_desc_unused(tx_ring) < size)
+ return -EBUSY;
+
+ /* A reprieve! */
+ netif_wake_subqueue(netdev, tx_ring->queue_index);
+
+ u64_stats_update_begin(&tx_ring->tx_syncp2);
+ tx_ring->tx_stats.restart_queue2++;
+ u64_stats_update_end(&tx_ring->tx_syncp2);
+
+ return 0;
+}
+
+static inline int igc_maybe_stop_tx(struct igc_ring *tx_ring, const u16 size)
+{
+ if (igc_desc_unused(tx_ring) >= size)
+ return 0;
+ return __igc_maybe_stop_tx(tx_ring, size);
+}
+
+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;
+
+ return cmd_type;
+}
+
+static void igc_tx_olinfo_status(struct igc_ring *tx_ring,
+ union igc_adv_tx_desc *tx_desc,
+ u32 tx_flags, unsigned int paylen)
+{
+ u32 olinfo_status = paylen << IGC_ADVTXD_PAYLEN_SHIFT;
+
+ /* insert L4 checksum */
+ olinfo_status |= (tx_flags & IGC_TX_FLAGS_CSUM) *
+ ((IGC_TXD_POPTS_TXSM << 8) /
+ IGC_TX_FLAGS_CSUM);
+
+ /* insert IPv4 checksum */
+ olinfo_status |= (tx_flags & IGC_TX_FLAGS_IPV4) *
+ (((IGC_TXD_POPTS_IXSM << 8)) /
+ IGC_TX_FLAGS_IPV4);
+
+ tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status);
+}
+
+static int igc_tx_map(struct igc_ring *tx_ring,
+ struct igc_tx_buffer *first,
+ const u8 hdr_len)
+{
+ struct sk_buff *skb = first->skb;
+ struct igc_tx_buffer *tx_buffer;
+ union igc_adv_tx_desc *tx_desc;
+ u32 tx_flags = first->tx_flags;
+ struct skb_frag_struct *frag;
+ u16 i = tx_ring->next_to_use;
+ unsigned int data_len, size;
+ dma_addr_t dma;
+ u32 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);
+
+ size = skb_headlen(skb);
+ data_len = skb->data_len;
+
+ dma = dma_map_single(tx_ring->dev, skb->data, size, DMA_TO_DEVICE);
+
+ tx_buffer = first;
+
+ for (frag = &skb_shinfo(skb)->frags[0];; frag++) {
+ if (dma_mapping_error(tx_ring->dev, dma))
+ goto dma_error;
+
+ /* record length, and DMA address */
+ dma_unmap_len_set(tx_buffer, len, size);
+ dma_unmap_addr_set(tx_buffer, dma, dma);
+
+ tx_desc->read.buffer_addr = cpu_to_le64(dma);
+
+ while (unlikely(size > IGC_MAX_DATA_PER_TXD)) {
+ tx_desc->read.cmd_type_len =
+ cpu_to_le32(cmd_type ^ IGC_MAX_DATA_PER_TXD);
+
+ i++;
+ tx_desc++;
+ if (i == tx_ring->count) {
+ tx_desc = IGC_TX_DESC(tx_ring, 0);
+ i = 0;
+ }
+ tx_desc->read.olinfo_status = 0;
+
+ dma += IGC_MAX_DATA_PER_TXD;
+ size -= IGC_MAX_DATA_PER_TXD;
+
+ tx_desc->read.buffer_addr = cpu_to_le64(dma);
+ }
+
+ if (likely(!data_len))
+ break;
+
+ tx_desc->read.cmd_type_len = cpu_to_le32(cmd_type ^ size);
+
+ i++;
+ tx_desc++;
+ if (i == tx_ring->count) {
+ tx_desc = IGC_TX_DESC(tx_ring, 0);
+ i = 0;
+ }
+ tx_desc->read.olinfo_status = 0;
+
+ size = skb_frag_size(frag);
+ data_len -= size;
+
+ dma = skb_frag_dma_map(tx_ring->dev, frag, 0,
+ size, DMA_TO_DEVICE);
+
+ tx_buffer = &tx_ring->tx_buffer_info[i];
+ }
+
+ /* write last descriptor with RS and EOP bits */
+ cmd_type |= size | IGC_TXD_DCMD;
+ tx_desc->read.cmd_type_len = cpu_to_le32(cmd_type);
+
+ netdev_tx_sent_queue(txring_txq(tx_ring), first->bytecount);
+
+ /* set the timestamp */
+ first->time_stamp = jiffies;
+
+ /* 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).
+ *
+ * We also need this memory barrier to make certain all of the
+ * status bits have been updated before next_to_watch is written.
+ */
+ wmb();
+
+ /* set next_to_watch value indicating a packet is present */
+ first->next_to_watch = tx_desc;
+
+ i++;
+ if (i == tx_ring->count)
+ i = 0;
+
+ tx_ring->next_to_use = i;
+
+ /* Make sure there is space in the ring for the next send. */
+ igc_maybe_stop_tx(tx_ring, DESC_NEEDED);
+
+ if (netif_xmit_stopped(txring_txq(tx_ring)) || !skb->xmit_more) {
+ writel(i, tx_ring->tail);
+
+ /* we need this if more than one processor can write to our tail
+ * at a time, it synchronizes IO on IA64/Altix systems
+ */
+ mmiowb();
+ }
+
+ return 0;
+dma_error:
+ dev_err(tx_ring->dev, "TX DMA map failed\n");
+ tx_buffer = &tx_ring->tx_buffer_info[i];
+
+ /* 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);
+
+ if (i-- == 0)
+ i += tx_ring->count;
+ tx_buffer = &tx_ring->tx_buffer_info[i];
+ }
+
+ 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);
+
+ dev_kfree_skb_any(tx_buffer->skb);
+ tx_buffer->skb = NULL;
+
+ tx_ring->next_to_use = i;
+
+ return -1;
+}
+
+static netdev_tx_t igc_xmit_frame_ring(struct sk_buff *skb,
+ struct igc_ring *tx_ring)
+{
+ u16 count = TXD_USE_COUNT(skb_headlen(skb));
+ __be16 protocol = vlan_get_protocol(skb);
+ struct igc_tx_buffer *first;
+ u32 tx_flags = 0;
+ unsigned short f;
+ u8 hdr_len = 0;
+
+ /* need: 1 descriptor per page * PAGE_SIZE/IGC_MAX_DATA_PER_TXD,
+ * + 1 desc for skb_headlen/IGC_MAX_DATA_PER_TXD,
+ * + 2 desc gap to keep tail from touching head,
+ * + 1 desc for context descriptor,
+ * otherwise try next time
+ */
+ for (f = 0; f < skb_shinfo(skb)->nr_frags; f++)
+ count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size);
+
+ if (igc_maybe_stop_tx(tx_ring, count + 3)) {
+ /* this is a hard error */
+ return NETDEV_TX_BUSY;
+ }
+
+ /* record the location of the first descriptor for this packet */
+ first = &tx_ring->tx_buffer_info[tx_ring->next_to_use];
+ first->skb = skb;
+ first->bytecount = skb->len;
+ first->gso_segs = 1;
+
+ skb_tx_timestamp(skb);
+
+ /* record initial flags and protocol */
+ first->tx_flags = tx_flags;
+ first->protocol = protocol;
+
+ igc_tx_csum(tx_ring, first);
+
+ igc_tx_map(tx_ring, first, hdr_len);
+
+ return NETDEV_TX_OK;
+}
+
+static inline struct igc_ring *igc_tx_queue_mapping(struct igc_adapter *adapter,
+ struct sk_buff *skb)
+{
+ unsigned int r_idx = skb->queue_mapping;
+
+ if (r_idx >= adapter->num_tx_queues)
+ r_idx = r_idx % adapter->num_tx_queues;
+
+ return adapter->tx_ring[r_idx];
+}
+
+static netdev_tx_t igc_xmit_frame(struct sk_buff *skb,
+ struct net_device *netdev)
+{
+ struct igc_adapter *adapter = netdev_priv(netdev);
+
+ /* The minimum packet size with TCTL.PSP set is 17 so pad the skb
+ * in order to meet this minimum size requirement.
+ */
+ if (skb->len < 17) {
+ if (skb_padto(skb, 17))
+ return NETDEV_TX_OK;
+ skb->len = 17;
+ }
+
+ return igc_xmit_frame_ring(skb, igc_tx_queue_mapping(adapter, skb));
+}
+
+static inline void igc_rx_hash(struct igc_ring *ring,
+ union igc_adv_rx_desc *rx_desc,
+ struct sk_buff *skb)
+{
+ if (ring->netdev->features & NETIF_F_RXHASH)
+ skb_set_hash(skb,
+ le32_to_cpu(rx_desc->wb.lower.hi_dword.rss),
+ PKT_HASH_TYPE_L3);
+}
+
+/**
+ * igc_process_skb_fields - Populate skb header fields from Rx descriptor
+ * @rx_ring: rx descriptor ring packet is being transacted on
+ * @rx_desc: pointer to the EOP Rx descriptor
+ * @skb: pointer to current skb being populated
+ *
+ * This function checks the ring, descriptor, and packet information in
+ * order to populate the hash, checksum, VLAN, timestamp, protocol, and
+ * other fields within the skb.
+ */
+static void igc_process_skb_fields(struct igc_ring *rx_ring,
+ union igc_adv_rx_desc *rx_desc,
+ struct sk_buff *skb)
+{
+ igc_rx_hash(rx_ring, rx_desc, skb);
+
+ skb_record_rx_queue(skb, rx_ring->queue_index);
+
+ skb->protocol = eth_type_trans(skb, rx_ring->netdev);
+}
+
+static struct igc_rx_buffer *igc_get_rx_buffer(struct igc_ring *rx_ring,
+ const unsigned int size)
+{
+ struct igc_rx_buffer *rx_buffer;
+
+ rx_buffer = &rx_ring->rx_buffer_info[rx_ring->next_to_clean];
+ prefetchw(rx_buffer->page);
+
+ /* we are reusing so sync this buffer for CPU use */
+ dma_sync_single_range_for_cpu(rx_ring->dev,
+ rx_buffer->dma,
+ rx_buffer->page_offset,
+ size,
+ DMA_FROM_DEVICE);
+
+ rx_buffer->pagecnt_bias--;
+
+ return rx_buffer;
+}
+
+/**
+ * igc_add_rx_frag - Add contents of Rx buffer to sk_buff
+ * @rx_ring: rx descriptor ring to transact packets on
+ * @rx_buffer: buffer containing page to add
+ * @skb: sk_buff to place the data into
+ * @size: size of buffer to be added
+ *
+ * This function will add the data contained in rx_buffer->page to the skb.
+ */
+static void igc_add_rx_frag(struct igc_ring *rx_ring,
+ struct igc_rx_buffer *rx_buffer,
+ struct sk_buff *skb,
+ unsigned int size)
+{
+#if (PAGE_SIZE < 8192)
+ unsigned int truesize = igc_rx_pg_size(rx_ring) / 2;
+
+ skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, rx_buffer->page,
+ rx_buffer->page_offset, size, truesize);
+ rx_buffer->page_offset ^= truesize;
+#else
+ unsigned int truesize = ring_uses_build_skb(rx_ring) ?
+ SKB_DATA_ALIGN(IGC_SKB_PAD + size) :
+ SKB_DATA_ALIGN(size);
+ skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, rx_buffer->page,
+ rx_buffer->page_offset, size, truesize);
+ rx_buffer->page_offset += truesize;
+#endif
+}
+
+static struct sk_buff *igc_build_skb(struct igc_ring *rx_ring,
+ struct igc_rx_buffer *rx_buffer,
+ union igc_adv_rx_desc *rx_desc,
+ unsigned int size)
+{
+ void *va = page_address(rx_buffer->page) + rx_buffer->page_offset;
+#if (PAGE_SIZE < 8192)
+ unsigned int truesize = igc_rx_pg_size(rx_ring) / 2;
+#else
+ unsigned int truesize = SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) +
+ SKB_DATA_ALIGN(IGC_SKB_PAD + size);
+#endif
+ struct sk_buff *skb;
+
+ /* prefetch first cache line of first page */
+ prefetch(va);
+#if L1_CACHE_BYTES < 128
+ prefetch(va + L1_CACHE_BYTES);
+#endif
+
+ /* build an skb around the page buffer */
+ skb = build_skb(va - IGC_SKB_PAD, truesize);
+ if (unlikely(!skb))
+ return NULL;
+
+ /* update pointers within the skb to store the data */
+ skb_reserve(skb, IGC_SKB_PAD);
+ __skb_put(skb, size);
+
+ /* update buffer offset */
+#if (PAGE_SIZE < 8192)
+ rx_buffer->page_offset ^= truesize;
+#else
+ rx_buffer->page_offset += truesize;
+#endif
+
+ return skb;
+}
+
+static struct sk_buff *igc_construct_skb(struct igc_ring *rx_ring,
+ struct igc_rx_buffer *rx_buffer,
+ union igc_adv_rx_desc *rx_desc,
+ unsigned int size)
+{
+ void *va = page_address(rx_buffer->page) + rx_buffer->page_offset;
+#if (PAGE_SIZE < 8192)
+ unsigned int truesize = igc_rx_pg_size(rx_ring) / 2;
+#else
+ unsigned int truesize = SKB_DATA_ALIGN(size);
+#endif
+ unsigned int headlen;
+ struct sk_buff *skb;
+
+ /* prefetch first cache line of first page */
+ prefetch(va);
+#if L1_CACHE_BYTES < 128
+ prefetch(va + L1_CACHE_BYTES);
+#endif
+
+ /* allocate a skb to store the frags */
+ skb = napi_alloc_skb(&rx_ring->q_vector->napi, IGC_RX_HDR_LEN);
+ if (unlikely(!skb))
+ return NULL;
+
+ /* Determine available headroom for copy */
+ headlen = size;
+ if (headlen > IGC_RX_HDR_LEN)
+ headlen = eth_get_headlen(va, IGC_RX_HDR_LEN);
+
+ /* align pull length to size of long to optimize memcpy performance */
+ memcpy(__skb_put(skb, headlen), va, ALIGN(headlen, sizeof(long)));
+
+ /* update all of the pointers */
+ size -= headlen;
+ if (size) {
+ skb_add_rx_frag(skb, 0, rx_buffer->page,
+ (va + headlen) - page_address(rx_buffer->page),
+ size, truesize);
+#if (PAGE_SIZE < 8192)
+ rx_buffer->page_offset ^= truesize;
+#else
+ rx_buffer->page_offset += truesize;
+#endif
+ } else {
+ rx_buffer->pagecnt_bias++;
+ }
+
+ return skb;
+}
+
+/**
+ * igc_reuse_rx_page - page flip buffer and store it back on the ring
+ * @rx_ring: rx descriptor ring to store buffers on
+ * @old_buff: donor buffer to have page reused
+ *
+ * Synchronizes page for reuse by the adapter
+ */
+static void igc_reuse_rx_page(struct igc_ring *rx_ring,
+ struct igc_rx_buffer *old_buff)
+{
+ u16 nta = rx_ring->next_to_alloc;
+ struct igc_rx_buffer *new_buff;
+
+ new_buff = &rx_ring->rx_buffer_info[nta];
+
+ /* update, and store next to alloc */
+ nta++;
+ rx_ring->next_to_alloc = (nta < rx_ring->count) ? nta : 0;
+
+ /* Transfer page from old buffer to new buffer.
+ * Move each member individually to avoid possible store
+ * forwarding stalls.
+ */
+ new_buff->dma = old_buff->dma;
+ new_buff->page = old_buff->page;
+ new_buff->page_offset = old_buff->page_offset;
+ new_buff->pagecnt_bias = old_buff->pagecnt_bias;
+}
+
+static inline bool igc_page_is_reserved(struct page *page)
+{
+ return (page_to_nid(page) != numa_mem_id()) || page_is_pfmemalloc(page);
+}
+
+static bool igc_can_reuse_rx_page(struct igc_rx_buffer *rx_buffer)
+{
+ unsigned int pagecnt_bias = rx_buffer->pagecnt_bias;
+ struct page *page = rx_buffer->page;
+
+ /* avoid re-using remote pages */
+ if (unlikely(igc_page_is_reserved(page)))
+ return false;
+
+#if (PAGE_SIZE < 8192)
+ /* if we are only owner of page we can reuse it */
+ if (unlikely((page_ref_count(page) - pagecnt_bias) > 1))
+ return false;
+#else
+#define IGC_LAST_OFFSET \
+ (SKB_WITH_OVERHEAD(PAGE_SIZE) - IGC_RXBUFFER_2048)
+
+ if (rx_buffer->page_offset > IGC_LAST_OFFSET)
+ return false;
+#endif
+
+ /* If we have drained the page fragment pool we need to update
+ * the pagecnt_bias and page count so that we fully restock the
+ * number of references the driver holds.
+ */
+ if (unlikely(!pagecnt_bias)) {
+ page_ref_add(page, USHRT_MAX);
+ rx_buffer->pagecnt_bias = USHRT_MAX;
+ }
+
+ return true;
+}
+
+/**
+ * igc_is_non_eop - process handling of non-EOP buffers
+ * @rx_ring: Rx ring being processed
+ * @rx_desc: Rx descriptor for current buffer
+ * @skb: current socket buffer containing buffer in progress
+ *
+ * This function updates next to clean. If the buffer is an EOP buffer
+ * this function exits returning false, otherwise it will place the
+ * sk_buff in the next buffer to be chained and return true indicating
+ * that this is in fact a non-EOP buffer.
+ */
+static bool igc_is_non_eop(struct igc_ring *rx_ring,
+ union igc_adv_rx_desc *rx_desc)
+{
+ u32 ntc = rx_ring->next_to_clean + 1;
+
+ /* fetch, update, and store next to clean */
+ ntc = (ntc < rx_ring->count) ? ntc : 0;
+ rx_ring->next_to_clean = ntc;
+
+ prefetch(IGC_RX_DESC(rx_ring, ntc));
+
+ if (likely(igc_test_staterr(rx_desc, IGC_RXD_STAT_EOP)))
+ return false;
+
+ return true;
+}
+
+/**
+ * igc_cleanup_headers - Correct corrupted or empty headers
+ * @rx_ring: rx descriptor ring packet is being transacted on
+ * @rx_desc: pointer to the EOP Rx descriptor
+ * @skb: pointer to current skb being fixed
+ *
+ * Address the case where we are pulling data in on pages only
+ * and as such no data is present in the skb header.
+ *
+ * In addition if skb is not at least 60 bytes we need to pad it so that
+ * it is large enough to qualify as a valid Ethernet frame.
+ *
+ * Returns true if an error was encountered and skb was freed.
+ */
+static bool igc_cleanup_headers(struct igc_ring *rx_ring,
+ union igc_adv_rx_desc *rx_desc,
+ struct sk_buff *skb)
+{
+ if (unlikely((igc_test_staterr(rx_desc,
+ IGC_RXDEXT_ERR_FRAME_ERR_MASK)))) {
+ struct net_device *netdev = rx_ring->netdev;
+
+ if (!(netdev->features & NETIF_F_RXALL)) {
+ dev_kfree_skb_any(skb);
+ return true;
+ }
+ }
+
+ /* if eth_skb_pad returns an error the skb was freed */
+ if (eth_skb_pad(skb))
+ return true;
+
+ return false;
+}
+
+static void igc_put_rx_buffer(struct igc_ring *rx_ring,
+ struct igc_rx_buffer *rx_buffer)
+{
+ if (igc_can_reuse_rx_page(rx_buffer)) {
+ /* hand second half of page back to the ring */
+ igc_reuse_rx_page(rx_ring, rx_buffer);
+ } else {
+ /* We are not reusing the buffer so unmap it and free
+ * any references we are holding to it
+ */
+ dma_unmap_page_attrs(rx_ring->dev, rx_buffer->dma,
+ igc_rx_pg_size(rx_ring), DMA_FROM_DEVICE,
+ IGC_RX_DMA_ATTR);
+ __page_frag_cache_drain(rx_buffer->page,
+ rx_buffer->pagecnt_bias);
+ }
+
+ /* clear contents of rx_buffer */
+ rx_buffer->page = NULL;
+}
+
+/**
+ * igc_alloc_rx_buffers - Replace used receive buffers; packet split
+ * @adapter: address of board private structure
+ */
+static void igc_alloc_rx_buffers(struct igc_ring *rx_ring, u16 cleaned_count)
+{
+ union igc_adv_rx_desc *rx_desc;
+ u16 i = rx_ring->next_to_use;
+ struct igc_rx_buffer *bi;
+ u16 bufsz;
+
+ /* nothing to do */
+ if (!cleaned_count)
+ return;
+
+ rx_desc = IGC_RX_DESC(rx_ring, i);
+ bi = &rx_ring->rx_buffer_info[i];
+ i -= rx_ring->count;
+
+ bufsz = igc_rx_bufsz(rx_ring);
+
+ do {
+ if (!igc_alloc_mapped_page(rx_ring, bi))
+ break;
+
+ /* sync the buffer for use by the device */
+ dma_sync_single_range_for_device(rx_ring->dev, bi->dma,
+ bi->page_offset, bufsz,
+ DMA_FROM_DEVICE);
+
+ /* Refresh the desc even if buffer_addrs didn't change
+ * because each write-back erases this info.
+ */
+ rx_desc->read.pkt_addr = cpu_to_le64(bi->dma + bi->page_offset);
+
+ rx_desc++;
+ bi++;
+ i++;
+ if (unlikely(!i)) {
+ rx_desc = IGC_RX_DESC(rx_ring, 0);
+ bi = rx_ring->rx_buffer_info;
+ i -= rx_ring->count;
+ }
+
+ /* clear the length for the next_to_use descriptor */
+ rx_desc->wb.upper.length = 0;
+
+ cleaned_count--;
+ } while (cleaned_count);
+
+ i += rx_ring->count;
+
+ if (rx_ring->next_to_use != i) {
+ /* record the next descriptor to use */
+ rx_ring->next_to_use = i;
+
+ /* update next to alloc since we have filled the ring */
+ rx_ring->next_to_alloc = 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, rx_ring->tail);
+ }
+}
+
+static int igc_clean_rx_irq(struct igc_q_vector *q_vector, const int budget)
+{
+ unsigned int total_bytes = 0, total_packets = 0;
+ struct igc_ring *rx_ring = q_vector->rx.ring;
+ struct sk_buff *skb = rx_ring->skb;
+ u16 cleaned_count = igc_desc_unused(rx_ring);
+
+ while (likely(total_packets < budget)) {
+ union igc_adv_rx_desc *rx_desc;
+ struct igc_rx_buffer *rx_buffer;
+ unsigned int size;
+
+ /* return some buffers to hardware, one at a time is too slow */
+ if (cleaned_count >= IGC_RX_BUFFER_WRITE) {
+ igc_alloc_rx_buffers(rx_ring, cleaned_count);
+ cleaned_count = 0;
+ }
+
+ rx_desc = IGC_RX_DESC(rx_ring, rx_ring->next_to_clean);
+ size = le16_to_cpu(rx_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();
+
+ rx_buffer = igc_get_rx_buffer(rx_ring, size);
+
+ /* retrieve a buffer from the ring */
+ if (skb)
+ igc_add_rx_frag(rx_ring, rx_buffer, skb, size);
+ else if (ring_uses_build_skb(rx_ring))
+ skb = igc_build_skb(rx_ring, rx_buffer, rx_desc, size);
+ else
+ skb = igc_construct_skb(rx_ring, rx_buffer,
+ rx_desc, size);
+
+ /* exit if we failed to retrieve a buffer */
+ if (!skb) {
+ rx_ring->rx_stats.alloc_failed++;
+ rx_buffer->pagecnt_bias++;
+ break;
+ }
+
+ igc_put_rx_buffer(rx_ring, rx_buffer);
+ cleaned_count++;
+
+ /* fetch next buffer in frame if non-eop */
+ if (igc_is_non_eop(rx_ring, rx_desc))
+ continue;
+
+ /* verify the packet layout is correct */
+ if (igc_cleanup_headers(rx_ring, rx_desc, skb)) {
+ skb = NULL;
+ continue;
+ }
+
+ /* probably a little skewed due to removing CRC */
+ total_bytes += skb->len;
+
+ /* populate checksum, timestamp, VLAN, and protocol */
+ igc_process_skb_fields(rx_ring, rx_desc, skb);
+
+ napi_gro_receive(&q_vector->napi, skb);
+
+ /* reset skb pointer */
+ skb = NULL;
+
+ /* update budget accounting */
+ total_packets++;
+ }
+
+ /* 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;
+
+ if (cleaned_count)
+ igc_alloc_rx_buffers(rx_ring, cleaned_count);
+
+ return total_packets;
+}
+
+static inline unsigned int igc_rx_offset(struct igc_ring *rx_ring)
+{
+ return ring_uses_build_skb(rx_ring) ? IGC_SKB_PAD : 0;
+}
+
+static bool igc_alloc_mapped_page(struct igc_ring *rx_ring,
+ struct igc_rx_buffer *bi)
+{
+ struct page *page = bi->page;
+ dma_addr_t dma;
+
+ /* since we are recycling buffers we should seldom need to alloc */
+ if (likely(page))
+ return true;
+
+ /* alloc new page for storage */
+ page = dev_alloc_pages(igc_rx_pg_order(rx_ring));
+ if (unlikely(!page)) {
+ rx_ring->rx_stats.alloc_failed++;
+ return false;
+ }
+
+ /* map page for use */
+ dma = dma_map_page_attrs(rx_ring->dev, page, 0,
+ igc_rx_pg_size(rx_ring),
+ DMA_FROM_DEVICE,
+ IGC_RX_DMA_ATTR);
+
+ /* if mapping failed free memory back to system since
+ * there isn't much point in holding memory we can't use
+ */
+ if (dma_mapping_error(rx_ring->dev, dma)) {
+ __free_page(page);
+
+ rx_ring->rx_stats.alloc_failed++;
+ return false;
+ }
+
+ bi->dma = dma;
+ bi->page = page;
+ bi->page_offset = igc_rx_offset(rx_ring);
+ bi->pagecnt_bias = 1;
+
+ return true;
+}
+
+/**
+ * igc_clean_tx_irq - Reclaim resources after transmit completes
+ * @q_vector: pointer to q_vector containing needed info
+ * @napi_budget: Used to determine if we are in netpoll
+ *
+ * returns true if ring is completely cleaned
+ */
+static bool igc_clean_tx_irq(struct igc_q_vector *q_vector, int napi_budget)
+{
+ struct igc_adapter *adapter = q_vector->adapter;
+ unsigned int total_bytes = 0, total_packets = 0;
+ unsigned int budget = q_vector->tx.work_limit;
+ struct igc_ring *tx_ring = q_vector->tx.ring;
+ unsigned int i = tx_ring->next_to_clean;
+ struct igc_tx_buffer *tx_buffer;
+ union igc_adv_tx_desc *tx_desc;
+
+ if (test_bit(__IGC_DOWN, &adapter->state))
+ return true;
+
+ tx_buffer = &tx_ring->tx_buffer_info[i];
+ tx_desc = IGC_TX_DESC(tx_ring, i);
+ i -= tx_ring->count;
+
+ do {
+ union igc_adv_tx_desc *eop_desc = tx_buffer->next_to_watch;
+
+ /* if next_to_watch is not set then there is no work pending */
+ if (!eop_desc)
+ break;
+
+ /* prevent any other reads prior to eop_desc */
+ smp_rmb();
+
+ /* if DD is not set pending work has not been completed */
+ if (!(eop_desc->wb.status & cpu_to_le32(IGC_TXD_STAT_DD)))
+ break;
+
+ /* clear next_to_watch to prevent false hangs */
+ tx_buffer->next_to_watch = NULL;
+
+ /* update the statistics for this packet */
+ total_bytes += tx_buffer->bytecount;
+ total_packets += tx_buffer->gso_segs;
+
+ /* free the 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);
+
+ /* clear last DMA location and unmap remaining buffers */
+ while (tx_desc != eop_desc) {
+ tx_buffer++;
+ tx_desc++;
+ i++;
+ if (unlikely(!i)) {
+ i -= tx_ring->count;
+ tx_buffer = tx_ring->tx_buffer_info;
+ tx_desc = IGC_TX_DESC(tx_ring, 0);
+ }
+
+ /* 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);
+ }
+ }
+
+ /* move us one more past the eop_desc for start of next pkt */
+ tx_buffer++;
+ tx_desc++;
+ i++;
+ if (unlikely(!i)) {
+ i -= tx_ring->count;
+ tx_buffer = tx_ring->tx_buffer_info;
+ tx_desc = IGC_TX_DESC(tx_ring, 0);
+ }
+
+ /* issue prefetch for next Tx descriptor */
+ prefetch(tx_desc);
+
+ /* update budget accounting */
+ budget--;
+ } while (likely(budget));
+
+ netdev_tx_completed_queue(txring_txq(tx_ring),
+ total_packets, total_bytes);
+
+ 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;
+
+ if (test_bit(IGC_RING_FLAG_TX_DETECT_HANG, &tx_ring->flags)) {
+ struct igc_hw *hw = &adapter->hw;
+
+ /* Detect a transmit hang in hardware, this serializes the
+ * check with the clearing of time_stamp and movement of i
+ */
+ clear_bit(IGC_RING_FLAG_TX_DETECT_HANG, &tx_ring->flags);
+ if (tx_buffer->next_to_watch &&
+ time_after(jiffies, tx_buffer->time_stamp +
+ (adapter->tx_timeout_factor * HZ)) &&
+ !(rd32(IGC_STATUS) & IGC_STATUS_TXOFF)) {
+ /* detected Tx unit hang */
+ dev_err(tx_ring->dev,
+ "Detected Tx Unit Hang\n"
+ " Tx Queue <%d>\n"
+ " TDH <%x>\n"
+ " TDT <%x>\n"
+ " next_to_use <%x>\n"
+ " next_to_clean <%x>\n"
+ "buffer_info[next_to_clean]\n"
+ " time_stamp <%lx>\n"
+ " next_to_watch <%p>\n"
+ " jiffies <%lx>\n"
+ " desc.status <%x>\n",
+ tx_ring->queue_index,
+ rd32(IGC_TDH(tx_ring->reg_idx)),
+ readl(tx_ring->tail),
+ tx_ring->next_to_use,
+ tx_ring->next_to_clean,
+ tx_buffer->time_stamp,
+ tx_buffer->next_to_watch,
+ jiffies,
+ tx_buffer->next_to_watch->wb.status);
+ netif_stop_subqueue(tx_ring->netdev,
+ tx_ring->queue_index);
+
+ /* we are about to reset, no point in enabling stuff */
+ return true;
+ }
+ }
+
+#define TX_WAKE_THRESHOLD (DESC_NEEDED * 2)
+ if (unlikely(total_packets &&
+ netif_carrier_ok(tx_ring->netdev) &&
+ igc_desc_unused(tx_ring) >= TX_WAKE_THRESHOLD)) {
+ /* Make sure that anybody stopping the queue after this
+ * sees the new next_to_clean.
+ */
+ smp_mb();
+ if (__netif_subqueue_stopped(tx_ring->netdev,
+ tx_ring->queue_index) &&
+ !(test_bit(__IGC_DOWN, &adapter->state))) {
+ netif_wake_subqueue(tx_ring->netdev,
+ tx_ring->queue_index);
+
+ u64_stats_update_begin(&tx_ring->tx_syncp);
+ tx_ring->tx_stats.restart_queue++;
+ u64_stats_update_end(&tx_ring->tx_syncp);
+ }
+ }
+
+ return !!budget;
+}
+
+/**
+ * igc_ioctl - I/O control method
+ * @netdev: network interface device structure
+ * @ifreq: frequency
+ * @cmd: command
+ */
+static int igc_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+ switch (cmd) {
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+/**
+ * igc_up - Open the interface and prepare it to handle traffic
+ * @adapter: board private structure
+ */
+static void igc_up(struct igc_adapter *adapter)
+{
+ struct igc_hw *hw = &adapter->hw;
+ int i = 0;
+
+ /* hardware has been reset, we need to reload some things */
+ igc_configure(adapter);
+
+ clear_bit(__IGC_DOWN, &adapter->state);
+
+ for (i = 0; i < adapter->num_q_vectors; i++)
+ napi_enable(&adapter->q_vector[i]->napi);
+
+ if (adapter->msix_entries)
+ igc_configure_msix(adapter);
+ else
+ igc_assign_vector(adapter->q_vector[0], 0);
+
+ /* Clear any pending interrupts. */
+ rd32(IGC_ICR);
+ igc_irq_enable(adapter);
+
+ netif_tx_start_all_queues(adapter->netdev);
+
+ /* start the watchdog. */
+ hw->mac.get_link_status = 1;
+ schedule_work(&adapter->watchdog_task);
+}
+
+/**
+ * igc_update_stats - Update the board statistics counters
+ * @adapter: board private structure
+ */
+static void igc_update_stats(struct igc_adapter *adapter)
+{
+}
+
+static void igc_nfc_filter_exit(struct igc_adapter *adapter)
+{
+}
+
+/**
+ * igc_down - Close the interface
+ * @adapter: board private structure
+ */
+static void igc_down(struct igc_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct igc_hw *hw = &adapter->hw;
+ u32 tctl, rctl;
+ int i = 0;
+
+ set_bit(__IGC_DOWN, &adapter->state);
+
+ /* disable receives in the hardware */
+ rctl = rd32(IGC_RCTL);
+ wr32(IGC_RCTL, rctl & ~IGC_RCTL_EN);
+ /* flush and sleep below */
+
+ igc_nfc_filter_exit(adapter);
+
+ /* set trans_start so we don't get spurious watchdogs during reset */
+ netif_trans_update(netdev);
+
+ netif_carrier_off(netdev);
+ netif_tx_stop_all_queues(netdev);
+
+ /* disable transmits in the hardware */
+ tctl = rd32(IGC_TCTL);
+ tctl &= ~IGC_TCTL_EN;
+ wr32(IGC_TCTL, tctl);
+ /* flush both disables and wait for them to finish */
+ wrfl();
+ usleep_range(10000, 20000);
+
+ igc_irq_disable(adapter);
+
+ adapter->flags &= ~IGC_FLAG_NEED_LINK_UPDATE;
+
+ for (i = 0; i < adapter->num_q_vectors; i++) {
+ if (adapter->q_vector[i]) {
+ napi_synchronize(&adapter->q_vector[i]->napi);
+ napi_disable(&adapter->q_vector[i]->napi);
+ }
+ }
+
+ del_timer_sync(&adapter->watchdog_timer);
+ del_timer_sync(&adapter->phy_info_timer);
+
+ /* record the stats before reset*/
+ spin_lock(&adapter->stats64_lock);
+ igc_update_stats(adapter);
+ spin_unlock(&adapter->stats64_lock);
+
+ adapter->link_speed = 0;
+ adapter->link_duplex = 0;
+
+ if (!pci_channel_offline(adapter->pdev))
+ igc_reset(adapter);
+
+ /* clear VLAN promisc flag so VFTA will be updated if necessary */
+ adapter->flags &= ~IGC_FLAG_VLAN_PROMISC;
+
+ igc_clean_all_tx_rings(adapter);
+ igc_clean_all_rx_rings(adapter);
+}
+
+static void igc_reinit_locked(struct igc_adapter *adapter)
+{
+ WARN_ON(in_interrupt());
+ while (test_and_set_bit(__IGC_RESETTING, &adapter->state))
+ usleep_range(1000, 2000);
+ igc_down(adapter);
+ igc_up(adapter);
+ clear_bit(__IGC_RESETTING, &adapter->state);
+}
+
+static void igc_reset_task(struct work_struct *work)
+{
+ struct igc_adapter *adapter;
+
+ adapter = container_of(work, struct igc_adapter, reset_task);
+
+ netdev_err(adapter->netdev, "Reset adapter\n");
+ igc_reinit_locked(adapter);
+}
+
+/**
+ * igc_change_mtu - Change the Maximum Transfer Unit
+ * @netdev: network interface device structure
+ * @new_mtu: new value for maximum frame size
+ *
+ * Returns 0 on success, negative on failure
+ */
+static int igc_change_mtu(struct net_device *netdev, int new_mtu)
+{
+ int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;
+ struct igc_adapter *adapter = netdev_priv(netdev);
+ struct pci_dev *pdev = adapter->pdev;
+
+ /* adjust max frame to be at least the size of a standard frame */
+ if (max_frame < (ETH_FRAME_LEN + ETH_FCS_LEN))
+ max_frame = ETH_FRAME_LEN + ETH_FCS_LEN;
+
+ while (test_and_set_bit(__IGC_RESETTING, &adapter->state))
+ usleep_range(1000, 2000);
+
+ /* igc_down has a dependency on max_frame_size */
+ adapter->max_frame_size = max_frame;
+
+ if (netif_running(netdev))
+ igc_down(adapter);
+
+ dev_info(&pdev->dev, "changing MTU from %d to %d\n",
+ netdev->mtu, new_mtu);
+ netdev->mtu = new_mtu;
+
+ if (netif_running(netdev))
+ igc_up(adapter);
+ else
+ igc_reset(adapter);
+
+ clear_bit(__IGC_RESETTING, &adapter->state);
+
+ return 0;
+}
+
+/**
+ * igc_get_stats - Get System Network Statistics
+ * @netdev: network interface device structure
+ *
+ * Returns the address of the device statistics structure.
+ * The statistics are updated here and also from the timer callback.
+ */
+static struct net_device_stats *igc_get_stats(struct net_device *netdev)
+{
+ struct igc_adapter *adapter = netdev_priv(netdev);
+
+ if (!test_bit(__IGC_RESETTING, &adapter->state))
+ igc_update_stats(adapter);
+
+ /* only return the current stats */
+ return &netdev->stats;
+}
+
+/**
+ * igc_configure - configure the hardware for RX and TX
+ * @adapter: private board structure
+ */
+static void igc_configure(struct igc_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ int i = 0;
+
+ igc_get_hw_control(adapter);
+ igc_set_rx_mode(netdev);
+
+ igc_setup_tctl(adapter);
+ igc_setup_mrqc(adapter);
+ igc_setup_rctl(adapter);
+
+ igc_configure_tx(adapter);
+ igc_configure_rx(adapter);
+
+ igc_rx_fifo_flush_base(&adapter->hw);
+
+ /* call igc_desc_unused which always leaves
+ * at least 1 descriptor unused to make sure
+ * next_to_use != next_to_clean
+ */
+ 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));
+ }
+}
+
+/**
+ * igc_rar_set_index - Sync RAL[index] and RAH[index] registers with MAC table
+ * @adapter: Pointer to adapter structure
+ * @index: Index of the RAR entry which need to be synced with MAC table
+ */
+static void igc_rar_set_index(struct igc_adapter *adapter, u32 index)
+{
+ u8 *addr = adapter->mac_table[index].addr;
+ struct igc_hw *hw = &adapter->hw;
+ u32 rar_low, rar_high;
+
+ /* HW expects these to be in network order when they are plugged
+ * into the registers which are little endian. In order to guarantee
+ * that ordering we need to do an leXX_to_cpup here in order to be
+ * ready for the byteswap that occurs with writel
+ */
+ rar_low = le32_to_cpup((__le32 *)(addr));
+ rar_high = le16_to_cpup((__le16 *)(addr + 4));
+
+ /* Indicate to hardware the Address is Valid. */
+ if (adapter->mac_table[index].state & IGC_MAC_STATE_IN_USE) {
+ if (is_valid_ether_addr(addr))
+ rar_high |= IGC_RAH_AV;
+
+ rar_high |= IGC_RAH_POOL_1 <<
+ adapter->mac_table[index].queue;
+ }
+
+ wr32(IGC_RAL(index), rar_low);
+ wrfl();
+ wr32(IGC_RAH(index), rar_high);
+ wrfl();
+}
+
+/* Set default MAC address for the PF in the first RAR entry */
+static void igc_set_default_mac_filter(struct igc_adapter *adapter)
+{
+ struct igc_mac_addr *mac_table = &adapter->mac_table[0];
+
+ ether_addr_copy(mac_table->addr, adapter->hw.mac.addr);
+ mac_table->state = IGC_MAC_STATE_DEFAULT | IGC_MAC_STATE_IN_USE;
+
+ igc_rar_set_index(adapter, 0);
+}
+
+/**
+ * igc_set_rx_mode - Secondary Unicast, Multicast and Promiscuous mode set
+ * @netdev: network interface device structure
+ *
+ * The set_rx_mode entry point is called whenever the unicast or multicast
+ * address lists or the network interface flags are updated. This routine is
+ * responsible for configuring the hardware for proper unicast, multicast,
+ * promiscuous mode, and all-multi behavior.
+ */
+static void igc_set_rx_mode(struct net_device *netdev)
+{
+}
+
+/**
+ * igc_msix_other - msix other interrupt handler
+ * @irq: interrupt number
+ * @data: pointer to a q_vector
+ */
+static irqreturn_t igc_msix_other(int irq, void *data)
+{
+ struct igc_adapter *adapter = data;
+ struct igc_hw *hw = &adapter->hw;
+ u32 icr = rd32(IGC_ICR);
+
+ /* reading ICR causes bit 31 of EICR to be cleared */
+ if (icr & IGC_ICR_DRSTA)
+ schedule_work(&adapter->reset_task);
+
+ if (icr & IGC_ICR_DOUTSYNC) {
+ /* HW is reporting DMA is out of sync */
+ adapter->stats.doosync++;
+ }
+
+ if (icr & IGC_ICR_LSC) {
+ hw->mac.get_link_status = 1;
+ /* guard against interrupt when we're going down */
+ if (!test_bit(__IGC_DOWN, &adapter->state))
+ mod_timer(&adapter->watchdog_timer, jiffies + 1);
+ }
+
+ wr32(IGC_EIMS, adapter->eims_other);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * igc_write_ivar - configure ivar for given MSI-X vector
+ * @hw: pointer to the HW structure
+ * @msix_vector: vector number we are allocating to a given ring
+ * @index: row index of IVAR register to write within IVAR table
+ * @offset: column offset of in IVAR, should be multiple of 8
+ *
+ * The IVAR table consists of 2 columns,
+ * each containing an cause allocation for an Rx and Tx ring, and a
+ * variable number of rows depending on the number of queues supported.
+ */
+static void igc_write_ivar(struct igc_hw *hw, int msix_vector,
+ int index, int offset)
+{
+ u32 ivar = array_rd32(IGC_IVAR0, index);
+
+ /* clear any bits that are currently set */
+ ivar &= ~((u32)0xFF << offset);
+
+ /* write vector and valid bit */
+ ivar |= (msix_vector | IGC_IVAR_VALID) << offset;
+
+ array_wr32(IGC_IVAR0, index, ivar);
+}
+
+static void igc_assign_vector(struct igc_q_vector *q_vector, int msix_vector)
+{
+ struct igc_adapter *adapter = q_vector->adapter;
+ struct igc_hw *hw = &adapter->hw;
+ int rx_queue = IGC_N0_QUEUE;
+ int tx_queue = IGC_N0_QUEUE;
+
+ if (q_vector->rx.ring)
+ rx_queue = q_vector->rx.ring->reg_idx;
+ if (q_vector->tx.ring)
+ tx_queue = q_vector->tx.ring->reg_idx;
+
+ switch (hw->mac.type) {
+ case igc_i225:
+ if (rx_queue > IGC_N0_QUEUE)
+ igc_write_ivar(hw, msix_vector,
+ rx_queue >> 1,
+ (rx_queue & 0x1) << 4);
+ if (tx_queue > IGC_N0_QUEUE)
+ igc_write_ivar(hw, msix_vector,
+ tx_queue >> 1,
+ ((tx_queue & 0x1) << 4) + 8);
+ q_vector->eims_value = BIT(msix_vector);
+ break;
+ default:
+ WARN_ONCE(hw->mac.type != igc_i225, "Wrong MAC type\n");
+ break;
+ }
+
+ /* add q_vector eims value to global eims_enable_mask */
+ adapter->eims_enable_mask |= q_vector->eims_value;
+
+ /* configure q_vector to set itr on first interrupt */
+ q_vector->set_itr = 1;
+}
+
+/**
+ * igc_configure_msix - Configure MSI-X hardware
+ * @adapter: Pointer to adapter structure
+ *
+ * igc_configure_msix sets up the hardware to properly
+ * generate MSI-X interrupts.
+ */
+static void igc_configure_msix(struct igc_adapter *adapter)
+{
+ struct igc_hw *hw = &adapter->hw;
+ int i, vector = 0;
+ u32 tmp;
+
+ adapter->eims_enable_mask = 0;
+
+ /* set vector for other causes, i.e. link changes */
+ switch (hw->mac.type) {
+ case igc_i225:
+ /* Turn on MSI-X capability first, or our settings
+ * won't stick. And it will take days to debug.
+ */
+ wr32(IGC_GPIE, IGC_GPIE_MSIX_MODE |
+ IGC_GPIE_PBA | IGC_GPIE_EIAME |
+ IGC_GPIE_NSICR);
+
+ /* enable msix_other interrupt */
+ adapter->eims_other = BIT(vector);
+ tmp = (vector++ | IGC_IVAR_VALID) << 8;
+
+ wr32(IGC_IVAR_MISC, tmp);
+ break;
+ default:
+ /* do nothing, since nothing else supports MSI-X */
+ break;
+ } /* switch (hw->mac.type) */
+
+ adapter->eims_enable_mask |= adapter->eims_other;
+
+ for (i = 0; i < adapter->num_q_vectors; i++)
+ igc_assign_vector(adapter->q_vector[i], vector++);
+
+ wrfl();
+}
+
+static irqreturn_t igc_msix_ring(int irq, void *data)
+{
+ struct igc_q_vector *q_vector = data;
+
+ /* Write the ITR value calculated from the previous interrupt. */
+ igc_write_itr(q_vector);
+
+ napi_schedule(&q_vector->napi);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * igc_request_msix - Initialize MSI-X interrupts
+ * @adapter: Pointer to adapter structure
+ *
+ * igc_request_msix allocates MSI-X vectors and requests interrupts from the
+ * kernel.
+ */
+static int igc_request_msix(struct igc_adapter *adapter)
+{
+ int i = 0, err = 0, vector = 0, free_vector = 0;
+ struct net_device *netdev = adapter->netdev;
+
+ err = request_irq(adapter->msix_entries[vector].vector,
+ &igc_msix_other, 0, netdev->name, adapter);
+ if (err)
+ goto err_out;
+
+ for (i = 0; i < adapter->num_q_vectors; i++) {
+ struct igc_q_vector *q_vector = adapter->q_vector[i];
+
+ vector++;
+
+ q_vector->itr_register = adapter->io_addr + IGC_EITR(vector);
+
+ if (q_vector->rx.ring && q_vector->tx.ring)
+ sprintf(q_vector->name, "%s-TxRx-%u", netdev->name,
+ q_vector->rx.ring->queue_index);
+ else if (q_vector->tx.ring)
+ sprintf(q_vector->name, "%s-tx-%u", netdev->name,
+ q_vector->tx.ring->queue_index);
+ else if (q_vector->rx.ring)
+ sprintf(q_vector->name, "%s-rx-%u", netdev->name,
+ q_vector->rx.ring->queue_index);
+ else
+ sprintf(q_vector->name, "%s-unused", netdev->name);
+
+ err = request_irq(adapter->msix_entries[vector].vector,
+ igc_msix_ring, 0, q_vector->name,
+ q_vector);
+ if (err)
+ goto err_free;
+ }
+
+ igc_configure_msix(adapter);
+ return 0;
+
+err_free:
+ /* free already assigned IRQs */
+ free_irq(adapter->msix_entries[free_vector++].vector, adapter);
+
+ vector--;
+ for (i = 0; i < vector; i++) {
+ free_irq(adapter->msix_entries[free_vector++].vector,
+ adapter->q_vector[i]);
+ }
+err_out:
+ return err;
+}
+
+/**
+ * igc_reset_q_vector - Reset config for interrupt vector
+ * @adapter: board private structure to initialize
+ * @v_idx: Index of vector to be reset
+ *
+ * If NAPI is enabled it will delete any references to the
+ * NAPI struct. This is preparation for igc_free_q_vector.
+ */
+static void igc_reset_q_vector(struct igc_adapter *adapter, int v_idx)
+{
+ struct igc_q_vector *q_vector = adapter->q_vector[v_idx];
+
+ /* if we're coming from igc_set_interrupt_capability, the vectors are
+ * not yet allocated
+ */
+ if (!q_vector)
+ return;
+
+ if (q_vector->tx.ring)
+ adapter->tx_ring[q_vector->tx.ring->queue_index] = NULL;
+
+ if (q_vector->rx.ring)
+ adapter->rx_ring[q_vector->rx.ring->queue_index] = NULL;
+
+ netif_napi_del(&q_vector->napi);
+}
+
+static void igc_reset_interrupt_capability(struct igc_adapter *adapter)
+{
+ int v_idx = adapter->num_q_vectors;
+
+ if (adapter->msix_entries) {
+ pci_disable_msix(adapter->pdev);
+ kfree(adapter->msix_entries);
+ adapter->msix_entries = NULL;
+ } else if (adapter->flags & IGC_FLAG_HAS_MSI) {
+ pci_disable_msi(adapter->pdev);
+ }
+
+ while (v_idx--)
+ igc_reset_q_vector(adapter, v_idx);
+}
+
+/**
+ * igc_clear_interrupt_scheme - reset the device to a state of no interrupts
+ * @adapter: Pointer to adapter structure
+ *
+ * This function resets the device so that it has 0 rx queues, tx queues, and
+ * MSI-X interrupts allocated.
+ */
+static void igc_clear_interrupt_scheme(struct igc_adapter *adapter)
+{
+ igc_free_q_vectors(adapter);
+ igc_reset_interrupt_capability(adapter);
+}
+
+/**
+ * igc_free_q_vectors - Free memory allocated for interrupt vectors
+ * @adapter: board private structure to initialize
+ *
+ * This function frees the memory allocated to the q_vectors. In addition if
+ * NAPI is enabled it will delete any references to the NAPI struct prior
+ * to freeing the q_vector.
+ */
+static void igc_free_q_vectors(struct igc_adapter *adapter)
+{
+ int v_idx = adapter->num_q_vectors;
+
+ adapter->num_tx_queues = 0;
+ adapter->num_rx_queues = 0;
+ adapter->num_q_vectors = 0;
+
+ while (v_idx--) {
+ igc_reset_q_vector(adapter, v_idx);
+ igc_free_q_vector(adapter, v_idx);
+ }
+}
+
+/**
+ * igc_free_q_vector - Free memory allocated for specific interrupt vector
+ * @adapter: board private structure to initialize
+ * @v_idx: Index of vector to be freed
+ *
+ * This function frees the memory allocated to the q_vector.
+ */
+static void igc_free_q_vector(struct igc_adapter *adapter, int v_idx)
+{
+ struct igc_q_vector *q_vector = adapter->q_vector[v_idx];
+
+ adapter->q_vector[v_idx] = NULL;
+
+ /* igc_get_stats64() might access the rings on this vector,
+ * we must wait a grace period before freeing it.
+ */
+ if (q_vector)
+ kfree_rcu(q_vector, rcu);
+}
+
+/* Need to wait a few seconds after link up to get diagnostic information from
+ * the phy
+ */
+static void igc_update_phy_info(struct timer_list *t)
+{
+ struct igc_adapter *adapter = from_timer(adapter, t, phy_info_timer);
+
+ igc_get_phy_info(&adapter->hw);
+}
+
+/**
+ * igc_has_link - check shared code for link and determine up/down
+ * @adapter: pointer to driver private info
+ */
+static bool igc_has_link(struct igc_adapter *adapter)
+{
+ struct igc_hw *hw = &adapter->hw;
+ bool link_active = false;
+
+ /* get_link_status is set on LSC (link status) interrupt or
+ * rx sequence error interrupt. get_link_status will stay
+ * false until the igc_check_for_link establishes link
+ * for copper adapters ONLY
+ */
+ switch (hw->phy.media_type) {
+ case igc_media_type_copper:
+ if (!hw->mac.get_link_status)
+ return true;
+ hw->mac.ops.check_for_link(hw);
+ link_active = !hw->mac.get_link_status;
+ break;
+ default:
+ case igc_media_type_unknown:
+ break;
+ }
+
+ if (hw->mac.type == igc_i225 &&
+ hw->phy.id == I225_I_PHY_ID) {
+ if (!netif_carrier_ok(adapter->netdev)) {
+ adapter->flags &= ~IGC_FLAG_NEED_LINK_UPDATE;
+ } else if (!(adapter->flags & IGC_FLAG_NEED_LINK_UPDATE)) {
+ adapter->flags |= IGC_FLAG_NEED_LINK_UPDATE;
+ adapter->link_check_timeout = jiffies;
+ }
+ }
+
+ return link_active;
+}
+
+/**
+ * igc_watchdog - Timer Call-back
+ * @data: pointer to adapter cast into an unsigned long
+ */
+static void igc_watchdog(struct timer_list *t)
+{
+ struct igc_adapter *adapter = from_timer(adapter, t, watchdog_timer);
+ /* Do the rest outside of interrupt context */
+ schedule_work(&adapter->watchdog_task);
+}
+
+static void igc_watchdog_task(struct work_struct *work)
+{
+ struct igc_adapter *adapter = container_of(work,
+ struct igc_adapter,
+ watchdog_task);
+ struct net_device *netdev = adapter->netdev;
+ struct igc_hw *hw = &adapter->hw;
+ struct igc_phy_info *phy = &hw->phy;
+ u16 phy_data, retry_count = 20;
+ u32 connsw;
+ u32 link;
+ int i;
+
+ link = igc_has_link(adapter);
+
+ if (adapter->flags & IGC_FLAG_NEED_LINK_UPDATE) {
+ if (time_after(jiffies, (adapter->link_check_timeout + HZ)))
+ adapter->flags &= ~IGC_FLAG_NEED_LINK_UPDATE;
+ else
+ link = false;
+ }
+
+ /* Force link down if we have fiber to swap to */
+ if (adapter->flags & IGC_FLAG_MAS_ENABLE) {
+ if (hw->phy.media_type == igc_media_type_copper) {
+ connsw = rd32(IGC_CONNSW);
+ if (!(connsw & IGC_CONNSW_AUTOSENSE_EN))
+ link = 0;
+ }
+ }
+ if (link) {
+ if (!netif_carrier_ok(netdev)) {
+ u32 ctrl;
+
+ hw->mac.ops.get_speed_and_duplex(hw,
+ &adapter->link_speed,
+ &adapter->link_duplex);
+
+ ctrl = rd32(IGC_CTRL);
+ /* Link status message must follow this format */
+ netdev_info(netdev,
+ "igc: %s NIC Link is Up %d Mbps %s Duplex, Flow Control: %s\n",
+ netdev->name,
+ adapter->link_speed,
+ adapter->link_duplex == FULL_DUPLEX ?
+ "Full" : "Half",
+ (ctrl & IGC_CTRL_TFCE) &&
+ (ctrl & IGC_CTRL_RFCE) ? "RX/TX" :
+ (ctrl & IGC_CTRL_RFCE) ? "RX" :
+ (ctrl & IGC_CTRL_TFCE) ? "TX" : "None");
+
+ /* check if SmartSpeed worked */
+ igc_check_downshift(hw);
+ if (phy->speed_downgraded)
+ netdev_warn(netdev, "Link Speed was downgraded by SmartSpeed\n");
+
+ /* adjust timeout factor according to speed/duplex */
+ adapter->tx_timeout_factor = 1;
+ switch (adapter->link_speed) {
+ case SPEED_10:
+ adapter->tx_timeout_factor = 14;
+ break;
+ case SPEED_100:
+ /* maybe add some timeout factor ? */
+ break;
+ }
+
+ if (adapter->link_speed != SPEED_1000)
+ goto no_wait;
+
+ /* wait for Remote receiver status OK */
+retry_read_status:
+ if (!igc_read_phy_reg(hw, PHY_1000T_STATUS,
+ &phy_data)) {
+ if (!(phy_data & SR_1000T_REMOTE_RX_STATUS) &&
+ retry_count) {
+ msleep(100);
+ retry_count--;
+ goto retry_read_status;
+ } else if (!retry_count) {
+ dev_err(&adapter->pdev->dev, "exceed max 2 second\n");
+ }
+ } else {
+ dev_err(&adapter->pdev->dev, "read 1000Base-T Status Reg\n");
+ }
+no_wait:
+ netif_carrier_on(netdev);
+
+ /* link state has changed, schedule phy info update */
+ if (!test_bit(__IGC_DOWN, &adapter->state))
+ mod_timer(&adapter->phy_info_timer,
+ round_jiffies(jiffies + 2 * HZ));
+ }
+ } else {
+ if (netif_carrier_ok(netdev)) {
+ adapter->link_speed = 0;
+ adapter->link_duplex = 0;
+
+ /* Links status message must follow this format */
+ netdev_info(netdev, "igc: %s NIC Link is Down\n",
+ netdev->name);
+ netif_carrier_off(netdev);
+
+ /* link state has changed, schedule phy info update */
+ if (!test_bit(__IGC_DOWN, &adapter->state))
+ mod_timer(&adapter->phy_info_timer,
+ round_jiffies(jiffies + 2 * HZ));
+
+ /* link is down, time to check for alternate media */
+ if (adapter->flags & IGC_FLAG_MAS_ENABLE) {
+ if (adapter->flags & IGC_FLAG_MEDIA_RESET) {
+ schedule_work(&adapter->reset_task);
+ /* return immediately */
+ return;
+ }
+ }
+
+ /* also check for alternate media here */
+ } else if (!netif_carrier_ok(netdev) &&
+ (adapter->flags & IGC_FLAG_MAS_ENABLE)) {
+ if (adapter->flags & IGC_FLAG_MEDIA_RESET) {
+ schedule_work(&adapter->reset_task);
+ /* return immediately */
+ return;
+ }
+ }
+ }
+
+ spin_lock(&adapter->stats64_lock);
+ igc_update_stats(adapter);
+ spin_unlock(&adapter->stats64_lock);
+
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ struct igc_ring *tx_ring = adapter->tx_ring[i];
+
+ if (!netif_carrier_ok(netdev)) {
+ /* We've lost link, so the controller stops DMA,
+ * but we've got queued Tx work that's never going
+ * to get done, so reset controller to flush Tx.
+ * (Do the reset outside of interrupt context).
+ */
+ if (igc_desc_unused(tx_ring) + 1 < tx_ring->count) {
+ adapter->tx_timeout_count++;
+ schedule_work(&adapter->reset_task);
+ /* return immediately since reset is imminent */
+ return;
+ }
+ }
+
+ /* Force detection of hung controller every watchdog period */
+ set_bit(IGC_RING_FLAG_TX_DETECT_HANG, &tx_ring->flags);
+ }
+
+ /* Cause software interrupt to ensure Rx ring is cleaned */
+ if (adapter->flags & IGC_FLAG_HAS_MSIX) {
+ u32 eics = 0;
+
+ for (i = 0; i < adapter->num_q_vectors; i++)
+ eics |= adapter->q_vector[i]->eims_value;
+ wr32(IGC_EICS, eics);
+ } else {
+ wr32(IGC_ICS, IGC_ICS_RXDMT0);
+ }
+
+ /* Reset the timer */
+ if (!test_bit(__IGC_DOWN, &adapter->state)) {
+ if (adapter->flags & IGC_FLAG_NEED_LINK_UPDATE)
+ mod_timer(&adapter->watchdog_timer,
+ round_jiffies(jiffies + HZ));
+ else
+ mod_timer(&adapter->watchdog_timer,
+ round_jiffies(jiffies + 2 * HZ));
+ }
+}
+
+/**
+ * igc_update_ring_itr - update the dynamic ITR value based on packet size
+ * @q_vector: pointer to q_vector
+ *
+ * Stores a new ITR value based on strictly on packet size. This
+ * algorithm is less sophisticated than that used in igc_update_itr,
+ * due to the difficulty of synchronizing statistics across multiple
+ * receive rings. The divisors and thresholds used by this function
+ * were determined based on theoretical maximum wire speed and testing
+ * data, in order to minimize response time while increasing bulk
+ * throughput.
+ * NOTE: This function is called only when operating in a multiqueue
+ * receive environment.
+ */
+static void igc_update_ring_itr(struct igc_q_vector *q_vector)
+{
+ struct igc_adapter *adapter = q_vector->adapter;
+ int new_val = q_vector->itr_val;
+ int avg_wire_size = 0;
+ unsigned int packets;
+
+ /* For non-gigabit speeds, just fix the interrupt rate at 4000
+ * ints/sec - ITR timer value of 120 ticks.
+ */
+ switch (adapter->link_speed) {
+ case SPEED_10:
+ case SPEED_100:
+ new_val = IGC_4K_ITR;
+ goto set_itr_val;
+ default:
+ break;
+ }
+
+ packets = q_vector->rx.total_packets;
+ if (packets)
+ avg_wire_size = q_vector->rx.total_bytes / packets;
+
+ packets = q_vector->tx.total_packets;
+ if (packets)
+ avg_wire_size = max_t(u32, avg_wire_size,
+ q_vector->tx.total_bytes / packets);
+
+ /* if avg_wire_size isn't set no work was done */
+ if (!avg_wire_size)
+ goto clear_counts;
+
+ /* Add 24 bytes to size to account for CRC, preamble, and gap */
+ avg_wire_size += 24;
+
+ /* Don't starve jumbo frames */
+ avg_wire_size = min(avg_wire_size, 3000);
+
+ /* Give a little boost to mid-size frames */
+ if (avg_wire_size > 300 && avg_wire_size < 1200)
+ new_val = avg_wire_size / 3;
+ else
+ new_val = avg_wire_size / 2;
+
+ /* conservative mode (itr 3) eliminates the lowest_latency setting */
+ if (new_val < IGC_20K_ITR &&
+ ((q_vector->rx.ring && adapter->rx_itr_setting == 3) ||
+ (!q_vector->rx.ring && adapter->tx_itr_setting == 3)))
+ new_val = IGC_20K_ITR;
+
+set_itr_val:
+ if (new_val != q_vector->itr_val) {
+ q_vector->itr_val = new_val;
+ q_vector->set_itr = 1;
+ }
+clear_counts:
+ q_vector->rx.total_bytes = 0;
+ q_vector->rx.total_packets = 0;
+ q_vector->tx.total_bytes = 0;
+ q_vector->tx.total_packets = 0;
+}
+
+/**
+ * igc_update_itr - update the dynamic ITR value based on statistics
+ * @q_vector: pointer to q_vector
+ * @ring_container: ring info to update the itr for
+ *
+ * Stores a new ITR value based on packets and byte
+ * counts during the last interrupt. The advantage of per interrupt
+ * computation is faster updates and more accurate ITR for the current
+ * traffic pattern. Constants in this function were computed
+ * based on theoretical maximum wire speed and thresholds were set based
+ * on testing data as well as attempting to minimize response time
+ * while increasing bulk throughput.
+ * NOTE: These calculations are only valid when operating in a single-
+ * queue environment.
+ */
+static void igc_update_itr(struct igc_q_vector *q_vector,
+ struct igc_ring_container *ring_container)
+{
+ unsigned int packets = ring_container->total_packets;
+ unsigned int bytes = ring_container->total_bytes;
+ u8 itrval = ring_container->itr;
+
+ /* no packets, exit with status unchanged */
+ if (packets == 0)
+ return;
+
+ switch (itrval) {
+ case lowest_latency:
+ /* handle TSO and jumbo frames */
+ if (bytes / packets > 8000)
+ itrval = bulk_latency;
+ else if ((packets < 5) && (bytes > 512))
+ itrval = low_latency;
+ break;
+ case low_latency: /* 50 usec aka 20000 ints/s */
+ if (bytes > 10000) {
+ /* this if handles the TSO accounting */
+ if (bytes / packets > 8000)
+ itrval = bulk_latency;
+ else if ((packets < 10) || ((bytes / packets) > 1200))
+ itrval = bulk_latency;
+ else if ((packets > 35))
+ itrval = lowest_latency;
+ } else if (bytes / packets > 2000) {
+ itrval = bulk_latency;
+ } else if (packets <= 2 && bytes < 512) {
+ itrval = lowest_latency;
+ }
+ break;
+ case bulk_latency: /* 250 usec aka 4000 ints/s */
+ if (bytes > 25000) {
+ if (packets > 35)
+ itrval = low_latency;
+ } else if (bytes < 1500) {
+ itrval = low_latency;
+ }
+ break;
+ }
+
+ /* clear work counters since we have the values we need */
+ ring_container->total_bytes = 0;
+ ring_container->total_packets = 0;
+
+ /* write updated itr to ring container */
+ ring_container->itr = itrval;
+}
+
+/**
+ * igc_intr_msi - Interrupt Handler
+ * @irq: interrupt number
+ * @data: pointer to a network interface device structure
+ */
+static irqreturn_t igc_intr_msi(int irq, void *data)
+{
+ struct igc_adapter *adapter = data;
+ struct igc_q_vector *q_vector = adapter->q_vector[0];
+ struct igc_hw *hw = &adapter->hw;
+ /* read ICR disables interrupts using IAM */
+ u32 icr = rd32(IGC_ICR);
+
+ igc_write_itr(q_vector);
+
+ if (icr & IGC_ICR_DRSTA)
+ schedule_work(&adapter->reset_task);
+
+ if (icr & IGC_ICR_DOUTSYNC) {
+ /* HW is reporting DMA is out of sync */
+ adapter->stats.doosync++;
+ }
+
+ if (icr & (IGC_ICR_RXSEQ | IGC_ICR_LSC)) {
+ hw->mac.get_link_status = 1;
+ if (!test_bit(__IGC_DOWN, &adapter->state))
+ mod_timer(&adapter->watchdog_timer, jiffies + 1);
+ }
+
+ napi_schedule(&q_vector->napi);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * igc_intr - Legacy Interrupt Handler
+ * @irq: interrupt number
+ * @data: pointer to a network interface device structure
+ */
+static irqreturn_t igc_intr(int irq, void *data)
+{
+ struct igc_adapter *adapter = data;
+ struct igc_q_vector *q_vector = adapter->q_vector[0];
+ struct igc_hw *hw = &adapter->hw;
+ /* Interrupt Auto-Mask...upon reading ICR, interrupts are masked. No
+ * need for the IMC write
+ */
+ u32 icr = rd32(IGC_ICR);
+
+ /* IMS will not auto-mask if INT_ASSERTED is not set, and if it is
+ * not set, then the adapter didn't send an interrupt
+ */
+ if (!(icr & IGC_ICR_INT_ASSERTED))
+ return IRQ_NONE;
+
+ igc_write_itr(q_vector);
+
+ if (icr & IGC_ICR_DRSTA)
+ schedule_work(&adapter->reset_task);
+
+ if (icr & IGC_ICR_DOUTSYNC) {
+ /* HW is reporting DMA is out of sync */
+ adapter->stats.doosync++;
+ }
+
+ if (icr & (IGC_ICR_RXSEQ | IGC_ICR_LSC)) {
+ hw->mac.get_link_status = 1;
+ /* guard against interrupt when we're going down */
+ if (!test_bit(__IGC_DOWN, &adapter->state))
+ mod_timer(&adapter->watchdog_timer, jiffies + 1);
+ }
+
+ napi_schedule(&q_vector->napi);
+
+ return IRQ_HANDLED;
+}
+
+static void igc_set_itr(struct igc_q_vector *q_vector)
+{
+ struct igc_adapter *adapter = q_vector->adapter;
+ u32 new_itr = q_vector->itr_val;
+ u8 current_itr = 0;
+
+ /* for non-gigabit speeds, just fix the interrupt rate at 4000 */
+ switch (adapter->link_speed) {
+ case SPEED_10:
+ case SPEED_100:
+ current_itr = 0;
+ new_itr = IGC_4K_ITR;
+ goto set_itr_now;
+ default:
+ break;
+ }
+
+ igc_update_itr(q_vector, &q_vector->tx);
+ igc_update_itr(q_vector, &q_vector->rx);
+
+ current_itr = max(q_vector->rx.itr, q_vector->tx.itr);
+
+ /* conservative mode (itr 3) eliminates the lowest_latency setting */
+ if (current_itr == lowest_latency &&
+ ((q_vector->rx.ring && adapter->rx_itr_setting == 3) ||
+ (!q_vector->rx.ring && adapter->tx_itr_setting == 3)))
+ current_itr = low_latency;
+
+ switch (current_itr) {
+ /* counts and packets in update_itr are dependent on these numbers */
+ case lowest_latency:
+ new_itr = IGC_70K_ITR; /* 70,000 ints/sec */
+ break;
+ case low_latency:
+ new_itr = IGC_20K_ITR; /* 20,000 ints/sec */
+ break;
+ case bulk_latency:
+ new_itr = IGC_4K_ITR; /* 4,000 ints/sec */
+ break;
+ default:
+ break;
+ }
+
+set_itr_now:
+ if (new_itr != q_vector->itr_val) {
+ /* this attempts to bias the interrupt rate towards Bulk
+ * by adding intermediate steps when interrupt rate is
+ * increasing
+ */
+ new_itr = new_itr > q_vector->itr_val ?
+ max((new_itr * q_vector->itr_val) /
+ (new_itr + (q_vector->itr_val >> 2)),
+ new_itr) : new_itr;
+ /* Don't write the value here; it resets the adapter's
+ * internal timer, and causes us to delay far longer than
+ * we should between interrupts. Instead, we write the ITR
+ * value at the beginning of the next interrupt so the timing
+ * ends up being correct.
+ */
+ q_vector->itr_val = new_itr;
+ q_vector->set_itr = 1;
+ }
+}
+
+static void igc_ring_irq_enable(struct igc_q_vector *q_vector)
+{
+ struct igc_adapter *adapter = q_vector->adapter;
+ struct igc_hw *hw = &adapter->hw;
+
+ if ((q_vector->rx.ring && (adapter->rx_itr_setting & 3)) ||
+ (!q_vector->rx.ring && (adapter->tx_itr_setting & 3))) {
+ if (adapter->num_q_vectors == 1)
+ igc_set_itr(q_vector);
+ else
+ igc_update_ring_itr(q_vector);
+ }
+
+ if (!test_bit(__IGC_DOWN, &adapter->state)) {
+ if (adapter->msix_entries)
+ wr32(IGC_EIMS, q_vector->eims_value);
+ else
+ igc_irq_enable(adapter);
+ }
+}
+
+/**
+ * igc_poll - NAPI Rx polling callback
+ * @napi: napi polling structure
+ * @budget: count of how many packets we should handle
+ */
+static int igc_poll(struct napi_struct *napi, int budget)
+{
+ struct igc_q_vector *q_vector = container_of(napi,
+ struct igc_q_vector,
+ napi);
+ 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);
+
+ work_done += cleaned;
+ if (cleaned >= budget)
+ clean_complete = false;
+ }
+
+ /* If all work not completed, return budget and keep polling */
+ if (!clean_complete)
+ return budget;
+
+ /* If not enough Rx work done, exit the polling mode */
+ napi_complete_done(napi, work_done);
+ igc_ring_irq_enable(q_vector);
+
+ return 0;
+}
+
+/**
+ * igc_set_interrupt_capability - set MSI or MSI-X if supported
+ * @adapter: Pointer to adapter structure
+ *
+ * Attempt to configure interrupts using the best available
+ * capabilities of the hardware and kernel.
+ */
+static void igc_set_interrupt_capability(struct igc_adapter *adapter,
+ bool msix)
+{
+ int numvecs, i;
+ int err;
+
+ if (!msix)
+ goto msi_only;
+ adapter->flags |= IGC_FLAG_HAS_MSIX;
+
+ /* Number of supported queues. */
+ adapter->num_rx_queues = adapter->rss_queues;
+
+ adapter->num_tx_queues = adapter->rss_queues;
+
+ /* start with one vector for every Rx queue */
+ numvecs = adapter->num_rx_queues;
+
+ /* if Tx handler is separate add 1 for every Tx queue */
+ if (!(adapter->flags & IGC_FLAG_QUEUE_PAIRS))
+ numvecs += adapter->num_tx_queues;
+
+ /* store the number of vectors reserved for queues */
+ adapter->num_q_vectors = numvecs;
+
+ /* add 1 vector for link status interrupts */
+ numvecs++;
+
+ adapter->msix_entries = kcalloc(numvecs, sizeof(struct msix_entry),
+ GFP_KERNEL);
+
+ if (!adapter->msix_entries)
+ return;
+
+ /* populate entry values */
+ for (i = 0; i < numvecs; i++)
+ adapter->msix_entries[i].entry = i;
+
+ err = pci_enable_msix_range(adapter->pdev,
+ adapter->msix_entries,
+ numvecs,
+ numvecs);
+ if (err > 0)
+ return;
+
+ kfree(adapter->msix_entries);
+ adapter->msix_entries = NULL;
+
+ igc_reset_interrupt_capability(adapter);
+
+msi_only:
+ adapter->flags &= ~IGC_FLAG_HAS_MSIX;
+
+ adapter->rss_queues = 1;
+ adapter->flags |= IGC_FLAG_QUEUE_PAIRS;
+ adapter->num_rx_queues = 1;
+ adapter->num_tx_queues = 1;
+ adapter->num_q_vectors = 1;
+ if (!pci_enable_msi(adapter->pdev))
+ adapter->flags |= IGC_FLAG_HAS_MSI;
+}
+
+static void igc_add_ring(struct igc_ring *ring,
+ struct igc_ring_container *head)
+{
+ head->ring = ring;
+ head->count++;
+}
+
+/**
+ * igc_alloc_q_vector - Allocate memory for a single interrupt vector
+ * @adapter: board private structure to initialize
+ * @v_count: q_vectors allocated on adapter, used for ring interleaving
+ * @v_idx: index of vector in adapter struct
+ * @txr_count: total number of Tx rings to allocate
+ * @txr_idx: index of first Tx ring to allocate
+ * @rxr_count: total number of Rx rings to allocate
+ * @rxr_idx: index of first Rx ring to allocate
+ *
+ * We allocate one q_vector. If allocation fails we return -ENOMEM.
+ */
+static int igc_alloc_q_vector(struct igc_adapter *adapter,
+ unsigned int v_count, unsigned int v_idx,
+ unsigned int txr_count, unsigned int txr_idx,
+ unsigned int rxr_count, unsigned int rxr_idx)
+{
+ struct igc_q_vector *q_vector;
+ struct igc_ring *ring;
+ int ring_count, size;
+
+ /* igc only supports 1 Tx and/or 1 Rx queue per vector */
+ if (txr_count > 1 || rxr_count > 1)
+ return -ENOMEM;
+
+ ring_count = txr_count + rxr_count;
+ size = sizeof(struct igc_q_vector) +
+ (sizeof(struct igc_ring) * ring_count);
+
+ /* allocate q_vector and rings */
+ q_vector = adapter->q_vector[v_idx];
+ if (!q_vector)
+ q_vector = kzalloc(size, GFP_KERNEL);
+ else
+ memset(q_vector, 0, size);
+ if (!q_vector)
+ return -ENOMEM;
+
+ /* initialize NAPI */
+ netif_napi_add(adapter->netdev, &q_vector->napi,
+ igc_poll, 64);
+
+ /* tie q_vector and adapter together */
+ adapter->q_vector[v_idx] = q_vector;
+ q_vector->adapter = adapter;
+
+ /* initialize work limits */
+ q_vector->tx.work_limit = adapter->tx_work_limit;
+
+ /* initialize ITR configuration */
+ q_vector->itr_register = adapter->io_addr + IGC_EITR(0);
+ q_vector->itr_val = IGC_START_ITR;
+
+ /* initialize pointer to rings */
+ ring = q_vector->ring;
+
+ /* initialize ITR */
+ if (rxr_count) {
+ /* rx or rx/tx vector */
+ if (!adapter->rx_itr_setting || adapter->rx_itr_setting > 3)
+ q_vector->itr_val = adapter->rx_itr_setting;
+ } else {
+ /* tx only vector */
+ if (!adapter->tx_itr_setting || adapter->tx_itr_setting > 3)
+ q_vector->itr_val = adapter->tx_itr_setting;
+ }
+
+ if (txr_count) {
+ /* assign generic ring traits */
+ ring->dev = &adapter->pdev->dev;
+ ring->netdev = adapter->netdev;
+
+ /* configure backlink on ring */
+ ring->q_vector = q_vector;
+
+ /* update q_vector Tx values */
+ igc_add_ring(ring, &q_vector->tx);
+
+ /* apply Tx specific ring traits */
+ ring->count = adapter->tx_ring_count;
+ ring->queue_index = txr_idx;
+
+ /* assign ring to adapter */
+ adapter->tx_ring[txr_idx] = ring;
+
+ /* push pointer to next ring */
+ ring++;
+ }
+
+ if (rxr_count) {
+ /* assign generic ring traits */
+ ring->dev = &adapter->pdev->dev;
+ ring->netdev = adapter->netdev;
+
+ /* configure backlink on ring */
+ ring->q_vector = q_vector;
+
+ /* update q_vector Rx values */
+ igc_add_ring(ring, &q_vector->rx);
+
+ /* apply Rx specific ring traits */
+ ring->count = adapter->rx_ring_count;
+ ring->queue_index = rxr_idx;
+
+ /* assign ring to adapter */
+ adapter->rx_ring[rxr_idx] = ring;
+ }
+
+ return 0;
+}
+
+/**
+ * igc_alloc_q_vectors - Allocate memory for interrupt vectors
+ * @adapter: board private structure to initialize
+ *
+ * We allocate one q_vector per queue interrupt. If allocation fails we
+ * return -ENOMEM.
+ */
+static int igc_alloc_q_vectors(struct igc_adapter *adapter)
+{
+ int rxr_remaining = adapter->num_rx_queues;
+ int txr_remaining = adapter->num_tx_queues;
+ int rxr_idx = 0, txr_idx = 0, v_idx = 0;
+ int q_vectors = adapter->num_q_vectors;
+ int err;
+
+ if (q_vectors >= (rxr_remaining + txr_remaining)) {
+ for (; rxr_remaining; v_idx++) {
+ err = igc_alloc_q_vector(adapter, q_vectors, v_idx,
+ 0, 0, 1, rxr_idx);
+
+ if (err)
+ goto err_out;
+
+ /* update counts and index */
+ rxr_remaining--;
+ rxr_idx++;
+ }
+ }
+
+ for (; v_idx < q_vectors; v_idx++) {
+ int rqpv = DIV_ROUND_UP(rxr_remaining, q_vectors - v_idx);
+ int tqpv = DIV_ROUND_UP(txr_remaining, q_vectors - v_idx);
+
+ err = igc_alloc_q_vector(adapter, q_vectors, v_idx,
+ tqpv, txr_idx, rqpv, rxr_idx);
+
+ if (err)
+ goto err_out;
+
+ /* update counts and index */
+ rxr_remaining -= rqpv;
+ txr_remaining -= tqpv;
+ rxr_idx++;
+ txr_idx++;
+ }
+
+ return 0;
+
+err_out:
+ adapter->num_tx_queues = 0;
+ adapter->num_rx_queues = 0;
+ adapter->num_q_vectors = 0;
+
+ while (v_idx--)
+ igc_free_q_vector(adapter, v_idx);
+
+ return -ENOMEM;
+}
+
+/**
+ * igc_cache_ring_register - Descriptor ring to register mapping
+ * @adapter: board private structure to initialize
+ *
+ * Once we know the feature-set enabled for the device, we'll cache
+ * the register offset the descriptor ring is assigned to.
+ */
+static void igc_cache_ring_register(struct igc_adapter *adapter)
+{
+ int i = 0, j = 0;
+
+ switch (adapter->hw.mac.type) {
+ case igc_i225:
+ /* Fall through */
+ default:
+ for (; i < adapter->num_rx_queues; i++)
+ adapter->rx_ring[i]->reg_idx = i;
+ for (; j < adapter->num_tx_queues; j++)
+ adapter->tx_ring[j]->reg_idx = j;
+ break;
+ }
+}
+
+/**
+ * igc_init_interrupt_scheme - initialize interrupts, allocate queues/vectors
+ * @adapter: Pointer to adapter structure
+ *
+ * This function initializes the interrupts and allocates all of the queues.
+ */
+static int igc_init_interrupt_scheme(struct igc_adapter *adapter, bool msix)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ int err = 0;
+
+ igc_set_interrupt_capability(adapter, msix);
+
+ err = igc_alloc_q_vectors(adapter);
+ if (err) {
+ dev_err(&pdev->dev, "Unable to allocate memory for vectors\n");
+ goto err_alloc_q_vectors;
+ }
+
+ igc_cache_ring_register(adapter);
+
+ return 0;
+
+err_alloc_q_vectors:
+ igc_reset_interrupt_capability(adapter);
+ return err;
+}
+
+static void igc_free_irq(struct igc_adapter *adapter)
+{
+ if (adapter->msix_entries) {
+ int vector = 0, i;
+
+ free_irq(adapter->msix_entries[vector++].vector, adapter);
+
+ for (i = 0; i < adapter->num_q_vectors; i++)
+ free_irq(adapter->msix_entries[vector++].vector,
+ adapter->q_vector[i]);
+ } else {
+ free_irq(adapter->pdev->irq, adapter);
+ }
+}
+
+/**
+ * igc_irq_disable - Mask off interrupt generation on the NIC
+ * @adapter: board private structure
+ */
+static void igc_irq_disable(struct igc_adapter *adapter)
+{
+ struct igc_hw *hw = &adapter->hw;
+
+ if (adapter->msix_entries) {
+ u32 regval = rd32(IGC_EIAM);
+
+ wr32(IGC_EIAM, regval & ~adapter->eims_enable_mask);
+ wr32(IGC_EIMC, adapter->eims_enable_mask);
+ regval = rd32(IGC_EIAC);
+ wr32(IGC_EIAC, regval & ~adapter->eims_enable_mask);
+ }
+
+ wr32(IGC_IAM, 0);
+ wr32(IGC_IMC, ~0);
+ wrfl();
+
+ if (adapter->msix_entries) {
+ int vector = 0, i;
+
+ synchronize_irq(adapter->msix_entries[vector++].vector);
+
+ for (i = 0; i < adapter->num_q_vectors; i++)
+ synchronize_irq(adapter->msix_entries[vector++].vector);
+ } else {
+ synchronize_irq(adapter->pdev->irq);
+ }
+}
+
+/**
+ * igc_irq_enable - Enable default interrupt generation settings
+ * @adapter: board private structure
+ */
+static void igc_irq_enable(struct igc_adapter *adapter)
+{
+ struct igc_hw *hw = &adapter->hw;
+
+ if (adapter->msix_entries) {
+ u32 ims = IGC_IMS_LSC | IGC_IMS_DOUTSYNC | IGC_IMS_DRSTA;
+ u32 regval = rd32(IGC_EIAC);
+
+ wr32(IGC_EIAC, regval | adapter->eims_enable_mask);
+ regval = rd32(IGC_EIAM);
+ wr32(IGC_EIAM, regval | adapter->eims_enable_mask);
+ wr32(IGC_EIMS, adapter->eims_enable_mask);
+ wr32(IGC_IMS, ims);
+ } else {
+ wr32(IGC_IMS, IMS_ENABLE_MASK | IGC_IMS_DRSTA);
+ wr32(IGC_IAM, IMS_ENABLE_MASK | IGC_IMS_DRSTA);
+ }
+}
+
+/**
+ * igc_request_irq - initialize interrupts
+ * @adapter: Pointer to adapter structure
+ *
+ * Attempts to configure interrupts using the best available
+ * capabilities of the hardware and kernel.
+ */
+static int igc_request_irq(struct igc_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct pci_dev *pdev = adapter->pdev;
+ int err = 0;
+
+ if (adapter->flags & IGC_FLAG_HAS_MSIX) {
+ err = igc_request_msix(adapter);
+ if (!err)
+ goto request_done;
+ /* fall back to MSI */
+ igc_free_all_tx_resources(adapter);
+ igc_free_all_rx_resources(adapter);
+
+ igc_clear_interrupt_scheme(adapter);
+ err = igc_init_interrupt_scheme(adapter, false);
+ if (err)
+ goto request_done;
+ igc_setup_all_tx_resources(adapter);
+ igc_setup_all_rx_resources(adapter);
+ igc_configure(adapter);
+ }
+
+ igc_assign_vector(adapter->q_vector[0], 0);
+
+ if (adapter->flags & IGC_FLAG_HAS_MSI) {
+ err = request_irq(pdev->irq, &igc_intr_msi, 0,
+ netdev->name, adapter);
+ if (!err)
+ goto request_done;
+
+ /* fall back to legacy interrupts */
+ igc_reset_interrupt_capability(adapter);
+ adapter->flags &= ~IGC_FLAG_HAS_MSI;
+ }
+
+ err = request_irq(pdev->irq, &igc_intr, IRQF_SHARED,
+ netdev->name, adapter);
+
+ if (err)
+ dev_err(&pdev->dev, "Error %d getting interrupt\n",
+ err);
+
+request_done:
+ return err;
+}
+
+static void igc_write_itr(struct igc_q_vector *q_vector)
+{
+ u32 itr_val = q_vector->itr_val & IGC_QVECTOR_MASK;
+
+ if (!q_vector->set_itr)
+ return;
+
+ if (!itr_val)
+ itr_val = IGC_ITR_VAL_MASK;
+
+ itr_val |= IGC_EITR_CNT_IGNR;
+
+ writel(itr_val, q_vector->itr_register);
+ q_vector->set_itr = 0;
+}
+
+/**
+ * igc_open - Called when a network interface is made active
+ * @netdev: network interface device structure
+ *
+ * Returns 0 on success, negative value on failure
+ *
+ * The open entry point is called when a network interface is made
+ * active by the system (IFF_UP). At this point all resources needed
+ * for transmit and receive operations are allocated, the interrupt
+ * handler is registered with the OS, the watchdog timer is started,
+ * and the stack is notified that the interface is ready.
+ */
+static int __igc_open(struct net_device *netdev, bool resuming)
+{
+ struct igc_adapter *adapter = netdev_priv(netdev);
+ struct igc_hw *hw = &adapter->hw;
+ int err = 0;
+ int i = 0;
+
+ /* disallow open during test */
+
+ if (test_bit(__IGC_TESTING, &adapter->state)) {
+ WARN_ON(resuming);
+ return -EBUSY;
+ }
+
+ netif_carrier_off(netdev);
+
+ /* allocate transmit descriptors */
+ err = igc_setup_all_tx_resources(adapter);
+ if (err)
+ goto err_setup_tx;
+
+ /* allocate receive descriptors */
+ err = igc_setup_all_rx_resources(adapter);
+ if (err)
+ goto err_setup_rx;
+
+ igc_power_up_link(adapter);
+
+ igc_configure(adapter);
+
+ err = igc_request_irq(adapter);
+ if (err)
+ goto err_req_irq;
+
+ /* Notify the stack of the actual queue counts. */
+ netif_set_real_num_tx_queues(netdev, adapter->num_tx_queues);
+ if (err)
+ goto err_set_queues;
+
+ err = netif_set_real_num_rx_queues(netdev, adapter->num_rx_queues);
+ if (err)
+ goto err_set_queues;
+
+ clear_bit(__IGC_DOWN, &adapter->state);
+
+ for (i = 0; i < adapter->num_q_vectors; i++)
+ napi_enable(&adapter->q_vector[i]->napi);
+
+ /* Clear any pending interrupts. */
+ rd32(IGC_ICR);
+ igc_irq_enable(adapter);
+
+ netif_tx_start_all_queues(netdev);
+
+ /* start the watchdog. */
+ hw->mac.get_link_status = 1;
+ schedule_work(&adapter->watchdog_task);
+
+ return IGC_SUCCESS;
+
+err_set_queues:
+ igc_free_irq(adapter);
+err_req_irq:
+ igc_release_hw_control(adapter);
+ igc_power_down_link(adapter);
+ igc_free_all_rx_resources(adapter);
+err_setup_rx:
+ igc_free_all_tx_resources(adapter);
+err_setup_tx:
+ igc_reset(adapter);
+
+ return err;
+}
+
+static int igc_open(struct net_device *netdev)
+{
+ return __igc_open(netdev, false);
+}
+
+/**
+ * igc_close - Disables a network interface
+ * @netdev: network interface device structure
+ *
+ * Returns 0, this is not allowed to fail
+ *
+ * The close entry point is called when an interface is de-activated
+ * by the OS. The hardware is still under the driver's control, but
+ * needs to be disabled. A global MAC reset is issued to stop the
+ * hardware, and all transmit and receive resources are freed.
+ */
+static int __igc_close(struct net_device *netdev, bool suspending)
+{
+ struct igc_adapter *adapter = netdev_priv(netdev);
+
+ WARN_ON(test_bit(__IGC_RESETTING, &adapter->state));
+
+ igc_down(adapter);
+
+ igc_release_hw_control(adapter);
+
+ igc_free_irq(adapter);
+
+ igc_free_all_tx_resources(adapter);
+ igc_free_all_rx_resources(adapter);
+
+ return 0;
+}
+
+static int igc_close(struct net_device *netdev)
+{
+ if (netif_device_present(netdev) || netdev->dismantle)
+ return __igc_close(netdev, false);
+ return 0;
+}
+
+static const struct net_device_ops igc_netdev_ops = {
+ .ndo_open = igc_open,
+ .ndo_stop = igc_close,
+ .ndo_start_xmit = igc_xmit_frame,
+ .ndo_set_mac_address = igc_set_mac,
+ .ndo_change_mtu = igc_change_mtu,
+ .ndo_get_stats = igc_get_stats,
+ .ndo_do_ioctl = igc_ioctl,
+};
+
+/* PCIe configuration access */
+void igc_read_pci_cfg(struct igc_hw *hw, u32 reg, u16 *value)
+{
+ struct igc_adapter *adapter = hw->back;
+
+ pci_read_config_word(adapter->pdev, reg, value);
+}
+
+void igc_write_pci_cfg(struct igc_hw *hw, u32 reg, u16 *value)
+{
+ struct igc_adapter *adapter = hw->back;
+
+ pci_write_config_word(adapter->pdev, reg, *value);
+}
+
+s32 igc_read_pcie_cap_reg(struct igc_hw *hw, u32 reg, u16 *value)
+{
+ struct igc_adapter *adapter = hw->back;
+ u16 cap_offset;
+
+ cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
+ if (!cap_offset)
+ return -IGC_ERR_CONFIG;
+
+ pci_read_config_word(adapter->pdev, cap_offset + reg, value);
+
+ return IGC_SUCCESS;
+}
+
+s32 igc_write_pcie_cap_reg(struct igc_hw *hw, u32 reg, u16 *value)
+{
+ struct igc_adapter *adapter = hw->back;
+ u16 cap_offset;
+
+ cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
+ if (!cap_offset)
+ return -IGC_ERR_CONFIG;
+
+ pci_write_config_word(adapter->pdev, cap_offset + reg, *value);
+
+ return IGC_SUCCESS;
+}
+
+u32 igc_rd32(struct igc_hw *hw, u32 reg)
+{
+ struct igc_adapter *igc = container_of(hw, struct igc_adapter, hw);
+ u8 __iomem *hw_addr = READ_ONCE(hw->hw_addr);
+ u32 value = 0;
+
+ if (IGC_REMOVED(hw_addr))
+ return ~value;
+
+ value = readl(&hw_addr[reg]);
+
+ /* reads should not return all F's */
+ if (!(~value) && (!reg || !(~readl(hw_addr)))) {
+ struct net_device *netdev = igc->netdev;
+
+ hw->hw_addr = NULL;
+ netif_device_detach(netdev);
+ netdev_err(netdev, "PCIe link lost, device now detached\n");
+ }
+
+ return value;
+}
+
+/**
+ * igc_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @ent: entry in igc_pci_tbl
+ *
+ * Returns 0 on success, negative on failure
+ *
+ * igc_probe initializes an adapter identified by a pci_dev structure.
+ * The OS initialization, configuring the adapter private structure,
+ * and a hardware reset occur.
+ */
+static int igc_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct igc_adapter *adapter;
+ struct net_device *netdev;
+ struct igc_hw *hw;
+ const struct igc_info *ei = igc_info_tbl[ent->driver_data];
+ int err, pci_using_dac;
+
+ err = pci_enable_device_mem(pdev);
+ if (err)
+ return err;
+
+ pci_using_dac = 0;
+ err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
+ if (!err) {
+ err = dma_set_coherent_mask(&pdev->dev,
+ DMA_BIT_MASK(64));
+ if (!err)
+ pci_using_dac = 1;
+ } else {
+ err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
+ if (err) {
+ err = dma_set_coherent_mask(&pdev->dev,
+ DMA_BIT_MASK(32));
+ if (err) {
+ IGC_ERR("Wrong DMA configuration, aborting\n");
+ goto err_dma;
+ }
+ }
+ }
+
+ err = pci_request_selected_regions(pdev,
+ pci_select_bars(pdev,
+ IORESOURCE_MEM),
+ igc_driver_name);
+ if (err)
+ goto err_pci_reg;
+
+ pci_enable_pcie_error_reporting(pdev);
+
+ pci_set_master(pdev);
+
+ err = -ENOMEM;
+ netdev = alloc_etherdev_mq(sizeof(struct igc_adapter),
+ IGC_MAX_TX_QUEUES);
+
+ if (!netdev)
+ goto err_alloc_etherdev;
+
+ SET_NETDEV_DEV(netdev, &pdev->dev);
+
+ pci_set_drvdata(pdev, netdev);
+ adapter = netdev_priv(netdev);
+ adapter->netdev = netdev;
+ adapter->pdev = pdev;
+ hw = &adapter->hw;
+ hw->back = adapter;
+ adapter->port_num = hw->bus.func;
+ adapter->msg_enable = GENMASK(debug - 1, 0);
+
+ err = pci_save_state(pdev);
+ if (err)
+ goto err_ioremap;
+
+ err = -EIO;
+ adapter->io_addr = ioremap(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+ if (!adapter->io_addr)
+ goto err_ioremap;
+
+ /* hw->hw_addr can be zeroed, so use adapter->io_addr for unmap */
+ hw->hw_addr = adapter->io_addr;
+
+ netdev->netdev_ops = &igc_netdev_ops;
+
+ netdev->watchdog_timeo = 5 * HZ;
+
+ netdev->mem_start = pci_resource_start(pdev, 0);
+ netdev->mem_end = pci_resource_end(pdev, 0);
+
+ /* PCI config space info */
+ hw->vendor_id = pdev->vendor;
+ hw->device_id = pdev->device;
+ hw->revision_id = pdev->revision;
+ hw->subsystem_vendor_id = pdev->subsystem_vendor;
+ hw->subsystem_device_id = pdev->subsystem_device;
+
+ /* Copy the default MAC and PHY function pointers */
+ memcpy(&hw->mac.ops, ei->mac_ops, sizeof(hw->mac.ops));
+ memcpy(&hw->phy.ops, ei->phy_ops, sizeof(hw->phy.ops));
+
+ /* Initialize skew-specific constants */
+ err = ei->get_invariants(hw);
+ if (err)
+ goto err_sw_init;
+
+ /* setup the private structure */
+ err = igc_sw_init(adapter);
+ if (err)
+ goto err_sw_init;
+
+ /* MTU range: 68 - 9216 */
+ netdev->min_mtu = ETH_MIN_MTU;
+ netdev->max_mtu = MAX_STD_JUMBO_FRAME_SIZE;
+
+ /* before reading the NVM, reset the controller to put the device in a
+ * known good starting state
+ */
+ hw->mac.ops.reset_hw(hw);
+
+ if (eth_platform_get_mac_address(&pdev->dev, hw->mac.addr)) {
+ /* copy the MAC address out of the NVM */
+ if (hw->mac.ops.read_mac_addr(hw))
+ dev_err(&pdev->dev, "NVM Read Error\n");
+ }
+
+ memcpy(netdev->dev_addr, hw->mac.addr, netdev->addr_len);
+
+ if (!is_valid_ether_addr(netdev->dev_addr)) {
+ dev_err(&pdev->dev, "Invalid MAC Address\n");
+ err = -EIO;
+ goto err_eeprom;
+ }
+
+ /* configure RXPBSIZE and TXPBSIZE */
+ wr32(IGC_RXPBS, I225_RXPBSIZE_DEFAULT);
+ wr32(IGC_TXPBS, I225_TXPBSIZE_DEFAULT);
+
+ timer_setup(&adapter->watchdog_timer, igc_watchdog, 0);
+ timer_setup(&adapter->phy_info_timer, igc_update_phy_info, 0);
+
+ INIT_WORK(&adapter->reset_task, igc_reset_task);
+ INIT_WORK(&adapter->watchdog_task, igc_watchdog_task);
+
+ /* Initialize link properties that are user-changeable */
+ adapter->fc_autoneg = true;
+ hw->mac.autoneg = true;
+ hw->phy.autoneg_advertised = 0xaf;
+
+ hw->fc.requested_mode = igc_fc_default;
+ hw->fc.current_mode = igc_fc_default;
+
+ /* reset the hardware with the new settings */
+ igc_reset(adapter);
+
+ /* let the f/w know that the h/w is now under the control of the
+ * driver.
+ */
+ igc_get_hw_control(adapter);
+
+ strncpy(netdev->name, "eth%d", IFNAMSIZ);
+ err = register_netdev(netdev);
+ if (err)
+ goto err_register;
+
+ /* carrier off reporting is important to ethtool even BEFORE open */
+ netif_carrier_off(netdev);
+
+ /* Check if Media Autosense is enabled */
+ adapter->ei = *ei;
+
+ /* print pcie link status and MAC address */
+ pcie_print_link_status(pdev);
+ netdev_info(netdev, "MAC: %pM\n", netdev->dev_addr);
+
+ return 0;
+
+err_register:
+ igc_release_hw_control(adapter);
+err_eeprom:
+ if (!igc_check_reset_block(hw))
+ igc_reset_phy(hw);
+err_sw_init:
+ igc_clear_interrupt_scheme(adapter);
+ iounmap(adapter->io_addr);
+err_ioremap:
+ free_netdev(netdev);
+err_alloc_etherdev:
+ pci_release_selected_regions(pdev,
+ pci_select_bars(pdev, IORESOURCE_MEM));
+err_pci_reg:
+err_dma:
+ pci_disable_device(pdev);
+ return err;
+}
+
+/**
+ * igc_remove - Device Removal Routine
+ * @pdev: PCI device information struct
+ *
+ * igc_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device. This could be caused by a
+ * Hot-Plug event, or because the driver is going to be removed from
+ * memory.
+ */
+static void igc_remove(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct igc_adapter *adapter = netdev_priv(netdev);
+
+ set_bit(__IGC_DOWN, &adapter->state);
+
+ del_timer_sync(&adapter->watchdog_timer);
+ del_timer_sync(&adapter->phy_info_timer);
+
+ cancel_work_sync(&adapter->reset_task);
+ cancel_work_sync(&adapter->watchdog_task);
+
+ /* Release control of h/w to f/w. If f/w is AMT enabled, this
+ * would have already happened in close and is redundant.
+ */
+ igc_release_hw_control(adapter);
+ unregister_netdev(netdev);
+
+ igc_clear_interrupt_scheme(adapter);
+ pci_iounmap(pdev, adapter->io_addr);
+ pci_release_mem_regions(pdev);
+
+ kfree(adapter->mac_table);
+ kfree(adapter->shadow_vfta);
+ free_netdev(netdev);
+
+ pci_disable_pcie_error_reporting(pdev);
+
+ pci_disable_device(pdev);
+}
+
+static struct pci_driver igc_driver = {
+ .name = igc_driver_name,
+ .id_table = igc_pci_tbl,
+ .probe = igc_probe,
+ .remove = igc_remove,
+};
+
+static void igc_set_flag_queue_pairs(struct igc_adapter *adapter,
+ const u32 max_rss_queues)
+{
+ /* Determine if we need to pair queues. */
+ /* If rss_queues > half of max_rss_queues, pair the queues in
+ * order to conserve interrupts due to limited supply.
+ */
+ if (adapter->rss_queues > (max_rss_queues / 2))
+ adapter->flags |= IGC_FLAG_QUEUE_PAIRS;
+ else
+ adapter->flags &= ~IGC_FLAG_QUEUE_PAIRS;
+}
+
+static unsigned int igc_get_max_rss_queues(struct igc_adapter *adapter)
+{
+ unsigned int max_rss_queues;
+
+ /* Determine the maximum number of RSS queues supported. */
+ max_rss_queues = IGC_MAX_RX_QUEUES;
+
+ return max_rss_queues;
+}
+
+static void igc_init_queue_configuration(struct igc_adapter *adapter)
+{
+ u32 max_rss_queues;
+
+ max_rss_queues = igc_get_max_rss_queues(adapter);
+ adapter->rss_queues = min_t(u32, max_rss_queues, num_online_cpus());
+
+ igc_set_flag_queue_pairs(adapter, max_rss_queues);
+}
+
+/**
+ * igc_sw_init - Initialize general software structures (struct igc_adapter)
+ * @adapter: board private structure to initialize
+ *
+ * igc_sw_init initializes the Adapter private data structure.
+ * Fields are initialized based on PCI device information and
+ * OS network device settings (MTU size).
+ */
+static int igc_sw_init(struct igc_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct pci_dev *pdev = adapter->pdev;
+ struct igc_hw *hw = &adapter->hw;
+
+ int size = sizeof(struct igc_mac_addr) * hw->mac.rar_entry_count;
+
+ pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word);
+
+ /* set default ring sizes */
+ adapter->tx_ring_count = IGC_DEFAULT_TXD;
+ adapter->rx_ring_count = IGC_DEFAULT_RXD;
+
+ /* set default ITR values */
+ adapter->rx_itr_setting = IGC_DEFAULT_ITR;
+ adapter->tx_itr_setting = IGC_DEFAULT_ITR;
+
+ /* set default work limits */
+ adapter->tx_work_limit = IGC_DEFAULT_TX_WORK;
+
+ /* adjust max frame to be at least the size of a standard frame */
+ adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN +
+ VLAN_HLEN;
+ adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
+
+ spin_lock_init(&adapter->nfc_lock);
+ spin_lock_init(&adapter->stats64_lock);
+ /* Assume MSI-X interrupts, will be checked during IRQ allocation */
+ adapter->flags |= IGC_FLAG_HAS_MSIX;
+
+ adapter->mac_table = kzalloc(size, GFP_ATOMIC);
+ if (!adapter->mac_table)
+ return -ENOMEM;
+
+ igc_init_queue_configuration(adapter);
+
+ /* This call may decrease the number of queues */
+ if (igc_init_interrupt_scheme(adapter, true)) {
+ dev_err(&pdev->dev, "Unable to allocate memory for queues\n");
+ return -ENOMEM;
+ }
+
+ /* Explicitly disable IRQ since the NIC can be in any state. */
+ igc_irq_disable(adapter);
+
+ set_bit(__IGC_DOWN, &adapter->state);
+
+ return 0;
+}
+
+/**
+ * igc_get_hw_dev - return device
+ * @hw: pointer to hardware structure
+ *
+ * used by hardware layer to print debugging information
+ */
+struct net_device *igc_get_hw_dev(struct igc_hw *hw)
+{
+ struct igc_adapter *adapter = hw->back;
+
+ return adapter->netdev;
+}
+
+/**
+ * igc_init_module - Driver Registration Routine
+ *
+ * igc_init_module is the first routine called when the driver is
+ * loaded. All it does is register with the PCI subsystem.
+ */
+static int __init igc_init_module(void)
+{
+ int ret;
+
+ pr_info("%s - version %s\n",
+ igc_driver_string, igc_driver_version);
+
+ pr_info("%s\n", igc_copyright);
+
+ ret = pci_register_driver(&igc_driver);
+ return ret;
+}
+
+module_init(igc_init_module);
+
+/**
+ * igc_exit_module - Driver Exit Cleanup Routine
+ *
+ * igc_exit_module is called just before the driver is removed
+ * from memory.
+ */
+static void __exit igc_exit_module(void)
+{
+ pci_unregister_driver(&igc_driver);
+}
+
+module_exit(igc_exit_module);
+/* igc_main.c */
diff --git a/drivers/net/ethernet/intel/igc/igc_nvm.c b/drivers/net/ethernet/intel/igc/igc_nvm.c
new file mode 100644
index 000000000000..58f81aba0144
--- /dev/null
+++ b/drivers/net/ethernet/intel/igc/igc_nvm.c
@@ -0,0 +1,215 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2018 Intel Corporation */
+
+#include "igc_mac.h"
+#include "igc_nvm.h"
+
+/**
+ * igc_poll_eerd_eewr_done - Poll for EEPROM read/write completion
+ * @hw: pointer to the HW structure
+ * @ee_reg: EEPROM flag for polling
+ *
+ * Polls the EEPROM status bit for either read or write completion based
+ * upon the value of 'ee_reg'.
+ */
+static s32 igc_poll_eerd_eewr_done(struct igc_hw *hw, int ee_reg)
+{
+ s32 ret_val = -IGC_ERR_NVM;
+ u32 attempts = 100000;
+ u32 i, reg = 0;
+
+ for (i = 0; i < attempts; i++) {
+ if (ee_reg == IGC_NVM_POLL_READ)
+ reg = rd32(IGC_EERD);
+ else
+ reg = rd32(IGC_EEWR);
+
+ if (reg & IGC_NVM_RW_REG_DONE) {
+ ret_val = 0;
+ break;
+ }
+
+ udelay(5);
+ }
+
+ return ret_val;
+}
+
+/**
+ * igc_acquire_nvm - Generic request for access to EEPROM
+ * @hw: pointer to the HW structure
+ *
+ * Set the EEPROM access request bit and wait for EEPROM access grant bit.
+ * Return successful if access grant bit set, else clear the request for
+ * EEPROM access and return -IGC_ERR_NVM (-1).
+ */
+s32 igc_acquire_nvm(struct igc_hw *hw)
+{
+ s32 timeout = IGC_NVM_GRANT_ATTEMPTS;
+ u32 eecd = rd32(IGC_EECD);
+ s32 ret_val = 0;
+
+ wr32(IGC_EECD, eecd | IGC_EECD_REQ);
+ eecd = rd32(IGC_EECD);
+
+ while (timeout) {
+ if (eecd & IGC_EECD_GNT)
+ break;
+ udelay(5);
+ eecd = rd32(IGC_EECD);
+ timeout--;
+ }
+
+ if (!timeout) {
+ eecd &= ~IGC_EECD_REQ;
+ wr32(IGC_EECD, eecd);
+ hw_dbg("Could not acquire NVM grant\n");
+ ret_val = -IGC_ERR_NVM;
+ }
+
+ return ret_val;
+}
+
+/**
+ * igc_release_nvm - Release exclusive access to EEPROM
+ * @hw: pointer to the HW structure
+ *
+ * Stop any current commands to the EEPROM and clear the EEPROM request bit.
+ */
+void igc_release_nvm(struct igc_hw *hw)
+{
+ u32 eecd;
+
+ eecd = rd32(IGC_EECD);
+ eecd &= ~IGC_EECD_REQ;
+ wr32(IGC_EECD, eecd);
+}
+
+/**
+ * igc_read_nvm_eerd - Reads EEPROM using EERD register
+ * @hw: pointer to the HW structure
+ * @offset: offset of word in the EEPROM to read
+ * @words: number of words to read
+ * @data: word read from the EEPROM
+ *
+ * Reads a 16 bit word from the EEPROM using the EERD register.
+ */
+s32 igc_read_nvm_eerd(struct igc_hw *hw, u16 offset, u16 words, u16 *data)
+{
+ struct igc_nvm_info *nvm = &hw->nvm;
+ u32 i, eerd = 0;
+ s32 ret_val = 0;
+
+ /* A check for invalid values: offset too large, too many words,
+ * and not enough words.
+ */
+ if (offset >= nvm->word_size || (words > (nvm->word_size - offset)) ||
+ words == 0) {
+ hw_dbg("nvm parameter(s) out of bounds\n");
+ ret_val = -IGC_ERR_NVM;
+ goto out;
+ }
+
+ for (i = 0; i < words; i++) {
+ eerd = ((offset + i) << IGC_NVM_RW_ADDR_SHIFT) +
+ IGC_NVM_RW_REG_START;
+
+ wr32(IGC_EERD, eerd);
+ ret_val = igc_poll_eerd_eewr_done(hw, IGC_NVM_POLL_READ);
+ if (ret_val)
+ break;
+
+ data[i] = (rd32(IGC_EERD) >> IGC_NVM_RW_REG_DATA);
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * igc_read_mac_addr - Read device MAC address
+ * @hw: pointer to the HW structure
+ */
+s32 igc_read_mac_addr(struct igc_hw *hw)
+{
+ u32 rar_high;
+ u32 rar_low;
+ u16 i;
+
+ rar_high = rd32(IGC_RAH(0));
+ rar_low = rd32(IGC_RAL(0));
+
+ for (i = 0; i < IGC_RAL_MAC_ADDR_LEN; i++)
+ hw->mac.perm_addr[i] = (u8)(rar_low >> (i * 8));
+
+ for (i = 0; i < IGC_RAH_MAC_ADDR_LEN; i++)
+ hw->mac.perm_addr[i + 4] = (u8)(rar_high >> (i * 8));
+
+ for (i = 0; i < ETH_ALEN; i++)
+ hw->mac.addr[i] = hw->mac.perm_addr[i];
+
+ return 0;
+}
+
+/**
+ * igc_validate_nvm_checksum - Validate EEPROM checksum
+ * @hw: pointer to the HW structure
+ *
+ * Calculates the EEPROM checksum by reading/adding each word of the EEPROM
+ * and then verifies that the sum of the EEPROM is equal to 0xBABA.
+ */
+s32 igc_validate_nvm_checksum(struct igc_hw *hw)
+{
+ u16 checksum = 0;
+ u16 i, nvm_data;
+ s32 ret_val = 0;
+
+ for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) {
+ ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
+ if (ret_val) {
+ hw_dbg("NVM Read Error\n");
+ goto out;
+ }
+ checksum += nvm_data;
+ }
+
+ if (checksum != (u16)NVM_SUM) {
+ hw_dbg("NVM Checksum Invalid\n");
+ ret_val = -IGC_ERR_NVM;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * igc_update_nvm_checksum - Update EEPROM checksum
+ * @hw: pointer to the HW structure
+ *
+ * Updates the EEPROM checksum by reading/adding each word of the EEPROM
+ * up to the checksum. Then calculates the EEPROM checksum and writes the
+ * value to the EEPROM.
+ */
+s32 igc_update_nvm_checksum(struct igc_hw *hw)
+{
+ u16 checksum = 0;
+ u16 i, nvm_data;
+ s32 ret_val;
+
+ for (i = 0; i < NVM_CHECKSUM_REG; i++) {
+ ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
+ if (ret_val) {
+ hw_dbg("NVM Read Error while updating checksum.\n");
+ goto out;
+ }
+ checksum += nvm_data;
+ }
+ checksum = (u16)NVM_SUM - checksum;
+ ret_val = hw->nvm.ops.write(hw, NVM_CHECKSUM_REG, 1, &checksum);
+ if (ret_val)
+ hw_dbg("NVM Write Error while updating checksum.\n");
+
+out:
+ return ret_val;
+}
diff --git a/drivers/net/ethernet/intel/igc/igc_nvm.h b/drivers/net/ethernet/intel/igc/igc_nvm.h
new file mode 100644
index 000000000000..f9fc2e9cfb03
--- /dev/null
+++ b/drivers/net/ethernet/intel/igc/igc_nvm.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2018 Intel Corporation */
+
+#ifndef _IGC_NVM_H_
+#define _IGC_NVM_H_
+
+s32 igc_acquire_nvm(struct igc_hw *hw);
+void igc_release_nvm(struct igc_hw *hw);
+s32 igc_read_mac_addr(struct igc_hw *hw);
+s32 igc_read_nvm_eerd(struct igc_hw *hw, u16 offset, u16 words, u16 *data);
+s32 igc_validate_nvm_checksum(struct igc_hw *hw);
+s32 igc_update_nvm_checksum(struct igc_hw *hw);
+
+#endif
diff --git a/drivers/net/ethernet/intel/igc/igc_phy.c b/drivers/net/ethernet/intel/igc/igc_phy.c
new file mode 100644
index 000000000000..38e43e6fc1c7
--- /dev/null
+++ b/drivers/net/ethernet/intel/igc/igc_phy.c
@@ -0,0 +1,791 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2018 Intel Corporation */
+
+#include "igc_phy.h"
+
+/* forward declaration */
+static s32 igc_phy_setup_autoneg(struct igc_hw *hw);
+static s32 igc_wait_autoneg(struct igc_hw *hw);
+
+/**
+ * igc_check_reset_block - Check if PHY reset is blocked
+ * @hw: pointer to the HW structure
+ *
+ * Read the PHY management control register and check whether a PHY reset
+ * is blocked. If a reset is not blocked return 0, otherwise
+ * return IGC_ERR_BLK_PHY_RESET (12).
+ */
+s32 igc_check_reset_block(struct igc_hw *hw)
+{
+ u32 manc;
+
+ manc = rd32(IGC_MANC);
+
+ return (manc & IGC_MANC_BLK_PHY_RST_ON_IDE) ?
+ IGC_ERR_BLK_PHY_RESET : 0;
+}
+
+/**
+ * igc_get_phy_id - Retrieve the PHY ID and revision
+ * @hw: pointer to the HW structure
+ *
+ * Reads the PHY registers and stores the PHY ID and possibly the PHY
+ * revision in the hardware structure.
+ */
+s32 igc_get_phy_id(struct igc_hw *hw)
+{
+ struct igc_phy_info *phy = &hw->phy;
+ s32 ret_val = 0;
+ u16 phy_id;
+
+ ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id);
+ if (ret_val)
+ goto out;
+
+ phy->id = (u32)(phy_id << 16);
+ usleep_range(200, 500);
+ ret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id);
+ if (ret_val)
+ goto out;
+
+ phy->id |= (u32)(phy_id & PHY_REVISION_MASK);
+ phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
+
+out:
+ return ret_val;
+}
+
+/**
+ * igc_phy_has_link - Polls PHY for link
+ * @hw: pointer to the HW structure
+ * @iterations: number of times to poll for link
+ * @usec_interval: delay between polling attempts
+ * @success: pointer to whether polling was successful or not
+ *
+ * Polls the PHY status register for link, 'iterations' number of times.
+ */
+s32 igc_phy_has_link(struct igc_hw *hw, u32 iterations,
+ u32 usec_interval, bool *success)
+{
+ u16 i, phy_status;
+ s32 ret_val = 0;
+
+ for (i = 0; i < iterations; i++) {
+ /* Some PHYs require the PHY_STATUS register to be read
+ * twice due to the link bit being sticky. No harm doing
+ * it across the board.
+ */
+ ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
+ if (ret_val && usec_interval > 0) {
+ /* If the first read fails, another entity may have
+ * ownership of the resources, wait and try again to
+ * see if they have relinquished the resources yet.
+ */
+ if (usec_interval >= 1000)
+ mdelay(usec_interval / 1000);
+ else
+ udelay(usec_interval);
+ }
+ ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
+ if (ret_val)
+ break;
+ if (phy_status & MII_SR_LINK_STATUS)
+ break;
+ if (usec_interval >= 1000)
+ mdelay(usec_interval / 1000);
+ else
+ udelay(usec_interval);
+ }
+
+ *success = (i < iterations) ? true : false;
+
+ return ret_val;
+}
+
+/**
+ * igc_power_up_phy_copper - Restore copper link in case of PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of a PHY power down to save power, or to turn off link during a
+ * driver unload, restore the link to previous settings.
+ */
+void igc_power_up_phy_copper(struct igc_hw *hw)
+{
+ u16 mii_reg = 0;
+
+ /* The PHY will retain its settings across a power down/up cycle */
+ hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
+ mii_reg &= ~MII_CR_POWER_DOWN;
+ hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
+}
+
+/**
+ * igc_power_down_phy_copper - Power down copper PHY
+ * @hw: pointer to the HW structure
+ *
+ * Power down PHY to save power when interface is down and wake on lan
+ * is not enabled.
+ */
+void igc_power_down_phy_copper(struct igc_hw *hw)
+{
+ u16 mii_reg = 0;
+
+ /* The PHY will retain its settings across a power down/up cycle */
+ hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
+ mii_reg |= MII_CR_POWER_DOWN;
+
+ /* Temporary workaround - should be removed when PHY will implement
+ * IEEE registers as properly
+ */
+ /* hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);*/
+ usleep_range(1000, 2000);
+}
+
+/**
+ * igc_check_downshift - Checks whether a downshift in speed occurred
+ * @hw: pointer to the HW structure
+ *
+ * Success returns 0, Failure returns 1
+ *
+ * A downshift is detected by querying the PHY link health.
+ */
+s32 igc_check_downshift(struct igc_hw *hw)
+{
+ struct igc_phy_info *phy = &hw->phy;
+ u16 phy_data, offset, mask;
+ s32 ret_val;
+
+ switch (phy->type) {
+ case igc_phy_i225:
+ default:
+ /* speed downshift not supported */
+ phy->speed_downgraded = false;
+ ret_val = 0;
+ goto out;
+ }
+
+ ret_val = phy->ops.read_reg(hw, offset, &phy_data);
+
+ if (!ret_val)
+ phy->speed_downgraded = (phy_data & mask) ? true : false;
+
+out:
+ return ret_val;
+}
+
+/**
+ * igc_phy_hw_reset - PHY hardware reset
+ * @hw: pointer to the HW structure
+ *
+ * Verify the reset block is not blocking us from resetting. Acquire
+ * semaphore (if necessary) and read/set/write the device control reset
+ * bit in the PHY. Wait the appropriate delay time for the device to
+ * reset and release the semaphore (if necessary).
+ */
+s32 igc_phy_hw_reset(struct igc_hw *hw)
+{
+ struct igc_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u32 ctrl;
+
+ ret_val = igc_check_reset_block(hw);
+ if (ret_val) {
+ ret_val = 0;
+ goto out;
+ }
+
+ ret_val = phy->ops.acquire(hw);
+ if (ret_val)
+ goto out;
+
+ ctrl = rd32(IGC_CTRL);
+ wr32(IGC_CTRL, ctrl | IGC_CTRL_PHY_RST);
+ wrfl();
+
+ udelay(phy->reset_delay_us);
+
+ wr32(IGC_CTRL, ctrl);
+ wrfl();
+
+ usleep_range(1500, 2000);
+
+ phy->ops.release(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * igc_copper_link_autoneg - Setup/Enable autoneg for copper link
+ * @hw: pointer to the HW structure
+ *
+ * Performs initial bounds checking on autoneg advertisement parameter, then
+ * configure to advertise the full capability. Setup the PHY to autoneg
+ * and restart the negotiation process between the link partner. If
+ * autoneg_wait_to_complete, then wait for autoneg to complete before exiting.
+ */
+static s32 igc_copper_link_autoneg(struct igc_hw *hw)
+{
+ struct igc_phy_info *phy = &hw->phy;
+ u16 phy_ctrl;
+ s32 ret_val;
+
+ /* Perform some bounds checking on the autoneg advertisement
+ * parameter.
+ */
+ phy->autoneg_advertised &= phy->autoneg_mask;
+
+ /* If autoneg_advertised is zero, we assume it was not defaulted
+ * by the calling code so we set to advertise full capability.
+ */
+ if (phy->autoneg_advertised == 0)
+ phy->autoneg_advertised = phy->autoneg_mask;
+
+ hw_dbg("Reconfiguring auto-neg advertisement params\n");
+ ret_val = igc_phy_setup_autoneg(hw);
+ if (ret_val) {
+ hw_dbg("Error Setting up Auto-Negotiation\n");
+ goto out;
+ }
+ hw_dbg("Restarting Auto-Neg\n");
+
+ /* Restart auto-negotiation by setting the Auto Neg Enable bit and
+ * the Auto Neg Restart bit in the PHY control register.
+ */
+ ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
+ if (ret_val)
+ goto out;
+
+ phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
+ ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
+ if (ret_val)
+ goto out;
+
+ /* Does the user want to wait for Auto-Neg to complete here, or
+ * check at a later time (for example, callback routine).
+ */
+ if (phy->autoneg_wait_to_complete) {
+ ret_val = igc_wait_autoneg(hw);
+ if (ret_val) {
+ hw_dbg("Error while waiting for autoneg to complete\n");
+ goto out;
+ }
+ }
+
+ hw->mac.get_link_status = true;
+
+out:
+ return ret_val;
+}
+
+/**
+ * igc_wait_autoneg - Wait for auto-neg completion
+ * @hw: pointer to the HW structure
+ *
+ * Waits for auto-negotiation to complete or for the auto-negotiation time
+ * limit to expire, which ever happens first.
+ */
+static s32 igc_wait_autoneg(struct igc_hw *hw)
+{
+ u16 i, phy_status;
+ s32 ret_val = 0;
+
+ /* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */
+ for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) {
+ ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
+ if (ret_val)
+ break;
+ ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
+ if (ret_val)
+ break;
+ if (phy_status & MII_SR_AUTONEG_COMPLETE)
+ break;
+ msleep(100);
+ }
+
+ /* PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation
+ * has completed.
+ */
+ return ret_val;
+}
+
+/**
+ * igc_phy_setup_autoneg - Configure PHY for auto-negotiation
+ * @hw: pointer to the HW structure
+ *
+ * Reads the MII auto-neg advertisement register and/or the 1000T control
+ * register and if the PHY is already setup for auto-negotiation, then
+ * return successful. Otherwise, setup advertisement and flow control to
+ * the appropriate values for the wanted auto-negotiation.
+ */
+static s32 igc_phy_setup_autoneg(struct igc_hw *hw)
+{
+ struct igc_phy_info *phy = &hw->phy;
+ u16 aneg_multigbt_an_ctrl = 0;
+ u16 mii_1000t_ctrl_reg = 0;
+ u16 mii_autoneg_adv_reg;
+ s32 ret_val;
+
+ phy->autoneg_advertised &= phy->autoneg_mask;
+
+ /* Read the MII Auto-Neg Advertisement Register (Address 4). */
+ ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
+ if (ret_val)
+ return ret_val;
+
+ if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
+ /* Read the MII 1000Base-T Control Register (Address 9). */
+ ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL,
+ &mii_1000t_ctrl_reg);
+ if (ret_val)
+ return ret_val;
+ }
+
+ if ((phy->autoneg_mask & ADVERTISE_2500_FULL) &&
+ hw->phy.id == I225_I_PHY_ID) {
+ /* Read the MULTI GBT AN Control Register - reg 7.32 */
+ ret_val = phy->ops.read_reg(hw, (STANDARD_AN_REG_MASK <<
+ MMD_DEVADDR_SHIFT) |
+ ANEG_MULTIGBT_AN_CTRL,
+ &aneg_multigbt_an_ctrl);
+
+ if (ret_val)
+ return ret_val;
+ }
+
+ /* Need to parse both autoneg_advertised and fc and set up
+ * the appropriate PHY registers. First we will parse for
+ * autoneg_advertised software override. Since we can advertise
+ * a plethora of combinations, we need to check each bit
+ * individually.
+ */
+
+ /* First we clear all the 10/100 mb speed bits in the Auto-Neg
+ * Advertisement Register (Address 4) and the 1000 mb speed bits in
+ * the 1000Base-T Control Register (Address 9).
+ */
+ mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS |
+ NWAY_AR_100TX_HD_CAPS |
+ NWAY_AR_10T_FD_CAPS |
+ NWAY_AR_10T_HD_CAPS);
+ mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS);
+
+ hw_dbg("autoneg_advertised %x\n", phy->autoneg_advertised);
+
+ /* Do we want to advertise 10 Mb Half Duplex? */
+ if (phy->autoneg_advertised & ADVERTISE_10_HALF) {
+ hw_dbg("Advertise 10mb Half duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
+ }
+
+ /* Do we want to advertise 10 Mb Full Duplex? */
+ if (phy->autoneg_advertised & ADVERTISE_10_FULL) {
+ hw_dbg("Advertise 10mb Full duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
+ }
+
+ /* Do we want to advertise 100 Mb Half Duplex? */
+ if (phy->autoneg_advertised & ADVERTISE_100_HALF) {
+ hw_dbg("Advertise 100mb Half duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
+ }
+
+ /* Do we want to advertise 100 Mb Full Duplex? */
+ if (phy->autoneg_advertised & ADVERTISE_100_FULL) {
+ hw_dbg("Advertise 100mb Full duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
+ }
+
+ /* We do not allow the Phy to advertise 1000 Mb Half Duplex */
+ if (phy->autoneg_advertised & ADVERTISE_1000_HALF)
+ hw_dbg("Advertise 1000mb Half duplex request denied!\n");
+
+ /* Do we want to advertise 1000 Mb Full Duplex? */
+ if (phy->autoneg_advertised & ADVERTISE_1000_FULL) {
+ hw_dbg("Advertise 1000mb Full duplex\n");
+ mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
+ }
+
+ /* We do not allow the Phy to advertise 2500 Mb Half Duplex */
+ if (phy->autoneg_advertised & ADVERTISE_2500_HALF)
+ hw_dbg("Advertise 2500mb Half duplex request denied!\n");
+
+ /* Do we want to advertise 2500 Mb Full Duplex? */
+ if (phy->autoneg_advertised & ADVERTISE_2500_FULL) {
+ hw_dbg("Advertise 2500mb Full duplex\n");
+ aneg_multigbt_an_ctrl |= CR_2500T_FD_CAPS;
+ } else {
+ aneg_multigbt_an_ctrl &= ~CR_2500T_FD_CAPS;
+ }
+
+ /* Check for a software override of the flow control settings, and
+ * setup the PHY advertisement registers accordingly. If
+ * auto-negotiation is enabled, then software will have to set the
+ * "PAUSE" bits to the correct value in the Auto-Negotiation
+ * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-
+ * negotiation.
+ *
+ * The possible values of the "fc" parameter are:
+ * 0: Flow control is completely disabled
+ * 1: Rx flow control is enabled (we can receive pause frames
+ * but not send pause frames).
+ * 2: Tx flow control is enabled (we can send pause frames
+ * but we do not support receiving pause frames).
+ * 3: Both Rx and Tx flow control (symmetric) are enabled.
+ * other: No software override. The flow control configuration
+ * in the EEPROM is used.
+ */
+ switch (hw->fc.current_mode) {
+ case igc_fc_none:
+ /* Flow control (Rx & Tx) is completely disabled by a
+ * software over-ride.
+ */
+ mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+ break;
+ case igc_fc_rx_pause:
+ /* Rx Flow control is enabled, and Tx Flow control is
+ * disabled, by a software over-ride.
+ *
+ * Since there really isn't a way to advertise that we are
+ * capable of Rx Pause ONLY, we will advertise that we
+ * support both symmetric and asymmetric Rx PAUSE. Later
+ * (in igc_config_fc_after_link_up) we will disable the
+ * hw's ability to send PAUSE frames.
+ */
+ mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+ break;
+ case igc_fc_tx_pause:
+ /* Tx Flow control is enabled, and Rx Flow control is
+ * disabled, by a software over-ride.
+ */
+ mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
+ mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
+ break;
+ case igc_fc_full:
+ /* Flow control (both Rx and Tx) is enabled by a software
+ * over-ride.
+ */
+ mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+ break;
+ default:
+ hw_dbg("Flow control param set incorrectly\n");
+ return -IGC_ERR_CONFIG;
+ }
+
+ ret_val = phy->ops.write_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
+ if (ret_val)
+ return ret_val;
+
+ hw_dbg("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
+
+ if (phy->autoneg_mask & ADVERTISE_1000_FULL)
+ ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL,
+ mii_1000t_ctrl_reg);
+
+ if ((phy->autoneg_mask & ADVERTISE_2500_FULL) &&
+ hw->phy.id == I225_I_PHY_ID)
+ ret_val = phy->ops.write_reg(hw,
+ (STANDARD_AN_REG_MASK <<
+ MMD_DEVADDR_SHIFT) |
+ ANEG_MULTIGBT_AN_CTRL,
+ aneg_multigbt_an_ctrl);
+
+ return ret_val;
+}
+
+/**
+ * igc_setup_copper_link - Configure copper link settings
+ * @hw: pointer to the HW structure
+ *
+ * Calls the appropriate function to configure the link for auto-neg or forced
+ * speed and duplex. Then we check for link, once link is established calls
+ * to configure collision distance and flow control are called. If link is
+ * not established, we return -IGC_ERR_PHY (-2).
+ */
+s32 igc_setup_copper_link(struct igc_hw *hw)
+{
+ s32 ret_val = 0;
+ bool link;
+
+ if (hw->mac.autoneg) {
+ /* Setup autoneg and flow control advertisement and perform
+ * autonegotiation.
+ */
+ ret_val = igc_copper_link_autoneg(hw);
+ if (ret_val)
+ goto out;
+ } else {
+ /* PHY will be set to 10H, 10F, 100H or 100F
+ * depending on user settings.
+ */
+ hw_dbg("Forcing Speed and Duplex\n");
+ ret_val = hw->phy.ops.force_speed_duplex(hw);
+ if (ret_val) {
+ hw_dbg("Error Forcing Speed and Duplex\n");
+ goto out;
+ }
+ }
+
+ /* Check link status. Wait up to 100 microseconds for link to become
+ * valid.
+ */
+ ret_val = igc_phy_has_link(hw, COPPER_LINK_UP_LIMIT, 10, &link);
+ if (ret_val)
+ goto out;
+
+ if (link) {
+ hw_dbg("Valid link established!!!\n");
+ igc_config_collision_dist(hw);
+ ret_val = igc_config_fc_after_link_up(hw);
+ } else {
+ hw_dbg("Unable to establish link!!!\n");
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * igc_read_phy_reg_mdic - Read MDI control register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Reads the MDI control register in the PHY at offset and stores the
+ * information read to data.
+ */
+static s32 igc_read_phy_reg_mdic(struct igc_hw *hw, u32 offset, u16 *data)
+{
+ struct igc_phy_info *phy = &hw->phy;
+ u32 i, mdic = 0;
+ s32 ret_val = 0;
+
+ if (offset > MAX_PHY_REG_ADDRESS) {
+ hw_dbg("PHY Address %d is out of range\n", offset);
+ ret_val = -IGC_ERR_PARAM;
+ goto out;
+ }
+
+ /* Set up Op-code, Phy Address, and register offset in the MDI
+ * Control register. The MAC will take care of interfacing with the
+ * PHY to retrieve the desired data.
+ */
+ mdic = ((offset << IGC_MDIC_REG_SHIFT) |
+ (phy->addr << IGC_MDIC_PHY_SHIFT) |
+ (IGC_MDIC_OP_READ));
+
+ wr32(IGC_MDIC, mdic);
+
+ /* Poll the ready bit to see if the MDI read completed
+ * Increasing the time out as testing showed failures with
+ * the lower time out
+ */
+ for (i = 0; i < IGC_GEN_POLL_TIMEOUT; i++) {
+ usleep_range(500, 1000);
+ mdic = rd32(IGC_MDIC);
+ if (mdic & IGC_MDIC_READY)
+ break;
+ }
+ if (!(mdic & IGC_MDIC_READY)) {
+ hw_dbg("MDI Read did not complete\n");
+ ret_val = -IGC_ERR_PHY;
+ goto out;
+ }
+ if (mdic & IGC_MDIC_ERROR) {
+ hw_dbg("MDI Error\n");
+ ret_val = -IGC_ERR_PHY;
+ goto out;
+ }
+ *data = (u16)mdic;
+
+out:
+ return ret_val;
+}
+
+/**
+ * igc_write_phy_reg_mdic - Write MDI control register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write to register at offset
+ *
+ * Writes data to MDI control register in the PHY at offset.
+ */
+static s32 igc_write_phy_reg_mdic(struct igc_hw *hw, u32 offset, u16 data)
+{
+ struct igc_phy_info *phy = &hw->phy;
+ u32 i, mdic = 0;
+ s32 ret_val = 0;
+
+ if (offset > MAX_PHY_REG_ADDRESS) {
+ hw_dbg("PHY Address %d is out of range\n", offset);
+ ret_val = -IGC_ERR_PARAM;
+ goto out;
+ }
+
+ /* Set up Op-code, Phy Address, and register offset in the MDI
+ * Control register. The MAC will take care of interfacing with the
+ * PHY to write the desired data.
+ */
+ mdic = (((u32)data) |
+ (offset << IGC_MDIC_REG_SHIFT) |
+ (phy->addr << IGC_MDIC_PHY_SHIFT) |
+ (IGC_MDIC_OP_WRITE));
+
+ wr32(IGC_MDIC, mdic);
+
+ /* Poll the ready bit to see if the MDI read completed
+ * Increasing the time out as testing showed failures with
+ * the lower time out
+ */
+ for (i = 0; i < IGC_GEN_POLL_TIMEOUT; i++) {
+ usleep_range(500, 1000);
+ mdic = rd32(IGC_MDIC);
+ if (mdic & IGC_MDIC_READY)
+ break;
+ }
+ if (!(mdic & IGC_MDIC_READY)) {
+ hw_dbg("MDI Write did not complete\n");
+ ret_val = -IGC_ERR_PHY;
+ goto out;
+ }
+ if (mdic & IGC_MDIC_ERROR) {
+ hw_dbg("MDI Error\n");
+ ret_val = -IGC_ERR_PHY;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * __igc_access_xmdio_reg - Read/write XMDIO register
+ * @hw: pointer to the HW structure
+ * @address: XMDIO address to program
+ * @dev_addr: device address to program
+ * @data: pointer to value to read/write from/to the XMDIO address
+ * @read: boolean flag to indicate read or write
+ */
+static s32 __igc_access_xmdio_reg(struct igc_hw *hw, u16 address,
+ u8 dev_addr, u16 *data, bool read)
+{
+ s32 ret_val;
+
+ ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAC, dev_addr);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAAD, address);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAC, IGC_MMDAC_FUNC_DATA |
+ dev_addr);
+ if (ret_val)
+ return ret_val;
+
+ if (read)
+ ret_val = hw->phy.ops.read_reg(hw, IGC_MMDAAD, data);
+ else
+ ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAAD, *data);
+ if (ret_val)
+ return ret_val;
+
+ /* Recalibrate the device back to 0 */
+ ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAC, 0);
+ if (ret_val)
+ return ret_val;
+
+ return ret_val;
+}
+
+/**
+ * igc_read_xmdio_reg - Read XMDIO register
+ * @hw: pointer to the HW structure
+ * @addr: XMDIO address to program
+ * @dev_addr: device address to program
+ * @data: value to be read from the EMI address
+ */
+static s32 igc_read_xmdio_reg(struct igc_hw *hw, u16 addr,
+ u8 dev_addr, u16 *data)
+{
+ return __igc_access_xmdio_reg(hw, addr, dev_addr, data, true);
+}
+
+/**
+ * igc_write_xmdio_reg - Write XMDIO register
+ * @hw: pointer to the HW structure
+ * @addr: XMDIO address to program
+ * @dev_addr: device address to program
+ * @data: value to be written to the XMDIO address
+ */
+static s32 igc_write_xmdio_reg(struct igc_hw *hw, u16 addr,
+ u8 dev_addr, u16 data)
+{
+ return __igc_access_xmdio_reg(hw, addr, dev_addr, &data, false);
+}
+
+/**
+ * igc_write_phy_reg_gpy - Write GPY PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Acquires semaphore, if necessary, then writes the data to PHY register
+ * at the offset. Release any acquired semaphores before exiting.
+ */
+s32 igc_write_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 data)
+{
+ u8 dev_addr = (offset & GPY_MMD_MASK) >> GPY_MMD_SHIFT;
+ s32 ret_val;
+
+ offset = offset & GPY_REG_MASK;
+
+ if (!dev_addr) {
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ return ret_val;
+ ret_val = igc_write_phy_reg_mdic(hw, offset, data);
+ if (ret_val)
+ return ret_val;
+ hw->phy.ops.release(hw);
+ } else {
+ ret_val = igc_write_xmdio_reg(hw, (u16)offset, dev_addr,
+ data);
+ }
+
+ return ret_val;
+}
+
+/**
+ * igc_read_phy_reg_gpy - Read GPY PHY register
+ * @hw: pointer to the HW structure
+ * @offset: lower half is register offset to read to
+ * upper half is MMD to use.
+ * @data: data to read at register offset
+ *
+ * Acquires semaphore, if necessary, then reads the data in the PHY register
+ * at the offset. Release any acquired semaphores before exiting.
+ */
+s32 igc_read_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 *data)
+{
+ u8 dev_addr = (offset & GPY_MMD_MASK) >> GPY_MMD_SHIFT;
+ s32 ret_val;
+
+ offset = offset & GPY_REG_MASK;
+
+ if (!dev_addr) {
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ return ret_val;
+ ret_val = igc_read_phy_reg_mdic(hw, offset, data);
+ if (ret_val)
+ return ret_val;
+ hw->phy.ops.release(hw);
+ } else {
+ ret_val = igc_read_xmdio_reg(hw, (u16)offset, dev_addr,
+ data);
+ }
+
+ return ret_val;
+}
diff --git a/drivers/net/ethernet/intel/igc/igc_phy.h b/drivers/net/ethernet/intel/igc/igc_phy.h
new file mode 100644
index 000000000000..25cba33de7e2
--- /dev/null
+++ b/drivers/net/ethernet/intel/igc/igc_phy.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2018 Intel Corporation */
+
+#ifndef _IGC_PHY_H_
+#define _IGC_PHY_H_
+
+#include "igc_mac.h"
+
+s32 igc_check_reset_block(struct igc_hw *hw);
+s32 igc_phy_hw_reset(struct igc_hw *hw);
+s32 igc_get_phy_id(struct igc_hw *hw);
+s32 igc_phy_has_link(struct igc_hw *hw, u32 iterations,
+ u32 usec_interval, bool *success);
+s32 igc_check_downshift(struct igc_hw *hw);
+s32 igc_setup_copper_link(struct igc_hw *hw);
+void igc_power_up_phy_copper(struct igc_hw *hw);
+void igc_power_down_phy_copper(struct igc_hw *hw);
+s32 igc_write_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 data);
+s32 igc_read_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 *data);
+
+#endif
diff --git a/drivers/net/ethernet/intel/igc/igc_regs.h b/drivers/net/ethernet/intel/igc/igc_regs.h
new file mode 100644
index 000000000000..a1bd3216c906
--- /dev/null
+++ b/drivers/net/ethernet/intel/igc/igc_regs.h
@@ -0,0 +1,221 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2018 Intel Corporation */
+
+#ifndef _IGC_REGS_H_
+#define _IGC_REGS_H_
+
+/* General Register Descriptions */
+#define IGC_CTRL 0x00000 /* Device Control - RW */
+#define IGC_STATUS 0x00008 /* Device Status - RO */
+#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 */
+
+/* Internal Packet Buffer Size Registers */
+#define IGC_RXPBS 0x02404 /* Rx Packet Buffer Size - RW */
+#define IGC_TXPBS 0x03404 /* Tx Packet Buffer Size - RW */
+
+/* NVM Register Descriptions */
+#define IGC_EERD 0x12014 /* EEprom mode read - RW */
+#define IGC_EEWR 0x12018 /* EEprom mode write - RW */
+
+/* Flow Control Register Descriptions */
+#define IGC_FCAL 0x00028 /* FC Address Low - RW */
+#define IGC_FCAH 0x0002C /* FC Address High - RW */
+#define IGC_FCT 0x00030 /* FC Type - RW */
+#define IGC_FCTTV 0x00170 /* FC Transmit Timer - RW */
+#define IGC_FCRTL 0x02160 /* FC Receive Threshold Low - RW */
+#define IGC_FCRTH 0x02168 /* FC Receive Threshold High - RW */
+#define IGC_FCRTV 0x02460 /* FC Refresh Timer Value - RW */
+#define IGC_FCSTS 0x02464 /* FC Status - RO */
+
+/* PCIe Register Description */
+#define IGC_GCR 0x05B00 /* PCIe control- RW */
+
+/* Semaphore registers */
+#define IGC_SW_FW_SYNC 0x05B5C /* SW-FW Synchronization - RW */
+#define IGC_SWSM 0x05B50 /* SW Semaphore */
+#define IGC_FWSM 0x05B54 /* FW Semaphore */
+
+/* Function Active and Power State to MNG */
+#define IGC_FACTPS 0x05B30
+
+/* Interrupt Register Description */
+#define IGC_EICS 0x01520 /* Ext. Interrupt Cause Set - W0 */
+#define IGC_EIMS 0x01524 /* Ext. Interrupt Mask Set/Read - RW */
+#define IGC_EIMC 0x01528 /* Ext. Interrupt Mask Clear - WO */
+#define IGC_EIAC 0x0152C /* Ext. Interrupt Auto Clear - RW */
+#define IGC_EIAM 0x01530 /* Ext. Interrupt Auto Mask - RW */
+#define IGC_ICR 0x01500 /* Intr Cause Read - RC/W1C */
+#define IGC_ICS 0x01504 /* Intr Cause Set - WO */
+#define IGC_IMS 0x01508 /* Intr Mask Set/Read - RW */
+#define IGC_IMC 0x0150C /* Intr Mask Clear - WO */
+#define IGC_IAM 0x01510 /* Intr Ack Auto Mask- RW */
+/* Intr Throttle - RW */
+#define IGC_EITR(_n) (0x01680 + (0x4 * (_n)))
+/* Interrupt Vector Allocation - RW */
+#define IGC_IVAR0 0x01700
+#define IGC_IVAR_MISC 0x01740 /* IVAR for "other" causes - RW */
+#define IGC_GPIE 0x01514 /* General Purpose Intr Enable - RW */
+
+/* Interrupt Cause */
+#define IGC_ICRXPTC 0x04104 /* Rx Packet Timer Expire Count */
+#define IGC_ICRXATC 0x04108 /* Rx Absolute Timer Expire Count */
+#define IGC_ICTXPTC 0x0410C /* Tx Packet Timer Expire Count */
+#define IGC_ICTXATC 0x04110 /* Tx Absolute Timer Expire Count */
+#define IGC_ICTXQEC 0x04118 /* Tx Queue Empty Count */
+#define IGC_ICTXQMTC 0x0411C /* Tx Queue Min Threshold Count */
+#define IGC_ICRXDMTC 0x04120 /* Rx Descriptor Min Threshold Count */
+#define IGC_ICRXOC 0x04124 /* Receiver Overrun Count */
+
+#define IGC_CBTMPC 0x0402C /* Circuit Breaker TX Packet Count */
+#define IGC_HTDPMC 0x0403C /* Host Transmit Discarded Packets */
+#define IGC_CBRMPC 0x040FC /* Circuit Breaker RX Packet Count */
+#define IGC_RPTHC 0x04104 /* Rx Packets To Host */
+#define IGC_HGPTC 0x04118 /* Host Good Packets TX Count */
+#define IGC_HTCBDPC 0x04124 /* Host TX Circ.Breaker Drop Count */
+
+/* MSI-X Table Register Descriptions */
+#define IGC_PBACL 0x05B68 /* MSIx PBA Clear - R/W 1 to clear */
+
+/* Receive Register Descriptions */
+#define IGC_RCTL 0x00100 /* Rx Control - RW */
+#define IGC_SRRCTL(_n) (0x0C00C + ((_n) * 0x40))
+#define IGC_PSRTYPE(_i) (0x05480 + ((_i) * 4))
+#define IGC_RDBAL(_n) (0x0C000 + ((_n) * 0x40))
+#define IGC_RDBAH(_n) (0x0C004 + ((_n) * 0x40))
+#define IGC_RDLEN(_n) (0x0C008 + ((_n) * 0x40))
+#define IGC_RDH(_n) (0x0C010 + ((_n) * 0x40))
+#define IGC_RDT(_n) (0x0C018 + ((_n) * 0x40))
+#define IGC_RXDCTL(_n) (0x0C028 + ((_n) * 0x40))
+#define IGC_RQDPC(_n) (0x0C030 + ((_n) * 0x40))
+#define IGC_RXCSUM 0x05000 /* Rx Checksum Control - RW */
+#define IGC_RLPML 0x05004 /* Rx Long Packet Max Length */
+#define IGC_RFCTL 0x05008 /* Receive Filter Control*/
+#define IGC_MTA 0x05200 /* Multicast Table Array - RW Array */
+#define IGC_UTA 0x0A000 /* Unicast Table Array - RW */
+#define IGC_RAL(_n) (0x05400 + ((_n) * 0x08))
+#define IGC_RAH(_n) (0x05404 + ((_n) * 0x08))
+
+/* Transmit Register Descriptions */
+#define IGC_TCTL 0x00400 /* Tx Control - RW */
+#define IGC_TIPG 0x00410 /* Tx Inter-packet gap - RW */
+#define IGC_TDBAL(_n) (0x0E000 + ((_n) * 0x40))
+#define IGC_TDBAH(_n) (0x0E004 + ((_n) * 0x40))
+#define IGC_TDLEN(_n) (0x0E008 + ((_n) * 0x40))
+#define IGC_TDH(_n) (0x0E010 + ((_n) * 0x40))
+#define IGC_TDT(_n) (0x0E018 + ((_n) * 0x40))
+#define IGC_TXDCTL(_n) (0x0E028 + ((_n) * 0x40))
+
+/* MMD Register Descriptions */
+#define IGC_MMDAC 13 /* MMD Access Control */
+#define IGC_MMDAAD 14 /* MMD Access Address/Data */
+
+/* Good transmitted packets counter registers */
+#define IGC_PQGPTC(_n) (0x010014 + (0x100 * (_n)))
+
+/* Statistics Register Descriptions */
+#define IGC_CRCERRS 0x04000 /* CRC Error Count - R/clr */
+#define IGC_ALGNERRC 0x04004 /* Alignment Error Count - R/clr */
+#define IGC_SYMERRS 0x04008 /* Symbol Error Count - R/clr */
+#define IGC_RXERRC 0x0400C /* Receive Error Count - R/clr */
+#define IGC_MPC 0x04010 /* Missed Packet Count - R/clr */
+#define IGC_SCC 0x04014 /* Single Collision Count - R/clr */
+#define IGC_ECOL 0x04018 /* Excessive Collision Count - R/clr */
+#define IGC_MCC 0x0401C /* Multiple Collision Count - R/clr */
+#define IGC_LATECOL 0x04020 /* Late Collision Count - R/clr */
+#define IGC_COLC 0x04028 /* Collision Count - R/clr */
+#define IGC_DC 0x04030 /* Defer Count - R/clr */
+#define IGC_TNCRS 0x04034 /* Tx-No CRS - R/clr */
+#define IGC_SEC 0x04038 /* Sequence Error Count - R/clr */
+#define IGC_CEXTERR 0x0403C /* Carrier Extension Error Count - R/clr */
+#define IGC_RLEC 0x04040 /* Receive Length Error Count - R/clr */
+#define IGC_XONRXC 0x04048 /* XON Rx Count - R/clr */
+#define IGC_XONTXC 0x0404C /* XON Tx Count - R/clr */
+#define IGC_XOFFRXC 0x04050 /* XOFF Rx Count - R/clr */
+#define IGC_XOFFTXC 0x04054 /* XOFF Tx Count - R/clr */
+#define IGC_FCRUC 0x04058 /* Flow Control Rx Unsupported Count- R/clr */
+#define IGC_PRC64 0x0405C /* Packets Rx (64 bytes) - R/clr */
+#define IGC_PRC127 0x04060 /* Packets Rx (65-127 bytes) - R/clr */
+#define IGC_PRC255 0x04064 /* Packets Rx (128-255 bytes) - R/clr */
+#define IGC_PRC511 0x04068 /* Packets Rx (255-511 bytes) - R/clr */
+#define IGC_PRC1023 0x0406C /* Packets Rx (512-1023 bytes) - R/clr */
+#define IGC_PRC1522 0x04070 /* Packets Rx (1024-1522 bytes) - R/clr */
+#define IGC_GPRC 0x04074 /* Good Packets Rx Count - R/clr */
+#define IGC_BPRC 0x04078 /* Broadcast Packets Rx Count - R/clr */
+#define IGC_MPRC 0x0407C /* Multicast Packets Rx Count - R/clr */
+#define IGC_GPTC 0x04080 /* Good Packets Tx Count - R/clr */
+#define IGC_GORCL 0x04088 /* Good Octets Rx Count Low - R/clr */
+#define IGC_GORCH 0x0408C /* Good Octets Rx Count High - R/clr */
+#define IGC_GOTCL 0x04090 /* Good Octets Tx Count Low - R/clr */
+#define IGC_GOTCH 0x04094 /* Good Octets Tx Count High - R/clr */
+#define IGC_RNBC 0x040A0 /* Rx No Buffers Count - R/clr */
+#define IGC_RUC 0x040A4 /* Rx Undersize Count - R/clr */
+#define IGC_RFC 0x040A8 /* Rx Fragment Count - R/clr */
+#define IGC_ROC 0x040AC /* Rx Oversize Count - R/clr */
+#define IGC_RJC 0x040B0 /* Rx Jabber Count - R/clr */
+#define IGC_MGTPRC 0x040B4 /* Management Packets Rx Count - R/clr */
+#define IGC_MGTPDC 0x040B8 /* Management Packets Dropped Count - R/clr */
+#define IGC_MGTPTC 0x040BC /* Management Packets Tx Count - R/clr */
+#define IGC_TORL 0x040C0 /* Total Octets Rx Low - R/clr */
+#define IGC_TORH 0x040C4 /* Total Octets Rx High - R/clr */
+#define IGC_TOTL 0x040C8 /* Total Octets Tx Low - R/clr */
+#define IGC_TOTH 0x040CC /* Total Octets Tx High - R/clr */
+#define IGC_TPR 0x040D0 /* Total Packets Rx - R/clr */
+#define IGC_TPT 0x040D4 /* Total Packets Tx - R/clr */
+#define IGC_PTC64 0x040D8 /* Packets Tx (64 bytes) - R/clr */
+#define IGC_PTC127 0x040DC /* Packets Tx (65-127 bytes) - R/clr */
+#define IGC_PTC255 0x040E0 /* Packets Tx (128-255 bytes) - R/clr */
+#define IGC_PTC511 0x040E4 /* Packets Tx (256-511 bytes) - R/clr */
+#define IGC_PTC1023 0x040E8 /* Packets Tx (512-1023 bytes) - R/clr */
+#define IGC_PTC1522 0x040EC /* Packets Tx (1024-1522 Bytes) - R/clr */
+#define IGC_MPTC 0x040F0 /* Multicast Packets Tx Count - R/clr */
+#define IGC_BPTC 0x040F4 /* Broadcast Packets Tx Count - R/clr */
+#define IGC_TSCTC 0x040F8 /* TCP Segmentation Context Tx - R/clr */
+#define IGC_TSCTFC 0x040FC /* TCP Segmentation Context Tx Fail - R/clr */
+#define IGC_IAC 0x04100 /* Interrupt Assertion Count */
+#define IGC_ICTXPTC 0x0410C /* Interrupt Cause Tx Pkt Timer Expire Count */
+#define IGC_ICTXATC 0x04110 /* Interrupt Cause Tx Abs Timer Expire Count */
+#define IGC_ICTXQEC 0x04118 /* Interrupt Cause Tx Queue Empty Count */
+#define IGC_ICTXQMTC 0x0411C /* Interrupt Cause Tx Queue Min Thresh Count */
+#define IGC_RPTHC 0x04104 /* Rx Packets To Host */
+#define IGC_HGPTC 0x04118 /* Host Good Packets Tx Count */
+#define IGC_RXDMTC 0x04120 /* Rx Descriptor Minimum Threshold Count */
+#define IGC_HGORCL 0x04128 /* Host Good Octets Received Count Low */
+#define IGC_HGORCH 0x0412C /* Host Good Octets Received Count High */
+#define IGC_HGOTCL 0x04130 /* Host Good Octets Transmit Count Low */
+#define IGC_HGOTCH 0x04134 /* Host Good Octets Transmit Count High */
+#define IGC_LENERRS 0x04138 /* Length Errors Count */
+#define IGC_SCVPC 0x04228 /* SerDes/SGMII Code Violation Pkt Count */
+#define IGC_HRMPC 0x0A018 /* Header Redirection Missed Packet Count */
+
+/* Management registers */
+#define IGC_MANC 0x05820 /* Management Control - RW */
+
+/* Shadow Ram Write Register - RW */
+#define IGC_SRWR 0x12018
+
+/* forward declaration */
+struct igc_hw;
+u32 igc_rd32(struct igc_hw *hw, u32 reg);
+
+/* write operations, indexed using DWORDS */
+#define wr32(reg, val) \
+do { \
+ u8 __iomem *hw_addr = READ_ONCE((hw)->hw_addr); \
+ if (!IGC_REMOVED(hw_addr)) \
+ writel((val), &hw_addr[(reg)]); \
+} while (0)
+
+#define rd32(reg) (igc_rd32(hw, reg))
+
+#define wrfl() ((void)rd32(IGC_STATUS))
+
+#define array_wr32(reg, offset, value) \
+ wr32((reg) + ((offset) << 2), (value))
+
+#define array_rd32(reg, offset) (igc_rd32(hw, (reg) + ((offset) << 2)))
+
+#endif
diff --git a/drivers/net/ethernet/intel/ixgb/ixgb_main.c b/drivers/net/ethernet/intel/ixgb/ixgb_main.c
index 7722153c4ac2..1d4d1686909a 100644
--- a/drivers/net/ethernet/intel/ixgb/ixgb_main.c
+++ b/drivers/net/ethernet/intel/ixgb/ixgb_main.c
@@ -102,7 +102,7 @@ static struct pci_driver ixgb_driver = {
MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
MODULE_DESCRIPTION("Intel(R) PRO/10GbE Network Driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_VERSION(DRV_VERSION);
#define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV|NETIF_MSG_PROBE|NETIF_MSG_LINK)
diff --git a/drivers/net/ethernet/intel/ixgbe/Makefile b/drivers/net/ethernet/intel/ixgbe/Makefile
index 5414685189ce..4fb0d9e3f2da 100644
--- a/drivers/net/ethernet/intel/ixgbe/Makefile
+++ b/drivers/net/ethernet/intel/ixgbe/Makefile
@@ -8,7 +8,8 @@ obj-$(CONFIG_IXGBE) += ixgbe.o
ixgbe-objs := ixgbe_main.o ixgbe_common.o ixgbe_ethtool.o \
ixgbe_82599.o ixgbe_82598.o ixgbe_phy.o ixgbe_sriov.o \
- ixgbe_mbx.o ixgbe_x540.o ixgbe_x550.o ixgbe_lib.o ixgbe_ptp.o
+ ixgbe_mbx.o ixgbe_x540.o ixgbe_x550.o ixgbe_lib.o ixgbe_ptp.o \
+ ixgbe_xsk.o
ixgbe-$(CONFIG_IXGBE_DCB) += ixgbe_dcb.o ixgbe_dcb_82598.o \
ixgbe_dcb_82599.o ixgbe_dcb_nl.o
@@ -16,4 +17,4 @@ ixgbe-$(CONFIG_IXGBE_DCB) += ixgbe_dcb.o ixgbe_dcb_82598.o \
ixgbe-$(CONFIG_IXGBE_HWMON) += ixgbe_sysfs.o
ixgbe-$(CONFIG_DEBUG_FS) += ixgbe_debugfs.o
ixgbe-$(CONFIG_FCOE:m=y) += ixgbe_fcoe.o
-ixgbe-$(CONFIG_XFRM_OFFLOAD) += ixgbe_ipsec.o
+ixgbe-$(CONFIG_IXGBE_IPSEC) += ixgbe_ipsec.o
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
index 4fc906c6166b..143bdd5ee2a0 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
@@ -30,7 +30,6 @@
#include "ixgbe_ipsec.h"
#include <net/xdp.h>
-#include <net/busy_poll.h>
/* common prefix used by pr_<> macros */
#undef pr_fmt
@@ -228,13 +227,17 @@ struct ixgbe_tx_buffer {
struct ixgbe_rx_buffer {
struct sk_buff *skb;
dma_addr_t dma;
- struct page *page;
-#if (BITS_PER_LONG > 32) || (PAGE_SIZE >= 65536)
- __u32 page_offset;
-#else
- __u16 page_offset;
-#endif
- __u16 pagecnt_bias;
+ union {
+ struct {
+ struct page *page;
+ __u32 page_offset;
+ __u16 pagecnt_bias;
+ };
+ struct {
+ void *addr;
+ u64 handle;
+ };
+ };
};
struct ixgbe_queue_stats {
@@ -271,6 +274,7 @@ enum ixgbe_ring_state_t {
__IXGBE_TX_DETECT_HANG,
__IXGBE_HANG_CHECK_ARMED,
__IXGBE_TX_XDP_RING,
+ __IXGBE_TX_DISABLED,
};
#define ring_uses_build_skb(ring) \
@@ -347,6 +351,10 @@ struct ixgbe_ring {
struct ixgbe_rx_queue_stats rx_stats;
};
struct xdp_rxq_info xdp_rxq;
+ struct xdp_umem *xsk_umem;
+ struct zero_copy_allocator zca; /* ZC allocator anchor */
+ u16 ring_idx; /* {rx,tx,xdp}_ring back reference idx */
+ u16 rx_buf_len;
} ____cacheline_internodealigned_in_smp;
enum ixgbe_ring_f_enum {
@@ -605,6 +613,7 @@ struct ixgbe_adapter {
#define IXGBE_FLAG2_EEE_ENABLED BIT(15)
#define IXGBE_FLAG2_RX_LEGACY BIT(16)
#define IXGBE_FLAG2_IPSEC_ENABLED BIT(17)
+#define IXGBE_FLAG2_VF_IPSEC_ENABLED BIT(18)
/* Tx fast path data */
int num_tx_queues;
@@ -760,9 +769,14 @@ struct ixgbe_adapter {
#define IXGBE_RSS_KEY_SIZE 40 /* size of RSS Hash Key in bytes */
u32 *rss_key;
-#ifdef CONFIG_XFRM_OFFLOAD
+#ifdef CONFIG_IXGBE_IPSEC
struct ixgbe_ipsec *ipsec;
-#endif /* CONFIG_XFRM_OFFLOAD */
+#endif /* CONFIG_IXGBE_IPSEC */
+
+ /* AF_XDP zero-copy */
+ struct xdp_umem **xsk_umems;
+ u16 num_xsk_umems_used;
+ u16 num_xsk_umems;
};
static inline u8 ixgbe_max_rss_indices(struct ixgbe_adapter *adapter)
@@ -994,7 +1008,7 @@ void ixgbe_store_key(struct ixgbe_adapter *adapter);
void ixgbe_store_reta(struct ixgbe_adapter *adapter);
s32 ixgbe_negotiate_fc(struct ixgbe_hw *hw, u32 adv_reg, u32 lp_reg,
u32 adv_sym, u32 adv_asm, u32 lp_sym, u32 lp_asm);
-#ifdef CONFIG_XFRM_OFFLOAD
+#ifdef CONFIG_IXGBE_IPSEC
void ixgbe_init_ipsec_offload(struct ixgbe_adapter *adapter);
void ixgbe_stop_ipsec_offload(struct ixgbe_adapter *adapter);
void ixgbe_ipsec_restore(struct ixgbe_adapter *adapter);
@@ -1003,15 +1017,24 @@ void ixgbe_ipsec_rx(struct ixgbe_ring *rx_ring,
struct sk_buff *skb);
int ixgbe_ipsec_tx(struct ixgbe_ring *tx_ring, struct ixgbe_tx_buffer *first,
struct ixgbe_ipsec_tx_data *itd);
+void ixgbe_ipsec_vf_clear(struct ixgbe_adapter *adapter, u32 vf);
+int ixgbe_ipsec_vf_add_sa(struct ixgbe_adapter *adapter, u32 *mbuf, u32 vf);
+int ixgbe_ipsec_vf_del_sa(struct ixgbe_adapter *adapter, u32 *mbuf, u32 vf);
#else
-static inline void ixgbe_init_ipsec_offload(struct ixgbe_adapter *adapter) { };
-static inline void ixgbe_stop_ipsec_offload(struct ixgbe_adapter *adapter) { };
-static inline void ixgbe_ipsec_restore(struct ixgbe_adapter *adapter) { };
+static inline void ixgbe_init_ipsec_offload(struct ixgbe_adapter *adapter) { }
+static inline void ixgbe_stop_ipsec_offload(struct ixgbe_adapter *adapter) { }
+static inline void ixgbe_ipsec_restore(struct ixgbe_adapter *adapter) { }
static inline void ixgbe_ipsec_rx(struct ixgbe_ring *rx_ring,
union ixgbe_adv_rx_desc *rx_desc,
- struct sk_buff *skb) { };
+ struct sk_buff *skb) { }
static inline int ixgbe_ipsec_tx(struct ixgbe_ring *tx_ring,
struct ixgbe_tx_buffer *first,
- struct ixgbe_ipsec_tx_data *itd) { return 0; };
-#endif /* CONFIG_XFRM_OFFLOAD */
+ struct ixgbe_ipsec_tx_data *itd) { return 0; }
+static inline void ixgbe_ipsec_vf_clear(struct ixgbe_adapter *adapter,
+ u32 vf) { }
+static inline int ixgbe_ipsec_vf_add_sa(struct ixgbe_adapter *adapter,
+ u32 *mbuf, u32 vf) { return -EACCES; }
+static inline int ixgbe_ipsec_vf_del_sa(struct ixgbe_adapter *adapter,
+ u32 *mbuf, u32 vf) { return -EACCES; }
+#endif /* CONFIG_IXGBE_IPSEC */
#endif /* _IXGBE_H_ */
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
index e5a8461fe6a9..732b1e6ecc43 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
@@ -136,6 +136,8 @@ static const char ixgbe_gstrings_test[][ETH_GSTRING_LEN] = {
static const char ixgbe_priv_flags_strings[][ETH_GSTRING_LEN] = {
#define IXGBE_PRIV_FLAGS_LEGACY_RX BIT(0)
"legacy-rx",
+#define IXGBE_PRIV_FLAGS_VF_IPSEC_EN BIT(1)
+ "vf-ipsec",
};
#define IXGBE_PRIV_FLAGS_STR_LEN ARRAY_SIZE(ixgbe_priv_flags_strings)
@@ -3409,6 +3411,9 @@ static u32 ixgbe_get_priv_flags(struct net_device *netdev)
if (adapter->flags2 & IXGBE_FLAG2_RX_LEGACY)
priv_flags |= IXGBE_PRIV_FLAGS_LEGACY_RX;
+ if (adapter->flags2 & IXGBE_FLAG2_VF_IPSEC_ENABLED)
+ priv_flags |= IXGBE_PRIV_FLAGS_VF_IPSEC_EN;
+
return priv_flags;
}
@@ -3421,6 +3426,10 @@ static int ixgbe_set_priv_flags(struct net_device *netdev, u32 priv_flags)
if (priv_flags & IXGBE_PRIV_FLAGS_LEGACY_RX)
flags2 |= IXGBE_FLAG2_RX_LEGACY;
+ flags2 &= ~IXGBE_FLAG2_VF_IPSEC_ENABLED;
+ if (priv_flags & IXGBE_PRIV_FLAGS_VF_IPSEC_EN)
+ flags2 |= IXGBE_FLAG2_VF_IPSEC_ENABLED;
+
if (flags2 != adapter->flags2) {
adapter->flags2 = flags2;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c
index da4322e4daed..fd1b0546fd67 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c
@@ -5,6 +5,11 @@
#include <net/xfrm.h>
#include <crypto/aead.h>
+#define IXGBE_IPSEC_KEY_BITS 160
+static const char aes_gcm_name[] = "rfc4106(gcm(aes))";
+
+static void ixgbe_ipsec_del_sa(struct xfrm_state *xs);
+
/**
* ixgbe_ipsec_set_tx_sa - set the Tx SA registers
* @hw: hw specific details
@@ -113,7 +118,6 @@ static void ixgbe_ipsec_set_rx_ip(struct ixgbe_hw *hw, u16 idx, __be32 addr[])
**/
static void ixgbe_ipsec_clear_hw_tables(struct ixgbe_adapter *adapter)
{
- struct ixgbe_ipsec *ipsec = adapter->ipsec;
struct ixgbe_hw *hw = &adapter->hw;
u32 buf[4] = {0, 0, 0, 0};
u16 idx;
@@ -132,9 +136,6 @@ static void ixgbe_ipsec_clear_hw_tables(struct ixgbe_adapter *adapter)
ixgbe_ipsec_set_tx_sa(hw, idx, buf, 0);
ixgbe_ipsec_set_rx_sa(hw, idx, 0, buf, 0, 0, 0);
}
-
- ipsec->num_rx_sa = 0;
- ipsec->num_tx_sa = 0;
}
/**
@@ -290,6 +291,13 @@ static void ixgbe_ipsec_start_engine(struct ixgbe_adapter *adapter)
/**
* ixgbe_ipsec_restore - restore the ipsec HW settings after a reset
* @adapter: board private structure
+ *
+ * Reload the HW tables from the SW tables after they've been bashed
+ * by a chip reset.
+ *
+ * Any VF entries are removed from the SW and HW tables since either
+ * (a) the VF also gets reset on PF reset and will ask again for the
+ * offloads, or (b) the VF has been removed by a change in the num_vfs.
**/
void ixgbe_ipsec_restore(struct ixgbe_adapter *adapter)
{
@@ -305,6 +313,28 @@ void ixgbe_ipsec_restore(struct ixgbe_adapter *adapter)
ixgbe_ipsec_clear_hw_tables(adapter);
ixgbe_ipsec_start_engine(adapter);
+ /* reload the Rx and Tx keys */
+ for (i = 0; i < IXGBE_IPSEC_MAX_SA_COUNT; i++) {
+ struct rx_sa *r = &ipsec->rx_tbl[i];
+ struct tx_sa *t = &ipsec->tx_tbl[i];
+
+ if (r->used) {
+ if (r->mode & IXGBE_RXTXMOD_VF)
+ ixgbe_ipsec_del_sa(r->xs);
+ else
+ ixgbe_ipsec_set_rx_sa(hw, i, r->xs->id.spi,
+ r->key, r->salt,
+ r->mode, r->iptbl_ind);
+ }
+
+ if (t->used) {
+ if (t->mode & IXGBE_RXTXMOD_VF)
+ ixgbe_ipsec_del_sa(t->xs);
+ else
+ ixgbe_ipsec_set_tx_sa(hw, i, t->key, t->salt);
+ }
+ }
+
/* reload the IP addrs */
for (i = 0; i < IXGBE_IPSEC_MAX_RX_IP_COUNT; i++) {
struct rx_ip_sa *ipsa = &ipsec->ip_tbl[i];
@@ -312,20 +342,6 @@ void ixgbe_ipsec_restore(struct ixgbe_adapter *adapter)
if (ipsa->used)
ixgbe_ipsec_set_rx_ip(hw, i, ipsa->ipaddr);
}
-
- /* reload the Rx and Tx keys */
- for (i = 0; i < IXGBE_IPSEC_MAX_SA_COUNT; i++) {
- struct rx_sa *rsa = &ipsec->rx_tbl[i];
- struct tx_sa *tsa = &ipsec->tx_tbl[i];
-
- if (rsa->used)
- ixgbe_ipsec_set_rx_sa(hw, i, rsa->xs->id.spi,
- rsa->key, rsa->salt,
- rsa->mode, rsa->iptbl_ind);
-
- if (tsa->used)
- ixgbe_ipsec_set_tx_sa(hw, i, tsa->key, tsa->salt);
- }
}
/**
@@ -382,6 +398,8 @@ static struct xfrm_state *ixgbe_ipsec_find_rx_state(struct ixgbe_ipsec *ipsec,
rcu_read_lock();
hash_for_each_possible_rcu(ipsec->rx_sa_list, rsa, hlist,
(__force u32)spi) {
+ if (rsa->mode & IXGBE_RXTXMOD_VF)
+ continue;
if (spi == rsa->xs->id.spi &&
((ip4 && *daddr == rsa->xs->id.daddr.a4) ||
(!ip4 && !memcmp(daddr, &rsa->xs->id.daddr.a6,
@@ -411,7 +429,6 @@ static int ixgbe_ipsec_parse_proto_keys(struct xfrm_state *xs,
struct net_device *dev = xs->xso.dev;
unsigned char *key_data;
char *alg_name = NULL;
- const char aes_gcm_name[] = "rfc4106(gcm(aes))";
int key_len;
if (!xs->aead) {
@@ -439,9 +456,9 @@ static int ixgbe_ipsec_parse_proto_keys(struct xfrm_state *xs,
* we don't need to do any byteswapping.
* 160 accounts for 16 byte key and 4 byte salt
*/
- if (key_len == 160) {
+ if (key_len == IXGBE_IPSEC_KEY_BITS) {
*mysalt = ((u32 *)key_data)[4];
- } else if (key_len != 128) {
+ } else if (key_len != (IXGBE_IPSEC_KEY_BITS - (sizeof(*mysalt) * 8))) {
netdev_err(dev, "IPsec hw offload only supports keys up to 128 bits with a 32 bit salt\n");
return -EINVAL;
} else {
@@ -676,6 +693,9 @@ static int ixgbe_ipsec_add_sa(struct xfrm_state *xs)
} else {
struct tx_sa tsa;
+ if (adapter->num_vfs)
+ return -EOPNOTSUPP;
+
/* find the first unused index */
ret = ixgbe_ipsec_find_empty_idx(ipsec, false);
if (ret < 0) {
@@ -811,6 +831,226 @@ static const struct xfrmdev_ops ixgbe_xfrmdev_ops = {
};
/**
+ * ixgbe_ipsec_vf_clear - clear the tables of data for a VF
+ * @adapter: board private structure
+ * @vf: VF id to be removed
+ **/
+void ixgbe_ipsec_vf_clear(struct ixgbe_adapter *adapter, u32 vf)
+{
+ struct ixgbe_ipsec *ipsec = adapter->ipsec;
+ int i;
+
+ /* search rx sa table */
+ for (i = 0; i < IXGBE_IPSEC_MAX_SA_COUNT && ipsec->num_rx_sa; i++) {
+ if (!ipsec->rx_tbl[i].used)
+ continue;
+ if (ipsec->rx_tbl[i].mode & IXGBE_RXTXMOD_VF &&
+ ipsec->rx_tbl[i].vf == vf)
+ ixgbe_ipsec_del_sa(ipsec->rx_tbl[i].xs);
+ }
+
+ /* search tx sa table */
+ for (i = 0; i < IXGBE_IPSEC_MAX_SA_COUNT && ipsec->num_tx_sa; i++) {
+ if (!ipsec->tx_tbl[i].used)
+ continue;
+ if (ipsec->tx_tbl[i].mode & IXGBE_RXTXMOD_VF &&
+ ipsec->tx_tbl[i].vf == vf)
+ ixgbe_ipsec_del_sa(ipsec->tx_tbl[i].xs);
+ }
+}
+
+/**
+ * ixgbe_ipsec_vf_add_sa - translate VF request to SA add
+ * @adapter: board private structure
+ * @msgbuf: The message buffer
+ * @vf: the VF index
+ *
+ * Make up a new xs and algorithm info from the data sent by the VF.
+ * We only need to sketch in just enough to set up the HW offload.
+ * Put the resulting offload_handle into the return message to the VF.
+ *
+ * Returns 0 or error value
+ **/
+int ixgbe_ipsec_vf_add_sa(struct ixgbe_adapter *adapter, u32 *msgbuf, u32 vf)
+{
+ struct ixgbe_ipsec *ipsec = adapter->ipsec;
+ struct xfrm_algo_desc *algo;
+ struct sa_mbx_msg *sam;
+ struct xfrm_state *xs;
+ size_t aead_len;
+ u16 sa_idx;
+ u32 pfsa;
+ int err;
+
+ sam = (struct sa_mbx_msg *)(&msgbuf[1]);
+ if (!adapter->vfinfo[vf].trusted ||
+ !(adapter->flags2 & IXGBE_FLAG2_VF_IPSEC_ENABLED)) {
+ e_warn(drv, "VF %d attempted to add an IPsec SA\n", vf);
+ err = -EACCES;
+ goto err_out;
+ }
+
+ /* Tx IPsec offload doesn't seem to work on this
+ * device, so block these requests for now.
+ */
+ if (!(sam->flags & XFRM_OFFLOAD_INBOUND)) {
+ err = -EOPNOTSUPP;
+ goto err_out;
+ }
+
+ xs = kzalloc(sizeof(*xs), GFP_KERNEL);
+ if (unlikely(!xs)) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ xs->xso.flags = sam->flags;
+ xs->id.spi = sam->spi;
+ xs->id.proto = sam->proto;
+ xs->props.family = sam->family;
+ if (xs->props.family == AF_INET6)
+ memcpy(&xs->id.daddr.a6, sam->addr, sizeof(xs->id.daddr.a6));
+ else
+ memcpy(&xs->id.daddr.a4, sam->addr, sizeof(xs->id.daddr.a4));
+ xs->xso.dev = adapter->netdev;
+
+ algo = xfrm_aead_get_byname(aes_gcm_name, IXGBE_IPSEC_AUTH_BITS, 1);
+ if (unlikely(!algo)) {
+ err = -ENOENT;
+ goto err_xs;
+ }
+
+ aead_len = sizeof(*xs->aead) + IXGBE_IPSEC_KEY_BITS / 8;
+ xs->aead = kzalloc(aead_len, GFP_KERNEL);
+ if (unlikely(!xs->aead)) {
+ err = -ENOMEM;
+ goto err_xs;
+ }
+
+ xs->props.ealgo = algo->desc.sadb_alg_id;
+ xs->geniv = algo->uinfo.aead.geniv;
+ xs->aead->alg_icv_len = IXGBE_IPSEC_AUTH_BITS;
+ xs->aead->alg_key_len = IXGBE_IPSEC_KEY_BITS;
+ memcpy(xs->aead->alg_key, sam->key, sizeof(sam->key));
+ memcpy(xs->aead->alg_name, aes_gcm_name, sizeof(aes_gcm_name));
+
+ /* set up the HW offload */
+ err = ixgbe_ipsec_add_sa(xs);
+ if (err)
+ goto err_aead;
+
+ pfsa = xs->xso.offload_handle;
+ if (pfsa < IXGBE_IPSEC_BASE_TX_INDEX) {
+ sa_idx = pfsa - IXGBE_IPSEC_BASE_RX_INDEX;
+ ipsec->rx_tbl[sa_idx].vf = vf;
+ ipsec->rx_tbl[sa_idx].mode |= IXGBE_RXTXMOD_VF;
+ } else {
+ sa_idx = pfsa - IXGBE_IPSEC_BASE_TX_INDEX;
+ ipsec->tx_tbl[sa_idx].vf = vf;
+ ipsec->tx_tbl[sa_idx].mode |= IXGBE_RXTXMOD_VF;
+ }
+
+ msgbuf[1] = xs->xso.offload_handle;
+
+ return 0;
+
+err_aead:
+ memset(xs->aead, 0, sizeof(*xs->aead));
+ kfree(xs->aead);
+err_xs:
+ memset(xs, 0, sizeof(*xs));
+ kfree(xs);
+err_out:
+ msgbuf[1] = err;
+ return err;
+}
+
+/**
+ * ixgbe_ipsec_vf_del_sa - translate VF request to SA delete
+ * @adapter: board private structure
+ * @msgbuf: The message buffer
+ * @vf: the VF index
+ *
+ * Given the offload_handle sent by the VF, look for the related SA table
+ * entry and use its xs field to call for a delete of the SA.
+ *
+ * Note: We silently ignore requests to delete entries that are already
+ * set to unused because when a VF is set to "DOWN", the PF first
+ * gets a reset and clears all the VF's entries; then the VF's
+ * XFRM stack sends individual deletes for each entry, which the
+ * reset already removed. In the future it might be good to try to
+ * optimize this so not so many unnecessary delete messages are sent.
+ *
+ * Returns 0 or error value
+ **/
+int ixgbe_ipsec_vf_del_sa(struct ixgbe_adapter *adapter, u32 *msgbuf, u32 vf)
+{
+ struct ixgbe_ipsec *ipsec = adapter->ipsec;
+ struct xfrm_state *xs;
+ u32 pfsa = msgbuf[1];
+ u16 sa_idx;
+
+ if (!adapter->vfinfo[vf].trusted) {
+ e_err(drv, "vf %d attempted to delete an SA\n", vf);
+ return -EPERM;
+ }
+
+ if (pfsa < IXGBE_IPSEC_BASE_TX_INDEX) {
+ struct rx_sa *rsa;
+
+ sa_idx = pfsa - IXGBE_IPSEC_BASE_RX_INDEX;
+ if (sa_idx >= IXGBE_IPSEC_MAX_SA_COUNT) {
+ e_err(drv, "vf %d SA index %d out of range\n",
+ vf, sa_idx);
+ return -EINVAL;
+ }
+
+ rsa = &ipsec->rx_tbl[sa_idx];
+
+ if (!rsa->used)
+ return 0;
+
+ if (!(rsa->mode & IXGBE_RXTXMOD_VF) ||
+ rsa->vf != vf) {
+ e_err(drv, "vf %d bad Rx SA index %d\n", vf, sa_idx);
+ return -ENOENT;
+ }
+
+ xs = ipsec->rx_tbl[sa_idx].xs;
+ } else {
+ struct tx_sa *tsa;
+
+ sa_idx = pfsa - IXGBE_IPSEC_BASE_TX_INDEX;
+ if (sa_idx >= IXGBE_IPSEC_MAX_SA_COUNT) {
+ e_err(drv, "vf %d SA index %d out of range\n",
+ vf, sa_idx);
+ return -EINVAL;
+ }
+
+ tsa = &ipsec->tx_tbl[sa_idx];
+
+ if (!tsa->used)
+ return 0;
+
+ if (!(tsa->mode & IXGBE_RXTXMOD_VF) ||
+ tsa->vf != vf) {
+ e_err(drv, "vf %d bad Tx SA index %d\n", vf, sa_idx);
+ return -ENOENT;
+ }
+
+ xs = ipsec->tx_tbl[sa_idx].xs;
+ }
+
+ ixgbe_ipsec_del_sa(xs);
+
+ /* remove the xs that was made-up in the add request */
+ memset(xs, 0, sizeof(*xs));
+ kfree(xs);
+
+ return 0;
+}
+
+/**
* ixgbe_ipsec_tx - setup Tx flags for ipsec offload
* @tx_ring: outgoing context
* @first: current data packet
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.h
index 9ef7faadda69..d2b64ff8eb4e 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.h
@@ -26,6 +26,7 @@ enum ixgbe_ipsec_tbl_sel {
#define IXGBE_RXMOD_PROTO_ESP 0x00000004
#define IXGBE_RXMOD_DECRYPT 0x00000008
#define IXGBE_RXMOD_IPV6 0x00000010
+#define IXGBE_RXTXMOD_VF 0x00000020
struct rx_sa {
struct hlist_node hlist;
@@ -37,6 +38,7 @@ struct rx_sa {
u8 iptbl_ind;
bool used;
bool decrypt;
+ u32 vf;
};
struct rx_ip_sa {
@@ -49,8 +51,10 @@ struct tx_sa {
struct xfrm_state *xs;
u32 key[4];
u32 salt;
+ u32 mode;
bool encrypt;
bool used;
+ u32 vf;
};
struct ixgbe_ipsec_tx_data {
@@ -67,4 +71,13 @@ struct ixgbe_ipsec {
struct tx_sa *tx_tbl;
DECLARE_HASHTABLE(rx_sa_list, 10);
};
+
+struct sa_mbx_msg {
+ __be32 spi;
+ u8 flags;
+ u8 proto;
+ u16 family;
+ __be32 addr[4];
+ u32 key[5];
+};
#endif /* _IXGBE_IPSEC_H_ */
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
index d361f570ca37..62e6499e4146 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
@@ -1055,7 +1055,7 @@ static int ixgbe_alloc_q_vectors(struct ixgbe_adapter *adapter)
int txr_remaining = adapter->num_tx_queues;
int xdp_remaining = adapter->num_xdp_queues;
int rxr_idx = 0, txr_idx = 0, xdp_idx = 0, v_idx = 0;
- int err;
+ int err, i;
/* only one q_vector if MSI-X is disabled. */
if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED))
@@ -1097,6 +1097,21 @@ static int ixgbe_alloc_q_vectors(struct ixgbe_adapter *adapter)
xdp_idx += xqpv;
}
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ if (adapter->rx_ring[i])
+ adapter->rx_ring[i]->ring_idx = i;
+ }
+
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ if (adapter->tx_ring[i])
+ adapter->tx_ring[i]->ring_idx = i;
+ }
+
+ for (i = 0; i < adapter->num_xdp_queues; i++) {
+ if (adapter->xdp_ring[i])
+ adapter->xdp_ring[i]->ring_idx = i;
+ }
+
return 0;
err_out:
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index f27d73a7bf16..113b38e0defb 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -34,12 +34,14 @@
#include <net/tc_act/tc_mirred.h>
#include <net/vxlan.h>
#include <net/mpls.h>
+#include <net/xdp_sock.h>
#include "ixgbe.h"
#include "ixgbe_common.h"
#include "ixgbe_dcb_82599.h"
#include "ixgbe_sriov.h"
#include "ixgbe_model.h"
+#include "ixgbe_txrx_common.h"
char ixgbe_driver_name[] = "ixgbe";
static const char ixgbe_driver_string[] =
@@ -159,7 +161,7 @@ MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
MODULE_DESCRIPTION("Intel(R) 10 Gigabit PCI Express Network Driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_VERSION(DRV_VERSION);
static struct workqueue_struct *ixgbe_wq;
@@ -893,8 +895,8 @@ static void ixgbe_set_ivar(struct ixgbe_adapter *adapter, s8 direction,
}
}
-static inline void ixgbe_irq_rearm_queues(struct ixgbe_adapter *adapter,
- u64 qmask)
+void ixgbe_irq_rearm_queues(struct ixgbe_adapter *adapter,
+ u64 qmask)
{
u32 mask;
@@ -1673,9 +1675,9 @@ static void ixgbe_update_rsc_stats(struct ixgbe_ring *rx_ring,
* order to populate the hash, checksum, VLAN, timestamp, protocol, and
* other fields within the skb.
**/
-static void ixgbe_process_skb_fields(struct ixgbe_ring *rx_ring,
- union ixgbe_adv_rx_desc *rx_desc,
- struct sk_buff *skb)
+void ixgbe_process_skb_fields(struct ixgbe_ring *rx_ring,
+ union ixgbe_adv_rx_desc *rx_desc,
+ struct sk_buff *skb)
{
struct net_device *dev = rx_ring->netdev;
u32 flags = rx_ring->q_vector->adapter->flags;
@@ -1708,8 +1710,8 @@ static void ixgbe_process_skb_fields(struct ixgbe_ring *rx_ring,
skb->protocol = eth_type_trans(skb, dev);
}
-static void ixgbe_rx_skb(struct ixgbe_q_vector *q_vector,
- struct sk_buff *skb)
+void ixgbe_rx_skb(struct ixgbe_q_vector *q_vector,
+ struct sk_buff *skb)
{
napi_gro_receive(&q_vector->napi, skb);
}
@@ -1868,9 +1870,9 @@ static void ixgbe_dma_sync_frag(struct ixgbe_ring *rx_ring,
*
* Returns true if an error was encountered and skb was freed.
**/
-static bool ixgbe_cleanup_headers(struct ixgbe_ring *rx_ring,
- union ixgbe_adv_rx_desc *rx_desc,
- struct sk_buff *skb)
+bool ixgbe_cleanup_headers(struct ixgbe_ring *rx_ring,
+ union ixgbe_adv_rx_desc *rx_desc,
+ struct sk_buff *skb)
{
struct net_device *netdev = rx_ring->netdev;
@@ -2186,14 +2188,6 @@ static struct sk_buff *ixgbe_build_skb(struct ixgbe_ring *rx_ring,
return skb;
}
-#define IXGBE_XDP_PASS 0
-#define IXGBE_XDP_CONSUMED BIT(0)
-#define IXGBE_XDP_TX BIT(1)
-#define IXGBE_XDP_REDIR BIT(2)
-
-static int ixgbe_xmit_xdp_ring(struct ixgbe_adapter *adapter,
- struct xdp_frame *xdpf);
-
static struct sk_buff *ixgbe_run_xdp(struct ixgbe_adapter *adapter,
struct ixgbe_ring *rx_ring,
struct xdp_buff *xdp)
@@ -3167,7 +3161,11 @@ int ixgbe_poll(struct napi_struct *napi, int budget)
#endif
ixgbe_for_each_ring(ring, q_vector->tx) {
- if (!ixgbe_clean_tx_irq(q_vector, ring, budget))
+ bool wd = ring->xsk_umem ?
+ ixgbe_clean_xdp_tx_irq(q_vector, ring, budget) :
+ ixgbe_clean_tx_irq(q_vector, ring, budget);
+
+ if (!wd)
clean_complete = false;
}
@@ -3183,7 +3181,10 @@ int ixgbe_poll(struct napi_struct *napi, int budget)
per_ring_budget = budget;
ixgbe_for_each_ring(ring, q_vector->rx) {
- int cleaned = ixgbe_clean_rx_irq(q_vector, ring,
+ int cleaned = ring->xsk_umem ?
+ ixgbe_clean_rx_irq_zc(q_vector, ring,
+ per_ring_budget) :
+ ixgbe_clean_rx_irq(q_vector, ring,
per_ring_budget);
work_done += cleaned;
@@ -3196,11 +3197,13 @@ int ixgbe_poll(struct napi_struct *napi, int budget)
return budget;
/* all work done, exit the polling mode */
- napi_complete_done(napi, work_done);
- if (adapter->rx_itr_setting & 1)
- ixgbe_set_itr(q_vector);
- if (!test_bit(__IXGBE_DOWN, &adapter->state))
- ixgbe_irq_enable_queues(adapter, BIT_ULL(q_vector->v_idx));
+ if (likely(napi_complete_done(napi, work_done))) {
+ if (adapter->rx_itr_setting & 1)
+ ixgbe_set_itr(q_vector);
+ if (!test_bit(__IXGBE_DOWN, &adapter->state))
+ ixgbe_irq_enable_queues(adapter,
+ BIT_ULL(q_vector->v_idx));
+ }
return min(work_done, budget - 1);
}
@@ -3473,6 +3476,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
u32 txdctl = IXGBE_TXDCTL_ENABLE;
u8 reg_idx = ring->reg_idx;
+ ring->xsk_umem = NULL;
+ if (ring_is_xdp(ring))
+ ring->xsk_umem = ixgbe_xsk_umem(adapter, ring);
+
/* disable queue to avoid issues while updating state */
IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), 0);
IXGBE_WRITE_FLUSH(hw);
@@ -3577,12 +3584,18 @@ static void ixgbe_setup_mtqc(struct ixgbe_adapter *adapter)
else
mtqc |= IXGBE_MTQC_64VF;
} else {
- if (tcs > 4)
+ if (tcs > 4) {
mtqc = IXGBE_MTQC_RT_ENA | IXGBE_MTQC_8TC_8TQ;
- else if (tcs > 1)
+ } else if (tcs > 1) {
mtqc = IXGBE_MTQC_RT_ENA | IXGBE_MTQC_4TC_4TQ;
- else
- mtqc = IXGBE_MTQC_64Q_1PB;
+ } else {
+ u8 max_txq = adapter->num_tx_queues +
+ adapter->num_xdp_queues;
+ if (max_txq > 63)
+ mtqc = IXGBE_MTQC_RT_ENA | IXGBE_MTQC_4TC_4TQ;
+ else
+ mtqc = IXGBE_MTQC_64Q_1PB;
+ }
}
IXGBE_WRITE_REG(hw, IXGBE_MTQC, mtqc);
@@ -3705,10 +3718,27 @@ static void ixgbe_configure_srrctl(struct ixgbe_adapter *adapter,
srrctl = IXGBE_RX_HDR_SIZE << IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT;
/* configure the packet buffer length */
- if (test_bit(__IXGBE_RX_3K_BUFFER, &rx_ring->state))
+ if (rx_ring->xsk_umem) {
+ u32 xsk_buf_len = rx_ring->xsk_umem->chunk_size_nohr -
+ XDP_PACKET_HEADROOM;
+
+ /* If the MAC support setting RXDCTL.RLPML, the
+ * SRRCTL[n].BSIZEPKT is set to PAGE_SIZE and
+ * RXDCTL.RLPML is set to the actual UMEM buffer
+ * size. If not, then we are stuck with a 1k buffer
+ * size resolution. In this case frames larger than
+ * the UMEM buffer size viewed in a 1k resolution will
+ * be dropped.
+ */
+ if (hw->mac.type != ixgbe_mac_82599EB)
+ srrctl |= PAGE_SIZE >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
+ else
+ srrctl |= xsk_buf_len >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
+ } else if (test_bit(__IXGBE_RX_3K_BUFFER, &rx_ring->state)) {
srrctl |= IXGBE_RXBUFFER_3K >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
- else
+ } else {
srrctl |= IXGBE_RXBUFFER_2K >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
+ }
/* configure descriptor type */
srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF;
@@ -4031,6 +4061,19 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
u32 rxdctl;
u8 reg_idx = ring->reg_idx;
+ xdp_rxq_info_unreg_mem_model(&ring->xdp_rxq);
+ ring->xsk_umem = ixgbe_xsk_umem(adapter, ring);
+ if (ring->xsk_umem) {
+ ring->zca.free = ixgbe_zca_free;
+ WARN_ON(xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
+ MEM_TYPE_ZERO_COPY,
+ &ring->zca));
+
+ } else {
+ WARN_ON(xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
+ MEM_TYPE_PAGE_SHARED, NULL));
+ }
+
/* disable queue to avoid use of these values while updating state */
rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(reg_idx));
rxdctl &= ~IXGBE_RXDCTL_ENABLE;
@@ -4080,6 +4123,17 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
#endif
}
+ if (ring->xsk_umem && hw->mac.type != ixgbe_mac_82599EB) {
+ u32 xsk_buf_len = ring->xsk_umem->chunk_size_nohr -
+ XDP_PACKET_HEADROOM;
+
+ rxdctl &= ~(IXGBE_RXDCTL_RLPMLMASK |
+ IXGBE_RXDCTL_RLPML_EN);
+ rxdctl |= xsk_buf_len | IXGBE_RXDCTL_RLPML_EN;
+
+ ring->rx_buf_len = xsk_buf_len;
+ }
+
/* initialize rx_buffer_info */
memset(ring->rx_buffer_info, 0,
sizeof(struct ixgbe_rx_buffer) * ring->count);
@@ -4093,7 +4147,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
ixgbe_rx_desc_queue_enable(adapter, ring);
- ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
+ if (ring->xsk_umem)
+ ixgbe_alloc_rx_buffers_zc(ring, ixgbe_desc_unused(ring));
+ else
+ ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
}
static void ixgbe_setup_psrtype(struct ixgbe_adapter *adapter)
@@ -5173,6 +5230,7 @@ static void ixgbe_fdir_filter_restore(struct ixgbe_adapter *adapter)
struct ixgbe_hw *hw = &adapter->hw;
struct hlist_node *node2;
struct ixgbe_fdir_filter *filter;
+ u64 action;
spin_lock(&adapter->fdir_perfect_lock);
@@ -5181,12 +5239,17 @@ static void ixgbe_fdir_filter_restore(struct ixgbe_adapter *adapter)
hlist_for_each_entry_safe(filter, node2,
&adapter->fdir_filter_list, fdir_node) {
+ action = filter->action;
+ if (action != IXGBE_FDIR_DROP_QUEUE && action != 0)
+ action =
+ (action >> ETHTOOL_RX_FLOW_SPEC_RING_VF_OFF) - 1;
+
ixgbe_fdir_write_perfect_filter_82599(hw,
&filter->filter,
filter->sw_idx,
- (filter->action == IXGBE_FDIR_DROP_QUEUE) ?
+ (action == IXGBE_FDIR_DROP_QUEUE) ?
IXGBE_FDIR_DROP_QUEUE :
- adapter->rx_ring[filter->action]->reg_idx);
+ adapter->rx_ring[action]->reg_idx);
}
spin_unlock(&adapter->fdir_perfect_lock);
@@ -5201,6 +5264,11 @@ static void ixgbe_clean_rx_ring(struct ixgbe_ring *rx_ring)
u16 i = rx_ring->next_to_clean;
struct ixgbe_rx_buffer *rx_buffer = &rx_ring->rx_buffer_info[i];
+ if (rx_ring->xsk_umem) {
+ ixgbe_xsk_clean_rx_ring(rx_ring);
+ goto skip_free;
+ }
+
/* Free all the Rx ring sk_buffs */
while (i != rx_ring->next_to_alloc) {
if (rx_buffer->skb) {
@@ -5239,6 +5307,7 @@ static void ixgbe_clean_rx_ring(struct ixgbe_ring *rx_ring)
}
}
+skip_free:
rx_ring->next_to_alloc = 0;
rx_ring->next_to_clean = 0;
rx_ring->next_to_use = 0;
@@ -5883,6 +5952,11 @@ static void ixgbe_clean_tx_ring(struct ixgbe_ring *tx_ring)
u16 i = tx_ring->next_to_clean;
struct ixgbe_tx_buffer *tx_buffer = &tx_ring->tx_buffer_info[i];
+ if (tx_ring->xsk_umem) {
+ ixgbe_xsk_clean_tx_ring(tx_ring);
+ goto out;
+ }
+
while (i != tx_ring->next_to_use) {
union ixgbe_adv_tx_desc *eop_desc, *tx_desc;
@@ -5934,6 +6008,7 @@ static void ixgbe_clean_tx_ring(struct ixgbe_ring *tx_ring)
if (!ring_is_xdp(tx_ring))
netdev_tx_reset_queue(txring_txq(tx_ring));
+out:
/* reset next_to_use and next_to_clean */
tx_ring->next_to_use = 0;
tx_ring->next_to_clean = 0;
@@ -6434,7 +6509,7 @@ int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter,
struct device *dev = rx_ring->dev;
int orig_node = dev_to_node(dev);
int ring_node = -1;
- int size, err;
+ int size;
size = sizeof(struct ixgbe_rx_buffer) * rx_ring->count;
@@ -6471,13 +6546,6 @@ int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter,
rx_ring->queue_index) < 0)
goto err;
- err = xdp_rxq_info_reg_mem_model(&rx_ring->xdp_rxq,
- MEM_TYPE_PAGE_SHARED, NULL);
- if (err) {
- xdp_rxq_info_unreg(&rx_ring->xdp_rxq);
- goto err;
- }
-
rx_ring->xdp_prog = adapter->xdp_prog;
return 0;
@@ -7775,6 +7843,33 @@ static void ixgbe_reset_subtask(struct ixgbe_adapter *adapter)
}
/**
+ * ixgbe_check_fw_error - Check firmware for errors
+ * @adapter: the adapter private structure
+ *
+ * Check firmware errors in register FWSM
+ */
+static bool ixgbe_check_fw_error(struct ixgbe_adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 fwsm;
+
+ /* read fwsm.ext_err_ind register and log errors */
+ fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM(hw));
+
+ if (fwsm & IXGBE_FWSM_EXT_ERR_IND_MASK ||
+ !(fwsm & IXGBE_FWSM_FW_VAL_BIT))
+ e_dev_warn("Warning firmware error detected FWSM: 0x%08X\n",
+ fwsm);
+
+ if (hw->mac.ops.fw_recovery_mode && hw->mac.ops.fw_recovery_mode(hw)) {
+ e_dev_err("Firmware recovery mode detected. Limiting functionality. Refer to the Intel(R) Ethernet Adapters and Devices User Guide for details on firmware recovery mode.\n");
+ return true;
+ }
+
+ return false;
+}
+
+/**
* ixgbe_service_task - manages and runs subtasks
* @work: pointer to work_struct containing our data
**/
@@ -7792,6 +7887,15 @@ static void ixgbe_service_task(struct work_struct *work)
ixgbe_service_event_complete(adapter);
return;
}
+ if (ixgbe_check_fw_error(adapter)) {
+ if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
+ rtnl_lock();
+ unregister_netdev(adapter->netdev);
+ rtnl_unlock();
+ }
+ ixgbe_service_event_complete(adapter);
+ return;
+ }
if (adapter->flags2 & IXGBE_FLAG2_UDP_TUN_REREG_NEEDED) {
rtnl_lock();
adapter->flags2 &= ~IXGBE_FLAG2_UDP_TUN_REREG_NEEDED;
@@ -8066,9 +8170,6 @@ static inline int ixgbe_maybe_stop_tx(struct ixgbe_ring *tx_ring, u16 size)
return __ixgbe_maybe_stop_tx(tx_ring, size);
}
-#define IXGBE_TXD_CMD (IXGBE_TXD_CMD_EOP | \
- IXGBE_TXD_CMD_RS)
-
static int ixgbe_tx_map(struct ixgbe_ring *tx_ring,
struct ixgbe_tx_buffer *first,
const u8 hdr_len)
@@ -8421,8 +8522,8 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb,
}
#endif
-static int ixgbe_xmit_xdp_ring(struct ixgbe_adapter *adapter,
- struct xdp_frame *xdpf)
+int ixgbe_xmit_xdp_ring(struct ixgbe_adapter *adapter,
+ struct xdp_frame *xdpf)
{
struct ixgbe_ring *ring = adapter->xdp_ring[smp_processor_id()];
struct ixgbe_tx_buffer *tx_buffer;
@@ -8593,7 +8694,7 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
#endif /* IXGBE_FCOE */
-#ifdef CONFIG_XFRM_OFFLOAD
+#ifdef CONFIG_IXGBE_IPSEC
if (skb->sp && !ixgbe_ipsec_tx(tx_ring, first, &ipsec_tx))
goto out_drop;
#endif
@@ -8644,6 +8745,8 @@ static netdev_tx_t __ixgbe_xmit_frame(struct sk_buff *skb,
return NETDEV_TX_OK;
tx_ring = ring ? ring : adapter->tx_ring[skb->queue_mapping];
+ if (unlikely(test_bit(__IXGBE_TX_DISABLED, &tx_ring->state)))
+ return NETDEV_TX_BUSY;
return ixgbe_xmit_frame_ring(skb, adapter, tx_ring);
}
@@ -10087,7 +10190,7 @@ ixgbe_features_check(struct sk_buff *skb, struct net_device *dev,
* the TSO, so it's the exception.
*/
if (skb->encapsulation && !(features & NETIF_F_TSO_MANGLEID)) {
-#ifdef CONFIG_XFRM_OFFLOAD
+#ifdef CONFIG_IXGBE_IPSEC
if (!skb->sp)
#endif
features &= ~NETIF_F_TSO;
@@ -10155,12 +10258,19 @@ static int ixgbe_xdp(struct net_device *dev, struct netdev_bpf *xdp)
xdp->prog_id = adapter->xdp_prog ?
adapter->xdp_prog->aux->id : 0;
return 0;
+ case XDP_QUERY_XSK_UMEM:
+ return ixgbe_xsk_umem_query(adapter, &xdp->xsk.umem,
+ xdp->xsk.queue_id);
+ case XDP_SETUP_XSK_UMEM:
+ return ixgbe_xsk_umem_setup(adapter, xdp->xsk.umem,
+ xdp->xsk.queue_id);
+
default:
return -EINVAL;
}
}
-static void ixgbe_xdp_ring_update_tail(struct ixgbe_ring *ring)
+void ixgbe_xdp_ring_update_tail(struct ixgbe_ring *ring)
{
/* Force memory writes to complete before letting h/w know there
* are new descriptors to fetch.
@@ -10190,6 +10300,9 @@ static int ixgbe_xdp_xmit(struct net_device *dev, int n,
if (unlikely(!ring))
return -ENXIO;
+ if (unlikely(test_bit(__IXGBE_TX_DISABLED, &ring->state)))
+ return -ENXIO;
+
for (i = 0; i < n; i++) {
struct xdp_frame *xdpf = frames[i];
int err;
@@ -10251,8 +10364,162 @@ static const struct net_device_ops ixgbe_netdev_ops = {
.ndo_features_check = ixgbe_features_check,
.ndo_bpf = ixgbe_xdp,
.ndo_xdp_xmit = ixgbe_xdp_xmit,
+ .ndo_xsk_async_xmit = ixgbe_xsk_async_xmit,
};
+static void ixgbe_disable_txr_hw(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *tx_ring)
+{
+ unsigned long wait_delay, delay_interval;
+ struct ixgbe_hw *hw = &adapter->hw;
+ u8 reg_idx = tx_ring->reg_idx;
+ int wait_loop;
+ u32 txdctl;
+
+ IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), IXGBE_TXDCTL_SWFLSH);
+
+ /* delay mechanism from ixgbe_disable_tx */
+ delay_interval = ixgbe_get_completion_timeout(adapter) / 100;
+
+ wait_loop = IXGBE_MAX_RX_DESC_POLL;
+ wait_delay = delay_interval;
+
+ while (wait_loop--) {
+ usleep_range(wait_delay, wait_delay + 10);
+ wait_delay += delay_interval * 2;
+ txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(reg_idx));
+
+ if (!(txdctl & IXGBE_TXDCTL_ENABLE))
+ return;
+ }
+
+ e_err(drv, "TXDCTL.ENABLE not cleared within the polling period\n");
+}
+
+static void ixgbe_disable_txr(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *tx_ring)
+{
+ set_bit(__IXGBE_TX_DISABLED, &tx_ring->state);
+ ixgbe_disable_txr_hw(adapter, tx_ring);
+}
+
+static void ixgbe_disable_rxr_hw(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *rx_ring)
+{
+ unsigned long wait_delay, delay_interval;
+ struct ixgbe_hw *hw = &adapter->hw;
+ u8 reg_idx = rx_ring->reg_idx;
+ int wait_loop;
+ u32 rxdctl;
+
+ rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(reg_idx));
+ rxdctl &= ~IXGBE_RXDCTL_ENABLE;
+ rxdctl |= IXGBE_RXDCTL_SWFLSH;
+
+ /* write value back with RXDCTL.ENABLE bit cleared */
+ IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+
+ /* RXDCTL.EN may not change on 82598 if link is down, so skip it */
+ if (hw->mac.type == ixgbe_mac_82598EB &&
+ !(IXGBE_READ_REG(hw, IXGBE_LINKS) & IXGBE_LINKS_UP))
+ return;
+
+ /* delay mechanism from ixgbe_disable_rx */
+ delay_interval = ixgbe_get_completion_timeout(adapter) / 100;
+
+ wait_loop = IXGBE_MAX_RX_DESC_POLL;
+ wait_delay = delay_interval;
+
+ while (wait_loop--) {
+ usleep_range(wait_delay, wait_delay + 10);
+ wait_delay += delay_interval * 2;
+ rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(reg_idx));
+
+ if (!(rxdctl & IXGBE_RXDCTL_ENABLE))
+ return;
+ }
+
+ e_err(drv, "RXDCTL.ENABLE not cleared within the polling period\n");
+}
+
+static void ixgbe_reset_txr_stats(struct ixgbe_ring *tx_ring)
+{
+ memset(&tx_ring->stats, 0, sizeof(tx_ring->stats));
+ memset(&tx_ring->tx_stats, 0, sizeof(tx_ring->tx_stats));
+}
+
+static void ixgbe_reset_rxr_stats(struct ixgbe_ring *rx_ring)
+{
+ memset(&rx_ring->stats, 0, sizeof(rx_ring->stats));
+ memset(&rx_ring->rx_stats, 0, sizeof(rx_ring->rx_stats));
+}
+
+/**
+ * ixgbe_txrx_ring_disable - Disable Rx/Tx/XDP Tx rings
+ * @adapter: adapter structure
+ * @ring: ring index
+ *
+ * This function disables a certain Rx/Tx/XDP Tx ring. The function
+ * assumes that the netdev is running.
+ **/
+void ixgbe_txrx_ring_disable(struct ixgbe_adapter *adapter, int ring)
+{
+ struct ixgbe_ring *rx_ring, *tx_ring, *xdp_ring;
+
+ rx_ring = adapter->rx_ring[ring];
+ tx_ring = adapter->tx_ring[ring];
+ xdp_ring = adapter->xdp_ring[ring];
+
+ ixgbe_disable_txr(adapter, tx_ring);
+ if (xdp_ring)
+ ixgbe_disable_txr(adapter, xdp_ring);
+ ixgbe_disable_rxr_hw(adapter, rx_ring);
+
+ if (xdp_ring)
+ synchronize_sched();
+
+ /* Rx/Tx/XDP Tx share the same napi context. */
+ napi_disable(&rx_ring->q_vector->napi);
+
+ ixgbe_clean_tx_ring(tx_ring);
+ if (xdp_ring)
+ ixgbe_clean_tx_ring(xdp_ring);
+ ixgbe_clean_rx_ring(rx_ring);
+
+ ixgbe_reset_txr_stats(tx_ring);
+ if (xdp_ring)
+ ixgbe_reset_txr_stats(xdp_ring);
+ ixgbe_reset_rxr_stats(rx_ring);
+}
+
+/**
+ * ixgbe_txrx_ring_enable - Enable Rx/Tx/XDP Tx rings
+ * @adapter: adapter structure
+ * @ring: ring index
+ *
+ * This function enables a certain Rx/Tx/XDP Tx ring. The function
+ * assumes that the netdev is running.
+ **/
+void ixgbe_txrx_ring_enable(struct ixgbe_adapter *adapter, int ring)
+{
+ struct ixgbe_ring *rx_ring, *tx_ring, *xdp_ring;
+
+ rx_ring = adapter->rx_ring[ring];
+ tx_ring = adapter->tx_ring[ring];
+ xdp_ring = adapter->xdp_ring[ring];
+
+ /* Rx/Tx/XDP Tx share the same napi context. */
+ napi_enable(&rx_ring->q_vector->napi);
+
+ ixgbe_configure_tx_ring(adapter, tx_ring);
+ if (xdp_ring)
+ ixgbe_configure_tx_ring(adapter, xdp_ring);
+ ixgbe_configure_rx_ring(adapter, rx_ring);
+
+ clear_bit(__IXGBE_TX_DISABLED, &tx_ring->state);
+ clear_bit(__IXGBE_TX_DISABLED, &xdp_ring->state);
+}
+
/**
* ixgbe_enumerate_functions - Get the number of ports this device has
* @adapter: adapter structure
@@ -10616,7 +10883,7 @@ skip_sriov:
if (hw->mac.type >= ixgbe_mac_82599EB)
netdev->features |= NETIF_F_SCTP_CRC;
-#ifdef CONFIG_XFRM_OFFLOAD
+#ifdef CONFIG_IXGBE_IPSEC
#define IXGBE_ESP_FEATURES (NETIF_F_HW_ESP | \
NETIF_F_HW_ESP_TX_CSUM | \
NETIF_F_GSO_ESP)
@@ -10691,6 +10958,11 @@ skip_sriov:
if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED)
netdev->features |= NETIF_F_LRO;
+ if (ixgbe_check_fw_error(adapter)) {
+ err = -EIO;
+ goto err_sw_init;
+ }
+
/* make sure the EEPROM is good */
if (hw->eeprom.ops.validate_checksum(hw, NULL) < 0) {
e_dev_err("The EEPROM Checksum Is Not Valid\n");
@@ -11050,8 +11322,6 @@ static pci_ers_result_t ixgbe_io_error_detected(struct pci_dev *pdev,
/* Free device reference count */
pci_dev_put(vfdev);
}
-
- pci_cleanup_aer_uncorrect_error_status(pdev);
}
/*
@@ -11101,7 +11371,6 @@ static pci_ers_result_t ixgbe_io_slot_reset(struct pci_dev *pdev)
{
struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
pci_ers_result_t result;
- int err;
if (pci_enable_device_mem(pdev)) {
e_err(probe, "Cannot re-enable PCI device after reset.\n");
@@ -11121,13 +11390,6 @@ static pci_ers_result_t ixgbe_io_slot_reset(struct pci_dev *pdev)
result = PCI_ERS_RESULT_RECOVERED;
}
- err = pci_cleanup_aer_uncorrect_error_status(pdev);
- if (err) {
- e_dev_err("pci_cleanup_aer_uncorrect_error_status "
- "failed 0x%0x\n", err);
- /* non-fatal, continue */
- }
-
return result;
}
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h
index e085b6520dac..a148534d7256 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h
@@ -50,6 +50,7 @@ enum ixgbe_pfvf_api_rev {
ixgbe_mbox_api_11, /* API version 1.1, linux/freebsd VF driver */
ixgbe_mbox_api_12, /* API version 1.2, linux/freebsd VF driver */
ixgbe_mbox_api_13, /* API version 1.3, linux/freebsd VF driver */
+ ixgbe_mbox_api_14, /* API version 1.4, linux/freebsd VF driver */
/* This value should always be last */
ixgbe_mbox_api_unknown, /* indicates that API version is not known */
};
@@ -80,6 +81,10 @@ enum ixgbe_pfvf_api_rev {
#define IXGBE_VF_UPDATE_XCAST_MODE 0x0c
+/* mailbox API, version 1.4 VF requests */
+#define IXGBE_VF_IPSEC_ADD 0x0d
+#define IXGBE_VF_IPSEC_DEL 0x0e
+
/* length of permanent address message returned from PF */
#define IXGBE_VF_PERMADDR_MSG_LEN 4
/* word in permanent address message with the current multicast type */
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
index 3c6f01c41b78..5dacfc870259 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
@@ -496,6 +496,7 @@ static s32 ixgbe_set_vf_lpe(struct ixgbe_adapter *adapter, u32 *msgbuf, u32 vf)
case ixgbe_mbox_api_11:
case ixgbe_mbox_api_12:
case ixgbe_mbox_api_13:
+ case ixgbe_mbox_api_14:
/* Version 1.1 supports jumbo frames on VFs if PF has
* jumbo frames enabled which means legacy VFs are
* disabled
@@ -721,13 +722,18 @@ static inline void ixgbe_vf_reset_event(struct ixgbe_adapter *adapter, u32 vf)
ixgbe_set_vmvir(adapter, vfinfo->pf_vlan,
adapter->default_up, vf);
- if (vfinfo->spoofchk_enabled)
+ if (vfinfo->spoofchk_enabled) {
hw->mac.ops.set_vlan_anti_spoofing(hw, true, vf);
+ hw->mac.ops.set_mac_anti_spoofing(hw, true, vf);
+ }
}
/* reset multicast table array for vf */
adapter->vfinfo[vf].num_vf_mc_hashes = 0;
+ /* clear any ipsec table info */
+ ixgbe_ipsec_vf_clear(adapter, vf);
+
/* Flush and reset the mta with the new values */
ixgbe_set_rx_mode(adapter->netdev);
@@ -1000,6 +1006,7 @@ static int ixgbe_negotiate_vf_api(struct ixgbe_adapter *adapter,
case ixgbe_mbox_api_11:
case ixgbe_mbox_api_12:
case ixgbe_mbox_api_13:
+ case ixgbe_mbox_api_14:
adapter->vfinfo[vf].vf_api = api;
return 0;
default:
@@ -1025,6 +1032,7 @@ static int ixgbe_get_vf_queues(struct ixgbe_adapter *adapter,
case ixgbe_mbox_api_11:
case ixgbe_mbox_api_12:
case ixgbe_mbox_api_13:
+ case ixgbe_mbox_api_14:
break;
default:
return -1;
@@ -1065,6 +1073,7 @@ static int ixgbe_get_vf_reta(struct ixgbe_adapter *adapter, u32 *msgbuf, u32 vf)
/* verify the PF is supporting the correct API */
switch (adapter->vfinfo[vf].vf_api) {
+ case ixgbe_mbox_api_14:
case ixgbe_mbox_api_13:
case ixgbe_mbox_api_12:
break;
@@ -1097,6 +1106,7 @@ static int ixgbe_get_vf_rss_key(struct ixgbe_adapter *adapter,
/* verify the PF is supporting the correct API */
switch (adapter->vfinfo[vf].vf_api) {
+ case ixgbe_mbox_api_14:
case ixgbe_mbox_api_13:
case ixgbe_mbox_api_12:
break;
@@ -1122,8 +1132,9 @@ static int ixgbe_update_vf_xcast_mode(struct ixgbe_adapter *adapter,
/* promisc introduced in 1.3 version */
if (xcast_mode == IXGBEVF_XCAST_MODE_PROMISC)
return -EOPNOTSUPP;
- /* Fall threw */
+ /* Fall through */
case ixgbe_mbox_api_13:
+ case ixgbe_mbox_api_14:
break;
default:
return -EOPNOTSUPP;
@@ -1249,6 +1260,12 @@ static int ixgbe_rcv_msg_from_vf(struct ixgbe_adapter *adapter, u32 vf)
case IXGBE_VF_UPDATE_XCAST_MODE:
retval = ixgbe_update_vf_xcast_mode(adapter, msgbuf, vf);
break;
+ case IXGBE_VF_IPSEC_ADD:
+ retval = ixgbe_ipsec_vf_add_sa(adapter, msgbuf, vf);
+ break;
+ case IXGBE_VF_IPSEC_DEL:
+ retval = ixgbe_ipsec_vf_del_sa(adapter, msgbuf, vf);
+ break;
default:
e_err(drv, "Unhandled Msg %8.8x\n", msgbuf[0]);
retval = IXGBE_ERR_MBX;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_txrx_common.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_txrx_common.h
new file mode 100644
index 000000000000..53d4089f5644
--- /dev/null
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_txrx_common.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2018 Intel Corporation. */
+
+#ifndef _IXGBE_TXRX_COMMON_H_
+#define _IXGBE_TXRX_COMMON_H_
+
+#define IXGBE_XDP_PASS 0
+#define IXGBE_XDP_CONSUMED BIT(0)
+#define IXGBE_XDP_TX BIT(1)
+#define IXGBE_XDP_REDIR BIT(2)
+
+#define IXGBE_TXD_CMD (IXGBE_TXD_CMD_EOP | \
+ IXGBE_TXD_CMD_RS)
+
+int ixgbe_xmit_xdp_ring(struct ixgbe_adapter *adapter,
+ struct xdp_frame *xdpf);
+bool ixgbe_cleanup_headers(struct ixgbe_ring *rx_ring,
+ union ixgbe_adv_rx_desc *rx_desc,
+ struct sk_buff *skb);
+void ixgbe_process_skb_fields(struct ixgbe_ring *rx_ring,
+ union ixgbe_adv_rx_desc *rx_desc,
+ struct sk_buff *skb);
+void ixgbe_rx_skb(struct ixgbe_q_vector *q_vector,
+ struct sk_buff *skb);
+void ixgbe_xdp_ring_update_tail(struct ixgbe_ring *ring);
+void ixgbe_irq_rearm_queues(struct ixgbe_adapter *adapter, u64 qmask);
+
+void ixgbe_txrx_ring_disable(struct ixgbe_adapter *adapter, int ring);
+void ixgbe_txrx_ring_enable(struct ixgbe_adapter *adapter, int ring);
+
+struct xdp_umem *ixgbe_xsk_umem(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *ring);
+int ixgbe_xsk_umem_query(struct ixgbe_adapter *adapter, struct xdp_umem **umem,
+ u16 qid);
+int ixgbe_xsk_umem_setup(struct ixgbe_adapter *adapter, struct xdp_umem *umem,
+ u16 qid);
+
+void ixgbe_zca_free(struct zero_copy_allocator *alloc, unsigned long handle);
+
+void ixgbe_alloc_rx_buffers_zc(struct ixgbe_ring *rx_ring, u16 cleaned_count);
+int ixgbe_clean_rx_irq_zc(struct ixgbe_q_vector *q_vector,
+ struct ixgbe_ring *rx_ring,
+ const int budget);
+void ixgbe_xsk_clean_rx_ring(struct ixgbe_ring *rx_ring);
+bool ixgbe_clean_xdp_tx_irq(struct ixgbe_q_vector *q_vector,
+ struct ixgbe_ring *tx_ring, int napi_budget);
+int ixgbe_xsk_async_xmit(struct net_device *dev, u32 queue_id);
+void ixgbe_xsk_clean_tx_ring(struct ixgbe_ring *tx_ring);
+
+#endif /* #define _IXGBE_TXRX_COMMON_H_ */
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
index 41bcbb337e83..84f2dba39e36 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
@@ -924,6 +924,9 @@ struct ixgbe_nvm_version {
/* Firmware Semaphore Register */
#define IXGBE_FWSM_MODE_MASK 0xE
#define IXGBE_FWSM_FW_MODE_PT 0x4
+#define IXGBE_FWSM_FW_NVM_RECOVERY_MODE BIT(5)
+#define IXGBE_FWSM_EXT_ERR_IND_MASK 0x01F80000
+#define IXGBE_FWSM_FW_VAL_BIT BIT(15)
/* ARC Subsystem registers */
#define IXGBE_HICR 0x15F00
@@ -3461,6 +3464,7 @@ struct ixgbe_mac_operations {
const char *);
s32 (*get_thermal_sensor_data)(struct ixgbe_hw *);
s32 (*init_thermal_sensor_thresh)(struct ixgbe_hw *hw);
+ bool (*fw_recovery_mode)(struct ixgbe_hw *hw);
void (*disable_rx)(struct ixgbe_hw *hw);
void (*enable_rx)(struct ixgbe_hw *hw);
void (*set_source_address_pruning)(struct ixgbe_hw *, bool,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
index a8148c7126e5..10dbaf4f6e80 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
@@ -1247,6 +1247,20 @@ static s32 ixgbe_get_bus_info_X550em(struct ixgbe_hw *hw)
return 0;
}
+/**
+ * ixgbe_fw_recovery_mode - Check FW NVM recovery mode
+ * @hw: pointer t hardware structure
+ *
+ * Returns true if in FW NVM recovery mode.
+ */
+static bool ixgbe_fw_recovery_mode_X550(struct ixgbe_hw *hw)
+{
+ u32 fwsm;
+
+ fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM(hw));
+ return !!(fwsm & IXGBE_FWSM_FW_NVM_RECOVERY_MODE);
+}
+
/** ixgbe_disable_rx_x550 - Disable RX unit
*
* Enables the Rx DMA unit for x550
@@ -3816,6 +3830,7 @@ static s32 ixgbe_write_phy_reg_x550a(struct ixgbe_hw *hw, u32 reg_addr,
.enable_rx_buff = &ixgbe_enable_rx_buff_generic, \
.get_thermal_sensor_data = NULL, \
.init_thermal_sensor_thresh = NULL, \
+ .fw_recovery_mode = &ixgbe_fw_recovery_mode_X550, \
.enable_rx = &ixgbe_enable_rx_generic, \
.disable_rx = &ixgbe_disable_rx_x550, \
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c
new file mode 100644
index 000000000000..65c3e2c979d4
--- /dev/null
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c
@@ -0,0 +1,801 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2018 Intel Corporation. */
+
+#include <linux/bpf_trace.h>
+#include <net/xdp_sock.h>
+#include <net/xdp.h>
+
+#include "ixgbe.h"
+#include "ixgbe_txrx_common.h"
+
+struct xdp_umem *ixgbe_xsk_umem(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *ring)
+{
+ bool xdp_on = READ_ONCE(adapter->xdp_prog);
+ int qid = ring->ring_idx;
+
+ if (!adapter->xsk_umems || !adapter->xsk_umems[qid] ||
+ qid >= adapter->num_xsk_umems || !xdp_on)
+ return NULL;
+
+ return adapter->xsk_umems[qid];
+}
+
+static int ixgbe_alloc_xsk_umems(struct ixgbe_adapter *adapter)
+{
+ if (adapter->xsk_umems)
+ return 0;
+
+ adapter->num_xsk_umems_used = 0;
+ adapter->num_xsk_umems = adapter->num_rx_queues;
+ adapter->xsk_umems = kcalloc(adapter->num_xsk_umems,
+ sizeof(*adapter->xsk_umems),
+ GFP_KERNEL);
+ if (!adapter->xsk_umems) {
+ adapter->num_xsk_umems = 0;
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int ixgbe_add_xsk_umem(struct ixgbe_adapter *adapter,
+ struct xdp_umem *umem,
+ u16 qid)
+{
+ int err;
+
+ err = ixgbe_alloc_xsk_umems(adapter);
+ if (err)
+ return err;
+
+ adapter->xsk_umems[qid] = umem;
+ adapter->num_xsk_umems_used++;
+
+ return 0;
+}
+
+static void ixgbe_remove_xsk_umem(struct ixgbe_adapter *adapter, u16 qid)
+{
+ adapter->xsk_umems[qid] = NULL;
+ adapter->num_xsk_umems_used--;
+
+ if (adapter->num_xsk_umems == 0) {
+ kfree(adapter->xsk_umems);
+ adapter->xsk_umems = NULL;
+ adapter->num_xsk_umems = 0;
+ }
+}
+
+static int ixgbe_xsk_umem_dma_map(struct ixgbe_adapter *adapter,
+ struct xdp_umem *umem)
+{
+ struct device *dev = &adapter->pdev->dev;
+ unsigned int i, j;
+ dma_addr_t dma;
+
+ for (i = 0; i < umem->npgs; i++) {
+ dma = dma_map_page_attrs(dev, umem->pgs[i], 0, PAGE_SIZE,
+ DMA_BIDIRECTIONAL, IXGBE_RX_DMA_ATTR);
+ if (dma_mapping_error(dev, dma))
+ goto out_unmap;
+
+ umem->pages[i].dma = dma;
+ }
+
+ return 0;
+
+out_unmap:
+ for (j = 0; j < i; j++) {
+ dma_unmap_page_attrs(dev, umem->pages[i].dma, PAGE_SIZE,
+ DMA_BIDIRECTIONAL, IXGBE_RX_DMA_ATTR);
+ umem->pages[i].dma = 0;
+ }
+
+ return -1;
+}
+
+static void ixgbe_xsk_umem_dma_unmap(struct ixgbe_adapter *adapter,
+ struct xdp_umem *umem)
+{
+ struct device *dev = &adapter->pdev->dev;
+ unsigned int i;
+
+ for (i = 0; i < umem->npgs; i++) {
+ dma_unmap_page_attrs(dev, umem->pages[i].dma, PAGE_SIZE,
+ DMA_BIDIRECTIONAL, IXGBE_RX_DMA_ATTR);
+
+ umem->pages[i].dma = 0;
+ }
+}
+
+static int ixgbe_xsk_umem_enable(struct ixgbe_adapter *adapter,
+ struct xdp_umem *umem,
+ u16 qid)
+{
+ struct xdp_umem_fq_reuse *reuseq;
+ bool if_running;
+ int err;
+
+ if (qid >= adapter->num_rx_queues)
+ return -EINVAL;
+
+ if (adapter->xsk_umems) {
+ if (qid >= adapter->num_xsk_umems)
+ return -EINVAL;
+ if (adapter->xsk_umems[qid])
+ return -EBUSY;
+ }
+
+ reuseq = xsk_reuseq_prepare(adapter->rx_ring[0]->count);
+ if (!reuseq)
+ return -ENOMEM;
+
+ xsk_reuseq_free(xsk_reuseq_swap(umem, reuseq));
+
+ err = ixgbe_xsk_umem_dma_map(adapter, umem);
+ if (err)
+ return err;
+
+ if_running = netif_running(adapter->netdev) &&
+ READ_ONCE(adapter->xdp_prog);
+
+ if (if_running)
+ ixgbe_txrx_ring_disable(adapter, qid);
+
+ err = ixgbe_add_xsk_umem(adapter, umem, qid);
+
+ if (if_running)
+ ixgbe_txrx_ring_enable(adapter, qid);
+
+ return err;
+}
+
+static int ixgbe_xsk_umem_disable(struct ixgbe_adapter *adapter, u16 qid)
+{
+ bool if_running;
+
+ if (!adapter->xsk_umems || qid >= adapter->num_xsk_umems ||
+ !adapter->xsk_umems[qid])
+ return -EINVAL;
+
+ if_running = netif_running(adapter->netdev) &&
+ READ_ONCE(adapter->xdp_prog);
+
+ if (if_running)
+ ixgbe_txrx_ring_disable(adapter, qid);
+
+ ixgbe_xsk_umem_dma_unmap(adapter, adapter->xsk_umems[qid]);
+ ixgbe_remove_xsk_umem(adapter, qid);
+
+ if (if_running)
+ ixgbe_txrx_ring_enable(adapter, qid);
+
+ return 0;
+}
+
+int ixgbe_xsk_umem_query(struct ixgbe_adapter *adapter, struct xdp_umem **umem,
+ u16 qid)
+{
+ if (qid >= adapter->num_rx_queues)
+ return -EINVAL;
+
+ if (adapter->xsk_umems) {
+ if (qid >= adapter->num_xsk_umems)
+ return -EINVAL;
+ *umem = adapter->xsk_umems[qid];
+ return 0;
+ }
+
+ *umem = NULL;
+ return 0;
+}
+
+int ixgbe_xsk_umem_setup(struct ixgbe_adapter *adapter, struct xdp_umem *umem,
+ u16 qid)
+{
+ return umem ? ixgbe_xsk_umem_enable(adapter, umem, qid) :
+ ixgbe_xsk_umem_disable(adapter, qid);
+}
+
+static int ixgbe_run_xdp_zc(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *rx_ring,
+ struct xdp_buff *xdp)
+{
+ int err, result = IXGBE_XDP_PASS;
+ struct bpf_prog *xdp_prog;
+ 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);
+ xdp->handle += xdp->data - xdp->data_hard_start;
+ switch (act) {
+ case XDP_PASS:
+ break;
+ case XDP_TX:
+ xdpf = convert_to_xdp_frame(xdp);
+ if (unlikely(!xdpf)) {
+ result = IXGBE_XDP_CONSUMED;
+ break;
+ }
+ result = ixgbe_xmit_xdp_ring(adapter, xdpf);
+ break;
+ case XDP_REDIRECT:
+ err = xdp_do_redirect(rx_ring->netdev, xdp, xdp_prog);
+ result = !err ? IXGBE_XDP_REDIR : IXGBE_XDP_CONSUMED;
+ break;
+ default:
+ bpf_warn_invalid_xdp_action(act);
+ /* fallthrough */
+ case XDP_ABORTED:
+ trace_xdp_exception(rx_ring->netdev, xdp_prog, act);
+ /* fallthrough -- handle aborts by dropping packet */
+ case XDP_DROP:
+ result = IXGBE_XDP_CONSUMED;
+ break;
+ }
+ rcu_read_unlock();
+ return result;
+}
+
+static struct
+ixgbe_rx_buffer *ixgbe_get_rx_buffer_zc(struct ixgbe_ring *rx_ring,
+ unsigned int size)
+{
+ struct ixgbe_rx_buffer *bi;
+
+ bi = &rx_ring->rx_buffer_info[rx_ring->next_to_clean];
+
+ /* we are reusing so sync this buffer for CPU use */
+ dma_sync_single_range_for_cpu(rx_ring->dev,
+ bi->dma, 0,
+ size,
+ DMA_BIDIRECTIONAL);
+
+ return bi;
+}
+
+static void ixgbe_reuse_rx_buffer_zc(struct ixgbe_ring *rx_ring,
+ struct ixgbe_rx_buffer *obi)
+{
+ unsigned long mask = (unsigned long)rx_ring->xsk_umem->chunk_mask;
+ u64 hr = rx_ring->xsk_umem->headroom + XDP_PACKET_HEADROOM;
+ u16 nta = rx_ring->next_to_alloc;
+ struct ixgbe_rx_buffer *nbi;
+
+ nbi = &rx_ring->rx_buffer_info[rx_ring->next_to_alloc];
+ /* update, and store next to alloc */
+ nta++;
+ rx_ring->next_to_alloc = (nta < rx_ring->count) ? nta : 0;
+
+ /* transfer page from old buffer to new buffer */
+ nbi->dma = obi->dma & mask;
+ nbi->dma += hr;
+
+ nbi->addr = (void *)((unsigned long)obi->addr & mask);
+ nbi->addr += hr;
+
+ nbi->handle = obi->handle & mask;
+ nbi->handle += rx_ring->xsk_umem->headroom;
+
+ obi->addr = NULL;
+ obi->skb = NULL;
+}
+
+void ixgbe_zca_free(struct zero_copy_allocator *alloc, unsigned long handle)
+{
+ struct ixgbe_rx_buffer *bi;
+ struct ixgbe_ring *rx_ring;
+ u64 hr, mask;
+ u16 nta;
+
+ rx_ring = container_of(alloc, struct ixgbe_ring, zca);
+ hr = rx_ring->xsk_umem->headroom + XDP_PACKET_HEADROOM;
+ mask = rx_ring->xsk_umem->chunk_mask;
+
+ nta = rx_ring->next_to_alloc;
+ bi = rx_ring->rx_buffer_info;
+
+ nta++;
+ rx_ring->next_to_alloc = (nta < rx_ring->count) ? nta : 0;
+
+ handle &= mask;
+
+ bi->dma = xdp_umem_get_dma(rx_ring->xsk_umem, handle);
+ bi->dma += hr;
+
+ bi->addr = xdp_umem_get_data(rx_ring->xsk_umem, handle);
+ bi->addr += hr;
+
+ bi->handle = (u64)handle + rx_ring->xsk_umem->headroom;
+}
+
+static bool ixgbe_alloc_buffer_zc(struct ixgbe_ring *rx_ring,
+ struct ixgbe_rx_buffer *bi)
+{
+ struct xdp_umem *umem = rx_ring->xsk_umem;
+ void *addr = bi->addr;
+ u64 handle, hr;
+
+ if (addr)
+ return true;
+
+ if (!xsk_umem_peek_addr(umem, &handle)) {
+ rx_ring->rx_stats.alloc_rx_page_failed++;
+ return false;
+ }
+
+ hr = umem->headroom + XDP_PACKET_HEADROOM;
+
+ bi->dma = xdp_umem_get_dma(umem, handle);
+ bi->dma += hr;
+
+ bi->addr = xdp_umem_get_data(umem, handle);
+ bi->addr += hr;
+
+ bi->handle = handle + umem->headroom;
+
+ xsk_umem_discard_addr(umem);
+ return true;
+}
+
+static bool ixgbe_alloc_buffer_slow_zc(struct ixgbe_ring *rx_ring,
+ struct ixgbe_rx_buffer *bi)
+{
+ struct xdp_umem *umem = rx_ring->xsk_umem;
+ u64 handle, hr;
+
+ if (!xsk_umem_peek_addr_rq(umem, &handle)) {
+ rx_ring->rx_stats.alloc_rx_page_failed++;
+ return false;
+ }
+
+ handle &= rx_ring->xsk_umem->chunk_mask;
+
+ hr = umem->headroom + XDP_PACKET_HEADROOM;
+
+ bi->dma = xdp_umem_get_dma(umem, handle);
+ bi->dma += hr;
+
+ bi->addr = xdp_umem_get_data(umem, handle);
+ bi->addr += hr;
+
+ bi->handle = handle + umem->headroom;
+
+ xsk_umem_discard_addr_rq(umem);
+ return true;
+}
+
+static __always_inline bool
+__ixgbe_alloc_rx_buffers_zc(struct ixgbe_ring *rx_ring, u16 cleaned_count,
+ bool alloc(struct ixgbe_ring *rx_ring,
+ struct ixgbe_rx_buffer *bi))
+{
+ union ixgbe_adv_rx_desc *rx_desc;
+ struct ixgbe_rx_buffer *bi;
+ u16 i = rx_ring->next_to_use;
+ bool ok = true;
+
+ /* nothing to do */
+ if (!cleaned_count)
+ return true;
+
+ rx_desc = IXGBE_RX_DESC(rx_ring, i);
+ bi = &rx_ring->rx_buffer_info[i];
+ i -= rx_ring->count;
+
+ do {
+ if (!alloc(rx_ring, bi)) {
+ ok = false;
+ break;
+ }
+
+ /* sync the buffer for use by the device */
+ dma_sync_single_range_for_device(rx_ring->dev, bi->dma,
+ bi->page_offset,
+ rx_ring->rx_buf_len,
+ DMA_BIDIRECTIONAL);
+
+ /* Refresh the desc even if buffer_addrs didn't change
+ * because each write-back erases this info.
+ */
+ rx_desc->read.pkt_addr = cpu_to_le64(bi->dma);
+
+ rx_desc++;
+ bi++;
+ i++;
+ if (unlikely(!i)) {
+ rx_desc = IXGBE_RX_DESC(rx_ring, 0);
+ bi = rx_ring->rx_buffer_info;
+ i -= rx_ring->count;
+ }
+
+ /* clear the length for the next_to_use descriptor */
+ rx_desc->wb.upper.length = 0;
+
+ cleaned_count--;
+ } while (cleaned_count);
+
+ i += rx_ring->count;
+
+ if (rx_ring->next_to_use != i) {
+ rx_ring->next_to_use = i;
+
+ /* update next to alloc since we have filled the ring */
+ rx_ring->next_to_alloc = 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, rx_ring->tail);
+ }
+
+ return ok;
+}
+
+void ixgbe_alloc_rx_buffers_zc(struct ixgbe_ring *rx_ring, u16 count)
+{
+ __ixgbe_alloc_rx_buffers_zc(rx_ring, count,
+ ixgbe_alloc_buffer_slow_zc);
+}
+
+static bool ixgbe_alloc_rx_buffers_fast_zc(struct ixgbe_ring *rx_ring,
+ u16 count)
+{
+ return __ixgbe_alloc_rx_buffers_zc(rx_ring, count,
+ ixgbe_alloc_buffer_zc);
+}
+
+static struct sk_buff *ixgbe_construct_skb_zc(struct ixgbe_ring *rx_ring,
+ struct ixgbe_rx_buffer *bi,
+ struct xdp_buff *xdp)
+{
+ unsigned int metasize = xdp->data - xdp->data_meta;
+ unsigned int datasize = xdp->data_end - xdp->data;
+ struct sk_buff *skb;
+
+ /* allocate a skb to store the frags */
+ skb = __napi_alloc_skb(&rx_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 - xdp->data_hard_start);
+ memcpy(__skb_put(skb, datasize), xdp->data, datasize);
+ if (metasize)
+ skb_metadata_set(skb, metasize);
+
+ ixgbe_reuse_rx_buffer_zc(rx_ring, bi);
+ return skb;
+}
+
+static void ixgbe_inc_ntc(struct ixgbe_ring *rx_ring)
+{
+ u32 ntc = rx_ring->next_to_clean + 1;
+
+ ntc = (ntc < rx_ring->count) ? ntc : 0;
+ rx_ring->next_to_clean = ntc;
+ prefetch(IXGBE_RX_DESC(rx_ring, ntc));
+}
+
+int ixgbe_clean_rx_irq_zc(struct ixgbe_q_vector *q_vector,
+ struct ixgbe_ring *rx_ring,
+ const int budget)
+{
+ unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+ struct ixgbe_adapter *adapter = q_vector->adapter;
+ u16 cleaned_count = ixgbe_desc_unused(rx_ring);
+ unsigned int xdp_res, xdp_xmit = 0;
+ bool failure = false;
+ struct sk_buff *skb;
+ struct xdp_buff xdp;
+
+ xdp.rxq = &rx_ring->xdp_rxq;
+
+ while (likely(total_rx_packets < budget)) {
+ union ixgbe_adv_rx_desc *rx_desc;
+ struct ixgbe_rx_buffer *bi;
+ unsigned int size;
+
+ /* return some buffers to hardware, one at a time is too slow */
+ if (cleaned_count >= IXGBE_RX_BUFFER_WRITE) {
+ failure = failure ||
+ !ixgbe_alloc_rx_buffers_fast_zc(rx_ring,
+ cleaned_count);
+ cleaned_count = 0;
+ }
+
+ rx_desc = IXGBE_RX_DESC(rx_ring, rx_ring->next_to_clean);
+ size = le16_to_cpu(rx_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 = ixgbe_get_rx_buffer_zc(rx_ring, size);
+
+ if (unlikely(!ixgbe_test_staterr(rx_desc,
+ IXGBE_RXD_STAT_EOP))) {
+ struct ixgbe_rx_buffer *next_bi;
+
+ ixgbe_reuse_rx_buffer_zc(rx_ring, bi);
+ ixgbe_inc_ntc(rx_ring);
+ next_bi =
+ &rx_ring->rx_buffer_info[rx_ring->next_to_clean];
+ next_bi->skb = ERR_PTR(-EINVAL);
+ continue;
+ }
+
+ if (unlikely(bi->skb)) {
+ ixgbe_reuse_rx_buffer_zc(rx_ring, bi);
+ ixgbe_inc_ntc(rx_ring);
+ continue;
+ }
+
+ xdp.data = bi->addr;
+ xdp.data_meta = xdp.data;
+ xdp.data_hard_start = xdp.data - XDP_PACKET_HEADROOM;
+ xdp.data_end = xdp.data + size;
+ xdp.handle = bi->handle;
+
+ xdp_res = ixgbe_run_xdp_zc(adapter, rx_ring, &xdp);
+
+ if (xdp_res) {
+ if (xdp_res & (IXGBE_XDP_TX | IXGBE_XDP_REDIR)) {
+ xdp_xmit |= xdp_res;
+ bi->addr = NULL;
+ bi->skb = NULL;
+ } else {
+ ixgbe_reuse_rx_buffer_zc(rx_ring, bi);
+ }
+ total_rx_packets++;
+ total_rx_bytes += size;
+
+ cleaned_count++;
+ ixgbe_inc_ntc(rx_ring);
+ continue;
+ }
+
+ /* XDP_PASS path */
+ skb = ixgbe_construct_skb_zc(rx_ring, bi, &xdp);
+ if (!skb) {
+ rx_ring->rx_stats.alloc_rx_buff_failed++;
+ break;
+ }
+
+ cleaned_count++;
+ ixgbe_inc_ntc(rx_ring);
+
+ if (eth_skb_pad(skb))
+ continue;
+
+ total_rx_bytes += skb->len;
+ total_rx_packets++;
+
+ ixgbe_process_skb_fields(rx_ring, rx_desc, skb);
+ ixgbe_rx_skb(q_vector, skb);
+ }
+
+ if (xdp_xmit & IXGBE_XDP_REDIR)
+ xdp_do_flush_map();
+
+ if (xdp_xmit & IXGBE_XDP_TX) {
+ struct ixgbe_ring *ring = adapter->xdp_ring[smp_processor_id()];
+
+ /* Force memory writes to complete before letting h/w
+ * know there are new descriptors to fetch.
+ */
+ wmb();
+ writel(ring->next_to_use, ring->tail);
+ }
+
+ u64_stats_update_begin(&rx_ring->syncp);
+ rx_ring->stats.packets += total_rx_packets;
+ rx_ring->stats.bytes += total_rx_bytes;
+ u64_stats_update_end(&rx_ring->syncp);
+ q_vector->rx.total_packets += total_rx_packets;
+ q_vector->rx.total_bytes += total_rx_bytes;
+
+ return failure ? budget : (int)total_rx_packets;
+}
+
+void ixgbe_xsk_clean_rx_ring(struct ixgbe_ring *rx_ring)
+{
+ u16 i = rx_ring->next_to_clean;
+ struct ixgbe_rx_buffer *bi = &rx_ring->rx_buffer_info[i];
+
+ while (i != rx_ring->next_to_alloc) {
+ xsk_umem_fq_reuse(rx_ring->xsk_umem, bi->handle);
+ i++;
+ bi++;
+ if (i == rx_ring->count) {
+ i = 0;
+ bi = rx_ring->rx_buffer_info;
+ }
+ }
+}
+
+static bool ixgbe_xmit_zc(struct ixgbe_ring *xdp_ring, unsigned int budget)
+{
+ union ixgbe_adv_tx_desc *tx_desc = NULL;
+ struct ixgbe_tx_buffer *tx_bi;
+ bool work_done = true;
+ u32 len, cmd_type;
+ dma_addr_t dma;
+
+ while (budget-- > 0) {
+ if (unlikely(!ixgbe_desc_unused(xdp_ring))) {
+ work_done = false;
+ break;
+ }
+
+ if (!xsk_umem_consume_tx(xdp_ring->xsk_umem, &dma, &len))
+ break;
+
+ dma_sync_single_for_device(xdp_ring->dev, dma, len,
+ DMA_BIDIRECTIONAL);
+
+ tx_bi = &xdp_ring->tx_buffer_info[xdp_ring->next_to_use];
+ tx_bi->bytecount = len;
+ tx_bi->xdpf = NULL;
+
+ tx_desc = IXGBE_TX_DESC(xdp_ring, xdp_ring->next_to_use);
+ tx_desc->read.buffer_addr = cpu_to_le64(dma);
+
+ /* put descriptor type bits */
+ cmd_type = IXGBE_ADVTXD_DTYP_DATA |
+ IXGBE_ADVTXD_DCMD_DEXT |
+ IXGBE_ADVTXD_DCMD_IFCS;
+ cmd_type |= len | IXGBE_TXD_CMD;
+ tx_desc->read.cmd_type_len = cpu_to_le32(cmd_type);
+ tx_desc->read.olinfo_status =
+ cpu_to_le32(len << IXGBE_ADVTXD_PAYLEN_SHIFT);
+
+ xdp_ring->next_to_use++;
+ if (xdp_ring->next_to_use == xdp_ring->count)
+ xdp_ring->next_to_use = 0;
+ }
+
+ if (tx_desc) {
+ ixgbe_xdp_ring_update_tail(xdp_ring);
+ xsk_umem_consume_tx_done(xdp_ring->xsk_umem);
+ }
+
+ return !!budget && work_done;
+}
+
+static void ixgbe_clean_xdp_tx_buffer(struct ixgbe_ring *tx_ring,
+ struct ixgbe_tx_buffer *tx_bi)
+{
+ xdp_return_frame(tx_bi->xdpf);
+ dma_unmap_single(tx_ring->dev,
+ dma_unmap_addr(tx_bi, dma),
+ dma_unmap_len(tx_bi, len), DMA_TO_DEVICE);
+ dma_unmap_len_set(tx_bi, len, 0);
+}
+
+bool ixgbe_clean_xdp_tx_irq(struct ixgbe_q_vector *q_vector,
+ struct ixgbe_ring *tx_ring, int napi_budget)
+{
+ unsigned int total_packets = 0, total_bytes = 0;
+ u32 i = tx_ring->next_to_clean, xsk_frames = 0;
+ unsigned int budget = q_vector->tx.work_limit;
+ struct xdp_umem *umem = tx_ring->xsk_umem;
+ union ixgbe_adv_tx_desc *tx_desc;
+ struct ixgbe_tx_buffer *tx_bi;
+ bool xmit_done;
+
+ tx_bi = &tx_ring->tx_buffer_info[i];
+ tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ i -= tx_ring->count;
+
+ do {
+ if (!(tx_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)))
+ break;
+
+ total_bytes += tx_bi->bytecount;
+ total_packets += tx_bi->gso_segs;
+
+ if (tx_bi->xdpf)
+ ixgbe_clean_xdp_tx_buffer(tx_ring, tx_bi);
+ else
+ xsk_frames++;
+
+ tx_bi->xdpf = NULL;
+ total_bytes += tx_bi->bytecount;
+
+ tx_bi++;
+ tx_desc++;
+ i++;
+ if (unlikely(!i)) {
+ i -= tx_ring->count;
+ tx_bi = tx_ring->tx_buffer_info;
+ tx_desc = IXGBE_TX_DESC(tx_ring, 0);
+ }
+
+ /* issue prefetch for next Tx descriptor */
+ prefetch(tx_desc);
+
+ /* update budget accounting */
+ budget--;
+ } while (likely(budget));
+
+ i += tx_ring->count;
+ tx_ring->next_to_clean = i;
+
+ u64_stats_update_begin(&tx_ring->syncp);
+ tx_ring->stats.bytes += total_bytes;
+ tx_ring->stats.packets += total_packets;
+ u64_stats_update_end(&tx_ring->syncp);
+ q_vector->tx.total_bytes += total_bytes;
+ q_vector->tx.total_packets += total_packets;
+
+ if (xsk_frames)
+ xsk_umem_complete_tx(umem, xsk_frames);
+
+ xmit_done = ixgbe_xmit_zc(tx_ring, q_vector->tx.work_limit);
+ return budget > 0 && xmit_done;
+}
+
+int ixgbe_xsk_async_xmit(struct net_device *dev, u32 qid)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(dev);
+ struct ixgbe_ring *ring;
+
+ if (test_bit(__IXGBE_DOWN, &adapter->state))
+ return -ENETDOWN;
+
+ if (!READ_ONCE(adapter->xdp_prog))
+ return -ENXIO;
+
+ if (qid >= adapter->num_xdp_queues)
+ return -ENXIO;
+
+ if (!adapter->xsk_umems || !adapter->xsk_umems[qid])
+ return -ENXIO;
+
+ ring = adapter->xdp_ring[qid];
+ if (!napi_if_scheduled_mark_missed(&ring->q_vector->napi)) {
+ u64 eics = BIT_ULL(ring->q_vector->v_idx);
+
+ ixgbe_irq_rearm_queues(adapter, eics);
+ }
+
+ return 0;
+}
+
+void ixgbe_xsk_clean_tx_ring(struct ixgbe_ring *tx_ring)
+{
+ u16 ntc = tx_ring->next_to_clean, ntu = tx_ring->next_to_use;
+ struct xdp_umem *umem = tx_ring->xsk_umem;
+ struct ixgbe_tx_buffer *tx_bi;
+ u32 xsk_frames = 0;
+
+ while (ntc != ntu) {
+ tx_bi = &tx_ring->tx_buffer_info[ntc];
+
+ if (tx_bi->xdpf)
+ ixgbe_clean_xdp_tx_buffer(tx_ring, tx_bi);
+ else
+ xsk_frames++;
+
+ tx_bi->xdpf = NULL;
+
+ ntc++;
+ if (ntc == tx_ring->count)
+ ntc = 0;
+ }
+
+ if (xsk_frames)
+ xsk_umem_complete_tx(umem, xsk_frames);
+}
diff --git a/drivers/net/ethernet/intel/ixgbevf/Makefile b/drivers/net/ethernet/intel/ixgbevf/Makefile
index aba1e6a37a6a..186a4bb24fde 100644
--- a/drivers/net/ethernet/intel/ixgbevf/Makefile
+++ b/drivers/net/ethernet/intel/ixgbevf/Makefile
@@ -10,4 +10,5 @@ ixgbevf-objs := vf.o \
mbx.o \
ethtool.o \
ixgbevf_main.o
+ixgbevf-$(CONFIG_IXGBEVF_IPSEC) += ipsec.o
diff --git a/drivers/net/ethernet/intel/ixgbevf/defines.h b/drivers/net/ethernet/intel/ixgbevf/defines.h
index 700d8eb2f6f8..6bace746eaac 100644
--- a/drivers/net/ethernet/intel/ixgbevf/defines.h
+++ b/drivers/net/ethernet/intel/ixgbevf/defines.h
@@ -133,9 +133,14 @@ typedef u32 ixgbe_link_speed;
#define IXGBE_RXDADV_STAT_FCSTAT_NODDP 0x00000010 /* 01: Ctxt w/o DDP */
#define IXGBE_RXDADV_STAT_FCSTAT_FCPRSP 0x00000020 /* 10: Recv. FCP_RSP */
#define IXGBE_RXDADV_STAT_FCSTAT_DDP 0x00000030 /* 11: Ctxt w/ DDP */
+#define IXGBE_RXDADV_STAT_SECP 0x00020000 /* IPsec/MACsec pkt found */
#define IXGBE_RXDADV_RSSTYPE_MASK 0x0000000F
#define IXGBE_RXDADV_PKTTYPE_MASK 0x0000FFF0
+#define IXGBE_RXDADV_PKTTYPE_IPV4 0x00000010 /* IPv4 hdr present */
+#define IXGBE_RXDADV_PKTTYPE_IPV6 0x00000040 /* IPv6 hdr present */
+#define IXGBE_RXDADV_PKTTYPE_IPSEC_ESP 0x00001000 /* IPSec ESP */
+#define IXGBE_RXDADV_PKTTYPE_IPSEC_AH 0x00002000 /* IPSec AH */
#define IXGBE_RXDADV_PKTTYPE_MASK_EX 0x0001FFF0
#define IXGBE_RXDADV_HDRBUFLEN_MASK 0x00007FE0
#define IXGBE_RXDADV_RSCCNT_MASK 0x001E0000
@@ -229,7 +234,7 @@ union ixgbe_adv_rx_desc {
/* Context descriptors */
struct ixgbe_adv_tx_context_desc {
__le32 vlan_macip_lens;
- __le32 seqnum_seed;
+ __le32 fceof_saidx;
__le32 type_tucmd_mlhl;
__le32 mss_l4len_idx;
};
@@ -250,9 +255,12 @@ struct ixgbe_adv_tx_context_desc {
#define IXGBE_ADVTXD_TUCMD_L4T_UDP 0x00000000 /* L4 Packet TYPE of UDP */
#define IXGBE_ADVTXD_TUCMD_L4T_TCP 0x00000800 /* L4 Packet TYPE of TCP */
#define IXGBE_ADVTXD_TUCMD_L4T_SCTP 0x00001000 /* L4 Packet TYPE of SCTP */
+#define IXGBE_ADVTXD_TUCMD_IPSEC_TYPE_ESP 0x00002000 /* IPSec Type ESP */
+#define IXGBE_ADVTXD_TUCMD_IPSEC_ENCRYPT_EN 0x00004000 /* ESP Encrypt Enable */
#define IXGBE_ADVTXD_IDX_SHIFT 4 /* Adv desc Index shift */
#define IXGBE_ADVTXD_CC 0x00000080 /* Check Context */
#define IXGBE_ADVTXD_POPTS_SHIFT 8 /* Adv desc POPTS shift */
+#define IXGBE_ADVTXD_POPTS_IPSEC 0x00000400 /* IPSec offload request */
#define IXGBE_ADVTXD_POPTS_IXSM (IXGBE_TXD_POPTS_IXSM << \
IXGBE_ADVTXD_POPTS_SHIFT)
#define IXGBE_ADVTXD_POPTS_TXSM (IXGBE_TXD_POPTS_TXSM << \
diff --git a/drivers/net/ethernet/intel/ixgbevf/ethtool.c b/drivers/net/ethernet/intel/ixgbevf/ethtool.c
index 631c91046f39..5399787e07af 100644
--- a/drivers/net/ethernet/intel/ixgbevf/ethtool.c
+++ b/drivers/net/ethernet/intel/ixgbevf/ethtool.c
@@ -55,6 +55,8 @@ static struct ixgbe_stats ixgbevf_gstrings_stats[] = {
IXGBEVF_STAT("alloc_rx_page", alloc_rx_page),
IXGBEVF_STAT("alloc_rx_page_failed", alloc_rx_page_failed),
IXGBEVF_STAT("alloc_rx_buff_failed", alloc_rx_buff_failed),
+ IXGBEVF_STAT("tx_ipsec", tx_ipsec),
+ IXGBEVF_STAT("rx_ipsec", rx_ipsec),
};
#define IXGBEVF_QUEUE_STATS_LEN ( \
diff --git a/drivers/net/ethernet/intel/ixgbevf/ipsec.c b/drivers/net/ethernet/intel/ixgbevf/ipsec.c
new file mode 100644
index 000000000000..e8a3231be0bf
--- /dev/null
+++ b/drivers/net/ethernet/intel/ixgbevf/ipsec.c
@@ -0,0 +1,670 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2018 Oracle and/or its affiliates. All rights reserved. */
+
+#include "ixgbevf.h"
+#include <net/xfrm.h>
+#include <crypto/aead.h>
+
+#define IXGBE_IPSEC_KEY_BITS 160
+static const char aes_gcm_name[] = "rfc4106(gcm(aes))";
+
+/**
+ * ixgbevf_ipsec_set_pf_sa - ask the PF to set up an SA
+ * @adapter: board private structure
+ * @xs: xfrm info to be sent to the PF
+ *
+ * Returns: positive offload handle from the PF, or negative error code
+ **/
+static int ixgbevf_ipsec_set_pf_sa(struct ixgbevf_adapter *adapter,
+ struct xfrm_state *xs)
+{
+ u32 msgbuf[IXGBE_VFMAILBOX_SIZE] = { 0 };
+ struct ixgbe_hw *hw = &adapter->hw;
+ struct sa_mbx_msg *sam;
+ int ret;
+
+ /* send the important bits to the PF */
+ sam = (struct sa_mbx_msg *)(&msgbuf[1]);
+ sam->flags = xs->xso.flags;
+ sam->spi = xs->id.spi;
+ sam->proto = xs->id.proto;
+ sam->family = xs->props.family;
+
+ if (xs->props.family == AF_INET6)
+ memcpy(sam->addr, &xs->id.daddr.a6, sizeof(xs->id.daddr.a6));
+ else
+ memcpy(sam->addr, &xs->id.daddr.a4, sizeof(xs->id.daddr.a4));
+ memcpy(sam->key, xs->aead->alg_key, sizeof(sam->key));
+
+ msgbuf[0] = IXGBE_VF_IPSEC_ADD;
+
+ spin_lock_bh(&adapter->mbx_lock);
+
+ ret = hw->mbx.ops.write_posted(hw, msgbuf, IXGBE_VFMAILBOX_SIZE);
+ if (ret)
+ goto out;
+
+ ret = hw->mbx.ops.read_posted(hw, msgbuf, 2);
+ if (ret)
+ goto out;
+
+ ret = (int)msgbuf[1];
+ if (msgbuf[0] & IXGBE_VT_MSGTYPE_NACK && ret >= 0)
+ ret = -1;
+
+out:
+ spin_unlock_bh(&adapter->mbx_lock);
+
+ return ret;
+}
+
+/**
+ * ixgbevf_ipsec_del_pf_sa - ask the PF to delete an SA
+ * @adapter: board private structure
+ * @pfsa: sa index returned from PF when created, -1 for all
+ *
+ * Returns: 0 on success, or negative error code
+ **/
+static int ixgbevf_ipsec_del_pf_sa(struct ixgbevf_adapter *adapter, int pfsa)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 msgbuf[2];
+ int err;
+
+ memset(msgbuf, 0, sizeof(msgbuf));
+ msgbuf[0] = IXGBE_VF_IPSEC_DEL;
+ msgbuf[1] = (u32)pfsa;
+
+ spin_lock_bh(&adapter->mbx_lock);
+
+ err = hw->mbx.ops.write_posted(hw, msgbuf, 2);
+ if (err)
+ goto out;
+
+ err = hw->mbx.ops.read_posted(hw, msgbuf, 2);
+ if (err)
+ goto out;
+
+out:
+ spin_unlock_bh(&adapter->mbx_lock);
+ return err;
+}
+
+/**
+ * ixgbevf_ipsec_restore - restore the IPsec HW settings after a reset
+ * @adapter: board private structure
+ *
+ * Reload the HW tables from the SW tables after they've been bashed
+ * by a chip reset. While we're here, make sure any stale VF data is
+ * removed, since we go through reset when num_vfs changes.
+ **/
+void ixgbevf_ipsec_restore(struct ixgbevf_adapter *adapter)
+{
+ struct ixgbevf_ipsec *ipsec = adapter->ipsec;
+ struct net_device *netdev = adapter->netdev;
+ int i;
+
+ if (!(adapter->netdev->features & NETIF_F_HW_ESP))
+ return;
+
+ /* reload the Rx and Tx keys */
+ for (i = 0; i < IXGBE_IPSEC_MAX_SA_COUNT; i++) {
+ struct rx_sa *r = &ipsec->rx_tbl[i];
+ struct tx_sa *t = &ipsec->tx_tbl[i];
+ int ret;
+
+ if (r->used) {
+ ret = ixgbevf_ipsec_set_pf_sa(adapter, r->xs);
+ if (ret < 0)
+ netdev_err(netdev, "reload rx_tbl[%d] failed = %d\n",
+ i, ret);
+ }
+
+ if (t->used) {
+ ret = ixgbevf_ipsec_set_pf_sa(adapter, t->xs);
+ if (ret < 0)
+ netdev_err(netdev, "reload tx_tbl[%d] failed = %d\n",
+ i, ret);
+ }
+ }
+}
+
+/**
+ * ixgbevf_ipsec_find_empty_idx - find the first unused security parameter index
+ * @ipsec: pointer to IPsec struct
+ * @rxtable: true if we need to look in the Rx table
+ *
+ * Returns the first unused index in either the Rx or Tx SA table
+ **/
+static
+int ixgbevf_ipsec_find_empty_idx(struct ixgbevf_ipsec *ipsec, bool rxtable)
+{
+ u32 i;
+
+ if (rxtable) {
+ if (ipsec->num_rx_sa == IXGBE_IPSEC_MAX_SA_COUNT)
+ return -ENOSPC;
+
+ /* search rx sa table */
+ for (i = 0; i < IXGBE_IPSEC_MAX_SA_COUNT; i++) {
+ if (!ipsec->rx_tbl[i].used)
+ return i;
+ }
+ } else {
+ if (ipsec->num_tx_sa == IXGBE_IPSEC_MAX_SA_COUNT)
+ return -ENOSPC;
+
+ /* search tx sa table */
+ for (i = 0; i < IXGBE_IPSEC_MAX_SA_COUNT; i++) {
+ if (!ipsec->tx_tbl[i].used)
+ return i;
+ }
+ }
+
+ return -ENOSPC;
+}
+
+/**
+ * ixgbevf_ipsec_find_rx_state - find the state that matches
+ * @ipsec: pointer to IPsec struct
+ * @daddr: inbound address to match
+ * @proto: protocol to match
+ * @spi: SPI to match
+ * @ip4: true if using an IPv4 address
+ *
+ * Returns a pointer to the matching SA state information
+ **/
+static
+struct xfrm_state *ixgbevf_ipsec_find_rx_state(struct ixgbevf_ipsec *ipsec,
+ __be32 *daddr, u8 proto,
+ __be32 spi, bool ip4)
+{
+ struct xfrm_state *ret = NULL;
+ struct rx_sa *rsa;
+
+ rcu_read_lock();
+ hash_for_each_possible_rcu(ipsec->rx_sa_list, rsa, hlist,
+ (__force u32)spi) {
+ if (spi == rsa->xs->id.spi &&
+ ((ip4 && *daddr == rsa->xs->id.daddr.a4) ||
+ (!ip4 && !memcmp(daddr, &rsa->xs->id.daddr.a6,
+ sizeof(rsa->xs->id.daddr.a6)))) &&
+ proto == rsa->xs->id.proto) {
+ ret = rsa->xs;
+ xfrm_state_hold(ret);
+ break;
+ }
+ }
+ rcu_read_unlock();
+ return ret;
+}
+
+/**
+ * ixgbevf_ipsec_parse_proto_keys - find the key and salt based on the protocol
+ * @xs: pointer to xfrm_state struct
+ * @mykey: pointer to key array to populate
+ * @mysalt: pointer to salt value to populate
+ *
+ * This copies the protocol keys and salt to our own data tables. The
+ * 82599 family only supports the one algorithm.
+ **/
+static int ixgbevf_ipsec_parse_proto_keys(struct xfrm_state *xs,
+ u32 *mykey, u32 *mysalt)
+{
+ struct net_device *dev = xs->xso.dev;
+ unsigned char *key_data;
+ char *alg_name = NULL;
+ int key_len;
+
+ if (!xs->aead) {
+ netdev_err(dev, "Unsupported IPsec algorithm\n");
+ return -EINVAL;
+ }
+
+ if (xs->aead->alg_icv_len != IXGBE_IPSEC_AUTH_BITS) {
+ netdev_err(dev, "IPsec offload requires %d bit authentication\n",
+ IXGBE_IPSEC_AUTH_BITS);
+ return -EINVAL;
+ }
+
+ key_data = &xs->aead->alg_key[0];
+ key_len = xs->aead->alg_key_len;
+ alg_name = xs->aead->alg_name;
+
+ if (strcmp(alg_name, aes_gcm_name)) {
+ netdev_err(dev, "Unsupported IPsec algorithm - please use %s\n",
+ aes_gcm_name);
+ return -EINVAL;
+ }
+
+ /* The key bytes come down in a big endian array of bytes, so
+ * we don't need to do any byte swapping.
+ * 160 accounts for 16 byte key and 4 byte salt
+ */
+ if (key_len > IXGBE_IPSEC_KEY_BITS) {
+ *mysalt = ((u32 *)key_data)[4];
+ } else if (key_len == IXGBE_IPSEC_KEY_BITS) {
+ *mysalt = 0;
+ } else {
+ netdev_err(dev, "IPsec hw offload only supports keys up to 128 bits with a 32 bit salt\n");
+ return -EINVAL;
+ }
+ memcpy(mykey, key_data, 16);
+
+ return 0;
+}
+
+/**
+ * ixgbevf_ipsec_add_sa - program device with a security association
+ * @xs: pointer to transformer state struct
+ **/
+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;
+ u16 sa_idx;
+ int ret;
+
+ 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);
+ return -EINVAL;
+ }
+
+ if (xs->xso.flags & XFRM_OFFLOAD_INBOUND) {
+ struct rx_sa rsa;
+
+ if (xs->calg) {
+ netdev_err(dev, "Compression offload not supported\n");
+ return -EINVAL;
+ }
+
+ /* find the first unused index */
+ ret = ixgbevf_ipsec_find_empty_idx(ipsec, true);
+ if (ret < 0) {
+ netdev_err(dev, "No space for SA in Rx table!\n");
+ return ret;
+ }
+ sa_idx = (u16)ret;
+
+ memset(&rsa, 0, sizeof(rsa));
+ rsa.used = true;
+ rsa.xs = xs;
+
+ if (rsa.xs->id.proto & IPPROTO_ESP)
+ rsa.decrypt = xs->ealg || xs->aead;
+
+ /* get the key and salt */
+ ret = ixgbevf_ipsec_parse_proto_keys(xs, rsa.key, &rsa.salt);
+ if (ret) {
+ netdev_err(dev, "Failed to get key data for Rx SA table\n");
+ return ret;
+ }
+
+ /* get ip for rx sa table */
+ if (xs->props.family == AF_INET6)
+ memcpy(rsa.ipaddr, &xs->id.daddr.a6, 16);
+ else
+ memcpy(&rsa.ipaddr[3], &xs->id.daddr.a4, 4);
+
+ rsa.mode = IXGBE_RXMOD_VALID;
+ if (rsa.xs->id.proto & IPPROTO_ESP)
+ rsa.mode |= IXGBE_RXMOD_PROTO_ESP;
+ if (rsa.decrypt)
+ rsa.mode |= IXGBE_RXMOD_DECRYPT;
+ if (rsa.xs->props.family == AF_INET6)
+ rsa.mode |= IXGBE_RXMOD_IPV6;
+
+ ret = ixgbevf_ipsec_set_pf_sa(adapter, xs);
+ if (ret < 0)
+ return ret;
+ rsa.pfsa = ret;
+
+ /* the preparations worked, so save the info */
+ memcpy(&ipsec->rx_tbl[sa_idx], &rsa, sizeof(rsa));
+
+ xs->xso.offload_handle = sa_idx + IXGBE_IPSEC_BASE_RX_INDEX;
+
+ ipsec->num_rx_sa++;
+
+ /* hash the new entry for faster search in Rx path */
+ hash_add_rcu(ipsec->rx_sa_list, &ipsec->rx_tbl[sa_idx].hlist,
+ (__force u32)rsa.xs->id.spi);
+ } else {
+ struct tx_sa tsa;
+
+ /* find the first unused index */
+ ret = ixgbevf_ipsec_find_empty_idx(ipsec, false);
+ if (ret < 0) {
+ netdev_err(dev, "No space for SA in Tx table\n");
+ return ret;
+ }
+ sa_idx = (u16)ret;
+
+ memset(&tsa, 0, sizeof(tsa));
+ tsa.used = true;
+ tsa.xs = xs;
+
+ if (xs->id.proto & IPPROTO_ESP)
+ tsa.encrypt = xs->ealg || xs->aead;
+
+ ret = ixgbevf_ipsec_parse_proto_keys(xs, tsa.key, &tsa.salt);
+ if (ret) {
+ netdev_err(dev, "Failed to get key data for Tx SA table\n");
+ memset(&tsa, 0, sizeof(tsa));
+ return ret;
+ }
+
+ ret = ixgbevf_ipsec_set_pf_sa(adapter, xs);
+ if (ret < 0)
+ return ret;
+ tsa.pfsa = ret;
+
+ /* the preparations worked, so save the info */
+ memcpy(&ipsec->tx_tbl[sa_idx], &tsa, sizeof(tsa));
+
+ xs->xso.offload_handle = sa_idx + IXGBE_IPSEC_BASE_TX_INDEX;
+
+ ipsec->num_tx_sa++;
+ }
+
+ return 0;
+}
+
+/**
+ * ixgbevf_ipsec_del_sa - clear out this specific SA
+ * @xs: pointer to transformer state struct
+ **/
+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;
+ u16 sa_idx;
+
+ if (xs->xso.flags & XFRM_OFFLOAD_INBOUND) {
+ sa_idx = xs->xso.offload_handle - IXGBE_IPSEC_BASE_RX_INDEX;
+
+ if (!ipsec->rx_tbl[sa_idx].used) {
+ netdev_err(dev, "Invalid Rx SA selected sa_idx=%d offload_handle=%lu\n",
+ sa_idx, xs->xso.offload_handle);
+ return;
+ }
+
+ ixgbevf_ipsec_del_pf_sa(adapter, ipsec->rx_tbl[sa_idx].pfsa);
+ hash_del_rcu(&ipsec->rx_tbl[sa_idx].hlist);
+ memset(&ipsec->rx_tbl[sa_idx], 0, sizeof(struct rx_sa));
+ ipsec->num_rx_sa--;
+ } else {
+ sa_idx = xs->xso.offload_handle - IXGBE_IPSEC_BASE_TX_INDEX;
+
+ if (!ipsec->tx_tbl[sa_idx].used) {
+ netdev_err(dev, "Invalid Tx SA selected sa_idx=%d offload_handle=%lu\n",
+ sa_idx, xs->xso.offload_handle);
+ return;
+ }
+
+ ixgbevf_ipsec_del_pf_sa(adapter, ipsec->tx_tbl[sa_idx].pfsa);
+ memset(&ipsec->tx_tbl[sa_idx], 0, sizeof(struct tx_sa));
+ ipsec->num_tx_sa--;
+ }
+}
+
+/**
+ * ixgbevf_ipsec_offload_ok - can this packet use the xfrm hw offload
+ * @skb: current data packet
+ * @xs: pointer to transformer state struct
+ **/
+static bool ixgbevf_ipsec_offload_ok(struct sk_buff *skb, struct xfrm_state *xs)
+{
+ if (xs->props.family == AF_INET) {
+ /* Offload with IPv4 options is not supported yet */
+ if (ip_hdr(skb)->ihl != 5)
+ return false;
+ } else {
+ /* Offload with IPv6 extension headers is not support yet */
+ if (ipv6_ext_hdr(ipv6_hdr(skb)->nexthdr))
+ return false;
+ }
+
+ return true;
+}
+
+static const struct xfrmdev_ops ixgbevf_xfrmdev_ops = {
+ .xdo_dev_state_add = ixgbevf_ipsec_add_sa,
+ .xdo_dev_state_delete = ixgbevf_ipsec_del_sa,
+ .xdo_dev_offload_ok = ixgbevf_ipsec_offload_ok,
+};
+
+/**
+ * ixgbevf_ipsec_tx - setup Tx flags for IPsec offload
+ * @tx_ring: outgoing context
+ * @first: current data packet
+ * @itd: ipsec Tx data for later use in building context descriptor
+ **/
+int ixgbevf_ipsec_tx(struct ixgbevf_ring *tx_ring,
+ struct ixgbevf_tx_buffer *first,
+ struct ixgbevf_ipsec_tx_data *itd)
+{
+ struct ixgbevf_adapter *adapter = netdev_priv(tx_ring->netdev);
+ struct ixgbevf_ipsec *ipsec = adapter->ipsec;
+ struct xfrm_state *xs;
+ struct tx_sa *tsa;
+ u16 sa_idx;
+
+ if (unlikely(!first->skb->sp->len)) {
+ netdev_err(tx_ring->netdev, "%s: no xfrm state len = %d\n",
+ __func__, first->skb->sp->len);
+ return 0;
+ }
+
+ xs = xfrm_input_state(first->skb);
+ if (unlikely(!xs)) {
+ netdev_err(tx_ring->netdev, "%s: no xfrm_input_state() xs = %p\n",
+ __func__, xs);
+ return 0;
+ }
+
+ sa_idx = xs->xso.offload_handle - IXGBE_IPSEC_BASE_TX_INDEX;
+ if (unlikely(sa_idx >= IXGBE_IPSEC_MAX_SA_COUNT)) {
+ netdev_err(tx_ring->netdev, "%s: bad sa_idx=%d handle=%lu\n",
+ __func__, sa_idx, xs->xso.offload_handle);
+ return 0;
+ }
+
+ tsa = &ipsec->tx_tbl[sa_idx];
+ if (unlikely(!tsa->used)) {
+ netdev_err(tx_ring->netdev, "%s: unused sa_idx=%d\n",
+ __func__, sa_idx);
+ return 0;
+ }
+
+ itd->pfsa = tsa->pfsa - IXGBE_IPSEC_BASE_TX_INDEX;
+
+ first->tx_flags |= IXGBE_TX_FLAGS_IPSEC | IXGBE_TX_FLAGS_CSUM;
+
+ if (xs->id.proto == IPPROTO_ESP) {
+ itd->flags |= IXGBE_ADVTXD_TUCMD_IPSEC_TYPE_ESP |
+ IXGBE_ADVTXD_TUCMD_L4T_TCP;
+ if (first->protocol == htons(ETH_P_IP))
+ itd->flags |= IXGBE_ADVTXD_TUCMD_IPV4;
+
+ /* The actual trailer length is authlen (16 bytes) plus
+ * 2 bytes for the proto and the padlen values, plus
+ * padlen bytes of padding. This ends up not the same
+ * as the static value found in xs->props.trailer_len (21).
+ *
+ * ... but if we're doing GSO, don't bother as the stack
+ * doesn't add a trailer for those.
+ */
+ if (!skb_is_gso(first->skb)) {
+ /* The "correct" way to get the auth length would be
+ * to use
+ * authlen = crypto_aead_authsize(xs->data);
+ * but since we know we only have one size to worry
+ * about * we can let the compiler use the constant
+ * and save us a few CPU cycles.
+ */
+ const int authlen = IXGBE_IPSEC_AUTH_BITS / 8;
+ struct sk_buff *skb = first->skb;
+ u8 padlen;
+ int ret;
+
+ ret = skb_copy_bits(skb, skb->len - (authlen + 2),
+ &padlen, 1);
+ if (unlikely(ret))
+ return 0;
+ itd->trailer_len = authlen + 2 + padlen;
+ }
+ }
+ if (tsa->encrypt)
+ itd->flags |= IXGBE_ADVTXD_TUCMD_IPSEC_ENCRYPT_EN;
+
+ return 1;
+}
+
+/**
+ * ixgbevf_ipsec_rx - decode IPsec bits from Rx descriptor
+ * @rx_ring: receiving ring
+ * @rx_desc: receive data descriptor
+ * @skb: current data packet
+ *
+ * Determine if there was an IPsec encapsulation noticed, and if so set up
+ * the resulting status for later in the receive stack.
+ **/
+void ixgbevf_ipsec_rx(struct ixgbevf_ring *rx_ring,
+ union ixgbe_adv_rx_desc *rx_desc,
+ struct sk_buff *skb)
+{
+ struct ixgbevf_adapter *adapter = netdev_priv(rx_ring->netdev);
+ __le16 pkt_info = rx_desc->wb.lower.lo_dword.hs_rss.pkt_info;
+ __le16 ipsec_pkt_types = cpu_to_le16(IXGBE_RXDADV_PKTTYPE_IPSEC_AH |
+ IXGBE_RXDADV_PKTTYPE_IPSEC_ESP);
+ struct ixgbevf_ipsec *ipsec = adapter->ipsec;
+ struct xfrm_offload *xo = NULL;
+ struct xfrm_state *xs = NULL;
+ struct ipv6hdr *ip6 = NULL;
+ struct iphdr *ip4 = NULL;
+ void *daddr;
+ __be32 spi;
+ u8 *c_hdr;
+ u8 proto;
+
+ /* Find the IP and crypto headers in the data.
+ * We can assume no VLAN header in the way, b/c the
+ * hw won't recognize the IPsec packet and anyway the
+ * currently VLAN device doesn't support xfrm offload.
+ */
+ if (pkt_info & cpu_to_le16(IXGBE_RXDADV_PKTTYPE_IPV4)) {
+ ip4 = (struct iphdr *)(skb->data + ETH_HLEN);
+ daddr = &ip4->daddr;
+ c_hdr = (u8 *)ip4 + ip4->ihl * 4;
+ } else if (pkt_info & cpu_to_le16(IXGBE_RXDADV_PKTTYPE_IPV6)) {
+ ip6 = (struct ipv6hdr *)(skb->data + ETH_HLEN);
+ daddr = &ip6->daddr;
+ c_hdr = (u8 *)ip6 + sizeof(struct ipv6hdr);
+ } else {
+ return;
+ }
+
+ switch (pkt_info & ipsec_pkt_types) {
+ case cpu_to_le16(IXGBE_RXDADV_PKTTYPE_IPSEC_AH):
+ spi = ((struct ip_auth_hdr *)c_hdr)->spi;
+ proto = IPPROTO_AH;
+ break;
+ case cpu_to_le16(IXGBE_RXDADV_PKTTYPE_IPSEC_ESP):
+ spi = ((struct ip_esp_hdr *)c_hdr)->spi;
+ proto = IPPROTO_ESP;
+ break;
+ default:
+ return;
+ }
+
+ xs = ixgbevf_ipsec_find_rx_state(ipsec, daddr, proto, spi, !!ip4);
+ if (unlikely(!xs))
+ return;
+
+ skb->sp = secpath_dup(skb->sp);
+ if (unlikely(!skb->sp))
+ return;
+
+ skb->sp->xvec[skb->sp->len++] = xs;
+ skb->sp->olen++;
+ xo = xfrm_offload(skb);
+ xo->flags = CRYPTO_DONE;
+ xo->status = CRYPTO_SUCCESS;
+
+ adapter->rx_ipsec++;
+}
+
+/**
+ * ixgbevf_init_ipsec_offload - initialize registers for IPsec operation
+ * @adapter: board private structure
+ **/
+void ixgbevf_init_ipsec_offload(struct ixgbevf_adapter *adapter)
+{
+ struct ixgbevf_ipsec *ipsec;
+ size_t size;
+
+ switch (adapter->hw.api_version) {
+ case ixgbe_mbox_api_14:
+ break;
+ default:
+ return;
+ }
+
+ ipsec = kzalloc(sizeof(*ipsec), GFP_KERNEL);
+ if (!ipsec)
+ goto err1;
+ hash_init(ipsec->rx_sa_list);
+
+ size = sizeof(struct rx_sa) * IXGBE_IPSEC_MAX_SA_COUNT;
+ ipsec->rx_tbl = kzalloc(size, GFP_KERNEL);
+ if (!ipsec->rx_tbl)
+ goto err2;
+
+ size = sizeof(struct tx_sa) * IXGBE_IPSEC_MAX_SA_COUNT;
+ ipsec->tx_tbl = kzalloc(size, GFP_KERNEL);
+ if (!ipsec->tx_tbl)
+ goto err2;
+
+ ipsec->num_rx_sa = 0;
+ ipsec->num_tx_sa = 0;
+
+ adapter->ipsec = ipsec;
+
+ adapter->netdev->xfrmdev_ops = &ixgbevf_xfrmdev_ops;
+
+#define IXGBEVF_ESP_FEATURES (NETIF_F_HW_ESP | \
+ NETIF_F_HW_ESP_TX_CSUM | \
+ NETIF_F_GSO_ESP)
+
+ adapter->netdev->features |= IXGBEVF_ESP_FEATURES;
+ adapter->netdev->hw_enc_features |= IXGBEVF_ESP_FEATURES;
+
+ return;
+
+err2:
+ kfree(ipsec->rx_tbl);
+ kfree(ipsec->tx_tbl);
+ kfree(ipsec);
+err1:
+ netdev_err(adapter->netdev, "Unable to allocate memory for SA tables");
+}
+
+/**
+ * ixgbevf_stop_ipsec_offload - tear down the IPsec offload
+ * @adapter: board private structure
+ **/
+void ixgbevf_stop_ipsec_offload(struct ixgbevf_adapter *adapter)
+{
+ struct ixgbevf_ipsec *ipsec = adapter->ipsec;
+
+ adapter->ipsec = NULL;
+ if (ipsec) {
+ kfree(ipsec->rx_tbl);
+ kfree(ipsec->tx_tbl);
+ kfree(ipsec);
+ }
+}
diff --git a/drivers/net/ethernet/intel/ixgbevf/ipsec.h b/drivers/net/ethernet/intel/ixgbevf/ipsec.h
new file mode 100644
index 000000000000..3740725041c3
--- /dev/null
+++ b/drivers/net/ethernet/intel/ixgbevf/ipsec.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2018 Oracle and/or its affiliates. All rights reserved. */
+
+#ifndef _IXGBEVF_IPSEC_H_
+#define _IXGBEVF_IPSEC_H_
+
+#define IXGBE_IPSEC_MAX_SA_COUNT 1024
+#define IXGBE_IPSEC_BASE_RX_INDEX 0
+#define IXGBE_IPSEC_BASE_TX_INDEX IXGBE_IPSEC_MAX_SA_COUNT
+#define IXGBE_IPSEC_AUTH_BITS 128
+
+#define IXGBE_RXMOD_VALID 0x00000001
+#define IXGBE_RXMOD_PROTO_ESP 0x00000004
+#define IXGBE_RXMOD_DECRYPT 0x00000008
+#define IXGBE_RXMOD_IPV6 0x00000010
+
+struct rx_sa {
+ struct hlist_node hlist;
+ struct xfrm_state *xs;
+ __be32 ipaddr[4];
+ u32 key[4];
+ u32 salt;
+ u32 mode;
+ u32 pfsa;
+ bool used;
+ bool decrypt;
+};
+
+struct rx_ip_sa {
+ __be32 ipaddr[4];
+ u32 ref_cnt;
+ bool used;
+};
+
+struct tx_sa {
+ struct xfrm_state *xs;
+ u32 key[4];
+ u32 salt;
+ u32 pfsa;
+ bool encrypt;
+ bool used;
+};
+
+struct ixgbevf_ipsec_tx_data {
+ u32 flags;
+ u16 trailer_len;
+ u16 pfsa;
+};
+
+struct ixgbevf_ipsec {
+ u16 num_rx_sa;
+ u16 num_tx_sa;
+ struct rx_sa *rx_tbl;
+ struct tx_sa *tx_tbl;
+ DECLARE_HASHTABLE(rx_sa_list, 10);
+};
+
+struct sa_mbx_msg {
+ __be32 spi;
+ u8 flags;
+ u8 proto;
+ u16 family;
+ __be32 addr[4];
+ u32 key[5];
+};
+#endif /* _IXGBEVF_IPSEC_H_ */
diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h
index 56a1031dcc07..ecab686574b6 100644
--- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h
+++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h
@@ -14,6 +14,7 @@
#include <net/xdp.h>
#include "vf.h"
+#include "ipsec.h"
#define IXGBE_MAX_TXD_PWR 14
#define IXGBE_MAX_DATA_PER_TXD BIT(IXGBE_MAX_TXD_PWR)
@@ -163,6 +164,7 @@ struct ixgbevf_ring {
#define IXGBE_TX_FLAGS_VLAN BIT(1)
#define IXGBE_TX_FLAGS_TSO BIT(2)
#define IXGBE_TX_FLAGS_IPV4 BIT(3)
+#define IXGBE_TX_FLAGS_IPSEC BIT(4)
#define IXGBE_TX_FLAGS_VLAN_MASK 0xffff0000
#define IXGBE_TX_FLAGS_VLAN_PRIO_MASK 0x0000e000
#define IXGBE_TX_FLAGS_VLAN_SHIFT 16
@@ -338,6 +340,7 @@ struct ixgbevf_adapter {
struct ixgbevf_ring *tx_ring[MAX_TX_QUEUES]; /* One per active queue */
u64 restart_queue;
u32 tx_timeout_count;
+ u64 tx_ipsec;
/* RX */
int num_rx_queues;
@@ -348,6 +351,7 @@ struct ixgbevf_adapter {
u64 alloc_rx_page_failed;
u64 alloc_rx_buff_failed;
u64 alloc_rx_page;
+ u64 rx_ipsec;
struct msix_entry *msix_entries;
@@ -384,6 +388,10 @@ struct ixgbevf_adapter {
u8 rss_indir_tbl[IXGBEVF_X550_VFRETA_SIZE];
u32 flags;
#define IXGBEVF_FLAGS_LEGACY_RX BIT(1)
+
+#ifdef CONFIG_XFRM
+ struct ixgbevf_ipsec *ipsec;
+#endif /* CONFIG_XFRM */
};
enum ixbgevf_state_t {
@@ -451,6 +459,31 @@ int ethtool_ioctl(struct ifreq *ifr);
extern void ixgbevf_write_eitr(struct ixgbevf_q_vector *q_vector);
+#ifdef CONFIG_IXGBEVF_IPSEC
+void ixgbevf_init_ipsec_offload(struct ixgbevf_adapter *adapter);
+void ixgbevf_stop_ipsec_offload(struct ixgbevf_adapter *adapter);
+void ixgbevf_ipsec_restore(struct ixgbevf_adapter *adapter);
+void ixgbevf_ipsec_rx(struct ixgbevf_ring *rx_ring,
+ union ixgbe_adv_rx_desc *rx_desc,
+ struct sk_buff *skb);
+int ixgbevf_ipsec_tx(struct ixgbevf_ring *tx_ring,
+ struct ixgbevf_tx_buffer *first,
+ struct ixgbevf_ipsec_tx_data *itd);
+#else
+static inline void ixgbevf_init_ipsec_offload(struct ixgbevf_adapter *adapter)
+{ }
+static inline void ixgbevf_stop_ipsec_offload(struct ixgbevf_adapter *adapter)
+{ }
+static inline void ixgbevf_ipsec_restore(struct ixgbevf_adapter *adapter) { }
+static inline void ixgbevf_ipsec_rx(struct ixgbevf_ring *rx_ring,
+ union ixgbe_adv_rx_desc *rx_desc,
+ struct sk_buff *skb) { }
+static inline int ixgbevf_ipsec_tx(struct ixgbevf_ring *tx_ring,
+ struct ixgbevf_tx_buffer *first,
+ struct ixgbevf_ipsec_tx_data *itd)
+{ return 0; }
+#endif /* CONFIG_IXGBEVF_IPSEC */
+
void ixgbe_napi_add_all(struct ixgbevf_adapter *adapter);
void ixgbe_napi_del_all(struct ixgbevf_adapter *adapter);
diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
index 5a228582423b..5e47ede7e832 100644
--- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
+++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
@@ -40,7 +40,7 @@ static const char ixgbevf_driver_string[] =
#define DRV_VERSION "4.1.0-k"
const char ixgbevf_driver_version[] = DRV_VERSION;
static char ixgbevf_copyright[] =
- "Copyright (c) 2009 - 2015 Intel Corporation.";
+ "Copyright (c) 2009 - 2018 Intel Corporation.";
static const struct ixgbevf_info *ixgbevf_info_tbl[] = {
[board_82599_vf] = &ixgbevf_82599_vf_info,
@@ -79,7 +79,7 @@ MODULE_DEVICE_TABLE(pci, ixgbevf_pci_tbl);
MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
MODULE_DESCRIPTION("Intel(R) 10 Gigabit Virtual Function Network Driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_VERSION(DRV_VERSION);
#define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV|NETIF_MSG_PROBE|NETIF_MSG_LINK)
@@ -268,7 +268,7 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
struct ixgbevf_adapter *adapter = q_vector->adapter;
struct ixgbevf_tx_buffer *tx_buffer;
union ixgbe_adv_tx_desc *tx_desc;
- unsigned int total_bytes = 0, total_packets = 0;
+ unsigned int total_bytes = 0, total_packets = 0, total_ipsec = 0;
unsigned int budget = tx_ring->count / 2;
unsigned int i = tx_ring->next_to_clean;
@@ -299,6 +299,8 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
/* update the statistics for this packet */
total_bytes += tx_buffer->bytecount;
total_packets += tx_buffer->gso_segs;
+ if (tx_buffer->tx_flags & IXGBE_TX_FLAGS_IPSEC)
+ total_ipsec++;
/* free the skb */
if (ring_is_xdp(tx_ring))
@@ -361,6 +363,7 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
u64_stats_update_end(&tx_ring->syncp);
q_vector->tx.total_bytes += total_bytes;
q_vector->tx.total_packets += total_packets;
+ adapter->tx_ipsec += total_ipsec;
if (check_for_tx_hang(tx_ring) && ixgbevf_check_tx_hang(tx_ring)) {
struct ixgbe_hw *hw = &adapter->hw;
@@ -516,6 +519,9 @@ static void ixgbevf_process_skb_fields(struct ixgbevf_ring *rx_ring,
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid);
}
+ if (ixgbevf_test_staterr(rx_desc, IXGBE_RXDADV_STAT_SECP))
+ ixgbevf_ipsec_rx(rx_ring, rx_desc, skb);
+
skb->protocol = eth_type_trans(skb, rx_ring->netdev);
}
@@ -1012,7 +1018,7 @@ static int ixgbevf_xmit_xdp_ring(struct ixgbevf_ring *ring,
context_desc = IXGBEVF_TX_CTXTDESC(ring, 0);
context_desc->vlan_macip_lens =
cpu_to_le32(ETH_HLEN << IXGBE_ADVTXD_MACLEN_SHIFT);
- context_desc->seqnum_seed = 0;
+ context_desc->fceof_saidx = 0;
context_desc->type_tucmd_mlhl =
cpu_to_le32(IXGBE_TXD_CMD_DEXT |
IXGBE_ADVTXD_DTYP_CTXT);
@@ -2200,6 +2206,7 @@ static void ixgbevf_configure(struct ixgbevf_adapter *adapter)
ixgbevf_set_rx_mode(adapter->netdev);
ixgbevf_restore_vlan(adapter);
+ ixgbevf_ipsec_restore(adapter);
ixgbevf_configure_tx(adapter);
ixgbevf_configure_rx(adapter);
@@ -2246,7 +2253,8 @@ static void ixgbevf_init_last_counter_stats(struct ixgbevf_adapter *adapter)
static void ixgbevf_negotiate_api(struct ixgbevf_adapter *adapter)
{
struct ixgbe_hw *hw = &adapter->hw;
- int api[] = { ixgbe_mbox_api_13,
+ int api[] = { ixgbe_mbox_api_14,
+ ixgbe_mbox_api_13,
ixgbe_mbox_api_12,
ixgbe_mbox_api_11,
ixgbe_mbox_api_10,
@@ -2605,6 +2613,7 @@ static void ixgbevf_set_num_queues(struct ixgbevf_adapter *adapter)
case ixgbe_mbox_api_11:
case ixgbe_mbox_api_12:
case ixgbe_mbox_api_13:
+ case ixgbe_mbox_api_14:
if (adapter->xdp_prog &&
hw->mac.max_tx_queues == rss)
rss = rss > 3 ? 2 : 1;
@@ -3700,8 +3709,8 @@ static void ixgbevf_queue_reset_subtask(struct ixgbevf_adapter *adapter)
}
static void ixgbevf_tx_ctxtdesc(struct ixgbevf_ring *tx_ring,
- u32 vlan_macip_lens, u32 type_tucmd,
- u32 mss_l4len_idx)
+ u32 vlan_macip_lens, u32 fceof_saidx,
+ u32 type_tucmd, u32 mss_l4len_idx)
{
struct ixgbe_adv_tx_context_desc *context_desc;
u16 i = tx_ring->next_to_use;
@@ -3715,14 +3724,15 @@ static void ixgbevf_tx_ctxtdesc(struct ixgbevf_ring *tx_ring,
type_tucmd |= IXGBE_TXD_CMD_DEXT | IXGBE_ADVTXD_DTYP_CTXT;
context_desc->vlan_macip_lens = cpu_to_le32(vlan_macip_lens);
- context_desc->seqnum_seed = 0;
+ context_desc->fceof_saidx = cpu_to_le32(fceof_saidx);
context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd);
context_desc->mss_l4len_idx = cpu_to_le32(mss_l4len_idx);
}
static int ixgbevf_tso(struct ixgbevf_ring *tx_ring,
struct ixgbevf_tx_buffer *first,
- u8 *hdr_len)
+ u8 *hdr_len,
+ struct ixgbevf_ipsec_tx_data *itd)
{
u32 vlan_macip_lens, type_tucmd, mss_l4len_idx;
struct sk_buff *skb = first->skb;
@@ -3736,6 +3746,7 @@ static int ixgbevf_tso(struct ixgbevf_ring *tx_ring,
unsigned char *hdr;
} l4;
u32 paylen, l4_offset;
+ u32 fceof_saidx = 0;
int err;
if (skb->ip_summed != CHECKSUM_PARTIAL)
@@ -3761,13 +3772,15 @@ static int ixgbevf_tso(struct ixgbevf_ring *tx_ring,
if (ip.v4->version == 4) {
unsigned char *csum_start = skb_checksum_start(skb);
unsigned char *trans_start = ip.hdr + (ip.v4->ihl * 4);
+ int len = csum_start - trans_start;
/* IP header will have to cancel out any data that
- * is not a part of the outer IP header
+ * is not a part of the outer IP header, so set to
+ * a reverse csum if needed, else init check to 0.
*/
- ip.v4->check = csum_fold(csum_partial(trans_start,
- csum_start - trans_start,
- 0));
+ ip.v4->check = (skb_shinfo(skb)->gso_type & SKB_GSO_PARTIAL) ?
+ csum_fold(csum_partial(trans_start,
+ len, 0)) : 0;
type_tucmd |= IXGBE_ADVTXD_TUCMD_IPV4;
ip.v4->tot_len = 0;
@@ -3799,13 +3812,16 @@ static int ixgbevf_tso(struct ixgbevf_ring *tx_ring,
mss_l4len_idx |= skb_shinfo(skb)->gso_size << IXGBE_ADVTXD_MSS_SHIFT;
mss_l4len_idx |= (1u << IXGBE_ADVTXD_IDX_SHIFT);
+ fceof_saidx |= itd->pfsa;
+ type_tucmd |= itd->flags | itd->trailer_len;
+
/* vlan_macip_lens: HEADLEN, MACLEN, VLAN tag */
vlan_macip_lens = l4.hdr - ip.hdr;
vlan_macip_lens |= (ip.hdr - skb->data) << IXGBE_ADVTXD_MACLEN_SHIFT;
vlan_macip_lens |= first->tx_flags & IXGBE_TX_FLAGS_VLAN_MASK;
- ixgbevf_tx_ctxtdesc(tx_ring, vlan_macip_lens,
- type_tucmd, mss_l4len_idx);
+ ixgbevf_tx_ctxtdesc(tx_ring, vlan_macip_lens, fceof_saidx, type_tucmd,
+ mss_l4len_idx);
return 1;
}
@@ -3820,10 +3836,12 @@ static inline bool ixgbevf_ipv6_csum_is_sctp(struct sk_buff *skb)
}
static void ixgbevf_tx_csum(struct ixgbevf_ring *tx_ring,
- struct ixgbevf_tx_buffer *first)
+ struct ixgbevf_tx_buffer *first,
+ struct ixgbevf_ipsec_tx_data *itd)
{
struct sk_buff *skb = first->skb;
u32 vlan_macip_lens = 0;
+ u32 fceof_saidx = 0;
u32 type_tucmd = 0;
if (skb->ip_summed != CHECKSUM_PARTIAL)
@@ -3849,6 +3867,10 @@ static void ixgbevf_tx_csum(struct ixgbevf_ring *tx_ring,
skb_checksum_help(skb);
goto no_csum;
}
+
+ if (first->protocol == htons(ETH_P_IP))
+ type_tucmd |= IXGBE_ADVTXD_TUCMD_IPV4;
+
/* update TX checksum flag */
first->tx_flags |= IXGBE_TX_FLAGS_CSUM;
vlan_macip_lens = skb_checksum_start_offset(skb) -
@@ -3858,7 +3880,11 @@ no_csum:
vlan_macip_lens |= skb_network_offset(skb) << IXGBE_ADVTXD_MACLEN_SHIFT;
vlan_macip_lens |= first->tx_flags & IXGBE_TX_FLAGS_VLAN_MASK;
- ixgbevf_tx_ctxtdesc(tx_ring, vlan_macip_lens, type_tucmd, 0);
+ fceof_saidx |= itd->pfsa;
+ type_tucmd |= itd->flags | itd->trailer_len;
+
+ ixgbevf_tx_ctxtdesc(tx_ring, vlan_macip_lens,
+ fceof_saidx, type_tucmd, 0);
}
static __le32 ixgbevf_tx_cmd_type(u32 tx_flags)
@@ -3892,8 +3918,12 @@ static void ixgbevf_tx_olinfo_status(union ixgbe_adv_tx_desc *tx_desc,
if (tx_flags & IXGBE_TX_FLAGS_IPV4)
olinfo_status |= cpu_to_le32(IXGBE_ADVTXD_POPTS_IXSM);
- /* use index 1 context for TSO/FSO/FCOE */
- if (tx_flags & IXGBE_TX_FLAGS_TSO)
+ /* enable IPsec */
+ if (tx_flags & IXGBE_TX_FLAGS_IPSEC)
+ olinfo_status |= cpu_to_le32(IXGBE_ADVTXD_POPTS_IPSEC);
+
+ /* use index 1 context for TSO/FSO/FCOE/IPSEC */
+ if (tx_flags & (IXGBE_TX_FLAGS_TSO | IXGBE_TX_FLAGS_IPSEC))
olinfo_status |= cpu_to_le32(1u << IXGBE_ADVTXD_IDX_SHIFT);
/* Check Context must be set if Tx switch is enabled, which it
@@ -4075,6 +4105,7 @@ static int ixgbevf_xmit_frame_ring(struct sk_buff *skb,
int tso;
u32 tx_flags = 0;
u16 count = TXD_USE_COUNT(skb_headlen(skb));
+ struct ixgbevf_ipsec_tx_data ipsec_tx = { 0 };
#if PAGE_SIZE > IXGBE_MAX_DATA_PER_TXD
unsigned short f;
#endif
@@ -4119,11 +4150,15 @@ static int ixgbevf_xmit_frame_ring(struct sk_buff *skb,
first->tx_flags = tx_flags;
first->protocol = vlan_get_protocol(skb);
- tso = ixgbevf_tso(tx_ring, first, &hdr_len);
+#ifdef CONFIG_IXGBEVF_IPSEC
+ if (skb->sp && !ixgbevf_ipsec_tx(tx_ring, first, &ipsec_tx))
+ goto out_drop;
+#endif
+ tso = ixgbevf_tso(tx_ring, first, &hdr_len, &ipsec_tx);
if (tso < 0)
goto out_drop;
else if (!tso)
- ixgbevf_tx_csum(tx_ring, first);
+ ixgbevf_tx_csum(tx_ring, first, &ipsec_tx);
ixgbevf_tx_map(tx_ring, first, hdr_len);
@@ -4613,6 +4648,7 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
case ixgbe_mbox_api_11:
case ixgbe_mbox_api_12:
case ixgbe_mbox_api_13:
+ case ixgbe_mbox_api_14:
netdev->max_mtu = IXGBE_MAX_JUMBO_FRAME_SIZE -
(ETH_HLEN + ETH_FCS_LEN);
break;
@@ -4648,6 +4684,7 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_drvdata(pdev, netdev);
netif_carrier_off(netdev);
+ ixgbevf_init_ipsec_offload(adapter);
ixgbevf_init_last_counter_stats(adapter);
@@ -4714,6 +4751,7 @@ static void ixgbevf_remove(struct pci_dev *pdev)
if (netdev->reg_state == NETREG_REGISTERED)
unregister_netdev(netdev);
+ ixgbevf_stop_ipsec_offload(adapter);
ixgbevf_clear_interrupt_scheme(adapter);
ixgbevf_reset_interrupt_capability(adapter);
diff --git a/drivers/net/ethernet/intel/ixgbevf/mbx.h b/drivers/net/ethernet/intel/ixgbevf/mbx.h
index bfd9ae150808..853796c8ef0e 100644
--- a/drivers/net/ethernet/intel/ixgbevf/mbx.h
+++ b/drivers/net/ethernet/intel/ixgbevf/mbx.h
@@ -62,6 +62,7 @@ enum ixgbe_pfvf_api_rev {
ixgbe_mbox_api_11, /* API version 1.1, linux/freebsd VF driver */
ixgbe_mbox_api_12, /* API version 1.2, linux/freebsd VF driver */
ixgbe_mbox_api_13, /* API version 1.3, linux/freebsd VF driver */
+ ixgbe_mbox_api_14, /* API version 1.4, linux/freebsd VF driver */
/* This value should always be last */
ixgbe_mbox_api_unknown, /* indicates that API version is not known */
};
@@ -92,6 +93,10 @@ enum ixgbe_pfvf_api_rev {
#define IXGBE_VF_UPDATE_XCAST_MODE 0x0c
+/* mailbox API, version 1.4 VF requests */
+#define IXGBE_VF_IPSEC_ADD 0x0d
+#define IXGBE_VF_IPSEC_DEL 0x0e
+
/* length of permanent address message returned from PF */
#define IXGBE_VF_PERMADDR_MSG_LEN 4
/* word in permanent address message with the current multicast type */
diff --git a/drivers/net/ethernet/intel/ixgbevf/vf.c b/drivers/net/ethernet/intel/ixgbevf/vf.c
index bf0577e819e1..cd3b81300cc7 100644
--- a/drivers/net/ethernet/intel/ixgbevf/vf.c
+++ b/drivers/net/ethernet/intel/ixgbevf/vf.c
@@ -309,6 +309,7 @@ int ixgbevf_get_reta_locked(struct ixgbe_hw *hw, u32 *reta, int num_rx_queues)
* is not supported for this device type.
*/
switch (hw->api_version) {
+ case ixgbe_mbox_api_14:
case ixgbe_mbox_api_13:
case ixgbe_mbox_api_12:
if (hw->mac.type < ixgbe_mac_X550_vf)
@@ -376,6 +377,7 @@ int ixgbevf_get_rss_key_locked(struct ixgbe_hw *hw, u8 *rss_key)
* or if the operation is not supported for this device type.
*/
switch (hw->api_version) {
+ case ixgbe_mbox_api_14:
case ixgbe_mbox_api_13:
case ixgbe_mbox_api_12:
if (hw->mac.type < ixgbe_mac_X550_vf)
@@ -540,6 +542,7 @@ static s32 ixgbevf_update_xcast_mode(struct ixgbe_hw *hw, int xcast_mode)
if (xcast_mode == IXGBEVF_XCAST_MODE_PROMISC)
return -EOPNOTSUPP;
/* Fall threw */
+ case ixgbe_mbox_api_14:
case ixgbe_mbox_api_13:
break;
default:
@@ -890,6 +893,7 @@ int ixgbevf_get_queues(struct ixgbe_hw *hw, unsigned int *num_tcs,
case ixgbe_mbox_api_11:
case ixgbe_mbox_api_12:
case ixgbe_mbox_api_13:
+ case ixgbe_mbox_api_14:
break;
default:
return 0;
diff --git a/drivers/net/ethernet/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c
index e08301d833e2..32ac9045cdae 100644
--- a/drivers/net/ethernet/lantiq_etop.c
+++ b/drivers/net/ethernet/lantiq_etop.c
@@ -365,15 +365,8 @@ ltq_etop_mdio_probe(struct net_device *dev)
return PTR_ERR(phydev);
}
- phydev->supported &= (SUPPORTED_10baseT_Half
- | SUPPORTED_10baseT_Full
- | SUPPORTED_100baseT_Half
- | SUPPORTED_100baseT_Full
- | SUPPORTED_Autoneg
- | SUPPORTED_MII
- | SUPPORTED_TP);
-
- phydev->advertising = phydev->supported;
+ phy_set_max_speed(phydev, SPEED_100);
+
phy_attached_info(phydev);
return 0;
@@ -439,6 +432,7 @@ ltq_etop_open(struct net_device *dev)
if (!IS_TX(i) && (!IS_RX(i)))
continue;
ltq_dma_open(&ch->dma);
+ ltq_dma_enable_irq(&ch->dma);
napi_enable(&ch->napi);
}
phy_start(dev->phydev);
diff --git a/drivers/net/ethernet/lantiq_xrx200.c b/drivers/net/ethernet/lantiq_xrx200.c
new file mode 100644
index 000000000000..8c5ba4b81fb7
--- /dev/null
+++ b/drivers/net/ethernet/lantiq_xrx200.c
@@ -0,0 +1,567 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Lantiq / Intel PMAC driver for XRX200 SoCs
+ *
+ * Copyright (C) 2010 Lantiq Deutschland
+ * Copyright (C) 2012 John Crispin <john@phrozen.org>
+ * Copyright (C) 2017 - 2018 Hauke Mehrtens <hauke@hauke-m.de>
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+
+#include <linux/of_net.h>
+#include <linux/of_platform.h>
+
+#include <xway_dma.h>
+
+/* DMA */
+#define XRX200_DMA_DATA_LEN 0x600
+#define XRX200_DMA_RX 0
+#define XRX200_DMA_TX 1
+
+/* cpu port mac */
+#define PMAC_RX_IPG 0x0024
+#define PMAC_RX_IPG_MASK 0xf
+
+#define PMAC_HD_CTL 0x0000
+/* Add Ethernet header to packets from DMA to PMAC */
+#define PMAC_HD_CTL_ADD BIT(0)
+/* Add VLAN tag to Packets from DMA to PMAC */
+#define PMAC_HD_CTL_TAG BIT(1)
+/* Add CRC to packets from DMA to PMAC */
+#define PMAC_HD_CTL_AC BIT(2)
+/* Add status header to packets from PMAC to DMA */
+#define PMAC_HD_CTL_AS BIT(3)
+/* Remove CRC from packets from PMAC to DMA */
+#define PMAC_HD_CTL_RC BIT(4)
+/* Remove Layer-2 header from packets from PMAC to DMA */
+#define PMAC_HD_CTL_RL2 BIT(5)
+/* Status header is present from DMA to PMAC */
+#define PMAC_HD_CTL_RXSH BIT(6)
+/* Add special tag from PMAC to switch */
+#define PMAC_HD_CTL_AST BIT(7)
+/* Remove specail Tag from PMAC to DMA */
+#define PMAC_HD_CTL_RST BIT(8)
+/* Check CRC from DMA to PMAC */
+#define PMAC_HD_CTL_CCRC BIT(9)
+/* Enable reaction to Pause frames in the PMAC */
+#define PMAC_HD_CTL_FC BIT(10)
+
+struct xrx200_chan {
+ int tx_free;
+
+ struct napi_struct napi;
+ struct ltq_dma_channel dma;
+ struct sk_buff *skb[LTQ_DESC_NUM];
+
+ struct xrx200_priv *priv;
+};
+
+struct xrx200_priv {
+ struct clk *clk;
+
+ struct xrx200_chan chan_tx;
+ struct xrx200_chan chan_rx;
+
+ struct net_device *net_dev;
+ struct device *dev;
+
+ __iomem void *pmac_reg;
+};
+
+static u32 xrx200_pmac_r32(struct xrx200_priv *priv, u32 offset)
+{
+ return __raw_readl(priv->pmac_reg + offset);
+}
+
+static void xrx200_pmac_w32(struct xrx200_priv *priv, u32 val, u32 offset)
+{
+ __raw_writel(val, priv->pmac_reg + offset);
+}
+
+static void xrx200_pmac_mask(struct xrx200_priv *priv, u32 clear, u32 set,
+ u32 offset)
+{
+ u32 val = xrx200_pmac_r32(priv, offset);
+
+ val &= ~(clear);
+ val |= set;
+ xrx200_pmac_w32(priv, val, offset);
+}
+
+/* drop all the packets from the DMA ring */
+static void xrx200_flush_dma(struct xrx200_chan *ch)
+{
+ int i;
+
+ for (i = 0; i < LTQ_DESC_NUM; i++) {
+ struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc];
+
+ if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) != LTQ_DMA_C)
+ break;
+
+ desc->ctl = LTQ_DMA_OWN | LTQ_DMA_RX_OFFSET(NET_IP_ALIGN) |
+ XRX200_DMA_DATA_LEN;
+ ch->dma.desc++;
+ ch->dma.desc %= LTQ_DESC_NUM;
+ }
+}
+
+static int xrx200_open(struct net_device *net_dev)
+{
+ struct xrx200_priv *priv = netdev_priv(net_dev);
+
+ napi_enable(&priv->chan_tx.napi);
+ ltq_dma_open(&priv->chan_tx.dma);
+ ltq_dma_enable_irq(&priv->chan_tx.dma);
+
+ napi_enable(&priv->chan_rx.napi);
+ ltq_dma_open(&priv->chan_rx.dma);
+ /* The boot loader does not always deactivate the receiving of frames
+ * on the ports and then some packets queue up in the PPE buffers.
+ * They already passed the PMAC so they do not have the tags
+ * configured here. Read the these packets here and drop them.
+ * The HW should have written them into memory after 10us
+ */
+ usleep_range(20, 40);
+ xrx200_flush_dma(&priv->chan_rx);
+ ltq_dma_enable_irq(&priv->chan_rx.dma);
+
+ netif_wake_queue(net_dev);
+
+ return 0;
+}
+
+static int xrx200_close(struct net_device *net_dev)
+{
+ struct xrx200_priv *priv = netdev_priv(net_dev);
+
+ netif_stop_queue(net_dev);
+
+ napi_disable(&priv->chan_rx.napi);
+ ltq_dma_close(&priv->chan_rx.dma);
+
+ napi_disable(&priv->chan_tx.napi);
+ ltq_dma_close(&priv->chan_tx.dma);
+
+ return 0;
+}
+
+static int xrx200_alloc_skb(struct xrx200_chan *ch)
+{
+ int ret = 0;
+
+ ch->skb[ch->dma.desc] = netdev_alloc_skb_ip_align(ch->priv->net_dev,
+ XRX200_DMA_DATA_LEN);
+ if (!ch->skb[ch->dma.desc]) {
+ ret = -ENOMEM;
+ goto skip;
+ }
+
+ ch->dma.desc_base[ch->dma.desc].addr = dma_map_single(ch->priv->dev,
+ ch->skb[ch->dma.desc]->data, XRX200_DMA_DATA_LEN,
+ DMA_FROM_DEVICE);
+ if (unlikely(dma_mapping_error(ch->priv->dev,
+ ch->dma.desc_base[ch->dma.desc].addr))) {
+ dev_kfree_skb_any(ch->skb[ch->dma.desc]);
+ ret = -ENOMEM;
+ goto skip;
+ }
+
+skip:
+ ch->dma.desc_base[ch->dma.desc].ctl =
+ LTQ_DMA_OWN | LTQ_DMA_RX_OFFSET(NET_IP_ALIGN) |
+ XRX200_DMA_DATA_LEN;
+
+ return ret;
+}
+
+static int xrx200_hw_receive(struct xrx200_chan *ch)
+{
+ struct xrx200_priv *priv = ch->priv;
+ struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc];
+ struct sk_buff *skb = ch->skb[ch->dma.desc];
+ int len = (desc->ctl & LTQ_DMA_SIZE_MASK);
+ struct net_device *net_dev = priv->net_dev;
+ int ret;
+
+ ret = xrx200_alloc_skb(ch);
+
+ ch->dma.desc++;
+ ch->dma.desc %= LTQ_DESC_NUM;
+
+ if (ret) {
+ netdev_err(net_dev, "failed to allocate new rx buffer\n");
+ return ret;
+ }
+
+ skb_put(skb, len);
+ skb->protocol = eth_type_trans(skb, net_dev);
+ netif_receive_skb(skb);
+ net_dev->stats.rx_packets++;
+ net_dev->stats.rx_bytes += len - ETH_FCS_LEN;
+
+ return 0;
+}
+
+static int xrx200_poll_rx(struct napi_struct *napi, int budget)
+{
+ struct xrx200_chan *ch = container_of(napi,
+ struct xrx200_chan, napi);
+ int rx = 0;
+ int ret;
+
+ while (rx < budget) {
+ struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc];
+
+ if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) == LTQ_DMA_C) {
+ ret = xrx200_hw_receive(ch);
+ if (ret)
+ return ret;
+ rx++;
+ } else {
+ break;
+ }
+ }
+
+ if (rx < budget) {
+ napi_complete(&ch->napi);
+ ltq_dma_enable_irq(&ch->dma);
+ }
+
+ return rx;
+}
+
+static int xrx200_tx_housekeeping(struct napi_struct *napi, int budget)
+{
+ struct xrx200_chan *ch = container_of(napi,
+ struct xrx200_chan, napi);
+ struct net_device *net_dev = ch->priv->net_dev;
+ int pkts = 0;
+ int bytes = 0;
+
+ while (pkts < budget) {
+ struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->tx_free];
+
+ if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) == LTQ_DMA_C) {
+ struct sk_buff *skb = ch->skb[ch->tx_free];
+
+ pkts++;
+ bytes += skb->len;
+ ch->skb[ch->tx_free] = NULL;
+ consume_skb(skb);
+ memset(&ch->dma.desc_base[ch->tx_free], 0,
+ sizeof(struct ltq_dma_desc));
+ ch->tx_free++;
+ ch->tx_free %= LTQ_DESC_NUM;
+ } else {
+ break;
+ }
+ }
+
+ net_dev->stats.tx_packets += pkts;
+ net_dev->stats.tx_bytes += bytes;
+ netdev_completed_queue(ch->priv->net_dev, pkts, bytes);
+
+ if (pkts < budget) {
+ napi_complete(&ch->napi);
+ ltq_dma_enable_irq(&ch->dma);
+ }
+
+ return pkts;
+}
+
+static int xrx200_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
+{
+ struct xrx200_priv *priv = netdev_priv(net_dev);
+ struct xrx200_chan *ch = &priv->chan_tx;
+ struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc];
+ u32 byte_offset;
+ dma_addr_t mapping;
+ int len;
+
+ skb->dev = net_dev;
+ if (skb_put_padto(skb, ETH_ZLEN)) {
+ net_dev->stats.tx_dropped++;
+ return NETDEV_TX_OK;
+ }
+
+ len = skb->len;
+
+ if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) || ch->skb[ch->dma.desc]) {
+ netdev_err(net_dev, "tx ring full\n");
+ netif_stop_queue(net_dev);
+ return NETDEV_TX_BUSY;
+ }
+
+ ch->skb[ch->dma.desc] = skb;
+
+ mapping = dma_map_single(priv->dev, skb->data, len, DMA_TO_DEVICE);
+ if (unlikely(dma_mapping_error(priv->dev, mapping)))
+ goto err_drop;
+
+ /* dma needs to start on a 16 byte aligned address */
+ byte_offset = mapping % 16;
+
+ desc->addr = mapping - byte_offset;
+ /* Make sure the address is written before we give it to HW */
+ wmb();
+ desc->ctl = LTQ_DMA_OWN | LTQ_DMA_SOP | LTQ_DMA_EOP |
+ LTQ_DMA_TX_OFFSET(byte_offset) | (len & LTQ_DMA_SIZE_MASK);
+ ch->dma.desc++;
+ ch->dma.desc %= LTQ_DESC_NUM;
+ if (ch->dma.desc == ch->tx_free)
+ netif_stop_queue(net_dev);
+
+ netdev_sent_queue(net_dev, len);
+
+ return NETDEV_TX_OK;
+
+err_drop:
+ dev_kfree_skb(skb);
+ net_dev->stats.tx_dropped++;
+ net_dev->stats.tx_errors++;
+ return NETDEV_TX_OK;
+}
+
+static const struct net_device_ops xrx200_netdev_ops = {
+ .ndo_open = xrx200_open,
+ .ndo_stop = xrx200_close,
+ .ndo_start_xmit = xrx200_start_xmit,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_change_mtu = eth_change_mtu,
+};
+
+static irqreturn_t xrx200_dma_irq(int irq, void *ptr)
+{
+ struct xrx200_chan *ch = ptr;
+
+ ltq_dma_disable_irq(&ch->dma);
+ ltq_dma_ack_irq(&ch->dma);
+
+ napi_schedule(&ch->napi);
+
+ return IRQ_HANDLED;
+}
+
+static int xrx200_dma_init(struct xrx200_priv *priv)
+{
+ struct xrx200_chan *ch_rx = &priv->chan_rx;
+ struct xrx200_chan *ch_tx = &priv->chan_tx;
+ int ret = 0;
+ int i;
+
+ ltq_dma_init_port(DMA_PORT_ETOP);
+
+ ch_rx->dma.nr = XRX200_DMA_RX;
+ ch_rx->dma.dev = priv->dev;
+ ch_rx->priv = priv;
+
+ ltq_dma_alloc_rx(&ch_rx->dma);
+ for (ch_rx->dma.desc = 0; ch_rx->dma.desc < LTQ_DESC_NUM;
+ ch_rx->dma.desc++) {
+ ret = xrx200_alloc_skb(ch_rx);
+ if (ret)
+ goto rx_free;
+ }
+ ch_rx->dma.desc = 0;
+ ret = devm_request_irq(priv->dev, ch_rx->dma.irq, xrx200_dma_irq, 0,
+ "xrx200_net_rx", &priv->chan_rx);
+ if (ret) {
+ dev_err(priv->dev, "failed to request RX irq %d\n",
+ ch_rx->dma.irq);
+ goto rx_ring_free;
+ }
+
+ ch_tx->dma.nr = XRX200_DMA_TX;
+ ch_tx->dma.dev = priv->dev;
+ ch_tx->priv = priv;
+
+ ltq_dma_alloc_tx(&ch_tx->dma);
+ ret = devm_request_irq(priv->dev, ch_tx->dma.irq, xrx200_dma_irq, 0,
+ "xrx200_net_tx", &priv->chan_tx);
+ if (ret) {
+ dev_err(priv->dev, "failed to request TX irq %d\n",
+ ch_tx->dma.irq);
+ goto tx_free;
+ }
+
+ return ret;
+
+tx_free:
+ ltq_dma_free(&ch_tx->dma);
+
+rx_ring_free:
+ /* free the allocated RX ring */
+ for (i = 0; i < LTQ_DESC_NUM; i++) {
+ if (priv->chan_rx.skb[i])
+ dev_kfree_skb_any(priv->chan_rx.skb[i]);
+ }
+
+rx_free:
+ ltq_dma_free(&ch_rx->dma);
+ return ret;
+}
+
+static void xrx200_hw_cleanup(struct xrx200_priv *priv)
+{
+ int i;
+
+ ltq_dma_free(&priv->chan_tx.dma);
+ ltq_dma_free(&priv->chan_rx.dma);
+
+ /* free the allocated RX ring */
+ for (i = 0; i < LTQ_DESC_NUM; i++)
+ dev_kfree_skb_any(priv->chan_rx.skb[i]);
+}
+
+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;
+ const u8 *mac;
+ int err;
+
+ /* alloc the network device */
+ net_dev = devm_alloc_etherdev(dev, sizeof(struct xrx200_priv));
+ if (!net_dev)
+ return -ENOMEM;
+
+ priv = netdev_priv(net_dev);
+ priv->net_dev = net_dev;
+ priv->dev = dev;
+
+ net_dev->netdev_ops = &xrx200_netdev_ops;
+ SET_NETDEV_DEV(net_dev, dev);
+ net_dev->min_mtu = ETH_ZLEN;
+ 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);
+ if (IS_ERR(priv->pmac_reg)) {
+ dev_err(dev, "failed to request and remap io ranges\n");
+ return PTR_ERR(priv->pmac_reg);
+ }
+
+ priv->chan_rx.dma.irq = platform_get_irq_byname(pdev, "rx");
+ if (priv->chan_rx.dma.irq < 0) {
+ dev_err(dev, "failed to get RX IRQ, %i\n",
+ priv->chan_rx.dma.irq);
+ return -ENOENT;
+ }
+ priv->chan_tx.dma.irq = platform_get_irq_byname(pdev, "tx");
+ if (priv->chan_tx.dma.irq < 0) {
+ dev_err(dev, "failed to get TX IRQ, %i\n",
+ priv->chan_tx.dma.irq);
+ return -ENOENT;
+ }
+
+ /* get the clock */
+ 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);
+ }
+
+ mac = of_get_mac_address(np);
+ if (mac && is_valid_ether_addr(mac))
+ ether_addr_copy(net_dev->dev_addr, mac);
+ else
+ eth_hw_addr_random(net_dev);
+
+ /* bring up the dma engine and IP core */
+ err = xrx200_dma_init(priv);
+ if (err)
+ return err;
+
+ /* enable clock gate */
+ err = clk_prepare_enable(priv->clk);
+ if (err)
+ goto err_uninit_dma;
+
+ /* set IPG to 12 */
+ xrx200_pmac_mask(priv, PMAC_RX_IPG_MASK, 0xb, PMAC_RX_IPG);
+
+ /* enable status header, enable CRC */
+ xrx200_pmac_mask(priv, 0,
+ PMAC_HD_CTL_RST | PMAC_HD_CTL_AST | PMAC_HD_CTL_RXSH |
+ PMAC_HD_CTL_AS | PMAC_HD_CTL_AC | PMAC_HD_CTL_RC,
+ PMAC_HD_CTL);
+
+ /* setup NAPI */
+ netif_napi_add(net_dev, &priv->chan_rx.napi, xrx200_poll_rx, 32);
+ netif_napi_add(net_dev, &priv->chan_tx.napi, xrx200_tx_housekeeping, 32);
+
+ platform_set_drvdata(pdev, priv);
+
+ err = register_netdev(net_dev);
+ if (err)
+ goto err_unprepare_clk;
+ return err;
+
+err_unprepare_clk:
+ clk_disable_unprepare(priv->clk);
+
+err_uninit_dma:
+ xrx200_hw_cleanup(priv);
+
+ return 0;
+}
+
+static int xrx200_remove(struct platform_device *pdev)
+{
+ struct xrx200_priv *priv = platform_get_drvdata(pdev);
+ struct net_device *net_dev = priv->net_dev;
+
+ /* free stack related instances */
+ netif_stop_queue(net_dev);
+ netif_napi_del(&priv->chan_tx.napi);
+ netif_napi_del(&priv->chan_rx.napi);
+
+ /* remove the actual device */
+ unregister_netdev(net_dev);
+
+ /* release the clock */
+ clk_disable_unprepare(priv->clk);
+
+ /* shut down hardware */
+ xrx200_hw_cleanup(priv);
+
+ return 0;
+}
+
+static const struct of_device_id xrx200_match[] = {
+ { .compatible = "lantiq,xrx200-net" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, xrx200_match);
+
+static struct platform_driver xrx200_driver = {
+ .probe = xrx200_probe,
+ .remove = xrx200_remove,
+ .driver = {
+ .name = "lantiq,xrx200-net",
+ .of_match_table = xrx200_match,
+ },
+};
+
+module_platform_driver(xrx200_driver);
+
+MODULE_AUTHOR("John Crispin <john@phrozen.org>");
+MODULE_DESCRIPTION("Lantiq SoC XRX200 ethernet");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/marvell/Kconfig b/drivers/net/ethernet/marvell/Kconfig
index f33fd22b351c..3238aa7f5dac 100644
--- a/drivers/net/ethernet/marvell/Kconfig
+++ b/drivers/net/ethernet/marvell/Kconfig
@@ -167,4 +167,7 @@ config SKY2_DEBUG
If unsure, say N.
+
+source "drivers/net/ethernet/marvell/octeontx2/Kconfig"
+
endif # NET_VENDOR_MARVELL
diff --git a/drivers/net/ethernet/marvell/Makefile b/drivers/net/ethernet/marvell/Makefile
index 55d4d10aa7d3..89dea7284d5b 100644
--- a/drivers/net/ethernet/marvell/Makefile
+++ b/drivers/net/ethernet/marvell/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_MVPP2) += mvpp2/
obj-$(CONFIG_PXA168_ETH) += pxa168_eth.o
obj-$(CONFIG_SKGE) += skge.o
obj-$(CONFIG_SKY2) += sky2.o
+obj-y += octeontx2/
diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c
index 62f204f32316..1e9bcbdc6a90 100644
--- a/drivers/net/ethernet/marvell/mv643xx_eth.c
+++ b/drivers/net/ethernet/marvell/mv643xx_eth.c
@@ -2733,17 +2733,17 @@ static int mv643xx_eth_shared_of_add_port(struct platform_device *pdev,
memset(&res, 0, sizeof(res));
if (of_irq_to_resource(pnp, 0, &res) <= 0) {
- dev_err(&pdev->dev, "missing interrupt on %s\n", pnp->name);
+ dev_err(&pdev->dev, "missing interrupt on %pOFn\n", pnp);
return -EINVAL;
}
if (of_property_read_u32(pnp, "reg", &ppd.port_number)) {
- dev_err(&pdev->dev, "missing reg property on %s\n", pnp->name);
+ dev_err(&pdev->dev, "missing reg property on %pOFn\n", pnp);
return -EINVAL;
}
if (ppd.port_number >= 3) {
- dev_err(&pdev->dev, "invalid reg property on %s\n", pnp->name);
+ dev_err(&pdev->dev, "invalid reg property on %pOFn\n", pnp);
return -EINVAL;
}
diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c
index b4ed7d394d07..3ba672e9e353 100644
--- a/drivers/net/ethernet/marvell/mvneta.c
+++ b/drivers/net/ethernet/marvell/mvneta.c
@@ -221,6 +221,8 @@
#define MVNETA_GMAC_AN_FLOW_CTRL_EN BIT(11)
#define MVNETA_GMAC_CONFIG_FULL_DUPLEX BIT(12)
#define MVNETA_GMAC_AN_DUPLEX_EN BIT(13)
+#define MVNETA_GMAC_CTRL_4 0x2c90
+#define MVNETA_GMAC4_SHORT_PREAMBLE_ENABLE BIT(1)
#define MVNETA_MIB_COUNTERS_BASE 0x3000
#define MVNETA_MIB_LATE_COLLISION 0x7c
#define MVNETA_DA_FILT_SPEC_MCAST 0x3400
@@ -492,7 +494,7 @@ struct mvneta_port {
#if defined(__LITTLE_ENDIAN)
struct mvneta_tx_desc {
u32 command; /* Options used by HW for packet transmitting.*/
- u16 reserverd1; /* csum_l4 (for future use) */
+ u16 reserved1; /* csum_l4 (for future use) */
u16 data_size; /* Data size of transmitted packet in bytes */
u32 buf_phys_addr; /* Physical addr of transmitted buffer */
u32 reserved2; /* hw_cmd - (for future use, PMT) */
@@ -517,7 +519,7 @@ struct mvneta_rx_desc {
#else
struct mvneta_tx_desc {
u16 data_size; /* Data size of transmitted packet in bytes */
- u16 reserverd1; /* csum_l4 (for future use) */
+ u16 reserved1; /* csum_l4 (for future use) */
u32 command; /* Options used by HW for packet transmitting.*/
u32 reserved2; /* hw_cmd - (for future use, PMT) */
u32 buf_phys_addr; /* Physical addr of transmitted buffer */
@@ -2064,10 +2066,7 @@ static int mvneta_rx_swbm(struct napi_struct *napi,
/* Linux processing */
rxq->skb->protocol = eth_type_trans(rxq->skb, dev);
- if (dev->features & NETIF_F_GRO)
- napi_gro_receive(napi, rxq->skb);
- else
- netif_receive_skb(rxq->skb);
+ napi_gro_receive(napi, rxq->skb);
/* clean uncomplete skb pointer in queue */
rxq->skb = NULL;
@@ -2395,7 +2394,7 @@ error:
}
/* Main tx processing */
-static int mvneta_tx(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t mvneta_tx(struct sk_buff *skb, struct net_device *dev)
{
struct mvneta_port *pp = netdev_priv(dev);
u16 txq_id = skb_get_queue_mapping(skb);
@@ -2509,12 +2508,13 @@ static void mvneta_tx_done_gbe(struct mvneta_port *pp, u32 cause_tx_done)
{
struct mvneta_tx_queue *txq;
struct netdev_queue *nq;
+ int cpu = smp_processor_id();
while (cause_tx_done) {
txq = mvneta_tx_done_policy(pp, cause_tx_done);
nq = netdev_get_tx_queue(pp->dev, txq->id);
- __netif_tx_lock(nq, smp_processor_id());
+ __netif_tx_lock(nq, cpu);
if (txq->count)
mvneta_txq_done(pp, txq);
@@ -3343,6 +3343,7 @@ static void mvneta_validate(struct net_device *ndev, unsigned long *supported,
if (state->interface != PHY_INTERFACE_MODE_NA &&
state->interface != PHY_INTERFACE_MODE_QSGMII &&
state->interface != PHY_INTERFACE_MODE_SGMII &&
+ state->interface != PHY_INTERFACE_MODE_2500BASEX &&
!phy_interface_mode_is_8023z(state->interface) &&
!phy_interface_mode_is_rgmii(state->interface)) {
bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
@@ -3355,9 +3356,15 @@ static void mvneta_validate(struct net_device *ndev, unsigned long *supported,
/* Asymmetric pause is unsupported */
phylink_set(mask, Pause);
- /* Half-duplex at speeds higher than 100Mbit is unsupported */
- phylink_set(mask, 1000baseT_Full);
- phylink_set(mask, 1000baseX_Full);
+
+ /* We cannot use 1Gbps when using the 2.5G interface. */
+ if (state->interface == PHY_INTERFACE_MODE_2500BASEX) {
+ phylink_set(mask, 2500baseT_Full);
+ phylink_set(mask, 2500baseX_Full);
+ } else {
+ phylink_set(mask, 1000baseT_Full);
+ phylink_set(mask, 1000baseX_Full);
+ }
if (!phy_interface_mode_is_8023z(state->interface)) {
/* 10M and 100M are only supported in non-802.3z mode */
@@ -3418,12 +3425,14 @@ static void mvneta_mac_config(struct net_device *ndev, unsigned int mode,
struct mvneta_port *pp = netdev_priv(ndev);
u32 new_ctrl0, gmac_ctrl0 = mvreg_read(pp, MVNETA_GMAC_CTRL_0);
u32 new_ctrl2, gmac_ctrl2 = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
+ u32 new_ctrl4, gmac_ctrl4 = mvreg_read(pp, MVNETA_GMAC_CTRL_4);
u32 new_clk, gmac_clk = mvreg_read(pp, MVNETA_GMAC_CLOCK_DIVIDER);
u32 new_an, gmac_an = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
new_ctrl0 = gmac_ctrl0 & ~MVNETA_GMAC0_PORT_1000BASE_X;
new_ctrl2 = gmac_ctrl2 & ~(MVNETA_GMAC2_INBAND_AN_ENABLE |
MVNETA_GMAC2_PORT_RESET);
+ new_ctrl4 = gmac_ctrl4 & ~(MVNETA_GMAC4_SHORT_PREAMBLE_ENABLE);
new_clk = gmac_clk & ~MVNETA_GMAC_1MS_CLOCK_ENABLE;
new_an = gmac_an & ~(MVNETA_GMAC_INBAND_AN_ENABLE |
MVNETA_GMAC_INBAND_RESTART_AN |
@@ -3456,7 +3465,7 @@ static void mvneta_mac_config(struct net_device *ndev, unsigned int mode,
if (state->duplex)
new_an |= MVNETA_GMAC_CONFIG_FULL_DUPLEX;
- if (state->speed == SPEED_1000)
+ if (state->speed == SPEED_1000 || state->speed == SPEED_2500)
new_an |= MVNETA_GMAC_CONFIG_GMII_SPEED;
else if (state->speed == SPEED_100)
new_an |= MVNETA_GMAC_CONFIG_MII_SPEED;
@@ -3495,10 +3504,18 @@ static void mvneta_mac_config(struct net_device *ndev, unsigned int mode,
MVNETA_GMAC_FORCE_LINK_DOWN);
}
+ /* When at 2.5G, the link partner can send frames with shortened
+ * preambles.
+ */
+ if (state->speed == SPEED_2500)
+ new_ctrl4 |= MVNETA_GMAC4_SHORT_PREAMBLE_ENABLE;
+
if (new_ctrl0 != gmac_ctrl0)
mvreg_write(pp, MVNETA_GMAC_CTRL_0, new_ctrl0);
if (new_ctrl2 != gmac_ctrl2)
mvreg_write(pp, MVNETA_GMAC_CTRL_2, new_ctrl2);
+ if (new_ctrl4 != gmac_ctrl4)
+ mvreg_write(pp, MVNETA_GMAC_CTRL_4, new_ctrl4);
if (new_clk != gmac_clk)
mvreg_write(pp, MVNETA_GMAC_CLOCK_DIVIDER, new_clk);
if (new_an != gmac_an)
@@ -3792,9 +3809,6 @@ static int mvneta_open(struct net_device *dev)
goto err_free_online_hp;
}
- /* In default link is down */
- netif_carrier_off(pp->dev);
-
ret = mvneta_mdio_probe(pp);
if (ret < 0) {
netdev_err(dev, "cannot probe MDIO bus\n");
@@ -4597,7 +4611,8 @@ static int mvneta_probe(struct platform_device *pdev)
}
}
- dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_TSO;
+ dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+ NETIF_F_TSO | NETIF_F_RXCSUM;
dev->hw_features |= dev->features;
dev->vlan_features |= dev->features;
dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h
index 67b9e81b7c02..398328f10743 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h
@@ -253,7 +253,8 @@
#define MVPP2_ISR_ENABLE_INTERRUPT(mask) ((mask) & 0xffff)
#define MVPP2_ISR_DISABLE_INTERRUPT(mask) (((mask) << 16) & 0xffff0000)
#define MVPP2_ISR_RX_TX_CAUSE_REG(port) (0x5480 + 4 * (port))
-#define MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK 0xffff
+#define MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK(version) \
+ ((version) == MVPP21 ? 0xffff : 0xff)
#define MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK 0xff0000
#define MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_OFFSET 16
#define MVPP2_CAUSE_RX_FIFO_OVERRUN_MASK BIT(24)
@@ -330,6 +331,7 @@
#define MVPP2_TXP_SCHED_ENQ_MASK 0xff
#define MVPP2_TXP_SCHED_DISQ_OFFSET 8
#define MVPP2_TXP_SCHED_CMD_1_REG 0x8010
+#define MVPP2_TXP_SCHED_FIXED_PRIO_REG 0x8014
#define MVPP2_TXP_SCHED_PERIOD_REG 0x8018
#define MVPP2_TXP_SCHED_MTU_REG 0x801c
#define MVPP2_TXP_MTU_MAX 0x7FFFF
@@ -613,6 +615,7 @@
/* Port flags */
#define MVPP2_F_LOOPBACK BIT(0)
+#define MVPP2_F_DT_COMPAT BIT(1)
/* Marvell tag types */
enum mvpp2_tag_type {
@@ -662,7 +665,7 @@ enum mvpp2_prs_l3_cast {
#define MVPP21_ADDR_SPACE_SZ 0
#define MVPP22_ADDR_SPACE_SZ SZ_64K
-#define MVPP2_MAX_THREADS 8
+#define MVPP2_MAX_THREADS 9
#define MVPP2_MAX_QVECS MVPP2_MAX_THREADS
/* GMAC MIB Counters register definitions */
@@ -734,6 +737,11 @@ struct mvpp2 {
int port_count;
struct mvpp2_port *port_list[MVPP2_MAX_PORTS];
+ /* Number of Tx threads used */
+ unsigned int nthreads;
+ /* Map of threads needing locking */
+ unsigned long lock_map;
+
/* Aggregated TXQs */
struct mvpp2_tx_queue *aggr_txqs;
@@ -788,6 +796,7 @@ struct mvpp2_queue_vector {
int nrxqs;
u32 pending_cause_rx;
struct mvpp2_port *port;
+ struct cpumask *mask;
};
struct mvpp2_port {
@@ -823,6 +832,12 @@ struct mvpp2_port {
/* Per-CPU port control */
struct mvpp2_port_pcpu __percpu *pcpu;
+ /* Protect the BM refills and the Tx paths when a thread is used on more
+ * than a single CPU.
+ */
+ spinlock_t bm_lock[MVPP2_MAX_THREADS];
+ spinlock_t tx_lock[MVPP2_MAX_THREADS];
+
/* Flags */
unsigned long flags;
@@ -969,7 +984,7 @@ struct mvpp2_txq_pcpu_buf {
/* Per-CPU Tx queue control */
struct mvpp2_txq_pcpu {
- int cpu;
+ unsigned int thread;
/* Number of Tx DMA descriptors in the descriptor ring */
int size;
@@ -1095,14 +1110,6 @@ struct mvpp2_bm_pool {
void mvpp2_write(struct mvpp2 *priv, u32 offset, u32 data);
u32 mvpp2_read(struct mvpp2 *priv, u32 offset);
-u32 mvpp2_read_relaxed(struct mvpp2 *priv, u32 offset);
-
-void mvpp2_percpu_write(struct mvpp2 *priv, int cpu, u32 offset, u32 data);
-u32 mvpp2_percpu_read(struct mvpp2 *priv, int cpu, u32 offset);
-
-void mvpp2_percpu_write_relaxed(struct mvpp2 *priv, int cpu, u32 offset,
- u32 data);
-
void mvpp2_dbgfs_init(struct mvpp2 *priv, const char *name);
void mvpp2_dbgfs_cleanup(struct mvpp2 *priv);
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
index 38cc01beea79..7a37a37e3fb3 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
@@ -82,13 +82,19 @@ u32 mvpp2_read(struct mvpp2 *priv, u32 offset)
return readl(priv->swth_base[0] + offset);
}
-u32 mvpp2_read_relaxed(struct mvpp2 *priv, u32 offset)
+static u32 mvpp2_read_relaxed(struct mvpp2 *priv, u32 offset)
{
return readl_relaxed(priv->swth_base[0] + offset);
}
+
+static inline u32 mvpp2_cpu_to_thread(struct mvpp2 *priv, int cpu)
+{
+ return cpu % priv->nthreads;
+}
+
/* These accessors should be used to access:
*
- * - per-CPU registers, where each CPU has its own copy of the
+ * - per-thread registers, where each thread has its own copy of the
* register.
*
* MVPP2_BM_VIRT_ALLOC_REG
@@ -104,8 +110,8 @@ u32 mvpp2_read_relaxed(struct mvpp2 *priv, u32 offset)
* MVPP2_TXQ_SENT_REG
* MVPP2_RXQ_NUM_REG
*
- * - global registers that must be accessed through a specific CPU
- * window, because they are related to an access to a per-CPU
+ * - global registers that must be accessed through a specific thread
+ * window, because they are related to an access to a per-thread
* register
*
* MVPP2_BM_PHY_ALLOC_REG (related to MVPP2_BM_VIRT_ALLOC_REG)
@@ -122,28 +128,28 @@ u32 mvpp2_read_relaxed(struct mvpp2 *priv, u32 offset)
* MVPP2_TXQ_PREF_BUF_REG (related to MVPP2_TXQ_NUM_REG)
* MVPP2_TXQ_PREF_BUF_REG (related to MVPP2_TXQ_NUM_REG)
*/
-void mvpp2_percpu_write(struct mvpp2 *priv, int cpu,
+static void mvpp2_thread_write(struct mvpp2 *priv, unsigned int thread,
u32 offset, u32 data)
{
- writel(data, priv->swth_base[cpu] + offset);
+ writel(data, priv->swth_base[thread] + offset);
}
-u32 mvpp2_percpu_read(struct mvpp2 *priv, int cpu,
+static u32 mvpp2_thread_read(struct mvpp2 *priv, unsigned int thread,
u32 offset)
{
- return readl(priv->swth_base[cpu] + offset);
+ return readl(priv->swth_base[thread] + offset);
}
-void mvpp2_percpu_write_relaxed(struct mvpp2 *priv, int cpu,
+static void mvpp2_thread_write_relaxed(struct mvpp2 *priv, unsigned int thread,
u32 offset, u32 data)
{
- writel_relaxed(data, priv->swth_base[cpu] + offset);
+ writel_relaxed(data, priv->swth_base[thread] + offset);
}
-static u32 mvpp2_percpu_read_relaxed(struct mvpp2 *priv, int cpu,
+static u32 mvpp2_thread_read_relaxed(struct mvpp2 *priv, unsigned int thread,
u32 offset)
{
- return readl_relaxed(priv->swth_base[cpu] + offset);
+ return readl_relaxed(priv->swth_base[thread] + offset);
}
static dma_addr_t mvpp2_txdesc_dma_addr_get(struct mvpp2_port *port,
@@ -385,17 +391,17 @@ static void mvpp2_bm_bufs_get_addrs(struct device *dev, struct mvpp2 *priv,
dma_addr_t *dma_addr,
phys_addr_t *phys_addr)
{
- int cpu = get_cpu();
+ unsigned int thread = mvpp2_cpu_to_thread(priv, get_cpu());
- *dma_addr = mvpp2_percpu_read(priv, cpu,
+ *dma_addr = mvpp2_thread_read(priv, thread,
MVPP2_BM_PHY_ALLOC_REG(bm_pool->id));
- *phys_addr = mvpp2_percpu_read(priv, cpu, MVPP2_BM_VIRT_ALLOC_REG);
+ *phys_addr = mvpp2_thread_read(priv, thread, MVPP2_BM_VIRT_ALLOC_REG);
if (priv->hw_version == MVPP22) {
u32 val;
u32 dma_addr_highbits, phys_addr_highbits;
- val = mvpp2_percpu_read(priv, cpu, MVPP22_BM_ADDR_HIGH_ALLOC);
+ val = mvpp2_thread_read(priv, thread, MVPP22_BM_ADDR_HIGH_ALLOC);
dma_addr_highbits = (val & MVPP22_BM_ADDR_HIGH_PHYS_MASK);
phys_addr_highbits = (val & MVPP22_BM_ADDR_HIGH_VIRT_MASK) >>
MVPP22_BM_ADDR_HIGH_VIRT_SHIFT;
@@ -626,7 +632,11 @@ static inline void mvpp2_bm_pool_put(struct mvpp2_port *port, int pool,
dma_addr_t buf_dma_addr,
phys_addr_t buf_phys_addr)
{
- int cpu = get_cpu();
+ unsigned int thread = mvpp2_cpu_to_thread(port->priv, get_cpu());
+ unsigned long flags = 0;
+
+ if (test_bit(thread, &port->priv->lock_map))
+ spin_lock_irqsave(&port->bm_lock[thread], flags);
if (port->priv->hw_version == MVPP22) {
u32 val = 0;
@@ -640,7 +650,7 @@ static inline void mvpp2_bm_pool_put(struct mvpp2_port *port, int pool,
<< MVPP22_BM_ADDR_HIGH_VIRT_RLS_SHIFT) &
MVPP22_BM_ADDR_HIGH_VIRT_RLS_MASK;
- mvpp2_percpu_write_relaxed(port->priv, cpu,
+ mvpp2_thread_write_relaxed(port->priv, thread,
MVPP22_BM_ADDR_HIGH_RLS_REG, val);
}
@@ -649,11 +659,14 @@ static inline void mvpp2_bm_pool_put(struct mvpp2_port *port, int pool,
* descriptor. Instead of storing the virtual address, we
* store the physical address
*/
- mvpp2_percpu_write_relaxed(port->priv, cpu,
+ mvpp2_thread_write_relaxed(port->priv, thread,
MVPP2_BM_VIRT_RLS_REG, buf_phys_addr);
- mvpp2_percpu_write_relaxed(port->priv, cpu,
+ mvpp2_thread_write_relaxed(port->priv, thread,
MVPP2_BM_PHY_RLS_REG(pool), buf_dma_addr);
+ if (test_bit(thread, &port->priv->lock_map))
+ spin_unlock_irqrestore(&port->bm_lock[thread], flags);
+
put_cpu();
}
@@ -886,7 +899,7 @@ static inline void mvpp2_qvec_interrupt_disable(struct mvpp2_queue_vector *qvec)
MVPP2_ISR_DISABLE_INTERRUPT(qvec->sw_thread_mask));
}
-/* Mask the current CPU's Rx/Tx interrupts
+/* Mask the current thread's Rx/Tx interrupts
* Called by on_each_cpu(), guaranteed to run with migration disabled,
* using smp_processor_id() is OK.
*/
@@ -894,11 +907,16 @@ static void mvpp2_interrupts_mask(void *arg)
{
struct mvpp2_port *port = arg;
- mvpp2_percpu_write(port->priv, smp_processor_id(),
+ /* If the thread isn't used, don't do anything */
+ if (smp_processor_id() > port->priv->nthreads)
+ return;
+
+ mvpp2_thread_write(port->priv,
+ mvpp2_cpu_to_thread(port->priv, smp_processor_id()),
MVPP2_ISR_RX_TX_MASK_REG(port->id), 0);
}
-/* Unmask the current CPU's Rx/Tx interrupts.
+/* Unmask the current thread's Rx/Tx interrupts.
* Called by on_each_cpu(), guaranteed to run with migration disabled,
* using smp_processor_id() is OK.
*/
@@ -907,12 +925,17 @@ static void mvpp2_interrupts_unmask(void *arg)
struct mvpp2_port *port = arg;
u32 val;
+ /* If the thread isn't used, don't do anything */
+ if (smp_processor_id() > port->priv->nthreads)
+ return;
+
val = MVPP2_CAUSE_MISC_SUM_MASK |
- MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK;
+ MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK(port->priv->hw_version);
if (port->has_tx_irqs)
val |= MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK;
- mvpp2_percpu_write(port->priv, smp_processor_id(),
+ mvpp2_thread_write(port->priv,
+ mvpp2_cpu_to_thread(port->priv, smp_processor_id()),
MVPP2_ISR_RX_TX_MASK_REG(port->id), val);
}
@@ -928,7 +951,7 @@ mvpp2_shared_interrupt_mask_unmask(struct mvpp2_port *port, bool mask)
if (mask)
val = 0;
else
- val = MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK;
+ val = MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK(MVPP22);
for (i = 0; i < port->nqvecs; i++) {
struct mvpp2_queue_vector *v = port->qvecs + i;
@@ -936,7 +959,7 @@ mvpp2_shared_interrupt_mask_unmask(struct mvpp2_port *port, bool mask)
if (v->type != MVPP2_QUEUE_VECTOR_SHARED)
continue;
- mvpp2_percpu_write(port->priv, v->sw_thread_id,
+ mvpp2_thread_write(port->priv, v->sw_thread_id,
MVPP2_ISR_RX_TX_MASK_REG(port->id), val);
}
}
@@ -1425,6 +1448,9 @@ static void mvpp2_defaults_set(struct mvpp2_port *port)
tx_port_num);
mvpp2_write(port->priv, MVPP2_TXP_SCHED_CMD_1_REG, 0);
+ /* Set TXQ scheduling to Round-Robin */
+ mvpp2_write(port->priv, MVPP2_TXP_SCHED_FIXED_PRIO_REG, 0);
+
/* Close bandwidth for all queues */
for (queue = 0; queue < MVPP2_MAX_TXQ; queue++) {
ptxq = mvpp2_txq_phys(port->id, queue);
@@ -1624,7 +1650,8 @@ mvpp2_txq_next_desc_get(struct mvpp2_tx_queue *txq)
static void mvpp2_aggr_txq_pend_desc_add(struct mvpp2_port *port, int pending)
{
/* aggregated access - relevant TXQ number is written in TX desc */
- mvpp2_percpu_write(port->priv, smp_processor_id(),
+ mvpp2_thread_write(port->priv,
+ mvpp2_cpu_to_thread(port->priv, smp_processor_id()),
MVPP2_AGGR_TXQ_UPDATE_REG, pending);
}
@@ -1634,14 +1661,15 @@ static void mvpp2_aggr_txq_pend_desc_add(struct mvpp2_port *port, int pending)
* Called only from mvpp2_tx(), so migration is disabled, using
* smp_processor_id() is OK.
*/
-static int mvpp2_aggr_desc_num_check(struct mvpp2 *priv,
+static int mvpp2_aggr_desc_num_check(struct mvpp2_port *port,
struct mvpp2_tx_queue *aggr_txq, int num)
{
if ((aggr_txq->count + num) > MVPP2_AGGR_TXQ_SIZE) {
/* Update number of occupied aggregated Tx descriptors */
- int cpu = smp_processor_id();
- u32 val = mvpp2_read_relaxed(priv,
- MVPP2_AGGR_TXQ_STATUS_REG(cpu));
+ unsigned int thread =
+ mvpp2_cpu_to_thread(port->priv, smp_processor_id());
+ u32 val = mvpp2_read_relaxed(port->priv,
+ MVPP2_AGGR_TXQ_STATUS_REG(thread));
aggr_txq->count = val & MVPP2_AGGR_TXQ_PENDING_MASK;
@@ -1657,16 +1685,17 @@ static int mvpp2_aggr_desc_num_check(struct mvpp2 *priv,
* only by mvpp2_tx(), so migration is disabled, using
* smp_processor_id() is OK.
*/
-static int mvpp2_txq_alloc_reserved_desc(struct mvpp2 *priv,
+static int mvpp2_txq_alloc_reserved_desc(struct mvpp2_port *port,
struct mvpp2_tx_queue *txq, int num)
{
+ unsigned int thread = mvpp2_cpu_to_thread(port->priv, smp_processor_id());
+ struct mvpp2 *priv = port->priv;
u32 val;
- int cpu = smp_processor_id();
val = (txq->id << MVPP2_TXQ_RSVD_REQ_Q_OFFSET) | num;
- mvpp2_percpu_write_relaxed(priv, cpu, MVPP2_TXQ_RSVD_REQ_REG, val);
+ mvpp2_thread_write_relaxed(priv, thread, MVPP2_TXQ_RSVD_REQ_REG, val);
- val = mvpp2_percpu_read_relaxed(priv, cpu, MVPP2_TXQ_RSVD_RSLT_REG);
+ val = mvpp2_thread_read_relaxed(priv, thread, MVPP2_TXQ_RSVD_RSLT_REG);
return val & MVPP2_TXQ_RSVD_RSLT_MASK;
}
@@ -1674,12 +1703,13 @@ static int mvpp2_txq_alloc_reserved_desc(struct mvpp2 *priv,
/* Check if there are enough reserved descriptors for transmission.
* If not, request chunk of reserved descriptors and check again.
*/
-static int mvpp2_txq_reserved_desc_num_proc(struct mvpp2 *priv,
+static int mvpp2_txq_reserved_desc_num_proc(struct mvpp2_port *port,
struct mvpp2_tx_queue *txq,
struct mvpp2_txq_pcpu *txq_pcpu,
int num)
{
- int req, cpu, desc_count;
+ int req, desc_count;
+ unsigned int thread;
if (txq_pcpu->reserved_num >= num)
return 0;
@@ -1690,10 +1720,10 @@ static int mvpp2_txq_reserved_desc_num_proc(struct mvpp2 *priv,
desc_count = 0;
/* Compute total of used descriptors */
- for_each_present_cpu(cpu) {
+ for (thread = 0; thread < port->priv->nthreads; thread++) {
struct mvpp2_txq_pcpu *txq_pcpu_aux;
- txq_pcpu_aux = per_cpu_ptr(txq->pcpu, cpu);
+ txq_pcpu_aux = per_cpu_ptr(txq->pcpu, thread);
desc_count += txq_pcpu_aux->count;
desc_count += txq_pcpu_aux->reserved_num;
}
@@ -1702,10 +1732,10 @@ static int mvpp2_txq_reserved_desc_num_proc(struct mvpp2 *priv,
desc_count += req;
if (desc_count >
- (txq->size - (num_present_cpus() * MVPP2_CPU_DESC_CHUNK)))
+ (txq->size - (MVPP2_MAX_THREADS * MVPP2_CPU_DESC_CHUNK)))
return -ENOMEM;
- txq_pcpu->reserved_num += mvpp2_txq_alloc_reserved_desc(priv, txq, req);
+ txq_pcpu->reserved_num += mvpp2_txq_alloc_reserved_desc(port, txq, req);
/* OK, the descriptor could have been updated: check again. */
if (txq_pcpu->reserved_num < num)
@@ -1725,7 +1755,7 @@ static void mvpp2_txq_desc_put(struct mvpp2_tx_queue *txq)
}
/* Set Tx descriptors fields relevant for CSUM calculation */
-static u32 mvpp2_txq_desc_csum(int l3_offs, int l3_proto,
+static u32 mvpp2_txq_desc_csum(int l3_offs, __be16 l3_proto,
int ip_hdr_len, int l4_proto)
{
u32 command;
@@ -1759,7 +1789,7 @@ static u32 mvpp2_txq_desc_csum(int l3_offs, int l3_proto,
/* Get number of sent descriptors and decrement counter.
* The number of sent descriptors is returned.
- * Per-CPU access
+ * Per-thread access
*
* Called only from mvpp2_txq_done(), called from mvpp2_tx()
* (migration disabled) and from the TX completion tasklet (migration
@@ -1771,7 +1801,8 @@ static inline int mvpp2_txq_sent_desc_proc(struct mvpp2_port *port,
u32 val;
/* Reading status reg resets transmitted descriptor counter */
- val = mvpp2_percpu_read_relaxed(port->priv, smp_processor_id(),
+ val = mvpp2_thread_read_relaxed(port->priv,
+ mvpp2_cpu_to_thread(port->priv, smp_processor_id()),
MVPP2_TXQ_SENT_REG(txq->id));
return (val & MVPP2_TRANSMITTED_COUNT_MASK) >>
@@ -1786,10 +1817,15 @@ static void mvpp2_txq_sent_counter_clear(void *arg)
struct mvpp2_port *port = arg;
int queue;
+ /* If the thread isn't used, don't do anything */
+ if (smp_processor_id() > port->priv->nthreads)
+ return;
+
for (queue = 0; queue < port->ntxqs; queue++) {
int id = port->txqs[queue]->id;
- mvpp2_percpu_read(port->priv, smp_processor_id(),
+ mvpp2_thread_read(port->priv,
+ mvpp2_cpu_to_thread(port->priv, smp_processor_id()),
MVPP2_TXQ_SENT_REG(id));
}
}
@@ -1849,13 +1885,13 @@ static void mvpp2_txp_max_tx_size_set(struct mvpp2_port *port)
static void mvpp2_rx_pkts_coal_set(struct mvpp2_port *port,
struct mvpp2_rx_queue *rxq)
{
- int cpu = get_cpu();
+ unsigned int thread = mvpp2_cpu_to_thread(port->priv, get_cpu());
if (rxq->pkts_coal > MVPP2_OCCUPIED_THRESH_MASK)
rxq->pkts_coal = MVPP2_OCCUPIED_THRESH_MASK;
- mvpp2_percpu_write(port->priv, cpu, MVPP2_RXQ_NUM_REG, rxq->id);
- mvpp2_percpu_write(port->priv, cpu, MVPP2_RXQ_THRESH_REG,
+ mvpp2_thread_write(port->priv, thread, MVPP2_RXQ_NUM_REG, rxq->id);
+ mvpp2_thread_write(port->priv, thread, MVPP2_RXQ_THRESH_REG,
rxq->pkts_coal);
put_cpu();
@@ -1865,15 +1901,15 @@ static void mvpp2_rx_pkts_coal_set(struct mvpp2_port *port,
static void mvpp2_tx_pkts_coal_set(struct mvpp2_port *port,
struct mvpp2_tx_queue *txq)
{
- int cpu = get_cpu();
+ unsigned int thread = mvpp2_cpu_to_thread(port->priv, get_cpu());
u32 val;
if (txq->done_pkts_coal > MVPP2_TXQ_THRESH_MASK)
txq->done_pkts_coal = MVPP2_TXQ_THRESH_MASK;
val = (txq->done_pkts_coal << MVPP2_TXQ_THRESH_OFFSET);
- mvpp2_percpu_write(port->priv, cpu, MVPP2_TXQ_NUM_REG, txq->id);
- mvpp2_percpu_write(port->priv, cpu, MVPP2_TXQ_THRESH_REG, val);
+ mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_NUM_REG, txq->id);
+ mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_THRESH_REG, val);
put_cpu();
}
@@ -1974,7 +2010,7 @@ static void mvpp2_txq_done(struct mvpp2_port *port, struct mvpp2_tx_queue *txq,
struct netdev_queue *nq = netdev_get_tx_queue(port->dev, txq->log_id);
int tx_done;
- if (txq_pcpu->cpu != smp_processor_id())
+ if (txq_pcpu->thread != mvpp2_cpu_to_thread(port->priv, smp_processor_id()))
netdev_err(port->dev, "wrong cpu on the end of Tx processing\n");
tx_done = mvpp2_txq_sent_desc_proc(port, txq);
@@ -1990,7 +2026,7 @@ static void mvpp2_txq_done(struct mvpp2_port *port, struct mvpp2_tx_queue *txq,
}
static unsigned int mvpp2_tx_done(struct mvpp2_port *port, u32 cause,
- int cpu)
+ unsigned int thread)
{
struct mvpp2_tx_queue *txq;
struct mvpp2_txq_pcpu *txq_pcpu;
@@ -2001,7 +2037,7 @@ static unsigned int mvpp2_tx_done(struct mvpp2_port *port, u32 cause,
if (!txq)
break;
- txq_pcpu = per_cpu_ptr(txq->pcpu, cpu);
+ txq_pcpu = per_cpu_ptr(txq->pcpu, thread);
if (txq_pcpu->count) {
mvpp2_txq_done(port, txq, txq_pcpu);
@@ -2017,8 +2053,8 @@ static unsigned int mvpp2_tx_done(struct mvpp2_port *port, u32 cause,
/* Allocate and initialize descriptors for aggr TXQ */
static int mvpp2_aggr_txq_init(struct platform_device *pdev,
- struct mvpp2_tx_queue *aggr_txq, int cpu,
- struct mvpp2 *priv)
+ struct mvpp2_tx_queue *aggr_txq,
+ unsigned int thread, struct mvpp2 *priv)
{
u32 txq_dma;
@@ -2033,7 +2069,7 @@ static int mvpp2_aggr_txq_init(struct platform_device *pdev,
/* Aggr TXQ no reset WA */
aggr_txq->next_desc_to_proc = mvpp2_read(priv,
- MVPP2_AGGR_TXQ_INDEX_REG(cpu));
+ MVPP2_AGGR_TXQ_INDEX_REG(thread));
/* Set Tx descriptors queue starting address indirect
* access
@@ -2044,8 +2080,8 @@ static int mvpp2_aggr_txq_init(struct platform_device *pdev,
txq_dma = aggr_txq->descs_dma >>
MVPP22_AGGR_TXQ_DESC_ADDR_OFFS;
- mvpp2_write(priv, MVPP2_AGGR_TXQ_DESC_ADDR_REG(cpu), txq_dma);
- mvpp2_write(priv, MVPP2_AGGR_TXQ_DESC_SIZE_REG(cpu),
+ mvpp2_write(priv, MVPP2_AGGR_TXQ_DESC_ADDR_REG(thread), txq_dma);
+ mvpp2_write(priv, MVPP2_AGGR_TXQ_DESC_SIZE_REG(thread),
MVPP2_AGGR_TXQ_SIZE);
return 0;
@@ -2056,8 +2092,8 @@ static int mvpp2_rxq_init(struct mvpp2_port *port,
struct mvpp2_rx_queue *rxq)
{
+ unsigned int thread;
u32 rxq_dma;
- int cpu;
rxq->size = port->rx_ring_size;
@@ -2074,15 +2110,15 @@ static int mvpp2_rxq_init(struct mvpp2_port *port,
mvpp2_write(port->priv, MVPP2_RXQ_STATUS_REG(rxq->id), 0);
/* Set Rx descriptors queue starting address - indirect access */
- cpu = get_cpu();
- mvpp2_percpu_write(port->priv, cpu, MVPP2_RXQ_NUM_REG, rxq->id);
+ thread = mvpp2_cpu_to_thread(port->priv, get_cpu());
+ mvpp2_thread_write(port->priv, thread, MVPP2_RXQ_NUM_REG, rxq->id);
if (port->priv->hw_version == MVPP21)
rxq_dma = rxq->descs_dma;
else
rxq_dma = rxq->descs_dma >> MVPP22_DESC_ADDR_OFFS;
- mvpp2_percpu_write(port->priv, cpu, MVPP2_RXQ_DESC_ADDR_REG, rxq_dma);
- mvpp2_percpu_write(port->priv, cpu, MVPP2_RXQ_DESC_SIZE_REG, rxq->size);
- mvpp2_percpu_write(port->priv, cpu, MVPP2_RXQ_INDEX_REG, 0);
+ mvpp2_thread_write(port->priv, thread, MVPP2_RXQ_DESC_ADDR_REG, rxq_dma);
+ mvpp2_thread_write(port->priv, thread, MVPP2_RXQ_DESC_SIZE_REG, rxq->size);
+ mvpp2_thread_write(port->priv, thread, MVPP2_RXQ_INDEX_REG, 0);
put_cpu();
/* Set Offset */
@@ -2127,7 +2163,7 @@ static void mvpp2_rxq_drop_pkts(struct mvpp2_port *port,
static void mvpp2_rxq_deinit(struct mvpp2_port *port,
struct mvpp2_rx_queue *rxq)
{
- int cpu;
+ unsigned int thread;
mvpp2_rxq_drop_pkts(port, rxq);
@@ -2146,10 +2182,10 @@ static void mvpp2_rxq_deinit(struct mvpp2_port *port,
* free descriptor number
*/
mvpp2_write(port->priv, MVPP2_RXQ_STATUS_REG(rxq->id), 0);
- cpu = get_cpu();
- mvpp2_percpu_write(port->priv, cpu, MVPP2_RXQ_NUM_REG, rxq->id);
- mvpp2_percpu_write(port->priv, cpu, MVPP2_RXQ_DESC_ADDR_REG, 0);
- mvpp2_percpu_write(port->priv, cpu, MVPP2_RXQ_DESC_SIZE_REG, 0);
+ thread = mvpp2_cpu_to_thread(port->priv, get_cpu());
+ mvpp2_thread_write(port->priv, thread, MVPP2_RXQ_NUM_REG, rxq->id);
+ mvpp2_thread_write(port->priv, thread, MVPP2_RXQ_DESC_ADDR_REG, 0);
+ mvpp2_thread_write(port->priv, thread, MVPP2_RXQ_DESC_SIZE_REG, 0);
put_cpu();
}
@@ -2158,7 +2194,8 @@ static int mvpp2_txq_init(struct mvpp2_port *port,
struct mvpp2_tx_queue *txq)
{
u32 val;
- int cpu, desc, desc_per_txq, tx_port_num;
+ unsigned int thread;
+ int desc, desc_per_txq, tx_port_num;
struct mvpp2_txq_pcpu *txq_pcpu;
txq->size = port->tx_ring_size;
@@ -2173,18 +2210,18 @@ static int mvpp2_txq_init(struct mvpp2_port *port,
txq->last_desc = txq->size - 1;
/* Set Tx descriptors queue starting address - indirect access */
- cpu = get_cpu();
- mvpp2_percpu_write(port->priv, cpu, MVPP2_TXQ_NUM_REG, txq->id);
- mvpp2_percpu_write(port->priv, cpu, MVPP2_TXQ_DESC_ADDR_REG,
+ thread = mvpp2_cpu_to_thread(port->priv, get_cpu());
+ mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_NUM_REG, txq->id);
+ mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_DESC_ADDR_REG,
txq->descs_dma);
- mvpp2_percpu_write(port->priv, cpu, MVPP2_TXQ_DESC_SIZE_REG,
+ mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_DESC_SIZE_REG,
txq->size & MVPP2_TXQ_DESC_SIZE_MASK);
- mvpp2_percpu_write(port->priv, cpu, MVPP2_TXQ_INDEX_REG, 0);
- mvpp2_percpu_write(port->priv, cpu, MVPP2_TXQ_RSVD_CLR_REG,
+ mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_INDEX_REG, 0);
+ mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_RSVD_CLR_REG,
txq->id << MVPP2_TXQ_RSVD_CLR_OFFSET);
- val = mvpp2_percpu_read(port->priv, cpu, MVPP2_TXQ_PENDING_REG);
+ val = mvpp2_thread_read(port->priv, thread, MVPP2_TXQ_PENDING_REG);
val &= ~MVPP2_TXQ_PENDING_MASK;
- mvpp2_percpu_write(port->priv, cpu, MVPP2_TXQ_PENDING_REG, val);
+ mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_PENDING_REG, val);
/* Calculate base address in prefetch buffer. We reserve 16 descriptors
* for each existing TXQ.
@@ -2195,7 +2232,7 @@ static int mvpp2_txq_init(struct mvpp2_port *port,
desc = (port->id * MVPP2_MAX_TXQ * desc_per_txq) +
(txq->log_id * desc_per_txq);
- mvpp2_percpu_write(port->priv, cpu, MVPP2_TXQ_PREF_BUF_REG,
+ mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_PREF_BUF_REG,
MVPP2_PREF_BUF_PTR(desc) | MVPP2_PREF_BUF_SIZE_16 |
MVPP2_PREF_BUF_THRESH(desc_per_txq / 2));
put_cpu();
@@ -2214,8 +2251,8 @@ static int mvpp2_txq_init(struct mvpp2_port *port,
mvpp2_write(port->priv, MVPP2_TXQ_SCHED_TOKEN_SIZE_REG(txq->log_id),
val);
- for_each_present_cpu(cpu) {
- txq_pcpu = per_cpu_ptr(txq->pcpu, cpu);
+ for (thread = 0; thread < port->priv->nthreads; thread++) {
+ txq_pcpu = per_cpu_ptr(txq->pcpu, thread);
txq_pcpu->size = txq->size;
txq_pcpu->buffs = kmalloc_array(txq_pcpu->size,
sizeof(*txq_pcpu->buffs),
@@ -2249,10 +2286,10 @@ static void mvpp2_txq_deinit(struct mvpp2_port *port,
struct mvpp2_tx_queue *txq)
{
struct mvpp2_txq_pcpu *txq_pcpu;
- int cpu;
+ unsigned int thread;
- for_each_present_cpu(cpu) {
- txq_pcpu = per_cpu_ptr(txq->pcpu, cpu);
+ for (thread = 0; thread < port->priv->nthreads; thread++) {
+ txq_pcpu = per_cpu_ptr(txq->pcpu, thread);
kfree(txq_pcpu->buffs);
if (txq_pcpu->tso_headers)
@@ -2278,10 +2315,10 @@ static void mvpp2_txq_deinit(struct mvpp2_port *port,
mvpp2_write(port->priv, MVPP2_TXQ_SCHED_TOKEN_CNTR_REG(txq->id), 0);
/* Set Tx descriptors queue starting address and size */
- cpu = get_cpu();
- mvpp2_percpu_write(port->priv, cpu, MVPP2_TXQ_NUM_REG, txq->id);
- mvpp2_percpu_write(port->priv, cpu, MVPP2_TXQ_DESC_ADDR_REG, 0);
- mvpp2_percpu_write(port->priv, cpu, MVPP2_TXQ_DESC_SIZE_REG, 0);
+ thread = mvpp2_cpu_to_thread(port->priv, get_cpu());
+ mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_NUM_REG, txq->id);
+ mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_DESC_ADDR_REG, 0);
+ mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_DESC_SIZE_REG, 0);
put_cpu();
}
@@ -2289,14 +2326,14 @@ static void mvpp2_txq_deinit(struct mvpp2_port *port,
static void mvpp2_txq_clean(struct mvpp2_port *port, struct mvpp2_tx_queue *txq)
{
struct mvpp2_txq_pcpu *txq_pcpu;
- int delay, pending, cpu;
+ int delay, pending;
+ unsigned int thread = mvpp2_cpu_to_thread(port->priv, get_cpu());
u32 val;
- cpu = get_cpu();
- mvpp2_percpu_write(port->priv, cpu, MVPP2_TXQ_NUM_REG, txq->id);
- val = mvpp2_percpu_read(port->priv, cpu, MVPP2_TXQ_PREF_BUF_REG);
+ mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_NUM_REG, txq->id);
+ val = mvpp2_thread_read(port->priv, thread, MVPP2_TXQ_PREF_BUF_REG);
val |= MVPP2_TXQ_DRAIN_EN_MASK;
- mvpp2_percpu_write(port->priv, cpu, MVPP2_TXQ_PREF_BUF_REG, val);
+ mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_PREF_BUF_REG, val);
/* The napi queue has been stopped so wait for all packets
* to be transmitted.
@@ -2312,17 +2349,17 @@ static void mvpp2_txq_clean(struct mvpp2_port *port, struct mvpp2_tx_queue *txq)
mdelay(1);
delay++;
- pending = mvpp2_percpu_read(port->priv, cpu,
+ pending = mvpp2_thread_read(port->priv, thread,
MVPP2_TXQ_PENDING_REG);
pending &= MVPP2_TXQ_PENDING_MASK;
} while (pending);
val &= ~MVPP2_TXQ_DRAIN_EN_MASK;
- mvpp2_percpu_write(port->priv, cpu, MVPP2_TXQ_PREF_BUF_REG, val);
+ mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_PREF_BUF_REG, val);
put_cpu();
- for_each_present_cpu(cpu) {
- txq_pcpu = per_cpu_ptr(txq->pcpu, cpu);
+ for (thread = 0; thread < port->priv->nthreads; thread++) {
+ txq_pcpu = per_cpu_ptr(txq->pcpu, thread);
/* Release all packets */
mvpp2_txq_bufs_free(port, txq, txq_pcpu, txq_pcpu->count);
@@ -2389,13 +2426,17 @@ err_cleanup:
static int mvpp2_setup_txqs(struct mvpp2_port *port)
{
struct mvpp2_tx_queue *txq;
- int queue, err;
+ int queue, err, cpu;
for (queue = 0; queue < port->ntxqs; queue++) {
txq = port->txqs[queue];
err = mvpp2_txq_init(port, txq);
if (err)
goto err_cleanup;
+
+ /* Assign this queue to a CPU */
+ cpu = queue % num_present_cpus();
+ netif_set_xps_queue(port->dev, cpumask_of(cpu), queue);
}
if (port->has_tx_irqs) {
@@ -2503,16 +2544,20 @@ static void mvpp2_tx_proc_cb(unsigned long data)
{
struct net_device *dev = (struct net_device *)data;
struct mvpp2_port *port = netdev_priv(dev);
- struct mvpp2_port_pcpu *port_pcpu = this_cpu_ptr(port->pcpu);
+ struct mvpp2_port_pcpu *port_pcpu;
unsigned int tx_todo, cause;
+ port_pcpu = per_cpu_ptr(port->pcpu,
+ mvpp2_cpu_to_thread(port->priv, smp_processor_id()));
+
if (!netif_running(dev))
return;
port_pcpu->timer_scheduled = false;
/* Process all the Tx queues */
cause = (1 << port->ntxqs) - 1;
- tx_todo = mvpp2_tx_done(port, cause, smp_processor_id());
+ tx_todo = mvpp2_tx_done(port, cause,
+ mvpp2_cpu_to_thread(port->priv, smp_processor_id()));
/* Set the timer in case not all the packets were processed */
if (tx_todo)
@@ -2600,14 +2645,15 @@ static u32 mvpp2_skb_tx_csum(struct mvpp2_port *port, struct sk_buff *skb)
if (skb->ip_summed == CHECKSUM_PARTIAL) {
int ip_hdr_len = 0;
u8 l4_proto;
+ __be16 l3_proto = vlan_get_protocol(skb);
- if (skb->protocol == htons(ETH_P_IP)) {
+ if (l3_proto == htons(ETH_P_IP)) {
struct iphdr *ip4h = ip_hdr(skb);
/* Calculate IPv4 checksum and L4 checksum */
ip_hdr_len = ip4h->ihl;
l4_proto = ip4h->protocol;
- } else if (skb->protocol == htons(ETH_P_IPV6)) {
+ } else if (l3_proto == htons(ETH_P_IPV6)) {
struct ipv6hdr *ip6h = ipv6_hdr(skb);
/* Read l4_protocol from one of IPv6 extra headers */
@@ -2619,7 +2665,7 @@ static u32 mvpp2_skb_tx_csum(struct mvpp2_port *port, struct sk_buff *skb)
}
return mvpp2_txq_desc_csum(skb_network_offset(skb),
- skb->protocol, ip_hdr_len, l4_proto);
+ l3_proto, ip_hdr_len, l4_proto);
}
return MVPP2_TXD_L4_CSUM_NOT | MVPP2_TXD_IP_CSUM_DISABLE;
@@ -2728,7 +2774,8 @@ static inline void
tx_desc_unmap_put(struct mvpp2_port *port, struct mvpp2_tx_queue *txq,
struct mvpp2_tx_desc *desc)
{
- struct mvpp2_txq_pcpu *txq_pcpu = this_cpu_ptr(txq->pcpu);
+ unsigned int thread = mvpp2_cpu_to_thread(port->priv, smp_processor_id());
+ struct mvpp2_txq_pcpu *txq_pcpu = per_cpu_ptr(txq->pcpu, thread);
dma_addr_t buf_dma_addr =
mvpp2_txdesc_dma_addr_get(port, desc);
@@ -2745,7 +2792,8 @@ static int mvpp2_tx_frag_process(struct mvpp2_port *port, struct sk_buff *skb,
struct mvpp2_tx_queue *aggr_txq,
struct mvpp2_tx_queue *txq)
{
- struct mvpp2_txq_pcpu *txq_pcpu = this_cpu_ptr(txq->pcpu);
+ unsigned int thread = mvpp2_cpu_to_thread(port->priv, smp_processor_id());
+ struct mvpp2_txq_pcpu *txq_pcpu = per_cpu_ptr(txq->pcpu, thread);
struct mvpp2_tx_desc *tx_desc;
int i;
dma_addr_t buf_dma_addr;
@@ -2864,9 +2912,8 @@ static int mvpp2_tx_tso(struct sk_buff *skb, struct net_device *dev,
int i, len, descs = 0;
/* Check number of available descriptors */
- if (mvpp2_aggr_desc_num_check(port->priv, aggr_txq,
- tso_count_descs(skb)) ||
- mvpp2_txq_reserved_desc_num_proc(port->priv, txq, txq_pcpu,
+ if (mvpp2_aggr_desc_num_check(port, aggr_txq, tso_count_descs(skb)) ||
+ mvpp2_txq_reserved_desc_num_proc(port, txq, txq_pcpu,
tso_count_descs(skb)))
return 0;
@@ -2906,21 +2953,28 @@ release:
}
/* Main tx processing */
-static int mvpp2_tx(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t mvpp2_tx(struct sk_buff *skb, struct net_device *dev)
{
struct mvpp2_port *port = netdev_priv(dev);
struct mvpp2_tx_queue *txq, *aggr_txq;
struct mvpp2_txq_pcpu *txq_pcpu;
struct mvpp2_tx_desc *tx_desc;
dma_addr_t buf_dma_addr;
+ unsigned long flags = 0;
+ unsigned int thread;
int frags = 0;
u16 txq_id;
u32 tx_cmd;
+ thread = mvpp2_cpu_to_thread(port->priv, smp_processor_id());
+
txq_id = skb_get_queue_mapping(skb);
txq = port->txqs[txq_id];
- txq_pcpu = this_cpu_ptr(txq->pcpu);
- aggr_txq = &port->priv->aggr_txqs[smp_processor_id()];
+ txq_pcpu = per_cpu_ptr(txq->pcpu, thread);
+ aggr_txq = &port->priv->aggr_txqs[thread];
+
+ if (test_bit(thread, &port->priv->lock_map))
+ spin_lock_irqsave(&port->tx_lock[thread], flags);
if (skb_is_gso(skb)) {
frags = mvpp2_tx_tso(skb, dev, txq, aggr_txq, txq_pcpu);
@@ -2929,9 +2983,8 @@ static int mvpp2_tx(struct sk_buff *skb, struct net_device *dev)
frags = skb_shinfo(skb)->nr_frags + 1;
/* Check number of available descriptors */
- if (mvpp2_aggr_desc_num_check(port->priv, aggr_txq, frags) ||
- mvpp2_txq_reserved_desc_num_proc(port->priv, txq,
- txq_pcpu, frags)) {
+ if (mvpp2_aggr_desc_num_check(port, aggr_txq, frags) ||
+ mvpp2_txq_reserved_desc_num_proc(port, txq, txq_pcpu, frags)) {
frags = 0;
goto out;
}
@@ -2973,7 +3026,7 @@ static int mvpp2_tx(struct sk_buff *skb, struct net_device *dev)
out:
if (frags > 0) {
- struct mvpp2_pcpu_stats *stats = this_cpu_ptr(port->stats);
+ struct mvpp2_pcpu_stats *stats = per_cpu_ptr(port->stats, thread);
struct netdev_queue *nq = netdev_get_tx_queue(dev, txq_id);
txq_pcpu->reserved_num -= frags;
@@ -3003,11 +3056,14 @@ out:
/* Set the timer in case not all frags were processed */
if (!port->has_tx_irqs && txq_pcpu->count <= frags &&
txq_pcpu->count > 0) {
- struct mvpp2_port_pcpu *port_pcpu = this_cpu_ptr(port->pcpu);
+ struct mvpp2_port_pcpu *port_pcpu = per_cpu_ptr(port->pcpu, thread);
mvpp2_timer_set(port_pcpu);
}
+ if (test_bit(thread, &port->priv->lock_map))
+ spin_unlock_irqrestore(&port->tx_lock[thread], flags);
+
return NETDEV_TX_OK;
}
@@ -3027,7 +3083,7 @@ static int mvpp2_poll(struct napi_struct *napi, int budget)
int rx_done = 0;
struct mvpp2_port *port = netdev_priv(napi->dev);
struct mvpp2_queue_vector *qv;
- int cpu = smp_processor_id();
+ unsigned int thread = mvpp2_cpu_to_thread(port->priv, smp_processor_id());
qv = container_of(napi, struct mvpp2_queue_vector, napi);
@@ -3041,7 +3097,7 @@ static int mvpp2_poll(struct napi_struct *napi, int budget)
*
* Each CPU has its own Rx/Tx cause register
*/
- cause_rx_tx = mvpp2_percpu_read_relaxed(port->priv, qv->sw_thread_id,
+ cause_rx_tx = mvpp2_thread_read_relaxed(port->priv, qv->sw_thread_id,
MVPP2_ISR_RX_TX_CAUSE_REG(port->id));
cause_misc = cause_rx_tx & MVPP2_CAUSE_MISC_SUM_MASK;
@@ -3050,7 +3106,7 @@ static int mvpp2_poll(struct napi_struct *napi, int budget)
/* Clear the cause register */
mvpp2_write(port->priv, MVPP2_ISR_MISC_CAUSE_REG, 0);
- mvpp2_percpu_write(port->priv, cpu,
+ mvpp2_thread_write(port->priv, thread,
MVPP2_ISR_RX_TX_CAUSE_REG(port->id),
cause_rx_tx & ~MVPP2_CAUSE_MISC_SUM_MASK);
}
@@ -3064,7 +3120,8 @@ static int mvpp2_poll(struct napi_struct *napi, int budget)
}
/* Process RX packets */
- cause_rx = cause_rx_tx & MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK;
+ cause_rx = cause_rx_tx &
+ MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK(port->priv->hw_version);
cause_rx <<= qv->first_rxq;
cause_rx |= qv->pending_cause_rx;
while (cause_rx && budget > 0) {
@@ -3139,14 +3196,13 @@ static void mvpp2_start_dev(struct mvpp2_port *port)
for (i = 0; i < port->nqvecs; i++)
napi_enable(&port->qvecs[i].napi);
- /* Enable interrupts on all CPUs */
+ /* Enable interrupts on all threads */
mvpp2_interrupts_enable(port);
if (port->priv->hw_version == MVPP22)
mvpp22_mode_reconfigure(port);
if (port->phylink) {
- netif_carrier_off(port->dev);
phylink_start(port->phylink);
} else {
/* Phylink isn't used as of now for ACPI, so the MAC has to be
@@ -3169,7 +3225,7 @@ static void mvpp2_stop_dev(struct mvpp2_port *port)
{
int i;
- /* Disable interrupts on all CPUs */
+ /* Disable interrupts on all threads */
mvpp2_interrupts_disable(port);
for (i = 0; i < port->nqvecs; i++)
@@ -3242,16 +3298,31 @@ static int mvpp2_irqs_init(struct mvpp2_port *port)
for (i = 0; i < port->nqvecs; i++) {
struct mvpp2_queue_vector *qv = port->qvecs + i;
- if (qv->type == MVPP2_QUEUE_VECTOR_PRIVATE)
+ if (qv->type == MVPP2_QUEUE_VECTOR_PRIVATE) {
+ qv->mask = kzalloc(cpumask_size(), GFP_KERNEL);
+ if (!qv->mask) {
+ err = -ENOMEM;
+ goto err;
+ }
+
irq_set_status_flags(qv->irq, IRQ_NO_BALANCING);
+ }
err = request_irq(qv->irq, mvpp2_isr, 0, port->dev->name, qv);
if (err)
goto err;
- if (qv->type == MVPP2_QUEUE_VECTOR_PRIVATE)
- irq_set_affinity_hint(qv->irq,
- cpumask_of(qv->sw_thread_id));
+ if (qv->type == MVPP2_QUEUE_VECTOR_PRIVATE) {
+ unsigned int cpu;
+
+ for_each_present_cpu(cpu) {
+ if (mvpp2_cpu_to_thread(port->priv, cpu) ==
+ qv->sw_thread_id)
+ cpumask_set_cpu(cpu, qv->mask);
+ }
+
+ irq_set_affinity_hint(qv->irq, qv->mask);
+ }
}
return 0;
@@ -3260,6 +3331,8 @@ err:
struct mvpp2_queue_vector *qv = port->qvecs + i;
irq_set_affinity_hint(qv->irq, NULL);
+ kfree(qv->mask);
+ qv->mask = NULL;
free_irq(qv->irq, qv);
}
@@ -3274,6 +3347,8 @@ static void mvpp2_irqs_deinit(struct mvpp2_port *port)
struct mvpp2_queue_vector *qv = port->qvecs + i;
irq_set_affinity_hint(qv->irq, NULL);
+ kfree(qv->mask);
+ qv->mask = NULL;
irq_clear_status_flags(qv->irq, IRQ_NO_BALANCING);
free_irq(qv->irq, qv);
}
@@ -3395,11 +3470,11 @@ static int mvpp2_stop(struct net_device *dev)
{
struct mvpp2_port *port = netdev_priv(dev);
struct mvpp2_port_pcpu *port_pcpu;
- int cpu;
+ unsigned int thread;
mvpp2_stop_dev(port);
- /* Mask interrupts on all CPUs */
+ /* Mask interrupts on all threads */
on_each_cpu(mvpp2_interrupts_mask, port, 1);
mvpp2_shared_interrupt_mask_unmask(port, true);
@@ -3410,8 +3485,8 @@ static int mvpp2_stop(struct net_device *dev)
mvpp2_irqs_deinit(port);
if (!port->has_tx_irqs) {
- for_each_present_cpu(cpu) {
- port_pcpu = per_cpu_ptr(port->pcpu, cpu);
+ for (thread = 0; thread < port->priv->nthreads; thread++) {
+ port_pcpu = per_cpu_ptr(port->pcpu, thread);
hrtimer_cancel(&port_pcpu->tx_done_timer);
port_pcpu->timer_scheduled = false;
@@ -3556,7 +3631,7 @@ mvpp2_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
{
struct mvpp2_port *port = netdev_priv(dev);
unsigned int start;
- int cpu;
+ unsigned int cpu;
for_each_possible_cpu(cpu) {
struct mvpp2_pcpu_stats *cpu_stats;
@@ -3983,12 +4058,18 @@ static int mvpp2_simple_queue_vectors_init(struct mvpp2_port *port,
static int mvpp2_multi_queue_vectors_init(struct mvpp2_port *port,
struct device_node *port_node)
{
+ struct mvpp2 *priv = port->priv;
struct mvpp2_queue_vector *v;
int i, ret;
- port->nqvecs = num_possible_cpus();
- if (queue_mode == MVPP2_QDIST_SINGLE_MODE)
- port->nqvecs += 1;
+ switch (queue_mode) {
+ case MVPP2_QDIST_SINGLE_MODE:
+ port->nqvecs = priv->nthreads + 1;
+ break;
+ case MVPP2_QDIST_MULTI_MODE:
+ port->nqvecs = priv->nthreads;
+ break;
+ }
for (i = 0; i < port->nqvecs; i++) {
char irqname[16];
@@ -4000,7 +4081,10 @@ static int mvpp2_multi_queue_vectors_init(struct mvpp2_port *port,
v->sw_thread_id = i;
v->sw_thread_mask = BIT(i);
- snprintf(irqname, sizeof(irqname), "tx-cpu%d", i);
+ if (port->flags & MVPP2_F_DT_COMPAT)
+ snprintf(irqname, sizeof(irqname), "tx-cpu%d", i);
+ else
+ snprintf(irqname, sizeof(irqname), "hif%d", i);
if (queue_mode == MVPP2_QDIST_MULTI_MODE) {
v->first_rxq = i * MVPP2_DEFAULT_RXQ;
@@ -4010,7 +4094,9 @@ static int mvpp2_multi_queue_vectors_init(struct mvpp2_port *port,
v->first_rxq = 0;
v->nrxqs = port->nrxqs;
v->type = MVPP2_QUEUE_VECTOR_SHARED;
- strncpy(irqname, "rx-shared", sizeof(irqname));
+
+ if (port->flags & MVPP2_F_DT_COMPAT)
+ strncpy(irqname, "rx-shared", sizeof(irqname));
}
if (port_node)
@@ -4087,7 +4173,8 @@ static int mvpp2_port_init(struct mvpp2_port *port)
struct device *dev = port->dev->dev.parent;
struct mvpp2 *priv = port->priv;
struct mvpp2_txq_pcpu *txq_pcpu;
- int queue, cpu, err;
+ unsigned int thread;
+ int queue, err;
/* Checks for hardware constraints */
if (port->first_rxq + port->nrxqs >
@@ -4131,9 +4218,9 @@ static int mvpp2_port_init(struct mvpp2_port *port)
txq->id = queue_phy_id;
txq->log_id = queue;
txq->done_pkts_coal = MVPP2_TXDONE_COAL_PKTS_THRESH;
- for_each_present_cpu(cpu) {
- txq_pcpu = per_cpu_ptr(txq->pcpu, cpu);
- txq_pcpu->cpu = cpu;
+ for (thread = 0; thread < priv->nthreads; thread++) {
+ txq_pcpu = per_cpu_ptr(txq->pcpu, thread);
+ txq_pcpu->thread = thread;
}
port->txqs[queue] = txq;
@@ -4206,24 +4293,51 @@ err_free_percpu:
return err;
}
-/* Checks if the port DT description has the TX interrupts
- * described. On PPv2.1, there are no such interrupts. On PPv2.2,
- * there are available, but we need to keep support for old DTs.
+static bool mvpp22_port_has_legacy_tx_irqs(struct device_node *port_node,
+ unsigned long *flags)
+{
+ char *irqs[5] = { "rx-shared", "tx-cpu0", "tx-cpu1", "tx-cpu2",
+ "tx-cpu3" };
+ int i;
+
+ for (i = 0; i < 5; i++)
+ if (of_property_match_string(port_node, "interrupt-names",
+ irqs[i]) < 0)
+ return false;
+
+ *flags |= MVPP2_F_DT_COMPAT;
+ return true;
+}
+
+/* Checks if the port dt description has the required Tx interrupts:
+ * - PPv2.1: there are no such interrupts.
+ * - PPv2.2:
+ * - The old DTs have: "rx-shared", "tx-cpuX" with X in [0...3]
+ * - The new ones have: "hifX" with X in [0..8]
+ *
+ * All those variants are supported to keep the backward compatibility.
*/
-static bool mvpp2_port_has_tx_irqs(struct mvpp2 *priv,
- struct device_node *port_node)
+static bool mvpp2_port_has_irqs(struct mvpp2 *priv,
+ struct device_node *port_node,
+ unsigned long *flags)
{
- char *irqs[5] = { "rx-shared", "tx-cpu0", "tx-cpu1",
- "tx-cpu2", "tx-cpu3" };
- int ret, i;
+ char name[5];
+ int i;
+
+ /* ACPI */
+ if (!port_node)
+ return true;
if (priv->hw_version == MVPP21)
return false;
- for (i = 0; i < 5; i++) {
- ret = of_property_match_string(port_node, "interrupt-names",
- irqs[i]);
- if (ret < 0)
+ if (mvpp22_port_has_legacy_tx_irqs(port_node, flags))
+ return true;
+
+ for (i = 0; i < MVPP2_MAX_THREADS; i++) {
+ snprintf(name, 5, "hif%d", i);
+ if (of_property_match_string(port_node, "interrupt-names",
+ name) < 0)
return false;
}
@@ -4600,23 +4714,21 @@ static int mvpp2_port_probe(struct platform_device *pdev,
struct resource *res;
struct phylink *phylink;
char *mac_from = "";
- unsigned int ntxqs, nrxqs;
+ unsigned int ntxqs, nrxqs, thread;
+ unsigned long flags = 0;
bool has_tx_irqs;
u32 id;
int features;
int phy_mode;
- int err, i, cpu;
+ int err, i;
- if (port_node) {
- has_tx_irqs = mvpp2_port_has_tx_irqs(priv, port_node);
- } else {
- has_tx_irqs = true;
- queue_mode = MVPP2_QDIST_MULTI_MODE;
+ has_tx_irqs = mvpp2_port_has_irqs(priv, port_node, &flags);
+ if (!has_tx_irqs && queue_mode == MVPP2_QDIST_MULTI_MODE) {
+ dev_err(&pdev->dev,
+ "not enough IRQs to support multi queue mode\n");
+ return -EINVAL;
}
- if (!has_tx_irqs)
- queue_mode = MVPP2_QDIST_SINGLE_MODE;
-
ntxqs = MVPP2_MAX_TXQ;
if (priv->hw_version == MVPP22 && queue_mode == MVPP2_QDIST_MULTI_MODE)
nrxqs = MVPP2_DEFAULT_RXQ * num_possible_cpus();
@@ -4664,6 +4776,7 @@ static int mvpp2_port_probe(struct platform_device *pdev,
port->nrxqs = nrxqs;
port->priv = priv;
port->has_tx_irqs = has_tx_irqs;
+ port->flags = flags;
err = mvpp2_queue_vectors_init(port, port_node);
if (err)
@@ -4760,8 +4873,8 @@ static int mvpp2_port_probe(struct platform_device *pdev,
}
if (!port->has_tx_irqs) {
- for_each_present_cpu(cpu) {
- port_pcpu = per_cpu_ptr(port->pcpu, cpu);
+ for (thread = 0; thread < priv->nthreads; thread++) {
+ port_pcpu = per_cpu_ptr(port->pcpu, thread);
hrtimer_init(&port_pcpu->tx_done_timer, CLOCK_MONOTONIC,
HRTIMER_MODE_REL_PINNED);
@@ -5045,13 +5158,13 @@ static int mvpp2_init(struct platform_device *pdev, struct mvpp2 *priv)
}
/* Allocate and initialize aggregated TXQs */
- priv->aggr_txqs = devm_kcalloc(&pdev->dev, num_present_cpus(),
+ priv->aggr_txqs = devm_kcalloc(&pdev->dev, MVPP2_MAX_THREADS,
sizeof(*priv->aggr_txqs),
GFP_KERNEL);
if (!priv->aggr_txqs)
return -ENOMEM;
- for_each_present_cpu(i) {
+ for (i = 0; i < MVPP2_MAX_THREADS; i++) {
priv->aggr_txqs[i].id = i;
priv->aggr_txqs[i].size = MVPP2_AGGR_TXQ_SIZE;
err = mvpp2_aggr_txq_init(pdev, &priv->aggr_txqs[i], i, priv);
@@ -5098,7 +5211,7 @@ static int mvpp2_probe(struct platform_device *pdev)
struct mvpp2 *priv;
struct resource *res;
void __iomem *base;
- int i;
+ int i, shared;
int err;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
@@ -5163,6 +5276,15 @@ static int mvpp2_probe(struct platform_device *pdev)
mvpp2_setup_bm_pool();
+
+ priv->nthreads = min_t(unsigned int, num_present_cpus(),
+ MVPP2_MAX_THREADS);
+
+ shared = num_present_cpus() - priv->nthreads;
+ if (shared > 0)
+ bitmap_fill(&priv->lock_map,
+ min_t(int, shared, MVPP2_MAX_THREADS));
+
for (i = 0; i < MVPP2_MAX_THREADS; i++) {
u32 addr_space_sz;
@@ -5337,7 +5459,7 @@ static int mvpp2_remove(struct platform_device *pdev)
mvpp2_bm_pool_destroy(pdev, priv, bm_pool);
}
- for_each_present_cpu(i) {
+ for (i = 0; i < MVPP2_MAX_THREADS; i++) {
struct mvpp2_tx_queue *aggr_txq = &priv->aggr_txqs[i];
dma_free_coherent(&pdev->dev,
diff --git a/drivers/net/ethernet/marvell/octeontx2/Kconfig b/drivers/net/ethernet/marvell/octeontx2/Kconfig
new file mode 100644
index 000000000000..35827bdf1878
--- /dev/null
+++ b/drivers/net/ethernet/marvell/octeontx2/Kconfig
@@ -0,0 +1,17 @@
+#
+# Marvell OcteonTX2 drivers configuration
+#
+
+config OCTEONTX2_MBOX
+ tristate
+
+config OCTEONTX2_AF
+ tristate "Marvell OcteonTX2 RVU Admin Function driver"
+ select OCTEONTX2_MBOX
+ depends on (64BIT && COMPILE_TEST) || ARM64
+ depends on PCI
+ help
+ This driver supports Marvell's OcteonTX2 Resource Virtualization
+ Unit's admin function manager which manages all RVU HW resources
+ and provides a medium to other PF/VFs to configure HW. Should be
+ enabled for other RVU device drivers to work.
diff --git a/drivers/net/ethernet/marvell/octeontx2/Makefile b/drivers/net/ethernet/marvell/octeontx2/Makefile
new file mode 100644
index 000000000000..e579dcd54c97
--- /dev/null
+++ b/drivers/net/ethernet/marvell/octeontx2/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for Marvell OcteonTX2 device drivers.
+#
+
+obj-$(CONFIG_OCTEONTX2_AF) += af/
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/Makefile b/drivers/net/ethernet/marvell/octeontx2/af/Makefile
new file mode 100644
index 000000000000..06329acf9c2c
--- /dev/null
+++ b/drivers/net/ethernet/marvell/octeontx2/af/Makefile
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for Marvell's OcteonTX2 RVU Admin Function driver
+#
+
+obj-$(CONFIG_OCTEONTX2_MBOX) += octeontx2_mbox.o
+obj-$(CONFIG_OCTEONTX2_AF) += octeontx2_af.o
+
+octeontx2_mbox-y := mbox.o
+octeontx2_af-y := cgx.o rvu.o rvu_cgx.o rvu_npa.o rvu_nix.o \
+ rvu_reg.o rvu_npc.o
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
new file mode 100644
index 000000000000..12db256c8c9f
--- /dev/null
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
@@ -0,0 +1,721 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Marvell OcteonTx2 CGX driver
+ *
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/acpi.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/phy.h>
+#include <linux/of.h>
+#include <linux/of_mdio.h>
+#include <linux/of_net.h>
+
+#include "cgx.h"
+
+#define DRV_NAME "octeontx2-cgx"
+#define DRV_STRING "Marvell OcteonTX2 CGX/MAC Driver"
+
+/**
+ * struct lmac
+ * @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
+ * @event_cb: callback for linkchange events
+ * @cmd_pend: flag set before new command is started
+ * flag cleared after command response is received
+ * @cgx: parent cgx port
+ * @lmac_id: lmac port id
+ * @name: lmac port name
+ */
+struct lmac {
+ wait_queue_head_t wq_cmd_cmplt;
+ struct mutex cmd_lock;
+ u64 resp;
+ struct cgx_link_user_info link_info;
+ struct cgx_event_cb event_cb;
+ bool cmd_pend;
+ struct cgx *cgx;
+ u8 lmac_id;
+ char *name;
+};
+
+struct cgx {
+ void __iomem *reg_base;
+ struct pci_dev *pdev;
+ u8 cgx_id;
+ u8 lmac_count;
+ struct lmac *lmac_idmap[MAX_LMAC_PER_CGX];
+ struct list_head cgx_list;
+};
+
+static LIST_HEAD(cgx_list);
+
+/* Convert firmware speed encoding to user format(Mbps) */
+static u32 cgx_speed_mbps[CGX_LINK_SPEED_MAX];
+
+/* Convert firmware lmac type encoding to string */
+static char *cgx_lmactype_string[LMAC_MODE_MAX];
+
+/* Supported devices */
+static const struct pci_device_id cgx_id_table[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_OCTEONTX2_CGX) },
+ { 0, } /* end of table */
+};
+
+MODULE_DEVICE_TABLE(pci, cgx_id_table);
+
+static void cgx_write(struct cgx *cgx, u64 lmac, u64 offset, u64 val)
+{
+ writeq(val, cgx->reg_base + (lmac << 18) + offset);
+}
+
+static u64 cgx_read(struct cgx *cgx, u64 lmac, u64 offset)
+{
+ return readq(cgx->reg_base + (lmac << 18) + offset);
+}
+
+static inline struct lmac *lmac_pdata(u8 lmac_id, struct cgx *cgx)
+{
+ if (!cgx || lmac_id >= MAX_LMAC_PER_CGX)
+ return NULL;
+
+ return cgx->lmac_idmap[lmac_id];
+}
+
+int cgx_get_cgx_cnt(void)
+{
+ struct cgx *cgx_dev;
+ int count = 0;
+
+ list_for_each_entry(cgx_dev, &cgx_list, cgx_list)
+ count++;
+
+ return count;
+}
+EXPORT_SYMBOL(cgx_get_cgx_cnt);
+
+int cgx_get_lmac_cnt(void *cgxd)
+{
+ struct cgx *cgx = cgxd;
+
+ if (!cgx)
+ return -ENODEV;
+
+ return cgx->lmac_count;
+}
+EXPORT_SYMBOL(cgx_get_lmac_cnt);
+
+void *cgx_get_pdata(int cgx_id)
+{
+ struct cgx *cgx_dev;
+
+ list_for_each_entry(cgx_dev, &cgx_list, cgx_list) {
+ if (cgx_dev->cgx_id == cgx_id)
+ return cgx_dev;
+ }
+ return NULL;
+}
+EXPORT_SYMBOL(cgx_get_pdata);
+
+/* Ensure the required lock for event queue(where asynchronous events are
+ * posted) is acquired before calling this API. Else an asynchronous event(with
+ * latest link status) can reach the destination before this function returns
+ * and could make the link status appear wrong.
+ */
+int cgx_get_link_info(void *cgxd, int lmac_id,
+ struct cgx_link_user_info *linfo)
+{
+ struct lmac *lmac = lmac_pdata(lmac_id, cgxd);
+
+ if (!lmac)
+ return -ENODEV;
+
+ *linfo = lmac->link_info;
+ return 0;
+}
+EXPORT_SYMBOL(cgx_get_link_info);
+
+static u64 mac2u64 (u8 *mac_addr)
+{
+ u64 mac = 0;
+ int index;
+
+ for (index = ETH_ALEN - 1; index >= 0; index--)
+ mac |= ((u64)*mac_addr++) << (8 * index);
+ return mac;
+}
+
+int cgx_lmac_addr_set(u8 cgx_id, u8 lmac_id, u8 *mac_addr)
+{
+ struct cgx *cgx_dev = cgx_get_pdata(cgx_id);
+ u64 cfg;
+
+ /* 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)),
+ 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;
+ cgx_write(cgx_dev, lmac_id, CGXX_CMRX_RX_DMAC_CTL0, cfg);
+
+ return 0;
+}
+EXPORT_SYMBOL(cgx_lmac_addr_set);
+
+u64 cgx_lmac_addr_get(u8 cgx_id, u8 lmac_id)
+{
+ struct cgx *cgx_dev = cgx_get_pdata(cgx_id);
+ u64 cfg;
+
+ cfg = cgx_read(cgx_dev, 0, CGXX_CMRX_RX_DMAC_CAM0 + lmac_id * 0x8);
+ return cfg & CGX_RX_DMAC_ADR_MASK;
+}
+EXPORT_SYMBOL(cgx_lmac_addr_get);
+
+int cgx_set_pkind(void *cgxd, u8 lmac_id, int pkind)
+{
+ struct cgx *cgx = cgxd;
+
+ if (!cgx || lmac_id >= cgx->lmac_count)
+ return -ENODEV;
+
+ cgx_write(cgx, lmac_id, CGXX_CMRX_RX_ID_MAP, (pkind & 0x3F));
+ return 0;
+}
+EXPORT_SYMBOL(cgx_set_pkind);
+
+static inline u8 cgx_get_lmac_type(struct cgx *cgx, int lmac_id)
+{
+ u64 cfg;
+
+ cfg = cgx_read(cgx, lmac_id, CGXX_CMRX_CFG);
+ return (cfg >> CGX_LMAC_TYPE_SHIFT) & CGX_LMAC_TYPE_MASK;
+}
+
+/* Configure CGX LMAC in internal loopback mode */
+int cgx_lmac_internal_loopback(void *cgxd, int lmac_id, bool enable)
+{
+ struct cgx *cgx = cgxd;
+ u8 lmac_type;
+ u64 cfg;
+
+ if (!cgx || lmac_id >= cgx->lmac_count)
+ return -ENODEV;
+
+ lmac_type = cgx_get_lmac_type(cgx, lmac_id);
+ if (lmac_type == LMAC_MODE_SGMII || lmac_type == LMAC_MODE_QSGMII) {
+ cfg = cgx_read(cgx, lmac_id, CGXX_GMP_PCS_MRX_CTL);
+ if (enable)
+ cfg |= CGXX_GMP_PCS_MRX_CTL_LBK;
+ else
+ cfg &= ~CGXX_GMP_PCS_MRX_CTL_LBK;
+ cgx_write(cgx, lmac_id, CGXX_GMP_PCS_MRX_CTL, cfg);
+ } else {
+ cfg = cgx_read(cgx, lmac_id, CGXX_SPUX_CONTROL1);
+ if (enable)
+ cfg |= CGXX_SPUX_CONTROL1_LBK;
+ else
+ cfg &= ~CGXX_SPUX_CONTROL1_LBK;
+ cgx_write(cgx, lmac_id, CGXX_SPUX_CONTROL1, cfg);
+ }
+ return 0;
+}
+EXPORT_SYMBOL(cgx_lmac_internal_loopback);
+
+void cgx_lmac_promisc_config(int cgx_id, int lmac_id, bool enable)
+{
+ struct cgx *cgx = cgx_get_pdata(cgx_id);
+ u64 cfg = 0;
+
+ if (!cgx)
+ return;
+
+ 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;
+ 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);
+ } 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);
+ }
+}
+EXPORT_SYMBOL(cgx_lmac_promisc_config);
+
+int cgx_get_rx_stats(void *cgxd, int lmac_id, int idx, u64 *rx_stat)
+{
+ struct cgx *cgx = cgxd;
+
+ if (!cgx || lmac_id >= cgx->lmac_count)
+ return -ENODEV;
+ *rx_stat = cgx_read(cgx, lmac_id, CGXX_CMRX_RX_STAT0 + (idx * 8));
+ return 0;
+}
+EXPORT_SYMBOL(cgx_get_rx_stats);
+
+int cgx_get_tx_stats(void *cgxd, int lmac_id, int idx, u64 *tx_stat)
+{
+ struct cgx *cgx = cgxd;
+
+ if (!cgx || lmac_id >= cgx->lmac_count)
+ return -ENODEV;
+ *tx_stat = cgx_read(cgx, lmac_id, CGXX_CMRX_TX_STAT0 + (idx * 8));
+ return 0;
+}
+EXPORT_SYMBOL(cgx_get_tx_stats);
+
+int cgx_lmac_rx_tx_enable(void *cgxd, int lmac_id, bool enable)
+{
+ struct cgx *cgx = cgxd;
+ u64 cfg;
+
+ if (!cgx || lmac_id >= cgx->lmac_count)
+ return -ENODEV;
+
+ cfg = cgx_read(cgx, lmac_id, CGXX_CMRX_CFG);
+ if (enable)
+ cfg |= CMR_EN | DATA_PKT_RX_EN | DATA_PKT_TX_EN;
+ else
+ cfg &= ~(CMR_EN | DATA_PKT_RX_EN | DATA_PKT_TX_EN);
+ cgx_write(cgx, lmac_id, CGXX_CMRX_CFG, cfg);
+ return 0;
+}
+EXPORT_SYMBOL(cgx_lmac_rx_tx_enable);
+
+/* CGX Firmware interface low level support */
+static int cgx_fwi_cmd_send(u64 req, u64 *resp, struct lmac *lmac)
+{
+ struct cgx *cgx = lmac->cgx;
+ struct device *dev;
+ int err = 0;
+ u64 cmd;
+
+ /* Ensure no other command is in progress */
+ err = mutex_lock_interruptible(&lmac->cmd_lock);
+ if (err)
+ return err;
+
+ /* Ensure command register is free */
+ cmd = cgx_read(cgx, lmac->lmac_id, CGX_COMMAND_REG);
+ if (FIELD_GET(CMDREG_OWN, cmd) != CGX_CMD_OWN_NS) {
+ err = -EBUSY;
+ goto unlock;
+ }
+
+ /* Update ownership in command request */
+ req = FIELD_SET(CMDREG_OWN, CGX_CMD_OWN_FIRMWARE, req);
+
+ /* Mark this lmac as pending, before we start */
+ lmac->cmd_pend = true;
+
+ /* Start command in hardware */
+ cgx_write(cgx, lmac->lmac_id, CGX_COMMAND_REG, req);
+
+ /* Ensure command is completed without errors */
+ if (!wait_event_timeout(lmac->wq_cmd_cmplt, !lmac->cmd_pend,
+ msecs_to_jiffies(CGX_CMD_TIMEOUT))) {
+ dev = &cgx->pdev->dev;
+ dev_err(dev, "cgx port %d:%d cmd timeout\n",
+ cgx->cgx_id, lmac->lmac_id);
+ err = -EIO;
+ goto unlock;
+ }
+
+ /* we have a valid command response */
+ smp_rmb(); /* Ensure the latest updates are visible */
+ *resp = lmac->resp;
+
+unlock:
+ mutex_unlock(&lmac->cmd_lock);
+
+ return err;
+}
+
+static inline int cgx_fwi_cmd_generic(u64 req, u64 *resp,
+ struct cgx *cgx, int lmac_id)
+{
+ struct lmac *lmac;
+ int err;
+
+ lmac = lmac_pdata(lmac_id, cgx);
+ if (!lmac)
+ return -ENODEV;
+
+ err = cgx_fwi_cmd_send(req, resp, lmac);
+
+ /* Check for valid response */
+ if (!err) {
+ if (FIELD_GET(EVTREG_STAT, *resp) == CGX_STAT_FAIL)
+ return -EIO;
+ else
+ return 0;
+ }
+
+ return err;
+}
+
+static inline void cgx_link_usertable_init(void)
+{
+ cgx_speed_mbps[CGX_LINK_NONE] = 0;
+ cgx_speed_mbps[CGX_LINK_10M] = 10;
+ cgx_speed_mbps[CGX_LINK_100M] = 100;
+ cgx_speed_mbps[CGX_LINK_1G] = 1000;
+ cgx_speed_mbps[CGX_LINK_2HG] = 2500;
+ cgx_speed_mbps[CGX_LINK_5G] = 5000;
+ cgx_speed_mbps[CGX_LINK_10G] = 10000;
+ cgx_speed_mbps[CGX_LINK_20G] = 20000;
+ cgx_speed_mbps[CGX_LINK_25G] = 25000;
+ cgx_speed_mbps[CGX_LINK_40G] = 40000;
+ cgx_speed_mbps[CGX_LINK_50G] = 50000;
+ cgx_speed_mbps[CGX_LINK_100G] = 100000;
+
+ cgx_lmactype_string[LMAC_MODE_SGMII] = "SGMII";
+ cgx_lmactype_string[LMAC_MODE_XAUI] = "XAUI";
+ cgx_lmactype_string[LMAC_MODE_RXAUI] = "RXAUI";
+ cgx_lmactype_string[LMAC_MODE_10G_R] = "10G_R";
+ cgx_lmactype_string[LMAC_MODE_40G_R] = "40G_R";
+ cgx_lmactype_string[LMAC_MODE_QSGMII] = "QSGMII";
+ cgx_lmactype_string[LMAC_MODE_25G_R] = "25G_R";
+ cgx_lmactype_string[LMAC_MODE_50G_R] = "50G_R";
+ cgx_lmactype_string[LMAC_MODE_100G_R] = "100G_R";
+ cgx_lmactype_string[LMAC_MODE_USXGMII] = "USXGMII";
+}
+
+static inline void link_status_user_format(u64 lstat,
+ struct cgx_link_user_info *linfo,
+ struct cgx *cgx, u8 lmac_id)
+{
+ char *lmac_string;
+
+ linfo->link_up = FIELD_GET(RESP_LINKSTAT_UP, lstat);
+ linfo->full_duplex = FIELD_GET(RESP_LINKSTAT_FDUPLEX, lstat);
+ linfo->speed = cgx_speed_mbps[FIELD_GET(RESP_LINKSTAT_SPEED, lstat)];
+ linfo->lmac_type_id = cgx_get_lmac_type(cgx, lmac_id);
+ lmac_string = cgx_lmactype_string[linfo->lmac_type_id];
+ strncpy(linfo->lmac_type, lmac_string, LMACTYPE_STR_LEN - 1);
+}
+
+/* Hardware event handlers */
+static inline void cgx_link_change_handler(u64 lstat,
+ struct lmac *lmac)
+{
+ struct cgx_link_user_info *linfo;
+ struct cgx *cgx = lmac->cgx;
+ struct cgx_link_event event;
+ struct device *dev;
+ int err_type;
+
+ dev = &cgx->pdev->dev;
+
+ link_status_user_format(lstat, &event.link_uinfo, cgx, lmac->lmac_id);
+ err_type = FIELD_GET(RESP_LINKSTAT_ERRTYPE, lstat);
+
+ event.cgx_id = cgx->cgx_id;
+ event.lmac_id = lmac->lmac_id;
+
+ /* update the local copy of link status */
+ lmac->link_info = event.link_uinfo;
+ linfo = &lmac->link_info;
+
+ if (!lmac->event_cb.notify_link_chg) {
+ dev_dbg(dev, "cgx port %d:%d Link change handler null",
+ cgx->cgx_id, lmac->lmac_id);
+ if (err_type != CGX_ERR_NONE) {
+ dev_err(dev, "cgx port %d:%d Link error %d\n",
+ cgx->cgx_id, lmac->lmac_id, err_type);
+ }
+ dev_info(dev, "cgx port %d:%d Link is %s %d Mbps\n",
+ cgx->cgx_id, lmac->lmac_id,
+ linfo->link_up ? "UP" : "DOWN", linfo->speed);
+ return;
+ }
+
+ if (lmac->event_cb.notify_link_chg(&event, lmac->event_cb.data))
+ dev_err(dev, "event notification failure\n");
+}
+
+static inline bool cgx_cmdresp_is_linkevent(u64 event)
+{
+ u8 id;
+
+ id = FIELD_GET(EVTREG_ID, event);
+ if (id == CGX_CMD_LINK_BRING_UP ||
+ id == CGX_CMD_LINK_BRING_DOWN)
+ return true;
+ else
+ return false;
+}
+
+static inline bool cgx_event_is_linkevent(u64 event)
+{
+ if (FIELD_GET(EVTREG_ID, event) == CGX_EVT_LINK_CHANGE)
+ return true;
+ else
+ return false;
+}
+
+static irqreturn_t cgx_fwi_event_handler(int irq, void *data)
+{
+ struct lmac *lmac = data;
+ struct cgx *cgx;
+ u64 event;
+
+ cgx = lmac->cgx;
+
+ event = cgx_read(cgx, lmac->lmac_id, CGX_EVENT_REG);
+
+ if (!FIELD_GET(EVTREG_ACK, event))
+ return IRQ_NONE;
+
+ switch (FIELD_GET(EVTREG_EVT_TYPE, event)) {
+ case CGX_EVT_CMD_RESP:
+ /* Copy the response. Since only one command is active at a
+ * time, there is no way a response can get overwritten
+ */
+ lmac->resp = event;
+ /* Ensure response is updated before thread context starts */
+ smp_wmb();
+
+ /* There wont be separate events for link change initiated from
+ * software; Hence report the command responses as events
+ */
+ if (cgx_cmdresp_is_linkevent(event))
+ cgx_link_change_handler(event, lmac);
+
+ /* Release thread waiting for completion */
+ lmac->cmd_pend = false;
+ wake_up_interruptible(&lmac->wq_cmd_cmplt);
+ break;
+ case CGX_EVT_ASYNC:
+ if (cgx_event_is_linkevent(event))
+ cgx_link_change_handler(event, lmac);
+ break;
+ }
+
+ /* Any new event or command response will be posted by firmware
+ * only after the current status is acked.
+ * Ack the interrupt register as well.
+ */
+ cgx_write(lmac->cgx, lmac->lmac_id, CGX_EVENT_REG, 0);
+ cgx_write(lmac->cgx, lmac->lmac_id, CGXX_CMRX_INT, FW_CGX_INT);
+
+ return IRQ_HANDLED;
+}
+
+/* APIs for PHY management using CGX firmware interface */
+
+/* callback registration for hardware events like link change */
+int cgx_lmac_evh_register(struct cgx_event_cb *cb, void *cgxd, int lmac_id)
+{
+ struct cgx *cgx = cgxd;
+ struct lmac *lmac;
+
+ lmac = lmac_pdata(lmac_id, cgx);
+ if (!lmac)
+ return -ENODEV;
+
+ lmac->event_cb = *cb;
+
+ return 0;
+}
+EXPORT_SYMBOL(cgx_lmac_evh_register);
+
+static inline int cgx_fwi_read_version(u64 *resp, struct cgx *cgx)
+{
+ u64 req = 0;
+
+ req = FIELD_SET(CMDREG_ID, CGX_CMD_GET_FW_VER, req);
+ return cgx_fwi_cmd_generic(req, resp, cgx, 0);
+}
+
+static int cgx_lmac_verify_fwi_version(struct cgx *cgx)
+{
+ struct device *dev = &cgx->pdev->dev;
+ int major_ver, minor_ver;
+ u64 resp;
+ int err;
+
+ if (!cgx->lmac_count)
+ return 0;
+
+ err = cgx_fwi_read_version(&resp, cgx);
+ if (err)
+ return err;
+
+ major_ver = FIELD_GET(RESP_MAJOR_VER, resp);
+ minor_ver = FIELD_GET(RESP_MINOR_VER, resp);
+ dev_dbg(dev, "Firmware command interface version = %d.%d\n",
+ major_ver, minor_ver);
+ if (major_ver != CGX_FIRMWARE_MAJOR_VER ||
+ minor_ver != CGX_FIRMWARE_MINOR_VER)
+ return -EIO;
+ else
+ return 0;
+}
+
+static int cgx_lmac_init(struct cgx *cgx)
+{
+ struct lmac *lmac;
+ int i, err;
+
+ cgx->lmac_count = cgx_read(cgx, 0, CGXX_CMRX_RX_LMACS) & 0x7;
+ if (cgx->lmac_count > MAX_LMAC_PER_CGX)
+ cgx->lmac_count = MAX_LMAC_PER_CGX;
+
+ for (i = 0; i < cgx->lmac_count; i++) {
+ lmac = kcalloc(1, sizeof(struct lmac), GFP_KERNEL);
+ if (!lmac)
+ return -ENOMEM;
+ lmac->name = kcalloc(1, sizeof("cgx_fwi_xxx_yyy"), GFP_KERNEL);
+ if (!lmac->name)
+ return -ENOMEM;
+ sprintf(lmac->name, "cgx_fwi_%d_%d", cgx->cgx_id, i);
+ lmac->lmac_id = i;
+ lmac->cgx = cgx;
+ init_waitqueue_head(&lmac->wq_cmd_cmplt);
+ mutex_init(&lmac->cmd_lock);
+ err = request_irq(pci_irq_vector(cgx->pdev,
+ CGX_LMAC_FWI + i * 9),
+ cgx_fwi_event_handler, 0, lmac->name, lmac);
+ if (err)
+ return err;
+
+ /* Enable interrupt */
+ cgx_write(cgx, lmac->lmac_id, CGXX_CMRX_INT_ENA_W1S,
+ FW_CGX_INT);
+
+ /* Add reference */
+ cgx->lmac_idmap[i] = lmac;
+ }
+
+ return cgx_lmac_verify_fwi_version(cgx);
+}
+
+static int cgx_lmac_exit(struct cgx *cgx)
+{
+ struct lmac *lmac;
+ int i;
+
+ /* Free all lmac related resources */
+ for (i = 0; i < cgx->lmac_count; i++) {
+ lmac = cgx->lmac_idmap[i];
+ if (!lmac)
+ continue;
+ free_irq(pci_irq_vector(cgx->pdev, CGX_LMAC_FWI + i * 9), lmac);
+ kfree(lmac->name);
+ kfree(lmac);
+ }
+
+ return 0;
+}
+
+static int cgx_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct device *dev = &pdev->dev;
+ struct cgx *cgx;
+ int err, nvec;
+
+ cgx = devm_kzalloc(dev, sizeof(*cgx), GFP_KERNEL);
+ if (!cgx)
+ return -ENOMEM;
+ cgx->pdev = pdev;
+
+ pci_set_drvdata(pdev, cgx);
+
+ err = pci_enable_device(pdev);
+ if (err) {
+ dev_err(dev, "Failed to enable PCI device\n");
+ pci_set_drvdata(pdev, NULL);
+ return err;
+ }
+
+ err = pci_request_regions(pdev, DRV_NAME);
+ if (err) {
+ dev_err(dev, "PCI request regions failed 0x%x\n", err);
+ goto err_disable_device;
+ }
+
+ /* MAP configuration registers */
+ cgx->reg_base = pcim_iomap(pdev, PCI_CFG_REG_BAR_NUM, 0);
+ if (!cgx->reg_base) {
+ dev_err(dev, "CGX: Cannot map CSR memory space, aborting\n");
+ err = -ENOMEM;
+ goto err_release_regions;
+ }
+
+ nvec = CGX_NVEC;
+ err = pci_alloc_irq_vectors(pdev, nvec, nvec, PCI_IRQ_MSIX);
+ if (err < 0 || err != nvec) {
+ dev_err(dev, "Request for %d msix vectors failed, err %d\n",
+ nvec, err);
+ goto err_release_regions;
+ }
+
+ list_add(&cgx->cgx_list, &cgx_list);
+ cgx->cgx_id = cgx_get_cgx_cnt() - 1;
+
+ cgx_link_usertable_init();
+
+ err = cgx_lmac_init(cgx);
+ if (err)
+ goto err_release_lmac;
+
+ return 0;
+
+err_release_lmac:
+ cgx_lmac_exit(cgx);
+ list_del(&cgx->cgx_list);
+err_release_regions:
+ pci_release_regions(pdev);
+err_disable_device:
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+ return err;
+}
+
+static void cgx_remove(struct pci_dev *pdev)
+{
+ struct cgx *cgx = pci_get_drvdata(pdev);
+
+ cgx_lmac_exit(cgx);
+ list_del(&cgx->cgx_list);
+ pci_free_irq_vectors(pdev);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+}
+
+struct pci_driver cgx_driver = {
+ .name = DRV_NAME,
+ .id_table = cgx_id_table,
+ .probe = cgx_probe,
+ .remove = cgx_remove,
+};
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h
new file mode 100644
index 000000000000..0a66d2717442
--- /dev/null
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h
@@ -0,0 +1,111 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * Marvell OcteonTx2 CGX driver
+ *
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef CGX_H
+#define CGX_H
+
+#include "mbox.h"
+#include "cgx_fw_if.h"
+
+ /* PCI device IDs */
+#define PCI_DEVID_OCTEONTX2_CGX 0xA059
+
+/* PCI BAR nos */
+#define PCI_CFG_REG_BAR_NUM 0
+
+#define MAX_CGX 3
+#define MAX_LMAC_PER_CGX 4
+#define CGX_OFFSET(x) ((x) * MAX_LMAC_PER_CGX)
+
+/* Registers */
+#define CGXX_CMRX_CFG 0x00
+#define CMR_EN BIT_ULL(55)
+#define DATA_PKT_TX_EN BIT_ULL(53)
+#define DATA_PKT_RX_EN BIT_ULL(54)
+#define CGX_LMAC_TYPE_SHIFT 40
+#define CGX_LMAC_TYPE_MASK 0xF
+#define CGXX_CMRX_INT 0x040
+#define FW_CGX_INT BIT_ULL(1)
+#define CGXX_CMRX_INT_ENA_W1S 0x058
+#define CGXX_CMRX_RX_ID_MAP 0x060
+#define CGXX_CMRX_RX_STAT0 0x070
+#define CGXX_CMRX_RX_LMACS 0x128
+#define CGXX_CMRX_RX_DMAC_CTL0 0x1F8
+#define CGX_DMAC_CTL0_CAM_ENABLE BIT_ULL(3)
+#define CGX_DMAC_CAM_ACCEPT BIT_ULL(3)
+#define CGX_DMAC_MCAST_MODE BIT_ULL(1)
+#define CGX_DMAC_BCAST_MODE BIT_ULL(0)
+#define CGXX_CMRX_RX_DMAC_CAM0 0x200
+#define CGX_DMAC_CAM_ADDR_ENABLE BIT_ULL(48)
+#define CGXX_CMRX_RX_DMAC_CAM1 0x400
+#define CGX_RX_DMAC_ADR_MASK GENMASK_ULL(47, 0)
+#define CGXX_CMRX_TX_STAT0 0x700
+#define CGXX_SCRATCH0_REG 0x1050
+#define CGXX_SCRATCH1_REG 0x1058
+#define CGX_CONST 0x2000
+#define CGXX_SPUX_CONTROL1 0x10000
+#define CGXX_SPUX_CONTROL1_LBK BIT_ULL(14)
+#define CGXX_GMP_PCS_MRX_CTL 0x30000
+#define CGXX_GMP_PCS_MRX_CTL_LBK BIT_ULL(14)
+
+#define CGX_COMMAND_REG CGXX_SCRATCH1_REG
+#define CGX_EVENT_REG CGXX_SCRATCH0_REG
+#define CGX_CMD_TIMEOUT 2200 /* msecs */
+
+#define CGX_NVEC 37
+#define CGX_LMAC_FWI 0
+
+enum LMAC_TYPE {
+ LMAC_MODE_SGMII = 0,
+ LMAC_MODE_XAUI = 1,
+ LMAC_MODE_RXAUI = 2,
+ LMAC_MODE_10G_R = 3,
+ LMAC_MODE_40G_R = 4,
+ LMAC_MODE_QSGMII = 6,
+ LMAC_MODE_25G_R = 7,
+ LMAC_MODE_50G_R = 8,
+ LMAC_MODE_100G_R = 9,
+ LMAC_MODE_USXGMII = 10,
+ LMAC_MODE_MAX,
+};
+
+struct cgx_link_event {
+ struct cgx_link_user_info link_uinfo;
+ u8 cgx_id;
+ u8 lmac_id;
+};
+
+/**
+ * struct cgx_event_cb
+ * @notify_link_chg: callback for link change notification
+ * @data: data passed to callback function
+ */
+struct cgx_event_cb {
+ int (*notify_link_chg)(struct cgx_link_event *event, void *data);
+ void *data;
+};
+
+extern struct pci_driver cgx_driver;
+
+int cgx_get_cgx_cnt(void);
+int cgx_get_lmac_cnt(void *cgxd);
+void *cgx_get_pdata(int cgx_id);
+int cgx_set_pkind(void *cgxd, u8 lmac_id, int pkind);
+int cgx_lmac_evh_register(struct cgx_event_cb *cb, void *cgxd, int lmac_id);
+int cgx_get_tx_stats(void *cgxd, int lmac_id, int idx, u64 *tx_stat);
+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_addr_set(u8 cgx_id, u8 lmac_id, u8 *mac_addr);
+u64 cgx_lmac_addr_get(u8 cgx_id, u8 lmac_id);
+void cgx_lmac_promisc_config(int cgx_id, int lmac_id, bool enable);
+int cgx_lmac_internal_loopback(void *cgxd, int lmac_id, bool enable);
+int cgx_get_link_info(void *cgxd, int lmac_id,
+ struct cgx_link_user_info *linfo);
+#endif /* CGX_H */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx_fw_if.h b/drivers/net/ethernet/marvell/octeontx2/af/cgx_fw_if.h
new file mode 100644
index 000000000000..fa17af3f4ba7
--- /dev/null
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx_fw_if.h
@@ -0,0 +1,186 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * Marvell OcteonTx2 CGX driver
+ *
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __CGX_FW_INTF_H__
+#define __CGX_FW_INTF_H__
+
+#include <linux/bitops.h>
+#include <linux/bitfield.h>
+
+#define CGX_FIRMWARE_MAJOR_VER 1
+#define CGX_FIRMWARE_MINOR_VER 0
+
+#define CGX_EVENT_ACK 1UL
+
+/* CGX error types. set for cmd response status as CGX_STAT_FAIL */
+enum cgx_error_type {
+ CGX_ERR_NONE,
+ CGX_ERR_LMAC_NOT_ENABLED,
+ CGX_ERR_LMAC_MODE_INVALID,
+ CGX_ERR_REQUEST_ID_INVALID,
+ CGX_ERR_PREV_ACK_NOT_CLEAR,
+ CGX_ERR_PHY_LINK_DOWN,
+ CGX_ERR_PCS_RESET_FAIL,
+ CGX_ERR_AN_CPT_FAIL,
+ CGX_ERR_TX_NOT_IDLE,
+ CGX_ERR_RX_NOT_IDLE,
+ CGX_ERR_SPUX_BR_BLKLOCK_FAIL,
+ CGX_ERR_SPUX_RX_ALIGN_FAIL,
+ CGX_ERR_SPUX_TX_FAULT,
+ CGX_ERR_SPUX_RX_FAULT,
+ CGX_ERR_SPUX_RESET_FAIL,
+ CGX_ERR_SPUX_AN_RESET_FAIL,
+ CGX_ERR_SPUX_USX_AN_RESET_FAIL,
+ CGX_ERR_SMUX_RX_LINK_NOT_OK,
+ CGX_ERR_PCS_RECV_LINK_FAIL,
+ CGX_ERR_TRAINING_FAIL,
+ CGX_ERR_RX_EQU_FAIL,
+ CGX_ERR_SPUX_BER_FAIL,
+ CGX_ERR_SPUX_RSFEC_ALGN_FAIL, /* = 22 */
+};
+
+/* LINK speed types */
+enum cgx_link_speed {
+ CGX_LINK_NONE,
+ CGX_LINK_10M,
+ CGX_LINK_100M,
+ CGX_LINK_1G,
+ CGX_LINK_2HG,
+ CGX_LINK_5G,
+ CGX_LINK_10G,
+ CGX_LINK_20G,
+ CGX_LINK_25G,
+ CGX_LINK_40G,
+ CGX_LINK_50G,
+ CGX_LINK_100G,
+ CGX_LINK_SPEED_MAX,
+};
+
+/* REQUEST ID types. Input to firmware */
+enum cgx_cmd_id {
+ CGX_CMD_NONE,
+ CGX_CMD_GET_FW_VER,
+ CGX_CMD_GET_MAC_ADDR,
+ CGX_CMD_SET_MTU,
+ CGX_CMD_GET_LINK_STS, /* optional to user */
+ CGX_CMD_LINK_BRING_UP,
+ CGX_CMD_LINK_BRING_DOWN,
+ CGX_CMD_INTERNAL_LBK,
+ CGX_CMD_EXTERNAL_LBK,
+ CGX_CMD_HIGIG,
+ CGX_CMD_LINK_STATE_CHANGE,
+ CGX_CMD_MODE_CHANGE, /* hot plug support */
+ CGX_CMD_INTF_SHUTDOWN,
+ CGX_CMD_IRQ_ENABLE,
+ CGX_CMD_IRQ_DISABLE,
+};
+
+/* async event ids */
+enum cgx_evt_id {
+ CGX_EVT_NONE,
+ CGX_EVT_LINK_CHANGE,
+};
+
+/* event types - cause of interrupt */
+enum cgx_evt_type {
+ CGX_EVT_ASYNC,
+ CGX_EVT_CMD_RESP
+};
+
+enum cgx_stat {
+ CGX_STAT_SUCCESS,
+ CGX_STAT_FAIL
+};
+
+enum cgx_cmd_own {
+ CGX_CMD_OWN_NS,
+ CGX_CMD_OWN_FIRMWARE,
+};
+
+/* m - bit mask
+ * y - value to be written in the bitrange
+ * x - input value whose bitrange to be modified
+ */
+#define FIELD_SET(m, y, x) \
+ (((x) & ~(m)) | \
+ FIELD_PREP((m), (y)))
+
+/* scratchx(0) CSR used for ATF->non-secure SW communication.
+ * This acts as the status register
+ * Provides details on command ack/status, command response, error details
+ */
+#define EVTREG_ACK BIT_ULL(0)
+#define EVTREG_EVT_TYPE BIT_ULL(1)
+#define EVTREG_STAT BIT_ULL(2)
+#define EVTREG_ID GENMASK_ULL(8, 3)
+
+/* Response to command IDs with command status as CGX_STAT_FAIL
+ *
+ * Not applicable for commands :
+ * CGX_CMD_LINK_BRING_UP/DOWN/CGX_EVT_LINK_CHANGE
+ */
+#define EVTREG_ERRTYPE GENMASK_ULL(18, 9)
+
+/* Response to cmd ID as CGX_CMD_GET_FW_VER with cmd status as
+ * CGX_STAT_SUCCESS
+ */
+#define RESP_MAJOR_VER GENMASK_ULL(12, 9)
+#define RESP_MINOR_VER GENMASK_ULL(16, 13)
+
+/* Response to cmd ID as CGX_CMD_GET_MAC_ADDR with cmd status as
+ * CGX_STAT_SUCCESS
+ */
+#define RESP_MAC_ADDR GENMASK_ULL(56, 9)
+
+/* Response to cmd ID - CGX_CMD_LINK_BRING_UP/DOWN, event ID CGX_EVT_LINK_CHANGE
+ * status can be either CGX_STAT_FAIL or CGX_STAT_SUCCESS
+ *
+ * In case of CGX_STAT_FAIL, it indicates CGX configuration failed
+ * when processing link up/down/change command.
+ * Both err_type and current link status will be updated
+ *
+ * In case of CGX_STAT_SUCCESS, err_type will be CGX_ERR_NONE and current
+ * link status will be updated
+ */
+struct cgx_lnk_sts {
+ uint64_t reserved1:9;
+ uint64_t link_up:1;
+ uint64_t full_duplex:1;
+ uint64_t speed:4; /* cgx_link_speed */
+ uint64_t err_type:10;
+ uint64_t reserved2:39;
+};
+
+#define RESP_LINKSTAT_UP GENMASK_ULL(9, 9)
+#define RESP_LINKSTAT_FDUPLEX GENMASK_ULL(10, 10)
+#define RESP_LINKSTAT_SPEED GENMASK_ULL(14, 11)
+#define RESP_LINKSTAT_ERRTYPE GENMASK_ULL(24, 15)
+
+/* scratchx(1) CSR used for non-secure SW->ATF communication
+ * This CSR acts as a command register
+ */
+#define CMDREG_OWN BIT_ULL(0)
+#define CMDREG_ID GENMASK_ULL(7, 2)
+
+/* Any command using enable/disable as an argument need
+ * to set this bitfield.
+ * Ex: Loopback, HiGig...
+ */
+#define CMDREG_ENABLE BIT_ULL(8)
+
+/* command argument to be passed for cmd ID - CGX_CMD_SET_MTU */
+#define CMDMTU_SIZE GENMASK_ULL(23, 8)
+
+/* command argument to be passed for cmd ID - CGX_CMD_LINK_CHANGE */
+#define CMDLINKCHANGE_LINKUP BIT_ULL(8)
+#define CMDLINKCHANGE_FULLDPLX BIT_ULL(9)
+#define CMDLINKCHANGE_SPEED GENMASK_ULL(13, 10)
+
+#endif /* __CGX_FW_INTF_H__ */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/common.h b/drivers/net/ethernet/marvell/octeontx2/af/common.h
new file mode 100644
index 000000000000..d39ada404c8f
--- /dev/null
+++ b/drivers/net/ethernet/marvell/octeontx2/af/common.h
@@ -0,0 +1,211 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * Marvell OcteonTx2 RVU Admin Function driver
+ *
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef COMMON_H
+#define COMMON_H
+
+#include "rvu_struct.h"
+
+#define OTX2_ALIGN 128 /* Align to cacheline */
+
+#define Q_SIZE_16 0ULL /* 16 entries */
+#define Q_SIZE_64 1ULL /* 64 entries */
+#define Q_SIZE_256 2ULL
+#define Q_SIZE_1K 3ULL
+#define Q_SIZE_4K 4ULL
+#define Q_SIZE_16K 5ULL
+#define Q_SIZE_64K 6ULL
+#define Q_SIZE_256K 7ULL
+#define Q_SIZE_1M 8ULL /* Million entries */
+#define Q_SIZE_MIN Q_SIZE_16
+#define Q_SIZE_MAX Q_SIZE_1M
+
+#define Q_COUNT(x) (16ULL << (2 * x))
+#define Q_SIZE(x, n) ((ilog2(x) - (n)) / 2)
+
+/* Admin queue info */
+
+/* Since we intend to add only one instruction at a time,
+ * keep queue size to it's minimum.
+ */
+#define AQ_SIZE Q_SIZE_16
+/* HW head & tail pointer mask */
+#define AQ_PTR_MASK 0xFFFFF
+
+struct qmem {
+ void *base;
+ dma_addr_t iova;
+ int alloc_sz;
+ u8 entry_sz;
+ u8 align;
+ u32 qsize;
+};
+
+static inline int qmem_alloc(struct device *dev, struct qmem **q,
+ int qsize, int entry_sz)
+{
+ struct qmem *qmem;
+ int aligned_addr;
+
+ if (!qsize)
+ return -EINVAL;
+
+ *q = devm_kzalloc(dev, sizeof(*qmem), GFP_KERNEL);
+ if (!*q)
+ return -ENOMEM;
+ qmem = *q;
+
+ qmem->entry_sz = entry_sz;
+ qmem->alloc_sz = (qsize * entry_sz) + OTX2_ALIGN;
+ qmem->base = dma_zalloc_coherent(dev, qmem->alloc_sz,
+ &qmem->iova, GFP_KERNEL);
+ if (!qmem->base)
+ return -ENOMEM;
+
+ qmem->qsize = qsize;
+
+ aligned_addr = ALIGN((u64)qmem->iova, OTX2_ALIGN);
+ qmem->align = (aligned_addr - qmem->iova);
+ qmem->base += qmem->align;
+ qmem->iova += qmem->align;
+ return 0;
+}
+
+static inline void qmem_free(struct device *dev, struct qmem *qmem)
+{
+ if (!qmem)
+ return;
+
+ if (qmem->base)
+ dma_free_coherent(dev, qmem->alloc_sz,
+ qmem->base - qmem->align,
+ qmem->iova - qmem->align);
+ devm_kfree(dev, qmem);
+}
+
+struct admin_queue {
+ struct qmem *inst;
+ struct qmem *res;
+ spinlock_t lock; /* Serialize inst enqueue from PFs */
+};
+
+/* NPA aura count */
+enum npa_aura_sz {
+ NPA_AURA_SZ_0,
+ NPA_AURA_SZ_128,
+ NPA_AURA_SZ_256,
+ NPA_AURA_SZ_512,
+ NPA_AURA_SZ_1K,
+ NPA_AURA_SZ_2K,
+ NPA_AURA_SZ_4K,
+ NPA_AURA_SZ_8K,
+ NPA_AURA_SZ_16K,
+ NPA_AURA_SZ_32K,
+ NPA_AURA_SZ_64K,
+ NPA_AURA_SZ_128K,
+ NPA_AURA_SZ_256K,
+ NPA_AURA_SZ_512K,
+ NPA_AURA_SZ_1M,
+ NPA_AURA_SZ_MAX,
+};
+
+#define NPA_AURA_COUNT(x) (1ULL << ((x) + 6))
+
+/* NPA AQ result structure for init/read/write of aura HW contexts */
+struct npa_aq_aura_res {
+ struct npa_aq_res_s res;
+ struct npa_aura_s aura_ctx;
+ struct npa_aura_s ctx_mask;
+};
+
+/* NPA AQ result structure for init/read/write of pool HW contexts */
+struct npa_aq_pool_res {
+ struct npa_aq_res_s res;
+ struct npa_pool_s pool_ctx;
+ struct npa_pool_s ctx_mask;
+};
+
+/* NIX Transmit schedulers */
+enum nix_scheduler {
+ NIX_TXSCH_LVL_SMQ = 0x0,
+ NIX_TXSCH_LVL_MDQ = 0x0,
+ NIX_TXSCH_LVL_TL4 = 0x1,
+ NIX_TXSCH_LVL_TL3 = 0x2,
+ NIX_TXSCH_LVL_TL2 = 0x3,
+ NIX_TXSCH_LVL_TL1 = 0x4,
+ NIX_TXSCH_LVL_CNT = 0x5,
+};
+
+/* NIX RX action operation*/
+#define NIX_RX_ACTIONOP_DROP (0x0ull)
+#define NIX_RX_ACTIONOP_UCAST (0x1ull)
+#define NIX_RX_ACTIONOP_UCAST_IPSEC (0x2ull)
+#define NIX_RX_ACTIONOP_MCAST (0x3ull)
+#define NIX_RX_ACTIONOP_RSS (0x4ull)
+
+/* NIX TX action operation*/
+#define NIX_TX_ACTIONOP_DROP (0x0ull)
+#define NIX_TX_ACTIONOP_UCAST_DEFAULT (0x1ull)
+#define NIX_TX_ACTIONOP_UCAST_CHAN (0x2ull)
+#define NIX_TX_ACTIONOP_MCAST (0x3ull)
+#define NIX_TX_ACTIONOP_DROP_VIOL (0x5ull)
+
+#define NPC_MCAM_KEY_X1 0
+#define NPC_MCAM_KEY_X2 1
+#define NPC_MCAM_KEY_X4 2
+
+#define NIX_INTF_RX 0
+#define NIX_INTF_TX 1
+
+#define NIX_INTF_TYPE_CGX 0
+#define NIX_INTF_TYPE_LBK 1
+
+#define MAX_LMAC_PKIND 12
+#define NIX_LINK_CGX_LMAC(a, b) (0 + 4 * (a) + (b))
+#define NIX_CHAN_CGX_LMAC_CHX(a, b, c) (0x800 + 0x100 * (a) + 0x10 * (b) + (c))
+
+/* NIX LSO format indices.
+ * As of now TSO is the only one using, so statically assigning indices.
+ */
+#define NIX_LSO_FORMAT_IDX_TSOV4 0
+#define NIX_LSO_FORMAT_IDX_TSOV6 1
+
+/* RSS info */
+#define MAX_RSS_GROUPS 8
+/* Group 0 has to be used in default pkt forwarding MCAM entries
+ * reserved for NIXLFs. Groups 1-7 can be used for RSS for ntuple
+ * filters.
+ */
+#define DEFAULT_RSS_CONTEXT_GROUP 0
+#define MAX_RSS_INDIR_TBL_SIZE 256 /* 1 << Max adder bits */
+
+/* NIX flow tag, key type flags */
+#define FLOW_KEY_TYPE_PORT BIT(0)
+#define FLOW_KEY_TYPE_IPV4 BIT(1)
+#define FLOW_KEY_TYPE_IPV6 BIT(2)
+#define FLOW_KEY_TYPE_TCP BIT(3)
+#define FLOW_KEY_TYPE_UDP BIT(4)
+#define FLOW_KEY_TYPE_SCTP BIT(5)
+
+/* NIX flow tag algorithm indices, max is 31 */
+enum {
+ FLOW_KEY_ALG_PORT,
+ FLOW_KEY_ALG_IP,
+ FLOW_KEY_ALG_TCP,
+ FLOW_KEY_ALG_UDP,
+ FLOW_KEY_ALG_SCTP,
+ FLOW_KEY_ALG_TCP_UDP,
+ FLOW_KEY_ALG_TCP_SCTP,
+ FLOW_KEY_ALG_UDP_SCTP,
+ FLOW_KEY_ALG_TCP_UDP_SCTP,
+ FLOW_KEY_ALG_MAX,
+};
+
+#endif /* COMMON_H */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.c b/drivers/net/ethernet/marvell/octeontx2/af/mbox.c
new file mode 100644
index 000000000000..85ba24a05774
--- /dev/null
+++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.c
@@ -0,0 +1,303 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Marvell OcteonTx2 RVU Admin Function driver
+ *
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+
+#include "rvu_reg.h"
+#include "mbox.h"
+
+static const u16 msgs_offset = ALIGN(sizeof(struct mbox_hdr), MBOX_MSG_ALIGN);
+
+void otx2_mbox_reset(struct otx2_mbox *mbox, int devid)
+{
+ struct otx2_mbox_dev *mdev = &mbox->dev[devid];
+ struct mbox_hdr *tx_hdr, *rx_hdr;
+
+ tx_hdr = mdev->mbase + mbox->tx_start;
+ rx_hdr = mdev->mbase + mbox->rx_start;
+
+ spin_lock(&mdev->mbox_lock);
+ mdev->msg_size = 0;
+ mdev->rsp_size = 0;
+ tx_hdr->num_msgs = 0;
+ rx_hdr->num_msgs = 0;
+ spin_unlock(&mdev->mbox_lock);
+}
+EXPORT_SYMBOL(otx2_mbox_reset);
+
+void otx2_mbox_destroy(struct otx2_mbox *mbox)
+{
+ mbox->reg_base = NULL;
+ mbox->hwbase = NULL;
+
+ kfree(mbox->dev);
+ mbox->dev = NULL;
+}
+EXPORT_SYMBOL(otx2_mbox_destroy);
+
+int otx2_mbox_init(struct otx2_mbox *mbox, void *hwbase, struct pci_dev *pdev,
+ void *reg_base, int direction, int ndevs)
+{
+ struct otx2_mbox_dev *mdev;
+ int devid;
+
+ switch (direction) {
+ case MBOX_DIR_AFPF:
+ case MBOX_DIR_PFVF:
+ mbox->tx_start = MBOX_DOWN_TX_START;
+ mbox->rx_start = MBOX_DOWN_RX_START;
+ mbox->tx_size = MBOX_DOWN_TX_SIZE;
+ mbox->rx_size = MBOX_DOWN_RX_SIZE;
+ break;
+ case MBOX_DIR_PFAF:
+ case MBOX_DIR_VFPF:
+ mbox->tx_start = MBOX_DOWN_RX_START;
+ mbox->rx_start = MBOX_DOWN_TX_START;
+ mbox->tx_size = MBOX_DOWN_RX_SIZE;
+ mbox->rx_size = MBOX_DOWN_TX_SIZE;
+ break;
+ case MBOX_DIR_AFPF_UP:
+ case MBOX_DIR_PFVF_UP:
+ mbox->tx_start = MBOX_UP_TX_START;
+ mbox->rx_start = MBOX_UP_RX_START;
+ mbox->tx_size = MBOX_UP_TX_SIZE;
+ mbox->rx_size = MBOX_UP_RX_SIZE;
+ break;
+ case MBOX_DIR_PFAF_UP:
+ case MBOX_DIR_VFPF_UP:
+ mbox->tx_start = MBOX_UP_RX_START;
+ mbox->rx_start = MBOX_UP_TX_START;
+ mbox->tx_size = MBOX_UP_RX_SIZE;
+ mbox->rx_size = MBOX_UP_TX_SIZE;
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ switch (direction) {
+ case MBOX_DIR_AFPF:
+ case MBOX_DIR_AFPF_UP:
+ mbox->trigger = RVU_AF_AFPF_MBOX0;
+ mbox->tr_shift = 4;
+ break;
+ case MBOX_DIR_PFAF:
+ case MBOX_DIR_PFAF_UP:
+ mbox->trigger = RVU_PF_PFAF_MBOX1;
+ mbox->tr_shift = 0;
+ break;
+ case MBOX_DIR_PFVF:
+ case MBOX_DIR_PFVF_UP:
+ mbox->trigger = RVU_PF_VFX_PFVF_MBOX0;
+ mbox->tr_shift = 12;
+ break;
+ case MBOX_DIR_VFPF:
+ case MBOX_DIR_VFPF_UP:
+ mbox->trigger = RVU_VF_VFPF_MBOX1;
+ mbox->tr_shift = 0;
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ mbox->reg_base = reg_base;
+ mbox->hwbase = hwbase;
+ mbox->pdev = pdev;
+
+ mbox->dev = kcalloc(ndevs, sizeof(struct otx2_mbox_dev), GFP_KERNEL);
+ if (!mbox->dev) {
+ otx2_mbox_destroy(mbox);
+ return -ENOMEM;
+ }
+
+ mbox->ndevs = ndevs;
+ for (devid = 0; devid < ndevs; devid++) {
+ mdev = &mbox->dev[devid];
+ mdev->mbase = mbox->hwbase + (devid * MBOX_SIZE);
+ spin_lock_init(&mdev->mbox_lock);
+ /* Init header to reset value */
+ otx2_mbox_reset(mbox, devid);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(otx2_mbox_init);
+
+int otx2_mbox_wait_for_rsp(struct otx2_mbox *mbox, int devid)
+{
+ struct otx2_mbox_dev *mdev = &mbox->dev[devid];
+ int timeout = 0, sleep = 1;
+
+ while (mdev->num_msgs != mdev->msgs_acked) {
+ msleep(sleep);
+ timeout += sleep;
+ if (timeout >= MBOX_RSP_TIMEOUT)
+ return -EIO;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(otx2_mbox_wait_for_rsp);
+
+int otx2_mbox_busy_poll_for_rsp(struct otx2_mbox *mbox, int devid)
+{
+ struct otx2_mbox_dev *mdev = &mbox->dev[devid];
+ unsigned long timeout = jiffies + 1 * HZ;
+
+ while (!time_after(jiffies, timeout)) {
+ if (mdev->num_msgs == mdev->msgs_acked)
+ return 0;
+ cpu_relax();
+ }
+ return -EIO;
+}
+EXPORT_SYMBOL(otx2_mbox_busy_poll_for_rsp);
+
+void otx2_mbox_msg_send(struct otx2_mbox *mbox, int devid)
+{
+ struct otx2_mbox_dev *mdev = &mbox->dev[devid];
+ struct mbox_hdr *tx_hdr, *rx_hdr;
+
+ tx_hdr = mdev->mbase + mbox->tx_start;
+ rx_hdr = mdev->mbase + mbox->rx_start;
+
+ spin_lock(&mdev->mbox_lock);
+ /* Reset header for next messages */
+ mdev->msg_size = 0;
+ mdev->rsp_size = 0;
+ mdev->msgs_acked = 0;
+
+ /* Sync mbox data into memory */
+ smp_wmb();
+
+ /* num_msgs != 0 signals to the peer that the buffer has a number of
+ * messages. So this should be written after writing all the messages
+ * to the shared memory.
+ */
+ tx_hdr->num_msgs = mdev->num_msgs;
+ rx_hdr->num_msgs = 0;
+ spin_unlock(&mdev->mbox_lock);
+
+ /* The interrupt should be fired after num_msgs is written
+ * to the shared memory
+ */
+ writeq(1, (void __iomem *)mbox->reg_base +
+ (mbox->trigger | (devid << mbox->tr_shift)));
+}
+EXPORT_SYMBOL(otx2_mbox_msg_send);
+
+struct mbox_msghdr *otx2_mbox_alloc_msg_rsp(struct otx2_mbox *mbox, int devid,
+ int size, int size_rsp)
+{
+ struct otx2_mbox_dev *mdev = &mbox->dev[devid];
+ struct mbox_msghdr *msghdr = NULL;
+
+ spin_lock(&mdev->mbox_lock);
+ size = ALIGN(size, MBOX_MSG_ALIGN);
+ size_rsp = ALIGN(size_rsp, MBOX_MSG_ALIGN);
+ /* Check if there is space in mailbox */
+ if ((mdev->msg_size + size) > mbox->tx_size - msgs_offset)
+ goto exit;
+ if ((mdev->rsp_size + size_rsp) > mbox->rx_size - msgs_offset)
+ goto exit;
+
+ if (mdev->msg_size == 0)
+ mdev->num_msgs = 0;
+ mdev->num_msgs++;
+
+ msghdr = mdev->mbase + mbox->tx_start + msgs_offset + mdev->msg_size;
+
+ /* Clear the whole msg region */
+ memset(msghdr, 0, sizeof(*msghdr) + size);
+ /* Init message header with reset values */
+ msghdr->ver = OTX2_MBOX_VERSION;
+ mdev->msg_size += size;
+ mdev->rsp_size += size_rsp;
+ msghdr->next_msgoff = mdev->msg_size + msgs_offset;
+exit:
+ spin_unlock(&mdev->mbox_lock);
+
+ return msghdr;
+}
+EXPORT_SYMBOL(otx2_mbox_alloc_msg_rsp);
+
+struct mbox_msghdr *otx2_mbox_get_rsp(struct otx2_mbox *mbox, int devid,
+ struct mbox_msghdr *msg)
+{
+ unsigned long imsg = mbox->tx_start + msgs_offset;
+ unsigned long irsp = mbox->rx_start + msgs_offset;
+ struct otx2_mbox_dev *mdev = &mbox->dev[devid];
+ u16 msgs;
+
+ if (mdev->num_msgs != mdev->msgs_acked)
+ return ERR_PTR(-ENODEV);
+
+ for (msgs = 0; msgs < mdev->msgs_acked; msgs++) {
+ struct mbox_msghdr *pmsg = mdev->mbase + imsg;
+ struct mbox_msghdr *prsp = mdev->mbase + irsp;
+
+ if (msg == pmsg) {
+ if (pmsg->id != prsp->id)
+ return ERR_PTR(-ENODEV);
+ return prsp;
+ }
+
+ imsg = pmsg->next_msgoff;
+ irsp = prsp->next_msgoff;
+ }
+
+ return ERR_PTR(-ENODEV);
+}
+EXPORT_SYMBOL(otx2_mbox_get_rsp);
+
+int
+otx2_reply_invalid_msg(struct otx2_mbox *mbox, int devid, u16 pcifunc, u16 id)
+{
+ struct msg_rsp *rsp;
+
+ rsp = (struct msg_rsp *)
+ otx2_mbox_alloc_msg(mbox, devid, sizeof(*rsp));
+ if (!rsp)
+ return -ENOMEM;
+ rsp->hdr.id = id;
+ rsp->hdr.sig = OTX2_MBOX_RSP_SIG;
+ rsp->hdr.rc = MBOX_MSG_INVALID;
+ rsp->hdr.pcifunc = pcifunc;
+ return 0;
+}
+EXPORT_SYMBOL(otx2_reply_invalid_msg);
+
+bool otx2_mbox_nonempty(struct otx2_mbox *mbox, int devid)
+{
+ struct otx2_mbox_dev *mdev = &mbox->dev[devid];
+ bool ret;
+
+ spin_lock(&mdev->mbox_lock);
+ ret = mdev->num_msgs != 0;
+ spin_unlock(&mdev->mbox_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(otx2_mbox_nonempty);
+
+const char *otx2_mbox_id2name(u16 id)
+{
+ switch (id) {
+#define M(_name, _id, _1, _2) case _id: return # _name;
+ MBOX_MESSAGES
+#undef M
+ default:
+ return "INVALID ID";
+ }
+}
+EXPORT_SYMBOL(otx2_mbox_id2name);
+
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
new file mode 100644
index 000000000000..a15a59c9a239
--- /dev/null
+++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
@@ -0,0 +1,525 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * Marvell OcteonTx2 RVU Admin Function driver
+ *
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef MBOX_H
+#define MBOX_H
+
+#include <linux/etherdevice.h>
+#include <linux/sizes.h>
+
+#include "rvu_struct.h"
+#include "common.h"
+
+#define MBOX_SIZE SZ_64K
+
+/* AF/PF: PF initiated, PF/VF VF initiated */
+#define MBOX_DOWN_RX_START 0
+#define MBOX_DOWN_RX_SIZE (46 * SZ_1K)
+#define MBOX_DOWN_TX_START (MBOX_DOWN_RX_START + MBOX_DOWN_RX_SIZE)
+#define MBOX_DOWN_TX_SIZE (16 * SZ_1K)
+/* AF/PF: AF initiated, PF/VF PF initiated */
+#define MBOX_UP_RX_START (MBOX_DOWN_TX_START + MBOX_DOWN_TX_SIZE)
+#define MBOX_UP_RX_SIZE SZ_1K
+#define MBOX_UP_TX_START (MBOX_UP_RX_START + MBOX_UP_RX_SIZE)
+#define MBOX_UP_TX_SIZE SZ_1K
+
+#if MBOX_UP_TX_SIZE + MBOX_UP_TX_START != MBOX_SIZE
+# error "incorrect mailbox area sizes"
+#endif
+
+#define INTR_MASK(pfvfs) ((pfvfs < 64) ? (BIT_ULL(pfvfs) - 1) : (~0ull))
+
+#define MBOX_RSP_TIMEOUT 1000 /* in ms, Time to wait for mbox response */
+
+#define MBOX_MSG_ALIGN 16 /* Align mbox msg start to 16bytes */
+
+/* Mailbox directions */
+#define MBOX_DIR_AFPF 0 /* AF replies to PF */
+#define MBOX_DIR_PFAF 1 /* PF sends messages to AF */
+#define MBOX_DIR_PFVF 2 /* PF replies to VF */
+#define MBOX_DIR_VFPF 3 /* VF sends messages to PF */
+#define MBOX_DIR_AFPF_UP 4 /* AF sends messages to PF */
+#define MBOX_DIR_PFAF_UP 5 /* PF replies to AF */
+#define MBOX_DIR_PFVF_UP 6 /* PF sends messages to VF */
+#define MBOX_DIR_VFPF_UP 7 /* VF replies to PF */
+
+struct otx2_mbox_dev {
+ void *mbase; /* This dev's mbox region */
+ spinlock_t mbox_lock;
+ u16 msg_size; /* Total msg size to be sent */
+ u16 rsp_size; /* Total rsp size to be sure the reply is ok */
+ u16 num_msgs; /* No of msgs sent or waiting for response */
+ u16 msgs_acked; /* No of msgs for which response is received */
+};
+
+struct otx2_mbox {
+ struct pci_dev *pdev;
+ void *hwbase; /* Mbox region advertised by HW */
+ void *reg_base;/* CSR base for this dev */
+ u64 trigger; /* Trigger mbox notification */
+ u16 tr_shift; /* Mbox trigger shift */
+ u64 rx_start; /* Offset of Rx region in mbox memory */
+ u64 tx_start; /* Offset of Tx region in mbox memory */
+ u16 rx_size; /* Size of Rx region */
+ u16 tx_size; /* Size of Tx region */
+ u16 ndevs; /* The number of peers */
+ struct otx2_mbox_dev *dev;
+};
+
+/* Header which preceeds all mbox messages */
+struct mbox_hdr {
+ u16 num_msgs; /* No of msgs embedded */
+};
+
+/* Header which preceeds every msg and is also part of it */
+struct mbox_msghdr {
+ u16 pcifunc; /* Who's sending this msg */
+ u16 id; /* Mbox message ID */
+#define OTX2_MBOX_REQ_SIG (0xdead)
+#define OTX2_MBOX_RSP_SIG (0xbeef)
+ u16 sig; /* Signature, for validating corrupted msgs */
+#define OTX2_MBOX_VERSION (0x0001)
+ u16 ver; /* Version of msg's structure for this ID */
+ u16 next_msgoff; /* Offset of next msg within mailbox region */
+ int rc; /* Msg process'ed response code */
+};
+
+void otx2_mbox_reset(struct otx2_mbox *mbox, int devid);
+void otx2_mbox_destroy(struct otx2_mbox *mbox);
+int otx2_mbox_init(struct otx2_mbox *mbox, void __force *hwbase,
+ struct pci_dev *pdev, void __force *reg_base,
+ int direction, int ndevs);
+void otx2_mbox_msg_send(struct otx2_mbox *mbox, int devid);
+int otx2_mbox_wait_for_rsp(struct otx2_mbox *mbox, int devid);
+int otx2_mbox_busy_poll_for_rsp(struct otx2_mbox *mbox, int devid);
+struct mbox_msghdr *otx2_mbox_alloc_msg_rsp(struct otx2_mbox *mbox, int devid,
+ int size, int size_rsp);
+struct mbox_msghdr *otx2_mbox_get_rsp(struct otx2_mbox *mbox, int devid,
+ struct mbox_msghdr *msg);
+int otx2_reply_invalid_msg(struct otx2_mbox *mbox, int devid,
+ u16 pcifunc, u16 id);
+bool otx2_mbox_nonempty(struct otx2_mbox *mbox, int devid);
+const char *otx2_mbox_id2name(u16 id);
+static inline struct mbox_msghdr *otx2_mbox_alloc_msg(struct otx2_mbox *mbox,
+ int devid, int size)
+{
+ return otx2_mbox_alloc_msg_rsp(mbox, devid, size, 0);
+}
+
+/* Mailbox message types */
+#define MBOX_MSG_MASK 0xFFFF
+#define MBOX_MSG_INVALID 0xFFFE
+#define MBOX_MSG_MAX 0xFFFF
+
+#define MBOX_MESSAGES \
+/* Generic mbox IDs (range 0x000 - 0x1FF) */ \
+M(READY, 0x001, msg_req, ready_msg_rsp) \
+M(ATTACH_RESOURCES, 0x002, rsrc_attach, msg_rsp) \
+M(DETACH_RESOURCES, 0x003, rsrc_detach, msg_rsp) \
+M(MSIX_OFFSET, 0x004, msg_req, msix_offset_rsp) \
+/* CGX mbox IDs (range 0x200 - 0x3FF) */ \
+M(CGX_START_RXTX, 0x200, msg_req, msg_rsp) \
+M(CGX_STOP_RXTX, 0x201, msg_req, msg_rsp) \
+M(CGX_STATS, 0x202, msg_req, cgx_stats_rsp) \
+M(CGX_MAC_ADDR_SET, 0x203, cgx_mac_addr_set_or_get, \
+ cgx_mac_addr_set_or_get) \
+M(CGX_MAC_ADDR_GET, 0x204, cgx_mac_addr_set_or_get, \
+ cgx_mac_addr_set_or_get) \
+M(CGX_PROMISC_ENABLE, 0x205, msg_req, msg_rsp) \
+M(CGX_PROMISC_DISABLE, 0x206, msg_req, msg_rsp) \
+M(CGX_START_LINKEVENTS, 0x207, msg_req, msg_rsp) \
+M(CGX_STOP_LINKEVENTS, 0x208, msg_req, msg_rsp) \
+M(CGX_GET_LINKINFO, 0x209, msg_req, cgx_link_info_msg) \
+M(CGX_INTLBK_ENABLE, 0x20A, msg_req, msg_rsp) \
+M(CGX_INTLBK_DISABLE, 0x20B, msg_req, msg_rsp) \
+/* NPA mbox IDs (range 0x400 - 0x5FF) */ \
+M(NPA_LF_ALLOC, 0x400, npa_lf_alloc_req, npa_lf_alloc_rsp) \
+M(NPA_LF_FREE, 0x401, msg_req, msg_rsp) \
+M(NPA_AQ_ENQ, 0x402, npa_aq_enq_req, npa_aq_enq_rsp) \
+M(NPA_HWCTX_DISABLE, 0x403, hwctx_disable_req, msg_rsp) \
+/* SSO/SSOW mbox IDs (range 0x600 - 0x7FF) */ \
+/* TIM mbox IDs (range 0x800 - 0x9FF) */ \
+/* CPT mbox IDs (range 0xA00 - 0xBFF) */ \
+/* NPC mbox IDs (range 0x6000 - 0x7FFF) */ \
+/* NIX mbox IDs (range 0x8000 - 0xFFFF) */ \
+M(NIX_LF_ALLOC, 0x8000, nix_lf_alloc_req, nix_lf_alloc_rsp) \
+M(NIX_LF_FREE, 0x8001, msg_req, msg_rsp) \
+M(NIX_AQ_ENQ, 0x8002, nix_aq_enq_req, nix_aq_enq_rsp) \
+M(NIX_HWCTX_DISABLE, 0x8003, hwctx_disable_req, msg_rsp) \
+M(NIX_TXSCH_ALLOC, 0x8004, nix_txsch_alloc_req, nix_txsch_alloc_rsp) \
+M(NIX_TXSCH_FREE, 0x8005, nix_txsch_free_req, msg_rsp) \
+M(NIX_TXSCHQ_CFG, 0x8006, nix_txschq_config, msg_rsp) \
+M(NIX_STATS_RST, 0x8007, msg_req, msg_rsp) \
+M(NIX_VTAG_CFG, 0x8008, nix_vtag_config, msg_rsp) \
+M(NIX_RSS_FLOWKEY_CFG, 0x8009, nix_rss_flowkey_cfg, msg_rsp) \
+M(NIX_SET_MAC_ADDR, 0x800a, nix_set_mac_addr, msg_rsp) \
+M(NIX_SET_RX_MODE, 0x800b, nix_rx_mode, msg_rsp)
+
+/* Messages initiated by AF (range 0xC00 - 0xDFF) */
+#define MBOX_UP_CGX_MESSAGES \
+M(CGX_LINK_EVENT, 0xC00, cgx_link_info_msg, msg_rsp)
+
+enum {
+#define M(_name, _id, _1, _2) MBOX_MSG_ ## _name = _id,
+MBOX_MESSAGES
+MBOX_UP_CGX_MESSAGES
+#undef M
+};
+
+/* Mailbox message formats */
+
+#define RVU_DEFAULT_PF_FUNC 0xFFFF
+
+/* Generic request msg used for those mbox messages which
+ * don't send any data in the request.
+ */
+struct msg_req {
+ struct mbox_msghdr hdr;
+};
+
+/* Generic rsponse msg used a ack or response for those mbox
+ * messages which doesn't have a specific rsp msg format.
+ */
+struct msg_rsp {
+ struct mbox_msghdr hdr;
+};
+
+struct ready_msg_rsp {
+ struct mbox_msghdr hdr;
+ u16 sclk_feq; /* SCLK frequency */
+};
+
+/* Structure for requesting resource provisioning.
+ * 'modify' flag to be used when either requesting more
+ * or to detach partial of a cetain resource type.
+ * Rest of the fields specify how many of what type to
+ * be attached.
+ */
+struct rsrc_attach {
+ struct mbox_msghdr hdr;
+ u8 modify:1;
+ u8 npalf:1;
+ u8 nixlf:1;
+ u16 sso;
+ u16 ssow;
+ u16 timlfs;
+ u16 cptlfs;
+};
+
+/* Structure for relinquishing resources.
+ * 'partial' flag to be used when relinquishing all resources
+ * but only of a certain type. If not set, all resources of all
+ * types provisioned to the RVU function will be detached.
+ */
+struct rsrc_detach {
+ struct mbox_msghdr hdr;
+ u8 partial:1;
+ u8 npalf:1;
+ u8 nixlf:1;
+ u8 sso:1;
+ u8 ssow:1;
+ u8 timlfs:1;
+ u8 cptlfs:1;
+};
+
+#define MSIX_VECTOR_INVALID 0xFFFF
+#define MAX_RVU_BLKLF_CNT 256
+
+struct msix_offset_rsp {
+ struct mbox_msghdr hdr;
+ u16 npa_msixoff;
+ u16 nix_msixoff;
+ u8 sso;
+ u8 ssow;
+ u8 timlfs;
+ u8 cptlfs;
+ u16 sso_msixoff[MAX_RVU_BLKLF_CNT];
+ u16 ssow_msixoff[MAX_RVU_BLKLF_CNT];
+ u16 timlf_msixoff[MAX_RVU_BLKLF_CNT];
+ u16 cptlf_msixoff[MAX_RVU_BLKLF_CNT];
+};
+
+/* CGX mbox message formats */
+
+struct cgx_stats_rsp {
+ struct mbox_msghdr hdr;
+#define CGX_RX_STATS_COUNT 13
+#define CGX_TX_STATS_COUNT 18
+ u64 rx_stats[CGX_RX_STATS_COUNT];
+ u64 tx_stats[CGX_TX_STATS_COUNT];
+};
+
+/* Structure for requesting the operation for
+ * setting/getting mac address in the CGX interface
+ */
+struct cgx_mac_addr_set_or_get {
+ struct mbox_msghdr hdr;
+ u8 mac_addr[ETH_ALEN];
+};
+
+struct cgx_link_user_info {
+ uint64_t link_up:1;
+ uint64_t full_duplex:1;
+ uint64_t lmac_type_id:4;
+ uint64_t speed:20; /* speed in Mbps */
+#define LMACTYPE_STR_LEN 16
+ char lmac_type[LMACTYPE_STR_LEN];
+};
+
+struct cgx_link_info_msg {
+ struct mbox_msghdr hdr;
+ struct cgx_link_user_info link_info;
+};
+
+/* NPA mbox message formats */
+
+/* NPA mailbox error codes
+ * Range 301 - 400.
+ */
+enum npa_af_status {
+ NPA_AF_ERR_PARAM = -301,
+ NPA_AF_ERR_AQ_FULL = -302,
+ NPA_AF_ERR_AQ_ENQUEUE = -303,
+ NPA_AF_ERR_AF_LF_INVALID = -304,
+ NPA_AF_ERR_AF_LF_ALLOC = -305,
+ NPA_AF_ERR_LF_RESET = -306,
+};
+
+/* For NPA LF context alloc and init */
+struct npa_lf_alloc_req {
+ struct mbox_msghdr hdr;
+ int node;
+ int aura_sz; /* No of auras */
+ u32 nr_pools; /* No of pools */
+};
+
+struct npa_lf_alloc_rsp {
+ struct mbox_msghdr hdr;
+ u32 stack_pg_ptrs; /* No of ptrs per stack page */
+ u32 stack_pg_bytes; /* Size of stack page */
+ u16 qints; /* NPA_AF_CONST::QINTS */
+};
+
+/* NPA AQ enqueue msg */
+struct npa_aq_enq_req {
+ struct mbox_msghdr hdr;
+ u32 aura_id;
+ u8 ctype;
+ u8 op;
+ union {
+ /* Valid when op == WRITE/INIT and ctype == AURA.
+ * LF fills the pool_id in aura.pool_addr. AF will translate
+ * the pool_id to pool context pointer.
+ */
+ struct npa_aura_s aura;
+ /* Valid when op == WRITE/INIT and ctype == POOL */
+ struct npa_pool_s pool;
+ };
+ /* Mask data when op == WRITE (1=write, 0=don't write) */
+ union {
+ /* Valid when op == WRITE and ctype == AURA */
+ struct npa_aura_s aura_mask;
+ /* Valid when op == WRITE and ctype == POOL */
+ struct npa_pool_s pool_mask;
+ };
+};
+
+struct npa_aq_enq_rsp {
+ struct mbox_msghdr hdr;
+ union {
+ /* Valid when op == READ and ctype == AURA */
+ struct npa_aura_s aura;
+ /* Valid when op == READ and ctype == POOL */
+ struct npa_pool_s pool;
+ };
+};
+
+/* Disable all contexts of type 'ctype' */
+struct hwctx_disable_req {
+ struct mbox_msghdr hdr;
+ u8 ctype;
+};
+
+/* NIX mailbox error codes
+ * Range 401 - 500.
+ */
+enum nix_af_status {
+ NIX_AF_ERR_PARAM = -401,
+ NIX_AF_ERR_AQ_FULL = -402,
+ NIX_AF_ERR_AQ_ENQUEUE = -403,
+ NIX_AF_ERR_AF_LF_INVALID = -404,
+ NIX_AF_ERR_AF_LF_ALLOC = -405,
+ NIX_AF_ERR_TLX_ALLOC_FAIL = -406,
+ NIX_AF_ERR_TLX_INVALID = -407,
+ NIX_AF_ERR_RSS_SIZE_INVALID = -408,
+ NIX_AF_ERR_RSS_GRPS_INVALID = -409,
+ NIX_AF_ERR_FRS_INVALID = -410,
+ NIX_AF_ERR_RX_LINK_INVALID = -411,
+ NIX_AF_INVAL_TXSCHQ_CFG = -412,
+ NIX_AF_SMQ_FLUSH_FAILED = -413,
+ NIX_AF_ERR_LF_RESET = -414,
+};
+
+/* For NIX LF context alloc and init */
+struct nix_lf_alloc_req {
+ struct mbox_msghdr hdr;
+ int node;
+ u32 rq_cnt; /* No of receive queues */
+ u32 sq_cnt; /* No of send queues */
+ u32 cq_cnt; /* No of completion queues */
+ u8 xqe_sz;
+ u16 rss_sz;
+ u8 rss_grps;
+ u16 npa_func;
+ u16 sso_func;
+ u64 rx_cfg; /* See NIX_AF_LF(0..127)_RX_CFG */
+};
+
+struct nix_lf_alloc_rsp {
+ struct mbox_msghdr hdr;
+ u16 sqb_size;
+ u16 rx_chan_base;
+ u16 tx_chan_base;
+ u8 rx_chan_cnt; /* total number of RX channels */
+ u8 tx_chan_cnt; /* total number of TX channels */
+ u8 lso_tsov4_idx;
+ u8 lso_tsov6_idx;
+ u8 mac_addr[ETH_ALEN];
+};
+
+/* NIX AQ enqueue msg */
+struct nix_aq_enq_req {
+ struct mbox_msghdr hdr;
+ u32 qidx;
+ u8 ctype;
+ u8 op;
+ union {
+ struct nix_rq_ctx_s rq;
+ struct nix_sq_ctx_s sq;
+ struct nix_cq_ctx_s cq;
+ struct nix_rsse_s rss;
+ struct nix_rx_mce_s mce;
+ };
+ union {
+ struct nix_rq_ctx_s rq_mask;
+ struct nix_sq_ctx_s sq_mask;
+ struct nix_cq_ctx_s cq_mask;
+ struct nix_rsse_s rss_mask;
+ struct nix_rx_mce_s mce_mask;
+ };
+};
+
+struct nix_aq_enq_rsp {
+ struct mbox_msghdr hdr;
+ union {
+ struct nix_rq_ctx_s rq;
+ struct nix_sq_ctx_s sq;
+ struct nix_cq_ctx_s cq;
+ struct nix_rsse_s rss;
+ struct nix_rx_mce_s mce;
+ };
+};
+
+/* Tx scheduler/shaper mailbox messages */
+
+#define MAX_TXSCHQ_PER_FUNC 128
+
+struct nix_txsch_alloc_req {
+ struct mbox_msghdr hdr;
+ /* Scheduler queue count request at each level */
+ u16 schq_contig[NIX_TXSCH_LVL_CNT]; /* No of contiguous queues */
+ u16 schq[NIX_TXSCH_LVL_CNT]; /* No of non-contiguous queues */
+};
+
+struct nix_txsch_alloc_rsp {
+ struct mbox_msghdr hdr;
+ /* Scheduler queue count allocated at each level */
+ u16 schq_contig[NIX_TXSCH_LVL_CNT];
+ u16 schq[NIX_TXSCH_LVL_CNT];
+ /* Scheduler queue list allocated at each level */
+ u16 schq_contig_list[NIX_TXSCH_LVL_CNT][MAX_TXSCHQ_PER_FUNC];
+ u16 schq_list[NIX_TXSCH_LVL_CNT][MAX_TXSCHQ_PER_FUNC];
+};
+
+struct nix_txsch_free_req {
+ struct mbox_msghdr hdr;
+#define TXSCHQ_FREE_ALL BIT_ULL(0)
+ u16 flags;
+ /* Scheduler queue level to be freed */
+ u16 schq_lvl;
+ /* List of scheduler queues to be freed */
+ u16 schq;
+};
+
+struct nix_txschq_config {
+ struct mbox_msghdr hdr;
+ u8 lvl; /* SMQ/MDQ/TL4/TL3/TL2/TL1 */
+#define TXSCHQ_IDX_SHIFT 16
+#define TXSCHQ_IDX_MASK (BIT_ULL(10) - 1)
+#define TXSCHQ_IDX(reg, shift) (((reg) >> (shift)) & TXSCHQ_IDX_MASK)
+ u8 num_regs;
+#define MAX_REGS_PER_MBOX_MSG 20
+ u64 reg[MAX_REGS_PER_MBOX_MSG];
+ u64 regval[MAX_REGS_PER_MBOX_MSG];
+};
+
+struct nix_vtag_config {
+ struct mbox_msghdr hdr;
+ u8 vtag_size;
+ /* cfg_type is '0' for tx vlan cfg
+ * cfg_type is '1' for rx vlan cfg
+ */
+ u8 cfg_type;
+ union {
+ /* valid when cfg_type is '0' */
+ struct {
+ /* tx vlan0 tag(C-VLAN) */
+ u64 vlan0;
+ /* tx vlan1 tag(S-VLAN) */
+ u64 vlan1;
+ /* insert tx vlan tag */
+ u8 insert_vlan :1;
+ /* insert tx double vlan tag */
+ u8 double_vlan :1;
+ } tx;
+
+ /* valid when cfg_type is '1' */
+ struct {
+ /* rx vtag type index */
+ u8 vtag_type;
+ /* rx vtag strip */
+ u8 strip_vtag :1;
+ /* rx vtag capture */
+ u8 capture_vtag :1;
+ } rx;
+ };
+};
+
+struct nix_rss_flowkey_cfg {
+ struct mbox_msghdr hdr;
+ int mcam_index; /* MCAM entry index to modify */
+ u32 flowkey_cfg; /* Flowkey types selected */
+ u8 group; /* RSS context or group */
+};
+
+struct nix_set_mac_addr {
+ struct mbox_msghdr hdr;
+ u8 mac_addr[ETH_ALEN]; /* MAC address to be set for this pcifunc */
+};
+
+struct nix_rx_mode {
+ struct mbox_msghdr hdr;
+#define NIX_RX_MODE_UCAST BIT(0)
+#define NIX_RX_MODE_PROMISC BIT(1)
+#define NIX_RX_MODE_ALLMULTI BIT(2)
+ u16 mode;
+};
+
+#endif /* MBOX_H */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/npc.h b/drivers/net/ethernet/marvell/octeontx2/af/npc.h
new file mode 100644
index 000000000000..f98b0113def3
--- /dev/null
+++ b/drivers/net/ethernet/marvell/octeontx2/af/npc.h
@@ -0,0 +1,262 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * Marvell OcteonTx2 RVU Admin Function driver
+ *
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef NPC_H
+#define NPC_H
+
+enum NPC_LID_E {
+ NPC_LID_LA = 0,
+ NPC_LID_LB,
+ NPC_LID_LC,
+ NPC_LID_LD,
+ NPC_LID_LE,
+ NPC_LID_LF,
+ NPC_LID_LG,
+ NPC_LID_LH,
+};
+
+#define NPC_LT_NA 0
+
+enum npc_kpu_la_ltype {
+ NPC_LT_LA_8023 = 1,
+ NPC_LT_LA_ETHER,
+};
+
+enum npc_kpu_lb_ltype {
+ NPC_LT_LB_ETAG = 1,
+ NPC_LT_LB_CTAG,
+ NPC_LT_LB_STAG,
+ NPC_LT_LB_BTAG,
+ NPC_LT_LB_QINQ,
+ NPC_LT_LB_ITAG,
+};
+
+enum npc_kpu_lc_ltype {
+ NPC_LT_LC_IP = 1,
+ NPC_LT_LC_IP6,
+ NPC_LT_LC_ARP,
+ NPC_LT_LC_RARP,
+ NPC_LT_LC_MPLS,
+ NPC_LT_LC_NSH,
+ NPC_LT_LC_PTP,
+ NPC_LT_LC_FCOE,
+};
+
+/* Don't modify Ltypes upto SCTP, otherwise it will
+ * effect flow tag calculation and thus RSS.
+ */
+enum npc_kpu_ld_ltype {
+ NPC_LT_LD_TCP = 1,
+ NPC_LT_LD_UDP,
+ NPC_LT_LD_ICMP,
+ NPC_LT_LD_SCTP,
+ NPC_LT_LD_IGMP,
+ NPC_LT_LD_ICMP6,
+ NPC_LT_LD_ESP,
+ NPC_LT_LD_AH,
+ NPC_LT_LD_GRE,
+ NPC_LT_LD_GRE_MPLS,
+ NPC_LT_LD_GRE_NSH,
+ NPC_LT_LD_TU_MPLS,
+};
+
+enum npc_kpu_le_ltype {
+ NPC_LT_LE_TU_ETHER = 1,
+ NPC_LT_LE_TU_PPP,
+ NPC_LT_LE_TU_MPLS_IN_NSH,
+ NPC_LT_LE_TU_3RD_NSH,
+};
+
+enum npc_kpu_lf_ltype {
+ NPC_LT_LF_TU_IP = 1,
+ NPC_LT_LF_TU_IP6,
+ NPC_LT_LF_TU_ARP,
+ NPC_LT_LF_TU_MPLS_IP,
+ NPC_LT_LF_TU_MPLS_IP6,
+ NPC_LT_LF_TU_MPLS_ETHER,
+};
+
+enum npc_kpu_lg_ltype {
+ NPC_LT_LG_TU_TCP = 1,
+ NPC_LT_LG_TU_UDP,
+ NPC_LT_LG_TU_SCTP,
+ NPC_LT_LG_TU_ICMP,
+ NPC_LT_LG_TU_IGMP,
+ NPC_LT_LG_TU_ICMP6,
+ NPC_LT_LG_TU_ESP,
+ NPC_LT_LG_TU_AH,
+};
+
+enum npc_kpu_lh_ltype {
+ NPC_LT_LH_TCP_DATA = 1,
+ NPC_LT_LH_HTTP_DATA,
+ NPC_LT_LH_HTTPS_DATA,
+ NPC_LT_LH_PPTP_DATA,
+ NPC_LT_LH_UDP_DATA,
+};
+
+struct npc_kpu_profile_cam {
+ u8 state;
+ u8 state_mask;
+ u16 dp0;
+ u16 dp0_mask;
+ u16 dp1;
+ u16 dp1_mask;
+ u16 dp2;
+ u16 dp2_mask;
+};
+
+struct npc_kpu_profile_action {
+ u8 errlev;
+ u8 errcode;
+ u8 dp0_offset;
+ u8 dp1_offset;
+ u8 dp2_offset;
+ u8 bypass_count;
+ u8 parse_done;
+ u8 next_state;
+ u8 ptr_advance;
+ u8 cap_ena;
+ u8 lid;
+ u8 ltype;
+ u8 flags;
+ u8 offset;
+ u8 mask;
+ u8 right;
+ u8 shift;
+};
+
+struct npc_kpu_profile {
+ int cam_entries;
+ int action_entries;
+ struct npc_kpu_profile_cam *cam;
+ struct npc_kpu_profile_action *action;
+};
+
+/* NPC KPU register formats */
+struct npc_kpu_cam {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ u64 rsvd_63_56 : 8;
+ u64 state : 8;
+ u64 dp2_data : 16;
+ u64 dp1_data : 16;
+ u64 dp0_data : 16;
+#else
+ u64 dp0_data : 16;
+ u64 dp1_data : 16;
+ u64 dp2_data : 16;
+ u64 state : 8;
+ u64 rsvd_63_56 : 8;
+#endif
+};
+
+struct npc_kpu_action0 {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ u64 rsvd_63_57 : 7;
+ u64 byp_count : 3;
+ u64 capture_ena : 1;
+ u64 parse_done : 1;
+ u64 next_state : 8;
+ u64 rsvd_43 : 1;
+ u64 capture_lid : 3;
+ u64 capture_ltype : 4;
+ u64 capture_flags : 8;
+ u64 ptr_advance : 8;
+ u64 var_len_offset : 8;
+ u64 var_len_mask : 8;
+ u64 var_len_right : 1;
+ u64 var_len_shift : 3;
+#else
+ u64 var_len_shift : 3;
+ u64 var_len_right : 1;
+ u64 var_len_mask : 8;
+ u64 var_len_offset : 8;
+ u64 ptr_advance : 8;
+ u64 capture_flags : 8;
+ u64 capture_ltype : 4;
+ u64 capture_lid : 3;
+ u64 rsvd_43 : 1;
+ u64 next_state : 8;
+ u64 parse_done : 1;
+ u64 capture_ena : 1;
+ u64 byp_count : 3;
+ u64 rsvd_63_57 : 7;
+#endif
+};
+
+struct npc_kpu_action1 {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ u64 rsvd_63_36 : 28;
+ u64 errlev : 4;
+ u64 errcode : 8;
+ u64 dp2_offset : 8;
+ u64 dp1_offset : 8;
+ u64 dp0_offset : 8;
+#else
+ u64 dp0_offset : 8;
+ u64 dp1_offset : 8;
+ u64 dp2_offset : 8;
+ u64 errcode : 8;
+ u64 errlev : 4;
+ u64 rsvd_63_36 : 28;
+#endif
+};
+
+struct npc_kpu_pkind_cpi_def {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ u64 ena : 1;
+ u64 rsvd_62_59 : 4;
+ u64 lid : 3;
+ u64 ltype_match : 4;
+ u64 ltype_mask : 4;
+ u64 flags_match : 8;
+ u64 flags_mask : 8;
+ u64 add_offset : 8;
+ u64 add_mask : 8;
+ u64 rsvd_15 : 1;
+ u64 add_shift : 3;
+ u64 rsvd_11_10 : 2;
+ u64 cpi_base : 10;
+#else
+ u64 cpi_base : 10;
+ u64 rsvd_11_10 : 2;
+ u64 add_shift : 3;
+ u64 rsvd_15 : 1;
+ u64 add_mask : 8;
+ u64 add_offset : 8;
+ u64 flags_mask : 8;
+ u64 flags_match : 8;
+ u64 ltype_mask : 4;
+ u64 ltype_match : 4;
+ u64 lid : 3;
+ u64 rsvd_62_59 : 4;
+ u64 ena : 1;
+#endif
+};
+
+struct nix_rx_action {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ u64 rsvd_63_61 :3;
+ u64 flow_key_alg :5;
+ u64 match_id :16;
+ u64 index :20;
+ u64 pf_func :16;
+ u64 op :4;
+#else
+ u64 op :4;
+ u64 pf_func :16;
+ u64 index :20;
+ u64 match_id :16;
+ u64 flow_key_alg :5;
+ u64 rsvd_63_61 :3;
+#endif
+};
+
+#endif /* NPC_H */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/npc_profile.h b/drivers/net/ethernet/marvell/octeontx2/af/npc_profile.h
new file mode 100644
index 000000000000..b2ce957605bb
--- /dev/null
+++ b/drivers/net/ethernet/marvell/octeontx2/af/npc_profile.h
@@ -0,0 +1,5709 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * Marvell OcteonTx2 RVU Admin Function driver
+ *
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef NPC_PROFILE_H
+#define NPC_PROFILE_H
+
+#define NPC_ETYPE_IP 0x0800
+#define NPC_ETYPE_IP6 0x86dd
+#define NPC_ETYPE_ARP 0x0806
+#define NPC_ETYPE_RARP 0x8035
+#define NPC_ETYPE_MPLSU 0x8847
+#define NPC_ETYPE_MPLSM 0x8848
+#define NPC_ETYPE_ETAG 0x893f
+#define NPC_ETYPE_CTAG 0x8100
+#define NPC_ETYPE_SBTAG 0x88a8
+#define NPC_ETYPE_ITAG 0x88e7
+#define NPC_ETYPE_PTP 0x88f7
+#define NPC_ETYPE_FCOE 0x8906
+#define NPC_ETYPE_QINQ 0x9100
+#define NPC_ETYPE_TRANS_ETH_BR 0x6558
+#define NPC_ETYPE_PPP 0x880b
+#define NPC_ETYPE_NSH 0x894f
+
+#define NPC_IPNH_HOP 0
+#define NPC_IPNH_ICMP 1
+#define NPC_IPNH_IGMP 2
+#define NPC_IPNH_IP 4
+#define NPC_IPNH_TCP 6
+#define NPC_IPNH_UDP 17
+#define NPC_IPNH_IP6 41
+#define NPC_IPNH_ROUT 43
+#define NPC_IPNH_FRAG 44
+#define NPC_IPNH_GRE 47
+#define NPC_IPNH_ESP 50
+#define NPC_IPNH_AH 51
+#define NPC_IPNH_ICMP6 58
+#define NPC_IPNH_NONH 59
+#define NPC_IPNH_DEST 60
+#define NPC_IPNH_SCTP 132
+#define NPC_IPNH_MPLS 137
+
+#define NPC_UDP_PORT_GTPC 2123
+#define NPC_UDP_PORT_GTPU 2152
+#define NPC_UDP_PORT_VXLAN 4789
+#define NPC_UDP_PORT_VXLANGPE 4790
+#define NPC_UDP_PORT_GENEVE 6081
+
+#define NPC_VXLANGPE_NP_IP 0x1
+#define NPC_VXLANGPE_NP_IP6 0x2
+#define NPC_VXLANGPE_NP_ETH 0x3
+#define NPC_VXLANGPE_NP_NSH 0x4
+#define NPC_VXLANGPE_NP_MPLS 0x5
+#define NPC_VXLANGPE_NP_GBP 0x6
+#define NPC_VXLANGPE_NP_VBNG 0x7
+
+#define NPC_NSH_NP_IP 0x1
+#define NPC_NSH_NP_IP6 0x2
+#define NPC_NSH_NP_ETH 0x3
+#define NPC_NSH_NP_NSH 0x4
+#define NPC_NSH_NP_MPLS 0x5
+
+#define NPC_TCP_PORT_HTTP 80
+#define NPC_TCP_PORT_HTTPS 443
+#define NPC_TCP_PORT_PPTP 1723
+
+#define NPC_MPLS_S 0x0100
+
+#define NPC_IP_VER_4 0x4000
+#define NPC_IP_VER_6 0x6000
+#define NPC_IP_VER_MASK 0xf000
+#define NPC_IP_HDR_LEN_5 0x0500
+#define NPC_IP_HDR_LEN_MASK 0x0f00
+
+#define NPC_GRE_F_CSUM (0x1 << 15)
+#define NPC_GRE_F_ROUTE (0x1 << 14)
+#define NPC_GRE_F_KEY (0x1 << 13)
+#define NPC_GRE_F_SEQ (0x1 << 12)
+#define NPC_GRE_F_ACK (0x1 << 7)
+#define NPC_GRE_FLAG_MASK (NPC_GRE_F_CSUM | NPC_GRE_F_ROUTE | \
+ NPC_GRE_F_KEY | NPC_GRE_F_SEQ | NPC_GRE_F_ACK)
+#define NPC_GRE_VER_MASK 0x0003
+#define NPC_GRE_VER_1 0x0001
+
+#define NPC_VXLAN_I 0x0800
+
+#define NPC_VXLANGPE_VER (0x3 << 12)
+#define NPC_VXLANGPE_I (0x1 << 11)
+#define NPC_VXLANGPE_P (0x1 << 10)
+#define NPC_VXLANGPE_B (0x1 << 9)
+#define NPC_VXLANGPE_NP_MASK 0x00ff
+
+#define NPC_NSH_NP_MASK 0x00ff
+
+#define NPC_GENEVE_F_OAM (0x1 << 7)
+#define NPC_GENEVE_F_CRI_OPT (0x1 << 6)
+
+#define NPC_GTP_PT_GTP (0x1 << 12)
+#define NPC_GTP_PT_MASK (0x1 << 12)
+#define NPC_GTP_VER1 (0x1 << 13)
+#define NPC_GTP_VER_MASK (0x7 << 13)
+#define NPC_GTP_MT_G_PDU 0xff
+#define NPC_GTP_MT_MASK 0xff
+
+#define NPC_TCP_DATA_OFFSET_5 0x5000
+#define NPC_TCP_DATA_OFFSET_MASK 0xf000
+
+enum npc_kpu_parser_state {
+ NPC_S_NA = 0,
+ NPC_S_KPU1_ETHER,
+ NPC_S_KPU1_PKI,
+ NPC_S_KPU2_CTAG,
+ NPC_S_KPU2_SBTAG,
+ NPC_S_KPU2_QINQ,
+ NPC_S_KPU2_ETAG,
+ NPC_S_KPU2_ITAG,
+ NPC_S_KPU3_CTAG,
+ NPC_S_KPU3_STAG,
+ NPC_S_KPU3_QINQ,
+ NPC_S_KPU3_ITAG,
+ NPC_S_KPU4_MPLS,
+ NPC_S_KPU4_NSH,
+ NPC_S_KPU5_IP,
+ NPC_S_KPU5_IP6,
+ NPC_S_KPU5_ARP,
+ NPC_S_KPU5_RARP,
+ NPC_S_KPU5_PTP,
+ NPC_S_KPU5_FCOE,
+ NPC_S_KPU5_MPLS,
+ NPC_S_KPU5_MPLS_PL,
+ NPC_S_KPU5_NSH,
+ NPC_S_KPU6_IP6_EXT,
+ NPC_S_KPU7_IP6_EXT,
+ NPC_S_KPU8_TCP,
+ NPC_S_KPU8_UDP,
+ NPC_S_KPU8_SCTP,
+ NPC_S_KPU8_ICMP,
+ NPC_S_KPU8_IGMP,
+ NPC_S_KPU8_ICMP6,
+ NPC_S_KPU8_GRE,
+ NPC_S_KPU8_ESP,
+ NPC_S_KPU8_AH,
+ NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN,
+ NPC_S_KPU9_TU_MPLS,
+ NPC_S_KPU9_TU_NSH,
+ NPC_S_KPU10_TU_MPLS_PL,
+ NPC_S_KPU10_TU_MPLS,
+ NPC_S_KPU10_TU_NSH,
+ NPC_S_KPU11_TU_ETHER,
+ NPC_S_KPU11_TU_PPP,
+ NPC_S_KPU11_TU_MPLS_IN_NSH,
+ NPC_S_KPU11_TU_3RD_NSH,
+ NPC_S_KPU12_TU_IP,
+ NPC_S_KPU12_TU_IP6,
+ NPC_S_KPU12_TU_ARP,
+ NPC_S_KPU13_TU_IP6_EXT,
+ NPC_S_KPU14_TU_IP6_EXT,
+ NPC_S_KPU15_TU_TCP,
+ NPC_S_KPU15_TU_UDP,
+ NPC_S_KPU15_TU_SCTP,
+ NPC_S_KPU15_TU_ICMP,
+ NPC_S_KPU15_TU_IGMP,
+ NPC_S_KPU15_TU_ICMP6,
+ NPC_S_KPU15_TU_ESP,
+ NPC_S_KPU15_TU_AH,
+ NPC_S_KPU16_HTTP_DATA,
+ NPC_S_KPU16_HTTPS_DATA,
+ NPC_S_KPU16_PPTP_DATA,
+ NPC_S_KPU16_TCP_DATA,
+ NPC_S_KPU16_UDP_DATA,
+ NPC_S_LAST /* has to be the last item */
+};
+
+enum npc_kpu_parser_flag {
+ NPC_F_NA = 0,
+ NPC_F_PKI,
+ NPC_F_PKI_VLAN,
+ NPC_F_PKI_ETAG,
+ NPC_F_PKI_ITAG,
+ NPC_F_PKI_MPLS,
+ NPC_F_PKI_NSH,
+ NPC_F_ETYPE_UNK,
+ NPC_F_ETHER_VLAN,
+ NPC_F_ETHER_ETAG,
+ NPC_F_ETHER_ITAG,
+ NPC_F_ETHER_MPLS,
+ NPC_F_ETHER_NSH,
+ NPC_F_STAG_CTAG,
+ NPC_F_STAG_CTAG_UNK,
+ NPC_F_STAG_STAG_CTAG,
+ NPC_F_STAG_STAG_STAG,
+ NPC_F_QINQ_CTAG,
+ NPC_F_QINQ_CTAG_UNK,
+ NPC_F_QINQ_QINQ_CTAG,
+ NPC_F_QINQ_QINQ_QINQ,
+ NPC_F_BTAG_ITAG,
+ NPC_F_BTAG_ITAG_STAG,
+ NPC_F_BTAG_ITAG_CTAG,
+ NPC_F_BTAG_ITAG_UNK,
+ NPC_F_ETAG_CTAG,
+ NPC_F_ETAG_BTAG_ITAG,
+ NPC_F_ETAG_STAG,
+ NPC_F_ETAG_QINQ,
+ NPC_F_ETAG_ITAG,
+ NPC_F_ETAG_ITAG_STAG,
+ NPC_F_ETAG_ITAG_CTAG,
+ NPC_F_ETAG_ITAG_UNK,
+ NPC_F_ITAG_STAG_CTAG,
+ NPC_F_ITAG_STAG,
+ NPC_F_ITAG_CTAG,
+ NPC_F_MPLS_4_LABELS,
+ NPC_F_MPLS_3_LABELS,
+ NPC_F_MPLS_2_LABELS,
+ NPC_F_IP_HAS_OPTIONS,
+ NPC_F_IP_IP_IN_IP,
+ NPC_F_IP_6TO4,
+ NPC_F_IP_MPLS_IN_IP,
+ NPC_F_IP_UNK_PROTO,
+ NPC_F_IP_IP_IN_IP_HAS_OPTIONS,
+ NPC_F_IP_6TO4_HAS_OPTIONS,
+ NPC_F_IP_MPLS_IN_IP_HAS_OPTIONS,
+ NPC_F_IP_UNK_PROTO_HAS_OPTIONS,
+ NPC_F_IP6_HAS_EXT,
+ NPC_F_IP6_TUN_IP6,
+ NPC_F_IP6_MPLS_IN_IP,
+ NPC_F_TCP_HAS_OPTIONS,
+ NPC_F_TCP_HTTP,
+ NPC_F_TCP_HTTPS,
+ NPC_F_TCP_PPTP,
+ NPC_F_TCP_UNK_PORT,
+ NPC_F_TCP_HTTP_HAS_OPTIONS,
+ NPC_F_TCP_HTTPS_HAS_OPTIONS,
+ NPC_F_TCP_PPTP_HAS_OPTIONS,
+ NPC_F_TCP_UNK_PORT_HAS_OPTIONS,
+ NPC_F_UDP_VXLAN,
+ NPC_F_UDP_VXLAN_NOVNI,
+ NPC_F_UDP_VXLAN_NOVNI_NSH,
+ NPC_F_UDP_VXLANGPE,
+ NPC_F_UDP_VXLANGPE_NSH,
+ NPC_F_UDP_VXLANGPE_MPLS,
+ NPC_F_UDP_VXLANGPE_NOVNI,
+ NPC_F_UDP_VXLANGPE_NOVNI_NSH,
+ NPC_F_UDP_VXLANGPE_NOVNI_MPLS,
+ NPC_F_UDP_VXLANGPE_UNK,
+ NPC_F_UDP_VXLANGPE_NONP,
+ NPC_F_UDP_GTP_GTPC,
+ NPC_F_UDP_GTP_GTPU_G_PDU,
+ NPC_F_UDP_GTP_GTPU_UNK,
+ NPC_F_UDP_UNK_PORT,
+ NPC_F_UDP_GENEVE,
+ NPC_F_UDP_GENEVE_OAM,
+ NPC_F_UDP_GENEVE_CRI_OPT,
+ NPC_F_UDP_GENEVE_OAM_CRI_OPT,
+ NPC_F_GRE_NVGRE,
+ NPC_F_GRE_HAS_SRE,
+ NPC_F_GRE_HAS_CSUM,
+ NPC_F_GRE_HAS_KEY,
+ NPC_F_GRE_HAS_SEQ,
+ NPC_F_GRE_HAS_CSUM_KEY,
+ NPC_F_GRE_HAS_CSUM_SEQ,
+ NPC_F_GRE_HAS_KEY_SEQ,
+ NPC_F_GRE_HAS_CSUM_KEY_SEQ,
+ NPC_F_GRE_HAS_ROUTE,
+ NPC_F_GRE_UNK_PROTO,
+ NPC_F_GRE_VER1,
+ NPC_F_GRE_VER1_HAS_SEQ,
+ NPC_F_GRE_VER1_HAS_ACK,
+ NPC_F_GRE_VER1_HAS_SEQ_ACK,
+ NPC_F_GRE_VER1_UNK_PROTO,
+ NPC_F_TU_ETHER_UNK,
+ NPC_F_TU_ETHER_CTAG,
+ NPC_F_TU_ETHER_CTAG_UNK,
+ NPC_F_TU_ETHER_STAG_CTAG,
+ NPC_F_TU_ETHER_STAG_CTAG_UNK,
+ NPC_F_TU_ETHER_STAG,
+ NPC_F_TU_ETHER_STAG_UNK,
+ NPC_F_TU_ETHER_QINQ_CTAG,
+ NPC_F_TU_ETHER_QINQ_CTAG_UNK,
+ NPC_F_TU_ETHER_QINQ,
+ NPC_F_TU_ETHER_QINQ_UNK,
+ NPC_F_LAST /* has to be the last item */
+};
+
+enum npc_kpu_err_code {
+ NPC_EC_NOERR = 0, /* has to be zero */
+ NPC_EC_UNK,
+ NPC_EC_L2_K1,
+ NPC_EC_L2_K2,
+ NPC_EC_L2_K3,
+ NPC_EC_L2_K3_ETYPE_UNK,
+ NPC_EC_L2_MPLS_2MANY,
+ NPC_EC_L2_K4,
+ NPC_EC_IP_VER,
+ NPC_EC_IP6_VER,
+ NPC_EC_VXLAN,
+ NPC_EC_NVGRE,
+ NPC_EC_GRE,
+ NPC_EC_GRE_VER1,
+ NPC_EC_L4,
+ NPC_EC_LAST /* has to be the last item */
+};
+
+enum NPC_ERRLEV_E {
+ NPC_ERRLEV_RE = 0,
+ NPC_ERRLEV_LA = 1,
+ NPC_ERRLEV_LB = 2,
+ NPC_ERRLEV_LC = 3,
+ NPC_ERRLEV_LD = 4,
+ NPC_ERRLEV_LE = 5,
+ NPC_ERRLEV_LF = 6,
+ NPC_ERRLEV_LG = 7,
+ NPC_ERRLEV_LH = 8,
+ NPC_ERRLEV_R9 = 9,
+ NPC_ERRLEV_R10 = 10,
+ NPC_ERRLEV_R11 = 11,
+ NPC_ERRLEV_R12 = 12,
+ NPC_ERRLEV_R13 = 13,
+ NPC_ERRLEV_R14 = 14,
+ NPC_ERRLEV_NIX = 15,
+ NPC_ERRLEV_ENUM_LAST = 16,
+};
+
+static struct npc_kpu_profile_action ikpu_action_entries[] = {
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16,
+ 0, 0, NPC_S_KPU1_ETHER, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 1, 0xff,
+ 0, 0,
+ },
+};
+
+static struct npc_kpu_profile_cam kpu1_cam_entries[] = {
+ {
+ NPC_S_KPU1_ETHER, 0xff, NPC_ETYPE_IP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU1_ETHER, 0xff, NPC_ETYPE_IP6, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU1_ETHER, 0xff, NPC_ETYPE_ARP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU1_ETHER, 0xff, NPC_ETYPE_RARP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU1_ETHER, 0xff, NPC_ETYPE_PTP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU1_ETHER, 0xff, NPC_ETYPE_FCOE, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU1_ETHER, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU1_ETHER, 0xff, NPC_ETYPE_SBTAG, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU1_ETHER, 0xff, NPC_ETYPE_QINQ, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU1_ETHER, 0xff, NPC_ETYPE_ETAG, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU1_ETHER, 0xff, NPC_ETYPE_ITAG, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU1_ETHER, 0xff, NPC_ETYPE_MPLSU, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU1_ETHER, 0xff, NPC_ETYPE_MPLSM, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU1_ETHER, 0xff, NPC_ETYPE_NSH, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU1_ETHER, 0xff, 0x0000, 0xfc00,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU1_ETHER, 0xff, 0x0400, 0xfe00,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU1_ETHER, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU1_PKI, 0xff, NPC_ETYPE_IP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU1_PKI, 0xff, NPC_ETYPE_IP6, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU1_PKI, 0xff, NPC_ETYPE_ARP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU1_PKI, 0xff, NPC_ETYPE_RARP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU1_PKI, 0xff, NPC_ETYPE_PTP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU1_PKI, 0xff, NPC_ETYPE_FCOE, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU1_PKI, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU1_PKI, 0xff, NPC_ETYPE_SBTAG, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU1_PKI, 0xff, NPC_ETYPE_QINQ, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU1_PKI, 0xff, NPC_ETYPE_ETAG, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU1_PKI, 0xff, NPC_ETYPE_ITAG, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU1_PKI, 0xff, NPC_ETYPE_MPLSU, 0xffff,
+ 0x0010, 0x0010, 0x0000, 0xffff,
+ },
+ {
+ NPC_S_KPU1_PKI, 0xff, NPC_ETYPE_MPLSM, 0xffff,
+ 0x0010, 0x0010, 0x0000, 0xffff,
+ },
+ {
+ NPC_S_KPU1_PKI, 0xff, NPC_ETYPE_NSH, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU1_PKI, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_NA, 0X00, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+};
+
+static struct npc_kpu_profile_cam kpu2_cam_entries[] = {
+ {
+ NPC_S_KPU2_CTAG, 0xff, NPC_ETYPE_IP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_CTAG, 0xff, NPC_ETYPE_IP6, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_CTAG, 0xff, NPC_ETYPE_ARP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_CTAG, 0xff, NPC_ETYPE_RARP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_CTAG, 0xff, NPC_ETYPE_PTP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_CTAG, 0xff, NPC_ETYPE_FCOE, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_CTAG, 0xff, NPC_ETYPE_MPLSU, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_CTAG, 0xff, NPC_ETYPE_MPLSM, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_CTAG, 0xff, NPC_ETYPE_NSH, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_CTAG, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_IP, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_IP6, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_ARP, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_RARP, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_PTP, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_FCOE, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_MPLSU, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_MPLSM, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_NSH, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_SBTAG, 0xffff,
+ NPC_ETYPE_CTAG, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_SBTAG, 0xffff,
+ NPC_ETYPE_SBTAG, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_ITAG, 0xffff,
+ 0x0000, 0x0000, NPC_ETYPE_IP, 0xffff,
+ },
+ {
+ NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_ITAG, 0xffff,
+ 0x0000, 0x0000, NPC_ETYPE_IP6, 0xffff,
+ },
+ {
+ NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_ITAG, 0xffff,
+ 0x0000, 0x0000, NPC_ETYPE_ARP, 0xffff,
+ },
+ {
+ NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_ITAG, 0xffff,
+ 0x0000, 0x0000, NPC_ETYPE_RARP, 0xffff,
+ },
+ {
+ NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_ITAG, 0xffff,
+ 0x0000, 0x0000, NPC_ETYPE_PTP, 0xffff,
+ },
+ {
+ NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_ITAG, 0xffff,
+ 0x0000, 0x0000, NPC_ETYPE_FCOE, 0xffff,
+ },
+ {
+ NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_ITAG, 0xffff,
+ 0x0000, 0x0000, NPC_ETYPE_MPLSU, 0xffff,
+ },
+ {
+ NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_ITAG, 0xffff,
+ 0x0000, 0x0000, NPC_ETYPE_MPLSM, 0xffff,
+ },
+ {
+ NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_ITAG, 0xffff,
+ 0x0000, 0x0000, NPC_ETYPE_NSH, 0xffff,
+ },
+ {
+ NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_ITAG, 0xffff,
+ 0x0000, 0x0000, NPC_ETYPE_SBTAG, 0xffff,
+ },
+ {
+ NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_ITAG, 0xffff,
+ 0x0000, 0x0000, NPC_ETYPE_CTAG, 0xffff,
+ },
+ {
+ NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_ITAG, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_IP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_IP6, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_ARP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_RARP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_PTP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_FCOE, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_MPLSU, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_MPLSM, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_NSH, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_SBTAG, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_IP, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_IP6, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_ARP, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_RARP, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_PTP, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_FCOE, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_MPLSU, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_MPLSM, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_NSH, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_QINQ, 0xffff,
+ NPC_ETYPE_CTAG, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_QINQ, 0xffff,
+ NPC_ETYPE_QINQ, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_IP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_IP6, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_ARP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_RARP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_PTP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_FCOE, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_MPLSU, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_MPLSM, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_NSH, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_QINQ, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_ETAG, 0xff, NPC_ETYPE_IP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_ETAG, 0xff, NPC_ETYPE_IP6, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_ETAG, 0xff, NPC_ETYPE_ARP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_ETAG, 0xff, NPC_ETYPE_RARP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_ETAG, 0xff, NPC_ETYPE_PTP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_ETAG, 0xff, NPC_ETYPE_FCOE, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_ETAG, 0xff, NPC_ETYPE_MPLSU, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_ETAG, 0xff, NPC_ETYPE_MPLSM, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_ETAG, 0xff, NPC_ETYPE_NSH, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_ETAG, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ 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, 0x0000,
+ },
+ {
+ NPC_S_KPU2_ETAG, 0xff, NPC_ETYPE_QINQ, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_ETAG, 0xff, NPC_ETYPE_ITAG, 0xffff,
+ 0x0000, 0x0000, NPC_ETYPE_IP, 0xffff,
+ },
+ {
+ NPC_S_KPU2_ETAG, 0xff, NPC_ETYPE_ITAG, 0xffff,
+ 0x0000, 0x0000, NPC_ETYPE_IP6, 0xffff,
+ },
+ {
+ NPC_S_KPU2_ETAG, 0xff, NPC_ETYPE_ITAG, 0xffff,
+ 0x0000, 0x0000, NPC_ETYPE_ARP, 0xffff,
+ },
+ {
+ NPC_S_KPU2_ETAG, 0xff, NPC_ETYPE_ITAG, 0xffff,
+ 0x0000, 0x0000, NPC_ETYPE_SBTAG, 0xffff,
+ },
+ {
+ NPC_S_KPU2_ETAG, 0xff, NPC_ETYPE_ITAG, 0xffff,
+ 0x0000, 0x0000, NPC_ETYPE_CTAG, 0xffff,
+ },
+ {
+ NPC_S_KPU2_ETAG, 0xff, NPC_ETYPE_ITAG, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU2_ETAG, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 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_NA, 0X00, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+};
+
+static struct npc_kpu_profile_cam kpu3_cam_entries[] = {
+ {
+ NPC_S_KPU3_CTAG, 0xff, NPC_ETYPE_IP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_CTAG, 0xff, NPC_ETYPE_IP6, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_CTAG, 0xff, NPC_ETYPE_ARP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_CTAG, 0xff, NPC_ETYPE_RARP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_CTAG, 0xff, NPC_ETYPE_PTP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_CTAG, 0xff, NPC_ETYPE_FCOE, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_CTAG, 0xff, NPC_ETYPE_MPLSU, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_CTAG, 0xff, NPC_ETYPE_MPLSM, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_CTAG, 0xff, NPC_ETYPE_NSH, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_CTAG, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_STAG, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_IP, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_STAG, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_IP6, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_STAG, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_ARP, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_STAG, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_RARP, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_STAG, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_PTP, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_STAG, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_FCOE, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_STAG, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_MPLSU, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_STAG, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_MPLSM, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_STAG, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_NSH, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_STAG, 0xff, NPC_ETYPE_IP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_STAG, 0xff, NPC_ETYPE_IP6, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_STAG, 0xff, NPC_ETYPE_ARP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_STAG, 0xff, NPC_ETYPE_RARP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_STAG, 0xff, NPC_ETYPE_MPLSU, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_STAG, 0xff, NPC_ETYPE_MPLSM, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_STAG, 0xff, NPC_ETYPE_NSH, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_STAG, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_IP, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_IP6, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_ARP, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_RARP, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_PTP, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_FCOE, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_MPLSU, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_MPLSM, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_NSH, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_QINQ, 0xff, NPC_ETYPE_IP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_QINQ, 0xff, NPC_ETYPE_IP6, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_QINQ, 0xff, NPC_ETYPE_ARP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_QINQ, 0xff, NPC_ETYPE_RARP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_QINQ, 0xff, NPC_ETYPE_PTP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_QINQ, 0xff, NPC_ETYPE_FCOE, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_QINQ, 0xff, NPC_ETYPE_MPLSU, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_QINQ, 0xff, NPC_ETYPE_MPLSM, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_QINQ, 0xff, NPC_ETYPE_NSH, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU3_QINQ, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 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_NA, 0X00, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+};
+
+static struct npc_kpu_profile_cam kpu4_cam_entries[] = {
+ {
+ NPC_S_KPU4_MPLS, 0xff, NPC_MPLS_S, NPC_MPLS_S,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU4_MPLS, 0xff, 0x0000, NPC_MPLS_S,
+ NPC_MPLS_S, NPC_MPLS_S, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU4_MPLS, 0xff, 0x0000, NPC_MPLS_S,
+ 0x0000, NPC_MPLS_S, NPC_MPLS_S, NPC_MPLS_S,
+ },
+ {
+ NPC_S_KPU4_MPLS, 0xff, 0x0000, NPC_MPLS_S,
+ 0x0000, NPC_MPLS_S, 0x0000, NPC_MPLS_S,
+ },
+ {
+ NPC_S_KPU4_NSH, 0xff, NPC_NSH_NP_IP, NPC_NSH_NP_MASK,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU4_NSH, 0xff, NPC_NSH_NP_IP6, NPC_NSH_NP_MASK,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU4_NSH, 0xff, NPC_NSH_NP_ETH, NPC_NSH_NP_MASK,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU4_NSH, 0xff, NPC_NSH_NP_NSH, NPC_NSH_NP_MASK,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU4_NSH, 0xff, NPC_NSH_NP_MPLS, NPC_NSH_NP_MASK,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_NA, 0X00, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+};
+
+static 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, 0x0000, 0x0000,
+ },
+ {
+ 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, 0x0000, 0x0000,
+ },
+ {
+ 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, 0x0000, 0x0000,
+ },
+ {
+ 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, 0x0000, 0x0000,
+ },
+ {
+ 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, 0x0000, 0x0000,
+ },
+ {
+ 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, 0x0000, 0x0000,
+ },
+ {
+ 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, 0x0000, 0x0000,
+ },
+ {
+ 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, 0x0000, 0x0000,
+ },
+ {
+ 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, 0x0000, 0x0000,
+ },
+ {
+ 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, 0x0000, 0x0000,
+ },
+ {
+ 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, 0x0000, 0x0000,
+ },
+ {
+ 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, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_IP, 0xff, NPC_IPNH_TCP, 0x00ff,
+ NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_IP, 0xff, NPC_IPNH_UDP, 0x00ff,
+ NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_IP, 0xff, NPC_IPNH_SCTP, 0x00ff,
+ NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_IP, 0xff, NPC_IPNH_ICMP, 0x00ff,
+ NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_IP, 0xff, NPC_IPNH_IGMP, 0x00ff,
+ NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_IP, 0xff, NPC_IPNH_ESP, 0x00ff,
+ NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_IP, 0xff, NPC_IPNH_AH, 0x00ff,
+ NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_IP, 0xff, NPC_IPNH_GRE, 0x00ff,
+ NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_IP, 0xff, NPC_IPNH_IP, 0x00ff,
+ NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_IP, 0xff, NPC_IPNH_IP6, 0x00ff,
+ NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_IP, 0xff, NPC_IPNH_MPLS, 0x00ff,
+ NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_IP, 0xff, 0x0000, 0x0000,
+ NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_IP, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_ARP, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_RARP, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_PTP, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_FCOE, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_IP6, 0xff, NPC_IPNH_TCP << 8, 0xff00,
+ NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_IP6, 0xff, NPC_IPNH_UDP << 8, 0xff00,
+ NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_IP6, 0xff, NPC_IPNH_SCTP << 8, 0xff00,
+ NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_IP6, 0xff, NPC_IPNH_ICMP << 8, 0xff00,
+ NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_IP6, 0xff, NPC_IPNH_ICMP6 << 8, 0xff00,
+ NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_IP6, 0xff, NPC_IPNH_ESP << 8, 0xff00,
+ NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_IP6, 0xff, NPC_IPNH_AH << 8, 0xff00,
+ NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_IP6, 0xff, NPC_IPNH_GRE << 8, 0xff00,
+ NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_IP6, 0xff, NPC_IPNH_IP6 << 8, 0xff00,
+ NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_IP6, 0xff, NPC_IPNH_MPLS << 8, 0xff00,
+ NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_IP6, 0xff, 0x0000, 0x0000,
+ NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_IP6, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_MPLS, 0xff, NPC_MPLS_S, NPC_MPLS_S,
+ NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_MPLS, 0xff, NPC_MPLS_S, NPC_MPLS_S,
+ NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_MPLS, 0xff, NPC_MPLS_S, NPC_MPLS_S,
+ 0x0000, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_MPLS, 0xff, NPC_MPLS_S, NPC_MPLS_S,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_MPLS, 0xff, 0x0000, NPC_MPLS_S,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_MPLS_PL, 0xff, NPC_IP_VER_4, NPC_IP_VER_MASK,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_MPLS_PL, 0xff, NPC_IP_VER_6, NPC_IP_VER_MASK,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_MPLS_PL, 0xff, 0x0000, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_MPLS_PL, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_NSH, 0xff, NPC_NSH_NP_IP, NPC_NSH_NP_MASK,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_NSH, 0xff, NPC_NSH_NP_IP6, NPC_NSH_NP_MASK,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_NSH, 0xff, NPC_NSH_NP_ETH, NPC_NSH_NP_MASK,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_NSH, 0xff, NPC_NSH_NP_NSH, NPC_NSH_NP_MASK,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU5_NSH, 0xff, NPC_NSH_NP_MPLS, NPC_NSH_NP_MASK,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_NA, 0X00, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+};
+
+static struct npc_kpu_profile_cam kpu6_cam_entries[] = {
+ {
+ NPC_S_KPU6_IP6_EXT, 0xff, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000,
+ },
+};
+
+static struct npc_kpu_profile_cam kpu7_cam_entries[] = {
+ {
+ NPC_S_KPU7_IP6_EXT, 0xff, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000,
+ },
+};
+
+static struct npc_kpu_profile_cam kpu8_cam_entries[] = {
+ {
+ NPC_S_KPU8_TCP, 0xff, NPC_TCP_PORT_HTTP, 0xffff,
+ NPC_TCP_DATA_OFFSET_5, NPC_TCP_DATA_OFFSET_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_TCP, 0xff, NPC_TCP_PORT_HTTPS, 0xffff,
+ NPC_TCP_DATA_OFFSET_5, NPC_TCP_DATA_OFFSET_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_TCP, 0xff, NPC_TCP_PORT_PPTP, 0xffff,
+ NPC_TCP_DATA_OFFSET_5, NPC_TCP_DATA_OFFSET_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_TCP, 0xff, 0x0000, 0x0000,
+ NPC_TCP_DATA_OFFSET_5, NPC_TCP_DATA_OFFSET_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_TCP, 0xff, NPC_TCP_PORT_HTTP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_TCP, 0xff, NPC_TCP_PORT_HTTPS, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_TCP, 0xff, NPC_TCP_PORT_PPTP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_TCP, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_VXLAN, 0xffff,
+ NPC_VXLAN_I, NPC_VXLAN_I, 0x0000, 0xffff,
+ },
+ {
+ NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_VXLAN, 0xffff,
+ 0x0000, 0xffff, 0x0000, 0xffff,
+ },
+ {
+ NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_VXLAN, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_VXLANGPE, 0xffff,
+ NPC_VXLANGPE_P | NPC_VXLANGPE_I,
+ NPC_VXLANGPE_P | NPC_VXLANGPE_I,
+ NPC_VXLANGPE_NP_IP, NPC_VXLANGPE_NP_MASK,
+ },
+ {
+ NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_VXLANGPE, 0xffff,
+ NPC_VXLANGPE_P | NPC_VXLANGPE_I,
+ NPC_VXLANGPE_P | NPC_VXLANGPE_I,
+ NPC_VXLANGPE_NP_IP6, NPC_VXLANGPE_NP_MASK,
+ },
+ {
+ NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_VXLANGPE, 0xffff,
+ NPC_VXLANGPE_P | NPC_VXLANGPE_I,
+ NPC_VXLANGPE_P | NPC_VXLANGPE_I,
+ NPC_VXLANGPE_NP_ETH, NPC_VXLANGPE_NP_MASK,
+ },
+ {
+ NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_VXLANGPE, 0xffff,
+ NPC_VXLANGPE_P | NPC_VXLANGPE_I,
+ NPC_VXLANGPE_P | NPC_VXLANGPE_I,
+ NPC_VXLANGPE_NP_NSH, NPC_VXLANGPE_NP_MASK,
+ },
+ {
+ NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_VXLANGPE, 0xffff,
+ NPC_VXLANGPE_P | NPC_VXLANGPE_I,
+ NPC_VXLANGPE_P | NPC_VXLANGPE_I,
+ NPC_VXLANGPE_NP_MPLS, NPC_VXLANGPE_NP_MASK,
+ },
+ {
+ NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_VXLANGPE, 0xffff,
+ NPC_VXLANGPE_P, NPC_VXLANGPE_P | NPC_VXLANGPE_I,
+ NPC_VXLANGPE_NP_IP, NPC_VXLANGPE_NP_MASK,
+ },
+ {
+ NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_VXLANGPE, 0xffff,
+ NPC_VXLANGPE_P, NPC_VXLANGPE_P | NPC_VXLANGPE_I,
+ NPC_VXLANGPE_NP_IP6, NPC_VXLANGPE_NP_MASK,
+ },
+ {
+ NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_VXLANGPE, 0xffff,
+ NPC_VXLANGPE_P, NPC_VXLANGPE_P | NPC_VXLANGPE_I,
+ NPC_VXLANGPE_NP_ETH, NPC_VXLANGPE_NP_MASK,
+ },
+ {
+ NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_VXLANGPE, 0xffff,
+ NPC_VXLANGPE_P, NPC_VXLANGPE_P | NPC_VXLANGPE_I,
+ NPC_VXLANGPE_NP_NSH, NPC_VXLANGPE_NP_MASK,
+ },
+ {
+ NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_VXLANGPE, 0xffff,
+ NPC_VXLANGPE_P, NPC_VXLANGPE_P | NPC_VXLANGPE_I,
+ NPC_VXLANGPE_NP_MPLS, NPC_VXLANGPE_NP_MASK,
+ },
+ {
+ NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_VXLANGPE, 0xffff,
+ NPC_VXLANGPE_P, NPC_VXLANGPE_P, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_VXLANGPE, 0xffff,
+ 0x0000, NPC_VXLANGPE_P, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_GENEVE, 0xffff,
+ 0x0000, NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT,
+ NPC_ETYPE_TRANS_ETH_BR, 0xffff,
+ },
+ {
+ NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_GENEVE, 0xffff,
+ NPC_GENEVE_F_OAM, NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT,
+ NPC_ETYPE_TRANS_ETH_BR, 0xffff,
+ },
+ {
+ NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_GENEVE, 0xffff,
+ NPC_GENEVE_F_CRI_OPT, NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT,
+ NPC_ETYPE_TRANS_ETH_BR, 0xffff,
+ },
+ {
+ NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_GENEVE, 0xffff,
+ NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT,
+ NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT,
+ NPC_ETYPE_TRANS_ETH_BR, 0xffff,
+ },
+ {
+ NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_GENEVE, 0xffff,
+ 0x0000, NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT,
+ NPC_ETYPE_IP, 0xffff,
+ },
+ {
+ NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_GENEVE, 0xffff,
+ NPC_GENEVE_F_OAM, NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT,
+ NPC_ETYPE_IP, 0xffff,
+ },
+ {
+ NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_GENEVE, 0xffff,
+ NPC_GENEVE_F_CRI_OPT, NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT,
+ NPC_ETYPE_IP, 0xffff,
+ },
+ {
+ NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_GENEVE, 0xffff,
+ NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT,
+ NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT, NPC_ETYPE_IP, 0xffff,
+ },
+ {
+ NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_GENEVE, 0xffff,
+ 0x0000, NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT,
+ NPC_ETYPE_IP6, 0xffff,
+ },
+ {
+ NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_GENEVE, 0xffff,
+ NPC_GENEVE_F_OAM, NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT,
+ NPC_ETYPE_IP6, 0xffff,
+ },
+ {
+ NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_GENEVE, 0xffff,
+ NPC_GENEVE_F_CRI_OPT,
+ NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT, NPC_ETYPE_IP6, 0xffff,
+ },
+ {
+ NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_GENEVE, 0xffff,
+ NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT,
+ NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT, NPC_ETYPE_IP6, 0xffff,
+ },
+ {
+ NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_GTPC, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_GTPU, 0xffff,
+ NPC_GTP_PT_GTP | NPC_GTP_VER1 | NPC_GTP_MT_G_PDU,
+ NPC_GTP_PT_MASK | NPC_GTP_VER_MASK | NPC_GTP_MT_MASK,
+ 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_GTPU, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_UDP, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_SCTP, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_ICMP, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_IGMP, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_ICMP6, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_ESP, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_AH, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_TRANS_ETH_BR, 0xffff,
+ NPC_GRE_F_KEY, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_TRANS_ETH_BR, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_MPLSU, 0xffff,
+ 0x0000, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_MPLSU, 0xffff,
+ NPC_GRE_F_CSUM, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_MPLSU, 0xffff,
+ NPC_GRE_F_KEY, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_MPLSU, 0xffff,
+ NPC_GRE_F_SEQ, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_MPLSU, 0xffff,
+ NPC_GRE_F_CSUM | NPC_GRE_F_KEY, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_MPLSU, 0xffff,
+ NPC_GRE_F_CSUM | NPC_GRE_F_SEQ, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_MPLSU, 0xffff,
+ NPC_GRE_F_KEY | NPC_GRE_F_SEQ, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_MPLSU, 0xffff,
+ NPC_GRE_F_CSUM | NPC_GRE_F_KEY | NPC_GRE_F_SEQ,
+ 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_MPLSM, 0xffff,
+ 0x0000, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_MPLSM, 0xffff,
+ NPC_GRE_F_CSUM, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_MPLSM, 0xffff,
+ NPC_GRE_F_KEY, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_MPLSM, 0xffff,
+ NPC_GRE_F_SEQ, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_MPLSM, 0xffff,
+ NPC_GRE_F_CSUM | NPC_GRE_F_KEY, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_MPLSM, 0xffff,
+ NPC_GRE_F_CSUM | NPC_GRE_F_SEQ, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_MPLSM, 0xffff,
+ NPC_GRE_F_KEY | NPC_GRE_F_SEQ, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_MPLSM, 0xffff,
+ NPC_GRE_F_CSUM | NPC_GRE_F_KEY | NPC_GRE_F_SEQ,
+ 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_NSH, 0xffff,
+ 0x0000, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_NSH, 0xffff,
+ NPC_GRE_F_CSUM, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_NSH, 0xffff,
+ NPC_GRE_F_KEY, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_NSH, 0xffff,
+ NPC_GRE_F_SEQ, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_NSH, 0xffff,
+ NPC_GRE_F_CSUM | NPC_GRE_F_KEY, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_NSH, 0xffff,
+ NPC_GRE_F_CSUM | NPC_GRE_F_SEQ, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_NSH, 0xffff,
+ NPC_GRE_F_KEY | NPC_GRE_F_SEQ, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_NSH, 0xffff,
+ NPC_GRE_F_CSUM | NPC_GRE_F_KEY | NPC_GRE_F_SEQ,
+ 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_IP, 0xffff,
+ 0x0000, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_IP, 0xffff,
+ NPC_GRE_F_CSUM, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_IP, 0xffff,
+ NPC_GRE_F_KEY, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_IP, 0xffff,
+ NPC_GRE_F_SEQ, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_IP, 0xffff,
+ NPC_GRE_F_CSUM | NPC_GRE_F_KEY, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_IP, 0xffff,
+ NPC_GRE_F_CSUM | NPC_GRE_F_SEQ, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_IP, 0xffff,
+ NPC_GRE_F_KEY | NPC_GRE_F_SEQ, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_IP, 0xffff,
+ NPC_GRE_F_CSUM | NPC_GRE_F_KEY | NPC_GRE_F_SEQ,
+ 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_IP6, 0xffff,
+ 0x0000, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_IP6, 0xffff,
+ NPC_GRE_F_CSUM, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_IP6, 0xffff,
+ NPC_GRE_F_KEY, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_IP6, 0xffff,
+ NPC_GRE_F_SEQ, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_IP6, 0xffff,
+ NPC_GRE_F_CSUM | NPC_GRE_F_KEY, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_IP6, 0xffff,
+ NPC_GRE_F_CSUM | NPC_GRE_F_SEQ, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_IP6, 0xffff,
+ NPC_GRE_F_KEY | NPC_GRE_F_SEQ, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_IP6, 0xffff,
+ NPC_GRE_F_CSUM | NPC_GRE_F_KEY | NPC_GRE_F_SEQ,
+ 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, 0x0000, 0xffff,
+ NPC_GRE_F_ROUTE, 0x4fff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, 0x0000, 0xffff,
+ 0x0000, 0x4fff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, 0x0000, 0xffff,
+ 0x0000, 0x0003, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_PPP, 0xffff,
+ NPC_GRE_F_KEY | NPC_GRE_VER_1, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_PPP, 0xffff,
+ NPC_GRE_F_KEY | NPC_GRE_F_SEQ | NPC_GRE_VER_1,
+ 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_PPP, 0xffff,
+ NPC_GRE_F_KEY | NPC_GRE_F_ACK | NPC_GRE_VER_1,
+ 0xffff, 0x0000, 0x0000,
+ },
+ {
+ 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,
+ 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, 0x0000, 0xffff,
+ 0x2001, 0xef7f, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU8_GRE, 0xff, 0x0000, 0xffff,
+ 0x0001, 0x0003, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_NA, 0X00, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+};
+
+static struct npc_kpu_profile_cam kpu9_cam_entries[] = {
+ {
+ NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 0xff, NPC_MPLS_S, NPC_MPLS_S,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 0xff, 0x0000, NPC_MPLS_S,
+ NPC_MPLS_S, NPC_MPLS_S, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 0xff, 0x0000, NPC_MPLS_S,
+ 0x0000, NPC_MPLS_S, NPC_MPLS_S, NPC_MPLS_S,
+ },
+ {
+ NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 0xff, 0x0000, NPC_MPLS_S,
+ 0x0000, NPC_MPLS_S, 0x0000, NPC_MPLS_S,
+ },
+ {
+ NPC_S_KPU9_TU_MPLS, 0xff, NPC_MPLS_S, NPC_MPLS_S,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU9_TU_MPLS, 0xff, 0x0000, NPC_MPLS_S,
+ NPC_MPLS_S, NPC_MPLS_S, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU9_TU_MPLS, 0xff, 0x0000, NPC_MPLS_S,
+ 0x0000, NPC_MPLS_S, NPC_MPLS_S, NPC_MPLS_S,
+ },
+ {
+ NPC_S_KPU9_TU_MPLS, 0xff, 0x0000, NPC_MPLS_S,
+ 0x0000, NPC_MPLS_S, 0x0000, NPC_MPLS_S,
+ },
+ {
+ NPC_S_KPU9_TU_NSH, 0xff, NPC_NSH_NP_IP, NPC_NSH_NP_MASK,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU9_TU_NSH, 0xff, NPC_NSH_NP_IP6, NPC_NSH_NP_MASK,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU9_TU_NSH, 0xff, NPC_NSH_NP_ETH, NPC_NSH_NP_MASK,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU9_TU_NSH, 0xff, NPC_NSH_NP_NSH, NPC_NSH_NP_MASK,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU9_TU_NSH, 0xff, NPC_NSH_NP_MPLS, NPC_NSH_NP_MASK,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_NA, 0X00, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+};
+
+static struct npc_kpu_profile_cam kpu10_cam_entries[] = {
+ {
+ NPC_S_KPU10_TU_MPLS, 0xff, NPC_MPLS_S, NPC_MPLS_S,
+ NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU10_TU_MPLS, 0xff, NPC_MPLS_S, NPC_MPLS_S,
+ NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU10_TU_MPLS, 0xff, NPC_MPLS_S, NPC_MPLS_S,
+ 0x0000, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU10_TU_MPLS, 0xff, NPC_MPLS_S, NPC_MPLS_S,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU10_TU_MPLS, 0xff, 0x0000, NPC_MPLS_S,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU10_TU_MPLS_PL, 0xff, NPC_IP_VER_4, NPC_IP_VER_MASK,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU10_TU_MPLS_PL, 0xff, NPC_IP_VER_6, NPC_IP_VER_MASK,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU10_TU_MPLS_PL, 0xff, 0x0000, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU10_TU_MPLS_PL, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU10_TU_NSH, 0xff, NPC_NSH_NP_IP, NPC_NSH_NP_MASK,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU10_TU_NSH, 0xff, NPC_NSH_NP_IP6, NPC_NSH_NP_MASK,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU10_TU_NSH, 0xff, NPC_NSH_NP_ETH, NPC_NSH_NP_MASK,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU10_TU_NSH, 0xff, NPC_NSH_NP_NSH, NPC_NSH_NP_MASK,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU10_TU_NSH, 0xff, NPC_NSH_NP_MPLS, NPC_NSH_NP_MASK,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_NA, 0X00, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+};
+
+static struct npc_kpu_profile_cam kpu11_cam_entries[] = {
+ {
+ NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_IP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_IP6, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_ARP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_IP, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_IP6, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ NPC_ETYPE_ARP, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_CTAG, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_SBTAG, 0xffff,
+ NPC_ETYPE_CTAG, 0xffff, NPC_ETYPE_IP, 0xffff,
+ },
+ {
+ NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_SBTAG, 0xffff,
+ NPC_ETYPE_CTAG, 0xffff, NPC_ETYPE_IP6, 0xffff,
+ },
+ {
+ NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_SBTAG, 0xffff,
+ NPC_ETYPE_CTAG, 0xffff, NPC_ETYPE_ARP, 0xffff,
+ },
+ {
+ NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_SBTAG, 0xffff,
+ NPC_ETYPE_CTAG, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_SBTAG, 0xffff,
+ NPC_ETYPE_IP, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_SBTAG, 0xffff,
+ NPC_ETYPE_IP6, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_SBTAG, 0xffff,
+ NPC_ETYPE_ARP, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_SBTAG, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_QINQ, 0xffff,
+ NPC_ETYPE_CTAG, 0xffff, NPC_ETYPE_IP, 0xffff,
+ },
+ {
+ NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_QINQ, 0xffff,
+ NPC_ETYPE_CTAG, 0xffff, NPC_ETYPE_IP6, 0xffff,
+ },
+ {
+ NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_QINQ, 0xffff,
+ NPC_ETYPE_CTAG, 0xffff, NPC_ETYPE_ARP, 0xffff,
+ },
+ {
+ NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_QINQ, 0xffff,
+ NPC_ETYPE_CTAG, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_QINQ, 0xffff,
+ NPC_ETYPE_IP, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_QINQ, 0xffff,
+ NPC_ETYPE_IP6, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_QINQ, 0xffff,
+ NPC_ETYPE_ARP, 0xffff, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_QINQ, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU11_TU_ETHER, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU11_TU_PPP, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU11_TU_MPLS_IN_NSH, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU11_TU_3RD_NSH, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_NA, 0X00, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+};
+
+static struct npc_kpu_profile_cam kpu12_cam_entries[] = {
+ {
+ 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, 0x0000, 0x0000,
+ },
+ {
+ 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, 0x0000, 0x0000,
+ },
+ {
+ 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, 0x0000, 0x0000,
+ },
+ {
+ 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, 0x0000, 0x0000,
+ },
+ {
+ 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, 0x0000, 0x0000,
+ },
+ {
+ 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, 0x0000, 0x0000,
+ },
+ {
+ 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, 0x0000, 0x0000,
+ },
+ {
+ 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, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU12_TU_IP, 0xff, NPC_IPNH_TCP, 0x00ff,
+ NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU12_TU_IP, 0xff, NPC_IPNH_UDP, 0x00ff,
+ NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU12_TU_IP, 0xff, NPC_IPNH_SCTP, 0x00ff,
+ NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU12_TU_IP, 0xff, NPC_IPNH_ICMP, 0x00ff,
+ NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU12_TU_IP, 0xff, NPC_IPNH_IGMP, 0x00ff,
+ NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU12_TU_IP, 0xff, NPC_IPNH_ESP, 0x00ff,
+ NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU12_TU_IP, 0xff, NPC_IPNH_AH, 0x00ff,
+ NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU12_TU_IP, 0xff, 0x0000, 0x0000,
+ NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU12_TU_IP, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU12_TU_ARP, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU12_TU_IP6, 0xff, NPC_IPNH_TCP << 8, 0xff00,
+ NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU12_TU_IP6, 0xff, NPC_IPNH_UDP << 8, 0xff00,
+ NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU12_TU_IP6, 0xff, NPC_IPNH_SCTP << 8, 0xff00,
+ NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU12_TU_IP6, 0xff, NPC_IPNH_ICMP << 8, 0xff00,
+ NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU12_TU_IP6, 0xff, NPC_IPNH_ICMP6 << 8, 0xff00,
+ NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU12_TU_IP6, 0xff, NPC_IPNH_ESP << 8, 0xff00,
+ NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU12_TU_IP6, 0xff, NPC_IPNH_AH << 8, 0xff00,
+ NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU12_TU_IP6, 0xff, 0x0000, 0x0000,
+ NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU12_TU_IP6, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_NA, 0X00, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+};
+
+static struct npc_kpu_profile_cam kpu13_cam_entries[] = {
+ {
+ NPC_S_KPU13_TU_IP6_EXT, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+};
+
+static struct npc_kpu_profile_cam kpu14_cam_entries[] = {
+ {
+ NPC_S_KPU14_TU_IP6_EXT, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+};
+
+static struct npc_kpu_profile_cam kpu15_cam_entries[] = {
+ {
+ NPC_S_KPU15_TU_TCP, 0xff, NPC_TCP_PORT_HTTP, 0xffff,
+ NPC_TCP_DATA_OFFSET_5, NPC_TCP_DATA_OFFSET_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU15_TU_TCP, 0xff, NPC_TCP_PORT_HTTPS, 0xffff,
+ NPC_TCP_DATA_OFFSET_5, NPC_TCP_DATA_OFFSET_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU15_TU_TCP, 0xff, NPC_TCP_PORT_PPTP, 0xffff,
+ NPC_TCP_DATA_OFFSET_5, NPC_TCP_DATA_OFFSET_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU15_TU_TCP, 0xff, 0x0000, 0x0000,
+ NPC_TCP_DATA_OFFSET_5, NPC_TCP_DATA_OFFSET_MASK, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU15_TU_TCP, 0xff, NPC_TCP_PORT_HTTP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU15_TU_TCP, 0xff, NPC_TCP_PORT_HTTPS, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU15_TU_TCP, 0xff, NPC_TCP_PORT_PPTP, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU15_TU_TCP, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU15_TU_UDP, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU15_TU_SCTP, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU15_TU_ICMP, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU15_TU_IGMP, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU15_TU_ICMP6, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU15_TU_ESP, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU15_TU_AH, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_NA, 0X00, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+};
+
+static struct npc_kpu_profile_cam kpu16_cam_entries[] = {
+ {
+ NPC_S_KPU16_TCP_DATA, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU16_HTTP_DATA, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU16_HTTPS_DATA, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU16_PPTP_DATA, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+ {
+ NPC_S_KPU16_UDP_DATA, 0xff, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ },
+};
+
+static struct npc_kpu_profile_action kpu1_action_entries[] = {
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 3, 0, NPC_S_KPU5_IP, 14, 1,
+ NPC_LID_LA, NPC_LT_LA_ETHER, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 3, 0, NPC_S_KPU5_IP6, 14, 1,
+ NPC_LID_LA, NPC_LT_LA_ETHER, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 3, 0, NPC_S_KPU5_ARP, 14, 1,
+ NPC_LID_LA, NPC_LT_LA_ETHER, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 3, 0, NPC_S_KPU5_RARP, 14, 1,
+ NPC_LID_LA, NPC_LT_LA_ETHER, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 3, 0, NPC_S_KPU5_PTP, 14, 1,
+ NPC_LID_LA, NPC_LT_LA_ETHER, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 3, 0, NPC_S_KPU5_FCOE, 14, 1,
+ NPC_LID_LA, NPC_LT_LA_ETHER, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 0,
+ 0, 0, NPC_S_KPU2_CTAG, 14, 1,
+ NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_ETHER_VLAN, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 20,
+ 0, 0, NPC_S_KPU2_SBTAG, 14, 1,
+ NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_ETHER_VLAN, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 0,
+ 0, 0, NPC_S_KPU2_QINQ, 14, 1,
+ NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_ETHER_VLAN, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 10, 24,
+ 0, 0, NPC_S_KPU2_ETAG, 14, 1,
+ NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_ETHER_ETAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 16, 20, 24,
+ 0, 0, NPC_S_KPU2_ITAG, 14, 1,
+ NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_ETHER_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, NPC_F_ETHER_MPLS, 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, NPC_F_ETHER_MPLS, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0,
+ 2, 0, NPC_S_KPU4_NSH, 14, 1,
+ NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_ETHER_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_8023, 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, 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_ETHER, NPC_F_ETYPE_UNK, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 3, 0, NPC_S_KPU5_IP, 14, 1,
+ NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_PKI, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 3, 0, NPC_S_KPU5_IP6, 14, 1,
+ NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_PKI, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 3, 0, NPC_S_KPU5_ARP, 14, 1,
+ NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_PKI, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 3, 0, NPC_S_KPU5_RARP, 14, 1,
+ NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_PKI, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 3, 0, NPC_S_KPU5_PTP, 14, 1,
+ NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_PKI, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 3, 0, NPC_S_KPU5_FCOE, 14, 1,
+ NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_PKI, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 0,
+ 0, 0, NPC_S_KPU2_CTAG, 14, 1,
+ NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_PKI_VLAN, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 20,
+ 0, 0, NPC_S_KPU2_SBTAG, 14, 1,
+ NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_PKI_VLAN, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 0,
+ 0, 0, NPC_S_KPU2_QINQ, 14, 1,
+ NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_PKI_VLAN, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 10, 24,
+ 0, 0, NPC_S_KPU2_ETAG, 14, 1,
+ NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_PKI_ETAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 16, 20, 24,
+ 0, 0, NPC_S_KPU2_ITAG, 14, 1,
+ NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_PKI_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, NPC_F_PKI_MPLS, 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, NPC_F_PKI_MPLS, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 2, 0, NPC_S_KPU4_NSH, 14, 1,
+ NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_PKI_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_ETHER, NPC_F_ETYPE_UNK, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_LA, NPC_EC_L2_K1, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 0,
+ NPC_LID_LA, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+};
+
+static struct npc_kpu_profile_action kpu2_action_entries[] = {
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 2, 0, NPC_S_KPU5_IP, 4, 1,
+ NPC_LID_LB, NPC_LT_LB_CTAG, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 2, 0, NPC_S_KPU5_IP6, 4, 1,
+ NPC_LID_LB, NPC_LT_LB_CTAG, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU5_ARP, 4, 1,
+ NPC_LID_LB, NPC_LT_LB_CTAG, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU5_RARP, 4, 1,
+ NPC_LID_LB, NPC_LT_LB_CTAG, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU5_PTP, 4, 1,
+ NPC_LID_LB, NPC_LT_LB_CTAG, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU5_FCOE, 4, 1,
+ NPC_LID_LB, NPC_LT_LB_CTAG, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 1, 0, NPC_S_KPU4_MPLS, 4, 1,
+ NPC_LID_LB, NPC_LT_LB_CTAG, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 1, 0, NPC_S_KPU4_MPLS, 4, 1,
+ NPC_LID_LB, NPC_LT_LB_CTAG, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0,
+ 1, 0, NPC_S_KPU4_NSH, 4, 1,
+ NPC_LID_LB, NPC_LT_LB_CTAG, 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, NPC_F_ETYPE_UNK, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 2, 0, NPC_S_KPU5_IP, 8, 1,
+ NPC_LID_LB, NPC_LT_LB_STAG, NPC_F_STAG_CTAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 2, 0, NPC_S_KPU5_IP6, 8, 1,
+ NPC_LID_LB, NPC_LT_LB_STAG, NPC_F_STAG_CTAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU5_ARP, 8, 1,
+ NPC_LID_LB, NPC_LT_LB_STAG, NPC_F_STAG_CTAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU5_RARP, 8, 1,
+ NPC_LID_LB, NPC_LT_LB_STAG, NPC_F_STAG_CTAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU5_PTP, 8, 1,
+ NPC_LID_LB, NPC_LT_LB_STAG, NPC_F_STAG_CTAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU5_FCOE, 8, 1,
+ NPC_LID_LB, NPC_LT_LB_STAG, NPC_F_STAG_CTAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 1, 0, NPC_S_KPU4_MPLS, 8, 1,
+ NPC_LID_LB, NPC_LT_LB_STAG, NPC_F_STAG_CTAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 1, 0, NPC_S_KPU4_MPLS, 8, 1,
+ NPC_LID_LB, NPC_LT_LB_STAG, NPC_F_STAG_CTAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0,
+ 1, 0, NPC_S_KPU4_NSH, 8, 1,
+ NPC_LID_LB, NPC_LT_LB_STAG, NPC_F_STAG_CTAG, 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_STAG, NPC_F_STAG_CTAG_UNK, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 0,
+ 0, 0, NPC_S_KPU3_CTAG, 8, 1,
+ NPC_LID_LB, NPC_LT_LB_STAG, NPC_F_STAG_STAG_CTAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 0,
+ 0, 0, NPC_S_KPU3_STAG, 8, 1,
+ NPC_LID_LB, NPC_LT_LB_STAG, NPC_F_STAG_STAG_STAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 2, 0, NPC_S_KPU5_IP, 22, 1,
+ NPC_LID_LB, NPC_LT_LB_BTAG, NPC_F_BTAG_ITAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 2, 0, NPC_S_KPU5_IP6, 22, 1,
+ NPC_LID_LB, NPC_LT_LB_BTAG, NPC_F_BTAG_ITAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU5_ARP, 22, 1,
+ NPC_LID_LB, NPC_LT_LB_BTAG, NPC_F_BTAG_ITAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU5_RARP, 22, 1,
+ NPC_LID_LB, NPC_LT_LB_BTAG, NPC_F_BTAG_ITAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU5_PTP, 22, 1,
+ NPC_LID_LB, NPC_LT_LB_BTAG, NPC_F_BTAG_ITAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU5_FCOE, 22, 1,
+ NPC_LID_LB, NPC_LT_LB_BTAG, NPC_F_BTAG_ITAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 1, 0, NPC_S_KPU4_MPLS, 22, 1,
+ NPC_LID_LB, NPC_LT_LB_BTAG, NPC_F_BTAG_ITAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 1, 0, NPC_S_KPU4_MPLS, 22, 1,
+ NPC_LID_LB, NPC_LT_LB_BTAG, NPC_F_BTAG_ITAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0,
+ 1, 0, NPC_S_KPU4_NSH, 22, 1,
+ NPC_LID_LB, NPC_LT_LB_BTAG, NPC_F_BTAG_ITAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0,
+ 0, 0, NPC_S_KPU3_STAG, 22, 1,
+ NPC_LID_LB, NPC_LT_LB_BTAG, NPC_F_BTAG_ITAG_STAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0,
+ 0, 0, NPC_S_KPU3_CTAG, 22, 1,
+ NPC_LID_LB, NPC_LT_LB_BTAG, NPC_F_BTAG_ITAG_CTAG, 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_BTAG, NPC_F_BTAG_ITAG_UNK, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 2, 0, NPC_S_KPU5_IP, 4, 1,
+ NPC_LID_LB, NPC_LT_LB_STAG, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 2, 0, NPC_S_KPU5_IP6, 4, 1,
+ NPC_LID_LB, NPC_LT_LB_STAG, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU5_ARP, 4, 1,
+ NPC_LID_LB, NPC_LT_LB_STAG, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU5_RARP, 4, 1,
+ NPC_LID_LB, NPC_LT_LB_STAG, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU5_PTP, 4, 1,
+ NPC_LID_LB, NPC_LT_LB_STAG, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU5_FCOE, 4, 1,
+ NPC_LID_LB, NPC_LT_LB_STAG, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 1, 0, NPC_S_KPU4_MPLS, 4, 1,
+ NPC_LID_LB, NPC_LT_LB_STAG, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 1, 0, NPC_S_KPU4_MPLS, 4, 1,
+ NPC_LID_LB, NPC_LT_LB_STAG, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0,
+ 1, 0, NPC_S_KPU4_NSH, 4, 1,
+ NPC_LID_LB, NPC_LT_LB_STAG, 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_STAG, NPC_F_ETYPE_UNK, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 2, 0, NPC_S_KPU5_IP, 8, 1,
+ NPC_LID_LB, NPC_LT_LB_QINQ, NPC_F_QINQ_CTAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 2, 0, NPC_S_KPU5_IP6, 8, 1,
+ NPC_LID_LB, NPC_LT_LB_QINQ, NPC_F_QINQ_CTAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU5_ARP, 8, 1,
+ NPC_LID_LB, NPC_LT_LB_QINQ, NPC_F_QINQ_CTAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU5_RARP, 8, 1,
+ NPC_LID_LB, NPC_LT_LB_QINQ, NPC_F_QINQ_CTAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU5_PTP, 8, 1,
+ NPC_LID_LB, NPC_LT_LB_QINQ, NPC_F_QINQ_CTAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU5_FCOE, 8, 1,
+ NPC_LID_LB, NPC_LT_LB_QINQ, NPC_F_QINQ_CTAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 1, 0, NPC_S_KPU4_MPLS, 8, 1,
+ NPC_LID_LB, NPC_LT_LB_QINQ, NPC_F_QINQ_CTAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 1, 0, NPC_S_KPU4_MPLS, 8, 1,
+ NPC_LID_LB, NPC_LT_LB_QINQ, NPC_F_QINQ_CTAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0,
+ 1, 0, NPC_S_KPU4_NSH, 8, 1,
+ NPC_LID_LB, NPC_LT_LB_QINQ, NPC_F_QINQ_CTAG, 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_QINQ, NPC_F_QINQ_CTAG_UNK, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 0,
+ 0, 0, NPC_S_KPU3_CTAG, 8, 1,
+ NPC_LID_LB, NPC_LT_LB_QINQ, NPC_F_QINQ_QINQ_CTAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 0,
+ 0, 0, NPC_S_KPU3_QINQ, 8, 1,
+ NPC_LID_LB, NPC_LT_LB_QINQ, NPC_F_QINQ_QINQ_QINQ, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 2, 0, NPC_S_KPU5_IP, 4, 1,
+ NPC_LID_LB, NPC_LT_LB_QINQ, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 2, 0, NPC_S_KPU5_IP6, 4, 1,
+ NPC_LID_LB, NPC_LT_LB_QINQ, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU5_ARP, 4, 1,
+ NPC_LID_LB, NPC_LT_LB_QINQ, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU5_RARP, 4, 1,
+ NPC_LID_LB, NPC_LT_LB_QINQ, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU5_PTP, 4, 1,
+ NPC_LID_LB, NPC_LT_LB_QINQ, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU5_FCOE, 4, 1,
+ NPC_LID_LB, NPC_LT_LB_QINQ, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 1, 0, NPC_S_KPU4_MPLS, 4, 1,
+ NPC_LID_LB, NPC_LT_LB_QINQ, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 1, 0, NPC_S_KPU4_MPLS, 4, 1,
+ NPC_LID_LB, NPC_LT_LB_QINQ, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0,
+ 1, 0, NPC_S_KPU4_NSH, 4, 1,
+ NPC_LID_LB, NPC_LT_LB_QINQ, 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_QINQ, NPC_F_ETYPE_UNK, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 2, 0, NPC_S_KPU5_IP, 8, 1,
+ NPC_LID_LB, NPC_LT_LB_ETAG, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 2, 0, NPC_S_KPU5_IP6, 8, 1,
+ NPC_LID_LB, NPC_LT_LB_ETAG, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU5_ARP, 8, 1,
+ NPC_LID_LB, NPC_LT_LB_ETAG, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU5_RARP, 8, 1,
+ NPC_LID_LB, NPC_LT_LB_ETAG, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU5_PTP, 8, 1,
+ NPC_LID_LB, NPC_LT_LB_ETAG, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU5_FCOE, 8, 1,
+ NPC_LID_LB, NPC_LT_LB_ETAG, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 1, 0, NPC_S_KPU4_MPLS, 8, 1,
+ NPC_LID_LB, NPC_LT_LB_ETAG, 1, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 1, 0, NPC_S_KPU4_MPLS, 8, 1,
+ NPC_LID_LB, NPC_LT_LB_ETAG, 2, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 1, 0, NPC_S_KPU4_NSH, 8, 1,
+ NPC_LID_LB, NPC_LT_LB_ETAG, 2, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0,
+ 0, 0, NPC_S_KPU3_CTAG, 8, 1,
+ NPC_LID_LB, NPC_LT_LB_ETAG, NPC_F_ETAG_CTAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 16, 20, 24,
+ 0, 0, NPC_S_KPU3_ITAG, 12, 1,
+ NPC_LID_LB, NPC_LT_LB_ETAG, NPC_F_ETAG_BTAG_ITAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 0,
+ 0, 0, NPC_S_KPU3_STAG, 8, 1,
+ NPC_LID_LB, NPC_LT_LB_ETAG, NPC_F_ETAG_STAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 0,
+ 0, 0, NPC_S_KPU3_QINQ, 8, 1,
+ NPC_LID_LB, NPC_LT_LB_ETAG, NPC_F_ETAG_QINQ, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 2, 0, NPC_S_KPU5_IP, 26, 1,
+ NPC_LID_LB, NPC_LT_LB_ETAG, NPC_F_ETAG_ITAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 2, 0, NPC_S_KPU5_IP6, 26, 1,
+ NPC_LID_LB, NPC_LT_LB_ETAG, NPC_F_ETAG_ITAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU5_ARP, 26, 1,
+ NPC_LID_LB, NPC_LT_LB_ETAG, NPC_F_ETAG_ITAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0,
+ 0, 0, NPC_S_KPU3_STAG, 26, 1,
+ NPC_LID_LB, NPC_LT_LB_ETAG, NPC_F_ETAG_ITAG_STAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0,
+ 0, 0, NPC_S_KPU3_CTAG, 26, 1,
+ NPC_LID_LB, NPC_LT_LB_ETAG, NPC_F_ETAG_ITAG_CTAG, 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_ETAG, NPC_F_ETAG_ITAG_UNK, 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_ETAG, NPC_F_ETYPE_UNK, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 2, 0, NPC_S_KPU5_IP, 18, 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, 18, 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, 18, 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, 18, 1,
+ NPC_LID_LB, NPC_LT_LB_ITAG, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 2, 0, NPC_S_KPU5_IP, 26, 1,
+ NPC_LID_LB, NPC_LT_LB_ITAG, NPC_F_ITAG_STAG_CTAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 2, 0, NPC_S_KPU5_IP6, 26, 1,
+ NPC_LID_LB, NPC_LT_LB_ITAG, NPC_F_ITAG_STAG_CTAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU5_ARP, 26, 1,
+ NPC_LID_LB, NPC_LT_LB_ITAG, NPC_F_ITAG_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, 0,
+ 2, 0, NPC_S_KPU5_IP, 22, 1,
+ NPC_LID_LB, NPC_LT_LB_ITAG, NPC_F_ITAG_STAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 2, 0, NPC_S_KPU5_IP6, 22, 1,
+ NPC_LID_LB, NPC_LT_LB_ITAG, NPC_F_ITAG_STAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU5_ARP, 22, 1,
+ NPC_LID_LB, NPC_LT_LB_ITAG, NPC_F_ITAG_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, 0,
+ 2, 0, NPC_S_KPU5_IP, 22, 1,
+ NPC_LID_LB, NPC_LT_LB_ITAG, NPC_F_ITAG_CTAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 2, 0, NPC_S_KPU5_IP6, 22, 1,
+ NPC_LID_LB, NPC_LT_LB_ITAG, NPC_F_ITAG_CTAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU5_ARP, 22, 1,
+ NPC_LID_LB, NPC_LT_LB_ITAG, NPC_F_ITAG_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_LB, NPC_EC_L2_K3, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 0,
+ NPC_LID_LB, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+};
+
+static struct npc_kpu_profile_action kpu3_action_entries[] = {
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 1, 0, NPC_S_KPU5_IP, 4, 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, 4, 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, 4, 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_RARP, 4, 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_PTP, 4, 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_FCOE, 4, 0,
+ NPC_LID_LB, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 0, 0, NPC_S_KPU4_MPLS, 4, 0,
+ NPC_LID_LB, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 0, 0, NPC_S_KPU4_MPLS, 4, 0,
+ NPC_LID_LB, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0,
+ 0, 0, NPC_S_KPU4_NSH, 4, 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, 0,
+ 1, 0, NPC_S_KPU5_IP, 8, 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, 8, 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, 8, 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_RARP, 8, 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_PTP, 8, 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_FCOE, 8, 0,
+ NPC_LID_LB, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 0, 0, NPC_S_KPU4_MPLS, 8, 0,
+ NPC_LID_LB, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 0, 0, NPC_S_KPU4_MPLS, 8, 0,
+ NPC_LID_LB, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0,
+ 0, 0, NPC_S_KPU4_NSH, 8, 0,
+ NPC_LID_LB, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 1, 0, NPC_S_KPU5_IP, 4, 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, 4, 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, 4, 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_RARP, 4, 0,
+ NPC_LID_LB, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 0, 0, NPC_S_KPU4_MPLS, 4, 0,
+ NPC_LID_LB, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 0, 0, NPC_S_KPU4_MPLS, 4, 0,
+ NPC_LID_LB, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0,
+ 0, 0, NPC_S_KPU4_NSH, 4, 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, 0,
+ 1, 0, NPC_S_KPU5_IP, 8, 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, 8, 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, 8, 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_RARP, 8, 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_PTP, 8, 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_FCOE, 8, 0,
+ NPC_LID_LB, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 0, 0, NPC_S_KPU4_MPLS, 8, 0,
+ NPC_LID_LB, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 0, 0, NPC_S_KPU4_MPLS, 8, 0,
+ NPC_LID_LB, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0,
+ 0, 0, NPC_S_KPU4_NSH, 8, 0,
+ NPC_LID_LB, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 1, 0, NPC_S_KPU5_IP, 4, 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, 4, 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, 4, 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_RARP, 4, 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_PTP, 4, 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_FCOE, 4, 0,
+ NPC_LID_LB, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 0, 0, NPC_S_KPU4_MPLS, 4, 0,
+ NPC_LID_LB, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 0, 0, NPC_S_KPU4_MPLS, 4, 0,
+ NPC_LID_LB, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0,
+ 0, 0, NPC_S_KPU4_NSH, 4, 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, 0,
+ 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, 0,
+ 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, 0,
+ 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, 0,
+ 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_LB, NPC_EC_L2_K3, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 0,
+ NPC_LID_LB, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+};
+
+static struct npc_kpu_profile_action kpu4_action_entries[] = {
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 0, NPC_S_KPU5_MPLS_PL, 4, 1,
+ NPC_LID_LC, NPC_LT_LC_MPLS, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 0, NPC_S_KPU5_MPLS_PL, 8, 1,
+ NPC_LID_LC, NPC_LT_LC_MPLS, NPC_F_MPLS_2_LABELS, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 0, NPC_S_KPU5_MPLS_PL, 12, 1,
+ NPC_LID_LC, NPC_LT_LC_MPLS, NPC_F_MPLS_3_LABELS, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 4, 0,
+ 0, 0, NPC_S_KPU5_MPLS, 12, 1,
+ NPC_LID_LC, NPC_LT_LC_MPLS, NPC_F_MPLS_4_LABELS, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 7, 0, NPC_S_KPU12_TU_IP, 0, 1,
+ NPC_LID_LC, NPC_LT_LC_NSH, 0, 1, 0x3f,
+ 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 7, 0, NPC_S_KPU12_TU_IP6, 0, 1,
+ NPC_LID_LC, NPC_LT_LC_NSH, 0, 1, 0x3f,
+ 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20,
+ 6, 0, NPC_S_KPU11_TU_ETHER, 0, 1,
+ NPC_LID_LC, NPC_LT_LC_NSH, 0, 1, 0x3f,
+ 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0,
+ 0, 0, NPC_S_KPU5_NSH, 0, 1,
+ NPC_LID_LC, NPC_LT_LC_NSH, 0, 1, 0x3f,
+ 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 4, 0, NPC_S_KPU9_TU_MPLS, 0, 1,
+ NPC_LID_LC, NPC_LT_LC_NSH, 0, 1, 0x3f,
+ 0, 2,
+ },
+ {
+ NPC_ERRLEV_LB, NPC_EC_L2_K4, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 0,
+ NPC_LID_LC, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+};
+
+static struct npc_kpu_profile_action kpu5_action_entries[] = {
+ {
+ 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, 8, 10,
+ 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,
+ 0, 0, NPC_S_KPU8_ESP, 20, 1,
+ NPC_LID_LC, NPC_LT_LC_IP, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 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, 0,
+ 6, 0, NPC_S_KPU12_TU_IP, 20, 1,
+ NPC_LID_LC, NPC_LT_LC_IP, NPC_F_IP_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_IP_6TO4, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 3, 0, NPC_S_KPU9_TU_MPLS, 20, 1,
+ NPC_LID_LC, NPC_LT_LC_IP, NPC_F_IP_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_IP_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, NPC_F_IP_HAS_OPTIONS, 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, NPC_F_IP_HAS_OPTIONS, 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, NPC_F_IP_HAS_OPTIONS, 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, NPC_F_IP_HAS_OPTIONS, 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, NPC_F_IP_HAS_OPTIONS, 0, 0xf,
+ 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 0, NPC_S_KPU8_ESP, 0, 1,
+ NPC_LID_LC, NPC_LT_LC_IP, NPC_F_IP_HAS_OPTIONS, 0, 0xf,
+ 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 0, NPC_S_KPU8_AH, 0, 1,
+ NPC_LID_LC, NPC_LT_LC_IP, NPC_F_IP_HAS_OPTIONS, 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, NPC_F_IP_HAS_OPTIONS, 0, 0xf,
+ 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 6, 0, NPC_S_KPU12_TU_IP, 0, 1,
+ NPC_LID_LC, NPC_LT_LC_IP, NPC_F_IP_IP_IN_IP_HAS_OPTIONS, 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, NPC_F_IP_6TO4_HAS_OPTIONS, 0, 0xf,
+ 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 3, 0, NPC_S_KPU9_TU_MPLS, 20, 1,
+ NPC_LID_LC, NPC_LT_LC_IP, NPC_F_IP_MPLS_IN_IP_HAS_OPTIONS,
+ 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, NPC_F_IP_UNK_PROTO_HAS_OPTIONS, 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_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LC, NPC_LT_LC_ARP, 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_RARP, 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_PTP, 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_FCOE, 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, 8, 10,
+ 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_ESP, 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_AH, 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_IP6_TUN_IP6, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 3, 0, NPC_S_KPU9_TU_MPLS, 40, 1,
+ NPC_LID_LC, NPC_LT_LC_IP6, NPC_F_IP6_MPLS_IN_IP, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0,
+ 0, 0, NPC_S_KPU6_IP6_EXT, 0, 1,
+ NPC_LID_LC, NPC_LT_LC_IP6, NPC_F_IP6_HAS_EXT, 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_RE, NPC_EC_NOERR, 8, 0, 0,
+ 6, 0, NPC_S_KPU12_TU_IP, 4, 0,
+ NPC_LID_LB, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 6, 0, NPC_S_KPU12_TU_IP6, 4, 0,
+ NPC_LID_LB, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20,
+ 5, 0, NPC_S_KPU11_TU_ETHER, 8, 0,
+ NPC_LID_LB, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20,
+ 5, 0, NPC_S_KPU11_TU_ETHER, 4, 0,
+ NPC_LID_LB, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_LB, NPC_EC_L2_MPLS_2MANY, 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, 0,
+ 6, 0, NPC_S_KPU12_TU_IP, 0, 0,
+ NPC_LID_LB, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 6, 0, NPC_S_KPU12_TU_IP6, 0, 0,
+ NPC_LID_LB, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20,
+ 5, 0, NPC_S_KPU11_TU_ETHER, 4, 0,
+ NPC_LID_LB, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20,
+ 5, 0, NPC_S_KPU11_TU_ETHER, 0, 0,
+ NPC_LID_LB, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 6, 0, NPC_S_KPU12_TU_IP, 0, 0,
+ NPC_LID_LD, NPC_LT_NA, 0, 1, 0x3f,
+ 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 6, 0, NPC_S_KPU12_TU_IP6, 0, 0,
+ NPC_LID_LD, NPC_LT_NA, 0, 1, 0x3f,
+ 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20,
+ 5, 0, NPC_S_KPU11_TU_ETHER, 0, 0,
+ NPC_LID_LD, NPC_LT_NA, 0, 1, 0x3f,
+ 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0,
+ 5, 0, NPC_S_KPU11_TU_3RD_NSH, 0, 0,
+ NPC_LID_LD, NPC_LT_NA, 0, 1, 0x3f,
+ 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 3, 0, NPC_S_KPU9_TU_MPLS, 0, 0,
+ NPC_LID_LD, NPC_LT_NA, 0, 1, 0x3f,
+ 0, 2,
+ },
+ {
+ NPC_ERRLEV_LC, NPC_EC_UNK, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 0,
+ NPC_LID_LC, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+};
+
+static struct npc_kpu_profile_action kpu6_action_entries[] = {
+ {
+ 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,
+ },
+};
+
+static struct npc_kpu_profile_action kpu7_action_entries[] = {
+ {
+ 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,
+ },
+};
+
+static struct npc_kpu_profile_action kpu8_action_entries[] = {
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 7, 0, NPC_S_KPU16_HTTP_DATA, 20, 1,
+ NPC_LID_LD, NPC_LT_LD_TCP, NPC_F_TCP_HTTP, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 7, 0, NPC_S_KPU16_HTTPS_DATA, 20, 1,
+ NPC_LID_LD, NPC_LT_LD_TCP, NPC_F_TCP_HTTPS, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 7, 0, NPC_S_KPU16_PPTP_DATA, 20, 1,
+ NPC_LID_LD, NPC_LT_LD_TCP, NPC_F_TCP_PPTP, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 7, 0, NPC_S_KPU16_TCP_DATA, 20, 1,
+ NPC_LID_LD, NPC_LT_LD_TCP, NPC_F_TCP_UNK_PORT, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 7, 0, NPC_S_KPU16_HTTP_DATA, 0, 1,
+ NPC_LID_LD, NPC_LT_LD_TCP, NPC_F_TCP_HTTP_HAS_OPTIONS,
+ 12, 0xf0, 1, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 7, 0, NPC_S_KPU16_HTTPS_DATA, 0, 1,
+ NPC_LID_LD, NPC_LT_LD_TCP, NPC_F_TCP_HTTPS_HAS_OPTIONS,
+ 12, 0xf0, 1, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 7, 0, NPC_S_KPU16_PPTP_DATA, 0, 1,
+ NPC_LID_LD, NPC_LT_LD_TCP, NPC_F_TCP_PPTP_HAS_OPTIONS,
+ 12, 0xf0, 1, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 7, 0, NPC_S_KPU16_TCP_DATA, 0, 1,
+ NPC_LID_LD, NPC_LT_LD_TCP, NPC_F_TCP_UNK_PORT_HAS_OPTIONS,
+ 12, 0xf0, 1, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20,
+ 2, 0, NPC_S_KPU11_TU_ETHER, 16, 1,
+ NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_VXLAN, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20,
+ 2, 0, NPC_S_KPU11_TU_ETHER, 16, 1,
+ NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_VXLAN_NOVNI, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_LD, NPC_EC_VXLAN, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 0,
+ NPC_LID_LD, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 3, 0, NPC_S_KPU12_TU_IP, 16, 1,
+ NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_VXLANGPE, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 3, 0, NPC_S_KPU12_TU_IP6, 16, 1,
+ NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_VXLANGPE, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20,
+ 2, 0, NPC_S_KPU11_TU_ETHER, 16, 1,
+ NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_VXLANGPE, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0,
+ 0, 0, NPC_S_KPU9_TU_NSH, 16, 1,
+ NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_VXLANGPE_NSH, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 0, 0, NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 16, 1,
+ NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_VXLANGPE_MPLS, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 3, 0, NPC_S_KPU12_TU_IP, 16, 1,
+ NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_VXLANGPE_NOVNI, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 3, 0, NPC_S_KPU12_TU_IP6, 16, 1,
+ NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_VXLANGPE_NOVNI, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20,
+ 2, 0, NPC_S_KPU11_TU_ETHER, 16, 1,
+ NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_VXLANGPE_NOVNI, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0,
+ 0, 0, NPC_S_KPU9_TU_NSH, 16, 1,
+ NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_VXLANGPE_NOVNI_NSH, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 0, 0, NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 16, 1,
+ NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_VXLANGPE_NOVNI_MPLS, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_VXLANGPE_UNK, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_VXLANGPE_NONP, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20,
+ 2, 0, NPC_S_KPU11_TU_ETHER, 16, 1,
+ NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_GENEVE, 8, 0x3f,
+ 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20,
+ 2, 0, NPC_S_KPU11_TU_ETHER, 16, 1,
+ NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_GENEVE_OAM, 8, 0x3f,
+ 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20,
+ 2, 0, NPC_S_KPU11_TU_ETHER, 16, 1,
+ NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_GENEVE_CRI_OPT, 8, 0x3f,
+ 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20,
+ 2, 0, NPC_S_KPU11_TU_ETHER, 16, 1,
+ NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_GENEVE_OAM_CRI_OPT,
+ 8, 0x3f, 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 3, 0, NPC_S_KPU12_TU_IP, 16, 1,
+ NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_GENEVE, 8, 0x3f,
+ 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 3, 0, NPC_S_KPU12_TU_IP, 16, 1,
+ NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_GENEVE_OAM,
+ 8, 0x3f, 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 3, 0, NPC_S_KPU12_TU_IP, 16, 1,
+ NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_GENEVE_CRI_OPT,
+ 8, 0x3f, 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 3, 0, NPC_S_KPU12_TU_IP, 16, 1,
+ NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_GENEVE_OAM_CRI_OPT,
+ 8, 0x3f, 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 3, 0, NPC_S_KPU12_TU_IP6, 16, 1,
+ NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_GENEVE, 8, 0x3f,
+ 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 3, 0, NPC_S_KPU12_TU_IP6, 16, 1,
+ NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_GENEVE_OAM, 8, 0x3f,
+ 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 3, 0, NPC_S_KPU12_TU_IP6, 16, 1,
+ NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_GENEVE_CRI_OPT,
+ 8, 0x3f, 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 3, 0, NPC_S_KPU12_TU_IP6, 16, 1,
+ NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_GENEVE_OAM_CRI_OPT,
+ 8, 0x3f, 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_GTP_GTPC, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 3, 0, NPC_S_KPU12_TU_IP, 16, 1,
+ NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_GTP_GTPU_G_PDU, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_GTP_GTPU_UNK, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 7, 0, NPC_S_KPU16_UDP_DATA, 8, 1,
+ NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_UNK_PORT, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LD, NPC_LT_LD_SCTP, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LD, NPC_LT_LD_ICMP, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LD, NPC_LT_LD_IGMP, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LD, NPC_LT_LD_ICMP6, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LD, NPC_LT_LD_ESP, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LD, NPC_LT_LD_AH, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20,
+ 2, 0, NPC_S_KPU11_TU_ETHER, 8, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_NVGRE, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_LD, NPC_EC_NVGRE, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 0,
+ NPC_LID_LD, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 0, 0, NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 4, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE_MPLS, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 0, 0, NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 8, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE_MPLS, NPC_F_GRE_HAS_CSUM, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 0, 0, NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 8, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE_MPLS, NPC_F_GRE_HAS_KEY, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 0, 0, NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 8, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE_MPLS, NPC_F_GRE_HAS_SEQ, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 0, 0, NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 12, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE_MPLS, NPC_F_GRE_HAS_CSUM_KEY, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 0, 0, NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 12, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE_MPLS, NPC_F_GRE_HAS_CSUM_SEQ, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 0, 0, NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 12, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE_MPLS, NPC_F_GRE_HAS_KEY_SEQ, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 0, 0, NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 16, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE_MPLS, NPC_F_GRE_HAS_CSUM_KEY_SEQ,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 0, 0, NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 4, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE_MPLS, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 0, 0, NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 8, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE_MPLS, NPC_F_GRE_HAS_CSUM, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 0, 0, NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 8, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE_MPLS, NPC_F_GRE_HAS_KEY, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 0, 0, NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 8, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE_MPLS, NPC_F_GRE_HAS_SEQ, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 0, 0, NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 12, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE_MPLS, NPC_F_GRE_HAS_CSUM_KEY, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 0, 0, NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 12, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE_MPLS, NPC_F_GRE_HAS_CSUM_SEQ, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 0, 0, NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 12, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE_MPLS, NPC_F_GRE_HAS_KEY_SEQ, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10,
+ 0, 0, NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 16, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE_MPLS, NPC_F_GRE_HAS_CSUM_KEY_SEQ,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0,
+ 0, 0, NPC_S_KPU9_TU_NSH, 4, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE_NSH, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0,
+ 0, 0, NPC_S_KPU9_TU_NSH, 8, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE_NSH, NPC_F_GRE_HAS_CSUM, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0,
+ 0, 0, NPC_S_KPU9_TU_NSH, 8, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE_NSH, NPC_F_GRE_HAS_KEY, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0,
+ 0, 0, NPC_S_KPU9_TU_NSH, 8, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE_NSH, NPC_F_GRE_HAS_SEQ, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0,
+ 0, 0, NPC_S_KPU9_TU_NSH, 12, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE_NSH, NPC_F_GRE_HAS_CSUM_KEY, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0,
+ 0, 0, NPC_S_KPU9_TU_NSH, 12, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE_NSH, NPC_F_GRE_HAS_CSUM_SEQ, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0,
+ 0, 0, NPC_S_KPU9_TU_NSH, 12, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE_NSH, NPC_F_GRE_HAS_KEY_SEQ, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0,
+ 0, 0, NPC_S_KPU9_TU_NSH, 16, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE_NSH, NPC_F_GRE_HAS_CSUM_KEY_SEQ, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 3, 0, NPC_S_KPU12_TU_IP, 4, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 3, 0, NPC_S_KPU12_TU_IP, 8, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_HAS_CSUM, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 3, 0, NPC_S_KPU12_TU_IP, 8, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_HAS_KEY, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 3, 0, NPC_S_KPU12_TU_IP, 8, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_HAS_SEQ, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 3, 0, NPC_S_KPU12_TU_IP, 12, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_HAS_CSUM_KEY, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 3, 0, NPC_S_KPU12_TU_IP, 12, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_HAS_CSUM_SEQ, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 3, 0, NPC_S_KPU12_TU_IP, 12, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_HAS_KEY_SEQ, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 3, 0, NPC_S_KPU12_TU_IP, 16, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_HAS_CSUM_KEY_SEQ, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 3, 0, NPC_S_KPU12_TU_IP6, 4, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 3, 0, NPC_S_KPU12_TU_IP6, 8, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_HAS_CSUM, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 3, 0, NPC_S_KPU12_TU_IP6, 8, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_HAS_KEY, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 3, 0, NPC_S_KPU12_TU_IP6, 8, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_HAS_SEQ, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 3, 0, NPC_S_KPU12_TU_IP6, 12, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_HAS_CSUM_KEY, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 3, 0, NPC_S_KPU12_TU_IP6, 12, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_HAS_CSUM_SEQ, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 3, 0, NPC_S_KPU12_TU_IP6, 12, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_HAS_KEY_SEQ, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 3, 0, NPC_S_KPU12_TU_IP6, 16, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_HAS_CSUM_KEY_SEQ, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_HAS_ROUTE, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_UNK_PROTO, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_LD, NPC_EC_GRE, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 0,
+ NPC_LID_LD, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU11_TU_PPP, 8, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_VER1, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU11_TU_PPP, 12, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_VER1_HAS_SEQ, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU11_TU_PPP, 12, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_VER1_HAS_ACK, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU11_TU_PPP, 16, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_VER1_HAS_SEQ_ACK, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_VER1_UNK_PROTO, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_LD, NPC_EC_GRE_VER1, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 0,
+ NPC_LID_LD, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_LD, NPC_EC_UNK, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 0,
+ NPC_LID_LD, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+};
+
+static struct npc_kpu_profile_action kpu9_action_entries[] = {
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 0, NPC_S_KPU10_TU_MPLS_PL, 4, 0,
+ NPC_LID_LD, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 0, NPC_S_KPU10_TU_MPLS_PL, 8, 0,
+ NPC_LID_LD, NPC_LT_NA, NPC_F_MPLS_2_LABELS, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 0, NPC_S_KPU10_TU_MPLS_PL, 12, 0,
+ NPC_LID_LD, NPC_LT_NA, NPC_F_MPLS_3_LABELS, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 4, 0,
+ 0, 0, NPC_S_KPU10_TU_MPLS, 12, 0,
+ NPC_LID_LD, NPC_LT_NA, NPC_F_MPLS_4_LABELS, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 0, NPC_S_KPU10_TU_MPLS_PL, 4, 1,
+ NPC_LID_LD, NPC_LT_LD_TU_MPLS, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 0, NPC_S_KPU10_TU_MPLS_PL, 8, 1,
+ NPC_LID_LD, NPC_LT_LD_TU_MPLS, NPC_F_MPLS_2_LABELS, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 0, NPC_S_KPU10_TU_MPLS_PL, 12, 1,
+ NPC_LID_LD, NPC_LT_LD_TU_MPLS, NPC_F_MPLS_3_LABELS, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 4, 0,
+ 0, 0, NPC_S_KPU10_TU_MPLS, 12, 1,
+ NPC_LID_LD, NPC_LT_LD_TU_MPLS, NPC_F_MPLS_4_LABELS, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 2, 0, NPC_S_KPU12_TU_IP, 0, 0,
+ NPC_LID_LD, NPC_LT_NA, 0, 1, 0x3f,
+ 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 2, 0, NPC_S_KPU12_TU_IP6, 0, 0,
+ NPC_LID_LD, NPC_LT_NA, 0, 1, 0x3f,
+ 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20,
+ 1, 0, NPC_S_KPU11_TU_ETHER, 0, 0,
+ NPC_LID_LD, NPC_LT_NA, 0, 1, 0x3f,
+ 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0,
+ 0, 0, NPC_S_KPU10_TU_NSH, 0, 0,
+ NPC_LID_LD, NPC_LT_NA, 0, 1, 0x3f,
+ 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 1, 0, NPC_S_KPU11_TU_MPLS_IN_NSH, 0, 0,
+ NPC_LID_LD, NPC_LT_NA, 0, 1, 0x3f,
+ 0, 2,
+ },
+ {
+ NPC_ERRLEV_LE, NPC_EC_UNK, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 0,
+ NPC_LID_LD, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+};
+
+static struct npc_kpu_profile_action kpu10_action_entries[] = {
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 1, 0, NPC_S_KPU12_TU_IP, 4, 0,
+ NPC_LID_LD, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 1, 0, NPC_S_KPU12_TU_IP6, 4, 0,
+ NPC_LID_LD, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20,
+ 0, 0, NPC_S_KPU11_TU_ETHER, 8, 0,
+ NPC_LID_LD, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20,
+ 0, 0, NPC_S_KPU11_TU_ETHER, 4, 0,
+ NPC_LID_LD, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_LB, NPC_EC_L2_MPLS_2MANY, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 0,
+ NPC_LID_LD, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 1, 0, NPC_S_KPU12_TU_IP, 0, 0,
+ NPC_LID_LD, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 1, 0, NPC_S_KPU12_TU_IP6, 0, 0,
+ NPC_LID_LD, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20,
+ 0, 0, NPC_S_KPU11_TU_ETHER, 4, 0,
+ NPC_LID_LD, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20,
+ 0, 0, NPC_S_KPU11_TU_ETHER, 0, 0,
+ NPC_LID_LD, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 1, 0, NPC_S_KPU12_TU_IP, 0, 0,
+ NPC_LID_LD, NPC_LT_NA, 0, 1, 0x3f,
+ 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 1, 0, NPC_S_KPU12_TU_IP6, 0, 0,
+ NPC_LID_LD, NPC_LT_NA, 0, 1, 0x3f,
+ 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20,
+ 0, 0, NPC_S_KPU11_TU_ETHER, 0, 0,
+ NPC_LID_LD, NPC_LT_NA, 0, 1, 0x3f,
+ 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0,
+ 0, 0, NPC_S_KPU11_TU_3RD_NSH, 0, 0,
+ NPC_LID_LD, NPC_LT_NA, 0, 1, 0x3f,
+ 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 0, NPC_S_KPU11_TU_MPLS_IN_NSH, 0, 0,
+ NPC_LID_LD, NPC_LT_NA, 0, 1, 0x3f,
+ 0, 2,
+ },
+ {
+ NPC_ERRLEV_LE, NPC_EC_UNK, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 0,
+ NPC_LID_LD, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+};
+
+static struct npc_kpu_profile_action kpu11_action_entries[] = {
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 0, 0, NPC_S_KPU12_TU_IP, 14, 1,
+ NPC_LID_LE, NPC_LT_LE_TU_ETHER, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 0, 0, NPC_S_KPU12_TU_IP6, 14, 1,
+ NPC_LID_LE, NPC_LT_LE_TU_ETHER, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 0, NPC_S_KPU12_TU_ARP, 14, 1,
+ NPC_LID_LE, NPC_LT_LE_TU_ETHER, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 0, 0, NPC_S_KPU12_TU_IP, 18, 1,
+ NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_CTAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 0, 0, NPC_S_KPU12_TU_IP6, 18, 1,
+ NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_CTAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 0, NPC_S_KPU12_TU_ARP, 18, 1,
+ NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_CTAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_CTAG_UNK, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 0, 0, NPC_S_KPU12_TU_IP, 22, 1,
+ NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_STAG_CTAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 0, 0, NPC_S_KPU12_TU_IP6, 22, 1,
+ NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_STAG_CTAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 0, NPC_S_KPU12_TU_ARP, 22, 1,
+ NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_STAG_CTAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LE, NPC_LT_LE_TU_ETHER,
+ NPC_F_TU_ETHER_STAG_CTAG_UNK, 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 0, 0, NPC_S_KPU12_TU_IP, 18, 1,
+ NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_STAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 0, 0, NPC_S_KPU12_TU_IP6, 18, 1,
+ NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_STAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 0, NPC_S_KPU12_TU_ARP, 18, 1,
+ NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_STAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_STAG_UNK, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 0, 0, NPC_S_KPU12_TU_IP, 22, 1,
+ NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_QINQ_CTAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 0, 0, NPC_S_KPU12_TU_IP6, 22, 1,
+ NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_QINQ_CTAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 0, NPC_S_KPU12_TU_ARP, 22, 1,
+ NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_QINQ_CTAG, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LE, NPC_LT_LE_TU_ETHER,
+ NPC_F_TU_ETHER_QINQ_CTAG_UNK, 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0,
+ 0, 0, NPC_S_KPU12_TU_IP, 18, 1,
+ NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_QINQ, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0,
+ 0, 0, NPC_S_KPU12_TU_IP6, 18, 1,
+ NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_QINQ, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 0, NPC_S_KPU12_TU_ARP, 18, 1,
+ NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_QINQ, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_QINQ_UNK, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_UNK, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LE, NPC_LT_LE_TU_PPP, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LE, NPC_LT_LE_TU_MPLS_IN_NSH, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LE, NPC_LT_LE_TU_3RD_NSH, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_LE, NPC_EC_UNK, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 0,
+ NPC_LID_LE, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+};
+
+static struct npc_kpu_profile_action kpu12_action_entries[] = {
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 12, 0,
+ 2, 0, NPC_S_KPU15_TU_TCP, 20, 1,
+ NPC_LID_LF, NPC_LT_LF_TU_IP, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0,
+ 2, 0, NPC_S_KPU15_TU_UDP, 20, 1,
+ NPC_LID_LF, NPC_LT_LF_TU_IP, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU15_TU_SCTP, 20, 1,
+ NPC_LID_LF, NPC_LT_LF_TU_IP, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU15_TU_ICMP, 20, 1,
+ NPC_LID_LF, NPC_LT_LF_TU_IP, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU15_TU_IGMP, 20, 1,
+ NPC_LID_LF, NPC_LT_LF_TU_IP, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU15_TU_ESP, 20, 1,
+ NPC_LID_LF, NPC_LT_LF_TU_IP, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU15_TU_AH, 20, 1,
+ NPC_LID_LF, NPC_LT_LF_TU_IP, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LF, NPC_LT_LF_TU_IP, NPC_F_IP_UNK_PROTO, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 12, 0,
+ 2, 0, NPC_S_KPU15_TU_TCP, 0, 1,
+ NPC_LID_LF, NPC_LT_LF_TU_IP, NPC_F_IP_HAS_OPTIONS, 0, 0xf,
+ 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0,
+ 2, 0, NPC_S_KPU15_TU_UDP, 0, 1,
+ NPC_LID_LF, NPC_LT_LF_TU_IP, NPC_F_IP_HAS_OPTIONS, 0, 0xf,
+ 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU15_TU_SCTP, 0, 1,
+ NPC_LID_LF, NPC_LT_LF_TU_IP, NPC_F_IP_HAS_OPTIONS, 0, 0xf,
+ 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU15_TU_ICMP, 0, 1,
+ NPC_LID_LF, NPC_LT_LF_TU_IP, NPC_F_IP_HAS_OPTIONS, 0, 0xf,
+ 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU15_TU_IGMP, 0, 1,
+ NPC_LID_LF, NPC_LT_LF_TU_IP, NPC_F_IP_HAS_OPTIONS, 0, 0xf,
+ 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU15_TU_ESP, 0, 1,
+ NPC_LID_LF, NPC_LT_LF_TU_IP, NPC_F_IP_HAS_OPTIONS, 0, 0xf,
+ 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU15_TU_AH, 0, 1,
+ NPC_LID_LF, NPC_LT_LF_TU_IP, NPC_F_IP_HAS_OPTIONS, 0, 0xf,
+ 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LF, NPC_LT_LF_TU_IP,
+ NPC_F_IP_UNK_PROTO_HAS_OPTIONS, 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_LF, NPC_EC_IP_VER, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LF, NPC_LT_LF_TU_IP, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LF, NPC_LT_LF_TU_ARP, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 12, 0,
+ 2, 0, NPC_S_KPU15_TU_TCP, 40, 1,
+ NPC_LID_LF, NPC_LT_LF_TU_IP6, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0,
+ 2, 0, NPC_S_KPU15_TU_UDP, 40, 1,
+ NPC_LID_LF, NPC_LT_LF_TU_IP6, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU15_TU_SCTP, 40, 1,
+ NPC_LID_LF, NPC_LT_LF_TU_IP6, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU15_TU_ICMP, 40, 1,
+ NPC_LID_LF, NPC_LT_LF_TU_IP6, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU15_TU_ICMP6, 40, 1,
+ NPC_LID_LF, NPC_LT_LF_TU_IP6, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU15_TU_ESP, 40, 1,
+ NPC_LID_LC, NPC_LT_LF_TU_IP6, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 2, 0, NPC_S_KPU15_TU_AH, 40, 1,
+ NPC_LID_LC, NPC_LT_LF_TU_IP6, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0,
+ 0, 0, NPC_S_KPU13_TU_IP6_EXT, 0, 1,
+ NPC_LID_LF, NPC_LT_LF_TU_IP6, NPC_F_IP6_HAS_EXT, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_LF, NPC_EC_IP6_VER, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LF, NPC_LT_LF_TU_IP6, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_LF, NPC_EC_UNK, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 0,
+ NPC_LID_LF, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+};
+
+static struct npc_kpu_profile_action kpu13_action_entries[] = {
+ {
+ 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,
+ },
+};
+
+static struct npc_kpu_profile_action kpu14_action_entries[] = {
+ {
+ 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,
+ },
+};
+
+static struct npc_kpu_profile_action kpu15_action_entries[] = {
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 0, NPC_S_KPU16_HTTP_DATA, 20, 1,
+ NPC_LID_LG, NPC_LT_LG_TU_TCP, NPC_F_TCP_HTTP, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 0, NPC_S_KPU16_HTTPS_DATA, 20, 1,
+ NPC_LID_LG, NPC_LT_LG_TU_TCP, NPC_F_TCP_HTTPS, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 0, NPC_S_KPU16_PPTP_DATA, 20, 1,
+ NPC_LID_LD, NPC_LT_LG_TU_TCP, NPC_F_TCP_PPTP, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 0, NPC_S_KPU16_TCP_DATA, 20, 1,
+ NPC_LID_LG, NPC_LT_LG_TU_TCP, NPC_F_TCP_UNK_PORT, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 0, NPC_S_KPU16_HTTP_DATA, 0, 1,
+ NPC_LID_LG, NPC_LT_LG_TU_TCP, NPC_F_TCP_HTTP_HAS_OPTIONS,
+ 12, 0xf0, 1, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 0, NPC_S_KPU16_HTTPS_DATA, 0, 1,
+ NPC_LID_LG, NPC_LT_LG_TU_TCP, NPC_F_TCP_HTTPS_HAS_OPTIONS,
+ 12, 0xf0, 1, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 0, NPC_S_KPU16_PPTP_DATA, 0, 1,
+ NPC_LID_LG, NPC_LT_LG_TU_TCP, NPC_F_TCP_PPTP_HAS_OPTIONS,
+ 12, 0xf0, 1, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 0, NPC_S_KPU16_TCP_DATA, 0, 1,
+ NPC_LID_LG, NPC_LT_LG_TU_TCP, NPC_F_TCP_UNK_PORT_HAS_OPTIONS,
+ 12, 0xf0, 1, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 0, NPC_S_KPU16_UDP_DATA, 8, 1,
+ NPC_LID_LG, NPC_LT_LG_TU_UDP, NPC_F_UDP_UNK_PORT, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LG, NPC_LT_LG_TU_SCTP, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LG, NPC_LT_LG_TU_ICMP, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LG, NPC_LT_LG_TU_IGMP, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LG, NPC_LT_LG_TU_ICMP6, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LG, NPC_LT_LG_TU_ESP, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LG, NPC_LT_LG_TU_AH, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_LG, NPC_EC_L4, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 0,
+ NPC_LID_LG, NPC_LT_NA, 0, 0, 0,
+ 0, 0,
+ },
+};
+
+static struct npc_kpu_profile_action kpu16_action_entries[] = {
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LH, NPC_LT_LH_TCP_DATA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LH, NPC_LT_LH_HTTP_DATA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LH, NPC_LT_LH_HTTPS_DATA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LH, NPC_LT_LH_PPTP_DATA, 0, 0, 0,
+ 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0,
+ 0, 1, NPC_S_NA, 0, 1,
+ NPC_LID_LH, NPC_LT_LH_UDP_DATA, 0, 0, 0,
+ 0, 0,
+ },
+};
+
+static struct npc_kpu_profile npc_kpu_profiles[] = {
+ {
+ ARRAY_SIZE(kpu1_cam_entries),
+ ARRAY_SIZE(kpu1_action_entries),
+ &kpu1_cam_entries[0],
+ &kpu1_action_entries[0],
+ },
+ {
+ ARRAY_SIZE(kpu2_cam_entries),
+ ARRAY_SIZE(kpu2_action_entries),
+ &kpu2_cam_entries[0],
+ &kpu2_action_entries[0],
+ },
+ {
+ ARRAY_SIZE(kpu3_cam_entries),
+ ARRAY_SIZE(kpu3_action_entries),
+ &kpu3_cam_entries[0],
+ &kpu3_action_entries[0],
+ },
+ {
+ ARRAY_SIZE(kpu4_cam_entries),
+ ARRAY_SIZE(kpu4_action_entries),
+ &kpu4_cam_entries[0],
+ &kpu4_action_entries[0],
+ },
+ {
+ ARRAY_SIZE(kpu5_cam_entries),
+ ARRAY_SIZE(kpu5_action_entries),
+ &kpu5_cam_entries[0],
+ &kpu5_action_entries[0],
+ },
+ {
+ ARRAY_SIZE(kpu6_cam_entries),
+ ARRAY_SIZE(kpu6_action_entries),
+ &kpu6_cam_entries[0],
+ &kpu6_action_entries[0],
+ },
+ {
+ ARRAY_SIZE(kpu7_cam_entries),
+ ARRAY_SIZE(kpu7_action_entries),
+ &kpu7_cam_entries[0],
+ &kpu7_action_entries[0],
+ },
+ {
+ ARRAY_SIZE(kpu8_cam_entries),
+ ARRAY_SIZE(kpu8_action_entries),
+ &kpu8_cam_entries[0],
+ &kpu8_action_entries[0],
+ },
+ {
+ ARRAY_SIZE(kpu9_cam_entries),
+ ARRAY_SIZE(kpu9_action_entries),
+ &kpu9_cam_entries[0],
+ &kpu9_action_entries[0],
+ },
+ {
+ ARRAY_SIZE(kpu10_cam_entries),
+ ARRAY_SIZE(kpu10_action_entries),
+ &kpu10_cam_entries[0],
+ &kpu10_action_entries[0],
+ },
+ {
+ ARRAY_SIZE(kpu11_cam_entries),
+ ARRAY_SIZE(kpu11_action_entries),
+ &kpu11_cam_entries[0],
+ &kpu11_action_entries[0],
+ },
+ {
+ ARRAY_SIZE(kpu12_cam_entries),
+ ARRAY_SIZE(kpu12_action_entries),
+ &kpu12_cam_entries[0],
+ &kpu12_action_entries[0],
+ },
+ {
+ ARRAY_SIZE(kpu13_cam_entries),
+ ARRAY_SIZE(kpu13_action_entries),
+ &kpu13_cam_entries[0],
+ &kpu13_action_entries[0],
+ },
+ {
+ ARRAY_SIZE(kpu14_cam_entries),
+ ARRAY_SIZE(kpu14_action_entries),
+ &kpu14_cam_entries[0],
+ &kpu14_action_entries[0],
+ },
+ {
+ ARRAY_SIZE(kpu15_cam_entries),
+ ARRAY_SIZE(kpu15_action_entries),
+ &kpu15_cam_entries[0],
+ &kpu15_action_entries[0],
+ },
+ {
+ ARRAY_SIZE(kpu16_cam_entries),
+ ARRAY_SIZE(kpu16_action_entries),
+ &kpu16_cam_entries[0],
+ &kpu16_action_entries[0],
+ },
+};
+
+#endif /* NPC_PROFILE_H */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
new file mode 100644
index 000000000000..dc28fa2b9481
--- /dev/null
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
@@ -0,0 +1,1772 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Marvell OcteonTx2 RVU Admin Function driver
+ *
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/pci.h>
+#include <linux/sysfs.h>
+
+#include "cgx.h"
+#include "rvu.h"
+#include "rvu_reg.h"
+
+#define DRV_NAME "octeontx2-af"
+#define DRV_STRING "Marvell OcteonTX2 RVU Admin Function Driver"
+#define DRV_VERSION "1.0"
+
+static int rvu_get_hwvf(struct rvu *rvu, int pcifunc);
+
+static void rvu_set_msix_offset(struct rvu *rvu, struct rvu_pfvf *pfvf,
+ struct rvu_block *block, int lf);
+static void rvu_clear_msix_offset(struct rvu *rvu, struct rvu_pfvf *pfvf,
+ struct rvu_block *block, int lf);
+
+/* Supported devices */
+static const struct pci_device_id rvu_id_table[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_OCTEONTX2_RVU_AF) },
+ { 0, } /* end of table */
+};
+
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_DESCRIPTION(DRV_STRING);
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(DRV_VERSION);
+MODULE_DEVICE_TABLE(pci, rvu_id_table);
+
+/* Poll a RVU block's register 'offset', for a 'zero'
+ * or 'nonzero' at bits specified by 'mask'
+ */
+int rvu_poll_reg(struct rvu *rvu, u64 block, u64 offset, u64 mask, bool zero)
+{
+ unsigned long timeout = jiffies + usecs_to_jiffies(100);
+ void __iomem *reg;
+ u64 reg_val;
+
+ reg = rvu->afreg_base + ((block << 28) | offset);
+ while (time_before(jiffies, timeout)) {
+ reg_val = readq(reg);
+ if (zero && !(reg_val & mask))
+ return 0;
+ if (!zero && (reg_val & mask))
+ return 0;
+ usleep_range(1, 5);
+ timeout--;
+ }
+ return -EBUSY;
+}
+
+int rvu_alloc_rsrc(struct rsrc_bmap *rsrc)
+{
+ int id;
+
+ if (!rsrc->bmap)
+ return -EINVAL;
+
+ id = find_first_zero_bit(rsrc->bmap, rsrc->max);
+ if (id >= rsrc->max)
+ return -ENOSPC;
+
+ __set_bit(id, rsrc->bmap);
+
+ return id;
+}
+
+int rvu_alloc_rsrc_contig(struct rsrc_bmap *rsrc, int nrsrc)
+{
+ int start;
+
+ if (!rsrc->bmap)
+ return -EINVAL;
+
+ start = bitmap_find_next_zero_area(rsrc->bmap, rsrc->max, 0, nrsrc, 0);
+ if (start >= rsrc->max)
+ return -ENOSPC;
+
+ bitmap_set(rsrc->bmap, start, nrsrc);
+ return start;
+}
+
+static void rvu_free_rsrc_contig(struct rsrc_bmap *rsrc, int nrsrc, int start)
+{
+ if (!rsrc->bmap)
+ return;
+ if (start >= rsrc->max)
+ return;
+
+ bitmap_clear(rsrc->bmap, start, nrsrc);
+}
+
+bool rvu_rsrc_check_contig(struct rsrc_bmap *rsrc, int nrsrc)
+{
+ int start;
+
+ if (!rsrc->bmap)
+ return false;
+
+ start = bitmap_find_next_zero_area(rsrc->bmap, rsrc->max, 0, nrsrc, 0);
+ if (start >= rsrc->max)
+ return false;
+
+ return true;
+}
+
+void rvu_free_rsrc(struct rsrc_bmap *rsrc, int id)
+{
+ if (!rsrc->bmap)
+ return;
+
+ __clear_bit(id, rsrc->bmap);
+}
+
+int rvu_rsrc_free_count(struct rsrc_bmap *rsrc)
+{
+ int used;
+
+ if (!rsrc->bmap)
+ return 0;
+
+ used = bitmap_weight(rsrc->bmap, rsrc->max);
+ return (rsrc->max - used);
+}
+
+int rvu_alloc_bitmap(struct rsrc_bmap *rsrc)
+{
+ rsrc->bmap = kcalloc(BITS_TO_LONGS(rsrc->max),
+ sizeof(long), GFP_KERNEL);
+ if (!rsrc->bmap)
+ return -ENOMEM;
+ return 0;
+}
+
+/* Get block LF's HW index from a PF_FUNC's block slot number */
+int rvu_get_lf(struct rvu *rvu, struct rvu_block *block, u16 pcifunc, u16 slot)
+{
+ u16 match = 0;
+ int lf;
+
+ spin_lock(&rvu->rsrc_lock);
+ for (lf = 0; lf < block->lf.max; lf++) {
+ if (block->fn_map[lf] == pcifunc) {
+ if (slot == match) {
+ spin_unlock(&rvu->rsrc_lock);
+ return lf;
+ }
+ match++;
+ }
+ }
+ spin_unlock(&rvu->rsrc_lock);
+ return -ENODEV;
+}
+
+/* Convert BLOCK_TYPE_E to a BLOCK_ADDR_E.
+ * Some silicon variants of OcteonTX2 supports
+ * multiple blocks of same type.
+ *
+ * @pcifunc has to be zero when no LF is yet attached.
+ */
+int rvu_get_blkaddr(struct rvu *rvu, int blktype, u16 pcifunc)
+{
+ int devnum, blkaddr = -ENODEV;
+ u64 cfg, reg;
+ bool is_pf;
+
+ switch (blktype) {
+ case BLKTYPE_NPC:
+ blkaddr = BLKADDR_NPC;
+ goto exit;
+ case BLKTYPE_NPA:
+ blkaddr = BLKADDR_NPA;
+ goto exit;
+ case BLKTYPE_NIX:
+ /* For now assume NIX0 */
+ if (!pcifunc) {
+ blkaddr = BLKADDR_NIX0;
+ goto exit;
+ }
+ break;
+ case BLKTYPE_SSO:
+ blkaddr = BLKADDR_SSO;
+ goto exit;
+ case BLKTYPE_SSOW:
+ blkaddr = BLKADDR_SSOW;
+ goto exit;
+ case BLKTYPE_TIM:
+ blkaddr = BLKADDR_TIM;
+ goto exit;
+ case BLKTYPE_CPT:
+ /* For now assume CPT0 */
+ if (!pcifunc) {
+ blkaddr = BLKADDR_CPT0;
+ goto exit;
+ }
+ break;
+ }
+
+ /* Check if this is a RVU PF or VF */
+ if (pcifunc & RVU_PFVF_FUNC_MASK) {
+ is_pf = false;
+ devnum = rvu_get_hwvf(rvu, pcifunc);
+ } else {
+ is_pf = true;
+ devnum = rvu_get_pf(pcifunc);
+ }
+
+ /* Check if the 'pcifunc' has a NIX LF from 'BLKADDR_NIX0' */
+ if (blktype == BLKTYPE_NIX) {
+ reg = is_pf ? RVU_PRIV_PFX_NIX0_CFG : RVU_PRIV_HWVFX_NIX0_CFG;
+ cfg = rvu_read64(rvu, BLKADDR_RVUM, reg | (devnum << 16));
+ if (cfg)
+ blkaddr = BLKADDR_NIX0;
+ }
+
+ /* Check if the 'pcifunc' has a CPT LF from 'BLKADDR_CPT0' */
+ if (blktype == BLKTYPE_CPT) {
+ reg = is_pf ? RVU_PRIV_PFX_CPT0_CFG : RVU_PRIV_HWVFX_CPT0_CFG;
+ cfg = rvu_read64(rvu, BLKADDR_RVUM, reg | (devnum << 16));
+ if (cfg)
+ blkaddr = BLKADDR_CPT0;
+ }
+
+exit:
+ if (is_block_implemented(rvu->hw, blkaddr))
+ return blkaddr;
+ return -ENODEV;
+}
+
+static void rvu_update_rsrc_map(struct rvu *rvu, struct rvu_pfvf *pfvf,
+ struct rvu_block *block, u16 pcifunc,
+ u16 lf, bool attach)
+{
+ int devnum, num_lfs = 0;
+ bool is_pf;
+ u64 reg;
+
+ if (lf >= block->lf.max) {
+ dev_err(&rvu->pdev->dev,
+ "%s: FATAL: LF %d is >= %s's max lfs i.e %d\n",
+ __func__, lf, block->name, block->lf.max);
+ return;
+ }
+
+ /* Check if this is for a RVU PF or VF */
+ if (pcifunc & RVU_PFVF_FUNC_MASK) {
+ is_pf = false;
+ devnum = rvu_get_hwvf(rvu, pcifunc);
+ } else {
+ is_pf = true;
+ devnum = rvu_get_pf(pcifunc);
+ }
+
+ block->fn_map[lf] = attach ? pcifunc : 0;
+
+ switch (block->type) {
+ case BLKTYPE_NPA:
+ pfvf->npalf = attach ? true : false;
+ num_lfs = pfvf->npalf;
+ break;
+ case BLKTYPE_NIX:
+ pfvf->nixlf = attach ? true : false;
+ num_lfs = pfvf->nixlf;
+ break;
+ case BLKTYPE_SSO:
+ attach ? pfvf->sso++ : pfvf->sso--;
+ num_lfs = pfvf->sso;
+ break;
+ case BLKTYPE_SSOW:
+ attach ? pfvf->ssow++ : pfvf->ssow--;
+ num_lfs = pfvf->ssow;
+ break;
+ case BLKTYPE_TIM:
+ attach ? pfvf->timlfs++ : pfvf->timlfs--;
+ num_lfs = pfvf->timlfs;
+ break;
+ case BLKTYPE_CPT:
+ attach ? pfvf->cptlfs++ : pfvf->cptlfs--;
+ num_lfs = pfvf->cptlfs;
+ break;
+ }
+
+ reg = is_pf ? block->pf_lfcnt_reg : block->vf_lfcnt_reg;
+ rvu_write64(rvu, BLKADDR_RVUM, reg | (devnum << 16), num_lfs);
+}
+
+inline int rvu_get_pf(u16 pcifunc)
+{
+ return (pcifunc >> RVU_PFVF_PF_SHIFT) & RVU_PFVF_PF_MASK;
+}
+
+void rvu_get_pf_numvfs(struct rvu *rvu, int pf, int *numvfs, int *hwvf)
+{
+ u64 cfg;
+
+ /* Get numVFs attached to this PF and first HWVF */
+ cfg = rvu_read64(rvu, BLKADDR_RVUM, RVU_PRIV_PFX_CFG(pf));
+ *numvfs = (cfg >> 12) & 0xFF;
+ *hwvf = cfg & 0xFFF;
+}
+
+static int rvu_get_hwvf(struct rvu *rvu, int pcifunc)
+{
+ int pf, func;
+ u64 cfg;
+
+ pf = rvu_get_pf(pcifunc);
+ func = pcifunc & RVU_PFVF_FUNC_MASK;
+
+ /* Get first HWVF attached to this PF */
+ cfg = rvu_read64(rvu, BLKADDR_RVUM, RVU_PRIV_PFX_CFG(pf));
+
+ return ((cfg & 0xFFF) + func - 1);
+}
+
+struct rvu_pfvf *rvu_get_pfvf(struct rvu *rvu, int pcifunc)
+{
+ /* Check if it is a PF or VF */
+ if (pcifunc & RVU_PFVF_FUNC_MASK)
+ return &rvu->hwvf[rvu_get_hwvf(rvu, pcifunc)];
+ else
+ return &rvu->pf[rvu_get_pf(pcifunc)];
+}
+
+bool is_block_implemented(struct rvu_hwinfo *hw, int blkaddr)
+{
+ struct rvu_block *block;
+
+ if (blkaddr < BLKADDR_RVUM || blkaddr >= BLK_COUNT)
+ return false;
+
+ block = &hw->block[blkaddr];
+ return block->implemented;
+}
+
+static void rvu_check_block_implemented(struct rvu *rvu)
+{
+ struct rvu_hwinfo *hw = rvu->hw;
+ struct rvu_block *block;
+ int blkid;
+ u64 cfg;
+
+ /* For each block check if 'implemented' bit is set */
+ for (blkid = 0; blkid < BLK_COUNT; blkid++) {
+ block = &hw->block[blkid];
+ cfg = rvupf_read64(rvu, RVU_PF_BLOCK_ADDRX_DISC(blkid));
+ if (cfg & BIT_ULL(11))
+ block->implemented = true;
+ }
+}
+
+int rvu_lf_reset(struct rvu *rvu, struct rvu_block *block, int lf)
+{
+ int err;
+
+ if (!block->implemented)
+ return 0;
+
+ rvu_write64(rvu, block->addr, block->lfreset_reg, lf | BIT_ULL(12));
+ err = rvu_poll_reg(rvu, block->addr, block->lfreset_reg, BIT_ULL(12),
+ true);
+ return err;
+}
+
+static void rvu_block_reset(struct rvu *rvu, int blkaddr, u64 rst_reg)
+{
+ struct rvu_block *block = &rvu->hw->block[blkaddr];
+
+ if (!block->implemented)
+ return;
+
+ rvu_write64(rvu, blkaddr, rst_reg, BIT_ULL(0));
+ rvu_poll_reg(rvu, blkaddr, rst_reg, BIT_ULL(63), true);
+}
+
+static void rvu_reset_all_blocks(struct rvu *rvu)
+{
+ /* Do a HW reset of all RVU blocks */
+ rvu_block_reset(rvu, BLKADDR_NPA, NPA_AF_BLK_RST);
+ rvu_block_reset(rvu, BLKADDR_NIX0, NIX_AF_BLK_RST);
+ rvu_block_reset(rvu, BLKADDR_NPC, NPC_AF_BLK_RST);
+ rvu_block_reset(rvu, BLKADDR_SSO, SSO_AF_BLK_RST);
+ rvu_block_reset(rvu, BLKADDR_TIM, TIM_AF_BLK_RST);
+ rvu_block_reset(rvu, BLKADDR_CPT0, CPT_AF_BLK_RST);
+ rvu_block_reset(rvu, BLKADDR_NDC0, NDC_AF_BLK_RST);
+ rvu_block_reset(rvu, BLKADDR_NDC1, NDC_AF_BLK_RST);
+ rvu_block_reset(rvu, BLKADDR_NDC2, NDC_AF_BLK_RST);
+}
+
+static void rvu_scan_block(struct rvu *rvu, struct rvu_block *block)
+{
+ struct rvu_pfvf *pfvf;
+ u64 cfg;
+ int lf;
+
+ for (lf = 0; lf < block->lf.max; lf++) {
+ cfg = rvu_read64(rvu, block->addr,
+ block->lfcfg_reg | (lf << block->lfshift));
+ if (!(cfg & BIT_ULL(63)))
+ continue;
+
+ /* Set this resource as being used */
+ __set_bit(lf, block->lf.bmap);
+
+ /* Get, to whom this LF is attached */
+ pfvf = rvu_get_pfvf(rvu, (cfg >> 8) & 0xFFFF);
+ rvu_update_rsrc_map(rvu, pfvf, block,
+ (cfg >> 8) & 0xFFFF, lf, true);
+
+ /* Set start MSIX vector for this LF within this PF/VF */
+ rvu_set_msix_offset(rvu, pfvf, block, lf);
+ }
+}
+
+static void rvu_check_min_msix_vec(struct rvu *rvu, int nvecs, int pf, int vf)
+{
+ int min_vecs;
+
+ if (!vf)
+ goto check_pf;
+
+ if (!nvecs) {
+ dev_warn(rvu->dev,
+ "PF%d:VF%d is configured with zero msix vectors, %d\n",
+ pf, vf - 1, nvecs);
+ }
+ return;
+
+check_pf:
+ if (pf == 0)
+ min_vecs = RVU_AF_INT_VEC_CNT + RVU_PF_INT_VEC_CNT;
+ else
+ min_vecs = RVU_PF_INT_VEC_CNT;
+
+ if (!(nvecs < min_vecs))
+ return;
+ dev_warn(rvu->dev,
+ "PF%d is configured with too few vectors, %d, min is %d\n",
+ pf, nvecs, min_vecs);
+}
+
+static int rvu_setup_msix_resources(struct rvu *rvu)
+{
+ struct rvu_hwinfo *hw = rvu->hw;
+ int pf, vf, numvfs, hwvf, err;
+ int nvecs, offset, max_msix;
+ struct rvu_pfvf *pfvf;
+ u64 cfg, phy_addr;
+ dma_addr_t iova;
+
+ for (pf = 0; pf < hw->total_pfs; pf++) {
+ cfg = rvu_read64(rvu, BLKADDR_RVUM, RVU_PRIV_PFX_CFG(pf));
+ /* If PF is not enabled, nothing to do */
+ if (!((cfg >> 20) & 0x01))
+ continue;
+
+ rvu_get_pf_numvfs(rvu, pf, &numvfs, &hwvf);
+
+ pfvf = &rvu->pf[pf];
+ /* Get num of MSIX vectors attached to this PF */
+ cfg = rvu_read64(rvu, BLKADDR_RVUM, RVU_PRIV_PFX_MSIX_CFG(pf));
+ pfvf->msix.max = ((cfg >> 32) & 0xFFF) + 1;
+ rvu_check_min_msix_vec(rvu, pfvf->msix.max, pf, 0);
+
+ /* Alloc msix bitmap for this PF */
+ err = rvu_alloc_bitmap(&pfvf->msix);
+ if (err)
+ return err;
+
+ /* Allocate memory for MSIX vector to RVU block LF mapping */
+ pfvf->msix_lfmap = devm_kcalloc(rvu->dev, pfvf->msix.max,
+ sizeof(u16), GFP_KERNEL);
+ if (!pfvf->msix_lfmap)
+ return -ENOMEM;
+
+ /* For PF0 (AF) firmware will set msix vector offsets for
+ * AF, block AF and PF0_INT vectors, so jump to VFs.
+ */
+ if (!pf)
+ goto setup_vfmsix;
+
+ /* Set MSIX offset for PF's 'RVU_PF_INT_VEC' vectors.
+ * These are allocated on driver init and never freed,
+ * so no need to set 'msix_lfmap' for these.
+ */
+ cfg = rvu_read64(rvu, BLKADDR_RVUM, RVU_PRIV_PFX_INT_CFG(pf));
+ nvecs = (cfg >> 12) & 0xFF;
+ cfg &= ~0x7FFULL;
+ offset = rvu_alloc_rsrc_contig(&pfvf->msix, nvecs);
+ rvu_write64(rvu, BLKADDR_RVUM,
+ RVU_PRIV_PFX_INT_CFG(pf), cfg | offset);
+setup_vfmsix:
+ /* Alloc msix bitmap for VFs */
+ for (vf = 0; vf < numvfs; vf++) {
+ pfvf = &rvu->hwvf[hwvf + vf];
+ /* Get num of MSIX vectors attached to this VF */
+ cfg = rvu_read64(rvu, BLKADDR_RVUM,
+ RVU_PRIV_PFX_MSIX_CFG(pf));
+ pfvf->msix.max = (cfg & 0xFFF) + 1;
+ rvu_check_min_msix_vec(rvu, pfvf->msix.max, pf, vf + 1);
+
+ /* Alloc msix bitmap for this VF */
+ err = rvu_alloc_bitmap(&pfvf->msix);
+ if (err)
+ return err;
+
+ pfvf->msix_lfmap =
+ devm_kcalloc(rvu->dev, pfvf->msix.max,
+ sizeof(u16), GFP_KERNEL);
+ if (!pfvf->msix_lfmap)
+ return -ENOMEM;
+
+ /* Set MSIX offset for HWVF's 'RVU_VF_INT_VEC' vectors.
+ * These are allocated on driver init and never freed,
+ * so no need to set 'msix_lfmap' for these.
+ */
+ cfg = rvu_read64(rvu, BLKADDR_RVUM,
+ RVU_PRIV_HWVFX_INT_CFG(hwvf + vf));
+ nvecs = (cfg >> 12) & 0xFF;
+ cfg &= ~0x7FFULL;
+ offset = rvu_alloc_rsrc_contig(&pfvf->msix, nvecs);
+ rvu_write64(rvu, BLKADDR_RVUM,
+ RVU_PRIV_HWVFX_INT_CFG(hwvf + vf),
+ cfg | offset);
+ }
+ }
+
+ /* HW interprets RVU_AF_MSIXTR_BASE address as an IOVA, hence
+ * create a IOMMU mapping for the physcial address configured by
+ * firmware and reconfig RVU_AF_MSIXTR_BASE with IOVA.
+ */
+ cfg = rvu_read64(rvu, BLKADDR_RVUM, RVU_PRIV_CONST);
+ max_msix = cfg & 0xFFFFF;
+ phy_addr = rvu_read64(rvu, BLKADDR_RVUM, RVU_AF_MSIXTR_BASE);
+ iova = dma_map_resource(rvu->dev, phy_addr,
+ max_msix * PCI_MSIX_ENTRY_SIZE,
+ DMA_BIDIRECTIONAL, 0);
+
+ if (dma_mapping_error(rvu->dev, iova))
+ return -ENOMEM;
+
+ rvu_write64(rvu, BLKADDR_RVUM, RVU_AF_MSIXTR_BASE, (u64)iova);
+ rvu->msix_base_iova = iova;
+
+ return 0;
+}
+
+static void rvu_free_hw_resources(struct rvu *rvu)
+{
+ struct rvu_hwinfo *hw = rvu->hw;
+ struct rvu_block *block;
+ struct rvu_pfvf *pfvf;
+ int id, max_msix;
+ u64 cfg;
+
+ rvu_npa_freemem(rvu);
+ rvu_npc_freemem(rvu);
+ rvu_nix_freemem(rvu);
+
+ /* Free block LF bitmaps */
+ for (id = 0; id < BLK_COUNT; id++) {
+ block = &hw->block[id];
+ kfree(block->lf.bmap);
+ }
+
+ /* Free MSIX bitmaps */
+ for (id = 0; id < hw->total_pfs; id++) {
+ pfvf = &rvu->pf[id];
+ kfree(pfvf->msix.bmap);
+ }
+
+ for (id = 0; id < hw->total_vfs; id++) {
+ pfvf = &rvu->hwvf[id];
+ kfree(pfvf->msix.bmap);
+ }
+
+ /* Unmap MSIX vector base IOVA mapping */
+ if (!rvu->msix_base_iova)
+ return;
+ cfg = rvu_read64(rvu, BLKADDR_RVUM, RVU_PRIV_CONST);
+ max_msix = cfg & 0xFFFFF;
+ dma_unmap_resource(rvu->dev, rvu->msix_base_iova,
+ max_msix * PCI_MSIX_ENTRY_SIZE,
+ DMA_BIDIRECTIONAL, 0);
+}
+
+static int rvu_setup_hw_resources(struct rvu *rvu)
+{
+ struct rvu_hwinfo *hw = rvu->hw;
+ struct rvu_block *block;
+ int blkid, err;
+ u64 cfg;
+
+ /* Get HW supported max RVU PF & VF count */
+ cfg = rvu_read64(rvu, BLKADDR_RVUM, RVU_PRIV_CONST);
+ hw->total_pfs = (cfg >> 32) & 0xFF;
+ hw->total_vfs = (cfg >> 20) & 0xFFF;
+ hw->max_vfs_per_pf = (cfg >> 40) & 0xFF;
+
+ /* Init NPA LF's bitmap */
+ block = &hw->block[BLKADDR_NPA];
+ if (!block->implemented)
+ goto nix;
+ cfg = rvu_read64(rvu, BLKADDR_NPA, NPA_AF_CONST);
+ block->lf.max = (cfg >> 16) & 0xFFF;
+ block->addr = BLKADDR_NPA;
+ block->type = BLKTYPE_NPA;
+ block->lfshift = 8;
+ block->lookup_reg = NPA_AF_RVU_LF_CFG_DEBUG;
+ block->pf_lfcnt_reg = RVU_PRIV_PFX_NPA_CFG;
+ block->vf_lfcnt_reg = RVU_PRIV_HWVFX_NPA_CFG;
+ block->lfcfg_reg = NPA_PRIV_LFX_CFG;
+ block->msixcfg_reg = NPA_PRIV_LFX_INT_CFG;
+ block->lfreset_reg = NPA_AF_LF_RST;
+ sprintf(block->name, "NPA");
+ err = rvu_alloc_bitmap(&block->lf);
+ if (err)
+ return err;
+
+nix:
+ /* Init NIX LF's bitmap */
+ block = &hw->block[BLKADDR_NIX0];
+ if (!block->implemented)
+ goto sso;
+ cfg = rvu_read64(rvu, BLKADDR_NIX0, NIX_AF_CONST2);
+ block->lf.max = cfg & 0xFFF;
+ block->addr = BLKADDR_NIX0;
+ block->type = BLKTYPE_NIX;
+ block->lfshift = 8;
+ block->lookup_reg = NIX_AF_RVU_LF_CFG_DEBUG;
+ block->pf_lfcnt_reg = RVU_PRIV_PFX_NIX0_CFG;
+ block->vf_lfcnt_reg = RVU_PRIV_HWVFX_NIX0_CFG;
+ block->lfcfg_reg = NIX_PRIV_LFX_CFG;
+ block->msixcfg_reg = NIX_PRIV_LFX_INT_CFG;
+ block->lfreset_reg = NIX_AF_LF_RST;
+ sprintf(block->name, "NIX");
+ err = rvu_alloc_bitmap(&block->lf);
+ if (err)
+ return err;
+
+sso:
+ /* Init SSO group's bitmap */
+ block = &hw->block[BLKADDR_SSO];
+ if (!block->implemented)
+ goto ssow;
+ cfg = rvu_read64(rvu, BLKADDR_SSO, SSO_AF_CONST);
+ block->lf.max = cfg & 0xFFFF;
+ block->addr = BLKADDR_SSO;
+ block->type = BLKTYPE_SSO;
+ block->multislot = true;
+ block->lfshift = 3;
+ block->lookup_reg = SSO_AF_RVU_LF_CFG_DEBUG;
+ block->pf_lfcnt_reg = RVU_PRIV_PFX_SSO_CFG;
+ block->vf_lfcnt_reg = RVU_PRIV_HWVFX_SSO_CFG;
+ block->lfcfg_reg = SSO_PRIV_LFX_HWGRP_CFG;
+ block->msixcfg_reg = SSO_PRIV_LFX_HWGRP_INT_CFG;
+ block->lfreset_reg = SSO_AF_LF_HWGRP_RST;
+ sprintf(block->name, "SSO GROUP");
+ err = rvu_alloc_bitmap(&block->lf);
+ if (err)
+ return err;
+
+ssow:
+ /* Init SSO workslot's bitmap */
+ block = &hw->block[BLKADDR_SSOW];
+ if (!block->implemented)
+ goto tim;
+ block->lf.max = (cfg >> 56) & 0xFF;
+ block->addr = BLKADDR_SSOW;
+ block->type = BLKTYPE_SSOW;
+ block->multislot = true;
+ block->lfshift = 3;
+ block->lookup_reg = SSOW_AF_RVU_LF_HWS_CFG_DEBUG;
+ block->pf_lfcnt_reg = RVU_PRIV_PFX_SSOW_CFG;
+ block->vf_lfcnt_reg = RVU_PRIV_HWVFX_SSOW_CFG;
+ block->lfcfg_reg = SSOW_PRIV_LFX_HWS_CFG;
+ block->msixcfg_reg = SSOW_PRIV_LFX_HWS_INT_CFG;
+ block->lfreset_reg = SSOW_AF_LF_HWS_RST;
+ sprintf(block->name, "SSOWS");
+ err = rvu_alloc_bitmap(&block->lf);
+ if (err)
+ return err;
+
+tim:
+ /* Init TIM LF's bitmap */
+ block = &hw->block[BLKADDR_TIM];
+ if (!block->implemented)
+ goto cpt;
+ cfg = rvu_read64(rvu, BLKADDR_TIM, TIM_AF_CONST);
+ block->lf.max = cfg & 0xFFFF;
+ block->addr = BLKADDR_TIM;
+ block->type = BLKTYPE_TIM;
+ block->multislot = true;
+ block->lfshift = 3;
+ block->lookup_reg = TIM_AF_RVU_LF_CFG_DEBUG;
+ block->pf_lfcnt_reg = RVU_PRIV_PFX_TIM_CFG;
+ block->vf_lfcnt_reg = RVU_PRIV_HWVFX_TIM_CFG;
+ block->lfcfg_reg = TIM_PRIV_LFX_CFG;
+ block->msixcfg_reg = TIM_PRIV_LFX_INT_CFG;
+ block->lfreset_reg = TIM_AF_LF_RST;
+ sprintf(block->name, "TIM");
+ err = rvu_alloc_bitmap(&block->lf);
+ if (err)
+ return err;
+
+cpt:
+ /* Init CPT LF's bitmap */
+ block = &hw->block[BLKADDR_CPT0];
+ if (!block->implemented)
+ goto init;
+ cfg = rvu_read64(rvu, BLKADDR_CPT0, CPT_AF_CONSTANTS0);
+ block->lf.max = cfg & 0xFF;
+ block->addr = BLKADDR_CPT0;
+ block->type = BLKTYPE_CPT;
+ block->multislot = true;
+ block->lfshift = 3;
+ block->lookup_reg = CPT_AF_RVU_LF_CFG_DEBUG;
+ block->pf_lfcnt_reg = RVU_PRIV_PFX_CPT0_CFG;
+ block->vf_lfcnt_reg = RVU_PRIV_HWVFX_CPT0_CFG;
+ block->lfcfg_reg = CPT_PRIV_LFX_CFG;
+ block->msixcfg_reg = CPT_PRIV_LFX_INT_CFG;
+ block->lfreset_reg = CPT_AF_LF_RST;
+ sprintf(block->name, "CPT");
+ err = rvu_alloc_bitmap(&block->lf);
+ if (err)
+ return err;
+
+init:
+ /* Allocate memory for PFVF data */
+ rvu->pf = devm_kcalloc(rvu->dev, hw->total_pfs,
+ sizeof(struct rvu_pfvf), GFP_KERNEL);
+ if (!rvu->pf)
+ return -ENOMEM;
+
+ rvu->hwvf = devm_kcalloc(rvu->dev, hw->total_vfs,
+ sizeof(struct rvu_pfvf), GFP_KERNEL);
+ if (!rvu->hwvf)
+ return -ENOMEM;
+
+ spin_lock_init(&rvu->rsrc_lock);
+
+ err = rvu_setup_msix_resources(rvu);
+ if (err)
+ return err;
+
+ for (blkid = 0; blkid < BLK_COUNT; blkid++) {
+ block = &hw->block[blkid];
+ if (!block->lf.bmap)
+ continue;
+
+ /* Allocate memory for block LF/slot to pcifunc mapping info */
+ block->fn_map = devm_kcalloc(rvu->dev, block->lf.max,
+ sizeof(u16), GFP_KERNEL);
+ if (!block->fn_map)
+ return -ENOMEM;
+
+ /* Scan all blocks to check if low level firmware has
+ * already provisioned any of the resources to a PF/VF.
+ */
+ rvu_scan_block(rvu, block);
+ }
+
+ err = rvu_npc_init(rvu);
+ if (err)
+ return err;
+
+ err = rvu_npa_init(rvu);
+ if (err)
+ return err;
+
+ err = rvu_nix_init(rvu);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+/* NPA and NIX admin queue APIs */
+void rvu_aq_free(struct rvu *rvu, struct admin_queue *aq)
+{
+ if (!aq)
+ return;
+
+ qmem_free(rvu->dev, aq->inst);
+ qmem_free(rvu->dev, aq->res);
+ devm_kfree(rvu->dev, aq);
+}
+
+int rvu_aq_alloc(struct rvu *rvu, struct admin_queue **ad_queue,
+ int qsize, int inst_size, int res_size)
+{
+ struct admin_queue *aq;
+ int err;
+
+ *ad_queue = devm_kzalloc(rvu->dev, sizeof(*aq), GFP_KERNEL);
+ if (!*ad_queue)
+ return -ENOMEM;
+ aq = *ad_queue;
+
+ /* Alloc memory for instructions i.e AQ */
+ err = qmem_alloc(rvu->dev, &aq->inst, qsize, inst_size);
+ if (err) {
+ devm_kfree(rvu->dev, aq);
+ return err;
+ }
+
+ /* Alloc memory for results */
+ err = qmem_alloc(rvu->dev, &aq->res, qsize, res_size);
+ if (err) {
+ rvu_aq_free(rvu, aq);
+ return err;
+ }
+
+ spin_lock_init(&aq->lock);
+ return 0;
+}
+
+static int rvu_mbox_handler_READY(struct rvu *rvu, struct msg_req *req,
+ struct ready_msg_rsp *rsp)
+{
+ return 0;
+}
+
+/* Get current count of a RVU block's LF/slots
+ * provisioned to a given RVU func.
+ */
+static u16 rvu_get_rsrc_mapcount(struct rvu_pfvf *pfvf, int blktype)
+{
+ switch (blktype) {
+ case BLKTYPE_NPA:
+ return pfvf->npalf ? 1 : 0;
+ case BLKTYPE_NIX:
+ return pfvf->nixlf ? 1 : 0;
+ case BLKTYPE_SSO:
+ return pfvf->sso;
+ case BLKTYPE_SSOW:
+ return pfvf->ssow;
+ case BLKTYPE_TIM:
+ return pfvf->timlfs;
+ case BLKTYPE_CPT:
+ return pfvf->cptlfs;
+ }
+ return 0;
+}
+
+static int rvu_lookup_rsrc(struct rvu *rvu, struct rvu_block *block,
+ int pcifunc, int slot)
+{
+ u64 val;
+
+ val = ((u64)pcifunc << 24) | (slot << 16) | (1ULL << 13);
+ rvu_write64(rvu, block->addr, block->lookup_reg, val);
+ /* Wait for the lookup to finish */
+ /* TODO: put some timeout here */
+ while (rvu_read64(rvu, block->addr, block->lookup_reg) & (1ULL << 13))
+ ;
+
+ val = rvu_read64(rvu, block->addr, block->lookup_reg);
+
+ /* Check LF valid bit */
+ if (!(val & (1ULL << 12)))
+ return -1;
+
+ return (val & 0xFFF);
+}
+
+static void rvu_detach_block(struct rvu *rvu, int pcifunc, int blktype)
+{
+ struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, pcifunc);
+ struct rvu_hwinfo *hw = rvu->hw;
+ struct rvu_block *block;
+ int slot, lf, num_lfs;
+ int blkaddr;
+
+ blkaddr = rvu_get_blkaddr(rvu, blktype, pcifunc);
+ if (blkaddr < 0)
+ return;
+
+ block = &hw->block[blkaddr];
+
+ num_lfs = rvu_get_rsrc_mapcount(pfvf, block->type);
+ if (!num_lfs)
+ return;
+
+ for (slot = 0; slot < num_lfs; slot++) {
+ lf = rvu_lookup_rsrc(rvu, block, pcifunc, slot);
+ if (lf < 0) /* This should never happen */
+ continue;
+
+ /* Disable the LF */
+ rvu_write64(rvu, blkaddr, block->lfcfg_reg |
+ (lf << block->lfshift), 0x00ULL);
+
+ /* Update SW maintained mapping info as well */
+ rvu_update_rsrc_map(rvu, pfvf, block,
+ pcifunc, lf, false);
+
+ /* Free the resource */
+ rvu_free_rsrc(&block->lf, lf);
+
+ /* Clear MSIX vector offset for this LF */
+ rvu_clear_msix_offset(rvu, pfvf, block, lf);
+ }
+}
+
+static int rvu_detach_rsrcs(struct rvu *rvu, struct rsrc_detach *detach,
+ u16 pcifunc)
+{
+ struct rvu_hwinfo *hw = rvu->hw;
+ bool detach_all = true;
+ struct rvu_block *block;
+ int blkid;
+
+ spin_lock(&rvu->rsrc_lock);
+
+ /* Check for partial resource detach */
+ if (detach && detach->partial)
+ detach_all = false;
+
+ /* Check for RVU block's LFs attached to this func,
+ * if so, detach them.
+ */
+ for (blkid = 0; blkid < BLK_COUNT; blkid++) {
+ block = &hw->block[blkid];
+ if (!block->lf.bmap)
+ continue;
+ if (!detach_all && detach) {
+ if (blkid == BLKADDR_NPA && !detach->npalf)
+ continue;
+ else if ((blkid == BLKADDR_NIX0) && !detach->nixlf)
+ continue;
+ else if ((blkid == BLKADDR_SSO) && !detach->sso)
+ continue;
+ else if ((blkid == BLKADDR_SSOW) && !detach->ssow)
+ continue;
+ else if ((blkid == BLKADDR_TIM) && !detach->timlfs)
+ continue;
+ else if ((blkid == BLKADDR_CPT0) && !detach->cptlfs)
+ continue;
+ }
+ rvu_detach_block(rvu, pcifunc, block->type);
+ }
+
+ spin_unlock(&rvu->rsrc_lock);
+ return 0;
+}
+
+static int rvu_mbox_handler_DETACH_RESOURCES(struct rvu *rvu,
+ struct rsrc_detach *detach,
+ struct msg_rsp *rsp)
+{
+ return rvu_detach_rsrcs(rvu, detach, detach->hdr.pcifunc);
+}
+
+static void rvu_attach_block(struct rvu *rvu, int pcifunc,
+ int blktype, int num_lfs)
+{
+ struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, pcifunc);
+ struct rvu_hwinfo *hw = rvu->hw;
+ struct rvu_block *block;
+ int slot, lf;
+ int blkaddr;
+ u64 cfg;
+
+ if (!num_lfs)
+ return;
+
+ blkaddr = rvu_get_blkaddr(rvu, blktype, 0);
+ if (blkaddr < 0)
+ return;
+
+ block = &hw->block[blkaddr];
+ if (!block->lf.bmap)
+ return;
+
+ for (slot = 0; slot < num_lfs; slot++) {
+ /* Allocate the resource */
+ lf = rvu_alloc_rsrc(&block->lf);
+ if (lf < 0)
+ return;
+
+ cfg = (1ULL << 63) | (pcifunc << 8) | slot;
+ rvu_write64(rvu, blkaddr, block->lfcfg_reg |
+ (lf << block->lfshift), cfg);
+ rvu_update_rsrc_map(rvu, pfvf, block,
+ pcifunc, lf, true);
+
+ /* Set start MSIX vector for this LF within this PF/VF */
+ rvu_set_msix_offset(rvu, pfvf, block, lf);
+ }
+}
+
+static int rvu_check_rsrc_availability(struct rvu *rvu,
+ struct rsrc_attach *req, u16 pcifunc)
+{
+ struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, pcifunc);
+ struct rvu_hwinfo *hw = rvu->hw;
+ struct rvu_block *block;
+ int free_lfs, mappedlfs;
+
+ /* Only one NPA LF can be attached */
+ if (req->npalf && !rvu_get_rsrc_mapcount(pfvf, BLKTYPE_NPA)) {
+ block = &hw->block[BLKADDR_NPA];
+ free_lfs = rvu_rsrc_free_count(&block->lf);
+ if (!free_lfs)
+ goto fail;
+ } else if (req->npalf) {
+ dev_err(&rvu->pdev->dev,
+ "Func 0x%x: Invalid req, already has NPA\n",
+ pcifunc);
+ return -EINVAL;
+ }
+
+ /* Only one NIX LF can be attached */
+ if (req->nixlf && !rvu_get_rsrc_mapcount(pfvf, BLKTYPE_NIX)) {
+ block = &hw->block[BLKADDR_NIX0];
+ free_lfs = rvu_rsrc_free_count(&block->lf);
+ if (!free_lfs)
+ goto fail;
+ } else if (req->nixlf) {
+ dev_err(&rvu->pdev->dev,
+ "Func 0x%x: Invalid req, already has NIX\n",
+ pcifunc);
+ return -EINVAL;
+ }
+
+ if (req->sso) {
+ block = &hw->block[BLKADDR_SSO];
+ /* Is request within limits ? */
+ if (req->sso > block->lf.max) {
+ dev_err(&rvu->pdev->dev,
+ "Func 0x%x: Invalid SSO req, %d > max %d\n",
+ pcifunc, req->sso, block->lf.max);
+ return -EINVAL;
+ }
+ mappedlfs = rvu_get_rsrc_mapcount(pfvf, block->type);
+ free_lfs = rvu_rsrc_free_count(&block->lf);
+ /* Check if additional resources are available */
+ if (req->sso > mappedlfs &&
+ ((req->sso - mappedlfs) > free_lfs))
+ goto fail;
+ }
+
+ if (req->ssow) {
+ block = &hw->block[BLKADDR_SSOW];
+ if (req->ssow > block->lf.max) {
+ dev_err(&rvu->pdev->dev,
+ "Func 0x%x: Invalid SSOW req, %d > max %d\n",
+ pcifunc, req->sso, block->lf.max);
+ return -EINVAL;
+ }
+ mappedlfs = rvu_get_rsrc_mapcount(pfvf, block->type);
+ free_lfs = rvu_rsrc_free_count(&block->lf);
+ if (req->ssow > mappedlfs &&
+ ((req->ssow - mappedlfs) > free_lfs))
+ goto fail;
+ }
+
+ if (req->timlfs) {
+ block = &hw->block[BLKADDR_TIM];
+ if (req->timlfs > block->lf.max) {
+ dev_err(&rvu->pdev->dev,
+ "Func 0x%x: Invalid TIMLF req, %d > max %d\n",
+ pcifunc, req->timlfs, block->lf.max);
+ return -EINVAL;
+ }
+ mappedlfs = rvu_get_rsrc_mapcount(pfvf, block->type);
+ free_lfs = rvu_rsrc_free_count(&block->lf);
+ if (req->timlfs > mappedlfs &&
+ ((req->timlfs - mappedlfs) > free_lfs))
+ goto fail;
+ }
+
+ if (req->cptlfs) {
+ block = &hw->block[BLKADDR_CPT0];
+ if (req->cptlfs > block->lf.max) {
+ dev_err(&rvu->pdev->dev,
+ "Func 0x%x: Invalid CPTLF req, %d > max %d\n",
+ pcifunc, req->cptlfs, block->lf.max);
+ return -EINVAL;
+ }
+ mappedlfs = rvu_get_rsrc_mapcount(pfvf, block->type);
+ free_lfs = rvu_rsrc_free_count(&block->lf);
+ if (req->cptlfs > mappedlfs &&
+ ((req->cptlfs - mappedlfs) > free_lfs))
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ dev_info(rvu->dev, "Request for %s failed\n", block->name);
+ return -ENOSPC;
+}
+
+static int rvu_mbox_handler_ATTACH_RESOURCES(struct rvu *rvu,
+ struct rsrc_attach *attach,
+ struct msg_rsp *rsp)
+{
+ u16 pcifunc = attach->hdr.pcifunc;
+ int err;
+
+ /* If first request, detach all existing attached resources */
+ if (!attach->modify)
+ rvu_detach_rsrcs(rvu, NULL, pcifunc);
+
+ spin_lock(&rvu->rsrc_lock);
+
+ /* Check if the request can be accommodated */
+ err = rvu_check_rsrc_availability(rvu, attach, pcifunc);
+ if (err)
+ goto exit;
+
+ /* Now attach the requested resources */
+ if (attach->npalf)
+ rvu_attach_block(rvu, pcifunc, BLKTYPE_NPA, 1);
+
+ if (attach->nixlf)
+ rvu_attach_block(rvu, pcifunc, BLKTYPE_NIX, 1);
+
+ if (attach->sso) {
+ /* RVU func doesn't know which exact LF or slot is attached
+ * to it, it always sees as slot 0,1,2. So for a 'modify'
+ * request, simply detach all existing attached LFs/slots
+ * and attach a fresh.
+ */
+ if (attach->modify)
+ rvu_detach_block(rvu, pcifunc, BLKTYPE_SSO);
+ rvu_attach_block(rvu, pcifunc, BLKTYPE_SSO, attach->sso);
+ }
+
+ if (attach->ssow) {
+ if (attach->modify)
+ rvu_detach_block(rvu, pcifunc, BLKTYPE_SSOW);
+ rvu_attach_block(rvu, pcifunc, BLKTYPE_SSOW, attach->ssow);
+ }
+
+ if (attach->timlfs) {
+ if (attach->modify)
+ rvu_detach_block(rvu, pcifunc, BLKTYPE_TIM);
+ rvu_attach_block(rvu, pcifunc, BLKTYPE_TIM, attach->timlfs);
+ }
+
+ if (attach->cptlfs) {
+ if (attach->modify)
+ rvu_detach_block(rvu, pcifunc, BLKTYPE_CPT);
+ rvu_attach_block(rvu, pcifunc, BLKTYPE_CPT, attach->cptlfs);
+ }
+
+exit:
+ spin_unlock(&rvu->rsrc_lock);
+ return err;
+}
+
+static u16 rvu_get_msix_offset(struct rvu *rvu, struct rvu_pfvf *pfvf,
+ int blkaddr, int lf)
+{
+ u16 vec;
+
+ if (lf < 0)
+ return MSIX_VECTOR_INVALID;
+
+ for (vec = 0; vec < pfvf->msix.max; vec++) {
+ if (pfvf->msix_lfmap[vec] == MSIX_BLKLF(blkaddr, lf))
+ return vec;
+ }
+ return MSIX_VECTOR_INVALID;
+}
+
+static void rvu_set_msix_offset(struct rvu *rvu, struct rvu_pfvf *pfvf,
+ struct rvu_block *block, int lf)
+{
+ u16 nvecs, vec, offset;
+ u64 cfg;
+
+ cfg = rvu_read64(rvu, block->addr, block->msixcfg_reg |
+ (lf << block->lfshift));
+ nvecs = (cfg >> 12) & 0xFF;
+
+ /* Check and alloc MSIX vectors, must be contiguous */
+ if (!rvu_rsrc_check_contig(&pfvf->msix, nvecs))
+ return;
+
+ offset = rvu_alloc_rsrc_contig(&pfvf->msix, nvecs);
+
+ /* Config MSIX offset in LF */
+ rvu_write64(rvu, block->addr, block->msixcfg_reg |
+ (lf << block->lfshift), (cfg & ~0x7FFULL) | offset);
+
+ /* Update the bitmap as well */
+ for (vec = 0; vec < nvecs; vec++)
+ pfvf->msix_lfmap[offset + vec] = MSIX_BLKLF(block->addr, lf);
+}
+
+static void rvu_clear_msix_offset(struct rvu *rvu, struct rvu_pfvf *pfvf,
+ struct rvu_block *block, int lf)
+{
+ u16 nvecs, vec, offset;
+ u64 cfg;
+
+ cfg = rvu_read64(rvu, block->addr, block->msixcfg_reg |
+ (lf << block->lfshift));
+ nvecs = (cfg >> 12) & 0xFF;
+
+ /* Clear MSIX offset in LF */
+ rvu_write64(rvu, block->addr, block->msixcfg_reg |
+ (lf << block->lfshift), cfg & ~0x7FFULL);
+
+ offset = rvu_get_msix_offset(rvu, pfvf, block->addr, lf);
+
+ /* Update the mapping */
+ for (vec = 0; vec < nvecs; vec++)
+ pfvf->msix_lfmap[offset + vec] = 0;
+
+ /* Free the same in MSIX bitmap */
+ rvu_free_rsrc_contig(&pfvf->msix, nvecs, offset);
+}
+
+static int rvu_mbox_handler_MSIX_OFFSET(struct rvu *rvu, struct msg_req *req,
+ struct msix_offset_rsp *rsp)
+{
+ struct rvu_hwinfo *hw = rvu->hw;
+ u16 pcifunc = req->hdr.pcifunc;
+ struct rvu_pfvf *pfvf;
+ int lf, slot;
+
+ pfvf = rvu_get_pfvf(rvu, pcifunc);
+ if (!pfvf->msix.bmap)
+ return 0;
+
+ /* Set MSIX offsets for each block's LFs attached to this PF/VF */
+ lf = rvu_get_lf(rvu, &hw->block[BLKADDR_NPA], pcifunc, 0);
+ rsp->npa_msixoff = rvu_get_msix_offset(rvu, pfvf, BLKADDR_NPA, lf);
+
+ lf = rvu_get_lf(rvu, &hw->block[BLKADDR_NIX0], pcifunc, 0);
+ rsp->nix_msixoff = rvu_get_msix_offset(rvu, pfvf, BLKADDR_NIX0, lf);
+
+ rsp->sso = pfvf->sso;
+ for (slot = 0; slot < rsp->sso; slot++) {
+ lf = rvu_get_lf(rvu, &hw->block[BLKADDR_SSO], pcifunc, slot);
+ rsp->sso_msixoff[slot] =
+ rvu_get_msix_offset(rvu, pfvf, BLKADDR_SSO, lf);
+ }
+
+ rsp->ssow = pfvf->ssow;
+ for (slot = 0; slot < rsp->ssow; slot++) {
+ lf = rvu_get_lf(rvu, &hw->block[BLKADDR_SSOW], pcifunc, slot);
+ rsp->ssow_msixoff[slot] =
+ rvu_get_msix_offset(rvu, pfvf, BLKADDR_SSOW, lf);
+ }
+
+ rsp->timlfs = pfvf->timlfs;
+ for (slot = 0; slot < rsp->timlfs; slot++) {
+ lf = rvu_get_lf(rvu, &hw->block[BLKADDR_TIM], pcifunc, slot);
+ rsp->timlf_msixoff[slot] =
+ rvu_get_msix_offset(rvu, pfvf, BLKADDR_TIM, lf);
+ }
+
+ rsp->cptlfs = pfvf->cptlfs;
+ for (slot = 0; slot < rsp->cptlfs; slot++) {
+ lf = rvu_get_lf(rvu, &hw->block[BLKADDR_CPT0], pcifunc, slot);
+ rsp->cptlf_msixoff[slot] =
+ rvu_get_msix_offset(rvu, pfvf, BLKADDR_CPT0, lf);
+ }
+ return 0;
+}
+
+static int rvu_process_mbox_msg(struct rvu *rvu, int devid,
+ struct mbox_msghdr *req)
+{
+ /* Check if valid, if not reply with a invalid msg */
+ if (req->sig != OTX2_MBOX_REQ_SIG)
+ goto bad_message;
+
+ switch (req->id) {
+#define M(_name, _id, _req_type, _rsp_type) \
+ case _id: { \
+ struct _rsp_type *rsp; \
+ int err; \
+ \
+ rsp = (struct _rsp_type *)otx2_mbox_alloc_msg( \
+ &rvu->mbox, devid, \
+ sizeof(struct _rsp_type)); \
+ if (rsp) { \
+ rsp->hdr.id = _id; \
+ rsp->hdr.sig = OTX2_MBOX_RSP_SIG; \
+ rsp->hdr.pcifunc = req->pcifunc; \
+ rsp->hdr.rc = 0; \
+ } \
+ \
+ err = rvu_mbox_handler_ ## _name(rvu, \
+ (struct _req_type *)req, \
+ rsp); \
+ if (rsp && err) \
+ rsp->hdr.rc = err; \
+ \
+ return rsp ? err : -ENOMEM; \
+ }
+MBOX_MESSAGES
+#undef M
+ break;
+bad_message:
+ default:
+ otx2_reply_invalid_msg(&rvu->mbox, devid, req->pcifunc,
+ req->id);
+ return -ENODEV;
+ }
+}
+
+static void rvu_mbox_handler(struct work_struct *work)
+{
+ struct rvu_work *mwork = container_of(work, struct rvu_work, work);
+ struct rvu *rvu = mwork->rvu;
+ struct otx2_mbox_dev *mdev;
+ struct mbox_hdr *req_hdr;
+ struct mbox_msghdr *msg;
+ struct otx2_mbox *mbox;
+ int offset, id, err;
+ u16 pf;
+
+ mbox = &rvu->mbox;
+ pf = mwork - rvu->mbox_wrk;
+ mdev = &mbox->dev[pf];
+
+ /* Process received mbox messages */
+ req_hdr = mdev->mbase + mbox->rx_start;
+ if (req_hdr->num_msgs == 0)
+ return;
+
+ offset = mbox->rx_start + ALIGN(sizeof(*req_hdr), MBOX_MSG_ALIGN);
+
+ for (id = 0; id < req_hdr->num_msgs; id++) {
+ msg = mdev->mbase + offset;
+
+ /* Set which PF sent this message based on mbox IRQ */
+ msg->pcifunc &= ~(RVU_PFVF_PF_MASK << RVU_PFVF_PF_SHIFT);
+ msg->pcifunc |= (pf << RVU_PFVF_PF_SHIFT);
+ err = rvu_process_mbox_msg(rvu, pf, msg);
+ if (!err) {
+ offset = mbox->rx_start + msg->next_msgoff;
+ continue;
+ }
+
+ if (msg->pcifunc & RVU_PFVF_FUNC_MASK)
+ dev_warn(rvu->dev, "Error %d when processing message %s (0x%x) from PF%d:VF%d\n",
+ err, otx2_mbox_id2name(msg->id), msg->id, pf,
+ (msg->pcifunc & RVU_PFVF_FUNC_MASK) - 1);
+ else
+ dev_warn(rvu->dev, "Error %d when processing message %s (0x%x) from PF%d\n",
+ err, otx2_mbox_id2name(msg->id), msg->id, pf);
+ }
+
+ /* Send mbox responses to PF */
+ otx2_mbox_msg_send(mbox, pf);
+}
+
+static void rvu_mbox_up_handler(struct work_struct *work)
+{
+ struct rvu_work *mwork = container_of(work, struct rvu_work, work);
+ struct rvu *rvu = mwork->rvu;
+ struct otx2_mbox_dev *mdev;
+ struct mbox_hdr *rsp_hdr;
+ struct mbox_msghdr *msg;
+ struct otx2_mbox *mbox;
+ int offset, id;
+ u16 pf;
+
+ mbox = &rvu->mbox_up;
+ pf = mwork - rvu->mbox_wrk_up;
+ mdev = &mbox->dev[pf];
+
+ rsp_hdr = mdev->mbase + mbox->rx_start;
+ if (rsp_hdr->num_msgs == 0) {
+ dev_warn(rvu->dev, "mbox up handler: num_msgs = 0\n");
+ return;
+ }
+
+ offset = mbox->rx_start + ALIGN(sizeof(*rsp_hdr), MBOX_MSG_ALIGN);
+
+ for (id = 0; id < rsp_hdr->num_msgs; id++) {
+ msg = mdev->mbase + offset;
+
+ if (msg->id >= MBOX_MSG_MAX) {
+ dev_err(rvu->dev,
+ "Mbox msg with unknown ID 0x%x\n", msg->id);
+ goto end;
+ }
+
+ if (msg->sig != OTX2_MBOX_RSP_SIG) {
+ dev_err(rvu->dev,
+ "Mbox msg with wrong signature %x, ID 0x%x\n",
+ msg->sig, msg->id);
+ goto end;
+ }
+
+ switch (msg->id) {
+ case MBOX_MSG_CGX_LINK_EVENT:
+ break;
+ default:
+ if (msg->rc)
+ dev_err(rvu->dev,
+ "Mbox msg response has err %d, ID 0x%x\n",
+ msg->rc, msg->id);
+ break;
+ }
+end:
+ offset = mbox->rx_start + msg->next_msgoff;
+ mdev->msgs_acked++;
+ }
+
+ otx2_mbox_reset(mbox, 0);
+}
+
+static int rvu_mbox_init(struct rvu *rvu)
+{
+ struct rvu_hwinfo *hw = rvu->hw;
+ void __iomem *hwbase = NULL;
+ struct rvu_work *mwork;
+ u64 bar4_addr;
+ int err, pf;
+
+ rvu->mbox_wq = alloc_workqueue("rvu_afpf_mailbox",
+ WQ_UNBOUND | WQ_HIGHPRI | WQ_MEM_RECLAIM,
+ hw->total_pfs);
+ if (!rvu->mbox_wq)
+ return -ENOMEM;
+
+ rvu->mbox_wrk = devm_kcalloc(rvu->dev, hw->total_pfs,
+ sizeof(struct rvu_work), GFP_KERNEL);
+ if (!rvu->mbox_wrk) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ rvu->mbox_wrk_up = devm_kcalloc(rvu->dev, hw->total_pfs,
+ sizeof(struct rvu_work), GFP_KERNEL);
+ if (!rvu->mbox_wrk_up) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ /* Map mbox region shared with PFs */
+ bar4_addr = rvu_read64(rvu, BLKADDR_RVUM, RVU_AF_PF_BAR4_ADDR);
+ /* Mailbox is a reserved memory (in RAM) region shared between
+ * RVU devices, shouldn't be mapped as device memory to allow
+ * unaligned accesses.
+ */
+ hwbase = ioremap_wc(bar4_addr, MBOX_SIZE * hw->total_pfs);
+ if (!hwbase) {
+ dev_err(rvu->dev, "Unable to map mailbox region\n");
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ err = otx2_mbox_init(&rvu->mbox, hwbase, rvu->pdev, rvu->afreg_base,
+ MBOX_DIR_AFPF, hw->total_pfs);
+ if (err)
+ goto exit;
+
+ err = otx2_mbox_init(&rvu->mbox_up, hwbase, rvu->pdev, rvu->afreg_base,
+ MBOX_DIR_AFPF_UP, hw->total_pfs);
+ if (err)
+ goto exit;
+
+ for (pf = 0; pf < hw->total_pfs; pf++) {
+ mwork = &rvu->mbox_wrk[pf];
+ mwork->rvu = rvu;
+ INIT_WORK(&mwork->work, rvu_mbox_handler);
+ }
+
+ for (pf = 0; pf < hw->total_pfs; pf++) {
+ mwork = &rvu->mbox_wrk_up[pf];
+ mwork->rvu = rvu;
+ INIT_WORK(&mwork->work, rvu_mbox_up_handler);
+ }
+
+ return 0;
+exit:
+ if (hwbase)
+ iounmap((void __iomem *)hwbase);
+ destroy_workqueue(rvu->mbox_wq);
+ return err;
+}
+
+static void rvu_mbox_destroy(struct rvu *rvu)
+{
+ if (rvu->mbox_wq) {
+ flush_workqueue(rvu->mbox_wq);
+ destroy_workqueue(rvu->mbox_wq);
+ rvu->mbox_wq = NULL;
+ }
+
+ if (rvu->mbox.hwbase)
+ iounmap((void __iomem *)rvu->mbox.hwbase);
+
+ otx2_mbox_destroy(&rvu->mbox);
+ otx2_mbox_destroy(&rvu->mbox_up);
+}
+
+static irqreturn_t rvu_mbox_intr_handler(int irq, void *rvu_irq)
+{
+ struct rvu *rvu = (struct rvu *)rvu_irq;
+ struct otx2_mbox_dev *mdev;
+ struct otx2_mbox *mbox;
+ struct mbox_hdr *hdr;
+ u64 intr;
+ u8 pf;
+
+ intr = rvu_read64(rvu, BLKADDR_RVUM, RVU_AF_PFAF_MBOX_INT);
+ /* Clear interrupts */
+ rvu_write64(rvu, BLKADDR_RVUM, RVU_AF_PFAF_MBOX_INT, intr);
+
+ /* Sync with mbox memory region */
+ smp_wmb();
+
+ for (pf = 0; pf < rvu->hw->total_pfs; pf++) {
+ if (intr & (1ULL << pf)) {
+ mbox = &rvu->mbox;
+ mdev = &mbox->dev[pf];
+ hdr = mdev->mbase + mbox->rx_start;
+ if (hdr->num_msgs)
+ queue_work(rvu->mbox_wq,
+ &rvu->mbox_wrk[pf].work);
+ mbox = &rvu->mbox_up;
+ mdev = &mbox->dev[pf];
+ hdr = mdev->mbase + mbox->rx_start;
+ if (hdr->num_msgs)
+ queue_work(rvu->mbox_wq,
+ &rvu->mbox_wrk_up[pf].work);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void rvu_enable_mbox_intr(struct rvu *rvu)
+{
+ struct rvu_hwinfo *hw = rvu->hw;
+
+ /* Clear spurious irqs, if any */
+ rvu_write64(rvu, BLKADDR_RVUM,
+ RVU_AF_PFAF_MBOX_INT, INTR_MASK(hw->total_pfs));
+
+ /* Enable mailbox interrupt for all PFs except PF0 i.e AF itself */
+ rvu_write64(rvu, BLKADDR_RVUM, RVU_AF_PFAF_MBOX_INT_ENA_W1S,
+ INTR_MASK(hw->total_pfs) & ~1ULL);
+}
+
+static void rvu_unregister_interrupts(struct rvu *rvu)
+{
+ int irq;
+
+ /* Disable the Mbox interrupt */
+ rvu_write64(rvu, BLKADDR_RVUM, RVU_AF_PFAF_MBOX_INT_ENA_W1C,
+ INTR_MASK(rvu->hw->total_pfs) & ~1ULL);
+
+ for (irq = 0; irq < rvu->num_vec; irq++) {
+ if (rvu->irq_allocated[irq])
+ free_irq(pci_irq_vector(rvu->pdev, irq), rvu);
+ }
+
+ pci_free_irq_vectors(rvu->pdev);
+ rvu->num_vec = 0;
+}
+
+static int rvu_register_interrupts(struct rvu *rvu)
+{
+ int ret;
+
+ rvu->num_vec = pci_msix_vec_count(rvu->pdev);
+
+ rvu->irq_name = devm_kmalloc_array(rvu->dev, rvu->num_vec,
+ NAME_SIZE, GFP_KERNEL);
+ if (!rvu->irq_name)
+ return -ENOMEM;
+
+ rvu->irq_allocated = devm_kcalloc(rvu->dev, rvu->num_vec,
+ sizeof(bool), GFP_KERNEL);
+ if (!rvu->irq_allocated)
+ return -ENOMEM;
+
+ /* Enable MSI-X */
+ ret = pci_alloc_irq_vectors(rvu->pdev, rvu->num_vec,
+ rvu->num_vec, PCI_IRQ_MSIX);
+ if (ret < 0) {
+ dev_err(rvu->dev,
+ "RVUAF: Request for %d msix vectors failed, ret %d\n",
+ rvu->num_vec, ret);
+ return ret;
+ }
+
+ /* Register mailbox interrupt handler */
+ sprintf(&rvu->irq_name[RVU_AF_INT_VEC_MBOX * NAME_SIZE], "RVUAF Mbox");
+ ret = request_irq(pci_irq_vector(rvu->pdev, RVU_AF_INT_VEC_MBOX),
+ rvu_mbox_intr_handler, 0,
+ &rvu->irq_name[RVU_AF_INT_VEC_MBOX * NAME_SIZE], rvu);
+ if (ret) {
+ dev_err(rvu->dev,
+ "RVUAF: IRQ registration failed for mbox irq\n");
+ goto fail;
+ }
+
+ rvu->irq_allocated[RVU_AF_INT_VEC_MBOX] = true;
+
+ /* Enable mailbox interrupts from all PFs */
+ rvu_enable_mbox_intr(rvu);
+
+ return 0;
+
+fail:
+ pci_free_irq_vectors(rvu->pdev);
+ return ret;
+}
+
+static int rvu_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct device *dev = &pdev->dev;
+ struct rvu *rvu;
+ int err;
+
+ rvu = devm_kzalloc(dev, sizeof(*rvu), GFP_KERNEL);
+ if (!rvu)
+ return -ENOMEM;
+
+ rvu->hw = devm_kzalloc(dev, sizeof(struct rvu_hwinfo), GFP_KERNEL);
+ if (!rvu->hw) {
+ devm_kfree(dev, rvu);
+ return -ENOMEM;
+ }
+
+ pci_set_drvdata(pdev, rvu);
+ rvu->pdev = pdev;
+ rvu->dev = &pdev->dev;
+
+ err = pci_enable_device(pdev);
+ if (err) {
+ dev_err(dev, "Failed to enable PCI device\n");
+ goto err_freemem;
+ }
+
+ err = pci_request_regions(pdev, DRV_NAME);
+ if (err) {
+ dev_err(dev, "PCI request regions failed 0x%x\n", err);
+ goto err_disable_device;
+ }
+
+ err = pci_set_dma_mask(pdev, DMA_BIT_MASK(48));
+ if (err) {
+ dev_err(dev, "Unable to set DMA mask\n");
+ goto err_release_regions;
+ }
+
+ err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(48));
+ if (err) {
+ dev_err(dev, "Unable to set consistent DMA mask\n");
+ goto err_release_regions;
+ }
+
+ /* Map Admin function CSRs */
+ rvu->afreg_base = pcim_iomap(pdev, PCI_AF_REG_BAR_NUM, 0);
+ rvu->pfreg_base = pcim_iomap(pdev, PCI_PF_REG_BAR_NUM, 0);
+ if (!rvu->afreg_base || !rvu->pfreg_base) {
+ dev_err(dev, "Unable to map admin function CSRs, aborting\n");
+ err = -ENOMEM;
+ goto err_release_regions;
+ }
+
+ /* Check which blocks the HW supports */
+ rvu_check_block_implemented(rvu);
+
+ rvu_reset_all_blocks(rvu);
+
+ err = rvu_setup_hw_resources(rvu);
+ if (err)
+ goto err_release_regions;
+
+ err = rvu_mbox_init(rvu);
+ if (err)
+ goto err_hwsetup;
+
+ err = rvu_cgx_probe(rvu);
+ if (err)
+ goto err_mbox;
+
+ err = rvu_register_interrupts(rvu);
+ if (err)
+ goto err_cgx;
+
+ return 0;
+err_cgx:
+ rvu_cgx_wq_destroy(rvu);
+err_mbox:
+ rvu_mbox_destroy(rvu);
+err_hwsetup:
+ rvu_reset_all_blocks(rvu);
+ rvu_free_hw_resources(rvu);
+err_release_regions:
+ pci_release_regions(pdev);
+err_disable_device:
+ pci_disable_device(pdev);
+err_freemem:
+ pci_set_drvdata(pdev, NULL);
+ devm_kfree(&pdev->dev, rvu->hw);
+ devm_kfree(dev, rvu);
+ return err;
+}
+
+static void rvu_remove(struct pci_dev *pdev)
+{
+ struct rvu *rvu = pci_get_drvdata(pdev);
+
+ rvu_unregister_interrupts(rvu);
+ rvu_cgx_wq_destroy(rvu);
+ rvu_mbox_destroy(rvu);
+ rvu_reset_all_blocks(rvu);
+ rvu_free_hw_resources(rvu);
+
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+
+ devm_kfree(&pdev->dev, rvu->hw);
+ devm_kfree(&pdev->dev, rvu);
+}
+
+static struct pci_driver rvu_driver = {
+ .name = DRV_NAME,
+ .id_table = rvu_id_table,
+ .probe = rvu_probe,
+ .remove = rvu_remove,
+};
+
+static int __init rvu_init_module(void)
+{
+ int err;
+
+ pr_info("%s: %s\n", DRV_NAME, DRV_STRING);
+
+ err = pci_register_driver(&cgx_driver);
+ if (err < 0)
+ return err;
+
+ err = pci_register_driver(&rvu_driver);
+ if (err < 0)
+ pci_unregister_driver(&cgx_driver);
+
+ return err;
+}
+
+static void __exit rvu_cleanup_module(void)
+{
+ pci_unregister_driver(&rvu_driver);
+ pci_unregister_driver(&cgx_driver);
+}
+
+module_init(rvu_init_module);
+module_exit(rvu_cleanup_module);
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
new file mode 100644
index 000000000000..2c0580cd2807
--- /dev/null
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
@@ -0,0 +1,368 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * Marvell OcteonTx2 RVU Admin Function driver
+ *
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef RVU_H
+#define RVU_H
+
+#include "rvu_struct.h"
+#include "common.h"
+#include "mbox.h"
+
+/* PCI device IDs */
+#define PCI_DEVID_OCTEONTX2_RVU_AF 0xA065
+
+/* PCI BAR nos */
+#define PCI_AF_REG_BAR_NUM 0
+#define PCI_PF_REG_BAR_NUM 2
+#define PCI_MBOX_BAR_NUM 4
+
+#define NAME_SIZE 32
+
+/* PF_FUNC */
+#define RVU_PFVF_PF_SHIFT 10
+#define RVU_PFVF_PF_MASK 0x3F
+#define RVU_PFVF_FUNC_SHIFT 0
+#define RVU_PFVF_FUNC_MASK 0x3FF
+
+struct rvu_work {
+ struct work_struct work;
+ struct rvu *rvu;
+};
+
+struct rsrc_bmap {
+ unsigned long *bmap; /* Pointer to resource bitmap */
+ u16 max; /* Max resource id or count */
+};
+
+struct rvu_block {
+ struct rsrc_bmap lf;
+ struct admin_queue *aq; /* NIX/NPA AQ */
+ u16 *fn_map; /* LF to pcifunc mapping */
+ bool multislot;
+ bool implemented;
+ u8 addr; /* RVU_BLOCK_ADDR_E */
+ u8 type; /* RVU_BLOCK_TYPE_E */
+ u8 lfshift;
+ u64 lookup_reg;
+ u64 pf_lfcnt_reg;
+ u64 vf_lfcnt_reg;
+ u64 lfcfg_reg;
+ u64 msixcfg_reg;
+ u64 lfreset_reg;
+ unsigned char name[NAME_SIZE];
+};
+
+struct nix_mcast {
+ struct qmem *mce_ctx;
+ struct qmem *mcast_buf;
+ int replay_pkind;
+ int next_free_mce;
+ spinlock_t mce_lock; /* Serialize MCE updates */
+};
+
+struct nix_mce_list {
+ struct hlist_head head;
+ int count;
+ int max;
+};
+
+struct npc_mcam {
+ spinlock_t lock; /* MCAM entries and counters update lock */
+ u8 keysize; /* MCAM keysize 112/224/448 bits */
+ u8 banks; /* Number of MCAM banks */
+ u8 banks_per_entry;/* Number of keywords in key */
+ u16 banksize; /* Number of MCAM entries in each bank */
+ u16 total_entries; /* Total number of MCAM entries */
+ u16 entries; /* Total minus reserved for NIX LFs */
+ u16 nixlf_offset; /* Offset of nixlf rsvd uncast entries */
+ u16 pf_offset; /* Offset of PF's rsvd bcast, promisc entries */
+};
+
+/* Structure for per RVU func info ie PF/VF */
+struct rvu_pfvf {
+ bool npalf; /* Only one NPALF per RVU_FUNC */
+ bool nixlf; /* Only one NIXLF per RVU_FUNC */
+ u16 sso;
+ u16 ssow;
+ u16 cptlfs;
+ u16 timlfs;
+ u8 cgx_lmac;
+
+ /* Block LF's MSIX vector info */
+ struct rsrc_bmap msix; /* Bitmap for MSIX vector alloc */
+#define MSIX_BLKLF(blkaddr, lf) (((blkaddr) << 8) | ((lf) & 0xFF))
+ u16 *msix_lfmap; /* Vector to block LF mapping */
+
+ /* NPA contexts */
+ struct qmem *aura_ctx;
+ struct qmem *pool_ctx;
+ struct qmem *npa_qints_ctx;
+ unsigned long *aura_bmap;
+ unsigned long *pool_bmap;
+
+ /* NIX contexts */
+ struct qmem *rq_ctx;
+ struct qmem *sq_ctx;
+ struct qmem *cq_ctx;
+ struct qmem *rss_ctx;
+ struct qmem *cq_ints_ctx;
+ struct qmem *nix_qints_ctx;
+ unsigned long *sq_bmap;
+ unsigned long *rq_bmap;
+ unsigned long *cq_bmap;
+
+ u16 rx_chan_base;
+ u16 tx_chan_base;
+ u8 rx_chan_cnt; /* total number of RX channels */
+ u8 tx_chan_cnt; /* total number of TX channels */
+
+ u8 mac_addr[ETH_ALEN]; /* MAC address of this PF/VF */
+
+ /* Broadcast pkt replication info */
+ u16 bcast_mce_idx;
+ struct nix_mce_list bcast_mce_list;
+};
+
+struct nix_txsch {
+ struct rsrc_bmap schq;
+ u8 lvl;
+ u16 *pfvf_map;
+};
+
+struct npc_pkind {
+ struct rsrc_bmap rsrc;
+ u32 *pfchan_map;
+};
+
+struct nix_hw {
+ struct nix_txsch txsch[NIX_TXSCH_LVL_CNT]; /* Tx schedulers */
+ struct nix_mcast mcast;
+};
+
+struct rvu_hwinfo {
+ u8 total_pfs; /* MAX RVU PFs HW supports */
+ u16 total_vfs; /* Max RVU VFs HW supports */
+ u16 max_vfs_per_pf; /* Max VFs that can be attached to a PF */
+ u8 cgx;
+ u8 lmac_per_cgx;
+ u8 cgx_links;
+ u8 lbk_links;
+ u8 sdp_links;
+ u8 npc_kpus; /* No of parser units */
+
+
+ struct rvu_block block[BLK_COUNT]; /* Block info */
+ struct nix_hw *nix0;
+ struct npc_pkind pkind;
+ struct npc_mcam mcam;
+};
+
+struct rvu {
+ void __iomem *afreg_base;
+ void __iomem *pfreg_base;
+ struct pci_dev *pdev;
+ struct device *dev;
+ struct rvu_hwinfo *hw;
+ struct rvu_pfvf *pf;
+ struct rvu_pfvf *hwvf;
+ spinlock_t rsrc_lock; /* Serialize resource alloc/free */
+
+ /* Mbox */
+ struct otx2_mbox mbox;
+ struct rvu_work *mbox_wrk;
+ struct otx2_mbox mbox_up;
+ struct rvu_work *mbox_wrk_up;
+ struct workqueue_struct *mbox_wq;
+
+ /* MSI-X */
+ u16 num_vec;
+ char *irq_name;
+ bool *irq_allocated;
+ dma_addr_t msix_base_iova;
+
+ /* CGX */
+#define PF_CGXMAP_BASE 1 /* PF 0 is reserved for RVU PF */
+ u8 cgx_mapped_pfs;
+ u8 cgx_cnt; /* available cgx ports */
+ u8 *pf2cgxlmac_map; /* pf to cgx_lmac map */
+ u16 *cgxlmac2pf_map; /* bitmap of mapped pfs for
+ * every cgx lmac port
+ */
+ unsigned long pf_notify_bmap; /* Flags for PF notification */
+ void **cgx_idmap; /* cgx id to cgx data map table */
+ struct work_struct cgx_evh_work;
+ struct workqueue_struct *cgx_evh_wq;
+ spinlock_t cgx_evq_lock; /* cgx event queue lock */
+ struct list_head cgx_evq_head; /* cgx event queue head */
+};
+
+static inline void rvu_write64(struct rvu *rvu, u64 block, u64 offset, u64 val)
+{
+ writeq(val, rvu->afreg_base + ((block << 28) | offset));
+}
+
+static inline u64 rvu_read64(struct rvu *rvu, u64 block, u64 offset)
+{
+ return readq(rvu->afreg_base + ((block << 28) | offset));
+}
+
+static inline void rvupf_write64(struct rvu *rvu, u64 offset, u64 val)
+{
+ writeq(val, rvu->pfreg_base + offset);
+}
+
+static inline u64 rvupf_read64(struct rvu *rvu, u64 offset)
+{
+ return readq(rvu->pfreg_base + offset);
+}
+
+/* Function Prototypes
+ * 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);
+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);
+int rvu_get_pf(u16 pcifunc);
+struct rvu_pfvf *rvu_get_pfvf(struct rvu *rvu, int pcifunc);
+void rvu_get_pf_numvfs(struct rvu *rvu, int pf, int *numvfs, int *hwvf);
+bool is_block_implemented(struct rvu_hwinfo *hw, int blkaddr);
+int rvu_get_lf(struct rvu *rvu, struct rvu_block *block, u16 pcifunc, u16 slot);
+int rvu_lf_reset(struct rvu *rvu, struct rvu_block *block, int lf);
+int rvu_get_blkaddr(struct rvu *rvu, int blktype, u16 pcifunc);
+int rvu_poll_reg(struct rvu *rvu, u64 block, u64 offset, u64 mask, bool zero);
+
+/* RVU HW reg validation */
+enum regmap_block {
+ TXSCHQ_HWREGMAP = 0,
+ MAX_HWREGMAP,
+};
+
+bool rvu_check_valid_reg(int regmap, int regblk, u64 reg);
+
+/* NPA/NIX AQ APIs */
+int rvu_aq_alloc(struct rvu *rvu, struct admin_queue **ad_queue,
+ int qsize, int inst_size, int res_size);
+void rvu_aq_free(struct rvu *rvu, struct admin_queue *aq);
+
+/* CGX APIs */
+static inline bool is_pf_cgxmapped(struct rvu *rvu, u8 pf)
+{
+ return (pf >= PF_CGXMAP_BASE && pf <= rvu->cgx_mapped_pfs);
+}
+
+static inline void rvu_get_cgx_lmac_id(u8 map, u8 *cgx_id, u8 *lmac_id)
+{
+ *cgx_id = (map >> 4) & 0xF;
+ *lmac_id = (map & 0xF);
+}
+
+int rvu_cgx_probe(struct rvu *rvu);
+void rvu_cgx_wq_destroy(struct rvu *rvu);
+void *rvu_cgx_pdata(u8 cgx_id, struct rvu *rvu);
+int rvu_cgx_config_rxtx(struct rvu *rvu, u16 pcifunc, bool start);
+int rvu_mbox_handler_CGX_START_RXTX(struct rvu *rvu, struct msg_req *req,
+ struct msg_rsp *rsp);
+int rvu_mbox_handler_CGX_STOP_RXTX(struct rvu *rvu, struct msg_req *req,
+ struct msg_rsp *rsp);
+int rvu_mbox_handler_CGX_STATS(struct rvu *rvu, struct msg_req *req,
+ struct cgx_stats_rsp *rsp);
+int rvu_mbox_handler_CGX_MAC_ADDR_SET(struct rvu *rvu,
+ struct cgx_mac_addr_set_or_get *req,
+ struct cgx_mac_addr_set_or_get *rsp);
+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);
+int rvu_mbox_handler_CGX_PROMISC_ENABLE(struct rvu *rvu, struct msg_req *req,
+ struct msg_rsp *rsp);
+int rvu_mbox_handler_CGX_PROMISC_DISABLE(struct rvu *rvu, struct msg_req *req,
+ struct msg_rsp *rsp);
+int rvu_mbox_handler_CGX_START_LINKEVENTS(struct rvu *rvu, struct msg_req *req,
+ struct msg_rsp *rsp);
+int rvu_mbox_handler_CGX_STOP_LINKEVENTS(struct rvu *rvu, struct msg_req *req,
+ struct msg_rsp *rsp);
+int rvu_mbox_handler_CGX_GET_LINKINFO(struct rvu *rvu, struct msg_req *req,
+ struct cgx_link_info_msg *rsp);
+int rvu_mbox_handler_CGX_INTLBK_ENABLE(struct rvu *rvu, struct msg_req *req,
+ struct msg_rsp *rsp);
+int rvu_mbox_handler_CGX_INTLBK_DISABLE(struct rvu *rvu, struct msg_req *req,
+ struct msg_rsp *rsp);
+
+/* NPA APIs */
+int rvu_npa_init(struct rvu *rvu);
+void rvu_npa_freemem(struct rvu *rvu);
+int rvu_mbox_handler_NPA_AQ_ENQ(struct rvu *rvu,
+ struct npa_aq_enq_req *req,
+ struct npa_aq_enq_rsp *rsp);
+int rvu_mbox_handler_NPA_HWCTX_DISABLE(struct rvu *rvu,
+ struct hwctx_disable_req *req,
+ struct msg_rsp *rsp);
+int rvu_mbox_handler_NPA_LF_ALLOC(struct rvu *rvu,
+ struct npa_lf_alloc_req *req,
+ struct npa_lf_alloc_rsp *rsp);
+int rvu_mbox_handler_NPA_LF_FREE(struct rvu *rvu, struct msg_req *req,
+ struct msg_rsp *rsp);
+
+/* NIX APIs */
+int rvu_nix_init(struct rvu *rvu);
+void rvu_nix_freemem(struct rvu *rvu);
+int rvu_get_nixlf_count(struct rvu *rvu);
+int rvu_mbox_handler_NIX_LF_ALLOC(struct rvu *rvu,
+ struct nix_lf_alloc_req *req,
+ struct nix_lf_alloc_rsp *rsp);
+int rvu_mbox_handler_NIX_LF_FREE(struct rvu *rvu, struct msg_req *req,
+ struct msg_rsp *rsp);
+int rvu_mbox_handler_NIX_AQ_ENQ(struct rvu *rvu,
+ struct nix_aq_enq_req *req,
+ struct nix_aq_enq_rsp *rsp);
+int rvu_mbox_handler_NIX_HWCTX_DISABLE(struct rvu *rvu,
+ struct hwctx_disable_req *req,
+ struct msg_rsp *rsp);
+int rvu_mbox_handler_NIX_TXSCH_ALLOC(struct rvu *rvu,
+ struct nix_txsch_alloc_req *req,
+ struct nix_txsch_alloc_rsp *rsp);
+int rvu_mbox_handler_NIX_TXSCH_FREE(struct rvu *rvu,
+ struct nix_txsch_free_req *req,
+ struct msg_rsp *rsp);
+int rvu_mbox_handler_NIX_TXSCHQ_CFG(struct rvu *rvu,
+ struct nix_txschq_config *req,
+ struct msg_rsp *rsp);
+int rvu_mbox_handler_NIX_STATS_RST(struct rvu *rvu, struct msg_req *req,
+ struct msg_rsp *rsp);
+int rvu_mbox_handler_NIX_VTAG_CFG(struct rvu *rvu,
+ struct nix_vtag_config *req,
+ struct msg_rsp *rsp);
+int rvu_mbox_handler_NIX_RSS_FLOWKEY_CFG(struct rvu *rvu,
+ struct nix_rss_flowkey_cfg *req,
+ struct msg_rsp *rsp);
+int rvu_mbox_handler_NIX_SET_MAC_ADDR(struct rvu *rvu,
+ struct nix_set_mac_addr *req,
+ struct msg_rsp *rsp);
+int rvu_mbox_handler_NIX_SET_RX_MODE(struct rvu *rvu, struct nix_rx_mode *req,
+ struct msg_rsp *rsp);
+
+/* NPC APIs */
+int rvu_npc_init(struct rvu *rvu);
+void rvu_npc_freemem(struct rvu *rvu);
+int rvu_npc_get_pkind(struct rvu *rvu, u16 pf);
+void rvu_npc_set_pkind(struct rvu *rvu, int pkind, struct rvu_pfvf *pfvf);
+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, bool allmulti);
+void rvu_npc_disable_promisc_entry(struct rvu *rvu, u16 pcifunc, int nixlf);
+void rvu_npc_install_bcast_match_entry(struct rvu *rvu, u16 pcifunc,
+ int nixlf, u64 chan);
+void rvu_npc_disable_mcam_entries(struct rvu *rvu, u16 pcifunc, int nixlf);
+void rvu_npc_update_flowkey_alg_idx(struct rvu *rvu, u16 pcifunc, int nixlf,
+ int group, int alg_idx, int mcam_index);
+#endif /* RVU_H */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c
new file mode 100644
index 000000000000..188185c15b4a
--- /dev/null
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c
@@ -0,0 +1,515 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Marvell OcteonTx2 RVU Admin Function driver
+ *
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include "rvu.h"
+#include "cgx.h"
+
+struct cgx_evq_entry {
+ struct list_head evq_node;
+ struct cgx_link_event link_event;
+};
+
+#define M(_name, _id, _req_type, _rsp_type) \
+static struct _req_type __maybe_unused \
+*otx2_mbox_alloc_msg_ ## _name(struct rvu *rvu, int devid) \
+{ \
+ struct _req_type *req; \
+ \
+ req = (struct _req_type *)otx2_mbox_alloc_msg_rsp( \
+ &rvu->mbox_up, devid, sizeof(struct _req_type), \
+ sizeof(struct _rsp_type)); \
+ if (!req) \
+ return NULL; \
+ req->hdr.sig = OTX2_MBOX_REQ_SIG; \
+ req->hdr.id = _id; \
+ return req; \
+}
+
+MBOX_UP_CGX_MESSAGES
+#undef M
+
+/* Returns bitmap of mapped PFs */
+static inline u16 cgxlmac_to_pfmap(struct rvu *rvu, u8 cgx_id, u8 lmac_id)
+{
+ return rvu->cgxlmac2pf_map[CGX_OFFSET(cgx_id) + lmac_id];
+}
+
+static inline u8 cgxlmac_id_to_bmap(u8 cgx_id, u8 lmac_id)
+{
+ return ((cgx_id & 0xF) << 4) | (lmac_id & 0xF);
+}
+
+void *rvu_cgx_pdata(u8 cgx_id, struct rvu *rvu)
+{
+ if (cgx_id >= rvu->cgx_cnt)
+ return NULL;
+
+ return rvu->cgx_idmap[cgx_id];
+}
+
+static int rvu_map_cgx_lmac_pf(struct rvu *rvu)
+{
+ struct npc_pkind *pkind = &rvu->hw->pkind;
+ int cgx_cnt = rvu->cgx_cnt;
+ int cgx, lmac_cnt, lmac;
+ int pf = PF_CGXMAP_BASE;
+ int size, free_pkind;
+
+ if (!cgx_cnt)
+ return 0;
+
+ if (cgx_cnt > 0xF || MAX_LMAC_PER_CGX > 0xF)
+ return -EINVAL;
+
+ /* Alloc map table
+ * An additional entry is required since PF id starts from 1 and
+ * hence entry at offset 0 is invalid.
+ */
+ size = (cgx_cnt * MAX_LMAC_PER_CGX + 1) * sizeof(u8);
+ rvu->pf2cgxlmac_map = devm_kzalloc(rvu->dev, size, GFP_KERNEL);
+ if (!rvu->pf2cgxlmac_map)
+ return -ENOMEM;
+
+ /* Initialize offset 0 with an invalid cgx and lmac id */
+ rvu->pf2cgxlmac_map[0] = 0xFF;
+
+ /* Reverse map table */
+ rvu->cgxlmac2pf_map = devm_kzalloc(rvu->dev,
+ cgx_cnt * MAX_LMAC_PER_CGX * sizeof(u16),
+ GFP_KERNEL);
+ if (!rvu->cgxlmac2pf_map)
+ return -ENOMEM;
+
+ rvu->cgx_mapped_pfs = 0;
+ for (cgx = 0; cgx < cgx_cnt; cgx++) {
+ lmac_cnt = cgx_get_lmac_cnt(rvu_cgx_pdata(cgx, rvu));
+ for (lmac = 0; lmac < lmac_cnt; lmac++, pf++) {
+ rvu->pf2cgxlmac_map[pf] = cgxlmac_id_to_bmap(cgx, lmac);
+ rvu->cgxlmac2pf_map[CGX_OFFSET(cgx) + lmac] = 1 << pf;
+ free_pkind = rvu_alloc_rsrc(&pkind->rsrc);
+ pkind->pfchan_map[free_pkind] = ((pf) & 0x3F) << 16;
+ rvu->cgx_mapped_pfs++;
+ }
+ }
+ return 0;
+}
+
+static int rvu_cgx_send_link_info(int cgx_id, int lmac_id, struct rvu *rvu)
+{
+ struct cgx_evq_entry *qentry;
+ unsigned long flags;
+ int err;
+
+ qentry = kmalloc(sizeof(*qentry), GFP_KERNEL);
+ if (!qentry)
+ return -ENOMEM;
+
+ /* Lock the event queue before we read the local link status */
+ spin_lock_irqsave(&rvu->cgx_evq_lock, flags);
+ err = cgx_get_link_info(rvu_cgx_pdata(cgx_id, rvu), lmac_id,
+ &qentry->link_event.link_uinfo);
+ qentry->link_event.cgx_id = cgx_id;
+ qentry->link_event.lmac_id = lmac_id;
+ if (err)
+ goto skip_add;
+ list_add_tail(&qentry->evq_node, &rvu->cgx_evq_head);
+skip_add:
+ spin_unlock_irqrestore(&rvu->cgx_evq_lock, flags);
+
+ /* start worker to process the events */
+ queue_work(rvu->cgx_evh_wq, &rvu->cgx_evh_work);
+
+ return 0;
+}
+
+/* This is called from interrupt context and is expected to be atomic */
+static int cgx_lmac_postevent(struct cgx_link_event *event, void *data)
+{
+ struct cgx_evq_entry *qentry;
+ struct rvu *rvu = data;
+
+ /* post event to the event queue */
+ qentry = kmalloc(sizeof(*qentry), GFP_ATOMIC);
+ if (!qentry)
+ return -ENOMEM;
+ qentry->link_event = *event;
+ spin_lock(&rvu->cgx_evq_lock);
+ list_add_tail(&qentry->evq_node, &rvu->cgx_evq_head);
+ spin_unlock(&rvu->cgx_evq_lock);
+
+ /* start worker to process the events */
+ queue_work(rvu->cgx_evh_wq, &rvu->cgx_evh_work);
+
+ return 0;
+}
+
+static void cgx_notify_pfs(struct cgx_link_event *event, struct rvu *rvu)
+{
+ struct cgx_link_user_info *linfo;
+ struct cgx_link_info_msg *msg;
+ unsigned long pfmap;
+ int err, pfid;
+
+ linfo = &event->link_uinfo;
+ pfmap = cgxlmac_to_pfmap(rvu, event->cgx_id, event->lmac_id);
+
+ do {
+ pfid = find_first_bit(&pfmap, 16);
+ clear_bit(pfid, &pfmap);
+
+ /* check if notification is enabled */
+ if (!test_bit(pfid, &rvu->pf_notify_bmap)) {
+ dev_info(rvu->dev, "cgx %d: lmac %d Link status %s\n",
+ event->cgx_id, event->lmac_id,
+ linfo->link_up ? "UP" : "DOWN");
+ continue;
+ }
+
+ /* Send mbox message to PF */
+ msg = otx2_mbox_alloc_msg_CGX_LINK_EVENT(rvu, pfid);
+ if (!msg)
+ continue;
+ msg->link_info = *linfo;
+ otx2_mbox_msg_send(&rvu->mbox_up, pfid);
+ err = otx2_mbox_wait_for_rsp(&rvu->mbox_up, pfid);
+ if (err)
+ dev_warn(rvu->dev, "notification to pf %d failed\n",
+ pfid);
+ } while (pfmap);
+}
+
+static void cgx_evhandler_task(struct work_struct *work)
+{
+ struct rvu *rvu = container_of(work, struct rvu, cgx_evh_work);
+ struct cgx_evq_entry *qentry;
+ struct cgx_link_event *event;
+ unsigned long flags;
+
+ do {
+ /* Dequeue an event */
+ spin_lock_irqsave(&rvu->cgx_evq_lock, flags);
+ qentry = list_first_entry_or_null(&rvu->cgx_evq_head,
+ struct cgx_evq_entry,
+ evq_node);
+ if (qentry)
+ list_del(&qentry->evq_node);
+ spin_unlock_irqrestore(&rvu->cgx_evq_lock, flags);
+ if (!qentry)
+ break; /* nothing more to process */
+
+ event = &qentry->link_event;
+
+ /* process event */
+ cgx_notify_pfs(event, rvu);
+ kfree(qentry);
+ } while (1);
+}
+
+static void cgx_lmac_event_handler_init(struct rvu *rvu)
+{
+ struct cgx_event_cb cb;
+ int cgx, lmac, err;
+ void *cgxd;
+
+ spin_lock_init(&rvu->cgx_evq_lock);
+ INIT_LIST_HEAD(&rvu->cgx_evq_head);
+ INIT_WORK(&rvu->cgx_evh_work, cgx_evhandler_task);
+ rvu->cgx_evh_wq = alloc_workqueue("rvu_evh_wq", 0, 0);
+ if (!rvu->cgx_evh_wq) {
+ dev_err(rvu->dev, "alloc workqueue failed");
+ return;
+ }
+
+ cb.notify_link_chg = cgx_lmac_postevent; /* link change call back */
+ cb.data = rvu;
+
+ for (cgx = 0; cgx < rvu->cgx_cnt; cgx++) {
+ cgxd = rvu_cgx_pdata(cgx, rvu);
+ for (lmac = 0; lmac < cgx_get_lmac_cnt(cgxd); lmac++) {
+ err = cgx_lmac_evh_register(&cb, cgxd, lmac);
+ if (err)
+ dev_err(rvu->dev,
+ "%d:%d handler register failed\n",
+ cgx, lmac);
+ }
+ }
+}
+
+void rvu_cgx_wq_destroy(struct rvu *rvu)
+{
+ if (rvu->cgx_evh_wq) {
+ flush_workqueue(rvu->cgx_evh_wq);
+ destroy_workqueue(rvu->cgx_evh_wq);
+ rvu->cgx_evh_wq = NULL;
+ }
+}
+
+int rvu_cgx_probe(struct rvu *rvu)
+{
+ int i, err;
+
+ /* find available cgx ports */
+ rvu->cgx_cnt = cgx_get_cgx_cnt();
+ if (!rvu->cgx_cnt) {
+ dev_info(rvu->dev, "No CGX devices found!\n");
+ return -ENODEV;
+ }
+
+ rvu->cgx_idmap = devm_kzalloc(rvu->dev, rvu->cgx_cnt * sizeof(void *),
+ GFP_KERNEL);
+ if (!rvu->cgx_idmap)
+ return -ENOMEM;
+
+ /* Initialize the cgxdata table */
+ for (i = 0; i < rvu->cgx_cnt; i++)
+ rvu->cgx_idmap[i] = cgx_get_pdata(i);
+
+ /* Map CGX LMAC interfaces to RVU PFs */
+ err = rvu_map_cgx_lmac_pf(rvu);
+ if (err)
+ return err;
+
+ /* Register for CGX events */
+ cgx_lmac_event_handler_init(rvu);
+ return 0;
+}
+
+int rvu_cgx_config_rxtx(struct rvu *rvu, u16 pcifunc, bool start)
+{
+ int pf = rvu_get_pf(pcifunc);
+ u8 cgx_id, lmac_id;
+
+ /* This msg is expected only from PFs that are mapped to CGX LMACs,
+ * if received from other PF/VF simply ACK, nothing to do.
+ */
+ if ((pcifunc & RVU_PFVF_FUNC_MASK) || !is_pf_cgxmapped(rvu, pf))
+ return -ENODEV;
+
+ rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
+
+ cgx_lmac_rx_tx_enable(rvu_cgx_pdata(cgx_id, rvu), lmac_id, start);
+
+ return 0;
+}
+
+int rvu_mbox_handler_CGX_START_RXTX(struct rvu *rvu, struct msg_req *req,
+ struct msg_rsp *rsp)
+{
+ rvu_cgx_config_rxtx(rvu, req->hdr.pcifunc, true);
+ return 0;
+}
+
+int rvu_mbox_handler_CGX_STOP_RXTX(struct rvu *rvu, struct msg_req *req,
+ struct msg_rsp *rsp)
+{
+ rvu_cgx_config_rxtx(rvu, req->hdr.pcifunc, false);
+ return 0;
+}
+
+int rvu_mbox_handler_CGX_STATS(struct rvu *rvu, struct msg_req *req,
+ struct cgx_stats_rsp *rsp)
+{
+ int pf = rvu_get_pf(req->hdr.pcifunc);
+ int stat = 0, err = 0;
+ u64 tx_stat, rx_stat;
+ u8 cgx_idx, lmac;
+ void *cgxd;
+
+ if ((req->hdr.pcifunc & RVU_PFVF_FUNC_MASK) ||
+ !is_pf_cgxmapped(rvu, pf))
+ return -ENODEV;
+
+ rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_idx, &lmac);
+ cgxd = rvu_cgx_pdata(cgx_idx, rvu);
+
+ /* Rx stats */
+ while (stat < CGX_RX_STATS_COUNT) {
+ err = cgx_get_rx_stats(cgxd, lmac, stat, &rx_stat);
+ if (err)
+ return err;
+ rsp->rx_stats[stat] = rx_stat;
+ stat++;
+ }
+
+ /* Tx stats */
+ stat = 0;
+ while (stat < CGX_TX_STATS_COUNT) {
+ err = cgx_get_tx_stats(cgxd, lmac, stat, &tx_stat);
+ if (err)
+ return err;
+ rsp->tx_stats[stat] = tx_stat;
+ stat++;
+ }
+ return 0;
+}
+
+int rvu_mbox_handler_CGX_MAC_ADDR_SET(struct rvu *rvu,
+ struct cgx_mac_addr_set_or_get *req,
+ struct cgx_mac_addr_set_or_get *rsp)
+{
+ int pf = rvu_get_pf(req->hdr.pcifunc);
+ u8 cgx_id, lmac_id;
+
+ rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
+
+ cgx_lmac_addr_set(cgx_id, lmac_id, req->mac_addr);
+
+ 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)
+{
+ int pf = rvu_get_pf(req->hdr.pcifunc);
+ u8 cgx_id, lmac_id;
+ int rc = 0, i;
+ u64 cfg;
+
+ rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
+
+ rsp->hdr.rc = rc;
+ cfg = cgx_lmac_addr_get(cgx_id, lmac_id);
+ /* copy 48 bit mac address to req->mac_addr */
+ for (i = 0; i < ETH_ALEN; i++)
+ rsp->mac_addr[i] = cfg >> (ETH_ALEN - 1 - i) * 8;
+ return 0;
+}
+
+int rvu_mbox_handler_CGX_PROMISC_ENABLE(struct rvu *rvu, struct msg_req *req,
+ struct msg_rsp *rsp)
+{
+ u16 pcifunc = req->hdr.pcifunc;
+ int pf = rvu_get_pf(pcifunc);
+ u8 cgx_id, lmac_id;
+
+ /* This msg is expected only from PFs that are mapped to CGX LMACs,
+ * if received from other PF/VF simply ACK, nothing to do.
+ */
+ if ((req->hdr.pcifunc & RVU_PFVF_FUNC_MASK) ||
+ !is_pf_cgxmapped(rvu, pf))
+ return -ENODEV;
+
+ rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
+
+ cgx_lmac_promisc_config(cgx_id, lmac_id, true);
+ return 0;
+}
+
+int rvu_mbox_handler_CGX_PROMISC_DISABLE(struct rvu *rvu, struct msg_req *req,
+ struct msg_rsp *rsp)
+{
+ u16 pcifunc = req->hdr.pcifunc;
+ int pf = rvu_get_pf(pcifunc);
+ u8 cgx_id, lmac_id;
+
+ /* This msg is expected only from PFs that are mapped to CGX LMACs,
+ * if received from other PF/VF simply ACK, nothing to do.
+ */
+ if ((req->hdr.pcifunc & RVU_PFVF_FUNC_MASK) ||
+ !is_pf_cgxmapped(rvu, pf))
+ return -ENODEV;
+
+ rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
+
+ cgx_lmac_promisc_config(cgx_id, lmac_id, false);
+ return 0;
+}
+
+static int rvu_cgx_config_linkevents(struct rvu *rvu, u16 pcifunc, bool en)
+{
+ int pf = rvu_get_pf(pcifunc);
+ u8 cgx_id, lmac_id;
+
+ /* This msg is expected only from PFs that are mapped to CGX LMACs,
+ * if received from other PF/VF simply ACK, nothing to do.
+ */
+ if ((pcifunc & RVU_PFVF_FUNC_MASK) || !is_pf_cgxmapped(rvu, pf))
+ return -ENODEV;
+
+ rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
+
+ if (en) {
+ set_bit(pf, &rvu->pf_notify_bmap);
+ /* Send the current link status to PF */
+ rvu_cgx_send_link_info(cgx_id, lmac_id, rvu);
+ } else {
+ clear_bit(pf, &rvu->pf_notify_bmap);
+ }
+
+ return 0;
+}
+
+int rvu_mbox_handler_CGX_START_LINKEVENTS(struct rvu *rvu, struct msg_req *req,
+ struct msg_rsp *rsp)
+{
+ rvu_cgx_config_linkevents(rvu, req->hdr.pcifunc, true);
+ return 0;
+}
+
+int rvu_mbox_handler_CGX_STOP_LINKEVENTS(struct rvu *rvu, struct msg_req *req,
+ struct msg_rsp *rsp)
+{
+ rvu_cgx_config_linkevents(rvu, req->hdr.pcifunc, false);
+ return 0;
+}
+
+int rvu_mbox_handler_CGX_GET_LINKINFO(struct rvu *rvu, struct msg_req *req,
+ struct cgx_link_info_msg *rsp)
+{
+ u8 cgx_id, lmac_id;
+ int pf, err;
+
+ pf = rvu_get_pf(req->hdr.pcifunc);
+
+ if (!is_pf_cgxmapped(rvu, pf))
+ return -ENODEV;
+
+ rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
+
+ err = cgx_get_link_info(rvu_cgx_pdata(cgx_id, rvu), lmac_id,
+ &rsp->link_info);
+ return err;
+}
+
+static int rvu_cgx_config_intlbk(struct rvu *rvu, u16 pcifunc, bool en)
+{
+ int pf = rvu_get_pf(pcifunc);
+ u8 cgx_id, lmac_id;
+
+ /* This msg is expected only from PFs that are mapped to CGX LMACs,
+ * if received from other PF/VF simply ACK, nothing to do.
+ */
+ if ((pcifunc & RVU_PFVF_FUNC_MASK) || !is_pf_cgxmapped(rvu, pf))
+ return -ENODEV;
+
+ rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
+
+ return cgx_lmac_internal_loopback(rvu_cgx_pdata(cgx_id, rvu),
+ lmac_id, en);
+}
+
+int rvu_mbox_handler_CGX_INTLBK_ENABLE(struct rvu *rvu, struct msg_req *req,
+ struct msg_rsp *rsp)
+{
+ rvu_cgx_config_intlbk(rvu, req->hdr.pcifunc, true);
+ return 0;
+}
+
+int rvu_mbox_handler_CGX_INTLBK_DISABLE(struct rvu *rvu, struct msg_req *req,
+ struct msg_rsp *rsp)
+{
+ rvu_cgx_config_intlbk(rvu, req->hdr.pcifunc, false);
+ return 0;
+}
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
new file mode 100644
index 000000000000..a5ab7eff2301
--- /dev/null
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
@@ -0,0 +1,1959 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Marvell OcteonTx2 RVU Admin Function driver
+ *
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include "rvu_struct.h"
+#include "rvu_reg.h"
+#include "rvu.h"
+#include "npc.h"
+#include "cgx.h"
+
+static int nix_update_bcast_mce_list(struct rvu *rvu, u16 pcifunc, bool add);
+
+enum mc_tbl_sz {
+ MC_TBL_SZ_256,
+ MC_TBL_SZ_512,
+ MC_TBL_SZ_1K,
+ MC_TBL_SZ_2K,
+ MC_TBL_SZ_4K,
+ MC_TBL_SZ_8K,
+ MC_TBL_SZ_16K,
+ MC_TBL_SZ_32K,
+ MC_TBL_SZ_64K,
+};
+
+enum mc_buf_cnt {
+ MC_BUF_CNT_8,
+ MC_BUF_CNT_16,
+ MC_BUF_CNT_32,
+ MC_BUF_CNT_64,
+ MC_BUF_CNT_128,
+ MC_BUF_CNT_256,
+ MC_BUF_CNT_512,
+ MC_BUF_CNT_1024,
+ MC_BUF_CNT_2048,
+};
+
+/* For now considering MC resources needed for broadcast
+ * pkt replication only. i.e 256 HWVFs + 12 PFs.
+ */
+#define MC_TBL_SIZE MC_TBL_SZ_512
+#define MC_BUF_CNT MC_BUF_CNT_128
+
+struct mce {
+ struct hlist_node node;
+ u16 idx;
+ u16 pcifunc;
+};
+
+int rvu_get_nixlf_count(struct rvu *rvu)
+{
+ struct rvu_block *block;
+ int blkaddr;
+
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, 0);
+ if (blkaddr < 0)
+ return 0;
+ block = &rvu->hw->block[blkaddr];
+ return block->lf.max;
+}
+
+static void nix_mce_list_init(struct nix_mce_list *list, int max)
+{
+ INIT_HLIST_HEAD(&list->head);
+ list->count = 0;
+ list->max = max;
+}
+
+static u16 nix_alloc_mce_list(struct nix_mcast *mcast, int count)
+{
+ int idx;
+
+ if (!mcast)
+ return 0;
+
+ idx = mcast->next_free_mce;
+ mcast->next_free_mce += count;
+ return idx;
+}
+
+static inline struct nix_hw *get_nix_hw(struct rvu_hwinfo *hw, int blkaddr)
+{
+ if (blkaddr == BLKADDR_NIX0 && hw->nix0)
+ return hw->nix0;
+
+ return NULL;
+}
+
+static bool is_valid_txschq(struct rvu *rvu, int blkaddr,
+ int lvl, u16 pcifunc, u16 schq)
+{
+ struct nix_txsch *txsch;
+ struct nix_hw *nix_hw;
+
+ nix_hw = get_nix_hw(rvu->hw, blkaddr);
+ if (!nix_hw)
+ return false;
+
+ txsch = &nix_hw->txsch[lvl];
+ /* Check out of bounds */
+ if (schq >= txsch->schq.max)
+ return false;
+
+ spin_lock(&rvu->rsrc_lock);
+ if (txsch->pfvf_map[schq] != pcifunc) {
+ spin_unlock(&rvu->rsrc_lock);
+ return false;
+ }
+ spin_unlock(&rvu->rsrc_lock);
+ return true;
+}
+
+static int nix_interface_init(struct rvu *rvu, u16 pcifunc, int type, int nixlf)
+{
+ struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, pcifunc);
+ u8 cgx_id, lmac_id;
+ int pkind, pf;
+ int err;
+
+ pf = rvu_get_pf(pcifunc);
+ if (!is_pf_cgxmapped(rvu, pf) && type != NIX_INTF_TYPE_LBK)
+ return 0;
+
+ switch (type) {
+ case NIX_INTF_TYPE_CGX:
+ pfvf->cgx_lmac = rvu->pf2cgxlmac_map[pf];
+ rvu_get_cgx_lmac_id(pfvf->cgx_lmac, &cgx_id, &lmac_id);
+
+ pkind = rvu_npc_get_pkind(rvu, pf);
+ if (pkind < 0) {
+ dev_err(rvu->dev,
+ "PF_Func 0x%x: Invalid pkind\n", pcifunc);
+ return -EINVAL;
+ }
+ pfvf->rx_chan_base = NIX_CHAN_CGX_LMAC_CHX(cgx_id, lmac_id, 0);
+ pfvf->tx_chan_base = pfvf->rx_chan_base;
+ pfvf->rx_chan_cnt = 1;
+ pfvf->tx_chan_cnt = 1;
+ cgx_set_pkind(rvu_cgx_pdata(cgx_id, rvu), lmac_id, pkind);
+ rvu_npc_set_pkind(rvu, pkind, pfvf);
+ break;
+ case NIX_INTF_TYPE_LBK:
+ break;
+ }
+
+ /* Add a UCAST forwarding rule in MCAM with this NIXLF attached
+ * RVU PF/VF's MAC address.
+ */
+ rvu_npc_install_ucast_entry(rvu, pcifunc, 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);
+ if (err) {
+ dev_err(rvu->dev,
+ "Bcast list, failed to enable PF_FUNC 0x%x\n",
+ pcifunc);
+ return err;
+ }
+
+ rvu_npc_install_bcast_match_entry(rvu, pcifunc,
+ nixlf, pfvf->rx_chan_base);
+
+ return 0;
+}
+
+static void nix_interface_deinit(struct rvu *rvu, u16 pcifunc, u8 nixlf)
+{
+ int err;
+
+ /* Remove this PF_FUNC from bcast pkt replication list */
+ err = nix_update_bcast_mce_list(rvu, pcifunc, false);
+ if (err) {
+ dev_err(rvu->dev,
+ "Bcast list, failed to disable PF_FUNC 0x%x\n",
+ pcifunc);
+ }
+
+ /* Free and disable any MCAM entries used by this NIX LF */
+ rvu_npc_disable_mcam_entries(rvu, pcifunc, nixlf);
+}
+
+static void nix_setup_lso_tso_l3(struct rvu *rvu, int blkaddr,
+ u64 format, bool v4, u64 *fidx)
+{
+ struct nix_lso_format field = {0};
+
+ /* IP's Length field */
+ field.layer = NIX_TXLAYER_OL3;
+ /* In ipv4, length field is at offset 2 bytes, for ipv6 it's 4 */
+ field.offset = v4 ? 2 : 4;
+ field.sizem1 = 1; /* i.e 2 bytes */
+ field.alg = NIX_LSOALG_ADD_PAYLEN;
+ rvu_write64(rvu, blkaddr,
+ NIX_AF_LSO_FORMATX_FIELDX(format, (*fidx)++),
+ *(u64 *)&field);
+
+ /* No ID field in IPv6 header */
+ if (!v4)
+ return;
+
+ /* IP's ID field */
+ field.layer = NIX_TXLAYER_OL3;
+ field.offset = 4;
+ field.sizem1 = 1; /* i.e 2 bytes */
+ field.alg = NIX_LSOALG_ADD_SEGNUM;
+ rvu_write64(rvu, blkaddr,
+ NIX_AF_LSO_FORMATX_FIELDX(format, (*fidx)++),
+ *(u64 *)&field);
+}
+
+static void nix_setup_lso_tso_l4(struct rvu *rvu, int blkaddr,
+ u64 format, u64 *fidx)
+{
+ struct nix_lso_format field = {0};
+
+ /* TCP's sequence number field */
+ field.layer = NIX_TXLAYER_OL4;
+ field.offset = 4;
+ field.sizem1 = 3; /* i.e 4 bytes */
+ field.alg = NIX_LSOALG_ADD_OFFSET;
+ rvu_write64(rvu, blkaddr,
+ NIX_AF_LSO_FORMATX_FIELDX(format, (*fidx)++),
+ *(u64 *)&field);
+
+ /* TCP's flags field */
+ field.layer = NIX_TXLAYER_OL4;
+ field.offset = 12;
+ field.sizem1 = 0; /* not needed */
+ field.alg = NIX_LSOALG_TCP_FLAGS;
+ rvu_write64(rvu, blkaddr,
+ NIX_AF_LSO_FORMATX_FIELDX(format, (*fidx)++),
+ *(u64 *)&field);
+}
+
+static void nix_setup_lso(struct rvu *rvu, int blkaddr)
+{
+ u64 cfg, idx, fidx = 0;
+
+ /* Enable LSO */
+ cfg = rvu_read64(rvu, blkaddr, NIX_AF_LSO_CFG);
+ /* For TSO, set first and middle segment flags to
+ * mask out PSH, RST & FIN flags in TCP packet
+ */
+ cfg &= ~((0xFFFFULL << 32) | (0xFFFFULL << 16));
+ cfg |= (0xFFF2ULL << 32) | (0xFFF2ULL << 16);
+ rvu_write64(rvu, blkaddr, NIX_AF_LSO_CFG, cfg | BIT_ULL(63));
+
+ /* Configure format fields for TCPv4 segmentation offload */
+ idx = NIX_LSO_FORMAT_IDX_TSOV4;
+ nix_setup_lso_tso_l3(rvu, blkaddr, idx, true, &fidx);
+ nix_setup_lso_tso_l4(rvu, blkaddr, idx, &fidx);
+
+ /* Set rest of the fields to NOP */
+ for (; fidx < 8; fidx++) {
+ rvu_write64(rvu, blkaddr,
+ NIX_AF_LSO_FORMATX_FIELDX(idx, fidx), 0x0ULL);
+ }
+
+ /* Configure format fields for TCPv6 segmentation offload */
+ idx = NIX_LSO_FORMAT_IDX_TSOV6;
+ fidx = 0;
+ nix_setup_lso_tso_l3(rvu, blkaddr, idx, false, &fidx);
+ nix_setup_lso_tso_l4(rvu, blkaddr, idx, &fidx);
+
+ /* Set rest of the fields to NOP */
+ for (; fidx < 8; fidx++) {
+ rvu_write64(rvu, blkaddr,
+ NIX_AF_LSO_FORMATX_FIELDX(idx, fidx), 0x0ULL);
+ }
+}
+
+static void nix_ctx_free(struct rvu *rvu, struct rvu_pfvf *pfvf)
+{
+ kfree(pfvf->rq_bmap);
+ kfree(pfvf->sq_bmap);
+ kfree(pfvf->cq_bmap);
+ if (pfvf->rq_ctx)
+ qmem_free(rvu->dev, pfvf->rq_ctx);
+ if (pfvf->sq_ctx)
+ qmem_free(rvu->dev, pfvf->sq_ctx);
+ if (pfvf->cq_ctx)
+ qmem_free(rvu->dev, pfvf->cq_ctx);
+ if (pfvf->rss_ctx)
+ qmem_free(rvu->dev, pfvf->rss_ctx);
+ if (pfvf->nix_qints_ctx)
+ qmem_free(rvu->dev, pfvf->nix_qints_ctx);
+ if (pfvf->cq_ints_ctx)
+ qmem_free(rvu->dev, pfvf->cq_ints_ctx);
+
+ pfvf->rq_bmap = NULL;
+ pfvf->cq_bmap = NULL;
+ pfvf->sq_bmap = NULL;
+ pfvf->rq_ctx = NULL;
+ pfvf->sq_ctx = NULL;
+ pfvf->cq_ctx = NULL;
+ pfvf->rss_ctx = NULL;
+ pfvf->nix_qints_ctx = NULL;
+ pfvf->cq_ints_ctx = NULL;
+}
+
+static int nixlf_rss_ctx_init(struct rvu *rvu, int blkaddr,
+ struct rvu_pfvf *pfvf, int nixlf,
+ int rss_sz, int rss_grps, int hwctx_size)
+{
+ int err, grp, num_indices;
+
+ /* RSS is not requested for this NIXLF */
+ if (!rss_sz)
+ return 0;
+ num_indices = rss_sz * rss_grps;
+
+ /* Alloc NIX RSS HW context memory and config the base */
+ err = qmem_alloc(rvu->dev, &pfvf->rss_ctx, num_indices, hwctx_size);
+ if (err)
+ return err;
+
+ rvu_write64(rvu, blkaddr, NIX_AF_LFX_RSS_BASE(nixlf),
+ (u64)pfvf->rss_ctx->iova);
+
+ /* Config full RSS table size, enable RSS and caching */
+ rvu_write64(rvu, blkaddr, NIX_AF_LFX_RSS_CFG(nixlf),
+ BIT_ULL(36) | BIT_ULL(4) |
+ ilog2(num_indices / MAX_RSS_INDIR_TBL_SIZE));
+ /* Config RSS group offset and sizes */
+ for (grp = 0; grp < rss_grps; grp++)
+ rvu_write64(rvu, blkaddr, NIX_AF_LFX_RSS_GRPX(nixlf, grp),
+ ((ilog2(rss_sz) - 1) << 16) | (rss_sz * grp));
+ return 0;
+}
+
+static int nix_aq_enqueue_wait(struct rvu *rvu, struct rvu_block *block,
+ struct nix_aq_inst_s *inst)
+{
+ struct admin_queue *aq = block->aq;
+ struct nix_aq_res_s *result;
+ int timeout = 1000;
+ u64 reg, head;
+
+ result = (struct nix_aq_res_s *)aq->res->base;
+
+ /* Get current head pointer where to append this instruction */
+ reg = rvu_read64(rvu, block->addr, NIX_AF_AQ_STATUS);
+ head = (reg >> 4) & AQ_PTR_MASK;
+
+ memcpy((void *)(aq->inst->base + (head * aq->inst->entry_sz)),
+ (void *)inst, aq->inst->entry_sz);
+ memset(result, 0, sizeof(*result));
+ /* sync into memory */
+ wmb();
+
+ /* Ring the doorbell and wait for result */
+ rvu_write64(rvu, block->addr, NIX_AF_AQ_DOOR, 1);
+ while (result->compcode == NIX_AQ_COMP_NOTDONE) {
+ cpu_relax();
+ udelay(1);
+ timeout--;
+ if (!timeout)
+ return -EBUSY;
+ }
+
+ if (result->compcode != NIX_AQ_COMP_GOOD)
+ /* TODO: Replace this with some error code */
+ return -EBUSY;
+
+ return 0;
+}
+
+static int rvu_nix_aq_enq_inst(struct rvu *rvu, struct nix_aq_enq_req *req,
+ struct nix_aq_enq_rsp *rsp)
+{
+ struct rvu_hwinfo *hw = rvu->hw;
+ u16 pcifunc = req->hdr.pcifunc;
+ int nixlf, blkaddr, rc = 0;
+ struct nix_aq_inst_s inst;
+ struct rvu_block *block;
+ struct admin_queue *aq;
+ struct rvu_pfvf *pfvf;
+ void *ctx, *mask;
+ bool ena;
+ u64 cfg;
+
+ 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;
+
+ block = &hw->block[blkaddr];
+ aq = block->aq;
+ if (!aq) {
+ dev_warn(rvu->dev, "%s: NIX AQ not initialized\n", __func__);
+ return NIX_AF_ERR_AQ_ENQUEUE;
+ }
+
+ nixlf = rvu_get_lf(rvu, block, pcifunc, 0);
+ if (nixlf < 0)
+ return NIX_AF_ERR_AF_LF_INVALID;
+
+ switch (req->ctype) {
+ case NIX_AQ_CTYPE_RQ:
+ /* Check if index exceeds max no of queues */
+ if (!pfvf->rq_ctx || req->qidx >= pfvf->rq_ctx->qsize)
+ rc = NIX_AF_ERR_AQ_ENQUEUE;
+ break;
+ case NIX_AQ_CTYPE_SQ:
+ if (!pfvf->sq_ctx || req->qidx >= pfvf->sq_ctx->qsize)
+ rc = NIX_AF_ERR_AQ_ENQUEUE;
+ break;
+ case NIX_AQ_CTYPE_CQ:
+ if (!pfvf->cq_ctx || req->qidx >= pfvf->cq_ctx->qsize)
+ rc = NIX_AF_ERR_AQ_ENQUEUE;
+ break;
+ case NIX_AQ_CTYPE_RSS:
+ /* Check if RSS is enabled and qidx is within range */
+ cfg = rvu_read64(rvu, blkaddr, NIX_AF_LFX_RSS_CFG(nixlf));
+ if (!(cfg & BIT_ULL(4)) || !pfvf->rss_ctx ||
+ (req->qidx >= (256UL << (cfg & 0xF))))
+ rc = NIX_AF_ERR_AQ_ENQUEUE;
+ break;
+ case NIX_AQ_CTYPE_MCE:
+ cfg = rvu_read64(rvu, blkaddr, NIX_AF_RX_MCAST_CFG);
+ /* Check if index exceeds MCE list length */
+ if (!hw->nix0->mcast.mce_ctx ||
+ (req->qidx >= (256UL << (cfg & 0xF))))
+ rc = NIX_AF_ERR_AQ_ENQUEUE;
+
+ /* Adding multicast lists for requests from PF/VFs is not
+ * yet supported, so ignore this.
+ */
+ if (rsp)
+ rc = NIX_AF_ERR_AQ_ENQUEUE;
+ break;
+ default:
+ rc = NIX_AF_ERR_AQ_ENQUEUE;
+ }
+
+ if (rc)
+ return rc;
+
+ /* Check if SQ pointed SMQ belongs to this PF/VF or not */
+ if (req->ctype == NIX_AQ_CTYPE_SQ &&
+ req->op != NIX_AQ_INSTOP_WRITE) {
+ if (!is_valid_txschq(rvu, blkaddr, NIX_TXSCH_LVL_SMQ,
+ pcifunc, req->sq.smq))
+ return NIX_AF_ERR_AQ_ENQUEUE;
+ }
+
+ memset(&inst, 0, sizeof(struct nix_aq_inst_s));
+ inst.lf = nixlf;
+ inst.cindex = req->qidx;
+ inst.ctype = req->ctype;
+ inst.op = req->op;
+ /* Currently we are not supporting enqueuing multiple instructions,
+ * so always choose first entry in result memory.
+ */
+ inst.res_addr = (u64)aq->res->iova;
+
+ /* Clean result + context memory */
+ memset(aq->res->base, 0, aq->res->entry_sz);
+ /* Context needs to be written at RES_ADDR + 128 */
+ ctx = aq->res->base + 128;
+ /* Mask needs to be written at RES_ADDR + 256 */
+ mask = aq->res->base + 256;
+
+ switch (req->op) {
+ case NIX_AQ_INSTOP_WRITE:
+ if (req->ctype == NIX_AQ_CTYPE_RQ)
+ memcpy(mask, &req->rq_mask,
+ sizeof(struct nix_rq_ctx_s));
+ else if (req->ctype == NIX_AQ_CTYPE_SQ)
+ memcpy(mask, &req->sq_mask,
+ sizeof(struct nix_sq_ctx_s));
+ else if (req->ctype == NIX_AQ_CTYPE_CQ)
+ memcpy(mask, &req->cq_mask,
+ sizeof(struct nix_cq_ctx_s));
+ else if (req->ctype == NIX_AQ_CTYPE_RSS)
+ memcpy(mask, &req->rss_mask,
+ sizeof(struct nix_rsse_s));
+ else if (req->ctype == NIX_AQ_CTYPE_MCE)
+ memcpy(mask, &req->mce_mask,
+ sizeof(struct nix_rx_mce_s));
+ /* Fall through */
+ case NIX_AQ_INSTOP_INIT:
+ if (req->ctype == NIX_AQ_CTYPE_RQ)
+ memcpy(ctx, &req->rq, sizeof(struct nix_rq_ctx_s));
+ else if (req->ctype == NIX_AQ_CTYPE_SQ)
+ memcpy(ctx, &req->sq, sizeof(struct nix_sq_ctx_s));
+ else if (req->ctype == NIX_AQ_CTYPE_CQ)
+ memcpy(ctx, &req->cq, sizeof(struct nix_cq_ctx_s));
+ else if (req->ctype == NIX_AQ_CTYPE_RSS)
+ 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));
+ break;
+ case NIX_AQ_INSTOP_NOP:
+ case NIX_AQ_INSTOP_READ:
+ case NIX_AQ_INSTOP_LOCK:
+ case NIX_AQ_INSTOP_UNLOCK:
+ break;
+ default:
+ rc = NIX_AF_ERR_AQ_ENQUEUE;
+ return rc;
+ }
+
+ spin_lock(&aq->lock);
+
+ /* Submit the instruction to AQ */
+ rc = nix_aq_enqueue_wait(rvu, block, &inst);
+ if (rc) {
+ spin_unlock(&aq->lock);
+ return rc;
+ }
+
+ /* Set RQ/SQ/CQ bitmap if respective queue hw context is enabled */
+ if (req->op == NIX_AQ_INSTOP_INIT) {
+ if (req->ctype == NIX_AQ_CTYPE_RQ && req->rq.ena)
+ __set_bit(req->qidx, pfvf->rq_bmap);
+ if (req->ctype == NIX_AQ_CTYPE_SQ && req->sq.ena)
+ __set_bit(req->qidx, pfvf->sq_bmap);
+ if (req->ctype == NIX_AQ_CTYPE_CQ && req->cq.ena)
+ __set_bit(req->qidx, pfvf->cq_bmap);
+ }
+
+ if (req->op == NIX_AQ_INSTOP_WRITE) {
+ if (req->ctype == NIX_AQ_CTYPE_RQ) {
+ ena = (req->rq.ena & req->rq_mask.ena) |
+ (test_bit(req->qidx, pfvf->rq_bmap) &
+ ~req->rq_mask.ena);
+ if (ena)
+ __set_bit(req->qidx, pfvf->rq_bmap);
+ else
+ __clear_bit(req->qidx, pfvf->rq_bmap);
+ }
+ if (req->ctype == NIX_AQ_CTYPE_SQ) {
+ ena = (req->rq.ena & req->sq_mask.ena) |
+ (test_bit(req->qidx, pfvf->sq_bmap) &
+ ~req->sq_mask.ena);
+ if (ena)
+ __set_bit(req->qidx, pfvf->sq_bmap);
+ else
+ __clear_bit(req->qidx, pfvf->sq_bmap);
+ }
+ if (req->ctype == NIX_AQ_CTYPE_CQ) {
+ ena = (req->rq.ena & req->cq_mask.ena) |
+ (test_bit(req->qidx, pfvf->cq_bmap) &
+ ~req->cq_mask.ena);
+ if (ena)
+ __set_bit(req->qidx, pfvf->cq_bmap);
+ else
+ __clear_bit(req->qidx, pfvf->cq_bmap);
+ }
+ }
+
+ if (rsp) {
+ /* Copy read context into mailbox */
+ if (req->op == NIX_AQ_INSTOP_READ) {
+ if (req->ctype == NIX_AQ_CTYPE_RQ)
+ memcpy(&rsp->rq, ctx,
+ sizeof(struct nix_rq_ctx_s));
+ else if (req->ctype == NIX_AQ_CTYPE_SQ)
+ memcpy(&rsp->sq, ctx,
+ sizeof(struct nix_sq_ctx_s));
+ else if (req->ctype == NIX_AQ_CTYPE_CQ)
+ memcpy(&rsp->cq, ctx,
+ sizeof(struct nix_cq_ctx_s));
+ else if (req->ctype == NIX_AQ_CTYPE_RSS)
+ memcpy(&rsp->rss, ctx,
+ sizeof(struct nix_rsse_s));
+ else if (req->ctype == NIX_AQ_CTYPE_MCE)
+ memcpy(&rsp->mce, ctx,
+ sizeof(struct nix_rx_mce_s));
+ }
+ }
+
+ spin_unlock(&aq->lock);
+ return 0;
+}
+
+static int nix_lf_hwctx_disable(struct rvu *rvu, struct hwctx_disable_req *req)
+{
+ struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, req->hdr.pcifunc);
+ struct nix_aq_enq_req aq_req;
+ unsigned long *bmap;
+ int qidx, q_cnt = 0;
+ int err = 0, rc;
+
+ if (!pfvf->cq_ctx || !pfvf->sq_ctx || !pfvf->rq_ctx)
+ return NIX_AF_ERR_AQ_ENQUEUE;
+
+ memset(&aq_req, 0, sizeof(struct nix_aq_enq_req));
+ aq_req.hdr.pcifunc = req->hdr.pcifunc;
+
+ if (req->ctype == NIX_AQ_CTYPE_CQ) {
+ aq_req.cq.ena = 0;
+ aq_req.cq_mask.ena = 1;
+ q_cnt = pfvf->cq_ctx->qsize;
+ bmap = pfvf->cq_bmap;
+ }
+ if (req->ctype == NIX_AQ_CTYPE_SQ) {
+ aq_req.sq.ena = 0;
+ aq_req.sq_mask.ena = 1;
+ q_cnt = pfvf->sq_ctx->qsize;
+ bmap = pfvf->sq_bmap;
+ }
+ if (req->ctype == NIX_AQ_CTYPE_RQ) {
+ aq_req.rq.ena = 0;
+ aq_req.rq_mask.ena = 1;
+ q_cnt = pfvf->rq_ctx->qsize;
+ bmap = pfvf->rq_bmap;
+ }
+
+ aq_req.ctype = req->ctype;
+ aq_req.op = NIX_AQ_INSTOP_WRITE;
+
+ for (qidx = 0; qidx < q_cnt; qidx++) {
+ if (!test_bit(qidx, bmap))
+ continue;
+ aq_req.qidx = qidx;
+ rc = rvu_nix_aq_enq_inst(rvu, &aq_req, NULL);
+ if (rc) {
+ err = rc;
+ dev_err(rvu->dev, "Failed to disable %s:%d context\n",
+ (req->ctype == NIX_AQ_CTYPE_CQ) ?
+ "CQ" : ((req->ctype == NIX_AQ_CTYPE_RQ) ?
+ "RQ" : "SQ"), qidx);
+ }
+ }
+
+ return err;
+}
+
+int rvu_mbox_handler_NIX_AQ_ENQ(struct rvu *rvu,
+ struct nix_aq_enq_req *req,
+ struct nix_aq_enq_rsp *rsp)
+{
+ return rvu_nix_aq_enq_inst(rvu, req, rsp);
+}
+
+int rvu_mbox_handler_NIX_HWCTX_DISABLE(struct rvu *rvu,
+ struct hwctx_disable_req *req,
+ struct msg_rsp *rsp)
+{
+ return nix_lf_hwctx_disable(rvu, req);
+}
+
+int rvu_mbox_handler_NIX_LF_ALLOC(struct rvu *rvu,
+ struct nix_lf_alloc_req *req,
+ struct nix_lf_alloc_rsp *rsp)
+{
+ int nixlf, qints, hwctx_size, err, rc = 0;
+ struct rvu_hwinfo *hw = rvu->hw;
+ u16 pcifunc = req->hdr.pcifunc;
+ struct rvu_block *block;
+ struct rvu_pfvf *pfvf;
+ u64 cfg, ctx_cfg;
+ int blkaddr;
+
+ if (!req->rq_cnt || !req->sq_cnt || !req->cq_cnt)
+ return NIX_AF_ERR_PARAM;
+
+ 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;
+
+ block = &hw->block[blkaddr];
+ nixlf = rvu_get_lf(rvu, block, pcifunc, 0);
+ if (nixlf < 0)
+ return NIX_AF_ERR_AF_LF_INVALID;
+
+ /* If RSS is being enabled, check if requested config is valid.
+ * RSS table size should be power of two, otherwise
+ * RSS_GRP::OFFSET + adder might go beyond that group or
+ * won't be able to use entire table.
+ */
+ if (req->rss_sz && (req->rss_sz > MAX_RSS_INDIR_TBL_SIZE ||
+ !is_power_of_2(req->rss_sz)))
+ return NIX_AF_ERR_RSS_SIZE_INVALID;
+
+ if (req->rss_sz &&
+ (!req->rss_grps || req->rss_grps > MAX_RSS_GROUPS))
+ return NIX_AF_ERR_RSS_GRPS_INVALID;
+
+ /* Reset this NIX LF */
+ err = rvu_lf_reset(rvu, block, nixlf);
+ if (err) {
+ dev_err(rvu->dev, "Failed to reset NIX%d LF%d\n",
+ block->addr - BLKADDR_NIX0, nixlf);
+ return NIX_AF_ERR_LF_RESET;
+ }
+
+ ctx_cfg = rvu_read64(rvu, blkaddr, NIX_AF_CONST3);
+
+ /* Alloc NIX RQ HW context memory and config the base */
+ hwctx_size = 1UL << ((ctx_cfg >> 4) & 0xF);
+ err = qmem_alloc(rvu->dev, &pfvf->rq_ctx, req->rq_cnt, hwctx_size);
+ if (err)
+ goto free_mem;
+
+ pfvf->rq_bmap = kcalloc(req->rq_cnt, sizeof(long), GFP_KERNEL);
+ if (!pfvf->rq_bmap)
+ goto free_mem;
+
+ rvu_write64(rvu, blkaddr, NIX_AF_LFX_RQS_BASE(nixlf),
+ (u64)pfvf->rq_ctx->iova);
+
+ /* Set caching and queue count in HW */
+ cfg = BIT_ULL(36) | (req->rq_cnt - 1);
+ rvu_write64(rvu, blkaddr, NIX_AF_LFX_RQS_CFG(nixlf), cfg);
+
+ /* Alloc NIX SQ HW context memory and config the base */
+ hwctx_size = 1UL << (ctx_cfg & 0xF);
+ err = qmem_alloc(rvu->dev, &pfvf->sq_ctx, req->sq_cnt, hwctx_size);
+ if (err)
+ goto free_mem;
+
+ pfvf->sq_bmap = kcalloc(req->sq_cnt, sizeof(long), GFP_KERNEL);
+ if (!pfvf->sq_bmap)
+ goto free_mem;
+
+ rvu_write64(rvu, blkaddr, NIX_AF_LFX_SQS_BASE(nixlf),
+ (u64)pfvf->sq_ctx->iova);
+ cfg = BIT_ULL(36) | (req->sq_cnt - 1);
+ rvu_write64(rvu, blkaddr, NIX_AF_LFX_SQS_CFG(nixlf), cfg);
+
+ /* Alloc NIX CQ HW context memory and config the base */
+ hwctx_size = 1UL << ((ctx_cfg >> 8) & 0xF);
+ err = qmem_alloc(rvu->dev, &pfvf->cq_ctx, req->cq_cnt, hwctx_size);
+ if (err)
+ goto free_mem;
+
+ pfvf->cq_bmap = kcalloc(req->cq_cnt, sizeof(long), GFP_KERNEL);
+ if (!pfvf->cq_bmap)
+ goto free_mem;
+
+ rvu_write64(rvu, blkaddr, NIX_AF_LFX_CQS_BASE(nixlf),
+ (u64)pfvf->cq_ctx->iova);
+ cfg = BIT_ULL(36) | (req->cq_cnt - 1);
+ rvu_write64(rvu, blkaddr, NIX_AF_LFX_CQS_CFG(nixlf), cfg);
+
+ /* Initialize receive side scaling (RSS) */
+ hwctx_size = 1UL << ((ctx_cfg >> 12) & 0xF);
+ err = nixlf_rss_ctx_init(rvu, blkaddr, pfvf, nixlf,
+ req->rss_sz, req->rss_grps, hwctx_size);
+ if (err)
+ goto free_mem;
+
+ /* Alloc memory for CQINT's HW contexts */
+ cfg = rvu_read64(rvu, blkaddr, NIX_AF_CONST2);
+ qints = (cfg >> 24) & 0xFFF;
+ hwctx_size = 1UL << ((ctx_cfg >> 24) & 0xF);
+ err = qmem_alloc(rvu->dev, &pfvf->cq_ints_ctx, qints, hwctx_size);
+ if (err)
+ goto free_mem;
+
+ rvu_write64(rvu, blkaddr, NIX_AF_LFX_CINTS_BASE(nixlf),
+ (u64)pfvf->cq_ints_ctx->iova);
+ rvu_write64(rvu, blkaddr, NIX_AF_LFX_CINTS_CFG(nixlf), BIT_ULL(36));
+
+ /* Alloc memory for QINT's HW contexts */
+ cfg = rvu_read64(rvu, blkaddr, NIX_AF_CONST2);
+ qints = (cfg >> 12) & 0xFFF;
+ hwctx_size = 1UL << ((ctx_cfg >> 20) & 0xF);
+ err = qmem_alloc(rvu->dev, &pfvf->nix_qints_ctx, qints, hwctx_size);
+ if (err)
+ goto free_mem;
+
+ rvu_write64(rvu, blkaddr, NIX_AF_LFX_QINTS_BASE(nixlf),
+ (u64)pfvf->nix_qints_ctx->iova);
+ rvu_write64(rvu, blkaddr, NIX_AF_LFX_QINTS_CFG(nixlf), BIT_ULL(36));
+
+ /* Enable LMTST for this NIX LF */
+ rvu_write64(rvu, blkaddr, NIX_AF_LFX_TX_CFG2(nixlf), BIT_ULL(0));
+
+ /* Set CQE/WQE size, NPA_PF_FUNC for SQBs and also SSO_PF_FUNC
+ * If requester has sent a 'RVU_DEFAULT_PF_FUNC' use this NIX LF's
+ * PCIFUNC itself.
+ */
+ if (req->npa_func == RVU_DEFAULT_PF_FUNC)
+ cfg = pcifunc;
+ else
+ cfg = req->npa_func;
+
+ if (req->sso_func == RVU_DEFAULT_PF_FUNC)
+ cfg |= (u64)pcifunc << 16;
+ else
+ cfg |= (u64)req->sso_func << 16;
+
+ cfg |= (u64)req->xqe_sz << 33;
+ rvu_write64(rvu, blkaddr, NIX_AF_LFX_CFG(nixlf), cfg);
+
+ /* Config Rx pkt length, csum checks and apad enable / disable */
+ rvu_write64(rvu, blkaddr, NIX_AF_LFX_RX_CFG(nixlf), req->rx_cfg);
+
+ err = nix_interface_init(rvu, pcifunc, NIX_INTF_TYPE_CGX, nixlf);
+ if (err)
+ goto free_mem;
+
+ goto exit;
+
+free_mem:
+ nix_ctx_free(rvu, pfvf);
+ rc = -ENOMEM;
+
+exit:
+ /* Set macaddr of this PF/VF */
+ ether_addr_copy(rsp->mac_addr, pfvf->mac_addr);
+
+ /* set SQB size info */
+ cfg = rvu_read64(rvu, blkaddr, NIX_AF_SQ_CONST);
+ rsp->sqb_size = (cfg >> 34) & 0xFFFF;
+ rsp->rx_chan_base = pfvf->rx_chan_base;
+ rsp->tx_chan_base = pfvf->tx_chan_base;
+ rsp->rx_chan_cnt = pfvf->rx_chan_cnt;
+ rsp->tx_chan_cnt = pfvf->tx_chan_cnt;
+ rsp->lso_tsov4_idx = NIX_LSO_FORMAT_IDX_TSOV4;
+ rsp->lso_tsov6_idx = NIX_LSO_FORMAT_IDX_TSOV6;
+ return rc;
+}
+
+int rvu_mbox_handler_NIX_LF_FREE(struct rvu *rvu, struct msg_req *req,
+ struct msg_rsp *rsp)
+{
+ struct rvu_hwinfo *hw = rvu->hw;
+ u16 pcifunc = req->hdr.pcifunc;
+ struct rvu_block *block;
+ int blkaddr, nixlf, err;
+ 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;
+
+ block = &hw->block[blkaddr];
+ nixlf = rvu_get_lf(rvu, block, pcifunc, 0);
+ if (nixlf < 0)
+ return NIX_AF_ERR_AF_LF_INVALID;
+
+ nix_interface_deinit(rvu, pcifunc, nixlf);
+
+ /* Reset this NIX LF */
+ err = rvu_lf_reset(rvu, block, nixlf);
+ if (err) {
+ dev_err(rvu->dev, "Failed to reset NIX%d LF%d\n",
+ block->addr - BLKADDR_NIX0, nixlf);
+ return NIX_AF_ERR_LF_RESET;
+ }
+
+ nix_ctx_free(rvu, pfvf);
+
+ return 0;
+}
+
+/* Disable shaping of pkts by a scheduler queue
+ * at a given scheduler level.
+ */
+static void nix_reset_tx_shaping(struct rvu *rvu, int blkaddr,
+ int lvl, int schq)
+{
+ u64 cir_reg = 0, pir_reg = 0;
+ u64 cfg;
+
+ switch (lvl) {
+ case NIX_TXSCH_LVL_TL1:
+ cir_reg = NIX_AF_TL1X_CIR(schq);
+ pir_reg = 0; /* PIR not available at TL1 */
+ break;
+ case NIX_TXSCH_LVL_TL2:
+ cir_reg = NIX_AF_TL2X_CIR(schq);
+ pir_reg = NIX_AF_TL2X_PIR(schq);
+ break;
+ case NIX_TXSCH_LVL_TL3:
+ cir_reg = NIX_AF_TL3X_CIR(schq);
+ pir_reg = NIX_AF_TL3X_PIR(schq);
+ break;
+ case NIX_TXSCH_LVL_TL4:
+ cir_reg = NIX_AF_TL4X_CIR(schq);
+ pir_reg = NIX_AF_TL4X_PIR(schq);
+ break;
+ }
+
+ if (!cir_reg)
+ return;
+ cfg = rvu_read64(rvu, blkaddr, cir_reg);
+ rvu_write64(rvu, blkaddr, cir_reg, cfg & ~BIT_ULL(0));
+
+ if (!pir_reg)
+ return;
+ cfg = rvu_read64(rvu, blkaddr, pir_reg);
+ rvu_write64(rvu, blkaddr, pir_reg, cfg & ~BIT_ULL(0));
+}
+
+static void nix_reset_tx_linkcfg(struct rvu *rvu, int blkaddr,
+ int lvl, int schq)
+{
+ struct rvu_hwinfo *hw = rvu->hw;
+ int link;
+
+ /* Reset TL4's SDP link config */
+ if (lvl == NIX_TXSCH_LVL_TL4)
+ rvu_write64(rvu, blkaddr, NIX_AF_TL4X_SDP_LINK_CFG(schq), 0x00);
+
+ if (lvl != NIX_TXSCH_LVL_TL2)
+ return;
+
+ /* Reset TL2's CGX or LBK link config */
+ for (link = 0; link < (hw->cgx_links + hw->lbk_links); link++)
+ rvu_write64(rvu, blkaddr,
+ NIX_AF_TL3_TL2X_LINKX_CFG(schq, link), 0x00);
+}
+
+int rvu_mbox_handler_NIX_TXSCH_ALLOC(struct rvu *rvu,
+ struct nix_txsch_alloc_req *req,
+ struct nix_txsch_alloc_rsp *rsp)
+{
+ u16 pcifunc = req->hdr.pcifunc;
+ struct nix_txsch *txsch;
+ int lvl, idx, req_schq;
+ struct rvu_pfvf *pfvf;
+ struct nix_hw *nix_hw;
+ int blkaddr, rc = 0;
+ u16 schq;
+
+ 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 -EINVAL;
+
+ spin_lock(&rvu->rsrc_lock);
+ for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) {
+ txsch = &nix_hw->txsch[lvl];
+ req_schq = req->schq_contig[lvl] + req->schq[lvl];
+
+ /* There are only 28 TL1s */
+ if (lvl == NIX_TXSCH_LVL_TL1 && req_schq > txsch->schq.max)
+ goto err;
+
+ /* Check if request is valid */
+ if (!req_schq || req_schq > MAX_TXSCHQ_PER_FUNC)
+ goto err;
+
+ /* If contiguous queues are needed, check for availability */
+ if (req->schq_contig[lvl] &&
+ !rvu_rsrc_check_contig(&txsch->schq, req->schq_contig[lvl]))
+ goto err;
+
+ /* Check if full request can be accommodated */
+ if (req_schq >= rvu_rsrc_free_count(&txsch->schq))
+ goto err;
+ }
+
+ for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) {
+ txsch = &nix_hw->txsch[lvl];
+ rsp->schq_contig[lvl] = req->schq_contig[lvl];
+ rsp->schq[lvl] = req->schq[lvl];
+
+ schq = 0;
+ /* Alloc contiguous queues first */
+ if (req->schq_contig[lvl]) {
+ schq = rvu_alloc_rsrc_contig(&txsch->schq,
+ req->schq_contig[lvl]);
+
+ for (idx = 0; idx < req->schq_contig[lvl]; idx++) {
+ txsch->pfvf_map[schq] = pcifunc;
+ nix_reset_tx_linkcfg(rvu, blkaddr, lvl, schq);
+ nix_reset_tx_shaping(rvu, blkaddr, lvl, schq);
+ rsp->schq_contig_list[lvl][idx] = schq;
+ schq++;
+ }
+ }
+
+ /* Alloc non-contiguous queues */
+ for (idx = 0; idx < req->schq[lvl]; idx++) {
+ schq = rvu_alloc_rsrc(&txsch->schq);
+ txsch->pfvf_map[schq] = pcifunc;
+ nix_reset_tx_linkcfg(rvu, blkaddr, lvl, schq);
+ nix_reset_tx_shaping(rvu, blkaddr, lvl, schq);
+ rsp->schq_list[lvl][idx] = schq;
+ }
+ }
+ goto exit;
+err:
+ rc = NIX_AF_ERR_TLX_ALLOC_FAIL;
+exit:
+ spin_unlock(&rvu->rsrc_lock);
+ return rc;
+}
+
+static int nix_txschq_free(struct rvu *rvu, u16 pcifunc)
+{
+ int blkaddr, nixlf, lvl, schq, err;
+ struct rvu_hwinfo *hw = rvu->hw;
+ struct nix_txsch *txsch;
+ struct nix_hw *nix_hw;
+ u64 cfg;
+
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc);
+ if (blkaddr < 0)
+ return NIX_AF_ERR_AF_LF_INVALID;
+
+ nix_hw = get_nix_hw(rvu->hw, blkaddr);
+ if (!nix_hw)
+ return -EINVAL;
+
+ nixlf = rvu_get_lf(rvu, &hw->block[blkaddr], pcifunc, 0);
+ if (nixlf < 0)
+ return NIX_AF_ERR_AF_LF_INVALID;
+
+ /* Disable TL2/3 queue links before SMQ flush*/
+ spin_lock(&rvu->rsrc_lock);
+ for (lvl = NIX_TXSCH_LVL_TL4; lvl < NIX_TXSCH_LVL_CNT; lvl++) {
+ if (lvl != NIX_TXSCH_LVL_TL2 && lvl != NIX_TXSCH_LVL_TL4)
+ continue;
+
+ txsch = &nix_hw->txsch[lvl];
+ for (schq = 0; schq < txsch->schq.max; schq++) {
+ if (txsch->pfvf_map[schq] != pcifunc)
+ continue;
+ nix_reset_tx_linkcfg(rvu, blkaddr, lvl, schq);
+ }
+ }
+
+ /* Flush SMQs */
+ txsch = &nix_hw->txsch[NIX_TXSCH_LVL_SMQ];
+ for (schq = 0; schq < txsch->schq.max; schq++) {
+ if (txsch->pfvf_map[schq] != pcifunc)
+ continue;
+ cfg = rvu_read64(rvu, blkaddr, NIX_AF_SMQX_CFG(schq));
+ /* Do SMQ flush and set enqueue xoff */
+ cfg |= BIT_ULL(50) | BIT_ULL(49);
+ rvu_write64(rvu, blkaddr, NIX_AF_SMQX_CFG(schq), cfg);
+
+ /* Wait for flush to complete */
+ err = rvu_poll_reg(rvu, blkaddr,
+ NIX_AF_SMQX_CFG(schq), BIT_ULL(49), true);
+ if (err) {
+ dev_err(rvu->dev,
+ "NIXLF%d: SMQ%d flush failed\n", nixlf, schq);
+ }
+ }
+
+ /* Now free scheduler queues to free pool */
+ for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) {
+ txsch = &nix_hw->txsch[lvl];
+ for (schq = 0; schq < txsch->schq.max; schq++) {
+ if (txsch->pfvf_map[schq] != pcifunc)
+ continue;
+ rvu_free_rsrc(&txsch->schq, schq);
+ txsch->pfvf_map[schq] = 0;
+ }
+ }
+ spin_unlock(&rvu->rsrc_lock);
+
+ /* Sync cached info for this LF in NDC-TX to LLC/DRAM */
+ rvu_write64(rvu, blkaddr, NIX_AF_NDC_TX_SYNC, BIT_ULL(12) | nixlf);
+ err = rvu_poll_reg(rvu, blkaddr, NIX_AF_NDC_TX_SYNC, BIT_ULL(12), true);
+ if (err)
+ dev_err(rvu->dev, "NDC-TX sync failed for NIXLF %d\n", nixlf);
+
+ return 0;
+}
+
+int rvu_mbox_handler_NIX_TXSCH_FREE(struct rvu *rvu,
+ struct nix_txsch_free_req *req,
+ struct msg_rsp *rsp)
+{
+ return nix_txschq_free(rvu, req->hdr.pcifunc);
+}
+
+static bool is_txschq_config_valid(struct rvu *rvu, u16 pcifunc, int blkaddr,
+ int lvl, u64 reg, u64 regval)
+{
+ u64 regbase = reg & 0xFFFF;
+ u16 schq, parent;
+
+ if (!rvu_check_valid_reg(TXSCHQ_HWREGMAP, lvl, reg))
+ return false;
+
+ schq = TXSCHQ_IDX(reg, TXSCHQ_IDX_SHIFT);
+ /* Check if this schq belongs to this PF/VF or not */
+ if (!is_valid_txschq(rvu, blkaddr, lvl, pcifunc, schq))
+ return false;
+
+ parent = (regval >> 16) & 0x1FF;
+ /* Validate MDQ's TL4 parent */
+ if (regbase == NIX_AF_MDQX_PARENT(0) &&
+ !is_valid_txschq(rvu, blkaddr, NIX_TXSCH_LVL_TL4, pcifunc, parent))
+ return false;
+
+ /* Validate TL4's TL3 parent */
+ if (regbase == NIX_AF_TL4X_PARENT(0) &&
+ !is_valid_txschq(rvu, blkaddr, NIX_TXSCH_LVL_TL3, pcifunc, parent))
+ return false;
+
+ /* Validate TL3's TL2 parent */
+ if (regbase == NIX_AF_TL3X_PARENT(0) &&
+ !is_valid_txschq(rvu, blkaddr, NIX_TXSCH_LVL_TL2, pcifunc, parent))
+ return false;
+
+ /* Validate TL2's TL1 parent */
+ if (regbase == NIX_AF_TL2X_PARENT(0) &&
+ !is_valid_txschq(rvu, blkaddr, NIX_TXSCH_LVL_TL1, pcifunc, parent))
+ return false;
+
+ return true;
+}
+
+int rvu_mbox_handler_NIX_TXSCHQ_CFG(struct rvu *rvu,
+ struct nix_txschq_config *req,
+ struct msg_rsp *rsp)
+{
+ struct rvu_hwinfo *hw = rvu->hw;
+ u16 pcifunc = req->hdr.pcifunc;
+ u64 reg, regval, schq_regbase;
+ struct nix_txsch *txsch;
+ struct nix_hw *nix_hw;
+ int blkaddr, idx, err;
+ int nixlf;
+
+ if (req->lvl >= NIX_TXSCH_LVL_CNT ||
+ req->num_regs > MAX_REGS_PER_MBOX_MSG)
+ return NIX_AF_INVAL_TXSCHQ_CFG;
+
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc);
+ if (blkaddr < 0)
+ return NIX_AF_ERR_AF_LF_INVALID;
+
+ nix_hw = get_nix_hw(rvu->hw, blkaddr);
+ if (!nix_hw)
+ return -EINVAL;
+
+ nixlf = rvu_get_lf(rvu, &hw->block[blkaddr], pcifunc, 0);
+ if (nixlf < 0)
+ return NIX_AF_ERR_AF_LF_INVALID;
+
+ txsch = &nix_hw->txsch[req->lvl];
+ for (idx = 0; idx < req->num_regs; idx++) {
+ reg = req->reg[idx];
+ regval = req->regval[idx];
+ schq_regbase = reg & 0xFFFF;
+
+ if (!is_txschq_config_valid(rvu, pcifunc, blkaddr,
+ txsch->lvl, reg, regval))
+ return NIX_AF_INVAL_TXSCHQ_CFG;
+
+ /* Replace PF/VF visible NIXLF slot with HW NIXLF id */
+ if (schq_regbase == NIX_AF_SMQX_CFG(0)) {
+ nixlf = rvu_get_lf(rvu, &hw->block[blkaddr],
+ pcifunc, 0);
+ regval &= ~(0x7FULL << 24);
+ regval |= ((u64)nixlf << 24);
+ }
+
+ rvu_write64(rvu, blkaddr, reg, regval);
+
+ /* Check for SMQ flush, if so, poll for its completion */
+ if (schq_regbase == NIX_AF_SMQX_CFG(0) &&
+ (regval & BIT_ULL(49))) {
+ err = rvu_poll_reg(rvu, blkaddr,
+ reg, BIT_ULL(49), true);
+ if (err)
+ return NIX_AF_SMQ_FLUSH_FAILED;
+ }
+ }
+ return 0;
+}
+
+static int nix_rx_vtag_cfg(struct rvu *rvu, int nixlf, int blkaddr,
+ struct nix_vtag_config *req)
+{
+ u64 regval = 0;
+
+#define NIX_VTAGTYPE_MAX 0x8ull
+#define NIX_VTAGSIZE_MASK 0x7ull
+#define NIX_VTAGSTRIP_CAP_MASK 0x30ull
+
+ if (req->rx.vtag_type >= NIX_VTAGTYPE_MAX ||
+ req->vtag_size > VTAGSIZE_T8)
+ return -EINVAL;
+
+ regval = rvu_read64(rvu, blkaddr,
+ NIX_AF_LFX_RX_VTAG_TYPEX(nixlf, req->rx.vtag_type));
+
+ if (req->rx.strip_vtag && req->rx.capture_vtag)
+ regval |= BIT_ULL(4) | BIT_ULL(5);
+ else if (req->rx.strip_vtag)
+ regval |= BIT_ULL(4);
+ else
+ regval &= ~(BIT_ULL(4) | BIT_ULL(5));
+
+ regval &= ~NIX_VTAGSIZE_MASK;
+ regval |= req->vtag_size & NIX_VTAGSIZE_MASK;
+
+ rvu_write64(rvu, blkaddr,
+ NIX_AF_LFX_RX_VTAG_TYPEX(nixlf, req->rx.vtag_type), regval);
+ return 0;
+}
+
+int rvu_mbox_handler_NIX_VTAG_CFG(struct rvu *rvu,
+ struct nix_vtag_config *req,
+ struct msg_rsp *rsp)
+{
+ struct rvu_hwinfo *hw = rvu->hw;
+ u16 pcifunc = req->hdr.pcifunc;
+ int blkaddr, nixlf, err;
+
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc);
+ if (blkaddr < 0)
+ return NIX_AF_ERR_AF_LF_INVALID;
+
+ nixlf = rvu_get_lf(rvu, &hw->block[blkaddr], pcifunc, 0);
+ if (nixlf < 0)
+ return NIX_AF_ERR_AF_LF_INVALID;
+
+ if (req->cfg_type) {
+ err = nix_rx_vtag_cfg(rvu, nixlf, blkaddr, req);
+ if (err)
+ return NIX_AF_ERR_PARAM;
+ } else {
+ /* TODO: handle tx vtag configuration */
+ return 0;
+ }
+
+ return 0;
+}
+
+static int nix_setup_mce(struct rvu *rvu, int mce, u8 op,
+ u16 pcifunc, int next, bool eol)
+{
+ struct nix_aq_enq_req aq_req;
+ int err;
+
+ aq_req.hdr.pcifunc = pcifunc;
+ aq_req.ctype = NIX_AQ_CTYPE_MCE;
+ aq_req.op = op;
+ aq_req.qidx = mce;
+
+ /* Forward bcast pkts to RQ0, RSS not needed */
+ aq_req.mce.op = 0;
+ aq_req.mce.index = 0;
+ aq_req.mce.eol = eol;
+ aq_req.mce.pf_func = pcifunc;
+ aq_req.mce.next = next;
+
+ /* All fields valid */
+ *(u64 *)(&aq_req.mce_mask) = ~0ULL;
+
+ err = rvu_nix_aq_enq_inst(rvu, &aq_req, NULL);
+ if (err) {
+ dev_err(rvu->dev, "Failed to setup Bcast MCE for PF%d:VF%d\n",
+ rvu_get_pf(pcifunc), pcifunc & RVU_PFVF_FUNC_MASK);
+ return err;
+ }
+ return 0;
+}
+
+static int nix_update_mce_list(struct nix_mce_list *mce_list,
+ u16 pcifunc, int idx, bool add)
+{
+ struct mce *mce, *tail = NULL;
+ bool delete = false;
+
+ /* Scan through the current list */
+ hlist_for_each_entry(mce, &mce_list->head, node) {
+ /* If already exists, then delete */
+ if (mce->pcifunc == pcifunc && !add) {
+ delete = true;
+ break;
+ }
+ tail = mce;
+ }
+
+ if (delete) {
+ hlist_del(&mce->node);
+ kfree(mce);
+ mce_list->count--;
+ return 0;
+ }
+
+ if (!add)
+ return 0;
+
+ /* Add a new one to the list, at the tail */
+ mce = kzalloc(sizeof(*mce), GFP_ATOMIC);
+ if (!mce)
+ return -ENOMEM;
+ mce->idx = idx;
+ mce->pcifunc = pcifunc;
+ if (!tail)
+ hlist_add_head(&mce->node, &mce_list->head);
+ else
+ hlist_add_behind(&mce->node, &tail->node);
+ mce_list->count++;
+ return 0;
+}
+
+static int nix_update_bcast_mce_list(struct rvu *rvu, u16 pcifunc, bool add)
+{
+ int err = 0, idx, next_idx, count;
+ struct nix_mce_list *mce_list;
+ struct mce *mce, *next_mce;
+ struct nix_mcast *mcast;
+ struct nix_hw *nix_hw;
+ struct rvu_pfvf *pfvf;
+ int blkaddr;
+
+ 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;
+
+ /* 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);
+
+ mce_list = &pfvf->bcast_mce_list;
+ if (idx > (pfvf->bcast_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,
+ pcifunc >> RVU_PFVF_PF_SHIFT);
+ return -EINVAL;
+ }
+
+ spin_lock(&mcast->mce_lock);
+
+ err = nix_update_mce_list(mce_list, pcifunc, idx, add);
+ if (err)
+ goto end;
+
+ /* Disable MCAM entry in NPC */
+
+ if (!mce_list->count)
+ goto end;
+ count = mce_list->count;
+
+ /* Dump the updated list to HW */
+ hlist_for_each_entry(mce, &mce_list->head, node) {
+ next_idx = 0;
+ count--;
+ if (count) {
+ next_mce = hlist_entry(mce->node.next,
+ struct mce, node);
+ next_idx = next_mce->idx;
+ }
+ /* EOL should be set in last MCE */
+ err = nix_setup_mce(rvu, mce->idx,
+ NIX_AQ_INSTOP_WRITE, mce->pcifunc,
+ next_idx, count ? false : true);
+ if (err)
+ goto end;
+ }
+
+end:
+ spin_unlock(&mcast->mce_lock);
+ return err;
+}
+
+static int nix_setup_bcast_tables(struct rvu *rvu, struct nix_hw *nix_hw)
+{
+ struct nix_mcast *mcast = &nix_hw->mcast;
+ int err, pf, numvfs, idx;
+ struct rvu_pfvf *pfvf;
+ u16 pcifunc;
+ u64 cfg;
+
+ /* Skip PF0 (i.e AF) */
+ for (pf = 1; pf < (rvu->cgx_mapped_pfs + 1); pf++) {
+ cfg = rvu_read64(rvu, BLKADDR_RVUM, RVU_PRIV_PFX_CFG(pf));
+ /* If PF is not enabled, nothing to do */
+ if (!((cfg >> 20) & 0x01))
+ continue;
+ /* Get numVFs attached to this PF */
+ numvfs = (cfg >> 12) & 0xFF;
+
+ pfvf = &rvu->pf[pf];
+ /* Save the start MCE */
+ pfvf->bcast_mce_idx = nix_alloc_mce_list(mcast, numvfs + 1);
+
+ nix_mce_list_init(&pfvf->bcast_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);
+ pcifunc |= idx;
+ /* Add dummy entries now, so that we don't have to check
+ * for whether AQ_OP should be INIT/WRITE later on.
+ * Will be updated when a NIXLF is attached/detached to
+ * these PF/VFs.
+ */
+ err = nix_setup_mce(rvu, pfvf->bcast_mce_idx + idx,
+ NIX_AQ_INSTOP_INIT,
+ pcifunc, 0, true);
+ if (err)
+ return err;
+ }
+ }
+ return 0;
+}
+
+static int nix_setup_mcast(struct rvu *rvu, struct nix_hw *nix_hw, int blkaddr)
+{
+ struct nix_mcast *mcast = &nix_hw->mcast;
+ struct rvu_hwinfo *hw = rvu->hw;
+ int err, size;
+
+ size = (rvu_read64(rvu, blkaddr, NIX_AF_CONST3) >> 16) & 0x0F;
+ size = (1ULL << size);
+
+ /* Alloc memory for multicast/mirror replication entries */
+ err = qmem_alloc(rvu->dev, &mcast->mce_ctx,
+ (256UL << MC_TBL_SIZE), size);
+ if (err)
+ return -ENOMEM;
+
+ rvu_write64(rvu, blkaddr, NIX_AF_RX_MCAST_BASE,
+ (u64)mcast->mce_ctx->iova);
+
+ /* Set max list length equal to max no of VFs per PF + PF itself */
+ rvu_write64(rvu, blkaddr, NIX_AF_RX_MCAST_CFG,
+ BIT_ULL(36) | (hw->max_vfs_per_pf << 4) | MC_TBL_SIZE);
+
+ /* Alloc memory for multicast replication buffers */
+ size = rvu_read64(rvu, blkaddr, NIX_AF_MC_MIRROR_CONST) & 0xFFFF;
+ err = qmem_alloc(rvu->dev, &mcast->mcast_buf,
+ (8UL << MC_BUF_CNT), size);
+ if (err)
+ return -ENOMEM;
+
+ rvu_write64(rvu, blkaddr, NIX_AF_RX_MCAST_BUF_BASE,
+ (u64)mcast->mcast_buf->iova);
+
+ /* Alloc pkind for NIX internal RX multicast/mirror replay */
+ mcast->replay_pkind = rvu_alloc_rsrc(&hw->pkind.rsrc);
+
+ rvu_write64(rvu, blkaddr, NIX_AF_RX_MCAST_BUF_CFG,
+ BIT_ULL(63) | (mcast->replay_pkind << 24) |
+ BIT_ULL(20) | MC_BUF_CNT);
+
+ spin_lock_init(&mcast->mce_lock);
+
+ return nix_setup_bcast_tables(rvu, nix_hw);
+}
+
+static int nix_setup_txschq(struct rvu *rvu, struct nix_hw *nix_hw, int blkaddr)
+{
+ struct nix_txsch *txsch;
+ u64 cfg, reg;
+ int err, lvl;
+
+ /* Get scheduler queue count of each type and alloc
+ * bitmap for each for alloc/free/attach operations.
+ */
+ for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) {
+ txsch = &nix_hw->txsch[lvl];
+ txsch->lvl = lvl;
+ switch (lvl) {
+ case NIX_TXSCH_LVL_SMQ:
+ reg = NIX_AF_MDQ_CONST;
+ break;
+ case NIX_TXSCH_LVL_TL4:
+ reg = NIX_AF_TL4_CONST;
+ break;
+ case NIX_TXSCH_LVL_TL3:
+ reg = NIX_AF_TL3_CONST;
+ break;
+ case NIX_TXSCH_LVL_TL2:
+ reg = NIX_AF_TL2_CONST;
+ break;
+ case NIX_TXSCH_LVL_TL1:
+ reg = NIX_AF_TL1_CONST;
+ break;
+ }
+ cfg = rvu_read64(rvu, blkaddr, reg);
+ txsch->schq.max = cfg & 0xFFFF;
+ err = rvu_alloc_bitmap(&txsch->schq);
+ if (err)
+ return err;
+
+ /* Allocate memory for scheduler queues to
+ * PF/VF pcifunc mapping info.
+ */
+ txsch->pfvf_map = devm_kcalloc(rvu->dev, txsch->schq.max,
+ sizeof(u16), GFP_KERNEL);
+ if (!txsch->pfvf_map)
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+int rvu_mbox_handler_NIX_STATS_RST(struct rvu *rvu, struct msg_req *req,
+ struct msg_rsp *rsp)
+{
+ struct rvu_hwinfo *hw = rvu->hw;
+ u16 pcifunc = req->hdr.pcifunc;
+ int i, nixlf, blkaddr;
+ u64 stats;
+
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc);
+ if (blkaddr < 0)
+ return NIX_AF_ERR_AF_LF_INVALID;
+
+ nixlf = rvu_get_lf(rvu, &hw->block[blkaddr], pcifunc, 0);
+ if (nixlf < 0)
+ return NIX_AF_ERR_AF_LF_INVALID;
+
+ /* Get stats count supported by HW */
+ stats = rvu_read64(rvu, blkaddr, NIX_AF_CONST1);
+
+ /* Reset tx stats */
+ for (i = 0; i < ((stats >> 24) & 0xFF); i++)
+ rvu_write64(rvu, blkaddr, NIX_AF_LFX_TX_STATX(nixlf, i), 0);
+
+ /* Reset rx stats */
+ for (i = 0; i < ((stats >> 32) & 0xFF); i++)
+ rvu_write64(rvu, blkaddr, NIX_AF_LFX_RX_STATX(nixlf, i), 0);
+
+ return 0;
+}
+
+/* Returns the ALG index to be set into NPC_RX_ACTION */
+static int get_flowkey_alg_idx(u32 flow_cfg)
+{
+ u32 ip_cfg;
+
+ flow_cfg &= ~FLOW_KEY_TYPE_PORT;
+ ip_cfg = FLOW_KEY_TYPE_IPV4 | FLOW_KEY_TYPE_IPV6;
+ if (flow_cfg == ip_cfg)
+ return FLOW_KEY_ALG_IP;
+ else if (flow_cfg == (ip_cfg | FLOW_KEY_TYPE_TCP))
+ return FLOW_KEY_ALG_TCP;
+ else if (flow_cfg == (ip_cfg | FLOW_KEY_TYPE_UDP))
+ return FLOW_KEY_ALG_UDP;
+ else if (flow_cfg == (ip_cfg | FLOW_KEY_TYPE_SCTP))
+ return FLOW_KEY_ALG_SCTP;
+ else if (flow_cfg == (ip_cfg | FLOW_KEY_TYPE_TCP | FLOW_KEY_TYPE_UDP))
+ return FLOW_KEY_ALG_TCP_UDP;
+ else if (flow_cfg == (ip_cfg | FLOW_KEY_TYPE_TCP | FLOW_KEY_TYPE_SCTP))
+ return FLOW_KEY_ALG_TCP_SCTP;
+ else if (flow_cfg == (ip_cfg | FLOW_KEY_TYPE_UDP | FLOW_KEY_TYPE_SCTP))
+ return FLOW_KEY_ALG_UDP_SCTP;
+ else if (flow_cfg == (ip_cfg | FLOW_KEY_TYPE_TCP |
+ FLOW_KEY_TYPE_UDP | FLOW_KEY_TYPE_SCTP))
+ return FLOW_KEY_ALG_TCP_UDP_SCTP;
+
+ return FLOW_KEY_ALG_PORT;
+}
+
+int rvu_mbox_handler_NIX_RSS_FLOWKEY_CFG(struct rvu *rvu,
+ struct nix_rss_flowkey_cfg *req,
+ struct msg_rsp *rsp)
+{
+ struct rvu_hwinfo *hw = rvu->hw;
+ u16 pcifunc = req->hdr.pcifunc;
+ int alg_idx, nixlf, blkaddr;
+
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc);
+ if (blkaddr < 0)
+ return NIX_AF_ERR_AF_LF_INVALID;
+
+ nixlf = rvu_get_lf(rvu, &hw->block[blkaddr], pcifunc, 0);
+ if (nixlf < 0)
+ return NIX_AF_ERR_AF_LF_INVALID;
+
+ alg_idx = get_flowkey_alg_idx(req->flowkey_cfg);
+
+ rvu_npc_update_flowkey_alg_idx(rvu, pcifunc, nixlf, req->group,
+ alg_idx, req->mcam_index);
+ return 0;
+}
+
+static void set_flowkey_fields(struct nix_rx_flowkey_alg *alg, u32 flow_cfg)
+{
+ struct nix_rx_flowkey_alg *field = NULL;
+ int idx, key_type;
+
+ if (!alg)
+ return;
+
+ /* FIELD0: IPv4
+ * FIELD1: IPv6
+ * FIELD2: TCP/UDP/SCTP/ALL
+ * FIELD3: Unused
+ * FIELD4: Unused
+ *
+ * Each of the 32 possible flow key algorithm definitions should
+ * fall into above incremental config (except ALG0). Otherwise a
+ * single NPC MCAM entry is not sufficient for supporting RSS.
+ *
+ * If a different definition or combination needed then NPC MCAM
+ * has to be programmed to filter such pkts and it's action should
+ * point to this definition to calculate flowtag or hash.
+ */
+ for (idx = 0; idx < 32; idx++) {
+ key_type = flow_cfg & BIT_ULL(idx);
+ if (!key_type)
+ continue;
+ switch (key_type) {
+ case FLOW_KEY_TYPE_PORT:
+ field = &alg[0];
+ field->sel_chan = true;
+ /* This should be set to 1, when SEL_CHAN is set */
+ field->bytesm1 = 1;
+ break;
+ case FLOW_KEY_TYPE_IPV4:
+ field = &alg[0];
+ field->lid = NPC_LID_LC;
+ field->ltype_match = NPC_LT_LC_IP;
+ field->hdr_offset = 12; /* SIP offset */
+ field->bytesm1 = 7; /* SIP + DIP, 8 bytes */
+ field->ltype_mask = 0xF; /* Match only IPv4 */
+ break;
+ case FLOW_KEY_TYPE_IPV6:
+ field = &alg[1];
+ field->lid = NPC_LID_LC;
+ field->ltype_match = NPC_LT_LC_IP6;
+ field->hdr_offset = 8; /* SIP offset */
+ field->bytesm1 = 31; /* SIP + DIP, 32 bytes */
+ field->ltype_mask = 0xF; /* Match only IPv6 */
+ break;
+ case FLOW_KEY_TYPE_TCP:
+ case FLOW_KEY_TYPE_UDP:
+ case FLOW_KEY_TYPE_SCTP:
+ field = &alg[2];
+ field->lid = NPC_LID_LD;
+ field->bytesm1 = 3; /* Sport + Dport, 4 bytes */
+ if (key_type == FLOW_KEY_TYPE_TCP)
+ field->ltype_match |= NPC_LT_LD_TCP;
+ else if (key_type == FLOW_KEY_TYPE_UDP)
+ field->ltype_match |= NPC_LT_LD_UDP;
+ else if (key_type == FLOW_KEY_TYPE_SCTP)
+ field->ltype_match |= NPC_LT_LD_SCTP;
+ field->key_offset = 32; /* After IPv4/v6 SIP, DIP */
+ field->ltype_mask = ~field->ltype_match;
+ break;
+ }
+ if (field)
+ field->ena = 1;
+ field = NULL;
+ }
+}
+
+static void nix_rx_flowkey_alg_cfg(struct rvu *rvu, int blkaddr)
+{
+#define FIELDS_PER_ALG 5
+ u64 field[FLOW_KEY_ALG_MAX][FIELDS_PER_ALG];
+ u32 flowkey_cfg, minkey_cfg;
+ int alg, fid;
+
+ memset(&field, 0, sizeof(u64) * FLOW_KEY_ALG_MAX * FIELDS_PER_ALG);
+
+ /* Only incoming channel number */
+ flowkey_cfg = FLOW_KEY_TYPE_PORT;
+ set_flowkey_fields((void *)&field[FLOW_KEY_ALG_PORT], flowkey_cfg);
+
+ /* For a incoming pkt if none of the fields match then flowkey
+ * will be zero, hence tag generated will also be zero.
+ * RSS entry at rsse_index = NIX_AF_LF()_RSS_GRP()[OFFSET] will
+ * be used to queue the packet.
+ */
+
+ /* IPv4/IPv6 SIP/DIPs */
+ flowkey_cfg = FLOW_KEY_TYPE_IPV4 | FLOW_KEY_TYPE_IPV6;
+ set_flowkey_fields((void *)&field[FLOW_KEY_ALG_IP], flowkey_cfg);
+
+ /* TCPv4/v6 4-tuple, SIP, DIP, Sport, Dport */
+ minkey_cfg = flowkey_cfg;
+ flowkey_cfg = minkey_cfg | FLOW_KEY_TYPE_TCP;
+ set_flowkey_fields((void *)&field[FLOW_KEY_ALG_TCP], flowkey_cfg);
+
+ /* UDPv4/v6 4-tuple, SIP, DIP, Sport, Dport */
+ flowkey_cfg = minkey_cfg | FLOW_KEY_TYPE_UDP;
+ set_flowkey_fields((void *)&field[FLOW_KEY_ALG_UDP], flowkey_cfg);
+
+ /* SCTPv4/v6 4-tuple, SIP, DIP, Sport, Dport */
+ flowkey_cfg = minkey_cfg | FLOW_KEY_TYPE_SCTP;
+ set_flowkey_fields((void *)&field[FLOW_KEY_ALG_SCTP], flowkey_cfg);
+
+ /* TCP/UDP v4/v6 4-tuple, rest IP pkts 2-tuple */
+ flowkey_cfg = minkey_cfg | FLOW_KEY_TYPE_TCP | FLOW_KEY_TYPE_UDP;
+ set_flowkey_fields((void *)&field[FLOW_KEY_ALG_TCP_UDP], flowkey_cfg);
+
+ /* TCP/SCTP v4/v6 4-tuple, rest IP pkts 2-tuple */
+ flowkey_cfg = minkey_cfg | FLOW_KEY_TYPE_TCP | FLOW_KEY_TYPE_SCTP;
+ set_flowkey_fields((void *)&field[FLOW_KEY_ALG_TCP_SCTP], flowkey_cfg);
+
+ /* UDP/SCTP v4/v6 4-tuple, rest IP pkts 2-tuple */
+ flowkey_cfg = minkey_cfg | FLOW_KEY_TYPE_UDP | FLOW_KEY_TYPE_SCTP;
+ set_flowkey_fields((void *)&field[FLOW_KEY_ALG_UDP_SCTP], flowkey_cfg);
+
+ /* TCP/UDP/SCTP v4/v6 4-tuple, rest IP pkts 2-tuple */
+ flowkey_cfg = minkey_cfg | FLOW_KEY_TYPE_TCP |
+ FLOW_KEY_TYPE_UDP | FLOW_KEY_TYPE_SCTP;
+ set_flowkey_fields((void *)&field[FLOW_KEY_ALG_TCP_UDP_SCTP],
+ flowkey_cfg);
+
+ for (alg = 0; alg < FLOW_KEY_ALG_MAX; alg++) {
+ for (fid = 0; fid < FIELDS_PER_ALG; fid++)
+ rvu_write64(rvu, blkaddr,
+ NIX_AF_RX_FLOW_KEY_ALGX_FIELDX(alg, fid),
+ field[alg][fid]);
+ }
+}
+
+int rvu_mbox_handler_NIX_SET_MAC_ADDR(struct rvu *rvu,
+ struct nix_set_mac_addr *req,
+ struct msg_rsp *rsp)
+{
+ struct rvu_hwinfo *hw = rvu->hw;
+ u16 pcifunc = req->hdr.pcifunc;
+ struct rvu_pfvf *pfvf;
+ int blkaddr, nixlf;
+
+ 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;
+
+ nixlf = rvu_get_lf(rvu, &hw->block[blkaddr], pcifunc, 0);
+ if (nixlf < 0)
+ return NIX_AF_ERR_AF_LF_INVALID;
+
+ ether_addr_copy(pfvf->mac_addr, req->mac_addr);
+
+ rvu_npc_install_ucast_entry(rvu, pcifunc, nixlf,
+ pfvf->rx_chan_base, req->mac_addr);
+ return 0;
+}
+
+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;
+ struct rvu_hwinfo *hw = rvu->hw;
+ u16 pcifunc = req->hdr.pcifunc;
+ struct rvu_pfvf *pfvf;
+ int blkaddr, nixlf;
+
+ 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;
+
+ nixlf = rvu_get_lf(rvu, &hw->block[blkaddr], pcifunc, 0);
+ if (nixlf < 0)
+ return NIX_AF_ERR_AF_LF_INVALID;
+
+ if (req->mode & NIX_RX_MODE_PROMISC)
+ allmulti = false;
+ else if (req->mode & NIX_RX_MODE_ALLMULTI)
+ allmulti = true;
+ else
+ disable_promisc = true;
+
+ if (disable_promisc)
+ rvu_npc_disable_promisc_entry(rvu, pcifunc, nixlf);
+ else
+ rvu_npc_install_promisc_entry(rvu, pcifunc, nixlf,
+ pfvf->rx_chan_base, allmulti);
+ return 0;
+}
+
+static int nix_calibrate_x2p(struct rvu *rvu, int blkaddr)
+{
+ int idx, err;
+ u64 status;
+
+ /* Start X2P bus calibration */
+ rvu_write64(rvu, blkaddr, NIX_AF_CFG,
+ rvu_read64(rvu, blkaddr, NIX_AF_CFG) | BIT_ULL(9));
+ /* Wait for calibration to complete */
+ err = rvu_poll_reg(rvu, blkaddr,
+ NIX_AF_STATUS, BIT_ULL(10), false);
+ if (err) {
+ dev_err(rvu->dev, "NIX X2P bus calibration failed\n");
+ return err;
+ }
+
+ status = rvu_read64(rvu, blkaddr, NIX_AF_STATUS);
+ /* Check if CGX devices are ready */
+ for (idx = 0; idx < cgx_get_cgx_cnt(); idx++) {
+ if (status & (BIT_ULL(16 + idx)))
+ continue;
+ dev_err(rvu->dev,
+ "CGX%d didn't respond to NIX X2P calibration\n", idx);
+ err = -EBUSY;
+ }
+
+ /* Check if LBK is ready */
+ if (!(status & BIT_ULL(19))) {
+ dev_err(rvu->dev,
+ "LBK didn't respond to NIX X2P calibration\n");
+ err = -EBUSY;
+ }
+
+ /* Clear 'calibrate_x2p' bit */
+ rvu_write64(rvu, blkaddr, NIX_AF_CFG,
+ rvu_read64(rvu, blkaddr, NIX_AF_CFG) & ~BIT_ULL(9));
+ if (err || (status & 0x3FFULL))
+ dev_err(rvu->dev,
+ "NIX X2P calibration failed, status 0x%llx\n", status);
+ if (err)
+ return err;
+ return 0;
+}
+
+static int nix_aq_init(struct rvu *rvu, struct rvu_block *block)
+{
+ u64 cfg;
+ int err;
+
+ /* Set admin queue endianness */
+ cfg = rvu_read64(rvu, block->addr, NIX_AF_CFG);
+#ifdef __BIG_ENDIAN
+ cfg |= BIT_ULL(1);
+ rvu_write64(rvu, block->addr, NIX_AF_CFG, cfg);
+#else
+ cfg &= ~BIT_ULL(1);
+ rvu_write64(rvu, block->addr, NIX_AF_CFG, cfg);
+#endif
+
+ /* Do not bypass NDC cache */
+ cfg = rvu_read64(rvu, block->addr, NIX_AF_NDC_CFG);
+ cfg &= ~0x3FFEULL;
+ rvu_write64(rvu, block->addr, NIX_AF_NDC_CFG, cfg);
+
+ /* Result structure can be followed by RQ/SQ/CQ context at
+ * RES + 128bytes and a write mask at RES + 256 bytes, depending on
+ * operation type. Alloc sufficient result memory for all operations.
+ */
+ err = rvu_aq_alloc(rvu, &block->aq,
+ Q_COUNT(AQ_SIZE), sizeof(struct nix_aq_inst_s),
+ ALIGN(sizeof(struct nix_aq_res_s), 128) + 256);
+ if (err)
+ return err;
+
+ rvu_write64(rvu, block->addr, NIX_AF_AQ_CFG, AQ_SIZE);
+ rvu_write64(rvu, block->addr,
+ NIX_AF_AQ_BASE, (u64)block->aq->inst->iova);
+ return 0;
+}
+
+int rvu_nix_init(struct rvu *rvu)
+{
+ struct rvu_hwinfo *hw = rvu->hw;
+ struct rvu_block *block;
+ int blkaddr, err;
+ u64 cfg;
+
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, 0);
+ if (blkaddr < 0)
+ return 0;
+ block = &hw->block[blkaddr];
+
+ /* Calibrate X2P bus to check if CGX/LBK links are fine */
+ err = nix_calibrate_x2p(rvu, blkaddr);
+ if (err)
+ return err;
+
+ /* Set num of links of each type */
+ cfg = rvu_read64(rvu, blkaddr, NIX_AF_CONST);
+ hw->cgx = (cfg >> 12) & 0xF;
+ hw->lmac_per_cgx = (cfg >> 8) & 0xF;
+ hw->cgx_links = hw->cgx * hw->lmac_per_cgx;
+ hw->lbk_links = 1;
+ hw->sdp_links = 1;
+
+ /* Initialize admin queue */
+ err = nix_aq_init(rvu, block);
+ if (err)
+ return err;
+
+ /* Restore CINT timer delay to HW reset values */
+ rvu_write64(rvu, blkaddr, NIX_AF_CINT_DELAY, 0x0ULL);
+
+ /* Configure segmentation offload formats */
+ nix_setup_lso(rvu, blkaddr);
+
+ if (blkaddr == BLKADDR_NIX0) {
+ hw->nix0 = devm_kzalloc(rvu->dev,
+ sizeof(struct nix_hw), GFP_KERNEL);
+ if (!hw->nix0)
+ return -ENOMEM;
+
+ err = nix_setup_txschq(rvu, hw->nix0, blkaddr);
+ if (err)
+ return err;
+
+ err = nix_setup_mcast(rvu, hw->nix0, blkaddr);
+ if (err)
+ return err;
+
+ /* Config Outer L2, IP, TCP and UDP's NPC layer info.
+ * This helps HW protocol checker to identify headers
+ * and validate length and checksums.
+ */
+ rvu_write64(rvu, blkaddr, NIX_AF_RX_DEF_OL2,
+ (NPC_LID_LA << 8) | (NPC_LT_LA_ETHER << 4) | 0x0F);
+ rvu_write64(rvu, blkaddr, NIX_AF_RX_DEF_OUDP,
+ (NPC_LID_LD << 8) | (NPC_LT_LD_UDP << 4) | 0x0F);
+ rvu_write64(rvu, blkaddr, NIX_AF_RX_DEF_OTCP,
+ (NPC_LID_LD << 8) | (NPC_LT_LD_TCP << 4) | 0x0F);
+ rvu_write64(rvu, blkaddr, NIX_AF_RX_DEF_OIP4,
+ (NPC_LID_LC << 8) | (NPC_LT_LC_IP << 4) | 0x0F);
+
+ nix_rx_flowkey_alg_cfg(rvu, blkaddr);
+ }
+ return 0;
+}
+
+void rvu_nix_freemem(struct rvu *rvu)
+{
+ struct rvu_hwinfo *hw = rvu->hw;
+ struct rvu_block *block;
+ struct nix_txsch *txsch;
+ struct nix_mcast *mcast;
+ struct nix_hw *nix_hw;
+ int blkaddr, lvl;
+
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, 0);
+ if (blkaddr < 0)
+ return;
+
+ block = &hw->block[blkaddr];
+ rvu_aq_free(rvu, block->aq);
+
+ if (blkaddr == BLKADDR_NIX0) {
+ nix_hw = get_nix_hw(rvu->hw, blkaddr);
+ if (!nix_hw)
+ return;
+
+ for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) {
+ txsch = &nix_hw->txsch[lvl];
+ kfree(txsch->schq.bmap);
+ }
+
+ mcast = &nix_hw->mcast;
+ qmem_free(rvu->dev, mcast->mce_ctx);
+ qmem_free(rvu->dev, mcast->mcast_buf);
+ }
+}
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c
new file mode 100644
index 000000000000..7531fdc54fa1
--- /dev/null
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c
@@ -0,0 +1,472 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Marvell OcteonTx2 RVU Admin Function driver
+ *
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include "rvu_struct.h"
+#include "rvu_reg.h"
+#include "rvu.h"
+
+static int npa_aq_enqueue_wait(struct rvu *rvu, struct rvu_block *block,
+ struct npa_aq_inst_s *inst)
+{
+ struct admin_queue *aq = block->aq;
+ struct npa_aq_res_s *result;
+ int timeout = 1000;
+ u64 reg, head;
+
+ result = (struct npa_aq_res_s *)aq->res->base;
+
+ /* Get current head pointer where to append this instruction */
+ reg = rvu_read64(rvu, block->addr, NPA_AF_AQ_STATUS);
+ head = (reg >> 4) & AQ_PTR_MASK;
+
+ memcpy((void *)(aq->inst->base + (head * aq->inst->entry_sz)),
+ (void *)inst, aq->inst->entry_sz);
+ memset(result, 0, sizeof(*result));
+ /* sync into memory */
+ wmb();
+
+ /* Ring the doorbell and wait for result */
+ rvu_write64(rvu, block->addr, NPA_AF_AQ_DOOR, 1);
+ while (result->compcode == NPA_AQ_COMP_NOTDONE) {
+ cpu_relax();
+ udelay(1);
+ timeout--;
+ if (!timeout)
+ return -EBUSY;
+ }
+
+ if (result->compcode != NPA_AQ_COMP_GOOD)
+ /* TODO: Replace this with some error code */
+ return -EBUSY;
+
+ return 0;
+}
+
+static int rvu_npa_aq_enq_inst(struct rvu *rvu, struct npa_aq_enq_req *req,
+ struct npa_aq_enq_rsp *rsp)
+{
+ struct rvu_hwinfo *hw = rvu->hw;
+ u16 pcifunc = req->hdr.pcifunc;
+ int blkaddr, npalf, rc = 0;
+ struct npa_aq_inst_s inst;
+ struct rvu_block *block;
+ struct admin_queue *aq;
+ struct rvu_pfvf *pfvf;
+ void *ctx, *mask;
+ bool ena;
+
+ pfvf = rvu_get_pfvf(rvu, pcifunc);
+ if (!pfvf->aura_ctx || req->aura_id >= pfvf->aura_ctx->qsize)
+ return NPA_AF_ERR_AQ_ENQUEUE;
+
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, pcifunc);
+ if (!pfvf->npalf || blkaddr < 0)
+ return NPA_AF_ERR_AF_LF_INVALID;
+
+ block = &hw->block[blkaddr];
+ aq = block->aq;
+ if (!aq) {
+ dev_warn(rvu->dev, "%s: NPA AQ not initialized\n", __func__);
+ return NPA_AF_ERR_AQ_ENQUEUE;
+ }
+
+ npalf = rvu_get_lf(rvu, block, pcifunc, 0);
+ if (npalf < 0)
+ return NPA_AF_ERR_AF_LF_INVALID;
+
+ memset(&inst, 0, sizeof(struct npa_aq_inst_s));
+ inst.cindex = req->aura_id;
+ inst.lf = npalf;
+ inst.ctype = req->ctype;
+ inst.op = req->op;
+ /* Currently we are not supporting enqueuing multiple instructions,
+ * so always choose first entry in result memory.
+ */
+ inst.res_addr = (u64)aq->res->iova;
+
+ /* Clean result + context memory */
+ memset(aq->res->base, 0, aq->res->entry_sz);
+ /* Context needs to be written at RES_ADDR + 128 */
+ ctx = aq->res->base + 128;
+ /* Mask needs to be written at RES_ADDR + 256 */
+ mask = aq->res->base + 256;
+
+ switch (req->op) {
+ case NPA_AQ_INSTOP_WRITE:
+ /* Copy context and write mask */
+ if (req->ctype == NPA_AQ_CTYPE_AURA) {
+ memcpy(mask, &req->aura_mask,
+ sizeof(struct npa_aura_s));
+ memcpy(ctx, &req->aura, sizeof(struct npa_aura_s));
+ } else {
+ memcpy(mask, &req->pool_mask,
+ sizeof(struct npa_pool_s));
+ memcpy(ctx, &req->pool, sizeof(struct npa_pool_s));
+ }
+ break;
+ case NPA_AQ_INSTOP_INIT:
+ if (req->ctype == NPA_AQ_CTYPE_AURA) {
+ if (req->aura.pool_addr >= pfvf->pool_ctx->qsize) {
+ rc = NPA_AF_ERR_AQ_FULL;
+ break;
+ }
+ /* Set pool's context address */
+ req->aura.pool_addr = pfvf->pool_ctx->iova +
+ (req->aura.pool_addr * pfvf->pool_ctx->entry_sz);
+ memcpy(ctx, &req->aura, sizeof(struct npa_aura_s));
+ } else { /* POOL's context */
+ memcpy(ctx, &req->pool, sizeof(struct npa_pool_s));
+ }
+ break;
+ case NPA_AQ_INSTOP_NOP:
+ case NPA_AQ_INSTOP_READ:
+ case NPA_AQ_INSTOP_LOCK:
+ case NPA_AQ_INSTOP_UNLOCK:
+ break;
+ default:
+ rc = NPA_AF_ERR_AQ_FULL;
+ break;
+ }
+
+ if (rc)
+ return rc;
+
+ spin_lock(&aq->lock);
+
+ /* Submit the instruction to AQ */
+ rc = npa_aq_enqueue_wait(rvu, block, &inst);
+ if (rc) {
+ spin_unlock(&aq->lock);
+ return rc;
+ }
+
+ /* Set aura bitmap if aura hw context is enabled */
+ if (req->ctype == NPA_AQ_CTYPE_AURA) {
+ if (req->op == NPA_AQ_INSTOP_INIT && req->aura.ena)
+ __set_bit(req->aura_id, pfvf->aura_bmap);
+ if (req->op == NPA_AQ_INSTOP_WRITE) {
+ ena = (req->aura.ena & req->aura_mask.ena) |
+ (test_bit(req->aura_id, pfvf->aura_bmap) &
+ ~req->aura_mask.ena);
+ if (ena)
+ __set_bit(req->aura_id, pfvf->aura_bmap);
+ else
+ __clear_bit(req->aura_id, pfvf->aura_bmap);
+ }
+ }
+
+ /* Set pool bitmap if pool hw context is enabled */
+ if (req->ctype == NPA_AQ_CTYPE_POOL) {
+ if (req->op == NPA_AQ_INSTOP_INIT && req->pool.ena)
+ __set_bit(req->aura_id, pfvf->pool_bmap);
+ if (req->op == NPA_AQ_INSTOP_WRITE) {
+ ena = (req->pool.ena & req->pool_mask.ena) |
+ (test_bit(req->aura_id, pfvf->pool_bmap) &
+ ~req->pool_mask.ena);
+ if (ena)
+ __set_bit(req->aura_id, pfvf->pool_bmap);
+ else
+ __clear_bit(req->aura_id, pfvf->pool_bmap);
+ }
+ }
+ spin_unlock(&aq->lock);
+
+ if (rsp) {
+ /* Copy read context into mailbox */
+ if (req->op == NPA_AQ_INSTOP_READ) {
+ if (req->ctype == NPA_AQ_CTYPE_AURA)
+ memcpy(&rsp->aura, ctx,
+ sizeof(struct npa_aura_s));
+ else
+ memcpy(&rsp->pool, ctx,
+ sizeof(struct npa_pool_s));
+ }
+ }
+
+ return 0;
+}
+
+static int npa_lf_hwctx_disable(struct rvu *rvu, struct hwctx_disable_req *req)
+{
+ struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, req->hdr.pcifunc);
+ struct npa_aq_enq_req aq_req;
+ unsigned long *bmap;
+ int id, cnt = 0;
+ int err = 0, rc;
+
+ if (!pfvf->pool_ctx || !pfvf->aura_ctx)
+ return NPA_AF_ERR_AQ_ENQUEUE;
+
+ memset(&aq_req, 0, sizeof(struct npa_aq_enq_req));
+ aq_req.hdr.pcifunc = req->hdr.pcifunc;
+
+ if (req->ctype == NPA_AQ_CTYPE_POOL) {
+ aq_req.pool.ena = 0;
+ aq_req.pool_mask.ena = 1;
+ cnt = pfvf->pool_ctx->qsize;
+ bmap = pfvf->pool_bmap;
+ } else if (req->ctype == NPA_AQ_CTYPE_AURA) {
+ aq_req.aura.ena = 0;
+ aq_req.aura_mask.ena = 1;
+ cnt = pfvf->aura_ctx->qsize;
+ bmap = pfvf->aura_bmap;
+ }
+
+ aq_req.ctype = req->ctype;
+ aq_req.op = NPA_AQ_INSTOP_WRITE;
+
+ for (id = 0; id < cnt; id++) {
+ if (!test_bit(id, bmap))
+ continue;
+ aq_req.aura_id = id;
+ rc = rvu_npa_aq_enq_inst(rvu, &aq_req, NULL);
+ if (rc) {
+ err = rc;
+ dev_err(rvu->dev, "Failed to disable %s:%d context\n",
+ (req->ctype == NPA_AQ_CTYPE_AURA) ?
+ "Aura" : "Pool", id);
+ }
+ }
+
+ return err;
+}
+
+int rvu_mbox_handler_NPA_AQ_ENQ(struct rvu *rvu,
+ struct npa_aq_enq_req *req,
+ struct npa_aq_enq_rsp *rsp)
+{
+ return rvu_npa_aq_enq_inst(rvu, req, rsp);
+}
+
+int rvu_mbox_handler_NPA_HWCTX_DISABLE(struct rvu *rvu,
+ struct hwctx_disable_req *req,
+ struct msg_rsp *rsp)
+{
+ return npa_lf_hwctx_disable(rvu, req);
+}
+
+static void npa_ctx_free(struct rvu *rvu, struct rvu_pfvf *pfvf)
+{
+ kfree(pfvf->aura_bmap);
+ pfvf->aura_bmap = NULL;
+
+ qmem_free(rvu->dev, pfvf->aura_ctx);
+ pfvf->aura_ctx = NULL;
+
+ kfree(pfvf->pool_bmap);
+ pfvf->pool_bmap = NULL;
+
+ qmem_free(rvu->dev, pfvf->pool_ctx);
+ pfvf->pool_ctx = NULL;
+
+ qmem_free(rvu->dev, pfvf->npa_qints_ctx);
+ pfvf->npa_qints_ctx = NULL;
+}
+
+int rvu_mbox_handler_NPA_LF_ALLOC(struct rvu *rvu,
+ struct npa_lf_alloc_req *req,
+ struct npa_lf_alloc_rsp *rsp)
+{
+ int npalf, qints, hwctx_size, err, rc = 0;
+ struct rvu_hwinfo *hw = rvu->hw;
+ u16 pcifunc = req->hdr.pcifunc;
+ struct rvu_block *block;
+ struct rvu_pfvf *pfvf;
+ u64 cfg, ctx_cfg;
+ int blkaddr;
+
+ if (req->aura_sz > NPA_AURA_SZ_MAX ||
+ req->aura_sz == NPA_AURA_SZ_0 || !req->nr_pools)
+ return NPA_AF_ERR_PARAM;
+
+ pfvf = rvu_get_pfvf(rvu, pcifunc);
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, pcifunc);
+ if (!pfvf->npalf || blkaddr < 0)
+ return NPA_AF_ERR_AF_LF_INVALID;
+
+ block = &hw->block[blkaddr];
+ npalf = rvu_get_lf(rvu, block, pcifunc, 0);
+ if (npalf < 0)
+ return NPA_AF_ERR_AF_LF_INVALID;
+
+ /* Reset this NPA LF */
+ err = rvu_lf_reset(rvu, block, npalf);
+ if (err) {
+ dev_err(rvu->dev, "Failed to reset NPALF%d\n", npalf);
+ return NPA_AF_ERR_LF_RESET;
+ }
+
+ ctx_cfg = rvu_read64(rvu, blkaddr, NPA_AF_CONST1);
+
+ /* Alloc memory for aura HW contexts */
+ hwctx_size = 1UL << (ctx_cfg & 0xF);
+ err = qmem_alloc(rvu->dev, &pfvf->aura_ctx,
+ NPA_AURA_COUNT(req->aura_sz), hwctx_size);
+ if (err)
+ goto free_mem;
+
+ pfvf->aura_bmap = kcalloc(NPA_AURA_COUNT(req->aura_sz), sizeof(long),
+ GFP_KERNEL);
+ if (!pfvf->aura_bmap)
+ goto free_mem;
+
+ /* Alloc memory for pool HW contexts */
+ hwctx_size = 1UL << ((ctx_cfg >> 4) & 0xF);
+ err = qmem_alloc(rvu->dev, &pfvf->pool_ctx, req->nr_pools, hwctx_size);
+ if (err)
+ goto free_mem;
+
+ pfvf->pool_bmap = kcalloc(NPA_AURA_COUNT(req->aura_sz), sizeof(long),
+ GFP_KERNEL);
+ if (!pfvf->pool_bmap)
+ goto free_mem;
+
+ /* Get no of queue interrupts supported */
+ cfg = rvu_read64(rvu, blkaddr, NPA_AF_CONST);
+ qints = (cfg >> 28) & 0xFFF;
+
+ /* Alloc memory for Qints HW contexts */
+ hwctx_size = 1UL << ((ctx_cfg >> 8) & 0xF);
+ err = qmem_alloc(rvu->dev, &pfvf->npa_qints_ctx, qints, hwctx_size);
+ if (err)
+ goto free_mem;
+
+ cfg = rvu_read64(rvu, blkaddr, NPA_AF_LFX_AURAS_CFG(npalf));
+ /* Clear way partition mask and set aura offset to '0' */
+ cfg &= ~(BIT_ULL(34) - 1);
+ /* Set aura size & enable caching of contexts */
+ cfg |= (req->aura_sz << 16) | BIT_ULL(34);
+ rvu_write64(rvu, blkaddr, NPA_AF_LFX_AURAS_CFG(npalf), cfg);
+
+ /* Configure aura HW context's base */
+ rvu_write64(rvu, blkaddr, NPA_AF_LFX_LOC_AURAS_BASE(npalf),
+ (u64)pfvf->aura_ctx->iova);
+
+ /* Enable caching of qints hw context */
+ rvu_write64(rvu, blkaddr, NPA_AF_LFX_QINTS_CFG(npalf), BIT_ULL(36));
+ rvu_write64(rvu, blkaddr, NPA_AF_LFX_QINTS_BASE(npalf),
+ (u64)pfvf->npa_qints_ctx->iova);
+
+ goto exit;
+
+free_mem:
+ npa_ctx_free(rvu, pfvf);
+ rc = -ENOMEM;
+
+exit:
+ /* set stack page info */
+ cfg = rvu_read64(rvu, blkaddr, NPA_AF_CONST);
+ rsp->stack_pg_ptrs = (cfg >> 8) & 0xFF;
+ rsp->stack_pg_bytes = cfg & 0xFF;
+ rsp->qints = (cfg >> 28) & 0xFFF;
+ return rc;
+}
+
+int rvu_mbox_handler_NPA_LF_FREE(struct rvu *rvu, struct msg_req *req,
+ struct msg_rsp *rsp)
+{
+ struct rvu_hwinfo *hw = rvu->hw;
+ u16 pcifunc = req->hdr.pcifunc;
+ struct rvu_block *block;
+ struct rvu_pfvf *pfvf;
+ int npalf, err;
+ int blkaddr;
+
+ pfvf = rvu_get_pfvf(rvu, pcifunc);
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, pcifunc);
+ if (!pfvf->npalf || blkaddr < 0)
+ return NPA_AF_ERR_AF_LF_INVALID;
+
+ block = &hw->block[blkaddr];
+ npalf = rvu_get_lf(rvu, block, pcifunc, 0);
+ if (npalf < 0)
+ return NPA_AF_ERR_AF_LF_INVALID;
+
+ /* Reset this NPA LF */
+ err = rvu_lf_reset(rvu, block, npalf);
+ if (err) {
+ dev_err(rvu->dev, "Failed to reset NPALF%d\n", npalf);
+ return NPA_AF_ERR_LF_RESET;
+ }
+
+ npa_ctx_free(rvu, pfvf);
+
+ return 0;
+}
+
+static int npa_aq_init(struct rvu *rvu, struct rvu_block *block)
+{
+ u64 cfg;
+ int err;
+
+ /* Set admin queue endianness */
+ cfg = rvu_read64(rvu, block->addr, NPA_AF_GEN_CFG);
+#ifdef __BIG_ENDIAN
+ cfg |= BIT_ULL(1);
+ rvu_write64(rvu, block->addr, NPA_AF_GEN_CFG, cfg);
+#else
+ cfg &= ~BIT_ULL(1);
+ rvu_write64(rvu, block->addr, NPA_AF_GEN_CFG, cfg);
+#endif
+
+ /* Do not bypass NDC cache */
+ cfg = rvu_read64(rvu, block->addr, NPA_AF_NDC_CFG);
+ cfg &= ~0x03DULL;
+ rvu_write64(rvu, block->addr, NPA_AF_NDC_CFG, cfg);
+
+ /* Result structure can be followed by Aura/Pool context at
+ * RES + 128bytes and a write mask at RES + 256 bytes, depending on
+ * operation type. Alloc sufficient result memory for all operations.
+ */
+ err = rvu_aq_alloc(rvu, &block->aq,
+ Q_COUNT(AQ_SIZE), sizeof(struct npa_aq_inst_s),
+ ALIGN(sizeof(struct npa_aq_res_s), 128) + 256);
+ if (err)
+ return err;
+
+ rvu_write64(rvu, block->addr, NPA_AF_AQ_CFG, AQ_SIZE);
+ rvu_write64(rvu, block->addr,
+ NPA_AF_AQ_BASE, (u64)block->aq->inst->iova);
+ return 0;
+}
+
+int rvu_npa_init(struct rvu *rvu)
+{
+ struct rvu_hwinfo *hw = rvu->hw;
+ int blkaddr, err;
+
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, 0);
+ if (blkaddr < 0)
+ return 0;
+
+ /* Initialize admin queue */
+ err = npa_aq_init(rvu, &hw->block[blkaddr]);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+void rvu_npa_freemem(struct rvu *rvu)
+{
+ struct rvu_hwinfo *hw = rvu->hw;
+ struct rvu_block *block;
+ int blkaddr;
+
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, 0);
+ if (blkaddr < 0)
+ return;
+
+ block = &hw->block[blkaddr];
+ rvu_aq_free(rvu, block->aq);
+}
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
new file mode 100644
index 000000000000..23ff47f7efc5
--- /dev/null
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
@@ -0,0 +1,816 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Marvell OcteonTx2 RVU Admin Function driver
+ *
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include "rvu_struct.h"
+#include "rvu_reg.h"
+#include "rvu.h"
+#include "npc.h"
+#include "npc_profile.h"
+
+#define RSVD_MCAM_ENTRIES_PER_PF 2 /* Bcast & Promisc */
+#define RSVD_MCAM_ENTRIES_PER_NIXLF 1 /* Ucast for LFs */
+
+#define NIXLF_UCAST_ENTRY 0
+#define NIXLF_BCAST_ENTRY 1
+#define NIXLF_PROMISC_ENTRY 2
+
+#define NPC_PARSE_RESULT_DMAC_OFFSET 8
+
+struct mcam_entry {
+#define NPC_MAX_KWS_IN_KEY 7 /* Number of keywords in max keywidth */
+ u64 kw[NPC_MAX_KWS_IN_KEY];
+ u64 kw_mask[NPC_MAX_KWS_IN_KEY];
+ u64 action;
+ u64 vtag_action;
+};
+
+void rvu_npc_set_pkind(struct rvu *rvu, int pkind, struct rvu_pfvf *pfvf)
+{
+ int blkaddr;
+ u64 val = 0;
+
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
+ if (blkaddr < 0)
+ return;
+
+ /* Config CPI base for the PKIND */
+ val = pkind | 1ULL << 62;
+ rvu_write64(rvu, blkaddr, NPC_AF_PKINDX_CPI_DEFX(pkind, 0), val);
+}
+
+int rvu_npc_get_pkind(struct rvu *rvu, u16 pf)
+{
+ struct npc_pkind *pkind = &rvu->hw->pkind;
+ u32 map;
+ int i;
+
+ for (i = 0; i < pkind->rsrc.max; i++) {
+ map = pkind->pfchan_map[i];
+ if (((map >> 16) & 0x3F) == pf)
+ return i;
+ }
+ return -1;
+}
+
+static int npc_get_nixlf_mcam_index(struct npc_mcam *mcam,
+ u16 pcifunc, int nixlf, int type)
+{
+ int pf = rvu_get_pf(pcifunc);
+ int index;
+
+ /* Check if this is for a PF */
+ if (pf && !(pcifunc & RVU_PFVF_FUNC_MASK)) {
+ /* Reserved entries exclude PF0 */
+ pf--;
+ index = mcam->pf_offset + (pf * RSVD_MCAM_ENTRIES_PER_PF);
+ /* Broadcast address matching entry should be first so
+ * that the packet can be replicated to all VFs.
+ */
+ if (type == NIXLF_BCAST_ENTRY)
+ return index;
+ else if (type == NIXLF_PROMISC_ENTRY)
+ return index + 1;
+ }
+
+ return (mcam->nixlf_offset + (nixlf * RSVD_MCAM_ENTRIES_PER_NIXLF));
+}
+
+static int npc_get_bank(struct npc_mcam *mcam, int index)
+{
+ int bank = index / mcam->banksize;
+
+ /* 0,1 & 2,3 banks are combined for this keysize */
+ if (mcam->keysize == NPC_MCAM_KEY_X2)
+ return bank ? 2 : 0;
+
+ return bank;
+}
+
+static bool is_mcam_entry_enabled(struct rvu *rvu, struct npc_mcam *mcam,
+ int blkaddr, int index)
+{
+ int bank = npc_get_bank(mcam, index);
+ u64 cfg;
+
+ index &= (mcam->banksize - 1);
+ cfg = rvu_read64(rvu, blkaddr, NPC_AF_MCAMEX_BANKX_CFG(index, bank));
+ return (cfg & 1);
+}
+
+static void npc_enable_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam,
+ int blkaddr, int index, bool enable)
+{
+ int bank = npc_get_bank(mcam, index);
+ int actbank = bank;
+
+ index &= (mcam->banksize - 1);
+ for (; bank < (actbank + mcam->banks_per_entry); bank++) {
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_MCAMEX_BANKX_CFG(index, bank),
+ enable ? 1 : 0);
+ }
+}
+
+static void npc_get_keyword(struct mcam_entry *entry, int idx,
+ u64 *cam0, u64 *cam1)
+{
+ u64 kw_mask = 0x00;
+
+#define CAM_MASK(n) (BIT_ULL(n) - 1)
+
+ /* 0, 2, 4, 6 indices refer to BANKX_CAMX_W0 and
+ * 1, 3, 5, 7 indices refer to BANKX_CAMX_W1.
+ *
+ * Also, only 48 bits of BANKX_CAMX_W1 are valid.
+ */
+ switch (idx) {
+ case 0:
+ /* BANK(X)_CAM_W0<63:0> = MCAM_KEY[KW0]<63:0> */
+ *cam1 = entry->kw[0];
+ kw_mask = entry->kw_mask[0];
+ break;
+ case 1:
+ /* BANK(X)_CAM_W1<47:0> = MCAM_KEY[KW1]<47:0> */
+ *cam1 = entry->kw[1] & CAM_MASK(48);
+ kw_mask = entry->kw_mask[1] & CAM_MASK(48);
+ break;
+ case 2:
+ /* BANK(X + 1)_CAM_W0<15:0> = MCAM_KEY[KW1]<63:48>
+ * BANK(X + 1)_CAM_W0<63:16> = MCAM_KEY[KW2]<47:0>
+ */
+ *cam1 = (entry->kw[1] >> 48) & CAM_MASK(16);
+ *cam1 |= ((entry->kw[2] & CAM_MASK(48)) << 16);
+ kw_mask = (entry->kw_mask[1] >> 48) & CAM_MASK(16);
+ kw_mask |= ((entry->kw_mask[2] & CAM_MASK(48)) << 16);
+ break;
+ case 3:
+ /* BANK(X + 1)_CAM_W1<15:0> = MCAM_KEY[KW2]<63:48>
+ * BANK(X + 1)_CAM_W1<47:16> = MCAM_KEY[KW3]<31:0>
+ */
+ *cam1 = (entry->kw[2] >> 48) & CAM_MASK(16);
+ *cam1 |= ((entry->kw[3] & CAM_MASK(32)) << 16);
+ kw_mask = (entry->kw_mask[2] >> 48) & CAM_MASK(16);
+ kw_mask |= ((entry->kw_mask[3] & CAM_MASK(32)) << 16);
+ break;
+ case 4:
+ /* BANK(X + 2)_CAM_W0<31:0> = MCAM_KEY[KW3]<63:32>
+ * BANK(X + 2)_CAM_W0<63:32> = MCAM_KEY[KW4]<31:0>
+ */
+ *cam1 = (entry->kw[3] >> 32) & CAM_MASK(32);
+ *cam1 |= ((entry->kw[4] & CAM_MASK(32)) << 32);
+ kw_mask = (entry->kw_mask[3] >> 32) & CAM_MASK(32);
+ kw_mask |= ((entry->kw_mask[4] & CAM_MASK(32)) << 32);
+ break;
+ case 5:
+ /* BANK(X + 2)_CAM_W1<31:0> = MCAM_KEY[KW4]<63:32>
+ * BANK(X + 2)_CAM_W1<47:32> = MCAM_KEY[KW5]<15:0>
+ */
+ *cam1 = (entry->kw[4] >> 32) & CAM_MASK(32);
+ *cam1 |= ((entry->kw[5] & CAM_MASK(16)) << 32);
+ kw_mask = (entry->kw_mask[4] >> 32) & CAM_MASK(32);
+ kw_mask |= ((entry->kw_mask[5] & CAM_MASK(16)) << 32);
+ break;
+ case 6:
+ /* BANK(X + 3)_CAM_W0<47:0> = MCAM_KEY[KW5]<63:16>
+ * BANK(X + 3)_CAM_W0<63:48> = MCAM_KEY[KW6]<15:0>
+ */
+ *cam1 = (entry->kw[5] >> 16) & CAM_MASK(48);
+ *cam1 |= ((entry->kw[6] & CAM_MASK(16)) << 48);
+ kw_mask = (entry->kw_mask[5] >> 16) & CAM_MASK(48);
+ kw_mask |= ((entry->kw_mask[6] & CAM_MASK(16)) << 48);
+ break;
+ case 7:
+ /* BANK(X + 3)_CAM_W1<47:0> = MCAM_KEY[KW6]<63:16> */
+ *cam1 = (entry->kw[6] >> 16) & CAM_MASK(48);
+ kw_mask = (entry->kw_mask[6] >> 16) & CAM_MASK(48);
+ break;
+ }
+
+ *cam1 &= kw_mask;
+ *cam0 = ~*cam1 & kw_mask;
+}
+
+static void npc_config_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam,
+ int blkaddr, int index, u8 intf,
+ struct mcam_entry *entry, bool enable)
+{
+ int bank = npc_get_bank(mcam, index);
+ int kw = 0, actbank, actindex;
+ u64 cam0, cam1;
+
+ actbank = bank; /* Save bank id, to set action later on */
+ actindex = index;
+ index &= (mcam->banksize - 1);
+
+ /* CAM1 takes the comparison value and
+ * CAM0 specifies match for a bit in key being '0' or '1' or 'dontcare'.
+ * CAM1<n> = 0 & CAM0<n> = 1 => match if key<n> = 0
+ * CAM1<n> = 1 & CAM0<n> = 0 => match if key<n> = 1
+ * CAM1<n> = 0 & CAM0<n> = 0 => always match i.e dontcare.
+ */
+ for (; bank < (actbank + mcam->banks_per_entry); bank++, kw = kw + 2) {
+ /* Interface should be set in all banks */
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_MCAMEX_BANKX_CAMX_INTF(index, bank, 1),
+ intf);
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_MCAMEX_BANKX_CAMX_INTF(index, bank, 0),
+ ~intf & 0x3);
+
+ /* Set the match key */
+ npc_get_keyword(entry, kw, &cam0, &cam1);
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_MCAMEX_BANKX_CAMX_W0(index, bank, 1), cam1);
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_MCAMEX_BANKX_CAMX_W0(index, bank, 0), cam0);
+
+ npc_get_keyword(entry, kw + 1, &cam0, &cam1);
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_MCAMEX_BANKX_CAMX_W1(index, bank, 1), cam1);
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_MCAMEX_BANKX_CAMX_W1(index, bank, 0), cam0);
+ }
+
+ /* Set 'action' */
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_MCAMEX_BANKX_ACTION(index, actbank), entry->action);
+
+ /* Set TAG 'action' */
+ rvu_write64(rvu, blkaddr, NPC_AF_MCAMEX_BANKX_TAG_ACT(index, actbank),
+ entry->vtag_action);
+
+ /* Enable the entry */
+ if (enable)
+ npc_enable_mcam_entry(rvu, mcam, blkaddr, actindex, true);
+ else
+ npc_enable_mcam_entry(rvu, mcam, blkaddr, actindex, false);
+}
+
+static u64 npc_get_mcam_action(struct rvu *rvu, struct npc_mcam *mcam,
+ int blkaddr, int index)
+{
+ int bank = npc_get_bank(mcam, index);
+
+ index &= (mcam->banksize - 1);
+ return rvu_read64(rvu, blkaddr,
+ NPC_AF_MCAMEX_BANKX_ACTION(index, bank));
+}
+
+void rvu_npc_install_ucast_entry(struct rvu *rvu, u16 pcifunc,
+ int nixlf, u64 chan, u8 *mac_addr)
+{
+ struct npc_mcam *mcam = &rvu->hw->mcam;
+ struct mcam_entry entry = { {0} };
+ struct nix_rx_action action;
+ int blkaddr, index, kwi;
+ u64 mac = 0;
+
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
+ if (blkaddr < 0)
+ return;
+
+ for (index = ETH_ALEN - 1; index >= 0; index--)
+ mac |= ((u64)*mac_addr++) << (8 * index);
+
+ index = npc_get_nixlf_mcam_index(mcam, pcifunc,
+ nixlf, NIXLF_UCAST_ENTRY);
+
+ /* Match ingress channel and DMAC */
+ entry.kw[0] = chan;
+ entry.kw_mask[0] = 0xFFFULL;
+
+ kwi = NPC_PARSE_RESULT_DMAC_OFFSET / sizeof(u64);
+ entry.kw[kwi] = mac;
+ entry.kw_mask[kwi] = BIT_ULL(48) - 1;
+
+ /* Don't change the action if entry is already enabled
+ * Otherwise RSS action may get overwritten.
+ */
+ if (is_mcam_entry_enabled(rvu, mcam, blkaddr, index)) {
+ *(u64 *)&action = npc_get_mcam_action(rvu, mcam,
+ blkaddr, index);
+ } else {
+ *(u64 *)&action = 0x00;
+ action.op = NIX_RX_ACTIONOP_UCAST;
+ action.pf_func = pcifunc;
+ }
+
+ entry.action = *(u64 *)&action;
+ npc_config_mcam_entry(rvu, mcam, blkaddr, index,
+ NIX_INTF_RX, &entry, true);
+}
+
+void rvu_npc_install_promisc_entry(struct rvu *rvu, u16 pcifunc,
+ int nixlf, u64 chan, bool allmulti)
+{
+ struct npc_mcam *mcam = &rvu->hw->mcam;
+ struct mcam_entry entry = { {0} };
+ struct nix_rx_action action;
+ int blkaddr, index, kwi;
+
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
+ if (blkaddr < 0)
+ return;
+
+ /* Only PF or AF VF can add a promiscuous entry */
+ if (pcifunc & RVU_PFVF_FUNC_MASK)
+ return;
+
+ index = npc_get_nixlf_mcam_index(mcam, pcifunc,
+ nixlf, NIXLF_PROMISC_ENTRY);
+
+ entry.kw[0] = chan;
+ entry.kw_mask[0] = 0xFFFULL;
+
+ if (allmulti) {
+ kwi = NPC_PARSE_RESULT_DMAC_OFFSET / sizeof(u64);
+ entry.kw[kwi] = BIT_ULL(40); /* LSB bit of 1st byte in DMAC */
+ entry.kw_mask[kwi] = BIT_ULL(40);
+ }
+
+ *(u64 *)&action = 0x00;
+ action.op = NIX_RX_ACTIONOP_UCAST;
+ action.pf_func = pcifunc;
+
+ entry.action = *(u64 *)&action;
+ npc_config_mcam_entry(rvu, mcam, blkaddr, index,
+ NIX_INTF_RX, &entry, true);
+}
+
+void rvu_npc_disable_promisc_entry(struct rvu *rvu, u16 pcifunc, int nixlf)
+{
+ struct npc_mcam *mcam = &rvu->hw->mcam;
+ int blkaddr, index;
+
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
+ if (blkaddr < 0)
+ return;
+
+ /* Only PF's have a promiscuous entry */
+ if (pcifunc & RVU_PFVF_FUNC_MASK)
+ return;
+
+ index = npc_get_nixlf_mcam_index(mcam, pcifunc,
+ nixlf, NIXLF_PROMISC_ENTRY);
+ npc_enable_mcam_entry(rvu, mcam, blkaddr, index, false);
+}
+
+void rvu_npc_install_bcast_match_entry(struct rvu *rvu, u16 pcifunc,
+ int nixlf, u64 chan)
+{
+ struct npc_mcam *mcam = &rvu->hw->mcam;
+ struct mcam_entry entry = { {0} };
+ struct nix_rx_action action;
+#ifdef MCAST_MCE
+ struct rvu_pfvf *pfvf;
+#endif
+ int blkaddr, index;
+
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
+ if (blkaddr < 0)
+ return;
+
+ /* Only PF can add a bcast match entry */
+ if (pcifunc & RVU_PFVF_FUNC_MASK)
+ return;
+#ifdef MCAST_MCE
+ pfvf = rvu_get_pfvf(rvu, pcifunc & ~RVU_PFVF_FUNC_MASK);
+#endif
+
+ index = npc_get_nixlf_mcam_index(mcam, pcifunc,
+ nixlf, NIXLF_BCAST_ENTRY);
+
+ /* Check for L2B bit and LMAC channel */
+ entry.kw[0] = BIT_ULL(25) | chan;
+ entry.kw_mask[0] = BIT_ULL(25) | 0xFFFULL;
+
+ *(u64 *)&action = 0x00;
+#ifdef MCAST_MCE
+ /* Early silicon doesn't support pkt replication,
+ * so install entry with UCAST action, so that PF
+ * receives all broadcast packets.
+ */
+ action.op = NIX_RX_ACTIONOP_MCAST;
+ action.pf_func = pcifunc;
+ action.index = pfvf->bcast_mce_idx;
+#else
+ action.op = NIX_RX_ACTIONOP_UCAST;
+ action.pf_func = pcifunc;
+#endif
+
+ entry.action = *(u64 *)&action;
+ npc_config_mcam_entry(rvu, mcam, blkaddr, index,
+ NIX_INTF_RX, &entry, true);
+}
+
+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 nix_rx_action action;
+ int blkaddr, index, bank;
+
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
+ if (blkaddr < 0)
+ return;
+
+ /* Check if this is for reserved default entry */
+ if (mcam_index < 0) {
+ if (group != DEFAULT_RSS_CONTEXT_GROUP)
+ return;
+ index = npc_get_nixlf_mcam_index(mcam, pcifunc,
+ nixlf, NIXLF_UCAST_ENTRY);
+ } else {
+ /* TODO: validate this mcam index */
+ index = mcam_index;
+ }
+
+ if (index >= mcam->total_entries)
+ return;
+
+ bank = npc_get_bank(mcam, index);
+ index &= (mcam->banksize - 1);
+
+ *(u64 *)&action = rvu_read64(rvu, blkaddr,
+ NPC_AF_MCAMEX_BANKX_ACTION(index, bank));
+ /* Ignore if no action was set earlier */
+ if (!*(u64 *)&action)
+ return;
+
+ action.op = NIX_RX_ACTIONOP_RSS;
+ action.pf_func = pcifunc;
+ action.index = group;
+ action.flow_key_alg = alg_idx;
+
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_MCAMEX_BANKX_ACTION(index, bank), *(u64 *)&action);
+}
+
+void rvu_npc_disable_mcam_entries(struct rvu *rvu, u16 pcifunc, int nixlf)
+{
+ struct npc_mcam *mcam = &rvu->hw->mcam;
+ struct nix_rx_action action;
+ int blkaddr, index, bank;
+
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
+ if (blkaddr < 0)
+ return;
+
+ /* Disable ucast MCAM match entry of this PF/VF */
+ index = npc_get_nixlf_mcam_index(mcam, pcifunc,
+ nixlf, NIXLF_UCAST_ENTRY);
+ npc_enable_mcam_entry(rvu, mcam, blkaddr, index, false);
+
+ /* For PF, disable promisc and bcast MCAM match entries */
+ if (!(pcifunc & RVU_PFVF_FUNC_MASK)) {
+ index = npc_get_nixlf_mcam_index(mcam, pcifunc,
+ nixlf, NIXLF_BCAST_ENTRY);
+ /* For bcast, disable only if it's action is not
+ * packet replication, incase if action is replication
+ * then this PF's nixlf is removed from bcast replication
+ * list.
+ */
+ bank = npc_get_bank(mcam, index);
+ index &= (mcam->banksize - 1);
+ *(u64 *)&action = rvu_read64(rvu, blkaddr,
+ NPC_AF_MCAMEX_BANKX_ACTION(index, bank));
+ if (action.op != NIX_RX_ACTIONOP_MCAST)
+ npc_enable_mcam_entry(rvu, mcam, blkaddr, index, false);
+
+ rvu_npc_disable_promisc_entry(rvu, pcifunc, nixlf);
+ }
+}
+
+#define LDATA_EXTRACT_CONFIG(intf, lid, ltype, ld, cfg) \
+ rvu_write64(rvu, blkaddr, \
+ NPC_AF_INTFX_LIDX_LTX_LDX_CFG(intf, lid, ltype, ld), cfg)
+
+#define LDATA_FLAGS_CONFIG(intf, ld, flags, cfg) \
+ rvu_write64(rvu, blkaddr, \
+ NPC_AF_INTFX_LDATAX_FLAGSX_CFG(intf, ld, flags), cfg)
+
+static void npc_config_ldata_extract(struct rvu *rvu, int blkaddr)
+{
+ struct npc_mcam *mcam = &rvu->hw->mcam;
+ int lid, ltype;
+ int lid_count;
+ u64 cfg;
+
+ cfg = rvu_read64(rvu, blkaddr, NPC_AF_CONST);
+ lid_count = (cfg >> 4) & 0xF;
+
+ /* First clear any existing config i.e
+ * disable LDATA and FLAGS extraction.
+ */
+ for (lid = 0; lid < lid_count; lid++) {
+ for (ltype = 0; ltype < 16; ltype++) {
+ LDATA_EXTRACT_CONFIG(NIX_INTF_RX, lid, ltype, 0, 0ULL);
+ LDATA_EXTRACT_CONFIG(NIX_INTF_RX, lid, ltype, 1, 0ULL);
+ LDATA_EXTRACT_CONFIG(NIX_INTF_TX, lid, ltype, 0, 0ULL);
+ LDATA_EXTRACT_CONFIG(NIX_INTF_TX, lid, ltype, 1, 0ULL);
+
+ LDATA_FLAGS_CONFIG(NIX_INTF_RX, 0, ltype, 0ULL);
+ LDATA_FLAGS_CONFIG(NIX_INTF_RX, 1, ltype, 0ULL);
+ LDATA_FLAGS_CONFIG(NIX_INTF_TX, 0, ltype, 0ULL);
+ LDATA_FLAGS_CONFIG(NIX_INTF_TX, 1, ltype, 0ULL);
+ }
+ }
+
+ /* If we plan to extract Outer IPv4 tuple for TCP/UDP pkts
+ * then 112bit key is not sufficient
+ */
+ if (mcam->keysize != NPC_MCAM_KEY_X2)
+ return;
+
+ /* Start placing extracted data/flags from 64bit onwards, for now */
+ /* Extract DMAC from the packet */
+ cfg = (0x05 << 16) | BIT_ULL(7) | NPC_PARSE_RESULT_DMAC_OFFSET;
+ LDATA_EXTRACT_CONFIG(NIX_INTF_RX, NPC_LID_LA, NPC_LT_LA_ETHER, 0, cfg);
+}
+
+static void npc_config_kpuaction(struct rvu *rvu, int blkaddr,
+ struct npc_kpu_profile_action *kpuaction,
+ int kpu, int entry, bool pkind)
+{
+ struct npc_kpu_action0 action0 = {0};
+ struct npc_kpu_action1 action1 = {0};
+ u64 reg;
+
+ action1.errlev = kpuaction->errlev;
+ action1.errcode = kpuaction->errcode;
+ action1.dp0_offset = kpuaction->dp0_offset;
+ action1.dp1_offset = kpuaction->dp1_offset;
+ action1.dp2_offset = kpuaction->dp2_offset;
+
+ if (pkind)
+ reg = NPC_AF_PKINDX_ACTION1(entry);
+ else
+ reg = NPC_AF_KPUX_ENTRYX_ACTION1(kpu, entry);
+
+ rvu_write64(rvu, blkaddr, reg, *(u64 *)&action1);
+
+ action0.byp_count = kpuaction->bypass_count;
+ action0.capture_ena = kpuaction->cap_ena;
+ action0.parse_done = kpuaction->parse_done;
+ action0.next_state = kpuaction->next_state;
+ action0.capture_lid = kpuaction->lid;
+ action0.capture_ltype = kpuaction->ltype;
+ action0.capture_flags = kpuaction->flags;
+ action0.ptr_advance = kpuaction->ptr_advance;
+ action0.var_len_offset = kpuaction->offset;
+ action0.var_len_mask = kpuaction->mask;
+ action0.var_len_right = kpuaction->right;
+ action0.var_len_shift = kpuaction->shift;
+
+ if (pkind)
+ reg = NPC_AF_PKINDX_ACTION0(entry);
+ else
+ reg = NPC_AF_KPUX_ENTRYX_ACTION0(kpu, entry);
+
+ rvu_write64(rvu, blkaddr, reg, *(u64 *)&action0);
+}
+
+static void npc_config_kpucam(struct rvu *rvu, int blkaddr,
+ struct npc_kpu_profile_cam *kpucam,
+ int kpu, int entry)
+{
+ struct npc_kpu_cam cam0 = {0};
+ struct npc_kpu_cam cam1 = {0};
+
+ cam1.state = kpucam->state & kpucam->state_mask;
+ cam1.dp0_data = kpucam->dp0 & kpucam->dp0_mask;
+ cam1.dp1_data = kpucam->dp1 & kpucam->dp1_mask;
+ cam1.dp2_data = kpucam->dp2 & kpucam->dp2_mask;
+
+ cam0.state = ~kpucam->state & kpucam->state_mask;
+ cam0.dp0_data = ~kpucam->dp0 & kpucam->dp0_mask;
+ cam0.dp1_data = ~kpucam->dp1 & kpucam->dp1_mask;
+ cam0.dp2_data = ~kpucam->dp2 & kpucam->dp2_mask;
+
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_KPUX_ENTRYX_CAMX(kpu, entry, 0), *(u64 *)&cam0);
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_KPUX_ENTRYX_CAMX(kpu, entry, 1), *(u64 *)&cam1);
+}
+
+static inline u64 enable_mask(int count)
+{
+ return (((count) < 64) ? ~(BIT_ULL(count) - 1) : (0x00ULL));
+}
+
+static void npc_program_kpu_profile(struct rvu *rvu, int blkaddr, int kpu,
+ struct npc_kpu_profile *profile)
+{
+ int entry, num_entries, max_entries;
+
+ if (profile->cam_entries != profile->action_entries) {
+ dev_err(rvu->dev,
+ "KPU%d: CAM and action entries [%d != %d] not equal\n",
+ kpu, profile->cam_entries, profile->action_entries);
+ }
+
+ max_entries = rvu_read64(rvu, blkaddr, NPC_AF_CONST1) & 0xFFF;
+
+ /* Program CAM match entries for previous KPU extracted data */
+ num_entries = min_t(int, profile->cam_entries, max_entries);
+ for (entry = 0; entry < num_entries; entry++)
+ npc_config_kpucam(rvu, blkaddr,
+ &profile->cam[entry], kpu, entry);
+
+ /* Program this KPU's actions */
+ num_entries = min_t(int, profile->action_entries, max_entries);
+ for (entry = 0; entry < num_entries; entry++)
+ npc_config_kpuaction(rvu, blkaddr, &profile->action[entry],
+ kpu, entry, false);
+
+ /* Enable all programmed entries */
+ num_entries = min_t(int, profile->action_entries, profile->cam_entries);
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_KPUX_ENTRY_DISX(kpu, 0), enable_mask(num_entries));
+ if (num_entries > 64) {
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_KPUX_ENTRY_DISX(kpu, 1),
+ enable_mask(num_entries - 64));
+ }
+
+ /* Enable this KPU */
+ rvu_write64(rvu, blkaddr, NPC_AF_KPUX_CFG(kpu), 0x01);
+}
+
+static void npc_parser_profile_init(struct rvu *rvu, int blkaddr)
+{
+ struct rvu_hwinfo *hw = rvu->hw;
+ int num_pkinds, num_kpus, idx;
+ struct npc_pkind *pkind;
+
+ /* Get HW limits */
+ hw->npc_kpus = (rvu_read64(rvu, blkaddr, NPC_AF_CONST) >> 8) & 0x1F;
+
+ /* Disable all KPUs and their entries */
+ for (idx = 0; idx < hw->npc_kpus; idx++) {
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_KPUX_ENTRY_DISX(idx, 0), ~0ULL);
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_KPUX_ENTRY_DISX(idx, 1), ~0ULL);
+ rvu_write64(rvu, blkaddr, NPC_AF_KPUX_CFG(idx), 0x00);
+ }
+
+ /* First program IKPU profile i.e PKIND configs.
+ * Check HW max count to avoid configuring junk or
+ * writing to unsupported CSR addresses.
+ */
+ pkind = &hw->pkind;
+ num_pkinds = ARRAY_SIZE(ikpu_action_entries);
+ num_pkinds = min_t(int, pkind->rsrc.max, num_pkinds);
+
+ for (idx = 0; idx < num_pkinds; idx++)
+ npc_config_kpuaction(rvu, blkaddr,
+ &ikpu_action_entries[idx], 0, idx, true);
+
+ /* Program KPU CAM and Action profiles */
+ num_kpus = ARRAY_SIZE(npc_kpu_profiles);
+ num_kpus = min_t(int, hw->npc_kpus, num_kpus);
+
+ for (idx = 0; idx < num_kpus; idx++)
+ npc_program_kpu_profile(rvu, blkaddr,
+ idx, &npc_kpu_profiles[idx]);
+}
+
+static int npc_mcam_rsrcs_init(struct rvu *rvu, int blkaddr)
+{
+ int nixlf_count = rvu_get_nixlf_count(rvu);
+ struct npc_mcam *mcam = &rvu->hw->mcam;
+ int rsvd;
+ u64 cfg;
+
+ /* Get HW limits */
+ cfg = rvu_read64(rvu, blkaddr, NPC_AF_CONST);
+ mcam->banks = (cfg >> 44) & 0xF;
+ mcam->banksize = (cfg >> 28) & 0xFFFF;
+
+ /* Actual number of MCAM entries vary by entry size */
+ cfg = (rvu_read64(rvu, blkaddr,
+ NPC_AF_INTFX_KEX_CFG(0)) >> 32) & 0x07;
+ mcam->total_entries = (mcam->banks / BIT_ULL(cfg)) * mcam->banksize;
+ mcam->keysize = cfg;
+
+ /* Number of banks combined per MCAM entry */
+ if (cfg == NPC_MCAM_KEY_X4)
+ mcam->banks_per_entry = 4;
+ else if (cfg == NPC_MCAM_KEY_X2)
+ mcam->banks_per_entry = 2;
+ else
+ mcam->banks_per_entry = 1;
+
+ /* Reserve one MCAM entry for each of the NIX LF to
+ * guarantee space to install default matching DMAC rule.
+ * Also reserve 2 MCAM entries for each PF for default
+ * channel based matching or 'bcast & promisc' matching to
+ * support BCAST and PROMISC modes of operation for PFs.
+ * PF0 is excluded.
+ */
+ rsvd = (nixlf_count * RSVD_MCAM_ENTRIES_PER_NIXLF) +
+ ((rvu->hw->total_pfs - 1) * RSVD_MCAM_ENTRIES_PER_PF);
+ if (mcam->total_entries <= rsvd) {
+ dev_warn(rvu->dev,
+ "Insufficient NPC MCAM size %d for pkt I/O, exiting\n",
+ mcam->total_entries);
+ return -ENOMEM;
+ }
+
+ mcam->entries = mcam->total_entries - rsvd;
+ mcam->nixlf_offset = mcam->entries;
+ mcam->pf_offset = mcam->nixlf_offset + nixlf_count;
+
+ spin_lock_init(&mcam->lock);
+
+ return 0;
+}
+
+int rvu_npc_init(struct rvu *rvu)
+{
+ struct npc_pkind *pkind = &rvu->hw->pkind;
+ u64 keyz = NPC_MCAM_KEY_X2;
+ int blkaddr, err;
+
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
+ if (blkaddr < 0) {
+ dev_err(rvu->dev, "%s: NPC block not implemented\n", __func__);
+ return -ENODEV;
+ }
+
+ /* Allocate resource bimap for pkind*/
+ pkind->rsrc.max = (rvu_read64(rvu, blkaddr,
+ NPC_AF_CONST1) >> 12) & 0xFF;
+ err = rvu_alloc_bitmap(&pkind->rsrc);
+ if (err)
+ return err;
+
+ /* Allocate mem for pkind to PF and channel mapping info */
+ pkind->pfchan_map = devm_kcalloc(rvu->dev, pkind->rsrc.max,
+ sizeof(u32), GFP_KERNEL);
+ if (!pkind->pfchan_map)
+ return -ENOMEM;
+
+ /* Configure KPU profile */
+ npc_parser_profile_init(rvu, blkaddr);
+
+ /* Config Outer L2, IPv4's NPC layer info */
+ rvu_write64(rvu, blkaddr, NPC_AF_PCK_DEF_OL2,
+ (NPC_LID_LA << 8) | (NPC_LT_LA_ETHER << 4) | 0x0F);
+ rvu_write64(rvu, blkaddr, NPC_AF_PCK_DEF_OIP4,
+ (NPC_LID_LC << 8) | (NPC_LT_LC_IP << 4) | 0x0F);
+
+ /* Enable below for Rx pkts.
+ * - Outer IPv4 header checksum validation.
+ * - Detect outer L2 broadcast address and set NPC_RESULT_S[L2M].
+ */
+ rvu_write64(rvu, blkaddr, NPC_AF_PCK_CFG,
+ rvu_read64(rvu, blkaddr, NPC_AF_PCK_CFG) |
+ BIT_ULL(6) | BIT_ULL(2));
+
+ /* Set RX and TX side MCAM search key size.
+ * Also enable parse key extract nibbles suchthat except
+ * layer E to H, rest of the key is included for MCAM search.
+ */
+ rvu_write64(rvu, blkaddr, NPC_AF_INTFX_KEX_CFG(NIX_INTF_RX),
+ ((keyz & 0x3) << 32) | ((1ULL << 20) - 1));
+ rvu_write64(rvu, blkaddr, NPC_AF_INTFX_KEX_CFG(NIX_INTF_TX),
+ ((keyz & 0x3) << 32) | ((1ULL << 20) - 1));
+
+ err = npc_mcam_rsrcs_init(rvu, blkaddr);
+ if (err)
+ return err;
+
+ /* Config packet data and flags extraction into PARSE result */
+ npc_config_ldata_extract(rvu, blkaddr);
+
+ /* Set TX miss action to UCAST_DEFAULT i.e
+ * transmit the packet on NIX LF SQ's default channel.
+ */
+ rvu_write64(rvu, blkaddr, NPC_AF_INTFX_MISS_ACT(NIX_INTF_TX),
+ NIX_TX_ACTIONOP_UCAST_DEFAULT);
+
+ /* If MCAM lookup doesn't result in a match, drop the received packet */
+ rvu_write64(rvu, blkaddr, NPC_AF_INTFX_MISS_ACT(NIX_INTF_RX),
+ NIX_RX_ACTIONOP_DROP);
+
+ return 0;
+}
+
+void rvu_npc_freemem(struct rvu *rvu)
+{
+ struct npc_pkind *pkind = &rvu->hw->pkind;
+
+ kfree(pkind->rsrc.bmap);
+}
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.c
new file mode 100644
index 000000000000..9d7c135c7965
--- /dev/null
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.c
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Marvell OcteonTx2 RVU Admin Function driver
+ *
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include "rvu_struct.h"
+#include "common.h"
+#include "mbox.h"
+#include "rvu.h"
+
+struct reg_range {
+ u64 start;
+ u64 end;
+};
+
+struct hw_reg_map {
+ u8 regblk;
+ u8 num_ranges;
+ u64 mask;
+#define MAX_REG_RANGES 8
+ struct reg_range range[MAX_REG_RANGES];
+};
+
+static struct hw_reg_map txsch_reg_map[NIX_TXSCH_LVL_CNT] = {
+ {NIX_TXSCH_LVL_SMQ, 2, 0xFFFF, {{0x0700, 0x0708}, {0x1400, 0x14C8} } },
+ {NIX_TXSCH_LVL_TL4, 3, 0xFFFF, {{0x0B00, 0x0B08}, {0x0B10, 0x0B18},
+ {0x1200, 0x12E0} } },
+ {NIX_TXSCH_LVL_TL3, 3, 0xFFFF, {{0x1000, 0x10E0}, {0x1600, 0x1608},
+ {0x1610, 0x1618} } },
+ {NIX_TXSCH_LVL_TL2, 2, 0xFFFF, {{0x0E00, 0x0EE0}, {0x1700, 0x1768} } },
+ {NIX_TXSCH_LVL_TL1, 1, 0xFFFF, {{0x0C00, 0x0D98} } },
+};
+
+bool rvu_check_valid_reg(int regmap, int regblk, u64 reg)
+{
+ int idx;
+ struct hw_reg_map *map;
+
+ /* Only 64bit offsets */
+ if (reg & 0x07)
+ return false;
+
+ if (regmap == TXSCHQ_HWREGMAP) {
+ if (regblk >= NIX_TXSCH_LVL_CNT)
+ return false;
+ map = &txsch_reg_map[regblk];
+ } else {
+ return false;
+ }
+
+ /* Should never happen */
+ if (map->regblk != regblk)
+ return false;
+
+ reg &= map->mask;
+
+ for (idx = 0; idx < map->num_ranges; idx++) {
+ if (reg >= map->range[idx].start &&
+ reg < map->range[idx].end)
+ return true;
+ }
+ return false;
+}
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h
new file mode 100644
index 000000000000..09a8d61f3144
--- /dev/null
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h
@@ -0,0 +1,502 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * Marvell OcteonTx2 RVU Admin Function driver
+ *
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef RVU_REG_H
+#define RVU_REG_H
+
+/* Admin function registers */
+#define RVU_AF_MSIXTR_BASE (0x10)
+#define RVU_AF_ECO (0x20)
+#define RVU_AF_BLK_RST (0x30)
+#define RVU_AF_PF_BAR4_ADDR (0x40)
+#define RVU_AF_RAS (0x100)
+#define RVU_AF_RAS_W1S (0x108)
+#define RVU_AF_RAS_ENA_W1S (0x110)
+#define RVU_AF_RAS_ENA_W1C (0x118)
+#define RVU_AF_GEN_INT (0x120)
+#define RVU_AF_GEN_INT_W1S (0x128)
+#define RVU_AF_GEN_INT_ENA_W1S (0x130)
+#define RVU_AF_GEN_INT_ENA_W1C (0x138)
+#define RVU_AF_AFPF_MBOX0 (0x02000)
+#define RVU_AF_AFPF_MBOX1 (0x02008)
+#define RVU_AF_AFPFX_MBOXX(a, b) (0x2000 | (a) << 4 | (b) << 3)
+#define RVU_AF_PFME_STATUS (0x2800)
+#define RVU_AF_PFTRPEND (0x2810)
+#define RVU_AF_PFTRPEND_W1S (0x2820)
+#define RVU_AF_PF_RST (0x2840)
+#define RVU_AF_HWVF_RST (0x2850)
+#define RVU_AF_PFAF_MBOX_INT (0x2880)
+#define RVU_AF_PFAF_MBOX_INT_W1S (0x2888)
+#define RVU_AF_PFAF_MBOX_INT_ENA_W1S (0x2890)
+#define RVU_AF_PFAF_MBOX_INT_ENA_W1C (0x2898)
+#define RVU_AF_PFFLR_INT (0x28a0)
+#define RVU_AF_PFFLR_INT_W1S (0x28a8)
+#define RVU_AF_PFFLR_INT_ENA_W1S (0x28b0)
+#define RVU_AF_PFFLR_INT_ENA_W1C (0x28b8)
+#define RVU_AF_PFME_INT (0x28c0)
+#define RVU_AF_PFME_INT_W1S (0x28c8)
+#define RVU_AF_PFME_INT_ENA_W1S (0x28d0)
+#define RVU_AF_PFME_INT_ENA_W1C (0x28d8)
+
+/* Admin function's privileged PF/VF registers */
+#define RVU_PRIV_CONST (0x8000000)
+#define RVU_PRIV_GEN_CFG (0x8000010)
+#define RVU_PRIV_CLK_CFG (0x8000020)
+#define RVU_PRIV_ACTIVE_PC (0x8000030)
+#define RVU_PRIV_PFX_CFG(a) (0x8000100 | (a) << 16)
+#define RVU_PRIV_PFX_MSIX_CFG(a) (0x8000110 | (a) << 16)
+#define RVU_PRIV_PFX_ID_CFG(a) (0x8000120 | (a) << 16)
+#define RVU_PRIV_PFX_INT_CFG(a) (0x8000200 | (a) << 16)
+#define RVU_PRIV_PFX_NIX0_CFG (0x8000300)
+#define RVU_PRIV_PFX_NPA_CFG (0x8000310)
+#define RVU_PRIV_PFX_SSO_CFG (0x8000320)
+#define RVU_PRIV_PFX_SSOW_CFG (0x8000330)
+#define RVU_PRIV_PFX_TIM_CFG (0x8000340)
+#define RVU_PRIV_PFX_CPT0_CFG (0x8000350)
+#define RVU_PRIV_BLOCK_TYPEX_REV(a) (0x8000400 | (a) << 3)
+#define RVU_PRIV_HWVFX_INT_CFG(a) (0x8001280 | (a) << 16)
+#define RVU_PRIV_HWVFX_NIX0_CFG (0x8001300)
+#define RVU_PRIV_HWVFX_NPA_CFG (0x8001310)
+#define RVU_PRIV_HWVFX_SSO_CFG (0x8001320)
+#define RVU_PRIV_HWVFX_SSOW_CFG (0x8001330)
+#define RVU_PRIV_HWVFX_TIM_CFG (0x8001340)
+#define RVU_PRIV_HWVFX_CPT0_CFG (0x8001350)
+
+/* RVU PF registers */
+#define RVU_PF_VFX_PFVF_MBOX0 (0x00000)
+#define RVU_PF_VFX_PFVF_MBOX1 (0x00008)
+#define RVU_PF_VFX_PFVF_MBOXX(a, b) (0x0 | (a) << 12 | (b) << 3)
+#define RVU_PF_VF_BAR4_ADDR (0x10)
+#define RVU_PF_BLOCK_ADDRX_DISC(a) (0x200 | (a) << 3)
+#define RVU_PF_VFME_STATUSX(a) (0x800 | (a) << 3)
+#define RVU_PF_VFTRPENDX(a) (0x820 | (a) << 3)
+#define RVU_PF_VFTRPEND_W1SX(a) (0x840 | (a) << 3)
+#define RVU_PF_VFPF_MBOX_INTX(a) (0x880 | (a) << 3)
+#define RVU_PF_VFPF_MBOX_INT_W1SX(a) (0x8A0 | (a) << 3)
+#define RVU_PF_VFPF_MBOX_INT_ENA_W1SX(a) (0x8C0 | (a) << 3)
+#define RVU_PF_VFPF_MBOX_INT_ENA_W1CX(a) (0x8E0 | (a) << 3)
+#define RVU_PF_VFFLR_INTX(a) (0x900 | (a) << 3)
+#define RVU_PF_VFFLR_INT_W1SX(a) (0x920 | (a) << 3)
+#define RVU_PF_VFFLR_INT_ENA_W1SX(a) (0x940 | (a) << 3)
+#define RVU_PF_VFFLR_INT_ENA_W1CX(a) (0x960 | (a) << 3)
+#define RVU_PF_VFME_INTX(a) (0x980 | (a) << 3)
+#define RVU_PF_VFME_INT_W1SX(a) (0x9A0 | (a) << 3)
+#define RVU_PF_VFME_INT_ENA_W1SX(a) (0x9C0 | (a) << 3)
+#define RVU_PF_VFME_INT_ENA_W1CX(a) (0x9E0 | (a) << 3)
+#define RVU_PF_PFAF_MBOX0 (0xC00)
+#define RVU_PF_PFAF_MBOX1 (0xC08)
+#define RVU_PF_PFAF_MBOXX(a) (0xC00 | (a) << 3)
+#define RVU_PF_INT (0xc20)
+#define RVU_PF_INT_W1S (0xc28)
+#define RVU_PF_INT_ENA_W1S (0xc30)
+#define RVU_PF_INT_ENA_W1C (0xc38)
+#define RVU_PF_MSIX_VECX_ADDR(a) (0x000 | (a) << 4)
+#define RVU_PF_MSIX_VECX_CTL(a) (0x008 | (a) << 4)
+#define RVU_PF_MSIX_PBAX(a) (0xF0000 | (a) << 3)
+
+/* RVU VF registers */
+#define RVU_VF_VFPF_MBOX0 (0x00000)
+#define RVU_VF_VFPF_MBOX1 (0x00008)
+
+/* NPA block's admin function registers */
+#define NPA_AF_BLK_RST (0x0000)
+#define NPA_AF_CONST (0x0010)
+#define NPA_AF_CONST1 (0x0018)
+#define NPA_AF_LF_RST (0x0020)
+#define NPA_AF_GEN_CFG (0x0030)
+#define NPA_AF_NDC_CFG (0x0040)
+#define NPA_AF_INP_CTL (0x00D0)
+#define NPA_AF_ACTIVE_CYCLES_PC (0x00F0)
+#define NPA_AF_AVG_DELAY (0x0100)
+#define NPA_AF_GEN_INT (0x0140)
+#define NPA_AF_GEN_INT_W1S (0x0148)
+#define NPA_AF_GEN_INT_ENA_W1S (0x0150)
+#define NPA_AF_GEN_INT_ENA_W1C (0x0158)
+#define NPA_AF_RVU_INT (0x0160)
+#define NPA_AF_RVU_INT_W1S (0x0168)
+#define NPA_AF_RVU_INT_ENA_W1S (0x0170)
+#define NPA_AF_RVU_INT_ENA_W1C (0x0178)
+#define NPA_AF_ERR_INT (0x0180)
+#define NPA_AF_ERR_INT_W1S (0x0188)
+#define NPA_AF_ERR_INT_ENA_W1S (0x0190)
+#define NPA_AF_ERR_INT_ENA_W1C (0x0198)
+#define NPA_AF_RAS (0x01A0)
+#define NPA_AF_RAS_W1S (0x01A8)
+#define NPA_AF_RAS_ENA_W1S (0x01B0)
+#define NPA_AF_RAS_ENA_W1C (0x01B8)
+#define NPA_AF_BP_TEST (0x0200)
+#define NPA_AF_ECO (0x0300)
+#define NPA_AF_AQ_CFG (0x0600)
+#define NPA_AF_AQ_BASE (0x0610)
+#define NPA_AF_AQ_STATUS (0x0620)
+#define NPA_AF_AQ_DOOR (0x0630)
+#define NPA_AF_AQ_DONE_WAIT (0x0640)
+#define NPA_AF_AQ_DONE (0x0650)
+#define NPA_AF_AQ_DONE_ACK (0x0660)
+#define NPA_AF_AQ_DONE_INT (0x0680)
+#define NPA_AF_AQ_DONE_INT_W1S (0x0688)
+#define NPA_AF_AQ_DONE_ENA_W1S (0x0690)
+#define NPA_AF_AQ_DONE_ENA_W1C (0x0698)
+#define NPA_AF_LFX_AURAS_CFG(a) (0x4000 | (a) << 18)
+#define NPA_AF_LFX_LOC_AURAS_BASE(a) (0x4010 | (a) << 18)
+#define NPA_AF_LFX_QINTS_CFG(a) (0x4100 | (a) << 18)
+#define NPA_AF_LFX_QINTS_BASE(a) (0x4110 | (a) << 18)
+#define NPA_PRIV_AF_INT_CFG (0x10000)
+#define NPA_PRIV_LFX_CFG (0x10010)
+#define NPA_PRIV_LFX_INT_CFG (0x10020)
+#define NPA_AF_RVU_LF_CFG_DEBUG (0x10030)
+
+/* NIX block's admin function registers */
+#define NIX_AF_CFG (0x0000)
+#define NIX_AF_STATUS (0x0010)
+#define NIX_AF_NDC_CFG (0x0018)
+#define NIX_AF_CONST (0x0020)
+#define NIX_AF_CONST1 (0x0028)
+#define NIX_AF_CONST2 (0x0030)
+#define NIX_AF_CONST3 (0x0038)
+#define NIX_AF_SQ_CONST (0x0040)
+#define NIX_AF_CQ_CONST (0x0048)
+#define NIX_AF_RQ_CONST (0x0050)
+#define NIX_AF_PSE_CONST (0x0060)
+#define NIX_AF_TL1_CONST (0x0070)
+#define NIX_AF_TL2_CONST (0x0078)
+#define NIX_AF_TL3_CONST (0x0080)
+#define NIX_AF_TL4_CONST (0x0088)
+#define NIX_AF_MDQ_CONST (0x0090)
+#define NIX_AF_MC_MIRROR_CONST (0x0098)
+#define NIX_AF_LSO_CFG (0x00A8)
+#define NIX_AF_BLK_RST (0x00B0)
+#define NIX_AF_TX_TSTMP_CFG (0x00C0)
+#define NIX_AF_RX_CFG (0x00D0)
+#define NIX_AF_AVG_DELAY (0x00E0)
+#define NIX_AF_CINT_DELAY (0x00F0)
+#define NIX_AF_RX_MCAST_BASE (0x0100)
+#define NIX_AF_RX_MCAST_CFG (0x0110)
+#define NIX_AF_RX_MCAST_BUF_BASE (0x0120)
+#define NIX_AF_RX_MCAST_BUF_CFG (0x0130)
+#define NIX_AF_RX_MIRROR_BUF_BASE (0x0140)
+#define NIX_AF_RX_MIRROR_BUF_CFG (0x0148)
+#define NIX_AF_LF_RST (0x0150)
+#define NIX_AF_GEN_INT (0x0160)
+#define NIX_AF_GEN_INT_W1S (0x0168)
+#define NIX_AF_GEN_INT_ENA_W1S (0x0170)
+#define NIX_AF_GEN_INT_ENA_W1C (0x0178)
+#define NIX_AF_ERR_INT (0x0180)
+#define NIX_AF_ERR_INT_W1S (0x0188)
+#define NIX_AF_ERR_INT_ENA_W1S (0x0190)
+#define NIX_AF_ERR_INT_ENA_W1C (0x0198)
+#define NIX_AF_RAS (0x01A0)
+#define NIX_AF_RAS_W1S (0x01A8)
+#define NIX_AF_RAS_ENA_W1S (0x01B0)
+#define NIX_AF_RAS_ENA_W1C (0x01B8)
+#define NIX_AF_RVU_INT (0x01C0)
+#define NIX_AF_RVU_INT_W1S (0x01C8)
+#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_OL2 (0x0200)
+#define NIX_AF_RX_DEF_OIP4 (0x0210)
+#define NIX_AF_RX_DEF_IIP4 (0x0220)
+#define NIX_AF_RX_DEF_OIP6 (0x0230)
+#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_ISCTP (0x02A0)
+#define NIX_AF_RX_DEF_IPSECX (0x02B0)
+#define NIX_AF_RX_IPSEC_GEN_CFG (0x0300)
+#define NIX_AF_RX_CPTX_INST_ADDR (0x0310)
+#define NIX_AF_NDC_TX_SYNC (0x03F0)
+#define NIX_AF_AQ_CFG (0x0400)
+#define NIX_AF_AQ_BASE (0x0410)
+#define NIX_AF_AQ_STATUS (0x0420)
+#define NIX_AF_AQ_DOOR (0x0430)
+#define NIX_AF_AQ_DONE_WAIT (0x0440)
+#define NIX_AF_AQ_DONE (0x0450)
+#define NIX_AF_AQ_DONE_ACK (0x0460)
+#define NIX_AF_AQ_DONE_TIMER (0x0470)
+#define NIX_AF_AQ_DONE_INT (0x0480)
+#define NIX_AF_AQ_DONE_INT_W1S (0x0488)
+#define NIX_AF_AQ_DONE_ENA_W1S (0x0490)
+#define NIX_AF_AQ_DONE_ENA_W1C (0x0498)
+#define NIX_AF_RX_LINKX_SLX_SPKT_CNT (0x0500)
+#define NIX_AF_RX_LINKX_SLX_SXQE_CNT (0x0510)
+#define NIX_AF_RX_MCAST_JOBSX_SW_CNT (0x0520)
+#define NIX_AF_RX_MIRROR_JOBSX_SW_CNT (0x0530)
+#define NIX_AF_RX_LINKX_CFG(a) (0x0540 | (a) << 16)
+#define NIX_AF_RX_SW_SYNC (0x0550)
+#define NIX_AF_RX_SW_SYNC_DONE (0x0560)
+#define NIX_AF_SEB_ECO (0x0600)
+#define NIX_AF_SEB_TEST_BP (0x0610)
+#define NIX_AF_NORM_TX_FIFO_STATUS (0x0620)
+#define NIX_AF_EXPR_TX_FIFO_STATUS (0x0630)
+#define NIX_AF_SDP_TX_FIFO_STATUS (0x0640)
+#define NIX_AF_TX_NPC_CAPTURE_CONFIG (0x0660)
+#define NIX_AF_TX_NPC_CAPTURE_INFO (0x0670)
+
+#define NIX_AF_DEBUG_NPC_RESP_DATAX(a) (0x680 | (a) << 3)
+#define NIX_AF_SMQX_CFG(a) (0x700 | (a) << 16)
+#define NIX_AF_PSE_CHANNEL_LEVEL (0x800)
+#define NIX_AF_PSE_SHAPER_CFG (0x810)
+#define NIX_AF_TX_EXPR_CREDIT (0x830)
+#define NIX_AF_MARK_FORMATX_CTL(a) (0x900 | (a) << 18)
+#define NIX_AF_TX_LINKX_NORM_CREDIT(a) (0xA00 | (a) << 16)
+#define NIX_AF_TX_LINKX_EXPR_CREDIT(a) (0xA10 | (a) << 16)
+#define NIX_AF_TX_LINKX_SW_XOFF(a) (0xA20 | (a) << 16)
+#define NIX_AF_TX_LINKX_HW_XOFF(a) (0xA30 | (a) << 16)
+#define NIX_AF_SDP_LINK_CREDIT (0xa40)
+#define NIX_AF_SDP_SW_XOFFX(a) (0xA60 | (a) << 3)
+#define NIX_AF_SDP_HW_XOFFX(a) (0xAC0 | (a) << 3)
+#define NIX_AF_TL4X_BP_STATUS(a) (0xB00 | (a) << 16)
+#define NIX_AF_TL4X_SDP_LINK_CFG(a) (0xB10 | (a) << 16)
+#define NIX_AF_TL1X_SCHEDULE(a) (0xC00 | (a) << 16)
+#define NIX_AF_TL1X_SHAPE(a) (0xC10 | (a) << 16)
+#define NIX_AF_TL1X_CIR(a) (0xC20 | (a) << 16)
+#define NIX_AF_TL1X_SHAPE_STATE(a) (0xC50 | (a) << 16)
+#define NIX_AF_TL1X_SW_XOFF(a) (0xC70 | (a) << 16)
+#define NIX_AF_TL1X_TOPOLOGY(a) (0xC80 | (a) << 16)
+#define NIX_AF_TL1X_GREEN(a) (0xC90 | (a) << 16)
+#define NIX_AF_TL1X_YELLOW(a) (0xCA0 | (a) << 16)
+#define NIX_AF_TL1X_RED(a) (0xCB0 | (a) << 16)
+#define NIX_AF_TL1X_MD_DEBUG0(a) (0xCC0 | (a) << 16)
+#define NIX_AF_TL1X_MD_DEBUG1(a) (0xCC8 | (a) << 16)
+#define NIX_AF_TL1X_MD_DEBUG2(a) (0xCD0 | (a) << 16)
+#define NIX_AF_TL1X_MD_DEBUG3(a) (0xCD8 | (a) << 16)
+#define NIX_AF_TL1A_DEBUG (0xce0)
+#define NIX_AF_TL1B_DEBUG (0xcf0)
+#define NIX_AF_TL1_DEBUG_GREEN (0xd00)
+#define NIX_AF_TL1_DEBUG_NODE (0xd10)
+#define NIX_AF_TL1X_DROPPED_PACKETS(a) (0xD20 | (a) << 16)
+#define NIX_AF_TL1X_DROPPED_BYTES(a) (0xD30 | (a) << 16)
+#define NIX_AF_TL1X_RED_PACKETS(a) (0xD40 | (a) << 16)
+#define NIX_AF_TL1X_RED_BYTES(a) (0xD50 | (a) << 16)
+#define NIX_AF_TL1X_YELLOW_PACKETS(a) (0xD60 | (a) << 16)
+#define NIX_AF_TL1X_YELLOW_BYTES(a) (0xD70 | (a) << 16)
+#define NIX_AF_TL1X_GREEN_PACKETS(a) (0xD80 | (a) << 16)
+#define NIX_AF_TL1X_GREEN_BYTES(a) (0xD90 | (a) << 16)
+#define NIX_AF_TL2X_SCHEDULE(a) (0xE00 | (a) << 16)
+#define NIX_AF_TL2X_SHAPE(a) (0xE10 | (a) << 16)
+#define NIX_AF_TL2X_CIR(a) (0xE20 | (a) << 16)
+#define NIX_AF_TL2X_PIR(a) (0xE30 | (a) << 16)
+#define NIX_AF_TL2X_SCHED_STATE(a) (0xE40 | (a) << 16)
+#define NIX_AF_TL2X_SHAPE_STATE(a) (0xE50 | (a) << 16)
+#define NIX_AF_TL2X_POINTERS(a) (0xE60 | (a) << 16)
+#define NIX_AF_TL2X_SW_XOFF(a) (0xE70 | (a) << 16)
+#define NIX_AF_TL2X_TOPOLOGY(a) (0xE80 | (a) << 16)
+#define NIX_AF_TL2X_PARENT(a) (0xE88 | (a) << 16)
+#define NIX_AF_TL2X_GREEN(a) (0xE90 | (a) << 16)
+#define NIX_AF_TL2X_YELLOW(a) (0xEA0 | (a) << 16)
+#define NIX_AF_TL2X_RED(a) (0xEB0 | (a) << 16)
+#define NIX_AF_TL2X_MD_DEBUG0(a) (0xEC0 | (a) << 16)
+#define NIX_AF_TL2X_MD_DEBUG1(a) (0xEC8 | (a) << 16)
+#define NIX_AF_TL2X_MD_DEBUG2(a) (0xED0 | (a) << 16)
+#define NIX_AF_TL2X_MD_DEBUG3(a) (0xED8 | (a) << 16)
+#define NIX_AF_TL2A_DEBUG (0xee0)
+#define NIX_AF_TL2B_DEBUG (0xef0)
+#define NIX_AF_TL3X_SCHEDULE(a) (0x1000 | (a) << 16)
+#define NIX_AF_TL3X_SHAPE(a) (0x1010 | (a) << 16)
+#define NIX_AF_TL3X_CIR(a) (0x1020 | (a) << 16)
+#define NIX_AF_TL3X_PIR(a) (0x1030 | (a) << 16)
+#define NIX_AF_TL3X_SCHED_STATE(a) (0x1040 | (a) << 16)
+#define NIX_AF_TL3X_SHAPE_STATE(a) (0x1050 | (a) << 16)
+#define NIX_AF_TL3X_POINTERS(a) (0x1060 | (a) << 16)
+#define NIX_AF_TL3X_SW_XOFF(a) (0x1070 | (a) << 16)
+#define NIX_AF_TL3X_TOPOLOGY(a) (0x1080 | (a) << 16)
+#define NIX_AF_TL3X_PARENT(a) (0x1088 | (a) << 16)
+#define NIX_AF_TL3X_GREEN(a) (0x1090 | (a) << 16)
+#define NIX_AF_TL3X_YELLOW(a) (0x10A0 | (a) << 16)
+#define NIX_AF_TL3X_RED(a) (0x10B0 | (a) << 16)
+#define NIX_AF_TL3X_MD_DEBUG0(a) (0x10C0 | (a) << 16)
+#define NIX_AF_TL3X_MD_DEBUG1(a) (0x10C8 | (a) << 16)
+#define NIX_AF_TL3X_MD_DEBUG2(a) (0x10D0 | (a) << 16)
+#define NIX_AF_TL3X_MD_DEBUG3(a) (0x10D8 | (a) << 16)
+#define NIX_AF_TL3A_DEBUG (0x10e0)
+#define NIX_AF_TL3B_DEBUG (0x10f0)
+#define NIX_AF_TL4X_SCHEDULE(a) (0x1200 | (a) << 16)
+#define NIX_AF_TL4X_SHAPE(a) (0x1210 | (a) << 16)
+#define NIX_AF_TL4X_CIR(a) (0x1220 | (a) << 16)
+#define NIX_AF_TL4X_PIR(a) (0x1230 | (a) << 16)
+#define NIX_AF_TL4X_SCHED_STATE(a) (0x1240 | (a) << 16)
+#define NIX_AF_TL4X_SHAPE_STATE(a) (0x1250 | (a) << 16)
+#define NIX_AF_TL4X_POINTERS(a) (0x1260 | (a) << 16)
+#define NIX_AF_TL4X_SW_XOFF(a) (0x1270 | (a) << 16)
+#define NIX_AF_TL4X_TOPOLOGY(a) (0x1280 | (a) << 16)
+#define NIX_AF_TL4X_PARENT(a) (0x1288 | (a) << 16)
+#define NIX_AF_TL4X_GREEN(a) (0x1290 | (a) << 16)
+#define NIX_AF_TL4X_YELLOW(a) (0x12A0 | (a) << 16)
+#define NIX_AF_TL4X_RED(a) (0x12B0 | (a) << 16)
+#define NIX_AF_TL4X_MD_DEBUG0(a) (0x12C0 | (a) << 16)
+#define NIX_AF_TL4X_MD_DEBUG1(a) (0x12C8 | (a) << 16)
+#define NIX_AF_TL4X_MD_DEBUG2(a) (0x12D0 | (a) << 16)
+#define NIX_AF_TL4X_MD_DEBUG3(a) (0x12D8 | (a) << 16)
+#define NIX_AF_TL4A_DEBUG (0x12e0)
+#define NIX_AF_TL4B_DEBUG (0x12f0)
+#define NIX_AF_MDQX_SCHEDULE(a) (0x1400 | (a) << 16)
+#define NIX_AF_MDQX_SHAPE(a) (0x1410 | (a) << 16)
+#define NIX_AF_MDQX_CIR(a) (0x1420 | (a) << 16)
+#define NIX_AF_MDQX_PIR(a) (0x1430 | (a) << 16)
+#define NIX_AF_MDQX_SCHED_STATE(a) (0x1440 | (a) << 16)
+#define NIX_AF_MDQX_SHAPE_STATE(a) (0x1450 | (a) << 16)
+#define NIX_AF_MDQX_POINTERS(a) (0x1460 | (a) << 16)
+#define NIX_AF_MDQX_SW_XOFF(a) (0x1470 | (a) << 16)
+#define NIX_AF_MDQX_PARENT(a) (0x1480 | (a) << 16)
+#define NIX_AF_MDQX_MD_DEBUG(a) (0x14C0 | (a) << 16)
+#define NIX_AF_MDQX_PTR_FIFO(a) (0x14D0 | (a) << 16)
+#define NIX_AF_MDQA_DEBUG (0x14e0)
+#define NIX_AF_MDQB_DEBUG (0x14f0)
+#define NIX_AF_TL3_TL2X_CFG(a) (0x1600 | (a) << 18)
+#define NIX_AF_TL3_TL2X_BP_STATUS(a) (0x1610 | (a) << 16)
+#define NIX_AF_TL3_TL2X_LINKX_CFG(a, b) (0x1700 | (a) << 16 | (b) << 3)
+#define NIX_AF_RX_FLOW_KEY_ALGX_FIELDX(a, b) (0x1800 | (a) << 18 | (b) << 3)
+#define NIX_AF_TX_MCASTX(a) (0x1900 | (a) << 15)
+#define NIX_AF_TX_VTAG_DEFX_CTL(a) (0x1A00 | (a) << 16)
+#define NIX_AF_TX_VTAG_DEFX_DATA(a) (0x1A10 | (a) << 16)
+#define NIX_AF_RX_BPIDX_STATUS(a) (0x1A20 | (a) << 17)
+#define NIX_AF_RX_CHANX_CFG(a) (0x1A30 | (a) << 15)
+#define NIX_AF_CINT_TIMERX(a) (0x1A40 | (a) << 18)
+#define NIX_AF_LSO_FORMATX_FIELDX(a, b) (0x1B00 | (a) << 16 | (b) << 3)
+#define NIX_AF_LFX_CFG(a) (0x4000 | (a) << 17)
+#define NIX_AF_LFX_SQS_CFG(a) (0x4020 | (a) << 17)
+#define NIX_AF_LFX_TX_CFG2(a) (0x4028 | (a) << 17)
+#define NIX_AF_LFX_SQS_BASE(a) (0x4030 | (a) << 17)
+#define NIX_AF_LFX_RQS_CFG(a) (0x4040 | (a) << 17)
+#define NIX_AF_LFX_RQS_BASE(a) (0x4050 | (a) << 17)
+#define NIX_AF_LFX_CQS_CFG(a) (0x4060 | (a) << 17)
+#define NIX_AF_LFX_CQS_BASE(a) (0x4070 | (a) << 17)
+#define NIX_AF_LFX_TX_CFG(a) (0x4080 | (a) << 17)
+#define NIX_AF_LFX_TX_PARSE_CFG(a) (0x4090 | (a) << 17)
+#define NIX_AF_LFX_RX_CFG(a) (0x40A0 | (a) << 17)
+#define NIX_AF_LFX_RSS_CFG(a) (0x40C0 | (a) << 17)
+#define NIX_AF_LFX_RSS_BASE(a) (0x40D0 | (a) << 17)
+#define NIX_AF_LFX_QINTS_CFG(a) (0x4100 | (a) << 17)
+#define NIX_AF_LFX_QINTS_BASE(a) (0x4110 | (a) << 17)
+#define NIX_AF_LFX_CINTS_CFG(a) (0x4120 | (a) << 17)
+#define NIX_AF_LFX_CINTS_BASE(a) (0x4130 | (a) << 17)
+#define NIX_AF_LFX_RX_IPSEC_CFG0(a) (0x4140 | (a) << 17)
+#define NIX_AF_LFX_RX_IPSEC_CFG1(a) (0x4148 | (a) << 17)
+#define NIX_AF_LFX_RX_IPSEC_DYNO_CFG(a) (0x4150 | (a) << 17)
+#define NIX_AF_LFX_RX_IPSEC_DYNO_BASE(a) (0x4158 | (a) << 17)
+#define NIX_AF_LFX_RX_IPSEC_SA_BASE(a) (0x4170 | (a) << 17)
+#define NIX_AF_LFX_TX_STATUS(a) (0x4180 | (a) << 17)
+#define NIX_AF_LFX_RX_VTAG_TYPEX(a, b) (0x4200 | (a) << 17 | (b) << 3)
+#define NIX_AF_LFX_LOCKX(a, b) (0x4300 | (a) << 17 | (b) << 3)
+#define NIX_AF_LFX_TX_STATX(a, b) (0x4400 | (a) << 17 | (b) << 3)
+#define NIX_AF_LFX_RX_STATX(a, b) (0x4500 | (a) << 17 | (b) << 3)
+#define NIX_AF_LFX_RSS_GRPX(a, b) (0x4600 | (a) << 17 | (b) << 3)
+#define NIX_AF_RX_NPC_MC_RCV (0x4700)
+#define NIX_AF_RX_NPC_MC_DROP (0x4710)
+#define NIX_AF_RX_NPC_MIRROR_RCV (0x4720)
+#define NIX_AF_RX_NPC_MIRROR_DROP (0x4730)
+#define NIX_AF_RX_ACTIVE_CYCLES_PCX(a) (0x4800 | (a) << 16)
+
+#define NIX_PRIV_AF_INT_CFG (0x8000000)
+#define NIX_PRIV_LFX_CFG (0x8000010)
+#define NIX_PRIV_LFX_INT_CFG (0x8000020)
+#define NIX_AF_RVU_LF_CFG_DEBUG (0x8000030)
+
+/* SSO */
+#define SSO_AF_CONST (0x1000)
+#define SSO_AF_CONST1 (0x1008)
+#define SSO_AF_BLK_RST (0x10f8)
+#define SSO_AF_LF_HWGRP_RST (0x10e0)
+#define SSO_AF_RVU_LF_CFG_DEBUG (0x3800)
+#define SSO_PRIV_LFX_HWGRP_CFG (0x10000)
+#define SSO_PRIV_LFX_HWGRP_INT_CFG (0x20000)
+
+/* SSOW */
+#define SSOW_AF_RVU_LF_HWS_CFG_DEBUG (0x0010)
+#define SSOW_AF_LF_HWS_RST (0x0030)
+#define SSOW_PRIV_LFX_HWS_CFG (0x1000)
+#define SSOW_PRIV_LFX_HWS_INT_CFG (0x2000)
+
+/* TIM */
+#define TIM_AF_CONST (0x90)
+#define TIM_PRIV_LFX_CFG (0x20000)
+#define TIM_PRIV_LFX_INT_CFG (0x24000)
+#define TIM_AF_RVU_LF_CFG_DEBUG (0x30000)
+#define TIM_AF_BLK_RST (0x10)
+#define TIM_AF_LF_RST (0x20)
+
+/* CPT */
+#define CPT_AF_CONSTANTS0 (0x0000)
+#define CPT_PRIV_LFX_CFG (0x41000)
+#define CPT_PRIV_LFX_INT_CFG (0x43000)
+#define CPT_AF_RVU_LF_CFG_DEBUG (0x45000)
+#define CPT_AF_LF_RST (0x44000)
+#define CPT_AF_BLK_RST (0x46000)
+
+#define NDC_AF_BLK_RST (0x002F0)
+#define NPC_AF_BLK_RST (0x00040)
+
+/* NPC */
+#define NPC_AF_CFG (0x00000)
+#define NPC_AF_ACTIVE_PC (0x00010)
+#define NPC_AF_CONST (0x00020)
+#define NPC_AF_CONST1 (0x00030)
+#define NPC_AF_BLK_RST (0x00040)
+#define NPC_AF_MCAM_SCRUB_CTL (0x000a0)
+#define NPC_AF_KCAM_SCRUB_CTL (0x000b0)
+#define NPC_AF_KPUX_CFG(a) (0x00500 | (a) << 3)
+#define NPC_AF_PCK_CFG (0x00600)
+#define NPC_AF_PCK_DEF_OL2 (0x00610)
+#define NPC_AF_PCK_DEF_OIP4 (0x00620)
+#define NPC_AF_PCK_DEF_OIP6 (0x00630)
+#define NPC_AF_PCK_DEF_IIP4 (0x00640)
+#define NPC_AF_KEX_LDATAX_FLAGS_CFG(a) (0x00800 | (a) << 3)
+#define NPC_AF_INTFX_KEX_CFG(a) (0x01010 | (a) << 8)
+#define NPC_AF_PKINDX_ACTION0(a) (0x80000ull | (a) << 6)
+#define NPC_AF_PKINDX_ACTION1(a) (0x80008ull | (a) << 6)
+#define NPC_AF_PKINDX_CPI_DEFX(a, b) (0x80020ull | (a) << 6 | (b) << 3)
+#define NPC_AF_KPUX_ENTRYX_CAMX(a, b, c) \
+ (0x100000 | (a) << 14 | (b) << 6 | (c) << 3)
+#define NPC_AF_KPUX_ENTRYX_ACTION0(a, b) \
+ (0x100020 | (a) << 14 | (b) << 6)
+#define NPC_AF_KPUX_ENTRYX_ACTION1(a, b) \
+ (0x100028 | (a) << 14 | (b) << 6)
+#define NPC_AF_KPUX_ENTRY_DISX(a, b) (0x180000 | (a) << 6 | (b) << 3)
+#define NPC_AF_CPIX_CFG(a) (0x200000 | (a) << 3)
+#define NPC_AF_INTFX_LIDX_LTX_LDX_CFG(a, b, c, d) \
+ (0x900000 | (a) << 16 | (b) << 12 | (c) << 5 | (d) << 3)
+#define NPC_AF_INTFX_LDATAX_FLAGSX_CFG(a, b, c) \
+ (0x980000 | (a) << 16 | (b) << 12 | (c) << 3)
+#define NPC_AF_MCAMEX_BANKX_CAMX_INTF(a, b, c) \
+ (0x1000000ull | (a) << 10 | (b) << 6 | (c) << 3)
+#define NPC_AF_MCAMEX_BANKX_CAMX_W0(a, b, c) \
+ (0x1000010ull | (a) << 10 | (b) << 6 | (c) << 3)
+#define NPC_AF_MCAMEX_BANKX_CAMX_W1(a, b, c) \
+ (0x1000020ull | (a) << 10 | (b) << 6 | (c) << 3)
+#define NPC_AF_MCAMEX_BANKX_CFG(a, b) (0x1800000ull | (a) << 8 | (b) << 4)
+#define NPC_AF_MCAMEX_BANKX_STAT_ACT(a, b) \
+ (0x1880000 | (a) << 8 | (b) << 4)
+#define NPC_AF_MATCH_STATX(a) (0x1880008 | (a) << 8)
+#define NPC_AF_INTFX_MISS_STAT_ACT(a) (0x1880040 + (a) * 0x8)
+#define NPC_AF_MCAMEX_BANKX_ACTION(a, b) (0x1900000ull | (a) << 8 | (b) << 4)
+#define NPC_AF_MCAMEX_BANKX_TAG_ACT(a, b) \
+ (0x1900008 | (a) << 8 | (b) << 4)
+#define NPC_AF_INTFX_MISS_ACT(a) (0x1a00000 | (a) << 4)
+#define NPC_AF_INTFX_MISS_TAG_ACT(a) (0x1b00008 | (a) << 4)
+#define NPC_AF_MCAM_BANKX_HITX(a, b) (0x1c80000 | (a) << 8 | (b) << 4)
+#define NPC_AF_LKUP_CTL (0x2000000)
+#define NPC_AF_LKUP_DATAX(a) (0x2000200 | (a) << 4)
+#define NPC_AF_LKUP_RESULTX(a) (0x2000400 | (a) << 4)
+#define NPC_AF_INTFX_STAT(a) (0x2000800 | (a) << 4)
+#define NPC_AF_DBG_CTL (0x3000000)
+#define NPC_AF_DBG_STATUS (0x3000010)
+#define NPC_AF_KPUX_DBG(a) (0x3000020 | (a) << 8)
+#define NPC_AF_IKPU_ERR_CTL (0x3000080)
+#define NPC_AF_KPUX_ERR_CTL(a) (0x30000a0 | (a) << 8)
+#define NPC_AF_MCAM_DBG (0x3001000)
+#define NPC_AF_DBG_DATAX(a) (0x3001400 | (a) << 4)
+#define NPC_AF_DBG_RESULTX(a) (0x3001800 | (a) << 4)
+
+#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
new file mode 100644
index 000000000000..f920dac74e6c
--- /dev/null
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h
@@ -0,0 +1,917 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * Marvell OcteonTx2 RVU Admin Function driver
+ *
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef RVU_STRUCT_H
+#define RVU_STRUCT_H
+
+/* RVU Block Address Enumeration */
+enum rvu_block_addr_e {
+ BLKADDR_RVUM = 0x0ULL,
+ BLKADDR_LMT = 0x1ULL,
+ BLKADDR_MSIX = 0x2ULL,
+ BLKADDR_NPA = 0x3ULL,
+ BLKADDR_NIX0 = 0x4ULL,
+ BLKADDR_NIX1 = 0x5ULL,
+ BLKADDR_NPC = 0x6ULL,
+ BLKADDR_SSO = 0x7ULL,
+ BLKADDR_SSOW = 0x8ULL,
+ BLKADDR_TIM = 0x9ULL,
+ BLKADDR_CPT0 = 0xaULL,
+ BLKADDR_CPT1 = 0xbULL,
+ BLKADDR_NDC0 = 0xcULL,
+ BLKADDR_NDC1 = 0xdULL,
+ BLKADDR_NDC2 = 0xeULL,
+ BLK_COUNT = 0xfULL,
+};
+
+/* RVU Block Type Enumeration */
+enum rvu_block_type_e {
+ BLKTYPE_RVUM = 0x0,
+ BLKTYPE_MSIX = 0x1,
+ BLKTYPE_LMT = 0x2,
+ BLKTYPE_NIX = 0x3,
+ BLKTYPE_NPA = 0x4,
+ BLKTYPE_NPC = 0x5,
+ BLKTYPE_SSO = 0x6,
+ BLKTYPE_SSOW = 0x7,
+ BLKTYPE_TIM = 0x8,
+ BLKTYPE_CPT = 0x9,
+ BLKTYPE_NDC = 0xa,
+ BLKTYPE_MAX = 0xa,
+};
+
+/* RVU Admin function Interrupt Vector Enumeration */
+enum rvu_af_int_vec_e {
+ RVU_AF_INT_VEC_POISON = 0x0,
+ RVU_AF_INT_VEC_PFFLR = 0x1,
+ RVU_AF_INT_VEC_PFME = 0x2,
+ RVU_AF_INT_VEC_GEN = 0x3,
+ RVU_AF_INT_VEC_MBOX = 0x4,
+ RVU_AF_INT_VEC_CNT = 0x5,
+};
+
+/**
+ * RVU PF Interrupt Vector Enumeration
+ */
+enum rvu_pf_int_vec_e {
+ RVU_PF_INT_VEC_VFFLR0 = 0x0,
+ RVU_PF_INT_VEC_VFFLR1 = 0x1,
+ RVU_PF_INT_VEC_VFME0 = 0x2,
+ RVU_PF_INT_VEC_VFME1 = 0x3,
+ RVU_PF_INT_VEC_VFPF_MBOX0 = 0x4,
+ RVU_PF_INT_VEC_VFPF_MBOX1 = 0x5,
+ RVU_PF_INT_VEC_AFPF_MBOX = 0x6,
+ RVU_PF_INT_VEC_CNT = 0x7,
+};
+
+/* NPA admin queue completion enumeration */
+enum npa_aq_comp {
+ NPA_AQ_COMP_NOTDONE = 0x0,
+ NPA_AQ_COMP_GOOD = 0x1,
+ NPA_AQ_COMP_SWERR = 0x2,
+ NPA_AQ_COMP_CTX_POISON = 0x3,
+ NPA_AQ_COMP_CTX_FAULT = 0x4,
+ NPA_AQ_COMP_LOCKERR = 0x5,
+};
+
+/* NPA admin queue context types */
+enum npa_aq_ctype {
+ NPA_AQ_CTYPE_AURA = 0x0,
+ NPA_AQ_CTYPE_POOL = 0x1,
+};
+
+/* NPA admin queue instruction opcodes */
+enum npa_aq_instop {
+ NPA_AQ_INSTOP_NOP = 0x0,
+ NPA_AQ_INSTOP_INIT = 0x1,
+ NPA_AQ_INSTOP_WRITE = 0x2,
+ NPA_AQ_INSTOP_READ = 0x3,
+ NPA_AQ_INSTOP_LOCK = 0x4,
+ NPA_AQ_INSTOP_UNLOCK = 0x5,
+};
+
+/* NPA admin queue instruction structure */
+struct npa_aq_inst_s {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ u64 doneint : 1; /* W0 */
+ u64 reserved_44_62 : 19;
+ u64 cindex : 20;
+ u64 reserved_17_23 : 7;
+ u64 lf : 9;
+ u64 ctype : 4;
+ u64 op : 4;
+#else
+ u64 op : 4;
+ u64 ctype : 4;
+ u64 lf : 9;
+ u64 reserved_17_23 : 7;
+ u64 cindex : 20;
+ u64 reserved_44_62 : 19;
+ u64 doneint : 1;
+#endif
+ u64 res_addr; /* W1 */
+};
+
+/* NPA admin queue result structure */
+struct npa_aq_res_s {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ u64 reserved_17_63 : 47; /* W0 */
+ u64 doneint : 1;
+ u64 compcode : 8;
+ u64 ctype : 4;
+ u64 op : 4;
+#else
+ u64 op : 4;
+ u64 ctype : 4;
+ u64 compcode : 8;
+ u64 doneint : 1;
+ u64 reserved_17_63 : 47;
+#endif
+ u64 reserved_64_127; /* W1 */
+};
+
+struct npa_aura_s {
+ u64 pool_addr; /* W0 */
+#if defined(__BIG_ENDIAN_BITFIELD) /* W1 */
+ u64 avg_level : 8;
+ u64 reserved_118_119 : 2;
+ u64 shift : 6;
+ u64 aura_drop : 8;
+ u64 reserved_98_103 : 6;
+ u64 bp_ena : 2;
+ u64 aura_drop_ena : 1;
+ u64 pool_drop_ena : 1;
+ u64 reserved_93 : 1;
+ u64 avg_con : 9;
+ u64 pool_way_mask : 16;
+ u64 pool_caching : 1;
+ u64 reserved_65 : 2;
+ u64 ena : 1;
+#else
+ u64 ena : 1;
+ u64 reserved_65 : 2;
+ u64 pool_caching : 1;
+ u64 pool_way_mask : 16;
+ u64 avg_con : 9;
+ u64 reserved_93 : 1;
+ u64 pool_drop_ena : 1;
+ u64 aura_drop_ena : 1;
+ u64 bp_ena : 2;
+ u64 reserved_98_103 : 6;
+ u64 aura_drop : 8;
+ u64 shift : 6;
+ u64 reserved_118_119 : 2;
+ u64 avg_level : 8;
+#endif
+#if defined(__BIG_ENDIAN_BITFIELD) /* W2 */
+ u64 reserved_189_191 : 3;
+ u64 nix1_bpid : 9;
+ u64 reserved_177_179 : 3;
+ u64 nix0_bpid : 9;
+ u64 reserved_164_167 : 4;
+ u64 count : 36;
+#else
+ u64 count : 36;
+ u64 reserved_164_167 : 4;
+ u64 nix0_bpid : 9;
+ u64 reserved_177_179 : 3;
+ u64 nix1_bpid : 9;
+ u64 reserved_189_191 : 3;
+#endif
+#if defined(__BIG_ENDIAN_BITFIELD) /* W3 */
+ u64 reserved_252_255 : 4;
+ u64 fc_hyst_bits : 4;
+ u64 fc_stype : 2;
+ u64 fc_up_crossing : 1;
+ u64 fc_ena : 1;
+ u64 reserved_240_243 : 4;
+ u64 bp : 8;
+ u64 reserved_228_231 : 4;
+ u64 limit : 36;
+#else
+ u64 limit : 36;
+ u64 reserved_228_231 : 4;
+ u64 bp : 8;
+ u64 reserved_240_243 : 4;
+ u64 fc_ena : 1;
+ u64 fc_up_crossing : 1;
+ u64 fc_stype : 2;
+ u64 fc_hyst_bits : 4;
+ u64 reserved_252_255 : 4;
+#endif
+ u64 fc_addr; /* W4 */
+#if defined(__BIG_ENDIAN_BITFIELD) /* W5 */
+ u64 reserved_379_383 : 5;
+ u64 err_qint_idx : 7;
+ u64 reserved_371 : 1;
+ u64 thresh_qint_idx : 7;
+ u64 reserved_363 : 1;
+ u64 thresh_up : 1;
+ u64 thresh_int_ena : 1;
+ u64 thresh_int : 1;
+ u64 err_int_ena : 8;
+ u64 err_int : 8;
+ u64 update_time : 16;
+ u64 pool_drop : 8;
+#else
+ u64 pool_drop : 8;
+ u64 update_time : 16;
+ u64 err_int : 8;
+ u64 err_int_ena : 8;
+ u64 thresh_int : 1;
+ u64 thresh_int_ena : 1;
+ u64 thresh_up : 1;
+ u64 reserved_363 : 1;
+ u64 thresh_qint_idx : 7;
+ u64 reserved_371 : 1;
+ u64 err_qint_idx : 7;
+ u64 reserved_379_383 : 5;
+#endif
+#if defined(__BIG_ENDIAN_BITFIELD) /* W6 */
+ u64 reserved_420_447 : 28;
+ u64 thresh : 36;
+#else
+ u64 thresh : 36;
+ u64 reserved_420_447 : 28;
+#endif
+ u64 reserved_448_511; /* W7 */
+};
+
+struct npa_pool_s {
+ u64 stack_base; /* W0 */
+#if defined(__BIG_ENDIAN_BITFIELD) /* W1 */
+ u64 reserved_115_127 : 13;
+ u64 buf_size : 11;
+ u64 reserved_100_103 : 4;
+ u64 buf_offset : 12;
+ u64 stack_way_mask : 16;
+ u64 reserved_70_71 : 3;
+ u64 stack_caching : 1;
+ u64 reserved_66_67 : 2;
+ u64 nat_align : 1;
+ u64 ena : 1;
+#else
+ u64 ena : 1;
+ u64 nat_align : 1;
+ u64 reserved_66_67 : 2;
+ u64 stack_caching : 1;
+ u64 reserved_70_71 : 3;
+ u64 stack_way_mask : 16;
+ u64 buf_offset : 12;
+ u64 reserved_100_103 : 4;
+ u64 buf_size : 11;
+ u64 reserved_115_127 : 13;
+#endif
+#if defined(__BIG_ENDIAN_BITFIELD) /* W2 */
+ u64 stack_pages : 32;
+ u64 stack_max_pages : 32;
+#else
+ u64 stack_max_pages : 32;
+ u64 stack_pages : 32;
+#endif
+#if defined(__BIG_ENDIAN_BITFIELD) /* W3 */
+ u64 reserved_240_255 : 16;
+ u64 op_pc : 48;
+#else
+ u64 op_pc : 48;
+ u64 reserved_240_255 : 16;
+#endif
+#if defined(__BIG_ENDIAN_BITFIELD) /* W4 */
+ u64 reserved_316_319 : 4;
+ u64 update_time : 16;
+ u64 reserved_297_299 : 3;
+ u64 fc_up_crossing : 1;
+ u64 fc_hyst_bits : 4;
+ u64 fc_stype : 2;
+ u64 fc_ena : 1;
+ u64 avg_con : 9;
+ u64 avg_level : 8;
+ u64 reserved_270_271 : 2;
+ u64 shift : 6;
+ u64 reserved_260_263 : 4;
+ u64 stack_offset : 4;
+#else
+ u64 stack_offset : 4;
+ u64 reserved_260_263 : 4;
+ u64 shift : 6;
+ u64 reserved_270_271 : 2;
+ u64 avg_level : 8;
+ u64 avg_con : 9;
+ u64 fc_ena : 1;
+ u64 fc_stype : 2;
+ u64 fc_hyst_bits : 4;
+ u64 fc_up_crossing : 1;
+ u64 reserved_297_299 : 3;
+ u64 update_time : 16;
+ u64 reserved_316_319 : 4;
+#endif
+ u64 fc_addr; /* W5 */
+ u64 ptr_start; /* W6 */
+ u64 ptr_end; /* W7 */
+#if defined(__BIG_ENDIAN_BITFIELD) /* W8 */
+ u64 reserved_571_575 : 5;
+ u64 err_qint_idx : 7;
+ u64 reserved_563 : 1;
+ u64 thresh_qint_idx : 7;
+ u64 reserved_555 : 1;
+ u64 thresh_up : 1;
+ u64 thresh_int_ena : 1;
+ u64 thresh_int : 1;
+ u64 err_int_ena : 8;
+ u64 err_int : 8;
+ u64 reserved_512_535 : 24;
+#else
+ u64 reserved_512_535 : 24;
+ u64 err_int : 8;
+ u64 err_int_ena : 8;
+ u64 thresh_int : 1;
+ u64 thresh_int_ena : 1;
+ u64 thresh_up : 1;
+ u64 reserved_555 : 1;
+ u64 thresh_qint_idx : 7;
+ u64 reserved_563 : 1;
+ u64 err_qint_idx : 7;
+ u64 reserved_571_575 : 5;
+#endif
+#if defined(__BIG_ENDIAN_BITFIELD) /* W9 */
+ u64 reserved_612_639 : 28;
+ u64 thresh : 36;
+#else
+ u64 thresh : 36;
+ u64 reserved_612_639 : 28;
+#endif
+ u64 reserved_640_703; /* W10 */
+ u64 reserved_704_767; /* W11 */
+ u64 reserved_768_831; /* W12 */
+ u64 reserved_832_895; /* W13 */
+ u64 reserved_896_959; /* W14 */
+ u64 reserved_960_1023; /* W15 */
+};
+
+/* NIX admin queue completion status */
+enum nix_aq_comp {
+ NIX_AQ_COMP_NOTDONE = 0x0,
+ NIX_AQ_COMP_GOOD = 0x1,
+ NIX_AQ_COMP_SWERR = 0x2,
+ NIX_AQ_COMP_CTX_POISON = 0x3,
+ NIX_AQ_COMP_CTX_FAULT = 0x4,
+ NIX_AQ_COMP_LOCKERR = 0x5,
+ NIX_AQ_COMP_SQB_ALLOC_FAIL = 0x6,
+};
+
+/* NIX admin queue context types */
+enum nix_aq_ctype {
+ NIX_AQ_CTYPE_RQ = 0x0,
+ NIX_AQ_CTYPE_SQ = 0x1,
+ NIX_AQ_CTYPE_CQ = 0x2,
+ NIX_AQ_CTYPE_MCE = 0x3,
+ NIX_AQ_CTYPE_RSS = 0x4,
+ NIX_AQ_CTYPE_DYNO = 0x5,
+};
+
+/* NIX admin queue instruction opcodes */
+enum nix_aq_instop {
+ NIX_AQ_INSTOP_NOP = 0x0,
+ NIX_AQ_INSTOP_INIT = 0x1,
+ NIX_AQ_INSTOP_WRITE = 0x2,
+ NIX_AQ_INSTOP_READ = 0x3,
+ NIX_AQ_INSTOP_LOCK = 0x4,
+ NIX_AQ_INSTOP_UNLOCK = 0x5,
+};
+
+/* NIX admin queue instruction structure */
+struct nix_aq_inst_s {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ u64 doneint : 1; /* W0 */
+ u64 reserved_44_62 : 19;
+ u64 cindex : 20;
+ u64 reserved_15_23 : 9;
+ u64 lf : 7;
+ u64 ctype : 4;
+ u64 op : 4;
+#else
+ u64 op : 4;
+ u64 ctype : 4;
+ u64 lf : 7;
+ u64 reserved_15_23 : 9;
+ u64 cindex : 20;
+ u64 reserved_44_62 : 19;
+ u64 doneint : 1;
+#endif
+ u64 res_addr; /* W1 */
+};
+
+/* NIX admin queue result structure */
+struct nix_aq_res_s {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ u64 reserved_17_63 : 47; /* W0 */
+ u64 doneint : 1;
+ u64 compcode : 8;
+ u64 ctype : 4;
+ u64 op : 4;
+#else
+ u64 op : 4;
+ u64 ctype : 4;
+ u64 compcode : 8;
+ u64 doneint : 1;
+ u64 reserved_17_63 : 47;
+#endif
+ u64 reserved_64_127; /* W1 */
+};
+
+/* NIX Completion queue context structure */
+struct nix_cq_ctx_s {
+ u64 base;
+#if defined(__BIG_ENDIAN_BITFIELD) /* W1 */
+ u64 wrptr : 20;
+ u64 avg_con : 9;
+ u64 cint_idx : 7;
+ u64 cq_err : 1;
+ u64 qint_idx : 7;
+ u64 rsvd_81_83 : 3;
+ u64 bpid : 9;
+ u64 rsvd_69_71 : 3;
+ u64 bp_ena : 1;
+ u64 rsvd_64_67 : 4;
+#else
+ u64 rsvd_64_67 : 4;
+ u64 bp_ena : 1;
+ u64 rsvd_69_71 : 3;
+ u64 bpid : 9;
+ u64 rsvd_81_83 : 3;
+ u64 qint_idx : 7;
+ u64 cq_err : 1;
+ u64 cint_idx : 7;
+ u64 avg_con : 9;
+ u64 wrptr : 20;
+#endif
+#if defined(__BIG_ENDIAN_BITFIELD) /* W2 */
+ u64 update_time : 16;
+ u64 avg_level : 8;
+ u64 head : 20;
+ u64 tail : 20;
+#else
+ u64 tail : 20;
+ u64 head : 20;
+ u64 avg_level : 8;
+ u64 update_time : 16;
+#endif
+#if defined(__BIG_ENDIAN_BITFIELD) /* W3 */
+ u64 cq_err_int_ena : 8;
+ u64 cq_err_int : 8;
+ u64 qsize : 4;
+ u64 rsvd_233_235 : 3;
+ u64 caching : 1;
+ u64 substream : 20;
+ u64 rsvd_210_211 : 2;
+ u64 ena : 1;
+ u64 drop_ena : 1;
+ u64 drop : 8;
+ u64 dp : 8;
+#else
+ u64 dp : 8;
+ u64 drop : 8;
+ u64 drop_ena : 1;
+ u64 ena : 1;
+ u64 rsvd_210_211 : 2;
+ u64 substream : 20;
+ u64 caching : 1;
+ u64 rsvd_233_235 : 3;
+ u64 qsize : 4;
+ u64 cq_err_int : 8;
+ u64 cq_err_int_ena : 8;
+#endif
+};
+
+/* NIX Receive queue context structure */
+struct nix_rq_ctx_s {
+#if defined(__BIG_ENDIAN_BITFIELD) /* W0 */
+ u64 wqe_aura : 20;
+ u64 substream : 20;
+ u64 cq : 20;
+ u64 ena_wqwd : 1;
+ u64 ipsech_ena : 1;
+ u64 sso_ena : 1;
+ u64 ena : 1;
+#else
+ u64 ena : 1;
+ u64 sso_ena : 1;
+ u64 ipsech_ena : 1;
+ u64 ena_wqwd : 1;
+ u64 cq : 20;
+ u64 substream : 20;
+ u64 wqe_aura : 20;
+#endif
+#if defined(__BIG_ENDIAN_BITFIELD) /* W1 */
+ u64 rsvd_127_122 : 6;
+ u64 lpb_drop_ena : 1;
+ u64 spb_drop_ena : 1;
+ u64 xqe_drop_ena : 1;
+ u64 wqe_caching : 1;
+ u64 pb_caching : 2;
+ u64 sso_tt : 2;
+ u64 sso_grp : 10;
+ u64 lpb_aura : 20;
+ u64 spb_aura : 20;
+#else
+ u64 spb_aura : 20;
+ u64 lpb_aura : 20;
+ u64 sso_grp : 10;
+ u64 sso_tt : 2;
+ u64 pb_caching : 2;
+ u64 wqe_caching : 1;
+ u64 xqe_drop_ena : 1;
+ u64 spb_drop_ena : 1;
+ u64 lpb_drop_ena : 1;
+ u64 rsvd_127_122 : 6;
+#endif
+#if defined(__BIG_ENDIAN_BITFIELD) /* W2 */
+ u64 xqe_hdr_split : 1;
+ u64 xqe_imm_copy : 1;
+ u64 rsvd_189_184 : 6;
+ u64 xqe_imm_size : 6;
+ u64 later_skip : 6;
+ u64 rsvd_171 : 1;
+ u64 first_skip : 7;
+ u64 lpb_sizem1 : 12;
+ u64 spb_ena : 1;
+ u64 rsvd_150_148 : 3;
+ u64 wqe_skip : 2;
+ u64 spb_sizem1 : 6;
+ u64 rsvd_139_128 : 12;
+#else
+ u64 rsvd_139_128 : 12;
+ u64 spb_sizem1 : 6;
+ u64 wqe_skip : 2;
+ u64 rsvd_150_148 : 3;
+ u64 spb_ena : 1;
+ u64 lpb_sizem1 : 12;
+ u64 first_skip : 7;
+ u64 rsvd_171 : 1;
+ u64 later_skip : 6;
+ u64 xqe_imm_size : 6;
+ u64 rsvd_189_184 : 6;
+ u64 xqe_imm_copy : 1;
+ u64 xqe_hdr_split : 1;
+#endif
+#if defined(__BIG_ENDIAN_BITFIELD) /* W3 */
+ u64 spb_pool_pass : 8;
+ u64 spb_pool_drop : 8;
+ u64 spb_aura_pass : 8;
+ u64 spb_aura_drop : 8;
+ u64 wqe_pool_pass : 8;
+ u64 wqe_pool_drop : 8;
+ u64 xqe_pass : 8;
+ u64 xqe_drop : 8;
+#else
+ u64 xqe_drop : 8;
+ u64 xqe_pass : 8;
+ u64 wqe_pool_drop : 8;
+ u64 wqe_pool_pass : 8;
+ u64 spb_aura_drop : 8;
+ u64 spb_aura_pass : 8;
+ u64 spb_pool_drop : 8;
+ u64 spb_pool_pass : 8;
+#endif
+#if defined(__BIG_ENDIAN_BITFIELD) /* W4 */
+ u64 rsvd_319_315 : 5;
+ u64 qint_idx : 7;
+ u64 rq_int_ena : 8;
+ u64 rq_int : 8;
+ u64 rsvd_291_288 : 4;
+ u64 lpb_pool_pass : 8;
+ u64 lpb_pool_drop : 8;
+ u64 lpb_aura_pass : 8;
+ u64 lpb_aura_drop : 8;
+#else
+ u64 lpb_aura_drop : 8;
+ u64 lpb_aura_pass : 8;
+ u64 lpb_pool_drop : 8;
+ u64 lpb_pool_pass : 8;
+ u64 rsvd_291_288 : 4;
+ u64 rq_int : 8;
+ u64 rq_int_ena : 8;
+ u64 qint_idx : 7;
+ u64 rsvd_319_315 : 5;
+#endif
+#if defined(__BIG_ENDIAN_BITFIELD) /* W5 */
+ u64 rsvd_383_366 : 18;
+ u64 flow_tagw : 6;
+ u64 bad_utag : 8;
+ u64 good_utag : 8;
+ u64 ltag : 24;
+#else
+ u64 ltag : 24;
+ u64 good_utag : 8;
+ u64 bad_utag : 8;
+ u64 flow_tagw : 6;
+ u64 rsvd_383_366 : 18;
+#endif
+#if defined(__BIG_ENDIAN_BITFIELD) /* W6 */
+ u64 rsvd_447_432 : 16;
+ u64 octs : 48;
+#else
+ u64 octs : 48;
+ u64 rsvd_447_432 : 16;
+#endif
+#if defined(__BIG_ENDIAN_BITFIELD) /* W7 */
+ u64 rsvd_511_496 : 16;
+ u64 pkts : 48;
+#else
+ u64 pkts : 48;
+ u64 rsvd_511_496 : 16;
+#endif
+#if defined(__BIG_ENDIAN_BITFIELD) /* W8 */
+ u64 rsvd_575_560 : 16;
+ u64 drop_octs : 48;
+#else
+ u64 drop_octs : 48;
+ u64 rsvd_575_560 : 16;
+#endif
+#if defined(__BIG_ENDIAN_BITFIELD) /* W9 */
+ u64 rsvd_639_624 : 16;
+ u64 drop_pkts : 48;
+#else
+ u64 drop_pkts : 48;
+ u64 rsvd_639_624 : 16;
+#endif
+#if defined(__BIG_ENDIAN_BITFIELD) /* W10 */
+ u64 rsvd_703_688 : 16;
+ u64 re_pkts : 48;
+#else
+ u64 re_pkts : 48;
+ u64 rsvd_703_688 : 16;
+#endif
+ u64 rsvd_767_704; /* W11 */
+ u64 rsvd_831_768; /* W12 */
+ u64 rsvd_895_832; /* W13 */
+ u64 rsvd_959_896; /* W14 */
+ u64 rsvd_1023_960; /* W15 */
+};
+
+/* NIX sqe sizes */
+enum nix_maxsqesz {
+ NIX_MAXSQESZ_W16 = 0x0,
+ NIX_MAXSQESZ_W8 = 0x1,
+};
+
+/* NIX SQB caching type */
+enum nix_stype {
+ NIX_STYPE_STF = 0x0,
+ NIX_STYPE_STT = 0x1,
+ NIX_STYPE_STP = 0x2,
+};
+
+/* NIX Send queue context structure */
+struct nix_sq_ctx_s {
+#if defined(__BIG_ENDIAN_BITFIELD) /* W0 */
+ u64 sqe_way_mask : 16;
+ u64 cq : 20;
+ u64 sdp_mcast : 1;
+ u64 substream : 20;
+ u64 qint_idx : 6;
+ u64 ena : 1;
+#else
+ u64 ena : 1;
+ u64 qint_idx : 6;
+ u64 substream : 20;
+ u64 sdp_mcast : 1;
+ u64 cq : 20;
+ u64 sqe_way_mask : 16;
+#endif
+#if defined(__BIG_ENDIAN_BITFIELD) /* W1 */
+ u64 sqb_count : 16;
+ u64 default_chan : 12;
+ u64 smq_rr_quantum : 24;
+ u64 sso_ena : 1;
+ u64 xoff : 1;
+ u64 cq_ena : 1;
+ u64 smq : 9;
+#else
+ u64 smq : 9;
+ u64 cq_ena : 1;
+ u64 xoff : 1;
+ u64 sso_ena : 1;
+ u64 smq_rr_quantum : 24;
+ u64 default_chan : 12;
+ u64 sqb_count : 16;
+#endif
+#if defined(__BIG_ENDIAN_BITFIELD) /* W2 */
+ u64 rsvd_191 : 1;
+ u64 sqe_stype : 2;
+ u64 sq_int_ena : 8;
+ u64 sq_int : 8;
+ u64 sqb_aura : 20;
+ u64 smq_rr_count : 25;
+#else
+ u64 smq_rr_count : 25;
+ u64 sqb_aura : 20;
+ u64 sq_int : 8;
+ u64 sq_int_ena : 8;
+ u64 sqe_stype : 2;
+ u64 rsvd_191 : 1;
+#endif
+#if defined(__BIG_ENDIAN_BITFIELD) /* W3 */
+ u64 rsvd_255_253 : 3;
+ u64 smq_next_sq_vld : 1;
+ u64 smq_pend : 1;
+ u64 smenq_next_sqb_vld : 1;
+ u64 head_offset : 6;
+ u64 smenq_offset : 6;
+ u64 tail_offset : 6;
+ u64 smq_lso_segnum : 8;
+ u64 smq_next_sq : 20;
+ u64 mnq_dis : 1;
+ u64 lmt_dis : 1;
+ u64 cq_limit : 8;
+ u64 max_sqe_size : 2;
+#else
+ u64 max_sqe_size : 2;
+ u64 cq_limit : 8;
+ u64 lmt_dis : 1;
+ u64 mnq_dis : 1;
+ u64 smq_next_sq : 20;
+ u64 smq_lso_segnum : 8;
+ u64 tail_offset : 6;
+ u64 smenq_offset : 6;
+ u64 head_offset : 6;
+ u64 smenq_next_sqb_vld : 1;
+ u64 smq_pend : 1;
+ u64 smq_next_sq_vld : 1;
+ u64 rsvd_255_253 : 3;
+#endif
+ u64 next_sqb : 64;/* W4 */
+ u64 tail_sqb : 64;/* W5 */
+ u64 smenq_sqb : 64;/* W6 */
+ u64 smenq_next_sqb : 64;/* W7 */
+ u64 head_sqb : 64;/* W8 */
+#if defined(__BIG_ENDIAN_BITFIELD) /* W9 */
+ u64 rsvd_639_630 : 10;
+ u64 vfi_lso_vld : 1;
+ u64 vfi_lso_vlan1_ins_ena : 1;
+ u64 vfi_lso_vlan0_ins_ena : 1;
+ u64 vfi_lso_mps : 14;
+ u64 vfi_lso_sb : 8;
+ u64 vfi_lso_sizem1 : 3;
+ u64 vfi_lso_total : 18;
+ u64 rsvd_583_576 : 8;
+#else
+ u64 rsvd_583_576 : 8;
+ u64 vfi_lso_total : 18;
+ u64 vfi_lso_sizem1 : 3;
+ u64 vfi_lso_sb : 8;
+ u64 vfi_lso_mps : 14;
+ u64 vfi_lso_vlan0_ins_ena : 1;
+ u64 vfi_lso_vlan1_ins_ena : 1;
+ u64 vfi_lso_vld : 1;
+ u64 rsvd_639_630 : 10;
+#endif
+#if defined(__BIG_ENDIAN_BITFIELD) /* W10 */
+ u64 rsvd_703_658 : 46;
+ u64 scm_lso_rem : 18;
+#else
+ u64 scm_lso_rem : 18;
+ u64 rsvd_703_658 : 46;
+#endif
+#if defined(__BIG_ENDIAN_BITFIELD) /* W11 */
+ u64 rsvd_767_752 : 16;
+ u64 octs : 48;
+#else
+ u64 octs : 48;
+ u64 rsvd_767_752 : 16;
+#endif
+#if defined(__BIG_ENDIAN_BITFIELD) /* W12 */
+ u64 rsvd_831_816 : 16;
+ u64 pkts : 48;
+#else
+ u64 pkts : 48;
+ u64 rsvd_831_816 : 16;
+#endif
+ u64 rsvd_895_832 : 64;/* W13 */
+#if defined(__BIG_ENDIAN_BITFIELD) /* W14 */
+ u64 rsvd_959_944 : 16;
+ u64 dropped_octs : 48;
+#else
+ u64 dropped_octs : 48;
+ u64 rsvd_959_944 : 16;
+#endif
+#if defined(__BIG_ENDIAN_BITFIELD) /* W15 */
+ u64 rsvd_1023_1008 : 16;
+ u64 dropped_pkts : 48;
+#else
+ u64 dropped_pkts : 48;
+ u64 rsvd_1023_1008 : 16;
+#endif
+};
+
+/* NIX Receive side scaling entry structure*/
+struct nix_rsse_s {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ uint32_t reserved_20_31 : 12;
+ uint32_t rq : 20;
+#else
+ uint32_t rq : 20;
+ uint32_t reserved_20_31 : 12;
+
+#endif
+};
+
+/* NIX receive multicast/mirror entry structure */
+struct nix_rx_mce_s {
+#if defined(__BIG_ENDIAN_BITFIELD) /* W0 */
+ uint64_t next : 16;
+ uint64_t pf_func : 16;
+ uint64_t rsvd_31_24 : 8;
+ uint64_t index : 20;
+ uint64_t eol : 1;
+ uint64_t rsvd_2 : 1;
+ uint64_t op : 2;
+#else
+ uint64_t op : 2;
+ uint64_t rsvd_2 : 1;
+ uint64_t eol : 1;
+ uint64_t index : 20;
+ uint64_t rsvd_31_24 : 8;
+ uint64_t pf_func : 16;
+ uint64_t next : 16;
+#endif
+};
+
+enum nix_lsoalg {
+ NIX_LSOALG_NOP,
+ NIX_LSOALG_ADD_SEGNUM,
+ NIX_LSOALG_ADD_PAYLEN,
+ NIX_LSOALG_ADD_OFFSET,
+ NIX_LSOALG_TCP_FLAGS,
+};
+
+enum nix_txlayer {
+ NIX_TXLAYER_OL3,
+ NIX_TXLAYER_OL4,
+ NIX_TXLAYER_IL3,
+ NIX_TXLAYER_IL4,
+};
+
+struct nix_lso_format {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ u64 rsvd_19_63 : 45;
+ u64 alg : 3;
+ u64 rsvd_14_15 : 2;
+ u64 sizem1 : 2;
+ u64 rsvd_10_11 : 2;
+ u64 layer : 2;
+ u64 offset : 8;
+#else
+ u64 offset : 8;
+ u64 layer : 2;
+ u64 rsvd_10_11 : 2;
+ u64 sizem1 : 2;
+ u64 rsvd_14_15 : 2;
+ u64 alg : 3;
+ u64 rsvd_19_63 : 45;
+#endif
+};
+
+struct nix_rx_flowkey_alg {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ u64 reserved_35_63 :29;
+ u64 ltype_match :4;
+ u64 ltype_mask :4;
+ u64 sel_chan :1;
+ u64 ena :1;
+ u64 reserved_24_24 :1;
+ u64 lid :3;
+ u64 bytesm1 :5;
+ u64 hdr_offset :8;
+ u64 fn_mask :1;
+ u64 ln_mask :1;
+ u64 key_offset :6;
+#else
+ u64 key_offset :6;
+ u64 ln_mask :1;
+ u64 fn_mask :1;
+ u64 hdr_offset :8;
+ u64 bytesm1 :5;
+ u64 lid :3;
+ u64 reserved_24_24 :1;
+ u64 ena :1;
+ u64 sel_chan :1;
+ u64 ltype_mask :4;
+ u64 ltype_match :4;
+ u64 reserved_35_63 :29;
+#endif
+};
+
+/* NIX VTAG size */
+enum nix_vtag_size {
+ VTAGSIZE_T4 = 0x0,
+ VTAGSIZE_T8 = 0x1,
+};
+#endif /* RVU_STRUCT_H */
diff --git a/drivers/net/ethernet/marvell/pxa168_eth.c b/drivers/net/ethernet/marvell/pxa168_eth.c
index 3a9730612a70..0bd4351b2a49 100644
--- a/drivers/net/ethernet/marvell/pxa168_eth.c
+++ b/drivers/net/ethernet/marvell/pxa168_eth.c
@@ -988,8 +988,8 @@ static int pxa168_init_phy(struct net_device *dev)
cmd.base.phy_address = pep->phy_addr;
cmd.base.speed = pep->phy_speed;
cmd.base.duplex = pep->phy_duplex;
- ethtool_convert_legacy_u32_to_link_mode(cmd.link_modes.advertising,
- PHY_BASIC_FEATURES);
+ bitmap_copy(cmd.link_modes.advertising, PHY_BASIC_FEATURES,
+ __ETHTOOL_LINK_MODE_MASK_NBITS);
cmd.base.autoneg = AUTONEG_ENABLE;
if (cmd.base.speed != 0)
@@ -1260,7 +1260,8 @@ static int pxa168_rx_poll(struct napi_struct *napi, int budget)
return work_done;
}
-static int pxa168_eth_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t
+pxa168_eth_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct pxa168_eth_private *pep = netdev_priv(dev);
struct net_device_stats *stats = &dev->stats;
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index 6e6abdc399de..7dbfdac4067a 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -243,11 +243,7 @@ static void mtk_phy_link_adjust(struct net_device *dev)
if (dev->phydev->asym_pause)
rmt_adv |= LPA_PAUSE_ASYM;
- if (dev->phydev->advertising & ADVERTISED_Pause)
- lcl_adv |= ADVERTISE_PAUSE_CAP;
- if (dev->phydev->advertising & ADVERTISED_Asym_Pause)
- lcl_adv |= ADVERTISE_PAUSE_ASYM;
-
+ lcl_adv = ethtool_adv_to_lcl_adv_t(dev->phydev->advertising);
flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
if (flowctrl & FLOW_CTRL_TX)
@@ -355,12 +351,8 @@ static int mtk_phy_connect(struct net_device *dev)
dev->phydev->speed = 0;
dev->phydev->duplex = 0;
- if (of_phy_is_fixed_link(mac->of_node))
- dev->phydev->supported |=
- SUPPORTED_Pause | SUPPORTED_Asym_Pause;
-
- dev->phydev->supported &= PHY_GBIT_FEATURES | SUPPORTED_Pause |
- SUPPORTED_Asym_Pause;
+ phy_set_max_speed(dev->phydev, SPEED_1000);
+ phy_support_asym_pause(dev->phydev);
dev->phydev->advertising = dev->phydev->supported |
ADVERTISED_Autoneg;
phy_start_aneg(dev->phydev);
@@ -405,7 +397,7 @@ static int mtk_mdio_init(struct mtk_eth *eth)
eth->mii_bus->priv = eth;
eth->mii_bus->parent = eth->dev;
- snprintf(eth->mii_bus->id, MII_BUS_ID_SIZE, "%s", mii_np->name);
+ snprintf(eth->mii_bus->id, MII_BUS_ID_SIZE, "%pOFn", mii_np);
ret = of_mdiobus_register(eth->mii_bus, mii_np);
err_put_node:
diff --git a/drivers/net/ethernet/mellanox/mlx4/alloc.c b/drivers/net/ethernet/mellanox/mlx4/alloc.c
index 4bdf25059542..deef5a998985 100644
--- a/drivers/net/ethernet/mellanox/mlx4/alloc.c
+++ b/drivers/net/ethernet/mellanox/mlx4/alloc.c
@@ -614,7 +614,7 @@ int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct,
int i;
buf->direct.buf = NULL;
- buf->nbufs = (size + PAGE_SIZE - 1) / PAGE_SIZE;
+ buf->nbufs = DIV_ROUND_UP(size, PAGE_SIZE);
buf->npages = buf->nbufs;
buf->page_shift = PAGE_SHIFT;
buf->page_list = kcalloc(buf->nbufs, sizeof(*buf->page_list),
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_main.c b/drivers/net/ethernet/mellanox/mlx4/en_main.c
index d25e16d2c319..109472d6b61f 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_main.c
@@ -167,8 +167,13 @@ static void mlx4_en_get_profile(struct mlx4_en_dev *mdev)
params->prof[i].rx_ppp = pfcrx;
params->prof[i].tx_pause = !(pfcrx || pfctx);
params->prof[i].tx_ppp = pfctx;
- params->prof[i].tx_ring_size = MLX4_EN_DEF_TX_RING_SIZE;
- params->prof[i].rx_ring_size = MLX4_EN_DEF_RX_RING_SIZE;
+ if (mlx4_low_memory_profile()) {
+ params->prof[i].tx_ring_size = MLX4_EN_MIN_TX_SIZE;
+ params->prof[i].rx_ring_size = MLX4_EN_MIN_RX_SIZE;
+ } else {
+ params->prof[i].tx_ring_size = MLX4_EN_DEF_TX_RING_SIZE;
+ params->prof[i].rx_ring_size = MLX4_EN_DEF_RX_RING_SIZE;
+ }
params->prof[i].num_up = MLX4_EN_NUM_UP_LOW;
params->prof[i].num_tx_rings_p_up = params->max_num_tx_rings_p_up;
params->prof[i].tx_ring_num[TX] = params->max_num_tx_rings_p_up *
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index fe49384eba48..b744cd49a785 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -39,7 +39,6 @@
#include <linux/slab.h>
#include <linux/hash.h>
#include <net/ip.h>
-#include <net/busy_poll.h>
#include <net/vxlan.h>
#include <net/devlink.h>
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
index a1aeeb8094c3..db00bf1c23f5 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
@@ -31,7 +31,6 @@
*
*/
-#include <net/busy_poll.h>
#include <linux/bpf.h>
#include <linux/bpf_trace.h>
#include <linux/mlx4/cq.h>
@@ -44,6 +43,7 @@
#include <linux/vmalloc.h>
#include <linux/irq.h>
+#include <net/ip.h>
#if IS_ENABLED(CONFIG_IPV6)
#include <net/ip6_checksum.h>
#endif
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
index 1857ee0f0871..6f5153afcab4 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
@@ -1006,7 +1006,6 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
ring->packets++;
}
ring->bytes += tx_info->nr_bytes;
- netdev_tx_sent_queue(ring->tx_queue, tx_info->nr_bytes);
AVG_PERF_COUNTER(priv->pstats.tx_pktsz_avg, skb->len);
if (tx_info->inl)
@@ -1044,7 +1043,10 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
netif_tx_stop_queue(ring->tx_queue);
ring->queue_stopped++;
}
- send_doorbell = !skb->xmit_more || netif_xmit_stopped(ring->tx_queue);
+
+ send_doorbell = __netdev_tx_sent_queue(ring->tx_queue,
+ tx_info->nr_bytes,
+ skb->xmit_more);
real_size = (real_size / 16) & 0x3f;
diff --git a/drivers/net/ethernet/mellanox/mlx4/icm.c b/drivers/net/ethernet/mellanox/mlx4/icm.c
index 7262c6310650..4b4351141b94 100644
--- a/drivers/net/ethernet/mellanox/mlx4/icm.c
+++ b/drivers/net/ethernet/mellanox/mlx4/icm.c
@@ -406,7 +406,7 @@ int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table,
obj_per_chunk = MLX4_TABLE_CHUNK_SIZE / obj_size;
if (WARN_ON(!obj_per_chunk))
return -EINVAL;
- num_icm = (nobj + obj_per_chunk - 1) / obj_per_chunk;
+ num_icm = DIV_ROUND_UP(nobj, obj_per_chunk);
table->icm = kvcalloc(num_icm, sizeof(*table->icm), GFP_KERNEL);
if (!table->icm)
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c
index d2d59444f562..6a046030e873 100644
--- a/drivers/net/ethernet/mellanox/mlx4/main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/main.c
@@ -260,47 +260,34 @@ static const struct devlink_param mlx4_devlink_params[] = {
NULL, NULL, NULL),
};
-static void mlx4_devlink_set_init_value(struct devlink *devlink, u32 param_id,
- union devlink_param_value init_val)
-{
- struct mlx4_priv *priv = devlink_priv(devlink);
- struct mlx4_dev *dev = &priv->dev;
- int err;
-
- err = devlink_param_driverinit_value_set(devlink, param_id, init_val);
- if (err)
- mlx4_warn(dev,
- "devlink set parameter %u value failed (err = %d)",
- param_id, err);
-}
-
static void mlx4_devlink_set_params_init_values(struct devlink *devlink)
{
union devlink_param_value value;
value.vbool = !!mlx4_internal_err_reset;
- mlx4_devlink_set_init_value(devlink,
- DEVLINK_PARAM_GENERIC_ID_INT_ERR_RESET,
- value);
+ devlink_param_driverinit_value_set(devlink,
+ DEVLINK_PARAM_GENERIC_ID_INT_ERR_RESET,
+ value);
value.vu32 = 1UL << log_num_mac;
- mlx4_devlink_set_init_value(devlink,
- DEVLINK_PARAM_GENERIC_ID_MAX_MACS, value);
+ devlink_param_driverinit_value_set(devlink,
+ DEVLINK_PARAM_GENERIC_ID_MAX_MACS,
+ value);
value.vbool = enable_64b_cqe_eqe;
- mlx4_devlink_set_init_value(devlink,
- MLX4_DEVLINK_PARAM_ID_ENABLE_64B_CQE_EQE,
- value);
+ devlink_param_driverinit_value_set(devlink,
+ MLX4_DEVLINK_PARAM_ID_ENABLE_64B_CQE_EQE,
+ value);
value.vbool = enable_4k_uar;
- mlx4_devlink_set_init_value(devlink,
- MLX4_DEVLINK_PARAM_ID_ENABLE_4K_UAR,
- value);
+ devlink_param_driverinit_value_set(devlink,
+ MLX4_DEVLINK_PARAM_ID_ENABLE_4K_UAR,
+ value);
value.vbool = false;
- mlx4_devlink_set_init_value(devlink,
- DEVLINK_PARAM_GENERIC_ID_REGION_SNAPSHOT,
- value);
+ devlink_param_driverinit_value_set(devlink,
+ DEVLINK_PARAM_GENERIC_ID_REGION_SNAPSHOT,
+ value);
}
static inline void mlx4_set_num_reserved_uars(struct mlx4_dev *dev,
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index c3228b89df46..485d856546c6 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -72,7 +72,7 @@
#define MLX4_EN_PAGE_SIZE (1 << MLX4_EN_PAGE_SHIFT)
#define DEF_RX_RINGS 16
#define MAX_RX_RINGS 128
-#define MIN_RX_RINGS 4
+#define MIN_RX_RINGS 1
#define LOG_TXBB_SIZE 6
#define TXBB_SIZE BIT(LOG_TXBB_SIZE)
#define HEADROOM (2048 / TXBB_SIZE + 1)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
index a53736c26c0c..a5a0823e5ada 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
@@ -308,10 +308,11 @@ static int mlx5_internal_err_ret_value(struct mlx5_core_dev *dev, u16 op,
case MLX5_CMD_OP_MODIFY_FLOW_TABLE:
case MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY:
case MLX5_CMD_OP_SET_FLOW_TABLE_ROOT:
- case MLX5_CMD_OP_DEALLOC_ENCAP_HEADER:
+ case MLX5_CMD_OP_DEALLOC_PACKET_REFORMAT_CONTEXT:
case MLX5_CMD_OP_DEALLOC_MODIFY_HEADER_CONTEXT:
case MLX5_CMD_OP_FPGA_DESTROY_QP:
case MLX5_CMD_OP_DESTROY_GENERAL_OBJECT:
+ case MLX5_CMD_OP_DEALLOC_MEMIC:
return MLX5_CMD_STAT_OK;
case MLX5_CMD_OP_QUERY_HCA_CAP:
@@ -426,7 +427,7 @@ static int mlx5_internal_err_ret_value(struct mlx5_core_dev *dev, u16 op,
case MLX5_CMD_OP_QUERY_FLOW_TABLE_ENTRY:
case MLX5_CMD_OP_ALLOC_FLOW_COUNTER:
case MLX5_CMD_OP_QUERY_FLOW_COUNTER:
- case MLX5_CMD_OP_ALLOC_ENCAP_HEADER:
+ case MLX5_CMD_OP_ALLOC_PACKET_REFORMAT_CONTEXT:
case MLX5_CMD_OP_ALLOC_MODIFY_HEADER_CONTEXT:
case MLX5_CMD_OP_FPGA_CREATE_QP:
case MLX5_CMD_OP_FPGA_MODIFY_QP:
@@ -435,6 +436,7 @@ static int mlx5_internal_err_ret_value(struct mlx5_core_dev *dev, u16 op,
case MLX5_CMD_OP_CREATE_GENERAL_OBJECT:
case MLX5_CMD_OP_MODIFY_GENERAL_OBJECT:
case MLX5_CMD_OP_QUERY_GENERAL_OBJECT:
+ case MLX5_CMD_OP_ALLOC_MEMIC:
*status = MLX5_DRIVER_STATUS_ABORTED;
*synd = MLX5_DRIVER_SYND;
return -EIO;
@@ -599,8 +601,8 @@ const char *mlx5_command_str(int command)
MLX5_COMMAND_STR_CASE(DEALLOC_FLOW_COUNTER);
MLX5_COMMAND_STR_CASE(QUERY_FLOW_COUNTER);
MLX5_COMMAND_STR_CASE(MODIFY_FLOW_TABLE);
- MLX5_COMMAND_STR_CASE(ALLOC_ENCAP_HEADER);
- MLX5_COMMAND_STR_CASE(DEALLOC_ENCAP_HEADER);
+ MLX5_COMMAND_STR_CASE(ALLOC_PACKET_REFORMAT_CONTEXT);
+ MLX5_COMMAND_STR_CASE(DEALLOC_PACKET_REFORMAT_CONTEXT);
MLX5_COMMAND_STR_CASE(ALLOC_MODIFY_HEADER_CONTEXT);
MLX5_COMMAND_STR_CASE(DEALLOC_MODIFY_HEADER_CONTEXT);
MLX5_COMMAND_STR_CASE(FPGA_CREATE_QP);
@@ -617,6 +619,8 @@ const char *mlx5_command_str(int command)
MLX5_COMMAND_STR_CASE(MODIFY_GENERAL_OBJECT);
MLX5_COMMAND_STR_CASE(QUERY_GENERAL_OBJECT);
MLX5_COMMAND_STR_CASE(QUERY_MODIFY_HEADER_CONTEXT);
+ MLX5_COMMAND_STR_CASE(ALLOC_MEMIC);
+ MLX5_COMMAND_STR_CASE(DEALLOC_MEMIC);
default: return "unknown command opcode";
}
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cq.c b/drivers/net/ethernet/mellanox/mlx5/core/cq.c
index a4179122a279..4b85abb5c9f7 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/cq.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/cq.c
@@ -109,6 +109,7 @@ int mlx5_core_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
cq->cons_index = 0;
cq->arm_sn = 0;
cq->eq = eq;
+ cq->uid = MLX5_GET(create_cq_in, in, uid);
refcount_set(&cq->refcount, 1);
init_completion(&cq->free);
if (!cq->comp)
@@ -144,6 +145,7 @@ err_cmd:
memset(dout, 0, sizeof(dout));
MLX5_SET(destroy_cq_in, din, opcode, MLX5_CMD_OP_DESTROY_CQ);
MLX5_SET(destroy_cq_in, din, cqn, cq->cqn);
+ MLX5_SET(destroy_cq_in, din, uid, cq->uid);
mlx5_cmd_exec(dev, din, sizeof(din), dout, sizeof(dout));
return err;
}
@@ -165,6 +167,7 @@ int mlx5_core_destroy_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq)
MLX5_SET(destroy_cq_in, in, opcode, MLX5_CMD_OP_DESTROY_CQ);
MLX5_SET(destroy_cq_in, in, cqn, cq->cqn);
+ MLX5_SET(destroy_cq_in, in, uid, cq->uid);
err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
if (err)
return err;
@@ -196,6 +199,7 @@ int mlx5_core_modify_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
u32 out[MLX5_ST_SZ_DW(modify_cq_out)] = {0};
MLX5_SET(modify_cq_in, in, opcode, MLX5_CMD_OP_MODIFY_CQ);
+ MLX5_SET(modify_cq_in, in, uid, cq->uid);
return mlx5_cmd_exec(dev, in, inlen, out, sizeof(out));
}
EXPORT_SYMBOL(mlx5_core_modify_cq);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/diag/fs_tracepoint.h b/drivers/net/ethernet/mellanox/mlx5/core/diag/fs_tracepoint.h
index 0240aee9189e..d027ce00c8ce 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/diag/fs_tracepoint.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/diag/fs_tracepoint.h
@@ -133,7 +133,7 @@ TRACE_EVENT(mlx5_fs_del_fg,
{MLX5_FLOW_CONTEXT_ACTION_DROP, "DROP"},\
{MLX5_FLOW_CONTEXT_ACTION_FWD_DEST, "FWD"},\
{MLX5_FLOW_CONTEXT_ACTION_COUNT, "CNT"},\
- {MLX5_FLOW_CONTEXT_ACTION_ENCAP, "ENCAP"},\
+ {MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT, "REFORMAT"},\
{MLX5_FLOW_CONTEXT_ACTION_DECAP, "DECAP"},\
{MLX5_FLOW_CONTEXT_ACTION_MOD_HDR, "MOD_HDR"},\
{MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH, "VLAN_PUSH"},\
@@ -252,10 +252,10 @@ TRACE_EVENT(mlx5_fs_add_rule,
memcpy(__entry->destination,
&rule->dest_attr,
sizeof(__entry->destination));
- if (rule->dest_attr.type & MLX5_FLOW_DESTINATION_TYPE_COUNTER &&
- rule->dest_attr.counter)
+ if (rule->dest_attr.type &
+ MLX5_FLOW_DESTINATION_TYPE_COUNTER)
__entry->counter_id =
- rule->dest_attr.counter->id;
+ rule->dest_attr.counter_id;
),
TP_printk("rule=%p fte=%p index=%u sw_action=<%s> [dst] %s\n",
__entry->rule, __entry->fte, __entry->index,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h
index db2cfcd21d43..d7fbd5b6ac95 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h
@@ -54,6 +54,7 @@
#include "en_stats.h"
#include "en/fs.h"
+extern const struct net_device_ops mlx5e_netdev_ops;
struct page_pool;
#define MLX5E_METADATA_ETHER_TYPE (0x8CE4)
@@ -172,6 +173,7 @@ static inline u16 mlx5_min_rx_wqes(int wq_type, u32 wq_size)
}
}
+/* Use this function to get max num channels (rxqs/txqs) only to create netdev */
static inline int mlx5e_get_max_num_channels(struct mlx5_core_dev *mdev)
{
return is_kdump_kernel() ?
@@ -180,6 +182,13 @@ static inline int mlx5e_get_max_num_channels(struct mlx5_core_dev *mdev)
MLX5E_MAX_NUM_CHANNELS);
}
+/* Use this function to get max num channels after netdev was created */
+static inline int mlx5e_get_netdev_max_channels(struct net_device *netdev)
+{
+ return min_t(unsigned int, netdev->num_rx_queues,
+ netdev->num_tx_queues);
+}
+
struct mlx5e_tx_wqe {
struct mlx5_wqe_ctrl_seg ctrl;
struct mlx5_wqe_eth_seg eth;
@@ -204,18 +213,12 @@ struct mlx5e_umr_wqe {
extern const char mlx5e_self_tests[][ETH_GSTRING_LEN];
-static const char mlx5e_priv_flags[][ETH_GSTRING_LEN] = {
- "rx_cqe_moder",
- "tx_cqe_moder",
- "rx_cqe_compress",
- "rx_striding_rq",
-};
-
enum mlx5e_priv_flag {
MLX5E_PFLAG_RX_CQE_BASED_MODER = (1 << 0),
MLX5E_PFLAG_TX_CQE_BASED_MODER = (1 << 1),
MLX5E_PFLAG_RX_CQE_COMPRESS = (1 << 2),
MLX5E_PFLAG_RX_STRIDING_RQ = (1 << 3),
+ MLX5E_PFLAG_RX_NO_CSUM_COMPLETE = (1 << 4),
};
#define MLX5E_SET_PFLAG(params, pflag, enable) \
@@ -297,6 +300,7 @@ struct mlx5e_dcbx_dp {
enum {
MLX5E_RQ_STATE_ENABLED,
MLX5E_RQ_STATE_AM,
+ MLX5E_RQ_STATE_NO_CSUM_COMPLETE,
};
struct mlx5e_cq {
@@ -677,7 +681,7 @@ struct mlx5e_priv {
struct work_struct update_carrier_work;
struct work_struct set_rx_mode_work;
struct work_struct tx_timeout_work;
- struct delayed_work update_stats_work;
+ struct work_struct update_stats_work;
struct mlx5_core_dev *mdev;
struct net_device *netdev;
@@ -702,7 +706,7 @@ struct mlx5e_priv {
};
struct mlx5e_profile {
- void (*init)(struct mlx5_core_dev *mdev,
+ int (*init)(struct mlx5_core_dev *mdev,
struct net_device *netdev,
const struct mlx5e_profile *profile, void *ppriv);
void (*cleanup)(struct mlx5e_priv *priv);
@@ -714,7 +718,6 @@ struct mlx5e_profile {
void (*disable)(struct mlx5e_priv *priv);
void (*update_stats)(struct mlx5e_priv *priv);
void (*update_carrier)(struct mlx5e_priv *priv);
- int (*max_nch)(struct mlx5_core_dev *mdev);
struct {
mlx5e_fp_handle_rx_cqe handle_rx_cqe;
mlx5e_fp_handle_rx_cqe handle_rx_cqe_mpwqe;
@@ -905,10 +908,16 @@ void mlx5e_destroy_mdev_resources(struct mlx5_core_dev *mdev);
int mlx5e_refresh_tirs(struct mlx5e_priv *priv, bool enable_uc_lb);
/* common netdev helpers */
+void mlx5e_create_q_counters(struct mlx5e_priv *priv);
+void mlx5e_destroy_q_counters(struct mlx5e_priv *priv);
+int mlx5e_open_drop_rq(struct mlx5e_priv *priv,
+ struct mlx5e_rq *drop_rq);
+void mlx5e_close_drop_rq(struct mlx5e_rq *drop_rq);
+
int mlx5e_create_indirect_rqt(struct mlx5e_priv *priv);
-int mlx5e_create_indirect_tirs(struct mlx5e_priv *priv);
-void mlx5e_destroy_indirect_tirs(struct mlx5e_priv *priv);
+int mlx5e_create_indirect_tirs(struct mlx5e_priv *priv, bool inner_ttc);
+void mlx5e_destroy_indirect_tirs(struct mlx5e_priv *priv, bool inner_ttc);
int mlx5e_create_direct_rqts(struct mlx5e_priv *priv);
void mlx5e_destroy_direct_rqts(struct mlx5e_priv *priv);
@@ -924,8 +933,8 @@ int mlx5e_create_tises(struct mlx5e_priv *priv);
void mlx5e_cleanup_nic_tx(struct mlx5e_priv *priv);
int mlx5e_close(struct net_device *netdev);
int mlx5e_open(struct net_device *netdev);
-void mlx5e_update_stats_work(struct work_struct *work);
+void mlx5e_queue_update_stats(struct mlx5e_priv *priv);
int mlx5e_bits_invert(unsigned long a, int size);
typedef int (*change_hw_mtu_cb)(struct mlx5e_priv *priv);
@@ -952,21 +961,32 @@ int mlx5e_ethtool_get_coalesce(struct mlx5e_priv *priv,
struct ethtool_coalesce *coal);
int mlx5e_ethtool_set_coalesce(struct mlx5e_priv *priv,
struct ethtool_coalesce *coal);
+u32 mlx5e_ethtool_get_rxfh_key_size(struct mlx5e_priv *priv);
+u32 mlx5e_ethtool_get_rxfh_indir_size(struct mlx5e_priv *priv);
int mlx5e_ethtool_get_ts_info(struct mlx5e_priv *priv,
struct ethtool_ts_info *info);
int mlx5e_ethtool_flash_device(struct mlx5e_priv *priv,
struct ethtool_flash *flash);
/* mlx5e generic netdev management API */
+int mlx5e_netdev_init(struct net_device *netdev,
+ struct mlx5e_priv *priv,
+ struct mlx5_core_dev *mdev,
+ const struct mlx5e_profile *profile,
+ void *ppriv);
+void mlx5e_netdev_cleanup(struct net_device *netdev, struct mlx5e_priv *priv);
struct net_device*
mlx5e_create_netdev(struct mlx5_core_dev *mdev, const struct mlx5e_profile *profile,
- void *ppriv);
+ int nch, void *ppriv);
int mlx5e_attach_netdev(struct mlx5e_priv *priv);
void mlx5e_detach_netdev(struct mlx5e_priv *priv);
void mlx5e_destroy_netdev(struct mlx5e_priv *priv);
void mlx5e_build_nic_params(struct mlx5_core_dev *mdev,
struct mlx5e_params *params,
u16 max_channels, u16 mtu);
+void mlx5e_build_rq_params(struct mlx5_core_dev *mdev,
+ struct mlx5e_params *params);
+void mlx5e_build_rss_params(struct mlx5e_params *params);
u8 mlx5e_params_calculate_tx_min_inline(struct mlx5_core_dev *mdev);
void mlx5e_rx_dim_work(struct work_struct *work);
void mlx5e_tx_dim_work(struct work_struct *work);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/fs.h b/drivers/net/ethernet/mellanox/mlx5/core/en/fs.h
index bbf69e859b78..1431232c9a09 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/fs.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/fs.h
@@ -16,6 +16,8 @@ struct mlx5e_tc_table {
DECLARE_HASHTABLE(mod_hdr_tbl, 8);
DECLARE_HASHTABLE(hairpin_tbl, 8);
+
+ struct notifier_block netdevice_nb;
};
struct mlx5e_flow_table {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/port.c b/drivers/net/ethernet/mellanox/mlx5/core/en/port.c
index 24e3b564964f..023dc4bccd28 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/port.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/port.c
@@ -235,3 +235,211 @@ out:
kfree(out);
return err;
}
+
+static u32 fec_supported_speeds[] = {
+ 10000,
+ 40000,
+ 25000,
+ 50000,
+ 56000,
+ 100000
+};
+
+#define MLX5E_FEC_SUPPORTED_SPEEDS ARRAY_SIZE(fec_supported_speeds)
+
+/* get/set FEC admin field for a given speed */
+static int mlx5e_fec_admin_field(u32 *pplm,
+ u8 *fec_policy,
+ bool write,
+ u32 speed)
+{
+ switch (speed) {
+ case 10000:
+ case 40000:
+ if (!write)
+ *fec_policy = MLX5_GET(pplm_reg, pplm,
+ fec_override_cap_10g_40g);
+ else
+ MLX5_SET(pplm_reg, pplm,
+ fec_override_admin_10g_40g, *fec_policy);
+ break;
+ case 25000:
+ if (!write)
+ *fec_policy = MLX5_GET(pplm_reg, pplm,
+ fec_override_admin_25g);
+ else
+ MLX5_SET(pplm_reg, pplm,
+ fec_override_admin_25g, *fec_policy);
+ break;
+ case 50000:
+ if (!write)
+ *fec_policy = MLX5_GET(pplm_reg, pplm,
+ fec_override_admin_50g);
+ else
+ MLX5_SET(pplm_reg, pplm,
+ fec_override_admin_50g, *fec_policy);
+ break;
+ case 56000:
+ if (!write)
+ *fec_policy = MLX5_GET(pplm_reg, pplm,
+ fec_override_admin_56g);
+ else
+ MLX5_SET(pplm_reg, pplm,
+ fec_override_admin_56g, *fec_policy);
+ break;
+ case 100000:
+ if (!write)
+ *fec_policy = MLX5_GET(pplm_reg, pplm,
+ fec_override_admin_100g);
+ else
+ MLX5_SET(pplm_reg, pplm,
+ fec_override_admin_100g, *fec_policy);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* returns FEC capabilities for a given speed */
+static int mlx5e_get_fec_cap_field(u32 *pplm,
+ u8 *fec_cap,
+ u32 speed)
+{
+ switch (speed) {
+ case 10000:
+ case 40000:
+ *fec_cap = MLX5_GET(pplm_reg, pplm,
+ fec_override_admin_10g_40g);
+ break;
+ case 25000:
+ *fec_cap = MLX5_GET(pplm_reg, pplm,
+ fec_override_cap_25g);
+ break;
+ case 50000:
+ *fec_cap = MLX5_GET(pplm_reg, pplm,
+ fec_override_cap_50g);
+ break;
+ case 56000:
+ *fec_cap = MLX5_GET(pplm_reg, pplm,
+ fec_override_cap_56g);
+ break;
+ case 100000:
+ *fec_cap = MLX5_GET(pplm_reg, pplm,
+ fec_override_cap_100g);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int mlx5e_get_fec_caps(struct mlx5_core_dev *dev, u8 *fec_caps)
+{
+ u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {};
+ u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
+ int sz = MLX5_ST_SZ_BYTES(pplm_reg);
+ u32 current_fec_speed;
+ int err;
+
+ if (!MLX5_CAP_GEN(dev, pcam_reg))
+ return -EOPNOTSUPP;
+
+ if (!MLX5_CAP_PCAM_REG(dev, pplm))
+ return -EOPNOTSUPP;
+
+ MLX5_SET(pplm_reg, in, local_port, 1);
+ err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0);
+ if (err)
+ return err;
+
+ err = mlx5e_port_linkspeed(dev, &current_fec_speed);
+ if (err)
+ return err;
+
+ return mlx5e_get_fec_cap_field(out, fec_caps, current_fec_speed);
+}
+
+int mlx5e_get_fec_mode(struct mlx5_core_dev *dev, u32 *fec_mode_active,
+ u8 *fec_configured_mode)
+{
+ u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {};
+ u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
+ int sz = MLX5_ST_SZ_BYTES(pplm_reg);
+ u32 link_speed;
+ int err;
+
+ if (!MLX5_CAP_GEN(dev, pcam_reg))
+ return -EOPNOTSUPP;
+
+ if (!MLX5_CAP_PCAM_REG(dev, pplm))
+ return -EOPNOTSUPP;
+
+ MLX5_SET(pplm_reg, in, local_port, 1);
+ err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0);
+ if (err)
+ return err;
+
+ *fec_mode_active = MLX5_GET(pplm_reg, out, fec_mode_active);
+
+ if (!fec_configured_mode)
+ return 0;
+
+ err = mlx5e_port_linkspeed(dev, &link_speed);
+ if (err)
+ return err;
+
+ return mlx5e_fec_admin_field(out, fec_configured_mode, 0, link_speed);
+}
+
+int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u8 fec_policy)
+{
+ bool fec_mode_not_supp_in_speed = false;
+ u8 no_fec_policy = BIT(MLX5E_FEC_NOFEC);
+ u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {};
+ u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
+ int sz = MLX5_ST_SZ_BYTES(pplm_reg);
+ u32 current_fec_speed;
+ u8 fec_caps = 0;
+ int err;
+ int i;
+
+ if (!MLX5_CAP_GEN(dev, pcam_reg))
+ return -EOPNOTSUPP;
+
+ if (!MLX5_CAP_PCAM_REG(dev, pplm))
+ return -EOPNOTSUPP;
+
+ MLX5_SET(pplm_reg, in, local_port, 1);
+ err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0);
+ if (err)
+ return err;
+
+ err = mlx5e_port_linkspeed(dev, &current_fec_speed);
+ if (err)
+ return err;
+
+ memset(in, 0, sz);
+ MLX5_SET(pplm_reg, in, local_port, 1);
+ for (i = 0; i < MLX5E_FEC_SUPPORTED_SPEEDS && !!fec_policy; i++) {
+ mlx5e_get_fec_cap_field(out, &fec_caps, fec_supported_speeds[i]);
+ /* policy supported for link speed */
+ if (!!(fec_caps & fec_policy)) {
+ mlx5e_fec_admin_field(in, &fec_policy, 1,
+ fec_supported_speeds[i]);
+ } else {
+ if (fec_supported_speeds[i] == current_fec_speed)
+ return -EOPNOTSUPP;
+ mlx5e_fec_admin_field(in, &no_fec_policy, 1,
+ fec_supported_speeds[i]);
+ fec_mode_not_supp_in_speed = true;
+ }
+ }
+
+ if (fec_mode_not_supp_in_speed)
+ mlx5_core_dbg(dev,
+ "FEC policy 0x%x is not supported for some speeds",
+ fec_policy);
+
+ return mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 1);
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/port.h b/drivers/net/ethernet/mellanox/mlx5/core/en/port.h
index f8cbd8194179..cd2160b8c9bf 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/port.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/port.h
@@ -45,4 +45,16 @@ int mlx5e_port_query_pbmc(struct mlx5_core_dev *mdev, void *out);
int mlx5e_port_set_pbmc(struct mlx5_core_dev *mdev, void *in);
int mlx5e_port_query_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer);
int mlx5e_port_set_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer);
+
+int mlx5e_get_fec_caps(struct mlx5_core_dev *dev, u8 *fec_caps);
+int mlx5e_get_fec_mode(struct mlx5_core_dev *dev, u32 *fec_mode_active,
+ u8 *fec_configured_mode);
+int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u8 fec_policy);
+
+enum {
+ MLX5E_FEC_NOFEC,
+ MLX5E_FEC_FIRECODE,
+ MLX5E_FEC_RS_528_514,
+};
+
#endif
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c b/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c
index 45cdde694d20..8657e0f26995 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c
@@ -543,8 +543,11 @@ static struct mlx5_flow_handle *arfs_add_rule(struct mlx5e_priv *priv,
rule = mlx5_add_flow_rules(ft, spec, &flow_act, &dest, 1);
if (IS_ERR(rule)) {
err = PTR_ERR(rule);
- netdev_err(priv->netdev, "%s: add rule(filter id=%d, rq idx=%d) failed, err=%d\n",
- __func__, arfs_rule->filter_id, arfs_rule->rxq, err);
+ priv->channel_stats[arfs_rule->rxq].rq.arfs_err++;
+ mlx5e_dbg(HW, priv,
+ "%s: add rule(filter id=%d, rq idx=%d, ip proto=0x%x) failed,err=%d\n",
+ __func__, arfs_rule->filter_id, arfs_rule->rxq,
+ tuple->ip_proto, err);
}
out:
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_common.c b/drivers/net/ethernet/mellanox/mlx5/core/en_common.c
index db3278cc052b..3078491cc0d0 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_common.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_common.c
@@ -153,7 +153,7 @@ int mlx5e_refresh_tirs(struct mlx5e_priv *priv, bool enable_uc_lb)
if (enable_uc_lb)
MLX5_SET(modify_tir_in, in, ctx.self_lb_block,
- MLX5_TIRC_SELF_LB_BLOCK_BLOCK_UNICAST_);
+ MLX5_TIRC_SELF_LB_BLOCK_BLOCK_UNICAST);
MLX5_SET(modify_tir_in, in, bitmask.self_lb_en, 1);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
index 98dd3e0ada72..3e770abfd802 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
@@ -135,6 +135,14 @@ void mlx5e_build_ptys2ethtool_map(void)
ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT);
}
+static const char mlx5e_priv_flags[][ETH_GSTRING_LEN] = {
+ "rx_cqe_moder",
+ "tx_cqe_moder",
+ "rx_cqe_compress",
+ "rx_striding_rq",
+ "rx_no_csum_complete",
+};
+
int mlx5e_ethtool_get_sset_count(struct mlx5e_priv *priv, int sset)
{
int i, num_stats = 0;
@@ -311,7 +319,7 @@ static int mlx5e_set_ringparam(struct net_device *dev,
void mlx5e_ethtool_get_channels(struct mlx5e_priv *priv,
struct ethtool_channels *ch)
{
- ch->max_combined = priv->profile->max_nch(priv->mdev);
+ ch->max_combined = mlx5e_get_netdev_max_channels(priv->netdev);
ch->combined_count = priv->channels.params.num_channels;
}
@@ -539,6 +547,70 @@ static void ptys2ethtool_adver_link(unsigned long *advertising_modes,
__ETHTOOL_LINK_MODE_MASK_NBITS);
}
+static const u32 pplm_fec_2_ethtool[] = {
+ [MLX5E_FEC_NOFEC] = ETHTOOL_FEC_OFF,
+ [MLX5E_FEC_FIRECODE] = ETHTOOL_FEC_BASER,
+ [MLX5E_FEC_RS_528_514] = ETHTOOL_FEC_RS,
+};
+
+static u32 pplm2ethtool_fec(u_long fec_mode, unsigned long size)
+{
+ int mode = 0;
+
+ if (!fec_mode)
+ return ETHTOOL_FEC_AUTO;
+
+ mode = find_first_bit(&fec_mode, size);
+
+ if (mode < ARRAY_SIZE(pplm_fec_2_ethtool))
+ return pplm_fec_2_ethtool[mode];
+
+ return 0;
+}
+
+/* we use ETHTOOL_FEC_* offset and apply it to ETHTOOL_LINK_MODE_FEC_*_BIT */
+static u32 ethtool_fec2ethtool_caps(u_long ethtool_fec_code)
+{
+ u32 offset;
+
+ offset = find_first_bit(&ethtool_fec_code, sizeof(u32));
+ offset -= ETHTOOL_FEC_OFF_BIT;
+ offset += ETHTOOL_LINK_MODE_FEC_NONE_BIT;
+
+ return offset;
+}
+
+static int get_fec_supported_advertised(struct mlx5_core_dev *dev,
+ struct ethtool_link_ksettings *link_ksettings)
+{
+ u_long fec_caps = 0;
+ u32 active_fec = 0;
+ u32 offset;
+ u32 bitn;
+ int err;
+
+ err = mlx5e_get_fec_caps(dev, (u8 *)&fec_caps);
+ if (err)
+ return (err == -EOPNOTSUPP) ? 0 : err;
+
+ err = mlx5e_get_fec_mode(dev, &active_fec, NULL);
+ if (err)
+ return err;
+
+ for_each_set_bit(bitn, &fec_caps, ARRAY_SIZE(pplm_fec_2_ethtool)) {
+ u_long ethtool_bitmask = pplm_fec_2_ethtool[bitn];
+
+ offset = ethtool_fec2ethtool_caps(ethtool_bitmask);
+ __set_bit(offset, link_ksettings->link_modes.supported);
+ }
+
+ active_fec = pplm2ethtool_fec(active_fec, sizeof(u32) * BITS_PER_BYTE);
+ offset = ethtool_fec2ethtool_caps(active_fec);
+ __set_bit(offset, link_ksettings->link_modes.advertising);
+
+ return 0;
+}
+
static void ptys2ethtool_supported_advertised_port(struct ethtool_link_ksettings *link_ksettings,
u32 eth_proto_cap,
u8 connector_type)
@@ -734,7 +806,7 @@ static int mlx5e_get_link_ksettings(struct net_device *netdev,
if (err) {
netdev_err(netdev, "%s: query port ptys failed: %d\n",
__func__, err);
- goto err_query_ptys;
+ goto err_query_regs;
}
eth_proto_cap = MLX5_GET(ptys_reg, out, eth_proto_capability);
@@ -770,11 +842,17 @@ static int mlx5e_get_link_ksettings(struct net_device *netdev,
AUTONEG_ENABLE;
ethtool_link_ksettings_add_link_mode(link_ksettings, supported,
Autoneg);
+
+ err = get_fec_supported_advertised(mdev, link_ksettings);
+ if (err)
+ netdev_dbg(netdev, "%s: FEC caps query failed: %d\n",
+ __func__, err);
+
if (!an_disable_admin)
ethtool_link_ksettings_add_link_mode(link_ksettings,
advertising, Autoneg);
-err_query_ptys:
+err_query_regs:
return err;
}
@@ -852,18 +930,30 @@ out:
return err;
}
+u32 mlx5e_ethtool_get_rxfh_key_size(struct mlx5e_priv *priv)
+{
+ return sizeof(priv->channels.params.toeplitz_hash_key);
+}
+
static u32 mlx5e_get_rxfh_key_size(struct net_device *netdev)
{
struct mlx5e_priv *priv = netdev_priv(netdev);
- return sizeof(priv->channels.params.toeplitz_hash_key);
+ return mlx5e_ethtool_get_rxfh_key_size(priv);
}
-static u32 mlx5e_get_rxfh_indir_size(struct net_device *netdev)
+u32 mlx5e_ethtool_get_rxfh_indir_size(struct mlx5e_priv *priv)
{
return MLX5E_INDIR_RQT_SIZE;
}
+static u32 mlx5e_get_rxfh_indir_size(struct net_device *netdev)
+{
+ struct mlx5e_priv *priv = netdev_priv(netdev);
+
+ return mlx5e_ethtool_get_rxfh_indir_size(priv);
+}
+
static int mlx5e_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
u8 *hfunc)
{
@@ -1257,6 +1347,58 @@ static int mlx5e_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
return mlx5_set_port_wol(mdev, mlx5_wol_mode);
}
+static int mlx5e_get_fecparam(struct net_device *netdev,
+ struct ethtool_fecparam *fecparam)
+{
+ struct mlx5e_priv *priv = netdev_priv(netdev);
+ struct mlx5_core_dev *mdev = priv->mdev;
+ u8 fec_configured = 0;
+ u32 fec_active = 0;
+ int err;
+
+ err = mlx5e_get_fec_mode(mdev, &fec_active, &fec_configured);
+
+ if (err)
+ return err;
+
+ fecparam->active_fec = pplm2ethtool_fec((u_long)fec_active,
+ sizeof(u32) * BITS_PER_BYTE);
+
+ if (!fecparam->active_fec)
+ return -EOPNOTSUPP;
+
+ fecparam->fec = pplm2ethtool_fec((u_long)fec_configured,
+ sizeof(u8) * BITS_PER_BYTE);
+
+ return 0;
+}
+
+static int mlx5e_set_fecparam(struct net_device *netdev,
+ struct ethtool_fecparam *fecparam)
+{
+ struct mlx5e_priv *priv = netdev_priv(netdev);
+ struct mlx5_core_dev *mdev = priv->mdev;
+ u8 fec_policy = 0;
+ int mode;
+ int err;
+
+ for (mode = 0; mode < ARRAY_SIZE(pplm_fec_2_ethtool); mode++) {
+ if (!(pplm_fec_2_ethtool[mode] & fecparam->fec))
+ continue;
+ fec_policy |= (1 << mode);
+ break;
+ }
+
+ err = mlx5e_set_fec_mode(mdev, fec_policy);
+
+ if (err)
+ return err;
+
+ mlx5_toggle_port_link(mdev);
+
+ return 0;
+}
+
static u32 mlx5e_get_msglevel(struct net_device *dev)
{
return ((struct mlx5e_priv *)netdev_priv(dev))->msglevel;
@@ -1512,6 +1654,27 @@ static int set_pflag_rx_striding_rq(struct net_device *netdev, bool enable)
return 0;
}
+static int set_pflag_rx_no_csum_complete(struct net_device *netdev, bool enable)
+{
+ struct mlx5e_priv *priv = netdev_priv(netdev);
+ struct mlx5e_channels *channels = &priv->channels;
+ struct mlx5e_channel *c;
+ int i;
+
+ if (!test_bit(MLX5E_STATE_OPENED, &priv->state))
+ return 0;
+
+ for (i = 0; i < channels->num; i++) {
+ c = channels->c[i];
+ if (enable)
+ __set_bit(MLX5E_RQ_STATE_NO_CSUM_COMPLETE, &c->rq.state);
+ else
+ __clear_bit(MLX5E_RQ_STATE_NO_CSUM_COMPLETE, &c->rq.state);
+ }
+
+ return 0;
+}
+
static int mlx5e_handle_pflag(struct net_device *netdev,
u32 wanted_flags,
enum mlx5e_priv_flag flag,
@@ -1563,6 +1726,12 @@ static int mlx5e_set_priv_flags(struct net_device *netdev, u32 pflags)
err = mlx5e_handle_pflag(netdev, pflags,
MLX5E_PFLAG_RX_STRIDING_RQ,
set_pflag_rx_striding_rq);
+ if (err)
+ goto out;
+
+ err = mlx5e_handle_pflag(netdev, pflags,
+ MLX5E_PFLAG_RX_NO_CSUM_COMPLETE,
+ set_pflag_rx_no_csum_complete);
out:
mutex_unlock(&priv->state_lock);
@@ -1652,4 +1821,6 @@ const struct ethtool_ops mlx5e_ethtool_ops = {
.self_test = mlx5e_self_test,
.get_msglevel = mlx5e_get_msglevel,
.set_msglevel = mlx5e_set_msglevel,
+ .get_fecparam = mlx5e_get_fecparam,
+ .set_fecparam = mlx5e_set_fecparam,
};
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c
index 41cde926cdab..c18dcebe1462 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c
@@ -131,14 +131,14 @@ set_ip4(void *headers_c, void *headers_v, __be32 ip4src_m,
if (ip4src_m) {
memcpy(MLX5E_FTE_ADDR_OF(headers_v, src_ipv4_src_ipv6.ipv4_layout.ipv4),
&ip4src_v, sizeof(ip4src_v));
- memset(MLX5E_FTE_ADDR_OF(headers_c, src_ipv4_src_ipv6.ipv4_layout.ipv4),
- 0xff, sizeof(ip4src_m));
+ memcpy(MLX5E_FTE_ADDR_OF(headers_c, src_ipv4_src_ipv6.ipv4_layout.ipv4),
+ &ip4src_m, sizeof(ip4src_m));
}
if (ip4dst_m) {
memcpy(MLX5E_FTE_ADDR_OF(headers_v, dst_ipv4_dst_ipv6.ipv4_layout.ipv4),
&ip4dst_v, sizeof(ip4dst_v));
- memset(MLX5E_FTE_ADDR_OF(headers_c, dst_ipv4_dst_ipv6.ipv4_layout.ipv4),
- 0xff, sizeof(ip4dst_m));
+ memcpy(MLX5E_FTE_ADDR_OF(headers_c, dst_ipv4_dst_ipv6.ipv4_layout.ipv4),
+ &ip4dst_m, sizeof(ip4dst_m));
}
MLX5E_FTE_SET(headers_c, ethertype, 0xffff);
@@ -173,11 +173,11 @@ set_tcp(void *headers_c, void *headers_v, __be16 psrc_m, __be16 psrc_v,
__be16 pdst_m, __be16 pdst_v)
{
if (psrc_m) {
- MLX5E_FTE_SET(headers_c, tcp_sport, 0xffff);
+ MLX5E_FTE_SET(headers_c, tcp_sport, ntohs(psrc_m));
MLX5E_FTE_SET(headers_v, tcp_sport, ntohs(psrc_v));
}
if (pdst_m) {
- MLX5E_FTE_SET(headers_c, tcp_dport, 0xffff);
+ MLX5E_FTE_SET(headers_c, tcp_dport, ntohs(pdst_m));
MLX5E_FTE_SET(headers_v, tcp_dport, ntohs(pdst_v));
}
@@ -190,12 +190,12 @@ set_udp(void *headers_c, void *headers_v, __be16 psrc_m, __be16 psrc_v,
__be16 pdst_m, __be16 pdst_v)
{
if (psrc_m) {
- MLX5E_FTE_SET(headers_c, udp_sport, 0xffff);
+ MLX5E_FTE_SET(headers_c, udp_sport, ntohs(psrc_m));
MLX5E_FTE_SET(headers_v, udp_sport, ntohs(psrc_v));
}
if (pdst_m) {
- MLX5E_FTE_SET(headers_c, udp_dport, 0xffff);
+ MLX5E_FTE_SET(headers_c, udp_dport, ntohs(pdst_m));
MLX5E_FTE_SET(headers_v, udp_dport, ntohs(pdst_v));
}
@@ -508,26 +508,14 @@ static int validate_tcpudp4(struct ethtool_rx_flow_spec *fs)
if (l4_mask->tos)
return -EINVAL;
- if (l4_mask->ip4src) {
- if (!all_ones(l4_mask->ip4src))
- return -EINVAL;
+ if (l4_mask->ip4src)
ntuples++;
- }
- if (l4_mask->ip4dst) {
- if (!all_ones(l4_mask->ip4dst))
- return -EINVAL;
+ if (l4_mask->ip4dst)
ntuples++;
- }
- if (l4_mask->psrc) {
- if (!all_ones(l4_mask->psrc))
- return -EINVAL;
+ if (l4_mask->psrc)
ntuples++;
- }
- if (l4_mask->pdst) {
- if (!all_ones(l4_mask->pdst))
- return -EINVAL;
+ if (l4_mask->pdst)
ntuples++;
- }
/* Flow is TCP/UDP */
return ++ntuples;
}
@@ -540,16 +528,10 @@ static int validate_ip4(struct ethtool_rx_flow_spec *fs)
if (l3_mask->l4_4_bytes || l3_mask->tos ||
fs->h_u.usr_ip4_spec.ip_ver != ETH_RX_NFC_IP4)
return -EINVAL;
- if (l3_mask->ip4src) {
- if (!all_ones(l3_mask->ip4src))
- return -EINVAL;
+ if (l3_mask->ip4src)
ntuples++;
- }
- if (l3_mask->ip4dst) {
- if (!all_ones(l3_mask->ip4dst))
- return -EINVAL;
+ if (l3_mask->ip4dst)
ntuples++;
- }
if (l3_mask->proto)
ntuples++;
/* Flow is IPv4 */
@@ -588,16 +570,10 @@ static int validate_tcpudp6(struct ethtool_rx_flow_spec *fs)
if (!ipv6_addr_any((struct in6_addr *)l4_mask->ip6dst))
ntuples++;
- if (l4_mask->psrc) {
- if (!all_ones(l4_mask->psrc))
- return -EINVAL;
+ if (l4_mask->psrc)
ntuples++;
- }
- if (l4_mask->pdst) {
- if (!all_ones(l4_mask->pdst))
- return -EINVAL;
+ if (l4_mask->pdst)
ntuples++;
- }
/* Flow is TCP/UDP */
return ++ntuples;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index 54118b77dc1f..1243edbedc9e 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -272,10 +272,9 @@ static void mlx5e_update_ndo_stats(struct mlx5e_priv *priv)
mlx5e_stats_grps[i].update_stats(priv);
}
-void mlx5e_update_stats_work(struct work_struct *work)
+static void mlx5e_update_stats_work(struct work_struct *work)
{
- struct delayed_work *dwork = to_delayed_work(work);
- struct mlx5e_priv *priv = container_of(dwork, struct mlx5e_priv,
+ struct mlx5e_priv *priv = container_of(work, struct mlx5e_priv,
update_stats_work);
mutex_lock(&priv->state_lock);
@@ -283,6 +282,17 @@ void mlx5e_update_stats_work(struct work_struct *work)
mutex_unlock(&priv->state_lock);
}
+void mlx5e_queue_update_stats(struct mlx5e_priv *priv)
+{
+ if (!priv->profile->update_stats)
+ return;
+
+ if (unlikely(test_bit(MLX5E_STATE_DESTROYING, &priv->state)))
+ return;
+
+ queue_work(priv->wq, &priv->update_stats_work);
+}
+
static void mlx5e_async_event(struct mlx5_core_dev *mdev, void *vpriv,
enum mlx5_dev_event event, unsigned long param)
{
@@ -929,6 +939,9 @@ static int mlx5e_open_rq(struct mlx5e_channel *c,
if (params->rx_dim_enabled)
__set_bit(MLX5E_RQ_STATE_AM, &c->rq.state);
+ if (params->pflags & MLX5E_PFLAG_RX_NO_CSUM_COMPLETE)
+ __set_bit(MLX5E_RQ_STATE_NO_CSUM_COMPLETE, &c->rq.state);
+
return 0;
err_destroy_rq:
@@ -1786,7 +1799,7 @@ static int mlx5e_open_sqs(struct mlx5e_channel *c,
struct mlx5e_channel_param *cparam)
{
struct mlx5e_priv *priv = c->priv;
- int err, tc, max_nch = priv->profile->max_nch(priv->mdev);
+ int err, tc, max_nch = mlx5e_get_netdev_max_channels(priv->netdev);
for (tc = 0; tc < params->num_tc; tc++) {
int txq_ix = c->ix + tc * max_nch;
@@ -2426,7 +2439,7 @@ int mlx5e_create_direct_rqts(struct mlx5e_priv *priv)
int err;
int ix;
- for (ix = 0; ix < priv->profile->max_nch(priv->mdev); ix++) {
+ for (ix = 0; ix < mlx5e_get_netdev_max_channels(priv->netdev); ix++) {
rqt = &priv->direct_tir[ix].rqt;
err = mlx5e_create_rqt(priv, 1 /*size */, rqt);
if (err)
@@ -2447,7 +2460,7 @@ void mlx5e_destroy_direct_rqts(struct mlx5e_priv *priv)
{
int i;
- for (i = 0; i < priv->profile->max_nch(priv->mdev); i++)
+ for (i = 0; i < mlx5e_get_netdev_max_channels(priv->netdev); i++)
mlx5e_destroy_rqt(priv, &priv->direct_tir[i].rqt);
}
@@ -2541,7 +2554,7 @@ static void mlx5e_redirect_rqts(struct mlx5e_priv *priv,
mlx5e_redirect_rqt(priv, rqtn, MLX5E_INDIR_RQT_SIZE, rrp);
}
- for (ix = 0; ix < priv->profile->max_nch(priv->mdev); ix++) {
+ for (ix = 0; ix < mlx5e_get_netdev_max_channels(priv->netdev); ix++) {
struct mlx5e_redirect_rqt_param direct_rrp = {
.is_rss = false,
{
@@ -2742,7 +2755,7 @@ static int mlx5e_modify_tirs_lro(struct mlx5e_priv *priv)
goto free_in;
}
- for (ix = 0; ix < priv->profile->max_nch(priv->mdev); ix++) {
+ for (ix = 0; ix < mlx5e_get_netdev_max_channels(priv->netdev); ix++) {
err = mlx5_core_modify_tir(mdev, priv->direct_tir[ix].tirn,
in, inlen);
if (err)
@@ -2842,7 +2855,7 @@ static void mlx5e_netdev_set_tcs(struct net_device *netdev)
static void mlx5e_build_tc2txq_maps(struct mlx5e_priv *priv)
{
- int max_nch = priv->profile->max_nch(priv->mdev);
+ int max_nch = mlx5e_get_netdev_max_channels(priv->netdev);
int i, tc;
for (i = 0; i < max_nch; i++)
@@ -2954,9 +2967,7 @@ int mlx5e_open_locked(struct net_device *netdev)
if (priv->profile->update_carrier)
priv->profile->update_carrier(priv);
- if (priv->profile->update_stats)
- queue_delayed_work(priv->wq, &priv->update_stats_work, 0);
-
+ mlx5e_queue_update_stats(priv);
return 0;
err_clear_state_opened_flag:
@@ -3049,8 +3060,8 @@ static int mlx5e_alloc_drop_cq(struct mlx5_core_dev *mdev,
return mlx5e_alloc_cq_common(mdev, param, cq);
}
-static int mlx5e_open_drop_rq(struct mlx5e_priv *priv,
- struct mlx5e_rq *drop_rq)
+int mlx5e_open_drop_rq(struct mlx5e_priv *priv,
+ struct mlx5e_rq *drop_rq)
{
struct mlx5_core_dev *mdev = priv->mdev;
struct mlx5e_cq_param cq_param = {};
@@ -3094,7 +3105,7 @@ err_free_cq:
return err;
}
-static void mlx5e_close_drop_rq(struct mlx5e_rq *drop_rq)
+void mlx5e_close_drop_rq(struct mlx5e_rq *drop_rq)
{
mlx5e_destroy_rq(drop_rq);
mlx5e_free_rq(drop_rq);
@@ -3175,7 +3186,7 @@ static void mlx5e_build_direct_tir_ctx(struct mlx5e_priv *priv, u32 rqtn, u32 *t
MLX5_SET(tirc, tirc, rx_hash_fn, MLX5_RX_HASH_FN_INVERTED_XOR8);
}
-int mlx5e_create_indirect_tirs(struct mlx5e_priv *priv)
+int mlx5e_create_indirect_tirs(struct mlx5e_priv *priv, bool inner_ttc)
{
struct mlx5e_tir *tir;
void *tirc;
@@ -3202,7 +3213,7 @@ int mlx5e_create_indirect_tirs(struct mlx5e_priv *priv)
}
}
- if (!mlx5e_tunnel_inner_ft_supported(priv->mdev))
+ if (!inner_ttc || !mlx5e_tunnel_inner_ft_supported(priv->mdev))
goto out;
for (i = 0; i < MLX5E_NUM_INDIR_TIRS; i++) {
@@ -3236,7 +3247,7 @@ err_destroy_inner_tirs:
int mlx5e_create_direct_tirs(struct mlx5e_priv *priv)
{
- int nch = priv->profile->max_nch(priv->mdev);
+ int nch = mlx5e_get_netdev_max_channels(priv->netdev);
struct mlx5e_tir *tir;
void *tirc;
int inlen;
@@ -3273,14 +3284,14 @@ err_destroy_ch_tirs:
return err;
}
-void mlx5e_destroy_indirect_tirs(struct mlx5e_priv *priv)
+void mlx5e_destroy_indirect_tirs(struct mlx5e_priv *priv, bool inner_ttc)
{
int i;
for (i = 0; i < MLX5E_NUM_INDIR_TIRS; i++)
mlx5e_destroy_tir(priv->mdev, &priv->indir_tir[i]);
- if (!mlx5e_tunnel_inner_ft_supported(priv->mdev))
+ if (!inner_ttc || !mlx5e_tunnel_inner_ft_supported(priv->mdev))
return;
for (i = 0; i < MLX5E_NUM_INDIR_TIRS; i++)
@@ -3289,7 +3300,7 @@ void mlx5e_destroy_indirect_tirs(struct mlx5e_priv *priv)
void mlx5e_destroy_direct_tirs(struct mlx5e_priv *priv)
{
- int nch = priv->profile->max_nch(priv->mdev);
+ int nch = mlx5e_get_netdev_max_channels(priv->netdev);
int i;
for (i = 0; i < nch; i++)
@@ -3381,9 +3392,6 @@ static int mlx5e_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
{
struct mlx5e_priv *priv = cb_priv;
- if (!tc_cls_can_offload_and_chain0(priv->netdev, type_data))
- return -EOPNOTSUPP;
-
switch (type) {
case TC_SETUP_CLSFLOWER:
return mlx5e_setup_tc_cls_flower(priv, type_data, MLX5E_TC_INGRESS);
@@ -3438,7 +3446,7 @@ mlx5e_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats)
struct mlx5e_pport_stats *pstats = &priv->stats.pport;
/* update HW stats in background for next time */
- queue_delayed_work(priv->wq, &priv->update_stats_work, 0);
+ mlx5e_queue_update_stats(priv);
if (mlx5e_is_uplink_rep(priv)) {
stats->rx_packets = PPORT_802_3_GET(pstats, a_frames_received_ok);
@@ -4315,7 +4323,7 @@ static int mlx5e_xdp(struct net_device *dev, struct netdev_bpf *xdp)
}
}
-static const struct net_device_ops mlx5e_netdev_ops = {
+const struct net_device_ops mlx5e_netdev_ops = {
.ndo_open = mlx5e_open,
.ndo_stop = mlx5e_close,
.ndo_start_xmit = mlx5e_xmit,
@@ -4480,6 +4488,31 @@ static u32 mlx5e_choose_lro_timeout(struct mlx5_core_dev *mdev, u32 wanted_timeo
return MLX5_CAP_ETH(mdev, lro_timer_supported_periods[i]);
}
+void mlx5e_build_rq_params(struct mlx5_core_dev *mdev,
+ struct mlx5e_params *params)
+{
+ /* Prefer Striding RQ, unless any of the following holds:
+ * - Striding RQ configuration is not possible/supported.
+ * - Slow PCI heuristic.
+ * - Legacy RQ would use linear SKB while Striding RQ would use non-linear.
+ */
+ if (!slow_pci_heuristic(mdev) &&
+ mlx5e_striding_rq_possible(mdev, params) &&
+ (mlx5e_rx_mpwqe_is_linear_skb(mdev, params) ||
+ !mlx5e_rx_is_linear_skb(mdev, params)))
+ MLX5E_SET_PFLAG(params, MLX5E_PFLAG_RX_STRIDING_RQ, true);
+ mlx5e_set_rq_type(mdev, params);
+ mlx5e_init_rq_type_params(mdev, params);
+}
+
+void mlx5e_build_rss_params(struct mlx5e_params *params)
+{
+ params->rss_hfunc = ETH_RSS_HASH_XOR;
+ netdev_rss_key_fill(params->toeplitz_hash_key, sizeof(params->toeplitz_hash_key));
+ mlx5e_build_default_indir_rqt(params->indirection_rqt,
+ MLX5E_INDIR_RQT_SIZE, params->num_channels);
+}
+
void mlx5e_build_nic_params(struct mlx5_core_dev *mdev,
struct mlx5e_params *params,
u16 max_channels, u16 mtu)
@@ -4503,20 +4536,10 @@ void mlx5e_build_nic_params(struct mlx5_core_dev *mdev,
params->rx_cqe_compress_def = slow_pci_heuristic(mdev);
MLX5E_SET_PFLAG(params, MLX5E_PFLAG_RX_CQE_COMPRESS, params->rx_cqe_compress_def);
+ MLX5E_SET_PFLAG(params, MLX5E_PFLAG_RX_NO_CSUM_COMPLETE, false);
/* RQ */
- /* Prefer Striding RQ, unless any of the following holds:
- * - Striding RQ configuration is not possible/supported.
- * - Slow PCI heuristic.
- * - Legacy RQ would use linear SKB while Striding RQ would use non-linear.
- */
- if (!slow_pci_heuristic(mdev) &&
- mlx5e_striding_rq_possible(mdev, params) &&
- (mlx5e_rx_mpwqe_is_linear_skb(mdev, params) ||
- !mlx5e_rx_is_linear_skb(mdev, params)))
- MLX5E_SET_PFLAG(params, MLX5E_PFLAG_RX_STRIDING_RQ, true);
- mlx5e_set_rq_type(mdev, params);
- mlx5e_init_rq_type_params(mdev, params);
+ mlx5e_build_rq_params(mdev, params);
/* HW LRO */
@@ -4539,37 +4562,7 @@ void mlx5e_build_nic_params(struct mlx5_core_dev *mdev,
params->tx_min_inline_mode = mlx5e_params_calculate_tx_min_inline(mdev);
/* RSS */
- params->rss_hfunc = ETH_RSS_HASH_XOR;
- netdev_rss_key_fill(params->toeplitz_hash_key, sizeof(params->toeplitz_hash_key));
- mlx5e_build_default_indir_rqt(params->indirection_rqt,
- MLX5E_INDIR_RQT_SIZE, max_channels);
-}
-
-static void mlx5e_build_nic_netdev_priv(struct mlx5_core_dev *mdev,
- struct net_device *netdev,
- const struct mlx5e_profile *profile,
- void *ppriv)
-{
- struct mlx5e_priv *priv = netdev_priv(netdev);
-
- priv->mdev = mdev;
- priv->netdev = netdev;
- priv->profile = profile;
- priv->ppriv = ppriv;
- priv->msglevel = MLX5E_MSG_LEVEL;
- priv->max_opened_tc = 1;
-
- mlx5e_build_nic_params(mdev, &priv->channels.params,
- profile->max_nch(mdev), netdev->mtu);
-
- mutex_init(&priv->state_lock);
-
- INIT_WORK(&priv->update_carrier_work, mlx5e_update_carrier_work);
- INIT_WORK(&priv->set_rx_mode_work, mlx5e_set_rx_mode_work);
- INIT_WORK(&priv->tx_timeout_work, mlx5e_tx_timeout_work);
- INIT_DELAYED_WORK(&priv->update_stats_work, mlx5e_update_stats_work);
-
- mlx5e_timestamp_init(priv);
+ mlx5e_build_rss_params(params);
}
static void mlx5e_set_netdev_dev_addr(struct net_device *netdev)
@@ -4707,7 +4700,7 @@ static void mlx5e_build_nic_netdev(struct net_device *netdev)
mlx5e_tls_build_netdev(priv);
}
-static void mlx5e_create_q_counters(struct mlx5e_priv *priv)
+void mlx5e_create_q_counters(struct mlx5e_priv *priv)
{
struct mlx5_core_dev *mdev = priv->mdev;
int err;
@@ -4725,7 +4718,7 @@ static void mlx5e_create_q_counters(struct mlx5e_priv *priv)
}
}
-static void mlx5e_destroy_q_counters(struct mlx5e_priv *priv)
+void mlx5e_destroy_q_counters(struct mlx5e_priv *priv)
{
if (priv->q_counter)
mlx5_core_dealloc_q_counter(priv->mdev, priv->q_counter);
@@ -4734,15 +4727,23 @@ static void mlx5e_destroy_q_counters(struct mlx5e_priv *priv)
mlx5_core_dealloc_q_counter(priv->mdev, priv->drop_rq_q_counter);
}
-static void mlx5e_nic_init(struct mlx5_core_dev *mdev,
- struct net_device *netdev,
- const struct mlx5e_profile *profile,
- void *ppriv)
+static int mlx5e_nic_init(struct mlx5_core_dev *mdev,
+ struct net_device *netdev,
+ const struct mlx5e_profile *profile,
+ void *ppriv)
{
struct mlx5e_priv *priv = netdev_priv(netdev);
int err;
- mlx5e_build_nic_netdev_priv(mdev, netdev, profile, ppriv);
+ err = mlx5e_netdev_init(netdev, priv, mdev, profile, ppriv);
+ if (err)
+ return err;
+
+ mlx5e_build_nic_params(mdev, &priv->channels.params,
+ mlx5e_get_netdev_max_channels(netdev), netdev->mtu);
+
+ mlx5e_timestamp_init(priv);
+
err = mlx5e_ipsec_init(priv);
if (err)
mlx5_core_err(mdev, "IPSec initialization failed, %d\n", err);
@@ -4751,12 +4752,15 @@ static void mlx5e_nic_init(struct mlx5_core_dev *mdev,
mlx5_core_err(mdev, "TLS initialization failed, %d\n", err);
mlx5e_build_nic_netdev(netdev);
mlx5e_build_tc2txq_maps(priv);
+
+ return 0;
}
static void mlx5e_nic_cleanup(struct mlx5e_priv *priv)
{
mlx5e_tls_cleanup(priv);
mlx5e_ipsec_cleanup(priv);
+ mlx5e_netdev_cleanup(priv->netdev, priv);
}
static int mlx5e_init_nic_rx(struct mlx5e_priv *priv)
@@ -4764,15 +4768,23 @@ static int mlx5e_init_nic_rx(struct mlx5e_priv *priv)
struct mlx5_core_dev *mdev = priv->mdev;
int err;
+ mlx5e_create_q_counters(priv);
+
+ err = mlx5e_open_drop_rq(priv, &priv->drop_rq);
+ if (err) {
+ mlx5_core_err(mdev, "open drop rq failed, %d\n", err);
+ goto err_destroy_q_counters;
+ }
+
err = mlx5e_create_indirect_rqt(priv);
if (err)
- return err;
+ goto err_close_drop_rq;
err = mlx5e_create_direct_rqts(priv);
if (err)
goto err_destroy_indirect_rqts;
- err = mlx5e_create_indirect_tirs(priv);
+ err = mlx5e_create_indirect_tirs(priv, true);
if (err)
goto err_destroy_direct_rqts;
@@ -4797,11 +4809,15 @@ err_destroy_flow_steering:
err_destroy_direct_tirs:
mlx5e_destroy_direct_tirs(priv);
err_destroy_indirect_tirs:
- mlx5e_destroy_indirect_tirs(priv);
+ mlx5e_destroy_indirect_tirs(priv, true);
err_destroy_direct_rqts:
mlx5e_destroy_direct_rqts(priv);
err_destroy_indirect_rqts:
mlx5e_destroy_rqt(priv, &priv->indir_rqt);
+err_close_drop_rq:
+ mlx5e_close_drop_rq(&priv->drop_rq);
+err_destroy_q_counters:
+ mlx5e_destroy_q_counters(priv);
return err;
}
@@ -4810,9 +4826,11 @@ static void mlx5e_cleanup_nic_rx(struct mlx5e_priv *priv)
mlx5e_tc_nic_cleanup(priv);
mlx5e_destroy_flow_steering(priv);
mlx5e_destroy_direct_tirs(priv);
- mlx5e_destroy_indirect_tirs(priv);
+ mlx5e_destroy_indirect_tirs(priv, true);
mlx5e_destroy_direct_rqts(priv);
mlx5e_destroy_rqt(priv, &priv->indir_rqt);
+ mlx5e_close_drop_rq(&priv->drop_rq);
+ mlx5e_destroy_q_counters(priv);
}
static int mlx5e_init_nic_tx(struct mlx5e_priv *priv)
@@ -4905,7 +4923,6 @@ static const struct mlx5e_profile mlx5e_nic_profile = {
.enable = mlx5e_nic_enable,
.disable = mlx5e_nic_disable,
.update_stats = mlx5e_update_ndo_stats,
- .max_nch = mlx5e_get_max_num_channels,
.update_carrier = mlx5e_update_carrier,
.rx_handlers.handle_rx_cqe = mlx5e_handle_rx_cqe,
.rx_handlers.handle_rx_cqe_mpwqe = mlx5e_handle_rx_cqe_mpwrq,
@@ -4914,13 +4931,53 @@ static const struct mlx5e_profile mlx5e_nic_profile = {
/* mlx5e generic netdev management API (move to en_common.c) */
+/* mlx5e_netdev_init/cleanup must be called from profile->init/cleanup callbacks */
+int mlx5e_netdev_init(struct net_device *netdev,
+ struct mlx5e_priv *priv,
+ struct mlx5_core_dev *mdev,
+ const struct mlx5e_profile *profile,
+ void *ppriv)
+{
+ /* priv init */
+ priv->mdev = mdev;
+ priv->netdev = netdev;
+ priv->profile = profile;
+ priv->ppriv = ppriv;
+ priv->msglevel = MLX5E_MSG_LEVEL;
+ priv->max_opened_tc = 1;
+
+ mutex_init(&priv->state_lock);
+ INIT_WORK(&priv->update_carrier_work, mlx5e_update_carrier_work);
+ INIT_WORK(&priv->set_rx_mode_work, mlx5e_set_rx_mode_work);
+ INIT_WORK(&priv->tx_timeout_work, mlx5e_tx_timeout_work);
+ INIT_WORK(&priv->update_stats_work, mlx5e_update_stats_work);
+
+ priv->wq = create_singlethread_workqueue("mlx5e");
+ if (!priv->wq)
+ return -ENOMEM;
+
+ /* netdev init */
+ netif_carrier_off(netdev);
+
+#ifdef CONFIG_MLX5_EN_ARFS
+ netdev->rx_cpu_rmap = mdev->rmap;
+#endif
+
+ return 0;
+}
+
+void mlx5e_netdev_cleanup(struct net_device *netdev, struct mlx5e_priv *priv)
+{
+ destroy_workqueue(priv->wq);
+}
+
struct net_device *mlx5e_create_netdev(struct mlx5_core_dev *mdev,
const struct mlx5e_profile *profile,
+ int nch,
void *ppriv)
{
- int nch = profile->max_nch(mdev);
struct net_device *netdev;
- struct mlx5e_priv *priv;
+ int err;
netdev = alloc_etherdev_mqs(sizeof(struct mlx5e_priv),
nch * profile->max_tc,
@@ -4930,25 +4987,15 @@ struct net_device *mlx5e_create_netdev(struct mlx5_core_dev *mdev,
return NULL;
}
-#ifdef CONFIG_MLX5_EN_ARFS
- netdev->rx_cpu_rmap = mdev->rmap;
-#endif
-
- profile->init(mdev, netdev, profile, ppriv);
-
- netif_carrier_off(netdev);
-
- priv = netdev_priv(netdev);
-
- priv->wq = create_singlethread_workqueue("mlx5e");
- if (!priv->wq)
- goto err_cleanup_nic;
+ err = profile->init(mdev, netdev, profile, ppriv);
+ if (err) {
+ mlx5_core_err(mdev, "failed to init mlx5e profile %d\n", err);
+ goto err_free_netdev;
+ }
return netdev;
-err_cleanup_nic:
- if (profile->cleanup)
- profile->cleanup(priv);
+err_free_netdev:
free_netdev(netdev);
return NULL;
@@ -4956,7 +5003,6 @@ err_cleanup_nic:
int mlx5e_attach_netdev(struct mlx5e_priv *priv)
{
- struct mlx5_core_dev *mdev = priv->mdev;
const struct mlx5e_profile *profile;
int err;
@@ -4967,28 +5013,16 @@ int mlx5e_attach_netdev(struct mlx5e_priv *priv)
if (err)
goto out;
- mlx5e_create_q_counters(priv);
-
- err = mlx5e_open_drop_rq(priv, &priv->drop_rq);
- if (err) {
- mlx5_core_err(mdev, "open drop rq failed, %d\n", err);
- goto err_destroy_q_counters;
- }
-
err = profile->init_rx(priv);
if (err)
- goto err_close_drop_rq;
+ goto err_cleanup_tx;
if (profile->enable)
profile->enable(priv);
return 0;
-err_close_drop_rq:
- mlx5e_close_drop_rq(&priv->drop_rq);
-
-err_destroy_q_counters:
- mlx5e_destroy_q_counters(priv);
+err_cleanup_tx:
profile->cleanup_tx(priv);
out:
@@ -5006,10 +5040,8 @@ void mlx5e_detach_netdev(struct mlx5e_priv *priv)
flush_workqueue(priv->wq);
profile->cleanup_rx(priv);
- mlx5e_close_drop_rq(&priv->drop_rq);
- mlx5e_destroy_q_counters(priv);
profile->cleanup_tx(priv);
- cancel_delayed_work_sync(&priv->update_stats_work);
+ cancel_work_sync(&priv->update_stats_work);
}
void mlx5e_destroy_netdev(struct mlx5e_priv *priv)
@@ -5017,7 +5049,6 @@ void mlx5e_destroy_netdev(struct mlx5e_priv *priv)
const struct mlx5e_profile *profile = priv->profile;
struct net_device *netdev = priv->netdev;
- destroy_workqueue(priv->wq);
if (profile->cleanup)
profile->cleanup(priv);
free_netdev(netdev);
@@ -5066,6 +5097,7 @@ static void *mlx5e_add(struct mlx5_core_dev *mdev)
void *rpriv = NULL;
void *priv;
int err;
+ int nch;
err = mlx5e_check_required_hca_cap(mdev);
if (err)
@@ -5081,7 +5113,8 @@ static void *mlx5e_add(struct mlx5_core_dev *mdev)
}
#endif
- netdev = mlx5e_create_netdev(mdev, &mlx5e_nic_profile, rpriv);
+ nch = mlx5e_get_max_num_channels(mdev);
+ netdev = mlx5e_create_netdev(mdev, &mlx5e_nic_profile, nch, rpriv);
if (!netdev) {
mlx5_core_err(mdev, "mlx5e_create_netdev failed\n");
goto err_free_rpriv;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
index c9cc9747d21d..c3c657548824 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
@@ -46,8 +46,6 @@
#define MLX5E_REP_PARAMS_LOG_SQ_SIZE \
max(0x6, MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE)
-#define MLX5E_REP_PARAMS_LOG_RQ_SIZE \
- max(0x6, MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE)
static const char mlx5e_rep_driver_name[] = "mlx5e_rep";
@@ -182,12 +180,108 @@ static int mlx5e_rep_get_sset_count(struct net_device *dev, int sset)
}
}
+static void mlx5e_rep_get_ringparam(struct net_device *dev,
+ struct ethtool_ringparam *param)
+{
+ struct mlx5e_priv *priv = netdev_priv(dev);
+
+ mlx5e_ethtool_get_ringparam(priv, param);
+}
+
+static int mlx5e_rep_set_ringparam(struct net_device *dev,
+ struct ethtool_ringparam *param)
+{
+ struct mlx5e_priv *priv = netdev_priv(dev);
+
+ return mlx5e_ethtool_set_ringparam(priv, param);
+}
+
+static int mlx5e_replace_rep_vport_rx_rule(struct mlx5e_priv *priv,
+ struct mlx5_flow_destination *dest)
+{
+ struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
+ struct mlx5e_rep_priv *rpriv = priv->ppriv;
+ struct mlx5_eswitch_rep *rep = rpriv->rep;
+ struct mlx5_flow_handle *flow_rule;
+
+ flow_rule = mlx5_eswitch_create_vport_rx_rule(esw,
+ rep->vport,
+ dest);
+ if (IS_ERR(flow_rule))
+ return PTR_ERR(flow_rule);
+
+ mlx5_del_flow_rules(rpriv->vport_rx_rule);
+ rpriv->vport_rx_rule = flow_rule;
+ return 0;
+}
+
+static void mlx5e_rep_get_channels(struct net_device *dev,
+ struct ethtool_channels *ch)
+{
+ struct mlx5e_priv *priv = netdev_priv(dev);
+
+ mlx5e_ethtool_get_channels(priv, ch);
+}
+
+static int mlx5e_rep_set_channels(struct net_device *dev,
+ struct ethtool_channels *ch)
+{
+ struct mlx5e_priv *priv = netdev_priv(dev);
+ u16 curr_channels_amount = priv->channels.params.num_channels;
+ u32 new_channels_amount = ch->combined_count;
+ struct mlx5_flow_destination new_dest;
+ int err = 0;
+
+ err = mlx5e_ethtool_set_channels(priv, ch);
+ if (err)
+ return err;
+
+ if (curr_channels_amount == 1 && new_channels_amount > 1) {
+ new_dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
+ new_dest.ft = priv->fs.ttc.ft.t;
+ } else if (new_channels_amount == 1 && curr_channels_amount > 1) {
+ new_dest.type = MLX5_FLOW_DESTINATION_TYPE_TIR;
+ new_dest.tir_num = priv->direct_tir[0].tirn;
+ } else {
+ return 0;
+ }
+
+ err = mlx5e_replace_rep_vport_rx_rule(priv, &new_dest);
+ if (err) {
+ netdev_warn(priv->netdev, "Failed to update vport rx rule, when going from (%d) channels to (%d) channels\n",
+ curr_channels_amount, new_channels_amount);
+ return err;
+ }
+
+ return 0;
+}
+
+static u32 mlx5e_rep_get_rxfh_key_size(struct net_device *netdev)
+{
+ struct mlx5e_priv *priv = netdev_priv(netdev);
+
+ return mlx5e_ethtool_get_rxfh_key_size(priv);
+}
+
+static u32 mlx5e_rep_get_rxfh_indir_size(struct net_device *netdev)
+{
+ struct mlx5e_priv *priv = netdev_priv(netdev);
+
+ return mlx5e_ethtool_get_rxfh_indir_size(priv);
+}
+
static const struct ethtool_ops mlx5e_rep_ethtool_ops = {
.get_drvinfo = mlx5e_rep_get_drvinfo,
.get_link = ethtool_op_get_link,
.get_strings = mlx5e_rep_get_strings,
.get_sset_count = mlx5e_rep_get_sset_count,
.get_ethtool_stats = mlx5e_rep_get_ethtool_stats,
+ .get_ringparam = mlx5e_rep_get_ringparam,
+ .set_ringparam = mlx5e_rep_set_ringparam,
+ .get_channels = mlx5e_rep_get_channels,
+ .set_channels = mlx5e_rep_set_channels,
+ .get_rxfh_key_size = mlx5e_rep_get_rxfh_key_size,
+ .get_rxfh_indir_size = mlx5e_rep_get_rxfh_indir_size,
};
int mlx5e_attr_get(struct net_device *dev, struct switchdev_attr *attr)
@@ -759,9 +853,6 @@ static int mlx5e_rep_setup_tc_cb_egdev(enum tc_setup_type type, void *type_data,
{
struct mlx5e_priv *priv = cb_priv;
- if (!tc_cls_can_offload_and_chain0(priv->netdev, type_data))
- return -EOPNOTSUPP;
-
switch (type) {
case TC_SETUP_CLSFLOWER:
return mlx5e_rep_setup_tc_cls_flower(priv, type_data, MLX5E_TC_EGRESS);
@@ -775,9 +866,6 @@ static int mlx5e_rep_setup_tc_cb(enum tc_setup_type type, void *type_data,
{
struct mlx5e_priv *priv = cb_priv;
- if (!tc_cls_can_offload_and_chain0(priv->netdev, type_data))
- return -EOPNOTSUPP;
-
switch (type) {
case TC_SETUP_CLSFLOWER:
return mlx5e_rep_setup_tc_cls_flower(priv, type_data, MLX5E_TC_INGRESS);
@@ -898,8 +986,7 @@ mlx5e_rep_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats)
struct mlx5e_priv *priv = netdev_priv(dev);
/* update HW stats in background for next time */
- queue_delayed_work(priv->wq, &priv->update_stats_work, 0);
-
+ mlx5e_queue_update_stats(priv);
memcpy(stats, &priv->stats.vf_vport, sizeof(*stats));
}
@@ -934,16 +1021,20 @@ static void mlx5e_build_rep_params(struct mlx5_core_dev *mdev,
params->hard_mtu = MLX5E_ETH_HARD_MTU;
params->sw_mtu = mtu;
params->log_sq_size = MLX5E_REP_PARAMS_LOG_SQ_SIZE;
- params->rq_wq_type = MLX5_WQ_TYPE_CYCLIC;
- params->log_rq_mtu_frames = MLX5E_REP_PARAMS_LOG_RQ_SIZE;
+ /* RQ */
+ mlx5e_build_rq_params(mdev, params);
+
+ /* CQ moderation params */
params->rx_dim_enabled = MLX5_CAP_GEN(mdev, cq_moderation);
mlx5e_set_rx_cq_mode_params(params, cq_period_mode);
params->num_tc = 1;
- params->lro_wqe_sz = MLX5E_PARAMS_DEFAULT_LRO_WQE_SZ;
mlx5_query_min_inline(mdev, &params->tx_min_inline_mode);
+
+ /* RSS */
+ mlx5e_build_rss_params(params);
}
static void mlx5e_build_rep_netdev(struct net_device *netdev)
@@ -963,6 +1054,16 @@ static void mlx5e_build_rep_netdev(struct net_device *netdev)
netdev->features |= NETIF_F_VLAN_CHALLENGED | NETIF_F_HW_TC | NETIF_F_NETNS_LOCAL;
netdev->hw_features |= NETIF_F_HW_TC;
+ netdev->hw_features |= NETIF_F_SG;
+ netdev->hw_features |= NETIF_F_IP_CSUM;
+ netdev->hw_features |= NETIF_F_IPV6_CSUM;
+ netdev->hw_features |= NETIF_F_GRO;
+ netdev->hw_features |= NETIF_F_TSO;
+ netdev->hw_features |= NETIF_F_TSO6;
+ netdev->hw_features |= NETIF_F_RXCSUM;
+
+ netdev->features |= netdev->hw_features;
+
eth_hw_addr_random(netdev);
netdev->min_mtu = ETH_MIN_MTU;
@@ -970,63 +1071,127 @@ static void mlx5e_build_rep_netdev(struct net_device *netdev)
netdev->max_mtu = MLX5E_HW2SW_MTU(&priv->channels.params, max_mtu);
}
-static void mlx5e_init_rep(struct mlx5_core_dev *mdev,
- struct net_device *netdev,
- const struct mlx5e_profile *profile,
- void *ppriv)
+static int mlx5e_init_rep(struct mlx5_core_dev *mdev,
+ struct net_device *netdev,
+ const struct mlx5e_profile *profile,
+ void *ppriv)
{
struct mlx5e_priv *priv = netdev_priv(netdev);
+ int err;
- priv->mdev = mdev;
- priv->netdev = netdev;
- priv->profile = profile;
- priv->ppriv = ppriv;
-
- mutex_init(&priv->state_lock);
+ err = mlx5e_netdev_init(netdev, priv, mdev, profile, ppriv);
+ if (err)
+ return err;
- INIT_DELAYED_WORK(&priv->update_stats_work, mlx5e_update_stats_work);
- priv->channels.params.num_channels = profile->max_nch(mdev);
+ priv->channels.params.num_channels =
+ mlx5e_get_netdev_max_channels(netdev);
mlx5e_build_rep_params(mdev, &priv->channels.params, netdev->mtu);
mlx5e_build_rep_netdev(netdev);
mlx5e_timestamp_init(priv);
+
+ return 0;
}
-static int mlx5e_init_rep_rx(struct mlx5e_priv *priv)
+static void mlx5e_cleanup_rep(struct mlx5e_priv *priv)
+{
+ mlx5e_netdev_cleanup(priv->netdev, priv);
+}
+
+static int mlx5e_create_rep_ttc_table(struct mlx5e_priv *priv)
+{
+ struct ttc_params ttc_params = {};
+ int tt, err;
+
+ priv->fs.ns = mlx5_get_flow_namespace(priv->mdev,
+ MLX5_FLOW_NAMESPACE_KERNEL);
+
+ /* The inner_ttc in the ttc params is intentionally not set */
+ ttc_params.any_tt_tirn = priv->direct_tir[0].tirn;
+ mlx5e_set_ttc_ft_params(&ttc_params);
+ for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++)
+ ttc_params.indir_tirn[tt] = priv->indir_tir[tt].tirn;
+
+ err = mlx5e_create_ttc_table(priv, &ttc_params, &priv->fs.ttc);
+ if (err) {
+ netdev_err(priv->netdev, "Failed to create rep ttc table, err=%d\n", err);
+ return err;
+ }
+ return 0;
+}
+
+static int mlx5e_create_rep_vport_rx_rule(struct mlx5e_priv *priv)
{
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
struct mlx5e_rep_priv *rpriv = priv->ppriv;
struct mlx5_eswitch_rep *rep = rpriv->rep;
struct mlx5_flow_handle *flow_rule;
+ struct mlx5_flow_destination dest;
+
+ dest.type = MLX5_FLOW_DESTINATION_TYPE_TIR;
+ dest.tir_num = priv->direct_tir[0].tirn;
+ flow_rule = mlx5_eswitch_create_vport_rx_rule(esw,
+ rep->vport,
+ &dest);
+ if (IS_ERR(flow_rule))
+ return PTR_ERR(flow_rule);
+ rpriv->vport_rx_rule = flow_rule;
+ return 0;
+}
+
+static int mlx5e_init_rep_rx(struct mlx5e_priv *priv)
+{
+ struct mlx5_core_dev *mdev = priv->mdev;
int err;
mlx5e_init_l2_addr(priv);
+ err = mlx5e_open_drop_rq(priv, &priv->drop_rq);
+ if (err) {
+ mlx5_core_err(mdev, "open drop rq failed, %d\n", err);
+ return err;
+ }
+
+ err = mlx5e_create_indirect_rqt(priv);
+ if (err)
+ goto err_close_drop_rq;
+
err = mlx5e_create_direct_rqts(priv);
if (err)
- return err;
+ goto err_destroy_indirect_rqts;
- err = mlx5e_create_direct_tirs(priv);
+ err = mlx5e_create_indirect_tirs(priv, false);
if (err)
goto err_destroy_direct_rqts;
- flow_rule = mlx5_eswitch_create_vport_rx_rule(esw,
- rep->vport,
- priv->direct_tir[0].tirn);
- if (IS_ERR(flow_rule)) {
- err = PTR_ERR(flow_rule);
+ err = mlx5e_create_direct_tirs(priv);
+ if (err)
+ goto err_destroy_indirect_tirs;
+
+ err = mlx5e_create_rep_ttc_table(priv);
+ if (err)
goto err_destroy_direct_tirs;
- }
- rpriv->vport_rx_rule = flow_rule;
+
+ err = mlx5e_create_rep_vport_rx_rule(priv);
+ if (err)
+ goto err_destroy_ttc_table;
return 0;
+err_destroy_ttc_table:
+ mlx5e_destroy_ttc_table(priv, &priv->fs.ttc);
err_destroy_direct_tirs:
mlx5e_destroy_direct_tirs(priv);
+err_destroy_indirect_tirs:
+ mlx5e_destroy_indirect_tirs(priv, false);
err_destroy_direct_rqts:
mlx5e_destroy_direct_rqts(priv);
+err_destroy_indirect_rqts:
+ mlx5e_destroy_rqt(priv, &priv->indir_rqt);
+err_close_drop_rq:
+ mlx5e_close_drop_rq(&priv->drop_rq);
return err;
}
@@ -1035,8 +1200,12 @@ static void mlx5e_cleanup_rep_rx(struct mlx5e_priv *priv)
struct mlx5e_rep_priv *rpriv = priv->ppriv;
mlx5_del_flow_rules(rpriv->vport_rx_rule);
+ mlx5e_destroy_ttc_table(priv, &priv->fs.ttc);
mlx5e_destroy_direct_tirs(priv);
+ mlx5e_destroy_indirect_tirs(priv, false);
mlx5e_destroy_direct_rqts(priv);
+ mlx5e_destroy_rqt(priv, &priv->indir_rqt);
+ mlx5e_close_drop_rq(&priv->drop_rq);
}
static int mlx5e_init_rep_tx(struct mlx5e_priv *priv)
@@ -1051,23 +1220,17 @@ static int mlx5e_init_rep_tx(struct mlx5e_priv *priv)
return 0;
}
-static int mlx5e_get_rep_max_num_channels(struct mlx5_core_dev *mdev)
-{
-#define MLX5E_PORT_REPRESENTOR_NCH 1
- return MLX5E_PORT_REPRESENTOR_NCH;
-}
-
static const struct mlx5e_profile mlx5e_rep_profile = {
.init = mlx5e_init_rep,
+ .cleanup = mlx5e_cleanup_rep,
.init_rx = mlx5e_init_rep_rx,
.cleanup_rx = mlx5e_cleanup_rep_rx,
.init_tx = mlx5e_init_rep_tx,
.cleanup_tx = mlx5e_cleanup_nic_tx,
.update_stats = mlx5e_rep_update_hw_counters,
- .max_nch = mlx5e_get_rep_max_num_channels,
.update_carrier = NULL,
.rx_handlers.handle_rx_cqe = mlx5e_handle_rx_cqe_rep,
- .rx_handlers.handle_rx_cqe_mpwqe = NULL /* Not supported */,
+ .rx_handlers.handle_rx_cqe_mpwqe = mlx5e_handle_rx_cqe_mpwrq,
.max_tc = 1,
};
@@ -1127,13 +1290,14 @@ mlx5e_vport_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
struct mlx5e_rep_priv *rpriv;
struct net_device *netdev;
struct mlx5e_priv *upriv;
- int err;
+ int nch, err;
rpriv = kzalloc(sizeof(*rpriv), GFP_KERNEL);
if (!rpriv)
return -ENOMEM;
- netdev = mlx5e_create_netdev(dev, &mlx5e_rep_profile, rpriv);
+ nch = mlx5e_get_max_num_channels(dev);
+ netdev = mlx5e_create_netdev(dev, &mlx5e_rep_profile, nch, rpriv);
if (!netdev) {
pr_warn("Failed to create representor netdev for vport %d\n",
rep->vport);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
index 15d8ae28c040..79638dcbae78 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
@@ -34,9 +34,9 @@
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/tcp.h>
-#include <net/busy_poll.h>
#include <net/ip6_checksum.h>
#include <net/page_pool.h>
+#include <net/inet_ecn.h>
#include "en.h"
#include "en_tc.h"
#include "eswitch.h"
@@ -432,10 +432,9 @@ static inline u16 mlx5e_icosq_wrap_cnt(struct mlx5e_icosq *sq)
static inline void mlx5e_fill_icosq_frag_edge(struct mlx5e_icosq *sq,
struct mlx5_wq_cyc *wq,
- u16 pi, u16 frag_pi)
+ u16 pi, u16 nnops)
{
struct mlx5e_sq_wqe_info *edge_wi, *wi = &sq->db.ico_wqe[pi];
- u8 nnops = mlx5_wq_cyc_get_frag_size(wq) - frag_pi;
edge_wi = wi + nnops;
@@ -454,15 +453,14 @@ static int mlx5e_alloc_rx_mpwqe(struct mlx5e_rq *rq, u16 ix)
struct mlx5_wq_cyc *wq = &sq->wq;
struct mlx5e_umr_wqe *umr_wqe;
u16 xlt_offset = ix << (MLX5E_LOG_ALIGNED_MPWQE_PPW - 1);
- u16 pi, frag_pi;
+ u16 pi, contig_wqebbs_room;
int err;
int i;
pi = mlx5_wq_cyc_ctr2ix(wq, sq->pc);
- frag_pi = mlx5_wq_cyc_ctr2fragix(wq, sq->pc);
-
- if (unlikely(frag_pi + MLX5E_UMR_WQEBBS > mlx5_wq_cyc_get_frag_size(wq))) {
- mlx5e_fill_icosq_frag_edge(sq, wq, pi, frag_pi);
+ contig_wqebbs_room = mlx5_wq_cyc_get_contig_wqebbs(wq, pi);
+ if (unlikely(contig_wqebbs_room < MLX5E_UMR_WQEBBS)) {
+ mlx5e_fill_icosq_frag_edge(sq, wq, pi, contig_wqebbs_room);
pi = mlx5_wq_cyc_ctr2ix(wq, sq->pc);
}
@@ -690,51 +688,48 @@ static inline void mlx5e_skb_set_hash(struct mlx5_cqe64 *cqe,
skb_set_hash(skb, be32_to_cpu(cqe->rss_hash_result), ht);
}
-static inline bool is_last_ethertype_ip(struct sk_buff *skb, int *network_depth)
+static inline bool is_last_ethertype_ip(struct sk_buff *skb, int *network_depth,
+ __be16 *proto)
{
- __be16 ethertype = ((struct ethhdr *)skb->data)->h_proto;
-
- ethertype = __vlan_get_protocol(skb, ethertype, network_depth);
- return (ethertype == htons(ETH_P_IP) || ethertype == htons(ETH_P_IPV6));
+ *proto = ((struct ethhdr *)skb->data)->h_proto;
+ *proto = __vlan_get_protocol(skb, *proto, network_depth);
+ return (*proto == htons(ETH_P_IP) || *proto == htons(ETH_P_IPV6));
}
-static __be32 mlx5e_get_fcs(struct sk_buff *skb)
+static inline void mlx5e_enable_ecn(struct mlx5e_rq *rq, struct sk_buff *skb)
{
- int last_frag_sz, bytes_in_prev, nr_frags;
- u8 *fcs_p1, *fcs_p2;
- skb_frag_t *last_frag;
- __be32 fcs_bytes;
+ int network_depth = 0;
+ __be16 proto;
+ void *ip;
+ int rc;
- if (!skb_is_nonlinear(skb))
- return *(__be32 *)(skb->data + skb->len - ETH_FCS_LEN);
+ if (unlikely(!is_last_ethertype_ip(skb, &network_depth, &proto)))
+ return;
- nr_frags = skb_shinfo(skb)->nr_frags;
- last_frag = &skb_shinfo(skb)->frags[nr_frags - 1];
- last_frag_sz = skb_frag_size(last_frag);
+ ip = skb->data + network_depth;
+ rc = ((proto == htons(ETH_P_IP)) ? IP_ECN_set_ce((struct iphdr *)ip) :
+ IP6_ECN_set_ce(skb, (struct ipv6hdr *)ip));
- /* If all FCS data is in last frag */
- if (last_frag_sz >= ETH_FCS_LEN)
- return *(__be32 *)(skb_frag_address(last_frag) +
- last_frag_sz - ETH_FCS_LEN);
+ rq->stats->ecn_mark += !!rc;
+}
- fcs_p2 = (u8 *)skb_frag_address(last_frag);
- bytes_in_prev = ETH_FCS_LEN - last_frag_sz;
+static u32 mlx5e_get_fcs(const struct sk_buff *skb)
+{
+ const void *fcs_bytes;
+ u32 _fcs_bytes;
- /* Find where the other part of the FCS is - Linear or another frag */
- if (nr_frags == 1) {
- fcs_p1 = skb_tail_pointer(skb);
- } else {
- skb_frag_t *prev_frag = &skb_shinfo(skb)->frags[nr_frags - 2];
+ fcs_bytes = skb_header_pointer(skb, skb->len - ETH_FCS_LEN,
+ ETH_FCS_LEN, &_fcs_bytes);
- fcs_p1 = skb_frag_address(prev_frag) +
- skb_frag_size(prev_frag);
- }
- fcs_p1 -= bytes_in_prev;
+ return __get_unaligned_cpu32(fcs_bytes);
+}
- memcpy(&fcs_bytes, fcs_p1, bytes_in_prev);
- memcpy(((u8 *)&fcs_bytes) + bytes_in_prev, fcs_p2, last_frag_sz);
+static u8 get_ip_proto(struct sk_buff *skb, __be16 proto)
+{
+ void *ip_p = skb->data + sizeof(struct ethhdr);
- return fcs_bytes;
+ return (proto == htons(ETH_P_IP)) ? ((struct iphdr *)ip_p)->protocol :
+ ((struct ipv6hdr *)ip_p)->nexthdr;
}
static inline void mlx5e_handle_csum(struct net_device *netdev,
@@ -745,6 +740,7 @@ static inline void mlx5e_handle_csum(struct net_device *netdev,
{
struct mlx5e_rq_stats *stats = rq->stats;
int network_depth = 0;
+ __be16 proto;
if (unlikely(!(netdev->features & NETIF_F_RXCSUM)))
goto csum_none;
@@ -755,7 +751,13 @@ static inline void mlx5e_handle_csum(struct net_device *netdev,
return;
}
- if (likely(is_last_ethertype_ip(skb, &network_depth))) {
+ if (unlikely(test_bit(MLX5E_RQ_STATE_NO_CSUM_COMPLETE, &rq->state)))
+ goto csum_unnecessary;
+
+ if (likely(is_last_ethertype_ip(skb, &network_depth, &proto))) {
+ if (unlikely(get_ip_proto(skb, proto) == IPPROTO_SCTP))
+ goto csum_unnecessary;
+
skb->ip_summed = CHECKSUM_COMPLETE;
skb->csum = csum_unfold((__force __sum16)cqe->check_sum);
if (network_depth > ETH_HLEN)
@@ -767,14 +769,17 @@ static inline void mlx5e_handle_csum(struct net_device *netdev,
network_depth - ETH_HLEN,
skb->csum);
if (unlikely(netdev->features & NETIF_F_RXFCS))
- skb->csum = csum_add(skb->csum,
- (__force __wsum)mlx5e_get_fcs(skb));
+ skb->csum = csum_block_add(skb->csum,
+ (__force __wsum)mlx5e_get_fcs(skb),
+ skb->len - ETH_FCS_LEN);
stats->csum_complete++;
return;
}
+csum_unnecessary:
if (likely((cqe->hds_ip_ext & CQE_L3_OK) &&
- (cqe->hds_ip_ext & CQE_L4_OK))) {
+ ((cqe->hds_ip_ext & CQE_L4_OK) ||
+ (get_cqe_l4_hdr_type(cqe) == CQE_L4_HDR_TYPE_NONE)))) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
if (cqe_is_tunneled(cqe)) {
skb->csum_level = 1;
@@ -790,6 +795,8 @@ csum_none:
stats->csum_none++;
}
+#define MLX5E_CE_BIT_MASK 0x80
+
static inline void mlx5e_build_rx_skb(struct mlx5_cqe64 *cqe,
u32 cqe_bcnt,
struct mlx5e_rq *rq,
@@ -834,6 +841,10 @@ static inline void mlx5e_build_rx_skb(struct mlx5_cqe64 *cqe,
skb->mark = be32_to_cpu(cqe->sop_drop_qpn) & MLX5E_TC_FLOW_ID_MASK;
mlx5e_handle_csum(netdev, cqe, rq, skb, !!lro_num_seg);
+ /* checking CE bit in cqe - MSB in ml_path field */
+ if (unlikely(cqe->ml_path & MLX5E_CE_BIT_MASK))
+ mlx5e_enable_ecn(rq, skb);
+
skb->protocol = eth_type_trans(skb, netdev);
}
@@ -1230,8 +1241,8 @@ static inline void mlx5i_complete_rx_cqe(struct mlx5e_rq *rq,
u32 cqe_bcnt,
struct sk_buff *skb)
{
- struct mlx5e_rq_stats *stats = rq->stats;
struct hwtstamp_config *tstamp;
+ struct mlx5e_rq_stats *stats;
struct net_device *netdev;
struct mlx5e_priv *priv;
char *pseudo_header;
@@ -1254,6 +1265,7 @@ static inline void mlx5i_complete_rx_cqe(struct mlx5e_rq *rq,
priv = mlx5i_epriv(netdev);
tstamp = &priv->tstamp;
+ stats = &priv->channel_stats[rq->ix].rq;
g = (be32_to_cpu(cqe->flags_rqpn) >> 28) & 3;
dgid = skb->data + MLX5_IB_GRH_DGID_OFFSET;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
index 6839481f7697..1e55b9c27ffc 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
@@ -53,6 +53,7 @@ static const struct counter_desc sw_stats_desc[] = {
{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_lro_packets) },
{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_lro_bytes) },
+ { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_ecn_mark) },
{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_removed_vlan_packets) },
{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_csum_unnecessary) },
{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_csum_none) },
@@ -92,6 +93,7 @@ static const struct counter_desc sw_stats_desc[] = {
{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_cache_busy) },
{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_cache_waive) },
{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_congst_umr) },
+ { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_arfs_err) },
{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, ch_events) },
{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, ch_poll) },
{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, ch_arm) },
@@ -131,7 +133,7 @@ void mlx5e_grp_sw_update_stats(struct mlx5e_priv *priv)
memset(s, 0, sizeof(*s));
- for (i = 0; i < priv->profile->max_nch(priv->mdev); i++) {
+ for (i = 0; i < mlx5e_get_netdev_max_channels(priv->netdev); i++) {
struct mlx5e_channel_stats *channel_stats =
&priv->channel_stats[i];
struct mlx5e_xdpsq_stats *xdpsq_red_stats = &channel_stats->xdpsq;
@@ -144,6 +146,7 @@ void mlx5e_grp_sw_update_stats(struct mlx5e_priv *priv)
s->rx_bytes += rq_stats->bytes;
s->rx_lro_packets += rq_stats->lro_packets;
s->rx_lro_bytes += rq_stats->lro_bytes;
+ s->rx_ecn_mark += rq_stats->ecn_mark;
s->rx_removed_vlan_packets += rq_stats->removed_vlan_packets;
s->rx_csum_none += rq_stats->csum_none;
s->rx_csum_complete += rq_stats->csum_complete;
@@ -168,6 +171,7 @@ void mlx5e_grp_sw_update_stats(struct mlx5e_priv *priv)
s->rx_cache_busy += rq_stats->cache_busy;
s->rx_cache_waive += rq_stats->cache_waive;
s->rx_congst_umr += rq_stats->congst_umr;
+ s->rx_arfs_err += rq_stats->arfs_err;
s->ch_events += ch_stats->events;
s->ch_poll += ch_stats->poll;
s->ch_arm += ch_stats->arm;
@@ -610,46 +614,82 @@ static const struct counter_desc pport_phy_statistical_stats_desc[] = {
{ "rx_corrected_bits_phy", PPORT_PHY_STATISTICAL_OFF(phy_corrected_bits) },
};
-#define NUM_PPORT_PHY_STATISTICAL_COUNTERS ARRAY_SIZE(pport_phy_statistical_stats_desc)
+static const struct counter_desc
+pport_phy_statistical_err_lanes_stats_desc[] = {
+ { "rx_err_lane_0_phy", PPORT_PHY_STATISTICAL_OFF(phy_corrected_bits_lane0) },
+ { "rx_err_lane_1_phy", PPORT_PHY_STATISTICAL_OFF(phy_corrected_bits_lane1) },
+ { "rx_err_lane_2_phy", PPORT_PHY_STATISTICAL_OFF(phy_corrected_bits_lane2) },
+ { "rx_err_lane_3_phy", PPORT_PHY_STATISTICAL_OFF(phy_corrected_bits_lane3) },
+};
+
+#define NUM_PPORT_PHY_STATISTICAL_COUNTERS \
+ ARRAY_SIZE(pport_phy_statistical_stats_desc)
+#define NUM_PPORT_PHY_STATISTICAL_PER_LANE_COUNTERS \
+ ARRAY_SIZE(pport_phy_statistical_err_lanes_stats_desc)
static int mlx5e_grp_phy_get_num_stats(struct mlx5e_priv *priv)
{
+ struct mlx5_core_dev *mdev = priv->mdev;
+ int num_stats;
+
/* "1" for link_down_events special counter */
- return MLX5_CAP_PCAM_FEATURE((priv)->mdev, ppcnt_statistical_group) ?
- NUM_PPORT_PHY_STATISTICAL_COUNTERS + 1 : 1;
+ num_stats = 1;
+
+ num_stats += MLX5_CAP_PCAM_FEATURE(mdev, ppcnt_statistical_group) ?
+ NUM_PPORT_PHY_STATISTICAL_COUNTERS : 0;
+
+ num_stats += MLX5_CAP_PCAM_FEATURE(mdev, per_lane_error_counters) ?
+ NUM_PPORT_PHY_STATISTICAL_PER_LANE_COUNTERS : 0;
+
+ return num_stats;
}
static int mlx5e_grp_phy_fill_strings(struct mlx5e_priv *priv, u8 *data,
int idx)
{
+ struct mlx5_core_dev *mdev = priv->mdev;
int i;
strcpy(data + (idx++) * ETH_GSTRING_LEN, "link_down_events_phy");
- if (!MLX5_CAP_PCAM_FEATURE((priv)->mdev, ppcnt_statistical_group))
+ if (!MLX5_CAP_PCAM_FEATURE(mdev, ppcnt_statistical_group))
return idx;
for (i = 0; i < NUM_PPORT_PHY_STATISTICAL_COUNTERS; i++)
strcpy(data + (idx++) * ETH_GSTRING_LEN,
pport_phy_statistical_stats_desc[i].format);
+
+ if (MLX5_CAP_PCAM_FEATURE(mdev, per_lane_error_counters))
+ for (i = 0; i < NUM_PPORT_PHY_STATISTICAL_PER_LANE_COUNTERS; i++)
+ strcpy(data + (idx++) * ETH_GSTRING_LEN,
+ pport_phy_statistical_err_lanes_stats_desc[i].format);
+
return idx;
}
static int mlx5e_grp_phy_fill_stats(struct mlx5e_priv *priv, u64 *data, int idx)
{
+ struct mlx5_core_dev *mdev = priv->mdev;
int i;
/* link_down_events_phy has special handling since it is not stored in __be64 format */
data[idx++] = MLX5_GET(ppcnt_reg, priv->stats.pport.phy_counters,
counter_set.phys_layer_cntrs.link_down_events);
- if (!MLX5_CAP_PCAM_FEATURE((priv)->mdev, ppcnt_statistical_group))
+ if (!MLX5_CAP_PCAM_FEATURE(mdev, ppcnt_statistical_group))
return idx;
for (i = 0; i < NUM_PPORT_PHY_STATISTICAL_COUNTERS; i++)
data[idx++] =
MLX5E_READ_CTR64_BE(&priv->stats.pport.phy_statistical_counters,
pport_phy_statistical_stats_desc, i);
+
+ if (MLX5_CAP_PCAM_FEATURE(mdev, per_lane_error_counters))
+ for (i = 0; i < NUM_PPORT_PHY_STATISTICAL_PER_LANE_COUNTERS; i++)
+ data[idx++] =
+ MLX5E_READ_CTR64_BE(&priv->stats.pport.phy_statistical_counters,
+ pport_phy_statistical_err_lanes_stats_desc,
+ i);
return idx;
}
@@ -1144,6 +1184,7 @@ static const struct counter_desc rq_stats_desc[] = {
{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, xdp_redirect) },
{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, lro_packets) },
{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, lro_bytes) },
+ { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, ecn_mark) },
{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, removed_vlan_packets) },
{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, wqe_err) },
{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, mpwqe_filler_cqes) },
@@ -1158,6 +1199,7 @@ static const struct counter_desc rq_stats_desc[] = {
{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, cache_busy) },
{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, cache_waive) },
{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, congst_umr) },
+ { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, arfs_err) },
};
static const struct counter_desc sq_stats_desc[] = {
@@ -1211,7 +1253,7 @@ static const struct counter_desc ch_stats_desc[] = {
static int mlx5e_grp_channels_get_num_stats(struct mlx5e_priv *priv)
{
- int max_nch = priv->profile->max_nch(priv->mdev);
+ int max_nch = mlx5e_get_netdev_max_channels(priv->netdev);
return (NUM_RQ_STATS * max_nch) +
(NUM_CH_STATS * max_nch) +
@@ -1223,7 +1265,7 @@ static int mlx5e_grp_channels_get_num_stats(struct mlx5e_priv *priv)
static int mlx5e_grp_channels_fill_strings(struct mlx5e_priv *priv, u8 *data,
int idx)
{
- int max_nch = priv->profile->max_nch(priv->mdev);
+ int max_nch = mlx5e_get_netdev_max_channels(priv->netdev);
int i, j, tc;
for (i = 0; i < max_nch; i++)
@@ -1258,7 +1300,7 @@ static int mlx5e_grp_channels_fill_strings(struct mlx5e_priv *priv, u8 *data,
static int mlx5e_grp_channels_fill_stats(struct mlx5e_priv *priv, u64 *data,
int idx)
{
- int max_nch = priv->profile->max_nch(priv->mdev);
+ int max_nch = mlx5e_get_netdev_max_channels(priv->netdev);
int i, j, tc;
for (i = 0; i < max_nch; i++)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h
index a4c035aedd46..77f74ce11280 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h
@@ -66,6 +66,7 @@ struct mlx5e_sw_stats {
u64 tx_nop;
u64 rx_lro_packets;
u64 rx_lro_bytes;
+ u64 rx_ecn_mark;
u64 rx_removed_vlan_packets;
u64 rx_csum_unnecessary;
u64 rx_csum_none;
@@ -105,6 +106,7 @@ struct mlx5e_sw_stats {
u64 rx_cache_busy;
u64 rx_cache_waive;
u64 rx_congst_umr;
+ u64 rx_arfs_err;
u64 ch_events;
u64 ch_poll;
u64 ch_arm;
@@ -184,6 +186,7 @@ struct mlx5e_rq_stats {
u64 csum_none;
u64 lro_packets;
u64 lro_bytes;
+ u64 ecn_mark;
u64 removed_vlan_packets;
u64 xdp_drop;
u64 xdp_redirect;
@@ -200,6 +203,7 @@ struct mlx5e_rq_stats {
u64 cache_busy;
u64 cache_waive;
u64 congst_umr;
+ u64 arfs_err;
};
struct mlx5e_sq_stats {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
index 9fed54017659..608025ca5c04 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
@@ -61,6 +61,7 @@ struct mlx5_nic_flow_attr {
u32 hairpin_tirn;
u8 match_level;
struct mlx5_flow_table *hairpin_ft;
+ struct mlx5_fc *counter;
};
#define MLX5E_TC_FLOW_BASE (MLX5E_TC_LAST_EXPORTED_BIT + 1)
@@ -73,6 +74,7 @@ enum {
MLX5E_TC_FLOW_OFFLOADED = BIT(MLX5E_TC_FLOW_BASE + 2),
MLX5E_TC_FLOW_HAIRPIN = BIT(MLX5E_TC_FLOW_BASE + 3),
MLX5E_TC_FLOW_HAIRPIN_RSS = BIT(MLX5E_TC_FLOW_BASE + 4),
+ MLX5E_TC_FLOW_SLOW = BIT(MLX5E_TC_FLOW_BASE + 5),
};
#define MLX5E_TC_MAX_SPLITS 1
@@ -81,7 +83,7 @@ struct mlx5e_tc_flow {
struct rhash_head node;
struct mlx5e_priv *priv;
u64 cookie;
- u8 flags;
+ u16 flags;
struct mlx5_flow_handle *rule[MLX5E_TC_MAX_SPLITS + 1];
struct list_head encap; /* flows sharing the same encap ID */
struct list_head mod_hdr; /* flows sharing the same mod hdr ID */
@@ -100,11 +102,6 @@ struct mlx5e_tc_flow_parse_attr {
int mirred_ifindex;
};
-enum {
- MLX5_HEADER_TYPE_VXLAN = 0x0,
- MLX5_HEADER_TYPE_NVGRE = 0x1,
-};
-
#define MLX5E_TC_TABLE_NUM_GROUPS 4
#define MLX5E_TC_TABLE_MAX_GROUP_SIZE BIT(16)
@@ -532,7 +529,8 @@ static struct mlx5e_hairpin_entry *mlx5e_hairpin_get(struct mlx5e_priv *priv,
#define UNKNOWN_MATCH_PRIO 8
static int mlx5e_hairpin_get_prio(struct mlx5e_priv *priv,
- struct mlx5_flow_spec *spec, u8 *match_prio)
+ struct mlx5_flow_spec *spec, u8 *match_prio,
+ struct netlink_ext_ack *extack)
{
void *headers_c, *headers_v;
u8 prio_val, prio_mask = 0;
@@ -540,8 +538,8 @@ static int mlx5e_hairpin_get_prio(struct mlx5e_priv *priv,
#ifdef CONFIG_MLX5_CORE_EN_DCB
if (priv->dcbx_dp.trust_state != MLX5_QPTS_TRUST_PCP) {
- netdev_warn(priv->netdev,
- "only PCP trust state supported for hairpin\n");
+ NL_SET_ERR_MSG_MOD(extack,
+ "only PCP trust state supported for hairpin");
return -EOPNOTSUPP;
}
#endif
@@ -557,8 +555,8 @@ static int mlx5e_hairpin_get_prio(struct mlx5e_priv *priv,
if (!vlan_present || !prio_mask) {
prio_val = UNKNOWN_MATCH_PRIO;
} else if (prio_mask != 0x7) {
- netdev_warn(priv->netdev,
- "masked priority match not supported for hairpin\n");
+ NL_SET_ERR_MSG_MOD(extack,
+ "masked priority match not supported for hairpin");
return -EOPNOTSUPP;
}
@@ -568,7 +566,8 @@ static int mlx5e_hairpin_get_prio(struct mlx5e_priv *priv,
static int mlx5e_hairpin_flow_add(struct mlx5e_priv *priv,
struct mlx5e_tc_flow *flow,
- struct mlx5e_tc_flow_parse_attr *parse_attr)
+ struct mlx5e_tc_flow_parse_attr *parse_attr,
+ struct netlink_ext_ack *extack)
{
int peer_ifindex = parse_attr->mirred_ifindex;
struct mlx5_hairpin_params params;
@@ -583,12 +582,13 @@ static int mlx5e_hairpin_flow_add(struct mlx5e_priv *priv,
peer_mdev = mlx5e_hairpin_get_mdev(dev_net(priv->netdev), peer_ifindex);
if (!MLX5_CAP_GEN(priv->mdev, hairpin) || !MLX5_CAP_GEN(peer_mdev, hairpin)) {
- netdev_warn(priv->netdev, "hairpin is not supported\n");
+ NL_SET_ERR_MSG_MOD(extack, "hairpin is not supported");
return -EOPNOTSUPP;
}
peer_id = MLX5_CAP_GEN(peer_mdev, vhca_id);
- err = mlx5e_hairpin_get_prio(priv, &parse_attr->spec, &match_prio);
+ err = mlx5e_hairpin_get_prio(priv, &parse_attr->spec, &match_prio,
+ extack);
if (err)
return err;
hpe = mlx5e_hairpin_get(priv, peer_id, match_prio);
@@ -674,29 +674,28 @@ static void mlx5e_hairpin_flow_del(struct mlx5e_priv *priv,
}
}
-static struct mlx5_flow_handle *
+static int
mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
struct mlx5e_tc_flow_parse_attr *parse_attr,
- struct mlx5e_tc_flow *flow)
+ struct mlx5e_tc_flow *flow,
+ struct netlink_ext_ack *extack)
{
struct mlx5_nic_flow_attr *attr = flow->nic_attr;
struct mlx5_core_dev *dev = priv->mdev;
struct mlx5_flow_destination dest[2] = {};
struct mlx5_flow_act flow_act = {
.action = attr->action,
- .has_flow_tag = true,
.flow_tag = attr->flow_tag,
- .encap_id = 0,
+ .reformat_id = 0,
+ .flags = FLOW_ACT_HAS_TAG | FLOW_ACT_NO_APPEND,
};
struct mlx5_fc *counter = NULL;
- struct mlx5_flow_handle *rule;
bool table_created = false;
int err, dest_ix = 0;
if (flow->flags & MLX5E_TC_FLOW_HAIRPIN) {
- err = mlx5e_hairpin_flow_add(priv, flow, parse_attr);
+ err = mlx5e_hairpin_flow_add(priv, flow, parse_attr, extack);
if (err) {
- rule = ERR_PTR(err);
goto err_add_hairpin_flow;
}
if (flow->flags & MLX5E_TC_FLOW_HAIRPIN_RSS) {
@@ -716,22 +715,21 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
if (attr->action & MLX5_FLOW_CONTEXT_ACTION_COUNT) {
counter = mlx5_fc_create(dev, true);
if (IS_ERR(counter)) {
- rule = ERR_CAST(counter);
+ err = PTR_ERR(counter);
goto err_fc_create;
}
dest[dest_ix].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
- dest[dest_ix].counter = counter;
+ dest[dest_ix].counter_id = mlx5_fc_id(counter);
dest_ix++;
+ attr->counter = counter;
}
if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) {
err = mlx5e_attach_mod_hdr(priv, flow, parse_attr);
flow_act.modify_id = attr->mod_hdr_id;
kfree(parse_attr->mod_hdr_actions);
- if (err) {
- rule = ERR_PTR(err);
+ if (err)
goto err_create_mod_hdr_id;
- }
}
if (IS_ERR_OR_NULL(priv->fs.tc.t)) {
@@ -753,9 +751,11 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
MLX5E_TC_TABLE_NUM_GROUPS,
MLX5E_TC_FT_LEVEL, 0);
if (IS_ERR(priv->fs.tc.t)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Failed to create tc offload table\n");
netdev_err(priv->netdev,
"Failed to create tc offload table\n");
- rule = ERR_CAST(priv->fs.tc.t);
+ err = PTR_ERR(priv->fs.tc.t);
goto err_create_ft;
}
@@ -765,13 +765,15 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
if (attr->match_level != MLX5_MATCH_NONE)
parse_attr->spec.match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
- rule = mlx5_add_flow_rules(priv->fs.tc.t, &parse_attr->spec,
- &flow_act, dest, dest_ix);
+ flow->rule[0] = mlx5_add_flow_rules(priv->fs.tc.t, &parse_attr->spec,
+ &flow_act, dest, dest_ix);
- if (IS_ERR(rule))
+ if (IS_ERR(flow->rule[0])) {
+ err = PTR_ERR(flow->rule[0]);
goto err_add_rule;
+ }
- return rule;
+ return 0;
err_add_rule:
if (table_created) {
@@ -787,7 +789,7 @@ err_fc_create:
if (flow->flags & MLX5E_TC_FLOW_HAIRPIN)
mlx5e_hairpin_flow_del(priv, flow);
err_add_hairpin_flow:
- return rule;
+ return err;
}
static void mlx5e_tc_del_nic_flow(struct mlx5e_priv *priv,
@@ -796,7 +798,7 @@ static void mlx5e_tc_del_nic_flow(struct mlx5e_priv *priv,
struct mlx5_nic_flow_attr *attr = flow->nic_attr;
struct mlx5_fc *counter = NULL;
- counter = mlx5_flow_rule_counter(flow->rule[0]);
+ counter = attr->counter;
mlx5_del_flow_rules(flow->rule[0]);
mlx5_fc_destroy(priv->mdev, counter);
@@ -819,30 +821,119 @@ static int mlx5e_attach_encap(struct mlx5e_priv *priv,
struct ip_tunnel_info *tun_info,
struct net_device *mirred_dev,
struct net_device **encap_dev,
- struct mlx5e_tc_flow *flow);
+ struct mlx5e_tc_flow *flow,
+ struct netlink_ext_ack *extack);
+
+static struct mlx5_flow_handle *
+mlx5e_tc_offload_fdb_rules(struct mlx5_eswitch *esw,
+ struct mlx5e_tc_flow *flow,
+ struct mlx5_flow_spec *spec,
+ struct mlx5_esw_flow_attr *attr)
+{
+ struct mlx5_flow_handle *rule;
+
+ rule = mlx5_eswitch_add_offloaded_rule(esw, spec, attr);
+ if (IS_ERR(rule))
+ return rule;
+
+ if (attr->mirror_count) {
+ flow->rule[1] = mlx5_eswitch_add_fwd_rule(esw, spec, attr);
+ if (IS_ERR(flow->rule[1])) {
+ mlx5_eswitch_del_offloaded_rule(esw, rule, attr);
+ return flow->rule[1];
+ }
+ }
+
+ flow->flags |= MLX5E_TC_FLOW_OFFLOADED;
+ return rule;
+}
+
+static void
+mlx5e_tc_unoffload_fdb_rules(struct mlx5_eswitch *esw,
+ struct mlx5e_tc_flow *flow,
+ struct mlx5_esw_flow_attr *attr)
+{
+ flow->flags &= ~MLX5E_TC_FLOW_OFFLOADED;
+
+ if (attr->mirror_count)
+ mlx5_eswitch_del_fwd_rule(esw, flow->rule[1], attr);
+
+ mlx5_eswitch_del_offloaded_rule(esw, flow->rule[0], attr);
+}
static struct mlx5_flow_handle *
+mlx5e_tc_offload_to_slow_path(struct mlx5_eswitch *esw,
+ struct mlx5e_tc_flow *flow,
+ struct mlx5_flow_spec *spec,
+ struct mlx5_esw_flow_attr *slow_attr)
+{
+ struct mlx5_flow_handle *rule;
+
+ memcpy(slow_attr, flow->esw_attr, sizeof(*slow_attr));
+ slow_attr->action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST,
+ slow_attr->mirror_count = 0,
+ slow_attr->dest_chain = FDB_SLOW_PATH_CHAIN,
+
+ rule = mlx5e_tc_offload_fdb_rules(esw, flow, spec, slow_attr);
+ if (!IS_ERR(rule))
+ flow->flags |= MLX5E_TC_FLOW_SLOW;
+
+ return rule;
+}
+
+static void
+mlx5e_tc_unoffload_from_slow_path(struct mlx5_eswitch *esw,
+ struct mlx5e_tc_flow *flow,
+ struct mlx5_esw_flow_attr *slow_attr)
+{
+ memcpy(slow_attr, flow->esw_attr, sizeof(*slow_attr));
+ mlx5e_tc_unoffload_fdb_rules(esw, flow, slow_attr);
+ flow->flags &= ~MLX5E_TC_FLOW_SLOW;
+}
+
+static int
mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
struct mlx5e_tc_flow_parse_attr *parse_attr,
- struct mlx5e_tc_flow *flow)
+ struct mlx5e_tc_flow *flow,
+ struct netlink_ext_ack *extack)
{
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
+ u32 max_chain = mlx5_eswitch_get_chain_range(esw);
struct mlx5_esw_flow_attr *attr = flow->esw_attr;
+ u16 max_prio = mlx5_eswitch_get_prio_range(esw);
struct net_device *out_dev, *encap_dev = NULL;
- struct mlx5_flow_handle *rule = NULL;
+ struct mlx5_fc *counter = NULL;
struct mlx5e_rep_priv *rpriv;
struct mlx5e_priv *out_priv;
- int err;
+ int err = 0, encap_err = 0;
- if (attr->action & MLX5_FLOW_CONTEXT_ACTION_ENCAP) {
+ /* if prios are not supported, keep the old behaviour of using same prio
+ * for all offloaded rules.
+ */
+ if (!mlx5_eswitch_prios_supported(esw))
+ attr->prio = 1;
+
+ if (attr->chain > max_chain) {
+ NL_SET_ERR_MSG(extack, "Requested chain is out of supported range");
+ err = -EOPNOTSUPP;
+ goto err_max_prio_chain;
+ }
+
+ if (attr->prio > max_prio) {
+ NL_SET_ERR_MSG(extack, "Requested priority is out of supported range");
+ err = -EOPNOTSUPP;
+ goto err_max_prio_chain;
+ }
+
+ if (attr->action & MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT) {
out_dev = __dev_get_by_index(dev_net(priv->netdev),
attr->parse_attr->mirred_ifindex);
- err = mlx5e_attach_encap(priv, &parse_attr->tun_info,
- out_dev, &encap_dev, flow);
- if (err) {
- rule = ERR_PTR(err);
- if (err != -EAGAIN)
- goto err_attach_encap;
+ encap_err = mlx5e_attach_encap(priv, &parse_attr->tun_info,
+ out_dev, &encap_dev, flow,
+ extack);
+ if (encap_err && encap_err != -EAGAIN) {
+ err = encap_err;
+ goto err_attach_encap;
}
out_priv = netdev_priv(encap_dev);
rpriv = out_priv->ppriv;
@@ -851,49 +942,58 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
}
err = mlx5_eswitch_add_vlan_action(esw, attr);
- if (err) {
- rule = ERR_PTR(err);
+ if (err)
goto err_add_vlan;
- }
if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) {
err = mlx5e_attach_mod_hdr(priv, flow, parse_attr);
kfree(parse_attr->mod_hdr_actions);
- if (err) {
- rule = ERR_PTR(err);
+ if (err)
goto err_mod_hdr;
+ }
+
+ if (attr->action & MLX5_FLOW_CONTEXT_ACTION_COUNT) {
+ counter = mlx5_fc_create(esw->dev, true);
+ if (IS_ERR(counter)) {
+ err = PTR_ERR(counter);
+ goto err_create_counter;
}
+
+ attr->counter = counter;
}
- /* we get here if (1) there's no error (rule being null) or when
+ /* we get here if (1) there's no error or when
* (2) there's an encap action and we're on -EAGAIN (no valid neigh)
*/
- if (rule != ERR_PTR(-EAGAIN)) {
- rule = mlx5_eswitch_add_offloaded_rule(esw, &parse_attr->spec, attr);
- if (IS_ERR(rule))
- goto err_add_rule;
-
- if (attr->mirror_count) {
- flow->rule[1] = mlx5_eswitch_add_fwd_rule(esw, &parse_attr->spec, attr);
- if (IS_ERR(flow->rule[1]))
- goto err_fwd_rule;
- }
+ if (encap_err == -EAGAIN) {
+ /* continue with goto slow path rule instead */
+ struct mlx5_esw_flow_attr slow_attr;
+
+ flow->rule[0] = mlx5e_tc_offload_to_slow_path(esw, flow, &parse_attr->spec, &slow_attr);
+ } else {
+ flow->rule[0] = mlx5e_tc_offload_fdb_rules(esw, flow, &parse_attr->spec, attr);
}
- return rule;
-err_fwd_rule:
- mlx5_eswitch_del_offloaded_rule(esw, rule, attr);
- rule = flow->rule[1];
+ if (IS_ERR(flow->rule[0])) {
+ err = PTR_ERR(flow->rule[0]);
+ goto err_add_rule;
+ }
+
+ return 0;
+
err_add_rule:
+ mlx5_fc_destroy(esw->dev, counter);
+err_create_counter:
if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
mlx5e_detach_mod_hdr(priv, flow);
err_mod_hdr:
mlx5_eswitch_del_vlan_action(esw, attr);
err_add_vlan:
- if (attr->action & MLX5_FLOW_CONTEXT_ACTION_ENCAP)
+ if (attr->action & MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT)
mlx5e_detach_encap(priv, flow);
err_attach_encap:
- return rule;
+err_max_prio_chain:
+ return err;
}
static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv,
@@ -901,36 +1001,43 @@ static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv,
{
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
struct mlx5_esw_flow_attr *attr = flow->esw_attr;
+ struct mlx5_esw_flow_attr slow_attr;
if (flow->flags & MLX5E_TC_FLOW_OFFLOADED) {
- flow->flags &= ~MLX5E_TC_FLOW_OFFLOADED;
- if (attr->mirror_count)
- mlx5_eswitch_del_offloaded_rule(esw, flow->rule[1], attr);
- mlx5_eswitch_del_offloaded_rule(esw, flow->rule[0], attr);
+ if (flow->flags & MLX5E_TC_FLOW_SLOW)
+ mlx5e_tc_unoffload_from_slow_path(esw, flow, &slow_attr);
+ else
+ mlx5e_tc_unoffload_fdb_rules(esw, flow, attr);
}
mlx5_eswitch_del_vlan_action(esw, attr);
- if (attr->action & MLX5_FLOW_CONTEXT_ACTION_ENCAP) {
+ if (attr->action & MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT) {
mlx5e_detach_encap(priv, flow);
kvfree(attr->parse_attr);
}
if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
mlx5e_detach_mod_hdr(priv, flow);
+
+ if (attr->action & MLX5_FLOW_CONTEXT_ACTION_COUNT)
+ mlx5_fc_destroy(esw->dev, attr->counter);
}
void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv,
struct mlx5e_encap_entry *e)
{
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
- struct mlx5_esw_flow_attr *esw_attr;
+ struct mlx5_esw_flow_attr slow_attr, *esw_attr;
+ struct mlx5_flow_handle *rule;
+ struct mlx5_flow_spec *spec;
struct mlx5e_tc_flow *flow;
int err;
- err = mlx5_encap_alloc(priv->mdev, e->tunnel_type,
- e->encap_size, e->encap_header,
- &e->encap_id);
+ err = mlx5_packet_reformat_alloc(priv->mdev, e->tunnel_type,
+ e->encap_size, e->encap_header,
+ MLX5_FLOW_NAMESPACE_FDB,
+ &e->encap_id);
if (err) {
mlx5_core_warn(priv->mdev, "Failed to offload cached encapsulation header, %d\n",
err);
@@ -942,26 +1049,20 @@ void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv,
list_for_each_entry(flow, &e->flows, encap) {
esw_attr = flow->esw_attr;
esw_attr->encap_id = e->encap_id;
- flow->rule[0] = mlx5_eswitch_add_offloaded_rule(esw, &esw_attr->parse_attr->spec, esw_attr);
- if (IS_ERR(flow->rule[0])) {
- err = PTR_ERR(flow->rule[0]);
+ spec = &esw_attr->parse_attr->spec;
+
+ /* update from slow path rule to encap rule */
+ rule = mlx5e_tc_offload_fdb_rules(esw, flow, spec, esw_attr);
+ if (IS_ERR(rule)) {
+ err = PTR_ERR(rule);
mlx5_core_warn(priv->mdev, "Failed to update cached encapsulation flow, %d\n",
err);
continue;
}
- if (esw_attr->mirror_count) {
- flow->rule[1] = mlx5_eswitch_add_fwd_rule(esw, &esw_attr->parse_attr->spec, esw_attr);
- if (IS_ERR(flow->rule[1])) {
- mlx5_eswitch_del_offloaded_rule(esw, flow->rule[0], esw_attr);
- err = PTR_ERR(flow->rule[1]);
- mlx5_core_warn(priv->mdev, "Failed to update cached mirror flow, %d\n",
- err);
- continue;
- }
- }
-
- flow->flags |= MLX5E_TC_FLOW_OFFLOADED;
+ mlx5e_tc_unoffload_from_slow_path(esw, flow, &slow_attr);
+ flow->flags |= MLX5E_TC_FLOW_OFFLOADED; /* was unset when slow path rule removed */
+ flow->rule[0] = rule;
}
}
@@ -969,25 +1070,44 @@ void mlx5e_tc_encap_flows_del(struct mlx5e_priv *priv,
struct mlx5e_encap_entry *e)
{
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
+ struct mlx5_esw_flow_attr slow_attr;
+ struct mlx5_flow_handle *rule;
+ struct mlx5_flow_spec *spec;
struct mlx5e_tc_flow *flow;
+ int err;
list_for_each_entry(flow, &e->flows, encap) {
- if (flow->flags & MLX5E_TC_FLOW_OFFLOADED) {
- struct mlx5_esw_flow_attr *attr = flow->esw_attr;
+ spec = &flow->esw_attr->parse_attr->spec;
- flow->flags &= ~MLX5E_TC_FLOW_OFFLOADED;
- if (attr->mirror_count)
- mlx5_eswitch_del_offloaded_rule(esw, flow->rule[1], attr);
- mlx5_eswitch_del_offloaded_rule(esw, flow->rule[0], attr);
+ /* update from encap rule to slow path rule */
+ rule = mlx5e_tc_offload_to_slow_path(esw, flow, spec, &slow_attr);
+
+ if (IS_ERR(rule)) {
+ err = PTR_ERR(rule);
+ mlx5_core_warn(priv->mdev, "Failed to update slow path (encap) flow, %d\n",
+ err);
+ continue;
}
+
+ mlx5e_tc_unoffload_fdb_rules(esw, flow, flow->esw_attr);
+ flow->flags |= MLX5E_TC_FLOW_OFFLOADED; /* was unset when fast path rule removed */
+ flow->rule[0] = rule;
}
if (e->flags & MLX5_ENCAP_ENTRY_VALID) {
e->flags &= ~MLX5_ENCAP_ENTRY_VALID;
- mlx5_encap_dealloc(priv->mdev, e->encap_id);
+ mlx5_packet_reformat_dealloc(priv->mdev, e->encap_id);
}
}
+static struct mlx5_fc *mlx5e_tc_get_counter(struct mlx5e_tc_flow *flow)
+{
+ if (flow->flags & MLX5E_TC_FLOW_ESWITCH)
+ return flow->esw_attr->counter;
+ else
+ return flow->nic_attr->counter;
+}
+
void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe)
{
struct mlx5e_neigh *m_neigh = &nhe->m_neigh;
@@ -1013,7 +1133,7 @@ void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe)
continue;
list_for_each_entry(flow, &e->flows, encap) {
if (flow->flags & MLX5E_TC_FLOW_OFFLOADED) {
- counter = mlx5_flow_rule_counter(flow->rule[0]);
+ counter = mlx5e_tc_get_counter(flow);
mlx5_fc_query_cached(counter, &bytes, &packets, &lastuse);
if (time_after((unsigned long)lastuse, nhe->reported_lastuse)) {
neigh_used = true;
@@ -1053,7 +1173,7 @@ static void mlx5e_detach_encap(struct mlx5e_priv *priv,
mlx5e_rep_encap_entry_detach(netdev_priv(e->out_dev), e);
if (e->flags & MLX5_ENCAP_ENTRY_VALID)
- mlx5_encap_dealloc(priv->mdev, e->encap_id);
+ mlx5_packet_reformat_dealloc(priv->mdev, e->encap_id);
hash_del_rcu(&e->encap_hlist);
kfree(e->encap_header);
@@ -1105,6 +1225,7 @@ static int parse_tunnel_attr(struct mlx5e_priv *priv,
struct mlx5_flow_spec *spec,
struct tc_cls_flower_offload *f)
{
+ struct netlink_ext_ack *extack = f->common.extack;
void *headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
outer_headers);
void *headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
@@ -1133,6 +1254,8 @@ static int parse_tunnel_attr(struct mlx5e_priv *priv,
MLX5_CAP_ESW(priv->mdev, vxlan_encap_decap))
parse_vxlan_attr(spec, f);
else {
+ NL_SET_ERR_MSG_MOD(extack,
+ "port isn't an offloaded vxlan udp dport");
netdev_warn(priv->netdev,
"%d isn't an offloaded vxlan udp dport\n", be16_to_cpu(key->dst));
return -EOPNOTSUPP;
@@ -1149,6 +1272,8 @@ static int parse_tunnel_attr(struct mlx5e_priv *priv,
udp_sport, ntohs(key->src));
} else { /* udp dst port must be given */
vxlan_match_offload_err:
+ NL_SET_ERR_MSG_MOD(extack,
+ "IP tunnel decap offload supported only for vxlan, must set UDP dport");
netdev_warn(priv->netdev,
"IP tunnel decap offload supported only for vxlan, must set UDP dport\n");
return -EOPNOTSUPP;
@@ -1225,6 +1350,16 @@ vxlan_match_offload_err:
MLX5_SET(fte_match_set_lyr_2_4, headers_c, ttl_hoplimit, mask->ttl);
MLX5_SET(fte_match_set_lyr_2_4, headers_v, ttl_hoplimit, key->ttl);
+
+ if (mask->ttl &&
+ !MLX5_CAP_ESW_FLOWTABLE_FDB
+ (priv->mdev,
+ ft_field_support.outer_ipv4_ttl)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Matching on TTL is not supported");
+ return -EOPNOTSUPP;
+ }
+
}
/* Enforce DMAC when offloading incoming tunneled flows.
@@ -1247,6 +1382,7 @@ static int __parse_cls_flower(struct mlx5e_priv *priv,
struct tc_cls_flower_offload *f,
u8 *match_level)
{
+ struct netlink_ext_ack *extack = f->common.extack;
void *headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
outer_headers);
void *headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
@@ -1277,6 +1413,7 @@ static int __parse_cls_flower(struct mlx5e_priv *priv,
BIT(FLOW_DISSECTOR_KEY_TCP) |
BIT(FLOW_DISSECTOR_KEY_IP) |
BIT(FLOW_DISSECTOR_KEY_ENC_IP))) {
+ NL_SET_ERR_MSG_MOD(extack, "Unsupported key");
netdev_warn(priv->netdev, "Unsupported key used: 0x%x\n",
f->dissector->used_keys);
return -EOPNOTSUPP;
@@ -1368,6 +1505,9 @@ static int __parse_cls_flower(struct mlx5e_priv *priv,
*match_level = MLX5_MATCH_L2;
}
+ } else {
+ MLX5_SET(fte_match_set_lyr_2_4, headers_c, svlan_tag, 1);
+ MLX5_SET(fte_match_set_lyr_2_4, headers_c, cvlan_tag, 1);
}
if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_CVLAN)) {
@@ -1550,8 +1690,11 @@ static int __parse_cls_flower(struct mlx5e_priv *priv,
if (mask->ttl &&
!MLX5_CAP_ESW_FLOWTABLE_FDB(priv->mdev,
- ft_field_support.outer_ipv4_ttl))
+ ft_field_support.outer_ipv4_ttl)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Matching on TTL is not supported");
return -EOPNOTSUPP;
+ }
if (mask->tos || mask->ttl)
*match_level = MLX5_MATCH_L3;
@@ -1593,6 +1736,8 @@ static int __parse_cls_flower(struct mlx5e_priv *priv,
udp_dport, ntohs(key->dst));
break;
default:
+ NL_SET_ERR_MSG_MOD(extack,
+ "Only UDP and TCP transports are supported for L4 matching");
netdev_err(priv->netdev,
"Only UDP and TCP transport are supported\n");
return -EINVAL;
@@ -1629,6 +1774,7 @@ static int parse_cls_flower(struct mlx5e_priv *priv,
struct mlx5_flow_spec *spec,
struct tc_cls_flower_offload *f)
{
+ struct netlink_ext_ack *extack = f->common.extack;
struct mlx5_core_dev *dev = priv->mdev;
struct mlx5_eswitch *esw = dev->priv.eswitch;
struct mlx5e_rep_priv *rpriv = priv->ppriv;
@@ -1643,6 +1789,8 @@ static int parse_cls_flower(struct mlx5e_priv *priv,
if (rep->vport != FDB_UPLINK_VPORT &&
(esw->offloads.inline_mode != MLX5_INLINE_MODE_NONE &&
esw->offloads.inline_mode < match_level)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Flow is not offloaded due to min inline setting");
netdev_warn(priv->netdev,
"Flow is not offloaded due to min inline setting, required %d actual %d\n",
match_level, esw->offloads.inline_mode);
@@ -1744,7 +1892,8 @@ static struct mlx5_fields fields[] = {
*/
static int offload_pedit_fields(struct pedit_headers *masks,
struct pedit_headers *vals,
- struct mlx5e_tc_flow_parse_attr *parse_attr)
+ struct mlx5e_tc_flow_parse_attr *parse_attr,
+ struct netlink_ext_ack *extack)
{
struct pedit_headers *set_masks, *add_masks, *set_vals, *add_vals;
int i, action_size, nactions, max_actions, first, last, next_z;
@@ -1783,11 +1932,15 @@ static int offload_pedit_fields(struct pedit_headers *masks,
continue;
if (s_mask && a_mask) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "can't set and add to the same HW field");
printk(KERN_WARNING "mlx5: can't set and add to the same HW field (%x)\n", f->field);
return -EOPNOTSUPP;
}
if (nactions == max_actions) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "too many pedit actions, can't offload");
printk(KERN_WARNING "mlx5: parsed %d pedit actions, can't do more\n", nactions);
return -EOPNOTSUPP;
}
@@ -1820,6 +1973,8 @@ static int offload_pedit_fields(struct pedit_headers *masks,
next_z = find_next_zero_bit(&mask, field_bsize, first);
last = find_last_bit(&mask, field_bsize);
if (first < next_z && next_z < last) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "rewrite of few sub-fields isn't supported");
printk(KERN_WARNING "mlx5: rewrite of few sub-fields (mask %lx) isn't offloaded\n",
mask);
return -EOPNOTSUPP;
@@ -1878,7 +2033,8 @@ static const struct pedit_headers zero_masks = {};
static int parse_tc_pedit_action(struct mlx5e_priv *priv,
const struct tc_action *a, int namespace,
- struct mlx5e_tc_flow_parse_attr *parse_attr)
+ struct mlx5e_tc_flow_parse_attr *parse_attr,
+ struct netlink_ext_ack *extack)
{
struct pedit_headers masks[__PEDIT_CMD_MAX], vals[__PEDIT_CMD_MAX], *cmd_masks;
int nkeys, i, err = -EOPNOTSUPP;
@@ -1896,12 +2052,13 @@ static int parse_tc_pedit_action(struct mlx5e_priv *priv,
err = -EOPNOTSUPP; /* can't be all optimistic */
if (htype == TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK) {
- netdev_warn(priv->netdev, "legacy pedit isn't offloaded\n");
+ NL_SET_ERR_MSG_MOD(extack,
+ "legacy pedit isn't offloaded");
goto out_err;
}
if (cmd != TCA_PEDIT_KEY_EX_CMD_SET && cmd != TCA_PEDIT_KEY_EX_CMD_ADD) {
- netdev_warn(priv->netdev, "pedit cmd %d isn't offloaded\n", cmd);
+ NL_SET_ERR_MSG_MOD(extack, "pedit cmd isn't offloaded");
goto out_err;
}
@@ -1918,13 +2075,15 @@ static int parse_tc_pedit_action(struct mlx5e_priv *priv,
if (err)
goto out_err;
- err = offload_pedit_fields(masks, vals, parse_attr);
+ err = offload_pedit_fields(masks, vals, parse_attr, extack);
if (err < 0)
goto out_dealloc_parsed_actions;
for (cmd = 0; cmd < __PEDIT_CMD_MAX; cmd++) {
cmd_masks = &masks[cmd];
if (memcmp(cmd_masks, &zero_masks, sizeof(zero_masks))) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "attempt to offload an unsupported field");
netdev_warn(priv->netdev, "attempt to offload an unsupported field (cmd %d)\n", cmd);
print_hex_dump(KERN_WARNING, "mask: ", DUMP_PREFIX_ADDRESS,
16, 1, cmd_masks, sizeof(zero_masks), true);
@@ -1941,19 +2100,26 @@ out_err:
return err;
}
-static bool csum_offload_supported(struct mlx5e_priv *priv, u32 action, u32 update_flags)
+static bool csum_offload_supported(struct mlx5e_priv *priv,
+ u32 action,
+ u32 update_flags,
+ struct netlink_ext_ack *extack)
{
u32 prot_flags = TCA_CSUM_UPDATE_FLAG_IPV4HDR | TCA_CSUM_UPDATE_FLAG_TCP |
TCA_CSUM_UPDATE_FLAG_UDP;
/* The HW recalcs checksums only if re-writing headers */
if (!(action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "TC csum action is only offloaded with pedit");
netdev_warn(priv->netdev,
"TC csum action is only offloaded with pedit\n");
return false;
}
if (update_flags & ~prot_flags) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "can't offload TC csum action for some header/s");
netdev_warn(priv->netdev,
"can't offload TC csum action for some header/s - flags %#x\n",
update_flags);
@@ -1964,7 +2130,8 @@ static bool csum_offload_supported(struct mlx5e_priv *priv, u32 action, u32 upda
}
static bool modify_header_match_supported(struct mlx5_flow_spec *spec,
- struct tcf_exts *exts)
+ struct tcf_exts *exts,
+ struct netlink_ext_ack *extack)
{
const struct tc_action *a;
bool modify_ip_header;
@@ -2002,6 +2169,8 @@ static bool modify_header_match_supported(struct mlx5_flow_spec *spec,
ip_proto = MLX5_GET(fte_match_set_lyr_2_4, headers_v, ip_protocol);
if (modify_ip_header && ip_proto != IPPROTO_TCP &&
ip_proto != IPPROTO_UDP && ip_proto != IPPROTO_ICMP) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "can't offload re-write of non TCP/UDP");
pr_info("can't offload re-write of ip proto %d\n", ip_proto);
return false;
}
@@ -2013,7 +2182,8 @@ out_ok:
static bool actions_match_supported(struct mlx5e_priv *priv,
struct tcf_exts *exts,
struct mlx5e_tc_flow_parse_attr *parse_attr,
- struct mlx5e_tc_flow *flow)
+ struct mlx5e_tc_flow *flow,
+ struct netlink_ext_ack *extack)
{
u32 actions;
@@ -2027,7 +2197,8 @@ static bool actions_match_supported(struct mlx5e_priv *priv,
return false;
if (actions & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
- return modify_header_match_supported(&parse_attr->spec, exts);
+ return modify_header_match_supported(&parse_attr->spec, exts,
+ extack);
return true;
}
@@ -2040,15 +2211,16 @@ static bool same_hw_devs(struct mlx5e_priv *priv, struct mlx5e_priv *peer_priv)
fmdev = priv->mdev;
pmdev = peer_priv->mdev;
- mlx5_query_nic_vport_system_image_guid(fmdev, &fsystem_guid);
- mlx5_query_nic_vport_system_image_guid(pmdev, &psystem_guid);
+ fsystem_guid = mlx5_query_nic_system_image_guid(fmdev);
+ psystem_guid = mlx5_query_nic_system_image_guid(pmdev);
return (fsystem_guid == psystem_guid);
}
static int parse_tc_nic_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
struct mlx5e_tc_flow_parse_attr *parse_attr,
- struct mlx5e_tc_flow *flow)
+ struct mlx5e_tc_flow *flow,
+ struct netlink_ext_ack *extack)
{
struct mlx5_nic_flow_attr *attr = flow->nic_attr;
const struct tc_action *a;
@@ -2072,7 +2244,7 @@ static int parse_tc_nic_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
if (is_tcf_pedit(a)) {
err = parse_tc_pedit_action(priv, a, MLX5_FLOW_NAMESPACE_KERNEL,
- parse_attr);
+ parse_attr, extack);
if (err)
return err;
@@ -2083,7 +2255,8 @@ static int parse_tc_nic_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
if (is_tcf_csum(a)) {
if (csum_offload_supported(priv, action,
- tcf_csum_update_flags(a)))
+ tcf_csum_update_flags(a),
+ extack))
continue;
return -EOPNOTSUPP;
@@ -2099,6 +2272,8 @@ static int parse_tc_nic_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
MLX5_FLOW_CONTEXT_ACTION_COUNT;
} else {
+ NL_SET_ERR_MSG_MOD(extack,
+ "device is not on same HW, can't offload");
netdev_warn(priv->netdev, "device %s not on same HW, can't offload\n",
peer_dev->name);
return -EINVAL;
@@ -2110,8 +2285,8 @@ static int parse_tc_nic_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
u32 mark = tcf_skbedit_mark(a);
if (mark & ~MLX5E_TC_FLOW_ID_MASK) {
- netdev_warn(priv->netdev, "Bad flow mark - only 16 bit is supported: 0x%x\n",
- mark);
+ NL_SET_ERR_MSG_MOD(extack,
+ "Bad flow mark - only 16 bit is supported");
return -EINVAL;
}
@@ -2124,7 +2299,7 @@ static int parse_tc_nic_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
}
attr->action = action;
- if (!actions_match_supported(priv, exts, parse_attr, flow))
+ if (!actions_match_supported(priv, exts, parse_attr, flow, extack))
return -EOPNOTSUPP;
return 0;
@@ -2328,7 +2503,7 @@ static int mlx5e_create_encap_header_ipv4(struct mlx5e_priv *priv,
return -ENOMEM;
switch (e->tunnel_type) {
- case MLX5_HEADER_TYPE_VXLAN:
+ case MLX5_REFORMAT_TYPE_L2_TO_VXLAN:
fl4.flowi4_proto = IPPROTO_UDP;
fl4.fl4_dport = tun_key->tp_dst;
break;
@@ -2372,7 +2547,7 @@ static int mlx5e_create_encap_header_ipv4(struct mlx5e_priv *priv,
read_unlock_bh(&n->lock);
switch (e->tunnel_type) {
- case MLX5_HEADER_TYPE_VXLAN:
+ case MLX5_REFORMAT_TYPE_L2_TO_VXLAN:
gen_vxlan_header_ipv4(out_dev, encap_header,
ipv4_encap_size, e->h_dest, tos, ttl,
fl4.daddr,
@@ -2392,8 +2567,10 @@ static int mlx5e_create_encap_header_ipv4(struct mlx5e_priv *priv,
goto out;
}
- err = mlx5_encap_alloc(priv->mdev, e->tunnel_type,
- ipv4_encap_size, encap_header, &e->encap_id);
+ err = mlx5_packet_reformat_alloc(priv->mdev, e->tunnel_type,
+ ipv4_encap_size, encap_header,
+ MLX5_FLOW_NAMESPACE_FDB,
+ &e->encap_id);
if (err)
goto destroy_neigh_entry;
@@ -2437,7 +2614,7 @@ static int mlx5e_create_encap_header_ipv6(struct mlx5e_priv *priv,
return -ENOMEM;
switch (e->tunnel_type) {
- case MLX5_HEADER_TYPE_VXLAN:
+ case MLX5_REFORMAT_TYPE_L2_TO_VXLAN:
fl6.flowi6_proto = IPPROTO_UDP;
fl6.fl6_dport = tun_key->tp_dst;
break;
@@ -2481,7 +2658,7 @@ static int mlx5e_create_encap_header_ipv6(struct mlx5e_priv *priv,
read_unlock_bh(&n->lock);
switch (e->tunnel_type) {
- case MLX5_HEADER_TYPE_VXLAN:
+ case MLX5_REFORMAT_TYPE_L2_TO_VXLAN:
gen_vxlan_header_ipv6(out_dev, encap_header,
ipv6_encap_size, e->h_dest, tos, ttl,
&fl6.daddr,
@@ -2502,8 +2679,10 @@ static int mlx5e_create_encap_header_ipv6(struct mlx5e_priv *priv,
goto out;
}
- err = mlx5_encap_alloc(priv->mdev, e->tunnel_type,
- ipv6_encap_size, encap_header, &e->encap_id);
+ err = mlx5_packet_reformat_alloc(priv->mdev, e->tunnel_type,
+ ipv6_encap_size, encap_header,
+ MLX5_FLOW_NAMESPACE_FDB,
+ &e->encap_id);
if (err)
goto destroy_neigh_entry;
@@ -2526,7 +2705,8 @@ static int mlx5e_attach_encap(struct mlx5e_priv *priv,
struct ip_tunnel_info *tun_info,
struct net_device *mirred_dev,
struct net_device **encap_dev,
- struct mlx5e_tc_flow *flow)
+ struct mlx5e_tc_flow *flow,
+ struct netlink_ext_ack *extack)
{
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
unsigned short family = ip_tunnel_info_af(tun_info);
@@ -2544,6 +2724,8 @@ static int mlx5e_attach_encap(struct mlx5e_priv *priv,
/* setting udp src port isn't supported */
if (memchr_inv(&key->tp_src, 0, sizeof(key->tp_src))) {
vxlan_encap_offload_err:
+ NL_SET_ERR_MSG_MOD(extack,
+ "must set udp dst port and not set udp src port");
netdev_warn(priv->netdev,
"must set udp dst port and not set udp src port\n");
return -EOPNOTSUPP;
@@ -2551,8 +2733,10 @@ vxlan_encap_offload_err:
if (mlx5_vxlan_lookup_port(priv->mdev->vxlan, be16_to_cpu(key->tp_dst)) &&
MLX5_CAP_ESW(priv->mdev, vxlan_encap_decap)) {
- tunnel_type = MLX5_HEADER_TYPE_VXLAN;
+ tunnel_type = MLX5_REFORMAT_TYPE_L2_TO_VXLAN;
} else {
+ NL_SET_ERR_MSG_MOD(extack,
+ "port isn't an offloaded vxlan udp dport");
netdev_warn(priv->netdev,
"%d isn't an offloaded vxlan udp dport\n", be16_to_cpu(key->tp_dst));
return -EOPNOTSUPP;
@@ -2657,8 +2841,10 @@ static int parse_tc_vlan_action(struct mlx5e_priv *priv,
static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
struct mlx5e_tc_flow_parse_attr *parse_attr,
- struct mlx5e_tc_flow *flow)
+ struct mlx5e_tc_flow *flow,
+ struct netlink_ext_ack *extack)
{
+ struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
struct mlx5_esw_flow_attr *attr = flow->esw_attr;
struct mlx5e_rep_priv *rpriv = priv->ppriv;
struct ip_tunnel_info *info = NULL;
@@ -2683,7 +2869,7 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
if (is_tcf_pedit(a)) {
err = parse_tc_pedit_action(priv, a, MLX5_FLOW_NAMESPACE_FDB,
- parse_attr);
+ parse_attr, extack);
if (err)
return err;
@@ -2694,7 +2880,8 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
if (is_tcf_csum(a)) {
if (csum_offload_supported(priv, action,
- tcf_csum_update_flags(a)))
+ tcf_csum_update_flags(a),
+ extack))
continue;
return -EOPNOTSUPP;
@@ -2707,6 +2894,8 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
out_dev = tcf_mirred_dev(a);
if (attr->out_count >= MLX5_MAX_FLOW_FWD_VPORTS) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "can't support more output ports, can't offload forwarding");
pr_err("can't support more than %d output ports, can't offload forwarding\n",
attr->out_count);
return -EOPNOTSUPP;
@@ -2725,11 +2914,13 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
parse_attr->mirred_ifindex = out_dev->ifindex;
parse_attr->tun_info = *info;
attr->parse_attr = parse_attr;
- action |= MLX5_FLOW_CONTEXT_ACTION_ENCAP |
+ action |= MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT |
MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
MLX5_FLOW_CONTEXT_ACTION_COUNT;
/* attr->out_rep is resolved when we handle encap */
} else {
+ NL_SET_ERR_MSG_MOD(extack,
+ "devices are not on same switch HW, can't offload forwarding");
pr_err("devices %s %s not on same switch HW, can't offload forwarding\n",
priv->netdev->name, out_dev->name);
return -EINVAL;
@@ -2762,14 +2953,35 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
continue;
}
+ if (is_tcf_gact_goto_chain(a)) {
+ u32 dest_chain = tcf_gact_goto_chain_index(a);
+ u32 max_chain = mlx5_eswitch_get_chain_range(esw);
+
+ if (dest_chain <= attr->chain) {
+ NL_SET_ERR_MSG(extack, "Goto earlier chain isn't supported");
+ return -EOPNOTSUPP;
+ }
+ if (dest_chain > max_chain) {
+ NL_SET_ERR_MSG(extack, "Requested destination chain is out of supported range");
+ return -EOPNOTSUPP;
+ }
+ action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
+ MLX5_FLOW_CONTEXT_ACTION_COUNT;
+ attr->dest_chain = dest_chain;
+
+ continue;
+ }
+
return -EINVAL;
}
attr->action = action;
- if (!actions_match_supported(priv, exts, parse_attr, flow))
+ if (!actions_match_supported(priv, exts, parse_attr, flow, extack))
return -EOPNOTSUPP;
if (attr->out_count > 1 && !mlx5_esw_has_fwd_fdb(priv->mdev)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "current firmware doesn't support split rule for port mirroring");
netdev_warn_once(priv->netdev, "current firmware doesn't support split rule for port mirroring\n");
return -EOPNOTSUPP;
}
@@ -2777,9 +2989,9 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
return 0;
}
-static void get_flags(int flags, u8 *flow_flags)
+static void get_flags(int flags, u16 *flow_flags)
{
- u8 __flow_flags = 0;
+ u16 __flow_flags = 0;
if (flags & MLX5E_TC_INGRESS)
__flow_flags |= MLX5E_TC_FLOW_INGRESS;
@@ -2808,31 +3020,15 @@ static struct rhashtable *get_tc_ht(struct mlx5e_priv *priv)
return &priv->fs.tc.ht;
}
-int mlx5e_configure_flower(struct mlx5e_priv *priv,
- struct tc_cls_flower_offload *f, int flags)
+static int
+mlx5e_alloc_flow(struct mlx5e_priv *priv, int attr_size,
+ struct tc_cls_flower_offload *f, u16 flow_flags,
+ struct mlx5e_tc_flow_parse_attr **__parse_attr,
+ struct mlx5e_tc_flow **__flow)
{
- struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
struct mlx5e_tc_flow_parse_attr *parse_attr;
- struct rhashtable *tc_ht = get_tc_ht(priv);
struct mlx5e_tc_flow *flow;
- int attr_size, err = 0;
- u8 flow_flags = 0;
-
- get_flags(flags, &flow_flags);
-
- flow = rhashtable_lookup_fast(tc_ht, &f->cookie, tc_ht_params);
- if (flow) {
- netdev_warn_once(priv->netdev, "flow cookie %lx already exists, ignoring\n", f->cookie);
- return 0;
- }
-
- if (esw && esw->mode == SRIOV_OFFLOADS) {
- flow_flags |= MLX5E_TC_FLOW_ESWITCH;
- attr_size = sizeof(struct mlx5_esw_flow_attr);
- } else {
- flow_flags |= MLX5E_TC_FLOW_NIC;
- attr_size = sizeof(struct mlx5_nic_flow_attr);
- }
+ int err;
flow = kzalloc(sizeof(*flow) + attr_size, GFP_KERNEL);
parse_attr = kvzalloc(sizeof(*parse_attr), GFP_KERNEL);
@@ -2846,45 +3042,161 @@ int mlx5e_configure_flower(struct mlx5e_priv *priv,
flow->priv = priv;
err = parse_cls_flower(priv, flow, &parse_attr->spec, f);
- if (err < 0)
+ if (err)
goto err_free;
- if (flow->flags & MLX5E_TC_FLOW_ESWITCH) {
- err = parse_tc_fdb_actions(priv, f->exts, parse_attr, flow);
- if (err < 0)
- goto err_free;
- flow->rule[0] = mlx5e_tc_add_fdb_flow(priv, parse_attr, flow);
- } else {
- err = parse_tc_nic_actions(priv, f->exts, parse_attr, flow);
- if (err < 0)
- goto err_free;
- flow->rule[0] = mlx5e_tc_add_nic_flow(priv, parse_attr, flow);
- }
+ *__flow = flow;
+ *__parse_attr = parse_attr;
- if (IS_ERR(flow->rule[0])) {
- err = PTR_ERR(flow->rule[0]);
- if (err != -EAGAIN)
- goto err_free;
- }
+ return 0;
- if (err != -EAGAIN)
- flow->flags |= MLX5E_TC_FLOW_OFFLOADED;
+err_free:
+ kfree(flow);
+ kvfree(parse_attr);
+ return err;
+}
+
+static int
+mlx5e_add_fdb_flow(struct mlx5e_priv *priv,
+ struct tc_cls_flower_offload *f,
+ u16 flow_flags,
+ struct mlx5e_tc_flow **__flow)
+{
+ struct netlink_ext_ack *extack = f->common.extack;
+ struct mlx5e_tc_flow_parse_attr *parse_attr;
+ struct mlx5e_tc_flow *flow;
+ int attr_size, err;
+
+ flow_flags |= MLX5E_TC_FLOW_ESWITCH;
+ attr_size = sizeof(struct mlx5_esw_flow_attr);
+ err = mlx5e_alloc_flow(priv, attr_size, f, flow_flags,
+ &parse_attr, &flow);
+ if (err)
+ goto out;
+
+ flow->esw_attr->chain = f->common.chain_index;
+ flow->esw_attr->prio = TC_H_MAJ(f->common.prio) >> 16;
+ err = parse_tc_fdb_actions(priv, f->exts, parse_attr, flow, extack);
+ if (err)
+ goto err_free;
+
+ err = mlx5e_tc_add_fdb_flow(priv, parse_attr, flow, extack);
+ if (err)
+ goto err_free;
- if (!(flow->flags & MLX5E_TC_FLOW_ESWITCH) ||
- !(flow->esw_attr->action & MLX5_FLOW_CONTEXT_ACTION_ENCAP))
+ if (!(flow->esw_attr->action &
+ MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT))
kvfree(parse_attr);
- err = rhashtable_insert_fast(tc_ht, &flow->node, tc_ht_params);
- if (err) {
- mlx5e_tc_del_flow(priv, flow);
- kfree(flow);
- }
+ *__flow = flow;
+ return 0;
+
+err_free:
+ kfree(flow);
+ kvfree(parse_attr);
+out:
return err;
+}
+
+static int
+mlx5e_add_nic_flow(struct mlx5e_priv *priv,
+ struct tc_cls_flower_offload *f,
+ u16 flow_flags,
+ struct mlx5e_tc_flow **__flow)
+{
+ struct netlink_ext_ack *extack = f->common.extack;
+ struct mlx5e_tc_flow_parse_attr *parse_attr;
+ struct mlx5e_tc_flow *flow;
+ int attr_size, err;
+
+ /* multi-chain not supported for NIC rules */
+ if (!tc_cls_can_offload_and_chain0(priv->netdev, &f->common))
+ return -EOPNOTSUPP;
+
+ flow_flags |= MLX5E_TC_FLOW_NIC;
+ attr_size = sizeof(struct mlx5_nic_flow_attr);
+ err = mlx5e_alloc_flow(priv, attr_size, f, flow_flags,
+ &parse_attr, &flow);
+ if (err)
+ goto out;
+
+ err = parse_tc_nic_actions(priv, f->exts, parse_attr, flow, extack);
+ if (err)
+ goto err_free;
+
+ err = mlx5e_tc_add_nic_flow(priv, parse_attr, flow, extack);
+ if (err)
+ goto err_free;
+
+ flow->flags |= MLX5E_TC_FLOW_OFFLOADED;
+ kvfree(parse_attr);
+ *__flow = flow;
+
+ return 0;
err_free:
+ kfree(flow);
kvfree(parse_attr);
+out:
+ return err;
+}
+
+static int
+mlx5e_tc_add_flow(struct mlx5e_priv *priv,
+ struct tc_cls_flower_offload *f,
+ int flags,
+ struct mlx5e_tc_flow **flow)
+{
+ struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
+ u16 flow_flags;
+ int err;
+
+ get_flags(flags, &flow_flags);
+
+ if (!tc_can_offload_extack(priv->netdev, f->common.extack))
+ return -EOPNOTSUPP;
+
+ if (esw && esw->mode == SRIOV_OFFLOADS)
+ err = mlx5e_add_fdb_flow(priv, f, flow_flags, flow);
+ else
+ err = mlx5e_add_nic_flow(priv, f, flow_flags, flow);
+
+ return err;
+}
+
+int mlx5e_configure_flower(struct mlx5e_priv *priv,
+ struct tc_cls_flower_offload *f, int flags)
+{
+ struct netlink_ext_ack *extack = f->common.extack;
+ struct rhashtable *tc_ht = get_tc_ht(priv);
+ struct mlx5e_tc_flow *flow;
+ int err = 0;
+
+ flow = rhashtable_lookup_fast(tc_ht, &f->cookie, tc_ht_params);
+ if (flow) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "flow cookie already exists, ignoring");
+ netdev_warn_once(priv->netdev,
+ "flow cookie %lx already exists, ignoring\n",
+ f->cookie);
+ goto out;
+ }
+
+ err = mlx5e_tc_add_flow(priv, f, flags, &flow);
+ if (err)
+ goto out;
+
+ err = rhashtable_insert_fast(tc_ht, &flow->node, tc_ht_params);
+ if (err)
+ goto err_free;
+
+ return 0;
+
+err_free:
+ mlx5e_tc_del_flow(priv, flow);
kfree(flow);
+out:
return err;
}
@@ -2935,7 +3247,7 @@ int mlx5e_stats_flower(struct mlx5e_priv *priv,
if (!(flow->flags & MLX5E_TC_FLOW_OFFLOADED))
return 0;
- counter = mlx5_flow_rule_counter(flow->rule[0]);
+ counter = mlx5e_tc_get_counter(flow);
if (!counter)
return 0;
@@ -2946,14 +3258,71 @@ int mlx5e_stats_flower(struct mlx5e_priv *priv,
return 0;
}
+static void mlx5e_tc_hairpin_update_dead_peer(struct mlx5e_priv *priv,
+ struct mlx5e_priv *peer_priv)
+{
+ struct mlx5_core_dev *peer_mdev = peer_priv->mdev;
+ struct mlx5e_hairpin_entry *hpe;
+ u16 peer_vhca_id;
+ int bkt;
+
+ if (!same_hw_devs(priv, peer_priv))
+ return;
+
+ peer_vhca_id = MLX5_CAP_GEN(peer_mdev, vhca_id);
+
+ hash_for_each(priv->fs.tc.hairpin_tbl, bkt, hpe, hairpin_hlist) {
+ if (hpe->peer_vhca_id == peer_vhca_id)
+ hpe->hp->pair->peer_gone = true;
+ }
+}
+
+static int mlx5e_tc_netdev_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ struct net_device *ndev = netdev_notifier_info_to_dev(ptr);
+ struct mlx5e_flow_steering *fs;
+ struct mlx5e_priv *peer_priv;
+ struct mlx5e_tc_table *tc;
+ struct mlx5e_priv *priv;
+
+ if (ndev->netdev_ops != &mlx5e_netdev_ops ||
+ event != NETDEV_UNREGISTER ||
+ ndev->reg_state == NETREG_REGISTERED)
+ return NOTIFY_DONE;
+
+ tc = container_of(this, struct mlx5e_tc_table, netdevice_nb);
+ fs = container_of(tc, struct mlx5e_flow_steering, tc);
+ priv = container_of(fs, struct mlx5e_priv, fs);
+ peer_priv = netdev_priv(ndev);
+ if (priv == peer_priv ||
+ !(priv->netdev->features & NETIF_F_HW_TC))
+ return NOTIFY_DONE;
+
+ mlx5e_tc_hairpin_update_dead_peer(priv, peer_priv);
+
+ return NOTIFY_DONE;
+}
+
int mlx5e_tc_nic_init(struct mlx5e_priv *priv)
{
struct mlx5e_tc_table *tc = &priv->fs.tc;
+ int err;
hash_init(tc->mod_hdr_tbl);
hash_init(tc->hairpin_tbl);
- return rhashtable_init(&tc->ht, &tc_ht_params);
+ err = rhashtable_init(&tc->ht, &tc_ht_params);
+ if (err)
+ return err;
+
+ tc->netdevice_nb.notifier_call = mlx5e_tc_netdev_event;
+ if (register_netdevice_notifier(&tc->netdevice_nb)) {
+ tc->netdevice_nb.notifier_call = NULL;
+ mlx5_core_warn(priv->mdev, "Failed to register netdev notifier\n");
+ }
+
+ return err;
}
static void _mlx5e_tc_del_flow(void *ptr, void *arg)
@@ -2969,6 +3338,9 @@ void mlx5e_tc_nic_cleanup(struct mlx5e_priv *priv)
{
struct mlx5e_tc_table *tc = &priv->fs.tc;
+ if (tc->netdevice_nb.notifier_call)
+ unregister_netdevice_notifier(&tc->netdevice_nb);
+
rhashtable_free_and_destroy(&tc->ht, _mlx5e_tc_del_flow, NULL);
if (!IS_ERR_OR_NULL(tc->t)) {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
index ae73ea992845..6dacaeba2fbf 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
@@ -290,10 +290,9 @@ dma_unmap_wqe_err:
static inline void mlx5e_fill_sq_frag_edge(struct mlx5e_txqsq *sq,
struct mlx5_wq_cyc *wq,
- u16 pi, u16 frag_pi)
+ u16 pi, u16 nnops)
{
struct mlx5e_tx_wqe_info *edge_wi, *wi = &sq->db.wqe_info[pi];
- u8 nnops = mlx5_wq_cyc_get_frag_size(wq) - frag_pi;
edge_wi = wi + nnops;
@@ -348,8 +347,8 @@ netdev_tx_t mlx5e_sq_xmit(struct mlx5e_txqsq *sq, struct sk_buff *skb,
struct mlx5e_tx_wqe_info *wi;
struct mlx5e_sq_stats *stats = sq->stats;
+ u16 headlen, ihs, contig_wqebbs_room;
u16 ds_cnt, ds_cnt_inl = 0;
- u16 headlen, ihs, frag_pi;
u8 num_wqebbs, opcode;
u32 num_bytes;
int num_dma;
@@ -386,9 +385,9 @@ netdev_tx_t mlx5e_sq_xmit(struct mlx5e_txqsq *sq, struct sk_buff *skb,
}
num_wqebbs = DIV_ROUND_UP(ds_cnt, MLX5_SEND_WQEBB_NUM_DS);
- frag_pi = mlx5_wq_cyc_ctr2fragix(wq, sq->pc);
- if (unlikely(frag_pi + num_wqebbs > mlx5_wq_cyc_get_frag_size(wq))) {
- mlx5e_fill_sq_frag_edge(sq, wq, pi, frag_pi);
+ contig_wqebbs_room = mlx5_wq_cyc_get_contig_wqebbs(wq, pi);
+ if (unlikely(contig_wqebbs_room < num_wqebbs)) {
+ mlx5e_fill_sq_frag_edge(sq, wq, pi, contig_wqebbs_room);
mlx5e_sq_fetch_wqe(sq, &wqe, &pi);
}
@@ -636,7 +635,7 @@ netdev_tx_t mlx5i_sq_xmit(struct mlx5e_txqsq *sq, struct sk_buff *skb,
struct mlx5e_tx_wqe_info *wi;
struct mlx5e_sq_stats *stats = sq->stats;
- u16 headlen, ihs, pi, frag_pi;
+ u16 headlen, ihs, pi, contig_wqebbs_room;
u16 ds_cnt, ds_cnt_inl = 0;
u8 num_wqebbs, opcode;
u32 num_bytes;
@@ -672,13 +671,14 @@ netdev_tx_t mlx5i_sq_xmit(struct mlx5e_txqsq *sq, struct sk_buff *skb,
}
num_wqebbs = DIV_ROUND_UP(ds_cnt, MLX5_SEND_WQEBB_NUM_DS);
- frag_pi = mlx5_wq_cyc_ctr2fragix(wq, sq->pc);
- if (unlikely(frag_pi + num_wqebbs > mlx5_wq_cyc_get_frag_size(wq))) {
+ pi = mlx5_wq_cyc_ctr2ix(wq, sq->pc);
+ contig_wqebbs_room = mlx5_wq_cyc_get_contig_wqebbs(wq, pi);
+ if (unlikely(contig_wqebbs_room < num_wqebbs)) {
+ mlx5e_fill_sq_frag_edge(sq, wq, pi, contig_wqebbs_room);
pi = mlx5_wq_cyc_ctr2ix(wq, sq->pc);
- mlx5e_fill_sq_frag_edge(sq, wq, pi, frag_pi);
}
- mlx5i_sq_fetch_wqe(sq, &wqe, &pi);
+ mlx5i_sq_fetch_wqe(sq, &wqe, pi);
/* fill wqe */
wi = &sq->db.wqe_info[pi];
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
index 48864f4988a4..c1e1a16a9b07 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
@@ -273,7 +273,7 @@ static void eq_pf_process(struct mlx5_eq *eq)
case MLX5_PFAULT_SUBTYPE_WQE:
/* WQE based event */
pfault->type =
- be32_to_cpu(pf_eqe->wqe.pftype_wq) >> 24;
+ (be32_to_cpu(pf_eqe->wqe.pftype_wq) >> 24) & 0x7;
pfault->token =
be32_to_cpu(pf_eqe->wqe.token);
pfault->wqe.wq_num =
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
index 2b252cde5cc2..d004957328f9 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
@@ -263,7 +263,7 @@ static int esw_create_legacy_fdb_table(struct mlx5_eswitch *esw)
esw_debug(dev, "Create FDB log_max_size(%d)\n",
MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size));
- root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB);
+ root_ns = mlx5_get_fdb_sub_ns(dev, 0);
if (!root_ns) {
esw_warn(dev, "Failed to get FDB flow namespace\n");
return -EOPNOTSUPP;
@@ -1198,7 +1198,7 @@ static int esw_vport_ingress_config(struct mlx5_eswitch *esw,
if (counter) {
flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_COUNT;
drop_ctr_dst.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
- drop_ctr_dst.counter = counter;
+ drop_ctr_dst.counter_id = mlx5_fc_id(counter);
dst = &drop_ctr_dst;
dest_num++;
}
@@ -1285,7 +1285,7 @@ static int esw_vport_egress_config(struct mlx5_eswitch *esw,
if (counter) {
flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_COUNT;
drop_ctr_dst.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
- drop_ctr_dst.counter = counter;
+ drop_ctr_dst.counter_id = mlx5_fc_id(counter);
dst = &drop_ctr_dst;
dest_num++;
}
@@ -1746,7 +1746,7 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev)
esw->enabled_vports = 0;
esw->mode = SRIOV_NONE;
esw->offloads.inline_mode = MLX5_INLINE_MODE_NONE;
- if (MLX5_CAP_ESW_FLOWTABLE_FDB(dev, encap) &&
+ if (MLX5_CAP_ESW_FLOWTABLE_FDB(dev, reformat) &&
MLX5_CAP_ESW_FLOWTABLE_FDB(dev, decap))
esw->offloads.encap = DEVLINK_ESWITCH_ENCAP_MODE_BASIC;
else
@@ -2000,7 +2000,7 @@ static u32 calculate_vports_min_rate_divider(struct mlx5_eswitch *esw)
u32 max_guarantee = 0;
int i;
- for (i = 0; i <= esw->total_vports; i++) {
+ for (i = 0; i < esw->total_vports; i++) {
evport = &esw->vports[i];
if (!evport->enabled || evport->info.min_rate < max_guarantee)
continue;
@@ -2020,7 +2020,7 @@ static int normalize_vports_min_rate(struct mlx5_eswitch *esw, u32 divider)
int err;
int i;
- for (i = 0; i <= esw->total_vports; i++) {
+ for (i = 0; i < esw->total_vports; i++) {
evport = &esw->vports[i];
if (!evport->enabled)
continue;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
index c17bfcab517c..aaafc9f17115 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
@@ -59,6 +59,10 @@
#define mlx5_esw_has_fwd_fdb(dev) \
MLX5_CAP_ESW_FLOWTABLE(dev, fdb_multi_path_to_table)
+#define FDB_MAX_CHAIN 3
+#define FDB_SLOW_PATH_CHAIN (FDB_MAX_CHAIN + 1)
+#define FDB_MAX_PRIO 16
+
struct vport_ingress {
struct mlx5_flow_table *acl;
struct mlx5_flow_group *allow_untagged_spoofchk_grp;
@@ -120,6 +124,13 @@ struct mlx5_vport {
u16 enabled_events;
};
+enum offloads_fdb_flags {
+ ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED = BIT(0),
+};
+
+extern const unsigned int ESW_POOLS[4];
+
+#define PRIO_LEVELS 2
struct mlx5_eswitch_fdb {
union {
struct legacy_fdb {
@@ -130,16 +141,24 @@ struct mlx5_eswitch_fdb {
} legacy;
struct offloads_fdb {
- struct mlx5_flow_table *fast_fdb;
- struct mlx5_flow_table *fwd_fdb;
struct mlx5_flow_table *slow_fdb;
struct mlx5_flow_group *send_to_vport_grp;
struct mlx5_flow_group *miss_grp;
struct mlx5_flow_handle *miss_rule_uni;
struct mlx5_flow_handle *miss_rule_multi;
int vlan_push_pop_refcount;
+
+ struct {
+ struct mlx5_flow_table *fdb;
+ u32 num_rules;
+ } fdb_prio[FDB_MAX_CHAIN + 1][FDB_MAX_PRIO + 1][PRIO_LEVELS];
+ /* Protects fdb_prio table */
+ struct mutex fdb_prio_lock;
+
+ int fdb_left[ARRAY_SIZE(ESW_POOLS)];
} offloads;
};
+ u32 flags;
};
struct mlx5_esw_offload {
@@ -181,6 +200,7 @@ struct mlx5_eswitch {
struct mlx5_esw_offload offloads;
int mode;
+ int nvports;
};
void esw_offloads_cleanup(struct mlx5_eswitch *esw, int nvports);
@@ -228,9 +248,23 @@ void
mlx5_eswitch_del_offloaded_rule(struct mlx5_eswitch *esw,
struct mlx5_flow_handle *rule,
struct mlx5_esw_flow_attr *attr);
+void
+mlx5_eswitch_del_fwd_rule(struct mlx5_eswitch *esw,
+ struct mlx5_flow_handle *rule,
+ struct mlx5_esw_flow_attr *attr);
+
+bool
+mlx5_eswitch_prios_supported(struct mlx5_eswitch *esw);
+
+u16
+mlx5_eswitch_get_prio_range(struct mlx5_eswitch *esw);
+
+u32
+mlx5_eswitch_get_chain_range(struct mlx5_eswitch *esw);
struct mlx5_flow_handle *
-mlx5_eswitch_create_vport_rx_rule(struct mlx5_eswitch *esw, int vport, u32 tirn);
+mlx5_eswitch_create_vport_rx_rule(struct mlx5_eswitch *esw, int vport,
+ struct mlx5_flow_destination *dest);
enum {
SET_VLAN_STRIP = BIT(0),
@@ -265,15 +299,22 @@ struct mlx5_esw_flow_attr {
u32 encap_id;
u32 mod_hdr_id;
u8 match_level;
+ struct mlx5_fc *counter;
+ u32 chain;
+ u16 prio;
+ u32 dest_chain;
struct mlx5e_tc_flow_parse_attr *parse_attr;
};
-int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode);
+int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
+ struct netlink_ext_ack *extack);
int mlx5_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode);
-int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode);
+int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode,
+ struct netlink_ext_ack *extack);
int mlx5_devlink_eswitch_inline_mode_get(struct devlink *devlink, u8 *mode);
int mlx5_eswitch_inline_mode_get(struct mlx5_eswitch *esw, int nvfs, u8 *mode);
-int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink, u8 encap);
+int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink, u8 encap,
+ struct netlink_ext_ack *extack);
int mlx5_devlink_eswitch_encap_mode_get(struct devlink *devlink, u8 *encap);
void *mlx5_eswitch_get_uplink_priv(struct mlx5_eswitch *esw, u8 rep_type);
@@ -314,6 +355,11 @@ static inline void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw) {}
static inline void mlx5_eswitch_vport_event(struct mlx5_eswitch *esw, struct mlx5_eqe *eqe) {}
static inline int mlx5_eswitch_enable_sriov(struct mlx5_eswitch *esw, int nvfs, int mode) { return 0; }
static inline void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw) {}
+
+#define FDB_MAX_CHAIN 1
+#define FDB_SLOW_PATH_CHAIN (FDB_MAX_CHAIN + 1)
+#define FDB_MAX_PRIO 1
+
#endif /* CONFIG_MLX5_ESWITCH */
#endif /* __MLX5_ESWITCH_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
index 3028e8d90920..9eac137790f5 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
@@ -37,33 +37,59 @@
#include <linux/mlx5/fs.h>
#include "mlx5_core.h"
#include "eswitch.h"
+#include "en.h"
+#include "fs_core.h"
enum {
FDB_FAST_PATH = 0,
FDB_SLOW_PATH
};
+#define fdb_prio_table(esw, chain, prio, level) \
+ (esw)->fdb_table.offloads.fdb_prio[(chain)][(prio)][(level)]
+
+static struct mlx5_flow_table *
+esw_get_prio_table(struct mlx5_eswitch *esw, u32 chain, u16 prio, int level);
+static void
+esw_put_prio_table(struct mlx5_eswitch *esw, u32 chain, u16 prio, int level);
+
+bool mlx5_eswitch_prios_supported(struct mlx5_eswitch *esw)
+{
+ return (!!(esw->fdb_table.flags & ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED));
+}
+
+u32 mlx5_eswitch_get_chain_range(struct mlx5_eswitch *esw)
+{
+ if (esw->fdb_table.flags & ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED)
+ return FDB_MAX_CHAIN;
+
+ return 0;
+}
+
+u16 mlx5_eswitch_get_prio_range(struct mlx5_eswitch *esw)
+{
+ if (esw->fdb_table.flags & ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED)
+ return FDB_MAX_PRIO;
+
+ return 1;
+}
+
struct mlx5_flow_handle *
mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
struct mlx5_flow_spec *spec,
struct mlx5_esw_flow_attr *attr)
{
struct mlx5_flow_destination dest[MLX5_MAX_FLOW_FWD_VPORTS + 1] = {};
- struct mlx5_flow_act flow_act = {0};
- struct mlx5_flow_table *ft = NULL;
- struct mlx5_fc *counter = NULL;
+ struct mlx5_flow_act flow_act = { .flags = FLOW_ACT_NO_APPEND, };
+ bool mirror = !!(attr->mirror_count);
struct mlx5_flow_handle *rule;
+ struct mlx5_flow_table *fdb;
int j, i = 0;
void *misc;
if (esw->mode != SRIOV_OFFLOADS)
return ERR_PTR(-EOPNOTSUPP);
- if (attr->mirror_count)
- ft = esw->fdb_table.offloads.fwd_fdb;
- else
- ft = esw->fdb_table.offloads.fast_fdb;
-
flow_act.action = attr->action;
/* if per flow vlan pop/push is emulated, don't set that into the firmware */
if (!mlx5_eswitch_vlan_actions_supported(esw->dev, 1))
@@ -81,23 +107,33 @@ mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
}
if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) {
- for (j = attr->mirror_count; j < attr->out_count; j++) {
- dest[i].type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
- dest[i].vport.num = attr->out_rep[j]->vport;
- dest[i].vport.vhca_id =
- MLX5_CAP_GEN(attr->out_mdev[j], vhca_id);
- dest[i].vport.vhca_id_valid = !!MLX5_CAP_ESW(esw->dev, merged_eswitch);
+ if (attr->dest_chain) {
+ struct mlx5_flow_table *ft;
+
+ ft = esw_get_prio_table(esw, attr->dest_chain, 1, 0);
+ if (IS_ERR(ft)) {
+ rule = ERR_CAST(ft);
+ goto err_create_goto_table;
+ }
+
+ dest[i].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
+ dest[i].ft = ft;
i++;
+ } else {
+ for (j = attr->mirror_count; j < attr->out_count; j++) {
+ dest[i].type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
+ dest[i].vport.num = attr->out_rep[j]->vport;
+ dest[i].vport.vhca_id =
+ MLX5_CAP_GEN(attr->out_mdev[j], vhca_id);
+ dest[i].vport.vhca_id_valid =
+ !!MLX5_CAP_ESW(esw->dev, merged_eswitch);
+ i++;
+ }
}
}
if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_COUNT) {
- counter = mlx5_fc_create(esw->dev, true);
- if (IS_ERR(counter)) {
- rule = ERR_CAST(counter);
- goto err_counter_alloc;
- }
dest[i].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
- dest[i].counter = counter;
+ dest[i].counter_id = mlx5_fc_id(attr->counter);
i++;
}
@@ -127,10 +163,16 @@ mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
flow_act.modify_id = attr->mod_hdr_id;
- if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_ENCAP)
- flow_act.encap_id = attr->encap_id;
+ if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT)
+ flow_act.reformat_id = attr->encap_id;
- rule = mlx5_add_flow_rules(ft, spec, &flow_act, dest, i);
+ fdb = esw_get_prio_table(esw, attr->chain, attr->prio, !!mirror);
+ if (IS_ERR(fdb)) {
+ rule = ERR_CAST(fdb);
+ goto err_esw_get;
+ }
+
+ rule = mlx5_add_flow_rules(fdb, spec, &flow_act, dest, i);
if (IS_ERR(rule))
goto err_add_rule;
else
@@ -139,8 +181,11 @@ mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
return rule;
err_add_rule:
- mlx5_fc_destroy(esw->dev, counter);
-err_counter_alloc:
+ esw_put_prio_table(esw, attr->chain, attr->prio, !!mirror);
+err_esw_get:
+ if (attr->dest_chain)
+ esw_put_prio_table(esw, attr->dest_chain, 1, 0);
+err_create_goto_table:
return rule;
}
@@ -150,11 +195,25 @@ mlx5_eswitch_add_fwd_rule(struct mlx5_eswitch *esw,
struct mlx5_esw_flow_attr *attr)
{
struct mlx5_flow_destination dest[MLX5_MAX_FLOW_FWD_VPORTS + 1] = {};
- struct mlx5_flow_act flow_act = {0};
+ struct mlx5_flow_act flow_act = { .flags = FLOW_ACT_NO_APPEND, };
+ struct mlx5_flow_table *fast_fdb;
+ struct mlx5_flow_table *fwd_fdb;
struct mlx5_flow_handle *rule;
void *misc;
int i;
+ fast_fdb = esw_get_prio_table(esw, attr->chain, attr->prio, 0);
+ if (IS_ERR(fast_fdb)) {
+ rule = ERR_CAST(fast_fdb);
+ goto err_get_fast;
+ }
+
+ fwd_fdb = esw_get_prio_table(esw, attr->chain, attr->prio, 1);
+ if (IS_ERR(fwd_fdb)) {
+ rule = ERR_CAST(fwd_fdb);
+ goto err_get_fwd;
+ }
+
flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
for (i = 0; i < attr->mirror_count; i++) {
dest[i].type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
@@ -164,7 +223,7 @@ mlx5_eswitch_add_fwd_rule(struct mlx5_eswitch *esw,
dest[i].vport.vhca_id_valid = !!MLX5_CAP_ESW(esw->dev, merged_eswitch);
}
dest[i].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
- dest[i].ft = esw->fdb_table.offloads.fwd_fdb,
+ dest[i].ft = fwd_fdb,
i++;
misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
@@ -187,25 +246,57 @@ mlx5_eswitch_add_fwd_rule(struct mlx5_eswitch *esw,
spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS |
MLX5_MATCH_MISC_PARAMETERS;
- rule = mlx5_add_flow_rules(esw->fdb_table.offloads.fast_fdb, spec, &flow_act, dest, i);
+ rule = mlx5_add_flow_rules(fast_fdb, spec, &flow_act, dest, i);
- if (!IS_ERR(rule))
- esw->offloads.num_flows++;
+ if (IS_ERR(rule))
+ goto add_err;
+ esw->offloads.num_flows++;
+
+ return rule;
+add_err:
+ esw_put_prio_table(esw, attr->chain, attr->prio, 1);
+err_get_fwd:
+ esw_put_prio_table(esw, attr->chain, attr->prio, 0);
+err_get_fast:
return rule;
}
+static void
+__mlx5_eswitch_del_rule(struct mlx5_eswitch *esw,
+ struct mlx5_flow_handle *rule,
+ struct mlx5_esw_flow_attr *attr,
+ bool fwd_rule)
+{
+ bool mirror = (attr->mirror_count > 0);
+
+ mlx5_del_flow_rules(rule);
+ esw->offloads.num_flows--;
+
+ if (fwd_rule) {
+ esw_put_prio_table(esw, attr->chain, attr->prio, 1);
+ esw_put_prio_table(esw, attr->chain, attr->prio, 0);
+ } else {
+ esw_put_prio_table(esw, attr->chain, attr->prio, !!mirror);
+ if (attr->dest_chain)
+ esw_put_prio_table(esw, attr->dest_chain, 1, 0);
+ }
+}
+
void
mlx5_eswitch_del_offloaded_rule(struct mlx5_eswitch *esw,
struct mlx5_flow_handle *rule,
struct mlx5_esw_flow_attr *attr)
{
- struct mlx5_fc *counter = NULL;
+ __mlx5_eswitch_del_rule(esw, rule, attr, false);
+}
- counter = mlx5_flow_rule_counter(rule);
- mlx5_del_flow_rules(rule);
- mlx5_fc_destroy(esw->dev, counter);
- esw->offloads.num_flows--;
+void
+mlx5_eswitch_del_fwd_rule(struct mlx5_eswitch *esw,
+ struct mlx5_flow_handle *rule,
+ struct mlx5_esw_flow_attr *attr)
+{
+ __mlx5_eswitch_del_rule(esw, rule, attr, true);
}
static int esw_set_global_vlan_pop(struct mlx5_eswitch *esw, u8 val)
@@ -294,7 +385,8 @@ int mlx5_eswitch_add_vlan_action(struct mlx5_eswitch *esw,
push = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH);
pop = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP);
- fwd = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST);
+ fwd = !!((attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) &&
+ !attr->dest_chain);
err = esw_add_vlan_action_check(attr, push, pop, fwd);
if (err)
@@ -501,74 +593,170 @@ out:
#define ESW_OFFLOADS_NUM_GROUPS 4
-static int esw_create_offloads_fast_fdb_table(struct mlx5_eswitch *esw)
+/* Firmware currently has 4 pool of 4 sizes that it supports (ESW_POOLS),
+ * and a virtual memory region of 16M (ESW_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 put/get_sz_to_pool.
+ * Firmware doesn't report any of this for now.
+ * ESW_POOL is expected to be sorted from large to small
+ */
+#define ESW_SIZE (16 * 1024 * 1024)
+const unsigned int ESW_POOLS[4] = { 4 * 1024 * 1024, 1 * 1024 * 1024,
+ 64 * 1024, 4 * 1024 };
+
+static int
+get_sz_from_pool(struct mlx5_eswitch *esw)
+{
+ int sz = 0, i;
+
+ for (i = 0; i < ARRAY_SIZE(ESW_POOLS); i++) {
+ if (esw->fdb_table.offloads.fdb_left[i]) {
+ --esw->fdb_table.offloads.fdb_left[i];
+ sz = ESW_POOLS[i];
+ break;
+ }
+ }
+
+ return sz;
+}
+
+static void
+put_sz_to_pool(struct mlx5_eswitch *esw, int sz)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ESW_POOLS); i++) {
+ if (sz >= ESW_POOLS[i]) {
+ ++esw->fdb_table.offloads.fdb_left[i];
+ break;
+ }
+ }
+}
+
+static struct mlx5_flow_table *
+create_next_size_table(struct mlx5_eswitch *esw,
+ struct mlx5_flow_namespace *ns,
+ u16 table_prio,
+ int level,
+ u32 flags)
+{
+ struct mlx5_flow_table *fdb;
+ int sz;
+
+ sz = get_sz_from_pool(esw);
+ if (!sz)
+ return ERR_PTR(-ENOSPC);
+
+ fdb = mlx5_create_auto_grouped_flow_table(ns,
+ table_prio,
+ sz,
+ ESW_OFFLOADS_NUM_GROUPS,
+ level,
+ flags);
+ if (IS_ERR(fdb)) {
+ esw_warn(esw->dev, "Failed to create FDB Table err %d (table prio: %d, level: %d, size: %d)\n",
+ (int)PTR_ERR(fdb), table_prio, level, sz);
+ put_sz_to_pool(esw, sz);
+ }
+
+ return fdb;
+}
+
+static struct mlx5_flow_table *
+esw_get_prio_table(struct mlx5_eswitch *esw, u32 chain, u16 prio, int level)
{
struct mlx5_core_dev *dev = esw->dev;
- struct mlx5_flow_namespace *root_ns;
struct mlx5_flow_table *fdb = NULL;
- int esw_size, err = 0;
+ struct mlx5_flow_namespace *ns;
+ int table_prio, l = 0;
u32 flags = 0;
- u32 max_flow_counter = (MLX5_CAP_GEN(dev, max_flow_counter_31_16) << 16) |
- MLX5_CAP_GEN(dev, max_flow_counter_15_0);
- root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB);
- if (!root_ns) {
- esw_warn(dev, "Failed to get FDB flow namespace\n");
- err = -EOPNOTSUPP;
- goto out_namespace;
- }
+ if (chain == FDB_SLOW_PATH_CHAIN)
+ return esw->fdb_table.offloads.slow_fdb;
- esw_debug(dev, "Create offloads FDB table, min (max esw size(2^%d), max counters(%d)*groups(%d))\n",
- MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size),
- max_flow_counter, ESW_OFFLOADS_NUM_GROUPS);
+ mutex_lock(&esw->fdb_table.offloads.fdb_prio_lock);
- esw_size = min_t(int, max_flow_counter * ESW_OFFLOADS_NUM_GROUPS,
- 1 << MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size));
+ fdb = fdb_prio_table(esw, chain, prio, level).fdb;
+ if (fdb) {
+ /* take ref on earlier levels as well */
+ while (level >= 0)
+ fdb_prio_table(esw, chain, prio, level--).num_rules++;
+ mutex_unlock(&esw->fdb_table.offloads.fdb_prio_lock);
+ return fdb;
+ }
- if (mlx5_esw_has_fwd_fdb(dev))
- esw_size >>= 1;
+ ns = mlx5_get_fdb_sub_ns(dev, chain);
+ if (!ns) {
+ esw_warn(dev, "Failed to get FDB sub namespace\n");
+ mutex_unlock(&esw->fdb_table.offloads.fdb_prio_lock);
+ return ERR_PTR(-EOPNOTSUPP);
+ }
if (esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE)
- flags |= MLX5_FLOW_TABLE_TUNNEL_EN;
+ flags |= (MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT |
+ MLX5_FLOW_TABLE_TUNNEL_EN_DECAP);
- fdb = mlx5_create_auto_grouped_flow_table(root_ns, FDB_FAST_PATH,
- esw_size,
- ESW_OFFLOADS_NUM_GROUPS, 0,
- flags);
- if (IS_ERR(fdb)) {
- err = PTR_ERR(fdb);
- esw_warn(dev, "Failed to create Fast path FDB Table err %d\n", err);
- goto out_namespace;
- }
- esw->fdb_table.offloads.fast_fdb = fdb;
+ table_prio = (chain * FDB_MAX_PRIO) + prio - 1;
+
+ /* create earlier levels for correct fs_core lookup when
+ * connecting tables
+ */
+ for (l = 0; l <= level; l++) {
+ if (fdb_prio_table(esw, chain, prio, l).fdb) {
+ fdb_prio_table(esw, chain, prio, l).num_rules++;
+ continue;
+ }
- if (!mlx5_esw_has_fwd_fdb(dev))
- goto out_namespace;
+ fdb = create_next_size_table(esw, ns, table_prio, l, flags);
+ if (IS_ERR(fdb)) {
+ l--;
+ goto err_create_fdb;
+ }
- fdb = mlx5_create_auto_grouped_flow_table(root_ns, FDB_FAST_PATH,
- esw_size,
- ESW_OFFLOADS_NUM_GROUPS, 1,
- flags);
- if (IS_ERR(fdb)) {
- err = PTR_ERR(fdb);
- esw_warn(dev, "Failed to create fwd table err %d\n", err);
- goto out_ft;
+ fdb_prio_table(esw, chain, prio, l).fdb = fdb;
+ fdb_prio_table(esw, chain, prio, l).num_rules = 1;
}
- esw->fdb_table.offloads.fwd_fdb = fdb;
- return err;
+ mutex_unlock(&esw->fdb_table.offloads.fdb_prio_lock);
+ return fdb;
-out_ft:
- mlx5_destroy_flow_table(esw->fdb_table.offloads.fast_fdb);
-out_namespace:
- return err;
+err_create_fdb:
+ mutex_unlock(&esw->fdb_table.offloads.fdb_prio_lock);
+ if (l >= 0)
+ esw_put_prio_table(esw, chain, prio, l);
+
+ return fdb;
+}
+
+static void
+esw_put_prio_table(struct mlx5_eswitch *esw, u32 chain, u16 prio, int level)
+{
+ int l;
+
+ if (chain == FDB_SLOW_PATH_CHAIN)
+ return;
+
+ mutex_lock(&esw->fdb_table.offloads.fdb_prio_lock);
+
+ for (l = level; l >= 0; l--) {
+ if (--(fdb_prio_table(esw, chain, prio, l).num_rules) > 0)
+ continue;
+
+ put_sz_to_pool(esw, fdb_prio_table(esw, chain, prio, l).fdb->max_fte);
+ mlx5_destroy_flow_table(fdb_prio_table(esw, chain, prio, l).fdb);
+ fdb_prio_table(esw, chain, prio, l).fdb = NULL;
+ }
+
+ mutex_unlock(&esw->fdb_table.offloads.fdb_prio_lock);
}
-static void esw_destroy_offloads_fast_fdb_table(struct mlx5_eswitch *esw)
+static void esw_destroy_offloads_fast_fdb_tables(struct mlx5_eswitch *esw)
{
- if (mlx5_esw_has_fwd_fdb(esw->dev))
- mlx5_destroy_flow_table(esw->fdb_table.offloads.fwd_fdb);
- mlx5_destroy_flow_table(esw->fdb_table.offloads.fast_fdb);
+ /* If lazy creation isn't supported, deref the fast path tables */
+ if (!(esw->fdb_table.flags & ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED)) {
+ esw_put_prio_table(esw, 0, 1, 1);
+ esw_put_prio_table(esw, 0, 1, 0);
+ }
}
#define MAX_PF_SQ 256
@@ -579,12 +767,13 @@ static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw, int nvports)
int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
struct mlx5_flow_table_attr ft_attr = {};
struct mlx5_core_dev *dev = esw->dev;
+ u32 *flow_group_in, max_flow_counter;
struct mlx5_flow_namespace *root_ns;
struct mlx5_flow_table *fdb = NULL;
- int table_size, ix, err = 0;
+ int table_size, ix, err = 0, i;
struct mlx5_flow_group *g;
+ u32 flags = 0, fdb_max;
void *match_criteria;
- u32 *flow_group_in;
u8 *dmac;
esw_debug(esw->dev, "Create offloads FDB Tables\n");
@@ -599,12 +788,29 @@ static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw, int nvports)
goto ns_err;
}
- err = esw_create_offloads_fast_fdb_table(esw);
- if (err)
- goto fast_fdb_err;
+ max_flow_counter = (MLX5_CAP_GEN(dev, max_flow_counter_31_16) << 16) |
+ MLX5_CAP_GEN(dev, max_flow_counter_15_0);
+ fdb_max = 1 << MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size);
+
+ esw_debug(dev, "Create offloads FDB table, min (max esw size(2^%d), max counters(%d), groups(%d), max flow table size(2^%d))\n",
+ MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size),
+ max_flow_counter, ESW_OFFLOADS_NUM_GROUPS,
+ fdb_max);
+
+ for (i = 0; i < ARRAY_SIZE(ESW_POOLS); i++)
+ esw->fdb_table.offloads.fdb_left[i] =
+ ESW_POOLS[i] <= fdb_max ? ESW_SIZE / ESW_POOLS[i] : 0;
table_size = nvports * MAX_SQ_NVPORTS + MAX_PF_SQ + 2;
+ /* create the slow path fdb with encap set, so further table instances
+ * can be created at run time while VFs are probed if the FW allows that.
+ */
+ if (esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE)
+ flags |= (MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT |
+ MLX5_FLOW_TABLE_TUNNEL_EN_DECAP);
+
+ ft_attr.flags = flags;
ft_attr.max_fte = table_size;
ft_attr.prio = FDB_SLOW_PATH;
@@ -616,6 +822,18 @@ static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw, int nvports)
}
esw->fdb_table.offloads.slow_fdb = fdb;
+ /* If lazy creation isn't supported, open the fast path tables now */
+ if (!MLX5_CAP_ESW_FLOWTABLE(esw->dev, multi_fdb_encap) &&
+ esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE) {
+ esw->fdb_table.flags &= ~ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED;
+ esw_warn(dev, "Lazy creation of flow tables isn't supported, ignoring priorities\n");
+ esw_get_prio_table(esw, 0, 1, 0);
+ esw_get_prio_table(esw, 0, 1, 1);
+ } else {
+ esw_debug(dev, "Lazy creation of flow tables supported, deferring table opening\n");
+ esw->fdb_table.flags |= ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED;
+ }
+
/* create send-to-vport group */
memset(flow_group_in, 0, inlen);
MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
@@ -663,6 +881,7 @@ static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw, int nvports)
if (err)
goto miss_rule_err;
+ esw->nvports = nvports;
kvfree(flow_group_in);
return 0;
@@ -671,10 +890,9 @@ miss_rule_err:
miss_err:
mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_grp);
send_vport_err:
+ esw_destroy_offloads_fast_fdb_tables(esw);
mlx5_destroy_flow_table(esw->fdb_table.offloads.slow_fdb);
slow_fdb_err:
- esw_destroy_offloads_fast_fdb_table(esw);
-fast_fdb_err:
ns_err:
kvfree(flow_group_in);
return err;
@@ -682,7 +900,7 @@ ns_err:
static void esw_destroy_offloads_fdb_tables(struct mlx5_eswitch *esw)
{
- if (!esw->fdb_table.offloads.fast_fdb)
+ if (!esw->fdb_table.offloads.slow_fdb)
return;
esw_debug(esw->dev, "Destroy offloads FDB Tables\n");
@@ -692,7 +910,7 @@ static void esw_destroy_offloads_fdb_tables(struct mlx5_eswitch *esw)
mlx5_destroy_flow_group(esw->fdb_table.offloads.miss_grp);
mlx5_destroy_flow_table(esw->fdb_table.offloads.slow_fdb);
- esw_destroy_offloads_fast_fdb_table(esw);
+ esw_destroy_offloads_fast_fdb_tables(esw);
}
static int esw_create_offloads_table(struct mlx5_eswitch *esw)
@@ -775,10 +993,10 @@ static void esw_destroy_vport_rx_group(struct mlx5_eswitch *esw)
}
struct mlx5_flow_handle *
-mlx5_eswitch_create_vport_rx_rule(struct mlx5_eswitch *esw, int vport, u32 tirn)
+mlx5_eswitch_create_vport_rx_rule(struct mlx5_eswitch *esw, int vport,
+ struct mlx5_flow_destination *dest)
{
struct mlx5_flow_act flow_act = {0};
- struct mlx5_flow_destination dest = {};
struct mlx5_flow_handle *flow_rule;
struct mlx5_flow_spec *spec;
void *misc;
@@ -796,12 +1014,10 @@ mlx5_eswitch_create_vport_rx_rule(struct mlx5_eswitch *esw, int vport, u32 tirn)
MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
- dest.type = MLX5_FLOW_DESTINATION_TYPE_TIR;
- dest.tir_num = tirn;
flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
flow_rule = mlx5_add_flow_rules(esw->offloads.ft_offloads, spec,
- &flow_act, &dest, 1);
+ &flow_act, dest, 1);
if (IS_ERR(flow_rule)) {
esw_warn(esw->dev, "fs offloads: Failed to add vport rx rule err %ld\n", PTR_ERR(flow_rule));
goto out;
@@ -812,29 +1028,35 @@ out:
return flow_rule;
}
-static int esw_offloads_start(struct mlx5_eswitch *esw)
+static int esw_offloads_start(struct mlx5_eswitch *esw,
+ struct netlink_ext_ack *extack)
{
int err, err1, num_vfs = esw->dev->priv.sriov.num_vfs;
if (esw->mode != SRIOV_LEGACY) {
- esw_warn(esw->dev, "Can't set offloads mode, SRIOV legacy not enabled\n");
+ NL_SET_ERR_MSG_MOD(extack,
+ "Can't set offloads mode, SRIOV legacy not enabled");
return -EINVAL;
}
mlx5_eswitch_disable_sriov(esw);
err = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_OFFLOADS);
if (err) {
- esw_warn(esw->dev, "Failed setting eswitch to offloads, err %d\n", err);
+ NL_SET_ERR_MSG_MOD(extack,
+ "Failed setting eswitch to offloads");
err1 = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_LEGACY);
- if (err1)
- esw_warn(esw->dev, "Failed setting eswitch back to legacy, err %d\n", err1);
+ if (err1) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Failed setting eswitch back to legacy");
+ }
}
if (esw->offloads.inline_mode == MLX5_INLINE_MODE_NONE) {
if (mlx5_eswitch_inline_mode_get(esw,
num_vfs,
&esw->offloads.inline_mode)) {
esw->offloads.inline_mode = MLX5_INLINE_MODE_L2;
- esw_warn(esw->dev, "Inline mode is different between vports\n");
+ NL_SET_ERR_MSG_MOD(extack,
+ "Inline mode is different between vports");
}
}
return err;
@@ -945,6 +1167,8 @@ int esw_offloads_init(struct mlx5_eswitch *esw, int nvports)
{
int err;
+ mutex_init(&esw->fdb_table.offloads.fdb_prio_lock);
+
err = esw_create_offloads_fdb_tables(esw, nvports);
if (err)
return err;
@@ -975,17 +1199,20 @@ create_ft_err:
return err;
}
-static int esw_offloads_stop(struct mlx5_eswitch *esw)
+static int esw_offloads_stop(struct mlx5_eswitch *esw,
+ struct netlink_ext_ack *extack)
{
int err, err1, num_vfs = esw->dev->priv.sriov.num_vfs;
mlx5_eswitch_disable_sriov(esw);
err = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_LEGACY);
if (err) {
- esw_warn(esw->dev, "Failed setting eswitch to legacy, err %d\n", err);
+ NL_SET_ERR_MSG_MOD(extack, "Failed setting eswitch to legacy");
err1 = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_OFFLOADS);
- if (err1)
- esw_warn(esw->dev, "Failed setting eswitch back to offloads, err %d\n", err);
+ if (err1) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Failed setting eswitch back to offloads");
+ }
}
/* enable back PF RoCE */
@@ -1094,7 +1321,8 @@ static int mlx5_devlink_eswitch_check(struct devlink *devlink)
return 0;
}
-int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode)
+int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
+ struct netlink_ext_ack *extack)
{
struct mlx5_core_dev *dev = devlink_priv(devlink);
u16 cur_mlx5_mode, mlx5_mode = 0;
@@ -1113,9 +1341,9 @@ int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode)
return 0;
if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV)
- return esw_offloads_start(dev->priv.eswitch);
+ return esw_offloads_start(dev->priv.eswitch, extack);
else if (mode == DEVLINK_ESWITCH_MODE_LEGACY)
- return esw_offloads_stop(dev->priv.eswitch);
+ return esw_offloads_stop(dev->priv.eswitch, extack);
else
return -EINVAL;
}
@@ -1132,7 +1360,8 @@ int mlx5_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode)
return esw_mode_to_devlink(dev->priv.eswitch->mode, mode);
}
-int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode)
+int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode,
+ struct netlink_ext_ack *extack)
{
struct mlx5_core_dev *dev = devlink_priv(devlink);
struct mlx5_eswitch *esw = dev->priv.eswitch;
@@ -1149,14 +1378,15 @@ int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode)
return 0;
/* fall through */
case MLX5_CAP_INLINE_MODE_L2:
- esw_warn(dev, "Inline mode can't be set\n");
+ NL_SET_ERR_MSG_MOD(extack, "Inline mode can't be set");
return -EOPNOTSUPP;
case MLX5_CAP_INLINE_MODE_VPORT_CONTEXT:
break;
}
if (esw->offloads.num_flows > 0) {
- esw_warn(dev, "Can't set inline mode when flows are configured\n");
+ NL_SET_ERR_MSG_MOD(extack,
+ "Can't set inline mode when flows are configured");
return -EOPNOTSUPP;
}
@@ -1167,8 +1397,8 @@ int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode)
for (vport = 1; vport < esw->enabled_vports; vport++) {
err = mlx5_modify_nic_vport_min_inline(dev, vport, mlx5_mode);
if (err) {
- esw_warn(dev, "Failed to set min inline on vport %d\n",
- vport);
+ NL_SET_ERR_MSG_MOD(extack,
+ "Failed to set min inline on vport");
goto revert_inline_mode;
}
}
@@ -1234,7 +1464,8 @@ out:
return 0;
}
-int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink, u8 encap)
+int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink, u8 encap,
+ struct netlink_ext_ack *extack)
{
struct mlx5_core_dev *dev = devlink_priv(devlink);
struct mlx5_eswitch *esw = dev->priv.eswitch;
@@ -1245,7 +1476,7 @@ int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink, u8 encap)
return err;
if (encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE &&
- (!MLX5_CAP_ESW_FLOWTABLE_FDB(dev, encap) ||
+ (!MLX5_CAP_ESW_FLOWTABLE_FDB(dev, reformat) ||
!MLX5_CAP_ESW_FLOWTABLE_FDB(dev, decap)))
return -EOPNOTSUPP;
@@ -1261,19 +1492,24 @@ int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink, u8 encap)
return 0;
if (esw->offloads.num_flows > 0) {
- esw_warn(dev, "Can't set encapsulation when flows are configured\n");
+ NL_SET_ERR_MSG_MOD(extack,
+ "Can't set encapsulation when flows are configured");
return -EOPNOTSUPP;
}
- esw_destroy_offloads_fast_fdb_table(esw);
+ esw_destroy_offloads_fdb_tables(esw);
esw->offloads.encap = encap;
- err = esw_create_offloads_fast_fdb_table(esw);
+
+ err = esw_create_offloads_fdb_tables(esw, esw->nvports);
+
if (err) {
- esw_warn(esw->dev, "Failed re-creating fast FDB table, err %d\n", err);
+ NL_SET_ERR_MSG_MOD(extack,
+ "Failed re-creating fast FDB table");
esw->offloads.encap = !encap;
- (void)esw_create_offloads_fast_fdb_table(esw);
+ (void)esw_create_offloads_fdb_tables(esw, esw->nvports);
}
+
return err;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c b/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c
index 5645a4facad2..515e3d6de051 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c
@@ -245,7 +245,7 @@ static void *mlx5_fpga_ipsec_cmd_exec(struct mlx5_core_dev *mdev,
return ERR_PTR(res);
}
- /* Context will be freed by wait func after completion */
+ /* Context should be freed by the caller after completion. */
return context;
}
@@ -418,10 +418,8 @@ static int mlx5_fpga_ipsec_set_caps(struct mlx5_core_dev *mdev, u32 flags)
cmd.cmd = htonl(MLX5_FPGA_IPSEC_CMD_OP_SET_CAP);
cmd.flags = htonl(flags);
context = mlx5_fpga_ipsec_cmd_exec(mdev, &cmd, sizeof(cmd));
- if (IS_ERR(context)) {
- err = PTR_ERR(context);
- goto out;
- }
+ if (IS_ERR(context))
+ return PTR_ERR(context);
err = mlx5_fpga_ipsec_cmd_wait(context);
if (err)
@@ -435,6 +433,7 @@ static int mlx5_fpga_ipsec_set_caps(struct mlx5_core_dev *mdev, u32 flags)
}
out:
+ kfree(context);
return err;
}
@@ -650,7 +649,7 @@ static bool mlx5_is_fpga_egress_ipsec_rule(struct mlx5_core_dev *dev,
(match_criteria_enable &
~(MLX5_MATCH_OUTER_HEADERS | MLX5_MATCH_MISC_PARAMETERS)) ||
(flow_act->action & ~(MLX5_FLOW_CONTEXT_ACTION_ENCRYPT | MLX5_FLOW_CONTEXT_ACTION_ALLOW)) ||
- flow_act->has_flow_tag)
+ (flow_act->flags & FLOW_ACT_HAS_TAG))
return false;
return true;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c
index 8e01f818021b..08a891f9aade 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c
@@ -152,7 +152,8 @@ static int mlx5_cmd_create_flow_table(struct mlx5_core_dev *dev,
struct mlx5_flow_table *next_ft,
unsigned int *table_id, u32 flags)
{
- int en_encap_decap = !!(flags & MLX5_FLOW_TABLE_TUNNEL_EN);
+ int en_encap = !!(flags & MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT);
+ int en_decap = !!(flags & MLX5_FLOW_TABLE_TUNNEL_EN_DECAP);
u32 out[MLX5_ST_SZ_DW(create_flow_table_out)] = {0};
u32 in[MLX5_ST_SZ_DW(create_flow_table_in)] = {0};
int err;
@@ -169,9 +170,9 @@ static int mlx5_cmd_create_flow_table(struct mlx5_core_dev *dev,
}
MLX5_SET(create_flow_table_in, in, flow_table_context.decap_en,
- en_encap_decap);
- MLX5_SET(create_flow_table_in, in, flow_table_context.encap_en,
- en_encap_decap);
+ en_decap);
+ MLX5_SET(create_flow_table_in, in, flow_table_context.reformat_en,
+ en_encap);
switch (op_mod) {
case FS_FT_OP_MOD_NORMAL:
@@ -343,7 +344,8 @@ static int mlx5_cmd_set_fte(struct mlx5_core_dev *dev,
MLX5_SET(flow_context, in_flow_context, flow_tag, fte->action.flow_tag);
MLX5_SET(flow_context, in_flow_context, action, fte->action.action);
- MLX5_SET(flow_context, in_flow_context, encap_id, fte->action.encap_id);
+ MLX5_SET(flow_context, in_flow_context, packet_reformat_id,
+ fte->action.reformat_id);
MLX5_SET(flow_context, in_flow_context, modify_header_id,
fte->action.modify_id);
@@ -417,7 +419,7 @@ static int mlx5_cmd_set_fte(struct mlx5_core_dev *dev,
continue;
MLX5_SET(flow_counter_list, in_dests, flow_counter_id,
- dst->dest_attr.counter->id);
+ dst->dest_attr.counter_id);
in_dests += MLX5_ST_SZ_BYTES(dest_format_struct);
list_size++;
}
@@ -594,62 +596,78 @@ void mlx5_cmd_fc_bulk_get(struct mlx5_core_dev *dev,
*bytes = MLX5_GET64(traffic_counter, stats, octets);
}
-int mlx5_encap_alloc(struct mlx5_core_dev *dev,
- int header_type,
- size_t size,
- void *encap_header,
- u32 *encap_id)
+int mlx5_packet_reformat_alloc(struct mlx5_core_dev *dev,
+ int reformat_type,
+ size_t size,
+ void *reformat_data,
+ enum mlx5_flow_namespace_type namespace,
+ u32 *packet_reformat_id)
{
- int max_encap_size = MLX5_CAP_ESW(dev, max_encap_header_size);
- u32 out[MLX5_ST_SZ_DW(alloc_encap_header_out)];
- void *encap_header_in;
- void *header;
+ u32 out[MLX5_ST_SZ_DW(alloc_packet_reformat_context_out)];
+ void *packet_reformat_context_in;
+ int max_encap_size;
+ void *reformat;
int inlen;
int err;
u32 *in;
+ if (namespace == MLX5_FLOW_NAMESPACE_FDB)
+ max_encap_size = MLX5_CAP_ESW(dev, max_encap_header_size);
+ else
+ max_encap_size = MLX5_CAP_FLOWTABLE(dev, max_encap_header_size);
+
if (size > max_encap_size) {
mlx5_core_warn(dev, "encap size %zd too big, max supported is %d\n",
size, max_encap_size);
return -EINVAL;
}
- in = kzalloc(MLX5_ST_SZ_BYTES(alloc_encap_header_in) + size,
+ in = kzalloc(MLX5_ST_SZ_BYTES(alloc_packet_reformat_context_in) + size,
GFP_KERNEL);
if (!in)
return -ENOMEM;
- encap_header_in = MLX5_ADDR_OF(alloc_encap_header_in, in, encap_header);
- header = MLX5_ADDR_OF(encap_header_in, encap_header_in, encap_header);
- inlen = header - (void *)in + size;
+ packet_reformat_context_in = MLX5_ADDR_OF(alloc_packet_reformat_context_in,
+ in, packet_reformat_context);
+ reformat = MLX5_ADDR_OF(packet_reformat_context_in,
+ packet_reformat_context_in,
+ reformat_data);
+ inlen = reformat - (void *)in + size;
memset(in, 0, inlen);
- MLX5_SET(alloc_encap_header_in, in, opcode,
- MLX5_CMD_OP_ALLOC_ENCAP_HEADER);
- MLX5_SET(encap_header_in, encap_header_in, encap_header_size, size);
- MLX5_SET(encap_header_in, encap_header_in, header_type, header_type);
- memcpy(header, encap_header, 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);
+ MLX5_SET(packet_reformat_context_in, packet_reformat_context_in,
+ reformat_type, reformat_type);
+ memcpy(reformat, reformat_data, size);
memset(out, 0, sizeof(out));
err = mlx5_cmd_exec(dev, in, inlen, out, sizeof(out));
- *encap_id = MLX5_GET(alloc_encap_header_out, out, encap_id);
+ *packet_reformat_id = MLX5_GET(alloc_packet_reformat_context_out,
+ out, packet_reformat_id);
kfree(in);
return err;
}
+EXPORT_SYMBOL(mlx5_packet_reformat_alloc);
-void mlx5_encap_dealloc(struct mlx5_core_dev *dev, u32 encap_id)
+void mlx5_packet_reformat_dealloc(struct mlx5_core_dev *dev,
+ u32 packet_reformat_id)
{
- u32 in[MLX5_ST_SZ_DW(dealloc_encap_header_in)];
- u32 out[MLX5_ST_SZ_DW(dealloc_encap_header_out)];
+ u32 in[MLX5_ST_SZ_DW(dealloc_packet_reformat_context_in)];
+ u32 out[MLX5_ST_SZ_DW(dealloc_packet_reformat_context_out)];
memset(in, 0, sizeof(in));
- MLX5_SET(dealloc_encap_header_in, in, opcode,
- MLX5_CMD_OP_DEALLOC_ENCAP_HEADER);
- MLX5_SET(dealloc_encap_header_in, in, encap_id, encap_id);
+ MLX5_SET(dealloc_packet_reformat_context_in, in, opcode,
+ MLX5_CMD_OP_DEALLOC_PACKET_REFORMAT_CONTEXT);
+ MLX5_SET(dealloc_packet_reformat_context_in, in, packet_reformat_id,
+ packet_reformat_id);
mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
}
+EXPORT_SYMBOL(mlx5_packet_reformat_dealloc);
int mlx5_modify_header_alloc(struct mlx5_core_dev *dev,
u8 namespace, u8 num_actions,
@@ -667,9 +685,14 @@ int mlx5_modify_header_alloc(struct mlx5_core_dev *dev,
table_type = FS_FT_FDB;
break;
case MLX5_FLOW_NAMESPACE_KERNEL:
+ case MLX5_FLOW_NAMESPACE_BYPASS:
max_actions = MLX5_CAP_FLOWTABLE_NIC_RX(dev, max_modify_header_actions);
table_type = FS_FT_NIC_RX;
break;
+ case MLX5_FLOW_NAMESPACE_EGRESS:
+ max_actions = MLX5_CAP_FLOWTABLE_NIC_TX(dev, max_modify_header_actions);
+ table_type = FS_FT_NIC_TX;
+ break;
default:
return -EOPNOTSUPP;
}
@@ -702,6 +725,7 @@ int mlx5_modify_header_alloc(struct mlx5_core_dev *dev,
kfree(in);
return err;
}
+EXPORT_SYMBOL(mlx5_modify_header_alloc);
void mlx5_modify_header_dealloc(struct mlx5_core_dev *dev, u32 modify_header_id)
{
@@ -716,6 +740,7 @@ void mlx5_modify_header_dealloc(struct mlx5_core_dev *dev, u32 modify_header_id)
mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
}
+EXPORT_SYMBOL(mlx5_modify_header_dealloc);
static const struct mlx5_flow_cmds mlx5_flow_cmds = {
.create_flow_table = mlx5_cmd_create_flow_table,
@@ -760,8 +785,8 @@ const struct mlx5_flow_cmds *mlx5_fs_cmd_get_default(enum fs_flow_table_type typ
case FS_FT_FDB:
case FS_FT_SNIFFER_RX:
case FS_FT_SNIFFER_TX:
- return mlx5_fs_cmd_get_fw_cmds();
case FS_FT_NIC_TX:
+ return mlx5_fs_cmd_get_fw_cmds();
default:
return mlx5_fs_cmd_get_stub_cmds();
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
index 37d114c668b7..9d73eb955f75 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
@@ -40,6 +40,7 @@
#include "diag/fs_tracepoint.h"
#include "accel/ipsec.h"
#include "fpga/ipsec.h"
+#include "eswitch.h"
#define INIT_TREE_NODE_ARRAY_SIZE(...) (sizeof((struct init_tree_node[]){__VA_ARGS__}) /\
sizeof(struct init_tree_node))
@@ -76,6 +77,14 @@
FS_CAP(flow_table_properties_nic_receive.identified_miss_table_mode), \
FS_CAP(flow_table_properties_nic_receive.flow_table_modify))
+#define FS_CHAINING_CAPS_EGRESS \
+ FS_REQUIRED_CAPS( \
+ FS_CAP(flow_table_properties_nic_transmit.flow_modify_en), \
+ FS_CAP(flow_table_properties_nic_transmit.modify_root), \
+ FS_CAP(flow_table_properties_nic_transmit \
+ .identified_miss_table_mode), \
+ FS_CAP(flow_table_properties_nic_transmit.flow_table_modify))
+
#define LEFTOVERS_NUM_LEVELS 1
#define LEFTOVERS_NUM_PRIOS 1
@@ -151,6 +160,17 @@ static struct init_tree_node {
}
};
+static struct init_tree_node egress_root_fs = {
+ .type = FS_TYPE_NAMESPACE,
+ .ar_size = 1,
+ .children = (struct init_tree_node[]) {
+ ADD_PRIO(0, MLX5_BY_PASS_NUM_PRIOS, 0,
+ FS_CHAINING_CAPS_EGRESS,
+ ADD_NS(ADD_MULTIPLE_PRIO(MLX5_BY_PASS_NUM_PRIOS,
+ BY_PASS_PRIO_NUM_LEVELS))),
+ }
+};
+
enum fs_i_lock_class {
FS_LOCK_GRANDPARENT,
FS_LOCK_PARENT,
@@ -694,7 +714,7 @@ static struct mlx5_flow_table *find_closest_ft_recursive(struct fs_node *root,
struct fs_node *iter = list_entry(start, struct fs_node, list);
struct mlx5_flow_table *ft = NULL;
- if (!root)
+ if (!root || root->type == FS_TYPE_PRIO_CHAINS)
return NULL;
list_for_each_advance_continue(iter, &root->children, reverse) {
@@ -1388,7 +1408,7 @@ static bool check_conflicting_actions(u32 action1, u32 action2)
return false;
if (xored_actions & (MLX5_FLOW_CONTEXT_ACTION_DROP |
- MLX5_FLOW_CONTEXT_ACTION_ENCAP |
+ MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT |
MLX5_FLOW_CONTEXT_ACTION_DECAP |
MLX5_FLOW_CONTEXT_ACTION_MOD_HDR |
MLX5_FLOW_CONTEXT_ACTION_VLAN_POP |
@@ -1408,7 +1428,7 @@ static int check_conflicting_ftes(struct fs_fte *fte, const struct mlx5_flow_act
return -EEXIST;
}
- if (flow_act->has_flow_tag &&
+ if ((flow_act->flags & FLOW_ACT_HAS_TAG) &&
fte->action.flow_tag != flow_act->flow_tag) {
mlx5_core_warn(get_dev(&fte->node),
"FTE flow tag %u already exists with different flow tag %u\n",
@@ -1455,29 +1475,8 @@ static struct mlx5_flow_handle *add_rule_fg(struct mlx5_flow_group *fg,
return handle;
}
-struct mlx5_fc *mlx5_flow_rule_counter(struct mlx5_flow_handle *handle)
+static bool counter_is_valid(u32 action)
{
- struct mlx5_flow_rule *dst;
- struct fs_fte *fte;
-
- fs_get_obj(fte, handle->rule[0]->node.parent);
-
- fs_for_each_dst(dst, fte) {
- if (dst->dest_attr.type == MLX5_FLOW_DESTINATION_TYPE_COUNTER)
- return dst->dest_attr.counter;
- }
-
- return NULL;
-}
-
-static bool counter_is_valid(struct mlx5_fc *counter, u32 action)
-{
- if (!(action & MLX5_FLOW_CONTEXT_ACTION_COUNT))
- return !counter;
-
- if (!counter)
- return false;
-
return (action & (MLX5_FLOW_CONTEXT_ACTION_DROP |
MLX5_FLOW_CONTEXT_ACTION_FWD_DEST));
}
@@ -1487,7 +1486,7 @@ static bool dest_is_valid(struct mlx5_flow_destination *dest,
struct mlx5_flow_table *ft)
{
if (dest && (dest->type == MLX5_FLOW_DESTINATION_TYPE_COUNTER))
- return counter_is_valid(dest->counter, action);
+ return counter_is_valid(action);
if (!(action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST))
return true;
@@ -1629,6 +1628,8 @@ try_add_to_existing_fg(struct mlx5_flow_table *ft,
search_again_locked:
version = matched_fgs_get_version(match_head);
+ if (flow_act->flags & FLOW_ACT_NO_APPEND)
+ goto skip_search;
/* Try to find a fg that already contains a matching fte */
list_for_each_entry(iter, match_head, list) {
struct fs_fte *fte_tmp;
@@ -1645,6 +1646,11 @@ search_again_locked:
return rule;
}
+skip_search:
+ /* No group with matching fte found, or we skipped the search.
+ * Try to add a new fte to any matching fg.
+ */
+
/* Check the ft version, for case that new flow group
* was added while the fgs weren't locked
*/
@@ -1975,12 +1981,24 @@ void mlx5_destroy_flow_group(struct mlx5_flow_group *fg)
fg->id);
}
+struct mlx5_flow_namespace *mlx5_get_fdb_sub_ns(struct mlx5_core_dev *dev,
+ int n)
+{
+ struct mlx5_flow_steering *steering = dev->priv.steering;
+
+ if (!steering || !steering->fdb_sub_ns)
+ return NULL;
+
+ return steering->fdb_sub_ns[n];
+}
+EXPORT_SYMBOL(mlx5_get_fdb_sub_ns);
+
struct mlx5_flow_namespace *mlx5_get_flow_namespace(struct mlx5_core_dev *dev,
enum mlx5_flow_namespace_type type)
{
struct mlx5_flow_steering *steering = dev->priv.steering;
struct mlx5_flow_root_namespace *root_ns;
- int prio;
+ int prio = 0;
struct fs_prio *fs_prio;
struct mlx5_flow_namespace *ns;
@@ -1988,40 +2006,29 @@ struct mlx5_flow_namespace *mlx5_get_flow_namespace(struct mlx5_core_dev *dev,
return NULL;
switch (type) {
- case MLX5_FLOW_NAMESPACE_BYPASS:
- case MLX5_FLOW_NAMESPACE_LAG:
- case MLX5_FLOW_NAMESPACE_OFFLOADS:
- case MLX5_FLOW_NAMESPACE_ETHTOOL:
- case MLX5_FLOW_NAMESPACE_KERNEL:
- case MLX5_FLOW_NAMESPACE_LEFTOVERS:
- case MLX5_FLOW_NAMESPACE_ANCHOR:
- prio = type;
- break;
case MLX5_FLOW_NAMESPACE_FDB:
if (steering->fdb_root_ns)
return &steering->fdb_root_ns->ns;
- else
- return NULL;
+ return NULL;
case MLX5_FLOW_NAMESPACE_SNIFFER_RX:
if (steering->sniffer_rx_root_ns)
return &steering->sniffer_rx_root_ns->ns;
- else
- return NULL;
+ return NULL;
case MLX5_FLOW_NAMESPACE_SNIFFER_TX:
if (steering->sniffer_tx_root_ns)
return &steering->sniffer_tx_root_ns->ns;
- else
- return NULL;
- case MLX5_FLOW_NAMESPACE_EGRESS:
- if (steering->egress_root_ns)
- return &steering->egress_root_ns->ns;
- else
- return NULL;
- default:
return NULL;
+ default:
+ break;
+ }
+
+ if (type == MLX5_FLOW_NAMESPACE_EGRESS) {
+ root_ns = steering->egress_root_ns;
+ } else { /* Must be NIC RX */
+ root_ns = steering->root_ns;
+ prio = type;
}
- root_ns = steering->root_ns;
if (!root_ns)
return NULL;
@@ -2064,8 +2071,10 @@ struct mlx5_flow_namespace *mlx5_get_flow_vport_acl_namespace(struct mlx5_core_d
}
}
-static struct fs_prio *fs_create_prio(struct mlx5_flow_namespace *ns,
- unsigned int prio, int num_levels)
+static struct fs_prio *_fs_create_prio(struct mlx5_flow_namespace *ns,
+ unsigned int prio,
+ int num_levels,
+ enum fs_node_type type)
{
struct fs_prio *fs_prio;
@@ -2073,7 +2082,7 @@ static struct fs_prio *fs_create_prio(struct mlx5_flow_namespace *ns,
if (!fs_prio)
return ERR_PTR(-ENOMEM);
- fs_prio->node.type = FS_TYPE_PRIO;
+ fs_prio->node.type = type;
tree_init_node(&fs_prio->node, NULL, del_sw_prio);
tree_add_node(&fs_prio->node, &ns->node);
fs_prio->num_levels = num_levels;
@@ -2083,6 +2092,19 @@ static struct fs_prio *fs_create_prio(struct mlx5_flow_namespace *ns,
return fs_prio;
}
+static struct fs_prio *fs_create_prio_chained(struct mlx5_flow_namespace *ns,
+ unsigned int prio,
+ int num_levels)
+{
+ return _fs_create_prio(ns, prio, num_levels, FS_TYPE_PRIO_CHAINS);
+}
+
+static struct fs_prio *fs_create_prio(struct mlx5_flow_namespace *ns,
+ unsigned int prio, int num_levels)
+{
+ return _fs_create_prio(ns, prio, num_levels, FS_TYPE_PRIO);
+}
+
static struct mlx5_flow_namespace *fs_init_namespace(struct mlx5_flow_namespace
*ns)
{
@@ -2387,6 +2409,9 @@ void mlx5_cleanup_fs(struct mlx5_core_dev *dev)
cleanup_egress_acls_root_ns(dev);
cleanup_ingress_acls_root_ns(dev);
cleanup_root_ns(steering->fdb_root_ns);
+ steering->fdb_root_ns = NULL;
+ kfree(steering->fdb_sub_ns);
+ steering->fdb_sub_ns = NULL;
cleanup_root_ns(steering->sniffer_rx_root_ns);
cleanup_root_ns(steering->sniffer_tx_root_ns);
cleanup_root_ns(steering->egress_root_ns);
@@ -2432,27 +2457,64 @@ static int init_sniffer_rx_root_ns(struct mlx5_flow_steering *steering)
static int init_fdb_root_ns(struct mlx5_flow_steering *steering)
{
- struct fs_prio *prio;
+ struct mlx5_flow_namespace *ns;
+ struct fs_prio *maj_prio;
+ struct fs_prio *min_prio;
+ int levels;
+ int chain;
+ int prio;
+ int err;
steering->fdb_root_ns = create_root_ns(steering, FS_FT_FDB);
if (!steering->fdb_root_ns)
return -ENOMEM;
- prio = fs_create_prio(&steering->fdb_root_ns->ns, 0, 2);
- if (IS_ERR(prio))
+ steering->fdb_sub_ns = kzalloc(sizeof(steering->fdb_sub_ns) *
+ (FDB_MAX_CHAIN + 1), GFP_KERNEL);
+ if (!steering->fdb_sub_ns)
+ return -ENOMEM;
+
+ levels = 2 * FDB_MAX_PRIO * (FDB_MAX_CHAIN + 1);
+ maj_prio = fs_create_prio_chained(&steering->fdb_root_ns->ns, 0,
+ levels);
+ if (IS_ERR(maj_prio)) {
+ err = PTR_ERR(maj_prio);
goto out_err;
+ }
+
+ for (chain = 0; chain <= FDB_MAX_CHAIN; chain++) {
+ ns = fs_create_namespace(maj_prio);
+ if (IS_ERR(ns)) {
+ err = PTR_ERR(ns);
+ goto out_err;
+ }
+
+ for (prio = 0; prio < FDB_MAX_PRIO * (chain + 1); prio++) {
+ min_prio = fs_create_prio(ns, prio, 2);
+ if (IS_ERR(min_prio)) {
+ err = PTR_ERR(min_prio);
+ goto out_err;
+ }
+ }
+
+ steering->fdb_sub_ns[chain] = ns;
+ }
- prio = fs_create_prio(&steering->fdb_root_ns->ns, 1, 1);
- if (IS_ERR(prio))
+ maj_prio = fs_create_prio(&steering->fdb_root_ns->ns, 1, 1);
+ if (IS_ERR(maj_prio)) {
+ err = PTR_ERR(maj_prio);
goto out_err;
+ }
set_prio_attrs(steering->fdb_root_ns);
return 0;
out_err:
cleanup_root_ns(steering->fdb_root_ns);
+ kfree(steering->fdb_sub_ns);
+ steering->fdb_sub_ns = NULL;
steering->fdb_root_ns = NULL;
- return PTR_ERR(prio);
+ return err;
}
static int init_egress_acl_root_ns(struct mlx5_flow_steering *steering, int vport)
@@ -2537,16 +2599,23 @@ cleanup_root_ns:
static int init_egress_root_ns(struct mlx5_flow_steering *steering)
{
- struct fs_prio *prio;
+ int err;
steering->egress_root_ns = create_root_ns(steering,
FS_FT_NIC_TX);
if (!steering->egress_root_ns)
return -ENOMEM;
- /* create 1 prio*/
- prio = fs_create_prio(&steering->egress_root_ns->ns, 0, 1);
- return PTR_ERR_OR_ZERO(prio);
+ err = init_root_tree(steering, &egress_root_fs,
+ &steering->egress_root_ns->ns.node);
+ if (err)
+ goto cleanup;
+ set_prio_attrs(steering->egress_root_ns);
+ return 0;
+cleanup:
+ cleanup_root_ns(steering->egress_root_ns);
+ steering->egress_root_ns = NULL;
+ return err;
}
int mlx5_init_fs(struct mlx5_core_dev *dev)
@@ -2614,7 +2683,7 @@ int mlx5_init_fs(struct mlx5_core_dev *dev)
goto err;
}
- if (MLX5_IPSEC_DEV(dev)) {
+ if (MLX5_IPSEC_DEV(dev) || MLX5_CAP_FLOWTABLE_NIC_TX(dev, ft_support)) {
err = init_egress_root_ns(steering);
if (err)
goto err;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h
index 32070e5d993d..b51ad217da32 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h
@@ -36,10 +36,23 @@
#include <linux/refcount.h>
#include <linux/mlx5/fs.h>
#include <linux/rhashtable.h>
+#include <linux/llist.h>
+
+/* FS_TYPE_PRIO_CHAINS is a PRIO that will have namespaces only,
+ * and those are in parallel to one another when going over them to connect
+ * a new flow table. Meaning the last flow table in a TYPE_PRIO prio in one
+ * parallel namespace will not automatically connect to the first flow table
+ * found in any prio in any next namespace, but skip the entire containing
+ * TYPE_PRIO_CHAINS prio.
+ *
+ * This is used to implement tc chains, each chain of prios is a different
+ * namespace inside a containing TYPE_PRIO_CHAINS prio.
+ */
enum fs_node_type {
FS_TYPE_NAMESPACE,
FS_TYPE_PRIO,
+ FS_TYPE_PRIO_CHAINS,
FS_TYPE_FLOW_TABLE,
FS_TYPE_FLOW_GROUP,
FS_TYPE_FLOW_ENTRY,
@@ -72,6 +85,7 @@ struct mlx5_flow_steering {
struct kmem_cache *ftes_cache;
struct mlx5_flow_root_namespace *root_ns;
struct mlx5_flow_root_namespace *fdb_root_ns;
+ struct mlx5_flow_namespace **fdb_sub_ns;
struct mlx5_flow_root_namespace **esw_egress_root_ns;
struct mlx5_flow_root_namespace **esw_ingress_root_ns;
struct mlx5_flow_root_namespace *sniffer_tx_root_ns;
@@ -138,8 +152,9 @@ struct mlx5_fc_cache {
};
struct mlx5_fc {
- struct rb_node node;
struct list_head list;
+ struct llist_node addlist;
+ struct llist_node dellist;
/* last{packets,bytes} members are used when calculating the delta since
* last reading
@@ -148,7 +163,6 @@ struct mlx5_fc {
u64 lastbytes;
u32 id;
- bool deleted;
bool aging;
struct mlx5_fc_cache cache ____cacheline_aligned_in_smp;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c
index 58af6be13dfa..32accd6b041b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c
@@ -52,11 +52,13 @@
* access to counter list:
* - create (user context)
* - mlx5_fc_create() only adds to an addlist to be used by
- * mlx5_fc_stats_query_work(). addlist is protected by a spinlock.
+ * mlx5_fc_stats_query_work(). addlist is a lockless single linked list
+ * that doesn't require any additional synchronization when adding single
+ * node.
* - spawn thread to do the actual destroy
*
* - destroy (user context)
- * - mark a counter as deleted
+ * - add a counter to lockless dellist
* - spawn thread to do the actual del
*
* - dump (user context)
@@ -71,36 +73,55 @@
* elapsed, the thread will actually query the hardware.
*/
-static void mlx5_fc_stats_insert(struct rb_root *root, struct mlx5_fc *counter)
+static struct list_head *mlx5_fc_counters_lookup_next(struct mlx5_core_dev *dev,
+ u32 id)
{
- struct rb_node **new = &root->rb_node;
- struct rb_node *parent = NULL;
-
- while (*new) {
- struct mlx5_fc *this = rb_entry(*new, struct mlx5_fc, node);
- int result = counter->id - this->id;
-
- parent = *new;
- if (result < 0)
- new = &((*new)->rb_left);
- else
- new = &((*new)->rb_right);
- }
+ struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats;
+ unsigned long next_id = (unsigned long)id + 1;
+ struct mlx5_fc *counter;
+
+ rcu_read_lock();
+ /* skip counters that are in idr, but not yet in counters list */
+ while ((counter = idr_get_next_ul(&fc_stats->counters_idr,
+ &next_id)) != NULL &&
+ list_empty(&counter->list))
+ next_id++;
+ rcu_read_unlock();
+
+ return counter ? &counter->list : &fc_stats->counters;
+}
+
+static void mlx5_fc_stats_insert(struct mlx5_core_dev *dev,
+ struct mlx5_fc *counter)
+{
+ struct list_head *next = mlx5_fc_counters_lookup_next(dev, counter->id);
+
+ list_add_tail(&counter->list, next);
+}
+
+static void mlx5_fc_stats_remove(struct mlx5_core_dev *dev,
+ struct mlx5_fc *counter)
+{
+ struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats;
- /* Add new node and rebalance tree. */
- rb_link_node(&counter->node, parent, new);
- rb_insert_color(&counter->node, root);
+ list_del(&counter->list);
+
+ spin_lock(&fc_stats->counters_idr_lock);
+ WARN_ON(!idr_remove(&fc_stats->counters_idr, counter->id));
+ spin_unlock(&fc_stats->counters_idr_lock);
}
-/* The function returns the last node that was queried so the caller
+/* The function returns the last counter that was queried so the caller
* function can continue calling it till all counters are queried.
*/
-static struct rb_node *mlx5_fc_stats_query(struct mlx5_core_dev *dev,
+static struct mlx5_fc *mlx5_fc_stats_query(struct mlx5_core_dev *dev,
struct mlx5_fc *first,
u32 last_id)
{
+ struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats;
+ struct mlx5_fc *counter = NULL;
struct mlx5_cmd_fc_bulk *b;
- struct rb_node *node = NULL;
+ bool more = false;
u32 afirst_id;
int num;
int err;
@@ -130,14 +151,16 @@ static struct rb_node *mlx5_fc_stats_query(struct mlx5_core_dev *dev,
goto out;
}
- for (node = &first->node; node; node = rb_next(node)) {
- struct mlx5_fc *counter = rb_entry(node, struct mlx5_fc, node);
+ counter = first;
+ list_for_each_entry_from(counter, &fc_stats->counters, list) {
struct mlx5_fc_cache *c = &counter->cache;
u64 packets;
u64 bytes;
- if (counter->id > last_id)
+ if (counter->id > last_id) {
+ more = true;
break;
+ }
mlx5_cmd_fc_bulk_get(dev, b,
counter->id, &packets, &bytes);
@@ -153,7 +176,14 @@ static struct rb_node *mlx5_fc_stats_query(struct mlx5_core_dev *dev,
out:
mlx5_cmd_fc_bulk_free(b);
- return node;
+ return more ? counter : NULL;
+}
+
+static void mlx5_free_fc(struct mlx5_core_dev *dev,
+ struct mlx5_fc *counter)
+{
+ mlx5_cmd_fc_free(dev, counter->id);
+ kfree(counter);
}
static void mlx5_fc_stats_work(struct work_struct *work)
@@ -161,52 +191,36 @@ static void mlx5_fc_stats_work(struct work_struct *work)
struct mlx5_core_dev *dev = container_of(work, struct mlx5_core_dev,
priv.fc_stats.work.work);
struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats;
+ /* Take dellist first to ensure that counters cannot be deleted before
+ * they are inserted.
+ */
+ struct llist_node *dellist = llist_del_all(&fc_stats->dellist);
+ struct llist_node *addlist = llist_del_all(&fc_stats->addlist);
+ struct mlx5_fc *counter = NULL, *last = NULL, *tmp;
unsigned long now = jiffies;
- struct mlx5_fc *counter = NULL;
- struct mlx5_fc *last = NULL;
- struct rb_node *node;
- LIST_HEAD(tmplist);
- spin_lock(&fc_stats->addlist_lock);
-
- list_splice_tail_init(&fc_stats->addlist, &tmplist);
-
- if (!list_empty(&tmplist) || !RB_EMPTY_ROOT(&fc_stats->counters))
+ if (addlist || !list_empty(&fc_stats->counters))
queue_delayed_work(fc_stats->wq, &fc_stats->work,
fc_stats->sampling_interval);
- spin_unlock(&fc_stats->addlist_lock);
-
- list_for_each_entry(counter, &tmplist, list)
- mlx5_fc_stats_insert(&fc_stats->counters, counter);
+ llist_for_each_entry(counter, addlist, addlist)
+ mlx5_fc_stats_insert(dev, counter);
- node = rb_first(&fc_stats->counters);
- while (node) {
- counter = rb_entry(node, struct mlx5_fc, node);
+ llist_for_each_entry_safe(counter, tmp, dellist, dellist) {
+ mlx5_fc_stats_remove(dev, counter);
- node = rb_next(node);
-
- if (counter->deleted) {
- rb_erase(&counter->node, &fc_stats->counters);
-
- mlx5_cmd_fc_free(dev, counter->id);
-
- kfree(counter);
- continue;
- }
-
- last = counter;
+ mlx5_free_fc(dev, counter);
}
- if (time_before(now, fc_stats->next_query) || !last)
+ if (time_before(now, fc_stats->next_query) ||
+ list_empty(&fc_stats->counters))
return;
+ last = list_last_entry(&fc_stats->counters, struct mlx5_fc, list);
- node = rb_first(&fc_stats->counters);
- while (node) {
- counter = rb_entry(node, struct mlx5_fc, node);
-
- node = mlx5_fc_stats_query(dev, counter, last->id);
- }
+ counter = list_first_entry(&fc_stats->counters, struct mlx5_fc,
+ list);
+ while (counter)
+ counter = mlx5_fc_stats_query(dev, counter, last->id);
fc_stats->next_query = now + fc_stats->sampling_interval;
}
@@ -220,24 +234,38 @@ struct mlx5_fc *mlx5_fc_create(struct mlx5_core_dev *dev, bool aging)
counter = kzalloc(sizeof(*counter), GFP_KERNEL);
if (!counter)
return ERR_PTR(-ENOMEM);
+ INIT_LIST_HEAD(&counter->list);
err = mlx5_cmd_fc_alloc(dev, &counter->id);
if (err)
goto err_out;
if (aging) {
+ u32 id = counter->id;
+
counter->cache.lastuse = jiffies;
counter->aging = true;
- spin_lock(&fc_stats->addlist_lock);
- list_add(&counter->list, &fc_stats->addlist);
- spin_unlock(&fc_stats->addlist_lock);
+ idr_preload(GFP_KERNEL);
+ spin_lock(&fc_stats->counters_idr_lock);
+
+ err = idr_alloc_u32(&fc_stats->counters_idr, counter, &id, id,
+ GFP_NOWAIT);
+
+ spin_unlock(&fc_stats->counters_idr_lock);
+ idr_preload_end();
+ if (err)
+ goto err_out_alloc;
+
+ llist_add(&counter->addlist, &fc_stats->addlist);
mod_delayed_work(fc_stats->wq, &fc_stats->work, 0);
}
return counter;
+err_out_alloc:
+ mlx5_cmd_fc_free(dev, counter->id);
err_out:
kfree(counter);
@@ -245,6 +273,12 @@ err_out:
}
EXPORT_SYMBOL(mlx5_fc_create);
+u32 mlx5_fc_id(struct mlx5_fc *counter)
+{
+ return counter->id;
+}
+EXPORT_SYMBOL(mlx5_fc_id);
+
void mlx5_fc_destroy(struct mlx5_core_dev *dev, struct mlx5_fc *counter)
{
struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats;
@@ -253,13 +287,12 @@ void mlx5_fc_destroy(struct mlx5_core_dev *dev, struct mlx5_fc *counter)
return;
if (counter->aging) {
- counter->deleted = true;
+ llist_add(&counter->dellist, &fc_stats->dellist);
mod_delayed_work(fc_stats->wq, &fc_stats->work, 0);
return;
}
- mlx5_cmd_fc_free(dev, counter->id);
- kfree(counter);
+ mlx5_free_fc(dev, counter);
}
EXPORT_SYMBOL(mlx5_fc_destroy);
@@ -267,9 +300,11 @@ int mlx5_init_fc_stats(struct mlx5_core_dev *dev)
{
struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats;
- fc_stats->counters = RB_ROOT;
- INIT_LIST_HEAD(&fc_stats->addlist);
- spin_lock_init(&fc_stats->addlist_lock);
+ spin_lock_init(&fc_stats->counters_idr_lock);
+ idr_init(&fc_stats->counters_idr);
+ INIT_LIST_HEAD(&fc_stats->counters);
+ init_llist_head(&fc_stats->addlist);
+ init_llist_head(&fc_stats->dellist);
fc_stats->wq = create_singlethread_workqueue("mlx5_fc");
if (!fc_stats->wq)
@@ -284,34 +319,22 @@ int mlx5_init_fc_stats(struct mlx5_core_dev *dev)
void mlx5_cleanup_fc_stats(struct mlx5_core_dev *dev)
{
struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats;
+ struct llist_node *tmplist;
struct mlx5_fc *counter;
struct mlx5_fc *tmp;
- struct rb_node *node;
cancel_delayed_work_sync(&dev->priv.fc_stats.work);
destroy_workqueue(dev->priv.fc_stats.wq);
dev->priv.fc_stats.wq = NULL;
- list_for_each_entry_safe(counter, tmp, &fc_stats->addlist, list) {
- list_del(&counter->list);
-
- mlx5_cmd_fc_free(dev, counter->id);
+ idr_destroy(&fc_stats->counters_idr);
- kfree(counter);
- }
-
- node = rb_first(&fc_stats->counters);
- while (node) {
- counter = rb_entry(node, struct mlx5_fc, node);
-
- node = rb_next(node);
+ tmplist = llist_del_all(&fc_stats->addlist);
+ llist_for_each_entry_safe(counter, tmp, tmplist, addlist)
+ mlx5_free_fc(dev, counter);
- rb_erase(&counter->node, &fc_stats->counters);
-
- mlx5_cmd_fc_free(dev, counter->id);
-
- kfree(counter);
- }
+ list_for_each_entry_safe(counter, tmp, &fc_stats->counters, list)
+ mlx5_free_fc(dev, counter);
}
int mlx5_fc_query(struct mlx5_core_dev *dev, struct mlx5_fc *counter,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
index 41ad24f0de2c..1ab6f7e3bec6 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
@@ -250,7 +250,7 @@ int mlx5_cmd_force_teardown_hca(struct mlx5_core_dev *dev)
if (ret)
return ret;
- force_state = MLX5_GET(teardown_hca_out, out, force_state);
+ force_state = MLX5_GET(teardown_hca_out, out, state);
if (force_state == MLX5_TEARDOWN_HCA_OUT_FORCE_STATE_FAIL) {
mlx5_core_warn(dev, "teardown with force mode failed, doing normal teardown\n");
return -EIO;
@@ -259,6 +259,54 @@ int mlx5_cmd_force_teardown_hca(struct mlx5_core_dev *dev)
return 0;
}
+#define MLX5_FAST_TEARDOWN_WAIT_MS 3000
+int mlx5_cmd_fast_teardown_hca(struct mlx5_core_dev *dev)
+{
+ unsigned long end, delay_ms = MLX5_FAST_TEARDOWN_WAIT_MS;
+ u32 out[MLX5_ST_SZ_DW(teardown_hca_out)] = {0};
+ u32 in[MLX5_ST_SZ_DW(teardown_hca_in)] = {0};
+ int state;
+ int ret;
+
+ if (!MLX5_CAP_GEN(dev, fast_teardown)) {
+ mlx5_core_dbg(dev, "fast teardown is not supported in the firmware\n");
+ return -EOPNOTSUPP;
+ }
+
+ MLX5_SET(teardown_hca_in, in, opcode, MLX5_CMD_OP_TEARDOWN_HCA);
+ MLX5_SET(teardown_hca_in, in, profile,
+ MLX5_TEARDOWN_HCA_IN_PROFILE_PREPARE_FAST_TEARDOWN);
+
+ ret = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
+ if (ret)
+ return ret;
+
+ state = MLX5_GET(teardown_hca_out, out, state);
+ if (state == MLX5_TEARDOWN_HCA_OUT_FORCE_STATE_FAIL) {
+ mlx5_core_warn(dev, "teardown with fast mode failed\n");
+ return -EIO;
+ }
+
+ mlx5_set_nic_state(dev, MLX5_NIC_IFC_DISABLED);
+
+ /* Loop until device state turns to disable */
+ end = jiffies + msecs_to_jiffies(delay_ms);
+ do {
+ if (mlx5_get_nic_state(dev) == MLX5_NIC_IFC_DISABLED)
+ break;
+
+ cond_resched();
+ } while (!time_after(jiffies, end));
+
+ if (mlx5_get_nic_state(dev) != MLX5_NIC_IFC_DISABLED) {
+ dev_err(&dev->pdev->dev, "NIC IFC still %d after %lums.\n",
+ mlx5_get_nic_state(dev), delay_ms);
+ return -EIO;
+ }
+
+ return 0;
+}
+
enum mlxsw_reg_mcc_instruction {
MLX5_REG_MCC_INSTRUCTION_LOCK_UPDATE_HANDLE = 0x01,
MLX5_REG_MCC_INSTRUCTION_RELEASE_UPDATE_HANDLE = 0x02,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c
index 9f39aeca863f..43118de8ee99 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/health.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c
@@ -59,22 +59,25 @@ enum {
};
enum {
- MLX5_NIC_IFC_FULL = 0,
- MLX5_NIC_IFC_DISABLED = 1,
- MLX5_NIC_IFC_NO_DRAM_NIC = 2,
- MLX5_NIC_IFC_INVALID = 3
-};
-
-enum {
MLX5_DROP_NEW_HEALTH_WORK,
MLX5_DROP_NEW_RECOVERY_WORK,
};
-static u8 get_nic_state(struct mlx5_core_dev *dev)
+u8 mlx5_get_nic_state(struct mlx5_core_dev *dev)
{
return (ioread32be(&dev->iseg->cmdq_addr_l_sz) >> 8) & 3;
}
+void mlx5_set_nic_state(struct mlx5_core_dev *dev, u8 state)
+{
+ u32 cur_cmdq_addr_l_sz;
+
+ cur_cmdq_addr_l_sz = ioread32be(&dev->iseg->cmdq_addr_l_sz);
+ iowrite32be((cur_cmdq_addr_l_sz & 0xFFFFF000) |
+ state << MLX5_NIC_IFC_OFFSET,
+ &dev->iseg->cmdq_addr_l_sz);
+}
+
static void trigger_cmd_completions(struct mlx5_core_dev *dev)
{
unsigned long flags;
@@ -103,7 +106,7 @@ static int in_fatal(struct mlx5_core_dev *dev)
struct mlx5_core_health *health = &dev->priv.health;
struct health_buffer __iomem *h = health->health;
- if (get_nic_state(dev) == MLX5_NIC_IFC_DISABLED)
+ if (mlx5_get_nic_state(dev) == MLX5_NIC_IFC_DISABLED)
return 1;
if (ioread32be(&h->fw_ver) == 0xffffffff)
@@ -133,7 +136,7 @@ unlock:
static void mlx5_handle_bad_state(struct mlx5_core_dev *dev)
{
- u8 nic_interface = get_nic_state(dev);
+ u8 nic_interface = mlx5_get_nic_state(dev);
switch (nic_interface) {
case MLX5_NIC_IFC_FULL:
@@ -168,7 +171,7 @@ static void health_recover(struct work_struct *work)
priv = container_of(health, struct mlx5_priv, health);
dev = container_of(priv, struct mlx5_core_dev, priv);
- nic_state = get_nic_state(dev);
+ nic_state = mlx5_get_nic_state(dev);
if (nic_state == MLX5_NIC_IFC_INVALID) {
dev_err(&dev->pdev->dev, "health recovery flow aborted since the nic state is invalid\n");
return;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c
index e3797a44e074..b59953daf8b4 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c
@@ -45,6 +45,7 @@ static int mlx5i_change_mtu(struct net_device *netdev, int new_mtu);
static const struct net_device_ops mlx5i_netdev_ops = {
.ndo_open = mlx5i_open,
.ndo_stop = mlx5i_close,
+ .ndo_get_stats64 = mlx5i_get_stats,
.ndo_init = mlx5i_dev_init,
.ndo_uninit = mlx5i_dev_cleanup,
.ndo_change_mtu = mlx5i_change_mtu,
@@ -70,26 +71,25 @@ static void mlx5i_build_nic_params(struct mlx5_core_dev *mdev,
}
/* Called directly after IPoIB netdevice was created to initialize SW structs */
-void mlx5i_init(struct mlx5_core_dev *mdev,
- struct net_device *netdev,
- const struct mlx5e_profile *profile,
- void *ppriv)
+int mlx5i_init(struct mlx5_core_dev *mdev,
+ struct net_device *netdev,
+ const struct mlx5e_profile *profile,
+ void *ppriv)
{
struct mlx5e_priv *priv = mlx5i_epriv(netdev);
u16 max_mtu;
+ int err;
- /* priv init */
- priv->mdev = mdev;
- priv->netdev = netdev;
- priv->profile = profile;
- priv->ppriv = ppriv;
- mutex_init(&priv->state_lock);
+ err = mlx5e_netdev_init(netdev, priv, mdev, profile, ppriv);
+ if (err)
+ return err;
mlx5_query_port_max_mtu(mdev, &max_mtu, 1);
netdev->mtu = max_mtu;
mlx5e_build_nic_params(mdev, &priv->channels.params,
- profile->max_nch(mdev), netdev->mtu);
+ mlx5e_get_netdev_max_channels(netdev),
+ netdev->mtu);
mlx5i_build_nic_params(mdev, &priv->channels.params);
mlx5e_timestamp_init(priv);
@@ -106,12 +106,56 @@ void mlx5i_init(struct mlx5_core_dev *mdev,
netdev->netdev_ops = &mlx5i_netdev_ops;
netdev->ethtool_ops = &mlx5i_ethtool_ops;
+
+ return 0;
}
/* Called directly before IPoIB netdevice is destroyed to cleanup SW structs */
-static void mlx5i_cleanup(struct mlx5e_priv *priv)
+void mlx5i_cleanup(struct mlx5e_priv *priv)
+{
+ mlx5e_netdev_cleanup(priv->netdev, priv);
+}
+
+static void mlx5i_grp_sw_update_stats(struct mlx5e_priv *priv)
+{
+ int max_nch = mlx5e_get_netdev_max_channels(priv->netdev);
+ struct mlx5e_sw_stats s = { 0 };
+ int i, j;
+
+ for (i = 0; i < max_nch; i++) {
+ struct mlx5e_channel_stats *channel_stats;
+ struct mlx5e_rq_stats *rq_stats;
+
+ channel_stats = &priv->channel_stats[i];
+ rq_stats = &channel_stats->rq;
+
+ s.rx_packets += rq_stats->packets;
+ s.rx_bytes += rq_stats->bytes;
+
+ for (j = 0; j < priv->max_opened_tc; j++) {
+ struct mlx5e_sq_stats *sq_stats = &channel_stats->sq[j];
+
+ s.tx_packets += sq_stats->packets;
+ s.tx_bytes += sq_stats->bytes;
+ s.tx_queue_dropped += sq_stats->dropped;
+ }
+ }
+
+ memcpy(&priv->stats.sw, &s, sizeof(s));
+}
+
+void mlx5i_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats)
{
- /* Do nothing .. */
+ struct mlx5e_priv *priv = mlx5i_epriv(dev);
+ struct mlx5e_sw_stats *sstats = &priv->stats.sw;
+
+ mlx5i_grp_sw_update_stats(priv);
+
+ stats->rx_packets = sstats->rx_packets;
+ stats->rx_bytes = sstats->rx_bytes;
+ stats->tx_packets = sstats->tx_packets;
+ stats->tx_bytes = sstats->tx_bytes;
+ stats->tx_dropped = sstats->tx_queue_dropped;
}
int mlx5i_init_underlay_qp(struct mlx5e_priv *priv)
@@ -306,17 +350,26 @@ static void mlx5i_destroy_flow_steering(struct mlx5e_priv *priv)
static int mlx5i_init_rx(struct mlx5e_priv *priv)
{
+ struct mlx5_core_dev *mdev = priv->mdev;
int err;
+ mlx5e_create_q_counters(priv);
+
+ err = mlx5e_open_drop_rq(priv, &priv->drop_rq);
+ if (err) {
+ mlx5_core_err(mdev, "open drop rq failed, %d\n", err);
+ goto err_destroy_q_counters;
+ }
+
err = mlx5e_create_indirect_rqt(priv);
if (err)
- return err;
+ goto err_close_drop_rq;
err = mlx5e_create_direct_rqts(priv);
if (err)
goto err_destroy_indirect_rqts;
- err = mlx5e_create_indirect_tirs(priv);
+ err = mlx5e_create_indirect_tirs(priv, true);
if (err)
goto err_destroy_direct_rqts;
@@ -333,11 +386,15 @@ static int mlx5i_init_rx(struct mlx5e_priv *priv)
err_destroy_direct_tirs:
mlx5e_destroy_direct_tirs(priv);
err_destroy_indirect_tirs:
- mlx5e_destroy_indirect_tirs(priv);
+ mlx5e_destroy_indirect_tirs(priv, true);
err_destroy_direct_rqts:
mlx5e_destroy_direct_rqts(priv);
err_destroy_indirect_rqts:
mlx5e_destroy_rqt(priv, &priv->indir_rqt);
+err_close_drop_rq:
+ mlx5e_close_drop_rq(&priv->drop_rq);
+err_destroy_q_counters:
+ mlx5e_destroy_q_counters(priv);
return err;
}
@@ -345,9 +402,11 @@ static void mlx5i_cleanup_rx(struct mlx5e_priv *priv)
{
mlx5i_destroy_flow_steering(priv);
mlx5e_destroy_direct_tirs(priv);
- mlx5e_destroy_indirect_tirs(priv);
+ mlx5e_destroy_indirect_tirs(priv, true);
mlx5e_destroy_direct_rqts(priv);
mlx5e_destroy_rqt(priv, &priv->indir_rqt);
+ mlx5e_close_drop_rq(&priv->drop_rq);
+ mlx5e_destroy_q_counters(priv);
}
static const struct mlx5e_profile mlx5i_nic_profile = {
@@ -360,7 +419,6 @@ static const struct mlx5e_profile mlx5i_nic_profile = {
.enable = NULL, /* mlx5i_enable */
.disable = NULL, /* mlx5i_disable */
.update_stats = NULL, /* mlx5i_update_stats */
- .max_nch = mlx5e_get_max_num_channels,
.update_carrier = NULL, /* no HW update in IB link */
.rx_handlers.handle_rx_cqe = mlx5i_handle_rx_cqe,
.rx_handlers.handle_rx_cqe_mpwqe = NULL, /* Not supported */
@@ -592,7 +650,6 @@ static void mlx5_rdma_netdev_free(struct net_device *netdev)
mlx5e_detach_netdev(priv);
profile->cleanup(priv);
- destroy_workqueue(priv->wq);
if (!ipriv->sub_interface) {
mlx5i_pkey_qpn_ht_cleanup(netdev);
@@ -600,58 +657,37 @@ static void mlx5_rdma_netdev_free(struct net_device *netdev)
}
}
-struct net_device *mlx5_rdma_netdev_alloc(struct mlx5_core_dev *mdev,
- struct ib_device *ibdev,
- const char *name,
- void (*setup)(struct net_device *))
+static bool mlx5_is_sub_interface(struct mlx5_core_dev *mdev)
+{
+ return mdev->mlx5e_res.pdn != 0;
+}
+
+static const struct mlx5e_profile *mlx5_get_profile(struct mlx5_core_dev *mdev)
+{
+ if (mlx5_is_sub_interface(mdev))
+ return mlx5i_pkey_get_profile();
+ return &mlx5i_nic_profile;
+}
+
+static int mlx5_rdma_setup_rn(struct ib_device *ibdev, u8 port_num,
+ struct net_device *netdev, void *param)
{
- const struct mlx5e_profile *profile;
- struct net_device *netdev;
+ struct mlx5_core_dev *mdev = (struct mlx5_core_dev *)param;
+ const struct mlx5e_profile *prof = mlx5_get_profile(mdev);
struct mlx5i_priv *ipriv;
struct mlx5e_priv *epriv;
struct rdma_netdev *rn;
- bool sub_interface;
- int nch;
int err;
- if (mlx5i_check_required_hca_cap(mdev)) {
- mlx5_core_warn(mdev, "Accelerated mode is not supported\n");
- return ERR_PTR(-EOPNOTSUPP);
- }
-
- /* TODO: Need to find a better way to check if child device*/
- sub_interface = (mdev->mlx5e_res.pdn != 0);
-
- if (sub_interface)
- profile = mlx5i_pkey_get_profile();
- else
- profile = &mlx5i_nic_profile;
-
- nch = profile->max_nch(mdev);
-
- netdev = alloc_netdev_mqs(sizeof(struct mlx5i_priv) + sizeof(struct mlx5e_priv),
- name, NET_NAME_UNKNOWN,
- setup,
- nch * MLX5E_MAX_NUM_TC,
- nch);
- if (!netdev) {
- mlx5_core_warn(mdev, "alloc_netdev_mqs failed\n");
- return NULL;
- }
-
ipriv = netdev_priv(netdev);
epriv = mlx5i_epriv(netdev);
- epriv->wq = create_singlethread_workqueue("mlx5i");
- if (!epriv->wq)
- goto err_free_netdev;
-
- ipriv->sub_interface = sub_interface;
+ ipriv->sub_interface = mlx5_is_sub_interface(mdev);
if (!ipriv->sub_interface) {
err = mlx5i_pkey_qpn_ht_init(netdev);
if (err) {
mlx5_core_warn(mdev, "allocate qpn_to_netdev ht failed\n");
- goto destroy_wq;
+ return err;
}
/* This should only be called once per mdev */
@@ -660,7 +696,7 @@ struct net_device *mlx5_rdma_netdev_alloc(struct mlx5_core_dev *mdev,
goto destroy_ht;
}
- profile->init(mdev, netdev, profile, ipriv);
+ prof->init(mdev, netdev, prof, ipriv);
mlx5e_attach_netdev(epriv);
netif_carrier_off(netdev);
@@ -676,15 +712,35 @@ struct net_device *mlx5_rdma_netdev_alloc(struct mlx5_core_dev *mdev,
netdev->priv_destructor = mlx5_rdma_netdev_free;
netdev->needs_free_netdev = 1;
- return netdev;
+ return 0;
destroy_ht:
mlx5i_pkey_qpn_ht_cleanup(netdev);
-destroy_wq:
- destroy_workqueue(epriv->wq);
-err_free_netdev:
- free_netdev(netdev);
+ return err;
+}
- return NULL;
+int mlx5_rdma_rn_get_params(struct mlx5_core_dev *mdev,
+ struct ib_device *device,
+ struct rdma_netdev_alloc_params *params)
+{
+ int nch;
+ int rc;
+
+ rc = mlx5i_check_required_hca_cap(mdev);
+ if (rc)
+ return rc;
+
+ nch = mlx5e_get_max_num_channels(mdev);
+
+ *params = (struct rdma_netdev_alloc_params){
+ .sizeof_priv = sizeof(struct mlx5i_priv) +
+ sizeof(struct mlx5e_priv),
+ .txqs = nch * MLX5E_MAX_NUM_TC,
+ .rxqs = nch,
+ .param = mdev,
+ .initialize_rdma_netdev = mlx5_rdma_setup_rn,
+ };
+
+ return 0;
}
-EXPORT_SYMBOL(mlx5_rdma_netdev_alloc);
+EXPORT_SYMBOL(mlx5_rdma_rn_get_params);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h
index 08eac92fc26c..9165ca567047 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h
@@ -84,10 +84,11 @@ void mlx5i_dev_cleanup(struct net_device *dev);
int mlx5i_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
/* Parent profile functions */
-void mlx5i_init(struct mlx5_core_dev *mdev,
- struct net_device *netdev,
- const struct mlx5e_profile *profile,
- void *ppriv);
+int mlx5i_init(struct mlx5_core_dev *mdev,
+ struct net_device *netdev,
+ const struct mlx5e_profile *profile,
+ void *ppriv);
+void mlx5i_cleanup(struct mlx5e_priv *priv);
/* Get child interface nic profile */
const struct mlx5e_profile *mlx5i_pkey_get_profile(void);
@@ -109,18 +110,18 @@ struct mlx5i_tx_wqe {
static inline void mlx5i_sq_fetch_wqe(struct mlx5e_txqsq *sq,
struct mlx5i_tx_wqe **wqe,
- u16 *pi)
+ u16 pi)
{
struct mlx5_wq_cyc *wq = &sq->wq;
- *pi = mlx5_wq_cyc_ctr2ix(wq, sq->pc);
- *wqe = mlx5_wq_cyc_get_wqe(wq, *pi);
+ *wqe = mlx5_wq_cyc_get_wqe(wq, pi);
memset(*wqe, 0, sizeof(**wqe));
}
netdev_tx_t mlx5i_sq_xmit(struct mlx5e_txqsq *sq, struct sk_buff *skb,
struct mlx5_av *av, u32 dqpn, u32 dqkey);
void mlx5i_handle_rx_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe);
+void mlx5i_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats);
#endif /* CONFIG_MLX5_CORE_IPOIB */
#endif /* __MLX5E_IPOB_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c
index 54a188f41f90..b491b8f5fd6b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c
@@ -146,6 +146,7 @@ static const struct net_device_ops mlx5i_pkey_netdev_ops = {
.ndo_open = mlx5i_pkey_open,
.ndo_stop = mlx5i_pkey_close,
.ndo_init = mlx5i_pkey_dev_init,
+ .ndo_get_stats64 = mlx5i_get_stats,
.ndo_uninit = mlx5i_pkey_dev_cleanup,
.ndo_change_mtu = mlx5i_pkey_change_mtu,
.ndo_do_ioctl = mlx5i_pkey_ioctl,
@@ -274,14 +275,17 @@ static int mlx5i_pkey_change_mtu(struct net_device *netdev, int new_mtu)
}
/* Called directly after IPoIB netdevice was created to initialize SW structs */
-static void mlx5i_pkey_init(struct mlx5_core_dev *mdev,
- struct net_device *netdev,
- const struct mlx5e_profile *profile,
- void *ppriv)
+static int mlx5i_pkey_init(struct mlx5_core_dev *mdev,
+ struct net_device *netdev,
+ const struct mlx5e_profile *profile,
+ void *ppriv)
{
struct mlx5e_priv *priv = mlx5i_epriv(netdev);
+ int err;
- mlx5i_init(mdev, netdev, profile, ppriv);
+ err = mlx5i_init(mdev, netdev, profile, ppriv);
+ if (err)
+ return err;
/* Override parent ndo */
netdev->netdev_ops = &mlx5i_pkey_netdev_ops;
@@ -291,12 +295,14 @@ static void mlx5i_pkey_init(struct mlx5_core_dev *mdev,
/* Use dummy rqs */
priv->channels.params.log_rq_mtu_frames = MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE;
+
+ return 0;
}
/* Called directly before IPoIB netdevice is destroyed to cleanup SW structs */
static void mlx5i_pkey_cleanup(struct mlx5e_priv *priv)
{
- /* Do nothing .. */
+ mlx5i_cleanup(priv);
}
static int mlx5i_pkey_init_tx(struct mlx5e_priv *priv)
@@ -345,7 +351,6 @@ static const struct mlx5e_profile mlx5i_pkey_nic_profile = {
.enable = NULL,
.disable = NULL,
.update_stats = NULL,
- .max_nch = mlx5e_get_max_num_channels,
.rx_handlers.handle_rx_cqe = mlx5i_handle_rx_cqe,
.rx_handlers.handle_rx_cqe_mpwqe = NULL, /* Not supported */
.max_tc = MLX5I_MAX_NUM_TC,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c
index 3f767cde4c1d..0d90b1b4a3d3 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c
@@ -111,10 +111,10 @@ static void mlx5_pps_out(struct work_struct *work)
for (i = 0; i < clock->ptp_info.n_pins; i++) {
u64 tstart;
- write_lock_irqsave(&clock->lock, flags);
+ write_seqlock_irqsave(&clock->lock, flags);
tstart = clock->pps_info.start[i];
clock->pps_info.start[i] = 0;
- write_unlock_irqrestore(&clock->lock, flags);
+ write_sequnlock_irqrestore(&clock->lock, flags);
if (!tstart)
continue;
@@ -132,10 +132,10 @@ static void mlx5_timestamp_overflow(struct work_struct *work)
overflow_work);
unsigned long flags;
- write_lock_irqsave(&clock->lock, flags);
+ write_seqlock_irqsave(&clock->lock, flags);
timecounter_read(&clock->tc);
mlx5_update_clock_info_page(clock->mdev);
- write_unlock_irqrestore(&clock->lock, flags);
+ write_sequnlock_irqrestore(&clock->lock, flags);
schedule_delayed_work(&clock->overflow_work, clock->overflow_period);
}
@@ -147,10 +147,10 @@ static int mlx5_ptp_settime(struct ptp_clock_info *ptp,
u64 ns = timespec64_to_ns(ts);
unsigned long flags;
- write_lock_irqsave(&clock->lock, flags);
+ write_seqlock_irqsave(&clock->lock, flags);
timecounter_init(&clock->tc, &clock->cycles, ns);
mlx5_update_clock_info_page(clock->mdev);
- write_unlock_irqrestore(&clock->lock, flags);
+ write_sequnlock_irqrestore(&clock->lock, flags);
return 0;
}
@@ -162,9 +162,9 @@ static int mlx5_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
u64 ns;
unsigned long flags;
- write_lock_irqsave(&clock->lock, flags);
+ write_seqlock_irqsave(&clock->lock, flags);
ns = timecounter_read(&clock->tc);
- write_unlock_irqrestore(&clock->lock, flags);
+ write_sequnlock_irqrestore(&clock->lock, flags);
*ts = ns_to_timespec64(ns);
@@ -177,10 +177,10 @@ static int mlx5_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
ptp_info);
unsigned long flags;
- write_lock_irqsave(&clock->lock, flags);
+ write_seqlock_irqsave(&clock->lock, flags);
timecounter_adjtime(&clock->tc, delta);
mlx5_update_clock_info_page(clock->mdev);
- write_unlock_irqrestore(&clock->lock, flags);
+ write_sequnlock_irqrestore(&clock->lock, flags);
return 0;
}
@@ -203,12 +203,12 @@ static int mlx5_ptp_adjfreq(struct ptp_clock_info *ptp, s32 delta)
adj *= delta;
diff = div_u64(adj, 1000000000ULL);
- write_lock_irqsave(&clock->lock, flags);
+ write_seqlock_irqsave(&clock->lock, flags);
timecounter_read(&clock->tc);
clock->cycles.mult = neg_adj ? clock->nominal_c_mult - diff :
clock->nominal_c_mult + diff;
mlx5_update_clock_info_page(clock->mdev);
- write_unlock_irqrestore(&clock->lock, flags);
+ write_sequnlock_irqrestore(&clock->lock, flags);
return 0;
}
@@ -307,12 +307,12 @@ static int mlx5_perout_configure(struct ptp_clock_info *ptp,
ts.tv_nsec = rq->perout.start.nsec;
ns = timespec64_to_ns(&ts);
cycles_now = mlx5_read_internal_timer(mdev);
- write_lock_irqsave(&clock->lock, flags);
+ write_seqlock_irqsave(&clock->lock, flags);
nsec_now = timecounter_cyc2time(&clock->tc, cycles_now);
nsec_delta = ns - nsec_now;
cycles_delta = div64_u64(nsec_delta << clock->cycles.shift,
clock->cycles.mult);
- write_unlock_irqrestore(&clock->lock, flags);
+ write_sequnlock_irqrestore(&clock->lock, flags);
time_stamp = cycles_now + cycles_delta;
field_select = MLX5_MTPPS_FS_PIN_MODE |
MLX5_MTPPS_FS_PATTERN |
@@ -471,14 +471,14 @@ void mlx5_pps_event(struct mlx5_core_dev *mdev,
ts.tv_sec += 1;
ts.tv_nsec = 0;
ns = timespec64_to_ns(&ts);
- write_lock_irqsave(&clock->lock, flags);
+ write_seqlock_irqsave(&clock->lock, flags);
nsec_now = timecounter_cyc2time(&clock->tc, cycles_now);
nsec_delta = ns - nsec_now;
cycles_delta = div64_u64(nsec_delta << clock->cycles.shift,
clock->cycles.mult);
clock->pps_info.start[pin] = cycles_now + cycles_delta;
schedule_work(&clock->pps_info.out_work);
- write_unlock_irqrestore(&clock->lock, flags);
+ write_sequnlock_irqrestore(&clock->lock, flags);
break;
default:
mlx5_core_err(mdev, " Unhandled event\n");
@@ -498,7 +498,7 @@ void mlx5_init_clock(struct mlx5_core_dev *mdev)
mlx5_core_warn(mdev, "invalid device_frequency_khz, aborting HW clock init\n");
return;
}
- rwlock_init(&clock->lock);
+ seqlock_init(&clock->lock);
clock->cycles.read = read_internal_timer;
clock->cycles.shift = MLX5_CYCLES_SHIFT;
clock->cycles.mult = clocksource_khz2mult(dev_freq,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.h
index 02e2e4575e4f..263cb6e2aeee 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.h
@@ -46,11 +46,13 @@ static inline int mlx5_clock_get_ptp_index(struct mlx5_core_dev *mdev)
static inline ktime_t mlx5_timecounter_cyc2time(struct mlx5_clock *clock,
u64 timestamp)
{
+ unsigned int seq;
u64 nsec;
- read_lock(&clock->lock);
- nsec = timecounter_cyc2time(&clock->tc, timestamp);
- read_unlock(&clock->lock);
+ do {
+ seq = read_seqbegin(&clock->lock);
+ nsec = timecounter_cyc2time(&clock->tc, timestamp);
+ } while (read_seqretry(&clock->lock, seq));
return ns_to_ktime(nsec);
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
index b5e9f664fc66..28132c7dc05f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -1594,12 +1594,17 @@ static const struct pci_error_handlers mlx5_err_handler = {
static int mlx5_try_fast_unload(struct mlx5_core_dev *dev)
{
- int ret;
+ bool fast_teardown = false, force_teardown = false;
+ int ret = 1;
+
+ fast_teardown = MLX5_CAP_GEN(dev, fast_teardown);
+ force_teardown = MLX5_CAP_GEN(dev, force_teardown);
+
+ mlx5_core_dbg(dev, "force teardown firmware support=%d\n", force_teardown);
+ mlx5_core_dbg(dev, "fast teardown firmware support=%d\n", fast_teardown);
- if (!MLX5_CAP_GEN(dev, force_teardown)) {
- mlx5_core_dbg(dev, "force teardown is not supported in the firmware\n");
+ if (!fast_teardown && !force_teardown)
return -EOPNOTSUPP;
- }
if (dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) {
mlx5_core_dbg(dev, "Device in internal error state, giving up\n");
@@ -1612,13 +1617,19 @@ static int mlx5_try_fast_unload(struct mlx5_core_dev *dev)
mlx5_drain_health_wq(dev);
mlx5_stop_health_poll(dev, false);
+ ret = mlx5_cmd_fast_teardown_hca(dev);
+ if (!ret)
+ goto succeed;
+
ret = mlx5_cmd_force_teardown_hca(dev);
- if (ret) {
- mlx5_core_dbg(dev, "Firmware couldn't do fast unload error: %d\n", ret);
- mlx5_start_health_poll(dev);
- return ret;
- }
+ if (!ret)
+ goto succeed;
+
+ mlx5_core_dbg(dev, "Firmware couldn't do fast unload error: %d\n", ret);
+ mlx5_start_health_poll(dev);
+ return ret;
+succeed:
mlx5_enter_error_state(dev, true);
/* Some platforms requiring freeing the IRQ's in the shutdown
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
index b4134fa0bba3..0594d0961cb3 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
@@ -39,6 +39,7 @@
#include <linux/if_link.h>
#include <linux/firmware.h>
#include <linux/mlx5/cq.h>
+#include <linux/mlx5/fs.h>
#define DRIVER_NAME "mlx5_core"
#define DRIVER_VERSION "5.0-0"
@@ -95,6 +96,8 @@ int mlx5_query_board_id(struct mlx5_core_dev *dev);
int mlx5_cmd_init_hca(struct mlx5_core_dev *dev, uint32_t *sw_owner_id);
int mlx5_cmd_teardown_hca(struct mlx5_core_dev *dev);
int mlx5_cmd_force_teardown_hca(struct mlx5_core_dev *dev);
+int mlx5_cmd_fast_teardown_hca(struct mlx5_core_dev *dev);
+
void mlx5_core_event(struct mlx5_core_dev *dev, enum mlx5_dev_event event,
unsigned long param);
void mlx5_core_page_fault(struct mlx5_core_dev *dev,
@@ -169,17 +172,6 @@ struct mlx5_core_dev *mlx5_get_next_phys_dev(struct mlx5_core_dev *dev);
void mlx5_dev_list_lock(void);
void mlx5_dev_list_unlock(void);
int mlx5_dev_list_trylock(void);
-int mlx5_encap_alloc(struct mlx5_core_dev *dev,
- int header_type,
- size_t size,
- void *encap_header,
- u32 *encap_id);
-void mlx5_encap_dealloc(struct mlx5_core_dev *dev, u32 encap_id);
-
-int mlx5_modify_header_alloc(struct mlx5_core_dev *dev,
- u8 namespace, u8 num_actions,
- void *modify_actions, u32 *modify_header_id);
-void mlx5_modify_header_dealloc(struct mlx5_core_dev *dev, u32 modify_header_id);
bool mlx5_lag_intf_add(struct mlx5_interface *intf, struct mlx5_priv *priv);
@@ -214,4 +206,14 @@ int mlx5_lag_allow(struct mlx5_core_dev *dev);
int mlx5_lag_forbid(struct mlx5_core_dev *dev);
void mlx5_reload_interface(struct mlx5_core_dev *mdev, int protocol);
+
+enum {
+ MLX5_NIC_IFC_FULL = 0,
+ MLX5_NIC_IFC_DISABLED = 1,
+ MLX5_NIC_IFC_NO_DRAM_NIC = 2,
+ MLX5_NIC_IFC_INVALID = 3
+};
+
+u8 mlx5_get_nic_state(struct mlx5_core_dev *dev);
+void mlx5_set_nic_state(struct mlx5_core_dev *dev, u8 state);
#endif /* __MLX5_CORE_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/qp.c b/drivers/net/ethernet/mellanox/mlx5/core/qp.c
index 4ca07bfb6b14..91b8139a388d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/qp.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/qp.c
@@ -211,6 +211,7 @@ int mlx5_core_create_dct(struct mlx5_core_dev *dev,
}
qp->qpn = MLX5_GET(create_dct_out, out, dctn);
+ qp->uid = MLX5_GET(create_dct_in, in, uid);
err = create_resource_common(dev, qp, MLX5_RES_DCT);
if (err)
goto err_cmd;
@@ -219,6 +220,7 @@ int mlx5_core_create_dct(struct mlx5_core_dev *dev,
err_cmd:
MLX5_SET(destroy_dct_in, din, opcode, MLX5_CMD_OP_DESTROY_DCT);
MLX5_SET(destroy_dct_in, din, dctn, qp->qpn);
+ MLX5_SET(destroy_dct_in, din, uid, qp->uid);
mlx5_cmd_exec(dev, (void *)&in, sizeof(din),
(void *)&out, sizeof(dout));
return err;
@@ -240,6 +242,7 @@ int mlx5_core_create_qp(struct mlx5_core_dev *dev,
if (err)
return err;
+ qp->uid = MLX5_GET(create_qp_in, in, uid);
qp->qpn = MLX5_GET(create_qp_out, out, qpn);
mlx5_core_dbg(dev, "qpn = 0x%x\n", qp->qpn);
@@ -261,6 +264,7 @@ err_cmd:
memset(dout, 0, sizeof(dout));
MLX5_SET(destroy_qp_in, din, opcode, MLX5_CMD_OP_DESTROY_QP);
MLX5_SET(destroy_qp_in, din, qpn, qp->qpn);
+ MLX5_SET(destroy_qp_in, din, uid, qp->uid);
mlx5_cmd_exec(dev, din, sizeof(din), dout, sizeof(dout));
return err;
}
@@ -275,6 +279,7 @@ static int mlx5_core_drain_dct(struct mlx5_core_dev *dev,
MLX5_SET(drain_dct_in, in, opcode, MLX5_CMD_OP_DRAIN_DCT);
MLX5_SET(drain_dct_in, in, dctn, qp->qpn);
+ MLX5_SET(drain_dct_in, in, uid, qp->uid);
return mlx5_cmd_exec(dev, (void *)&in, sizeof(in),
(void *)&out, sizeof(out));
}
@@ -301,6 +306,7 @@ destroy:
destroy_resource_common(dev, &dct->mqp);
MLX5_SET(destroy_dct_in, in, opcode, MLX5_CMD_OP_DESTROY_DCT);
MLX5_SET(destroy_dct_in, in, dctn, qp->qpn);
+ MLX5_SET(destroy_dct_in, in, uid, qp->uid);
err = mlx5_cmd_exec(dev, (void *)&in, sizeof(in),
(void *)&out, sizeof(out));
return err;
@@ -320,6 +326,7 @@ int mlx5_core_destroy_qp(struct mlx5_core_dev *dev,
MLX5_SET(destroy_qp_in, in, opcode, MLX5_CMD_OP_DESTROY_QP);
MLX5_SET(destroy_qp_in, in, qpn, qp->qpn);
+ MLX5_SET(destroy_qp_in, in, uid, qp->uid);
err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
if (err)
return err;
@@ -373,7 +380,7 @@ static void mbox_free(struct mbox_info *mbox)
static int modify_qp_mbox_alloc(struct mlx5_core_dev *dev, u16 opcode, int qpn,
u32 opt_param_mask, void *qpc,
- struct mbox_info *mbox)
+ struct mbox_info *mbox, u16 uid)
{
mbox->out = NULL;
mbox->in = NULL;
@@ -381,26 +388,32 @@ static int modify_qp_mbox_alloc(struct mlx5_core_dev *dev, u16 opcode, int qpn,
#define MBOX_ALLOC(mbox, typ) \
mbox_alloc(mbox, MLX5_ST_SZ_BYTES(typ##_in), MLX5_ST_SZ_BYTES(typ##_out))
-#define MOD_QP_IN_SET(typ, in, _opcode, _qpn) \
- MLX5_SET(typ##_in, in, opcode, _opcode); \
- MLX5_SET(typ##_in, in, qpn, _qpn)
-
-#define MOD_QP_IN_SET_QPC(typ, in, _opcode, _qpn, _opt_p, _qpc) \
- MOD_QP_IN_SET(typ, in, _opcode, _qpn); \
- MLX5_SET(typ##_in, in, opt_param_mask, _opt_p); \
- memcpy(MLX5_ADDR_OF(typ##_in, in, qpc), _qpc, MLX5_ST_SZ_BYTES(qpc))
+#define MOD_QP_IN_SET(typ, in, _opcode, _qpn, _uid) \
+ do { \
+ MLX5_SET(typ##_in, in, opcode, _opcode); \
+ MLX5_SET(typ##_in, in, qpn, _qpn); \
+ MLX5_SET(typ##_in, in, uid, _uid); \
+ } while (0)
+
+#define MOD_QP_IN_SET_QPC(typ, in, _opcode, _qpn, _opt_p, _qpc, _uid) \
+ do { \
+ MOD_QP_IN_SET(typ, in, _opcode, _qpn, _uid); \
+ MLX5_SET(typ##_in, in, opt_param_mask, _opt_p); \
+ memcpy(MLX5_ADDR_OF(typ##_in, in, qpc), _qpc, \
+ MLX5_ST_SZ_BYTES(qpc)); \
+ } while (0)
switch (opcode) {
/* 2RST & 2ERR */
case MLX5_CMD_OP_2RST_QP:
if (MBOX_ALLOC(mbox, qp_2rst))
return -ENOMEM;
- MOD_QP_IN_SET(qp_2rst, mbox->in, opcode, qpn);
+ MOD_QP_IN_SET(qp_2rst, mbox->in, opcode, qpn, uid);
break;
case MLX5_CMD_OP_2ERR_QP:
if (MBOX_ALLOC(mbox, qp_2err))
return -ENOMEM;
- MOD_QP_IN_SET(qp_2err, mbox->in, opcode, qpn);
+ MOD_QP_IN_SET(qp_2err, mbox->in, opcode, qpn, uid);
break;
/* MODIFY with QPC */
@@ -408,37 +421,37 @@ static int modify_qp_mbox_alloc(struct mlx5_core_dev *dev, u16 opcode, int qpn,
if (MBOX_ALLOC(mbox, rst2init_qp))
return -ENOMEM;
MOD_QP_IN_SET_QPC(rst2init_qp, mbox->in, opcode, qpn,
- opt_param_mask, qpc);
+ opt_param_mask, qpc, uid);
break;
case MLX5_CMD_OP_INIT2RTR_QP:
if (MBOX_ALLOC(mbox, init2rtr_qp))
return -ENOMEM;
MOD_QP_IN_SET_QPC(init2rtr_qp, mbox->in, opcode, qpn,
- opt_param_mask, qpc);
+ opt_param_mask, qpc, uid);
break;
case MLX5_CMD_OP_RTR2RTS_QP:
if (MBOX_ALLOC(mbox, rtr2rts_qp))
return -ENOMEM;
MOD_QP_IN_SET_QPC(rtr2rts_qp, mbox->in, opcode, qpn,
- opt_param_mask, qpc);
+ opt_param_mask, qpc, uid);
break;
case MLX5_CMD_OP_RTS2RTS_QP:
if (MBOX_ALLOC(mbox, rts2rts_qp))
return -ENOMEM;
MOD_QP_IN_SET_QPC(rts2rts_qp, mbox->in, opcode, qpn,
- opt_param_mask, qpc);
+ opt_param_mask, qpc, uid);
break;
case MLX5_CMD_OP_SQERR2RTS_QP:
if (MBOX_ALLOC(mbox, sqerr2rts_qp))
return -ENOMEM;
MOD_QP_IN_SET_QPC(sqerr2rts_qp, mbox->in, opcode, qpn,
- opt_param_mask, qpc);
+ opt_param_mask, qpc, uid);
break;
case MLX5_CMD_OP_INIT2INIT_QP:
if (MBOX_ALLOC(mbox, init2init_qp))
return -ENOMEM;
MOD_QP_IN_SET_QPC(init2init_qp, mbox->in, opcode, qpn,
- opt_param_mask, qpc);
+ opt_param_mask, qpc, uid);
break;
default:
mlx5_core_err(dev, "Unknown transition for modify QP: OP(0x%x) QPN(0x%x)\n",
@@ -456,7 +469,7 @@ int mlx5_core_qp_modify(struct mlx5_core_dev *dev, u16 opcode,
int err;
err = modify_qp_mbox_alloc(dev, opcode, qp->qpn,
- opt_param_mask, qpc, &mbox);
+ opt_param_mask, qpc, &mbox, qp->uid);
if (err)
return err;
@@ -531,6 +544,17 @@ int mlx5_core_xrcd_dealloc(struct mlx5_core_dev *dev, u32 xrcdn)
}
EXPORT_SYMBOL_GPL(mlx5_core_xrcd_dealloc);
+static void destroy_rq_tracked(struct mlx5_core_dev *dev, u32 rqn, u16 uid)
+{
+ u32 in[MLX5_ST_SZ_DW(destroy_rq_in)] = {};
+ u32 out[MLX5_ST_SZ_DW(destroy_rq_out)] = {};
+
+ MLX5_SET(destroy_rq_in, in, opcode, MLX5_CMD_OP_DESTROY_RQ);
+ MLX5_SET(destroy_rq_in, in, rqn, rqn);
+ MLX5_SET(destroy_rq_in, in, uid, uid);
+ mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
+}
+
int mlx5_core_create_rq_tracked(struct mlx5_core_dev *dev, u32 *in, int inlen,
struct mlx5_core_qp *rq)
{
@@ -541,6 +565,7 @@ int mlx5_core_create_rq_tracked(struct mlx5_core_dev *dev, u32 *in, int inlen,
if (err)
return err;
+ rq->uid = MLX5_GET(create_rq_in, in, uid);
rq->qpn = rqn;
err = create_resource_common(dev, rq, MLX5_RES_RQ);
if (err)
@@ -549,7 +574,7 @@ int mlx5_core_create_rq_tracked(struct mlx5_core_dev *dev, u32 *in, int inlen,
return 0;
err_destroy_rq:
- mlx5_core_destroy_rq(dev, rq->qpn);
+ destroy_rq_tracked(dev, rq->qpn, rq->uid);
return err;
}
@@ -559,10 +584,21 @@ void mlx5_core_destroy_rq_tracked(struct mlx5_core_dev *dev,
struct mlx5_core_qp *rq)
{
destroy_resource_common(dev, rq);
- mlx5_core_destroy_rq(dev, rq->qpn);
+ destroy_rq_tracked(dev, rq->qpn, rq->uid);
}
EXPORT_SYMBOL(mlx5_core_destroy_rq_tracked);
+static void destroy_sq_tracked(struct mlx5_core_dev *dev, u32 sqn, u16 uid)
+{
+ u32 in[MLX5_ST_SZ_DW(destroy_sq_in)] = {};
+ u32 out[MLX5_ST_SZ_DW(destroy_sq_out)] = {};
+
+ MLX5_SET(destroy_sq_in, in, opcode, MLX5_CMD_OP_DESTROY_SQ);
+ MLX5_SET(destroy_sq_in, in, sqn, sqn);
+ MLX5_SET(destroy_sq_in, in, uid, uid);
+ mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
+}
+
int mlx5_core_create_sq_tracked(struct mlx5_core_dev *dev, u32 *in, int inlen,
struct mlx5_core_qp *sq)
{
@@ -573,6 +609,7 @@ int mlx5_core_create_sq_tracked(struct mlx5_core_dev *dev, u32 *in, int inlen,
if (err)
return err;
+ sq->uid = MLX5_GET(create_sq_in, in, uid);
sq->qpn = sqn;
err = create_resource_common(dev, sq, MLX5_RES_SQ);
if (err)
@@ -581,7 +618,7 @@ int mlx5_core_create_sq_tracked(struct mlx5_core_dev *dev, u32 *in, int inlen,
return 0;
err_destroy_sq:
- mlx5_core_destroy_sq(dev, sq->qpn);
+ destroy_sq_tracked(dev, sq->qpn, sq->uid);
return err;
}
@@ -591,7 +628,7 @@ void mlx5_core_destroy_sq_tracked(struct mlx5_core_dev *dev,
struct mlx5_core_qp *sq)
{
destroy_resource_common(dev, sq);
- mlx5_core_destroy_sq(dev, sq->qpn);
+ destroy_sq_tracked(dev, sq->qpn, sq->uid);
}
EXPORT_SYMBOL(mlx5_core_destroy_sq_tracked);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/srq.c b/drivers/net/ethernet/mellanox/mlx5/core/srq.c
index 23cc337a96c9..6a6fc9be01e6 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/srq.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/srq.c
@@ -73,7 +73,7 @@ static int get_pas_size(struct mlx5_srq_attr *in)
u32 rq_sz = 1 << (log_srq_size + 4 + log_rq_stride);
u32 page_size = 1 << log_page_size;
u32 rq_sz_po = rq_sz + (page_offset * po_quanta);
- u32 rq_num_pas = (rq_sz_po + page_size - 1) / page_size;
+ u32 rq_num_pas = DIV_ROUND_UP(rq_sz_po, page_size);
return rq_num_pas * sizeof(u64);
}
@@ -166,6 +166,7 @@ static int create_srq_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq,
if (!create_in)
return -ENOMEM;
+ MLX5_SET(create_srq_in, create_in, uid, in->uid);
srqc = MLX5_ADDR_OF(create_srq_in, create_in, srq_context_entry);
pas = MLX5_ADDR_OF(create_srq_in, create_in, pas);
@@ -178,8 +179,10 @@ static int create_srq_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq,
err = mlx5_cmd_exec(dev, create_in, inlen, create_out,
sizeof(create_out));
kvfree(create_in);
- if (!err)
+ if (!err) {
srq->srqn = MLX5_GET(create_srq_out, create_out, srqn);
+ srq->uid = in->uid;
+ }
return err;
}
@@ -193,6 +196,7 @@ static int destroy_srq_cmd(struct mlx5_core_dev *dev,
MLX5_SET(destroy_srq_in, srq_in, opcode,
MLX5_CMD_OP_DESTROY_SRQ);
MLX5_SET(destroy_srq_in, srq_in, srqn, srq->srqn);
+ MLX5_SET(destroy_srq_in, srq_in, uid, srq->uid);
return mlx5_cmd_exec(dev, srq_in, sizeof(srq_in),
srq_out, sizeof(srq_out));
@@ -208,6 +212,7 @@ static int arm_srq_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq,
MLX5_SET(arm_rq_in, srq_in, op_mod, MLX5_ARM_RQ_IN_OP_MOD_SRQ);
MLX5_SET(arm_rq_in, srq_in, srq_number, srq->srqn);
MLX5_SET(arm_rq_in, srq_in, lwm, lwm);
+ MLX5_SET(arm_rq_in, srq_in, uid, srq->uid);
return mlx5_cmd_exec(dev, srq_in, sizeof(srq_in),
srq_out, sizeof(srq_out));
@@ -260,6 +265,7 @@ static int create_xrc_srq_cmd(struct mlx5_core_dev *dev,
if (!create_in)
return -ENOMEM;
+ MLX5_SET(create_xrc_srq_in, create_in, uid, in->uid);
xrc_srqc = MLX5_ADDR_OF(create_xrc_srq_in, create_in,
xrc_srq_context_entry);
pas = MLX5_ADDR_OF(create_xrc_srq_in, create_in, pas);
@@ -277,6 +283,7 @@ static int create_xrc_srq_cmd(struct mlx5_core_dev *dev,
goto out;
srq->srqn = MLX5_GET(create_xrc_srq_out, create_out, xrc_srqn);
+ srq->uid = in->uid;
out:
kvfree(create_in);
return err;
@@ -291,6 +298,7 @@ static int destroy_xrc_srq_cmd(struct mlx5_core_dev *dev,
MLX5_SET(destroy_xrc_srq_in, xrcsrq_in, opcode,
MLX5_CMD_OP_DESTROY_XRC_SRQ);
MLX5_SET(destroy_xrc_srq_in, xrcsrq_in, xrc_srqn, srq->srqn);
+ MLX5_SET(destroy_xrc_srq_in, xrcsrq_in, uid, srq->uid);
return mlx5_cmd_exec(dev, xrcsrq_in, sizeof(xrcsrq_in),
xrcsrq_out, sizeof(xrcsrq_out));
@@ -306,6 +314,7 @@ static int arm_xrc_srq_cmd(struct mlx5_core_dev *dev,
MLX5_SET(arm_xrc_srq_in, xrcsrq_in, op_mod, MLX5_ARM_XRC_SRQ_IN_OP_MOD_XRC_SRQ);
MLX5_SET(arm_xrc_srq_in, xrcsrq_in, xrc_srqn, srq->srqn);
MLX5_SET(arm_xrc_srq_in, xrcsrq_in, lwm, lwm);
+ MLX5_SET(arm_xrc_srq_in, xrcsrq_in, uid, srq->uid);
return mlx5_cmd_exec(dev, xrcsrq_in, sizeof(xrcsrq_in),
xrcsrq_out, sizeof(xrcsrq_out));
@@ -365,10 +374,13 @@ static int create_rmp_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq,
wq = MLX5_ADDR_OF(rmpc, rmpc, wq);
MLX5_SET(rmpc, rmpc, state, MLX5_RMPC_STATE_RDY);
+ MLX5_SET(create_rmp_in, create_in, uid, in->uid);
set_wq(wq, in);
memcpy(MLX5_ADDR_OF(rmpc, rmpc, wq.pas), in->pas, pas_size);
err = mlx5_core_create_rmp(dev, create_in, inlen, &srq->srqn);
+ if (!err)
+ srq->uid = in->uid;
kvfree(create_in);
return err;
@@ -377,7 +389,13 @@ static int create_rmp_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq,
static int destroy_rmp_cmd(struct mlx5_core_dev *dev,
struct mlx5_core_srq *srq)
{
- return mlx5_core_destroy_rmp(dev, srq->srqn);
+ u32 in[MLX5_ST_SZ_DW(destroy_rmp_in)] = {};
+ u32 out[MLX5_ST_SZ_DW(destroy_rmp_out)] = {};
+
+ MLX5_SET(destroy_rmp_in, in, opcode, MLX5_CMD_OP_DESTROY_RMP);
+ MLX5_SET(destroy_rmp_in, in, rmpn, srq->srqn);
+ MLX5_SET(destroy_rmp_in, in, uid, srq->uid);
+ return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
}
static int arm_rmp_cmd(struct mlx5_core_dev *dev,
@@ -400,6 +418,7 @@ static int arm_rmp_cmd(struct mlx5_core_dev *dev,
MLX5_SET(modify_rmp_in, in, rmp_state, MLX5_RMPC_STATE_RDY);
MLX5_SET(modify_rmp_in, in, rmpn, srq->srqn);
+ MLX5_SET(modify_rmp_in, in, uid, srq->uid);
MLX5_SET(wq, wq, lwm, lwm);
MLX5_SET(rmp_bitmask, bitmask, lwm, 1);
MLX5_SET(rmpc, rmpc, state, MLX5_RMPC_STATE_RDY);
@@ -469,11 +488,14 @@ static int create_xrq_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq,
MLX5_SET(xrqc, xrqc, user_index, in->user_index);
MLX5_SET(xrqc, xrqc, cqn, in->cqn);
MLX5_SET(create_xrq_in, create_in, opcode, MLX5_CMD_OP_CREATE_XRQ);
+ MLX5_SET(create_xrq_in, create_in, uid, in->uid);
err = mlx5_cmd_exec(dev, create_in, inlen, create_out,
sizeof(create_out));
kvfree(create_in);
- if (!err)
+ if (!err) {
srq->srqn = MLX5_GET(create_xrq_out, create_out, xrqn);
+ srq->uid = in->uid;
+ }
return err;
}
@@ -485,6 +507,7 @@ static int destroy_xrq_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq)
MLX5_SET(destroy_xrq_in, in, opcode, MLX5_CMD_OP_DESTROY_XRQ);
MLX5_SET(destroy_xrq_in, in, xrqn, srq->srqn);
+ MLX5_SET(destroy_xrq_in, in, uid, srq->uid);
return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
}
@@ -500,6 +523,7 @@ static int arm_xrq_cmd(struct mlx5_core_dev *dev,
MLX5_SET(arm_rq_in, in, op_mod, MLX5_ARM_RQ_IN_OP_MOD_XRQ);
MLX5_SET(arm_rq_in, in, srq_number, srq->srqn);
MLX5_SET(arm_rq_in, in, lwm, lwm);
+ MLX5_SET(arm_rq_in, in, uid, srq->uid);
return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/transobj.c b/drivers/net/ethernet/mellanox/mlx5/core/transobj.c
index d2f76070ea7c..a1ee9a8a769e 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/transobj.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/transobj.c
@@ -475,7 +475,8 @@ static void mlx5_hairpin_destroy_queues(struct mlx5_hairpin *hp)
for (i = 0; i < hp->num_channels; i++) {
mlx5_core_destroy_rq(hp->func_mdev, hp->rqn[i]);
- mlx5_core_destroy_sq(hp->peer_mdev, hp->sqn[i]);
+ if (!hp->peer_gone)
+ mlx5_core_destroy_sq(hp->peer_mdev, hp->sqn[i]);
}
}
@@ -567,6 +568,8 @@ static void mlx5_hairpin_unpair_queues(struct mlx5_hairpin *hp)
MLX5_RQC_STATE_RST, 0, 0);
/* unset peer SQs */
+ if (hp->peer_gone)
+ return;
for (i = 0; i < hp->num_channels; i++)
mlx5_hairpin_modify_sq(hp->peer_mdev, hp->sqn[i], MLX5_SQC_STATE_RDY,
MLX5_SQC_STATE_RST, 0, 0);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vport.c b/drivers/net/ethernet/mellanox/mlx5/core/vport.c
index b02af317c125..cfbea66b4879 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/vport.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.c
@@ -1201,3 +1201,12 @@ int mlx5_nic_vport_unaffiliate_multiport(struct mlx5_core_dev *port_mdev)
return err;
}
EXPORT_SYMBOL_GPL(mlx5_nic_vport_unaffiliate_multiport);
+
+u64 mlx5_query_nic_system_image_guid(struct mlx5_core_dev *mdev)
+{
+ if (!mdev->sys_image_guid)
+ mlx5_query_nic_vport_system_image_guid(mdev, &mdev->sys_image_guid);
+
+ return mdev->sys_image_guid;
+}
+EXPORT_SYMBOL_GPL(mlx5_query_nic_system_image_guid);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/wq.c b/drivers/net/ethernet/mellanox/mlx5/core/wq.c
index 68e7f8df2a6d..2dcbf1ebfd6a 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/wq.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/wq.c
@@ -39,11 +39,6 @@ u32 mlx5_wq_cyc_get_size(struct mlx5_wq_cyc *wq)
return (u32)wq->fbc.sz_m1 + 1;
}
-u16 mlx5_wq_cyc_get_frag_size(struct mlx5_wq_cyc *wq)
-{
- return wq->fbc.frag_sz_m1 + 1;
-}
-
u32 mlx5_cqwq_get_size(struct mlx5_cqwq *wq)
{
return wq->fbc.sz_m1 + 1;
@@ -54,54 +49,37 @@ u32 mlx5_wq_ll_get_size(struct mlx5_wq_ll *wq)
return (u32)wq->fbc.sz_m1 + 1;
}
-static u32 mlx5_wq_cyc_get_byte_size(struct mlx5_wq_cyc *wq)
-{
- return mlx5_wq_cyc_get_size(wq) << wq->fbc.log_stride;
-}
-
-static u32 mlx5_wq_qp_get_byte_size(struct mlx5_wq_qp *wq)
-{
- return mlx5_wq_cyc_get_byte_size(&wq->rq) +
- mlx5_wq_cyc_get_byte_size(&wq->sq);
-}
-
-static u32 mlx5_cqwq_get_byte_size(struct mlx5_cqwq *wq)
+static u32 wq_get_byte_sz(u8 log_sz, u8 log_stride)
{
- return mlx5_cqwq_get_size(wq) << wq->fbc.log_stride;
-}
-
-static u32 mlx5_wq_ll_get_byte_size(struct mlx5_wq_ll *wq)
-{
- return mlx5_wq_ll_get_size(wq) << wq->fbc.log_stride;
+ return ((u32)1 << log_sz) << log_stride;
}
int mlx5_wq_cyc_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param,
void *wqc, struct mlx5_wq_cyc *wq,
struct mlx5_wq_ctrl *wq_ctrl)
{
+ u8 log_wq_stride = MLX5_GET(wq, wqc, log_wq_stride);
+ u8 log_wq_sz = MLX5_GET(wq, wqc, log_wq_sz);
struct mlx5_frag_buf_ctrl *fbc = &wq->fbc;
int err;
- mlx5_fill_fbc(MLX5_GET(wq, wqc, log_wq_stride),
- MLX5_GET(wq, wqc, log_wq_sz),
- fbc);
- wq->sz = wq->fbc.sz_m1 + 1;
-
err = mlx5_db_alloc_node(mdev, &wq_ctrl->db, param->db_numa_node);
if (err) {
mlx5_core_warn(mdev, "mlx5_db_alloc_node() failed, %d\n", err);
return err;
}
- err = mlx5_frag_buf_alloc_node(mdev, mlx5_wq_cyc_get_byte_size(wq),
+ wq->db = wq_ctrl->db.db;
+
+ err = mlx5_frag_buf_alloc_node(mdev, wq_get_byte_sz(log_wq_sz, log_wq_stride),
&wq_ctrl->buf, param->buf_numa_node);
if (err) {
mlx5_core_warn(mdev, "mlx5_frag_buf_alloc_node() failed, %d\n", err);
goto err_db_free;
}
- fbc->frag_buf = wq_ctrl->buf;
- wq->db = wq_ctrl->db.db;
+ mlx5_init_fbc(wq_ctrl->buf.frags, log_wq_stride, log_wq_sz, fbc);
+ wq->sz = mlx5_wq_cyc_get_size(wq);
wq_ctrl->mdev = mdev;
@@ -113,46 +91,19 @@ err_db_free:
return err;
}
-static void mlx5_qp_set_frag_buf(struct mlx5_frag_buf *buf,
- struct mlx5_wq_qp *qp)
-{
- struct mlx5_frag_buf_ctrl *sq_fbc;
- struct mlx5_frag_buf *rqb, *sqb;
-
- rqb = &qp->rq.fbc.frag_buf;
- *rqb = *buf;
- rqb->size = mlx5_wq_cyc_get_byte_size(&qp->rq);
- rqb->npages = DIV_ROUND_UP(rqb->size, PAGE_SIZE);
-
- sq_fbc = &qp->sq.fbc;
- sqb = &sq_fbc->frag_buf;
- *sqb = *buf;
- sqb->size = mlx5_wq_cyc_get_byte_size(&qp->sq);
- sqb->npages = DIV_ROUND_UP(sqb->size, PAGE_SIZE);
- sqb->frags += rqb->npages; /* first part is for the rq */
- if (sq_fbc->strides_offset)
- sqb->frags--;
-}
-
int mlx5_wq_qp_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param,
void *qpc, struct mlx5_wq_qp *wq,
struct mlx5_wq_ctrl *wq_ctrl)
{
- u16 sq_strides_offset;
- u32 rq_pg_remainder;
- int err;
+ u8 log_rq_stride = MLX5_GET(qpc, qpc, log_rq_stride) + 4;
+ u8 log_rq_sz = MLX5_GET(qpc, qpc, log_rq_size);
+ u8 log_sq_stride = ilog2(MLX5_SEND_WQE_BB);
+ u8 log_sq_sz = MLX5_GET(qpc, qpc, log_sq_size);
- mlx5_fill_fbc(MLX5_GET(qpc, qpc, log_rq_stride) + 4,
- MLX5_GET(qpc, qpc, log_rq_size),
- &wq->rq.fbc);
+ u32 rq_byte_size;
+ int err;
- rq_pg_remainder = mlx5_wq_cyc_get_byte_size(&wq->rq) % PAGE_SIZE;
- sq_strides_offset = rq_pg_remainder / MLX5_SEND_WQE_BB;
- mlx5_fill_fbc_offset(ilog2(MLX5_SEND_WQE_BB),
- MLX5_GET(qpc, qpc, log_sq_size),
- sq_strides_offset,
- &wq->sq.fbc);
err = mlx5_db_alloc_node(mdev, &wq_ctrl->db, param->db_numa_node);
if (err) {
@@ -160,14 +111,32 @@ int mlx5_wq_qp_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param,
return err;
}
- err = mlx5_frag_buf_alloc_node(mdev, mlx5_wq_qp_get_byte_size(wq),
+ err = mlx5_frag_buf_alloc_node(mdev,
+ wq_get_byte_sz(log_rq_sz, log_rq_stride) +
+ wq_get_byte_sz(log_sq_sz, log_sq_stride),
&wq_ctrl->buf, param->buf_numa_node);
if (err) {
mlx5_core_warn(mdev, "mlx5_frag_buf_alloc_node() failed, %d\n", err);
goto err_db_free;
}
- mlx5_qp_set_frag_buf(&wq_ctrl->buf, wq);
+ mlx5_init_fbc(wq_ctrl->buf.frags, log_rq_stride, log_rq_sz, &wq->rq.fbc);
+
+ rq_byte_size = wq_get_byte_sz(log_rq_sz, log_rq_stride);
+
+ if (rq_byte_size < PAGE_SIZE) {
+ /* SQ starts within the same page of the RQ */
+ u16 sq_strides_offset = rq_byte_size / MLX5_SEND_WQE_BB;
+
+ mlx5_init_fbc_offset(wq_ctrl->buf.frags,
+ log_sq_stride, log_sq_sz, sq_strides_offset,
+ &wq->sq.fbc);
+ } else {
+ u16 rq_npages = rq_byte_size >> PAGE_SHIFT;
+
+ mlx5_init_fbc(wq_ctrl->buf.frags + rq_npages,
+ log_sq_stride, log_sq_sz, &wq->sq.fbc);
+ }
wq->rq.db = &wq_ctrl->db.db[MLX5_RCV_DBR];
wq->sq.db = &wq_ctrl->db.db[MLX5_SND_DBR];
@@ -186,17 +155,19 @@ int mlx5_cqwq_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param,
void *cqc, struct mlx5_cqwq *wq,
struct mlx5_wq_ctrl *wq_ctrl)
{
+ u8 log_wq_stride = MLX5_GET(cqc, cqc, cqe_sz) + 6;
+ u8 log_wq_sz = MLX5_GET(cqc, cqc, log_cq_size);
int err;
- mlx5_core_init_cq_frag_buf(&wq->fbc, cqc);
-
err = mlx5_db_alloc_node(mdev, &wq_ctrl->db, param->db_numa_node);
if (err) {
mlx5_core_warn(mdev, "mlx5_db_alloc_node() failed, %d\n", err);
return err;
}
- err = mlx5_frag_buf_alloc_node(mdev, mlx5_cqwq_get_byte_size(wq),
+ wq->db = wq_ctrl->db.db;
+
+ err = mlx5_frag_buf_alloc_node(mdev, wq_get_byte_sz(log_wq_sz, log_wq_stride),
&wq_ctrl->buf,
param->buf_numa_node);
if (err) {
@@ -205,8 +176,7 @@ int mlx5_cqwq_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param,
goto err_db_free;
}
- wq->fbc.frag_buf = wq_ctrl->buf;
- wq->db = wq_ctrl->db.db;
+ mlx5_init_fbc(wq_ctrl->buf.frags, log_wq_stride, log_wq_sz, &wq->fbc);
wq_ctrl->mdev = mdev;
@@ -222,30 +192,29 @@ int mlx5_wq_ll_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param,
void *wqc, struct mlx5_wq_ll *wq,
struct mlx5_wq_ctrl *wq_ctrl)
{
+ u8 log_wq_stride = MLX5_GET(wq, wqc, log_wq_stride);
+ u8 log_wq_sz = MLX5_GET(wq, wqc, log_wq_sz);
struct mlx5_frag_buf_ctrl *fbc = &wq->fbc;
struct mlx5_wqe_srq_next_seg *next_seg;
int err;
int i;
- mlx5_fill_fbc(MLX5_GET(wq, wqc, log_wq_stride),
- MLX5_GET(wq, wqc, log_wq_sz),
- fbc);
-
err = mlx5_db_alloc_node(mdev, &wq_ctrl->db, param->db_numa_node);
if (err) {
mlx5_core_warn(mdev, "mlx5_db_alloc_node() failed, %d\n", err);
return err;
}
- err = mlx5_frag_buf_alloc_node(mdev, mlx5_wq_ll_get_byte_size(wq),
+ wq->db = wq_ctrl->db.db;
+
+ err = mlx5_frag_buf_alloc_node(mdev, wq_get_byte_sz(log_wq_sz, log_wq_stride),
&wq_ctrl->buf, param->buf_numa_node);
if (err) {
mlx5_core_warn(mdev, "mlx5_frag_buf_alloc_node() failed, %d\n", err);
goto err_db_free;
}
- wq->fbc.frag_buf = wq_ctrl->buf;
- wq->db = wq_ctrl->db.db;
+ mlx5_init_fbc(wq_ctrl->buf.frags, log_wq_stride, log_wq_sz, fbc);
for (i = 0; i < fbc->sz_m1; i++) {
next_seg = mlx5_wq_ll_get_wqe(wq, i);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/wq.h b/drivers/net/ethernet/mellanox/mlx5/core/wq.h
index 3a1a170bb2d7..b1293d153a58 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/wq.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/wq.h
@@ -80,7 +80,6 @@ int mlx5_wq_cyc_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param,
void *wqc, struct mlx5_wq_cyc *wq,
struct mlx5_wq_ctrl *wq_ctrl);
u32 mlx5_wq_cyc_get_size(struct mlx5_wq_cyc *wq);
-u16 mlx5_wq_cyc_get_frag_size(struct mlx5_wq_cyc *wq);
int mlx5_wq_qp_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param,
void *qpc, struct mlx5_wq_qp *wq,
@@ -140,11 +139,6 @@ static inline u16 mlx5_wq_cyc_ctr2ix(struct mlx5_wq_cyc *wq, u16 ctr)
return ctr & wq->fbc.sz_m1;
}
-static inline u16 mlx5_wq_cyc_ctr2fragix(struct mlx5_wq_cyc *wq, u16 ctr)
-{
- return ctr & wq->fbc.frag_sz_m1;
-}
-
static inline u16 mlx5_wq_cyc_get_head(struct mlx5_wq_cyc *wq)
{
return mlx5_wq_cyc_ctr2ix(wq, wq->wqe_ctr);
@@ -160,6 +154,11 @@ static inline void *mlx5_wq_cyc_get_wqe(struct mlx5_wq_cyc *wq, u16 ix)
return mlx5_frag_buf_get_wqe(&wq->fbc, ix);
}
+static inline u16 mlx5_wq_cyc_get_contig_wqebbs(struct mlx5_wq_cyc *wq, u16 ix)
+{
+ return mlx5_frag_buf_get_idx_last_contig_stride(&wq->fbc, ix) - ix + 1;
+}
+
static inline int mlx5_wq_cyc_cc_bigger(u16 cc1, u16 cc2)
{
int equal = (cc1 == cc2);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/Makefile b/drivers/net/ethernet/mellanox/mlxsw/Makefile
index 68fa44a41485..1f77e97e2d7a 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/Makefile
+++ b/drivers/net/ethernet/mellanox/mlxsw/Makefile
@@ -27,7 +27,8 @@ mlxsw_spectrum-objs := spectrum.o spectrum_buffers.o \
spectrum_acl_flex_keys.o \
spectrum1_mr_tcam.o spectrum2_mr_tcam.o \
spectrum_mr_tcam.o spectrum_mr.o \
- spectrum_qdisc.o spectrum_span.o
+ spectrum_qdisc.o spectrum_span.o \
+ spectrum_nve.o spectrum_nve_vxlan.o
mlxsw_spectrum-$(CONFIG_MLXSW_SPECTRUM_DCB) += spectrum_dcb.o
mlxsw_spectrum-$(CONFIG_NET_DEVLINK) += spectrum_dpipe.o
obj-$(CONFIG_MLXSW_MINIMAL) += mlxsw_minimal.o
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c
index 81533d7f395c..30f751e69698 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core.c
@@ -943,8 +943,8 @@ static int mlxsw_devlink_core_bus_device_reload(struct devlink *devlink,
mlxsw_core->bus,
mlxsw_core->bus_priv, true,
devlink);
- if (err)
- mlxsw_core->reload_fail = true;
+ mlxsw_core->reload_fail = !!err;
+
return err;
}
@@ -1055,6 +1055,7 @@ int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
err_driver_init:
mlxsw_thermal_fini(mlxsw_core->thermal);
err_thermal_init:
+ mlxsw_hwmon_fini(mlxsw_core->hwmon);
err_hwmon_init:
if (!reload)
devlink_unregister(devlink);
@@ -1082,12 +1083,20 @@ void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core,
{
struct devlink *devlink = priv_to_devlink(mlxsw_core);
- if (mlxsw_core->reload_fail)
- goto reload_fail;
+ if (mlxsw_core->reload_fail) {
+ if (!reload)
+ /* Only the parts that were not de-initialized in the
+ * failed reload attempt need to be de-initialized.
+ */
+ goto reload_fail_deinit;
+ else
+ return;
+ }
if (mlxsw_core->driver->fini)
mlxsw_core->driver->fini(mlxsw_core);
mlxsw_thermal_fini(mlxsw_core->thermal);
+ mlxsw_hwmon_fini(mlxsw_core->hwmon);
if (!reload)
devlink_unregister(devlink);
mlxsw_emad_fini(mlxsw_core);
@@ -1096,9 +1105,12 @@ void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core,
if (!reload)
devlink_resources_unregister(devlink, NULL);
mlxsw_core->bus->fini(mlxsw_core->bus_priv);
- if (reload)
- return;
-reload_fail:
+
+ return;
+
+reload_fail_deinit:
+ devlink_unregister(devlink);
+ devlink_resources_unregister(devlink, NULL);
devlink_free(devlink);
}
EXPORT_SYMBOL(mlxsw_core_bus_device_unregister);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h
index 655ddd204ab2..c35be477856f 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/core.h
@@ -359,6 +359,10 @@ static inline int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core,
return 0;
}
+static inline void mlxsw_hwmon_fini(struct mlxsw_hwmon *mlxsw_hwmon)
+{
+}
+
#endif
struct mlxsw_thermal;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c
index f6cf2896d337..e04e8162aa14 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c
@@ -303,8 +303,7 @@ int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core,
struct device *hwmon_dev;
int err;
- mlxsw_hwmon = devm_kzalloc(mlxsw_bus_info->dev, sizeof(*mlxsw_hwmon),
- GFP_KERNEL);
+ mlxsw_hwmon = kzalloc(sizeof(*mlxsw_hwmon), GFP_KERNEL);
if (!mlxsw_hwmon)
return -ENOMEM;
mlxsw_hwmon->core = mlxsw_core;
@@ -321,10 +320,9 @@ int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core,
mlxsw_hwmon->groups[0] = &mlxsw_hwmon->group;
mlxsw_hwmon->group.attrs = mlxsw_hwmon->attrs;
- hwmon_dev = devm_hwmon_device_register_with_groups(mlxsw_bus_info->dev,
- "mlxsw",
- mlxsw_hwmon,
- mlxsw_hwmon->groups);
+ hwmon_dev = hwmon_device_register_with_groups(mlxsw_bus_info->dev,
+ "mlxsw", mlxsw_hwmon,
+ mlxsw_hwmon->groups);
if (IS_ERR(hwmon_dev)) {
err = PTR_ERR(hwmon_dev);
goto err_hwmon_register;
@@ -337,5 +335,12 @@ int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core,
err_hwmon_register:
err_fans_init:
err_temp_init:
+ kfree(mlxsw_hwmon);
return err;
}
+
+void mlxsw_hwmon_fini(struct mlxsw_hwmon *mlxsw_hwmon)
+{
+ hwmon_device_unregister(mlxsw_hwmon->hwmon_dev);
+ kfree(mlxsw_hwmon);
+}
diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c
index 4d271fb3de3d..5890fdfd62c3 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/pci.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c
@@ -718,14 +718,17 @@ static void mlxsw_pci_eq_tasklet(unsigned long data)
memset(&active_cqns, 0, sizeof(active_cqns));
while ((eqe = mlxsw_pci_eq_sw_eqe_get(q))) {
- u8 event_type = mlxsw_pci_eqe_event_type_get(eqe);
- switch (event_type) {
- case MLXSW_PCI_EQE_EVENT_TYPE_CMD:
+ /* Command interface completion events are always received on
+ * queue MLXSW_PCI_EQ_ASYNC_NUM (EQ0) and completion events
+ * are mapped to queue MLXSW_PCI_EQ_COMP_NUM (EQ1).
+ */
+ switch (q->num) {
+ case MLXSW_PCI_EQ_ASYNC_NUM:
mlxsw_pci_eq_cmd_event(mlxsw_pci, eqe);
q->u.eq.ev_cmd_count++;
break;
- case MLXSW_PCI_EQE_EVENT_TYPE_COMP:
+ case MLXSW_PCI_EQ_COMP_NUM:
cqn = mlxsw_pci_eqe_cqn_get(eqe);
set_bit(cqn, active_cqns);
cq_handle = true;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h b/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h
index 83f452b7ccbb..bb99f6d41fe0 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h
@@ -221,7 +221,7 @@ MLXSW_ITEM32(pci, eqe, event_type, 0x0C, 24, 8);
MLXSW_ITEM32(pci, eqe, event_sub_type, 0x0C, 16, 8);
/* pci_eqe_cqn
- * Completion Queue that triggeret this EQE.
+ * Completion Queue that triggered this EQE.
*/
MLXSW_ITEM32(pci, eqe, cqn, 0x0C, 8, 7);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h
index 6e8b619b769b..db3d2790aeec 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h
@@ -295,6 +295,7 @@ enum mlxsw_reg_sfd_rec_type {
MLXSW_REG_SFD_REC_TYPE_UNICAST = 0x0,
MLXSW_REG_SFD_REC_TYPE_UNICAST_LAG = 0x1,
MLXSW_REG_SFD_REC_TYPE_MULTICAST = 0x2,
+ MLXSW_REG_SFD_REC_TYPE_UNICAST_TUNNEL = 0xC,
};
/* reg_sfd_rec_type
@@ -525,6 +526,61 @@ mlxsw_reg_sfd_mc_pack(char *payload, int rec_index,
mlxsw_reg_sfd_mc_mid_set(payload, rec_index, mid);
}
+/* reg_sfd_uc_tunnel_uip_msb
+ * When protocol is IPv4, the most significant byte of the underlay IPv4
+ * destination IP.
+ * When protocol is IPv6, reserved.
+ * Access: RW
+ */
+MLXSW_ITEM32_INDEXED(reg, sfd, uc_tunnel_uip_msb, MLXSW_REG_SFD_BASE_LEN, 24,
+ 8, MLXSW_REG_SFD_REC_LEN, 0x08, false);
+
+/* reg_sfd_uc_tunnel_fid
+ * Filtering ID.
+ * Access: Index
+ */
+MLXSW_ITEM32_INDEXED(reg, sfd, uc_tunnel_fid, MLXSW_REG_SFD_BASE_LEN, 0, 16,
+ MLXSW_REG_SFD_REC_LEN, 0x08, false);
+
+enum mlxsw_reg_sfd_uc_tunnel_protocol {
+ MLXSW_REG_SFD_UC_TUNNEL_PROTOCOL_IPV4,
+ MLXSW_REG_SFD_UC_TUNNEL_PROTOCOL_IPV6,
+};
+
+/* reg_sfd_uc_tunnel_protocol
+ * IP protocol.
+ * Access: RW
+ */
+MLXSW_ITEM32_INDEXED(reg, sfd, uc_tunnel_protocol, MLXSW_REG_SFD_BASE_LEN, 27,
+ 1, MLXSW_REG_SFD_REC_LEN, 0x0C, false);
+
+/* reg_sfd_uc_tunnel_uip_lsb
+ * When protocol is IPv4, the least significant bytes of the underlay
+ * IPv4 destination IP.
+ * When protocol is IPv6, pointer to the underlay IPv6 destination IP
+ * which is configured by RIPS.
+ * Access: RW
+ */
+MLXSW_ITEM32_INDEXED(reg, sfd, uc_tunnel_uip_lsb, MLXSW_REG_SFD_BASE_LEN, 0,
+ 24, MLXSW_REG_SFD_REC_LEN, 0x0C, false);
+
+static inline void
+mlxsw_reg_sfd_uc_tunnel_pack(char *payload, int rec_index,
+ enum mlxsw_reg_sfd_rec_policy policy,
+ const char *mac, u16 fid,
+ enum mlxsw_reg_sfd_rec_action action, u32 uip,
+ enum mlxsw_reg_sfd_uc_tunnel_protocol proto)
+{
+ mlxsw_reg_sfd_rec_pack(payload, rec_index,
+ MLXSW_REG_SFD_REC_TYPE_UNICAST_TUNNEL, mac,
+ action);
+ mlxsw_reg_sfd_rec_policy_set(payload, rec_index, policy);
+ mlxsw_reg_sfd_uc_tunnel_uip_msb_set(payload, rec_index, uip >> 24);
+ mlxsw_reg_sfd_uc_tunnel_uip_lsb_set(payload, rec_index, uip);
+ mlxsw_reg_sfd_uc_tunnel_fid_set(payload, rec_index, fid);
+ mlxsw_reg_sfd_uc_tunnel_protocol_set(payload, rec_index, proto);
+}
+
/* SFN - Switch FDB Notification Register
* -------------------------------------------
* The switch provides notifications on newly learned FDB entries and
@@ -1069,6 +1125,8 @@ enum mlxsw_reg_sfdf_flush_type {
MLXSW_REG_SFDF_FLUSH_PER_PORT_AND_FID,
MLXSW_REG_SFDF_FLUSH_PER_LAG,
MLXSW_REG_SFDF_FLUSH_PER_LAG_AND_FID,
+ MLXSW_REG_SFDF_FLUSH_PER_NVE,
+ MLXSW_REG_SFDF_FLUSH_PER_NVE_AND_FID,
};
/* reg_sfdf_flush_type
@@ -1079,6 +1137,10 @@ enum mlxsw_reg_sfdf_flush_type {
* 3 - All FID dynamic entries pointing to port are flushed.
* 4 - All dynamic entries pointing to LAG are flushed.
* 5 - All FID dynamic entries pointing to LAG are flushed.
+ * 6 - All entries of type "Unicast Tunnel" or "Multicast Tunnel" are
+ * flushed.
+ * 7 - All entries of type "Unicast Tunnel" or "Multicast Tunnel" are
+ * flushed, per FID.
* Access: RW
*/
MLXSW_ITEM32(reg, sfdf, flush_type, 0x04, 28, 4);
@@ -1315,12 +1377,19 @@ MLXSW_ITEM32(reg, slcr, type, 0x00, 0, 4);
*/
MLXSW_ITEM32(reg, slcr, lag_hash, 0x04, 0, 20);
-static inline void mlxsw_reg_slcr_pack(char *payload, u16 lag_hash)
+/* reg_slcr_seed
+ * LAG seed value. The seed is the same for all ports.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, slcr, seed, 0x08, 0, 32);
+
+static inline void mlxsw_reg_slcr_pack(char *payload, u16 lag_hash, u32 seed)
{
MLXSW_REG_ZERO(slcr, payload);
mlxsw_reg_slcr_pp_set(payload, MLXSW_REG_SLCR_PP_GLOBAL);
mlxsw_reg_slcr_type_set(payload, MLXSW_REG_SLCR_TYPE_CRC);
mlxsw_reg_slcr_lag_hash_set(payload, lag_hash);
+ mlxsw_reg_slcr_seed_set(payload, seed);
}
/* SLCOR - Switch LAG Collector Register
@@ -3215,7 +3284,7 @@ static inline void mlxsw_reg_qtct_pack(char *payload, u8 local_port,
* Configures the ETS elements.
*/
#define MLXSW_REG_QEEC_ID 0x400D
-#define MLXSW_REG_QEEC_LEN 0x1C
+#define MLXSW_REG_QEEC_LEN 0x20
MLXSW_REG_DEFINE(qeec, MLXSW_REG_QEEC_ID, MLXSW_REG_QEEC_LEN);
@@ -3257,6 +3326,15 @@ MLXSW_ITEM32(reg, qeec, element_index, 0x04, 0, 8);
*/
MLXSW_ITEM32(reg, qeec, next_element_index, 0x08, 0, 8);
+/* reg_qeec_mise
+ * Min shaper configuration enable. Enables configuration of the min
+ * shaper on this ETS element
+ * 0 - Disable
+ * 1 - Enable
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, qeec, mise, 0x0C, 31, 1);
+
enum {
MLXSW_REG_QEEC_BYTES_MODE,
MLXSW_REG_QEEC_PACKETS_MODE,
@@ -3273,6 +3351,17 @@ enum {
*/
MLXSW_ITEM32(reg, qeec, pb, 0x0C, 28, 1);
+/* The smallest permitted min shaper rate. */
+#define MLXSW_REG_QEEC_MIS_MIN 200000 /* Kbps */
+
+/* reg_qeec_min_shaper_rate
+ * Min shaper information rate.
+ * For CPU port, can only be configured for port hierarchy.
+ * When in bytes mode, value is specified in units of 1000bps.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, qeec, min_shaper_rate, 0x0C, 0, 28);
+
/* reg_qeec_mase
* Max shaper configuration enable. Enables configuration of the max
* shaper on this ETS element.
@@ -8279,6 +8368,508 @@ static inline void mlxsw_reg_mgpc_pack(char *payload, u32 counter_index,
mlxsw_reg_mgpc_opcode_set(payload, opcode);
}
+/* MPRS - Monitoring Parsing State Register
+ * ----------------------------------------
+ * The MPRS register is used for setting up the parsing for hash,
+ * policy-engine and routing.
+ */
+#define MLXSW_REG_MPRS_ID 0x9083
+#define MLXSW_REG_MPRS_LEN 0x14
+
+MLXSW_REG_DEFINE(mprs, MLXSW_REG_MPRS_ID, MLXSW_REG_MPRS_LEN);
+
+/* reg_mprs_parsing_depth
+ * Minimum parsing depth.
+ * Need to enlarge parsing depth according to L3, MPLS, tunnels, ACL
+ * rules, traps, hash, etc. Default is 96 bytes. Reserved when SwitchX-2.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, mprs, parsing_depth, 0x00, 0, 16);
+
+/* reg_mprs_parsing_en
+ * Parsing enable.
+ * Bit 0 - Enable parsing of NVE of types VxLAN, VxLAN-GPE, GENEVE and
+ * NVGRE. Default is enabled. Reserved when SwitchX-2.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, mprs, parsing_en, 0x04, 0, 16);
+
+/* reg_mprs_vxlan_udp_dport
+ * VxLAN UDP destination port.
+ * Used for identifying VxLAN packets and for dport field in
+ * encapsulation. Default is 4789.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, mprs, vxlan_udp_dport, 0x10, 0, 16);
+
+static inline void mlxsw_reg_mprs_pack(char *payload, u16 parsing_depth,
+ u16 vxlan_udp_dport)
+{
+ MLXSW_REG_ZERO(mprs, payload);
+ mlxsw_reg_mprs_parsing_depth_set(payload, parsing_depth);
+ mlxsw_reg_mprs_parsing_en_set(payload, true);
+ mlxsw_reg_mprs_vxlan_udp_dport_set(payload, vxlan_udp_dport);
+}
+
+/* TNGCR - Tunneling NVE General Configuration Register
+ * ----------------------------------------------------
+ * The TNGCR register is used for setting up the NVE Tunneling configuration.
+ */
+#define MLXSW_REG_TNGCR_ID 0xA001
+#define MLXSW_REG_TNGCR_LEN 0x44
+
+MLXSW_REG_DEFINE(tngcr, MLXSW_REG_TNGCR_ID, MLXSW_REG_TNGCR_LEN);
+
+enum mlxsw_reg_tngcr_type {
+ MLXSW_REG_TNGCR_TYPE_VXLAN,
+ MLXSW_REG_TNGCR_TYPE_VXLAN_GPE,
+ MLXSW_REG_TNGCR_TYPE_GENEVE,
+ MLXSW_REG_TNGCR_TYPE_NVGRE,
+};
+
+/* reg_tngcr_type
+ * Tunnel type for encapsulation and decapsulation. The types are mutually
+ * exclusive.
+ * Note: For Spectrum the NVE parsing must be enabled in MPRS.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, tngcr, type, 0x00, 0, 4);
+
+/* reg_tngcr_nve_valid
+ * The VTEP is valid. Allows adding FDB entries for tunnel encapsulation.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, tngcr, nve_valid, 0x04, 31, 1);
+
+/* reg_tngcr_nve_ttl_uc
+ * The TTL for NVE tunnel encapsulation underlay unicast packets.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, tngcr, nve_ttl_uc, 0x04, 0, 8);
+
+/* reg_tngcr_nve_ttl_mc
+ * The TTL for NVE tunnel encapsulation underlay multicast packets.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, tngcr, nve_ttl_mc, 0x08, 0, 8);
+
+enum {
+ /* Do not copy flow label. Calculate flow label using nve_flh. */
+ MLXSW_REG_TNGCR_FL_NO_COPY,
+ /* Copy flow label from inner packet if packet is IPv6 and
+ * encapsulation is by IPv6. Otherwise, calculate flow label using
+ * nve_flh.
+ */
+ MLXSW_REG_TNGCR_FL_COPY,
+};
+
+/* reg_tngcr_nve_flc
+ * For NVE tunnel encapsulation: Flow label copy from inner packet.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, tngcr, nve_flc, 0x0C, 25, 1);
+
+enum {
+ /* Flow label is static. In Spectrum this means '0'. Spectrum-2
+ * uses {nve_fl_prefix, nve_fl_suffix}.
+ */
+ MLXSW_REG_TNGCR_FL_NO_HASH,
+ /* 8 LSBs of the flow label are calculated from ECMP hash of the
+ * inner packet. 12 MSBs are configured by nve_fl_prefix.
+ */
+ MLXSW_REG_TNGCR_FL_HASH,
+};
+
+/* reg_tngcr_nve_flh
+ * NVE flow label hash.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, tngcr, nve_flh, 0x0C, 24, 1);
+
+/* reg_tngcr_nve_fl_prefix
+ * NVE flow label prefix. Constant 12 MSBs of the flow label.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, tngcr, nve_fl_prefix, 0x0C, 8, 12);
+
+/* reg_tngcr_nve_fl_suffix
+ * NVE flow label suffix. Constant 8 LSBs of the flow label.
+ * Reserved when nve_flh=1 and for Spectrum.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, tngcr, nve_fl_suffix, 0x0C, 0, 8);
+
+enum {
+ /* Source UDP port is fixed (default '0') */
+ MLXSW_REG_TNGCR_UDP_SPORT_NO_HASH,
+ /* Source UDP port is calculated based on hash */
+ MLXSW_REG_TNGCR_UDP_SPORT_HASH,
+};
+
+/* reg_tngcr_nve_udp_sport_type
+ * NVE UDP source port type.
+ * Spectrum uses LAG hash (SLCRv2). Spectrum-2 uses ECMP hash (RECRv2).
+ * When the source UDP port is calculated based on hash, then the 8 LSBs
+ * are calculated from hash the 8 MSBs are configured by
+ * nve_udp_sport_prefix.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, tngcr, nve_udp_sport_type, 0x10, 24, 1);
+
+/* reg_tngcr_nve_udp_sport_prefix
+ * NVE UDP source port prefix. Constant 8 MSBs of the UDP source port.
+ * Reserved when NVE type is NVGRE.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, tngcr, nve_udp_sport_prefix, 0x10, 8, 8);
+
+/* reg_tngcr_nve_group_size_mc
+ * The amount of sequential linked lists of MC entries. The first linked
+ * list is configured by SFD.underlay_mc_ptr.
+ * Valid values: 1, 2, 4, 8, 16, 32, 64
+ * The linked list are configured by TNUMT.
+ * The hash is set by LAG hash.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, tngcr, nve_group_size_mc, 0x18, 0, 8);
+
+/* reg_tngcr_nve_group_size_flood
+ * The amount of sequential linked lists of flooding entries. The first
+ * linked list is configured by SFMR.nve_tunnel_flood_ptr
+ * Valid values: 1, 2, 4, 8, 16, 32, 64
+ * The linked list are configured by TNUMT.
+ * The hash is set by LAG hash.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, tngcr, nve_group_size_flood, 0x1C, 0, 8);
+
+/* reg_tngcr_learn_enable
+ * During decapsulation, whether to learn from NVE port.
+ * Reserved when Spectrum-2. See TNPC.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, tngcr, learn_enable, 0x20, 31, 1);
+
+/* reg_tngcr_underlay_virtual_router
+ * Underlay virtual router.
+ * Reserved when Spectrum-2.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, tngcr, underlay_virtual_router, 0x20, 0, 16);
+
+/* reg_tngcr_underlay_rif
+ * Underlay ingress router interface. RIF type should be loopback generic.
+ * Reserved when Spectrum.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, tngcr, underlay_rif, 0x24, 0, 16);
+
+/* reg_tngcr_usipv4
+ * Underlay source IPv4 address of the NVE.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, tngcr, usipv4, 0x28, 0, 32);
+
+/* reg_tngcr_usipv6
+ * Underlay source IPv6 address of the NVE. For Spectrum, must not be
+ * modified under traffic of NVE tunneling encapsulation.
+ * Access: RW
+ */
+MLXSW_ITEM_BUF(reg, tngcr, usipv6, 0x30, 16);
+
+static inline void mlxsw_reg_tngcr_pack(char *payload,
+ enum mlxsw_reg_tngcr_type type,
+ bool valid, u8 ttl)
+{
+ MLXSW_REG_ZERO(tngcr, payload);
+ mlxsw_reg_tngcr_type_set(payload, type);
+ mlxsw_reg_tngcr_nve_valid_set(payload, valid);
+ mlxsw_reg_tngcr_nve_ttl_uc_set(payload, ttl);
+ mlxsw_reg_tngcr_nve_ttl_mc_set(payload, ttl);
+ mlxsw_reg_tngcr_nve_flc_set(payload, MLXSW_REG_TNGCR_FL_NO_COPY);
+ mlxsw_reg_tngcr_nve_flh_set(payload, 0);
+ mlxsw_reg_tngcr_nve_udp_sport_type_set(payload,
+ MLXSW_REG_TNGCR_UDP_SPORT_HASH);
+ mlxsw_reg_tngcr_nve_udp_sport_prefix_set(payload, 0);
+ mlxsw_reg_tngcr_nve_group_size_mc_set(payload, 1);
+ mlxsw_reg_tngcr_nve_group_size_flood_set(payload, 1);
+}
+
+/* TNUMT - Tunneling NVE Underlay Multicast Table Register
+ * -------------------------------------------------------
+ * The TNUMT register is for building the underlay MC table. It is used
+ * for MC, flooding and BC traffic into the NVE tunnel.
+ */
+#define MLXSW_REG_TNUMT_ID 0xA003
+#define MLXSW_REG_TNUMT_LEN 0x20
+
+MLXSW_REG_DEFINE(tnumt, MLXSW_REG_TNUMT_ID, MLXSW_REG_TNUMT_LEN);
+
+enum mlxsw_reg_tnumt_record_type {
+ MLXSW_REG_TNUMT_RECORD_TYPE_IPV4,
+ MLXSW_REG_TNUMT_RECORD_TYPE_IPV6,
+ MLXSW_REG_TNUMT_RECORD_TYPE_LABEL,
+};
+
+/* reg_tnumt_record_type
+ * Record type.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, tnumt, record_type, 0x00, 28, 4);
+
+enum mlxsw_reg_tnumt_tunnel_port {
+ MLXSW_REG_TNUMT_TUNNEL_PORT_NVE,
+ MLXSW_REG_TNUMT_TUNNEL_PORT_VPLS,
+ MLXSW_REG_TNUMT_TUNNEL_FLEX_TUNNEL0,
+ MLXSW_REG_TNUMT_TUNNEL_FLEX_TUNNEL1,
+};
+
+/* reg_tnumt_tunnel_port
+ * Tunnel port.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, tnumt, tunnel_port, 0x00, 24, 4);
+
+/* reg_tnumt_underlay_mc_ptr
+ * Index to the underlay multicast table.
+ * For Spectrum the index is to the KVD linear.
+ * Access: Index
+ */
+MLXSW_ITEM32(reg, tnumt, underlay_mc_ptr, 0x00, 0, 24);
+
+/* reg_tnumt_vnext
+ * The next_underlay_mc_ptr is valid.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, tnumt, vnext, 0x04, 31, 1);
+
+/* reg_tnumt_next_underlay_mc_ptr
+ * The next index to the underlay multicast table.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, tnumt, next_underlay_mc_ptr, 0x04, 0, 24);
+
+/* reg_tnumt_record_size
+ * Number of IP addresses in the record.
+ * Range is 1..cap_max_nve_mc_entries_ipv{4,6}
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, tnumt, record_size, 0x08, 0, 3);
+
+/* reg_tnumt_udip
+ * The underlay IPv4 addresses. udip[i] is reserved if i >= size
+ * Access: RW
+ */
+MLXSW_ITEM32_INDEXED(reg, tnumt, udip, 0x0C, 0, 32, 0x04, 0x00, false);
+
+/* reg_tnumt_udip_ptr
+ * The pointer to the underlay IPv6 addresses. udip_ptr[i] is reserved if
+ * i >= size. The IPv6 addresses are configured by RIPS.
+ * Access: RW
+ */
+MLXSW_ITEM32_INDEXED(reg, tnumt, udip_ptr, 0x0C, 0, 24, 0x04, 0x00, false);
+
+static inline void mlxsw_reg_tnumt_pack(char *payload,
+ enum mlxsw_reg_tnumt_record_type type,
+ enum mlxsw_reg_tnumt_tunnel_port tport,
+ u32 underlay_mc_ptr, bool vnext,
+ u32 next_underlay_mc_ptr,
+ u8 record_size)
+{
+ MLXSW_REG_ZERO(tnumt, payload);
+ mlxsw_reg_tnumt_record_type_set(payload, type);
+ mlxsw_reg_tnumt_tunnel_port_set(payload, tport);
+ mlxsw_reg_tnumt_underlay_mc_ptr_set(payload, underlay_mc_ptr);
+ mlxsw_reg_tnumt_vnext_set(payload, vnext);
+ mlxsw_reg_tnumt_next_underlay_mc_ptr_set(payload, next_underlay_mc_ptr);
+ mlxsw_reg_tnumt_record_size_set(payload, record_size);
+}
+
+/* TNQCR - Tunneling NVE QoS Configuration Register
+ * ------------------------------------------------
+ * The TNQCR register configures how QoS is set in encapsulation into the
+ * underlay network.
+ */
+#define MLXSW_REG_TNQCR_ID 0xA010
+#define MLXSW_REG_TNQCR_LEN 0x0C
+
+MLXSW_REG_DEFINE(tnqcr, MLXSW_REG_TNQCR_ID, MLXSW_REG_TNQCR_LEN);
+
+/* reg_tnqcr_enc_set_dscp
+ * For encapsulation: How to set DSCP field:
+ * 0 - Copy the DSCP from the overlay (inner) IP header to the underlay
+ * (outer) IP header. If there is no IP header, use TNQDR.dscp
+ * 1 - Set the DSCP field as TNQDR.dscp
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, tnqcr, enc_set_dscp, 0x04, 28, 1);
+
+static inline void mlxsw_reg_tnqcr_pack(char *payload)
+{
+ MLXSW_REG_ZERO(tnqcr, payload);
+ mlxsw_reg_tnqcr_enc_set_dscp_set(payload, 0);
+}
+
+/* TNQDR - Tunneling NVE QoS Default Register
+ * ------------------------------------------
+ * The TNQDR register configures the default QoS settings for NVE
+ * encapsulation.
+ */
+#define MLXSW_REG_TNQDR_ID 0xA011
+#define MLXSW_REG_TNQDR_LEN 0x08
+
+MLXSW_REG_DEFINE(tnqdr, MLXSW_REG_TNQDR_ID, MLXSW_REG_TNQDR_LEN);
+
+/* reg_tnqdr_local_port
+ * Local port number (receive port). CPU port is supported.
+ * Access: Index
+ */
+MLXSW_ITEM32(reg, tnqdr, local_port, 0x00, 16, 8);
+
+/* reg_tnqdr_dscp
+ * For encapsulation, the default DSCP.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, tnqdr, dscp, 0x04, 0, 6);
+
+static inline void mlxsw_reg_tnqdr_pack(char *payload, u8 local_port)
+{
+ MLXSW_REG_ZERO(tnqdr, payload);
+ mlxsw_reg_tnqdr_local_port_set(payload, local_port);
+ mlxsw_reg_tnqdr_dscp_set(payload, 0);
+}
+
+/* TNEEM - Tunneling NVE Encapsulation ECN Mapping Register
+ * --------------------------------------------------------
+ * The TNEEM register maps ECN of the IP header at the ingress to the
+ * encapsulation to the ECN of the underlay network.
+ */
+#define MLXSW_REG_TNEEM_ID 0xA012
+#define MLXSW_REG_TNEEM_LEN 0x0C
+
+MLXSW_REG_DEFINE(tneem, MLXSW_REG_TNEEM_ID, MLXSW_REG_TNEEM_LEN);
+
+/* reg_tneem_overlay_ecn
+ * ECN of the IP header in the overlay network.
+ * Access: Index
+ */
+MLXSW_ITEM32(reg, tneem, overlay_ecn, 0x04, 24, 2);
+
+/* reg_tneem_underlay_ecn
+ * ECN of the IP header in the underlay network.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, tneem, underlay_ecn, 0x04, 16, 2);
+
+static inline void mlxsw_reg_tneem_pack(char *payload, u8 overlay_ecn,
+ u8 underlay_ecn)
+{
+ MLXSW_REG_ZERO(tneem, payload);
+ mlxsw_reg_tneem_overlay_ecn_set(payload, overlay_ecn);
+ mlxsw_reg_tneem_underlay_ecn_set(payload, underlay_ecn);
+}
+
+/* TNDEM - Tunneling NVE Decapsulation ECN Mapping Register
+ * --------------------------------------------------------
+ * The TNDEM register configures the actions that are done in the
+ * decapsulation.
+ */
+#define MLXSW_REG_TNDEM_ID 0xA013
+#define MLXSW_REG_TNDEM_LEN 0x0C
+
+MLXSW_REG_DEFINE(tndem, MLXSW_REG_TNDEM_ID, MLXSW_REG_TNDEM_LEN);
+
+/* reg_tndem_underlay_ecn
+ * ECN field of the IP header in the underlay network.
+ * Access: Index
+ */
+MLXSW_ITEM32(reg, tndem, underlay_ecn, 0x04, 24, 2);
+
+/* reg_tndem_overlay_ecn
+ * ECN field of the IP header in the overlay network.
+ * Access: Index
+ */
+MLXSW_ITEM32(reg, tndem, overlay_ecn, 0x04, 16, 2);
+
+/* reg_tndem_eip_ecn
+ * Egress IP ECN. ECN field of the IP header of the packet which goes out
+ * from the decapsulation.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, tndem, eip_ecn, 0x04, 8, 2);
+
+/* reg_tndem_trap_en
+ * Trap enable:
+ * 0 - No trap due to decap ECN
+ * 1 - Trap enable with trap_id
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, tndem, trap_en, 0x08, 28, 4);
+
+/* reg_tndem_trap_id
+ * Trap ID. Either DECAP_ECN0 or DECAP_ECN1.
+ * Reserved when trap_en is '0'.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, tndem, trap_id, 0x08, 0, 9);
+
+static inline void mlxsw_reg_tndem_pack(char *payload, u8 underlay_ecn,
+ u8 overlay_ecn, u8 ecn, bool trap_en,
+ u16 trap_id)
+{
+ MLXSW_REG_ZERO(tndem, payload);
+ mlxsw_reg_tndem_underlay_ecn_set(payload, underlay_ecn);
+ mlxsw_reg_tndem_overlay_ecn_set(payload, overlay_ecn);
+ mlxsw_reg_tndem_eip_ecn_set(payload, ecn);
+ mlxsw_reg_tndem_trap_en_set(payload, trap_en);
+ mlxsw_reg_tndem_trap_id_set(payload, trap_id);
+}
+
+/* TNPC - Tunnel Port Configuration Register
+ * -----------------------------------------
+ * The TNPC register is used for tunnel port configuration.
+ * Reserved when Spectrum.
+ */
+#define MLXSW_REG_TNPC_ID 0xA020
+#define MLXSW_REG_TNPC_LEN 0x18
+
+MLXSW_REG_DEFINE(tnpc, MLXSW_REG_TNPC_ID, MLXSW_REG_TNPC_LEN);
+
+enum mlxsw_reg_tnpc_tunnel_port {
+ MLXSW_REG_TNPC_TUNNEL_PORT_NVE,
+ MLXSW_REG_TNPC_TUNNEL_PORT_VPLS,
+ MLXSW_REG_TNPC_TUNNEL_FLEX_TUNNEL0,
+ MLXSW_REG_TNPC_TUNNEL_FLEX_TUNNEL1,
+};
+
+/* reg_tnpc_tunnel_port
+ * Tunnel port.
+ * Access: Index
+ */
+MLXSW_ITEM32(reg, tnpc, tunnel_port, 0x00, 0, 4);
+
+/* reg_tnpc_learn_enable_v6
+ * During IPv6 underlay decapsulation, whether to learn from tunnel port.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, tnpc, learn_enable_v6, 0x04, 1, 1);
+
+/* reg_tnpc_learn_enable_v4
+ * During IPv4 underlay decapsulation, whether to learn from tunnel port.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, tnpc, learn_enable_v4, 0x04, 0, 1);
+
+static inline void mlxsw_reg_tnpc_pack(char *payload,
+ enum mlxsw_reg_tnpc_tunnel_port tport,
+ bool learn_enable)
+{
+ MLXSW_REG_ZERO(tnpc, payload);
+ mlxsw_reg_tnpc_tunnel_port_set(payload, tport);
+ mlxsw_reg_tnpc_learn_enable_v4_set(payload, learn_enable);
+ mlxsw_reg_tnpc_learn_enable_v6_set(payload, learn_enable);
+}
+
/* TIGCR - Tunneling IPinIP General Configuration Register
* -------------------------------------------------------
* The TIGCR register is used for setting up the IPinIP Tunnel configuration.
@@ -8336,8 +8927,15 @@ MLXSW_ITEM32(reg, sbpr, dir, 0x00, 24, 2);
*/
MLXSW_ITEM32(reg, sbpr, pool, 0x00, 0, 4);
+/* reg_sbpr_infi_size
+ * Size is infinite.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, sbpr, infi_size, 0x04, 31, 1);
+
/* reg_sbpr_size
* Pool size in buffer cells.
+ * Reserved when infi_size = 1.
* Access: RW
*/
MLXSW_ITEM32(reg, sbpr, size, 0x04, 0, 24);
@@ -8355,13 +8953,15 @@ MLXSW_ITEM32(reg, sbpr, mode, 0x08, 0, 4);
static inline void mlxsw_reg_sbpr_pack(char *payload, u8 pool,
enum mlxsw_reg_sbxx_dir dir,
- enum mlxsw_reg_sbpr_mode mode, u32 size)
+ enum mlxsw_reg_sbpr_mode mode, u32 size,
+ bool infi_size)
{
MLXSW_REG_ZERO(sbpr, payload);
mlxsw_reg_sbpr_pool_set(payload, pool);
mlxsw_reg_sbpr_dir_set(payload, dir);
mlxsw_reg_sbpr_mode_set(payload, mode);
mlxsw_reg_sbpr_size_set(payload, size);
+ mlxsw_reg_sbpr_infi_size_set(payload, infi_size);
}
/* SBCM - Shared Buffer Class Management Register
@@ -8409,6 +9009,12 @@ MLXSW_ITEM32(reg, sbcm, min_buff, 0x18, 0, 24);
#define MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN 1
#define MLXSW_REG_SBXX_DYN_MAX_BUFF_MAX 14
+/* reg_sbcm_infi_max
+ * Max buffer is infinite.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, sbcm, infi_max, 0x1C, 31, 1);
+
/* reg_sbcm_max_buff
* When the pool associated to the port-pg/tclass is configured to
* static, Maximum buffer size for the limiter configured in cells.
@@ -8418,6 +9024,7 @@ MLXSW_ITEM32(reg, sbcm, min_buff, 0x18, 0, 24);
* 0: 0
* i: (1/128)*2^(i-1), for i=1..14
* 0xFF: Infinity
+ * Reserved when infi_max = 1.
* Access: RW
*/
MLXSW_ITEM32(reg, sbcm, max_buff, 0x1C, 0, 24);
@@ -8430,7 +9037,8 @@ MLXSW_ITEM32(reg, sbcm, pool, 0x24, 0, 4);
static inline void mlxsw_reg_sbcm_pack(char *payload, u8 local_port, u8 pg_buff,
enum mlxsw_reg_sbxx_dir dir,
- u32 min_buff, u32 max_buff, u8 pool)
+ u32 min_buff, u32 max_buff,
+ bool infi_max, u8 pool)
{
MLXSW_REG_ZERO(sbcm, payload);
mlxsw_reg_sbcm_local_port_set(payload, local_port);
@@ -8438,6 +9046,7 @@ static inline void mlxsw_reg_sbcm_pack(char *payload, u8 local_port, u8 pg_buff,
mlxsw_reg_sbcm_dir_set(payload, dir);
mlxsw_reg_sbcm_min_buff_set(payload, min_buff);
mlxsw_reg_sbcm_max_buff_set(payload, max_buff);
+ mlxsw_reg_sbcm_infi_max_set(payload, infi_max);
mlxsw_reg_sbcm_pool_set(payload, pool);
}
@@ -8810,6 +9419,14 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = {
MLXSW_REG(mcc),
MLXSW_REG(mcda),
MLXSW_REG(mgpc),
+ MLXSW_REG(mprs),
+ MLXSW_REG(tngcr),
+ MLXSW_REG(tnumt),
+ MLXSW_REG(tnqcr),
+ MLXSW_REG(tnqdr),
+ MLXSW_REG(tneem),
+ MLXSW_REG(tndem),
+ MLXSW_REG(tnpc),
MLXSW_REG(tigcr),
MLXSW_REG(sbpr),
MLXSW_REG(sbcm),
diff --git a/drivers/net/ethernet/mellanox/mlxsw/resources.h b/drivers/net/ethernet/mellanox/mlxsw/resources.h
index 79a31de7c825..99b341539870 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/resources.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/resources.h
@@ -46,6 +46,8 @@ enum mlxsw_res_id {
MLXSW_RES_ID_MAX_RIFS,
MLXSW_RES_ID_MC_ERIF_LIST_ENTRIES,
MLXSW_RES_ID_MAX_LPM_TREES,
+ MLXSW_RES_ID_MAX_NVE_MC_ENTRIES_IPV4,
+ MLXSW_RES_ID_MAX_NVE_MC_ENTRIES_IPV6,
/* Internal resources.
* Determined by the SW, not queried from the HW.
@@ -96,6 +98,8 @@ static u16 mlxsw_res_ids[] = {
[MLXSW_RES_ID_MAX_RIFS] = 0x2C02,
[MLXSW_RES_ID_MC_ERIF_LIST_ENTRIES] = 0x2C10,
[MLXSW_RES_ID_MAX_LPM_TREES] = 0x2C30,
+ [MLXSW_RES_ID_MAX_NVE_MC_ENTRIES_IPV4] = 0x2E02,
+ [MLXSW_RES_ID_MAX_NVE_MC_ENTRIES_IPV6] = 0x2E03,
};
struct mlxsw_res {
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index b492152c8881..9bec940330a4 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -21,6 +21,7 @@
#include <linux/dcbnl.h>
#include <linux/inetdevice.h>
#include <linux/netlink.h>
+#include <linux/random.h>
#include <net/switchdev.h>
#include <net/pkt_cls.h>
#include <net/tc_act/tc_mirred.h>
@@ -331,7 +332,10 @@ static int mlxsw_sp_fw_rev_validate(struct mlxsw_sp *mlxsw_sp)
return -EINVAL;
}
if (MLXSW_SP_FWREV_MINOR_TO_BRANCH(rev->minor) ==
- MLXSW_SP_FWREV_MINOR_TO_BRANCH(req_rev->minor))
+ MLXSW_SP_FWREV_MINOR_TO_BRANCH(req_rev->minor) &&
+ (rev->minor > req_rev->minor ||
+ (rev->minor == req_rev->minor &&
+ rev->subminor >= req_rev->subminor)))
return 0;
dev_info(mlxsw_sp->bus_info->dev, "The firmware version %d.%d.%d is incompatible with the driver\n",
@@ -2736,6 +2740,21 @@ int mlxsw_sp_port_ets_maxrate_set(struct mlxsw_sp_port *mlxsw_sp_port,
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qeec), qeec_pl);
}
+static int mlxsw_sp_port_min_bw_set(struct mlxsw_sp_port *mlxsw_sp_port,
+ enum mlxsw_reg_qeec_hr hr, u8 index,
+ u8 next_index, u32 minrate)
+{
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+ char qeec_pl[MLXSW_REG_QEEC_LEN];
+
+ mlxsw_reg_qeec_pack(qeec_pl, mlxsw_sp_port->local_port, hr, index,
+ next_index);
+ mlxsw_reg_qeec_mise_set(qeec_pl, true);
+ mlxsw_reg_qeec_min_shaper_rate_set(qeec_pl, minrate);
+
+ return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qeec), qeec_pl);
+}
+
int mlxsw_sp_port_prio_tc_set(struct mlxsw_sp_port *mlxsw_sp_port,
u8 switch_prio, u8 tclass)
{
@@ -2804,6 +2823,23 @@ static int mlxsw_sp_port_ets_init(struct mlxsw_sp_port *mlxsw_sp_port)
MLXSW_REG_QEEC_MAS_DIS);
if (err)
return err;
+
+ err = mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port,
+ MLXSW_REG_QEEC_HIERARCY_TC,
+ i + 8, i,
+ MLXSW_REG_QEEC_MAS_DIS);
+ if (err)
+ return err;
+ }
+
+ /* Configure the min shaper for multicast TCs. */
+ for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
+ err = mlxsw_sp_port_min_bw_set(mlxsw_sp_port,
+ MLXSW_REG_QEEC_HIERARCY_TC,
+ i + 8, i,
+ MLXSW_REG_QEEC_MIS_MIN);
+ if (err)
+ return err;
}
/* Map all priorities to traffic class 0. */
@@ -2983,6 +3019,13 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
goto err_port_qdiscs_init;
}
+ err = mlxsw_sp_port_nve_init(mlxsw_sp_port);
+ if (err) {
+ dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize NVE\n",
+ mlxsw_sp_port->local_port);
+ goto err_port_nve_init;
+ }
+
mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_get(mlxsw_sp_port, 1);
if (IS_ERR(mlxsw_sp_port_vlan)) {
dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to create VID 1\n",
@@ -3011,6 +3054,8 @@ err_register_netdev:
mlxsw_sp_port_switchdev_fini(mlxsw_sp_port);
mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan);
err_port_vlan_get:
+ mlxsw_sp_port_nve_fini(mlxsw_sp_port);
+err_port_nve_init:
mlxsw_sp_tc_qdisc_fini(mlxsw_sp_port);
err_port_qdiscs_init:
mlxsw_sp_port_fids_fini(mlxsw_sp_port);
@@ -3050,6 +3095,7 @@ static void mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port)
mlxsw_sp->ports[local_port] = NULL;
mlxsw_sp_port_switchdev_fini(mlxsw_sp_port);
mlxsw_sp_port_vlan_flush(mlxsw_sp_port);
+ mlxsw_sp_port_nve_fini(mlxsw_sp_port);
mlxsw_sp_tc_qdisc_fini(mlxsw_sp_port);
mlxsw_sp_port_fids_fini(mlxsw_sp_port);
mlxsw_sp_port_dcb_fini(mlxsw_sp_port);
@@ -3459,6 +3505,7 @@ static const struct mlxsw_listener mlxsw_sp_listener[] = {
MLXSW_SP_RXL_MARK(ROUTER_ALERT_IPV4, TRAP_TO_CPU, ROUTER_EXP, false),
MLXSW_SP_RXL_MARK(ROUTER_ALERT_IPV6, TRAP_TO_CPU, ROUTER_EXP, false),
MLXSW_SP_RXL_MARK(IPIP_DECAP_ERROR, TRAP_TO_CPU, ROUTER_EXP, false),
+ MLXSW_SP_RXL_MARK(DECAP_ECN0, TRAP_TO_CPU, ROUTER_EXP, false),
MLXSW_SP_RXL_MARK(IPV4_VRRP, TRAP_TO_CPU, ROUTER_EXP, false),
MLXSW_SP_RXL_MARK(IPV6_VRRP, TRAP_TO_CPU, ROUTER_EXP, false),
/* PKT Sample trap */
@@ -3472,6 +3519,8 @@ static const struct mlxsw_listener mlxsw_sp_listener[] = {
MLXSW_SP_RXL_MARK(RPF, TRAP_TO_CPU, RPF, false),
MLXSW_SP_RXL_MARK(ACL1, TRAP_TO_CPU, MULTICAST, false),
MLXSW_SP_RXL_MR_MARK(ACL2, TRAP_TO_CPU, MULTICAST, false),
+ /* NVE traps */
+ MLXSW_SP_RXL_MARK(NVE_ENCAP_ARP, TRAP_TO_CPU, ARP, false),
};
static int mlxsw_sp_cpu_policers_set(struct mlxsw_core *mlxsw_core)
@@ -3519,7 +3568,6 @@ static int mlxsw_sp_cpu_policers_set(struct mlxsw_core *mlxsw_core)
burst_size = 7;
break;
case MLXSW_REG_HTGT_TRAP_GROUP_SP_IP2ME:
- is_bytes = true;
rate = 4 * 1024;
burst_size = 4;
break;
@@ -3656,8 +3704,10 @@ static void mlxsw_sp_traps_fini(struct mlxsw_sp *mlxsw_sp)
static int mlxsw_sp_lag_init(struct mlxsw_sp *mlxsw_sp)
{
char slcr_pl[MLXSW_REG_SLCR_LEN];
+ u32 seed;
int err;
+ get_random_bytes(&seed, sizeof(seed));
mlxsw_reg_slcr_pack(slcr_pl, MLXSW_REG_SLCR_LAG_HASH_SMAC |
MLXSW_REG_SLCR_LAG_HASH_DMAC |
MLXSW_REG_SLCR_LAG_HASH_ETHERTYPE |
@@ -3666,7 +3716,7 @@ static int mlxsw_sp_lag_init(struct mlxsw_sp *mlxsw_sp)
MLXSW_REG_SLCR_LAG_HASH_DIP |
MLXSW_REG_SLCR_LAG_HASH_SPORT |
MLXSW_REG_SLCR_LAG_HASH_DPORT |
- MLXSW_REG_SLCR_LAG_HASH_IPPROTO);
+ MLXSW_REG_SLCR_LAG_HASH_IPPROTO, seed);
err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(slcr), slcr_pl);
if (err)
return err;
@@ -3779,6 +3829,12 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core,
goto err_afa_init;
}
+ err = mlxsw_sp_nve_init(mlxsw_sp);
+ if (err) {
+ dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize NVE\n");
+ goto err_nve_init;
+ }
+
err = mlxsw_sp_router_init(mlxsw_sp);
if (err) {
dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize router\n");
@@ -3825,6 +3881,8 @@ err_acl_init:
err_netdev_notifier:
mlxsw_sp_router_fini(mlxsw_sp);
err_router_init:
+ mlxsw_sp_nve_fini(mlxsw_sp);
+err_nve_init:
mlxsw_sp_afa_fini(mlxsw_sp);
err_afa_init:
mlxsw_sp_counter_pool_fini(mlxsw_sp);
@@ -3857,6 +3915,7 @@ static int mlxsw_sp1_init(struct mlxsw_core *mlxsw_core,
mlxsw_sp->afk_ops = &mlxsw_sp1_afk_ops;
mlxsw_sp->mr_tcam_ops = &mlxsw_sp1_mr_tcam_ops;
mlxsw_sp->acl_tcam_ops = &mlxsw_sp1_acl_tcam_ops;
+ mlxsw_sp->nve_ops_arr = mlxsw_sp1_nve_ops_arr;
return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info);
}
@@ -3871,6 +3930,7 @@ static int mlxsw_sp2_init(struct mlxsw_core *mlxsw_core,
mlxsw_sp->afk_ops = &mlxsw_sp2_afk_ops;
mlxsw_sp->mr_tcam_ops = &mlxsw_sp2_mr_tcam_ops;
mlxsw_sp->acl_tcam_ops = &mlxsw_sp2_acl_tcam_ops;
+ mlxsw_sp->nve_ops_arr = mlxsw_sp2_nve_ops_arr;
return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info);
}
@@ -3884,6 +3944,7 @@ static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core)
mlxsw_sp_acl_fini(mlxsw_sp);
unregister_netdevice_notifier(&mlxsw_sp->netdevice_nb);
mlxsw_sp_router_fini(mlxsw_sp);
+ mlxsw_sp_nve_fini(mlxsw_sp);
mlxsw_sp_afa_fini(mlxsw_sp);
mlxsw_sp_counter_pool_fini(mlxsw_sp);
mlxsw_sp_switchdev_fini(mlxsw_sp);
@@ -4550,6 +4611,41 @@ static void mlxsw_sp_port_ovs_leave(struct mlxsw_sp_port *mlxsw_sp_port)
mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
}
+static bool mlxsw_sp_bridge_has_multiple_vxlans(struct net_device *br_dev)
+{
+ unsigned int num_vxlans = 0;
+ struct net_device *dev;
+ struct list_head *iter;
+
+ netdev_for_each_lower_dev(br_dev, dev, iter) {
+ if (netif_is_vxlan(dev))
+ num_vxlans++;
+ }
+
+ return num_vxlans > 1;
+}
+
+static bool mlxsw_sp_bridge_vxlan_is_valid(struct net_device *br_dev,
+ struct netlink_ext_ack *extack)
+{
+ if (br_multicast_enabled(br_dev)) {
+ NL_SET_ERR_MSG_MOD(extack, "Multicast can not be enabled on a bridge with a VxLAN device");
+ return false;
+ }
+
+ if (br_vlan_enabled(br_dev)) {
+ NL_SET_ERR_MSG_MOD(extack, "VLAN filtering can not be enabled on a bridge with a VxLAN device");
+ return false;
+ }
+
+ if (mlxsw_sp_bridge_has_multiple_vxlans(br_dev)) {
+ NL_SET_ERR_MSG_MOD(extack, "Multiple VxLAN devices are not supported in a VLAN-unaware bridge");
+ return false;
+ }
+
+ return true;
+}
+
static int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev,
struct net_device *dev,
unsigned long event, void *ptr)
@@ -4579,6 +4675,11 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev,
}
if (!info->linking)
break;
+ if (netif_is_bridge_master(upper_dev) &&
+ !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp, upper_dev) &&
+ mlxsw_sp_bridge_has_vxlan(upper_dev) &&
+ !mlxsw_sp_bridge_vxlan_is_valid(upper_dev, extack))
+ return -EOPNOTSUPP;
if (netdev_has_any_upper_dev(upper_dev) &&
(!netif_is_bridge_master(upper_dev) ||
!mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp,
@@ -4736,6 +4837,11 @@ static int mlxsw_sp_netdevice_port_vlan_event(struct net_device *vlan_dev,
}
if (!info->linking)
break;
+ if (netif_is_bridge_master(upper_dev) &&
+ !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp, upper_dev) &&
+ mlxsw_sp_bridge_has_vxlan(upper_dev) &&
+ !mlxsw_sp_bridge_vxlan_is_valid(upper_dev, extack))
+ return -EOPNOTSUPP;
if (netdev_has_any_upper_dev(upper_dev) &&
(!netif_is_bridge_master(upper_dev) ||
!mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp,
@@ -4845,6 +4951,8 @@ static int mlxsw_sp_netdevice_bridge_event(struct net_device *br_dev,
upper_dev = info->upper_dev;
if (info->linking)
break;
+ if (is_vlan_dev(upper_dev))
+ mlxsw_sp_rif_destroy_by_dev(mlxsw_sp, upper_dev);
if (netif_is_macvlan(upper_dev))
mlxsw_sp_rif_macvlan_del(mlxsw_sp, upper_dev);
break;
@@ -4880,6 +4988,63 @@ static bool mlxsw_sp_is_vrf_event(unsigned long event, void *ptr)
return netif_is_l3_master(info->upper_dev);
}
+static int mlxsw_sp_netdevice_vxlan_event(struct mlxsw_sp *mlxsw_sp,
+ struct net_device *dev,
+ unsigned long event, void *ptr)
+{
+ struct netdev_notifier_changeupper_info *cu_info;
+ struct netdev_notifier_info *info = ptr;
+ struct netlink_ext_ack *extack;
+ struct net_device *upper_dev;
+
+ extack = netdev_notifier_info_to_extack(info);
+
+ switch (event) {
+ case NETDEV_CHANGEUPPER:
+ cu_info = container_of(info,
+ struct netdev_notifier_changeupper_info,
+ info);
+ upper_dev = cu_info->upper_dev;
+ if (!netif_is_bridge_master(upper_dev))
+ return 0;
+ if (!mlxsw_sp_lower_get(upper_dev))
+ return 0;
+ if (!mlxsw_sp_bridge_vxlan_is_valid(upper_dev, extack))
+ return -EOPNOTSUPP;
+ if (cu_info->linking) {
+ if (!netif_running(dev))
+ return 0;
+ return mlxsw_sp_bridge_vxlan_join(mlxsw_sp, upper_dev,
+ dev, extack);
+ } else {
+ mlxsw_sp_bridge_vxlan_leave(mlxsw_sp, upper_dev, dev);
+ }
+ break;
+ case NETDEV_PRE_UP:
+ upper_dev = netdev_master_upper_dev_get(dev);
+ if (!upper_dev)
+ return 0;
+ if (!netif_is_bridge_master(upper_dev))
+ return 0;
+ if (!mlxsw_sp_lower_get(upper_dev))
+ return 0;
+ return mlxsw_sp_bridge_vxlan_join(mlxsw_sp, upper_dev, dev,
+ extack);
+ case NETDEV_DOWN:
+ upper_dev = netdev_master_upper_dev_get(dev);
+ if (!upper_dev)
+ return 0;
+ if (!netif_is_bridge_master(upper_dev))
+ return 0;
+ if (!mlxsw_sp_lower_get(upper_dev))
+ return 0;
+ mlxsw_sp_bridge_vxlan_leave(mlxsw_sp, upper_dev, dev);
+ break;
+ }
+
+ return 0;
+}
+
static int mlxsw_sp_netdevice_event(struct notifier_block *nb,
unsigned long event, void *ptr)
{
@@ -4896,6 +5061,8 @@ static int mlxsw_sp_netdevice_event(struct notifier_block *nb,
}
mlxsw_sp_span_respin(mlxsw_sp);
+ if (netif_is_vxlan(dev))
+ err = mlxsw_sp_netdevice_vxlan_event(mlxsw_sp, dev, event, ptr);
if (mlxsw_sp_netdev_is_ipip_ol(mlxsw_sp, dev))
err = mlxsw_sp_netdevice_ipip_ol_event(mlxsw_sp, dev,
event, ptr);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
index 3cdb7aca90b7..0875a79cbe7b 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
@@ -16,6 +16,7 @@
#include <net/psample.h>
#include <net/pkt_cls.h>
#include <net/red.h>
+#include <net/vxlan.h>
#include "port.h"
#include "core.h"
@@ -55,6 +56,8 @@ enum mlxsw_sp_resource_id {
struct mlxsw_sp_port;
struct mlxsw_sp_rif;
struct mlxsw_sp_span_entry;
+enum mlxsw_sp_l3proto;
+union mlxsw_sp_l3addr;
struct mlxsw_sp_upper {
struct net_device *dev;
@@ -113,9 +116,11 @@ struct mlxsw_sp_acl;
struct mlxsw_sp_counter_pool;
struct mlxsw_sp_fid_core;
struct mlxsw_sp_kvdl;
+struct mlxsw_sp_nve;
struct mlxsw_sp_kvdl_ops;
struct mlxsw_sp_mr_tcam_ops;
struct mlxsw_sp_acl_tcam_ops;
+struct mlxsw_sp_nve_ops;
struct mlxsw_sp {
struct mlxsw_sp_port **ports;
@@ -132,6 +137,7 @@ struct mlxsw_sp {
struct mlxsw_sp_acl *acl;
struct mlxsw_sp_fid_core *fid_core;
struct mlxsw_sp_kvdl *kvdl;
+ struct mlxsw_sp_nve *nve;
struct notifier_block netdevice_nb;
struct mlxsw_sp_counter_pool *counter_pool;
@@ -146,6 +152,7 @@ struct mlxsw_sp {
const struct mlxsw_afk_ops *afk_ops;
const struct mlxsw_sp_mr_tcam_ops *mr_tcam_ops;
const struct mlxsw_sp_acl_tcam_ops *acl_tcam_ops;
+ const struct mlxsw_sp_nve_ops **nve_ops_arr;
};
static inline struct mlxsw_sp_upper *
@@ -235,6 +242,25 @@ struct mlxsw_sp_port {
struct mlxsw_sp_acl_block *eg_acl_block;
};
+static inline struct net_device *
+mlxsw_sp_bridge_vxlan_dev_find(struct net_device *br_dev)
+{
+ struct net_device *dev;
+ struct list_head *iter;
+
+ netdev_for_each_lower_dev(br_dev, dev, iter) {
+ if (netif_is_vxlan(dev))
+ return dev;
+ }
+
+ return NULL;
+}
+
+static inline bool mlxsw_sp_bridge_has_vxlan(struct net_device *br_dev)
+{
+ return !!mlxsw_sp_bridge_vxlan_dev_find(br_dev);
+}
+
static inline bool
mlxsw_sp_port_is_pause_en(const struct mlxsw_sp_port *mlxsw_sp_port)
{
@@ -330,6 +356,13 @@ void mlxsw_sp_port_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_port,
struct net_device *br_dev);
bool mlxsw_sp_bridge_device_is_offloaded(const struct mlxsw_sp *mlxsw_sp,
const struct net_device *br_dev);
+int mlxsw_sp_bridge_vxlan_join(struct mlxsw_sp *mlxsw_sp,
+ const struct net_device *br_dev,
+ const struct net_device *vxlan_dev,
+ struct netlink_ext_ack *extack);
+void mlxsw_sp_bridge_vxlan_leave(struct mlxsw_sp *mlxsw_sp,
+ const struct net_device *br_dev,
+ const struct net_device *vxlan_dev);
/* spectrum.c */
int mlxsw_sp_port_ets_set(struct mlxsw_sp_port *mlxsw_sp_port,
@@ -383,6 +416,17 @@ static inline void mlxsw_sp_port_dcb_fini(struct mlxsw_sp_port *mlxsw_sp_port)
#endif
/* spectrum_router.c */
+enum mlxsw_sp_l3proto {
+ MLXSW_SP_L3_PROTO_IPV4,
+ MLXSW_SP_L3_PROTO_IPV6,
+#define MLXSW_SP_L3_PROTO_MAX (MLXSW_SP_L3_PROTO_IPV6 + 1)
+};
+
+union mlxsw_sp_l3addr {
+ __be32 addr4;
+ struct in6_addr addr6;
+};
+
int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp);
void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp);
int mlxsw_sp_netdevice_router_port_event(struct net_device *dev);
@@ -416,6 +460,19 @@ mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan);
void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif);
void mlxsw_sp_rif_destroy_by_dev(struct mlxsw_sp *mlxsw_sp,
struct net_device *dev);
+struct mlxsw_sp_rif *mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp,
+ const struct net_device *dev);
+u8 mlxsw_sp_router_port(const struct mlxsw_sp *mlxsw_sp);
+struct mlxsw_sp_fid *mlxsw_sp_rif_fid(const struct mlxsw_sp_rif *rif);
+int mlxsw_sp_router_nve_promote_decap(struct mlxsw_sp *mlxsw_sp, u32 ul_tb_id,
+ enum mlxsw_sp_l3proto ul_proto,
+ const union mlxsw_sp_l3addr *ul_sip,
+ u32 tunnel_index);
+void mlxsw_sp_router_nve_demote_decap(struct mlxsw_sp *mlxsw_sp, u32 ul_tb_id,
+ enum mlxsw_sp_l3proto ul_proto,
+ const union mlxsw_sp_l3addr *ul_sip);
+int mlxsw_sp_router_tb_id_vr_id(struct mlxsw_sp *mlxsw_sp, u32 tb_id,
+ u16 *vr_id);
/* spectrum_kvdl.c */
enum mlxsw_sp_kvdl_entry_type {
@@ -423,6 +480,7 @@ enum mlxsw_sp_kvdl_entry_type {
MLXSW_SP_KVDL_ENTRY_TYPE_ACTSET,
MLXSW_SP_KVDL_ENTRY_TYPE_PBS,
MLXSW_SP_KVDL_ENTRY_TYPE_MCRIGR,
+ MLXSW_SP_KVDL_ENTRY_TYPE_TNUMT,
};
static inline unsigned int
@@ -433,6 +491,7 @@ mlxsw_sp_kvdl_entry_size(enum mlxsw_sp_kvdl_entry_type type)
case MLXSW_SP_KVDL_ENTRY_TYPE_ACTSET: /* fall through */
case MLXSW_SP_KVDL_ENTRY_TYPE_PBS: /* fall through */
case MLXSW_SP_KVDL_ENTRY_TYPE_MCRIGR: /* fall through */
+ case MLXSW_SP_KVDL_ENTRY_TYPE_TNUMT: /* fall through */
default:
return 1;
}
@@ -662,6 +721,16 @@ int mlxsw_sp_setup_tc_prio(struct mlxsw_sp_port *mlxsw_sp_port,
struct tc_prio_qopt_offload *p);
/* spectrum_fid.c */
+struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_vni(struct mlxsw_sp *mlxsw_sp,
+ __be32 vni);
+int mlxsw_sp_fid_vni(const struct mlxsw_sp_fid *fid, __be32 *vni);
+int mlxsw_sp_fid_nve_flood_index_set(struct mlxsw_sp_fid *fid,
+ u32 nve_flood_index);
+void mlxsw_sp_fid_nve_flood_index_clear(struct mlxsw_sp_fid *fid);
+bool mlxsw_sp_fid_nve_flood_index_is_set(const struct mlxsw_sp_fid *fid);
+int mlxsw_sp_fid_vni_set(struct mlxsw_sp_fid *fid, __be32 vni);
+void mlxsw_sp_fid_vni_clear(struct mlxsw_sp_fid *fid);
+bool mlxsw_sp_fid_vni_is_set(const struct mlxsw_sp_fid *fid);
int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid,
enum mlxsw_sp_flood_type packet_type, u8 local_port,
bool member);
@@ -680,6 +749,8 @@ u16 mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid *fid);
struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_get(struct mlxsw_sp *mlxsw_sp, u16 vid);
struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_get(struct mlxsw_sp *mlxsw_sp,
int br_ifindex);
+struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_lookup(struct mlxsw_sp *mlxsw_sp,
+ int br_ifindex);
struct mlxsw_sp_fid *mlxsw_sp_fid_rfid_get(struct mlxsw_sp *mlxsw_sp,
u16 rif_index);
struct mlxsw_sp_fid *mlxsw_sp_fid_dummy_get(struct mlxsw_sp *mlxsw_sp);
@@ -725,4 +796,39 @@ extern const struct mlxsw_sp_mr_tcam_ops mlxsw_sp1_mr_tcam_ops;
/* spectrum2_mr_tcam.c */
extern const struct mlxsw_sp_mr_tcam_ops mlxsw_sp2_mr_tcam_ops;
+/* spectrum_nve.c */
+enum mlxsw_sp_nve_type {
+ MLXSW_SP_NVE_TYPE_VXLAN,
+};
+
+struct mlxsw_sp_nve_params {
+ enum mlxsw_sp_nve_type type;
+ __be32 vni;
+ const struct net_device *dev;
+};
+
+extern const struct mlxsw_sp_nve_ops *mlxsw_sp1_nve_ops_arr[];
+extern const struct mlxsw_sp_nve_ops *mlxsw_sp2_nve_ops_arr[];
+
+int mlxsw_sp_nve_flood_ip_add(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_fid *fid,
+ enum mlxsw_sp_l3proto proto,
+ union mlxsw_sp_l3addr *addr);
+void mlxsw_sp_nve_flood_ip_del(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_fid *fid,
+ enum mlxsw_sp_l3proto proto,
+ union mlxsw_sp_l3addr *addr);
+u32 mlxsw_sp_nve_decap_tunnel_index_get(const struct mlxsw_sp *mlxsw_sp);
+bool mlxsw_sp_nve_ipv4_route_is_decap(const struct mlxsw_sp *mlxsw_sp,
+ u32 tb_id, __be32 addr);
+int mlxsw_sp_nve_fid_enable(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fid *fid,
+ struct mlxsw_sp_nve_params *params,
+ struct netlink_ext_ack *extack);
+void mlxsw_sp_nve_fid_disable(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_fid *fid);
+int mlxsw_sp_port_nve_init(struct mlxsw_sp_port *mlxsw_sp_port);
+void mlxsw_sp_port_nve_fini(struct mlxsw_sp_port *mlxsw_sp_port);
+int mlxsw_sp_nve_init(struct mlxsw_sp *mlxsw_sp);
+void mlxsw_sp_nve_fini(struct mlxsw_sp *mlxsw_sp);
+
#endif
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum2_kvdl.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum2_kvdl.c
index 68c8b148bef2..8d14770766b4 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum2_kvdl.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum2_kvdl.c
@@ -35,6 +35,7 @@ static const struct mlxsw_sp2_kvdl_part_info mlxsw_sp2_kvdl_parts_info[] = {
MAX_KVD_ACTION_SETS),
MLXSW_SP2_KVDL_PART_INFO(PBS, 0x24, KVD_SIZE, KVD_SIZE),
MLXSW_SP2_KVDL_PART_INFO(MCRIGR, 0x26, KVD_SIZE, KVD_SIZE),
+ MLXSW_SP2_KVDL_PART_INFO(TNUMT, 0x29, KVD_SIZE, KVD_SIZE),
};
#define MLXSW_SP2_KVDL_PARTS_INFO_LEN ARRAY_SIZE(mlxsw_sp2_kvdl_parts_info)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c
index 3589432d1643..12c61e0cc570 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c
@@ -25,28 +25,52 @@ struct mlxsw_cp_sb_occ {
struct mlxsw_sp_sb_cm {
u32 min_buff;
u32 max_buff;
- u8 pool;
+ u16 pool_index;
struct mlxsw_cp_sb_occ occ;
};
+#define MLXSW_SP_SB_INFI -1U
+
struct mlxsw_sp_sb_pm {
u32 min_buff;
u32 max_buff;
struct mlxsw_cp_sb_occ occ;
};
-#define MLXSW_SP_SB_POOL_COUNT 4
-#define MLXSW_SP_SB_TC_COUNT 8
+struct mlxsw_sp_sb_pool_des {
+ enum mlxsw_reg_sbxx_dir dir;
+ u8 pool;
+};
+
+/* Order ingress pools before egress pools. */
+static const struct mlxsw_sp_sb_pool_des mlxsw_sp_sb_pool_dess[] = {
+ {MLXSW_REG_SBXX_DIR_INGRESS, 0},
+ {MLXSW_REG_SBXX_DIR_INGRESS, 1},
+ {MLXSW_REG_SBXX_DIR_INGRESS, 2},
+ {MLXSW_REG_SBXX_DIR_INGRESS, 3},
+ {MLXSW_REG_SBXX_DIR_EGRESS, 0},
+ {MLXSW_REG_SBXX_DIR_EGRESS, 1},
+ {MLXSW_REG_SBXX_DIR_EGRESS, 2},
+ {MLXSW_REG_SBXX_DIR_EGRESS, 3},
+ {MLXSW_REG_SBXX_DIR_EGRESS, 15},
+};
+
+#define MLXSW_SP_SB_POOL_DESS_LEN ARRAY_SIZE(mlxsw_sp_sb_pool_dess)
+
+#define MLXSW_SP_SB_ING_TC_COUNT 8
+#define MLXSW_SP_SB_EG_TC_COUNT 16
struct mlxsw_sp_sb_port {
- struct mlxsw_sp_sb_cm cms[2][MLXSW_SP_SB_TC_COUNT];
- struct mlxsw_sp_sb_pm pms[2][MLXSW_SP_SB_POOL_COUNT];
+ struct mlxsw_sp_sb_cm ing_cms[MLXSW_SP_SB_ING_TC_COUNT];
+ struct mlxsw_sp_sb_cm eg_cms[MLXSW_SP_SB_EG_TC_COUNT];
+ struct mlxsw_sp_sb_pm pms[MLXSW_SP_SB_POOL_DESS_LEN];
};
struct mlxsw_sp_sb {
- struct mlxsw_sp_sb_pr prs[2][MLXSW_SP_SB_POOL_COUNT];
+ struct mlxsw_sp_sb_pr prs[MLXSW_SP_SB_POOL_DESS_LEN];
struct mlxsw_sp_sb_port *ports;
u32 cell_size;
+ u64 sb_size;
};
u32 mlxsw_sp_cells_bytes(const struct mlxsw_sp *mlxsw_sp, u32 cells)
@@ -60,95 +84,122 @@ u32 mlxsw_sp_bytes_cells(const struct mlxsw_sp *mlxsw_sp, u32 bytes)
}
static struct mlxsw_sp_sb_pr *mlxsw_sp_sb_pr_get(struct mlxsw_sp *mlxsw_sp,
- u8 pool,
- enum mlxsw_reg_sbxx_dir dir)
+ u16 pool_index)
{
- return &mlxsw_sp->sb->prs[dir][pool];
+ return &mlxsw_sp->sb->prs[pool_index];
+}
+
+static bool mlxsw_sp_sb_cm_exists(u8 pg_buff, enum mlxsw_reg_sbxx_dir dir)
+{
+ if (dir == MLXSW_REG_SBXX_DIR_INGRESS)
+ return pg_buff < MLXSW_SP_SB_ING_TC_COUNT;
+ else
+ return pg_buff < MLXSW_SP_SB_EG_TC_COUNT;
}
static struct mlxsw_sp_sb_cm *mlxsw_sp_sb_cm_get(struct mlxsw_sp *mlxsw_sp,
u8 local_port, u8 pg_buff,
enum mlxsw_reg_sbxx_dir dir)
{
- return &mlxsw_sp->sb->ports[local_port].cms[dir][pg_buff];
+ struct mlxsw_sp_sb_port *sb_port = &mlxsw_sp->sb->ports[local_port];
+
+ WARN_ON(!mlxsw_sp_sb_cm_exists(pg_buff, dir));
+ if (dir == MLXSW_REG_SBXX_DIR_INGRESS)
+ return &sb_port->ing_cms[pg_buff];
+ else
+ return &sb_port->eg_cms[pg_buff];
}
static struct mlxsw_sp_sb_pm *mlxsw_sp_sb_pm_get(struct mlxsw_sp *mlxsw_sp,
- u8 local_port, u8 pool,
- enum mlxsw_reg_sbxx_dir dir)
+ u8 local_port, u16 pool_index)
{
- return &mlxsw_sp->sb->ports[local_port].pms[dir][pool];
+ return &mlxsw_sp->sb->ports[local_port].pms[pool_index];
}
-static int mlxsw_sp_sb_pr_write(struct mlxsw_sp *mlxsw_sp, u8 pool,
- enum mlxsw_reg_sbxx_dir dir,
- enum mlxsw_reg_sbpr_mode mode, u32 size)
+static int mlxsw_sp_sb_pr_write(struct mlxsw_sp *mlxsw_sp, u16 pool_index,
+ enum mlxsw_reg_sbpr_mode mode,
+ u32 size, bool infi_size)
{
+ const struct mlxsw_sp_sb_pool_des *des =
+ &mlxsw_sp_sb_pool_dess[pool_index];
char sbpr_pl[MLXSW_REG_SBPR_LEN];
struct mlxsw_sp_sb_pr *pr;
int err;
- mlxsw_reg_sbpr_pack(sbpr_pl, pool, dir, mode, size);
+ mlxsw_reg_sbpr_pack(sbpr_pl, des->pool, des->dir, mode,
+ size, infi_size);
err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbpr), sbpr_pl);
if (err)
return err;
- pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool, dir);
+ if (infi_size)
+ size = mlxsw_sp_bytes_cells(mlxsw_sp, mlxsw_sp->sb->sb_size);
+ pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool_index);
pr->mode = mode;
pr->size = size;
return 0;
}
static int mlxsw_sp_sb_cm_write(struct mlxsw_sp *mlxsw_sp, u8 local_port,
- u8 pg_buff, enum mlxsw_reg_sbxx_dir dir,
- u32 min_buff, u32 max_buff, u8 pool)
+ u8 pg_buff, u32 min_buff, u32 max_buff,
+ bool infi_max, u16 pool_index)
{
+ const struct mlxsw_sp_sb_pool_des *des =
+ &mlxsw_sp_sb_pool_dess[pool_index];
char sbcm_pl[MLXSW_REG_SBCM_LEN];
+ struct mlxsw_sp_sb_cm *cm;
int err;
- mlxsw_reg_sbcm_pack(sbcm_pl, local_port, pg_buff, dir,
- min_buff, max_buff, pool);
+ mlxsw_reg_sbcm_pack(sbcm_pl, local_port, pg_buff, des->dir,
+ min_buff, max_buff, infi_max, des->pool);
err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbcm), sbcm_pl);
if (err)
return err;
- if (pg_buff < MLXSW_SP_SB_TC_COUNT) {
- struct mlxsw_sp_sb_cm *cm;
- cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port, pg_buff, dir);
+ if (mlxsw_sp_sb_cm_exists(pg_buff, des->dir)) {
+ if (infi_max)
+ max_buff = mlxsw_sp_bytes_cells(mlxsw_sp,
+ mlxsw_sp->sb->sb_size);
+
+ cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port, pg_buff,
+ des->dir);
cm->min_buff = min_buff;
cm->max_buff = max_buff;
- cm->pool = pool;
+ cm->pool_index = pool_index;
}
return 0;
}
static int mlxsw_sp_sb_pm_write(struct mlxsw_sp *mlxsw_sp, u8 local_port,
- u8 pool, enum mlxsw_reg_sbxx_dir dir,
- u32 min_buff, u32 max_buff)
+ u16 pool_index, u32 min_buff, u32 max_buff)
{
+ const struct mlxsw_sp_sb_pool_des *des =
+ &mlxsw_sp_sb_pool_dess[pool_index];
char sbpm_pl[MLXSW_REG_SBPM_LEN];
struct mlxsw_sp_sb_pm *pm;
int err;
- mlxsw_reg_sbpm_pack(sbpm_pl, local_port, pool, dir, false,
+ mlxsw_reg_sbpm_pack(sbpm_pl, local_port, des->pool, des->dir, false,
min_buff, max_buff);
err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbpm), sbpm_pl);
if (err)
return err;
- pm = mlxsw_sp_sb_pm_get(mlxsw_sp, local_port, pool, dir);
+ pm = mlxsw_sp_sb_pm_get(mlxsw_sp, local_port, pool_index);
pm->min_buff = min_buff;
pm->max_buff = max_buff;
return 0;
}
static int mlxsw_sp_sb_pm_occ_clear(struct mlxsw_sp *mlxsw_sp, u8 local_port,
- u8 pool, enum mlxsw_reg_sbxx_dir dir,
- struct list_head *bulk_list)
+ u16 pool_index, struct list_head *bulk_list)
{
+ const struct mlxsw_sp_sb_pool_des *des =
+ &mlxsw_sp_sb_pool_dess[pool_index];
char sbpm_pl[MLXSW_REG_SBPM_LEN];
- mlxsw_reg_sbpm_pack(sbpm_pl, local_port, pool, dir, true, 0, 0);
+ mlxsw_reg_sbpm_pack(sbpm_pl, local_port, des->pool, des->dir,
+ true, 0, 0);
return mlxsw_reg_trans_query(mlxsw_sp->core, MLXSW_REG(sbpm), sbpm_pl,
bulk_list, NULL, 0);
}
@@ -163,14 +214,16 @@ static void mlxsw_sp_sb_pm_occ_query_cb(struct mlxsw_core *mlxsw_core,
}
static int mlxsw_sp_sb_pm_occ_query(struct mlxsw_sp *mlxsw_sp, u8 local_port,
- u8 pool, enum mlxsw_reg_sbxx_dir dir,
- struct list_head *bulk_list)
+ u16 pool_index, struct list_head *bulk_list)
{
+ const struct mlxsw_sp_sb_pool_des *des =
+ &mlxsw_sp_sb_pool_dess[pool_index];
char sbpm_pl[MLXSW_REG_SBPM_LEN];
struct mlxsw_sp_sb_pm *pm;
- pm = mlxsw_sp_sb_pm_get(mlxsw_sp, local_port, pool, dir);
- mlxsw_reg_sbpm_pack(sbpm_pl, local_port, pool, dir, false, 0, 0);
+ pm = mlxsw_sp_sb_pm_get(mlxsw_sp, local_port, pool_index);
+ mlxsw_reg_sbpm_pack(sbpm_pl, local_port, des->pool, des->dir,
+ false, 0, 0);
return mlxsw_reg_trans_query(mlxsw_sp->core, MLXSW_REG(sbpm), sbpm_pl,
bulk_list,
mlxsw_sp_sb_pm_occ_query_cb,
@@ -254,63 +307,54 @@ static void mlxsw_sp_sb_ports_fini(struct mlxsw_sp *mlxsw_sp)
.size = _size, \
}
-static const struct mlxsw_sp_sb_pr mlxsw_sp_sb_prs_ingress[] = {
+static const struct mlxsw_sp_sb_pr mlxsw_sp_sb_prs[] = {
+ /* Ingress pools. */
MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC,
MLXSW_SP_SB_PR_INGRESS_SIZE),
MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0),
MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0),
MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC,
MLXSW_SP_SB_PR_INGRESS_MNG_SIZE),
-};
-
-#define MLXSW_SP_SB_PRS_INGRESS_LEN ARRAY_SIZE(mlxsw_sp_sb_prs_ingress)
-
-static const struct mlxsw_sp_sb_pr mlxsw_sp_sb_prs_egress[] = {
+ /* Egress pools. */
MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, MLXSW_SP_SB_PR_EGRESS_SIZE),
MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0),
MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0),
MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0),
+ MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, MLXSW_SP_SB_INFI),
};
-#define MLXSW_SP_SB_PRS_EGRESS_LEN ARRAY_SIZE(mlxsw_sp_sb_prs_egress)
+#define MLXSW_SP_SB_PRS_LEN ARRAY_SIZE(mlxsw_sp_sb_prs)
-static int __mlxsw_sp_sb_prs_init(struct mlxsw_sp *mlxsw_sp,
- enum mlxsw_reg_sbxx_dir dir,
- const struct mlxsw_sp_sb_pr *prs,
- size_t prs_len)
+static int mlxsw_sp_sb_prs_init(struct mlxsw_sp *mlxsw_sp,
+ const struct mlxsw_sp_sb_pr *prs,
+ size_t prs_len)
{
int i;
int err;
for (i = 0; i < prs_len; i++) {
- u32 size = mlxsw_sp_bytes_cells(mlxsw_sp, prs[i].size);
-
- err = mlxsw_sp_sb_pr_write(mlxsw_sp, i, dir, prs[i].mode, size);
+ u32 size = prs[i].size;
+ u32 size_cells;
+
+ if (size == MLXSW_SP_SB_INFI) {
+ err = mlxsw_sp_sb_pr_write(mlxsw_sp, i, prs[i].mode,
+ 0, true);
+ } else {
+ size_cells = mlxsw_sp_bytes_cells(mlxsw_sp, size);
+ err = mlxsw_sp_sb_pr_write(mlxsw_sp, i, prs[i].mode,
+ size_cells, false);
+ }
if (err)
return err;
}
return 0;
}
-static int mlxsw_sp_sb_prs_init(struct mlxsw_sp *mlxsw_sp)
-{
- int err;
-
- err = __mlxsw_sp_sb_prs_init(mlxsw_sp, MLXSW_REG_SBXX_DIR_INGRESS,
- mlxsw_sp_sb_prs_ingress,
- MLXSW_SP_SB_PRS_INGRESS_LEN);
- if (err)
- return err;
- return __mlxsw_sp_sb_prs_init(mlxsw_sp, MLXSW_REG_SBXX_DIR_EGRESS,
- mlxsw_sp_sb_prs_egress,
- MLXSW_SP_SB_PRS_EGRESS_LEN);
-}
-
#define MLXSW_SP_SB_CM(_min_buff, _max_buff, _pool) \
{ \
.min_buff = _min_buff, \
.max_buff = _max_buff, \
- .pool = _pool, \
+ .pool_index = _pool, \
}
static const struct mlxsw_sp_sb_cm mlxsw_sp_sb_cms_ingress[] = {
@@ -329,38 +373,38 @@ static const struct mlxsw_sp_sb_cm mlxsw_sp_sb_cms_ingress[] = {
#define MLXSW_SP_SB_CMS_INGRESS_LEN ARRAY_SIZE(mlxsw_sp_sb_cms_ingress)
static const struct mlxsw_sp_sb_cm mlxsw_sp_sb_cms_egress[] = {
- MLXSW_SP_SB_CM(1500, 9, 0),
- MLXSW_SP_SB_CM(1500, 9, 0),
- MLXSW_SP_SB_CM(1500, 9, 0),
- MLXSW_SP_SB_CM(1500, 9, 0),
- MLXSW_SP_SB_CM(1500, 9, 0),
- MLXSW_SP_SB_CM(1500, 9, 0),
- MLXSW_SP_SB_CM(1500, 9, 0),
- MLXSW_SP_SB_CM(1500, 9, 0),
- MLXSW_SP_SB_CM(0, 140000, 15),
- MLXSW_SP_SB_CM(0, 140000, 15),
- MLXSW_SP_SB_CM(0, 140000, 15),
- MLXSW_SP_SB_CM(0, 140000, 15),
- MLXSW_SP_SB_CM(0, 140000, 15),
- MLXSW_SP_SB_CM(0, 140000, 15),
- MLXSW_SP_SB_CM(0, 140000, 15),
- MLXSW_SP_SB_CM(0, 140000, 15),
- MLXSW_SP_SB_CM(1, 0xff, 0),
+ MLXSW_SP_SB_CM(1500, 9, 4),
+ MLXSW_SP_SB_CM(1500, 9, 4),
+ MLXSW_SP_SB_CM(1500, 9, 4),
+ MLXSW_SP_SB_CM(1500, 9, 4),
+ MLXSW_SP_SB_CM(1500, 9, 4),
+ MLXSW_SP_SB_CM(1500, 9, 4),
+ MLXSW_SP_SB_CM(1500, 9, 4),
+ MLXSW_SP_SB_CM(1500, 9, 4),
+ MLXSW_SP_SB_CM(0, MLXSW_SP_SB_INFI, 8),
+ MLXSW_SP_SB_CM(0, MLXSW_SP_SB_INFI, 8),
+ MLXSW_SP_SB_CM(0, MLXSW_SP_SB_INFI, 8),
+ MLXSW_SP_SB_CM(0, MLXSW_SP_SB_INFI, 8),
+ MLXSW_SP_SB_CM(0, MLXSW_SP_SB_INFI, 8),
+ MLXSW_SP_SB_CM(0, MLXSW_SP_SB_INFI, 8),
+ MLXSW_SP_SB_CM(0, MLXSW_SP_SB_INFI, 8),
+ MLXSW_SP_SB_CM(0, MLXSW_SP_SB_INFI, 8),
+ MLXSW_SP_SB_CM(1, 0xff, 4),
};
#define MLXSW_SP_SB_CMS_EGRESS_LEN ARRAY_SIZE(mlxsw_sp_sb_cms_egress)
-#define MLXSW_SP_CPU_PORT_SB_CM MLXSW_SP_SB_CM(0, 0, 0)
+#define MLXSW_SP_CPU_PORT_SB_CM MLXSW_SP_SB_CM(0, 0, 4)
static const struct mlxsw_sp_sb_cm mlxsw_sp_cpu_port_sb_cms[] = {
MLXSW_SP_CPU_PORT_SB_CM,
- MLXSW_SP_SB_CM(MLXSW_PORT_MAX_MTU, 0, 0),
- MLXSW_SP_SB_CM(MLXSW_PORT_MAX_MTU, 0, 0),
- MLXSW_SP_SB_CM(MLXSW_PORT_MAX_MTU, 0, 0),
- MLXSW_SP_SB_CM(MLXSW_PORT_MAX_MTU, 0, 0),
- MLXSW_SP_SB_CM(MLXSW_PORT_MAX_MTU, 0, 0),
+ MLXSW_SP_SB_CM(MLXSW_PORT_MAX_MTU, 0, 4),
+ MLXSW_SP_SB_CM(MLXSW_PORT_MAX_MTU, 0, 4),
+ MLXSW_SP_SB_CM(MLXSW_PORT_MAX_MTU, 0, 4),
+ MLXSW_SP_SB_CM(MLXSW_PORT_MAX_MTU, 0, 4),
+ MLXSW_SP_SB_CM(MLXSW_PORT_MAX_MTU, 0, 4),
MLXSW_SP_CPU_PORT_SB_CM,
- MLXSW_SP_SB_CM(MLXSW_PORT_MAX_MTU, 0, 0),
+ MLXSW_SP_SB_CM(MLXSW_PORT_MAX_MTU, 0, 4),
MLXSW_SP_CPU_PORT_SB_CM,
MLXSW_SP_CPU_PORT_SB_CM,
MLXSW_SP_CPU_PORT_SB_CM,
@@ -390,6 +434,14 @@ static const struct mlxsw_sp_sb_cm mlxsw_sp_cpu_port_sb_cms[] = {
#define MLXSW_SP_CPU_PORT_SB_MCS_LEN \
ARRAY_SIZE(mlxsw_sp_cpu_port_sb_cms)
+static bool
+mlxsw_sp_sb_pool_is_static(struct mlxsw_sp *mlxsw_sp, u16 pool_index)
+{
+ struct mlxsw_sp_sb_pr *pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool_index);
+
+ return pr->mode == MLXSW_REG_SBPR_MODE_STATIC;
+}
+
static int __mlxsw_sp_sb_cms_init(struct mlxsw_sp *mlxsw_sp, u8 local_port,
enum mlxsw_reg_sbxx_dir dir,
const struct mlxsw_sp_sb_cm *cms,
@@ -401,16 +453,29 @@ static int __mlxsw_sp_sb_cms_init(struct mlxsw_sp *mlxsw_sp, u8 local_port,
for (i = 0; i < cms_len; i++) {
const struct mlxsw_sp_sb_cm *cm;
u32 min_buff;
+ u32 max_buff;
if (i == 8 && dir == MLXSW_REG_SBXX_DIR_INGRESS)
continue; /* PG number 8 does not exist, skip it */
cm = &cms[i];
- /* All pools are initialized using dynamic thresholds,
- * therefore 'max_buff' isn't specified in cells.
- */
+ if (WARN_ON(mlxsw_sp_sb_pool_dess[cm->pool_index].dir != dir))
+ continue;
+
min_buff = mlxsw_sp_bytes_cells(mlxsw_sp, cm->min_buff);
- err = mlxsw_sp_sb_cm_write(mlxsw_sp, local_port, i, dir,
- min_buff, cm->max_buff, cm->pool);
+ max_buff = cm->max_buff;
+ if (max_buff == MLXSW_SP_SB_INFI) {
+ err = mlxsw_sp_sb_cm_write(mlxsw_sp, local_port, i,
+ min_buff, 0,
+ true, cm->pool_index);
+ } else {
+ if (mlxsw_sp_sb_pool_is_static(mlxsw_sp,
+ cm->pool_index))
+ max_buff = mlxsw_sp_bytes_cells(mlxsw_sp,
+ max_buff);
+ err = mlxsw_sp_sb_cm_write(mlxsw_sp, local_port, i,
+ min_buff, max_buff,
+ false, cm->pool_index);
+ }
if (err)
return err;
}
@@ -448,91 +513,74 @@ static int mlxsw_sp_cpu_port_sb_cms_init(struct mlxsw_sp *mlxsw_sp)
.max_buff = _max_buff, \
}
-static const struct mlxsw_sp_sb_pm mlxsw_sp_sb_pms_ingress[] = {
+static const struct mlxsw_sp_sb_pm mlxsw_sp_sb_pms[] = {
+ /* Ingress pools. */
MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MAX),
MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN),
MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN),
MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MAX),
-};
-
-#define MLXSW_SP_SB_PMS_INGRESS_LEN ARRAY_SIZE(mlxsw_sp_sb_pms_ingress)
-
-static const struct mlxsw_sp_sb_pm mlxsw_sp_sb_pms_egress[] = {
+ /* Egress pools. */
MLXSW_SP_SB_PM(0, 7),
MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN),
MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN),
MLXSW_SP_SB_PM(0, MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN),
+ MLXSW_SP_SB_PM(10000, 90000),
};
-#define MLXSW_SP_SB_PMS_EGRESS_LEN ARRAY_SIZE(mlxsw_sp_sb_pms_egress)
+#define MLXSW_SP_SB_PMS_LEN ARRAY_SIZE(mlxsw_sp_sb_pms)
-static int __mlxsw_sp_port_sb_pms_init(struct mlxsw_sp *mlxsw_sp, u8 local_port,
- enum mlxsw_reg_sbxx_dir dir,
- const struct mlxsw_sp_sb_pm *pms,
- size_t pms_len)
+static int mlxsw_sp_port_sb_pms_init(struct mlxsw_sp_port *mlxsw_sp_port)
{
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
int i;
int err;
- for (i = 0; i < pms_len; i++) {
- const struct mlxsw_sp_sb_pm *pm;
+ for (i = 0; i < MLXSW_SP_SB_PMS_LEN; i++) {
+ const struct mlxsw_sp_sb_pm *pm = &mlxsw_sp_sb_pms[i];
+ u32 max_buff;
+ u32 min_buff;
- pm = &pms[i];
- err = mlxsw_sp_sb_pm_write(mlxsw_sp, local_port, i, dir,
- pm->min_buff, pm->max_buff);
+ min_buff = mlxsw_sp_bytes_cells(mlxsw_sp, pm->min_buff);
+ max_buff = pm->max_buff;
+ if (mlxsw_sp_sb_pool_is_static(mlxsw_sp, i))
+ max_buff = mlxsw_sp_bytes_cells(mlxsw_sp, max_buff);
+ err = mlxsw_sp_sb_pm_write(mlxsw_sp, mlxsw_sp_port->local_port,
+ i, min_buff, max_buff);
if (err)
return err;
}
return 0;
}
-static int mlxsw_sp_port_sb_pms_init(struct mlxsw_sp_port *mlxsw_sp_port)
-{
- int err;
-
- err = __mlxsw_sp_port_sb_pms_init(mlxsw_sp_port->mlxsw_sp,
- mlxsw_sp_port->local_port,
- MLXSW_REG_SBXX_DIR_INGRESS,
- mlxsw_sp_sb_pms_ingress,
- MLXSW_SP_SB_PMS_INGRESS_LEN);
- if (err)
- return err;
- return __mlxsw_sp_port_sb_pms_init(mlxsw_sp_port->mlxsw_sp,
- mlxsw_sp_port->local_port,
- MLXSW_REG_SBXX_DIR_EGRESS,
- mlxsw_sp_sb_pms_egress,
- MLXSW_SP_SB_PMS_EGRESS_LEN);
-}
-
struct mlxsw_sp_sb_mm {
u32 min_buff;
u32 max_buff;
- u8 pool;
+ u16 pool_index;
};
#define MLXSW_SP_SB_MM(_min_buff, _max_buff, _pool) \
{ \
.min_buff = _min_buff, \
.max_buff = _max_buff, \
- .pool = _pool, \
+ .pool_index = _pool, \
}
static const struct mlxsw_sp_sb_mm mlxsw_sp_sb_mms[] = {
- MLXSW_SP_SB_MM(20000, 0xff, 0),
- MLXSW_SP_SB_MM(20000, 0xff, 0),
- MLXSW_SP_SB_MM(20000, 0xff, 0),
- MLXSW_SP_SB_MM(20000, 0xff, 0),
- MLXSW_SP_SB_MM(20000, 0xff, 0),
- MLXSW_SP_SB_MM(20000, 0xff, 0),
- MLXSW_SP_SB_MM(20000, 0xff, 0),
- MLXSW_SP_SB_MM(20000, 0xff, 0),
- MLXSW_SP_SB_MM(20000, 0xff, 0),
- MLXSW_SP_SB_MM(20000, 0xff, 0),
- MLXSW_SP_SB_MM(20000, 0xff, 0),
- MLXSW_SP_SB_MM(20000, 0xff, 0),
- MLXSW_SP_SB_MM(20000, 0xff, 0),
- MLXSW_SP_SB_MM(20000, 0xff, 0),
- MLXSW_SP_SB_MM(20000, 0xff, 0),
+ MLXSW_SP_SB_MM(0, 6, 4),
+ MLXSW_SP_SB_MM(0, 6, 4),
+ MLXSW_SP_SB_MM(0, 6, 4),
+ MLXSW_SP_SB_MM(0, 6, 4),
+ MLXSW_SP_SB_MM(0, 6, 4),
+ MLXSW_SP_SB_MM(0, 6, 4),
+ MLXSW_SP_SB_MM(0, 6, 4),
+ MLXSW_SP_SB_MM(0, 6, 4),
+ MLXSW_SP_SB_MM(0, 6, 4),
+ MLXSW_SP_SB_MM(0, 6, 4),
+ MLXSW_SP_SB_MM(0, 6, 4),
+ MLXSW_SP_SB_MM(0, 6, 4),
+ MLXSW_SP_SB_MM(0, 6, 4),
+ MLXSW_SP_SB_MM(0, 6, 4),
+ MLXSW_SP_SB_MM(0, 6, 4),
};
#define MLXSW_SP_SB_MMS_LEN ARRAY_SIZE(mlxsw_sp_sb_mms)
@@ -544,16 +592,18 @@ static int mlxsw_sp_sb_mms_init(struct mlxsw_sp *mlxsw_sp)
int err;
for (i = 0; i < MLXSW_SP_SB_MMS_LEN; i++) {
+ const struct mlxsw_sp_sb_pool_des *des;
const struct mlxsw_sp_sb_mm *mc;
u32 min_buff;
mc = &mlxsw_sp_sb_mms[i];
- /* All pools are initialized using dynamic thresholds,
- * therefore 'max_buff' isn't specified in cells.
+ des = &mlxsw_sp_sb_pool_dess[mc->pool_index];
+ /* All pools used by sb_mm's are initialized using dynamic
+ * thresholds, therefore 'max_buff' isn't specified in cells.
*/
min_buff = mlxsw_sp_bytes_cells(mlxsw_sp, mc->min_buff);
mlxsw_reg_sbmm_pack(sbmm_pl, i, min_buff, mc->max_buff,
- mc->pool);
+ des->pool);
err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbmm), sbmm_pl);
if (err)
return err;
@@ -561,9 +611,24 @@ static int mlxsw_sp_sb_mms_init(struct mlxsw_sp *mlxsw_sp)
return 0;
}
+static void mlxsw_sp_pool_count(u16 *p_ingress_len, u16 *p_egress_len)
+{
+ int i;
+
+ for (i = 0; i < MLXSW_SP_SB_POOL_DESS_LEN; ++i)
+ if (mlxsw_sp_sb_pool_dess[i].dir == MLXSW_REG_SBXX_DIR_EGRESS)
+ goto out;
+ WARN(1, "No egress pools\n");
+
+out:
+ *p_ingress_len = i;
+ *p_egress_len = MLXSW_SP_SB_POOL_DESS_LEN - i;
+}
+
int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp)
{
- u64 sb_size;
+ u16 ing_pool_count;
+ u16 eg_pool_count;
int err;
if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, CELL_SIZE))
@@ -571,17 +636,19 @@ int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp)
if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_BUFFER_SIZE))
return -EIO;
- sb_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_BUFFER_SIZE);
mlxsw_sp->sb = kzalloc(sizeof(*mlxsw_sp->sb), GFP_KERNEL);
if (!mlxsw_sp->sb)
return -ENOMEM;
mlxsw_sp->sb->cell_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, CELL_SIZE);
+ mlxsw_sp->sb->sb_size = MLXSW_CORE_RES_GET(mlxsw_sp->core,
+ MAX_BUFFER_SIZE);
err = mlxsw_sp_sb_ports_init(mlxsw_sp);
if (err)
goto err_sb_ports_init;
- err = mlxsw_sp_sb_prs_init(mlxsw_sp);
+ err = mlxsw_sp_sb_prs_init(mlxsw_sp, mlxsw_sp_sb_prs,
+ MLXSW_SP_SB_PRS_LEN);
if (err)
goto err_sb_prs_init;
err = mlxsw_sp_cpu_port_sb_cms_init(mlxsw_sp);
@@ -590,11 +657,13 @@ int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp)
err = mlxsw_sp_sb_mms_init(mlxsw_sp);
if (err)
goto err_sb_mms_init;
- err = devlink_sb_register(priv_to_devlink(mlxsw_sp->core), 0, sb_size,
- MLXSW_SP_SB_POOL_COUNT,
- MLXSW_SP_SB_POOL_COUNT,
- MLXSW_SP_SB_TC_COUNT,
- MLXSW_SP_SB_TC_COUNT);
+ mlxsw_sp_pool_count(&ing_pool_count, &eg_pool_count);
+ err = devlink_sb_register(priv_to_devlink(mlxsw_sp->core), 0,
+ mlxsw_sp->sb->sb_size,
+ ing_pool_count,
+ eg_pool_count,
+ MLXSW_SP_SB_ING_TC_COUNT,
+ MLXSW_SP_SB_EG_TC_COUNT);
if (err)
goto err_devlink_sb_register;
@@ -632,36 +701,15 @@ int mlxsw_sp_port_buffers_init(struct mlxsw_sp_port *mlxsw_sp_port)
return err;
}
-static u8 pool_get(u16 pool_index)
-{
- return pool_index % MLXSW_SP_SB_POOL_COUNT;
-}
-
-static u16 pool_index_get(u8 pool, enum mlxsw_reg_sbxx_dir dir)
-{
- u16 pool_index;
-
- pool_index = pool;
- if (dir == MLXSW_REG_SBXX_DIR_EGRESS)
- pool_index += MLXSW_SP_SB_POOL_COUNT;
- return pool_index;
-}
-
-static enum mlxsw_reg_sbxx_dir dir_get(u16 pool_index)
-{
- return pool_index < MLXSW_SP_SB_POOL_COUNT ?
- MLXSW_REG_SBXX_DIR_INGRESS : MLXSW_REG_SBXX_DIR_EGRESS;
-}
-
int mlxsw_sp_sb_pool_get(struct mlxsw_core *mlxsw_core,
unsigned int sb_index, u16 pool_index,
struct devlink_sb_pool_info *pool_info)
{
+ enum mlxsw_reg_sbxx_dir dir = mlxsw_sp_sb_pool_dess[pool_index].dir;
struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
- u8 pool = pool_get(pool_index);
- enum mlxsw_reg_sbxx_dir dir = dir_get(pool_index);
- struct mlxsw_sp_sb_pr *pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool, dir);
+ struct mlxsw_sp_sb_pr *pr;
+ pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool_index);
pool_info->pool_type = (enum devlink_sb_pool_type) dir;
pool_info->size = mlxsw_sp_cells_bytes(mlxsw_sp, pr->size);
pool_info->threshold_type = (enum devlink_sb_threshold_type) pr->mode;
@@ -674,34 +722,32 @@ int mlxsw_sp_sb_pool_set(struct mlxsw_core *mlxsw_core,
{
struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
u32 pool_size = mlxsw_sp_bytes_cells(mlxsw_sp, size);
- u8 pool = pool_get(pool_index);
- enum mlxsw_reg_sbxx_dir dir = dir_get(pool_index);
enum mlxsw_reg_sbpr_mode mode;
if (size > MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_BUFFER_SIZE))
return -EINVAL;
mode = (enum mlxsw_reg_sbpr_mode) threshold_type;
- return mlxsw_sp_sb_pr_write(mlxsw_sp, pool, dir, mode, pool_size);
+ return mlxsw_sp_sb_pr_write(mlxsw_sp, pool_index, mode,
+ pool_size, false);
}
#define MLXSW_SP_SB_THRESHOLD_TO_ALPHA_OFFSET (-2) /* 3->1, 16->14 */
-static u32 mlxsw_sp_sb_threshold_out(struct mlxsw_sp *mlxsw_sp, u8 pool,
- enum mlxsw_reg_sbxx_dir dir, u32 max_buff)
+static u32 mlxsw_sp_sb_threshold_out(struct mlxsw_sp *mlxsw_sp, u16 pool_index,
+ u32 max_buff)
{
- struct mlxsw_sp_sb_pr *pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool, dir);
+ struct mlxsw_sp_sb_pr *pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool_index);
if (pr->mode == MLXSW_REG_SBPR_MODE_DYNAMIC)
return max_buff - MLXSW_SP_SB_THRESHOLD_TO_ALPHA_OFFSET;
return mlxsw_sp_cells_bytes(mlxsw_sp, max_buff);
}
-static int mlxsw_sp_sb_threshold_in(struct mlxsw_sp *mlxsw_sp, u8 pool,
- enum mlxsw_reg_sbxx_dir dir, u32 threshold,
- u32 *p_max_buff)
+static int mlxsw_sp_sb_threshold_in(struct mlxsw_sp *mlxsw_sp, u16 pool_index,
+ u32 threshold, u32 *p_max_buff)
{
- struct mlxsw_sp_sb_pr *pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool, dir);
+ struct mlxsw_sp_sb_pr *pr = mlxsw_sp_sb_pr_get(mlxsw_sp, pool_index);
if (pr->mode == MLXSW_REG_SBPR_MODE_DYNAMIC) {
int val;
@@ -725,12 +771,10 @@ int mlxsw_sp_sb_port_pool_get(struct mlxsw_core_port *mlxsw_core_port,
mlxsw_core_port_driver_priv(mlxsw_core_port);
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
u8 local_port = mlxsw_sp_port->local_port;
- u8 pool = pool_get(pool_index);
- enum mlxsw_reg_sbxx_dir dir = dir_get(pool_index);
struct mlxsw_sp_sb_pm *pm = mlxsw_sp_sb_pm_get(mlxsw_sp, local_port,
- pool, dir);
+ pool_index);
- *p_threshold = mlxsw_sp_sb_threshold_out(mlxsw_sp, pool, dir,
+ *p_threshold = mlxsw_sp_sb_threshold_out(mlxsw_sp, pool_index,
pm->max_buff);
return 0;
}
@@ -743,17 +787,15 @@ int mlxsw_sp_sb_port_pool_set(struct mlxsw_core_port *mlxsw_core_port,
mlxsw_core_port_driver_priv(mlxsw_core_port);
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
u8 local_port = mlxsw_sp_port->local_port;
- u8 pool = pool_get(pool_index);
- enum mlxsw_reg_sbxx_dir dir = dir_get(pool_index);
u32 max_buff;
int err;
- err = mlxsw_sp_sb_threshold_in(mlxsw_sp, pool, dir,
+ err = mlxsw_sp_sb_threshold_in(mlxsw_sp, pool_index,
threshold, &max_buff);
if (err)
return err;
- return mlxsw_sp_sb_pm_write(mlxsw_sp, local_port, pool, dir,
+ return mlxsw_sp_sb_pm_write(mlxsw_sp, local_port, pool_index,
0, max_buff);
}
@@ -771,9 +813,9 @@ int mlxsw_sp_sb_tc_pool_bind_get(struct mlxsw_core_port *mlxsw_core_port,
struct mlxsw_sp_sb_cm *cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port,
pg_buff, dir);
- *p_threshold = mlxsw_sp_sb_threshold_out(mlxsw_sp, cm->pool, dir,
+ *p_threshold = mlxsw_sp_sb_threshold_out(mlxsw_sp, cm->pool_index,
cm->max_buff);
- *p_pool_index = pool_index_get(cm->pool, dir);
+ *p_pool_index = cm->pool_index;
return 0;
}
@@ -788,24 +830,24 @@ int mlxsw_sp_sb_tc_pool_bind_set(struct mlxsw_core_port *mlxsw_core_port,
u8 local_port = mlxsw_sp_port->local_port;
u8 pg_buff = tc_index;
enum mlxsw_reg_sbxx_dir dir = (enum mlxsw_reg_sbxx_dir) pool_type;
- u8 pool = pool_get(pool_index);
u32 max_buff;
int err;
- if (dir != dir_get(pool_index))
+ if (dir != mlxsw_sp_sb_pool_dess[pool_index].dir)
return -EINVAL;
- err = mlxsw_sp_sb_threshold_in(mlxsw_sp, pool, dir,
+ err = mlxsw_sp_sb_threshold_in(mlxsw_sp, pool_index,
threshold, &max_buff);
if (err)
return err;
- return mlxsw_sp_sb_cm_write(mlxsw_sp, local_port, pg_buff, dir,
- 0, max_buff, pool);
+ return mlxsw_sp_sb_cm_write(mlxsw_sp, local_port, pg_buff,
+ 0, max_buff, false, pool_index);
}
#define MASKED_COUNT_MAX \
- (MLXSW_REG_SBSR_REC_MAX_COUNT / (MLXSW_SP_SB_TC_COUNT * 2))
+ (MLXSW_REG_SBSR_REC_MAX_COUNT / \
+ (MLXSW_SP_SB_ING_TC_COUNT + MLXSW_SP_SB_EG_TC_COUNT))
struct mlxsw_sp_sb_sr_occ_query_cb_ctx {
u8 masked_count;
@@ -831,7 +873,7 @@ static void mlxsw_sp_sb_sr_occ_query_cb(struct mlxsw_core *mlxsw_core,
local_port < mlxsw_core_max_ports(mlxsw_core); local_port++) {
if (!mlxsw_sp->ports[local_port])
continue;
- for (i = 0; i < MLXSW_SP_SB_TC_COUNT; i++) {
+ for (i = 0; i < MLXSW_SP_SB_ING_TC_COUNT; i++) {
cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port, i,
MLXSW_REG_SBXX_DIR_INGRESS);
mlxsw_reg_sbsr_rec_unpack(sbsr_pl, rec_index++,
@@ -845,7 +887,7 @@ static void mlxsw_sp_sb_sr_occ_query_cb(struct mlxsw_core *mlxsw_core,
local_port < mlxsw_core_max_ports(mlxsw_core); local_port++) {
if (!mlxsw_sp->ports[local_port])
continue;
- for (i = 0; i < MLXSW_SP_SB_TC_COUNT; i++) {
+ for (i = 0; i < MLXSW_SP_SB_EG_TC_COUNT; i++) {
cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port, i,
MLXSW_REG_SBXX_DIR_EGRESS);
mlxsw_reg_sbsr_rec_unpack(sbsr_pl, rec_index++,
@@ -880,23 +922,17 @@ next_batch:
local_port_1 = local_port;
masked_count = 0;
mlxsw_reg_sbsr_pack(sbsr_pl, false);
- for (i = 0; i < MLXSW_SP_SB_TC_COUNT; i++) {
+ for (i = 0; i < MLXSW_SP_SB_ING_TC_COUNT; i++)
mlxsw_reg_sbsr_pg_buff_mask_set(sbsr_pl, i, 1);
+ for (i = 0; i < MLXSW_SP_SB_EG_TC_COUNT; i++)
mlxsw_reg_sbsr_tclass_mask_set(sbsr_pl, i, 1);
- }
for (; local_port < mlxsw_core_max_ports(mlxsw_core); local_port++) {
if (!mlxsw_sp->ports[local_port])
continue;
mlxsw_reg_sbsr_ingress_port_mask_set(sbsr_pl, local_port, 1);
mlxsw_reg_sbsr_egress_port_mask_set(sbsr_pl, local_port, 1);
- for (i = 0; i < MLXSW_SP_SB_POOL_COUNT; i++) {
- err = mlxsw_sp_sb_pm_occ_query(mlxsw_sp, local_port, i,
- MLXSW_REG_SBXX_DIR_INGRESS,
- &bulk_list);
- if (err)
- goto out;
+ for (i = 0; i < MLXSW_SP_SB_POOL_DESS_LEN; i++) {
err = mlxsw_sp_sb_pm_occ_query(mlxsw_sp, local_port, i,
- MLXSW_REG_SBXX_DIR_EGRESS,
&bulk_list);
if (err)
goto out;
@@ -945,23 +981,17 @@ next_batch:
local_port++;
masked_count = 0;
mlxsw_reg_sbsr_pack(sbsr_pl, true);
- for (i = 0; i < MLXSW_SP_SB_TC_COUNT; i++) {
+ for (i = 0; i < MLXSW_SP_SB_ING_TC_COUNT; i++)
mlxsw_reg_sbsr_pg_buff_mask_set(sbsr_pl, i, 1);
+ for (i = 0; i < MLXSW_SP_SB_EG_TC_COUNT; i++)
mlxsw_reg_sbsr_tclass_mask_set(sbsr_pl, i, 1);
- }
for (; local_port < mlxsw_core_max_ports(mlxsw_core); local_port++) {
if (!mlxsw_sp->ports[local_port])
continue;
mlxsw_reg_sbsr_ingress_port_mask_set(sbsr_pl, local_port, 1);
mlxsw_reg_sbsr_egress_port_mask_set(sbsr_pl, local_port, 1);
- for (i = 0; i < MLXSW_SP_SB_POOL_COUNT; i++) {
- err = mlxsw_sp_sb_pm_occ_clear(mlxsw_sp, local_port, i,
- MLXSW_REG_SBXX_DIR_INGRESS,
- &bulk_list);
- if (err)
- goto out;
+ for (i = 0; i < MLXSW_SP_SB_POOL_DESS_LEN; i++) {
err = mlxsw_sp_sb_pm_occ_clear(mlxsw_sp, local_port, i,
- MLXSW_REG_SBXX_DIR_EGRESS,
&bulk_list);
if (err)
goto out;
@@ -994,10 +1024,8 @@ int mlxsw_sp_sb_occ_port_pool_get(struct mlxsw_core_port *mlxsw_core_port,
mlxsw_core_port_driver_priv(mlxsw_core_port);
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
u8 local_port = mlxsw_sp_port->local_port;
- u8 pool = pool_get(pool_index);
- enum mlxsw_reg_sbxx_dir dir = dir_get(pool_index);
struct mlxsw_sp_sb_pm *pm = mlxsw_sp_sb_pm_get(mlxsw_sp, local_port,
- pool, dir);
+ pool_index);
*p_cur = mlxsw_sp_cells_bytes(mlxsw_sp, pm->occ.cur);
*p_max = mlxsw_sp_cells_bytes(mlxsw_sp, pm->occ.max);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c
index 715d24ff937e..a3db033d7399 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c
@@ -6,6 +6,7 @@
#include <linux/if_vlan.h>
#include <linux/if_bridge.h>
#include <linux/netdevice.h>
+#include <linux/rhashtable.h>
#include <linux/rtnetlink.h>
#include "spectrum.h"
@@ -14,6 +15,7 @@
struct mlxsw_sp_fid_family;
struct mlxsw_sp_fid_core {
+ struct rhashtable vni_ht;
struct mlxsw_sp_fid_family *fid_family_arr[MLXSW_SP_FID_TYPE_MAX];
unsigned int *port_fid_mappings;
};
@@ -24,6 +26,12 @@ struct mlxsw_sp_fid {
unsigned int ref_count;
u16 fid_index;
struct mlxsw_sp_fid_family *fid_family;
+
+ struct rhash_head vni_ht_node;
+ __be32 vni;
+ u32 nve_flood_index;
+ u8 vni_valid:1,
+ nve_flood_index_valid:1;
};
struct mlxsw_sp_fid_8021q {
@@ -36,6 +44,12 @@ struct mlxsw_sp_fid_8021d {
int br_ifindex;
};
+static const struct rhashtable_params mlxsw_sp_fid_vni_ht_params = {
+ .key_len = sizeof_field(struct mlxsw_sp_fid, vni),
+ .key_offset = offsetof(struct mlxsw_sp_fid, vni),
+ .head_offset = offsetof(struct mlxsw_sp_fid, vni_ht_node),
+};
+
struct mlxsw_sp_flood_table {
enum mlxsw_sp_flood_type packet_type;
enum mlxsw_reg_sfgc_bridge_type bridge_type;
@@ -56,6 +70,11 @@ struct mlxsw_sp_fid_ops {
struct mlxsw_sp_port *port, u16 vid);
void (*port_vid_unmap)(struct mlxsw_sp_fid *fid,
struct mlxsw_sp_port *port, u16 vid);
+ int (*vni_set)(struct mlxsw_sp_fid *fid, __be32 vni);
+ void (*vni_clear)(struct mlxsw_sp_fid *fid);
+ int (*nve_flood_index_set)(struct mlxsw_sp_fid *fid,
+ u32 nve_flood_index);
+ void (*nve_flood_index_clear)(struct mlxsw_sp_fid *fid);
};
struct mlxsw_sp_fid_family {
@@ -94,6 +113,117 @@ static const int *mlxsw_sp_packet_type_sfgc_types[] = {
[MLXSW_SP_FLOOD_TYPE_MC] = mlxsw_sp_sfgc_mc_packet_types,
};
+struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_vni(struct mlxsw_sp *mlxsw_sp,
+ __be32 vni)
+{
+ struct mlxsw_sp_fid *fid;
+
+ fid = rhashtable_lookup_fast(&mlxsw_sp->fid_core->vni_ht, &vni,
+ mlxsw_sp_fid_vni_ht_params);
+ if (fid)
+ fid->ref_count++;
+
+ return fid;
+}
+
+int mlxsw_sp_fid_vni(const struct mlxsw_sp_fid *fid, __be32 *vni)
+{
+ if (!fid->vni_valid)
+ return -EINVAL;
+
+ *vni = fid->vni;
+
+ return 0;
+}
+
+int mlxsw_sp_fid_nve_flood_index_set(struct mlxsw_sp_fid *fid,
+ u32 nve_flood_index)
+{
+ struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
+ const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
+ int err;
+
+ if (WARN_ON(!ops->nve_flood_index_set || fid->nve_flood_index_valid))
+ return -EINVAL;
+
+ err = ops->nve_flood_index_set(fid, nve_flood_index);
+ if (err)
+ return err;
+
+ fid->nve_flood_index = nve_flood_index;
+ fid->nve_flood_index_valid = true;
+
+ return 0;
+}
+
+void mlxsw_sp_fid_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
+{
+ struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
+ const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
+
+ if (WARN_ON(!ops->nve_flood_index_clear || !fid->nve_flood_index_valid))
+ return;
+
+ fid->nve_flood_index_valid = false;
+ ops->nve_flood_index_clear(fid);
+}
+
+bool mlxsw_sp_fid_nve_flood_index_is_set(const struct mlxsw_sp_fid *fid)
+{
+ return fid->nve_flood_index_valid;
+}
+
+int mlxsw_sp_fid_vni_set(struct mlxsw_sp_fid *fid, __be32 vni)
+{
+ struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
+ const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
+ struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
+ int err;
+
+ if (WARN_ON(!ops->vni_set || fid->vni_valid))
+ return -EINVAL;
+
+ fid->vni = vni;
+ err = rhashtable_lookup_insert_fast(&mlxsw_sp->fid_core->vni_ht,
+ &fid->vni_ht_node,
+ mlxsw_sp_fid_vni_ht_params);
+ if (err)
+ return err;
+
+ err = ops->vni_set(fid, vni);
+ if (err)
+ goto err_vni_set;
+
+ fid->vni_valid = true;
+
+ return 0;
+
+err_vni_set:
+ rhashtable_remove_fast(&mlxsw_sp->fid_core->vni_ht, &fid->vni_ht_node,
+ mlxsw_sp_fid_vni_ht_params);
+ return err;
+}
+
+void mlxsw_sp_fid_vni_clear(struct mlxsw_sp_fid *fid)
+{
+ struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
+ const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
+ struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
+
+ if (WARN_ON(!ops->vni_clear || !fid->vni_valid))
+ return;
+
+ fid->vni_valid = false;
+ ops->vni_clear(fid);
+ rhashtable_remove_fast(&mlxsw_sp->fid_core->vni_ht, &fid->vni_ht_node,
+ mlxsw_sp_fid_vni_ht_params);
+}
+
+bool mlxsw_sp_fid_vni_is_set(const struct mlxsw_sp_fid *fid)
+{
+ return fid->vni_valid;
+}
+
static const struct mlxsw_sp_flood_table *
mlxsw_sp_fid_flood_table_lookup(const struct mlxsw_sp_fid *fid,
enum mlxsw_sp_flood_type packet_type)
@@ -217,6 +347,21 @@ static int mlxsw_sp_fid_op(struct mlxsw_sp *mlxsw_sp, u16 fid_index,
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl);
}
+static int mlxsw_sp_fid_vni_op(struct mlxsw_sp *mlxsw_sp, u16 fid_index,
+ __be32 vni, bool vni_valid, u32 nve_flood_index,
+ bool nve_flood_index_valid)
+{
+ char sfmr_pl[MLXSW_REG_SFMR_LEN];
+
+ mlxsw_reg_sfmr_pack(sfmr_pl, MLXSW_REG_SFMR_OP_CREATE_FID, fid_index,
+ 0);
+ mlxsw_reg_sfmr_vv_set(sfmr_pl, vni_valid);
+ mlxsw_reg_sfmr_vni_set(sfmr_pl, be32_to_cpu(vni));
+ mlxsw_reg_sfmr_vtfp_set(sfmr_pl, nve_flood_index_valid);
+ mlxsw_reg_sfmr_nve_tunnel_flood_ptr_set(sfmr_pl, nve_flood_index);
+ return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl);
+}
+
static int mlxsw_sp_fid_vid_map(struct mlxsw_sp *mlxsw_sp, u16 fid_index,
u16 vid, bool valid)
{
@@ -393,6 +538,8 @@ static int mlxsw_sp_fid_8021d_configure(struct mlxsw_sp_fid *fid)
static void mlxsw_sp_fid_8021d_deconfigure(struct mlxsw_sp_fid *fid)
{
+ if (fid->vni_valid)
+ mlxsw_sp_nve_fid_disable(fid->fid_family->mlxsw_sp, fid);
mlxsw_sp_fid_op(fid->fid_family->mlxsw_sp, fid->fid_index, 0, false);
}
@@ -531,6 +678,41 @@ mlxsw_sp_fid_8021d_port_vid_unmap(struct mlxsw_sp_fid *fid,
mlxsw_sp_port->local_port, vid, false);
}
+static int mlxsw_sp_fid_8021d_vni_set(struct mlxsw_sp_fid *fid, __be32 vni)
+{
+ struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
+
+ return mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index, vni,
+ true, fid->nve_flood_index,
+ fid->nve_flood_index_valid);
+}
+
+static void mlxsw_sp_fid_8021d_vni_clear(struct mlxsw_sp_fid *fid)
+{
+ struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
+
+ mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index, 0, false,
+ fid->nve_flood_index, fid->nve_flood_index_valid);
+}
+
+static int mlxsw_sp_fid_8021d_nve_flood_index_set(struct mlxsw_sp_fid *fid,
+ u32 nve_flood_index)
+{
+ struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
+
+ return mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index,
+ fid->vni, fid->vni_valid, nve_flood_index,
+ true);
+}
+
+static void mlxsw_sp_fid_8021d_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
+{
+ struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
+
+ mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index, fid->vni,
+ fid->vni_valid, 0, false);
+}
+
static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = {
.setup = mlxsw_sp_fid_8021d_setup,
.configure = mlxsw_sp_fid_8021d_configure,
@@ -540,6 +722,10 @@ static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = {
.flood_index = mlxsw_sp_fid_8021d_flood_index,
.port_vid_map = mlxsw_sp_fid_8021d_port_vid_map,
.port_vid_unmap = mlxsw_sp_fid_8021d_port_vid_unmap,
+ .vni_set = mlxsw_sp_fid_8021d_vni_set,
+ .vni_clear = mlxsw_sp_fid_8021d_vni_clear,
+ .nve_flood_index_set = mlxsw_sp_fid_8021d_nve_flood_index_set,
+ .nve_flood_index_clear = mlxsw_sp_fid_8021d_nve_flood_index_clear,
};
static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021d_flood_tables[] = {
@@ -708,14 +894,12 @@ static const struct mlxsw_sp_fid_family *mlxsw_sp_fid_family_arr[] = {
[MLXSW_SP_FID_TYPE_DUMMY] = &mlxsw_sp_fid_dummy_family,
};
-static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp,
- enum mlxsw_sp_fid_type type,
- const void *arg)
+static struct mlxsw_sp_fid *mlxsw_sp_fid_lookup(struct mlxsw_sp *mlxsw_sp,
+ enum mlxsw_sp_fid_type type,
+ const void *arg)
{
struct mlxsw_sp_fid_family *fid_family;
struct mlxsw_sp_fid *fid;
- u16 fid_index;
- int err;
fid_family = mlxsw_sp->fid_core->fid_family_arr[type];
list_for_each_entry(fid, &fid_family->fids_list, list) {
@@ -725,6 +909,23 @@ static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp,
return fid;
}
+ return NULL;
+}
+
+static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp,
+ enum mlxsw_sp_fid_type type,
+ const void *arg)
+{
+ struct mlxsw_sp_fid_family *fid_family;
+ struct mlxsw_sp_fid *fid;
+ u16 fid_index;
+ int err;
+
+ fid = mlxsw_sp_fid_lookup(mlxsw_sp, type, arg);
+ if (fid)
+ return fid;
+
+ fid_family = mlxsw_sp->fid_core->fid_family_arr[type];
fid = kzalloc(fid_family->fid_size, GFP_KERNEL);
if (!fid)
return ERR_PTR(-ENOMEM);
@@ -784,6 +985,13 @@ struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_get(struct mlxsw_sp *mlxsw_sp,
return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D, &br_ifindex);
}
+struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_lookup(struct mlxsw_sp *mlxsw_sp,
+ int br_ifindex)
+{
+ return mlxsw_sp_fid_lookup(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D,
+ &br_ifindex);
+}
+
struct mlxsw_sp_fid *mlxsw_sp_fid_rfid_get(struct mlxsw_sp *mlxsw_sp,
u16 rif_index)
{
@@ -918,6 +1126,10 @@ int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp)
return -ENOMEM;
mlxsw_sp->fid_core = fid_core;
+ err = rhashtable_init(&fid_core->vni_ht, &mlxsw_sp_fid_vni_ht_params);
+ if (err)
+ goto err_rhashtable_init;
+
fid_core->port_fid_mappings = kcalloc(max_ports, sizeof(unsigned int),
GFP_KERNEL);
if (!fid_core->port_fid_mappings) {
@@ -944,6 +1156,8 @@ err_fid_ops_register:
}
kfree(fid_core->port_fid_mappings);
err_alloc_port_fid_mappings:
+ rhashtable_destroy(&fid_core->vni_ht);
+err_rhashtable_init:
kfree(fid_core);
return err;
}
@@ -957,5 +1171,6 @@ void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp)
mlxsw_sp_fid_family_unregister(mlxsw_sp,
fid_core->fid_family_arr[i]);
kfree(fid_core->port_fid_mappings);
+ rhashtable_destroy(&fid_core->vni_ht);
kfree(fid_core);
}
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c
new file mode 100644
index 000000000000..ad06d9969bc1
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c
@@ -0,0 +1,982 @@
+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+/* Copyright (c) 2018 Mellanox Technologies. All rights reserved */
+
+#include <linux/err.h>
+#include <linux/gfp.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/slab.h>
+#include <net/inet_ecn.h>
+#include <net/ipv6.h>
+
+#include "reg.h"
+#include "spectrum.h"
+#include "spectrum_nve.h"
+
+const struct mlxsw_sp_nve_ops *mlxsw_sp1_nve_ops_arr[] = {
+ [MLXSW_SP_NVE_TYPE_VXLAN] = &mlxsw_sp1_nve_vxlan_ops,
+};
+
+const struct mlxsw_sp_nve_ops *mlxsw_sp2_nve_ops_arr[] = {
+ [MLXSW_SP_NVE_TYPE_VXLAN] = &mlxsw_sp2_nve_vxlan_ops,
+};
+
+struct mlxsw_sp_nve_mc_entry;
+struct mlxsw_sp_nve_mc_record;
+struct mlxsw_sp_nve_mc_list;
+
+struct mlxsw_sp_nve_mc_record_ops {
+ enum mlxsw_reg_tnumt_record_type type;
+ int (*entry_add)(struct mlxsw_sp_nve_mc_record *mc_record,
+ struct mlxsw_sp_nve_mc_entry *mc_entry,
+ const union mlxsw_sp_l3addr *addr);
+ void (*entry_del)(const struct mlxsw_sp_nve_mc_record *mc_record,
+ const struct mlxsw_sp_nve_mc_entry *mc_entry);
+ void (*entry_set)(const struct mlxsw_sp_nve_mc_record *mc_record,
+ const struct mlxsw_sp_nve_mc_entry *mc_entry,
+ char *tnumt_pl, unsigned int entry_index);
+ bool (*entry_compare)(const struct mlxsw_sp_nve_mc_record *mc_record,
+ const struct mlxsw_sp_nve_mc_entry *mc_entry,
+ const union mlxsw_sp_l3addr *addr);
+};
+
+struct mlxsw_sp_nve_mc_list_key {
+ u16 fid_index;
+};
+
+struct mlxsw_sp_nve_mc_ipv6_entry {
+ struct in6_addr addr6;
+ u32 addr6_kvdl_index;
+};
+
+struct mlxsw_sp_nve_mc_entry {
+ union {
+ __be32 addr4;
+ struct mlxsw_sp_nve_mc_ipv6_entry ipv6_entry;
+ };
+ u8 valid:1;
+};
+
+struct mlxsw_sp_nve_mc_record {
+ struct list_head list;
+ enum mlxsw_sp_l3proto proto;
+ unsigned int num_entries;
+ struct mlxsw_sp *mlxsw_sp;
+ struct mlxsw_sp_nve_mc_list *mc_list;
+ const struct mlxsw_sp_nve_mc_record_ops *ops;
+ u32 kvdl_index;
+ struct mlxsw_sp_nve_mc_entry entries[0];
+};
+
+struct mlxsw_sp_nve_mc_list {
+ struct list_head records_list;
+ struct rhash_head ht_node;
+ struct mlxsw_sp_nve_mc_list_key key;
+};
+
+static const struct rhashtable_params mlxsw_sp_nve_mc_list_ht_params = {
+ .key_len = sizeof(struct mlxsw_sp_nve_mc_list_key),
+ .key_offset = offsetof(struct mlxsw_sp_nve_mc_list, key),
+ .head_offset = offsetof(struct mlxsw_sp_nve_mc_list, ht_node),
+};
+
+static int
+mlxsw_sp_nve_mc_record_ipv4_entry_add(struct mlxsw_sp_nve_mc_record *mc_record,
+ struct mlxsw_sp_nve_mc_entry *mc_entry,
+ const union mlxsw_sp_l3addr *addr)
+{
+ mc_entry->addr4 = addr->addr4;
+
+ return 0;
+}
+
+static void
+mlxsw_sp_nve_mc_record_ipv4_entry_del(const struct mlxsw_sp_nve_mc_record *mc_record,
+ const struct mlxsw_sp_nve_mc_entry *mc_entry)
+{
+}
+
+static void
+mlxsw_sp_nve_mc_record_ipv4_entry_set(const struct mlxsw_sp_nve_mc_record *mc_record,
+ const struct mlxsw_sp_nve_mc_entry *mc_entry,
+ char *tnumt_pl, unsigned int entry_index)
+{
+ u32 udip = be32_to_cpu(mc_entry->addr4);
+
+ mlxsw_reg_tnumt_udip_set(tnumt_pl, entry_index, udip);
+}
+
+static bool
+mlxsw_sp_nve_mc_record_ipv4_entry_compare(const struct mlxsw_sp_nve_mc_record *mc_record,
+ const struct mlxsw_sp_nve_mc_entry *mc_entry,
+ const union mlxsw_sp_l3addr *addr)
+{
+ return mc_entry->addr4 == addr->addr4;
+}
+
+static const struct mlxsw_sp_nve_mc_record_ops
+mlxsw_sp_nve_mc_record_ipv4_ops = {
+ .type = MLXSW_REG_TNUMT_RECORD_TYPE_IPV4,
+ .entry_add = &mlxsw_sp_nve_mc_record_ipv4_entry_add,
+ .entry_del = &mlxsw_sp_nve_mc_record_ipv4_entry_del,
+ .entry_set = &mlxsw_sp_nve_mc_record_ipv4_entry_set,
+ .entry_compare = &mlxsw_sp_nve_mc_record_ipv4_entry_compare,
+};
+
+static int
+mlxsw_sp_nve_mc_record_ipv6_entry_add(struct mlxsw_sp_nve_mc_record *mc_record,
+ struct mlxsw_sp_nve_mc_entry *mc_entry,
+ const union mlxsw_sp_l3addr *addr)
+{
+ WARN_ON(1);
+
+ return -EINVAL;
+}
+
+static void
+mlxsw_sp_nve_mc_record_ipv6_entry_del(const struct mlxsw_sp_nve_mc_record *mc_record,
+ const struct mlxsw_sp_nve_mc_entry *mc_entry)
+{
+}
+
+static void
+mlxsw_sp_nve_mc_record_ipv6_entry_set(const struct mlxsw_sp_nve_mc_record *mc_record,
+ const struct mlxsw_sp_nve_mc_entry *mc_entry,
+ char *tnumt_pl, unsigned int entry_index)
+{
+ u32 udip_ptr = mc_entry->ipv6_entry.addr6_kvdl_index;
+
+ mlxsw_reg_tnumt_udip_ptr_set(tnumt_pl, entry_index, udip_ptr);
+}
+
+static bool
+mlxsw_sp_nve_mc_record_ipv6_entry_compare(const struct mlxsw_sp_nve_mc_record *mc_record,
+ const struct mlxsw_sp_nve_mc_entry *mc_entry,
+ const union mlxsw_sp_l3addr *addr)
+{
+ return ipv6_addr_equal(&mc_entry->ipv6_entry.addr6, &addr->addr6);
+}
+
+static const struct mlxsw_sp_nve_mc_record_ops
+mlxsw_sp_nve_mc_record_ipv6_ops = {
+ .type = MLXSW_REG_TNUMT_RECORD_TYPE_IPV6,
+ .entry_add = &mlxsw_sp_nve_mc_record_ipv6_entry_add,
+ .entry_del = &mlxsw_sp_nve_mc_record_ipv6_entry_del,
+ .entry_set = &mlxsw_sp_nve_mc_record_ipv6_entry_set,
+ .entry_compare = &mlxsw_sp_nve_mc_record_ipv6_entry_compare,
+};
+
+static const struct mlxsw_sp_nve_mc_record_ops *
+mlxsw_sp_nve_mc_record_ops_arr[] = {
+ [MLXSW_SP_L3_PROTO_IPV4] = &mlxsw_sp_nve_mc_record_ipv4_ops,
+ [MLXSW_SP_L3_PROTO_IPV6] = &mlxsw_sp_nve_mc_record_ipv6_ops,
+};
+
+static struct mlxsw_sp_nve_mc_list *
+mlxsw_sp_nve_mc_list_find(struct mlxsw_sp *mlxsw_sp,
+ const struct mlxsw_sp_nve_mc_list_key *key)
+{
+ struct mlxsw_sp_nve *nve = mlxsw_sp->nve;
+
+ return rhashtable_lookup_fast(&nve->mc_list_ht, key,
+ mlxsw_sp_nve_mc_list_ht_params);
+}
+
+static struct mlxsw_sp_nve_mc_list *
+mlxsw_sp_nve_mc_list_create(struct mlxsw_sp *mlxsw_sp,
+ const struct mlxsw_sp_nve_mc_list_key *key)
+{
+ struct mlxsw_sp_nve *nve = mlxsw_sp->nve;
+ struct mlxsw_sp_nve_mc_list *mc_list;
+ int err;
+
+ mc_list = kmalloc(sizeof(*mc_list), GFP_KERNEL);
+ if (!mc_list)
+ return ERR_PTR(-ENOMEM);
+
+ INIT_LIST_HEAD(&mc_list->records_list);
+ mc_list->key = *key;
+
+ err = rhashtable_insert_fast(&nve->mc_list_ht, &mc_list->ht_node,
+ mlxsw_sp_nve_mc_list_ht_params);
+ if (err)
+ goto err_rhashtable_insert;
+
+ return mc_list;
+
+err_rhashtable_insert:
+ kfree(mc_list);
+ return ERR_PTR(err);
+}
+
+static void mlxsw_sp_nve_mc_list_destroy(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_nve_mc_list *mc_list)
+{
+ struct mlxsw_sp_nve *nve = mlxsw_sp->nve;
+
+ rhashtable_remove_fast(&nve->mc_list_ht, &mc_list->ht_node,
+ mlxsw_sp_nve_mc_list_ht_params);
+ WARN_ON(!list_empty(&mc_list->records_list));
+ kfree(mc_list);
+}
+
+static struct mlxsw_sp_nve_mc_list *
+mlxsw_sp_nve_mc_list_get(struct mlxsw_sp *mlxsw_sp,
+ const struct mlxsw_sp_nve_mc_list_key *key)
+{
+ struct mlxsw_sp_nve_mc_list *mc_list;
+
+ mc_list = mlxsw_sp_nve_mc_list_find(mlxsw_sp, key);
+ if (mc_list)
+ return mc_list;
+
+ return mlxsw_sp_nve_mc_list_create(mlxsw_sp, key);
+}
+
+static void
+mlxsw_sp_nve_mc_list_put(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_nve_mc_list *mc_list)
+{
+ if (!list_empty(&mc_list->records_list))
+ return;
+ mlxsw_sp_nve_mc_list_destroy(mlxsw_sp, mc_list);
+}
+
+static struct mlxsw_sp_nve_mc_record *
+mlxsw_sp_nve_mc_record_create(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_nve_mc_list *mc_list,
+ enum mlxsw_sp_l3proto proto)
+{
+ unsigned int num_max_entries = mlxsw_sp->nve->num_max_mc_entries[proto];
+ struct mlxsw_sp_nve_mc_record *mc_record;
+ int err;
+
+ mc_record = kzalloc(sizeof(*mc_record) + num_max_entries *
+ sizeof(struct mlxsw_sp_nve_mc_entry), GFP_KERNEL);
+ if (!mc_record)
+ return ERR_PTR(-ENOMEM);
+
+ err = mlxsw_sp_kvdl_alloc(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_TNUMT, 1,
+ &mc_record->kvdl_index);
+ if (err)
+ goto err_kvdl_alloc;
+
+ mc_record->ops = mlxsw_sp_nve_mc_record_ops_arr[proto];
+ mc_record->mlxsw_sp = mlxsw_sp;
+ mc_record->mc_list = mc_list;
+ mc_record->proto = proto;
+ list_add_tail(&mc_record->list, &mc_list->records_list);
+
+ return mc_record;
+
+err_kvdl_alloc:
+ kfree(mc_record);
+ return ERR_PTR(err);
+}
+
+static void
+mlxsw_sp_nve_mc_record_destroy(struct mlxsw_sp_nve_mc_record *mc_record)
+{
+ struct mlxsw_sp *mlxsw_sp = mc_record->mlxsw_sp;
+
+ list_del(&mc_record->list);
+ mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_TNUMT, 1,
+ mc_record->kvdl_index);
+ WARN_ON(mc_record->num_entries);
+ kfree(mc_record);
+}
+
+static struct mlxsw_sp_nve_mc_record *
+mlxsw_sp_nve_mc_record_get(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_nve_mc_list *mc_list,
+ enum mlxsw_sp_l3proto proto)
+{
+ struct mlxsw_sp_nve_mc_record *mc_record;
+
+ list_for_each_entry_reverse(mc_record, &mc_list->records_list, list) {
+ unsigned int num_entries = mc_record->num_entries;
+ struct mlxsw_sp_nve *nve = mlxsw_sp->nve;
+
+ if (mc_record->proto == proto &&
+ num_entries < nve->num_max_mc_entries[proto])
+ return mc_record;
+ }
+
+ return mlxsw_sp_nve_mc_record_create(mlxsw_sp, mc_list, proto);
+}
+
+static void
+mlxsw_sp_nve_mc_record_put(struct mlxsw_sp_nve_mc_record *mc_record)
+{
+ if (mc_record->num_entries != 0)
+ return;
+
+ mlxsw_sp_nve_mc_record_destroy(mc_record);
+}
+
+static struct mlxsw_sp_nve_mc_entry *
+mlxsw_sp_nve_mc_free_entry_find(struct mlxsw_sp_nve_mc_record *mc_record)
+{
+ struct mlxsw_sp_nve *nve = mc_record->mlxsw_sp->nve;
+ unsigned int num_max_entries;
+ int i;
+
+ num_max_entries = nve->num_max_mc_entries[mc_record->proto];
+ for (i = 0; i < num_max_entries; i++) {
+ if (mc_record->entries[i].valid)
+ continue;
+ return &mc_record->entries[i];
+ }
+
+ return NULL;
+}
+
+static int
+mlxsw_sp_nve_mc_record_refresh(struct mlxsw_sp_nve_mc_record *mc_record)
+{
+ enum mlxsw_reg_tnumt_record_type type = mc_record->ops->type;
+ struct mlxsw_sp_nve_mc_list *mc_list = mc_record->mc_list;
+ struct mlxsw_sp *mlxsw_sp = mc_record->mlxsw_sp;
+ char tnumt_pl[MLXSW_REG_TNUMT_LEN];
+ unsigned int num_max_entries;
+ unsigned int num_entries = 0;
+ u32 next_kvdl_index = 0;
+ bool next_valid = false;
+ int i;
+
+ if (!list_is_last(&mc_record->list, &mc_list->records_list)) {
+ struct mlxsw_sp_nve_mc_record *next_record;
+
+ next_record = list_next_entry(mc_record, list);
+ next_kvdl_index = next_record->kvdl_index;
+ next_valid = true;
+ }
+
+ mlxsw_reg_tnumt_pack(tnumt_pl, type, MLXSW_REG_TNUMT_TUNNEL_PORT_NVE,
+ mc_record->kvdl_index, next_valid,
+ next_kvdl_index, mc_record->num_entries);
+
+ num_max_entries = mlxsw_sp->nve->num_max_mc_entries[mc_record->proto];
+ for (i = 0; i < num_max_entries; i++) {
+ struct mlxsw_sp_nve_mc_entry *mc_entry;
+
+ mc_entry = &mc_record->entries[i];
+ if (!mc_entry->valid)
+ continue;
+ mc_record->ops->entry_set(mc_record, mc_entry, tnumt_pl,
+ num_entries++);
+ }
+
+ WARN_ON(num_entries != mc_record->num_entries);
+
+ return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tnumt), tnumt_pl);
+}
+
+static bool
+mlxsw_sp_nve_mc_record_is_first(struct mlxsw_sp_nve_mc_record *mc_record)
+{
+ struct mlxsw_sp_nve_mc_list *mc_list = mc_record->mc_list;
+ struct mlxsw_sp_nve_mc_record *first_record;
+
+ first_record = list_first_entry(&mc_list->records_list,
+ struct mlxsw_sp_nve_mc_record, list);
+
+ return mc_record == first_record;
+}
+
+static struct mlxsw_sp_nve_mc_entry *
+mlxsw_sp_nve_mc_entry_find(struct mlxsw_sp_nve_mc_record *mc_record,
+ union mlxsw_sp_l3addr *addr)
+{
+ struct mlxsw_sp_nve *nve = mc_record->mlxsw_sp->nve;
+ unsigned int num_max_entries;
+ int i;
+
+ num_max_entries = nve->num_max_mc_entries[mc_record->proto];
+ for (i = 0; i < num_max_entries; i++) {
+ struct mlxsw_sp_nve_mc_entry *mc_entry;
+
+ mc_entry = &mc_record->entries[i];
+ if (!mc_entry->valid)
+ continue;
+ if (mc_record->ops->entry_compare(mc_record, mc_entry, addr))
+ return mc_entry;
+ }
+
+ return NULL;
+}
+
+static int
+mlxsw_sp_nve_mc_record_ip_add(struct mlxsw_sp_nve_mc_record *mc_record,
+ union mlxsw_sp_l3addr *addr)
+{
+ struct mlxsw_sp_nve_mc_entry *mc_entry = NULL;
+ int err;
+
+ mc_entry = mlxsw_sp_nve_mc_free_entry_find(mc_record);
+ if (WARN_ON(!mc_entry))
+ return -EINVAL;
+
+ err = mc_record->ops->entry_add(mc_record, mc_entry, addr);
+ if (err)
+ return err;
+ mc_record->num_entries++;
+ mc_entry->valid = true;
+
+ err = mlxsw_sp_nve_mc_record_refresh(mc_record);
+ if (err)
+ goto err_record_refresh;
+
+ /* If this is a new record and not the first one, then we need to
+ * update the next pointer of the previous entry
+ */
+ if (mc_record->num_entries != 1 ||
+ mlxsw_sp_nve_mc_record_is_first(mc_record))
+ return 0;
+
+ err = mlxsw_sp_nve_mc_record_refresh(list_prev_entry(mc_record, list));
+ if (err)
+ goto err_prev_record_refresh;
+
+ return 0;
+
+err_prev_record_refresh:
+err_record_refresh:
+ mc_entry->valid = false;
+ mc_record->num_entries--;
+ mc_record->ops->entry_del(mc_record, mc_entry);
+ return err;
+}
+
+static void
+mlxsw_sp_nve_mc_record_entry_del(struct mlxsw_sp_nve_mc_record *mc_record,
+ struct mlxsw_sp_nve_mc_entry *mc_entry)
+{
+ struct mlxsw_sp_nve_mc_list *mc_list = mc_record->mc_list;
+
+ mc_entry->valid = false;
+ mc_record->num_entries--;
+
+ /* When the record continues to exist we only need to invalidate
+ * the requested entry
+ */
+ if (mc_record->num_entries != 0) {
+ mlxsw_sp_nve_mc_record_refresh(mc_record);
+ mc_record->ops->entry_del(mc_record, mc_entry);
+ return;
+ }
+
+ /* If the record needs to be deleted, but it is not the first,
+ * then we need to make sure that the previous record no longer
+ * points to it. Remove deleted record from the list to reflect
+ * that and then re-add it at the end, so that it could be
+ * properly removed by the record destruction code
+ */
+ if (!mlxsw_sp_nve_mc_record_is_first(mc_record)) {
+ struct mlxsw_sp_nve_mc_record *prev_record;
+
+ prev_record = list_prev_entry(mc_record, list);
+ list_del(&mc_record->list);
+ mlxsw_sp_nve_mc_record_refresh(prev_record);
+ list_add_tail(&mc_record->list, &mc_list->records_list);
+ mc_record->ops->entry_del(mc_record, mc_entry);
+ return;
+ }
+
+ /* If the first record needs to be deleted, but the list is not
+ * singular, then the second record needs to be written in the
+ * first record's address, as this address is stored as a property
+ * of the FID
+ */
+ if (mlxsw_sp_nve_mc_record_is_first(mc_record) &&
+ !list_is_singular(&mc_list->records_list)) {
+ struct mlxsw_sp_nve_mc_record *next_record;
+
+ next_record = list_next_entry(mc_record, list);
+ swap(mc_record->kvdl_index, next_record->kvdl_index);
+ mlxsw_sp_nve_mc_record_refresh(next_record);
+ mc_record->ops->entry_del(mc_record, mc_entry);
+ return;
+ }
+
+ /* This is the last case where the last remaining record needs to
+ * be deleted. Simply delete the entry
+ */
+ mc_record->ops->entry_del(mc_record, mc_entry);
+}
+
+static struct mlxsw_sp_nve_mc_record *
+mlxsw_sp_nve_mc_record_find(struct mlxsw_sp_nve_mc_list *mc_list,
+ enum mlxsw_sp_l3proto proto,
+ union mlxsw_sp_l3addr *addr,
+ struct mlxsw_sp_nve_mc_entry **mc_entry)
+{
+ struct mlxsw_sp_nve_mc_record *mc_record;
+
+ list_for_each_entry(mc_record, &mc_list->records_list, list) {
+ if (mc_record->proto != proto)
+ continue;
+
+ *mc_entry = mlxsw_sp_nve_mc_entry_find(mc_record, addr);
+ if (*mc_entry)
+ return mc_record;
+ }
+
+ return NULL;
+}
+
+static int mlxsw_sp_nve_mc_list_ip_add(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_nve_mc_list *mc_list,
+ enum mlxsw_sp_l3proto proto,
+ union mlxsw_sp_l3addr *addr)
+{
+ struct mlxsw_sp_nve_mc_record *mc_record;
+ int err;
+
+ mc_record = mlxsw_sp_nve_mc_record_get(mlxsw_sp, mc_list, proto);
+ if (IS_ERR(mc_record))
+ return PTR_ERR(mc_record);
+
+ err = mlxsw_sp_nve_mc_record_ip_add(mc_record, addr);
+ if (err)
+ goto err_ip_add;
+
+ return 0;
+
+err_ip_add:
+ mlxsw_sp_nve_mc_record_put(mc_record);
+ return err;
+}
+
+static void mlxsw_sp_nve_mc_list_ip_del(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_nve_mc_list *mc_list,
+ enum mlxsw_sp_l3proto proto,
+ union mlxsw_sp_l3addr *addr)
+{
+ struct mlxsw_sp_nve_mc_record *mc_record;
+ struct mlxsw_sp_nve_mc_entry *mc_entry;
+
+ mc_record = mlxsw_sp_nve_mc_record_find(mc_list, proto, addr,
+ &mc_entry);
+ if (WARN_ON(!mc_record))
+ return;
+
+ mlxsw_sp_nve_mc_record_entry_del(mc_record, mc_entry);
+ mlxsw_sp_nve_mc_record_put(mc_record);
+}
+
+static int
+mlxsw_sp_nve_fid_flood_index_set(struct mlxsw_sp_fid *fid,
+ struct mlxsw_sp_nve_mc_list *mc_list)
+{
+ struct mlxsw_sp_nve_mc_record *mc_record;
+
+ /* The address of the first record in the list is a property of
+ * the FID and we never change it. It only needs to be set when
+ * a new list is created
+ */
+ if (mlxsw_sp_fid_nve_flood_index_is_set(fid))
+ return 0;
+
+ mc_record = list_first_entry(&mc_list->records_list,
+ struct mlxsw_sp_nve_mc_record, list);
+
+ return mlxsw_sp_fid_nve_flood_index_set(fid, mc_record->kvdl_index);
+}
+
+static void
+mlxsw_sp_nve_fid_flood_index_clear(struct mlxsw_sp_fid *fid,
+ struct mlxsw_sp_nve_mc_list *mc_list)
+{
+ struct mlxsw_sp_nve_mc_record *mc_record;
+
+ /* The address of the first record needs to be invalidated only when
+ * the last record is about to be removed
+ */
+ if (!list_is_singular(&mc_list->records_list))
+ return;
+
+ mc_record = list_first_entry(&mc_list->records_list,
+ struct mlxsw_sp_nve_mc_record, list);
+ if (mc_record->num_entries != 1)
+ return;
+
+ return mlxsw_sp_fid_nve_flood_index_clear(fid);
+}
+
+int mlxsw_sp_nve_flood_ip_add(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_fid *fid,
+ enum mlxsw_sp_l3proto proto,
+ union mlxsw_sp_l3addr *addr)
+{
+ struct mlxsw_sp_nve_mc_list_key key = { 0 };
+ struct mlxsw_sp_nve_mc_list *mc_list;
+ int err;
+
+ key.fid_index = mlxsw_sp_fid_index(fid);
+ mc_list = mlxsw_sp_nve_mc_list_get(mlxsw_sp, &key);
+ if (IS_ERR(mc_list))
+ return PTR_ERR(mc_list);
+
+ err = mlxsw_sp_nve_mc_list_ip_add(mlxsw_sp, mc_list, proto, addr);
+ if (err)
+ goto err_add_ip;
+
+ err = mlxsw_sp_nve_fid_flood_index_set(fid, mc_list);
+ if (err)
+ goto err_fid_flood_index_set;
+
+ return 0;
+
+err_fid_flood_index_set:
+ mlxsw_sp_nve_mc_list_ip_del(mlxsw_sp, mc_list, proto, addr);
+err_add_ip:
+ mlxsw_sp_nve_mc_list_put(mlxsw_sp, mc_list);
+ return err;
+}
+
+void mlxsw_sp_nve_flood_ip_del(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_fid *fid,
+ enum mlxsw_sp_l3proto proto,
+ union mlxsw_sp_l3addr *addr)
+{
+ struct mlxsw_sp_nve_mc_list_key key = { 0 };
+ struct mlxsw_sp_nve_mc_list *mc_list;
+
+ key.fid_index = mlxsw_sp_fid_index(fid);
+ mc_list = mlxsw_sp_nve_mc_list_find(mlxsw_sp, &key);
+ if (WARN_ON(!mc_list))
+ return;
+
+ mlxsw_sp_nve_fid_flood_index_clear(fid, mc_list);
+ mlxsw_sp_nve_mc_list_ip_del(mlxsw_sp, mc_list, proto, addr);
+ mlxsw_sp_nve_mc_list_put(mlxsw_sp, mc_list);
+}
+
+static void
+mlxsw_sp_nve_mc_record_delete(struct mlxsw_sp_nve_mc_record *mc_record)
+{
+ struct mlxsw_sp_nve *nve = mc_record->mlxsw_sp->nve;
+ unsigned int num_max_entries;
+ int i;
+
+ num_max_entries = nve->num_max_mc_entries[mc_record->proto];
+ for (i = 0; i < num_max_entries; i++) {
+ struct mlxsw_sp_nve_mc_entry *mc_entry = &mc_record->entries[i];
+
+ if (!mc_entry->valid)
+ continue;
+ mlxsw_sp_nve_mc_record_entry_del(mc_record, mc_entry);
+ }
+
+ WARN_ON(mc_record->num_entries);
+ mlxsw_sp_nve_mc_record_put(mc_record);
+}
+
+static void mlxsw_sp_nve_flood_ip_flush(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_fid *fid)
+{
+ struct mlxsw_sp_nve_mc_record *mc_record, *tmp;
+ struct mlxsw_sp_nve_mc_list_key key = { 0 };
+ struct mlxsw_sp_nve_mc_list *mc_list;
+
+ if (!mlxsw_sp_fid_nve_flood_index_is_set(fid))
+ return;
+
+ mlxsw_sp_fid_nve_flood_index_clear(fid);
+
+ key.fid_index = mlxsw_sp_fid_index(fid);
+ mc_list = mlxsw_sp_nve_mc_list_find(mlxsw_sp, &key);
+ if (WARN_ON(!mc_list))
+ return;
+
+ list_for_each_entry_safe(mc_record, tmp, &mc_list->records_list, list)
+ mlxsw_sp_nve_mc_record_delete(mc_record);
+
+ WARN_ON(!list_empty(&mc_list->records_list));
+ mlxsw_sp_nve_mc_list_put(mlxsw_sp, mc_list);
+}
+
+u32 mlxsw_sp_nve_decap_tunnel_index_get(const struct mlxsw_sp *mlxsw_sp)
+{
+ WARN_ON(mlxsw_sp->nve->num_nve_tunnels == 0);
+
+ return mlxsw_sp->nve->tunnel_index;
+}
+
+bool mlxsw_sp_nve_ipv4_route_is_decap(const struct mlxsw_sp *mlxsw_sp,
+ u32 tb_id, __be32 addr)
+{
+ struct mlxsw_sp_nve *nve = mlxsw_sp->nve;
+ struct mlxsw_sp_nve_config *config = &nve->config;
+
+ if (nve->num_nve_tunnels &&
+ config->ul_proto == MLXSW_SP_L3_PROTO_IPV4 &&
+ config->ul_sip.addr4 == addr && config->ul_tb_id == tb_id)
+ return true;
+
+ return false;
+}
+
+static int mlxsw_sp_nve_tunnel_init(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_nve_config *config)
+{
+ struct mlxsw_sp_nve *nve = mlxsw_sp->nve;
+ const struct mlxsw_sp_nve_ops *ops;
+ int err;
+
+ if (nve->num_nve_tunnels++ != 0)
+ return 0;
+
+ err = mlxsw_sp_kvdl_alloc(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1,
+ &nve->tunnel_index);
+ if (err)
+ goto err_kvdl_alloc;
+
+ ops = nve->nve_ops_arr[config->type];
+ err = ops->init(nve, config);
+ if (err)
+ goto err_ops_init;
+
+ return 0;
+
+err_ops_init:
+ mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1,
+ nve->tunnel_index);
+err_kvdl_alloc:
+ nve->num_nve_tunnels--;
+ return err;
+}
+
+static void mlxsw_sp_nve_tunnel_fini(struct mlxsw_sp *mlxsw_sp)
+{
+ struct mlxsw_sp_nve *nve = mlxsw_sp->nve;
+ const struct mlxsw_sp_nve_ops *ops;
+
+ ops = nve->nve_ops_arr[nve->config.type];
+
+ if (mlxsw_sp->nve->num_nve_tunnels == 1) {
+ ops->fini(nve);
+ mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1,
+ nve->tunnel_index);
+ }
+ nve->num_nve_tunnels--;
+}
+
+static void mlxsw_sp_nve_fdb_flush_by_fid(struct mlxsw_sp *mlxsw_sp,
+ u16 fid_index)
+{
+ char sfdf_pl[MLXSW_REG_SFDF_LEN];
+
+ mlxsw_reg_sfdf_pack(sfdf_pl, MLXSW_REG_SFDF_FLUSH_PER_NVE_AND_FID);
+ mlxsw_reg_sfdf_fid_set(sfdf_pl, fid_index);
+ mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfdf), sfdf_pl);
+}
+
+int mlxsw_sp_nve_fid_enable(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fid *fid,
+ struct mlxsw_sp_nve_params *params,
+ struct netlink_ext_ack *extack)
+{
+ struct mlxsw_sp_nve *nve = mlxsw_sp->nve;
+ const struct mlxsw_sp_nve_ops *ops;
+ struct mlxsw_sp_nve_config config;
+ int err;
+
+ ops = nve->nve_ops_arr[params->type];
+
+ if (!ops->can_offload(nve, params->dev, extack))
+ return -EOPNOTSUPP;
+
+ memset(&config, 0, sizeof(config));
+ ops->nve_config(nve, params->dev, &config);
+ if (nve->num_nve_tunnels &&
+ memcmp(&config, &nve->config, sizeof(config))) {
+ NL_SET_ERR_MSG_MOD(extack, "Conflicting NVE tunnels configuration");
+ return -EOPNOTSUPP;
+ }
+
+ err = mlxsw_sp_nve_tunnel_init(mlxsw_sp, &config);
+ if (err) {
+ NL_SET_ERR_MSG_MOD(extack, "Failed to initialize NVE tunnel");
+ return err;
+ }
+
+ err = mlxsw_sp_fid_vni_set(fid, params->vni);
+ if (err) {
+ NL_SET_ERR_MSG_MOD(extack, "Failed to set VNI on FID");
+ goto err_fid_vni_set;
+ }
+
+ nve->config = config;
+
+ return 0;
+
+err_fid_vni_set:
+ mlxsw_sp_nve_tunnel_fini(mlxsw_sp);
+ return err;
+}
+
+void mlxsw_sp_nve_fid_disable(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_fid *fid)
+{
+ u16 fid_index = mlxsw_sp_fid_index(fid);
+
+ mlxsw_sp_nve_flood_ip_flush(mlxsw_sp, fid);
+ mlxsw_sp_nve_fdb_flush_by_fid(mlxsw_sp, fid_index);
+ mlxsw_sp_fid_vni_clear(fid);
+ mlxsw_sp_nve_tunnel_fini(mlxsw_sp);
+}
+
+int mlxsw_sp_port_nve_init(struct mlxsw_sp_port *mlxsw_sp_port)
+{
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+ char tnqdr_pl[MLXSW_REG_TNQDR_LEN];
+
+ mlxsw_reg_tnqdr_pack(tnqdr_pl, mlxsw_sp_port->local_port);
+ return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tnqdr), tnqdr_pl);
+}
+
+void mlxsw_sp_port_nve_fini(struct mlxsw_sp_port *mlxsw_sp_port)
+{
+}
+
+static int mlxsw_sp_nve_qos_init(struct mlxsw_sp *mlxsw_sp)
+{
+ char tnqcr_pl[MLXSW_REG_TNQCR_LEN];
+
+ mlxsw_reg_tnqcr_pack(tnqcr_pl);
+ return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tnqcr), tnqcr_pl);
+}
+
+static int mlxsw_sp_nve_ecn_encap_init(struct mlxsw_sp *mlxsw_sp)
+{
+ int i;
+
+ /* Iterate over inner ECN values */
+ for (i = INET_ECN_NOT_ECT; i <= INET_ECN_CE; i++) {
+ u8 outer_ecn = INET_ECN_encapsulate(0, i);
+ char tneem_pl[MLXSW_REG_TNEEM_LEN];
+ int err;
+
+ mlxsw_reg_tneem_pack(tneem_pl, i, outer_ecn);
+ err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tneem),
+ tneem_pl);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int __mlxsw_sp_nve_ecn_decap_init(struct mlxsw_sp *mlxsw_sp,
+ u8 inner_ecn, u8 outer_ecn)
+{
+ char tndem_pl[MLXSW_REG_TNDEM_LEN];
+ bool trap_en, set_ce = false;
+ u8 new_inner_ecn;
+
+ trap_en = !!__INET_ECN_decapsulate(outer_ecn, inner_ecn, &set_ce);
+ new_inner_ecn = set_ce ? INET_ECN_CE : inner_ecn;
+
+ mlxsw_reg_tndem_pack(tndem_pl, outer_ecn, inner_ecn, new_inner_ecn,
+ trap_en, trap_en ? MLXSW_TRAP_ID_DECAP_ECN0 : 0);
+ return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tndem), tndem_pl);
+}
+
+static int mlxsw_sp_nve_ecn_decap_init(struct mlxsw_sp *mlxsw_sp)
+{
+ int i;
+
+ /* Iterate over inner ECN values */
+ for (i = INET_ECN_NOT_ECT; i <= INET_ECN_CE; i++) {
+ int j;
+
+ /* Iterate over outer ECN values */
+ for (j = INET_ECN_NOT_ECT; j <= INET_ECN_CE; j++) {
+ int err;
+
+ err = __mlxsw_sp_nve_ecn_decap_init(mlxsw_sp, i, j);
+ if (err)
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static int mlxsw_sp_nve_ecn_init(struct mlxsw_sp *mlxsw_sp)
+{
+ int err;
+
+ err = mlxsw_sp_nve_ecn_encap_init(mlxsw_sp);
+ if (err)
+ return err;
+
+ return mlxsw_sp_nve_ecn_decap_init(mlxsw_sp);
+}
+
+static int mlxsw_sp_nve_resources_query(struct mlxsw_sp *mlxsw_sp)
+{
+ unsigned int max;
+
+ if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_NVE_MC_ENTRIES_IPV4) ||
+ !MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_NVE_MC_ENTRIES_IPV6))
+ return -EIO;
+ max = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_NVE_MC_ENTRIES_IPV4);
+ mlxsw_sp->nve->num_max_mc_entries[MLXSW_SP_L3_PROTO_IPV4] = max;
+ max = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_NVE_MC_ENTRIES_IPV6);
+ mlxsw_sp->nve->num_max_mc_entries[MLXSW_SP_L3_PROTO_IPV6] = max;
+
+ return 0;
+}
+
+int mlxsw_sp_nve_init(struct mlxsw_sp *mlxsw_sp)
+{
+ struct mlxsw_sp_nve *nve;
+ int err;
+
+ nve = kzalloc(sizeof(*mlxsw_sp->nve), GFP_KERNEL);
+ if (!nve)
+ return -ENOMEM;
+ mlxsw_sp->nve = nve;
+ nve->mlxsw_sp = mlxsw_sp;
+ nve->nve_ops_arr = mlxsw_sp->nve_ops_arr;
+
+ err = rhashtable_init(&nve->mc_list_ht,
+ &mlxsw_sp_nve_mc_list_ht_params);
+ if (err)
+ goto err_rhashtable_init;
+
+ err = mlxsw_sp_nve_qos_init(mlxsw_sp);
+ if (err)
+ goto err_nve_qos_init;
+
+ err = mlxsw_sp_nve_ecn_init(mlxsw_sp);
+ if (err)
+ goto err_nve_ecn_init;
+
+ err = mlxsw_sp_nve_resources_query(mlxsw_sp);
+ if (err)
+ goto err_nve_resources_query;
+
+ return 0;
+
+err_nve_resources_query:
+err_nve_ecn_init:
+err_nve_qos_init:
+ rhashtable_destroy(&nve->mc_list_ht);
+err_rhashtable_init:
+ mlxsw_sp->nve = NULL;
+ kfree(nve);
+ return err;
+}
+
+void mlxsw_sp_nve_fini(struct mlxsw_sp *mlxsw_sp)
+{
+ WARN_ON(mlxsw_sp->nve->num_nve_tunnels);
+ rhashtable_destroy(&mlxsw_sp->nve->mc_list_ht);
+ mlxsw_sp->nve = NULL;
+ kfree(mlxsw_sp->nve);
+}
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.h
new file mode 100644
index 000000000000..4cc3297e13d6
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */
+/* Copyright (c) 2018 Mellanox Technologies. All rights reserved */
+
+#ifndef _MLXSW_SPECTRUM_NVE_H
+#define _MLXSW_SPECTRUM_NVE_H
+
+#include <linux/netlink.h>
+#include <linux/rhashtable.h>
+
+#include "spectrum.h"
+
+struct mlxsw_sp_nve_config {
+ enum mlxsw_sp_nve_type type;
+ u8 ttl;
+ u8 learning_en:1;
+ __be16 udp_dport;
+ __be32 flowlabel;
+ u32 ul_tb_id;
+ enum mlxsw_sp_l3proto ul_proto;
+ union mlxsw_sp_l3addr ul_sip;
+};
+
+struct mlxsw_sp_nve {
+ struct mlxsw_sp_nve_config config;
+ struct rhashtable mc_list_ht;
+ struct mlxsw_sp *mlxsw_sp;
+ const struct mlxsw_sp_nve_ops **nve_ops_arr;
+ unsigned int num_nve_tunnels; /* Protected by RTNL */
+ unsigned int num_max_mc_entries[MLXSW_SP_L3_PROTO_MAX];
+ u32 tunnel_index;
+};
+
+struct mlxsw_sp_nve_ops {
+ enum mlxsw_sp_nve_type type;
+ bool (*can_offload)(const struct mlxsw_sp_nve *nve,
+ const struct net_device *dev,
+ struct netlink_ext_ack *extack);
+ void (*nve_config)(const struct mlxsw_sp_nve *nve,
+ const struct net_device *dev,
+ struct mlxsw_sp_nve_config *config);
+ int (*init)(struct mlxsw_sp_nve *nve,
+ const struct mlxsw_sp_nve_config *config);
+ void (*fini)(struct mlxsw_sp_nve *nve);
+};
+
+extern const struct mlxsw_sp_nve_ops mlxsw_sp1_nve_vxlan_ops;
+extern const struct mlxsw_sp_nve_ops mlxsw_sp2_nve_vxlan_ops;
+
+#endif
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c
new file mode 100644
index 000000000000..d21c7be5b1c9
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c
@@ -0,0 +1,249 @@
+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+/* Copyright (c) 2018 Mellanox Technologies. All rights reserved */
+
+#include <linux/netdevice.h>
+#include <linux/netlink.h>
+#include <linux/random.h>
+#include <net/vxlan.h>
+
+#include "reg.h"
+#include "spectrum_nve.h"
+
+/* Eth (18B) | IPv6 (40B) | UDP (8B) | VxLAN (8B) | Eth (14B) | IPv6 (40B)
+ *
+ * In the worst case - where we have a VLAN tag on the outer Ethernet
+ * header and IPv6 in overlay and underlay - we need to parse 128 bytes
+ */
+#define MLXSW_SP_NVE_VXLAN_PARSING_DEPTH 128
+#define MLXSW_SP_NVE_DEFAULT_PARSING_DEPTH 96
+
+#define MLXSW_SP_NVE_VXLAN_SUPPORTED_FLAGS VXLAN_F_UDP_ZERO_CSUM_TX
+
+static bool mlxsw_sp1_nve_vxlan_can_offload(const struct mlxsw_sp_nve *nve,
+ const struct net_device *dev,
+ struct netlink_ext_ack *extack)
+{
+ struct vxlan_dev *vxlan = netdev_priv(dev);
+ struct vxlan_config *cfg = &vxlan->cfg;
+
+ if (cfg->saddr.sa.sa_family != AF_INET) {
+ NL_SET_ERR_MSG_MOD(extack, "VxLAN: Only IPv4 underlay is supported");
+ return false;
+ }
+
+ if (vxlan_addr_multicast(&cfg->remote_ip)) {
+ NL_SET_ERR_MSG_MOD(extack, "VxLAN: Multicast destination IP is not supported");
+ return false;
+ }
+
+ if (vxlan_addr_any(&cfg->saddr)) {
+ NL_SET_ERR_MSG_MOD(extack, "VxLAN: Source address must be specified");
+ return false;
+ }
+
+ if (cfg->remote_ifindex) {
+ NL_SET_ERR_MSG_MOD(extack, "VxLAN: Local interface is not supported");
+ return false;
+ }
+
+ if (cfg->port_min || cfg->port_max) {
+ NL_SET_ERR_MSG_MOD(extack, "VxLAN: Only default UDP source port range is supported");
+ return false;
+ }
+
+ if (cfg->tos != 1) {
+ NL_SET_ERR_MSG_MOD(extack, "VxLAN: TOS must be configured to inherit");
+ return false;
+ }
+
+ if (cfg->flags & VXLAN_F_TTL_INHERIT) {
+ NL_SET_ERR_MSG_MOD(extack, "VxLAN: TTL must not be configured to inherit");
+ return false;
+ }
+
+ if (cfg->flags & VXLAN_F_LEARN) {
+ NL_SET_ERR_MSG_MOD(extack, "VxLAN: Learning is not supported");
+ return false;
+ }
+
+ if (!(cfg->flags & VXLAN_F_UDP_ZERO_CSUM_TX)) {
+ NL_SET_ERR_MSG_MOD(extack, "VxLAN: UDP checksum is not supported");
+ return false;
+ }
+
+ if (cfg->flags & ~MLXSW_SP_NVE_VXLAN_SUPPORTED_FLAGS) {
+ NL_SET_ERR_MSG_MOD(extack, "VxLAN: Unsupported flag");
+ return false;
+ }
+
+ if (cfg->ttl == 0) {
+ NL_SET_ERR_MSG_MOD(extack, "VxLAN: TTL must not be configured to 0");
+ return false;
+ }
+
+ if (cfg->label != 0) {
+ NL_SET_ERR_MSG_MOD(extack, "VxLAN: Flow label must be configured to 0");
+ return false;
+ }
+
+ return true;
+}
+
+static void mlxsw_sp_nve_vxlan_config(const struct mlxsw_sp_nve *nve,
+ const struct net_device *dev,
+ struct mlxsw_sp_nve_config *config)
+{
+ struct vxlan_dev *vxlan = netdev_priv(dev);
+ struct vxlan_config *cfg = &vxlan->cfg;
+
+ config->type = MLXSW_SP_NVE_TYPE_VXLAN;
+ config->ttl = cfg->ttl;
+ config->flowlabel = cfg->label;
+ config->learning_en = cfg->flags & VXLAN_F_LEARN ? 1 : 0;
+ config->ul_tb_id = RT_TABLE_MAIN;
+ config->ul_proto = MLXSW_SP_L3_PROTO_IPV4;
+ config->ul_sip.addr4 = cfg->saddr.sin.sin_addr.s_addr;
+ config->udp_dport = cfg->dst_port;
+}
+
+static int mlxsw_sp_nve_parsing_set(struct mlxsw_sp *mlxsw_sp,
+ unsigned int parsing_depth,
+ __be16 udp_dport)
+{
+ char mprs_pl[MLXSW_REG_MPRS_LEN];
+
+ mlxsw_reg_mprs_pack(mprs_pl, parsing_depth, be16_to_cpu(udp_dport));
+ return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mprs), mprs_pl);
+}
+
+static int
+mlxsw_sp1_nve_vxlan_config_set(struct mlxsw_sp *mlxsw_sp,
+ const struct mlxsw_sp_nve_config *config)
+{
+ char tngcr_pl[MLXSW_REG_TNGCR_LEN];
+ u16 ul_vr_id;
+ u8 udp_sport;
+ int err;
+
+ err = mlxsw_sp_router_tb_id_vr_id(mlxsw_sp, config->ul_tb_id,
+ &ul_vr_id);
+ if (err)
+ return err;
+
+ mlxsw_reg_tngcr_pack(tngcr_pl, MLXSW_REG_TNGCR_TYPE_VXLAN, true,
+ config->ttl);
+ /* VxLAN driver's default UDP source port range is 32768 (0x8000)
+ * to 60999 (0xee47). Set the upper 8 bits of the UDP source port
+ * to a random number between 0x80 and 0xee
+ */
+ get_random_bytes(&udp_sport, sizeof(udp_sport));
+ udp_sport = (udp_sport % (0xee - 0x80 + 1)) + 0x80;
+ mlxsw_reg_tngcr_nve_udp_sport_prefix_set(tngcr_pl, udp_sport);
+ mlxsw_reg_tngcr_learn_enable_set(tngcr_pl, config->learning_en);
+ mlxsw_reg_tngcr_underlay_virtual_router_set(tngcr_pl, ul_vr_id);
+ mlxsw_reg_tngcr_usipv4_set(tngcr_pl, be32_to_cpu(config->ul_sip.addr4));
+
+ return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tngcr), tngcr_pl);
+}
+
+static void mlxsw_sp1_nve_vxlan_config_clear(struct mlxsw_sp *mlxsw_sp)
+{
+ char tngcr_pl[MLXSW_REG_TNGCR_LEN];
+
+ mlxsw_reg_tngcr_pack(tngcr_pl, MLXSW_REG_TNGCR_TYPE_VXLAN, false, 0);
+
+ mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tngcr), tngcr_pl);
+}
+
+static int mlxsw_sp1_nve_vxlan_rtdp_set(struct mlxsw_sp *mlxsw_sp,
+ unsigned int tunnel_index)
+{
+ char rtdp_pl[MLXSW_REG_RTDP_LEN];
+
+ mlxsw_reg_rtdp_pack(rtdp_pl, MLXSW_REG_RTDP_TYPE_NVE, tunnel_index);
+
+ return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtdp), rtdp_pl);
+}
+
+static int mlxsw_sp1_nve_vxlan_init(struct mlxsw_sp_nve *nve,
+ const struct mlxsw_sp_nve_config *config)
+{
+ struct mlxsw_sp *mlxsw_sp = nve->mlxsw_sp;
+ int err;
+
+ err = mlxsw_sp_nve_parsing_set(mlxsw_sp,
+ MLXSW_SP_NVE_VXLAN_PARSING_DEPTH,
+ config->udp_dport);
+ if (err)
+ return err;
+
+ err = mlxsw_sp1_nve_vxlan_config_set(mlxsw_sp, config);
+ if (err)
+ goto err_config_set;
+
+ err = mlxsw_sp1_nve_vxlan_rtdp_set(mlxsw_sp, nve->tunnel_index);
+ if (err)
+ goto err_rtdp_set;
+
+ err = mlxsw_sp_router_nve_promote_decap(mlxsw_sp, config->ul_tb_id,
+ config->ul_proto,
+ &config->ul_sip,
+ nve->tunnel_index);
+ if (err)
+ goto err_promote_decap;
+
+ return 0;
+
+err_promote_decap:
+err_rtdp_set:
+ mlxsw_sp1_nve_vxlan_config_clear(mlxsw_sp);
+err_config_set:
+ mlxsw_sp_nve_parsing_set(mlxsw_sp, MLXSW_SP_NVE_DEFAULT_PARSING_DEPTH,
+ config->udp_dport);
+ return err;
+}
+
+static void mlxsw_sp1_nve_vxlan_fini(struct mlxsw_sp_nve *nve)
+{
+ struct mlxsw_sp_nve_config *config = &nve->config;
+ struct mlxsw_sp *mlxsw_sp = nve->mlxsw_sp;
+
+ mlxsw_sp_router_nve_demote_decap(mlxsw_sp, config->ul_tb_id,
+ config->ul_proto, &config->ul_sip);
+ mlxsw_sp1_nve_vxlan_config_clear(mlxsw_sp);
+ mlxsw_sp_nve_parsing_set(mlxsw_sp, MLXSW_SP_NVE_DEFAULT_PARSING_DEPTH,
+ config->udp_dport);
+}
+
+const struct mlxsw_sp_nve_ops mlxsw_sp1_nve_vxlan_ops = {
+ .type = MLXSW_SP_NVE_TYPE_VXLAN,
+ .can_offload = mlxsw_sp1_nve_vxlan_can_offload,
+ .nve_config = mlxsw_sp_nve_vxlan_config,
+ .init = mlxsw_sp1_nve_vxlan_init,
+ .fini = mlxsw_sp1_nve_vxlan_fini,
+};
+
+static bool mlxsw_sp2_nve_vxlan_can_offload(const struct mlxsw_sp_nve *nve,
+ const struct net_device *dev,
+ struct netlink_ext_ack *extack)
+{
+ return false;
+}
+
+static int mlxsw_sp2_nve_vxlan_init(struct mlxsw_sp_nve *nve,
+ const struct mlxsw_sp_nve_config *config)
+{
+ return -EOPNOTSUPP;
+}
+
+static void mlxsw_sp2_nve_vxlan_fini(struct mlxsw_sp_nve *nve)
+{
+}
+
+const struct mlxsw_sp_nve_ops mlxsw_sp2_nve_vxlan_ops = {
+ .type = MLXSW_SP_NVE_TYPE_VXLAN,
+ .can_offload = mlxsw_sp2_nve_vxlan_can_offload,
+ .nve_config = mlxsw_sp_nve_vxlan_config,
+ .init = mlxsw_sp2_nve_vxlan_init,
+ .fini = mlxsw_sp2_nve_vxlan_fini,
+};
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
index 2ab9cf25a08a..9e9bb57134f2 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
@@ -366,6 +366,7 @@ enum mlxsw_sp_fib_entry_type {
* encapsulating entries.)
*/
MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP,
+ MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP,
};
struct mlxsw_sp_nexthop_group;
@@ -741,6 +742,19 @@ static struct mlxsw_sp_vr *mlxsw_sp_vr_find(struct mlxsw_sp *mlxsw_sp,
return NULL;
}
+int mlxsw_sp_router_tb_id_vr_id(struct mlxsw_sp *mlxsw_sp, u32 tb_id,
+ u16 *vr_id)
+{
+ struct mlxsw_sp_vr *vr;
+
+ vr = mlxsw_sp_vr_find(mlxsw_sp, tb_id);
+ if (!vr)
+ return -ESRCH;
+ *vr_id = vr->id;
+
+ return 0;
+}
+
static struct mlxsw_sp_fib *mlxsw_sp_vr_fib(const struct mlxsw_sp_vr *vr,
enum mlxsw_sp_l3proto proto)
{
@@ -1128,6 +1142,52 @@ mlxsw_sp_ipip_entry_promote_decap(struct mlxsw_sp *mlxsw_sp,
mlxsw_sp_ipip_entry_demote_decap(mlxsw_sp, ipip_entry);
}
+static struct mlxsw_sp_fib_entry *
+mlxsw_sp_router_ip2me_fib_entry_find(struct mlxsw_sp *mlxsw_sp, u32 tb_id,
+ enum mlxsw_sp_l3proto proto,
+ const union mlxsw_sp_l3addr *addr,
+ enum mlxsw_sp_fib_entry_type type)
+{
+ struct mlxsw_sp_fib_entry *fib_entry;
+ struct mlxsw_sp_fib_node *fib_node;
+ unsigned char addr_prefix_len;
+ struct mlxsw_sp_fib *fib;
+ struct mlxsw_sp_vr *vr;
+ const void *addrp;
+ size_t addr_len;
+ u32 addr4;
+
+ vr = mlxsw_sp_vr_find(mlxsw_sp, tb_id);
+ if (!vr)
+ return NULL;
+ fib = mlxsw_sp_vr_fib(vr, proto);
+
+ switch (proto) {
+ case MLXSW_SP_L3_PROTO_IPV4:
+ addr4 = be32_to_cpu(addr->addr4);
+ addrp = &addr4;
+ addr_len = 4;
+ addr_prefix_len = 32;
+ break;
+ case MLXSW_SP_L3_PROTO_IPV6: /* fall through */
+ default:
+ WARN_ON(1);
+ return NULL;
+ }
+
+ fib_node = mlxsw_sp_fib_node_lookup(fib, addrp, addr_len,
+ addr_prefix_len);
+ if (!fib_node || list_empty(&fib_node->entry_list))
+ return NULL;
+
+ fib_entry = list_first_entry(&fib_node->entry_list,
+ struct mlxsw_sp_fib_entry, list);
+ if (fib_entry->type != type)
+ return NULL;
+
+ return fib_entry;
+}
+
/* Given an IPIP entry, find the corresponding decap route. */
static struct mlxsw_sp_fib_entry *
mlxsw_sp_ipip_entry_find_decap(struct mlxsw_sp *mlxsw_sp,
@@ -1765,6 +1825,56 @@ mlxsw_sp_netdevice_ipip_ul_event(struct mlxsw_sp *mlxsw_sp,
return 0;
}
+int mlxsw_sp_router_nve_promote_decap(struct mlxsw_sp *mlxsw_sp, u32 ul_tb_id,
+ enum mlxsw_sp_l3proto ul_proto,
+ const union mlxsw_sp_l3addr *ul_sip,
+ u32 tunnel_index)
+{
+ enum mlxsw_sp_fib_entry_type type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP;
+ struct mlxsw_sp_fib_entry *fib_entry;
+ int err;
+
+ /* It is valid to create a tunnel with a local IP and only later
+ * assign this IP address to a local interface
+ */
+ fib_entry = mlxsw_sp_router_ip2me_fib_entry_find(mlxsw_sp, ul_tb_id,
+ ul_proto, ul_sip,
+ type);
+ if (!fib_entry)
+ return 0;
+
+ fib_entry->decap.tunnel_index = tunnel_index;
+ fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP;
+
+ err = mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry);
+ if (err)
+ goto err_fib_entry_update;
+
+ return 0;
+
+err_fib_entry_update:
+ fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP;
+ mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry);
+ return err;
+}
+
+void mlxsw_sp_router_nve_demote_decap(struct mlxsw_sp *mlxsw_sp, u32 ul_tb_id,
+ enum mlxsw_sp_l3proto ul_proto,
+ const union mlxsw_sp_l3addr *ul_sip)
+{
+ enum mlxsw_sp_fib_entry_type type = MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP;
+ struct mlxsw_sp_fib_entry *fib_entry;
+
+ fib_entry = mlxsw_sp_router_ip2me_fib_entry_find(mlxsw_sp, ul_tb_id,
+ ul_proto, ul_sip,
+ type);
+ if (!fib_entry)
+ return;
+
+ fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP;
+ mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry);
+}
+
struct mlxsw_sp_neigh_key {
struct neighbour *n;
};
@@ -3815,6 +3925,7 @@ mlxsw_sp_fib_entry_should_offload(const struct mlxsw_sp_fib_entry *fib_entry)
case MLXSW_SP_FIB_ENTRY_TYPE_LOCAL:
return !!nh_group->nh_rif;
case MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP:
+ case MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP:
return true;
default:
return false;
@@ -3848,7 +3959,8 @@ mlxsw_sp_fib4_entry_offload_set(struct mlxsw_sp_fib_entry *fib_entry)
int i;
if (fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_LOCAL ||
- fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP) {
+ fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP ||
+ fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP) {
nh_grp->nexthops->key.fib_nh->nh_flags |= RTNH_F_OFFLOAD;
return;
}
@@ -4072,6 +4184,18 @@ mlxsw_sp_fib_entry_op_ipip_decap(struct mlxsw_sp *mlxsw_sp,
fib_entry->decap.tunnel_index);
}
+static int mlxsw_sp_fib_entry_op_nve_decap(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_fib_entry *fib_entry,
+ enum mlxsw_reg_ralue_op op)
+{
+ char ralue_pl[MLXSW_REG_RALUE_LEN];
+
+ mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op);
+ mlxsw_reg_ralue_act_ip2me_tun_pack(ralue_pl,
+ fib_entry->decap.tunnel_index);
+ return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
+}
+
static int __mlxsw_sp_fib_entry_op(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry *fib_entry,
enum mlxsw_reg_ralue_op op)
@@ -4086,6 +4210,8 @@ static int __mlxsw_sp_fib_entry_op(struct mlxsw_sp *mlxsw_sp,
case MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP:
return mlxsw_sp_fib_entry_op_ipip_decap(mlxsw_sp,
fib_entry, op);
+ case MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP:
+ return mlxsw_sp_fib_entry_op_nve_decap(mlxsw_sp, fib_entry, op);
}
return -EINVAL;
}
@@ -4121,6 +4247,7 @@ mlxsw_sp_fib4_entry_type_set(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry *fib_entry)
{
union mlxsw_sp_l3addr dip = { .addr4 = htonl(fen_info->dst) };
+ u32 tb_id = mlxsw_sp_fix_tb_id(fen_info->tb_id);
struct net_device *dev = fen_info->fi->fib_dev;
struct mlxsw_sp_ipip_entry *ipip_entry;
struct fib_info *fi = fen_info->fi;
@@ -4135,6 +4262,15 @@ mlxsw_sp_fib4_entry_type_set(struct mlxsw_sp *mlxsw_sp,
fib_entry,
ipip_entry);
}
+ if (mlxsw_sp_nve_ipv4_route_is_decap(mlxsw_sp, tb_id,
+ dip.addr4)) {
+ u32 t_index;
+
+ t_index = mlxsw_sp_nve_decap_tunnel_index_get(mlxsw_sp);
+ fib_entry->decap.tunnel_index = t_index;
+ fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP;
+ return 0;
+ }
/* fall through */
case RTN_BROADCAST:
fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h
index 1a60391daafa..3dbafdeaab2b 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h
@@ -7,17 +7,6 @@
#include "spectrum.h"
#include "reg.h"
-enum mlxsw_sp_l3proto {
- MLXSW_SP_L3_PROTO_IPV4,
- MLXSW_SP_L3_PROTO_IPV6,
-#define MLXSW_SP_L3_PROTO_MAX (MLXSW_SP_L3_PROTO_IPV6 + 1)
-};
-
-union mlxsw_sp_l3addr {
- __be32 addr4;
- struct in6_addr addr6;
-};
-
struct mlxsw_sp_rif_ipip_lb;
struct mlxsw_sp_rif_ipip_lb_config {
enum mlxsw_reg_ritr_loopback_ipip_type lb_ipipt;
@@ -35,8 +24,6 @@ struct mlxsw_sp_neigh_entry;
struct mlxsw_sp_nexthop;
struct mlxsw_sp_ipip_entry;
-struct mlxsw_sp_rif *mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp,
- const struct net_device *dev);
struct mlxsw_sp_rif *mlxsw_sp_rif_by_index(const struct mlxsw_sp *mlxsw_sp,
u16 rif_index);
u16 mlxsw_sp_rif_index(const struct mlxsw_sp_rif *rif);
@@ -44,9 +31,7 @@ u16 mlxsw_sp_ipip_lb_rif_index(const struct mlxsw_sp_rif_ipip_lb *rif);
u16 mlxsw_sp_ipip_lb_ul_vr_id(const struct mlxsw_sp_rif_ipip_lb *rif);
u32 mlxsw_sp_ipip_dev_ul_tb_id(const struct net_device *ol_dev);
int mlxsw_sp_rif_dev_ifindex(const struct mlxsw_sp_rif *rif);
-u8 mlxsw_sp_router_port(const struct mlxsw_sp *mlxsw_sp);
const struct net_device *mlxsw_sp_rif_dev(const struct mlxsw_sp_rif *rif);
-struct mlxsw_sp_fid *mlxsw_sp_rif_fid(const struct mlxsw_sp_rif *rif);
int mlxsw_sp_rif_counter_value_get(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_rif *rif,
enum mlxsw_sp_rif_counter_dir dir,
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
index db715da7bab7..739a51f0a366 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
@@ -15,9 +15,9 @@
#include <linux/rtnetlink.h>
#include <linux/netlink.h>
#include <net/switchdev.h>
+#include <net/vxlan.h>
#include "spectrum_span.h"
-#include "spectrum_router.h"
#include "spectrum_switchdev.h"
#include "spectrum.h"
#include "core.h"
@@ -84,9 +84,19 @@ struct mlxsw_sp_bridge_ops {
void (*port_leave)(struct mlxsw_sp_bridge_device *bridge_device,
struct mlxsw_sp_bridge_port *bridge_port,
struct mlxsw_sp_port *mlxsw_sp_port);
+ int (*vxlan_join)(struct mlxsw_sp_bridge_device *bridge_device,
+ const struct net_device *vxlan_dev,
+ struct netlink_ext_ack *extack);
+ void (*vxlan_leave)(struct mlxsw_sp_bridge_device *bridge_device,
+ const struct net_device *vxlan_dev);
struct mlxsw_sp_fid *
(*fid_get)(struct mlxsw_sp_bridge_device *bridge_device,
u16 vid);
+ struct mlxsw_sp_fid *
+ (*fid_lookup)(struct mlxsw_sp_bridge_device *bridge_device,
+ u16 vid);
+ u16 (*fid_vid)(struct mlxsw_sp_bridge_device *bridge_device,
+ const struct mlxsw_sp_fid *fid);
};
static int
@@ -1237,6 +1247,51 @@ static enum mlxsw_reg_sfd_op mlxsw_sp_sfd_op(bool adding)
MLXSW_REG_SFD_OP_WRITE_REMOVE;
}
+static int mlxsw_sp_port_fdb_tunnel_uc_op(struct mlxsw_sp *mlxsw_sp,
+ const char *mac, u16 fid,
+ enum mlxsw_sp_l3proto proto,
+ const union mlxsw_sp_l3addr *addr,
+ bool adding, bool dynamic)
+{
+ enum mlxsw_reg_sfd_uc_tunnel_protocol sfd_proto;
+ char *sfd_pl;
+ u8 num_rec;
+ u32 uip;
+ int err;
+
+ switch (proto) {
+ case MLXSW_SP_L3_PROTO_IPV4:
+ uip = be32_to_cpu(addr->addr4);
+ sfd_proto = MLXSW_REG_SFD_UC_TUNNEL_PROTOCOL_IPV4;
+ break;
+ case MLXSW_SP_L3_PROTO_IPV6: /* fall through */
+ default:
+ WARN_ON(1);
+ return -EOPNOTSUPP;
+ }
+
+ sfd_pl = kmalloc(MLXSW_REG_SFD_LEN, GFP_KERNEL);
+ if (!sfd_pl)
+ return -ENOMEM;
+
+ mlxsw_reg_sfd_pack(sfd_pl, mlxsw_sp_sfd_op(adding), 0);
+ mlxsw_reg_sfd_uc_tunnel_pack(sfd_pl, 0,
+ mlxsw_sp_sfd_rec_policy(dynamic), mac, fid,
+ MLXSW_REG_SFD_REC_ACTION_NOP, uip,
+ sfd_proto);
+ num_rec = mlxsw_reg_sfd_num_rec_get(sfd_pl);
+ err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl);
+ if (err)
+ goto out;
+
+ if (num_rec != mlxsw_reg_sfd_num_rec_get(sfd_pl))
+ err = -EBUSY;
+
+out:
+ kfree(sfd_pl);
+ return err;
+}
+
static int __mlxsw_sp_port_fdb_uc_op(struct mlxsw_sp *mlxsw_sp, u8 local_port,
const char *mac, u16 fid, bool adding,
enum mlxsw_reg_sfd_rec_action action,
@@ -1950,6 +2005,21 @@ mlxsw_sp_bridge_8021q_port_leave(struct mlxsw_sp_bridge_device *bridge_device,
mlxsw_sp_port_pvid_set(mlxsw_sp_port, 1);
}
+static int
+mlxsw_sp_bridge_8021q_vxlan_join(struct mlxsw_sp_bridge_device *bridge_device,
+ const struct net_device *vxlan_dev,
+ struct netlink_ext_ack *extack)
+{
+ WARN_ON(1);
+ return -EINVAL;
+}
+
+static void
+mlxsw_sp_bridge_8021q_vxlan_leave(struct mlxsw_sp_bridge_device *bridge_device,
+ const struct net_device *vxlan_dev)
+{
+}
+
static struct mlxsw_sp_fid *
mlxsw_sp_bridge_8021q_fid_get(struct mlxsw_sp_bridge_device *bridge_device,
u16 vid)
@@ -1959,10 +2029,29 @@ mlxsw_sp_bridge_8021q_fid_get(struct mlxsw_sp_bridge_device *bridge_device,
return mlxsw_sp_fid_8021q_get(mlxsw_sp, vid);
}
+static struct mlxsw_sp_fid *
+mlxsw_sp_bridge_8021q_fid_lookup(struct mlxsw_sp_bridge_device *bridge_device,
+ u16 vid)
+{
+ WARN_ON(1);
+ return NULL;
+}
+
+static u16
+mlxsw_sp_bridge_8021q_fid_vid(struct mlxsw_sp_bridge_device *bridge_device,
+ const struct mlxsw_sp_fid *fid)
+{
+ return mlxsw_sp_fid_8021q_vid(fid);
+}
+
static const struct mlxsw_sp_bridge_ops mlxsw_sp_bridge_8021q_ops = {
.port_join = mlxsw_sp_bridge_8021q_port_join,
.port_leave = mlxsw_sp_bridge_8021q_port_leave,
+ .vxlan_join = mlxsw_sp_bridge_8021q_vxlan_join,
+ .vxlan_leave = mlxsw_sp_bridge_8021q_vxlan_leave,
.fid_get = mlxsw_sp_bridge_8021q_fid_get,
+ .fid_lookup = mlxsw_sp_bridge_8021q_fid_lookup,
+ .fid_vid = mlxsw_sp_bridge_8021q_fid_vid,
};
static bool
@@ -2026,19 +2115,126 @@ mlxsw_sp_bridge_8021d_port_leave(struct mlxsw_sp_bridge_device *bridge_device,
mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan);
}
+static int
+mlxsw_sp_bridge_8021d_vxlan_join(struct mlxsw_sp_bridge_device *bridge_device,
+ const struct net_device *vxlan_dev,
+ struct netlink_ext_ack *extack)
+{
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_device->dev);
+ struct vxlan_dev *vxlan = netdev_priv(vxlan_dev);
+ struct mlxsw_sp_nve_params params = {
+ .type = MLXSW_SP_NVE_TYPE_VXLAN,
+ .vni = vxlan->cfg.vni,
+ .dev = vxlan_dev,
+ };
+ struct mlxsw_sp_fid *fid;
+ int err;
+
+ fid = mlxsw_sp_fid_8021d_lookup(mlxsw_sp, bridge_device->dev->ifindex);
+ if (!fid)
+ return -EINVAL;
+
+ if (mlxsw_sp_fid_vni_is_set(fid))
+ return -EINVAL;
+
+ err = mlxsw_sp_nve_fid_enable(mlxsw_sp, fid, &params, extack);
+ if (err)
+ goto err_nve_fid_enable;
+
+ /* The tunnel port does not hold a reference on the FID. Only
+ * local ports and the router port
+ */
+ mlxsw_sp_fid_put(fid);
+
+ return 0;
+
+err_nve_fid_enable:
+ mlxsw_sp_fid_put(fid);
+ return err;
+}
+
+static void
+mlxsw_sp_bridge_8021d_vxlan_leave(struct mlxsw_sp_bridge_device *bridge_device,
+ const struct net_device *vxlan_dev)
+{
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_device->dev);
+ struct mlxsw_sp_fid *fid;
+
+ fid = mlxsw_sp_fid_8021d_lookup(mlxsw_sp, bridge_device->dev->ifindex);
+ if (WARN_ON(!fid))
+ return;
+
+ /* If the VxLAN device is down, then the FID does not have a VNI */
+ if (!mlxsw_sp_fid_vni_is_set(fid))
+ goto out;
+
+ mlxsw_sp_nve_fid_disable(mlxsw_sp, fid);
+out:
+ mlxsw_sp_fid_put(fid);
+}
+
static struct mlxsw_sp_fid *
mlxsw_sp_bridge_8021d_fid_get(struct mlxsw_sp_bridge_device *bridge_device,
u16 vid)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_device->dev);
+ struct net_device *vxlan_dev;
+ struct mlxsw_sp_fid *fid;
+ int err;
+
+ fid = mlxsw_sp_fid_8021d_get(mlxsw_sp, bridge_device->dev->ifindex);
+ if (IS_ERR(fid))
+ return fid;
+
+ if (mlxsw_sp_fid_vni_is_set(fid))
+ return fid;
+
+ vxlan_dev = mlxsw_sp_bridge_vxlan_dev_find(bridge_device->dev);
+ if (!vxlan_dev)
+ return fid;
+
+ if (!netif_running(vxlan_dev))
+ return fid;
+
+ err = mlxsw_sp_bridge_8021d_vxlan_join(bridge_device, vxlan_dev, NULL);
+ if (err)
+ goto err_vxlan_join;
+
+ return fid;
+
+err_vxlan_join:
+ mlxsw_sp_fid_put(fid);
+ return ERR_PTR(err);
+}
+
+static struct mlxsw_sp_fid *
+mlxsw_sp_bridge_8021d_fid_lookup(struct mlxsw_sp_bridge_device *bridge_device,
+ u16 vid)
+{
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_device->dev);
- return mlxsw_sp_fid_8021d_get(mlxsw_sp, bridge_device->dev->ifindex);
+ /* The only valid VLAN for a VLAN-unaware bridge is 0 */
+ if (vid)
+ return NULL;
+
+ return mlxsw_sp_fid_8021d_lookup(mlxsw_sp, bridge_device->dev->ifindex);
+}
+
+static u16
+mlxsw_sp_bridge_8021d_fid_vid(struct mlxsw_sp_bridge_device *bridge_device,
+ const struct mlxsw_sp_fid *fid)
+{
+ return 0;
}
static const struct mlxsw_sp_bridge_ops mlxsw_sp_bridge_8021d_ops = {
.port_join = mlxsw_sp_bridge_8021d_port_join,
.port_leave = mlxsw_sp_bridge_8021d_port_leave,
+ .vxlan_join = mlxsw_sp_bridge_8021d_vxlan_join,
+ .vxlan_leave = mlxsw_sp_bridge_8021d_vxlan_leave,
.fid_get = mlxsw_sp_bridge_8021d_fid_get,
+ .fid_lookup = mlxsw_sp_bridge_8021d_fid_lookup,
+ .fid_vid = mlxsw_sp_bridge_8021d_fid_vid,
};
int mlxsw_sp_port_bridge_join(struct mlxsw_sp_port *mlxsw_sp_port,
@@ -2088,15 +2284,43 @@ void mlxsw_sp_port_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_port,
mlxsw_sp_bridge_port_put(mlxsw_sp->bridge, bridge_port);
}
+int mlxsw_sp_bridge_vxlan_join(struct mlxsw_sp *mlxsw_sp,
+ const struct net_device *br_dev,
+ const struct net_device *vxlan_dev,
+ struct netlink_ext_ack *extack)
+{
+ struct mlxsw_sp_bridge_device *bridge_device;
+
+ bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, br_dev);
+ if (WARN_ON(!bridge_device))
+ return -EINVAL;
+
+ return bridge_device->ops->vxlan_join(bridge_device, vxlan_dev, extack);
+}
+
+void mlxsw_sp_bridge_vxlan_leave(struct mlxsw_sp *mlxsw_sp,
+ const struct net_device *br_dev,
+ const struct net_device *vxlan_dev)
+{
+ struct mlxsw_sp_bridge_device *bridge_device;
+
+ bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, br_dev);
+ if (WARN_ON(!bridge_device))
+ return;
+
+ bridge_device->ops->vxlan_leave(bridge_device, vxlan_dev);
+}
+
static void
mlxsw_sp_fdb_call_notifiers(enum switchdev_notifier_type type,
const char *mac, u16 vid,
- struct net_device *dev)
+ 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);
}
@@ -2148,7 +2372,7 @@ do_fdb_op:
if (!do_notification)
return;
type = adding ? SWITCHDEV_FDB_ADD_TO_BRIDGE : SWITCHDEV_FDB_DEL_TO_BRIDGE;
- mlxsw_sp_fdb_call_notifiers(type, mac, vid, bridge_port->dev);
+ mlxsw_sp_fdb_call_notifiers(type, mac, vid, bridge_port->dev, adding);
return;
@@ -2208,7 +2432,7 @@ do_fdb_op:
if (!do_notification)
return;
type = adding ? SWITCHDEV_FDB_ADD_TO_BRIDGE : SWITCHDEV_FDB_DEL_TO_BRIDGE;
- mlxsw_sp_fdb_call_notifiers(type, mac, vid, bridge_port->dev);
+ mlxsw_sp_fdb_call_notifiers(type, mac, vid, bridge_port->dev, adding);
return;
@@ -2284,12 +2508,127 @@ out:
struct mlxsw_sp_switchdev_event_work {
struct work_struct work;
- struct switchdev_notifier_fdb_info fdb_info;
+ union {
+ struct switchdev_notifier_fdb_info fdb_info;
+ struct switchdev_notifier_vxlan_fdb_info vxlan_fdb_info;
+ };
struct net_device *dev;
unsigned long event;
};
-static void mlxsw_sp_switchdev_event_work(struct work_struct *work)
+static void
+mlxsw_sp_switchdev_vxlan_addr_convert(const union vxlan_addr *vxlan_addr,
+ enum mlxsw_sp_l3proto *proto,
+ union mlxsw_sp_l3addr *addr)
+{
+ if (vxlan_addr->sa.sa_family == AF_INET) {
+ addr->addr4 = vxlan_addr->sin.sin_addr.s_addr;
+ *proto = MLXSW_SP_L3_PROTO_IPV4;
+ } else {
+ addr->addr6 = vxlan_addr->sin6.sin6_addr;
+ *proto = MLXSW_SP_L3_PROTO_IPV6;
+ }
+}
+
+static void
+mlxsw_sp_switchdev_bridge_vxlan_fdb_event(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_switchdev_event_work *
+ switchdev_work,
+ struct mlxsw_sp_fid *fid, __be32 vni)
+{
+ struct switchdev_notifier_vxlan_fdb_info vxlan_fdb_info;
+ struct switchdev_notifier_fdb_info *fdb_info;
+ struct net_device *dev = switchdev_work->dev;
+ enum mlxsw_sp_l3proto proto;
+ union mlxsw_sp_l3addr addr;
+ int err;
+
+ fdb_info = &switchdev_work->fdb_info;
+ err = vxlan_fdb_find_uc(dev, fdb_info->addr, vni, &vxlan_fdb_info);
+ if (err)
+ return;
+
+ mlxsw_sp_switchdev_vxlan_addr_convert(&vxlan_fdb_info.remote_ip,
+ &proto, &addr);
+
+ switch (switchdev_work->event) {
+ case SWITCHDEV_FDB_ADD_TO_DEVICE:
+ err = mlxsw_sp_port_fdb_tunnel_uc_op(mlxsw_sp,
+ vxlan_fdb_info.eth_addr,
+ mlxsw_sp_fid_index(fid),
+ proto, &addr, true, false);
+ if (err)
+ return;
+ vxlan_fdb_info.offloaded = true;
+ call_switchdev_notifiers(SWITCHDEV_VXLAN_FDB_OFFLOADED, dev,
+ &vxlan_fdb_info.info);
+ mlxsw_sp_fdb_call_notifiers(SWITCHDEV_FDB_OFFLOADED,
+ vxlan_fdb_info.eth_addr,
+ fdb_info->vid, dev, true);
+ break;
+ case SWITCHDEV_FDB_DEL_TO_DEVICE:
+ err = mlxsw_sp_port_fdb_tunnel_uc_op(mlxsw_sp,
+ vxlan_fdb_info.eth_addr,
+ mlxsw_sp_fid_index(fid),
+ proto, &addr, false,
+ false);
+ vxlan_fdb_info.offloaded = false;
+ call_switchdev_notifiers(SWITCHDEV_VXLAN_FDB_OFFLOADED, dev,
+ &vxlan_fdb_info.info);
+ break;
+ }
+}
+
+static void
+mlxsw_sp_switchdev_bridge_nve_fdb_event(struct mlxsw_sp_switchdev_event_work *
+ switchdev_work)
+{
+ struct mlxsw_sp_bridge_device *bridge_device;
+ struct net_device *dev = switchdev_work->dev;
+ struct net_device *br_dev;
+ struct mlxsw_sp *mlxsw_sp;
+ struct mlxsw_sp_fid *fid;
+ __be32 vni;
+ int err;
+
+ if (switchdev_work->event != SWITCHDEV_FDB_ADD_TO_DEVICE &&
+ switchdev_work->event != SWITCHDEV_FDB_DEL_TO_DEVICE)
+ return;
+
+ if (!switchdev_work->fdb_info.added_by_user)
+ return;
+
+ if (!netif_running(dev))
+ return;
+ br_dev = netdev_master_upper_dev_get(dev);
+ if (!br_dev)
+ return;
+ if (!netif_is_bridge_master(br_dev))
+ return;
+ mlxsw_sp = mlxsw_sp_lower_get(br_dev);
+ if (!mlxsw_sp)
+ return;
+ bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, br_dev);
+ if (!bridge_device)
+ return;
+
+ fid = bridge_device->ops->fid_lookup(bridge_device,
+ switchdev_work->fdb_info.vid);
+ if (!fid)
+ return;
+
+ err = mlxsw_sp_fid_vni(fid, &vni);
+ if (err)
+ goto out;
+
+ mlxsw_sp_switchdev_bridge_vxlan_fdb_event(mlxsw_sp, switchdev_work, fid,
+ vni);
+
+out:
+ mlxsw_sp_fid_put(fid);
+}
+
+static void mlxsw_sp_switchdev_bridge_fdb_event_work(struct work_struct *work)
{
struct mlxsw_sp_switchdev_event_work *switchdev_work =
container_of(work, struct mlxsw_sp_switchdev_event_work, work);
@@ -2299,6 +2638,11 @@ static void mlxsw_sp_switchdev_event_work(struct work_struct *work)
int err;
rtnl_lock();
+ if (netif_is_vxlan(dev)) {
+ mlxsw_sp_switchdev_bridge_nve_fdb_event(switchdev_work);
+ goto out;
+ }
+
mlxsw_sp_port = mlxsw_sp_port_dev_lower_find(dev);
if (!mlxsw_sp_port)
goto out;
@@ -2313,12 +2657,10 @@ static void mlxsw_sp_switchdev_event_work(struct work_struct *work)
break;
mlxsw_sp_fdb_call_notifiers(SWITCHDEV_FDB_OFFLOADED,
fdb_info->addr,
- fdb_info->vid, dev);
+ fdb_info->vid, dev, true);
break;
case SWITCHDEV_FDB_DEL_TO_DEVICE:
fdb_info = &switchdev_work->fdb_info;
- if (!fdb_info->added_by_user)
- break;
mlxsw_sp_port_fdb_set(mlxsw_sp_port, fdb_info, false);
break;
case SWITCHDEV_FDB_ADD_TO_BRIDGE: /* fall through */
@@ -2338,22 +2680,213 @@ out:
dev_put(dev);
}
+static void
+mlxsw_sp_switchdev_vxlan_fdb_add(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_switchdev_event_work *
+ switchdev_work)
+{
+ struct switchdev_notifier_vxlan_fdb_info *vxlan_fdb_info;
+ struct mlxsw_sp_bridge_device *bridge_device;
+ struct net_device *dev = switchdev_work->dev;
+ u8 all_zeros_mac[ETH_ALEN] = { 0 };
+ enum mlxsw_sp_l3proto proto;
+ union mlxsw_sp_l3addr addr;
+ struct net_device *br_dev;
+ struct mlxsw_sp_fid *fid;
+ u16 vid;
+ int err;
+
+ vxlan_fdb_info = &switchdev_work->vxlan_fdb_info;
+ br_dev = netdev_master_upper_dev_get(dev);
+
+ bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, br_dev);
+ if (!bridge_device)
+ return;
+
+ fid = mlxsw_sp_fid_lookup_by_vni(mlxsw_sp, vxlan_fdb_info->vni);
+ if (!fid)
+ return;
+
+ mlxsw_sp_switchdev_vxlan_addr_convert(&vxlan_fdb_info->remote_ip,
+ &proto, &addr);
+
+ if (ether_addr_equal(vxlan_fdb_info->eth_addr, all_zeros_mac)) {
+ err = mlxsw_sp_nve_flood_ip_add(mlxsw_sp, fid, proto, &addr);
+ if (err) {
+ mlxsw_sp_fid_put(fid);
+ return;
+ }
+ vxlan_fdb_info->offloaded = true;
+ call_switchdev_notifiers(SWITCHDEV_VXLAN_FDB_OFFLOADED, dev,
+ &vxlan_fdb_info->info);
+ mlxsw_sp_fid_put(fid);
+ return;
+ }
+
+ /* The device has a single FDB table, whereas Linux has two - one
+ * in the bridge driver and another in the VxLAN driver. We only
+ * program an entry to the device if the MAC points to the VxLAN
+ * device in the bridge's FDB table
+ */
+ vid = bridge_device->ops->fid_vid(bridge_device, fid);
+ if (br_fdb_find_port(br_dev, vxlan_fdb_info->eth_addr, vid) != dev)
+ goto err_br_fdb_find;
+
+ err = mlxsw_sp_port_fdb_tunnel_uc_op(mlxsw_sp, vxlan_fdb_info->eth_addr,
+ mlxsw_sp_fid_index(fid), proto,
+ &addr, true, false);
+ if (err)
+ goto err_fdb_tunnel_uc_op;
+ vxlan_fdb_info->offloaded = true;
+ call_switchdev_notifiers(SWITCHDEV_VXLAN_FDB_OFFLOADED, dev,
+ &vxlan_fdb_info->info);
+ mlxsw_sp_fdb_call_notifiers(SWITCHDEV_FDB_OFFLOADED,
+ vxlan_fdb_info->eth_addr, vid, dev, true);
+
+ mlxsw_sp_fid_put(fid);
+
+ return;
+
+err_fdb_tunnel_uc_op:
+err_br_fdb_find:
+ mlxsw_sp_fid_put(fid);
+}
+
+static void
+mlxsw_sp_switchdev_vxlan_fdb_del(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_switchdev_event_work *
+ switchdev_work)
+{
+ struct switchdev_notifier_vxlan_fdb_info *vxlan_fdb_info;
+ struct mlxsw_sp_bridge_device *bridge_device;
+ struct net_device *dev = switchdev_work->dev;
+ struct net_device *br_dev = netdev_master_upper_dev_get(dev);
+ u8 all_zeros_mac[ETH_ALEN] = { 0 };
+ enum mlxsw_sp_l3proto proto;
+ union mlxsw_sp_l3addr addr;
+ struct mlxsw_sp_fid *fid;
+ u16 vid;
+
+ vxlan_fdb_info = &switchdev_work->vxlan_fdb_info;
+
+ bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, br_dev);
+ if (!bridge_device)
+ return;
+
+ fid = mlxsw_sp_fid_lookup_by_vni(mlxsw_sp, vxlan_fdb_info->vni);
+ if (!fid)
+ return;
+
+ mlxsw_sp_switchdev_vxlan_addr_convert(&vxlan_fdb_info->remote_ip,
+ &proto, &addr);
+
+ if (ether_addr_equal(vxlan_fdb_info->eth_addr, all_zeros_mac)) {
+ mlxsw_sp_nve_flood_ip_del(mlxsw_sp, fid, proto, &addr);
+ mlxsw_sp_fid_put(fid);
+ return;
+ }
+
+ mlxsw_sp_port_fdb_tunnel_uc_op(mlxsw_sp, vxlan_fdb_info->eth_addr,
+ mlxsw_sp_fid_index(fid), proto, &addr,
+ false, false);
+ vid = bridge_device->ops->fid_vid(bridge_device, fid);
+ mlxsw_sp_fdb_call_notifiers(SWITCHDEV_FDB_OFFLOADED,
+ vxlan_fdb_info->eth_addr, vid, dev, false);
+
+ mlxsw_sp_fid_put(fid);
+}
+
+static void mlxsw_sp_switchdev_vxlan_fdb_event_work(struct work_struct *work)
+{
+ struct mlxsw_sp_switchdev_event_work *switchdev_work =
+ container_of(work, struct mlxsw_sp_switchdev_event_work, work);
+ struct net_device *dev = switchdev_work->dev;
+ struct mlxsw_sp *mlxsw_sp;
+ struct net_device *br_dev;
+
+ rtnl_lock();
+
+ if (!netif_running(dev))
+ goto out;
+ br_dev = netdev_master_upper_dev_get(dev);
+ if (!br_dev)
+ goto out;
+ if (!netif_is_bridge_master(br_dev))
+ goto out;
+ mlxsw_sp = mlxsw_sp_lower_get(br_dev);
+ if (!mlxsw_sp)
+ goto out;
+
+ switch (switchdev_work->event) {
+ case SWITCHDEV_VXLAN_FDB_ADD_TO_DEVICE:
+ mlxsw_sp_switchdev_vxlan_fdb_add(mlxsw_sp, switchdev_work);
+ break;
+ case SWITCHDEV_VXLAN_FDB_DEL_TO_DEVICE:
+ mlxsw_sp_switchdev_vxlan_fdb_del(mlxsw_sp, switchdev_work);
+ break;
+ }
+
+out:
+ rtnl_unlock();
+ kfree(switchdev_work);
+ dev_put(dev);
+}
+
+static int
+mlxsw_sp_switchdev_vxlan_work_prepare(struct mlxsw_sp_switchdev_event_work *
+ switchdev_work,
+ struct switchdev_notifier_info *info)
+{
+ struct vxlan_dev *vxlan = netdev_priv(switchdev_work->dev);
+ struct switchdev_notifier_vxlan_fdb_info *vxlan_fdb_info;
+ struct vxlan_config *cfg = &vxlan->cfg;
+
+ vxlan_fdb_info = container_of(info,
+ struct switchdev_notifier_vxlan_fdb_info,
+ info);
+
+ if (vxlan_fdb_info->remote_port != cfg->dst_port)
+ return -EOPNOTSUPP;
+ if (vxlan_fdb_info->remote_vni != cfg->vni)
+ return -EOPNOTSUPP;
+ if (vxlan_fdb_info->vni != cfg->vni)
+ return -EOPNOTSUPP;
+ if (vxlan_fdb_info->remote_ifindex)
+ return -EOPNOTSUPP;
+ if (is_multicast_ether_addr(vxlan_fdb_info->eth_addr))
+ return -EOPNOTSUPP;
+ if (vxlan_addr_multicast(&vxlan_fdb_info->remote_ip))
+ return -EOPNOTSUPP;
+
+ switchdev_work->vxlan_fdb_info = *vxlan_fdb_info;
+
+ return 0;
+}
+
/* Called under rcu_read_lock() */
static int mlxsw_sp_switchdev_event(struct notifier_block *unused,
unsigned long event, void *ptr)
{
struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
struct mlxsw_sp_switchdev_event_work *switchdev_work;
- struct switchdev_notifier_fdb_info *fdb_info = ptr;
+ struct switchdev_notifier_fdb_info *fdb_info;
+ struct switchdev_notifier_info *info = ptr;
+ struct net_device *br_dev;
+ int err;
- if (!mlxsw_sp_port_dev_lower_find_rcu(dev))
+ /* Tunnel devices are not our uppers, so check their master instead */
+ br_dev = netdev_master_upper_dev_get_rcu(dev);
+ if (!br_dev)
+ return NOTIFY_DONE;
+ if (!netif_is_bridge_master(br_dev))
+ return NOTIFY_DONE;
+ if (!mlxsw_sp_port_dev_lower_find_rcu(br_dev))
return NOTIFY_DONE;
switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC);
if (!switchdev_work)
return NOTIFY_BAD;
- INIT_WORK(&switchdev_work->work, mlxsw_sp_switchdev_event_work);
switchdev_work->dev = dev;
switchdev_work->event = event;
@@ -2362,6 +2895,11 @@ static int mlxsw_sp_switchdev_event(struct notifier_block *unused,
case SWITCHDEV_FDB_DEL_TO_DEVICE: /* fall through */
case SWITCHDEV_FDB_ADD_TO_BRIDGE: /* fall through */
case SWITCHDEV_FDB_DEL_TO_BRIDGE:
+ fdb_info = container_of(info,
+ struct switchdev_notifier_fdb_info,
+ info);
+ INIT_WORK(&switchdev_work->work,
+ mlxsw_sp_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);
@@ -2375,6 +2913,16 @@ static int mlxsw_sp_switchdev_event(struct notifier_block *unused,
*/
dev_hold(dev);
break;
+ case SWITCHDEV_VXLAN_FDB_ADD_TO_DEVICE: /* fall through */
+ case SWITCHDEV_VXLAN_FDB_DEL_TO_DEVICE:
+ INIT_WORK(&switchdev_work->work,
+ mlxsw_sp_switchdev_vxlan_fdb_event_work);
+ err = mlxsw_sp_switchdev_vxlan_work_prepare(switchdev_work,
+ info);
+ if (err)
+ goto err_vxlan_work_prepare;
+ dev_hold(dev);
+ break;
default:
kfree(switchdev_work);
return NOTIFY_DONE;
@@ -2384,6 +2932,7 @@ static int mlxsw_sp_switchdev_event(struct notifier_block *unused,
return NOTIFY_DONE;
+err_vxlan_work_prepare:
err_addr_alloc:
kfree(switchdev_work);
return NOTIFY_BAD;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/trap.h b/drivers/net/ethernet/mellanox/mlxsw/trap.h
index 53020724c2f6..6f18f4d3322a 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/trap.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/trap.h
@@ -24,6 +24,7 @@ enum {
MLXSW_TRAP_ID_IGMP_V3_REPORT = 0x34,
MLXSW_TRAP_ID_PKT_SAMPLE = 0x38,
MLXSW_TRAP_ID_FID_MISS = 0x3D,
+ MLXSW_TRAP_ID_DECAP_ECN0 = 0x40,
MLXSW_TRAP_ID_ARPBC = 0x50,
MLXSW_TRAP_ID_ARPUC = 0x51,
MLXSW_TRAP_ID_MTUERROR = 0x52,
@@ -59,6 +60,7 @@ enum {
MLXSW_TRAP_ID_IPV6_MC_LINK_LOCAL_DEST = 0x91,
MLXSW_TRAP_ID_HOST_MISS_IPV6 = 0x92,
MLXSW_TRAP_ID_IPIP_DECAP_ERROR = 0xB1,
+ MLXSW_TRAP_ID_NVE_ENCAP_ARP = 0xBD,
MLXSW_TRAP_ID_ROUTER_ALERT_IPV4 = 0xD6,
MLXSW_TRAP_ID_ROUTER_ALERT_IPV6 = 0xD7,
MLXSW_TRAP_ID_ACL0 = 0x1C0,
diff --git a/drivers/net/ethernet/micrel/ks8695net.c b/drivers/net/ethernet/micrel/ks8695net.c
index bd51e057e915..b881f5d4a7f9 100644
--- a/drivers/net/ethernet/micrel/ks8695net.c
+++ b/drivers/net/ethernet/micrel/ks8695net.c
@@ -1164,7 +1164,7 @@ ks8695_timeout(struct net_device *ndev)
* sk_buff and adds it to the TX ring. It then kicks the TX DMA
* engine to ensure transmission begins.
*/
-static int
+static netdev_tx_t
ks8695_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{
struct ks8695_priv *ksp = netdev_priv(ndev);
diff --git a/drivers/net/ethernet/micrel/ks8851_mll.c b/drivers/net/ethernet/micrel/ks8851_mll.c
index 0e9719fbc624..35f8c9ef204d 100644
--- a/drivers/net/ethernet/micrel/ks8851_mll.c
+++ b/drivers/net/ethernet/micrel/ks8851_mll.c
@@ -1021,9 +1021,9 @@ static void ks_write_qmu(struct ks_net *ks, u8 *pdata, u16 len)
* spin_lock_irqsave is required because tx and rx should be mutual exclusive.
* So while tx is in-progress, prevent IRQ interrupt from happenning.
*/
-static int ks_start_xmit(struct sk_buff *skb, struct net_device *netdev)
+static netdev_tx_t ks_start_xmit(struct sk_buff *skb, struct net_device *netdev)
{
- int retv = NETDEV_TX_OK;
+ netdev_tx_t retv = NETDEV_TX_OK;
struct ks_net *ks = netdev_priv(netdev);
disable_irq(netdev->irq);
diff --git a/drivers/net/ethernet/microchip/Kconfig b/drivers/net/ethernet/microchip/Kconfig
index 16bd3f44dbe8..cf1d49149cc8 100644
--- a/drivers/net/ethernet/microchip/Kconfig
+++ b/drivers/net/ethernet/microchip/Kconfig
@@ -5,7 +5,6 @@
config NET_VENDOR_MICROCHIP
bool "Microchip devices"
default y
- depends on SPI
---help---
If you have a network (Ethernet) card belonging to this class, say Y.
diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c
index 001b5f714c1b..867cddba840f 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.c
+++ b/drivers/net/ethernet/microchip/lan743x_main.c
@@ -999,7 +999,6 @@ static int lan743x_phy_open(struct lan743x_adapter *adapter)
struct phy_device *phydev;
struct net_device *netdev;
int ret = -EIO;
- u32 mii_adv;
netdev = adapter->netdev;
phydev = phy_find_first(adapter->mdiobus);
@@ -1013,13 +1012,11 @@ static int lan743x_phy_open(struct lan743x_adapter *adapter)
goto return_error;
/* MAC doesn't support 1000T Half */
- phydev->supported &= ~SUPPORTED_1000baseT_Half;
+ phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
/* support both flow controls */
+ phy_support_asym_pause(phydev);
phy->fc_request_control = (FLOW_CTRL_RX | FLOW_CTRL_TX);
- phydev->advertising &= ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause);
- mii_adv = (u32)mii_advertise_flowctrl(phy->fc_request_control);
- phydev->advertising |= mii_adv_to_ethtool_adv_t(mii_adv);
phy->fc_autoneg = phydev->autoneg;
phy_start(phydev);
diff --git a/drivers/net/ethernet/microchip/lan743x_ptp.c b/drivers/net/ethernet/microchip/lan743x_ptp.c
index ccdf9123f26f..b2109eca81fd 100644
--- a/drivers/net/ethernet/microchip/lan743x_ptp.c
+++ b/drivers/net/ethernet/microchip/lan743x_ptp.c
@@ -977,8 +977,8 @@ void lan743x_ptp_close(struct lan743x_adapter *adapter)
lan743x_ptp_disable(adapter);
}
-void lan743x_ptp_set_sync_ts_insert(struct lan743x_adapter *adapter,
- bool ts_insert_enable)
+static void lan743x_ptp_set_sync_ts_insert(struct lan743x_adapter *adapter,
+ bool ts_insert_enable)
{
u32 ptp_tx_mod = lan743x_csr_read(adapter, PTP_TX_MOD);
diff --git a/drivers/net/ethernet/mscc/Kconfig b/drivers/net/ethernet/mscc/Kconfig
index 36c84625d54e..bcec0587cf61 100644
--- a/drivers/net/ethernet/mscc/Kconfig
+++ b/drivers/net/ethernet/mscc/Kconfig
@@ -23,6 +23,8 @@ config MSCC_OCELOT_SWITCH
config MSCC_OCELOT_SWITCH_OCELOT
tristate "Ocelot switch driver on Ocelot"
depends on MSCC_OCELOT_SWITCH
+ depends on GENERIC_PHY
+ depends on OF_NET
help
This driver supports the Ocelot network switch device as present on
the Ocelot SoCs.
diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c
index 1a4f2bb48ead..3238b9ee42f3 100644
--- a/drivers/net/ethernet/mscc/ocelot.c
+++ b/drivers/net/ethernet/mscc/ocelot.c
@@ -133,9 +133,9 @@ static inline int ocelot_vlant_wait_for_completion(struct ocelot *ocelot)
{
unsigned int val, timeout = 10;
- /* Wait for the issued mac table command to be completed, or timeout.
- * When the command read from ANA_TABLES_MACACCESS is
- * MACACCESS_CMD_IDLE, the issued command completed successfully.
+ /* Wait for the issued vlan table command to be completed, or timeout.
+ * When the command read from ANA_TABLES_VLANACCESS is
+ * VLANACCESS_CMD_IDLE, the issued command completed successfully.
*/
do {
val = ocelot_read(ocelot, ANA_TABLES_VLANACCESS);
@@ -472,6 +472,7 @@ static int ocelot_port_open(struct net_device *dev)
{
struct ocelot_port *port = netdev_priv(dev);
struct ocelot *ocelot = port->ocelot;
+ enum phy_mode phy_mode;
int err;
/* Enable receiving frames on the port, and activate auto-learning of
@@ -482,8 +483,21 @@ static int ocelot_port_open(struct net_device *dev)
ANA_PORT_PORT_CFG_PORTID_VAL(port->chip_port),
ANA_PORT_PORT_CFG, port->chip_port);
+ if (port->serdes) {
+ if (port->phy_mode == PHY_INTERFACE_MODE_SGMII)
+ phy_mode = PHY_MODE_SGMII;
+ else
+ phy_mode = PHY_MODE_QSGMII;
+
+ err = phy_set_mode(port->serdes, phy_mode);
+ if (err) {
+ netdev_err(dev, "Could not set mode of SerDes\n");
+ return err;
+ }
+ }
+
err = phy_connect_direct(dev, port->phy, &ocelot_port_adjust_link,
- PHY_INTERFACE_MODE_NA);
+ port->phy_mode);
if (err) {
netdev_err(dev, "Could not attach to PHY\n");
return err;
@@ -1606,7 +1620,7 @@ int ocelot_probe_port(struct ocelot *ocelot, u8 port,
dev->ethtool_ops = &ocelot_ethtool_ops;
dev->switchdev_ops = &ocelot_port_switchdev_ops;
- dev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER;
+ dev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_RXFCS;
dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
memcpy(dev->dev_addr, ocelot->base_mac, ETH_ALEN);
diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h
index 616bec30dfa3..62c7c8eb00d9 100644
--- a/drivers/net/ethernet/mscc/ocelot.h
+++ b/drivers/net/ethernet/mscc/ocelot.h
@@ -11,12 +11,13 @@
#include <linux/bitops.h>
#include <linux/etherdevice.h>
#include <linux/if_vlan.h>
+#include <linux/phy.h>
+#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include "ocelot_ana.h"
#include "ocelot_dev.h"
-#include "ocelot_hsio.h"
#include "ocelot_qsys.h"
#include "ocelot_rew.h"
#include "ocelot_sys.h"
@@ -333,79 +334,6 @@ enum ocelot_reg {
SYS_CM_DATA_RD,
SYS_CM_OP,
SYS_CM_DATA,
- HSIO_PLL5G_CFG0 = HSIO << TARGET_OFFSET,
- HSIO_PLL5G_CFG1,
- HSIO_PLL5G_CFG2,
- HSIO_PLL5G_CFG3,
- HSIO_PLL5G_CFG4,
- HSIO_PLL5G_CFG5,
- HSIO_PLL5G_CFG6,
- HSIO_PLL5G_STATUS0,
- HSIO_PLL5G_STATUS1,
- HSIO_PLL5G_BIST_CFG0,
- HSIO_PLL5G_BIST_CFG1,
- HSIO_PLL5G_BIST_CFG2,
- HSIO_PLL5G_BIST_STAT0,
- HSIO_PLL5G_BIST_STAT1,
- HSIO_RCOMP_CFG0,
- HSIO_RCOMP_STATUS,
- HSIO_SYNC_ETH_CFG,
- HSIO_SYNC_ETH_PLL_CFG,
- HSIO_S1G_DES_CFG,
- HSIO_S1G_IB_CFG,
- HSIO_S1G_OB_CFG,
- HSIO_S1G_SER_CFG,
- HSIO_S1G_COMMON_CFG,
- HSIO_S1G_PLL_CFG,
- HSIO_S1G_PLL_STATUS,
- HSIO_S1G_DFT_CFG0,
- HSIO_S1G_DFT_CFG1,
- HSIO_S1G_DFT_CFG2,
- HSIO_S1G_TP_CFG,
- HSIO_S1G_RC_PLL_BIST_CFG,
- HSIO_S1G_MISC_CFG,
- HSIO_S1G_DFT_STATUS,
- HSIO_S1G_MISC_STATUS,
- HSIO_MCB_S1G_ADDR_CFG,
- HSIO_S6G_DIG_CFG,
- HSIO_S6G_DFT_CFG0,
- HSIO_S6G_DFT_CFG1,
- HSIO_S6G_DFT_CFG2,
- HSIO_S6G_TP_CFG0,
- HSIO_S6G_TP_CFG1,
- HSIO_S6G_RC_PLL_BIST_CFG,
- HSIO_S6G_MISC_CFG,
- HSIO_S6G_OB_ANEG_CFG,
- HSIO_S6G_DFT_STATUS,
- HSIO_S6G_ERR_CNT,
- HSIO_S6G_MISC_STATUS,
- HSIO_S6G_DES_CFG,
- HSIO_S6G_IB_CFG,
- HSIO_S6G_IB_CFG1,
- HSIO_S6G_IB_CFG2,
- HSIO_S6G_IB_CFG3,
- HSIO_S6G_IB_CFG4,
- HSIO_S6G_IB_CFG5,
- HSIO_S6G_OB_CFG,
- HSIO_S6G_OB_CFG1,
- HSIO_S6G_SER_CFG,
- HSIO_S6G_COMMON_CFG,
- HSIO_S6G_PLL_CFG,
- HSIO_S6G_ACJTAG_CFG,
- HSIO_S6G_GP_CFG,
- HSIO_S6G_IB_STATUS0,
- HSIO_S6G_IB_STATUS1,
- HSIO_S6G_ACJTAG_STATUS,
- HSIO_S6G_PLL_STATUS,
- HSIO_S6G_REVID,
- HSIO_MCB_S6G_ADDR_CFG,
- HSIO_HW_CFG,
- HSIO_HW_QSGMII_CFG,
- HSIO_HW_QSGMII_STAT,
- HSIO_CLK_CFG,
- HSIO_TEMP_SENSOR_CTRL,
- HSIO_TEMP_SENSOR_CFG,
- HSIO_TEMP_SENSOR_STAT,
};
enum ocelot_regfield {
@@ -527,6 +455,9 @@ struct ocelot_port {
u8 vlan_aware;
u64 *stats;
+
+ phy_interface_t phy_mode;
+ struct phy *serdes;
};
u32 __ocelot_read_ix(struct ocelot *ocelot, u32 reg, u32 offset);
diff --git a/drivers/net/ethernet/mscc/ocelot_board.c b/drivers/net/ethernet/mscc/ocelot_board.c
index 3cdf63e35b53..4c23d18bbf44 100644
--- a/drivers/net/ethernet/mscc/ocelot_board.c
+++ b/drivers/net/ethernet/mscc/ocelot_board.c
@@ -6,9 +6,11 @@
*/
#include <linux/interrupt.h>
#include <linux/module.h>
+#include <linux/of_net.h>
#include <linux/netdevice.h>
#include <linux/of_mdio.h>
#include <linux/of_platform.h>
+#include <linux/mfd/syscon.h>
#include <linux/skbuff.h>
#include "ocelot.h"
@@ -126,11 +128,16 @@ static irqreturn_t ocelot_xtr_irq_handler(int irq, void *arg)
len += sz;
} while (len < buf_len);
- /* Read the FCS and discard it */
+ /* Read the FCS */
sz = ocelot_rx_frame_word(ocelot, grp, false, &val);
/* Update the statistics if part of the FCS was read before */
len -= ETH_FCS_LEN - sz;
+ if (unlikely(dev->features & NETIF_F_RXFCS)) {
+ buf = (u32 *)skb_put(skb, ETH_FCS_LEN);
+ *buf = val;
+ }
+
if (sz < 0) {
err = sz;
break;
@@ -168,6 +175,7 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
struct device_node *ports, *portnp;
struct ocelot *ocelot;
+ struct regmap *hsio;
u32 val;
struct {
@@ -179,7 +187,6 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
{ QSYS, "qsys" },
{ ANA, "ana" },
{ QS, "qs" },
- { HSIO, "hsio" },
};
if (!np && !pdev->dev.platform_data)
@@ -202,6 +209,14 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
ocelot->targets[res[i].id] = target;
}
+ hsio = syscon_regmap_lookup_by_compatible("mscc,ocelot-hsio");
+ if (IS_ERR(hsio)) {
+ dev_err(&pdev->dev, "missing hsio syscon\n");
+ return PTR_ERR(hsio);
+ }
+
+ ocelot->targets[HSIO] = hsio;
+
err = ocelot_chip_init(ocelot);
if (err)
return err;
@@ -244,18 +259,11 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&ocelot->multicast);
ocelot_init(ocelot);
- ocelot_rmw(ocelot, HSIO_HW_CFG_DEV1G_4_MODE |
- HSIO_HW_CFG_DEV1G_6_MODE |
- HSIO_HW_CFG_DEV1G_9_MODE,
- HSIO_HW_CFG_DEV1G_4_MODE |
- HSIO_HW_CFG_DEV1G_6_MODE |
- HSIO_HW_CFG_DEV1G_9_MODE,
- HSIO_HW_CFG);
-
for_each_available_child_of_node(ports, portnp) {
struct device_node *phy_node;
struct phy_device *phy;
struct resource *res;
+ struct phy *serdes;
void __iomem *regs;
char res_name[8];
u32 port;
@@ -280,10 +288,43 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
continue;
err = ocelot_probe_port(ocelot, port, regs, phy);
- if (err) {
- dev_err(&pdev->dev, "failed to probe ports\n");
+ if (err)
+ return err;
+
+ err = of_get_phy_mode(portnp);
+ if (err < 0)
+ ocelot->ports[port]->phy_mode = PHY_INTERFACE_MODE_NA;
+ else
+ ocelot->ports[port]->phy_mode = err;
+
+ switch (ocelot->ports[port]->phy_mode) {
+ case PHY_INTERFACE_MODE_NA:
+ continue;
+ case PHY_INTERFACE_MODE_SGMII:
+ break;
+ case PHY_INTERFACE_MODE_QSGMII:
+ break;
+ default:
+ dev_err(ocelot->dev,
+ "invalid phy mode for port%d, (Q)SGMII only\n",
+ port);
+ return -EINVAL;
+ }
+
+ serdes = devm_of_phy_get(ocelot->dev, portnp, NULL);
+ if (IS_ERR(serdes)) {
+ err = PTR_ERR(serdes);
+ if (err == -EPROBE_DEFER)
+ dev_dbg(ocelot->dev, "deferring probe\n");
+ else
+ dev_err(ocelot->dev,
+ "missing SerDes phys for port%d\n",
+ port);
+
goto err_probe_ports;
}
+
+ ocelot->ports[port]->serdes = serdes;
}
register_netdevice_notifier(&ocelot_netdevice_nb);
diff --git a/drivers/net/ethernet/mscc/ocelot_dev_gmii.h b/drivers/net/ethernet/mscc/ocelot_dev_gmii.h
deleted file mode 100644
index 6aa40ea223a2..000000000000
--- a/drivers/net/ethernet/mscc/ocelot_dev_gmii.h
+++ /dev/null
@@ -1,154 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
-/*
- * Microsemi Ocelot Switch driver
- *
- * Copyright (c) 2017 Microsemi Corporation
- */
-
-#ifndef _MSCC_OCELOT_DEV_GMII_H_
-#define _MSCC_OCELOT_DEV_GMII_H_
-
-#define DEV_GMII_PORT_MODE_CLOCK_CFG 0x0
-
-#define DEV_GMII_PORT_MODE_CLOCK_CFG_MAC_TX_RST BIT(5)
-#define DEV_GMII_PORT_MODE_CLOCK_CFG_MAC_RX_RST BIT(4)
-#define DEV_GMII_PORT_MODE_CLOCK_CFG_PORT_RST BIT(3)
-#define DEV_GMII_PORT_MODE_CLOCK_CFG_PHY_RST BIT(2)
-#define DEV_GMII_PORT_MODE_CLOCK_CFG_LINK_SPEED(x) ((x) & GENMASK(1, 0))
-#define DEV_GMII_PORT_MODE_CLOCK_CFG_LINK_SPEED_M GENMASK(1, 0)
-
-#define DEV_GMII_PORT_MODE_PORT_MISC 0x4
-
-#define DEV_GMII_PORT_MODE_PORT_MISC_MPLS_RX_ENA BIT(5)
-#define DEV_GMII_PORT_MODE_PORT_MISC_FWD_ERROR_ENA BIT(4)
-#define DEV_GMII_PORT_MODE_PORT_MISC_FWD_PAUSE_ENA BIT(3)
-#define DEV_GMII_PORT_MODE_PORT_MISC_FWD_CTRL_ENA BIT(2)
-#define DEV_GMII_PORT_MODE_PORT_MISC_GMII_LOOP_ENA BIT(1)
-#define DEV_GMII_PORT_MODE_PORT_MISC_DEV_LOOP_ENA BIT(0)
-
-#define DEV_GMII_PORT_MODE_EVENTS 0x8
-
-#define DEV_GMII_PORT_MODE_EEE_CFG 0xc
-
-#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_ENA BIT(22)
-#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_AGE(x) (((x) << 15) & GENMASK(21, 15))
-#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_AGE_M GENMASK(21, 15)
-#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_AGE_X(x) (((x) & GENMASK(21, 15)) >> 15)
-#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_WAKEUP(x) (((x) << 8) & GENMASK(14, 8))
-#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_WAKEUP_M GENMASK(14, 8)
-#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_WAKEUP_X(x) (((x) & GENMASK(14, 8)) >> 8)
-#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_HOLDOFF(x) (((x) << 1) & GENMASK(7, 1))
-#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_HOLDOFF_M GENMASK(7, 1)
-#define DEV_GMII_PORT_MODE_EEE_CFG_EEE_TIMER_HOLDOFF_X(x) (((x) & GENMASK(7, 1)) >> 1)
-#define DEV_GMII_PORT_MODE_EEE_CFG_PORT_LPI BIT(0)
-
-#define DEV_GMII_PORT_MODE_RX_PATH_DELAY 0x10
-
-#define DEV_GMII_PORT_MODE_TX_PATH_DELAY 0x14
-
-#define DEV_GMII_PORT_MODE_PTP_PREDICT_CFG 0x18
-
-#define DEV_GMII_MAC_CFG_STATUS_MAC_ENA_CFG 0x1c
-
-#define DEV_GMII_MAC_CFG_STATUS_MAC_ENA_CFG_RX_ENA BIT(4)
-#define DEV_GMII_MAC_CFG_STATUS_MAC_ENA_CFG_TX_ENA BIT(0)
-
-#define DEV_GMII_MAC_CFG_STATUS_MAC_MODE_CFG 0x20
-
-#define DEV_GMII_MAC_CFG_STATUS_MAC_MODE_CFG_FC_WORD_SYNC_ENA BIT(8)
-#define DEV_GMII_MAC_CFG_STATUS_MAC_MODE_CFG_GIGA_MODE_ENA BIT(4)
-#define DEV_GMII_MAC_CFG_STATUS_MAC_MODE_CFG_FDX_ENA BIT(0)
-
-#define DEV_GMII_MAC_CFG_STATUS_MAC_MAXLEN_CFG 0x24
-
-#define DEV_GMII_MAC_CFG_STATUS_MAC_TAGS_CFG 0x28
-
-#define DEV_GMII_MAC_CFG_STATUS_MAC_TAGS_CFG_TAG_ID(x) (((x) << 16) & GENMASK(31, 16))
-#define DEV_GMII_MAC_CFG_STATUS_MAC_TAGS_CFG_TAG_ID_M GENMASK(31, 16)
-#define DEV_GMII_MAC_CFG_STATUS_MAC_TAGS_CFG_TAG_ID_X(x) (((x) & GENMASK(31, 16)) >> 16)
-#define DEV_GMII_MAC_CFG_STATUS_MAC_TAGS_CFG_PB_ENA BIT(1)
-#define DEV_GMII_MAC_CFG_STATUS_MAC_TAGS_CFG_VLAN_AWR_ENA BIT(0)
-#define DEV_GMII_MAC_CFG_STATUS_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA BIT(2)
-
-#define DEV_GMII_MAC_CFG_STATUS_MAC_ADV_CHK_CFG 0x2c
-
-#define DEV_GMII_MAC_CFG_STATUS_MAC_ADV_CHK_CFG_LEN_DROP_ENA BIT(0)
-
-#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG 0x30
-
-#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_RESTORE_OLD_IPG_CHECK BIT(17)
-#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_REDUCED_TX_IFG BIT(16)
-#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_TX_IFG(x) (((x) << 8) & GENMASK(12, 8))
-#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_TX_IFG_M GENMASK(12, 8)
-#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_TX_IFG_X(x) (((x) & GENMASK(12, 8)) >> 8)
-#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_RX_IFG2(x) (((x) << 4) & GENMASK(7, 4))
-#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_RX_IFG2_M GENMASK(7, 4)
-#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_RX_IFG2_X(x) (((x) & GENMASK(7, 4)) >> 4)
-#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_RX_IFG1(x) ((x) & GENMASK(3, 0))
-#define DEV_GMII_MAC_CFG_STATUS_MAC_IFG_CFG_RX_IFG1_M GENMASK(3, 0)
-
-#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG 0x34
-
-#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_BYPASS_COL_SYNC BIT(26)
-#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_OB_ENA BIT(25)
-#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_WEXC_DIS BIT(24)
-#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_SEED(x) (((x) << 16) & GENMASK(23, 16))
-#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_SEED_M GENMASK(23, 16)
-#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_SEED_X(x) (((x) & GENMASK(23, 16)) >> 16)
-#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_SEED_LOAD BIT(12)
-#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_RETRY_AFTER_EXC_COL_ENA BIT(8)
-#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_LATE_COL_POS(x) ((x) & GENMASK(6, 0))
-#define DEV_GMII_MAC_CFG_STATUS_MAC_HDX_CFG_LATE_COL_POS_M GENMASK(6, 0)
-
-#define DEV_GMII_MAC_CFG_STATUS_MAC_DBG_CFG 0x38
-
-#define DEV_GMII_MAC_CFG_STATUS_MAC_DBG_CFG_TBI_MODE BIT(4)
-#define DEV_GMII_MAC_CFG_STATUS_MAC_DBG_CFG_IFG_CRS_EXT_CHK_ENA BIT(0)
-
-#define DEV_GMII_MAC_CFG_STATUS_MAC_FC_MAC_LOW_CFG 0x3c
-
-#define DEV_GMII_MAC_CFG_STATUS_MAC_FC_MAC_HIGH_CFG 0x40
-
-#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY 0x44
-
-#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_RX_IPG_SHRINK_STICKY BIT(9)
-#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_RX_PREAM_SHRINK_STICKY BIT(8)
-#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_RX_CARRIER_EXT_STICKY BIT(7)
-#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_RX_CARRIER_EXT_ERR_STICKY BIT(6)
-#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_RX_JUNK_STICKY BIT(5)
-#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_TX_RETRANSMIT_STICKY BIT(4)
-#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_TX_JAM_STICKY BIT(3)
-#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_TX_FIFO_OFLW_STICKY BIT(2)
-#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_TX_FRM_LEN_OVR_STICKY BIT(1)
-#define DEV_GMII_MAC_CFG_STATUS_MAC_STICKY_TX_ABORT_STICKY BIT(0)
-
-#define DEV_GMII_MM_CONFIG_ENABLE_CONFIG 0x48
-
-#define DEV_GMII_MM_CONFIG_ENABLE_CONFIG_MM_RX_ENA BIT(0)
-#define DEV_GMII_MM_CONFIG_ENABLE_CONFIG_MM_TX_ENA BIT(4)
-#define DEV_GMII_MM_CONFIG_ENABLE_CONFIG_KEEP_S_AFTER_D BIT(8)
-
-#define DEV_GMII_MM_CONFIG_VERIF_CONFIG 0x4c
-
-#define DEV_GMII_MM_CONFIG_VERIF_CONFIG_PRM_VERIFY_DIS BIT(0)
-#define DEV_GMII_MM_CONFIG_VERIF_CONFIG_PRM_VERIFY_TIME(x) (((x) << 4) & GENMASK(11, 4))
-#define DEV_GMII_MM_CONFIG_VERIF_CONFIG_PRM_VERIFY_TIME_M GENMASK(11, 4)
-#define DEV_GMII_MM_CONFIG_VERIF_CONFIG_PRM_VERIFY_TIME_X(x) (((x) & GENMASK(11, 4)) >> 4)
-#define DEV_GMII_MM_CONFIG_VERIF_CONFIG_VERIF_TIMER_UNITS(x) (((x) << 12) & GENMASK(13, 12))
-#define DEV_GMII_MM_CONFIG_VERIF_CONFIG_VERIF_TIMER_UNITS_M GENMASK(13, 12)
-#define DEV_GMII_MM_CONFIG_VERIF_CONFIG_VERIF_TIMER_UNITS_X(x) (((x) & GENMASK(13, 12)) >> 12)
-
-#define DEV_GMII_MM_STATISTICS_MM_STATUS 0x50
-
-#define DEV_GMII_MM_STATISTICS_MM_STATUS_PRMPT_ACTIVE_STATUS BIT(0)
-#define DEV_GMII_MM_STATISTICS_MM_STATUS_PRMPT_ACTIVE_STICKY BIT(4)
-#define DEV_GMII_MM_STATISTICS_MM_STATUS_PRMPT_VERIFY_STATE(x) (((x) << 8) & GENMASK(10, 8))
-#define DEV_GMII_MM_STATISTICS_MM_STATUS_PRMPT_VERIFY_STATE_M GENMASK(10, 8)
-#define DEV_GMII_MM_STATISTICS_MM_STATUS_PRMPT_VERIFY_STATE_X(x) (((x) & GENMASK(10, 8)) >> 8)
-#define DEV_GMII_MM_STATISTICS_MM_STATUS_UNEXP_RX_PFRM_STICKY BIT(12)
-#define DEV_GMII_MM_STATISTICS_MM_STATUS_UNEXP_TX_PFRM_STICKY BIT(16)
-#define DEV_GMII_MM_STATISTICS_MM_STATUS_MM_RX_FRAME_STATUS BIT(20)
-#define DEV_GMII_MM_STATISTICS_MM_STATUS_MM_TX_FRAME_STATUS BIT(24)
-#define DEV_GMII_MM_STATISTICS_MM_STATUS_MM_TX_PRMPT_STATUS BIT(28)
-
-#endif
diff --git a/drivers/net/ethernet/mscc/ocelot_hsio.h b/drivers/net/ethernet/mscc/ocelot_hsio.h
deleted file mode 100644
index d93ddec3931b..000000000000
--- a/drivers/net/ethernet/mscc/ocelot_hsio.h
+++ /dev/null
@@ -1,785 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
-/*
- * Microsemi Ocelot Switch driver
- *
- * Copyright (c) 2017 Microsemi Corporation
- */
-
-#ifndef _MSCC_OCELOT_HSIO_H_
-#define _MSCC_OCELOT_HSIO_H_
-
-#define HSIO_PLL5G_CFG0_ENA_ROT BIT(31)
-#define HSIO_PLL5G_CFG0_ENA_LANE BIT(30)
-#define HSIO_PLL5G_CFG0_ENA_CLKTREE BIT(29)
-#define HSIO_PLL5G_CFG0_DIV4 BIT(28)
-#define HSIO_PLL5G_CFG0_ENA_LOCK_FINE BIT(27)
-#define HSIO_PLL5G_CFG0_SELBGV820(x) (((x) << 23) & GENMASK(26, 23))
-#define HSIO_PLL5G_CFG0_SELBGV820_M GENMASK(26, 23)
-#define HSIO_PLL5G_CFG0_SELBGV820_X(x) (((x) & GENMASK(26, 23)) >> 23)
-#define HSIO_PLL5G_CFG0_LOOP_BW_RES(x) (((x) << 18) & GENMASK(22, 18))
-#define HSIO_PLL5G_CFG0_LOOP_BW_RES_M GENMASK(22, 18)
-#define HSIO_PLL5G_CFG0_LOOP_BW_RES_X(x) (((x) & GENMASK(22, 18)) >> 18)
-#define HSIO_PLL5G_CFG0_SELCPI(x) (((x) << 16) & GENMASK(17, 16))
-#define HSIO_PLL5G_CFG0_SELCPI_M GENMASK(17, 16)
-#define HSIO_PLL5G_CFG0_SELCPI_X(x) (((x) & GENMASK(17, 16)) >> 16)
-#define HSIO_PLL5G_CFG0_ENA_VCO_CONTRH BIT(15)
-#define HSIO_PLL5G_CFG0_ENA_CP1 BIT(14)
-#define HSIO_PLL5G_CFG0_ENA_VCO_BUF BIT(13)
-#define HSIO_PLL5G_CFG0_ENA_BIAS BIT(12)
-#define HSIO_PLL5G_CFG0_CPU_CLK_DIV(x) (((x) << 6) & GENMASK(11, 6))
-#define HSIO_PLL5G_CFG0_CPU_CLK_DIV_M GENMASK(11, 6)
-#define HSIO_PLL5G_CFG0_CPU_CLK_DIV_X(x) (((x) & GENMASK(11, 6)) >> 6)
-#define HSIO_PLL5G_CFG0_CORE_CLK_DIV(x) ((x) & GENMASK(5, 0))
-#define HSIO_PLL5G_CFG0_CORE_CLK_DIV_M GENMASK(5, 0)
-
-#define HSIO_PLL5G_CFG1_ENA_DIRECT BIT(18)
-#define HSIO_PLL5G_CFG1_ROT_SPEED BIT(17)
-#define HSIO_PLL5G_CFG1_ROT_DIR BIT(16)
-#define HSIO_PLL5G_CFG1_READBACK_DATA_SEL BIT(15)
-#define HSIO_PLL5G_CFG1_RC_ENABLE BIT(14)
-#define HSIO_PLL5G_CFG1_RC_CTRL_DATA(x) (((x) << 6) & GENMASK(13, 6))
-#define HSIO_PLL5G_CFG1_RC_CTRL_DATA_M GENMASK(13, 6)
-#define HSIO_PLL5G_CFG1_RC_CTRL_DATA_X(x) (((x) & GENMASK(13, 6)) >> 6)
-#define HSIO_PLL5G_CFG1_QUARTER_RATE BIT(5)
-#define HSIO_PLL5G_CFG1_PWD_TX BIT(4)
-#define HSIO_PLL5G_CFG1_PWD_RX BIT(3)
-#define HSIO_PLL5G_CFG1_OUT_OF_RANGE_RECAL_ENA BIT(2)
-#define HSIO_PLL5G_CFG1_HALF_RATE BIT(1)
-#define HSIO_PLL5G_CFG1_FORCE_SET_ENA BIT(0)
-
-#define HSIO_PLL5G_CFG2_ENA_TEST_MODE BIT(30)
-#define HSIO_PLL5G_CFG2_ENA_PFD_IN_FLIP BIT(29)
-#define HSIO_PLL5G_CFG2_ENA_VCO_NREF_TESTOUT BIT(28)
-#define HSIO_PLL5G_CFG2_ENA_FBTESTOUT BIT(27)
-#define HSIO_PLL5G_CFG2_ENA_RCPLL BIT(26)
-#define HSIO_PLL5G_CFG2_ENA_CP2 BIT(25)
-#define HSIO_PLL5G_CFG2_ENA_CLK_BYPASS1 BIT(24)
-#define HSIO_PLL5G_CFG2_AMPC_SEL(x) (((x) << 16) & GENMASK(23, 16))
-#define HSIO_PLL5G_CFG2_AMPC_SEL_M GENMASK(23, 16)
-#define HSIO_PLL5G_CFG2_AMPC_SEL_X(x) (((x) & GENMASK(23, 16)) >> 16)
-#define HSIO_PLL5G_CFG2_ENA_CLK_BYPASS BIT(15)
-#define HSIO_PLL5G_CFG2_PWD_AMPCTRL_N BIT(14)
-#define HSIO_PLL5G_CFG2_ENA_AMPCTRL BIT(13)
-#define HSIO_PLL5G_CFG2_ENA_AMP_CTRL_FORCE BIT(12)
-#define HSIO_PLL5G_CFG2_FRC_FSM_POR BIT(11)
-#define HSIO_PLL5G_CFG2_DISABLE_FSM_POR BIT(10)
-#define HSIO_PLL5G_CFG2_GAIN_TEST(x) (((x) << 5) & GENMASK(9, 5))
-#define HSIO_PLL5G_CFG2_GAIN_TEST_M GENMASK(9, 5)
-#define HSIO_PLL5G_CFG2_GAIN_TEST_X(x) (((x) & GENMASK(9, 5)) >> 5)
-#define HSIO_PLL5G_CFG2_EN_RESET_OVERRUN BIT(4)
-#define HSIO_PLL5G_CFG2_EN_RESET_LIM_DET BIT(3)
-#define HSIO_PLL5G_CFG2_EN_RESET_FRQ_DET BIT(2)
-#define HSIO_PLL5G_CFG2_DISABLE_FSM BIT(1)
-#define HSIO_PLL5G_CFG2_ENA_GAIN_TEST BIT(0)
-
-#define HSIO_PLL5G_CFG3_TEST_ANA_OUT_SEL(x) (((x) << 22) & GENMASK(23, 22))
-#define HSIO_PLL5G_CFG3_TEST_ANA_OUT_SEL_M GENMASK(23, 22)
-#define HSIO_PLL5G_CFG3_TEST_ANA_OUT_SEL_X(x) (((x) & GENMASK(23, 22)) >> 22)
-#define HSIO_PLL5G_CFG3_TESTOUT_SEL(x) (((x) << 19) & GENMASK(21, 19))
-#define HSIO_PLL5G_CFG3_TESTOUT_SEL_M GENMASK(21, 19)
-#define HSIO_PLL5G_CFG3_TESTOUT_SEL_X(x) (((x) & GENMASK(21, 19)) >> 19)
-#define HSIO_PLL5G_CFG3_ENA_ANA_TEST_OUT BIT(18)
-#define HSIO_PLL5G_CFG3_ENA_TEST_OUT BIT(17)
-#define HSIO_PLL5G_CFG3_SEL_FBDCLK BIT(16)
-#define HSIO_PLL5G_CFG3_SEL_CML_CMOS_PFD BIT(15)
-#define HSIO_PLL5G_CFG3_RST_FB_N BIT(14)
-#define HSIO_PLL5G_CFG3_FORCE_VCO_CONTRH BIT(13)
-#define HSIO_PLL5G_CFG3_FORCE_LO BIT(12)
-#define HSIO_PLL5G_CFG3_FORCE_HI BIT(11)
-#define HSIO_PLL5G_CFG3_FORCE_ENA BIT(10)
-#define HSIO_PLL5G_CFG3_FORCE_CP BIT(9)
-#define HSIO_PLL5G_CFG3_FBDIVSEL_TST_ENA BIT(8)
-#define HSIO_PLL5G_CFG3_FBDIVSEL(x) ((x) & GENMASK(7, 0))
-#define HSIO_PLL5G_CFG3_FBDIVSEL_M GENMASK(7, 0)
-
-#define HSIO_PLL5G_CFG4_IB_BIAS_CTRL(x) (((x) << 16) & GENMASK(23, 16))
-#define HSIO_PLL5G_CFG4_IB_BIAS_CTRL_M GENMASK(23, 16)
-#define HSIO_PLL5G_CFG4_IB_BIAS_CTRL_X(x) (((x) & GENMASK(23, 16)) >> 16)
-#define HSIO_PLL5G_CFG4_IB_CTRL(x) ((x) & GENMASK(15, 0))
-#define HSIO_PLL5G_CFG4_IB_CTRL_M GENMASK(15, 0)
-
-#define HSIO_PLL5G_CFG5_OB_BIAS_CTRL(x) (((x) << 16) & GENMASK(23, 16))
-#define HSIO_PLL5G_CFG5_OB_BIAS_CTRL_M GENMASK(23, 16)
-#define HSIO_PLL5G_CFG5_OB_BIAS_CTRL_X(x) (((x) & GENMASK(23, 16)) >> 16)
-#define HSIO_PLL5G_CFG5_OB_CTRL(x) ((x) & GENMASK(15, 0))
-#define HSIO_PLL5G_CFG5_OB_CTRL_M GENMASK(15, 0)
-
-#define HSIO_PLL5G_CFG6_REFCLK_SEL_SRC BIT(23)
-#define HSIO_PLL5G_CFG6_REFCLK_SEL(x) (((x) << 20) & GENMASK(22, 20))
-#define HSIO_PLL5G_CFG6_REFCLK_SEL_M GENMASK(22, 20)
-#define HSIO_PLL5G_CFG6_REFCLK_SEL_X(x) (((x) & GENMASK(22, 20)) >> 20)
-#define HSIO_PLL5G_CFG6_REFCLK_SRC BIT(19)
-#define HSIO_PLL5G_CFG6_POR_DEL_SEL(x) (((x) << 16) & GENMASK(17, 16))
-#define HSIO_PLL5G_CFG6_POR_DEL_SEL_M GENMASK(17, 16)
-#define HSIO_PLL5G_CFG6_POR_DEL_SEL_X(x) (((x) & GENMASK(17, 16)) >> 16)
-#define HSIO_PLL5G_CFG6_DIV125REF_SEL(x) (((x) << 8) & GENMASK(15, 8))
-#define HSIO_PLL5G_CFG6_DIV125REF_SEL_M GENMASK(15, 8)
-#define HSIO_PLL5G_CFG6_DIV125REF_SEL_X(x) (((x) & GENMASK(15, 8)) >> 8)
-#define HSIO_PLL5G_CFG6_ENA_REFCLKC2 BIT(7)
-#define HSIO_PLL5G_CFG6_ENA_FBCLKC2 BIT(6)
-#define HSIO_PLL5G_CFG6_DDR_CLK_DIV(x) ((x) & GENMASK(5, 0))
-#define HSIO_PLL5G_CFG6_DDR_CLK_DIV_M GENMASK(5, 0)
-
-#define HSIO_PLL5G_STATUS0_RANGE_LIM BIT(12)
-#define HSIO_PLL5G_STATUS0_OUT_OF_RANGE_ERR BIT(11)
-#define HSIO_PLL5G_STATUS0_CALIBRATION_ERR BIT(10)
-#define HSIO_PLL5G_STATUS0_CALIBRATION_DONE BIT(9)
-#define HSIO_PLL5G_STATUS0_READBACK_DATA(x) (((x) << 1) & GENMASK(8, 1))
-#define HSIO_PLL5G_STATUS0_READBACK_DATA_M GENMASK(8, 1)
-#define HSIO_PLL5G_STATUS0_READBACK_DATA_X(x) (((x) & GENMASK(8, 1)) >> 1)
-#define HSIO_PLL5G_STATUS0_LOCK_STATUS BIT(0)
-
-#define HSIO_PLL5G_STATUS1_SIG_DEL(x) (((x) << 21) & GENMASK(28, 21))
-#define HSIO_PLL5G_STATUS1_SIG_DEL_M GENMASK(28, 21)
-#define HSIO_PLL5G_STATUS1_SIG_DEL_X(x) (((x) & GENMASK(28, 21)) >> 21)
-#define HSIO_PLL5G_STATUS1_GAIN_STAT(x) (((x) << 16) & GENMASK(20, 16))
-#define HSIO_PLL5G_STATUS1_GAIN_STAT_M GENMASK(20, 16)
-#define HSIO_PLL5G_STATUS1_GAIN_STAT_X(x) (((x) & GENMASK(20, 16)) >> 16)
-#define HSIO_PLL5G_STATUS1_FBCNT_DIF(x) (((x) << 4) & GENMASK(13, 4))
-#define HSIO_PLL5G_STATUS1_FBCNT_DIF_M GENMASK(13, 4)
-#define HSIO_PLL5G_STATUS1_FBCNT_DIF_X(x) (((x) & GENMASK(13, 4)) >> 4)
-#define HSIO_PLL5G_STATUS1_FSM_STAT(x) (((x) << 1) & GENMASK(3, 1))
-#define HSIO_PLL5G_STATUS1_FSM_STAT_M GENMASK(3, 1)
-#define HSIO_PLL5G_STATUS1_FSM_STAT_X(x) (((x) & GENMASK(3, 1)) >> 1)
-#define HSIO_PLL5G_STATUS1_FSM_LOCK BIT(0)
-
-#define HSIO_PLL5G_BIST_CFG0_PLLB_START_BIST BIT(31)
-#define HSIO_PLL5G_BIST_CFG0_PLLB_MEAS_MODE BIT(30)
-#define HSIO_PLL5G_BIST_CFG0_PLLB_LOCK_REPEAT(x) (((x) << 20) & GENMASK(23, 20))
-#define HSIO_PLL5G_BIST_CFG0_PLLB_LOCK_REPEAT_M GENMASK(23, 20)
-#define HSIO_PLL5G_BIST_CFG0_PLLB_LOCK_REPEAT_X(x) (((x) & GENMASK(23, 20)) >> 20)
-#define HSIO_PLL5G_BIST_CFG0_PLLB_LOCK_UNCERT(x) (((x) << 16) & GENMASK(19, 16))
-#define HSIO_PLL5G_BIST_CFG0_PLLB_LOCK_UNCERT_M GENMASK(19, 16)
-#define HSIO_PLL5G_BIST_CFG0_PLLB_LOCK_UNCERT_X(x) (((x) & GENMASK(19, 16)) >> 16)
-#define HSIO_PLL5G_BIST_CFG0_PLLB_DIV_FACTOR_PRE(x) ((x) & GENMASK(15, 0))
-#define HSIO_PLL5G_BIST_CFG0_PLLB_DIV_FACTOR_PRE_M GENMASK(15, 0)
-
-#define HSIO_PLL5G_BIST_STAT0_PLLB_FSM_STAT(x) (((x) << 4) & GENMASK(7, 4))
-#define HSIO_PLL5G_BIST_STAT0_PLLB_FSM_STAT_M GENMASK(7, 4)
-#define HSIO_PLL5G_BIST_STAT0_PLLB_FSM_STAT_X(x) (((x) & GENMASK(7, 4)) >> 4)
-#define HSIO_PLL5G_BIST_STAT0_PLLB_BUSY BIT(2)
-#define HSIO_PLL5G_BIST_STAT0_PLLB_DONE_N BIT(1)
-#define HSIO_PLL5G_BIST_STAT0_PLLB_FAIL BIT(0)
-
-#define HSIO_PLL5G_BIST_STAT1_PLLB_CNT_OUT(x) (((x) << 16) & GENMASK(31, 16))
-#define HSIO_PLL5G_BIST_STAT1_PLLB_CNT_OUT_M GENMASK(31, 16)
-#define HSIO_PLL5G_BIST_STAT1_PLLB_CNT_OUT_X(x) (((x) & GENMASK(31, 16)) >> 16)
-#define HSIO_PLL5G_BIST_STAT1_PLLB_CNT_REF_DIFF(x) ((x) & GENMASK(15, 0))
-#define HSIO_PLL5G_BIST_STAT1_PLLB_CNT_REF_DIFF_M GENMASK(15, 0)
-
-#define HSIO_RCOMP_CFG0_PWD_ENA BIT(13)
-#define HSIO_RCOMP_CFG0_RUN_CAL BIT(12)
-#define HSIO_RCOMP_CFG0_SPEED_SEL(x) (((x) << 10) & GENMASK(11, 10))
-#define HSIO_RCOMP_CFG0_SPEED_SEL_M GENMASK(11, 10)
-#define HSIO_RCOMP_CFG0_SPEED_SEL_X(x) (((x) & GENMASK(11, 10)) >> 10)
-#define HSIO_RCOMP_CFG0_MODE_SEL(x) (((x) << 8) & GENMASK(9, 8))
-#define HSIO_RCOMP_CFG0_MODE_SEL_M GENMASK(9, 8)
-#define HSIO_RCOMP_CFG0_MODE_SEL_X(x) (((x) & GENMASK(9, 8)) >> 8)
-#define HSIO_RCOMP_CFG0_FORCE_ENA BIT(4)
-#define HSIO_RCOMP_CFG0_RCOMP_VAL(x) ((x) & GENMASK(3, 0))
-#define HSIO_RCOMP_CFG0_RCOMP_VAL_M GENMASK(3, 0)
-
-#define HSIO_RCOMP_STATUS_BUSY BIT(12)
-#define HSIO_RCOMP_STATUS_DELTA_ALERT BIT(7)
-#define HSIO_RCOMP_STATUS_RCOMP(x) ((x) & GENMASK(3, 0))
-#define HSIO_RCOMP_STATUS_RCOMP_M GENMASK(3, 0)
-
-#define HSIO_SYNC_ETH_CFG_RSZ 0x4
-
-#define HSIO_SYNC_ETH_CFG_SEL_RECO_CLK_SRC(x) (((x) << 4) & GENMASK(7, 4))
-#define HSIO_SYNC_ETH_CFG_SEL_RECO_CLK_SRC_M GENMASK(7, 4)
-#define HSIO_SYNC_ETH_CFG_SEL_RECO_CLK_SRC_X(x) (((x) & GENMASK(7, 4)) >> 4)
-#define HSIO_SYNC_ETH_CFG_SEL_RECO_CLK_DIV(x) (((x) << 1) & GENMASK(3, 1))
-#define HSIO_SYNC_ETH_CFG_SEL_RECO_CLK_DIV_M GENMASK(3, 1)
-#define HSIO_SYNC_ETH_CFG_SEL_RECO_CLK_DIV_X(x) (((x) & GENMASK(3, 1)) >> 1)
-#define HSIO_SYNC_ETH_CFG_RECO_CLK_ENA BIT(0)
-
-#define HSIO_SYNC_ETH_PLL_CFG_PLL_AUTO_SQUELCH_ENA BIT(0)
-
-#define HSIO_S1G_DES_CFG_DES_PHS_CTRL(x) (((x) << 13) & GENMASK(16, 13))
-#define HSIO_S1G_DES_CFG_DES_PHS_CTRL_M GENMASK(16, 13)
-#define HSIO_S1G_DES_CFG_DES_PHS_CTRL_X(x) (((x) & GENMASK(16, 13)) >> 13)
-#define HSIO_S1G_DES_CFG_DES_CPMD_SEL(x) (((x) << 11) & GENMASK(12, 11))
-#define HSIO_S1G_DES_CFG_DES_CPMD_SEL_M GENMASK(12, 11)
-#define HSIO_S1G_DES_CFG_DES_CPMD_SEL_X(x) (((x) & GENMASK(12, 11)) >> 11)
-#define HSIO_S1G_DES_CFG_DES_MBTR_CTRL(x) (((x) << 8) & GENMASK(10, 8))
-#define HSIO_S1G_DES_CFG_DES_MBTR_CTRL_M GENMASK(10, 8)
-#define HSIO_S1G_DES_CFG_DES_MBTR_CTRL_X(x) (((x) & GENMASK(10, 8)) >> 8)
-#define HSIO_S1G_DES_CFG_DES_BW_ANA(x) (((x) << 5) & GENMASK(7, 5))
-#define HSIO_S1G_DES_CFG_DES_BW_ANA_M GENMASK(7, 5)
-#define HSIO_S1G_DES_CFG_DES_BW_ANA_X(x) (((x) & GENMASK(7, 5)) >> 5)
-#define HSIO_S1G_DES_CFG_DES_SWAP_ANA BIT(4)
-#define HSIO_S1G_DES_CFG_DES_BW_HYST(x) (((x) << 1) & GENMASK(3, 1))
-#define HSIO_S1G_DES_CFG_DES_BW_HYST_M GENMASK(3, 1)
-#define HSIO_S1G_DES_CFG_DES_BW_HYST_X(x) (((x) & GENMASK(3, 1)) >> 1)
-#define HSIO_S1G_DES_CFG_DES_SWAP_HYST BIT(0)
-
-#define HSIO_S1G_IB_CFG_IB_FX100_ENA BIT(27)
-#define HSIO_S1G_IB_CFG_ACJTAG_HYST(x) (((x) << 24) & GENMASK(26, 24))
-#define HSIO_S1G_IB_CFG_ACJTAG_HYST_M GENMASK(26, 24)
-#define HSIO_S1G_IB_CFG_ACJTAG_HYST_X(x) (((x) & GENMASK(26, 24)) >> 24)
-#define HSIO_S1G_IB_CFG_IB_DET_LEV(x) (((x) << 19) & GENMASK(21, 19))
-#define HSIO_S1G_IB_CFG_IB_DET_LEV_M GENMASK(21, 19)
-#define HSIO_S1G_IB_CFG_IB_DET_LEV_X(x) (((x) & GENMASK(21, 19)) >> 19)
-#define HSIO_S1G_IB_CFG_IB_HYST_LEV BIT(14)
-#define HSIO_S1G_IB_CFG_IB_ENA_CMV_TERM BIT(13)
-#define HSIO_S1G_IB_CFG_IB_ENA_DC_COUPLING BIT(12)
-#define HSIO_S1G_IB_CFG_IB_ENA_DETLEV BIT(11)
-#define HSIO_S1G_IB_CFG_IB_ENA_HYST BIT(10)
-#define HSIO_S1G_IB_CFG_IB_ENA_OFFSET_COMP BIT(9)
-#define HSIO_S1G_IB_CFG_IB_EQ_GAIN(x) (((x) << 6) & GENMASK(8, 6))
-#define HSIO_S1G_IB_CFG_IB_EQ_GAIN_M GENMASK(8, 6)
-#define HSIO_S1G_IB_CFG_IB_EQ_GAIN_X(x) (((x) & GENMASK(8, 6)) >> 6)
-#define HSIO_S1G_IB_CFG_IB_SEL_CORNER_FREQ(x) (((x) << 4) & GENMASK(5, 4))
-#define HSIO_S1G_IB_CFG_IB_SEL_CORNER_FREQ_M GENMASK(5, 4)
-#define HSIO_S1G_IB_CFG_IB_SEL_CORNER_FREQ_X(x) (((x) & GENMASK(5, 4)) >> 4)
-#define HSIO_S1G_IB_CFG_IB_RESISTOR_CTRL(x) ((x) & GENMASK(3, 0))
-#define HSIO_S1G_IB_CFG_IB_RESISTOR_CTRL_M GENMASK(3, 0)
-
-#define HSIO_S1G_OB_CFG_OB_SLP(x) (((x) << 17) & GENMASK(18, 17))
-#define HSIO_S1G_OB_CFG_OB_SLP_M GENMASK(18, 17)
-#define HSIO_S1G_OB_CFG_OB_SLP_X(x) (((x) & GENMASK(18, 17)) >> 17)
-#define HSIO_S1G_OB_CFG_OB_AMP_CTRL(x) (((x) << 13) & GENMASK(16, 13))
-#define HSIO_S1G_OB_CFG_OB_AMP_CTRL_M GENMASK(16, 13)
-#define HSIO_S1G_OB_CFG_OB_AMP_CTRL_X(x) (((x) & GENMASK(16, 13)) >> 13)
-#define HSIO_S1G_OB_CFG_OB_CMM_BIAS_CTRL(x) (((x) << 10) & GENMASK(12, 10))
-#define HSIO_S1G_OB_CFG_OB_CMM_BIAS_CTRL_M GENMASK(12, 10)
-#define HSIO_S1G_OB_CFG_OB_CMM_BIAS_CTRL_X(x) (((x) & GENMASK(12, 10)) >> 10)
-#define HSIO_S1G_OB_CFG_OB_DIS_VCM_CTRL BIT(9)
-#define HSIO_S1G_OB_CFG_OB_EN_MEAS_VREG BIT(8)
-#define HSIO_S1G_OB_CFG_OB_VCM_CTRL(x) (((x) << 4) & GENMASK(7, 4))
-#define HSIO_S1G_OB_CFG_OB_VCM_CTRL_M GENMASK(7, 4)
-#define HSIO_S1G_OB_CFG_OB_VCM_CTRL_X(x) (((x) & GENMASK(7, 4)) >> 4)
-#define HSIO_S1G_OB_CFG_OB_RESISTOR_CTRL(x) ((x) & GENMASK(3, 0))
-#define HSIO_S1G_OB_CFG_OB_RESISTOR_CTRL_M GENMASK(3, 0)
-
-#define HSIO_S1G_SER_CFG_SER_IDLE BIT(9)
-#define HSIO_S1G_SER_CFG_SER_DEEMPH BIT(8)
-#define HSIO_S1G_SER_CFG_SER_CPMD_SEL BIT(7)
-#define HSIO_S1G_SER_CFG_SER_SWAP_CPMD BIT(6)
-#define HSIO_S1G_SER_CFG_SER_ALISEL(x) (((x) << 4) & GENMASK(5, 4))
-#define HSIO_S1G_SER_CFG_SER_ALISEL_M GENMASK(5, 4)
-#define HSIO_S1G_SER_CFG_SER_ALISEL_X(x) (((x) & GENMASK(5, 4)) >> 4)
-#define HSIO_S1G_SER_CFG_SER_ENHYS BIT(3)
-#define HSIO_S1G_SER_CFG_SER_BIG_WIN BIT(2)
-#define HSIO_S1G_SER_CFG_SER_EN_WIN BIT(1)
-#define HSIO_S1G_SER_CFG_SER_ENALI BIT(0)
-
-#define HSIO_S1G_COMMON_CFG_SYS_RST BIT(31)
-#define HSIO_S1G_COMMON_CFG_SE_AUTO_SQUELCH_ENA BIT(21)
-#define HSIO_S1G_COMMON_CFG_ENA_LANE BIT(18)
-#define HSIO_S1G_COMMON_CFG_PWD_RX BIT(17)
-#define HSIO_S1G_COMMON_CFG_PWD_TX BIT(16)
-#define HSIO_S1G_COMMON_CFG_LANE_CTRL(x) (((x) << 13) & GENMASK(15, 13))
-#define HSIO_S1G_COMMON_CFG_LANE_CTRL_M GENMASK(15, 13)
-#define HSIO_S1G_COMMON_CFG_LANE_CTRL_X(x) (((x) & GENMASK(15, 13)) >> 13)
-#define HSIO_S1G_COMMON_CFG_ENA_DIRECT BIT(12)
-#define HSIO_S1G_COMMON_CFG_ENA_ELOOP BIT(11)
-#define HSIO_S1G_COMMON_CFG_ENA_FLOOP BIT(10)
-#define HSIO_S1G_COMMON_CFG_ENA_ILOOP BIT(9)
-#define HSIO_S1G_COMMON_CFG_ENA_PLOOP BIT(8)
-#define HSIO_S1G_COMMON_CFG_HRATE BIT(7)
-#define HSIO_S1G_COMMON_CFG_IF_MODE BIT(0)
-
-#define HSIO_S1G_PLL_CFG_PLL_ENA_FB_DIV2 BIT(22)
-#define HSIO_S1G_PLL_CFG_PLL_ENA_RC_DIV2 BIT(21)
-#define HSIO_S1G_PLL_CFG_PLL_FSM_CTRL_DATA(x) (((x) << 8) & GENMASK(15, 8))
-#define HSIO_S1G_PLL_CFG_PLL_FSM_CTRL_DATA_M GENMASK(15, 8)
-#define HSIO_S1G_PLL_CFG_PLL_FSM_CTRL_DATA_X(x) (((x) & GENMASK(15, 8)) >> 8)
-#define HSIO_S1G_PLL_CFG_PLL_FSM_ENA BIT(7)
-#define HSIO_S1G_PLL_CFG_PLL_FSM_FORCE_SET_ENA BIT(6)
-#define HSIO_S1G_PLL_CFG_PLL_FSM_OOR_RECAL_ENA BIT(5)
-#define HSIO_S1G_PLL_CFG_PLL_RB_DATA_SEL BIT(3)
-
-#define HSIO_S1G_PLL_STATUS_PLL_CAL_NOT_DONE BIT(12)
-#define HSIO_S1G_PLL_STATUS_PLL_CAL_ERR BIT(11)
-#define HSIO_S1G_PLL_STATUS_PLL_OUT_OF_RANGE_ERR BIT(10)
-#define HSIO_S1G_PLL_STATUS_PLL_RB_DATA(x) ((x) & GENMASK(7, 0))
-#define HSIO_S1G_PLL_STATUS_PLL_RB_DATA_M GENMASK(7, 0)
-
-#define HSIO_S1G_DFT_CFG0_LAZYBIT BIT(31)
-#define HSIO_S1G_DFT_CFG0_INV_DIS BIT(23)
-#define HSIO_S1G_DFT_CFG0_PRBS_SEL(x) (((x) << 20) & GENMASK(21, 20))
-#define HSIO_S1G_DFT_CFG0_PRBS_SEL_M GENMASK(21, 20)
-#define HSIO_S1G_DFT_CFG0_PRBS_SEL_X(x) (((x) & GENMASK(21, 20)) >> 20)
-#define HSIO_S1G_DFT_CFG0_TEST_MODE(x) (((x) << 16) & GENMASK(18, 16))
-#define HSIO_S1G_DFT_CFG0_TEST_MODE_M GENMASK(18, 16)
-#define HSIO_S1G_DFT_CFG0_TEST_MODE_X(x) (((x) & GENMASK(18, 16)) >> 16)
-#define HSIO_S1G_DFT_CFG0_RX_PHS_CORR_DIS BIT(4)
-#define HSIO_S1G_DFT_CFG0_RX_PDSENS_ENA BIT(3)
-#define HSIO_S1G_DFT_CFG0_RX_DFT_ENA BIT(2)
-#define HSIO_S1G_DFT_CFG0_TX_DFT_ENA BIT(0)
-
-#define HSIO_S1G_DFT_CFG1_TX_JITTER_AMPL(x) (((x) << 8) & GENMASK(17, 8))
-#define HSIO_S1G_DFT_CFG1_TX_JITTER_AMPL_M GENMASK(17, 8)
-#define HSIO_S1G_DFT_CFG1_TX_JITTER_AMPL_X(x) (((x) & GENMASK(17, 8)) >> 8)
-#define HSIO_S1G_DFT_CFG1_TX_STEP_FREQ(x) (((x) << 4) & GENMASK(7, 4))
-#define HSIO_S1G_DFT_CFG1_TX_STEP_FREQ_M GENMASK(7, 4)
-#define HSIO_S1G_DFT_CFG1_TX_STEP_FREQ_X(x) (((x) & GENMASK(7, 4)) >> 4)
-#define HSIO_S1G_DFT_CFG1_TX_JI_ENA BIT(3)
-#define HSIO_S1G_DFT_CFG1_TX_WAVEFORM_SEL BIT(2)
-#define HSIO_S1G_DFT_CFG1_TX_FREQOFF_DIR BIT(1)
-#define HSIO_S1G_DFT_CFG1_TX_FREQOFF_ENA BIT(0)
-
-#define HSIO_S1G_DFT_CFG2_RX_JITTER_AMPL(x) (((x) << 8) & GENMASK(17, 8))
-#define HSIO_S1G_DFT_CFG2_RX_JITTER_AMPL_M GENMASK(17, 8)
-#define HSIO_S1G_DFT_CFG2_RX_JITTER_AMPL_X(x) (((x) & GENMASK(17, 8)) >> 8)
-#define HSIO_S1G_DFT_CFG2_RX_STEP_FREQ(x) (((x) << 4) & GENMASK(7, 4))
-#define HSIO_S1G_DFT_CFG2_RX_STEP_FREQ_M GENMASK(7, 4)
-#define HSIO_S1G_DFT_CFG2_RX_STEP_FREQ_X(x) (((x) & GENMASK(7, 4)) >> 4)
-#define HSIO_S1G_DFT_CFG2_RX_JI_ENA BIT(3)
-#define HSIO_S1G_DFT_CFG2_RX_WAVEFORM_SEL BIT(2)
-#define HSIO_S1G_DFT_CFG2_RX_FREQOFF_DIR BIT(1)
-#define HSIO_S1G_DFT_CFG2_RX_FREQOFF_ENA BIT(0)
-
-#define HSIO_S1G_RC_PLL_BIST_CFG_PLL_BIST_ENA BIT(20)
-#define HSIO_S1G_RC_PLL_BIST_CFG_PLL_BIST_FBS_HIGH(x) (((x) << 16) & GENMASK(17, 16))
-#define HSIO_S1G_RC_PLL_BIST_CFG_PLL_BIST_FBS_HIGH_M GENMASK(17, 16)
-#define HSIO_S1G_RC_PLL_BIST_CFG_PLL_BIST_FBS_HIGH_X(x) (((x) & GENMASK(17, 16)) >> 16)
-#define HSIO_S1G_RC_PLL_BIST_CFG_PLL_BIST_HIGH(x) (((x) << 8) & GENMASK(15, 8))
-#define HSIO_S1G_RC_PLL_BIST_CFG_PLL_BIST_HIGH_M GENMASK(15, 8)
-#define HSIO_S1G_RC_PLL_BIST_CFG_PLL_BIST_HIGH_X(x) (((x) & GENMASK(15, 8)) >> 8)
-#define HSIO_S1G_RC_PLL_BIST_CFG_PLL_BIST_LOW(x) ((x) & GENMASK(7, 0))
-#define HSIO_S1G_RC_PLL_BIST_CFG_PLL_BIST_LOW_M GENMASK(7, 0)
-
-#define HSIO_S1G_MISC_CFG_DES_100FX_KICK_MODE(x) (((x) << 11) & GENMASK(12, 11))
-#define HSIO_S1G_MISC_CFG_DES_100FX_KICK_MODE_M GENMASK(12, 11)
-#define HSIO_S1G_MISC_CFG_DES_100FX_KICK_MODE_X(x) (((x) & GENMASK(12, 11)) >> 11)
-#define HSIO_S1G_MISC_CFG_DES_100FX_CPMD_SWAP BIT(10)
-#define HSIO_S1G_MISC_CFG_DES_100FX_CPMD_MODE BIT(9)
-#define HSIO_S1G_MISC_CFG_DES_100FX_CPMD_ENA BIT(8)
-#define HSIO_S1G_MISC_CFG_RX_LPI_MODE_ENA BIT(5)
-#define HSIO_S1G_MISC_CFG_TX_LPI_MODE_ENA BIT(4)
-#define HSIO_S1G_MISC_CFG_RX_DATA_INV_ENA BIT(3)
-#define HSIO_S1G_MISC_CFG_TX_DATA_INV_ENA BIT(2)
-#define HSIO_S1G_MISC_CFG_LANE_RST BIT(0)
-
-#define HSIO_S1G_DFT_STATUS_PLL_BIST_NOT_DONE BIT(7)
-#define HSIO_S1G_DFT_STATUS_PLL_BIST_FAILED BIT(6)
-#define HSIO_S1G_DFT_STATUS_PLL_BIST_TIMEOUT_ERR BIT(5)
-#define HSIO_S1G_DFT_STATUS_BIST_ACTIVE BIT(3)
-#define HSIO_S1G_DFT_STATUS_BIST_NOSYNC BIT(2)
-#define HSIO_S1G_DFT_STATUS_BIST_COMPLETE_N BIT(1)
-#define HSIO_S1G_DFT_STATUS_BIST_ERROR BIT(0)
-
-#define HSIO_S1G_MISC_STATUS_DES_100FX_PHASE_SEL BIT(0)
-
-#define HSIO_MCB_S1G_ADDR_CFG_SERDES1G_WR_ONE_SHOT BIT(31)
-#define HSIO_MCB_S1G_ADDR_CFG_SERDES1G_RD_ONE_SHOT BIT(30)
-#define HSIO_MCB_S1G_ADDR_CFG_SERDES1G_ADDR(x) ((x) & GENMASK(8, 0))
-#define HSIO_MCB_S1G_ADDR_CFG_SERDES1G_ADDR_M GENMASK(8, 0)
-
-#define HSIO_S6G_DIG_CFG_GP(x) (((x) << 16) & GENMASK(18, 16))
-#define HSIO_S6G_DIG_CFG_GP_M GENMASK(18, 16)
-#define HSIO_S6G_DIG_CFG_GP_X(x) (((x) & GENMASK(18, 16)) >> 16)
-#define HSIO_S6G_DIG_CFG_TX_BIT_DOUBLING_MODE_ENA BIT(7)
-#define HSIO_S6G_DIG_CFG_SIGDET_TESTMODE BIT(6)
-#define HSIO_S6G_DIG_CFG_SIGDET_AST(x) (((x) << 3) & GENMASK(5, 3))
-#define HSIO_S6G_DIG_CFG_SIGDET_AST_M GENMASK(5, 3)
-#define HSIO_S6G_DIG_CFG_SIGDET_AST_X(x) (((x) & GENMASK(5, 3)) >> 3)
-#define HSIO_S6G_DIG_CFG_SIGDET_DST(x) ((x) & GENMASK(2, 0))
-#define HSIO_S6G_DIG_CFG_SIGDET_DST_M GENMASK(2, 0)
-
-#define HSIO_S6G_DFT_CFG0_LAZYBIT BIT(31)
-#define HSIO_S6G_DFT_CFG0_INV_DIS BIT(23)
-#define HSIO_S6G_DFT_CFG0_PRBS_SEL(x) (((x) << 20) & GENMASK(21, 20))
-#define HSIO_S6G_DFT_CFG0_PRBS_SEL_M GENMASK(21, 20)
-#define HSIO_S6G_DFT_CFG0_PRBS_SEL_X(x) (((x) & GENMASK(21, 20)) >> 20)
-#define HSIO_S6G_DFT_CFG0_TEST_MODE(x) (((x) << 16) & GENMASK(18, 16))
-#define HSIO_S6G_DFT_CFG0_TEST_MODE_M GENMASK(18, 16)
-#define HSIO_S6G_DFT_CFG0_TEST_MODE_X(x) (((x) & GENMASK(18, 16)) >> 16)
-#define HSIO_S6G_DFT_CFG0_RX_PHS_CORR_DIS BIT(4)
-#define HSIO_S6G_DFT_CFG0_RX_PDSENS_ENA BIT(3)
-#define HSIO_S6G_DFT_CFG0_RX_DFT_ENA BIT(2)
-#define HSIO_S6G_DFT_CFG0_TX_DFT_ENA BIT(0)
-
-#define HSIO_S6G_DFT_CFG1_TX_JITTER_AMPL(x) (((x) << 8) & GENMASK(17, 8))
-#define HSIO_S6G_DFT_CFG1_TX_JITTER_AMPL_M GENMASK(17, 8)
-#define HSIO_S6G_DFT_CFG1_TX_JITTER_AMPL_X(x) (((x) & GENMASK(17, 8)) >> 8)
-#define HSIO_S6G_DFT_CFG1_TX_STEP_FREQ(x) (((x) << 4) & GENMASK(7, 4))
-#define HSIO_S6G_DFT_CFG1_TX_STEP_FREQ_M GENMASK(7, 4)
-#define HSIO_S6G_DFT_CFG1_TX_STEP_FREQ_X(x) (((x) & GENMASK(7, 4)) >> 4)
-#define HSIO_S6G_DFT_CFG1_TX_JI_ENA BIT(3)
-#define HSIO_S6G_DFT_CFG1_TX_WAVEFORM_SEL BIT(2)
-#define HSIO_S6G_DFT_CFG1_TX_FREQOFF_DIR BIT(1)
-#define HSIO_S6G_DFT_CFG1_TX_FREQOFF_ENA BIT(0)
-
-#define HSIO_S6G_DFT_CFG2_RX_JITTER_AMPL(x) (((x) << 8) & GENMASK(17, 8))
-#define HSIO_S6G_DFT_CFG2_RX_JITTER_AMPL_M GENMASK(17, 8)
-#define HSIO_S6G_DFT_CFG2_RX_JITTER_AMPL_X(x) (((x) & GENMASK(17, 8)) >> 8)
-#define HSIO_S6G_DFT_CFG2_RX_STEP_FREQ(x) (((x) << 4) & GENMASK(7, 4))
-#define HSIO_S6G_DFT_CFG2_RX_STEP_FREQ_M GENMASK(7, 4)
-#define HSIO_S6G_DFT_CFG2_RX_STEP_FREQ_X(x) (((x) & GENMASK(7, 4)) >> 4)
-#define HSIO_S6G_DFT_CFG2_RX_JI_ENA BIT(3)
-#define HSIO_S6G_DFT_CFG2_RX_WAVEFORM_SEL BIT(2)
-#define HSIO_S6G_DFT_CFG2_RX_FREQOFF_DIR BIT(1)
-#define HSIO_S6G_DFT_CFG2_RX_FREQOFF_ENA BIT(0)
-
-#define HSIO_S6G_RC_PLL_BIST_CFG_PLL_BIST_ENA BIT(20)
-#define HSIO_S6G_RC_PLL_BIST_CFG_PLL_BIST_FBS_HIGH(x) (((x) << 16) & GENMASK(19, 16))
-#define HSIO_S6G_RC_PLL_BIST_CFG_PLL_BIST_FBS_HIGH_M GENMASK(19, 16)
-#define HSIO_S6G_RC_PLL_BIST_CFG_PLL_BIST_FBS_HIGH_X(x) (((x) & GENMASK(19, 16)) >> 16)
-#define HSIO_S6G_RC_PLL_BIST_CFG_PLL_BIST_HIGH(x) (((x) << 8) & GENMASK(15, 8))
-#define HSIO_S6G_RC_PLL_BIST_CFG_PLL_BIST_HIGH_M GENMASK(15, 8)
-#define HSIO_S6G_RC_PLL_BIST_CFG_PLL_BIST_HIGH_X(x) (((x) & GENMASK(15, 8)) >> 8)
-#define HSIO_S6G_RC_PLL_BIST_CFG_PLL_BIST_LOW(x) ((x) & GENMASK(7, 0))
-#define HSIO_S6G_RC_PLL_BIST_CFG_PLL_BIST_LOW_M GENMASK(7, 0)
-
-#define HSIO_S6G_MISC_CFG_SEL_RECO_CLK(x) (((x) << 13) & GENMASK(14, 13))
-#define HSIO_S6G_MISC_CFG_SEL_RECO_CLK_M GENMASK(14, 13)
-#define HSIO_S6G_MISC_CFG_SEL_RECO_CLK_X(x) (((x) & GENMASK(14, 13)) >> 13)
-#define HSIO_S6G_MISC_CFG_DES_100FX_KICK_MODE(x) (((x) << 11) & GENMASK(12, 11))
-#define HSIO_S6G_MISC_CFG_DES_100FX_KICK_MODE_M GENMASK(12, 11)
-#define HSIO_S6G_MISC_CFG_DES_100FX_KICK_MODE_X(x) (((x) & GENMASK(12, 11)) >> 11)
-#define HSIO_S6G_MISC_CFG_DES_100FX_CPMD_SWAP BIT(10)
-#define HSIO_S6G_MISC_CFG_DES_100FX_CPMD_MODE BIT(9)
-#define HSIO_S6G_MISC_CFG_DES_100FX_CPMD_ENA BIT(8)
-#define HSIO_S6G_MISC_CFG_RX_BUS_FLIP_ENA BIT(7)
-#define HSIO_S6G_MISC_CFG_TX_BUS_FLIP_ENA BIT(6)
-#define HSIO_S6G_MISC_CFG_RX_LPI_MODE_ENA BIT(5)
-#define HSIO_S6G_MISC_CFG_TX_LPI_MODE_ENA BIT(4)
-#define HSIO_S6G_MISC_CFG_RX_DATA_INV_ENA BIT(3)
-#define HSIO_S6G_MISC_CFG_TX_DATA_INV_ENA BIT(2)
-#define HSIO_S6G_MISC_CFG_LANE_RST BIT(0)
-
-#define HSIO_S6G_OB_ANEG_CFG_AN_OB_POST0(x) (((x) << 23) & GENMASK(28, 23))
-#define HSIO_S6G_OB_ANEG_CFG_AN_OB_POST0_M GENMASK(28, 23)
-#define HSIO_S6G_OB_ANEG_CFG_AN_OB_POST0_X(x) (((x) & GENMASK(28, 23)) >> 23)
-#define HSIO_S6G_OB_ANEG_CFG_AN_OB_POST1(x) (((x) << 18) & GENMASK(22, 18))
-#define HSIO_S6G_OB_ANEG_CFG_AN_OB_POST1_M GENMASK(22, 18)
-#define HSIO_S6G_OB_ANEG_CFG_AN_OB_POST1_X(x) (((x) & GENMASK(22, 18)) >> 18)
-#define HSIO_S6G_OB_ANEG_CFG_AN_OB_PREC(x) (((x) << 13) & GENMASK(17, 13))
-#define HSIO_S6G_OB_ANEG_CFG_AN_OB_PREC_M GENMASK(17, 13)
-#define HSIO_S6G_OB_ANEG_CFG_AN_OB_PREC_X(x) (((x) & GENMASK(17, 13)) >> 13)
-#define HSIO_S6G_OB_ANEG_CFG_AN_OB_ENA_CAS(x) (((x) << 6) & GENMASK(8, 6))
-#define HSIO_S6G_OB_ANEG_CFG_AN_OB_ENA_CAS_M GENMASK(8, 6)
-#define HSIO_S6G_OB_ANEG_CFG_AN_OB_ENA_CAS_X(x) (((x) & GENMASK(8, 6)) >> 6)
-#define HSIO_S6G_OB_ANEG_CFG_AN_OB_LEV(x) ((x) & GENMASK(5, 0))
-#define HSIO_S6G_OB_ANEG_CFG_AN_OB_LEV_M GENMASK(5, 0)
-
-#define HSIO_S6G_DFT_STATUS_PRBS_SYNC_STAT BIT(8)
-#define HSIO_S6G_DFT_STATUS_PLL_BIST_NOT_DONE BIT(7)
-#define HSIO_S6G_DFT_STATUS_PLL_BIST_FAILED BIT(6)
-#define HSIO_S6G_DFT_STATUS_PLL_BIST_TIMEOUT_ERR BIT(5)
-#define HSIO_S6G_DFT_STATUS_BIST_ACTIVE BIT(3)
-#define HSIO_S6G_DFT_STATUS_BIST_NOSYNC BIT(2)
-#define HSIO_S6G_DFT_STATUS_BIST_COMPLETE_N BIT(1)
-#define HSIO_S6G_DFT_STATUS_BIST_ERROR BIT(0)
-
-#define HSIO_S6G_MISC_STATUS_DES_100FX_PHASE_SEL BIT(0)
-
-#define HSIO_S6G_DES_CFG_DES_PHS_CTRL(x) (((x) << 13) & GENMASK(16, 13))
-#define HSIO_S6G_DES_CFG_DES_PHS_CTRL_M GENMASK(16, 13)
-#define HSIO_S6G_DES_CFG_DES_PHS_CTRL_X(x) (((x) & GENMASK(16, 13)) >> 13)
-#define HSIO_S6G_DES_CFG_DES_MBTR_CTRL(x) (((x) << 10) & GENMASK(12, 10))
-#define HSIO_S6G_DES_CFG_DES_MBTR_CTRL_M GENMASK(12, 10)
-#define HSIO_S6G_DES_CFG_DES_MBTR_CTRL_X(x) (((x) & GENMASK(12, 10)) >> 10)
-#define HSIO_S6G_DES_CFG_DES_CPMD_SEL(x) (((x) << 8) & GENMASK(9, 8))
-#define HSIO_S6G_DES_CFG_DES_CPMD_SEL_M GENMASK(9, 8)
-#define HSIO_S6G_DES_CFG_DES_CPMD_SEL_X(x) (((x) & GENMASK(9, 8)) >> 8)
-#define HSIO_S6G_DES_CFG_DES_BW_HYST(x) (((x) << 5) & GENMASK(7, 5))
-#define HSIO_S6G_DES_CFG_DES_BW_HYST_M GENMASK(7, 5)
-#define HSIO_S6G_DES_CFG_DES_BW_HYST_X(x) (((x) & GENMASK(7, 5)) >> 5)
-#define HSIO_S6G_DES_CFG_DES_SWAP_HYST BIT(4)
-#define HSIO_S6G_DES_CFG_DES_BW_ANA(x) (((x) << 1) & GENMASK(3, 1))
-#define HSIO_S6G_DES_CFG_DES_BW_ANA_M GENMASK(3, 1)
-#define HSIO_S6G_DES_CFG_DES_BW_ANA_X(x) (((x) & GENMASK(3, 1)) >> 1)
-#define HSIO_S6G_DES_CFG_DES_SWAP_ANA BIT(0)
-
-#define HSIO_S6G_IB_CFG_IB_SOFSI(x) (((x) << 29) & GENMASK(30, 29))
-#define HSIO_S6G_IB_CFG_IB_SOFSI_M GENMASK(30, 29)
-#define HSIO_S6G_IB_CFG_IB_SOFSI_X(x) (((x) & GENMASK(30, 29)) >> 29)
-#define HSIO_S6G_IB_CFG_IB_VBULK_SEL BIT(28)
-#define HSIO_S6G_IB_CFG_IB_RTRM_ADJ(x) (((x) << 24) & GENMASK(27, 24))
-#define HSIO_S6G_IB_CFG_IB_RTRM_ADJ_M GENMASK(27, 24)
-#define HSIO_S6G_IB_CFG_IB_RTRM_ADJ_X(x) (((x) & GENMASK(27, 24)) >> 24)
-#define HSIO_S6G_IB_CFG_IB_ICML_ADJ(x) (((x) << 20) & GENMASK(23, 20))
-#define HSIO_S6G_IB_CFG_IB_ICML_ADJ_M GENMASK(23, 20)
-#define HSIO_S6G_IB_CFG_IB_ICML_ADJ_X(x) (((x) & GENMASK(23, 20)) >> 20)
-#define HSIO_S6G_IB_CFG_IB_TERM_MODE_SEL(x) (((x) << 18) & GENMASK(19, 18))
-#define HSIO_S6G_IB_CFG_IB_TERM_MODE_SEL_M GENMASK(19, 18)
-#define HSIO_S6G_IB_CFG_IB_TERM_MODE_SEL_X(x) (((x) & GENMASK(19, 18)) >> 18)
-#define HSIO_S6G_IB_CFG_IB_SIG_DET_CLK_SEL(x) (((x) << 15) & GENMASK(17, 15))
-#define HSIO_S6G_IB_CFG_IB_SIG_DET_CLK_SEL_M GENMASK(17, 15)
-#define HSIO_S6G_IB_CFG_IB_SIG_DET_CLK_SEL_X(x) (((x) & GENMASK(17, 15)) >> 15)
-#define HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_HP(x) (((x) << 13) & GENMASK(14, 13))
-#define HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_HP_M GENMASK(14, 13)
-#define HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_HP_X(x) (((x) & GENMASK(14, 13)) >> 13)
-#define HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_MID(x) (((x) << 11) & GENMASK(12, 11))
-#define HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_MID_M GENMASK(12, 11)
-#define HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_MID_X(x) (((x) & GENMASK(12, 11)) >> 11)
-#define HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_LP(x) (((x) << 9) & GENMASK(10, 9))
-#define HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_LP_M GENMASK(10, 9)
-#define HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_LP_X(x) (((x) & GENMASK(10, 9)) >> 9)
-#define HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_OFFSET(x) (((x) << 7) & GENMASK(8, 7))
-#define HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_OFFSET_M GENMASK(8, 7)
-#define HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_OFFSET_X(x) (((x) & GENMASK(8, 7)) >> 7)
-#define HSIO_S6G_IB_CFG_IB_ANA_TEST_ENA BIT(6)
-#define HSIO_S6G_IB_CFG_IB_SIG_DET_ENA BIT(5)
-#define HSIO_S6G_IB_CFG_IB_CONCUR BIT(4)
-#define HSIO_S6G_IB_CFG_IB_CAL_ENA BIT(3)
-#define HSIO_S6G_IB_CFG_IB_SAM_ENA BIT(2)
-#define HSIO_S6G_IB_CFG_IB_EQZ_ENA BIT(1)
-#define HSIO_S6G_IB_CFG_IB_REG_ENA BIT(0)
-
-#define HSIO_S6G_IB_CFG1_IB_TJTAG(x) (((x) << 17) & GENMASK(21, 17))
-#define HSIO_S6G_IB_CFG1_IB_TJTAG_M GENMASK(21, 17)
-#define HSIO_S6G_IB_CFG1_IB_TJTAG_X(x) (((x) & GENMASK(21, 17)) >> 17)
-#define HSIO_S6G_IB_CFG1_IB_TSDET(x) (((x) << 12) & GENMASK(16, 12))
-#define HSIO_S6G_IB_CFG1_IB_TSDET_M GENMASK(16, 12)
-#define HSIO_S6G_IB_CFG1_IB_TSDET_X(x) (((x) & GENMASK(16, 12)) >> 12)
-#define HSIO_S6G_IB_CFG1_IB_SCALY(x) (((x) << 8) & GENMASK(11, 8))
-#define HSIO_S6G_IB_CFG1_IB_SCALY_M GENMASK(11, 8)
-#define HSIO_S6G_IB_CFG1_IB_SCALY_X(x) (((x) & GENMASK(11, 8)) >> 8)
-#define HSIO_S6G_IB_CFG1_IB_FILT_HP BIT(7)
-#define HSIO_S6G_IB_CFG1_IB_FILT_MID BIT(6)
-#define HSIO_S6G_IB_CFG1_IB_FILT_LP BIT(5)
-#define HSIO_S6G_IB_CFG1_IB_FILT_OFFSET BIT(4)
-#define HSIO_S6G_IB_CFG1_IB_FRC_HP BIT(3)
-#define HSIO_S6G_IB_CFG1_IB_FRC_MID BIT(2)
-#define HSIO_S6G_IB_CFG1_IB_FRC_LP BIT(1)
-#define HSIO_S6G_IB_CFG1_IB_FRC_OFFSET BIT(0)
-
-#define HSIO_S6G_IB_CFG2_IB_TINFV(x) (((x) << 27) & GENMASK(29, 27))
-#define HSIO_S6G_IB_CFG2_IB_TINFV_M GENMASK(29, 27)
-#define HSIO_S6G_IB_CFG2_IB_TINFV_X(x) (((x) & GENMASK(29, 27)) >> 27)
-#define HSIO_S6G_IB_CFG2_IB_OINFI(x) (((x) << 22) & GENMASK(26, 22))
-#define HSIO_S6G_IB_CFG2_IB_OINFI_M GENMASK(26, 22)
-#define HSIO_S6G_IB_CFG2_IB_OINFI_X(x) (((x) & GENMASK(26, 22)) >> 22)
-#define HSIO_S6G_IB_CFG2_IB_TAUX(x) (((x) << 19) & GENMASK(21, 19))
-#define HSIO_S6G_IB_CFG2_IB_TAUX_M GENMASK(21, 19)
-#define HSIO_S6G_IB_CFG2_IB_TAUX_X(x) (((x) & GENMASK(21, 19)) >> 19)
-#define HSIO_S6G_IB_CFG2_IB_OINFS(x) (((x) << 16) & GENMASK(18, 16))
-#define HSIO_S6G_IB_CFG2_IB_OINFS_M GENMASK(18, 16)
-#define HSIO_S6G_IB_CFG2_IB_OINFS_X(x) (((x) & GENMASK(18, 16)) >> 16)
-#define HSIO_S6G_IB_CFG2_IB_OCALS(x) (((x) << 10) & GENMASK(15, 10))
-#define HSIO_S6G_IB_CFG2_IB_OCALS_M GENMASK(15, 10)
-#define HSIO_S6G_IB_CFG2_IB_OCALS_X(x) (((x) & GENMASK(15, 10)) >> 10)
-#define HSIO_S6G_IB_CFG2_IB_TCALV(x) (((x) << 5) & GENMASK(9, 5))
-#define HSIO_S6G_IB_CFG2_IB_TCALV_M GENMASK(9, 5)
-#define HSIO_S6G_IB_CFG2_IB_TCALV_X(x) (((x) & GENMASK(9, 5)) >> 5)
-#define HSIO_S6G_IB_CFG2_IB_UMAX(x) (((x) << 3) & GENMASK(4, 3))
-#define HSIO_S6G_IB_CFG2_IB_UMAX_M GENMASK(4, 3)
-#define HSIO_S6G_IB_CFG2_IB_UMAX_X(x) (((x) & GENMASK(4, 3)) >> 3)
-#define HSIO_S6G_IB_CFG2_IB_UREG(x) ((x) & GENMASK(2, 0))
-#define HSIO_S6G_IB_CFG2_IB_UREG_M GENMASK(2, 0)
-
-#define HSIO_S6G_IB_CFG3_IB_INI_HP(x) (((x) << 18) & GENMASK(23, 18))
-#define HSIO_S6G_IB_CFG3_IB_INI_HP_M GENMASK(23, 18)
-#define HSIO_S6G_IB_CFG3_IB_INI_HP_X(x) (((x) & GENMASK(23, 18)) >> 18)
-#define HSIO_S6G_IB_CFG3_IB_INI_MID(x) (((x) << 12) & GENMASK(17, 12))
-#define HSIO_S6G_IB_CFG3_IB_INI_MID_M GENMASK(17, 12)
-#define HSIO_S6G_IB_CFG3_IB_INI_MID_X(x) (((x) & GENMASK(17, 12)) >> 12)
-#define HSIO_S6G_IB_CFG3_IB_INI_LP(x) (((x) << 6) & GENMASK(11, 6))
-#define HSIO_S6G_IB_CFG3_IB_INI_LP_M GENMASK(11, 6)
-#define HSIO_S6G_IB_CFG3_IB_INI_LP_X(x) (((x) & GENMASK(11, 6)) >> 6)
-#define HSIO_S6G_IB_CFG3_IB_INI_OFFSET(x) ((x) & GENMASK(5, 0))
-#define HSIO_S6G_IB_CFG3_IB_INI_OFFSET_M GENMASK(5, 0)
-
-#define HSIO_S6G_IB_CFG4_IB_MAX_HP(x) (((x) << 18) & GENMASK(23, 18))
-#define HSIO_S6G_IB_CFG4_IB_MAX_HP_M GENMASK(23, 18)
-#define HSIO_S6G_IB_CFG4_IB_MAX_HP_X(x) (((x) & GENMASK(23, 18)) >> 18)
-#define HSIO_S6G_IB_CFG4_IB_MAX_MID(x) (((x) << 12) & GENMASK(17, 12))
-#define HSIO_S6G_IB_CFG4_IB_MAX_MID_M GENMASK(17, 12)
-#define HSIO_S6G_IB_CFG4_IB_MAX_MID_X(x) (((x) & GENMASK(17, 12)) >> 12)
-#define HSIO_S6G_IB_CFG4_IB_MAX_LP(x) (((x) << 6) & GENMASK(11, 6))
-#define HSIO_S6G_IB_CFG4_IB_MAX_LP_M GENMASK(11, 6)
-#define HSIO_S6G_IB_CFG4_IB_MAX_LP_X(x) (((x) & GENMASK(11, 6)) >> 6)
-#define HSIO_S6G_IB_CFG4_IB_MAX_OFFSET(x) ((x) & GENMASK(5, 0))
-#define HSIO_S6G_IB_CFG4_IB_MAX_OFFSET_M GENMASK(5, 0)
-
-#define HSIO_S6G_IB_CFG5_IB_MIN_HP(x) (((x) << 18) & GENMASK(23, 18))
-#define HSIO_S6G_IB_CFG5_IB_MIN_HP_M GENMASK(23, 18)
-#define HSIO_S6G_IB_CFG5_IB_MIN_HP_X(x) (((x) & GENMASK(23, 18)) >> 18)
-#define HSIO_S6G_IB_CFG5_IB_MIN_MID(x) (((x) << 12) & GENMASK(17, 12))
-#define HSIO_S6G_IB_CFG5_IB_MIN_MID_M GENMASK(17, 12)
-#define HSIO_S6G_IB_CFG5_IB_MIN_MID_X(x) (((x) & GENMASK(17, 12)) >> 12)
-#define HSIO_S6G_IB_CFG5_IB_MIN_LP(x) (((x) << 6) & GENMASK(11, 6))
-#define HSIO_S6G_IB_CFG5_IB_MIN_LP_M GENMASK(11, 6)
-#define HSIO_S6G_IB_CFG5_IB_MIN_LP_X(x) (((x) & GENMASK(11, 6)) >> 6)
-#define HSIO_S6G_IB_CFG5_IB_MIN_OFFSET(x) ((x) & GENMASK(5, 0))
-#define HSIO_S6G_IB_CFG5_IB_MIN_OFFSET_M GENMASK(5, 0)
-
-#define HSIO_S6G_OB_CFG_OB_IDLE BIT(31)
-#define HSIO_S6G_OB_CFG_OB_ENA1V_MODE BIT(30)
-#define HSIO_S6G_OB_CFG_OB_POL BIT(29)
-#define HSIO_S6G_OB_CFG_OB_POST0(x) (((x) << 23) & GENMASK(28, 23))
-#define HSIO_S6G_OB_CFG_OB_POST0_M GENMASK(28, 23)
-#define HSIO_S6G_OB_CFG_OB_POST0_X(x) (((x) & GENMASK(28, 23)) >> 23)
-#define HSIO_S6G_OB_CFG_OB_PREC(x) (((x) << 18) & GENMASK(22, 18))
-#define HSIO_S6G_OB_CFG_OB_PREC_M GENMASK(22, 18)
-#define HSIO_S6G_OB_CFG_OB_PREC_X(x) (((x) & GENMASK(22, 18)) >> 18)
-#define HSIO_S6G_OB_CFG_OB_R_ADJ_MUX BIT(17)
-#define HSIO_S6G_OB_CFG_OB_R_ADJ_PDR BIT(16)
-#define HSIO_S6G_OB_CFG_OB_POST1(x) (((x) << 11) & GENMASK(15, 11))
-#define HSIO_S6G_OB_CFG_OB_POST1_M GENMASK(15, 11)
-#define HSIO_S6G_OB_CFG_OB_POST1_X(x) (((x) & GENMASK(15, 11)) >> 11)
-#define HSIO_S6G_OB_CFG_OB_R_COR BIT(10)
-#define HSIO_S6G_OB_CFG_OB_SEL_RCTRL BIT(9)
-#define HSIO_S6G_OB_CFG_OB_SR_H BIT(8)
-#define HSIO_S6G_OB_CFG_OB_SR(x) (((x) << 4) & GENMASK(7, 4))
-#define HSIO_S6G_OB_CFG_OB_SR_M GENMASK(7, 4)
-#define HSIO_S6G_OB_CFG_OB_SR_X(x) (((x) & GENMASK(7, 4)) >> 4)
-#define HSIO_S6G_OB_CFG_OB_RESISTOR_CTRL(x) ((x) & GENMASK(3, 0))
-#define HSIO_S6G_OB_CFG_OB_RESISTOR_CTRL_M GENMASK(3, 0)
-
-#define HSIO_S6G_OB_CFG1_OB_ENA_CAS(x) (((x) << 6) & GENMASK(8, 6))
-#define HSIO_S6G_OB_CFG1_OB_ENA_CAS_M GENMASK(8, 6)
-#define HSIO_S6G_OB_CFG1_OB_ENA_CAS_X(x) (((x) & GENMASK(8, 6)) >> 6)
-#define HSIO_S6G_OB_CFG1_OB_LEV(x) ((x) & GENMASK(5, 0))
-#define HSIO_S6G_OB_CFG1_OB_LEV_M GENMASK(5, 0)
-
-#define HSIO_S6G_SER_CFG_SER_4TAP_ENA BIT(8)
-#define HSIO_S6G_SER_CFG_SER_CPMD_SEL BIT(7)
-#define HSIO_S6G_SER_CFG_SER_SWAP_CPMD BIT(6)
-#define HSIO_S6G_SER_CFG_SER_ALISEL(x) (((x) << 4) & GENMASK(5, 4))
-#define HSIO_S6G_SER_CFG_SER_ALISEL_M GENMASK(5, 4)
-#define HSIO_S6G_SER_CFG_SER_ALISEL_X(x) (((x) & GENMASK(5, 4)) >> 4)
-#define HSIO_S6G_SER_CFG_SER_ENHYS BIT(3)
-#define HSIO_S6G_SER_CFG_SER_BIG_WIN BIT(2)
-#define HSIO_S6G_SER_CFG_SER_EN_WIN BIT(1)
-#define HSIO_S6G_SER_CFG_SER_ENALI BIT(0)
-
-#define HSIO_S6G_COMMON_CFG_SYS_RST BIT(17)
-#define HSIO_S6G_COMMON_CFG_SE_DIV2_ENA BIT(16)
-#define HSIO_S6G_COMMON_CFG_SE_AUTO_SQUELCH_ENA BIT(15)
-#define HSIO_S6G_COMMON_CFG_ENA_LANE BIT(14)
-#define HSIO_S6G_COMMON_CFG_PWD_RX BIT(13)
-#define HSIO_S6G_COMMON_CFG_PWD_TX BIT(12)
-#define HSIO_S6G_COMMON_CFG_LANE_CTRL(x) (((x) << 9) & GENMASK(11, 9))
-#define HSIO_S6G_COMMON_CFG_LANE_CTRL_M GENMASK(11, 9)
-#define HSIO_S6G_COMMON_CFG_LANE_CTRL_X(x) (((x) & GENMASK(11, 9)) >> 9)
-#define HSIO_S6G_COMMON_CFG_ENA_DIRECT BIT(8)
-#define HSIO_S6G_COMMON_CFG_ENA_ELOOP BIT(7)
-#define HSIO_S6G_COMMON_CFG_ENA_FLOOP BIT(6)
-#define HSIO_S6G_COMMON_CFG_ENA_ILOOP BIT(5)
-#define HSIO_S6G_COMMON_CFG_ENA_PLOOP BIT(4)
-#define HSIO_S6G_COMMON_CFG_HRATE BIT(3)
-#define HSIO_S6G_COMMON_CFG_QRATE BIT(2)
-#define HSIO_S6G_COMMON_CFG_IF_MODE(x) ((x) & GENMASK(1, 0))
-#define HSIO_S6G_COMMON_CFG_IF_MODE_M GENMASK(1, 0)
-
-#define HSIO_S6G_PLL_CFG_PLL_ENA_OFFS(x) (((x) << 16) & GENMASK(17, 16))
-#define HSIO_S6G_PLL_CFG_PLL_ENA_OFFS_M GENMASK(17, 16)
-#define HSIO_S6G_PLL_CFG_PLL_ENA_OFFS_X(x) (((x) & GENMASK(17, 16)) >> 16)
-#define HSIO_S6G_PLL_CFG_PLL_DIV4 BIT(15)
-#define HSIO_S6G_PLL_CFG_PLL_ENA_ROT BIT(14)
-#define HSIO_S6G_PLL_CFG_PLL_FSM_CTRL_DATA(x) (((x) << 6) & GENMASK(13, 6))
-#define HSIO_S6G_PLL_CFG_PLL_FSM_CTRL_DATA_M GENMASK(13, 6)
-#define HSIO_S6G_PLL_CFG_PLL_FSM_CTRL_DATA_X(x) (((x) & GENMASK(13, 6)) >> 6)
-#define HSIO_S6G_PLL_CFG_PLL_FSM_ENA BIT(5)
-#define HSIO_S6G_PLL_CFG_PLL_FSM_FORCE_SET_ENA BIT(4)
-#define HSIO_S6G_PLL_CFG_PLL_FSM_OOR_RECAL_ENA BIT(3)
-#define HSIO_S6G_PLL_CFG_PLL_RB_DATA_SEL BIT(2)
-#define HSIO_S6G_PLL_CFG_PLL_ROT_DIR BIT(1)
-#define HSIO_S6G_PLL_CFG_PLL_ROT_FRQ BIT(0)
-
-#define HSIO_S6G_ACJTAG_CFG_ACJTAG_INIT_DATA_N BIT(5)
-#define HSIO_S6G_ACJTAG_CFG_ACJTAG_INIT_DATA_P BIT(4)
-#define HSIO_S6G_ACJTAG_CFG_ACJTAG_INIT_CLK BIT(3)
-#define HSIO_S6G_ACJTAG_CFG_OB_DIRECT BIT(2)
-#define HSIO_S6G_ACJTAG_CFG_ACJTAG_ENA BIT(1)
-#define HSIO_S6G_ACJTAG_CFG_JTAG_CTRL_ENA BIT(0)
-
-#define HSIO_S6G_GP_CFG_GP_MSB(x) (((x) << 16) & GENMASK(31, 16))
-#define HSIO_S6G_GP_CFG_GP_MSB_M GENMASK(31, 16)
-#define HSIO_S6G_GP_CFG_GP_MSB_X(x) (((x) & GENMASK(31, 16)) >> 16)
-#define HSIO_S6G_GP_CFG_GP_LSB(x) ((x) & GENMASK(15, 0))
-#define HSIO_S6G_GP_CFG_GP_LSB_M GENMASK(15, 0)
-
-#define HSIO_S6G_IB_STATUS0_IB_CAL_DONE BIT(8)
-#define HSIO_S6G_IB_STATUS0_IB_HP_GAIN_ACT BIT(7)
-#define HSIO_S6G_IB_STATUS0_IB_MID_GAIN_ACT BIT(6)
-#define HSIO_S6G_IB_STATUS0_IB_LP_GAIN_ACT BIT(5)
-#define HSIO_S6G_IB_STATUS0_IB_OFFSET_ACT BIT(4)
-#define HSIO_S6G_IB_STATUS0_IB_OFFSET_VLD BIT(3)
-#define HSIO_S6G_IB_STATUS0_IB_OFFSET_ERR BIT(2)
-#define HSIO_S6G_IB_STATUS0_IB_OFFSDIR BIT(1)
-#define HSIO_S6G_IB_STATUS0_IB_SIG_DET BIT(0)
-
-#define HSIO_S6G_IB_STATUS1_IB_HP_GAIN_STAT(x) (((x) << 18) & GENMASK(23, 18))
-#define HSIO_S6G_IB_STATUS1_IB_HP_GAIN_STAT_M GENMASK(23, 18)
-#define HSIO_S6G_IB_STATUS1_IB_HP_GAIN_STAT_X(x) (((x) & GENMASK(23, 18)) >> 18)
-#define HSIO_S6G_IB_STATUS1_IB_MID_GAIN_STAT(x) (((x) << 12) & GENMASK(17, 12))
-#define HSIO_S6G_IB_STATUS1_IB_MID_GAIN_STAT_M GENMASK(17, 12)
-#define HSIO_S6G_IB_STATUS1_IB_MID_GAIN_STAT_X(x) (((x) & GENMASK(17, 12)) >> 12)
-#define HSIO_S6G_IB_STATUS1_IB_LP_GAIN_STAT(x) (((x) << 6) & GENMASK(11, 6))
-#define HSIO_S6G_IB_STATUS1_IB_LP_GAIN_STAT_M GENMASK(11, 6)
-#define HSIO_S6G_IB_STATUS1_IB_LP_GAIN_STAT_X(x) (((x) & GENMASK(11, 6)) >> 6)
-#define HSIO_S6G_IB_STATUS1_IB_OFFSET_STAT(x) ((x) & GENMASK(5, 0))
-#define HSIO_S6G_IB_STATUS1_IB_OFFSET_STAT_M GENMASK(5, 0)
-
-#define HSIO_S6G_ACJTAG_STATUS_ACJTAG_CAPT_DATA_N BIT(2)
-#define HSIO_S6G_ACJTAG_STATUS_ACJTAG_CAPT_DATA_P BIT(1)
-#define HSIO_S6G_ACJTAG_STATUS_IB_DIRECT BIT(0)
-
-#define HSIO_S6G_PLL_STATUS_PLL_CAL_NOT_DONE BIT(10)
-#define HSIO_S6G_PLL_STATUS_PLL_CAL_ERR BIT(9)
-#define HSIO_S6G_PLL_STATUS_PLL_OUT_OF_RANGE_ERR BIT(8)
-#define HSIO_S6G_PLL_STATUS_PLL_RB_DATA(x) ((x) & GENMASK(7, 0))
-#define HSIO_S6G_PLL_STATUS_PLL_RB_DATA_M GENMASK(7, 0)
-
-#define HSIO_S6G_REVID_SERDES_REV(x) (((x) << 26) & GENMASK(31, 26))
-#define HSIO_S6G_REVID_SERDES_REV_M GENMASK(31, 26)
-#define HSIO_S6G_REVID_SERDES_REV_X(x) (((x) & GENMASK(31, 26)) >> 26)
-#define HSIO_S6G_REVID_RCPLL_REV(x) (((x) << 21) & GENMASK(25, 21))
-#define HSIO_S6G_REVID_RCPLL_REV_M GENMASK(25, 21)
-#define HSIO_S6G_REVID_RCPLL_REV_X(x) (((x) & GENMASK(25, 21)) >> 21)
-#define HSIO_S6G_REVID_SER_REV(x) (((x) << 16) & GENMASK(20, 16))
-#define HSIO_S6G_REVID_SER_REV_M GENMASK(20, 16)
-#define HSIO_S6G_REVID_SER_REV_X(x) (((x) & GENMASK(20, 16)) >> 16)
-#define HSIO_S6G_REVID_DES_REV(x) (((x) << 10) & GENMASK(15, 10))
-#define HSIO_S6G_REVID_DES_REV_M GENMASK(15, 10)
-#define HSIO_S6G_REVID_DES_REV_X(x) (((x) & GENMASK(15, 10)) >> 10)
-#define HSIO_S6G_REVID_OB_REV(x) (((x) << 5) & GENMASK(9, 5))
-#define HSIO_S6G_REVID_OB_REV_M GENMASK(9, 5)
-#define HSIO_S6G_REVID_OB_REV_X(x) (((x) & GENMASK(9, 5)) >> 5)
-#define HSIO_S6G_REVID_IB_REV(x) ((x) & GENMASK(4, 0))
-#define HSIO_S6G_REVID_IB_REV_M GENMASK(4, 0)
-
-#define HSIO_MCB_S6G_ADDR_CFG_SERDES6G_WR_ONE_SHOT BIT(31)
-#define HSIO_MCB_S6G_ADDR_CFG_SERDES6G_RD_ONE_SHOT BIT(30)
-#define HSIO_MCB_S6G_ADDR_CFG_SERDES6G_ADDR(x) ((x) & GENMASK(24, 0))
-#define HSIO_MCB_S6G_ADDR_CFG_SERDES6G_ADDR_M GENMASK(24, 0)
-
-#define HSIO_HW_CFG_DEV2G5_10_MODE BIT(6)
-#define HSIO_HW_CFG_DEV1G_9_MODE BIT(5)
-#define HSIO_HW_CFG_DEV1G_6_MODE BIT(4)
-#define HSIO_HW_CFG_DEV1G_5_MODE BIT(3)
-#define HSIO_HW_CFG_DEV1G_4_MODE BIT(2)
-#define HSIO_HW_CFG_PCIE_ENA BIT(1)
-#define HSIO_HW_CFG_QSGMII_ENA BIT(0)
-
-#define HSIO_HW_QSGMII_CFG_SHYST_DIS BIT(3)
-#define HSIO_HW_QSGMII_CFG_E_DET_ENA BIT(2)
-#define HSIO_HW_QSGMII_CFG_USE_I1_ENA BIT(1)
-#define HSIO_HW_QSGMII_CFG_FLIP_LANES BIT(0)
-
-#define HSIO_HW_QSGMII_STAT_DELAY_VAR_X200PS(x) (((x) << 1) & GENMASK(6, 1))
-#define HSIO_HW_QSGMII_STAT_DELAY_VAR_X200PS_M GENMASK(6, 1)
-#define HSIO_HW_QSGMII_STAT_DELAY_VAR_X200PS_X(x) (((x) & GENMASK(6, 1)) >> 1)
-#define HSIO_HW_QSGMII_STAT_SYNC BIT(0)
-
-#define HSIO_CLK_CFG_CLKDIV_PHY(x) (((x) << 1) & GENMASK(8, 1))
-#define HSIO_CLK_CFG_CLKDIV_PHY_M GENMASK(8, 1)
-#define HSIO_CLK_CFG_CLKDIV_PHY_X(x) (((x) & GENMASK(8, 1)) >> 1)
-#define HSIO_CLK_CFG_CLKDIV_PHY_DIS BIT(0)
-
-#define HSIO_TEMP_SENSOR_CTRL_FORCE_TEMP_RD BIT(5)
-#define HSIO_TEMP_SENSOR_CTRL_FORCE_RUN BIT(4)
-#define HSIO_TEMP_SENSOR_CTRL_FORCE_NO_RST BIT(3)
-#define HSIO_TEMP_SENSOR_CTRL_FORCE_POWER_UP BIT(2)
-#define HSIO_TEMP_SENSOR_CTRL_FORCE_CLK BIT(1)
-#define HSIO_TEMP_SENSOR_CTRL_SAMPLE_ENA BIT(0)
-
-#define HSIO_TEMP_SENSOR_CFG_RUN_WID(x) (((x) << 8) & GENMASK(15, 8))
-#define HSIO_TEMP_SENSOR_CFG_RUN_WID_M GENMASK(15, 8)
-#define HSIO_TEMP_SENSOR_CFG_RUN_WID_X(x) (((x) & GENMASK(15, 8)) >> 8)
-#define HSIO_TEMP_SENSOR_CFG_SAMPLE_PER(x) ((x) & GENMASK(7, 0))
-#define HSIO_TEMP_SENSOR_CFG_SAMPLE_PER_M GENMASK(7, 0)
-
-#define HSIO_TEMP_SENSOR_STAT_TEMP_VALID BIT(8)
-#define HSIO_TEMP_SENSOR_STAT_TEMP(x) ((x) & GENMASK(7, 0))
-#define HSIO_TEMP_SENSOR_STAT_TEMP_M GENMASK(7, 0)
-
-#endif
diff --git a/drivers/net/ethernet/mscc/ocelot_regs.c b/drivers/net/ethernet/mscc/ocelot_regs.c
index e334b406c40c..9271af18b93b 100644
--- a/drivers/net/ethernet/mscc/ocelot_regs.c
+++ b/drivers/net/ethernet/mscc/ocelot_regs.c
@@ -5,6 +5,7 @@
* Copyright (c) 2017 Microsemi Corporation
*/
#include "ocelot.h"
+#include <soc/mscc/ocelot_hsio.h>
static const u32 ocelot_ana_regmap[] = {
REG(ANA_ADVLEARN, 0x009000),
@@ -102,82 +103,6 @@ static const u32 ocelot_qs_regmap[] = {
REG(QS_INH_DBG, 0x000048),
};
-static const u32 ocelot_hsio_regmap[] = {
- REG(HSIO_PLL5G_CFG0, 0x000000),
- REG(HSIO_PLL5G_CFG1, 0x000004),
- REG(HSIO_PLL5G_CFG2, 0x000008),
- REG(HSIO_PLL5G_CFG3, 0x00000c),
- REG(HSIO_PLL5G_CFG4, 0x000010),
- REG(HSIO_PLL5G_CFG5, 0x000014),
- REG(HSIO_PLL5G_CFG6, 0x000018),
- REG(HSIO_PLL5G_STATUS0, 0x00001c),
- REG(HSIO_PLL5G_STATUS1, 0x000020),
- REG(HSIO_PLL5G_BIST_CFG0, 0x000024),
- REG(HSIO_PLL5G_BIST_CFG1, 0x000028),
- REG(HSIO_PLL5G_BIST_CFG2, 0x00002c),
- REG(HSIO_PLL5G_BIST_STAT0, 0x000030),
- REG(HSIO_PLL5G_BIST_STAT1, 0x000034),
- REG(HSIO_RCOMP_CFG0, 0x000038),
- REG(HSIO_RCOMP_STATUS, 0x00003c),
- REG(HSIO_SYNC_ETH_CFG, 0x000040),
- REG(HSIO_SYNC_ETH_PLL_CFG, 0x000048),
- REG(HSIO_S1G_DES_CFG, 0x00004c),
- REG(HSIO_S1G_IB_CFG, 0x000050),
- REG(HSIO_S1G_OB_CFG, 0x000054),
- REG(HSIO_S1G_SER_CFG, 0x000058),
- REG(HSIO_S1G_COMMON_CFG, 0x00005c),
- REG(HSIO_S1G_PLL_CFG, 0x000060),
- REG(HSIO_S1G_PLL_STATUS, 0x000064),
- REG(HSIO_S1G_DFT_CFG0, 0x000068),
- REG(HSIO_S1G_DFT_CFG1, 0x00006c),
- REG(HSIO_S1G_DFT_CFG2, 0x000070),
- REG(HSIO_S1G_TP_CFG, 0x000074),
- REG(HSIO_S1G_RC_PLL_BIST_CFG, 0x000078),
- REG(HSIO_S1G_MISC_CFG, 0x00007c),
- REG(HSIO_S1G_DFT_STATUS, 0x000080),
- REG(HSIO_S1G_MISC_STATUS, 0x000084),
- REG(HSIO_MCB_S1G_ADDR_CFG, 0x000088),
- REG(HSIO_S6G_DIG_CFG, 0x00008c),
- REG(HSIO_S6G_DFT_CFG0, 0x000090),
- REG(HSIO_S6G_DFT_CFG1, 0x000094),
- REG(HSIO_S6G_DFT_CFG2, 0x000098),
- REG(HSIO_S6G_TP_CFG0, 0x00009c),
- REG(HSIO_S6G_TP_CFG1, 0x0000a0),
- REG(HSIO_S6G_RC_PLL_BIST_CFG, 0x0000a4),
- REG(HSIO_S6G_MISC_CFG, 0x0000a8),
- REG(HSIO_S6G_OB_ANEG_CFG, 0x0000ac),
- REG(HSIO_S6G_DFT_STATUS, 0x0000b0),
- REG(HSIO_S6G_ERR_CNT, 0x0000b4),
- REG(HSIO_S6G_MISC_STATUS, 0x0000b8),
- REG(HSIO_S6G_DES_CFG, 0x0000bc),
- REG(HSIO_S6G_IB_CFG, 0x0000c0),
- REG(HSIO_S6G_IB_CFG1, 0x0000c4),
- REG(HSIO_S6G_IB_CFG2, 0x0000c8),
- REG(HSIO_S6G_IB_CFG3, 0x0000cc),
- REG(HSIO_S6G_IB_CFG4, 0x0000d0),
- REG(HSIO_S6G_IB_CFG5, 0x0000d4),
- REG(HSIO_S6G_OB_CFG, 0x0000d8),
- REG(HSIO_S6G_OB_CFG1, 0x0000dc),
- REG(HSIO_S6G_SER_CFG, 0x0000e0),
- REG(HSIO_S6G_COMMON_CFG, 0x0000e4),
- REG(HSIO_S6G_PLL_CFG, 0x0000e8),
- REG(HSIO_S6G_ACJTAG_CFG, 0x0000ec),
- REG(HSIO_S6G_GP_CFG, 0x0000f0),
- REG(HSIO_S6G_IB_STATUS0, 0x0000f4),
- REG(HSIO_S6G_IB_STATUS1, 0x0000f8),
- REG(HSIO_S6G_ACJTAG_STATUS, 0x0000fc),
- REG(HSIO_S6G_PLL_STATUS, 0x000100),
- REG(HSIO_S6G_REVID, 0x000104),
- REG(HSIO_MCB_S6G_ADDR_CFG, 0x000108),
- REG(HSIO_HW_CFG, 0x00010c),
- REG(HSIO_HW_QSGMII_CFG, 0x000110),
- REG(HSIO_HW_QSGMII_STAT, 0x000114),
- REG(HSIO_CLK_CFG, 0x000118),
- REG(HSIO_TEMP_SENSOR_CTRL, 0x00011c),
- REG(HSIO_TEMP_SENSOR_CFG, 0x000120),
- REG(HSIO_TEMP_SENSOR_STAT, 0x000124),
-};
-
static const u32 ocelot_qsys_regmap[] = {
REG(QSYS_PORT_MODE, 0x011200),
REG(QSYS_SWITCH_PORT_MODE, 0x011234),
@@ -302,7 +227,6 @@ static const u32 ocelot_sys_regmap[] = {
static const u32 *ocelot_regmap[] = {
[ANA] = ocelot_ana_regmap,
[QS] = ocelot_qs_regmap,
- [HSIO] = ocelot_hsio_regmap,
[QSYS] = ocelot_qsys_regmap,
[REW] = ocelot_rew_regmap,
[SYS] = ocelot_sys_regmap,
@@ -453,9 +377,11 @@ static void ocelot_pll5_init(struct ocelot *ocelot)
/* Configure PLL5. This will need a proper CCF driver
* The values are coming from the VTSS API for Ocelot
*/
- ocelot_write(ocelot, HSIO_PLL5G_CFG4_IB_CTRL(0x7600) |
- HSIO_PLL5G_CFG4_IB_BIAS_CTRL(0x8), HSIO_PLL5G_CFG4);
- ocelot_write(ocelot, HSIO_PLL5G_CFG0_CORE_CLK_DIV(0x11) |
+ regmap_write(ocelot->targets[HSIO], HSIO_PLL5G_CFG4,
+ HSIO_PLL5G_CFG4_IB_CTRL(0x7600) |
+ HSIO_PLL5G_CFG4_IB_BIAS_CTRL(0x8));
+ regmap_write(ocelot->targets[HSIO], HSIO_PLL5G_CFG0,
+ HSIO_PLL5G_CFG0_CORE_CLK_DIV(0x11) |
HSIO_PLL5G_CFG0_CPU_CLK_DIV(2) |
HSIO_PLL5G_CFG0_ENA_BIAS |
HSIO_PLL5G_CFG0_ENA_VCO_BUF |
@@ -465,13 +391,14 @@ static void ocelot_pll5_init(struct ocelot *ocelot)
HSIO_PLL5G_CFG0_SELBGV820(4) |
HSIO_PLL5G_CFG0_DIV4 |
HSIO_PLL5G_CFG0_ENA_CLKTREE |
- HSIO_PLL5G_CFG0_ENA_LANE, HSIO_PLL5G_CFG0);
- ocelot_write(ocelot, HSIO_PLL5G_CFG2_EN_RESET_FRQ_DET |
+ HSIO_PLL5G_CFG0_ENA_LANE);
+ regmap_write(ocelot->targets[HSIO], HSIO_PLL5G_CFG2,
+ HSIO_PLL5G_CFG2_EN_RESET_FRQ_DET |
HSIO_PLL5G_CFG2_EN_RESET_OVERRUN |
HSIO_PLL5G_CFG2_GAIN_TEST(0x8) |
HSIO_PLL5G_CFG2_ENA_AMPCTRL |
HSIO_PLL5G_CFG2_PWD_AMPCTRL_N |
- HSIO_PLL5G_CFG2_AMPC_SEL(0x10), HSIO_PLL5G_CFG2);
+ HSIO_PLL5G_CFG2_AMPC_SEL(0x10));
}
int ocelot_chip_init(struct ocelot *ocelot)
diff --git a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c
index b2d2ec8c11e2..5f384f73007d 100644
--- a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c
+++ b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c
@@ -70,7 +70,6 @@
#include <net/tcp.h>
#include <asm/byteorder.h>
#include <asm/processor.h>
-#include <net/busy_poll.h>
#include "myri10ge_mcp.h"
#include "myri10ge_mcp_gen_header.h"
diff --git a/drivers/net/ethernet/neterion/s2io.c b/drivers/net/ethernet/neterion/s2io.c
index b8983e73265a..82be90075695 100644
--- a/drivers/net/ethernet/neterion/s2io.c
+++ b/drivers/net/ethernet/neterion/s2io.c
@@ -75,6 +75,7 @@
#include <linux/tcp.h>
#include <linux/uaccess.h>
#include <linux/io.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/slab.h>
#include <linux/prefetch.h>
#include <net/tcp.h>
@@ -491,7 +492,7 @@ static struct pci_driver s2io_driver = {
};
/* A simplifier macro used both by init and free shared_mem Fns(). */
-#define TXD_MEM_PAGE_CNT(len, per_each) ((len+per_each - 1) / per_each)
+#define TXD_MEM_PAGE_CNT(len, per_each) DIV_ROUND_UP(len, per_each)
/* netqueue manipulation helper functions */
static inline void s2io_stop_all_tx_queue(struct s2io_nic *sp)
@@ -3679,11 +3680,9 @@ static void restore_xmsi_data(struct s2io_nic *nic)
writeq(nic->msix_info[i].data, &bar0->xmsi_data);
val64 = (s2BIT(7) | s2BIT(15) | vBIT(msix_index, 26, 6));
writeq(val64, &bar0->xmsi_access);
- if (wait_for_msix_trans(nic, msix_index)) {
+ if (wait_for_msix_trans(nic, msix_index))
DBG_PRINT(ERR_DBG, "%s: index: %d failed\n",
__func__, msix_index);
- continue;
- }
}
}
diff --git a/drivers/net/ethernet/neterion/s2io.h b/drivers/net/ethernet/neterion/s2io.h
index 1a24a7218794..0a921f30f98f 100644
--- a/drivers/net/ethernet/neterion/s2io.h
+++ b/drivers/net/ethernet/neterion/s2io.h
@@ -10,6 +10,7 @@
* system is licensed under the GPL.
* See the file COPYING in this distribution for more information.
************************************************************************/
+#include <linux/io-64-nonatomic-lo-hi.h>
#ifndef _S2IO_H
#define _S2IO_H
@@ -970,27 +971,6 @@ struct s2io_nic {
#define RESET_ERROR 1
#define CMD_ERROR 2
-/* OS related system calls */
-#ifndef readq
-static inline u64 readq(void __iomem *addr)
-{
- u64 ret = 0;
- ret = readl(addr + 4);
- ret <<= 32;
- ret |= readl(addr);
-
- return ret;
-}
-#endif
-
-#ifndef writeq
-static inline void writeq(u64 val, void __iomem *addr)
-{
- writel((u32) (val), addr);
- writel((u32) (val >> 32), (addr + 4));
-}
-#endif
-
/*
* Some registers have to be written in a particular order to
* expect correct hardware operation. The macro SPECIAL_REG_WRITE
diff --git a/drivers/net/ethernet/neterion/vxge/vxge-config.c b/drivers/net/ethernet/neterion/vxge/vxge-config.c
index 398011c87643..4c1fb7e57888 100644
--- a/drivers/net/ethernet/neterion/vxge/vxge-config.c
+++ b/drivers/net/ethernet/neterion/vxge/vxge-config.c
@@ -13,6 +13,7 @@
******************************************************************************/
#include <linux/vmalloc.h>
#include <linux/etherdevice.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/pci.h>
#include <linux/slab.h>
diff --git a/drivers/net/ethernet/neterion/vxge/vxge-config.h b/drivers/net/ethernet/neterion/vxge/vxge-config.h
index d743a37a3cee..e678ba379598 100644
--- a/drivers/net/ethernet/neterion/vxge/vxge-config.h
+++ b/drivers/net/ethernet/neterion/vxge/vxge-config.h
@@ -2011,26 +2011,6 @@ enum vxge_hw_status vxge_hw_vpath_mtu_set(
void
vxge_hw_vpath_rx_doorbell_init(struct __vxge_hw_vpath_handle *vp);
-#ifndef readq
-static inline u64 readq(void __iomem *addr)
-{
- u64 ret = 0;
- ret = readl(addr + 4);
- ret <<= 32;
- ret |= readl(addr);
-
- return ret;
-}
-#endif
-
-#ifndef writeq
-static inline void writeq(u64 val, void __iomem *addr)
-{
- writel((u32) (val), addr);
- writel((u32) (val >> 32), (addr + 4));
-}
-#endif
-
static inline void __vxge_hw_pio_mem_write32_upper(u32 val, void __iomem *addr)
{
writel(val, addr + 4);
diff --git a/drivers/net/ethernet/neterion/vxge/vxge-traffic.c b/drivers/net/ethernet/neterion/vxge/vxge-traffic.c
index 0c3b5dea2858..f7a0d1d5885e 100644
--- a/drivers/net/ethernet/neterion/vxge/vxge-traffic.c
+++ b/drivers/net/ethernet/neterion/vxge/vxge-traffic.c
@@ -12,6 +12,7 @@
* Copyright(c) 2002-2010 Exar Corp.
******************************************************************************/
#include <linux/etherdevice.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/prefetch.h>
#include "vxge-traffic.h"
@@ -2261,7 +2262,7 @@ void vxge_hw_vpath_msix_clear(struct __vxge_hw_vpath_handle *vp, int msix_id)
{
struct __vxge_hw_device *hldev = vp->vpath->hldev;
- if ((hldev->config.intr_mode == VXGE_HW_INTR_MODE_MSIX_ONE_SHOT))
+ if (hldev->config.intr_mode == VXGE_HW_INTR_MODE_MSIX_ONE_SHOT)
__vxge_hw_pio_mem_write32_upper(
(u32) vxge_bVALn(vxge_mBIT((msix_id >> 2)), 0, 32),
&hldev->common_reg->clr_msix_one_shot_vec[msix_id % 4]);
diff --git a/drivers/net/ethernet/netronome/nfp/abm/ctrl.c b/drivers/net/ethernet/netronome/nfp/abm/ctrl.c
index b157ccd8c80f..3c661f422688 100644
--- a/drivers/net/ethernet/netronome/nfp/abm/ctrl.c
+++ b/drivers/net/ethernet/netronome/nfp/abm/ctrl.c
@@ -1,36 +1,5 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
-/*
- * Copyright (C) 2018 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2018 Netronome Systems, Inc. */
#include <linux/kernel.h>
@@ -55,30 +24,21 @@
#define NFP_QMSTAT_DROP 16
#define NFP_QMSTAT_ECN 24
-static unsigned long long
-nfp_abm_q_lvl_thrs(struct nfp_abm_link *alink, unsigned int queue)
-{
- return alink->abm->q_lvls->addr +
- (alink->queue_base + queue) * NFP_QLVL_STRIDE + NFP_QLVL_THRS;
-}
-
static int
nfp_abm_ctrl_stat(struct nfp_abm_link *alink, const struct nfp_rtsym *sym,
unsigned int stride, unsigned int offset, unsigned int i,
bool is_u64, u64 *res)
{
struct nfp_cpp *cpp = alink->abm->app->cpp;
- u32 val32, mur;
- u64 val, addr;
+ u64 val, sym_offset;
+ u32 val32;
int err;
- mur = NFP_CPP_ATOMIC_RD(sym->target, sym->domain);
-
- addr = sym->addr + (alink->queue_base + i) * stride + offset;
+ sym_offset = (alink->queue_base + i) * stride + offset;
if (is_u64)
- err = nfp_cpp_readq(cpp, mur, addr, &val);
+ err = __nfp_rtsym_readq(cpp, sym, 3, 0, sym_offset, &val);
else
- err = nfp_cpp_readl(cpp, mur, addr, &val32);
+ err = __nfp_rtsym_readl(cpp, sym, 3, 0, sym_offset, &val32);
if (err) {
nfp_err(cpp,
"RED offload reading stat failed on vNIC %d queue %d\n",
@@ -114,13 +74,12 @@ nfp_abm_ctrl_stat_all(struct nfp_abm_link *alink, const struct nfp_rtsym *sym,
int nfp_abm_ctrl_set_q_lvl(struct nfp_abm_link *alink, unsigned int i, u32 val)
{
struct nfp_cpp *cpp = alink->abm->app->cpp;
- u32 muw;
+ u64 sym_offset;
int err;
- muw = NFP_CPP_ATOMIC_WR(alink->abm->q_lvls->target,
- alink->abm->q_lvls->domain);
-
- err = nfp_cpp_writel(cpp, muw, nfp_abm_q_lvl_thrs(alink, i), val);
+ sym_offset = (alink->queue_base + i) * NFP_QLVL_STRIDE + NFP_QLVL_THRS;
+ err = __nfp_rtsym_writel(cpp, alink->abm->q_lvls, 4, 0,
+ sym_offset, val);
if (err) {
nfp_err(cpp, "RED offload setting level failed on vNIC %d queue %d\n",
alink->id, i);
@@ -290,10 +249,10 @@ nfp_abm_ctrl_find_rtsym(struct nfp_pf *pf, const char *name, unsigned int size)
nfp_err(pf->cpp, "Symbol '%s' not found\n", name);
return ERR_PTR(-ENOENT);
}
- if (sym->size != size) {
+ if (nfp_rtsym_size(sym) != size) {
nfp_err(pf->cpp,
"Symbol '%s' wrong size: expected %u got %llu\n",
- name, size, sym->size);
+ name, size, nfp_rtsym_size(sym));
return ERR_PTR(-EINVAL);
}
diff --git a/drivers/net/ethernet/netronome/nfp/abm/main.c b/drivers/net/ethernet/netronome/nfp/abm/main.c
index b84a6c2d387b..c0830c0c2c3f 100644
--- a/drivers/net/ethernet/netronome/nfp/abm/main.c
+++ b/drivers/net/ethernet/netronome/nfp/abm/main.c
@@ -1,36 +1,5 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
-/*
- * Copyright (C) 2018 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2018 Netronome Systems, Inc. */
#include <linux/bitfield.h>
#include <linux/etherdevice.h>
@@ -540,8 +509,9 @@ nfp_abm_vnic_set_mac(struct nfp_pf *pf, struct nfp_abm *abm, struct nfp_net *nn,
{
struct nfp_eth_table_port *eth_port = &pf->eth_tbl->ports[id];
u8 mac_addr[ETH_ALEN];
- const char *mac_str;
- char name[32];
+ struct nfp_nsp *nsp;
+ char hwinfo[32];
+ int err;
if (id > pf->eth_tbl->count) {
nfp_warn(pf->cpp, "No entry for persistent MAC address\n");
@@ -549,22 +519,37 @@ nfp_abm_vnic_set_mac(struct nfp_pf *pf, struct nfp_abm *abm, struct nfp_net *nn,
return;
}
- snprintf(name, sizeof(name), "eth%u.mac.pf%u",
+ snprintf(hwinfo, sizeof(hwinfo), "eth%u.mac.pf%u",
eth_port->eth_index, abm->pf_id);
- mac_str = nfp_hwinfo_lookup(pf->hwinfo, name);
- if (!mac_str) {
- nfp_warn(pf->cpp, "Can't lookup persistent MAC address (%s)\n",
- name);
+ nsp = nfp_nsp_open(pf->cpp);
+ if (IS_ERR(nsp)) {
+ nfp_warn(pf->cpp, "Failed to access the NSP for persistent MAC address: %ld\n",
+ PTR_ERR(nsp));
+ eth_hw_addr_random(nn->dp.netdev);
+ return;
+ }
+
+ if (!nfp_nsp_has_hwinfo_lookup(nsp)) {
+ nfp_warn(pf->cpp, "NSP doesn't support PF MAC generation\n");
+ eth_hw_addr_random(nn->dp.netdev);
+ return;
+ }
+
+ err = nfp_nsp_hwinfo_lookup(nsp, hwinfo, sizeof(hwinfo));
+ nfp_nsp_close(nsp);
+ if (err) {
+ nfp_warn(pf->cpp, "Reading persistent MAC address failed: %d\n",
+ err);
eth_hw_addr_random(nn->dp.netdev);
return;
}
- if (sscanf(mac_str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
+ if (sscanf(hwinfo, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
&mac_addr[0], &mac_addr[1], &mac_addr[2],
&mac_addr[3], &mac_addr[4], &mac_addr[5]) != 6) {
nfp_warn(pf->cpp, "Can't parse persistent MAC address (%s)\n",
- mac_str);
+ hwinfo);
eth_hw_addr_random(nn->dp.netdev);
return;
}
diff --git a/drivers/net/ethernet/netronome/nfp/abm/main.h b/drivers/net/ethernet/netronome/nfp/abm/main.h
index 934a70835473..f907b7d98917 100644
--- a/drivers/net/ethernet/netronome/nfp/abm/main.h
+++ b/drivers/net/ethernet/netronome/nfp/abm/main.h
@@ -1,36 +1,5 @@
-/* SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) */
-/*
- * Copyright (C) 2018 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/* Copyright (C) 2018 Netronome Systems, Inc. */
#ifndef __NFP_ABM_H__
#define __NFP_ABM_H__ 1
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/cmsg.c b/drivers/net/ethernet/netronome/nfp/bpf/cmsg.c
index 2572a4b91c7c..9b6cfa697879 100644
--- a/drivers/net/ethernet/netronome/nfp/bpf/cmsg.c
+++ b/drivers/net/ethernet/netronome/nfp/bpf/cmsg.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2017-2018 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2017-2018 Netronome Systems, Inc. */
#include <linux/bpf.h>
#include <linux/bitops.h>
@@ -89,15 +59,32 @@ nfp_bpf_cmsg_alloc(struct nfp_app_bpf *bpf, unsigned int size)
return skb;
}
+static unsigned int
+nfp_bpf_cmsg_map_req_size(struct nfp_app_bpf *bpf, unsigned int n)
+{
+ unsigned int size;
+
+ size = sizeof(struct cmsg_req_map_op);
+ size += (bpf->cmsg_key_sz + bpf->cmsg_val_sz) * n;
+
+ return size;
+}
+
static struct sk_buff *
nfp_bpf_cmsg_map_req_alloc(struct nfp_app_bpf *bpf, unsigned int n)
{
+ return nfp_bpf_cmsg_alloc(bpf, nfp_bpf_cmsg_map_req_size(bpf, n));
+}
+
+static unsigned int
+nfp_bpf_cmsg_map_reply_size(struct nfp_app_bpf *bpf, unsigned int n)
+{
unsigned int size;
- size = sizeof(struct cmsg_req_map_op);
- size += sizeof(struct cmsg_key_value_pair) * n;
+ size = sizeof(struct cmsg_reply_map_op);
+ size += (bpf->cmsg_key_sz + bpf->cmsg_val_sz) * n;
- return nfp_bpf_cmsg_alloc(bpf, size);
+ return size;
}
static u8 nfp_bpf_cmsg_get_type(struct sk_buff *skb)
@@ -338,6 +325,34 @@ void nfp_bpf_ctrl_free_map(struct nfp_app_bpf *bpf, struct nfp_bpf_map *nfp_map)
dev_consume_skb_any(skb);
}
+static void *
+nfp_bpf_ctrl_req_key(struct nfp_app_bpf *bpf, struct cmsg_req_map_op *req,
+ unsigned int n)
+{
+ return &req->data[bpf->cmsg_key_sz * n + bpf->cmsg_val_sz * n];
+}
+
+static void *
+nfp_bpf_ctrl_req_val(struct nfp_app_bpf *bpf, struct cmsg_req_map_op *req,
+ unsigned int n)
+{
+ return &req->data[bpf->cmsg_key_sz * (n + 1) + bpf->cmsg_val_sz * n];
+}
+
+static void *
+nfp_bpf_ctrl_reply_key(struct nfp_app_bpf *bpf, struct cmsg_reply_map_op *reply,
+ unsigned int n)
+{
+ return &reply->data[bpf->cmsg_key_sz * n + bpf->cmsg_val_sz * n];
+}
+
+static void *
+nfp_bpf_ctrl_reply_val(struct nfp_app_bpf *bpf, struct cmsg_reply_map_op *reply,
+ unsigned int n)
+{
+ return &reply->data[bpf->cmsg_key_sz * (n + 1) + bpf->cmsg_val_sz * n];
+}
+
static int
nfp_bpf_ctrl_entry_op(struct bpf_offloaded_map *offmap,
enum nfp_bpf_cmsg_type op,
@@ -366,12 +381,13 @@ nfp_bpf_ctrl_entry_op(struct bpf_offloaded_map *offmap,
/* Copy inputs */
if (key)
- memcpy(&req->elem[0].key, key, map->key_size);
+ memcpy(nfp_bpf_ctrl_req_key(bpf, req, 0), key, map->key_size);
if (value)
- memcpy(&req->elem[0].value, value, map->value_size);
+ memcpy(nfp_bpf_ctrl_req_val(bpf, req, 0), value,
+ map->value_size);
skb = nfp_bpf_cmsg_communicate(bpf, skb, op,
- sizeof(*reply) + sizeof(*reply->elem));
+ nfp_bpf_cmsg_map_reply_size(bpf, 1));
if (IS_ERR(skb))
return PTR_ERR(skb);
@@ -382,9 +398,11 @@ nfp_bpf_ctrl_entry_op(struct bpf_offloaded_map *offmap,
/* Copy outputs */
if (out_key)
- memcpy(out_key, &reply->elem[0].key, map->key_size);
+ memcpy(out_key, nfp_bpf_ctrl_reply_key(bpf, reply, 0),
+ map->key_size);
if (out_value)
- memcpy(out_value, &reply->elem[0].value, map->value_size);
+ memcpy(out_value, nfp_bpf_ctrl_reply_val(bpf, reply, 0),
+ map->value_size);
dev_consume_skb_any(skb);
@@ -428,6 +446,13 @@ int nfp_bpf_ctrl_getnext_entry(struct bpf_offloaded_map *offmap,
key, NULL, 0, next_key, NULL);
}
+unsigned int nfp_bpf_ctrl_cmsg_mtu(struct nfp_app_bpf *bpf)
+{
+ return max3((unsigned int)NFP_NET_DEFAULT_MTU,
+ nfp_bpf_cmsg_map_req_size(bpf, 1),
+ nfp_bpf_cmsg_map_reply_size(bpf, 1));
+}
+
void nfp_bpf_ctrl_msg_rx(struct nfp_app *app, struct sk_buff *skb)
{
struct nfp_app_bpf *bpf = app->priv;
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/fw.h b/drivers/net/ethernet/netronome/nfp/bpf/fw.h
index e4f9b7ec8528..721921bcf120 100644
--- a/drivers/net/ethernet/netronome/nfp/bpf/fw.h
+++ b/drivers/net/ethernet/netronome/nfp/bpf/fw.h
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2017-2018 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/* Copyright (C) 2017-2018 Netronome Systems, Inc. */
#ifndef NFP_BPF_FW_H
#define NFP_BPF_FW_H 1
@@ -52,6 +22,7 @@ enum bpf_cap_tlv_type {
NFP_BPF_CAP_TYPE_RANDOM = 4,
NFP_BPF_CAP_TYPE_QUEUE_SELECT = 5,
NFP_BPF_CAP_TYPE_ADJUST_TAIL = 6,
+ NFP_BPF_CAP_TYPE_ABI_VERSION = 7,
};
struct nfp_bpf_cap_tlv_func {
@@ -98,6 +69,7 @@ enum nfp_bpf_cmsg_type {
#define CMSG_TYPE_MAP_REPLY_BIT 7
#define __CMSG_REPLY(req) (BIT(CMSG_TYPE_MAP_REPLY_BIT) | (req))
+/* BPF ABIv2 fixed-length control message fields */
#define CMSG_MAP_KEY_LW 16
#define CMSG_MAP_VALUE_LW 16
@@ -147,24 +119,19 @@ struct cmsg_reply_map_free_tbl {
__be32 count;
};
-struct cmsg_key_value_pair {
- __be32 key[CMSG_MAP_KEY_LW];
- __be32 value[CMSG_MAP_VALUE_LW];
-};
-
struct cmsg_req_map_op {
struct cmsg_hdr hdr;
__be32 tid;
__be32 count;
__be32 flags;
- struct cmsg_key_value_pair elem[0];
+ u8 data[0];
};
struct cmsg_reply_map_op {
struct cmsg_reply_map_simple reply_hdr;
__be32 count;
__be32 resv;
- struct cmsg_key_value_pair elem[0];
+ u8 data[0];
};
struct cmsg_bpf_event {
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/jit.c b/drivers/net/ethernet/netronome/nfp/bpf/jit.c
index eff57f7d056a..97d33bb4d84d 100644
--- a/drivers/net/ethernet/netronome/nfp/bpf/jit.c
+++ b/drivers/net/ethernet/netronome/nfp/bpf/jit.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2016-2018 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2016-2018 Netronome Systems, Inc. */
#define pr_fmt(fmt) "NFP net bpf: " fmt
@@ -267,6 +237,38 @@ emit_br_bset(struct nfp_prog *nfp_prog, swreg src, u8 bit, u16 addr, u8 defer)
}
static void
+__emit_br_alu(struct nfp_prog *nfp_prog, u16 areg, u16 breg, u16 imm_hi,
+ u8 defer, bool dst_lmextn, bool src_lmextn)
+{
+ u64 insn;
+
+ insn = OP_BR_ALU_BASE |
+ FIELD_PREP(OP_BR_ALU_A_SRC, areg) |
+ FIELD_PREP(OP_BR_ALU_B_SRC, breg) |
+ FIELD_PREP(OP_BR_ALU_DEFBR, defer) |
+ FIELD_PREP(OP_BR_ALU_IMM_HI, imm_hi) |
+ FIELD_PREP(OP_BR_ALU_SRC_LMEXTN, src_lmextn) |
+ FIELD_PREP(OP_BR_ALU_DST_LMEXTN, dst_lmextn);
+
+ nfp_prog_push(nfp_prog, insn);
+}
+
+static void emit_rtn(struct nfp_prog *nfp_prog, swreg base, u8 defer)
+{
+ struct nfp_insn_ur_regs reg;
+ int err;
+
+ err = swreg_to_unrestricted(reg_none(), base, reg_imm(0), &reg);
+ if (err) {
+ nfp_prog->error = err;
+ return;
+ }
+
+ __emit_br_alu(nfp_prog, reg.areg, reg.breg, 0, defer, reg.dst_lmextn,
+ reg.src_lmextn);
+}
+
+static void
__emit_immed(struct nfp_prog *nfp_prog, u16 areg, u16 breg, u16 imm_hi,
enum immed_width width, bool invert,
enum immed_shift shift, bool wr_both,
@@ -1137,7 +1139,7 @@ mem_op_stack(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
unsigned int size, unsigned int ptr_off, u8 gpr, u8 ptr_gpr,
bool clr_gpr, lmem_step step)
{
- s32 off = nfp_prog->stack_depth + meta->insn.off + ptr_off;
+ s32 off = nfp_prog->stack_frame_depth + meta->insn.off + ptr_off;
bool first = true, last;
bool needs_inc = false;
swreg stack_off_reg;
@@ -1146,7 +1148,8 @@ mem_op_stack(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
bool lm3 = true;
int ret;
- if (meta->ptr_not_const) {
+ if (meta->ptr_not_const ||
+ meta->flags & FLAG_INSN_PTR_CALLER_STACK_FRAME) {
/* Use of the last encountered ptr_off is OK, they all have
* the same alignment. Depend on low bits of value being
* discarded when written to LMaddr register.
@@ -1695,7 +1698,7 @@ map_call_stack_common(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
s64 lm_off;
/* We only have to reload LM0 if the key is not at start of stack */
- lm_off = nfp_prog->stack_depth;
+ lm_off = nfp_prog->stack_frame_depth;
lm_off += meta->arg2.reg.var_off.value + meta->arg2.reg.off;
load_lm_ptr = meta->arg2.var_off || lm_off;
@@ -1808,10 +1811,10 @@ static int mov_reg64(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
swreg stack_depth_reg;
stack_depth_reg = ur_load_imm_any(nfp_prog,
- nfp_prog->stack_depth,
+ nfp_prog->stack_frame_depth,
stack_imm(nfp_prog));
- emit_alu(nfp_prog, reg_both(dst),
- stack_reg(nfp_prog), ALU_OP_ADD, stack_depth_reg);
+ emit_alu(nfp_prog, reg_both(dst), stack_reg(nfp_prog),
+ ALU_OP_ADD, stack_depth_reg);
wrp_immed(nfp_prog, reg_both(dst + 1), 0);
} else {
wrp_reg_mov(nfp_prog, dst, src);
@@ -3081,7 +3084,93 @@ static int jne_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
return wrp_test_reg(nfp_prog, meta, ALU_OP_XOR, BR_BNE);
}
-static int call(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
+static int
+bpf_to_bpf_call(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
+{
+ u32 ret_tgt, stack_depth, offset_br;
+ swreg tmp_reg;
+
+ stack_depth = round_up(nfp_prog->stack_frame_depth, STACK_FRAME_ALIGN);
+ /* Space for saving the return address is accounted for by the callee,
+ * so stack_depth can be zero for the main function.
+ */
+ if (stack_depth) {
+ tmp_reg = ur_load_imm_any(nfp_prog, stack_depth,
+ stack_imm(nfp_prog));
+ emit_alu(nfp_prog, stack_reg(nfp_prog),
+ stack_reg(nfp_prog), ALU_OP_ADD, tmp_reg);
+ emit_csr_wr(nfp_prog, stack_reg(nfp_prog),
+ NFP_CSR_ACT_LM_ADDR0);
+ }
+
+ /* Two cases for jumping to the callee:
+ *
+ * - If callee uses and needs to save R6~R9 then:
+ * 1. Put the start offset of the callee into imm_b(). This will
+ * require a fixup step, as we do not necessarily know this
+ * address yet.
+ * 2. Put the return address from the callee to the caller into
+ * register ret_reg().
+ * 3. (After defer slots are consumed) Jump to the subroutine that
+ * pushes the registers to the stack.
+ * The subroutine acts as a trampoline, and returns to the address in
+ * imm_b(), i.e. jumps to the callee.
+ *
+ * - If callee does not need to save R6~R9 then just load return
+ * address to the caller in ret_reg(), and jump to the callee
+ * directly.
+ *
+ * Using ret_reg() to pass the return address to the callee is set here
+ * as a convention. The callee can then push this address onto its
+ * stack frame in its prologue. The advantages of passing the return
+ * address through ret_reg(), instead of pushing it to the stack right
+ * here, are the following:
+ * - It looks cleaner.
+ * - If the called function is called multiple time, we get a lower
+ * program size.
+ * - We save two no-op instructions that should be added just before
+ * the emit_br() when stack depth is not null otherwise.
+ * - If we ever find a register to hold the return address during whole
+ * execution of the callee, we will not have to push the return
+ * address to the stack for leaf functions.
+ */
+ if (!meta->jmp_dst) {
+ pr_err("BUG: BPF-to-BPF call has no destination recorded\n");
+ return -ELOOP;
+ }
+ if (nfp_prog->subprog[meta->jmp_dst->subprog_idx].needs_reg_push) {
+ ret_tgt = nfp_prog_current_offset(nfp_prog) + 3;
+ emit_br_relo(nfp_prog, BR_UNC, BR_OFF_RELO, 2,
+ RELO_BR_GO_CALL_PUSH_REGS);
+ offset_br = nfp_prog_current_offset(nfp_prog);
+ wrp_immed_relo(nfp_prog, imm_b(nfp_prog), 0, RELO_IMMED_REL);
+ } else {
+ ret_tgt = nfp_prog_current_offset(nfp_prog) + 2;
+ emit_br(nfp_prog, BR_UNC, meta->n + 1 + meta->insn.imm, 1);
+ offset_br = nfp_prog_current_offset(nfp_prog);
+ }
+ wrp_immed_relo(nfp_prog, ret_reg(nfp_prog), ret_tgt, RELO_IMMED_REL);
+
+ if (!nfp_prog_confirm_current_offset(nfp_prog, ret_tgt))
+ return -EINVAL;
+
+ if (stack_depth) {
+ tmp_reg = ur_load_imm_any(nfp_prog, stack_depth,
+ stack_imm(nfp_prog));
+ emit_alu(nfp_prog, stack_reg(nfp_prog),
+ stack_reg(nfp_prog), ALU_OP_SUB, tmp_reg);
+ emit_csr_wr(nfp_prog, stack_reg(nfp_prog),
+ NFP_CSR_ACT_LM_ADDR0);
+ wrp_nops(nfp_prog, 3);
+ }
+
+ meta->num_insns_after_br = nfp_prog_current_offset(nfp_prog);
+ meta->num_insns_after_br -= offset_br;
+
+ return 0;
+}
+
+static int helper_call(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
{
switch (meta->insn.imm) {
case BPF_FUNC_xdp_adjust_head:
@@ -3102,6 +3191,19 @@ static int call(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
}
}
+static int call(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
+{
+ if (is_mbpf_pseudo_call(meta))
+ return bpf_to_bpf_call(nfp_prog, meta);
+ else
+ return helper_call(nfp_prog, meta);
+}
+
+static bool nfp_is_main_function(struct nfp_insn_meta *meta)
+{
+ return meta->subprog_idx == 0;
+}
+
static int goto_out(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
{
emit_br_relo(nfp_prog, BR_UNC, BR_OFF_RELO, 0, RELO_BR_GO_OUT);
@@ -3109,6 +3211,39 @@ static int goto_out(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
return 0;
}
+static int
+nfp_subprog_epilogue(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
+{
+ if (nfp_prog->subprog[meta->subprog_idx].needs_reg_push) {
+ /* Pop R6~R9 to the stack via related subroutine.
+ * We loaded the return address to the caller into ret_reg().
+ * This means that the subroutine does not come back here, we
+ * make it jump back to the subprogram caller directly!
+ */
+ emit_br_relo(nfp_prog, BR_UNC, BR_OFF_RELO, 1,
+ RELO_BR_GO_CALL_POP_REGS);
+ /* Pop return address from the stack. */
+ wrp_mov(nfp_prog, ret_reg(nfp_prog), reg_lm(0, 0));
+ } else {
+ /* Pop return address from the stack. */
+ wrp_mov(nfp_prog, ret_reg(nfp_prog), reg_lm(0, 0));
+ /* Jump back to caller if no callee-saved registers were used
+ * by the subprogram.
+ */
+ emit_rtn(nfp_prog, ret_reg(nfp_prog), 0);
+ }
+
+ return 0;
+}
+
+static int jmp_exit(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
+{
+ if (nfp_is_main_function(meta))
+ return goto_out(nfp_prog, meta);
+ else
+ return nfp_subprog_epilogue(nfp_prog, meta);
+}
+
static const instr_cb_t instr_cb[256] = {
[BPF_ALU64 | BPF_MOV | BPF_X] = mov_reg64,
[BPF_ALU64 | BPF_MOV | BPF_K] = mov_imm64,
@@ -3197,36 +3332,66 @@ static const instr_cb_t instr_cb[256] = {
[BPF_JMP | BPF_JSET | BPF_X] = jset_reg,
[BPF_JMP | BPF_JNE | BPF_X] = jne_reg,
[BPF_JMP | BPF_CALL] = call,
- [BPF_JMP | BPF_EXIT] = goto_out,
+ [BPF_JMP | BPF_EXIT] = jmp_exit,
};
/* --- Assembler logic --- */
+static int
+nfp_fixup_immed_relo(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
+ struct nfp_insn_meta *jmp_dst, u32 br_idx)
+{
+ if (immed_get_value(nfp_prog->prog[br_idx + 1])) {
+ pr_err("BUG: failed to fix up callee register saving\n");
+ return -EINVAL;
+ }
+
+ immed_set_value(&nfp_prog->prog[br_idx + 1], jmp_dst->off);
+
+ return 0;
+}
+
static int nfp_fixup_branches(struct nfp_prog *nfp_prog)
{
struct nfp_insn_meta *meta, *jmp_dst;
u32 idx, br_idx;
+ int err;
list_for_each_entry(meta, &nfp_prog->insns, l) {
if (meta->skip)
continue;
- if (meta->insn.code == (BPF_JMP | BPF_CALL))
- continue;
if (BPF_CLASS(meta->insn.code) != BPF_JMP)
continue;
+ if (meta->insn.code == (BPF_JMP | BPF_EXIT) &&
+ !nfp_is_main_function(meta))
+ continue;
+ if (is_mbpf_helper_call(meta))
+ continue;
if (list_is_last(&meta->l, &nfp_prog->insns))
br_idx = nfp_prog->last_bpf_off;
else
br_idx = list_next_entry(meta, l)->off - 1;
+ /* For BPF-to-BPF function call, a stack adjustment sequence is
+ * generated after the return instruction. Therefore, we must
+ * withdraw the length of this sequence to have br_idx pointing
+ * to where the "branch" NFP instruction is expected to be.
+ */
+ if (is_mbpf_pseudo_call(meta))
+ br_idx -= meta->num_insns_after_br;
+
if (!nfp_is_br(nfp_prog->prog[br_idx])) {
pr_err("Fixup found block not ending in branch %d %02x %016llx!!\n",
br_idx, meta->insn.code, nfp_prog->prog[br_idx]);
return -ELOOP;
}
+
+ if (meta->insn.code == (BPF_JMP | BPF_EXIT))
+ continue;
+
/* Leave special branches for later */
if (FIELD_GET(OP_RELO_TYPE, nfp_prog->prog[br_idx]) !=
- RELO_BR_REL)
+ RELO_BR_REL && !is_mbpf_pseudo_call(meta))
continue;
if (!meta->jmp_dst) {
@@ -3241,6 +3406,18 @@ static int nfp_fixup_branches(struct nfp_prog *nfp_prog)
return -ELOOP;
}
+ if (is_mbpf_pseudo_call(meta) &&
+ nfp_prog->subprog[jmp_dst->subprog_idx].needs_reg_push) {
+ err = nfp_fixup_immed_relo(nfp_prog, meta,
+ jmp_dst, br_idx);
+ if (err)
+ return err;
+ }
+
+ if (FIELD_GET(OP_RELO_TYPE, nfp_prog->prog[br_idx]) !=
+ RELO_BR_REL)
+ continue;
+
for (idx = meta->off; idx <= br_idx; idx++) {
if (!nfp_is_br(nfp_prog->prog[idx]))
continue;
@@ -3258,6 +3435,27 @@ static void nfp_intro(struct nfp_prog *nfp_prog)
plen_reg(nfp_prog), ALU_OP_AND, pv_len(nfp_prog));
}
+static void
+nfp_subprog_prologue(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
+{
+ /* Save return address into the stack. */
+ wrp_mov(nfp_prog, reg_lm(0, 0), ret_reg(nfp_prog));
+}
+
+static void
+nfp_start_subprog(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
+{
+ unsigned int depth = nfp_prog->subprog[meta->subprog_idx].stack_depth;
+
+ nfp_prog->stack_frame_depth = round_up(depth, 4);
+ nfp_subprog_prologue(nfp_prog, meta);
+}
+
+bool nfp_is_subprog_start(struct nfp_insn_meta *meta)
+{
+ return meta->flags & FLAG_INSN_IS_SUBPROG_START;
+}
+
static void nfp_outro_tc_da(struct nfp_prog *nfp_prog)
{
/* TC direct-action mode:
@@ -3348,6 +3546,67 @@ static void nfp_outro_xdp(struct nfp_prog *nfp_prog)
emit_ld_field(nfp_prog, reg_a(0), 0xc, reg_b(2), SHF_SC_L_SHF, 16);
}
+static bool nfp_prog_needs_callee_reg_save(struct nfp_prog *nfp_prog)
+{
+ unsigned int idx;
+
+ for (idx = 1; idx < nfp_prog->subprog_cnt; idx++)
+ if (nfp_prog->subprog[idx].needs_reg_push)
+ return true;
+
+ return false;
+}
+
+static void nfp_push_callee_registers(struct nfp_prog *nfp_prog)
+{
+ u8 reg;
+
+ /* Subroutine: Save all callee saved registers (R6 ~ R9).
+ * imm_b() holds the return address.
+ */
+ nfp_prog->tgt_call_push_regs = nfp_prog_current_offset(nfp_prog);
+ for (reg = BPF_REG_6; reg <= BPF_REG_9; reg++) {
+ u8 adj = (reg - BPF_REG_0) * 2;
+ u8 idx = (reg - BPF_REG_6) * 2;
+
+ /* The first slot in the stack frame is used to push the return
+ * address in bpf_to_bpf_call(), start just after.
+ */
+ wrp_mov(nfp_prog, reg_lm(0, 1 + idx), reg_b(adj));
+
+ if (reg == BPF_REG_8)
+ /* Prepare to jump back, last 3 insns use defer slots */
+ emit_rtn(nfp_prog, imm_b(nfp_prog), 3);
+
+ wrp_mov(nfp_prog, reg_lm(0, 1 + idx + 1), reg_b(adj + 1));
+ }
+}
+
+static void nfp_pop_callee_registers(struct nfp_prog *nfp_prog)
+{
+ u8 reg;
+
+ /* Subroutine: Restore all callee saved registers (R6 ~ R9).
+ * ret_reg() holds the return address.
+ */
+ nfp_prog->tgt_call_pop_regs = nfp_prog_current_offset(nfp_prog);
+ for (reg = BPF_REG_6; reg <= BPF_REG_9; reg++) {
+ u8 adj = (reg - BPF_REG_0) * 2;
+ u8 idx = (reg - BPF_REG_6) * 2;
+
+ /* The first slot in the stack frame holds the return address,
+ * start popping just after that.
+ */
+ wrp_mov(nfp_prog, reg_both(adj), reg_lm(0, 1 + idx));
+
+ if (reg == BPF_REG_8)
+ /* Prepare to jump back, last 3 insns use defer slots */
+ emit_rtn(nfp_prog, ret_reg(nfp_prog), 3);
+
+ wrp_mov(nfp_prog, reg_both(adj + 1), reg_lm(0, 1 + idx + 1));
+ }
+}
+
static void nfp_outro(struct nfp_prog *nfp_prog)
{
switch (nfp_prog->type) {
@@ -3360,13 +3619,23 @@ static void nfp_outro(struct nfp_prog *nfp_prog)
default:
WARN_ON(1);
}
+
+ if (!nfp_prog_needs_callee_reg_save(nfp_prog))
+ return;
+
+ nfp_push_callee_registers(nfp_prog);
+ nfp_pop_callee_registers(nfp_prog);
}
static int nfp_translate(struct nfp_prog *nfp_prog)
{
struct nfp_insn_meta *meta;
+ unsigned int depth;
int err;
+ depth = nfp_prog->subprog[0].stack_depth;
+ nfp_prog->stack_frame_depth = round_up(depth, 4);
+
nfp_intro(nfp_prog);
if (nfp_prog->error)
return nfp_prog->error;
@@ -3376,6 +3645,12 @@ static int nfp_translate(struct nfp_prog *nfp_prog)
meta->off = nfp_prog_current_offset(nfp_prog);
+ if (nfp_is_subprog_start(meta)) {
+ nfp_start_subprog(nfp_prog, meta);
+ if (nfp_prog->error)
+ return nfp_prog->error;
+ }
+
if (meta->skip) {
nfp_prog->n_translated++;
continue;
@@ -4018,20 +4293,35 @@ void nfp_bpf_jit_prepare(struct nfp_prog *nfp_prog, unsigned int cnt)
/* Another pass to record jump information. */
list_for_each_entry(meta, &nfp_prog->insns, l) {
+ struct nfp_insn_meta *dst_meta;
u64 code = meta->insn.code;
+ unsigned int dst_idx;
+ bool pseudo_call;
+
+ if (BPF_CLASS(code) != BPF_JMP)
+ continue;
+ if (BPF_OP(code) == BPF_EXIT)
+ continue;
+ if (is_mbpf_helper_call(meta))
+ continue;
- if (BPF_CLASS(code) == BPF_JMP && BPF_OP(code) != BPF_EXIT &&
- BPF_OP(code) != BPF_CALL) {
- struct nfp_insn_meta *dst_meta;
- unsigned short dst_indx;
+ /* If opcode is BPF_CALL at this point, this can only be a
+ * BPF-to-BPF call (a.k.a pseudo call).
+ */
+ pseudo_call = BPF_OP(code) == BPF_CALL;
- dst_indx = meta->n + 1 + meta->insn.off;
- dst_meta = nfp_bpf_goto_meta(nfp_prog, meta, dst_indx,
- cnt);
+ if (pseudo_call)
+ dst_idx = meta->n + 1 + meta->insn.imm;
+ else
+ dst_idx = meta->n + 1 + meta->insn.off;
- meta->jmp_dst = dst_meta;
- dst_meta->flags |= FLAG_INSN_IS_JUMP_DST;
- }
+ dst_meta = nfp_bpf_goto_meta(nfp_prog, meta, dst_idx, cnt);
+
+ if (pseudo_call)
+ dst_meta->flags |= FLAG_INSN_IS_SUBPROG_START;
+
+ dst_meta->flags |= FLAG_INSN_IS_JUMP_DST;
+ meta->jmp_dst = dst_meta;
}
}
@@ -4054,6 +4344,7 @@ void *nfp_bpf_relo_for_vnic(struct nfp_prog *nfp_prog, struct nfp_bpf_vnic *bv)
for (i = 0; i < nfp_prog->prog_len; i++) {
enum nfp_relo_type special;
u32 val;
+ u16 off;
special = FIELD_GET(OP_RELO_TYPE, prog[i]);
switch (special) {
@@ -4070,6 +4361,24 @@ void *nfp_bpf_relo_for_vnic(struct nfp_prog *nfp_prog, struct nfp_bpf_vnic *bv)
br_set_offset(&prog[i],
nfp_prog->tgt_abort + bv->start_off);
break;
+ case RELO_BR_GO_CALL_PUSH_REGS:
+ if (!nfp_prog->tgt_call_push_regs) {
+ pr_err("BUG: failed to detect subprogram registers needs\n");
+ err = -EINVAL;
+ goto err_free_prog;
+ }
+ off = nfp_prog->tgt_call_push_regs + bv->start_off;
+ br_set_offset(&prog[i], off);
+ break;
+ case RELO_BR_GO_CALL_POP_REGS:
+ if (!nfp_prog->tgt_call_pop_regs) {
+ pr_err("BUG: failed to detect subprogram registers needs\n");
+ err = -EINVAL;
+ goto err_free_prog;
+ }
+ off = nfp_prog->tgt_call_pop_regs + bv->start_off;
+ br_set_offset(&prog[i], off);
+ break;
case RELO_BR_NEXT_PKT:
br_set_offset(&prog[i], bv->tgt_done);
break;
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.c b/drivers/net/ethernet/netronome/nfp/bpf/main.c
index 970af07f4656..6243af0ab025 100644
--- a/drivers/net/ethernet/netronome/nfp/bpf/main.c
+++ b/drivers/net/ethernet/netronome/nfp/bpf/main.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2017-2018 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2017-2018 Netronome Systems, Inc. */
#include <net/pkt_cls.h>
@@ -54,11 +24,14 @@ const struct rhashtable_params nfp_bpf_maps_neutral_params = {
static bool nfp_net_ebpf_capable(struct nfp_net *nn)
{
#ifdef __LITTLE_ENDIAN
- if (nn->cap & NFP_NET_CFG_CTRL_BPF &&
- nn_readb(nn, NFP_NET_CFG_BPF_ABI) == NFP_NET_BPF_ABI)
- return true;
-#endif
+ struct nfp_app_bpf *bpf = nn->app->priv;
+
+ return nn->cap & NFP_NET_CFG_CTRL_BPF &&
+ bpf->abi_version &&
+ nn_readb(nn, NFP_NET_CFG_BPF_ABI) == bpf->abi_version;
+#else
return false;
+#endif
}
static int
@@ -342,6 +315,26 @@ nfp_bpf_parse_cap_adjust_tail(struct nfp_app_bpf *bpf, void __iomem *value,
return 0;
}
+static int
+nfp_bpf_parse_cap_abi_version(struct nfp_app_bpf *bpf, void __iomem *value,
+ u32 length)
+{
+ if (length < 4) {
+ nfp_err(bpf->app->cpp, "truncated ABI version TLV: %d\n",
+ length);
+ return -EINVAL;
+ }
+
+ bpf->abi_version = readl(value);
+ if (bpf->abi_version < 2 || bpf->abi_version > 3) {
+ nfp_warn(bpf->app->cpp, "unsupported BPF ABI version: %d\n",
+ bpf->abi_version);
+ bpf->abi_version = 0;
+ }
+
+ return 0;
+}
+
static int nfp_bpf_parse_capabilities(struct nfp_app *app)
{
struct nfp_cpp *cpp = app->pf->cpp;
@@ -393,6 +386,11 @@ static int nfp_bpf_parse_capabilities(struct nfp_app *app)
length))
goto err_release_free;
break;
+ case NFP_BPF_CAP_TYPE_ABI_VERSION:
+ if (nfp_bpf_parse_cap_abi_version(app->priv, value,
+ length))
+ goto err_release_free;
+ break;
default:
nfp_dbg(cpp, "unknown BPF capability: %d\n", type);
break;
@@ -414,6 +412,11 @@ err_release_free:
return -EINVAL;
}
+static void nfp_bpf_init_capabilities(struct nfp_app_bpf *bpf)
+{
+ bpf->abi_version = 2; /* Original BPF ABI version */
+}
+
static int nfp_bpf_ndo_init(struct nfp_app *app, struct net_device *netdev)
{
struct nfp_app_bpf *bpf = app->priv;
@@ -447,10 +450,21 @@ static int nfp_bpf_init(struct nfp_app *app)
if (err)
goto err_free_bpf;
+ nfp_bpf_init_capabilities(bpf);
+
err = nfp_bpf_parse_capabilities(app);
if (err)
goto err_free_neutral_maps;
+ if (bpf->abi_version < 3) {
+ bpf->cmsg_key_sz = CMSG_MAP_KEY_LW * 4;
+ bpf->cmsg_val_sz = CMSG_MAP_VALUE_LW * 4;
+ } else {
+ bpf->cmsg_key_sz = bpf->maps.max_key_sz;
+ bpf->cmsg_val_sz = bpf->maps.max_val_sz;
+ app->ctrl_mtu = nfp_bpf_ctrl_cmsg_mtu(bpf);
+ }
+
bpf->bpf_dev = bpf_offload_dev_create();
err = PTR_ERR_OR_ZERO(bpf->bpf_dev);
if (err)
@@ -465,11 +479,6 @@ err_free_bpf:
return err;
}
-static void nfp_check_rhashtable_empty(void *ptr, void *arg)
-{
- WARN_ON_ONCE(1);
-}
-
static void nfp_bpf_clean(struct nfp_app *app)
{
struct nfp_app_bpf *bpf = app->priv;
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.h b/drivers/net/ethernet/netronome/nfp/bpf/main.h
index dbd00982fd2b..7f591d71ab28 100644
--- a/drivers/net/ethernet/netronome/nfp/bpf/main.h
+++ b/drivers/net/ethernet/netronome/nfp/bpf/main.h
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2016-2018 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/* Copyright (C) 2016-2018 Netronome Systems, Inc. */
#ifndef __NFP_BPF_H__
#define __NFP_BPF_H__ 1
@@ -61,6 +31,8 @@ enum nfp_relo_type {
/* internal jumps to parts of the outro */
RELO_BR_GO_OUT,
RELO_BR_GO_ABORT,
+ RELO_BR_GO_CALL_PUSH_REGS,
+ RELO_BR_GO_CALL_POP_REGS,
/* external jumps to fixed addresses */
RELO_BR_NEXT_PKT,
RELO_BR_HELPER,
@@ -104,6 +76,7 @@ enum pkt_vec {
#define imma_a(np) reg_a(STATIC_REG_IMMA)
#define imma_b(np) reg_b(STATIC_REG_IMMA)
#define imm_both(np) reg_both(STATIC_REG_IMM)
+#define ret_reg(np) imm_a(np)
#define NFP_BPF_ABI_FLAGS reg_imm(0)
#define NFP_BPF_ABI_FLAG_MARK 1
@@ -121,12 +94,17 @@ enum pkt_vec {
* @cmsg_replies: received cmsg replies waiting to be consumed
* @cmsg_wq: work queue for waiting for cmsg replies
*
+ * @cmsg_key_sz: size of key in cmsg element array
+ * @cmsg_val_sz: size of value in cmsg element array
+ *
* @map_list: list of offloaded maps
* @maps_in_use: number of currently offloaded maps
* @map_elems_in_use: number of elements allocated to offloaded maps
*
* @maps_neutral: hash table of offload-neutral maps (on pointer)
*
+ * @abi_version: global BPF ABI version
+ *
* @adjust_head: adjust head capability
* @adjust_head.flags: extra flags for adjust head
* @adjust_head.off_min: minimal packet offset within buffer required
@@ -164,12 +142,17 @@ struct nfp_app_bpf {
struct sk_buff_head cmsg_replies;
struct wait_queue_head cmsg_wq;
+ unsigned int cmsg_key_sz;
+ unsigned int cmsg_val_sz;
+
struct list_head map_list;
unsigned int maps_in_use;
unsigned int map_elems_in_use;
struct rhashtable maps_neutral;
+ u32 abi_version;
+
struct nfp_bpf_cap_adjust_head {
u32 flags;
int off_min;
@@ -206,6 +189,11 @@ enum nfp_bpf_map_use {
NFP_MAP_USE_ATOMIC_CNT,
};
+struct nfp_bpf_map_word {
+ unsigned char type :4;
+ unsigned char non_zero_update :1;
+};
+
/**
* struct nfp_bpf_map - private per-map data attached to BPF maps for offload
* @offmap: pointer to the offloaded BPF map
@@ -219,7 +207,7 @@ struct nfp_bpf_map {
struct nfp_app_bpf *bpf;
u32 tid;
struct list_head l;
- enum nfp_bpf_map_use use_map[];
+ struct nfp_bpf_map_word use_map[];
};
struct nfp_bpf_neutral_map {
@@ -252,7 +240,9 @@ struct nfp_bpf_reg_state {
bool var_off;
};
-#define FLAG_INSN_IS_JUMP_DST BIT(0)
+#define FLAG_INSN_IS_JUMP_DST BIT(0)
+#define FLAG_INSN_IS_SUBPROG_START BIT(1)
+#define FLAG_INSN_PTR_CALLER_STACK_FRAME BIT(2)
/**
* struct nfp_insn_meta - BPF instruction wrapper
@@ -269,6 +259,7 @@ struct nfp_bpf_reg_state {
* @xadd_maybe_16bit: 16bit immediate is possible
* @jmp_dst: destination info for jump instructions
* @jump_neg_op: jump instruction has inverted immediate, use ADD instead of SUB
+ * @num_insns_after_br: number of insns following a branch jump, used for fixup
* @func_id: function id for call instructions
* @arg1: arg1 for call instructions
* @arg2: arg2 for call instructions
@@ -279,6 +270,7 @@ struct nfp_bpf_reg_state {
* @off: index of first generated machine instruction (in nfp_prog.prog)
* @n: eBPF instruction number
* @flags: eBPF instruction extra optimization flags
+ * @subprog_idx: index of subprogram to which the instruction belongs
* @skip: skip this instruction (optimized out)
* @double_cb: callback for second part of the instruction
* @l: link on nfp_prog->insns list
@@ -304,6 +296,7 @@ struct nfp_insn_meta {
struct {
struct nfp_insn_meta *jmp_dst;
bool jump_neg_op;
+ u32 num_insns_after_br; /* only for BPF-to-BPF calls */
};
/* function calls */
struct {
@@ -325,6 +318,7 @@ struct nfp_insn_meta {
unsigned int off;
unsigned short n;
unsigned short flags;
+ unsigned short subprog_idx;
bool skip;
instr_cb_t double_cb;
@@ -413,23 +407,56 @@ static inline bool is_mbpf_div(const struct nfp_insn_meta *meta)
return is_mbpf_alu(meta) && mbpf_op(meta) == BPF_DIV;
}
+static inline bool is_mbpf_helper_call(const struct nfp_insn_meta *meta)
+{
+ struct bpf_insn insn = meta->insn;
+
+ return insn.code == (BPF_JMP | BPF_CALL) &&
+ insn.src_reg != BPF_PSEUDO_CALL;
+}
+
+static inline bool is_mbpf_pseudo_call(const struct nfp_insn_meta *meta)
+{
+ struct bpf_insn insn = meta->insn;
+
+ return insn.code == (BPF_JMP | BPF_CALL) &&
+ insn.src_reg == BPF_PSEUDO_CALL;
+}
+
+#define STACK_FRAME_ALIGN 64
+
+/**
+ * struct nfp_bpf_subprog_info - nfp BPF sub-program (a.k.a. function) info
+ * @stack_depth: maximum stack depth used by this sub-program
+ * @needs_reg_push: whether sub-program uses callee-saved registers
+ */
+struct nfp_bpf_subprog_info {
+ u16 stack_depth;
+ u8 needs_reg_push : 1;
+};
+
/**
* struct nfp_prog - nfp BPF program
* @bpf: backpointer to the bpf app priv structure
* @prog: machine code
* @prog_len: number of valid instructions in @prog array
* @__prog_alloc_len: alloc size of @prog array
+ * @stack_size: total amount of stack used
* @verifier_meta: temporary storage for verifier's insn meta
* @type: BPF program type
* @last_bpf_off: address of the last instruction translated from BPF
* @tgt_out: jump target for normal exit
* @tgt_abort: jump target for abort (e.g. access outside of packet buffer)
+ * @tgt_call_push_regs: jump target for subroutine for saving R6~R9 to stack
+ * @tgt_call_pop_regs: jump target for subroutine used for restoring R6~R9
* @n_translated: number of successfully translated instructions (for errors)
* @error: error code if something went wrong
- * @stack_depth: max stack depth from the verifier
+ * @stack_frame_depth: max stack depth for current frame
* @adjust_head_location: if program has single adjust head call - the insn no.
* @map_records_cnt: the number of map pointers recorded for this prog
+ * @subprog_cnt: number of sub-programs, including main function
* @map_records: the map record pointers from bpf->maps_neutral
+ * @subprog: pointer to an array of objects holding info about sub-programs
* @insns: list of BPF instruction wrappers (struct nfp_insn_meta)
*/
struct nfp_prog {
@@ -439,6 +466,8 @@ struct nfp_prog {
unsigned int prog_len;
unsigned int __prog_alloc_len;
+ unsigned int stack_size;
+
struct nfp_insn_meta *verifier_meta;
enum bpf_prog_type type;
@@ -446,15 +475,19 @@ struct nfp_prog {
unsigned int last_bpf_off;
unsigned int tgt_out;
unsigned int tgt_abort;
+ unsigned int tgt_call_push_regs;
+ unsigned int tgt_call_pop_regs;
unsigned int n_translated;
int error;
- unsigned int stack_depth;
+ unsigned int stack_frame_depth;
unsigned int adjust_head_location;
unsigned int map_records_cnt;
+ unsigned int subprog_cnt;
struct nfp_bpf_neutral_map **map_records;
+ struct nfp_bpf_subprog_info *subprog;
struct list_head insns;
};
@@ -471,6 +504,7 @@ struct nfp_bpf_vnic {
unsigned int tgt_done;
};
+bool nfp_is_subprog_start(struct nfp_insn_meta *meta);
void nfp_bpf_jit_prepare(struct nfp_prog *nfp_prog, unsigned int cnt);
int nfp_bpf_jit(struct nfp_prog *prog);
bool nfp_bpf_supported_opcode(u8 code);
@@ -492,6 +526,7 @@ nfp_bpf_goto_meta(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
void *nfp_bpf_relo_for_vnic(struct nfp_prog *nfp_prog, struct nfp_bpf_vnic *bv);
+unsigned int nfp_bpf_ctrl_cmsg_mtu(struct nfp_app_bpf *bpf);
long long int
nfp_bpf_ctrl_alloc_map(struct nfp_app_bpf *bpf, struct bpf_map *map);
void
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/offload.c b/drivers/net/ethernet/netronome/nfp/bpf/offload.c
index 1ccd6371a15b..ba8ceedcf6a2 100644
--- a/drivers/net/ethernet/netronome/nfp/bpf/offload.c
+++ b/drivers/net/ethernet/netronome/nfp/bpf/offload.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2016-2018 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2016-2018 Netronome Systems, Inc. */
/*
* nfp_net_offload.c
@@ -208,6 +178,8 @@ static void nfp_prog_free(struct nfp_prog *nfp_prog)
{
struct nfp_insn_meta *meta, *tmp;
+ kfree(nfp_prog->subprog);
+
list_for_each_entry_safe(meta, tmp, &nfp_prog->insns, l) {
list_del(&meta->l);
kfree(meta);
@@ -250,18 +222,9 @@ err_free:
static int nfp_bpf_translate(struct nfp_net *nn, struct bpf_prog *prog)
{
struct nfp_prog *nfp_prog = prog->aux->offload->dev_priv;
- unsigned int stack_size;
unsigned int max_instr;
int err;
- stack_size = nn_readb(nn, NFP_NET_CFG_BPF_STACK_SZ) * 64;
- if (prog->aux->stack_depth > stack_size) {
- nn_info(nn, "stack too large: program %dB > FW stack %dB\n",
- prog->aux->stack_depth, stack_size);
- return -EOPNOTSUPP;
- }
- nfp_prog->stack_depth = round_up(prog->aux->stack_depth, 4);
-
max_instr = nn_readw(nn, NFP_NET_CFG_BPF_MAX_LEN);
nfp_prog->__prog_alloc_len = max_instr * sizeof(u64);
@@ -299,10 +262,25 @@ static void nfp_map_bpf_byte_swap(struct nfp_bpf_map *nfp_map, void *value)
unsigned int i;
for (i = 0; i < DIV_ROUND_UP(nfp_map->offmap->map.value_size, 4); i++)
- if (nfp_map->use_map[i] == NFP_MAP_USE_ATOMIC_CNT)
+ if (nfp_map->use_map[i].type == NFP_MAP_USE_ATOMIC_CNT)
word[i] = (__force u32)cpu_to_be32(word[i]);
}
+/* Mark value as unsafely initialized in case it becomes atomic later
+ * and we didn't byte swap something non-byte swap neutral.
+ */
+static void
+nfp_map_bpf_byte_swap_record(struct nfp_bpf_map *nfp_map, void *value)
+{
+ u32 *word = value;
+ unsigned int i;
+
+ for (i = 0; i < DIV_ROUND_UP(nfp_map->offmap->map.value_size, 4); i++)
+ if (nfp_map->use_map[i].type == NFP_MAP_UNUSED &&
+ word[i] != (__force u32)cpu_to_be32(word[i]))
+ nfp_map->use_map[i].non_zero_update = 1;
+}
+
static int
nfp_bpf_map_lookup_entry(struct bpf_offloaded_map *offmap,
void *key, void *value)
@@ -322,6 +300,7 @@ nfp_bpf_map_update_entry(struct bpf_offloaded_map *offmap,
void *key, void *value, u64 flags)
{
nfp_map_bpf_byte_swap(offmap->dev_priv, value);
+ nfp_map_bpf_byte_swap_record(offmap->dev_priv, value);
return nfp_bpf_ctrl_update_entry(offmap, key, value, flags);
}
@@ -510,7 +489,7 @@ nfp_net_bpf_load(struct nfp_net *nn, struct bpf_prog *prog,
struct netlink_ext_ack *extack)
{
struct nfp_prog *nfp_prog = prog->aux->offload->dev_priv;
- unsigned int max_mtu;
+ unsigned int max_mtu, max_stack, max_prog_len;
dma_addr_t dma_addr;
void *img;
int err;
@@ -521,6 +500,18 @@ nfp_net_bpf_load(struct nfp_net *nn, struct bpf_prog *prog,
return -EOPNOTSUPP;
}
+ max_stack = nn_readb(nn, NFP_NET_CFG_BPF_STACK_SZ) * 64;
+ if (nfp_prog->stack_size > max_stack) {
+ NL_SET_ERR_MSG_MOD(extack, "stack too large");
+ return -EOPNOTSUPP;
+ }
+
+ max_prog_len = nn_readw(nn, NFP_NET_CFG_BPF_MAX_LEN);
+ if (nfp_prog->prog_len > max_prog_len) {
+ NL_SET_ERR_MSG_MOD(extack, "program too long");
+ return -EOPNOTSUPP;
+ }
+
img = nfp_bpf_relo_for_vnic(nfp_prog, nn->app_priv);
if (IS_ERR(img))
return PTR_ERR(img);
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/verifier.c b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c
index a6e9248669e1..99f977bfd8cc 100644
--- a/drivers/net/ethernet/netronome/nfp/bpf/verifier.c
+++ b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c
@@ -1,43 +1,15 @@
-/*
- * Copyright (C) 2016-2018 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2016-2018 Netronome Systems, Inc. */
#include <linux/bpf.h>
#include <linux/bpf_verifier.h>
#include <linux/kernel.h>
+#include <linux/netdevice.h>
#include <linux/pkt_cls.h>
#include "../nfp_app.h"
#include "../nfp_main.h"
+#include "../nfp_net.h"
#include "fw.h"
#include "main.h"
@@ -108,6 +80,46 @@ exit_set_location:
nfp_prog->adjust_head_location = location;
}
+static bool nfp_bpf_map_update_value_ok(struct bpf_verifier_env *env)
+{
+ const struct bpf_reg_state *reg1 = cur_regs(env) + BPF_REG_1;
+ const struct bpf_reg_state *reg3 = cur_regs(env) + BPF_REG_3;
+ struct bpf_offloaded_map *offmap;
+ struct bpf_func_state *state;
+ struct nfp_bpf_map *nfp_map;
+ int off, i;
+
+ state = env->cur_state->frame[reg3->frameno];
+
+ /* We need to record each time update happens with non-zero words,
+ * in case such word is used in atomic operations.
+ * Implicitly depend on nfp_bpf_stack_arg_ok(reg3) being run before.
+ */
+
+ offmap = map_to_offmap(reg1->map_ptr);
+ nfp_map = offmap->dev_priv;
+ off = reg3->off + reg3->var_off.value;
+
+ for (i = 0; i < offmap->map.value_size; i++) {
+ struct bpf_stack_state *stack_entry;
+ unsigned int soff;
+
+ soff = -(off + i) - 1;
+ stack_entry = &state->stack[soff / BPF_REG_SIZE];
+ if (stack_entry->slot_type[soff % BPF_REG_SIZE] == STACK_ZERO)
+ continue;
+
+ if (nfp_map->use_map[i / 4].type == NFP_MAP_USE_ATOMIC_CNT) {
+ pr_vlog(env, "value at offset %d/%d may be non-zero, bpf_map_update_elem() is required to initialize atomic counters to zero to avoid offload endian issues\n",
+ i, soff);
+ return false;
+ }
+ nfp_map->use_map[i / 4].non_zero_update = 1;
+ }
+
+ return true;
+}
+
static int
nfp_bpf_stack_arg_ok(const char *fname, struct bpf_verifier_env *env,
const struct bpf_reg_state *reg,
@@ -155,8 +167,9 @@ nfp_bpf_map_call_ok(const char *fname, struct bpf_verifier_env *env,
}
static int
-nfp_bpf_check_call(struct nfp_prog *nfp_prog, struct bpf_verifier_env *env,
- struct nfp_insn_meta *meta)
+nfp_bpf_check_helper_call(struct nfp_prog *nfp_prog,
+ struct bpf_verifier_env *env,
+ struct nfp_insn_meta *meta)
{
const struct bpf_reg_state *reg1 = cur_regs(env) + BPF_REG_1;
const struct bpf_reg_state *reg2 = cur_regs(env) + BPF_REG_2;
@@ -198,7 +211,8 @@ nfp_bpf_check_call(struct nfp_prog *nfp_prog, struct bpf_verifier_env *env,
bpf->helpers.map_update, reg1) ||
!nfp_bpf_stack_arg_ok("map_update", env, reg2,
meta->func_id ? &meta->arg2 : NULL) ||
- !nfp_bpf_stack_arg_ok("map_update", env, reg3, NULL))
+ !nfp_bpf_stack_arg_ok("map_update", env, reg3, NULL) ||
+ !nfp_bpf_map_update_value_ok(env))
return -EOPNOTSUPP;
break;
@@ -333,6 +347,9 @@ nfp_bpf_check_stack_access(struct nfp_prog *nfp_prog,
{
s32 old_off, new_off;
+ if (reg->frameno != env->cur_state->curframe)
+ meta->flags |= FLAG_INSN_PTR_CALLER_STACK_FRAME;
+
if (!tnum_is_const(reg->var_off)) {
pr_vlog(env, "variable ptr stack access\n");
return -EINVAL;
@@ -376,15 +393,22 @@ nfp_bpf_map_mark_used_one(struct bpf_verifier_env *env,
struct nfp_bpf_map *nfp_map,
unsigned int off, enum nfp_bpf_map_use use)
{
- if (nfp_map->use_map[off / 4] != NFP_MAP_UNUSED &&
- nfp_map->use_map[off / 4] != use) {
+ if (nfp_map->use_map[off / 4].type != NFP_MAP_UNUSED &&
+ nfp_map->use_map[off / 4].type != use) {
pr_vlog(env, "map value use type conflict %s vs %s off: %u\n",
- nfp_bpf_map_use_name(nfp_map->use_map[off / 4]),
+ nfp_bpf_map_use_name(nfp_map->use_map[off / 4].type),
nfp_bpf_map_use_name(use), off);
return -EOPNOTSUPP;
}
- nfp_map->use_map[off / 4] = use;
+ if (nfp_map->use_map[off / 4].non_zero_update &&
+ use == NFP_MAP_USE_ATOMIC_CNT) {
+ pr_vlog(env, "atomic counter in map value may already be initialized to non-zero value off: %u\n",
+ off);
+ return -EOPNOTSUPP;
+ }
+
+ nfp_map->use_map[off / 4].type = use;
return 0;
}
@@ -620,8 +644,8 @@ nfp_verify_insn(struct bpf_verifier_env *env, int insn_idx, int prev_insn_idx)
return -EINVAL;
}
- if (meta->insn.code == (BPF_JMP | BPF_CALL))
- return nfp_bpf_check_call(nfp_prog, env, meta);
+ if (is_mbpf_helper_call(meta))
+ return nfp_bpf_check_helper_call(nfp_prog, env, meta);
if (meta->insn.code == (BPF_JMP | BPF_EXIT))
return nfp_bpf_check_exit(nfp_prog, env);
@@ -640,6 +664,132 @@ nfp_verify_insn(struct bpf_verifier_env *env, int insn_idx, int prev_insn_idx)
return 0;
}
+static int
+nfp_assign_subprog_idx_and_regs(struct bpf_verifier_env *env,
+ struct nfp_prog *nfp_prog)
+{
+ struct nfp_insn_meta *meta;
+ int index = 0;
+
+ list_for_each_entry(meta, &nfp_prog->insns, l) {
+ if (nfp_is_subprog_start(meta))
+ index++;
+ meta->subprog_idx = index;
+
+ if (meta->insn.dst_reg >= BPF_REG_6 &&
+ meta->insn.dst_reg <= BPF_REG_9)
+ nfp_prog->subprog[index].needs_reg_push = 1;
+ }
+
+ if (index + 1 != nfp_prog->subprog_cnt) {
+ pr_vlog(env, "BUG: number of processed BPF functions is not consistent (processed %d, expected %d)\n",
+ index + 1, nfp_prog->subprog_cnt);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static unsigned int
+nfp_bpf_get_stack_usage(struct nfp_prog *nfp_prog, unsigned int cnt)
+{
+ struct nfp_insn_meta *meta = nfp_prog_first_meta(nfp_prog);
+ unsigned int max_depth = 0, depth = 0, frame = 0;
+ struct nfp_insn_meta *ret_insn[MAX_CALL_FRAMES];
+ unsigned short frame_depths[MAX_CALL_FRAMES];
+ unsigned short ret_prog[MAX_CALL_FRAMES];
+ unsigned short idx = meta->subprog_idx;
+
+ /* Inspired from check_max_stack_depth() from kernel verifier.
+ * Starting from main subprogram, walk all instructions and recursively
+ * walk all callees that given subprogram can call. Since recursion is
+ * prevented by the kernel verifier, this algorithm only needs a local
+ * stack of MAX_CALL_FRAMES to remember callsites.
+ */
+process_subprog:
+ frame_depths[frame] = nfp_prog->subprog[idx].stack_depth;
+ frame_depths[frame] = round_up(frame_depths[frame], STACK_FRAME_ALIGN);
+ depth += frame_depths[frame];
+ max_depth = max(max_depth, depth);
+
+continue_subprog:
+ for (; meta != nfp_prog_last_meta(nfp_prog) && meta->subprog_idx == idx;
+ meta = nfp_meta_next(meta)) {
+ if (!is_mbpf_pseudo_call(meta))
+ continue;
+
+ /* We found a call to a subprogram. Remember instruction to
+ * return to and subprog id.
+ */
+ ret_insn[frame] = nfp_meta_next(meta);
+ ret_prog[frame] = idx;
+
+ /* Find the callee and start processing it. */
+ meta = nfp_bpf_goto_meta(nfp_prog, meta,
+ meta->n + 1 + meta->insn.imm, cnt);
+ idx = meta->subprog_idx;
+ frame++;
+ goto process_subprog;
+ }
+ /* End of for() loop means the last instruction of the subprog was
+ * reached. If we popped all stack frames, return; otherwise, go on
+ * processing remaining instructions from the caller.
+ */
+ if (frame == 0)
+ return max_depth;
+
+ depth -= frame_depths[frame];
+ frame--;
+ meta = ret_insn[frame];
+ idx = ret_prog[frame];
+ goto continue_subprog;
+}
+
+static int nfp_bpf_finalize(struct bpf_verifier_env *env)
+{
+ struct bpf_subprog_info *info;
+ struct nfp_prog *nfp_prog;
+ unsigned int max_stack;
+ struct nfp_net *nn;
+ int i;
+
+ nfp_prog = env->prog->aux->offload->dev_priv;
+ nfp_prog->subprog_cnt = env->subprog_cnt;
+ nfp_prog->subprog = kcalloc(nfp_prog->subprog_cnt,
+ sizeof(nfp_prog->subprog[0]), GFP_KERNEL);
+ if (!nfp_prog->subprog)
+ return -ENOMEM;
+
+ nfp_assign_subprog_idx_and_regs(env, nfp_prog);
+
+ info = env->subprog_info;
+ for (i = 0; i < nfp_prog->subprog_cnt; i++) {
+ nfp_prog->subprog[i].stack_depth = info[i].stack_depth;
+
+ if (i == 0)
+ continue;
+
+ /* Account for size of return address. */
+ nfp_prog->subprog[i].stack_depth += REG_WIDTH;
+ /* Account for size of saved registers, if necessary. */
+ if (nfp_prog->subprog[i].needs_reg_push)
+ nfp_prog->subprog[i].stack_depth += BPF_REG_SIZE * 4;
+ }
+
+ nn = netdev_priv(env->prog->aux->offload->netdev);
+ max_stack = nn_readb(nn, NFP_NET_CFG_BPF_STACK_SZ) * 64;
+ nfp_prog->stack_size = nfp_bpf_get_stack_usage(nfp_prog,
+ env->prog->len);
+ if (nfp_prog->stack_size > max_stack) {
+ pr_vlog(env, "stack too large: program %dB > FW stack %dB\n",
+ nfp_prog->stack_size, max_stack);
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
const struct bpf_prog_offload_ops nfp_bpf_analyzer_ops = {
- .insn_hook = nfp_verify_insn,
+ .insn_hook = nfp_verify_insn,
+ .finalize = nfp_bpf_finalize,
};
diff --git a/drivers/net/ethernet/netronome/nfp/flower/action.c b/drivers/net/ethernet/netronome/nfp/flower/action.c
index 46ba0cf257c6..244dc261006e 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/action.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/action.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2017-2018 Netronome Systems, Inc. */
#include <linux/bitfield.h>
#include <net/geneve.h>
@@ -429,12 +399,14 @@ nfp_fl_set_ip4(const struct tc_action *action, int idx, u32 off,
switch (off) {
case offsetof(struct iphdr, daddr):
- set_ip_addr->ipv4_dst_mask = mask;
- set_ip_addr->ipv4_dst = exact;
+ set_ip_addr->ipv4_dst_mask |= mask;
+ set_ip_addr->ipv4_dst &= ~mask;
+ set_ip_addr->ipv4_dst |= exact & mask;
break;
case offsetof(struct iphdr, saddr):
- set_ip_addr->ipv4_src_mask = mask;
- set_ip_addr->ipv4_src = exact;
+ set_ip_addr->ipv4_src_mask |= mask;
+ set_ip_addr->ipv4_src &= ~mask;
+ set_ip_addr->ipv4_src |= exact & mask;
break;
default:
return -EOPNOTSUPP;
@@ -448,11 +420,12 @@ nfp_fl_set_ip4(const struct tc_action *action, int idx, u32 off,
}
static void
-nfp_fl_set_ip6_helper(int opcode_tag, int idx, __be32 exact, __be32 mask,
+nfp_fl_set_ip6_helper(int opcode_tag, u8 word, __be32 exact, __be32 mask,
struct nfp_fl_set_ipv6_addr *ip6)
{
- ip6->ipv6[idx % 4].mask = mask;
- ip6->ipv6[idx % 4].exact = exact;
+ ip6->ipv6[word].mask |= mask;
+ ip6->ipv6[word].exact &= ~mask;
+ ip6->ipv6[word].exact |= exact & mask;
ip6->reserved = cpu_to_be16(0);
ip6->head.jump_id = opcode_tag;
@@ -465,6 +438,7 @@ nfp_fl_set_ip6(const struct tc_action *action, int idx, u32 off,
struct nfp_fl_set_ipv6_addr *ip_src)
{
__be32 exact, mask;
+ u8 word;
/* We are expecting tcf_pedit to return a big endian value */
mask = (__force __be32)~tcf_pedit_mask(action, idx);
@@ -473,17 +447,20 @@ nfp_fl_set_ip6(const struct tc_action *action, int idx, u32 off,
if (exact & ~mask)
return -EOPNOTSUPP;
- if (off < offsetof(struct ipv6hdr, saddr))
+ if (off < offsetof(struct ipv6hdr, saddr)) {
return -EOPNOTSUPP;
- else if (off < offsetof(struct ipv6hdr, daddr))
- nfp_fl_set_ip6_helper(NFP_FL_ACTION_OPCODE_SET_IPV6_SRC, idx,
+ } else if (off < offsetof(struct ipv6hdr, daddr)) {
+ word = (off - offsetof(struct ipv6hdr, saddr)) / sizeof(exact);
+ nfp_fl_set_ip6_helper(NFP_FL_ACTION_OPCODE_SET_IPV6_SRC, word,
exact, mask, ip_src);
- else if (off < offsetof(struct ipv6hdr, daddr) +
- sizeof(struct in6_addr))
- nfp_fl_set_ip6_helper(NFP_FL_ACTION_OPCODE_SET_IPV6_DST, idx,
+ } else if (off < offsetof(struct ipv6hdr, daddr) +
+ sizeof(struct in6_addr)) {
+ word = (off - offsetof(struct ipv6hdr, daddr)) / sizeof(exact);
+ nfp_fl_set_ip6_helper(NFP_FL_ACTION_OPCODE_SET_IPV6_DST, word,
exact, mask, ip_dst);
- else
+ } else {
return -EOPNOTSUPP;
+ }
return 0;
}
@@ -541,7 +518,7 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow,
struct nfp_fl_set_eth set_eth;
enum pedit_header_type htype;
int idx, nkeys, err;
- size_t act_size;
+ size_t act_size = 0;
u32 offset, cmd;
u8 ip_proto = 0;
@@ -599,7 +576,9 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow,
act_size = sizeof(set_eth);
memcpy(nfp_action, &set_eth, act_size);
*a_len += act_size;
- } else if (set_ip_addr.head.len_lw) {
+ }
+ if (set_ip_addr.head.len_lw) {
+ nfp_action += act_size;
act_size = sizeof(set_ip_addr);
memcpy(nfp_action, &set_ip_addr, act_size);
*a_len += act_size;
@@ -607,10 +586,12 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow,
/* Hardware will automatically fix IPv4 and TCP/UDP checksum. */
*csum_updated |= TCA_CSUM_UPDATE_FLAG_IPV4HDR |
nfp_fl_csum_l4_to_flag(ip_proto);
- } else if (set_ip6_dst.head.len_lw && set_ip6_src.head.len_lw) {
+ }
+ if (set_ip6_dst.head.len_lw && set_ip6_src.head.len_lw) {
/* TC compiles set src and dst IPv6 address as a single action,
* the hardware requires this to be 2 separate actions.
*/
+ nfp_action += act_size;
act_size = sizeof(set_ip6_src);
memcpy(nfp_action, &set_ip6_src, act_size);
*a_len += act_size;
@@ -623,6 +604,7 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow,
/* Hardware will automatically fix TCP/UDP checksum. */
*csum_updated |= nfp_fl_csum_l4_to_flag(ip_proto);
} else if (set_ip6_dst.head.len_lw) {
+ nfp_action += act_size;
act_size = sizeof(set_ip6_dst);
memcpy(nfp_action, &set_ip6_dst, act_size);
*a_len += act_size;
@@ -630,13 +612,16 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow,
/* Hardware will automatically fix TCP/UDP checksum. */
*csum_updated |= nfp_fl_csum_l4_to_flag(ip_proto);
} else if (set_ip6_src.head.len_lw) {
+ nfp_action += act_size;
act_size = sizeof(set_ip6_src);
memcpy(nfp_action, &set_ip6_src, act_size);
*a_len += act_size;
/* Hardware will automatically fix TCP/UDP checksum. */
*csum_updated |= nfp_fl_csum_l4_to_flag(ip_proto);
- } else if (set_tport.head.len_lw) {
+ }
+ if (set_tport.head.len_lw) {
+ nfp_action += act_size;
act_size = sizeof(set_tport);
memcpy(nfp_action, &set_tport, act_size);
*a_len += act_size;
diff --git a/drivers/net/ethernet/netronome/nfp/flower/cmsg.c b/drivers/net/ethernet/netronome/nfp/flower/cmsg.c
index cb8565222621..4c5eaf36d5bb 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/cmsg.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/cmsg.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2015-2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2015-2018 Netronome Systems, Inc. */
#include <linux/bitfield.h>
#include <linux/netdevice.h>
diff --git a/drivers/net/ethernet/netronome/nfp/flower/cmsg.h b/drivers/net/ethernet/netronome/nfp/flower/cmsg.h
index 325954b829c8..29d673aa5277 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/cmsg.h
+++ b/drivers/net/ethernet/netronome/nfp/flower/cmsg.h
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/* Copyright (C) 2017-2018 Netronome Systems, Inc. */
#ifndef NFP_FLOWER_CMSG_H
#define NFP_FLOWER_CMSG_H
diff --git a/drivers/net/ethernet/netronome/nfp/flower/lag_conf.c b/drivers/net/ethernet/netronome/nfp/flower/lag_conf.c
index bf10598f66ae..81dcf5b318ba 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/lag_conf.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/lag_conf.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2018 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2018 Netronome Systems, Inc. */
#include "main.h"
diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.c b/drivers/net/ethernet/netronome/nfp/flower/main.c
index e57d23746585..3a54728d2ea6 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/main.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/main.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2017-2018 Netronome Systems, Inc. */
#include <linux/etherdevice.h>
#include <linux/lockdep.h>
@@ -518,8 +488,8 @@ err_clear_nn:
static int nfp_flower_init(struct nfp_app *app)
{
const struct nfp_pf *pf = app->pf;
+ u64 version, features, ctx_count;
struct nfp_flower_priv *app_priv;
- u64 version, features;
int err;
if (!pf->eth_tbl) {
@@ -543,6 +513,16 @@ static int nfp_flower_init(struct nfp_app *app)
return err;
}
+ ctx_count = nfp_rtsym_read_le(app->pf->rtbl, "CONFIG_FC_HOST_CTX_COUNT",
+ &err);
+ if (err) {
+ nfp_warn(app->cpp,
+ "FlowerNIC: unsupported host context count: %d\n",
+ err);
+ err = 0;
+ ctx_count = BIT(17);
+ }
+
/* We need to ensure hardware has enough flower capabilities. */
if (version != NFP_FLOWER_ALLOWED_VER) {
nfp_warn(app->cpp, "FlowerNIC: unsupported firmware version\n");
@@ -553,6 +533,7 @@ static int nfp_flower_init(struct nfp_app *app)
if (!app_priv)
return -ENOMEM;
+ app_priv->stats_ring_size = roundup_pow_of_two(ctx_count);
app->priv = app_priv;
app_priv->app = app;
skb_queue_head_init(&app_priv->cmsg_skbs_high);
@@ -563,7 +544,7 @@ static int nfp_flower_init(struct nfp_app *app)
init_waitqueue_head(&app_priv->mtu_conf.wait_q);
spin_lock_init(&app_priv->mtu_conf.lock);
- err = nfp_flower_metadata_init(app);
+ err = nfp_flower_metadata_init(app, ctx_count);
if (err)
goto err_free_app_priv;
diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.h b/drivers/net/ethernet/netronome/nfp/flower/main.h
index 81d941ab895c..90045bab95bf 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/main.h
+++ b/drivers/net/ethernet/netronome/nfp/flower/main.h
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/* Copyright (C) 2017-2018 Netronome Systems, Inc. */
#ifndef __NFP_FLOWER_H__
#define __NFP_FLOWER_H__ 1
@@ -38,6 +8,7 @@
#include <linux/circ_buf.h>
#include <linux/hashtable.h>
+#include <linux/rhashtable.h>
#include <linux/time64.h>
#include <linux/types.h>
#include <net/pkt_cls.h>
@@ -50,10 +21,8 @@ struct net_device;
struct nfp_app;
#define NFP_FL_STATS_CTX_DONT_CARE cpu_to_be32(0xffffffff)
-#define NFP_FL_STATS_ENTRY_RS BIT(20)
-#define NFP_FL_STATS_ELEM_RS 4
-#define NFP_FL_REPEATED_HASH_MAX BIT(17)
-#define NFP_FLOWER_HASH_BITS 19
+#define NFP_FL_STATS_ELEM_RS FIELD_SIZEOF(struct nfp_fl_stats_id, \
+ init_unalloc)
#define NFP_FLOWER_MASK_ENTRY_RS 256
#define NFP_FLOWER_MASK_ELEMENT_RS 1
#define NFP_FLOWER_MASK_HASH_BITS 10
@@ -138,7 +107,10 @@ struct nfp_fl_lag {
* @stats_ids: List of free stats ids
* @mask_ids: List of free mask ids
* @mask_table: Hash table used to store masks
+ * @stats_ring_size: Maximum number of allowed stats ids
* @flow_table: Hash table used to store flower rules
+ * @stats: Stored stats updates for flower rules
+ * @stats_lock: Lock for flower rule stats updates
* @cmsg_work: Workqueue for control messages processing
* @cmsg_skbs_high: List of higher priority skbs for control message
* processing
@@ -171,7 +143,10 @@ struct nfp_flower_priv {
struct nfp_fl_stats_id stats_ids;
struct nfp_fl_mask_id mask_ids;
DECLARE_HASHTABLE(mask_table, NFP_FLOWER_MASK_HASH_BITS);
- DECLARE_HASHTABLE(flow_table, NFP_FLOWER_HASH_BITS);
+ u32 stats_ring_size;
+ struct rhashtable flow_table;
+ struct nfp_fl_stats *stats;
+ spinlock_t stats_lock; /* lock stats */
struct work_struct cmsg_work;
struct sk_buff_head cmsg_skbs_high;
struct sk_buff_head cmsg_skbs_low;
@@ -227,10 +202,8 @@ struct nfp_fl_stats {
struct nfp_fl_payload {
struct nfp_fl_rule_metadata meta;
unsigned long tc_flower_cookie;
- struct hlist_node link;
+ struct rhash_head fl_node;
struct rcu_head rcu;
- spinlock_t lock; /* lock stats */
- struct nfp_fl_stats stats;
__be32 nfp_tun_ipv4_addr;
struct net_device *ingress_dev;
char *unmasked_data;
@@ -239,6 +212,8 @@ struct nfp_fl_payload {
bool ingress_offload;
};
+extern const struct rhashtable_params nfp_flower_table_params;
+
struct nfp_fl_stats_frame {
__be32 stats_con_id;
__be32 pkt_count;
@@ -246,7 +221,7 @@ struct nfp_fl_stats_frame {
__be64 stats_cookie;
};
-int nfp_flower_metadata_init(struct nfp_app *app);
+int nfp_flower_metadata_init(struct nfp_app *app, u64 host_ctx_count);
void nfp_flower_metadata_cleanup(struct nfp_app *app);
int nfp_flower_setup_tc(struct nfp_app *app, struct net_device *netdev,
diff --git a/drivers/net/ethernet/netronome/nfp/flower/match.c b/drivers/net/ethernet/netronome/nfp/flower/match.c
index 17acb8cc6044..e54fb6034326 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/match.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/match.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2017-2018 Netronome Systems, Inc. */
#include <linux/bitfield.h>
#include <net/pkt_cls.h>
diff --git a/drivers/net/ethernet/netronome/nfp/flower/metadata.c b/drivers/net/ethernet/netronome/nfp/flower/metadata.c
index c098730544b7..48729bf171e0 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/metadata.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/metadata.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2017-2018 Netronome Systems, Inc. */
#include <linux/hash.h>
#include <linux/hashtable.h>
@@ -48,6 +18,12 @@ struct nfp_mask_id_table {
u8 mask_id;
};
+struct nfp_fl_flow_table_cmp_arg {
+ struct net_device *netdev;
+ unsigned long cookie;
+ __be32 host_ctx;
+};
+
static int nfp_release_stats_entry(struct nfp_app *app, u32 stats_context_id)
{
struct nfp_flower_priv *priv = app->priv;
@@ -55,14 +31,14 @@ static int nfp_release_stats_entry(struct nfp_app *app, u32 stats_context_id)
ring = &priv->stats_ids.free_list;
/* Check if buffer is full. */
- if (!CIRC_SPACE(ring->head, ring->tail, NFP_FL_STATS_ENTRY_RS *
- NFP_FL_STATS_ELEM_RS -
+ if (!CIRC_SPACE(ring->head, ring->tail,
+ priv->stats_ring_size * NFP_FL_STATS_ELEM_RS -
NFP_FL_STATS_ELEM_RS + 1))
return -ENOBUFS;
memcpy(&ring->buf[ring->head], &stats_context_id, NFP_FL_STATS_ELEM_RS);
ring->head = (ring->head + NFP_FL_STATS_ELEM_RS) %
- (NFP_FL_STATS_ENTRY_RS * NFP_FL_STATS_ELEM_RS);
+ (priv->stats_ring_size * NFP_FL_STATS_ELEM_RS);
return 0;
}
@@ -74,7 +50,7 @@ static int nfp_get_stats_entry(struct nfp_app *app, u32 *stats_context_id)
struct circ_buf *ring;
ring = &priv->stats_ids.free_list;
- freed_stats_id = NFP_FL_STATS_ENTRY_RS;
+ freed_stats_id = priv->stats_ring_size;
/* Check for unallocated entries first. */
if (priv->stats_ids.init_unalloc > 0) {
*stats_context_id = priv->stats_ids.init_unalloc - 1;
@@ -92,7 +68,7 @@ static int nfp_get_stats_entry(struct nfp_app *app, u32 *stats_context_id)
*stats_context_id = temp_stats_id;
memcpy(&ring->buf[ring->tail], &freed_stats_id, NFP_FL_STATS_ELEM_RS);
ring->tail = (ring->tail + NFP_FL_STATS_ELEM_RS) %
- (NFP_FL_STATS_ENTRY_RS * NFP_FL_STATS_ELEM_RS);
+ (priv->stats_ring_size * NFP_FL_STATS_ELEM_RS);
return 0;
}
@@ -102,56 +78,37 @@ struct nfp_fl_payload *
nfp_flower_search_fl_table(struct nfp_app *app, unsigned long tc_flower_cookie,
struct net_device *netdev, __be32 host_ctx)
{
+ struct nfp_fl_flow_table_cmp_arg flower_cmp_arg;
struct nfp_flower_priv *priv = app->priv;
- struct nfp_fl_payload *flower_entry;
- hash_for_each_possible_rcu(priv->flow_table, flower_entry, link,
- tc_flower_cookie)
- if (flower_entry->tc_flower_cookie == tc_flower_cookie &&
- (!netdev || flower_entry->ingress_dev == netdev) &&
- (host_ctx == NFP_FL_STATS_CTX_DONT_CARE ||
- flower_entry->meta.host_ctx_id == host_ctx))
- return flower_entry;
+ flower_cmp_arg.netdev = netdev;
+ flower_cmp_arg.cookie = tc_flower_cookie;
+ flower_cmp_arg.host_ctx = host_ctx;
- return NULL;
-}
-
-static void
-nfp_flower_update_stats(struct nfp_app *app, struct nfp_fl_stats_frame *stats)
-{
- struct nfp_fl_payload *nfp_flow;
- unsigned long flower_cookie;
-
- flower_cookie = be64_to_cpu(stats->stats_cookie);
-
- rcu_read_lock();
- nfp_flow = nfp_flower_search_fl_table(app, flower_cookie, NULL,
- stats->stats_con_id);
- if (!nfp_flow)
- goto exit_rcu_unlock;
-
- spin_lock(&nfp_flow->lock);
- nfp_flow->stats.pkts += be32_to_cpu(stats->pkt_count);
- nfp_flow->stats.bytes += be64_to_cpu(stats->byte_count);
- nfp_flow->stats.used = jiffies;
- spin_unlock(&nfp_flow->lock);
-
-exit_rcu_unlock:
- rcu_read_unlock();
+ return rhashtable_lookup_fast(&priv->flow_table, &flower_cmp_arg,
+ nfp_flower_table_params);
}
void nfp_flower_rx_flow_stats(struct nfp_app *app, struct sk_buff *skb)
{
unsigned int msg_len = nfp_flower_cmsg_get_data_len(skb);
- struct nfp_fl_stats_frame *stats_frame;
+ struct nfp_flower_priv *priv = app->priv;
+ struct nfp_fl_stats_frame *stats;
unsigned char *msg;
+ u32 ctx_id;
int i;
msg = nfp_flower_cmsg_get_data(skb);
- stats_frame = (struct nfp_fl_stats_frame *)msg;
- for (i = 0; i < msg_len / sizeof(*stats_frame); i++)
- nfp_flower_update_stats(app, stats_frame + i);
+ spin_lock(&priv->stats_lock);
+ for (i = 0; i < msg_len / sizeof(*stats); i++) {
+ stats = (struct nfp_fl_stats_frame *)msg + i;
+ ctx_id = be32_to_cpu(stats->stats_con_id);
+ priv->stats[ctx_id].pkts += be32_to_cpu(stats->pkt_count);
+ priv->stats[ctx_id].bytes += be64_to_cpu(stats->byte_count);
+ priv->stats[ctx_id].used = jiffies;
+ }
+ spin_unlock(&priv->stats_lock);
}
static int nfp_release_mask_id(struct nfp_app *app, u8 mask_id)
@@ -345,9 +302,9 @@ int nfp_compile_flow_metadata(struct nfp_app *app,
/* Update flow payload with mask ids. */
nfp_flow->unmasked_data[NFP_FL_MASK_ID_LOCATION] = new_mask_id;
- nfp_flow->stats.pkts = 0;
- nfp_flow->stats.bytes = 0;
- nfp_flow->stats.used = jiffies;
+ priv->stats[stats_cxt].pkts = 0;
+ priv->stats[stats_cxt].bytes = 0;
+ priv->stats[stats_cxt].used = jiffies;
check_entry = nfp_flower_search_fl_table(app, flow->cookie, netdev,
NFP_FL_STATS_CTX_DONT_CARE);
@@ -389,12 +346,56 @@ int nfp_modify_flow_metadata(struct nfp_app *app,
return nfp_release_stats_entry(app, temp_ctx_id);
}
-int nfp_flower_metadata_init(struct nfp_app *app)
+static int nfp_fl_obj_cmpfn(struct rhashtable_compare_arg *arg,
+ const void *obj)
+{
+ const struct nfp_fl_flow_table_cmp_arg *cmp_arg = arg->key;
+ const struct nfp_fl_payload *flow_entry = obj;
+
+ if ((!cmp_arg->netdev || flow_entry->ingress_dev == cmp_arg->netdev) &&
+ (cmp_arg->host_ctx == NFP_FL_STATS_CTX_DONT_CARE ||
+ flow_entry->meta.host_ctx_id == cmp_arg->host_ctx))
+ return flow_entry->tc_flower_cookie != cmp_arg->cookie;
+
+ return 1;
+}
+
+static u32 nfp_fl_obj_hashfn(const void *data, u32 len, u32 seed)
+{
+ const struct nfp_fl_payload *flower_entry = data;
+
+ return jhash2((u32 *)&flower_entry->tc_flower_cookie,
+ sizeof(flower_entry->tc_flower_cookie) / sizeof(u32),
+ seed);
+}
+
+static u32 nfp_fl_key_hashfn(const void *data, u32 len, u32 seed)
+{
+ const struct nfp_fl_flow_table_cmp_arg *cmp_arg = data;
+
+ return jhash2((u32 *)&cmp_arg->cookie,
+ sizeof(cmp_arg->cookie) / sizeof(u32), seed);
+}
+
+const struct rhashtable_params nfp_flower_table_params = {
+ .head_offset = offsetof(struct nfp_fl_payload, fl_node),
+ .hashfn = nfp_fl_key_hashfn,
+ .obj_cmpfn = nfp_fl_obj_cmpfn,
+ .obj_hashfn = nfp_fl_obj_hashfn,
+ .automatic_shrinking = true,
+};
+
+int nfp_flower_metadata_init(struct nfp_app *app, u64 host_ctx_count)
{
struct nfp_flower_priv *priv = app->priv;
+ int err;
hash_init(priv->mask_table);
- hash_init(priv->flow_table);
+
+ err = rhashtable_init(&priv->flow_table, &nfp_flower_table_params);
+ if (err)
+ return err;
+
get_random_bytes(&priv->mask_id_seed, sizeof(priv->mask_id_seed));
/* Init ring buffer and unallocated mask_ids. */
@@ -402,7 +403,7 @@ int nfp_flower_metadata_init(struct nfp_app *app)
kmalloc_array(NFP_FLOWER_MASK_ENTRY_RS,
NFP_FLOWER_MASK_ELEMENT_RS, GFP_KERNEL);
if (!priv->mask_ids.mask_id_free_list.buf)
- return -ENOMEM;
+ goto err_free_flow_table;
priv->mask_ids.init_unallocated = NFP_FLOWER_MASK_ENTRY_RS - 1;
@@ -416,18 +417,29 @@ int nfp_flower_metadata_init(struct nfp_app *app)
/* Init ring buffer and unallocated stats_ids. */
priv->stats_ids.free_list.buf =
vmalloc(array_size(NFP_FL_STATS_ELEM_RS,
- NFP_FL_STATS_ENTRY_RS));
+ priv->stats_ring_size));
if (!priv->stats_ids.free_list.buf)
goto err_free_last_used;
- priv->stats_ids.init_unalloc = NFP_FL_REPEATED_HASH_MAX;
+ priv->stats_ids.init_unalloc = host_ctx_count;
+
+ priv->stats = kvmalloc_array(priv->stats_ring_size,
+ sizeof(struct nfp_fl_stats), GFP_KERNEL);
+ if (!priv->stats)
+ goto err_free_ring_buf;
+
+ spin_lock_init(&priv->stats_lock);
return 0;
+err_free_ring_buf:
+ vfree(priv->stats_ids.free_list.buf);
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_flow_table:
+ rhashtable_destroy(&priv->flow_table);
return -ENOMEM;
}
@@ -438,6 +450,9 @@ void nfp_flower_metadata_cleanup(struct nfp_app *app)
if (!priv)
return;
+ rhashtable_free_and_destroy(&priv->flow_table,
+ nfp_check_rhashtable_empty, NULL);
+ kvfree(priv->stats);
kfree(priv->mask_ids.mask_id_free_list.buf);
kfree(priv->mask_ids.last_used);
vfree(priv->stats_ids.free_list.buf);
diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c
index bd19624f10cf..29c95423ab64 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/offload.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2017-2018 Netronome Systems, Inc. */
#include <linux/skbuff.h>
#include <net/devlink.h>
@@ -428,8 +398,6 @@ nfp_flower_allocate_new(struct nfp_fl_key_ls *key_layer, bool egress)
flow_pay->nfp_tun_ipv4_addr = 0;
flow_pay->meta.flags = 0;
- spin_lock_init(&flow_pay->lock);
-
flow_pay->ingress_offload = !egress;
return flow_pay;
@@ -513,9 +481,12 @@ nfp_flower_add_offload(struct nfp_app *app, struct net_device *netdev,
if (err)
goto err_destroy_flow;
- INIT_HLIST_NODE(&flow_pay->link);
flow_pay->tc_flower_cookie = flow->cookie;
- hash_add_rcu(priv->flow_table, &flow_pay->link, flow->cookie);
+ err = rhashtable_insert_fast(&priv->flow_table, &flow_pay->fl_node,
+ nfp_flower_table_params);
+ if (err)
+ goto err_destroy_flow;
+
port->tc_offload_cnt++;
/* Deallocate flow payload when flower rule has been destroyed. */
@@ -550,6 +521,7 @@ nfp_flower_del_offload(struct nfp_app *app, struct net_device *netdev,
struct tc_cls_flower_offload *flow, bool egress)
{
struct nfp_port *port = nfp_port_from_netdev(netdev);
+ struct nfp_flower_priv *priv = app->priv;
struct nfp_fl_payload *nfp_flow;
struct net_device *ingr_dev;
int err;
@@ -573,11 +545,13 @@ nfp_flower_del_offload(struct nfp_app *app, struct net_device *netdev,
goto err_free_flow;
err_free_flow:
- hash_del_rcu(&nfp_flow->link);
port->tc_offload_cnt--;
kfree(nfp_flow->action_data);
kfree(nfp_flow->mask_data);
kfree(nfp_flow->unmasked_data);
+ WARN_ON_ONCE(rhashtable_remove_fast(&priv->flow_table,
+ &nfp_flow->fl_node,
+ nfp_flower_table_params));
kfree_rcu(nfp_flow, rcu);
return err;
}
@@ -598,8 +572,10 @@ static int
nfp_flower_get_stats(struct nfp_app *app, struct net_device *netdev,
struct tc_cls_flower_offload *flow, bool egress)
{
+ struct nfp_flower_priv *priv = app->priv;
struct nfp_fl_payload *nfp_flow;
struct net_device *ingr_dev;
+ u32 ctx_id;
ingr_dev = egress ? NULL : netdev;
nfp_flow = nfp_flower_search_fl_table(app, flow->cookie, ingr_dev,
@@ -610,13 +586,16 @@ nfp_flower_get_stats(struct nfp_app *app, struct net_device *netdev,
if (nfp_flow->ingress_offload && egress)
return 0;
- spin_lock_bh(&nfp_flow->lock);
- tcf_exts_stats_update(flow->exts, nfp_flow->stats.bytes,
- nfp_flow->stats.pkts, nfp_flow->stats.used);
+ ctx_id = be32_to_cpu(nfp_flow->meta.host_ctx_id);
+
+ spin_lock_bh(&priv->stats_lock);
+ tcf_exts_stats_update(flow->exts, priv->stats[ctx_id].bytes,
+ priv->stats[ctx_id].pkts,
+ priv->stats[ctx_id].used);
- nfp_flow->stats.pkts = 0;
- nfp_flow->stats.bytes = 0;
- spin_unlock_bh(&nfp_flow->lock);
+ priv->stats[ctx_id].pkts = 0;
+ priv->stats[ctx_id].bytes = 0;
+ spin_unlock_bh(&priv->stats_lock);
return 0;
}
diff --git a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
index 382bb93cb090..8e5bec04d1f9 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
@@ -1,39 +1,10 @@
-/*
- * Copyright (C) 2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2017-2018 Netronome Systems, Inc. */
#include <linux/etherdevice.h>
#include <linux/inetdevice.h>
#include <net/netevent.h>
+#include <net/vxlan.h>
#include <linux/idr.h>
#include <net/dst_metadata.h>
#include <net/arp.h>
@@ -217,7 +188,7 @@ static bool nfp_tun_is_netdev_to_offload(struct net_device *netdev)
return false;
if (!strcmp(netdev->rtnl_link_ops->kind, "openvswitch"))
return true;
- if (!strcmp(netdev->rtnl_link_ops->kind, "vxlan"))
+ if (netif_is_vxlan(netdev))
return true;
return false;
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_abi.h b/drivers/net/ethernet/netronome/nfp/nfp_abi.h
index 8b56c27931bf..dd359a44adfb 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_abi.h
+++ b/drivers/net/ethernet/netronome/nfp/nfp_abi.h
@@ -1,36 +1,5 @@
-/* SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) */
-/*
- * Copyright (C) 2018 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/* Copyright (C) 2018 Netronome Systems, Inc. */
#ifndef __NFP_ABI__
#define __NFP_ABI__ 1
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.c b/drivers/net/ethernet/netronome/nfp/nfp_app.c
index 8607d09ab732..68a0991aac22 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_app.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_app.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2017-2018 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2017-2018 Netronome Systems, Inc. */
#include <linux/bug.h>
#include <linux/lockdep.h>
@@ -60,6 +30,11 @@ static const struct nfp_app_type *apps[] = {
#endif
};
+void nfp_check_rhashtable_empty(void *ptr, void *arg)
+{
+ WARN_ON_ONCE(1);
+}
+
struct nfp_app *nfp_app_from_netdev(struct net_device *netdev)
{
if (nfp_netdev_is_nfp_net(netdev)) {
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.h b/drivers/net/ethernet/netronome/nfp/nfp_app.h
index 4e1eb3395648..4d6ecf99b1cc 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_app.h
+++ b/drivers/net/ethernet/netronome/nfp/nfp_app.h
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/* Copyright (C) 2017-2018 Netronome Systems, Inc. */
#ifndef _NFP_APP_H
#define _NFP_APP_H 1
@@ -40,6 +10,8 @@
#include "nfp_net_repr.h"
+#define NFP_APP_CTRL_MTU_MAX U32_MAX
+
struct bpf_prog;
struct net_device;
struct netdev_bpf;
@@ -178,6 +150,7 @@ struct nfp_app_type {
* @ctrl: pointer to ctrl vNIC struct
* @reprs: array of pointers to representors
* @type: pointer to const application ops and info
+ * @ctrl_mtu: MTU to set on the control vNIC (set in .init())
* @priv: app-specific priv data
*/
struct nfp_app {
@@ -189,9 +162,11 @@ struct nfp_app {
struct nfp_reprs __rcu *reprs[NFP_REPR_TYPE_MAX + 1];
const struct nfp_app_type *type;
+ unsigned int ctrl_mtu;
void *priv;
};
+void nfp_check_rhashtable_empty(void *ptr, void *arg);
bool __nfp_ctrl_tx(struct nfp_net *nn, struct sk_buff *skb);
bool nfp_ctrl_tx(struct nfp_net *nn, struct sk_buff *skb);
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app_nic.c b/drivers/net/ethernet/netronome/nfp/nfp_app_nic.c
index e2dfe4f168bb..f119277fd66c 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_app_nic.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_app_nic.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2017-2018 Netronome Systems, Inc. */
#include "nfpcore/nfp_cpp.h"
#include "nfpcore/nfp_nsp.h"
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_asm.c b/drivers/net/ethernet/netronome/nfp/nfp_asm.c
index cc6ace2be8a9..b04b83687fe2 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_asm.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_asm.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2016-2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2016-2018 Netronome Systems, Inc. */
#include <linux/bitops.h>
#include <linux/errno.h>
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_asm.h b/drivers/net/ethernet/netronome/nfp/nfp_asm.h
index fad0e62a910c..648c2810e5ba 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_asm.h
+++ b/drivers/net/ethernet/netronome/nfp/nfp_asm.h
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2016-2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/* Copyright (C) 2016-2018 Netronome Systems, Inc. */
#ifndef __NFP_ASM_H__
#define __NFP_ASM_H__ 1
@@ -82,6 +52,15 @@
#define OP_BR_BIT_ADDR_LO OP_BR_ADDR_LO
#define OP_BR_BIT_ADDR_HI OP_BR_ADDR_HI
+#define OP_BR_ALU_BASE 0x0e800000000ULL
+#define OP_BR_ALU_BASE_MASK 0x0ff80000000ULL
+#define OP_BR_ALU_A_SRC 0x000000003ffULL
+#define OP_BR_ALU_B_SRC 0x000000ffc00ULL
+#define OP_BR_ALU_DEFBR 0x00000300000ULL
+#define OP_BR_ALU_IMM_HI 0x0007fc00000ULL
+#define OP_BR_ALU_SRC_LMEXTN 0x40000000000ULL
+#define OP_BR_ALU_DST_LMEXTN 0x80000000000ULL
+
static inline bool nfp_is_br(u64 insn)
{
return (insn & OP_BR_BASE_MASK) == OP_BR_BASE ||
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c
index db463e20a876..808647ec3573 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2017-2018 Netronome Systems, Inc. */
#include <linux/rtnetlink.h>
#include <net/devlink.h>
@@ -96,6 +66,7 @@ nfp_devlink_port_split(struct devlink *devlink, unsigned int port_index,
{
struct nfp_pf *pf = devlink_priv(devlink);
struct nfp_eth_table_port eth_port;
+ unsigned int lanes;
int ret;
if (count < 2)
@@ -114,8 +85,12 @@ nfp_devlink_port_split(struct devlink *devlink, unsigned int port_index,
goto out;
}
- ret = nfp_devlink_set_lanes(pf, eth_port.index,
- eth_port.port_lanes / count);
+ /* Special case the 100G CXP -> 2x40G split */
+ lanes = eth_port.port_lanes / count;
+ if (eth_port.lanes == 10 && count == 2)
+ lanes = 8 / count;
+
+ ret = nfp_devlink_set_lanes(pf, eth_port.index, lanes);
out:
mutex_unlock(&pf->lock);
@@ -128,6 +103,7 @@ nfp_devlink_port_unsplit(struct devlink *devlink, unsigned int port_index,
{
struct nfp_pf *pf = devlink_priv(devlink);
struct nfp_eth_table_port eth_port;
+ unsigned int lanes;
int ret;
mutex_lock(&pf->lock);
@@ -143,7 +119,12 @@ nfp_devlink_port_unsplit(struct devlink *devlink, unsigned int port_index,
goto out;
}
- ret = nfp_devlink_set_lanes(pf, eth_port.index, eth_port.port_lanes);
+ /* Special case the 100G CXP -> 2x40G unsplit */
+ lanes = eth_port.port_lanes;
+ if (eth_port.port_lanes == 8)
+ lanes = 10;
+
+ ret = nfp_devlink_set_lanes(pf, eth_port.index, lanes);
out:
mutex_unlock(&pf->lock);
@@ -177,7 +158,8 @@ static int nfp_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode)
return nfp_app_eswitch_mode_get(pf->app, mode);
}
-static int nfp_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode)
+static int nfp_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
+ struct netlink_ext_ack *extack)
{
struct nfp_pf *pf = devlink_priv(devlink);
int ret;
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_hwmon.c b/drivers/net/ethernet/netronome/nfp/nfp_hwmon.c
index f0dcf45aeec1..5cabb1aa9c0c 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_hwmon.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_hwmon.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2017 Netronome Systems, Inc. */
#include <linux/kernel.h>
#include <linux/bitops.h>
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.c b/drivers/net/ethernet/netronome/nfp/nfp_main.c
index 4a540c5e27fe..6c10e8d119e4 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_main.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_main.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2015-2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2015-2018 Netronome Systems, Inc. */
/*
* nfp_main.c
@@ -68,6 +38,10 @@ static const struct pci_device_id nfp_pci_device_ids[] = {
PCI_VENDOR_ID_NETRONOME, PCI_ANY_ID,
PCI_ANY_ID, 0,
},
+ { PCI_VENDOR_ID_NETRONOME, PCI_DEVICE_ID_NETRONOME_NFP5000,
+ PCI_VENDOR_ID_NETRONOME, PCI_ANY_ID,
+ PCI_ANY_ID, 0,
+ },
{ PCI_VENDOR_ID_NETRONOME, PCI_DEVICE_ID_NETRONOME_NFP4000,
PCI_VENDOR_ID_NETRONOME, PCI_ANY_ID,
PCI_ANY_ID, 0,
@@ -112,23 +86,18 @@ nfp_pf_map_rtsym(struct nfp_pf *pf, const char *name, const char *sym_fmt,
int nfp_mbox_cmd(struct nfp_pf *pf, u32 cmd, void *in_data, u64 in_length,
void *out_data, u64 out_length)
{
- unsigned long long addr;
unsigned long err_at;
u64 max_data_sz;
u32 val = 0;
- u32 cpp_id;
int n, err;
if (!pf->mbox)
return -EOPNOTSUPP;
- cpp_id = NFP_CPP_ISLAND_ID(pf->mbox->target, NFP_CPP_ACTION_RW, 0,
- pf->mbox->domain);
- addr = pf->mbox->addr;
- max_data_sz = pf->mbox->size - NFP_MBOX_SYM_MIN_SIZE;
+ max_data_sz = nfp_rtsym_size(pf->mbox) - NFP_MBOX_SYM_MIN_SIZE;
/* Check if cmd field is clear */
- err = nfp_cpp_readl(pf->cpp, cpp_id, addr + NFP_MBOX_CMD, &val);
+ err = nfp_rtsym_readl(pf->cpp, pf->mbox, NFP_MBOX_CMD, &val);
if (err || val) {
nfp_warn(pf->cpp, "failed to issue command (%u): %u, err: %d\n",
cmd, val, err);
@@ -136,30 +105,29 @@ int nfp_mbox_cmd(struct nfp_pf *pf, u32 cmd, void *in_data, u64 in_length,
}
in_length = min(in_length, max_data_sz);
- n = nfp_cpp_write(pf->cpp, cpp_id, addr + NFP_MBOX_DATA,
- in_data, in_length);
+ n = nfp_rtsym_write(pf->cpp, pf->mbox, NFP_MBOX_DATA, in_data,
+ in_length);
if (n != in_length)
return -EIO;
/* Write data_len and wipe reserved */
- err = nfp_cpp_writeq(pf->cpp, cpp_id, addr + NFP_MBOX_DATA_LEN,
- in_length);
+ err = nfp_rtsym_writeq(pf->cpp, pf->mbox, NFP_MBOX_DATA_LEN, in_length);
if (err)
return err;
/* Read back for ordering */
- err = nfp_cpp_readl(pf->cpp, cpp_id, addr + NFP_MBOX_DATA_LEN, &val);
+ err = nfp_rtsym_readl(pf->cpp, pf->mbox, NFP_MBOX_DATA_LEN, &val);
if (err)
return err;
/* Write cmd and wipe return value */
- err = nfp_cpp_writeq(pf->cpp, cpp_id, addr + NFP_MBOX_CMD, cmd);
+ err = nfp_rtsym_writeq(pf->cpp, pf->mbox, NFP_MBOX_CMD, cmd);
if (err)
return err;
err_at = jiffies + 5 * HZ;
while (true) {
/* Wait for command to go to 0 (NFP_MBOX_NO_CMD) */
- err = nfp_cpp_readl(pf->cpp, cpp_id, addr + NFP_MBOX_CMD, &val);
+ err = nfp_rtsym_readl(pf->cpp, pf->mbox, NFP_MBOX_CMD, &val);
if (err)
return err;
if (!val)
@@ -172,18 +140,18 @@ int nfp_mbox_cmd(struct nfp_pf *pf, u32 cmd, void *in_data, u64 in_length,
}
/* Copy output if any (could be error info, do it before reading ret) */
- err = nfp_cpp_readl(pf->cpp, cpp_id, addr + NFP_MBOX_DATA_LEN, &val);
+ err = nfp_rtsym_readl(pf->cpp, pf->mbox, NFP_MBOX_DATA_LEN, &val);
if (err)
return err;
out_length = min_t(u32, val, min(out_length, max_data_sz));
- n = nfp_cpp_read(pf->cpp, cpp_id, addr + NFP_MBOX_DATA,
- out_data, out_length);
+ n = nfp_rtsym_read(pf->cpp, pf->mbox, NFP_MBOX_DATA,
+ out_data, out_length);
if (n != out_length)
return -EIO;
/* Check if there is an error */
- err = nfp_cpp_readl(pf->cpp, cpp_id, addr + NFP_MBOX_RET, &val);
+ err = nfp_rtsym_readl(pf->cpp, pf->mbox, NFP_MBOX_RET, &val);
if (err)
return err;
if (val)
@@ -441,8 +409,11 @@ nfp_fw_load(struct pci_dev *pdev, struct nfp_pf *pf, struct nfp_nsp *nsp)
}
fw = nfp_net_fw_find(pdev, pf);
- if (!fw)
+ if (!fw) {
+ if (nfp_nsp_has_stored_fw_load(nsp))
+ nfp_nsp_load_stored_fw(nsp);
return 0;
+ }
dev_info(&pdev->dev, "Soft-reset, loading FW image\n");
err = nfp_nsp_device_soft_reset(nsp);
@@ -453,7 +424,6 @@ nfp_fw_load(struct pci_dev *pdev, struct nfp_pf *pf, struct nfp_nsp *nsp)
}
err = nfp_nsp_load_fw(nsp, fw);
-
if (err < 0) {
dev_err(&pdev->dev, "FW loading failed: %d\n", err);
goto exit_release_fw;
@@ -566,9 +536,9 @@ static int nfp_pf_find_rtsyms(struct nfp_pf *pf)
/* Optional per-PCI PF mailbox */
snprintf(pf_symbol, sizeof(pf_symbol), NFP_MBOX_SYM_NAME, pf_id);
pf->mbox = nfp_rtsym_lookup(pf->rtbl, pf_symbol);
- if (pf->mbox && pf->mbox->size < NFP_MBOX_SYM_MIN_SIZE) {
+ if (pf->mbox && nfp_rtsym_size(pf->mbox) < NFP_MBOX_SYM_MIN_SIZE) {
nfp_err(pf->cpp, "PF mailbox symbol too small: %llu < %d\n",
- pf->mbox->size, NFP_MBOX_SYM_MIN_SIZE);
+ nfp_rtsym_size(pf->mbox), NFP_MBOX_SYM_MIN_SIZE);
return -EINVAL;
}
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.h b/drivers/net/ethernet/netronome/nfp/nfp_main.h
index 595b3dc280e3..a3613a2e0aa5 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_main.h
+++ b/drivers/net/ethernet/netronome/nfp/nfp_main.h
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2015-2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/* Copyright (C) 2015-2018 Netronome Systems, Inc. */
/*
* nfp_main.h
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h
index 439e6ffe2f05..6f0c37d09256 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net.h
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2015-2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/* Copyright (C) 2015-2018 Netronome Systems, Inc. */
/*
* nfp_net.h
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
index 8ed38fd5a852..6bddfcfdec34 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2015-2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2015-2018 Netronome Systems, Inc. */
/*
* nfp_net_common.c
@@ -2077,28 +2047,35 @@ nfp_ctrl_rx_one(struct nfp_net *nn, struct nfp_net_dp *dp,
return true;
}
-static void nfp_ctrl_rx(struct nfp_net_r_vector *r_vec)
+static bool nfp_ctrl_rx(struct nfp_net_r_vector *r_vec)
{
struct nfp_net_rx_ring *rx_ring = r_vec->rx_ring;
struct nfp_net *nn = r_vec->nfp_net;
struct nfp_net_dp *dp = &nn->dp;
+ unsigned int budget = 512;
- while (nfp_ctrl_rx_one(nn, dp, r_vec, rx_ring))
+ while (nfp_ctrl_rx_one(nn, dp, r_vec, rx_ring) && budget--)
continue;
+
+ return budget;
}
static void nfp_ctrl_poll(unsigned long arg)
{
struct nfp_net_r_vector *r_vec = (void *)arg;
- spin_lock_bh(&r_vec->lock);
+ spin_lock(&r_vec->lock);
nfp_net_tx_complete(r_vec->tx_ring, 0);
__nfp_ctrl_tx_queued(r_vec);
- spin_unlock_bh(&r_vec->lock);
+ spin_unlock(&r_vec->lock);
- nfp_ctrl_rx(r_vec);
-
- nfp_net_irq_unmask(r_vec->nfp_net, r_vec->irq_entry);
+ if (nfp_ctrl_rx(r_vec)) {
+ nfp_net_irq_unmask(r_vec->nfp_net, r_vec->irq_entry);
+ } else {
+ tasklet_schedule(&r_vec->tasklet);
+ nn_dp_warn(&r_vec->nfp_net->dp,
+ "control message budget exceeded!\n");
+ }
}
/* Setup and Configuration
@@ -2180,9 +2157,13 @@ nfp_net_tx_ring_alloc(struct nfp_net_dp *dp, struct nfp_net_tx_ring *tx_ring)
tx_ring->size = array_size(tx_ring->cnt, sizeof(*tx_ring->txds));
tx_ring->txds = dma_zalloc_coherent(dp->dev, tx_ring->size,
- &tx_ring->dma, GFP_KERNEL);
- if (!tx_ring->txds)
+ &tx_ring->dma,
+ GFP_KERNEL | __GFP_NOWARN);
+ if (!tx_ring->txds) {
+ netdev_warn(dp->netdev, "failed to allocate TX descriptor ring memory, requested descriptor count: %d, consider lowering descriptor count\n",
+ tx_ring->cnt);
goto err_alloc;
+ }
tx_ring->txbufs = kvcalloc(tx_ring->cnt, sizeof(*tx_ring->txbufs),
GFP_KERNEL);
@@ -2334,9 +2315,13 @@ nfp_net_rx_ring_alloc(struct nfp_net_dp *dp, struct nfp_net_rx_ring *rx_ring)
rx_ring->cnt = dp->rxd_cnt;
rx_ring->size = array_size(rx_ring->cnt, sizeof(*rx_ring->rxds));
rx_ring->rxds = dma_zalloc_coherent(dp->dev, rx_ring->size,
- &rx_ring->dma, GFP_KERNEL);
- if (!rx_ring->rxds)
+ &rx_ring->dma,
+ GFP_KERNEL | __GFP_NOWARN);
+ if (!rx_ring->rxds) {
+ netdev_warn(dp->netdev, "failed to allocate RX descriptor ring memory, requested descriptor count: %d, consider lowering descriptor count\n",
+ rx_ring->cnt);
goto err_alloc;
+ }
rx_ring->rxbufs = kvcalloc(rx_ring->cnt, sizeof(*rx_ring->rxbufs),
GFP_KERNEL);
@@ -3152,6 +3137,7 @@ static void nfp_net_stat64(struct net_device *netdev,
struct nfp_net *nn = netdev_priv(netdev);
int r;
+ /* Collect software stats */
for (r = 0; r < nn->max_r_vecs; r++) {
struct nfp_net_r_vector *r_vec = &nn->r_vecs[r];
u64 data[3];
@@ -3177,6 +3163,14 @@ static void nfp_net_stat64(struct net_device *netdev,
stats->tx_bytes += data[1];
stats->tx_errors += data[2];
}
+
+ /* Add in device stats */
+ stats->multicast += nn_readq(nn, NFP_NET_CFG_STATS_RX_MC_FRAMES);
+ stats->rx_dropped += nn_readq(nn, NFP_NET_CFG_STATS_RX_DISCARDS);
+ stats->rx_errors += nn_readq(nn, NFP_NET_CFG_STATS_RX_ERRORS);
+
+ stats->tx_dropped += nn_readq(nn, NFP_NET_CFG_STATS_TX_DISCARDS);
+ stats->tx_errors += nn_readq(nn, NFP_NET_CFG_STATS_TX_ERRORS);
}
static int nfp_net_set_features(struct net_device *netdev,
@@ -3744,15 +3738,18 @@ static void nfp_net_netdev_init(struct nfp_net *nn)
}
if (nn->cap & NFP_NET_CFG_CTRL_RSS_ANY)
netdev->hw_features |= NETIF_F_RXHASH;
- if (nn->cap & NFP_NET_CFG_CTRL_VXLAN &&
- nn->cap & NFP_NET_CFG_CTRL_NVGRE) {
+ if (nn->cap & NFP_NET_CFG_CTRL_VXLAN) {
if (nn->cap & NFP_NET_CFG_CTRL_LSO)
- netdev->hw_features |= NETIF_F_GSO_GRE |
- NETIF_F_GSO_UDP_TUNNEL;
- nn->dp.ctrl |= NFP_NET_CFG_CTRL_VXLAN | NFP_NET_CFG_CTRL_NVGRE;
-
- netdev->hw_enc_features = netdev->hw_features;
+ netdev->hw_features |= NETIF_F_GSO_UDP_TUNNEL;
+ nn->dp.ctrl |= NFP_NET_CFG_CTRL_VXLAN;
+ }
+ if (nn->cap & NFP_NET_CFG_CTRL_NVGRE) {
+ if (nn->cap & NFP_NET_CFG_CTRL_LSO)
+ netdev->hw_features |= NETIF_F_GSO_GRE;
+ nn->dp.ctrl |= NFP_NET_CFG_CTRL_NVGRE;
}
+ if (nn->cap & (NFP_NET_CFG_CTRL_VXLAN | NFP_NET_CFG_CTRL_NVGRE))
+ netdev->hw_enc_features = netdev->hw_features;
netdev->vlan_features = netdev->hw_features;
@@ -3857,10 +3854,20 @@ int nfp_net_init(struct nfp_net *nn)
return err;
/* Set default MTU and Freelist buffer size */
- if (nn->max_mtu < NFP_NET_DEFAULT_MTU)
+ if (!nfp_net_is_data_vnic(nn) && nn->app->ctrl_mtu) {
+ if (nn->app->ctrl_mtu <= nn->max_mtu) {
+ nn->dp.mtu = nn->app->ctrl_mtu;
+ } else {
+ if (nn->app->ctrl_mtu != NFP_APP_CTRL_MTU_MAX)
+ nn_warn(nn, "app requested MTU above max supported %u > %u\n",
+ nn->app->ctrl_mtu, nn->max_mtu);
+ nn->dp.mtu = nn->max_mtu;
+ }
+ } else if (nn->max_mtu < NFP_NET_DEFAULT_MTU) {
nn->dp.mtu = nn->max_mtu;
- else
+ } else {
nn->dp.mtu = NFP_NET_DEFAULT_MTU;
+ }
nn->dp.fl_bufsz = nfp_net_calc_fl_bufsz(&nn->dp);
if (nfp_app_ctrl_uses_data_vnics(nn->app))
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.c
index 1f9149bb2ae6..f2aaef976c7d 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2018 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2018 Netronome Systems, Inc. */
#include <linux/bitfield.h>
#include <linux/device.h>
@@ -113,6 +83,13 @@ int nfp_net_tlv_caps_parse(struct device *dev, u8 __iomem *ctrl_mem,
caps->mbox_len = length;
}
break;
+ case NFP_NET_CFG_TLV_TYPE_EXPERIMENTAL0:
+ case NFP_NET_CFG_TLV_TYPE_EXPERIMENTAL1:
+ dev_warn(dev,
+ "experimental TLV type:%u offset:%u len:%u\n",
+ FIELD_GET(NFP_NET_CFG_TLV_HEADER_TYPE, hdr),
+ offset, length);
+ break;
default:
if (!FIELD_GET(NFP_NET_CFG_TLV_HEADER_REQUIRED, hdr))
break;
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h
index 44d3ea75d043..d7c8518ac952 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2015-2018 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/* Copyright (C) 2015-2018 Netronome Systems, Inc. */
/*
* nfp_net_ctrl.h
@@ -264,7 +234,6 @@
* %NFP_NET_CFG_BPF_ADDR: DMA address of the buffer with JITed BPF code
*/
#define NFP_NET_CFG_BPF_ABI 0x0080
-#define NFP_NET_BPF_ABI 2
#define NFP_NET_CFG_BPF_CAP 0x0081
#define NFP_NET_BPF_CAP_RELO (1 << 0) /* seamless reload */
#define NFP_NET_CFG_BPF_MAX_LEN 0x0082
@@ -489,12 +458,20 @@
* %NFP_NET_CFG_TLV_TYPE_MBOX:
* Variable, mailbox area. Overwrites the default location which is
* %NFP_NET_CFG_MBOX_BASE and length %NFP_NET_CFG_MBOX_VAL_MAX_SZ.
+ *
+ * %NFP_NET_CFG_TLV_TYPE_EXPERIMENTAL0:
+ * %NFP_NET_CFG_TLV_TYPE_EXPERIMENTAL1:
+ * Variable, experimental IDs. IDs designated for internal development and
+ * experiments before a stable TLV ID has been allocated to a feature. Should
+ * never be present in production firmware.
*/
#define NFP_NET_CFG_TLV_TYPE_UNKNOWN 0
#define NFP_NET_CFG_TLV_TYPE_RESERVED 1
#define NFP_NET_CFG_TLV_TYPE_END 2
#define NFP_NET_CFG_TLV_TYPE_ME_FREQ 3
#define NFP_NET_CFG_TLV_TYPE_MBOX 4
+#define NFP_NET_CFG_TLV_TYPE_EXPERIMENTAL0 5
+#define NFP_NET_CFG_TLV_TYPE_EXPERIMENTAL1 6
struct device;
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_debugdump.c b/drivers/net/ethernet/netronome/nfp/nfp_net_debugdump.c
index bb8ed460086e..769ceef09756 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_debugdump.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_debugdump.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2017-2018 Netronome Systems, Inc. */
#include <linux/ethtool.h>
#include <linux/vmalloc.h>
@@ -188,25 +158,21 @@ nfp_net_dump_load_dumpspec(struct nfp_cpp *cpp, struct nfp_rtsym_table *rtbl)
const struct nfp_rtsym *specsym;
struct nfp_dumpspec *dumpspec;
int bytes_read;
- u32 cpp_id;
+ u64 sym_size;
specsym = nfp_rtsym_lookup(rtbl, NFP_DUMP_SPEC_RTSYM);
if (!specsym)
return NULL;
+ sym_size = nfp_rtsym_size(specsym);
/* expected size of this buffer is in the order of tens of kilobytes */
- dumpspec = vmalloc(sizeof(*dumpspec) + specsym->size);
+ dumpspec = vmalloc(sizeof(*dumpspec) + sym_size);
if (!dumpspec)
return NULL;
+ dumpspec->size = sym_size;
- dumpspec->size = specsym->size;
-
- cpp_id = NFP_CPP_ISLAND_ID(specsym->target, NFP_CPP_ACTION_RW, 0,
- specsym->domain);
-
- bytes_read = nfp_cpp_read(cpp, cpp_id, specsym->addr, dumpspec->data,
- specsym->size);
- if (bytes_read != specsym->size) {
+ bytes_read = nfp_rtsym_read(cpp, specsym, 0, dumpspec->data, sym_size);
+ if (bytes_read != sym_size) {
vfree(dumpspec);
nfp_warn(cpp, "Debug dump specification read failed.\n");
return NULL;
@@ -266,7 +232,6 @@ nfp_calc_rtsym_dump_sz(struct nfp_pf *pf, struct nfp_dump_tl *spec)
struct nfp_dumpspec_rtsym *spec_rtsym;
const struct nfp_rtsym *sym;
u32 tl_len, key_len;
- u32 size;
spec_rtsym = (struct nfp_dumpspec_rtsym *)spec;
tl_len = be32_to_cpu(spec->length);
@@ -278,13 +243,8 @@ nfp_calc_rtsym_dump_sz(struct nfp_pf *pf, struct nfp_dump_tl *spec)
if (!sym)
return nfp_dump_error_tlv_size(spec);
- if (sym->type == NFP_RTSYM_TYPE_ABS)
- size = sizeof(sym->addr);
- else
- size = sym->size;
-
return ALIGN8(offsetof(struct nfp_dump_rtsym, rtsym) + key_len + 1) +
- ALIGN8(size);
+ ALIGN8(nfp_rtsym_size(sym));
}
static int
@@ -644,7 +604,6 @@ nfp_dump_single_rtsym(struct nfp_pf *pf, struct nfp_dumpspec_rtsym *spec,
const struct nfp_rtsym *sym;
u32 tl_len, key_len;
int bytes_read;
- u32 cpp_id;
void *dest;
int err;
@@ -657,11 +616,7 @@ nfp_dump_single_rtsym(struct nfp_pf *pf, struct nfp_dumpspec_rtsym *spec,
if (!sym)
return nfp_dump_error_tlv(&spec->tl, -ENOENT, dump);
- if (sym->type == NFP_RTSYM_TYPE_ABS)
- sym_size = sizeof(sym->addr);
- else
- sym_size = sym->size;
-
+ sym_size = nfp_rtsym_size(sym);
header_size =
ALIGN8(offsetof(struct nfp_dump_rtsym, rtsym) + key_len + 1);
total_size = header_size + ALIGN8(sym_size);
@@ -676,23 +631,20 @@ nfp_dump_single_rtsym(struct nfp_pf *pf, struct nfp_dumpspec_rtsym *spec,
memcpy(dump_header->rtsym, spec->rtsym, key_len + 1);
dump_header->cpp.dump_length = cpu_to_be32(sym_size);
- if (sym->type == NFP_RTSYM_TYPE_ABS) {
- *(u64 *)dest = sym->addr;
- } else {
+ if (sym->type != NFP_RTSYM_TYPE_ABS) {
cpp_params.target = sym->target;
cpp_params.action = NFP_CPP_ACTION_RW;
cpp_params.token = 0;
cpp_params.island = sym->domain;
- cpp_id = nfp_get_numeric_cpp_id(&cpp_params);
dump_header->cpp.cpp_id = cpp_params;
dump_header->cpp.offset = cpu_to_be32(sym->addr);
- bytes_read = nfp_cpp_read(pf->cpp, cpp_id, sym->addr, dest,
- sym_size);
- if (bytes_read != sym_size) {
- if (bytes_read >= 0)
- bytes_read = -EIO;
- dump_header->error = cpu_to_be32(bytes_read);
- }
+ }
+
+ bytes_read = nfp_rtsym_read(pf->cpp, sym, 0, dest, sym_size);
+ if (bytes_read != sym_size) {
+ if (bytes_read >= 0)
+ bytes_read = -EIO;
+ dump_header->error = cpu_to_be32(bytes_read);
}
return 0;
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c b/drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c
index 099b63d67451..69b1c9b62e3d 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2015-2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2015-2018 Netronome Systems, Inc. */
#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/rtnetlink.h>
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
index 6a79c8e4a7a4..cb9c512abc76 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2015-2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2015-2018 Netronome Systems, Inc. */
/*
* nfp_net_ethtool.c
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c
index 28516eecccc8..1e7d20468a34 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2015-2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2015-2018 Netronome Systems, Inc. */
/*
* nfp_net_main.c
@@ -470,8 +440,8 @@ static void nfp_net_pci_unmap_mem(struct nfp_pf *pf)
static int nfp_net_pci_map_mem(struct nfp_pf *pf)
{
+ u32 min_size, cpp_id;
u8 __iomem *mem;
- u32 min_size;
int err;
min_size = pf->max_data_vnics * NFP_PF_CSR_SLICE_SIZE;
@@ -519,9 +489,9 @@ static int nfp_net_pci_map_mem(struct nfp_pf *pf)
pf->vfcfg_tbl2 = NULL;
}
- mem = nfp_cpp_map_area(pf->cpp, "net.qc", 0, 0,
- NFP_PCIE_QUEUE(0), NFP_QCP_QUEUE_AREA_SZ,
- &pf->qc_area);
+ cpp_id = NFP_CPP_ISLAND_ID(0, NFP_CPP_ACTION_RW, 0, 0);
+ mem = nfp_cpp_map_area(pf->cpp, "net.qc", cpp_id, NFP_PCIE_QUEUE(0),
+ NFP_QCP_QUEUE_AREA_SZ, &pf->qc_area);
if (IS_ERR(mem)) {
nfp_err(pf->cpp, "Failed to map Queue Controller area.\n");
err = PTR_ERR(mem);
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c
index 18a09cdcd9c6..c09b893c30dd 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2017-2018 Netronome Systems, Inc. */
#include <linux/etherdevice.h>
#include <linux/io-64-nonatomic-hi-lo.h>
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.h b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.h
index 1bf2b18109ab..c412b94bfb97 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.h
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.h
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/* Copyright (C) 2017-2018 Netronome Systems, Inc. */
#ifndef NFP_NET_REPR_H
#define NFP_NET_REPR_H
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_sriov.c b/drivers/net/ethernet/netronome/nfp/nfp_net_sriov.c
index 8b1b962cf1d1..b6ec46ed0540 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_sriov.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_sriov.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2017 Netronome Systems, Inc. */
#include <linux/bitfield.h>
#include <linux/errno.h>
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_sriov.h b/drivers/net/ethernet/netronome/nfp/nfp_net_sriov.h
index e9df9d1eab8e..c9f09c5bb5ee 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_sriov.h
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_sriov.h
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/* Copyright (C) 2017 Netronome Systems, Inc. */
#ifndef _NFP_NET_SRIOV_H_
#define _NFP_NET_SRIOV_H_
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c b/drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c
index 68928c86b698..d2c1e9ea5668 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2015-2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2015-2018 Netronome Systems, Inc. */
/*
* nfp_netvf_main.c
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_port.c b/drivers/net/ethernet/netronome/nfp/nfp_port.c
index 9c1298114c70..86bc149ca231 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_port.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_port.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2017-2018 Netronome Systems, Inc. */
#include <linux/lockdep.h>
#include <linux/netdevice.h>
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_port.h b/drivers/net/ethernet/netronome/nfp/nfp_port.h
index 51f10ae2d53e..b2479a2a49e5 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_port.h
+++ b/drivers/net/ethernet/netronome/nfp/nfp_port.h
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/* Copyright (C) 2017-2018 Netronome Systems, Inc. */
#ifndef _NFP_PORT_H_
#define _NFP_PORT_H_
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_shared_buf.c b/drivers/net/ethernet/netronome/nfp/nfp_shared_buf.c
index 0ecd83705368..814360ed3a20 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_shared_buf.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_shared_buf.c
@@ -1,36 +1,5 @@
-// SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
-/*
- * Copyright (C) 2018 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2018 Netronome Systems, Inc. */
#include <linux/kernel.h>
#include <net/devlink.h>
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/crc32.h b/drivers/net/ethernet/netronome/nfp/nfpcore/crc32.h
index 6cee6382deb4..afab6f0fc564 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/crc32.h
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/crc32.h
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2015-2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/* Copyright (C) 2015-2017 Netronome Systems, Inc. */
#ifndef NFP_CRC32_H
#define NFP_CRC32_H
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp.h
index f44d0a857314..db94b0bddc92 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp.h
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp.h
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2015-2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/* Copyright (C) 2015-2018 Netronome Systems, Inc. */
/*
* nfp.h
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000/nfp6000.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000/nfp6000.h
index 0e497a6154db..4a12133850f5 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000/nfp6000.h
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000/nfp6000.h
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2015-2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/* Copyright (C) 2015-2017 Netronome Systems, Inc. */
#ifndef NFP6000_NFP6000_H
#define NFP6000_NFP6000_H
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000/nfp_xpb.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000/nfp_xpb.h
index 40fb19939505..9a86ec11c5ba 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000/nfp_xpb.h
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000/nfp_xpb.h
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2015-2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/* Copyright (C) 2015-2017 Netronome Systems, Inc. */
/*
* nfp_xpb.h
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c
index c8d0b1016a64..85d46f206b3c 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2015-2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2015-2018 Netronome Systems, Inc. */
/*
* nfp6000_pcie.c
@@ -138,6 +108,7 @@
/* The number of explicit BARs to reserve.
* Minimum is 0, maximum is 4 on the NFP6000.
+ * The NFP3800 can have only one per PF.
*/
#define NFP_PCIE_EXPLICIT_BARS 2
@@ -589,8 +560,8 @@ static int enable_bars(struct nfp6000_pcie *nfp, u16 interface)
NFP_PCIE_BAR_PCIE2CPP_MapType_EXPLICIT3),
};
char status_msg[196] = {};
+ int i, err, bars_free;
struct nfp_bar *bar;
- int i, bars_free;
int expl_groups;
char *msg, *end;
@@ -643,6 +614,8 @@ static int enable_bars(struct nfp6000_pcie *nfp, u16 interface)
bar->iomem = ioremap_nocache(nfp_bar_resource_start(bar),
nfp_bar_resource_len(bar));
if (bar->iomem) {
+ int pf;
+
msg += snprintf(msg, end - msg, "0.0: General/MSI-X SRAM, ");
atomic_inc(&bar->refcnt);
bars_free--;
@@ -651,22 +624,40 @@ static int enable_bars(struct nfp6000_pcie *nfp, u16 interface)
nfp->expl.data = bar->iomem + NFP_PCIE_SRAM + 0x1000;
- if (nfp->pdev->device == PCI_DEVICE_ID_NETRONOME_NFP4000 ||
- nfp->pdev->device == PCI_DEVICE_ID_NETRONOME_NFP6000) {
- nfp->iomem.csr = bar->iomem + NFP_PCIE_BAR(0);
- } else {
- int pf = nfp->pdev->devfn & 7;
-
+ switch (nfp->pdev->device) {
+ case PCI_DEVICE_ID_NETRONOME_NFP3800:
+ pf = nfp->pdev->devfn & 7;
nfp->iomem.csr = bar->iomem + NFP_PCIE_BAR(pf);
+ break;
+ case PCI_DEVICE_ID_NETRONOME_NFP4000:
+ case PCI_DEVICE_ID_NETRONOME_NFP5000:
+ case PCI_DEVICE_ID_NETRONOME_NFP6000:
+ nfp->iomem.csr = bar->iomem + NFP_PCIE_BAR(0);
+ break;
+ default:
+ dev_err(nfp->dev, "Unsupported device ID: %04hx!\n",
+ nfp->pdev->device);
+ err = -EINVAL;
+ goto err_unmap_bar0;
}
nfp->iomem.em = bar->iomem + NFP_PCIE_EM;
}
- if (nfp->pdev->device == PCI_DEVICE_ID_NETRONOME_NFP4000 ||
- nfp->pdev->device == PCI_DEVICE_ID_NETRONOME_NFP6000)
- expl_groups = 4;
- else
+ switch (nfp->pdev->device) {
+ case PCI_DEVICE_ID_NETRONOME_NFP3800:
expl_groups = 1;
+ break;
+ case PCI_DEVICE_ID_NETRONOME_NFP4000:
+ case PCI_DEVICE_ID_NETRONOME_NFP5000:
+ case PCI_DEVICE_ID_NETRONOME_NFP6000:
+ expl_groups = 4;
+ break;
+ default:
+ dev_err(nfp->dev, "Unsupported device ID: %04hx!\n",
+ nfp->pdev->device);
+ err = -EINVAL;
+ goto err_unmap_bar0;
+ }
/* Configure, and lock, BAR0.1 for PCIe XPB (MSI-X PBA) */
bar = &nfp->bar[1];
@@ -711,6 +702,11 @@ static int enable_bars(struct nfp6000_pcie *nfp, u16 interface)
dev_info(nfp->dev, "%sfree: %d/%d\n", status_msg, bars_free, nfp->bars);
return 0;
+
+err_unmap_bar0:
+ if (nfp->bar[0].iomem)
+ iounmap(nfp->bar[0].iomem);
+ return err;
}
static void disable_bars(struct nfp6000_pcie *nfp)
@@ -1327,7 +1323,7 @@ struct nfp_cpp *nfp_cpp_from_nfp6000_pcie(struct pci_dev *pdev)
/* Finished with card initialization. */
dev_info(&pdev->dev,
- "Netronome Flow Processor NFP4000/NFP6000 PCIe Card Probe\n");
+ "Netronome Flow Processor NFP4000/NFP5000/NFP6000 PCIe Card Probe\n");
pcie_print_link_status(pdev);
nfp = kzalloc(sizeof(*nfp), GFP_KERNEL);
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.h
index 245d8aaaa97d..6d1bffa6eac6 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.h
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.h
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2015-2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/* Copyright (C) 2015-2017 Netronome Systems, Inc. */
/*
* nfp6000_pcie.h
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_arm.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_arm.h
index 31fe92247f51..3d172e255693 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_arm.h
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_arm.h
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2015-2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/* Copyright (C) 2015-2017 Netronome Systems, Inc. */
/*
* nfp_arm.h
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h
index c338d539fa96..2dd0f5842873 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2015-2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/* Copyright (C) 2015-2018 Netronome Systems, Inc. */
/*
* nfp_cpp.h
@@ -56,9 +26,16 @@
dev_info(nfp_cpp_device(cpp)->parent, NFP_SUBSYS ": " fmt, ## args)
#define nfp_dbg(cpp, fmt, args...) \
dev_dbg(nfp_cpp_device(cpp)->parent, NFP_SUBSYS ": " fmt, ## args)
+#define nfp_printk(level, cpp, fmt, args...) \
+ dev_printk(level, nfp_cpp_device(cpp)->parent, \
+ NFP_SUBSYS ": " fmt, ## args)
#define PCI_64BIT_BAR_COUNT 3
+/* NFP hardware vendor/device ids.
+ */
+#define PCI_DEVICE_ID_NETRONOME_NFP3800 0x3800
+
#define NFP_CPP_NUM_TARGETS 16
/* Max size of area it should be safe to request */
#define NFP_CPP_SAFE_AREA_SIZE SZ_2M
@@ -226,6 +203,7 @@ void nfp_cpp_free(struct nfp_cpp *cpp);
u32 nfp_cpp_model(struct nfp_cpp *cpp);
u16 nfp_cpp_interface(struct nfp_cpp *cpp);
int nfp_cpp_serial(struct nfp_cpp *cpp, const u8 **serial);
+unsigned int nfp_cpp_mu_locality_lsb(struct nfp_cpp *cpp);
struct nfp_cpp_area *nfp_cpp_area_alloc_with_name(struct nfp_cpp *cpp,
u32 cpp_id,
@@ -286,8 +264,8 @@ int nfp_cpp_writeq(struct nfp_cpp *cpp, u32 cpp_id,
unsigned long long address, u64 value);
u8 __iomem *
-nfp_cpp_map_area(struct nfp_cpp *cpp, const char *name, int domain, int target,
- u64 addr, unsigned long size, struct nfp_cpp_area **area);
+nfp_cpp_map_area(struct nfp_cpp *cpp, const char *name, u32 cpp_id, u64 addr,
+ unsigned long size, struct nfp_cpp_area **area);
struct nfp_cpp_mutex;
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c
index 73de57a09800..94994a939277 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2015-2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2015-2018 Netronome Systems, Inc. */
/*
* nfp_cppcore.c
@@ -75,6 +45,7 @@ struct nfp_cpp_resource {
* @interface: chip interface id we are using to reach it
* @serial: chip serial number
* @imb_cat_table: CPP Mapping Table
+ * @mu_locality_lsb: MU access type bit offset
*
* Following fields use explicit locking:
* @resource_list: NFP CPP resource list
@@ -100,6 +71,7 @@ struct nfp_cpp {
wait_queue_head_t waitq;
u32 imb_cat_table[16];
+ unsigned int mu_locality_lsb;
struct mutex area_cache_mutex;
struct list_head area_cache_list;
@@ -266,6 +238,34 @@ int nfp_cpp_serial(struct nfp_cpp *cpp, const u8 **serial)
return sizeof(cpp->serial);
}
+#define NFP_IMB_TGTADDRESSMODECFG_MODE_of(_x) (((_x) >> 13) & 0x7)
+#define NFP_IMB_TGTADDRESSMODECFG_ADDRMODE BIT(12)
+#define NFP_IMB_TGTADDRESSMODECFG_ADDRMODE_32_BIT 0
+#define NFP_IMB_TGTADDRESSMODECFG_ADDRMODE_40_BIT BIT(12)
+
+static int nfp_cpp_set_mu_locality_lsb(struct nfp_cpp *cpp)
+{
+ unsigned int mode, addr40;
+ u32 imbcppat;
+ int res;
+
+ imbcppat = cpp->imb_cat_table[NFP_CPP_TARGET_MU];
+ mode = NFP_IMB_TGTADDRESSMODECFG_MODE_of(imbcppat);
+ addr40 = !!(imbcppat & NFP_IMB_TGTADDRESSMODECFG_ADDRMODE);
+
+ res = nfp_cppat_mu_locality_lsb(mode, addr40);
+ if (res < 0)
+ return res;
+ cpp->mu_locality_lsb = res;
+
+ return 0;
+}
+
+unsigned int nfp_cpp_mu_locality_lsb(struct nfp_cpp *cpp)
+{
+ return cpp->mu_locality_lsb;
+}
+
/**
* nfp_cpp_area_alloc_with_name() - allocate a new CPP area
* @cpp: CPP device handle
@@ -1241,6 +1241,12 @@ nfp_cpp_from_operations(const struct nfp_cpp_operations *ops,
nfp_cpp_readl(cpp, arm, NFP_ARM_GCSR + NFP_ARM_GCSR_SOFTMODEL3,
&mask[1]);
+ err = nfp_cpp_set_mu_locality_lsb(cpp);
+ if (err < 0) {
+ dev_err(parent, "Can't calculate MU locality bit offset\n");
+ goto err_out;
+ }
+
dev_info(cpp->dev.parent, "Model: 0x%08x, SN: %pM, Ifc: 0x%04x\n",
nfp_cpp_model(cpp), cpp->serial, nfp_cpp_interface(cpp));
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpplib.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpplib.c
index 20bad05e2e92..3cfecf105bde 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpplib.c
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpplib.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2015-2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2015-2018 Netronome Systems, Inc. */
/*
* nfp_cpplib.c
@@ -294,8 +264,7 @@ exit_release:
* nfp_cpp_map_area() - Helper function to map an area
* @cpp: NFP CPP handler
* @name: Name for the area
- * @domain: CPP domain
- * @target: CPP target
+ * @cpp_id: CPP ID for operation
* @addr: CPP address
* @size: Size of the area
* @area: Area handle (output)
@@ -306,15 +275,12 @@ exit_release:
* Return: Pointer to memory mapped area or ERR_PTR
*/
u8 __iomem *
-nfp_cpp_map_area(struct nfp_cpp *cpp, const char *name, int domain, int target,
- u64 addr, unsigned long size, struct nfp_cpp_area **area)
+nfp_cpp_map_area(struct nfp_cpp *cpp, const char *name, u32 cpp_id, u64 addr,
+ unsigned long size, struct nfp_cpp_area **area)
{
u8 __iomem *res;
- u32 dest;
-
- dest = NFP_CPP_ISLAND_ID(target, NFP_CPP_ACTION_RW, 0, domain);
- *area = nfp_cpp_area_alloc_acquire(cpp, name, dest, addr, size);
+ *area = nfp_cpp_area_alloc_acquire(cpp, name, cpp_id, addr, size);
if (!*area)
goto err_eio;
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_hwinfo.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_hwinfo.c
index 063a9a6243d6..f05dd34ab89f 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_hwinfo.c
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_hwinfo.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2015-2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2015-2017 Netronome Systems, Inc. */
/* Parse the hwinfo table that the ARM firmware builds in the ARM scratch SRAM
* after chip reset.
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_mip.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_mip.c
index 5f193fe2d69e..79e17943519e 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_mip.c
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_mip.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2015-2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2015-2017 Netronome Systems, Inc. */
/*
* nfp_mip.c
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_mutex.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_mutex.c
index c88bf673cb76..7bc17b94ac60 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_mutex.c
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_mutex.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2015-2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2015-2018 Netronome Systems, Inc. */
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.c
index 40510860341b..d4e02542e2e9 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.c
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2015-2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2015-2018 Netronome Systems, Inc. */
/*
* nfp_nffw.c
@@ -156,29 +126,6 @@ static u64 nffw_fwinfo_mip_offset_get(const struct nffw_fwinfo *fi)
return (mip_off_hi & 0xFF) << 32 | le32_to_cpu(fi->mip_offset_lo);
}
-#define NFP_IMB_TGTADDRESSMODECFG_MODE_of(_x) (((_x) >> 13) & 0x7)
-#define NFP_IMB_TGTADDRESSMODECFG_ADDRMODE BIT(12)
-#define NFP_IMB_TGTADDRESSMODECFG_ADDRMODE_32_BIT 0
-#define NFP_IMB_TGTADDRESSMODECFG_ADDRMODE_40_BIT BIT(12)
-
-static int nfp_mip_mu_locality_lsb(struct nfp_cpp *cpp)
-{
- unsigned int mode, addr40;
- u32 xpbaddr, imbcppat;
- int err;
-
- /* Hardcoded XPB IMB Base, island 0 */
- xpbaddr = 0x000a0000 + NFP_CPP_TARGET_MU * 4;
- err = nfp_xpb_readl(cpp, xpbaddr, &imbcppat);
- if (err < 0)
- return err;
-
- mode = NFP_IMB_TGTADDRESSMODECFG_MODE_of(imbcppat);
- addr40 = !!(imbcppat & NFP_IMB_TGTADDRESSMODECFG_ADDRMODE);
-
- return nfp_cppat_mu_locality_lsb(mode, addr40);
-}
-
static unsigned int
nffw_res_fwinfos(struct nfp_nffw_info_data *fwinf, struct nffw_fwinfo **arr)
{
@@ -304,14 +251,7 @@ int nfp_nffw_info_mip_first(struct nfp_nffw_info *state, u32 *cpp_id, u64 *off)
*off = nffw_fwinfo_mip_offset_get(fwinfo);
if (nffw_fwinfo_mip_mu_da_get(fwinfo)) {
- int locality_off;
-
- if (NFP_CPP_ID_TARGET_of(*cpp_id) != NFP_CPP_TARGET_MU)
- return 0;
-
- locality_off = nfp_mip_mu_locality_lsb(state->cpp);
- if (locality_off < 0)
- return locality_off;
+ int locality_off = nfp_cpp_mu_locality_lsb(state->cpp);
*off &= ~(NFP_MU_ADDR_ACCESS_TYPE_MASK << locality_off);
*off |= NFP_MU_ADDR_ACCESS_TYPE_DIRECT << locality_off;
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h
index df599d5b6bb3..49a4d3f56b56 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2015-2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/* Copyright (C) 2015-2018 Netronome Systems, Inc. */
/*
* nfp_nffw.h
@@ -61,10 +31,12 @@ void nfp_mip_strtab(const struct nfp_mip *mip, u32 *addr, u32 *size);
/* Implemented in nfp_rtsym.c */
-#define NFP_RTSYM_TYPE_NONE 0
-#define NFP_RTSYM_TYPE_OBJECT 1
-#define NFP_RTSYM_TYPE_FUNCTION 2
-#define NFP_RTSYM_TYPE_ABS 3
+enum nfp_rtsym_type {
+ NFP_RTSYM_TYPE_NONE = 0,
+ NFP_RTSYM_TYPE_OBJECT = 1,
+ NFP_RTSYM_TYPE_FUNCTION = 2,
+ NFP_RTSYM_TYPE_ABS = 3,
+};
#define NFP_RTSYM_TARGET_NONE 0
#define NFP_RTSYM_TARGET_LMEM -1
@@ -83,7 +55,7 @@ struct nfp_rtsym {
const char *name;
u64 addr;
u64 size;
- int type;
+ enum nfp_rtsym_type type;
int target;
int domain;
};
@@ -98,6 +70,32 @@ const struct nfp_rtsym *nfp_rtsym_get(struct nfp_rtsym_table *rtbl, int idx);
const struct nfp_rtsym *
nfp_rtsym_lookup(struct nfp_rtsym_table *rtbl, const char *name);
+u64 nfp_rtsym_size(const struct nfp_rtsym *rtsym);
+int __nfp_rtsym_read(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
+ u8 action, u8 token, u64 off, void *buf, size_t len);
+int nfp_rtsym_read(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
+ void *buf, size_t len);
+int __nfp_rtsym_readl(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
+ u8 action, u8 token, u64 off, u32 *value);
+int nfp_rtsym_readl(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
+ u32 *value);
+int __nfp_rtsym_readq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
+ u8 action, u8 token, u64 off, u64 *value);
+int nfp_rtsym_readq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
+ u64 *value);
+int __nfp_rtsym_write(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
+ u8 action, u8 token, u64 off, void *buf, size_t len);
+int nfp_rtsym_write(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
+ void *buf, size_t len);
+int __nfp_rtsym_writel(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
+ u8 action, u8 token, u64 off, u32 value);
+int nfp_rtsym_writel(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
+ u32 value);
+int __nfp_rtsym_writeq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
+ u8 action, u8 token, u64 off, u64 value);
+int nfp_rtsym_writeq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
+ u64 value);
+
u64 nfp_rtsym_read_le(struct nfp_rtsym_table *rtbl, const char *name,
int *error);
int nfp_rtsym_write_le(struct nfp_rtsym_table *rtbl, const char *name,
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c
index 2abee0fe3a7c..ce1577bbbd2a 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2015-2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2015-2018 Netronome Systems, Inc. */
/*
* nfp_nsp.c
@@ -87,6 +57,11 @@
#define NSP_CODE_MAJOR GENMASK(15, 12)
#define NSP_CODE_MINOR GENMASK(11, 0)
+#define NFP_FW_LOAD_RET_MAJOR GENMASK(15, 8)
+#define NFP_FW_LOAD_RET_MINOR GENMASK(23, 16)
+
+#define NFP_HWINFO_LOOKUP_SIZE GENMASK(11, 0)
+
enum nfp_nsp_cmd {
SPCODE_NOOP = 0, /* No operation */
SPCODE_SOFT_RESET = 1, /* Soft reset the NFP */
@@ -100,6 +75,8 @@ enum nfp_nsp_cmd {
SPCODE_NSP_WRITE_FLASH = 11, /* Load and flash image from buffer */
SPCODE_NSP_SENSORS = 12, /* Read NSP sensor(s) */
SPCODE_NSP_IDENTIFY = 13, /* Read NSP version */
+ SPCODE_FW_STORED = 16, /* If no FW loaded, load flash app FW */
+ SPCODE_HWINFO_LOOKUP = 17, /* Lookup HWinfo with overwrites etc. */
};
static const struct {
@@ -127,6 +104,40 @@ struct nfp_nsp {
void *entries;
};
+/**
+ * struct nfp_nsp_command_arg - NFP command argument structure
+ * @code: NFP SP Command Code
+ * @timeout_sec:Timeout value to wait for completion in seconds
+ * @option: NFP SP Command Argument
+ * @buff_cpp: NFP SP Buffer CPP Address info
+ * @buff_addr: NFP SP Buffer Host address
+ * @error_cb: Callback for interpreting option if error occurred
+ */
+struct nfp_nsp_command_arg {
+ u16 code;
+ unsigned int timeout_sec;
+ u32 option;
+ u32 buff_cpp;
+ u64 buff_addr;
+ void (*error_cb)(struct nfp_nsp *state, u32 ret_val);
+};
+
+/**
+ * struct nfp_nsp_command_buf_arg - NFP command with buffer argument structure
+ * @arg: NFP command argument structure
+ * @in_buf: Buffer with data for input
+ * @in_size: Size of @in_buf
+ * @out_buf: Buffer for output data
+ * @out_size: Size of @out_buf
+ */
+struct nfp_nsp_command_buf_arg {
+ struct nfp_nsp_command_arg arg;
+ const void *in_buf;
+ unsigned int in_size;
+ void *out_buf;
+ unsigned int out_size;
+};
+
struct nfp_cpp *nfp_nsp_cpp(struct nfp_nsp *state)
{
return state->cpp;
@@ -291,11 +302,7 @@ nfp_nsp_wait_reg(struct nfp_cpp *cpp, u64 *reg, u32 nsp_cpp, u64 addr,
/**
* __nfp_nsp_command() - Execute a command on the NFP Service Processor
* @state: NFP SP state
- * @code: NFP SP Command Code
- * @option: NFP SP Command Argument
- * @buff_cpp: NFP SP Buffer CPP Address info
- * @buff_addr: NFP SP Buffer Host address
- * @timeout_sec:Timeout value to wait for completion in seconds
+ * @arg: NFP command argument structure
*
* Return: 0 for success with no result
*
@@ -308,8 +315,7 @@ nfp_nsp_wait_reg(struct nfp_cpp *cpp, u64 *reg, u32 nsp_cpp, u64 addr,
* -ETIMEDOUT if the NSP took longer than @timeout_sec seconds to complete
*/
static int
-__nfp_nsp_command(struct nfp_nsp *state, u16 code, u32 option, u32 buff_cpp,
- u64 buff_addr, u32 timeout_sec)
+__nfp_nsp_command(struct nfp_nsp *state, const struct nfp_nsp_command_arg *arg)
{
u64 reg, ret_val, nsp_base, nsp_buffer, nsp_status, nsp_command;
struct nfp_cpp *cpp = state->cpp;
@@ -326,22 +332,22 @@ __nfp_nsp_command(struct nfp_nsp *state, u16 code, u32 option, u32 buff_cpp,
if (err)
return err;
- if (!FIELD_FIT(NSP_BUFFER_CPP, buff_cpp >> 8) ||
- !FIELD_FIT(NSP_BUFFER_ADDRESS, buff_addr)) {
+ if (!FIELD_FIT(NSP_BUFFER_CPP, arg->buff_cpp >> 8) ||
+ !FIELD_FIT(NSP_BUFFER_ADDRESS, arg->buff_addr)) {
nfp_err(cpp, "Host buffer out of reach %08x %016llx\n",
- buff_cpp, buff_addr);
+ arg->buff_cpp, arg->buff_addr);
return -EINVAL;
}
err = nfp_cpp_writeq(cpp, nsp_cpp, nsp_buffer,
- FIELD_PREP(NSP_BUFFER_CPP, buff_cpp >> 8) |
- FIELD_PREP(NSP_BUFFER_ADDRESS, buff_addr));
+ FIELD_PREP(NSP_BUFFER_CPP, arg->buff_cpp >> 8) |
+ FIELD_PREP(NSP_BUFFER_ADDRESS, arg->buff_addr));
if (err < 0)
return err;
err = nfp_cpp_writeq(cpp, nsp_cpp, nsp_command,
- FIELD_PREP(NSP_COMMAND_OPTION, option) |
- FIELD_PREP(NSP_COMMAND_CODE, code) |
+ FIELD_PREP(NSP_COMMAND_OPTION, arg->option) |
+ FIELD_PREP(NSP_COMMAND_CODE, arg->code) |
FIELD_PREP(NSP_COMMAND_START, 1));
if (err < 0)
return err;
@@ -351,16 +357,16 @@ __nfp_nsp_command(struct nfp_nsp *state, u16 code, u32 option, u32 buff_cpp,
NSP_COMMAND_START, 0, NFP_NSP_TIMEOUT_DEFAULT);
if (err) {
nfp_err(cpp, "Error %d waiting for code 0x%04x to start\n",
- err, code);
+ err, arg->code);
return err;
}
/* Wait for NSP_STATUS_BUSY to go to 0 */
err = nfp_nsp_wait_reg(cpp, &reg, nsp_cpp, nsp_status, NSP_STATUS_BUSY,
- 0, timeout_sec);
+ 0, arg->timeout_sec ?: NFP_NSP_TIMEOUT_DEFAULT);
if (err) {
nfp_err(cpp, "Error %d waiting for code 0x%04x to complete\n",
- err, code);
+ err, arg->code);
return err;
}
@@ -372,26 +378,28 @@ __nfp_nsp_command(struct nfp_nsp *state, u16 code, u32 option, u32 buff_cpp,
err = FIELD_GET(NSP_STATUS_RESULT, reg);
if (err) {
nfp_warn(cpp, "Result (error) code set: %d (%d) command: %d\n",
- -err, (int)ret_val, code);
- nfp_nsp_print_extended_error(state, ret_val);
+ -err, (int)ret_val, arg->code);
+ if (arg->error_cb)
+ arg->error_cb(state, ret_val);
+ else
+ nfp_nsp_print_extended_error(state, ret_val);
return -err;
}
return ret_val;
}
-static int
-nfp_nsp_command(struct nfp_nsp *state, u16 code, u32 option, u32 buff_cpp,
- u64 buff_addr)
+static int nfp_nsp_command(struct nfp_nsp *state, u16 code)
{
- return __nfp_nsp_command(state, code, option, buff_cpp, buff_addr,
- NFP_NSP_TIMEOUT_DEFAULT);
+ const struct nfp_nsp_command_arg arg = {
+ .code = code,
+ };
+
+ return __nfp_nsp_command(state, &arg);
}
static int
-__nfp_nsp_command_buf(struct nfp_nsp *nsp, u16 code, u32 option,
- const void *in_buf, unsigned int in_size, void *out_buf,
- unsigned int out_size, u32 timeout_sec)
+nfp_nsp_command_buf(struct nfp_nsp *nsp, struct nfp_nsp_command_buf_arg *arg)
{
struct nfp_cpp *cpp = nsp->cpp;
unsigned int max_size;
@@ -401,7 +409,7 @@ __nfp_nsp_command_buf(struct nfp_nsp *nsp, u16 code, u32 option,
if (nsp->ver.minor < 13) {
nfp_err(cpp, "NSP: Code 0x%04x with buffer not supported (ABI %hu.%hu)\n",
- code, nsp->ver.major, nsp->ver.minor);
+ arg->arg.code, nsp->ver.major, nsp->ver.minor);
return -EOPNOTSUPP;
}
@@ -412,10 +420,11 @@ __nfp_nsp_command_buf(struct nfp_nsp *nsp, u16 code, u32 option,
if (err < 0)
return err;
- max_size = max(in_size, out_size);
+ max_size = max(arg->in_size, arg->out_size);
if (FIELD_GET(NSP_DFLT_BUFFER_SIZE_MB, reg) * SZ_1M < max_size) {
nfp_err(cpp, "NSP: default buffer too small for command 0x%04x (%llu < %u)\n",
- code, FIELD_GET(NSP_DFLT_BUFFER_SIZE_MB, reg) * SZ_1M,
+ arg->arg.code,
+ FIELD_GET(NSP_DFLT_BUFFER_SIZE_MB, reg) * SZ_1M,
max_size);
return -EINVAL;
}
@@ -430,27 +439,30 @@ __nfp_nsp_command_buf(struct nfp_nsp *nsp, u16 code, u32 option,
cpp_id = FIELD_GET(NSP_DFLT_BUFFER_CPP, reg) << 8;
cpp_buf = FIELD_GET(NSP_DFLT_BUFFER_ADDRESS, reg);
- if (in_buf && in_size) {
- err = nfp_cpp_write(cpp, cpp_id, cpp_buf, in_buf, in_size);
+ if (arg->in_buf && arg->in_size) {
+ err = nfp_cpp_write(cpp, cpp_id, cpp_buf,
+ arg->in_buf, arg->in_size);
if (err < 0)
return err;
}
/* Zero out remaining part of the buffer */
- if (out_buf && out_size && out_size > in_size) {
- memset(out_buf, 0, out_size - in_size);
- err = nfp_cpp_write(cpp, cpp_id, cpp_buf + in_size,
- out_buf, out_size - in_size);
+ if (arg->out_buf && arg->out_size && arg->out_size > arg->in_size) {
+ memset(arg->out_buf, 0, arg->out_size - arg->in_size);
+ err = nfp_cpp_write(cpp, cpp_id, cpp_buf + arg->in_size,
+ arg->out_buf, arg->out_size - arg->in_size);
if (err < 0)
return err;
}
- ret = __nfp_nsp_command(nsp, code, option, cpp_id, cpp_buf,
- timeout_sec);
+ arg->arg.buff_cpp = cpp_id;
+ arg->arg.buff_addr = cpp_buf;
+ ret = __nfp_nsp_command(nsp, &arg->arg);
if (ret < 0)
return ret;
- if (out_buf && out_size) {
- err = nfp_cpp_read(cpp, cpp_id, cpp_buf, out_buf, out_size);
+ if (arg->out_buf && arg->out_size) {
+ err = nfp_cpp_read(cpp, cpp_id, cpp_buf,
+ arg->out_buf, arg->out_size);
if (err < 0)
return err;
}
@@ -458,16 +470,6 @@ __nfp_nsp_command_buf(struct nfp_nsp *nsp, u16 code, u32 option,
return ret;
}
-static int
-nfp_nsp_command_buf(struct nfp_nsp *nsp, u16 code, u32 option,
- const void *in_buf, unsigned int in_size, void *out_buf,
- unsigned int out_size)
-{
- return __nfp_nsp_command_buf(nsp, code, option, in_buf, in_size,
- out_buf, out_size,
- NFP_NSP_TIMEOUT_DEFAULT);
-}
-
int nfp_nsp_wait(struct nfp_nsp *state)
{
const unsigned long wait_until = jiffies + NFP_NSP_TIMEOUT_BOOT * HZ;
@@ -479,7 +481,7 @@ int nfp_nsp_wait(struct nfp_nsp *state)
for (;;) {
const unsigned long start_time = jiffies;
- err = nfp_nsp_command(state, SPCODE_NOOP, 0, 0, 0);
+ err = nfp_nsp_command(state, SPCODE_NOOP);
if (err != -EAGAIN)
break;
@@ -501,53 +503,211 @@ int nfp_nsp_wait(struct nfp_nsp *state)
int nfp_nsp_device_soft_reset(struct nfp_nsp *state)
{
- return nfp_nsp_command(state, SPCODE_SOFT_RESET, 0, 0, 0);
+ return nfp_nsp_command(state, SPCODE_SOFT_RESET);
}
int nfp_nsp_mac_reinit(struct nfp_nsp *state)
{
- return nfp_nsp_command(state, SPCODE_MAC_INIT, 0, 0, 0);
+ return nfp_nsp_command(state, SPCODE_MAC_INIT);
+}
+
+static void nfp_nsp_load_fw_extended_msg(struct nfp_nsp *state, u32 ret_val)
+{
+ static const char * const major_msg[] = {
+ /* 0 */ "Firmware from driver loaded",
+ /* 1 */ "Firmware from flash loaded",
+ /* 2 */ "Firmware loading failure",
+ };
+ static const char * const minor_msg[] = {
+ /* 0 */ "",
+ /* 1 */ "no named partition on flash",
+ /* 2 */ "error reading from flash",
+ /* 3 */ "can not deflate",
+ /* 4 */ "not a trusted file",
+ /* 5 */ "can not parse FW file",
+ /* 6 */ "MIP not found in FW file",
+ /* 7 */ "null firmware name in MIP",
+ /* 8 */ "FW version none",
+ /* 9 */ "FW build number none",
+ /* 10 */ "no FW selection policy HWInfo key found",
+ /* 11 */ "static FW selection policy",
+ /* 12 */ "FW version has precedence",
+ /* 13 */ "different FW application load requested",
+ /* 14 */ "development build",
+ };
+ unsigned int major, minor;
+ const char *level;
+
+ major = FIELD_GET(NFP_FW_LOAD_RET_MAJOR, ret_val);
+ minor = FIELD_GET(NFP_FW_LOAD_RET_MINOR, ret_val);
+
+ if (!nfp_nsp_has_stored_fw_load(state))
+ return;
+
+ /* Lower the message level in legacy case */
+ if (major == 0 && (minor == 0 || minor == 10))
+ level = KERN_DEBUG;
+ else if (major == 2)
+ level = KERN_ERR;
+ else
+ level = KERN_INFO;
+
+ if (major >= ARRAY_SIZE(major_msg))
+ nfp_printk(level, state->cpp, "FW loading status: %x\n",
+ ret_val);
+ else if (minor >= ARRAY_SIZE(minor_msg))
+ nfp_printk(level, state->cpp, "%s, reason code: %d\n",
+ major_msg[major], minor);
+ else
+ nfp_printk(level, state->cpp, "%s%c %s\n",
+ major_msg[major], minor ? ',' : '.',
+ minor_msg[minor]);
}
int nfp_nsp_load_fw(struct nfp_nsp *state, const struct firmware *fw)
{
- return nfp_nsp_command_buf(state, SPCODE_FW_LOAD, fw->size, fw->data,
- fw->size, NULL, 0);
+ struct nfp_nsp_command_buf_arg load_fw = {
+ {
+ .code = SPCODE_FW_LOAD,
+ .option = fw->size,
+ .error_cb = nfp_nsp_load_fw_extended_msg,
+ },
+ .in_buf = fw->data,
+ .in_size = fw->size,
+ };
+ int ret;
+
+ ret = nfp_nsp_command_buf(state, &load_fw);
+ if (ret < 0)
+ return ret;
+
+ nfp_nsp_load_fw_extended_msg(state, ret);
+ return 0;
}
int nfp_nsp_write_flash(struct nfp_nsp *state, const struct firmware *fw)
{
- /* The flash time is specified to take a maximum of 70s so we add an
- * additional factor to this spec time.
- */
- u32 timeout_sec = 2.5 * 70;
-
- return __nfp_nsp_command_buf(state, SPCODE_NSP_WRITE_FLASH, fw->size,
- fw->data, fw->size, NULL, 0, timeout_sec);
+ struct nfp_nsp_command_buf_arg write_flash = {
+ {
+ .code = SPCODE_NSP_WRITE_FLASH,
+ .option = fw->size,
+ /* The flash time is specified to take a maximum of 70s
+ * so we add an additional factor to this spec time.
+ */
+ .timeout_sec = 2.5 * 70,
+ },
+ .in_buf = fw->data,
+ .in_size = fw->size,
+ };
+
+ return nfp_nsp_command_buf(state, &write_flash);
}
int nfp_nsp_read_eth_table(struct nfp_nsp *state, void *buf, unsigned int size)
{
- return nfp_nsp_command_buf(state, SPCODE_ETH_RESCAN, size, NULL, 0,
- buf, size);
+ struct nfp_nsp_command_buf_arg eth_rescan = {
+ {
+ .code = SPCODE_ETH_RESCAN,
+ .option = size,
+ },
+ .out_buf = buf,
+ .out_size = size,
+ };
+
+ return nfp_nsp_command_buf(state, &eth_rescan);
}
int nfp_nsp_write_eth_table(struct nfp_nsp *state,
const void *buf, unsigned int size)
{
- return nfp_nsp_command_buf(state, SPCODE_ETH_CONTROL, size, buf, size,
- NULL, 0);
+ struct nfp_nsp_command_buf_arg eth_ctrl = {
+ {
+ .code = SPCODE_ETH_CONTROL,
+ .option = size,
+ },
+ .in_buf = buf,
+ .in_size = size,
+ };
+
+ return nfp_nsp_command_buf(state, &eth_ctrl);
}
int nfp_nsp_read_identify(struct nfp_nsp *state, void *buf, unsigned int size)
{
- return nfp_nsp_command_buf(state, SPCODE_NSP_IDENTIFY, size, NULL, 0,
- buf, size);
+ struct nfp_nsp_command_buf_arg identify = {
+ {
+ .code = SPCODE_NSP_IDENTIFY,
+ .option = size,
+ },
+ .out_buf = buf,
+ .out_size = size,
+ };
+
+ return nfp_nsp_command_buf(state, &identify);
}
int nfp_nsp_read_sensors(struct nfp_nsp *state, unsigned int sensor_mask,
void *buf, unsigned int size)
{
- return nfp_nsp_command_buf(state, SPCODE_NSP_SENSORS, sensor_mask,
- NULL, 0, buf, size);
+ struct nfp_nsp_command_buf_arg sensors = {
+ {
+ .code = SPCODE_NSP_SENSORS,
+ .option = sensor_mask,
+ },
+ .out_buf = buf,
+ .out_size = size,
+ };
+
+ return nfp_nsp_command_buf(state, &sensors);
+}
+
+int nfp_nsp_load_stored_fw(struct nfp_nsp *state)
+{
+ const struct nfp_nsp_command_arg arg = {
+ .code = SPCODE_FW_STORED,
+ .error_cb = nfp_nsp_load_fw_extended_msg,
+ };
+ int ret;
+
+ ret = __nfp_nsp_command(state, &arg);
+ if (ret < 0)
+ return ret;
+
+ nfp_nsp_load_fw_extended_msg(state, ret);
+ return 0;
+}
+
+static int
+__nfp_nsp_hwinfo_lookup(struct nfp_nsp *state, void *buf, unsigned int size)
+{
+ struct nfp_nsp_command_buf_arg hwinfo_lookup = {
+ {
+ .code = SPCODE_HWINFO_LOOKUP,
+ .option = size,
+ },
+ .in_buf = buf,
+ .in_size = size,
+ .out_buf = buf,
+ .out_size = size,
+ };
+
+ return nfp_nsp_command_buf(state, &hwinfo_lookup);
+}
+
+int nfp_nsp_hwinfo_lookup(struct nfp_nsp *state, void *buf, unsigned int size)
+{
+ int err;
+
+ size = min_t(u32, size, NFP_HWINFO_LOOKUP_SIZE);
+
+ err = __nfp_nsp_hwinfo_lookup(state, buf, size);
+ if (err)
+ return err;
+
+ if (strnlen(buf, size) == size) {
+ nfp_err(state->cpp, "NSP HWinfo value not NULL-terminated\n");
+ return -EINVAL;
+ }
+
+ return 0;
}
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h
index f23d9e06f097..ff33ac54097a 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2015-2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/* Copyright (C) 2015-2018 Netronome Systems, Inc. */
#ifndef NSP_NSP_H
#define NSP_NSP_H 1
@@ -50,12 +20,24 @@ int nfp_nsp_device_soft_reset(struct nfp_nsp *state);
int nfp_nsp_load_fw(struct nfp_nsp *state, const struct firmware *fw);
int nfp_nsp_write_flash(struct nfp_nsp *state, const struct firmware *fw);
int nfp_nsp_mac_reinit(struct nfp_nsp *state);
+int nfp_nsp_load_stored_fw(struct nfp_nsp *state);
+int nfp_nsp_hwinfo_lookup(struct nfp_nsp *state, void *buf, unsigned int size);
static inline bool nfp_nsp_has_mac_reinit(struct nfp_nsp *state)
{
return nfp_nsp_get_abi_ver_minor(state) > 20;
}
+static inline bool nfp_nsp_has_stored_fw_load(struct nfp_nsp *state)
+{
+ return nfp_nsp_get_abi_ver_minor(state) > 23;
+}
+
+static inline bool nfp_nsp_has_hwinfo_lookup(struct nfp_nsp *state)
+{
+ return nfp_nsp_get_abi_ver_minor(state) > 24;
+}
+
enum nfp_eth_interface {
NFP_INTERFACE_NONE = 0,
NFP_INTERFACE_SFP = 1,
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_cmds.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_cmds.c
index 5d362f87af08..0997d127144f 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_cmds.c
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_cmds.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2017 Netronome Systems, Inc. */
#include <linux/kernel.h>
#include <linux/slab.h>
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c
index 7ca589660e4d..802c9224bb32 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2015-2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2015-2017 Netronome Systems, Inc. */
/* Authors: David Brunecz <david.brunecz@netronome.com>
* Jakub Kicinski <jakub.kicinski@netronome.com>
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c
index d32af598da90..ce7492a6a98f 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2015-2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2015-2018 Netronome Systems, Inc. */
/*
* nfp_resource.c
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c
index 9e34216578da..75f012444796 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2015-2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2015-2018 Netronome Systems, Inc. */
/*
* nfp_rtsym.c
@@ -39,6 +9,8 @@
* Espen Skoglund <espen.skoglund@netronome.com>
* Francois H. Theron <francois.theron@netronome.com>
*/
+
+#include <asm/unaligned.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -233,6 +205,229 @@ nfp_rtsym_lookup(struct nfp_rtsym_table *rtbl, const char *name)
return NULL;
}
+u64 nfp_rtsym_size(const struct nfp_rtsym *sym)
+{
+ switch (sym->type) {
+ case NFP_RTSYM_TYPE_NONE:
+ pr_err("rtsym '%s': type NONE\n", sym->name);
+ return 0;
+ default:
+ pr_warn("rtsym '%s': unknown type: %d\n", sym->name, sym->type);
+ /* fall through */
+ case NFP_RTSYM_TYPE_OBJECT:
+ case NFP_RTSYM_TYPE_FUNCTION:
+ return sym->size;
+ case NFP_RTSYM_TYPE_ABS:
+ return sizeof(u64);
+ }
+}
+
+static int
+nfp_rtsym_to_dest(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
+ u8 action, u8 token, u64 off, u32 *cpp_id, u64 *addr)
+{
+ if (sym->type != NFP_RTSYM_TYPE_OBJECT) {
+ nfp_err(cpp, "rtsym '%s': direct access to non-object rtsym\n",
+ sym->name);
+ return -EINVAL;
+ }
+
+ *addr = sym->addr + off;
+
+ if (sym->target == NFP_RTSYM_TARGET_EMU_CACHE) {
+ int locality_off = nfp_cpp_mu_locality_lsb(cpp);
+
+ *addr &= ~(NFP_MU_ADDR_ACCESS_TYPE_MASK << locality_off);
+ *addr |= NFP_MU_ADDR_ACCESS_TYPE_DIRECT << locality_off;
+
+ *cpp_id = NFP_CPP_ISLAND_ID(NFP_CPP_TARGET_MU, action, token,
+ sym->domain);
+ } else if (sym->target < 0) {
+ nfp_err(cpp, "rtsym '%s': unhandled target encoding: %d\n",
+ sym->name, sym->target);
+ return -EINVAL;
+ } else {
+ *cpp_id = NFP_CPP_ISLAND_ID(sym->target, action, token,
+ sym->domain);
+ }
+
+ return 0;
+}
+
+int __nfp_rtsym_read(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
+ u8 action, u8 token, u64 off, void *buf, size_t len)
+{
+ u64 sym_size = nfp_rtsym_size(sym);
+ u32 cpp_id;
+ u64 addr;
+ int err;
+
+ if (off > sym_size) {
+ nfp_err(cpp, "rtsym '%s': read out of bounds: off: %lld + len: %zd > size: %lld\n",
+ sym->name, off, len, sym_size);
+ return -ENXIO;
+ }
+ len = min_t(size_t, len, sym_size - off);
+
+ if (sym->type == NFP_RTSYM_TYPE_ABS) {
+ u8 tmp[8];
+
+ put_unaligned_le64(sym->addr, tmp);
+ memcpy(buf, &tmp[off], len);
+
+ return len;
+ }
+
+ err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr);
+ if (err)
+ return err;
+
+ return nfp_cpp_read(cpp, cpp_id, addr, buf, len);
+}
+
+int nfp_rtsym_read(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
+ void *buf, size_t len)
+{
+ return __nfp_rtsym_read(cpp, sym, NFP_CPP_ACTION_RW, 0, off, buf, len);
+}
+
+int __nfp_rtsym_readl(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
+ u8 action, u8 token, u64 off, u32 *value)
+{
+ u32 cpp_id;
+ u64 addr;
+ int err;
+
+ if (off + 4 > nfp_rtsym_size(sym)) {
+ nfp_err(cpp, "rtsym '%s': readl out of bounds: off: %lld + 4 > size: %lld\n",
+ sym->name, off, nfp_rtsym_size(sym));
+ return -ENXIO;
+ }
+
+ err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr);
+ if (err)
+ return err;
+
+ return nfp_cpp_readl(cpp, cpp_id, addr, value);
+}
+
+int nfp_rtsym_readl(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
+ u32 *value)
+{
+ return __nfp_rtsym_readl(cpp, sym, NFP_CPP_ACTION_RW, 0, off, value);
+}
+
+int __nfp_rtsym_readq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
+ u8 action, u8 token, u64 off, u64 *value)
+{
+ u32 cpp_id;
+ u64 addr;
+ int err;
+
+ if (off + 8 > nfp_rtsym_size(sym)) {
+ nfp_err(cpp, "rtsym '%s': readq out of bounds: off: %lld + 8 > size: %lld\n",
+ sym->name, off, nfp_rtsym_size(sym));
+ return -ENXIO;
+ }
+
+ if (sym->type == NFP_RTSYM_TYPE_ABS) {
+ *value = sym->addr;
+ return 0;
+ }
+
+ err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr);
+ if (err)
+ return err;
+
+ return nfp_cpp_readq(cpp, cpp_id, addr, value);
+}
+
+int nfp_rtsym_readq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
+ u64 *value)
+{
+ return __nfp_rtsym_readq(cpp, sym, NFP_CPP_ACTION_RW, 0, off, value);
+}
+
+int __nfp_rtsym_write(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
+ u8 action, u8 token, u64 off, void *buf, size_t len)
+{
+ u64 sym_size = nfp_rtsym_size(sym);
+ u32 cpp_id;
+ u64 addr;
+ int err;
+
+ if (off > sym_size) {
+ nfp_err(cpp, "rtsym '%s': write out of bounds: off: %lld + len: %zd > size: %lld\n",
+ sym->name, off, len, sym_size);
+ return -ENXIO;
+ }
+ len = min_t(size_t, len, sym_size - off);
+
+ err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr);
+ if (err)
+ return err;
+
+ return nfp_cpp_write(cpp, cpp_id, addr, buf, len);
+}
+
+int nfp_rtsym_write(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
+ void *buf, size_t len)
+{
+ return __nfp_rtsym_write(cpp, sym, NFP_CPP_ACTION_RW, 0, off, buf, len);
+}
+
+int __nfp_rtsym_writel(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
+ u8 action, u8 token, u64 off, u32 value)
+{
+ u32 cpp_id;
+ u64 addr;
+ int err;
+
+ if (off + 4 > nfp_rtsym_size(sym)) {
+ nfp_err(cpp, "rtsym '%s': writel out of bounds: off: %lld + 4 > size: %lld\n",
+ sym->name, off, nfp_rtsym_size(sym));
+ return -ENXIO;
+ }
+
+ err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr);
+ if (err)
+ return err;
+
+ return nfp_cpp_writel(cpp, cpp_id, addr, value);
+}
+
+int nfp_rtsym_writel(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
+ u32 value)
+{
+ return __nfp_rtsym_writel(cpp, sym, NFP_CPP_ACTION_RW, 0, off, value);
+}
+
+int __nfp_rtsym_writeq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
+ u8 action, u8 token, u64 off, u64 value)
+{
+ u32 cpp_id;
+ u64 addr;
+ int err;
+
+ if (off + 8 > nfp_rtsym_size(sym)) {
+ nfp_err(cpp, "rtsym '%s': writeq out of bounds: off: %lld + 8 > size: %lld\n",
+ sym->name, off, nfp_rtsym_size(sym));
+ return -ENXIO;
+ }
+
+ err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr);
+ if (err)
+ return err;
+
+ return nfp_cpp_writeq(cpp, cpp_id, addr, value);
+}
+
+int nfp_rtsym_writeq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
+ u64 value)
+{
+ return __nfp_rtsym_writeq(cpp, sym, NFP_CPP_ACTION_RW, 0, off, value);
+}
+
/**
* nfp_rtsym_read_le() - Read a simple unsigned scalar value from symbol
* @rtbl: NFP RTsym table
@@ -249,7 +444,7 @@ u64 nfp_rtsym_read_le(struct nfp_rtsym_table *rtbl, const char *name,
int *error)
{
const struct nfp_rtsym *sym;
- u32 val32, id;
+ u32 val32;
u64 val;
int err;
@@ -259,20 +454,18 @@ u64 nfp_rtsym_read_le(struct nfp_rtsym_table *rtbl, const char *name,
goto exit;
}
- id = NFP_CPP_ISLAND_ID(sym->target, NFP_CPP_ACTION_RW, 0, sym->domain);
-
- switch (sym->size) {
+ switch (nfp_rtsym_size(sym)) {
case 4:
- err = nfp_cpp_readl(rtbl->cpp, id, sym->addr, &val32);
+ err = nfp_rtsym_readl(rtbl->cpp, sym, 0, &val32);
val = val32;
break;
case 8:
- err = nfp_cpp_readq(rtbl->cpp, id, sym->addr, &val);
+ err = nfp_rtsym_readq(rtbl->cpp, sym, 0, &val);
break;
default:
nfp_err(rtbl->cpp,
- "rtsym '%s' unsupported or non-scalar size: %lld\n",
- name, sym->size);
+ "rtsym '%s': unsupported or non-scalar size: %lld\n",
+ name, nfp_rtsym_size(sym));
err = -EINVAL;
break;
}
@@ -303,25 +496,22 @@ int nfp_rtsym_write_le(struct nfp_rtsym_table *rtbl, const char *name,
{
const struct nfp_rtsym *sym;
int err;
- u32 id;
sym = nfp_rtsym_lookup(rtbl, name);
if (!sym)
return -ENOENT;
- id = NFP_CPP_ISLAND_ID(sym->target, NFP_CPP_ACTION_RW, 0, sym->domain);
-
- switch (sym->size) {
+ switch (nfp_rtsym_size(sym)) {
case 4:
- err = nfp_cpp_writel(rtbl->cpp, id, sym->addr, value);
+ err = nfp_rtsym_writel(rtbl->cpp, sym, 0, value);
break;
case 8:
- err = nfp_cpp_writeq(rtbl->cpp, id, sym->addr, value);
+ err = nfp_rtsym_writeq(rtbl->cpp, sym, 0, value);
break;
default:
nfp_err(rtbl->cpp,
- "rtsym '%s' unsupported or non-scalar size: %lld\n",
- name, sym->size);
+ "rtsym '%s': unsupported or non-scalar size: %lld\n",
+ name, nfp_rtsym_size(sym));
err = -EINVAL;
break;
}
@@ -335,20 +525,29 @@ nfp_rtsym_map(struct nfp_rtsym_table *rtbl, const char *name, const char *id,
{
const struct nfp_rtsym *sym;
u8 __iomem *mem;
+ u32 cpp_id;
+ u64 addr;
+ int err;
sym = nfp_rtsym_lookup(rtbl, name);
if (!sym)
return (u8 __iomem *)ERR_PTR(-ENOENT);
+ err = nfp_rtsym_to_dest(rtbl->cpp, sym, NFP_CPP_ACTION_RW, 0, 0,
+ &cpp_id, &addr);
+ if (err) {
+ nfp_err(rtbl->cpp, "rtsym '%s': mapping failed\n", name);
+ return (u8 __iomem *)ERR_PTR(err);
+ }
+
if (sym->size < min_size) {
- nfp_err(rtbl->cpp, "Symbol %s too small\n", name);
+ nfp_err(rtbl->cpp, "rtsym '%s': too small\n", name);
return (u8 __iomem *)ERR_PTR(-EINVAL);
}
- mem = nfp_cpp_map_area(rtbl->cpp, id, sym->domain, sym->target,
- sym->addr, sym->size, area);
+ mem = nfp_cpp_map_area(rtbl->cpp, id, cpp_id, addr, sym->size, area);
if (IS_ERR(mem)) {
- nfp_err(rtbl->cpp, "Failed to map symbol %s: %ld\n",
+ nfp_err(rtbl->cpp, "rtysm '%s': failed to map: %ld\n",
name, PTR_ERR(mem));
return mem;
}
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c
index 4ea1e585d945..79470f198a62 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2015-2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2015-2018 Netronome Systems, Inc. */
/*
* nfp_target.c
@@ -39,7 +9,11 @@
* Francois H. Theron <francois.theron@netronome.com>
*/
+#define pr_fmt(fmt) "NFP target: " fmt
+
#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/printk.h>
#include "nfp_cpp.h"
@@ -733,8 +707,10 @@ int nfp_target_cpp(u32 cpp_island_id, u64 cpp_island_address,
u32 imb;
int err;
- if (target < 0 || target >= 16)
+ if (target < 0 || target >= 16) {
+ pr_err("Invalid CPP target: %d\n", target);
return -EINVAL;
+ }
if (island == 0) {
/* Already translated */
@@ -753,8 +729,10 @@ int nfp_target_cpp(u32 cpp_island_id, u64 cpp_island_address,
err = nfp_cppat_addr_encode(cpp_target_address, island, target,
((imb >> 13) & 7), ((imb >> 12) & 1),
((imb >> 6) & 0x3f), ((imb >> 0) & 0x3f));
- if (err)
+ if (err) {
+ pr_err("Can't encode CPP address: %d\n", err);
return err;
+ }
*cpp_target_id = NFP_CPP_ID(target,
NFP_CPP_ID_ACTION_of(cpp_island_id),
diff --git a/drivers/net/ethernet/netronome/nfp/nic/main.c b/drivers/net/ethernet/netronome/nfp/nic/main.c
index d5b587fccaa3..aea8579206ee 100644
--- a/drivers/net/ethernet/netronome/nfp/nic/main.c
+++ b/drivers/net/ethernet/netronome/nfp/nic/main.c
@@ -1,35 +1,5 @@
-/*
- * Copyright (C) 2017 Netronome Systems, Inc.
- *
- * This software is dual licensed under the GNU General License Version 2,
- * June 1991 as shown in the file COPYING in the top-level directory of this
- * source tree or the BSD 2-Clause License provided below. You have the
- * option to license this software under the complete terms of either license.
- *
- * The BSD 2-Clause License:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2017 Netronome Systems, Inc. */
#include "../nfpcore/nfp_cpp.h"
#include "../nfpcore/nfp_nsp.h"
diff --git a/drivers/net/ethernet/ni/Kconfig b/drivers/net/ethernet/ni/Kconfig
index aa41e5f6e437..c73978474c4b 100644
--- a/drivers/net/ethernet/ni/Kconfig
+++ b/drivers/net/ethernet/ni/Kconfig
@@ -18,8 +18,9 @@ if NET_VENDOR_NI
config NI_XGE_MANAGEMENT_ENET
tristate "National Instruments XGE management enet support"
- depends on ARCH_ZYNQ
+ depends on HAS_IOMEM && HAS_DMA
select PHYLIB
+ select OF_MDIO if OF
help
Simple LAN device for debug or management purposes. Can
support either 10G or 1G PHYs via SFP+ ports.
diff --git a/drivers/net/ethernet/ni/nixge.c b/drivers/net/ethernet/ni/nixge.c
index 76efed058f33..0611f2335b4a 100644
--- a/drivers/net/ethernet/ni/nixge.c
+++ b/drivers/net/ethernet/ni/nixge.c
@@ -106,10 +106,10 @@
(NIXGE_JUMBO_MTU + NIXGE_HDR_SIZE + NIXGE_TRL_SIZE)
struct nixge_hw_dma_bd {
- u32 next;
- u32 reserved1;
- u32 phys;
- u32 reserved2;
+ u32 next_lo;
+ u32 next_hi;
+ u32 phys_lo;
+ u32 phys_hi;
u32 reserved3;
u32 reserved4;
u32 cntrl;
@@ -119,11 +119,39 @@ struct nixge_hw_dma_bd {
u32 app2;
u32 app3;
u32 app4;
- u32 sw_id_offset;
- u32 reserved5;
+ u32 sw_id_offset_lo;
+ u32 sw_id_offset_hi;
u32 reserved6;
};
+#ifdef CONFIG_PHYS_ADDR_T_64BIT
+#define nixge_hw_dma_bd_set_addr(bd, field, addr) \
+ do { \
+ (bd)->field##_lo = lower_32_bits((addr)); \
+ (bd)->field##_hi = upper_32_bits((addr)); \
+ } while (0)
+#else
+#define nixge_hw_dma_bd_set_addr(bd, field, addr) \
+ ((bd)->field##_lo = lower_32_bits((addr)))
+#endif
+
+#define nixge_hw_dma_bd_set_phys(bd, addr) \
+ nixge_hw_dma_bd_set_addr((bd), phys, (addr))
+
+#define nixge_hw_dma_bd_set_next(bd, addr) \
+ nixge_hw_dma_bd_set_addr((bd), next, (addr))
+
+#define nixge_hw_dma_bd_set_offset(bd, addr) \
+ nixge_hw_dma_bd_set_addr((bd), sw_id_offset, (addr))
+
+#ifdef CONFIG_PHYS_ADDR_T_64BIT
+#define nixge_hw_dma_bd_get_addr(bd, field) \
+ (dma_addr_t)((((u64)(bd)->field##_hi) << 32) | ((bd)->field##_lo))
+#else
+#define nixge_hw_dma_bd_get_addr(bd, field) \
+ (dma_addr_t)((bd)->field##_lo)
+#endif
+
struct nixge_tx_skb {
struct sk_buff *skb;
dma_addr_t mapping;
@@ -176,6 +204,15 @@ static void nixge_dma_write_reg(struct nixge_priv *priv, off_t offset, u32 val)
writel(val, priv->dma_regs + offset);
}
+static void nixge_dma_write_desc_reg(struct nixge_priv *priv, off_t offset,
+ dma_addr_t addr)
+{
+ writel(lower_32_bits(addr), priv->dma_regs + offset);
+#ifdef CONFIG_PHYS_ADDR_T_64BIT
+ writel(upper_32_bits(addr), priv->dma_regs + offset + 4);
+#endif
+}
+
static u32 nixge_dma_read_reg(const struct nixge_priv *priv, off_t offset)
{
return readl(priv->dma_regs + offset);
@@ -202,13 +239,22 @@ static u32 nixge_ctrl_read_reg(struct nixge_priv *priv, off_t offset)
static void nixge_hw_dma_bd_release(struct net_device *ndev)
{
struct nixge_priv *priv = netdev_priv(ndev);
+ dma_addr_t phys_addr;
+ struct sk_buff *skb;
int i;
for (i = 0; i < RX_BD_NUM; i++) {
- dma_unmap_single(ndev->dev.parent, priv->rx_bd_v[i].phys,
- NIXGE_MAX_JUMBO_FRAME_SIZE, DMA_FROM_DEVICE);
- dev_kfree_skb((struct sk_buff *)
- (priv->rx_bd_v[i].sw_id_offset));
+ phys_addr = nixge_hw_dma_bd_get_addr(&priv->rx_bd_v[i],
+ phys);
+
+ dma_unmap_single(ndev->dev.parent, phys_addr,
+ NIXGE_MAX_JUMBO_FRAME_SIZE,
+ DMA_FROM_DEVICE);
+
+ skb = (struct sk_buff *)(uintptr_t)
+ nixge_hw_dma_bd_get_addr(&priv->rx_bd_v[i],
+ sw_id_offset);
+ dev_kfree_skb(skb);
}
if (priv->rx_bd_v)
@@ -231,6 +277,7 @@ static int nixge_hw_dma_bd_init(struct net_device *ndev)
{
struct nixge_priv *priv = netdev_priv(ndev);
struct sk_buff *skb;
+ dma_addr_t phys;
u32 cr;
int i;
@@ -259,27 +306,30 @@ static int nixge_hw_dma_bd_init(struct net_device *ndev)
goto out;
for (i = 0; i < TX_BD_NUM; i++) {
- priv->tx_bd_v[i].next = priv->tx_bd_p +
- sizeof(*priv->tx_bd_v) *
- ((i + 1) % TX_BD_NUM);
+ nixge_hw_dma_bd_set_next(&priv->tx_bd_v[i],
+ priv->tx_bd_p +
+ sizeof(*priv->tx_bd_v) *
+ ((i + 1) % TX_BD_NUM));
}
for (i = 0; i < RX_BD_NUM; i++) {
- priv->rx_bd_v[i].next = priv->rx_bd_p +
- sizeof(*priv->rx_bd_v) *
- ((i + 1) % RX_BD_NUM);
+ nixge_hw_dma_bd_set_next(&priv->rx_bd_v[i],
+ priv->rx_bd_p
+ + sizeof(*priv->rx_bd_v) *
+ ((i + 1) % RX_BD_NUM));
skb = netdev_alloc_skb_ip_align(ndev,
NIXGE_MAX_JUMBO_FRAME_SIZE);
if (!skb)
goto out;
- priv->rx_bd_v[i].sw_id_offset = (u32)skb;
- priv->rx_bd_v[i].phys =
- dma_map_single(ndev->dev.parent,
- skb->data,
- NIXGE_MAX_JUMBO_FRAME_SIZE,
- DMA_FROM_DEVICE);
+ nixge_hw_dma_bd_set_offset(&priv->rx_bd_v[i], (uintptr_t)skb);
+ phys = dma_map_single(ndev->dev.parent, skb->data,
+ NIXGE_MAX_JUMBO_FRAME_SIZE,
+ DMA_FROM_DEVICE);
+
+ nixge_hw_dma_bd_set_phys(&priv->rx_bd_v[i], phys);
+
priv->rx_bd_v[i].cntrl = NIXGE_MAX_JUMBO_FRAME_SIZE;
}
@@ -312,18 +362,18 @@ static int nixge_hw_dma_bd_init(struct net_device *ndev)
/* Populate the tail pointer and bring the Rx Axi DMA engine out of
* halted state. This will make the Rx side ready for reception.
*/
- nixge_dma_write_reg(priv, XAXIDMA_RX_CDESC_OFFSET, priv->rx_bd_p);
+ nixge_dma_write_desc_reg(priv, XAXIDMA_RX_CDESC_OFFSET, priv->rx_bd_p);
cr = nixge_dma_read_reg(priv, XAXIDMA_RX_CR_OFFSET);
nixge_dma_write_reg(priv, XAXIDMA_RX_CR_OFFSET,
cr | XAXIDMA_CR_RUNSTOP_MASK);
- nixge_dma_write_reg(priv, XAXIDMA_RX_TDESC_OFFSET, priv->rx_bd_p +
+ nixge_dma_write_desc_reg(priv, XAXIDMA_RX_TDESC_OFFSET, priv->rx_bd_p +
(sizeof(*priv->rx_bd_v) * (RX_BD_NUM - 1)));
/* Write to the RS (Run-stop) bit in the Tx channel control register.
* Tx channel is now ready to run. But only after we write to the
* tail pointer register that the Tx channel will start transmitting.
*/
- nixge_dma_write_reg(priv, XAXIDMA_TX_CDESC_OFFSET, priv->tx_bd_p);
+ nixge_dma_write_desc_reg(priv, XAXIDMA_TX_CDESC_OFFSET, priv->tx_bd_p);
cr = nixge_dma_read_reg(priv, XAXIDMA_TX_CR_OFFSET);
nixge_dma_write_reg(priv, XAXIDMA_TX_CR_OFFSET,
cr | XAXIDMA_CR_RUNSTOP_MASK);
@@ -451,7 +501,7 @@ static int nixge_start_xmit(struct sk_buff *skb, struct net_device *ndev)
struct nixge_priv *priv = netdev_priv(ndev);
struct nixge_hw_dma_bd *cur_p;
struct nixge_tx_skb *tx_skb;
- dma_addr_t tail_p;
+ dma_addr_t tail_p, cur_phys;
skb_frag_t *frag;
u32 num_frag;
u32 ii;
@@ -466,15 +516,16 @@ static int nixge_start_xmit(struct sk_buff *skb, struct net_device *ndev)
return NETDEV_TX_OK;
}
- cur_p->phys = dma_map_single(ndev->dev.parent, skb->data,
- skb_headlen(skb), DMA_TO_DEVICE);
- if (dma_mapping_error(ndev->dev.parent, cur_p->phys))
+ cur_phys = dma_map_single(ndev->dev.parent, skb->data,
+ skb_headlen(skb), DMA_TO_DEVICE);
+ if (dma_mapping_error(ndev->dev.parent, cur_phys))
goto drop;
+ nixge_hw_dma_bd_set_phys(cur_p, cur_phys);
cur_p->cntrl = skb_headlen(skb) | XAXIDMA_BD_CTRL_TXSOF_MASK;
tx_skb->skb = NULL;
- tx_skb->mapping = cur_p->phys;
+ tx_skb->mapping = cur_phys;
tx_skb->size = skb_headlen(skb);
tx_skb->mapped_as_page = false;
@@ -485,16 +536,17 @@ static int nixge_start_xmit(struct sk_buff *skb, struct net_device *ndev)
tx_skb = &priv->tx_skb[priv->tx_bd_tail];
frag = &skb_shinfo(skb)->frags[ii];
- cur_p->phys = skb_frag_dma_map(ndev->dev.parent, frag, 0,
- skb_frag_size(frag),
- DMA_TO_DEVICE);
- if (dma_mapping_error(ndev->dev.parent, cur_p->phys))
+ cur_phys = skb_frag_dma_map(ndev->dev.parent, frag, 0,
+ skb_frag_size(frag),
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(ndev->dev.parent, cur_phys))
goto frag_err;
+ nixge_hw_dma_bd_set_phys(cur_p, cur_phys);
cur_p->cntrl = skb_frag_size(frag);
tx_skb->skb = NULL;
- tx_skb->mapping = cur_p->phys;
+ tx_skb->mapping = cur_phys;
tx_skb->size = skb_frag_size(frag);
tx_skb->mapped_as_page = true;
}
@@ -506,7 +558,7 @@ static int nixge_start_xmit(struct sk_buff *skb, struct net_device *ndev)
tail_p = priv->tx_bd_p + sizeof(*priv->tx_bd_v) * priv->tx_bd_tail;
/* Start the transfer */
- nixge_dma_write_reg(priv, XAXIDMA_TX_TDESC_OFFSET, tail_p);
+ nixge_dma_write_desc_reg(priv, XAXIDMA_TX_TDESC_OFFSET, tail_p);
++priv->tx_bd_tail;
priv->tx_bd_tail %= TX_BD_NUM;
@@ -537,7 +589,7 @@ static int nixge_recv(struct net_device *ndev, int budget)
struct nixge_priv *priv = netdev_priv(ndev);
struct sk_buff *skb, *new_skb;
struct nixge_hw_dma_bd *cur_p;
- dma_addr_t tail_p = 0;
+ dma_addr_t tail_p = 0, cur_phys = 0;
u32 packets = 0;
u32 length = 0;
u32 size = 0;
@@ -549,13 +601,15 @@ static int nixge_recv(struct net_device *ndev, int budget)
tail_p = priv->rx_bd_p + sizeof(*priv->rx_bd_v) *
priv->rx_bd_ci;
- skb = (struct sk_buff *)(cur_p->sw_id_offset);
+ skb = (struct sk_buff *)(uintptr_t)
+ nixge_hw_dma_bd_get_addr(cur_p, sw_id_offset);
length = cur_p->status & XAXIDMA_BD_STS_ACTUAL_LEN_MASK;
if (length > NIXGE_MAX_JUMBO_FRAME_SIZE)
length = NIXGE_MAX_JUMBO_FRAME_SIZE;
- dma_unmap_single(ndev->dev.parent, cur_p->phys,
+ dma_unmap_single(ndev->dev.parent,
+ nixge_hw_dma_bd_get_addr(cur_p, phys),
NIXGE_MAX_JUMBO_FRAME_SIZE,
DMA_FROM_DEVICE);
@@ -579,16 +633,17 @@ static int nixge_recv(struct net_device *ndev, int budget)
if (!new_skb)
return packets;
- cur_p->phys = dma_map_single(ndev->dev.parent, new_skb->data,
- NIXGE_MAX_JUMBO_FRAME_SIZE,
- DMA_FROM_DEVICE);
- if (dma_mapping_error(ndev->dev.parent, cur_p->phys)) {
+ cur_phys = dma_map_single(ndev->dev.parent, new_skb->data,
+ NIXGE_MAX_JUMBO_FRAME_SIZE,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(ndev->dev.parent, cur_phys)) {
/* FIXME: bail out and clean up */
netdev_err(ndev, "Failed to map ...\n");
}
+ nixge_hw_dma_bd_set_phys(cur_p, cur_phys);
cur_p->cntrl = NIXGE_MAX_JUMBO_FRAME_SIZE;
cur_p->status = 0;
- cur_p->sw_id_offset = (u32)new_skb;
+ nixge_hw_dma_bd_set_offset(cur_p, (uintptr_t)new_skb);
++priv->rx_bd_ci;
priv->rx_bd_ci %= RX_BD_NUM;
@@ -599,7 +654,7 @@ static int nixge_recv(struct net_device *ndev, int budget)
ndev->stats.rx_bytes += size;
if (tail_p)
- nixge_dma_write_reg(priv, XAXIDMA_RX_TDESC_OFFSET, tail_p);
+ nixge_dma_write_desc_reg(priv, XAXIDMA_RX_TDESC_OFFSET, tail_p);
return packets;
}
@@ -637,6 +692,7 @@ static irqreturn_t nixge_tx_irq(int irq, void *_ndev)
struct nixge_priv *priv = netdev_priv(_ndev);
struct net_device *ndev = _ndev;
unsigned int status;
+ dma_addr_t phys;
u32 cr;
status = nixge_dma_read_reg(priv, XAXIDMA_TX_SR_OFFSET);
@@ -650,9 +706,11 @@ static irqreturn_t nixge_tx_irq(int irq, void *_ndev)
return IRQ_NONE;
}
if (status & XAXIDMA_IRQ_ERROR_MASK) {
+ phys = nixge_hw_dma_bd_get_addr(&priv->tx_bd_v[priv->tx_bd_ci],
+ phys);
+
netdev_err(ndev, "DMA Tx error 0x%x\n", status);
- netdev_err(ndev, "Current BD is at: 0x%x\n",
- (priv->tx_bd_v[priv->tx_bd_ci]).phys);
+ netdev_err(ndev, "Current BD is at: 0x%llx\n", (u64)phys);
cr = nixge_dma_read_reg(priv, XAXIDMA_TX_CR_OFFSET);
/* Disable coalesce, delay timer and error interrupts */
@@ -678,6 +736,7 @@ static irqreturn_t nixge_rx_irq(int irq, void *_ndev)
struct nixge_priv *priv = netdev_priv(_ndev);
struct net_device *ndev = _ndev;
unsigned int status;
+ dma_addr_t phys;
u32 cr;
status = nixge_dma_read_reg(priv, XAXIDMA_RX_SR_OFFSET);
@@ -697,9 +756,10 @@ static irqreturn_t nixge_rx_irq(int irq, void *_ndev)
return IRQ_NONE;
}
if (status & XAXIDMA_IRQ_ERROR_MASK) {
+ phys = nixge_hw_dma_bd_get_addr(&priv->rx_bd_v[priv->rx_bd_ci],
+ phys);
netdev_err(ndev, "DMA Rx error 0x%x\n", status);
- netdev_err(ndev, "Current BD is at: 0x%x\n",
- (priv->rx_bd_v[priv->rx_bd_ci]).phys);
+ netdev_err(ndev, "Current BD is at: 0x%llx\n", (u64)phys);
cr = nixge_dma_read_reg(priv, XAXIDMA_TX_CR_OFFSET);
/* Disable coalesce, delay timer and error interrupts */
@@ -735,10 +795,10 @@ static void nixge_dma_err_handler(unsigned long data)
tx_skb = &lp->tx_skb[i];
nixge_tx_skb_unmap(lp, tx_skb);
- cur_p->phys = 0;
+ nixge_hw_dma_bd_set_phys(cur_p, 0);
cur_p->cntrl = 0;
cur_p->status = 0;
- cur_p->sw_id_offset = 0;
+ nixge_hw_dma_bd_set_offset(cur_p, 0);
}
for (i = 0; i < RX_BD_NUM; i++) {
@@ -779,18 +839,18 @@ static void nixge_dma_err_handler(unsigned long data)
/* Populate the tail pointer and bring the Rx Axi DMA engine out of
* halted state. This will make the Rx side ready for reception.
*/
- nixge_dma_write_reg(lp, XAXIDMA_RX_CDESC_OFFSET, lp->rx_bd_p);
+ nixge_dma_write_desc_reg(lp, XAXIDMA_RX_CDESC_OFFSET, lp->rx_bd_p);
cr = nixge_dma_read_reg(lp, XAXIDMA_RX_CR_OFFSET);
nixge_dma_write_reg(lp, XAXIDMA_RX_CR_OFFSET,
cr | XAXIDMA_CR_RUNSTOP_MASK);
- nixge_dma_write_reg(lp, XAXIDMA_RX_TDESC_OFFSET, lp->rx_bd_p +
+ nixge_dma_write_desc_reg(lp, XAXIDMA_RX_TDESC_OFFSET, lp->rx_bd_p +
(sizeof(*lp->rx_bd_v) * (RX_BD_NUM - 1)));
/* Write to the RS (Run-stop) bit in the Tx channel control register.
* Tx channel is now ready to run. But only after we write to the
* tail pointer register that the Tx channel will start transmitting
*/
- nixge_dma_write_reg(lp, XAXIDMA_TX_CDESC_OFFSET, lp->tx_bd_p);
+ nixge_dma_write_desc_reg(lp, XAXIDMA_TX_CDESC_OFFSET, lp->tx_bd_p);
cr = nixge_dma_read_reg(lp, XAXIDMA_TX_CR_OFFSET);
nixge_dma_write_reg(lp, XAXIDMA_TX_CR_OFFSET,
cr | XAXIDMA_CR_RUNSTOP_MASK);
diff --git a/drivers/net/ethernet/nxp/lpc_eth.c b/drivers/net/ethernet/nxp/lpc_eth.c
index 08381ef8bdb4..25382f8fbb70 100644
--- a/drivers/net/ethernet/nxp/lpc_eth.c
+++ b/drivers/net/ethernet/nxp/lpc_eth.c
@@ -19,34 +19,18 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/crc32.h>
-#include <linux/platform_device.h>
-#include <linux/spinlock.h>
-#include <linux/ethtool.h>
-#include <linux/mii.h>
#include <linux/clk.h>
-#include <linux/workqueue.h>
-#include <linux/netdevice.h>
+#include <linux/crc32.h>
#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/phy.h>
-#include <linux/dma-mapping.h>
-#include <linux/of.h>
+#include <linux/module.h>
#include <linux/of_net.h>
-#include <linux/types.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
-#include <linux/io.h>
#include <mach/board.h>
-#include <mach/platform.h>
#include <mach/hardware.h>
+#include <mach/platform.h>
#define MODNAME "lpc-eth"
#define DRV_VERSION "1.00"
@@ -797,8 +781,7 @@ static int lpc_mii_probe(struct net_device *ndev)
return PTR_ERR(phydev);
}
- /* mask with MAC supported features */
- phydev->supported &= PHY_BASIC_FEATURES;
+ phy_set_max_speed(phydev, SPEED_100);
phydev->advertising = phydev->supported;
@@ -1258,18 +1241,19 @@ static const struct net_device_ops lpc_netdev_ops = {
static int lpc_eth_drv_probe(struct platform_device *pdev)
{
- struct resource *res;
- struct net_device *ndev;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
struct netdata_local *pldat;
- struct phy_device *phydev;
+ struct net_device *ndev;
dma_addr_t dma_handle;
+ struct resource *res;
int irq, ret;
u32 tmp;
/* Setup network interface for RMII or MII mode */
tmp = __raw_readl(LPC32XX_CLKPWR_MACCLK_CTRL);
tmp &= ~LPC32XX_CLKPWR_MACCTRL_PINS_MSK;
- if (lpc_phy_interface_mode(&pdev->dev) == PHY_INTERFACE_MODE_MII)
+ if (lpc_phy_interface_mode(dev) == PHY_INTERFACE_MODE_MII)
tmp |= LPC32XX_CLKPWR_MACCTRL_USE_MII_PINS;
else
tmp |= LPC32XX_CLKPWR_MACCTRL_USE_RMII_PINS;
@@ -1279,7 +1263,7 @@ static int lpc_eth_drv_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
if (!res || irq < 0) {
- dev_err(&pdev->dev, "error getting resources.\n");
+ dev_err(dev, "error getting resources.\n");
ret = -ENXIO;
goto err_exit;
}
@@ -1287,12 +1271,12 @@ static int lpc_eth_drv_probe(struct platform_device *pdev)
/* Allocate net driver data structure */
ndev = alloc_etherdev(sizeof(struct netdata_local));
if (!ndev) {
- dev_err(&pdev->dev, "could not allocate device.\n");
+ dev_err(dev, "could not allocate device.\n");
ret = -ENOMEM;
goto err_exit;
}
- SET_NETDEV_DEV(ndev, &pdev->dev);
+ SET_NETDEV_DEV(ndev, dev);
pldat = netdev_priv(ndev);
pldat->pdev = pdev;
@@ -1304,9 +1288,9 @@ static int lpc_eth_drv_probe(struct platform_device *pdev)
ndev->irq = irq;
/* Get clock for the device */
- pldat->clk = clk_get(&pdev->dev, NULL);
+ pldat->clk = clk_get(dev, NULL);
if (IS_ERR(pldat->clk)) {
- dev_err(&pdev->dev, "error getting clock.\n");
+ dev_err(dev, "error getting clock.\n");
ret = PTR_ERR(pldat->clk);
goto err_out_free_dev;
}
@@ -1319,14 +1303,14 @@ static int lpc_eth_drv_probe(struct platform_device *pdev)
/* Map IO space */
pldat->net_base = ioremap(res->start, resource_size(res));
if (!pldat->net_base) {
- dev_err(&pdev->dev, "failed to map registers\n");
+ dev_err(dev, "failed to map registers\n");
ret = -ENOMEM;
goto err_out_disable_clocks;
}
ret = request_irq(ndev->irq, __lpc_eth_interrupt, 0,
ndev->name, ndev);
if (ret) {
- dev_err(&pdev->dev, "error requesting interrupt.\n");
+ dev_err(dev, "error requesting interrupt.\n");
goto err_out_iounmap;
}
@@ -1340,7 +1324,7 @@ static int lpc_eth_drv_probe(struct platform_device *pdev)
sizeof(struct txrx_desc_t) + sizeof(struct rx_status_t));
pldat->dma_buff_base_v = 0;
- if (use_iram_for_net(&pldat->pdev->dev)) {
+ if (use_iram_for_net(dev)) {
dma_handle = LPC32XX_IRAM_BASE;
if (pldat->dma_buff_size <= lpc32xx_return_iram_size())
pldat->dma_buff_base_v =
@@ -1351,7 +1335,7 @@ static int lpc_eth_drv_probe(struct platform_device *pdev)
}
if (pldat->dma_buff_base_v == 0) {
- ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+ ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
if (ret)
goto err_out_free_irq;
@@ -1360,7 +1344,7 @@ static int lpc_eth_drv_probe(struct platform_device *pdev)
/* Allocate a chunk of memory for the DMA ethernet buffers
and descriptors */
pldat->dma_buff_base_v =
- dma_alloc_coherent(&pldat->pdev->dev,
+ dma_alloc_coherent(dev,
pldat->dma_buff_size, &dma_handle,
GFP_KERNEL);
if (pldat->dma_buff_base_v == NULL) {
@@ -1385,7 +1369,7 @@ static int lpc_eth_drv_probe(struct platform_device *pdev)
__lpc_get_mac(pldat, ndev->dev_addr);
if (!is_valid_ether_addr(ndev->dev_addr)) {
- const char *macaddr = of_get_mac_address(pdev->dev.of_node);
+ const char *macaddr = of_get_mac_address(np);
if (macaddr)
memcpy(ndev->dev_addr, macaddr, ETH_ALEN);
}
@@ -1415,7 +1399,7 @@ static int lpc_eth_drv_probe(struct platform_device *pdev)
ret = register_netdev(ndev);
if (ret) {
- dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
+ dev_err(dev, "Cannot register net device, aborting.\n");
goto err_out_dma_unmap;
}
platform_set_drvdata(pdev, ndev);
@@ -1427,19 +1411,17 @@ static int lpc_eth_drv_probe(struct platform_device *pdev)
netdev_info(ndev, "LPC mac at 0x%08x irq %d\n",
res->start, ndev->irq);
- phydev = ndev->phydev;
-
- device_init_wakeup(&pdev->dev, 1);
- device_set_wakeup_enable(&pdev->dev, 0);
+ device_init_wakeup(dev, 1);
+ device_set_wakeup_enable(dev, 0);
return 0;
err_out_unregister_netdev:
unregister_netdev(ndev);
err_out_dma_unmap:
- if (!use_iram_for_net(&pldat->pdev->dev) ||
+ if (!use_iram_for_net(dev) ||
pldat->dma_buff_size > lpc32xx_return_iram_size())
- dma_free_coherent(&pldat->pdev->dev, pldat->dma_buff_size,
+ dma_free_coherent(dev, pldat->dma_buff_size,
pldat->dma_buff_base_v,
pldat->dma_buff_base_p);
err_out_free_irq:
@@ -1534,13 +1516,11 @@ static int lpc_eth_drv_resume(struct platform_device *pdev)
}
#endif
-#ifdef CONFIG_OF
static const struct of_device_id lpc_eth_match[] = {
{ .compatible = "nxp,lpc-eth" },
{ }
};
MODULE_DEVICE_TABLE(of, lpc_eth_match);
-#endif
static struct platform_driver lpc_eth_driver = {
.probe = lpc_eth_drv_probe,
@@ -1551,7 +1531,7 @@ static struct platform_driver lpc_eth_driver = {
#endif
.driver = {
.name = MODNAME,
- .of_match_table = of_match_ptr(lpc_eth_match),
+ .of_match_table = lpc_eth_match,
},
};
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
index 69aa7fc392c5..7d9819d80e44 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
@@ -72,9 +72,6 @@ static void netxen_schedule_work(struct netxen_adapter *adapter,
work_func_t func, int delay);
static void netxen_cancel_fw_work(struct netxen_adapter *adapter);
static int netxen_nic_poll(struct napi_struct *napi, int budget);
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void netxen_nic_poll_controller(struct net_device *netdev);
-#endif
static void netxen_create_sysfs_entries(struct netxen_adapter *adapter);
static void netxen_remove_sysfs_entries(struct netxen_adapter *adapter);
@@ -581,9 +578,6 @@ static const struct net_device_ops netxen_netdev_ops = {
.ndo_tx_timeout = netxen_tx_timeout,
.ndo_fix_features = netxen_fix_features,
.ndo_set_features = netxen_set_features,
-#ifdef CONFIG_NET_POLL_CONTROLLER
- .ndo_poll_controller = netxen_nic_poll_controller,
-#endif
};
static inline bool netxen_function_zero(struct pci_dev *pdev)
@@ -1790,11 +1784,6 @@ static pci_ers_result_t netxen_io_slot_reset(struct pci_dev *pdev)
return err ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED;
}
-static void netxen_io_resume(struct pci_dev *pdev)
-{
- pci_cleanup_aer_uncorrect_error_status(pdev);
-}
-
static void netxen_nic_shutdown(struct pci_dev *pdev)
{
struct netxen_adapter *adapter = pci_get_drvdata(pdev);
@@ -2402,23 +2391,6 @@ static int netxen_nic_poll(struct napi_struct *napi, int budget)
return work_done;
}
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void netxen_nic_poll_controller(struct net_device *netdev)
-{
- int ring;
- struct nx_host_sds_ring *sds_ring;
- struct netxen_adapter *adapter = netdev_priv(netdev);
- struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
-
- disable_irq(adapter->irq);
- for (ring = 0; ring < adapter->max_sds_rings; ring++) {
- sds_ring = &recv_ctx->sds_rings[ring];
- netxen_intr(adapter->irq, sds_ring);
- }
- enable_irq(adapter->irq);
-}
-#endif
-
static int
nx_incr_dev_ref_cnt(struct netxen_adapter *adapter)
{
@@ -3488,7 +3460,6 @@ netxen_free_ip_list(struct netxen_adapter *adapter, bool master)
static const struct pci_error_handlers netxen_err_handler = {
.error_detected = netxen_io_error_detected,
.slot_reset = netxen_io_slot_reset,
- .resume = netxen_io_resume,
};
static struct pci_driver netxen_driver = {
diff --git a/drivers/net/ethernet/qlogic/qed/qed.h b/drivers/net/ethernet/qlogic/qed/qed.h
index a60e1c8d470a..d9a03aba0e02 100644
--- a/drivers/net/ethernet/qlogic/qed/qed.h
+++ b/drivers/net/ethernet/qlogic/qed/qed.h
@@ -623,6 +623,7 @@ struct qed_hwfn {
void *unzip_buf;
struct dbg_tools_data dbg_info;
+ void *dbg_user_info;
/* PWM region specific data */
u16 wid_count;
@@ -914,7 +915,7 @@ u16 qed_get_cm_pq_idx_llt_mtc(struct qed_hwfn *p_hwfn, u8 tc);
/* Prototypes */
int qed_fill_dev_info(struct qed_dev *cdev,
struct qed_dev_info *dev_info);
-void qed_link_update(struct qed_hwfn *hwfn);
+void qed_link_update(struct qed_hwfn *hwfn, struct qed_ptt *ptt);
u32 qed_unzip_data(struct qed_hwfn *p_hwfn,
u32 input_len, u8 *input_buf,
u32 max_size, u8 *unzip_buf);
diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.c b/drivers/net/ethernet/qlogic/qed/qed_cxt.c
index f1977aa440e5..dc1c1b616084 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_cxt.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.c
@@ -40,7 +40,6 @@
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/string.h>
-#include <linux/bitops.h>
#include "qed.h"
#include "qed_cxt.h"
#include "qed_dev_api.h"
diff --git a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c
index f5459de6d60a..8e8fa823d611 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c
@@ -262,8 +262,9 @@ qed_dcbx_get_app_protocol_type(struct qed_hwfn *p_hwfn,
*type = DCBX_PROTOCOL_ROCE_V2;
} else {
*type = DCBX_MAX_PROTOCOL_TYPE;
- DP_ERR(p_hwfn, "No action required, App TLV entry = 0x%x\n",
- app_prio_bitmap);
+ DP_VERBOSE(p_hwfn, QED_MSG_DCB,
+ "No action required, App TLV entry = 0x%x\n",
+ app_prio_bitmap);
return false;
}
diff --git a/drivers/net/ethernet/qlogic/qed/qed_debug.c b/drivers/net/ethernet/qlogic/qed/qed_debug.c
index 1aa9fc1c5890..78a638ec7c0a 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_debug.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_debug.c
@@ -3454,7 +3454,8 @@ static u32 qed_grc_dump_iors(struct qed_hwfn *p_hwfn,
addr = BYTES_TO_DWORDS(storm->sem_fast_mem_addr +
SEM_FAST_REG_STORM_REG_FILE) +
IOR_SET_OFFSET(set_id);
- buf[strlen(buf) - 1] = '0' + set_id;
+ if (strlen(buf) > 0)
+ buf[strlen(buf) - 1] = '0' + set_id;
offset += qed_grc_dump_mem(p_hwfn,
p_ptt,
dump_buf + offset,
@@ -5563,35 +5564,6 @@ struct block_info {
enum block_id id;
};
-struct mcp_trace_format {
- u32 data;
-#define MCP_TRACE_FORMAT_MODULE_MASK 0x0000ffff
-#define MCP_TRACE_FORMAT_MODULE_SHIFT 0
-#define MCP_TRACE_FORMAT_LEVEL_MASK 0x00030000
-#define MCP_TRACE_FORMAT_LEVEL_SHIFT 16
-#define MCP_TRACE_FORMAT_P1_SIZE_MASK 0x000c0000
-#define MCP_TRACE_FORMAT_P1_SIZE_SHIFT 18
-#define MCP_TRACE_FORMAT_P2_SIZE_MASK 0x00300000
-#define MCP_TRACE_FORMAT_P2_SIZE_SHIFT 20
-#define MCP_TRACE_FORMAT_P3_SIZE_MASK 0x00c00000
-#define MCP_TRACE_FORMAT_P3_SIZE_SHIFT 22
-#define MCP_TRACE_FORMAT_LEN_MASK 0xff000000
-#define MCP_TRACE_FORMAT_LEN_SHIFT 24
-
- char *format_str;
-};
-
-/* Meta data structure, generated by a perl script during MFW build. therefore,
- * the structs mcp_trace_meta and mcp_trace_format are duplicated in the perl
- * script.
- */
-struct mcp_trace_meta {
- u32 modules_num;
- char **modules;
- u32 formats_num;
- struct mcp_trace_format *formats;
-};
-
/* REG fifo element */
struct reg_fifo_element {
u64 data;
@@ -5714,6 +5686,20 @@ struct igu_fifo_addr_data {
enum igu_fifo_addr_types type;
};
+struct mcp_trace_meta {
+ u32 modules_num;
+ char **modules;
+ u32 formats_num;
+ struct mcp_trace_format *formats;
+ bool is_allocated;
+};
+
+/* Debug Tools user data */
+struct dbg_tools_user_data {
+ struct mcp_trace_meta mcp_trace_meta;
+ const u32 *mcp_trace_user_meta_buf;
+};
+
/******************************** Constants **********************************/
#define MAX_MSG_LEN 1024
@@ -6137,15 +6123,6 @@ static const struct igu_fifo_addr_data s_igu_fifo_addr_data[] = {
/******************************** Variables **********************************/
-/* MCP Trace meta data array - used in case the dump doesn't contain the
- * meta data (e.g. due to no NVRAM access).
- */
-static struct user_dbg_array s_mcp_trace_meta_arr = { NULL, 0 };
-
-/* Parsed MCP Trace meta data info, based on MCP trace meta array */
-static struct mcp_trace_meta s_mcp_trace_meta;
-static bool s_mcp_trace_meta_valid;
-
/* Temporary buffer, used for print size calculations */
static char s_temp_buf[MAX_MSG_LEN];
@@ -6311,6 +6288,12 @@ static u32 qed_print_section_params(u32 *dump_buf,
return dump_offset;
}
+static struct dbg_tools_user_data *
+qed_dbg_get_user_data(struct qed_hwfn *p_hwfn)
+{
+ return (struct dbg_tools_user_data *)p_hwfn->dbg_user_info;
+}
+
/* Parses the idle check rules and returns the number of characters printed.
* In case of parsing error, returns 0.
*/
@@ -6570,43 +6553,26 @@ static enum dbg_status qed_parse_idle_chk_dump(u32 *dump_buf,
return DBG_STATUS_OK;
}
-/* Frees the specified MCP Trace meta data */
-static void qed_mcp_trace_free_meta(struct qed_hwfn *p_hwfn,
- struct mcp_trace_meta *meta)
-{
- u32 i;
-
- s_mcp_trace_meta_valid = false;
-
- /* Release modules */
- if (meta->modules) {
- for (i = 0; i < meta->modules_num; i++)
- kfree(meta->modules[i]);
- kfree(meta->modules);
- }
-
- /* Release formats */
- if (meta->formats) {
- for (i = 0; i < meta->formats_num; i++)
- kfree(meta->formats[i].format_str);
- kfree(meta->formats);
- }
-}
-
/* Allocates and fills MCP Trace meta data based on the specified meta data
* dump buffer.
* Returns debug status code.
*/
-static enum dbg_status qed_mcp_trace_alloc_meta(struct qed_hwfn *p_hwfn,
- const u32 *meta_buf,
- struct mcp_trace_meta *meta)
+static enum dbg_status
+qed_mcp_trace_alloc_meta_data(struct qed_hwfn *p_hwfn,
+ const u32 *meta_buf)
{
- u8 *meta_buf_bytes = (u8 *)meta_buf;
+ struct dbg_tools_user_data *dev_user_data;
u32 offset = 0, signature, i;
+ struct mcp_trace_meta *meta;
+ u8 *meta_buf_bytes;
+
+ dev_user_data = qed_dbg_get_user_data(p_hwfn);
+ meta = &dev_user_data->mcp_trace_meta;
+ meta_buf_bytes = (u8 *)meta_buf;
/* Free the previous meta before loading a new one. */
- if (s_mcp_trace_meta_valid)
- qed_mcp_trace_free_meta(p_hwfn, meta);
+ if (meta->is_allocated)
+ qed_mcp_trace_free_meta_data(p_hwfn);
memset(meta, 0, sizeof(*meta));
@@ -6674,7 +6640,7 @@ static enum dbg_status qed_mcp_trace_alloc_meta(struct qed_hwfn *p_hwfn,
format_len, format_ptr->format_str);
}
- s_mcp_trace_meta_valid = true;
+ meta->is_allocated = true;
return DBG_STATUS_OK;
}
@@ -6687,21 +6653,26 @@ static enum dbg_status qed_mcp_trace_alloc_meta(struct qed_hwfn *p_hwfn,
* buffer.
* data_size - size in bytes of data to parse.
* parsed_buf - destination buffer for parsed data.
- * parsed_bytes - size of parsed data in bytes.
+ * parsed_results_bytes - size of parsed data in bytes.
*/
-static enum dbg_status qed_parse_mcp_trace_buf(u8 *trace_buf,
+static enum dbg_status qed_parse_mcp_trace_buf(struct qed_hwfn *p_hwfn,
+ u8 *trace_buf,
u32 trace_buf_size,
u32 data_offset,
u32 data_size,
char *parsed_buf,
- u32 *parsed_bytes)
+ u32 *parsed_results_bytes)
{
+ struct dbg_tools_user_data *dev_user_data;
+ struct mcp_trace_meta *meta;
u32 param_mask, param_shift;
enum dbg_status status;
- *parsed_bytes = 0;
+ dev_user_data = qed_dbg_get_user_data(p_hwfn);
+ meta = &dev_user_data->mcp_trace_meta;
+ *parsed_results_bytes = 0;
- if (!s_mcp_trace_meta_valid)
+ if (!meta->is_allocated)
return DBG_STATUS_MCP_TRACE_BAD_DATA;
status = DBG_STATUS_OK;
@@ -6723,7 +6694,7 @@ static enum dbg_status qed_parse_mcp_trace_buf(u8 *trace_buf,
format_idx = header & MFW_TRACE_EVENTID_MASK;
/* Skip message if its index doesn't exist in the meta data */
- if (format_idx >= s_mcp_trace_meta.formats_num) {
+ if (format_idx >= meta->formats_num) {
u8 format_size =
(u8)((header & MFW_TRACE_PRM_SIZE_MASK) >>
MFW_TRACE_PRM_SIZE_SHIFT);
@@ -6738,7 +6709,7 @@ static enum dbg_status qed_parse_mcp_trace_buf(u8 *trace_buf,
continue;
}
- format_ptr = &s_mcp_trace_meta.formats[format_idx];
+ format_ptr = &meta->formats[format_idx];
for (i = 0,
param_mask = MCP_TRACE_FORMAT_P1_SIZE_MASK,
@@ -6783,19 +6754,20 @@ static enum dbg_status qed_parse_mcp_trace_buf(u8 *trace_buf,
return DBG_STATUS_MCP_TRACE_BAD_DATA;
/* Print current message to results buffer */
- *parsed_bytes +=
- sprintf(qed_get_buf_ptr(parsed_buf, *parsed_bytes),
+ *parsed_results_bytes +=
+ sprintf(qed_get_buf_ptr(parsed_buf,
+ *parsed_results_bytes),
"%s %-8s: ",
s_mcp_trace_level_str[format_level],
- s_mcp_trace_meta.modules[format_module]);
- *parsed_bytes +=
- sprintf(qed_get_buf_ptr(parsed_buf, *parsed_bytes),
+ meta->modules[format_module]);
+ *parsed_results_bytes +=
+ sprintf(qed_get_buf_ptr(parsed_buf, *parsed_results_bytes),
format_ptr->format_str,
params[0], params[1], params[2]);
}
/* Add string NULL terminator */
- (*parsed_bytes)++;
+ (*parsed_results_bytes)++;
return status;
}
@@ -6803,24 +6775,25 @@ static enum dbg_status qed_parse_mcp_trace_buf(u8 *trace_buf,
/* Parses an MCP Trace dump buffer.
* If result_buf is not NULL, the MCP Trace results are printed to it.
* In any case, the required results buffer size is assigned to
- * parsed_bytes.
+ * parsed_results_bytes.
* The parsing status is returned.
*/
static enum dbg_status qed_parse_mcp_trace_dump(struct qed_hwfn *p_hwfn,
u32 *dump_buf,
- char *parsed_buf,
- u32 *parsed_bytes)
+ char *results_buf,
+ u32 *parsed_results_bytes,
+ bool free_meta_data)
{
const char *section_name, *param_name, *param_str_val;
u32 data_size, trace_data_dwords, trace_meta_dwords;
- u32 offset, results_offset, parsed_buf_bytes;
+ u32 offset, results_offset, results_buf_bytes;
u32 param_num_val, num_section_params;
struct mcp_trace *trace;
enum dbg_status status;
const u32 *meta_buf;
u8 *trace_buf;
- *parsed_bytes = 0;
+ *parsed_results_bytes = 0;
/* Read global_params section */
dump_buf += qed_read_section_hdr(dump_buf,
@@ -6831,7 +6804,7 @@ static enum dbg_status qed_parse_mcp_trace_dump(struct qed_hwfn *p_hwfn,
/* Print global params */
dump_buf += qed_print_section_params(dump_buf,
num_section_params,
- parsed_buf, &results_offset);
+ results_buf, &results_offset);
/* Read trace_data section */
dump_buf += qed_read_section_hdr(dump_buf,
@@ -6846,6 +6819,9 @@ static enum dbg_status qed_parse_mcp_trace_dump(struct qed_hwfn *p_hwfn,
/* Prepare trace info */
trace = (struct mcp_trace *)dump_buf;
+ if (trace->signature != MFW_TRACE_SIGNATURE || !trace->size)
+ return DBG_STATUS_MCP_TRACE_BAD_DATA;
+
trace_buf = (u8 *)dump_buf + sizeof(*trace);
offset = trace->trace_oldest;
data_size = qed_cyclic_sub(trace->trace_prod, offset, trace->size);
@@ -6865,31 +6841,39 @@ static enum dbg_status qed_parse_mcp_trace_dump(struct qed_hwfn *p_hwfn,
/* Choose meta data buffer */
if (!trace_meta_dwords) {
/* Dump doesn't include meta data */
- if (!s_mcp_trace_meta_arr.ptr)
+ struct dbg_tools_user_data *dev_user_data =
+ qed_dbg_get_user_data(p_hwfn);
+
+ if (!dev_user_data->mcp_trace_user_meta_buf)
return DBG_STATUS_MCP_TRACE_NO_META;
- meta_buf = s_mcp_trace_meta_arr.ptr;
+
+ meta_buf = dev_user_data->mcp_trace_user_meta_buf;
} else {
/* Dump includes meta data */
meta_buf = dump_buf;
}
/* Allocate meta data memory */
- status = qed_mcp_trace_alloc_meta(p_hwfn, meta_buf, &s_mcp_trace_meta);
+ status = qed_mcp_trace_alloc_meta_data(p_hwfn, meta_buf);
if (status != DBG_STATUS_OK)
return status;
- status = qed_parse_mcp_trace_buf(trace_buf,
+ status = qed_parse_mcp_trace_buf(p_hwfn,
+ trace_buf,
trace->size,
offset,
data_size,
- parsed_buf ?
- parsed_buf + results_offset :
+ results_buf ?
+ results_buf + results_offset :
NULL,
- &parsed_buf_bytes);
+ &results_buf_bytes);
if (status != DBG_STATUS_OK)
return status;
- *parsed_bytes = results_offset + parsed_buf_bytes;
+ if (free_meta_data)
+ qed_mcp_trace_free_meta_data(p_hwfn);
+
+ *parsed_results_bytes = results_offset + results_buf_bytes;
return DBG_STATUS_OK;
}
@@ -7361,6 +7345,16 @@ enum dbg_status qed_dbg_user_set_bin_ptr(const u8 * const bin_ptr)
return DBG_STATUS_OK;
}
+enum dbg_status qed_dbg_alloc_user_data(struct qed_hwfn *p_hwfn)
+{
+ p_hwfn->dbg_user_info = kzalloc(sizeof(struct dbg_tools_user_data),
+ GFP_KERNEL);
+ if (!p_hwfn->dbg_user_info)
+ return DBG_STATUS_VIRT_MEM_ALLOC_FAILED;
+
+ return DBG_STATUS_OK;
+}
+
const char *qed_dbg_get_status_str(enum dbg_status status)
{
return (status <
@@ -7397,10 +7391,13 @@ enum dbg_status qed_print_idle_chk_results(struct qed_hwfn *p_hwfn,
num_errors, num_warnings);
}
-void qed_dbg_mcp_trace_set_meta_data(u32 *data, u32 size)
+void qed_dbg_mcp_trace_set_meta_data(struct qed_hwfn *p_hwfn,
+ const u32 *meta_buf)
{
- s_mcp_trace_meta_arr.ptr = data;
- s_mcp_trace_meta_arr.size_in_dwords = size;
+ struct dbg_tools_user_data *dev_user_data =
+ qed_dbg_get_user_data(p_hwfn);
+
+ dev_user_data->mcp_trace_user_meta_buf = meta_buf;
}
enum dbg_status qed_get_mcp_trace_results_buf_size(struct qed_hwfn *p_hwfn,
@@ -7409,7 +7406,7 @@ enum dbg_status qed_get_mcp_trace_results_buf_size(struct qed_hwfn *p_hwfn,
u32 *results_buf_size)
{
return qed_parse_mcp_trace_dump(p_hwfn,
- dump_buf, NULL, results_buf_size);
+ dump_buf, NULL, results_buf_size, true);
}
enum dbg_status qed_print_mcp_trace_results(struct qed_hwfn *p_hwfn,
@@ -7421,20 +7418,61 @@ enum dbg_status qed_print_mcp_trace_results(struct qed_hwfn *p_hwfn,
return qed_parse_mcp_trace_dump(p_hwfn,
dump_buf,
- results_buf, &parsed_buf_size);
+ results_buf, &parsed_buf_size, true);
+}
+
+enum dbg_status qed_print_mcp_trace_results_cont(struct qed_hwfn *p_hwfn,
+ u32 *dump_buf,
+ char *results_buf)
+{
+ u32 parsed_buf_size;
+
+ return qed_parse_mcp_trace_dump(p_hwfn, dump_buf, results_buf,
+ &parsed_buf_size, false);
}
-enum dbg_status qed_print_mcp_trace_line(u8 *dump_buf,
+enum dbg_status qed_print_mcp_trace_line(struct qed_hwfn *p_hwfn,
+ u8 *dump_buf,
u32 num_dumped_bytes,
char *results_buf)
{
- u32 parsed_bytes;
+ u32 parsed_results_bytes;
- return qed_parse_mcp_trace_buf(dump_buf,
+ return qed_parse_mcp_trace_buf(p_hwfn,
+ dump_buf,
num_dumped_bytes,
0,
num_dumped_bytes,
- results_buf, &parsed_bytes);
+ results_buf, &parsed_results_bytes);
+}
+
+/* Frees the specified MCP Trace meta data */
+void qed_mcp_trace_free_meta_data(struct qed_hwfn *p_hwfn)
+{
+ struct dbg_tools_user_data *dev_user_data;
+ struct mcp_trace_meta *meta;
+ u32 i;
+
+ dev_user_data = qed_dbg_get_user_data(p_hwfn);
+ meta = &dev_user_data->mcp_trace_meta;
+ if (!meta->is_allocated)
+ return;
+
+ /* Release modules */
+ if (meta->modules) {
+ for (i = 0; i < meta->modules_num; i++)
+ kfree(meta->modules[i]);
+ kfree(meta->modules);
+ }
+
+ /* Release formats */
+ if (meta->formats) {
+ for (i = 0; i < meta->formats_num; i++)
+ kfree(meta->formats[i].format_str);
+ kfree(meta->formats);
+ }
+
+ meta->is_allocated = false;
}
enum dbg_status qed_get_reg_fifo_results_buf_size(struct qed_hwfn *p_hwfn,
diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c
index 97f073fd3725..7ceb2b97538d 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_dev.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c
@@ -144,6 +144,12 @@ static void qed_qm_info_free(struct qed_hwfn *p_hwfn)
qm_info->wfq_data = NULL;
}
+static void qed_dbg_user_data_free(struct qed_hwfn *p_hwfn)
+{
+ kfree(p_hwfn->dbg_user_info);
+ p_hwfn->dbg_user_info = NULL;
+}
+
void qed_resc_free(struct qed_dev *cdev)
{
int i;
@@ -183,6 +189,7 @@ void qed_resc_free(struct qed_dev *cdev)
qed_l2_free(p_hwfn);
qed_dmae_info_free(p_hwfn);
qed_dcbx_info_free(p_hwfn);
+ qed_dbg_user_data_free(p_hwfn);
}
}
@@ -1083,6 +1090,10 @@ int qed_resc_alloc(struct qed_dev *cdev)
rc = qed_dcbx_info_alloc(p_hwfn);
if (rc)
goto alloc_err;
+
+ rc = qed_dbg_alloc_user_data(p_hwfn);
+ if (rc)
+ goto alloc_err;
}
cdev->reset_stats = kzalloc(sizeof(*cdev->reset_stats), GFP_KERNEL);
@@ -2668,6 +2679,9 @@ static int qed_hw_get_nvm_info(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
case NVM_CFG1_PORT_DRV_LINK_SPEED_10G:
link->speed.forced_speed = 10000;
break;
+ case NVM_CFG1_PORT_DRV_LINK_SPEED_20G:
+ link->speed.forced_speed = 20000;
+ break;
case NVM_CFG1_PORT_DRV_LINK_SPEED_25G:
link->speed.forced_speed = 25000;
break;
diff --git a/drivers/net/ethernet/qlogic/qed/qed_fcoe.c b/drivers/net/ethernet/qlogic/qed/qed_fcoe.c
index cc1b373c0ace..46dc93d3b9b5 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_fcoe.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_fcoe.c
@@ -147,7 +147,8 @@ qed_sp_fcoe_func_start(struct qed_hwfn *p_hwfn,
"Cannot satisfy CQ amount. CQs requested %d, CQs available %d. Aborting function start\n",
fcoe_pf_params->num_cqs,
p_hwfn->hw_info.feat_num[QED_FCOE_CQ]);
- return -EINVAL;
+ rc = -EINVAL;
+ goto err;
}
p_data->mtu = cpu_to_le16(fcoe_pf_params->mtu);
@@ -156,14 +157,14 @@ qed_sp_fcoe_func_start(struct qed_hwfn *p_hwfn,
rc = qed_cxt_acquire_cid(p_hwfn, PROTOCOLID_FCOE, &dummy_cid);
if (rc)
- return rc;
+ goto err;
cxt_info.iid = dummy_cid;
rc = qed_cxt_get_cid_info(p_hwfn, &cxt_info);
if (rc) {
DP_NOTICE(p_hwfn, "Cannot find context info for dummy cid=%d\n",
dummy_cid);
- return rc;
+ goto err;
}
p_cxt = cxt_info.p_cxt;
SET_FIELD(p_cxt->tstorm_ag_context.flags3,
@@ -240,6 +241,10 @@ qed_sp_fcoe_func_start(struct qed_hwfn *p_hwfn,
rc = qed_spq_post(p_hwfn, p_ent, NULL);
return rc;
+
+err:
+ qed_sp_destroy_request(p_hwfn, p_ent);
+ return rc;
}
static int
diff --git a/drivers/net/ethernet/qlogic/qed/qed_hsi.h b/drivers/net/ethernet/qlogic/qed/qed_hsi.h
index 9b3ef00e5782..5c221ebaa7b3 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_hsi.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_hsi.h
@@ -274,7 +274,8 @@ struct core_rx_start_ramrod_data {
u8 mf_si_mcast_accept_all;
struct core_rx_action_on_error action_on_error;
u8 gsi_offload_flag;
- u8 reserved[6];
+ u8 wipe_inner_vlan_pri_en;
+ u8 reserved[5];
};
/* Ramrod data for rx queue stop ramrod */
@@ -351,7 +352,8 @@ struct core_tx_start_ramrod_data {
__le16 pbl_size;
__le16 qm_pq_id;
u8 gsi_offload_flag;
- u8 resrved[3];
+ u8 vport_id;
+ u8 resrved[2];
};
/* Ramrod data for tx queue stop ramrod */
@@ -914,6 +916,16 @@ struct eth_rx_rate_limit {
__le16 reserved1;
};
+/* Update RSS indirection table entry command */
+struct eth_tstorm_rss_update_data {
+ u8 valid;
+ u8 vport_id;
+ u8 ind_table_index;
+ u8 reserved;
+ __le16 ind_table_value;
+ __le16 reserved1;
+};
+
struct eth_ustorm_per_pf_stat {
struct regpair rcv_lb_ucast_bytes;
struct regpair rcv_lb_mcast_bytes;
@@ -1241,6 +1253,10 @@ struct rl_update_ramrod_data {
u8 rl_id_first;
u8 rl_id_last;
u8 rl_dc_qcn_flg;
+ u8 dcqcn_reset_alpha_on_idle;
+ u8 rl_bc_stage_th;
+ u8 rl_timer_stage_th;
+ u8 reserved1;
__le32 rl_bc_rate;
__le16 rl_max_rate;
__le16 rl_r_ai;
@@ -1249,7 +1265,7 @@ struct rl_update_ramrod_data {
__le32 dcqcn_k_us;
__le32 dcqcn_timeuot_us;
__le32 qcn_timeuot_us;
- __le32 reserved[2];
+ __le32 reserved2;
};
/* Slowpath Element (SPQE) */
@@ -3322,6 +3338,25 @@ enum dbg_status qed_dbg_read_attn(struct qed_hwfn *p_hwfn,
enum dbg_status qed_dbg_print_attn(struct qed_hwfn *p_hwfn,
struct dbg_attn_block_result *results);
+/******************************* Data Types **********************************/
+
+struct mcp_trace_format {
+ u32 data;
+#define MCP_TRACE_FORMAT_MODULE_MASK 0x0000ffff
+#define MCP_TRACE_FORMAT_MODULE_SHIFT 0
+#define MCP_TRACE_FORMAT_LEVEL_MASK 0x00030000
+#define MCP_TRACE_FORMAT_LEVEL_SHIFT 16
+#define MCP_TRACE_FORMAT_P1_SIZE_MASK 0x000c0000
+#define MCP_TRACE_FORMAT_P1_SIZE_SHIFT 18
+#define MCP_TRACE_FORMAT_P2_SIZE_MASK 0x00300000
+#define MCP_TRACE_FORMAT_P2_SIZE_SHIFT 20
+#define MCP_TRACE_FORMAT_P3_SIZE_MASK 0x00c00000
+#define MCP_TRACE_FORMAT_P3_SIZE_SHIFT 22
+#define MCP_TRACE_FORMAT_LEN_MASK 0xff000000
+#define MCP_TRACE_FORMAT_LEN_SHIFT 24
+ char *format_str;
+};
+
/******************************** Constants **********************************/
#define MAX_NAME_LEN 16
@@ -3337,6 +3372,13 @@ enum dbg_status qed_dbg_print_attn(struct qed_hwfn *p_hwfn,
enum dbg_status qed_dbg_user_set_bin_ptr(const u8 * const bin_ptr);
/**
+ * @brief qed_dbg_alloc_user_data - Allocates user debug data.
+ *
+ * @param p_hwfn - HW device data
+ */
+enum dbg_status qed_dbg_alloc_user_data(struct qed_hwfn *p_hwfn);
+
+/**
* @brief qed_dbg_get_status_str - Returns a string for the specified status.
*
* @param status - a debug status code.
@@ -3381,8 +3423,7 @@ enum dbg_status qed_print_idle_chk_results(struct qed_hwfn *p_hwfn,
u32 *num_warnings);
/**
- * @brief qed_dbg_mcp_trace_set_meta_data - Sets a pointer to the MCP Trace
- * meta data.
+ * @brief qed_dbg_mcp_trace_set_meta_data - Sets the MCP Trace meta data.
*
* Needed in case the MCP Trace dump doesn't contain the meta data (e.g. due to
* no NVRAM access).
@@ -3390,7 +3431,8 @@ enum dbg_status qed_print_idle_chk_results(struct qed_hwfn *p_hwfn,
* @param data - pointer to MCP Trace meta data
* @param size - size of MCP Trace meta data in dwords
*/
-void qed_dbg_mcp_trace_set_meta_data(u32 *data, u32 size);
+void qed_dbg_mcp_trace_set_meta_data(struct qed_hwfn *p_hwfn,
+ const u32 *meta_buf);
/**
* @brief qed_get_mcp_trace_results_buf_size - Returns the required buffer size
@@ -3425,19 +3467,45 @@ enum dbg_status qed_print_mcp_trace_results(struct qed_hwfn *p_hwfn,
char *results_buf);
/**
+ * @brief qed_print_mcp_trace_results_cont - Prints MCP Trace results, and
+ * keeps the MCP trace meta data allocated, to support continuous MCP Trace
+ * parsing. After the continuous parsing ends, mcp_trace_free_meta_data should
+ * be called to free the meta data.
+ *
+ * @param p_hwfn - HW device data
+ * @param dump_buf - mcp trace dump buffer, starting from the header.
+ * @param results_buf - buffer for printing the mcp trace results.
+ *
+ * @return error if the parsing fails, ok otherwise.
+ */
+enum dbg_status qed_print_mcp_trace_results_cont(struct qed_hwfn *p_hwfn,
+ u32 *dump_buf,
+ char *results_buf);
+
+/**
* @brief print_mcp_trace_line - Prints MCP Trace results for a single line
*
+ * @param p_hwfn - HW device data
* @param dump_buf - mcp trace dump buffer, starting from the header.
* @param num_dumped_bytes - number of bytes that were dumped.
* @param results_buf - buffer for printing the mcp trace results.
*
* @return error if the parsing fails, ok otherwise.
*/
-enum dbg_status qed_print_mcp_trace_line(u8 *dump_buf,
+enum dbg_status qed_print_mcp_trace_line(struct qed_hwfn *p_hwfn,
+ u8 *dump_buf,
u32 num_dumped_bytes,
char *results_buf);
/**
+ * @brief mcp_trace_free_meta_data - Frees the MCP Trace meta data.
+ * Should be called after continuous MCP Trace parsing.
+ *
+ * @param p_hwfn - HW device data
+ */
+void qed_mcp_trace_free_meta_data(struct qed_hwfn *p_hwfn);
+
+/**
* @brief qed_get_reg_fifo_results_buf_size - Returns the required buffer size
* for reg_fifo results (in bytes).
*
@@ -4303,154 +4371,161 @@ void qed_set_rdma_error_level(struct qed_hwfn *p_hwfn,
(IRO[29].base + ((pf_id) * IRO[29].m1))
#define ETH_RX_RATE_LIMIT_SIZE (IRO[29].size)
+/* RSS indirection table entry update command per PF offset in TSTORM PF BAR0.
+ * Use eth_tstorm_rss_update_data for update.
+ */
+#define TSTORM_ETH_RSS_UPDATE_OFFSET(pf_id) \
+ (IRO[30].base + ((pf_id) * IRO[30].m1))
+#define TSTORM_ETH_RSS_UPDATE_SIZE (IRO[30].size)
+
/* Xstorm queue zone */
#define XSTORM_ETH_QUEUE_ZONE_OFFSET(queue_id) \
- (IRO[30].base + ((queue_id) * IRO[30].m1))
-#define XSTORM_ETH_QUEUE_ZONE_SIZE (IRO[30].size)
+ (IRO[31].base + ((queue_id) * IRO[31].m1))
+#define XSTORM_ETH_QUEUE_ZONE_SIZE (IRO[31].size)
/* Ystorm cqe producer */
#define YSTORM_TOE_CQ_PROD_OFFSET(rss_id) \
- (IRO[31].base + ((rss_id) * IRO[31].m1))
-#define YSTORM_TOE_CQ_PROD_SIZE (IRO[31].size)
+ (IRO[32].base + ((rss_id) * IRO[32].m1))
+#define YSTORM_TOE_CQ_PROD_SIZE (IRO[32].size)
/* Ustorm cqe producer */
#define USTORM_TOE_CQ_PROD_OFFSET(rss_id) \
- (IRO[32].base + ((rss_id) * IRO[32].m1))
-#define USTORM_TOE_CQ_PROD_SIZE (IRO[32].size)
+ (IRO[33].base + ((rss_id) * IRO[33].m1))
+#define USTORM_TOE_CQ_PROD_SIZE (IRO[33].size)
/* Ustorm grq producer */
#define USTORM_TOE_GRQ_PROD_OFFSET(pf_id) \
- (IRO[33].base + ((pf_id) * IRO[33].m1))
-#define USTORM_TOE_GRQ_PROD_SIZE (IRO[33].size)
+ (IRO[34].base + ((pf_id) * IRO[34].m1))
+#define USTORM_TOE_GRQ_PROD_SIZE (IRO[34].size)
/* Tstorm cmdq-cons of given command queue-id */
#define TSTORM_SCSI_CMDQ_CONS_OFFSET(cmdq_queue_id) \
- (IRO[34].base + ((cmdq_queue_id) * IRO[34].m1))
-#define TSTORM_SCSI_CMDQ_CONS_SIZE (IRO[34].size)
+ (IRO[35].base + ((cmdq_queue_id) * IRO[35].m1))
+#define TSTORM_SCSI_CMDQ_CONS_SIZE (IRO[35].size)
/* Tstorm (reflects M-Storm) bdq-external-producer of given function ID,
* BDqueue-id.
*/
#define TSTORM_SCSI_BDQ_EXT_PROD_OFFSET(func_id, bdq_id) \
- (IRO[35].base + ((func_id) * IRO[35].m1) + ((bdq_id) * IRO[35].m2))
-#define TSTORM_SCSI_BDQ_EXT_PROD_SIZE (IRO[35].size)
+ (IRO[36].base + ((func_id) * IRO[36].m1) + ((bdq_id) * IRO[36].m2))
+#define TSTORM_SCSI_BDQ_EXT_PROD_SIZE (IRO[36].size)
/* Mstorm bdq-external-producer of given BDQ resource ID, BDqueue-id */
#define MSTORM_SCSI_BDQ_EXT_PROD_OFFSET(func_id, bdq_id) \
- (IRO[36].base + ((func_id) * IRO[36].m1) + ((bdq_id) * IRO[36].m2))
-#define MSTORM_SCSI_BDQ_EXT_PROD_SIZE (IRO[36].size)
+ (IRO[37].base + ((func_id) * IRO[37].m1) + ((bdq_id) * IRO[37].m2))
+#define MSTORM_SCSI_BDQ_EXT_PROD_SIZE (IRO[37].size)
/* Tstorm iSCSI RX stats */
#define TSTORM_ISCSI_RX_STATS_OFFSET(pf_id) \
- (IRO[37].base + ((pf_id) * IRO[37].m1))
-#define TSTORM_ISCSI_RX_STATS_SIZE (IRO[37].size)
+ (IRO[38].base + ((pf_id) * IRO[38].m1))
+#define TSTORM_ISCSI_RX_STATS_SIZE (IRO[38].size)
/* Mstorm iSCSI RX stats */
#define MSTORM_ISCSI_RX_STATS_OFFSET(pf_id) \
- (IRO[38].base + ((pf_id) * IRO[38].m1))
-#define MSTORM_ISCSI_RX_STATS_SIZE (IRO[38].size)
+ (IRO[39].base + ((pf_id) * IRO[39].m1))
+#define MSTORM_ISCSI_RX_STATS_SIZE (IRO[39].size)
/* Ustorm iSCSI RX stats */
#define USTORM_ISCSI_RX_STATS_OFFSET(pf_id) \
- (IRO[39].base + ((pf_id) * IRO[39].m1))
-#define USTORM_ISCSI_RX_STATS_SIZE (IRO[39].size)
+ (IRO[40].base + ((pf_id) * IRO[40].m1))
+#define USTORM_ISCSI_RX_STATS_SIZE (IRO[40].size)
/* Xstorm iSCSI TX stats */
#define XSTORM_ISCSI_TX_STATS_OFFSET(pf_id) \
- (IRO[40].base + ((pf_id) * IRO[40].m1))
-#define XSTORM_ISCSI_TX_STATS_SIZE (IRO[40].size)
+ (IRO[41].base + ((pf_id) * IRO[41].m1))
+#define XSTORM_ISCSI_TX_STATS_SIZE (IRO[41].size)
/* Ystorm iSCSI TX stats */
#define YSTORM_ISCSI_TX_STATS_OFFSET(pf_id) \
- (IRO[41].base + ((pf_id) * IRO[41].m1))
-#define YSTORM_ISCSI_TX_STATS_SIZE (IRO[41].size)
+ (IRO[42].base + ((pf_id) * IRO[42].m1))
+#define YSTORM_ISCSI_TX_STATS_SIZE (IRO[42].size)
/* Pstorm iSCSI TX stats */
#define PSTORM_ISCSI_TX_STATS_OFFSET(pf_id) \
- (IRO[42].base + ((pf_id) * IRO[42].m1))
-#define PSTORM_ISCSI_TX_STATS_SIZE (IRO[42].size)
+ (IRO[43].base + ((pf_id) * IRO[43].m1))
+#define PSTORM_ISCSI_TX_STATS_SIZE (IRO[43].size)
/* Tstorm FCoE RX stats */
#define TSTORM_FCOE_RX_STATS_OFFSET(pf_id) \
- (IRO[43].base + ((pf_id) * IRO[43].m1))
-#define TSTORM_FCOE_RX_STATS_SIZE (IRO[43].size)
+ (IRO[44].base + ((pf_id) * IRO[44].m1))
+#define TSTORM_FCOE_RX_STATS_SIZE (IRO[44].size)
/* Pstorm FCoE TX stats */
#define PSTORM_FCOE_TX_STATS_OFFSET(pf_id) \
- (IRO[44].base + ((pf_id) * IRO[44].m1))
-#define PSTORM_FCOE_TX_STATS_SIZE (IRO[44].size)
+ (IRO[45].base + ((pf_id) * IRO[45].m1))
+#define PSTORM_FCOE_TX_STATS_SIZE (IRO[45].size)
/* Pstorm RDMA queue statistics */
#define PSTORM_RDMA_QUEUE_STAT_OFFSET(rdma_stat_counter_id) \
- (IRO[45].base + ((rdma_stat_counter_id) * IRO[45].m1))
-#define PSTORM_RDMA_QUEUE_STAT_SIZE (IRO[45].size)
+ (IRO[46].base + ((rdma_stat_counter_id) * IRO[46].m1))
+#define PSTORM_RDMA_QUEUE_STAT_SIZE (IRO[46].size)
/* Tstorm RDMA queue statistics */
#define TSTORM_RDMA_QUEUE_STAT_OFFSET(rdma_stat_counter_id) \
- (IRO[46].base + ((rdma_stat_counter_id) * IRO[46].m1))
-#define TSTORM_RDMA_QUEUE_STAT_SIZE (IRO[46].size)
+ (IRO[47].base + ((rdma_stat_counter_id) * IRO[47].m1))
+#define TSTORM_RDMA_QUEUE_STAT_SIZE (IRO[47].size)
/* Xstorm error level for assert */
#define XSTORM_RDMA_ASSERT_LEVEL_OFFSET(pf_id) \
- (IRO[47].base + ((pf_id) * IRO[47].m1))
-#define XSTORM_RDMA_ASSERT_LEVEL_SIZE (IRO[47].size)
+ (IRO[48].base + ((pf_id) * IRO[48].m1))
+#define XSTORM_RDMA_ASSERT_LEVEL_SIZE (IRO[48].size)
/* Ystorm error level for assert */
#define YSTORM_RDMA_ASSERT_LEVEL_OFFSET(pf_id) \
- (IRO[48].base + ((pf_id) * IRO[48].m1))
-#define YSTORM_RDMA_ASSERT_LEVEL_SIZE (IRO[48].size)
+ (IRO[49].base + ((pf_id) * IRO[49].m1))
+#define YSTORM_RDMA_ASSERT_LEVEL_SIZE (IRO[49].size)
/* Pstorm error level for assert */
#define PSTORM_RDMA_ASSERT_LEVEL_OFFSET(pf_id) \
- (IRO[49].base + ((pf_id) * IRO[49].m1))
-#define PSTORM_RDMA_ASSERT_LEVEL_SIZE (IRO[49].size)
+ (IRO[50].base + ((pf_id) * IRO[50].m1))
+#define PSTORM_RDMA_ASSERT_LEVEL_SIZE (IRO[50].size)
/* Tstorm error level for assert */
#define TSTORM_RDMA_ASSERT_LEVEL_OFFSET(pf_id) \
- (IRO[50].base + ((pf_id) * IRO[50].m1))
-#define TSTORM_RDMA_ASSERT_LEVEL_SIZE (IRO[50].size)
+ (IRO[51].base + ((pf_id) * IRO[51].m1))
+#define TSTORM_RDMA_ASSERT_LEVEL_SIZE (IRO[51].size)
/* Mstorm error level for assert */
#define MSTORM_RDMA_ASSERT_LEVEL_OFFSET(pf_id) \
- (IRO[51].base + ((pf_id) * IRO[51].m1))
-#define MSTORM_RDMA_ASSERT_LEVEL_SIZE (IRO[51].size)
+ (IRO[52].base + ((pf_id) * IRO[52].m1))
+#define MSTORM_RDMA_ASSERT_LEVEL_SIZE (IRO[52].size)
/* Ustorm error level for assert */
#define USTORM_RDMA_ASSERT_LEVEL_OFFSET(pf_id) \
- (IRO[52].base + ((pf_id) * IRO[52].m1))
-#define USTORM_RDMA_ASSERT_LEVEL_SIZE (IRO[52].size)
+ (IRO[53].base + ((pf_id) * IRO[53].m1))
+#define USTORM_RDMA_ASSERT_LEVEL_SIZE (IRO[53].size)
/* Xstorm iWARP rxmit stats */
#define XSTORM_IWARP_RXMIT_STATS_OFFSET(pf_id) \
- (IRO[53].base + ((pf_id) * IRO[53].m1))
-#define XSTORM_IWARP_RXMIT_STATS_SIZE (IRO[53].size)
+ (IRO[54].base + ((pf_id) * IRO[54].m1))
+#define XSTORM_IWARP_RXMIT_STATS_SIZE (IRO[54].size)
/* Tstorm RoCE Event Statistics */
#define TSTORM_ROCE_EVENTS_STAT_OFFSET(roce_pf_id) \
- (IRO[54].base + ((roce_pf_id) * IRO[54].m1))
-#define TSTORM_ROCE_EVENTS_STAT_SIZE (IRO[54].size)
+ (IRO[55].base + ((roce_pf_id) * IRO[55].m1))
+#define TSTORM_ROCE_EVENTS_STAT_SIZE (IRO[55].size)
/* DCQCN Received Statistics */
#define YSTORM_ROCE_DCQCN_RECEIVED_STATS_OFFSET(roce_pf_id) \
- (IRO[55].base + ((roce_pf_id) * IRO[55].m1))
-#define YSTORM_ROCE_DCQCN_RECEIVED_STATS_SIZE (IRO[55].size)
+ (IRO[56].base + ((roce_pf_id) * IRO[56].m1))
+#define YSTORM_ROCE_DCQCN_RECEIVED_STATS_SIZE (IRO[56].size)
/* RoCE Error Statistics */
#define YSTORM_ROCE_ERROR_STATS_OFFSET(roce_pf_id) \
- (IRO[56].base + ((roce_pf_id) * IRO[56].m1))
-#define YSTORM_ROCE_ERROR_STATS_SIZE (IRO[56].size)
+ (IRO[57].base + ((roce_pf_id) * IRO[57].m1))
+#define YSTORM_ROCE_ERROR_STATS_SIZE (IRO[57].size)
/* DCQCN Sent Statistics */
#define PSTORM_ROCE_DCQCN_SENT_STATS_OFFSET(roce_pf_id) \
- (IRO[57].base + ((roce_pf_id) * IRO[57].m1))
-#define PSTORM_ROCE_DCQCN_SENT_STATS_SIZE (IRO[57].size)
+ (IRO[58].base + ((roce_pf_id) * IRO[58].m1))
+#define PSTORM_ROCE_DCQCN_SENT_STATS_SIZE (IRO[58].size)
/* RoCE CQEs Statistics */
#define USTORM_ROCE_CQE_STATS_OFFSET(roce_pf_id) \
- (IRO[58].base + ((roce_pf_id) * IRO[58].m1))
-#define USTORM_ROCE_CQE_STATS_SIZE (IRO[58].size)
+ (IRO[59].base + ((roce_pf_id) * IRO[59].m1))
+#define USTORM_ROCE_CQE_STATS_SIZE (IRO[59].size)
-static const struct iro iro_arr[59] = {
+static const struct iro iro_arr[60] = {
{0x0, 0x0, 0x0, 0x0, 0x8},
{0x4cb8, 0x88, 0x0, 0x0, 0x88},
{0x6530, 0x20, 0x0, 0x0, 0x20},
@@ -4461,14 +4536,14 @@ static const struct iro iro_arr[59] = {
{0x84, 0x8, 0x0, 0x0, 0x2},
{0x4c48, 0x0, 0x0, 0x0, 0x78},
{0x3e38, 0x0, 0x0, 0x0, 0x78},
- {0x2b78, 0x0, 0x0, 0x0, 0x78},
+ {0x3ef8, 0x0, 0x0, 0x0, 0x78},
{0x4c40, 0x0, 0x0, 0x0, 0x78},
{0x4998, 0x0, 0x0, 0x0, 0x78},
{0x7f50, 0x0, 0x0, 0x0, 0x78},
{0xa28, 0x8, 0x0, 0x0, 0x8},
{0x6210, 0x10, 0x0, 0x0, 0x10},
{0xb820, 0x30, 0x0, 0x0, 0x30},
- {0x96c0, 0x30, 0x0, 0x0, 0x30},
+ {0xa990, 0x30, 0x0, 0x0, 0x30},
{0x4b68, 0x80, 0x0, 0x0, 0x40},
{0x1f8, 0x4, 0x0, 0x0, 0x4},
{0x53a8, 0x80, 0x4, 0x0, 0x4},
@@ -4476,11 +4551,12 @@ static const struct iro iro_arr[59] = {
{0x4ba8, 0x80, 0x0, 0x0, 0x20},
{0x8158, 0x40, 0x0, 0x0, 0x30},
{0xe770, 0x60, 0x0, 0x0, 0x60},
- {0x2d10, 0x80, 0x0, 0x0, 0x38},
- {0xf2b8, 0x78, 0x0, 0x0, 0x78},
+ {0x4090, 0x80, 0x0, 0x0, 0x38},
+ {0xfea8, 0x78, 0x0, 0x0, 0x78},
{0x1f8, 0x4, 0x0, 0x0, 0x4},
{0xaf20, 0x0, 0x0, 0x0, 0xf0},
{0xb010, 0x8, 0x0, 0x0, 0x8},
+ {0xc00, 0x8, 0x0, 0x0, 0x8},
{0x1f8, 0x8, 0x0, 0x0, 0x8},
{0xac0, 0x8, 0x0, 0x0, 0x8},
{0x2578, 0x8, 0x0, 0x0, 0x8},
@@ -4492,23 +4568,23 @@ static const struct iro iro_arr[59] = {
{0x12908, 0x18, 0x0, 0x0, 0x10},
{0x11aa8, 0x40, 0x0, 0x0, 0x18},
{0xa588, 0x50, 0x0, 0x0, 0x20},
- {0x8700, 0x40, 0x0, 0x0, 0x28},
- {0x10300, 0x18, 0x0, 0x0, 0x10},
+ {0x8f00, 0x40, 0x0, 0x0, 0x28},
+ {0x10e30, 0x18, 0x0, 0x0, 0x10},
{0xde48, 0x48, 0x0, 0x0, 0x38},
- {0x10768, 0x20, 0x0, 0x0, 0x20},
- {0x2d48, 0x80, 0x0, 0x0, 0x10},
+ {0x11298, 0x20, 0x0, 0x0, 0x20},
+ {0x40c8, 0x80, 0x0, 0x0, 0x10},
{0x5048, 0x10, 0x0, 0x0, 0x10},
{0xc748, 0x8, 0x0, 0x0, 0x1},
- {0xa128, 0x8, 0x0, 0x0, 0x1},
- {0x10f00, 0x8, 0x0, 0x0, 0x1},
+ {0xa928, 0x8, 0x0, 0x0, 0x1},
+ {0x11a30, 0x8, 0x0, 0x0, 0x1},
{0xf030, 0x8, 0x0, 0x0, 0x1},
{0x13028, 0x8, 0x0, 0x0, 0x1},
{0x12c58, 0x8, 0x0, 0x0, 0x1},
{0xc9b8, 0x30, 0x0, 0x0, 0x10},
{0xed90, 0x28, 0x0, 0x0, 0x28},
- {0xa520, 0x18, 0x0, 0x0, 0x18},
- {0xa6a0, 0x8, 0x0, 0x0, 0x8},
- {0x13108, 0x8, 0x0, 0x0, 0x8},
+ {0xad20, 0x18, 0x0, 0x0, 0x18},
+ {0xaea0, 0x8, 0x0, 0x0, 0x8},
+ {0x13c38, 0x8, 0x0, 0x0, 0x8},
{0x13c50, 0x18, 0x0, 0x0, 0x18},
};
@@ -5661,6 +5737,14 @@ enum eth_filter_type {
MAX_ETH_FILTER_TYPE
};
+/* inner to inner vlan priority translation configurations */
+struct eth_in_to_in_pri_map_cfg {
+ u8 inner_vlan_pri_remap_en;
+ u8 reserved[7];
+ u8 non_rdma_in_to_in_pri_map[8];
+ u8 rdma_in_to_in_pri_map[8];
+};
+
/* Eth IPv4 Fragment Type */
enum eth_ipv4_frag_type {
ETH_IPV4_NOT_FRAG,
@@ -6018,6 +6102,14 @@ struct tx_queue_update_ramrod_data {
struct regpair reserved1[5];
};
+/* Inner to Inner VLAN priority map update mode */
+enum update_in_to_in_pri_map_mode_enum {
+ ETH_IN_TO_IN_PRI_MAP_UPDATE_DISABLED,
+ ETH_IN_TO_IN_PRI_MAP_UPDATE_NON_RDMA_TBL,
+ ETH_IN_TO_IN_PRI_MAP_UPDATE_RDMA_TBL,
+ MAX_UPDATE_IN_TO_IN_PRI_MAP_MODE_ENUM
+};
+
/* Ramrod data for vport update ramrod */
struct vport_filter_update_ramrod_data {
struct eth_filter_cmd_header filter_cmd_hdr;
@@ -6048,7 +6140,8 @@ struct vport_start_ramrod_data {
u8 zero_placement_offset;
u8 ctl_frame_mac_check_en;
u8 ctl_frame_ethtype_check_en;
- u8 reserved[1];
+ u8 wipe_inner_vlan_pri_en;
+ struct eth_in_to_in_pri_map_cfg in_to_in_vlan_pri_map_cfg;
};
/* Ramrod data for vport stop ramrod */
@@ -6100,7 +6193,9 @@ struct vport_update_ramrod_data_cmn {
u8 update_ctl_frame_checks_en_flg;
u8 ctl_frame_mac_check_en;
u8 ctl_frame_ethtype_check_en;
- u8 reserved[15];
+ u8 update_in_to_in_pri_map_mode;
+ u8 in_to_in_pri_map[8];
+ u8 reserved[6];
};
struct vport_update_ramrod_mcast {
@@ -6929,11 +7024,6 @@ struct mstorm_rdma_task_st_ctx {
struct regpair temp[4];
};
-/* The roce task context of Ustorm */
-struct ustorm_rdma_task_st_ctx {
- struct regpair temp[2];
-};
-
struct e4_ustorm_rdma_task_ag_ctx {
u8 reserved;
u8 state;
@@ -7007,8 +7097,6 @@ struct e4_rdma_task_context {
struct e4_mstorm_rdma_task_ag_ctx mstorm_ag_context;
struct mstorm_rdma_task_st_ctx mstorm_st_context;
struct rdif_task_context rdif_context;
- struct ustorm_rdma_task_st_ctx ustorm_st_context;
- struct regpair ustorm_st_padding[2];
struct e4_ustorm_rdma_task_ag_ctx ustorm_ag_context;
};
@@ -7388,7 +7476,7 @@ struct e4_ustorm_rdma_conn_ag_ctx {
#define E4_USTORM_RDMA_CONN_AG_CTX_RULE8EN_MASK 0x1
#define E4_USTORM_RDMA_CONN_AG_CTX_RULE8EN_SHIFT 7
u8 byte2;
- u8 byte3;
+ u8 nvmf_only;
__le16 conn_dpi;
__le16 word1;
__le32 cq_cons;
@@ -7831,7 +7919,12 @@ struct roce_create_qp_req_ramrod_data {
struct regpair qp_handle_for_cqe;
struct regpair qp_handle_for_async;
u8 stats_counter_id;
- u8 reserved3[7];
+ u8 reserved3[6];
+ u8 flags2;
+#define ROCE_CREATE_QP_REQ_RAMROD_DATA_EDPM_MODE_MASK 0x1
+#define ROCE_CREATE_QP_REQ_RAMROD_DATA_EDPM_MODE_SHIFT 0
+#define ROCE_CREATE_QP_REQ_RAMROD_DATA_RESERVED_MASK 0x7F
+#define ROCE_CREATE_QP_REQ_RAMROD_DATA_RESERVED_SHIFT 1
__le16 regular_latency_phy_queue;
__le16 dpi;
};
@@ -7954,6 +8047,7 @@ enum roce_event_opcode {
ROCE_EVENT_DESTROY_QP,
ROCE_EVENT_CREATE_UD_QP,
ROCE_EVENT_DESTROY_UD_QP,
+ ROCE_EVENT_FUNC_UPDATE,
MAX_ROCE_EVENT_OPCODE
};
@@ -7962,7 +8056,13 @@ struct roce_init_func_params {
u8 ll2_queue_id;
u8 cnp_vlan_priority;
u8 cnp_dscp;
- u8 reserved;
+ u8 flags;
+#define ROCE_INIT_FUNC_PARAMS_DCQCN_NP_EN_MASK 0x1
+#define ROCE_INIT_FUNC_PARAMS_DCQCN_NP_EN_SHIFT 0
+#define ROCE_INIT_FUNC_PARAMS_DCQCN_RP_EN_MASK 0x1
+#define ROCE_INIT_FUNC_PARAMS_DCQCN_RP_EN_SHIFT 1
+#define ROCE_INIT_FUNC_PARAMS_RESERVED0_MASK 0x3F
+#define ROCE_INIT_FUNC_PARAMS_RESERVED0_SHIFT 2
__le32 cnp_send_timeout;
__le16 rl_offset;
u8 rl_count_log;
@@ -8109,9 +8209,24 @@ enum roce_ramrod_cmd_id {
ROCE_RAMROD_DESTROY_QP,
ROCE_RAMROD_CREATE_UD_QP,
ROCE_RAMROD_DESTROY_UD_QP,
+ ROCE_RAMROD_FUNC_UPDATE,
MAX_ROCE_RAMROD_CMD_ID
};
+/* RoCE func init ramrod data */
+struct roce_update_func_params {
+ u8 cnp_vlan_priority;
+ u8 cnp_dscp;
+ __le16 flags;
+#define ROCE_UPDATE_FUNC_PARAMS_DCQCN_NP_EN_MASK 0x1
+#define ROCE_UPDATE_FUNC_PARAMS_DCQCN_NP_EN_SHIFT 0
+#define ROCE_UPDATE_FUNC_PARAMS_DCQCN_RP_EN_MASK 0x1
+#define ROCE_UPDATE_FUNC_PARAMS_DCQCN_RP_EN_SHIFT 1
+#define ROCE_UPDATE_FUNC_PARAMS_RESERVED0_MASK 0x3FFF
+#define ROCE_UPDATE_FUNC_PARAMS_RESERVED0_SHIFT 2
+ __le32 cnp_send_timeout;
+};
+
struct e4_xstorm_roce_conn_ag_ctx_dq_ext_ld_part {
u8 reserved0;
u8 state;
@@ -11987,6 +12102,7 @@ struct public_global {
u32 running_bundle_id;
s32 external_temperature;
u32 mdump_reason;
+ u64 reserved;
u32 data_ptr;
u32 data_size;
};
@@ -12091,11 +12207,56 @@ struct public_port {
u32 transceiver_data;
#define ETH_TRANSCEIVER_STATE_MASK 0x000000FF
#define ETH_TRANSCEIVER_STATE_SHIFT 0x00000000
+#define ETH_TRANSCEIVER_STATE_OFFSET 0x00000000
#define ETH_TRANSCEIVER_STATE_UNPLUGGED 0x00000000
#define ETH_TRANSCEIVER_STATE_PRESENT 0x00000001
#define ETH_TRANSCEIVER_STATE_VALID 0x00000003
#define ETH_TRANSCEIVER_STATE_UPDATING 0x00000008
-
+#define ETH_TRANSCEIVER_TYPE_MASK 0x0000FF00
+#define ETH_TRANSCEIVER_TYPE_OFFSET 0x8
+#define ETH_TRANSCEIVER_TYPE_NONE 0x00
+#define ETH_TRANSCEIVER_TYPE_UNKNOWN 0xFF
+#define ETH_TRANSCEIVER_TYPE_1G_PCC 0x01
+#define ETH_TRANSCEIVER_TYPE_1G_ACC 0x02
+#define ETH_TRANSCEIVER_TYPE_1G_LX 0x03
+#define ETH_TRANSCEIVER_TYPE_1G_SX 0x04
+#define ETH_TRANSCEIVER_TYPE_10G_SR 0x05
+#define ETH_TRANSCEIVER_TYPE_10G_LR 0x06
+#define ETH_TRANSCEIVER_TYPE_10G_LRM 0x07
+#define ETH_TRANSCEIVER_TYPE_10G_ER 0x08
+#define ETH_TRANSCEIVER_TYPE_10G_PCC 0x09
+#define ETH_TRANSCEIVER_TYPE_10G_ACC 0x0a
+#define ETH_TRANSCEIVER_TYPE_XLPPI 0x0b
+#define ETH_TRANSCEIVER_TYPE_40G_LR4 0x0c
+#define ETH_TRANSCEIVER_TYPE_40G_SR4 0x0d
+#define ETH_TRANSCEIVER_TYPE_40G_CR4 0x0e
+#define ETH_TRANSCEIVER_TYPE_100G_AOC 0x0f
+#define ETH_TRANSCEIVER_TYPE_100G_SR4 0x10
+#define ETH_TRANSCEIVER_TYPE_100G_LR4 0x11
+#define ETH_TRANSCEIVER_TYPE_100G_ER4 0x12
+#define ETH_TRANSCEIVER_TYPE_100G_ACC 0x13
+#define ETH_TRANSCEIVER_TYPE_100G_CR4 0x14
+#define ETH_TRANSCEIVER_TYPE_4x10G_SR 0x15
+#define ETH_TRANSCEIVER_TYPE_25G_CA_N 0x16
+#define ETH_TRANSCEIVER_TYPE_25G_ACC_S 0x17
+#define ETH_TRANSCEIVER_TYPE_25G_CA_S 0x18
+#define ETH_TRANSCEIVER_TYPE_25G_ACC_M 0x19
+#define ETH_TRANSCEIVER_TYPE_25G_CA_L 0x1a
+#define ETH_TRANSCEIVER_TYPE_25G_ACC_L 0x1b
+#define ETH_TRANSCEIVER_TYPE_25G_SR 0x1c
+#define ETH_TRANSCEIVER_TYPE_25G_LR 0x1d
+#define ETH_TRANSCEIVER_TYPE_25G_AOC 0x1e
+#define ETH_TRANSCEIVER_TYPE_4x10G 0x1f
+#define ETH_TRANSCEIVER_TYPE_4x25G_CR 0x20
+#define ETH_TRANSCEIVER_TYPE_1000BASET 0x21
+#define ETH_TRANSCEIVER_TYPE_10G_BASET 0x22
+#define ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_SR 0x30
+#define ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_CR 0x31
+#define ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_LR 0x32
+#define ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_SR 0x33
+#define ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_CR 0x34
+#define ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_LR 0x35
+#define ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_AOC 0x36
u32 wol_info;
u32 wol_pkt_len;
u32 wol_pkt_details;
@@ -12160,7 +12321,7 @@ struct public_func {
#define FUNC_MF_CFG_MAX_BW_DEFAULT 0x00640000
u32 status;
-#define FUNC_STATUS_VLINK_DOWN 0x00000001
+#define FUNC_STATUS_VIRTUAL_LINK_UP 0x00000001
u32 mac_upper;
#define FUNC_MF_CFG_UPPERMAC_MASK 0x0000ffff
@@ -12582,6 +12743,7 @@ struct public_drv_mb {
#define DRV_MB_PARAM_FEATURE_SUPPORT_PORT_MASK 0x0000FFFF
#define DRV_MB_PARAM_FEATURE_SUPPORT_PORT_OFFSET 0
#define DRV_MB_PARAM_FEATURE_SUPPORT_PORT_EEE 0x00000002
+#define DRV_MB_PARAM_FEATURE_SUPPORT_FUNC_VLINK 0x00010000
u32 fw_mb_header;
#define FW_MSG_CODE_MASK 0xffff0000
@@ -12634,6 +12796,7 @@ struct public_drv_mb {
/* get MFW feature support response */
#define FW_MB_PARAM_FEATURE_SUPPORT_EEE 0x00000002
+#define FW_MB_PARAM_FEATURE_SUPPORT_VLINK 0x00010000
#define FW_MB_PARAM_LOAD_DONE_DID_EFUSE_ERROR (1 << 0)
@@ -13039,6 +13202,7 @@ struct nvm_cfg1_port {
#define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_OFFSET 0
#define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G 0x1
#define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G 0x2
+#define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G 0x4
#define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G 0x8
#define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G 0x10
#define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G 0x20
@@ -13049,6 +13213,7 @@ struct nvm_cfg1_port {
#define NVM_CFG1_PORT_DRV_LINK_SPEED_AUTONEG 0x0
#define NVM_CFG1_PORT_DRV_LINK_SPEED_1G 0x1
#define NVM_CFG1_PORT_DRV_LINK_SPEED_10G 0x2
+#define NVM_CFG1_PORT_DRV_LINK_SPEED_20G 0x3
#define NVM_CFG1_PORT_DRV_LINK_SPEED_25G 0x4
#define NVM_CFG1_PORT_DRV_LINK_SPEED_40G 0x5
#define NVM_CFG1_PORT_DRV_LINK_SPEED_50G 0x6
@@ -13079,6 +13244,13 @@ struct nvm_cfg1_port {
u32 transceiver_00;
u32 device_ids;
u32 board_cfg;
+#define NVM_CFG1_PORT_PORT_TYPE_MASK 0x000000FF
+#define NVM_CFG1_PORT_PORT_TYPE_OFFSET 0
+#define NVM_CFG1_PORT_PORT_TYPE_UNDEFINED 0x0
+#define NVM_CFG1_PORT_PORT_TYPE_MODULE 0x1
+#define NVM_CFG1_PORT_PORT_TYPE_BACKPLANE 0x2
+#define NVM_CFG1_PORT_PORT_TYPE_EXT_PHY 0x3
+#define NVM_CFG1_PORT_PORT_TYPE_MODULE_SLAVE 0x4
u32 mnm_10g_cap;
u32 mnm_10g_ctrl;
u32 mnm_10g_misc;
diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.c b/drivers/net/ethernet/qlogic/qed/qed_int.c
index af3a28ec04eb..0f0aba793352 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_int.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_int.c
@@ -228,7 +228,7 @@ static int qed_grc_attn_cb(struct qed_hwfn *p_hwfn)
attn_master_to_str(GET_FIELD(tmp, QED_GRC_ATTENTION_MASTER)),
GET_FIELD(tmp2, QED_GRC_ATTENTION_PF),
(GET_FIELD(tmp2, QED_GRC_ATTENTION_PRIV) ==
- QED_GRC_ATTENTION_PRIV_VF) ? "VF" : "(Ireelevant)",
+ QED_GRC_ATTENTION_PRIV_VF) ? "VF" : "(Irrelevant)",
GET_FIELD(tmp2, QED_GRC_ATTENTION_VF));
out:
diff --git a/drivers/net/ethernet/qlogic/qed/qed_iscsi.c b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c
index 1135387bd99d..4f8a685d1a55 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iscsi.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c
@@ -200,6 +200,7 @@ qed_sp_iscsi_func_start(struct qed_hwfn *p_hwfn,
"Cannot satisfy CQ amount. Queues requested %d, CQs available %d. Aborting function start\n",
p_params->num_queues,
p_hwfn->hw_info.feat_num[QED_ISCSI_CQ]);
+ qed_sp_destroy_request(p_hwfn, p_ent);
return -EINVAL;
}
diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index 17f3dfa2cc94..beb8e5d6401a 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -935,9 +935,8 @@ qed_iwarp_return_ep(struct qed_hwfn *p_hwfn, struct qed_iwarp_ep *ep)
}
spin_lock_bh(&p_hwfn->p_rdma_info->iwarp.iw_lock);
- list_del(&ep->list_entry);
- list_add_tail(&ep->list_entry,
- &p_hwfn->p_rdma_info->iwarp.ep_free_list);
+ list_move_tail(&ep->list_entry,
+ &p_hwfn->p_rdma_info->iwarp.ep_free_list);
spin_unlock_bh(&p_hwfn->p_rdma_info->iwarp.iw_lock);
}
@@ -1710,7 +1709,7 @@ qed_iwarp_parse_rx_pkt(struct qed_hwfn *p_hwfn,
cm_info->local_ip[0] = ntohl(iph->daddr);
cm_info->remote_ip[0] = ntohl(iph->saddr);
- cm_info->ip_version = TCP_IPV4;
+ cm_info->ip_version = QED_TCP_IPV4;
ip_hlen = (iph->ihl) * sizeof(u32);
*payload_len = ntohs(iph->tot_len) - ip_hlen;
@@ -1730,7 +1729,7 @@ qed_iwarp_parse_rx_pkt(struct qed_hwfn *p_hwfn,
cm_info->remote_ip[i] =
ntohl(ip6h->saddr.in6_u.u6_addr32[i]);
}
- cm_info->ip_version = TCP_IPV6;
+ cm_info->ip_version = QED_TCP_IPV6;
ip_hlen = sizeof(*ip6h);
*payload_len = ntohs(ip6h->payload_len);
@@ -2270,8 +2269,8 @@ static void qed_iwarp_process_pending_pkts(struct qed_hwfn *p_hwfn)
if (rc == -EBUSY)
break;
- list_del(&mpa_buf->list_entry);
- list_add_tail(&mpa_buf->list_entry, &iwarp_info->mpa_buf_list);
+ list_move_tail(&mpa_buf->list_entry,
+ &iwarp_info->mpa_buf_list);
if (rc) { /* different error, don't continue */
DP_NOTICE(p_hwfn, "process pkts failed rc=%d\n", rc);
diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.c b/drivers/net/ethernet/qlogic/qed/qed_l2.c
index 82a1bd1f8a8c..67c02ea93906 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_l2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_l2.c
@@ -740,8 +740,7 @@ int qed_sp_vport_update(struct qed_hwfn *p_hwfn,
rc = qed_sp_vport_update_rss(p_hwfn, p_ramrod, p_rss_params);
if (rc) {
- /* Return spq entry which is taken in qed_sp_init_request()*/
- qed_spq_return_entry(p_hwfn, p_ent);
+ qed_sp_destroy_request(p_hwfn, p_ent);
return rc;
}
@@ -1355,6 +1354,7 @@ qed_filter_ucast_common(struct qed_hwfn *p_hwfn,
DP_NOTICE(p_hwfn,
"%d is not supported yet\n",
p_filter_cmd->opcode);
+ qed_sp_destroy_request(p_hwfn, *pp_ent);
return -EINVAL;
}
@@ -2056,13 +2056,13 @@ qed_configure_rfs_ntuple_filter(struct qed_hwfn *p_hwfn,
} else {
rc = qed_fw_vport(p_hwfn, p_params->vport_id, &abs_vport_id);
if (rc)
- return rc;
+ goto err;
if (p_params->qid != QED_RFS_NTUPLE_QID_RSS) {
rc = qed_fw_l2_queue(p_hwfn, p_params->qid,
&abs_rx_q_id);
if (rc)
- return rc;
+ goto err;
p_ramrod->rx_qid_valid = 1;
p_ramrod->rx_qid = cpu_to_le16(abs_rx_q_id);
@@ -2083,6 +2083,10 @@ qed_configure_rfs_ntuple_filter(struct qed_hwfn *p_hwfn,
(u64)p_params->addr, p_params->length);
return qed_spq_post(p_hwfn, p_ent, NULL);
+
+err:
+ qed_sp_destroy_request(p_hwfn, p_ent);
+ return rc;
}
int qed_get_rxq_coalesce(struct qed_hwfn *p_hwfn,
diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
index 14ac9cab2653..aa633381aa47 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
@@ -63,8 +63,8 @@
#include "qed_sp.h"
#include "qed_rdma.h"
-#define QED_LL2_RX_REGISTERED(ll2) ((ll2)->rx_queue.b_cb_registred)
-#define QED_LL2_TX_REGISTERED(ll2) ((ll2)->tx_queue.b_cb_registred)
+#define QED_LL2_RX_REGISTERED(ll2) ((ll2)->rx_queue.b_cb_registered)
+#define QED_LL2_TX_REGISTERED(ll2) ((ll2)->tx_queue.b_cb_registered)
#define QED_LL2_TX_SIZE (256)
#define QED_LL2_RX_SIZE (4096)
@@ -796,7 +796,18 @@ qed_ooo_submit_tx_buffers(struct qed_hwfn *p_hwfn,
tx_pkt.vlan = p_buffer->vlan;
tx_pkt.bd_flags = bd_flags;
tx_pkt.l4_hdr_offset_w = l4_hdr_offset_w;
- tx_pkt.tx_dest = p_ll2_conn->tx_dest;
+ switch (p_ll2_conn->tx_dest) {
+ case CORE_TX_DEST_NW:
+ tx_pkt.tx_dest = QED_LL2_TX_DEST_NW;
+ break;
+ case CORE_TX_DEST_LB:
+ tx_pkt.tx_dest = QED_LL2_TX_DEST_LB;
+ break;
+ case CORE_TX_DEST_DROP:
+ default:
+ tx_pkt.tx_dest = QED_LL2_TX_DEST_DROP;
+ break;
+ }
tx_pkt.first_frag = first_frag;
tx_pkt.first_frag_len = p_buffer->packet_length;
tx_pkt.cookie = p_buffer;
@@ -1404,7 +1415,7 @@ int qed_ll2_acquire_connection(void *cxt, struct qed_ll2_acquire_data *data)
&p_hwfn->p_ll2_info[i],
&p_ll2_info->rx_queue.rx_sb_index,
&p_ll2_info->rx_queue.p_fw_cons);
- p_ll2_info->rx_queue.b_cb_registred = true;
+ p_ll2_info->rx_queue.b_cb_registered = true;
}
if (data->input.tx_num_desc) {
@@ -1413,7 +1424,7 @@ int qed_ll2_acquire_connection(void *cxt, struct qed_ll2_acquire_data *data)
&p_hwfn->p_ll2_info[i],
&p_ll2_info->tx_queue.tx_sb_index,
&p_ll2_info->tx_queue.p_fw_cons);
- p_ll2_info->tx_queue.b_cb_registred = true;
+ p_ll2_info->tx_queue.b_cb_registered = true;
}
*data->p_connection_handle = i;
@@ -1929,7 +1940,7 @@ int qed_ll2_terminate_connection(void *cxt, u8 connection_handle)
/* Stop Tx & Rx of connection, if needed */
if (QED_LL2_TX_REGISTERED(p_ll2_conn)) {
- p_ll2_conn->tx_queue.b_cb_registred = false;
+ p_ll2_conn->tx_queue.b_cb_registered = false;
smp_wmb(); /* Make sure this is seen by ll2_lb_rxq_completion */
rc = qed_sp_ll2_tx_queue_stop(p_hwfn, p_ll2_conn);
if (rc)
@@ -1940,7 +1951,7 @@ int qed_ll2_terminate_connection(void *cxt, u8 connection_handle)
}
if (QED_LL2_RX_REGISTERED(p_ll2_conn)) {
- p_ll2_conn->rx_queue.b_cb_registred = false;
+ p_ll2_conn->rx_queue.b_cb_registered = false;
smp_wmb(); /* Make sure this is seen by ll2_lb_rxq_completion */
rc = qed_sp_ll2_rx_queue_stop(p_hwfn, p_ll2_conn);
if (rc)
diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.h b/drivers/net/ethernet/qlogic/qed/qed_ll2.h
index f65817012e97..1a5c1ae01474 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.h
@@ -79,7 +79,7 @@ struct qed_ll2_rx_queue {
struct qed_chain rxq_chain;
struct qed_chain rcq_chain;
u8 rx_sb_index;
- bool b_cb_registred;
+ bool b_cb_registered;
__le16 *p_fw_cons;
struct list_head active_descq;
struct list_head free_descq;
@@ -93,7 +93,7 @@ struct qed_ll2_tx_queue {
spinlock_t lock;
struct qed_chain txq_chain;
u8 tx_sb_index;
- bool b_cb_registred;
+ bool b_cb_registered;
__le16 *p_fw_cons;
struct list_head active_descq;
struct list_head free_descq;
diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c
index 2094d86a7a08..35fd0db6a677 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_main.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_main.c
@@ -58,6 +58,7 @@
#include "qed_iscsi.h"
#include "qed_mcp.h"
+#include "qed_reg_addr.h"
#include "qed_hw.h"
#include "qed_selftest.h"
#include "qed_debug.h"
@@ -1304,6 +1305,7 @@ static int qed_set_link(struct qed_dev *cdev, struct qed_link_params *params)
struct qed_hwfn *hwfn;
struct qed_mcp_link_params *link_params;
struct qed_ptt *ptt;
+ u32 sup_caps;
int rc;
if (!cdev)
@@ -1330,23 +1332,50 @@ static int qed_set_link(struct qed_dev *cdev, struct qed_link_params *params)
link_params->speed.autoneg = params->autoneg;
if (params->override_flags & QED_LINK_OVERRIDE_SPEED_ADV_SPEEDS) {
link_params->speed.advertised_speeds = 0;
- if ((params->adv_speeds & QED_LM_1000baseT_Half_BIT) ||
- (params->adv_speeds & QED_LM_1000baseT_Full_BIT))
+ sup_caps = QED_LM_1000baseT_Full_BIT |
+ QED_LM_1000baseKX_Full_BIT |
+ QED_LM_1000baseX_Full_BIT;
+ if (params->adv_speeds & sup_caps)
link_params->speed.advertised_speeds |=
NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G;
- if (params->adv_speeds & QED_LM_10000baseKR_Full_BIT)
+ sup_caps = QED_LM_10000baseT_Full_BIT |
+ QED_LM_10000baseKR_Full_BIT |
+ QED_LM_10000baseKX4_Full_BIT |
+ QED_LM_10000baseR_FEC_BIT |
+ QED_LM_10000baseCR_Full_BIT |
+ QED_LM_10000baseSR_Full_BIT |
+ QED_LM_10000baseLR_Full_BIT |
+ QED_LM_10000baseLRM_Full_BIT;
+ if (params->adv_speeds & sup_caps)
link_params->speed.advertised_speeds |=
NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G;
- if (params->adv_speeds & QED_LM_25000baseKR_Full_BIT)
+ if (params->adv_speeds & QED_LM_20000baseKR2_Full_BIT)
+ link_params->speed.advertised_speeds |=
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G;
+ sup_caps = QED_LM_25000baseKR_Full_BIT |
+ QED_LM_25000baseCR_Full_BIT |
+ QED_LM_25000baseSR_Full_BIT;
+ if (params->adv_speeds & sup_caps)
link_params->speed.advertised_speeds |=
NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G;
- if (params->adv_speeds & QED_LM_40000baseLR4_Full_BIT)
+ sup_caps = QED_LM_40000baseLR4_Full_BIT |
+ QED_LM_40000baseKR4_Full_BIT |
+ QED_LM_40000baseCR4_Full_BIT |
+ QED_LM_40000baseSR4_Full_BIT;
+ if (params->adv_speeds & sup_caps)
link_params->speed.advertised_speeds |=
- NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G;
- if (params->adv_speeds & QED_LM_50000baseKR2_Full_BIT)
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G;
+ sup_caps = QED_LM_50000baseKR2_Full_BIT |
+ QED_LM_50000baseCR2_Full_BIT |
+ QED_LM_50000baseSR2_Full_BIT;
+ if (params->adv_speeds & sup_caps)
link_params->speed.advertised_speeds |=
NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G;
- if (params->adv_speeds & QED_LM_100000baseKR4_Full_BIT)
+ sup_caps = QED_LM_100000baseKR4_Full_BIT |
+ QED_LM_100000baseSR4_Full_BIT |
+ QED_LM_100000baseCR4_Full_BIT |
+ QED_LM_100000baseLR4_ER4_Full_BIT;
+ if (params->adv_speeds & sup_caps)
link_params->speed.advertised_speeds |=
NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G;
}
@@ -1459,12 +1488,149 @@ static int qed_get_link_data(struct qed_hwfn *hwfn,
return 0;
}
+static void qed_fill_link_capability(struct qed_hwfn *hwfn,
+ struct qed_ptt *ptt, u32 capability,
+ u32 *if_capability)
+{
+ u32 media_type, tcvr_state, tcvr_type;
+ u32 speed_mask, board_cfg;
+
+ if (qed_mcp_get_media_type(hwfn, ptt, &media_type))
+ media_type = MEDIA_UNSPECIFIED;
+
+ if (qed_mcp_get_transceiver_data(hwfn, ptt, &tcvr_state, &tcvr_type))
+ tcvr_type = ETH_TRANSCEIVER_STATE_UNPLUGGED;
+
+ if (qed_mcp_trans_speed_mask(hwfn, ptt, &speed_mask))
+ speed_mask = 0xFFFFFFFF;
+
+ if (qed_mcp_get_board_config(hwfn, ptt, &board_cfg))
+ board_cfg = NVM_CFG1_PORT_PORT_TYPE_UNDEFINED;
+
+ DP_VERBOSE(hwfn->cdev, NETIF_MSG_DRV,
+ "Media_type = 0x%x tcvr_state = 0x%x tcvr_type = 0x%x speed_mask = 0x%x board_cfg = 0x%x\n",
+ media_type, tcvr_state, tcvr_type, speed_mask, board_cfg);
+
+ switch (media_type) {
+ case MEDIA_DA_TWINAX:
+ if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G)
+ *if_capability |= QED_LM_20000baseKR2_Full_BIT;
+ /* For DAC media multiple speed capabilities are supported*/
+ capability = capability & speed_mask;
+ if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G)
+ *if_capability |= QED_LM_1000baseKX_Full_BIT;
+ if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G)
+ *if_capability |= QED_LM_10000baseCR_Full_BIT;
+ if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G)
+ *if_capability |= QED_LM_40000baseCR4_Full_BIT;
+ if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G)
+ *if_capability |= QED_LM_25000baseCR_Full_BIT;
+ if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G)
+ *if_capability |= QED_LM_50000baseCR2_Full_BIT;
+ if (capability &
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G)
+ *if_capability |= QED_LM_100000baseCR4_Full_BIT;
+ break;
+ case MEDIA_BASE_T:
+ if (board_cfg & NVM_CFG1_PORT_PORT_TYPE_EXT_PHY) {
+ if (capability &
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) {
+ *if_capability |= QED_LM_1000baseT_Full_BIT;
+ }
+ if (capability &
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) {
+ *if_capability |= QED_LM_10000baseT_Full_BIT;
+ }
+ }
+ if (board_cfg & NVM_CFG1_PORT_PORT_TYPE_MODULE) {
+ if (tcvr_type == ETH_TRANSCEIVER_TYPE_1000BASET)
+ *if_capability |= QED_LM_1000baseT_Full_BIT;
+ if (tcvr_type == ETH_TRANSCEIVER_TYPE_10G_BASET)
+ *if_capability |= QED_LM_10000baseT_Full_BIT;
+ }
+ break;
+ case MEDIA_SFP_1G_FIBER:
+ case MEDIA_SFPP_10G_FIBER:
+ case MEDIA_XFP_FIBER:
+ case MEDIA_MODULE_FIBER:
+ if (capability &
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) {
+ if ((tcvr_type == ETH_TRANSCEIVER_TYPE_1G_LX) ||
+ (tcvr_type == ETH_TRANSCEIVER_TYPE_1G_SX))
+ *if_capability |= QED_LM_1000baseKX_Full_BIT;
+ }
+ if (capability &
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G) {
+ if (tcvr_type == ETH_TRANSCEIVER_TYPE_10G_SR)
+ *if_capability |= QED_LM_10000baseSR_Full_BIT;
+ if (tcvr_type == ETH_TRANSCEIVER_TYPE_10G_LR)
+ *if_capability |= QED_LM_10000baseLR_Full_BIT;
+ if (tcvr_type == ETH_TRANSCEIVER_TYPE_10G_LRM)
+ *if_capability |= QED_LM_10000baseLRM_Full_BIT;
+ if (tcvr_type == ETH_TRANSCEIVER_TYPE_10G_ER)
+ *if_capability |= QED_LM_10000baseR_FEC_BIT;
+ }
+ if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G)
+ *if_capability |= QED_LM_20000baseKR2_Full_BIT;
+ if (capability &
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G) {
+ if (tcvr_type == ETH_TRANSCEIVER_TYPE_25G_SR)
+ *if_capability |= QED_LM_25000baseSR_Full_BIT;
+ }
+ if (capability &
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G) {
+ if (tcvr_type == ETH_TRANSCEIVER_TYPE_40G_LR4)
+ *if_capability |= QED_LM_40000baseLR4_Full_BIT;
+ if (tcvr_type == ETH_TRANSCEIVER_TYPE_40G_SR4)
+ *if_capability |= QED_LM_40000baseSR4_Full_BIT;
+ }
+ if (capability &
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G)
+ *if_capability |= QED_LM_50000baseKR2_Full_BIT;
+ if (capability &
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G) {
+ if (tcvr_type == ETH_TRANSCEIVER_TYPE_100G_SR4)
+ *if_capability |= QED_LM_100000baseSR4_Full_BIT;
+ }
+
+ break;
+ case MEDIA_KR:
+ if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G)
+ *if_capability |= QED_LM_20000baseKR2_Full_BIT;
+ if (capability &
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G)
+ *if_capability |= QED_LM_1000baseKX_Full_BIT;
+ if (capability &
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G)
+ *if_capability |= QED_LM_10000baseKR_Full_BIT;
+ if (capability &
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G)
+ *if_capability |= QED_LM_25000baseKR_Full_BIT;
+ if (capability &
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G)
+ *if_capability |= QED_LM_40000baseKR4_Full_BIT;
+ if (capability &
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G)
+ *if_capability |= QED_LM_50000baseKR2_Full_BIT;
+ if (capability &
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G)
+ *if_capability |= QED_LM_100000baseKR4_Full_BIT;
+ break;
+ case MEDIA_UNSPECIFIED:
+ case MEDIA_NOT_PRESENT:
+ DP_VERBOSE(hwfn->cdev, QED_MSG_DEBUG,
+ "Unknown media and transceiver type;\n");
+ break;
+ }
+}
+
static void qed_fill_link(struct qed_hwfn *hwfn,
+ struct qed_ptt *ptt,
struct qed_link_output *if_link)
{
+ struct qed_mcp_link_capabilities link_caps;
struct qed_mcp_link_params params;
struct qed_mcp_link_state link;
- struct qed_mcp_link_capabilities link_caps;
u32 media_type;
memset(if_link, 0, sizeof(*if_link));
@@ -1495,52 +1661,20 @@ static void qed_fill_link(struct qed_hwfn *hwfn,
if_link->advertised_caps |= QED_LM_Autoneg_BIT;
else
if_link->advertised_caps &= ~QED_LM_Autoneg_BIT;
- if (params.speed.advertised_speeds &
- NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G)
- if_link->advertised_caps |= QED_LM_1000baseT_Half_BIT |
- QED_LM_1000baseT_Full_BIT;
- if (params.speed.advertised_speeds &
- NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G)
- if_link->advertised_caps |= QED_LM_10000baseKR_Full_BIT;
- if (params.speed.advertised_speeds &
- NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G)
- if_link->advertised_caps |= QED_LM_25000baseKR_Full_BIT;
- if (params.speed.advertised_speeds &
- NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G)
- if_link->advertised_caps |= QED_LM_40000baseLR4_Full_BIT;
- if (params.speed.advertised_speeds &
- NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G)
- if_link->advertised_caps |= QED_LM_50000baseKR2_Full_BIT;
- if (params.speed.advertised_speeds &
- NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G)
- if_link->advertised_caps |= QED_LM_100000baseKR4_Full_BIT;
-
- if (link_caps.speed_capabilities &
- NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G)
- if_link->supported_caps |= QED_LM_1000baseT_Half_BIT |
- QED_LM_1000baseT_Full_BIT;
- if (link_caps.speed_capabilities &
- NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G)
- if_link->supported_caps |= QED_LM_10000baseKR_Full_BIT;
- if (link_caps.speed_capabilities &
- NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G)
- if_link->supported_caps |= QED_LM_25000baseKR_Full_BIT;
- if (link_caps.speed_capabilities &
- NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G)
- if_link->supported_caps |= QED_LM_40000baseLR4_Full_BIT;
- if (link_caps.speed_capabilities &
- NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G)
- if_link->supported_caps |= QED_LM_50000baseKR2_Full_BIT;
- if (link_caps.speed_capabilities &
- NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G)
- if_link->supported_caps |= QED_LM_100000baseKR4_Full_BIT;
+
+ /* Fill link advertised capability*/
+ qed_fill_link_capability(hwfn, ptt, params.speed.advertised_speeds,
+ &if_link->advertised_caps);
+ /* Fill link supported capability*/
+ qed_fill_link_capability(hwfn, ptt, link_caps.speed_capabilities,
+ &if_link->supported_caps);
if (link.link_up)
if_link->speed = link.speed;
/* TODO - fill duplex properly */
if_link->duplex = DUPLEX_FULL;
- qed_mcp_get_media_type(hwfn->cdev, &media_type);
+ qed_mcp_get_media_type(hwfn, ptt, &media_type);
if_link->port = qed_get_port_type(media_type);
if_link->autoneg = params.speed.autoneg;
@@ -1553,12 +1687,13 @@ static void qed_fill_link(struct qed_hwfn *hwfn,
if_link->pause_config |= QED_LINK_PAUSE_TX_ENABLE;
/* Link partner capabilities */
- if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_1G_HD)
- if_link->lp_caps |= QED_LM_1000baseT_Half_BIT;
- if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_1G_FD)
+ if (link.partner_adv_speed &
+ QED_LINK_PARTNER_SPEED_1G_FD)
if_link->lp_caps |= QED_LM_1000baseT_Full_BIT;
if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_10G)
if_link->lp_caps |= QED_LM_10000baseKR_Full_BIT;
+ if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_20G)
+ if_link->lp_caps |= QED_LM_20000baseKR2_Full_BIT;
if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_25G)
if_link->lp_caps |= QED_LM_25000baseKR_Full_BIT;
if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_40G)
@@ -1596,21 +1731,34 @@ static void qed_fill_link(struct qed_hwfn *hwfn,
static void qed_get_current_link(struct qed_dev *cdev,
struct qed_link_output *if_link)
{
+ struct qed_hwfn *hwfn;
+ struct qed_ptt *ptt;
int i;
- qed_fill_link(&cdev->hwfns[0], if_link);
+ hwfn = &cdev->hwfns[0];
+ if (IS_PF(cdev)) {
+ ptt = qed_ptt_acquire(hwfn);
+ if (ptt) {
+ qed_fill_link(hwfn, ptt, if_link);
+ qed_ptt_release(hwfn, ptt);
+ } else {
+ DP_NOTICE(hwfn, "Failed to fill link; No PTT\n");
+ }
+ } else {
+ qed_fill_link(hwfn, NULL, if_link);
+ }
for_each_hwfn(cdev, i)
qed_inform_vf_link_state(&cdev->hwfns[i]);
}
-void qed_link_update(struct qed_hwfn *hwfn)
+void qed_link_update(struct qed_hwfn *hwfn, struct qed_ptt *ptt)
{
void *cookie = hwfn->cdev->ops_cookie;
struct qed_common_cb_ops *op = hwfn->cdev->protocol_ops.common;
struct qed_link_output if_link;
- qed_fill_link(hwfn, &if_link);
+ qed_fill_link(hwfn, ptt, &if_link);
qed_inform_vf_link_state(hwfn);
if (IS_LEAD_HWFN(hwfn) && cookie)
diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.c b/drivers/net/ethernet/qlogic/qed/qed_mcp.c
index 58c7eb9d8e1b..a96364df4320 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_mcp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.c
@@ -1247,6 +1247,52 @@ static void qed_mcp_read_eee_config(struct qed_hwfn *p_hwfn,
p_link->eee_lp_adv_caps |= QED_EEE_10G_ADV;
}
+static u32 qed_mcp_get_shmem_func(struct qed_hwfn *p_hwfn,
+ struct qed_ptt *p_ptt,
+ struct public_func *p_data, int pfid)
+{
+ u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base,
+ PUBLIC_FUNC);
+ u32 mfw_path_offsize = qed_rd(p_hwfn, p_ptt, addr);
+ u32 func_addr;
+ u32 i, size;
+
+ func_addr = SECTION_ADDR(mfw_path_offsize, pfid);
+ memset(p_data, 0, sizeof(*p_data));
+
+ size = min_t(u32, sizeof(*p_data), QED_SECTION_SIZE(mfw_path_offsize));
+ for (i = 0; i < size / sizeof(u32); i++)
+ ((u32 *)p_data)[i] = qed_rd(p_hwfn, p_ptt,
+ func_addr + (i << 2));
+ return size;
+}
+
+static void qed_read_pf_bandwidth(struct qed_hwfn *p_hwfn,
+ struct public_func *p_shmem_info)
+{
+ struct qed_mcp_function_info *p_info;
+
+ p_info = &p_hwfn->mcp_info->func_info;
+
+ p_info->bandwidth_min = QED_MFW_GET_FIELD(p_shmem_info->config,
+ FUNC_MF_CFG_MIN_BW);
+ if (p_info->bandwidth_min < 1 || p_info->bandwidth_min > 100) {
+ DP_INFO(p_hwfn,
+ "bandwidth minimum out of bounds [%02x]. Set to 1\n",
+ p_info->bandwidth_min);
+ p_info->bandwidth_min = 1;
+ }
+
+ p_info->bandwidth_max = QED_MFW_GET_FIELD(p_shmem_info->config,
+ FUNC_MF_CFG_MAX_BW);
+ if (p_info->bandwidth_max < 1 || p_info->bandwidth_max > 100) {
+ DP_INFO(p_hwfn,
+ "bandwidth maximum out of bounds [%02x]. Set to 100\n",
+ p_info->bandwidth_max);
+ p_info->bandwidth_max = 100;
+ }
+}
+
static void qed_mcp_handle_link_change(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt, bool b_reset)
{
@@ -1274,10 +1320,29 @@ static void qed_mcp_handle_link_change(struct qed_hwfn *p_hwfn,
goto out;
}
- if (p_hwfn->b_drv_link_init)
- p_link->link_up = !!(status & LINK_STATUS_LINK_UP);
- else
+ if (p_hwfn->b_drv_link_init) {
+ /* Link indication with modern MFW arrives as per-PF
+ * indication.
+ */
+ if (p_hwfn->mcp_info->capabilities &
+ FW_MB_PARAM_FEATURE_SUPPORT_VLINK) {
+ struct public_func shmem_info;
+
+ qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info,
+ MCP_PF_ID(p_hwfn));
+ p_link->link_up = !!(shmem_info.status &
+ FUNC_STATUS_VIRTUAL_LINK_UP);
+ qed_read_pf_bandwidth(p_hwfn, &shmem_info);
+ DP_VERBOSE(p_hwfn, NETIF_MSG_LINK,
+ "Virtual link_up = %d\n", p_link->link_up);
+ } else {
+ p_link->link_up = !!(status & LINK_STATUS_LINK_UP);
+ DP_VERBOSE(p_hwfn, NETIF_MSG_LINK,
+ "Physical link_up = %d\n", p_link->link_up);
+ }
+ } else {
p_link->link_up = false;
+ }
p_link->full_duplex = true;
switch ((status & LINK_STATUS_SPEED_AND_DUPLEX_MASK)) {
@@ -1382,7 +1447,7 @@ static void qed_mcp_handle_link_change(struct qed_hwfn *p_hwfn,
if (p_hwfn->mcp_info->capabilities & FW_MB_PARAM_FEATURE_SUPPORT_EEE)
qed_mcp_read_eee_config(p_hwfn, p_ptt, p_link);
- qed_link_update(p_hwfn);
+ qed_link_update(p_hwfn, p_ptt);
out:
spin_unlock_bh(&p_hwfn->mcp_info->link_lock);
}
@@ -1504,53 +1569,6 @@ static void qed_mcp_send_protocol_stats(struct qed_hwfn *p_hwfn,
qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params);
}
-static void qed_read_pf_bandwidth(struct qed_hwfn *p_hwfn,
- struct public_func *p_shmem_info)
-{
- struct qed_mcp_function_info *p_info;
-
- p_info = &p_hwfn->mcp_info->func_info;
-
- p_info->bandwidth_min = (p_shmem_info->config &
- FUNC_MF_CFG_MIN_BW_MASK) >>
- FUNC_MF_CFG_MIN_BW_SHIFT;
- if (p_info->bandwidth_min < 1 || p_info->bandwidth_min > 100) {
- DP_INFO(p_hwfn,
- "bandwidth minimum out of bounds [%02x]. Set to 1\n",
- p_info->bandwidth_min);
- p_info->bandwidth_min = 1;
- }
-
- p_info->bandwidth_max = (p_shmem_info->config &
- FUNC_MF_CFG_MAX_BW_MASK) >>
- FUNC_MF_CFG_MAX_BW_SHIFT;
- if (p_info->bandwidth_max < 1 || p_info->bandwidth_max > 100) {
- DP_INFO(p_hwfn,
- "bandwidth maximum out of bounds [%02x]. Set to 100\n",
- p_info->bandwidth_max);
- p_info->bandwidth_max = 100;
- }
-}
-
-static u32 qed_mcp_get_shmem_func(struct qed_hwfn *p_hwfn,
- struct qed_ptt *p_ptt,
- struct public_func *p_data, int pfid)
-{
- u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base,
- PUBLIC_FUNC);
- u32 mfw_path_offsize = qed_rd(p_hwfn, p_ptt, addr);
- u32 func_addr = SECTION_ADDR(mfw_path_offsize, pfid);
- u32 i, size;
-
- memset(p_data, 0, sizeof(*p_data));
-
- size = min_t(u32, sizeof(*p_data), QED_SECTION_SIZE(mfw_path_offsize));
- for (i = 0; i < size / sizeof(u32); i++)
- ((u32 *)p_data)[i] = qed_rd(p_hwfn, p_ptt,
- func_addr + (i << 2));
- return size;
-}
-
static void qed_mcp_update_bw(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
{
struct qed_mcp_function_info *p_info;
@@ -1849,12 +1867,12 @@ int qed_mcp_get_mbi_ver(struct qed_hwfn *p_hwfn,
return 0;
}
-int qed_mcp_get_media_type(struct qed_dev *cdev, u32 *p_media_type)
+int qed_mcp_get_media_type(struct qed_hwfn *p_hwfn,
+ struct qed_ptt *p_ptt, u32 *p_media_type)
{
- struct qed_hwfn *p_hwfn = &cdev->hwfns[0];
- struct qed_ptt *p_ptt;
+ *p_media_type = MEDIA_UNSPECIFIED;
- if (IS_VF(cdev))
+ if (IS_VF(p_hwfn->cdev))
return -EINVAL;
if (!qed_mcp_is_init(p_hwfn)) {
@@ -1862,16 +1880,198 @@ int qed_mcp_get_media_type(struct qed_dev *cdev, u32 *p_media_type)
return -EBUSY;
}
- *p_media_type = MEDIA_UNSPECIFIED;
+ if (!p_ptt) {
+ *p_media_type = MEDIA_UNSPECIFIED;
+ return -EINVAL;
+ }
- p_ptt = qed_ptt_acquire(p_hwfn);
- if (!p_ptt)
+ *p_media_type = qed_rd(p_hwfn, p_ptt,
+ p_hwfn->mcp_info->port_addr +
+ offsetof(struct public_port,
+ media_type));
+
+ return 0;
+}
+
+int qed_mcp_get_transceiver_data(struct qed_hwfn *p_hwfn,
+ struct qed_ptt *p_ptt,
+ u32 *p_transceiver_state,
+ u32 *p_transceiver_type)
+{
+ u32 transceiver_info;
+
+ *p_transceiver_type = ETH_TRANSCEIVER_TYPE_NONE;
+ *p_transceiver_state = ETH_TRANSCEIVER_STATE_UPDATING;
+
+ if (IS_VF(p_hwfn->cdev))
+ return -EINVAL;
+
+ if (!qed_mcp_is_init(p_hwfn)) {
+ DP_NOTICE(p_hwfn, "MFW is not initialized!\n");
return -EBUSY;
+ }
- *p_media_type = qed_rd(p_hwfn, p_ptt, p_hwfn->mcp_info->port_addr +
- offsetof(struct public_port, media_type));
+ transceiver_info = qed_rd(p_hwfn, p_ptt,
+ p_hwfn->mcp_info->port_addr +
+ offsetof(struct public_port,
+ transceiver_data));
- qed_ptt_release(p_hwfn, p_ptt);
+ *p_transceiver_state = (transceiver_info &
+ ETH_TRANSCEIVER_STATE_MASK) >>
+ ETH_TRANSCEIVER_STATE_OFFSET;
+
+ if (*p_transceiver_state == ETH_TRANSCEIVER_STATE_PRESENT)
+ *p_transceiver_type = (transceiver_info &
+ ETH_TRANSCEIVER_TYPE_MASK) >>
+ ETH_TRANSCEIVER_TYPE_OFFSET;
+ else
+ *p_transceiver_type = ETH_TRANSCEIVER_TYPE_UNKNOWN;
+
+ return 0;
+}
+static bool qed_is_transceiver_ready(u32 transceiver_state,
+ u32 transceiver_type)
+{
+ if ((transceiver_state & ETH_TRANSCEIVER_STATE_PRESENT) &&
+ ((transceiver_state & ETH_TRANSCEIVER_STATE_UPDATING) == 0x0) &&
+ (transceiver_type != ETH_TRANSCEIVER_TYPE_NONE))
+ return true;
+
+ return false;
+}
+
+int qed_mcp_trans_speed_mask(struct qed_hwfn *p_hwfn,
+ struct qed_ptt *p_ptt, u32 *p_speed_mask)
+{
+ u32 transceiver_type, transceiver_state;
+ int ret;
+
+ ret = qed_mcp_get_transceiver_data(p_hwfn, p_ptt, &transceiver_state,
+ &transceiver_type);
+ if (ret)
+ return ret;
+
+ if (qed_is_transceiver_ready(transceiver_state, transceiver_type) ==
+ false)
+ return -EINVAL;
+
+ switch (transceiver_type) {
+ case ETH_TRANSCEIVER_TYPE_1G_LX:
+ case ETH_TRANSCEIVER_TYPE_1G_SX:
+ case ETH_TRANSCEIVER_TYPE_1G_PCC:
+ case ETH_TRANSCEIVER_TYPE_1G_ACC:
+ case ETH_TRANSCEIVER_TYPE_1000BASET:
+ *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G;
+ break;
+ case ETH_TRANSCEIVER_TYPE_10G_SR:
+ case ETH_TRANSCEIVER_TYPE_10G_LR:
+ case ETH_TRANSCEIVER_TYPE_10G_LRM:
+ case ETH_TRANSCEIVER_TYPE_10G_ER:
+ case ETH_TRANSCEIVER_TYPE_10G_PCC:
+ case ETH_TRANSCEIVER_TYPE_10G_ACC:
+ case ETH_TRANSCEIVER_TYPE_4x10G:
+ *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G;
+ break;
+ case ETH_TRANSCEIVER_TYPE_40G_LR4:
+ case ETH_TRANSCEIVER_TYPE_40G_SR4:
+ case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_SR:
+ case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_LR:
+ *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G |
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G;
+ break;
+ case ETH_TRANSCEIVER_TYPE_100G_AOC:
+ case ETH_TRANSCEIVER_TYPE_100G_SR4:
+ case ETH_TRANSCEIVER_TYPE_100G_LR4:
+ case ETH_TRANSCEIVER_TYPE_100G_ER4:
+ case ETH_TRANSCEIVER_TYPE_100G_ACC:
+ *p_speed_mask =
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G |
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G;
+ break;
+ case ETH_TRANSCEIVER_TYPE_25G_SR:
+ case ETH_TRANSCEIVER_TYPE_25G_LR:
+ case ETH_TRANSCEIVER_TYPE_25G_AOC:
+ case ETH_TRANSCEIVER_TYPE_25G_ACC_S:
+ case ETH_TRANSCEIVER_TYPE_25G_ACC_M:
+ case ETH_TRANSCEIVER_TYPE_25G_ACC_L:
+ *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G;
+ break;
+ case ETH_TRANSCEIVER_TYPE_25G_CA_N:
+ case ETH_TRANSCEIVER_TYPE_25G_CA_S:
+ case ETH_TRANSCEIVER_TYPE_25G_CA_L:
+ case ETH_TRANSCEIVER_TYPE_4x25G_CR:
+ *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G |
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G |
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G;
+ break;
+ case ETH_TRANSCEIVER_TYPE_40G_CR4:
+ case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_CR:
+ *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G |
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G |
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G;
+ break;
+ case ETH_TRANSCEIVER_TYPE_100G_CR4:
+ case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_CR:
+ *p_speed_mask =
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G |
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G |
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G |
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G |
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G |
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G |
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G;
+ break;
+ case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_SR:
+ case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_LR:
+ case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_AOC:
+ *p_speed_mask =
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G |
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G |
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G |
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G;
+ break;
+ case ETH_TRANSCEIVER_TYPE_XLPPI:
+ *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G;
+ break;
+ case ETH_TRANSCEIVER_TYPE_10G_BASET:
+ *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G |
+ NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G;
+ break;
+ default:
+ DP_INFO(p_hwfn, "Unknown transceiver type 0x%x\n",
+ transceiver_type);
+ *p_speed_mask = 0xff;
+ break;
+ }
+
+ return 0;
+}
+
+int qed_mcp_get_board_config(struct qed_hwfn *p_hwfn,
+ struct qed_ptt *p_ptt, u32 *p_board_config)
+{
+ u32 nvm_cfg_addr, nvm_cfg1_offset, port_cfg_addr;
+
+ if (IS_VF(p_hwfn->cdev))
+ return -EINVAL;
+
+ if (!qed_mcp_is_init(p_hwfn)) {
+ DP_NOTICE(p_hwfn, "MFW is not initialized!\n");
+ return -EBUSY;
+ }
+ if (!p_ptt) {
+ *p_board_config = NVM_CFG1_PORT_PORT_TYPE_UNDEFINED;
+ return -EINVAL;
+ }
+
+ nvm_cfg_addr = qed_rd(p_hwfn, p_ptt, MISC_REG_GEN_PURP_CR0);
+ nvm_cfg1_offset = qed_rd(p_hwfn, p_ptt, nvm_cfg_addr + 4);
+ port_cfg_addr = MCP_REG_SCRATCH + nvm_cfg1_offset +
+ offsetof(struct nvm_cfg1, port[MFW_PORT(p_hwfn)]);
+ *p_board_config = qed_rd(p_hwfn, p_ptt,
+ port_cfg_addr +
+ offsetof(struct nvm_cfg1_port,
+ board_cfg));
return 0;
}
@@ -3351,7 +3551,8 @@ int qed_mcp_set_capabilities(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
{
u32 mcp_resp, mcp_param, features;
- features = DRV_MB_PARAM_FEATURE_SUPPORT_PORT_EEE;
+ features = DRV_MB_PARAM_FEATURE_SUPPORT_PORT_EEE |
+ DRV_MB_PARAM_FEATURE_SUPPORT_FUNC_VLINK;
return qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_FEATURE_SUPPORT,
features, &mcp_resp, &mcp_param);
diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.h b/drivers/net/ethernet/qlogic/qed/qed_mcp.h
index 85e6b3989e7a..1adfe52b3905 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_mcp.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.h
@@ -322,14 +322,61 @@ int qed_mcp_get_mbi_ver(struct qed_hwfn *p_hwfn,
* @brief Get media type value of the port.
*
* @param cdev - qed dev pointer
+ * @param p_ptt
* @param mfw_ver - media type value
*
* @return int -
* 0 - Operation was successul.
* -EBUSY - Operation failed
*/
-int qed_mcp_get_media_type(struct qed_dev *cdev,
- u32 *media_type);
+int qed_mcp_get_media_type(struct qed_hwfn *p_hwfn,
+ struct qed_ptt *p_ptt, u32 *media_type);
+
+/**
+ * @brief Get transceiver data of the port.
+ *
+ * @param cdev - qed dev pointer
+ * @param p_ptt
+ * @param p_transceiver_state - transceiver state.
+ * @param p_transceiver_type - media type value
+ *
+ * @return int -
+ * 0 - Operation was successful.
+ * -EBUSY - Operation failed
+ */
+int qed_mcp_get_transceiver_data(struct qed_hwfn *p_hwfn,
+ struct qed_ptt *p_ptt,
+ u32 *p_transceiver_state,
+ u32 *p_tranceiver_type);
+
+/**
+ * @brief Get transceiver supported speed mask.
+ *
+ * @param cdev - qed dev pointer
+ * @param p_ptt
+ * @param p_speed_mask - Bit mask of all supported speeds.
+ *
+ * @return int -
+ * 0 - Operation was successful.
+ * -EBUSY - Operation failed
+ */
+
+int qed_mcp_trans_speed_mask(struct qed_hwfn *p_hwfn,
+ struct qed_ptt *p_ptt, u32 *p_speed_mask);
+
+/**
+ * @brief Get board configuration.
+ *
+ * @param cdev - qed dev pointer
+ * @param p_ptt
+ * @param p_board_config - Board config.
+ *
+ * @return int -
+ * 0 - Operation was successful.
+ * -EBUSY - Operation failed
+ */
+int qed_mcp_get_board_config(struct qed_hwfn *p_hwfn,
+ struct qed_ptt *p_ptt, u32 *p_board_config);
/**
* @brief General function for sending commands to the MCP
diff --git a/drivers/net/ethernet/qlogic/qed/qed_ooo.c b/drivers/net/ethernet/qlogic/qed/qed_ooo.c
index 6172354b451c..ffac4ac87394 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ooo.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_ooo.c
@@ -211,9 +211,8 @@ void qed_ooo_release_connection_isles(struct qed_hwfn *p_hwfn,
if (!p_buffer)
break;
- list_del(&p_buffer->list_entry);
- list_add_tail(&p_buffer->list_entry,
- &p_ooo_info->free_buffers_list);
+ list_move_tail(&p_buffer->list_entry,
+ &p_ooo_info->free_buffers_list);
}
list_add_tail(&p_isle->list_entry,
&p_ooo_info->free_isles_list);
@@ -247,9 +246,8 @@ void qed_ooo_release_all_isles(struct qed_hwfn *p_hwfn,
if (!p_buffer)
break;
- list_del(&p_buffer->list_entry);
- list_add_tail(&p_buffer->list_entry,
- &p_ooo_info->free_buffers_list);
+ list_move_tail(&p_buffer->list_entry,
+ &p_ooo_info->free_buffers_list);
}
list_add_tail(&p_isle->list_entry,
&p_ooo_info->free_isles_list);
@@ -353,11 +351,9 @@ void qed_ooo_delete_isles(struct qed_hwfn *p_hwfn,
struct qed_ooo_info *p_ooo_info,
u32 cid, u8 drop_isle, u8 drop_size)
{
- struct qed_ooo_archipelago *p_archipelago = NULL;
struct qed_ooo_isle *p_isle = NULL;
u8 isle_idx;
- p_archipelago = qed_ooo_seek_archipelago(p_hwfn, p_ooo_info, cid);
for (isle_idx = 0; isle_idx < drop_size; isle_idx++) {
p_isle = qed_ooo_seek_isle(p_hwfn, p_ooo_info, cid, drop_isle);
if (!p_isle) {
@@ -462,7 +458,6 @@ void qed_ooo_add_new_buffer(struct qed_hwfn *p_hwfn,
void qed_ooo_join_isles(struct qed_hwfn *p_hwfn,
struct qed_ooo_info *p_ooo_info, u32 cid, u8 left_isle)
{
- struct qed_ooo_archipelago *p_archipelago = NULL;
struct qed_ooo_isle *p_right_isle = NULL;
struct qed_ooo_isle *p_left_isle = NULL;
@@ -475,7 +470,6 @@ void qed_ooo_join_isles(struct qed_hwfn *p_hwfn,
return;
}
- p_archipelago = qed_ooo_seek_archipelago(p_hwfn, p_ooo_info, cid);
list_del(&p_right_isle->list_entry);
p_ooo_info->cur_isles_number--;
if (left_isle) {
diff --git a/drivers/net/ethernet/qlogic/qed/qed_rdma.c b/drivers/net/ethernet/qlogic/qed/qed_rdma.c
index be941cfaa2d4..62113438c880 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_rdma.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_rdma.c
@@ -228,7 +228,7 @@ static int qed_rdma_alloc(struct qed_hwfn *p_hwfn,
num_cons, "Toggle");
if (rc) {
DP_VERBOSE(p_hwfn, QED_MSG_RDMA,
- "Failed to allocate toogle bits, rc = %d\n", rc);
+ "Failed to allocate toggle bits, rc = %d\n", rc);
goto free_cq_map;
}
@@ -1514,6 +1514,7 @@ qed_rdma_register_tid(void *rdma_cxt,
default:
rc = -EINVAL;
DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "rc = %d\n", rc);
+ qed_sp_destroy_request(p_hwfn, p_ent);
return rc;
}
SET_FIELD(p_ramrod->flags1,
diff --git a/drivers/net/ethernet/qlogic/qed/qed_roce.c b/drivers/net/ethernet/qlogic/qed/qed_roce.c
index 7d7a64c55ff1..e49fada85410 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_roce.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_roce.c
@@ -140,23 +140,16 @@ static void qed_rdma_copy_gids(struct qed_rdma_qp *qp, __le32 *src_gid,
static enum roce_flavor qed_roce_mode_to_flavor(enum roce_mode roce_mode)
{
- enum roce_flavor flavor;
-
switch (roce_mode) {
case ROCE_V1:
- flavor = PLAIN_ROCE;
- break;
+ return PLAIN_ROCE;
case ROCE_V2_IPV4:
- flavor = RROCE_IPV4;
- break;
+ return RROCE_IPV4;
case ROCE_V2_IPV6:
- flavor = ROCE_V2_IPV6;
- break;
+ return RROCE_IPV6;
default:
- flavor = MAX_ROCE_MODE;
- break;
+ return MAX_ROCE_FLAVOR;
}
- return flavor;
}
static void qed_roce_free_cid_pair(struct qed_hwfn *p_hwfn, u16 cid)
@@ -752,6 +745,7 @@ static int qed_roce_sp_destroy_qp_responder(struct qed_hwfn *p_hwfn,
DP_NOTICE(p_hwfn,
"qed destroy responder failed: cannot allocate memory (ramrod). rc = %d\n",
rc);
+ qed_sp_destroy_request(p_hwfn, p_ent);
return rc;
}
diff --git a/drivers/net/ethernet/qlogic/qed/qed_sp.h b/drivers/net/ethernet/qlogic/qed/qed_sp.h
index e95431f6acd4..3157c0d99441 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_sp.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_sp.h
@@ -167,6 +167,9 @@ struct qed_spq_entry {
enum spq_mode comp_mode;
struct qed_spq_comp_cb comp_cb;
struct qed_spq_comp_done comp_done; /* SPQ_MODE_EBLOCK */
+
+ /* Posted entry for unlimited list entry in EBLOCK mode */
+ struct qed_spq_entry *post_ent;
};
struct qed_eq {
@@ -396,6 +399,17 @@ struct qed_sp_init_data {
struct qed_spq_comp_cb *p_comp_data;
};
+/**
+ * @brief Returns a SPQ entry to the pool / frees the entry if allocated.
+ * Should be called on in error flows after initializing the SPQ entry
+ * and before posting it.
+ *
+ * @param p_hwfn
+ * @param p_ent
+ */
+void qed_sp_destroy_request(struct qed_hwfn *p_hwfn,
+ struct qed_spq_entry *p_ent);
+
int qed_sp_init_request(struct qed_hwfn *p_hwfn,
struct qed_spq_entry **pp_ent,
u8 cmd,
diff --git a/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c b/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c
index 8de644b4721e..888274fa208b 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c
@@ -47,6 +47,19 @@
#include "qed_sp.h"
#include "qed_sriov.h"
+void qed_sp_destroy_request(struct qed_hwfn *p_hwfn,
+ struct qed_spq_entry *p_ent)
+{
+ /* qed_spq_get_entry() can either get an entry from the free_pool,
+ * or, if no entries are left, allocate a new entry and add it to
+ * the unlimited_pending list.
+ */
+ if (p_ent->queue == &p_hwfn->p_spq->unlimited_pending)
+ kfree(p_ent);
+ else
+ qed_spq_return_entry(p_hwfn, p_ent);
+}
+
int qed_sp_init_request(struct qed_hwfn *p_hwfn,
struct qed_spq_entry **pp_ent,
u8 cmd, u8 protocol, struct qed_sp_init_data *p_data)
@@ -80,7 +93,7 @@ int qed_sp_init_request(struct qed_hwfn *p_hwfn,
case QED_SPQ_MODE_BLOCK:
if (!p_data->p_comp_data)
- return -EINVAL;
+ goto err;
p_ent->comp_cb.cookie = p_data->p_comp_data->cookie;
break;
@@ -95,7 +108,7 @@ int qed_sp_init_request(struct qed_hwfn *p_hwfn,
default:
DP_NOTICE(p_hwfn, "Unknown SPQE completion mode %d\n",
p_ent->comp_mode);
- return -EINVAL;
+ goto err;
}
DP_VERBOSE(p_hwfn, QED_MSG_SPQ,
@@ -109,6 +122,11 @@ int qed_sp_init_request(struct qed_hwfn *p_hwfn,
memset(&p_ent->ramrod, 0, sizeof(p_ent->ramrod));
return 0;
+
+err:
+ qed_sp_destroy_request(p_hwfn, p_ent);
+
+ return -EINVAL;
}
static enum tunnel_clss qed_tunn_clss_to_fw_clss(u8 type)
@@ -154,7 +172,7 @@ qed_set_pf_update_tunn_mode(struct qed_tunnel_info *p_tun,
static void qed_set_tunn_cls_info(struct qed_tunnel_info *p_tun,
struct qed_tunnel_info *p_src)
{
- enum tunnel_clss type;
+ int type;
p_tun->b_update_rx_cls = p_src->b_update_rx_cls;
p_tun->b_update_tx_cls = p_src->b_update_tx_cls;
diff --git a/drivers/net/ethernet/qlogic/qed/qed_spq.c b/drivers/net/ethernet/qlogic/qed/qed_spq.c
index 1673fc90027f..0a9c5bb0fa48 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_spq.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_spq.c
@@ -142,6 +142,7 @@ static int qed_spq_block(struct qed_hwfn *p_hwfn,
DP_INFO(p_hwfn, "Ramrod is stuck, requesting MCP drain\n");
rc = qed_mcp_drain(p_hwfn, p_ptt);
+ qed_ptt_release(p_hwfn, p_ptt);
if (rc) {
DP_NOTICE(p_hwfn, "MCP drain failed\n");
goto err;
@@ -150,18 +151,15 @@ static int qed_spq_block(struct qed_hwfn *p_hwfn,
/* Retry after drain */
rc = __qed_spq_block(p_hwfn, p_ent, p_fw_ret, true);
if (!rc)
- goto out;
+ return 0;
comp_done = (struct qed_spq_comp_done *)p_ent->comp_cb.cookie;
- if (comp_done->done == 1)
+ if (comp_done->done == 1) {
if (p_fw_ret)
*p_fw_ret = comp_done->fw_return_code;
-out:
- qed_ptt_release(p_hwfn, p_ptt);
- return 0;
-
+ return 0;
+ }
err:
- qed_ptt_release(p_hwfn, p_ptt);
DP_NOTICE(p_hwfn,
"Ramrod is stuck [CID %08x cmd %02x protocol %02x echo %04x]\n",
le32_to_cpu(p_ent->elem.hdr.cid),
@@ -685,6 +683,8 @@ static int qed_spq_add_entry(struct qed_hwfn *p_hwfn,
/* EBLOCK responsible to free the allocated p_ent */
if (p_ent->comp_mode != QED_SPQ_MODE_EBLOCK)
kfree(p_ent);
+ else
+ p_ent->post_ent = p_en2;
p_ent = p_en2;
}
@@ -730,8 +730,7 @@ static int qed_spq_post_list(struct qed_hwfn *p_hwfn,
!list_empty(head)) {
struct qed_spq_entry *p_ent =
list_first_entry(head, struct qed_spq_entry, list);
- list_del(&p_ent->list);
- list_add_tail(&p_ent->list, &p_spq->completion_pending);
+ list_move_tail(&p_ent->list, &p_spq->completion_pending);
p_spq->comp_sent_count++;
rc = qed_spq_hw_post(p_hwfn, p_spq, p_ent);
@@ -768,6 +767,25 @@ static int qed_spq_pend_post(struct qed_hwfn *p_hwfn)
SPQ_HIGH_PRI_RESERVE_DEFAULT);
}
+/* Avoid overriding of SPQ entries when getting out-of-order completions, by
+ * marking the completions in a bitmap and increasing the chain consumer only
+ * for the first successive completed entries.
+ */
+static void qed_spq_comp_bmap_update(struct qed_hwfn *p_hwfn, __le16 echo)
+{
+ u16 pos = le16_to_cpu(echo) % SPQ_RING_SIZE;
+ struct qed_spq *p_spq = p_hwfn->p_spq;
+
+ __set_bit(pos, p_spq->p_comp_bitmap);
+ while (test_bit(p_spq->comp_bitmap_idx,
+ p_spq->p_comp_bitmap)) {
+ __clear_bit(p_spq->comp_bitmap_idx,
+ p_spq->p_comp_bitmap);
+ p_spq->comp_bitmap_idx++;
+ qed_chain_return_produced(&p_spq->chain);
+ }
+}
+
int qed_spq_post(struct qed_hwfn *p_hwfn,
struct qed_spq_entry *p_ent, u8 *fw_return_code)
{
@@ -825,11 +843,12 @@ int qed_spq_post(struct qed_hwfn *p_hwfn,
p_ent->queue == &p_spq->unlimited_pending);
if (p_ent->queue == &p_spq->unlimited_pending) {
- /* This is an allocated p_ent which does not need to
- * return to pool.
- */
+ struct qed_spq_entry *p_post_ent = p_ent->post_ent;
+
kfree(p_ent);
- return rc;
+
+ /* Return the entry which was actually posted */
+ p_ent = p_post_ent;
}
if (rc)
@@ -843,7 +862,7 @@ int qed_spq_post(struct qed_hwfn *p_hwfn,
spq_post_fail2:
spin_lock_bh(&p_spq->lock);
list_del(&p_ent->list);
- qed_chain_return_produced(&p_spq->chain);
+ qed_spq_comp_bmap_update(p_hwfn, p_ent->elem.hdr.echo);
spq_post_fail:
/* return to the free pool */
@@ -875,25 +894,8 @@ int qed_spq_completion(struct qed_hwfn *p_hwfn,
spin_lock_bh(&p_spq->lock);
list_for_each_entry_safe(p_ent, tmp, &p_spq->completion_pending, list) {
if (p_ent->elem.hdr.echo == echo) {
- u16 pos = le16_to_cpu(echo) % SPQ_RING_SIZE;
-
list_del(&p_ent->list);
-
- /* Avoid overriding of SPQ entries when getting
- * out-of-order completions, by marking the completions
- * in a bitmap and increasing the chain consumer only
- * for the first successive completed entries.
- */
- __set_bit(pos, p_spq->p_comp_bitmap);
-
- while (test_bit(p_spq->comp_bitmap_idx,
- p_spq->p_comp_bitmap)) {
- __clear_bit(p_spq->comp_bitmap_idx,
- p_spq->p_comp_bitmap);
- p_spq->comp_bitmap_idx++;
- qed_chain_return_produced(&p_spq->chain);
- }
-
+ qed_spq_comp_bmap_update(p_hwfn, echo);
p_spq->comp_count++;
found = p_ent;
break;
@@ -932,11 +934,9 @@ int qed_spq_completion(struct qed_hwfn *p_hwfn,
QED_MSG_SPQ,
"Got a completion without a callback function\n");
- if ((found->comp_mode != QED_SPQ_MODE_EBLOCK) ||
- (found->queue == &p_spq->unlimited_pending))
+ if (found->comp_mode != QED_SPQ_MODE_EBLOCK)
/* EBLOCK is responsible for returning its own entry into the
- * free list, unless it originally added the entry into the
- * unlimited pending list.
+ * free list.
*/
qed_spq_return_entry(p_hwfn, found);
diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.c b/drivers/net/ethernet/qlogic/qed/qed_sriov.c
index 9b08a9d9e151..ca6290fa0f30 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_sriov.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.c
@@ -101,6 +101,7 @@ static int qed_sp_vf_start(struct qed_hwfn *p_hwfn, struct qed_vf_info *p_vf)
default:
DP_NOTICE(p_hwfn, "Unknown VF personality %d\n",
p_hwfn->hw_info.personality);
+ qed_sp_destroy_request(p_hwfn, p_ent);
return -EINVAL;
}
diff --git a/drivers/net/ethernet/qlogic/qed/qed_vf.c b/drivers/net/ethernet/qlogic/qed/qed_vf.c
index 3d4269659820..b6cccf44bf40 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_vf.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_vf.c
@@ -413,7 +413,6 @@ static int qed_vf_pf_acquire(struct qed_hwfn *p_hwfn)
}
if (!p_iov->b_pre_fp_hsi &&
- ETH_HSI_VER_MINOR &&
(resp->pfdev_info.minor_fp_hsi < ETH_HSI_VER_MINOR)) {
DP_INFO(p_hwfn,
"PF is using older fastpath HSI; %02x.%02x is configured\n",
@@ -572,7 +571,7 @@ free_p_iov:
static void
__qed_vf_prep_tunn_req_tlv(struct vfpf_update_tunn_param_tlv *p_req,
struct qed_tunn_update_type *p_src,
- enum qed_tunn_clss mask, u8 *p_cls)
+ enum qed_tunn_mode mask, u8 *p_cls)
{
if (p_src->b_update_mode) {
p_req->tun_mode_update_mask |= BIT(mask);
@@ -587,7 +586,7 @@ __qed_vf_prep_tunn_req_tlv(struct vfpf_update_tunn_param_tlv *p_req,
static void
qed_vf_prep_tunn_req_tlv(struct vfpf_update_tunn_param_tlv *p_req,
struct qed_tunn_update_type *p_src,
- enum qed_tunn_clss mask,
+ enum qed_tunn_mode mask,
u8 *p_cls, struct qed_tunn_update_udp_port *p_port,
u8 *p_update_port, u16 *p_udp_port)
{
@@ -1689,7 +1688,7 @@ static void qed_handle_bulletin_change(struct qed_hwfn *hwfn)
ops->ports_update(cookie, vxlan_port, geneve_port);
/* Always update link configuration according to bulletin */
- qed_link_update(hwfn);
+ qed_link_update(hwfn, NULL);
}
void qed_iov_vf_task(struct work_struct *work)
diff --git a/drivers/net/ethernet/qlogic/qede/qede.h b/drivers/net/ethernet/qlogic/qede/qede.h
index 6a4d266fb8e2..de98a974673b 100644
--- a/drivers/net/ethernet/qlogic/qede/qede.h
+++ b/drivers/net/ethernet/qlogic/qede/qede.h
@@ -440,7 +440,7 @@ struct qede_fastpath {
struct qede_tx_queue *txq;
struct qede_tx_queue *xdp_tx;
-#define VEC_NAME_SIZE (sizeof(((struct net_device *)0)->name) + 8)
+#define VEC_NAME_SIZE (FIELD_SIZEOF(struct net_device, name) + 8)
char name[VEC_NAME_SIZE];
};
diff --git a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c
index 19652cd27ca7..8cbbd628fd73 100644
--- a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c
+++ b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c
@@ -413,18 +413,42 @@ struct qede_link_mode_mapping {
};
static const struct qede_link_mode_mapping qed_lm_map[] = {
- {QED_LM_FIBRE_BIT, ETHTOOL_LINK_MODE_FIBRE_BIT},
{QED_LM_Autoneg_BIT, ETHTOOL_LINK_MODE_Autoneg_BIT},
{QED_LM_Asym_Pause_BIT, ETHTOOL_LINK_MODE_Asym_Pause_BIT},
{QED_LM_Pause_BIT, ETHTOOL_LINK_MODE_Pause_BIT},
- {QED_LM_1000baseT_Half_BIT, ETHTOOL_LINK_MODE_1000baseT_Half_BIT},
{QED_LM_1000baseT_Full_BIT, ETHTOOL_LINK_MODE_1000baseT_Full_BIT},
+ {QED_LM_10000baseT_Full_BIT, ETHTOOL_LINK_MODE_10000baseT_Full_BIT},
+ {QED_LM_2500baseX_Full_BIT, ETHTOOL_LINK_MODE_2500baseX_Full_BIT},
+ {QED_LM_Backplane_BIT, ETHTOOL_LINK_MODE_Backplane_BIT},
+ {QED_LM_1000baseKX_Full_BIT, ETHTOOL_LINK_MODE_1000baseKX_Full_BIT},
+ {QED_LM_10000baseKX4_Full_BIT, ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT},
{QED_LM_10000baseKR_Full_BIT, ETHTOOL_LINK_MODE_10000baseKR_Full_BIT},
- {QED_LM_25000baseKR_Full_BIT, ETHTOOL_LINK_MODE_25000baseKR_Full_BIT},
+ {QED_LM_10000baseKR_Full_BIT, ETHTOOL_LINK_MODE_10000baseKR_Full_BIT},
+ {QED_LM_10000baseR_FEC_BIT, ETHTOOL_LINK_MODE_10000baseR_FEC_BIT},
+ {QED_LM_20000baseKR2_Full_BIT, ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT},
+ {QED_LM_40000baseKR4_Full_BIT, ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT},
+ {QED_LM_40000baseCR4_Full_BIT, ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT},
+ {QED_LM_40000baseSR4_Full_BIT, ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT},
{QED_LM_40000baseLR4_Full_BIT, ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT},
+ {QED_LM_25000baseCR_Full_BIT, ETHTOOL_LINK_MODE_25000baseCR_Full_BIT},
+ {QED_LM_25000baseKR_Full_BIT, ETHTOOL_LINK_MODE_25000baseKR_Full_BIT},
+ {QED_LM_25000baseSR_Full_BIT, ETHTOOL_LINK_MODE_25000baseSR_Full_BIT},
+ {QED_LM_50000baseCR2_Full_BIT, ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT},
{QED_LM_50000baseKR2_Full_BIT, ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT},
{QED_LM_100000baseKR4_Full_BIT,
- ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT},
+ ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT},
+ {QED_LM_100000baseSR4_Full_BIT,
+ ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT},
+ {QED_LM_100000baseCR4_Full_BIT,
+ ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT},
+ {QED_LM_100000baseLR4_ER4_Full_BIT,
+ ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT},
+ {QED_LM_50000baseSR2_Full_BIT, ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT},
+ {QED_LM_1000baseX_Full_BIT, ETHTOOL_LINK_MODE_1000baseX_Full_BIT},
+ {QED_LM_10000baseCR_Full_BIT, ETHTOOL_LINK_MODE_10000baseCR_Full_BIT},
+ {QED_LM_10000baseSR_Full_BIT, ETHTOOL_LINK_MODE_10000baseSR_Full_BIT},
+ {QED_LM_10000baseLR_Full_BIT, ETHTOOL_LINK_MODE_10000baseLR_Full_BIT},
+ {QED_LM_10000baseLRM_Full_BIT, ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT},
};
#define QEDE_DRV_TO_ETHTOOL_CAPS(caps, lk_ksettings, name) \
@@ -494,6 +518,7 @@ static int qede_set_link_ksettings(struct net_device *dev,
struct qede_dev *edev = netdev_priv(dev);
struct qed_link_output current_link;
struct qed_link_params params;
+ u32 sup_caps;
if (!edev->ops || !edev->ops->common->can_link_change(edev->cdev)) {
DP_INFO(edev, "Link settings are not allowed to be changed\n");
@@ -520,52 +545,85 @@ static int qede_set_link_ksettings(struct net_device *dev,
params.forced_speed = base->speed;
switch (base->speed) {
case SPEED_1000:
- if (!(current_link.supported_caps &
- QED_LM_1000baseT_Full_BIT)) {
+ sup_caps = QED_LM_1000baseT_Full_BIT |
+ QED_LM_1000baseKX_Full_BIT |
+ QED_LM_1000baseX_Full_BIT;
+ if (!(current_link.supported_caps & sup_caps)) {
DP_INFO(edev, "1G speed not supported\n");
return -EINVAL;
}
- params.adv_speeds = QED_LM_1000baseT_Full_BIT;
+ params.adv_speeds = current_link.supported_caps &
+ sup_caps;
break;
case SPEED_10000:
- if (!(current_link.supported_caps &
- QED_LM_10000baseKR_Full_BIT)) {
+ sup_caps = QED_LM_10000baseT_Full_BIT |
+ QED_LM_10000baseKR_Full_BIT |
+ QED_LM_10000baseKX4_Full_BIT |
+ QED_LM_10000baseR_FEC_BIT |
+ QED_LM_10000baseCR_Full_BIT |
+ QED_LM_10000baseSR_Full_BIT |
+ QED_LM_10000baseLR_Full_BIT |
+ QED_LM_10000baseLRM_Full_BIT;
+ if (!(current_link.supported_caps & sup_caps)) {
DP_INFO(edev, "10G speed not supported\n");
return -EINVAL;
}
- params.adv_speeds = QED_LM_10000baseKR_Full_BIT;
+ params.adv_speeds = current_link.supported_caps &
+ sup_caps;
break;
- case SPEED_25000:
+ case SPEED_20000:
if (!(current_link.supported_caps &
- QED_LM_25000baseKR_Full_BIT)) {
+ QED_LM_20000baseKR2_Full_BIT)) {
+ DP_INFO(edev, "20G speed not supported\n");
+ return -EINVAL;
+ }
+ params.adv_speeds = QED_LM_20000baseKR2_Full_BIT;
+ break;
+ case SPEED_25000:
+ sup_caps = QED_LM_25000baseKR_Full_BIT |
+ QED_LM_25000baseCR_Full_BIT |
+ QED_LM_25000baseSR_Full_BIT;
+ if (!(current_link.supported_caps & sup_caps)) {
DP_INFO(edev, "25G speed not supported\n");
return -EINVAL;
}
- params.adv_speeds = QED_LM_25000baseKR_Full_BIT;
+ params.adv_speeds = current_link.supported_caps &
+ sup_caps;
break;
case SPEED_40000:
- if (!(current_link.supported_caps &
- QED_LM_40000baseLR4_Full_BIT)) {
+ sup_caps = QED_LM_40000baseLR4_Full_BIT |
+ QED_LM_40000baseKR4_Full_BIT |
+ QED_LM_40000baseCR4_Full_BIT |
+ QED_LM_40000baseSR4_Full_BIT;
+ if (!(current_link.supported_caps & sup_caps)) {
DP_INFO(edev, "40G speed not supported\n");
return -EINVAL;
}
- params.adv_speeds = QED_LM_40000baseLR4_Full_BIT;
+ params.adv_speeds = current_link.supported_caps &
+ sup_caps;
break;
case SPEED_50000:
- if (!(current_link.supported_caps &
- QED_LM_50000baseKR2_Full_BIT)) {
+ sup_caps = QED_LM_50000baseKR2_Full_BIT |
+ QED_LM_50000baseCR2_Full_BIT |
+ QED_LM_50000baseSR2_Full_BIT;
+ if (!(current_link.supported_caps & sup_caps)) {
DP_INFO(edev, "50G speed not supported\n");
return -EINVAL;
}
- params.adv_speeds = QED_LM_50000baseKR2_Full_BIT;
+ params.adv_speeds = current_link.supported_caps &
+ sup_caps;
break;
case SPEED_100000:
- if (!(current_link.supported_caps &
- QED_LM_100000baseKR4_Full_BIT)) {
+ sup_caps = QED_LM_100000baseKR4_Full_BIT |
+ QED_LM_100000baseSR4_Full_BIT |
+ QED_LM_100000baseCR4_Full_BIT |
+ QED_LM_100000baseLR4_ER4_Full_BIT;
+ if (!(current_link.supported_caps & sup_caps)) {
DP_INFO(edev, "100G speed not supported\n");
return -EINVAL;
}
- params.adv_speeds = QED_LM_100000baseKR4_Full_BIT;
+ params.adv_speeds = current_link.supported_caps &
+ sup_caps;
break;
default:
DP_INFO(edev, "Unsupported speed %u\n", base->speed);
diff --git a/drivers/net/ethernet/qlogic/qla3xxx.c b/drivers/net/ethernet/qlogic/qla3xxx.c
index b48f76182049..10b075bc5959 100644
--- a/drivers/net/ethernet/qlogic/qla3xxx.c
+++ b/drivers/net/ethernet/qlogic/qla3xxx.c
@@ -380,8 +380,6 @@ static void fm93c56a_select(struct ql3_adapter *qdev)
qdev->eeprom_cmd_data = AUBURN_EEPROM_CS_1;
ql_write_nvram_reg(qdev, spir, ISP_NVRAM_MASK | qdev->eeprom_cmd_data);
- ql_write_nvram_reg(qdev, spir,
- ((ISP_NVRAM_MASK << 16) | qdev->eeprom_cmd_data));
}
/*
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index 81312924df14..0c443ea98479 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -1800,7 +1800,8 @@ struct qlcnic_hardware_ops {
int (*config_loopback) (struct qlcnic_adapter *, u8);
int (*clear_loopback) (struct qlcnic_adapter *, u8);
int (*config_promisc_mode) (struct qlcnic_adapter *, u32);
- void (*change_l2_filter) (struct qlcnic_adapter *, u64 *, u16);
+ void (*change_l2_filter)(struct qlcnic_adapter *adapter, u64 *addr,
+ u16 vlan, struct qlcnic_host_tx_ring *tx_ring);
int (*get_board_info) (struct qlcnic_adapter *);
void (*set_mac_filter_count) (struct qlcnic_adapter *);
void (*free_mac_list) (struct qlcnic_adapter *);
@@ -2064,9 +2065,10 @@ static inline int qlcnic_nic_set_promisc(struct qlcnic_adapter *adapter,
}
static inline void qlcnic_change_filter(struct qlcnic_adapter *adapter,
- u64 *addr, u16 id)
+ u64 *addr, u16 vlan,
+ struct qlcnic_host_tx_ring *tx_ring)
{
- adapter->ahw->hw_ops->change_l2_filter(adapter, addr, id);
+ adapter->ahw->hw_ops->change_l2_filter(adapter, addr, vlan, tx_ring);
}
static inline int qlcnic_get_board_info(struct qlcnic_adapter *adapter)
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
index 569d54ededec..2a533280b124 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
@@ -2135,7 +2135,8 @@ out:
}
void qlcnic_83xx_change_l2_filter(struct qlcnic_adapter *adapter, u64 *addr,
- u16 vlan_id)
+ u16 vlan_id,
+ struct qlcnic_host_tx_ring *tx_ring)
{
u8 mac[ETH_ALEN];
memcpy(&mac, addr, ETH_ALEN);
@@ -4232,7 +4233,6 @@ static void qlcnic_83xx_io_resume(struct pci_dev *pdev)
{
struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
- pci_cleanup_aer_uncorrect_error_status(pdev);
if (test_and_clear_bit(__QLCNIC_AER, &adapter->state))
qlcnic_83xx_aer_start_poll_work(adapter);
}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
index b75a81246856..73fe2f64491d 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
@@ -550,7 +550,8 @@ int qlcnic_83xx_wrt_reg_indirect(struct qlcnic_adapter *, ulong, u32);
int qlcnic_83xx_nic_set_promisc(struct qlcnic_adapter *, u32);
int qlcnic_83xx_config_hw_lro(struct qlcnic_adapter *, int);
int qlcnic_83xx_config_rss(struct qlcnic_adapter *, int);
-void qlcnic_83xx_change_l2_filter(struct qlcnic_adapter *, u64 *, u16);
+void qlcnic_83xx_change_l2_filter(struct qlcnic_adapter *adapter, u64 *addr,
+ u16 vlan, struct qlcnic_host_tx_ring *ring);
int qlcnic_83xx_get_pci_info(struct qlcnic_adapter *, struct qlcnic_pci_info *);
int qlcnic_83xx_set_nic_info(struct qlcnic_adapter *, struct qlcnic_info *);
void qlcnic_83xx_initialize_nic(struct qlcnic_adapter *, int);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c
index 4b76c69fe86d..834208e55f7b 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c
@@ -883,7 +883,7 @@ static u8 qlcnic_dcb_get_capability(struct net_device *netdev, int capid,
struct qlcnic_adapter *adapter = netdev_priv(netdev);
if (!test_bit(QLCNIC_DCB_STATE, &adapter->dcb->state))
- return 0;
+ return 1;
switch (capid) {
case DCB_CAP_ATTR_PG:
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
index 4bb33af8e2b3..56a3bd9e37dc 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
@@ -173,7 +173,8 @@ int qlcnic_82xx_napi_add(struct qlcnic_adapter *adapter,
struct net_device *netdev);
void qlcnic_82xx_get_beacon_state(struct qlcnic_adapter *);
void qlcnic_82xx_change_filter(struct qlcnic_adapter *adapter,
- u64 *uaddr, u16 vlan_id);
+ u64 *uaddr, u16 vlan_id,
+ struct qlcnic_host_tx_ring *tx_ring);
int qlcnic_82xx_config_intr_coalesce(struct qlcnic_adapter *,
struct ethtool_coalesce *);
int qlcnic_82xx_set_rx_coalesce(struct qlcnic_adapter *);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
index 84dd83031a1b..14f26bf3b388 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
@@ -268,13 +268,12 @@ static void qlcnic_add_lb_filter(struct qlcnic_adapter *adapter,
}
void qlcnic_82xx_change_filter(struct qlcnic_adapter *adapter, u64 *uaddr,
- u16 vlan_id)
+ u16 vlan_id, struct qlcnic_host_tx_ring *tx_ring)
{
struct cmd_desc_type0 *hwdesc;
struct qlcnic_nic_req *req;
struct qlcnic_mac_req *mac_req;
struct qlcnic_vlan_req *vlan_req;
- struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
u32 producer;
u64 word;
@@ -301,7 +300,8 @@ void qlcnic_82xx_change_filter(struct qlcnic_adapter *adapter, u64 *uaddr,
static void qlcnic_send_filter(struct qlcnic_adapter *adapter,
struct cmd_desc_type0 *first_desc,
- struct sk_buff *skb)
+ struct sk_buff *skb,
+ struct qlcnic_host_tx_ring *tx_ring)
{
struct vlan_ethhdr *vh = (struct vlan_ethhdr *)(skb->data);
struct ethhdr *phdr = (struct ethhdr *)(skb->data);
@@ -335,7 +335,7 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter,
tmp_fil->vlan_id == vlan_id) {
if (jiffies > (QLCNIC_READD_AGE * HZ + tmp_fil->ftime))
qlcnic_change_filter(adapter, &src_addr,
- vlan_id);
+ vlan_id, tx_ring);
tmp_fil->ftime = jiffies;
return;
}
@@ -350,7 +350,7 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter,
if (!fil)
return;
- qlcnic_change_filter(adapter, &src_addr, vlan_id);
+ qlcnic_change_filter(adapter, &src_addr, vlan_id, tx_ring);
fil->ftime = jiffies;
fil->vlan_id = vlan_id;
memcpy(fil->faddr, &src_addr, ETH_ALEN);
@@ -459,7 +459,7 @@ static int qlcnic_tx_pkt(struct qlcnic_adapter *adapter,
struct cmd_desc_type0 *first_desc, struct sk_buff *skb,
struct qlcnic_host_tx_ring *tx_ring)
{
- u8 l4proto, opcode = 0, hdr_len = 0;
+ u8 l4proto, opcode = 0, hdr_len = 0, tag_vlan = 0;
u16 flags = 0, vlan_tci = 0;
int copied, offset, copy_len, size;
struct cmd_desc_type0 *hwdesc;
@@ -472,14 +472,16 @@ static int qlcnic_tx_pkt(struct qlcnic_adapter *adapter,
flags = QLCNIC_FLAGS_VLAN_TAGGED;
vlan_tci = ntohs(vh->h_vlan_TCI);
protocol = ntohs(vh->h_vlan_encapsulated_proto);
+ tag_vlan = 1;
} else if (skb_vlan_tag_present(skb)) {
flags = QLCNIC_FLAGS_VLAN_OOB;
vlan_tci = skb_vlan_tag_get(skb);
+ tag_vlan = 1;
}
if (unlikely(adapter->tx_pvid)) {
- if (vlan_tci && !(adapter->flags & QLCNIC_TAGGING_ENABLED))
+ if (tag_vlan && !(adapter->flags & QLCNIC_TAGGING_ENABLED))
return -EIO;
- if (vlan_tci && (adapter->flags & QLCNIC_TAGGING_ENABLED))
+ if (tag_vlan && (adapter->flags & QLCNIC_TAGGING_ENABLED))
goto set_flags;
flags = QLCNIC_FLAGS_VLAN_OOB;
@@ -766,7 +768,7 @@ netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
}
if (adapter->drv_mac_learn)
- qlcnic_send_filter(adapter, first_desc, skb);
+ qlcnic_send_filter(adapter, first_desc, skb, tx_ring);
tx_ring->tx_stats.tx_bytes += skb->len;
tx_ring->tx_stats.xmit_called++;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index 2d38d1ac2aae..d42ba2293d8c 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -59,9 +59,6 @@ static int qlcnic_close(struct net_device *netdev);
static void qlcnic_tx_timeout(struct net_device *netdev);
static void qlcnic_attach_work(struct work_struct *work);
static void qlcnic_fwinit_work(struct work_struct *work);
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void qlcnic_poll_controller(struct net_device *netdev);
-#endif
static void qlcnic_idc_debug_info(struct qlcnic_adapter *adapter, u8 encoding);
static int qlcnic_can_start_firmware(struct qlcnic_adapter *adapter);
@@ -545,9 +542,6 @@ static const struct net_device_ops qlcnic_netdev_ops = {
.ndo_udp_tunnel_add = qlcnic_add_vxlan_port,
.ndo_udp_tunnel_del = qlcnic_del_vxlan_port,
.ndo_features_check = qlcnic_features_check,
-#ifdef CONFIG_NET_POLL_CONTROLLER
- .ndo_poll_controller = qlcnic_poll_controller,
-#endif
#ifdef CONFIG_QLCNIC_SRIOV
.ndo_set_vf_mac = qlcnic_sriov_set_vf_mac,
.ndo_set_vf_rate = qlcnic_sriov_set_vf_tx_rate,
@@ -3200,45 +3194,6 @@ static irqreturn_t qlcnic_msix_tx_intr(int irq, void *data)
return IRQ_HANDLED;
}
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void qlcnic_poll_controller(struct net_device *netdev)
-{
- struct qlcnic_adapter *adapter = netdev_priv(netdev);
- struct qlcnic_host_sds_ring *sds_ring;
- struct qlcnic_recv_context *recv_ctx;
- struct qlcnic_host_tx_ring *tx_ring;
- int ring;
-
- if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
- return;
-
- recv_ctx = adapter->recv_ctx;
-
- for (ring = 0; ring < adapter->drv_sds_rings; ring++) {
- sds_ring = &recv_ctx->sds_rings[ring];
- qlcnic_disable_sds_intr(adapter, sds_ring);
- napi_schedule(&sds_ring->napi);
- }
-
- if (adapter->flags & QLCNIC_MSIX_ENABLED) {
- /* Only Multi-Tx queue capable devices need to
- * schedule NAPI for TX rings
- */
- if ((qlcnic_83xx_check(adapter) &&
- (adapter->flags & QLCNIC_TX_INTR_SHARED)) ||
- (qlcnic_82xx_check(adapter) &&
- !qlcnic_check_multi_tx(adapter)))
- return;
-
- for (ring = 0; ring < adapter->drv_tx_rings; ring++) {
- tx_ring = &adapter->tx_ring[ring];
- qlcnic_disable_tx_intr(adapter, tx_ring);
- napi_schedule(&tx_ring->napi);
- }
- }
-}
-#endif
-
static void
qlcnic_idc_debug_info(struct qlcnic_adapter *adapter, u8 encoding)
{
@@ -3975,7 +3930,6 @@ static void qlcnic_82xx_io_resume(struct pci_dev *pdev)
u32 state;
struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
- pci_cleanup_aer_uncorrect_error_status(pdev);
state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
if (state == QLCNIC_DEV_READY && test_and_clear_bit(__QLCNIC_AER,
&adapter->state))
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
index 77e386ebff09..f7c2f32237cb 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
@@ -904,13 +904,11 @@ static void qlcnic_sriov_pull_bc_msg(struct qlcnic_adapter *adapter,
u32 *hdr, u32 *pay, u32 size)
{
struct qlcnic_hardware_context *ahw = adapter->ahw;
- u32 fw_mbx;
u8 i, max = 2, hdr_size, j;
hdr_size = (sizeof(struct qlcnic_bc_hdr) / sizeof(u32));
max = (size / sizeof(u32)) + hdr_size;
- fw_mbx = readl(QLCNIC_MBX_FW(ahw, 0));
for (i = 2, j = 0; j < hdr_size; i++, j++)
*(hdr++) = readl(QLCNIC_MBX_FW(ahw, i));
for (; j < max; i++, j++)
@@ -936,7 +934,7 @@ static int __qlcnic_sriov_issue_bc_post(struct qlcnic_vf_info *vf)
static int qlcnic_sriov_issue_bc_post(struct qlcnic_bc_trans *trans, u8 type)
{
struct qlcnic_vf_info *vf = trans->vf;
- u32 pay_size, hdr_size;
+ u32 pay_size;
u32 *hdr, *pay;
int ret;
u8 pci_func = trans->func_id;
@@ -947,14 +945,12 @@ static int qlcnic_sriov_issue_bc_post(struct qlcnic_bc_trans *trans, u8 type)
if (type == QLC_BC_COMMAND) {
hdr = (u32 *)(trans->req_hdr + trans->curr_req_frag);
pay = (u32 *)(trans->req_pay + trans->curr_req_frag);
- hdr_size = (sizeof(struct qlcnic_bc_hdr) / sizeof(u32));
pay_size = qlcnic_sriov_get_bc_paysize(trans->req_pay_size,
trans->curr_req_frag);
pay_size = (pay_size / sizeof(u32));
} else {
hdr = (u32 *)(trans->rsp_hdr + trans->curr_rsp_frag);
pay = (u32 *)(trans->rsp_pay + trans->curr_rsp_frag);
- hdr_size = (sizeof(struct qlcnic_bc_hdr) / sizeof(u32));
pay_size = qlcnic_sriov_get_bc_paysize(trans->rsp_pay_size,
trans->curr_rsp_frag);
pay_size = (pay_size / sizeof(u32));
diff --git a/drivers/net/ethernet/qualcomm/qca_7k.c b/drivers/net/ethernet/qualcomm/qca_7k.c
index 6c8543fb90c0..4292c89bd35c 100644
--- a/drivers/net/ethernet/qualcomm/qca_7k.c
+++ b/drivers/net/ethernet/qualcomm/qca_7k.c
@@ -81,8 +81,8 @@ qcaspi_read_register(struct qcaspi *qca, u16 reg, u16 *result)
return ret;
}
-int
-qcaspi_write_register(struct qcaspi *qca, u16 reg, u16 value)
+static int
+__qcaspi_write_register(struct qcaspi *qca, u16 reg, u16 value)
{
__be16 tx_data[2];
struct spi_transfer transfer[2];
@@ -117,3 +117,33 @@ qcaspi_write_register(struct qcaspi *qca, u16 reg, u16 value)
return ret;
}
+
+int
+qcaspi_write_register(struct qcaspi *qca, u16 reg, u16 value, int retry)
+{
+ int ret, i = 0;
+ u16 confirmed;
+
+ do {
+ ret = __qcaspi_write_register(qca, reg, value);
+ if (ret)
+ return ret;
+
+ if (!retry)
+ return 0;
+
+ ret = qcaspi_read_register(qca, reg, &confirmed);
+ if (ret)
+ return ret;
+
+ ret = confirmed != value;
+ if (!ret)
+ return 0;
+
+ i++;
+ qca->stats.write_verify_failed++;
+
+ } while (i <= retry);
+
+ return ret;
+}
diff --git a/drivers/net/ethernet/qualcomm/qca_7k.h b/drivers/net/ethernet/qualcomm/qca_7k.h
index 27124c2bb77a..356de8ec5d48 100644
--- a/drivers/net/ethernet/qualcomm/qca_7k.h
+++ b/drivers/net/ethernet/qualcomm/qca_7k.h
@@ -66,6 +66,6 @@
void qcaspi_spi_error(struct qcaspi *qca);
int qcaspi_read_register(struct qcaspi *qca, u16 reg, u16 *result);
-int qcaspi_write_register(struct qcaspi *qca, u16 reg, u16 value);
+int qcaspi_write_register(struct qcaspi *qca, u16 reg, u16 value, int retry);
#endif /* _QCA_7K_H */
diff --git a/drivers/net/ethernet/qualcomm/qca_debug.c b/drivers/net/ethernet/qualcomm/qca_debug.c
index 51d89c86e60f..a9f1bc013364 100644
--- a/drivers/net/ethernet/qualcomm/qca_debug.c
+++ b/drivers/net/ethernet/qualcomm/qca_debug.c
@@ -60,6 +60,7 @@ static const char qcaspi_gstrings_stats[][ETH_GSTRING_LEN] = {
"Write buffer misses",
"Transmit ring full",
"SPI errors",
+ "Write verify errors",
};
#ifdef CONFIG_DEBUG_FS
diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c
index 66b775d462fd..d5310504f436 100644
--- a/drivers/net/ethernet/qualcomm/qca_spi.c
+++ b/drivers/net/ethernet/qualcomm/qca_spi.c
@@ -69,6 +69,12 @@ static int qcaspi_pluggable = QCASPI_PLUGGABLE_MIN;
module_param(qcaspi_pluggable, int, 0);
MODULE_PARM_DESC(qcaspi_pluggable, "Pluggable SPI connection (yes/no).");
+#define QCASPI_WRITE_VERIFY_MIN 0
+#define QCASPI_WRITE_VERIFY_MAX 3
+static int wr_verify = QCASPI_WRITE_VERIFY_MIN;
+module_param(wr_verify, int, 0);
+MODULE_PARM_DESC(wr_verify, "SPI register write verify trails. Use 0-3.");
+
#define QCASPI_TX_TIMEOUT (1 * HZ)
#define QCASPI_QCA7K_REBOOT_TIME_MS 1000
@@ -77,7 +83,7 @@ start_spi_intr_handling(struct qcaspi *qca, u16 *intr_cause)
{
*intr_cause = 0;
- qcaspi_write_register(qca, SPI_REG_INTR_ENABLE, 0);
+ qcaspi_write_register(qca, SPI_REG_INTR_ENABLE, 0, wr_verify);
qcaspi_read_register(qca, SPI_REG_INTR_CAUSE, intr_cause);
netdev_dbg(qca->net_dev, "interrupts: 0x%04x\n", *intr_cause);
}
@@ -90,8 +96,8 @@ end_spi_intr_handling(struct qcaspi *qca, u16 intr_cause)
SPI_INT_RDBUF_ERR |
SPI_INT_WRBUF_ERR);
- qcaspi_write_register(qca, SPI_REG_INTR_CAUSE, intr_cause);
- qcaspi_write_register(qca, SPI_REG_INTR_ENABLE, intr_enable);
+ qcaspi_write_register(qca, SPI_REG_INTR_CAUSE, intr_cause, 0);
+ qcaspi_write_register(qca, SPI_REG_INTR_ENABLE, intr_enable, wr_verify);
netdev_dbg(qca->net_dev, "acking int: 0x%04x\n", intr_cause);
}
@@ -239,7 +245,7 @@ qcaspi_tx_frame(struct qcaspi *qca, struct sk_buff *skb)
len = skb->len;
- qcaspi_write_register(qca, SPI_REG_BFR_SIZE, len);
+ qcaspi_write_register(qca, SPI_REG_BFR_SIZE, len, wr_verify);
if (qca->legacy_mode)
qcaspi_tx_cmd(qca, QCA7K_SPI_WRITE | QCA7K_SPI_EXTERNAL);
@@ -345,6 +351,7 @@ qcaspi_receive(struct qcaspi *qca)
/* Read the packet size. */
qcaspi_read_register(qca, SPI_REG_RDBUF_BYTE_AVA, &available);
+
netdev_dbg(net_dev, "qcaspi_receive: SPI_REG_RDBUF_BYTE_AVA: Value: %08x\n",
available);
@@ -353,7 +360,7 @@ qcaspi_receive(struct qcaspi *qca)
return -1;
}
- qcaspi_write_register(qca, SPI_REG_BFR_SIZE, available);
+ qcaspi_write_register(qca, SPI_REG_BFR_SIZE, available, wr_verify);
if (qca->legacy_mode)
qcaspi_tx_cmd(qca, QCA7K_SPI_READ | QCA7K_SPI_EXTERNAL);
@@ -524,7 +531,7 @@ qcaspi_qca7k_sync(struct qcaspi *qca, int event)
netdev_dbg(qca->net_dev, "sync: resetting device.\n");
qcaspi_read_register(qca, SPI_REG_SPI_CONFIG, &spi_config);
spi_config |= QCASPI_SLAVE_RESET_BIT;
- qcaspi_write_register(qca, SPI_REG_SPI_CONFIG, spi_config);
+ qcaspi_write_register(qca, SPI_REG_SPI_CONFIG, spi_config, 0);
qca->sync = QCASPI_SYNC_RESET;
qca->stats.trig_reset++;
@@ -684,7 +691,7 @@ qcaspi_netdev_close(struct net_device *dev)
netif_stop_queue(dev);
- qcaspi_write_register(qca, SPI_REG_INTR_ENABLE, 0);
+ qcaspi_write_register(qca, SPI_REG_INTR_ENABLE, 0, wr_verify);
free_irq(qca->spi_dev->irq, qca);
kthread_stop(qca->spi_thread);
@@ -904,6 +911,13 @@ qca_spi_probe(struct spi_device *spi)
return -EINVAL;
}
+ if (wr_verify < QCASPI_WRITE_VERIFY_MIN ||
+ wr_verify > QCASPI_WRITE_VERIFY_MAX) {
+ dev_err(&spi->dev, "Invalid write verify: %d\n",
+ wr_verify);
+ return -EINVAL;
+ }
+
dev_info(&spi->dev, "ver=%s, clkspeed=%d, burst_len=%d, pluggable=%d\n",
QCASPI_DRV_VERSION,
qcaspi_clkspeed,
diff --git a/drivers/net/ethernet/qualcomm/qca_spi.h b/drivers/net/ethernet/qualcomm/qca_spi.h
index fc0e98726b36..2d2c49726492 100644
--- a/drivers/net/ethernet/qualcomm/qca_spi.h
+++ b/drivers/net/ethernet/qualcomm/qca_spi.h
@@ -73,6 +73,7 @@ struct qcaspi_stats {
u64 write_buf_miss;
u64 ring_full;
u64 spi_err;
+ u64 write_verify_failed;
};
struct qcaspi {
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c
index 7fd86d40a337..11167abe5934 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c
@@ -113,7 +113,7 @@ rmnet_map_ingress_handler(struct sk_buff *skb,
struct sk_buff *skbn;
if (skb->dev->type == ARPHRD_ETHER) {
- if (pskb_expand_head(skb, ETH_HLEN, 0, GFP_KERNEL)) {
+ if (pskb_expand_head(skb, ETH_HLEN, 0, GFP_ATOMIC)) {
kfree_skb(skb);
return;
}
@@ -147,7 +147,7 @@ static int rmnet_map_egress_handler(struct sk_buff *skb,
}
if (skb_headroom(skb) < required_headroom) {
- if (pskb_expand_head(skb, required_headroom, 0, GFP_KERNEL))
+ if (pskb_expand_head(skb, required_headroom, 0, GFP_ATOMIC))
return -ENOMEM;
}
@@ -189,6 +189,9 @@ rx_handler_result_t rmnet_rx_handler(struct sk_buff **pskb)
if (!skb)
goto done;
+ if (skb->pkt_type == PACKET_LOOPBACK)
+ return RX_HANDLER_PASS;
+
dev = skb->dev;
port = rmnet_get_port(dev);
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c
index 0afc3d335d56..d11c16aeb19a 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c
@@ -234,7 +234,7 @@ int rmnet_vnd_newlink(u8 id, struct net_device *rmnet_dev,
struct net_device *real_dev,
struct rmnet_endpoint *ep)
{
- struct rmnet_priv *priv;
+ struct rmnet_priv *priv = netdev_priv(rmnet_dev);
int rc;
if (ep->egress_dev)
@@ -247,6 +247,8 @@ int rmnet_vnd_newlink(u8 id, struct net_device *rmnet_dev,
rmnet_dev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
rmnet_dev->hw_features |= NETIF_F_SG;
+ priv->real_dev = real_dev;
+
rc = register_netdevice(rmnet_dev);
if (!rc) {
ep->egress_dev = rmnet_dev;
@@ -255,9 +257,7 @@ int rmnet_vnd_newlink(u8 id, struct net_device *rmnet_dev,
rmnet_dev->rtnl_link_ops = &rmnet_link_ops;
- priv = netdev_priv(rmnet_dev);
priv->mux_id = id;
- priv->real_dev = real_dev;
netdev_dbg(rmnet_dev, "rmnet dev created\n");
}
diff --git a/drivers/net/ethernet/rdc/r6040.c b/drivers/net/ethernet/rdc/r6040.c
index aa11b70b9ca4..04aa592f35c3 100644
--- a/drivers/net/ethernet/rdc/r6040.c
+++ b/drivers/net/ethernet/rdc/r6040.c
@@ -1024,16 +1024,8 @@ static int r6040_mii_probe(struct net_device *dev)
return PTR_ERR(phydev);
}
- /* mask with MAC supported features */
- phydev->supported &= (SUPPORTED_10baseT_Half
- | SUPPORTED_10baseT_Full
- | SUPPORTED_100baseT_Half
- | SUPPORTED_100baseT_Full
- | SUPPORTED_Autoneg
- | SUPPORTED_MII
- | SUPPORTED_TP);
-
- phydev->advertising = phydev->supported;
+ phy_set_max_speed(phydev, SPEED_100);
+
lp->old_link = 0;
lp->old_duplex = -1;
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index ab30aaeac6d3..1fd01688d37b 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -77,8 +77,6 @@ static const int multicast_filter_limit = 32;
#define R8169_TX_RING_BYTES (NUM_TX_DESC * sizeof(struct TxDesc))
#define R8169_RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc))
-#define RTL8169_TX_TIMEOUT (6*HZ)
-
/* write/read MMIO register */
#define RTL_W8(tp, reg, val8) writeb((val8), tp->mmio_addr + (reg))
#define RTL_W16(tp, reg, val16) writew((val16), tp->mmio_addr + (reg))
@@ -633,7 +631,6 @@ struct rtl8169_tc_offsets {
enum rtl_flag {
RTL_FLAG_TASK_ENABLED = 0,
- RTL_FLAG_TASK_SLOW_PENDING,
RTL_FLAG_TASK_RESET_PENDING,
RTL_FLAG_MAX
};
@@ -1354,7 +1351,8 @@ static void rtl_irq_enable_all(struct rtl8169_private *tp)
static void rtl8169_irq_mask_and_ack(struct rtl8169_private *tp)
{
rtl_irq_disable(tp);
- rtl_ack_events(tp, RTL_EVENT_NAPI | tp->event_slow);
+ rtl_ack_events(tp, 0xffff);
+ /* PCI commit */
RTL_R8(tp, ChipCmd);
}
@@ -4048,23 +4046,11 @@ static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp)
rtl_hw_phy_config(dev);
if (tp->mac_version <= RTL_GIGA_MAC_VER_06) {
- netif_dbg(tp, drv, dev,
- "Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
- RTL_W8(tp, 0x82, 0x01);
- }
-
- pci_write_config_byte(tp->pci_dev, PCI_LATENCY_TIMER, 0x40);
-
- if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
+ pci_write_config_byte(tp->pci_dev, PCI_LATENCY_TIMER, 0x40);
pci_write_config_byte(tp->pci_dev, PCI_CACHE_LINE_SIZE, 0x08);
-
- if (tp->mac_version == RTL_GIGA_MAC_VER_02) {
netif_dbg(tp, drv, dev,
"Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
RTL_W8(tp, 0x82, 0x01);
- netif_dbg(tp, drv, dev,
- "Set PHY Reg 0x0bh = 0x00h\n");
- rtl_writephy(tp, 0x0b, 0x0000); //w 0x0b 15 0 0
}
/* We may have called phy_speed_down before */
@@ -4072,13 +4058,12 @@ static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp)
genphy_soft_reset(dev->phydev);
- /* It was reported that chip version 33 ends up with 10MBit/Half on a
+ /* It was reported that several chips end up with 10MBit/Half on a
* 1GBit link after resuming from S3. For whatever reason the PHY on
- * this chip doesn't properly start a renegotiation when soft-reset.
+ * these chips doesn't properly start a renegotiation when soft-reset.
* Explicitly requesting a renegotiation fixes this.
*/
- if (tp->mac_version == RTL_GIGA_MAC_VER_33 &&
- dev->phydev->autoneg == AUTONEG_ENABLE)
+ if (dev->phydev->autoneg == AUTONEG_ENABLE)
phy_restart_aneg(dev->phydev);
}
@@ -4176,10 +4161,15 @@ static void rtl_wol_suspend_quirk(struct rtl8169_private *tp)
static bool rtl_wol_pll_power_down(struct rtl8169_private *tp)
{
- if (!netif_running(tp->dev) || !__rtl8169_get_wol(tp))
+ struct phy_device *phydev;
+
+ if (!__rtl8169_get_wol(tp))
return false;
- phy_speed_down(tp->dev->phydev, false);
+ /* phydev may not be attached to netdevice */
+ phydev = mdiobus_get_phy(tp->mii_bus, 0);
+
+ phy_speed_down(phydev, false);
rtl_wol_suspend_quirk(tp);
return true;
@@ -4283,8 +4273,8 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp)
RTL_W32(tp, RxConfig, RX_FIFO_THRESH | RX_DMA_BURST);
break;
case RTL_GIGA_MAC_VER_18 ... RTL_GIGA_MAC_VER_24:
- case RTL_GIGA_MAC_VER_34:
- case RTL_GIGA_MAC_VER_35:
+ case RTL_GIGA_MAC_VER_34 ... RTL_GIGA_MAC_VER_36:
+ case RTL_GIGA_MAC_VER_38:
RTL_W32(tp, RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST);
break;
case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_51:
@@ -4536,9 +4526,14 @@ static void rtl8169_hw_reset(struct rtl8169_private *tp)
static void rtl_set_tx_config_registers(struct rtl8169_private *tp)
{
- /* Set DMA burst size and Interframe Gap Time */
- RTL_W32(tp, TxConfig, (TX_DMA_BURST << TxDMAShift) |
- (InterFrameGap << TxInterFrameGapShift));
+ u32 val = TX_DMA_BURST << TxDMAShift |
+ InterFrameGap << TxInterFrameGapShift;
+
+ if (tp->mac_version >= RTL_GIGA_MAC_VER_34 &&
+ tp->mac_version != RTL_GIGA_MAC_VER_39)
+ val |= TXCFG_AUTO_FIFO;
+
+ RTL_W32(tp, TxConfig, val);
}
static void rtl_set_rx_max_size(struct rtl8169_private *tp)
@@ -4562,27 +4557,19 @@ static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp)
static void rtl8169_set_magic_reg(struct rtl8169_private *tp, unsigned mac_version)
{
- static const struct rtl_cfg2_info {
- u32 mac_version;
- u32 clk;
- u32 val;
- } cfg2_info [] = {
- { RTL_GIGA_MAC_VER_05, PCI_Clock_33MHz, 0x000fff00 }, // 8110SCd
- { RTL_GIGA_MAC_VER_05, PCI_Clock_66MHz, 0x000fffff },
- { RTL_GIGA_MAC_VER_06, PCI_Clock_33MHz, 0x00ffff00 }, // 8110SCe
- { RTL_GIGA_MAC_VER_06, PCI_Clock_66MHz, 0x00ffffff }
- };
- const struct rtl_cfg2_info *p = cfg2_info;
- unsigned int i;
- u32 clk;
+ u32 val;
- clk = RTL_R8(tp, Config2) & PCI_Clock_66MHz;
- for (i = 0; i < ARRAY_SIZE(cfg2_info); i++, p++) {
- if ((p->mac_version == mac_version) && (p->clk == clk)) {
- RTL_W32(tp, 0x7c, p->val);
- break;
- }
- }
+ if (tp->mac_version == RTL_GIGA_MAC_VER_05)
+ val = 0x000fff00;
+ else if (tp->mac_version == RTL_GIGA_MAC_VER_06)
+ val = 0x00ffff00;
+ else
+ return;
+
+ if (RTL_R8(tp, Config2) & PCI_Clock_66MHz)
+ val |= 0xff;
+
+ RTL_W32(tp, 0x7c, val);
}
static void rtl_set_rx_mode(struct net_device *dev)
@@ -5033,7 +5020,6 @@ static void rtl_hw_start_8168e_2(struct rtl8169_private *tp)
rtl_disable_clock_request(tp);
- RTL_W32(tp, TxConfig, RTL_R32(tp, TxConfig) | TXCFG_AUTO_FIFO);
RTL_W8(tp, MCU, RTL_R8(tp, MCU) & ~NOW_IS_OOB);
/* Adjust EEE LED frequency */
@@ -5067,7 +5053,6 @@ static void rtl_hw_start_8168f(struct rtl8169_private *tp)
rtl_disable_clock_request(tp);
- RTL_W32(tp, TxConfig, RTL_R32(tp, TxConfig) | TXCFG_AUTO_FIFO);
RTL_W8(tp, MCU, RTL_R8(tp, MCU) & ~NOW_IS_OOB);
RTL_W8(tp, DLLPR, RTL_R8(tp, DLLPR) | PFM_EN);
RTL_W32(tp, MISC, RTL_R32(tp, MISC) | PWM_EN);
@@ -5112,8 +5097,6 @@ static void rtl_hw_start_8411(struct rtl8169_private *tp)
static void rtl_hw_start_8168g(struct rtl8169_private *tp)
{
- RTL_W32(tp, TxConfig, RTL_R32(tp, TxConfig) | TXCFG_AUTO_FIFO);
-
rtl_eri_write(tp, 0xc8, ERIAR_MASK_0101, 0x080002, ERIAR_EXGMAC);
rtl_eri_write(tp, 0xcc, ERIAR_MASK_0001, 0x38, ERIAR_EXGMAC);
rtl_eri_write(tp, 0xd0, ERIAR_MASK_0001, 0x48, ERIAR_EXGMAC);
@@ -5211,8 +5194,6 @@ static void rtl_hw_start_8168h_1(struct rtl8169_private *tp)
rtl_hw_aspm_clkreq_enable(tp, false);
rtl_ephy_init(tp, e_info_8168h_1, ARRAY_SIZE(e_info_8168h_1));
- RTL_W32(tp, TxConfig, RTL_R32(tp, TxConfig) | TXCFG_AUTO_FIFO);
-
rtl_eri_write(tp, 0xc8, ERIAR_MASK_0101, 0x00080002, ERIAR_EXGMAC);
rtl_eri_write(tp, 0xcc, ERIAR_MASK_0001, 0x38, ERIAR_EXGMAC);
rtl_eri_write(tp, 0xd0, ERIAR_MASK_0001, 0x48, ERIAR_EXGMAC);
@@ -5295,8 +5276,6 @@ static void rtl_hw_start_8168ep(struct rtl8169_private *tp)
{
rtl8168ep_stop_cmac(tp);
- RTL_W32(tp, TxConfig, RTL_R32(tp, TxConfig) | TXCFG_AUTO_FIFO);
-
rtl_eri_write(tp, 0xc8, ERIAR_MASK_0101, 0x00080002, ERIAR_EXGMAC);
rtl_eri_write(tp, 0xcc, ERIAR_MASK_0001, 0x2f, ERIAR_EXGMAC);
rtl_eri_write(tp, 0xd0, ERIAR_MASK_0001, 0x5f, ERIAR_EXGMAC);
@@ -5618,7 +5597,6 @@ static void rtl_hw_start_8402(struct rtl8169_private *tp)
/* Force LAN exit from ASPM if Rx/Tx are not idle */
RTL_W32(tp, FuncEvent, RTL_R32(tp, FuncEvent) | 0x002800);
- RTL_W32(tp, TxConfig, RTL_R32(tp, TxConfig) | TXCFG_AUTO_FIFO);
RTL_W8(tp, MCU, RTL_R8(tp, MCU) & ~NOW_IS_OOB);
rtl_ephy_init(tp, e_info_8402, ARRAY_SIZE(e_info_8402));
@@ -5878,6 +5856,7 @@ static void rtl8169_tx_clear(struct rtl8169_private *tp)
{
rtl8169_tx_clear_range(tp, tp->dirty_tx, NUM_TX_DESC);
tp->cur_tx = tp->dirty_tx = 0;
+ netdev_reset_queue(tp->dev);
}
static void rtl_reset_work(struct rtl8169_private *tp)
@@ -6180,6 +6159,8 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
txd->opts2 = cpu_to_le32(opts[1]);
+ netdev_sent_queue(dev, skb->len);
+
skb_tx_timestamp(skb);
/* Force memory writes to complete before releasing descriptor */
@@ -6278,7 +6259,7 @@ static void rtl8169_pcierr_interrupt(struct net_device *dev)
static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp)
{
- unsigned int dirty_tx, tx_left;
+ unsigned int dirty_tx, tx_left, bytes_compl = 0, pkts_compl = 0;
dirty_tx = tp->dirty_tx;
smp_rmb();
@@ -6302,10 +6283,8 @@ static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp)
rtl8169_unmap_tx_skb(tp_to_dev(tp), tx_skb,
tp->TxDescArray + entry);
if (status & LastFrag) {
- u64_stats_update_begin(&tp->tx_stats.syncp);
- tp->tx_stats.packets++;
- tp->tx_stats.bytes += tx_skb->skb->len;
- u64_stats_update_end(&tp->tx_stats.syncp);
+ pkts_compl++;
+ bytes_compl += tx_skb->skb->len;
dev_consume_skb_any(tx_skb->skb);
tx_skb->skb = NULL;
}
@@ -6314,6 +6293,13 @@ static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp)
}
if (tp->dirty_tx != dirty_tx) {
+ netdev_completed_queue(dev, pkts_compl, bytes_compl);
+
+ u64_stats_update_begin(&tp->tx_stats.syncp);
+ tp->tx_stats.packets += pkts_compl;
+ tp->tx_stats.bytes += bytes_compl;
+ u64_stats_update_end(&tp->tx_stats.syncp);
+
tp->dirty_tx = dirty_tx;
/* Sync with rtl8169_start_xmit:
* - publish dirty_tx ring index (write barrier)
@@ -6478,42 +6464,29 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
if (status == 0xffff || !(status & (RTL_EVENT_NAPI | tp->event_slow)))
return IRQ_NONE;
- rtl_irq_disable(tp);
- napi_schedule_irqoff(&tp->napi);
-
- return IRQ_HANDLED;
-}
-
-/*
- * Workqueue context.
- */
-static void rtl_slow_event_work(struct rtl8169_private *tp)
-{
- struct net_device *dev = tp->dev;
- u16 status;
+ if (unlikely(status & SYSErr)) {
+ rtl8169_pcierr_interrupt(tp->dev);
+ goto out;
+ }
- status = rtl_get_events(tp) & tp->event_slow;
- rtl_ack_events(tp, status);
+ if (status & LinkChg)
+ phy_mac_interrupt(tp->dev->phydev);
- if (unlikely(status & RxFIFOOver)) {
- switch (tp->mac_version) {
- /* Work around for rx fifo overflow */
- case RTL_GIGA_MAC_VER_11:
- netif_stop_queue(dev);
- /* XXX - Hack alert. See rtl_task(). */
- set_bit(RTL_FLAG_TASK_RESET_PENDING, tp->wk.flags);
- default:
- break;
- }
+ if (unlikely(status & RxFIFOOver &&
+ tp->mac_version == RTL_GIGA_MAC_VER_11)) {
+ netif_stop_queue(tp->dev);
+ /* XXX - Hack alert. See rtl_task(). */
+ set_bit(RTL_FLAG_TASK_RESET_PENDING, tp->wk.flags);
}
- if (unlikely(status & SYSErr))
- rtl8169_pcierr_interrupt(dev);
-
- if (status & LinkChg)
- phy_mac_interrupt(dev->phydev);
+ if (status & RTL_EVENT_NAPI) {
+ rtl_irq_disable(tp);
+ napi_schedule_irqoff(&tp->napi);
+ }
+out:
+ rtl_ack_events(tp, status);
- rtl_irq_enable_all(tp);
+ return IRQ_HANDLED;
}
static void rtl_task(struct work_struct *work)
@@ -6522,8 +6495,6 @@ static void rtl_task(struct work_struct *work)
int bitnr;
void (*action)(struct rtl8169_private *);
} rtl_work[] = {
- /* XXX - keep rtl_slow_event_work() as first element. */
- { RTL_FLAG_TASK_SLOW_PENDING, rtl_slow_event_work },
{ RTL_FLAG_TASK_RESET_PENDING, rtl_reset_work },
};
struct rtl8169_private *tp =
@@ -6553,29 +6524,16 @@ static int rtl8169_poll(struct napi_struct *napi, int budget)
{
struct rtl8169_private *tp = container_of(napi, struct rtl8169_private, napi);
struct net_device *dev = tp->dev;
- u16 enable_mask = RTL_EVENT_NAPI | tp->event_slow;
- int work_done= 0;
- u16 status;
-
- status = rtl_get_events(tp);
- rtl_ack_events(tp, status & ~tp->event_slow);
+ int work_done;
- if (status & RTL_EVENT_NAPI_RX)
- work_done = rtl_rx(dev, tp, (u32) budget);
+ work_done = rtl_rx(dev, tp, (u32) budget);
- if (status & RTL_EVENT_NAPI_TX)
- rtl_tx(dev, tp);
-
- if (status & tp->event_slow) {
- enable_mask &= ~tp->event_slow;
-
- rtl_schedule_task(tp, RTL_FLAG_TASK_SLOW_PENDING);
- }
+ rtl_tx(dev, tp);
if (work_done < budget) {
napi_complete_done(napi, work_done);
- rtl_irq_enable(tp, enable_mask);
+ rtl_irq_enable_all(tp);
mmiowb();
}
@@ -6851,7 +6809,6 @@ static void rtl8169_net_suspend(struct net_device *dev)
phy_stop(dev->phydev);
netif_device_detach(dev);
- netif_stop_queue(dev);
rtl_lock_work(tp);
napi_disable(&tp->napi);
@@ -6869,8 +6826,10 @@ static int rtl8169_suspend(struct device *device)
{
struct pci_dev *pdev = to_pci_dev(device);
struct net_device *dev = pci_get_drvdata(pdev);
+ struct rtl8169_private *tp = netdev_priv(dev);
rtl8169_net_suspend(dev);
+ clk_disable_unprepare(tp->clk);
return 0;
}
@@ -6898,6 +6857,9 @@ static int rtl8169_resume(struct device *device)
{
struct pci_dev *pdev = to_pci_dev(device);
struct net_device *dev = pci_get_drvdata(pdev);
+ struct rtl8169_private *tp = netdev_priv(dev);
+
+ clk_prepare_enable(tp->clk);
if (netif_running(dev))
__rtl8169_resume(dev);
@@ -7093,20 +7055,12 @@ static int rtl_alloc_irq(struct rtl8169_private *tp)
{
unsigned int flags;
- switch (tp->mac_version) {
- case RTL_GIGA_MAC_VER_01 ... RTL_GIGA_MAC_VER_06:
+ if (tp->mac_version <= RTL_GIGA_MAC_VER_06) {
RTL_W8(tp, Cfg9346, Cfg9346_Unlock);
RTL_W8(tp, Config2, RTL_R8(tp, Config2) & ~MSIEnable);
RTL_W8(tp, Cfg9346, Cfg9346_Lock);
flags = PCI_IRQ_LEGACY;
- break;
- case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_40:
- /* This version was reported to have issues with resume
- * from suspend when using MSI-X
- */
- flags = PCI_IRQ_LEGACY | PCI_IRQ_MSI;
- break;
- default:
+ } else {
flags = PCI_IRQ_ALL_TYPES;
}
@@ -7368,11 +7322,9 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
tp->cp_cmd = RTL_R16(tp, CPlusCmd);
- if ((sizeof(dma_addr_t) > 4) &&
- (use_dac == 1 || (use_dac == -1 && pci_is_pcie(pdev) &&
- tp->mac_version >= RTL_GIGA_MAC_VER_18)) &&
- !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) &&
- !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) {
+ if (sizeof(dma_addr_t) > 4 && (use_dac == 1 || (use_dac == -1 &&
+ tp->mac_version >= RTL_GIGA_MAC_VER_18)) &&
+ !dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64))) {
/* CPlusCmd Dual Access Cycle is only needed for non-PCIe */
if (!pci_is_pcie(pdev))
@@ -7388,14 +7340,12 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
rtl_init_rxcfg(tp);
- rtl_irq_disable(tp);
+ rtl8169_irq_mask_and_ack(tp);
rtl_hw_initialize(tp);
rtl_hw_reset(tp);
- rtl_ack_events(tp, 0xffff);
-
pci_set_master(pdev);
rtl_init_mdio_ops(tp);
@@ -7435,7 +7385,6 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
dev->dev_addr[i] = RTL_R8(tp, MAC0 + i);
dev->ethtool_ops = &rtl8169_ethtool_ops;
- dev->watchdog_timeo = RTL8169_TX_TIMEOUT;
netif_napi_add(dev, &tp->napi, rtl8169_poll, NAPI_POLL_WEIGHT);
diff --git a/drivers/net/ethernet/renesas/ravb.h b/drivers/net/ethernet/renesas/ravb.h
index 9b6bf557a2f5..1c6e4df94f01 100644
--- a/drivers/net/ethernet/renesas/ravb.h
+++ b/drivers/net/ethernet/renesas/ravb.h
@@ -959,7 +959,10 @@ enum RAVB_QUEUE {
#define RX_QUEUE_OFFSET 4
#define NUM_RX_QUEUE 2
#define NUM_TX_QUEUE 2
-#define NUM_TX_DESC 2 /* TX descriptors per packet */
+
+/* TX descriptors per packet */
+#define NUM_TX_DESC_GEN2 2
+#define NUM_TX_DESC_GEN3 1
struct ravb_tstamp_skb {
struct list_head list;
@@ -1038,6 +1041,7 @@ struct ravb_private {
unsigned no_avb_link:1;
unsigned avb_link_active_low:1;
unsigned wol_enabled:1;
+ int num_tx_desc; /* TX descriptors per packet */
};
static inline u32 ravb_read(struct net_device *ndev, enum ravb_reg reg)
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index d6f753925352..defed0d0c51d 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -182,6 +182,7 @@ static int ravb_tx_free(struct net_device *ndev, int q, bool free_txed_only)
{
struct ravb_private *priv = netdev_priv(ndev);
struct net_device_stats *stats = &priv->stats[q];
+ int num_tx_desc = priv->num_tx_desc;
struct ravb_tx_desc *desc;
int free_num = 0;
int entry;
@@ -191,7 +192,7 @@ static int ravb_tx_free(struct net_device *ndev, int q, bool free_txed_only)
bool txed;
entry = priv->dirty_tx[q] % (priv->num_tx_ring[q] *
- NUM_TX_DESC);
+ num_tx_desc);
desc = &priv->tx_ring[q][entry];
txed = desc->die_dt == DT_FEMPTY;
if (free_txed_only && !txed)
@@ -200,12 +201,12 @@ static int ravb_tx_free(struct net_device *ndev, int q, bool free_txed_only)
dma_rmb();
size = le16_to_cpu(desc->ds_tagl) & TX_DS;
/* Free the original skb. */
- if (priv->tx_skb[q][entry / NUM_TX_DESC]) {
+ if (priv->tx_skb[q][entry / num_tx_desc]) {
dma_unmap_single(ndev->dev.parent, le32_to_cpu(desc->dptr),
size, DMA_TO_DEVICE);
/* Last packet descriptor? */
- if (entry % NUM_TX_DESC == NUM_TX_DESC - 1) {
- entry /= NUM_TX_DESC;
+ if (entry % num_tx_desc == num_tx_desc - 1) {
+ entry /= num_tx_desc;
dev_kfree_skb_any(priv->tx_skb[q][entry]);
priv->tx_skb[q][entry] = NULL;
if (txed)
@@ -224,6 +225,7 @@ static int ravb_tx_free(struct net_device *ndev, int q, bool free_txed_only)
static void ravb_ring_free(struct net_device *ndev, int q)
{
struct ravb_private *priv = netdev_priv(ndev);
+ int num_tx_desc = priv->num_tx_desc;
int ring_size;
int i;
@@ -249,7 +251,7 @@ static void ravb_ring_free(struct net_device *ndev, int q)
ravb_tx_free(ndev, q, false);
ring_size = sizeof(struct ravb_tx_desc) *
- (priv->num_tx_ring[q] * NUM_TX_DESC + 1);
+ (priv->num_tx_ring[q] * num_tx_desc + 1);
dma_free_coherent(ndev->dev.parent, ring_size, priv->tx_ring[q],
priv->tx_desc_dma[q]);
priv->tx_ring[q] = NULL;
@@ -278,12 +280,13 @@ static void ravb_ring_free(struct net_device *ndev, int q)
static void ravb_ring_format(struct net_device *ndev, int q)
{
struct ravb_private *priv = netdev_priv(ndev);
+ int num_tx_desc = priv->num_tx_desc;
struct ravb_ex_rx_desc *rx_desc;
struct ravb_tx_desc *tx_desc;
struct ravb_desc *desc;
int rx_ring_size = sizeof(*rx_desc) * priv->num_rx_ring[q];
int tx_ring_size = sizeof(*tx_desc) * priv->num_tx_ring[q] *
- NUM_TX_DESC;
+ num_tx_desc;
dma_addr_t dma_addr;
int i;
@@ -318,8 +321,10 @@ static void ravb_ring_format(struct net_device *ndev, int q)
for (i = 0, tx_desc = priv->tx_ring[q]; i < priv->num_tx_ring[q];
i++, tx_desc++) {
tx_desc->die_dt = DT_EEMPTY;
- tx_desc++;
- tx_desc->die_dt = DT_EEMPTY;
+ if (num_tx_desc > 1) {
+ tx_desc++;
+ tx_desc->die_dt = DT_EEMPTY;
+ }
}
tx_desc->dptr = cpu_to_le32((u32)priv->tx_desc_dma[q]);
tx_desc->die_dt = DT_LINKFIX; /* type */
@@ -339,6 +344,7 @@ static void ravb_ring_format(struct net_device *ndev, int q)
static int ravb_ring_init(struct net_device *ndev, int q)
{
struct ravb_private *priv = netdev_priv(ndev);
+ int num_tx_desc = priv->num_tx_desc;
struct sk_buff *skb;
int ring_size;
int i;
@@ -362,11 +368,13 @@ static int ravb_ring_init(struct net_device *ndev, int q)
priv->rx_skb[q][i] = skb;
}
- /* Allocate rings for the aligned buffers */
- priv->tx_align[q] = kmalloc(DPTR_ALIGN * priv->num_tx_ring[q] +
- DPTR_ALIGN - 1, GFP_KERNEL);
- if (!priv->tx_align[q])
- goto error;
+ if (num_tx_desc > 1) {
+ /* Allocate rings for the aligned buffers */
+ priv->tx_align[q] = kmalloc(DPTR_ALIGN * priv->num_tx_ring[q] +
+ DPTR_ALIGN - 1, GFP_KERNEL);
+ if (!priv->tx_align[q])
+ goto error;
+ }
/* Allocate all RX descriptors. */
ring_size = sizeof(struct ravb_ex_rx_desc) * (priv->num_rx_ring[q] + 1);
@@ -380,7 +388,7 @@ static int ravb_ring_init(struct net_device *ndev, int q)
/* Allocate all TX descriptors. */
ring_size = sizeof(struct ravb_tx_desc) *
- (priv->num_tx_ring[q] * NUM_TX_DESC + 1);
+ (priv->num_tx_ring[q] * num_tx_desc + 1);
priv->tx_ring[q] = dma_alloc_coherent(ndev->dev.parent, ring_size,
&priv->tx_desc_dma[q],
GFP_KERNEL);
@@ -1074,8 +1082,11 @@ static int ravb_phy_init(struct net_device *ndev)
netdev_info(ndev, "limited PHY to 100Mbit/s\n");
}
- /* 10BASE is not supported */
- phydev->supported &= ~PHY_10BT_FEATURES;
+ /* 10BASE, Pause and Asym Pause is not supported */
+ phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT);
+ phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Full_BIT);
+ phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_Pause_BIT);
+ phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_Asym_Pause_BIT);
phy_attached_info(phydev);
@@ -1485,6 +1496,7 @@ static void ravb_tx_timeout_work(struct work_struct *work)
static netdev_tx_t ravb_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{
struct ravb_private *priv = netdev_priv(ndev);
+ int num_tx_desc = priv->num_tx_desc;
u16 q = skb_get_queue_mapping(skb);
struct ravb_tstamp_skb *ts_skb;
struct ravb_tx_desc *desc;
@@ -1496,7 +1508,7 @@ static netdev_tx_t ravb_start_xmit(struct sk_buff *skb, struct net_device *ndev)
spin_lock_irqsave(&priv->lock, flags);
if (priv->cur_tx[q] - priv->dirty_tx[q] > (priv->num_tx_ring[q] - 1) *
- NUM_TX_DESC) {
+ num_tx_desc) {
netif_err(priv, tx_queued, ndev,
"still transmitting with the full ring!\n");
netif_stop_subqueue(ndev, q);
@@ -1507,41 +1519,55 @@ static netdev_tx_t ravb_start_xmit(struct sk_buff *skb, struct net_device *ndev)
if (skb_put_padto(skb, ETH_ZLEN))
goto exit;
- entry = priv->cur_tx[q] % (priv->num_tx_ring[q] * NUM_TX_DESC);
- priv->tx_skb[q][entry / NUM_TX_DESC] = skb;
-
- buffer = PTR_ALIGN(priv->tx_align[q], DPTR_ALIGN) +
- entry / NUM_TX_DESC * DPTR_ALIGN;
- len = PTR_ALIGN(skb->data, DPTR_ALIGN) - skb->data;
- /* Zero length DMA descriptors are problematic as they seem to
- * terminate DMA transfers. Avoid them by simply using a length of
- * DPTR_ALIGN (4) when skb data is aligned to DPTR_ALIGN.
- *
- * As skb is guaranteed to have at least ETH_ZLEN (60) bytes of
- * data by the call to skb_put_padto() above this is safe with
- * respect to both the length of the first DMA descriptor (len)
- * overflowing the available data and the length of the second DMA
- * descriptor (skb->len - len) being negative.
- */
- if (len == 0)
- len = DPTR_ALIGN;
+ entry = priv->cur_tx[q] % (priv->num_tx_ring[q] * num_tx_desc);
+ priv->tx_skb[q][entry / num_tx_desc] = skb;
+
+ if (num_tx_desc > 1) {
+ buffer = PTR_ALIGN(priv->tx_align[q], DPTR_ALIGN) +
+ entry / num_tx_desc * DPTR_ALIGN;
+ len = PTR_ALIGN(skb->data, DPTR_ALIGN) - skb->data;
+
+ /* Zero length DMA descriptors are problematic as they seem
+ * to terminate DMA transfers. Avoid them by simply using a
+ * length of DPTR_ALIGN (4) when skb data is aligned to
+ * DPTR_ALIGN.
+ *
+ * As skb is guaranteed to have at least ETH_ZLEN (60)
+ * bytes of data by the call to skb_put_padto() above this
+ * is safe with respect to both the length of the first DMA
+ * descriptor (len) overflowing the available data and the
+ * length of the second DMA descriptor (skb->len - len)
+ * being negative.
+ */
+ if (len == 0)
+ len = DPTR_ALIGN;
- memcpy(buffer, skb->data, len);
- dma_addr = dma_map_single(ndev->dev.parent, buffer, len, DMA_TO_DEVICE);
- if (dma_mapping_error(ndev->dev.parent, dma_addr))
- goto drop;
+ memcpy(buffer, skb->data, len);
+ dma_addr = dma_map_single(ndev->dev.parent, buffer, len,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(ndev->dev.parent, dma_addr))
+ goto drop;
- desc = &priv->tx_ring[q][entry];
- desc->ds_tagl = cpu_to_le16(len);
- desc->dptr = cpu_to_le32(dma_addr);
+ desc = &priv->tx_ring[q][entry];
+ desc->ds_tagl = cpu_to_le16(len);
+ desc->dptr = cpu_to_le32(dma_addr);
- buffer = skb->data + len;
- len = skb->len - len;
- dma_addr = dma_map_single(ndev->dev.parent, buffer, len, DMA_TO_DEVICE);
- if (dma_mapping_error(ndev->dev.parent, dma_addr))
- goto unmap;
+ buffer = skb->data + len;
+ len = skb->len - len;
+ dma_addr = dma_map_single(ndev->dev.parent, buffer, len,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(ndev->dev.parent, dma_addr))
+ goto unmap;
- desc++;
+ desc++;
+ } else {
+ desc = &priv->tx_ring[q][entry];
+ len = skb->len;
+ dma_addr = dma_map_single(ndev->dev.parent, skb->data, skb->len,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(ndev->dev.parent, dma_addr))
+ goto drop;
+ }
desc->ds_tagl = cpu_to_le16(len);
desc->dptr = cpu_to_le32(dma_addr);
@@ -1549,9 +1575,11 @@ static netdev_tx_t ravb_start_xmit(struct sk_buff *skb, struct net_device *ndev)
if (q == RAVB_NC) {
ts_skb = kmalloc(sizeof(*ts_skb), GFP_ATOMIC);
if (!ts_skb) {
- desc--;
- dma_unmap_single(ndev->dev.parent, dma_addr, len,
- DMA_TO_DEVICE);
+ if (num_tx_desc > 1) {
+ desc--;
+ dma_unmap_single(ndev->dev.parent, dma_addr,
+ len, DMA_TO_DEVICE);
+ }
goto unmap;
}
ts_skb->skb = skb;
@@ -1568,15 +1596,18 @@ static netdev_tx_t ravb_start_xmit(struct sk_buff *skb, struct net_device *ndev)
skb_tx_timestamp(skb);
/* Descriptor type must be set after all the above writes */
dma_wmb();
- desc->die_dt = DT_FEND;
- desc--;
- desc->die_dt = DT_FSTART;
-
+ if (num_tx_desc > 1) {
+ desc->die_dt = DT_FEND;
+ desc--;
+ desc->die_dt = DT_FSTART;
+ } else {
+ desc->die_dt = DT_FSINGLE;
+ }
ravb_modify(ndev, TCCR, TCCR_TSRQ0 << q, TCCR_TSRQ0 << q);
- priv->cur_tx[q] += NUM_TX_DESC;
+ priv->cur_tx[q] += num_tx_desc;
if (priv->cur_tx[q] - priv->dirty_tx[q] >
- (priv->num_tx_ring[q] - 1) * NUM_TX_DESC &&
+ (priv->num_tx_ring[q] - 1) * num_tx_desc &&
!ravb_tx_free(ndev, q, true))
netif_stop_subqueue(ndev, q);
@@ -1590,7 +1621,7 @@ unmap:
le16_to_cpu(desc->ds_tagl), DMA_TO_DEVICE);
drop:
dev_kfree_skb_any(skb);
- priv->tx_skb[q][entry / NUM_TX_DESC] = NULL;
+ priv->tx_skb[q][entry / num_tx_desc] = NULL;
goto exit;
}
@@ -2076,6 +2107,9 @@ static int ravb_probe(struct platform_device *pdev)
ndev->max_mtu = 2048 - (ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN);
ndev->min_mtu = ETH_MIN_MTU;
+ priv->num_tx_desc = chip_id == RCAR_GEN2 ?
+ NUM_TX_DESC_GEN2 : NUM_TX_DESC_GEN3;
+
/* Set function */
ndev->netdev_ops = &ravb_netdev_ops;
ndev->ethtool_ops = &ravb_ethtool_ops;
diff --git a/drivers/net/ethernet/rocker/rocker_main.c b/drivers/net/ethernet/rocker/rocker_main.c
index aeafdb9ac015..beb06628f22d 100644
--- a/drivers/net/ethernet/rocker/rocker_main.c
+++ b/drivers/net/ethernet/rocker/rocker_main.c
@@ -371,7 +371,7 @@ static void rocker_desc_cookie_ptr_set(const struct rocker_desc_info *desc_info,
static struct rocker_desc_info *
rocker_desc_head_get(const struct rocker_dma_ring_info *info)
{
- static struct rocker_desc_info *desc_info;
+ struct rocker_desc_info *desc_info;
u32 head = __pos_inc(info->head, info->size);
desc_info = &info->desc_info[info->head];
@@ -402,7 +402,7 @@ static void rocker_desc_head_set(const struct rocker *rocker,
static struct rocker_desc_info *
rocker_desc_tail_get(struct rocker_dma_ring_info *info)
{
- static struct rocker_desc_info *desc_info;
+ struct rocker_desc_info *desc_info;
if (info->tail == info->head)
return NULL; /* nothing to be done between head and tail */
@@ -2728,6 +2728,7 @@ rocker_fdb_offload_notify(struct rocker_port *rocker_port,
info.addr = recv_info->addr;
info.vid = recv_info->vid;
+ info.offloaded = true;
call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED,
rocker_port->dev, &info.info);
}
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c
index a9da1ad4b4f2..690aee88f0eb 100644
--- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c
@@ -298,8 +298,8 @@ static int sxgbe_init_phy(struct net_device *ndev)
/* Stop Advertising 1000BASE Capability if interface is not GMII */
if ((phy_iface == PHY_INTERFACE_MODE_MII) ||
(phy_iface == PHY_INTERFACE_MODE_RMII))
- phydev->advertising &= ~(SUPPORTED_1000baseT_Half |
- SUPPORTED_1000baseT_Full);
+ phy_set_max_speed(phydev, SPEED_1000);
+
if (phydev->phy_id == 0) {
phy_disconnect(phydev);
return -ENODEV;
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c
index 330233286e78..98fe7e762e17 100644
--- a/drivers/net/ethernet/sfc/efx.c
+++ b/drivers/net/ethernet/sfc/efx.c
@@ -2208,29 +2208,6 @@ static void efx_fini_napi(struct efx_nic *efx)
/**************************************************************************
*
- * Kernel netpoll interface
- *
- *************************************************************************/
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
-
-/* Although in the common case interrupts will be disabled, this is not
- * guaranteed. However, all our work happens inside the NAPI callback,
- * so no locking is required.
- */
-static void efx_netpoll(struct net_device *net_dev)
-{
- struct efx_nic *efx = netdev_priv(net_dev);
- struct efx_channel *channel;
-
- efx_for_each_channel(channel, efx)
- efx_schedule_channel(channel);
-}
-
-#endif
-
-/**************************************************************************
- *
* Kernel net device interface
*
*************************************************************************/
@@ -2509,9 +2486,6 @@ static const struct net_device_ops efx_netdev_ops = {
#endif
.ndo_get_phys_port_id = efx_get_phys_port_id,
.ndo_get_phys_port_name = efx_get_phys_port_name,
-#ifdef CONFIG_NET_POLL_CONTROLLER
- .ndo_poll_controller = efx_netpoll,
-#endif
.ndo_setup_tc = efx_setup_tc,
#ifdef CONFIG_RFS_ACCEL
.ndo_rx_flow_steer = efx_filter_rfs,
@@ -3847,7 +3821,6 @@ static pci_ers_result_t efx_io_slot_reset(struct pci_dev *pdev)
{
struct efx_nic *efx = pci_get_drvdata(pdev);
pci_ers_result_t status = PCI_ERS_RESULT_RECOVERED;
- int rc;
if (pci_enable_device(pdev)) {
netif_err(efx, hw, efx->net_dev,
@@ -3855,13 +3828,6 @@ static pci_ers_result_t efx_io_slot_reset(struct pci_dev *pdev)
status = PCI_ERS_RESULT_DISCONNECT;
}
- rc = pci_cleanup_aer_uncorrect_error_status(pdev);
- if (rc) {
- netif_err(efx, hw, efx->net_dev,
- "pci_cleanup_aer_uncorrect_error_status failed (%d)\n", rc);
- /* Non-fatal error. Continue. */
- }
-
return status;
}
diff --git a/drivers/net/ethernet/sfc/falcon/efx.c b/drivers/net/ethernet/sfc/falcon/efx.c
index dd5530a4f8c8..8b1f94d7a6c5 100644
--- a/drivers/net/ethernet/sfc/falcon/efx.c
+++ b/drivers/net/ethernet/sfc/falcon/efx.c
@@ -2054,29 +2054,6 @@ static void ef4_fini_napi(struct ef4_nic *efx)
/**************************************************************************
*
- * Kernel netpoll interface
- *
- *************************************************************************/
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
-
-/* Although in the common case interrupts will be disabled, this is not
- * guaranteed. However, all our work happens inside the NAPI callback,
- * so no locking is required.
- */
-static void ef4_netpoll(struct net_device *net_dev)
-{
- struct ef4_nic *efx = netdev_priv(net_dev);
- struct ef4_channel *channel;
-
- ef4_for_each_channel(channel, efx)
- ef4_schedule_channel(channel);
-}
-
-#endif
-
-/**************************************************************************
- *
* Kernel net device interface
*
*************************************************************************/
@@ -2250,9 +2227,6 @@ static const struct net_device_ops ef4_netdev_ops = {
.ndo_set_mac_address = ef4_set_mac_address,
.ndo_set_rx_mode = ef4_set_rx_mode,
.ndo_set_features = ef4_set_features,
-#ifdef CONFIG_NET_POLL_CONTROLLER
- .ndo_poll_controller = ef4_netpoll,
-#endif
.ndo_setup_tc = ef4_setup_tc,
#ifdef CONFIG_RFS_ACCEL
.ndo_rx_flow_steer = ef4_filter_rfs,
@@ -3186,7 +3160,6 @@ static pci_ers_result_t ef4_io_slot_reset(struct pci_dev *pdev)
{
struct ef4_nic *efx = pci_get_drvdata(pdev);
pci_ers_result_t status = PCI_ERS_RESULT_RECOVERED;
- int rc;
if (pci_enable_device(pdev)) {
netif_err(efx, hw, efx->net_dev,
@@ -3194,13 +3167,6 @@ static pci_ers_result_t ef4_io_slot_reset(struct pci_dev *pdev)
status = PCI_ERS_RESULT_DISCONNECT;
}
- rc = pci_cleanup_aer_uncorrect_error_status(pdev);
- if (rc) {
- netif_err(efx, hw, efx->net_dev,
- "pci_cleanup_aer_uncorrect_error_status failed (%d)\n", rc);
- /* Non-fatal error. Continue. */
- }
-
return status;
}
diff --git a/drivers/net/ethernet/smsc/smc911x.c b/drivers/net/ethernet/smsc/smc911x.c
index b1b53f6c452f..8355dfbb8ec3 100644
--- a/drivers/net/ethernet/smsc/smc911x.c
+++ b/drivers/net/ethernet/smsc/smc911x.c
@@ -513,7 +513,8 @@ static void smc911x_hardware_send_pkt(struct net_device *dev)
* now, or set the card to generates an interrupt when ready
* for the packet.
*/
-static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t
+smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct smc911x_local *lp = netdev_priv(dev);
unsigned int free;
diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c
index b944828f9ea3..4823b6a51134 100644
--- a/drivers/net/ethernet/smsc/smc91x.c
+++ b/drivers/net/ethernet/smsc/smc91x.c
@@ -638,7 +638,8 @@ done: if (!THROTTLE_TX_PKTS)
* now, or set the card to generates an interrupt when ready
* for the packet.
*/
-static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t
+smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct smc_local *lp = netdev_priv(dev);
void __iomem *ioaddr = lp->base;
@@ -2446,8 +2447,7 @@ static int smc_drv_remove(struct platform_device *pdev)
static int smc_drv_suspend(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct net_device *ndev = platform_get_drvdata(pdev);
+ struct net_device *ndev = dev_get_drvdata(dev);
if (ndev) {
if (netif_running(ndev)) {
diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c
index f0afb88d7bc2..99a5a8a7c777 100644
--- a/drivers/net/ethernet/smsc/smsc911x.c
+++ b/drivers/net/ethernet/smsc/smsc911x.c
@@ -1048,10 +1048,10 @@ static int smsc911x_mii_probe(struct net_device *dev)
phy_attached_info(phydev);
+ phy_set_max_speed(phydev, SPEED_100);
+
/* mask with MAC supported features */
- phydev->supported &= (PHY_BASIC_FEATURES | SUPPORTED_Pause |
- SUPPORTED_Asym_Pause);
- phydev->advertising = phydev->supported;
+ phy_support_asym_pause(phydev);
pdata->last_duplex = -1;
pdata->last_carrier = -1;
@@ -1786,7 +1786,8 @@ static int smsc911x_stop(struct net_device *dev)
}
/* Entry point for transmitting a packet */
-static int smsc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t
+smsc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct smsc911x_data *pdata = netdev_priv(dev);
unsigned int freespace;
diff --git a/drivers/net/ethernet/smsc/smsc9420.c b/drivers/net/ethernet/smsc/smsc9420.c
index 2fa3c1d03abc..9b6366b20110 100644
--- a/drivers/net/ethernet/smsc/smsc9420.c
+++ b/drivers/net/ethernet/smsc/smsc9420.c
@@ -1135,10 +1135,10 @@ static int smsc9420_mii_probe(struct net_device *dev)
return PTR_ERR(phydev);
}
+ phy_set_max_speed(phydev, SPEED_100);
+
/* mask with MAC supported features */
- phydev->supported &= (PHY_BASIC_FEATURES | SUPPORTED_Pause |
- SUPPORTED_Asym_Pause);
- phydev->advertising = phydev->supported;
+ phy_support_asym_pause(phydev);
phy_attached_info(phydev);
diff --git a/drivers/net/ethernet/socionext/netsec.c b/drivers/net/ethernet/socionext/netsec.c
index 7aa5ebb6766c..d9d0d03e4ce7 100644
--- a/drivers/net/ethernet/socionext/netsec.c
+++ b/drivers/net/ethernet/socionext/netsec.c
@@ -274,6 +274,7 @@ struct netsec_priv {
struct clk *clk;
u32 msg_enable;
u32 freq;
+ u32 phy_addr;
bool rx_cksum_offload_flag;
};
@@ -431,9 +432,12 @@ static int netsec_mac_update_to_phy_state(struct netsec_priv *priv)
return 0;
}
+static int netsec_phy_read(struct mii_bus *bus, int phy_addr, int reg_addr);
+
static int netsec_phy_write(struct mii_bus *bus,
int phy_addr, int reg, u16 val)
{
+ int status;
struct netsec_priv *priv = bus->priv;
if (netsec_mac_write(priv, GMAC_REG_GDR, val))
@@ -446,8 +450,19 @@ static int netsec_phy_write(struct mii_bus *bus,
GMAC_REG_SHIFT_CR_GAR)))
return -ETIMEDOUT;
- return netsec_mac_wait_while_busy(priv, GMAC_REG_GAR,
- NETSEC_GMAC_GAR_REG_GB);
+ status = netsec_mac_wait_while_busy(priv, GMAC_REG_GAR,
+ NETSEC_GMAC_GAR_REG_GB);
+
+ /* Developerbox implements RTL8211E PHY and there is
+ * a compatibility problem with F_GMAC4.
+ * RTL8211E expects MDC clock must be kept toggling for several
+ * clock cycle with MDIO high before entering the IDLE state.
+ * To meet this requirement, netsec driver needs to issue dummy
+ * read(e.g. read PHYID1(offset 0x2) register) right after write.
+ */
+ netsec_phy_read(bus, phy_addr, MII_PHYSID1);
+
+ return status;
}
static int netsec_phy_read(struct mii_bus *bus, int phy_addr, int reg_addr)
@@ -735,8 +750,11 @@ static int netsec_process_rx(struct netsec_priv *priv, int budget)
u16 idx = dring->tail;
struct netsec_de *de = dring->vaddr + (DESC_SZ * idx);
- if (de->attr & (1U << NETSEC_RX_PKT_OWN_FIELD))
+ if (de->attr & (1U << NETSEC_RX_PKT_OWN_FIELD)) {
+ /* reading the register clears the irq */
+ netsec_read(priv, NETSEC_REG_NRM_RX_PKTCNT);
break;
+ }
/* This barrier is needed to keep us from reading
* any other fields out of the netsec_de until we have
@@ -937,6 +955,9 @@ static void netsec_uninit_pkt_dring(struct netsec_priv *priv, int id)
dring->head = 0;
dring->tail = 0;
dring->pkt_cnt = 0;
+
+ if (id == NETSEC_RING_TX)
+ netdev_reset_queue(priv->ndev);
}
static void netsec_free_dring(struct netsec_priv *priv, int id)
@@ -1340,11 +1361,11 @@ static int netsec_netdev_stop(struct net_device *ndev)
netsec_uninit_pkt_dring(priv, NETSEC_RING_TX);
netsec_uninit_pkt_dring(priv, NETSEC_RING_RX);
- ret = netsec_reset_hardware(priv, false);
-
phy_stop(ndev->phydev);
phy_disconnect(ndev->phydev);
+ ret = netsec_reset_hardware(priv, false);
+
pm_runtime_put_sync(priv->dev);
return ret;
@@ -1354,6 +1375,7 @@ static int netsec_netdev_init(struct net_device *ndev)
{
struct netsec_priv *priv = netdev_priv(ndev);
int ret;
+ u16 data;
ret = netsec_alloc_dring(priv, NETSEC_RING_TX);
if (ret)
@@ -1363,6 +1385,11 @@ static int netsec_netdev_init(struct net_device *ndev)
if (ret)
goto err1;
+ /* set phy power down */
+ data = netsec_phy_read(priv->mii_bus, priv->phy_addr, MII_BMCR) |
+ BMCR_PDOWN;
+ netsec_phy_write(priv->mii_bus, priv->phy_addr, MII_BMCR, data);
+
ret = netsec_reset_hardware(priv, true);
if (ret)
goto err2;
@@ -1412,7 +1439,7 @@ static const struct net_device_ops netsec_netdev_ops = {
};
static int netsec_of_probe(struct platform_device *pdev,
- struct netsec_priv *priv)
+ struct netsec_priv *priv, u32 *phy_addr)
{
priv->phy_np = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0);
if (!priv->phy_np) {
@@ -1420,6 +1447,8 @@ static int netsec_of_probe(struct platform_device *pdev,
return -EINVAL;
}
+ *phy_addr = of_mdio_parse_addr(&pdev->dev, priv->phy_np);
+
priv->clk = devm_clk_get(&pdev->dev, NULL); /* get by 'phy_ref_clk' */
if (IS_ERR(priv->clk)) {
dev_err(&pdev->dev, "phy_ref_clk not found\n");
@@ -1620,12 +1649,14 @@ static int netsec_probe(struct platform_device *pdev)
}
if (dev_of_node(&pdev->dev))
- ret = netsec_of_probe(pdev, priv);
+ ret = netsec_of_probe(pdev, priv, &phy_addr);
else
ret = netsec_acpi_probe(pdev, priv, &phy_addr);
if (ret)
goto free_ndev;
+ priv->phy_addr = phy_addr;
+
if (!priv->freq) {
dev_err(&pdev->dev, "missing PHY reference clock frequency\n");
ret = -ENODEV;
diff --git a/drivers/net/ethernet/socionext/sni_ave.c b/drivers/net/ethernet/socionext/sni_ave.c
index f7ecceeb1e28..6732f5cbde08 100644
--- a/drivers/net/ethernet/socionext/sni_ave.c
+++ b/drivers/net/ethernet/socionext/sni_ave.c
@@ -461,16 +461,7 @@ static int ave_ethtool_set_pauseparam(struct net_device *ndev,
priv->pause_rx = pause->rx_pause;
priv->pause_tx = pause->tx_pause;
- phydev->advertising &= ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause);
- if (pause->rx_pause)
- phydev->advertising |= ADVERTISED_Pause | ADVERTISED_Asym_Pause;
- if (pause->tx_pause)
- phydev->advertising ^= ADVERTISED_Asym_Pause;
-
- if (pause->autoneg) {
- if (netif_running(ndev))
- phy_start_aneg(phydev);
- }
+ phy_set_asym_pause(phydev, pause->rx_pause, pause->tx_pause);
return 0;
}
@@ -904,11 +895,11 @@ static void ave_rxfifo_reset(struct net_device *ndev)
/* assert reset */
writel(AVE_GRR_RXFFR, priv->base + AVE_GRR);
- usleep_range(40, 50);
+ udelay(50);
/* negate reset */
writel(0, priv->base + AVE_GRR);
- usleep_range(10, 20);
+ udelay(20);
/* negate interrupt status */
writel(AVE_GI_RXOVF, priv->base + AVE_GISR);
@@ -1125,11 +1116,8 @@ static void ave_phy_adjust_link(struct net_device *ndev)
rmt_adv |= LPA_PAUSE_CAP;
if (phydev->asym_pause)
rmt_adv |= LPA_PAUSE_ASYM;
- if (phydev->advertising & ADVERTISED_Pause)
- lcl_adv |= ADVERTISE_PAUSE_CAP;
- if (phydev->advertising & ADVERTISED_Asym_Pause)
- lcl_adv |= ADVERTISE_PAUSE_ASYM;
+ lcl_adv = ethtool_adv_to_lcl_adv_t(phydev->advertising);
cap = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
if (cap & FLOW_CTRL_TX)
txcr |= AVE_TXCR_FLOCTR;
@@ -1223,11 +1211,10 @@ static int ave_init(struct net_device *ndev)
phy_ethtool_get_wol(phydev, &wol);
device_set_wakeup_capable(&ndev->dev, !!wol.supported);
- if (!phy_interface_is_rgmii(phydev)) {
- phydev->supported &= ~PHY_GBIT_FEATURES;
- phydev->supported |= PHY_BASIC_FEATURES;
- }
- phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
+ if (!phy_interface_is_rgmii(phydev))
+ phy_set_max_speed(phydev, SPEED_100);
+
+ phy_support_asym_pause(phydev);
phy_attached_info(phydev);
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index b1b305f8f414..272b9ca66314 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -365,7 +365,8 @@ struct dma_features {
/* GMAC TX FIFO is 8K, Rx FIFO is 16K */
#define BUF_SIZE_16KiB 16384
-#define BUF_SIZE_8KiB 8192
+/* RX Buffer size must be < 8191 and multiple of 4/8/16 bytes */
+#define BUF_SIZE_8KiB 8188
#define BUF_SIZE_4KiB 4096
#define BUF_SIZE_2KiB 2048
diff --git a/drivers/net/ethernet/stmicro/stmmac/descs_com.h b/drivers/net/ethernet/stmicro/stmmac/descs_com.h
index ca9d7e48034c..40d6356a7e73 100644
--- a/drivers/net/ethernet/stmicro/stmmac/descs_com.h
+++ b/drivers/net/ethernet/stmicro/stmmac/descs_com.h
@@ -31,7 +31,7 @@
/* Enhanced descriptors */
static inline void ehn_desc_rx_set_on_ring(struct dma_desc *p, int end)
{
- p->des1 |= cpu_to_le32(((BUF_SIZE_8KiB - 1)
+ p->des1 |= cpu_to_le32((BUF_SIZE_8KiB
<< ERDES1_BUFFER2_SIZE_SHIFT)
& ERDES1_BUFFER2_SIZE_MASK);
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
index f9a61f90cfbc..0f660af01a4b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
@@ -714,8 +714,9 @@ static int get_ephy_nodes(struct stmmac_priv *priv)
return -ENODEV;
}
- mdio_internal = of_find_compatible_node(mdio_mux, NULL,
+ mdio_internal = of_get_compatible_child(mdio_mux,
"allwinner,sun8i-h3-mdio-internal");
+ of_node_put(mdio_mux);
if (!mdio_internal) {
dev_err(priv->device, "Cannot get internal_mdio node\n");
return -ENODEV;
@@ -729,13 +730,20 @@ static int get_ephy_nodes(struct stmmac_priv *priv)
gmac->rst_ephy = of_reset_control_get_exclusive(iphynode, NULL);
if (IS_ERR(gmac->rst_ephy)) {
ret = PTR_ERR(gmac->rst_ephy);
- if (ret == -EPROBE_DEFER)
+ if (ret == -EPROBE_DEFER) {
+ of_node_put(iphynode);
+ of_node_put(mdio_internal);
return ret;
+ }
continue;
}
dev_info(priv->device, "Found internal PHY node\n");
+ of_node_put(iphynode);
+ of_node_put(mdio_internal);
return 0;
}
+
+ of_node_put(mdio_internal);
return -ENODEV;
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
index 0a80fa25afe3..d6bb953685fa 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
@@ -119,11 +119,23 @@
#define XGMAC_MTL_TXQ_OPMODE(x) (0x00001100 + (0x80 * (x)))
#define XGMAC_TQS GENMASK(25, 16)
#define XGMAC_TQS_SHIFT 16
+#define XGMAC_Q2TCMAP GENMASK(10, 8)
+#define XGMAC_Q2TCMAP_SHIFT 8
#define XGMAC_TTC GENMASK(6, 4)
#define XGMAC_TTC_SHIFT 4
#define XGMAC_TXQEN GENMASK(3, 2)
#define XGMAC_TXQEN_SHIFT 2
#define XGMAC_TSF BIT(1)
+#define XGMAC_MTL_TCx_ETS_CONTROL(x) (0x00001110 + (0x80 * (x)))
+#define XGMAC_MTL_TCx_QUANTUM_WEIGHT(x) (0x00001118 + (0x80 * (x)))
+#define XGMAC_MTL_TCx_SENDSLOPE(x) (0x0000111c + (0x80 * (x)))
+#define XGMAC_MTL_TCx_HICREDIT(x) (0x00001120 + (0x80 * (x)))
+#define XGMAC_MTL_TCx_LOCREDIT(x) (0x00001124 + (0x80 * (x)))
+#define XGMAC_CC BIT(3)
+#define XGMAC_TSA GENMASK(1, 0)
+#define XGMAC_SP (0x0 << 0)
+#define XGMAC_CBS (0x1 << 0)
+#define XGMAC_ETS (0x2 << 0)
#define XGMAC_MTL_RXQ_OPMODE(x) (0x00001140 + (0x80 * (x)))
#define XGMAC_RQS GENMASK(25, 16)
#define XGMAC_RQS_SHIFT 16
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
index d182f82f7b58..64b8cb88ea45 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
@@ -177,6 +177,23 @@ static void dwxgmac2_map_mtl_to_dma(struct mac_device_info *hw, u32 queue,
writel(value, ioaddr + reg);
}
+static void dwxgmac2_config_cbs(struct mac_device_info *hw,
+ u32 send_slope, u32 idle_slope,
+ u32 high_credit, u32 low_credit, u32 queue)
+{
+ void __iomem *ioaddr = hw->pcsr;
+ u32 value;
+
+ writel(send_slope, ioaddr + XGMAC_MTL_TCx_SENDSLOPE(queue));
+ writel(idle_slope, ioaddr + XGMAC_MTL_TCx_QUANTUM_WEIGHT(queue));
+ writel(high_credit, ioaddr + XGMAC_MTL_TCx_HICREDIT(queue));
+ writel(low_credit, ioaddr + XGMAC_MTL_TCx_LOCREDIT(queue));
+
+ value = readl(ioaddr + XGMAC_MTL_TCx_ETS_CONTROL(queue));
+ value |= XGMAC_CC | XGMAC_CBS;
+ writel(value, ioaddr + XGMAC_MTL_TCx_ETS_CONTROL(queue));
+}
+
static int dwxgmac2_host_irq_status(struct mac_device_info *hw,
struct stmmac_extra_stats *x)
{
@@ -316,7 +333,7 @@ const struct stmmac_ops dwxgmac210_ops = {
.prog_mtl_tx_algorithms = dwxgmac2_prog_mtl_tx_algorithms,
.set_mtl_tx_queue_weight = NULL,
.map_mtl_to_dma = dwxgmac2_map_mtl_to_dma,
- .config_cbs = NULL,
+ .config_cbs = dwxgmac2_config_cbs,
.dump_regs = NULL,
.host_irq_status = dwxgmac2_host_irq_status,
.host_mtl_irq_status = dwxgmac2_host_mtl_irq_status,
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
index 20909036e002..6c5092e7771c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
@@ -182,6 +182,9 @@ static void dwxgmac2_dma_tx_mode(void __iomem *ioaddr, int mode,
value |= 0x7 << XGMAC_TTC_SHIFT;
}
+ /* Use static TC to Queue mapping */
+ value |= (channel << XGMAC_Q2TCMAP_SHIFT) & XGMAC_Q2TCMAP;
+
value &= ~XGMAC_TXQEN;
if (qmode != MTL_QUEUE_AVB)
value |= 0x2 << XGMAC_TXQEN_SHIFT;
@@ -374,6 +377,21 @@ static void dwxgmac2_enable_tso(void __iomem *ioaddr, bool en, u32 chan)
writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
}
+static void dwxgmac2_qmode(void __iomem *ioaddr, u32 channel, u8 qmode)
+{
+ u32 value = readl(ioaddr + XGMAC_MTL_TXQ_OPMODE(channel));
+
+ value &= ~XGMAC_TXQEN;
+ if (qmode != MTL_QUEUE_AVB) {
+ value |= 0x2 << XGMAC_TXQEN_SHIFT;
+ writel(0, ioaddr + XGMAC_MTL_TCx_ETS_CONTROL(channel));
+ } else {
+ value |= 0x1 << XGMAC_TXQEN_SHIFT;
+ }
+
+ writel(value, ioaddr + XGMAC_MTL_TXQ_OPMODE(channel));
+}
+
static void dwxgmac2_set_bfsize(void __iomem *ioaddr, int bfsize, u32 chan)
{
u32 value;
@@ -407,5 +425,6 @@ const struct stmmac_dma_ops dwxgmac210_dma_ops = {
.set_rx_tail_ptr = dwxgmac2_set_rx_tail_ptr,
.set_tx_tail_ptr = dwxgmac2_set_tx_tail_ptr,
.enable_tso = dwxgmac2_enable_tso,
+ .qmode = dwxgmac2_qmode,
.set_bfsize = dwxgmac2_set_bfsize,
};
diff --git a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
index 77914c89d749..5ef91a790f9d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
@@ -262,7 +262,7 @@ static void enh_desc_init_rx_desc(struct dma_desc *p, int disable_rx_ic,
int mode, int end)
{
p->des0 |= cpu_to_le32(RDES0_OWN);
- p->des1 |= cpu_to_le32((BUF_SIZE_8KiB - 1) & ERDES1_BUFFER1_SIZE_MASK);
+ p->des1 |= cpu_to_le32(BUF_SIZE_8KiB & ERDES1_BUFFER1_SIZE_MASK);
if (mode == STMMAC_CHAIN_MODE)
ehn_desc_rx_set_on_chain(p);
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.c b/drivers/net/ethernet/stmicro/stmmac/hwif.c
index 357309a6d6a5..81b966a8261b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.c
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.c
@@ -133,7 +133,7 @@ static const struct stmmac_hwif_entry {
.mac = &dwmac4_ops,
.hwtimestamp = &stmmac_ptp,
.mode = NULL,
- .tc = NULL,
+ .tc = &dwmac510_tc_ops,
.setup = dwmac4_setup,
.quirks = stmmac_dwmac4_quirks,
}, {
@@ -150,7 +150,7 @@ static const struct stmmac_hwif_entry {
.mac = &dwmac410_ops,
.hwtimestamp = &stmmac_ptp,
.mode = &dwmac4_ring_mode_ops,
- .tc = NULL,
+ .tc = &dwmac510_tc_ops,
.setup = dwmac4_setup,
.quirks = NULL,
}, {
@@ -167,7 +167,7 @@ static const struct stmmac_hwif_entry {
.mac = &dwmac410_ops,
.hwtimestamp = &stmmac_ptp,
.mode = &dwmac4_ring_mode_ops,
- .tc = NULL,
+ .tc = &dwmac510_tc_ops,
.setup = dwmac4_setup,
.quirks = NULL,
}, {
@@ -201,7 +201,7 @@ static const struct stmmac_hwif_entry {
.mac = &dwxgmac210_ops,
.hwtimestamp = &stmmac_ptp,
.mode = NULL,
- .tc = NULL,
+ .tc = &dwmac510_tc_ops,
.setup = dwxgmac2_setup,
.quirks = NULL,
},
diff --git a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
index a7ffc73fffe8..d8c5bc412219 100644
--- a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
+++ b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
@@ -59,7 +59,7 @@ static int jumbo_frm(void *p, struct sk_buff *skb, int csum)
desc->des3 = cpu_to_le32(des2 + BUF_SIZE_4KiB);
stmmac_prepare_tx_desc(priv, desc, 1, bmax, csum,
- STMMAC_RING_MODE, 0, false, skb->len);
+ STMMAC_RING_MODE, 1, false, skb->len);
tx_q->tx_skbuff[entry] = NULL;
entry = STMMAC_GET_ENTRY(entry, DMA_TX_SIZE);
@@ -91,7 +91,7 @@ static int jumbo_frm(void *p, struct sk_buff *skb, int csum)
tx_q->tx_skbuff_dma[entry].is_jumbo = true;
desc->des3 = cpu_to_le32(des2 + BUF_SIZE_4KiB);
stmmac_prepare_tx_desc(priv, desc, 1, nopaged_len, csum,
- STMMAC_RING_MODE, 0, true, skb->len);
+ STMMAC_RING_MODE, 1, true, skb->len);
}
tx_q->cur_tx = entry;
@@ -140,7 +140,7 @@ static void clean_desc3(void *priv_ptr, struct dma_desc *p)
static int set_16kib_bfsize(int mtu)
{
int ret = 0;
- if (unlikely(mtu >= BUF_SIZE_8KiB))
+ if (unlikely(mtu > BUF_SIZE_8KiB))
ret = BUF_SIZE_16KiB;
return ret;
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 75896d6ba6e2..076a8be18d67 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -991,17 +991,20 @@ static int stmmac_init_phy(struct net_device *dev)
if ((interface == PHY_INTERFACE_MODE_MII) ||
(interface == PHY_INTERFACE_MODE_RMII) ||
(max_speed < 1000 && max_speed > 0))
- phydev->advertising &= ~(SUPPORTED_1000baseT_Half |
- SUPPORTED_1000baseT_Full);
+ phy_set_max_speed(phydev, SPEED_100);
/*
* Half-duplex mode not supported with multiqueue
* half-duplex can only works with single queue
*/
- if (tx_cnt > 1)
- phydev->supported &= ~(SUPPORTED_1000baseT_Half |
- SUPPORTED_100baseT_Half |
- SUPPORTED_10baseT_Half);
+ if (tx_cnt > 1) {
+ phy_remove_link_mode(phydev,
+ ETHTOOL_LINK_MODE_10baseT_Half_BIT);
+ phy_remove_link_mode(phydev,
+ ETHTOOL_LINK_MODE_100baseT_Half_BIT);
+ phy_remove_link_mode(phydev,
+ ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
+ }
/*
* Broken HW is sometimes missing the pull-up resistor on the
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
index b72ef171477e..bdd351597b55 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
@@ -243,7 +243,7 @@ static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg,
*/
int stmmac_mdio_reset(struct mii_bus *bus)
{
-#if defined(CONFIG_STMMAC_PLATFORM)
+#if IS_ENABLED(CONFIG_STMMAC_PLATFORM)
struct net_device *ndev = bus->priv;
struct stmmac_priv *priv = netdev_priv(ndev);
unsigned int mii_address = priv->hw->mii.addr;
diff --git a/drivers/net/ethernet/sun/ldmvsw.c b/drivers/net/ethernet/sun/ldmvsw.c
index d42f47f6c632..644e42c181ee 100644
--- a/drivers/net/ethernet/sun/ldmvsw.c
+++ b/drivers/net/ethernet/sun/ldmvsw.c
@@ -113,7 +113,7 @@ static u16 vsw_select_queue(struct net_device *dev, struct sk_buff *skb,
}
/* Wrappers to common functions */
-static int vsw_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t vsw_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
return sunvnet_start_xmit_common(skb, dev, vsw_tx_port_find);
}
diff --git a/drivers/net/ethernet/sun/sunbmac.c b/drivers/net/ethernet/sun/sunbmac.c
index f047b2797156..720b7ac77f3b 100644
--- a/drivers/net/ethernet/sun/sunbmac.c
+++ b/drivers/net/ethernet/sun/sunbmac.c
@@ -950,7 +950,8 @@ static void bigmac_tx_timeout(struct net_device *dev)
}
/* Put a packet on the wire. */
-static int bigmac_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t
+bigmac_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct bigmac *bp = netdev_priv(dev);
int len, entry;
diff --git a/drivers/net/ethernet/sun/sunhme.c b/drivers/net/ethernet/sun/sunhme.c
index 06da2f59fcbf..863fd602fd33 100644
--- a/drivers/net/ethernet/sun/sunhme.c
+++ b/drivers/net/ethernet/sun/sunhme.c
@@ -2999,7 +2999,7 @@ static int happy_meal_pci_probe(struct pci_dev *pdev,
/* Now make sure pci_dev cookie is there. */
#ifdef CONFIG_SPARC
dp = pci_device_to_OF_node(pdev);
- strcpy(prom_name, dp->name);
+ snprintf(prom_name, sizeof(prom_name), "%pOFn", dp);
#else
if (is_quattro_p(pdev))
strcpy(prom_name, "SUNW,qfe");
diff --git a/drivers/net/ethernet/sun/sunqe.c b/drivers/net/ethernet/sun/sunqe.c
index 7fe0d5e33922..1468fa0a54e9 100644
--- a/drivers/net/ethernet/sun/sunqe.c
+++ b/drivers/net/ethernet/sun/sunqe.c
@@ -570,7 +570,7 @@ out:
}
/* Get a packet queued to go onto the wire. */
-static int qe_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t qe_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct sunqe *qep = netdev_priv(dev);
struct sunqe_buffers *qbufs = qep->buffers;
diff --git a/drivers/net/ethernet/sun/sunvnet.c b/drivers/net/ethernet/sun/sunvnet.c
index 12539b357a78..590172818b92 100644
--- a/drivers/net/ethernet/sun/sunvnet.c
+++ b/drivers/net/ethernet/sun/sunvnet.c
@@ -247,7 +247,7 @@ static u16 vnet_select_queue(struct net_device *dev, struct sk_buff *skb,
}
/* Wrappers to common functions */
-static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t vnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
return sunvnet_start_xmit_common(skb, dev, vnet_tx_port_find);
}
diff --git a/drivers/net/ethernet/sun/sunvnet_common.c b/drivers/net/ethernet/sun/sunvnet_common.c
index d8f4c3f28150..baa3088b475c 100644
--- a/drivers/net/ethernet/sun/sunvnet_common.c
+++ b/drivers/net/ethernet/sun/sunvnet_common.c
@@ -1216,9 +1216,10 @@ static inline struct sk_buff *vnet_skb_shape(struct sk_buff *skb, int ncookies)
return skb;
}
-static int vnet_handle_offloads(struct vnet_port *port, struct sk_buff *skb,
- struct vnet_port *(*vnet_tx_port)
- (struct sk_buff *, struct net_device *))
+static netdev_tx_t
+vnet_handle_offloads(struct vnet_port *port, struct sk_buff *skb,
+ struct vnet_port *(*vnet_tx_port)
+ (struct sk_buff *, struct net_device *))
{
struct net_device *dev = VNET_PORT_TO_NET_DEVICE(port);
struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING];
@@ -1321,9 +1322,10 @@ out_dropped:
return NETDEV_TX_OK;
}
-int sunvnet_start_xmit_common(struct sk_buff *skb, struct net_device *dev,
- struct vnet_port *(*vnet_tx_port)
- (struct sk_buff *, struct net_device *))
+netdev_tx_t
+sunvnet_start_xmit_common(struct sk_buff *skb, struct net_device *dev,
+ struct vnet_port *(*vnet_tx_port)
+ (struct sk_buff *, struct net_device *))
{
struct vnet_port *port = NULL;
struct vio_dring_state *dr;
diff --git a/drivers/net/ethernet/sun/sunvnet_common.h b/drivers/net/ethernet/sun/sunvnet_common.h
index 1ea0b016580a..2b808d2482d6 100644
--- a/drivers/net/ethernet/sun/sunvnet_common.h
+++ b/drivers/net/ethernet/sun/sunvnet_common.h
@@ -136,9 +136,10 @@ int sunvnet_close_common(struct net_device *dev);
void sunvnet_set_rx_mode_common(struct net_device *dev, struct vnet *vp);
int sunvnet_set_mac_addr_common(struct net_device *dev, void *p);
void sunvnet_tx_timeout_common(struct net_device *dev);
-int sunvnet_start_xmit_common(struct sk_buff *skb, struct net_device *dev,
- struct vnet_port *(*vnet_tx_port)
- (struct sk_buff *, struct net_device *));
+netdev_tx_t
+sunvnet_start_xmit_common(struct sk_buff *skb, struct net_device *dev,
+ struct vnet_port *(*vnet_tx_port)
+ (struct sk_buff *, struct net_device *));
#ifdef CONFIG_NET_POLL_CONTROLLER
void sunvnet_poll_controller_common(struct net_device *dev, struct vnet *vp);
#endif
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index 832bce07c385..500f7ed8c58c 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -484,13 +484,13 @@ enum {
};
#define CPSW_STAT(m) CPSW_STATS, \
- sizeof(((struct cpsw_hw_stats *)0)->m), \
+ FIELD_SIZEOF(struct cpsw_hw_stats, m), \
offsetof(struct cpsw_hw_stats, m)
#define CPDMA_RX_STAT(m) CPDMA_RX_STATS, \
- sizeof(((struct cpdma_chan_stats *)0)->m), \
+ FIELD_SIZEOF(struct cpdma_chan_stats, m), \
offsetof(struct cpdma_chan_stats, m)
#define CPDMA_TX_STAT(m) CPDMA_TX_STATS, \
- sizeof(((struct cpdma_chan_stats *)0)->m), \
+ FIELD_SIZEOF(struct cpdma_chan_stats, m), \
offsetof(struct cpdma_chan_stats, m)
static const struct cpsw_stats cpsw_gstrings_stats[] = {
@@ -570,16 +570,14 @@ static inline int cpsw_get_slave_port(u32 slave_num)
return slave_num + 1;
}
-static void cpsw_add_mcast(struct cpsw_priv *priv, u8 *addr)
+static void cpsw_add_mcast(struct cpsw_priv *priv, const u8 *addr)
{
struct cpsw_common *cpsw = priv->cpsw;
if (cpsw->data.dual_emac) {
struct cpsw_slave *slave = cpsw->slaves + priv->emac_port;
- int slave_port = cpsw_get_slave_port(slave->slave_num);
- cpsw_ale_add_mcast(cpsw->ale, addr,
- 1 << slave_port | ALE_PORT_HOST,
+ cpsw_ale_add_mcast(cpsw->ale, addr, ALE_PORT_HOST,
ALE_VLAN, slave->port_vlan, 0);
return;
}
@@ -642,6 +640,7 @@ static void cpsw_set_promiscious(struct net_device *ndev, bool enable)
/* Clear all mcast from ALE */
cpsw_ale_flush_multicast(ale, ALE_ALL_PORTS, -1);
+ __dev_mc_unsync(ndev, NULL);
/* Flood All Unicast Packets to Host port */
cpsw_ale_control_set(ale, 0, ALE_P0_UNI_FLOOD, 1);
@@ -662,16 +661,35 @@ static void cpsw_set_promiscious(struct net_device *ndev, bool enable)
}
}
-static void cpsw_ndo_set_rx_mode(struct net_device *ndev)
+static int cpsw_add_mc_addr(struct net_device *ndev, const u8 *addr)
+{
+ struct cpsw_priv *priv = netdev_priv(ndev);
+
+ cpsw_add_mcast(priv, addr);
+ return 0;
+}
+
+static int cpsw_del_mc_addr(struct net_device *ndev, const u8 *addr)
{
struct cpsw_priv *priv = netdev_priv(ndev);
struct cpsw_common *cpsw = priv->cpsw;
- int vid;
+ int vid, flags;
- if (cpsw->data.dual_emac)
+ if (cpsw->data.dual_emac) {
vid = cpsw->slaves[priv->emac_port].port_vlan;
- else
- vid = cpsw->data.default_vlan;
+ flags = ALE_VLAN;
+ } else {
+ vid = 0;
+ flags = 0;
+ }
+
+ cpsw_ale_del_mcast(cpsw->ale, addr, 0, flags, vid);
+ return 0;
+}
+
+static void cpsw_ndo_set_rx_mode(struct net_device *ndev)
+{
+ struct cpsw_common *cpsw = ndev_to_cpsw(ndev);
if (ndev->flags & IFF_PROMISC) {
/* Enable promiscuous mode */
@@ -684,19 +702,9 @@ static void cpsw_ndo_set_rx_mode(struct net_device *ndev)
}
/* Restore allmulti on vlans if necessary */
- cpsw_ale_set_allmulti(cpsw->ale, priv->ndev->flags & IFF_ALLMULTI);
-
- /* Clear all mcast from ALE */
- cpsw_ale_flush_multicast(cpsw->ale, ALE_ALL_PORTS, vid);
+ cpsw_ale_set_allmulti(cpsw->ale, ndev->flags & IFF_ALLMULTI);
- if (!netdev_mc_empty(ndev)) {
- struct netdev_hw_addr *ha;
-
- /* program multicast address list into ALE register */
- netdev_for_each_mc_addr(ha, ndev) {
- cpsw_add_mcast(priv, ha->addr);
- }
- }
+ __dev_mc_sync(ndev, cpsw_add_mc_addr, cpsw_del_mc_addr);
}
static void cpsw_intr_enable(struct cpsw_common *cpsw)
@@ -1410,7 +1418,7 @@ static inline void cpsw_add_dual_emac_def_ale_entries(
cpsw_ale_add_vlan(cpsw->ale, slave->port_vlan, port_mask,
port_mask, port_mask, 0);
cpsw_ale_add_mcast(cpsw->ale, priv->ndev->broadcast,
- port_mask, ALE_VLAN, slave->port_vlan, 0);
+ ALE_PORT_HOST, ALE_VLAN, slave->port_vlan, 0);
cpsw_ale_add_ucast(cpsw->ale, priv->mac_addr,
HOST_PORT_NUM, ALE_VLAN |
ALE_SECURE, slave->port_vlan);
@@ -1956,6 +1964,7 @@ static int cpsw_ndo_stop(struct net_device *ndev)
struct cpsw_common *cpsw = priv->cpsw;
cpsw_info(priv, ifdown, "shutting down cpsw device\n");
+ __dev_mc_unsync(priv->ndev, cpsw_del_mc_addr);
netif_tx_stop_all_queues(priv->ndev);
netif_carrier_off(priv->ndev);
@@ -2293,16 +2302,19 @@ static inline int cpsw_add_vlan_ale_entry(struct cpsw_priv *priv,
{
int ret;
int unreg_mcast_mask = 0;
+ int mcast_mask;
u32 port_mask;
struct cpsw_common *cpsw = priv->cpsw;
if (cpsw->data.dual_emac) {
port_mask = (1 << (priv->emac_port + 1)) | ALE_PORT_HOST;
+ mcast_mask = ALE_PORT_HOST;
if (priv->ndev->flags & IFF_ALLMULTI)
- unreg_mcast_mask = port_mask;
+ unreg_mcast_mask = mcast_mask;
} else {
port_mask = ALE_ALL_PORTS;
+ mcast_mask = port_mask;
if (priv->ndev->flags & IFF_ALLMULTI)
unreg_mcast_mask = ALE_ALL_PORTS;
@@ -2321,7 +2333,7 @@ static inline int cpsw_add_vlan_ale_entry(struct cpsw_priv *priv,
goto clean_vid;
ret = cpsw_ale_add_mcast(cpsw->ale, priv->ndev->broadcast,
- port_mask, ALE_VLAN, vid, 0);
+ mcast_mask, ALE_VLAN, vid, 0);
if (ret != 0)
goto clean_vlan_ucast;
return 0;
@@ -3658,8 +3670,7 @@ static int cpsw_remove(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP
static int cpsw_suspend(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct net_device *ndev = platform_get_drvdata(pdev);
+ struct net_device *ndev = dev_get_drvdata(dev);
struct cpsw_common *cpsw = ndev_to_cpsw(ndev);
if (cpsw->data.dual_emac) {
@@ -3682,8 +3693,7 @@ static int cpsw_suspend(struct device *dev)
static int cpsw_resume(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct net_device *ndev = platform_get_drvdata(pdev);
+ struct net_device *ndev = dev_get_drvdata(dev);
struct cpsw_common *cpsw = ndev_to_cpsw(ndev);
/* Select default pin state */
diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c
index 5766225a4ce1..798c989d5d93 100644
--- a/drivers/net/ethernet/ti/cpsw_ale.c
+++ b/drivers/net/ethernet/ti/cpsw_ale.c
@@ -136,7 +136,7 @@ static inline void cpsw_ale_get_addr(u32 *ale_entry, u8 *addr)
addr[i] = cpsw_ale_get_field(ale_entry, 40 - 8*i, 8);
}
-static inline void cpsw_ale_set_addr(u32 *ale_entry, u8 *addr)
+static inline void cpsw_ale_set_addr(u32 *ale_entry, const u8 *addr)
{
int i;
@@ -175,7 +175,7 @@ static int cpsw_ale_write(struct cpsw_ale *ale, int idx, u32 *ale_entry)
return idx;
}
-static int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr, u16 vid)
+static int cpsw_ale_match_addr(struct cpsw_ale *ale, const u8 *addr, u16 vid)
{
u32 ale_entry[ALE_ENTRY_WORDS];
int type, idx;
@@ -309,7 +309,7 @@ static inline void cpsw_ale_set_vlan_entry_type(u32 *ale_entry,
}
}
-int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port,
+int cpsw_ale_add_ucast(struct cpsw_ale *ale, const u8 *addr, int port,
int flags, u16 vid)
{
u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
@@ -336,7 +336,7 @@ int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port,
}
EXPORT_SYMBOL_GPL(cpsw_ale_add_ucast);
-int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port,
+int cpsw_ale_del_ucast(struct cpsw_ale *ale, const u8 *addr, int port,
int flags, u16 vid)
{
u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
@@ -352,7 +352,7 @@ int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port,
}
EXPORT_SYMBOL_GPL(cpsw_ale_del_ucast);
-int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
+int cpsw_ale_add_mcast(struct cpsw_ale *ale, const u8 *addr, int port_mask,
int flags, u16 vid, int mcast_state)
{
u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
@@ -386,7 +386,7 @@ int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
}
EXPORT_SYMBOL_GPL(cpsw_ale_add_mcast);
-int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
+int cpsw_ale_del_mcast(struct cpsw_ale *ale, const u8 *addr, int port_mask,
int flags, u16 vid)
{
u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
diff --git a/drivers/net/ethernet/ti/cpsw_ale.h b/drivers/net/ethernet/ti/cpsw_ale.h
index d4fe9016429b..cd07a3e96d57 100644
--- a/drivers/net/ethernet/ti/cpsw_ale.h
+++ b/drivers/net/ethernet/ti/cpsw_ale.h
@@ -105,13 +105,13 @@ void cpsw_ale_start(struct cpsw_ale *ale);
void cpsw_ale_stop(struct cpsw_ale *ale);
int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask, int vid);
-int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port,
+int cpsw_ale_add_ucast(struct cpsw_ale *ale, const u8 *addr, int port,
int flags, u16 vid);
-int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port,
+int cpsw_ale_del_ucast(struct cpsw_ale *ale, const u8 *addr, int port,
int flags, u16 vid);
-int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
+int cpsw_ale_add_mcast(struct cpsw_ale *ale, const u8 *addr, int port_mask,
int flags, u16 vid, int mcast_state);
-int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
+int cpsw_ale_del_mcast(struct cpsw_ale *ale, const u8 *addr, int port_mask,
int flags, u16 vid);
int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag,
int reg_mcast, int unreg_mcast);
diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c
index f270beebb428..9153db120352 100644
--- a/drivers/net/ethernet/ti/davinci_emac.c
+++ b/drivers/net/ethernet/ti/davinci_emac.c
@@ -2002,8 +2002,7 @@ static int davinci_emac_remove(struct platform_device *pdev)
static int davinci_emac_suspend(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct net_device *ndev = platform_get_drvdata(pdev);
+ struct net_device *ndev = dev_get_drvdata(dev);
if (netif_running(ndev))
emac_dev_stop(ndev);
@@ -2013,8 +2012,7 @@ static int davinci_emac_suspend(struct device *dev)
static int davinci_emac_resume(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct net_device *ndev = platform_get_drvdata(pdev);
+ struct net_device *ndev = dev_get_drvdata(dev);
if (netif_running(ndev))
emac_dev_open(ndev);
diff --git a/drivers/net/ethernet/ti/netcp_core.c b/drivers/net/ethernet/ti/netcp_core.c
index a1d335a3c5e4..1f612268c998 100644
--- a/drivers/net/ethernet/ti/netcp_core.c
+++ b/drivers/net/ethernet/ti/netcp_core.c
@@ -225,17 +225,6 @@ static int emac_arch_get_mac_addr(char *x, void __iomem *efuse_mac, u32 swap)
return 0;
}
-static const char *netcp_node_name(struct device_node *node)
-{
- const char *name;
-
- if (of_property_read_string(node, "label", &name) < 0)
- name = node->name;
- if (!name)
- name = "unknown";
- return name;
-}
-
/* Module management routines */
static int netcp_register_interface(struct netcp_intf *netcp)
{
@@ -267,8 +256,13 @@ static int netcp_module_probe(struct netcp_device *netcp_device,
}
for_each_available_child_of_node(devices, child) {
- const char *name = netcp_node_name(child);
+ const char *name;
+ char node_name[32];
+ if (of_property_read_string(node, "label", &name) < 0) {
+ snprintf(node_name, sizeof(node_name), "%pOFn", child);
+ name = node_name;
+ }
if (!strcasecmp(module->name, name))
break;
}
@@ -2209,8 +2203,8 @@ static int netcp_probe(struct platform_device *pdev)
for_each_available_child_of_node(interfaces, child) {
ret = netcp_create_interface(netcp_device, child);
if (ret) {
- dev_err(dev, "could not create interface(%s)\n",
- child->name);
+ dev_err(dev, "could not create interface(%pOFn)\n",
+ child);
goto probe_quit_interface;
}
}
diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c
index 72b98e27c992..0397ccb6597e 100644
--- a/drivers/net/ethernet/ti/netcp_ethss.c
+++ b/drivers/net/ethernet/ti/netcp_ethss.c
@@ -3137,15 +3137,15 @@ static void init_secondary_ports(struct gbe_priv *gbe_dev,
for_each_child_of_node(node, port) {
slave = devm_kzalloc(dev, sizeof(*slave), GFP_KERNEL);
if (!slave) {
- dev_err(dev, "memory alloc failed for secondary port(%s), skipping...\n",
- port->name);
+ dev_err(dev, "memory alloc failed for secondary port(%pOFn), skipping...\n",
+ port);
continue;
}
if (init_slave(gbe_dev, slave, port)) {
dev_err(dev,
- "Failed to initialize secondary port(%s), skipping...\n",
- port->name);
+ "Failed to initialize secondary port(%pOFn), skipping...\n",
+ port);
devm_kfree(dev, slave);
continue;
}
@@ -3239,8 +3239,8 @@ static int set_xgbe_ethss10_priv(struct gbe_priv *gbe_dev,
ret = of_address_to_resource(node, XGBE_SS_REG_INDEX, &res);
if (ret) {
dev_err(gbe_dev->dev,
- "Can't xlate xgbe of node(%s) ss address at %d\n",
- node->name, XGBE_SS_REG_INDEX);
+ "Can't xlate xgbe of node(%pOFn) ss address at %d\n",
+ node, XGBE_SS_REG_INDEX);
return ret;
}
@@ -3254,8 +3254,8 @@ static int set_xgbe_ethss10_priv(struct gbe_priv *gbe_dev,
ret = of_address_to_resource(node, XGBE_SM_REG_INDEX, &res);
if (ret) {
dev_err(gbe_dev->dev,
- "Can't xlate xgbe of node(%s) sm address at %d\n",
- node->name, XGBE_SM_REG_INDEX);
+ "Can't xlate xgbe of node(%pOFn) sm address at %d\n",
+ node, XGBE_SM_REG_INDEX);
return ret;
}
@@ -3269,8 +3269,8 @@ static int set_xgbe_ethss10_priv(struct gbe_priv *gbe_dev,
ret = of_address_to_resource(node, XGBE_SERDES_REG_INDEX, &res);
if (ret) {
dev_err(gbe_dev->dev,
- "Can't xlate xgbe serdes of node(%s) address at %d\n",
- node->name, XGBE_SERDES_REG_INDEX);
+ "Can't xlate xgbe serdes of node(%pOFn) address at %d\n",
+ node, XGBE_SERDES_REG_INDEX);
return ret;
}
@@ -3347,8 +3347,8 @@ static int get_gbe_resource_version(struct gbe_priv *gbe_dev,
ret = of_address_to_resource(node, GBE_SS_REG_INDEX, &res);
if (ret) {
dev_err(gbe_dev->dev,
- "Can't translate of node(%s) of gbe ss address at %d\n",
- node->name, GBE_SS_REG_INDEX);
+ "Can't translate of node(%pOFn) of gbe ss address at %d\n",
+ node, GBE_SS_REG_INDEX);
return ret;
}
@@ -3372,8 +3372,8 @@ static int set_gbe_ethss14_priv(struct gbe_priv *gbe_dev,
ret = of_address_to_resource(node, GBE_SGMII34_REG_INDEX, &res);
if (ret) {
dev_err(gbe_dev->dev,
- "Can't translate of gbe node(%s) address at index %d\n",
- node->name, GBE_SGMII34_REG_INDEX);
+ "Can't translate of gbe node(%pOFn) address at index %d\n",
+ node, GBE_SGMII34_REG_INDEX);
return ret;
}
@@ -3388,8 +3388,8 @@ static int set_gbe_ethss14_priv(struct gbe_priv *gbe_dev,
ret = of_address_to_resource(node, GBE_SM_REG_INDEX, &res);
if (ret) {
dev_err(gbe_dev->dev,
- "Can't translate of gbe node(%s) address at index %d\n",
- node->name, GBE_SM_REG_INDEX);
+ "Can't translate of gbe node(%pOFn) address at index %d\n",
+ node, GBE_SM_REG_INDEX);
return ret;
}
@@ -3498,8 +3498,8 @@ static int set_gbenu_ethss_priv(struct gbe_priv *gbe_dev,
ret = of_address_to_resource(node, GBENU_SM_REG_INDEX, &res);
if (ret) {
dev_err(gbe_dev->dev,
- "Can't translate of gbenu node(%s) addr at index %d\n",
- node->name, GBENU_SM_REG_INDEX);
+ "Can't translate of gbenu node(%pOFn) addr at index %d\n",
+ node, GBENU_SM_REG_INDEX);
return ret;
}
@@ -3642,7 +3642,7 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev,
ret = netcp_xgbe_serdes_init(gbe_dev->xgbe_serdes_regs,
gbe_dev->ss_regs);
} else {
- dev_err(dev, "unknown GBE node(%s)\n", node->name);
+ dev_err(dev, "unknown GBE node(%pOFn)\n", node);
ret = -ENODEV;
}
@@ -3667,8 +3667,8 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev,
for_each_child_of_node(interfaces, interface) {
ret = of_property_read_u32(interface, "slave-port", &slave_num);
if (ret) {
- dev_err(dev, "missing slave-port parameter, skipping interface configuration for %s\n",
- interface->name);
+ dev_err(dev, "missing slave-port parameter, skipping interface configuration for %pOFn\n",
+ interface);
continue;
}
gbe_dev->num_slaves++;
diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_net.c b/drivers/net/ethernet/toshiba/ps3_gelic_net.c
index 88d74aef218a..75237c81c63d 100644
--- a/drivers/net/ethernet/toshiba/ps3_gelic_net.c
+++ b/drivers/net/ethernet/toshiba/ps3_gelic_net.c
@@ -845,9 +845,9 @@ static int gelic_card_kick_txdma(struct gelic_card *card,
* @skb: packet to send out
* @netdev: interface device structure
*
- * returns 0 on success, <0 on failure
+ * returns NETDEV_TX_OK on success, NETDEV_TX_BUSY on failure
*/
-int gelic_net_xmit(struct sk_buff *skb, struct net_device *netdev)
+netdev_tx_t gelic_net_xmit(struct sk_buff *skb, struct net_device *netdev)
{
struct gelic_card *card = netdev_card(netdev);
struct gelic_descr *descr;
diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_net.h b/drivers/net/ethernet/toshiba/ps3_gelic_net.h
index 003d0452d9cb..fbbf9b54b173 100644
--- a/drivers/net/ethernet/toshiba/ps3_gelic_net.h
+++ b/drivers/net/ethernet/toshiba/ps3_gelic_net.h
@@ -370,7 +370,7 @@ void gelic_card_up(struct gelic_card *card);
void gelic_card_down(struct gelic_card *card);
int gelic_net_open(struct net_device *netdev);
int gelic_net_stop(struct net_device *netdev);
-int gelic_net_xmit(struct sk_buff *skb, struct net_device *netdev);
+netdev_tx_t gelic_net_xmit(struct sk_buff *skb, struct net_device *netdev);
void gelic_net_set_multi(struct net_device *netdev);
void gelic_net_tx_timeout(struct net_device *netdev);
int gelic_net_setup_netdev(struct net_device *netdev, struct gelic_card *card);
diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c b/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c
index 302079e22b06..00ab417694ad 100644
--- a/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c
+++ b/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c
@@ -1094,7 +1094,7 @@ static int gelic_wl_get_encode(struct net_device *netdev,
struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
struct iw_point *enc = &data->encoding;
unsigned long irqflag;
- unsigned int key_index, index_specified;
+ unsigned int key_index;
int ret = 0;
pr_debug("%s: <-\n", __func__);
@@ -1105,13 +1105,10 @@ static int gelic_wl_get_encode(struct net_device *netdev,
return -EINVAL;
spin_lock_irqsave(&wl->lock, irqflag);
- if (key_index) {
- index_specified = 1;
+ if (key_index)
key_index--;
- } else {
- index_specified = 0;
+ else
key_index = wl->current_key;
- }
if (wl->group_cipher_method == GELIC_WL_CIPHER_WEP) {
switch (wl->auth_method) {
diff --git a/drivers/net/ethernet/toshiba/spider_net.c b/drivers/net/ethernet/toshiba/spider_net.c
index d925b8203996..23417266b7ec 100644
--- a/drivers/net/ethernet/toshiba/spider_net.c
+++ b/drivers/net/ethernet/toshiba/spider_net.c
@@ -880,9 +880,9 @@ out:
* @skb: packet to send out
* @netdev: interface device structure
*
- * returns 0 on success, !0 on failure
+ * returns NETDEV_TX_OK on success, NETDEV_TX_BUSY on failure
*/
-static int
+static netdev_tx_t
spider_net_xmit(struct sk_buff *skb, struct net_device *netdev)
{
int cnt;
diff --git a/drivers/net/ethernet/toshiba/tc35815.c b/drivers/net/ethernet/toshiba/tc35815.c
index cce9c9ed46aa..6a71c2c0f17d 100644
--- a/drivers/net/ethernet/toshiba/tc35815.c
+++ b/drivers/net/ethernet/toshiba/tc35815.c
@@ -474,7 +474,8 @@ static void free_rxbuf_skb(struct pci_dev *hwdev, struct sk_buff *skb, dma_addr_
/* Index to functions, as function prototypes. */
static int tc35815_open(struct net_device *dev);
-static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev);
+static netdev_tx_t tc35815_send_packet(struct sk_buff *skb,
+ struct net_device *dev);
static irqreturn_t tc35815_interrupt(int irq, void *dev_id);
static int tc35815_rx(struct net_device *dev, int limit);
static int tc35815_poll(struct napi_struct *napi, int budget);
@@ -628,7 +629,7 @@ static int tc_mii_probe(struct net_device *dev)
phy_attached_info(phydev);
/* mask with MAC supported features */
- phydev->supported &= PHY_BASIC_FEATURES;
+ phy_set_max_speed(phydev, SPEED_100);
dropmask = 0;
if (options.speed == 10)
dropmask |= SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full;
@@ -1248,7 +1249,8 @@ tc35815_open(struct net_device *dev)
* invariant will hold if you make sure that the netif_*_queue()
* calls are done at the proper times.
*/
-static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t
+tc35815_send_packet(struct sk_buff *skb, struct net_device *dev)
{
struct tc35815_local *lp = netdev_priv(dev);
struct TxFD *txfd;
diff --git a/drivers/net/ethernet/wiznet/w5300.c b/drivers/net/ethernet/wiznet/w5300.c
index 80fdbff67d82..f9da5d6172e3 100644
--- a/drivers/net/ethernet/wiznet/w5300.c
+++ b/drivers/net/ethernet/wiznet/w5300.c
@@ -661,8 +661,7 @@ static int w5300_remove(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP
static int w5300_suspend(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct net_device *ndev = platform_get_drvdata(pdev);
+ struct net_device *ndev = dev_get_drvdata(dev);
struct w5300_priv *priv = netdev_priv(ndev);
if (netif_running(ndev)) {
@@ -676,8 +675,7 @@ static int w5300_suspend(struct device *dev)
static int w5300_resume(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct net_device *ndev = platform_get_drvdata(pdev);
+ struct net_device *ndev = dev_get_drvdata(dev);
struct w5300_priv *priv = netdev_priv(ndev);
if (!netif_running(ndev)) {
diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index 60abc9250f56..2241f9897092 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -674,7 +674,8 @@ static inline int temac_check_tx_bd_space(struct temac_local *lp, int num_frag)
return 0;
}
-static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+static netdev_tx_t
+temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{
struct temac_local *lp = netdev_priv(ndev);
struct cdmac_bd *cur_p;
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index f24f48f33802..12a14609ec47 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -653,7 +653,8 @@ static inline int axienet_check_tx_bd_space(struct axienet_local *lp,
* start the transmission. Additionally if checksum offloading is supported,
* it populates AXI Stream Control fields with appropriate values.
*/
-static int axienet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+static netdev_tx_t
+axienet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{
u32 ii;
u32 num_frag;
diff --git a/drivers/net/ethernet/xilinx/xilinx_emaclite.c b/drivers/net/ethernet/xilinx/xilinx_emaclite.c
index 42f1f518dad6..639e3e99af46 100644
--- a/drivers/net/ethernet/xilinx/xilinx_emaclite.c
+++ b/drivers/net/ethernet/xilinx/xilinx_emaclite.c
@@ -941,8 +941,7 @@ static int xemaclite_open(struct net_device *dev)
}
/* EmacLite doesn't support giga-bit speeds */
- lp->phy_dev->supported &= (PHY_BASIC_FEATURES);
- lp->phy_dev->advertising = lp->phy_dev->supported;
+ phy_set_max_speed(lp->phy_dev, SPEED_100);
/* Don't advertise 1000BASE-T Full/Half duplex speeds */
phy_write(lp->phy_dev, MII_CTRL1000, 0);
@@ -1020,9 +1019,10 @@ static int xemaclite_close(struct net_device *dev)
* deferred and the Tx queue is stopped so that the deferred socket buffer can
* be transmitted when the Emaclite device is free to transmit data.
*
- * Return: 0, always.
+ * Return: NETDEV_TX_OK, always.
*/
-static int xemaclite_send(struct sk_buff *orig_skb, struct net_device *dev)
+static netdev_tx_t
+xemaclite_send(struct sk_buff *orig_skb, struct net_device *dev)
{
struct net_local *lp = netdev_priv(dev);
struct sk_buff *new_skb;
@@ -1044,7 +1044,7 @@ static int xemaclite_send(struct sk_buff *orig_skb, struct net_device *dev)
/* Take the time stamp now, since we can't do this in an ISR. */
skb_tx_timestamp(new_skb);
spin_unlock_irqrestore(&lp->reset_lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
spin_unlock_irqrestore(&lp->reset_lock, flags);
@@ -1053,7 +1053,7 @@ static int xemaclite_send(struct sk_buff *orig_skb, struct net_device *dev)
dev->stats.tx_bytes += len;
dev_consume_skb_any(new_skb);
- return 0;
+ return NETDEV_TX_OK;
}
/**
diff --git a/drivers/net/fddi/Kconfig b/drivers/net/fddi/Kconfig
index 3a424c864f4d..d62e8c6205f7 100644
--- a/drivers/net/fddi/Kconfig
+++ b/drivers/net/fddi/Kconfig
@@ -15,6 +15,17 @@ config FDDI
if FDDI
+config DEFZA
+ tristate "DEC FDDIcontroller 700/700-C (DEFZA-xx) support"
+ depends on FDDI && TC
+ help
+ This is support for the DEC FDDIcontroller 700 (DEFZA-AA, fiber)
+ and 700-C (DEFZA-CA, copper) TURBOchannel network cards which
+ can connect you to a local FDDI network.
+
+ To compile this driver as a module, choose M here: the module
+ will be called defza. If unsure, say N.
+
config DEFXX
tristate "Digital DEFTA/DEFEA/DEFPA adapter support"
depends on FDDI && (PCI || EISA || TC)
diff --git a/drivers/net/fddi/Makefile b/drivers/net/fddi/Makefile
index 36da19c9a8aa..194b52cc20b0 100644
--- a/drivers/net/fddi/Makefile
+++ b/drivers/net/fddi/Makefile
@@ -3,4 +3,5 @@
#
obj-$(CONFIG_DEFXX) += defxx.o
+obj-$(CONFIG_DEFZA) += defza.o
obj-$(CONFIG_SKFP) += skfp/
diff --git a/drivers/net/fddi/defza.c b/drivers/net/fddi/defza.c
new file mode 100644
index 000000000000..c5cae8e74dc4
--- /dev/null
+++ b/drivers/net/fddi/defza.c
@@ -0,0 +1,1565 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* FDDI network adapter driver for DEC FDDIcontroller 700/700-C devices.
+ *
+ * Copyright (c) 2018 Maciej W. Rozycki
+ *
+ * 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.
+ *
+ * References:
+ *
+ * Dave Sawyer & Phil Weeks & Frank Itkowsky,
+ * "DEC FDDIcontroller 700 Port Specification",
+ * Revision 1.1, Digital Equipment Corporation
+ */
+
+/* ------------------------------------------------------------------------- */
+/* FZA configurable parameters. */
+
+/* The number of transmit ring descriptors; either 0 for 512 or 1 for 1024. */
+#define FZA_RING_TX_MODE 0
+
+/* The number of receive ring descriptors; from 2 up to 256. */
+#define FZA_RING_RX_SIZE 256
+
+/* End of FZA configurable parameters. No need to change anything below. */
+/* ------------------------------------------------------------------------- */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/fddidevice.h>
+#include <linux/sched.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/stat.h>
+#include <linux/tc.h>
+#include <linux/timer.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+
+#include <asm/barrier.h>
+
+#include "defza.h"
+
+#define DRV_NAME "defza"
+#define DRV_VERSION "v.1.1.4"
+#define DRV_RELDATE "Oct 6 2018"
+
+static const char version[] =
+ DRV_NAME ": " DRV_VERSION " " DRV_RELDATE " Maciej W. Rozycki\n";
+
+MODULE_AUTHOR("Maciej W. Rozycki <macro@linux-mips.org>");
+MODULE_DESCRIPTION("DEC FDDIcontroller 700 (DEFZA-xx) driver");
+MODULE_LICENSE("GPL");
+
+static int loopback;
+module_param(loopback, int, 0644);
+
+/* Ring Purger Multicast */
+static u8 hw_addr_purger[8] = { 0x09, 0x00, 0x2b, 0x02, 0x01, 0x05 };
+/* Directed Beacon Multicast */
+static u8 hw_addr_beacon[8] = { 0x01, 0x80, 0xc2, 0x00, 0x01, 0x00 };
+
+/* Shorthands for MMIO accesses that we require to be strongly ordered
+ * WRT preceding MMIO accesses.
+ */
+#define readw_o readw_relaxed
+#define readl_o readl_relaxed
+
+#define writew_o writew_relaxed
+#define writel_o writel_relaxed
+
+/* Shorthands for MMIO accesses that we are happy with being weakly ordered
+ * WRT preceding MMIO accesses.
+ */
+#define readw_u readw_relaxed
+#define readl_u readl_relaxed
+#define readq_u readq_relaxed
+
+#define writew_u writew_relaxed
+#define writel_u writel_relaxed
+#define writeq_u writeq_relaxed
+
+static inline struct sk_buff *fza_alloc_skb_irq(struct net_device *dev,
+ unsigned int length)
+{
+ return __netdev_alloc_skb(dev, length, GFP_ATOMIC);
+}
+
+static inline struct sk_buff *fza_alloc_skb(struct net_device *dev,
+ unsigned int length)
+{
+ return __netdev_alloc_skb(dev, length, GFP_KERNEL);
+}
+
+static inline void fza_skb_align(struct sk_buff *skb, unsigned int v)
+{
+ unsigned long x, y;
+
+ x = (unsigned long)skb->data;
+ y = ALIGN(x, v);
+
+ skb_reserve(skb, y - x);
+}
+
+static inline void fza_reads(const void __iomem *from, void *to,
+ unsigned long size)
+{
+ if (sizeof(unsigned long) == 8) {
+ const u64 __iomem *src = from;
+ const u32 __iomem *src_trail;
+ u64 *dst = to;
+ u32 *dst_trail;
+
+ for (size = (size + 3) / 4; size > 1; size -= 2)
+ *dst++ = readq_u(src++);
+ if (size) {
+ src_trail = (u32 __iomem *)src;
+ dst_trail = (u32 *)dst;
+ *dst_trail = readl_u(src_trail);
+ }
+ } else {
+ const u32 __iomem *src = from;
+ u32 *dst = to;
+
+ for (size = (size + 3) / 4; size; size--)
+ *dst++ = readl_u(src++);
+ }
+}
+
+static inline void fza_writes(const void *from, void __iomem *to,
+ unsigned long size)
+{
+ if (sizeof(unsigned long) == 8) {
+ const u64 *src = from;
+ const u32 *src_trail;
+ u64 __iomem *dst = to;
+ u32 __iomem *dst_trail;
+
+ for (size = (size + 3) / 4; size > 1; size -= 2)
+ writeq_u(*src++, dst++);
+ if (size) {
+ src_trail = (u32 *)src;
+ dst_trail = (u32 __iomem *)dst;
+ writel_u(*src_trail, dst_trail);
+ }
+ } else {
+ const u32 *src = from;
+ u32 __iomem *dst = to;
+
+ for (size = (size + 3) / 4; size; size--)
+ writel_u(*src++, dst++);
+ }
+}
+
+static inline void fza_moves(const void __iomem *from, void __iomem *to,
+ unsigned long size)
+{
+ if (sizeof(unsigned long) == 8) {
+ const u64 __iomem *src = from;
+ const u32 __iomem *src_trail;
+ u64 __iomem *dst = to;
+ u32 __iomem *dst_trail;
+
+ for (size = (size + 3) / 4; size > 1; size -= 2)
+ writeq_u(readq_u(src++), dst++);
+ if (size) {
+ src_trail = (u32 __iomem *)src;
+ dst_trail = (u32 __iomem *)dst;
+ writel_u(readl_u(src_trail), dst_trail);
+ }
+ } else {
+ const u32 __iomem *src = from;
+ u32 __iomem *dst = to;
+
+ for (size = (size + 3) / 4; size; size--)
+ writel_u(readl_u(src++), dst++);
+ }
+}
+
+static inline void fza_zeros(void __iomem *to, unsigned long size)
+{
+ if (sizeof(unsigned long) == 8) {
+ u64 __iomem *dst = to;
+ u32 __iomem *dst_trail;
+
+ for (size = (size + 3) / 4; size > 1; size -= 2)
+ writeq_u(0, dst++);
+ if (size) {
+ dst_trail = (u32 __iomem *)dst;
+ writel_u(0, dst_trail);
+ }
+ } else {
+ u32 __iomem *dst = to;
+
+ for (size = (size + 3) / 4; size; size--)
+ writel_u(0, dst++);
+ }
+}
+
+static inline void fza_regs_dump(struct fza_private *fp)
+{
+ pr_debug("%s: iomem registers:\n", fp->name);
+ pr_debug(" reset: 0x%04x\n", readw_o(&fp->regs->reset));
+ pr_debug(" interrupt event: 0x%04x\n", readw_u(&fp->regs->int_event));
+ pr_debug(" status: 0x%04x\n", readw_u(&fp->regs->status));
+ pr_debug(" interrupt mask: 0x%04x\n", readw_u(&fp->regs->int_mask));
+ pr_debug(" control A: 0x%04x\n", readw_u(&fp->regs->control_a));
+ pr_debug(" control B: 0x%04x\n", readw_u(&fp->regs->control_b));
+}
+
+static inline void fza_do_reset(struct fza_private *fp)
+{
+ /* Reset the board. */
+ writew_o(FZA_RESET_INIT, &fp->regs->reset);
+ readw_o(&fp->regs->reset); /* Synchronize. */
+ readw_o(&fp->regs->reset); /* Read it back for a small delay. */
+ writew_o(FZA_RESET_CLR, &fp->regs->reset);
+
+ /* Enable all interrupt events we handle. */
+ writew_o(fp->int_mask, &fp->regs->int_mask);
+ readw_o(&fp->regs->int_mask); /* Synchronize. */
+}
+
+static inline void fza_do_shutdown(struct fza_private *fp)
+{
+ /* Disable the driver mode. */
+ writew_o(FZA_CONTROL_B_IDLE, &fp->regs->control_b);
+
+ /* And reset the board. */
+ writew_o(FZA_RESET_INIT, &fp->regs->reset);
+ readw_o(&fp->regs->reset); /* Synchronize. */
+ writew_o(FZA_RESET_CLR, &fp->regs->reset);
+ readw_o(&fp->regs->reset); /* Synchronize. */
+}
+
+static int fza_reset(struct fza_private *fp)
+{
+ unsigned long flags;
+ uint status, state;
+ long t;
+
+ pr_info("%s: resetting the board...\n", fp->name);
+
+ spin_lock_irqsave(&fp->lock, flags);
+ fp->state_chg_flag = 0;
+ fza_do_reset(fp);
+ spin_unlock_irqrestore(&fp->lock, flags);
+
+ /* DEC says RESET needs up to 30 seconds to complete. My DEFZA-AA
+ * rev. C03 happily finishes in 9.7 seconds. :-) But we need to
+ * be on the safe side...
+ */
+ t = wait_event_timeout(fp->state_chg_wait, fp->state_chg_flag,
+ 45 * HZ);
+ status = readw_u(&fp->regs->status);
+ state = FZA_STATUS_GET_STATE(status);
+ if (fp->state_chg_flag == 0) {
+ pr_err("%s: RESET timed out!, state %x\n", fp->name, state);
+ return -EIO;
+ }
+ if (state != FZA_STATE_UNINITIALIZED) {
+ pr_err("%s: RESET failed!, state %x, failure ID %x\n",
+ fp->name, state, FZA_STATUS_GET_TEST(status));
+ return -EIO;
+ }
+ pr_info("%s: OK\n", fp->name);
+ pr_debug("%s: RESET: %lums elapsed\n", fp->name,
+ (45 * HZ - t) * 1000 / HZ);
+
+ return 0;
+}
+
+static struct fza_ring_cmd __iomem *fza_cmd_send(struct net_device *dev,
+ int command)
+{
+ struct fza_private *fp = netdev_priv(dev);
+ struct fza_ring_cmd __iomem *ring = fp->ring_cmd + fp->ring_cmd_index;
+ unsigned int old_mask, new_mask;
+ union fza_cmd_buf __iomem *buf;
+ struct netdev_hw_addr *ha;
+ int i;
+
+ old_mask = fp->int_mask;
+ new_mask = old_mask & ~FZA_MASK_STATE_CHG;
+ writew_u(new_mask, &fp->regs->int_mask);
+ readw_o(&fp->regs->int_mask); /* Synchronize. */
+ fp->int_mask = new_mask;
+
+ buf = fp->mmio + readl_u(&ring->buffer);
+
+ if ((readl_u(&ring->cmd_own) & FZA_RING_OWN_MASK) !=
+ FZA_RING_OWN_HOST) {
+ pr_warn("%s: command buffer full, command: %u!\n", fp->name,
+ command);
+ return NULL;
+ }
+
+ switch (command) {
+ case FZA_RING_CMD_INIT:
+ writel_u(FZA_RING_TX_MODE, &buf->init.tx_mode);
+ writel_u(FZA_RING_RX_SIZE, &buf->init.hst_rx_size);
+ fza_zeros(&buf->init.counters, sizeof(buf->init.counters));
+ break;
+
+ case FZA_RING_CMD_MODCAM:
+ i = 0;
+ fza_writes(&hw_addr_purger, &buf->cam.hw_addr[i++],
+ sizeof(*buf->cam.hw_addr));
+ fza_writes(&hw_addr_beacon, &buf->cam.hw_addr[i++],
+ sizeof(*buf->cam.hw_addr));
+ netdev_for_each_mc_addr(ha, dev) {
+ if (i >= FZA_CMD_CAM_SIZE)
+ break;
+ fza_writes(ha->addr, &buf->cam.hw_addr[i++],
+ sizeof(*buf->cam.hw_addr));
+ }
+ while (i < FZA_CMD_CAM_SIZE)
+ fza_zeros(&buf->cam.hw_addr[i++],
+ sizeof(*buf->cam.hw_addr));
+ break;
+
+ case FZA_RING_CMD_PARAM:
+ writel_u(loopback, &buf->param.loop_mode);
+ writel_u(fp->t_max, &buf->param.t_max);
+ writel_u(fp->t_req, &buf->param.t_req);
+ writel_u(fp->tvx, &buf->param.tvx);
+ writel_u(fp->lem_threshold, &buf->param.lem_threshold);
+ fza_writes(&fp->station_id, &buf->param.station_id,
+ sizeof(buf->param.station_id));
+ /* Convert to milliseconds due to buggy firmware. */
+ writel_u(fp->rtoken_timeout / 12500,
+ &buf->param.rtoken_timeout);
+ writel_u(fp->ring_purger, &buf->param.ring_purger);
+ break;
+
+ case FZA_RING_CMD_MODPROM:
+ if (dev->flags & IFF_PROMISC) {
+ writel_u(1, &buf->modprom.llc_prom);
+ writel_u(1, &buf->modprom.smt_prom);
+ } else {
+ writel_u(0, &buf->modprom.llc_prom);
+ writel_u(0, &buf->modprom.smt_prom);
+ }
+ if (dev->flags & IFF_ALLMULTI ||
+ netdev_mc_count(dev) > FZA_CMD_CAM_SIZE - 2)
+ writel_u(1, &buf->modprom.llc_multi);
+ else
+ writel_u(0, &buf->modprom.llc_multi);
+ writel_u(1, &buf->modprom.llc_bcast);
+ break;
+ }
+
+ /* Trigger the command. */
+ writel_u(FZA_RING_OWN_FZA | command, &ring->cmd_own);
+ writew_o(FZA_CONTROL_A_CMD_POLL, &fp->regs->control_a);
+
+ fp->ring_cmd_index = (fp->ring_cmd_index + 1) % FZA_RING_CMD_SIZE;
+
+ fp->int_mask = old_mask;
+ writew_u(fp->int_mask, &fp->regs->int_mask);
+
+ return ring;
+}
+
+static int fza_init_send(struct net_device *dev,
+ struct fza_cmd_init *__iomem *init)
+{
+ struct fza_private *fp = netdev_priv(dev);
+ struct fza_ring_cmd __iomem *ring;
+ unsigned long flags;
+ u32 stat;
+ long t;
+
+ spin_lock_irqsave(&fp->lock, flags);
+ fp->cmd_done_flag = 0;
+ ring = fza_cmd_send(dev, FZA_RING_CMD_INIT);
+ spin_unlock_irqrestore(&fp->lock, flags);
+ if (!ring)
+ /* This should never happen in the uninitialized state,
+ * so do not try to recover and just consider it fatal.
+ */
+ return -ENOBUFS;
+
+ /* INIT may take quite a long time (160ms for my C03). */
+ t = wait_event_timeout(fp->cmd_done_wait, fp->cmd_done_flag, 3 * HZ);
+ if (fp->cmd_done_flag == 0) {
+ pr_err("%s: INIT command timed out!, state %x\n", fp->name,
+ FZA_STATUS_GET_STATE(readw_u(&fp->regs->status)));
+ return -EIO;
+ }
+ stat = readl_u(&ring->stat);
+ if (stat != FZA_RING_STAT_SUCCESS) {
+ pr_err("%s: INIT command failed!, status %02x, state %x\n",
+ fp->name, stat,
+ FZA_STATUS_GET_STATE(readw_u(&fp->regs->status)));
+ return -EIO;
+ }
+ pr_debug("%s: INIT: %lums elapsed\n", fp->name,
+ (3 * HZ - t) * 1000 / HZ);
+
+ if (init)
+ *init = fp->mmio + readl_u(&ring->buffer);
+ return 0;
+}
+
+static void fza_rx_init(struct fza_private *fp)
+{
+ int i;
+
+ /* Fill the host receive descriptor ring. */
+ for (i = 0; i < FZA_RING_RX_SIZE; i++) {
+ writel_o(0, &fp->ring_hst_rx[i].rmc);
+ writel_o((fp->rx_dma[i] + 0x1000) >> 9,
+ &fp->ring_hst_rx[i].buffer1);
+ writel_o(fp->rx_dma[i] >> 9 | FZA_RING_OWN_FZA,
+ &fp->ring_hst_rx[i].buf0_own);
+ }
+}
+
+static void fza_set_rx_mode(struct net_device *dev)
+{
+ fza_cmd_send(dev, FZA_RING_CMD_MODCAM);
+ fza_cmd_send(dev, FZA_RING_CMD_MODPROM);
+}
+
+union fza_buffer_txp {
+ struct fza_buffer_tx *data_ptr;
+ struct fza_buffer_tx __iomem *mmio_ptr;
+};
+
+static int fza_do_xmit(union fza_buffer_txp ub, int len,
+ struct net_device *dev, int smt)
+{
+ struct fza_private *fp = netdev_priv(dev);
+ struct fza_buffer_tx __iomem *rmc_tx_ptr;
+ int i, first, frag_len, left_len;
+ u32 own, rmc;
+
+ if (((((fp->ring_rmc_txd_index - 1 + fp->ring_rmc_tx_size) -
+ fp->ring_rmc_tx_index) % fp->ring_rmc_tx_size) *
+ FZA_TX_BUFFER_SIZE) < len)
+ return 1;
+
+ first = fp->ring_rmc_tx_index;
+
+ left_len = len;
+ frag_len = FZA_TX_BUFFER_SIZE;
+ /* First descriptor is relinquished last. */
+ own = FZA_RING_TX_OWN_HOST;
+ /* First descriptor carries frame length; we don't use cut-through. */
+ rmc = FZA_RING_TX_SOP | FZA_RING_TX_VBC | len;
+ do {
+ i = fp->ring_rmc_tx_index;
+ rmc_tx_ptr = &fp->buffer_tx[i];
+
+ if (left_len < FZA_TX_BUFFER_SIZE)
+ frag_len = left_len;
+ left_len -= frag_len;
+
+ /* Length must be a multiple of 4 as only word writes are
+ * permitted!
+ */
+ frag_len = (frag_len + 3) & ~3;
+ if (smt)
+ fza_moves(ub.mmio_ptr, rmc_tx_ptr, frag_len);
+ else
+ fza_writes(ub.data_ptr, rmc_tx_ptr, frag_len);
+
+ if (left_len == 0)
+ rmc |= FZA_RING_TX_EOP; /* Mark last frag. */
+
+ writel_o(rmc, &fp->ring_rmc_tx[i].rmc);
+ writel_o(own, &fp->ring_rmc_tx[i].own);
+
+ ub.data_ptr++;
+ fp->ring_rmc_tx_index = (fp->ring_rmc_tx_index + 1) %
+ fp->ring_rmc_tx_size;
+
+ /* Settings for intermediate frags. */
+ own = FZA_RING_TX_OWN_RMC;
+ rmc = 0;
+ } while (left_len > 0);
+
+ if (((((fp->ring_rmc_txd_index - 1 + fp->ring_rmc_tx_size) -
+ fp->ring_rmc_tx_index) % fp->ring_rmc_tx_size) *
+ FZA_TX_BUFFER_SIZE) < dev->mtu + dev->hard_header_len) {
+ netif_stop_queue(dev);
+ pr_debug("%s: queue stopped\n", fp->name);
+ }
+
+ writel_o(FZA_RING_TX_OWN_RMC, &fp->ring_rmc_tx[first].own);
+
+ /* Go, go, go! */
+ writew_o(FZA_CONTROL_A_TX_POLL, &fp->regs->control_a);
+
+ return 0;
+}
+
+static int fza_do_recv_smt(struct fza_buffer_tx *data_ptr, int len,
+ u32 rmc, struct net_device *dev)
+{
+ struct fza_private *fp = netdev_priv(dev);
+ struct fza_buffer_tx __iomem *smt_rx_ptr;
+ u32 own;
+ int i;
+
+ i = fp->ring_smt_rx_index;
+ own = readl_o(&fp->ring_smt_rx[i].own);
+ if ((own & FZA_RING_OWN_MASK) == FZA_RING_OWN_FZA)
+ return 1;
+
+ smt_rx_ptr = fp->mmio + readl_u(&fp->ring_smt_rx[i].buffer);
+
+ /* Length must be a multiple of 4 as only word writes are permitted! */
+ fza_writes(data_ptr, smt_rx_ptr, (len + 3) & ~3);
+
+ writel_o(rmc, &fp->ring_smt_rx[i].rmc);
+ writel_o(FZA_RING_OWN_FZA, &fp->ring_smt_rx[i].own);
+
+ fp->ring_smt_rx_index =
+ (fp->ring_smt_rx_index + 1) % fp->ring_smt_rx_size;
+
+ /* Grab it! */
+ writew_o(FZA_CONTROL_A_SMT_RX_POLL, &fp->regs->control_a);
+
+ return 0;
+}
+
+static void fza_tx(struct net_device *dev)
+{
+ struct fza_private *fp = netdev_priv(dev);
+ u32 own, rmc;
+ int i;
+
+ while (1) {
+ i = fp->ring_rmc_txd_index;
+ if (i == fp->ring_rmc_tx_index)
+ break;
+ own = readl_o(&fp->ring_rmc_tx[i].own);
+ if ((own & FZA_RING_OWN_MASK) == FZA_RING_TX_OWN_RMC)
+ break;
+
+ rmc = readl_u(&fp->ring_rmc_tx[i].rmc);
+ /* Only process the first descriptor. */
+ if ((rmc & FZA_RING_TX_SOP) != 0) {
+ if ((rmc & FZA_RING_TX_DCC_MASK) ==
+ FZA_RING_TX_DCC_SUCCESS) {
+ int pkt_len = (rmc & FZA_RING_PBC_MASK) - 3;
+ /* Omit PRH. */
+
+ fp->stats.tx_packets++;
+ fp->stats.tx_bytes += pkt_len;
+ } else {
+ fp->stats.tx_errors++;
+ switch (rmc & FZA_RING_TX_DCC_MASK) {
+ case FZA_RING_TX_DCC_DTP_SOP:
+ case FZA_RING_TX_DCC_DTP:
+ case FZA_RING_TX_DCC_ABORT:
+ fp->stats.tx_aborted_errors++;
+ break;
+ case FZA_RING_TX_DCC_UNDRRUN:
+ fp->stats.tx_fifo_errors++;
+ break;
+ case FZA_RING_TX_DCC_PARITY:
+ default:
+ break;
+ }
+ }
+ }
+
+ fp->ring_rmc_txd_index = (fp->ring_rmc_txd_index + 1) %
+ fp->ring_rmc_tx_size;
+ }
+
+ if (((((fp->ring_rmc_txd_index - 1 + fp->ring_rmc_tx_size) -
+ fp->ring_rmc_tx_index) % fp->ring_rmc_tx_size) *
+ FZA_TX_BUFFER_SIZE) >= dev->mtu + dev->hard_header_len) {
+ if (fp->queue_active) {
+ netif_wake_queue(dev);
+ pr_debug("%s: queue woken\n", fp->name);
+ }
+ }
+}
+
+static inline int fza_rx_err(struct fza_private *fp,
+ const u32 rmc, const u8 fc)
+{
+ int len, min_len, max_len;
+
+ len = rmc & FZA_RING_PBC_MASK;
+
+ if (unlikely((rmc & FZA_RING_RX_BAD) != 0)) {
+ fp->stats.rx_errors++;
+
+ /* Check special status codes. */
+ if ((rmc & (FZA_RING_RX_CRC | FZA_RING_RX_RRR_MASK |
+ FZA_RING_RX_DA_MASK | FZA_RING_RX_SA_MASK)) ==
+ (FZA_RING_RX_CRC | FZA_RING_RX_RRR_DADDR |
+ FZA_RING_RX_DA_CAM | FZA_RING_RX_SA_ALIAS)) {
+ if (len >= 8190)
+ fp->stats.rx_length_errors++;
+ return 1;
+ }
+ if ((rmc & (FZA_RING_RX_CRC | FZA_RING_RX_RRR_MASK |
+ FZA_RING_RX_DA_MASK | FZA_RING_RX_SA_MASK)) ==
+ (FZA_RING_RX_CRC | FZA_RING_RX_RRR_DADDR |
+ FZA_RING_RX_DA_CAM | FZA_RING_RX_SA_CAM)) {
+ /* Halt the interface to trigger a reset. */
+ writew_o(FZA_CONTROL_A_HALT, &fp->regs->control_a);
+ readw_o(&fp->regs->control_a); /* Synchronize. */
+ return 1;
+ }
+
+ /* Check the MAC status. */
+ switch (rmc & FZA_RING_RX_RRR_MASK) {
+ case FZA_RING_RX_RRR_OK:
+ if ((rmc & FZA_RING_RX_CRC) != 0)
+ fp->stats.rx_crc_errors++;
+ else if ((rmc & FZA_RING_RX_FSC_MASK) == 0 ||
+ (rmc & FZA_RING_RX_FSB_ERR) != 0)
+ fp->stats.rx_frame_errors++;
+ return 1;
+ case FZA_RING_RX_RRR_SADDR:
+ case FZA_RING_RX_RRR_DADDR:
+ case FZA_RING_RX_RRR_ABORT:
+ /* Halt the interface to trigger a reset. */
+ writew_o(FZA_CONTROL_A_HALT, &fp->regs->control_a);
+ readw_o(&fp->regs->control_a); /* Synchronize. */
+ return 1;
+ case FZA_RING_RX_RRR_LENGTH:
+ fp->stats.rx_frame_errors++;
+ return 1;
+ default:
+ return 1;
+ }
+ }
+
+ /* Packet received successfully; validate the length. */
+ switch (fc & FDDI_FC_K_FORMAT_MASK) {
+ case FDDI_FC_K_FORMAT_MANAGEMENT:
+ if ((fc & FDDI_FC_K_CLASS_MASK) == FDDI_FC_K_CLASS_ASYNC)
+ min_len = 37;
+ else
+ min_len = 17;
+ break;
+ case FDDI_FC_K_FORMAT_LLC:
+ min_len = 20;
+ break;
+ default:
+ min_len = 17;
+ break;
+ }
+ max_len = 4495;
+ if (len < min_len || len > max_len) {
+ fp->stats.rx_errors++;
+ fp->stats.rx_length_errors++;
+ return 1;
+ }
+
+ return 0;
+}
+
+static void fza_rx(struct net_device *dev)
+{
+ struct fza_private *fp = netdev_priv(dev);
+ struct sk_buff *skb, *newskb;
+ struct fza_fddihdr *frame;
+ dma_addr_t dma, newdma;
+ u32 own, rmc, buf;
+ int i, len;
+ u8 fc;
+
+ while (1) {
+ i = fp->ring_hst_rx_index;
+ own = readl_o(&fp->ring_hst_rx[i].buf0_own);
+ if ((own & FZA_RING_OWN_MASK) == FZA_RING_OWN_FZA)
+ break;
+
+ rmc = readl_u(&fp->ring_hst_rx[i].rmc);
+ skb = fp->rx_skbuff[i];
+ dma = fp->rx_dma[i];
+
+ /* The RMC doesn't count the preamble and the starting
+ * delimiter. We fix it up here for a total of 3 octets.
+ */
+ dma_rmb();
+ len = (rmc & FZA_RING_PBC_MASK) + 3;
+ frame = (struct fza_fddihdr *)skb->data;
+
+ /* We need to get at real FC. */
+ dma_sync_single_for_cpu(fp->bdev,
+ dma +
+ ((u8 *)&frame->hdr.fc - (u8 *)frame),
+ sizeof(frame->hdr.fc),
+ DMA_FROM_DEVICE);
+ fc = frame->hdr.fc;
+
+ if (fza_rx_err(fp, rmc, fc))
+ goto err_rx;
+
+ /* We have to 512-byte-align RX buffers... */
+ newskb = fza_alloc_skb_irq(dev, FZA_RX_BUFFER_SIZE + 511);
+ if (newskb) {
+ fza_skb_align(newskb, 512);
+ newdma = dma_map_single(fp->bdev, newskb->data,
+ FZA_RX_BUFFER_SIZE,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(fp->bdev, newdma)) {
+ dev_kfree_skb_irq(newskb);
+ newskb = NULL;
+ }
+ }
+ if (newskb) {
+ int pkt_len = len - 7; /* Omit P, SD and FCS. */
+ int is_multi;
+ int rx_stat;
+
+ dma_unmap_single(fp->bdev, dma, FZA_RX_BUFFER_SIZE,
+ DMA_FROM_DEVICE);
+
+ /* Queue SMT frames to the SMT receive ring. */
+ if ((fc & (FDDI_FC_K_CLASS_MASK |
+ FDDI_FC_K_FORMAT_MASK)) ==
+ (FDDI_FC_K_CLASS_ASYNC |
+ FDDI_FC_K_FORMAT_MANAGEMENT) &&
+ (rmc & FZA_RING_RX_DA_MASK) !=
+ FZA_RING_RX_DA_PROM) {
+ if (fza_do_recv_smt((struct fza_buffer_tx *)
+ skb->data, len, rmc,
+ dev)) {
+ writel_o(FZA_CONTROL_A_SMT_RX_OVFL,
+ &fp->regs->control_a);
+ }
+ }
+
+ is_multi = ((frame->hdr.daddr[0] & 0x01) != 0);
+
+ skb_reserve(skb, 3); /* Skip over P and SD. */
+ skb_put(skb, pkt_len); /* And cut off FCS. */
+ skb->protocol = fddi_type_trans(skb, dev);
+
+ rx_stat = netif_rx(skb);
+ if (rx_stat != NET_RX_DROP) {
+ fp->stats.rx_packets++;
+ fp->stats.rx_bytes += pkt_len;
+ if (is_multi)
+ fp->stats.multicast++;
+ } else {
+ fp->stats.rx_dropped++;
+ }
+
+ skb = newskb;
+ dma = newdma;
+ fp->rx_skbuff[i] = skb;
+ fp->rx_dma[i] = dma;
+ } else {
+ fp->stats.rx_dropped++;
+ pr_notice("%s: memory squeeze, dropping packet\n",
+ fp->name);
+ }
+
+err_rx:
+ writel_o(0, &fp->ring_hst_rx[i].rmc);
+ buf = (dma + 0x1000) >> 9;
+ writel_o(buf, &fp->ring_hst_rx[i].buffer1);
+ buf = dma >> 9 | FZA_RING_OWN_FZA;
+ writel_o(buf, &fp->ring_hst_rx[i].buf0_own);
+ fp->ring_hst_rx_index =
+ (fp->ring_hst_rx_index + 1) % fp->ring_hst_rx_size;
+ }
+}
+
+static void fza_tx_smt(struct net_device *dev)
+{
+ struct fza_private *fp = netdev_priv(dev);
+ struct fza_buffer_tx __iomem *smt_tx_ptr;
+ int i, len;
+ u32 own;
+
+ while (1) {
+ i = fp->ring_smt_tx_index;
+ own = readl_o(&fp->ring_smt_tx[i].own);
+ if ((own & FZA_RING_OWN_MASK) == FZA_RING_OWN_FZA)
+ break;
+
+ smt_tx_ptr = fp->mmio + readl_u(&fp->ring_smt_tx[i].buffer);
+ len = readl_u(&fp->ring_smt_tx[i].rmc) & FZA_RING_PBC_MASK;
+
+ if (!netif_queue_stopped(dev)) {
+ if (dev_nit_active(dev)) {
+ struct fza_buffer_tx *skb_data_ptr;
+ struct sk_buff *skb;
+
+ /* Length must be a multiple of 4 as only word
+ * reads are permitted!
+ */
+ skb = fza_alloc_skb_irq(dev, (len + 3) & ~3);
+ if (!skb)
+ goto err_no_skb; /* Drop. */
+
+ skb_data_ptr = (struct fza_buffer_tx *)
+ skb->data;
+
+ fza_reads(smt_tx_ptr, skb_data_ptr,
+ (len + 3) & ~3);
+ skb->dev = dev;
+ skb_reserve(skb, 3); /* Skip over PRH. */
+ skb_put(skb, len - 3);
+ skb_reset_network_header(skb);
+
+ dev_queue_xmit_nit(skb, dev);
+
+ dev_kfree_skb_irq(skb);
+
+err_no_skb:
+ ;
+ }
+
+ /* Queue the frame to the RMC transmit ring. */
+ fza_do_xmit((union fza_buffer_txp)
+ { .mmio_ptr = smt_tx_ptr },
+ len, dev, 1);
+ }
+
+ writel_o(FZA_RING_OWN_FZA, &fp->ring_smt_tx[i].own);
+ fp->ring_smt_tx_index =
+ (fp->ring_smt_tx_index + 1) % fp->ring_smt_tx_size;
+ }
+}
+
+static void fza_uns(struct net_device *dev)
+{
+ struct fza_private *fp = netdev_priv(dev);
+ u32 own;
+ int i;
+
+ while (1) {
+ i = fp->ring_uns_index;
+ own = readl_o(&fp->ring_uns[i].own);
+ if ((own & FZA_RING_OWN_MASK) == FZA_RING_OWN_FZA)
+ break;
+
+ if (readl_u(&fp->ring_uns[i].id) == FZA_RING_UNS_RX_OVER) {
+ fp->stats.rx_errors++;
+ fp->stats.rx_over_errors++;
+ }
+
+ writel_o(FZA_RING_OWN_FZA, &fp->ring_uns[i].own);
+ fp->ring_uns_index =
+ (fp->ring_uns_index + 1) % FZA_RING_UNS_SIZE;
+ }
+}
+
+static void fza_tx_flush(struct net_device *dev)
+{
+ struct fza_private *fp = netdev_priv(dev);
+ u32 own;
+ int i;
+
+ /* Clean up the SMT TX ring. */
+ i = fp->ring_smt_tx_index;
+ do {
+ writel_o(FZA_RING_OWN_FZA, &fp->ring_smt_tx[i].own);
+ fp->ring_smt_tx_index =
+ (fp->ring_smt_tx_index + 1) % fp->ring_smt_tx_size;
+
+ } while (i != fp->ring_smt_tx_index);
+
+ /* Clean up the RMC TX ring. */
+ i = fp->ring_rmc_tx_index;
+ do {
+ own = readl_o(&fp->ring_rmc_tx[i].own);
+ if ((own & FZA_RING_OWN_MASK) == FZA_RING_TX_OWN_RMC) {
+ u32 rmc = readl_u(&fp->ring_rmc_tx[i].rmc);
+
+ writel_u(rmc | FZA_RING_TX_DTP,
+ &fp->ring_rmc_tx[i].rmc);
+ }
+ fp->ring_rmc_tx_index =
+ (fp->ring_rmc_tx_index + 1) % fp->ring_rmc_tx_size;
+
+ } while (i != fp->ring_rmc_tx_index);
+
+ /* Done. */
+ writew_o(FZA_CONTROL_A_FLUSH_DONE, &fp->regs->control_a);
+}
+
+static irqreturn_t fza_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct fza_private *fp = netdev_priv(dev);
+ uint int_event;
+
+ /* Get interrupt events. */
+ int_event = readw_o(&fp->regs->int_event) & fp->int_mask;
+ if (int_event == 0)
+ return IRQ_NONE;
+
+ /* Clear the events. */
+ writew_u(int_event, &fp->regs->int_event);
+
+ /* Now handle the events. The order matters. */
+
+ /* Command finished interrupt. */
+ if ((int_event & FZA_EVENT_CMD_DONE) != 0) {
+ fp->irq_count_cmd_done++;
+
+ spin_lock(&fp->lock);
+ fp->cmd_done_flag = 1;
+ wake_up(&fp->cmd_done_wait);
+ spin_unlock(&fp->lock);
+ }
+
+ /* Transmit finished interrupt. */
+ if ((int_event & FZA_EVENT_TX_DONE) != 0) {
+ fp->irq_count_tx_done++;
+ fza_tx(dev);
+ }
+
+ /* Host receive interrupt. */
+ if ((int_event & FZA_EVENT_RX_POLL) != 0) {
+ fp->irq_count_rx_poll++;
+ fza_rx(dev);
+ }
+
+ /* SMT transmit interrupt. */
+ if ((int_event & FZA_EVENT_SMT_TX_POLL) != 0) {
+ fp->irq_count_smt_tx_poll++;
+ fza_tx_smt(dev);
+ }
+
+ /* Transmit ring flush request. */
+ if ((int_event & FZA_EVENT_FLUSH_TX) != 0) {
+ fp->irq_count_flush_tx++;
+ fza_tx_flush(dev);
+ }
+
+ /* Link status change interrupt. */
+ if ((int_event & FZA_EVENT_LINK_ST_CHG) != 0) {
+ uint status;
+
+ fp->irq_count_link_st_chg++;
+ status = readw_u(&fp->regs->status);
+ if (FZA_STATUS_GET_LINK(status) == FZA_LINK_ON) {
+ netif_carrier_on(dev);
+ pr_info("%s: link available\n", fp->name);
+ } else {
+ netif_carrier_off(dev);
+ pr_info("%s: link unavailable\n", fp->name);
+ }
+ }
+
+ /* Unsolicited event interrupt. */
+ if ((int_event & FZA_EVENT_UNS_POLL) != 0) {
+ fp->irq_count_uns_poll++;
+ fza_uns(dev);
+ }
+
+ /* State change interrupt. */
+ if ((int_event & FZA_EVENT_STATE_CHG) != 0) {
+ uint status, state;
+
+ fp->irq_count_state_chg++;
+
+ status = readw_u(&fp->regs->status);
+ state = FZA_STATUS_GET_STATE(status);
+ pr_debug("%s: state change: %x\n", fp->name, state);
+ switch (state) {
+ case FZA_STATE_RESET:
+ break;
+
+ case FZA_STATE_UNINITIALIZED:
+ netif_carrier_off(dev);
+ del_timer_sync(&fp->reset_timer);
+ fp->ring_cmd_index = 0;
+ fp->ring_uns_index = 0;
+ fp->ring_rmc_tx_index = 0;
+ fp->ring_rmc_txd_index = 0;
+ fp->ring_hst_rx_index = 0;
+ fp->ring_smt_tx_index = 0;
+ fp->ring_smt_rx_index = 0;
+ if (fp->state > state) {
+ pr_info("%s: OK\n", fp->name);
+ fza_cmd_send(dev, FZA_RING_CMD_INIT);
+ }
+ break;
+
+ case FZA_STATE_INITIALIZED:
+ if (fp->state > state) {
+ fza_set_rx_mode(dev);
+ fza_cmd_send(dev, FZA_RING_CMD_PARAM);
+ }
+ break;
+
+ case FZA_STATE_RUNNING:
+ case FZA_STATE_MAINTENANCE:
+ fp->state = state;
+ fza_rx_init(fp);
+ fp->queue_active = 1;
+ netif_wake_queue(dev);
+ pr_debug("%s: queue woken\n", fp->name);
+ break;
+
+ case FZA_STATE_HALTED:
+ fp->queue_active = 0;
+ netif_stop_queue(dev);
+ pr_debug("%s: queue stopped\n", fp->name);
+ del_timer_sync(&fp->reset_timer);
+ pr_warn("%s: halted, reason: %x\n", fp->name,
+ FZA_STATUS_GET_HALT(status));
+ fza_regs_dump(fp);
+ pr_info("%s: resetting the board...\n", fp->name);
+ fza_do_reset(fp);
+ fp->timer_state = 0;
+ fp->reset_timer.expires = jiffies + 45 * HZ;
+ add_timer(&fp->reset_timer);
+ break;
+
+ default:
+ pr_warn("%s: undefined state: %x\n", fp->name, state);
+ break;
+ }
+
+ spin_lock(&fp->lock);
+ fp->state_chg_flag = 1;
+ wake_up(&fp->state_chg_wait);
+ spin_unlock(&fp->lock);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void fza_reset_timer(struct timer_list *t)
+{
+ struct fza_private *fp = from_timer(fp, t, reset_timer);
+
+ if (!fp->timer_state) {
+ pr_err("%s: RESET timed out!\n", fp->name);
+ pr_info("%s: trying harder...\n", fp->name);
+
+ /* Assert the board reset. */
+ writew_o(FZA_RESET_INIT, &fp->regs->reset);
+ readw_o(&fp->regs->reset); /* Synchronize. */
+
+ fp->timer_state = 1;
+ fp->reset_timer.expires = jiffies + HZ;
+ } else {
+ /* Clear the board reset. */
+ writew_u(FZA_RESET_CLR, &fp->regs->reset);
+
+ /* Enable all interrupt events we handle. */
+ writew_o(fp->int_mask, &fp->regs->int_mask);
+ readw_o(&fp->regs->int_mask); /* Synchronize. */
+
+ fp->timer_state = 0;
+ fp->reset_timer.expires = jiffies + 45 * HZ;
+ }
+ add_timer(&fp->reset_timer);
+}
+
+static int fza_set_mac_address(struct net_device *dev, void *addr)
+{
+ return -EOPNOTSUPP;
+}
+
+static netdev_tx_t fza_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct fza_private *fp = netdev_priv(dev);
+ unsigned int old_mask, new_mask;
+ int ret;
+ u8 fc;
+
+ skb_push(skb, 3); /* Make room for PRH. */
+
+ /* Decode FC to set PRH. */
+ fc = skb->data[3];
+ skb->data[0] = 0;
+ skb->data[1] = 0;
+ skb->data[2] = FZA_PRH2_NORMAL;
+ if ((fc & FDDI_FC_K_CLASS_MASK) == FDDI_FC_K_CLASS_SYNC)
+ skb->data[0] |= FZA_PRH0_FRAME_SYNC;
+ switch (fc & FDDI_FC_K_FORMAT_MASK) {
+ case FDDI_FC_K_FORMAT_MANAGEMENT:
+ if ((fc & FDDI_FC_K_CONTROL_MASK) == 0) {
+ /* Token. */
+ skb->data[0] |= FZA_PRH0_TKN_TYPE_IMM;
+ skb->data[1] |= FZA_PRH1_TKN_SEND_NONE;
+ } else {
+ /* SMT or MAC. */
+ skb->data[0] |= FZA_PRH0_TKN_TYPE_UNR;
+ skb->data[1] |= FZA_PRH1_TKN_SEND_UNR;
+ }
+ skb->data[1] |= FZA_PRH1_CRC_NORMAL;
+ break;
+ case FDDI_FC_K_FORMAT_LLC:
+ case FDDI_FC_K_FORMAT_FUTURE:
+ skb->data[0] |= FZA_PRH0_TKN_TYPE_UNR;
+ skb->data[1] |= FZA_PRH1_CRC_NORMAL | FZA_PRH1_TKN_SEND_UNR;
+ break;
+ case FDDI_FC_K_FORMAT_IMPLEMENTOR:
+ skb->data[0] |= FZA_PRH0_TKN_TYPE_UNR;
+ skb->data[1] |= FZA_PRH1_TKN_SEND_ORIG;
+ break;
+ }
+
+ /* SMT transmit interrupts may sneak frames into the RMC
+ * transmit ring. We disable them while queueing a frame
+ * to maintain consistency.
+ */
+ old_mask = fp->int_mask;
+ new_mask = old_mask & ~FZA_MASK_SMT_TX_POLL;
+ writew_u(new_mask, &fp->regs->int_mask);
+ readw_o(&fp->regs->int_mask); /* Synchronize. */
+ fp->int_mask = new_mask;
+ ret = fza_do_xmit((union fza_buffer_txp)
+ { .data_ptr = (struct fza_buffer_tx *)skb->data },
+ skb->len, dev, 0);
+ fp->int_mask = old_mask;
+ writew_u(fp->int_mask, &fp->regs->int_mask);
+
+ if (ret) {
+ /* Probably an SMT packet filled the remaining space,
+ * so just stop the queue, but don't report it as an error.
+ */
+ netif_stop_queue(dev);
+ pr_debug("%s: queue stopped\n", fp->name);
+ fp->stats.tx_dropped++;
+ }
+
+ dev_kfree_skb(skb);
+
+ return ret;
+}
+
+static int fza_open(struct net_device *dev)
+{
+ struct fza_private *fp = netdev_priv(dev);
+ struct fza_ring_cmd __iomem *ring;
+ struct sk_buff *skb;
+ unsigned long flags;
+ dma_addr_t dma;
+ int ret, i;
+ u32 stat;
+ long t;
+
+ for (i = 0; i < FZA_RING_RX_SIZE; i++) {
+ /* We have to 512-byte-align RX buffers... */
+ skb = fza_alloc_skb(dev, FZA_RX_BUFFER_SIZE + 511);
+ if (skb) {
+ fza_skb_align(skb, 512);
+ dma = dma_map_single(fp->bdev, skb->data,
+ FZA_RX_BUFFER_SIZE,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(fp->bdev, dma)) {
+ dev_kfree_skb(skb);
+ skb = NULL;
+ }
+ }
+ if (!skb) {
+ for (--i; i >= 0; i--) {
+ dma_unmap_single(fp->bdev, fp->rx_dma[i],
+ FZA_RX_BUFFER_SIZE,
+ DMA_FROM_DEVICE);
+ dev_kfree_skb(fp->rx_skbuff[i]);
+ fp->rx_dma[i] = 0;
+ fp->rx_skbuff[i] = NULL;
+ }
+ return -ENOMEM;
+ }
+ fp->rx_skbuff[i] = skb;
+ fp->rx_dma[i] = dma;
+ }
+
+ ret = fza_init_send(dev, NULL);
+ if (ret != 0)
+ return ret;
+
+ /* Purger and Beacon multicasts need to be supplied before PARAM. */
+ fza_set_rx_mode(dev);
+
+ spin_lock_irqsave(&fp->lock, flags);
+ fp->cmd_done_flag = 0;
+ ring = fza_cmd_send(dev, FZA_RING_CMD_PARAM);
+ spin_unlock_irqrestore(&fp->lock, flags);
+ if (!ring)
+ return -ENOBUFS;
+
+ t = wait_event_timeout(fp->cmd_done_wait, fp->cmd_done_flag, 3 * HZ);
+ if (fp->cmd_done_flag == 0) {
+ pr_err("%s: PARAM command timed out!, state %x\n", fp->name,
+ FZA_STATUS_GET_STATE(readw_u(&fp->regs->status)));
+ return -EIO;
+ }
+ stat = readl_u(&ring->stat);
+ if (stat != FZA_RING_STAT_SUCCESS) {
+ pr_err("%s: PARAM command failed!, status %02x, state %x\n",
+ fp->name, stat,
+ FZA_STATUS_GET_STATE(readw_u(&fp->regs->status)));
+ return -EIO;
+ }
+ pr_debug("%s: PARAM: %lums elapsed\n", fp->name,
+ (3 * HZ - t) * 1000 / HZ);
+
+ return 0;
+}
+
+static int fza_close(struct net_device *dev)
+{
+ struct fza_private *fp = netdev_priv(dev);
+ unsigned long flags;
+ uint state;
+ long t;
+ int i;
+
+ netif_stop_queue(dev);
+ pr_debug("%s: queue stopped\n", fp->name);
+
+ del_timer_sync(&fp->reset_timer);
+ spin_lock_irqsave(&fp->lock, flags);
+ fp->state = FZA_STATE_UNINITIALIZED;
+ fp->state_chg_flag = 0;
+ /* Shut the interface down. */
+ writew_o(FZA_CONTROL_A_SHUT, &fp->regs->control_a);
+ readw_o(&fp->regs->control_a); /* Synchronize. */
+ spin_unlock_irqrestore(&fp->lock, flags);
+
+ /* DEC says SHUT needs up to 10 seconds to complete. */
+ t = wait_event_timeout(fp->state_chg_wait, fp->state_chg_flag,
+ 15 * HZ);
+ state = FZA_STATUS_GET_STATE(readw_o(&fp->regs->status));
+ if (fp->state_chg_flag == 0) {
+ pr_err("%s: SHUT timed out!, state %x\n", fp->name, state);
+ return -EIO;
+ }
+ if (state != FZA_STATE_UNINITIALIZED) {
+ pr_err("%s: SHUT failed!, state %x\n", fp->name, state);
+ return -EIO;
+ }
+ pr_debug("%s: SHUT: %lums elapsed\n", fp->name,
+ (15 * HZ - t) * 1000 / HZ);
+
+ for (i = 0; i < FZA_RING_RX_SIZE; i++)
+ if (fp->rx_skbuff[i]) {
+ dma_unmap_single(fp->bdev, fp->rx_dma[i],
+ FZA_RX_BUFFER_SIZE, DMA_FROM_DEVICE);
+ dev_kfree_skb(fp->rx_skbuff[i]);
+ fp->rx_dma[i] = 0;
+ fp->rx_skbuff[i] = NULL;
+ }
+
+ return 0;
+}
+
+static struct net_device_stats *fza_get_stats(struct net_device *dev)
+{
+ struct fza_private *fp = netdev_priv(dev);
+
+ return &fp->stats;
+}
+
+static int fza_probe(struct device *bdev)
+{
+ static const struct net_device_ops netdev_ops = {
+ .ndo_open = fza_open,
+ .ndo_stop = fza_close,
+ .ndo_start_xmit = fza_start_xmit,
+ .ndo_set_rx_mode = fza_set_rx_mode,
+ .ndo_set_mac_address = fza_set_mac_address,
+ .ndo_get_stats = fza_get_stats,
+ };
+ static int version_printed;
+ char rom_rev[4], fw_rev[4], rmc_rev[4];
+ struct tc_dev *tdev = to_tc_dev(bdev);
+ struct fza_cmd_init __iomem *init;
+ resource_size_t start, len;
+ struct net_device *dev;
+ struct fza_private *fp;
+ uint smt_ver, pmd_type;
+ void __iomem *mmio;
+ uint hw_addr[2];
+ int ret, i;
+
+ if (!version_printed) {
+ pr_info("%s", version);
+ version_printed = 1;
+ }
+
+ dev = alloc_fddidev(sizeof(*fp));
+ if (!dev)
+ return -ENOMEM;
+ SET_NETDEV_DEV(dev, bdev);
+
+ fp = netdev_priv(dev);
+ dev_set_drvdata(bdev, dev);
+
+ fp->bdev = bdev;
+ fp->name = dev_name(bdev);
+
+ /* Request the I/O MEM resource. */
+ start = tdev->resource.start;
+ len = tdev->resource.end - start + 1;
+ if (!request_mem_region(start, len, dev_name(bdev))) {
+ pr_err("%s: cannot reserve MMIO region\n", fp->name);
+ ret = -EBUSY;
+ goto err_out_kfree;
+ }
+
+ /* MMIO mapping setup. */
+ mmio = ioremap_nocache(start, len);
+ if (!mmio) {
+ pr_err("%s: cannot map MMIO\n", fp->name);
+ ret = -ENOMEM;
+ goto err_out_resource;
+ }
+
+ /* Initialize the new device structure. */
+ switch (loopback) {
+ case FZA_LOOP_NORMAL:
+ case FZA_LOOP_INTERN:
+ case FZA_LOOP_EXTERN:
+ break;
+ default:
+ loopback = FZA_LOOP_NORMAL;
+ }
+
+ fp->mmio = mmio;
+ dev->irq = tdev->interrupt;
+
+ pr_info("%s: DEC FDDIcontroller 700 or 700-C at 0x%08llx, irq %d\n",
+ fp->name, (long long)tdev->resource.start, dev->irq);
+ pr_debug("%s: mapped at: 0x%p\n", fp->name, mmio);
+
+ fp->regs = mmio + FZA_REG_BASE;
+ fp->ring_cmd = mmio + FZA_RING_CMD;
+ fp->ring_uns = mmio + FZA_RING_UNS;
+
+ init_waitqueue_head(&fp->state_chg_wait);
+ init_waitqueue_head(&fp->cmd_done_wait);
+ spin_lock_init(&fp->lock);
+ fp->int_mask = FZA_MASK_NORMAL;
+
+ timer_setup(&fp->reset_timer, fza_reset_timer, 0);
+
+ /* Sanitize the board. */
+ fza_regs_dump(fp);
+ fza_do_shutdown(fp);
+
+ ret = request_irq(dev->irq, fza_interrupt, IRQF_SHARED, fp->name, dev);
+ if (ret != 0) {
+ pr_err("%s: unable to get IRQ %d!\n", fp->name, dev->irq);
+ goto err_out_map;
+ }
+
+ /* Enable the driver mode. */
+ writew_o(FZA_CONTROL_B_DRIVER, &fp->regs->control_b);
+
+ /* For some reason transmit done interrupts can trigger during
+ * reset. This avoids a division error in the handler.
+ */
+ fp->ring_rmc_tx_size = FZA_RING_TX_SIZE;
+
+ ret = fza_reset(fp);
+ if (ret != 0)
+ goto err_out_irq;
+
+ ret = fza_init_send(dev, &init);
+ if (ret != 0)
+ goto err_out_irq;
+
+ fza_reads(&init->hw_addr, &hw_addr, sizeof(hw_addr));
+ memcpy(dev->dev_addr, &hw_addr, FDDI_K_ALEN);
+
+ fza_reads(&init->rom_rev, &rom_rev, sizeof(rom_rev));
+ fza_reads(&init->fw_rev, &fw_rev, sizeof(fw_rev));
+ fza_reads(&init->rmc_rev, &rmc_rev, sizeof(rmc_rev));
+ for (i = 3; i >= 0 && rom_rev[i] == ' '; i--)
+ rom_rev[i] = 0;
+ for (i = 3; i >= 0 && fw_rev[i] == ' '; i--)
+ fw_rev[i] = 0;
+ for (i = 3; i >= 0 && rmc_rev[i] == ' '; i--)
+ rmc_rev[i] = 0;
+
+ fp->ring_rmc_tx = mmio + readl_u(&init->rmc_tx);
+ fp->ring_rmc_tx_size = readl_u(&init->rmc_tx_size);
+ fp->ring_hst_rx = mmio + readl_u(&init->hst_rx);
+ fp->ring_hst_rx_size = readl_u(&init->hst_rx_size);
+ fp->ring_smt_tx = mmio + readl_u(&init->smt_tx);
+ fp->ring_smt_tx_size = readl_u(&init->smt_tx_size);
+ fp->ring_smt_rx = mmio + readl_u(&init->smt_rx);
+ fp->ring_smt_rx_size = readl_u(&init->smt_rx_size);
+
+ fp->buffer_tx = mmio + FZA_TX_BUFFER_ADDR(readl_u(&init->rmc_tx));
+
+ fp->t_max = readl_u(&init->def_t_max);
+ fp->t_req = readl_u(&init->def_t_req);
+ fp->tvx = readl_u(&init->def_tvx);
+ fp->lem_threshold = readl_u(&init->lem_threshold);
+ fza_reads(&init->def_station_id, &fp->station_id,
+ sizeof(fp->station_id));
+ fp->rtoken_timeout = readl_u(&init->rtoken_timeout);
+ fp->ring_purger = readl_u(&init->ring_purger);
+
+ smt_ver = readl_u(&init->smt_ver);
+ pmd_type = readl_u(&init->pmd_type);
+
+ pr_debug("%s: INIT parameters:\n", fp->name);
+ pr_debug(" tx_mode: %u\n", readl_u(&init->tx_mode));
+ pr_debug(" hst_rx_size: %u\n", readl_u(&init->hst_rx_size));
+ pr_debug(" rmc_rev: %.4s\n", rmc_rev);
+ pr_debug(" rom_rev: %.4s\n", rom_rev);
+ pr_debug(" fw_rev: %.4s\n", fw_rev);
+ pr_debug(" mop_type: %u\n", readl_u(&init->mop_type));
+ pr_debug(" hst_rx: 0x%08x\n", readl_u(&init->hst_rx));
+ pr_debug(" rmc_tx: 0x%08x\n", readl_u(&init->rmc_tx));
+ pr_debug(" rmc_tx_size: %u\n", readl_u(&init->rmc_tx_size));
+ pr_debug(" smt_tx: 0x%08x\n", readl_u(&init->smt_tx));
+ pr_debug(" smt_tx_size: %u\n", readl_u(&init->smt_tx_size));
+ pr_debug(" smt_rx: 0x%08x\n", readl_u(&init->smt_rx));
+ pr_debug(" smt_rx_size: %u\n", readl_u(&init->smt_rx_size));
+ /* TC systems are always LE, so don't bother swapping. */
+ pr_debug(" hw_addr: 0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ (readl_u(&init->hw_addr[0]) >> 0) & 0xff,
+ (readl_u(&init->hw_addr[0]) >> 8) & 0xff,
+ (readl_u(&init->hw_addr[0]) >> 16) & 0xff,
+ (readl_u(&init->hw_addr[0]) >> 24) & 0xff,
+ (readl_u(&init->hw_addr[1]) >> 0) & 0xff,
+ (readl_u(&init->hw_addr[1]) >> 8) & 0xff,
+ (readl_u(&init->hw_addr[1]) >> 16) & 0xff,
+ (readl_u(&init->hw_addr[1]) >> 24) & 0xff);
+ pr_debug(" def_t_req: %u\n", readl_u(&init->def_t_req));
+ pr_debug(" def_tvx: %u\n", readl_u(&init->def_tvx));
+ pr_debug(" def_t_max: %u\n", readl_u(&init->def_t_max));
+ pr_debug(" lem_threshold: %u\n", readl_u(&init->lem_threshold));
+ /* Don't bother swapping, see above. */
+ pr_debug(" def_station_id: 0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ (readl_u(&init->def_station_id[0]) >> 0) & 0xff,
+ (readl_u(&init->def_station_id[0]) >> 8) & 0xff,
+ (readl_u(&init->def_station_id[0]) >> 16) & 0xff,
+ (readl_u(&init->def_station_id[0]) >> 24) & 0xff,
+ (readl_u(&init->def_station_id[1]) >> 0) & 0xff,
+ (readl_u(&init->def_station_id[1]) >> 8) & 0xff,
+ (readl_u(&init->def_station_id[1]) >> 16) & 0xff,
+ (readl_u(&init->def_station_id[1]) >> 24) & 0xff);
+ pr_debug(" pmd_type_alt: %u\n", readl_u(&init->pmd_type_alt));
+ pr_debug(" smt_ver: %u\n", readl_u(&init->smt_ver));
+ pr_debug(" rtoken_timeout: %u\n", readl_u(&init->rtoken_timeout));
+ pr_debug(" ring_purger: %u\n", readl_u(&init->ring_purger));
+ pr_debug(" smt_ver_max: %u\n", readl_u(&init->smt_ver_max));
+ pr_debug(" smt_ver_min: %u\n", readl_u(&init->smt_ver_min));
+ pr_debug(" pmd_type: %u\n", readl_u(&init->pmd_type));
+
+ pr_info("%s: model %s, address %pMF\n",
+ fp->name,
+ pmd_type == FZA_PMD_TYPE_TW ?
+ "700-C (DEFZA-CA), ThinWire PMD selected" :
+ pmd_type == FZA_PMD_TYPE_STP ?
+ "700-C (DEFZA-CA), STP PMD selected" :
+ "700 (DEFZA-AA), MMF PMD",
+ dev->dev_addr);
+ pr_info("%s: ROM rev. %.4s, firmware rev. %.4s, RMC rev. %.4s, "
+ "SMT ver. %u\n", fp->name, rom_rev, fw_rev, rmc_rev, smt_ver);
+
+ /* Now that we fetched initial parameters just shut the interface
+ * until opened.
+ */
+ ret = fza_close(dev);
+ if (ret != 0)
+ goto err_out_irq;
+
+ /* The FZA-specific entries in the device structure. */
+ dev->netdev_ops = &netdev_ops;
+
+ ret = register_netdev(dev);
+ if (ret != 0)
+ goto err_out_irq;
+
+ pr_info("%s: registered as %s\n", fp->name, dev->name);
+ fp->name = (const char *)dev->name;
+
+ get_device(bdev);
+ return 0;
+
+err_out_irq:
+ del_timer_sync(&fp->reset_timer);
+ fza_do_shutdown(fp);
+ free_irq(dev->irq, dev);
+
+err_out_map:
+ iounmap(mmio);
+
+err_out_resource:
+ release_mem_region(start, len);
+
+err_out_kfree:
+ free_netdev(dev);
+
+ pr_err("%s: initialization failure, aborting!\n", fp->name);
+ return ret;
+}
+
+static int fza_remove(struct device *bdev)
+{
+ struct net_device *dev = dev_get_drvdata(bdev);
+ struct fza_private *fp = netdev_priv(dev);
+ struct tc_dev *tdev = to_tc_dev(bdev);
+ resource_size_t start, len;
+
+ put_device(bdev);
+
+ unregister_netdev(dev);
+
+ del_timer_sync(&fp->reset_timer);
+ fza_do_shutdown(fp);
+ free_irq(dev->irq, dev);
+
+ iounmap(fp->mmio);
+
+ start = tdev->resource.start;
+ len = tdev->resource.end - start + 1;
+ release_mem_region(start, len);
+
+ free_netdev(dev);
+
+ return 0;
+}
+
+static struct tc_device_id const fza_tc_table[] = {
+ { "DEC ", "PMAF-AA " },
+ { }
+};
+MODULE_DEVICE_TABLE(tc, fza_tc_table);
+
+static struct tc_driver fza_driver = {
+ .id_table = fza_tc_table,
+ .driver = {
+ .name = "defza",
+ .bus = &tc_bus_type,
+ .probe = fza_probe,
+ .remove = fza_remove,
+ },
+};
+
+static int fza_init(void)
+{
+ return tc_register_driver(&fza_driver);
+}
+
+static void fza_exit(void)
+{
+ tc_unregister_driver(&fza_driver);
+}
+
+module_init(fza_init);
+module_exit(fza_exit);
diff --git a/drivers/net/fddi/defza.h b/drivers/net/fddi/defza.h
new file mode 100644
index 000000000000..93bda61be8e3
--- /dev/null
+++ b/drivers/net/fddi/defza.h
@@ -0,0 +1,792 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* FDDI network adapter driver for DEC FDDIcontroller 700/700-C devices.
+ *
+ * Copyright (c) 2018 Maciej W. Rozycki
+ *
+ * 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.
+ *
+ * References:
+ *
+ * Dave Sawyer & Phil Weeks & Frank Itkowsky,
+ * "DEC FDDIcontroller 700 Port Specification",
+ * Revision 1.1, Digital Equipment Corporation
+ */
+
+#include <linux/compiler.h>
+#include <linux/if_fddi.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <linux/types.h>
+
+/* IOmem register offsets. */
+#define FZA_REG_BASE 0x100000 /* register base address */
+#define FZA_REG_RESET 0x100200 /* reset, r/w */
+#define FZA_REG_INT_EVENT 0x100400 /* interrupt event, r/w1c */
+#define FZA_REG_STATUS 0x100402 /* status, r/o */
+#define FZA_REG_INT_MASK 0x100404 /* interrupt mask, r/w */
+#define FZA_REG_CONTROL_A 0x100500 /* control A, r/w1s */
+#define FZA_REG_CONTROL_B 0x100502 /* control B, r/w */
+
+/* Reset register constants. Bits 1:0 are r/w, others are fixed at 0. */
+#define FZA_RESET_DLU 0x0002 /* OR with INIT to blast flash memory */
+#define FZA_RESET_INIT 0x0001 /* switch into the reset state */
+#define FZA_RESET_CLR 0x0000 /* run self-test and return to work */
+
+/* Interrupt event register constants. All bits are r/w1c. */
+#define FZA_EVENT_DLU_DONE 0x0800 /* flash memory write complete */
+#define FZA_EVENT_FLUSH_TX 0x0400 /* transmit ring flush request */
+#define FZA_EVENT_PM_PARITY_ERR 0x0200 /* onboard packet memory parity err */
+#define FZA_EVENT_HB_PARITY_ERR 0x0100 /* host bus parity error */
+#define FZA_EVENT_NXM_ERR 0x0080 /* non-existent memory access error;
+ * also raised for unaligned and
+ * unsupported partial-word accesses
+ */
+#define FZA_EVENT_LINK_ST_CHG 0x0040 /* link status change */
+#define FZA_EVENT_STATE_CHG 0x0020 /* adapter state change */
+#define FZA_EVENT_UNS_POLL 0x0010 /* unsolicited event service request */
+#define FZA_EVENT_CMD_DONE 0x0008 /* command done ack */
+#define FZA_EVENT_SMT_TX_POLL 0x0004 /* SMT frame transmit request */
+#define FZA_EVENT_RX_POLL 0x0002 /* receive request (packet avail.) */
+#define FZA_EVENT_TX_DONE 0x0001 /* RMC transmit done ack */
+
+/* Status register constants. All bits are r/o. */
+#define FZA_STATUS_DLU_SHIFT 0xc /* down line upgrade status bits */
+#define FZA_STATUS_DLU_MASK 0x03
+#define FZA_STATUS_LINK_SHIFT 0xb /* link status bits */
+#define FZA_STATUS_LINK_MASK 0x01
+#define FZA_STATUS_STATE_SHIFT 0x8 /* adapter state bits */
+#define FZA_STATUS_STATE_MASK 0x07
+#define FZA_STATUS_HALT_SHIFT 0x0 /* halt reason bits */
+#define FZA_STATUS_HALT_MASK 0xff
+#define FZA_STATUS_TEST_SHIFT 0x0 /* test failure bits */
+#define FZA_STATUS_TEST_MASK 0xff
+
+#define FZA_STATUS_GET_DLU(x) (((x) >> FZA_STATUS_DLU_SHIFT) & \
+ FZA_STATUS_DLU_MASK)
+#define FZA_STATUS_GET_LINK(x) (((x) >> FZA_STATUS_LINK_SHIFT) & \
+ FZA_STATUS_LINK_MASK)
+#define FZA_STATUS_GET_STATE(x) (((x) >> FZA_STATUS_STATE_SHIFT) & \
+ FZA_STATUS_STATE_MASK)
+#define FZA_STATUS_GET_HALT(x) (((x) >> FZA_STATUS_HALT_SHIFT) & \
+ FZA_STATUS_HALT_MASK)
+#define FZA_STATUS_GET_TEST(x) (((x) >> FZA_STATUS_TEST_SHIFT) & \
+ FZA_STATUS_TEST_MASK)
+
+#define FZA_DLU_FAILURE 0x0 /* DLU catastrophic error; brain dead */
+#define FZA_DLU_ERROR 0x1 /* DLU error; old firmware intact */
+#define FZA_DLU_SUCCESS 0x2 /* DLU OK; new firmware loaded */
+
+#define FZA_LINK_OFF 0x0 /* link unavailable */
+#define FZA_LINK_ON 0x1 /* link available */
+
+#define FZA_STATE_RESET 0x0 /* resetting */
+#define FZA_STATE_UNINITIALIZED 0x1 /* after a reset */
+#define FZA_STATE_INITIALIZED 0x2 /* initialized */
+#define FZA_STATE_RUNNING 0x3 /* running (link active) */
+#define FZA_STATE_MAINTENANCE 0x4 /* running (link looped back) */
+#define FZA_STATE_HALTED 0x5 /* halted (error condition) */
+
+#define FZA_HALT_UNKNOWN 0x00 /* unknown reason */
+#define FZA_HALT_HOST 0x01 /* host-directed HALT */
+#define FZA_HALT_HB_PARITY 0x02 /* host bus parity error */
+#define FZA_HALT_NXM 0x03 /* adapter non-existent memory ref. */
+#define FZA_HALT_SW 0x04 /* adapter software fault */
+#define FZA_HALT_HW 0x05 /* adapter hardware fault */
+#define FZA_HALT_PC_TRACE 0x06 /* PC Trace path test */
+#define FZA_HALT_DLSW 0x07 /* data link software fault */
+#define FZA_HALT_DLHW 0x08 /* data link hardware fault */
+
+#define FZA_TEST_FATAL 0x00 /* self-test catastrophic failure */
+#define FZA_TEST_68K 0x01 /* 68000 CPU */
+#define FZA_TEST_SRAM_BWADDR 0x02 /* SRAM byte/word address */
+#define FZA_TEST_SRAM_DBUS 0x03 /* SRAM data bus */
+#define FZA_TEST_SRAM_STUCK1 0x04 /* SRAM stuck-at range 1 */
+#define FZA_TEST_SRAM_STUCK2 0x05 /* SRAM stuck-at range 2 */
+#define FZA_TEST_SRAM_COUPL1 0x06 /* SRAM coupling range 1 */
+#define FZA_TEST_SRAM_COUPL2 0x07 /* SRAM coupling */
+#define FZA_TEST_FLASH_CRC 0x08 /* Flash CRC */
+#define FZA_TEST_ROM 0x09 /* option ROM */
+#define FZA_TEST_PHY_CSR 0x0a /* PHY CSR */
+#define FZA_TEST_MAC_BIST 0x0b /* MAC BiST */
+#define FZA_TEST_MAC_CSR 0x0c /* MAC CSR */
+#define FZA_TEST_MAC_ADDR_UNIQ 0x0d /* MAC unique address */
+#define FZA_TEST_ELM_BIST 0x0e /* ELM BiST */
+#define FZA_TEST_ELM_CSR 0x0f /* ELM CSR */
+#define FZA_TEST_ELM_ADDR_UNIQ 0x10 /* ELM unique address */
+#define FZA_TEST_CAM 0x11 /* CAM */
+#define FZA_TEST_NIROM 0x12 /* NI ROM checksum */
+#define FZA_TEST_SC_LOOP 0x13 /* SC loopback packet */
+#define FZA_TEST_LM_LOOP 0x14 /* LM loopback packet */
+#define FZA_TEST_EB_LOOP 0x15 /* EB loopback packet */
+#define FZA_TEST_SC_LOOP_BYPS 0x16 /* SC bypass loopback packet */
+#define FZA_TEST_LM_LOOP_LOCAL 0x17 /* LM local loopback packet */
+#define FZA_TEST_EB_LOOP_LOCAL 0x18 /* EB local loopback packet */
+#define FZA_TEST_CDC_LOOP 0x19 /* CDC loopback packet */
+#define FZA_TEST_FIBER_LOOP 0x1A /* FIBER loopback packet */
+#define FZA_TEST_CAM_MATCH_LOOP 0x1B /* CAM match packet loopback */
+#define FZA_TEST_68K_IRQ_STUCK 0x1C /* 68000 interrupt line stuck-at */
+#define FZA_TEST_IRQ_PRESENT 0x1D /* interrupt present register */
+#define FZA_TEST_RMC_BIST 0x1E /* RMC BiST */
+#define FZA_TEST_RMC_CSR 0x1F /* RMC CSR */
+#define FZA_TEST_RMC_ADDR_UNIQ 0x20 /* RMC unique address */
+#define FZA_TEST_PM_DPATH 0x21 /* packet memory data path */
+#define FZA_TEST_PM_ADDR 0x22 /* packet memory address */
+#define FZA_TEST_RES_23 0x23 /* reserved */
+#define FZA_TEST_PM_DESC 0x24 /* packet memory descriptor */
+#define FZA_TEST_PM_OWN 0x25 /* packet memory own bit */
+#define FZA_TEST_PM_PARITY 0x26 /* packet memory parity */
+#define FZA_TEST_PM_BSWAP 0x27 /* packet memory byte swap */
+#define FZA_TEST_PM_WSWAP 0x28 /* packet memory word swap */
+#define FZA_TEST_PM_REF 0x29 /* packet memory refresh */
+#define FZA_TEST_PM_CSR 0x2A /* PM CSR */
+#define FZA_TEST_PORT_STATUS 0x2B /* port status register */
+#define FZA_TEST_HOST_IRQMASK 0x2C /* host interrupt mask */
+#define FZA_TEST_TIMER_IRQ1 0x2D /* RTOS timer */
+#define FZA_TEST_FORCE_IRQ1 0x2E /* force RTOS IRQ1 */
+#define FZA_TEST_TIMER_IRQ5 0x2F /* IRQ5 backoff timer */
+#define FZA_TEST_FORCE_IRQ5 0x30 /* force IRQ5 */
+#define FZA_TEST_RES_31 0x31 /* reserved */
+#define FZA_TEST_IC_PRIO 0x32 /* interrupt controller priority */
+#define FZA_TEST_PM_FULL 0x33 /* full packet memory */
+#define FZA_TEST_PMI_DMA 0x34 /* PMI DMA */
+
+/* Interrupt mask register constants. All bits are r/w. */
+#define FZA_MASK_RESERVED 0xf000 /* unused */
+#define FZA_MASK_DLU_DONE 0x0800 /* flash memory write complete */
+#define FZA_MASK_FLUSH_TX 0x0400 /* transmit ring flush request */
+#define FZA_MASK_PM_PARITY_ERR 0x0200 /* onboard packet memory parity error
+ */
+#define FZA_MASK_HB_PARITY_ERR 0x0100 /* host bus parity error */
+#define FZA_MASK_NXM_ERR 0x0080 /* adapter non-existent memory
+ * reference
+ */
+#define FZA_MASK_LINK_ST_CHG 0x0040 /* link status change */
+#define FZA_MASK_STATE_CHG 0x0020 /* adapter state change */
+#define FZA_MASK_UNS_POLL 0x0010 /* unsolicited event service request */
+#define FZA_MASK_CMD_DONE 0x0008 /* command ring entry processed */
+#define FZA_MASK_SMT_TX_POLL 0x0004 /* SMT frame transmit request */
+#define FZA_MASK_RCV_POLL 0x0002 /* receive request (packet available)
+ */
+#define FZA_MASK_TX_DONE 0x0001 /* RMC transmit done acknowledge */
+
+/* Which interrupts to receive: 0/1 is mask/unmask. */
+#define FZA_MASK_NONE 0x0000
+#define FZA_MASK_NORMAL \
+ ((~(FZA_MASK_RESERVED | FZA_MASK_DLU_DONE | \
+ FZA_MASK_PM_PARITY_ERR | FZA_MASK_HB_PARITY_ERR | \
+ FZA_MASK_NXM_ERR)) & 0xffff)
+
+/* Control A register constants. */
+#define FZA_CONTROL_A_HB_PARITY_ERR 0x8000 /* host bus parity error */
+#define FZA_CONTROL_A_NXM_ERR 0x4000 /* adapter non-existent memory
+ * reference
+ */
+#define FZA_CONTROL_A_SMT_RX_OVFL 0x0040 /* SMT receive overflow */
+#define FZA_CONTROL_A_FLUSH_DONE 0x0020 /* flush tx request complete */
+#define FZA_CONTROL_A_SHUT 0x0010 /* turn the interface off */
+#define FZA_CONTROL_A_HALT 0x0008 /* halt the controller */
+#define FZA_CONTROL_A_CMD_POLL 0x0004 /* command ring poll */
+#define FZA_CONTROL_A_SMT_RX_POLL 0x0002 /* SMT receive ring poll */
+#define FZA_CONTROL_A_TX_POLL 0x0001 /* transmit poll */
+
+/* Control B register constants. All bits are r/w.
+ *
+ * Possible values:
+ * 0x0000 after booting into REX,
+ * 0x0003 after issuing `boot #/mop'.
+ */
+#define FZA_CONTROL_B_CONSOLE 0x0002 /* OR with DRIVER for console
+ * (TC firmware) mode
+ */
+#define FZA_CONTROL_B_DRIVER 0x0001 /* driver mode */
+#define FZA_CONTROL_B_IDLE 0x0000 /* no driver installed */
+
+#define FZA_RESET_PAD \
+ (FZA_REG_RESET - FZA_REG_BASE)
+#define FZA_INT_EVENT_PAD \
+ (FZA_REG_INT_EVENT - FZA_REG_RESET - sizeof(u16))
+#define FZA_CONTROL_A_PAD \
+ (FZA_REG_CONTROL_A - FZA_REG_INT_MASK - sizeof(u16))
+
+/* Layout of registers. */
+struct fza_regs {
+ u8 pad0[FZA_RESET_PAD];
+ u16 reset; /* reset register */
+ u8 pad1[FZA_INT_EVENT_PAD];
+ u16 int_event; /* interrupt event register */
+ u16 status; /* status register */
+ u16 int_mask; /* interrupt mask register */
+ u8 pad2[FZA_CONTROL_A_PAD];
+ u16 control_a; /* control A register */
+ u16 control_b; /* control B register */
+};
+
+/* Command descriptor ring entry. */
+struct fza_ring_cmd {
+ u32 cmd_own; /* bit 31: ownership, bits [30:0]: command */
+ u32 stat; /* command status */
+ u32 buffer; /* address of the buffer in the FZA space */
+ u32 pad0;
+};
+
+#define FZA_RING_CMD 0x200400 /* command ring address */
+#define FZA_RING_CMD_SIZE 0x40 /* command descriptor ring
+ * size
+ */
+/* Command constants. */
+#define FZA_RING_CMD_MASK 0x7fffffff
+#define FZA_RING_CMD_NOP 0x00000000 /* nop */
+#define FZA_RING_CMD_INIT 0x00000001 /* initialize */
+#define FZA_RING_CMD_MODCAM 0x00000002 /* modify CAM */
+#define FZA_RING_CMD_PARAM 0x00000003 /* set system parameters */
+#define FZA_RING_CMD_MODPROM 0x00000004 /* modify promiscuous mode */
+#define FZA_RING_CMD_SETCHAR 0x00000005 /* set link characteristics */
+#define FZA_RING_CMD_RDCNTR 0x00000006 /* read counters */
+#define FZA_RING_CMD_STATUS 0x00000007 /* get link status */
+#define FZA_RING_CMD_RDCAM 0x00000008 /* read CAM */
+
+/* Command status constants. */
+#define FZA_RING_STAT_SUCCESS 0x00000000
+
+/* Unsolicited event descriptor ring entry. */
+struct fza_ring_uns {
+ u32 own; /* bit 31: ownership, bits [30:0]: reserved */
+ u32 id; /* event ID */
+ u32 buffer; /* address of the buffer in the FZA space */
+ u32 pad0; /* reserved */
+};
+
+#define FZA_RING_UNS 0x200800 /* unsolicited ring address */
+#define FZA_RING_UNS_SIZE 0x40 /* unsolicited descriptor ring
+ * size
+ */
+/* Unsolicited event constants. */
+#define FZA_RING_UNS_UND 0x00000000 /* undefined event ID */
+#define FZA_RING_UNS_INIT_IN 0x00000001 /* ring init initiated */
+#define FZA_RING_UNS_INIT_RX 0x00000002 /* ring init received */
+#define FZA_RING_UNS_BEAC_IN 0x00000003 /* ring beaconing initiated */
+#define FZA_RING_UNS_DUP_ADDR 0x00000004 /* duplicate address detected */
+#define FZA_RING_UNS_DUP_TOK 0x00000005 /* duplicate token detected */
+#define FZA_RING_UNS_PURG_ERR 0x00000006 /* ring purger error */
+#define FZA_RING_UNS_STRIP_ERR 0x00000007 /* bridge strip error */
+#define FZA_RING_UNS_OP_OSC 0x00000008 /* ring op oscillation */
+#define FZA_RING_UNS_BEAC_RX 0x00000009 /* directed beacon received */
+#define FZA_RING_UNS_PCT_IN 0x0000000a /* PC trace initiated */
+#define FZA_RING_UNS_PCT_RX 0x0000000b /* PC trace received */
+#define FZA_RING_UNS_TX_UNDER 0x0000000c /* transmit underrun */
+#define FZA_RING_UNS_TX_FAIL 0x0000000d /* transmit failure */
+#define FZA_RING_UNS_RX_OVER 0x0000000e /* receive overrun */
+
+/* RMC (Ring Memory Control) transmit descriptor ring entry. */
+struct fza_ring_rmc_tx {
+ u32 rmc; /* RMC information */
+ u32 avl; /* available for host (unused by RMC) */
+ u32 own; /* bit 31: ownership, bits [30:0]: reserved */
+ u32 pad0; /* reserved */
+};
+
+#define FZA_TX_BUFFER_ADDR(x) (0x200000 | (((x) & 0xffff) << 5))
+#define FZA_TX_BUFFER_SIZE 512
+struct fza_buffer_tx {
+ u32 data[FZA_TX_BUFFER_SIZE / sizeof(u32)];
+};
+
+/* Transmit ring RMC constants. */
+#define FZA_RING_TX_SOP 0x80000000 /* start of packet */
+#define FZA_RING_TX_EOP 0x40000000 /* end of packet */
+#define FZA_RING_TX_DTP 0x20000000 /* discard this packet */
+#define FZA_RING_TX_VBC 0x10000000 /* valid buffer byte count */
+#define FZA_RING_TX_DCC_MASK 0x0f000000 /* DMA completion code */
+#define FZA_RING_TX_DCC_SUCCESS 0x01000000 /* transmit succeeded */
+#define FZA_RING_TX_DCC_DTP_SOP 0x02000000 /* DTP set at SOP */
+#define FZA_RING_TX_DCC_DTP 0x04000000 /* DTP set within packet */
+#define FZA_RING_TX_DCC_ABORT 0x05000000 /* MAC-requested abort */
+#define FZA_RING_TX_DCC_PARITY 0x06000000 /* xmit data parity error */
+#define FZA_RING_TX_DCC_UNDRRUN 0x07000000 /* transmit underrun */
+#define FZA_RING_TX_XPO_MASK 0x003fe000 /* transmit packet offset */
+
+/* Host receive descriptor ring entry. */
+struct fza_ring_hst_rx {
+ u32 buf0_own; /* bit 31: ownership, bits [30:23]: unused,
+ * bits [22:0]: right-shifted address of the
+ * buffer in system memory (low buffer)
+ */
+ u32 buffer1; /* bits [31:23]: unused,
+ * bits [22:0]: right-shifted address of the
+ * buffer in system memory (high buffer)
+ */
+ u32 rmc; /* RMC information */
+ u32 pad0;
+};
+
+#define FZA_RX_BUFFER_SIZE (4096 + 512) /* buffer length */
+
+/* Receive ring RMC constants. */
+#define FZA_RING_RX_SOP 0x80000000 /* start of packet */
+#define FZA_RING_RX_EOP 0x40000000 /* end of packet */
+#define FZA_RING_RX_FSC_MASK 0x38000000 /* # of frame status bits */
+#define FZA_RING_RX_FSB_MASK 0x07c00000 /* frame status bits */
+#define FZA_RING_RX_FSB_ERR 0x04000000 /* error detected */
+#define FZA_RING_RX_FSB_ADDR 0x02000000 /* address recognized */
+#define FZA_RING_RX_FSB_COP 0x01000000 /* frame copied */
+#define FZA_RING_RX_FSB_F0 0x00800000 /* first additional flag */
+#define FZA_RING_RX_FSB_F1 0x00400000 /* second additional flag */
+#define FZA_RING_RX_BAD 0x00200000 /* bad packet */
+#define FZA_RING_RX_CRC 0x00100000 /* CRC error */
+#define FZA_RING_RX_RRR_MASK 0x000e0000 /* MAC receive status bits */
+#define FZA_RING_RX_RRR_OK 0x00000000 /* receive OK */
+#define FZA_RING_RX_RRR_SADDR 0x00020000 /* source address matched */
+#define FZA_RING_RX_RRR_DADDR 0x00040000 /* dest address not matched */
+#define FZA_RING_RX_RRR_ABORT 0x00060000 /* RMC abort */
+#define FZA_RING_RX_RRR_LENGTH 0x00080000 /* invalid length */
+#define FZA_RING_RX_RRR_FRAG 0x000a0000 /* fragment */
+#define FZA_RING_RX_RRR_FORMAT 0x000c0000 /* format error */
+#define FZA_RING_RX_RRR_RESET 0x000e0000 /* MAC reset */
+#define FZA_RING_RX_DA_MASK 0x00018000 /* daddr match status bits */
+#define FZA_RING_RX_DA_NONE 0x00000000 /* no match */
+#define FZA_RING_RX_DA_PROM 0x00008000 /* promiscuous match */
+#define FZA_RING_RX_DA_CAM 0x00010000 /* CAM entry match */
+#define FZA_RING_RX_DA_LOCAL 0x00018000 /* link addr or LLC bcast */
+#define FZA_RING_RX_SA_MASK 0x00006000 /* saddr match status bits */
+#define FZA_RING_RX_SA_NONE 0x00000000 /* no match */
+#define FZA_RING_RX_SA_ALIAS 0x00002000 /* alias address match */
+#define FZA_RING_RX_SA_CAM 0x00004000 /* CAM entry match */
+#define FZA_RING_RX_SA_LOCAL 0x00006000 /* link address match */
+
+/* SMT (Station Management) transmit/receive descriptor ring entry. */
+struct fza_ring_smt {
+ u32 own; /* bit 31: ownership, bits [30:0]: unused */
+ u32 rmc; /* RMC information */
+ u32 buffer; /* address of the buffer */
+ u32 pad0; /* reserved */
+};
+
+/* Ownership constants.
+ *
+ * Only an owner is permitted to process a given ring entry.
+ * RMC transmit ring meanings are reversed.
+ */
+#define FZA_RING_OWN_MASK 0x80000000
+#define FZA_RING_OWN_FZA 0x00000000 /* permit FZA, forbid host */
+#define FZA_RING_OWN_HOST 0x80000000 /* permit host, forbid FZA */
+#define FZA_RING_TX_OWN_RMC 0x80000000 /* permit RMC, forbid host */
+#define FZA_RING_TX_OWN_HOST 0x00000000 /* permit host, forbid RMC */
+
+/* RMC constants. */
+#define FZA_RING_PBC_MASK 0x00001fff /* frame length */
+
+/* Layout of counter buffers. */
+
+struct fza_counter {
+ u32 msw;
+ u32 lsw;
+};
+
+struct fza_counters {
+ struct fza_counter sys_buf; /* system buffer unavailable */
+ struct fza_counter tx_under; /* transmit underruns */
+ struct fza_counter tx_fail; /* transmit failures */
+ struct fza_counter rx_over; /* receive data overruns */
+ struct fza_counter frame_cnt; /* frame count */
+ struct fza_counter error_cnt; /* error count */
+ struct fza_counter lost_cnt; /* lost count */
+ struct fza_counter rinit_in; /* ring initialization initiated */
+ struct fza_counter rinit_rx; /* ring initialization received */
+ struct fza_counter beac_in; /* ring beacon initiated */
+ struct fza_counter dup_addr; /* duplicate address test failures */
+ struct fza_counter dup_tok; /* duplicate token detected */
+ struct fza_counter purg_err; /* ring purge errors */
+ struct fza_counter strip_err; /* bridge strip errors */
+ struct fza_counter pct_in; /* traces initiated */
+ struct fza_counter pct_rx; /* traces received */
+ struct fza_counter lem_rej; /* LEM rejects */
+ struct fza_counter tne_rej; /* TNE expiry rejects */
+ struct fza_counter lem_event; /* LEM events */
+ struct fza_counter lct_rej; /* LCT rejects */
+ struct fza_counter conn_cmpl; /* connections completed */
+ struct fza_counter el_buf; /* elasticity buffer errors */
+};
+
+/* Layout of command buffers. */
+
+/* INIT command buffer.
+ *
+ * Values of default link parameters given are as obtained from a
+ * DEFZA-AA rev. C03 board. The board counts time in units of 80ns.
+ */
+struct fza_cmd_init {
+ u32 tx_mode; /* transmit mode */
+ u32 hst_rx_size; /* host receive ring entries */
+
+ struct fza_counters counters; /* counters */
+
+ u8 rmc_rev[4]; /* RMC revision */
+ u8 rom_rev[4]; /* ROM revision */
+ u8 fw_rev[4]; /* firmware revision */
+
+ u32 mop_type; /* MOP device type */
+
+ u32 hst_rx; /* base of host rx descriptor ring */
+ u32 rmc_tx; /* base of RMC tx descriptor ring */
+ u32 rmc_tx_size; /* size of RMC tx descriptor ring */
+ u32 smt_tx; /* base of SMT tx descriptor ring */
+ u32 smt_tx_size; /* size of SMT tx descriptor ring */
+ u32 smt_rx; /* base of SMT rx descriptor ring */
+ u32 smt_rx_size; /* size of SMT rx descriptor ring */
+
+ u32 hw_addr[2]; /* link address */
+
+ u32 def_t_req; /* default Requested TTRT (T_REQ) --
+ * C03: 100000 [80ns]
+ */
+ u32 def_tvx; /* default Valid Transmission Time
+ * (TVX) -- C03: 32768 [80ns]
+ */
+ u32 def_t_max; /* default Maximum TTRT (T_MAX) --
+ * C03: 2162688 [80ns]
+ */
+ u32 lem_threshold; /* default LEM threshold -- C03: 8 */
+ u32 def_station_id[2]; /* default station ID */
+
+ u32 pmd_type_alt; /* alternative PMD type code */
+
+ u32 smt_ver; /* SMT version */
+
+ u32 rtoken_timeout; /* default restricted token timeout
+ * -- C03: 12500000 [80ns]
+ */
+ u32 ring_purger; /* default ring purger enable --
+ * C03: 1
+ */
+
+ u32 smt_ver_max; /* max SMT version ID */
+ u32 smt_ver_min; /* min SMT version ID */
+ u32 pmd_type; /* PMD type code */
+};
+
+/* INIT command PMD type codes. */
+#define FZA_PMD_TYPE_MMF 0 /* Multimode fiber */
+#define FZA_PMD_TYPE_TW 101 /* ThinWire */
+#define FZA_PMD_TYPE_STP 102 /* STP */
+
+/* MODCAM/RDCAM command buffer. */
+#define FZA_CMD_CAM_SIZE 64 /* CAM address entry count */
+struct fza_cmd_cam {
+ u32 hw_addr[FZA_CMD_CAM_SIZE][2]; /* CAM address entries */
+};
+
+/* PARAM command buffer.
+ *
+ * Permitted ranges given are as defined by the spec and obtained from a
+ * DEFZA-AA rev. C03 board, respectively. The rtoken_timeout field is
+ * erroneously interpreted in units of ms.
+ */
+struct fza_cmd_param {
+ u32 loop_mode; /* loopback mode */
+ u32 t_max; /* Maximum TTRT (T_MAX)
+ * def: ??? [80ns]
+ * C03: [t_req+1,4294967295] [80ns]
+ */
+ u32 t_req; /* Requested TTRT (T_REQ)
+ * def: [50000,2097151] [80ns]
+ * C03: [50001,t_max-1] [80ns]
+ */
+ u32 tvx; /* Valid Transmission Time (TVX)
+ * def: [29375,65280] [80ns]
+ * C03: [29376,65279] [80ns]
+ */
+ u32 lem_threshold; /* LEM threshold */
+ u32 station_id[2]; /* station ID */
+ u32 rtoken_timeout; /* restricted token timeout
+ * def: [0,125000000] [80ns]
+ * C03: [0,9999] [ms]
+ */
+ u32 ring_purger; /* ring purger enable: 0|1 */
+};
+
+/* Loopback modes for the PARAM command. */
+#define FZA_LOOP_NORMAL 0
+#define FZA_LOOP_INTERN 1
+#define FZA_LOOP_EXTERN 2
+
+/* MODPROM command buffer. */
+struct fza_cmd_modprom {
+ u32 llc_prom; /* LLC promiscuous enable */
+ u32 smt_prom; /* SMT promiscuous enable */
+ u32 llc_multi; /* LLC multicast promiscuous enable */
+ u32 llc_bcast; /* LLC broadcast promiscuous enable */
+};
+
+/* SETCHAR command buffer.
+ *
+ * Permitted ranges are as for the PARAM command.
+ */
+struct fza_cmd_setchar {
+ u32 t_max; /* Maximum TTRT (T_MAX) */
+ u32 t_req; /* Requested TTRT (T_REQ) */
+ u32 tvx; /* Valid Transmission Time (TVX) */
+ u32 lem_threshold; /* LEM threshold */
+ u32 rtoken_timeout; /* restricted token timeout */
+ u32 ring_purger; /* ring purger enable */
+};
+
+/* RDCNTR command buffer. */
+struct fza_cmd_rdcntr {
+ struct fza_counters counters; /* counters */
+};
+
+/* STATUS command buffer. */
+struct fza_cmd_status {
+ u32 led_state; /* LED state */
+ u32 rmt_state; /* ring management state */
+ u32 link_state; /* link state */
+ u32 dup_addr; /* duplicate address flag */
+ u32 ring_purger; /* ring purger state */
+ u32 t_neg; /* negotiated TTRT [80ns] */
+ u32 una[2]; /* upstream neighbour address */
+ u32 una_timeout; /* UNA timed out */
+ u32 strip_mode; /* frame strip mode */
+ u32 yield_mode; /* claim token yield mode */
+ u32 phy_state; /* PHY state */
+ u32 neigh_phy; /* neighbour PHY type */
+ u32 reject; /* reject reason */
+ u32 phy_lee; /* PHY link error estimate [-log10] */
+ u32 una_old[2]; /* old upstream neighbour address */
+ u32 rmt_mac; /* remote MAC indicated */
+ u32 ring_err; /* ring error reason */
+ u32 beac_rx[2]; /* sender of last directed beacon */
+ u32 un_dup_addr; /* upstream neighbr dup address flag */
+ u32 dna[2]; /* downstream neighbour address */
+ u32 dna_old[2]; /* old downstream neighbour address */
+};
+
+/* Common command buffer. */
+union fza_cmd_buf {
+ struct fza_cmd_init init;
+ struct fza_cmd_cam cam;
+ struct fza_cmd_param param;
+ struct fza_cmd_modprom modprom;
+ struct fza_cmd_setchar setchar;
+ struct fza_cmd_rdcntr rdcntr;
+ struct fza_cmd_status status;
+};
+
+/* MAC (Media Access Controller) chip packet request header constants. */
+
+/* Packet request header byte #0. */
+#define FZA_PRH0_FMT_TYPE_MASK 0xc0 /* type of packet, always zero */
+#define FZA_PRH0_TOK_TYPE_MASK 0x30 /* type of token required
+ * to send this frame
+ */
+#define FZA_PRH0_TKN_TYPE_ANY 0x30 /* use either token type */
+#define FZA_PRH0_TKN_TYPE_UNR 0x20 /* use an unrestricted token */
+#define FZA_PRH0_TKN_TYPE_RST 0x10 /* use a restricted token */
+#define FZA_PRH0_TKN_TYPE_IMM 0x00 /* send immediately, no token required
+ */
+#define FZA_PRH0_FRAME_MASK 0x08 /* type of frame to send */
+#define FZA_PRH0_FRAME_SYNC 0x08 /* send a synchronous frame */
+#define FZA_PRH0_FRAME_ASYNC 0x00 /* send an asynchronous frame */
+#define FZA_PRH0_MODE_MASK 0x04 /* send mode */
+#define FZA_PRH0_MODE_IMMED 0x04 /* an immediate mode, send regardless
+ * of the ring operational state
+ */
+#define FZA_PRH0_MODE_NORMAL 0x00 /* a normal mode, send only if ring
+ * operational
+ */
+#define FZA_PRH0_SF_MASK 0x02 /* send frame first */
+#define FZA_PRH0_SF_FIRST 0x02 /* send this frame first
+ * with this token capture
+ */
+#define FZA_PRH0_SF_NORMAL 0x00 /* treat this frame normally */
+#define FZA_PRH0_BCN_MASK 0x01 /* beacon frame */
+#define FZA_PRH0_BCN_BEACON 0x01 /* send the frame only
+ * if in the beacon state
+ */
+#define FZA_PRH0_BCN_DATA 0x01 /* send the frame only
+ * if in the data state
+ */
+/* Packet request header byte #1. */
+ /* bit 7 always zero */
+#define FZA_PRH1_SL_MASK 0x40 /* send frame last */
+#define FZA_PRH1_SL_LAST 0x40 /* send this frame last, releasing
+ * the token afterwards
+ */
+#define FZA_PRH1_SL_NORMAL 0x00 /* treat this frame normally */
+#define FZA_PRH1_CRC_MASK 0x20 /* CRC append */
+#define FZA_PRH1_CRC_NORMAL 0x20 /* calculate the CRC and append it
+ * as the FCS field to the frame
+ */
+#define FZA_PRH1_CRC_SKIP 0x00 /* leave the frame as is */
+#define FZA_PRH1_TKN_SEND_MASK 0x18 /* type of token to send after the
+ * frame if this is the last frame
+ */
+#define FZA_PRH1_TKN_SEND_ORIG 0x18 /* send a token of the same type as the
+ * originally captured one
+ */
+#define FZA_PRH1_TKN_SEND_RST 0x10 /* send a restricted token */
+#define FZA_PRH1_TKN_SEND_UNR 0x08 /* send an unrestricted token */
+#define FZA_PRH1_TKN_SEND_NONE 0x00 /* send no token */
+#define FZA_PRH1_EXTRA_FS_MASK 0x07 /* send extra frame status indicators
+ */
+#define FZA_PRH1_EXTRA_FS_ST 0x07 /* TR RR ST II */
+#define FZA_PRH1_EXTRA_FS_SS 0x06 /* TR RR SS II */
+#define FZA_PRH1_EXTRA_FS_SR 0x05 /* TR RR SR II */
+#define FZA_PRH1_EXTRA_FS_NONE1 0x04 /* TR RR II II */
+#define FZA_PRH1_EXTRA_FS_RT 0x03 /* TR RR RT II */
+#define FZA_PRH1_EXTRA_FS_RS 0x02 /* TR RR RS II */
+#define FZA_PRH1_EXTRA_FS_RR 0x01 /* TR RR RR II */
+#define FZA_PRH1_EXTRA_FS_NONE 0x00 /* TR RR II II */
+/* Packet request header byte #2. */
+#define FZA_PRH2_NORMAL 0x00 /* always zero */
+
+/* PRH used for LLC frames. */
+#define FZA_PRH0_LLC (FZA_PRH0_TKN_TYPE_UNR)
+#define FZA_PRH1_LLC (FZA_PRH1_CRC_NORMAL | FZA_PRH1_TKN_SEND_UNR)
+#define FZA_PRH2_LLC (FZA_PRH2_NORMAL)
+
+/* PRH used for SMT frames. */
+#define FZA_PRH0_SMT (FZA_PRH0_TKN_TYPE_UNR)
+#define FZA_PRH1_SMT (FZA_PRH1_CRC_NORMAL | FZA_PRH1_TKN_SEND_UNR)
+#define FZA_PRH2_SMT (FZA_PRH2_NORMAL)
+
+#if ((FZA_RING_RX_SIZE) < 2) || ((FZA_RING_RX_SIZE) > 256)
+# error FZA_RING_RX_SIZE has to be from 2 up to 256
+#endif
+#if ((FZA_RING_TX_MODE) != 0) && ((FZA_RING_TX_MODE) != 1)
+# error FZA_RING_TX_MODE has to be either 0 or 1
+#endif
+
+#define FZA_RING_TX_SIZE (512 << (FZA_RING_TX_MODE))
+
+struct fza_private {
+ struct device *bdev; /* pointer to the bus device */
+ const char *name; /* printable device name */
+ void __iomem *mmio; /* MMIO ioremap cookie */
+ struct fza_regs __iomem *regs; /* pointer to FZA registers */
+
+ struct sk_buff *rx_skbuff[FZA_RING_RX_SIZE];
+ /* all skbs assigned to the host
+ * receive descriptors
+ */
+ dma_addr_t rx_dma[FZA_RING_RX_SIZE];
+ /* their corresponding DMA addresses */
+
+ struct fza_ring_cmd __iomem *ring_cmd;
+ /* pointer to the command descriptor
+ * ring
+ */
+ int ring_cmd_index; /* index to the command descriptor ring
+ * for the next command
+ */
+ struct fza_ring_uns __iomem *ring_uns;
+ /* pointer to the unsolicited
+ * descriptor ring
+ */
+ int ring_uns_index; /* index to the unsolicited descriptor
+ * ring for the next event
+ */
+
+ struct fza_ring_rmc_tx __iomem *ring_rmc_tx;
+ /* pointer to the RMC transmit
+ * descriptor ring (obtained from the
+ * INIT command)
+ */
+ int ring_rmc_tx_size; /* number of entries in the RMC
+ * transmit descriptor ring (obtained
+ * from the INIT command)
+ */
+ int ring_rmc_tx_index; /* index to the RMC transmit descriptor
+ * ring for the next transmission
+ */
+ int ring_rmc_txd_index; /* index to the RMC transmit descriptor
+ * ring for the next transmit done
+ * acknowledge
+ */
+
+ struct fza_ring_hst_rx __iomem *ring_hst_rx;
+ /* pointer to the host receive
+ * descriptor ring (obtained from the
+ * INIT command)
+ */
+ int ring_hst_rx_size; /* number of entries in the host
+ * receive descriptor ring (set by the
+ * INIT command)
+ */
+ int ring_hst_rx_index; /* index to the host receive descriptor
+ * ring for the next transmission
+ */
+
+ struct fza_ring_smt __iomem *ring_smt_tx;
+ /* pointer to the SMT transmit
+ * descriptor ring (obtained from the
+ * INIT command)
+ */
+ int ring_smt_tx_size; /* number of entries in the SMT
+ * transmit descriptor ring (obtained
+ * from the INIT command)
+ */
+ int ring_smt_tx_index; /* index to the SMT transmit descriptor
+ * ring for the next transmission
+ */
+
+ struct fza_ring_smt __iomem *ring_smt_rx;
+ /* pointer to the SMT transmit
+ * descriptor ring (obtained from the
+ * INIT command)
+ */
+ int ring_smt_rx_size; /* number of entries in the SMT
+ * receive descriptor ring (obtained
+ * from the INIT command)
+ */
+ int ring_smt_rx_index; /* index to the SMT receive descriptor
+ * ring for the next transmission
+ */
+
+ struct fza_buffer_tx __iomem *buffer_tx;
+ /* pointer to the RMC transmit buffers
+ */
+
+ uint state; /* adapter expected state */
+
+ spinlock_t lock; /* for device & private data access */
+ uint int_mask; /* interrupt source selector */
+
+ int cmd_done_flag; /* command completion trigger */
+ wait_queue_head_t cmd_done_wait;
+
+ int state_chg_flag; /* state change trigger */
+ wait_queue_head_t state_chg_wait;
+
+ struct timer_list reset_timer; /* RESET time-out trigger */
+ int timer_state; /* RESET trigger state */
+
+ int queue_active; /* whether to enable queueing */
+
+ struct net_device_stats stats;
+
+ uint irq_count_flush_tx; /* transmit flush irqs */
+ uint irq_count_uns_poll; /* unsolicited event irqs */
+ uint irq_count_smt_tx_poll; /* SMT transmit irqs */
+ uint irq_count_rx_poll; /* host receive irqs */
+ uint irq_count_tx_done; /* transmit done irqs */
+ uint irq_count_cmd_done; /* command done irqs */
+ uint irq_count_state_chg; /* state change irqs */
+ uint irq_count_link_st_chg; /* link status change irqs */
+
+ uint t_max; /* T_MAX */
+ uint t_req; /* T_REQ */
+ uint tvx; /* TVX */
+ uint lem_threshold; /* LEM threshold */
+ uint station_id[2]; /* station ID */
+ uint rtoken_timeout; /* restricted token timeout */
+ uint ring_purger; /* ring purger enable flag */
+};
+
+struct fza_fddihdr {
+ u8 pa[2]; /* preamble */
+ u8 sd; /* starting delimiter */
+ struct fddihdr hdr;
+} __packed;
diff --git a/drivers/net/fddi/skfp/ecm.c b/drivers/net/fddi/skfp/ecm.c
index eee9ba91346a..c813e462183d 100644
--- a/drivers/net/fddi/skfp/ecm.c
+++ b/drivers/net/fddi/skfp/ecm.c
@@ -30,7 +30,6 @@
*
* The following external HW dependent functions are referenced :
* sm_pm_bypass_req()
- * sm_pm_ls_latch()
* sm_pm_get_ls()
*
* The following HW dependent events are required :
@@ -356,8 +355,6 @@ static void ecm_fsm(struct s_smc *smc, int cmd)
*/
start_ecm_timer(smc,smc->s.ecm_check_poll,0) ;
smc->e.ecm_line_state = TRUE ; /* flag to pcm: report Q/HLS */
- (void) sm_pm_ls_latch(smc,PA,1) ; /* enable line state latch */
- (void) sm_pm_ls_latch(smc,PB,1) ; /* enable line state latch */
ACTIONS_DONE() ;
break ;
case EC6_CHECK :
diff --git a/drivers/net/fddi/skfp/h/cmtdef.h b/drivers/net/fddi/skfp/h/cmtdef.h
index 5d6891154367..448d66c2e372 100644
--- a/drivers/net/fddi/skfp/h/cmtdef.h
+++ b/drivers/net/fddi/skfp/h/cmtdef.h
@@ -513,7 +513,6 @@ void pcm_status_state(struct s_smc *smc, int np, int *type, int *state,
void plc_config_mux(struct s_smc *smc, int mux);
void sm_lem_evaluate(struct s_smc *smc);
void mac_update_counter(struct s_smc *smc);
-void sm_pm_ls_latch(struct s_smc *smc, int phy, int on_off);
void sm_ma_control(struct s_smc *smc, int mode);
void sm_mac_check_beacon_claim(struct s_smc *smc);
void config_mux(struct s_smc *smc, int mux);
@@ -656,14 +655,6 @@ void dump_hex(char *p, int len);
#ifndef PNMI_INIT
#define PNMI_INIT(smc) /* Nothing */
#endif
-#ifndef PNMI_GET_ID
-#define PNMI_GET_ID( smc, ndis_oid, buf, len, BytesWritten, BytesNeeded ) \
- ( 1 ? (-1) : (-1) )
-#endif
-#ifndef PNMI_SET_ID
-#define PNMI_SET_ID( smc, ndis_oid, buf, len, BytesRead, BytesNeeded, \
- set_type) ( 1 ? (-1) : (-1) )
-#endif
/*
* SMT_PANIC defines
diff --git a/drivers/net/fddi/skfp/pcmplc.c b/drivers/net/fddi/skfp/pcmplc.c
index a9ecf923f63d..6ef44c480bd5 100644
--- a/drivers/net/fddi/skfp/pcmplc.c
+++ b/drivers/net/fddi/skfp/pcmplc.c
@@ -30,7 +30,6 @@
* The following external HW dependent functions are referenced :
* sm_pm_control()
* sm_ph_linestate()
- * sm_pm_ls_latch()
*
* The following HW dependent events are required :
* PC_QLS
@@ -1248,16 +1247,6 @@ static void sm_ph_lem_stop(struct s_smc *smc, int np)
CLEAR(PLC(np,PL_INTR_MASK),PL_LE_CTR) ;
}
-/* ARGSUSED */
-void sm_pm_ls_latch(struct s_smc *smc, int phy, int on_off)
-/* int on_off; en- or disable ident. ls */
-{
- SK_UNUSED(smc) ;
-
- phy = phy ; on_off = on_off ;
-}
-
-
/*
* PCM pseudo code
* receive actions are called AFTER the bit n is received,
diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
index 6acb6b5718b9..a0cd1c41cf5f 100644
--- a/drivers/net/geneve.c
+++ b/drivers/net/geneve.c
@@ -69,6 +69,7 @@ struct geneve_dev {
struct gro_cells gro_cells;
bool collect_md;
bool use_udp6_rx_checksums;
+ bool ttl_inherit;
};
struct geneve_sock {
@@ -830,12 +831,8 @@ static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
if (IS_ERR(rt))
return PTR_ERR(rt);
- if (skb_dst(skb)) {
- int mtu = dst_mtu(&rt->dst) - GENEVE_IPV4_HLEN -
- info->options_len;
-
- skb_dst_update_pmtu(skb, mtu);
- }
+ skb_tunnel_check_pmtu(skb, &rt->dst,
+ GENEVE_IPV4_HLEN + info->options_len);
sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
if (geneve->collect_md) {
@@ -843,7 +840,11 @@ static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
ttl = key->ttl;
} else {
tos = ip_tunnel_ecn_encap(fl4.flowi4_tos, ip_hdr(skb), skb);
- ttl = key->ttl ? : ip4_dst_hoplimit(&rt->dst);
+ if (geneve->ttl_inherit)
+ ttl = ip_tunnel_get_ttl(ip_hdr(skb), skb);
+ else
+ ttl = key->ttl;
+ ttl = ttl ? : ip4_dst_hoplimit(&rt->dst);
}
df = key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0;
@@ -876,11 +877,7 @@ static int geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
if (IS_ERR(dst))
return PTR_ERR(dst);
- if (skb_dst(skb)) {
- int mtu = dst_mtu(dst) - GENEVE_IPV6_HLEN - info->options_len;
-
- skb_dst_update_pmtu(skb, mtu);
- }
+ skb_tunnel_check_pmtu(skb, dst, GENEVE_IPV6_HLEN + info->options_len);
sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
if (geneve->collect_md) {
@@ -889,7 +886,11 @@ static int geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
} else {
prio = ip_tunnel_ecn_encap(ip6_tclass(fl6.flowlabel),
ip_hdr(skb), skb);
- ttl = key->ttl ? : ip6_dst_hoplimit(dst);
+ if (geneve->ttl_inherit)
+ ttl = ip_tunnel_get_ttl(ip_hdr(skb), skb);
+ else
+ ttl = key->ttl;
+ ttl = ttl ? : ip6_dst_hoplimit(dst);
}
err = geneve_build_skb(dst, skb, info, xnet, sizeof(struct ipv6hdr));
if (unlikely(err))
@@ -1091,6 +1092,7 @@ static const struct nla_policy geneve_policy[IFLA_GENEVE_MAX + 1] = {
[IFLA_GENEVE_UDP_CSUM] = { .type = NLA_U8 },
[IFLA_GENEVE_UDP_ZERO_CSUM6_TX] = { .type = NLA_U8 },
[IFLA_GENEVE_UDP_ZERO_CSUM6_RX] = { .type = NLA_U8 },
+ [IFLA_GENEVE_TTL_INHERIT] = { .type = NLA_U8 },
};
static int geneve_validate(struct nlattr *tb[], struct nlattr *data[],
@@ -1170,7 +1172,8 @@ static bool geneve_dst_addr_equal(struct ip_tunnel_info *a,
static int geneve_configure(struct net *net, struct net_device *dev,
struct netlink_ext_ack *extack,
const struct ip_tunnel_info *info,
- bool metadata, bool ipv6_rx_csum)
+ bool metadata, bool ipv6_rx_csum,
+ bool ttl_inherit)
{
struct geneve_net *gn = net_generic(net, geneve_net_id);
struct geneve_dev *t, *geneve = netdev_priv(dev);
@@ -1219,6 +1222,7 @@ static int geneve_configure(struct net *net, struct net_device *dev,
geneve->info = *info;
geneve->collect_md = metadata;
geneve->use_udp6_rx_checksums = ipv6_rx_csum;
+ geneve->ttl_inherit = ttl_inherit;
err = register_netdevice(dev);
if (err)
@@ -1237,7 +1241,8 @@ static void init_tnl_info(struct ip_tunnel_info *info, __u16 dst_port)
static int geneve_nl2info(struct nlattr *tb[], struct nlattr *data[],
struct netlink_ext_ack *extack,
struct ip_tunnel_info *info, bool *metadata,
- bool *use_udp6_rx_checksums, bool changelink)
+ bool *use_udp6_rx_checksums, bool *ttl_inherit,
+ bool changelink)
{
int attrtype;
@@ -1312,8 +1317,15 @@ static int geneve_nl2info(struct nlattr *tb[], struct nlattr *data[],
info->key.tun_id = tunid;
}
- if (data[IFLA_GENEVE_TTL])
+ if (data[IFLA_GENEVE_TTL_INHERIT]) {
+ if (nla_get_u8(data[IFLA_GENEVE_TTL_INHERIT]))
+ *ttl_inherit = true;
+ else
+ *ttl_inherit = false;
+ } else if (data[IFLA_GENEVE_TTL]) {
info->key.ttl = nla_get_u8(data[IFLA_GENEVE_TTL]);
+ *ttl_inherit = false;
+ }
if (data[IFLA_GENEVE_TOS])
info->key.tos = nla_get_u8(data[IFLA_GENEVE_TOS]);
@@ -1438,17 +1450,18 @@ static int geneve_newlink(struct net *net, struct net_device *dev,
{
bool use_udp6_rx_checksums = false;
struct ip_tunnel_info info;
+ bool ttl_inherit = false;
bool metadata = false;
int err;
init_tnl_info(&info, GENEVE_UDP_PORT);
err = geneve_nl2info(tb, data, extack, &info, &metadata,
- &use_udp6_rx_checksums, false);
+ &use_udp6_rx_checksums, &ttl_inherit, false);
if (err)
return err;
err = geneve_configure(net, dev, extack, &info, metadata,
- use_udp6_rx_checksums);
+ use_udp6_rx_checksums, ttl_inherit);
if (err)
return err;
@@ -1511,6 +1524,7 @@ static int geneve_changelink(struct net_device *dev, struct nlattr *tb[],
struct ip_tunnel_info info;
bool metadata;
bool use_udp6_rx_checksums;
+ bool ttl_inherit;
int err;
/* If the geneve device is configured for metadata (or externally
@@ -1523,8 +1537,9 @@ static int geneve_changelink(struct net_device *dev, struct nlattr *tb[],
memcpy(&info, &geneve->info, sizeof(info));
metadata = geneve->collect_md;
use_udp6_rx_checksums = geneve->use_udp6_rx_checksums;
+ ttl_inherit = geneve->ttl_inherit;
err = geneve_nl2info(tb, data, extack, &info, &metadata,
- &use_udp6_rx_checksums, true);
+ &use_udp6_rx_checksums, &ttl_inherit, true);
if (err)
return err;
@@ -1537,6 +1552,7 @@ static int geneve_changelink(struct net_device *dev, struct nlattr *tb[],
geneve->info = info;
geneve->collect_md = metadata;
geneve->use_udp6_rx_checksums = use_udp6_rx_checksums;
+ geneve->ttl_inherit = ttl_inherit;
geneve_unquiesce(geneve, gs4, gs6);
return 0;
@@ -1562,6 +1578,7 @@ static size_t geneve_get_size(const struct net_device *dev)
nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_UDP_CSUM */
nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_UDP_ZERO_CSUM6_TX */
nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_UDP_ZERO_CSUM6_RX */
+ nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_TTL_INHERIT */
0;
}
@@ -1569,6 +1586,7 @@ static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev)
{
struct geneve_dev *geneve = netdev_priv(dev);
struct ip_tunnel_info *info = &geneve->info;
+ bool ttl_inherit = geneve->ttl_inherit;
bool metadata = geneve->collect_md;
__u8 tmp_vni[3];
__u32 vni;
@@ -1614,6 +1632,9 @@ static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev)
goto nla_put_failure;
#endif
+ if (nla_put_u8(skb, IFLA_GENEVE_TTL_INHERIT, ttl_inherit))
+ goto nla_put_failure;
+
return 0;
nla_put_failure:
@@ -1650,7 +1671,7 @@ struct net_device *geneve_dev_create_fb(struct net *net, const char *name,
return dev;
init_tnl_info(&info, dst_port);
- err = geneve_configure(net, dev, NULL, &info, true, true);
+ err = geneve_configure(net, dev, NULL, &info, true, true, false);
if (err) {
free_netdev(dev);
return ERR_PTR(err);
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
index d79a69dd2146..17e6dcd2eb42 100644
--- a/drivers/net/hamradio/6pack.c
+++ b/drivers/net/hamradio/6pack.c
@@ -34,7 +34,6 @@
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/semaphore.h>
-#include <linux/compat.h>
#include <linux/refcount.h>
#define SIXPACK_VERSION "Revision: 0.3.0"
@@ -752,23 +751,6 @@ static int sixpack_ioctl(struct tty_struct *tty, struct file *file,
return err;
}
-#ifdef CONFIG_COMPAT
-static long sixpack_compat_ioctl(struct tty_struct * tty, struct file * file,
- unsigned int cmd, unsigned long arg)
-{
- switch (cmd) {
- case SIOCGIFNAME:
- case SIOCGIFENCAP:
- case SIOCSIFENCAP:
- case SIOCSIFHWADDR:
- return sixpack_ioctl(tty, file, cmd,
- (unsigned long)compat_ptr(arg));
- }
-
- return -ENOIOCTLCMD;
-}
-#endif
-
static struct tty_ldisc_ops sp_ldisc = {
.owner = THIS_MODULE,
.magic = TTY_LDISC_MAGIC,
@@ -776,9 +758,6 @@ static struct tty_ldisc_ops sp_ldisc = {
.open = sixpack_open,
.close = sixpack_close,
.ioctl = sixpack_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = sixpack_compat_ioctl,
-#endif
.receive_buf = sixpack_receive_buf,
.write_wakeup = sixpack_write_wakeup,
};
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index 13e4c1eff353..802233d41b25 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -35,7 +35,6 @@
#include <linux/skbuff.h>
#include <linux/if_arp.h>
#include <linux/jiffies.h>
-#include <linux/compat.h>
#include <net/ax25.h>
@@ -875,23 +874,6 @@ static int mkiss_ioctl(struct tty_struct *tty, struct file *file,
return err;
}
-#ifdef CONFIG_COMPAT
-static long mkiss_compat_ioctl(struct tty_struct *tty, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- switch (cmd) {
- case SIOCGIFNAME:
- case SIOCGIFENCAP:
- case SIOCSIFENCAP:
- case SIOCSIFHWADDR:
- return mkiss_ioctl(tty, file, cmd,
- (unsigned long)compat_ptr(arg));
- }
-
- return -ENOIOCTLCMD;
-}
-#endif
-
/*
* Handle the 'receiver data ready' interrupt.
* This function is called by the 'tty_io' module in the kernel when
@@ -966,9 +948,6 @@ static struct tty_ldisc_ops ax_ldisc = {
.open = mkiss_open,
.close = mkiss_close,
.ioctl = mkiss_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = mkiss_compat_ioctl,
-#endif
.receive_buf = mkiss_receive_buf,
.write_wakeup = mkiss_write_wakeup
};
diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c
index 16ec7af6ab7b..ba9df430fca6 100644
--- a/drivers/net/hamradio/yam.c
+++ b/drivers/net/hamradio/yam.c
@@ -966,6 +966,8 @@ static int yam_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
sizeof(struct yamdrv_ioctl_mcs));
if (IS_ERR(ym))
return PTR_ERR(ym);
+ if (ym->cmd != SIOCYAMSMCS)
+ return -EINVAL;
if (ym->bitrate > YAM_MAXBITRATE) {
kfree(ym);
return -EINVAL;
@@ -981,6 +983,8 @@ static int yam_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if (copy_from_user(&yi, ifr->ifr_data, sizeof(struct yamdrv_ioctl_cfg)))
return -EFAULT;
+ if (yi.cmd != SIOCYAMSCFG)
+ return -EINVAL;
if ((yi.cfg.mask & YAM_IOBASE) && netif_running(dev))
return -EINVAL; /* Cannot change this parameter when up */
if ((yi.cfg.mask & YAM_IRQ) && netif_running(dev))
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index a32ded5b4f41..ef6f766f6389 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -185,7 +185,9 @@ struct rndis_device {
/* Interface */
struct rndis_message;
+struct ndis_offload_params;
struct netvsc_device;
+struct netvsc_channel;
struct net_device_context;
extern u32 netvsc_ring_bytes;
@@ -203,10 +205,7 @@ void netvsc_linkstatus_callback(struct net_device *net,
struct rndis_message *resp);
int netvsc_recv_callback(struct net_device *net,
struct netvsc_device *nvdev,
- struct vmbus_channel *channel,
- void *data, u32 len,
- const struct ndis_tcp_ip_checksum_info *csum_info,
- const struct ndis_pkt_8021q_info *vlan);
+ struct netvsc_channel *nvchan);
void netvsc_channel_cb(void *context);
int netvsc_poll(struct napi_struct *napi, int budget);
@@ -220,9 +219,12 @@ void rndis_filter_device_remove(struct hv_device *dev,
struct netvsc_device *nvdev);
int rndis_filter_set_rss_param(struct rndis_device *rdev,
const u8 *key);
+int rndis_filter_set_offload_params(struct net_device *ndev,
+ struct netvsc_device *nvdev,
+ struct ndis_offload_params *req_offloads);
int rndis_filter_receive(struct net_device *ndev,
struct netvsc_device *net_dev,
- struct vmbus_channel *channel,
+ struct netvsc_channel *nvchan,
void *data, u32 buflen);
int rndis_filter_set_device_mac(struct netvsc_device *ndev,
@@ -524,6 +526,8 @@ struct nvsp_2_vsc_capability {
u64 ieee8021q:1;
u64 correlation_id:1;
u64 teaming:1;
+ u64 vsubnetid:1;
+ u64 rsc:1;
};
};
} __packed;
@@ -826,7 +830,7 @@ struct nvsp_message {
#define NETVSC_SUPPORTED_HW_FEATURES (NETIF_F_RXCSUM | NETIF_F_IP_CSUM | \
NETIF_F_TSO | NETIF_F_IPV6_CSUM | \
- NETIF_F_TSO6)
+ NETIF_F_TSO6 | NETIF_F_LRO)
#define VRSS_SEND_TAB_SIZE 16 /* must be power of 2 */
#define VRSS_CHANNEL_MAX 64
@@ -852,6 +856,18 @@ struct multi_recv_comp {
u32 next; /* next entry for writing */
};
+#define NVSP_RSC_MAX 562 /* Max #RSC frags in a vmbus xfer page pkt */
+
+struct nvsc_rsc {
+ const struct ndis_pkt_8021q_info *vlan;
+ const struct ndis_tcp_ip_checksum_info *csum_info;
+ u8 is_last; /* last RNDIS msg in a vmtransfer_page */
+ u32 cnt; /* #fragments in an RSC packet */
+ u32 pktlen; /* Full packet length */
+ void *data[NVSP_RSC_MAX];
+ u32 len[NVSP_RSC_MAX];
+};
+
struct netvsc_stats {
u64 packets;
u64 bytes;
@@ -955,6 +971,7 @@ struct netvsc_channel {
struct multi_send_data msd;
struct multi_recv_comp mrc;
atomic_t queue_sends;
+ struct nvsc_rsc rsc;
struct netvsc_stats tx_stats;
struct netvsc_stats rx_stats;
@@ -1136,7 +1153,8 @@ struct rndis_oobd {
/* Packet extension field contents associated with a Data message. */
struct rndis_per_packet_info {
u32 size;
- u32 type;
+ u32 type:31;
+ u32 internal:1;
u32 ppi_offset;
};
@@ -1157,6 +1175,25 @@ enum ndis_per_pkt_info_type {
MAX_PER_PKT_INFO
};
+enum rndis_per_pkt_info_interal_type {
+ RNDIS_PKTINFO_ID = 1,
+ /* Add more memebers here */
+
+ RNDIS_PKTINFO_MAX
+};
+
+#define RNDIS_PKTINFO_SUBALLOC BIT(0)
+#define RNDIS_PKTINFO_1ST_FRAG BIT(1)
+#define RNDIS_PKTINFO_LAST_FRAG BIT(2)
+
+#define RNDIS_PKTINFO_ID_V1 1
+
+struct rndis_pktinfo_id {
+ u8 ver;
+ u8 flag;
+ u16 pkt_id;
+};
+
struct ndis_pkt_8021q_info {
union {
struct {
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index fe01e141c8f8..922054c1d544 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -542,6 +542,9 @@ static int negotiate_nvsp_ver(struct hv_device *device,
init_packet->msg.v2_msg.send_ndis_config.capability.teaming = 1;
}
+ if (nvsp_ver >= NVSP_PROTOCOL_VERSION_61)
+ init_packet->msg.v2_msg.send_ndis_config.capability.rsc = 1;
+
trace_nvsp_send(ndev, init_packet);
ret = vmbus_sendpacket(device->channel, init_packet,
@@ -1111,11 +1114,12 @@ static void enq_receive_complete(struct net_device *ndev,
static int netvsc_receive(struct net_device *ndev,
struct netvsc_device *net_device,
- struct vmbus_channel *channel,
+ struct netvsc_channel *nvchan,
const struct vmpacket_descriptor *desc,
const struct nvsp_message *nvsp)
{
struct net_device_context *net_device_ctx = netdev_priv(ndev);
+ struct vmbus_channel *channel = nvchan->channel;
const struct vmtransfer_page_packet_header *vmxferpage_packet
= container_of(desc, const struct vmtransfer_page_packet_header, d);
u16 q_idx = channel->offermsg.offer.sub_channel_index;
@@ -1150,6 +1154,7 @@ static int netvsc_receive(struct net_device *ndev,
int ret;
if (unlikely(offset + buflen > net_device->recv_buf_size)) {
+ nvchan->rsc.cnt = 0;
status = NVSP_STAT_FAIL;
netif_err(net_device_ctx, rx_err, ndev,
"Packet offset:%u + len:%u too big\n",
@@ -1160,11 +1165,13 @@ static int netvsc_receive(struct net_device *ndev,
data = recv_buf + offset;
+ nvchan->rsc.is_last = (i == count - 1);
+
trace_rndis_recv(ndev, q_idx, data);
/* Pass it to the upper layer */
ret = rndis_filter_receive(ndev, net_device,
- channel, data, buflen);
+ nvchan, data, buflen);
if (unlikely(ret != NVSP_STAT_SUCCESS))
status = NVSP_STAT_FAIL;
@@ -1223,12 +1230,13 @@ static void netvsc_receive_inband(struct net_device *ndev,
}
static int netvsc_process_raw_pkt(struct hv_device *device,
- struct vmbus_channel *channel,
+ struct netvsc_channel *nvchan,
struct netvsc_device *net_device,
struct net_device *ndev,
const struct vmpacket_descriptor *desc,
int budget)
{
+ struct vmbus_channel *channel = nvchan->channel;
const struct nvsp_message *nvmsg = hv_pkt_data(desc);
trace_nvsp_recv(ndev, channel, nvmsg);
@@ -1240,7 +1248,7 @@ static int netvsc_process_raw_pkt(struct hv_device *device,
break;
case VM_PKT_DATA_USING_XFER_PAGES:
- return netvsc_receive(ndev, net_device, channel,
+ return netvsc_receive(ndev, net_device, nvchan,
desc, nvmsg);
break;
@@ -1284,7 +1292,7 @@ int netvsc_poll(struct napi_struct *napi, int budget)
nvchan->desc = hv_pkt_iter_first(channel);
while (nvchan->desc && work_done < budget) {
- work_done += netvsc_process_raw_pkt(device, channel, net_device,
+ work_done += netvsc_process_raw_pkt(device, nvchan, net_device,
ndev, nvchan->desc, budget);
nvchan->desc = hv_pkt_iter_next(channel, nvchan->desc);
}
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 3af6d8d15233..cf36e7ff3191 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -226,6 +226,7 @@ static inline void *init_ppi_data(struct rndis_message *msg,
ppi->size = ppi_size;
ppi->type = pkt_type;
+ ppi->internal = 0;
ppi->ppi_offset = sizeof(struct rndis_per_packet_info);
rndis_pkt->per_pkt_info_len += ppi_size;
@@ -744,14 +745,16 @@ void netvsc_linkstatus_callback(struct net_device *net,
}
static struct sk_buff *netvsc_alloc_recv_skb(struct net_device *net,
- struct napi_struct *napi,
- const struct ndis_tcp_ip_checksum_info *csum_info,
- const struct ndis_pkt_8021q_info *vlan,
- void *data, u32 buflen)
+ struct netvsc_channel *nvchan)
{
+ struct napi_struct *napi = &nvchan->napi;
+ const struct ndis_pkt_8021q_info *vlan = nvchan->rsc.vlan;
+ const struct ndis_tcp_ip_checksum_info *csum_info =
+ nvchan->rsc.csum_info;
struct sk_buff *skb;
+ int i;
- skb = napi_alloc_skb(napi, buflen);
+ skb = napi_alloc_skb(napi, nvchan->rsc.pktlen);
if (!skb)
return skb;
@@ -759,7 +762,8 @@ static struct sk_buff *netvsc_alloc_recv_skb(struct net_device *net,
* Copy to skb. This copy is needed here since the memory pointed by
* hv_netvsc_packet cannot be deallocated
*/
- skb_put_data(skb, data, buflen);
+ for (i = 0; i < nvchan->rsc.cnt; i++)
+ skb_put_data(skb, nvchan->rsc.data[i], nvchan->rsc.len[i]);
skb->protocol = eth_type_trans(skb, net);
@@ -792,14 +796,11 @@ static struct sk_buff *netvsc_alloc_recv_skb(struct net_device *net,
*/
int netvsc_recv_callback(struct net_device *net,
struct netvsc_device *net_device,
- struct vmbus_channel *channel,
- void *data, u32 len,
- const struct ndis_tcp_ip_checksum_info *csum_info,
- const struct ndis_pkt_8021q_info *vlan)
+ struct netvsc_channel *nvchan)
{
struct net_device_context *net_device_ctx = netdev_priv(net);
+ struct vmbus_channel *channel = nvchan->channel;
u16 q_idx = channel->offermsg.offer.sub_channel_index;
- struct netvsc_channel *nvchan = &net_device->chan_table[q_idx];
struct sk_buff *skb;
struct netvsc_stats *rx_stats;
@@ -807,8 +808,8 @@ int netvsc_recv_callback(struct net_device *net,
return NVSP_STAT_FAIL;
/* Allocate a skb - TODO direct I/O to pages? */
- skb = netvsc_alloc_recv_skb(net, &nvchan->napi,
- csum_info, vlan, data, len);
+ skb = netvsc_alloc_recv_skb(net, nvchan);
+
if (unlikely(!skb)) {
++net_device_ctx->eth_stats.rx_no_memory;
rcu_read_unlock();
@@ -825,7 +826,7 @@ int netvsc_recv_callback(struct net_device *net,
rx_stats = &nvchan->rx_stats;
u64_stats_update_begin(&rx_stats->syncp);
rx_stats->packets++;
- rx_stats->bytes += len;
+ rx_stats->bytes += nvchan->rsc.pktlen;
if (skb->pkt_type == PACKET_BROADCAST)
++rx_stats->broadcast;
@@ -1006,6 +1007,8 @@ static void netvsc_init_settings(struct net_device *dev)
ndc->speed = SPEED_UNKNOWN;
ndc->duplex = DUPLEX_FULL;
+
+ dev->features = NETIF_F_LRO;
}
static int netvsc_get_link_ksettings(struct net_device *dev,
@@ -1562,26 +1565,6 @@ netvsc_set_rxnfc(struct net_device *ndev, struct ethtool_rxnfc *info)
return -EOPNOTSUPP;
}
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void netvsc_poll_controller(struct net_device *dev)
-{
- struct net_device_context *ndc = netdev_priv(dev);
- struct netvsc_device *ndev;
- int i;
-
- rcu_read_lock();
- ndev = rcu_dereference(ndc->nvdev);
- if (ndev) {
- for (i = 0; i < ndev->num_chn; i++) {
- struct netvsc_channel *nvchan = &ndev->chan_table[i];
-
- napi_schedule(&nvchan->napi);
- }
- }
- rcu_read_unlock();
-}
-#endif
-
static u32 netvsc_get_rxfh_key_size(struct net_device *dev)
{
return NETVSC_HASH_KEYLEN;
@@ -1733,6 +1716,33 @@ static int netvsc_set_ringparam(struct net_device *ndev,
return ret;
}
+static int netvsc_set_features(struct net_device *ndev,
+ netdev_features_t features)
+{
+ netdev_features_t change = features ^ ndev->features;
+ struct net_device_context *ndevctx = netdev_priv(ndev);
+ struct netvsc_device *nvdev = rtnl_dereference(ndevctx->nvdev);
+ struct ndis_offload_params offloads;
+
+ if (!nvdev || nvdev->destroy)
+ return -ENODEV;
+
+ if (!(change & NETIF_F_LRO))
+ return 0;
+
+ memset(&offloads, 0, sizeof(struct ndis_offload_params));
+
+ if (features & NETIF_F_LRO) {
+ offloads.rsc_ip_v4 = NDIS_OFFLOAD_PARAMETERS_RSC_ENABLED;
+ offloads.rsc_ip_v6 = NDIS_OFFLOAD_PARAMETERS_RSC_ENABLED;
+ } else {
+ offloads.rsc_ip_v4 = NDIS_OFFLOAD_PARAMETERS_RSC_DISABLED;
+ offloads.rsc_ip_v6 = NDIS_OFFLOAD_PARAMETERS_RSC_DISABLED;
+ }
+
+ return rndis_filter_set_offload_params(ndev, nvdev, &offloads);
+}
+
static u32 netvsc_get_msglevel(struct net_device *ndev)
{
struct net_device_context *ndev_ctx = netdev_priv(ndev);
@@ -1776,14 +1786,12 @@ static const struct net_device_ops device_ops = {
.ndo_start_xmit = netvsc_start_xmit,
.ndo_change_rx_flags = netvsc_change_rx_flags,
.ndo_set_rx_mode = netvsc_set_rx_mode,
+ .ndo_set_features = netvsc_set_features,
.ndo_change_mtu = netvsc_change_mtu,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = netvsc_set_mac_addr,
.ndo_select_queue = netvsc_select_queue,
.ndo_get_stats64 = netvsc_get_stats64,
-#ifdef CONFIG_NET_POLL_CONTROLLER
- .ndo_poll_controller = netvsc_poll_controller,
-#endif
};
/*
@@ -2022,14 +2030,15 @@ static void netvsc_vf_setup(struct work_struct *w)
rtnl_unlock();
}
-/* Find netvsc by VMBus serial number.
- * The PCI hyperv controller records the serial number as the slot.
+/* Find netvsc by VF serial number.
+ * The PCI hyperv controller records the serial number as the slot kobj name.
*/
static struct net_device *get_netvsc_byslot(const struct net_device *vf_netdev)
{
struct device *parent = vf_netdev->dev.parent;
struct net_device_context *ndev_ctx;
struct pci_dev *pdev;
+ u32 serial;
if (!parent || !dev_is_pci(parent))
return NULL; /* not a PCI device */
@@ -2040,16 +2049,22 @@ static struct net_device *get_netvsc_byslot(const struct net_device *vf_netdev)
return NULL;
}
+ if (kstrtou32(pci_slot_name(pdev->slot), 10, &serial)) {
+ netdev_notice(vf_netdev, "Invalid vf serial:%s\n",
+ pci_slot_name(pdev->slot));
+ return NULL;
+ }
+
list_for_each_entry(ndev_ctx, &netvsc_dev_list, list) {
if (!ndev_ctx->vf_alloc)
continue;
- if (ndev_ctx->vf_serial == pdev->slot->number)
+ if (ndev_ctx->vf_serial == serial)
return hv_get_drvdata(ndev_ctx->device_ctx);
}
netdev_notice(vf_netdev,
- "no netdev found for slot %u\n", pdev->slot->number);
+ "no netdev found for vf serial:%u\n", serial);
return NULL;
}
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c
index 2a5209f23f29..8b537a049c1e 100644
--- a/drivers/net/hyperv/rndis_filter.c
+++ b/drivers/net/hyperv/rndis_filter.c
@@ -342,7 +342,8 @@ static void rndis_filter_receive_response(struct net_device *ndev,
* Get the Per-Packet-Info with the specified type
* return NULL if not found.
*/
-static inline void *rndis_get_ppi(struct rndis_packet *rpkt, u32 type)
+static inline void *rndis_get_ppi(struct rndis_packet *rpkt,
+ u32 type, u8 internal)
{
struct rndis_per_packet_info *ppi;
int len;
@@ -355,7 +356,7 @@ static inline void *rndis_get_ppi(struct rndis_packet *rpkt, u32 type)
len = rpkt->per_pkt_info_len;
while (len > 0) {
- if (ppi->type == type)
+ if (ppi->type == type && ppi->internal == internal)
return (void *)((ulong)ppi + ppi->ppi_offset);
len -= ppi->size;
ppi = (struct rndis_per_packet_info *)((ulong)ppi + ppi->size);
@@ -364,17 +365,41 @@ static inline void *rndis_get_ppi(struct rndis_packet *rpkt, u32 type)
return NULL;
}
+static inline
+void rsc_add_data(struct netvsc_channel *nvchan,
+ const struct ndis_pkt_8021q_info *vlan,
+ const struct ndis_tcp_ip_checksum_info *csum_info,
+ void *data, u32 len)
+{
+ u32 cnt = nvchan->rsc.cnt;
+
+ if (cnt) {
+ nvchan->rsc.pktlen += len;
+ } else {
+ nvchan->rsc.vlan = vlan;
+ nvchan->rsc.csum_info = csum_info;
+ nvchan->rsc.pktlen = len;
+ }
+
+ nvchan->rsc.data[cnt] = data;
+ nvchan->rsc.len[cnt] = len;
+ nvchan->rsc.cnt++;
+}
+
static int rndis_filter_receive_data(struct net_device *ndev,
struct netvsc_device *nvdev,
- struct vmbus_channel *channel,
+ struct netvsc_channel *nvchan,
struct rndis_message *msg,
u32 data_buflen)
{
struct rndis_packet *rndis_pkt = &msg->msg.pkt;
const struct ndis_tcp_ip_checksum_info *csum_info;
const struct ndis_pkt_8021q_info *vlan;
+ const struct rndis_pktinfo_id *pktinfo_id;
u32 data_offset;
void *data;
+ bool rsc_more = false;
+ int ret;
/* Remove the rndis header and pass it back up the stack */
data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset;
@@ -393,25 +418,59 @@ static int rndis_filter_receive_data(struct net_device *ndev,
return NVSP_STAT_FAIL;
}
- vlan = rndis_get_ppi(rndis_pkt, IEEE_8021Q_INFO);
+ vlan = rndis_get_ppi(rndis_pkt, IEEE_8021Q_INFO, 0);
+
+ csum_info = rndis_get_ppi(rndis_pkt, TCPIP_CHKSUM_PKTINFO, 0);
- csum_info = rndis_get_ppi(rndis_pkt, TCPIP_CHKSUM_PKTINFO);
+ pktinfo_id = rndis_get_ppi(rndis_pkt, RNDIS_PKTINFO_ID, 1);
data = (void *)msg + data_offset;
- /*
- * Remove the rndis trailer padding from rndis packet message
+ /* Identify RSC frags, drop erroneous packets */
+ if (pktinfo_id && (pktinfo_id->flag & RNDIS_PKTINFO_SUBALLOC)) {
+ if (pktinfo_id->flag & RNDIS_PKTINFO_1ST_FRAG)
+ nvchan->rsc.cnt = 0;
+ else if (nvchan->rsc.cnt == 0)
+ goto drop;
+
+ rsc_more = true;
+
+ if (pktinfo_id->flag & RNDIS_PKTINFO_LAST_FRAG)
+ rsc_more = false;
+
+ if (rsc_more && nvchan->rsc.is_last)
+ goto drop;
+ } else {
+ nvchan->rsc.cnt = 0;
+ }
+
+ if (unlikely(nvchan->rsc.cnt >= NVSP_RSC_MAX))
+ goto drop;
+
+ /* Put data into per channel structure.
+ * Also, remove the rndis trailer padding from rndis packet message
* rndis_pkt->data_len tell us the real data length, we only copy
* the data packet to the stack, without the rndis trailer padding
*/
- return netvsc_recv_callback(ndev, nvdev, channel,
- data, rndis_pkt->data_len,
- csum_info, vlan);
+ rsc_add_data(nvchan, vlan, csum_info, data, rndis_pkt->data_len);
+
+ if (rsc_more)
+ return NVSP_STAT_SUCCESS;
+
+ ret = netvsc_recv_callback(ndev, nvdev, nvchan);
+ nvchan->rsc.cnt = 0;
+
+ return ret;
+
+drop:
+ /* Drop incomplete packet */
+ nvchan->rsc.cnt = 0;
+ return NVSP_STAT_FAIL;
}
int rndis_filter_receive(struct net_device *ndev,
struct netvsc_device *net_dev,
- struct vmbus_channel *channel,
+ struct netvsc_channel *nvchan,
void *data, u32 buflen)
{
struct net_device_context *net_device_ctx = netdev_priv(ndev);
@@ -422,7 +481,7 @@ int rndis_filter_receive(struct net_device *ndev,
switch (rndis_msg->ndis_msg_type) {
case RNDIS_MSG_PACKET:
- return rndis_filter_receive_data(ndev, net_dev, channel,
+ return rndis_filter_receive_data(ndev, net_dev, nvchan,
rndis_msg, buflen);
case RNDIS_MSG_INIT_C:
case RNDIS_MSG_QUERY_C:
@@ -657,7 +716,7 @@ cleanup:
return ret;
}
-static int
+int
rndis_filter_set_offload_params(struct net_device *ndev,
struct netvsc_device *nvdev,
struct ndis_offload_params *req_offloads)
@@ -1184,6 +1243,18 @@ static int rndis_netdev_set_hwcaps(struct rndis_device *rndis_device,
}
}
+ if (hwcaps.rsc.ip4 && hwcaps.rsc.ip6) {
+ net->hw_features |= NETIF_F_LRO;
+
+ if (net->features & NETIF_F_LRO) {
+ offloads.rsc_ip_v4 = NDIS_OFFLOAD_PARAMETERS_RSC_ENABLED;
+ offloads.rsc_ip_v6 = NDIS_OFFLOAD_PARAMETERS_RSC_ENABLED;
+ } else {
+ offloads.rsc_ip_v4 = NDIS_OFFLOAD_PARAMETERS_RSC_DISABLED;
+ offloads.rsc_ip_v6 = NDIS_OFFLOAD_PARAMETERS_RSC_DISABLED;
+ }
+ }
+
/* In case some hw_features disappeared we need to remove them from
* net->features list as they're no longer supported.
*/
diff --git a/drivers/net/ieee802154/adf7242.c b/drivers/net/ieee802154/adf7242.c
index 23a52b9293f3..cd1d8faccca5 100644
--- a/drivers/net/ieee802154/adf7242.c
+++ b/drivers/net/ieee802154/adf7242.c
@@ -1308,8 +1308,7 @@ static int adf7242_remove(struct spi_device *spi)
{
struct adf7242_local *lp = spi_get_drvdata(spi);
- if (!IS_ERR_OR_NULL(lp->debugfs_root))
- debugfs_remove_recursive(lp->debugfs_root);
+ debugfs_remove_recursive(lp->debugfs_root);
cancel_delayed_work_sync(&lp->work);
destroy_workqueue(lp->wqueue);
diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c
index 58299fb666ed..0ff5a403a8dc 100644
--- a/drivers/net/ieee802154/ca8210.c
+++ b/drivers/net/ieee802154/ca8210.c
@@ -634,10 +634,9 @@ static int ca8210_test_int_driver_write(
for (i = 0; i < len; i++)
dev_dbg(&priv->spi->dev, "%#03x\n", buf[i]);
- fifo_buffer = kmalloc(len, GFP_KERNEL);
+ fifo_buffer = kmemdup(buf, len, GFP_KERNEL);
if (!fifo_buffer)
return -ENOMEM;
- memcpy(fifo_buffer, buf, len);
kfifo_in(&test->up_fifo, &fifo_buffer, 4);
wake_up_interruptible(&priv->test.readq);
@@ -3044,8 +3043,7 @@ static void ca8210_test_interface_clear(struct ca8210_priv *priv)
{
struct ca8210_test *test = &priv->test;
- if (!IS_ERR(test->ca8210_dfs_spi_int))
- debugfs_remove(test->ca8210_dfs_spi_int);
+ debugfs_remove(test->ca8210_dfs_spi_int);
kfifo_free(&test->up_fifo);
dev_info(&priv->spi->dev, "Test interface removed\n");
}
diff --git a/drivers/net/ieee802154/mac802154_hwsim.c b/drivers/net/ieee802154/mac802154_hwsim.c
index bf70ab892e69..51b5198d5943 100644
--- a/drivers/net/ieee802154/mac802154_hwsim.c
+++ b/drivers/net/ieee802154/mac802154_hwsim.c
@@ -37,8 +37,6 @@ MODULE_LICENSE("GPL");
static LIST_HEAD(hwsim_phys);
static DEFINE_MUTEX(hwsim_phys_lock);
-static LIST_HEAD(hwsim_ifup_phys);
-
static struct platform_device *mac802154hwsim_dev;
/* MAC802154_HWSIM netlink family */
@@ -85,7 +83,6 @@ struct hwsim_phy {
struct list_head edges;
struct list_head list;
- struct list_head list_ifup;
};
static int hwsim_add_one(struct genl_info *info, struct device *dev,
@@ -159,9 +156,6 @@ static int hwsim_hw_start(struct ieee802154_hw *hw)
struct hwsim_phy *phy = hw->priv;
phy->suspended = false;
- list_add_rcu(&phy->list_ifup, &hwsim_ifup_phys);
- synchronize_rcu();
-
return 0;
}
@@ -170,8 +164,6 @@ static void hwsim_hw_stop(struct ieee802154_hw *hw)
struct hwsim_phy *phy = hw->priv;
phy->suspended = true;
- list_del_rcu(&phy->list_ifup);
- synchronize_rcu();
}
static int
diff --git a/drivers/net/ieee802154/mcr20a.c b/drivers/net/ieee802154/mcr20a.c
index e428277781ac..44de81e5f140 100644
--- a/drivers/net/ieee802154/mcr20a.c
+++ b/drivers/net/ieee802154/mcr20a.c
@@ -132,11 +132,6 @@ static const struct reg_sequence mar20a_iar_overwrites[] = {
};
#define MCR20A_VALID_CHANNELS (0x07FFF800)
-
-struct mcr20a_platform_data {
- int rst_gpio;
-};
-
#define MCR20A_MAX_BUF (127)
#define printdev(X) (&X->spi->dev)
@@ -412,7 +407,6 @@ struct mcr20a_local {
struct spi_device *spi;
struct ieee802154_hw *hw;
- struct mcr20a_platform_data *pdata;
struct regmap *regmap_dar;
struct regmap *regmap_iar;
@@ -903,19 +897,19 @@ mcr20a_irq_clean_complete(void *context)
switch (seq_state) {
/* TX IRQ, RX IRQ and SEQ IRQ */
- case (0x03):
+ case (DAR_IRQSTS1_TXIRQ | DAR_IRQSTS1_SEQIRQ):
if (lp->is_tx) {
lp->is_tx = 0;
dev_dbg(printdev(lp), "TX is done. No ACK\n");
mcr20a_handle_tx_complete(lp);
}
break;
- case (0x05):
+ case (DAR_IRQSTS1_RXIRQ | DAR_IRQSTS1_SEQIRQ):
/* rx is starting */
dev_dbg(printdev(lp), "RX is starting\n");
mcr20a_handle_rx(lp);
break;
- case (0x07):
+ case (DAR_IRQSTS1_RXIRQ | DAR_IRQSTS1_TXIRQ | DAR_IRQSTS1_SEQIRQ):
if (lp->is_tx) {
/* tx is done */
lp->is_tx = 0;
@@ -927,7 +921,7 @@ mcr20a_irq_clean_complete(void *context)
mcr20a_handle_rx(lp);
}
break;
- case (0x01):
+ case (DAR_IRQSTS1_SEQIRQ):
if (lp->is_tx) {
dev_dbg(printdev(lp), "TX is starting\n");
mcr20a_handle_tx(lp);
@@ -976,20 +970,6 @@ static irqreturn_t mcr20a_irq_isr(int irq, void *data)
return IRQ_HANDLED;
}
-static int mcr20a_get_platform_data(struct spi_device *spi,
- struct mcr20a_platform_data *pdata)
-{
- int ret = 0;
-
- if (!spi->dev.of_node)
- return -EINVAL;
-
- pdata->rst_gpio = of_get_named_gpio(spi->dev.of_node, "rst_b-gpio", 0);
- dev_dbg(&spi->dev, "rst_b-gpio: %d\n", pdata->rst_gpio);
-
- return ret;
-}
-
static void mcr20a_hw_setup(struct mcr20a_local *lp)
{
u8 i;
@@ -1249,7 +1229,7 @@ mcr20a_probe(struct spi_device *spi)
{
struct ieee802154_hw *hw;
struct mcr20a_local *lp;
- struct mcr20a_platform_data *pdata;
+ struct gpio_desc *rst_b;
int irq_type;
int ret = -ENOMEM;
@@ -1260,48 +1240,32 @@ mcr20a_probe(struct spi_device *spi)
return -EINVAL;
}
- pdata = kmalloc(sizeof(*pdata), GFP_KERNEL);
- if (!pdata)
- return -ENOMEM;
-
- /* set mcr20a platform data */
- ret = mcr20a_get_platform_data(spi, pdata);
- if (ret < 0) {
- dev_crit(&spi->dev, "mcr20a_get_platform_data failed.\n");
- goto free_pdata;
- }
-
- /* init reset gpio */
- if (gpio_is_valid(pdata->rst_gpio)) {
- ret = devm_gpio_request_one(&spi->dev, pdata->rst_gpio,
- GPIOF_OUT_INIT_HIGH, "reset");
- if (ret)
- goto free_pdata;
+ rst_b = devm_gpiod_get(&spi->dev, "rst_b", GPIOD_OUT_HIGH);
+ if (IS_ERR(rst_b)) {
+ ret = PTR_ERR(rst_b);
+ if (ret != -EPROBE_DEFER)
+ dev_err(&spi->dev, "Failed to get 'rst_b' gpio: %d", ret);
+ return ret;
}
/* reset mcr20a */
- if (gpio_is_valid(pdata->rst_gpio)) {
- usleep_range(10, 20);
- gpio_set_value_cansleep(pdata->rst_gpio, 0);
- usleep_range(10, 20);
- gpio_set_value_cansleep(pdata->rst_gpio, 1);
- usleep_range(120, 240);
- }
+ usleep_range(10, 20);
+ gpiod_set_value_cansleep(rst_b, 1);
+ usleep_range(10, 20);
+ gpiod_set_value_cansleep(rst_b, 0);
+ usleep_range(120, 240);
/* allocate ieee802154_hw and private data */
hw = ieee802154_alloc_hw(sizeof(*lp), &mcr20a_hw_ops);
if (!hw) {
dev_crit(&spi->dev, "ieee802154_alloc_hw failed\n");
- ret = -ENOMEM;
- goto free_pdata;
+ return ret;
}
/* init mcr20a local data */
lp = hw->priv;
lp->hw = hw;
lp->spi = spi;
- lp->spi->dev.platform_data = pdata;
- lp->pdata = pdata;
/* init ieee802154_hw */
hw->parent = &spi->dev;
@@ -1370,8 +1334,6 @@ mcr20a_probe(struct spi_device *spi)
free_dev:
ieee802154_free_hw(lp->hw);
-free_pdata:
- kfree(pdata);
return ret;
}
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index 30612497643c..2df7f60fe052 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -59,12 +59,6 @@
#include <net/net_namespace.h>
#include <linux/u64_stats_sync.h>
-struct pcpu_lstats {
- u64 packets;
- u64 bytes;
- struct u64_stats_sync syncp;
-};
-
/* The higher levels take care of making this non-reentrant (it's
* called with bh's disabled).
*/
@@ -75,6 +69,10 @@ static netdev_tx_t loopback_xmit(struct sk_buff *skb,
int len;
skb_tx_timestamp(skb);
+
+ /* do not fool net_timestamp_check() with various clock bases */
+ skb->tstamp = 0;
+
skb_orphan(skb);
/* Before queueing this packet to netif_rx(),
diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
index 7de88b33d5b9..64a982563d59 100644
--- a/drivers/net/macsec.c
+++ b/drivers/net/macsec.c
@@ -64,9 +64,9 @@ struct macsec_eth_header {
#define MACSEC_NUM_AN 4 /* 2 bits for the association number */
-#define for_each_rxsc(secy, sc) \
+#define for_each_rxsc(secy, sc) \
for (sc = rcu_dereference_bh(secy->rx_sc); \
- sc; \
+ sc; \
sc = rcu_dereference_bh(sc->next))
#define for_each_rxsc_rtnl(secy, sc) \
for (sc = rtnl_dereference(secy->rx_sc); \
@@ -1142,6 +1142,7 @@ static rx_handler_result_t macsec_handle_frame(struct sk_buff **pskb)
list_for_each_entry_rcu(macsec, &rxd->secys, secys) {
struct macsec_rx_sc *sc = find_rx_sc(&macsec->secy, sci);
+
sc = sc ? macsec_rxsc_get(sc) : NULL;
if (sc) {
@@ -1584,7 +1585,6 @@ static struct macsec_rx_sa *get_rxsa_from_nl(struct net *net,
return rx_sa;
}
-
static const struct nla_policy macsec_genl_policy[NUM_MACSEC_ATTR] = {
[MACSEC_ATTR_IFINDEX] = { .type = NLA_U32 },
[MACSEC_ATTR_RXSC_CONFIG] = { .type = NLA_NESTED },
@@ -2156,7 +2156,7 @@ static int macsec_upd_rxsc(struct sk_buff *skb, struct genl_info *info)
}
static int copy_tx_sa_stats(struct sk_buff *skb,
- struct macsec_tx_sa_stats __percpu *pstats)
+ struct macsec_tx_sa_stats __percpu *pstats)
{
struct macsec_tx_sa_stats sum = {0, };
int cpu;
@@ -2176,7 +2176,7 @@ static int copy_tx_sa_stats(struct sk_buff *skb,
}
static int copy_rx_sa_stats(struct sk_buff *skb,
- struct macsec_rx_sa_stats __percpu *pstats)
+ struct macsec_rx_sa_stats __percpu *pstats)
{
struct macsec_rx_sa_stats sum = {0, };
int cpu;
@@ -2202,7 +2202,7 @@ static int copy_rx_sa_stats(struct sk_buff *skb,
}
static int copy_rx_sc_stats(struct sk_buff *skb,
- struct pcpu_rx_sc_stats __percpu *pstats)
+ struct pcpu_rx_sc_stats __percpu *pstats)
{
struct macsec_rx_sc_stats sum = {0, };
int cpu;
@@ -2266,7 +2266,7 @@ static int copy_rx_sc_stats(struct sk_buff *skb,
}
static int copy_tx_sc_stats(struct sk_buff *skb,
- struct pcpu_tx_sc_stats __percpu *pstats)
+ struct pcpu_tx_sc_stats __percpu *pstats)
{
struct macsec_tx_sc_stats sum = {0, };
int cpu;
@@ -2306,7 +2306,7 @@ static int copy_tx_sc_stats(struct sk_buff *skb,
}
static int copy_secy_stats(struct sk_buff *skb,
- struct pcpu_secy_stats __percpu *pstats)
+ struct pcpu_secy_stats __percpu *pstats)
{
struct macsec_dev_stats sum = {0, };
int cpu;
@@ -2812,9 +2812,6 @@ static int macsec_dev_open(struct net_device *dev)
struct net_device *real_dev = macsec->real_dev;
int err;
- if (!(real_dev->flags & IFF_UP))
- return -ENETDOWN;
-
err = dev_uc_add(real_dev, dev->dev_addr);
if (err < 0)
return err;
@@ -2962,13 +2959,11 @@ static int macsec_get_iflink(const struct net_device *dev)
return macsec_priv(dev)->real_dev->ifindex;
}
-
static int macsec_get_nest_level(struct net_device *dev)
{
return macsec_priv(dev)->nest_level;
}
-
static const struct net_device_ops macsec_netdev_ops = {
.ndo_init = macsec_dev_init,
.ndo_uninit = macsec_dev_uninit,
@@ -3308,6 +3303,9 @@ static int macsec_newlink(struct net *net, struct net_device *dev,
if (err < 0)
goto del_dev;
+ netif_stacked_transfer_operstate(real_dev, dev);
+ linkwatch_fire_event(dev);
+
macsec_generation++;
return 0;
@@ -3492,6 +3490,20 @@ static int macsec_notify(struct notifier_block *this, unsigned long event,
return NOTIFY_DONE;
switch (event) {
+ case NETDEV_DOWN:
+ case NETDEV_UP:
+ case NETDEV_CHANGE: {
+ struct macsec_dev *m, *n;
+ struct macsec_rxh_data *rxd;
+
+ rxd = macsec_data_rtnl(real_dev);
+ list_for_each_entry_safe(m, n, &rxd->secys, secys) {
+ struct net_device *dev = m->secy.netdev;
+
+ netif_stacked_transfer_operstate(real_dev, dev);
+ }
+ break;
+ }
case NETDEV_UNREGISTER: {
struct macsec_dev *m, *n;
struct macsec_rxh_data *rxd;
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index cfda146f3b3b..fc8d5f1ee1ad 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -1077,7 +1077,7 @@ static void macvlan_dev_netpoll_cleanup(struct net_device *dev)
vlan->netpoll = NULL;
- __netpoll_free_async(netpoll);
+ __netpoll_free(netpoll);
}
#endif /* CONFIG_NET_POLL_CONTROLLER */
diff --git a/drivers/net/net_failover.c b/drivers/net/net_failover.c
index 7ae1856d1f18..e964d312f4ca 100644
--- a/drivers/net/net_failover.c
+++ b/drivers/net/net_failover.c
@@ -19,7 +19,6 @@
#include <linux/ethtool.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <linux/netdevice.h>
#include <linux/netpoll.h>
#include <linux/rtnetlink.h>
#include <linux/if_vlan.h>
@@ -603,6 +602,9 @@ static int net_failover_slave_unregister(struct net_device *slave_dev,
primary_dev = rtnl_dereference(nfo_info->primary_dev);
standby_dev = rtnl_dereference(nfo_info->standby_dev);
+ if (WARN_ON_ONCE(slave_dev != primary_dev && slave_dev != standby_dev))
+ return -ENODEV;
+
vlan_vids_del_by_dev(slave_dev, failover_dev);
dev_uc_unsync(slave_dev, failover_dev);
dev_mc_unsync(slave_dev, failover_dev);
@@ -762,8 +764,10 @@ struct failover *net_failover_create(struct net_device *standby_dev)
netif_carrier_off(failover_dev);
failover = failover_register(failover_dev, &net_failover_ops);
- if (IS_ERR(failover))
+ if (IS_ERR(failover)) {
+ err = PTR_ERR(failover);
goto err_failover_register;
+ }
return failover;
diff --git a/drivers/net/netdevsim/bpf.c b/drivers/net/netdevsim/bpf.c
index 81444208b216..cb3518474f0e 100644
--- a/drivers/net/netdevsim/bpf.c
+++ b/drivers/net/netdevsim/bpf.c
@@ -86,8 +86,14 @@ nsim_bpf_verify_insn(struct bpf_verifier_env *env, int insn_idx, int prev_insn)
return 0;
}
+static int nsim_bpf_finalize(struct bpf_verifier_env *env)
+{
+ return 0;
+}
+
static const struct bpf_prog_offload_ops nsim_bpf_analyzer_ops = {
- .insn_hook = nsim_bpf_verify_insn,
+ .insn_hook = nsim_bpf_verify_insn,
+ .finalize = nsim_bpf_finalize,
};
static bool nsim_xdp_offload_active(struct netdevsim *ns)
diff --git a/drivers/net/nlmon.c b/drivers/net/nlmon.c
index 4b22955de191..dd0db7534cb3 100644
--- a/drivers/net/nlmon.c
+++ b/drivers/net/nlmon.c
@@ -6,12 +6,6 @@
#include <linux/if_arp.h>
#include <net/rtnetlink.h>
-struct pcpu_lstats {
- u64 packets;
- u64 bytes;
- struct u64_stats_sync syncp;
-};
-
static netdev_tx_t nlmon_xmit(struct sk_buff *skb, struct net_device *dev)
{
int len = skb->len;
diff --git a/drivers/net/ntb_netdev.c b/drivers/net/ntb_netdev.c
index b12023bc2cab..a5bab614ff84 100644
--- a/drivers/net/ntb_netdev.c
+++ b/drivers/net/ntb_netdev.c
@@ -71,7 +71,6 @@ static unsigned int tx_start = 10;
static unsigned int tx_stop = 5;
struct ntb_netdev {
- struct list_head list;
struct pci_dev *pdev;
struct net_device *ndev;
struct ntb_transport_qp *qp;
@@ -81,8 +80,6 @@ struct ntb_netdev {
#define NTB_TX_TIMEOUT_MS 1000
#define NTB_RXQ_SIZE 100
-static LIST_HEAD(dev_list);
-
static void ntb_netdev_event_handler(void *data, int link_is_up)
{
struct net_device *ndev = data;
@@ -236,7 +233,7 @@ static void ntb_netdev_tx_timer(struct timer_list *t)
struct net_device *ndev = dev->ndev;
if (ntb_transport_tx_free_entry(dev->qp) < tx_stop) {
- mod_timer(&dev->tx_timer, jiffies + msecs_to_jiffies(tx_time));
+ mod_timer(&dev->tx_timer, jiffies + usecs_to_jiffies(tx_time));
} else {
/* Make sure anybody stopping the queue after this sees the new
* value of ntb_transport_tx_free_entry()
@@ -452,7 +449,7 @@ static int ntb_netdev_probe(struct device *client_dev)
if (rc)
goto err1;
- list_add(&dev->list, &dev_list);
+ dev_set_drvdata(client_dev, ndev);
dev_info(&pdev->dev, "%s created\n", ndev->name);
return 0;
@@ -465,27 +462,8 @@ err:
static void ntb_netdev_remove(struct device *client_dev)
{
- struct ntb_dev *ntb;
- struct net_device *ndev;
- struct pci_dev *pdev;
- struct ntb_netdev *dev;
- bool found = false;
-
- ntb = dev_ntb(client_dev->parent);
- pdev = ntb->pdev;
-
- list_for_each_entry(dev, &dev_list, list) {
- if (dev->pdev == pdev) {
- found = true;
- break;
- }
- }
- if (!found)
- return;
-
- list_del(&dev->list);
-
- ndev = dev->ndev;
+ struct net_device *ndev = dev_get_drvdata(client_dev);
+ struct ntb_netdev *dev = netdev_priv(ndev);
unregister_netdev(ndev);
ntb_transport_free_queue(dev->qp);
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 82070792edbb..3d187cd50eb0 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -240,7 +240,7 @@ config AT803X_PHY
config BCM63XX_PHY
tristate "Broadcom 63xx SOCs internal PHY"
- depends on BCM63XX
+ depends on BCM63XX || COMPILE_TEST
select BCM_NET_PHYLIB
---help---
Currently supports the 6348 and 6358 PHYs.
diff --git a/drivers/net/phy/aquantia.c b/drivers/net/phy/aquantia.c
index 319edc9c8ec7..632472cab3bb 100644
--- a/drivers/net/phy/aquantia.c
+++ b/drivers/net/phy/aquantia.c
@@ -115,7 +115,7 @@ static struct phy_driver aquantia_driver[] = {
.phy_id = PHY_ID_AQ1202,
.phy_id_mask = 0xfffffff0,
.name = "Aquantia AQ1202",
- .features = PHY_AQUANTIA_FEATURES,
+ .features = PHY_10GBIT_FULL_FEATURES,
.flags = PHY_HAS_INTERRUPT,
.aneg_done = genphy_c45_aneg_done,
.config_aneg = aquantia_config_aneg,
@@ -127,7 +127,7 @@ static struct phy_driver aquantia_driver[] = {
.phy_id = PHY_ID_AQ2104,
.phy_id_mask = 0xfffffff0,
.name = "Aquantia AQ2104",
- .features = PHY_AQUANTIA_FEATURES,
+ .features = PHY_10GBIT_FULL_FEATURES,
.flags = PHY_HAS_INTERRUPT,
.aneg_done = genphy_c45_aneg_done,
.config_aneg = aquantia_config_aneg,
@@ -139,7 +139,7 @@ static struct phy_driver aquantia_driver[] = {
.phy_id = PHY_ID_AQR105,
.phy_id_mask = 0xfffffff0,
.name = "Aquantia AQR105",
- .features = PHY_AQUANTIA_FEATURES,
+ .features = PHY_10GBIT_FULL_FEATURES,
.flags = PHY_HAS_INTERRUPT,
.aneg_done = genphy_c45_aneg_done,
.config_aneg = aquantia_config_aneg,
@@ -151,7 +151,7 @@ static struct phy_driver aquantia_driver[] = {
.phy_id = PHY_ID_AQR106,
.phy_id_mask = 0xfffffff0,
.name = "Aquantia AQR106",
- .features = PHY_AQUANTIA_FEATURES,
+ .features = PHY_10GBIT_FULL_FEATURES,
.flags = PHY_HAS_INTERRUPT,
.aneg_done = genphy_c45_aneg_done,
.config_aneg = aquantia_config_aneg,
@@ -163,7 +163,7 @@ static struct phy_driver aquantia_driver[] = {
.phy_id = PHY_ID_AQR107,
.phy_id_mask = 0xfffffff0,
.name = "Aquantia AQR107",
- .features = PHY_AQUANTIA_FEATURES,
+ .features = PHY_10GBIT_FULL_FEATURES,
.flags = PHY_HAS_INTERRUPT,
.aneg_done = genphy_c45_aneg_done,
.config_aneg = aquantia_config_aneg,
@@ -175,7 +175,7 @@ static struct phy_driver aquantia_driver[] = {
.phy_id = PHY_ID_AQR405,
.phy_id_mask = 0xfffffff0,
.name = "Aquantia AQR405",
- .features = PHY_AQUANTIA_FEATURES,
+ .features = PHY_10GBIT_FULL_FEATURES,
.flags = PHY_HAS_INTERRUPT,
.aneg_done = genphy_c45_aneg_done,
.config_aneg = aquantia_config_aneg,
diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c
index 411cf1072bae..e74a047a846e 100644
--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -357,7 +357,7 @@ static int at803x_aneg_done(struct phy_device *phydev)
/* check if the SGMII link is OK. */
if (!(phy_read(phydev, AT803X_PSSR) & AT803X_PSSR_MR_AN_COMPLETE)) {
- pr_warn("803x_aneg_done: SGMII link is not ok\n");
+ phydev_warn(phydev, "803x_aneg_done: SGMII link is not ok\n");
aneg_done = 0;
}
/* switch back to copper page */
diff --git a/drivers/net/phy/bcm63xx.c b/drivers/net/phy/bcm63xx.c
index cf14613745c9..d95bffdec4c1 100644
--- a/drivers/net/phy/bcm63xx.c
+++ b/drivers/net/phy/bcm63xx.c
@@ -42,6 +42,9 @@ static int bcm63xx_config_init(struct phy_device *phydev)
{
int reg, err;
+ /* ASYM_PAUSE bit is marked RO in datasheet, so don't cheat */
+ phydev->supported |= SUPPORTED_Pause;
+
reg = phy_read(phydev, MII_BCM63XX_IR);
if (reg < 0)
return reg;
@@ -65,8 +68,7 @@ static struct phy_driver bcm63xx_driver[] = {
.phy_id = 0x00406000,
.phy_id_mask = 0xfffffc00,
.name = "Broadcom BCM63XX (1)",
- /* ASYM_PAUSE bit is marked RO in datasheet, so don't cheat */
- .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
+ .features = PHY_BASIC_FEATURES,
.flags = PHY_HAS_INTERRUPT | PHY_IS_INTERNAL,
.config_init = bcm63xx_config_init,
.ack_interrupt = bcm_phy_ack_intr,
@@ -75,8 +77,7 @@ static struct phy_driver bcm63xx_driver[] = {
/* same phy as above, with just a different OUI */
.phy_id = 0x002bdc00,
.phy_id_mask = 0xfffffc00,
- .name = "Broadcom BCM63XX (2)",
- .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
+ .features = PHY_BASIC_FEATURES,
.flags = PHY_HAS_INTERRUPT | PHY_IS_INTERNAL,
.config_init = bcm63xx_config_init,
.ack_interrupt = bcm_phy_ack_intr,
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
index e86ea105c802..704537010453 100644
--- a/drivers/net/phy/broadcom.c
+++ b/drivers/net/phy/broadcom.c
@@ -92,7 +92,7 @@ static int bcm54612e_config_init(struct phy_device *phydev)
return 0;
}
-static int bcm5481x_config(struct phy_device *phydev)
+static int bcm54xx_config_clock_delay(struct phy_device *phydev)
{
int rc, val;
@@ -429,7 +429,7 @@ static int bcm5481_config_aneg(struct phy_device *phydev)
ret = genphy_config_aneg(phydev);
/* Then we can set up the delay. */
- bcm5481x_config(phydev);
+ bcm54xx_config_clock_delay(phydev);
if (of_property_read_bool(np, "enet-phy-lane-swap")) {
/* Lane Swap - Undocumented register...magic! */
@@ -442,6 +442,19 @@ static int bcm5481_config_aneg(struct phy_device *phydev)
return ret;
}
+static int bcm54616s_config_aneg(struct phy_device *phydev)
+{
+ int ret;
+
+ /* Aneg firsly. */
+ ret = genphy_config_aneg(phydev);
+
+ /* Then we can set up the delay. */
+ bcm54xx_config_clock_delay(phydev);
+
+ return ret;
+}
+
static int brcm_phy_setbits(struct phy_device *phydev, int reg, int set)
{
int val;
@@ -636,6 +649,7 @@ static struct phy_driver broadcom_drivers[] = {
.features = PHY_GBIT_FEATURES,
.flags = PHY_HAS_INTERRUPT,
.config_init = bcm54xx_config_init,
+ .config_aneg = bcm54616s_config_aneg,
.ack_interrupt = bcm_phy_ack_intr,
.config_intr = bcm_phy_config_intr,
}, {
diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c
index 29aa8d772b0c..edd4d44a386d 100644
--- a/drivers/net/phy/dp83640.c
+++ b/drivers/net/phy/dp83640.c
@@ -553,16 +553,17 @@ static void enable_status_frames(struct phy_device *phydev, bool on)
mutex_unlock(&clock->extreg_lock);
if (!phydev->attached_dev) {
- pr_warn("expected to find an attached netdevice\n");
+ phydev_warn(phydev,
+ "expected to find an attached netdevice\n");
return;
}
if (on) {
if (dev_mc_add(phydev->attached_dev, status_frame_dst))
- pr_warn("failed to add mc address\n");
+ phydev_warn(phydev, "failed to add mc address\n");
} else {
if (dev_mc_del(phydev->attached_dev, status_frame_dst))
- pr_warn("failed to delete mc address\n");
+ phydev_warn(phydev, "failed to delete mc address\n");
}
}
@@ -686,9 +687,9 @@ static void recalibrate(struct dp83640_clock *clock)
* read out and correct offsets
*/
val = ext_read(master, PAGE4, PTP_STS);
- pr_info("master PTP_STS 0x%04hx\n", val);
+ phydev_info(master, "master PTP_STS 0x%04hx\n", val);
val = ext_read(master, PAGE4, PTP_ESTS);
- pr_info("master PTP_ESTS 0x%04hx\n", val);
+ phydev_info(master, "master PTP_ESTS 0x%04hx\n", val);
event_ts.ns_lo = ext_read(master, PAGE4, PTP_EDATA);
event_ts.ns_hi = ext_read(master, PAGE4, PTP_EDATA);
event_ts.sec_lo = ext_read(master, PAGE4, PTP_EDATA);
@@ -698,15 +699,16 @@ static void recalibrate(struct dp83640_clock *clock)
list_for_each(this, &clock->phylist) {
tmp = list_entry(this, struct dp83640_private, list);
val = ext_read(tmp->phydev, PAGE4, PTP_STS);
- pr_info("slave PTP_STS 0x%04hx\n", val);
+ phydev_info(tmp->phydev, "slave PTP_STS 0x%04hx\n", val);
val = ext_read(tmp->phydev, PAGE4, PTP_ESTS);
- pr_info("slave PTP_ESTS 0x%04hx\n", val);
+ phydev_info(tmp->phydev, "slave PTP_ESTS 0x%04hx\n", val);
event_ts.ns_lo = ext_read(tmp->phydev, PAGE4, PTP_EDATA);
event_ts.ns_hi = ext_read(tmp->phydev, PAGE4, PTP_EDATA);
event_ts.sec_lo = ext_read(tmp->phydev, PAGE4, PTP_EDATA);
event_ts.sec_hi = ext_read(tmp->phydev, PAGE4, PTP_EDATA);
diff = now - (s64) phy2txts(&event_ts);
- pr_info("slave offset %lld nanoseconds\n", diff);
+ phydev_info(tmp->phydev, "slave offset %lld nanoseconds\n",
+ diff);
diff += ADJTIME_FIX;
ts = ns_to_timespec64(diff);
tdr_write(0, tmp->phydev, &ts, PTP_STEP_CLK);
diff --git a/drivers/net/phy/et1011c.c b/drivers/net/phy/et1011c.c
index a9a4edfa23c8..565e49e7f76f 100644
--- a/drivers/net/phy/et1011c.c
+++ b/drivers/net/phy/et1011c.c
@@ -91,8 +91,7 @@ static struct phy_driver et1011c_driver[] = { {
.phy_id = 0x0282f014,
.name = "ET1011C",
.phy_id_mask = 0xfffffff0,
- .features = (PHY_BASIC_FEATURES | SUPPORTED_1000baseT_Full),
- .flags = PHY_POLL,
+ .features = PHY_GBIT_FEATURES,
.config_aneg = et1011c_config_aneg,
.read_status = et1011c_read_status,
} };
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index f7c69ca34056..cbec296107bd 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -265,7 +265,7 @@ static int marvell_set_polarity(struct phy_device *phydev, int polarity)
return err;
}
- return 0;
+ return val != reg;
}
static int marvell_set_downshift(struct phy_device *phydev, bool enable,
@@ -287,12 +287,15 @@ static int marvell_set_downshift(struct phy_device *phydev, bool enable,
static int marvell_config_aneg(struct phy_device *phydev)
{
+ int changed = 0;
int err;
err = marvell_set_polarity(phydev, phydev->mdix_ctrl);
if (err < 0)
return err;
+ changed = err;
+
err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL,
MII_M1111_PHY_LED_DIRECT);
if (err < 0)
@@ -302,7 +305,7 @@ static int marvell_config_aneg(struct phy_device *phydev)
if (err < 0)
return err;
- if (phydev->autoneg != AUTONEG_ENABLE) {
+ if (phydev->autoneg != AUTONEG_ENABLE || changed) {
/* A write to speed/duplex bits (that is performed by
* genphy_config_aneg() call above) must be followed by
* a software reset. Otherwise, the write has no effect.
@@ -350,42 +353,6 @@ static int m88e1101_config_aneg(struct phy_device *phydev)
return marvell_config_aneg(phydev);
}
-static int m88e1111_config_aneg(struct phy_device *phydev)
-{
- int err;
-
- /* The Marvell PHY has an errata which requires
- * that certain registers get written in order
- * to restart autonegotiation
- */
- err = genphy_soft_reset(phydev);
-
- err = marvell_set_polarity(phydev, phydev->mdix_ctrl);
- if (err < 0)
- return err;
-
- err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL,
- MII_M1111_PHY_LED_DIRECT);
- if (err < 0)
- return err;
-
- err = genphy_config_aneg(phydev);
- if (err < 0)
- return err;
-
- if (phydev->autoneg != AUTONEG_ENABLE) {
- /* A write to speed/duplex bits (that is performed by
- * genphy_config_aneg() call above) must be followed by
- * a software reset. Otherwise, the write has no effect.
- */
- err = genphy_soft_reset(phydev);
- if (err < 0)
- return err;
- }
-
- return 0;
-}
-
#ifdef CONFIG_OF_MDIO
/* Set and/or override some configuration registers based on the
* marvell,reg-init property stored in the of_node for the phydev.
@@ -479,6 +446,7 @@ static int m88e1121_config_aneg_rgmii_delays(struct phy_device *phydev)
static int m88e1121_config_aneg(struct phy_device *phydev)
{
+ int changed = 0;
int err = 0;
if (phy_interface_is_rgmii(phydev)) {
@@ -487,15 +455,26 @@ static int m88e1121_config_aneg(struct phy_device *phydev)
return err;
}
- err = genphy_soft_reset(phydev);
+ err = marvell_set_polarity(phydev, phydev->mdix_ctrl);
if (err < 0)
return err;
- err = marvell_set_polarity(phydev, phydev->mdix_ctrl);
+ changed = err;
+
+ err = genphy_config_aneg(phydev);
if (err < 0)
return err;
- return genphy_config_aneg(phydev);
+ if (phydev->autoneg != AUTONEG_ENABLE || changed) {
+ /* A software reset is used to ensure a "commit" of the
+ * changes is done.
+ */
+ err = genphy_soft_reset(phydev);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
}
static int m88e1318_config_aneg(struct phy_device *phydev)
@@ -659,7 +638,7 @@ static void marvell_config_led(struct phy_device *phydev)
err = phy_write_paged(phydev, MII_MARVELL_LED_PAGE, MII_PHY_LED_CTRL,
def_config);
if (err < 0)
- pr_warn("Fail to config marvell phy LED.\n");
+ phydev_warn(phydev, "Fail to config marvell phy LED.\n");
}
static int marvell_config_init(struct phy_device *phydev)
@@ -2067,7 +2046,7 @@ static struct phy_driver marvell_drivers[] = {
.flags = PHY_HAS_INTERRUPT,
.probe = marvell_probe,
.config_init = &m88e1111_config_init,
- .config_aneg = &m88e1111_config_aneg,
+ .config_aneg = &marvell_config_aneg,
.read_status = &marvell_read_status,
.ack_interrupt = &marvell_ack_interrupt,
.config_intr = &marvell_config_intr,
@@ -2222,7 +2201,7 @@ static struct phy_driver marvell_drivers[] = {
.phy_id = MARVELL_PHY_ID_88E1510,
.phy_id_mask = MARVELL_PHY_ID_MASK,
.name = "Marvell 88E1510",
- .features = PHY_GBIT_FEATURES | SUPPORTED_FIBRE,
+ .features = PHY_GBIT_FIBRE_FEATURES,
.flags = PHY_HAS_INTERRUPT,
.probe = &m88e1510_probe,
.config_init = &m88e1510_config_init,
diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c
index f77a2d9e7f9d..1c9d039eec63 100644
--- a/drivers/net/phy/marvell10g.c
+++ b/drivers/net/phy/marvell10g.c
@@ -337,9 +337,9 @@ static int mv3310_config_init(struct phy_device *phydev)
}
if (!ethtool_convert_link_mode_to_legacy_u32(&mask, supported))
- dev_warn(&phydev->mdio.dev,
- "PHY supports (%*pb) more modes than phylib supports, some modes not supported.\n",
- __ETHTOOL_LINK_MODE_MASK_NBITS, supported);
+ phydev_warn(phydev,
+ "PHY supports (%*pb) more modes than phylib supports, some modes not supported.\n",
+ __ETHTOOL_LINK_MODE_MASK_NBITS, supported);
phydev->supported &= mask;
phydev->advertising &= phydev->supported;
@@ -535,16 +535,7 @@ static struct phy_driver mv3310_drivers[] = {
.phy_id = 0x002b09aa,
.phy_id_mask = MARVELL_PHY_ID_MASK,
.name = "mv88x3310",
- .features = SUPPORTED_10baseT_Full |
- SUPPORTED_10baseT_Half |
- SUPPORTED_100baseT_Full |
- SUPPORTED_100baseT_Half |
- SUPPORTED_1000baseT_Full |
- SUPPORTED_Autoneg |
- SUPPORTED_TP |
- SUPPORTED_FIBRE |
- SUPPORTED_10000baseT_Full |
- SUPPORTED_Backplane,
+ .features = PHY_10GBIT_FEATURES,
.soft_reset = gen10g_no_soft_reset,
.config_init = mv3310_config_init,
.probe = mv3310_probe,
diff --git a/drivers/net/phy/mdio-bcm-unimac.c b/drivers/net/phy/mdio-bcm-unimac.c
index 8d370667fa1b..df75efa96a7d 100644
--- a/drivers/net/phy/mdio-bcm-unimac.c
+++ b/drivers/net/phy/mdio-bcm-unimac.c
@@ -16,6 +16,7 @@
#include <linux/module.h>
#include <linux/io.h>
#include <linux/delay.h>
+#include <linux/clk.h>
#include <linux/of.h>
#include <linux/of_platform.h>
@@ -45,6 +46,8 @@ struct unimac_mdio_priv {
void __iomem *base;
int (*wait_func) (void *wait_func_data);
void *wait_func_data;
+ struct clk *clk;
+ u32 clk_freq;
};
static inline u32 unimac_mdio_readl(struct unimac_mdio_priv *priv, u32 offset)
@@ -189,6 +192,35 @@ static int unimac_mdio_reset(struct mii_bus *bus)
return 0;
}
+static void unimac_mdio_clk_set(struct unimac_mdio_priv *priv)
+{
+ unsigned long rate;
+ u32 reg, div;
+
+ /* Keep the hardware default values */
+ if (!priv->clk_freq)
+ return;
+
+ if (!priv->clk)
+ rate = 250000000;
+ else
+ rate = clk_get_rate(priv->clk);
+
+ div = (rate / (2 * priv->clk_freq)) - 1;
+ if (div & ~MDIO_CLK_DIV_MASK) {
+ pr_warn("Incorrect MDIO clock frequency, ignoring\n");
+ return;
+ }
+
+ /* The MDIO clock is the reference clock (typicaly 250Mhz) divided by
+ * 2 x (MDIO_CLK_DIV + 1)
+ */
+ reg = unimac_mdio_readl(priv, MDIO_CFG);
+ reg &= ~(MDIO_CLK_DIV_MASK << MDIO_CLK_DIV_SHIFT);
+ reg |= div << MDIO_CLK_DIV_SHIFT;
+ unimac_mdio_writel(priv, reg, MDIO_CFG);
+}
+
static int unimac_mdio_probe(struct platform_device *pdev)
{
struct unimac_mdio_pdata *pdata = pdev->dev.platform_data;
@@ -217,9 +249,26 @@ static int unimac_mdio_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ priv->clk = devm_clk_get(&pdev->dev, NULL);
+ if (PTR_ERR(priv->clk) == -EPROBE_DEFER)
+ return PTR_ERR(priv->clk);
+ else
+ priv->clk = NULL;
+
+ ret = clk_prepare_enable(priv->clk);
+ if (ret)
+ return ret;
+
+ if (of_property_read_u32(np, "clock-frequency", &priv->clk_freq))
+ priv->clk_freq = 0;
+
+ unimac_mdio_clk_set(priv);
+
priv->mii_bus = mdiobus_alloc();
- if (!priv->mii_bus)
- return -ENOMEM;
+ if (!priv->mii_bus) {
+ ret = -ENOMEM;
+ goto out_clk_disable;
+ }
bus = priv->mii_bus;
bus->priv = priv;
@@ -253,6 +302,8 @@ static int unimac_mdio_probe(struct platform_device *pdev)
out_mdio_free:
mdiobus_free(bus);
+out_clk_disable:
+ clk_disable_unprepare(priv->clk);
return ret;
}
@@ -262,10 +313,37 @@ static int unimac_mdio_remove(struct platform_device *pdev)
mdiobus_unregister(priv->mii_bus);
mdiobus_free(priv->mii_bus);
+ clk_disable_unprepare(priv->clk);
+
+ return 0;
+}
+
+static int __maybe_unused unimac_mdio_suspend(struct device *d)
+{
+ struct unimac_mdio_priv *priv = dev_get_drvdata(d);
+
+ clk_disable_unprepare(priv->clk);
+
+ return 0;
+}
+
+static int __maybe_unused unimac_mdio_resume(struct device *d)
+{
+ struct unimac_mdio_priv *priv = dev_get_drvdata(d);
+ int ret;
+
+ ret = clk_prepare_enable(priv->clk);
+ if (ret)
+ return ret;
+
+ unimac_mdio_clk_set(priv);
return 0;
}
+static SIMPLE_DEV_PM_OPS(unimac_mdio_pm_ops,
+ unimac_mdio_suspend, unimac_mdio_resume);
+
static const struct of_device_id unimac_mdio_ids[] = {
{ .compatible = "brcm,genet-mdio-v5", },
{ .compatible = "brcm,genet-mdio-v4", },
@@ -281,6 +359,7 @@ static struct platform_driver unimac_mdio_driver = {
.driver = {
.name = UNIMAC_MDIO_DRV_NAME,
.of_match_table = unimac_mdio_ids,
+ .pm = &unimac_mdio_pm_ops,
},
.probe = unimac_mdio_probe,
.remove = unimac_mdio_remove,
diff --git a/drivers/net/phy/mdio-mux-bcm-iproc.c b/drivers/net/phy/mdio-mux-bcm-iproc.c
index c017486e9b86..696bdf1e4576 100644
--- a/drivers/net/phy/mdio-mux-bcm-iproc.c
+++ b/drivers/net/phy/mdio-mux-bcm-iproc.c
@@ -289,8 +289,7 @@ static int mdio_mux_iproc_remove(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP
static int mdio_mux_iproc_suspend(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct iproc_mdiomux_desc *md = platform_get_drvdata(pdev);
+ struct iproc_mdiomux_desc *md = dev_get_drvdata(dev);
clk_disable_unprepare(md->core_clk);
@@ -299,8 +298,7 @@ static int mdio_mux_iproc_suspend(struct device *dev)
static int mdio_mux_iproc_resume(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct iproc_mdiomux_desc *md = platform_get_drvdata(pdev);
+ struct iproc_mdiomux_desc *md = dev_get_drvdata(dev);
clk_prepare_enable(md->core_clk);
mdio_mux_iproc_config(md);
diff --git a/drivers/net/phy/mdio-mux-gpio.c b/drivers/net/phy/mdio-mux-gpio.c
index bc90764a8b8d..fe34576262bd 100644
--- a/drivers/net/phy/mdio-mux-gpio.c
+++ b/drivers/net/phy/mdio-mux-gpio.c
@@ -20,23 +20,21 @@
struct mdio_mux_gpio_state {
struct gpio_descs *gpios;
void *mux_handle;
- int values[];
};
static int mdio_mux_gpio_switch_fn(int current_child, int desired_child,
void *data)
{
struct mdio_mux_gpio_state *s = data;
- unsigned int n;
+ DECLARE_BITMAP(values, BITS_PER_TYPE(desired_child));
if (current_child == desired_child)
return 0;
- for (n = 0; n < s->gpios->ndescs; n++)
- s->values[n] = (desired_child >> n) & 1;
+ values[0] = desired_child;
gpiod_set_array_value_cansleep(s->gpios->ndescs, s->gpios->desc,
- s->values);
+ s->gpios->info, values);
return 0;
}
@@ -51,8 +49,7 @@ static int mdio_mux_gpio_probe(struct platform_device *pdev)
if (IS_ERR(gpios))
return PTR_ERR(gpios);
- s = devm_kzalloc(&pdev->dev, struct_size(s, values, gpios->ndescs),
- GFP_KERNEL);
+ s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL);
if (!s) {
gpiod_put_array(gpios);
return -ENOMEM;
diff --git a/drivers/net/phy/mdio-thunder.c b/drivers/net/phy/mdio-thunder.c
index 564616968cad..1546f6398831 100644
--- a/drivers/net/phy/mdio-thunder.c
+++ b/drivers/net/phy/mdio-thunder.c
@@ -73,8 +73,8 @@ static int thunder_mdiobus_pci_probe(struct pci_dev *pdev,
err = of_address_to_resource(node, 0, &r);
if (err) {
dev_err(&pdev->dev,
- "Couldn't translate address for \"%s\"\n",
- node->name);
+ "Couldn't translate address for \"%pOFn\"\n",
+ node);
break;
}
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 98f4b1f706df..2e59a8419b17 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -38,7 +38,6 @@
#include <linux/phy.h>
#include <linux/io.h>
#include <linux/uaccess.h>
-#include <linux/gpio/consumer.h>
#include <asm/irq.h>
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
index 3db06b40580d..9265dea79412 100644
--- a/drivers/net/phy/micrel.c
+++ b/drivers/net/phy/micrel.c
@@ -14,7 +14,7 @@
* option) any later version.
*
* Support : Micrel Phys:
- * Giga phys: ksz9021, ksz9031
+ * Giga phys: ksz9021, ksz9031, ksz9131
* 100/10 Phys : ksz8001, ksz8721, ksz8737, ksz8041
* ksz8021, ksz8031, ksz8051,
* ksz8081, ksz8091,
@@ -609,6 +609,116 @@ err_force_master:
return result;
}
+#define KSZ9131_SKEW_5BIT_MAX 2400
+#define KSZ9131_SKEW_4BIT_MAX 800
+#define KSZ9131_OFFSET 700
+#define KSZ9131_STEP 100
+
+static int ksz9131_of_load_skew_values(struct phy_device *phydev,
+ struct device_node *of_node,
+ u16 reg, size_t field_sz,
+ char *field[], u8 numfields)
+{
+ int val[4] = {-(1 + KSZ9131_OFFSET), -(2 + KSZ9131_OFFSET),
+ -(3 + KSZ9131_OFFSET), -(4 + KSZ9131_OFFSET)};
+ int skewval, skewmax = 0;
+ int matches = 0;
+ u16 maxval;
+ u16 newval;
+ u16 mask;
+ int i;
+
+ /* psec properties in dts should mean x pico seconds */
+ if (field_sz == 5)
+ skewmax = KSZ9131_SKEW_5BIT_MAX;
+ else
+ skewmax = KSZ9131_SKEW_4BIT_MAX;
+
+ for (i = 0; i < numfields; i++)
+ if (!of_property_read_s32(of_node, field[i], &skewval)) {
+ if (skewval < -KSZ9131_OFFSET)
+ skewval = -KSZ9131_OFFSET;
+ else if (skewval > skewmax)
+ skewval = skewmax;
+
+ val[i] = skewval + KSZ9131_OFFSET;
+ matches++;
+ }
+
+ if (!matches)
+ return 0;
+
+ if (matches < numfields)
+ newval = ksz9031_extended_read(phydev, OP_DATA, 2, reg);
+ else
+ newval = 0;
+
+ maxval = (field_sz == 4) ? 0xf : 0x1f;
+ for (i = 0; i < numfields; i++)
+ if (val[i] != -(i + 1 + KSZ9131_OFFSET)) {
+ mask = 0xffff;
+ mask ^= maxval << (field_sz * i);
+ newval = (newval & mask) |
+ (((val[i] / KSZ9131_STEP) & maxval)
+ << (field_sz * i));
+ }
+
+ return ksz9031_extended_write(phydev, OP_DATA, 2, reg, newval);
+}
+
+static int ksz9131_config_init(struct phy_device *phydev)
+{
+ const struct device *dev = &phydev->mdio.dev;
+ struct device_node *of_node = dev->of_node;
+ char *clk_skews[2] = {"rxc-skew-psec", "txc-skew-psec"};
+ char *rx_data_skews[4] = {
+ "rxd0-skew-psec", "rxd1-skew-psec",
+ "rxd2-skew-psec", "rxd3-skew-psec"
+ };
+ char *tx_data_skews[4] = {
+ "txd0-skew-psec", "txd1-skew-psec",
+ "txd2-skew-psec", "txd3-skew-psec"
+ };
+ char *control_skews[2] = {"txen-skew-psec", "rxdv-skew-psec"};
+ const struct device *dev_walker;
+ int ret;
+
+ dev_walker = &phydev->mdio.dev;
+ do {
+ of_node = dev_walker->of_node;
+ dev_walker = dev_walker->parent;
+ } while (!of_node && dev_walker);
+
+ if (!of_node)
+ return 0;
+
+ ret = ksz9131_of_load_skew_values(phydev, of_node,
+ MII_KSZ9031RN_CLK_PAD_SKEW, 5,
+ clk_skews, 2);
+ if (ret < 0)
+ return ret;
+
+ ret = ksz9131_of_load_skew_values(phydev, of_node,
+ MII_KSZ9031RN_CONTROL_PAD_SKEW, 4,
+ control_skews, 2);
+ if (ret < 0)
+ return ret;
+
+ ret = ksz9131_of_load_skew_values(phydev, of_node,
+ MII_KSZ9031RN_RX_DATA_PAD_SKEW, 4,
+ rx_data_skews, 4);
+ if (ret < 0)
+ return ret;
+
+ ret = ksz9131_of_load_skew_values(phydev, of_node,
+ MII_KSZ9031RN_TX_DATA_PAD_SKEW, 4,
+ tx_data_skews, 4);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
#define KSZ8873MLL_GLOBAL_CONTROL_4 0x06
#define KSZ8873MLL_GLOBAL_CONTROL_4_DUPLEX BIT(6)
#define KSZ8873MLL_GLOBAL_CONTROL_4_SPEED BIT(4)
@@ -975,6 +1085,23 @@ static struct phy_driver ksphy_driver[] = {
.suspend = genphy_suspend,
.resume = kszphy_resume,
}, {
+ .phy_id = PHY_ID_KSZ9131,
+ .phy_id_mask = MICREL_PHY_ID_MASK,
+ .name = "Microchip KSZ9131 Gigabit PHY",
+ .features = PHY_GBIT_FEATURES,
+ .flags = PHY_HAS_INTERRUPT,
+ .driver_data = &ksz9021_type,
+ .probe = kszphy_probe,
+ .config_init = ksz9131_config_init,
+ .read_status = ksz9031_read_status,
+ .ack_interrupt = kszphy_ack_interrupt,
+ .config_intr = kszphy_config_intr,
+ .get_sset_count = kszphy_get_sset_count,
+ .get_strings = kszphy_get_strings,
+ .get_stats = kszphy_get_stats,
+ .suspend = genphy_suspend,
+ .resume = kszphy_resume,
+}, {
.phy_id = PHY_ID_KSZ8873MLL,
.phy_id_mask = MICREL_PHY_ID_MASK,
.name = "Micrel KSZ8873MLL Switch",
@@ -1022,6 +1149,7 @@ MODULE_LICENSE("GPL");
static struct mdio_device_id __maybe_unused micrel_tbl[] = {
{ PHY_ID_KSZ9021, 0x000ffffe },
{ PHY_ID_KSZ9031, MICREL_PHY_ID_MASK },
+ { PHY_ID_KSZ9131, MICREL_PHY_ID_MASK },
{ PHY_ID_KSZ8001, 0x00fffffc },
{ PHY_ID_KS8737, MICREL_PHY_ID_MASK },
{ PHY_ID_KSZ8021, 0x00ffffff },
diff --git a/drivers/net/phy/microchip.c b/drivers/net/phy/microchip.c
index 2d67937866a3..04b12e34da58 100644
--- a/drivers/net/phy/microchip.c
+++ b/drivers/net/phy/microchip.c
@@ -88,7 +88,7 @@ static int lan88xx_TR_reg_set(struct phy_device *phydev, u16 regaddr,
/* Save current page */
save_page = phy_save_page(phydev);
if (save_page < 0) {
- pr_warn("Failed to get current page\n");
+ phydev_warn(phydev, "Failed to get current page\n");
goto err;
}
@@ -98,14 +98,14 @@ static int lan88xx_TR_reg_set(struct phy_device *phydev, u16 regaddr,
ret = __phy_write(phydev, LAN88XX_EXT_PAGE_TR_LOW_DATA,
(data & 0xFFFF));
if (ret < 0) {
- pr_warn("Failed to write TR low data\n");
+ phydev_warn(phydev, "Failed to write TR low data\n");
goto err;
}
ret = __phy_write(phydev, LAN88XX_EXT_PAGE_TR_HIGH_DATA,
(data & 0x00FF0000) >> 16);
if (ret < 0) {
- pr_warn("Failed to write TR high data\n");
+ phydev_warn(phydev, "Failed to write TR high data\n");
goto err;
}
@@ -115,14 +115,15 @@ static int lan88xx_TR_reg_set(struct phy_device *phydev, u16 regaddr,
ret = __phy_write(phydev, LAN88XX_EXT_PAGE_TR_CR, buf);
if (ret < 0) {
- pr_warn("Failed to write data in reg\n");
+ phydev_warn(phydev, "Failed to write data in reg\n");
goto err;
}
usleep_range(1000, 2000);/* Wait for Data to be written */
val = __phy_read(phydev, LAN88XX_EXT_PAGE_TR_CR);
if (!(val & 0x8000))
- pr_warn("TR Register[0x%X] configuration failed\n", regaddr);
+ phydev_warn(phydev, "TR Register[0x%X] configuration failed\n",
+ regaddr);
err:
return phy_restore_page(phydev, save_page, ret);
}
@@ -137,7 +138,7 @@ static void lan88xx_config_TR_regs(struct phy_device *phydev)
*/
err = lan88xx_TR_reg_set(phydev, 0x0F82, 0x12B00A);
if (err < 0)
- pr_warn("Failed to Set Register[0x0F82]\n");
+ phydev_warn(phydev, "Failed to Set Register[0x0F82]\n");
/* Get access to Channel b'10, Node b'1101, Register 0x06.
* Write 24-bit value 0xD2C46F to register. Setting SSTrKf1000Slv,
@@ -145,7 +146,7 @@ static void lan88xx_config_TR_regs(struct phy_device *phydev)
*/
err = lan88xx_TR_reg_set(phydev, 0x168C, 0xD2C46F);
if (err < 0)
- pr_warn("Failed to Set Register[0x168C]\n");
+ phydev_warn(phydev, "Failed to Set Register[0x168C]\n");
/* Get access to Channel b'10, Node b'1111, Register 0x11.
* Write 24-bit value 0x620 to register. Setting rem_upd_done_thresh
@@ -153,7 +154,7 @@ static void lan88xx_config_TR_regs(struct phy_device *phydev)
*/
err = lan88xx_TR_reg_set(phydev, 0x17A2, 0x620);
if (err < 0)
- pr_warn("Failed to Set Register[0x17A2]\n");
+ phydev_warn(phydev, "Failed to Set Register[0x17A2]\n");
/* Get access to Channel b'10, Node b'1101, Register 0x10.
* Write 24-bit value 0xEEFFDD to register. Setting
@@ -162,7 +163,7 @@ static void lan88xx_config_TR_regs(struct phy_device *phydev)
*/
err = lan88xx_TR_reg_set(phydev, 0x16A0, 0xEEFFDD);
if (err < 0)
- pr_warn("Failed to Set Register[0x16A0]\n");
+ phydev_warn(phydev, "Failed to Set Register[0x16A0]\n");
/* Get access to Channel b'10, Node b'1101, Register 0x13.
* Write 24-bit value 0x071448 to register. Setting
@@ -170,7 +171,7 @@ static void lan88xx_config_TR_regs(struct phy_device *phydev)
*/
err = lan88xx_TR_reg_set(phydev, 0x16A6, 0x071448);
if (err < 0)
- pr_warn("Failed to Set Register[0x16A6]\n");
+ phydev_warn(phydev, "Failed to Set Register[0x16A6]\n");
/* Get access to Channel b'10, Node b'1101, Register 0x12.
* Write 24-bit value 0x13132F to register. Setting
@@ -178,7 +179,7 @@ static void lan88xx_config_TR_regs(struct phy_device *phydev)
*/
err = lan88xx_TR_reg_set(phydev, 0x16A4, 0x13132F);
if (err < 0)
- pr_warn("Failed to Set Register[0x16A4]\n");
+ phydev_warn(phydev, "Failed to Set Register[0x16A4]\n");
/* Get access to Channel b'10, Node b'1101, Register 0x14.
* Write 24-bit value 0x0 to register. Setting eee_3level_delay,
@@ -186,7 +187,7 @@ static void lan88xx_config_TR_regs(struct phy_device *phydev)
*/
err = lan88xx_TR_reg_set(phydev, 0x16A8, 0x0);
if (err < 0)
- pr_warn("Failed to Set Register[0x16A8]\n");
+ phydev_warn(phydev, "Failed to Set Register[0x16A8]\n");
/* Get access to Channel b'01, Node b'1111, Register 0x34.
* Write 24-bit value 0x91B06C to register. Setting
@@ -195,7 +196,7 @@ static void lan88xx_config_TR_regs(struct phy_device *phydev)
*/
err = lan88xx_TR_reg_set(phydev, 0x0FE8, 0x91B06C);
if (err < 0)
- pr_warn("Failed to Set Register[0x0FE8]\n");
+ phydev_warn(phydev, "Failed to Set Register[0x0FE8]\n");
/* Get access to Channel b'01, Node b'1111, Register 0x3E.
* Write 24-bit value 0xC0A028 to register. Setting
@@ -204,7 +205,7 @@ static void lan88xx_config_TR_regs(struct phy_device *phydev)
*/
err = lan88xx_TR_reg_set(phydev, 0x0FFC, 0xC0A028);
if (err < 0)
- pr_warn("Failed to Set Register[0x0FFC]\n");
+ phydev_warn(phydev, "Failed to Set Register[0x0FFC]\n");
/* Get access to Channel b'01, Node b'1111, Register 0x35.
* Write 24-bit value 0x041600 to register. Setting
@@ -213,14 +214,14 @@ static void lan88xx_config_TR_regs(struct phy_device *phydev)
*/
err = lan88xx_TR_reg_set(phydev, 0x0FEA, 0x041600);
if (err < 0)
- pr_warn("Failed to Set Register[0x0FEA]\n");
+ phydev_warn(phydev, "Failed to Set Register[0x0FEA]\n");
/* Get access to Channel b'10, Node b'1101, Register 0x03.
* Write 24-bit value 0x000004 to register. Setting TrFreeze bits.
*/
err = lan88xx_TR_reg_set(phydev, 0x1686, 0x000004);
if (err < 0)
- pr_warn("Failed to Set Register[0x1686]\n");
+ phydev_warn(phydev, "Failed to Set Register[0x1686]\n");
}
static int lan88xx_probe(struct phy_device *phydev)
diff --git a/drivers/net/phy/microchip_t1.c b/drivers/net/phy/microchip_t1.c
index b1917dd1978a..c600a8509d60 100644
--- a/drivers/net/phy/microchip_t1.c
+++ b/drivers/net/phy/microchip_t1.c
@@ -46,7 +46,7 @@ static struct phy_driver microchip_t1_phy_driver[] = {
.phy_id_mask = 0xfffffff0,
.name = "Microchip LAN87xx T1",
- .features = SUPPORTED_100baseT_Full,
+ .features = PHY_BASIC_T1_FEATURES,
.flags = PHY_HAS_INTERRUPT,
.config_init = genphy_config_init,
diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c
index 84ca9ff40ae0..a2e59f4f6f01 100644
--- a/drivers/net/phy/mscc.c
+++ b/drivers/net/phy/mscc.c
@@ -6,6 +6,8 @@
* Copyright (c) 2016 Microsemi Corporation
*/
+#include <linux/firmware.h>
+#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mdio.h>
@@ -32,6 +34,15 @@ enum rgmii_rx_clock_delay {
#define DISABLE_HP_AUTO_MDIX_MASK 0x0080
#define DISABLE_PAIR_SWAP_CORR_MASK 0x0020
#define DISABLE_POLARITY_CORR_MASK 0x0010
+#define PARALLEL_DET_IGNORE_ADVERTISED 0x0008
+
+#define MSCC_PHY_EXT_CNTL_STATUS 22
+#define SMI_BROADCAST_WR_EN 0x0001
+
+#define MSCC_PHY_ERR_RX_CNT 19
+#define MSCC_PHY_ERR_FALSE_CARRIER_CNT 20
+#define MSCC_PHY_ERR_LINK_DISCONNECT_CNT 21
+#define ERR_CNT_MASK GENMASK(7, 0)
#define MSCC_PHY_EXT_PHY_CNTL_1 23
#define MAC_IF_SELECTION_MASK 0x1800
@@ -39,7 +50,22 @@ enum rgmii_rx_clock_delay {
#define MAC_IF_SELECTION_RMII 1
#define MAC_IF_SELECTION_RGMII 2
#define MAC_IF_SELECTION_POS 11
+#define VSC8584_MAC_IF_SELECTION_MASK 0x1000
+#define VSC8584_MAC_IF_SELECTION_SGMII 0
+#define VSC8584_MAC_IF_SELECTION_1000BASEX 1
+#define VSC8584_MAC_IF_SELECTION_POS 12
#define FAR_END_LOOPBACK_MODE_MASK 0x0008
+#define MEDIA_OP_MODE_MASK 0x0700
+#define MEDIA_OP_MODE_COPPER 0
+#define MEDIA_OP_MODE_SERDES 1
+#define MEDIA_OP_MODE_1000BASEX 2
+#define MEDIA_OP_MODE_100BASEFX 3
+#define MEDIA_OP_MODE_AMS_COPPER_SERDES 5
+#define MEDIA_OP_MODE_AMS_COPPER_1000BASEX 6
+#define MEDIA_OP_MODE_AMS_COPPER_100BASEFX 7
+#define MEDIA_OP_MODE_POS 8
+
+#define MSCC_PHY_EXT_PHY_CNTL_2 24
#define MII_VSC85XX_INT_MASK 25
#define MII_VSC85XX_INT_MASK_MASK 0xa000
@@ -54,27 +80,48 @@ enum rgmii_rx_clock_delay {
#define HP_AUTO_MDIX_X_OVER_IND_MASK 0x2000
#define MSCC_PHY_LED_MODE_SEL 29
-#define LED_1_MODE_SEL_MASK 0x00F0
-#define LED_0_MODE_SEL_MASK 0x000F
-#define LED_1_MODE_SEL_POS 4
+#define LED_MODE_SEL_POS(x) ((x) * 4)
+#define LED_MODE_SEL_MASK(x) (GENMASK(3, 0) << LED_MODE_SEL_POS(x))
+#define LED_MODE_SEL(x, mode) (((mode) << LED_MODE_SEL_POS(x)) & LED_MODE_SEL_MASK(x))
#define MSCC_EXT_PAGE_ACCESS 31
#define MSCC_PHY_PAGE_STANDARD 0x0000 /* Standard registers */
#define MSCC_PHY_PAGE_EXTENDED 0x0001 /* Extended registers */
#define MSCC_PHY_PAGE_EXTENDED_2 0x0002 /* Extended reg - page 2 */
+#define MSCC_PHY_PAGE_EXTENDED_3 0x0003 /* Extended reg - page 3 */
+#define MSCC_PHY_PAGE_EXTENDED_4 0x0004 /* Extended reg - page 4 */
+/* Extended reg - GPIO; this is a bank of registers that are shared for all PHYs
+ * in the same package.
+ */
+#define MSCC_PHY_PAGE_EXTENDED_GPIO 0x0010 /* Extended reg - GPIO */
+#define MSCC_PHY_PAGE_TEST 0x2a30 /* Test reg */
+#define MSCC_PHY_PAGE_TR 0x52b5 /* Token ring registers */
/* Extended Page 1 Registers */
+#define MSCC_PHY_CU_MEDIA_CRC_VALID_CNT 18
+#define VALID_CRC_CNT_CRC_MASK GENMASK(13, 0)
+
#define MSCC_PHY_EXT_MODE_CNTL 19
#define FORCE_MDI_CROSSOVER_MASK 0x000C
#define FORCE_MDI_CROSSOVER_MDIX 0x000C
#define FORCE_MDI_CROSSOVER_MDI 0x0008
#define MSCC_PHY_ACTIPHY_CNTL 20
+#define PHY_ADDR_REVERSED 0x0200
#define DOWNSHIFT_CNTL_MASK 0x001C
#define DOWNSHIFT_EN 0x0010
#define DOWNSHIFT_CNTL_POS 2
+#define MSCC_PHY_EXT_PHY_CNTL_4 23
+#define PHY_CNTL_4_ADDR_POS 11
+
+#define MSCC_PHY_VERIPHY_CNTL_2 25
+
+#define MSCC_PHY_VERIPHY_CNTL_3 26
+
/* Extended Page 2 Registers */
+#define MSCC_PHY_CU_PMD_TX_CNTL 16
+
#define MSCC_PHY_RGMII_CNTL 20
#define RGMII_RX_CLK_DELAY_MASK 0x0070
#define RGMII_RX_CLK_DELAY_POS 4
@@ -90,11 +137,90 @@ enum rgmii_rx_clock_delay {
#define SECURE_ON_ENABLE 0x8000
#define SECURE_ON_PASSWD_LEN_4 0x4000
+/* Extended Page 3 Registers */
+#define MSCC_PHY_SERDES_TX_VALID_CNT 21
+#define MSCC_PHY_SERDES_TX_CRC_ERR_CNT 22
+#define MSCC_PHY_SERDES_RX_VALID_CNT 28
+#define MSCC_PHY_SERDES_RX_CRC_ERR_CNT 29
+
+/* Extended page GPIO Registers */
+#define MSCC_DW8051_CNTL_STATUS 0
+#define MICRO_NSOFT_RESET 0x8000
+#define RUN_FROM_INT_ROM 0x4000
+#define AUTOINC_ADDR 0x2000
+#define PATCH_RAM_CLK 0x1000
+#define MICRO_PATCH_EN 0x0080
+#define DW8051_CLK_EN 0x0010
+#define MICRO_CLK_EN 0x0008
+#define MICRO_CLK_DIVIDE(x) ((x) >> 1)
+#define MSCC_DW8051_VLD_MASK 0xf1ff
+
+/* x Address in range 1-4 */
+#define MSCC_TRAP_ROM_ADDR(x) ((x) * 2 + 1)
+#define MSCC_PATCH_RAM_ADDR(x) (((x) + 1) * 2)
+#define MSCC_INT_MEM_ADDR 11
+
+#define MSCC_INT_MEM_CNTL 12
+#define READ_SFR 0x6000
+#define READ_PRAM 0x4000
+#define READ_ROM 0x2000
+#define READ_RAM 0x0000
+#define INT_MEM_WRITE_EN 0x1000
+#define EN_PATCH_RAM_TRAP_ADDR(x) (0x0100 << ((x) - 1))
+#define INT_MEM_DATA_M 0x00ff
+#define INT_MEM_DATA(x) (INT_MEM_DATA_M & (x))
+
+#define MSCC_PHY_PROC_CMD 18
+#define PROC_CMD_NCOMPLETED 0x8000
+#define PROC_CMD_FAILED 0x4000
+#define PROC_CMD_SGMII_PORT(x) ((x) << 8)
+#define PROC_CMD_FIBER_PORT(x) (0x0100 << (x) % 4)
+#define PROC_CMD_QSGMII_PORT 0x0c00
+#define PROC_CMD_RST_CONF_PORT 0x0080
+#define PROC_CMD_RECONF_PORT 0x0000
+#define PROC_CMD_READ_MOD_WRITE_PORT 0x0040
+#define PROC_CMD_WRITE 0x0040
+#define PROC_CMD_READ 0x0000
+#define PROC_CMD_FIBER_DISABLE 0x0020
+#define PROC_CMD_FIBER_100BASE_FX 0x0010
+#define PROC_CMD_FIBER_1000BASE_X 0x0000
+#define PROC_CMD_SGMII_MAC 0x0030
+#define PROC_CMD_QSGMII_MAC 0x0020
+#define PROC_CMD_NO_MAC_CONF 0x0000
+#define PROC_CMD_1588_DEFAULT_INIT 0x0010
+#define PROC_CMD_NOP 0x000f
+#define PROC_CMD_PHY_INIT 0x000a
+#define PROC_CMD_CRC16 0x0008
+#define PROC_CMD_FIBER_MEDIA_CONF 0x0001
+#define PROC_CMD_MCB_ACCESS_MAC_CONF 0x0000
+#define PROC_CMD_NCOMPLETED_TIMEOUT_MS 500
+
+#define MSCC_PHY_MAC_CFG_FASTLINK 19
+#define MAC_CFG_MASK 0xc000
+#define MAC_CFG_SGMII 0x0000
+#define MAC_CFG_QSGMII 0x4000
+
+/* Test page Registers */
+#define MSCC_PHY_TEST_PAGE_5 5
+#define MSCC_PHY_TEST_PAGE_8 8
+#define MSCC_PHY_TEST_PAGE_9 9
+#define MSCC_PHY_TEST_PAGE_20 20
+#define MSCC_PHY_TEST_PAGE_24 24
+
+/* Token ring page Registers */
+#define MSCC_PHY_TR_CNTL 16
+#define TR_WRITE 0x8000
+#define TR_ADDR(x) (0x7fff & (x))
+#define MSCC_PHY_TR_LSB 17
+#define MSCC_PHY_TR_MSB 18
+
/* Microsemi PHY ID's */
#define PHY_ID_VSC8530 0x00070560
#define PHY_ID_VSC8531 0x00070570
#define PHY_ID_VSC8540 0x00070760
#define PHY_ID_VSC8541 0x00070770
+#define PHY_ID_VSC8574 0x000704a0
+#define PHY_ID_VSC8584 0x000707c0
#define MSCC_VDDMAC_1500 1500
#define MSCC_VDDMAC_1800 1800
@@ -103,16 +229,160 @@ enum rgmii_rx_clock_delay {
#define DOWNSHIFT_COUNT_MAX 5
+#define MAX_LEDS 4
+
+#define VSC8584_SUPP_LED_MODES (BIT(VSC8531_LINK_ACTIVITY) | \
+ BIT(VSC8531_LINK_1000_ACTIVITY) | \
+ BIT(VSC8531_LINK_100_ACTIVITY) | \
+ BIT(VSC8531_LINK_10_ACTIVITY) | \
+ BIT(VSC8531_LINK_100_1000_ACTIVITY) | \
+ BIT(VSC8531_LINK_10_1000_ACTIVITY) | \
+ BIT(VSC8531_LINK_10_100_ACTIVITY) | \
+ BIT(VSC8584_LINK_100FX_1000X_ACTIVITY) | \
+ BIT(VSC8531_DUPLEX_COLLISION) | \
+ BIT(VSC8531_COLLISION) | \
+ BIT(VSC8531_ACTIVITY) | \
+ BIT(VSC8584_100FX_1000X_ACTIVITY) | \
+ BIT(VSC8531_AUTONEG_FAULT) | \
+ BIT(VSC8531_SERIAL_MODE) | \
+ BIT(VSC8531_FORCE_LED_OFF) | \
+ BIT(VSC8531_FORCE_LED_ON))
+
+#define VSC85XX_SUPP_LED_MODES (BIT(VSC8531_LINK_ACTIVITY) | \
+ BIT(VSC8531_LINK_1000_ACTIVITY) | \
+ BIT(VSC8531_LINK_100_ACTIVITY) | \
+ BIT(VSC8531_LINK_10_ACTIVITY) | \
+ BIT(VSC8531_LINK_100_1000_ACTIVITY) | \
+ BIT(VSC8531_LINK_10_1000_ACTIVITY) | \
+ BIT(VSC8531_LINK_10_100_ACTIVITY) | \
+ BIT(VSC8531_DUPLEX_COLLISION) | \
+ BIT(VSC8531_COLLISION) | \
+ BIT(VSC8531_ACTIVITY) | \
+ BIT(VSC8531_AUTONEG_FAULT) | \
+ BIT(VSC8531_SERIAL_MODE) | \
+ BIT(VSC8531_FORCE_LED_OFF) | \
+ BIT(VSC8531_FORCE_LED_ON))
+
+#define MSCC_VSC8584_REVB_INT8051_FW "mscc_vsc8584_revb_int8051_fb48.bin"
+#define MSCC_VSC8584_REVB_INT8051_FW_START_ADDR 0xe800
+#define MSCC_VSC8584_REVB_INT8051_FW_CRC 0xfb48
+
+#define MSCC_VSC8574_REVB_INT8051_FW "mscc_vsc8574_revb_int8051_29e8.bin"
+#define MSCC_VSC8574_REVB_INT8051_FW_START_ADDR 0x4000
+#define MSCC_VSC8574_REVB_INT8051_FW_CRC 0x29e8
+
+#define VSC8584_REVB 0x0001
+#define MSCC_DEV_REV_MASK GENMASK(3, 0)
+
+struct reg_val {
+ u16 reg;
+ u32 val;
+};
+
+struct vsc85xx_hw_stat {
+ const char *string;
+ u8 reg;
+ u16 page;
+ u16 mask;
+};
+
+static const struct vsc85xx_hw_stat vsc85xx_hw_stats[] = {
+ {
+ .string = "phy_receive_errors",
+ .reg = MSCC_PHY_ERR_RX_CNT,
+ .page = MSCC_PHY_PAGE_STANDARD,
+ .mask = ERR_CNT_MASK,
+ }, {
+ .string = "phy_false_carrier",
+ .reg = MSCC_PHY_ERR_FALSE_CARRIER_CNT,
+ .page = MSCC_PHY_PAGE_STANDARD,
+ .mask = ERR_CNT_MASK,
+ }, {
+ .string = "phy_cu_media_link_disconnect",
+ .reg = MSCC_PHY_ERR_LINK_DISCONNECT_CNT,
+ .page = MSCC_PHY_PAGE_STANDARD,
+ .mask = ERR_CNT_MASK,
+ }, {
+ .string = "phy_cu_media_crc_good_count",
+ .reg = MSCC_PHY_CU_MEDIA_CRC_VALID_CNT,
+ .page = MSCC_PHY_PAGE_EXTENDED,
+ .mask = VALID_CRC_CNT_CRC_MASK,
+ }, {
+ .string = "phy_cu_media_crc_error_count",
+ .reg = MSCC_PHY_EXT_PHY_CNTL_4,
+ .page = MSCC_PHY_PAGE_EXTENDED,
+ .mask = ERR_CNT_MASK,
+ },
+};
+
+static const struct vsc85xx_hw_stat vsc8584_hw_stats[] = {
+ {
+ .string = "phy_receive_errors",
+ .reg = MSCC_PHY_ERR_RX_CNT,
+ .page = MSCC_PHY_PAGE_STANDARD,
+ .mask = ERR_CNT_MASK,
+ }, {
+ .string = "phy_false_carrier",
+ .reg = MSCC_PHY_ERR_FALSE_CARRIER_CNT,
+ .page = MSCC_PHY_PAGE_STANDARD,
+ .mask = ERR_CNT_MASK,
+ }, {
+ .string = "phy_cu_media_link_disconnect",
+ .reg = MSCC_PHY_ERR_LINK_DISCONNECT_CNT,
+ .page = MSCC_PHY_PAGE_STANDARD,
+ .mask = ERR_CNT_MASK,
+ }, {
+ .string = "phy_cu_media_crc_good_count",
+ .reg = MSCC_PHY_CU_MEDIA_CRC_VALID_CNT,
+ .page = MSCC_PHY_PAGE_EXTENDED,
+ .mask = VALID_CRC_CNT_CRC_MASK,
+ }, {
+ .string = "phy_cu_media_crc_error_count",
+ .reg = MSCC_PHY_EXT_PHY_CNTL_4,
+ .page = MSCC_PHY_PAGE_EXTENDED,
+ .mask = ERR_CNT_MASK,
+ }, {
+ .string = "phy_serdes_tx_good_pkt_count",
+ .reg = MSCC_PHY_SERDES_TX_VALID_CNT,
+ .page = MSCC_PHY_PAGE_EXTENDED_3,
+ .mask = VALID_CRC_CNT_CRC_MASK,
+ }, {
+ .string = "phy_serdes_tx_bad_crc_count",
+ .reg = MSCC_PHY_SERDES_TX_CRC_ERR_CNT,
+ .page = MSCC_PHY_PAGE_EXTENDED_3,
+ .mask = ERR_CNT_MASK,
+ }, {
+ .string = "phy_serdes_rx_good_pkt_count",
+ .reg = MSCC_PHY_SERDES_RX_VALID_CNT,
+ .page = MSCC_PHY_PAGE_EXTENDED_3,
+ .mask = VALID_CRC_CNT_CRC_MASK,
+ }, {
+ .string = "phy_serdes_rx_bad_crc_count",
+ .reg = MSCC_PHY_SERDES_RX_CRC_ERR_CNT,
+ .page = MSCC_PHY_PAGE_EXTENDED_3,
+ .mask = ERR_CNT_MASK,
+ },
+};
+
struct vsc8531_private {
int rate_magic;
- u8 led_0_mode;
- u8 led_1_mode;
+ u16 supp_led_modes;
+ u32 leds_mode[MAX_LEDS];
+ u8 nleds;
+ const struct vsc85xx_hw_stat *hw_stats;
+ u64 *stats;
+ int nstats;
+ bool pkg_init;
+ /* For multiple port PHYs; the MDIO address of the base PHY in the
+ * package.
+ */
+ unsigned int base_addr;
};
#ifdef CONFIG_OF_MDIO
struct vsc8531_edge_rate_table {
- u16 vddmac;
- u8 slowdown[8];
+ u32 vddmac;
+ u32 slowdown[8];
};
static const struct vsc8531_edge_rate_table edge_table[] = {
@@ -123,12 +393,66 @@ static const struct vsc8531_edge_rate_table edge_table[] = {
};
#endif /* CONFIG_OF_MDIO */
-static int vsc85xx_phy_page_set(struct phy_device *phydev, u16 page)
+static int vsc85xx_phy_read_page(struct phy_device *phydev)
{
- int rc;
+ return __phy_read(phydev, MSCC_EXT_PAGE_ACCESS);
+}
- rc = phy_write(phydev, MSCC_EXT_PAGE_ACCESS, page);
- return rc;
+static int vsc85xx_phy_write_page(struct phy_device *phydev, int page)
+{
+ return __phy_write(phydev, MSCC_EXT_PAGE_ACCESS, page);
+}
+
+static int vsc85xx_get_sset_count(struct phy_device *phydev)
+{
+ struct vsc8531_private *priv = phydev->priv;
+
+ if (!priv)
+ return 0;
+
+ return priv->nstats;
+}
+
+static void vsc85xx_get_strings(struct phy_device *phydev, u8 *data)
+{
+ struct vsc8531_private *priv = phydev->priv;
+ int i;
+
+ if (!priv)
+ return;
+
+ for (i = 0; i < priv->nstats; i++)
+ strlcpy(data + i * ETH_GSTRING_LEN, priv->hw_stats[i].string,
+ ETH_GSTRING_LEN);
+}
+
+static u64 vsc85xx_get_stat(struct phy_device *phydev, int i)
+{
+ struct vsc8531_private *priv = phydev->priv;
+ int val;
+
+ val = phy_read_paged(phydev, priv->hw_stats[i].page,
+ priv->hw_stats[i].reg);
+ if (val < 0)
+ return U64_MAX;
+
+ val = val & priv->hw_stats[i].mask;
+ priv->stats[i] += val;
+
+ return priv->stats[i];
+}
+
+static void vsc85xx_get_stats(struct phy_device *phydev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct vsc8531_private *priv = phydev->priv;
+ int i;
+
+ if (!priv)
+ return;
+
+ for (i = 0; i < priv->nstats; i++)
+ data[i] = vsc85xx_get_stat(phydev, i);
}
static int vsc85xx_led_cntl_set(struct phy_device *phydev,
@@ -140,14 +464,8 @@ static int vsc85xx_led_cntl_set(struct phy_device *phydev,
mutex_lock(&phydev->lock);
reg_val = phy_read(phydev, MSCC_PHY_LED_MODE_SEL);
- if (led_num) {
- reg_val &= ~LED_1_MODE_SEL_MASK;
- reg_val |= (((u16)mode << LED_1_MODE_SEL_POS) &
- LED_1_MODE_SEL_MASK);
- } else {
- reg_val &= ~LED_0_MODE_SEL_MASK;
- reg_val |= ((u16)mode & LED_0_MODE_SEL_MASK);
- }
+ reg_val &= ~LED_MODE_SEL_MASK(led_num);
+ reg_val |= LED_MODE_SEL(led_num, (u16)mode);
rc = phy_write(phydev, MSCC_PHY_LED_MODE_SEL, reg_val);
mutex_unlock(&phydev->lock);
@@ -173,7 +491,7 @@ static int vsc85xx_mdix_set(struct phy_device *phydev, u8 mdix)
u16 reg_val;
reg_val = phy_read(phydev, MSCC_PHY_BYPASS_CONTROL);
- if ((mdix == ETH_TP_MDI) || (mdix == ETH_TP_MDI_X)) {
+ if (mdix == ETH_TP_MDI || mdix == ETH_TP_MDI_X) {
reg_val |= (DISABLE_PAIR_SWAP_CORR_MASK |
DISABLE_POLARITY_CORR_MASK |
DISABLE_HP_AUTO_MDIX_MASK);
@@ -183,25 +501,20 @@ static int vsc85xx_mdix_set(struct phy_device *phydev, u8 mdix)
DISABLE_HP_AUTO_MDIX_MASK);
}
rc = phy_write(phydev, MSCC_PHY_BYPASS_CONTROL, reg_val);
- if (rc != 0)
+ if (rc)
return rc;
- rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED);
- if (rc != 0)
- return rc;
+ reg_val = 0;
- reg_val = phy_read(phydev, MSCC_PHY_EXT_MODE_CNTL);
- reg_val &= ~(FORCE_MDI_CROSSOVER_MASK);
if (mdix == ETH_TP_MDI)
- reg_val |= FORCE_MDI_CROSSOVER_MDI;
+ reg_val = FORCE_MDI_CROSSOVER_MDI;
else if (mdix == ETH_TP_MDI_X)
- reg_val |= FORCE_MDI_CROSSOVER_MDIX;
- rc = phy_write(phydev, MSCC_PHY_EXT_MODE_CNTL, reg_val);
- if (rc != 0)
- return rc;
+ reg_val = FORCE_MDI_CROSSOVER_MDIX;
- rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
- if (rc != 0)
+ rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_EXTENDED,
+ MSCC_PHY_EXT_MODE_CNTL, FORCE_MDI_CROSSOVER_MASK,
+ reg_val);
+ if (rc < 0)
return rc;
return genphy_restart_aneg(phydev);
@@ -209,30 +522,24 @@ static int vsc85xx_mdix_set(struct phy_device *phydev, u8 mdix)
static int vsc85xx_downshift_get(struct phy_device *phydev, u8 *count)
{
- int rc;
- u16 reg_val;
+ int reg_val;
- rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED);
- if (rc != 0)
- goto out;
+ reg_val = phy_read_paged(phydev, MSCC_PHY_PAGE_EXTENDED,
+ MSCC_PHY_ACTIPHY_CNTL);
+ if (reg_val < 0)
+ return reg_val;
- reg_val = phy_read(phydev, MSCC_PHY_ACTIPHY_CNTL);
reg_val &= DOWNSHIFT_CNTL_MASK;
if (!(reg_val & DOWNSHIFT_EN))
*count = DOWNSHIFT_DEV_DISABLE;
else
*count = ((reg_val & ~DOWNSHIFT_EN) >> DOWNSHIFT_CNTL_POS) + 2;
- rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
-out:
- return rc;
+ return 0;
}
static int vsc85xx_downshift_set(struct phy_device *phydev, u8 count)
{
- int rc;
- u16 reg_val;
-
if (count == DOWNSHIFT_DEV_DEFAULT_COUNT) {
/* Default downshift count 3 (i.e. Bit3:2 = 0b01) */
count = ((1 << DOWNSHIFT_CNTL_POS) | DOWNSHIFT_EN);
@@ -244,21 +551,9 @@ static int vsc85xx_downshift_set(struct phy_device *phydev, u8 count)
count = (((count - 2) << DOWNSHIFT_CNTL_POS) | DOWNSHIFT_EN);
}
- rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED);
- if (rc != 0)
- goto out;
-
- reg_val = phy_read(phydev, MSCC_PHY_ACTIPHY_CNTL);
- reg_val &= ~(DOWNSHIFT_CNTL_MASK);
- reg_val |= count;
- rc = phy_write(phydev, MSCC_PHY_ACTIPHY_CNTL, reg_val);
- if (rc != 0)
- goto out;
-
- rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
-
-out:
- return rc;
+ return phy_modify_paged(phydev, MSCC_PHY_PAGE_EXTENDED,
+ MSCC_PHY_ACTIPHY_CNTL, DOWNSHIFT_CNTL_MASK,
+ count);
}
static int vsc85xx_wol_set(struct phy_device *phydev,
@@ -272,46 +567,48 @@ static int vsc85xx_wol_set(struct phy_device *phydev,
u8 *mac_addr = phydev->attached_dev->dev_addr;
mutex_lock(&phydev->lock);
- rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2);
- if (rc != 0)
+ rc = phy_select_page(phydev, MSCC_PHY_PAGE_EXTENDED_2);
+ if (rc < 0) {
+ rc = phy_restore_page(phydev, rc, rc);
goto out_unlock;
+ }
if (wol->wolopts & WAKE_MAGIC) {
/* Store the device address for the magic packet */
for (i = 0; i < ARRAY_SIZE(pwd); i++)
pwd[i] = mac_addr[5 - (i * 2 + 1)] << 8 |
mac_addr[5 - i * 2];
- phy_write(phydev, MSCC_PHY_WOL_LOWER_MAC_ADDR, pwd[0]);
- phy_write(phydev, MSCC_PHY_WOL_MID_MAC_ADDR, pwd[1]);
- phy_write(phydev, MSCC_PHY_WOL_UPPER_MAC_ADDR, pwd[2]);
+ __phy_write(phydev, MSCC_PHY_WOL_LOWER_MAC_ADDR, pwd[0]);
+ __phy_write(phydev, MSCC_PHY_WOL_MID_MAC_ADDR, pwd[1]);
+ __phy_write(phydev, MSCC_PHY_WOL_UPPER_MAC_ADDR, pwd[2]);
} else {
- phy_write(phydev, MSCC_PHY_WOL_LOWER_MAC_ADDR, 0);
- phy_write(phydev, MSCC_PHY_WOL_MID_MAC_ADDR, 0);
- phy_write(phydev, MSCC_PHY_WOL_UPPER_MAC_ADDR, 0);
+ __phy_write(phydev, MSCC_PHY_WOL_LOWER_MAC_ADDR, 0);
+ __phy_write(phydev, MSCC_PHY_WOL_MID_MAC_ADDR, 0);
+ __phy_write(phydev, MSCC_PHY_WOL_UPPER_MAC_ADDR, 0);
}
if (wol_conf->wolopts & WAKE_MAGICSECURE) {
for (i = 0; i < ARRAY_SIZE(pwd); i++)
pwd[i] = wol_conf->sopass[5 - (i * 2 + 1)] << 8 |
wol_conf->sopass[5 - i * 2];
- phy_write(phydev, MSCC_PHY_WOL_LOWER_PASSWD, pwd[0]);
- phy_write(phydev, MSCC_PHY_WOL_MID_PASSWD, pwd[1]);
- phy_write(phydev, MSCC_PHY_WOL_UPPER_PASSWD, pwd[2]);
+ __phy_write(phydev, MSCC_PHY_WOL_LOWER_PASSWD, pwd[0]);
+ __phy_write(phydev, MSCC_PHY_WOL_MID_PASSWD, pwd[1]);
+ __phy_write(phydev, MSCC_PHY_WOL_UPPER_PASSWD, pwd[2]);
} else {
- phy_write(phydev, MSCC_PHY_WOL_LOWER_PASSWD, 0);
- phy_write(phydev, MSCC_PHY_WOL_MID_PASSWD, 0);
- phy_write(phydev, MSCC_PHY_WOL_UPPER_PASSWD, 0);
+ __phy_write(phydev, MSCC_PHY_WOL_LOWER_PASSWD, 0);
+ __phy_write(phydev, MSCC_PHY_WOL_MID_PASSWD, 0);
+ __phy_write(phydev, MSCC_PHY_WOL_UPPER_PASSWD, 0);
}
- reg_val = phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL);
+ reg_val = __phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL);
if (wol_conf->wolopts & WAKE_MAGICSECURE)
reg_val |= SECURE_ON_ENABLE;
else
reg_val &= ~SECURE_ON_ENABLE;
- phy_write(phydev, MSCC_PHY_WOL_MAC_CONTROL, reg_val);
+ __phy_write(phydev, MSCC_PHY_WOL_MAC_CONTROL, reg_val);
- rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
- if (rc != 0)
+ rc = phy_restore_page(phydev, rc, rc > 0 ? 0 : rc);
+ if (rc < 0)
goto out_unlock;
if (wol->wolopts & WAKE_MAGIC) {
@@ -319,14 +616,14 @@ static int vsc85xx_wol_set(struct phy_device *phydev,
reg_val = phy_read(phydev, MII_VSC85XX_INT_MASK);
reg_val |= MII_VSC85XX_INT_MASK_WOL;
rc = phy_write(phydev, MII_VSC85XX_INT_MASK, reg_val);
- if (rc != 0)
+ if (rc)
goto out_unlock;
} else {
/* Disable the WOL interrupt */
reg_val = phy_read(phydev, MII_VSC85XX_INT_MASK);
reg_val &= (~MII_VSC85XX_INT_MASK_WOL);
rc = phy_write(phydev, MII_VSC85XX_INT_MASK, reg_val);
- if (rc != 0)
+ if (rc)
goto out_unlock;
}
/* Clear WOL iterrupt status */
@@ -348,17 +645,17 @@ static void vsc85xx_wol_get(struct phy_device *phydev,
struct ethtool_wolinfo *wol_conf = wol;
mutex_lock(&phydev->lock);
- rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2);
- if (rc != 0)
+ rc = phy_select_page(phydev, MSCC_PHY_PAGE_EXTENDED_2);
+ if (rc < 0)
goto out_unlock;
- reg_val = phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL);
+ reg_val = __phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL);
if (reg_val & SECURE_ON_ENABLE)
wol_conf->wolopts |= WAKE_MAGICSECURE;
if (wol_conf->wolopts & WAKE_MAGICSECURE) {
- pwd[0] = phy_read(phydev, MSCC_PHY_WOL_LOWER_PASSWD);
- pwd[1] = phy_read(phydev, MSCC_PHY_WOL_MID_PASSWD);
- pwd[2] = phy_read(phydev, MSCC_PHY_WOL_UPPER_PASSWD);
+ pwd[0] = __phy_read(phydev, MSCC_PHY_WOL_LOWER_PASSWD);
+ pwd[1] = __phy_read(phydev, MSCC_PHY_WOL_MID_PASSWD);
+ pwd[2] = __phy_read(phydev, MSCC_PHY_WOL_UPPER_PASSWD);
for (i = 0; i < ARRAY_SIZE(pwd); i++) {
wol_conf->sopass[5 - i * 2] = pwd[i] & 0x00ff;
wol_conf->sopass[5 - (i * 2 + 1)] = (pwd[i] & 0xff00)
@@ -366,18 +663,16 @@ static void vsc85xx_wol_get(struct phy_device *phydev,
}
}
- rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
-
out_unlock:
+ phy_restore_page(phydev, rc, rc > 0 ? 0 : rc);
mutex_unlock(&phydev->lock);
}
#ifdef CONFIG_OF_MDIO
static int vsc85xx_edge_rate_magic_get(struct phy_device *phydev)
{
- u8 sd;
- u16 vdd;
- int rc, i, j;
+ u32 vdd, sd;
+ int i, j;
struct device *dev = &phydev->mdio.dev;
struct device_node *of_node = dev->of_node;
u8 sd_array_size = ARRAY_SIZE(edge_table[0].slowdown);
@@ -385,12 +680,10 @@ static int vsc85xx_edge_rate_magic_get(struct phy_device *phydev)
if (!of_node)
return -ENODEV;
- rc = of_property_read_u16(of_node, "vsc8531,vddmac", &vdd);
- if (rc != 0)
+ if (of_property_read_u32(of_node, "vsc8531,vddmac", &vdd))
vdd = MSCC_VDDMAC_3300;
- rc = of_property_read_u8(of_node, "vsc8531,edge-slowdown", &sd);
- if (rc != 0)
+ if (of_property_read_u32(of_node, "vsc8531,edge-slowdown", &sd))
sd = 0;
for (i = 0; i < ARRAY_SIZE(edge_table); i++)
@@ -404,19 +697,20 @@ static int vsc85xx_edge_rate_magic_get(struct phy_device *phydev)
static int vsc85xx_dt_led_mode_get(struct phy_device *phydev,
char *led,
- u8 default_mode)
+ u32 default_mode)
{
+ struct vsc8531_private *priv = phydev->priv;
struct device *dev = &phydev->mdio.dev;
struct device_node *of_node = dev->of_node;
- u8 led_mode;
+ u32 led_mode;
int err;
if (!of_node)
return -ENODEV;
led_mode = default_mode;
- err = of_property_read_u8(of_node, led, &led_mode);
- if (!err && (led_mode > 15 || led_mode == 7 || led_mode == 11)) {
+ err = of_property_read_u32(of_node, led, &led_mode);
+ if (!err && !(BIT(led_mode) & priv->supp_led_modes)) {
phydev_err(phydev, "DT %s invalid\n", led);
return -EINVAL;
}
@@ -438,24 +732,36 @@ static int vsc85xx_dt_led_mode_get(struct phy_device *phydev,
}
#endif /* CONFIG_OF_MDIO */
+static int vsc85xx_dt_led_modes_get(struct phy_device *phydev,
+ u32 *default_mode)
+{
+ struct vsc8531_private *priv = phydev->priv;
+ char led_dt_prop[28];
+ int i, ret;
+
+ for (i = 0; i < priv->nleds; i++) {
+ ret = sprintf(led_dt_prop, "vsc8531,led-%d-mode", i);
+ if (ret < 0)
+ return ret;
+
+ ret = vsc85xx_dt_led_mode_get(phydev, led_dt_prop,
+ default_mode[i]);
+ if (ret < 0)
+ return ret;
+ priv->leds_mode[i] = ret;
+ }
+
+ return 0;
+}
+
static int vsc85xx_edge_rate_cntl_set(struct phy_device *phydev, u8 edge_rate)
{
int rc;
- u16 reg_val;
mutex_lock(&phydev->lock);
- rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2);
- if (rc != 0)
- goto out_unlock;
- reg_val = phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL);
- reg_val &= ~(EDGE_RATE_CNTL_MASK);
- reg_val |= (edge_rate << EDGE_RATE_CNTL_POS);
- rc = phy_write(phydev, MSCC_PHY_WOL_MAC_CONTROL, reg_val);
- if (rc != 0)
- goto out_unlock;
- rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
-
-out_unlock:
+ rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_EXTENDED_2,
+ MSCC_PHY_WOL_MAC_CONTROL, EDGE_RATE_CNTL_MASK,
+ edge_rate << EDGE_RATE_CNTL_POS);
mutex_unlock(&phydev->lock);
return rc;
@@ -486,7 +792,7 @@ static int vsc85xx_mac_if_set(struct phy_device *phydev,
goto out_unlock;
}
rc = phy_write(phydev, MSCC_PHY_EXT_PHY_CNTL_1, reg_val);
- if (rc != 0)
+ if (rc)
goto out_unlock;
rc = genphy_soft_reset(phydev);
@@ -504,17 +810,17 @@ static int vsc85xx_default_config(struct phy_device *phydev)
phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
mutex_lock(&phydev->lock);
- rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2);
- if (rc != 0)
+ rc = phy_select_page(phydev, MSCC_PHY_PAGE_EXTENDED_2);
+ if (rc < 0)
goto out_unlock;
reg_val = phy_read(phydev, MSCC_PHY_RGMII_CNTL);
reg_val &= ~(RGMII_RX_CLK_DELAY_MASK);
reg_val |= (RGMII_RX_CLK_DELAY_1_1_NS << RGMII_RX_CLK_DELAY_POS);
phy_write(phydev, MSCC_PHY_RGMII_CNTL, reg_val);
- rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
out_unlock:
+ rc = phy_restore_page(phydev, rc, rc > 0 ? 0 : rc);
mutex_unlock(&phydev->lock);
return rc;
@@ -543,9 +849,812 @@ static int vsc85xx_set_tunable(struct phy_device *phydev,
}
}
+/* mdiobus lock should be locked when using this function */
+static void vsc85xx_tr_write(struct phy_device *phydev, u16 addr, u32 val)
+{
+ __phy_write(phydev, MSCC_PHY_TR_MSB, val >> 16);
+ __phy_write(phydev, MSCC_PHY_TR_LSB, val & GENMASK(15, 0));
+ __phy_write(phydev, MSCC_PHY_TR_CNTL, TR_WRITE | TR_ADDR(addr));
+}
+
+static int vsc85xx_eee_init_seq_set(struct phy_device *phydev)
+{
+ const struct reg_val init_eee[] = {
+ {0x0f82, 0x0012b00a},
+ {0x1686, 0x00000004},
+ {0x168c, 0x00d2c46f},
+ {0x17a2, 0x00000620},
+ {0x16a0, 0x00eeffdd},
+ {0x16a6, 0x00071448},
+ {0x16a4, 0x0013132f},
+ {0x16a8, 0x00000000},
+ {0x0ffc, 0x00c0a028},
+ {0x0fe8, 0x0091b06c},
+ {0x0fea, 0x00041600},
+ {0x0f80, 0x00000af4},
+ {0x0fec, 0x00901809},
+ {0x0fee, 0x0000a6a1},
+ {0x0ffe, 0x00b01007},
+ {0x16b0, 0x00eeff00},
+ {0x16b2, 0x00007000},
+ {0x16b4, 0x00000814},
+ };
+ unsigned int i;
+ int oldpage;
+
+ mutex_lock(&phydev->lock);
+ oldpage = phy_select_page(phydev, MSCC_PHY_PAGE_TR);
+ if (oldpage < 0)
+ goto out_unlock;
+
+ for (i = 0; i < ARRAY_SIZE(init_eee); i++)
+ vsc85xx_tr_write(phydev, init_eee[i].reg, init_eee[i].val);
+
+out_unlock:
+ oldpage = phy_restore_page(phydev, oldpage, oldpage);
+ mutex_unlock(&phydev->lock);
+
+ return oldpage;
+}
+
+/* phydev->bus->mdio_lock should be locked when using this function */
+static int phy_base_write(struct phy_device *phydev, u32 regnum, u16 val)
+{
+ struct vsc8531_private *priv = phydev->priv;
+
+ if (unlikely(!mutex_is_locked(&phydev->mdio.bus->mdio_lock))) {
+ dev_err(&phydev->mdio.dev, "MDIO bus lock not held!\n");
+ dump_stack();
+ }
+
+ return __mdiobus_write(phydev->mdio.bus, priv->base_addr, regnum, val);
+}
+
+/* phydev->bus->mdio_lock should be locked when using this function */
+static int phy_base_read(struct phy_device *phydev, u32 regnum)
+{
+ struct vsc8531_private *priv = phydev->priv;
+
+ if (unlikely(!mutex_is_locked(&phydev->mdio.bus->mdio_lock))) {
+ dev_err(&phydev->mdio.dev, "MDIO bus lock not held!\n");
+ dump_stack();
+ }
+
+ return __mdiobus_read(phydev->mdio.bus, priv->base_addr, regnum);
+}
+
+/* bus->mdio_lock should be locked when using this function */
+static void vsc8584_csr_write(struct phy_device *phydev, u16 addr, u32 val)
+{
+ phy_base_write(phydev, MSCC_PHY_TR_MSB, val >> 16);
+ phy_base_write(phydev, MSCC_PHY_TR_LSB, val & GENMASK(15, 0));
+ phy_base_write(phydev, MSCC_PHY_TR_CNTL, TR_WRITE | TR_ADDR(addr));
+}
+
+/* bus->mdio_lock should be locked when using this function */
+static int vsc8584_cmd(struct phy_device *phydev, u16 val)
+{
+ unsigned long deadline;
+ u16 reg_val;
+
+ phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
+ MSCC_PHY_PAGE_EXTENDED_GPIO);
+
+ phy_base_write(phydev, MSCC_PHY_PROC_CMD, PROC_CMD_NCOMPLETED | val);
+
+ deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS);
+ do {
+ reg_val = phy_base_read(phydev, MSCC_PHY_PROC_CMD);
+ } while (time_before(jiffies, deadline) &&
+ (reg_val & PROC_CMD_NCOMPLETED) &&
+ !(reg_val & PROC_CMD_FAILED));
+
+ phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
+
+ if (reg_val & PROC_CMD_FAILED)
+ return -EIO;
+
+ if (reg_val & PROC_CMD_NCOMPLETED)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+/* bus->mdio_lock should be locked when using this function */
+static int vsc8584_micro_deassert_reset(struct phy_device *phydev,
+ bool patch_en)
+{
+ u32 enable, release;
+
+ phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
+ MSCC_PHY_PAGE_EXTENDED_GPIO);
+
+ enable = RUN_FROM_INT_ROM | MICRO_CLK_EN | DW8051_CLK_EN;
+ release = MICRO_NSOFT_RESET | RUN_FROM_INT_ROM | DW8051_CLK_EN |
+ MICRO_CLK_EN;
+
+ if (patch_en) {
+ enable |= MICRO_PATCH_EN;
+ release |= MICRO_PATCH_EN;
+
+ /* Clear all patches */
+ phy_base_write(phydev, MSCC_INT_MEM_CNTL, READ_RAM);
+ }
+
+ /* Enable 8051 Micro clock; CLEAR/SET patch present; disable PRAM clock
+ * override and addr. auto-incr; operate at 125 MHz
+ */
+ phy_base_write(phydev, MSCC_DW8051_CNTL_STATUS, enable);
+ /* Release 8051 Micro SW reset */
+ phy_base_write(phydev, MSCC_DW8051_CNTL_STATUS, release);
+
+ phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
+
+ return 0;
+}
+
+/* bus->mdio_lock should be locked when using this function */
+static int vsc8584_micro_assert_reset(struct phy_device *phydev)
+{
+ int ret;
+ u16 reg;
+
+ ret = vsc8584_cmd(phydev, PROC_CMD_NOP);
+ if (ret)
+ return ret;
+
+ phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
+ MSCC_PHY_PAGE_EXTENDED_GPIO);
+
+ reg = phy_base_read(phydev, MSCC_INT_MEM_CNTL);
+ reg &= ~EN_PATCH_RAM_TRAP_ADDR(4);
+ phy_base_write(phydev, MSCC_INT_MEM_CNTL, reg);
+
+ phy_base_write(phydev, MSCC_TRAP_ROM_ADDR(4), 0x005b);
+ phy_base_write(phydev, MSCC_PATCH_RAM_ADDR(4), 0x005b);
+
+ reg = phy_base_read(phydev, MSCC_INT_MEM_CNTL);
+ reg |= EN_PATCH_RAM_TRAP_ADDR(4);
+ phy_base_write(phydev, MSCC_INT_MEM_CNTL, reg);
+
+ phy_base_write(phydev, MSCC_PHY_PROC_CMD, PROC_CMD_NOP);
+
+ reg = phy_base_read(phydev, MSCC_DW8051_CNTL_STATUS);
+ reg &= ~MICRO_NSOFT_RESET;
+ phy_base_write(phydev, MSCC_DW8051_CNTL_STATUS, reg);
+
+ phy_base_write(phydev, MSCC_PHY_PROC_CMD, PROC_CMD_MCB_ACCESS_MAC_CONF |
+ PROC_CMD_SGMII_PORT(0) | PROC_CMD_NO_MAC_CONF |
+ PROC_CMD_READ);
+
+ reg = phy_base_read(phydev, MSCC_INT_MEM_CNTL);
+ reg &= ~EN_PATCH_RAM_TRAP_ADDR(4);
+ phy_base_write(phydev, MSCC_INT_MEM_CNTL, reg);
+
+ phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
+
+ return 0;
+}
+
+/* bus->mdio_lock should be locked when using this function */
+static int vsc8584_get_fw_crc(struct phy_device *phydev, u16 start, u16 size,
+ u16 *crc)
+{
+ int ret;
+
+ phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED);
+
+ phy_base_write(phydev, MSCC_PHY_VERIPHY_CNTL_2, start);
+ phy_base_write(phydev, MSCC_PHY_VERIPHY_CNTL_3, size);
+
+ /* Start Micro command */
+ ret = vsc8584_cmd(phydev, PROC_CMD_CRC16);
+ if (ret)
+ goto out;
+
+ phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED);
+
+ *crc = phy_base_read(phydev, MSCC_PHY_VERIPHY_CNTL_2);
+
+out:
+ phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
+
+ return ret;
+}
+
+/* bus->mdio_lock should be locked when using this function */
+static int vsc8584_patch_fw(struct phy_device *phydev,
+ const struct firmware *fw)
+{
+ int i, ret;
+
+ ret = vsc8584_micro_assert_reset(phydev);
+ if (ret) {
+ dev_err(&phydev->mdio.dev,
+ "%s: failed to assert reset of micro\n", __func__);
+ return ret;
+ }
+
+ phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
+ MSCC_PHY_PAGE_EXTENDED_GPIO);
+
+ /* Hold 8051 Micro in SW Reset, Enable auto incr address and patch clock
+ * Disable the 8051 Micro clock
+ */
+ phy_base_write(phydev, MSCC_DW8051_CNTL_STATUS, RUN_FROM_INT_ROM |
+ AUTOINC_ADDR | PATCH_RAM_CLK | MICRO_CLK_EN |
+ MICRO_CLK_DIVIDE(2));
+ phy_base_write(phydev, MSCC_INT_MEM_CNTL, READ_PRAM | INT_MEM_WRITE_EN |
+ INT_MEM_DATA(2));
+ phy_base_write(phydev, MSCC_INT_MEM_ADDR, 0x0000);
+
+ for (i = 0; i < fw->size; i++)
+ phy_base_write(phydev, MSCC_INT_MEM_CNTL, READ_PRAM |
+ INT_MEM_WRITE_EN | fw->data[i]);
+
+ /* Clear internal memory access */
+ phy_base_write(phydev, MSCC_INT_MEM_CNTL, READ_RAM);
+
+ phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
+
+ return 0;
+}
+
+/* bus->mdio_lock should be locked when using this function */
+static bool vsc8574_is_serdes_init(struct phy_device *phydev)
+{
+ u16 reg;
+ bool ret;
+
+ phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
+ MSCC_PHY_PAGE_EXTENDED_GPIO);
+
+ reg = phy_base_read(phydev, MSCC_TRAP_ROM_ADDR(1));
+ if (reg != 0x3eb7) {
+ ret = false;
+ goto out;
+ }
+
+ reg = phy_base_read(phydev, MSCC_PATCH_RAM_ADDR(1));
+ if (reg != 0x4012) {
+ ret = false;
+ goto out;
+ }
+
+ reg = phy_base_read(phydev, MSCC_INT_MEM_CNTL);
+ if (reg != EN_PATCH_RAM_TRAP_ADDR(1)) {
+ ret = false;
+ goto out;
+ }
+
+ reg = phy_base_read(phydev, MSCC_DW8051_CNTL_STATUS);
+ if ((MICRO_NSOFT_RESET | RUN_FROM_INT_ROM | DW8051_CLK_EN |
+ MICRO_CLK_EN) != (reg & MSCC_DW8051_VLD_MASK)) {
+ ret = false;
+ goto out;
+ }
+
+ ret = true;
+out:
+ phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
+
+ return ret;
+}
+
+/* bus->mdio_lock should be locked when using this function */
+static int vsc8574_config_pre_init(struct phy_device *phydev)
+{
+ const struct reg_val pre_init1[] = {
+ {0x0fae, 0x000401bd},
+ {0x0fac, 0x000f000f},
+ {0x17a0, 0x00a0f147},
+ {0x0fe4, 0x00052f54},
+ {0x1792, 0x0027303d},
+ {0x07fe, 0x00000704},
+ {0x0fe0, 0x00060150},
+ {0x0f82, 0x0012b00a},
+ {0x0f80, 0x00000d74},
+ {0x02e0, 0x00000012},
+ {0x03a2, 0x00050208},
+ {0x03b2, 0x00009186},
+ {0x0fb0, 0x000e3700},
+ {0x1688, 0x00049f81},
+ {0x0fd2, 0x0000ffff},
+ {0x168a, 0x00039fa2},
+ {0x1690, 0x0020640b},
+ {0x0258, 0x00002220},
+ {0x025a, 0x00002a20},
+ {0x025c, 0x00003060},
+ {0x025e, 0x00003fa0},
+ {0x03a6, 0x0000e0f0},
+ {0x0f92, 0x00001489},
+ {0x16a2, 0x00007000},
+ {0x16a6, 0x00071448},
+ {0x16a0, 0x00eeffdd},
+ {0x0fe8, 0x0091b06c},
+ {0x0fea, 0x00041600},
+ {0x16b0, 0x00eeff00},
+ {0x16b2, 0x00007000},
+ {0x16b4, 0x00000814},
+ {0x0f90, 0x00688980},
+ {0x03a4, 0x0000d8f0},
+ {0x0fc0, 0x00000400},
+ {0x07fa, 0x0050100f},
+ {0x0796, 0x00000003},
+ {0x07f8, 0x00c3ff98},
+ {0x0fa4, 0x0018292a},
+ {0x168c, 0x00d2c46f},
+ {0x17a2, 0x00000620},
+ {0x16a4, 0x0013132f},
+ {0x16a8, 0x00000000},
+ {0x0ffc, 0x00c0a028},
+ {0x0fec, 0x00901c09},
+ {0x0fee, 0x0004a6a1},
+ {0x0ffe, 0x00b01807},
+ };
+ const struct reg_val pre_init2[] = {
+ {0x0486, 0x0008a518},
+ {0x0488, 0x006dc696},
+ {0x048a, 0x00000912},
+ {0x048e, 0x00000db6},
+ {0x049c, 0x00596596},
+ {0x049e, 0x00000514},
+ {0x04a2, 0x00410280},
+ {0x04a4, 0x00000000},
+ {0x04a6, 0x00000000},
+ {0x04a8, 0x00000000},
+ {0x04aa, 0x00000000},
+ {0x04ae, 0x007df7dd},
+ {0x04b0, 0x006d95d4},
+ {0x04b2, 0x00492410},
+ };
+ struct device *dev = &phydev->mdio.dev;
+ const struct firmware *fw;
+ unsigned int i;
+ u16 crc, reg;
+ bool serdes_init;
+ int ret;
+
+ phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
+
+ /* all writes below are broadcasted to all PHYs in the same package */
+ reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS);
+ reg |= SMI_BROADCAST_WR_EN;
+ phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg);
+
+ phy_base_write(phydev, MII_VSC85XX_INT_MASK, 0);
+
+ /* The below register writes are tweaking analog and electrical
+ * configuration that were determined through characterization by PHY
+ * engineers. These don't mean anything more than "these are the best
+ * values".
+ */
+ phy_base_write(phydev, MSCC_PHY_EXT_PHY_CNTL_2, 0x0040);
+
+ phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST);
+
+ phy_base_write(phydev, MSCC_PHY_TEST_PAGE_20, 0x4320);
+ phy_base_write(phydev, MSCC_PHY_TEST_PAGE_24, 0x0c00);
+ phy_base_write(phydev, MSCC_PHY_TEST_PAGE_9, 0x18ca);
+ phy_base_write(phydev, MSCC_PHY_TEST_PAGE_5, 0x1b20);
+
+ reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8);
+ reg |= 0x8000;
+ phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg);
+
+ phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR);
+
+ for (i = 0; i < ARRAY_SIZE(pre_init1); i++)
+ vsc8584_csr_write(phydev, pre_init1[i].reg, pre_init1[i].val);
+
+ phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED_2);
+
+ phy_base_write(phydev, MSCC_PHY_CU_PMD_TX_CNTL, 0x028e);
+
+ phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR);
+
+ for (i = 0; i < ARRAY_SIZE(pre_init2); i++)
+ vsc8584_csr_write(phydev, pre_init2[i].reg, pre_init2[i].val);
+
+ phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST);
+
+ reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8);
+ reg &= ~0x8000;
+ phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg);
+
+ phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
+
+ /* end of write broadcasting */
+ reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS);
+ reg &= ~SMI_BROADCAST_WR_EN;
+ phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg);
+
+ ret = request_firmware(&fw, MSCC_VSC8574_REVB_INT8051_FW, dev);
+ if (ret) {
+ dev_err(dev, "failed to load firmware %s, ret: %d\n",
+ MSCC_VSC8574_REVB_INT8051_FW, ret);
+ return ret;
+ }
+
+ /* Add one byte to size for the one added by the patch_fw function */
+ ret = vsc8584_get_fw_crc(phydev,
+ MSCC_VSC8574_REVB_INT8051_FW_START_ADDR,
+ fw->size + 1, &crc);
+ if (ret)
+ goto out;
+
+ if (crc == MSCC_VSC8574_REVB_INT8051_FW_CRC) {
+ serdes_init = vsc8574_is_serdes_init(phydev);
+
+ if (!serdes_init) {
+ ret = vsc8584_micro_assert_reset(phydev);
+ if (ret) {
+ dev_err(dev,
+ "%s: failed to assert reset of micro\n",
+ __func__);
+ goto out;
+ }
+ }
+ } else {
+ dev_dbg(dev, "FW CRC is not the expected one, patching FW\n");
+
+ serdes_init = false;
+
+ if (vsc8584_patch_fw(phydev, fw))
+ dev_warn(dev,
+ "failed to patch FW, expect non-optimal device\n");
+ }
+
+ if (!serdes_init) {
+ phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
+ MSCC_PHY_PAGE_EXTENDED_GPIO);
+
+ phy_base_write(phydev, MSCC_TRAP_ROM_ADDR(1), 0x3eb7);
+ phy_base_write(phydev, MSCC_PATCH_RAM_ADDR(1), 0x4012);
+ phy_base_write(phydev, MSCC_INT_MEM_CNTL,
+ EN_PATCH_RAM_TRAP_ADDR(1));
+
+ vsc8584_micro_deassert_reset(phydev, false);
+
+ /* Add one byte to size for the one added by the patch_fw
+ * function
+ */
+ ret = vsc8584_get_fw_crc(phydev,
+ MSCC_VSC8574_REVB_INT8051_FW_START_ADDR,
+ fw->size + 1, &crc);
+ if (ret)
+ goto out;
+
+ if (crc != MSCC_VSC8574_REVB_INT8051_FW_CRC)
+ dev_warn(dev,
+ "FW CRC after patching is not the expected one, expect non-optimal device\n");
+ }
+
+ phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
+ MSCC_PHY_PAGE_EXTENDED_GPIO);
+
+ ret = vsc8584_cmd(phydev, PROC_CMD_1588_DEFAULT_INIT |
+ PROC_CMD_PHY_INIT);
+
+out:
+ phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
+
+ release_firmware(fw);
+
+ return ret;
+}
+
+/* bus->mdio_lock should be locked when using this function */
+static int vsc8584_config_pre_init(struct phy_device *phydev)
+{
+ const struct reg_val pre_init1[] = {
+ {0x07fa, 0x0050100f},
+ {0x1688, 0x00049f81},
+ {0x0f90, 0x00688980},
+ {0x03a4, 0x0000d8f0},
+ {0x0fc0, 0x00000400},
+ {0x0f82, 0x0012b002},
+ {0x1686, 0x00000004},
+ {0x168c, 0x00d2c46f},
+ {0x17a2, 0x00000620},
+ {0x16a0, 0x00eeffdd},
+ {0x16a6, 0x00071448},
+ {0x16a4, 0x0013132f},
+ {0x16a8, 0x00000000},
+ {0x0ffc, 0x00c0a028},
+ {0x0fe8, 0x0091b06c},
+ {0x0fea, 0x00041600},
+ {0x0f80, 0x00fffaff},
+ {0x0fec, 0x00901809},
+ {0x0ffe, 0x00b01007},
+ {0x16b0, 0x00eeff00},
+ {0x16b2, 0x00007000},
+ {0x16b4, 0x00000814},
+ };
+ const struct reg_val pre_init2[] = {
+ {0x0486, 0x0008a518},
+ {0x0488, 0x006dc696},
+ {0x048a, 0x00000912},
+ };
+ const struct firmware *fw;
+ struct device *dev = &phydev->mdio.dev;
+ unsigned int i;
+ u16 crc, reg;
+ int ret;
+
+ phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
+
+ /* all writes below are broadcasted to all PHYs in the same package */
+ reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS);
+ reg |= SMI_BROADCAST_WR_EN;
+ phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg);
+
+ phy_base_write(phydev, MII_VSC85XX_INT_MASK, 0);
+
+ reg = phy_base_read(phydev, MSCC_PHY_BYPASS_CONTROL);
+ reg |= PARALLEL_DET_IGNORE_ADVERTISED;
+ phy_base_write(phydev, MSCC_PHY_BYPASS_CONTROL, reg);
+
+ /* The below register writes are tweaking analog and electrical
+ * configuration that were determined through characterization by PHY
+ * engineers. These don't mean anything more than "these are the best
+ * values".
+ */
+ phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED_3);
+
+ phy_base_write(phydev, MSCC_PHY_SERDES_TX_CRC_ERR_CNT, 0x2000);
+
+ phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST);
+
+ phy_base_write(phydev, MSCC_PHY_TEST_PAGE_5, 0x1f20);
+
+ reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8);
+ reg |= 0x8000;
+ phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg);
+
+ phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR);
+
+ phy_base_write(phydev, MSCC_PHY_TR_CNTL, TR_WRITE | TR_ADDR(0x2fa4));
+
+ reg = phy_base_read(phydev, MSCC_PHY_TR_MSB);
+ reg &= ~0x007f;
+ reg |= 0x0019;
+ phy_base_write(phydev, MSCC_PHY_TR_MSB, reg);
+
+ phy_base_write(phydev, MSCC_PHY_TR_CNTL, TR_WRITE | TR_ADDR(0x0fa4));
+
+ for (i = 0; i < ARRAY_SIZE(pre_init1); i++)
+ vsc8584_csr_write(phydev, pre_init1[i].reg, pre_init1[i].val);
+
+ phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED_2);
+
+ phy_base_write(phydev, MSCC_PHY_CU_PMD_TX_CNTL, 0x028e);
+
+ phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR);
+
+ for (i = 0; i < ARRAY_SIZE(pre_init2); i++)
+ vsc8584_csr_write(phydev, pre_init2[i].reg, pre_init2[i].val);
+
+ phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST);
+
+ reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8);
+ reg &= ~0x8000;
+ phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg);
+
+ phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
+
+ /* end of write broadcasting */
+ reg = phy_base_read(phydev, MSCC_PHY_EXT_CNTL_STATUS);
+ reg &= ~SMI_BROADCAST_WR_EN;
+ phy_base_write(phydev, MSCC_PHY_EXT_CNTL_STATUS, reg);
+
+ ret = request_firmware(&fw, MSCC_VSC8584_REVB_INT8051_FW, dev);
+ if (ret) {
+ dev_err(dev, "failed to load firmware %s, ret: %d\n",
+ MSCC_VSC8584_REVB_INT8051_FW, ret);
+ return ret;
+ }
+
+ /* Add one byte to size for the one added by the patch_fw function */
+ ret = vsc8584_get_fw_crc(phydev,
+ MSCC_VSC8584_REVB_INT8051_FW_START_ADDR,
+ fw->size + 1, &crc);
+ if (ret)
+ goto out;
+
+ if (crc != MSCC_VSC8584_REVB_INT8051_FW_CRC) {
+ dev_dbg(dev, "FW CRC is not the expected one, patching FW\n");
+ if (vsc8584_patch_fw(phydev, fw))
+ dev_warn(dev,
+ "failed to patch FW, expect non-optimal device\n");
+ }
+
+ vsc8584_micro_deassert_reset(phydev, false);
+
+ /* Add one byte to size for the one added by the patch_fw function */
+ ret = vsc8584_get_fw_crc(phydev,
+ MSCC_VSC8584_REVB_INT8051_FW_START_ADDR,
+ fw->size + 1, &crc);
+ if (ret)
+ goto out;
+
+ if (crc != MSCC_VSC8584_REVB_INT8051_FW_CRC)
+ dev_warn(dev,
+ "FW CRC after patching is not the expected one, expect non-optimal device\n");
+
+ ret = vsc8584_micro_assert_reset(phydev);
+ if (ret)
+ goto out;
+
+ vsc8584_micro_deassert_reset(phydev, true);
+
+out:
+ phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
+
+ release_firmware(fw);
+
+ return ret;
+}
+
+/* Check if one PHY has already done the init of the parts common to all PHYs
+ * in the Quad PHY package.
+ */
+static bool vsc8584_is_pkg_init(struct phy_device *phydev, bool reversed)
+{
+ struct mdio_device **map = phydev->mdio.bus->mdio_map;
+ struct vsc8531_private *vsc8531;
+ struct phy_device *phy;
+ int i, addr;
+
+ /* VSC8584 is a Quad PHY */
+ for (i = 0; i < 4; i++) {
+ vsc8531 = phydev->priv;
+
+ if (reversed)
+ addr = vsc8531->base_addr - i;
+ else
+ addr = vsc8531->base_addr + i;
+
+ phy = container_of(map[addr], struct phy_device, mdio);
+
+ if ((phy->phy_id & phydev->drv->phy_id_mask) !=
+ (phydev->drv->phy_id & phydev->drv->phy_id_mask))
+ continue;
+
+ vsc8531 = phy->priv;
+
+ if (vsc8531 && vsc8531->pkg_init)
+ return true;
+ }
+
+ return false;
+}
+
+static int vsc8584_config_init(struct phy_device *phydev)
+{
+ struct vsc8531_private *vsc8531 = phydev->priv;
+ u16 addr, val;
+ int ret, i;
+
+ phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
+
+ mutex_lock(&phydev->mdio.bus->mdio_lock);
+
+ __mdiobus_write(phydev->mdio.bus, phydev->mdio.addr,
+ MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED);
+ addr = __mdiobus_read(phydev->mdio.bus, phydev->mdio.addr,
+ MSCC_PHY_EXT_PHY_CNTL_4);
+ addr >>= PHY_CNTL_4_ADDR_POS;
+
+ val = __mdiobus_read(phydev->mdio.bus, phydev->mdio.addr,
+ MSCC_PHY_ACTIPHY_CNTL);
+ if (val & PHY_ADDR_REVERSED)
+ vsc8531->base_addr = phydev->mdio.addr + addr;
+ else
+ vsc8531->base_addr = phydev->mdio.addr - addr;
+
+ /* Some parts of the init sequence are identical for every PHY in the
+ * package. Some parts are modifying the GPIO register bank which is a
+ * set of registers that are affecting all PHYs, a few resetting the
+ * microprocessor common to all PHYs. The CRC check responsible of the
+ * checking the firmware within the 8051 microprocessor can only be
+ * accessed via the PHY whose internal address in the package is 0.
+ * All PHYs' interrupts mask register has to be zeroed before enabling
+ * any PHY's interrupt in this register.
+ * For all these reasons, we need to do the init sequence once and only
+ * once whatever is the first PHY in the package that is initialized and
+ * do the correct init sequence for all PHYs that are package-critical
+ * in this pre-init function.
+ */
+ if (!vsc8584_is_pkg_init(phydev, val & PHY_ADDR_REVERSED ? 1 : 0)) {
+ if ((phydev->phy_id & phydev->drv->phy_id_mask) ==
+ (PHY_ID_VSC8574 & phydev->drv->phy_id_mask))
+ ret = vsc8574_config_pre_init(phydev);
+ else if ((phydev->phy_id & phydev->drv->phy_id_mask) ==
+ (PHY_ID_VSC8584 & phydev->drv->phy_id_mask))
+ ret = vsc8584_config_pre_init(phydev);
+ else
+ ret = -EINVAL;
+
+ if (ret)
+ goto err;
+ }
+
+ vsc8531->pkg_init = true;
+
+ phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS,
+ MSCC_PHY_PAGE_EXTENDED_GPIO);
+
+ val = phy_base_read(phydev, MSCC_PHY_MAC_CFG_FASTLINK);
+ val &= ~MAC_CFG_MASK;
+ if (phydev->interface == PHY_INTERFACE_MODE_QSGMII)
+ val |= MAC_CFG_QSGMII;
+ else
+ val |= MAC_CFG_SGMII;
+
+ ret = phy_base_write(phydev, MSCC_PHY_MAC_CFG_FASTLINK, val);
+ if (ret)
+ goto err;
+
+ val = PROC_CMD_MCB_ACCESS_MAC_CONF | PROC_CMD_RST_CONF_PORT |
+ PROC_CMD_READ_MOD_WRITE_PORT;
+ if (phydev->interface == PHY_INTERFACE_MODE_QSGMII)
+ val |= PROC_CMD_QSGMII_MAC;
+ else
+ val |= PROC_CMD_SGMII_MAC;
+
+ ret = vsc8584_cmd(phydev, val);
+ if (ret)
+ goto err;
+
+ usleep_range(10000, 20000);
+
+ /* Disable SerDes for 100Base-FX */
+ ret = vsc8584_cmd(phydev, PROC_CMD_FIBER_MEDIA_CONF |
+ PROC_CMD_FIBER_PORT(addr) | PROC_CMD_FIBER_DISABLE |
+ PROC_CMD_READ_MOD_WRITE_PORT |
+ PROC_CMD_RST_CONF_PORT | PROC_CMD_FIBER_100BASE_FX);
+ if (ret)
+ goto err;
+
+ /* Disable SerDes for 1000Base-X */
+ ret = vsc8584_cmd(phydev, PROC_CMD_FIBER_MEDIA_CONF |
+ PROC_CMD_FIBER_PORT(addr) | PROC_CMD_FIBER_DISABLE |
+ PROC_CMD_READ_MOD_WRITE_PORT |
+ PROC_CMD_RST_CONF_PORT | PROC_CMD_FIBER_1000BASE_X);
+ if (ret)
+ goto err;
+
+ mutex_unlock(&phydev->mdio.bus->mdio_lock);
+
+ phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
+
+ val = phy_read(phydev, MSCC_PHY_EXT_PHY_CNTL_1);
+ val &= ~(MEDIA_OP_MODE_MASK | VSC8584_MAC_IF_SELECTION_MASK);
+ val |= MEDIA_OP_MODE_COPPER | (VSC8584_MAC_IF_SELECTION_SGMII <<
+ VSC8584_MAC_IF_SELECTION_POS);
+ ret = phy_write(phydev, MSCC_PHY_EXT_PHY_CNTL_1, val);
+
+ ret = genphy_soft_reset(phydev);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < vsc8531->nleds; i++) {
+ ret = vsc85xx_led_cntl_set(phydev, i, vsc8531->leds_mode[i]);
+ if (ret)
+ return ret;
+ }
+
+ return genphy_config_init(phydev);
+
+err:
+ mutex_unlock(&phydev->mdio.bus->mdio_lock);
+ return ret;
+}
+
static int vsc85xx_config_init(struct phy_device *phydev)
{
- int rc;
+ int rc, i;
struct vsc8531_private *vsc8531 = phydev->priv;
rc = vsc85xx_default_config(phydev);
@@ -560,17 +1669,27 @@ static int vsc85xx_config_init(struct phy_device *phydev)
if (rc)
return rc;
- rc = vsc85xx_led_cntl_set(phydev, 1, vsc8531->led_1_mode);
+ rc = vsc85xx_eee_init_seq_set(phydev);
if (rc)
return rc;
- rc = vsc85xx_led_cntl_set(phydev, 0, vsc8531->led_0_mode);
- if (rc)
- return rc;
+ for (i = 0; i < vsc8531->nleds; i++) {
+ rc = vsc85xx_led_cntl_set(phydev, i, vsc8531->leds_mode[i]);
+ if (rc)
+ return rc;
+ }
- rc = genphy_config_init(phydev);
+ return genphy_config_init(phydev);
+}
- return rc;
+static int vsc8584_did_interrupt(struct phy_device *phydev)
+{
+ int rc = 0;
+
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+ rc = phy_read(phydev, MII_VSC85XX_INT_STATUS);
+
+ return (rc < 0) ? 0 : rc & MII_VSC85XX_INT_MASK_MASK;
}
static int vsc85xx_ack_interrupt(struct phy_device *phydev)
@@ -622,11 +1741,67 @@ static int vsc85xx_read_status(struct phy_device *phydev)
return genphy_read_status(phydev);
}
+static int vsc8574_probe(struct phy_device *phydev)
+{
+ struct vsc8531_private *vsc8531;
+ u32 default_mode[4] = {VSC8531_LINK_1000_ACTIVITY,
+ VSC8531_LINK_100_ACTIVITY, VSC8531_LINK_ACTIVITY,
+ VSC8531_DUPLEX_COLLISION};
+
+ vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL);
+ if (!vsc8531)
+ return -ENOMEM;
+
+ phydev->priv = vsc8531;
+
+ vsc8531->nleds = 4;
+ vsc8531->supp_led_modes = VSC8584_SUPP_LED_MODES;
+ vsc8531->hw_stats = vsc8584_hw_stats;
+ vsc8531->nstats = ARRAY_SIZE(vsc8584_hw_stats);
+ vsc8531->stats = devm_kmalloc_array(&phydev->mdio.dev, vsc8531->nstats,
+ sizeof(u64), GFP_KERNEL);
+ if (!vsc8531->stats)
+ return -ENOMEM;
+
+ return vsc85xx_dt_led_modes_get(phydev, default_mode);
+}
+
+static int vsc8584_probe(struct phy_device *phydev)
+{
+ struct vsc8531_private *vsc8531;
+ u32 default_mode[4] = {VSC8531_LINK_1000_ACTIVITY,
+ VSC8531_LINK_100_ACTIVITY, VSC8531_LINK_ACTIVITY,
+ VSC8531_DUPLEX_COLLISION};
+
+ if ((phydev->phy_id & MSCC_DEV_REV_MASK) != VSC8584_REVB) {
+ dev_err(&phydev->mdio.dev, "Only VSC8584 revB is supported.\n");
+ return -ENOTSUPP;
+ }
+
+ vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL);
+ if (!vsc8531)
+ return -ENOMEM;
+
+ phydev->priv = vsc8531;
+
+ vsc8531->nleds = 4;
+ vsc8531->supp_led_modes = VSC8584_SUPP_LED_MODES;
+ vsc8531->hw_stats = vsc8584_hw_stats;
+ vsc8531->nstats = ARRAY_SIZE(vsc8584_hw_stats);
+ vsc8531->stats = devm_kmalloc_array(&phydev->mdio.dev, vsc8531->nstats,
+ sizeof(u64), GFP_KERNEL);
+ if (!vsc8531->stats)
+ return -ENOMEM;
+
+ return vsc85xx_dt_led_modes_get(phydev, default_mode);
+}
+
static int vsc85xx_probe(struct phy_device *phydev)
{
struct vsc8531_private *vsc8531;
int rate_magic;
- int led_mode;
+ u32 default_mode[2] = {VSC8531_LINK_1000_ACTIVITY,
+ VSC8531_LINK_100_ACTIVITY};
rate_magic = vsc85xx_edge_rate_magic_get(phydev);
if (rate_magic < 0)
@@ -639,21 +1814,16 @@ static int vsc85xx_probe(struct phy_device *phydev)
phydev->priv = vsc8531;
vsc8531->rate_magic = rate_magic;
+ vsc8531->nleds = 2;
+ vsc8531->supp_led_modes = VSC85XX_SUPP_LED_MODES;
+ vsc8531->hw_stats = vsc85xx_hw_stats;
+ vsc8531->nstats = ARRAY_SIZE(vsc85xx_hw_stats);
+ vsc8531->stats = devm_kmalloc_array(&phydev->mdio.dev, vsc8531->nstats,
+ sizeof(u64), GFP_KERNEL);
+ if (!vsc8531->stats)
+ return -ENOMEM;
- /* LED[0] and LED[1] mode */
- led_mode = vsc85xx_dt_led_mode_get(phydev, "vsc8531,led-0-mode",
- VSC8531_LINK_1000_ACTIVITY);
- if (led_mode < 0)
- return led_mode;
- vsc8531->led_0_mode = led_mode;
-
- led_mode = vsc85xx_dt_led_mode_get(phydev, "vsc8531,led-1-mode",
- VSC8531_LINK_100_ACTIVITY);
- if (led_mode < 0)
- return led_mode;
- vsc8531->led_1_mode = led_mode;
-
- return 0;
+ return vsc85xx_dt_led_modes_get(phydev, default_mode);
}
/* Microsemi VSC85xx PHYs */
@@ -678,6 +1848,11 @@ static struct phy_driver vsc85xx_driver[] = {
.get_wol = &vsc85xx_wol_get,
.get_tunable = &vsc85xx_get_tunable,
.set_tunable = &vsc85xx_set_tunable,
+ .read_page = &vsc85xx_phy_read_page,
+ .write_page = &vsc85xx_phy_write_page,
+ .get_sset_count = &vsc85xx_get_sset_count,
+ .get_strings = &vsc85xx_get_strings,
+ .get_stats = &vsc85xx_get_stats,
},
{
.phy_id = PHY_ID_VSC8531,
@@ -699,6 +1874,11 @@ static struct phy_driver vsc85xx_driver[] = {
.get_wol = &vsc85xx_wol_get,
.get_tunable = &vsc85xx_get_tunable,
.set_tunable = &vsc85xx_set_tunable,
+ .read_page = &vsc85xx_phy_read_page,
+ .write_page = &vsc85xx_phy_write_page,
+ .get_sset_count = &vsc85xx_get_sset_count,
+ .get_strings = &vsc85xx_get_strings,
+ .get_stats = &vsc85xx_get_stats,
},
{
.phy_id = PHY_ID_VSC8540,
@@ -720,6 +1900,11 @@ static struct phy_driver vsc85xx_driver[] = {
.get_wol = &vsc85xx_wol_get,
.get_tunable = &vsc85xx_get_tunable,
.set_tunable = &vsc85xx_set_tunable,
+ .read_page = &vsc85xx_phy_read_page,
+ .write_page = &vsc85xx_phy_write_page,
+ .get_sset_count = &vsc85xx_get_sset_count,
+ .get_strings = &vsc85xx_get_strings,
+ .get_stats = &vsc85xx_get_stats,
},
{
.phy_id = PHY_ID_VSC8541,
@@ -741,6 +1926,63 @@ static struct phy_driver vsc85xx_driver[] = {
.get_wol = &vsc85xx_wol_get,
.get_tunable = &vsc85xx_get_tunable,
.set_tunable = &vsc85xx_set_tunable,
+ .read_page = &vsc85xx_phy_read_page,
+ .write_page = &vsc85xx_phy_write_page,
+ .get_sset_count = &vsc85xx_get_sset_count,
+ .get_strings = &vsc85xx_get_strings,
+ .get_stats = &vsc85xx_get_stats,
+},
+{
+ .phy_id = PHY_ID_VSC8574,
+ .name = "Microsemi GE VSC8574 SyncE",
+ .phy_id_mask = 0xfffffff0,
+ .features = PHY_GBIT_FEATURES,
+ .flags = PHY_HAS_INTERRUPT,
+ .soft_reset = &genphy_soft_reset,
+ .config_init = &vsc8584_config_init,
+ .config_aneg = &vsc85xx_config_aneg,
+ .aneg_done = &genphy_aneg_done,
+ .read_status = &vsc85xx_read_status,
+ .ack_interrupt = &vsc85xx_ack_interrupt,
+ .config_intr = &vsc85xx_config_intr,
+ .did_interrupt = &vsc8584_did_interrupt,
+ .suspend = &genphy_suspend,
+ .resume = &genphy_resume,
+ .probe = &vsc8574_probe,
+ .set_wol = &vsc85xx_wol_set,
+ .get_wol = &vsc85xx_wol_get,
+ .get_tunable = &vsc85xx_get_tunable,
+ .set_tunable = &vsc85xx_set_tunable,
+ .read_page = &vsc85xx_phy_read_page,
+ .write_page = &vsc85xx_phy_write_page,
+ .get_sset_count = &vsc85xx_get_sset_count,
+ .get_strings = &vsc85xx_get_strings,
+ .get_stats = &vsc85xx_get_stats,
+},
+{
+ .phy_id = PHY_ID_VSC8584,
+ .name = "Microsemi GE VSC8584 SyncE",
+ .phy_id_mask = 0xfffffff0,
+ .features = PHY_GBIT_FEATURES,
+ .flags = PHY_HAS_INTERRUPT,
+ .soft_reset = &genphy_soft_reset,
+ .config_init = &vsc8584_config_init,
+ .config_aneg = &vsc85xx_config_aneg,
+ .aneg_done = &genphy_aneg_done,
+ .read_status = &vsc85xx_read_status,
+ .ack_interrupt = &vsc85xx_ack_interrupt,
+ .config_intr = &vsc85xx_config_intr,
+ .did_interrupt = &vsc8584_did_interrupt,
+ .suspend = &genphy_suspend,
+ .resume = &genphy_resume,
+ .probe = &vsc8584_probe,
+ .get_tunable = &vsc85xx_get_tunable,
+ .set_tunable = &vsc85xx_set_tunable,
+ .read_page = &vsc85xx_phy_read_page,
+ .write_page = &vsc85xx_phy_write_page,
+ .get_sset_count = &vsc85xx_get_sset_count,
+ .get_strings = &vsc85xx_get_strings,
+ .get_stats = &vsc85xx_get_stats,
}
};
@@ -752,6 +1994,8 @@ static struct mdio_device_id __maybe_unused vsc85xx_tbl[] = {
{ PHY_ID_VSC8531, 0xfffffff0, },
{ PHY_ID_VSC8540, 0xfffffff0, },
{ PHY_ID_VSC8541, 0xfffffff0, },
+ { PHY_ID_VSC8574, 0xfffffff0, },
+ { PHY_ID_VSC8584, 0xfffffff0, },
{ }
};
diff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c
index e1225545362d..d7636ff03bc7 100644
--- a/drivers/net/phy/phy-c45.c
+++ b/drivers/net/phy/phy-c45.c
@@ -329,7 +329,7 @@ struct phy_driver genphy_10g_driver = {
.name = "Generic 10G PHY",
.soft_reset = gen10g_no_soft_reset,
.config_init = gen10g_config_init,
- .features = 0,
+ .features = PHY_10GBIT_FEATURES,
.config_aneg = gen10g_config_aneg,
.read_status = gen10g_read_status,
.suspend = gen10g_suspend,
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 1ee25877c4d1..1d73ac3309ce 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -482,16 +482,15 @@ static int phy_config_aneg(struct phy_device *phydev)
}
/**
- * phy_start_aneg_priv - start auto-negotiation for this PHY device
+ * phy_start_aneg - start auto-negotiation for this PHY device
* @phydev: the phy_device struct
- * @sync: indicate whether we should wait for the workqueue cancelation
*
* Description: Sanitizes the settings (if we're not autonegotiating
* them), and then calls the driver's config_aneg function.
* If the PHYCONTROL Layer is operating, we change the state to
* reflect the beginning of Auto-negotiation or forcing.
*/
-static int phy_start_aneg_priv(struct phy_device *phydev, bool sync)
+int phy_start_aneg(struct phy_device *phydev)
{
bool trigger = 0;
int err;
@@ -537,24 +536,10 @@ out_unlock:
mutex_unlock(&phydev->lock);
if (trigger)
- phy_trigger_machine(phydev, sync);
+ phy_trigger_machine(phydev);
return err;
}
-
-/**
- * phy_start_aneg - start auto-negotiation for this PHY device
- * @phydev: the phy_device struct
- *
- * Description: Sanitizes the settings (if we're not autonegotiating
- * them), and then calls the driver's config_aneg function.
- * If the PHYCONTROL Layer is operating, we change the state to
- * reflect the beginning of Auto-negotiation or forcing.
- */
-int phy_start_aneg(struct phy_device *phydev)
-{
- return phy_start_aneg_priv(phydev, true);
-}
EXPORT_SYMBOL(phy_start_aneg);
static int phy_poll_aneg_done(struct phy_device *phydev)
@@ -635,6 +620,13 @@ int phy_speed_up(struct phy_device *phydev)
}
EXPORT_SYMBOL_GPL(phy_speed_up);
+static void phy_queue_state_machine(struct phy_device *phydev,
+ unsigned int secs)
+{
+ mod_delayed_work(system_power_efficient_wq, &phydev->state_queue,
+ secs * HZ);
+}
+
/**
* phy_start_machine - start PHY state machine tracking
* @phydev: the phy_device struct
@@ -647,7 +639,7 @@ EXPORT_SYMBOL_GPL(phy_speed_up);
*/
void phy_start_machine(struct phy_device *phydev)
{
- queue_delayed_work(system_power_efficient_wq, &phydev->state_queue, HZ);
+ phy_trigger_machine(phydev);
}
EXPORT_SYMBOL_GPL(phy_start_machine);
@@ -655,19 +647,14 @@ EXPORT_SYMBOL_GPL(phy_start_machine);
* phy_trigger_machine - trigger the state machine to run
*
* @phydev: the phy_device struct
- * @sync: indicate whether we should wait for the workqueue cancelation
*
* Description: There has been a change in state which requires that the
* state machine runs.
*/
-void phy_trigger_machine(struct phy_device *phydev, bool sync)
+void phy_trigger_machine(struct phy_device *phydev)
{
- if (sync)
- cancel_delayed_work_sync(&phydev->state_queue);
- else
- cancel_delayed_work(&phydev->state_queue);
- queue_delayed_work(system_power_efficient_wq, &phydev->state_queue, 0);
+ phy_queue_state_machine(phydev, 0);
}
/**
@@ -703,7 +690,7 @@ static void phy_error(struct phy_device *phydev)
phydev->state = PHY_HALTED;
mutex_unlock(&phydev->lock);
- phy_trigger_machine(phydev, false);
+ phy_trigger_machine(phydev);
}
/**
@@ -745,7 +732,7 @@ static irqreturn_t phy_change(struct phy_device *phydev)
mutex_unlock(&phydev->lock);
/* reschedule state queue work to run as soon as possible */
- phy_trigger_machine(phydev, true);
+ phy_trigger_machine(phydev);
if (phy_interrupt_is_valid(phydev) && phy_clear_interrupt(phydev))
goto phy_err;
@@ -861,6 +848,8 @@ void phy_stop(struct phy_device *phydev)
out_unlock:
mutex_unlock(&phydev->lock);
+ phy_state_machine(&phydev->state_queue.work);
+
/* Cannot call flush_scheduled_work() here as desired because
* of rtnl_lock(), but PHY_HALTED shall guarantee phy_change()
* will not reenable interrupts.
@@ -909,7 +898,7 @@ void phy_start(struct phy_device *phydev)
}
mutex_unlock(&phydev->lock);
- phy_trigger_machine(phydev, true);
+ phy_trigger_machine(phydev);
}
EXPORT_SYMBOL(phy_start);
@@ -937,7 +926,6 @@ void phy_state_machine(struct work_struct *work)
bool needs_aneg = false, do_suspend = false;
enum phy_state old_state;
int err = 0;
- int old_link;
mutex_lock(&phydev->lock);
@@ -1021,26 +1009,16 @@ void phy_state_machine(struct work_struct *work)
}
break;
case PHY_RUNNING:
- /* Only register a CHANGE if we are polling and link changed
- * since latest checking.
- */
- if (phy_polling_mode(phydev)) {
- old_link = phydev->link;
- err = phy_read_status(phydev);
- if (err)
- break;
+ if (!phy_polling_mode(phydev))
+ break;
- if (old_link != phydev->link)
- phydev->state = PHY_CHANGELINK;
- }
- /*
- * Failsafe: check that nobody set phydev->link=0 between two
- * poll cycles, otherwise we won't leave RUNNING state as long
- * as link remains down.
- */
- if (!phydev->link && phydev->state == PHY_RUNNING) {
- phydev->state = PHY_CHANGELINK;
- phydev_err(phydev, "no link in PHY_RUNNING\n");
+ err = phy_read_status(phydev);
+ if (err)
+ break;
+
+ if (!phydev->link) {
+ phydev->state = PHY_NOLINK;
+ phy_link_down(phydev, true);
}
break;
case PHY_CHANGELINK:
@@ -1066,48 +1044,33 @@ void phy_state_machine(struct work_struct *work)
case PHY_RESUMING:
if (AUTONEG_ENABLE == phydev->autoneg) {
err = phy_aneg_done(phydev);
- if (err < 0)
+ if (err < 0) {
break;
-
- /* err > 0 if AN is done.
- * Otherwise, it's 0, and we're still waiting for AN
- */
- if (err > 0) {
- err = phy_read_status(phydev);
- if (err)
- break;
-
- if (phydev->link) {
- phydev->state = PHY_RUNNING;
- phy_link_up(phydev);
- } else {
- phydev->state = PHY_NOLINK;
- phy_link_down(phydev, false);
- }
- } else {
+ } else if (!err) {
phydev->state = PHY_AN;
phydev->link_timeout = PHY_AN_TIMEOUT;
- }
- } else {
- err = phy_read_status(phydev);
- if (err)
break;
-
- if (phydev->link) {
- phydev->state = PHY_RUNNING;
- phy_link_up(phydev);
- } else {
- phydev->state = PHY_NOLINK;
- phy_link_down(phydev, false);
}
}
+
+ err = phy_read_status(phydev);
+ if (err)
+ break;
+
+ if (phydev->link) {
+ phydev->state = PHY_RUNNING;
+ phy_link_up(phydev);
+ } else {
+ phydev->state = PHY_NOLINK;
+ phy_link_down(phydev, false);
+ }
break;
}
mutex_unlock(&phydev->lock);
if (needs_aneg)
- err = phy_start_aneg_priv(phydev, false);
+ err = phy_start_aneg(phydev);
else if (do_suspend)
phy_suspend(phydev);
@@ -1121,11 +1084,14 @@ void phy_state_machine(struct work_struct *work)
/* Only re-schedule a PHY state machine change if we are polling the
* PHY, if PHY_IGNORE_INTERRUPT is set, then we will be moving
- * between states from phy_mac_interrupt()
+ * between states from phy_mac_interrupt().
+ *
+ * In state PHY_HALTED the PHY gets suspended, so rescheduling the
+ * state machine would be pointless and possibly error prone when
+ * called from phy_disconnect() synchronously.
*/
- if (phy_polling_mode(phydev))
- queue_delayed_work(system_power_efficient_wq, &phydev->state_queue,
- PHY_STATE_TIME * HZ);
+ if (phy_polling_mode(phydev) && old_state != PHY_HALTED)
+ phy_queue_state_machine(phydev, PHY_STATE_TIME);
}
/**
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index db1172db1e7c..ab33d1777132 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -29,6 +29,7 @@
#include <linux/module.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
+#include <linux/bitmap.h>
#include <linux/phy.h>
#include <linux/phy_led_triggers.h>
#include <linux/mdio.h>
@@ -42,6 +43,149 @@ MODULE_DESCRIPTION("PHY library");
MODULE_AUTHOR("Andy Fleming");
MODULE_LICENSE("GPL");
+__ETHTOOL_DECLARE_LINK_MODE_MASK(phy_basic_features) __ro_after_init;
+EXPORT_SYMBOL_GPL(phy_basic_features);
+
+__ETHTOOL_DECLARE_LINK_MODE_MASK(phy_basic_t1_features) __ro_after_init;
+EXPORT_SYMBOL_GPL(phy_basic_t1_features);
+
+__ETHTOOL_DECLARE_LINK_MODE_MASK(phy_gbit_features) __ro_after_init;
+EXPORT_SYMBOL_GPL(phy_gbit_features);
+
+__ETHTOOL_DECLARE_LINK_MODE_MASK(phy_gbit_fibre_features) __ro_after_init;
+EXPORT_SYMBOL_GPL(phy_gbit_fibre_features);
+
+__ETHTOOL_DECLARE_LINK_MODE_MASK(phy_gbit_all_ports_features) __ro_after_init;
+EXPORT_SYMBOL_GPL(phy_gbit_all_ports_features);
+
+__ETHTOOL_DECLARE_LINK_MODE_MASK(phy_10gbit_features) __ro_after_init;
+EXPORT_SYMBOL_GPL(phy_10gbit_features);
+
+static const int phy_basic_ports_array[] = {
+ ETHTOOL_LINK_MODE_Autoneg_BIT,
+ ETHTOOL_LINK_MODE_TP_BIT,
+ ETHTOOL_LINK_MODE_MII_BIT,
+};
+
+static const int phy_fibre_port_array[] = {
+ ETHTOOL_LINK_MODE_FIBRE_BIT,
+};
+
+static const int phy_all_ports_features_array[] = {
+ ETHTOOL_LINK_MODE_Autoneg_BIT,
+ ETHTOOL_LINK_MODE_TP_BIT,
+ ETHTOOL_LINK_MODE_MII_BIT,
+ ETHTOOL_LINK_MODE_FIBRE_BIT,
+ ETHTOOL_LINK_MODE_AUI_BIT,
+ ETHTOOL_LINK_MODE_BNC_BIT,
+ ETHTOOL_LINK_MODE_Backplane_BIT,
+};
+
+static const int phy_10_100_features_array[] = {
+ ETHTOOL_LINK_MODE_10baseT_Half_BIT,
+ ETHTOOL_LINK_MODE_10baseT_Full_BIT,
+ ETHTOOL_LINK_MODE_100baseT_Half_BIT,
+ ETHTOOL_LINK_MODE_100baseT_Full_BIT,
+};
+
+static const int phy_basic_t1_features_array[] = {
+ ETHTOOL_LINK_MODE_TP_BIT,
+ ETHTOOL_LINK_MODE_100baseT_Full_BIT,
+};
+
+static const int phy_gbit_features_array[] = {
+ ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
+ ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
+};
+
+static const int phy_10gbit_features_array[] = {
+ ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
+};
+
+__ETHTOOL_DECLARE_LINK_MODE_MASK(phy_10gbit_full_features) __ro_after_init;
+EXPORT_SYMBOL_GPL(phy_10gbit_full_features);
+
+static const int phy_10gbit_full_features_array[] = {
+ ETHTOOL_LINK_MODE_10baseT_Full_BIT,
+ ETHTOOL_LINK_MODE_100baseT_Full_BIT,
+ ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
+ ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
+};
+
+static void features_init(void)
+{
+ /* 10/100 half/full*/
+ linkmode_set_bit_array(phy_basic_ports_array,
+ ARRAY_SIZE(phy_basic_ports_array),
+ phy_basic_features);
+ linkmode_set_bit_array(phy_10_100_features_array,
+ ARRAY_SIZE(phy_10_100_features_array),
+ phy_basic_features);
+
+ /* 100 full, TP */
+ linkmode_set_bit_array(phy_basic_t1_features_array,
+ ARRAY_SIZE(phy_basic_t1_features_array),
+ phy_basic_t1_features);
+
+ /* 10/100 half/full + 1000 half/full */
+ linkmode_set_bit_array(phy_basic_ports_array,
+ ARRAY_SIZE(phy_basic_ports_array),
+ phy_gbit_features);
+ linkmode_set_bit_array(phy_10_100_features_array,
+ ARRAY_SIZE(phy_10_100_features_array),
+ phy_gbit_features);
+ linkmode_set_bit_array(phy_gbit_features_array,
+ ARRAY_SIZE(phy_gbit_features_array),
+ phy_gbit_features);
+
+ /* 10/100 half/full + 1000 half/full + fibre*/
+ linkmode_set_bit_array(phy_basic_ports_array,
+ ARRAY_SIZE(phy_basic_ports_array),
+ phy_gbit_fibre_features);
+ linkmode_set_bit_array(phy_10_100_features_array,
+ ARRAY_SIZE(phy_10_100_features_array),
+ phy_gbit_fibre_features);
+ linkmode_set_bit_array(phy_gbit_features_array,
+ ARRAY_SIZE(phy_gbit_features_array),
+ phy_gbit_fibre_features);
+ linkmode_set_bit_array(phy_fibre_port_array,
+ ARRAY_SIZE(phy_fibre_port_array),
+ phy_gbit_fibre_features);
+
+ /* 10/100 half/full + 1000 half/full + TP/MII/FIBRE/AUI/BNC/Backplane*/
+ linkmode_set_bit_array(phy_all_ports_features_array,
+ ARRAY_SIZE(phy_all_ports_features_array),
+ phy_gbit_all_ports_features);
+ linkmode_set_bit_array(phy_10_100_features_array,
+ ARRAY_SIZE(phy_10_100_features_array),
+ phy_gbit_all_ports_features);
+ linkmode_set_bit_array(phy_gbit_features_array,
+ ARRAY_SIZE(phy_gbit_features_array),
+ phy_gbit_all_ports_features);
+
+ /* 10/100 half/full + 1000 half/full + 10G full*/
+ linkmode_set_bit_array(phy_all_ports_features_array,
+ ARRAY_SIZE(phy_all_ports_features_array),
+ phy_10gbit_features);
+ linkmode_set_bit_array(phy_10_100_features_array,
+ ARRAY_SIZE(phy_10_100_features_array),
+ phy_10gbit_features);
+ linkmode_set_bit_array(phy_gbit_features_array,
+ ARRAY_SIZE(phy_gbit_features_array),
+ phy_10gbit_features);
+ linkmode_set_bit_array(phy_10gbit_features_array,
+ ARRAY_SIZE(phy_10gbit_features_array),
+ phy_10gbit_features);
+
+ /* 10/100/1000/10G full */
+ linkmode_set_bit_array(phy_all_ports_features_array,
+ ARRAY_SIZE(phy_all_ports_features_array),
+ phy_10gbit_full_features);
+ linkmode_set_bit_array(phy_10gbit_full_features_array,
+ ARRAY_SIZE(phy_10gbit_full_features_array),
+ phy_10gbit_full_features);
+}
+
void phy_device_free(struct phy_device *phydev)
{
put_device(&phydev->mdio.dev);
@@ -93,7 +237,12 @@ static bool mdio_bus_phy_may_suspend(struct phy_device *phydev)
if (!netdev)
return !phydev->suspended;
- /* Don't suspend PHY if the attached netdev parent may wakeup.
+ if (netdev->wol_enabled)
+ return false;
+
+ /* As long as not all affected network drivers support the
+ * wol_enabled flag, let's check for hints that WoL is enabled.
+ * Don't suspend PHY if the attached netdev parent may wake up.
* The parent may point to a PCI device, as in tg3 driver.
*/
if (netdev->dev.parent && device_may_wakeup(netdev->dev.parent))
@@ -880,8 +1029,6 @@ int phy_init_hw(struct phy_device *phydev)
if (phydev->drv->soft_reset)
ret = phydev->drv->soft_reset(phydev);
- else
- ret = genphy_soft_reset(phydev);
if (ret < 0)
return ret;
@@ -922,13 +1069,13 @@ void phy_attached_print(struct phy_device *phydev, const char *fmt, ...)
if (!fmt) {
- dev_info(&phydev->mdio.dev, ATTACHED_FMT "\n",
+ phydev_info(phydev, ATTACHED_FMT "\n",
drv_name, phydev_name(phydev),
irq_str);
} else {
va_list ap;
- dev_info(&phydev->mdio.dev, ATTACHED_FMT,
+ phydev_info(phydev, ATTACHED_FMT,
drv_name, phydev_name(phydev),
irq_str);
@@ -1132,9 +1279,9 @@ void phy_detach(struct phy_device *phydev)
sysfs_remove_link(&dev->dev.kobj, "phydev");
sysfs_remove_link(&phydev->mdio.dev.kobj, "attached_dev");
}
+ phy_suspend(phydev);
phydev->attached_dev->phydev = NULL;
phydev->attached_dev = NULL;
- phy_suspend(phydev);
phydev->phylink = NULL;
phy_led_triggers_unregister(phydev);
@@ -1168,12 +1315,13 @@ EXPORT_SYMBOL(phy_detach);
int phy_suspend(struct phy_device *phydev)
{
struct phy_driver *phydrv = to_phy_driver(phydev->mdio.dev.driver);
+ struct net_device *netdev = phydev->attached_dev;
struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
int ret = 0;
/* If the device has WOL enabled, we cannot suspend the PHY */
phy_ethtool_get_wol(phydev, &wol);
- if (wol.wolopts)
+ if (wol.wolopts || (netdev && netdev->wol_enabled))
return -EBUSY;
if (phydev->drv && phydrv->suspend)
@@ -1765,6 +1913,125 @@ int phy_set_max_speed(struct phy_device *phydev, u32 max_speed)
}
EXPORT_SYMBOL(phy_set_max_speed);
+/**
+ * phy_remove_link_mode - Remove a supported link mode
+ * @phydev: phy_device structure to remove link mode from
+ * @link_mode: Link mode to be removed
+ *
+ * Description: Some MACs don't support all link modes which the PHY
+ * does. e.g. a 1G MAC often does not support 1000Half. Add a helper
+ * to remove a link mode.
+ */
+void phy_remove_link_mode(struct phy_device *phydev, u32 link_mode)
+{
+ WARN_ON(link_mode > 31);
+
+ phydev->supported &= ~BIT(link_mode);
+ phydev->advertising = phydev->supported;
+}
+EXPORT_SYMBOL(phy_remove_link_mode);
+
+/**
+ * phy_support_sym_pause - Enable support of symmetrical pause
+ * @phydev: target phy_device struct
+ *
+ * Description: Called by the MAC to indicate is supports symmetrical
+ * Pause, but not asym pause.
+ */
+void phy_support_sym_pause(struct phy_device *phydev)
+{
+ phydev->supported &= ~SUPPORTED_Asym_Pause;
+ phydev->supported |= SUPPORTED_Pause;
+ phydev->advertising = phydev->supported;
+}
+EXPORT_SYMBOL(phy_support_sym_pause);
+
+/**
+ * phy_support_asym_pause - Enable support of asym pause
+ * @phydev: target phy_device struct
+ *
+ * Description: Called by the MAC to indicate is supports Asym Pause.
+ */
+void phy_support_asym_pause(struct phy_device *phydev)
+{
+ phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
+ phydev->advertising = phydev->supported;
+}
+EXPORT_SYMBOL(phy_support_asym_pause);
+
+/**
+ * phy_set_sym_pause - Configure symmetric Pause
+ * @phydev: target phy_device struct
+ * @rx: Receiver Pause is supported
+ * @tx: Transmit Pause is supported
+ * @autoneg: Auto neg should be used
+ *
+ * Description: Configure advertised Pause support depending on if
+ * receiver pause and pause auto neg is supported. Generally called
+ * from the set_pauseparam .ndo.
+ */
+void phy_set_sym_pause(struct phy_device *phydev, bool rx, bool tx,
+ bool autoneg)
+{
+ phydev->supported &= ~SUPPORTED_Pause;
+
+ if (rx && tx && autoneg)
+ phydev->supported |= SUPPORTED_Pause;
+
+ phydev->advertising = phydev->supported;
+}
+EXPORT_SYMBOL(phy_set_sym_pause);
+
+/**
+ * phy_set_asym_pause - Configure Pause and Asym Pause
+ * @phydev: target phy_device struct
+ * @rx: Receiver Pause is supported
+ * @tx: Transmit Pause is supported
+ *
+ * Description: Configure advertised Pause support depending on if
+ * transmit and receiver pause is supported. If there has been a
+ * change in adverting, trigger a new autoneg. Generally called from
+ * the set_pauseparam .ndo.
+ */
+void phy_set_asym_pause(struct phy_device *phydev, bool rx, bool tx)
+{
+ u16 oldadv = phydev->advertising;
+ u16 newadv = oldadv &= ~(SUPPORTED_Pause | SUPPORTED_Asym_Pause);
+
+ if (rx)
+ newadv |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
+ if (tx)
+ newadv ^= SUPPORTED_Asym_Pause;
+
+ if (oldadv != newadv) {
+ phydev->advertising = newadv;
+
+ if (phydev->autoneg)
+ phy_start_aneg(phydev);
+ }
+}
+EXPORT_SYMBOL(phy_set_asym_pause);
+
+/**
+ * phy_validate_pause - Test if the PHY/MAC support the pause configuration
+ * @phydev: phy_device struct
+ * @pp: requested pause configuration
+ *
+ * Description: Test if the PHY/MAC combination supports the Pause
+ * configuration the user is requesting. Returns True if it is
+ * supported, false otherwise.
+ */
+bool phy_validate_pause(struct phy_device *phydev,
+ struct ethtool_pauseparam *pp)
+{
+ if (!(phydev->supported & SUPPORTED_Pause) ||
+ (!(phydev->supported & SUPPORTED_Asym_Pause) &&
+ pp->rx_pause != pp->tx_pause))
+ return false;
+ return true;
+}
+EXPORT_SYMBOL(phy_validate_pause);
+
static void of_set_phy_supported(struct phy_device *phydev)
{
struct device_node *node = phydev->mdio.dev.of_node;
@@ -1820,6 +2087,7 @@ static int phy_probe(struct device *dev)
struct phy_device *phydev = to_phy_device(dev);
struct device_driver *drv = phydev->mdio.dev.driver;
struct phy_driver *phydrv = to_phy_driver(drv);
+ u32 features;
int err = 0;
phydev->drv = phydrv;
@@ -1840,7 +2108,8 @@ static int phy_probe(struct device *dev)
* a controller will attach, and may modify one
* or both of these values
*/
- phydev->supported = phydrv->features;
+ ethtool_convert_link_mode_to_legacy_u32(&features, phydrv->features);
+ phydev->supported = features;
of_set_phy_supported(phydev);
phydev->advertising = phydev->supported;
@@ -1860,10 +2129,14 @@ static int phy_probe(struct device *dev)
* (e.g. hardware erratum) where the driver wants to set only one
* of these bits.
*/
- if (phydrv->features & (SUPPORTED_Pause | SUPPORTED_Asym_Pause)) {
+ if (test_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydrv->features) ||
+ test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, phydrv->features)) {
phydev->supported &= ~(SUPPORTED_Pause | SUPPORTED_Asym_Pause);
- phydev->supported |= phydrv->features &
- (SUPPORTED_Pause | SUPPORTED_Asym_Pause);
+ if (test_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydrv->features))
+ phydev->supported |= SUPPORTED_Pause;
+ if (test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
+ phydrv->features))
+ phydev->supported |= SUPPORTED_Asym_Pause;
} else {
phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
}
@@ -1976,9 +2249,7 @@ static struct phy_driver genphy_driver = {
.name = "Generic PHY",
.soft_reset = genphy_no_soft_reset,
.config_init = genphy_config_init,
- .features = PHY_GBIT_FEATURES | SUPPORTED_MII |
- SUPPORTED_AUI | SUPPORTED_FIBRE |
- SUPPORTED_BNC,
+ .features = PHY_GBIT_ALL_PORTS_FEATURES,
.aneg_done = genphy_aneg_done,
.suspend = genphy_suspend,
.resume = genphy_resume,
@@ -1993,6 +2264,8 @@ static int __init phy_init(void)
if (rc)
return rc;
+ features_init();
+
rc = phy_driver_register(&genphy_10g_driver, THIS_MODULE);
if (rc)
goto err_10g;
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index 3ba5cf2a8a5f..9b8dd0d0ee42 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -68,33 +68,6 @@ struct phylink {
struct sfp_bus *sfp_bus;
};
-static inline void linkmode_zero(unsigned long *dst)
-{
- bitmap_zero(dst, __ETHTOOL_LINK_MODE_MASK_NBITS);
-}
-
-static inline void linkmode_copy(unsigned long *dst, const unsigned long *src)
-{
- bitmap_copy(dst, src, __ETHTOOL_LINK_MODE_MASK_NBITS);
-}
-
-static inline void linkmode_and(unsigned long *dst, const unsigned long *a,
- const unsigned long *b)
-{
- bitmap_and(dst, a, b, __ETHTOOL_LINK_MODE_MASK_NBITS);
-}
-
-static inline void linkmode_or(unsigned long *dst, const unsigned long *a,
- const unsigned long *b)
-{
- bitmap_or(dst, a, b, __ETHTOOL_LINK_MODE_MASK_NBITS);
-}
-
-static inline bool linkmode_empty(const unsigned long *src)
-{
- return bitmap_empty(src, __ETHTOOL_LINK_MODE_MASK_NBITS);
-}
-
/**
* phylink_set_port_modes() - set the port type modes in the ethtool mask
* @mask: ethtool link mode mask
@@ -717,6 +690,30 @@ static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy)
return 0;
}
+static int __phylink_connect_phy(struct phylink *pl, struct phy_device *phy,
+ phy_interface_t interface)
+{
+ int ret;
+
+ if (WARN_ON(pl->link_an_mode == MLO_AN_FIXED ||
+ (pl->link_an_mode == MLO_AN_INBAND &&
+ phy_interface_mode_is_8023z(interface))))
+ return -EINVAL;
+
+ if (pl->phydev)
+ return -EBUSY;
+
+ ret = phy_attach_direct(pl->netdev, phy, 0, interface);
+ if (ret)
+ return ret;
+
+ ret = phylink_bringup_phy(pl, phy);
+ if (ret)
+ phy_detach(phy);
+
+ return ret;
+}
+
/**
* phylink_connect_phy() - connect a PHY to the phylink instance
* @pl: a pointer to a &struct phylink returned from phylink_create()
@@ -734,31 +731,13 @@ static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy)
*/
int phylink_connect_phy(struct phylink *pl, struct phy_device *phy)
{
- int ret;
-
- if (WARN_ON(pl->link_an_mode == MLO_AN_FIXED ||
- (pl->link_an_mode == MLO_AN_INBAND &&
- phy_interface_mode_is_8023z(pl->link_interface))))
- return -EINVAL;
-
- if (pl->phydev)
- return -EBUSY;
-
/* Use PHY device/driver interface */
if (pl->link_interface == PHY_INTERFACE_MODE_NA) {
pl->link_interface = phy->interface;
pl->link_config.interface = pl->link_interface;
}
- ret = phy_attach_direct(pl->netdev, phy, 0, pl->link_interface);
- if (ret)
- return ret;
-
- ret = phylink_bringup_phy(pl, phy);
- if (ret)
- phy_detach(phy);
-
- return ret;
+ return __phylink_connect_phy(pl, phy, pl->link_interface);
}
EXPORT_SYMBOL_GPL(phylink_connect_phy);
@@ -901,6 +880,9 @@ void phylink_start(struct phylink *pl)
phylink_an_mode_str(pl->link_an_mode),
phy_modes(pl->link_config.interface));
+ /* Always set the carrier off */
+ netif_carrier_off(pl->netdev);
+
/* Apply the link configuration to the MAC when starting. This allows
* a fixed-link to start with the correct parameters, and also
* ensures that we set the appropriate advertisement for Serdes links.
@@ -1672,7 +1654,9 @@ static void phylink_sfp_link_up(void *upstream)
static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy)
{
- return phylink_connect_phy(upstream, phy);
+ struct phylink *pl = upstream;
+
+ return __phylink_connect_phy(upstream, phy, pl->link_config.interface);
}
static void phylink_sfp_disconnect_phy(void *upstream)
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
index 7fc8508b5231..271e8adc39f1 100644
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -220,7 +220,7 @@ static struct phy_driver realtek_drvs[] = {
.flags = PHY_HAS_INTERRUPT,
}, {
.phy_id = 0x001cc816,
- .name = "RTL8201F 10/100Mbps Ethernet",
+ .name = "RTL8201F Fast Ethernet",
.phy_id_mask = 0x001fffff,
.features = PHY_BASIC_FEATURES,
.flags = PHY_HAS_INTERRUPT,
diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
index 52fffb98fde9..fd8bb998ae52 100644
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
@@ -163,8 +163,6 @@ static const enum gpiod_flags gpio_flags[] = {
/* Give this long for the PHY to reset. */
#define T_PHY_RESET_MS 50
-static DEFINE_MUTEX(sfp_mutex);
-
struct sff_data {
unsigned int gpios;
bool (*module_supported)(const struct sfp_eeprom_id *id);
@@ -1098,8 +1096,11 @@ static int sfp_hwmon_insert(struct sfp *sfp)
static void sfp_hwmon_remove(struct sfp *sfp)
{
- hwmon_device_unregister(sfp->hwmon_dev);
- kfree(sfp->hwmon_name);
+ if (!IS_ERR_OR_NULL(sfp->hwmon_dev)) {
+ hwmon_device_unregister(sfp->hwmon_dev);
+ sfp->hwmon_dev = NULL;
+ kfree(sfp->hwmon_name);
+ }
}
#else
static int sfp_hwmon_insert(struct sfp *sfp)
diff --git a/drivers/net/phy/ste10Xp.c b/drivers/net/phy/ste10Xp.c
index fbd548a1ad84..2fe9a87b55b5 100644
--- a/drivers/net/phy/ste10Xp.c
+++ b/drivers/net/phy/ste10Xp.c
@@ -86,7 +86,7 @@ static struct phy_driver ste10xp_pdriver[] = {
.phy_id = STE101P_PHY_ID,
.phy_id_mask = 0xfffffff0,
.name = "STe101p",
- .features = PHY_BASIC_FEATURES | SUPPORTED_Pause,
+ .features = PHY_BASIC_FEATURES,
.flags = PHY_HAS_INTERRUPT,
.config_init = ste10Xp_config_init,
.ack_interrupt = ste10Xp_ack_interrupt,
@@ -97,7 +97,7 @@ static struct phy_driver ste10xp_pdriver[] = {
.phy_id = STE100P_PHY_ID,
.phy_id_mask = 0xffffffff,
.name = "STe100p",
- .features = PHY_BASIC_FEATURES | SUPPORTED_Pause,
+ .features = PHY_BASIC_FEATURES,
.flags = PHY_HAS_INTERRUPT,
.config_init = ste10Xp_config_init,
.ack_interrupt = ste10Xp_ack_interrupt,
diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index 02ad03a2fab7..500bc0027c1b 100644
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -2400,7 +2400,7 @@ ppp_mp_reconstruct(struct ppp *ppp)
if (ppp->mrru == 0) /* do nothing until mrru is set */
return NULL;
- head = list->next;
+ head = __skb_peek(list);
tail = NULL;
skb_queue_walk_safe(list, p, tmp) {
again:
diff --git a/drivers/net/ppp/ppp_mppe.c b/drivers/net/ppp/ppp_mppe.c
index a205750b431b..7ccdc62c6052 100644
--- a/drivers/net/ppp/ppp_mppe.c
+++ b/drivers/net/ppp/ppp_mppe.c
@@ -95,7 +95,7 @@ static inline void sha_pad_init(struct sha_pad *shapad)
* State for an MPPE (de)compressor.
*/
struct ppp_mppe_state {
- struct crypto_skcipher *arc4;
+ struct crypto_sync_skcipher *arc4;
struct shash_desc *sha1;
unsigned char *sha1_digest;
unsigned char master_key[MPPE_MAX_KEY_LEN];
@@ -155,15 +155,15 @@ static void get_new_key_from_sha(struct ppp_mppe_state * state)
static void mppe_rekey(struct ppp_mppe_state * state, int initial_key)
{
struct scatterlist sg_in[1], sg_out[1];
- SKCIPHER_REQUEST_ON_STACK(req, state->arc4);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(req, state->arc4);
- skcipher_request_set_tfm(req, state->arc4);
+ skcipher_request_set_sync_tfm(req, state->arc4);
skcipher_request_set_callback(req, 0, NULL, NULL);
get_new_key_from_sha(state);
if (!initial_key) {
- crypto_skcipher_setkey(state->arc4, state->sha1_digest,
- state->keylen);
+ crypto_sync_skcipher_setkey(state->arc4, state->sha1_digest,
+ state->keylen);
sg_init_table(sg_in, 1);
sg_init_table(sg_out, 1);
setup_sg(sg_in, state->sha1_digest, state->keylen);
@@ -181,7 +181,8 @@ static void mppe_rekey(struct ppp_mppe_state * state, int initial_key)
state->session_key[1] = 0x26;
state->session_key[2] = 0x9e;
}
- crypto_skcipher_setkey(state->arc4, state->session_key, state->keylen);
+ crypto_sync_skcipher_setkey(state->arc4, state->session_key,
+ state->keylen);
skcipher_request_zero(req);
}
@@ -203,7 +204,7 @@ static void *mppe_alloc(unsigned char *options, int optlen)
goto out;
- state->arc4 = crypto_alloc_skcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
+ state->arc4 = crypto_alloc_sync_skcipher("ecb(arc4)", 0, 0);
if (IS_ERR(state->arc4)) {
state->arc4 = NULL;
goto out_free;
@@ -250,7 +251,7 @@ out_free:
crypto_free_shash(state->sha1->tfm);
kzfree(state->sha1);
}
- crypto_free_skcipher(state->arc4);
+ crypto_free_sync_skcipher(state->arc4);
kfree(state);
out:
return NULL;
@@ -266,7 +267,7 @@ static void mppe_free(void *arg)
kfree(state->sha1_digest);
crypto_free_shash(state->sha1->tfm);
kzfree(state->sha1);
- crypto_free_skcipher(state->arc4);
+ crypto_free_sync_skcipher(state->arc4);
kfree(state);
}
}
@@ -366,7 +367,7 @@ mppe_compress(void *arg, unsigned char *ibuf, unsigned char *obuf,
int isize, int osize)
{
struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
- SKCIPHER_REQUEST_ON_STACK(req, state->arc4);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(req, state->arc4);
int proto;
int err;
struct scatterlist sg_in[1], sg_out[1];
@@ -426,7 +427,7 @@ mppe_compress(void *arg, unsigned char *ibuf, unsigned char *obuf,
setup_sg(sg_in, ibuf, isize);
setup_sg(sg_out, obuf, osize);
- skcipher_request_set_tfm(req, state->arc4);
+ skcipher_request_set_sync_tfm(req, state->arc4);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, sg_in, sg_out, isize, NULL);
err = crypto_skcipher_encrypt(req);
@@ -480,7 +481,7 @@ mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf,
int osize)
{
struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
- SKCIPHER_REQUEST_ON_STACK(req, state->arc4);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(req, state->arc4);
unsigned ccount;
int flushed = MPPE_BITS(ibuf) & MPPE_BIT_FLUSHED;
struct scatterlist sg_in[1], sg_out[1];
@@ -615,7 +616,7 @@ mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf,
setup_sg(sg_in, ibuf, 1);
setup_sg(sg_out, obuf, 1);
- skcipher_request_set_tfm(req, state->arc4);
+ skcipher_request_set_sync_tfm(req, state->arc4);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, sg_in, sg_out, 1, NULL);
if (crypto_skcipher_decrypt(req)) {
diff --git a/drivers/net/slip/slip.c b/drivers/net/slip/slip.c
index b008266e91ea..9757f1fc104f 100644
--- a/drivers/net/slip/slip.c
+++ b/drivers/net/slip/slip.c
@@ -79,7 +79,6 @@
#include <linux/rtnetlink.h>
#include <linux/if_arp.h>
#include <linux/if_slip.h>
-#include <linux/compat.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -1167,27 +1166,6 @@ static int slip_ioctl(struct tty_struct *tty, struct file *file,
}
}
-#ifdef CONFIG_COMPAT
-static long slip_compat_ioctl(struct tty_struct *tty, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- switch (cmd) {
- case SIOCGIFNAME:
- case SIOCGIFENCAP:
- case SIOCSIFENCAP:
- case SIOCSIFHWADDR:
- case SIOCSKEEPALIVE:
- case SIOCGKEEPALIVE:
- case SIOCSOUTFILL:
- case SIOCGOUTFILL:
- return slip_ioctl(tty, file, cmd,
- (unsigned long)compat_ptr(arg));
- }
-
- return -ENOIOCTLCMD;
-}
-#endif
-
/* VSV changes start here */
#ifdef CONFIG_SLIP_SMART
/* function do_ioctl called from net/core/dev.c
@@ -1280,9 +1258,6 @@ static struct tty_ldisc_ops sl_ldisc = {
.close = slip_close,
.hangup = slip_hangup,
.ioctl = slip_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = slip_compat_ioctl,
-#endif
.receive_buf = slip_receive_buf,
.write_wakeup = slip_write_wakeup,
};
diff --git a/drivers/net/tap.c b/drivers/net/tap.c
index f0f7cd977667..f03004f37eca 100644
--- a/drivers/net/tap.c
+++ b/drivers/net/tap.c
@@ -619,7 +619,7 @@ static inline struct sk_buff *tap_alloc_skb(struct sock *sk, size_t prepad,
#define TAP_RESERVE HH_DATA_OFF(ETH_HLEN)
/* Get packet from user space buffer */
-static ssize_t tap_get_user(struct tap_queue *q, struct msghdr *m,
+static ssize_t tap_get_user(struct tap_queue *q, void *msg_control,
struct iov_iter *from, int noblock)
{
int good_linear = SKB_MAX_HEAD(TAP_RESERVE);
@@ -663,7 +663,7 @@ static ssize_t tap_get_user(struct tap_queue *q, struct msghdr *m,
if (unlikely(len < ETH_HLEN))
goto err;
- if (m && m->msg_control && sock_flag(&q->sk, SOCK_ZEROCOPY)) {
+ if (msg_control && sock_flag(&q->sk, SOCK_ZEROCOPY)) {
struct iov_iter i;
copylen = vnet_hdr.hdr_len ?
@@ -724,11 +724,11 @@ static ssize_t tap_get_user(struct tap_queue *q, struct msghdr *m,
tap = rcu_dereference(q->tap);
/* copy skb_ubuf_info for callback when skb has no error */
if (zerocopy) {
- skb_shinfo(skb)->destructor_arg = m->msg_control;
+ skb_shinfo(skb)->destructor_arg = msg_control;
skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY;
skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
- } else if (m && m->msg_control) {
- struct ubuf_info *uarg = m->msg_control;
+ } else if (msg_control) {
+ struct ubuf_info *uarg = msg_control;
uarg->callback(uarg, false);
}
@@ -830,8 +830,7 @@ static ssize_t tap_do_read(struct tap_queue *q,
ssize_t ret = 0;
if (!iov_iter_count(to)) {
- if (skb)
- kfree_skb(skb);
+ kfree_skb(skb);
return 0;
}
@@ -1146,11 +1145,87 @@ static const struct file_operations tap_fops = {
#endif
};
+static int tap_get_user_xdp(struct tap_queue *q, struct xdp_buff *xdp)
+{
+ struct tun_xdp_hdr *hdr = xdp->data_hard_start;
+ struct virtio_net_hdr *gso = &hdr->gso;
+ int buflen = hdr->buflen;
+ int vnet_hdr_len = 0;
+ struct tap_dev *tap;
+ struct sk_buff *skb;
+ int err, depth;
+
+ if (q->flags & IFF_VNET_HDR)
+ vnet_hdr_len = READ_ONCE(q->vnet_hdr_sz);
+
+ skb = build_skb(xdp->data_hard_start, buflen);
+ if (!skb) {
+ err = -ENOMEM;
+ goto err;
+ }
+
+ skb_reserve(skb, xdp->data - xdp->data_hard_start);
+ skb_put(skb, xdp->data_end - xdp->data);
+
+ skb_set_network_header(skb, ETH_HLEN);
+ skb_reset_mac_header(skb);
+ skb->protocol = eth_hdr(skb)->h_proto;
+
+ if (vnet_hdr_len) {
+ err = virtio_net_hdr_to_skb(skb, gso, tap_is_little_endian(q));
+ if (err)
+ goto err_kfree;
+ }
+
+ skb_probe_transport_header(skb, ETH_HLEN);
+
+ /* Move network header to the right position for VLAN tagged packets */
+ if ((skb->protocol == htons(ETH_P_8021Q) ||
+ skb->protocol == htons(ETH_P_8021AD)) &&
+ __vlan_get_protocol(skb, skb->protocol, &depth) != 0)
+ skb_set_network_header(skb, depth);
+
+ rcu_read_lock();
+ tap = rcu_dereference(q->tap);
+ if (tap) {
+ skb->dev = tap->dev;
+ dev_queue_xmit(skb);
+ } else {
+ kfree_skb(skb);
+ }
+ rcu_read_unlock();
+
+ return 0;
+
+err_kfree:
+ kfree_skb(skb);
+err:
+ rcu_read_lock();
+ tap = rcu_dereference(q->tap);
+ if (tap && tap->count_tx_dropped)
+ tap->count_tx_dropped(tap);
+ rcu_read_unlock();
+ return err;
+}
+
static int tap_sendmsg(struct socket *sock, struct msghdr *m,
size_t total_len)
{
struct tap_queue *q = container_of(sock, struct tap_queue, sock);
- return tap_get_user(q, m, &m->msg_iter, m->msg_flags & MSG_DONTWAIT);
+ struct tun_msg_ctl *ctl = m->msg_control;
+ struct xdp_buff *xdp;
+ int i;
+
+ if (ctl && (ctl->type == TUN_MSG_PTR)) {
+ for (i = 0; i < ctl->num; i++) {
+ xdp = &((struct xdp_buff *)ctl->ptr)[i];
+ tap_get_user_xdp(q, xdp);
+ }
+ return 0;
+ }
+
+ return tap_get_user(q, ctl ? ctl->ptr : NULL, &m->msg_iter,
+ m->msg_flags & MSG_DONTWAIT);
}
static int tap_recvmsg(struct socket *sock, struct msghdr *m,
@@ -1160,8 +1235,7 @@ static int tap_recvmsg(struct socket *sock, struct msghdr *m,
struct sk_buff *skb = m->msg_control;
int ret;
if (flags & ~(MSG_DONTWAIT|MSG_TRUNC)) {
- if (skb)
- kfree_skb(skb);
+ kfree_skb(skb);
return -EINVAL;
}
ret = tap_do_read(q, &m->msg_iter, flags & MSG_DONTWAIT, skb);
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index 6a047d30e8c6..db633ae9f784 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -1104,10 +1104,7 @@ static void team_port_disable_netpoll(struct team_port *port)
return;
port->np = NULL;
- /* Wait for transmitting packets to finish before freeing. */
- synchronize_rcu_bh();
- __netpoll_cleanup(np);
- kfree(np);
+ __netpoll_free(np);
}
#else
static int team_port_enable_netpoll(struct team_port *port)
@@ -1167,6 +1164,12 @@ static int team_port_add(struct team *team, struct net_device *port_dev,
return -EBUSY;
}
+ if (dev == port_dev) {
+ NL_SET_ERR_MSG(extack, "Cannot enslave team device to itself");
+ netdev_err(dev, "Cannot enslave team device to itself\n");
+ return -EINVAL;
+ }
+
if (port_dev->features & NETIF_F_VLAN_CHALLENGED &&
vlan_uses_dev(dev)) {
NL_SET_ERR_MSG(extack, "Device is VLAN challenged and team device has VLAN set up");
diff --git a/drivers/net/thunderbolt.c b/drivers/net/thunderbolt.c
index e0d6760f3219..c48c3a1eb1f8 100644
--- a/drivers/net/thunderbolt.c
+++ b/drivers/net/thunderbolt.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Networking over Thunderbolt cable using Apple ThunderboltIP protocol
*
@@ -5,10 +6,6 @@
* Authors: Amir Levy <amir.jer.levy@intel.com>
* Michael Jamet <michael.jamet@intel.com>
* Mika Westerberg <mika.westerberg@linux.intel.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/atomic.h>
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index e2648b5a3861..060135ceaf0e 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -113,7 +113,6 @@ do { \
} while (0)
#endif
-#define TUN_HEADROOM 256
#define TUN_RX_PAD (NET_IP_ALIGN + NET_SKB_PAD)
/* TUN device flags */
@@ -181,6 +180,7 @@ struct tun_file {
};
struct napi_struct napi;
bool napi_enabled;
+ bool napi_frags_enabled;
struct mutex napi_mutex; /* Protects access to the above napi */
struct list_head next;
struct tun_struct *detached;
@@ -313,32 +313,32 @@ static int tun_napi_poll(struct napi_struct *napi, int budget)
}
static void tun_napi_init(struct tun_struct *tun, struct tun_file *tfile,
- bool napi_en)
+ bool napi_en, bool napi_frags)
{
tfile->napi_enabled = napi_en;
+ tfile->napi_frags_enabled = napi_en && napi_frags;
if (napi_en) {
netif_napi_add(tun->dev, &tfile->napi, tun_napi_poll,
NAPI_POLL_WEIGHT);
napi_enable(&tfile->napi);
- mutex_init(&tfile->napi_mutex);
}
}
-static void tun_napi_disable(struct tun_struct *tun, struct tun_file *tfile)
+static void tun_napi_disable(struct tun_file *tfile)
{
if (tfile->napi_enabled)
napi_disable(&tfile->napi);
}
-static void tun_napi_del(struct tun_struct *tun, struct tun_file *tfile)
+static void tun_napi_del(struct tun_file *tfile)
{
if (tfile->napi_enabled)
netif_napi_del(&tfile->napi);
}
-static bool tun_napi_frags_enabled(const struct tun_struct *tun)
+static bool tun_napi_frags_enabled(const struct tun_file *tfile)
{
- return READ_ONCE(tun->flags) & IFF_NAPI_FRAGS;
+ return tfile->napi_frags_enabled;
}
#ifdef CONFIG_TUN_VNET_CROSS_LE
@@ -562,12 +562,11 @@ static inline void tun_flow_save_rps_rxhash(struct tun_flow_entry *e, u32 hash)
e->rps_rxhash = hash;
}
-/* We try to identify a flow through its rxhash first. The reason that
+/* We try to identify a flow through its rxhash. The reason that
* we do not check rxq no. is because some cards(e.g 82599), chooses
* the rxq based on the txq where the last packet of the flow comes. As
* the userspace application move between processors, we may get a
- * different rxq no. here. If we could not get rxhash, then we would
- * hope the rxq no. may help here.
+ * different rxq no. here.
*/
static u16 tun_automq_select_queue(struct tun_struct *tun, struct sk_buff *skb)
{
@@ -578,18 +577,13 @@ static u16 tun_automq_select_queue(struct tun_struct *tun, struct sk_buff *skb)
numqueues = READ_ONCE(tun->numqueues);
txq = __skb_get_hash_symmetric(skb);
- if (txq) {
- e = tun_flow_find(&tun->flows[tun_hashfn(txq)], txq);
- if (e) {
- tun_flow_save_rps_rxhash(e, txq);
- txq = e->queue_index;
- } else
- /* use multiply and shift instead of expensive divide */
- txq = ((u64)txq * numqueues) >> 32;
- } else if (likely(skb_rx_queue_recorded(skb))) {
- txq = skb_get_rx_queue(skb);
- while (unlikely(txq >= numqueues))
- txq -= numqueues;
+ e = tun_flow_find(&tun->flows[tun_hashfn(txq)], txq);
+ if (e) {
+ tun_flow_save_rps_rxhash(e, txq);
+ txq = e->queue_index;
+ } else {
+ /* use multiply and shift instead of expensive divide */
+ txq = ((u64)txq * numqueues) >> 32;
}
return txq;
@@ -690,8 +684,8 @@ static void __tun_detach(struct tun_file *tfile, bool clean)
tun = rtnl_dereference(tfile->tun);
if (tun && clean) {
- tun_napi_disable(tun, tfile);
- tun_napi_del(tun, tfile);
+ tun_napi_disable(tfile);
+ tun_napi_del(tfile);
}
if (tun && !tfile->detached) {
@@ -758,7 +752,7 @@ static void tun_detach_all(struct net_device *dev)
for (i = 0; i < n; i++) {
tfile = rtnl_dereference(tun->tfiles[i]);
BUG_ON(!tfile);
- tun_napi_disable(tun, tfile);
+ tun_napi_disable(tfile);
tfile->socket.sk->sk_shutdown = RCV_SHUTDOWN;
tfile->socket.sk->sk_data_ready(tfile->socket.sk);
RCU_INIT_POINTER(tfile->tun, NULL);
@@ -774,7 +768,7 @@ static void tun_detach_all(struct net_device *dev)
synchronize_net();
for (i = 0; i < n; i++) {
tfile = rtnl_dereference(tun->tfiles[i]);
- tun_napi_del(tun, tfile);
+ tun_napi_del(tfile);
/* Drop read queue */
tun_queue_purge(tfile);
xdp_rxq_info_unreg(&tfile->xdp_rxq);
@@ -793,7 +787,7 @@ static void tun_detach_all(struct net_device *dev)
}
static int tun_attach(struct tun_struct *tun, struct file *file,
- bool skip_filter, bool napi)
+ bool skip_filter, bool napi, bool napi_frags)
{
struct tun_file *tfile = file->private_data;
struct net_device *dev = tun->dev;
@@ -866,9 +860,12 @@ static int tun_attach(struct tun_struct *tun, struct file *file,
tun_enable_queue(tfile);
} else {
sock_hold(&tfile->sk);
- tun_napi_init(tun, tfile, napi);
+ tun_napi_init(tun, tfile, napi, napi_frags);
}
+ if (rtnl_dereference(tun->xdp_prog))
+ sock_set_flag(&tfile->sk, SOCK_XDP);
+
tun_set_real_num_queues(tun);
/* device is allowed to go away first, so no need to hold extra
@@ -1044,16 +1041,13 @@ static void tun_automq_xmit(struct tun_struct *tun, struct sk_buff *skb)
/* Select queue was not called for the skbuff, so we extract the
* RPS hash and save it into the flow_table here.
*/
+ struct tun_flow_entry *e;
__u32 rxhash;
rxhash = __skb_get_hash_symmetric(skb);
- if (rxhash) {
- struct tun_flow_entry *e;
- e = tun_flow_find(&tun->flows[tun_hashfn(rxhash)],
- rxhash);
- if (e)
- tun_flow_save_rps_rxhash(e, rxhash);
- }
+ e = tun_flow_find(&tun->flows[tun_hashfn(rxhash)], rxhash);
+ if (e)
+ tun_flow_save_rps_rxhash(e, rxhash);
}
#endif
}
@@ -1204,13 +1198,29 @@ static int tun_xdp_set(struct net_device *dev, struct bpf_prog *prog,
struct netlink_ext_ack *extack)
{
struct tun_struct *tun = netdev_priv(dev);
+ struct tun_file *tfile;
struct bpf_prog *old_prog;
+ int i;
old_prog = rtnl_dereference(tun->xdp_prog);
rcu_assign_pointer(tun->xdp_prog, prog);
if (old_prog)
bpf_prog_put(old_prog);
+ for (i = 0; i < tun->numqueues; i++) {
+ tfile = rtnl_dereference(tun->tfiles[i]);
+ if (prog)
+ sock_set_flag(&tfile->sk, SOCK_XDP);
+ else
+ sock_reset_flag(&tfile->sk, SOCK_XDP);
+ }
+ list_for_each_entry(tfile, &tun->disabled, next) {
+ if (prog)
+ sock_set_flag(&tfile->sk, SOCK_XDP);
+ else
+ sock_reset_flag(&tfile->sk, SOCK_XDP);
+ }
+
return 0;
}
@@ -1574,6 +1584,55 @@ static bool tun_can_build_skb(struct tun_struct *tun, struct tun_file *tfile,
return true;
}
+static struct sk_buff *__tun_build_skb(struct page_frag *alloc_frag, char *buf,
+ int buflen, int len, int pad)
+{
+ struct sk_buff *skb = build_skb(buf, buflen);
+
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ skb_reserve(skb, pad);
+ skb_put(skb, len);
+
+ get_page(alloc_frag->page);
+ alloc_frag->offset += buflen;
+
+ return skb;
+}
+
+static int tun_xdp_act(struct tun_struct *tun, struct bpf_prog *xdp_prog,
+ struct xdp_buff *xdp, u32 act)
+{
+ int err;
+
+ switch (act) {
+ case XDP_REDIRECT:
+ err = xdp_do_redirect(tun->dev, xdp, xdp_prog);
+ if (err)
+ return err;
+ break;
+ case XDP_TX:
+ err = tun_xdp_tx(tun->dev, xdp);
+ if (err < 0)
+ return err;
+ break;
+ case XDP_PASS:
+ break;
+ default:
+ bpf_warn_invalid_xdp_action(act);
+ /* fall through */
+ case XDP_ABORTED:
+ trace_xdp_exception(tun->dev, xdp_prog, act);
+ /* fall through */
+ case XDP_DROP:
+ this_cpu_inc(tun->pcpu_stats->rx_dropped);
+ break;
+ }
+
+ return act;
+}
+
static struct sk_buff *tun_build_skb(struct tun_struct *tun,
struct tun_file *tfile,
struct iov_iter *from,
@@ -1581,18 +1640,17 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun,
int len, int *skb_xdp)
{
struct page_frag *alloc_frag = &current->task_frag;
- struct sk_buff *skb;
struct bpf_prog *xdp_prog;
int buflen = SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
- unsigned int delta = 0;
char *buf;
size_t copied;
- int err, pad = TUN_RX_PAD;
+ int pad = TUN_RX_PAD;
+ int err = 0;
rcu_read_lock();
xdp_prog = rcu_dereference(tun->xdp_prog);
if (xdp_prog)
- pad += TUN_HEADROOM;
+ pad += XDP_PACKET_HEADROOM;
buflen += SKB_DATA_ALIGN(len + pad);
rcu_read_unlock();
@@ -1611,17 +1669,18 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun,
* of xdp_prog above, this should be rare and for simplicity
* we do XDP on skb in case the headroom is not enough.
*/
- if (hdr->gso_type || !xdp_prog)
+ if (hdr->gso_type || !xdp_prog) {
*skb_xdp = 1;
- else
- *skb_xdp = 0;
+ return __tun_build_skb(alloc_frag, buf, buflen, len, pad);
+ }
+
+ *skb_xdp = 0;
local_bh_disable();
rcu_read_lock();
xdp_prog = rcu_dereference(tun->xdp_prog);
- if (xdp_prog && !*skb_xdp) {
+ if (xdp_prog) {
struct xdp_buff xdp;
- void *orig_data;
u32 act;
xdp.data_hard_start = buf;
@@ -1629,66 +1688,33 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun,
xdp_set_data_meta_invalid(&xdp);
xdp.data_end = xdp.data + len;
xdp.rxq = &tfile->xdp_rxq;
- orig_data = xdp.data;
- act = bpf_prog_run_xdp(xdp_prog, &xdp);
- switch (act) {
- case XDP_REDIRECT:
- get_page(alloc_frag->page);
- alloc_frag->offset += buflen;
- err = xdp_do_redirect(tun->dev, &xdp, xdp_prog);
- xdp_do_flush_map();
- if (err)
- goto err_redirect;
- rcu_read_unlock();
- local_bh_enable();
- return NULL;
- case XDP_TX:
+ act = bpf_prog_run_xdp(xdp_prog, &xdp);
+ if (act == XDP_REDIRECT || act == XDP_TX) {
get_page(alloc_frag->page);
alloc_frag->offset += buflen;
- if (tun_xdp_tx(tun->dev, &xdp) < 0)
- goto err_redirect;
- rcu_read_unlock();
- local_bh_enable();
- return NULL;
- case XDP_PASS:
- delta = orig_data - xdp.data;
- len = xdp.data_end - xdp.data;
- break;
- default:
- bpf_warn_invalid_xdp_action(act);
- /* fall through */
- case XDP_ABORTED:
- trace_xdp_exception(tun->dev, xdp_prog, act);
- /* fall through */
- case XDP_DROP:
- goto err_xdp;
}
- }
+ err = tun_xdp_act(tun, xdp_prog, &xdp, act);
+ if (err < 0)
+ goto err_xdp;
+ if (err == XDP_REDIRECT)
+ xdp_do_flush_map();
+ if (err != XDP_PASS)
+ goto out;
- skb = build_skb(buf, buflen);
- if (!skb) {
- rcu_read_unlock();
- local_bh_enable();
- return ERR_PTR(-ENOMEM);
+ pad = xdp.data - xdp.data_hard_start;
+ len = xdp.data_end - xdp.data;
}
-
- skb_reserve(skb, pad - delta);
- skb_put(skb, len);
- get_page(alloc_frag->page);
- alloc_frag->offset += buflen;
-
rcu_read_unlock();
local_bh_enable();
- return skb;
+ return __tun_build_skb(alloc_frag, buf, buflen, len, pad);
-err_redirect:
- put_page(alloc_frag->page);
err_xdp:
+ put_page(alloc_frag->page);
+out:
rcu_read_unlock();
local_bh_enable();
- this_cpu_inc(tun->pcpu_stats->rx_dropped);
return NULL;
}
@@ -1709,7 +1735,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
int err;
u32 rxhash = 0;
int skb_xdp = 1;
- bool frags = tun_napi_frags_enabled(tun);
+ bool frags = tun_napi_frags_enabled(tfile);
if (!(tun->dev->flags & IFF_UP))
return -EIO;
@@ -2263,6 +2289,8 @@ static void tun_setup(struct net_device *dev)
static int tun_validate(struct nlattr *tb[], struct nlattr *data[],
struct netlink_ext_ack *extack)
{
+ if (!data)
+ return 0;
return -EINVAL;
}
@@ -2349,18 +2377,133 @@ static void tun_sock_write_space(struct sock *sk)
kill_fasync(&tfile->fasync, SIGIO, POLL_OUT);
}
+static int tun_xdp_one(struct tun_struct *tun,
+ struct tun_file *tfile,
+ struct xdp_buff *xdp, int *flush)
+{
+ struct tun_xdp_hdr *hdr = xdp->data_hard_start;
+ struct virtio_net_hdr *gso = &hdr->gso;
+ struct tun_pcpu_stats *stats;
+ struct bpf_prog *xdp_prog;
+ struct sk_buff *skb = NULL;
+ u32 rxhash = 0, act;
+ int buflen = hdr->buflen;
+ int err = 0;
+ bool skb_xdp = false;
+
+ xdp_prog = rcu_dereference(tun->xdp_prog);
+ if (xdp_prog) {
+ if (gso->gso_type) {
+ skb_xdp = true;
+ goto build;
+ }
+ xdp_set_data_meta_invalid(xdp);
+ xdp->rxq = &tfile->xdp_rxq;
+
+ act = bpf_prog_run_xdp(xdp_prog, xdp);
+ err = tun_xdp_act(tun, xdp_prog, xdp, act);
+ if (err < 0) {
+ put_page(virt_to_head_page(xdp->data));
+ return err;
+ }
+
+ switch (err) {
+ case XDP_REDIRECT:
+ *flush = true;
+ /* fall through */
+ case XDP_TX:
+ return 0;
+ case XDP_PASS:
+ break;
+ default:
+ put_page(virt_to_head_page(xdp->data));
+ return 0;
+ }
+ }
+
+build:
+ skb = build_skb(xdp->data_hard_start, buflen);
+ if (!skb) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ skb_reserve(skb, xdp->data - xdp->data_hard_start);
+ skb_put(skb, xdp->data_end - xdp->data);
+
+ if (virtio_net_hdr_to_skb(skb, gso, tun_is_little_endian(tun))) {
+ this_cpu_inc(tun->pcpu_stats->rx_frame_errors);
+ kfree_skb(skb);
+ err = -EINVAL;
+ goto out;
+ }
+
+ skb->protocol = eth_type_trans(skb, tun->dev);
+ skb_reset_network_header(skb);
+ skb_probe_transport_header(skb, 0);
+
+ if (skb_xdp) {
+ err = do_xdp_generic(xdp_prog, skb);
+ if (err != XDP_PASS)
+ goto out;
+ }
+
+ if (!rcu_dereference(tun->steering_prog))
+ rxhash = __skb_get_hash_symmetric(skb);
+
+ netif_receive_skb(skb);
+
+ stats = get_cpu_ptr(tun->pcpu_stats);
+ u64_stats_update_begin(&stats->syncp);
+ stats->rx_packets++;
+ stats->rx_bytes += skb->len;
+ u64_stats_update_end(&stats->syncp);
+ put_cpu_ptr(stats);
+
+ if (rxhash)
+ tun_flow_update(tun, rxhash, tfile);
+
+out:
+ return err;
+}
+
static int tun_sendmsg(struct socket *sock, struct msghdr *m, size_t total_len)
{
- int ret;
+ int ret, i;
struct tun_file *tfile = container_of(sock, struct tun_file, socket);
struct tun_struct *tun = tun_get(tfile);
+ struct tun_msg_ctl *ctl = m->msg_control;
+ struct xdp_buff *xdp;
if (!tun)
return -EBADFD;
- ret = tun_get_user(tun, tfile, m->msg_control, &m->msg_iter,
+ if (ctl && (ctl->type == TUN_MSG_PTR)) {
+ int n = ctl->num;
+ int flush = 0;
+
+ local_bh_disable();
+ rcu_read_lock();
+
+ for (i = 0; i < n; i++) {
+ xdp = &((struct xdp_buff *)ctl->ptr)[i];
+ tun_xdp_one(tun, tfile, xdp, &flush);
+ }
+
+ if (flush)
+ xdp_do_flush_map();
+
+ rcu_read_unlock();
+ local_bh_enable();
+
+ ret = total_len;
+ goto out;
+ }
+
+ ret = tun_get_user(tun, tfile, ctl ? ctl->ptr : NULL, &m->msg_iter,
m->msg_flags & MSG_DONTWAIT,
m->msg_flags & MSG_MORE);
+out:
tun_put(tun);
return ret;
}
@@ -2534,7 +2677,8 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
return err;
err = tun_attach(tun, file, ifr->ifr_flags & IFF_NOFILTER,
- ifr->ifr_flags & IFF_NAPI);
+ ifr->ifr_flags & IFF_NAPI,
+ ifr->ifr_flags & IFF_NAPI_FRAGS);
if (err < 0)
return err;
@@ -2632,7 +2776,8 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
(ifr->ifr_flags & TUN_FEATURES);
INIT_LIST_HEAD(&tun->disabled);
- err = tun_attach(tun, file, false, ifr->ifr_flags & IFF_NAPI);
+ err = tun_attach(tun, file, false, ifr->ifr_flags & IFF_NAPI,
+ ifr->ifr_flags & IFF_NAPI_FRAGS);
if (err < 0)
goto err_free_flow;
@@ -2781,7 +2926,8 @@ static int tun_set_queue(struct file *file, struct ifreq *ifr)
ret = security_tun_dev_attach_queue(tun->security);
if (ret < 0)
goto unlock;
- ret = tun_attach(tun, file, false, tun->flags & IFF_NAPI);
+ ret = tun_attach(tun, file, false, tun->flags & IFF_NAPI,
+ tun->flags & IFF_NAPI_FRAGS);
} else if (ifr->ifr_flags & IFF_DETACH_QUEUE) {
tun = rtnl_dereference(tfile->tun);
if (!tun || !(tun->flags & IFF_MULTI_QUEUE) || tfile->detached)
@@ -3199,6 +3345,7 @@ static int tun_chr_open(struct inode *inode, struct file * file)
return -ENOMEM;
}
+ mutex_init(&tfile->napi_mutex);
RCU_INIT_POINTER(tfile->tun, NULL);
tfile->flags = 0;
tfile->ifindex = 0;
diff --git a/drivers/net/usb/asix_common.c b/drivers/net/usb/asix_common.c
index e95dd12edec4..023b8d0bf175 100644
--- a/drivers/net/usb/asix_common.c
+++ b/drivers/net/usb/asix_common.c
@@ -607,6 +607,9 @@ int asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
struct usbnet *dev = netdev_priv(net);
u8 opt = 0;
+ if (wolinfo->wolopts & ~(WAKE_PHY | WAKE_MAGIC))
+ return -EINVAL;
+
if (wolinfo->wolopts & WAKE_PHY)
opt |= AX_MONITOR_LINK;
if (wolinfo->wolopts & WAKE_MAGIC)
diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c
index 9e8ad372f419..2207f7a7d1ff 100644
--- a/drivers/net/usb/ax88179_178a.c
+++ b/drivers/net/usb/ax88179_178a.c
@@ -566,6 +566,9 @@ ax88179_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
struct usbnet *dev = netdev_priv(net);
u8 opt = 0;
+ if (wolinfo->wolopts & ~(WAKE_PHY | WAKE_MAGIC))
+ return -EINVAL;
+
if (wolinfo->wolopts & WAKE_PHY)
opt |= AX_MONITOR_MODE_RWLC;
if (wolinfo->wolopts & WAKE_MAGIC)
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index 1eaec648bd1f..50c05d0f44cb 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -779,8 +779,7 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_
hrtimer_init(&ctx->tx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
ctx->tx_timer.function = &cdc_ncm_tx_timer_cb;
- ctx->bh.data = (unsigned long)dev;
- ctx->bh.func = cdc_ncm_txpath_bh;
+ tasklet_init(&ctx->bh, cdc_ncm_txpath_bh, (unsigned long)dev);
atomic_set(&ctx->stop, 0);
spin_lock_init(&ctx->mtx);
@@ -1601,11 +1600,8 @@ cdc_ncm_speed_change(struct usbnet *dev,
static void cdc_ncm_status(struct usbnet *dev, struct urb *urb)
{
- struct cdc_ncm_ctx *ctx;
struct usb_cdc_notification *event;
- ctx = (struct cdc_ncm_ctx *)dev->data[0];
-
if (urb->actual_length < sizeof(*event))
return;
diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c
index a9991c5f4736..be1917be28f2 100644
--- a/drivers/net/usb/lan78xx.c
+++ b/drivers/net/usb/lan78xx.c
@@ -1,18 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2015 Microchip Technology
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/version.h>
#include <linux/module.h>
@@ -948,11 +936,9 @@ static int lan78xx_read_otp(struct lan78xx_net *dev, u32 offset,
ret = lan78xx_read_raw_otp(dev, 0, 1, &sig);
if (ret == 0) {
- if (sig == OTP_INDICATOR_1)
- offset = offset;
- else if (sig == OTP_INDICATOR_2)
+ if (sig == OTP_INDICATOR_2)
offset += 0x100;
- else
+ else if (sig != OTP_INDICATOR_1)
ret = -EINVAL;
if (!ret)
ret = lan78xx_read_raw_otp(dev, offset, length, data);
@@ -1027,7 +1013,7 @@ done:
static void lan78xx_set_addr_filter(struct lan78xx_priv *pdata,
int index, u8 addr[ETH_ALEN])
{
- u32 temp;
+ u32 temp;
if ((pdata) && (index > 0) && (index < NUM_OF_MAF)) {
temp = addr[3];
@@ -1401,19 +1387,10 @@ static int lan78xx_set_wol(struct net_device *netdev,
if (ret < 0)
return ret;
- pdata->wol = 0;
- if (wol->wolopts & WAKE_UCAST)
- pdata->wol |= WAKE_UCAST;
- if (wol->wolopts & WAKE_MCAST)
- pdata->wol |= WAKE_MCAST;
- if (wol->wolopts & WAKE_BCAST)
- pdata->wol |= WAKE_BCAST;
- if (wol->wolopts & WAKE_MAGIC)
- pdata->wol |= WAKE_MAGIC;
- if (wol->wolopts & WAKE_PHY)
- pdata->wol |= WAKE_PHY;
- if (wol->wolopts & WAKE_ARP)
- pdata->wol |= WAKE_ARP;
+ if (wol->wolopts & ~WAKE_ALL)
+ return -EINVAL;
+
+ pdata->wol = wol->wolopts;
device_set_wakeup_enable(&dev->udev->dev, (bool)wol->wolopts);
@@ -1847,8 +1824,7 @@ static int lan78xx_mdio_init(struct lan78xx_net *dev)
node = of_get_child_by_name(dev->udev->dev.of_node, "mdio");
ret = of_mdiobus_register(dev->mdiobus, node);
- if (node)
- of_node_put(node);
+ of_node_put(node);
if (ret) {
netdev_err(dev->net, "can't register MDIO bus\n");
goto exit1;
@@ -2178,7 +2154,7 @@ static int lan78xx_phy_init(struct lan78xx_net *dev)
}
/* MAC doesn't support 1000T Half */
- phydev->supported &= ~SUPPORTED_1000baseT_Half;
+ phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
/* support both flow controls */
dev->fc_request_control = (FLOW_CTRL_RX | FLOW_CTRL_TX);
@@ -2702,7 +2678,7 @@ static void lan78xx_terminate_urbs(struct lan78xx_net *dev)
static int lan78xx_stop(struct net_device *net)
{
- struct lan78xx_net *dev = netdev_priv(net);
+ struct lan78xx_net *dev = netdev_priv(net);
if (timer_pending(&dev->stat_monitor))
del_timer_sync(&dev->stat_monitor);
@@ -2952,6 +2928,11 @@ static int lan78xx_bind(struct lan78xx_net *dev, struct usb_interface *intf)
int i;
ret = lan78xx_get_endpoints(dev, intf);
+ if (ret) {
+ netdev_warn(dev->net, "lan78xx_get_endpoints failed: %d\n",
+ ret);
+ return ret;
+ }
dev->data[0] = (unsigned long)kzalloc(sizeof(*pdata), GFP_KERNEL);
@@ -3080,7 +3061,7 @@ static void lan78xx_rx_vlan_offload(struct lan78xx_net *dev,
static void lan78xx_skb_return(struct lan78xx_net *dev, struct sk_buff *skb)
{
- int status;
+ int status;
if (test_bit(EVENT_RX_PAUSED, &dev->flags)) {
skb_queue_tail(&dev->rxq_pause, skb);
@@ -3347,9 +3328,9 @@ static void lan78xx_tx_bh(struct lan78xx_net *dev)
count = 0;
length = 0;
spin_lock_irqsave(&tqp->lock, flags);
- for (skb = tqp->next; pkt_cnt < tqp->qlen; skb = skb->next) {
+ skb_queue_walk(tqp, skb) {
if (skb_is_gso(skb)) {
- if (pkt_cnt) {
+ if (!skb_queue_is_first(tqp, skb)) {
/* handle previous packets first */
break;
}
@@ -3640,10 +3621,10 @@ static void intr_complete(struct urb *urb)
static void lan78xx_disconnect(struct usb_interface *intf)
{
- struct lan78xx_net *dev;
- struct usb_device *udev;
- struct net_device *net;
- struct phy_device *phydev;
+ struct lan78xx_net *dev;
+ struct usb_device *udev;
+ struct net_device *net;
+ struct phy_device *phydev;
dev = usb_get_intfdata(intf);
usb_set_intfdata(intf, NULL);
@@ -3761,7 +3742,6 @@ static int lan78xx_probe(struct usb_interface *intf,
ret = lan78xx_bind(dev, intf);
if (ret < 0)
goto out2;
- strcpy(netdev->name, "eth%d");
if (netdev->mtu > (dev->hard_mtu - netdev->hard_header_len))
netdev->mtu = dev->hard_mtu - netdev->hard_header_len;
diff --git a/drivers/net/usb/lan78xx.h b/drivers/net/usb/lan78xx.h
index 25aa54611774..968e5e5faee0 100644
--- a/drivers/net/usb/lan78xx.h
+++ b/drivers/net/usb/lan78xx.h
@@ -1,18 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2015 Microchip Technology
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _LAN78XX_H
#define _LAN78XX_H
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index 533b6fb8d923..72a55b6b4211 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -1241,6 +1241,7 @@ static const struct usb_device_id products[] = {
{QMI_FIXED_INTF(0x0b3c, 0xc00b, 4)}, /* Olivetti Olicard 500 */
{QMI_FIXED_INTF(0x1e2d, 0x0060, 4)}, /* Cinterion PLxx */
{QMI_FIXED_INTF(0x1e2d, 0x0053, 4)}, /* Cinterion PHxx,PXxx */
+ {QMI_FIXED_INTF(0x1e2d, 0x0063, 10)}, /* Cinterion ALASxx (1 RmNet) */
{QMI_FIXED_INTF(0x1e2d, 0x0082, 4)}, /* Cinterion PHxx,PXxx (2 RmNet) */
{QMI_FIXED_INTF(0x1e2d, 0x0082, 5)}, /* Cinterion PHxx,PXxx (2 RmNet) */
{QMI_FIXED_INTF(0x1e2d, 0x0083, 4)}, /* Cinterion PHxx,PXxx (1 RmNet + USB Audio)*/
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index 2cd71bdb6484..f1b5201cc320 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -4506,6 +4506,9 @@ static int rtl8152_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
if (!rtl_can_wakeup(tp))
return -EOPNOTSUPP;
+ if (wol->wolopts & ~WAKE_ANY)
+ return -EINVAL;
+
ret = usb_autopm_get_interface(tp->intf);
if (ret < 0)
goto out_set_wol;
diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c
index 05553d252446..ec287c9741e8 100644
--- a/drivers/net/usb/smsc75xx.c
+++ b/drivers/net/usb/smsc75xx.c
@@ -731,6 +731,9 @@ static int smsc75xx_ethtool_set_wol(struct net_device *net,
struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
int ret;
+ if (wolinfo->wolopts & ~SUPPORTED_WAKE)
+ return -EINVAL;
+
pdata->wolopts = wolinfo->wolopts & SUPPORTED_WAKE;
ret = device_set_wakeup_enable(&dev->udev->dev, pdata->wolopts);
@@ -1517,6 +1520,7 @@ static void smsc75xx_unbind(struct usbnet *dev, struct usb_interface *intf)
{
struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
if (pdata) {
+ cancel_work_sync(&pdata->set_multicast);
netif_dbg(dev, ifdown, dev->net, "free pdata\n");
kfree(pdata);
pdata = NULL;
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index 06b4d290784d..f2d01cb6f958 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -774,6 +774,9 @@ static int smsc95xx_ethtool_set_wol(struct net_device *net,
struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
int ret;
+ if (wolinfo->wolopts & ~SUPPORTED_WAKE)
+ return -EINVAL;
+
pdata->wolopts = wolinfo->wolopts & SUPPORTED_WAKE;
ret = device_set_wakeup_enable(&dev->udev->dev, pdata->wolopts);
@@ -1318,6 +1321,8 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf)
dev->net->ethtool_ops = &smsc95xx_ethtool_ops;
dev->net->flags |= IFF_MULTICAST;
dev->net->hard_header_len += SMSC95XX_TX_OVERHEAD_CSUM;
+ dev->net->min_mtu = ETH_MIN_MTU;
+ dev->net->max_mtu = ETH_DATA_LEN;
dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
pdata->dev = dev;
@@ -1595,6 +1600,8 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
return ret;
}
+ cancel_delayed_work_sync(&pdata->carrier_check);
+
if (pdata->suspend_flags) {
netdev_warn(dev->net, "error during last resume\n");
pdata->suspend_flags = 0;
@@ -1837,6 +1844,11 @@ done:
*/
if (ret && PMSG_IS_AUTO(message))
usbnet_resume(intf);
+
+ if (ret)
+ schedule_delayed_work(&pdata->carrier_check,
+ CARRIER_CHECK_DELAY);
+
return ret;
}
diff --git a/drivers/net/usb/sr9800.c b/drivers/net/usb/sr9800.c
index 9277a0f228df..35f39f23d881 100644
--- a/drivers/net/usb/sr9800.c
+++ b/drivers/net/usb/sr9800.c
@@ -421,6 +421,9 @@ sr_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
struct usbnet *dev = netdev_priv(net);
u8 opt = 0;
+ if (wolinfo->wolopts & ~(WAKE_PHY | WAKE_MAGIC))
+ return -EINVAL;
+
if (wolinfo->wolopts & WAKE_PHY)
opt |= SR_MONITOR_LINK;
if (wolinfo->wolopts & WAKE_MAGIC)
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 770aa624147f..504282af27e5 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -802,7 +802,7 @@ static void usbnet_terminate_urbs(struct usbnet *dev)
int usbnet_stop (struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);
- struct driver_info *info = dev->driver_info;
+ const struct driver_info *info = dev->driver_info;
int retval, pm, mpn;
clear_bit(EVENT_DEV_OPEN, &dev->flags);
@@ -865,7 +865,7 @@ int usbnet_open (struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);
int retval;
- struct driver_info *info = dev->driver_info;
+ const struct driver_info *info = dev->driver_info;
if ((retval = usb_autopm_get_interface(dev->intf)) < 0) {
netif_info(dev, ifup, dev->net,
@@ -1205,7 +1205,7 @@ fail_lowmem:
}
if (test_bit (EVENT_LINK_RESET, &dev->flags)) {
- struct driver_info *info = dev->driver_info;
+ const struct driver_info *info = dev->driver_info;
int retval = 0;
clear_bit (EVENT_LINK_RESET, &dev->flags);
@@ -1353,7 +1353,7 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
unsigned int length;
struct urb *urb = NULL;
struct skb_data *entry;
- struct driver_info *info = dev->driver_info;
+ const struct driver_info *info = dev->driver_info;
unsigned long flags;
int retval;
@@ -1527,6 +1527,7 @@ static void usbnet_bh (struct timer_list *t)
continue;
case tx_done:
kfree(entry->urb->sg);
+ /* fall through */
case rx_cleanup:
usb_free_urb (entry->urb);
dev_kfree_skb (skb);
@@ -1646,7 +1647,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
struct usbnet *dev;
struct net_device *net;
struct usb_host_interface *interface;
- struct driver_info *info;
+ const struct driver_info *info;
struct usb_device *xdev;
int status;
const char *name;
@@ -1662,7 +1663,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
}
name = udev->dev.driver->name;
- info = (struct driver_info *) prod->driver_info;
+ info = (const struct driver_info *) prod->driver_info;
if (!info) {
dev_dbg (&udev->dev, "blacklisted by %s\n", name);
return -ENODEV;
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 41a00cd76955..890fa5b905e2 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -24,6 +24,7 @@
#include <linux/filter.h>
#include <linux/ptr_ring.h>
#include <linux/bpf_trace.h>
+#include <linux/net_tstamp.h>
#define DRV_NAME "veth"
#define DRV_VERSION "1.0"
@@ -36,9 +37,10 @@
#define VETH_XDP_TX BIT(0)
#define VETH_XDP_REDIR BIT(1)
-struct pcpu_vstats {
- u64 packets;
- u64 bytes;
+struct veth_rq_stats {
+ u64 xdp_packets;
+ u64 xdp_bytes;
+ u64 xdp_drops;
struct u64_stats_sync syncp;
};
@@ -47,6 +49,7 @@ struct veth_rq {
struct net_device *dev;
struct bpf_prog __rcu *xdp_prog;
struct xdp_mem_info xdp_mem;
+ struct veth_rq_stats stats;
bool rx_notify_masked;
struct ptr_ring xdp_ring;
struct xdp_rxq_info xdp_rxq;
@@ -64,6 +67,21 @@ struct veth_priv {
* ethtool interface
*/
+struct veth_q_stat_desc {
+ char desc[ETH_GSTRING_LEN];
+ size_t offset;
+};
+
+#define VETH_RQ_STAT(m) offsetof(struct veth_rq_stats, m)
+
+static const struct veth_q_stat_desc veth_rq_stats_desc[] = {
+ { "xdp_packets", VETH_RQ_STAT(xdp_packets) },
+ { "xdp_bytes", VETH_RQ_STAT(xdp_bytes) },
+ { "xdp_drops", VETH_RQ_STAT(xdp_drops) },
+};
+
+#define VETH_RQ_STATS_LEN ARRAY_SIZE(veth_rq_stats_desc)
+
static struct {
const char string[ETH_GSTRING_LEN];
} ethtool_stats_keys[] = {
@@ -88,9 +106,20 @@ static void veth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *inf
static void veth_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
{
+ char *p = (char *)buf;
+ int i, j;
+
switch(stringset) {
case ETH_SS_STATS:
- memcpy(buf, &ethtool_stats_keys, sizeof(ethtool_stats_keys));
+ memcpy(p, &ethtool_stats_keys, sizeof(ethtool_stats_keys));
+ p += sizeof(ethtool_stats_keys);
+ for (i = 0; i < dev->real_num_rx_queues; i++) {
+ for (j = 0; j < VETH_RQ_STATS_LEN; j++) {
+ snprintf(p, ETH_GSTRING_LEN, "rx_queue_%u_%s",
+ i, veth_rq_stats_desc[j].desc);
+ p += ETH_GSTRING_LEN;
+ }
+ }
break;
}
}
@@ -99,7 +128,8 @@ static int veth_get_sset_count(struct net_device *dev, int sset)
{
switch (sset) {
case ETH_SS_STATS:
- return ARRAY_SIZE(ethtool_stats_keys);
+ return ARRAY_SIZE(ethtool_stats_keys) +
+ VETH_RQ_STATS_LEN * dev->real_num_rx_queues;
default:
return -EOPNOTSUPP;
}
@@ -110,8 +140,37 @@ static void veth_get_ethtool_stats(struct net_device *dev,
{
struct veth_priv *priv = netdev_priv(dev);
struct net_device *peer = rtnl_dereference(priv->peer);
+ int i, j, idx;
data[0] = peer ? peer->ifindex : 0;
+ idx = 1;
+ for (i = 0; i < dev->real_num_rx_queues; i++) {
+ const struct veth_rq_stats *rq_stats = &priv->rq[i].stats;
+ const void *stats_base = (void *)rq_stats;
+ unsigned int start;
+ size_t offset;
+
+ do {
+ start = u64_stats_fetch_begin_irq(&rq_stats->syncp);
+ for (j = 0; j < VETH_RQ_STATS_LEN; j++) {
+ offset = veth_rq_stats_desc[j].offset;
+ data[idx + j] = *(u64 *)(stats_base + offset);
+ }
+ } while (u64_stats_fetch_retry_irq(&rq_stats->syncp, start));
+ idx += VETH_RQ_STATS_LEN;
+ }
+}
+
+static int veth_get_ts_info(struct net_device *dev,
+ struct ethtool_ts_info *info)
+{
+ info->so_timestamping =
+ SOF_TIMESTAMPING_TX_SOFTWARE |
+ SOF_TIMESTAMPING_RX_SOFTWARE |
+ SOF_TIMESTAMPING_SOFTWARE;
+ info->phc_index = -1;
+
+ return 0;
}
static const struct ethtool_ops veth_ethtool_ops = {
@@ -121,6 +180,7 @@ static const struct ethtool_ops veth_ethtool_ops = {
.get_sset_count = veth_get_sset_count,
.get_ethtool_stats = veth_get_ethtool_stats,
.get_link_ksettings = veth_get_link_ksettings,
+ .get_ts_info = veth_get_ts_info,
};
/* general routines */
@@ -201,13 +261,16 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev)
skb_record_rx_queue(skb, rxq);
}
+ skb_tx_timestamp(skb);
if (likely(veth_forward_skb(rcv, skb, rq, rcv_xdp) == NET_RX_SUCCESS)) {
- struct pcpu_vstats *stats = this_cpu_ptr(dev->vstats);
+ if (!rcv_xdp) {
+ struct pcpu_lstats *stats = this_cpu_ptr(dev->lstats);
- u64_stats_update_begin(&stats->syncp);
- stats->bytes += length;
- stats->packets++;
- u64_stats_update_end(&stats->syncp);
+ u64_stats_update_begin(&stats->syncp);
+ stats->bytes += length;
+ stats->packets++;
+ u64_stats_update_end(&stats->syncp);
+ }
} else {
drop:
atomic64_inc(&priv->dropped);
@@ -221,7 +284,7 @@ drop:
return NETDEV_TX_OK;
}
-static u64 veth_stats_one(struct pcpu_vstats *result, struct net_device *dev)
+static u64 veth_stats_tx(struct pcpu_lstats *result, struct net_device *dev)
{
struct veth_priv *priv = netdev_priv(dev);
int cpu;
@@ -229,7 +292,7 @@ static u64 veth_stats_one(struct pcpu_vstats *result, struct net_device *dev)
result->packets = 0;
result->bytes = 0;
for_each_possible_cpu(cpu) {
- struct pcpu_vstats *stats = per_cpu_ptr(dev->vstats, cpu);
+ struct pcpu_lstats *stats = per_cpu_ptr(dev->lstats, cpu);
u64 packets, bytes;
unsigned int start;
@@ -244,23 +307,58 @@ static u64 veth_stats_one(struct pcpu_vstats *result, struct net_device *dev)
return atomic64_read(&priv->dropped);
}
+static void veth_stats_rx(struct veth_rq_stats *result, struct net_device *dev)
+{
+ struct veth_priv *priv = netdev_priv(dev);
+ int i;
+
+ result->xdp_packets = 0;
+ result->xdp_bytes = 0;
+ result->xdp_drops = 0;
+ for (i = 0; i < dev->num_rx_queues; i++) {
+ struct veth_rq_stats *stats = &priv->rq[i].stats;
+ u64 packets, bytes, drops;
+ unsigned int start;
+
+ do {
+ start = u64_stats_fetch_begin_irq(&stats->syncp);
+ packets = stats->xdp_packets;
+ bytes = stats->xdp_bytes;
+ drops = stats->xdp_drops;
+ } while (u64_stats_fetch_retry_irq(&stats->syncp, start));
+ result->xdp_packets += packets;
+ result->xdp_bytes += bytes;
+ result->xdp_drops += drops;
+ }
+}
+
static void veth_get_stats64(struct net_device *dev,
struct rtnl_link_stats64 *tot)
{
struct veth_priv *priv = netdev_priv(dev);
struct net_device *peer;
- struct pcpu_vstats one;
+ struct veth_rq_stats rx;
+ struct pcpu_lstats tx;
+
+ tot->tx_dropped = veth_stats_tx(&tx, dev);
+ tot->tx_bytes = tx.bytes;
+ tot->tx_packets = tx.packets;
- tot->tx_dropped = veth_stats_one(&one, dev);
- tot->tx_bytes = one.bytes;
- tot->tx_packets = one.packets;
+ veth_stats_rx(&rx, dev);
+ tot->rx_dropped = rx.xdp_drops;
+ tot->rx_bytes = rx.xdp_bytes;
+ tot->rx_packets = rx.xdp_packets;
rcu_read_lock();
peer = rcu_dereference(priv->peer);
if (peer) {
- tot->rx_dropped = veth_stats_one(&one, peer);
- tot->rx_bytes = one.bytes;
- tot->rx_packets = one.packets;
+ tot->rx_dropped += veth_stats_tx(&tx, peer);
+ tot->rx_bytes += tx.bytes;
+ tot->rx_packets += tx.packets;
+
+ veth_stats_rx(&rx, peer);
+ tot->tx_bytes += rx.xdp_bytes;
+ tot->tx_packets += rx.xdp_packets;
}
rcu_read_unlock();
}
@@ -299,16 +397,20 @@ static int veth_xdp_xmit(struct net_device *dev, int n,
{
struct veth_priv *rcv_priv, *priv = netdev_priv(dev);
struct net_device *rcv;
+ int i, ret, drops = n;
unsigned int max_len;
struct veth_rq *rq;
- int i, drops = 0;
- if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK))
- return -EINVAL;
+ if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK)) {
+ ret = -EINVAL;
+ goto drop;
+ }
rcv = rcu_dereference(priv->peer);
- if (unlikely(!rcv))
- return -ENXIO;
+ if (unlikely(!rcv)) {
+ ret = -ENXIO;
+ goto drop;
+ }
rcv_priv = netdev_priv(rcv);
rq = &rcv_priv->rq[veth_select_rxq(rcv)];
@@ -316,9 +418,12 @@ static int veth_xdp_xmit(struct net_device *dev, int n,
* side. This means an XDP program is loaded on the peer and the peer
* device is up.
*/
- if (!rcu_access_pointer(rq->xdp_prog))
- return -ENXIO;
+ if (!rcu_access_pointer(rq->xdp_prog)) {
+ ret = -ENXIO;
+ goto drop;
+ }
+ drops = 0;
max_len = rcv->mtu + rcv->hard_header_len + VLAN_HLEN;
spin_lock(&rq->xdp_ring.producer_lock);
@@ -337,7 +442,14 @@ static int veth_xdp_xmit(struct net_device *dev, int n,
if (flags & XDP_XMIT_FLUSH)
__veth_xdp_flush(rq);
- return n - drops;
+ if (likely(!drops))
+ return n;
+
+ ret = n - drops;
+drop:
+ atomic64_add(drops, &priv->dropped);
+
+ return ret;
}
static void veth_xdp_flush(struct net_device *dev)
@@ -586,28 +698,42 @@ xdp_xmit:
static int veth_xdp_rcv(struct veth_rq *rq, int budget, unsigned int *xdp_xmit)
{
- int i, done = 0;
+ int i, done = 0, drops = 0, bytes = 0;
for (i = 0; i < budget; i++) {
void *ptr = __ptr_ring_consume(&rq->xdp_ring);
+ unsigned int xdp_xmit_one = 0;
struct sk_buff *skb;
if (!ptr)
break;
if (veth_is_xdp_frame(ptr)) {
- skb = veth_xdp_rcv_one(rq, veth_ptr_to_xdp(ptr),
- xdp_xmit);
+ struct xdp_frame *frame = veth_ptr_to_xdp(ptr);
+
+ bytes += frame->len;
+ skb = veth_xdp_rcv_one(rq, frame, &xdp_xmit_one);
} else {
- skb = veth_xdp_rcv_skb(rq, ptr, xdp_xmit);
+ skb = ptr;
+ bytes += skb->len;
+ skb = veth_xdp_rcv_skb(rq, skb, &xdp_xmit_one);
}
+ *xdp_xmit |= xdp_xmit_one;
if (skb)
napi_gro_receive(&rq->xdp_napi, skb);
+ else if (!xdp_xmit_one)
+ drops++;
done++;
}
+ u64_stats_update_begin(&rq->stats.syncp);
+ rq->stats.xdp_packets += done;
+ rq->stats.xdp_bytes += bytes;
+ rq->stats.xdp_drops += drops;
+ u64_stats_update_end(&rq->stats.syncp);
+
return done;
}
@@ -798,8 +924,10 @@ static int veth_alloc_queues(struct net_device *dev)
if (!priv->rq)
return -ENOMEM;
- for (i = 0; i < dev->num_rx_queues; i++)
+ for (i = 0; i < dev->num_rx_queues; i++) {
priv->rq[i].dev = dev;
+ u64_stats_init(&priv->rq[i].stats.syncp);
+ }
return 0;
}
@@ -815,13 +943,13 @@ static int veth_dev_init(struct net_device *dev)
{
int err;
- dev->vstats = netdev_alloc_pcpu_stats(struct pcpu_vstats);
- if (!dev->vstats)
+ dev->lstats = netdev_alloc_pcpu_stats(struct pcpu_lstats);
+ if (!dev->lstats)
return -ENOMEM;
err = veth_alloc_queues(dev);
if (err) {
- free_percpu(dev->vstats);
+ free_percpu(dev->lstats);
return err;
}
@@ -831,7 +959,7 @@ static int veth_dev_init(struct net_device *dev)
static void veth_dev_free(struct net_device *dev)
{
veth_free_queues(dev);
- free_percpu(dev->vstats);
+ free_percpu(dev->lstats);
}
#ifdef CONFIG_NET_POLL_CONTROLLER
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 765920905226..3e2c041d76ac 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -1699,17 +1699,6 @@ static void virtnet_stats(struct net_device *dev,
tot->rx_frame_errors = dev->stats.rx_frame_errors;
}
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void virtnet_netpoll(struct net_device *dev)
-{
- struct virtnet_info *vi = netdev_priv(dev);
- int i;
-
- for (i = 0; i < vi->curr_queue_pairs; i++)
- napi_schedule(&vi->rq[i].napi);
-}
-#endif
-
static void virtnet_ack_link_announce(struct virtnet_info *vi)
{
rtnl_lock();
@@ -2181,6 +2170,53 @@ static int virtnet_get_link_ksettings(struct net_device *dev,
return 0;
}
+static int virtnet_set_coalesce(struct net_device *dev,
+ struct ethtool_coalesce *ec)
+{
+ struct ethtool_coalesce ec_default = {
+ .cmd = ETHTOOL_SCOALESCE,
+ .rx_max_coalesced_frames = 1,
+ };
+ struct virtnet_info *vi = netdev_priv(dev);
+ int i, napi_weight;
+
+ if (ec->tx_max_coalesced_frames > 1)
+ return -EINVAL;
+
+ ec_default.tx_max_coalesced_frames = ec->tx_max_coalesced_frames;
+ napi_weight = ec->tx_max_coalesced_frames ? NAPI_POLL_WEIGHT : 0;
+
+ /* disallow changes to fields not explicitly tested above */
+ if (memcmp(ec, &ec_default, sizeof(ec_default)))
+ return -EINVAL;
+
+ if (napi_weight ^ vi->sq[0].napi.weight) {
+ if (dev->flags & IFF_UP)
+ return -EBUSY;
+ for (i = 0; i < vi->max_queue_pairs; i++)
+ vi->sq[i].napi.weight = napi_weight;
+ }
+
+ return 0;
+}
+
+static int virtnet_get_coalesce(struct net_device *dev,
+ struct ethtool_coalesce *ec)
+{
+ struct ethtool_coalesce ec_default = {
+ .cmd = ETHTOOL_GCOALESCE,
+ .rx_max_coalesced_frames = 1,
+ };
+ struct virtnet_info *vi = netdev_priv(dev);
+
+ memcpy(ec, &ec_default, sizeof(ec_default));
+
+ if (vi->sq[0].napi.weight)
+ ec->tx_max_coalesced_frames = 1;
+
+ return 0;
+}
+
static void virtnet_init_settings(struct net_device *dev)
{
struct virtnet_info *vi = netdev_priv(dev);
@@ -2219,6 +2255,8 @@ static const struct ethtool_ops virtnet_ethtool_ops = {
.get_ts_info = ethtool_op_get_ts_info,
.get_link_ksettings = virtnet_get_link_ksettings,
.set_link_ksettings = virtnet_set_link_ksettings,
+ .set_coalesce = virtnet_set_coalesce,
+ .get_coalesce = virtnet_get_coalesce,
};
static void virtnet_freeze_down(struct virtio_device *vdev)
@@ -2229,8 +2267,9 @@ static void virtnet_freeze_down(struct virtio_device *vdev)
/* Make sure no work handler is accessing the device */
flush_work(&vi->config_work);
+ netif_tx_lock_bh(vi->dev);
netif_device_detach(vi->dev);
- netif_tx_disable(vi->dev);
+ netif_tx_unlock_bh(vi->dev);
cancel_delayed_work_sync(&vi->refill);
if (netif_running(vi->dev)) {
@@ -2266,7 +2305,9 @@ static int virtnet_restore_up(struct virtio_device *vdev)
}
}
+ netif_tx_lock_bh(vi->dev);
netif_device_attach(vi->dev);
+ netif_tx_unlock_bh(vi->dev);
return err;
}
@@ -2447,9 +2488,6 @@ static const struct net_device_ops virtnet_netdev = {
.ndo_get_stats64 = virtnet_stats,
.ndo_vlan_rx_add_vid = virtnet_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = virtnet_vlan_rx_kill_vid,
-#ifdef CONFIG_NET_POLL_CONTROLLER
- .ndo_poll_controller = virtnet_netpoll,
-#endif
.ndo_bpf = virtnet_xdp,
.ndo_xdp_xmit = virtnet_xdp_xmit,
.ndo_features_check = passthru_features_check,
diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c
index f93547f257fb..69b7227c637e 100644
--- a/drivers/net/vrf.c
+++ b/drivers/net/vrf.c
@@ -1215,8 +1215,19 @@ static int vrf_add_fib_rules(const struct net_device *dev)
goto ipmr_err;
#endif
+#if IS_ENABLED(CONFIG_IPV6_MROUTE_MULTIPLE_TABLES)
+ err = vrf_fib_rule(dev, RTNL_FAMILY_IP6MR, true);
+ if (err < 0)
+ goto ip6mr_err;
+#endif
+
return 0;
+#if IS_ENABLED(CONFIG_IPV6_MROUTE_MULTIPLE_TABLES)
+ip6mr_err:
+ vrf_fib_rule(dev, RTNL_FAMILY_IPMR, false);
+#endif
+
#if IS_ENABLED(CONFIG_IP_MROUTE_MULTIPLE_TABLES)
ipmr_err:
vrf_fib_rule(dev, AF_INET6, false);
diff --git a/drivers/net/vsockmon.c b/drivers/net/vsockmon.c
index c28bdce14fd5..7bad5c95551f 100644
--- a/drivers/net/vsockmon.c
+++ b/drivers/net/vsockmon.c
@@ -11,12 +11,6 @@
#define DEFAULT_MTU (VIRTIO_VSOCK_MAX_PKT_BUF_SIZE + \
sizeof(struct af_vsockmon_hdr))
-struct pcpu_lstats {
- u64 rx_packets;
- u64 rx_bytes;
- struct u64_stats_sync syncp;
-};
-
static int vsockmon_dev_init(struct net_device *dev)
{
dev->lstats = netdev_alloc_pcpu_stats(struct pcpu_lstats);
@@ -56,8 +50,8 @@ static netdev_tx_t vsockmon_xmit(struct sk_buff *skb, struct net_device *dev)
struct pcpu_lstats *stats = this_cpu_ptr(dev->lstats);
u64_stats_update_begin(&stats->syncp);
- stats->rx_bytes += len;
- stats->rx_packets++;
+ stats->bytes += len;
+ stats->packets++;
u64_stats_update_end(&stats->syncp);
dev_kfree_skb(skb);
@@ -80,8 +74,8 @@ vsockmon_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
do {
start = u64_stats_fetch_begin_irq(&vstats->syncp);
- tbytes = vstats->rx_bytes;
- tpackets = vstats->rx_packets;
+ tbytes = vstats->bytes;
+ tpackets = vstats->packets;
} while (u64_stats_fetch_retry_irq(&vstats->syncp, start));
packets += tpackets;
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index ababba37d735..297cdeaef479 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -103,22 +103,6 @@ bool vxlan_addr_equal(const union vxlan_addr *a, const union vxlan_addr *b)
return a->sin.sin_addr.s_addr == b->sin.sin_addr.s_addr;
}
-static inline bool vxlan_addr_any(const union vxlan_addr *ipa)
-{
- if (ipa->sa.sa_family == AF_INET6)
- return ipv6_addr_any(&ipa->sin6.sin6_addr);
- else
- return ipa->sin.sin_addr.s_addr == htonl(INADDR_ANY);
-}
-
-static inline bool vxlan_addr_multicast(const union vxlan_addr *ipa)
-{
- if (ipa->sa.sa_family == AF_INET6)
- return ipv6_addr_is_multicast(&ipa->sin6.sin6_addr);
- else
- return IN_MULTICAST(ntohl(ipa->sin.sin_addr.s_addr));
-}
-
static int vxlan_nla_get_addr(union vxlan_addr *ip, struct nlattr *nla)
{
if (nla_len(nla) >= sizeof(struct in6_addr)) {
@@ -151,16 +135,6 @@ bool vxlan_addr_equal(const union vxlan_addr *a, const union vxlan_addr *b)
return a->sin.sin_addr.s_addr == b->sin.sin_addr.s_addr;
}
-static inline bool vxlan_addr_any(const union vxlan_addr *ipa)
-{
- return ipa->sin.sin_addr.s_addr == htonl(INADDR_ANY);
-}
-
-static inline bool vxlan_addr_multicast(const union vxlan_addr *ipa)
-{
- return IN_MULTICAST(ntohl(ipa->sin.sin_addr.s_addr));
-}
-
static int vxlan_nla_get_addr(union vxlan_addr *ip, struct nlattr *nla)
{
if (nla_len(nla) >= sizeof(struct in6_addr)) {
@@ -298,6 +272,8 @@ static int vxlan_fdb_info(struct sk_buff *skb, struct vxlan_dev *vxlan,
ndm->ndm_state = fdb->state;
ndm->ndm_ifindex = vxlan->dev->ifindex;
ndm->ndm_flags = fdb->flags;
+ if (rdst->offloaded)
+ ndm->ndm_flags |= NTF_OFFLOADED;
ndm->ndm_type = RTN_UNICAST;
if (!net_eq(dev_net(vxlan->dev), vxlan->net) &&
@@ -353,8 +329,8 @@ static inline size_t vxlan_nlmsg_size(void)
+ nla_total_size(sizeof(struct nda_cacheinfo));
}
-static void vxlan_fdb_notify(struct vxlan_dev *vxlan, struct vxlan_fdb *fdb,
- struct vxlan_rdst *rd, int type)
+static void __vxlan_fdb_notify(struct vxlan_dev *vxlan, struct vxlan_fdb *fdb,
+ struct vxlan_rdst *rd, int type)
{
struct net *net = dev_net(vxlan->dev);
struct sk_buff *skb;
@@ -379,6 +355,49 @@ errout:
rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
}
+static void vxlan_fdb_switchdev_call_notifiers(struct vxlan_dev *vxlan,
+ struct vxlan_fdb *fdb,
+ struct vxlan_rdst *rd,
+ bool adding)
+{
+ struct switchdev_notifier_vxlan_fdb_info info;
+ enum switchdev_notifier_type notifier_type;
+
+ if (WARN_ON(!rd))
+ return;
+
+ notifier_type = adding ? SWITCHDEV_VXLAN_FDB_ADD_TO_DEVICE
+ : SWITCHDEV_VXLAN_FDB_DEL_TO_DEVICE;
+
+ info = (struct switchdev_notifier_vxlan_fdb_info){
+ .remote_ip = rd->remote_ip,
+ .remote_port = rd->remote_port,
+ .remote_vni = rd->remote_vni,
+ .remote_ifindex = rd->remote_ifindex,
+ .vni = fdb->vni,
+ .offloaded = rd->offloaded,
+ };
+ memcpy(info.eth_addr, fdb->eth_addr, ETH_ALEN);
+
+ call_switchdev_notifiers(notifier_type, vxlan->dev,
+ &info.info);
+}
+
+static void vxlan_fdb_notify(struct vxlan_dev *vxlan, struct vxlan_fdb *fdb,
+ struct vxlan_rdst *rd, int type)
+{
+ switch (type) {
+ case RTM_NEWNEIGH:
+ vxlan_fdb_switchdev_call_notifiers(vxlan, fdb, rd, true);
+ break;
+ case RTM_DELNEIGH:
+ vxlan_fdb_switchdev_call_notifiers(vxlan, fdb, rd, false);
+ break;
+ }
+
+ __vxlan_fdb_notify(vxlan, fdb, rd, type);
+}
+
static void vxlan_ip_miss(struct net_device *dev, union vxlan_addr *ipa)
{
struct vxlan_dev *vxlan = netdev_priv(dev);
@@ -464,7 +483,7 @@ static struct vxlan_fdb *vxlan_find_mac(struct vxlan_dev *vxlan,
struct vxlan_fdb *f;
f = __vxlan_find_mac(vxlan, mac, vni);
- if (f)
+ if (f && f->used != jiffies)
f->used = jiffies;
return f;
@@ -488,6 +507,47 @@ static struct vxlan_rdst *vxlan_fdb_find_rdst(struct vxlan_fdb *f,
return NULL;
}
+int vxlan_fdb_find_uc(struct net_device *dev, const u8 *mac, __be32 vni,
+ struct switchdev_notifier_vxlan_fdb_info *fdb_info)
+{
+ struct vxlan_dev *vxlan = netdev_priv(dev);
+ u8 eth_addr[ETH_ALEN + 2] = { 0 };
+ struct vxlan_rdst *rdst;
+ struct vxlan_fdb *f;
+ int rc = 0;
+
+ if (is_multicast_ether_addr(mac) ||
+ is_zero_ether_addr(mac))
+ return -EINVAL;
+
+ ether_addr_copy(eth_addr, mac);
+
+ rcu_read_lock();
+
+ f = __vxlan_find_mac(vxlan, eth_addr, vni);
+ if (!f) {
+ rc = -ENOENT;
+ goto out;
+ }
+
+ rdst = first_remote_rcu(f);
+
+ memset(fdb_info, 0, sizeof(*fdb_info));
+ fdb_info->info.dev = dev;
+ fdb_info->remote_ip = rdst->remote_ip;
+ fdb_info->remote_port = rdst->remote_port;
+ fdb_info->remote_vni = rdst->remote_vni;
+ fdb_info->remote_ifindex = rdst->remote_ifindex;
+ fdb_info->vni = vni;
+ fdb_info->offloaded = rdst->offloaded;
+ ether_addr_copy(fdb_info->eth_addr, mac);
+
+out:
+ rcu_read_unlock();
+ return rc;
+}
+EXPORT_SYMBOL_GPL(vxlan_fdb_find_uc);
+
/* Replace destination of unicast mac */
static int vxlan_fdb_replace(struct vxlan_fdb *f,
union vxlan_addr *ip, __be16 port, __be32 vni,
@@ -533,6 +593,7 @@ static int vxlan_fdb_append(struct vxlan_fdb *f,
rd->remote_ip = *ip;
rd->remote_port = port;
+ rd->offloaded = false;
rd->remote_vni = vni;
rd->remote_ifindex = ifindex;
@@ -697,6 +758,7 @@ static int vxlan_fdb_update(struct vxlan_dev *vxlan,
__be16 port, __be32 src_vni, __be32 vni,
__u32 ifindex, __u8 ndm_flags)
{
+ __u8 fdb_flags = (ndm_flags & ~NTF_USE);
struct vxlan_rdst *rd = NULL;
struct vxlan_fdb *f;
int notify = 0;
@@ -714,8 +776,8 @@ static int vxlan_fdb_update(struct vxlan_dev *vxlan,
f->updated = jiffies;
notify = 1;
}
- if (f->flags != ndm_flags) {
- f->flags = ndm_flags;
+ if (f->flags != fdb_flags) {
+ f->flags = fdb_flags;
f->updated = jiffies;
notify = 1;
}
@@ -737,6 +799,9 @@ static int vxlan_fdb_update(struct vxlan_dev *vxlan,
return rc;
notify |= rc;
}
+
+ if (ndm_flags & NTF_USE)
+ f->used = jiffies;
} else {
if (!(flags & NLM_F_CREATE))
return -ENOENT;
@@ -748,7 +813,7 @@ static int vxlan_fdb_update(struct vxlan_dev *vxlan,
netdev_dbg(vxlan->dev, "add %pM -> %pIS\n", mac, ip);
rc = vxlan_fdb_create(vxlan, mac, ip, state, port, src_vni,
- vni, ifindex, ndm_flags, &f);
+ vni, ifindex, fdb_flags, &f);
if (rc < 0)
return rc;
notify = 1;
@@ -778,12 +843,15 @@ static void vxlan_fdb_free(struct rcu_head *head)
static void vxlan_fdb_destroy(struct vxlan_dev *vxlan, struct vxlan_fdb *f,
bool do_notify)
{
+ struct vxlan_rdst *rd;
+
netdev_dbg(vxlan->dev,
"delete %pM\n", f->eth_addr);
--vxlan->addrcnt;
if (do_notify)
- vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f), RTM_DELNEIGH);
+ list_for_each_entry(rd, &f->remotes, list)
+ vxlan_fdb_notify(vxlan, f, rd, RTM_DELNEIGH);
hlist_del_rcu(&f->hlist);
call_rcu(&f->rcu, vxlan_fdb_free);
@@ -2194,11 +2262,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
}
ndst = &rt->dst;
- if (skb_dst(skb)) {
- int mtu = dst_mtu(ndst) - VXLAN_HEADROOM;
-
- skb_dst_update_pmtu(skb, mtu);
- }
+ skb_tunnel_check_pmtu(skb, ndst, VXLAN_HEADROOM);
tos = ip_tunnel_ecn_encap(tos, old_iph, skb);
ttl = ttl ? : ip4_dst_hoplimit(&rt->dst);
@@ -2235,11 +2299,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
goto out_unlock;
}
- if (skb_dst(skb)) {
- int mtu = dst_mtu(ndst) - VXLAN6_HEADROOM;
-
- skb_dst_update_pmtu(skb, mtu);
- }
+ skb_tunnel_check_pmtu(skb, ndst, VXLAN6_HEADROOM);
tos = ip_tunnel_ecn_encap(tos, old_iph, skb);
ttl = ttl ? : ip6_dst_hoplimit(ndst);
@@ -3539,6 +3599,7 @@ static size_t vxlan_get_size(const struct net_device *dev)
nla_total_size(sizeof(__u32)) + /* IFLA_VXLAN_LINK */
nla_total_size(sizeof(struct in6_addr)) + /* IFLA_VXLAN_LOCAL{6} */
nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_TTL */
+ nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_TTL_INHERIT */
nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_TOS */
nla_total_size(sizeof(__be32)) + /* IFLA_VXLAN_LABEL */
nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_LEARNING */
@@ -3603,6 +3664,8 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev)
}
if (nla_put_u8(skb, IFLA_VXLAN_TTL, vxlan->cfg.ttl) ||
+ nla_put_u8(skb, IFLA_VXLAN_TTL_INHERIT,
+ !!(vxlan->cfg.flags & VXLAN_F_TTL_INHERIT)) ||
nla_put_u8(skb, IFLA_VXLAN_TOS, vxlan->cfg.tos) ||
nla_put_be32(skb, IFLA_VXLAN_LABEL, vxlan->cfg.label) ||
nla_put_u8(skb, IFLA_VXLAN_LEARNING,
@@ -3754,6 +3817,51 @@ static struct notifier_block vxlan_notifier_block __read_mostly = {
.notifier_call = vxlan_netdevice_event,
};
+static void
+vxlan_fdb_offloaded_set(struct net_device *dev,
+ struct switchdev_notifier_vxlan_fdb_info *fdb_info)
+{
+ struct vxlan_dev *vxlan = netdev_priv(dev);
+ struct vxlan_rdst *rdst;
+ struct vxlan_fdb *f;
+
+ spin_lock_bh(&vxlan->hash_lock);
+
+ f = vxlan_find_mac(vxlan, fdb_info->eth_addr, fdb_info->vni);
+ if (!f)
+ goto out;
+
+ rdst = vxlan_fdb_find_rdst(f, &fdb_info->remote_ip,
+ fdb_info->remote_port,
+ fdb_info->remote_vni,
+ fdb_info->remote_ifindex);
+ if (!rdst)
+ goto out;
+
+ rdst->offloaded = fdb_info->offloaded;
+
+out:
+ spin_unlock_bh(&vxlan->hash_lock);
+}
+
+static int vxlan_switchdev_event(struct notifier_block *unused,
+ unsigned long event, void *ptr)
+{
+ struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
+
+ switch (event) {
+ case SWITCHDEV_VXLAN_FDB_OFFLOADED:
+ vxlan_fdb_offloaded_set(dev, ptr);
+ break;
+ }
+
+ return 0;
+}
+
+static struct notifier_block vxlan_switchdev_notifier_block __read_mostly = {
+ .notifier_call = vxlan_switchdev_event,
+};
+
static __net_init int vxlan_init_net(struct net *net)
{
struct vxlan_net *vn = net_generic(net, vxlan_net_id);
@@ -3827,11 +3935,17 @@ static int __init vxlan_init_module(void)
if (rc)
goto out2;
- rc = rtnl_link_register(&vxlan_link_ops);
+ rc = register_switchdev_notifier(&vxlan_switchdev_notifier_block);
if (rc)
goto out3;
+ rc = rtnl_link_register(&vxlan_link_ops);
+ if (rc)
+ goto out4;
+
return 0;
+out4:
+ unregister_switchdev_notifier(&vxlan_switchdev_notifier_block);
out3:
unregister_netdevice_notifier(&vxlan_notifier_block);
out2:
@@ -3844,6 +3958,7 @@ late_initcall(vxlan_init_module);
static void __exit vxlan_cleanup_module(void)
{
rtnl_link_unregister(&vxlan_link_ops);
+ unregister_switchdev_notifier(&vxlan_switchdev_notifier_block);
unregister_netdevice_notifier(&vxlan_notifier_block);
unregister_pernet_subsys(&vxlan_net_ops);
/* rcu_barrier() is called by netns */
diff --git a/drivers/net/wan/c101.c b/drivers/net/wan/c101.c
index 2371e078afbb..91dbbde3c35b 100644
--- a/drivers/net/wan/c101.c
+++ b/drivers/net/wan/c101.c
@@ -24,7 +24,6 @@
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/init.h>
-#include <linux/moduleparam.h>
#include <linux/netdevice.h>
#include <linux/hdlc.h>
#include <linux/delay.h>
diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c
index 5f0366a125e2..4d6409605207 100644
--- a/drivers/net/wan/fsl_ucc_hdlc.c
+++ b/drivers/net/wan/fsl_ucc_hdlc.c
@@ -36,6 +36,7 @@
#define DRV_NAME "ucc_hdlc"
#define TDM_PPPOHT_SLIC_MAXIN
+#define RX_BD_ERRORS (R_CD_S | R_OV_S | R_CR_S | R_AB_S | R_NO_S | R_LG_S)
static struct ucc_tdm_info utdm_primary_info = {
.uf_info = {
@@ -97,6 +98,12 @@ static int uhdlc_init(struct ucc_hdlc_private *priv)
if (priv->tsa) {
uf_info->tsa = 1;
uf_info->ctsp = 1;
+ uf_info->cds = 1;
+ uf_info->ctss = 1;
+ } else {
+ uf_info->cds = 0;
+ uf_info->ctsp = 0;
+ uf_info->ctss = 0;
}
/* This sets HPM register in CMXUCR register which configures a
@@ -265,7 +272,7 @@ static int uhdlc_init(struct ucc_hdlc_private *priv)
iowrite16be(MAX_FRAME_LENGTH, &priv->ucc_pram->mflr);
iowrite16be(DEFAULT_RFTHR, &priv->ucc_pram->rfthr);
iowrite16be(DEFAULT_RFTHR, &priv->ucc_pram->rfcnt);
- iowrite16be(DEFAULT_ADDR_MASK, &priv->ucc_pram->hmask);
+ iowrite16be(priv->hmask, &priv->ucc_pram->hmask);
iowrite16be(DEFAULT_HDLC_ADDR, &priv->ucc_pram->haddr1);
iowrite16be(DEFAULT_HDLC_ADDR, &priv->ucc_pram->haddr2);
iowrite16be(DEFAULT_HDLC_ADDR, &priv->ucc_pram->haddr3);
@@ -375,6 +382,10 @@ static netdev_tx_t ucc_hdlc_tx(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_bytes += skb->len;
break;
+ case ARPHRD_ETHER:
+ dev->stats.tx_bytes += skb->len;
+ break;
+
default:
dev->stats.tx_dropped++;
dev_kfree_skb(skb);
@@ -420,12 +431,25 @@ static netdev_tx_t ucc_hdlc_tx(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK;
}
+static int hdlc_tx_restart(struct ucc_hdlc_private *priv)
+{
+ u32 cecr_subblock;
+
+ cecr_subblock =
+ ucc_fast_get_qe_cr_subblock(priv->ut_info->uf_info.ucc_num);
+
+ qe_issue_cmd(QE_RESTART_TX, cecr_subblock,
+ QE_CR_PROTOCOL_UNSPECIFIED, 0);
+ return 0;
+}
+
static int hdlc_tx_done(struct ucc_hdlc_private *priv)
{
/* Start from the next BD that should be filled */
struct net_device *dev = priv->ndev;
struct qe_bd *bd; /* BD pointer */
u16 bd_status;
+ int tx_restart = 0;
bd = priv->dirty_tx;
bd_status = ioread16be(&bd->status);
@@ -434,6 +458,15 @@ static int hdlc_tx_done(struct ucc_hdlc_private *priv)
while ((bd_status & T_R_S) == 0) {
struct sk_buff *skb;
+ if (bd_status & T_UN_S) { /* Underrun */
+ dev->stats.tx_fifo_errors++;
+ tx_restart = 1;
+ }
+ if (bd_status & T_CT_S) { /* Carrier lost */
+ dev->stats.tx_carrier_errors++;
+ tx_restart = 1;
+ }
+
/* BD contains already transmitted buffer. */
/* Handle the transmitted buffer and release */
/* the BD to be used with the current frame */
@@ -465,6 +498,9 @@ static int hdlc_tx_done(struct ucc_hdlc_private *priv)
}
priv->dirty_tx = bd;
+ if (tx_restart)
+ hdlc_tx_restart(priv);
+
return 0;
}
@@ -483,11 +519,22 @@ static int hdlc_rx_done(struct ucc_hdlc_private *priv, int rx_work_limit)
/* while there are received buffers and BD is full (~R_E) */
while (!((bd_status & (R_E_S)) || (--rx_work_limit < 0))) {
- if (bd_status & R_OV_S)
- dev->stats.rx_over_errors++;
- if (bd_status & R_CR_S) {
- dev->stats.rx_crc_errors++;
- dev->stats.rx_dropped++;
+ if (bd_status & (RX_BD_ERRORS)) {
+ dev->stats.rx_errors++;
+
+ if (bd_status & R_CD_S)
+ dev->stats.collisions++;
+ if (bd_status & R_OV_S)
+ dev->stats.rx_fifo_errors++;
+ if (bd_status & R_CR_S)
+ dev->stats.rx_crc_errors++;
+ if (bd_status & R_AB_S)
+ dev->stats.rx_over_errors++;
+ if (bd_status & R_NO_S)
+ dev->stats.rx_frame_errors++;
+ if (bd_status & R_LG_S)
+ dev->stats.rx_length_errors++;
+
goto recycle;
}
bdbuffer = priv->rx_buffer +
@@ -512,6 +559,7 @@ static int hdlc_rx_done(struct ucc_hdlc_private *priv, int rx_work_limit)
break;
case ARPHRD_PPP:
+ case ARPHRD_ETHER:
length -= HDLC_CRC_SIZE;
skb = dev_alloc_skb(length);
@@ -535,7 +583,7 @@ static int hdlc_rx_done(struct ucc_hdlc_private *priv, int rx_work_limit)
netif_receive_skb(skb);
recycle:
- iowrite16be(bd_status | R_E_S | R_I_S, &bd->status);
+ iowrite16be((bd_status & R_W_S) | R_E_S | R_I_S, &bd->status);
/* update to point at the next bd */
if (bd_status & R_W_S) {
@@ -611,7 +659,7 @@ static irqreturn_t ucc_hdlc_irq_handler(int irq, void *dev_id)
/* Errors and other events */
if (ucce >> 16 & UCC_HDLC_UCCE_BSY)
- dev->stats.rx_errors++;
+ dev->stats.rx_missed_errors++;
if (ucce >> 16 & UCC_HDLC_UCCE_TXE)
dev->stats.tx_errors++;
@@ -780,6 +828,7 @@ static int ucc_hdlc_attach(struct net_device *dev, unsigned short encoding,
if (parity != PARITY_NONE &&
parity != PARITY_CRC32_PR1_CCITT &&
+ parity != PARITY_CRC16_PR0_CCITT &&
parity != PARITY_CRC16_PR1_CCITT)
return -EINVAL;
@@ -987,11 +1036,17 @@ static const struct dev_pm_ops uhdlc_pm_ops = {
#define HDLC_PM_OPS NULL
#endif
+static void uhdlc_tx_timeout(struct net_device *ndev)
+{
+ netdev_err(ndev, "%s\n", __func__);
+}
+
static const struct net_device_ops uhdlc_ops = {
.ndo_open = uhdlc_open,
.ndo_stop = uhdlc_close,
.ndo_start_xmit = hdlc_start_xmit,
.ndo_do_ioctl = uhdlc_ioctl,
+ .ndo_tx_timeout = uhdlc_tx_timeout,
};
static int ucc_hdlc_probe(struct platform_device *pdev)
@@ -1015,7 +1070,7 @@ static int ucc_hdlc_probe(struct platform_device *pdev)
}
ucc_num = val - 1;
- if ((ucc_num > 3) || (ucc_num < 0)) {
+ if (ucc_num > (UCC_MAX_NUM - 1) || ucc_num < 0) {
dev_err(&pdev->dev, ": Invalid UCC num\n");
return -EINVAL;
}
@@ -1090,6 +1145,9 @@ static int ucc_hdlc_probe(struct platform_device *pdev)
goto free_utdm;
}
+ if (of_property_read_u16(np, "fsl,hmask", &uhdlc_priv->hmask))
+ uhdlc_priv->hmask = DEFAULT_ADDR_MASK;
+
ret = uhdlc_init(uhdlc_priv);
if (ret) {
dev_err(&pdev->dev, "Failed to init uhdlc\n");
@@ -1107,6 +1165,7 @@ static int ucc_hdlc_probe(struct platform_device *pdev)
hdlc = dev_to_hdlc(dev);
dev->tx_queue_len = 16;
dev->netdev_ops = &uhdlc_ops;
+ dev->watchdog_timeo = 2 * HZ;
hdlc->attach = ucc_hdlc_attach;
hdlc->xmit = ucc_hdlc_tx;
netif_napi_add(dev, &uhdlc_priv->napi, ucc_hdlc_poll, 32);
diff --git a/drivers/net/wan/fsl_ucc_hdlc.h b/drivers/net/wan/fsl_ucc_hdlc.h
index c21134c1f180..b99fa2f1cd99 100644
--- a/drivers/net/wan/fsl_ucc_hdlc.h
+++ b/drivers/net/wan/fsl_ucc_hdlc.h
@@ -106,6 +106,7 @@ struct ucc_hdlc_private {
unsigned short encoding;
unsigned short parity;
+ unsigned short hmask;
u32 clocking;
spinlock_t lock; /* lock for Tx BD and Tx buffer */
#ifdef CONFIG_PM
diff --git a/drivers/net/wan/pci200syn.c b/drivers/net/wan/pci200syn.c
index 4e437c599e9a..1f8a3f77a7b9 100644
--- a/drivers/net/wan/pci200syn.c
+++ b/drivers/net/wan/pci200syn.c
@@ -27,7 +27,6 @@
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/ioport.h>
-#include <linux/moduleparam.h>
#include <linux/netdevice.h>
#include <linux/hdlc.h>
#include <linux/pci.h>
diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c
index 74c06a5f586f..1098263ab862 100644
--- a/drivers/net/wan/x25_asy.c
+++ b/drivers/net/wan/x25_asy.c
@@ -33,7 +33,6 @@
#include <linux/lapb.h>
#include <linux/init.h>
#include <linux/rtnetlink.h>
-#include <linux/compat.h>
#include <linux/slab.h>
#include <net/x25device.h>
#include "x25_asy.h"
@@ -703,21 +702,6 @@ static int x25_asy_ioctl(struct tty_struct *tty, struct file *file,
}
}
-#ifdef CONFIG_COMPAT
-static long x25_asy_compat_ioctl(struct tty_struct *tty, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- switch (cmd) {
- case SIOCGIFNAME:
- case SIOCSIFHWADDR:
- return x25_asy_ioctl(tty, file, cmd,
- (unsigned long)compat_ptr(arg));
- }
-
- return -ENOIOCTLCMD;
-}
-#endif
-
static int x25_asy_open_dev(struct net_device *dev)
{
struct x25_asy *sl = netdev_priv(dev);
@@ -769,9 +753,6 @@ static struct tty_ldisc_ops x25_ldisc = {
.open = x25_asy_open_tty,
.close = x25_asy_close_tty,
.ioctl = x25_asy_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = x25_asy_compat_ioctl,
-#endif
.receive_buf = x25_asy_receive_buf,
.write_wakeup = x25_asy_write_wakeup,
};
diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c
index 094cea775d0c..ef298d8525c5 100644
--- a/drivers/net/wimax/i2400m/control.c
+++ b/drivers/net/wimax/i2400m/control.c
@@ -257,7 +257,7 @@ static const struct
[I2400M_MS_ACCESSIBILITY_ERROR] = { "accesibility error", -EIO },
[I2400M_MS_BUSY] = { "busy", -EBUSY },
[I2400M_MS_CORRUPTED_TLV] = { "corrupted TLV", -EILSEQ },
- [I2400M_MS_UNINITIALIZED] = { "not unitialized", -EILSEQ },
+ [I2400M_MS_UNINITIALIZED] = { "uninitialized", -EILSEQ },
[I2400M_MS_UNKNOWN_ERROR] = { "unknown error", -EIO },
[I2400M_MS_PRODUCTION_ERROR] = { "production error", -EIO },
[I2400M_MS_NO_RF] = { "no RF", -EIO },
diff --git a/drivers/net/wireless/ath/ath10k/Kconfig b/drivers/net/wireless/ath/ath10k/Kconfig
index 54ff5930126c..e1ad6b9166a6 100644
--- a/drivers/net/wireless/ath/ath10k/Kconfig
+++ b/drivers/net/wireless/ath/ath10k/Kconfig
@@ -42,7 +42,9 @@ config ATH10K_USB
config ATH10K_SNOC
tristate "Qualcomm ath10k SNOC support (EXPERIMENTAL)"
- depends on ATH10K && ARCH_QCOM
+ depends on ATH10K
+ depends on ARCH_QCOM || COMPILE_TEST
+ select QCOM_QMI_HELPERS
---help---
This module adds support for integrated WCN3990 chip connected
to system NOC(SNOC). Currently work in progress and will not
diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile
index 44d60a61b242..66326b949ab1 100644
--- a/drivers/net/wireless/ath/ath10k/Makefile
+++ b/drivers/net/wireless/ath/ath10k/Makefile
@@ -36,7 +36,9 @@ obj-$(CONFIG_ATH10K_USB) += ath10k_usb.o
ath10k_usb-y += usb.o
obj-$(CONFIG_ATH10K_SNOC) += ath10k_snoc.o
-ath10k_snoc-y += snoc.o
+ath10k_snoc-y += qmi.o \
+ qmi_wlfw_v01.o \
+ snoc.o
# for tracing framework to find trace.h
CFLAGS_trace.o := -I$(src)
diff --git a/drivers/net/wireless/ath/ath10k/ahb.c b/drivers/net/wireless/ath/ath10k/ahb.c
index c9bd0e2b5db7..4cd69aca75e2 100644
--- a/drivers/net/wireless/ath/ath10k/ahb.c
+++ b/drivers/net/wireless/ath/ath10k/ahb.c
@@ -655,10 +655,10 @@ static void ath10k_ahb_hif_stop(struct ath10k *ar)
ath10k_ahb_irq_disable(ar);
synchronize_irq(ar_ahb->irq);
- ath10k_pci_flush(ar);
-
napi_synchronize(&ar->napi);
napi_disable(&ar->napi);
+
+ ath10k_pci_flush(ar);
}
static int ath10k_ahb_hif_power_up(struct ath10k *ar)
@@ -750,7 +750,7 @@ static int ath10k_ahb_probe(struct platform_device *pdev)
enum ath10k_hw_rev hw_rev;
size_t size;
int ret;
- u32 chip_id;
+ struct ath10k_bus_params bus_params;
of_id = of_match_device(ath10k_ahb_of_match, &pdev->dev);
if (!of_id) {
@@ -806,14 +806,15 @@ static int ath10k_ahb_probe(struct platform_device *pdev)
ath10k_pci_ce_deinit(ar);
- chip_id = ath10k_ahb_soc_read32(ar, SOC_CHIP_ID_ADDRESS);
- if (chip_id == 0xffffffff) {
+ bus_params.dev_type = ATH10K_DEV_TYPE_LL;
+ bus_params.chip_id = ath10k_ahb_soc_read32(ar, SOC_CHIP_ID_ADDRESS);
+ if (bus_params.chip_id == 0xffffffff) {
ath10k_err(ar, "failed to get chip id\n");
ret = -ENODEV;
goto err_halt_device;
}
- ret = ath10k_core_register(ar, chip_id);
+ ret = ath10k_core_register(ar, &bus_params);
if (ret) {
ath10k_err(ar, "failed to register driver core: %d\n", ret);
goto err_halt_device;
diff --git a/drivers/net/wireless/ath/ath10k/bmi.c b/drivers/net/wireless/ath/ath10k/bmi.c
index af4978d6a14b..1750b182209b 100644
--- a/drivers/net/wireless/ath/ath10k/bmi.c
+++ b/drivers/net/wireless/ath/ath10k/bmi.c
@@ -459,3 +459,26 @@ int ath10k_bmi_fast_download(struct ath10k *ar,
return ret;
}
+
+int ath10k_bmi_set_start(struct ath10k *ar, u32 address)
+{
+ struct bmi_cmd cmd;
+ u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.set_app_start);
+ int ret;
+
+ if (ar->bmi.done_sent) {
+ ath10k_warn(ar, "bmi set start command disallowed\n");
+ return -EBUSY;
+ }
+
+ cmd.id = __cpu_to_le32(BMI_SET_APP_START);
+ cmd.set_app_start.addr = __cpu_to_le32(address);
+
+ ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
+ if (ret) {
+ ath10k_warn(ar, "unable to set start to the device:%d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
diff --git a/drivers/net/wireless/ath/ath10k/bmi.h b/drivers/net/wireless/ath/ath10k/bmi.h
index 9a396817aa55..725c9afc63f2 100644
--- a/drivers/net/wireless/ath/ath10k/bmi.h
+++ b/drivers/net/wireless/ath/ath10k/bmi.h
@@ -86,6 +86,10 @@ enum bmi_cmd_id {
#define BMI_PARAM_GET_FLASH_BOARD_ID 0x8000
#define BMI_PARAM_FLASH_SECTION_ALL 0x10000
+/* Dual-band Extended Board ID */
+#define BMI_PARAM_GET_EXT_BOARD_ID 0x40000
+#define ATH10K_BMI_EXT_BOARD_ID_SUPPORT 0x40000
+
#define ATH10K_BMI_BOARD_ID_FROM_OTP_MASK 0x7c00
#define ATH10K_BMI_BOARD_ID_FROM_OTP_LSB 10
@@ -93,6 +97,7 @@ enum bmi_cmd_id {
#define ATH10K_BMI_CHIP_ID_FROM_OTP_LSB 15
#define ATH10K_BMI_BOARD_ID_STATUS_MASK 0xff
+#define ATH10K_BMI_EBOARD_ID_STATUS_MASK 0xff
struct bmi_cmd {
__le32 id; /* enum bmi_cmd_id */
@@ -190,6 +195,35 @@ struct bmi_target_info {
u32 type;
};
+struct bmi_segmented_file_header {
+ __le32 magic_num;
+ __le32 file_flags;
+ u8 data[];
+};
+
+struct bmi_segmented_metadata {
+ __le32 addr;
+ __le32 length;
+ u8 data[];
+};
+
+#define BMI_SGMTFILE_MAGIC_NUM 0x544d4753 /* "SGMT" */
+#define BMI_SGMTFILE_FLAG_COMPRESS 1
+
+/* Special values for bmi_segmented_metadata.length (all have high bit set) */
+
+/* end of segmented data */
+#define BMI_SGMTFILE_DONE 0xffffffff
+
+/* Board Data segment */
+#define BMI_SGMTFILE_BDDATA 0xfffffffe
+
+/* set beginning address */
+#define BMI_SGMTFILE_BEGINADDR 0xfffffffd
+
+/* immediate function execution */
+#define BMI_SGMTFILE_EXEC 0xfffffffc
+
/* in jiffies */
#define BMI_COMMUNICATION_TIMEOUT_HZ (3 * HZ)
@@ -239,4 +273,6 @@ int ath10k_bmi_fast_download(struct ath10k *ar, u32 address,
const void *buffer, u32 length);
int ath10k_bmi_read_soc_reg(struct ath10k *ar, u32 address, u32 *reg_val);
int ath10k_bmi_write_soc_reg(struct ath10k *ar, u32 address, u32 reg_val);
+int ath10k_bmi_set_start(struct ath10k *ar, u32 address);
+
#endif /* _BMI_H_ */
diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c
index 18c709c484e7..f6d3ecbdd3a3 100644
--- a/drivers/net/wireless/ath/ath10k/ce.c
+++ b/drivers/net/wireless/ath/ath10k/ce.c
@@ -1280,10 +1280,17 @@ static void ath10k_ce_per_engine_handler_adjust(struct ath10k_ce_pipe *ce_state)
int ath10k_ce_disable_interrupts(struct ath10k *ar)
{
+ struct ath10k_ce *ce = ath10k_ce_priv(ar);
+ struct ath10k_ce_pipe *ce_state;
+ u32 ctrl_addr;
int ce_id;
for (ce_id = 0; ce_id < CE_COUNT; ce_id++) {
- u32 ctrl_addr = ath10k_ce_base_address(ar, ce_id);
+ ce_state = &ce->ce_states[ce_id];
+ if (ce_state->attr_flags & CE_ATTR_POLL)
+ continue;
+
+ ctrl_addr = ath10k_ce_base_address(ar, ce_id);
ath10k_ce_copy_complete_intr_disable(ar, ctrl_addr);
ath10k_ce_error_intr_disable(ar, ctrl_addr);
@@ -1300,11 +1307,14 @@ void ath10k_ce_enable_interrupts(struct ath10k *ar)
int ce_id;
struct ath10k_ce_pipe *ce_state;
- /* Skip the last copy engine, CE7 the diagnostic window, as that
- * uses polling and isn't initialized for interrupts.
+ /* Enable interrupts for copy engine that
+ * are not using polling mode.
*/
- for (ce_id = 0; ce_id < CE_COUNT - 1; ce_id++) {
+ for (ce_id = 0; ce_id < CE_COUNT; ce_id++) {
ce_state = &ce->ce_states[ce_id];
+ if (ce_state->attr_flags & CE_ATTR_POLL)
+ continue;
+
ath10k_ce_per_engine_handler_adjust(ce_state);
}
}
@@ -1416,10 +1426,8 @@ ath10k_ce_alloc_src_ring(struct ath10k *ar, unsigned int ce_id,
nentries = roundup_pow_of_two(nentries);
- src_ring = kzalloc(sizeof(*src_ring) +
- (nentries *
- sizeof(*src_ring->per_transfer_context)),
- GFP_KERNEL);
+ src_ring = kzalloc(struct_size(src_ring, per_transfer_context,
+ nentries), GFP_KERNEL);
if (src_ring == NULL)
return ERR_PTR(-ENOMEM);
@@ -1476,10 +1484,8 @@ ath10k_ce_alloc_src_ring_64(struct ath10k *ar, unsigned int ce_id,
nentries = roundup_pow_of_two(nentries);
- src_ring = kzalloc(sizeof(*src_ring) +
- (nentries *
- sizeof(*src_ring->per_transfer_context)),
- GFP_KERNEL);
+ src_ring = kzalloc(struct_size(src_ring, per_transfer_context,
+ nentries), GFP_KERNEL);
if (!src_ring)
return ERR_PTR(-ENOMEM);
@@ -1534,10 +1540,8 @@ ath10k_ce_alloc_dest_ring(struct ath10k *ar, unsigned int ce_id,
nentries = roundup_pow_of_two(attr->dest_nentries);
- dest_ring = kzalloc(sizeof(*dest_ring) +
- (nentries *
- sizeof(*dest_ring->per_transfer_context)),
- GFP_KERNEL);
+ dest_ring = kzalloc(struct_size(dest_ring, per_transfer_context,
+ nentries), GFP_KERNEL);
if (dest_ring == NULL)
return ERR_PTR(-ENOMEM);
@@ -1580,10 +1584,8 @@ ath10k_ce_alloc_dest_ring_64(struct ath10k *ar, unsigned int ce_id,
nentries = roundup_pow_of_two(attr->dest_nentries);
- dest_ring = kzalloc(sizeof(*dest_ring) +
- (nentries *
- sizeof(*dest_ring->per_transfer_context)),
- GFP_KERNEL);
+ dest_ring = kzalloc(struct_size(dest_ring, per_transfer_context,
+ nentries), GFP_KERNEL);
if (!dest_ring)
return ERR_PTR(-ENOMEM);
diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h
index b8fb5382dede..ead9987c3259 100644
--- a/drivers/net/wireless/ath/ath10k/ce.h
+++ b/drivers/net/wireless/ath/ath10k/ce.h
@@ -275,16 +275,19 @@ void ath10k_ce_free_rri(struct ath10k *ar);
/* ce_attr.flags values */
/* Use NonSnooping PCIe accesses? */
-#define CE_ATTR_NO_SNOOP 1
+#define CE_ATTR_NO_SNOOP BIT(0)
/* Byte swap data words */
-#define CE_ATTR_BYTE_SWAP_DATA 2
+#define CE_ATTR_BYTE_SWAP_DATA BIT(1)
/* Swizzle descriptors? */
-#define CE_ATTR_SWIZZLE_DESCRIPTORS 4
+#define CE_ATTR_SWIZZLE_DESCRIPTORS BIT(2)
/* no interrupt on copy completion */
-#define CE_ATTR_DIS_INTR 8
+#define CE_ATTR_DIS_INTR BIT(3)
+
+/* no interrupt, only polling */
+#define CE_ATTR_POLL BIT(4)
/* Attributes of an instance of a Copy Engine */
struct ce_attr {
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index c40cd129afe7..da607febfd82 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/of.h>
+#include <linux/property.h>
#include <linux/dmi.h>
#include <linux/ctype.h>
#include <asm/byteorder.h>
@@ -63,6 +64,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
{
.id = QCA988X_HW_2_0_VERSION,
.dev_id = QCA988X_2_0_DEVICE_ID,
+ .bus = ATH10K_BUS_PCI,
.name = "qca988x hw2.0",
.patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR,
.uart_pin = 7,
@@ -84,13 +86,14 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.vht160_mcs_rx_highest = 0,
.vht160_mcs_tx_highest = 0,
.n_cipher_suites = 8,
- .num_peers = TARGET_TLV_NUM_PEERS,
.ast_skid_limit = 0x10,
.num_wds_entries = 0x20,
.target_64bit = false,
.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
.shadow_reg_support = false,
.rri_on_ddr = false,
+ .hw_filter_reset_required = true,
+ .fw_diag_ce_download = false,
},
{
.id = QCA988X_HW_2_0_VERSION,
@@ -116,7 +119,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.vht160_mcs_rx_highest = 0,
.vht160_mcs_tx_highest = 0,
.n_cipher_suites = 8,
- .num_peers = TARGET_TLV_NUM_PEERS,
.ast_skid_limit = 0x10,
.num_wds_entries = 0x20,
.target_64bit = false,
@@ -124,10 +126,13 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.per_ce_irq = false,
.shadow_reg_support = false,
.rri_on_ddr = false,
+ .hw_filter_reset_required = true,
+ .fw_diag_ce_download = false,
},
{
.id = QCA9887_HW_1_0_VERSION,
.dev_id = QCA9887_1_0_DEVICE_ID,
+ .bus = ATH10K_BUS_PCI,
.name = "qca9887 hw1.0",
.patch_load_addr = QCA9887_HW_1_0_PATCH_LOAD_ADDR,
.uart_pin = 7,
@@ -149,7 +154,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.vht160_mcs_rx_highest = 0,
.vht160_mcs_tx_highest = 0,
.n_cipher_suites = 8,
- .num_peers = TARGET_TLV_NUM_PEERS,
.ast_skid_limit = 0x10,
.num_wds_entries = 0x20,
.target_64bit = false,
@@ -157,10 +161,13 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.per_ce_irq = false,
.shadow_reg_support = false,
.rri_on_ddr = false,
+ .hw_filter_reset_required = true,
+ .fw_diag_ce_download = false,
},
{
.id = QCA6174_HW_2_1_VERSION,
.dev_id = QCA6164_2_1_DEVICE_ID,
+ .bus = ATH10K_BUS_PCI,
.name = "qca6164 hw2.1",
.patch_load_addr = QCA6174_HW_2_1_PATCH_LOAD_ADDR,
.uart_pin = 6,
@@ -181,7 +188,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.vht160_mcs_rx_highest = 0,
.vht160_mcs_tx_highest = 0,
.n_cipher_suites = 8,
- .num_peers = TARGET_TLV_NUM_PEERS,
.ast_skid_limit = 0x10,
.num_wds_entries = 0x20,
.target_64bit = false,
@@ -189,10 +195,13 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.per_ce_irq = false,
.shadow_reg_support = false,
.rri_on_ddr = false,
+ .hw_filter_reset_required = true,
+ .fw_diag_ce_download = false,
},
{
.id = QCA6174_HW_2_1_VERSION,
.dev_id = QCA6174_2_1_DEVICE_ID,
+ .bus = ATH10K_BUS_PCI,
.name = "qca6174 hw2.1",
.patch_load_addr = QCA6174_HW_2_1_PATCH_LOAD_ADDR,
.uart_pin = 6,
@@ -213,7 +222,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.vht160_mcs_rx_highest = 0,
.vht160_mcs_tx_highest = 0,
.n_cipher_suites = 8,
- .num_peers = TARGET_TLV_NUM_PEERS,
.ast_skid_limit = 0x10,
.num_wds_entries = 0x20,
.target_64bit = false,
@@ -221,10 +229,13 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.per_ce_irq = false,
.shadow_reg_support = false,
.rri_on_ddr = false,
+ .hw_filter_reset_required = true,
+ .fw_diag_ce_download = false,
},
{
.id = QCA6174_HW_3_0_VERSION,
.dev_id = QCA6174_2_1_DEVICE_ID,
+ .bus = ATH10K_BUS_PCI,
.name = "qca6174 hw3.0",
.patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR,
.uart_pin = 6,
@@ -245,7 +256,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.vht160_mcs_rx_highest = 0,
.vht160_mcs_tx_highest = 0,
.n_cipher_suites = 8,
- .num_peers = TARGET_TLV_NUM_PEERS,
.ast_skid_limit = 0x10,
.num_wds_entries = 0x20,
.target_64bit = false,
@@ -253,10 +263,13 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.per_ce_irq = false,
.shadow_reg_support = false,
.rri_on_ddr = false,
+ .hw_filter_reset_required = true,
+ .fw_diag_ce_download = false,
},
{
.id = QCA6174_HW_3_2_VERSION,
.dev_id = QCA6174_2_1_DEVICE_ID,
+ .bus = ATH10K_BUS_PCI,
.name = "qca6174 hw3.2",
.patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR,
.uart_pin = 6,
@@ -280,7 +293,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.vht160_mcs_rx_highest = 0,
.vht160_mcs_tx_highest = 0,
.n_cipher_suites = 8,
- .num_peers = TARGET_TLV_NUM_PEERS,
.ast_skid_limit = 0x10,
.num_wds_entries = 0x20,
.target_64bit = false,
@@ -288,10 +300,13 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.per_ce_irq = false,
.shadow_reg_support = false,
.rri_on_ddr = false,
+ .hw_filter_reset_required = true,
+ .fw_diag_ce_download = true,
},
{
.id = QCA99X0_HW_2_0_DEV_VERSION,
.dev_id = QCA99X0_2_0_DEVICE_ID,
+ .bus = ATH10K_BUS_PCI,
.name = "qca99x0 hw2.0",
.patch_load_addr = QCA99X0_HW_2_0_PATCH_LOAD_ADDR,
.uart_pin = 7,
@@ -318,7 +333,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.vht160_mcs_rx_highest = 0,
.vht160_mcs_tx_highest = 0,
.n_cipher_suites = 11,
- .num_peers = TARGET_TLV_NUM_PEERS,
.ast_skid_limit = 0x10,
.num_wds_entries = 0x20,
.target_64bit = false,
@@ -326,10 +340,13 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.per_ce_irq = false,
.shadow_reg_support = false,
.rri_on_ddr = false,
+ .hw_filter_reset_required = true,
+ .fw_diag_ce_download = false,
},
{
.id = QCA9984_HW_1_0_DEV_VERSION,
.dev_id = QCA9984_1_0_DEVICE_ID,
+ .bus = ATH10K_BUS_PCI,
.name = "qca9984/qca9994 hw1.0",
.patch_load_addr = QCA9984_HW_1_0_PATCH_LOAD_ADDR,
.uart_pin = 7,
@@ -346,8 +363,10 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.fw = {
.dir = QCA9984_HW_1_0_FW_DIR,
.board = QCA9984_HW_1_0_BOARD_DATA_FILE,
+ .eboard = QCA9984_HW_1_0_EBOARD_DATA_FILE,
.board_size = QCA99X0_BOARD_DATA_SZ,
.board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ,
+ .ext_board_size = QCA99X0_EXT_BOARD_DATA_SZ,
},
.sw_decrypt_mcast_mgmt = true,
.hw_ops = &qca99x0_ops,
@@ -361,7 +380,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.vht160_mcs_rx_highest = 1560,
.vht160_mcs_tx_highest = 1560,
.n_cipher_suites = 11,
- .num_peers = TARGET_TLV_NUM_PEERS,
.ast_skid_limit = 0x10,
.num_wds_entries = 0x20,
.target_64bit = false,
@@ -369,10 +387,13 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.per_ce_irq = false,
.shadow_reg_support = false,
.rri_on_ddr = false,
+ .hw_filter_reset_required = true,
+ .fw_diag_ce_download = false,
},
{
.id = QCA9888_HW_2_0_DEV_VERSION,
.dev_id = QCA9888_2_0_DEVICE_ID,
+ .bus = ATH10K_BUS_PCI,
.name = "qca9888 hw2.0",
.patch_load_addr = QCA9888_HW_2_0_PATCH_LOAD_ADDR,
.uart_pin = 7,
@@ -403,7 +424,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.vht160_mcs_rx_highest = 780,
.vht160_mcs_tx_highest = 780,
.n_cipher_suites = 11,
- .num_peers = TARGET_TLV_NUM_PEERS,
.ast_skid_limit = 0x10,
.num_wds_entries = 0x20,
.target_64bit = false,
@@ -411,10 +431,13 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.per_ce_irq = false,
.shadow_reg_support = false,
.rri_on_ddr = false,
+ .hw_filter_reset_required = true,
+ .fw_diag_ce_download = false,
},
{
.id = QCA9377_HW_1_0_DEV_VERSION,
.dev_id = QCA9377_1_0_DEVICE_ID,
+ .bus = ATH10K_BUS_PCI,
.name = "qca9377 hw1.0",
.patch_load_addr = QCA9377_HW_1_0_PATCH_LOAD_ADDR,
.uart_pin = 6,
@@ -435,7 +458,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.vht160_mcs_rx_highest = 0,
.vht160_mcs_tx_highest = 0,
.n_cipher_suites = 8,
- .num_peers = TARGET_TLV_NUM_PEERS,
.ast_skid_limit = 0x10,
.num_wds_entries = 0x20,
.target_64bit = false,
@@ -443,10 +465,13 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.per_ce_irq = false,
.shadow_reg_support = false,
.rri_on_ddr = false,
+ .hw_filter_reset_required = true,
+ .fw_diag_ce_download = false,
},
{
.id = QCA9377_HW_1_1_DEV_VERSION,
.dev_id = QCA9377_1_0_DEVICE_ID,
+ .bus = ATH10K_BUS_PCI,
.name = "qca9377 hw1.1",
.patch_load_addr = QCA9377_HW_1_0_PATCH_LOAD_ADDR,
.uart_pin = 6,
@@ -469,7 +494,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.vht160_mcs_rx_highest = 0,
.vht160_mcs_tx_highest = 0,
.n_cipher_suites = 8,
- .num_peers = TARGET_TLV_NUM_PEERS,
.ast_skid_limit = 0x10,
.num_wds_entries = 0x20,
.target_64bit = false,
@@ -477,10 +501,13 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.per_ce_irq = false,
.shadow_reg_support = false,
.rri_on_ddr = false,
+ .hw_filter_reset_required = true,
+ .fw_diag_ce_download = true,
},
{
.id = QCA4019_HW_1_0_DEV_VERSION,
.dev_id = 0,
+ .bus = ATH10K_BUS_AHB,
.name = "qca4019 hw1.0",
.patch_load_addr = QCA4019_HW_1_0_PATCH_LOAD_ADDR,
.uart_pin = 7,
@@ -508,7 +535,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.vht160_mcs_rx_highest = 0,
.vht160_mcs_tx_highest = 0,
.n_cipher_suites = 11,
- .num_peers = TARGET_TLV_NUM_PEERS,
.ast_skid_limit = 0x10,
.num_wds_entries = 0x20,
.target_64bit = false,
@@ -516,10 +542,13 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.per_ce_irq = false,
.shadow_reg_support = false,
.rri_on_ddr = false,
+ .hw_filter_reset_required = true,
+ .fw_diag_ce_download = false,
},
{
.id = WCN3990_HW_1_0_DEV_VERSION,
.dev_id = 0,
+ .bus = ATH10K_BUS_PCI,
.name = "wcn3990 hw1.0",
.continuous_frag_desc = true,
.tx_chain_mask = 0x7,
@@ -539,6 +568,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.per_ce_irq = true,
.shadow_reg_support = true,
.rri_on_ddr = true,
+ .hw_filter_reset_required = false,
+ .fw_diag_ce_download = false,
},
};
@@ -762,153 +793,11 @@ static int ath10k_push_board_ext_data(struct ath10k *ar, const void *data,
return 0;
}
-static int ath10k_download_board_data(struct ath10k *ar, const void *data,
- size_t data_len)
-{
- u32 board_data_size = ar->hw_params.fw.board_size;
- u32 address;
- int ret;
-
- ret = ath10k_push_board_ext_data(ar, data, data_len);
- if (ret) {
- ath10k_err(ar, "could not push board ext data (%d)\n", ret);
- goto exit;
- }
-
- ret = ath10k_bmi_read32(ar, hi_board_data, &address);
- if (ret) {
- ath10k_err(ar, "could not read board data addr (%d)\n", ret);
- goto exit;
- }
-
- ret = ath10k_bmi_write_memory(ar, address, data,
- min_t(u32, board_data_size,
- data_len));
- if (ret) {
- ath10k_err(ar, "could not write board data (%d)\n", ret);
- goto exit;
- }
-
- ret = ath10k_bmi_write32(ar, hi_board_data_initialized, 1);
- if (ret) {
- ath10k_err(ar, "could not write board data bit (%d)\n", ret);
- goto exit;
- }
-
-exit:
- return ret;
-}
-
-static int ath10k_download_cal_file(struct ath10k *ar,
- const struct firmware *file)
-{
- int ret;
-
- if (!file)
- return -ENOENT;
-
- if (IS_ERR(file))
- return PTR_ERR(file);
-
- ret = ath10k_download_board_data(ar, file->data, file->size);
- if (ret) {
- ath10k_err(ar, "failed to download cal_file data: %d\n", ret);
- return ret;
- }
-
- ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cal file downloaded\n");
-
- return 0;
-}
-
-static int ath10k_download_cal_dt(struct ath10k *ar, const char *dt_name)
-{
- struct device_node *node;
- int data_len;
- void *data;
- int ret;
-
- node = ar->dev->of_node;
- if (!node)
- /* Device Tree is optional, don't print any warnings if
- * there's no node for ath10k.
- */
- return -ENOENT;
-
- if (!of_get_property(node, dt_name, &data_len)) {
- /* The calibration data node is optional */
- return -ENOENT;
- }
-
- if (data_len != ar->hw_params.cal_data_len) {
- ath10k_warn(ar, "invalid calibration data length in DT: %d\n",
- data_len);
- ret = -EMSGSIZE;
- goto out;
- }
-
- data = kmalloc(data_len, GFP_KERNEL);
- if (!data) {
- ret = -ENOMEM;
- goto out;
- }
-
- ret = of_property_read_u8_array(node, dt_name, data, data_len);
- if (ret) {
- ath10k_warn(ar, "failed to read calibration data from DT: %d\n",
- ret);
- goto out_free;
- }
-
- ret = ath10k_download_board_data(ar, data, data_len);
- if (ret) {
- ath10k_warn(ar, "failed to download calibration data from Device Tree: %d\n",
- ret);
- goto out_free;
- }
-
- ret = 0;
-
-out_free:
- kfree(data);
-
-out:
- return ret;
-}
-
-static int ath10k_download_cal_eeprom(struct ath10k *ar)
-{
- size_t data_len;
- void *data = NULL;
- int ret;
-
- ret = ath10k_hif_fetch_cal_eeprom(ar, &data, &data_len);
- if (ret) {
- if (ret != -EOPNOTSUPP)
- ath10k_warn(ar, "failed to read calibration data from EEPROM: %d\n",
- ret);
- goto out_free;
- }
-
- ret = ath10k_download_board_data(ar, data, data_len);
- if (ret) {
- ath10k_warn(ar, "failed to download calibration data from EEPROM: %d\n",
- ret);
- goto out_free;
- }
-
- ret = 0;
-
-out_free:
- kfree(data);
-
- return ret;
-}
-
static int ath10k_core_get_board_id_from_otp(struct ath10k *ar)
{
u32 result, address;
u8 board_id, chip_id;
+ bool ext_bid_support;
int ret, bmi_board_id_param;
address = ar->hw_params.patch_load_addr;
@@ -948,10 +837,13 @@ static int ath10k_core_get_board_id_from_otp(struct ath10k *ar)
board_id = MS(result, ATH10K_BMI_BOARD_ID_FROM_OTP);
chip_id = MS(result, ATH10K_BMI_CHIP_ID_FROM_OTP);
+ ext_bid_support = (result & ATH10K_BMI_EXT_BOARD_ID_SUPPORT);
ath10k_dbg(ar, ATH10K_DBG_BOOT,
- "boot get otp board id result 0x%08x board_id %d chip_id %d\n",
- result, board_id, chip_id);
+ "boot get otp board id result 0x%08x board_id %d chip_id %d ext_bid_support %d\n",
+ result, board_id, chip_id, ext_bid_support);
+
+ ar->id.ext_bid_supported = ext_bid_support;
if ((result & ATH10K_BMI_BOARD_ID_STATUS_MASK) != 0 ||
(board_id == 0)) {
@@ -1055,64 +947,6 @@ static int ath10k_core_check_dt(struct ath10k *ar)
return 0;
}
-static int ath10k_download_and_run_otp(struct ath10k *ar)
-{
- u32 result, address = ar->hw_params.patch_load_addr;
- u32 bmi_otp_exe_param = ar->hw_params.otp_exe_param;
- int ret;
-
- ret = ath10k_download_board_data(ar,
- ar->running_fw->board_data,
- ar->running_fw->board_len);
- if (ret) {
- ath10k_err(ar, "failed to download board data: %d\n", ret);
- return ret;
- }
-
- /* OTP is optional */
-
- if (!ar->running_fw->fw_file.otp_data ||
- !ar->running_fw->fw_file.otp_len) {
- ath10k_warn(ar, "Not running otp, calibration will be incorrect (otp-data %pK otp_len %zd)!\n",
- ar->running_fw->fw_file.otp_data,
- ar->running_fw->fw_file.otp_len);
- return 0;
- }
-
- ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot upload otp to 0x%x len %zd\n",
- address, ar->running_fw->fw_file.otp_len);
-
- ret = ath10k_bmi_fast_download(ar, address,
- ar->running_fw->fw_file.otp_data,
- ar->running_fw->fw_file.otp_len);
- if (ret) {
- ath10k_err(ar, "could not write otp (%d)\n", ret);
- return ret;
- }
-
- /* As of now pre-cal is valid for 10_4 variants */
- if (ar->cal_mode == ATH10K_PRE_CAL_MODE_DT ||
- ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE)
- bmi_otp_exe_param = BMI_PARAM_FLASH_SECTION_ALL;
-
- ret = ath10k_bmi_execute(ar, address, bmi_otp_exe_param, &result);
- if (ret) {
- ath10k_err(ar, "could not execute otp (%d)\n", ret);
- return ret;
- }
-
- ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot otp execute result %d\n", result);
-
- if (!(skip_otp || test_bit(ATH10K_FW_FEATURE_IGNORE_OTP_RESULT,
- ar->running_fw->fw_file.fw_features)) &&
- result != 0) {
- ath10k_err(ar, "otp calibration failed: %d", result);
- return -EINVAL;
- }
-
- return 0;
-}
-
static int ath10k_download_fw(struct ath10k *ar)
{
u32 address, data_len;
@@ -1135,25 +969,42 @@ static int ath10k_download_fw(struct ath10k *ar)
"boot uploading firmware image %pK len %d\n",
data, data_len);
- ret = ath10k_bmi_fast_download(ar, address, data, data_len);
- if (ret) {
- ath10k_err(ar, "failed to download firmware: %d\n",
- ret);
- return ret;
+ /* Check if device supports to download firmware via
+ * diag copy engine. Downloading firmware via diag CE
+ * greatly reduces the time to download firmware.
+ */
+ if (ar->hw_params.fw_diag_ce_download) {
+ ret = ath10k_hw_diag_fast_download(ar, address,
+ data, data_len);
+ if (ret == 0)
+ /* firmware upload via diag ce was successful */
+ return 0;
+
+ ath10k_warn(ar,
+ "failed to upload firmware via diag ce, trying BMI: %d",
+ ret);
}
- return ret;
+ return ath10k_bmi_fast_download(ar, address,
+ data, data_len);
}
-static void ath10k_core_free_board_files(struct ath10k *ar)
+void ath10k_core_free_board_files(struct ath10k *ar)
{
if (!IS_ERR(ar->normal_mode_fw.board))
release_firmware(ar->normal_mode_fw.board);
+ if (!IS_ERR(ar->normal_mode_fw.ext_board))
+ release_firmware(ar->normal_mode_fw.ext_board);
+
ar->normal_mode_fw.board = NULL;
ar->normal_mode_fw.board_data = NULL;
ar->normal_mode_fw.board_len = 0;
+ ar->normal_mode_fw.ext_board = NULL;
+ ar->normal_mode_fw.ext_board_data = NULL;
+ ar->normal_mode_fw.ext_board_len = 0;
}
+EXPORT_SYMBOL(ath10k_core_free_board_files);
static void ath10k_core_free_firmware_files(struct ath10k *ar)
{
@@ -1206,28 +1057,47 @@ success:
return 0;
}
-static int ath10k_core_fetch_board_data_api_1(struct ath10k *ar)
+static int ath10k_core_fetch_board_data_api_1(struct ath10k *ar, int bd_ie_type)
{
- if (!ar->hw_params.fw.board) {
- ath10k_err(ar, "failed to find board file fw entry\n");
- return -EINVAL;
- }
+ const struct firmware *fw;
- ar->normal_mode_fw.board = ath10k_fetch_fw_file(ar,
- ar->hw_params.fw.dir,
- ar->hw_params.fw.board);
- if (IS_ERR(ar->normal_mode_fw.board))
- return PTR_ERR(ar->normal_mode_fw.board);
+ if (bd_ie_type == ATH10K_BD_IE_BOARD) {
+ if (!ar->hw_params.fw.board) {
+ ath10k_err(ar, "failed to find board file fw entry\n");
+ return -EINVAL;
+ }
+
+ ar->normal_mode_fw.board = ath10k_fetch_fw_file(ar,
+ ar->hw_params.fw.dir,
+ ar->hw_params.fw.board);
+ if (IS_ERR(ar->normal_mode_fw.board))
+ return PTR_ERR(ar->normal_mode_fw.board);
+
+ ar->normal_mode_fw.board_data = ar->normal_mode_fw.board->data;
+ ar->normal_mode_fw.board_len = ar->normal_mode_fw.board->size;
+ } else if (bd_ie_type == ATH10K_BD_IE_BOARD_EXT) {
+ if (!ar->hw_params.fw.eboard) {
+ ath10k_err(ar, "failed to find eboard file fw entry\n");
+ return -EINVAL;
+ }
- ar->normal_mode_fw.board_data = ar->normal_mode_fw.board->data;
- ar->normal_mode_fw.board_len = ar->normal_mode_fw.board->size;
+ fw = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir,
+ ar->hw_params.fw.eboard);
+ ar->normal_mode_fw.ext_board = fw;
+ if (IS_ERR(ar->normal_mode_fw.ext_board))
+ return PTR_ERR(ar->normal_mode_fw.ext_board);
+
+ ar->normal_mode_fw.ext_board_data = ar->normal_mode_fw.ext_board->data;
+ ar->normal_mode_fw.ext_board_len = ar->normal_mode_fw.ext_board->size;
+ }
return 0;
}
static int ath10k_core_parse_bd_ie_board(struct ath10k *ar,
const void *buf, size_t buf_len,
- const char *boardname)
+ const char *boardname,
+ int bd_ie_type)
{
const struct ath10k_fw_ie *hdr;
bool name_match_found;
@@ -1276,12 +1146,21 @@ static int ath10k_core_parse_bd_ie_board(struct ath10k *ar,
/* no match found */
break;
- ath10k_dbg(ar, ATH10K_DBG_BOOT,
- "boot found board data for '%s'",
- boardname);
+ if (bd_ie_type == ATH10K_BD_IE_BOARD) {
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
+ "boot found board data for '%s'",
+ boardname);
- ar->normal_mode_fw.board_data = board_ie_data;
- ar->normal_mode_fw.board_len = board_ie_len;
+ ar->normal_mode_fw.board_data = board_ie_data;
+ ar->normal_mode_fw.board_len = board_ie_len;
+ } else if (bd_ie_type == ATH10K_BD_IE_BOARD_EXT) {
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
+ "boot found eboard data for '%s'",
+ boardname);
+
+ ar->normal_mode_fw.ext_board_data = board_ie_data;
+ ar->normal_mode_fw.ext_board_len = board_ie_len;
+ }
ret = 0;
goto out;
@@ -1331,7 +1210,18 @@ static int ath10k_core_search_bd(struct ath10k *ar,
switch (ie_id) {
case ATH10K_BD_IE_BOARD:
ret = ath10k_core_parse_bd_ie_board(ar, data, ie_len,
- boardname);
+ boardname,
+ ATH10K_BD_IE_BOARD);
+ if (ret == -ENOENT)
+ /* no match found, continue */
+ break;
+
+ /* either found or error, so stop searching */
+ goto out;
+ case ATH10K_BD_IE_BOARD_EXT:
+ ret = ath10k_core_parse_bd_ie_board(ar, data, ie_len,
+ boardname,
+ ATH10K_BD_IE_BOARD_EXT);
if (ret == -ENOENT)
/* no match found, continue */
break;
@@ -1361,9 +1251,11 @@ static int ath10k_core_fetch_board_data_api_n(struct ath10k *ar,
const u8 *data;
int ret;
- ar->normal_mode_fw.board = ath10k_fetch_fw_file(ar,
- ar->hw_params.fw.dir,
- filename);
+ /* Skip if already fetched during board data download */
+ if (!ar->normal_mode_fw.board)
+ ar->normal_mode_fw.board = ath10k_fetch_fw_file(ar,
+ ar->hw_params.fw.dir,
+ filename);
if (IS_ERR(ar->normal_mode_fw.board))
return PTR_ERR(ar->normal_mode_fw.board);
@@ -1440,6 +1332,14 @@ static int ath10k_core_create_board_name(struct ath10k *ar, char *name,
goto out;
}
+ if (ar->id.qmi_ids_valid) {
+ scnprintf(name, name_len,
+ "bus=%s,qmi-board-id=%x",
+ ath10k_bus_str(ar->hif.bus),
+ ar->id.qmi_board_id);
+ goto out;
+ }
+
scnprintf(name, name_len,
"bus=%s,vendor=%04x,device=%04x,subsystem-vendor=%04x,subsystem-device=%04x%s",
ath10k_bus_str(ar->hif.bus),
@@ -1451,23 +1351,49 @@ out:
return 0;
}
-static int ath10k_core_fetch_board_file(struct ath10k *ar)
+static int ath10k_core_create_eboard_name(struct ath10k *ar, char *name,
+ size_t name_len)
+{
+ if (ar->id.bmi_ids_valid) {
+ scnprintf(name, name_len,
+ "bus=%s,bmi-chip-id=%d,bmi-eboard-id=%d",
+ ath10k_bus_str(ar->hif.bus),
+ ar->id.bmi_chip_id,
+ ar->id.bmi_eboard_id);
+
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot using eboard name '%s'\n", name);
+ return 0;
+ }
+ /* Fallback if returned board id is zero */
+ return -1;
+}
+
+int ath10k_core_fetch_board_file(struct ath10k *ar, int bd_ie_type)
{
char boardname[100], fallback_boardname[100];
int ret;
- ret = ath10k_core_create_board_name(ar, boardname,
- sizeof(boardname), true);
- if (ret) {
- ath10k_err(ar, "failed to create board name: %d", ret);
- return ret;
- }
+ if (bd_ie_type == ATH10K_BD_IE_BOARD) {
+ ret = ath10k_core_create_board_name(ar, boardname,
+ sizeof(boardname), true);
+ if (ret) {
+ ath10k_err(ar, "failed to create board name: %d", ret);
+ return ret;
+ }
- ret = ath10k_core_create_board_name(ar, fallback_boardname,
- sizeof(boardname), false);
- if (ret) {
- ath10k_err(ar, "failed to create fallback board name: %d", ret);
- return ret;
+ ret = ath10k_core_create_board_name(ar, fallback_boardname,
+ sizeof(boardname), false);
+ if (ret) {
+ ath10k_err(ar, "failed to create fallback board name: %d", ret);
+ return ret;
+ }
+ } else if (bd_ie_type == ATH10K_BD_IE_BOARD_EXT) {
+ ret = ath10k_core_create_eboard_name(ar, boardname,
+ sizeof(boardname));
+ if (ret) {
+ ath10k_err(ar, "fallback to eboard.bin since board id 0");
+ goto fallback;
+ }
}
ar->bd_api = 2;
@@ -1477,8 +1403,9 @@ static int ath10k_core_fetch_board_file(struct ath10k *ar)
if (!ret)
goto success;
+fallback:
ar->bd_api = 1;
- ret = ath10k_core_fetch_board_data_api_1(ar);
+ ret = ath10k_core_fetch_board_data_api_1(ar, bd_ie_type);
if (ret) {
ath10k_err(ar, "failed to fetch board-2.bin or board.bin from %s\n",
ar->hw_params.fw.dir);
@@ -1489,6 +1416,292 @@ success:
ath10k_dbg(ar, ATH10K_DBG_BOOT, "using board api %d\n", ar->bd_api);
return 0;
}
+EXPORT_SYMBOL(ath10k_core_fetch_board_file);
+
+static int ath10k_core_get_ext_board_id_from_otp(struct ath10k *ar)
+{
+ u32 result, address;
+ u8 ext_board_id;
+ int ret;
+
+ address = ar->hw_params.patch_load_addr;
+
+ if (!ar->normal_mode_fw.fw_file.otp_data ||
+ !ar->normal_mode_fw.fw_file.otp_len) {
+ ath10k_warn(ar,
+ "failed to retrieve extended board id due to otp binary missing\n");
+ return -ENODATA;
+ }
+
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
+ "boot upload otp to 0x%x len %zd for ext board id\n",
+ address, ar->normal_mode_fw.fw_file.otp_len);
+
+ ret = ath10k_bmi_fast_download(ar, address,
+ ar->normal_mode_fw.fw_file.otp_data,
+ ar->normal_mode_fw.fw_file.otp_len);
+ if (ret) {
+ ath10k_err(ar, "could not write otp for ext board id check: %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = ath10k_bmi_execute(ar, address, BMI_PARAM_GET_EXT_BOARD_ID, &result);
+ if (ret) {
+ ath10k_err(ar, "could not execute otp for ext board id check: %d\n",
+ ret);
+ return ret;
+ }
+
+ if (!result) {
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
+ "ext board id does not exist in otp, ignore it\n");
+ return -EOPNOTSUPP;
+ }
+
+ ext_board_id = result & ATH10K_BMI_EBOARD_ID_STATUS_MASK;
+
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
+ "boot get otp ext board id result 0x%08x ext_board_id %d\n",
+ result, ext_board_id);
+
+ ar->id.bmi_eboard_id = ext_board_id;
+
+ return 0;
+}
+
+static int ath10k_download_board_data(struct ath10k *ar, const void *data,
+ size_t data_len)
+{
+ u32 board_data_size = ar->hw_params.fw.board_size;
+ u32 eboard_data_size = ar->hw_params.fw.ext_board_size;
+ u32 board_address;
+ u32 ext_board_address;
+ int ret;
+
+ ret = ath10k_push_board_ext_data(ar, data, data_len);
+ if (ret) {
+ ath10k_err(ar, "could not push board ext data (%d)\n", ret);
+ goto exit;
+ }
+
+ ret = ath10k_bmi_read32(ar, hi_board_data, &board_address);
+ if (ret) {
+ ath10k_err(ar, "could not read board data addr (%d)\n", ret);
+ goto exit;
+ }
+
+ ret = ath10k_bmi_write_memory(ar, board_address, data,
+ min_t(u32, board_data_size,
+ data_len));
+ if (ret) {
+ ath10k_err(ar, "could not write board data (%d)\n", ret);
+ goto exit;
+ }
+
+ ret = ath10k_bmi_write32(ar, hi_board_data_initialized, 1);
+ if (ret) {
+ ath10k_err(ar, "could not write board data bit (%d)\n", ret);
+ goto exit;
+ }
+
+ if (!ar->id.ext_bid_supported)
+ goto exit;
+
+ /* Extended board data download */
+ ret = ath10k_core_get_ext_board_id_from_otp(ar);
+ if (ret == -EOPNOTSUPP) {
+ /* Not fetching ext_board_data if ext board id is 0 */
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "otp returned ext board id 0\n");
+ return 0;
+ } else if (ret) {
+ ath10k_err(ar, "failed to get extended board id: %d\n", ret);
+ goto exit;
+ }
+
+ ret = ath10k_core_fetch_board_file(ar, ATH10K_BD_IE_BOARD_EXT);
+ if (ret)
+ goto exit;
+
+ if (ar->normal_mode_fw.ext_board_data) {
+ ext_board_address = board_address + EXT_BOARD_ADDRESS_OFFSET;
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
+ "boot writing ext board data to addr 0x%x",
+ ext_board_address);
+ ret = ath10k_bmi_write_memory(ar, ext_board_address,
+ ar->normal_mode_fw.ext_board_data,
+ min_t(u32, eboard_data_size, data_len));
+ if (ret)
+ ath10k_err(ar, "failed to write ext board data: %d\n", ret);
+ }
+
+exit:
+ return ret;
+}
+
+static int ath10k_download_and_run_otp(struct ath10k *ar)
+{
+ u32 result, address = ar->hw_params.patch_load_addr;
+ u32 bmi_otp_exe_param = ar->hw_params.otp_exe_param;
+ int ret;
+
+ ret = ath10k_download_board_data(ar,
+ ar->running_fw->board_data,
+ ar->running_fw->board_len);
+ if (ret) {
+ ath10k_err(ar, "failed to download board data: %d\n", ret);
+ return ret;
+ }
+
+ /* OTP is optional */
+
+ if (!ar->running_fw->fw_file.otp_data ||
+ !ar->running_fw->fw_file.otp_len) {
+ ath10k_warn(ar, "Not running otp, calibration will be incorrect (otp-data %pK otp_len %zd)!\n",
+ ar->running_fw->fw_file.otp_data,
+ ar->running_fw->fw_file.otp_len);
+ return 0;
+ }
+
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot upload otp to 0x%x len %zd\n",
+ address, ar->running_fw->fw_file.otp_len);
+
+ ret = ath10k_bmi_fast_download(ar, address,
+ ar->running_fw->fw_file.otp_data,
+ ar->running_fw->fw_file.otp_len);
+ if (ret) {
+ ath10k_err(ar, "could not write otp (%d)\n", ret);
+ return ret;
+ }
+
+ /* As of now pre-cal is valid for 10_4 variants */
+ if (ar->cal_mode == ATH10K_PRE_CAL_MODE_DT ||
+ ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE)
+ bmi_otp_exe_param = BMI_PARAM_FLASH_SECTION_ALL;
+
+ ret = ath10k_bmi_execute(ar, address, bmi_otp_exe_param, &result);
+ if (ret) {
+ ath10k_err(ar, "could not execute otp (%d)\n", ret);
+ return ret;
+ }
+
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot otp execute result %d\n", result);
+
+ if (!(skip_otp || test_bit(ATH10K_FW_FEATURE_IGNORE_OTP_RESULT,
+ ar->running_fw->fw_file.fw_features)) &&
+ result != 0) {
+ ath10k_err(ar, "otp calibration failed: %d", result);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ath10k_download_cal_file(struct ath10k *ar,
+ const struct firmware *file)
+{
+ int ret;
+
+ if (!file)
+ return -ENOENT;
+
+ if (IS_ERR(file))
+ return PTR_ERR(file);
+
+ ret = ath10k_download_board_data(ar, file->data, file->size);
+ if (ret) {
+ ath10k_err(ar, "failed to download cal_file data: %d\n", ret);
+ return ret;
+ }
+
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cal file downloaded\n");
+
+ return 0;
+}
+
+static int ath10k_download_cal_dt(struct ath10k *ar, const char *dt_name)
+{
+ struct device_node *node;
+ int data_len;
+ void *data;
+ int ret;
+
+ node = ar->dev->of_node;
+ if (!node)
+ /* Device Tree is optional, don't print any warnings if
+ * there's no node for ath10k.
+ */
+ return -ENOENT;
+
+ if (!of_get_property(node, dt_name, &data_len)) {
+ /* The calibration data node is optional */
+ return -ENOENT;
+ }
+
+ if (data_len != ar->hw_params.cal_data_len) {
+ ath10k_warn(ar, "invalid calibration data length in DT: %d\n",
+ data_len);
+ ret = -EMSGSIZE;
+ goto out;
+ }
+
+ data = kmalloc(data_len, GFP_KERNEL);
+ if (!data) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = of_property_read_u8_array(node, dt_name, data, data_len);
+ if (ret) {
+ ath10k_warn(ar, "failed to read calibration data from DT: %d\n",
+ ret);
+ goto out_free;
+ }
+
+ ret = ath10k_download_board_data(ar, data, data_len);
+ if (ret) {
+ ath10k_warn(ar, "failed to download calibration data from Device Tree: %d\n",
+ ret);
+ goto out_free;
+ }
+
+ ret = 0;
+
+out_free:
+ kfree(data);
+
+out:
+ return ret;
+}
+
+static int ath10k_download_cal_eeprom(struct ath10k *ar)
+{
+ size_t data_len;
+ void *data = NULL;
+ int ret;
+
+ ret = ath10k_hif_fetch_cal_eeprom(ar, &data, &data_len);
+ if (ret) {
+ if (ret != -EOPNOTSUPP)
+ ath10k_warn(ar, "failed to read calibration data from EEPROM: %d\n",
+ ret);
+ goto out_free;
+ }
+
+ ret = ath10k_download_board_data(ar, data, data_len);
+ if (ret) {
+ ath10k_warn(ar, "failed to download calibration data from EEPROM: %d\n",
+ ret);
+ goto out_free;
+ }
+
+ ret = 0;
+
+out_free:
+ kfree(data);
+
+ return ret;
+}
int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name,
struct ath10k_fw_file *fw_file)
@@ -1882,7 +2095,8 @@ static int ath10k_init_hw_params(struct ath10k *ar)
for (i = 0; i < ARRAY_SIZE(ath10k_hw_params_list); i++) {
hw_params = &ath10k_hw_params_list[i];
- if (hw_params->id == ar->target_version &&
+ if (hw_params->bus == ar->hif.bus &&
+ hw_params->id == ar->target_version &&
hw_params->dev_id == ar->dev_id)
break;
}
@@ -1983,6 +2197,7 @@ static void ath10k_core_set_coverage_class_work(struct work_struct *work)
static int ath10k_core_init_firmware_features(struct ath10k *ar)
{
struct ath10k_fw_file *fw_file = &ar->normal_mode_fw.fw_file;
+ int max_num_peers;
if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, fw_file->fw_features) &&
!test_bit(ATH10K_FW_FEATURE_WMI_10X, fw_file->fw_features)) {
@@ -2062,7 +2277,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
switch (fw_file->wmi_op_version) {
case ATH10K_FW_WMI_OP_VERSION_MAIN:
- ar->max_num_peers = TARGET_NUM_PEERS;
+ max_num_peers = TARGET_NUM_PEERS;
ar->max_num_stations = TARGET_NUM_STATIONS;
ar->max_num_vdevs = TARGET_NUM_VDEVS;
ar->htt.max_num_pending_tx = TARGET_NUM_MSDU_DESC;
@@ -2074,10 +2289,10 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
case ATH10K_FW_WMI_OP_VERSION_10_2:
case ATH10K_FW_WMI_OP_VERSION_10_2_4:
if (ath10k_peer_stats_enabled(ar)) {
- ar->max_num_peers = TARGET_10X_TX_STATS_NUM_PEERS;
+ max_num_peers = TARGET_10X_TX_STATS_NUM_PEERS;
ar->max_num_stations = TARGET_10X_TX_STATS_NUM_STATIONS;
} else {
- ar->max_num_peers = TARGET_10X_NUM_PEERS;
+ max_num_peers = TARGET_10X_NUM_PEERS;
ar->max_num_stations = TARGET_10X_NUM_STATIONS;
}
ar->max_num_vdevs = TARGET_10X_NUM_VDEVS;
@@ -2086,7 +2301,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM;
break;
case ATH10K_FW_WMI_OP_VERSION_TLV:
- ar->max_num_peers = TARGET_TLV_NUM_PEERS;
+ max_num_peers = TARGET_TLV_NUM_PEERS;
ar->max_num_stations = TARGET_TLV_NUM_STATIONS;
ar->max_num_vdevs = TARGET_TLV_NUM_VDEVS;
ar->max_num_tdls_vdevs = TARGET_TLV_NUM_TDLS_VDEVS;
@@ -2098,7 +2313,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
ar->wmi.mgmt_max_num_pending_tx = TARGET_TLV_MGMT_NUM_MSDU_DESC;
break;
case ATH10K_FW_WMI_OP_VERSION_10_4:
- ar->max_num_peers = TARGET_10_4_NUM_PEERS;
+ max_num_peers = TARGET_10_4_NUM_PEERS;
ar->max_num_stations = TARGET_10_4_NUM_STATIONS;
ar->num_active_peers = TARGET_10_4_ACTIVE_PEERS;
ar->max_num_vdevs = TARGET_10_4_NUM_VDEVS;
@@ -2117,10 +2332,16 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
break;
case ATH10K_FW_WMI_OP_VERSION_UNSET:
case ATH10K_FW_WMI_OP_VERSION_MAX:
+ default:
WARN_ON(1);
return -EINVAL;
}
+ if (ar->hw_params.num_peers)
+ ar->max_num_peers = ar->hw_params.num_peers;
+ else
+ ar->max_num_peers = max_num_peers;
+
/* Backwards compatibility for firmwares without
* ATH10K_FW_IE_HTT_OP_VERSION.
*/
@@ -2370,6 +2591,10 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
ar->wmi.svc_map))
val |= WMI_10_4_TDLS_UAPSD_BUFFER_STA;
+ if (test_bit(WMI_SERVICE_TX_DATA_ACK_RSSI,
+ ar->wmi.svc_map))
+ val |= WMI_10_4_TX_DATA_ACK_RSSI;
+
status = ath10k_mac_ext_resource_config(ar, val);
if (status) {
ath10k_err(ar,
@@ -2405,7 +2630,8 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
* possible to implicitly make it correct by creating a dummy vdev and
* then deleting it.
*/
- if (mode == ATH10K_FIRMWARE_MODE_NORMAL) {
+ if (ar->hw_params.hw_filter_reset_required &&
+ mode == ATH10K_FIRMWARE_MODE_NORMAL) {
status = ath10k_core_reset_rx_filter(ar);
if (status) {
ath10k_err(ar,
@@ -2593,7 +2819,7 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
if (ret)
ath10k_dbg(ar, ATH10K_DBG_BOOT, "DT bdf variant name not set.\n");
- ret = ath10k_core_fetch_board_file(ar);
+ ret = ath10k_core_fetch_board_file(ar, ATH10K_BD_IE_BOARD);
if (ret) {
ath10k_err(ar, "failed to fetch board file: %d\n", ret);
goto err_free_firmware_files;
@@ -2602,6 +2828,8 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
ath10k_debug_print_board_info(ar);
}
+ device_get_mac_address(ar->dev, ar->mac_addr, sizeof(ar->mac_addr));
+
ret = ath10k_core_init_firmware_features(ar);
if (ret) {
ath10k_err(ar, "fatal problem with firmware features: %d\n",
@@ -2714,9 +2942,11 @@ err:
return;
}
-int ath10k_core_register(struct ath10k *ar, u32 chip_id)
+int ath10k_core_register(struct ath10k *ar,
+ const struct ath10k_bus_params *bus_params)
{
- ar->chip_id = chip_id;
+ ar->chip_id = bus_params->chip_id;
+ ar->dev_type = bus_params->dev_type;
queue_work(ar->workqueue, &ar->register_work);
return 0;
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 9feea02e7d37..042418097cf9 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -92,14 +92,6 @@
struct ath10k;
-enum ath10k_bus {
- ATH10K_BUS_PCI,
- ATH10K_BUS_AHB,
- ATH10K_BUS_SDIO,
- ATH10K_BUS_USB,
- ATH10K_BUS_SNOC,
-};
-
static inline const char *ath10k_bus_str(enum ath10k_bus bus)
{
switch (bus) {
@@ -461,6 +453,36 @@ struct ath10k_sta_tid_stats {
unsigned long int rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_MAX];
};
+enum ath10k_counter_type {
+ ATH10K_COUNTER_TYPE_BYTES,
+ ATH10K_COUNTER_TYPE_PKTS,
+ ATH10K_COUNTER_TYPE_MAX,
+};
+
+enum ath10k_stats_type {
+ ATH10K_STATS_TYPE_SUCC,
+ ATH10K_STATS_TYPE_FAIL,
+ ATH10K_STATS_TYPE_RETRY,
+ ATH10K_STATS_TYPE_AMPDU,
+ ATH10K_STATS_TYPE_MAX,
+};
+
+struct ath10k_htt_data_stats {
+ u64 legacy[ATH10K_COUNTER_TYPE_MAX][ATH10K_LEGACY_NUM];
+ u64 ht[ATH10K_COUNTER_TYPE_MAX][ATH10K_HT_MCS_NUM];
+ u64 vht[ATH10K_COUNTER_TYPE_MAX][ATH10K_VHT_MCS_NUM];
+ u64 bw[ATH10K_COUNTER_TYPE_MAX][ATH10K_BW_NUM];
+ u64 nss[ATH10K_COUNTER_TYPE_MAX][ATH10K_NSS_NUM];
+ u64 gi[ATH10K_COUNTER_TYPE_MAX][ATH10K_GI_NUM];
+};
+
+struct ath10k_htt_tx_stats {
+ struct ath10k_htt_data_stats stats[ATH10K_STATS_TYPE_MAX];
+ u64 tx_duration;
+ u64 ba_fails;
+ u64 ack_fails;
+};
+
struct ath10k_sta {
struct ath10k_vif *arvif;
@@ -474,6 +496,7 @@ struct ath10k_sta {
struct work_struct update_wk;
u64 rx_duration;
+ struct ath10k_htt_tx_stats *tx_stats;
#ifdef CONFIG_MAC80211_DEBUGFS
/* protected by conf_mutex */
@@ -482,6 +505,8 @@ struct ath10k_sta {
/* Protected with ar->data_lock */
struct ath10k_sta_tid_stats tid_stats[IEEE80211_NUM_TIDS + 1];
#endif
+ /* Protected with ar->data_lock */
+ u32 peer_ps_state;
};
#define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5 * HZ)
@@ -607,6 +632,7 @@ struct ath10k_debug {
u32 reg_addr;
u32 nf_cal_period;
void *cal_data;
+ u32 enable_extd_tx_stats;
};
enum ath10k_state {
@@ -861,6 +887,9 @@ struct ath10k_fw_components {
const struct firmware *board;
const void *board_data;
size_t board_len;
+ const struct firmware *ext_board;
+ const void *ext_board_data;
+ size_t ext_board_len;
struct ath10k_fw_file fw_file;
};
@@ -880,6 +909,16 @@ struct ath10k_per_peer_tx_stats {
u32 reserved2;
};
+enum ath10k_dev_type {
+ ATH10K_DEV_TYPE_LL,
+ ATH10K_DEV_TYPE_HL,
+};
+
+struct ath10k_bus_params {
+ u32 chip_id;
+ enum ath10k_dev_type dev_type;
+};
+
struct ath10k {
struct ath_common ath_common;
struct ieee80211_hw *hw;
@@ -890,6 +929,7 @@ struct ath10k {
enum ath10k_hw_rev hw_rev;
u16 dev_id;
u32 chip_id;
+ enum ath10k_dev_type dev_type;
u32 target_version;
u8 fw_version_major;
u32 fw_version_minor;
@@ -908,7 +948,10 @@ struct ath10k {
u32 low_5ghz_chan;
u32 high_5ghz_chan;
bool ani_enabled;
+ /* protected by conf_mutex */
+ u8 ps_state_enable;
+ bool nlo_enabled;
bool p2p;
struct {
@@ -946,8 +989,12 @@ struct ath10k {
u32 subsystem_device;
bool bmi_ids_valid;
+ bool qmi_ids_valid;
+ u32 qmi_board_id;
u8 bmi_board_id;
+ u8 bmi_eboard_id;
u8 bmi_chip_id;
+ bool ext_bid_supported;
char bdf_ext[ATH10K_SMBIOS_BDF_EXT_STR_LENGTH];
} id;
@@ -1003,6 +1050,7 @@ struct ath10k {
struct completion install_key_done;
+ int last_wmi_vdev_start_status;
struct completion vdev_setup_done;
struct workqueue_struct *workqueue;
@@ -1167,7 +1215,10 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
const struct ath10k_fw_components *fw_components);
int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt);
void ath10k_core_stop(struct ath10k *ar);
-int ath10k_core_register(struct ath10k *ar, u32 chip_id);
+int ath10k_core_register(struct ath10k *ar,
+ const struct ath10k_bus_params *bus_params);
void ath10k_core_unregister(struct ath10k *ar);
+int ath10k_core_fetch_board_file(struct ath10k *ar, int bd_ie_type);
+void ath10k_core_free_board_files(struct ath10k *ar);
#endif /* _CORE_H_ */
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index 0baaad90b8d1..15964b374f68 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -2042,6 +2042,61 @@ static const struct file_operations fops_btcoex = {
.open = simple_open
};
+static ssize_t ath10k_write_enable_extd_tx_stats(struct file *file,
+ const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ u32 filter;
+ int ret;
+
+ if (kstrtouint_from_user(ubuf, count, 0, &filter))
+ return -EINVAL;
+
+ mutex_lock(&ar->conf_mutex);
+
+ if (ar->state != ATH10K_STATE_ON) {
+ ar->debug.enable_extd_tx_stats = filter;
+ ret = count;
+ goto out;
+ }
+
+ if (filter == ar->debug.enable_extd_tx_stats) {
+ ret = count;
+ goto out;
+ }
+
+ ar->debug.enable_extd_tx_stats = filter;
+ ret = count;
+
+out:
+ mutex_unlock(&ar->conf_mutex);
+ return ret;
+}
+
+static ssize_t ath10k_read_enable_extd_tx_stats(struct file *file,
+ char __user *ubuf,
+ size_t count, loff_t *ppos)
+
+{
+ char buf[32];
+ struct ath10k *ar = file->private_data;
+ int len = 0;
+
+ mutex_lock(&ar->conf_mutex);
+ len = scnprintf(buf, sizeof(buf) - len, "%08x\n",
+ ar->debug.enable_extd_tx_stats);
+ mutex_unlock(&ar->conf_mutex);
+
+ return simple_read_from_buffer(ubuf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_enable_extd_tx_stats = {
+ .read = ath10k_read_enable_extd_tx_stats,
+ .write = ath10k_write_enable_extd_tx_stats,
+ .open = simple_open
+};
+
static ssize_t ath10k_write_peer_stats(struct file *file,
const char __user *ubuf,
size_t count, loff_t *ppos)
@@ -2343,6 +2398,85 @@ static const struct file_operations fops_warm_hw_reset = {
.llseek = default_llseek,
};
+static void ath10k_peer_ps_state_disable(void *data,
+ struct ieee80211_sta *sta)
+{
+ struct ath10k *ar = data;
+ struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
+
+ spin_lock_bh(&ar->data_lock);
+ arsta->peer_ps_state = WMI_PEER_PS_STATE_DISABLED;
+ spin_unlock_bh(&ar->data_lock);
+}
+
+static ssize_t ath10k_write_ps_state_enable(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ int ret;
+ u32 param;
+ u8 ps_state_enable;
+
+ if (kstrtou8_from_user(user_buf, count, 0, &ps_state_enable))
+ return -EINVAL;
+
+ if (ps_state_enable > 1)
+ return -EINVAL;
+
+ mutex_lock(&ar->conf_mutex);
+
+ if (ar->ps_state_enable == ps_state_enable) {
+ ret = count;
+ goto exit;
+ }
+
+ param = ar->wmi.pdev_param->peer_sta_ps_statechg_enable;
+ ret = ath10k_wmi_pdev_set_param(ar, param, ps_state_enable);
+ if (ret) {
+ ath10k_warn(ar, "failed to enable ps_state_enable: %d\n",
+ ret);
+ goto exit;
+ }
+ ar->ps_state_enable = ps_state_enable;
+
+ if (!ar->ps_state_enable)
+ ieee80211_iterate_stations_atomic(ar->hw,
+ ath10k_peer_ps_state_disable,
+ ar);
+
+ ret = count;
+
+exit:
+ mutex_unlock(&ar->conf_mutex);
+
+ return ret;
+}
+
+static ssize_t ath10k_read_ps_state_enable(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ int len = 0;
+ char buf[32];
+
+ mutex_lock(&ar->conf_mutex);
+ len = scnprintf(buf, sizeof(buf) - len, "%d\n",
+ ar->ps_state_enable);
+ mutex_unlock(&ar->conf_mutex);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_ps_state_enable = {
+ .read = ath10k_read_ps_state_enable,
+ .write = ath10k_write_ps_state_enable,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
int ath10k_debug_create(struct ath10k *ar)
{
ar->debug.cal_data = vzalloc(ATH10K_DEBUG_CAL_DATA_LEN);
@@ -2454,10 +2588,15 @@ int ath10k_debug_register(struct ath10k *ar)
debugfs_create_file("btcoex", 0644, ar->debug.debugfs_phy, ar,
&fops_btcoex);
- if (test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map))
+ if (test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map)) {
debugfs_create_file("peer_stats", 0644, ar->debug.debugfs_phy, ar,
&fops_peer_stats);
+ debugfs_create_file("enable_extd_tx_stats", 0644,
+ ar->debug.debugfs_phy, ar,
+ &fops_enable_extd_tx_stats);
+ }
+
debugfs_create_file("fw_checksums", 0400, ar->debug.debugfs_phy, ar,
&fops_fw_checksums);
@@ -2474,6 +2613,9 @@ int ath10k_debug_register(struct ath10k *ar)
debugfs_create_file("warm_hw_reset", 0600, ar->debug.debugfs_phy, ar,
&fops_warm_hw_reset);
+ debugfs_create_file("ps_state_enable", 0600, ar->debug.debugfs_phy, ar,
+ &fops_ps_state_enable);
+
return 0;
}
diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h
index 0afca5c106b6..5cf16d690724 100644
--- a/drivers/net/wireless/ath/ath10k/debug.h
+++ b/drivers/net/wireless/ath/ath10k/debug.h
@@ -44,6 +44,7 @@ enum ath10k_debug_mask {
ATH10K_DBG_USB = 0x00040000,
ATH10K_DBG_USB_BULK = 0x00080000,
ATH10K_DBG_SNOC = 0x00100000,
+ ATH10K_DBG_QMI = 0x00200000,
ATH10K_DBG_ANY = 0xffffffff,
};
@@ -128,6 +129,10 @@ static inline u32 ath10k_debug_get_fw_dbglog_level(struct ath10k *ar)
return ar->debug.fw_dbglog_level;
}
+static inline int ath10k_debug_is_extd_tx_stats_enabled(struct ath10k *ar)
+{
+ return ar->debug.enable_extd_tx_stats;
+}
#else
static inline int ath10k_debug_start(struct ath10k *ar)
@@ -190,6 +195,11 @@ static inline u32 ath10k_debug_get_fw_dbglog_level(struct ath10k *ar)
return 0;
}
+static inline int ath10k_debug_is_extd_tx_stats_enabled(struct ath10k *ar)
+{
+ return 0;
+}
+
#define ATH10K_DFS_STAT_INC(ar, c) do { } while (0)
#define ath10k_debug_get_et_strings NULL
diff --git a/drivers/net/wireless/ath/ath10k/debugfs_sta.c b/drivers/net/wireless/ath/ath10k/debugfs_sta.c
index a63c97e2c50c..b09cdc699c69 100644
--- a/drivers/net/wireless/ath/ath10k/debugfs_sta.c
+++ b/drivers/net/wireless/ath/ath10k/debugfs_sta.c
@@ -460,6 +460,33 @@ static const struct file_operations fops_peer_debug_trigger = {
.llseek = default_llseek,
};
+static ssize_t ath10k_dbg_sta_read_peer_ps_state(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ieee80211_sta *sta = file->private_data;
+ struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
+ struct ath10k *ar = arsta->arvif->ar;
+ char buf[20];
+ int len = 0;
+
+ spin_lock_bh(&ar->data_lock);
+
+ len = scnprintf(buf, sizeof(buf) - len, "%d\n",
+ arsta->peer_ps_state);
+
+ spin_unlock_bh(&ar->data_lock);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_peer_ps_state = {
+ .open = simple_open,
+ .read = ath10k_dbg_sta_read_peer_ps_state,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
static char *get_err_str(enum ath10k_pkt_rx_err i)
{
switch (i) {
@@ -626,9 +653,105 @@ static const struct file_operations fops_tid_stats_dump = {
.llseek = default_llseek,
};
+static ssize_t ath10k_dbg_sta_dump_tx_stats(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ieee80211_sta *sta = file->private_data;
+ struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
+ struct ath10k *ar = arsta->arvif->ar;
+ struct ath10k_htt_data_stats *stats;
+ const char *str_name[ATH10K_STATS_TYPE_MAX] = {"succ", "fail",
+ "retry", "ampdu"};
+ const char *str[ATH10K_COUNTER_TYPE_MAX] = {"bytes", "packets"};
+ int len = 0, i, j, k, retval = 0;
+ const int size = 2 * 4096;
+ char *buf;
+
+ buf = kzalloc(size, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ mutex_lock(&ar->conf_mutex);
+
+ spin_lock_bh(&ar->data_lock);
+ for (k = 0; k < ATH10K_STATS_TYPE_MAX; k++) {
+ for (j = 0; j < ATH10K_COUNTER_TYPE_MAX; j++) {
+ stats = &arsta->tx_stats->stats[k];
+ len += scnprintf(buf + len, size - len, "%s_%s\n",
+ str_name[k],
+ str[j]);
+ len += scnprintf(buf + len, size - len,
+ " VHT MCS %s\n",
+ str[j]);
+ for (i = 0; i < ATH10K_VHT_MCS_NUM; i++)
+ len += scnprintf(buf + len, size - len,
+ " %llu ",
+ stats->vht[j][i]);
+ len += scnprintf(buf + len, size - len, "\n");
+ len += scnprintf(buf + len, size - len, " HT MCS %s\n",
+ str[j]);
+ for (i = 0; i < ATH10K_HT_MCS_NUM; i++)
+ len += scnprintf(buf + len, size - len,
+ " %llu ", stats->ht[j][i]);
+ len += scnprintf(buf + len, size - len, "\n");
+ len += scnprintf(buf + len, size - len,
+ " BW %s (20,40,80,160 MHz)\n", str[j]);
+ len += scnprintf(buf + len, size - len,
+ " %llu %llu %llu %llu\n",
+ stats->bw[j][0], stats->bw[j][1],
+ stats->bw[j][2], stats->bw[j][3]);
+ len += scnprintf(buf + len, size - len,
+ " NSS %s (1x1,2x2,3x3,4x4)\n", str[j]);
+ len += scnprintf(buf + len, size - len,
+ " %llu %llu %llu %llu\n",
+ stats->nss[j][0], stats->nss[j][1],
+ stats->nss[j][2], stats->nss[j][3]);
+ len += scnprintf(buf + len, size - len,
+ " GI %s (LGI,SGI)\n",
+ str[j]);
+ len += scnprintf(buf + len, size - len, " %llu %llu\n",
+ stats->gi[j][0], stats->gi[j][1]);
+ len += scnprintf(buf + len, size - len,
+ " legacy rate %s (1,2 ... Mbps)\n ",
+ str[j]);
+ for (i = 0; i < ATH10K_LEGACY_NUM; i++)
+ len += scnprintf(buf + len, size - len, "%llu ",
+ stats->legacy[j][i]);
+ len += scnprintf(buf + len, size - len, "\n");
+ }
+ }
+
+ len += scnprintf(buf + len, size - len,
+ "\nTX duration\n %llu usecs\n",
+ arsta->tx_stats->tx_duration);
+ len += scnprintf(buf + len, size - len,
+ "BA fails\n %llu\n", arsta->tx_stats->ba_fails);
+ len += scnprintf(buf + len, size - len,
+ "ack fails\n %llu\n", arsta->tx_stats->ack_fails);
+ spin_unlock_bh(&ar->data_lock);
+
+ if (len > size)
+ len = size;
+ retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+ kfree(buf);
+
+ mutex_unlock(&ar->conf_mutex);
+ return retval;
+}
+
+static const struct file_operations fops_tx_stats = {
+ .read = ath10k_dbg_sta_dump_tx_stats,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct dentry *dir)
{
+ struct ath10k *ar = hw->priv;
+
debugfs_create_file("aggr_mode", 0644, dir, sta, &fops_aggr_mode);
debugfs_create_file("addba", 0200, dir, sta, &fops_addba);
debugfs_create_file("addba_resp", 0200, dir, sta, &fops_addba_resp);
@@ -637,4 +760,11 @@ void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
&fops_peer_debug_trigger);
debugfs_create_file("dump_tid_stats", 0400, dir, sta,
&fops_tid_stats_dump);
+
+ if (ath10k_peer_stats_enabled(ar) &&
+ ath10k_debug_is_extd_tx_stats_enabled(ar))
+ debugfs_create_file("tx_stats", 0400, dir, sta,
+ &fops_tx_stats);
+ debugfs_create_file("peer_ps_state", 0400, dir, sta,
+ &fops_peer_ps_state);
}
diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c
index 331b8d558791..28daed5981a1 100644
--- a/drivers/net/wireless/ath/ath10k/htc.c
+++ b/drivers/net/wireless/ath/ath10k/htc.c
@@ -53,7 +53,8 @@ static inline void ath10k_htc_restore_tx_skb(struct ath10k_htc *htc,
{
struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb);
- dma_unmap_single(htc->ar->dev, skb_cb->paddr, skb->len, DMA_TO_DEVICE);
+ if (htc->ar->dev_type != ATH10K_DEV_TYPE_HL)
+ dma_unmap_single(htc->ar->dev, skb_cb->paddr, skb->len, DMA_TO_DEVICE);
skb_pull(skb, sizeof(struct ath10k_htc_hdr));
}
@@ -137,11 +138,14 @@ int ath10k_htc_send(struct ath10k_htc *htc,
ath10k_htc_prepare_tx_skb(ep, skb);
skb_cb->eid = eid;
- skb_cb->paddr = dma_map_single(dev, skb->data, skb->len, DMA_TO_DEVICE);
- ret = dma_mapping_error(dev, skb_cb->paddr);
- if (ret) {
- ret = -EIO;
- goto err_credits;
+ if (ar->dev_type != ATH10K_DEV_TYPE_HL) {
+ skb_cb->paddr = dma_map_single(dev, skb->data, skb->len,
+ DMA_TO_DEVICE);
+ ret = dma_mapping_error(dev, skb_cb->paddr);
+ if (ret) {
+ ret = -EIO;
+ goto err_credits;
+ }
}
sg_item.transfer_id = ep->eid;
@@ -157,7 +161,8 @@ int ath10k_htc_send(struct ath10k_htc *htc,
return 0;
err_unmap:
- dma_unmap_single(dev, skb_cb->paddr, skb->len, DMA_TO_DEVICE);
+ if (ar->dev_type != ATH10K_DEV_TYPE_HL)
+ dma_unmap_single(dev, skb_cb->paddr, skb->len, DMA_TO_DEVICE);
err_credits:
if (ep->tx_credit_flow_enabled) {
spin_lock_bh(&htc->tx_lock);
@@ -803,8 +808,11 @@ setup:
ep->service_id,
&ep->ul_pipe_id,
&ep->dl_pipe_id);
- if (status)
+ if (status) {
+ ath10k_warn(ar, "unsupported HTC service id: %d\n",
+ ep->service_id);
return status;
+ }
ath10k_dbg(ar, ATH10K_DBG_BOOT,
"boot htc service '%s' ul pipe %d dl pipe %d eid %d ready\n",
@@ -838,6 +846,56 @@ struct sk_buff *ath10k_htc_alloc_skb(struct ath10k *ar, int size)
return skb;
}
+static void ath10k_htc_pktlog_process_rx(struct ath10k *ar, struct sk_buff *skb)
+{
+ trace_ath10k_htt_pktlog(ar, skb->data, skb->len);
+ dev_kfree_skb_any(skb);
+}
+
+static int ath10k_htc_pktlog_connect(struct ath10k *ar)
+{
+ struct ath10k_htc_svc_conn_resp conn_resp;
+ struct ath10k_htc_svc_conn_req conn_req;
+ int status;
+
+ memset(&conn_req, 0, sizeof(conn_req));
+ memset(&conn_resp, 0, sizeof(conn_resp));
+
+ conn_req.ep_ops.ep_tx_complete = NULL;
+ conn_req.ep_ops.ep_rx_complete = ath10k_htc_pktlog_process_rx;
+ conn_req.ep_ops.ep_tx_credits = NULL;
+
+ /* connect to control service */
+ conn_req.service_id = ATH10K_HTC_SVC_ID_HTT_LOG_MSG;
+ status = ath10k_htc_connect_service(&ar->htc, &conn_req, &conn_resp);
+ if (status) {
+ ath10k_warn(ar, "failed to connect to PKTLOG service: %d\n",
+ status);
+ return status;
+ }
+
+ return 0;
+}
+
+static bool ath10k_htc_pktlog_svc_supported(struct ath10k *ar)
+{
+ u8 ul_pipe_id;
+ u8 dl_pipe_id;
+ int status;
+
+ status = ath10k_hif_map_service_to_pipe(ar, ATH10K_HTC_SVC_ID_HTT_LOG_MSG,
+ &ul_pipe_id,
+ &dl_pipe_id);
+ if (status) {
+ ath10k_warn(ar, "unsupported HTC service id: %d\n",
+ ATH10K_HTC_SVC_ID_HTT_LOG_MSG);
+
+ return false;
+ }
+
+ return true;
+}
+
int ath10k_htc_start(struct ath10k_htc *htc)
{
struct ath10k *ar = htc->ar;
@@ -871,6 +929,14 @@ int ath10k_htc_start(struct ath10k_htc *htc)
return status;
}
+ if (ath10k_htc_pktlog_svc_supported(ar)) {
+ status = ath10k_htc_pktlog_connect(ar);
+ if (status) {
+ ath10k_err(ar, "failed to connect to pktlog: %d\n", status);
+ return status;
+ }
+ }
+
return 0;
}
diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
index 5d3ff80f3a1f..a76f7c9e2199 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -29,7 +29,6 @@
#include "htc.h"
#include "hw.h"
#include "rx_desc.h"
-#include "hw.h"
enum htt_dbg_stats_type {
HTT_DBG_STATS_WAL_PDEV_TXRX = 1 << 0,
@@ -577,6 +576,8 @@ struct htt_mgmt_tx_completion {
#define HTT_RX_INDICATION_INFO1_NUM_MPDU_RANGES_MASK 0xFF000000
#define HTT_RX_INDICATION_INFO1_NUM_MPDU_RANGES_LSB 24
+#define HTT_TX_CMPL_FLAG_DATA_RSSI BIT(0)
+
struct htt_rx_indication_hdr {
u8 info0; /* %HTT_RX_INDICATION_INFO0_ */
__le16 peer_id;
@@ -719,6 +720,15 @@ struct htt_rx_indication {
struct htt_rx_indication_mpdu_range mpdu_ranges[0];
} __packed;
+/* High latency version of the RX indication */
+struct htt_rx_indication_hl {
+ struct htt_rx_indication_hdr hdr;
+ struct htt_rx_indication_ppdu ppdu;
+ struct htt_rx_indication_prefix prefix;
+ struct fw_rx_desc_hl fw_desc;
+ struct htt_rx_indication_mpdu_range mpdu_ranges[0];
+} __packed;
+
static inline struct htt_rx_indication_mpdu_range *
htt_rx_ind_get_mpdu_ranges(struct htt_rx_indication *rx_ind)
{
@@ -731,6 +741,18 @@ static inline struct htt_rx_indication_mpdu_range *
return ptr;
}
+static inline struct htt_rx_indication_mpdu_range *
+ htt_rx_ind_get_mpdu_ranges_hl(struct htt_rx_indication_hl *rx_ind)
+{
+ void *ptr = rx_ind;
+
+ ptr += sizeof(rx_ind->hdr)
+ + sizeof(rx_ind->ppdu)
+ + sizeof(rx_ind->prefix)
+ + sizeof(rx_ind->fw_desc);
+ return ptr;
+}
+
enum htt_rx_flush_mpdu_status {
HTT_RX_FLUSH_MPDU_DISCARD = 0,
HTT_RX_FLUSH_MPDU_REORDER = 1,
@@ -840,7 +862,7 @@ struct htt_data_tx_completion {
} __packed;
} __packed;
u8 num_msdus;
- u8 rsvd0;
+ u8 flags2; /* HTT_TX_CMPL_FLAG_DATA_RSSI */
__le16 msdus[0]; /* variable length based on %num_msdus */
} __packed;
@@ -1641,6 +1663,7 @@ struct htt_resp {
struct htt_mgmt_tx_completion mgmt_tx_completion;
struct htt_data_tx_completion data_tx_completion;
struct htt_rx_indication rx_ind;
+ struct htt_rx_indication_hl rx_ind_hl;
struct htt_rx_fragment_indication rx_frag_ind;
struct htt_rx_peer_map peer_map;
struct htt_rx_peer_unmap peer_unmap;
@@ -1994,6 +2017,31 @@ struct htt_rx_desc {
u8 msdu_payload[0];
};
+#define HTT_RX_DESC_HL_INFO_SEQ_NUM_MASK 0x00000fff
+#define HTT_RX_DESC_HL_INFO_SEQ_NUM_LSB 0
+#define HTT_RX_DESC_HL_INFO_ENCRYPTED_MASK 0x00001000
+#define HTT_RX_DESC_HL_INFO_ENCRYPTED_LSB 12
+#define HTT_RX_DESC_HL_INFO_CHAN_INFO_PRESENT_MASK 0x00002000
+#define HTT_RX_DESC_HL_INFO_CHAN_INFO_PRESENT_LSB 13
+#define HTT_RX_DESC_HL_INFO_MCAST_BCAST_MASK 0x00008000
+#define HTT_RX_DESC_HL_INFO_MCAST_BCAST_LSB 15
+#define HTT_RX_DESC_HL_INFO_FRAGMENT_MASK 0x00010000
+#define HTT_RX_DESC_HL_INFO_FRAGMENT_LSB 16
+#define HTT_RX_DESC_HL_INFO_KEY_ID_OCT_MASK 0x01fe0000
+#define HTT_RX_DESC_HL_INFO_KEY_ID_OCT_LSB 17
+
+struct htt_rx_desc_base_hl {
+ __le32 info; /* HTT_RX_DESC_HL_INFO_ */
+};
+
+struct htt_rx_chan_info {
+ __le16 primary_chan_center_freq_mhz;
+ __le16 contig_chan1_center_freq_mhz;
+ __le16 contig_chan2_center_freq_mhz;
+ u8 phy_mode;
+ u8 reserved;
+} __packed;
+
#define HTT_RX_DESC_ALIGN 8
#define HTT_MAC_ADDR_LEN 6
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 4d1cd90d6d27..ffec98f7be50 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -265,6 +265,9 @@ int ath10k_htt_rx_ring_refill(struct ath10k *ar)
struct ath10k_htt *htt = &ar->htt;
int ret;
+ if (ar->dev_type == ATH10K_DEV_TYPE_HL)
+ return 0;
+
spin_lock_bh(&htt->rx_ring.lock);
ret = ath10k_htt_rx_ring_fill_n(htt, (htt->rx_ring.fill_level -
htt->rx_ring.fill_cnt));
@@ -279,6 +282,9 @@ int ath10k_htt_rx_ring_refill(struct ath10k *ar)
void ath10k_htt_rx_free(struct ath10k_htt *htt)
{
+ if (htt->ar->dev_type == ATH10K_DEV_TYPE_HL)
+ return;
+
del_timer_sync(&htt->rx_ring.refill_retry_timer);
skb_queue_purge(&htt->rx_msdus_q);
@@ -570,6 +576,9 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt)
size_t size;
struct timer_list *timer = &htt->rx_ring.refill_retry_timer;
+ if (ar->dev_type == ATH10K_DEV_TYPE_HL)
+ return 0;
+
htt->rx_confused = false;
/* XXX: The fill level could be changed during runtime in response to
@@ -1176,11 +1185,11 @@ static void ath10k_htt_rx_h_undecap_raw(struct ath10k *ar,
*/
/* This probably shouldn't happen but warn just in case */
- if (unlikely(WARN_ON_ONCE(!is_first)))
+ if (WARN_ON_ONCE(!is_first))
return;
/* This probably shouldn't happen but warn just in case */
- if (unlikely(WARN_ON_ONCE(!(is_first && is_last))))
+ if (WARN_ON_ONCE(!(is_first && is_last)))
return;
skb_trim(msdu, msdu->len - FCS_LEN);
@@ -1846,8 +1855,116 @@ static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt)
return 0;
}
-static void ath10k_htt_rx_proc_rx_ind(struct ath10k_htt *htt,
- struct htt_rx_indication *rx)
+static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt,
+ struct htt_rx_indication_hl *rx,
+ struct sk_buff *skb)
+{
+ struct ath10k *ar = htt->ar;
+ struct ath10k_peer *peer;
+ struct htt_rx_indication_mpdu_range *mpdu_ranges;
+ struct fw_rx_desc_hl *fw_desc;
+ struct ieee80211_hdr *hdr;
+ struct ieee80211_rx_status *rx_status;
+ u16 peer_id;
+ u8 rx_desc_len;
+ int num_mpdu_ranges;
+ size_t tot_hdr_len;
+ struct ieee80211_channel *ch;
+
+ peer_id = __le16_to_cpu(rx->hdr.peer_id);
+
+ spin_lock_bh(&ar->data_lock);
+ peer = ath10k_peer_find_by_id(ar, peer_id);
+ spin_unlock_bh(&ar->data_lock);
+ if (!peer)
+ ath10k_warn(ar, "Got RX ind from invalid peer: %u\n", peer_id);
+
+ num_mpdu_ranges = MS(__le32_to_cpu(rx->hdr.info1),
+ HTT_RX_INDICATION_INFO1_NUM_MPDU_RANGES);
+ mpdu_ranges = htt_rx_ind_get_mpdu_ranges_hl(rx);
+ fw_desc = &rx->fw_desc;
+ rx_desc_len = fw_desc->len;
+
+ /* I have not yet seen any case where num_mpdu_ranges > 1.
+ * qcacld does not seem handle that case either, so we introduce the
+ * same limitiation here as well.
+ */
+ if (num_mpdu_ranges > 1)
+ ath10k_warn(ar,
+ "Unsupported number of MPDU ranges: %d, ignoring all but the first\n",
+ num_mpdu_ranges);
+
+ if (mpdu_ranges->mpdu_range_status !=
+ HTT_RX_IND_MPDU_STATUS_OK) {
+ ath10k_warn(ar, "MPDU range status: %d\n",
+ mpdu_ranges->mpdu_range_status);
+ goto err;
+ }
+
+ /* Strip off all headers before the MAC header before delivery to
+ * mac80211
+ */
+ tot_hdr_len = sizeof(struct htt_resp_hdr) + sizeof(rx->hdr) +
+ sizeof(rx->ppdu) + sizeof(rx->prefix) +
+ sizeof(rx->fw_desc) +
+ sizeof(*mpdu_ranges) * num_mpdu_ranges + rx_desc_len;
+ skb_pull(skb, tot_hdr_len);
+
+ hdr = (struct ieee80211_hdr *)skb->data;
+ rx_status = IEEE80211_SKB_RXCB(skb);
+ rx_status->chains |= BIT(0);
+ rx_status->signal = ATH10K_DEFAULT_NOISE_FLOOR +
+ rx->ppdu.combined_rssi;
+ rx_status->flag &= ~RX_FLAG_NO_SIGNAL_VAL;
+
+ spin_lock_bh(&ar->data_lock);
+ ch = ar->scan_channel;
+ if (!ch)
+ ch = ar->rx_channel;
+ if (!ch)
+ ch = ath10k_htt_rx_h_any_channel(ar);
+ if (!ch)
+ ch = ar->tgt_oper_chan;
+ spin_unlock_bh(&ar->data_lock);
+
+ if (ch) {
+ rx_status->band = ch->band;
+ rx_status->freq = ch->center_freq;
+ }
+ if (rx->fw_desc.flags & FW_RX_DESC_FLAGS_LAST_MSDU)
+ rx_status->flag &= ~RX_FLAG_AMSDU_MORE;
+ else
+ rx_status->flag |= RX_FLAG_AMSDU_MORE;
+
+ /* Not entirely sure about this, but all frames from the chipset has
+ * the protected flag set even though they have already been decrypted.
+ * Unmasking this flag is necessary in order for mac80211 not to drop
+ * the frame.
+ * TODO: Verify this is always the case or find out a way to check
+ * if there has been hw decryption.
+ */
+ if (ieee80211_has_protected(hdr->frame_control)) {
+ hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+ rx_status->flag |= RX_FLAG_DECRYPTED |
+ RX_FLAG_IV_STRIPPED |
+ RX_FLAG_MMIC_STRIPPED;
+ }
+
+ ieee80211_rx_ni(ar->hw, skb);
+
+ /* We have delivered the skb to the upper layers (mac80211) so we
+ * must not free it.
+ */
+ return false;
+err:
+ /* Tell the caller that it must free the skb since we have not
+ * consumed it
+ */
+ return true;
+}
+
+static void ath10k_htt_rx_proc_rx_ind_ll(struct ath10k_htt *htt,
+ struct htt_rx_indication *rx)
{
struct ath10k *ar = htt->ar;
struct htt_rx_indication_mpdu_range *mpdu_ranges;
@@ -1884,7 +2001,9 @@ static void ath10k_htt_rx_tx_compl_ind(struct ath10k *ar,
struct htt_resp *resp = (struct htt_resp *)skb->data;
struct htt_tx_done tx_done = {};
int status = MS(resp->data_tx_completion.flags, HTT_DATA_TX_STATUS);
- __le16 msdu_id;
+ __le16 msdu_id, *msdus;
+ bool rssi_enabled = false;
+ u8 msdu_count = 0;
int i;
switch (status) {
@@ -1908,10 +2027,30 @@ static void ath10k_htt_rx_tx_compl_ind(struct ath10k *ar,
ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx completion num_msdus %d\n",
resp->data_tx_completion.num_msdus);
- for (i = 0; i < resp->data_tx_completion.num_msdus; i++) {
- msdu_id = resp->data_tx_completion.msdus[i];
+ msdu_count = resp->data_tx_completion.num_msdus;
+
+ if (resp->data_tx_completion.flags2 & HTT_TX_CMPL_FLAG_DATA_RSSI)
+ rssi_enabled = true;
+
+ for (i = 0; i < msdu_count; i++) {
+ msdus = resp->data_tx_completion.msdus;
+ msdu_id = msdus[i];
tx_done.msdu_id = __le16_to_cpu(msdu_id);
+ if (rssi_enabled) {
+ /* Total no of MSDUs should be even,
+ * if odd MSDUs are sent firmware fills
+ * last msdu id with 0xffff
+ */
+ if (msdu_count & 0x01) {
+ msdu_id = msdus[msdu_count + i + 1];
+ tx_done.ack_rssi = __le16_to_cpu(msdu_id);
+ } else {
+ msdu_id = msdus[msdu_count + i];
+ tx_done.ack_rssi = __le16_to_cpu(msdu_id);
+ }
+ }
+
/* kfifo_put: In practice firmware shouldn't fire off per-CE
* interrupt and main interrupt (MSI/-X range case) for the same
* HTC service so it should be safe to use kfifo_put w/o lock.
@@ -2488,7 +2627,7 @@ void ath10k_htt_htc_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
dev_kfree_skb_any(skb);
}
-static inline bool is_valid_legacy_rate(u8 rate)
+static inline int ath10k_get_legacy_rate_idx(struct ath10k *ar, u8 rate)
{
static const u8 legacy_rates[] = {1, 2, 5, 11, 6, 9, 12,
18, 24, 36, 48, 54};
@@ -2496,10 +2635,114 @@ static inline bool is_valid_legacy_rate(u8 rate)
for (i = 0; i < ARRAY_SIZE(legacy_rates); i++) {
if (rate == legacy_rates[i])
- return true;
+ return i;
}
- return false;
+ ath10k_warn(ar, "Invalid legacy rate %hhd peer stats", rate);
+ return -EINVAL;
+}
+
+static void
+ath10k_accumulate_per_peer_tx_stats(struct ath10k *ar,
+ struct ath10k_sta *arsta,
+ struct ath10k_per_peer_tx_stats *pstats,
+ u8 legacy_rate_idx)
+{
+ struct rate_info *txrate = &arsta->txrate;
+ struct ath10k_htt_tx_stats *tx_stats;
+ int ht_idx, gi, mcs, bw, nss;
+
+ if (!arsta->tx_stats)
+ return;
+
+ tx_stats = arsta->tx_stats;
+ gi = (arsta->txrate.flags & RATE_INFO_FLAGS_SHORT_GI);
+ ht_idx = txrate->mcs + txrate->nss * 8;
+ mcs = txrate->mcs;
+ bw = txrate->bw;
+ nss = txrate->nss;
+
+#define STATS_OP_FMT(name) tx_stats->stats[ATH10K_STATS_TYPE_##name]
+
+ if (txrate->flags == RATE_INFO_FLAGS_VHT_MCS) {
+ STATS_OP_FMT(SUCC).vht[0][mcs] += pstats->succ_bytes;
+ STATS_OP_FMT(SUCC).vht[1][mcs] += pstats->succ_pkts;
+ STATS_OP_FMT(FAIL).vht[0][mcs] += pstats->failed_bytes;
+ STATS_OP_FMT(FAIL).vht[1][mcs] += pstats->failed_pkts;
+ STATS_OP_FMT(RETRY).vht[0][mcs] += pstats->retry_bytes;
+ STATS_OP_FMT(RETRY).vht[1][mcs] += pstats->retry_pkts;
+ } else if (txrate->flags == RATE_INFO_FLAGS_MCS) {
+ STATS_OP_FMT(SUCC).ht[0][ht_idx] += pstats->succ_bytes;
+ STATS_OP_FMT(SUCC).ht[1][ht_idx] += pstats->succ_pkts;
+ STATS_OP_FMT(FAIL).ht[0][ht_idx] += pstats->failed_bytes;
+ STATS_OP_FMT(FAIL).ht[1][ht_idx] += pstats->failed_pkts;
+ STATS_OP_FMT(RETRY).ht[0][ht_idx] += pstats->retry_bytes;
+ STATS_OP_FMT(RETRY).ht[1][ht_idx] += pstats->retry_pkts;
+ } else {
+ mcs = legacy_rate_idx;
+
+ STATS_OP_FMT(SUCC).legacy[0][mcs] += pstats->succ_bytes;
+ STATS_OP_FMT(SUCC).legacy[1][mcs] += pstats->succ_pkts;
+ STATS_OP_FMT(FAIL).legacy[0][mcs] += pstats->failed_bytes;
+ STATS_OP_FMT(FAIL).legacy[1][mcs] += pstats->failed_pkts;
+ STATS_OP_FMT(RETRY).legacy[0][mcs] += pstats->retry_bytes;
+ STATS_OP_FMT(RETRY).legacy[1][mcs] += pstats->retry_pkts;
+ }
+
+ if (ATH10K_HW_AMPDU(pstats->flags)) {
+ tx_stats->ba_fails += ATH10K_HW_BA_FAIL(pstats->flags);
+
+ if (txrate->flags == RATE_INFO_FLAGS_MCS) {
+ STATS_OP_FMT(AMPDU).ht[0][ht_idx] +=
+ pstats->succ_bytes + pstats->retry_bytes;
+ STATS_OP_FMT(AMPDU).ht[1][ht_idx] +=
+ pstats->succ_pkts + pstats->retry_pkts;
+ } else {
+ STATS_OP_FMT(AMPDU).vht[0][mcs] +=
+ pstats->succ_bytes + pstats->retry_bytes;
+ STATS_OP_FMT(AMPDU).vht[1][mcs] +=
+ pstats->succ_pkts + pstats->retry_pkts;
+ }
+ STATS_OP_FMT(AMPDU).bw[0][bw] +=
+ pstats->succ_bytes + pstats->retry_bytes;
+ STATS_OP_FMT(AMPDU).nss[0][nss] +=
+ pstats->succ_bytes + pstats->retry_bytes;
+ STATS_OP_FMT(AMPDU).gi[0][gi] +=
+ pstats->succ_bytes + pstats->retry_bytes;
+ STATS_OP_FMT(AMPDU).bw[1][bw] +=
+ pstats->succ_pkts + pstats->retry_pkts;
+ STATS_OP_FMT(AMPDU).nss[1][nss] +=
+ pstats->succ_pkts + pstats->retry_pkts;
+ STATS_OP_FMT(AMPDU).gi[1][gi] +=
+ pstats->succ_pkts + pstats->retry_pkts;
+ } else {
+ tx_stats->ack_fails +=
+ ATH10K_HW_BA_FAIL(pstats->flags);
+ }
+
+ STATS_OP_FMT(SUCC).bw[0][bw] += pstats->succ_bytes;
+ STATS_OP_FMT(SUCC).nss[0][nss] += pstats->succ_bytes;
+ STATS_OP_FMT(SUCC).gi[0][gi] += pstats->succ_bytes;
+
+ STATS_OP_FMT(SUCC).bw[1][bw] += pstats->succ_pkts;
+ STATS_OP_FMT(SUCC).nss[1][nss] += pstats->succ_pkts;
+ STATS_OP_FMT(SUCC).gi[1][gi] += pstats->succ_pkts;
+
+ STATS_OP_FMT(FAIL).bw[0][bw] += pstats->failed_bytes;
+ STATS_OP_FMT(FAIL).nss[0][nss] += pstats->failed_bytes;
+ STATS_OP_FMT(FAIL).gi[0][gi] += pstats->failed_bytes;
+
+ STATS_OP_FMT(FAIL).bw[1][bw] += pstats->failed_pkts;
+ STATS_OP_FMT(FAIL).nss[1][nss] += pstats->failed_pkts;
+ STATS_OP_FMT(FAIL).gi[1][gi] += pstats->failed_pkts;
+
+ STATS_OP_FMT(RETRY).bw[0][bw] += pstats->retry_bytes;
+ STATS_OP_FMT(RETRY).nss[0][nss] += pstats->retry_bytes;
+ STATS_OP_FMT(RETRY).gi[0][gi] += pstats->retry_bytes;
+
+ STATS_OP_FMT(RETRY).bw[1][bw] += pstats->retry_pkts;
+ STATS_OP_FMT(RETRY).nss[1][nss] += pstats->retry_pkts;
+ STATS_OP_FMT(RETRY).gi[1][gi] += pstats->retry_pkts;
}
static void
@@ -2509,6 +2752,7 @@ ath10k_update_per_peer_tx_stats(struct ath10k *ar,
{
struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
u8 rate = 0, sgi;
+ s8 rate_idx = 0;
struct rate_info txrate;
lockdep_assert_held(&ar->data_lock);
@@ -2536,17 +2780,12 @@ ath10k_update_per_peer_tx_stats(struct ath10k *ar,
if (txrate.flags == WMI_RATE_PREAMBLE_CCK ||
txrate.flags == WMI_RATE_PREAMBLE_OFDM) {
rate = ATH10K_HW_LEGACY_RATE(peer_stats->ratecode);
-
- if (!is_valid_legacy_rate(rate)) {
- ath10k_warn(ar, "Invalid legacy rate %hhd peer stats",
- rate);
- return;
- }
-
/* This is hacky, FW sends CCK rate 5.5Mbps as 6 */
- rate *= 10;
- if (rate == 60 && txrate.flags == WMI_RATE_PREAMBLE_CCK)
- rate = rate - 5;
+ if (rate == 6 && txrate.flags == WMI_RATE_PREAMBLE_CCK)
+ rate = 5;
+ rate_idx = ath10k_get_legacy_rate_idx(ar, rate);
+ if (rate_idx < 0)
+ return;
arsta->txrate.legacy = rate;
} else if (txrate.flags == WMI_RATE_PREAMBLE_HT) {
arsta->txrate.flags = RATE_INFO_FLAGS_MCS;
@@ -2561,6 +2800,10 @@ ath10k_update_per_peer_tx_stats(struct ath10k *ar,
arsta->txrate.nss = txrate.nss;
arsta->txrate.bw = ath10k_bw_to_mac80211_bw(txrate.bw);
+
+ if (ath10k_debug_is_extd_tx_stats_enabled(ar))
+ ath10k_accumulate_per_peer_tx_stats(ar, arsta, peer_stats,
+ rate_idx);
}
static void ath10k_htt_fetch_peer_stats(struct ath10k *ar,
@@ -2702,7 +2945,12 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
break;
}
case HTT_T2H_MSG_TYPE_RX_IND:
- ath10k_htt_rx_proc_rx_ind(htt, &resp->rx_ind);
+ if (ar->dev_type == ATH10K_DEV_TYPE_HL)
+ return ath10k_htt_rx_proc_rx_ind_hl(htt,
+ &resp->rx_ind_hl,
+ skb);
+ else
+ ath10k_htt_rx_proc_rx_ind_ll(htt, &resp->rx_ind);
break;
case HTT_T2H_MSG_TYPE_PEER_MAP: {
struct htt_peer_map_event ev = {
@@ -2986,11 +3234,16 @@ static const struct ath10k_htt_rx_ops htt_rx_ops_64 = {
.htt_reset_paddrs_ring = ath10k_htt_reset_paddrs_ring_64,
};
+static const struct ath10k_htt_rx_ops htt_rx_ops_hl = {
+};
+
void ath10k_htt_set_rx_ops(struct ath10k_htt *htt)
{
struct ath10k *ar = htt->ar;
- if (ar->hw_params.target_64bit)
+ if (ar->dev_type == ATH10K_DEV_TYPE_HL)
+ htt->rx_ops = &htt_rx_ops_hl;
+ else if (ar->hw_params.target_64bit)
htt->rx_ops = &htt_rx_ops_64;
else
htt->rx_ops = &htt_rx_ops_32;
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c
index 7cff0d52338f..ad05ab714c9b 100644
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -495,6 +495,9 @@ int ath10k_htt_tx_start(struct ath10k_htt *htt)
if (htt->tx_mem_allocated)
return 0;
+ if (ar->dev_type == ATH10K_DEV_TYPE_HL)
+ return 0;
+
ret = ath10k_htt_tx_alloc_buf(htt);
if (ret)
goto free_idr_pending_tx;
@@ -934,6 +937,57 @@ static int ath10k_htt_send_rx_ring_cfg_64(struct ath10k_htt *htt)
return 0;
}
+static int ath10k_htt_send_rx_ring_cfg_hl(struct ath10k_htt *htt)
+{
+ struct ath10k *ar = htt->ar;
+ struct sk_buff *skb;
+ struct htt_cmd *cmd;
+ struct htt_rx_ring_setup_ring32 *ring;
+ const int num_rx_ring = 1;
+ u16 flags;
+ int len;
+ int ret;
+
+ /*
+ * the HW expects the buffer to be an integral number of 4-byte
+ * "words"
+ */
+ BUILD_BUG_ON(!IS_ALIGNED(HTT_RX_BUF_SIZE, 4));
+ BUILD_BUG_ON((HTT_RX_BUF_SIZE & HTT_MAX_CACHE_LINE_SIZE_MASK) != 0);
+
+ len = sizeof(cmd->hdr) + sizeof(cmd->rx_setup_32.hdr)
+ + (sizeof(*ring) * num_rx_ring);
+ skb = ath10k_htc_alloc_skb(ar, len);
+ if (!skb)
+ return -ENOMEM;
+
+ skb_put(skb, len);
+
+ cmd = (struct htt_cmd *)skb->data;
+ ring = &cmd->rx_setup_32.rings[0];
+
+ cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_RX_RING_CFG;
+ cmd->rx_setup_32.hdr.num_rings = 1;
+
+ flags = 0;
+ flags |= HTT_RX_RING_FLAGS_MSDU_PAYLOAD;
+ flags |= HTT_RX_RING_FLAGS_UNICAST_RX;
+ flags |= HTT_RX_RING_FLAGS_MULTICAST_RX;
+
+ memset(ring, 0, sizeof(*ring));
+ ring->rx_ring_len = __cpu_to_le16(HTT_RX_RING_SIZE_MIN);
+ ring->rx_ring_bufsize = __cpu_to_le16(HTT_RX_BUF_SIZE);
+ ring->flags = __cpu_to_le16(flags);
+
+ ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb);
+ if (ret) {
+ dev_kfree_skb_any(skb);
+ return ret;
+ }
+
+ return 0;
+}
+
int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt,
u8 max_subfrms_ampdu,
u8 max_subfrms_amsdu)
@@ -1123,7 +1177,8 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
return 0;
err_unmap_msdu:
- dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
+ if (ar->dev_type != ATH10K_DEV_TYPE_HL)
+ dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
err_free_txdesc:
dev_kfree_skb_any(txdesc);
err_free_msdu_id:
@@ -1134,6 +1189,94 @@ err:
return res;
}
+#define HTT_TX_HL_NEEDED_HEADROOM \
+ (unsigned int)(sizeof(struct htt_cmd_hdr) + \
+ sizeof(struct htt_data_tx_desc) + \
+ sizeof(struct ath10k_htc_hdr))
+
+static int ath10k_htt_tx_hl(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txmode,
+ struct sk_buff *msdu)
+{
+ struct ath10k *ar = htt->ar;
+ int res, data_len;
+ struct htt_cmd_hdr *cmd_hdr;
+ struct htt_data_tx_desc *tx_desc;
+ struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu);
+ struct sk_buff *tmp_skb;
+ bool is_eth = (txmode == ATH10K_HW_TXRX_ETHERNET);
+ u8 vdev_id = ath10k_htt_tx_get_vdev_id(ar, msdu);
+ u8 tid = ath10k_htt_tx_get_tid(msdu, is_eth);
+ u8 flags0 = 0;
+ u16 flags1 = 0;
+
+ data_len = msdu->len;
+
+ switch (txmode) {
+ case ATH10K_HW_TXRX_RAW:
+ case ATH10K_HW_TXRX_NATIVE_WIFI:
+ flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT;
+ /* fall through */
+ case ATH10K_HW_TXRX_ETHERNET:
+ flags0 |= SM(txmode, HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
+ break;
+ case ATH10K_HW_TXRX_MGMT:
+ flags0 |= SM(ATH10K_HW_TXRX_MGMT,
+ HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
+ flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT;
+ break;
+ }
+
+ if (skb_cb->flags & ATH10K_SKB_F_NO_HWCRYPT)
+ flags0 |= HTT_DATA_TX_DESC_FLAGS0_NO_ENCRYPT;
+
+ flags1 |= SM((u16)vdev_id, HTT_DATA_TX_DESC_FLAGS1_VDEV_ID);
+ flags1 |= SM((u16)tid, HTT_DATA_TX_DESC_FLAGS1_EXT_TID);
+ if (msdu->ip_summed == CHECKSUM_PARTIAL &&
+ !test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) {
+ flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD;
+ flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD;
+ }
+
+ /* Prepend the HTT header and TX desc struct to the data message
+ * and realloc the skb if it does not have enough headroom.
+ */
+ if (skb_headroom(msdu) < HTT_TX_HL_NEEDED_HEADROOM) {
+ tmp_skb = msdu;
+
+ ath10k_dbg(htt->ar, ATH10K_DBG_HTT,
+ "Not enough headroom in skb. Current headroom: %u, needed: %u. Reallocating...\n",
+ skb_headroom(msdu), HTT_TX_HL_NEEDED_HEADROOM);
+ msdu = skb_realloc_headroom(msdu, HTT_TX_HL_NEEDED_HEADROOM);
+ kfree_skb(tmp_skb);
+ if (!msdu) {
+ ath10k_warn(htt->ar, "htt hl tx: Unable to realloc skb!\n");
+ res = -ENOMEM;
+ goto out;
+ }
+ }
+
+ skb_push(msdu, sizeof(*cmd_hdr));
+ skb_push(msdu, sizeof(*tx_desc));
+ cmd_hdr = (struct htt_cmd_hdr *)msdu->data;
+ tx_desc = (struct htt_data_tx_desc *)(msdu->data + sizeof(*cmd_hdr));
+
+ cmd_hdr->msg_type = HTT_H2T_MSG_TYPE_TX_FRM;
+ tx_desc->flags0 = flags0;
+ tx_desc->flags1 = __cpu_to_le16(flags1);
+ tx_desc->len = __cpu_to_le16(data_len);
+ tx_desc->id = 0;
+ tx_desc->frags_paddr = 0; /* always zero */
+ /* Initialize peer_id to INVALID_PEER because this is NOT
+ * Reinjection path
+ */
+ tx_desc->peerid = __cpu_to_le32(HTT_INVALID_PEERID);
+
+ res = ath10k_htc_send(&htt->ar->htc, htt->eid, msdu);
+
+out:
+ return res;
+}
+
static int ath10k_htt_tx_32(struct ath10k_htt *htt,
enum ath10k_hw_txrx_mode txmode,
struct sk_buff *msdu)
@@ -1561,11 +1704,19 @@ static const struct ath10k_htt_tx_ops htt_tx_ops_64 = {
.htt_free_txbuff = ath10k_htt_tx_free_cont_txbuf_64,
};
+static const struct ath10k_htt_tx_ops htt_tx_ops_hl = {
+ .htt_send_rx_ring_cfg = ath10k_htt_send_rx_ring_cfg_hl,
+ .htt_send_frag_desc_bank_cfg = ath10k_htt_send_frag_desc_bank_cfg_32,
+ .htt_tx = ath10k_htt_tx_hl,
+};
+
void ath10k_htt_set_tx_ops(struct ath10k_htt *htt)
{
struct ath10k *ar = htt->ar;
- if (ar->hw_params.target_64bit)
+ if (ar->dev_type == ATH10K_DEV_TYPE_HL)
+ htt->tx_ops = &htt_tx_ops_hl;
+ else if (ar->hw_params.target_64bit)
htt->tx_ops = &htt_tx_ops_64;
else
htt->tx_ops = &htt_tx_ops_32;
diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c
index 677535b3d207..af8ae8117c62 100644
--- a/drivers/net/wireless/ath/ath10k/hw.c
+++ b/drivers/net/wireless/ath/ath10k/hw.c
@@ -16,6 +16,7 @@
#include <linux/types.h>
#include <linux/bitops.h>
+#include <linux/bitfield.h>
#include "core.h"
#include "hw.h"
#include "hif.h"
@@ -918,6 +919,196 @@ static int ath10k_hw_qca6174_enable_pll_clock(struct ath10k *ar)
return 0;
}
+/* Program CPU_ADDR_MSB to allow different memory
+ * region access.
+ */
+static void ath10k_hw_map_target_mem(struct ath10k *ar, u32 msb)
+{
+ u32 address = SOC_CORE_BASE_ADDRESS + FW_RAM_CONFIG_ADDRESS;
+
+ ath10k_hif_write32(ar, address, msb);
+}
+
+/* 1. Write to memory region of target, such as IRAM adn DRAM.
+ * 2. Target address( 0 ~ 00100000 & 0x00400000~0x00500000)
+ * can be written directly. See ath10k_pci_targ_cpu_to_ce_addr() too.
+ * 3. In order to access the region other than the above,
+ * we need to set the value of register CPU_ADDR_MSB.
+ * 4. Target memory access space is limited to 1M size. If the size is larger
+ * than 1M, need to split it and program CPU_ADDR_MSB accordingly.
+ */
+static int ath10k_hw_diag_segment_msb_download(struct ath10k *ar,
+ const void *buffer,
+ u32 address,
+ u32 length)
+{
+ u32 addr = address & REGION_ACCESS_SIZE_MASK;
+ int ret, remain_size, size;
+ const u8 *buf;
+
+ ath10k_hw_map_target_mem(ar, CPU_ADDR_MSB_REGION_VAL(address));
+
+ if (addr + length > REGION_ACCESS_SIZE_LIMIT) {
+ size = REGION_ACCESS_SIZE_LIMIT - addr;
+ remain_size = length - size;
+
+ ret = ath10k_hif_diag_write(ar, address, buffer, size);
+ if (ret) {
+ ath10k_warn(ar,
+ "failed to download the first %d bytes segment to address:0x%x: %d\n",
+ size, address, ret);
+ goto done;
+ }
+
+ /* Change msb to the next memory region*/
+ ath10k_hw_map_target_mem(ar,
+ CPU_ADDR_MSB_REGION_VAL(address) + 1);
+ buf = buffer + size;
+ ret = ath10k_hif_diag_write(ar,
+ address & ~REGION_ACCESS_SIZE_MASK,
+ buf, remain_size);
+ if (ret) {
+ ath10k_warn(ar,
+ "failed to download the second %d bytes segment to address:0x%x: %d\n",
+ remain_size,
+ address & ~REGION_ACCESS_SIZE_MASK,
+ ret);
+ goto done;
+ }
+ } else {
+ ret = ath10k_hif_diag_write(ar, address, buffer, length);
+ if (ret) {
+ ath10k_warn(ar,
+ "failed to download the only %d bytes segment to address:0x%x: %d\n",
+ length, address, ret);
+ goto done;
+ }
+ }
+
+done:
+ /* Change msb to DRAM */
+ ath10k_hw_map_target_mem(ar,
+ CPU_ADDR_MSB_REGION_VAL(DRAM_BASE_ADDRESS));
+ return ret;
+}
+
+static int ath10k_hw_diag_segment_download(struct ath10k *ar,
+ const void *buffer,
+ u32 address,
+ u32 length)
+{
+ if (address >= DRAM_BASE_ADDRESS + REGION_ACCESS_SIZE_LIMIT)
+ /* Needs to change MSB for memory write */
+ return ath10k_hw_diag_segment_msb_download(ar, buffer,
+ address, length);
+ else
+ return ath10k_hif_diag_write(ar, address, buffer, length);
+}
+
+int ath10k_hw_diag_fast_download(struct ath10k *ar,
+ u32 address,
+ const void *buffer,
+ u32 length)
+{
+ const u8 *buf = buffer;
+ bool sgmt_end = false;
+ u32 base_addr = 0;
+ u32 base_len = 0;
+ u32 left = 0;
+ struct bmi_segmented_file_header *hdr;
+ struct bmi_segmented_metadata *metadata;
+ int ret = 0;
+
+ if (length < sizeof(*hdr))
+ return -EINVAL;
+
+ /* check firmware header. If it has no correct magic number
+ * or it's compressed, returns error.
+ */
+ hdr = (struct bmi_segmented_file_header *)buf;
+ if (__le32_to_cpu(hdr->magic_num) != BMI_SGMTFILE_MAGIC_NUM) {
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
+ "Not a supported firmware, magic_num:0x%x\n",
+ hdr->magic_num);
+ return -EINVAL;
+ }
+
+ if (hdr->file_flags != 0) {
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
+ "Not a supported firmware, file_flags:0x%x\n",
+ hdr->file_flags);
+ return -EINVAL;
+ }
+
+ metadata = (struct bmi_segmented_metadata *)hdr->data;
+ left = length - sizeof(*hdr);
+
+ while (left > 0) {
+ if (left < sizeof(*metadata)) {
+ ath10k_warn(ar, "firmware segment is truncated: %d\n",
+ left);
+ ret = -EINVAL;
+ break;
+ }
+ base_addr = __le32_to_cpu(metadata->addr);
+ base_len = __le32_to_cpu(metadata->length);
+ buf = metadata->data;
+ left -= sizeof(*metadata);
+
+ switch (base_len) {
+ case BMI_SGMTFILE_BEGINADDR:
+ /* base_addr is the start address to run */
+ ret = ath10k_bmi_set_start(ar, base_addr);
+ base_len = 0;
+ break;
+ case BMI_SGMTFILE_DONE:
+ /* no more segment */
+ base_len = 0;
+ sgmt_end = true;
+ ret = 0;
+ break;
+ case BMI_SGMTFILE_BDDATA:
+ case BMI_SGMTFILE_EXEC:
+ ath10k_warn(ar,
+ "firmware has unsupported segment:%d\n",
+ base_len);
+ ret = -EINVAL;
+ break;
+ default:
+ if (base_len > left) {
+ /* sanity check */
+ ath10k_warn(ar,
+ "firmware has invalid segment length, %d > %d\n",
+ base_len, left);
+ ret = -EINVAL;
+ break;
+ }
+
+ ret = ath10k_hw_diag_segment_download(ar,
+ buf,
+ base_addr,
+ base_len);
+
+ if (ret)
+ ath10k_warn(ar,
+ "failed to download firmware via diag interface:%d\n",
+ ret);
+ break;
+ }
+
+ if (ret || sgmt_end)
+ break;
+
+ metadata = (struct bmi_segmented_metadata *)(buf + base_len);
+ left -= base_len;
+ }
+
+ if (ret == 0)
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
+ "boot firmware fast diag download successfully.\n");
+ return ret;
+}
+
const struct ath10k_hw_ops qca988x_ops = {
.set_coverage_class = ath10k_hw_qca988x_set_coverage_class,
};
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index 977f79ebb4fd..1b5da272d18c 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -21,6 +21,14 @@
#include "targaddrs.h"
+enum ath10k_bus {
+ ATH10K_BUS_PCI,
+ ATH10K_BUS_AHB,
+ ATH10K_BUS_SDIO,
+ ATH10K_BUS_USB,
+ ATH10K_BUS_SNOC,
+};
+
#define ATH10K_FW_DIR "ath10k"
#define QCA988X_2_0_DEVICE_ID_UBNT (0x11ac)
@@ -109,6 +117,7 @@ enum qca9377_chip_id_rev {
#define QCA9984_HW_1_0_CHIP_ID_REV 0x0
#define QCA9984_HW_1_0_FW_DIR ATH10K_FW_DIR "/QCA9984/hw1.0"
#define QCA9984_HW_1_0_BOARD_DATA_FILE "board.bin"
+#define QCA9984_HW_1_0_EBOARD_DATA_FILE "eboard.bin"
#define QCA9984_HW_1_0_PATCH_LOAD_ADDR 0x1234
/* QCA9888 2.0 defines */
@@ -221,6 +230,7 @@ enum ath10k_fw_htt_op_version {
enum ath10k_bd_ie_type {
/* contains sub IEs of enum ath10k_bd_ie_board_type */
ATH10K_BD_IE_BOARD = 0,
+ ATH10K_BD_IE_BOARD_EXT = 1,
};
enum ath10k_bd_ie_board_type {
@@ -389,6 +399,11 @@ extern const struct ath10k_hw_ce_regs qcax_ce_regs;
void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey,
u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev);
+int ath10k_hw_diag_fast_download(struct ath10k *ar,
+ u32 address,
+ const void *buffer,
+ u32 length);
+
#define QCA_REV_988X(ar) ((ar)->hw_rev == ATH10K_HW_QCA988X)
#define QCA_REV_9887(ar) ((ar)->hw_rev == ATH10K_HW_QCA9887)
#define QCA_REV_6174(ar) ((ar)->hw_rev == ATH10K_HW_QCA6174)
@@ -501,6 +516,7 @@ struct ath10k_hw_clk_params {
struct ath10k_hw_params {
u32 id;
u16 dev_id;
+ enum ath10k_bus bus;
const char *name;
u32 patch_load_addr;
int uart_pin;
@@ -539,6 +555,8 @@ struct ath10k_hw_params {
const char *dir;
const char *board;
size_t board_size;
+ const char *eboard;
+ size_t ext_board_size;
size_t board_ext_size;
} fw;
@@ -589,6 +607,14 @@ struct ath10k_hw_params {
/* Number of bytes to be the offset for each FFT sample */
int spectral_bin_offset;
+
+ /* targets which require hw filter reset during boot up,
+ * to avoid it sending spurious acks.
+ */
+ bool hw_filter_reset_required;
+
+ /* target supporting fw download via diag ce */
+ bool fw_diag_ce_download;
};
struct htt_rx_desc;
@@ -1124,4 +1150,15 @@ ath10k_rx_desc_get_l3_pad_bytes(struct ath10k_hw_params *hw,
#define RTC_SYNC_STATUS_PLL_CHANGING_MASK 0x00000020
/* qca6174 PLL offset/mask end */
+/* CPU_ADDR_MSB is a register, bit[3:0] is to specify which memory
+ * region is accessed. The memory region size is 1M.
+ * If host wants to access 0xX12345 at target, then CPU_ADDR_MSB[3:0]
+ * is 0xX.
+ * The following MACROs are defined to get the 0xX and the size limit.
+ */
+#define CPU_ADDR_MSB_REGION_MASK GENMASK(23, 20)
+#define CPU_ADDR_MSB_REGION_VAL(X) FIELD_GET(CPU_ADDR_MSB_REGION_MASK, X)
+#define REGION_ACCESS_SIZE_LIMIT 0x100000
+#define REGION_ACCESS_SIZE_MASK (REGION_ACCESS_SIZE_LIMIT - 1)
+
#endif /* _HW_H_ */
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 90f9372dec25..a1c2801ded10 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -18,6 +18,7 @@
#include "mac.h"
+#include <net/cfg80211.h>
#include <net/mac80211.h>
#include <linux/etherdevice.h>
#include <linux/acpi.h>
@@ -29,7 +30,6 @@
#include "htt.h"
#include "txrx.h"
#include "testmode.h"
-#include "wmi.h"
#include "wmi-tlv.h"
#include "wmi-ops.h"
#include "wow.h"
@@ -156,6 +156,22 @@ u8 ath10k_mac_bitrate_to_idx(const struct ieee80211_supported_band *sband,
return 0;
}
+static int ath10k_mac_get_rate_hw_value(int bitrate)
+{
+ int i;
+ u8 hw_value_prefix = 0;
+
+ if (ath10k_mac_bitrate_is_cck(bitrate))
+ hw_value_prefix = WMI_RATE_PREAMBLE_CCK << 6;
+
+ for (i = 0; i < ARRAY_SIZE(ath10k_rates); i++) {
+ if (ath10k_rates[i].bitrate == bitrate)
+ return hw_value_prefix | ath10k_rates[i].hw_value;
+ }
+
+ return -EINVAL;
+}
+
static int ath10k_mac_get_max_vht_mcs_map(u16 mcs_map, int nss)
{
switch ((mcs_map >> (2 * nss)) & 0x3) {
@@ -967,7 +983,7 @@ static inline int ath10k_vdev_setup_sync(struct ath10k *ar)
if (time_left == 0)
return -ETIMEDOUT;
- return 0;
+ return ar->last_wmi_vdev_start_status;
}
static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id)
@@ -4681,6 +4697,14 @@ static int ath10k_start(struct ieee80211_hw *hw)
goto err_core_stop;
}
+ if (test_bit(WMI_SERVICE_SPOOF_MAC_SUPPORT, ar->wmi.svc_map)) {
+ ret = ath10k_wmi_scan_prob_req_oui(ar, ar->mac_addr);
+ if (ret) {
+ ath10k_err(ar, "failed to set prob req oui: %i\n", ret);
+ goto err_core_stop;
+ }
+ }
+
if (test_bit(WMI_SERVICE_ADAPTIVE_OCS, ar->wmi.svc_map)) {
ret = ath10k_wmi_adaptive_qcs(ar, true);
if (ret) {
@@ -5451,9 +5475,10 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
struct cfg80211_chan_def def;
u32 vdev_param, pdev_param, slottime, preamble;
u16 bitrate, hw_value;
- u8 rate;
- int rateidx, ret = 0;
+ u8 rate, basic_rate_idx;
+ int rateidx, ret = 0, hw_rate_code;
enum nl80211_band band;
+ const struct ieee80211_supported_band *sband;
mutex_lock(&ar->conf_mutex);
@@ -5659,6 +5684,30 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
arvif->vdev_id, ret);
}
+ if (changed & BSS_CHANGED_BASIC_RATES) {
+ if (WARN_ON(ath10k_mac_vif_chan(vif, &def))) {
+ mutex_unlock(&ar->conf_mutex);
+ return;
+ }
+
+ sband = ar->hw->wiphy->bands[def.chan->band];
+ basic_rate_idx = ffs(vif->bss_conf.basic_rates) - 1;
+ bitrate = sband->bitrates[basic_rate_idx].bitrate;
+
+ hw_rate_code = ath10k_mac_get_rate_hw_value(bitrate);
+ if (hw_rate_code < 0) {
+ ath10k_warn(ar, "bitrate not supported %d\n", bitrate);
+ mutex_unlock(&ar->conf_mutex);
+ return;
+ }
+
+ vdev_param = ar->wmi.vdev_param->mgmt_rate;
+ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
+ hw_rate_code);
+ if (ret)
+ ath10k_warn(ar, "failed to set mgmt tx rate %d\n", ret);
+ }
+
mutex_unlock(&ar->conf_mutex);
}
@@ -6215,6 +6264,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
new_state == IEEE80211_STA_NONE) {
memset(arsta, 0, sizeof(*arsta));
arsta->arvif = arvif;
+ arsta->peer_ps_state = WMI_PEER_PS_STATE_DISABLED;
INIT_WORK(&arsta->update_wk, ath10k_sta_rc_update_wk);
for (i = 0; i < ARRAY_SIZE(sta->txq); i++)
@@ -6243,6 +6293,13 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
ar->num_stations + 1, ar->max_num_stations,
ar->num_peers + 1, ar->max_num_peers);
+ if (ath10k_debug_is_extd_tx_stats_enabled(ar)) {
+ arsta->tx_stats = kzalloc(sizeof(*arsta->tx_stats),
+ GFP_KERNEL);
+ if (!arsta->tx_stats)
+ goto exit;
+ }
+
num_tdls_stations = ath10k_mac_tdls_vif_stations_count(hw, vif);
num_tdls_vifs = ath10k_mac_tdls_vifs_count(hw);
@@ -6328,6 +6385,9 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
"mac vdev %d peer delete %pM sta %pK (sta gone)\n",
arvif->vdev_id, sta->addr, sta);
+ if (ath10k_debug_is_extd_tx_stats_enabled(ar))
+ kfree(arsta->tx_stats);
+
if (sta->tdls) {
ret = ath10k_mac_tdls_peer_update(ar, arvif->vdev_id,
sta,
@@ -6768,23 +6828,17 @@ static int ath10k_mac_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
return -EOPNOTSUPP;
}
-static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- u32 queues, bool drop)
+void ath10k_mac_wait_tx_complete(struct ath10k *ar)
{
- struct ath10k *ar = hw->priv;
bool skip;
long time_left;
/* mac80211 doesn't care if we really xmit queued frames or not
* we'll collect those frames either way if we stop/delete vdevs
*/
- if (drop)
- return;
-
- mutex_lock(&ar->conf_mutex);
if (ar->state == ATH10K_STATE_WEDGED)
- goto skip;
+ return;
time_left = wait_event_timeout(ar->htt.empty_tx_wq, ({
bool empty;
@@ -6803,8 +6857,29 @@ static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
if (time_left == 0 || skip)
ath10k_warn(ar, "failed to flush transmit queue (skip %i ar-state %i): %ld\n",
skip, ar->state, time_left);
+}
+
+static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ u32 queues, bool drop)
+{
+ struct ath10k *ar = hw->priv;
+ struct ath10k_vif *arvif;
+ u32 bitmap;
+
+ if (drop) {
+ if (vif->type == NL80211_IFTYPE_STATION) {
+ bitmap = ~(1 << WMI_MGMT_TID);
+ list_for_each_entry(arvif, &ar->arvifs, list) {
+ if (arvif->vdev_type == WMI_VDEV_TYPE_STA)
+ ath10k_wmi_peer_flush(ar, arvif->vdev_id,
+ arvif->bssid, bitmap);
+ }
+ }
+ return;
+ }
-skip:
+ mutex_lock(&ar->conf_mutex);
+ ath10k_mac_wait_tx_complete(ar);
mutex_unlock(&ar->conf_mutex);
}
@@ -8148,6 +8223,24 @@ static const struct ieee80211_iface_combination ath10k_10_4_if_comb[] = {
},
};
+static const struct
+ieee80211_iface_combination ath10k_10_4_bcn_int_if_comb[] = {
+ {
+ .limits = ath10k_10_4_if_limits,
+ .n_limits = ARRAY_SIZE(ath10k_10_4_if_limits),
+ .max_interfaces = 16,
+ .num_different_channels = 1,
+ .beacon_int_infra_match = true,
+ .beacon_int_min_gcd = 100,
+#ifdef CONFIG_ATH10K_DFS_CERTIFIED
+ .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
+ BIT(NL80211_CHAN_WIDTH_20) |
+ BIT(NL80211_CHAN_WIDTH_40) |
+ BIT(NL80211_CHAN_WIDTH_80),
+#endif
+ },
+};
+
static void ath10k_get_arvif_iter(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
@@ -8310,6 +8403,10 @@ int ath10k_mac_register(struct ath10k *ar)
void *channels;
int ret;
+ if (!is_valid_ether_addr(ar->mac_addr)) {
+ ath10k_warn(ar, "invalid MAC address; choosing random\n");
+ eth_random_addr(ar->mac_addr);
+ }
SET_IEEE80211_PERM_ADDR(ar->hw, ar->mac_addr);
SET_IEEE80211_DEV(ar->hw, ar->dev);
@@ -8359,6 +8456,7 @@ int ath10k_mac_register(struct ath10k *ar)
ar->hw->wiphy->bands[NL80211_BAND_5GHZ] = band;
}
+ wiphy_read_of_freq_limits(ar->hw->wiphy);
ath10k_mac_setup_ht_vht_cap(ar);
ar->hw->wiphy->interface_modes =
@@ -8414,6 +8512,18 @@ int ath10k_mac_register(struct ath10k *ar)
ar->hw->wiphy->max_scan_ssids = WLAN_SCAN_PARAMS_MAX_SSID;
ar->hw->wiphy->max_scan_ie_len = WLAN_SCAN_PARAMS_MAX_IE_LEN;
+ if (test_bit(WMI_SERVICE_NLO, ar->wmi.svc_map)) {
+ ar->hw->wiphy->max_sched_scan_reqs = 1;
+ ar->hw->wiphy->max_sched_scan_ssids = WMI_PNO_MAX_SUPP_NETWORKS;
+ ar->hw->wiphy->max_match_sets = WMI_PNO_MAX_SUPP_NETWORKS;
+ ar->hw->wiphy->max_sched_scan_ie_len = WMI_PNO_MAX_IE_LENGTH;
+ ar->hw->wiphy->max_sched_scan_plans = WMI_PNO_MAX_SCHED_SCAN_PLANS;
+ ar->hw->wiphy->max_sched_scan_plan_interval =
+ WMI_PNO_MAX_SCHED_SCAN_PLAN_INT;
+ ar->hw->wiphy->max_sched_scan_plan_iterations =
+ WMI_PNO_MAX_SCHED_SCAN_PLAN_ITRNS;
+ }
+
ar->hw->vif_data_size = sizeof(struct ath10k_vif);
ar->hw->sta_data_size = sizeof(struct ath10k_sta);
ar->hw->txq_data_size = sizeof(struct ath10k_txq);
@@ -8463,6 +8573,11 @@ int ath10k_mac_register(struct ath10k *ar)
wiphy_ext_feature_set(ar->hw->wiphy,
NL80211_EXT_FEATURE_SET_SCAN_DWELL);
+ if (test_bit(WMI_SERVICE_TX_DATA_ACK_RSSI, ar->wmi.svc_map) ||
+ test_bit(WMI_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS, ar->wmi.svc_map))
+ wiphy_ext_feature_set(ar->hw->wiphy,
+ NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT);
+
/*
* on LL hardware queues are managed entirely by the FW
* so we only advertise to mac we can do the queues thing
@@ -8506,6 +8621,13 @@ int ath10k_mac_register(struct ath10k *ar)
ar->hw->wiphy->iface_combinations = ath10k_10_4_if_comb;
ar->hw->wiphy->n_iface_combinations =
ARRAY_SIZE(ath10k_10_4_if_comb);
+ if (test_bit(WMI_SERVICE_VDEV_DIFFERENT_BEACON_INTERVAL_SUPPORT,
+ ar->wmi.svc_map)) {
+ ar->hw->wiphy->iface_combinations =
+ ath10k_10_4_bcn_int_if_comb;
+ ar->hw->wiphy->n_iface_combinations =
+ ARRAY_SIZE(ath10k_10_4_bcn_int_if_comb);
+ }
break;
case ATH10K_FW_WMI_OP_VERSION_UNSET:
case ATH10K_FW_WMI_OP_VERSION_MAX:
@@ -8545,12 +8667,6 @@ int ath10k_mac_register(struct ath10k *ar)
}
if (test_bit(WMI_SERVICE_SPOOF_MAC_SUPPORT, ar->wmi.svc_map)) {
- ret = ath10k_wmi_scan_prob_req_oui(ar, ar->mac_addr);
- if (ret) {
- ath10k_err(ar, "failed to set prob req oui: %i\n", ret);
- goto err_dfs_detector_exit;
- }
-
ar->hw->wiphy->features |=
NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
}
diff --git a/drivers/net/wireless/ath/ath10k/mac.h b/drivers/net/wireless/ath/ath10k/mac.h
index 81f8d6c0af35..570493d2d648 100644
--- a/drivers/net/wireless/ath/ath10k/mac.h
+++ b/drivers/net/wireless/ath/ath10k/mac.h
@@ -82,6 +82,7 @@ struct ieee80211_txq *ath10k_mac_txq_lookup(struct ath10k *ar,
u16 peer_id,
u8 tid);
int ath10k_mac_ext_resource_config(struct ath10k *ar, u32 val);
+void ath10k_mac_wait_tx_complete(struct ath10k *ar);
static inline void ath10k_tx_h_seq_no(struct ieee80211_vif *vif,
struct sk_buff *skb)
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index af2cf55c4c1e..01b4edb00e9e 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -192,7 +192,7 @@ static struct ce_attr host_ce_config_wlan[] = {
/* CE7: ce_diag, the Diagnostic Window */
{
- .flags = CE_ATTR_FLAGS,
+ .flags = CE_ATTR_FLAGS | CE_ATTR_POLL,
.src_nentries = 2,
.src_sz_max = DIAG_TRANSFER_LIMIT,
.dest_nentries = 2,
@@ -870,6 +870,21 @@ static u32 ath10k_pci_qca988x_targ_cpu_to_ce_addr(struct ath10k *ar, u32 addr)
return val;
}
+/* Refactor from ath10k_pci_qca988x_targ_cpu_to_ce_addr.
+ * Support to access target space below 1M for qca6174 and qca9377.
+ * If target space is below 1M, the bit[20] of converted CE addr is 0.
+ * Otherwise bit[20] of converted CE addr is 1.
+ */
+static u32 ath10k_pci_qca6174_targ_cpu_to_ce_addr(struct ath10k *ar, u32 addr)
+{
+ u32 val = 0, region = addr & 0xfffff;
+
+ val = (ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS)
+ & 0x7ff) << 21;
+ val |= ((addr >= 0x100000) ? 0x100000 : 0) | region;
+ return val;
+}
+
static u32 ath10k_pci_qca99x0_targ_cpu_to_ce_addr(struct ath10k *ar, u32 addr)
{
u32 val = 0, region = addr & 0xfffff;
@@ -931,6 +946,15 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
goto done;
}
+ /* The address supplied by the caller is in the
+ * Target CPU virtual address space.
+ *
+ * In order to use this address with the diagnostic CE,
+ * convert it from Target CPU virtual address space
+ * to CE address space
+ */
+ address = ath10k_pci_targ_cpu_to_ce_addr(ar, address);
+
remaining_bytes = nbytes;
ce_data = ce_data_base;
while (remaining_bytes) {
@@ -942,16 +966,6 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
goto done;
/* Request CE to send from Target(!) address to Host buffer */
- /*
- * The address supplied by the caller is in the
- * Target CPU virtual address space.
- *
- * In order to use this address with the diagnostic CE,
- * convert it from Target CPU virtual address space
- * to CE address space
- */
- address = ath10k_pci_targ_cpu_to_ce_addr(ar, address);
-
ret = ath10k_ce_send_nolock(ce_diag, NULL, (u32)address, nbytes, 0,
0);
if (ret)
@@ -960,8 +974,10 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
i = 0;
while (ath10k_ce_completed_send_next_nolock(ce_diag,
NULL) != 0) {
- mdelay(1);
- if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
+ udelay(DIAG_ACCESS_CE_WAIT_US);
+ i += DIAG_ACCESS_CE_WAIT_US;
+
+ if (i > DIAG_ACCESS_CE_TIMEOUT_US) {
ret = -EBUSY;
goto done;
}
@@ -972,9 +988,10 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
(void **)&buf,
&completed_nbytes)
!= 0) {
- mdelay(1);
+ udelay(DIAG_ACCESS_CE_WAIT_US);
+ i += DIAG_ACCESS_CE_WAIT_US;
- if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
+ if (i > DIAG_ACCESS_CE_TIMEOUT_US) {
ret = -EBUSY;
goto done;
}
@@ -1054,10 +1071,9 @@ int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
struct ath10k_ce *ce = ath10k_ce_priv(ar);
int ret = 0;
u32 *buf;
- unsigned int completed_nbytes, orig_nbytes, remaining_bytes;
+ unsigned int completed_nbytes, alloc_nbytes, remaining_bytes;
struct ath10k_ce_pipe *ce_diag;
void *data_buf = NULL;
- u32 ce_data; /* Host buffer address in CE space */
dma_addr_t ce_data_base = 0;
int i;
@@ -1071,9 +1087,10 @@ int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
* 1) 4-byte alignment
* 2) Buffer in DMA-able space
*/
- orig_nbytes = nbytes;
+ alloc_nbytes = min_t(unsigned int, nbytes, DIAG_TRANSFER_LIMIT);
+
data_buf = (unsigned char *)dma_alloc_coherent(ar->dev,
- orig_nbytes,
+ alloc_nbytes,
&ce_data_base,
GFP_ATOMIC);
if (!data_buf) {
@@ -1081,9 +1098,6 @@ int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
goto done;
}
- /* Copy caller's data to allocated DMA buf */
- memcpy(data_buf, data, orig_nbytes);
-
/*
* The address supplied by the caller is in the
* Target CPU virtual address space.
@@ -1096,12 +1110,14 @@ int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
*/
address = ath10k_pci_targ_cpu_to_ce_addr(ar, address);
- remaining_bytes = orig_nbytes;
- ce_data = ce_data_base;
+ remaining_bytes = nbytes;
while (remaining_bytes) {
/* FIXME: check cast */
nbytes = min_t(int, remaining_bytes, DIAG_TRANSFER_LIMIT);
+ /* Copy caller's data to allocated DMA buf */
+ memcpy(data_buf, data, nbytes);
+
/* Set up to receive directly into Target(!) address */
ret = ce_diag->ops->ce_rx_post_buf(ce_diag, &address, address);
if (ret != 0)
@@ -1111,7 +1127,7 @@ int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
* Request CE to send caller-supplied data that
* was copied to bounce buffer to Target(!) address.
*/
- ret = ath10k_ce_send_nolock(ce_diag, NULL, (u32)ce_data,
+ ret = ath10k_ce_send_nolock(ce_diag, NULL, ce_data_base,
nbytes, 0, 0);
if (ret != 0)
goto done;
@@ -1119,9 +1135,10 @@ int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
i = 0;
while (ath10k_ce_completed_send_next_nolock(ce_diag,
NULL) != 0) {
- mdelay(1);
+ udelay(DIAG_ACCESS_CE_WAIT_US);
+ i += DIAG_ACCESS_CE_WAIT_US;
- if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
+ if (i > DIAG_ACCESS_CE_TIMEOUT_US) {
ret = -EBUSY;
goto done;
}
@@ -1132,9 +1149,10 @@ int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
(void **)&buf,
&completed_nbytes)
!= 0) {
- mdelay(1);
+ udelay(DIAG_ACCESS_CE_WAIT_US);
+ i += DIAG_ACCESS_CE_WAIT_US;
- if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
+ if (i > DIAG_ACCESS_CE_TIMEOUT_US) {
ret = -EBUSY;
goto done;
}
@@ -1152,12 +1170,12 @@ int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
remaining_bytes -= nbytes;
address += nbytes;
- ce_data += nbytes;
+ data += nbytes;
}
done:
if (data_buf) {
- dma_free_coherent(ar->dev, orig_nbytes, data_buf,
+ dma_free_coherent(ar->dev, alloc_nbytes, data_buf,
ce_data_base);
}
@@ -1839,7 +1857,7 @@ int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar, u16 service_id,
}
}
- if (WARN_ON(!ul_set || !dl_set))
+ if (!ul_set || !dl_set)
return -ENOENT;
return 0;
@@ -2068,9 +2086,9 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
ath10k_pci_irq_disable(ar);
ath10k_pci_irq_sync(ar);
- ath10k_pci_flush(ar);
napi_synchronize(&ar->napi);
napi_disable(&ar->napi);
+ ath10k_pci_flush(ar);
spin_lock_irqsave(&ar_pci->ps_lock, flags);
WARN_ON(ar_pci->ps_wake_refcount > 0);
@@ -3482,7 +3500,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
struct ath10k *ar;
struct ath10k_pci *ar_pci;
enum ath10k_hw_rev hw_rev;
- u32 chip_id;
+ struct ath10k_bus_params bus_params;
bool pci_ps;
int (*pci_soft_reset)(struct ath10k *ar);
int (*pci_hard_reset)(struct ath10k *ar);
@@ -3510,7 +3528,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
pci_ps = true;
pci_soft_reset = ath10k_pci_warm_reset;
pci_hard_reset = ath10k_pci_qca6174_chip_reset;
- targ_cpu_to_ce_addr = ath10k_pci_qca988x_targ_cpu_to_ce_addr;
+ targ_cpu_to_ce_addr = ath10k_pci_qca6174_targ_cpu_to_ce_addr;
break;
case QCA99X0_2_0_DEVICE_ID:
hw_rev = ATH10K_HW_QCA99X0;
@@ -3538,7 +3556,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
pci_ps = true;
pci_soft_reset = NULL;
pci_hard_reset = ath10k_pci_qca6174_chip_reset;
- targ_cpu_to_ce_addr = ath10k_pci_qca988x_targ_cpu_to_ce_addr;
+ targ_cpu_to_ce_addr = ath10k_pci_qca6174_targ_cpu_to_ce_addr;
break;
default:
WARN_ON(1);
@@ -3618,19 +3636,20 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
goto err_free_irq;
}
- chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS);
- if (chip_id == 0xffffffff) {
+ bus_params.dev_type = ATH10K_DEV_TYPE_LL;
+ bus_params.chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS);
+ if (bus_params.chip_id == 0xffffffff) {
ath10k_err(ar, "failed to get chip id\n");
goto err_free_irq;
}
- if (!ath10k_pci_chip_is_supported(pdev->device, chip_id)) {
+ if (!ath10k_pci_chip_is_supported(pdev->device, bus_params.chip_id)) {
ath10k_err(ar, "device %04x with chip_id %08x isn't supported\n",
- pdev->device, chip_id);
+ pdev->device, bus_params.chip_id);
goto err_free_irq;
}
- ret = ath10k_core_register(ar, chip_id);
+ ret = ath10k_core_register(ar, &bus_params);
if (ret) {
ath10k_err(ar, "failed to register driver core: %d\n", ret);
goto err_free_irq;
diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h
index 0ed436657108..e8d86331c539 100644
--- a/drivers/net/wireless/ath/ath10k/pci.h
+++ b/drivers/net/wireless/ath/ath10k/pci.h
@@ -207,7 +207,8 @@ static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar)
#define CDC_WAR_DATA_CE 4
/* Wait up to this many Ms for a Diagnostic Access CE operation to complete */
-#define DIAG_ACCESS_CE_TIMEOUT_MS 10
+#define DIAG_ACCESS_CE_TIMEOUT_US 10000 /* 10 ms */
+#define DIAG_ACCESS_CE_WAIT_US 50
void ath10k_pci_write32(struct ath10k *ar, u32 offset, u32 value);
void ath10k_pci_soc_write32(struct ath10k *ar, u32 addr, u32 val);
diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c
new file mode 100644
index 000000000000..56cb1831dcdf
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/qmi.c
@@ -0,0 +1,1019 @@
+/*
+ * Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/completion.h>
+#include <linux/device.h>
+#include <linux/debugfs.h>
+#include <linux/idr.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/module.h>
+#include <linux/net.h>
+#include <linux/platform_device.h>
+#include <linux/qcom_scm.h>
+#include <linux/string.h>
+#include <net/sock.h>
+
+#include "debug.h"
+#include "snoc.h"
+
+#define ATH10K_QMI_CLIENT_ID 0x4b4e454c
+#define ATH10K_QMI_TIMEOUT 30
+
+static int ath10k_qmi_map_msa_permission(struct ath10k_qmi *qmi,
+ struct ath10k_msa_mem_info *mem_info)
+{
+ struct qcom_scm_vmperm dst_perms[3];
+ struct ath10k *ar = qmi->ar;
+ unsigned int src_perms;
+ u32 perm_count;
+ int ret;
+
+ src_perms = BIT(QCOM_SCM_VMID_HLOS);
+
+ dst_perms[0].vmid = QCOM_SCM_VMID_MSS_MSA;
+ dst_perms[0].perm = QCOM_SCM_PERM_RW;
+ dst_perms[1].vmid = QCOM_SCM_VMID_WLAN;
+ dst_perms[1].perm = QCOM_SCM_PERM_RW;
+
+ if (mem_info->secure) {
+ perm_count = 2;
+ } else {
+ dst_perms[2].vmid = QCOM_SCM_VMID_WLAN_CE;
+ dst_perms[2].perm = QCOM_SCM_PERM_RW;
+ perm_count = 3;
+ }
+
+ ret = qcom_scm_assign_mem(mem_info->addr, mem_info->size,
+ &src_perms, dst_perms, perm_count);
+ if (ret < 0)
+ ath10k_err(ar, "failed to assign msa map permissions: %d\n", ret);
+
+ return ret;
+}
+
+static int ath10k_qmi_unmap_msa_permission(struct ath10k_qmi *qmi,
+ struct ath10k_msa_mem_info *mem_info)
+{
+ struct qcom_scm_vmperm dst_perms;
+ struct ath10k *ar = qmi->ar;
+ unsigned int src_perms;
+ int ret;
+
+ src_perms = BIT(QCOM_SCM_VMID_MSS_MSA) | BIT(QCOM_SCM_VMID_WLAN);
+
+ if (!mem_info->secure)
+ src_perms |= BIT(QCOM_SCM_VMID_WLAN_CE);
+
+ dst_perms.vmid = QCOM_SCM_VMID_HLOS;
+ dst_perms.perm = QCOM_SCM_PERM_RW;
+
+ ret = qcom_scm_assign_mem(mem_info->addr, mem_info->size,
+ &src_perms, &dst_perms, 1);
+ if (ret < 0)
+ ath10k_err(ar, "failed to unmap msa permissions: %d\n", ret);
+
+ return ret;
+}
+
+static int ath10k_qmi_setup_msa_permissions(struct ath10k_qmi *qmi)
+{
+ int ret;
+ int i;
+
+ for (i = 0; i < qmi->nr_mem_region; i++) {
+ ret = ath10k_qmi_map_msa_permission(qmi, &qmi->mem_region[i]);
+ if (ret)
+ goto err_unmap;
+ }
+
+ return 0;
+
+err_unmap:
+ for (i--; i >= 0; i--)
+ ath10k_qmi_unmap_msa_permission(qmi, &qmi->mem_region[i]);
+ return ret;
+}
+
+static void ath10k_qmi_remove_msa_permission(struct ath10k_qmi *qmi)
+{
+ int i;
+
+ for (i = 0; i < qmi->nr_mem_region; i++)
+ ath10k_qmi_unmap_msa_permission(qmi, &qmi->mem_region[i]);
+}
+
+static int ath10k_qmi_msa_mem_info_send_sync_msg(struct ath10k_qmi *qmi)
+{
+ struct wlfw_msa_info_resp_msg_v01 resp = {};
+ struct wlfw_msa_info_req_msg_v01 req = {};
+ struct ath10k *ar = qmi->ar;
+ struct qmi_txn txn;
+ int ret;
+ int i;
+
+ req.msa_addr = qmi->msa_pa;
+ req.size = qmi->msa_mem_size;
+
+ ret = qmi_txn_init(&qmi->qmi_hdl, &txn,
+ wlfw_msa_info_resp_msg_v01_ei, &resp);
+ if (ret < 0)
+ goto out;
+
+ ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn,
+ QMI_WLFW_MSA_INFO_REQ_V01,
+ WLFW_MSA_INFO_REQ_MSG_V01_MAX_MSG_LEN,
+ wlfw_msa_info_req_msg_v01_ei, &req);
+ if (ret < 0) {
+ qmi_txn_cancel(&txn);
+ ath10k_err(ar, "failed to send msa mem info req: %d\n", ret);
+ goto out;
+ }
+
+ ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ);
+ if (ret < 0)
+ goto out;
+
+ if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+ ath10k_err(ar, "msa info req rejected: %d\n", resp.resp.error);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (resp.mem_region_info_len > QMI_WLFW_MAX_MEM_REG_V01) {
+ ath10k_err(ar, "invalid memory region length received: %d\n",
+ resp.mem_region_info_len);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ qmi->nr_mem_region = resp.mem_region_info_len;
+ for (i = 0; i < resp.mem_region_info_len; i++) {
+ qmi->mem_region[i].addr = resp.mem_region_info[i].region_addr;
+ qmi->mem_region[i].size = resp.mem_region_info[i].size;
+ qmi->mem_region[i].secure = resp.mem_region_info[i].secure_flag;
+ ath10k_dbg(ar, ATH10K_DBG_QMI,
+ "qmi msa mem region %d addr 0x%pa size 0x%x flag 0x%08x\n",
+ i, &qmi->mem_region[i].addr,
+ qmi->mem_region[i].size,
+ qmi->mem_region[i].secure);
+ }
+
+ ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi msa mem info request completed\n");
+ return 0;
+
+out:
+ return ret;
+}
+
+static int ath10k_qmi_msa_ready_send_sync_msg(struct ath10k_qmi *qmi)
+{
+ struct wlfw_msa_ready_resp_msg_v01 resp = {};
+ struct wlfw_msa_ready_req_msg_v01 req = {};
+ struct ath10k *ar = qmi->ar;
+ struct qmi_txn txn;
+ int ret;
+
+ ret = qmi_txn_init(&qmi->qmi_hdl, &txn,
+ wlfw_msa_ready_resp_msg_v01_ei, &resp);
+ if (ret < 0)
+ goto out;
+
+ ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn,
+ QMI_WLFW_MSA_READY_REQ_V01,
+ WLFW_MSA_READY_REQ_MSG_V01_MAX_MSG_LEN,
+ wlfw_msa_ready_req_msg_v01_ei, &req);
+ if (ret < 0) {
+ qmi_txn_cancel(&txn);
+ ath10k_err(ar, "failed to send msa mem ready request: %d\n", ret);
+ goto out;
+ }
+
+ ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ);
+ if (ret < 0)
+ goto out;
+
+ if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+ ath10k_err(ar, "msa ready request rejected: %d\n", resp.resp.error);
+ ret = -EINVAL;
+ }
+
+ ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi msa mem ready request completed\n");
+ return 0;
+
+out:
+ return ret;
+}
+
+static int ath10k_qmi_bdf_dnld_send_sync(struct ath10k_qmi *qmi)
+{
+ struct wlfw_bdf_download_resp_msg_v01 resp = {};
+ struct wlfw_bdf_download_req_msg_v01 *req;
+ struct ath10k *ar = qmi->ar;
+ unsigned int remaining;
+ struct qmi_txn txn;
+ const u8 *temp;
+ int ret;
+
+ req = kzalloc(sizeof(*req), GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
+
+ temp = ar->normal_mode_fw.board_data;
+ remaining = ar->normal_mode_fw.board_len;
+
+ while (remaining) {
+ req->valid = 1;
+ req->file_id_valid = 1;
+ req->file_id = 0;
+ req->total_size_valid = 1;
+ req->total_size = ar->normal_mode_fw.board_len;
+ req->seg_id_valid = 1;
+ req->data_valid = 1;
+ req->end_valid = 1;
+
+ if (remaining > QMI_WLFW_MAX_DATA_SIZE_V01) {
+ req->data_len = QMI_WLFW_MAX_DATA_SIZE_V01;
+ } else {
+ req->data_len = remaining;
+ req->end = 1;
+ }
+
+ memcpy(req->data, temp, req->data_len);
+
+ ret = qmi_txn_init(&qmi->qmi_hdl, &txn,
+ wlfw_bdf_download_resp_msg_v01_ei,
+ &resp);
+ if (ret < 0)
+ goto out;
+
+ ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn,
+ QMI_WLFW_BDF_DOWNLOAD_REQ_V01,
+ WLFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN,
+ wlfw_bdf_download_req_msg_v01_ei, req);
+ if (ret < 0) {
+ qmi_txn_cancel(&txn);
+ goto out;
+ }
+
+ ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ);
+
+ if (ret < 0)
+ goto out;
+
+ if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+ ath10k_err(ar, "failed to download board data file: %d\n",
+ resp.resp.error);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ remaining -= req->data_len;
+ temp += req->data_len;
+ req->seg_id++;
+ }
+
+ ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi bdf download request completed\n");
+
+ kfree(req);
+ return 0;
+
+out:
+ kfree(req);
+ return ret;
+}
+
+static int ath10k_qmi_send_cal_report_req(struct ath10k_qmi *qmi)
+{
+ struct wlfw_cal_report_resp_msg_v01 resp = {};
+ struct wlfw_cal_report_req_msg_v01 req = {};
+ struct ath10k *ar = qmi->ar;
+ struct qmi_txn txn;
+ int i, j = 0;
+ int ret;
+
+ ret = qmi_txn_init(&qmi->qmi_hdl, &txn, wlfw_cal_report_resp_msg_v01_ei,
+ &resp);
+ if (ret < 0)
+ goto out;
+
+ for (i = 0; i < QMI_WLFW_MAX_NUM_CAL_V01; i++) {
+ if (qmi->cal_data[i].total_size &&
+ qmi->cal_data[i].data) {
+ req.meta_data[j] = qmi->cal_data[i].cal_id;
+ j++;
+ }
+ }
+ req.meta_data_len = j;
+
+ ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn,
+ QMI_WLFW_CAL_REPORT_REQ_V01,
+ WLFW_CAL_REPORT_REQ_MSG_V01_MAX_MSG_LEN,
+ wlfw_cal_report_req_msg_v01_ei, &req);
+ if (ret < 0) {
+ qmi_txn_cancel(&txn);
+ ath10k_err(ar, "failed to send calibration request: %d\n", ret);
+ goto out;
+ }
+
+ ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ);
+ if (ret < 0)
+ goto out;
+
+ if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+ ath10k_err(ar, "calibration request rejected: %d\n", resp.resp.error);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi cal report request completed\n");
+ return 0;
+
+out:
+ return ret;
+}
+
+static int
+ath10k_qmi_mode_send_sync_msg(struct ath10k *ar, enum wlfw_driver_mode_enum_v01 mode)
+{
+ struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
+ struct ath10k_qmi *qmi = ar_snoc->qmi;
+ struct wlfw_wlan_mode_resp_msg_v01 resp = {};
+ struct wlfw_wlan_mode_req_msg_v01 req = {};
+ struct qmi_txn txn;
+ int ret;
+
+ ret = qmi_txn_init(&qmi->qmi_hdl, &txn,
+ wlfw_wlan_mode_resp_msg_v01_ei,
+ &resp);
+ if (ret < 0)
+ goto out;
+
+ req.mode = mode;
+ req.hw_debug_valid = 1;
+ req.hw_debug = 0;
+
+ ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn,
+ QMI_WLFW_WLAN_MODE_REQ_V01,
+ WLFW_WLAN_MODE_REQ_MSG_V01_MAX_MSG_LEN,
+ wlfw_wlan_mode_req_msg_v01_ei, &req);
+ if (ret < 0) {
+ qmi_txn_cancel(&txn);
+ ath10k_err(ar, "failed to send wlan mode %d request: %d\n", mode, ret);
+ goto out;
+ }
+
+ ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ);
+ if (ret < 0)
+ goto out;
+
+ if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+ ath10k_err(ar, "more request rejected: %d\n", resp.resp.error);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi wlan mode req completed: %d\n", mode);
+ return 0;
+
+out:
+ return ret;
+}
+
+static int
+ath10k_qmi_cfg_send_sync_msg(struct ath10k *ar,
+ struct ath10k_qmi_wlan_enable_cfg *config,
+ const char *version)
+{
+ struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
+ struct ath10k_qmi *qmi = ar_snoc->qmi;
+ struct wlfw_wlan_cfg_resp_msg_v01 resp = {};
+ struct wlfw_wlan_cfg_req_msg_v01 *req;
+ struct qmi_txn txn;
+ int ret;
+ u32 i;
+
+ req = kzalloc(sizeof(*req), GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
+
+ ret = qmi_txn_init(&qmi->qmi_hdl, &txn,
+ wlfw_wlan_cfg_resp_msg_v01_ei,
+ &resp);
+ if (ret < 0)
+ goto out;
+
+ req->host_version_valid = 0;
+
+ req->tgt_cfg_valid = 1;
+ if (config->num_ce_tgt_cfg > QMI_WLFW_MAX_NUM_CE_V01)
+ req->tgt_cfg_len = QMI_WLFW_MAX_NUM_CE_V01;
+ else
+ req->tgt_cfg_len = config->num_ce_tgt_cfg;
+ for (i = 0; i < req->tgt_cfg_len; i++) {
+ req->tgt_cfg[i].pipe_num = config->ce_tgt_cfg[i].pipe_num;
+ req->tgt_cfg[i].pipe_dir = config->ce_tgt_cfg[i].pipe_dir;
+ req->tgt_cfg[i].nentries = config->ce_tgt_cfg[i].nentries;
+ req->tgt_cfg[i].nbytes_max = config->ce_tgt_cfg[i].nbytes_max;
+ req->tgt_cfg[i].flags = config->ce_tgt_cfg[i].flags;
+ }
+
+ req->svc_cfg_valid = 1;
+ if (config->num_ce_svc_pipe_cfg > QMI_WLFW_MAX_NUM_SVC_V01)
+ req->svc_cfg_len = QMI_WLFW_MAX_NUM_SVC_V01;
+ else
+ req->svc_cfg_len = config->num_ce_svc_pipe_cfg;
+ for (i = 0; i < req->svc_cfg_len; i++) {
+ req->svc_cfg[i].service_id = config->ce_svc_cfg[i].service_id;
+ req->svc_cfg[i].pipe_dir = config->ce_svc_cfg[i].pipe_dir;
+ req->svc_cfg[i].pipe_num = config->ce_svc_cfg[i].pipe_num;
+ }
+
+ req->shadow_reg_valid = 1;
+ if (config->num_shadow_reg_cfg >
+ QMI_WLFW_MAX_NUM_SHADOW_REG_V01)
+ req->shadow_reg_len = QMI_WLFW_MAX_NUM_SHADOW_REG_V01;
+ else
+ req->shadow_reg_len = config->num_shadow_reg_cfg;
+
+ memcpy(req->shadow_reg, config->shadow_reg_cfg,
+ sizeof(struct wlfw_shadow_reg_cfg_s_v01) * req->shadow_reg_len);
+
+ ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn,
+ QMI_WLFW_WLAN_CFG_REQ_V01,
+ WLFW_WLAN_CFG_REQ_MSG_V01_MAX_MSG_LEN,
+ wlfw_wlan_cfg_req_msg_v01_ei, req);
+ if (ret < 0) {
+ qmi_txn_cancel(&txn);
+ ath10k_err(ar, "failed to send config request: %d\n", ret);
+ goto out;
+ }
+
+ ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ);
+ if (ret < 0)
+ goto out;
+
+ if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+ ath10k_err(ar, "config request rejected: %d\n", resp.resp.error);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi config request completed\n");
+ kfree(req);
+ return 0;
+
+out:
+ kfree(req);
+ return ret;
+}
+
+int ath10k_qmi_wlan_enable(struct ath10k *ar,
+ struct ath10k_qmi_wlan_enable_cfg *config,
+ enum wlfw_driver_mode_enum_v01 mode,
+ const char *version)
+{
+ int ret;
+
+ ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi mode %d config %p\n",
+ mode, config);
+
+ ret = ath10k_qmi_cfg_send_sync_msg(ar, config, version);
+ if (ret) {
+ ath10k_err(ar, "failed to send qmi config: %d\n", ret);
+ return ret;
+ }
+
+ ret = ath10k_qmi_mode_send_sync_msg(ar, mode);
+ if (ret) {
+ ath10k_err(ar, "failed to send qmi mode: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int ath10k_qmi_wlan_disable(struct ath10k *ar)
+{
+ return ath10k_qmi_mode_send_sync_msg(ar, QMI_WLFW_OFF_V01);
+}
+
+static int ath10k_qmi_cap_send_sync_msg(struct ath10k_qmi *qmi)
+{
+ struct wlfw_cap_resp_msg_v01 *resp;
+ struct wlfw_cap_req_msg_v01 req = {};
+ struct ath10k *ar = qmi->ar;
+ struct qmi_txn txn;
+ int ret;
+
+ resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+ if (!resp)
+ return -ENOMEM;
+
+ ret = qmi_txn_init(&qmi->qmi_hdl, &txn, wlfw_cap_resp_msg_v01_ei, resp);
+ if (ret < 0)
+ goto out;
+
+ ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn,
+ QMI_WLFW_CAP_REQ_V01,
+ WLFW_CAP_REQ_MSG_V01_MAX_MSG_LEN,
+ wlfw_cap_req_msg_v01_ei, &req);
+ if (ret < 0) {
+ qmi_txn_cancel(&txn);
+ ath10k_err(ar, "failed to send capability request: %d\n", ret);
+ goto out;
+ }
+
+ ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ);
+ if (ret < 0)
+ goto out;
+
+ if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
+ ath10k_err(ar, "capablity req rejected: %d\n", resp->resp.error);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (resp->chip_info_valid) {
+ qmi->chip_info.chip_id = resp->chip_info.chip_id;
+ qmi->chip_info.chip_family = resp->chip_info.chip_family;
+ }
+
+ if (resp->board_info_valid)
+ qmi->board_info.board_id = resp->board_info.board_id;
+ else
+ qmi->board_info.board_id = 0xFF;
+
+ if (resp->soc_info_valid)
+ qmi->soc_info.soc_id = resp->soc_info.soc_id;
+
+ if (resp->fw_version_info_valid) {
+ qmi->fw_version = resp->fw_version_info.fw_version;
+ strlcpy(qmi->fw_build_timestamp, resp->fw_version_info.fw_build_timestamp,
+ sizeof(qmi->fw_build_timestamp));
+ }
+
+ if (resp->fw_build_id_valid)
+ strlcpy(qmi->fw_build_id, resp->fw_build_id,
+ MAX_BUILD_ID_LEN + 1);
+
+ ath10k_dbg(ar, ATH10K_DBG_QMI,
+ "qmi chip_id 0x%x chip_family 0x%x board_id 0x%x soc_id 0x%x",
+ qmi->chip_info.chip_id, qmi->chip_info.chip_family,
+ qmi->board_info.board_id, qmi->soc_info.soc_id);
+ ath10k_dbg(ar, ATH10K_DBG_QMI,
+ "qmi fw_version 0x%x fw_build_timestamp %s fw_build_id %s",
+ qmi->fw_version, qmi->fw_build_timestamp, qmi->fw_build_id);
+
+ kfree(resp);
+ return 0;
+
+out:
+ kfree(resp);
+ return ret;
+}
+
+static int ath10k_qmi_host_cap_send_sync(struct ath10k_qmi *qmi)
+{
+ struct wlfw_host_cap_resp_msg_v01 resp = {};
+ struct wlfw_host_cap_req_msg_v01 req = {};
+ struct ath10k *ar = qmi->ar;
+ struct qmi_txn txn;
+ int ret;
+
+ req.daemon_support_valid = 1;
+ req.daemon_support = 0;
+
+ ret = qmi_txn_init(&qmi->qmi_hdl, &txn,
+ wlfw_host_cap_resp_msg_v01_ei, &resp);
+ if (ret < 0)
+ goto out;
+
+ ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn,
+ QMI_WLFW_HOST_CAP_REQ_V01,
+ WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN,
+ wlfw_host_cap_req_msg_v01_ei, &req);
+ if (ret < 0) {
+ qmi_txn_cancel(&txn);
+ ath10k_err(ar, "failed to send host capability request: %d\n", ret);
+ goto out;
+ }
+
+ ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ);
+ if (ret < 0)
+ goto out;
+
+ if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+ ath10k_err(ar, "host capability request rejected: %d\n", resp.resp.error);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi host capablity request completed\n");
+ return 0;
+
+out:
+ return ret;
+}
+
+static int
+ath10k_qmi_ind_register_send_sync_msg(struct ath10k_qmi *qmi)
+{
+ struct wlfw_ind_register_resp_msg_v01 resp = {};
+ struct wlfw_ind_register_req_msg_v01 req = {};
+ struct ath10k *ar = qmi->ar;
+ struct qmi_txn txn;
+ int ret;
+
+ req.client_id_valid = 1;
+ req.client_id = ATH10K_QMI_CLIENT_ID;
+ req.fw_ready_enable_valid = 1;
+ req.fw_ready_enable = 1;
+ req.msa_ready_enable_valid = 1;
+ req.msa_ready_enable = 1;
+
+ ret = qmi_txn_init(&qmi->qmi_hdl, &txn,
+ wlfw_ind_register_resp_msg_v01_ei, &resp);
+ if (ret < 0)
+ goto out;
+
+ ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn,
+ QMI_WLFW_IND_REGISTER_REQ_V01,
+ WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN,
+ wlfw_ind_register_req_msg_v01_ei, &req);
+ if (ret < 0) {
+ qmi_txn_cancel(&txn);
+ ath10k_err(ar, "failed to send indication registed request: %d\n", ret);
+ goto out;
+ }
+
+ ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ);
+ if (ret < 0)
+ goto out;
+
+ if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+ ath10k_err(ar, "indication request rejected: %d\n", resp.resp.error);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (resp.fw_status_valid) {
+ if (resp.fw_status & QMI_WLFW_FW_READY_V01)
+ qmi->fw_ready = true;
+ }
+ ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi indication register request completed\n");
+ return 0;
+
+out:
+ return ret;
+}
+
+static void ath10k_qmi_event_server_arrive(struct ath10k_qmi *qmi)
+{
+ struct ath10k *ar = qmi->ar;
+ int ret;
+
+ ret = ath10k_qmi_ind_register_send_sync_msg(qmi);
+ if (ret)
+ return;
+
+ if (qmi->fw_ready) {
+ ath10k_snoc_fw_indication(ar, ATH10K_QMI_EVENT_FW_READY_IND);
+ return;
+ }
+
+ ret = ath10k_qmi_host_cap_send_sync(qmi);
+ if (ret)
+ return;
+
+ ret = ath10k_qmi_msa_mem_info_send_sync_msg(qmi);
+ if (ret)
+ return;
+
+ ret = ath10k_qmi_setup_msa_permissions(qmi);
+ if (ret)
+ return;
+
+ ret = ath10k_qmi_msa_ready_send_sync_msg(qmi);
+ if (ret)
+ goto err_setup_msa;
+
+ ret = ath10k_qmi_cap_send_sync_msg(qmi);
+ if (ret)
+ goto err_setup_msa;
+
+ return;
+
+err_setup_msa:
+ ath10k_qmi_remove_msa_permission(qmi);
+}
+
+static int ath10k_qmi_fetch_board_file(struct ath10k_qmi *qmi)
+{
+ struct ath10k *ar = qmi->ar;
+
+ ar->hif.bus = ATH10K_BUS_SNOC;
+ ar->id.qmi_ids_valid = true;
+ ar->id.qmi_board_id = qmi->board_info.board_id;
+ ar->hw_params.fw.dir = WCN3990_HW_1_0_FW_DIR;
+
+ return ath10k_core_fetch_board_file(qmi->ar, ATH10K_BD_IE_BOARD);
+}
+
+static int
+ath10k_qmi_driver_event_post(struct ath10k_qmi *qmi,
+ enum ath10k_qmi_driver_event_type type,
+ void *data)
+{
+ struct ath10k_qmi_driver_event *event;
+
+ event = kzalloc(sizeof(*event), GFP_ATOMIC);
+ if (!event)
+ return -ENOMEM;
+
+ event->type = type;
+ event->data = data;
+
+ spin_lock(&qmi->event_lock);
+ list_add_tail(&event->list, &qmi->event_list);
+ spin_unlock(&qmi->event_lock);
+
+ queue_work(qmi->event_wq, &qmi->event_work);
+
+ return 0;
+}
+
+static void ath10k_qmi_event_server_exit(struct ath10k_qmi *qmi)
+{
+ struct ath10k *ar = qmi->ar;
+
+ ath10k_qmi_remove_msa_permission(qmi);
+ ath10k_core_free_board_files(ar);
+ ath10k_snoc_fw_indication(ar, ATH10K_QMI_EVENT_FW_DOWN_IND);
+ ath10k_dbg(ar, ATH10K_DBG_QMI, "wifi fw qmi service disconnected\n");
+}
+
+static void ath10k_qmi_event_msa_ready(struct ath10k_qmi *qmi)
+{
+ int ret;
+
+ ret = ath10k_qmi_fetch_board_file(qmi);
+ if (ret)
+ goto out;
+
+ ret = ath10k_qmi_bdf_dnld_send_sync(qmi);
+ if (ret)
+ goto out;
+
+ ret = ath10k_qmi_send_cal_report_req(qmi);
+
+out:
+ return;
+}
+
+static int ath10k_qmi_event_fw_ready_ind(struct ath10k_qmi *qmi)
+{
+ struct ath10k *ar = qmi->ar;
+
+ ath10k_dbg(ar, ATH10K_DBG_QMI, "wifi fw ready event received\n");
+ ath10k_snoc_fw_indication(ar, ATH10K_QMI_EVENT_FW_READY_IND);
+
+ return 0;
+}
+
+static void ath10k_qmi_fw_ready_ind(struct qmi_handle *qmi_hdl,
+ struct sockaddr_qrtr *sq,
+ struct qmi_txn *txn, const void *data)
+{
+ struct ath10k_qmi *qmi = container_of(qmi_hdl, struct ath10k_qmi, qmi_hdl);
+
+ ath10k_qmi_driver_event_post(qmi, ATH10K_QMI_EVENT_FW_READY_IND, NULL);
+}
+
+static void ath10k_qmi_msa_ready_ind(struct qmi_handle *qmi_hdl,
+ struct sockaddr_qrtr *sq,
+ struct qmi_txn *txn, const void *data)
+{
+ struct ath10k_qmi *qmi = container_of(qmi_hdl, struct ath10k_qmi, qmi_hdl);
+
+ ath10k_qmi_driver_event_post(qmi, ATH10K_QMI_EVENT_MSA_READY_IND, NULL);
+}
+
+static struct qmi_msg_handler qmi_msg_handler[] = {
+ {
+ .type = QMI_INDICATION,
+ .msg_id = QMI_WLFW_FW_READY_IND_V01,
+ .ei = wlfw_fw_ready_ind_msg_v01_ei,
+ .decoded_size = sizeof(struct wlfw_fw_ready_ind_msg_v01),
+ .fn = ath10k_qmi_fw_ready_ind,
+ },
+ {
+ .type = QMI_INDICATION,
+ .msg_id = QMI_WLFW_MSA_READY_IND_V01,
+ .ei = wlfw_msa_ready_ind_msg_v01_ei,
+ .decoded_size = sizeof(struct wlfw_msa_ready_ind_msg_v01),
+ .fn = ath10k_qmi_msa_ready_ind,
+ },
+ {}
+};
+
+static int ath10k_qmi_new_server(struct qmi_handle *qmi_hdl,
+ struct qmi_service *service)
+{
+ struct ath10k_qmi *qmi = container_of(qmi_hdl, struct ath10k_qmi, qmi_hdl);
+ struct sockaddr_qrtr *sq = &qmi->sq;
+ struct ath10k *ar = qmi->ar;
+ int ret;
+
+ sq->sq_family = AF_QIPCRTR;
+ sq->sq_node = service->node;
+ sq->sq_port = service->port;
+
+ ath10k_dbg(ar, ATH10K_DBG_QMI, "wifi fw qmi service found\n");
+
+ ret = kernel_connect(qmi_hdl->sock, (struct sockaddr *)&qmi->sq,
+ sizeof(qmi->sq), 0);
+ if (ret) {
+ ath10k_err(ar, "failed to connect to a remote QMI service port\n");
+ return ret;
+ }
+
+ ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi wifi fw qmi service connected\n");
+ ath10k_qmi_driver_event_post(qmi, ATH10K_QMI_EVENT_SERVER_ARRIVE, NULL);
+
+ return ret;
+}
+
+static void ath10k_qmi_del_server(struct qmi_handle *qmi_hdl,
+ struct qmi_service *service)
+{
+ struct ath10k_qmi *qmi =
+ container_of(qmi_hdl, struct ath10k_qmi, qmi_hdl);
+
+ qmi->fw_ready = false;
+ ath10k_qmi_driver_event_post(qmi, ATH10K_QMI_EVENT_SERVER_EXIT, NULL);
+}
+
+static struct qmi_ops ath10k_qmi_ops = {
+ .new_server = ath10k_qmi_new_server,
+ .del_server = ath10k_qmi_del_server,
+};
+
+static void ath10k_qmi_driver_event_work(struct work_struct *work)
+{
+ struct ath10k_qmi *qmi = container_of(work, struct ath10k_qmi,
+ event_work);
+ struct ath10k_qmi_driver_event *event;
+ struct ath10k *ar = qmi->ar;
+
+ spin_lock(&qmi->event_lock);
+ while (!list_empty(&qmi->event_list)) {
+ event = list_first_entry(&qmi->event_list,
+ struct ath10k_qmi_driver_event, list);
+ list_del(&event->list);
+ spin_unlock(&qmi->event_lock);
+
+ switch (event->type) {
+ case ATH10K_QMI_EVENT_SERVER_ARRIVE:
+ ath10k_qmi_event_server_arrive(qmi);
+ break;
+ case ATH10K_QMI_EVENT_SERVER_EXIT:
+ ath10k_qmi_event_server_exit(qmi);
+ break;
+ case ATH10K_QMI_EVENT_FW_READY_IND:
+ ath10k_qmi_event_fw_ready_ind(qmi);
+ break;
+ case ATH10K_QMI_EVENT_MSA_READY_IND:
+ ath10k_qmi_event_msa_ready(qmi);
+ break;
+ default:
+ ath10k_warn(ar, "invalid event type: %d", event->type);
+ break;
+ }
+ kfree(event);
+ spin_lock(&qmi->event_lock);
+ }
+ spin_unlock(&qmi->event_lock);
+}
+
+static int ath10k_qmi_setup_msa_resources(struct ath10k_qmi *qmi, u32 msa_size)
+{
+ struct ath10k *ar = qmi->ar;
+ struct device *dev = ar->dev;
+ struct device_node *node;
+ struct resource r;
+ int ret;
+
+ node = of_parse_phandle(dev->of_node, "memory-region", 0);
+ if (node) {
+ ret = of_address_to_resource(node, 0, &r);
+ if (ret) {
+ dev_err(dev, "failed to resolve msa fixed region\n");
+ return ret;
+ }
+ of_node_put(node);
+
+ qmi->msa_pa = r.start;
+ qmi->msa_mem_size = resource_size(&r);
+ qmi->msa_va = devm_memremap(dev, qmi->msa_pa, qmi->msa_mem_size,
+ MEMREMAP_WT);
+ if (!qmi->msa_pa) {
+ dev_err(dev, "failed to map memory region: %pa\n", &r.start);
+ return -EBUSY;
+ }
+ } else {
+ qmi->msa_va = dmam_alloc_coherent(dev, msa_size,
+ &qmi->msa_pa, GFP_KERNEL);
+ if (!qmi->msa_va) {
+ ath10k_err(ar, "failed to allocate dma memory for msa region\n");
+ return -ENOMEM;
+ }
+ qmi->msa_mem_size = msa_size;
+ }
+
+ ath10k_dbg(ar, ATH10K_DBG_QMI, "msa pa: %pad , msa va: 0x%p\n",
+ &qmi->msa_pa,
+ qmi->msa_va);
+
+ return 0;
+}
+
+int ath10k_qmi_init(struct ath10k *ar, u32 msa_size)
+{
+ struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
+ struct ath10k_qmi *qmi;
+ int ret;
+
+ qmi = kzalloc(sizeof(*qmi), GFP_KERNEL);
+ if (!qmi)
+ return -ENOMEM;
+
+ qmi->ar = ar;
+ ar_snoc->qmi = qmi;
+
+ ret = ath10k_qmi_setup_msa_resources(qmi, msa_size);
+ if (ret)
+ goto err;
+
+ ret = qmi_handle_init(&qmi->qmi_hdl,
+ WLFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN,
+ &ath10k_qmi_ops, qmi_msg_handler);
+ if (ret)
+ goto err;
+
+ qmi->event_wq = alloc_workqueue("ath10k_qmi_driver_event",
+ WQ_UNBOUND, 1);
+ if (!qmi->event_wq) {
+ ath10k_err(ar, "failed to allocate workqueue\n");
+ ret = -EFAULT;
+ goto err_release_qmi_handle;
+ }
+
+ INIT_LIST_HEAD(&qmi->event_list);
+ spin_lock_init(&qmi->event_lock);
+ INIT_WORK(&qmi->event_work, ath10k_qmi_driver_event_work);
+
+ ret = qmi_add_lookup(&qmi->qmi_hdl, WLFW_SERVICE_ID_V01,
+ WLFW_SERVICE_VERS_V01, 0);
+ if (ret)
+ goto err_qmi_lookup;
+
+ return 0;
+
+err_qmi_lookup:
+ destroy_workqueue(qmi->event_wq);
+
+err_release_qmi_handle:
+ qmi_handle_release(&qmi->qmi_hdl);
+
+err:
+ kfree(qmi);
+ return ret;
+}
+
+int ath10k_qmi_deinit(struct ath10k *ar)
+{
+ struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
+ struct ath10k_qmi *qmi = ar_snoc->qmi;
+
+ qmi_handle_release(&qmi->qmi_hdl);
+ cancel_work_sync(&qmi->event_work);
+ destroy_workqueue(qmi->event_wq);
+ ar_snoc->qmi = NULL;
+
+ return 0;
+}
diff --git a/drivers/net/wireless/ath/ath10k/qmi.h b/drivers/net/wireless/ath/ath10k/qmi.h
new file mode 100644
index 000000000000..1efe1d22fc2f
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/qmi.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef _ATH10K_QMI_H_
+#define _ATH10K_QMI_H_
+
+#include <linux/soc/qcom/qmi.h>
+#include <linux/qrtr.h>
+#include "qmi_wlfw_v01.h"
+
+#define MAX_NUM_MEMORY_REGIONS 2
+#define MAX_TIMESTAMP_LEN 32
+#define MAX_BUILD_ID_LEN 128
+#define MAX_NUM_CAL_V01 5
+
+enum ath10k_qmi_driver_event_type {
+ ATH10K_QMI_EVENT_SERVER_ARRIVE,
+ ATH10K_QMI_EVENT_SERVER_EXIT,
+ ATH10K_QMI_EVENT_FW_READY_IND,
+ ATH10K_QMI_EVENT_FW_DOWN_IND,
+ ATH10K_QMI_EVENT_MSA_READY_IND,
+ ATH10K_QMI_EVENT_MAX,
+};
+
+struct ath10k_msa_mem_info {
+ phys_addr_t addr;
+ u32 size;
+ bool secure;
+};
+
+struct ath10k_qmi_chip_info {
+ u32 chip_id;
+ u32 chip_family;
+};
+
+struct ath10k_qmi_board_info {
+ u32 board_id;
+};
+
+struct ath10k_qmi_soc_info {
+ u32 soc_id;
+};
+
+struct ath10k_qmi_cal_data {
+ u32 cal_id;
+ u32 total_size;
+ u8 *data;
+};
+
+struct ath10k_tgt_pipe_cfg {
+ __le32 pipe_num;
+ __le32 pipe_dir;
+ __le32 nentries;
+ __le32 nbytes_max;
+ __le32 flags;
+ __le32 reserved;
+};
+
+struct ath10k_svc_pipe_cfg {
+ __le32 service_id;
+ __le32 pipe_dir;
+ __le32 pipe_num;
+};
+
+struct ath10k_shadow_reg_cfg {
+ __le16 ce_id;
+ __le16 reg_offset;
+};
+
+struct ath10k_qmi_wlan_enable_cfg {
+ u32 num_ce_tgt_cfg;
+ struct ath10k_tgt_pipe_cfg *ce_tgt_cfg;
+ u32 num_ce_svc_pipe_cfg;
+ struct ath10k_svc_pipe_cfg *ce_svc_cfg;
+ u32 num_shadow_reg_cfg;
+ struct ath10k_shadow_reg_cfg *shadow_reg_cfg;
+};
+
+struct ath10k_qmi_driver_event {
+ struct list_head list;
+ enum ath10k_qmi_driver_event_type type;
+ void *data;
+};
+
+struct ath10k_qmi {
+ struct ath10k *ar;
+ struct qmi_handle qmi_hdl;
+ struct sockaddr_qrtr sq;
+ struct work_struct event_work;
+ struct workqueue_struct *event_wq;
+ struct list_head event_list;
+ spinlock_t event_lock; /* spinlock for qmi event list */
+ u32 nr_mem_region;
+ struct ath10k_msa_mem_info mem_region[MAX_NUM_MEMORY_REGIONS];
+ dma_addr_t msa_pa;
+ u32 msa_mem_size;
+ void *msa_va;
+ struct ath10k_qmi_chip_info chip_info;
+ struct ath10k_qmi_board_info board_info;
+ struct ath10k_qmi_soc_info soc_info;
+ char fw_build_id[MAX_BUILD_ID_LEN + 1];
+ u32 fw_version;
+ bool fw_ready;
+ char fw_build_timestamp[MAX_TIMESTAMP_LEN + 1];
+ struct ath10k_qmi_cal_data cal_data[MAX_NUM_CAL_V01];
+};
+
+int ath10k_qmi_wlan_enable(struct ath10k *ar,
+ struct ath10k_qmi_wlan_enable_cfg *config,
+ enum wlfw_driver_mode_enum_v01 mode,
+ const char *version);
+int ath10k_qmi_wlan_disable(struct ath10k *ar);
+int ath10k_qmi_register_service_notifier(struct notifier_block *nb);
+int ath10k_qmi_init(struct ath10k *ar, u32 msa_size);
+int ath10k_qmi_deinit(struct ath10k *ar);
+
+#endif /* ATH10K_QMI_H */
diff --git a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c
new file mode 100644
index 000000000000..ba79c2e4aed6
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c
@@ -0,0 +1,2072 @@
+/*
+ * Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/soc/qcom/qmi.h>
+#include <linux/types.h>
+#include "qmi_wlfw_v01.h"
+
+static struct qmi_elem_info wlfw_ce_tgt_pipe_cfg_s_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01,
+ pipe_num),
+ },
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = 1,
+ .elem_size = sizeof(enum wlfw_pipedir_enum_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01,
+ pipe_dir),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01,
+ nentries),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01,
+ nbytes_max),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01,
+ flags),
+ },
+ {}
+};
+
+static struct qmi_elem_info wlfw_ce_svc_pipe_cfg_s_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_ce_svc_pipe_cfg_s_v01,
+ service_id),
+ },
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = 1,
+ .elem_size = sizeof(enum wlfw_pipedir_enum_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_ce_svc_pipe_cfg_s_v01,
+ pipe_dir),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_ce_svc_pipe_cfg_s_v01,
+ pipe_num),
+ },
+ {}
+};
+
+static struct qmi_elem_info wlfw_shadow_reg_cfg_s_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_2_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u16),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_shadow_reg_cfg_s_v01,
+ id),
+ },
+ {
+ .data_type = QMI_UNSIGNED_2_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u16),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_shadow_reg_cfg_s_v01,
+ offset),
+ },
+ {}
+};
+
+static struct qmi_elem_info wlfw_shadow_reg_v2_cfg_s_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_shadow_reg_v2_cfg_s_v01,
+ addr),
+ },
+ {}
+};
+
+static struct qmi_elem_info wlfw_memory_region_info_s_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_8_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u64),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_memory_region_info_s_v01,
+ region_addr),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_memory_region_info_s_v01,
+ size),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_memory_region_info_s_v01,
+ secure_flag),
+ },
+ {}
+};
+
+static struct qmi_elem_info wlfw_mem_cfg_s_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_8_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u64),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_mem_cfg_s_v01,
+ offset),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_mem_cfg_s_v01,
+ size),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_mem_cfg_s_v01,
+ secure_flag),
+ },
+ {}
+};
+
+static struct qmi_elem_info wlfw_mem_seg_s_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_mem_seg_s_v01,
+ size),
+ },
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = 1,
+ .elem_size = sizeof(enum wlfw_mem_type_enum_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_mem_seg_s_v01,
+ type),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_mem_seg_s_v01,
+ mem_cfg_len),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = QMI_WLFW_MAX_NUM_MEM_CFG_V01,
+ .elem_size = sizeof(struct wlfw_mem_cfg_s_v01),
+ .array_type = VAR_LEN_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_mem_seg_s_v01,
+ mem_cfg),
+ .ei_array = wlfw_mem_cfg_s_v01_ei,
+ },
+ {}
+};
+
+static struct qmi_elem_info wlfw_mem_seg_resp_s_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_8_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u64),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_mem_seg_resp_s_v01,
+ addr),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_mem_seg_resp_s_v01,
+ size),
+ },
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = 1,
+ .elem_size = sizeof(enum wlfw_mem_type_enum_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_mem_seg_resp_s_v01,
+ type),
+ },
+ {}
+};
+
+static struct qmi_elem_info wlfw_rf_chip_info_s_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_rf_chip_info_s_v01,
+ chip_id),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_rf_chip_info_s_v01,
+ chip_family),
+ },
+ {}
+};
+
+static struct qmi_elem_info wlfw_rf_board_info_s_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_rf_board_info_s_v01,
+ board_id),
+ },
+ {}
+};
+
+static struct qmi_elem_info wlfw_soc_info_s_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_soc_info_s_v01,
+ soc_id),
+ },
+ {}
+};
+
+static struct qmi_elem_info wlfw_fw_version_info_s_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_fw_version_info_s_v01,
+ fw_version),
+ },
+ {
+ .data_type = QMI_STRING,
+ .elem_len = QMI_WLFW_MAX_TIMESTAMP_LEN_V01 + 1,
+ .elem_size = sizeof(char),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_fw_version_info_s_v01,
+ fw_build_timestamp),
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_ind_register_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ fw_ready_enable_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ fw_ready_enable),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ initiate_cal_download_enable_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ initiate_cal_download_enable),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ initiate_cal_update_enable_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ initiate_cal_update_enable),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ msa_ready_enable_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ msa_ready_enable),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ pin_connect_result_enable_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ pin_connect_result_enable),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x15,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ client_id_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x15,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ client_id),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x16,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ request_mem_enable_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x16,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ request_mem_enable),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x17,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ mem_ready_enable_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x17,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ mem_ready_enable),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x18,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ fw_init_done_enable_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x18,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ fw_init_done_enable),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x19,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ rejuvenate_enable_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x19,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ rejuvenate_enable),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x1A,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ xo_cal_enable_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x1A,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ xo_cal_enable),
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_ind_register_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_ind_register_resp_msg_v01,
+ resp),
+ .ei_array = qmi_response_type_v01_ei,
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_ind_register_resp_msg_v01,
+ fw_status_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_8_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u64),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_ind_register_resp_msg_v01,
+ fw_status),
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_fw_ready_ind_msg_v01_ei[] = {
+ {}
+};
+
+struct qmi_elem_info wlfw_msa_ready_ind_msg_v01_ei[] = {
+ {}
+};
+
+struct qmi_elem_info wlfw_pin_connect_result_ind_msg_v01_ei[] = {
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_pin_connect_result_ind_msg_v01,
+ pwr_pin_result_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_pin_connect_result_ind_msg_v01,
+ pwr_pin_result),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_pin_connect_result_ind_msg_v01,
+ phy_io_pin_result_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_pin_connect_result_ind_msg_v01,
+ phy_io_pin_result),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_pin_connect_result_ind_msg_v01,
+ rf_pin_result_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_pin_connect_result_ind_msg_v01,
+ rf_pin_result),
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_wlan_mode_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = 1,
+ .elem_size = sizeof(enum wlfw_driver_mode_enum_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_wlan_mode_req_msg_v01,
+ mode),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_wlan_mode_req_msg_v01,
+ hw_debug_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_wlan_mode_req_msg_v01,
+ hw_debug),
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_wlan_mode_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_wlan_mode_resp_msg_v01,
+ resp),
+ .ei_array = qmi_response_type_v01_ei,
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_wlan_cfg_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ host_version_valid),
+ },
+ {
+ .data_type = QMI_STRING,
+ .elem_len = QMI_WLFW_MAX_STR_LEN_V01 + 1,
+ .elem_size = sizeof(char),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ host_version),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ tgt_cfg_valid),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ tgt_cfg_len),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = QMI_WLFW_MAX_NUM_CE_V01,
+ .elem_size = sizeof(struct wlfw_ce_tgt_pipe_cfg_s_v01),
+ .array_type = VAR_LEN_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ tgt_cfg),
+ .ei_array = wlfw_ce_tgt_pipe_cfg_s_v01_ei,
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ svc_cfg_valid),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ svc_cfg_len),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = QMI_WLFW_MAX_NUM_SVC_V01,
+ .elem_size = sizeof(struct wlfw_ce_svc_pipe_cfg_s_v01),
+ .array_type = VAR_LEN_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ svc_cfg),
+ .ei_array = wlfw_ce_svc_pipe_cfg_s_v01_ei,
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ shadow_reg_valid),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ shadow_reg_len),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = QMI_WLFW_MAX_NUM_SHADOW_REG_V01,
+ .elem_size = sizeof(struct wlfw_shadow_reg_cfg_s_v01),
+ .array_type = VAR_LEN_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ shadow_reg),
+ .ei_array = wlfw_shadow_reg_cfg_s_v01_ei,
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ shadow_reg_v2_valid),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ shadow_reg_v2_len),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = QMI_WLFW_MAX_SHADOW_REG_V2,
+ .elem_size = sizeof(struct wlfw_shadow_reg_v2_cfg_s_v01),
+ .array_type = VAR_LEN_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ shadow_reg_v2),
+ .ei_array = wlfw_shadow_reg_v2_cfg_s_v01_ei,
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_wlan_cfg_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_wlan_cfg_resp_msg_v01,
+ resp),
+ .ei_array = qmi_response_type_v01_ei,
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_cap_req_msg_v01_ei[] = {
+ {}
+};
+
+struct qmi_elem_info wlfw_cap_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_cap_resp_msg_v01,
+ resp),
+ .ei_array = qmi_response_type_v01_ei,
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_cap_resp_msg_v01,
+ chip_info_valid),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct wlfw_rf_chip_info_s_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_cap_resp_msg_v01,
+ chip_info),
+ .ei_array = wlfw_rf_chip_info_s_v01_ei,
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_cap_resp_msg_v01,
+ board_info_valid),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct wlfw_rf_board_info_s_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_cap_resp_msg_v01,
+ board_info),
+ .ei_array = wlfw_rf_board_info_s_v01_ei,
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_cap_resp_msg_v01,
+ soc_info_valid),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct wlfw_soc_info_s_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_cap_resp_msg_v01,
+ soc_info),
+ .ei_array = wlfw_soc_info_s_v01_ei,
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_cap_resp_msg_v01,
+ fw_version_info_valid),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct wlfw_fw_version_info_s_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_cap_resp_msg_v01,
+ fw_version_info),
+ .ei_array = wlfw_fw_version_info_s_v01_ei,
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_cap_resp_msg_v01,
+ fw_build_id_valid),
+ },
+ {
+ .data_type = QMI_STRING,
+ .elem_len = QMI_WLFW_MAX_BUILD_ID_LEN_V01 + 1,
+ .elem_size = sizeof(char),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_cap_resp_msg_v01,
+ fw_build_id),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x15,
+ .offset = offsetof(struct wlfw_cap_resp_msg_v01,
+ num_macs_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x15,
+ .offset = offsetof(struct wlfw_cap_resp_msg_v01,
+ num_macs),
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_bdf_download_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ valid),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ file_id_valid),
+ },
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = 1,
+ .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ file_id),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ total_size_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ total_size),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ seg_id_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ seg_id),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ data_valid),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(u16),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ data_len),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = QMI_WLFW_MAX_DATA_SIZE_V01,
+ .elem_size = sizeof(u8),
+ .array_type = VAR_LEN_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ data),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ end_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ end),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x15,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ bdf_type_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x15,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ bdf_type),
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_bdf_download_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_bdf_download_resp_msg_v01,
+ resp),
+ .ei_array = qmi_response_type_v01_ei,
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_cal_report_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_cal_report_req_msg_v01,
+ meta_data_len),
+ },
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = QMI_WLFW_MAX_NUM_CAL_V01,
+ .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01),
+ .array_type = VAR_LEN_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_cal_report_req_msg_v01,
+ meta_data),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_cal_report_req_msg_v01,
+ xo_cal_data_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_cal_report_req_msg_v01,
+ xo_cal_data),
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_cal_report_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_cal_report_resp_msg_v01,
+ resp),
+ .ei_array = qmi_response_type_v01_ei,
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_initiate_cal_download_ind_msg_v01_ei[] = {
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = 1,
+ .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_initiate_cal_download_ind_msg_v01,
+ cal_id),
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_cal_download_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_cal_download_req_msg_v01,
+ valid),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_cal_download_req_msg_v01,
+ file_id_valid),
+ },
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = 1,
+ .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_cal_download_req_msg_v01,
+ file_id),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_cal_download_req_msg_v01,
+ total_size_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_cal_download_req_msg_v01,
+ total_size),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_cal_download_req_msg_v01,
+ seg_id_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_cal_download_req_msg_v01,
+ seg_id),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_cal_download_req_msg_v01,
+ data_valid),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(u16),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_cal_download_req_msg_v01,
+ data_len),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = QMI_WLFW_MAX_DATA_SIZE_V01,
+ .elem_size = sizeof(u8),
+ .array_type = VAR_LEN_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_cal_download_req_msg_v01,
+ data),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_cal_download_req_msg_v01,
+ end_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_cal_download_req_msg_v01,
+ end),
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_cal_download_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_cal_download_resp_msg_v01,
+ resp),
+ .ei_array = qmi_response_type_v01_ei,
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_initiate_cal_update_ind_msg_v01_ei[] = {
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = 1,
+ .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_initiate_cal_update_ind_msg_v01,
+ cal_id),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_initiate_cal_update_ind_msg_v01,
+ total_size),
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_cal_update_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = 1,
+ .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_cal_update_req_msg_v01,
+ cal_id),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_cal_update_req_msg_v01,
+ seg_id),
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_cal_update_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_cal_update_resp_msg_v01,
+ resp),
+ .ei_array = qmi_response_type_v01_ei,
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_cal_update_resp_msg_v01,
+ file_id_valid),
+ },
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = 1,
+ .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_cal_update_resp_msg_v01,
+ file_id),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_cal_update_resp_msg_v01,
+ total_size_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_cal_update_resp_msg_v01,
+ total_size),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_cal_update_resp_msg_v01,
+ seg_id_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_cal_update_resp_msg_v01,
+ seg_id),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_cal_update_resp_msg_v01,
+ data_valid),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(u16),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_cal_update_resp_msg_v01,
+ data_len),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = QMI_WLFW_MAX_DATA_SIZE_V01,
+ .elem_size = sizeof(u8),
+ .array_type = VAR_LEN_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_cal_update_resp_msg_v01,
+ data),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_cal_update_resp_msg_v01,
+ end_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_cal_update_resp_msg_v01,
+ end),
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_msa_info_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_8_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u64),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_msa_info_req_msg_v01,
+ msa_addr),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_msa_info_req_msg_v01,
+ size),
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_msa_info_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_msa_info_resp_msg_v01,
+ resp),
+ .ei_array = qmi_response_type_v01_ei,
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x03,
+ .offset = offsetof(struct wlfw_msa_info_resp_msg_v01,
+ mem_region_info_len),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = QMI_WLFW_MAX_MEM_REG_V01,
+ .elem_size = sizeof(struct wlfw_memory_region_info_s_v01),
+ .array_type = VAR_LEN_ARRAY,
+ .tlv_type = 0x03,
+ .offset = offsetof(struct wlfw_msa_info_resp_msg_v01,
+ mem_region_info),
+ .ei_array = wlfw_memory_region_info_s_v01_ei,
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_msa_ready_req_msg_v01_ei[] = {
+ {}
+};
+
+struct qmi_elem_info wlfw_msa_ready_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_msa_ready_resp_msg_v01,
+ resp),
+ .ei_array = qmi_response_type_v01_ei,
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_ini_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_ini_req_msg_v01,
+ enablefwlog_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_ini_req_msg_v01,
+ enablefwlog),
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_ini_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_ini_resp_msg_v01,
+ resp),
+ .ei_array = qmi_response_type_v01_ei,
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_athdiag_read_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_athdiag_read_req_msg_v01,
+ offset),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_athdiag_read_req_msg_v01,
+ mem_type),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x03,
+ .offset = offsetof(struct wlfw_athdiag_read_req_msg_v01,
+ data_len),
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_athdiag_read_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_athdiag_read_resp_msg_v01,
+ resp),
+ .ei_array = qmi_response_type_v01_ei,
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_athdiag_read_resp_msg_v01,
+ data_valid),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(u16),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_athdiag_read_resp_msg_v01,
+ data_len),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01,
+ .elem_size = sizeof(u8),
+ .array_type = VAR_LEN_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_athdiag_read_resp_msg_v01,
+ data),
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_athdiag_write_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_athdiag_write_req_msg_v01,
+ offset),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_athdiag_write_req_msg_v01,
+ mem_type),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(u16),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x03,
+ .offset = offsetof(struct wlfw_athdiag_write_req_msg_v01,
+ data_len),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01,
+ .elem_size = sizeof(u8),
+ .array_type = VAR_LEN_ARRAY,
+ .tlv_type = 0x03,
+ .offset = offsetof(struct wlfw_athdiag_write_req_msg_v01,
+ data),
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_athdiag_write_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_athdiag_write_resp_msg_v01,
+ resp),
+ .ei_array = qmi_response_type_v01_ei,
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_vbatt_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_8_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u64),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_vbatt_req_msg_v01,
+ voltage_uv),
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_vbatt_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_vbatt_resp_msg_v01,
+ resp),
+ .ei_array = qmi_response_type_v01_ei,
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_mac_addr_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_mac_addr_req_msg_v01,
+ mac_addr_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = QMI_WLFW_MAC_ADDR_SIZE_V01,
+ .elem_size = sizeof(u8),
+ .array_type = STATIC_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_mac_addr_req_msg_v01,
+ mac_addr),
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_mac_addr_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_mac_addr_resp_msg_v01,
+ resp),
+ .ei_array = qmi_response_type_v01_ei,
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_host_cap_req_msg_v01,
+ daemon_support_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_host_cap_req_msg_v01,
+ daemon_support),
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_host_cap_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_host_cap_resp_msg_v01,
+ resp),
+ .ei_array = qmi_response_type_v01_ei,
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_request_mem_ind_msg_v01_ei[] = {
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_request_mem_ind_msg_v01,
+ mem_seg_len),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = QMI_WLFW_MAX_NUM_MEM_SEG_V01,
+ .elem_size = sizeof(struct wlfw_mem_seg_s_v01),
+ .array_type = VAR_LEN_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_request_mem_ind_msg_v01,
+ mem_seg),
+ .ei_array = wlfw_mem_seg_s_v01_ei,
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_respond_mem_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_respond_mem_req_msg_v01,
+ mem_seg_len),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = QMI_WLFW_MAX_NUM_MEM_SEG_V01,
+ .elem_size = sizeof(struct wlfw_mem_seg_resp_s_v01),
+ .array_type = VAR_LEN_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_respond_mem_req_msg_v01,
+ mem_seg),
+ .ei_array = wlfw_mem_seg_resp_s_v01_ei,
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_respond_mem_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_respond_mem_resp_msg_v01,
+ resp),
+ .ei_array = qmi_response_type_v01_ei,
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_mem_ready_ind_msg_v01_ei[] = {
+ {}
+};
+
+struct qmi_elem_info wlfw_fw_init_done_ind_msg_v01_ei[] = {
+ {}
+};
+
+struct qmi_elem_info wlfw_rejuvenate_ind_msg_v01_ei[] = {
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01,
+ cause_for_rejuvenation_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01,
+ cause_for_rejuvenation),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01,
+ requesting_sub_system_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01,
+ requesting_sub_system),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01,
+ line_number_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_2_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u16),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01,
+ line_number),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01,
+ function_name_valid),
+ },
+ {
+ .data_type = QMI_STRING,
+ .elem_len = QMI_WLFW_FUNCTION_NAME_LEN_V01 + 1,
+ .elem_size = sizeof(char),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01,
+ function_name),
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_rejuvenate_ack_req_msg_v01_ei[] = {
+ {}
+};
+
+struct qmi_elem_info wlfw_rejuvenate_ack_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_rejuvenate_ack_resp_msg_v01,
+ resp),
+ .ei_array = qmi_response_type_v01_ei,
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_dynamic_feature_mask_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_dynamic_feature_mask_req_msg_v01,
+ mask_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_8_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u64),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_dynamic_feature_mask_req_msg_v01,
+ mask),
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_dynamic_feature_mask_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_dynamic_feature_mask_resp_msg_v01,
+ resp),
+ .ei_array = qmi_response_type_v01_ei,
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_dynamic_feature_mask_resp_msg_v01,
+ prev_mask_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_8_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u64),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_dynamic_feature_mask_resp_msg_v01,
+ prev_mask),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_dynamic_feature_mask_resp_msg_v01,
+ curr_mask_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_8_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u64),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_dynamic_feature_mask_resp_msg_v01,
+ curr_mask),
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_m3_info_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_8_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u64),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_m3_info_req_msg_v01,
+ addr),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_m3_info_req_msg_v01,
+ size),
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_m3_info_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_m3_info_resp_msg_v01,
+ resp),
+ .ei_array = qmi_response_type_v01_ei,
+ },
+ {}
+};
+
+struct qmi_elem_info wlfw_xo_cal_ind_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_xo_cal_ind_msg_v01,
+ xo_cal_data),
+ },
+ {}
+};
diff --git a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h
new file mode 100644
index 000000000000..c5e3870b8871
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h
@@ -0,0 +1,677 @@
+/*
+ * Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef WCN3990_QMI_SVC_V01_H
+#define WCN3990_QMI_SVC_V01_H
+
+#define WLFW_SERVICE_ID_V01 0x45
+#define WLFW_SERVICE_VERS_V01 0x01
+
+#define QMI_WLFW_BDF_DOWNLOAD_REQ_V01 0x0025
+#define QMI_WLFW_MEM_READY_IND_V01 0x0037
+#define QMI_WLFW_DYNAMIC_FEATURE_MASK_RESP_V01 0x003B
+#define QMI_WLFW_INITIATE_CAL_UPDATE_IND_V01 0x002A
+#define QMI_WLFW_HOST_CAP_REQ_V01 0x0034
+#define QMI_WLFW_M3_INFO_REQ_V01 0x003C
+#define QMI_WLFW_CAP_REQ_V01 0x0024
+#define QMI_WLFW_FW_INIT_DONE_IND_V01 0x0038
+#define QMI_WLFW_CAL_REPORT_REQ_V01 0x0026
+#define QMI_WLFW_M3_INFO_RESP_V01 0x003C
+#define QMI_WLFW_CAL_UPDATE_RESP_V01 0x0029
+#define QMI_WLFW_CAL_DOWNLOAD_RESP_V01 0x0027
+#define QMI_WLFW_XO_CAL_IND_V01 0x003D
+#define QMI_WLFW_INI_RESP_V01 0x002F
+#define QMI_WLFW_CAL_REPORT_RESP_V01 0x0026
+#define QMI_WLFW_MAC_ADDR_RESP_V01 0x0033
+#define QMI_WLFW_INITIATE_CAL_DOWNLOAD_IND_V01 0x0028
+#define QMI_WLFW_HOST_CAP_RESP_V01 0x0034
+#define QMI_WLFW_MSA_READY_IND_V01 0x002B
+#define QMI_WLFW_ATHDIAG_WRITE_RESP_V01 0x0031
+#define QMI_WLFW_WLAN_MODE_REQ_V01 0x0022
+#define QMI_WLFW_IND_REGISTER_REQ_V01 0x0020
+#define QMI_WLFW_WLAN_CFG_RESP_V01 0x0023
+#define QMI_WLFW_REQUEST_MEM_IND_V01 0x0035
+#define QMI_WLFW_REJUVENATE_IND_V01 0x0039
+#define QMI_WLFW_DYNAMIC_FEATURE_MASK_REQ_V01 0x003B
+#define QMI_WLFW_ATHDIAG_WRITE_REQ_V01 0x0031
+#define QMI_WLFW_WLAN_MODE_RESP_V01 0x0022
+#define QMI_WLFW_RESPOND_MEM_REQ_V01 0x0036
+#define QMI_WLFW_PIN_CONNECT_RESULT_IND_V01 0x002C
+#define QMI_WLFW_FW_READY_IND_V01 0x0021
+#define QMI_WLFW_MSA_READY_RESP_V01 0x002E
+#define QMI_WLFW_CAL_UPDATE_REQ_V01 0x0029
+#define QMI_WLFW_INI_REQ_V01 0x002F
+#define QMI_WLFW_BDF_DOWNLOAD_RESP_V01 0x0025
+#define QMI_WLFW_REJUVENATE_ACK_RESP_V01 0x003A
+#define QMI_WLFW_MSA_INFO_RESP_V01 0x002D
+#define QMI_WLFW_MSA_READY_REQ_V01 0x002E
+#define QMI_WLFW_CAP_RESP_V01 0x0024
+#define QMI_WLFW_REJUVENATE_ACK_REQ_V01 0x003A
+#define QMI_WLFW_ATHDIAG_READ_RESP_V01 0x0030
+#define QMI_WLFW_VBATT_REQ_V01 0x0032
+#define QMI_WLFW_MAC_ADDR_REQ_V01 0x0033
+#define QMI_WLFW_RESPOND_MEM_RESP_V01 0x0036
+#define QMI_WLFW_VBATT_RESP_V01 0x0032
+#define QMI_WLFW_MSA_INFO_REQ_V01 0x002D
+#define QMI_WLFW_CAL_DOWNLOAD_REQ_V01 0x0027
+#define QMI_WLFW_ATHDIAG_READ_REQ_V01 0x0030
+#define QMI_WLFW_WLAN_CFG_REQ_V01 0x0023
+#define QMI_WLFW_IND_REGISTER_RESP_V01 0x0020
+
+#define QMI_WLFW_MAX_MEM_REG_V01 2
+#define QMI_WLFW_MAX_NUM_MEM_SEG_V01 16
+#define QMI_WLFW_MAX_NUM_CAL_V01 5
+#define QMI_WLFW_MAX_DATA_SIZE_V01 6144
+#define QMI_WLFW_FUNCTION_NAME_LEN_V01 128
+#define QMI_WLFW_MAX_NUM_CE_V01 12
+#define QMI_WLFW_MAX_TIMESTAMP_LEN_V01 32
+#define QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01 6144
+#define QMI_WLFW_MAX_NUM_GPIO_V01 32
+#define QMI_WLFW_MAX_BUILD_ID_LEN_V01 128
+#define QMI_WLFW_MAX_NUM_MEM_CFG_V01 2
+#define QMI_WLFW_MAX_STR_LEN_V01 16
+#define QMI_WLFW_MAX_NUM_SHADOW_REG_V01 24
+#define QMI_WLFW_MAC_ADDR_SIZE_V01 6
+#define QMI_WLFW_MAX_SHADOW_REG_V2 36
+#define QMI_WLFW_MAX_NUM_SVC_V01 24
+
+enum wlfw_driver_mode_enum_v01 {
+ QMI_WLFW_MISSION_V01 = 0,
+ QMI_WLFW_FTM_V01 = 1,
+ QMI_WLFW_EPPING_V01 = 2,
+ QMI_WLFW_WALTEST_V01 = 3,
+ QMI_WLFW_OFF_V01 = 4,
+ QMI_WLFW_CCPM_V01 = 5,
+ QMI_WLFW_QVIT_V01 = 6,
+ QMI_WLFW_CALIBRATION_V01 = 7,
+};
+
+enum wlfw_cal_temp_id_enum_v01 {
+ QMI_WLFW_CAL_TEMP_IDX_0_V01 = 0,
+ QMI_WLFW_CAL_TEMP_IDX_1_V01 = 1,
+ QMI_WLFW_CAL_TEMP_IDX_2_V01 = 2,
+ QMI_WLFW_CAL_TEMP_IDX_3_V01 = 3,
+ QMI_WLFW_CAL_TEMP_IDX_4_V01 = 4,
+};
+
+enum wlfw_pipedir_enum_v01 {
+ QMI_WLFW_PIPEDIR_NONE_V01 = 0,
+ QMI_WLFW_PIPEDIR_IN_V01 = 1,
+ QMI_WLFW_PIPEDIR_OUT_V01 = 2,
+ QMI_WLFW_PIPEDIR_INOUT_V01 = 3,
+};
+
+enum wlfw_mem_type_enum_v01 {
+ QMI_WLFW_MEM_TYPE_MSA_V01 = 0,
+ QMI_WLFW_MEM_TYPE_DDR_V01 = 1,
+};
+
+#define QMI_WLFW_CE_ATTR_FLAGS_V01 ((u32)0x00)
+#define QMI_WLFW_CE_ATTR_NO_SNOOP_V01 ((u32)0x01)
+#define QMI_WLFW_CE_ATTR_BYTE_SWAP_DATA_V01 ((u32)0x02)
+#define QMI_WLFW_CE_ATTR_SWIZZLE_DESCRIPTORS_V01 ((u32)0x04)
+#define QMI_WLFW_CE_ATTR_DISABLE_INTR_V01 ((u32)0x08)
+#define QMI_WLFW_CE_ATTR_ENABLE_POLL_V01 ((u32)0x10)
+
+#define QMI_WLFW_ALREADY_REGISTERED_V01 ((u64)0x01ULL)
+#define QMI_WLFW_FW_READY_V01 ((u64)0x02ULL)
+#define QMI_WLFW_MSA_READY_V01 ((u64)0x04ULL)
+#define QMI_WLFW_MEM_READY_V01 ((u64)0x08ULL)
+#define QMI_WLFW_FW_INIT_DONE_V01 ((u64)0x10ULL)
+
+#define QMI_WLFW_FW_REJUVENATE_V01 ((u64)0x01ULL)
+
+struct wlfw_ce_tgt_pipe_cfg_s_v01 {
+ __le32 pipe_num;
+ __le32 pipe_dir;
+ __le32 nentries;
+ __le32 nbytes_max;
+ __le32 flags;
+};
+
+struct wlfw_ce_svc_pipe_cfg_s_v01 {
+ __le32 service_id;
+ __le32 pipe_dir;
+ __le32 pipe_num;
+};
+
+struct wlfw_shadow_reg_cfg_s_v01 {
+ u16 id;
+ u16 offset;
+};
+
+struct wlfw_shadow_reg_v2_cfg_s_v01 {
+ u32 addr;
+};
+
+struct wlfw_memory_region_info_s_v01 {
+ u64 region_addr;
+ u32 size;
+ u8 secure_flag;
+};
+
+struct wlfw_mem_cfg_s_v01 {
+ u64 offset;
+ u32 size;
+ u8 secure_flag;
+};
+
+struct wlfw_mem_seg_s_v01 {
+ u32 size;
+ enum wlfw_mem_type_enum_v01 type;
+ u32 mem_cfg_len;
+ struct wlfw_mem_cfg_s_v01 mem_cfg[QMI_WLFW_MAX_NUM_MEM_CFG_V01];
+};
+
+struct wlfw_mem_seg_resp_s_v01 {
+ u64 addr;
+ u32 size;
+ enum wlfw_mem_type_enum_v01 type;
+};
+
+struct wlfw_rf_chip_info_s_v01 {
+ u32 chip_id;
+ u32 chip_family;
+};
+
+struct wlfw_rf_board_info_s_v01 {
+ u32 board_id;
+};
+
+struct wlfw_soc_info_s_v01 {
+ u32 soc_id;
+};
+
+struct wlfw_fw_version_info_s_v01 {
+ u32 fw_version;
+ char fw_build_timestamp[QMI_WLFW_MAX_TIMESTAMP_LEN_V01 + 1];
+};
+
+struct wlfw_ind_register_req_msg_v01 {
+ u8 fw_ready_enable_valid;
+ u8 fw_ready_enable;
+ u8 initiate_cal_download_enable_valid;
+ u8 initiate_cal_download_enable;
+ u8 initiate_cal_update_enable_valid;
+ u8 initiate_cal_update_enable;
+ u8 msa_ready_enable_valid;
+ u8 msa_ready_enable;
+ u8 pin_connect_result_enable_valid;
+ u8 pin_connect_result_enable;
+ u8 client_id_valid;
+ u32 client_id;
+ u8 request_mem_enable_valid;
+ u8 request_mem_enable;
+ u8 mem_ready_enable_valid;
+ u8 mem_ready_enable;
+ u8 fw_init_done_enable_valid;
+ u8 fw_init_done_enable;
+ u8 rejuvenate_enable_valid;
+ u32 rejuvenate_enable;
+ u8 xo_cal_enable_valid;
+ u8 xo_cal_enable;
+};
+
+#define WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN 50
+extern struct qmi_elem_info wlfw_ind_register_req_msg_v01_ei[];
+
+struct wlfw_ind_register_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+ u8 fw_status_valid;
+ u64 fw_status;
+};
+
+#define WLFW_IND_REGISTER_RESP_MSG_V01_MAX_MSG_LEN 18
+extern struct qmi_elem_info wlfw_ind_register_resp_msg_v01_ei[];
+
+struct wlfw_fw_ready_ind_msg_v01 {
+ char placeholder;
+};
+
+#define WLFW_FW_READY_IND_MSG_V01_MAX_MSG_LEN 0
+extern struct qmi_elem_info wlfw_fw_ready_ind_msg_v01_ei[];
+
+struct wlfw_msa_ready_ind_msg_v01 {
+ char placeholder;
+};
+
+#define WLFW_MSA_READY_IND_MSG_V01_MAX_MSG_LEN 0
+extern struct qmi_elem_info wlfw_msa_ready_ind_msg_v01_ei[];
+
+struct wlfw_pin_connect_result_ind_msg_v01 {
+ u8 pwr_pin_result_valid;
+ u32 pwr_pin_result;
+ u8 phy_io_pin_result_valid;
+ u32 phy_io_pin_result;
+ u8 rf_pin_result_valid;
+ u32 rf_pin_result;
+};
+
+#define WLFW_PIN_CONNECT_RESULT_IND_MSG_V01_MAX_MSG_LEN 21
+extern struct qmi_elem_info wlfw_pin_connect_result_ind_msg_v01_ei[];
+
+struct wlfw_wlan_mode_req_msg_v01 {
+ enum wlfw_driver_mode_enum_v01 mode;
+ u8 hw_debug_valid;
+ u8 hw_debug;
+};
+
+#define WLFW_WLAN_MODE_REQ_MSG_V01_MAX_MSG_LEN 11
+extern struct qmi_elem_info wlfw_wlan_mode_req_msg_v01_ei[];
+
+struct wlfw_wlan_mode_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_WLAN_MODE_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_wlan_mode_resp_msg_v01_ei[];
+
+struct wlfw_wlan_cfg_req_msg_v01 {
+ u8 host_version_valid;
+ char host_version[QMI_WLFW_MAX_STR_LEN_V01 + 1];
+ u8 tgt_cfg_valid;
+ u32 tgt_cfg_len;
+ struct wlfw_ce_tgt_pipe_cfg_s_v01 tgt_cfg[QMI_WLFW_MAX_NUM_CE_V01];
+ u8 svc_cfg_valid;
+ u32 svc_cfg_len;
+ struct wlfw_ce_svc_pipe_cfg_s_v01 svc_cfg[QMI_WLFW_MAX_NUM_SVC_V01];
+ u8 shadow_reg_valid;
+ u32 shadow_reg_len;
+ struct wlfw_shadow_reg_cfg_s_v01 shadow_reg[QMI_WLFW_MAX_NUM_SHADOW_REG_V01];
+ u8 shadow_reg_v2_valid;
+ u32 shadow_reg_v2_len;
+ struct wlfw_shadow_reg_v2_cfg_s_v01 shadow_reg_v2[QMI_WLFW_MAX_SHADOW_REG_V2];
+};
+
+#define WLFW_WLAN_CFG_REQ_MSG_V01_MAX_MSG_LEN 803
+extern struct qmi_elem_info wlfw_wlan_cfg_req_msg_v01_ei[];
+
+struct wlfw_wlan_cfg_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_WLAN_CFG_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_wlan_cfg_resp_msg_v01_ei[];
+
+struct wlfw_cap_req_msg_v01 {
+ char placeholder;
+};
+
+#define WLFW_CAP_REQ_MSG_V01_MAX_MSG_LEN 0
+extern struct qmi_elem_info wlfw_cap_req_msg_v01_ei[];
+
+struct wlfw_cap_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+ u8 chip_info_valid;
+ struct wlfw_rf_chip_info_s_v01 chip_info;
+ u8 board_info_valid;
+ struct wlfw_rf_board_info_s_v01 board_info;
+ u8 soc_info_valid;
+ struct wlfw_soc_info_s_v01 soc_info;
+ u8 fw_version_info_valid;
+ struct wlfw_fw_version_info_s_v01 fw_version_info;
+ u8 fw_build_id_valid;
+ char fw_build_id[QMI_WLFW_MAX_BUILD_ID_LEN_V01 + 1];
+ u8 num_macs_valid;
+ u8 num_macs;
+};
+
+#define WLFW_CAP_RESP_MSG_V01_MAX_MSG_LEN 207
+extern struct qmi_elem_info wlfw_cap_resp_msg_v01_ei[];
+
+struct wlfw_bdf_download_req_msg_v01 {
+ u8 valid;
+ u8 file_id_valid;
+ enum wlfw_cal_temp_id_enum_v01 file_id;
+ u8 total_size_valid;
+ u32 total_size;
+ u8 seg_id_valid;
+ u32 seg_id;
+ u8 data_valid;
+ u32 data_len;
+ u8 data[QMI_WLFW_MAX_DATA_SIZE_V01];
+ u8 end_valid;
+ u8 end;
+ u8 bdf_type_valid;
+ u8 bdf_type;
+};
+
+#define WLFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN 6182
+extern struct qmi_elem_info wlfw_bdf_download_req_msg_v01_ei[];
+
+struct wlfw_bdf_download_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_BDF_DOWNLOAD_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_bdf_download_resp_msg_v01_ei[];
+
+struct wlfw_cal_report_req_msg_v01 {
+ u32 meta_data_len;
+ enum wlfw_cal_temp_id_enum_v01 meta_data[QMI_WLFW_MAX_NUM_CAL_V01];
+ u8 xo_cal_data_valid;
+ u8 xo_cal_data;
+};
+
+#define WLFW_CAL_REPORT_REQ_MSG_V01_MAX_MSG_LEN 28
+extern struct qmi_elem_info wlfw_cal_report_req_msg_v01_ei[];
+
+struct wlfw_cal_report_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_CAL_REPORT_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_cal_report_resp_msg_v01_ei[];
+
+struct wlfw_initiate_cal_download_ind_msg_v01 {
+ enum wlfw_cal_temp_id_enum_v01 cal_id;
+};
+
+#define WLFW_INITIATE_CAL_DOWNLOAD_IND_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_initiate_cal_download_ind_msg_v01_ei[];
+
+struct wlfw_cal_download_req_msg_v01 {
+ u8 valid;
+ u8 file_id_valid;
+ enum wlfw_cal_temp_id_enum_v01 file_id;
+ u8 total_size_valid;
+ u32 total_size;
+ u8 seg_id_valid;
+ u32 seg_id;
+ u8 data_valid;
+ u32 data_len;
+ u8 data[QMI_WLFW_MAX_DATA_SIZE_V01];
+ u8 end_valid;
+ u8 end;
+};
+
+#define WLFW_CAL_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN 6178
+extern struct qmi_elem_info wlfw_cal_download_req_msg_v01_ei[];
+
+struct wlfw_cal_download_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_CAL_DOWNLOAD_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_cal_download_resp_msg_v01_ei[];
+
+struct wlfw_initiate_cal_update_ind_msg_v01 {
+ enum wlfw_cal_temp_id_enum_v01 cal_id;
+ u32 total_size;
+};
+
+#define WLFW_INITIATE_CAL_UPDATE_IND_MSG_V01_MAX_MSG_LEN 14
+extern struct qmi_elem_info wlfw_initiate_cal_update_ind_msg_v01_ei[];
+
+struct wlfw_cal_update_req_msg_v01 {
+ enum wlfw_cal_temp_id_enum_v01 cal_id;
+ u32 seg_id;
+};
+
+#define WLFW_CAL_UPDATE_REQ_MSG_V01_MAX_MSG_LEN 14
+extern struct qmi_elem_info wlfw_cal_update_req_msg_v01_ei[];
+
+struct wlfw_cal_update_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+ u8 file_id_valid;
+ enum wlfw_cal_temp_id_enum_v01 file_id;
+ u8 total_size_valid;
+ u32 total_size;
+ u8 seg_id_valid;
+ u32 seg_id;
+ u8 data_valid;
+ u32 data_len;
+ u8 data[QMI_WLFW_MAX_DATA_SIZE_V01];
+ u8 end_valid;
+ u8 end;
+};
+
+#define WLFW_CAL_UPDATE_RESP_MSG_V01_MAX_MSG_LEN 6181
+extern struct qmi_elem_info wlfw_cal_update_resp_msg_v01_ei[];
+
+struct wlfw_msa_info_req_msg_v01 {
+ u64 msa_addr;
+ u32 size;
+};
+
+#define WLFW_MSA_INFO_REQ_MSG_V01_MAX_MSG_LEN 18
+extern struct qmi_elem_info wlfw_msa_info_req_msg_v01_ei[];
+
+struct wlfw_msa_info_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+ u32 mem_region_info_len;
+ struct wlfw_memory_region_info_s_v01 mem_region_info[QMI_WLFW_MAX_MEM_REG_V01];
+};
+
+#define WLFW_MSA_INFO_RESP_MSG_V01_MAX_MSG_LEN 37
+extern struct qmi_elem_info wlfw_msa_info_resp_msg_v01_ei[];
+
+struct wlfw_msa_ready_req_msg_v01 {
+ char placeholder;
+};
+
+#define WLFW_MSA_READY_REQ_MSG_V01_MAX_MSG_LEN 0
+extern struct qmi_elem_info wlfw_msa_ready_req_msg_v01_ei[];
+
+struct wlfw_msa_ready_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_MSA_READY_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_msa_ready_resp_msg_v01_ei[];
+
+struct wlfw_ini_req_msg_v01 {
+ u8 enablefwlog_valid;
+ u8 enablefwlog;
+};
+
+#define WLFW_INI_REQ_MSG_V01_MAX_MSG_LEN 4
+extern struct qmi_elem_info wlfw_ini_req_msg_v01_ei[];
+
+struct wlfw_ini_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_INI_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_ini_resp_msg_v01_ei[];
+
+struct wlfw_athdiag_read_req_msg_v01 {
+ u32 offset;
+ u32 mem_type;
+ u32 data_len;
+};
+
+#define WLFW_ATHDIAG_READ_REQ_MSG_V01_MAX_MSG_LEN 21
+extern struct qmi_elem_info wlfw_athdiag_read_req_msg_v01_ei[];
+
+struct wlfw_athdiag_read_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+ u8 data_valid;
+ u32 data_len;
+ u8 data[QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01];
+};
+
+#define WLFW_ATHDIAG_READ_RESP_MSG_V01_MAX_MSG_LEN 6156
+extern struct qmi_elem_info wlfw_athdiag_read_resp_msg_v01_ei[];
+
+struct wlfw_athdiag_write_req_msg_v01 {
+ u32 offset;
+ u32 mem_type;
+ u32 data_len;
+ u8 data[QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01];
+};
+
+#define WLFW_ATHDIAG_WRITE_REQ_MSG_V01_MAX_MSG_LEN 6163
+extern struct qmi_elem_info wlfw_athdiag_write_req_msg_v01_ei[];
+
+struct wlfw_athdiag_write_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_ATHDIAG_WRITE_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_athdiag_write_resp_msg_v01_ei[];
+
+struct wlfw_vbatt_req_msg_v01 {
+ u64 voltage_uv;
+};
+
+#define WLFW_VBATT_REQ_MSG_V01_MAX_MSG_LEN 11
+extern struct qmi_elem_info wlfw_vbatt_req_msg_v01_ei[];
+
+struct wlfw_vbatt_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_VBATT_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_vbatt_resp_msg_v01_ei[];
+
+struct wlfw_mac_addr_req_msg_v01 {
+ u8 mac_addr_valid;
+ u8 mac_addr[QMI_WLFW_MAC_ADDR_SIZE_V01];
+};
+
+#define WLFW_MAC_ADDR_REQ_MSG_V01_MAX_MSG_LEN 9
+extern struct qmi_elem_info wlfw_mac_addr_req_msg_v01_ei[];
+
+struct wlfw_mac_addr_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_MAC_ADDR_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_mac_addr_resp_msg_v01_ei[];
+
+struct wlfw_host_cap_req_msg_v01 {
+ u8 daemon_support_valid;
+ u8 daemon_support;
+};
+
+#define WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN 4
+extern struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[];
+
+struct wlfw_host_cap_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_HOST_CAP_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_host_cap_resp_msg_v01_ei[];
+
+struct wlfw_request_mem_ind_msg_v01 {
+ u32 mem_seg_len;
+ struct wlfw_mem_seg_s_v01 mem_seg[QMI_WLFW_MAX_NUM_MEM_SEG_V01];
+};
+
+#define WLFW_REQUEST_MEM_IND_MSG_V01_MAX_MSG_LEN 564
+extern struct qmi_elem_info wlfw_request_mem_ind_msg_v01_ei[];
+
+struct wlfw_respond_mem_req_msg_v01 {
+ u32 mem_seg_len;
+ struct wlfw_mem_seg_resp_s_v01 mem_seg[QMI_WLFW_MAX_NUM_MEM_SEG_V01];
+};
+
+#define WLFW_RESPOND_MEM_REQ_MSG_V01_MAX_MSG_LEN 260
+extern struct qmi_elem_info wlfw_respond_mem_req_msg_v01_ei[];
+
+struct wlfw_respond_mem_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_RESPOND_MEM_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_respond_mem_resp_msg_v01_ei[];
+
+struct wlfw_mem_ready_ind_msg_v01 {
+ char placeholder;
+};
+
+#define WLFW_MEM_READY_IND_MSG_V01_MAX_MSG_LEN 0
+extern struct qmi_elem_info wlfw_mem_ready_ind_msg_v01_ei[];
+
+struct wlfw_fw_init_done_ind_msg_v01 {
+ char placeholder;
+};
+
+#define WLFW_FW_INIT_DONE_IND_MSG_V01_MAX_MSG_LEN 0
+extern struct qmi_elem_info wlfw_fw_init_done_ind_msg_v01_ei[];
+
+struct wlfw_rejuvenate_ind_msg_v01 {
+ u8 cause_for_rejuvenation_valid;
+ u8 cause_for_rejuvenation;
+ u8 requesting_sub_system_valid;
+ u8 requesting_sub_system;
+ u8 line_number_valid;
+ u16 line_number;
+ u8 function_name_valid;
+ char function_name[QMI_WLFW_FUNCTION_NAME_LEN_V01 + 1];
+};
+
+#define WLFW_REJUVENATE_IND_MSG_V01_MAX_MSG_LEN 144
+extern struct qmi_elem_info wlfw_rejuvenate_ind_msg_v01_ei[];
+
+struct wlfw_rejuvenate_ack_req_msg_v01 {
+ char placeholder;
+};
+
+#define WLFW_REJUVENATE_ACK_REQ_MSG_V01_MAX_MSG_LEN 0
+extern struct qmi_elem_info wlfw_rejuvenate_ack_req_msg_v01_ei[];
+
+struct wlfw_rejuvenate_ack_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_REJUVENATE_ACK_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_rejuvenate_ack_resp_msg_v01_ei[];
+
+struct wlfw_dynamic_feature_mask_req_msg_v01 {
+ u8 mask_valid;
+ u64 mask;
+};
+
+#define WLFW_DYNAMIC_FEATURE_MASK_REQ_MSG_V01_MAX_MSG_LEN 11
+extern struct qmi_elem_info wlfw_dynamic_feature_mask_req_msg_v01_ei[];
+
+struct wlfw_dynamic_feature_mask_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+ u8 prev_mask_valid;
+ u64 prev_mask;
+ u8 curr_mask_valid;
+ u64 curr_mask;
+};
+
+#define WLFW_DYNAMIC_FEATURE_MASK_RESP_MSG_V01_MAX_MSG_LEN 29
+extern struct qmi_elem_info wlfw_dynamic_feature_mask_resp_msg_v01_ei[];
+
+struct wlfw_m3_info_req_msg_v01 {
+ u64 addr;
+ u32 size;
+};
+
+#define WLFW_M3_INFO_REQ_MSG_V01_MAX_MSG_LEN 18
+extern struct qmi_elem_info wlfw_m3_info_req_msg_v01_ei[];
+
+struct wlfw_m3_info_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_M3_INFO_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_m3_info_resp_msg_v01_ei[];
+
+struct wlfw_xo_cal_ind_msg_v01 {
+ u8 xo_cal_data;
+};
+
+#define WLFW_XO_CAL_IND_MSG_V01_MAX_MSG_LEN 4
+extern struct qmi_elem_info wlfw_xo_cal_ind_msg_v01_ei[];
+
+#endif
diff --git a/drivers/net/wireless/ath/ath10k/rx_desc.h b/drivers/net/wireless/ath/ath10k/rx_desc.h
index ea4075d456fa..310674de3cb8 100644
--- a/drivers/net/wireless/ath/ath10k/rx_desc.h
+++ b/drivers/net/wireless/ath/ath10k/rx_desc.h
@@ -1277,4 +1277,19 @@ struct fw_rx_desc_base {
u8 info0;
} __packed;
+#define FW_RX_DESC_FLAGS_FIRST_MSDU (1 << 0)
+#define FW_RX_DESC_FLAGS_LAST_MSDU (1 << 1)
+#define FW_RX_DESC_C3_FAILED (1 << 2)
+#define FW_RX_DESC_C4_FAILED (1 << 3)
+#define FW_RX_DESC_IPV6 (1 << 4)
+#define FW_RX_DESC_TCP (1 << 5)
+#define FW_RX_DESC_UDP (1 << 6)
+
+struct fw_rx_desc_hl {
+ u8 info0;
+ u8 version;
+ u8 len;
+ u8 flags;
+} __packed;
+
#endif /* _RX_DESC_H_ */
diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
index 7f61591ce0de..983ecfef1d28 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.c
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
@@ -1941,7 +1941,8 @@ static int ath10k_sdio_probe(struct sdio_func *func,
struct ath10k_sdio *ar_sdio;
struct ath10k *ar;
enum ath10k_hw_rev hw_rev;
- u32 chip_id, dev_id_base;
+ u32 dev_id_base;
+ struct ath10k_bus_params bus_params;
int ret, i;
/* Assumption: All SDIO based chipsets (so far) are QCA6174 based.
@@ -2035,9 +2036,10 @@ static int ath10k_sdio_probe(struct sdio_func *func,
goto err_free_wq;
}
+ bus_params.dev_type = ATH10K_DEV_TYPE_HL;
/* TODO: don't know yet how to get chip_id with SDIO */
- chip_id = 0;
- ret = ath10k_core_register(ar, chip_id);
+ bus_params.chip_id = 0;
+ ret = ath10k_core_register(ar, &bus_params);
if (ret) {
ath10k_err(ar, "failed to register driver core: %d\n", ret);
goto err_free_wq;
diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c
index fa1843a7e0fd..8d3d9bca410f 100644
--- a/drivers/net/wireless/ath/ath10k/snoc.c
+++ b/drivers/net/wireless/ath/ath10k/snoc.c
@@ -62,10 +62,77 @@ static void ath10k_snoc_htt_tx_cb(struct ath10k_ce_pipe *ce_state);
static void ath10k_snoc_htc_rx_cb(struct ath10k_ce_pipe *ce_state);
static void ath10k_snoc_htt_rx_cb(struct ath10k_ce_pipe *ce_state);
static void ath10k_snoc_htt_htc_rx_cb(struct ath10k_ce_pipe *ce_state);
+static void ath10k_snoc_pktlog_rx_cb(struct ath10k_ce_pipe *ce_state);
static const struct ath10k_snoc_drv_priv drv_priv = {
.hw_rev = ATH10K_HW_WCN3990,
.dma_mask = DMA_BIT_MASK(37),
+ .msa_size = 0x100000,
+};
+
+#define WCN3990_SRC_WR_IDX_OFFSET 0x3C
+#define WCN3990_DST_WR_IDX_OFFSET 0x40
+
+static struct ath10k_shadow_reg_cfg target_shadow_reg_cfg_map[] = {
+ {
+ .ce_id = __cpu_to_le16(0),
+ .reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET),
+ },
+
+ {
+ .ce_id = __cpu_to_le16(3),
+ .reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET),
+ },
+
+ {
+ .ce_id = __cpu_to_le16(4),
+ .reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET),
+ },
+
+ {
+ .ce_id = __cpu_to_le16(5),
+ .reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET),
+ },
+
+ {
+ .ce_id = __cpu_to_le16(7),
+ .reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET),
+ },
+
+ {
+ .ce_id = __cpu_to_le16(1),
+ .reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),
+ },
+
+ {
+ .ce_id = __cpu_to_le16(2),
+ .reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),
+ },
+
+ {
+ .ce_id = __cpu_to_le16(7),
+ .reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),
+ },
+
+ {
+ .ce_id = __cpu_to_le16(8),
+ .reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),
+ },
+
+ {
+ .ce_id = __cpu_to_le16(9),
+ .reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),
+ },
+
+ {
+ .ce_id = __cpu_to_le16(10),
+ .reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),
+ },
+
+ {
+ .ce_id = __cpu_to_le16(11),
+ .reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),
+ },
};
static struct ce_attr host_ce_config_wlan[] = {
@@ -171,7 +238,129 @@ static struct ce_attr host_ce_config_wlan[] = {
.src_nentries = 0,
.src_sz_max = 2048,
.dest_nentries = 512,
- .recv_cb = ath10k_snoc_htt_htc_rx_cb,
+ .recv_cb = ath10k_snoc_pktlog_rx_cb,
+ },
+};
+
+static struct ce_pipe_config target_ce_config_wlan[] = {
+ /* CE0: host->target HTC control and raw streams */
+ {
+ .pipenum = __cpu_to_le32(0),
+ .pipedir = __cpu_to_le32(PIPEDIR_OUT),
+ .nentries = __cpu_to_le32(32),
+ .nbytes_max = __cpu_to_le32(2048),
+ .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+ .reserved = __cpu_to_le32(0),
+ },
+
+ /* CE1: target->host HTT + HTC control */
+ {
+ .pipenum = __cpu_to_le32(1),
+ .pipedir = __cpu_to_le32(PIPEDIR_IN),
+ .nentries = __cpu_to_le32(32),
+ .nbytes_max = __cpu_to_le32(2048),
+ .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+ .reserved = __cpu_to_le32(0),
+ },
+
+ /* CE2: target->host WMI */
+ {
+ .pipenum = __cpu_to_le32(2),
+ .pipedir = __cpu_to_le32(PIPEDIR_IN),
+ .nentries = __cpu_to_le32(64),
+ .nbytes_max = __cpu_to_le32(2048),
+ .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+ .reserved = __cpu_to_le32(0),
+ },
+
+ /* CE3: host->target WMI */
+ {
+ .pipenum = __cpu_to_le32(3),
+ .pipedir = __cpu_to_le32(PIPEDIR_OUT),
+ .nentries = __cpu_to_le32(32),
+ .nbytes_max = __cpu_to_le32(2048),
+ .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+ .reserved = __cpu_to_le32(0),
+ },
+
+ /* CE4: host->target HTT */
+ {
+ .pipenum = __cpu_to_le32(4),
+ .pipedir = __cpu_to_le32(PIPEDIR_OUT),
+ .nentries = __cpu_to_le32(256),
+ .nbytes_max = __cpu_to_le32(256),
+ .flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR),
+ .reserved = __cpu_to_le32(0),
+ },
+
+ /* CE5: target->host HTT (HIF->HTT) */
+ {
+ .pipenum = __cpu_to_le32(5),
+ .pipedir = __cpu_to_le32(PIPEDIR_OUT),
+ .nentries = __cpu_to_le32(1024),
+ .nbytes_max = __cpu_to_le32(64),
+ .flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR),
+ .reserved = __cpu_to_le32(0),
+ },
+
+ /* CE6: Reserved for target autonomous hif_memcpy */
+ {
+ .pipenum = __cpu_to_le32(6),
+ .pipedir = __cpu_to_le32(PIPEDIR_INOUT),
+ .nentries = __cpu_to_le32(32),
+ .nbytes_max = __cpu_to_le32(16384),
+ .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+ .reserved = __cpu_to_le32(0),
+ },
+
+ /* CE7 used only by Host */
+ {
+ .pipenum = __cpu_to_le32(7),
+ .pipedir = __cpu_to_le32(4),
+ .nentries = __cpu_to_le32(0),
+ .nbytes_max = __cpu_to_le32(0),
+ .flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR),
+ .reserved = __cpu_to_le32(0),
+ },
+
+ /* CE8 Target to uMC */
+ {
+ .pipenum = __cpu_to_le32(8),
+ .pipedir = __cpu_to_le32(PIPEDIR_IN),
+ .nentries = __cpu_to_le32(32),
+ .nbytes_max = __cpu_to_le32(2048),
+ .flags = __cpu_to_le32(0),
+ .reserved = __cpu_to_le32(0),
+ },
+
+ /* CE9 target->host HTT */
+ {
+ .pipenum = __cpu_to_le32(9),
+ .pipedir = __cpu_to_le32(PIPEDIR_IN),
+ .nentries = __cpu_to_le32(32),
+ .nbytes_max = __cpu_to_le32(2048),
+ .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+ .reserved = __cpu_to_le32(0),
+ },
+
+ /* CE10 target->host HTT */
+ {
+ .pipenum = __cpu_to_le32(10),
+ .pipedir = __cpu_to_le32(PIPEDIR_IN),
+ .nentries = __cpu_to_le32(32),
+ .nbytes_max = __cpu_to_le32(2048),
+ .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+ .reserved = __cpu_to_le32(0),
+ },
+
+ /* CE11 target autonomous qcache memcpy */
+ {
+ .pipenum = __cpu_to_le32(11),
+ .pipedir = __cpu_to_le32(PIPEDIR_IN),
+ .nentries = __cpu_to_le32(32),
+ .nbytes_max = __cpu_to_le32(2048),
+ .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+ .reserved = __cpu_to_le32(0),
},
};
@@ -436,6 +625,14 @@ static void ath10k_snoc_htt_htc_rx_cb(struct ath10k_ce_pipe *ce_state)
ath10k_snoc_process_rx_cb(ce_state, ath10k_htc_rx_completion_handler);
}
+/* Called by lower (CE) layer when data is received from the Target.
+ * WCN3990 firmware uses separate CE(CE11) to transfer pktlog data.
+ */
+static void ath10k_snoc_pktlog_rx_cb(struct ath10k_ce_pipe *ce_state)
+{
+ ath10k_snoc_process_rx_cb(ce_state, ath10k_htc_rx_completion_handler);
+}
+
static void ath10k_snoc_htt_rx_deliver(struct ath10k *ar, struct sk_buff *skb)
{
skb_pull(skb, sizeof(struct ath10k_htc_hdr));
@@ -616,7 +813,7 @@ static int ath10k_snoc_hif_map_service_to_pipe(struct ath10k *ar,
}
}
- if (WARN_ON(!ul_set || !dl_set))
+ if (!ul_set || !dl_set)
return -ENOENT;
return 0;
@@ -722,14 +919,15 @@ static void ath10k_snoc_buffer_cleanup(struct ath10k *ar)
static void ath10k_snoc_hif_stop(struct ath10k *ar)
{
ath10k_snoc_irq_disable(ar);
- ath10k_snoc_buffer_cleanup(ar);
napi_synchronize(&ar->napi);
napi_disable(&ar->napi);
+ ath10k_snoc_buffer_cleanup(ar);
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif stop\n");
}
static int ath10k_snoc_hif_start(struct ath10k *ar)
{
+ napi_enable(&ar->napi);
ath10k_snoc_irq_enable(ar);
ath10k_snoc_rx_post(ar);
@@ -756,11 +954,47 @@ static int ath10k_snoc_init_pipes(struct ath10k *ar)
static int ath10k_snoc_wlan_enable(struct ath10k *ar)
{
- return 0;
+ struct ath10k_tgt_pipe_cfg tgt_cfg[CE_COUNT_MAX];
+ struct ath10k_qmi_wlan_enable_cfg cfg;
+ enum wlfw_driver_mode_enum_v01 mode;
+ int pipe_num;
+
+ for (pipe_num = 0; pipe_num < CE_COUNT_MAX; pipe_num++) {
+ tgt_cfg[pipe_num].pipe_num =
+ target_ce_config_wlan[pipe_num].pipenum;
+ tgt_cfg[pipe_num].pipe_dir =
+ target_ce_config_wlan[pipe_num].pipedir;
+ tgt_cfg[pipe_num].nentries =
+ target_ce_config_wlan[pipe_num].nentries;
+ tgt_cfg[pipe_num].nbytes_max =
+ target_ce_config_wlan[pipe_num].nbytes_max;
+ tgt_cfg[pipe_num].flags =
+ target_ce_config_wlan[pipe_num].flags;
+ tgt_cfg[pipe_num].reserved = 0;
+ }
+
+ cfg.num_ce_tgt_cfg = sizeof(target_ce_config_wlan) /
+ sizeof(struct ath10k_tgt_pipe_cfg);
+ cfg.ce_tgt_cfg = (struct ath10k_tgt_pipe_cfg *)
+ &tgt_cfg;
+ cfg.num_ce_svc_pipe_cfg = sizeof(target_service_to_ce_map_wlan) /
+ sizeof(struct ath10k_svc_pipe_cfg);
+ cfg.ce_svc_cfg = (struct ath10k_svc_pipe_cfg *)
+ &target_service_to_ce_map_wlan;
+ cfg.num_shadow_reg_cfg = sizeof(target_shadow_reg_cfg_map) /
+ sizeof(struct ath10k_shadow_reg_cfg);
+ cfg.shadow_reg_cfg = (struct ath10k_shadow_reg_cfg *)
+ &target_shadow_reg_cfg_map;
+
+ mode = QMI_WLFW_MISSION_V01;
+
+ return ath10k_qmi_wlan_enable(ar, &cfg, mode,
+ NULL);
}
static void ath10k_snoc_wlan_disable(struct ath10k *ar)
{
+ ath10k_qmi_wlan_disable(ar);
}
static void ath10k_snoc_hif_power_down(struct ath10k *ar)
@@ -792,7 +1026,6 @@ static int ath10k_snoc_hif_power_up(struct ath10k *ar)
goto err_wlan_enable;
}
- napi_enable(&ar->napi);
return 0;
err_wlan_enable:
@@ -948,6 +1181,32 @@ out:
return ret;
}
+int ath10k_snoc_fw_indication(struct ath10k *ar, u64 type)
+{
+ struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
+ struct ath10k_bus_params bus_params;
+ int ret;
+
+ switch (type) {
+ case ATH10K_QMI_EVENT_FW_READY_IND:
+ bus_params.dev_type = ATH10K_DEV_TYPE_LL;
+ bus_params.chip_id = ar_snoc->target_info.soc_version;
+ ret = ath10k_core_register(ar, &bus_params);
+ if (ret) {
+ ath10k_err(ar, "failed to register driver core: %d\n",
+ ret);
+ }
+ break;
+ case ATH10K_QMI_EVENT_FW_DOWN_IND:
+ break;
+ default:
+ ath10k_err(ar, "invalid fw indication: %llx\n", type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int ath10k_snoc_setup_resource(struct ath10k *ar)
{
struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
@@ -1272,6 +1531,7 @@ static int ath10k_snoc_probe(struct platform_device *pdev)
struct ath10k_snoc *ar_snoc;
struct device *dev;
struct ath10k *ar;
+ u32 msa_size;
int ret;
u32 i;
@@ -1303,6 +1563,7 @@ static int ath10k_snoc_probe(struct platform_device *pdev)
ar_snoc->ar = ar;
ar_snoc->ce.bus_ops = &ath10k_snoc_bus_ops;
ar->ce_priv = &ar_snoc->ce;
+ msa_size = drv_data->msa_size;
ret = ath10k_snoc_resource_init(ar);
if (ret) {
@@ -1341,10 +1602,10 @@ static int ath10k_snoc_probe(struct platform_device *pdev)
goto err_free_irq;
}
- ret = ath10k_core_register(ar, drv_data->hw_rev);
+ ret = ath10k_qmi_init(ar, msa_size);
if (ret) {
- ath10k_err(ar, "failed to register driver core: %d\n", ret);
- goto err_hw_power_off;
+ ath10k_warn(ar, "failed to register wlfw qmi client: %d\n", ret);
+ goto err_core_destroy;
}
ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc probe\n");
@@ -1352,9 +1613,6 @@ static int ath10k_snoc_probe(struct platform_device *pdev)
return 0;
-err_hw_power_off:
- ath10k_hw_power_off(ar);
-
err_free_irq:
ath10k_snoc_free_irq(ar);
@@ -1376,6 +1634,7 @@ static int ath10k_snoc_remove(struct platform_device *pdev)
ath10k_hw_power_off(ar);
ath10k_snoc_free_irq(ar);
ath10k_snoc_release_resource(ar);
+ ath10k_qmi_deinit(ar);
ath10k_core_destroy(ar);
return 0;
diff --git a/drivers/net/wireless/ath/ath10k/snoc.h b/drivers/net/wireless/ath/ath10k/snoc.h
index f9e530189d48..e1d2d6675556 100644
--- a/drivers/net/wireless/ath/ath10k/snoc.h
+++ b/drivers/net/wireless/ath/ath10k/snoc.h
@@ -19,10 +19,12 @@
#include "hw.h"
#include "ce.h"
+#include "qmi.h"
struct ath10k_snoc_drv_priv {
enum ath10k_hw_rev hw_rev;
u64 dma_mask;
+ u32 msa_size;
};
struct snoc_state {
@@ -81,6 +83,7 @@ struct ath10k_snoc {
struct timer_list rx_post_retry;
struct ath10k_wcn3990_vreg_info *vreg;
struct ath10k_wcn3990_clk_info *clk;
+ struct ath10k_qmi *qmi;
};
static inline struct ath10k_snoc *ath10k_snoc_priv(struct ath10k *ar)
@@ -90,5 +93,6 @@ static inline struct ath10k_snoc *ath10k_snoc_priv(struct ath10k *ar)
void ath10k_snoc_write32(struct ath10k *ar, u32 offset, u32 value);
u32 ath10k_snoc_read32(struct ath10k *ar, u32 offset);
+int ath10k_snoc_fw_indication(struct ath10k *ar, u64 type);
#endif /* _SNOC_H_ */
diff --git a/drivers/net/wireless/ath/ath10k/targaddrs.h b/drivers/net/wireless/ath/ath10k/targaddrs.h
index c2b5bad0459b..b11a1c3d87b4 100644
--- a/drivers/net/wireless/ath/ath10k/targaddrs.h
+++ b/drivers/net/wireless/ath/ath10k/targaddrs.h
@@ -484,6 +484,10 @@ struct host_interest {
#define QCA99X0_BOARD_DATA_SZ 12288
#define QCA99X0_BOARD_EXT_DATA_SZ 0
+/* Dual band extended board data */
+#define QCA99X0_EXT_BOARD_DATA_SZ 2048
+#define EXT_BOARD_ADDRESS_OFFSET 0x3000
+
#define QCA4019_BOARD_DATA_SZ 12064
#define QCA4019_BOARD_EXT_DATA_SZ 0
diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c
index cda164f6e9f6..23606b6972d0 100644
--- a/drivers/net/wireless/ath/ath10k/txrx.c
+++ b/drivers/net/wireless/ath/ath10k/txrx.c
@@ -95,7 +95,8 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt,
wake_up(&htt->empty_tx_wq);
spin_unlock_bh(&htt->tx_lock);
- dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
+ if (ar->dev_type != ATH10K_DEV_TYPE_HL)
+ dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
ath10k_report_offchan_tx(htt->ar, msdu);
diff --git a/drivers/net/wireless/ath/ath10k/usb.c b/drivers/net/wireless/ath/ath10k/usb.c
index d4803ff5a78a..f731d35ee76d 100644
--- a/drivers/net/wireless/ath/ath10k/usb.c
+++ b/drivers/net/wireless/ath/ath10k/usb.c
@@ -983,7 +983,7 @@ static int ath10k_usb_probe(struct usb_interface *interface,
struct usb_device *dev = interface_to_usbdev(interface);
int ret, vendor_id, product_id;
enum ath10k_hw_rev hw_rev;
- u32 chip_id;
+ struct ath10k_bus_params bus_params;
/* Assumption: All USB based chipsets (so far) are QCA9377 based.
* If there will be newer chipsets that does not use the hw reg
@@ -1016,9 +1016,10 @@ static int ath10k_usb_probe(struct usb_interface *interface,
ar->id.vendor = vendor_id;
ar->id.device = product_id;
+ bus_params.dev_type = ATH10K_DEV_TYPE_HL;
/* TODO: don't know yet how to get chip_id with USB */
- chip_id = 0;
- ret = ath10k_core_register(ar, chip_id);
+ bus_params.chip_id = 0;
+ ret = ath10k_core_register(ar, &bus_params);
if (ret) {
ath10k_warn(ar, "failed to register driver core: %d\n", ret);
goto err;
diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h
index 7fd63bbf8e24..7978a7783f90 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-ops.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h
@@ -210,6 +210,9 @@ struct wmi_ops {
u32 fw_feature_bitmap);
int (*get_vdev_subtype)(struct ath10k *ar,
enum wmi_vdev_subtype subtype);
+ struct sk_buff *(*gen_wow_config_pno)(struct ath10k *ar,
+ u32 vdev_id,
+ struct wmi_pno_scan_req *pno_scan);
struct sk_buff *(*gen_pdev_bss_chan_info_req)
(struct ath10k *ar,
enum wmi_bss_survey_req_type type);
@@ -1361,6 +1364,24 @@ ath10k_wmi_wow_del_pattern(struct ath10k *ar, u32 vdev_id, u32 pattern_id)
}
static inline int
+ath10k_wmi_wow_config_pno(struct ath10k *ar, u32 vdev_id,
+ struct wmi_pno_scan_req *pno_scan)
+{
+ struct sk_buff *skb;
+ u32 cmd_id;
+
+ if (!ar->wmi.ops->gen_wow_config_pno)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_wow_config_pno(ar, vdev_id, pno_scan);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ cmd_id = ar->wmi.cmd->network_list_offload_config_cmdid;
+ return ath10k_wmi_cmd_send(ar, skb, cmd_id);
+}
+
+static inline int
ath10k_wmi_update_fw_tdls_state(struct ath10k *ar, u32 vdev_id,
enum wmi_tdls_state state)
{
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
index cdc1e64d52ad..bab8b2527fb8 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -19,7 +19,6 @@
#include "debug.h"
#include "mac.h"
#include "hw.h"
-#include "mac.h"
#include "wmi.h"
#include "wmi-ops.h"
#include "wmi-tlv.h"
@@ -1569,7 +1568,10 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar)
cfg->num_vdevs = __cpu_to_le32(TARGET_TLV_NUM_VDEVS);
- cfg->num_peers = __cpu_to_le32(ar->hw_params.num_peers);
+ if (ar->hw_params.num_peers)
+ cfg->num_peers = __cpu_to_le32(ar->hw_params.num_peers);
+ else
+ cfg->num_peers = __cpu_to_le32(TARGET_TLV_NUM_PEERS);
cfg->ast_skid_limit = __cpu_to_le32(ar->hw_params.ast_skid_limit);
cfg->num_wds_entries = __cpu_to_le32(ar->hw_params.num_wds_entries);
@@ -1582,7 +1584,10 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar)
}
cfg->num_peer_keys = __cpu_to_le32(2);
- cfg->num_tids = __cpu_to_le32(TARGET_TLV_NUM_TIDS);
+ if (ar->hw_params.num_peers)
+ cfg->num_tids = __cpu_to_le32(ar->hw_params.num_peers * 2);
+ else
+ cfg->num_tids = __cpu_to_le32(TARGET_TLV_NUM_TIDS);
cfg->tx_chain_mask = __cpu_to_le32(0x7);
cfg->rx_chain_mask = __cpu_to_le32(0x7);
cfg->rx_timeout_pri[0] = __cpu_to_le32(0x64);
@@ -3436,6 +3441,192 @@ ath10k_wmi_tlv_op_gen_wow_del_pattern(struct ath10k *ar, u32 vdev_id,
return skb;
}
+/* Request FW to start PNO operation */
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_config_pno_start(struct ath10k *ar,
+ u32 vdev_id,
+ struct wmi_pno_scan_req *pno)
+{
+ struct nlo_configured_parameters *nlo_list;
+ struct wmi_tlv_wow_nlo_config_cmd *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+ __le32 *channel_list;
+ u16 tlv_len;
+ size_t len;
+ void *ptr;
+ u32 i;
+
+ len = sizeof(*tlv) + sizeof(*cmd) +
+ sizeof(*tlv) +
+ /* TLV place holder for array of structures
+ * nlo_configured_parameters(nlo_list)
+ */
+ sizeof(*tlv);
+ /* TLV place holder for array of uint32 channel_list */
+
+ len += sizeof(u32) * min_t(u8, pno->a_networks[0].channel_count,
+ WMI_NLO_MAX_CHAN);
+ len += sizeof(struct nlo_configured_parameters) *
+ min_t(u8, pno->uc_networks_count, WMI_NLO_MAX_SSIDS);
+
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ ptr = (void *)skb->data;
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_NLO_CONFIG_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+
+ /* wmi_tlv_wow_nlo_config_cmd parameters*/
+ cmd->vdev_id = __cpu_to_le32(pno->vdev_id);
+ cmd->flags = __cpu_to_le32(WMI_NLO_CONFIG_START | WMI_NLO_CONFIG_SSID_HIDE_EN);
+
+ /* current FW does not support min-max range for dwell time */
+ cmd->active_dwell_time = __cpu_to_le32(pno->active_max_time);
+ cmd->passive_dwell_time = __cpu_to_le32(pno->passive_max_time);
+
+ if (pno->do_passive_scan)
+ cmd->flags |= __cpu_to_le32(WMI_NLO_CONFIG_SCAN_PASSIVE);
+
+ /* copy scan interval */
+ cmd->fast_scan_period = __cpu_to_le32(pno->fast_scan_period);
+ cmd->slow_scan_period = __cpu_to_le32(pno->slow_scan_period);
+ cmd->fast_scan_max_cycles = __cpu_to_le32(pno->fast_scan_max_cycles);
+ cmd->delay_start_time = __cpu_to_le32(pno->delay_start_time);
+
+ if (pno->enable_pno_scan_randomization) {
+ cmd->flags |= __cpu_to_le32(WMI_NLO_CONFIG_SPOOFED_MAC_IN_PROBE_REQ |
+ WMI_NLO_CONFIG_RANDOM_SEQ_NO_IN_PROBE_REQ);
+ ether_addr_copy(cmd->mac_addr.addr, pno->mac_addr);
+ ether_addr_copy(cmd->mac_mask.addr, pno->mac_addr_mask);
+ }
+
+ ptr += sizeof(*tlv);
+ ptr += sizeof(*cmd);
+
+ /* nlo_configured_parameters(nlo_list) */
+ cmd->no_of_ssids = __cpu_to_le32(min_t(u8, pno->uc_networks_count,
+ WMI_NLO_MAX_SSIDS));
+ tlv_len = __le32_to_cpu(cmd->no_of_ssids) *
+ sizeof(struct nlo_configured_parameters);
+
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT);
+ tlv->len = __cpu_to_le16(len);
+
+ ptr += sizeof(*tlv);
+ nlo_list = ptr;
+ for (i = 0; i < __le32_to_cpu(cmd->no_of_ssids); i++) {
+ tlv = (struct wmi_tlv *)(&nlo_list[i].tlv_header);
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE);
+ tlv->len = __cpu_to_le16(sizeof(struct nlo_configured_parameters) -
+ sizeof(*tlv));
+
+ /* copy ssid and it's length */
+ nlo_list[i].ssid.valid = __cpu_to_le32(true);
+ nlo_list[i].ssid.ssid.ssid_len = pno->a_networks[i].ssid.ssid_len;
+ memcpy(nlo_list[i].ssid.ssid.ssid,
+ pno->a_networks[i].ssid.ssid,
+ __le32_to_cpu(nlo_list[i].ssid.ssid.ssid_len));
+
+ /* copy rssi threshold */
+ if (pno->a_networks[i].rssi_threshold &&
+ pno->a_networks[i].rssi_threshold > -300) {
+ nlo_list[i].rssi_cond.valid = __cpu_to_le32(true);
+ nlo_list[i].rssi_cond.rssi =
+ __cpu_to_le32(pno->a_networks[i].rssi_threshold);
+ }
+
+ nlo_list[i].bcast_nw_type.valid = __cpu_to_le32(true);
+ nlo_list[i].bcast_nw_type.bcast_nw_type =
+ __cpu_to_le32(pno->a_networks[i].bcast_nw_type);
+ }
+
+ ptr += __le32_to_cpu(cmd->no_of_ssids) * sizeof(struct nlo_configured_parameters);
+
+ /* copy channel info */
+ cmd->num_of_channels = __cpu_to_le32(min_t(u8,
+ pno->a_networks[0].channel_count,
+ WMI_NLO_MAX_CHAN));
+
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_UINT32);
+ tlv->len = __cpu_to_le16(__le32_to_cpu(cmd->num_of_channels) *
+ sizeof(u_int32_t));
+ ptr += sizeof(*tlv);
+
+ channel_list = (__le32 *)ptr;
+ for (i = 0; i < __le32_to_cpu(cmd->num_of_channels); i++)
+ channel_list[i] = __cpu_to_le32(pno->a_networks[0].channels[i]);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv start pno config vdev_id %d\n",
+ vdev_id);
+
+ return skb;
+}
+
+/* Request FW to stop ongoing PNO operation */
+static struct sk_buff *ath10k_wmi_tlv_op_gen_config_pno_stop(struct ath10k *ar,
+ u32 vdev_id)
+{
+ struct wmi_tlv_wow_nlo_config_cmd *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+ void *ptr;
+ size_t len;
+
+ len = sizeof(*tlv) + sizeof(*cmd) +
+ sizeof(*tlv) +
+ /* TLV place holder for array of structures
+ * nlo_configured_parameters(nlo_list)
+ */
+ sizeof(*tlv);
+ /* TLV place holder for array of uint32 channel_list */
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ ptr = (void *)skb->data;
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_NLO_CONFIG_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+
+ cmd->vdev_id = __cpu_to_le32(vdev_id);
+ cmd->flags = __cpu_to_le32(WMI_NLO_CONFIG_STOP);
+
+ ptr += sizeof(*tlv);
+ ptr += sizeof(*cmd);
+
+ /* nlo_configured_parameters(nlo_list) */
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT);
+ tlv->len = __cpu_to_le16(0);
+
+ ptr += sizeof(*tlv);
+
+ /* channel list */
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_UINT32);
+ tlv->len = __cpu_to_le16(0);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv stop pno config vdev_id %d\n", vdev_id);
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_config_pno(struct ath10k *ar, u32 vdev_id,
+ struct wmi_pno_scan_req *pno_scan)
+{
+ if (pno_scan->enable)
+ return ath10k_wmi_tlv_op_gen_config_pno_start(ar, vdev_id, pno_scan);
+ else
+ return ath10k_wmi_tlv_op_gen_config_pno_stop(ar, vdev_id);
+}
+
static struct sk_buff *
ath10k_wmi_tlv_op_gen_adaptive_qcs(struct ath10k *ar, bool enable)
{
@@ -3968,6 +4159,7 @@ static const struct wmi_ops wmi_tlv_ops = {
.gen_wow_host_wakeup_ind = ath10k_wmi_tlv_gen_wow_host_wakeup_ind,
.gen_wow_add_pattern = ath10k_wmi_tlv_op_gen_wow_add_pattern,
.gen_wow_del_pattern = ath10k_wmi_tlv_op_gen_wow_del_pattern,
+ .gen_wow_config_pno = ath10k_wmi_tlv_op_gen_config_pno,
.gen_update_fw_tdls_state = ath10k_wmi_tlv_op_gen_update_fw_tdls_state,
.gen_tdls_peer_update = ath10k_wmi_tlv_op_gen_tdls_peer_update,
.gen_adaptive_qcs = ath10k_wmi_tlv_op_gen_adaptive_qcs,
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
index 4f0c20c90642..92c25f51bf86 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
@@ -2146,6 +2146,260 @@ struct wmi_tlv_tdls_peer_event {
void ath10k_wmi_tlv_attach(struct ath10k *ar);
+enum wmi_nlo_auth_algorithm {
+ WMI_NLO_AUTH_ALGO_80211_OPEN = 1,
+ WMI_NLO_AUTH_ALGO_80211_SHARED_KEY = 2,
+ WMI_NLO_AUTH_ALGO_WPA = 3,
+ WMI_NLO_AUTH_ALGO_WPA_PSK = 4,
+ WMI_NLO_AUTH_ALGO_WPA_NONE = 5,
+ WMI_NLO_AUTH_ALGO_RSNA = 6,
+ WMI_NLO_AUTH_ALGO_RSNA_PSK = 7,
+};
+
+enum wmi_nlo_cipher_algorithm {
+ WMI_NLO_CIPHER_ALGO_NONE = 0x00,
+ WMI_NLO_CIPHER_ALGO_WEP40 = 0x01,
+ WMI_NLO_CIPHER_ALGO_TKIP = 0x02,
+ WMI_NLO_CIPHER_ALGO_CCMP = 0x04,
+ WMI_NLO_CIPHER_ALGO_WEP104 = 0x05,
+ WMI_NLO_CIPHER_ALGO_BIP = 0x06,
+ WMI_NLO_CIPHER_ALGO_RSN_USE_GROUP = 0x100,
+ WMI_NLO_CIPHER_ALGO_WEP = 0x101,
+};
+
+/* SSID broadcast type passed in NLO params */
+enum wmi_nlo_ssid_bcastnwtype {
+ WMI_NLO_BCAST_UNKNOWN = 0,
+ WMI_NLO_BCAST_NORMAL = 1,
+ WMI_NLO_BCAST_HIDDEN = 2,
+};
+
+#define WMI_NLO_MAX_SSIDS 16
+#define WMI_NLO_MAX_CHAN 48
+
+#define WMI_NLO_CONFIG_STOP (0x1 << 0)
+#define WMI_NLO_CONFIG_START (0x1 << 1)
+#define WMI_NLO_CONFIG_RESET (0x1 << 2)
+#define WMI_NLO_CONFIG_SLOW_SCAN (0x1 << 4)
+#define WMI_NLO_CONFIG_FAST_SCAN (0x1 << 5)
+#define WMI_NLO_CONFIG_SSID_HIDE_EN (0x1 << 6)
+
+/* This bit is used to indicate if EPNO or supplicant PNO is enabled.
+ * Only one of them can be enabled at a given time
+ */
+#define WMI_NLO_CONFIG_ENLO (0x1 << 7)
+#define WMI_NLO_CONFIG_SCAN_PASSIVE (0x1 << 8)
+#define WMI_NLO_CONFIG_ENLO_RESET (0x1 << 9)
+#define WMI_NLO_CONFIG_SPOOFED_MAC_IN_PROBE_REQ (0x1 << 10)
+#define WMI_NLO_CONFIG_RANDOM_SEQ_NO_IN_PROBE_REQ (0x1 << 11)
+#define WMI_NLO_CONFIG_ENABLE_IE_WHITELIST_IN_PROBE_REQ (0x1 << 12)
+#define WMI_NLO_CONFIG_ENABLE_CNLO_RSSI_CONFIG (0x1 << 13)
+
+/* Whether directed scan needs to be performed (for hidden SSIDs) */
+#define WMI_ENLO_FLAG_DIRECTED_SCAN 1
+
+/* Whether PNO event shall be triggered if the network is found on A band */
+#define WMI_ENLO_FLAG_A_BAND 2
+
+/* Whether PNO event shall be triggered if the network is found on G band */
+#define WMI_ENLO_FLAG_G_BAND 4
+
+/* Whether strict matching is required (i.e. firmware shall not
+ * match on the entire SSID)
+ */
+#define WMI_ENLO_FLAG_STRICT_MATCH 8
+
+/* Code for matching the beacon AUTH IE - additional codes TBD */
+/* open */
+#define WMI_ENLO_AUTH_CODE_OPEN 1
+
+/* WPA_PSK or WPA2PSK */
+#define WMI_ENLO_AUTH_CODE_PSK 2
+
+/* any EAPOL */
+#define WMI_ENLO_AUTH_CODE_EAPOL 4
+
+struct wmi_nlo_ssid_param {
+ __le32 valid;
+ struct wmi_ssid ssid;
+} __packed;
+
+struct wmi_nlo_enc_param {
+ __le32 valid;
+ __le32 enc_type;
+} __packed;
+
+struct wmi_nlo_auth_param {
+ __le32 valid;
+ __le32 auth_type;
+} __packed;
+
+struct wmi_nlo_bcast_nw_param {
+ __le32 valid;
+
+ /* If WMI_NLO_CONFIG_EPNO is not set. Supplicant PNO is enabled.
+ * The value should be true/false. Otherwise EPNO is enabled.
+ * bcast_nw_type would be used as a bit flag contains WMI_ENLO_FLAG_XXX
+ */
+ __le32 bcast_nw_type;
+} __packed;
+
+struct wmi_nlo_rssi_param {
+ __le32 valid;
+ __le32 rssi;
+} __packed;
+
+struct nlo_configured_parameters {
+ /* TLV tag and len;*/
+ __le32 tlv_header;
+ struct wmi_nlo_ssid_param ssid;
+ struct wmi_nlo_enc_param enc_type;
+ struct wmi_nlo_auth_param auth_type;
+ struct wmi_nlo_rssi_param rssi_cond;
+
+ /* indicates if the SSID is hidden or not */
+ struct wmi_nlo_bcast_nw_param bcast_nw_type;
+} __packed;
+
+/* Support channel prediction for PNO scan after scanning top_k_num channels
+ * if stationary_threshold is met.
+ */
+struct nlo_channel_prediction_cfg {
+ __le32 tlv_header;
+
+ /* Enable or disable this feature. */
+ __le32 enable;
+
+ /* Top K channels will be scanned before deciding whether to further scan
+ * or stop. Minimum value is 3 and maximum is 5.
+ */
+ __le32 top_k_num;
+
+ /* Preconfigured stationary threshold.
+ * Lesser value means more conservative. Bigger value means more aggressive.
+ * Maximum is 100 and mininum is 0.
+ */
+ __le32 stationary_threshold;
+
+ /* Periodic full channel scan in milliseconds unit.
+ * After full_scan_period_ms since last full scan, channel prediction
+ * scan is suppressed and will do full scan.
+ * This is to help detecting sudden AP power-on or -off. Value 0 means no
+ * full scan at all (not recommended).
+ */
+ __le32 full_scan_period_ms;
+} __packed;
+
+struct enlo_candidate_score_params_t {
+ __le32 tlv_header; /* TLV tag and len; */
+
+ /* minimum 5GHz RSSI for a BSSID to be considered (units = dBm) */
+ __le32 min_5ghz_rssi;
+
+ /* minimum 2.4GHz RSSI for a BSSID to be considered (units = dBm) */
+ __le32 min_24ghz_rssi;
+
+ /* the maximum score that a network can have before bonuses */
+ __le32 initial_score_max;
+
+ /* current_connection_bonus:
+ * only report when there is a network's score this much higher
+ * than the current connection
+ */
+ __le32 current_connection_bonus;
+
+ /* score bonus for all networks with the same network flag */
+ __le32 same_network_bonus;
+
+ /* score bonus for networks that are not open */
+ __le32 secure_bonus;
+
+ /* 5GHz RSSI score bonus (applied to all 5GHz networks) */
+ __le32 band_5ghz_bonus;
+} __packed;
+
+struct connected_nlo_bss_band_rssi_pref_t {
+ __le32 tlv_header; /* TLV tag and len;*/
+
+ /* band which needs to get preference over other band
+ * - see wmi_set_vdev_ie_band enum
+ */
+ __le32 band;
+
+ /* Amount of RSSI preference (in dB) that can be given to a band */
+ __le32 rssi_pref;
+} __packed;
+
+struct connected_nlo_rssi_params_t {
+ __le32 tlv_header; /* TLV tag and len;*/
+
+ /* Relative rssi threshold (in dB) by which new BSS should have
+ * better rssi than the current connected BSS.
+ */
+ __le32 relative_rssi;
+
+ /* The amount of rssi preference (in dB) that can be given
+ * to a 5G BSS over 2.4G BSS.
+ */
+ __le32 relative_rssi_5g_pref;
+} __packed;
+
+struct wmi_tlv_wow_nlo_config_cmd {
+ __le32 flags;
+ __le32 vdev_id;
+ __le32 fast_scan_max_cycles;
+ __le32 active_dwell_time;
+ __le32 passive_dwell_time; /* PDT in msecs */
+ __le32 probe_bundle_size;
+
+ /* ART = IRT */
+ __le32 rest_time;
+
+ /* Max value that can be reached after SBM */
+ __le32 max_rest_time;
+
+ /* SBM */
+ __le32 scan_backoff_multiplier;
+
+ /* SCBM */
+ __le32 fast_scan_period;
+
+ /* specific to windows */
+ __le32 slow_scan_period;
+
+ __le32 no_of_ssids;
+
+ __le32 num_of_channels;
+
+ /* NLO scan start delay time in milliseconds */
+ __le32 delay_start_time;
+
+ /** MAC Address to use in Probe Req as SA **/
+ struct wmi_mac_addr mac_addr;
+
+ /** Mask on which MAC has to be randomized **/
+ struct wmi_mac_addr mac_mask;
+
+ /** IE bitmap to use in Probe Req **/
+ __le32 ie_bitmap[8];
+
+ /** Number of vendor OUIs. In the TLV vendor_oui[] **/
+ __le32 num_vendor_oui;
+
+ /** Number of connected NLO band preferences **/
+ __le32 num_cnlo_band_pref;
+
+ /* The TLVs will follow.
+ * nlo_configured_parameters nlo_list[];
+ * A_UINT32 channel_list[num_of_channels];
+ * nlo_channel_prediction_cfg ch_prediction_cfg;
+ * enlo_candidate_score_params candidate_score_params;
+ * wmi_vendor_oui vendor_oui[num_vendor_oui];
+ * connected_nlo_rssi_params cnlo_rssi_params;
+ * connected_nlo_bss_band_rssi_pref cnlo_bss_band_rssi_pref[num_cnlo_band_pref];
+ */
+} __packed;
+
struct wmi_tlv_mgmt_tx_cmd {
__le32 vdev_id;
__le32 desc_id;
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index fd612d2905b0..25e8fa789e8d 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -1307,7 +1307,8 @@ static struct wmi_pdev_param_map wmi_10_2_4_pdev_param_map = {
.set_mcast2ucast_mode = WMI_PDEV_PARAM_UNSUPPORTED,
.set_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED,
.remove_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED,
- .peer_sta_ps_statechg_enable = WMI_PDEV_PARAM_UNSUPPORTED,
+ .peer_sta_ps_statechg_enable =
+ WMI_10X_PDEV_PARAM_PEER_STA_PS_STATECHG_ENABLE,
.igmpmld_ac_override = WMI_PDEV_PARAM_UNSUPPORTED,
.block_interbss = WMI_PDEV_PARAM_UNSUPPORTED,
.set_disable_reset_cmdid = WMI_PDEV_PARAM_UNSUPPORTED,
@@ -1869,6 +1870,12 @@ int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id)
if (ret)
dev_kfree_skb_any(skb);
+ if (ret == -EAGAIN) {
+ ath10k_warn(ar, "wmi command %d timeout, restarting hardware\n",
+ cmd_id);
+ queue_work(ar->workqueue, &ar->restart_work);
+ }
+
return ret;
}
@@ -2336,7 +2343,12 @@ static int wmi_process_mgmt_tx_comp(struct ath10k *ar, u32 desc_id,
dma_unmap_single(ar->dev, pkt_addr->paddr,
msdu->len, DMA_FROM_DEVICE);
info = IEEE80211_SKB_CB(msdu);
- info->flags |= status;
+
+ if (status)
+ info->flags &= ~IEEE80211_TX_STAT_ACK;
+ else
+ info->flags |= IEEE80211_TX_STAT_ACK;
+
ieee80211_tx_status_irqsafe(ar->hw, msdu);
ret = 0;
@@ -2476,7 +2488,8 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
status->freq, status->band, status->signal,
status->rate_idx);
- ieee80211_rx(ar->hw, skb);
+ ieee80211_rx_ni(ar->hw, skb);
+
return 0;
}
@@ -3236,18 +3249,31 @@ void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar, struct sk_buff *skb)
{
struct wmi_vdev_start_ev_arg arg = {};
int ret;
+ u32 status;
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_START_RESP_EVENTID\n");
+ ar->last_wmi_vdev_start_status = 0;
+
ret = ath10k_wmi_pull_vdev_start(ar, skb, &arg);
if (ret) {
ath10k_warn(ar, "failed to parse vdev start event: %d\n", ret);
- return;
+ ar->last_wmi_vdev_start_status = ret;
+ goto out;
}
- if (WARN_ON(__le32_to_cpu(arg.status)))
- return;
+ status = __le32_to_cpu(arg.status);
+ if (WARN_ON_ONCE(status)) {
+ ath10k_warn(ar, "vdev-start-response reports status error: %d (%s)\n",
+ status, (status == WMI_VDEV_START_CHAN_INVALID) ?
+ "chan-invalid" : "unknown");
+ /* Setup is done one way or another though, so we should still
+ * do the completion, so don't return here.
+ */
+ ar->last_wmi_vdev_start_status = -EINVAL;
+ }
+out:
complete(&ar->vdev_setup_done);
}
@@ -4774,6 +4800,13 @@ ath10k_wmi_tpc_final_get_rate(struct ath10k *ar,
}
}
+ if (pream == -1) {
+ ath10k_warn(ar, "unknown wmi tpc final index and frequency: %u, %u\n",
+ pream_idx, __le32_to_cpu(ev->chan_freq));
+ tpc = 0;
+ goto out;
+ }
+
if (pream == 4)
tpc = min_t(u8, ev->rates_array[rate_idx],
ev->max_reg_allow_pow[ch]);
@@ -5016,6 +5049,36 @@ ath10k_wmi_handle_tdls_peer_event(struct ath10k *ar, struct sk_buff *skb)
}
}
+static void
+ath10k_wmi_event_peer_sta_ps_state_chg(struct ath10k *ar, struct sk_buff *skb)
+{
+ struct wmi_peer_sta_ps_state_chg_event *ev;
+ struct ieee80211_sta *sta;
+ struct ath10k_sta *arsta;
+ u8 peer_addr[ETH_ALEN];
+
+ lockdep_assert_held(&ar->data_lock);
+
+ ev = (struct wmi_peer_sta_ps_state_chg_event *)skb->data;
+ ether_addr_copy(peer_addr, ev->peer_macaddr.addr);
+
+ rcu_read_lock();
+
+ sta = ieee80211_find_sta_by_ifaddr(ar->hw, peer_addr, NULL);
+
+ if (!sta) {
+ ath10k_warn(ar, "failed to find station entry %pM\n",
+ peer_addr);
+ goto exit;
+ }
+
+ arsta = (struct ath10k_sta *)sta->drv_priv;
+ arsta->peer_ps_state = __le32_to_cpu(ev->peer_ps_state);
+
+exit:
+ rcu_read_unlock();
+}
+
void ath10k_wmi_event_pdev_ftm_intg(struct ath10k *ar, struct sk_buff *skb)
{
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_FTM_INTG_EVENTID\n");
@@ -5449,7 +5512,8 @@ int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb)
arg.mac_addr,
__le32_to_cpu(arg.status));
- ether_addr_copy(ar->mac_addr, arg.mac_addr);
+ if (is_zero_ether_addr(ar->mac_addr))
+ ether_addr_copy(ar->mac_addr, arg.mac_addr);
complete(&ar->wmi.unified_ready);
return 0;
}
@@ -5945,6 +6009,9 @@ static void ath10k_wmi_10_2_op_rx(struct ath10k *ar, struct sk_buff *skb)
ath10k_dbg(ar, ATH10K_DBG_WMI,
"received event id %d not implemented\n", id);
break;
+ case WMI_10_2_PEER_STA_PS_STATECHG_EVENTID:
+ ath10k_wmi_event_peer_sta_ps_state_chg(ar, skb);
+ break;
default:
ath10k_warn(ar, "Unknown eventid: %d\n", id);
break;
@@ -6062,6 +6129,9 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb)
case WMI_10_4_DFS_STATUS_CHECK_EVENTID:
ath10k_wmi_event_dfs_status_check(ar, skb);
break;
+ case WMI_10_4_PEER_STA_PS_STATECHG_EVENTID:
+ ath10k_wmi_event_peer_sta_ps_state_chg(ar, skb);
+ break;
default:
ath10k_warn(ar, "Unknown eventid: %d\n", id);
break;
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index 36220258e3c7..f7badd079051 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -203,6 +203,8 @@ enum wmi_service {
WMI_SERVICE_TPC_STATS_FINAL,
WMI_SERVICE_RESET_CHIP,
WMI_SERVICE_SPOOF_MAC_SUPPORT,
+ WMI_SERVICE_TX_DATA_ACK_RSSI,
+ WMI_SERVICE_VDEV_DIFFERENT_BEACON_INTERVAL_SUPPORT,
/* keep last */
WMI_SERVICE_MAX,
@@ -350,6 +352,13 @@ enum wmi_10_4_service {
WMI_10_4_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS,
WMI_10_4_SERVICE_HOST_DFS_CHECK_SUPPORT,
WMI_10_4_SERVICE_TPC_STATS_FINAL,
+ WMI_10_4_SERVICE_CFR_CAPTURE_SUPPORT,
+ WMI_10_4_SERVICE_TX_DATA_ACK_RSSI,
+ WMI_10_4_SERVICE_CFR_CAPTURE_IND_MSG_TYPE_LEGACY,
+ WMI_10_4_SERVICE_PER_PACKET_SW_ENCRYPT,
+ WMI_10_4_SERVICE_PEER_TID_CONFIGS_SUPPORT,
+ WMI_10_4_SERVICE_VDEV_BCN_RATE_CONTROL,
+ WMI_10_4_SERVICE_VDEV_DIFFERENT_BEACON_INTERVAL_SUPPORT,
};
static inline char *wmi_service_name(int service_id)
@@ -463,6 +472,8 @@ static inline char *wmi_service_name(int service_id)
SVCSTR(WMI_SERVICE_HOST_DFS_CHECK_SUPPORT);
SVCSTR(WMI_SERVICE_TPC_STATS_FINAL);
SVCSTR(WMI_SERVICE_RESET_CHIP);
+ SVCSTR(WMI_SERVICE_TX_DATA_ACK_RSSI);
+ SVCSTR(WMI_SERVICE_VDEV_DIFFERENT_BEACON_INTERVAL_SUPPORT);
default:
return NULL;
}
@@ -771,6 +782,10 @@ static inline void wmi_10_4_svc_map(const __le32 *in, unsigned long *out,
WMI_SERVICE_HOST_DFS_CHECK_SUPPORT, len);
SVCMAP(WMI_10_4_SERVICE_TPC_STATS_FINAL,
WMI_SERVICE_TPC_STATS_FINAL, len);
+ SVCMAP(WMI_10_4_SERVICE_TX_DATA_ACK_RSSI,
+ WMI_SERVICE_TX_DATA_ACK_RSSI, len);
+ SVCMAP(WMI_10_4_SERVICE_VDEV_DIFFERENT_BEACON_INTERVAL_SUPPORT,
+ WMI_SERVICE_VDEV_DIFFERENT_BEACON_INTERVAL_SUPPORT, len);
}
#undef SVCMAP
@@ -2924,6 +2939,7 @@ enum wmi_coex_version {
* @WMI_10_4_TDLS_CONN_TRACKER_IN_HOST_MODE: TDLS connection tracker in host
* enable/disable
* @WMI_10_4_TDLS_EXPLICIT_MODE_ONLY:Explicit TDLS mode enable/disable
+ * @WMI_10_4_TX_DATA_ACK_RSSI: Enable DATA ACK RSSI if firmware is capable
*/
enum wmi_10_4_feature_mask {
WMI_10_4_LTEU_SUPPORT = BIT(0),
@@ -2939,6 +2955,7 @@ enum wmi_10_4_feature_mask {
WMI_10_4_TDLS_UAPSD_SLEEP_STA = BIT(10),
WMI_10_4_TDLS_CONN_TRACKER_IN_HOST_MODE = BIT(11),
WMI_10_4_TDLS_EXPLICIT_MODE_ONLY = BIT(12),
+ WMI_10_4_TX_DATA_ACK_RSSI = BIT(16),
};
@@ -4153,6 +4170,13 @@ enum wmi_tpc_pream_5ghz {
WMI_TPC_PREAM_5GHZ_HTCUP,
};
+#define WMI_PEER_PS_STATE_DISABLED 2
+
+struct wmi_peer_sta_ps_state_chg_event {
+ struct wmi_mac_addr peer_macaddr;
+ __le32 peer_ps_state;
+} __packed;
+
struct wmi_pdev_chanlist_update_event {
/* number of channels */
__le32 num_chan;
@@ -4958,10 +4982,15 @@ enum wmi_rate_preamble {
#define ATH10K_HW_GI(flags) (((flags) >> 5) & 0x1)
#define ATH10K_HW_RATECODE(rate, nss, preamble) \
(((preamble) << 6) | ((nss) << 4) | (rate))
+#define ATH10K_HW_AMPDU(flags) ((flags) & 0x1)
+#define ATH10K_HW_BA_FAIL(flags) (((flags) >> 1) & 0x3)
-#define VHT_MCS_NUM 10
-#define VHT_BW_NUM 4
-#define VHT_NSS_NUM 4
+#define ATH10K_VHT_MCS_NUM 10
+#define ATH10K_BW_NUM 4
+#define ATH10K_NSS_NUM 4
+#define ATH10K_LEGACY_NUM 12
+#define ATH10K_GI_NUM 2
+#define ATH10K_HT_MCS_NUM 32
/* Value to disable fixed rate setting */
#define WMI_FIXED_RATE_NONE (0xff)
@@ -6642,11 +6671,17 @@ struct wmi_ch_info_ev_arg {
__le32 rx_frame_count;
};
+/* From 10.4 firmware, not sure all have the same values. */
+enum wmi_vdev_start_status {
+ WMI_VDEV_START_OK = 0,
+ WMI_VDEV_START_CHAN_INVALID,
+};
+
struct wmi_vdev_start_ev_arg {
__le32 vdev_id;
__le32 req_id;
__le32 resp_type; /* %WMI_VDEV_RESP_ */
- __le32 status;
+ __le32 status; /* See wmi_vdev_start_status enum above */
};
struct wmi_peer_kick_ev_arg {
@@ -7033,6 +7068,63 @@ struct wmi_pdev_set_adaptive_cca_params {
__le32 cca_detect_margin;
} __packed;
+#define WMI_PNO_MAX_SCHED_SCAN_PLANS 2
+#define WMI_PNO_MAX_SCHED_SCAN_PLAN_INT 7200
+#define WMI_PNO_MAX_SCHED_SCAN_PLAN_ITRNS 100
+#define WMI_PNO_MAX_NETW_CHANNELS 26
+#define WMI_PNO_MAX_NETW_CHANNELS_EX 60
+#define WMI_PNO_MAX_SUPP_NETWORKS WLAN_SCAN_PARAMS_MAX_SSID
+#define WMI_PNO_MAX_IE_LENGTH WLAN_SCAN_PARAMS_MAX_IE_LEN
+
+/*size based of dot11 declaration without extra IEs as we will not carry those for PNO*/
+#define WMI_PNO_MAX_PB_REQ_SIZE 450
+
+#define WMI_PNO_24G_DEFAULT_CH 1
+#define WMI_PNO_5G_DEFAULT_CH 36
+
+#define WMI_ACTIVE_MAX_CHANNEL_TIME 40
+#define WMI_PASSIVE_MAX_CHANNEL_TIME 110
+
+/* SSID broadcast type */
+enum wmi_SSID_bcast_type {
+ BCAST_UNKNOWN = 0,
+ BCAST_NORMAL = 1,
+ BCAST_HIDDEN = 2,
+};
+
+struct wmi_network_type {
+ struct wmi_ssid ssid;
+ u32 authentication;
+ u32 encryption;
+ u32 bcast_nw_type;
+ u8 channel_count;
+ u16 channels[WMI_PNO_MAX_NETW_CHANNELS_EX];
+ s32 rssi_threshold;
+} __packed;
+
+struct wmi_pno_scan_req {
+ u8 enable;
+ u8 vdev_id;
+ u8 uc_networks_count;
+ struct wmi_network_type a_networks[WMI_PNO_MAX_SUPP_NETWORKS];
+ u32 fast_scan_period;
+ u32 slow_scan_period;
+ u8 fast_scan_max_cycles;
+
+ bool do_passive_scan;
+
+ u32 delay_start_time;
+ u32 active_min_time;
+ u32 active_max_time;
+ u32 passive_min_time;
+ u32 passive_max_time;
+
+ /* mac address randomization attributes */
+ u32 enable_pno_scan_randomization;
+ u8 mac_addr[ETH_ALEN];
+ u8 mac_addr_mask[ETH_ALEN];
+} __packed;
+
enum wmi_host_platform_type {
WMI_HOST_PLATFORM_HIGH_PERF,
WMI_HOST_PLATFORM_LOW_PERF,
diff --git a/drivers/net/wireless/ath/ath10k/wow.c b/drivers/net/wireless/ath/ath10k/wow.c
index a6b179f88d36..51b26b305885 100644
--- a/drivers/net/wireless/ath/ath10k/wow.c
+++ b/drivers/net/wireless/ath/ath10k/wow.c
@@ -180,6 +180,100 @@ static void ath10k_wow_convert_8023_to_80211
}
}
+static int ath10k_wmi_pno_check(struct ath10k *ar, u32 vdev_id,
+ struct cfg80211_sched_scan_request *nd_config,
+ struct wmi_pno_scan_req *pno)
+{
+ int i, j, ret = 0;
+ u8 ssid_len;
+
+ pno->enable = 1;
+ pno->vdev_id = vdev_id;
+ pno->uc_networks_count = nd_config->n_match_sets;
+
+ if (!pno->uc_networks_count ||
+ pno->uc_networks_count > WMI_PNO_MAX_SUPP_NETWORKS)
+ return -EINVAL;
+
+ if (nd_config->n_channels > WMI_PNO_MAX_NETW_CHANNELS_EX)
+ return -EINVAL;
+
+ /* Filling per profile params */
+ for (i = 0; i < pno->uc_networks_count; i++) {
+ ssid_len = nd_config->match_sets[i].ssid.ssid_len;
+
+ if (ssid_len == 0 || ssid_len > 32)
+ return -EINVAL;
+
+ pno->a_networks[i].ssid.ssid_len = __cpu_to_le32(ssid_len);
+
+ memcpy(pno->a_networks[i].ssid.ssid,
+ nd_config->match_sets[i].ssid.ssid,
+ nd_config->match_sets[i].ssid.ssid_len);
+ pno->a_networks[i].authentication = 0;
+ pno->a_networks[i].encryption = 0;
+ pno->a_networks[i].bcast_nw_type = 0;
+
+ /*Copying list of valid channel into request */
+ pno->a_networks[i].channel_count = nd_config->n_channels;
+ pno->a_networks[i].rssi_threshold = nd_config->match_sets[i].rssi_thold;
+
+ for (j = 0; j < nd_config->n_channels; j++) {
+ pno->a_networks[i].channels[j] =
+ nd_config->channels[j]->center_freq;
+ }
+ }
+
+ /* set scan to passive if no SSIDs are specified in the request */
+ if (nd_config->n_ssids == 0)
+ pno->do_passive_scan = true;
+ else
+ pno->do_passive_scan = false;
+
+ for (i = 0; i < nd_config->n_ssids; i++) {
+ j = 0;
+ while (j < pno->uc_networks_count) {
+ if (__le32_to_cpu(pno->a_networks[j].ssid.ssid_len) ==
+ nd_config->ssids[i].ssid_len &&
+ (memcmp(pno->a_networks[j].ssid.ssid,
+ nd_config->ssids[i].ssid,
+ __le32_to_cpu(pno->a_networks[j].ssid.ssid_len)) == 0)) {
+ pno->a_networks[j].bcast_nw_type = BCAST_HIDDEN;
+ break;
+ }
+ j++;
+ }
+ }
+
+ if (nd_config->n_scan_plans == 2) {
+ pno->fast_scan_period = nd_config->scan_plans[0].interval * MSEC_PER_SEC;
+ pno->fast_scan_max_cycles = nd_config->scan_plans[0].iterations;
+ pno->slow_scan_period =
+ nd_config->scan_plans[1].interval * MSEC_PER_SEC;
+ } else if (nd_config->n_scan_plans == 1) {
+ pno->fast_scan_period = nd_config->scan_plans[0].interval * MSEC_PER_SEC;
+ pno->fast_scan_max_cycles = 1;
+ pno->slow_scan_period = nd_config->scan_plans[0].interval * MSEC_PER_SEC;
+ } else {
+ ath10k_warn(ar, "Invalid number of scan plans %d !!",
+ nd_config->n_scan_plans);
+ }
+
+ if (nd_config->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
+ /* enable mac randomization */
+ pno->enable_pno_scan_randomization = 1;
+ memcpy(pno->mac_addr, nd_config->mac_addr, ETH_ALEN);
+ memcpy(pno->mac_addr_mask, nd_config->mac_addr_mask, ETH_ALEN);
+ }
+
+ pno->delay_start_time = nd_config->delay;
+
+ /* Current FW does not support min-max range for dwell time */
+ pno->active_max_time = WMI_ACTIVE_MAX_CHANNEL_TIME;
+ pno->passive_max_time = WMI_PASSIVE_MAX_CHANNEL_TIME;
+ return ret;
+}
+
static int ath10k_vif_wow_set_wakeups(struct ath10k_vif *arvif,
struct cfg80211_wowlan *wowlan)
{
@@ -213,6 +307,26 @@ static int ath10k_vif_wow_set_wakeups(struct ath10k_vif *arvif,
if (wowlan->magic_pkt)
__set_bit(WOW_MAGIC_PKT_RECVD_EVENT, &wow_mask);
+
+ if (wowlan->nd_config) {
+ struct wmi_pno_scan_req *pno;
+ int ret;
+
+ pno = kzalloc(sizeof(*pno), GFP_KERNEL);
+ if (!pno)
+ return -ENOMEM;
+
+ ar->nlo_enabled = true;
+
+ ret = ath10k_wmi_pno_check(ar, arvif->vdev_id,
+ wowlan->nd_config, pno);
+ if (!ret) {
+ ath10k_wmi_wow_config_pno(ar, arvif->vdev_id, pno);
+ __set_bit(WOW_NLO_DETECTED_EVENT, &wow_mask);
+ }
+
+ kfree(pno);
+ }
break;
default:
break;
@@ -299,6 +413,51 @@ static int ath10k_wow_set_wakeups(struct ath10k *ar,
return 0;
}
+static int ath10k_vif_wow_clean_nlo(struct ath10k_vif *arvif)
+{
+ int ret = 0;
+ struct ath10k *ar = arvif->ar;
+
+ switch (arvif->vdev_type) {
+ case WMI_VDEV_TYPE_STA:
+ if (ar->nlo_enabled) {
+ struct wmi_pno_scan_req *pno;
+
+ pno = kzalloc(sizeof(*pno), GFP_KERNEL);
+ if (!pno)
+ return -ENOMEM;
+
+ pno->enable = 0;
+ ar->nlo_enabled = false;
+ ret = ath10k_wmi_wow_config_pno(ar, arvif->vdev_id, pno);
+ kfree(pno);
+ }
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+static int ath10k_wow_nlo_cleanup(struct ath10k *ar)
+{
+ struct ath10k_vif *arvif;
+ int ret = 0;
+
+ lockdep_assert_held(&ar->conf_mutex);
+
+ list_for_each_entry(arvif, &ar->arvifs, list) {
+ ret = ath10k_vif_wow_clean_nlo(arvif);
+ if (ret) {
+ ath10k_warn(ar, "failed to clean nlo settings on vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
static int ath10k_wow_enable(struct ath10k *ar)
{
int ret;
@@ -374,6 +533,8 @@ int ath10k_wow_op_suspend(struct ieee80211_hw *hw,
goto cleanup;
}
+ ath10k_mac_wait_tx_complete(ar);
+
ret = ath10k_wow_enable(ar);
if (ret) {
ath10k_warn(ar, "failed to start wow: %d\n", ret);
@@ -434,6 +595,10 @@ int ath10k_wow_op_resume(struct ieee80211_hw *hw)
if (ret)
ath10k_warn(ar, "failed to wakeup from wow: %d\n", ret);
+ ret = ath10k_wow_nlo_cleanup(ar);
+ if (ret)
+ ath10k_warn(ar, "failed to cleanup nlo: %d\n", ret);
+
exit:
if (ret) {
switch (ar->state) {
@@ -473,6 +638,11 @@ int ath10k_wow_init(struct ath10k *ar)
ar->wow.wowlan_support.max_pkt_offset -= WOW_MAX_REDUCE;
}
+ if (test_bit(WMI_SERVICE_NLO, ar->wmi.svc_map)) {
+ ar->wow.wowlan_support.flags |= WIPHY_WOWLAN_NET_DETECT;
+ ar->wow.wowlan_support.max_nd_match_sets = WMI_PNO_MAX_SUPP_NETWORKS;
+ }
+
ar->wow.wowlan_support.n_patterns = ar->wow.max_num_patterns;
ar->hw->wiphy->wowlan = &ar->wow.wowlan_support;
diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c
index e01faf641288..94f70047d3fc 100644
--- a/drivers/net/wireless/ath/ath5k/debug.c
+++ b/drivers/net/wireless/ath/ath5k/debug.c
@@ -1028,8 +1028,6 @@ ath5k_debug_dump_bands(struct ath5k_hw *ah)
if (likely(!(ah->debug.level & ATH5K_DEBUG_DUMPBANDS)))
return;
- BUG_ON(!ah->sbands);
-
for (b = 0; b < NUM_NL80211_BANDS; b++) {
struct ieee80211_supported_band *band = &ah->sbands[b];
char bname[6];
diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c
index 58fb227a849f..54132af70094 100644
--- a/drivers/net/wireless/ath/ath6kl/init.c
+++ b/drivers/net/wireless/ath/ath6kl/init.c
@@ -710,8 +710,8 @@ static bool check_device_tree(struct ath6kl *ar)
for_each_compatible_node(node, NULL, "atheros,ath6kl") {
board_id = of_get_property(node, board_id_prop, NULL);
if (board_id == NULL) {
- ath6kl_warn("No \"%s\" property on %s node.\n",
- board_id_prop, node->name);
+ ath6kl_warn("No \"%s\" property on %pOFn node.\n",
+ board_id_prop, node);
continue;
}
snprintf(board_filename, sizeof(board_filename),
diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c
index 0c61dbaa62a4..cb59016c723b 100644
--- a/drivers/net/wireless/ath/ath6kl/main.c
+++ b/drivers/net/wireless/ath/ath6kl/main.c
@@ -638,7 +638,7 @@ void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, u8 *bssid,
memcpy(vif->bssid, bssid, sizeof(vif->bssid));
vif->bss_ch = channel;
- if ((vif->nw_type == INFRA_NETWORK)) {
+ if (vif->nw_type == INFRA_NETWORK) {
ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
vif->listen_intvl_t, 0);
ath6kl_check_ch_switch(ar, channel);
diff --git a/drivers/net/wireless/ath/ath9k/antenna.c b/drivers/net/wireless/ath/ath9k/antenna.c
index a3668433dc02..988222cea9df 100644
--- a/drivers/net/wireless/ath/ath9k/antenna.c
+++ b/drivers/net/wireless/ath/ath9k/antenna.c
@@ -755,11 +755,11 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
}
if (main_ant_conf == rx_ant_conf) {
- ANT_STAT_INC(ANT_MAIN, recv_cnt);
- ANT_LNA_INC(ANT_MAIN, rx_ant_conf);
+ ANT_STAT_INC(sc, ANT_MAIN, recv_cnt);
+ ANT_LNA_INC(sc, ANT_MAIN, rx_ant_conf);
} else {
- ANT_STAT_INC(ANT_ALT, recv_cnt);
- ANT_LNA_INC(ANT_ALT, rx_ant_conf);
+ ANT_STAT_INC(sc, ANT_ALT, recv_cnt);
+ ANT_LNA_INC(sc, ANT_ALT, rx_ant_conf);
}
/* Short scan check */
diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
index ef2dd68d3f77..11d6f975c87d 100644
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
@@ -37,10 +37,6 @@
#define AR5008_11NG_HT_SS_SHIFT 12
#define AR5008_11NG_HT_DS_SHIFT 20
-static const int firstep_table[] =
-/* level: 0 1 2 3 4 5 6 7 8 */
- { -4, -2, 0, 2, 4, 6, 8, 10, 12 }; /* lvl 0-8, default 2 */
-
/*
* register values to turn OFDM weak signal detection OFF
*/
diff --git a/drivers/net/wireless/ath/ath9k/common-debug.c b/drivers/net/wireless/ath/ath9k/common-debug.c
index 239429f10378..53ca4b063eb9 100644
--- a/drivers/net/wireless/ath/ath9k/common-debug.c
+++ b/drivers/net/wireless/ath/ath9k/common-debug.c
@@ -144,6 +144,8 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf,
RXS_ERR("BEACONS", rx_beacons);
RXS_ERR("FRAGS", rx_frags);
RXS_ERR("SPECTRAL", rx_spectral);
+ RXS_ERR("SPECTRAL SMPL GOOD", rx_spectral_sample_good);
+ RXS_ERR("SPECTRAL SMPL ERR", rx_spectral_sample_err);
RXS_ERR("CRC ERR", crc_err);
RXS_ERR("DECRYPT CRC ERR", decrypt_crc_err);
diff --git a/drivers/net/wireless/ath/ath9k/common-debug.h b/drivers/net/wireless/ath/ath9k/common-debug.h
index 3376990d3a24..2938b5b96b07 100644
--- a/drivers/net/wireless/ath/ath9k/common-debug.h
+++ b/drivers/net/wireless/ath/ath9k/common-debug.h
@@ -39,6 +39,8 @@
* @rx_beacons: No. of beacons received.
* @rx_frags: No. of rx-fragements received.
* @rx_spectral: No of spectral packets received.
+ * @rx_spectral_sample_good: No. of good spectral samples
+ * @rx_spectral_sample_err: No. of good spectral samples
*/
struct ath_rx_stats {
u32 rx_pkts_all;
@@ -58,6 +60,8 @@ struct ath_rx_stats {
u32 rx_beacons;
u32 rx_frags;
u32 rx_spectral;
+ u32 rx_spectral_sample_good;
+ u32 rx_spectral_sample_err;
};
#ifdef CONFIG_ATH9K_COMMON_DEBUG
diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c
index 440e16e641e4..6aa3ec024ffa 100644
--- a/drivers/net/wireless/ath/ath9k/common-spectral.c
+++ b/drivers/net/wireless/ath/ath9k/common-spectral.c
@@ -59,8 +59,7 @@ ath_cmn_max_idx_verify_ht20_fft(u8 *sample_end, int bytes_read)
sample = sample_end - SPECTRAL_HT20_SAMPLE_LEN + 1;
- max_index = spectral_max_index(mag_info->all_bins,
- SPECTRAL_HT20_NUM_BINS);
+ max_index = spectral_max_index_ht20(mag_info->all_bins);
max_magnitude = spectral_max_magnitude(mag_info->all_bins);
max_exp = mag_info->max_exp & 0xf;
@@ -72,7 +71,7 @@ ath_cmn_max_idx_verify_ht20_fft(u8 *sample_end, int bytes_read)
if (bytes_read < SPECTRAL_HT20_SAMPLE_LEN && max_index < 1)
return -1;
- if (sample[max_index] != (max_magnitude >> max_exp))
+ if ((sample[max_index] & 0xf8) != ((max_magnitude >> max_exp) & 0xf8))
return -1;
else
return 0;
@@ -100,12 +99,10 @@ ath_cmn_max_idx_verify_ht20_40_fft(u8 *sample_end, int bytes_read)
sample = sample_end - SPECTRAL_HT20_40_SAMPLE_LEN + 1;
lower_mag = spectral_max_magnitude(mag_info->lower_bins);
- lower_max_index = spectral_max_index(mag_info->lower_bins,
- SPECTRAL_HT20_40_NUM_BINS);
+ lower_max_index = spectral_max_index_ht40(mag_info->lower_bins);
upper_mag = spectral_max_magnitude(mag_info->upper_bins);
- upper_max_index = spectral_max_index(mag_info->upper_bins,
- SPECTRAL_HT20_40_NUM_BINS);
+ upper_max_index = spectral_max_index_ht40(mag_info->upper_bins);
max_exp = mag_info->max_exp & 0xf;
@@ -117,19 +114,10 @@ ath_cmn_max_idx_verify_ht20_40_fft(u8 *sample_end, int bytes_read)
((upper_max_index < 1) || (lower_max_index < 1)))
return -1;
- /* Some time hardware messes up the index and adds
- * the index of the middle point (dc_pos). Try to fix it.
- */
- if ((upper_max_index - dc_pos > 0) &&
- (sample[upper_max_index] == (upper_mag >> max_exp)))
- upper_max_index -= dc_pos;
-
- if ((lower_max_index - dc_pos > 0) &&
- (sample[lower_max_index - dc_pos] == (lower_mag >> max_exp)))
- lower_max_index -= dc_pos;
-
- if ((sample[upper_max_index + dc_pos] != (upper_mag >> max_exp)) ||
- (sample[lower_max_index] != (lower_mag >> max_exp)))
+ if (((sample[upper_max_index + dc_pos] & 0xf8) !=
+ ((upper_mag >> max_exp) & 0xf8)) ||
+ ((sample[lower_max_index] & 0xf8) !=
+ ((lower_mag >> max_exp) & 0xf8)))
return -1;
else
return 0;
@@ -169,8 +157,7 @@ ath_cmn_process_ht20_fft(struct ath_rx_status *rs,
magnitude = spectral_max_magnitude(mag_info->all_bins);
fft_sample_20.max_magnitude = __cpu_to_be16(magnitude);
- max_index = spectral_max_index(mag_info->all_bins,
- SPECTRAL_HT20_NUM_BINS);
+ max_index = spectral_max_index_ht20(mag_info->all_bins);
fft_sample_20.max_index = max_index;
bitmap_w = spectral_bitmap_weight(mag_info->all_bins);
@@ -188,7 +175,8 @@ ath_cmn_process_ht20_fft(struct ath_rx_status *rs,
magnitude >> max_exp,
max_index);
- if (fft_sample_20.data[max_index] != (magnitude >> max_exp)) {
+ if ((fft_sample_20.data[max_index] & 0xf8) !=
+ ((magnitude >> max_exp) & 0xf8)) {
ath_dbg(common, SPECTRAL_SCAN, "Magnitude mismatch !\n");
ret = -1;
}
@@ -302,12 +290,10 @@ ath_cmn_process_ht20_40_fft(struct ath_rx_status *rs,
upper_mag = spectral_max_magnitude(mag_info->upper_bins);
fft_sample_40.upper_max_magnitude = __cpu_to_be16(upper_mag);
- lower_max_index = spectral_max_index(mag_info->lower_bins,
- SPECTRAL_HT20_40_NUM_BINS);
+ lower_max_index = spectral_max_index_ht40(mag_info->lower_bins);
fft_sample_40.lower_max_index = lower_max_index;
- upper_max_index = spectral_max_index(mag_info->upper_bins,
- SPECTRAL_HT20_40_NUM_BINS);
+ upper_max_index = spectral_max_index_ht40(mag_info->upper_bins);
fft_sample_40.upper_max_index = upper_max_index;
lower_bitmap_w = spectral_bitmap_weight(mag_info->lower_bins);
@@ -331,29 +317,13 @@ ath_cmn_process_ht20_40_fft(struct ath_rx_status *rs,
upper_mag >> max_exp,
upper_max_index);
- /* Some time hardware messes up the index and adds
- * the index of the middle point (dc_pos). Try to fix it.
- */
- if ((upper_max_index - dc_pos > 0) &&
- (fft_sample_40.data[upper_max_index] == (upper_mag >> max_exp))) {
- upper_max_index -= dc_pos;
- fft_sample_40.upper_max_index = upper_max_index;
- }
-
- if ((lower_max_index - dc_pos > 0) &&
- (fft_sample_40.data[lower_max_index - dc_pos] ==
- (lower_mag >> max_exp))) {
- lower_max_index -= dc_pos;
- fft_sample_40.lower_max_index = lower_max_index;
- }
-
/* Check if we got the expected magnitude values at
* the expected bins
*/
- if ((fft_sample_40.data[upper_max_index + dc_pos]
- != (upper_mag >> max_exp)) ||
- (fft_sample_40.data[lower_max_index]
- != (lower_mag >> max_exp))) {
+ if (((fft_sample_40.data[upper_max_index + dc_pos] & 0xf8)
+ != ((upper_mag >> max_exp) & 0xf8)) ||
+ ((fft_sample_40.data[lower_max_index] & 0xf8)
+ != ((lower_mag >> max_exp) & 0xf8))) {
ath_dbg(common, SPECTRAL_SCAN, "Magnitude mismatch !\n");
ret = -1;
}
@@ -411,7 +381,7 @@ ath_cmn_process_ht20_40_fft(struct ath_rx_status *rs,
ath_dbg(common, SPECTRAL_SCAN,
"Calculated new upper max 0x%X at %i\n",
- tmp_mag, i);
+ tmp_mag, fft_sample_40.upper_max_index);
} else
for (i = dc_pos; i < SPECTRAL_HT20_40_NUM_BINS; i++) {
if (fft_sample_40.data[i] == (upper_mag >> max_exp))
@@ -501,6 +471,7 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h
u8 sample_buf[SPECTRAL_SAMPLE_MAX_LEN] = {0};
struct ath_hw *ah = spec_priv->ah;
struct ath_common *common = ath9k_hw_common(spec_priv->ah);
+ struct ath_softc *sc = (struct ath_softc *)common->priv;
u8 num_bins, *vdata = (u8 *)hdr;
struct ath_radar_info *radar_info;
int len = rs->rs_datalen;
@@ -649,8 +620,13 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h
sample_buf, sample_len,
sample_bytes);
- fft_handler(rs, spec_priv, sample_buf,
- tsf, freq, chan_type);
+ ret = fft_handler(rs, spec_priv, sample_buf,
+ tsf, freq, chan_type);
+
+ if (ret == 0)
+ RX_STAT_INC(sc, rx_spectral_sample_good);
+ else
+ RX_STAT_INC(sc, rx_spectral_sample_err);
memset(sample_buf, 0, SPECTRAL_SAMPLE_MAX_LEN);
@@ -665,6 +641,11 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h
ret = fft_handler(rs, spec_priv, sample_start,
tsf, freq, chan_type);
+ if (ret == 0)
+ RX_STAT_INC(sc, rx_spectral_sample_good);
+ else
+ RX_STAT_INC(sc, rx_spectral_sample_err);
+
/* Mix the received bins to the /dev/random
* pool
*/
@@ -675,7 +656,7 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h
* loop.
*/
if (len <= fft_len + 2)
- break;
+ return 1;
sample_start = &vdata[i + 1];
diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.h b/drivers/net/wireless/ath/ath9k/common-spectral.h
index 303ab470ce34..011d8ab8b974 100644
--- a/drivers/net/wireless/ath/ath9k/common-spectral.h
+++ b/drivers/net/wireless/ath/ath9k/common-spectral.h
@@ -145,6 +145,23 @@ static inline u8 spectral_max_index(u8 *bins, int num_bins)
return m;
}
+static inline u8 spectral_max_index_ht40(u8 *bins)
+{
+ u8 idx;
+
+ idx = spectral_max_index(bins, SPECTRAL_HT20_40_NUM_BINS);
+
+ /* positive values and zero are starting at the beginning
+ * of the data field.
+ */
+ return idx % (SPECTRAL_HT20_40_NUM_BINS / 2);
+}
+
+static inline u8 spectral_max_index_ht20(u8 *bins)
+{
+ return spectral_max_index(bins, SPECTRAL_HT20_NUM_BINS);
+}
+
/* return the bitmap weight from the all/upper/lower bins */
static inline u8 spectral_bitmap_weight(u8 *bins)
{
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 0a6eb8a8c1ed..4399e9ad058f 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -785,35 +785,35 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf,
{
int qnum = txq->axq_qnum;
- TX_STAT_INC(qnum, tx_pkts_all);
+ TX_STAT_INC(sc, qnum, tx_pkts_all);
sc->debug.stats.txstats[qnum].tx_bytes_all += bf->bf_mpdu->len;
if (bf_isampdu(bf)) {
if (flags & ATH_TX_ERROR)
- TX_STAT_INC(qnum, a_xretries);
+ TX_STAT_INC(sc, qnum, a_xretries);
else
- TX_STAT_INC(qnum, a_completed);
+ TX_STAT_INC(sc, qnum, a_completed);
} else {
if (ts->ts_status & ATH9K_TXERR_XRETRY)
- TX_STAT_INC(qnum, xretries);
+ TX_STAT_INC(sc, qnum, xretries);
else
- TX_STAT_INC(qnum, completed);
+ TX_STAT_INC(sc, qnum, completed);
}
if (ts->ts_status & ATH9K_TXERR_FILT)
- TX_STAT_INC(qnum, txerr_filtered);
+ TX_STAT_INC(sc, qnum, txerr_filtered);
if (ts->ts_status & ATH9K_TXERR_FIFO)
- TX_STAT_INC(qnum, fifo_underrun);
+ TX_STAT_INC(sc, qnum, fifo_underrun);
if (ts->ts_status & ATH9K_TXERR_XTXOP)
- TX_STAT_INC(qnum, xtxop);
+ TX_STAT_INC(sc, qnum, xtxop);
if (ts->ts_status & ATH9K_TXERR_TIMER_EXPIRED)
- TX_STAT_INC(qnum, timer_exp);
+ TX_STAT_INC(sc, qnum, timer_exp);
if (ts->ts_flags & ATH9K_TX_DESC_CFG_ERR)
- TX_STAT_INC(qnum, desc_cfg_err);
+ TX_STAT_INC(sc, qnum, desc_cfg_err);
if (ts->ts_flags & ATH9K_TX_DATA_UNDERRUN)
- TX_STAT_INC(qnum, data_underrun);
+ TX_STAT_INC(sc, qnum, data_underrun);
if (ts->ts_flags & ATH9K_TX_DELIM_UNDERRUN)
- TX_STAT_INC(qnum, delim_underrun);
+ TX_STAT_INC(sc, qnum, delim_underrun);
}
void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs)
@@ -990,19 +990,6 @@ static int read_file_dump_nfcal(struct seq_file *file, void *data)
return 0;
}
-static int open_file_dump_nfcal(struct inode *inode, struct file *f)
-{
- return single_open(f, read_file_dump_nfcal, inode->i_private);
-}
-
-static const struct file_operations fops_dump_nfcal = {
- .read = seq_read,
- .open = open_file_dump_nfcal,
- .owner = THIS_MODULE,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
static ssize_t read_file_btcoex(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index 249f8141cd00..79607db14387 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -25,17 +25,17 @@ struct ath_buf;
struct fft_sample_tlv;
#ifdef CONFIG_ATH9K_DEBUGFS
-#define TX_STAT_INC(q, c) sc->debug.stats.txstats[q].c++
-#define RX_STAT_INC(c) (sc->debug.stats.rxstats.c++)
-#define RESET_STAT_INC(sc, type) sc->debug.stats.reset[type]++
-#define ANT_STAT_INC(i, c) sc->debug.stats.ant_stats[i].c++
-#define ANT_LNA_INC(i, c) sc->debug.stats.ant_stats[i].lna_recv_cnt[c]++;
+#define TX_STAT_INC(sc, q, c) do { (sc)->debug.stats.txstats[q].c++; } while (0)
+#define RX_STAT_INC(sc, c) do { (sc)->debug.stats.rxstats.c++; } while (0)
+#define RESET_STAT_INC(sc, type) do { (sc)->debug.stats.reset[type]++; } while (0)
+#define ANT_STAT_INC(sc, i, c) do { (sc)->debug.stats.ant_stats[i].c++; } while (0)
+#define ANT_LNA_INC(sc, i, c) do { (sc)->debug.stats.ant_stats[i].lna_recv_cnt[c]++; } while (0)
#else
-#define TX_STAT_INC(q, c) do { } while (0)
-#define RX_STAT_INC(c)
-#define RESET_STAT_INC(sc, type) do { } while (0)
-#define ANT_STAT_INC(i, c) do { } while (0)
-#define ANT_LNA_INC(i, c) do { } while (0)
+#define TX_STAT_INC(sc, q, c) do { (void)(sc); } while (0)
+#define RX_STAT_INC(sc, c) do { (void)(sc); } while (0)
+#define RESET_STAT_INC(sc, type) do { (void)(sc); } while (0)
+#define ANT_STAT_INC(sc, i, c) do { (void)(sc); } while (0)
+#define ANT_LNA_INC(sc, i, c) do { (void)(sc); } while (0)
#endif
enum ath_reset_type {
diff --git a/drivers/net/wireless/ath/ath9k/debug_sta.c b/drivers/net/wireless/ath/ath9k/debug_sta.c
index a6f45f1bb5bb..e8fcd3e1c470 100644
--- a/drivers/net/wireless/ath/ath9k/debug_sta.c
+++ b/drivers/net/wireless/ath/ath9k/debug_sta.c
@@ -116,7 +116,7 @@ void ath_debug_rate_stats(struct ath_softc *sc,
if (rxs->rate_idx >= ARRAY_SIZE(rstats->ht_stats))
goto exit;
- if ((rxs->bw == RATE_INFO_BW_40))
+ if (rxs->bw == RATE_INFO_BW_40)
rstats->ht_stats[rxs->rate_idx].ht40_cnt++;
else
rstats->ht_stats[rxs->rate_idx].ht20_cnt++;
@@ -286,9 +286,25 @@ static ssize_t read_airtime(struct file *file, char __user *user_buf,
return retval;
}
+static ssize_t
+write_airtime_reset_stub(struct file *file, const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct ath_node *an = file->private_data;
+ struct ath_airtime_stats *astats;
+ int i;
+
+ astats = &an->airtime_stats;
+ astats->rx_airtime = 0;
+ astats->tx_airtime = 0;
+ for (i = 0; i < 4; i++)
+ an->airtime_deficit[i] = ATH_AIRTIME_QUANTUM;
+ return count;
+}
static const struct file_operations fops_airtime = {
.read = read_airtime,
+ .write = write_airtime_reset_stub,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
@@ -304,5 +320,5 @@ void ath9k_sta_add_debugfs(struct ieee80211_hw *hw,
debugfs_create_file("node_aggr", 0444, dir, an, &fops_node_aggr);
debugfs_create_file("node_recv", 0444, dir, an, &fops_node_recv);
- debugfs_create_file("airtime", 0444, dir, an, &fops_airtime);
+ debugfs_create_file("airtime", 0644, dir, an, &fops_airtime);
}
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 1049773378f2..1e3b5f4a4cf9 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -809,7 +809,7 @@ static void ath9k_tx(struct ieee80211_hw *hw,
if (ath_tx_start(hw, skb, &txctl) != 0) {
ath_dbg(common, XMIT, "TX failed\n");
- TX_STAT_INC(txctl.txq->axq_qnum, txfailed);
+ TX_STAT_INC(sc, txctl.txq->axq_qnum, txfailed);
goto exit;
}
@@ -1251,8 +1251,6 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
struct ath_vif *avp = (void *)vif->drv_priv;
struct ath_node *an = &avp->mcast_node;
- mutex_lock(&sc->mutex);
-
if (IS_ENABLED(CONFIG_ATH9K_TX99)) {
if (sc->cur_chan->nvifs >= 1) {
mutex_unlock(&sc->mutex);
@@ -1261,6 +1259,8 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
sc->tx99_vif = vif;
}
+ mutex_lock(&sc->mutex);
+
ath_dbg(common, CONFIG, "Attach a VIF of type: %d\n", vif->type);
sc->cur_chan->nvifs++;
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index a8ac42c96d71..30d1bd832d90 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -829,7 +829,7 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
* Discard zero-length packets and packets smaller than an ACK
*/
if (rx_stats->rs_datalen < 10) {
- RX_STAT_INC(rx_len_err);
+ RX_STAT_INC(sc, rx_len_err);
goto corrupt;
}
@@ -839,7 +839,7 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
* those frames.
*/
if (rx_stats->rs_datalen > (common->rx_bufsize - ah->caps.rx_status_len)) {
- RX_STAT_INC(rx_len_err);
+ RX_STAT_INC(sc, rx_len_err);
goto corrupt;
}
@@ -880,7 +880,7 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
} else if (sc->spec_priv.spectral_mode != SPECTRAL_DISABLED &&
ath_cmn_process_fft(&sc->spec_priv, hdr, rx_stats,
rx_status->mactime)) {
- RX_STAT_INC(rx_spectral);
+ RX_STAT_INC(sc, rx_spectral);
}
return -EINVAL;
}
@@ -898,7 +898,7 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
spin_unlock_bh(&sc->chan_lock);
if (ath_is_mybeacon(common, hdr)) {
- RX_STAT_INC(rx_beacons);
+ RX_STAT_INC(sc, rx_beacons);
rx_stats->is_mybeacon = true;
}
@@ -915,7 +915,7 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
*/
ath_dbg(common, ANY, "unsupported hw bitrate detected 0x%02x using 1 Mbit\n",
rx_stats->rs_rate);
- RX_STAT_INC(rx_rate_err);
+ RX_STAT_INC(sc, rx_rate_err);
return -EINVAL;
}
@@ -1136,7 +1136,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
* skb and put it at the tail of the sc->rx.rxbuf list for
* processing. */
if (!requeue_skb) {
- RX_STAT_INC(rx_oom_err);
+ RX_STAT_INC(sc, rx_oom_err);
goto requeue_drop_frag;
}
@@ -1164,7 +1164,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
rxs, decrypt_error);
if (rs.rs_more) {
- RX_STAT_INC(rx_frags);
+ RX_STAT_INC(sc, rx_frags);
/*
* rs_more indicates chained descriptors which can be
* used to link buffers together for a sort of
@@ -1174,7 +1174,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
/* too many fragments - cannot handle frame */
dev_kfree_skb_any(sc->rx.frag);
dev_kfree_skb_any(skb);
- RX_STAT_INC(rx_too_many_frags_err);
+ RX_STAT_INC(sc, rx_too_many_frags_err);
skb = NULL;
}
sc->rx.frag = skb;
@@ -1186,7 +1186,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
if (pskb_expand_head(hdr_skb, 0, space, GFP_ATOMIC) < 0) {
dev_kfree_skb(skb);
- RX_STAT_INC(rx_oom_err);
+ RX_STAT_INC(sc, rx_oom_err);
goto requeue_drop_frag;
}
diff --git a/drivers/net/wireless/ath/ath9k/tx99.c b/drivers/net/wireless/ath/ath9k/tx99.c
index ce50d8f5835e..95544ce05acf 100644
--- a/drivers/net/wireless/ath/ath9k/tx99.c
+++ b/drivers/net/wireless/ath/ath9k/tx99.c
@@ -56,11 +56,6 @@ static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc)
struct sk_buff *skb;
struct ath_vif *avp;
- if (!sc->tx99_vif)
- return NULL;
-
- avp = (struct ath_vif *)sc->tx99_vif->drv_priv;
-
skb = alloc_skb(len, GFP_KERNEL);
if (!skb)
return NULL;
@@ -77,7 +72,10 @@ static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc)
memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN);
memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);
- hdr->seq_ctrl |= cpu_to_le16(avp->seq_no);
+ if (sc->tx99_vif) {
+ avp = (struct ath_vif *) sc->tx99_vif->drv_priv;
+ hdr->seq_ctrl |= cpu_to_le16(avp->seq_no);
+ }
tx_info = IEEE80211_SKB_CB(skb);
memset(tx_info, 0, sizeof(*tx_info));
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 43b6c8508e49..25b3fc82d4ac 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -391,7 +391,7 @@ static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq,
struct ieee80211_hdr *hdr;
int prev = fi->retries;
- TX_STAT_INC(txq->axq_qnum, a_retries);
+ TX_STAT_INC(sc, txq->axq_qnum, a_retries);
fi->retries += count;
if (prev > 0)
@@ -1105,7 +1105,7 @@ finish:
al = get_frame_info(bf->bf_mpdu)->framelen;
bf->bf_state.bf_type = BUF_AMPDU;
} else {
- TX_STAT_INC(txq->axq_qnum, a_aggr);
+ TX_STAT_INC(sc, txq->axq_qnum, a_aggr);
}
return al;
@@ -1727,7 +1727,7 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
bf_tail = bf;
nframes--;
sent++;
- TX_STAT_INC(txq->axq_qnum, a_queued_hw);
+ TX_STAT_INC(sc, txq->axq_qnum, a_queued_hw);
if (an->sta && skb_queue_empty(&tid->retry_q))
ieee80211_sta_set_buffered(an->sta, i, false);
@@ -2110,14 +2110,14 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
}
if (puttxbuf) {
- TX_STAT_INC(txq->axq_qnum, puttxbuf);
+ TX_STAT_INC(sc, txq->axq_qnum, puttxbuf);
ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
ath_dbg(common, XMIT, "TXDP[%u] = %llx (%p)\n",
txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
}
if (!edma || sc->tx99_state) {
- TX_STAT_INC(txq->axq_qnum, txstart);
+ TX_STAT_INC(sc, txq->axq_qnum, txstart);
ath9k_hw_txstart(ah, txq->axq_qnum);
}
@@ -2154,7 +2154,7 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
bf->bf_lastbf = bf;
ath_tx_fill_desc(sc, bf, txq, fi->framelen);
ath_tx_txqaddbuf(sc, txq, &bf_head, false);
- TX_STAT_INC(txq->axq_qnum, queued);
+ TX_STAT_INC(sc, txq->axq_qnum, queued);
}
static void setup_frame_info(struct ieee80211_hw *hw,
@@ -2486,7 +2486,7 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
ath_txq_lock(sc, txctl.txq);
ath_tx_fill_desc(sc, bf, txctl.txq, 0);
ath_tx_txqaddbuf(sc, txctl.txq, &bf_q, false);
- TX_STAT_INC(txctl.txq->axq_qnum, queued);
+ TX_STAT_INC(sc, txctl.txq->axq_qnum, queued);
ath_txq_unlock(sc, txctl.txq);
}
@@ -2699,7 +2699,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
if (status == -EINPROGRESS)
break;
- TX_STAT_INC(txq->axq_qnum, txprocdesc);
+ TX_STAT_INC(sc, txq->axq_qnum, txprocdesc);
/*
* Remove ath_buf's of the same transmit unit from txq,
@@ -2778,7 +2778,7 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
ath_txq_lock(sc, txq);
- TX_STAT_INC(txq->axq_qnum, txprocdesc);
+ TX_STAT_INC(sc, txq->axq_qnum, txprocdesc);
fifo_list = &txq->txq_fifo[txq->txq_tailidx];
if (list_empty(fifo_list)) {
diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c
index 0cb5b58925dc..8c75651ede6c 100644
--- a/drivers/net/wireless/ath/carl9170/tx.c
+++ b/drivers/net/wireless/ath/carl9170/tx.c
@@ -246,8 +246,8 @@ static void carl9170_release_dev_space(struct ar9170 *ar, struct sk_buff *skb)
* of available memory blocks, so the number can
* never execeed the mem_blocks count.
*/
- if (unlikely(WARN_ON_ONCE(cookie == 0) ||
- WARN_ON_ONCE(cookie > ar->fw.mem_blocks)))
+ if (WARN_ON_ONCE(cookie == 0) ||
+ WARN_ON_ONCE(cookie > ar->fw.mem_blocks))
return;
atomic_add(DIV_ROUND_UP(skb->len, ar->fw.mem_block_size),
diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c
index 06cfe8d311f3..5ab3e31c9ffa 100644
--- a/drivers/net/wireless/ath/wcn36xx/dxe.c
+++ b/drivers/net/wireless/ath/wcn36xx/dxe.c
@@ -174,13 +174,12 @@ static int wcn36xx_dxe_init_descs(struct device *dev, struct wcn36xx_dxe_ch *wcn
int i;
size = wcn_ch->desc_num * sizeof(struct wcn36xx_dxe_desc);
- wcn_ch->cpu_addr = dma_alloc_coherent(dev, size, &wcn_ch->dma_addr,
- GFP_KERNEL);
+ wcn_ch->cpu_addr = dma_zalloc_coherent(dev, size,
+ &wcn_ch->dma_addr,
+ GFP_KERNEL);
if (!wcn_ch->cpu_addr)
return -ENOMEM;
- memset(wcn_ch->cpu_addr, 0, size);
-
cur_dxe = (struct wcn36xx_dxe_desc *)wcn_ch->cpu_addr;
cur_ctl = wcn_ch->head_blk_ctl;
@@ -628,13 +627,13 @@ int wcn36xx_dxe_allocate_mem_pools(struct wcn36xx *wcn)
16 - (WCN36XX_BD_CHUNK_SIZE % 8);
s = wcn->mgmt_mem_pool.chunk_size * WCN36XX_DXE_CH_DESC_NUMB_TX_H;
- cpu_addr = dma_alloc_coherent(wcn->dev, s, &wcn->mgmt_mem_pool.phy_addr,
- GFP_KERNEL);
+ cpu_addr = dma_zalloc_coherent(wcn->dev, s,
+ &wcn->mgmt_mem_pool.phy_addr,
+ GFP_KERNEL);
if (!cpu_addr)
goto out_err;
wcn->mgmt_mem_pool.virt_addr = cpu_addr;
- memset(cpu_addr, 0, s);
/* Allocate BD headers for DATA frames */
@@ -643,13 +642,13 @@ int wcn36xx_dxe_allocate_mem_pools(struct wcn36xx *wcn)
16 - (WCN36XX_BD_CHUNK_SIZE % 8);
s = wcn->data_mem_pool.chunk_size * WCN36XX_DXE_CH_DESC_NUMB_TX_L;
- cpu_addr = dma_alloc_coherent(wcn->dev, s, &wcn->data_mem_pool.phy_addr,
- GFP_KERNEL);
+ cpu_addr = dma_zalloc_coherent(wcn->dev, s,
+ &wcn->data_mem_pool.phy_addr,
+ GFP_KERNEL);
if (!cpu_addr)
goto out_err;
wcn->data_mem_pool.virt_addr = cpu_addr;
- memset(cpu_addr, 0, s);
return 0;
diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c
index 00098f24116d..1d2d698fb779 100644
--- a/drivers/net/wireless/ath/wcn36xx/smd.c
+++ b/drivers/net/wireless/ath/wcn36xx/smd.c
@@ -792,10 +792,10 @@ static int wcn36xx_smd_process_ptt_msg_rsp(void *buf, size_t len,
rsp->header.len - sizeof(rsp->ptt_msg_resp_status));
if (rsp->header.len > 0) {
- *p_ptt_rsp_msg = kmalloc(rsp->header.len, GFP_ATOMIC);
+ *p_ptt_rsp_msg = kmemdup(rsp->ptt_msg, rsp->header.len,
+ GFP_ATOMIC);
if (!*p_ptt_rsp_msg)
return -ENOMEM;
- memcpy(*p_ptt_rsp_msg, rsp->ptt_msg, rsp->header.len);
}
return ret;
}
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index f79c337105cb..d18e81fae5f1 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -48,9 +48,29 @@ static struct ieee80211_channel wil_60ghz_channels[] = {
CHAN60G(1, 0),
CHAN60G(2, 0),
CHAN60G(3, 0),
-/* channel 4 not supported yet */
+ CHAN60G(4, 0),
};
+static int wil_num_supported_channels(struct wil6210_priv *wil)
+{
+ int num_channels = ARRAY_SIZE(wil_60ghz_channels);
+
+ if (!test_bit(WMI_FW_CAPABILITY_CHANNEL_4, wil->fw_capabilities))
+ num_channels--;
+
+ return num_channels;
+}
+
+void update_supported_bands(struct wil6210_priv *wil)
+{
+ struct wiphy *wiphy = wil_to_wiphy(wil);
+
+ wil_dbg_misc(wil, "update supported bands");
+
+ wiphy->bands[NL80211_BAND_60GHZ]->n_channels =
+ wil_num_supported_channels(wil);
+}
+
/* Vendor id to be used in vendor specific command and events
* to user space.
* NOTE: The authoritative place for definition of QCA_NL80211_VENDOR_ID,
@@ -199,7 +219,9 @@ wil_mgmt_stypes[NUM_NL80211_IFTYPES] = {
.tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
BIT(IEEE80211_STYPE_PROBE_RESP >> 4) |
BIT(IEEE80211_STYPE_ASSOC_RESP >> 4) |
- BIT(IEEE80211_STYPE_DISASSOC >> 4),
+ BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+ BIT(IEEE80211_STYPE_AUTH >> 4) |
+ BIT(IEEE80211_STYPE_REASSOC_RESP >> 4),
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
@@ -871,6 +893,26 @@ static void wil_print_crypto(struct wil6210_priv *wil,
c->control_port_no_encrypt);
}
+static const char *
+wil_get_auth_type_name(enum nl80211_auth_type auth_type)
+{
+ switch (auth_type) {
+ case NL80211_AUTHTYPE_OPEN_SYSTEM:
+ return "OPEN_SYSTEM";
+ case NL80211_AUTHTYPE_SHARED_KEY:
+ return "SHARED_KEY";
+ case NL80211_AUTHTYPE_FT:
+ return "FT";
+ case NL80211_AUTHTYPE_NETWORK_EAP:
+ return "NETWORK_EAP";
+ case NL80211_AUTHTYPE_SAE:
+ return "SAE";
+ case NL80211_AUTHTYPE_AUTOMATIC:
+ return "AUTOMATIC";
+ default:
+ return "unknown";
+ }
+}
static void wil_print_connect_params(struct wil6210_priv *wil,
struct cfg80211_connect_params *sme)
{
@@ -884,11 +926,73 @@ static void wil_print_connect_params(struct wil6210_priv *wil,
if (sme->ssid)
print_hex_dump(KERN_INFO, " SSID: ", DUMP_PREFIX_OFFSET,
16, 1, sme->ssid, sme->ssid_len, true);
+ if (sme->prev_bssid)
+ wil_info(wil, " Previous BSSID=%pM\n", sme->prev_bssid);
+ wil_info(wil, " Auth Type: %s\n",
+ wil_get_auth_type_name(sme->auth_type));
wil_info(wil, " Privacy: %s\n", sme->privacy ? "secure" : "open");
wil_info(wil, " PBSS: %d\n", sme->pbss);
wil_print_crypto(wil, &sme->crypto);
}
+static int wil_ft_connect(struct wiphy *wiphy,
+ struct net_device *ndev,
+ struct cfg80211_connect_params *sme)
+{
+ struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ struct wil6210_vif *vif = ndev_to_vif(ndev);
+ struct wmi_ft_auth_cmd auth_cmd;
+ int rc;
+
+ if (!test_bit(WMI_FW_CAPABILITY_FT_ROAMING, wil->fw_capabilities)) {
+ wil_err(wil, "FT: FW does not support FT roaming\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (!sme->prev_bssid) {
+ wil_err(wil, "FT: prev_bssid was not set\n");
+ return -EINVAL;
+ }
+
+ if (ether_addr_equal(sme->prev_bssid, sme->bssid)) {
+ wil_err(wil, "FT: can not roam to same AP\n");
+ return -EINVAL;
+ }
+
+ if (!test_bit(wil_vif_fwconnected, vif->status)) {
+ wil_err(wil, "FT: roam while not connected\n");
+ return -EINVAL;
+ }
+
+ if (vif->privacy != sme->privacy) {
+ wil_err(wil, "FT: privacy mismatch, current (%d) roam (%d)\n",
+ vif->privacy, sme->privacy);
+ return -EINVAL;
+ }
+
+ if (sme->pbss) {
+ wil_err(wil, "FT: roam is not valid for PBSS\n");
+ return -EINVAL;
+ }
+
+ memset(&auth_cmd, 0, sizeof(auth_cmd));
+ auth_cmd.channel = sme->channel->hw_value - 1;
+ ether_addr_copy(auth_cmd.bssid, sme->bssid);
+
+ wil_info(wil, "FT: roaming\n");
+
+ set_bit(wil_vif_ft_roam, vif->status);
+ rc = wmi_send(wil, WMI_FT_AUTH_CMDID, vif->mid,
+ &auth_cmd, sizeof(auth_cmd));
+ if (rc == 0)
+ mod_timer(&vif->connect_timer,
+ jiffies + msecs_to_jiffies(5000));
+ else
+ clear_bit(wil_vif_ft_roam, vif->status);
+
+ return rc;
+}
+
static int wil_cfg80211_connect(struct wiphy *wiphy,
struct net_device *ndev,
struct cfg80211_connect_params *sme)
@@ -901,14 +1005,23 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
const u8 *rsn_eid;
int ch;
int rc = 0;
+ bool is_ft_roam = false;
+ u8 network_type;
enum ieee80211_bss_type bss_type = IEEE80211_BSS_TYPE_ESS;
wil_dbg_misc(wil, "connect, mid=%d\n", vif->mid);
wil_print_connect_params(wil, sme);
- if (test_bit(wil_vif_fwconnecting, vif->status) ||
+ if (sme->auth_type == NL80211_AUTHTYPE_FT)
+ is_ft_roam = true;
+ if (sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC &&
test_bit(wil_vif_fwconnected, vif->status))
- return -EALREADY;
+ is_ft_roam = true;
+
+ if (!is_ft_roam)
+ if (test_bit(wil_vif_fwconnecting, vif->status) ||
+ test_bit(wil_vif_fwconnected, vif->status))
+ return -EALREADY;
if (sme->ie_len > WMI_MAX_IE_LEN) {
wil_err(wil, "IE too large (%td bytes)\n", sme->ie_len);
@@ -918,8 +1031,13 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
rsn_eid = sme->ie ?
cfg80211_find_ie(WLAN_EID_RSN, sme->ie, sme->ie_len) :
NULL;
- if (sme->privacy && !rsn_eid)
+ if (sme->privacy && !rsn_eid) {
wil_info(wil, "WSC connection\n");
+ if (is_ft_roam) {
+ wil_err(wil, "No WSC with FT roam\n");
+ return -EINVAL;
+ }
+ }
if (sme->pbss)
bss_type = IEEE80211_BSS_TYPE_PBSS;
@@ -941,6 +1059,45 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
vif->privacy = sme->privacy;
vif->pbss = sme->pbss;
+ rc = wmi_set_ie(vif, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie);
+ if (rc)
+ goto out;
+
+ switch (bss->capability & WLAN_CAPABILITY_DMG_TYPE_MASK) {
+ case WLAN_CAPABILITY_DMG_TYPE_AP:
+ network_type = WMI_NETTYPE_INFRA;
+ break;
+ case WLAN_CAPABILITY_DMG_TYPE_PBSS:
+ network_type = WMI_NETTYPE_P2P;
+ break;
+ default:
+ wil_err(wil, "Unsupported BSS type, capability= 0x%04x\n",
+ bss->capability);
+ rc = -EINVAL;
+ goto out;
+ }
+
+ ch = bss->channel->hw_value;
+ if (ch == 0) {
+ wil_err(wil, "BSS at unknown frequency %dMhz\n",
+ bss->channel->center_freq);
+ rc = -EOPNOTSUPP;
+ goto out;
+ }
+
+ if (is_ft_roam) {
+ if (network_type != WMI_NETTYPE_INFRA) {
+ wil_err(wil, "FT: Unsupported BSS type, capability= 0x%04x\n",
+ bss->capability);
+ rc = -EINVAL;
+ goto out;
+ }
+ rc = wil_ft_connect(wiphy, ndev, sme);
+ if (rc == 0)
+ vif->bss = bss;
+ goto out;
+ }
+
if (vif->privacy) {
/* For secure assoc, remove old keys */
rc = wmi_del_cipher_key(vif, 0, bss->bssid,
@@ -957,28 +1114,9 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
}
}
- /* WMI_SET_APPIE_CMD. ie may contain rsn info as well as other info
- * elements. Send it also in case it's empty, to erase previously set
- * ies in FW.
- */
- rc = wmi_set_ie(vif, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie);
- if (rc)
- goto out;
-
/* WMI_CONNECT_CMD */
memset(&conn, 0, sizeof(conn));
- switch (bss->capability & WLAN_CAPABILITY_DMG_TYPE_MASK) {
- case WLAN_CAPABILITY_DMG_TYPE_AP:
- conn.network_type = WMI_NETTYPE_INFRA;
- break;
- case WLAN_CAPABILITY_DMG_TYPE_PBSS:
- conn.network_type = WMI_NETTYPE_P2P;
- break;
- default:
- wil_err(wil, "Unsupported BSS type, capability= 0x%04x\n",
- bss->capability);
- goto out;
- }
+ conn.network_type = network_type;
if (vif->privacy) {
if (rsn_eid) { /* regular secure connection */
conn.dot11_auth_mode = WMI_AUTH11_SHARED;
@@ -998,14 +1136,6 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
conn.ssid_len = min_t(u8, ssid_eid[1], 32);
memcpy(conn.ssid, ssid_eid+2, conn.ssid_len);
-
- ch = bss->channel->hw_value;
- if (ch == 0) {
- wil_err(wil, "BSS at unknown frequency %dMhz\n",
- bss->channel->center_freq);
- rc = -EOPNOTSUPP;
- goto out;
- }
conn.channel = ch - 1;
ether_addr_copy(conn.bssid, bss->bssid);
@@ -1201,9 +1331,9 @@ wil_find_sta_by_key_usage(struct wil6210_priv *wil, u8 mid,
return &wil->sta[cid];
}
-static void wil_set_crypto_rx(u8 key_index, enum wmi_key_usage key_usage,
- struct wil_sta_info *cs,
- struct key_params *params)
+void wil_set_crypto_rx(u8 key_index, enum wmi_key_usage key_usage,
+ struct wil_sta_info *cs,
+ struct key_params *params)
{
struct wil_tid_crypto_rx_single *cc;
int tid;
@@ -1286,13 +1416,19 @@ static int wil_cfg80211_add_key(struct wiphy *wiphy,
params->seq_len, params->seq);
if (IS_ERR(cs)) {
- wil_err(wil, "Not connected, %pM %s[%d] PN %*phN\n",
- mac_addr, key_usage_str[key_usage], key_index,
- params->seq_len, params->seq);
- return -EINVAL;
+ /* in FT, sta info may not be available as add_key may be
+ * sent by host before FW sends WMI_CONNECT_EVENT
+ */
+ if (!test_bit(wil_vif_ft_roam, vif->status)) {
+ wil_err(wil, "Not connected, %pM %s[%d] PN %*phN\n",
+ mac_addr, key_usage_str[key_usage], key_index,
+ params->seq_len, params->seq);
+ return -EINVAL;
+ }
}
- wil_del_rx_key(key_index, key_usage, cs);
+ if (!IS_ERR(cs))
+ wil_del_rx_key(key_index, key_usage, cs);
if (params->seq && params->seq_len != IEEE80211_GCMP_PN_LEN) {
wil_err(wil,
@@ -1305,7 +1441,10 @@ static int wil_cfg80211_add_key(struct wiphy *wiphy,
rc = wmi_add_cipher_key(vif, key_index, mac_addr, params->key_len,
params->key, key_usage);
- if (!rc)
+ if (!rc && !IS_ERR(cs))
+ /* in FT set crypto will take place upon receiving
+ * WMI_RING_EN_EVENTID event
+ */
wil_set_crypto_rx(key_index, key_usage, cs, params);
return rc;
@@ -1468,21 +1607,36 @@ static void wil_print_bcon_data(struct cfg80211_beacon_data *b)
}
/* internal functions for device reset and starting AP */
-static int _wil_cfg80211_set_ies(struct wil6210_vif *vif,
- struct cfg80211_beacon_data *bcon)
+static u8 *
+_wil_cfg80211_get_proberesp_ies(const u8 *proberesp, u16 proberesp_len,
+ u16 *ies_len)
{
- int rc;
- u16 len = 0, proberesp_len = 0;
- u8 *ies = NULL, *proberesp = NULL;
+ u8 *ies = NULL;
- if (bcon->probe_resp) {
+ if (proberesp) {
struct ieee80211_mgmt *f =
- (struct ieee80211_mgmt *)bcon->probe_resp;
+ (struct ieee80211_mgmt *)proberesp;
size_t hlen = offsetof(struct ieee80211_mgmt,
u.probe_resp.variable);
- proberesp = f->u.probe_resp.variable;
- proberesp_len = bcon->probe_resp_len - hlen;
+
+ ies = f->u.probe_resp.variable;
+ if (ies_len)
+ *ies_len = proberesp_len - hlen;
}
+
+ return ies;
+}
+
+static int _wil_cfg80211_set_ies(struct wil6210_vif *vif,
+ struct cfg80211_beacon_data *bcon)
+{
+ int rc;
+ u16 len = 0, proberesp_len = 0;
+ u8 *ies = NULL, *proberesp;
+
+ proberesp = _wil_cfg80211_get_proberesp_ies(bcon->probe_resp,
+ bcon->probe_resp_len,
+ &proberesp_len);
rc = _wil_cfg80211_merge_extra_ies(proberesp,
proberesp_len,
bcon->proberesp_ies,
@@ -1526,6 +1680,9 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy,
struct wireless_dev *wdev = ndev->ieee80211_ptr;
u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype);
u8 is_go = (wdev->iftype == NL80211_IFTYPE_P2P_GO);
+ u16 proberesp_len = 0;
+ u8 *proberesp;
+ bool ft = false;
if (pbss)
wmi_nettype = WMI_NETTYPE_P2P;
@@ -1538,6 +1695,25 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy,
wil_set_recovery_state(wil, fw_recovery_idle);
+ proberesp = _wil_cfg80211_get_proberesp_ies(bcon->probe_resp,
+ bcon->probe_resp_len,
+ &proberesp_len);
+ /* check that the probe response IEs has a MDE */
+ if ((proberesp && proberesp_len > 0 &&
+ cfg80211_find_ie(WLAN_EID_MOBILITY_DOMAIN,
+ proberesp,
+ proberesp_len)))
+ ft = true;
+
+ if (ft) {
+ if (!test_bit(WMI_FW_CAPABILITY_FT_ROAMING,
+ wil->fw_capabilities)) {
+ wil_err(wil, "FW does not support FT roaming\n");
+ return -ENOTSUPP;
+ }
+ set_bit(wil_vif_ft_roam, vif->status);
+ }
+
mutex_lock(&wil->mutex);
if (!wil_has_other_active_ifaces(wil, ndev, true, false)) {
@@ -1699,6 +1875,7 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
mutex_lock(&wil->mutex);
wmi_pcp_stop(vif);
+ clear_bit(wil_vif_ft_roam, vif->status);
if (last)
__wil_down(wil);
@@ -1718,8 +1895,9 @@ static int wil_cfg80211_add_station(struct wiphy *wiphy,
struct wil6210_vif *vif = ndev_to_vif(dev);
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
- wil_dbg_misc(wil, "add station %pM aid %d mid %d\n",
- mac, params->aid, vif->mid);
+ wil_dbg_misc(wil, "add station %pM aid %d mid %d mask 0x%x set 0x%x\n",
+ mac, params->aid, vif->mid,
+ params->sta_flags_mask, params->sta_flags_set);
if (!disable_ap_sme) {
wil_err(wil, "not supported with AP SME enabled\n");
@@ -2040,6 +2218,54 @@ wil_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev,
return 0;
}
+static int
+wil_cfg80211_update_ft_ies(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_update_ft_ies_params *ftie)
+{
+ struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ struct wil6210_vif *vif = ndev_to_vif(dev);
+ struct cfg80211_bss *bss;
+ struct wmi_ft_reassoc_cmd reassoc;
+ int rc = 0;
+
+ wil_dbg_misc(wil, "update ft ies, mid=%d\n", vif->mid);
+ wil_hex_dump_misc("FT IE ", DUMP_PREFIX_OFFSET, 16, 1,
+ ftie->ie, ftie->ie_len, true);
+
+ if (!test_bit(WMI_FW_CAPABILITY_FT_ROAMING, wil->fw_capabilities)) {
+ wil_err(wil, "FW does not support FT roaming\n");
+ return -EOPNOTSUPP;
+ }
+
+ rc = wmi_update_ft_ies(vif, ftie->ie_len, ftie->ie);
+ if (rc)
+ return rc;
+
+ if (!test_bit(wil_vif_ft_roam, vif->status))
+ /* vif is not roaming */
+ return 0;
+
+ /* wil_vif_ft_roam is set. wil_cfg80211_update_ft_ies is used as
+ * a trigger for reassoc
+ */
+
+ bss = vif->bss;
+ if (!bss) {
+ wil_err(wil, "FT: bss is NULL\n");
+ return -EINVAL;
+ }
+
+ memset(&reassoc, 0, sizeof(reassoc));
+ ether_addr_copy(reassoc.bssid, bss->bssid);
+
+ rc = wmi_send(wil, WMI_FT_REASSOC_CMDID, vif->mid,
+ &reassoc, sizeof(reassoc));
+ if (rc)
+ wil_err(wil, "FT: reassoc failed (%d)\n", rc);
+
+ return rc;
+}
+
static const struct cfg80211_ops wil_cfg80211_ops = {
.add_virtual_intf = wil_cfg80211_add_iface,
.del_virtual_intf = wil_cfg80211_del_iface,
@@ -2075,6 +2301,7 @@ static const struct cfg80211_ops wil_cfg80211_ops = {
.resume = wil_cfg80211_resume,
.sched_scan_start = wil_cfg80211_sched_scan_start,
.sched_scan_stop = wil_cfg80211_sched_scan_stop,
+ .update_ft_ies = wil_cfg80211_update_ft_ies,
};
static void wil_wiphy_init(struct wiphy *wiphy)
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index 51c3330bc316..aa50813a0595 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -416,8 +416,8 @@ static int wil_debugfs_iomem_x32_get(void *data, u64 *val)
return 0;
}
-DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, wil_debugfs_iomem_x32_get,
- wil_debugfs_iomem_x32_set, "0x%08llx\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_iomem_x32, wil_debugfs_iomem_x32_get,
+ wil_debugfs_iomem_x32_set, "0x%08llx\n");
static struct dentry *wil_debugfs_create_iomem_x32(const char *name,
umode_t mode,
@@ -432,7 +432,8 @@ static struct dentry *wil_debugfs_create_iomem_x32(const char *name,
data->wil = wil;
data->offset = value;
- file = debugfs_create_file(name, mode, parent, data, &fops_iomem_x32);
+ file = debugfs_create_file_unsafe(name, mode, parent, data,
+ &fops_iomem_x32);
if (!IS_ERR_OR_NULL(file))
wil->dbg_data.iomem_data_count++;
@@ -451,14 +452,15 @@ static int wil_debugfs_ulong_get(void *data, u64 *val)
return 0;
}
-DEFINE_SIMPLE_ATTRIBUTE(wil_fops_ulong, wil_debugfs_ulong_get,
- wil_debugfs_ulong_set, "0x%llx\n");
+DEFINE_DEBUGFS_ATTRIBUTE(wil_fops_ulong, wil_debugfs_ulong_get,
+ wil_debugfs_ulong_set, "0x%llx\n");
static struct dentry *wil_debugfs_create_ulong(const char *name, umode_t mode,
struct dentry *parent,
ulong *value)
{
- return debugfs_create_file(name, mode, parent, value, &wil_fops_ulong);
+ return debugfs_create_file_unsafe(name, mode, parent, value,
+ &wil_fops_ulong);
}
/**
@@ -725,32 +727,6 @@ struct dentry *wil_debugfs_create_ioblob(const char *name,
return debugfs_create_file(name, mode, parent, wil_blob, &fops_ioblob);
}
-/*---reset---*/
-static ssize_t wil_write_file_reset(struct file *file, const char __user *buf,
- size_t len, loff_t *ppos)
-{
- struct wil6210_priv *wil = file->private_data;
- struct net_device *ndev = wil->main_ndev;
-
- /**
- * BUG:
- * this code does NOT sync device state with the rest of system
- * use with care, debug only!!!
- */
- rtnl_lock();
- dev_close(ndev);
- ndev->flags &= ~IFF_UP;
- rtnl_unlock();
- wil_reset(wil, true);
-
- return len;
-}
-
-static const struct file_operations fops_reset = {
- .write = wil_write_file_reset,
- .open = simple_open,
-};
-
/*---write channel 1..4 to rxon for it, 0 to rxoff---*/
static ssize_t wil_write_file_rxon(struct file *file, const char __user *buf,
size_t len, loff_t *ppos)
@@ -1263,6 +1239,9 @@ static int wil_rx_buff_mgmt_debugfs_show(struct seq_file *s, void *data)
int num_active;
int num_free;
+ if (!rbm->buff_arr)
+ return -EINVAL;
+
seq_printf(s, " size = %zu\n", rbm->size);
seq_printf(s, " free_list_empty_cnt = %lu\n",
rbm->free_list_empty_cnt);
@@ -1436,7 +1415,7 @@ static int wil_freq_debugfs_show(struct seq_file *s, void *data)
{
struct wil6210_priv *wil = s->private;
struct wireless_dev *wdev = wil->main_ndev->ieee80211_ptr;
- u16 freq = wdev->chandef.chan ? wdev->chandef.chan->center_freq : 0;
+ u32 freq = wdev->chandef.chan ? wdev->chandef.chan->center_freq : 0;
seq_printf(s, "Freq = %d\n", freq);
@@ -1695,6 +1674,7 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
char *status = "unknown";
u8 aid = 0;
u8 mid;
+ bool sta_connected = false;
switch (p->status) {
case wil_sta_unused:
@@ -1709,8 +1689,20 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
break;
}
mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX;
- seq_printf(s, "[%d] %pM %s MID %d AID %d\n", i, p->addr, status,
- mid, aid);
+ if (mid < wil->max_vifs) {
+ struct wil6210_vif *vif = wil->vifs[mid];
+
+ if (vif->wdev.iftype == NL80211_IFTYPE_STATION &&
+ p->status == wil_sta_connected)
+ sta_connected = true;
+ }
+ /* print roam counter only for connected stations */
+ if (sta_connected)
+ seq_printf(s, "[%d] %pM connected (roam counter %d) MID %d AID %d\n",
+ i, p->addr, p->stats.ft_roams, mid, aid);
+ else
+ seq_printf(s, "[%d] %pM %s MID %d AID %d\n", i,
+ p->addr, status, mid, aid);
if (p->status == wil_sta_connected) {
spin_lock_bh(&p->tid_rx_lock);
@@ -2451,7 +2443,6 @@ static const struct {
{"desc", 0444, &fops_txdesc},
{"bf", 0444, &fops_bf},
{"mem_val", 0644, &fops_memread},
- {"reset", 0244, &fops_reset},
{"rxon", 0244, &fops_rxon},
{"tx_mgmt", 0244, &fops_txmgmt},
{"wmi_send", 0244, &fops_wmi},
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 7debed6bec06..398900a1c29e 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -223,6 +223,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
struct net_device *ndev = vif_to_ndev(vif);
struct wireless_dev *wdev = vif_to_wdev(vif);
struct wil_sta_info *sta = &wil->sta[cid];
+ int min_ring_id = wil_get_min_tx_ring_id(wil);
might_sleep();
wil_dbg_misc(wil, "disconnect_cid: CID %d, MID %d, status %d\n",
@@ -273,7 +274,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
memset(sta->tid_crypto_rx, 0, sizeof(sta->tid_crypto_rx));
memset(&sta->group_crypto_rx, 0, sizeof(sta->group_crypto_rx));
/* release vrings */
- for (i = 0; i < ARRAY_SIZE(wil->ring_tx); i++) {
+ for (i = min_ring_id; i < ARRAY_SIZE(wil->ring_tx); i++) {
if (wil->ring2cid_tid[i][0] == cid)
wil_ring_fini_tx(wil, i);
}
@@ -360,6 +361,8 @@ static void _wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid,
vif->bss = NULL;
}
clear_bit(wil_vif_fwconnecting, vif->status);
+ clear_bit(wil_vif_ft_roam, vif->status);
+
break;
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO:
@@ -604,8 +607,10 @@ int wil_priv_init(struct wil6210_priv *wil)
wil->sta[i].mid = U8_MAX;
}
- for (i = 0; i < WIL6210_MAX_TX_RINGS; i++)
+ for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
spin_lock_init(&wil->ring_tx_data[i].lock);
+ wil->ring2cid_tid[i][0] = WIL6210_MAX_CID;
+ }
mutex_init(&wil->mutex);
mutex_init(&wil->vif_mutex);
@@ -653,8 +658,6 @@ int wil_priv_init(struct wil6210_priv *wil)
/* edma configuration can be updated via debugfs before allocation */
wil->num_rx_status_rings = WIL_DEFAULT_NUM_RX_STATUS_RINGS;
- wil->use_compressed_rx_status = true;
- wil->use_rx_hw_reordering = true;
wil->tx_status_ring_order = WIL_TX_SRING_SIZE_ORDER_DEFAULT;
/* Rx status ring size should be bigger than the number of RX buffers
@@ -1154,6 +1157,8 @@ void wil_refresh_fw_capabilities(struct wil6210_priv *wil)
wil->max_agg_wsize = WIL_MAX_AGG_WSIZE;
wil->max_ampdu_size = WIL_MAX_AMPDU_SIZE;
}
+
+ update_supported_bands(wil);
}
void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r)
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
index 89119e7facd0..c8c6613371d1 100644
--- a/drivers/net/wireless/ath/wil6210/pcie_bus.c
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -108,6 +108,7 @@ int wil_set_capabilities(struct wil6210_priv *wil)
set_bit(hw_capa_no_flash, wil->hw_capa);
wil->use_enhanced_dma_hw = true;
wil->use_rx_hw_reordering = true;
+ wil->use_compressed_rx_status = true;
wil_fw_name = ftm_mode ? WIL_FW_NAME_FTM_TALYN :
WIL_FW_NAME_TALYN;
if (wil_fw_verify_file_exists(wil, wil_fw_name))
diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c
index 3a4194779ddf..75fe9323547c 100644
--- a/drivers/net/wireless/ath/wil6210/pm.c
+++ b/drivers/net/wireless/ath/wil6210/pm.c
@@ -190,7 +190,7 @@ out:
static int wil_suspend_keep_radio_on(struct wil6210_priv *wil)
{
int rc = 0;
- unsigned long start, data_comp_to;
+ unsigned long data_comp_to;
wil_dbg_pm(wil, "suspend keep radio on\n");
@@ -232,7 +232,6 @@ static int wil_suspend_keep_radio_on(struct wil6210_priv *wil)
}
/* Wait for completion of the pending RX packets */
- start = jiffies;
data_comp_to = jiffies + msecs_to_jiffies(WIL_DATA_COMPLETION_TO_MS);
if (test_bit(wil_status_napi_en, wil->status)) {
while (!wil->txrx_ops.is_rx_idle(wil)) {
diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c
index b608aa16b4f1..983bd001b53b 100644
--- a/drivers/net/wireless/ath/wil6210/rx_reorder.c
+++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c
@@ -382,11 +382,13 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
}
/* apply */
- r = wil_tid_ampdu_rx_alloc(wil, agg_wsize, ssn);
- spin_lock_bh(&sta->tid_rx_lock);
- wil_tid_ampdu_rx_free(wil, sta->tid_rx[tid]);
- sta->tid_rx[tid] = r;
- spin_unlock_bh(&sta->tid_rx_lock);
+ if (!wil->use_rx_hw_reordering) {
+ r = wil_tid_ampdu_rx_alloc(wil, agg_wsize, ssn);
+ spin_lock_bh(&sta->tid_rx_lock);
+ wil_tid_ampdu_rx_free(wil, sta->tid_rx[tid]);
+ sta->tid_rx[tid] = r;
+ spin_unlock_bh(&sta->tid_rx_lock);
+ }
out:
return rc;
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index 6a7943e487fb..cc5f263cc965 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -77,8 +77,9 @@ bool wil_is_tx_idle(struct wil6210_priv *wil)
{
int i;
unsigned long data_comp_to;
+ int min_ring_id = wil_get_min_tx_ring_id(wil);
- for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
+ for (i = min_ring_id; i < WIL6210_MAX_TX_RINGS; i++) {
struct wil_ring *vring = &wil->ring_tx[i];
int vring_index = vring - wil->ring_tx;
struct wil_ring_tx_data *txdata =
@@ -765,7 +766,14 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
return;
}
- if (wdev->iftype == NL80211_IFTYPE_AP && !vif->ap_isolate) {
+ if (wdev->iftype == NL80211_IFTYPE_STATION) {
+ if (mcast && ether_addr_equal(eth->h_source, ndev->dev_addr)) {
+ /* mcast packet looped back to us */
+ rc = GRO_DROP;
+ dev_kfree_skb(skb);
+ goto stats;
+ }
+ } else if (wdev->iftype == NL80211_IFTYPE_AP && !vif->ap_isolate) {
if (mcast) {
/* send multicast frames both to higher layers in
* local net stack and back to the wireless medium
@@ -1051,6 +1059,88 @@ static int wil_vring_init_tx(struct wil6210_vif *vif, int id, int size,
return rc;
}
+static int wil_tx_vring_modify(struct wil6210_vif *vif, int ring_id, int cid,
+ int tid)
+{
+ struct wil6210_priv *wil = vif_to_wil(vif);
+ int rc;
+ struct wmi_vring_cfg_cmd cmd = {
+ .action = cpu_to_le32(WMI_VRING_CMD_MODIFY),
+ .vring_cfg = {
+ .tx_sw_ring = {
+ .max_mpdu_size =
+ cpu_to_le16(wil_mtu2macbuf(mtu_max)),
+ .ring_size = 0,
+ },
+ .ringid = ring_id,
+ .cidxtid = mk_cidxtid(cid, tid),
+ .encap_trans_type = WMI_VRING_ENC_TYPE_802_3,
+ .mac_ctrl = 0,
+ .to_resolution = 0,
+ .agg_max_wsize = 0,
+ .schd_params = {
+ .priority = cpu_to_le16(0),
+ .timeslot_us = cpu_to_le16(0xfff),
+ },
+ },
+ };
+ struct {
+ struct wmi_cmd_hdr wmi;
+ struct wmi_vring_cfg_done_event cmd;
+ } __packed reply = {
+ .cmd = {.status = WMI_FW_STATUS_FAILURE},
+ };
+ struct wil_ring *vring = &wil->ring_tx[ring_id];
+ struct wil_ring_tx_data *txdata = &wil->ring_tx_data[ring_id];
+
+ wil_dbg_misc(wil, "vring_modify: ring %d cid %d tid %d\n", ring_id,
+ cid, tid);
+ lockdep_assert_held(&wil->mutex);
+
+ if (!vring->va) {
+ wil_err(wil, "Tx ring [%d] not allocated\n", ring_id);
+ return -EINVAL;
+ }
+
+ if (wil->ring2cid_tid[ring_id][0] != cid ||
+ wil->ring2cid_tid[ring_id][1] != tid) {
+ wil_err(wil, "ring info does not match cid=%u tid=%u\n",
+ wil->ring2cid_tid[ring_id][0],
+ wil->ring2cid_tid[ring_id][1]);
+ }
+
+ cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa);
+
+ rc = wmi_call(wil, WMI_VRING_CFG_CMDID, vif->mid, &cmd, sizeof(cmd),
+ WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100);
+ if (rc)
+ goto fail;
+
+ if (reply.cmd.status != WMI_FW_STATUS_SUCCESS) {
+ wil_err(wil, "Tx modify failed, status 0x%02x\n",
+ reply.cmd.status);
+ rc = -EINVAL;
+ goto fail;
+ }
+
+ /* set BA aggregation window size to 0 to force a new BA with the
+ * new AP
+ */
+ txdata->agg_wsize = 0;
+ if (txdata->dot1x_open && agg_wsize >= 0)
+ wil_addba_tx_request(wil, ring_id, agg_wsize);
+
+ return 0;
+fail:
+ spin_lock_bh(&txdata->lock);
+ txdata->dot1x_open = false;
+ txdata->enabled = 0;
+ spin_unlock_bh(&txdata->lock);
+ wil->ring2cid_tid[ring_id][0] = WIL6210_MAX_CID;
+ wil->ring2cid_tid[ring_id][1] = 0;
+ return rc;
+}
+
int wil_vring_init_bcast(struct wil6210_vif *vif, int id, int size)
{
struct wil6210_priv *wil = vif_to_wil(vif);
@@ -1935,6 +2025,7 @@ static inline void __wil_update_net_queues(struct wil6210_priv *wil,
bool check_stop)
{
int i;
+ int min_ring_id = wil_get_min_tx_ring_id(wil);
if (unlikely(!vif))
return;
@@ -1967,7 +2058,7 @@ static inline void __wil_update_net_queues(struct wil6210_priv *wil,
return;
/* check wake */
- for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
+ for (i = min_ring_id; i < WIL6210_MAX_TX_RINGS; i++) {
struct wil_ring *cur_ring = &wil->ring_tx[i];
struct wil_ring_tx_data *txdata = &wil->ring_tx_data[i];
@@ -2272,6 +2363,7 @@ void wil_init_txrx_ops_legacy_dma(struct wil6210_priv *wil)
wil->txrx_ops.ring_init_bcast = wil_vring_init_bcast;
wil->txrx_ops.tx_init = wil_tx_init;
wil->txrx_ops.tx_fini = wil_tx_fini;
+ wil->txrx_ops.tx_ring_modify = wil_tx_vring_modify;
/* RX ops */
wil->txrx_ops.rx_init = wil_rx_init;
wil->txrx_ops.wmi_addba_rx_resp = wmi_addba_rx_resp;
diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.c b/drivers/net/wireless/ath/wil6210/txrx_edma.c
index bca61cb44c37..2bbae75b9a84 100644
--- a/drivers/net/wireless/ath/wil6210/txrx_edma.c
+++ b/drivers/net/wireless/ath/wil6210/txrx_edma.c
@@ -279,9 +279,6 @@ static void wil_move_all_rx_buff_to_free_list(struct wil6210_priv *wil,
u16 buff_id;
*d = *_d;
- pa = wil_rx_desc_get_addr_edma(&d->dma);
- dmalen = le16_to_cpu(d->dma.length);
- dma_unmap_single(dev, pa, dmalen, DMA_FROM_DEVICE);
/* Extract the SKB from the rx_buff management array */
buff_id = __le16_to_cpu(d->mac.buff_id);
@@ -291,10 +288,15 @@ static void wil_move_all_rx_buff_to_free_list(struct wil6210_priv *wil,
}
skb = wil->rx_buff_mgmt.buff_arr[buff_id].skb;
wil->rx_buff_mgmt.buff_arr[buff_id].skb = NULL;
- if (unlikely(!skb))
+ if (unlikely(!skb)) {
wil_err(wil, "No Rx skb at buff_id %d\n", buff_id);
- else
+ } else {
+ pa = wil_rx_desc_get_addr_edma(&d->dma);
+ dmalen = le16_to_cpu(d->dma.length);
+ dma_unmap_single(dev, pa, dmalen, DMA_FROM_DEVICE);
+
kfree_skb(skb);
+ }
/* Move the buffer from the active to the free list */
list_move(&wil->rx_buff_mgmt.buff_arr[buff_id].list,
@@ -745,6 +747,16 @@ static int wil_ring_init_tx_edma(struct wil6210_vif *vif, int ring_id,
return rc;
}
+static int wil_tx_ring_modify_edma(struct wil6210_vif *vif, int ring_id,
+ int cid, int tid)
+{
+ struct wil6210_priv *wil = vif_to_wil(vif);
+
+ wil_err(wil, "ring modify is not supported for EDMA\n");
+
+ return -EOPNOTSUPP;
+}
+
/* This function is used only for RX SW reorder */
static int wil_check_bar(struct wil6210_priv *wil, void *msg, int cid,
struct sk_buff *skb, struct wil_net_stats *stats)
@@ -906,6 +918,9 @@ again:
wil->rx_buff_mgmt.buff_arr[buff_id].skb = NULL;
if (!skb) {
wil_err(wil, "No Rx skb at buff_id %d\n", buff_id);
+ /* Move the buffer from the active list to the free list */
+ list_move(&wil->rx_buff_mgmt.buff_arr[buff_id].list,
+ &wil->rx_buff_mgmt.free);
goto again;
}
@@ -1595,6 +1610,7 @@ void wil_init_txrx_ops_edma(struct wil6210_priv *wil)
wil->txrx_ops.tx_desc_map = wil_tx_desc_map_edma;
wil->txrx_ops.tx_desc_unmap = wil_tx_desc_unmap_edma;
wil->txrx_ops.tx_ring_tso = __wil_tx_ring_tso_edma;
+ wil->txrx_ops.tx_ring_modify = wil_tx_ring_modify_edma;
/* RX ops */
wil->txrx_ops.rx_init = wil_rx_init_edma;
wil->txrx_ops.wmi_addba_rx_resp = wmi_addba_rx_resp_edma;
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 17c294b1ead1..abb82018d3b4 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -449,6 +449,15 @@ static inline void parse_cidxtid(u8 cidxtid, u8 *cid, u8 *tid)
*tid = (cidxtid >> 4) & 0xf;
}
+/**
+ * wil_cid_valid - check cid is valid
+ * @cid: CID value
+ */
+static inline bool wil_cid_valid(u8 cid)
+{
+ return cid < WIL6210_MAX_CID;
+}
+
struct wil6210_mbox_ring {
u32 base;
u16 entry_size; /* max. size of mbox entry, incl. all headers */
@@ -577,6 +586,7 @@ struct wil_net_stats {
unsigned long rx_csum_err;
u16 last_mcs_rx;
u64 rx_per_mcs[WIL_MCS_MAX + 1];
+ u32 ft_roams; /* relevant in STA mode */
};
/**
@@ -599,6 +609,8 @@ struct wil_txrx_ops {
struct wil_ctx *ctx);
int (*tx_ring_tso)(struct wil6210_priv *wil, struct wil6210_vif *vif,
struct wil_ring *ring, struct sk_buff *skb);
+ int (*tx_ring_modify)(struct wil6210_vif *vif, int ring_id,
+ int cid, int tid);
irqreturn_t (*irq_tx)(int irq, void *cookie);
/* RX ops */
int (*rx_init)(struct wil6210_priv *wil, u16 ring_size);
@@ -821,6 +833,7 @@ extern u8 led_polarity;
enum wil6210_vif_status {
wil_vif_fwconnecting,
wil_vif_fwconnected,
+ wil_vif_ft_roam,
wil_vif_status_last /* keep last */
};
@@ -1204,6 +1217,7 @@ int wmi_add_cipher_key(struct wil6210_vif *vif, u8 key_index,
int wmi_echo(struct wil6210_priv *wil);
int wmi_set_ie(struct wil6210_vif *vif, u8 type, u16 ie_len, const void *ie);
int wmi_rx_chain_add(struct wil6210_priv *wil, struct wil_ring *vring);
+int wmi_update_ft_ies(struct wil6210_vif *vif, u16 ie_len, const void *ie);
int wmi_rxon(struct wil6210_priv *wil, bool on);
int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r);
int wmi_disconnect_sta(struct wil6210_vif *vif, const u8 *mac,
@@ -1319,6 +1333,9 @@ void wil6210_unmask_irq_tx_edma(struct wil6210_priv *wil);
void wil_rx_handle(struct wil6210_priv *wil, int *quota);
void wil6210_unmask_irq_rx(struct wil6210_priv *wil);
void wil6210_unmask_irq_rx_edma(struct wil6210_priv *wil);
+void wil_set_crypto_rx(u8 key_index, enum wmi_key_usage key_usage,
+ struct wil_sta_info *cs,
+ struct key_params *params);
int wil_iftype_nl2wmi(enum nl80211_iftype type);
@@ -1370,4 +1387,6 @@ int wmi_addba_rx_resp_edma(struct wil6210_priv *wil, u8 mid, u8 cid,
u8 tid, u8 token, u16 status, bool amsdu,
u16 agg_wsize, u16 timeout);
+void update_supported_bands(struct wil6210_priv *wil);
+
#endif /* __WIL6210_H__ */
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 42c02a20ec97..4859f0e43658 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -227,6 +227,14 @@ struct blink_on_off_time led_blink_time[] = {
{WIL_LED_BLINK_ON_FAST_MS, WIL_LED_BLINK_OFF_FAST_MS},
};
+struct auth_no_hdr {
+ __le16 auth_alg;
+ __le16 auth_transaction;
+ __le16 status_code;
+ /* possibly followed by Challenge text */
+ u8 variable[0];
+} __packed;
+
u8 led_polarity = LED_POLARITY_LOW_ACTIVE;
/**
@@ -468,6 +476,12 @@ static const char *cmdid2name(u16 cmdid)
return "WMI_LINK_STATS_CMD";
case WMI_SW_TX_REQ_EXT_CMDID:
return "WMI_SW_TX_REQ_EXT_CMDID";
+ case WMI_FT_AUTH_CMDID:
+ return "WMI_FT_AUTH_CMD";
+ case WMI_FT_REASSOC_CMDID:
+ return "WMI_FT_REASSOC_CMD";
+ case WMI_UPDATE_FT_IES_CMDID:
+ return "WMI_UPDATE_FT_IES_CMD";
default:
return "Untracked CMD";
}
@@ -606,6 +620,12 @@ static const char *eventid2name(u16 eventid)
return "WMI_LINK_STATS_CONFIG_DONE_EVENT";
case WMI_LINK_STATS_EVENTID:
return "WMI_LINK_STATS_EVENT";
+ case WMI_COMMAND_NOT_SUPPORTED_EVENTID:
+ return "WMI_COMMAND_NOT_SUPPORTED_EVENT";
+ case WMI_FT_AUTH_STATUS_EVENTID:
+ return "WMI_FT_AUTH_STATUS_EVENT";
+ case WMI_FT_REASSOC_STATUS_EVENTID:
+ return "WMI_FT_REASSOC_STATUS_EVENT";
default:
return "Untracked EVENT";
}
@@ -1156,6 +1176,9 @@ static void wmi_evt_ring_en(struct wil6210_vif *vif, int id, void *d, int len)
struct wmi_ring_en_event *evt = d;
u8 vri = evt->ring_index;
struct wireless_dev *wdev = vif_to_wdev(vif);
+ struct wil_sta_info *sta;
+ u8 cid;
+ struct key_params params;
wil_dbg_wmi(wil, "Enable vring %d MID %d\n", vri, vif->mid);
@@ -1164,13 +1187,33 @@ static void wmi_evt_ring_en(struct wil6210_vif *vif, int id, void *d, int len)
return;
}
- if (wdev->iftype != NL80211_IFTYPE_AP || !disable_ap_sme)
- /* in AP mode with disable_ap_sme, this is done by
- * wil_cfg80211_change_station()
+ if (wdev->iftype != NL80211_IFTYPE_AP || !disable_ap_sme ||
+ test_bit(wil_vif_ft_roam, vif->status))
+ /* in AP mode with disable_ap_sme that is not FT,
+ * this is done by wil_cfg80211_change_station()
*/
wil->ring_tx_data[vri].dot1x_open = true;
if (vri == vif->bcast_ring) /* no BA for bcast */
return;
+
+ cid = wil->ring2cid_tid[vri][0];
+ if (!wil_cid_valid(cid)) {
+ wil_err(wil, "invalid cid %d for vring %d\n", cid, vri);
+ return;
+ }
+
+ /* In FT mode we get key but not store it as it is received
+ * before WMI_CONNECT_EVENT received from FW.
+ * wil_set_crypto_rx is called here to reset the security PN
+ */
+ sta = &wil->sta[cid];
+ if (test_bit(wil_vif_ft_roam, vif->status)) {
+ memset(&params, 0, sizeof(params));
+ wil_set_crypto_rx(0, WMI_KEY_USE_PAIRWISE, sta, &params);
+ if (wdev->iftype != NL80211_IFTYPE_AP)
+ clear_bit(wil_vif_ft_roam, vif->status);
+ }
+
if (agg_wsize >= 0)
wil_addba_tx_request(wil, vri, agg_wsize);
}
@@ -1462,6 +1505,271 @@ wmi_evt_link_stats(struct wil6210_vif *vif, int id, void *d, int len)
}
/**
+ * find cid and ringid for the station vif
+ *
+ * return error, if other interfaces are used or ring was not found
+ */
+static int wil_find_cid_ringid_sta(struct wil6210_priv *wil,
+ struct wil6210_vif *vif,
+ int *cid,
+ int *ringid)
+{
+ struct wil_ring *ring;
+ struct wil_ring_tx_data *txdata;
+ int min_ring_id = wil_get_min_tx_ring_id(wil);
+ int i;
+ u8 lcid;
+
+ if (!(vif->wdev.iftype == NL80211_IFTYPE_STATION ||
+ vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT)) {
+ wil_err(wil, "invalid interface type %d\n", vif->wdev.iftype);
+ return -EINVAL;
+ }
+
+ /* In the STA mode, it is expected to have only one ring
+ * for the AP we are connected to.
+ * find it and return the cid associated with it.
+ */
+ for (i = min_ring_id; i < WIL6210_MAX_TX_RINGS; i++) {
+ ring = &wil->ring_tx[i];
+ txdata = &wil->ring_tx_data[i];
+ if (!ring->va || !txdata->enabled || txdata->mid != vif->mid)
+ continue;
+
+ lcid = wil->ring2cid_tid[i][0];
+ if (lcid >= WIL6210_MAX_CID) /* skip BCAST */
+ continue;
+
+ wil_dbg_wmi(wil, "find sta -> ringid %d cid %d\n", i, lcid);
+ *cid = lcid;
+ *ringid = i;
+ return 0;
+ }
+
+ wil_dbg_wmi(wil, "find sta cid while no rings active?\n");
+
+ return -ENOENT;
+}
+
+static void
+wmi_evt_auth_status(struct wil6210_vif *vif, int id, void *d, int len)
+{
+ struct wil6210_priv *wil = vif_to_wil(vif);
+ struct net_device *ndev = vif_to_ndev(vif);
+ struct wmi_ft_auth_status_event *data = d;
+ int ie_len = len - offsetof(struct wmi_ft_auth_status_event, ie_info);
+ int rc, cid = 0, ringid = 0;
+ struct cfg80211_ft_event_params ft;
+ u16 d_len;
+ /* auth_alg(u16) + auth_transaction(u16) + status_code(u16) */
+ const size_t auth_ie_offset = sizeof(u16) * 3;
+ struct auth_no_hdr *auth = (struct auth_no_hdr *)data->ie_info;
+
+ /* check the status */
+ if (ie_len >= 0 && data->status != WMI_FW_STATUS_SUCCESS) {
+ wil_err(wil, "FT: auth failed. status %d\n", data->status);
+ goto fail;
+ }
+
+ if (ie_len < auth_ie_offset) {
+ wil_err(wil, "FT: auth event too short, len %d\n", len);
+ goto fail;
+ }
+
+ d_len = le16_to_cpu(data->ie_len);
+ if (d_len != ie_len) {
+ wil_err(wil,
+ "FT: auth ie length mismatch, d_len %d should be %d\n",
+ d_len, ie_len);
+ goto fail;
+ }
+
+ if (!test_bit(wil_vif_ft_roam, wil->status)) {
+ wil_err(wil, "FT: Not in roaming state\n");
+ goto fail;
+ }
+
+ if (le16_to_cpu(auth->auth_transaction) != 2) {
+ wil_err(wil, "FT: auth error. auth_transaction %d\n",
+ le16_to_cpu(auth->auth_transaction));
+ goto fail;
+ }
+
+ if (le16_to_cpu(auth->auth_alg) != WLAN_AUTH_FT) {
+ wil_err(wil, "FT: auth error. auth_alg %d\n",
+ le16_to_cpu(auth->auth_alg));
+ goto fail;
+ }
+
+ wil_dbg_wmi(wil, "FT: Auth to %pM successfully\n", data->mac_addr);
+ wil_hex_dump_wmi("FT Auth ies : ", DUMP_PREFIX_OFFSET, 16, 1,
+ data->ie_info, d_len, true);
+
+ /* find cid and ringid */
+ rc = wil_find_cid_ringid_sta(wil, vif, &cid, &ringid);
+ if (rc) {
+ wil_err(wil, "No valid cid found\n");
+ goto fail;
+ }
+
+ if (vif->privacy) {
+ /* For secure assoc, remove old keys */
+ rc = wmi_del_cipher_key(vif, 0, wil->sta[cid].addr,
+ WMI_KEY_USE_PAIRWISE);
+ if (rc) {
+ wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD(PTK) failed\n");
+ goto fail;
+ }
+ rc = wmi_del_cipher_key(vif, 0, wil->sta[cid].addr,
+ WMI_KEY_USE_RX_GROUP);
+ if (rc) {
+ wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD(GTK) failed\n");
+ goto fail;
+ }
+ }
+
+ memset(&ft, 0, sizeof(ft));
+ ft.ies = data->ie_info + auth_ie_offset;
+ ft.ies_len = d_len - auth_ie_offset;
+ ft.target_ap = data->mac_addr;
+ cfg80211_ft_event(ndev, &ft);
+
+ return;
+
+fail:
+ wil6210_disconnect(vif, NULL, WLAN_REASON_PREV_AUTH_NOT_VALID, false);
+}
+
+static void
+wmi_evt_reassoc_status(struct wil6210_vif *vif, int id, void *d, int len)
+{
+ struct wil6210_priv *wil = vif_to_wil(vif);
+ struct net_device *ndev = vif_to_ndev(vif);
+ struct wiphy *wiphy = wil_to_wiphy(wil);
+ struct wmi_ft_reassoc_status_event *data = d;
+ int ies_len = len - offsetof(struct wmi_ft_reassoc_status_event,
+ ie_info);
+ int rc = -ENOENT, cid = 0, ringid = 0;
+ int ch; /* channel number (primary) */
+ size_t assoc_req_ie_len = 0, assoc_resp_ie_len = 0;
+ u8 *assoc_req_ie = NULL, *assoc_resp_ie = NULL;
+ /* capinfo(u16) + listen_interval(u16) + current_ap mac addr + IEs */
+ const size_t assoc_req_ie_offset = sizeof(u16) * 2 + ETH_ALEN;
+ /* capinfo(u16) + status_code(u16) + associd(u16) + IEs */
+ const size_t assoc_resp_ie_offset = sizeof(u16) * 3;
+ u16 d_len;
+ int freq;
+ struct cfg80211_roam_info info;
+
+ if (ies_len < 0) {
+ wil_err(wil, "ft reassoc event too short, len %d\n", len);
+ goto fail;
+ }
+
+ wil_dbg_wmi(wil, "Reasoc Status event: status=%d, aid=%d",
+ data->status, data->aid);
+ wil_dbg_wmi(wil, " mac_addr=%pM, beacon_ie_len=%d",
+ data->mac_addr, data->beacon_ie_len);
+ wil_dbg_wmi(wil, " reassoc_req_ie_len=%d, reassoc_resp_ie_len=%d",
+ le16_to_cpu(data->reassoc_req_ie_len),
+ le16_to_cpu(data->reassoc_resp_ie_len));
+
+ d_len = le16_to_cpu(data->beacon_ie_len) +
+ le16_to_cpu(data->reassoc_req_ie_len) +
+ le16_to_cpu(data->reassoc_resp_ie_len);
+ if (d_len != ies_len) {
+ wil_err(wil,
+ "ft reassoc ie length mismatch, d_len %d should be %d\n",
+ d_len, ies_len);
+ goto fail;
+ }
+
+ /* check the status */
+ if (data->status != WMI_FW_STATUS_SUCCESS) {
+ wil_err(wil, "ft reassoc failed. status %d\n", data->status);
+ goto fail;
+ }
+
+ /* find cid and ringid */
+ rc = wil_find_cid_ringid_sta(wil, vif, &cid, &ringid);
+ if (rc) {
+ wil_err(wil, "No valid cid found\n");
+ goto fail;
+ }
+
+ ch = data->channel + 1;
+ wil_info(wil, "FT: Roam %pM channel [%d] cid %d aid %d\n",
+ data->mac_addr, ch, cid, data->aid);
+
+ wil_hex_dump_wmi("reassoc AI : ", DUMP_PREFIX_OFFSET, 16, 1,
+ data->ie_info, len - sizeof(*data), true);
+
+ /* figure out IE's */
+ if (le16_to_cpu(data->reassoc_req_ie_len) > assoc_req_ie_offset) {
+ assoc_req_ie = &data->ie_info[assoc_req_ie_offset];
+ assoc_req_ie_len = le16_to_cpu(data->reassoc_req_ie_len) -
+ assoc_req_ie_offset;
+ }
+ if (le16_to_cpu(data->reassoc_resp_ie_len) <= assoc_resp_ie_offset) {
+ wil_err(wil, "FT: reassoc resp ie len is too short, len %d\n",
+ le16_to_cpu(data->reassoc_resp_ie_len));
+ goto fail;
+ }
+
+ assoc_resp_ie = &data->ie_info[le16_to_cpu(data->reassoc_req_ie_len) +
+ assoc_resp_ie_offset];
+ assoc_resp_ie_len = le16_to_cpu(data->reassoc_resp_ie_len) -
+ assoc_resp_ie_offset;
+
+ if (test_bit(wil_status_resetting, wil->status) ||
+ !test_bit(wil_status_fwready, wil->status)) {
+ wil_err(wil, "FT: status_resetting, cancel reassoc event\n");
+ /* no need for cleanup, wil_reset will do that */
+ return;
+ }
+
+ mutex_lock(&wil->mutex);
+
+ /* ring modify to set the ring for the roamed AP settings */
+ wil_dbg_wmi(wil,
+ "ft modify tx config for connection CID %d ring %d\n",
+ cid, ringid);
+
+ rc = wil->txrx_ops.tx_ring_modify(vif, ringid, cid, 0);
+ if (rc) {
+ wil_err(wil, "modify TX for CID %d MID %d ring %d failed (%d)\n",
+ cid, vif->mid, ringid, rc);
+ mutex_unlock(&wil->mutex);
+ goto fail;
+ }
+
+ /* Update the driver STA members with the new bss */
+ wil->sta[cid].aid = data->aid;
+ wil->sta[cid].stats.ft_roams++;
+ ether_addr_copy(wil->sta[cid].addr, vif->bss->bssid);
+ mutex_unlock(&wil->mutex);
+ del_timer_sync(&vif->connect_timer);
+
+ cfg80211_ref_bss(wiphy, vif->bss);
+ freq = ieee80211_channel_to_frequency(ch, NL80211_BAND_60GHZ);
+
+ memset(&info, 0, sizeof(info));
+ info.channel = ieee80211_get_channel(wiphy, freq);
+ info.bss = vif->bss;
+ info.req_ie = assoc_req_ie;
+ info.req_ie_len = assoc_req_ie_len;
+ info.resp_ie = assoc_resp_ie;
+ info.resp_ie_len = assoc_resp_ie_len;
+ cfg80211_roamed(ndev, &info, GFP_KERNEL);
+ vif->bss = NULL;
+
+ return;
+
+fail:
+ wil6210_disconnect(vif, NULL, WLAN_REASON_PREV_AUTH_NOT_VALID, false);
+}
+
+/**
* Some events are ignored for purpose; and need not be interpreted as
* "unhandled events"
*/
@@ -1492,6 +1800,8 @@ static const struct {
{WMI_DATA_PORT_OPEN_EVENTID, wmi_evt_ignore},
{WMI_SCHED_SCAN_RESULT_EVENTID, wmi_evt_sched_scan_result},
{WMI_LINK_STATS_EVENTID, wmi_evt_link_stats},
+ {WMI_FT_AUTH_STATUS_EVENTID, wmi_evt_auth_status},
+ {WMI_FT_REASSOC_STATUS_EVENTID, wmi_evt_reassoc_status},
};
/*
@@ -2086,6 +2396,40 @@ out:
return rc;
}
+int wmi_update_ft_ies(struct wil6210_vif *vif, u16 ie_len, const void *ie)
+{
+ struct wil6210_priv *wil = vif_to_wil(vif);
+ u16 len;
+ struct wmi_update_ft_ies_cmd *cmd;
+ int rc;
+
+ if (!ie)
+ ie_len = 0;
+
+ len = sizeof(struct wmi_update_ft_ies_cmd) + ie_len;
+ if (len < ie_len) {
+ wil_err(wil, "wraparound. ie len %d\n", ie_len);
+ return -EINVAL;
+ }
+
+ cmd = kzalloc(len, GFP_KERNEL);
+ if (!cmd) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ cmd->ie_len = cpu_to_le16(ie_len);
+ memcpy(cmd->ie_info, ie, ie_len);
+ rc = wmi_send(wil, WMI_UPDATE_FT_IES_CMDID, vif->mid, cmd, len);
+ kfree(cmd);
+
+out:
+ if (rc)
+ wil_err(wil, "update ft ies failed : %d\n", rc);
+
+ return rc;
+}
+
/**
* wmi_rxon - turn radio on/off
* @on: turn on if true, off otherwise
diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h
index 139acb2caf92..b668758da994 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.h
+++ b/drivers/net/wireless/ath/wil6210/wmi.h
@@ -103,6 +103,7 @@ enum wmi_fw_capability {
WMI_FW_CAPABILITY_AMSDU = 23,
WMI_FW_CAPABILITY_RAW_MODE = 24,
WMI_FW_CAPABILITY_TX_REQ_EXT = 25,
+ WMI_FW_CAPABILITY_CHANNEL_4 = 26,
WMI_FW_CAPABILITY_MAX,
};
@@ -2369,6 +2370,7 @@ struct wmi_ft_reassoc_status_event {
__le16 beacon_ie_len;
__le16 reassoc_req_ie_len;
__le16 reassoc_resp_ie_len;
+ u8 reserved[4];
u8 ie_info[0];
} __packed;
diff --git a/drivers/net/wireless/broadcom/b43/b43.h b/drivers/net/wireless/broadcom/b43/b43.h
index b77d1a904f7e..9fc7c088a539 100644
--- a/drivers/net/wireless/broadcom/b43/b43.h
+++ b/drivers/net/wireless/broadcom/b43/b43.h
@@ -909,7 +909,7 @@ struct b43_wl {
/* Set this if we call ieee80211_register_hw() and check if we call
* ieee80211_unregister_hw(). */
- bool hw_registred;
+ bool hw_registered;
/* We can only have one operating interface (802.11 core)
* at a time. General information about this interface follows.
diff --git a/drivers/net/wireless/broadcom/b43/dma.c b/drivers/net/wireless/broadcom/b43/dma.c
index 6b0e1ec346cb..dfc4c34298d4 100644
--- a/drivers/net/wireless/broadcom/b43/dma.c
+++ b/drivers/net/wireless/broadcom/b43/dma.c
@@ -1432,7 +1432,7 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb)
goto out;
}
- if (unlikely(WARN_ON(free_slots(ring) < TX_SLOTS_PER_FRAME))) {
+ if (WARN_ON(free_slots(ring) < TX_SLOTS_PER_FRAME)) {
/* If we get here, we have a real error with the queue
* full, but queues not stopped. */
b43err(dev->wl, "DMA queue overflow\n");
@@ -1518,13 +1518,15 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
}
} else {
/* More than a single header/data pair were missed.
- * Report this error, and reset the controller to
+ * Report this error. If running with open-source
+ * firmware, then reset the controller to
* revive operation.
*/
b43dbg(dev->wl,
"Out of order TX status report on DMA ring %d. Expected %d, but got %d\n",
ring->index, firstused, slot);
- b43_controller_restart(dev, "Out of order TX");
+ if (dev->fw.opensource)
+ b43_controller_restart(dev, "Out of order TX");
return;
}
}
diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c
index b37e7391f55d..74be3c809225 100644
--- a/drivers/net/wireless/broadcom/b43/main.c
+++ b/drivers/net/wireless/broadcom/b43/main.c
@@ -2611,7 +2611,7 @@ start_ieee80211:
err = ieee80211_register_hw(wl->hw);
if (err)
goto err_one_core_detach;
- wl->hw_registred = true;
+ wl->hw_registered = true;
b43_leds_register(wl->current_dev);
/* Register HW RNG driver */
@@ -5493,13 +5493,11 @@ err_powerdown:
static void b43_one_core_detach(struct b43_bus_dev *dev)
{
struct b43_wldev *wldev;
- struct b43_wl *wl;
/* Do not cancel ieee80211-workqueue based work here.
* See comment in b43_remove(). */
wldev = b43_bus_get_wldev(dev);
- wl = wldev->wl;
b43_debugfs_remove_device(wldev);
b43_wireless_core_detach(wldev);
list_del(&wldev->list);
@@ -5610,7 +5608,7 @@ static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev)
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
- wl->hw_registred = false;
+ wl->hw_registered = false;
hw->max_rates = 2;
SET_IEEE80211_DEV(hw, dev->dev);
if (is_valid_ether_addr(sprom->et1mac))
@@ -5693,7 +5691,7 @@ static void b43_bcma_remove(struct bcma_device *core)
B43_WARN_ON(!wl);
if (!wldev->fw.ucode.data)
return; /* NULL if firmware never loaded */
- if (wl->current_dev == wldev && wl->hw_registred) {
+ if (wl->current_dev == wldev && wl->hw_registered) {
b43_leds_stop(wldev);
ieee80211_unregister_hw(wl->hw);
}
@@ -5776,7 +5774,7 @@ static void b43_ssb_remove(struct ssb_device *sdev)
B43_WARN_ON(!wl);
if (!wldev->fw.ucode.data)
return; /* NULL if firmware never loaded */
- if (wl->current_dev == wldev && wl->hw_registred) {
+ if (wl->current_dev == wldev && wl->hw_registered) {
b43_leds_stop(wldev);
ieee80211_unregister_hw(wl->hw);
}
diff --git a/drivers/net/wireless/broadcom/b43legacy/dma.c b/drivers/net/wireless/broadcom/b43legacy/dma.c
index 2f0c64cef65f..1b1da7d83652 100644
--- a/drivers/net/wireless/broadcom/b43legacy/dma.c
+++ b/drivers/net/wireless/broadcom/b43legacy/dma.c
@@ -1149,7 +1149,7 @@ int b43legacy_dma_tx(struct b43legacy_wldev *dev,
return -ENOSPC;
}
- if (unlikely(WARN_ON(free_slots(ring) < SLOTS_PER_PACKET))) {
+ if (WARN_ON(free_slots(ring) < SLOTS_PER_PACKET)) {
/* If we get here, we have a real error with the queue
* full, but queues not stopped. */
b43legacyerr(dev->wl, "DMA queue overflow\n");
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
index d2f788d88668..3e37c8cf82c6 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
@@ -576,7 +576,7 @@ int brcmf_sdiod_recv_chain(struct brcmf_sdio_dev *sdiodev,
if (pktq->qlen == 1)
err = brcmf_sdiod_skbuff_read(sdiodev, sdiodev->func2, addr,
- pktq->next);
+ __skb_peek(pktq));
else if (!sdiodev->sg_support) {
glom_skb = brcmu_pkt_buf_get_skb(totlen);
if (!glom_skb)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index 5444e6213d45..230a378c26fc 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -1649,6 +1649,14 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
case WLAN_AKM_SUITE_PSK:
val = WPA2_AUTH_PSK;
break;
+ case WLAN_AKM_SUITE_FT_8021X:
+ val = WPA2_AUTH_UNSPECIFIED | WPA2_AUTH_FT;
+ if (sme->want_1x)
+ profile->use_fwsup = BRCMF_PROFILE_FWSUP_1X;
+ break;
+ case WLAN_AKM_SUITE_FT_PSK:
+ val = WPA2_AUTH_PSK | WPA2_AUTH_FT;
+ break;
default:
brcmf_err("invalid cipher group (%d)\n",
sme->crypto.cipher_group);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
index cd3651069d0c..94044a7a6021 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
@@ -296,9 +296,7 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
/* Replace all newline/linefeed characters with space
* character
*/
- ptr = clmver;
- while ((ptr = strnchr(ptr, '\n', sizeof(buf))) != NULL)
- *ptr = ' ';
+ strreplace(clmver, '\n', ' ');
brcmf_dbg(INFO, "CLM version = %s\n", clmver);
}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
index 8347da632a5b..4c5a3995dc35 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
@@ -178,7 +178,7 @@ static void brcmf_feat_iovar_data_set(struct brcmf_if *ifp,
ifp->fwil_fwerr = false;
}
-#define MAX_CAPS_BUFFER_SIZE 512
+#define MAX_CAPS_BUFFER_SIZE 768
static void brcmf_feat_firmware_capabilities(struct brcmf_if *ifp)
{
char caps[MAX_CAPS_BUFFER_SIZE];
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
index 3e9c4f2f5dd1..456a1bf008b3 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
@@ -74,7 +74,7 @@
#define P2P_AF_MAX_WAIT_TIME msecs_to_jiffies(2000)
#define P2P_INVALID_CHANNEL -1
#define P2P_CHANNEL_SYNC_RETRY 5
-#define P2P_AF_FRM_SCAN_MAX_WAIT msecs_to_jiffies(1500)
+#define P2P_AF_FRM_SCAN_MAX_WAIT msecs_to_jiffies(450)
#define P2P_DEFAULT_SLEEP_TIME_VSDB 200
/* WiFi P2P Public Action Frame OUI Subtypes */
@@ -1134,7 +1134,6 @@ static s32 brcmf_p2p_af_searching_channel(struct brcmf_p2p_info *p2p)
{
struct afx_hdl *afx_hdl = &p2p->afx_hdl;
struct brcmf_cfg80211_vif *pri_vif;
- unsigned long duration;
s32 retry;
brcmf_dbg(TRACE, "Enter\n");
@@ -1150,7 +1149,6 @@ static s32 brcmf_p2p_af_searching_channel(struct brcmf_p2p_info *p2p)
* pending action frame tx is cancelled.
*/
retry = 0;
- duration = msecs_to_jiffies(P2P_AF_FRM_SCAN_MAX_WAIT);
while ((retry < P2P_CHANNEL_SYNC_RETRY) &&
(afx_hdl->peer_chan == P2P_INVALID_CHANNEL)) {
afx_hdl->is_listen = false;
@@ -1158,7 +1156,8 @@ static s32 brcmf_p2p_af_searching_channel(struct brcmf_p2p_info *p2p)
retry);
/* search peer on peer's listen channel */
schedule_work(&afx_hdl->afx_work);
- wait_for_completion_timeout(&afx_hdl->act_frm_scan, duration);
+ wait_for_completion_timeout(&afx_hdl->act_frm_scan,
+ P2P_AF_FRM_SCAN_MAX_WAIT);
if ((afx_hdl->peer_chan != P2P_INVALID_CHANNEL) ||
(!test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL,
&p2p->status)))
@@ -1171,7 +1170,7 @@ static s32 brcmf_p2p_af_searching_channel(struct brcmf_p2p_info *p2p)
afx_hdl->is_listen = true;
schedule_work(&afx_hdl->afx_work);
wait_for_completion_timeout(&afx_hdl->act_frm_scan,
- duration);
+ P2P_AF_FRM_SCAN_MAX_WAIT);
}
if ((afx_hdl->peer_chan != P2P_INVALID_CHANNEL) ||
(!test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL,
@@ -1458,10 +1457,12 @@ int brcmf_p2p_notify_action_tx_complete(struct brcmf_if *ifp,
return 0;
if (e->event_code == BRCMF_E_ACTION_FRAME_COMPLETE) {
- if (e->status == BRCMF_E_STATUS_SUCCESS)
+ if (e->status == BRCMF_E_STATUS_SUCCESS) {
set_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED,
&p2p->status);
- else {
+ if (!p2p->wait_for_offchan_complete)
+ complete(&p2p->send_af_done);
+ } else {
set_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status);
/* If there is no ack, we don't need to wait for
* WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE event
@@ -1512,6 +1513,17 @@ static s32 brcmf_p2p_tx_action_frame(struct brcmf_p2p_info *p2p,
p2p->af_sent_channel = le32_to_cpu(af_params->channel);
p2p->af_tx_sent_jiffies = jiffies;
+ if (test_bit(BRCMF_P2P_STATUS_DISCOVER_LISTEN, &p2p->status) &&
+ p2p->af_sent_channel ==
+ ieee80211_frequency_to_channel(p2p->remain_on_channel.center_freq))
+ p2p->wait_for_offchan_complete = false;
+ else
+ p2p->wait_for_offchan_complete = true;
+
+ brcmf_dbg(TRACE, "Waiting for %s tx completion event\n",
+ (p2p->wait_for_offchan_complete) ?
+ "off-channel" : "on-channel");
+
timeout = wait_for_completion_timeout(&p2p->send_af_done,
P2P_AF_MAX_WAIT_TIME);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.h
index 0e8b34d2d85c..39f0d0218088 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.h
@@ -124,6 +124,7 @@ struct afx_hdl {
* @gon_req_action: about to send go negotiation requets frame.
* @block_gon_req_tx: drop tx go negotiation requets frame.
* @p2pdev_dynamically: is p2p device if created by module param or supplicant.
+ * @wait_for_offchan_complete: wait for off-channel tx completion event.
*/
struct brcmf_p2p_info {
struct brcmf_cfg80211_info *cfg;
@@ -144,6 +145,7 @@ struct brcmf_p2p_info {
bool gon_req_action;
bool block_gon_req_tx;
bool p2pdev_dynamically;
+ bool wait_for_offchan_complete;
};
s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg, bool p2pdev_forced);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
index 4fffa6988087..5dea569d63ed 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
@@ -2017,6 +2017,7 @@ static const struct dev_pm_ops brcmf_pciedrvr_pm = {
static const struct pci_device_id brcmf_pcie_devid_table[] = {
BRCMF_PCIE_DEVICE(BRCM_PCIE_4350_DEVICE_ID),
+ BRCMF_PCIE_DEVICE_SUB(0x4355, BRCM_PCIE_VENDOR_ID_BROADCOM, 0x4355),
BRCMF_PCIE_DEVICE(BRCM_PCIE_4356_DEVICE_ID),
BRCMF_PCIE_DEVICE(BRCM_PCIE_43567_DEVICE_ID),
BRCMF_PCIE_DEVICE(BRCM_PCIE_43570_DEVICE_ID),
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
index a907d7b065fa..b2e1ab5adb64 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
@@ -1463,7 +1463,7 @@ static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq)
struct sk_buff *pfirst, *pnext;
int errcode;
- u8 doff, sfdoff;
+ u8 doff;
struct brcmf_sdio_hdrinfo rd_new;
@@ -1597,7 +1597,6 @@ static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq)
/* Remove superframe header, remember offset */
skb_pull(pfirst, rd_new.dat_offset);
- sfdoff = rd_new.dat_offset;
num = 0;
/* Validate all the subframe headers */
@@ -2189,7 +2188,7 @@ brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
* length of the chain (including padding)
*/
if (bus->txglom)
- brcmf_sdio_update_hwhdr(pktq->next->data, total_len);
+ brcmf_sdio_update_hwhdr(__skb_peek(pktq)->data, total_len);
return 0;
}
@@ -3405,7 +3404,6 @@ static int brcmf_sdio_bus_preinit(struct device *dev)
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
struct brcmf_sdio *bus = sdiodev->bus;
struct brcmf_core *core = bus->sdio_core;
- uint pad_size;
u32 value;
int err;
@@ -3448,7 +3446,6 @@ static int brcmf_sdio_bus_preinit(struct device *dev)
if (sdiodev->sg_support) {
bus->txglom = false;
value = 1;
- pad_size = bus->sdiodev->func2->cur_blksize << 1;
err = brcmf_iovar_data_set(bus->sdiodev->dev, "bus:rxglom",
&value, sizeof(u32));
if (err < 0) {
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.c
index 2fe1f6863278..3bd54f125776 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.c
@@ -62,8 +62,7 @@ int brcms_debugfs_attach(struct brcms_pub *drvr)
void brcms_debugfs_detach(struct brcms_pub *drvr)
{
- if (!IS_ERR_OR_NULL(drvr->dbgfs_dir))
- debugfs_remove_recursive(drvr->dbgfs_dir);
+ debugfs_remove_recursive(drvr->dbgfs_dir);
}
struct dentry *brcms_debugfs_get_devdir(struct brcms_pub *drvr)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c
index ecc89e718b9c..81ff558046a8 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c
@@ -502,6 +502,7 @@ brcms_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
}
spin_lock_bh(&wl->lock);
+ wl->wlc->vif = vif;
wl->mute_tx = false;
brcms_c_mute(wl->wlc, false);
if (vif->type == NL80211_IFTYPE_STATION)
@@ -519,6 +520,11 @@ brcms_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
static void
brcms_ops_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
+ struct brcms_info *wl = hw->priv;
+
+ spin_lock_bh(&wl->lock);
+ wl->wlc->vif = NULL;
+ spin_unlock_bh(&wl->lock);
}
static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed)
@@ -937,6 +943,25 @@ static void brcms_ops_set_tsf(struct ieee80211_hw *hw,
spin_unlock_bh(&wl->lock);
}
+static int brcms_ops_beacon_set_tim(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta, bool set)
+{
+ struct brcms_info *wl = hw->priv;
+ struct sk_buff *beacon = NULL;
+ u16 tim_offset = 0;
+
+ spin_lock_bh(&wl->lock);
+ if (wl->wlc->vif)
+ beacon = ieee80211_beacon_get_tim(hw, wl->wlc->vif,
+ &tim_offset, NULL);
+ if (beacon)
+ brcms_c_set_new_beacon(wl->wlc, beacon, tim_offset,
+ wl->wlc->vif->bss_conf.dtim_period);
+ spin_unlock_bh(&wl->lock);
+
+ return 0;
+}
+
static const struct ieee80211_ops brcms_ops = {
.tx = brcms_ops_tx,
.start = brcms_ops_start,
@@ -955,6 +980,7 @@ static const struct ieee80211_ops brcms_ops = {
.flush = brcms_ops_flush,
.get_tsf = brcms_ops_get_tsf,
.set_tsf = brcms_ops_set_tsf,
+ .set_tim = brcms_ops_beacon_set_tim,
};
void brcms_dpc(unsigned long data)
@@ -1578,10 +1604,10 @@ int brcms_ucode_init_buf(struct brcms_info *wl, void **pbuf, u32 idx)
if (le32_to_cpu(hdr->idx) == idx) {
pdata = wl->fw.fw_bin[i]->data +
le32_to_cpu(hdr->offset);
- *pbuf = kmemdup(pdata, len, GFP_KERNEL);
+ *pbuf = kvmalloc(len, GFP_KERNEL);
if (*pbuf == NULL)
goto fail;
-
+ memcpy(*pbuf, pdata, len);
return 0;
}
}
@@ -1629,7 +1655,7 @@ int brcms_ucode_init_uint(struct brcms_info *wl, size_t *n_bytes, u32 idx)
*/
void brcms_ucode_free_buf(void *p)
{
- kfree(p);
+ kvfree(p);
}
/*
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.h
index c4d135cff04a..9f76b880814e 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.h
@@ -563,6 +563,7 @@ struct brcms_c_info {
struct wiphy *wiphy;
struct scb pri_scb;
+ struct ieee80211_vif *vif;
struct sk_buff *beacon;
u16 beacon_tim_offset;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c
index bedec1606caa..a57f2711f3c0 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c
@@ -25453,12 +25453,12 @@ void wlc_phy_cal_perical_nphy_run(struct brcms_phy *pi, u8 caltype)
(pi->cal_type_override ==
PHY_PERICAL_FULL) ? true : false;
- if ((pi->mphase_cal_phase_id > MPHASE_CAL_STATE_INIT)) {
+ if (pi->mphase_cal_phase_id > MPHASE_CAL_STATE_INIT) {
if (pi->nphy_txiqlocal_chanspec != pi->radio_chanspec)
wlc_phy_cal_perical_mphase_restart(pi);
}
- if ((pi->mphase_cal_phase_id == MPHASE_CAL_STATE_RXCAL))
+ if (pi->mphase_cal_phase_id == MPHASE_CAL_STATE_RXCAL)
wlapi_bmac_write_shm(pi->sh->physhim, M_CTS_DURATION, 10000);
wlapi_suspend_mac_and_wait(pi->sh->physhim);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmutil/d11.c b/drivers/net/wireless/broadcom/brcm80211/brcmutil/d11.c
index d8b79cb72b58..e7584b842dce 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmutil/d11.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmutil/d11.c
@@ -77,6 +77,8 @@ static u16 d11ac_bw(enum brcmu_chan_bw bw)
return BRCMU_CHSPEC_D11AC_BW_40;
case BRCMU_CHAN_BW_80:
return BRCMU_CHSPEC_D11AC_BW_80;
+ case BRCMU_CHAN_BW_160:
+ return BRCMU_CHSPEC_D11AC_BW_160;
default:
WARN_ON(1);
}
@@ -190,8 +192,38 @@ static void brcmu_d11ac_decchspec(struct brcmu_chan *ch)
break;
}
break;
- case BRCMU_CHSPEC_D11AC_BW_8080:
case BRCMU_CHSPEC_D11AC_BW_160:
+ switch (ch->sb) {
+ case BRCMU_CHAN_SB_LLL:
+ ch->control_ch_num -= CH_70MHZ_APART;
+ break;
+ case BRCMU_CHAN_SB_LLU:
+ ch->control_ch_num -= CH_50MHZ_APART;
+ break;
+ case BRCMU_CHAN_SB_LUL:
+ ch->control_ch_num -= CH_30MHZ_APART;
+ break;
+ case BRCMU_CHAN_SB_LUU:
+ ch->control_ch_num -= CH_10MHZ_APART;
+ break;
+ case BRCMU_CHAN_SB_ULL:
+ ch->control_ch_num += CH_10MHZ_APART;
+ break;
+ case BRCMU_CHAN_SB_ULU:
+ ch->control_ch_num += CH_30MHZ_APART;
+ break;
+ case BRCMU_CHAN_SB_UUL:
+ ch->control_ch_num += CH_50MHZ_APART;
+ break;
+ case BRCMU_CHAN_SB_UUU:
+ ch->control_ch_num += CH_70MHZ_APART;
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ break;
+ }
+ break;
+ case BRCMU_CHSPEC_D11AC_BW_8080:
default:
WARN_ON_ONCE(1);
break;
diff --git a/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h b/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h
index 7b9a77981df1..dddebaa60352 100644
--- a/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h
+++ b/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h
@@ -29,6 +29,8 @@
#define CH_UPPER_SB 0x01
#define CH_LOWER_SB 0x02
#define CH_EWA_VALID 0x04
+#define CH_70MHZ_APART 14
+#define CH_50MHZ_APART 10
#define CH_30MHZ_APART 6
#define CH_20MHZ_APART 4
#define CH_10MHZ_APART 2
@@ -237,6 +239,7 @@ static inline bool ac_bitmap_tst(u8 bitmap, int prec)
#define WPA2_AUTH_RESERVED4 0x0400
#define WPA2_AUTH_RESERVED5 0x0800
#define WPA2_AUTH_1X_SHA256 0x1000 /* 1X with SHA256 key derivation */
+#define WPA2_AUTH_FT 0x4000 /* Fast BSS Transition */
#define WPA2_AUTH_PSK_SHA256 0x8000 /* PSK with SHA256 key derivation */
#define DOT11_DEFAULT_RTS_LEN 2347
diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c
index 9644e7b93645..bbdca13c5a9f 100644
--- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c
@@ -5652,7 +5652,7 @@ static void ipw_merge_adhoc_network(struct work_struct *work)
}
mutex_lock(&priv->mutex);
- if ((priv->ieee->iw_mode == IW_MODE_ADHOC)) {
+ if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
IPW_DEBUG_MERGE("remove network %*pE\n",
priv->essid_len, priv->essid);
ipw_remove_current_network(priv);
diff --git a/drivers/net/wireless/intel/iwlegacy/4965.c b/drivers/net/wireless/intel/iwlegacy/4965.c
index c3c638ed0ed7..ce4144a89217 100644
--- a/drivers/net/wireless/intel/iwlegacy/4965.c
+++ b/drivers/net/wireless/intel/iwlegacy/4965.c
@@ -1297,6 +1297,8 @@ il4965_send_rxon_assoc(struct il_priv *il)
const struct il_rxon_cmd *rxon1 = &il->staging;
const struct il_rxon_cmd *rxon2 = &il->active;
+ lockdep_assert_held(&il->mutex);
+
if (rxon1->flags == rxon2->flags &&
rxon1->filter_flags == rxon2->filter_flags &&
rxon1->cck_basic_rates == rxon2->cck_basic_rates &&
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/1000.c b/drivers/net/wireless/intel/iwlwifi/cfg/1000.c
index 591687984962..76b5ddb20248 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/1000.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/1000.c
@@ -12,10 +12,6 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
@@ -51,6 +47,7 @@
static const struct iwl_base_params iwl1000_base_params = {
.num_of_queues = IWLAGN_NUM_QUEUES,
+ .max_tfd_queue_size = 256,
.eeprom_size = OTP_LOW_IMAGE_SIZE,
.pll_cfg = true,
.max_ll_items = OTP_MAX_LL_ITEMS_1000,
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/2000.c b/drivers/net/wireless/intel/iwlwifi/cfg/2000.c
index fedb108db68f..e7e45846dd07 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/2000.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/2000.c
@@ -12,10 +12,6 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
index 91ca77c7571c..da5d5f9b2573 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
@@ -56,7 +56,7 @@
#include "iwl-config.h"
/* Highest firmware API version supported */
-#define IWL_22000_UCODE_API_MAX 38
+#define IWL_22000_UCODE_API_MAX 41
/* Lowest firmware API version supported */
#define IWL_22000_UCODE_API_MIN 39
@@ -77,10 +77,13 @@
#define IWL_22000_HR_FW_PRE "iwlwifi-Qu-a0-hr-a0-"
#define IWL_22000_HR_CDB_FW_PRE "iwlwifi-QuIcp-z0-hrcdb-a0-"
#define IWL_22000_HR_A_F0_FW_PRE "iwlwifi-QuQnj-f0-hr-a0-"
-#define IWL_22000_HR_B_FW_PRE "iwlwifi-Qu-b0-hr-b0-"
+#define IWL_22000_HR_B_F0_FW_PRE "iwlwifi-Qu-b0-hr-b0-"
+#define IWL_22000_QU_B_HR_B_FW_PRE "iwlwifi-Qu-b0-hr-b0-"
+#define IWL_22000_HR_B_FW_PRE "iwlwifi-QuQnj-b0-hr-b0-"
#define IWL_22000_JF_B0_FW_PRE "iwlwifi-QuQnj-a0-jf-b0-"
#define IWL_22000_HR_A0_FW_PRE "iwlwifi-QuQnj-a0-hr-a0-"
#define IWL_22000_SU_Z0_FW_PRE "iwlwifi-su-z0-"
+#define IWL_QU_B_JF_B_FW_PRE "iwlwifi-Qu-b0-jf-b0-"
#define IWL_22000_HR_MODULE_FIRMWARE(api) \
IWL_22000_HR_FW_PRE __stringify(api) ".ucode"
@@ -88,7 +91,11 @@
IWL_22000_JF_FW_PRE __stringify(api) ".ucode"
#define IWL_22000_HR_A_F0_QNJ_MODULE_FIRMWARE(api) \
IWL_22000_HR_A_F0_FW_PRE __stringify(api) ".ucode"
-#define IWL_22000_HR_B_QNJ_MODULE_FIRMWARE(api) \
+#define IWL_22000_HR_B_F0_QNJ_MODULE_FIRMWARE(api) \
+ IWL_22000_HR_B_F0_FW_PRE __stringify(api) ".ucode"
+#define IWL_22000_QU_B_HR_B_MODULE_FIRMWARE(api) \
+ IWL_22000_QU_B_HR_B_FW_PRE __stringify(api) ".ucode"
+#define IWL_22000_HR_B_QNJ_MODULE_FIRMWARE(api) \
IWL_22000_HR_B_FW_PRE __stringify(api) ".ucode"
#define IWL_22000_JF_B0_QNJ_MODULE_FIRMWARE(api) \
IWL_22000_JF_B0_FW_PRE __stringify(api) ".ucode"
@@ -96,6 +103,8 @@
IWL_22000_HR_A0_FW_PRE __stringify(api) ".ucode"
#define IWL_22000_SU_Z0_MODULE_FIRMWARE(api) \
IWL_22000_SU_Z0_FW_PRE __stringify(api) ".ucode"
+#define IWL_QU_B_JF_B_MODULE_FIRMWARE(api) \
+ IWL_QU_B_JF_B_FW_PRE __stringify(api) ".ucode"
#define NVM_HW_SECTION_NUM_FAMILY_22000 10
@@ -134,7 +143,7 @@ static const struct iwl_ht_params iwl_22000_ht_params = {
.ucode_api_min = IWL_22000_UCODE_API_MIN, \
.led_mode = IWL_LED_RF_STATE, \
.nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_22000, \
- .non_shared_ant = ANT_A, \
+ .non_shared_ant = ANT_B, \
.dccm_offset = IWL_22000_DCCM_OFFSET, \
.dccm_len = IWL_22000_DCCM_LEN, \
.dccm2_offset = IWL_22000_DCCM2_OFFSET, \
@@ -155,7 +164,9 @@ static const struct iwl_ht_params iwl_22000_ht_params = {
.gen2 = true, \
.nvm_type = IWL_NVM_EXT, \
.dbgc_supported = true, \
- .min_umac_error_event_table = 0x400000
+ .min_umac_error_event_table = 0x400000, \
+ .d3_debug_data_base_addr = 0x401000, \
+ .d3_debug_data_length = 60 * 1024
#define IWL_DEVICE_22500 \
IWL_DEVICE_22000_COMMON, \
@@ -190,7 +201,54 @@ const struct iwl_cfg iwl22000_2ac_cfg_jf = {
const struct iwl_cfg iwl22000_2ax_cfg_hr = {
.name = "Intel(R) Dual Band Wireless AX 22000",
- .fw_name_pre = IWL_22000_HR_FW_PRE,
+ .fw_name_pre = IWL_22000_QU_B_HR_B_FW_PRE,
+ IWL_DEVICE_22500,
+ /*
+ * This device doesn't support receiving BlockAck with a large bitmap
+ * so we need to restrict the size of transmitted aggregation to the
+ * HT size; mac80211 would otherwise pick the HE max (256) by default.
+ */
+ .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
+};
+
+/*
+ * All JF radio modules are part of the 9000 series, but the MAC part
+ * looks more like 22000. That's why this device is here, but called
+ * 9560 nevertheless.
+ */
+const struct iwl_cfg iwl9461_2ac_cfg_qu_b0_jf_b0 = {
+ .name = "Intel(R) Wireless-AC 9461",
+ .fw_name_pre = IWL_QU_B_JF_B_FW_PRE,
+ IWL_DEVICE_22500,
+};
+
+const struct iwl_cfg iwl9462_2ac_cfg_qu_b0_jf_b0 = {
+ .name = "Intel(R) Wireless-AC 9462",
+ .fw_name_pre = IWL_QU_B_JF_B_FW_PRE,
+ IWL_DEVICE_22500,
+};
+
+const struct iwl_cfg iwl9560_2ac_cfg_qu_b0_jf_b0 = {
+ .name = "Intel(R) Wireless-AC 9560",
+ .fw_name_pre = IWL_QU_B_JF_B_FW_PRE,
+ IWL_DEVICE_22500,
+};
+
+const struct iwl_cfg killer1550i_2ac_cfg_qu_b0_jf_b0 = {
+ .name = "Killer (R) Wireless-AC 1550i Wireless Network Adapter (9560NGW)",
+ .fw_name_pre = IWL_QU_B_JF_B_FW_PRE,
+ IWL_DEVICE_22500,
+};
+
+const struct iwl_cfg killer1550s_2ac_cfg_qu_b0_jf_b0 = {
+ .name = "Killer (R) Wireless-AC 1550s Wireless Network Adapter (9560NGW)",
+ .fw_name_pre = IWL_QU_B_JF_B_FW_PRE,
+ IWL_DEVICE_22500,
+};
+
+const struct iwl_cfg iwl22000_2ax_cfg_jf = {
+ .name = "Intel(R) Dual Band Wireless AX 22000",
+ .fw_name_pre = IWL_QU_B_JF_B_FW_PRE,
IWL_DEVICE_22500,
/*
* This device doesn't support receiving BlockAck with a large bitmap
@@ -264,7 +322,10 @@ const struct iwl_cfg iwl22560_2ax_cfg_su_cdb = {
MODULE_FIRMWARE(IWL_22000_HR_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_22000_JF_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_22000_HR_A_F0_QNJ_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
+MODULE_FIRMWARE(IWL_22000_HR_B_F0_QNJ_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
+MODULE_FIRMWARE(IWL_22000_QU_B_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_22000_HR_B_QNJ_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_22000_JF_B0_QNJ_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_22000_HR_A0_QNJ_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_22000_SU_Z0_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
+MODULE_FIRMWARE(IWL_QU_B_JF_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/5000.c b/drivers/net/wireless/intel/iwlwifi/cfg/5000.c
index 36151e61a26f..575a7022d045 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/5000.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/5000.c
@@ -12,10 +12,6 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/6000.c b/drivers/net/wireless/intel/iwlwifi/cfg/6000.c
index b5d8274761d8..30e62a7c9d52 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/6000.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/6000.c
@@ -12,10 +12,6 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/7000.c b/drivers/net/wireless/intel/iwlwifi/cfg/7000.c
index a62c8346f13a..c973bfaa3414 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/7000.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/7000.c
@@ -19,11 +19,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/8000.c b/drivers/net/wireless/intel/iwlwifi/cfg/8000.c
index c46fa712985b..348c40fcddcb 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/8000.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/8000.c
@@ -19,11 +19,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c
index 24b2f7cbb308..d55fd23cafe6 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c
@@ -57,7 +57,7 @@
#include "fw/file.h"
/* Highest firmware API version supported */
-#define IWL9000_UCODE_API_MAX 38
+#define IWL9000_UCODE_API_MAX 41
/* Lowest firmware API version supported */
#define IWL9000_UCODE_API_MIN 30
@@ -155,7 +155,9 @@ static const struct iwl_tt_params iwl9000_tt_params = {
.nvm_type = IWL_NVM_EXT, \
.dbgc_supported = true, \
.min_umac_error_event_table = 0x800000, \
- .csr = &iwl_csr_v1
+ .csr = &iwl_csr_v1, \
+ .d3_debug_data_base_addr = 0x401000, \
+ .d3_debug_data_length = 92 * 1024
const struct iwl_cfg iwl9160_2ac_cfg = {
.name = "Intel(R) Dual Band Wireless AC 9160",
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/agn.h b/drivers/net/wireless/intel/iwlwifi/dvm/agn.h
index b79e38734f2f..431e13c6ee35 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/agn.h
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/agn.h
@@ -16,11 +16,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/calib.c b/drivers/net/wireless/intel/iwlwifi/dvm/calib.c
index c96f9b1d948a..588b15697710 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/calib.c
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/calib.c
@@ -16,11 +16,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/calib.h b/drivers/net/wireless/intel/iwlwifi/dvm/calib.h
index 099e3ce80ffc..c43ba94bfa8b 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/calib.h
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/calib.h
@@ -16,11 +16,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/commands.h b/drivers/net/wireless/intel/iwlwifi/dvm/commands.h
index f89736d60a3d..0f4be4be181c 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/commands.h
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/commands.h
@@ -16,11 +16,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c
index 096a07c5a33f..3d2e44a642de 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c
@@ -13,11 +13,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/dev.h b/drivers/net/wireless/intel/iwlwifi/dvm/dev.h
index cceb4cd8e501..c5b8376d827f 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/dev.h
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/dev.h
@@ -11,10 +11,6 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/devices.c b/drivers/net/wireless/intel/iwlwifi/dvm/devices.c
index f21732ec3b25..3dd7d8c45dab 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/devices.c
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/devices.c
@@ -11,10 +11,6 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/led.c b/drivers/net/wireless/intel/iwlwifi/dvm/led.c
index 1bbd17ada974..04c236e9399b 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/led.c
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/led.c
@@ -11,10 +11,6 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/led.h b/drivers/net/wireless/intel/iwlwifi/dvm/led.h
index 75f74edd018f..8f93a3246dee 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/led.h
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/led.h
@@ -11,10 +11,6 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/lib.c b/drivers/net/wireless/intel/iwlwifi/dvm/lib.c
index 2b6ffbc46fa5..b2f172d4f78a 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/lib.c
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/lib.c
@@ -13,11 +13,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c
index 82caae02dd09..49b71dbf8490 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c
@@ -14,10 +14,6 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/main.c b/drivers/net/wireless/intel/iwlwifi/dvm/main.c
index 030482b357a3..1088ff036e13 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/main.c
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/main.c
@@ -2,6 +2,7 @@
*
* Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2015 Intel Deutschland GmbH
+ * Copyright (C) 2018 Intel Corporation
*
* Portions of this file are derived from the ipw3945 project, as well
* as portions of the ieee80211 subsystem header files.
@@ -15,10 +16,6 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
@@ -1651,7 +1648,6 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv)
priv->status, table.valid);
}
- trace_iwlwifi_dev_ucode_error(trans->dev, &table, 0, table.brd_ver);
IWL_ERR(priv, "0x%08X | %-28s\n", table.error_id,
desc_lookup(table.error_id));
IWL_ERR(priv, "0x%08X | uPc\n", table.pc);
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/power.c b/drivers/net/wireless/intel/iwlwifi/dvm/power.c
index 0ad557c89514..8c25e3aefb2b 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/power.c
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/power.c
@@ -14,10 +14,6 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/power.h b/drivers/net/wireless/intel/iwlwifi/dvm/power.h
index 2fd9b43adafd..a04fd4d375c6 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/power.h
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/power.h
@@ -14,10 +14,6 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rs.c b/drivers/net/wireless/intel/iwlwifi/dvm/rs.c
index 98050d7be411..ef4b9de256f7 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/rs.c
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/rs.c
@@ -11,10 +11,6 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rs.h b/drivers/net/wireless/intel/iwlwifi/dvm/rs.h
index 50c1e951dd2d..b2df3a8cc464 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/rs.h
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/rs.h
@@ -11,10 +11,6 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rx.c b/drivers/net/wireless/intel/iwlwifi/dvm/rx.c
index c942830af2b5..6f17a5e24e82 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/rx.c
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/rx.c
@@ -15,10 +15,6 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c b/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c
index 8f3e5586eda9..eee1d48d453a 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c
@@ -12,10 +12,6 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/scan.c b/drivers/net/wireless/intel/iwlwifi/dvm/scan.c
index 17e6a32384d3..8d7aafb4d9e9 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/scan.c
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/scan.c
@@ -13,11 +13,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/sta.c b/drivers/net/wireless/intel/iwlwifi/dvm/sta.c
index de6ec9b7ace4..b1792de09594 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/sta.c
@@ -14,10 +14,6 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/tt.c b/drivers/net/wireless/intel/iwlwifi/dvm/tt.c
index 6524533d723c..4de2727ac63e 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/tt.c
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/tt.c
@@ -14,10 +14,6 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/tt.h b/drivers/net/wireless/intel/iwlwifi/dvm/tt.h
index d324e9be9cbf..6388c09603c6 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/tt.h
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/tt.h
@@ -14,10 +14,6 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/tx.c b/drivers/net/wireless/intel/iwlwifi/dvm/tx.c
index fb40ddfced99..4ff323a3a4e5 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/tx.c
@@ -13,11 +13,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/ucode.c b/drivers/net/wireless/intel/iwlwifi/dvm/ucode.c
index d6013bfe991c..3bf57085b976 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/ucode.c
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/ucode.c
@@ -14,11 +14,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
index 75cae54ea7de..32d000cffe9f 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
@@ -16,9 +16,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program;
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
index cb5f32c1d705..2439e98431ee 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
@@ -16,9 +16,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program;
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/coex.h b/drivers/net/wireless/intel/iwlwifi/fw/api/coex.h
index 87c1ddea75ae..68060085010f 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/coex.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/coex.h
@@ -8,6 +8,7 @@
* Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* Copyright(c) 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -30,6 +31,7 @@
* Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* Copyright(c) 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -203,6 +205,7 @@ enum iwl_bt_activity_grading {
BT_ON_NO_CONNECTION = 1,
BT_LOW_TRAFFIC = 2,
BT_HIGH_TRAFFIC = 3,
+ BT_VERY_HIGH_TRAFFIC = 4,
BT_MAX_AG,
}; /* BT_COEX_BT_ACTIVITY_GRADING_API_E_VER_1 */
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h
index 6dad748e5cdc..8b4922bbe139 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h
@@ -436,7 +436,8 @@ enum iwl_legacy_cmds {
/**
* @REDUCE_TX_POWER_CMD:
- * &struct iwl_dev_tx_power_cmd_v3 or &struct iwl_dev_tx_power_cmd
+ * &struct iwl_dev_tx_power_cmd_v3 or &struct iwl_dev_tx_power_cmd_v4
+ * or &struct iwl_dev_tx_power_cmd
*/
REDUCE_TX_POWER_CMD = 0x9f,
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h
index 57f4bc242023..6fae02fa4cad 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h
@@ -8,6 +8,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* Copyright(c) 2015 - 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -30,6 +31,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* Copyright(c) 2015 - 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -374,7 +376,7 @@ enum iwl_wowlan_wakeup_reason {
}; /* WOWLAN_WAKE_UP_REASON_API_E_VER_2 */
-struct iwl_wowlan_gtk_status {
+struct iwl_wowlan_gtk_status_v1 {
u8 key_index;
u8 reserved[3];
u8 decrypt_key[16];
@@ -382,9 +384,84 @@ struct iwl_wowlan_gtk_status {
struct iwl_wowlan_rsc_tsc_params_cmd rsc;
} __packed; /* WOWLAN_GTK_MATERIAL_VER_1 */
+#define WOWLAN_KEY_MAX_SIZE 32
+#define WOWLAN_GTK_KEYS_NUM 2
+#define WOWLAN_IGTK_KEYS_NUM 2
+
+/**
+ * struct iwl_wowlan_gtk_status - GTK status
+ * @key: GTK material
+ * @key_len: GTK legth, if set to 0, the key is not available
+ * @key_flags: information about the key:
+ * bits[0:1]: key index assigned by the AP
+ * bits[2:6]: GTK index of the key in the internal DB
+ * bit[7]: Set iff this is the currently used GTK
+ * @reserved: padding
+ * @tkip_mic_key: TKIP RX MIC key
+ * @rsc: TSC RSC counters
+ */
+struct iwl_wowlan_gtk_status {
+ u8 key[WOWLAN_KEY_MAX_SIZE];
+ u8 key_len;
+ u8 key_flags;
+ u8 reserved[2];
+ u8 tkip_mic_key[8];
+ struct iwl_wowlan_rsc_tsc_params_cmd rsc;
+} __packed; /* WOWLAN_GTK_MATERIAL_VER_2 */
+
+#define IWL_WOWLAN_GTK_IDX_MASK (BIT(0) | BIT(1))
+
+/**
+ * struct iwl_wowlan_igtk_status - IGTK status
+ * @key: IGTK material
+ * @ipn: the IGTK packet number (replay counter)
+ * @key_len: IGTK length, if set to 0, the key is not available
+ * @key_flags: information about the key:
+ * bits[0]: key index assigned by the AP (0: index 4, 1: index 5)
+ * bits[1:5]: IGTK index of the key in the internal DB
+ * bit[6]: Set iff this is the currently used IGTK
+ */
+struct iwl_wowlan_igtk_status {
+ u8 key[WOWLAN_KEY_MAX_SIZE];
+ u8 ipn[6];
+ u8 key_len;
+ u8 key_flags;
+} __packed; /* WOWLAN_IGTK_MATERIAL_VER_1 */
+
+/**
+ * struct iwl_wowlan_status_v6 - WoWLAN status
+ * @gtk: GTK 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
+ * @qos_seq_ctr: QoS sequence counters to use next
+ * @wakeup_reasons: wakeup reasons, see &enum iwl_wowlan_wakeup_reason
+ * @num_of_gtk_rekeys: number of GTK rekeys
+ * @transmitted_ndps: number of transmitted neighbor discovery packets
+ * @received_beacons: number of received beacons
+ * @wake_packet_length: wakeup packet length
+ * @wake_packet_bufsize: wakeup packet buffer size
+ * @wake_packet: wakeup packet
+ */
+struct iwl_wowlan_status_v6 {
+ struct iwl_wowlan_gtk_status_v1 gtk;
+ __le64 replay_ctr;
+ __le16 pattern_number;
+ __le16 non_qos_seq_ctr;
+ __le16 qos_seq_ctr[8];
+ __le32 wakeup_reasons;
+ __le32 num_of_gtk_rekeys;
+ __le32 transmitted_ndps;
+ __le32 received_beacons;
+ __le32 wake_packet_length;
+ __le32 wake_packet_bufsize;
+ u8 wake_packet[]; /* can be truncated from _length to _bufsize */
+} __packed; /* WOWLAN_STATUSES_API_S_VER_6 */
+
/**
* struct iwl_wowlan_status - WoWLAN status
* @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
@@ -398,7 +475,8 @@ struct iwl_wowlan_gtk_status {
* @wake_packet: wakeup packet
*/
struct iwl_wowlan_status {
- struct iwl_wowlan_gtk_status gtk;
+ struct iwl_wowlan_gtk_status gtk[WOWLAN_GTK_KEYS_NUM];
+ struct iwl_wowlan_igtk_status igtk[WOWLAN_IGTK_KEYS_NUM];
__le64 replay_ctr;
__le16 pattern_number;
__le16 non_qos_seq_ctr;
@@ -410,7 +488,12 @@ struct iwl_wowlan_status {
__le32 wake_packet_length;
__le32 wake_packet_bufsize;
u8 wake_packet[]; /* can be truncated from _length to _bufsize */
-} __packed; /* WOWLAN_STATUSES_API_S_VER_6 */
+} __packed; /* WOWLAN_STATUSES_API_S_VER_7 */
+
+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
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h
index 59b3c6e8f37b..eff3249af48a 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h
@@ -100,6 +100,11 @@ enum iwl_data_path_subcmd_ids {
TLC_MNG_CONFIG_CMD = 0xF,
/**
+ * @HE_AIR_SNIFFER_CONFIG_CMD: &struct iwl_he_monitor_cmd
+ */
+ HE_AIR_SNIFFER_CONFIG_CMD = 0x13,
+
+ /**
* @TLC_MNG_UPDATE_NOTIF: &struct iwl_tlc_update_notif
*/
TLC_MNG_UPDATE_NOTIF = 0xF7,
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h b/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h
index 106782341544..dc1fa377087a 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h
@@ -8,6 +8,7 @@
* Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
+ * Copyright (C) 2018 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -30,6 +31,7 @@
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
+ * Copyright (C) 2018 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -336,6 +338,9 @@ struct iwl_dbg_mem_access_rsp {
#define CONT_REC_COMMAND_SIZE 80
#define ENABLE_CONT_RECORDING 0x15
#define DISABLE_CONT_RECORDING 0x16
+#define BUFFER_ALLOCATION 0x27
+#define START_DEBUG_RECORDING 0x29
+#define STOP_DEBUG_RECORDING 0x2A
/*
* struct iwl_continuous_record_mode - recording mode
@@ -353,4 +358,31 @@ struct iwl_continuous_record_cmd {
sizeof(struct iwl_continuous_record_mode)];
} __packed;
+/* maximum fragments to be allocated per target of allocationId */
+#define IWL_BUFFER_LOCATION_MAX_FRAGS 2
+
+/**
+ * struct iwl_fragment_data single fragment structure
+ * @address: 64bit start address
+ * @size: size in bytes
+ */
+struct iwl_fragment_data {
+ __le64 address;
+ __le32 size;
+} __packed; /* FRAGMENT_STRUCTURE_API_S_VER_1 */
+
+/**
+ * struct iwl_buffer_allocation_cmd - buffer allocation command structure
+ * @allocation_id: id of the allocation
+ * @buffer_location: location of the buffer
+ * @num_frags: number of fragments
+ * @fragments: memory fragments
+ */
+struct iwl_buffer_allocation_cmd {
+ __le32 allocation_id;
+ __le32 buffer_location;
+ __le32 num_frags;
+ struct iwl_fragment_data fragments[IWL_BUFFER_LOCATION_MAX_FRAGS];
+} __packed; /* BUFFER_ALLOCATION_CMD_API_S_VER_1 */
+
#endif /* __iwl_fw_api_debug_h__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h
index 17c7ef1662a9..ca49db786ed6 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h
@@ -8,6 +8,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -30,6 +31,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -72,11 +74,58 @@ enum iwl_mac_conf_subcmd_ids {
*/
LOW_LATENCY_CMD = 0x3,
/**
+ * @PROBE_RESPONSE_DATA_NOTIF: &struct iwl_probe_resp_data_notif
+ */
+ PROBE_RESPONSE_DATA_NOTIF = 0xFC,
+
+ /**
* @CHANNEL_SWITCH_NOA_NOTIF: &struct iwl_channel_switch_noa_notif
*/
CHANNEL_SWITCH_NOA_NOTIF = 0xFF,
};
+#define IWL_P2P_NOA_DESC_COUNT (2)
+
+/**
+ * struct iwl_p2p_noa_attr - NOA attr contained in probe resp FW notification
+ *
+ * @id: attribute id
+ * @len_low: length low half
+ * @len_high: length high half
+ * @idx: instance of NoA timing
+ * @ctwin: GO's ct window and pwer save capability
+ * @desc: NoA descriptor
+ * @reserved: reserved for alignment purposes
+ */
+struct iwl_p2p_noa_attr {
+ u8 id;
+ u8 len_low;
+ u8 len_high;
+ u8 idx;
+ u8 ctwin;
+ struct ieee80211_p2p_noa_desc desc[IWL_P2P_NOA_DESC_COUNT];
+ u8 reserved;
+} __packed;
+
+#define IWL_PROBE_RESP_DATA_NO_CSA (0xff)
+
+/**
+ * struct iwl_probe_resp_data_notif - notification with NOA and CSA counter
+ *
+ * @mac_id: the mac which should send the probe response
+ * @noa_active: notifies if the noa attribute should be handled
+ * @noa_attr: P2P NOA attribute
+ * @csa_counter: current csa counter
+ * @reserved: reserved for alignment purposes
+ */
+struct iwl_probe_resp_data_notif {
+ __le32 mac_id;
+ __le32 noa_active;
+ struct iwl_p2p_noa_attr noa_attr;
+ u8 csa_counter;
+ u8 reserved[3];
+} __packed; /* PROBE_RESPONSE_DATA_NTFY_API_S_VER_1 */
+
/**
* struct iwl_channel_switch_noa_notif - Channel switch NOA notification
*
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h
index 55594c93b014..1dd23f846fb9 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h
@@ -578,4 +578,18 @@ struct iwl_he_sta_context_cmd {
struct iwl_he_backoff_conf trig_based_txf[AC_NUM];
} __packed; /* STA_CONTEXT_DOT11AX_API_S */
+/**
+ * struct iwl_he_monitor_cmd - configure air sniffer for HE
+ * @bssid: the BSSID to sniff for
+ * @reserved1: reserved for dword alignment
+ * @aid: the AID to track on for HE MU
+ * @reserved2: reserved for future use
+ */
+struct iwl_he_monitor_cmd {
+ u8 bssid[6];
+ __le16 reserved1;
+ __le16 aid;
+ u8 reserved2[6];
+} __packed; /* HE_AIR_SNIFFER_CONFIG_CMD_API_S_VER_1 */
+
#endif /* __iwl_fw_api_mac_h__ */
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 6c5338364794..93b392f0c6a4 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h
@@ -165,7 +165,7 @@ struct iwl_nvm_access_resp {
*/
struct iwl_nvm_get_info {
__le32 reserved;
-} __packed; /* GRP_REGULATORY_NVM_GET_INFO_CMD_S_VER_1 */
+} __packed; /* REGULATORY_NVM_GET_INFO_CMD_API_S_VER_1 */
/**
* enum iwl_nvm_info_general_flags - flags in NVM_GET_INFO resp
@@ -180,14 +180,14 @@ enum iwl_nvm_info_general_flags {
* @flags: bit 0: 1 - empty, 0 - non-empty
* @nvm_version: nvm version
* @board_type: board type
- * @reserved: reserved
+ * @n_hw_addrs: number of reserved MAC addresses
*/
struct iwl_nvm_get_info_general {
__le32 flags;
__le16 nvm_version;
u8 board_type;
- u8 reserved;
-} __packed; /* GRP_REGULATORY_NVM_GET_INFO_GENERAL_S_VER_1 */
+ u8 n_hw_addrs;
+} __packed; /* REGULATORY_NVM_GET_INFO_GENERAL_S_VER_2 */
/**
* enum iwl_nvm_mac_sku_flags - flags in &iwl_nvm_get_info_sku
@@ -231,7 +231,7 @@ struct iwl_nvm_get_info_sku {
struct iwl_nvm_get_info_phy {
__le32 tx_chains;
__le32 rx_chains;
-} __packed; /* GRP_REGULATORY_NVM_GET_INFO_PHY_SKU_SECTION_S_VER_1 */
+} __packed; /* REGULATORY_NVM_GET_INFO_PHY_SKU_SECTION_S_VER_1 */
#define IWL_NUM_CHANNELS (51)
@@ -245,7 +245,7 @@ struct iwl_nvm_get_info_regulatory {
__le32 lar_enabled;
__le16 channel_profile[IWL_NUM_CHANNELS];
__le16 reserved;
-} __packed; /* GRP_REGULATORY_NVM_GET_INFO_REGULATORY_S_VER_1 */
+} __packed; /* REGULATORY_NVM_GET_INFO_REGULATORY_S_VER_1 */
/**
* struct iwl_nvm_get_info_rsp - response to get NVM data
@@ -259,7 +259,7 @@ struct iwl_nvm_get_info_rsp {
struct iwl_nvm_get_info_sku mac_sku;
struct iwl_nvm_get_info_phy phy_sku;
struct iwl_nvm_get_info_regulatory regulatory;
-} __packed; /* GRP_REGULATORY_NVM_GET_INFO_CMD_RSP_S_VER_2 */
+} __packed; /* REGULATORY_NVM_GET_INFO_RSP_API_S_VER_3 */
/**
* struct iwl_nvm_access_complete_cmd - NVM_ACCESS commands are completed
@@ -270,22 +270,6 @@ struct iwl_nvm_access_complete_cmd {
} __packed; /* NVM_ACCESS_COMPLETE_CMD_API_S_VER_1 */
/**
- * struct iwl_mcc_update_cmd_v1 - Request the device to update geographic
- * regulatory profile according to the given MCC (Mobile Country Code).
- * The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain.
- * 'ZZ' MCC will be used to switch to NVM default profile; in this case, the
- * MCC in the cmd response will be the relevant MCC in the NVM.
- * @mcc: given mobile country code
- * @source_id: the source from where we got the MCC, see iwl_mcc_source
- * @reserved: reserved for alignment
- */
-struct iwl_mcc_update_cmd_v1 {
- __le16 mcc;
- u8 source_id;
- u8 reserved;
-} __packed; /* LAR_UPDATE_MCC_CMD_API_S_VER_1 */
-
-/**
* struct iwl_mcc_update_cmd - Request the device to update geographic
* regulatory profile according to the given MCC (Mobile Country Code).
* The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain.
@@ -306,7 +290,18 @@ struct iwl_mcc_update_cmd {
} __packed; /* LAR_UPDATE_MCC_CMD_API_S_VER_2 */
/**
- * struct iwl_mcc_update_resp_v1 - response to MCC_UPDATE_CMD.
+ * enum iwl_geo_information - geographic information.
+ * @GEO_NO_INFO: no special info for this geo profile.
+ * @GEO_WMM_ETSI_5GHZ_INFO: this geo profile limits the WMM params
+ * for the 5 GHz band.
+ */
+enum iwl_geo_information {
+ GEO_NO_INFO = 0,
+ GEO_WMM_ETSI_5GHZ_INFO = BIT(0),
+};
+
+/**
+ * struct iwl_mcc_update_resp_v3 - response to MCC_UPDATE_CMD.
* Contains the new channel control profile map, if changed, and the new MCC
* (mobile country code).
* The new MCC may be different than what was requested in MCC_UPDATE_CMD.
@@ -314,30 +309,23 @@ struct iwl_mcc_update_cmd {
* @mcc: the new applied MCC
* @cap: capabilities for all channels which matches the MCC
* @source_id: the MCC source, see iwl_mcc_source
- * @n_channels: number of channels in @channels_data (may be 14, 39, 50 or 51
- * channels, depending on platform)
+ * @time: time elapsed from the MCC test start (in units of 30 seconds)
+ * @geo_info: geographic specific profile information
+ * see &enum iwl_geo_information.
+ * @n_channels: number of channels in @channels_data.
* @channels: channel control data map, DWORD for each channel. Only the first
* 16bits are used.
*/
-struct iwl_mcc_update_resp_v1 {
+struct iwl_mcc_update_resp_v3 {
__le32 status;
__le16 mcc;
u8 cap;
u8 source_id;
+ __le16 time;
+ __le16 geo_info;
__le32 n_channels;
__le32 channels[0];
-} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_1 */
-
-/**
- * enum iwl_geo_information - geographic information.
- * @GEO_NO_INFO: no special info for this geo profile.
- * @GEO_WMM_ETSI_5GHZ_INFO: this geo profile limits the WMM params
- * for the 5 GHz band.
- */
-enum iwl_geo_information {
- GEO_NO_INFO = 0,
- GEO_WMM_ETSI_5GHZ_INFO = BIT(0),
-};
+} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_3 */
/**
* struct iwl_mcc_update_resp - response to MCC_UPDATE_CMD.
@@ -347,25 +335,26 @@ enum iwl_geo_information {
* @status: see &enum iwl_mcc_update_status
* @mcc: the new applied MCC
* @cap: capabilities for all channels which matches the MCC
- * @source_id: the MCC source, see iwl_mcc_source
- * @time: time elapsed from the MCC test start (in 30 seconds TU)
+ * @time: time elapsed from the MCC test start (in units of 30 seconds)
* @geo_info: geographic specific profile information
* see &enum iwl_geo_information.
- * @n_channels: number of channels in @channels_data (may be 14, 39, 50 or 51
- * channels, depending on platform)
+ * @source_id: the MCC source, see iwl_mcc_source
+ * @reserved: for four bytes alignment.
+ * @n_channels: number of channels in @channels_data.
* @channels: channel control data map, DWORD for each channel. Only the first
* 16bits are used.
*/
struct iwl_mcc_update_resp {
__le32 status;
__le16 mcc;
- u8 cap;
- u8 source_id;
+ __le16 cap;
__le16 time;
__le16 geo_info;
+ u8 source_id;
+ u8 reserved[3];
__le32 n_channels;
__le32 channels[0];
-} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_3 */
+} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_4 */
/**
* struct iwl_mcc_chub_notif - chub notifies of mcc change
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h
index a3c77e01863b..286a22da232d 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h
@@ -8,6 +8,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* Copyright(c) 2015 - 2017 Intel Deutschland GmbH
+ * Copyright (C) 2018 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -30,6 +31,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* Copyright(c) 2015 - 2017 Intel Deutschland GmbH
+ * Copyright (C) 2018 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -316,7 +318,9 @@ enum iwl_dev_tx_power_cmd_mode {
IWL_TX_POWER_MODE_SET_DEVICE = 1,
IWL_TX_POWER_MODE_SET_CHAINS = 2,
IWL_TX_POWER_MODE_SET_ACK = 3,
-}; /* TX_POWER_REDUCED_FLAGS_TYPE_API_E_VER_4 */;
+ IWL_TX_POWER_MODE_SET_SAR_TIMER = 4,
+ IWL_TX_POWER_MODE_SET_SAR_TIMER_DEFAULT_TABLE = 5,
+}; /* TX_POWER_REDUCED_FLAGS_TYPE_API_E_VER_5 */;
#define IWL_NUM_CHAIN_LIMITS 2
#define IWL_NUM_SUB_BANDS 5
@@ -350,13 +354,35 @@ struct iwl_dev_tx_power_cmd_v3 {
* reduction.
* @reserved: reserved (padding)
*/
-struct iwl_dev_tx_power_cmd {
+struct iwl_dev_tx_power_cmd_v4 {
/* v4 is just an extension of v3 - keep this here */
struct iwl_dev_tx_power_cmd_v3 v3;
u8 enable_ack_reduction;
u8 reserved[3];
} __packed; /* TX_REDUCED_POWER_API_S_VER_4 */
+/**
+ * struct iwl_dev_tx_power_cmd - TX power reduction command
+ * @v3: version 3 of the command, embedded here for easier software handling
+ * @enable_ack_reduction: enable or disable close range ack TX power
+ * reduction.
+ * @per_chain_restriction_changed: is per_chain_restriction has changed
+ * from last command. used if set_mode is
+ * IWL_TX_POWER_MODE_SET_SAR_TIMER.
+ * note: if not changed, the command is used for keep alive only.
+ * @reserved: reserved (padding)
+ * @timer_period: timer in milliseconds. if expires FW will change to default
+ * BIOS values. relevant if setMode is IWL_TX_POWER_MODE_SET_SAR_TIMER
+ */
+struct iwl_dev_tx_power_cmd {
+ /* v5 is just an extension of v3 - keep this here */
+ struct iwl_dev_tx_power_cmd_v3 v3;
+ u8 enable_ack_reduction;
+ u8 per_chain_restriction_changed;
+ u8 reserved[2];
+ __le32 timer_period;
+} __packed; /* TX_REDUCED_POWER_API_S_VER_5 */
+
#define IWL_NUM_GEO_PROFILES 3
/**
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h
index 087fae91baef..9eddc4dc2ae6 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h
@@ -66,12 +66,24 @@
/**
* enum iwl_tlc_mng_cfg_flags_enum - options for TLC config flags
- * @IWL_TLC_MNG_CFG_FLAGS_STBC_MSK: enable STBC
+ * @IWL_TLC_MNG_CFG_FLAGS_STBC_MSK: enable STBC. For HE this enables STBC for
+ * bandwidths <= 80MHz
* @IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK: enable LDPC
+ * @IWL_TLC_MNG_CFG_FLAGS_HE_STBC_160MHZ_MSK: enable STBC in HE at 160MHz
+ * bandwidth
+ * @IWL_TLC_MNG_CFG_FLAGS_HE_DCM_NSS_1_MSK: enable HE Dual Carrier Modulation
+ * for BPSK (MCS 0) with 1 spatial
+ * stream
+ * @IWL_TLC_MNG_CFG_FLAGS_HE_DCM_NSS_2_MSK: enable HE Dual Carrier Modulation
+ * for BPSK (MCS 0) with 2 spatial
+ * streams
*/
enum iwl_tlc_mng_cfg_flags {
- IWL_TLC_MNG_CFG_FLAGS_STBC_MSK = BIT(0),
- IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK = BIT(1),
+ IWL_TLC_MNG_CFG_FLAGS_STBC_MSK = BIT(0),
+ IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK = BIT(1),
+ IWL_TLC_MNG_CFG_FLAGS_HE_STBC_160MHZ_MSK = BIT(2),
+ IWL_TLC_MNG_CFG_FLAGS_HE_DCM_NSS_1_MSK = BIT(3),
+ IWL_TLC_MNG_CFG_FLAGS_HE_DCM_NSS_2_MSK = BIT(4),
};
/**
@@ -217,66 +229,6 @@ struct iwl_tlc_update_notif {
__le32 amsdu_enabled;
} __packed; /* TLC_MNG_UPDATE_NTFY_API_S_VER_2 */
-/**
- * enum iwl_tlc_debug_flags - debug options
- * @IWL_TLC_DEBUG_FIXED_RATE: set fixed rate for rate scaling
- * @IWL_TLC_DEBUG_STATS_TH: threshold for sending statistics to the driver, in
- * frames
- * @IWL_TLC_DEBUG_STATS_TIME_TH: threshold for sending statistics to the
- * driver, in msec
- * @IWL_TLC_DEBUG_AGG_TIME_LIM: time limit for a BA session
- * @IWL_TLC_DEBUG_AGG_DIS_START_TH: frame with try-count greater than this
- * threshold should not start an aggregation session
- * @IWL_TLC_DEBUG_AGG_FRAME_CNT_LIM: set max number of frames in an aggregation
- * @IWL_TLC_DEBUG_RENEW_ADDBA_DELAY: delay between retries of ADD BA
- * @IWL_TLC_DEBUG_START_AC_RATE_IDX: frames per second to start a BA session
- * @IWL_TLC_DEBUG_NO_FAR_RANGE_TWEAK: disable BW scaling
- */
-enum iwl_tlc_debug_flags {
- IWL_TLC_DEBUG_FIXED_RATE,
- IWL_TLC_DEBUG_STATS_TH,
- IWL_TLC_DEBUG_STATS_TIME_TH,
- IWL_TLC_DEBUG_AGG_TIME_LIM,
- IWL_TLC_DEBUG_AGG_DIS_START_TH,
- IWL_TLC_DEBUG_AGG_FRAME_CNT_LIM,
- IWL_TLC_DEBUG_RENEW_ADDBA_DELAY,
- IWL_TLC_DEBUG_START_AC_RATE_IDX,
- IWL_TLC_DEBUG_NO_FAR_RANGE_TWEAK,
-}; /* TLC_MNG_DEBUG_FLAGS_API_E_VER_1 */
-
-/**
- * struct iwl_dhc_tlc_dbg - fixed debug config
- * @sta_id: bit 0 - enable/disable, bits 1 - 7 hold station id
- * @reserved1: reserved
- * @flags: bitmap of %IWL_TLC_DEBUG_\*
- * @fixed_rate: rate value
- * @stats_threshold: if number of tx-ed frames is greater, send statistics
- * @time_threshold: statistics threshold in usec
- * @agg_time_lim: max agg time
- * @agg_dis_start_threshold: frames with try-cont greater than this count will
- * not be aggregated
- * @agg_frame_count_lim: agg size
- * @addba_retry_delay: delay between retries of ADD BA
- * @start_ac_rate_idx: frames per second to start a BA session
- * @no_far_range_tweak: disable BW scaling
- * @reserved2: reserved
- */
-struct iwl_dhc_tlc_cmd {
- u8 sta_id;
- u8 reserved1[3];
- __le32 flags;
- __le32 fixed_rate;
- __le16 stats_threshold;
- __le16 time_threshold;
- __le16 agg_time_lim;
- __le16 agg_dis_start_threshold;
- __le16 agg_frame_count_lim;
- __le16 addba_retry_delay;
- u8 start_ac_rate_idx[IEEE80211_NUM_ACS];
- u8 no_far_range_tweak;
- u8 reserved2[3];
-} __packed;
-
/*
* These serve as indexes into
* struct iwl_rate_info fw_rate_idx_to_plcp[IWL_RATE_COUNT];
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h
index 2f599353c885..0537496b6eb1 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h
@@ -362,18 +362,49 @@ enum iwl_rx_he_phy {
/* 6 bits reserved */
IWL_RX_HE_PHY_DELIM_EOF = BIT(31),
- /* second dword - MU data */
- IWL_RX_HE_PHY_SIGB_COMPRESSION = BIT_ULL(32 + 0),
- IWL_RX_HE_PHY_SIBG_SYM_OR_USER_NUM_MASK = 0x1e00000000ULL,
+ /* second dword - common data */
IWL_RX_HE_PHY_HE_LTF_NUM_MASK = 0xe000000000ULL,
IWL_RX_HE_PHY_RU_ALLOC_SEC80 = BIT_ULL(32 + 8),
/* trigger encoded */
IWL_RX_HE_PHY_RU_ALLOC_MASK = 0xfe0000000000ULL,
- IWL_RX_HE_PHY_SIGB_MCS_MASK = 0xf000000000000ULL,
- /* 1 bit reserved */
- IWL_RX_HE_PHY_SIGB_DCM = BIT_ULL(32 + 21),
- IWL_RX_HE_PHY_PREAMBLE_PUNC_TYPE_MASK = 0xc0000000000000ULL,
- /* 8 bits reserved */
+ IWL_RX_HE_PHY_INFO_TYPE_MASK = 0xf000000000000000ULL,
+ IWL_RX_HE_PHY_INFO_TYPE_SU = 0x0, /* TSF low valid (first DW) */
+ IWL_RX_HE_PHY_INFO_TYPE_MU = 0x1, /* TSF low/high valid (both DWs) */
+ IWL_RX_HE_PHY_INFO_TYPE_MU_EXT_INFO = 0x2, /* same + SIGB-common0/1/2 valid */
+ IWL_RX_HE_PHY_INFO_TYPE_TB = 0x3, /* TSF low/high valid (both DWs) */
+
+ /* second dword - MU data */
+ IWL_RX_HE_PHY_MU_SIGB_COMPRESSION = BIT_ULL(32 + 0),
+ IWL_RX_HE_PHY_MU_SIBG_SYM_OR_USER_NUM_MASK = 0x1e00000000ULL,
+ IWL_RX_HE_PHY_MU_SIGB_MCS_MASK = 0xf000000000000ULL,
+ IWL_RX_HE_PHY_MU_SIGB_DCM = BIT_ULL(32 + 21),
+ IWL_RX_HE_PHY_MU_PREAMBLE_PUNC_TYPE_MASK = 0xc0000000000000ULL,
+
+ /* second dword - TB data */
+ IWL_RX_HE_PHY_TB_PILOT_TYPE = BIT_ULL(32 + 0),
+ IWL_RX_HE_PHY_TB_LOW_SS_MASK = 0xe00000000ULL
+};
+
+enum iwl_rx_he_sigb_common0 {
+ /* the a1/a2/... is what the PHY/firmware calls the values */
+ IWL_RX_HE_SIGB_COMMON0_CH1_RU0 = 0x000000ff, /* a1 */
+ IWL_RX_HE_SIGB_COMMON0_CH1_RU2 = 0x0000ff00, /* a2 */
+ IWL_RX_HE_SIGB_COMMON0_CH2_RU0 = 0x00ff0000, /* b1 */
+ IWL_RX_HE_SIGB_COMMON0_CH2_RU2 = 0xff000000, /* b2 */
+};
+
+enum iwl_rx_he_sigb_common1 {
+ IWL_RX_HE_SIGB_COMMON1_CH1_RU1 = 0x000000ff, /* c1 */
+ IWL_RX_HE_SIGB_COMMON1_CH1_RU3 = 0x0000ff00, /* c2 */
+ IWL_RX_HE_SIGB_COMMON1_CH2_RU1 = 0x00ff0000, /* d1 */
+ IWL_RX_HE_SIGB_COMMON1_CH2_RU3 = 0xff000000, /* d2 */
+};
+
+enum iwl_rx_he_sigb_common2 {
+ IWL_RX_HE_SIGB_COMMON2_CH1_CTR_RU = 0x0001,
+ IWL_RX_HE_SIGB_COMMON2_CH2_CTR_RU = 0x0002,
+ IWL_RX_HE_SIGB_COMMON2_CH1_CRC_OK = 0x0004,
+ IWL_RX_HE_SIGB_COMMON2_CH2_CRC_OK = 0x0008,
};
/**
@@ -381,15 +412,31 @@ enum iwl_rx_he_phy {
*/
struct iwl_rx_mpdu_desc_v1 {
/* DW7 - carries rss_hash only when rpa_en == 1 */
- /**
- * @rss_hash: RSS hash value
- */
- __le32 rss_hash;
+ union {
+ /**
+ * @rss_hash: RSS hash value
+ */
+ __le32 rss_hash;
+
+ /**
+ * @sigb_common0: for HE sniffer, HE-SIG-B common part 0
+ */
+ __le32 sigb_common0;
+ };
+
/* DW8 - carries filter_match only when rpa_en == 1 */
- /**
- * @filter_match: filter match value
- */
- __le32 filter_match;
+ union {
+ /**
+ * @filter_match: filter match value
+ */
+ __le32 filter_match;
+
+ /**
+ * @sigb_common1: for HE sniffer, HE-SIG-B common part 1
+ */
+ __le32 sigb_common1;
+ };
+
/* DW9 */
/**
* @rate_n_flags: RX rate/flags encoding
@@ -439,15 +486,30 @@ struct iwl_rx_mpdu_desc_v1 {
*/
struct iwl_rx_mpdu_desc_v3 {
/* DW7 - carries filter_match only when rpa_en == 1 */
- /**
- * @filter_match: filter match value
- */
- __le32 filter_match;
+ union {
+ /**
+ * @filter_match: filter match value
+ */
+ __le32 filter_match;
+
+ /**
+ * @sigb_common0: for HE sniffer, HE-SIG-B common part 0
+ */
+ __le32 sigb_common0;
+ };
+
/* DW8 - carries rss_hash only when rpa_en == 1 */
- /**
- * @rss_hash: RSS hash value
- */
- __le32 rss_hash;
+ union {
+ /**
+ * @rss_hash: RSS hash value
+ */
+ __le32 rss_hash;
+
+ /**
+ * @sigb_common1: for HE sniffer, HE-SIG-B common part 1
+ */
+ __le32 sigb_common1;
+ };
/* DW9 */
/**
* @partial_hash: 31:0 ip/tcp header hash
@@ -543,10 +605,18 @@ struct iwl_rx_mpdu_desc {
* @raw_csum: raw checksum (alledgedly unreliable)
*/
__le16 raw_csum;
- /**
- * @l3l4_flags: &enum iwl_rx_l3l4_flags
- */
- __le16 l3l4_flags;
+
+ union {
+ /**
+ * @l3l4_flags: &enum iwl_rx_l3l4_flags
+ */
+ __le16 l3l4_flags;
+
+ /**
+ * @sigb_common2: for HE sniffer, HE-SIG-B common part 2
+ */
+ __le16 sigb_common2;
+ };
/* DW5 */
/**
* @status: &enum iwl_rx_mpdu_status
@@ -574,6 +644,69 @@ struct iwl_rx_mpdu_desc {
#define IWL_RX_DESC_SIZE_V1 offsetofend(struct iwl_rx_mpdu_desc, v1)
+#define IWL_CD_STTS_OPTIMIZED_POS 0
+#define IWL_CD_STTS_OPTIMIZED_MSK 0x01
+#define IWL_CD_STTS_TRANSFER_STATUS_POS 1
+#define IWL_CD_STTS_TRANSFER_STATUS_MSK 0x0E
+#define IWL_CD_STTS_WIFI_STATUS_POS 4
+#define IWL_CD_STTS_WIFI_STATUS_MSK 0xF0
+
+/**
+ * enum iwl_completion_desc_transfer_status - transfer status (bits 1-3)
+ * @IWL_CD_STTS_UNUSED: unused
+ * @IWL_CD_STTS_UNUSED_2: unused
+ * @IWL_CD_STTS_END_TRANSFER: successful transfer complete.
+ * In sniffer mode, when split is used, set in last CD completion. (RX)
+ * @IWL_CD_STTS_OVERFLOW: In sniffer mode, when using split - used for
+ * all CD completion. (RX)
+ * @IWL_CD_STTS_ABORTED: CR abort / close flow. (RX)
+ * @IWL_CD_STTS_ERROR: general error (RX)
+ */
+enum iwl_completion_desc_transfer_status {
+ IWL_CD_STTS_UNUSED,
+ IWL_CD_STTS_UNUSED_2,
+ IWL_CD_STTS_END_TRANSFER,
+ IWL_CD_STTS_OVERFLOW,
+ IWL_CD_STTS_ABORTED,
+ IWL_CD_STTS_ERROR,
+};
+
+/**
+ * enum iwl_completion_desc_wifi_status - wifi status (bits 4-7)
+ * @IWL_CD_STTS_VALID: the packet is valid (RX)
+ * @IWL_CD_STTS_FCS_ERR: frame check sequence error (RX)
+ * @IWL_CD_STTS_SEC_KEY_ERR: error handling the security key of rx (RX)
+ * @IWL_CD_STTS_DECRYPTION_ERR: error decrypting the frame (RX)
+ * @IWL_CD_STTS_DUP: duplicate packet (RX)
+ * @IWL_CD_STTS_ICV_MIC_ERR: MIC error (RX)
+ * @IWL_CD_STTS_INTERNAL_SNAP_ERR: problems removing the snap (RX)
+ * @IWL_CD_STTS_SEC_PORT_FAIL: security port fail (RX)
+ * @IWL_CD_STTS_BA_OLD_SN: block ack received old SN (RX)
+ * @IWL_CD_STTS_QOS_NULL: QoS null packet (RX)
+ * @IWL_CD_STTS_MAC_HDR_ERR: MAC header conversion error (RX)
+ * @IWL_CD_STTS_MAX_RETRANS: reached max number of retransmissions (TX)
+ * @IWL_CD_STTS_EX_LIFETIME: exceeded lifetime (TX)
+ * @IWL_CD_STTS_NOT_USED: completed but not used (RX)
+ * @IWL_CD_STTS_REPLAY_ERR: pn check failed, replay error (RX)
+ */
+enum iwl_completion_desc_wifi_status {
+ IWL_CD_STTS_VALID,
+ IWL_CD_STTS_FCS_ERR,
+ IWL_CD_STTS_SEC_KEY_ERR,
+ IWL_CD_STTS_DECRYPTION_ERR,
+ IWL_CD_STTS_DUP,
+ IWL_CD_STTS_ICV_MIC_ERR,
+ IWL_CD_STTS_INTERNAL_SNAP_ERR,
+ IWL_CD_STTS_SEC_PORT_FAIL,
+ IWL_CD_STTS_BA_OLD_SN,
+ IWL_CD_STTS_QOS_NULL,
+ IWL_CD_STTS_MAC_HDR_ERR,
+ IWL_CD_STTS_MAX_RETRANS,
+ IWL_CD_STTS_EX_LIFETIME,
+ IWL_CD_STTS_NOT_USED,
+ IWL_CD_STTS_REPLAY_ERR,
+};
+
struct iwl_frame_release {
u8 baid;
u8 reserved;
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h
index a17c4a79b8d4..18741889ec30 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h
@@ -262,6 +262,7 @@ enum iwl_scan_channel_flags {
IWL_SCAN_CHANNEL_FLAG_EBS = BIT(0),
IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE = BIT(1),
IWL_SCAN_CHANNEL_FLAG_CACHE_ADD = BIT(2),
+ IWL_SCAN_CHANNEL_FLAG_EBS_FRAG = BIT(3),
};
/* struct iwl_scan_channel_opt - CHANNEL_OPTIMIZATION_API_S
@@ -595,9 +596,12 @@ enum iwl_umac_scan_general_flags {
* enum iwl_umac_scan_general_flags2 - UMAC scan general flags #2
* @IWL_UMAC_SCAN_GEN_FLAGS2_NOTIF_PER_CHNL: Whether to send a complete
* notification per channel or not.
+ * @IWL_UMAC_SCAN_GEN_FLAGS2_ALLOW_CHNL_REORDER: Whether to allow channel
+ * reorder optimization or not.
*/
enum iwl_umac_scan_general_flags2 {
- IWL_UMAC_SCAN_GEN_FLAGS2_NOTIF_PER_CHNL = BIT(0),
+ IWL_UMAC_SCAN_GEN_FLAGS2_NOTIF_PER_CHNL = BIT(0),
+ IWL_UMAC_SCAN_GEN_FLAGS2_ALLOW_CHNL_REORDER = BIT(1),
};
/**
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h b/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h
index dc40cbd52f92..450227f81706 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h
@@ -8,6 +8,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -30,6 +31,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -391,7 +393,7 @@ enum iwl_sta_type {
* @tfd_queue_msk: tfd queues used by this station.
* Obselete for new TX API (9 and above).
* @rx_ba_window: aggregation window size
- * @sp_length: the size of the SP as it appears in the WME IE
+ * @sp_length: the size of the SP in actual number of frames
* @uapsd_acs: 4 LS bits are trigger enabled ACs, 4 MS bits are the deliver
* enabled ACs.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h
index 514b86123d3d..358bdf051e83 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h
@@ -186,7 +186,7 @@ enum iwl_tx_cmd_sec_ctrl {
/*
* TID for non QoS frames - to be written in tid_tspec
*/
-#define IWL_TID_NON_QOS IWL_MAX_TID_COUNT
+#define IWL_TID_NON_QOS 0
/*
* Limits on the retransmissions - to be written in {data,rts}_retry_limit
@@ -747,9 +747,9 @@ enum iwl_mvm_ba_resp_flags {
* @tfd_cnt: number of TFD-Q elements
* @ra_tid_cnt: number of RATID-Q elements
* @tfd: array of TFD queue status updates. See &iwl_mvm_compressed_ba_tfd
- * for details.
+ * for details. Length in @tfd_cnt.
* @ra_tid: array of RA-TID queue status updates. For debug purposes only. See
- * &iwl_mvm_compressed_ba_ratid for more details.
+ * &iwl_mvm_compressed_ba_ratid for more details. Length in @ra_tid_cnt.
*/
struct iwl_mvm_compressed_ba_notif {
__le32 flags;
@@ -766,7 +766,7 @@ struct iwl_mvm_compressed_ba_notif {
__le32 tx_rate;
__le16 tfd_cnt;
__le16 ra_tid_cnt;
- struct iwl_mvm_compressed_ba_tfd tfd[1];
+ struct iwl_mvm_compressed_ba_tfd tfd[0];
struct iwl_mvm_compressed_ba_ratid ra_tid[0];
} __packed; /* COMPRESSED_BA_RES_API_S_VER_4 */
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c
index a31a42e673c4..c16757051f16 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c
@@ -19,9 +19,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program;
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
@@ -243,7 +240,7 @@ static void iwl_fw_dump_fifos(struct iwl_fw_runtime *fwrt,
if (!iwl_trans_grab_nic_access(fwrt->trans, &flags))
return;
- if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_RXF)) {
+ if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_RXF)) {
/* Pull RXF1 */
iwl_fwrt_dump_rxf(fwrt, dump_data,
cfg->lmac[0].rxfifo1_size, 0, 0);
@@ -257,7 +254,7 @@ static void iwl_fw_dump_fifos(struct iwl_fw_runtime *fwrt,
LMAC2_PRPH_OFFSET, 2);
}
- if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_TXF)) {
+ if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_TXF)) {
/* Pull TXF data from LMAC1 */
for (i = 0; i < fwrt->smem_cfg.num_txfifo_entries; i++) {
/* Mark the number of TXF we're pulling now */
@@ -282,7 +279,7 @@ static void iwl_fw_dump_fifos(struct iwl_fw_runtime *fwrt,
}
}
- if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_INTERNAL_TXF) &&
+ if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_INTERNAL_TXF) &&
fw_has_capa(&fwrt->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG)) {
/* Pull UMAC internal TXF data from all TXFs */
@@ -458,8 +455,8 @@ static const struct iwl_prph_range iwl_prph_dump_addr_9000[] = {
{ .start = 0x00a02400, .end = 0x00a02758 },
};
-static void _iwl_read_prph_block(struct iwl_trans *trans, u32 start,
- u32 len_bytes, __le32 *data)
+static void iwl_read_prph_block(struct iwl_trans *trans, u32 start,
+ u32 len_bytes, __le32 *data)
{
u32 i;
@@ -467,21 +464,6 @@ static void _iwl_read_prph_block(struct iwl_trans *trans, u32 start,
*data++ = cpu_to_le32(iwl_read_prph_no_grab(trans, start + i));
}
-static bool iwl_read_prph_block(struct iwl_trans *trans, u32 start,
- u32 len_bytes, __le32 *data)
-{
- unsigned long flags;
- bool success = false;
-
- if (iwl_trans_grab_nic_access(trans, &flags)) {
- success = true;
- _iwl_read_prph_block(trans, start, len_bytes, data);
- iwl_trans_release_nic_access(trans, &flags);
- }
-
- return success;
-}
-
static void iwl_dump_prph(struct iwl_trans *trans,
struct iwl_fw_error_dump_data **data,
const struct iwl_prph_range *iwl_prph_dump_addr,
@@ -507,11 +489,11 @@ static void iwl_dump_prph(struct iwl_trans *trans,
prph = (void *)(*data)->data;
prph->prph_start = cpu_to_le32(iwl_prph_dump_addr[i].start);
- _iwl_read_prph_block(trans, iwl_prph_dump_addr[i].start,
- /* our range is inclusive, hence + 4 */
- iwl_prph_dump_addr[i].end -
- iwl_prph_dump_addr[i].start + 4,
- (void *)prph->data);
+ iwl_read_prph_block(trans, iwl_prph_dump_addr[i].start,
+ /* our range is inclusive, hence + 4 */
+ iwl_prph_dump_addr[i].end -
+ iwl_prph_dump_addr[i].start + 4,
+ (void *)prph->data);
*data = iwl_fw_error_next_data(*data);
}
@@ -556,42 +538,130 @@ static struct scatterlist *alloc_sgtable(int size)
return table;
}
-void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
+static int iwl_fw_get_prph_len(struct iwl_fw_runtime *fwrt)
+{
+ u32 prph_len = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr_comm);
+ i++) {
+ /* The range includes both boundaries */
+ int num_bytes_in_chunk =
+ iwl_prph_dump_addr_comm[i].end -
+ iwl_prph_dump_addr_comm[i].start + 4;
+
+ prph_len += sizeof(struct iwl_fw_error_dump_data) +
+ sizeof(struct iwl_fw_error_dump_prph) +
+ num_bytes_in_chunk;
+ }
+
+ if (fwrt->trans->cfg->mq_rx_supported) {
+ for (i = 0; i <
+ ARRAY_SIZE(iwl_prph_dump_addr_9000); i++) {
+ /* The range includes both boundaries */
+ int num_bytes_in_chunk =
+ iwl_prph_dump_addr_9000[i].end -
+ iwl_prph_dump_addr_9000[i].start + 4;
+
+ prph_len += sizeof(struct iwl_fw_error_dump_data) +
+ sizeof(struct iwl_fw_error_dump_prph) +
+ num_bytes_in_chunk;
+ }
+ }
+ return prph_len;
+}
+
+static void iwl_fw_dump_mem(struct iwl_fw_runtime *fwrt,
+ struct iwl_fw_error_dump_data **dump_data,
+ u32 len, u32 ofs, u32 type)
+{
+ struct iwl_fw_error_dump_mem *dump_mem;
+
+ if (!len)
+ return;
+
+ (*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
+ (*dump_data)->len = cpu_to_le32(len + sizeof(*dump_mem));
+ dump_mem = (void *)(*dump_data)->data;
+ dump_mem->type = cpu_to_le32(type);
+ dump_mem->offset = cpu_to_le32(ofs);
+ iwl_trans_read_mem_bytes(fwrt->trans, ofs, dump_mem->data, len);
+ *dump_data = iwl_fw_error_next_data(*dump_data);
+
+ IWL_DEBUG_INFO(fwrt, "WRT memory dump. Type=%u\n", dump_mem->type);
+}
+
+#define ADD_LEN(len, item_len, const_len) \
+ do {size_t item = item_len; len += (!!item) * const_len + item; } \
+ while (0)
+
+static int iwl_fw_fifo_len(struct iwl_fw_runtime *fwrt,
+ struct iwl_fwrt_shared_mem_cfg *mem_cfg)
+{
+ size_t hdr_len = sizeof(struct iwl_fw_error_dump_data) +
+ sizeof(struct iwl_fw_error_dump_fifo);
+ u32 fifo_len = 0;
+ int i;
+
+ if (!(fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_RXF)))
+ goto dump_txf;
+
+ /* Count RXF2 size */
+ ADD_LEN(fifo_len, mem_cfg->rxfifo2_size, hdr_len);
+
+ /* Count RXF1 sizes */
+ for (i = 0; i < mem_cfg->num_lmacs; i++)
+ ADD_LEN(fifo_len, mem_cfg->lmac[i].rxfifo1_size, hdr_len);
+
+dump_txf:
+ if (!(fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_TXF)))
+ goto dump_internal_txf;
+
+ /* Count TXF sizes */
+ for (i = 0; i < mem_cfg->num_lmacs; i++) {
+ int j;
+
+ for (j = 0; j < mem_cfg->num_txfifo_entries; j++)
+ ADD_LEN(fifo_len, mem_cfg->lmac[i].txfifo_size[j],
+ hdr_len);
+ }
+
+dump_internal_txf:
+ if (!((fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_INTERNAL_TXF)) &&
+ fw_has_capa(&fwrt->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG)))
+ goto out;
+
+ for (i = 0; i < ARRAY_SIZE(mem_cfg->internal_txfifo_size); i++)
+ ADD_LEN(fifo_len, mem_cfg->internal_txfifo_size[i], hdr_len);
+
+out:
+ return fifo_len;
+}
+
+static struct iwl_fw_error_dump_file *
+_iwl_fw_error_dump(struct iwl_fw_runtime *fwrt,
+ struct iwl_fw_dump_ptrs *fw_error_dump)
{
struct iwl_fw_error_dump_file *dump_file;
struct iwl_fw_error_dump_data *dump_data;
struct iwl_fw_error_dump_info *dump_info;
- struct iwl_fw_error_dump_mem *dump_mem;
struct iwl_fw_error_dump_smem_cfg *dump_smem_cfg;
struct iwl_fw_error_dump_trigger_desc *dump_trig;
- struct iwl_fw_dump_ptrs *fw_error_dump;
- struct scatterlist *sg_dump_data;
u32 sram_len, sram_ofs;
- const struct iwl_fw_dbg_mem_seg_tlv *fw_dbg_mem = fwrt->fw->dbg_mem_tlv;
+ const struct iwl_fw_dbg_mem_seg_tlv *fw_mem = fwrt->fw->dbg.mem_tlv;
struct iwl_fwrt_shared_mem_cfg *mem_cfg = &fwrt->smem_cfg;
- u32 file_len, fifo_data_len = 0, prph_len = 0, radio_len = 0;
- u32 smem_len = fwrt->fw->n_dbg_mem_tlv ? 0 : fwrt->trans->cfg->smem_len;
- u32 sram2_len = fwrt->fw->n_dbg_mem_tlv ?
+ u32 file_len, fifo_len = 0, prph_len = 0, radio_len = 0;
+ u32 smem_len = fwrt->fw->dbg.n_mem_tlv ? 0 : fwrt->trans->cfg->smem_len;
+ u32 sram2_len = fwrt->fw->dbg.n_mem_tlv ?
0 : fwrt->trans->cfg->dccm2_len;
bool monitor_dump_only = false;
int i;
- IWL_DEBUG_INFO(fwrt, "WRT dump start\n");
-
- /* there's no point in fw dump if the bus is dead */
- if (test_bit(STATUS_TRANS_DEAD, &fwrt->trans->status)) {
- IWL_ERR(fwrt, "Skip fw error dump since bus is dead\n");
- goto out;
- }
-
if (fwrt->dump.trig &&
fwrt->dump.trig->mode & IWL_FW_DBG_TRIGGER_MONITOR_ONLY)
monitor_dump_only = true;
- fw_error_dump = kzalloc(sizeof(*fw_error_dump), GFP_KERNEL);
- if (!fw_error_dump)
- goto out;
-
/* SRAM - include stack CCM if driver knows the values for it */
if (!fwrt->trans->cfg->dccm_offset || !fwrt->trans->cfg->dccm_len) {
const struct fw_img *img;
@@ -606,138 +676,43 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
/* reading RXF/TXF sizes */
if (test_bit(STATUS_FW_ERROR, &fwrt->trans->status)) {
- fifo_data_len = 0;
-
- if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_RXF)) {
-
- /* Count RXF2 size */
- if (mem_cfg->rxfifo2_size) {
- /* Add header info */
- fifo_data_len +=
- mem_cfg->rxfifo2_size +
- sizeof(*dump_data) +
- sizeof(struct iwl_fw_error_dump_fifo);
- }
-
- /* Count RXF1 sizes */
- for (i = 0; i < mem_cfg->num_lmacs; i++) {
- if (!mem_cfg->lmac[i].rxfifo1_size)
- continue;
-
- /* Add header info */
- fifo_data_len +=
- mem_cfg->lmac[i].rxfifo1_size +
- sizeof(*dump_data) +
- sizeof(struct iwl_fw_error_dump_fifo);
- }
- }
-
- if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_TXF)) {
- size_t fifo_const_len = sizeof(*dump_data) +
- sizeof(struct iwl_fw_error_dump_fifo);
-
- /* Count TXF sizes */
- for (i = 0; i < mem_cfg->num_lmacs; i++) {
- int j;
-
- for (j = 0; j < mem_cfg->num_txfifo_entries;
- j++) {
- if (!mem_cfg->lmac[i].txfifo_size[j])
- continue;
-
- /* Add header info */
- fifo_data_len +=
- fifo_const_len +
- mem_cfg->lmac[i].txfifo_size[j];
- }
- }
- }
-
- if ((fwrt->fw->dbg_dump_mask &
- BIT(IWL_FW_ERROR_DUMP_INTERNAL_TXF)) &&
- fw_has_capa(&fwrt->fw->ucode_capa,
- IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG)) {
- for (i = 0;
- i < ARRAY_SIZE(mem_cfg->internal_txfifo_size);
- i++) {
- if (!mem_cfg->internal_txfifo_size[i])
- continue;
-
- /* Add header info */
- fifo_data_len +=
- mem_cfg->internal_txfifo_size[i] +
- sizeof(*dump_data) +
- sizeof(struct iwl_fw_error_dump_fifo);
- }
- }
+ fifo_len = iwl_fw_fifo_len(fwrt, mem_cfg);
/* Make room for PRPH registers */
if (!fwrt->trans->cfg->gen2 &&
- fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_PRPH)) {
- for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr_comm);
- i++) {
- /* The range includes both boundaries */
- int num_bytes_in_chunk =
- iwl_prph_dump_addr_comm[i].end -
- iwl_prph_dump_addr_comm[i].start + 4;
-
- prph_len += sizeof(*dump_data) +
- sizeof(struct iwl_fw_error_dump_prph) +
- num_bytes_in_chunk;
- }
- }
-
- if (!fwrt->trans->cfg->gen2 &&
- fwrt->trans->cfg->mq_rx_supported &&
- fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_PRPH)) {
- for (i = 0; i <
- ARRAY_SIZE(iwl_prph_dump_addr_9000); i++) {
- /* The range includes both boundaries */
- int num_bytes_in_chunk =
- iwl_prph_dump_addr_9000[i].end -
- iwl_prph_dump_addr_9000[i].start + 4;
-
- prph_len += sizeof(*dump_data) +
- sizeof(struct iwl_fw_error_dump_prph) +
- num_bytes_in_chunk;
- }
- }
+ fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_PRPH))
+ prph_len += iwl_fw_get_prph_len(fwrt);
if (fwrt->trans->cfg->device_family == IWL_DEVICE_FAMILY_7000 &&
- fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_RADIO_REG))
+ fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_RADIO_REG))
radio_len = sizeof(*dump_data) + RADIO_REG_MAX_READ;
}
- file_len = sizeof(*dump_file) +
- fifo_data_len +
- prph_len +
- radio_len;
+ file_len = sizeof(*dump_file) + fifo_len + prph_len + radio_len;
- if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_DEV_FW_INFO))
+ if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_DEV_FW_INFO))
file_len += sizeof(*dump_data) + sizeof(*dump_info);
- if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM_CFG))
+ if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM_CFG))
file_len += sizeof(*dump_data) + sizeof(*dump_smem_cfg);
- if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM)) {
- /* Make room for the SMEM, if it exists */
- if (smem_len)
- file_len += sizeof(*dump_data) + sizeof(*dump_mem) +
- smem_len;
-
- /* Make room for the secondary SRAM, if it exists */
- if (sram2_len)
- file_len += sizeof(*dump_data) + sizeof(*dump_mem) +
- sram2_len;
-
- /* Make room for MEM segments */
- for (i = 0; i < fwrt->fw->n_dbg_mem_tlv; i++) {
- file_len += sizeof(*dump_data) + sizeof(*dump_mem) +
- le32_to_cpu(fw_dbg_mem[i].len);
- }
+ if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM)) {
+ size_t hdr_len = sizeof(*dump_data) +
+ sizeof(struct iwl_fw_error_dump_mem);
+
+ /* Dump SRAM only if no mem_tlvs */
+ if (!fwrt->fw->dbg.n_mem_tlv)
+ ADD_LEN(file_len, sram_len, hdr_len);
+
+ /* Make room for all mem types that exist */
+ ADD_LEN(file_len, smem_len, hdr_len);
+ ADD_LEN(file_len, sram2_len, hdr_len);
+
+ for (i = 0; i < fwrt->fw->dbg.n_mem_tlv; i++)
+ ADD_LEN(file_len, le32_to_cpu(fw_mem[i].len), hdr_len);
}
/* Make room for fw's virtual image pages, if it exists */
- if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_PAGING) &&
+ if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_PAGING) &&
!fwrt->trans->cfg->gen2 &&
fwrt->fw->img[fwrt->cur_fw_img].paging_mem_size &&
fwrt->fw_paging_db[0].fw_paging_block)
@@ -746,33 +721,32 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
sizeof(struct iwl_fw_error_dump_paging) +
PAGING_BLOCK_SIZE);
+ if (iwl_fw_dbg_is_d3_debug_enabled(fwrt) && fwrt->dump.d3_debug_data) {
+ file_len += sizeof(*dump_data) +
+ fwrt->trans->cfg->d3_debug_data_length * 2;
+ }
+
/* If we only want a monitor dump, reset the file length */
if (monitor_dump_only) {
file_len = sizeof(*dump_file) + sizeof(*dump_data) * 2 +
sizeof(*dump_info) + sizeof(*dump_smem_cfg);
}
- if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_ERROR_INFO) &&
+ if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_ERROR_INFO) &&
fwrt->dump.desc)
file_len += sizeof(*dump_data) + sizeof(*dump_trig) +
fwrt->dump.desc->len;
- if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM) &&
- !fwrt->fw->n_dbg_mem_tlv)
- file_len += sizeof(*dump_data) + sram_len + sizeof(*dump_mem);
-
dump_file = vzalloc(file_len);
- if (!dump_file) {
- kfree(fw_error_dump);
- goto out;
- }
+ if (!dump_file)
+ return NULL;
fw_error_dump->fwrt_ptr = dump_file;
dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER);
dump_data = (void *)dump_file->data;
- if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_DEV_FW_INFO)) {
+ if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_DEV_FW_INFO)) {
dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_DEV_FW_INFO);
dump_data->len = cpu_to_le32(sizeof(*dump_info));
dump_info = (void *)dump_data->data;
@@ -793,7 +767,7 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
dump_data = iwl_fw_error_next_data(dump_data);
}
- if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM_CFG)) {
+ if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM_CFG)) {
/* Dump shared memory configuration */
dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_CFG);
dump_data->len = cpu_to_le32(sizeof(*dump_smem_cfg));
@@ -824,13 +798,13 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
}
/* We only dump the FIFOs if the FW is in error state */
- if (test_bit(STATUS_FW_ERROR, &fwrt->trans->status)) {
+ if (fifo_len) {
iwl_fw_dump_fifos(fwrt, &dump_data);
if (radio_len)
iwl_read_radio_regs(fwrt, &dump_data);
}
- if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_ERROR_INFO) &&
+ if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_ERROR_INFO) &&
fwrt->dump.desc) {
dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_ERROR_INFO);
dump_data->len = cpu_to_le32(sizeof(*dump_trig) +
@@ -844,89 +818,54 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
/* In case we only want monitor dump, skip to dump trasport data */
if (monitor_dump_only)
- goto dump_trans_data;
-
- if (!fwrt->fw->n_dbg_mem_tlv &&
- fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM)) {
- dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
- dump_data->len = cpu_to_le32(sram_len + sizeof(*dump_mem));
- dump_mem = (void *)dump_data->data;
- dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SRAM);
- dump_mem->offset = cpu_to_le32(sram_ofs);
- iwl_trans_read_mem_bytes(fwrt->trans, sram_ofs, dump_mem->data,
- sram_len);
- dump_data = iwl_fw_error_next_data(dump_data);
- }
+ goto out;
+
+ if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM)) {
+ const struct iwl_fw_dbg_mem_seg_tlv *fw_dbg_mem =
+ fwrt->fw->dbg.mem_tlv;
- for (i = 0; i < fwrt->fw->n_dbg_mem_tlv; i++) {
- u32 len = le32_to_cpu(fw_dbg_mem[i].len);
- u32 ofs = le32_to_cpu(fw_dbg_mem[i].ofs);
- bool success;
-
- if (!(fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM)))
- break;
-
- dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
- dump_data->len = cpu_to_le32(len + sizeof(*dump_mem));
- dump_mem = (void *)dump_data->data;
- dump_mem->type = fw_dbg_mem[i].data_type;
- dump_mem->offset = cpu_to_le32(ofs);
-
- IWL_DEBUG_INFO(fwrt, "WRT memory dump. Type=%u\n",
- dump_mem->type);
-
- switch (dump_mem->type & cpu_to_le32(FW_DBG_MEM_TYPE_MASK)) {
- case cpu_to_le32(FW_DBG_MEM_TYPE_REGULAR):
- iwl_trans_read_mem_bytes(fwrt->trans, ofs,
- dump_mem->data,
- len);
- success = true;
- break;
- case cpu_to_le32(FW_DBG_MEM_TYPE_PRPH):
- success = iwl_read_prph_block(fwrt->trans, ofs, len,
- (void *)dump_mem->data);
- break;
- default:
- /*
- * shouldn't get here, we ignored this kind
- * of TLV earlier during the TLV parsing?!
- */
- WARN_ON(1);
- success = false;
+ if (!fwrt->fw->dbg.n_mem_tlv)
+ iwl_fw_dump_mem(fwrt, &dump_data, sram_len, sram_ofs,
+ IWL_FW_ERROR_DUMP_MEM_SRAM);
+
+ for (i = 0; i < fwrt->fw->dbg.n_mem_tlv; i++) {
+ u32 len = le32_to_cpu(fw_dbg_mem[i].len);
+ u32 ofs = le32_to_cpu(fw_dbg_mem[i].ofs);
+
+ iwl_fw_dump_mem(fwrt, &dump_data, len, ofs,
+ le32_to_cpu(fw_dbg_mem[i].data_type));
}
- if (success)
- dump_data = iwl_fw_error_next_data(dump_data);
- }
+ iwl_fw_dump_mem(fwrt, &dump_data, smem_len,
+ fwrt->trans->cfg->smem_offset,
+ IWL_FW_ERROR_DUMP_MEM_SMEM);
- if (smem_len && fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM)) {
- IWL_DEBUG_INFO(fwrt, "WRT SMEM dump\n");
- dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
- dump_data->len = cpu_to_le32(smem_len + sizeof(*dump_mem));
- dump_mem = (void *)dump_data->data;
- dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SMEM);
- dump_mem->offset = cpu_to_le32(fwrt->trans->cfg->smem_offset);
- iwl_trans_read_mem_bytes(fwrt->trans,
- fwrt->trans->cfg->smem_offset,
- dump_mem->data, smem_len);
- dump_data = iwl_fw_error_next_data(dump_data);
+ iwl_fw_dump_mem(fwrt, &dump_data, sram2_len,
+ fwrt->trans->cfg->dccm2_offset,
+ IWL_FW_ERROR_DUMP_MEM_SRAM);
}
- if (sram2_len && fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM)) {
- IWL_DEBUG_INFO(fwrt, "WRT SRAM dump\n");
- dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
- dump_data->len = cpu_to_le32(sram2_len + sizeof(*dump_mem));
- dump_mem = (void *)dump_data->data;
- dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SRAM);
- dump_mem->offset = cpu_to_le32(fwrt->trans->cfg->dccm2_offset);
- iwl_trans_read_mem_bytes(fwrt->trans,
- fwrt->trans->cfg->dccm2_offset,
- dump_mem->data, sram2_len);
+ if (iwl_fw_dbg_is_d3_debug_enabled(fwrt) && fwrt->dump.d3_debug_data) {
+ u32 addr = fwrt->trans->cfg->d3_debug_data_base_addr;
+ size_t data_size = fwrt->trans->cfg->d3_debug_data_length;
+
+ dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_D3_DEBUG_DATA);
+ dump_data->len = cpu_to_le32(data_size * 2);
+
+ memcpy(dump_data->data, fwrt->dump.d3_debug_data, data_size);
+
+ kfree(fwrt->dump.d3_debug_data);
+ fwrt->dump.d3_debug_data = NULL;
+
+ iwl_trans_read_mem_bytes(fwrt->trans, addr,
+ dump_data->data + data_size,
+ data_size);
+
dump_data = iwl_fw_error_next_data(dump_data);
}
/* Dump fw's virtual image */
- if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_PAGING) &&
+ if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_PAGING) &&
!fwrt->trans->cfg->gen2 &&
fwrt->fw->img[fwrt->cur_fw_img].paging_mem_size &&
fwrt->fw_paging_db[0].fw_paging_block) {
@@ -962,13 +901,44 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
ARRAY_SIZE(iwl_prph_dump_addr_9000));
}
-dump_trans_data:
+out:
+ dump_file->file_len = cpu_to_le32(file_len);
+ return dump_file;
+}
+
+void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
+{
+ struct iwl_fw_dump_ptrs *fw_error_dump;
+ struct iwl_fw_error_dump_file *dump_file;
+ struct scatterlist *sg_dump_data;
+ u32 file_len;
+
+ IWL_DEBUG_INFO(fwrt, "WRT dump start\n");
+
+ /* there's no point in fw dump if the bus is dead */
+ if (test_bit(STATUS_TRANS_DEAD, &fwrt->trans->status)) {
+ IWL_ERR(fwrt, "Skip fw error dump since bus is dead\n");
+ goto out;
+ }
+
+ fw_error_dump = kzalloc(sizeof(*fw_error_dump), GFP_KERNEL);
+ if (!fw_error_dump)
+ goto out;
+
+ dump_file = _iwl_fw_error_dump(fwrt, fw_error_dump);
+ if (!dump_file) {
+ kfree(fw_error_dump);
+ goto out;
+ }
+
fw_error_dump->trans_ptr = iwl_trans_dump_data(fwrt->trans,
fwrt->dump.trig);
+ file_len = le32_to_cpu(dump_file->file_len);
fw_error_dump->fwrt_len = file_len;
- if (fw_error_dump->trans_ptr)
+ if (fw_error_dump->trans_ptr) {
file_len += fw_error_dump->trans_ptr->len;
- dump_file->file_len = cpu_to_le32(file_len);
+ dump_file->file_len = cpu_to_le32(file_len);
+ }
sg_dump_data = alloc_sgtable(file_len);
if (sg_dump_data) {
@@ -1003,20 +973,39 @@ const struct iwl_fw_dump_desc iwl_dump_desc_assert = {
};
IWL_EXPORT_SYMBOL(iwl_dump_desc_assert);
-int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt,
- const struct iwl_fw_dump_desc *desc,
- const struct iwl_fw_dbg_trigger_tlv *trigger)
+void iwl_fw_alive_error_dump(struct iwl_fw_runtime *fwrt)
{
- unsigned int delay = 0;
+ struct iwl_fw_dump_desc *iwl_dump_desc_no_alive =
+ kmalloc(sizeof(*iwl_dump_desc_no_alive), GFP_KERNEL);
+
+ if (!iwl_dump_desc_no_alive)
+ return;
- if (trigger)
- delay = msecs_to_jiffies(le32_to_cpu(trigger->stop_delay));
+ iwl_dump_desc_no_alive->trig_desc.type =
+ cpu_to_le32(FW_DBG_TRIGGER_NO_ALIVE);
+ iwl_dump_desc_no_alive->len = 0;
+
+ if (WARN_ON(fwrt->dump.desc))
+ iwl_fw_free_dump_desc(fwrt);
+ IWL_WARN(fwrt, "Collecting data: trigger %d fired.\n",
+ FW_DBG_TRIGGER_NO_ALIVE);
+
+ fwrt->dump.desc = iwl_dump_desc_no_alive;
+ iwl_fw_error_dump(fwrt);
+ clear_bit(IWL_FWRT_STATUS_WAIT_ALIVE, &fwrt->status);
+}
+IWL_EXPORT_SYMBOL(iwl_fw_alive_error_dump);
+
+int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt,
+ const struct iwl_fw_dump_desc *desc, void *trigger,
+ unsigned int delay)
+{
/*
* If the loading of the FW completed successfully, the next step is to
* get the SMEM config data. Thus, if fwrt->smem_cfg.num_lmacs is non
* zero, the FW was already loaded successully. If the state is "NO_FW"
- * in such a case - WARN and exit, since FW may be dead. Otherwise, we
+ * in such a case - exit, since FW may be dead. Otherwise, we
* can try to collect the data, since FW might just not be fully
* loaded (no "ALIVE" yet), and the debug data is accessible.
*
@@ -1024,12 +1013,12 @@ int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt,
* config. In such a case, due to HW access problems, we might
* collect garbage.
*/
- if (WARN((fwrt->trans->state == IWL_TRANS_NO_FW) &&
- fwrt->smem_cfg.num_lmacs,
- "Can't collect dbg data when FW isn't alive\n"))
+ if (fwrt->trans->state == IWL_TRANS_NO_FW &&
+ fwrt->smem_cfg.num_lmacs)
return -EIO;
- if (test_and_set_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status))
+ if (test_and_set_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status) ||
+ test_bit(IWL_FWRT_STATUS_WAIT_ALIVE, &fwrt->status))
return -EBUSY;
if (WARN_ON(fwrt->dump.desc))
@@ -1050,25 +1039,38 @@ IWL_EXPORT_SYMBOL(iwl_fw_dbg_collect_desc);
int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt,
enum iwl_fw_dbg_trigger trig,
const char *str, size_t len,
- const struct iwl_fw_dbg_trigger_tlv *trigger)
+ struct iwl_fw_dbg_trigger_tlv *trigger)
{
struct iwl_fw_dump_desc *desc;
+ unsigned int delay = 0;
- if (trigger && trigger->flags & IWL_FW_DBG_FORCE_RESTART) {
- IWL_WARN(fwrt, "Force restart: trigger %d fired.\n", trig);
- iwl_force_nmi(fwrt->trans);
- return 0;
+ if (trigger) {
+ u16 occurrences = le16_to_cpu(trigger->occurrences) - 1;
+
+ if (!le16_to_cpu(trigger->occurrences))
+ return 0;
+
+ if (trigger->flags & IWL_FW_DBG_FORCE_RESTART) {
+ IWL_WARN(fwrt, "Force restart: trigger %d fired.\n",
+ trig);
+ iwl_force_nmi(fwrt->trans);
+ return 0;
+ }
+
+ trigger->occurrences = cpu_to_le16(occurrences);
+ delay = le16_to_cpu(trigger->trig_dis_ms);
}
desc = kzalloc(sizeof(*desc) + len, GFP_ATOMIC);
if (!desc)
return -ENOMEM;
+
desc->len = len;
desc->trig_desc.type = cpu_to_le32(trig);
memcpy(desc->trig_desc.data, str, len);
- return iwl_fw_dbg_collect_desc(fwrt, desc, trigger);
+ return iwl_fw_dbg_collect_desc(fwrt, desc, trigger, delay);
}
IWL_EXPORT_SYMBOL(iwl_fw_dbg_collect);
@@ -1076,13 +1078,9 @@ int iwl_fw_dbg_collect_trig(struct iwl_fw_runtime *fwrt,
struct iwl_fw_dbg_trigger_tlv *trigger,
const char *fmt, ...)
{
- u16 occurrences = le16_to_cpu(trigger->occurrences);
int ret, len = 0;
char buf[64];
- if (!occurrences)
- return 0;
-
if (fmt) {
va_list ap;
@@ -1105,7 +1103,6 @@ int iwl_fw_dbg_collect_trig(struct iwl_fw_runtime *fwrt,
if (ret)
return ret;
- trigger->occurrences = cpu_to_le16(occurrences - 1);
return 0;
}
IWL_EXPORT_SYMBOL(iwl_fw_dbg_collect_trig);
@@ -1116,29 +1113,26 @@ int iwl_fw_start_dbg_conf(struct iwl_fw_runtime *fwrt, u8 conf_id)
int ret;
int i;
- if (WARN_ONCE(conf_id >= ARRAY_SIZE(fwrt->fw->dbg_conf_tlv),
+ if (WARN_ONCE(conf_id >= ARRAY_SIZE(fwrt->fw->dbg.conf_tlv),
"Invalid configuration %d\n", conf_id))
return -EINVAL;
/* EARLY START - firmware's configuration is hard coded */
- if ((!fwrt->fw->dbg_conf_tlv[conf_id] ||
- !fwrt->fw->dbg_conf_tlv[conf_id]->num_of_hcmds) &&
+ if ((!fwrt->fw->dbg.conf_tlv[conf_id] ||
+ !fwrt->fw->dbg.conf_tlv[conf_id]->num_of_hcmds) &&
conf_id == FW_DBG_START_FROM_ALIVE)
return 0;
- if (!fwrt->fw->dbg_conf_tlv[conf_id])
+ if (!fwrt->fw->dbg.conf_tlv[conf_id])
return -EINVAL;
if (fwrt->dump.conf != FW_DBG_INVALID)
IWL_WARN(fwrt, "FW already configured (%d) - re-configuring\n",
fwrt->dump.conf);
- /* start default config marker cmd for syncing logs */
- iwl_fw_trigger_timestamp(fwrt, 1);
-
/* Send all HCMDs for configuring the FW debug */
- ptr = (void *)&fwrt->fw->dbg_conf_tlv[conf_id]->hcmd;
- for (i = 0; i < fwrt->fw->dbg_conf_tlv[conf_id]->num_of_hcmds; i++) {
+ ptr = (void *)&fwrt->fw->dbg.conf_tlv[conf_id]->hcmd;
+ for (i = 0; i < fwrt->fw->dbg.conf_tlv[conf_id]->num_of_hcmds; i++) {
struct iwl_fw_dbg_conf_hcmd *cmd = (void *)ptr;
struct iwl_host_cmd hcmd = {
.id = cmd->id,
@@ -1160,13 +1154,14 @@ int iwl_fw_start_dbg_conf(struct iwl_fw_runtime *fwrt, u8 conf_id)
}
IWL_EXPORT_SYMBOL(iwl_fw_start_dbg_conf);
-void iwl_fw_error_dump_wk(struct work_struct *work)
+/* this function assumes dump_start was called beforehand and dump_end will be
+ * called afterwards
+ */
+void iwl_fw_dbg_collect_sync(struct iwl_fw_runtime *fwrt)
{
- struct iwl_fw_runtime *fwrt =
- container_of(work, struct iwl_fw_runtime, dump.wk.work);
+ struct iwl_fw_dbg_params params = {0};
- if (fwrt->ops && fwrt->ops->dump_start &&
- fwrt->ops->dump_start(fwrt->ops_ctx))
+ if (!test_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status))
return;
if (fwrt->ops && fwrt->ops->fw_running &&
@@ -1174,44 +1169,58 @@ void iwl_fw_error_dump_wk(struct work_struct *work)
IWL_ERR(fwrt, "Firmware not running - cannot dump error\n");
iwl_fw_free_dump_desc(fwrt);
clear_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status);
- goto out;
+ return;
}
- if (fwrt->trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
- /* stop recording */
- iwl_fw_dbg_stop_recording(fwrt);
-
- iwl_fw_error_dump(fwrt);
-
- /* start recording again if the firmware is not crashed */
- if (!test_bit(STATUS_FW_ERROR, &fwrt->trans->status) &&
- fwrt->fw->dbg_dest_tlv) {
- iwl_clear_bits_prph(fwrt->trans,
- MON_BUFF_SAMPLE_CTL, 0x100);
- iwl_clear_bits_prph(fwrt->trans,
- MON_BUFF_SAMPLE_CTL, 0x1);
- iwl_set_bits_prph(fwrt->trans,
- MON_BUFF_SAMPLE_CTL, 0x1);
- }
- } else {
- u32 in_sample = iwl_read_prph(fwrt->trans, DBGC_IN_SAMPLE);
- u32 out_ctrl = iwl_read_prph(fwrt->trans, DBGC_OUT_CTRL);
+ iwl_fw_dbg_stop_recording(fwrt, &params);
+
+ iwl_fw_error_dump(fwrt);
- iwl_fw_dbg_stop_recording(fwrt);
+ /* start recording again if the firmware is not crashed */
+ if (!test_bit(STATUS_FW_ERROR, &fwrt->trans->status) &&
+ fwrt->fw->dbg.dest_tlv) {
/* wait before we collect the data till the DBGC stop */
udelay(500);
+ iwl_fw_dbg_restart_recording(fwrt, &params);
+ }
+}
+IWL_EXPORT_SYMBOL(iwl_fw_dbg_collect_sync);
- iwl_fw_error_dump(fwrt);
+void iwl_fw_error_dump_wk(struct work_struct *work)
+{
+ struct iwl_fw_runtime *fwrt =
+ container_of(work, struct iwl_fw_runtime, dump.wk.work);
+
+ if (fwrt->ops && fwrt->ops->dump_start &&
+ fwrt->ops->dump_start(fwrt->ops_ctx))
+ return;
+
+ iwl_fw_dbg_collect_sync(fwrt);
- /* start recording again if the firmware is not crashed */
- if (!test_bit(STATUS_FW_ERROR, &fwrt->trans->status) &&
- fwrt->fw->dbg_dest_tlv) {
- iwl_write_prph(fwrt->trans, DBGC_IN_SAMPLE, in_sample);
- iwl_write_prph(fwrt->trans, DBGC_OUT_CTRL, out_ctrl);
- }
- }
-out:
if (fwrt->ops && fwrt->ops->dump_end)
fwrt->ops->dump_end(fwrt->ops_ctx);
}
+void iwl_fw_dbg_read_d3_debug_data(struct iwl_fw_runtime *fwrt)
+{
+ const struct iwl_cfg *cfg = fwrt->trans->cfg;
+
+ if (!iwl_fw_dbg_is_d3_debug_enabled(fwrt))
+ return;
+
+ if (!fwrt->dump.d3_debug_data) {
+ fwrt->dump.d3_debug_data = kmalloc(cfg->d3_debug_data_length,
+ GFP_KERNEL);
+ if (!fwrt->dump.d3_debug_data) {
+ IWL_ERR(fwrt,
+ "failed to allocate memory for D3 debug data\n");
+ return;
+ }
+ }
+
+ /* if the buffer holds previous debug data it is overwritten */
+ iwl_trans_read_mem_bytes(fwrt->trans, cfg->d3_debug_data_base_addr,
+ fwrt->dump.d3_debug_data,
+ cfg->d3_debug_data_length);
+}
+IWL_EXPORT_SYMBOL(iwl_fw_dbg_read_d3_debug_data);
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h
index 507d9a49fa97..6f8d3256f7b0 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h
@@ -19,9 +19,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program;
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
@@ -74,6 +71,7 @@
#include "iwl-io.h"
#include "file.h"
#include "error-dump.h"
+#include "api/commands.h"
/**
* struct iwl_fw_dump_desc - describes the dump
@@ -86,6 +84,16 @@ struct iwl_fw_dump_desc {
struct iwl_fw_error_dump_trigger_desc trig_desc;
};
+/**
+ * struct iwl_fw_dbg_params - register values to restore
+ * @in_sample: DBGC_IN_SAMPLE value
+ * @out_ctrl: DBGC_OUT_CTRL value
+ */
+struct iwl_fw_dbg_params {
+ u32 in_sample;
+ u32 out_ctrl;
+};
+
extern const struct iwl_fw_dump_desc iwl_dump_desc_assert;
static inline void iwl_fw_free_dump_desc(struct iwl_fw_runtime *fwrt)
@@ -99,25 +107,25 @@ static inline void iwl_fw_free_dump_desc(struct iwl_fw_runtime *fwrt)
void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt);
int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt,
const struct iwl_fw_dump_desc *desc,
- const struct iwl_fw_dbg_trigger_tlv *trigger);
+ void *trigger, unsigned int delay);
int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt,
enum iwl_fw_dbg_trigger trig,
const char *str, size_t len,
- const struct iwl_fw_dbg_trigger_tlv *trigger);
+ struct iwl_fw_dbg_trigger_tlv *trigger);
int iwl_fw_dbg_collect_trig(struct iwl_fw_runtime *fwrt,
struct iwl_fw_dbg_trigger_tlv *trigger,
const char *fmt, ...) __printf(3, 4);
int iwl_fw_start_dbg_conf(struct iwl_fw_runtime *fwrt, u8 id);
#define iwl_fw_dbg_trigger_enabled(fw, id) ({ \
- void *__dbg_trigger = (fw)->dbg_trigger_tlv[(id)]; \
+ void *__dbg_trigger = (fw)->dbg.trigger_tlv[(id)]; \
unlikely(__dbg_trigger); \
})
static inline struct iwl_fw_dbg_trigger_tlv*
_iwl_fw_dbg_get_trigger(const struct iwl_fw *fw, enum iwl_fw_dbg_trigger id)
{
- return fw->dbg_trigger_tlv[id];
+ return fw->dbg.trigger_tlv[id];
}
#define iwl_fw_dbg_get_trigger(fw, id) ({ \
@@ -146,12 +154,9 @@ iwl_fw_dbg_trigger_stop_conf_match(struct iwl_fw_runtime *fwrt,
}
static inline bool
-iwl_fw_dbg_no_trig_window(struct iwl_fw_runtime *fwrt,
- struct iwl_fw_dbg_trigger_tlv *trig)
+iwl_fw_dbg_no_trig_window(struct iwl_fw_runtime *fwrt, u32 id, u32 dis_ms)
{
- unsigned long wind_jiff =
- msecs_to_jiffies(le16_to_cpu(trig->trig_dis_ms));
- u32 id = le32_to_cpu(trig->id);
+ unsigned long wind_jiff = msecs_to_jiffies(dis_ms);
/* If this is the first event checked, jump to update start ts */
if (fwrt->dump.non_collect_ts_start[id] &&
@@ -171,7 +176,8 @@ iwl_fw_dbg_trigger_check_stop(struct iwl_fw_runtime *fwrt,
if (wdev && !iwl_fw_dbg_trigger_vif_match(trig, wdev))
return false;
- if (iwl_fw_dbg_no_trig_window(fwrt, trig)) {
+ if (iwl_fw_dbg_no_trig_window(fwrt, le32_to_cpu(trig->id),
+ le16_to_cpu(trig->trig_dis_ms))) {
IWL_WARN(fwrt, "Trigger %d occurred while no-collect window.\n",
trig->id);
return false;
@@ -180,6 +186,30 @@ iwl_fw_dbg_trigger_check_stop(struct iwl_fw_runtime *fwrt,
return iwl_fw_dbg_trigger_stop_conf_match(fwrt, trig);
}
+static inline struct iwl_fw_dbg_trigger_tlv*
+_iwl_fw_dbg_trigger_on(struct iwl_fw_runtime *fwrt,
+ struct wireless_dev *wdev,
+ const enum iwl_fw_dbg_trigger id)
+{
+ struct iwl_fw_dbg_trigger_tlv *trig;
+
+ if (!iwl_fw_dbg_trigger_enabled(fwrt->fw, id))
+ return NULL;
+
+ trig = _iwl_fw_dbg_get_trigger(fwrt->fw, id);
+
+ if (!iwl_fw_dbg_trigger_check_stop(fwrt, wdev, trig))
+ return NULL;
+
+ return trig;
+}
+
+#define iwl_fw_dbg_trigger_on(fwrt, wdev, id) ({ \
+ BUILD_BUG_ON(!__builtin_constant_p(id)); \
+ BUILD_BUG_ON((id) >= FW_DBG_TRIGGER_MAX); \
+ _iwl_fw_dbg_trigger_on((fwrt), (wdev), (id)); \
+})
+
static inline void
_iwl_fw_dbg_trigger_simple_stop(struct iwl_fw_runtime *fwrt,
struct wireless_dev *wdev,
@@ -199,17 +229,80 @@ _iwl_fw_dbg_trigger_simple_stop(struct iwl_fw_runtime *fwrt,
iwl_fw_dbg_get_trigger((fwrt)->fw,\
(trig)))
-static inline void iwl_fw_dbg_stop_recording(struct iwl_fw_runtime *fwrt)
+static int iwl_fw_dbg_start_stop_hcmd(struct iwl_fw_runtime *fwrt, bool start)
+{
+ struct iwl_continuous_record_cmd cont_rec = {};
+ struct iwl_host_cmd hcmd = {
+ .id = LDBG_CONFIG_CMD,
+ .flags = CMD_ASYNC,
+ .data[0] = &cont_rec,
+ .len[0] = sizeof(cont_rec),
+ };
+
+ cont_rec.record_mode.enable_recording = start ?
+ cpu_to_le16(START_DEBUG_RECORDING) :
+ cpu_to_le16(STOP_DEBUG_RECORDING);
+
+ return iwl_trans_send_cmd(fwrt->trans, &hcmd);
+}
+
+static inline void
+_iwl_fw_dbg_stop_recording(struct iwl_trans *trans,
+ struct iwl_fw_dbg_params *params)
+{
+ if (trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
+ iwl_set_bits_prph(trans, MON_BUFF_SAMPLE_CTL, 0x100);
+ return;
+ }
+
+ if (params) {
+ params->in_sample = iwl_read_prph(trans, DBGC_IN_SAMPLE);
+ params->out_ctrl = iwl_read_prph(trans, DBGC_OUT_CTRL);
+ }
+
+ iwl_write_prph(trans, DBGC_IN_SAMPLE, 0);
+ udelay(100);
+ iwl_write_prph(trans, DBGC_OUT_CTRL, 0);
+}
+
+static inline void
+iwl_fw_dbg_stop_recording(struct iwl_fw_runtime *fwrt,
+ struct iwl_fw_dbg_params *params)
+{
+ if (fwrt->trans->cfg->device_family < IWL_DEVICE_FAMILY_22560)
+ _iwl_fw_dbg_stop_recording(fwrt->trans, params);
+ else
+ iwl_fw_dbg_start_stop_hcmd(fwrt, false);
+}
+
+static inline void
+_iwl_fw_dbg_restart_recording(struct iwl_trans *trans,
+ struct iwl_fw_dbg_params *params)
{
- if (fwrt->trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
- iwl_set_bits_prph(fwrt->trans, MON_BUFF_SAMPLE_CTL, 0x100);
+ if (WARN_ON(!params))
+ return;
+
+ if (trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
+ iwl_clear_bits_prph(trans, MON_BUFF_SAMPLE_CTL, 0x100);
+ iwl_clear_bits_prph(trans, MON_BUFF_SAMPLE_CTL, 0x1);
+ iwl_set_bits_prph(trans, MON_BUFF_SAMPLE_CTL, 0x1);
} else {
- iwl_write_prph(fwrt->trans, DBGC_IN_SAMPLE, 0);
+ iwl_write_prph(trans, DBGC_IN_SAMPLE, params->in_sample);
udelay(100);
- iwl_write_prph(fwrt->trans, DBGC_OUT_CTRL, 0);
+ iwl_write_prph(trans, DBGC_OUT_CTRL, params->out_ctrl);
}
}
+static inline void
+iwl_fw_dbg_restart_recording(struct iwl_fw_runtime *fwrt,
+ struct iwl_fw_dbg_params *params)
+{
+ if (fwrt->trans->cfg->device_family < IWL_DEVICE_FAMILY_22560)
+ _iwl_fw_dbg_restart_recording(fwrt->trans, params);
+ else
+ iwl_fw_dbg_start_stop_hcmd(fwrt, true);
+}
+
static inline void iwl_fw_dump_conf_clear(struct iwl_fw_runtime *fwrt)
{
fwrt->dump.conf = FW_DBG_INVALID;
@@ -217,6 +310,16 @@ static inline void iwl_fw_dump_conf_clear(struct iwl_fw_runtime *fwrt)
void iwl_fw_error_dump_wk(struct work_struct *work);
+static inline bool iwl_fw_dbg_is_d3_debug_enabled(struct iwl_fw_runtime *fwrt)
+{
+ return fw_has_capa(&fwrt->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_D3_DEBUG) &&
+ fwrt->trans->cfg->d3_debug_data_length &&
+ fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_D3_DEBUG_DATA);
+}
+
+void iwl_fw_dbg_read_d3_debug_data(struct iwl_fw_runtime *fwrt);
+
static inline void iwl_fw_flush_dump(struct iwl_fw_runtime *fwrt)
{
flush_delayed_work(&fwrt->dump.wk);
@@ -263,4 +366,6 @@ static inline void iwl_fw_resume_timestamp(struct iwl_fw_runtime *fwrt) {}
#endif /* CONFIG_IWLWIFI_DEBUGFS */
+void iwl_fw_alive_error_dump(struct iwl_fw_runtime *fwrt);
+void iwl_fw_dbg_collect_sync(struct iwl_fw_runtime *fwrt);
#endif /* __iwl_fw_dbg_h__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c
index 8ba5a60ec9ed..3e120dd47305 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c
@@ -8,6 +8,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
+ * Copyright (C) 2018 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -18,9 +19,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program.
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
@@ -33,6 +31,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
+ * Copyright (C) 2018 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -66,55 +65,117 @@
#include "debugfs.h"
#include "dbg.h"
-#define FWRT_DEBUGFS_READ_FILE_OPS(name) \
-static ssize_t iwl_dbgfs_##name##_read(struct iwl_fw_runtime *fwrt, \
- char *buf, size_t count, \
- loff_t *ppos); \
+#define FWRT_DEBUGFS_OPEN_WRAPPER(name, buflen, argtype) \
+struct dbgfs_##name##_data { \
+ argtype *arg; \
+ bool read_done; \
+ ssize_t rlen; \
+ char rbuf[buflen]; \
+}; \
+static int _iwl_dbgfs_##name##_open(struct inode *inode, \
+ struct file *file) \
+{ \
+ struct dbgfs_##name##_data *data; \
+ \
+ data = kzalloc(sizeof(*data), GFP_KERNEL); \
+ if (!data) \
+ return -ENOMEM; \
+ \
+ data->read_done = false; \
+ data->arg = inode->i_private; \
+ file->private_data = data; \
+ \
+ return 0; \
+}
+
+#define FWRT_DEBUGFS_READ_WRAPPER(name) \
+static ssize_t _iwl_dbgfs_##name##_read(struct file *file, \
+ char __user *user_buf, \
+ size_t count, loff_t *ppos) \
+{ \
+ struct dbgfs_##name##_data *data = file->private_data; \
+ \
+ if (!data->read_done) { \
+ data->read_done = true; \
+ data->rlen = iwl_dbgfs_##name##_read(data->arg, \
+ sizeof(data->rbuf),\
+ data->rbuf); \
+ } \
+ \
+ if (data->rlen < 0) \
+ return data->rlen; \
+ return simple_read_from_buffer(user_buf, count, ppos, \
+ data->rbuf, data->rlen); \
+}
+
+static int _iwl_dbgfs_release(struct inode *inode, struct file *file)
+{
+ kfree(file->private_data);
+
+ return 0;
+}
+
+#define _FWRT_DEBUGFS_READ_FILE_OPS(name, buflen, argtype) \
+FWRT_DEBUGFS_OPEN_WRAPPER(name, buflen, argtype) \
+FWRT_DEBUGFS_READ_WRAPPER(name) \
static const struct file_operations iwl_dbgfs_##name##_ops = { \
- .read = iwl_dbgfs_##name##_read, \
- .open = simple_open, \
+ .read = _iwl_dbgfs_##name##_read, \
+ .open = _iwl_dbgfs_##name##_open, \
.llseek = generic_file_llseek, \
+ .release = _iwl_dbgfs_release, \
}
-#define FWRT_DEBUGFS_WRITE_WRAPPER(name, buflen) \
-static ssize_t iwl_dbgfs_##name##_write(struct iwl_fw_runtime *fwrt, \
- char *buf, size_t count, \
- loff_t *ppos); \
+#define FWRT_DEBUGFS_WRITE_WRAPPER(name, buflen, argtype) \
static ssize_t _iwl_dbgfs_##name##_write(struct file *file, \
const char __user *user_buf, \
size_t count, loff_t *ppos) \
{ \
- struct iwl_fw_runtime *fwrt = file->private_data; \
+ argtype *arg = \
+ ((struct dbgfs_##name##_data *)file->private_data)->arg;\
char buf[buflen] = {}; \
size_t buf_size = min(count, sizeof(buf) - 1); \
\
if (copy_from_user(buf, user_buf, buf_size)) \
return -EFAULT; \
\
- return iwl_dbgfs_##name##_write(fwrt, buf, buf_size, ppos); \
+ return iwl_dbgfs_##name##_write(arg, buf, buf_size); \
}
-#define FWRT_DEBUGFS_READ_WRITE_FILE_OPS(name, buflen) \
-FWRT_DEBUGFS_WRITE_WRAPPER(name, buflen) \
+#define _FWRT_DEBUGFS_READ_WRITE_FILE_OPS(name, buflen, argtype) \
+FWRT_DEBUGFS_OPEN_WRAPPER(name, buflen, argtype) \
+FWRT_DEBUGFS_WRITE_WRAPPER(name, buflen, argtype) \
+FWRT_DEBUGFS_READ_WRAPPER(name) \
static const struct file_operations iwl_dbgfs_##name##_ops = { \
.write = _iwl_dbgfs_##name##_write, \
- .read = iwl_dbgfs_##name##_read, \
- .open = simple_open, \
+ .read = _iwl_dbgfs_##name##_read, \
+ .open = _iwl_dbgfs_##name##_open, \
.llseek = generic_file_llseek, \
+ .release = _iwl_dbgfs_release, \
}
-#define FWRT_DEBUGFS_WRITE_FILE_OPS(name, buflen) \
-FWRT_DEBUGFS_WRITE_WRAPPER(name, buflen) \
+#define _FWRT_DEBUGFS_WRITE_FILE_OPS(name, buflen, argtype) \
+FWRT_DEBUGFS_OPEN_WRAPPER(name, buflen, argtype) \
+FWRT_DEBUGFS_WRITE_WRAPPER(name, buflen, argtype) \
static const struct file_operations iwl_dbgfs_##name##_ops = { \
.write = _iwl_dbgfs_##name##_write, \
- .open = simple_open, \
+ .open = _iwl_dbgfs_##name##_open, \
.llseek = generic_file_llseek, \
+ .release = _iwl_dbgfs_release, \
}
+#define FWRT_DEBUGFS_READ_FILE_OPS(name, bufsz) \
+ _FWRT_DEBUGFS_READ_FILE_OPS(name, bufsz, struct iwl_fw_runtime)
+
+#define FWRT_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \
+ _FWRT_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct iwl_fw_runtime)
+
+#define FWRT_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
+ _FWRT_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct iwl_fw_runtime)
+
#define FWRT_DEBUGFS_ADD_FILE_ALIAS(alias, name, parent, mode) do { \
- if (!debugfs_create_file(alias, mode, parent, fwrt, \
- &iwl_dbgfs_##name##_ops)) \
- goto err; \
+ if (!debugfs_create_file(alias, mode, parent, fwrt, \
+ &iwl_dbgfs_##name##_ops)) \
+ goto err; \
} while (0)
#define FWRT_DEBUGFS_ADD_FILE(name, parent, mode) \
FWRT_DEBUGFS_ADD_FILE_ALIAS(#name, name, parent, mode)
@@ -173,8 +234,7 @@ void iwl_fw_trigger_timestamp(struct iwl_fw_runtime *fwrt, u32 delay)
}
static ssize_t iwl_dbgfs_timestamp_marker_write(struct iwl_fw_runtime *fwrt,
- char *buf, size_t count,
- loff_t *ppos)
+ char *buf, size_t count)
{
int ret;
u32 delay;
@@ -188,13 +248,85 @@ static ssize_t iwl_dbgfs_timestamp_marker_write(struct iwl_fw_runtime *fwrt,
return count;
}
-FWRT_DEBUGFS_WRITE_FILE_OPS(timestamp_marker, 10);
+static ssize_t iwl_dbgfs_timestamp_marker_read(struct iwl_fw_runtime *fwrt,
+ size_t size, char *buf)
+{
+ u32 delay_secs = jiffies_to_msecs(fwrt->timestamp.delay) / 1000;
+
+ return scnprintf(buf, size, "%d\n", delay_secs);
+}
+
+FWRT_DEBUGFS_READ_WRITE_FILE_OPS(timestamp_marker, 16);
+
+struct hcmd_write_data {
+ __be32 cmd_id;
+ __be32 flags;
+ __be16 length;
+ u8 data[0];
+} __packed;
+
+static ssize_t iwl_dbgfs_send_hcmd_write(struct iwl_fw_runtime *fwrt, char *buf,
+ size_t count)
+{
+ size_t header_size = (sizeof(u32) * 2 + sizeof(u16)) * 2;
+ size_t data_size = (count - 1) / 2;
+ int ret;
+ struct hcmd_write_data *data;
+ struct iwl_host_cmd hcmd = {
+ .len = { 0, },
+ .data = { NULL, },
+ };
+
+ if (fwrt->ops && fwrt->ops->fw_running &&
+ !fwrt->ops->fw_running(fwrt->ops_ctx))
+ return -EIO;
+
+ if (count < header_size + 1 || count > 1024 * 4)
+ return -EINVAL;
+
+ data = kmalloc(data_size, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ ret = hex2bin((u8 *)data, buf, data_size);
+ if (ret)
+ goto out;
+
+ hcmd.id = be32_to_cpu(data->cmd_id);
+ hcmd.flags = be32_to_cpu(data->flags);
+ hcmd.len[0] = be16_to_cpu(data->length);
+ hcmd.data[0] = data->data;
+
+ if (count != header_size + hcmd.len[0] * 2 + 1) {
+ IWL_ERR(fwrt,
+ "host command data size does not match header length\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (fwrt->ops && fwrt->ops->send_hcmd)
+ ret = fwrt->ops->send_hcmd(fwrt->ops_ctx, &hcmd);
+ else
+ ret = -EPERM;
+
+ if (ret < 0)
+ goto out;
+
+ if (hcmd.flags & CMD_WANT_SKB)
+ iwl_free_resp(&hcmd);
+out:
+ kfree(data);
+ return ret ?: count;
+}
+
+FWRT_DEBUGFS_WRITE_FILE_OPS(send_hcmd, 512);
int iwl_fwrt_dbgfs_register(struct iwl_fw_runtime *fwrt,
struct dentry *dbgfs_dir)
{
INIT_DELAYED_WORK(&fwrt->timestamp.wk, iwl_fw_timestamp_marker_wk);
FWRT_DEBUGFS_ADD_FILE(timestamp_marker, dbgfs_dir, 0200);
+ FWRT_DEBUGFS_ADD_FILE(send_hcmd, dbgfs_dir, 0200);
return 0;
err:
IWL_ERR(fwrt, "Can't create the fwrt debugfs directory\n");
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.h b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.h
index cbbfa8e9e66d..88255035e8ef 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.h
@@ -18,9 +18,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program.
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h
index ed7beca8817e..6fede174c664 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h
@@ -8,6 +8,7 @@
* Copyright(c) 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2014 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
+ * Copyright (C) 2018 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -18,11 +19,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
@@ -35,6 +31,7 @@
* Copyright(c) 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2014 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
+ * Copyright (C) 2018 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -116,6 +113,7 @@ enum iwl_fw_error_dump_type {
IWL_FW_ERROR_DUMP_INTERNAL_TXF = 14,
IWL_FW_ERROR_DUMP_EXTERNAL = 15, /* Do not move */
IWL_FW_ERROR_DUMP_MEM_CFG = 16,
+ IWL_FW_ERROR_DUMP_D3_DEBUG_DATA = 17,
IWL_FW_ERROR_DUMP_MAX,
};
@@ -330,6 +328,7 @@ iwl_fw_error_next_data(struct iwl_fw_error_dump_data *data)
* @FW_DBG_TDLS: trigger log collection upon TDLS related events.
* @FW_DBG_TRIGGER_TX_STATUS: trigger log collection upon tx status when
* the firmware sends a tx reply.
+ * @FW_DBG_TRIGGER_NO_ALIVE: trigger log collection if alive flow fails
*/
enum iwl_fw_dbg_trigger {
FW_DBG_TRIGGER_INVALID = 0,
@@ -347,6 +346,7 @@ enum iwl_fw_dbg_trigger {
FW_DBG_TRIGGER_TX_LATENCY,
FW_DBG_TRIGGER_TDLS,
FW_DBG_TRIGGER_TX_STATUS,
+ FW_DBG_TRIGGER_NO_ALIVE,
/* must be last */
FW_DBG_TRIGGER_MAX,
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h
index bbf2b265a06a..6005a41c53d1 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/file.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h
@@ -19,11 +19,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
@@ -258,6 +253,9 @@ typedef unsigned int __bitwise iwl_ucode_tlv_api_t;
* deprecated.
* @IWL_UCODE_TLV_API_ADAPTIVE_DWELL_V2: This ucode supports version 8
* of scan request: SCAN_REQUEST_CMD_UMAC_API_S_VER_8
+ * @IWL_UCODE_TLV_API_FRAG_EBS: This ucode supports fragmented EBS
+ * @IWL_UCODE_TLV_API_REDUCE_TX_POWER: This ucode supports v5 of
+ * the REDUCE_TX_POWER_CMD.
*
* @NUM_IWL_UCODE_TLV_API: number of bits used
*/
@@ -276,9 +274,12 @@ enum iwl_ucode_tlv_api {
IWL_UCODE_TLV_API_OCE = (__force iwl_ucode_tlv_api_t)33,
IWL_UCODE_TLV_API_NEW_BEACON_TEMPLATE = (__force iwl_ucode_tlv_api_t)34,
IWL_UCODE_TLV_API_NEW_RX_STATS = (__force iwl_ucode_tlv_api_t)35,
+ IWL_UCODE_TLV_API_WOWLAN_KEY_MATERIAL = (__force iwl_ucode_tlv_api_t)36,
IWL_UCODE_TLV_API_QUOTA_LOW_LATENCY = (__force iwl_ucode_tlv_api_t)38,
IWL_UCODE_TLV_API_DEPRECATE_TTAK = (__force iwl_ucode_tlv_api_t)41,
IWL_UCODE_TLV_API_ADAPTIVE_DWELL_V2 = (__force iwl_ucode_tlv_api_t)42,
+ IWL_UCODE_TLV_API_FRAG_EBS = (__force iwl_ucode_tlv_api_t)44,
+ IWL_UCODE_TLV_API_REDUCE_TX_POWER = (__force iwl_ucode_tlv_api_t)45,
NUM_IWL_UCODE_TLV_API
#ifdef __CHECKER__
@@ -325,6 +326,7 @@ typedef unsigned int __bitwise iwl_ucode_tlv_capa_t;
* @IWL_UCODE_TLV_CAPA_STA_PM_NOTIF: firmware will send STA PM notification
* @IWL_UCODE_TLV_CAPA_TLC_OFFLOAD: firmware implements rate scaling algorithm
* @IWL_UCODE_TLV_CAPA_DYNAMIC_QUOTA: firmware implements quota related
+ * @IWL_UCODE_TLV_CAPA_COEX_SCHEMA_2: firmware implements Coex Schema 2
* @IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE: extended DTS measurement
* @IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS: supports short PM timeouts
* @IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT: supports bt-coex Multi-priority LUT
@@ -335,7 +337,7 @@ typedef unsigned int __bitwise iwl_ucode_tlv_capa_t;
* antenna the beacon should be transmitted
* @IWL_UCODE_TLV_CAPA_BEACON_STORING: firmware will store the latest beacon
* from AP and will send it upon d0i3 exit.
- * @IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V2: support LAR API V2
+ * @IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V3: support LAR API V3
* @IWL_UCODE_TLV_CAPA_CT_KILL_BY_FW: firmware responsible for CT-kill
* @IWL_UCODE_TLV_CAPA_TEMP_THS_REPORT_SUPPORT: supports temperature
* thresholds reporting
@@ -349,6 +351,9 @@ typedef unsigned int __bitwise iwl_ucode_tlv_capa_t;
* command size (command version 4) that supports toggling ACK TX
* power reduction.
* @IWL_UCODE_TLV_CAPA_MLME_OFFLOAD: supports MLME offload
+ * @IWL_UCODE_TLV_CAPA_D3_DEBUG: supports debug recording during D3
+ * @IWL_UCODE_TLV_CAPA_MCC_UPDATE_11AX_SUPPORT: MCC response support 11ax
+ * capability.
*
* @NUM_IWL_UCODE_TLV_CAPA: number of bits used
*/
@@ -381,6 +386,7 @@ enum iwl_ucode_tlv_capa {
IWL_UCODE_TLV_CAPA_D0I3_END_FIRST = (__force iwl_ucode_tlv_capa_t)41,
IWL_UCODE_TLV_CAPA_TLC_OFFLOAD = (__force iwl_ucode_tlv_capa_t)43,
IWL_UCODE_TLV_CAPA_DYNAMIC_QUOTA = (__force iwl_ucode_tlv_capa_t)44,
+ IWL_UCODE_TLV_CAPA_COEX_SCHEMA_2 = (__force iwl_ucode_tlv_capa_t)45,
IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE = (__force iwl_ucode_tlv_capa_t)64,
IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS = (__force iwl_ucode_tlv_capa_t)65,
IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT = (__force iwl_ucode_tlv_capa_t)67,
@@ -388,7 +394,7 @@ enum iwl_ucode_tlv_capa {
IWL_UCODE_TLV_CAPA_CSA_AND_TBTT_OFFLOAD = (__force iwl_ucode_tlv_capa_t)70,
IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION = (__force iwl_ucode_tlv_capa_t)71,
IWL_UCODE_TLV_CAPA_BEACON_STORING = (__force iwl_ucode_tlv_capa_t)72,
- IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V2 = (__force iwl_ucode_tlv_capa_t)73,
+ IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V3 = (__force iwl_ucode_tlv_capa_t)73,
IWL_UCODE_TLV_CAPA_CT_KILL_BY_FW = (__force iwl_ucode_tlv_capa_t)74,
IWL_UCODE_TLV_CAPA_TEMP_THS_REPORT_SUPPORT = (__force iwl_ucode_tlv_capa_t)75,
IWL_UCODE_TLV_CAPA_CTDP_SUPPORT = (__force iwl_ucode_tlv_capa_t)76,
@@ -396,7 +402,9 @@ enum iwl_ucode_tlv_capa {
IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG = (__force iwl_ucode_tlv_capa_t)80,
IWL_UCODE_TLV_CAPA_LQM_SUPPORT = (__force iwl_ucode_tlv_capa_t)81,
IWL_UCODE_TLV_CAPA_TX_POWER_ACK = (__force iwl_ucode_tlv_capa_t)84,
- IWL_UCODE_TLV_CAPA_LED_CMD_SUPPORT = (__force iwl_ucode_tlv_capa_t)86,
+ IWL_UCODE_TLV_CAPA_D3_DEBUG = (__force iwl_ucode_tlv_capa_t)87,
+ IWL_UCODE_TLV_CAPA_LED_CMD_SUPPORT = (__force iwl_ucode_tlv_capa_t)88,
+ IWL_UCODE_TLV_CAPA_MCC_UPDATE_11AX_SUPPORT = (__force iwl_ucode_tlv_capa_t)89,
IWL_UCODE_TLV_CAPA_MLME_OFFLOAD = (__force iwl_ucode_tlv_capa_t)96,
NUM_IWL_UCODE_TLV_CAPA
@@ -528,22 +536,9 @@ enum iwl_fw_dbg_monitor_mode {
};
/**
- * enum iwl_fw_mem_seg_type - memory segment type
- * @FW_DBG_MEM_TYPE_MASK: mask for the type indication
- * @FW_DBG_MEM_TYPE_REGULAR: regular memory
- * @FW_DBG_MEM_TYPE_PRPH: periphery memory (requires special reading)
- */
-enum iwl_fw_mem_seg_type {
- FW_DBG_MEM_TYPE_MASK = 0xff000000,
- FW_DBG_MEM_TYPE_REGULAR = 0x00000000,
- FW_DBG_MEM_TYPE_PRPH = 0x01000000,
-};
-
-/**
* struct iwl_fw_dbg_mem_seg_tlv - configures the debug data memory segments
*
- * @data_type: the memory segment type to record, see &enum iwl_fw_mem_seg_type
- * for what we care about
+ * @data_type: the memory segment type to record
* @ofs: the memory segment offset
* @len: the memory segment length, in bytes
*
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/img.h b/drivers/net/wireless/intel/iwlwifi/fw/img.h
index 0861b97c4233..54dbbd998abf 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/img.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/img.h
@@ -19,11 +19,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
@@ -203,6 +198,29 @@ enum iwl_fw_type {
};
/**
+ * struct iwl_fw_dbg - debug data
+ *
+ * @dest_tlv: points to debug destination TLV (typically SRAM or DRAM)
+ * @n_dest_reg: num of reg_ops in dest_tlv
+ * @conf_tlv: array of pointers to configuration HCMDs
+ * @trigger_tlv: array of pointers to triggers TLVs
+ * @trigger_tlv_len: lengths of the @dbg_trigger_tlv entries
+ * @mem_tlv: Runtime addresses to dump
+ * @n_mem_tlv: number of runtime addresses
+ * @dump_mask: bitmask of dump regions
+*/
+struct iwl_fw_dbg {
+ struct iwl_fw_dbg_dest_tlv_v1 *dest_tlv;
+ u8 n_dest_reg;
+ struct iwl_fw_dbg_conf_tlv *conf_tlv[FW_DBG_CONF_MAX];
+ struct iwl_fw_dbg_trigger_tlv *trigger_tlv[FW_DBG_TRIGGER_MAX];
+ size_t trigger_tlv_len[FW_DBG_TRIGGER_MAX];
+ struct iwl_fw_dbg_mem_seg_tlv *mem_tlv;
+ size_t n_mem_tlv;
+ u32 dump_mask;
+};
+
+/**
* struct iwl_fw - variables associated with the firmware
*
* @ucode_ver: ucode version from the ucode file
@@ -222,12 +240,6 @@ enum iwl_fw_type {
* @cipher_scheme: optional external cipher scheme.
* @human_readable: human readable version
* we get the ALIVE from the uCode
- * @dbg_dest_tlv: points to the destination TLV for debug
- * @dbg_conf_tlv: array of pointers to configuration TLVs for debug
- * @dbg_conf_tlv_len: lengths of the @dbg_conf_tlv entries
- * @dbg_trigger_tlv: array of pointers to triggers TLVs
- * @dbg_trigger_tlv_len: lengths of the @dbg_trigger_tlv entries
- * @dbg_dest_reg_num: num of reg_ops in %dbg_dest_tlv
*/
struct iwl_fw {
u32 ucode_ver;
@@ -255,15 +267,7 @@ struct iwl_fw {
struct iwl_fw_cipher_scheme cs[IWL_UCODE_MAX_CS];
u8 human_readable[FW_VER_HUMAN_READABLE_SZ];
- struct iwl_fw_dbg_dest_tlv_v1 *dbg_dest_tlv;
- struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_CONF_MAX];
- size_t dbg_conf_tlv_len[FW_DBG_CONF_MAX];
- struct iwl_fw_dbg_trigger_tlv *dbg_trigger_tlv[FW_DBG_TRIGGER_MAX];
- struct iwl_fw_dbg_mem_seg_tlv *dbg_mem_tlv;
- size_t n_dbg_mem_tlv;
- size_t dbg_trigger_tlv_len[FW_DBG_TRIGGER_MAX];
- u8 dbg_dest_reg_num;
- u32 dbg_dump_mask;
+ struct iwl_fw_dbg dbg;
};
static inline const char *get_fw_dbg_mode_string(int mode)
@@ -285,7 +289,7 @@ static inline const char *get_fw_dbg_mode_string(int mode)
static inline bool
iwl_fw_dbg_conf_usniffer(const struct iwl_fw *fw, u8 id)
{
- const struct iwl_fw_dbg_conf_tlv *conf_tlv = fw->dbg_conf_tlv[id];
+ const struct iwl_fw_dbg_conf_tlv *conf_tlv = fw->dbg.conf_tlv[id];
if (!conf_tlv)
return false;
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/notif-wait.c b/drivers/net/wireless/intel/iwlwifi/fw/notif-wait.c
index 1096c945a68b..379735e086dc 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/notif-wait.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/notif-wait.c
@@ -17,11 +17,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/notif-wait.h b/drivers/net/wireless/intel/iwlwifi/fw/notif-wait.h
index 368884be4e7c..61b067eeeac9 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/notif-wait.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/notif-wait.h
@@ -17,11 +17,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h
index ed23367f7088..6b95d0e75889 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h
@@ -71,6 +71,7 @@ struct iwl_fw_runtime_ops {
int (*dump_start)(void *ctx);
void (*dump_end)(void *ctx);
bool (*fw_running)(void *ctx);
+ int (*send_hcmd)(void *ctx, struct iwl_host_cmd *host_cmd);
};
#define MAX_NUM_LMAC 2
@@ -88,6 +89,7 @@ struct iwl_fwrt_shared_mem_cfg {
enum iwl_fw_runtime_status {
IWL_FWRT_STATUS_DUMPING = 0,
+ IWL_FWRT_STATUS_WAIT_ALIVE,
};
/**
@@ -136,6 +138,7 @@ struct iwl_fw_runtime {
/* ts of the beginning of a non-collect fw dbg data period */
unsigned long non_collect_ts_start[FW_DBG_TRIGGER_MAX - 1];
+ u32 *d3_debug_data;
} dump;
#ifdef CONFIG_IWLWIFI_DEBUGFS
struct {
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-agn-hw.h b/drivers/net/wireless/intel/iwlwifi/iwl-agn-hw.h
index ee9347a54cdc..359537620c93 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-agn-hw.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-agn-hw.h
@@ -16,11 +16,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h
index 12fddcf15bab..5eb906a0d0d2 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h
@@ -18,11 +18,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
@@ -388,6 +383,8 @@ struct iwl_csr_params {
* @gen2: 22000 and on transport operation
* @cdb: CDB support
* @nvm_type: see &enum iwl_nvm_type
+ * @d3_debug_data_base_addr: base address where D3 debug data is stored
+ * @d3_debug_data_length: length of the D3 debug data
*
* We enable the driver to be backward compatible wrt. hardware features.
* API differences in uCode shouldn't be handled here but through TLVs
@@ -452,6 +449,8 @@ struct iwl_cfg {
u8 ucode_api_min;
u32 min_umac_error_event_table;
u32 extra_phy_cfg_flags;
+ u32 d3_debug_data_base_addr;
+ u32 d3_debug_data_length;
};
static const struct iwl_csr_params iwl_csr_v1 = {
@@ -574,11 +573,18 @@ extern const struct iwl_cfg iwl22000_2ac_cfg_hr;
extern const struct iwl_cfg iwl22000_2ac_cfg_hr_cdb;
extern const struct iwl_cfg iwl22000_2ac_cfg_jf;
extern const struct iwl_cfg iwl22000_2ax_cfg_hr;
+extern const struct iwl_cfg iwl9461_2ac_cfg_qu_b0_jf_b0;
+extern const struct iwl_cfg iwl9462_2ac_cfg_qu_b0_jf_b0;
+extern const struct iwl_cfg iwl9560_2ac_cfg_qu_b0_jf_b0;
+extern const struct iwl_cfg killer1550i_2ac_cfg_qu_b0_jf_b0;
+extern const struct iwl_cfg killer1550s_2ac_cfg_qu_b0_jf_b0;
+extern const struct iwl_cfg iwl22000_2ax_cfg_jf;
extern const struct iwl_cfg iwl22000_2ax_cfg_qnj_hr_a0_f0;
+extern const struct iwl_cfg iwl22000_2ax_cfg_qnj_hr_b0_f0;
extern const struct iwl_cfg iwl22000_2ax_cfg_qnj_hr_b0;
extern const struct iwl_cfg iwl22000_2ax_cfg_qnj_jf_b0;
extern const struct iwl_cfg iwl22000_2ax_cfg_qnj_hr_a0;
extern const struct iwl_cfg iwl22560_2ax_cfg_su_cdb;
-#endif /* CONFIG_IWLMVM */
+#endif /* CPTCFG_IWLMVM || CPTCFG_IWLFMAC */
#endif /* __IWL_CONFIG_H__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-context-info.h b/drivers/net/wireless/intel/iwlwifi/iwl-context-info.h
index 4b6fdf3b15fb..5ed07e37e3ee 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-context-info.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-context-info.h
@@ -64,20 +64,41 @@
* the init done for driver command that configures several system modes
* @IWL_CTXT_INFO_EARLY_DEBUG: enable early debug
* @IWL_CTXT_INFO_ENABLE_CDMP: enable core dump
- * @IWL_CTXT_INFO_RB_SIZE_4K: Use 4K RB size (the default is 2K)
* @IWL_CTXT_INFO_RB_CB_SIZE_POS: position of the RBD Cyclic Buffer Size
* exponent, the actual size is 2**value, valid sizes are 8-2048.
* The value is four bits long. Maximum valid exponent is 12
* @IWL_CTXT_INFO_TFD_FORMAT_LONG: use long TFD Format (the
* default is short format - not supported by the driver)
+ * @IWL_CTXT_INFO_RB_SIZE_POS: RB size position
+ * (values are IWL_CTXT_INFO_RB_SIZE_*K)
+ * @IWL_CTXT_INFO_RB_SIZE_1K: Value for 1K RB size
+ * @IWL_CTXT_INFO_RB_SIZE_2K: Value for 2K RB size
+ * @IWL_CTXT_INFO_RB_SIZE_4K: Value for 4K RB size
+ * @IWL_CTXT_INFO_RB_SIZE_8K: Value for 8K RB size
+ * @IWL_CTXT_INFO_RB_SIZE_12K: Value for 12K RB size
+ * @IWL_CTXT_INFO_RB_SIZE_16K: Value for 16K RB size
+ * @IWL_CTXT_INFO_RB_SIZE_20K: Value for 20K RB size
+ * @IWL_CTXT_INFO_RB_SIZE_24K: Value for 24K RB size
+ * @IWL_CTXT_INFO_RB_SIZE_28K: Value for 28K RB size
+ * @IWL_CTXT_INFO_RB_SIZE_32K: Value for 32K RB size
*/
enum iwl_context_info_flags {
IWL_CTXT_INFO_AUTO_FUNC_INIT = BIT(0),
IWL_CTXT_INFO_EARLY_DEBUG = BIT(1),
IWL_CTXT_INFO_ENABLE_CDMP = BIT(2),
- IWL_CTXT_INFO_RB_SIZE_4K = BIT(3),
IWL_CTXT_INFO_RB_CB_SIZE_POS = 4,
IWL_CTXT_INFO_TFD_FORMAT_LONG = BIT(8),
+ IWL_CTXT_INFO_RB_SIZE_POS = 9,
+ IWL_CTXT_INFO_RB_SIZE_1K = 0x1,
+ IWL_CTXT_INFO_RB_SIZE_2K = 0x2,
+ IWL_CTXT_INFO_RB_SIZE_4K = 0x4,
+ IWL_CTXT_INFO_RB_SIZE_8K = 0x8,
+ IWL_CTXT_INFO_RB_SIZE_12K = 0x9,
+ IWL_CTXT_INFO_RB_SIZE_16K = 0xa,
+ IWL_CTXT_INFO_RB_SIZE_20K = 0xb,
+ IWL_CTXT_INFO_RB_SIZE_24K = 0xc,
+ IWL_CTXT_INFO_RB_SIZE_28K = 0xd,
+ IWL_CTXT_INFO_RB_SIZE_32K = 0xe,
};
/*
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h
index 9019de99f077..caa5806acd81 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h
@@ -19,11 +19,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
@@ -188,6 +183,7 @@
#define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER (0x000000C0)
#define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI (0x00000100)
#define CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI (0x00000200)
+#define CSR_HW_IF_CONFIG_REG_D3_DEBUG (0x00000200)
#define CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE (0x00000C00)
#define CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH (0x00003000)
#define CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP (0x0000C000)
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-debug.c b/drivers/net/wireless/intel/iwlwifi/iwl-debug.c
index b1c3b0d0fcc6..e1a41fd503a8 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-debug.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-debug.c
@@ -16,11 +16,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-debug.h b/drivers/net/wireless/intel/iwlwifi/iwl-debug.h
index c023fcf5d452..a2af68a0d34b 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-debug.h
@@ -13,10 +13,6 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h
index a80e4202cd03..420e6d745f77 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h
@@ -2,6 +2,7 @@
*
* Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2015 Intel Deutschland GmbH
+ * Copyright(c) 2018 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
@@ -12,10 +13,6 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
@@ -33,38 +30,20 @@
#undef TRACE_SYSTEM
#define TRACE_SYSTEM iwlwifi_data
-TRACE_EVENT(iwlwifi_dev_tx_data,
- TP_PROTO(const struct device *dev,
- struct sk_buff *skb, u8 hdr_len),
- TP_ARGS(dev, skb, hdr_len),
+TRACE_EVENT(iwlwifi_dev_tx_tb,
+ TP_PROTO(const struct device *dev, struct sk_buff *skb,
+ u8 *data_src, size_t data_len),
+ TP_ARGS(dev, skb, data_src, data_len),
TP_STRUCT__entry(
DEV_ENTRY
__dynamic_array(u8, data,
- iwl_trace_data(skb) ? skb->len - hdr_len : 0)
+ iwl_trace_data(skb) ? data_len : 0)
),
TP_fast_assign(
DEV_ASSIGN;
if (iwl_trace_data(skb))
- skb_copy_bits(skb, hdr_len,
- __get_dynamic_array(data),
- skb->len - hdr_len);
- ),
- TP_printk("[%s] TX frame data", __get_str(dev))
-);
-
-TRACE_EVENT(iwlwifi_dev_tx_tso_chunk,
- TP_PROTO(const struct device *dev,
- u8 *data_src, size_t data_len),
- TP_ARGS(dev, data_src, data_len),
- TP_STRUCT__entry(
- DEV_ENTRY
-
- __dynamic_array(u8, data, data_len)
- ),
- TP_fast_assign(
- DEV_ASSIGN;
- memcpy(__get_dynamic_array(data), data_src, data_len);
+ memcpy(__get_dynamic_array(data), data_src, data_len);
),
TP_printk("[%s] TX frame data", __get_str(dev))
);
@@ -76,12 +55,11 @@ TRACE_EVENT(iwlwifi_dev_rx_data,
TP_ARGS(dev, trans, rxbuf, len),
TP_STRUCT__entry(
DEV_ENTRY
-
__dynamic_array(u8, data,
- len - iwl_rx_trace_len(trans, rxbuf, len))
+ len - iwl_rx_trace_len(trans, rxbuf, len, NULL))
),
TP_fast_assign(
- size_t offs = iwl_rx_trace_len(trans, rxbuf, len);
+ size_t offs = iwl_rx_trace_len(trans, rxbuf, len, NULL);
DEV_ASSIGN;
if (offs < len)
memcpy(__get_dynamic_array(data),
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-io.h b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-io.h
index 4164dc1745ed..7bb4e0e9bb69 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-io.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-io.h
@@ -12,10 +12,6 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h
index 27e3e4e96aa2..8e87186682e7 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h
@@ -3,6 +3,7 @@
* Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
@@ -13,10 +14,6 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
@@ -75,13 +72,18 @@ TRACE_EVENT(iwlwifi_dev_rx,
TP_STRUCT__entry(
DEV_ENTRY
__field(u16, cmd)
- __dynamic_array(u8, rxbuf, iwl_rx_trace_len(trans, pkt, len))
+ __field(u8, hdr_offset)
+ __dynamic_array(u8, rxbuf,
+ iwl_rx_trace_len(trans, pkt, len, NULL))
),
TP_fast_assign(
+ size_t hdr_offset = 0;
+
DEV_ASSIGN;
__entry->cmd = WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd);
memcpy(__get_dynamic_array(rxbuf), pkt,
- iwl_rx_trace_len(trans, pkt, len));
+ iwl_rx_trace_len(trans, pkt, len, &hdr_offset));
+ __entry->hdr_offset = hdr_offset;
),
TP_printk("[%s] RX cmd %#.2x",
__get_str(dev), __entry->cmd)
@@ -126,61 +128,6 @@ TRACE_EVENT(iwlwifi_dev_tx,
__entry->framelen, __entry->skbaddr)
);
-struct iwl_error_event_table;
-TRACE_EVENT(iwlwifi_dev_ucode_error,
- TP_PROTO(const struct device *dev, const struct iwl_error_event_table *table,
- u32 hw_ver, u32 brd_ver),
- TP_ARGS(dev, table, hw_ver, brd_ver),
- TP_STRUCT__entry(
- DEV_ENTRY
- __field(u32, desc)
- __field(u32, tsf_low)
- __field(u32, data1)
- __field(u32, data2)
- __field(u32, line)
- __field(u32, blink2)
- __field(u32, ilink1)
- __field(u32, ilink2)
- __field(u32, bcon_time)
- __field(u32, gp1)
- __field(u32, gp2)
- __field(u32, rev_type)
- __field(u32, major)
- __field(u32, minor)
- __field(u32, hw_ver)
- __field(u32, brd_ver)
- ),
- TP_fast_assign(
- DEV_ASSIGN;
- __entry->desc = table->error_id;
- __entry->tsf_low = table->tsf_low;
- __entry->data1 = table->data1;
- __entry->data2 = table->data2;
- __entry->line = table->line;
- __entry->blink2 = table->blink2;
- __entry->ilink1 = table->ilink1;
- __entry->ilink2 = table->ilink2;
- __entry->bcon_time = table->bcon_time;
- __entry->gp1 = table->gp1;
- __entry->gp2 = table->gp2;
- __entry->rev_type = table->gp3;
- __entry->major = table->ucode_ver;
- __entry->minor = table->hw_ver;
- __entry->hw_ver = hw_ver;
- __entry->brd_ver = brd_ver;
- ),
- TP_printk("[%s] #%02d %010u data 0x%08X 0x%08X line %u, "
- "blink2 0x%05X ilink 0x%05X 0x%05X "
- "bcon_tm %010u gp 0x%08X 0x%08X rev_type 0x%08X major 0x%08X "
- "minor 0x%08X hw 0x%08X brd 0x%08X",
- __get_str(dev), __entry->desc, __entry->tsf_low,
- __entry->data1, __entry->data2, __entry->line,
- __entry->blink2, __entry->ilink1, __entry->ilink2,
- __entry->bcon_time, __entry->gp1, __entry->gp2,
- __entry->rev_type, __entry->major, __entry->minor,
- __entry->hw_ver, __entry->brd_ver)
-);
-
TRACE_EVENT(iwlwifi_dev_ucode_event,
TP_PROTO(const struct device *dev, u32 time, u32 data, u32 ev),
TP_ARGS(dev, time, data, ev),
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-msg.h b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-msg.h
index 5dfc9295a7e0..32984c1f39a1 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-msg.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-msg.h
@@ -11,10 +11,6 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-ucode.h b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-ucode.h
index e9b8673dd245..53842226ef1b 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-ucode.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-ucode.h
@@ -11,10 +11,6 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.c b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.c
index 6aa719865a58..9805432f124f 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.c
@@ -1,6 +1,7 @@
/******************************************************************************
*
* Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved.
+ * Copyright (C) 2018 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
@@ -11,10 +12,6 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
@@ -30,12 +27,10 @@
#ifndef __CHECKER__
#include "iwl-trans.h"
-#include "dvm/commands.h"
#define CREATE_TRACE_POINTS
#include "iwl-devtrace.h"
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_event);
-EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_error);
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_cont_event);
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_wrap_event);
#endif
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.h
index f5c1127253cb..fc649b2bc017 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.h
@@ -1,7 +1,8 @@
/******************************************************************************
*
* Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved.
- * Copyright(C) 2016 Intel Deutschland GmbH
+ * Copyright(C) 2016 Intel Deutschland GmbH
+ * Copyright(c) 2018 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
@@ -12,10 +13,6 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
@@ -60,16 +57,23 @@ static inline bool iwl_trace_data(struct sk_buff *skb)
}
static inline size_t iwl_rx_trace_len(const struct iwl_trans *trans,
- void *rxbuf, size_t len)
+ void *rxbuf, size_t len,
+ size_t *out_hdr_offset)
{
struct iwl_cmd_header *cmd = (void *)((u8 *)rxbuf + sizeof(__le32));
- struct ieee80211_hdr *hdr;
+ struct ieee80211_hdr *hdr = NULL;
+ size_t hdr_offset;
if (cmd->cmd != trans->rx_mpdu_cmd)
return len;
- hdr = (void *)((u8 *)cmd + sizeof(struct iwl_cmd_header) +
- trans->rx_mpdu_cmd_hdr_size);
+ hdr_offset = sizeof(struct iwl_cmd_header) +
+ trans->rx_mpdu_cmd_hdr_size;
+
+ if (out_hdr_offset)
+ *out_hdr_offset = hdr_offset;
+
+ hdr = (void *)((u8 *)cmd + hdr_offset);
if (!ieee80211_is_data(hdr->frame_control))
return len;
/* maybe try to identify EAPOL frames? */
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
index c0631255aee7..ba41d23b4211 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
@@ -18,11 +18,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
@@ -173,12 +168,12 @@ static void iwl_dealloc_ucode(struct iwl_drv *drv)
{
int i;
- kfree(drv->fw.dbg_dest_tlv);
- for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_conf_tlv); i++)
- kfree(drv->fw.dbg_conf_tlv[i]);
- for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_trigger_tlv); i++)
- kfree(drv->fw.dbg_trigger_tlv[i]);
- kfree(drv->fw.dbg_mem_tlv);
+ kfree(drv->fw.dbg.dest_tlv);
+ for (i = 0; i < ARRAY_SIZE(drv->fw.dbg.conf_tlv); i++)
+ kfree(drv->fw.dbg.conf_tlv[i]);
+ for (i = 0; i < ARRAY_SIZE(drv->fw.dbg.trigger_tlv); i++)
+ kfree(drv->fw.dbg.trigger_tlv[i]);
+ kfree(drv->fw.dbg.mem_tlv);
kfree(drv->fw.iml);
for (i = 0; i < IWL_UCODE_TYPE_MAX; i++)
@@ -308,7 +303,7 @@ struct iwl_firmware_pieces {
struct iwl_fw_dbg_trigger_tlv *dbg_trigger_tlv[FW_DBG_TRIGGER_MAX];
size_t dbg_trigger_tlv_len[FW_DBG_TRIGGER_MAX];
struct iwl_fw_dbg_mem_seg_tlv *dbg_mem_tlv;
- size_t n_dbg_mem_tlv;
+ size_t n_mem_tlv;
};
/*
@@ -941,7 +936,7 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
IWL_INFO(drv, "Found debug destination: %s\n",
get_fw_dbg_mode_string(mon_mode));
- drv->fw.dbg_dest_reg_num = (dest_v1) ?
+ drv->fw.dbg.n_dest_reg = (dest_v1) ?
tlv_len -
offsetof(struct iwl_fw_dbg_dest_tlv_v1,
reg_ops) :
@@ -949,8 +944,8 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
offsetof(struct iwl_fw_dbg_dest_tlv,
reg_ops);
- drv->fw.dbg_dest_reg_num /=
- sizeof(drv->fw.dbg_dest_tlv->reg_ops[0]);
+ drv->fw.dbg.n_dest_reg /=
+ sizeof(drv->fw.dbg.dest_tlv->reg_ops[0]);
break;
}
@@ -964,7 +959,7 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
break;
}
- if (conf->id >= ARRAY_SIZE(drv->fw.dbg_conf_tlv)) {
+ if (conf->id >= ARRAY_SIZE(drv->fw.dbg.conf_tlv)) {
IWL_ERR(drv,
"Skip unknown configuration: %d\n",
conf->id);
@@ -993,7 +988,7 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
(void *)tlv_data;
u32 trigger_id = le32_to_cpu(trigger->id);
- if (trigger_id >= ARRAY_SIZE(drv->fw.dbg_trigger_tlv)) {
+ if (trigger_id >= ARRAY_SIZE(drv->fw.dbg.trigger_tlv)) {
IWL_ERR(drv,
"Skip unknown trigger: %u\n",
trigger->id);
@@ -1020,7 +1015,7 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
break;
}
- drv->fw.dbg_dump_mask =
+ drv->fw.dbg.dump_mask =
le32_to_cpup((__le32 *)tlv_data);
break;
}
@@ -1065,38 +1060,23 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
case IWL_UCODE_TLV_FW_MEM_SEG: {
struct iwl_fw_dbg_mem_seg_tlv *dbg_mem =
(void *)tlv_data;
- u32 type;
size_t size;
struct iwl_fw_dbg_mem_seg_tlv *n;
if (tlv_len != (sizeof(*dbg_mem)))
goto invalid_tlv_len;
- type = le32_to_cpu(dbg_mem->data_type);
-
IWL_DEBUG_INFO(drv, "Found debug memory segment: %u\n",
dbg_mem->data_type);
- switch (type & FW_DBG_MEM_TYPE_MASK) {
- case FW_DBG_MEM_TYPE_REGULAR:
- case FW_DBG_MEM_TYPE_PRPH:
- /* we know how to handle these */
- break;
- default:
- IWL_ERR(drv,
- "Found debug memory segment with invalid type: 0x%x\n",
- type);
- return -EINVAL;
- }
-
size = sizeof(*pieces->dbg_mem_tlv) *
- (pieces->n_dbg_mem_tlv + 1);
+ (pieces->n_mem_tlv + 1);
n = krealloc(pieces->dbg_mem_tlv, size, GFP_KERNEL);
if (!n)
return -ENOMEM;
pieces->dbg_mem_tlv = n;
- pieces->dbg_mem_tlv[pieces->n_dbg_mem_tlv] = *dbg_mem;
- pieces->n_dbg_mem_tlv++;
+ pieces->dbg_mem_tlv[pieces->n_mem_tlv] = *dbg_mem;
+ pieces->n_mem_tlv++;
break;
}
case IWL_UCODE_TLV_IML: {
@@ -1275,8 +1255,8 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
fw->ucode_capa.standard_phy_calibration_size =
IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE;
fw->ucode_capa.n_scan_channels = IWL_DEFAULT_SCAN_CHANNELS;
- /* dump all fw memory areas by default */
- fw->dbg_dump_mask = 0xffffffff;
+ /* dump all fw memory areas by default except d3 debug data */
+ fw->dbg.dump_mask = 0xfffdffff;
pieces = kzalloc(sizeof(*pieces), GFP_KERNEL);
if (!pieces)
@@ -1343,21 +1323,21 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
goto out_free_fw;
if (pieces->dbg_dest_tlv_init) {
- size_t dbg_dest_size = sizeof(*drv->fw.dbg_dest_tlv) +
- sizeof(drv->fw.dbg_dest_tlv->reg_ops[0]) *
- drv->fw.dbg_dest_reg_num;
+ size_t dbg_dest_size = sizeof(*drv->fw.dbg.dest_tlv) +
+ sizeof(drv->fw.dbg.dest_tlv->reg_ops[0]) *
+ drv->fw.dbg.n_dest_reg;
- drv->fw.dbg_dest_tlv = kmalloc(dbg_dest_size, GFP_KERNEL);
+ drv->fw.dbg.dest_tlv = kmalloc(dbg_dest_size, GFP_KERNEL);
- if (!drv->fw.dbg_dest_tlv)
+ if (!drv->fw.dbg.dest_tlv)
goto out_free_fw;
if (*pieces->dbg_dest_ver == 0) {
- memcpy(drv->fw.dbg_dest_tlv, pieces->dbg_dest_tlv_v1,
+ memcpy(drv->fw.dbg.dest_tlv, pieces->dbg_dest_tlv_v1,
dbg_dest_size);
} else {
struct iwl_fw_dbg_dest_tlv_v1 *dest_tlv =
- drv->fw.dbg_dest_tlv;
+ drv->fw.dbg.dest_tlv;
dest_tlv->version = pieces->dbg_dest_tlv->version;
dest_tlv->monitor_mode =
@@ -1372,8 +1352,8 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
pieces->dbg_dest_tlv->base_shift;
memcpy(dest_tlv->reg_ops,
pieces->dbg_dest_tlv->reg_ops,
- sizeof(drv->fw.dbg_dest_tlv->reg_ops[0]) *
- drv->fw.dbg_dest_reg_num);
+ sizeof(drv->fw.dbg.dest_tlv->reg_ops[0]) *
+ drv->fw.dbg.n_dest_reg);
/* In version 1 of the destination tlv, which is
* relevant for internal buffer exclusively,
@@ -1389,15 +1369,13 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
}
}
- for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_conf_tlv); i++) {
+ for (i = 0; i < ARRAY_SIZE(drv->fw.dbg.conf_tlv); i++) {
if (pieces->dbg_conf_tlv[i]) {
- drv->fw.dbg_conf_tlv_len[i] =
- pieces->dbg_conf_tlv_len[i];
- drv->fw.dbg_conf_tlv[i] =
+ drv->fw.dbg.conf_tlv[i] =
kmemdup(pieces->dbg_conf_tlv[i],
- drv->fw.dbg_conf_tlv_len[i],
+ pieces->dbg_conf_tlv_len[i],
GFP_KERNEL);
- if (!drv->fw.dbg_conf_tlv[i])
+ if (!pieces->dbg_conf_tlv_len[i])
goto out_free_fw;
}
}
@@ -1424,7 +1402,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
trigger_tlv_sz[FW_DBG_TRIGGER_TDLS] =
sizeof(struct iwl_fw_dbg_trigger_tdls);
- for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_trigger_tlv); i++) {
+ for (i = 0; i < ARRAY_SIZE(drv->fw.dbg.trigger_tlv); i++) {
if (pieces->dbg_trigger_tlv[i]) {
/*
* If the trigger isn't long enough, WARN and exit.
@@ -1437,22 +1415,22 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
(trigger_tlv_sz[i] +
sizeof(struct iwl_fw_dbg_trigger_tlv))))
goto out_free_fw;
- drv->fw.dbg_trigger_tlv_len[i] =
+ drv->fw.dbg.trigger_tlv_len[i] =
pieces->dbg_trigger_tlv_len[i];
- drv->fw.dbg_trigger_tlv[i] =
+ drv->fw.dbg.trigger_tlv[i] =
kmemdup(pieces->dbg_trigger_tlv[i],
- drv->fw.dbg_trigger_tlv_len[i],
+ drv->fw.dbg.trigger_tlv_len[i],
GFP_KERNEL);
- if (!drv->fw.dbg_trigger_tlv[i])
+ if (!drv->fw.dbg.trigger_tlv[i])
goto out_free_fw;
}
}
/* Now that we can no longer fail, copy information */
- drv->fw.dbg_mem_tlv = pieces->dbg_mem_tlv;
+ drv->fw.dbg.mem_tlv = pieces->dbg_mem_tlv;
pieces->dbg_mem_tlv = NULL;
- drv->fw.n_dbg_mem_tlv = pieces->n_dbg_mem_tlv;
+ drv->fw.dbg.n_mem_tlv = pieces->n_mem_tlv;
/*
* The (size - 16) / 12 formula is based on the information recorded
@@ -1493,6 +1471,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
break;
default:
WARN(1, "Invalid fw type %d\n", fw->type);
+ /* fall through */
case IWL_FW_MVM:
op = &iwlwifi_opmode_table[MVM_OP_MODE];
break;
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.h b/drivers/net/wireless/intel/iwlwifi/iwl-drv.h
index 1f8a2eeb7dff..2be30af7bdc3 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.h
@@ -17,11 +17,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c
index a4c96215933b..4e3422a1c7bb 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c
@@ -18,9 +18,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program;
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
@@ -745,7 +742,9 @@ void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg,
else
rx_chains = hweight8(rx_chains);
- if (!(data->sku_cap_11n_enable) || !cfg->ht_params) {
+ if (!(data->sku_cap_11n_enable) ||
+ (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL) ||
+ !cfg->ht_params) {
ht_info->ht_supported = false;
return;
}
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h
index 8be50ed12300..d910bda087f7 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h
@@ -17,11 +17,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-read.c b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-read.c
index ac965c34a2f8..a6db6a814257 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-read.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-read.c
@@ -17,11 +17,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-read.h b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-read.h
index 1ed78be06c23..47fced159800 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-read.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-read.h
@@ -16,11 +16,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h
index df0e9ffff706..c6a534303936 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h
@@ -18,9 +18,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program.
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
@@ -68,6 +65,8 @@
#include <linux/types.h>
#include <linux/bitfield.h>
+#include "iwl-trans.h"
+
/****************************/
/* Flow Handler Definitions */
/****************************/
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-io.c b/drivers/net/wireless/intel/iwlwifi/iwl-io.c
index efb1998dcabd..4f10914f6048 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-io.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-io.c
@@ -14,10 +14,6 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-io.h b/drivers/net/wireless/intel/iwlwifi/iwl-io.h
index 5c8c0e130194..38085850a2d3 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-io.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-io.h
@@ -13,10 +13,6 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h b/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h
index 97072cf75bca..6fc8dac4aab7 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h
@@ -17,9 +17,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program;
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
index 73969dbeb5c5..96e101d79662 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
@@ -19,11 +19,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
@@ -476,30 +471,40 @@ static struct ieee80211_sband_iftype_data iwl_he_capa = {
.has_he = true,
.he_cap_elem = {
.mac_cap_info[0] =
- IEEE80211_HE_MAC_CAP0_HTC_HE,
+ IEEE80211_HE_MAC_CAP0_HTC_HE |
+ IEEE80211_HE_MAC_CAP0_TWT_REQ,
.mac_cap_info[1] =
IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US |
- IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_8,
+ IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8,
.mac_cap_info[2] =
IEEE80211_HE_MAC_CAP2_32BIT_BA_BITMAP |
+ IEEE80211_HE_MAC_CAP2_MU_CASCADING |
IEEE80211_HE_MAC_CAP2_ACK_EN,
.mac_cap_info[3] =
- IEEE80211_HE_MAC_CAP3_GRP_ADDR_MULTI_STA_BA_DL_MU |
- IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_VHT_2,
- .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU,
+ IEEE80211_HE_MAC_CAP3_OMI_CONTROL |
+ IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2,
+ .mac_cap_info[4] =
+ IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU |
+ IEEE80211_HE_MAC_CAP4_MULTI_TID_AGG_TX_QOS_B39,
+ .mac_cap_info[5] =
+ IEEE80211_HE_MAC_CAP5_MULTI_TID_AGG_TX_QOS_B40 |
+ IEEE80211_HE_MAC_CAP5_MULTI_TID_AGG_TX_QOS_B41 |
+ IEEE80211_HE_MAC_CAP5_UL_2x996_TONE_RU,
.phy_cap_info[0] =
- IEEE80211_HE_PHY_CAP0_DUAL_BAND |
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,
.phy_cap_info[1] =
+ IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK |
IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A |
IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD |
- IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_MAX_NSTS,
+ IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS,
.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,
.phy_cap_info[3] =
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_BPSK |
IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_1 |
@@ -511,18 +516,31 @@ static struct ieee80211_sband_iftype_data iwl_he_capa = {
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,
+ IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2 |
+ IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK |
+ IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK,
.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_SU_BEAMFORMER_FB |
+ IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB |
+ IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB |
+ IEEE80211_HE_PHY_CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO |
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT,
.phy_cap_info[7] =
IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_AR |
IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI |
- IEEE80211_HE_PHY_CAP7_MAX_NC_7,
+ IEEE80211_HE_PHY_CAP7_MAX_NC_1,
.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_80MHZ_IN_160MHZ_HE_PPDU |
+ IEEE80211_HE_PHY_CAP8_DCM_MAX_BW_160_OR_80P80_MHZ,
+ .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,
},
/*
* Set default Tx/Rx HE MCS NSS Support field. Indicate support
@@ -559,9 +577,11 @@ static void iwl_init_he_hw_capab(struct ieee80211_supported_band *sband,
/* If not 2x2, we need to indicate 1x1 in the Midamble RX Max NSTS */
if ((tx_chains & rx_chains) != ANT_AB) {
iwl_he_capa.he_cap.he_cap_elem.phy_cap_info[1] &=
- ~IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_MAX_NSTS;
+ ~IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS;
iwl_he_capa.he_cap.he_cap_elem.phy_cap_info[2] &=
- ~IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_MAX_NSTS;
+ ~IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_TX_MAX_NSTS;
+ iwl_he_capa.he_cap.he_cap_elem.phy_cap_info[7] &=
+ ~IEEE80211_HE_PHY_CAP7_MAX_NC_MASK;
}
}
@@ -1315,6 +1335,7 @@ struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans,
bool lar_fw_supported = !iwlwifi_mod_params.lar_disable &&
fw_has_capa(&fw->ucode_capa,
IWL_UCODE_TLV_CAPA_LAR_SUPPORT);
+ bool empty_otp;
u32 mac_flags;
u32 sbands_flags = 0;
@@ -1330,7 +1351,9 @@ struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans,
}
rsp = (void *)hcmd.resp_pkt->data;
- if (le32_to_cpu(rsp->general.flags) & NVM_GENERAL_FLAGS_EMPTY_OTP)
+ empty_otp = !!(le32_to_cpu(rsp->general.flags) &
+ NVM_GENERAL_FLAGS_EMPTY_OTP);
+ if (empty_otp)
IWL_INFO(trans, "OTP is empty\n");
nvm = kzalloc(sizeof(*nvm) +
@@ -1354,6 +1377,11 @@ struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans,
/* Initialize general data */
nvm->nvm_version = le16_to_cpu(rsp->general.nvm_version);
+ nvm->n_hw_addrs = rsp->general.n_hw_addrs;
+ if (nvm->n_hw_addrs == 0)
+ IWL_WARN(trans,
+ "Firmware declares no reserved mac addresses. OTP is empty: %d\n",
+ empty_otp);
/* Initialize MAC sku data */
mac_flags = le32_to_cpu(rsp->mac_sku.mac_sku_flags);
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h
index 234d1009a9de..b7e1ddf8f177 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h
@@ -18,11 +18,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h
index b49eda8150bb..cbd1a8eed620 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h
@@ -8,6 +8,7 @@
* Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* Copyright(c) 2015 Intel Deutschland GmbH
+ * Copyright(c) 2018 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -18,11 +19,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
@@ -35,6 +31,7 @@
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* Copyright(c) 2015 Intel Deutschland GmbH
+ * Copyright(c) 2018 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-phy-db.c b/drivers/net/wireless/intel/iwlwifi/iwl-phy-db.c
index b7cd813ba70f..ae83cfdb750e 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-phy-db.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-phy-db.c
@@ -17,11 +17,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-phy-db.h b/drivers/net/wireless/intel/iwlwifi/iwl-phy-db.h
index d34de3f71db6..7020dca05221 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-phy-db.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-phy-db.h
@@ -16,11 +16,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h
index 421a869633a3..0f51c7bea8d0 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h
@@ -18,11 +18,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-scd.h b/drivers/net/wireless/intel/iwlwifi/iwl-scd.h
index 99b43da32adf..9f11f3912816 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-scd.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-scd.h
@@ -16,11 +16,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c
index 7e9c924e1220..727f73e0b3f1 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c
@@ -17,11 +17,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
index 279dd7b7a3fb..26b3c73051ca 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
@@ -18,11 +18,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
@@ -269,6 +264,7 @@ struct iwl_rx_cmd_buffer {
bool _page_stolen;
u32 _rx_page_order;
unsigned int truesize;
+ u8 status;
};
static inline void *rxb_addr(struct iwl_rx_cmd_buffer *r)
@@ -538,9 +534,6 @@ struct iwl_trans_rxq_dma_data {
* @dump_data: return a vmalloc'ed buffer with debug data, maybe containing last
* TX'ed commands and similar. The buffer will be vfree'd by the caller.
* Note that the transport must fill in the proper file headers.
- * @dump_regs: dump using IWL_ERR configuration space and memory mapped
- * registers of the device to diagnose failure, e.g., when HW becomes
- * inaccessible.
*/
struct iwl_trans_ops {
@@ -569,7 +562,7 @@ struct iwl_trans_ops {
bool configure_scd);
/* 22000 functions */
int (*txq_alloc)(struct iwl_trans *trans,
- struct iwl_tx_queue_cfg_cmd *cmd,
+ __le16 flags, u8 sta_id, u8 tid,
int cmd_id, int size,
unsigned int queue_wdg_timeout);
void (*txq_free)(struct iwl_trans *trans, int queue);
@@ -611,8 +604,6 @@ struct iwl_trans_ops {
struct iwl_trans_dump_data *(*dump_data)(struct iwl_trans *trans,
const struct iwl_fw_dbg_trigger_tlv
*trigger);
-
- void (*dump_regs)(struct iwl_trans *trans);
};
/**
@@ -688,6 +679,19 @@ enum iwl_plat_pm_mode {
* enter/exit (in msecs).
*/
#define IWL_TRANS_IDLE_TIMEOUT 2000
+#define IWL_MAX_DEBUG_ALLOCATIONS 1
+
+/**
+ * struct iwl_dram_data
+ * @physical: page phy pointer
+ * @block: pointer to the allocated block/page
+ * @size: size of the block/page
+ */
+struct iwl_dram_data {
+ dma_addr_t physical;
+ void *block;
+ int size;
+};
/**
* struct iwl_trans - transport common data
@@ -721,7 +725,9 @@ enum iwl_plat_pm_mode {
* @dbg_dest_tlv: points to the destination TLV for debug
* @dbg_conf_tlv: array of pointers to configuration TLVs for debug
* @dbg_trigger_tlv: array of pointers to triggers TLVs for debug
- * @dbg_dest_reg_num: num of reg_ops in %dbg_dest_tlv
+ * @dbg_n_dest_reg: num of reg_ops in %dbg_dest_tlv
+ * @num_blocks: number of blocks in fw_mon
+ * @fw_mon: address of the buffers for firmware monitor
* @system_pm_mode: the system-wide power management mode in use.
* This mode is set dynamically, depending on the WoWLAN values
* configured from the userspace at runtime.
@@ -772,7 +778,9 @@ struct iwl_trans {
const struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_CONF_MAX];
struct iwl_fw_dbg_trigger_tlv * const *dbg_trigger_tlv;
u32 dbg_dump_mask;
- u8 dbg_dest_reg_num;
+ u8 dbg_n_dest_reg;
+ int num_blocks;
+ struct iwl_dram_data fw_mon[IWL_MAX_DEBUG_ALLOCATIONS];
enum iwl_plat_pm_mode system_pm_mode;
enum iwl_plat_pm_mode runtime_pm_mode;
@@ -897,12 +905,6 @@ iwl_trans_dump_data(struct iwl_trans *trans,
return trans->ops->dump_data(trans, trigger);
}
-static inline void iwl_trans_dump_regs(struct iwl_trans *trans)
-{
- if (trans->ops->dump_regs)
- trans->ops->dump_regs(trans);
-}
-
static inline struct iwl_device_cmd *
iwl_trans_alloc_tx_cmd(struct iwl_trans *trans)
{
@@ -985,7 +987,7 @@ iwl_trans_txq_free(struct iwl_trans *trans, int queue)
static inline int
iwl_trans_txq_alloc(struct iwl_trans *trans,
- struct iwl_tx_queue_cfg_cmd *cmd,
+ __le16 flags, u8 sta_id, u8 tid,
int cmd_id, int size,
unsigned int wdg_timeout)
{
@@ -999,7 +1001,8 @@ iwl_trans_txq_alloc(struct iwl_trans *trans,
return -EIO;
}
- return trans->ops->txq_alloc(trans, cmd, cmd_id, size, wdg_timeout);
+ return trans->ops->txq_alloc(trans, flags, sta_id, tid,
+ cmd_id, size, wdg_timeout);
}
static inline void iwl_trans_txq_set_shared_mode(struct iwl_trans *trans,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/binding.c b/drivers/net/wireless/intel/iwlwifi/mvm/binding.c
index 75d35f6b041e..4094a4158032 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/binding.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/binding.c
@@ -17,11 +17,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c
index 016e03a5034f..730e37744dc0 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c
@@ -17,11 +17,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
@@ -331,7 +326,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
struct ieee80211_chanctx_conf *chanctx_conf;
/* default smps_mode is AUTOMATIC - only used for client modes */
enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_AUTOMATIC;
- u32 bt_activity_grading;
+ u32 bt_activity_grading, min_ag_for_static_smps;
int ave_rssi;
lockdep_assert_held(&mvm->mutex);
@@ -363,8 +358,13 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
return;
}
+ if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_COEX_SCHEMA_2))
+ min_ag_for_static_smps = BT_VERY_HIGH_TRAFFIC;
+ else
+ min_ag_for_static_smps = BT_HIGH_TRAFFIC;
+
bt_activity_grading = le32_to_cpu(data->notif->bt_activity_grading);
- if (bt_activity_grading >= BT_HIGH_TRAFFIC)
+ if (bt_activity_grading >= min_ag_for_static_smps)
smps_mode = IEEE80211_SMPS_STATIC;
else if (bt_activity_grading >= BT_LOW_TRAFFIC)
smps_mode = IEEE80211_SMPS_DYNAMIC;
@@ -691,6 +691,15 @@ bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm,
return bt_activity >= BT_LOW_TRAFFIC;
}
+u8 iwl_mvm_bt_coex_get_single_ant_msk(struct iwl_mvm *mvm, u8 enabled_ants)
+{
+ if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_COEX_SCHEMA_2) &&
+ (mvm->cfg->non_shared_ant & enabled_ants))
+ return mvm->cfg->non_shared_ant;
+
+ return first_antenna(enabled_ants);
+}
+
u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,
struct ieee80211_tx_info *info, u8 ac)
{
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h
index d61ff66ce07b..d96ada3c06fc 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h
@@ -18,11 +18,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
index 79bdae994822..843f3b41b72e 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
@@ -434,23 +434,13 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
u8 chains_static, chains_dynamic;
struct cfg80211_chan_def chandef;
int ret, i;
- struct iwl_binding_cmd binding_cmd = {};
+ struct iwl_binding_cmd_v1 binding_cmd = {};
struct iwl_time_quota_cmd quota_cmd = {};
struct iwl_time_quota_data *quota;
u32 status;
- int size;
-
- if (fw_has_capa(&mvm->fw->ucode_capa,
- IWL_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT)) {
- size = sizeof(binding_cmd);
- if (mvmvif->phy_ctxt->channel->band == NL80211_BAND_2GHZ ||
- !iwl_mvm_is_cdb_supported(mvm))
- binding_cmd.lmac_id = cpu_to_le32(IWL_LMAC_24G_INDEX);
- else
- binding_cmd.lmac_id = cpu_to_le32(IWL_LMAC_5G_INDEX);
- } else {
- size = IWL_BINDING_CMD_SIZE_V1;
- }
+
+ if (WARN_ON_ONCE(iwl_mvm_is_cdb_supported(mvm)))
+ return -EINVAL;
/* add back the PHY */
if (WARN_ON(!mvmvif->phy_ctxt))
@@ -497,7 +487,8 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
status = 0;
ret = iwl_mvm_send_cmd_pdu_status(mvm, BINDING_CONTEXT_CMD,
- size, &binding_cmd, &status);
+ IWL_BINDING_CMD_SIZE_V1, &binding_cmd,
+ &status);
if (ret) {
IWL_ERR(mvm, "Failed to add binding: %d\n", ret);
return ret;
@@ -731,8 +722,10 @@ int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,
{
struct iwl_wowlan_kek_kck_material_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);
struct wowlan_key_data key_data = {
- .configure_keys = !d0i3,
+ .configure_keys = !d0i3 && !unified,
.use_rsc_tsc = false,
.tkip = &tkip_cmd,
.use_tkip = false,
@@ -1042,7 +1035,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
* the recording automatically before entering D3. This can
* be removed once the FW starts doing that.
*/
- iwl_fw_dbg_stop_recording(&mvm->fwrt);
+ _iwl_fw_dbg_stop_recording(mvm->fwrt.trans, NULL);
/* must be last -- this switches firmware state */
ret = iwl_mvm_send_cmd(mvm, &d3_cfg_cmd);
@@ -1362,7 +1355,7 @@ static void iwl_mvm_set_key_rx_seq(struct iwl_mvm *mvm,
struct ieee80211_key_conf *key,
struct iwl_wowlan_status *status)
{
- union iwl_all_tsc_rsc *rsc = &status->gtk.rsc.all_tsc_rsc;
+ union iwl_all_tsc_rsc *rsc = &status->gtk[0].rsc.all_tsc_rsc;
switch (key->cipher) {
case WLAN_CIPHER_SUITE_CCMP:
@@ -1419,7 +1412,8 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw,
*/
if (sta) {
struct ieee80211_key_seq seq = {};
- union iwl_all_tsc_rsc *sc = &data->status->gtk.rsc.all_tsc_rsc;
+ union iwl_all_tsc_rsc *sc =
+ &data->status->gtk[0].rsc.all_tsc_rsc;
if (data->find_phase)
return;
@@ -1501,22 +1495,24 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm,
u8 key[32];
} conf = {
.conf.cipher = gtkdata.cipher,
- .conf.keyidx = status->gtk.key_index,
+ .conf.keyidx =
+ iwlmvm_wowlan_gtk_idx(&status->gtk[0]),
};
+ __be64 replay_ctr;
switch (gtkdata.cipher) {
case WLAN_CIPHER_SUITE_CCMP:
conf.conf.keylen = WLAN_KEY_LEN_CCMP;
- memcpy(conf.conf.key, status->gtk.decrypt_key,
+ memcpy(conf.conf.key, status->gtk[0].key,
WLAN_KEY_LEN_CCMP);
break;
case WLAN_CIPHER_SUITE_TKIP:
conf.conf.keylen = WLAN_KEY_LEN_TKIP;
- memcpy(conf.conf.key, status->gtk.decrypt_key, 16);
+ memcpy(conf.conf.key, status->gtk[0].key, 16);
/* leave TX MIC key zeroed, we don't use it anyway */
memcpy(conf.conf.key +
NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY,
- status->gtk.tkip_mic_key, 8);
+ status->gtk[0].tkip_mic_key, 8);
break;
}
@@ -1524,11 +1520,10 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm,
if (IS_ERR(key))
return false;
iwl_mvm_set_key_rx_seq(mvm, key, status);
- }
- if (status->num_of_gtk_rekeys) {
- __be64 replay_ctr =
+ replay_ctr =
cpu_to_be64(le64_to_cpu(status->replay_ctr));
+
ieee80211_gtk_rekey_notify(vif, vif->bss_conf.bssid,
(void *)&replay_ctr, GFP_KERNEL);
}
@@ -1541,71 +1536,118 @@ out:
return true;
}
-static struct iwl_wowlan_status *
-iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+struct iwl_wowlan_status *iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm)
{
- u32 base = mvm->error_event_table[0];
- struct error_table_start {
- /* cf. struct iwl_error_event_table */
- u32 valid;
- u32 error_id;
- } err_info;
+ struct iwl_wowlan_status *v7, *status;
struct iwl_host_cmd cmd = {
.id = WOWLAN_GET_STATUSES,
.flags = CMD_WANT_SKB,
};
- struct iwl_wowlan_status *status, *fw_status;
int ret, len, status_size;
- iwl_trans_read_mem_bytes(mvm->trans, base,
- &err_info, sizeof(err_info));
-
- if (err_info.valid) {
- IWL_INFO(mvm, "error table is valid (%d) with error (%d)\n",
- err_info.valid, err_info.error_id);
- if (err_info.error_id == RF_KILL_INDICATOR_FOR_WOWLAN) {
- struct cfg80211_wowlan_wakeup wakeup = {
- .rfkill_release = true,
- };
- ieee80211_report_wowlan_wakeup(vif, &wakeup,
- GFP_KERNEL);
- }
- return ERR_PTR(-EIO);
- }
-
- /* 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);
+ lockdep_assert_held(&mvm->mutex);
ret = iwl_mvm_send_cmd(mvm, &cmd);
if (ret) {
- IWL_ERR(mvm, "failed to query status (%d)\n", ret);
+ IWL_ERR(mvm, "failed to query wakeup status (%d)\n", ret);
return ERR_PTR(ret);
}
- status_size = sizeof(*fw_status);
+ if (!fw_has_api(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_API_WOWLAN_KEY_MATERIAL)) {
+ struct iwl_wowlan_status_v6 *v6 = (void *)cmd.resp_pkt->data;
+ int data_size;
+
+ status_size = sizeof(*v6);
+ len = iwl_rx_packet_payload_len(cmd.resp_pkt);
+
+ if (len < status_size) {
+ IWL_ERR(mvm, "Invalid WoWLAN status response!\n");
+ status = ERR_PTR(-EIO);
+ goto out_free_resp;
+ }
+
+ data_size = ALIGN(le32_to_cpu(v6->wake_packet_bufsize), 4);
+
+ if (len != (status_size + data_size)) {
+ IWL_ERR(mvm, "Invalid WoWLAN status response!\n");
+ status = ERR_PTR(-EIO);
+ goto out_free_resp;
+ }
+
+ status = kzalloc(sizeof(*status) + data_size, GFP_KERNEL);
+ if (!status)
+ goto out_free_resp;
+
+ BUILD_BUG_ON(sizeof(v6->gtk.decrypt_key) >
+ sizeof(status->gtk[0].key));
+ BUILD_BUG_ON(sizeof(v6->gtk.tkip_mic_key) >
+ sizeof(status->gtk[0].tkip_mic_key));
+
+ /* copy GTK info to the right place */
+ memcpy(status->gtk[0].key, v6->gtk.decrypt_key,
+ sizeof(v6->gtk.decrypt_key));
+ memcpy(status->gtk[0].tkip_mic_key, v6->gtk.tkip_mic_key,
+ sizeof(v6->gtk.tkip_mic_key));
+ memcpy(&status->gtk[0].rsc, &v6->gtk.rsc,
+ sizeof(status->gtk[0].rsc));
+
+ /* hardcode the key length to 16 since v6 only supports 16 */
+ status->gtk[0].key_len = 16;
+
+ /*
+ * The key index only uses 2 bits (values 0 to 3) and
+ * we always set bit 7 which means this is the
+ * currently used key.
+ */
+ status->gtk[0].key_flags = v6->gtk.key_index | BIT(7);
+
+ status->replay_ctr = v6->replay_ctr;
+
+ /* everything starting from pattern_number is identical */
+ memcpy(&status->pattern_number, &v6->pattern_number,
+ offsetof(struct iwl_wowlan_status, wake_packet) -
+ offsetof(struct iwl_wowlan_status, pattern_number) +
+ data_size);
+
+ goto out_free_resp;
+ }
+ v7 = (void *)cmd.resp_pkt->data;
+ status_size = sizeof(*v7);
len = iwl_rx_packet_payload_len(cmd.resp_pkt);
+
if (len < status_size) {
IWL_ERR(mvm, "Invalid WoWLAN status response!\n");
- fw_status = ERR_PTR(-EIO);
+ status = ERR_PTR(-EIO);
goto out_free_resp;
}
- status = (void *)cmd.resp_pkt->data;
if (len != (status_size +
- ALIGN(le32_to_cpu(status->wake_packet_bufsize), 4))) {
+ ALIGN(le32_to_cpu(v7->wake_packet_bufsize), 4))) {
IWL_ERR(mvm, "Invalid WoWLAN status response!\n");
- fw_status = ERR_PTR(-EIO);
+ status = ERR_PTR(-EIO);
goto out_free_resp;
}
- fw_status = kmemdup(status, len, GFP_KERNEL);
+ status = kmemdup(v7, len, GFP_KERNEL);
out_free_resp:
iwl_free_resp(&cmd);
- return fw_status;
+ return status;
+}
+
+static struct iwl_wowlan_status *
+iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm)
+{
+ 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);
+
+ return iwl_mvm_send_wowlan_get_status(mvm);
}
/* releases the MVM mutex */
@@ -1618,7 +1660,7 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
bool keep;
struct iwl_mvm_sta *mvm_ap_sta;
- fw_status = iwl_mvm_get_wakeup_status(mvm, vif);
+ fw_status = iwl_mvm_get_wakeup_status(mvm);
if (IS_ERR_OR_NULL(fw_status))
goto out_unlock;
@@ -1743,7 +1785,7 @@ static void iwl_mvm_query_netdetect_reasons(struct iwl_mvm *mvm,
u32 reasons = 0;
int i, j, n_matches, ret;
- fw_status = iwl_mvm_get_wakeup_status(mvm, vif);
+ fw_status = iwl_mvm_get_wakeup_status(mvm);
if (!IS_ERR_OR_NULL(fw_status)) {
reasons = le32_to_cpu(fw_status->wakeup_reasons);
kfree(fw_status);
@@ -1856,6 +1898,29 @@ static void iwl_mvm_d3_disconnect_iter(void *data, u8 *mac,
ieee80211_resume_disconnect(vif);
}
+static int iwl_mvm_check_rt_status(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif)
+{
+ u32 base = mvm->error_event_table[0];
+ struct error_table_start {
+ /* cf. struct iwl_error_event_table */
+ u32 valid;
+ u32 error_id;
+ } err_info;
+
+ iwl_trans_read_mem_bytes(mvm->trans, base,
+ &err_info, sizeof(err_info));
+
+ if (err_info.valid &&
+ err_info.error_id == RF_KILL_INDICATOR_FOR_WOWLAN) {
+ struct cfg80211_wowlan_wakeup wakeup = {
+ .rfkill_release = true,
+ };
+ ieee80211_report_wowlan_wakeup(vif, &wakeup, GFP_KERNEL);
+ }
+ return err_info.valid;
+}
+
static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
{
struct ieee80211_vif *vif = NULL;
@@ -1883,9 +1948,19 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
goto err;
}
+ iwl_fw_dbg_read_d3_debug_data(&mvm->fwrt);
/* query SRAM first in case we want event logging */
iwl_mvm_read_d3_sram(mvm);
+ if (iwl_mvm_check_rt_status(mvm, vif)) {
+ set_bit(STATUS_FW_ERROR, &mvm->trans->status);
+ iwl_mvm_dump_nic_error_log(mvm);
+ iwl_fw_dbg_collect_desc(&mvm->fwrt, &iwl_dump_desc_assert,
+ NULL, 0);
+ ret = 1;
+ goto err;
+ }
+
if (d0i3_first) {
ret = iwl_mvm_send_cmd_pdu(mvm, D0I3_END_CMD, 0, 0, NULL);
if (ret < 0) {
@@ -2117,6 +2192,8 @@ static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file)
mvm->d3_test_active = false;
+ iwl_fw_dbg_read_d3_debug_data(&mvm->fwrt);
+
rtnl_lock();
__iwl_mvm_resume(mvm, true);
rtnl_unlock();
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c
index 798605c4f122..1aa6c7e93088 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c
@@ -18,11 +18,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
index 05b77419953c..3b6b3d8fb961 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
@@ -19,11 +19,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
@@ -671,16 +666,11 @@ iwl_dbgfs_bt_force_ant_write(struct iwl_mvm *mvm, char *buf,
};
int ret, bt_force_ant_mode;
- for (bt_force_ant_mode = 0;
- bt_force_ant_mode < ARRAY_SIZE(modes_str);
- bt_force_ant_mode++) {
- if (!strcmp(buf, modes_str[bt_force_ant_mode]))
- break;
- }
-
- if (bt_force_ant_mode >= ARRAY_SIZE(modes_str))
- return -EINVAL;
+ ret = match_string(modes_str, ARRAY_SIZE(modes_str), buf);
+ if (ret < 0)
+ return ret;
+ bt_force_ant_mode = ret;
ret = 0;
mutex_lock(&mvm->mutex);
if (mvm->bt_force_ant_mode == bt_force_ant_mode)
@@ -1733,6 +1723,35 @@ iwl_dbgfs_send_echo_cmd_write(struct iwl_mvm *mvm, char *buf,
}
static ssize_t
+iwl_dbgfs_he_sniffer_params_write(struct iwl_mvm *mvm, char *buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_he_monitor_cmd he_mon_cmd = {};
+ u32 aid;
+ int ret;
+
+ if (!iwl_mvm_firmware_running(mvm))
+ return -EIO;
+
+ ret = sscanf(buf, "%x %2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx", &aid,
+ &he_mon_cmd.bssid[0], &he_mon_cmd.bssid[1],
+ &he_mon_cmd.bssid[2], &he_mon_cmd.bssid[3],
+ &he_mon_cmd.bssid[4], &he_mon_cmd.bssid[5]);
+ if (ret != 7)
+ return -EINVAL;
+
+ he_mon_cmd.aid = cpu_to_le16(aid);
+
+ mutex_lock(&mvm->mutex);
+ ret = iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(HE_AIR_SNIFFER_CONFIG_CMD,
+ DATA_PATH_GROUP, 0), 0,
+ sizeof(he_mon_cmd), &he_mon_cmd);
+ mutex_unlock(&mvm->mutex);
+
+ return ret ?: count;
+}
+
+static ssize_t
iwl_dbgfs_uapsd_noagg_bssids_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
@@ -1801,6 +1820,8 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8);
MVM_DEBUGFS_READ_FILE_OPS(sar_geo_profile);
#endif
+MVM_DEBUGFS_WRITE_FILE_OPS(he_sniffer_params, 32);
+
static ssize_t iwl_dbgfs_mem_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
@@ -1989,6 +2010,7 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
#ifdef CONFIG_ACPI
MVM_DEBUGFS_ADD_FILE(sar_geo_profile, dbgfs_dir, 0400);
#endif
+ MVM_DEBUGFS_ADD_FILE(he_sniffer_params, mvm->debugfs_dir, 0200);
if (!debugfs_create_bool("enable_scan_iteration_notif",
0600,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.h b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.h
index ede6ef8d390e..a83d252c0602 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.h
@@ -17,11 +17,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h
index e8e74dd558f7..143c7fcaea41 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h
@@ -18,11 +18,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
index 6bb1a99a197a..dade206d5511 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
@@ -19,11 +19,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
@@ -304,6 +299,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
enum iwl_ucode_type old_type = mvm->fwrt.cur_fw_img;
static const u16 alive_cmd[] = { MVM_ALIVE };
+ set_bit(IWL_FWRT_STATUS_WAIT_ALIVE, &mvm->fwrt.status);
if (ucode_type == IWL_UCODE_REGULAR &&
iwl_fw_dbg_conf_usniffer(mvm->fw, FW_DBG_START_FROM_ALIVE) &&
!(fw_has_capa(&mvm->fw->ucode_capa,
@@ -368,12 +364,20 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
*/
memset(&mvm->queue_info, 0, sizeof(mvm->queue_info));
- mvm->queue_info[IWL_MVM_DQA_CMD_QUEUE].hw_queue_refcount = 1;
+ /*
+ * Set a 'fake' TID for the command queue, since we use the
+ * hweight() of the tid_bitmap as a refcount now. Not that
+ * we ever even consider the command queue as one we might
+ * want to reuse, but be safe nevertheless.
+ */
+ mvm->queue_info[IWL_MVM_DQA_CMD_QUEUE].tid_bitmap =
+ BIT(IWL_MAX_TID_COUNT + 2);
for (i = 0; i < IEEE80211_MAX_QUEUES; i++)
atomic_set(&mvm->mac80211_queue_stop_count[i], 0);
set_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status);
+ clear_bit(IWL_FWRT_STATUS_WAIT_ALIVE, &mvm->fwrt.status);
return 0;
}
@@ -704,8 +708,12 @@ static int iwl_mvm_sar_get_ewrd_table(struct iwl_mvm *mvm)
enabled = !!(wifi_pkg->package.elements[1].integer.value);
n_profiles = wifi_pkg->package.elements[2].integer.value;
- /* in case of BIOS bug */
- if (n_profiles <= 0) {
+ /*
+ * Check the validity of n_profiles. The EWRD profiles start
+ * from index 1, so the maximum value allowed here is
+ * ACPI_SAR_PROFILES_NUM - 1.
+ */
+ if (n_profiles <= 0 || n_profiles >= ACPI_SAR_PROFILE_NUM) {
ret = -EINVAL;
goto out_free;
}
@@ -773,19 +781,28 @@ out_free:
int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b)
{
- struct iwl_dev_tx_power_cmd cmd = {
- .v3.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_CHAINS),
- };
+ union {
+ struct iwl_dev_tx_power_cmd v5;
+ struct iwl_dev_tx_power_cmd_v4 v4;
+ } cmd;
int i, j, idx;
int profs[ACPI_SAR_NUM_CHAIN_LIMITS] = { prof_a, prof_b };
- int len = sizeof(cmd);
+ int len;
BUILD_BUG_ON(ACPI_SAR_NUM_CHAIN_LIMITS < 2);
BUILD_BUG_ON(ACPI_SAR_NUM_CHAIN_LIMITS * ACPI_SAR_NUM_SUB_BANDS !=
ACPI_SAR_TABLE_SIZE);
- if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TX_POWER_ACK))
- len = sizeof(cmd.v3);
+ cmd.v5.v3.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_CHAINS);
+
+ if (fw_has_api(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_API_REDUCE_TX_POWER))
+ len = sizeof(cmd.v5);
+ else if (fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_TX_POWER_ACK))
+ len = sizeof(cmd.v4);
+ else
+ len = sizeof(cmd.v4.v3);
for (i = 0; i < ACPI_SAR_NUM_CHAIN_LIMITS; i++) {
struct iwl_mvm_sar_profile *prof;
@@ -812,7 +829,7 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b)
IWL_DEBUG_RADIO(mvm, " Chain[%d]:\n", i);
for (j = 0; j < ACPI_SAR_NUM_SUB_BANDS; j++) {
idx = (i * ACPI_SAR_NUM_SUB_BANDS) + j;
- cmd.v3.per_chain_restriction[i][j] =
+ cmd.v5.v3.per_chain_restriction[i][j] =
cpu_to_le16(prof->table[idx]);
IWL_DEBUG_RADIO(mvm, " Band[%d] = %d * .125dBm\n",
j, prof->table[idx]);
@@ -1018,7 +1035,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
mvm->fwrt.dump.conf = FW_DBG_INVALID;
/* if we have a destination, assume EARLY START */
- if (mvm->fw->dbg_dest_tlv)
+ if (mvm->fw->dbg.dest_tlv)
mvm->fwrt.dump.conf = FW_DBG_START_FROM_ALIVE;
iwl_fw_start_dbg_conf(&mvm->fwrt, FW_DBG_START_FROM_ALIVE);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/led.c b/drivers/net/wireless/intel/iwlwifi/mvm/led.c
index b27269504a62..9bb1de1cad64 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/led.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/led.c
@@ -17,11 +17,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
index b3fd20502abb..6486cfb33f40 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
@@ -8,6 +8,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* Copyright(c) 2015 - 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -18,11 +19,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
@@ -35,6 +31,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* Copyright(c) 2015 - 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -85,6 +82,10 @@ const u8 iwl_mvm_ac_to_gen2_tx_fifo[] = {
IWL_GEN2_EDCA_TX_FIFO_VI,
IWL_GEN2_EDCA_TX_FIFO_BE,
IWL_GEN2_EDCA_TX_FIFO_BK,
+ IWL_GEN2_TRIG_TX_FIFO_VO,
+ IWL_GEN2_TRIG_TX_FIFO_VI,
+ IWL_GEN2_TRIG_TX_FIFO_BE,
+ IWL_GEN2_TRIG_TX_FIFO_BK,
};
struct iwl_mvm_mac_iface_iterator_data {
@@ -1486,12 +1487,11 @@ static void iwl_mvm_beacon_loss_iterator(void *_data, u8 *mac,
IWL_MVM_MISSED_BEACONS_THRESHOLD)
ieee80211_beacon_loss(vif);
- if (!iwl_fw_dbg_trigger_enabled(mvm->fw,
- FW_DBG_TRIGGER_MISSED_BEACONS))
+ trigger = iwl_fw_dbg_trigger_on(&mvm->fwrt, ieee80211_vif_to_wdev(vif),
+ FW_DBG_TRIGGER_MISSED_BEACONS);
+ if (!trigger)
return;
- trigger = iwl_fw_dbg_get_trigger(mvm->fw,
- FW_DBG_TRIGGER_MISSED_BEACONS);
bcon_trig = (void *)trigger->data;
stop_trig_missed_bcon = le32_to_cpu(bcon_trig->stop_consec_missed_bcon);
stop_trig_missed_bcon_since_rx =
@@ -1499,11 +1499,6 @@ static void iwl_mvm_beacon_loss_iterator(void *_data, u8 *mac,
/* TODO: implement start trigger */
- if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt,
- ieee80211_vif_to_wdev(vif),
- trigger))
- return;
-
if (rx_missed_bcon_since_rx >= stop_trig_missed_bcon_since_rx ||
rx_missed_bcon >= stop_trig_missed_bcon)
iwl_fw_dbg_collect_trig(&mvm->fwrt, trigger, NULL);
@@ -1568,6 +1563,65 @@ void iwl_mvm_rx_stored_beacon_notif(struct iwl_mvm *mvm,
ieee80211_rx_napi(mvm->hw, NULL, skb, NULL);
}
+static void iwl_mvm_probe_resp_data_iter(void *_data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_probe_resp_data_notif *notif = _data;
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_probe_resp_data *old_data, *new_data;
+
+ if (mvmvif->id != (u16)le32_to_cpu(notif->mac_id))
+ return;
+
+ new_data = kzalloc(sizeof(*new_data), GFP_KERNEL);
+ if (!new_data)
+ return;
+
+ memcpy(&new_data->notif, notif, sizeof(new_data->notif));
+
+ /* noa_attr contains 1 reserved byte, need to substruct it */
+ new_data->noa_len = sizeof(struct ieee80211_vendor_ie) +
+ sizeof(new_data->notif.noa_attr) - 1;
+
+ /*
+ * If it's a one time NoA, only one descriptor is needed,
+ * adjust the length according to len_low.
+ */
+ if (new_data->notif.noa_attr.len_low ==
+ sizeof(struct ieee80211_p2p_noa_desc) + 2)
+ new_data->noa_len -= sizeof(struct ieee80211_p2p_noa_desc);
+
+ old_data = rcu_dereference_protected(mvmvif->probe_resp_data,
+ lockdep_is_held(&mvmvif->mvm->mutex));
+ rcu_assign_pointer(mvmvif->probe_resp_data, new_data);
+
+ if (old_data)
+ kfree_rcu(old_data, rcu_head);
+
+ if (notif->csa_counter != IWL_PROBE_RESP_DATA_NO_CSA &&
+ notif->csa_counter >= 1)
+ ieee80211_csa_set_counter(vif, notif->csa_counter);
+}
+
+void iwl_mvm_probe_resp_data_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+ struct iwl_probe_resp_data_notif *notif = (void *)pkt->data;
+ int len = iwl_rx_packet_payload_len(pkt);
+
+ if (WARN_ON_ONCE(len < sizeof(*notif)))
+ return;
+
+ IWL_DEBUG_INFO(mvm, "Probe response data notif: noa %d, csa %d\n",
+ notif->noa_active, notif->csa_counter);
+
+ ieee80211_iterate_active_interfaces(mvm->hw,
+ IEEE80211_IFACE_ITER_ACTIVE,
+ iwl_mvm_probe_resp_data_iter,
+ notif);
+}
+
void iwl_mvm_channel_switch_noa_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb)
{
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index b15b0d84bb7e..505b0385d800 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -19,11 +19,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
@@ -559,8 +554,6 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
hw->wiphy->max_remain_on_channel_duration = 10000;
hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL;
- /* we can compensate an offset of up to 3 channels = 15 MHz */
- hw->wiphy->max_adj_channel_rssi_comp = 3 * 5;
/* Extract MAC address */
memcpy(mvm->addresses[0].addr, mvm->nvm_data->hw_addr, ETH_ALEN);
@@ -864,16 +857,13 @@ iwl_mvm_ampdu_check_trigger(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct iwl_fw_dbg_trigger_tlv *trig;
struct iwl_fw_dbg_trigger_ba *ba_trig;
- if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_BA))
+ trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, ieee80211_vif_to_wdev(vif),
+ FW_DBG_TRIGGER_BA);
+ if (!trig)
return;
- trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_BA);
ba_trig = (void *)trig->data;
- if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt,
- ieee80211_vif_to_wdev(vif), trig))
- return;
-
switch (action) {
case IEEE80211_AMPDU_TX_OPERATIONAL: {
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
@@ -1035,6 +1025,7 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac,
mvmvif->phy_ctxt = NULL;
memset(&mvmvif->bf_data, 0, sizeof(mvmvif->bf_data));
+ memset(&mvmvif->probe_resp_data, 0, sizeof(mvmvif->probe_resp_data));
}
static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
@@ -1124,7 +1115,9 @@ int __iwl_mvm_mac_start(struct iwl_mvm *mvm)
* would do.
*/
clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
+#ifdef CONFIG_PM
iwl_mvm_d0i3_enable_tx(mvm, NULL);
+#endif
}
return ret;
@@ -1162,7 +1155,9 @@ static void iwl_mvm_restart_complete(struct iwl_mvm *mvm)
mutex_lock(&mvm->mutex);
clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
+#ifdef CONFIG_PM
iwl_mvm_d0i3_enable_tx(mvm, NULL);
+#endif
ret = iwl_mvm_update_quotas(mvm, true, NULL);
if (ret)
IWL_ERR(mvm, "Failed to update quotas after restart (%d)\n",
@@ -1233,12 +1228,15 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm)
iwl_mvm_del_aux_sta(mvm);
/*
- * Clear IN_HW_RESTART flag when stopping the hw (as restart_complete()
- * won't be called in this case).
+ * Clear IN_HW_RESTART and HW_RESTART_REQUESTED flag when stopping the
+ * hw (as restart_complete() won't be called in this case) and mac80211
+ * won't execute the restart.
* But make sure to cleanup interfaces that have gone down before/during
* HW restart was requested.
*/
- if (test_and_clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
+ if (test_and_clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) ||
+ test_and_clear_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED,
+ &mvm->status))
ieee80211_iterate_interfaces(mvm->hw, 0,
iwl_mvm_cleanup_iterator, mvm);
@@ -1308,19 +1306,28 @@ static struct iwl_mvm_phy_ctxt *iwl_mvm_get_free_phy_ctxt(struct iwl_mvm *mvm)
static int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
s16 tx_power)
{
- struct iwl_dev_tx_power_cmd cmd = {
- .v3.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_MAC),
- .v3.mac_context_id =
+ int len;
+ union {
+ struct iwl_dev_tx_power_cmd v5;
+ struct iwl_dev_tx_power_cmd_v4 v4;
+ } cmd = {
+ .v5.v3.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_MAC),
+ .v5.v3.mac_context_id =
cpu_to_le32(iwl_mvm_vif_from_mac80211(vif)->id),
- .v3.pwr_restriction = cpu_to_le16(8 * tx_power),
+ .v5.v3.pwr_restriction = cpu_to_le16(8 * tx_power),
};
- int len = sizeof(cmd);
if (tx_power == IWL_DEFAULT_MAX_TX_POWER)
- cmd.v3.pwr_restriction = cpu_to_le16(IWL_DEV_MAX_TX_POWER);
+ cmd.v5.v3.pwr_restriction = cpu_to_le16(IWL_DEV_MAX_TX_POWER);
- if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TX_POWER_ACK))
- len = sizeof(cmd.v3);
+ if (fw_has_api(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_API_REDUCE_TX_POWER))
+ len = sizeof(cmd.v5);
+ else if (fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_TX_POWER_ACK))
+ len = sizeof(cmd.v4);
+ else
+ len = sizeof(cmd.v4.v3);
return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, 0, len, &cmd);
}
@@ -1333,6 +1340,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
int ret;
mvmvif->mvm = mvm;
+ RCU_INIT_POINTER(mvmvif->probe_resp_data, NULL);
/*
* make sure D0i3 exit is completed, otherwise a target access
@@ -1497,6 +1505,7 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_probe_resp_data *probe_data;
iwl_mvm_prepare_mac_removal(mvm, vif);
@@ -1506,6 +1515,12 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
mutex_lock(&mvm->mutex);
+ probe_data = rcu_dereference_protected(mvmvif->probe_resp_data,
+ lockdep_is_held(&mvm->mutex));
+ RCU_INIT_POINTER(mvmvif->probe_resp_data, NULL);
+ if (probe_data)
+ kfree_rcu(probe_data, rcu_head);
+
if (mvm->bf_allowed_vif == mvmvif) {
mvm->bf_allowed_vif = NULL;
vif->driver_flags &= ~(IEEE80211_VIF_BEACON_FILTER |
@@ -1978,10 +1993,6 @@ static void iwl_mvm_cfg_he_sta(struct iwl_mvm *mvm,
sta_ctxt_cmd.htc_flags |=
cpu_to_le32(IWL_HE_HTC_LINK_ADAP_BOTH);
}
- if (sta->he_cap.he_cap_elem.mac_cap_info[2] &
- IEEE80211_HE_MAC_CAP2_UL_MU_RESP_SCHED)
- sta_ctxt_cmd.htc_flags |=
- cpu_to_le32(IWL_HE_HTC_UL_MU_RESP_SCHED);
if (sta->he_cap.he_cap_elem.mac_cap_info[2] & IEEE80211_HE_MAC_CAP2_BSR)
sta_ctxt_cmd.htc_flags |= cpu_to_le32(IWL_HE_HTC_BSR_SUPP);
if (sta->he_cap.he_cap_elem.mac_cap_info[3] &
@@ -2459,6 +2470,9 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw,
iwl_mvm_mac_ctxt_remove(mvm, vif);
+ kfree(mvmvif->ap_wep_key);
+ mvmvif->ap_wep_key = NULL;
+
mutex_unlock(&mvm->mutex);
}
@@ -2788,14 +2802,12 @@ iwl_mvm_tdls_check_trigger(struct iwl_mvm *mvm,
struct iwl_fw_dbg_trigger_tlv *trig;
struct iwl_fw_dbg_trigger_tdls *tdls_trig;
- if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_TDLS))
+ trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, ieee80211_vif_to_wdev(vif),
+ FW_DBG_TRIGGER_TDLS);
+ if (!trig)
return;
- trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_TDLS);
tdls_trig = (void *)trig->data;
- if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt,
- ieee80211_vif_to_wdev(vif), trig))
- return;
if (!(tdls_trig->action_bitmap & BIT(action)))
return;
@@ -2931,7 +2943,8 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
}
- iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band);
+ iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band,
+ false);
ret = iwl_mvm_update_sta(mvm, vif, sta);
} else if (old_state == IEEE80211_STA_ASSOC &&
new_state == IEEE80211_STA_AUTHORIZED) {
@@ -2947,9 +2960,16 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
/* enable beacon filtering */
WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0));
- iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band);
+ iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band,
+ true);
- ret = 0;
+ /* if wep is used, need to set the key for the station now */
+ if (vif->type == NL80211_IFTYPE_AP && mvmvif->ap_wep_key)
+ ret = iwl_mvm_set_sta_key(mvm, vif, sta,
+ mvmvif->ap_wep_key,
+ STA_KEY_IDX_INVALID);
+ else
+ ret = 0;
} else if (old_state == IEEE80211_STA_AUTHORIZED &&
new_state == IEEE80211_STA_ASSOC) {
/* disable beacon filtering */
@@ -3132,8 +3152,15 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
switch (key->cipher) {
case WLAN_CIPHER_SUITE_TKIP:
- key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
- key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
+ if (!mvm->trans->cfg->gen2) {
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
+ key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
+ } else if (vif->type == NL80211_IFTYPE_STATION) {
+ key->flags |= IEEE80211_KEY_FLAG_PUT_MIC_SPACE;
+ } else {
+ IWL_DEBUG_MAC80211(mvm, "Use SW encryption for TKIP\n");
+ return -EOPNOTSUPP;
+ }
break;
case WLAN_CIPHER_SUITE_CCMP:
case WLAN_CIPHER_SUITE_GCMP:
@@ -3148,13 +3175,17 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
break;
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
- /* For non-client mode, only use WEP keys for TX as we probably
- * don't have a station yet anyway and would then have to keep
- * track of the keys, linking them to each of the clients/peers
- * as they appear. For now, don't do that, for performance WEP
- * offload doesn't really matter much, but we need it for some
- * other offload features in client mode.
- */
+ if (vif->type == NL80211_IFTYPE_AP) {
+ struct iwl_mvm_vif *mvmvif =
+ iwl_mvm_vif_from_mac80211(vif);
+
+ mvmvif->ap_wep_key = kmemdup(key,
+ sizeof(*key) + key->keylen,
+ GFP_KERNEL);
+ if (!mvmvif->ap_wep_key)
+ return -ENOMEM;
+ }
+
if (vif->type != NL80211_IFTYPE_STATION)
return 0;
break;
@@ -4458,14 +4489,12 @@ static void iwl_mvm_event_mlme_callback(struct iwl_mvm *mvm,
struct iwl_fw_dbg_trigger_tlv *trig;
struct iwl_fw_dbg_trigger_mlme *trig_mlme;
- if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_MLME))
+ trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, ieee80211_vif_to_wdev(vif),
+ FW_DBG_TRIGGER_MLME);
+ if (!trig)
return;
- trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_MLME);
trig_mlme = (void *)trig->data;
- if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt,
- ieee80211_vif_to_wdev(vif), trig))
- return;
if (event->u.mlme.data == ASSOC_EVENT) {
if (event->u.mlme.status == MLME_DENIED)
@@ -4500,14 +4529,12 @@ static void iwl_mvm_event_bar_rx_callback(struct iwl_mvm *mvm,
struct iwl_fw_dbg_trigger_tlv *trig;
struct iwl_fw_dbg_trigger_ba *ba_trig;
- if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_BA))
+ trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, ieee80211_vif_to_wdev(vif),
+ FW_DBG_TRIGGER_BA);
+ if (!trig)
return;
- trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_BA);
ba_trig = (void *)trig->data;
- if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt,
- ieee80211_vif_to_wdev(vif), trig))
- return;
if (!(le16_to_cpu(ba_trig->rx_bar) & BIT(event->u.ba.tid)))
return;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index b3987a0a7018..7ba5bc2ed1c4 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -19,11 +19,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
@@ -336,6 +331,18 @@ struct iwl_mvm_vif_bf_data {
};
/**
+ * struct iwl_probe_resp_data - data for NoA/CSA updates
+ * @rcu_head: used for freeing the data on update
+ * @notif: notification data
+ * @noa_len: length of NoA attribute, calculated from the notification
+ */
+struct iwl_probe_resp_data {
+ struct rcu_head rcu_head;
+ struct iwl_probe_resp_data_notif notif;
+ int noa_len;
+};
+
+/**
* struct iwl_mvm_vif - data per Virtual Interface, it is a MAC context
* @id: between 0 and 3
* @color: to solve races upon MAC addition and removal
@@ -365,6 +372,8 @@ struct iwl_mvm_vif_bf_data {
* average signal of beacons retrieved from the firmware
* @csa_failed: CSA failed to schedule time event, report an error later
* @features: hw features active for this vif
+ * @probe_resp_data: data from FW notification to store NOA and CSA related
+ * data to be inserted into probe response.
*/
struct iwl_mvm_vif {
struct iwl_mvm *mvm;
@@ -460,6 +469,9 @@ struct iwl_mvm_vif {
/* TCP Checksum Offload */
netdev_features_t features;
+
+ struct iwl_probe_resp_data __rcu *probe_resp_data;
+ struct ieee80211_key_conf *ap_wep_key;
};
static inline struct iwl_mvm_vif *
@@ -500,6 +512,7 @@ enum iwl_mvm_scan_type {
IWL_SCAN_TYPE_WILD,
IWL_SCAN_TYPE_MILD,
IWL_SCAN_TYPE_FRAGMENTED,
+ IWL_SCAN_TYPE_FAST_BALANCE,
};
enum iwl_mvm_sched_scan_pass_all_states {
@@ -741,24 +754,12 @@ iwl_mvm_baid_data_from_reorder_buf(struct iwl_mvm_reorder_buffer *buf)
* This is a state in which a single queue serves more than one TID, all of
* which are not aggregated. Note that the queue is only associated to one
* RA.
- * @IWL_MVM_QUEUE_INACTIVE: queue is allocated but no traffic on it
- * This is a state of a queue that has had traffic on it, but during the
- * last %IWL_MVM_DQA_QUEUE_TIMEOUT time period there has been no traffic on
- * it. In this state, when a new queue is needed to be allocated but no
- * such free queue exists, an inactive queue might be freed and given to
- * the new RA/TID.
- * @IWL_MVM_QUEUE_RECONFIGURING: queue is being reconfigured
- * This is the state of a queue that has had traffic pass through it, but
- * needs to be reconfigured for some reason, e.g. the queue needs to
- * become unshared and aggregations re-enabled on.
*/
enum iwl_mvm_queue_status {
IWL_MVM_QUEUE_FREE,
IWL_MVM_QUEUE_RESERVED,
IWL_MVM_QUEUE_READY,
IWL_MVM_QUEUE_SHARED,
- IWL_MVM_QUEUE_INACTIVE,
- IWL_MVM_QUEUE_RECONFIGURING,
};
#define IWL_MVM_DQA_QUEUE_TIMEOUT (5 * HZ)
@@ -775,6 +776,17 @@ struct iwl_mvm_geo_profile {
u8 values[ACPI_GEO_TABLE_SIZE];
};
+struct iwl_mvm_dqa_txq_info {
+ u8 ra_sta_id; /* The RA this queue is mapped to, if exists */
+ bool reserved; /* Is this the TXQ reserved for a STA */
+ u8 mac80211_ac; /* The mac80211 AC this queue is mapped to */
+ u8 txq_tid; /* The TID "owner" of this queue*/
+ u16 tid_bitmap; /* Bitmap of the TIDs mapped to this queue */
+ /* Timestamp for inactivation per TID of this queue */
+ unsigned long last_frame_time[IWL_MAX_TID_COUNT + 1];
+ enum iwl_mvm_queue_status status;
+};
+
struct iwl_mvm {
/* for logger access */
struct device *dev;
@@ -831,17 +843,7 @@ struct iwl_mvm {
u16 hw_queue_to_mac80211[IWL_MAX_TVQM_QUEUES];
- struct {
- u8 hw_queue_refcount;
- u8 ra_sta_id; /* The RA this queue is mapped to, if exists */
- bool reserved; /* Is this the TXQ reserved for a STA */
- u8 mac80211_ac; /* The mac80211 AC this queue is mapped to */
- u8 txq_tid; /* The TID "owner" of this queue*/
- u16 tid_bitmap; /* Bitmap of the TIDs mapped to this queue */
- /* Timestamp for inactivation per TID of this queue */
- unsigned long last_frame_time[IWL_MAX_TID_COUNT + 1];
- enum iwl_mvm_queue_status status;
- } queue_info[IWL_MAX_HW_QUEUES];
+ struct iwl_mvm_dqa_txq_info queue_info[IWL_MAX_HW_QUEUES];
spinlock_t queue_info_lock; /* For syncing queue mgmt operations */
struct work_struct add_stream_wk; /* To add streams to queues */
@@ -1229,6 +1231,11 @@ static inline bool iwl_mvm_is_oce_supported(struct iwl_mvm *mvm)
return fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_OCE);
}
+static inline bool iwl_mvm_is_frag_ebs_supported(struct iwl_mvm *mvm)
+{
+ return fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_FRAG_EBS);
+}
+
static inline bool iwl_mvm_enter_d0i3_on_suspend(struct iwl_mvm *mvm)
{
/* For now we only use this mode to differentiate between
@@ -1602,6 +1609,8 @@ void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm,
struct ieee80211_vif *vif);
unsigned long iwl_mvm_get_used_hw_queues(struct iwl_mvm *mvm,
struct ieee80211_vif *exclude_vif);
+void iwl_mvm_probe_resp_data_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb);
void iwl_mvm_channel_switch_noa_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb);
/* Bindings */
@@ -1685,7 +1694,7 @@ iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
#endif /* CONFIG_IWLWIFI_DEBUGFS */
/* rate scaling */
-int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool init);
+int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool sync);
void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, u32 rate, bool agg);
int rs_pretty_print_rate(char *buf, int bufsz, const u32 rate);
void rs_update_last_rssi(struct iwl_mvm *mvm,
@@ -1733,6 +1742,7 @@ 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
int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
@@ -1776,10 +1786,13 @@ void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type);
void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type);
int iwl_mvm_ref_sync(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type);
bool iwl_mvm_ref_taken(struct iwl_mvm *mvm);
+
+#ifdef CONFIG_PM
void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq);
int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode);
int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode);
int _iwl_mvm_exit_d0i3(struct iwl_mvm *mvm);
+#endif
/* BT Coex */
int iwl_mvm_send_bt_init_conf(struct iwl_mvm *mvm);
@@ -1796,6 +1809,7 @@ bool iwl_mvm_bt_coex_is_ant_avail(struct iwl_mvm *mvm, u8 ant);
bool iwl_mvm_bt_coex_is_shared_ant_avail(struct iwl_mvm *mvm);
bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm,
enum nl80211_band band);
+u8 iwl_mvm_bt_coex_get_single_ant_msk(struct iwl_mvm *mvm, u8 enabled_ants);
u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,
struct ieee80211_tx_info *info, u8 ac);
@@ -1859,17 +1873,6 @@ void iwl_mvm_vif_set_low_latency(struct iwl_mvm_vif *mvmvif, bool set,
mvmvif->low_latency &= ~cause;
}
-/* hw scheduler queue config */
-bool iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
- u16 ssn, const struct iwl_trans_txq_scd_cfg *cfg,
- unsigned int wdg_timeout);
-int iwl_mvm_tvqm_enable_txq(struct iwl_mvm *mvm, int mac80211_queue,
- u8 sta_id, u8 tid, unsigned int timeout);
-
-int iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
- u8 tid, u8 flags);
-int iwl_mvm_find_free_queue(struct iwl_mvm *mvm, u8 sta_id, u8 minq, u8 maxq);
-
/* Return a bitmask with all the hw supported queues, except for the
* command queue, which can't be flushed.
*/
@@ -1881,6 +1884,11 @@ static inline u32 iwl_mvm_flushable_queues(struct iwl_mvm *mvm)
static inline void iwl_mvm_stop_device(struct iwl_mvm *mvm)
{
+ lockdep_assert_held(&mvm->mutex);
+ /* calling this function without using dump_start/end since at this
+ * point we already hold the op mode mutex
+ */
+ iwl_fw_dbg_collect_sync(&mvm->fwrt);
iwl_fw_cancel_timestamp(&mvm->fwrt);
iwl_free_fw_paging(&mvm->fwrt);
clear_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status);
@@ -1966,8 +1974,6 @@ void iwl_mvm_reorder_timer_expired(struct timer_list *t);
struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm);
bool iwl_mvm_is_vif_assoc(struct iwl_mvm *mvm);
-void iwl_mvm_inactivity_check(struct iwl_mvm *mvm);
-
#define MVM_TCM_PERIOD_MSEC 500
#define MVM_TCM_PERIOD (HZ * MVM_TCM_PERIOD_MSEC / 1000)
#define MVM_LL_PERIOD (10 * HZ)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
index cf48517944ec..3633f27d048a 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
@@ -19,11 +19,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
@@ -482,15 +477,11 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
u32 status;
int resp_len, n_channels;
u16 mcc;
- bool resp_v2 = fw_has_capa(&mvm->fw->ucode_capa,
- IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V2);
if (WARN_ON_ONCE(!iwl_mvm_is_lar_supported(mvm)))
return ERR_PTR(-EOPNOTSUPP);
cmd.len[0] = sizeof(struct iwl_mcc_update_cmd);
- if (!resp_v2)
- cmd.len[0] = sizeof(struct iwl_mcc_update_cmd_v1);
IWL_DEBUG_LAR(mvm, "send MCC update to FW with '%c%c' src = %d\n",
alpha2[0], alpha2[1], src_id);
@@ -502,7 +493,8 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
pkt = cmd.resp_pkt;
/* Extract MCC response */
- if (resp_v2) {
+ if (fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_MCC_UPDATE_11AX_SUPPORT)) {
struct iwl_mcc_update_resp *mcc_resp = (void *)pkt->data;
n_channels = __le32_to_cpu(mcc_resp->n_channels);
@@ -514,9 +506,9 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
goto exit;
}
} else {
- struct iwl_mcc_update_resp_v1 *mcc_resp_v1 = (void *)pkt->data;
+ struct iwl_mcc_update_resp_v3 *mcc_resp_v3 = (void *)pkt->data;
- n_channels = __le32_to_cpu(mcc_resp_v1->n_channels);
+ n_channels = __le32_to_cpu(mcc_resp_v3->n_channels);
resp_len = sizeof(struct iwl_mcc_update_resp) +
n_channels * sizeof(__le32);
resp_cp = kzalloc(resp_len, GFP_KERNEL);
@@ -525,12 +517,14 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
goto exit;
}
- resp_cp->status = mcc_resp_v1->status;
- resp_cp->mcc = mcc_resp_v1->mcc;
- resp_cp->cap = mcc_resp_v1->cap;
- resp_cp->source_id = mcc_resp_v1->source_id;
- resp_cp->n_channels = mcc_resp_v1->n_channels;
- memcpy(resp_cp->channels, mcc_resp_v1->channels,
+ resp_cp->status = mcc_resp_v3->status;
+ resp_cp->mcc = mcc_resp_v3->mcc;
+ resp_cp->cap = cpu_to_le16(mcc_resp_v3->cap);
+ resp_cp->source_id = mcc_resp_v3->source_id;
+ resp_cp->time = mcc_resp_v3->time;
+ resp_cp->geo_info = mcc_resp_v3->geo_info;
+ resp_cp->n_channels = mcc_resp_v3->n_channels;
+ memcpy(resp_cp->channels, mcc_resp_v3->channels,
n_channels * sizeof(__le32));
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c b/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c
index 6338d9cf7070..6d71e05626ad 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c
@@ -18,11 +18,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
index 0e26619fb330..0e2092526fae 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
@@ -19,11 +19,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
@@ -182,6 +177,9 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode)
if (mvm->trans->cfg->device_family < IWL_DEVICE_FAMILY_8000)
reg_val |= CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI;
+ if (iwl_fw_dbg_is_d3_debug_enabled(&mvm->fwrt))
+ reg_val |= CSR_HW_IF_CONFIG_REG_D3_DEBUG;
+
iwl_trans_set_bits_mask(mvm->trans, CSR_HW_IF_CONFIG_REG,
CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH |
CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP |
@@ -189,7 +187,8 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode)
CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP |
CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH |
CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
- CSR_HW_IF_CONFIG_REG_BIT_MAC_SI,
+ CSR_HW_IF_CONFIG_REG_BIT_MAC_SI |
+ CSR_HW_IF_CONFIG_REG_D3_DEBUG,
reg_val);
IWL_DEBUG_INFO(mvm, "Radio type=0x%x-0x%x-0x%x\n", radio_cfg_type,
@@ -491,7 +490,9 @@ static const struct iwl_hcmd_arr iwl_mvm_groups[] = {
/* this forward declaration can avoid to export the function */
static void iwl_mvm_async_handlers_wk(struct work_struct *wk);
+#ifdef CONFIG_PM
static void iwl_mvm_d0i3_exit_work(struct work_struct *wk);
+#endif
static u32 iwl_mvm_min_backoff(struct iwl_mvm *mvm)
{
@@ -564,10 +565,23 @@ static bool iwl_mvm_fwrt_fw_running(void *ctx)
return iwl_mvm_firmware_running(ctx);
}
+static int iwl_mvm_fwrt_send_hcmd(void *ctx, struct iwl_host_cmd *host_cmd)
+{
+ struct iwl_mvm *mvm = (struct iwl_mvm *)ctx;
+ int ret;
+
+ mutex_lock(&mvm->mutex);
+ ret = iwl_mvm_send_cmd(mvm, host_cmd);
+ mutex_unlock(&mvm->mutex);
+
+ return ret;
+}
+
static const struct iwl_fw_runtime_ops iwl_mvm_fwrt_ops = {
.dump_start = iwl_mvm_fwrt_dump_start,
.dump_end = iwl_mvm_fwrt_dump_end,
.fw_running = iwl_mvm_fwrt_fw_running,
+ .send_hcmd = iwl_mvm_fwrt_send_hcmd,
};
static struct iwl_op_mode *
@@ -583,6 +597,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
};
int err, scan_size;
u32 min_backoff;
+ enum iwl_amsdu_size rb_size_default;
/*
* We use IWL_MVM_STATION_COUNT to check the validity of the station
@@ -602,9 +617,13 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
if (cfg->max_rx_agg_size)
hw->max_rx_aggregation_subframes = cfg->max_rx_agg_size;
+ else
+ hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF;
if (cfg->max_tx_agg_size)
hw->max_tx_aggregation_subframes = cfg->max_tx_agg_size;
+ else
+ hw->max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF;
op_mode = hw->priv;
@@ -661,7 +680,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
INIT_WORK(&mvm->async_handlers_wk, iwl_mvm_async_handlers_wk);
INIT_WORK(&mvm->roc_done_wk, iwl_mvm_roc_done_wk);
+#ifdef CONFIG_PM
INIT_WORK(&mvm->d0i3_exit_work, iwl_mvm_d0i3_exit_work);
+#endif
INIT_DELAYED_WORK(&mvm->tdls_cs.dwork, iwl_mvm_tdls_ch_switch_work);
INIT_DELAYED_WORK(&mvm->scan_timeout_dwork, iwl_mvm_scan_timeout_wk);
INIT_WORK(&mvm->add_stream_wk, iwl_mvm_add_new_dqa_stream_wk);
@@ -691,8 +712,16 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
trans_cfg.op_mode = op_mode;
trans_cfg.no_reclaim_cmds = no_reclaim_cmds;
trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds);
+
+ if (mvm->trans->cfg->device_family >= IWL_DEVICE_FAMILY_22560)
+ rb_size_default = IWL_AMSDU_2K;
+ else
+ rb_size_default = IWL_AMSDU_4K;
+
switch (iwlwifi_mod_params.amsdu_size) {
case IWL_AMSDU_DEF:
+ trans_cfg.rx_buf_size = rb_size_default;
+ break;
case IWL_AMSDU_4K:
trans_cfg.rx_buf_size = IWL_AMSDU_4K;
break;
@@ -705,16 +734,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
default:
pr_err("%s: Unsupported amsdu_size: %d\n", KBUILD_MODNAME,
iwlwifi_mod_params.amsdu_size);
- trans_cfg.rx_buf_size = IWL_AMSDU_4K;
- }
-
- /* the hardware splits the A-MSDU */
- if (mvm->trans->cfg->device_family >= IWL_DEVICE_FAMILY_22560) {
- trans_cfg.rx_buf_size = IWL_AMSDU_2K;
- /* TODO: remove when balanced power mode is fw supported */
- iwlmvm_mod_params.power_scheme = IWL_POWER_SCHEME_CAM;
- } else if (mvm->cfg->mq_rx_supported) {
- trans_cfg.rx_buf_size = IWL_AMSDU_4K;
+ trans_cfg.rx_buf_size = rb_size_default;
}
trans->wide_cmd_header = true;
@@ -745,12 +765,12 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
iwl_trans_configure(mvm->trans, &trans_cfg);
trans->rx_mpdu_cmd = REPLY_RX_MPDU_CMD;
- trans->dbg_dest_tlv = mvm->fw->dbg_dest_tlv;
- trans->dbg_dest_reg_num = mvm->fw->dbg_dest_reg_num;
- memcpy(trans->dbg_conf_tlv, mvm->fw->dbg_conf_tlv,
+ trans->dbg_dest_tlv = mvm->fw->dbg.dest_tlv;
+ trans->dbg_n_dest_reg = mvm->fw->dbg.n_dest_reg;
+ memcpy(trans->dbg_conf_tlv, mvm->fw->dbg.conf_tlv,
sizeof(trans->dbg_conf_tlv));
- trans->dbg_trigger_tlv = mvm->fw->dbg_trigger_tlv;
- trans->dbg_dump_mask = mvm->fw->dbg_dump_mask;
+ trans->dbg_trigger_tlv = mvm->fw->dbg.trigger_tlv;
+ trans->dbg_dump_mask = mvm->fw->dbg.dump_mask;
trans->iml = mvm->fw->iml;
trans->iml_len = mvm->fw->iml_len;
@@ -781,6 +801,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
mutex_lock(&mvm->mutex);
iwl_mvm_ref(mvm, IWL_MVM_REF_INIT_UCODE);
err = iwl_run_init_mvm_ucode(mvm, true);
+ if (test_bit(IWL_FWRT_STATUS_WAIT_ALIVE, &mvm->fwrt.status))
+ iwl_fw_alive_error_dump(&mvm->fwrt);
if (!iwlmvm_mod_params.init_dbg || !err)
iwl_mvm_stop_device(mvm);
iwl_mvm_unref(mvm, IWL_MVM_REF_INIT_UCODE);
@@ -950,15 +972,13 @@ static inline void iwl_mvm_rx_check_trigger(struct iwl_mvm *mvm,
struct iwl_fw_dbg_trigger_cmd *cmds_trig;
int i;
- if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_FW_NOTIF))
+ trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, NULL,
+ FW_DBG_TRIGGER_FW_NOTIF);
+ if (!trig)
return;
- trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_FW_NOTIF);
cmds_trig = (void *)trig->data;
- if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, NULL, trig))
- return;
-
for (i = 0; i < ARRAY_SIZE(cmds_trig->cmds); i++) {
/* don't collect on CMD 0 */
if (!cmds_trig->cmds[i].cmd_id)
@@ -1220,7 +1240,7 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error)
*/
if (!mvm->fw_restart && fw_error) {
iwl_fw_dbg_collect_desc(&mvm->fwrt, &iwl_dump_desc_assert,
- NULL);
+ NULL, 0);
} else if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
struct iwl_mvm_reprobe *reprobe;
@@ -1246,7 +1266,8 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error)
INIT_WORK(&reprobe->work, iwl_mvm_reprobe_wk);
schedule_work(&reprobe->work);
} else if (mvm->fwrt.cur_fw_img == IWL_UCODE_REGULAR &&
- mvm->hw_registered) {
+ mvm->hw_registered &&
+ !test_bit(STATUS_TRANS_DEAD, &mvm->trans->status)) {
/* don't let the transport/FW power down */
iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN);
@@ -1261,7 +1282,8 @@ static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode)
{
struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
- iwl_mvm_dump_nic_error_log(mvm);
+ if (!test_bit(STATUS_TRANS_DEAD, &mvm->trans->status))
+ iwl_mvm_dump_nic_error_log(mvm);
iwl_mvm_nic_restart(mvm, true);
}
@@ -1274,6 +1296,7 @@ static void iwl_mvm_cmd_queue_full(struct iwl_op_mode *op_mode)
iwl_mvm_nic_restart(mvm, true);
}
+#ifdef CONFIG_PM
struct iwl_d0i3_iter_data {
struct iwl_mvm *mvm;
struct ieee80211_vif *connected_vif;
@@ -1596,25 +1619,23 @@ out:
static void iwl_mvm_d0i3_exit_work(struct work_struct *wk)
{
struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm, d0i3_exit_work);
- struct iwl_host_cmd get_status_cmd = {
- .id = WOWLAN_GET_STATUSES,
- .flags = CMD_HIGH_PRIO | CMD_WANT_SKB,
- };
struct iwl_mvm_d0i3_exit_work_iter_data iter_data = {
.mvm = mvm,
};
struct iwl_wowlan_status *status;
- int ret;
u32 wakeup_reasons = 0;
__le16 *qos_seq = NULL;
mutex_lock(&mvm->mutex);
- ret = iwl_mvm_send_cmd(mvm, &get_status_cmd);
- if (ret)
+
+ status = iwl_mvm_send_wowlan_get_status(mvm);
+ if (IS_ERR_OR_NULL(status)) {
+ /* set to NULL so we don't need to check before kfree'ing */
+ status = NULL;
goto out;
+ }
- status = (void *)get_status_cmd.resp_pkt->data;
wakeup_reasons = le32_to_cpu(status->wakeup_reasons);
qos_seq = status->qos_seq_ctr;
@@ -1633,8 +1654,7 @@ out:
wakeup_reasons);
/* qos_seq might point inside resp_pkt, so free it only now */
- if (get_status_cmd.resp_pkt)
- iwl_free_resp(&get_status_cmd);
+ kfree(status);
/* the FW might have updated the regdomain */
iwl_mvm_update_changed_regdom(mvm);
@@ -1685,6 +1705,13 @@ int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode)
return _iwl_mvm_exit_d0i3(mvm);
}
+#define IWL_MVM_D0I3_OPS \
+ .enter_d0i3 = iwl_mvm_enter_d0i3, \
+ .exit_d0i3 = iwl_mvm_exit_d0i3,
+#else /* CONFIG_PM */
+#define IWL_MVM_D0I3_OPS
+#endif /* CONFIG_PM */
+
#define IWL_MVM_COMMON_OPS \
/* these could be differentiated */ \
.async_cb = iwl_mvm_async_cb, \
@@ -1695,8 +1722,7 @@ int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode)
.nic_error = iwl_mvm_nic_error, \
.cmd_queue_full = iwl_mvm_cmd_queue_full, \
.nic_config = iwl_mvm_nic_config, \
- .enter_d0i3 = iwl_mvm_enter_d0i3, \
- .exit_d0i3 = iwl_mvm_exit_d0i3, \
+ IWL_MVM_D0I3_OPS \
/* as we only register one, these MUST be common! */ \
.start = iwl_op_mode_mvm_start, \
.stop = iwl_op_mode_mvm_stop
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/power.c b/drivers/net/wireless/intel/iwlwifi/mvm/power.c
index c11fe2621d51..5a0a28fd762d 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/power.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/power.c
@@ -18,11 +18,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/quota.c b/drivers/net/wireless/intel/iwlwifi/mvm/quota.c
index 690559bdf421..5e62b97af48b 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/quota.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/quota.c
@@ -18,11 +18,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c
index 8169d1450b3b..7a98e1a1dc40 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c
@@ -117,20 +117,42 @@ static u16 rs_fw_set_config_flags(struct iwl_mvm *mvm,
{
struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
+ struct ieee80211_sta_he_cap *he_cap = &sta->he_cap;
bool vht_ena = vht_cap && vht_cap->vht_supported;
u16 flags = 0;
if (mvm->cfg->ht_params->stbc &&
- (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) &&
- ((ht_cap && (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC)) ||
- (vht_ena && (vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK))))
- flags |= IWL_TLC_MNG_CFG_FLAGS_STBC_MSK;
+ (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1)) {
+ if (he_cap && he_cap->has_he) {
+ if (he_cap->he_cap_elem.phy_cap_info[2] &
+ IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ)
+ flags |= IWL_TLC_MNG_CFG_FLAGS_STBC_MSK;
+
+ if (he_cap->he_cap_elem.phy_cap_info[7] &
+ IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ)
+ flags |= IWL_TLC_MNG_CFG_FLAGS_HE_STBC_160MHZ_MSK;
+ } else if ((ht_cap &&
+ (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC)) ||
+ (vht_ena &&
+ (vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK)))
+ flags |= IWL_TLC_MNG_CFG_FLAGS_STBC_MSK;
+ }
if (mvm->cfg->ht_params->ldpc &&
((ht_cap && (ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING)) ||
(vht_ena && (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC))))
flags |= IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK;
+ if (he_cap && he_cap->has_he &&
+ (he_cap->he_cap_elem.phy_cap_info[3] &
+ IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_MASK)) {
+ flags |= IWL_TLC_MNG_CFG_FLAGS_HE_DCM_NSS_1_MSK;
+
+ if (he_cap->he_cap_elem.phy_cap_info[3] &
+ IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_2)
+ flags |= IWL_TLC_MNG_CFG_FLAGS_HE_DCM_NSS_2_MSK;
+ }
+
return flags;
}
@@ -311,7 +333,7 @@ out:
}
void rs_fw_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
- enum nl80211_band band)
+ enum nl80211_band band, bool update)
{
struct ieee80211_hw *hw = mvm->hw;
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
@@ -320,7 +342,8 @@ void rs_fw_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
struct ieee80211_supported_band *sband;
struct iwl_tlc_config_cmd cfg_cmd = {
.sta_id = mvmsta->sta_id,
- .max_ch_width = rs_fw_bw_from_sta_bw(sta),
+ .max_ch_width = update ?
+ rs_fw_bw_from_sta_bw(sta) : RATE_MCS_CHAN_WIDTH_20,
.flags = cpu_to_le16(rs_fw_set_config_flags(mvm, sta)),
.chains = rs_fw_set_active_chains(iwl_mvm_get_valid_tx_ant(mvm)),
.max_mpdu_len = cpu_to_le16(sta->max_amsdu_len),
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
index 30cfd7d50bc9..089972280daa 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
@@ -1239,7 +1239,11 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
!(info->flags & IEEE80211_TX_STAT_AMPDU))
return;
- rs_rate_from_ucode_rate(tx_resp_hwrate, info->band, &tx_resp_rate);
+ if (rs_rate_from_ucode_rate(tx_resp_hwrate, info->band,
+ &tx_resp_rate)) {
+ WARN_ON_ONCE(1);
+ return;
+ }
#ifdef CONFIG_MAC80211_DEBUGFS
/* Disable last tx check if we are debugging with fixed rate but
@@ -1276,7 +1280,7 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
(unsigned long)(lq_sta->last_tx +
(IWL_MVM_RS_IDLE_TIMEOUT * HZ)))) {
IWL_DEBUG_RATE(mvm, "Tx idle for too long. reinit rs\n");
- iwl_mvm_rs_rate_init(mvm, sta, info->band);
+ iwl_mvm_rs_rate_init(mvm, sta, info->band, true);
return;
}
lq_sta->last_tx = jiffies;
@@ -1290,7 +1294,10 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
*/
table = &lq_sta->lq;
lq_hwrate = le32_to_cpu(table->rs_table[0]);
- rs_rate_from_ucode_rate(lq_hwrate, info->band, &lq_rate);
+ if (rs_rate_from_ucode_rate(lq_hwrate, info->band, &lq_rate)) {
+ WARN_ON_ONCE(1);
+ return;
+ }
/* Here we actually compare this rate to the latest LQ command */
if (lq_color != LQ_FLAG_COLOR_GET(table->flags)) {
@@ -1392,8 +1399,12 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
/* Collect data for each rate used during failed TX attempts */
for (i = 0; i <= retries; ++i) {
lq_hwrate = le32_to_cpu(table->rs_table[i]);
- rs_rate_from_ucode_rate(lq_hwrate, info->band,
- &lq_rate);
+ if (rs_rate_from_ucode_rate(lq_hwrate, info->band,
+ &lq_rate)) {
+ WARN_ON_ONCE(1);
+ return;
+ }
+
/*
* Only collect stats if retried rate is in the same RS
* table as active/search.
@@ -2859,9 +2870,8 @@ void rs_update_last_rssi(struct iwl_mvm *mvm,
static void rs_initialize_lq(struct iwl_mvm *mvm,
struct ieee80211_sta *sta,
struct iwl_lq_sta *lq_sta,
- enum nl80211_band band)
+ enum nl80211_band band, bool update)
{
- struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
struct iwl_scale_tbl_info *tbl;
struct rs_rate *rate;
u8 active_tbl = 0;
@@ -2890,8 +2900,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
rs_set_expected_tpt_table(lq_sta, tbl);
rs_fill_lq_cmd(mvm, sta, lq_sta, rate);
/* TODO restore station should remember the lq cmd */
- iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq,
- mvmsta->sta_state < IEEE80211_STA_AUTHORIZED);
+ iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, !update);
}
static void rs_drv_get_rate(void *mvm_r, struct ieee80211_sta *sta,
@@ -3144,7 +3153,7 @@ void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, u32 rate, bool agg)
* Called after adding a new station to initialize rate scaling
*/
static void rs_drv_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
- enum nl80211_band band)
+ enum nl80211_band band, bool update)
{
int i, j;
struct ieee80211_hw *hw = mvm->hw;
@@ -3215,7 +3224,7 @@ static void rs_drv_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
/* These values will be overridden later */
lq_sta->lq.single_stream_ant_msk =
- first_antenna(iwl_mvm_get_valid_tx_ant(mvm));
+ iwl_mvm_bt_coex_get_single_ant_msk(mvm, iwl_mvm_get_valid_tx_ant(mvm));
lq_sta->lq.dual_stream_ant_msk = ANT_AB;
/* as default allow aggregation for all tids */
@@ -3224,7 +3233,7 @@ static void rs_drv_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
#ifdef CONFIG_IWLWIFI_DEBUGFS
iwl_mvm_reset_frame_stats(mvm);
#endif
- rs_initialize_lq(mvm, sta, lq_sta, band);
+ rs_initialize_lq(mvm, sta, lq_sta, band, update);
}
static void rs_drv_rate_update(void *mvm_r,
@@ -3244,7 +3253,7 @@ static void rs_drv_rate_update(void *mvm_r,
for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++)
ieee80211_stop_tx_ba_session(sta, tid);
- iwl_mvm_rs_rate_init(mvm, sta, sband->band);
+ iwl_mvm_rs_rate_init(mvm, sta, sband->band, true);
}
#ifdef CONFIG_MAC80211_DEBUGFS
@@ -3262,7 +3271,10 @@ static void rs_build_rates_table_from_fixed(struct iwl_mvm *mvm,
for (i = 0; i < num_rates; i++)
lq_cmd->rs_table[i] = ucode_rate_le32;
- rs_rate_from_ucode_rate(ucode_rate, band, &rate);
+ if (rs_rate_from_ucode_rate(ucode_rate, band, &rate)) {
+ WARN_ON_ONCE(1);
+ return;
+ }
if (is_mimo(&rate))
lq_cmd->mimo_delim = num_rates - 1;
@@ -3578,7 +3590,8 @@ static void rs_fill_lq_cmd(struct iwl_mvm *mvm,
mvmsta = iwl_mvm_sta_from_mac80211(sta);
mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif);
- if (num_of_ant(initial_rate->ant) == 1)
+ if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_COEX_SCHEMA_2) &&
+ num_of_ant(initial_rate->ant) == 1)
lq_cmd->single_stream_ant_msk = initial_rate->ant;
lq_cmd->agg_frame_cnt_limit = mvmsta->max_agg_bufsize;
@@ -4098,12 +4111,12 @@ static const struct rate_control_ops rs_mvm_ops_drv = {
};
void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
- enum nl80211_band band)
+ enum nl80211_band band, bool update)
{
if (iwl_mvm_has_tlc_offload(mvm))
- rs_fw_rate_init(mvm, sta, band);
+ rs_fw_rate_init(mvm, sta, band, update);
else
- rs_drv_rate_init(mvm, sta, band);
+ rs_drv_rate_init(mvm, sta, band, update);
}
int iwl_mvm_rate_control_register(void)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h
index d2cf484e2b73..d0f47899f284 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h
@@ -420,7 +420,7 @@ struct iwl_lq_sta {
/* Initialize station's rate scaling information after adding station */
void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
- enum nl80211_band band);
+ enum nl80211_band band, bool init);
/* Notify RS about Tx status */
void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
@@ -461,7 +461,7 @@ void rs_remove_sta_debugfs(void *mvm, void *mvm_sta);
void iwl_mvm_rs_add_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta);
void rs_fw_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
- enum nl80211_band band);
+ enum nl80211_band band, bool update);
int rs_fw_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
bool enable);
void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c
index bfb163419c67..ef624833cf1b 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c
@@ -18,11 +18,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
@@ -438,13 +433,14 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi,
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
struct ieee80211_vif *tx_blocked_vif =
rcu_dereference(mvm->csa_tx_blocked_vif);
+ struct iwl_fw_dbg_trigger_tlv *trig;
+ struct ieee80211_vif *vif = mvmsta->vif;
/* We have tx blocked stations (with CS bit). If we heard
* frames from a blocked station on a new channel we can
* TX to it again.
*/
- if (unlikely(tx_blocked_vif) &&
- mvmsta->vif == tx_blocked_vif) {
+ if (unlikely(tx_blocked_vif) && vif == tx_blocked_vif) {
struct iwl_mvm_vif *mvmvif =
iwl_mvm_vif_from_mac80211(tx_blocked_vif);
@@ -455,23 +451,18 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi,
rs_update_last_rssi(mvm, mvmsta, rx_status);
- if (iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_RSSI) &&
- ieee80211_is_beacon(hdr->frame_control)) {
- struct iwl_fw_dbg_trigger_tlv *trig;
+ trig = iwl_fw_dbg_trigger_on(&mvm->fwrt,
+ ieee80211_vif_to_wdev(vif),
+ FW_DBG_TRIGGER_RSSI);
+
+ if (trig && ieee80211_is_beacon(hdr->frame_control)) {
struct iwl_fw_dbg_trigger_low_rssi *rssi_trig;
- bool trig_check;
s32 rssi;
- trig = iwl_fw_dbg_get_trigger(mvm->fw,
- FW_DBG_TRIGGER_RSSI);
rssi_trig = (void *)trig->data;
rssi = le32_to_cpu(rssi_trig->rssi);
- trig_check =
- iwl_fw_dbg_trigger_check_stop(&mvm->fwrt,
- ieee80211_vif_to_wdev(mvmsta->vif),
- trig);
- if (trig_check && rx_status->signal < rssi)
+ if (rx_status->signal < rssi)
iwl_fw_dbg_collect_trig(&mvm->fwrt, trig,
NULL);
}
@@ -698,15 +689,12 @@ iwl_mvm_rx_stats_check_trigger(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt)
struct iwl_fw_dbg_trigger_stats *trig_stats;
u32 trig_offset, trig_thold;
- if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_STATS))
+ trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, NULL, FW_DBG_TRIGGER_STATS);
+ if (!trig)
return;
- trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_STATS);
trig_stats = (void *)trig->data;
- if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, NULL, trig))
- return;
-
trig_offset = le32_to_cpu(trig_stats->stop_offset);
trig_thold = le32_to_cpu(trig_stats->stop_threshold);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
index b53148f972a4..26ac9402568d 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
@@ -283,6 +283,10 @@ static int iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,
!(status & IWL_RX_MPDU_RES_STATUS_TTAK_OK))
return 0;
+ if (mvm->trans->cfg->gen2 &&
+ !(status & RX_MPDU_RES_STATUS_MIC_OK))
+ stats->flag |= RX_FLAG_MMIC_ERROR;
+
*crypt_len = IEEE80211_TKIP_IV_LEN;
/* fall through if TTAK OK */
case IWL_RX_MPDU_STATUS_SEC_WEP:
@@ -294,8 +298,11 @@ static int iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,
IWL_RX_MPDU_STATUS_SEC_WEP)
*crypt_len = IEEE80211_WEP_IV_LEN;
- if (pkt_flags & FH_RSCSR_RADA_EN)
+ if (pkt_flags & FH_RSCSR_RADA_EN) {
stats->flag |= RX_FLAG_ICV_STRIPPED;
+ if (mvm->trans->cfg->gen2)
+ stats->flag |= RX_FLAG_MMIC_STRIPPED;
+ }
return 0;
case IWL_RX_MPDU_STATUS_SEC_EXT_ENC:
@@ -856,6 +863,444 @@ static void iwl_mvm_flip_address(u8 *addr)
ether_addr_copy(addr, mac_addr);
}
+static void iwl_mvm_decode_he_sigb(struct iwl_mvm *mvm,
+ struct iwl_rx_mpdu_desc *desc,
+ u32 rate_n_flags,
+ struct ieee80211_radiotap_he_mu *he_mu)
+{
+ u32 sigb0, sigb1;
+ u16 sigb2;
+
+ if (mvm->trans->cfg->device_family >= IWL_DEVICE_FAMILY_22560) {
+ sigb0 = le32_to_cpu(desc->v3.sigb_common0);
+ sigb1 = le32_to_cpu(desc->v3.sigb_common1);
+ } else {
+ sigb0 = le32_to_cpu(desc->v1.sigb_common0);
+ sigb1 = le32_to_cpu(desc->v1.sigb_common1);
+ }
+
+ sigb2 = le16_to_cpu(desc->sigb_common2);
+
+ if (FIELD_GET(IWL_RX_HE_SIGB_COMMON2_CH1_CRC_OK, sigb2)) {
+ he_mu->flags1 |=
+ cpu_to_le16(IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH1_RU_KNOWN |
+ IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH1_CTR_26T_RU_KNOWN);
+
+ he_mu->flags1 |=
+ le16_encode_bits(FIELD_GET(IWL_RX_HE_SIGB_COMMON2_CH1_CTR_RU,
+ sigb2),
+ IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH1_CTR_26T_RU);
+
+ he_mu->ru_ch1[0] = FIELD_GET(IWL_RX_HE_SIGB_COMMON0_CH1_RU0,
+ sigb0);
+ he_mu->ru_ch1[1] = FIELD_GET(IWL_RX_HE_SIGB_COMMON1_CH1_RU1,
+ sigb1);
+ he_mu->ru_ch1[2] = FIELD_GET(IWL_RX_HE_SIGB_COMMON0_CH1_RU2,
+ sigb0);
+ he_mu->ru_ch1[3] = FIELD_GET(IWL_RX_HE_SIGB_COMMON1_CH1_RU3,
+ sigb1);
+ }
+
+ if (FIELD_GET(IWL_RX_HE_SIGB_COMMON2_CH2_CRC_OK, sigb2) &&
+ (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) != RATE_MCS_CHAN_WIDTH_20) {
+ he_mu->flags1 |=
+ cpu_to_le16(IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH2_RU_KNOWN |
+ IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH2_CTR_26T_RU_KNOWN);
+
+ he_mu->flags2 |=
+ le16_encode_bits(FIELD_GET(IWL_RX_HE_SIGB_COMMON2_CH2_CTR_RU,
+ sigb2),
+ IEEE80211_RADIOTAP_HE_MU_FLAGS2_CH2_CTR_26T_RU);
+
+ he_mu->ru_ch2[0] = FIELD_GET(IWL_RX_HE_SIGB_COMMON0_CH2_RU0,
+ sigb0);
+ he_mu->ru_ch2[1] = FIELD_GET(IWL_RX_HE_SIGB_COMMON1_CH2_RU1,
+ sigb1);
+ he_mu->ru_ch2[2] = FIELD_GET(IWL_RX_HE_SIGB_COMMON0_CH2_RU2,
+ sigb0);
+ he_mu->ru_ch2[3] = FIELD_GET(IWL_RX_HE_SIGB_COMMON1_CH2_RU3,
+ sigb1);
+ }
+}
+
+static void
+iwl_mvm_decode_he_phy_ru_alloc(u64 he_phy_data, u32 rate_n_flags,
+ struct ieee80211_radiotap_he *he,
+ struct ieee80211_radiotap_he_mu *he_mu,
+ struct ieee80211_rx_status *rx_status)
+{
+ /*
+ * Unfortunately, we have to leave the mac80211 data
+ * incorrect for the case that we receive an HE-MU
+ * transmission and *don't* have the HE phy data (due
+ * to the bits being used for TSF). This shouldn't
+ * happen though as management frames where we need
+ * the TSF/timers are not be transmitted in HE-MU.
+ */
+ u8 ru = FIELD_GET(IWL_RX_HE_PHY_RU_ALLOC_MASK, he_phy_data);
+ u8 offs = 0;
+
+ rx_status->bw = RATE_INFO_BW_HE_RU;
+
+ he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN);
+
+ switch (ru) {
+ case 0 ... 36:
+ rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26;
+ offs = ru;
+ break;
+ case 37 ... 52:
+ rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_52;
+ offs = ru - 37;
+ break;
+ case 53 ... 60:
+ rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106;
+ offs = ru - 53;
+ break;
+ case 61 ... 64:
+ rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_242;
+ offs = ru - 61;
+ break;
+ case 65 ... 66:
+ rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_484;
+ offs = ru - 65;
+ break;
+ case 67:
+ rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_996;
+ break;
+ case 68:
+ rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996;
+ break;
+ }
+ he->data2 |= le16_encode_bits(offs,
+ IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET);
+ he->data2 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_KNOWN |
+ IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET_KNOWN);
+ if (he_phy_data & IWL_RX_HE_PHY_RU_ALLOC_SEC80)
+ he->data2 |=
+ cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_SEC);
+
+ if (he_mu) {
+#define CHECK_BW(bw) \
+ BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_ ## bw ## MHZ != \
+ RATE_MCS_CHAN_WIDTH_##bw >> RATE_MCS_CHAN_WIDTH_POS)
+ CHECK_BW(20);
+ CHECK_BW(40);
+ CHECK_BW(80);
+ CHECK_BW(160);
+ he_mu->flags2 |=
+ le16_encode_bits(FIELD_GET(RATE_MCS_CHAN_WIDTH_MSK,
+ rate_n_flags),
+ IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW);
+ }
+}
+
+static void iwl_mvm_decode_he_phy_data(struct iwl_mvm *mvm,
+ struct iwl_rx_mpdu_desc *desc,
+ struct ieee80211_radiotap_he *he,
+ struct ieee80211_radiotap_he_mu *he_mu,
+ struct ieee80211_rx_status *rx_status,
+ u64 he_phy_data, u32 rate_n_flags,
+ int queue)
+{
+ u32 he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK;
+ bool sigb_data;
+ u16 d1known = IEEE80211_RADIOTAP_HE_DATA1_LDPC_XSYMSEG_KNOWN |
+ IEEE80211_RADIOTAP_HE_DATA1_UL_DL_KNOWN |
+ IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE_KNOWN |
+ IEEE80211_RADIOTAP_HE_DATA1_DOPPLER_KNOWN |
+ IEEE80211_RADIOTAP_HE_DATA1_BSS_COLOR_KNOWN;
+ u16 d2known = IEEE80211_RADIOTAP_HE_DATA2_PRE_FEC_PAD_KNOWN |
+ IEEE80211_RADIOTAP_HE_DATA2_PE_DISAMBIG_KNOWN |
+ IEEE80211_RADIOTAP_HE_DATA2_TXOP_KNOWN;
+
+ he->data1 |= cpu_to_le16(d1known);
+ he->data2 |= cpu_to_le16(d2known);
+ he->data3 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_BSS_COLOR_MASK,
+ he_phy_data),
+ IEEE80211_RADIOTAP_HE_DATA3_BSS_COLOR);
+ he->data3 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_UPLINK,
+ he_phy_data),
+ IEEE80211_RADIOTAP_HE_DATA3_UL_DL);
+ he->data3 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_LDPC_EXT_SYM,
+ he_phy_data),
+ IEEE80211_RADIOTAP_HE_DATA3_LDPC_XSYMSEG);
+ he->data4 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_SPATIAL_REUSE_MASK,
+ he_phy_data),
+ IEEE80211_RADIOTAP_HE_DATA4_SU_MU_SPTL_REUSE);
+ he->data5 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_PRE_FEC_PAD_MASK,
+ he_phy_data),
+ IEEE80211_RADIOTAP_HE_DATA5_PRE_FEC_PAD);
+ he->data5 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_PE_DISAMBIG,
+ he_phy_data),
+ IEEE80211_RADIOTAP_HE_DATA5_PE_DISAMBIG);
+ he->data6 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_TXOP_DUR_MASK,
+ he_phy_data),
+ IEEE80211_RADIOTAP_HE_DATA6_TXOP);
+ he->data6 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_DOPPLER,
+ he_phy_data),
+ IEEE80211_RADIOTAP_HE_DATA6_DOPPLER);
+
+ switch (he_type) {
+ case RATE_MCS_HE_TYPE_MU:
+ he_mu->flags1 |=
+ le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_SIGB_DCM,
+ he_phy_data),
+ IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_DCM);
+ he_mu->flags1 |=
+ le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_SIGB_MCS_MASK,
+ he_phy_data),
+ IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_MCS);
+ he_mu->flags2 |=
+ le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_SIBG_SYM_OR_USER_NUM_MASK,
+ he_phy_data),
+ IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_SYMS_USERS);
+ he_mu->flags2 |=
+ le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_SIGB_COMPRESSION,
+ he_phy_data),
+ IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_COMP);
+ he_mu->flags2 |=
+ le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_PREAMBLE_PUNC_TYPE_MASK,
+ he_phy_data),
+ IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW);
+
+ sigb_data = FIELD_GET(IWL_RX_HE_PHY_INFO_TYPE_MASK,
+ he_phy_data) ==
+ IWL_RX_HE_PHY_INFO_TYPE_MU_EXT_INFO;
+ if (sigb_data)
+ iwl_mvm_decode_he_sigb(mvm, desc, rate_n_flags, he_mu);
+ /* fall through */
+ case RATE_MCS_HE_TYPE_TRIG:
+ he->data2 |=
+ cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_NUM_LTF_SYMS_KNOWN);
+ he->data5 |=
+ le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_HE_LTF_NUM_MASK,
+ he_phy_data),
+ IEEE80211_RADIOTAP_HE_DATA5_NUM_LTF_SYMS);
+ break;
+ case RATE_MCS_HE_TYPE_SU:
+ case RATE_MCS_HE_TYPE_EXT_SU:
+ he->data1 |=
+ cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BEAM_CHANGE_KNOWN);
+ he->data3 |=
+ le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_BEAM_CHNG,
+ he_phy_data),
+ IEEE80211_RADIOTAP_HE_DATA3_BEAM_CHANGE);
+ break;
+ }
+
+ switch (FIELD_GET(IWL_RX_HE_PHY_INFO_TYPE_MASK, he_phy_data)) {
+ case IWL_RX_HE_PHY_INFO_TYPE_MU:
+ case IWL_RX_HE_PHY_INFO_TYPE_MU_EXT_INFO:
+ case IWL_RX_HE_PHY_INFO_TYPE_TB:
+ iwl_mvm_decode_he_phy_ru_alloc(he_phy_data, rate_n_flags,
+ he, he_mu, rx_status);
+ break;
+ default:
+ /* nothing */
+ break;
+ }
+}
+
+static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb,
+ struct iwl_rx_mpdu_desc *desc,
+ u32 rate_n_flags, u16 phy_info, int queue)
+{
+ struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
+ /* this is invalid e.g. because puncture type doesn't allow 0b11 */
+#define HE_PHY_DATA_INVAL ((u64)-1)
+ u64 he_phy_data = HE_PHY_DATA_INVAL;
+ struct ieee80211_radiotap_he *he = NULL;
+ struct ieee80211_radiotap_he_mu *he_mu = NULL;
+ u32 he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK;
+ u8 stbc, ltf;
+ static const struct ieee80211_radiotap_he known = {
+ .data1 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_DATA_MCS_KNOWN |
+ IEEE80211_RADIOTAP_HE_DATA1_DATA_DCM_KNOWN |
+ IEEE80211_RADIOTAP_HE_DATA1_STBC_KNOWN |
+ IEEE80211_RADIOTAP_HE_DATA1_CODING_KNOWN),
+ .data2 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_GI_KNOWN |
+ IEEE80211_RADIOTAP_HE_DATA2_TXBF_KNOWN),
+ };
+ static const struct ieee80211_radiotap_he_mu mu_known = {
+ .flags1 = cpu_to_le16(IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_MCS_KNOWN |
+ IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_DCM_KNOWN |
+ IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_SYMS_USERS_KNOWN |
+ IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_COMP_KNOWN),
+ .flags2 = cpu_to_le16(IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW_KNOWN |
+ IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN),
+ };
+ unsigned int radiotap_len = 0;
+
+ he = skb_put_data(skb, &known, sizeof(known));
+ radiotap_len += sizeof(known);
+ rx_status->flag |= RX_FLAG_RADIOTAP_HE;
+
+ if (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD) {
+ if (mvm->trans->cfg->device_family >= IWL_DEVICE_FAMILY_22560)
+ he_phy_data = le64_to_cpu(desc->v3.he_phy_data);
+ else
+ he_phy_data = le64_to_cpu(desc->v1.he_phy_data);
+
+ if (he_type == RATE_MCS_HE_TYPE_MU) {
+ he_mu = skb_put_data(skb, &mu_known, sizeof(mu_known));
+ radiotap_len += sizeof(mu_known);
+ rx_status->flag |= RX_FLAG_RADIOTAP_HE_MU;
+ }
+ }
+
+ /* temporarily hide the radiotap data */
+ __skb_pull(skb, radiotap_len);
+
+ if (he_phy_data != HE_PHY_DATA_INVAL &&
+ he_type == RATE_MCS_HE_TYPE_SU) {
+ /* report the AMPDU-EOF bit on single frames */
+ if (!queue && !(phy_info & IWL_RX_MPDU_PHY_AMPDU)) {
+ rx_status->flag |= RX_FLAG_AMPDU_DETAILS;
+ rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN;
+ if (FIELD_GET(IWL_RX_HE_PHY_DELIM_EOF, he_phy_data))
+ rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT;
+ }
+ }
+
+ if (he_phy_data != HE_PHY_DATA_INVAL)
+ iwl_mvm_decode_he_phy_data(mvm, desc, he, he_mu, rx_status,
+ he_phy_data, rate_n_flags, queue);
+
+ /* update aggregation data for monitor sake on default queue */
+ if (!queue && (phy_info & IWL_RX_MPDU_PHY_AMPDU)) {
+ bool toggle_bit = phy_info & IWL_RX_MPDU_PHY_AMPDU_TOGGLE;
+
+ /* toggle is switched whenever new aggregation starts */
+ if (toggle_bit != mvm->ampdu_toggle &&
+ he_phy_data != HE_PHY_DATA_INVAL &&
+ (he_type == RATE_MCS_HE_TYPE_MU ||
+ he_type == RATE_MCS_HE_TYPE_SU)) {
+ rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN;
+ if (FIELD_GET(IWL_RX_HE_PHY_DELIM_EOF,
+ he_phy_data))
+ rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT;
+ }
+ }
+
+ if (he_type == RATE_MCS_HE_TYPE_EXT_SU &&
+ rate_n_flags & RATE_MCS_HE_106T_MSK) {
+ rx_status->bw = RATE_INFO_BW_HE_RU;
+ rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106;
+ }
+
+ /* actually data is filled in mac80211 */
+ if (he_type == RATE_MCS_HE_TYPE_SU ||
+ he_type == RATE_MCS_HE_TYPE_EXT_SU)
+ he->data1 |=
+ cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN);
+
+ stbc = (rate_n_flags & RATE_MCS_STBC_MSK) >> RATE_MCS_STBC_POS;
+ rx_status->nss =
+ ((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >>
+ RATE_VHT_MCS_NSS_POS) + 1;
+ rx_status->rate_idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK;
+ rx_status->encoding = RX_ENC_HE;
+ rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT;
+ if (rate_n_flags & RATE_MCS_BF_MSK)
+ rx_status->enc_flags |= RX_ENC_FLAG_BF;
+
+ rx_status->he_dcm =
+ !!(rate_n_flags & RATE_HE_DUAL_CARRIER_MODE_MSK);
+
+#define CHECK_TYPE(F) \
+ BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA1_FORMAT_ ## F != \
+ (RATE_MCS_HE_TYPE_ ## F >> RATE_MCS_HE_TYPE_POS))
+
+ CHECK_TYPE(SU);
+ CHECK_TYPE(EXT_SU);
+ CHECK_TYPE(MU);
+ CHECK_TYPE(TRIG);
+
+ he->data1 |= cpu_to_le16(he_type >> RATE_MCS_HE_TYPE_POS);
+
+ if (rate_n_flags & RATE_MCS_BF_MSK)
+ he->data5 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA5_TXBF);
+
+ switch ((rate_n_flags & RATE_MCS_HE_GI_LTF_MSK) >>
+ RATE_MCS_HE_GI_LTF_POS) {
+ case 0:
+ if (he_type == RATE_MCS_HE_TYPE_TRIG)
+ rx_status->he_gi = NL80211_RATE_INFO_HE_GI_1_6;
+ else
+ rx_status->he_gi = NL80211_RATE_INFO_HE_GI_0_8;
+ if (he_type == RATE_MCS_HE_TYPE_MU)
+ ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_4X;
+ else
+ ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_1X;
+ break;
+ case 1:
+ if (he_type == RATE_MCS_HE_TYPE_TRIG)
+ rx_status->he_gi = NL80211_RATE_INFO_HE_GI_1_6;
+ else
+ rx_status->he_gi = NL80211_RATE_INFO_HE_GI_0_8;
+ ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_2X;
+ break;
+ case 2:
+ if (he_type == RATE_MCS_HE_TYPE_TRIG) {
+ rx_status->he_gi = NL80211_RATE_INFO_HE_GI_3_2;
+ ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_4X;
+ } else {
+ rx_status->he_gi = NL80211_RATE_INFO_HE_GI_1_6;
+ ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_2X;
+ }
+ break;
+ case 3:
+ if ((he_type == RATE_MCS_HE_TYPE_SU ||
+ he_type == RATE_MCS_HE_TYPE_EXT_SU) &&
+ rate_n_flags & RATE_MCS_SGI_MSK)
+ rx_status->he_gi = NL80211_RATE_INFO_HE_GI_0_8;
+ else
+ rx_status->he_gi = NL80211_RATE_INFO_HE_GI_3_2;
+ ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_4X;
+ break;
+ }
+
+ he->data5 |= le16_encode_bits(ltf, IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE);
+
+ if (he_type == RATE_MCS_HE_TYPE_SU ||
+ he_type == RATE_MCS_HE_TYPE_EXT_SU) {
+ u16 val;
+
+ /* LTF syms correspond to streams */
+ he->data2 |=
+ cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_NUM_LTF_SYMS_KNOWN);
+ switch (rx_status->nss) {
+ case 1:
+ val = 0;
+ break;
+ case 2:
+ val = 1;
+ break;
+ case 3:
+ case 4:
+ val = 2;
+ break;
+ case 5:
+ case 6:
+ val = 3;
+ break;
+ case 7:
+ case 8:
+ val = 4;
+ break;
+ default:
+ WARN_ONCE(1, "invalid nss: %d\n",
+ rx_status->nss);
+ val = 0;
+ }
+
+ he->data5 |=
+ le16_encode_bits(val,
+ IEEE80211_RADIOTAP_HE_DATA5_NUM_LTF_SYMS);
+ }
+}
+
void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
struct iwl_rx_cmd_buffer *rxb, int queue)
{
@@ -869,12 +1314,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
struct ieee80211_sta *sta = NULL;
struct sk_buff *skb;
u8 crypt_len = 0, channel, energy_a, energy_b;
- struct ieee80211_radiotap_he *he = NULL;
- struct ieee80211_radiotap_he_mu *he_mu = NULL;
- u32 he_type = 0xffffffff;
- /* this is invalid e.g. because puncture type doesn't allow 0b11 */
-#define HE_PHY_DATA_INVAL ((u64)-1)
- u64 he_phy_data = HE_PHY_DATA_INVAL;
size_t desc_size;
if (unlikely(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)))
@@ -918,49 +1357,24 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
rx_status = IEEE80211_SKB_RXCB(skb);
- if (rate_n_flags & RATE_MCS_HE_MSK) {
- static const struct ieee80211_radiotap_he known = {
- .data1 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_DATA_MCS_KNOWN |
- IEEE80211_RADIOTAP_HE_DATA1_DATA_DCM_KNOWN |
- IEEE80211_RADIOTAP_HE_DATA1_STBC_KNOWN |
- IEEE80211_RADIOTAP_HE_DATA1_CODING_KNOWN),
- .data2 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_GI_KNOWN |
- IEEE80211_RADIOTAP_HE_DATA2_TXBF_KNOWN),
- };
- static const struct ieee80211_radiotap_he_mu mu_known = {
- .flags1 = cpu_to_le16(IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_MCS_KNOWN |
- IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_DCM_KNOWN |
- IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_SYMS_USERS_KNOWN |
- IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_COMP_KNOWN),
- .flags2 = cpu_to_le16(IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW_KNOWN),
- };
- unsigned int radiotap_len = 0;
-
- he = skb_put_data(skb, &known, sizeof(known));
- radiotap_len += sizeof(known);
- rx_status->flag |= RX_FLAG_RADIOTAP_HE;
-
- he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK;
-
- if (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD) {
- if (mvm->trans->cfg->device_family >=
- IWL_DEVICE_FAMILY_22560)
- he_phy_data = le64_to_cpu(desc->v3.he_phy_data);
- else
- he_phy_data = le64_to_cpu(desc->v1.he_phy_data);
-
- if (he_type == RATE_MCS_HE_TYPE_MU) {
- he_mu = skb_put_data(skb, &mu_known,
- sizeof(mu_known));
- radiotap_len += sizeof(mu_known);
- rx_status->flag |= RX_FLAG_RADIOTAP_HE_MU;
- }
- }
-
- /* temporarily hide the radiotap data */
- __skb_pull(skb, radiotap_len);
+ /* This may be overridden by iwl_mvm_rx_he() to HE_RU */
+ switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) {
+ case RATE_MCS_CHAN_WIDTH_20:
+ break;
+ case RATE_MCS_CHAN_WIDTH_40:
+ rx_status->bw = RATE_INFO_BW_40;
+ break;
+ case RATE_MCS_CHAN_WIDTH_80:
+ rx_status->bw = RATE_INFO_BW_80;
+ break;
+ case RATE_MCS_CHAN_WIDTH_160:
+ rx_status->bw = RATE_INFO_BW_160;
+ break;
}
+ if (rate_n_flags & RATE_MCS_HE_MSK)
+ iwl_mvm_rx_he(mvm, skb, desc, rate_n_flags, phy_info, queue);
+
rx_status = IEEE80211_SKB_RXCB(skb);
if (iwl_mvm_rx_crypto(mvm, hdr, rx_status, phy_info, desc,
@@ -995,53 +1409,8 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
rx_status->mactime = tsf_on_air_rise;
/* TSF as indicated by the firmware is at INA time */
rx_status->flag |= RX_FLAG_MACTIME_PLCP_START;
- } else if (he_type == RATE_MCS_HE_TYPE_SU) {
- u64 he_phy_data;
-
- if (mvm->trans->cfg->device_family >= IWL_DEVICE_FAMILY_22560)
- he_phy_data = le64_to_cpu(desc->v3.he_phy_data);
- else
- he_phy_data = le64_to_cpu(desc->v1.he_phy_data);
-
- he->data1 |=
- cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_UL_DL_KNOWN);
- if (FIELD_GET(IWL_RX_HE_PHY_UPLINK,
- he_phy_data))
- he->data3 |=
- cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA3_UL_DL);
-
- if (!queue && !(phy_info & IWL_RX_MPDU_PHY_AMPDU)) {
- rx_status->ampdu_reference = mvm->ampdu_ref;
- mvm->ampdu_ref++;
-
- rx_status->flag |= RX_FLAG_AMPDU_DETAILS;
- rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN;
- if (FIELD_GET(IWL_RX_HE_PHY_DELIM_EOF,
- he_phy_data))
- rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT;
- }
- } else if (he_mu && he_phy_data != HE_PHY_DATA_INVAL) {
- he_mu->flags1 |=
- le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_SIBG_SYM_OR_USER_NUM_MASK,
- he_phy_data),
- IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_SYMS_USERS);
- he_mu->flags1 |=
- le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_SIGB_DCM,
- he_phy_data),
- IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_DCM);
- he_mu->flags1 |=
- le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_SIGB_MCS_MASK,
- he_phy_data),
- IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_MCS);
- he_mu->flags2 |=
- le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_SIGB_COMPRESSION,
- he_phy_data),
- IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_COMP);
- he_mu->flags2 |=
- le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_PREAMBLE_PUNC_TYPE_MASK,
- he_phy_data),
- IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW);
}
+
rx_status->device_timestamp = gp2_on_air_rise;
rx_status->band = channel > 14 ? NL80211_BAND_5GHZ :
NL80211_BAND_2GHZ;
@@ -1066,15 +1435,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
if (toggle_bit != mvm->ampdu_toggle) {
mvm->ampdu_ref++;
mvm->ampdu_toggle = toggle_bit;
-
- if (he_phy_data != HE_PHY_DATA_INVAL &&
- he_type == RATE_MCS_HE_TYPE_MU) {
- rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN;
- if (FIELD_GET(IWL_RX_HE_PHY_DELIM_EOF,
- he_phy_data))
- rx_status->flag |=
- RX_FLAG_AMPDU_EOF_BIT;
- }
}
}
@@ -1103,6 +1463,8 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
u8 baid = (u8)((le32_to_cpu(desc->reorder_data) &
IWL_RX_MPDU_REORDER_BAID_MASK) >>
IWL_RX_MPDU_REORDER_BAID_SHIFT);
+ struct iwl_fw_dbg_trigger_tlv *trig;
+ struct ieee80211_vif *vif = mvmsta->vif;
if (!mvm->tcm.paused && len >= sizeof(*hdr) &&
!is_multicast_ether_addr(hdr->addr1) &&
@@ -1115,8 +1477,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
* frames from a blocked station on a new channel we can
* TX to it again.
*/
- if (unlikely(tx_blocked_vif) &&
- tx_blocked_vif == mvmsta->vif) {
+ if (unlikely(tx_blocked_vif) && tx_blocked_vif == vif) {
struct iwl_mvm_vif *mvmvif =
iwl_mvm_vif_from_mac80211(tx_blocked_vif);
@@ -1127,23 +1488,18 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
rs_update_last_rssi(mvm, mvmsta, rx_status);
- if (iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_RSSI) &&
- ieee80211_is_beacon(hdr->frame_control)) {
- struct iwl_fw_dbg_trigger_tlv *trig;
+ trig = iwl_fw_dbg_trigger_on(&mvm->fwrt,
+ ieee80211_vif_to_wdev(vif),
+ FW_DBG_TRIGGER_RSSI);
+
+ if (trig && ieee80211_is_beacon(hdr->frame_control)) {
struct iwl_fw_dbg_trigger_low_rssi *rssi_trig;
- bool trig_check;
s32 rssi;
- trig = iwl_fw_dbg_get_trigger(mvm->fw,
- FW_DBG_TRIGGER_RSSI);
rssi_trig = (void *)trig->data;
rssi = le32_to_cpu(rssi_trig->rssi);
- trig_check =
- iwl_fw_dbg_trigger_check_stop(&mvm->fwrt,
- ieee80211_vif_to_wdev(mvmsta->vif),
- trig);
- if (trig_check && rx_status->signal < rssi)
+ if (rx_status->signal < rssi)
iwl_fw_dbg_collect_trig(&mvm->fwrt, trig,
NULL);
}
@@ -1183,84 +1539,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
}
}
- switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) {
- case RATE_MCS_CHAN_WIDTH_20:
- break;
- case RATE_MCS_CHAN_WIDTH_40:
- rx_status->bw = RATE_INFO_BW_40;
- break;
- case RATE_MCS_CHAN_WIDTH_80:
- rx_status->bw = RATE_INFO_BW_80;
- break;
- case RATE_MCS_CHAN_WIDTH_160:
- rx_status->bw = RATE_INFO_BW_160;
- break;
- }
-
- if (he_type == RATE_MCS_HE_TYPE_EXT_SU &&
- rate_n_flags & RATE_MCS_HE_106T_MSK) {
- rx_status->bw = RATE_INFO_BW_HE_RU;
- rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106;
- }
-
- if (rate_n_flags & RATE_MCS_HE_MSK &&
- phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD &&
- he_type == RATE_MCS_HE_TYPE_MU) {
- /*
- * Unfortunately, we have to leave the mac80211 data
- * incorrect for the case that we receive an HE-MU
- * transmission and *don't* have the he_mu pointer,
- * i.e. we don't have the phy data (due to the bits
- * being used for TSF). This shouldn't happen though
- * as management frames where we need the TSF/timers
- * are not be transmitted in HE-MU, I think.
- */
- u8 ru = FIELD_GET(IWL_RX_HE_PHY_RU_ALLOC_MASK, he_phy_data);
- u8 offs = 0;
-
- rx_status->bw = RATE_INFO_BW_HE_RU;
-
- switch (ru) {
- case 0 ... 36:
- rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26;
- offs = ru;
- break;
- case 37 ... 52:
- rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_52;
- offs = ru - 37;
- break;
- case 53 ... 60:
- rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106;
- offs = ru - 53;
- break;
- case 61 ... 64:
- rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_242;
- offs = ru - 61;
- break;
- case 65 ... 66:
- rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_484;
- offs = ru - 65;
- break;
- case 67:
- rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_996;
- break;
- case 68:
- rx_status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996;
- break;
- }
- he->data2 |=
- le16_encode_bits(offs,
- IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET);
- he->data2 |=
- cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_KNOWN);
- if (he_phy_data & IWL_RX_HE_PHY_RU_ALLOC_SEC80)
- he->data2 |=
- cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_SEC);
- } else if (he) {
- he->data1 |=
- cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN);
- }
-
if (!(rate_n_flags & RATE_MCS_CCK_MSK) &&
rate_n_flags & RATE_MCS_SGI_MSK)
rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
@@ -1285,120 +1563,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT;
if (rate_n_flags & RATE_MCS_BF_MSK)
rx_status->enc_flags |= RX_ENC_FLAG_BF;
- } else if (he) {
- u8 stbc = (rate_n_flags & RATE_MCS_STBC_MSK) >>
- RATE_MCS_STBC_POS;
- rx_status->nss =
- ((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >>
- RATE_VHT_MCS_NSS_POS) + 1;
- rx_status->rate_idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK;
- rx_status->encoding = RX_ENC_HE;
- rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT;
- if (rate_n_flags & RATE_MCS_BF_MSK)
- rx_status->enc_flags |= RX_ENC_FLAG_BF;
-
- rx_status->he_dcm =
- !!(rate_n_flags & RATE_HE_DUAL_CARRIER_MODE_MSK);
-
-#define CHECK_TYPE(F) \
- BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA1_FORMAT_ ## F != \
- (RATE_MCS_HE_TYPE_ ## F >> RATE_MCS_HE_TYPE_POS))
-
- CHECK_TYPE(SU);
- CHECK_TYPE(EXT_SU);
- CHECK_TYPE(MU);
- CHECK_TYPE(TRIG);
-
- he->data1 |= cpu_to_le16(he_type >> RATE_MCS_HE_TYPE_POS);
-
- if (rate_n_flags & RATE_MCS_BF_POS)
- he->data5 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA5_TXBF);
-
- switch ((rate_n_flags & RATE_MCS_HE_GI_LTF_MSK) >>
- RATE_MCS_HE_GI_LTF_POS) {
- case 0:
- rx_status->he_gi = NL80211_RATE_INFO_HE_GI_0_8;
- break;
- case 1:
- rx_status->he_gi = NL80211_RATE_INFO_HE_GI_0_8;
- break;
- case 2:
- rx_status->he_gi = NL80211_RATE_INFO_HE_GI_1_6;
- break;
- case 3:
- if (rate_n_flags & RATE_MCS_SGI_MSK)
- rx_status->he_gi = NL80211_RATE_INFO_HE_GI_0_8;
- else
- rx_status->he_gi = NL80211_RATE_INFO_HE_GI_3_2;
- break;
- }
-
- switch (he_type) {
- case RATE_MCS_HE_TYPE_SU: {
- u16 val;
-
- /* LTF syms correspond to streams */
- he->data2 |=
- cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_NUM_LTF_SYMS_KNOWN);
- switch (rx_status->nss) {
- case 1:
- val = 0;
- break;
- case 2:
- val = 1;
- break;
- case 3:
- case 4:
- val = 2;
- break;
- case 5:
- case 6:
- val = 3;
- break;
- case 7:
- case 8:
- val = 4;
- break;
- default:
- WARN_ONCE(1, "invalid nss: %d\n",
- rx_status->nss);
- val = 0;
- }
- he->data5 |=
- le16_encode_bits(val,
- IEEE80211_RADIOTAP_HE_DATA5_NUM_LTF_SYMS);
- }
- break;
- case RATE_MCS_HE_TYPE_MU: {
- u16 val;
- u64 he_phy_data;
-
- if (mvm->trans->cfg->device_family >=
- IWL_DEVICE_FAMILY_22560)
- he_phy_data = le64_to_cpu(desc->v3.he_phy_data);
- else
- he_phy_data = le64_to_cpu(desc->v1.he_phy_data);
-
- if (he_phy_data == HE_PHY_DATA_INVAL)
- break;
-
- val = FIELD_GET(IWL_RX_HE_PHY_HE_LTF_NUM_MASK,
- he_phy_data);
-
- he->data2 |=
- cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_NUM_LTF_SYMS_KNOWN);
- he->data5 |=
- cpu_to_le16(FIELD_PREP(
- IEEE80211_RADIOTAP_HE_DATA5_NUM_LTF_SYMS,
- val));
- }
- break;
- case RATE_MCS_HE_TYPE_EXT_SU:
- case RATE_MCS_HE_TYPE_TRIG:
- /* not supported yet */
- break;
- }
- } else {
+ } else if (!(rate_n_flags & RATE_MCS_HE_MSK)) {
int rate = iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags,
rx_status->band);
@@ -1409,7 +1574,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
goto out;
}
rx_status->rate_idx = rate;
-
}
/* management stuff on default queue */
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
index 11ecdf63b732..cfb784fea77b 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
@@ -19,9 +19,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
@@ -113,6 +110,10 @@ static struct iwl_mvm_scan_timing_params scan_timing[] = {
.suspend_time = 95,
.max_out_time = 44,
},
+ [IWL_SCAN_TYPE_FAST_BALANCE] = {
+ .suspend_time = 30,
+ .max_out_time = 37,
+ },
};
struct iwl_mvm_scan_params {
@@ -238,8 +239,32 @@ iwl_mvm_get_traffic_load_band(struct iwl_mvm *mvm, enum nl80211_band band)
return mvm->tcm.result.band_load[band];
}
+struct iwl_is_dcm_with_go_iterator_data {
+ struct ieee80211_vif *current_vif;
+ bool is_dcm_with_p2p_go;
+};
+
+static void iwl_mvm_is_dcm_with_go_iterator(void *_data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_is_dcm_with_go_iterator_data *data = _data;
+ struct iwl_mvm_vif *other_mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_mvm_vif *curr_mvmvif =
+ iwl_mvm_vif_from_mac80211(data->current_vif);
+
+ /* exclude the given vif */
+ if (vif == data->current_vif)
+ return;
+
+ if (vif->type == NL80211_IFTYPE_AP && vif->p2p &&
+ other_mvmvif->phy_ctxt && curr_mvmvif->phy_ctxt &&
+ other_mvmvif->phy_ctxt->id != curr_mvmvif->phy_ctxt->id)
+ data->is_dcm_with_p2p_go = true;
+}
+
static enum
-iwl_mvm_scan_type _iwl_mvm_get_scan_type(struct iwl_mvm *mvm, bool p2p_device,
+iwl_mvm_scan_type _iwl_mvm_get_scan_type(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
enum iwl_mvm_traffic_load load,
bool low_latency)
{
@@ -252,9 +277,30 @@ iwl_mvm_scan_type _iwl_mvm_get_scan_type(struct iwl_mvm *mvm, bool p2p_device,
if (!global_cnt)
return IWL_SCAN_TYPE_UNASSOC;
- if ((load == IWL_MVM_TRAFFIC_HIGH || low_latency) && !p2p_device &&
- fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_FRAGMENTED_SCAN))
- return IWL_SCAN_TYPE_FRAGMENTED;
+ if (fw_has_api(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_API_FRAGMENTED_SCAN)) {
+ if ((load == IWL_MVM_TRAFFIC_HIGH || low_latency) &&
+ (!vif || vif->type != NL80211_IFTYPE_P2P_DEVICE))
+ return IWL_SCAN_TYPE_FRAGMENTED;
+
+ /* in case of DCM with GO where BSS DTIM interval < 220msec
+ * set all scan requests as fast-balance scan
+ * */
+ if (vif && vif->type == NL80211_IFTYPE_STATION &&
+ vif->bss_conf.dtim_period < 220) {
+ struct iwl_is_dcm_with_go_iterator_data data = {
+ .current_vif = vif,
+ .is_dcm_with_p2p_go = false,
+ };
+
+ ieee80211_iterate_active_interfaces_atomic(mvm->hw,
+ IEEE80211_IFACE_ITER_NORMAL,
+ iwl_mvm_is_dcm_with_go_iterator,
+ &data);
+ if (data.is_dcm_with_p2p_go)
+ return IWL_SCAN_TYPE_FAST_BALANCE;
+ }
+ }
if (load >= IWL_MVM_TRAFFIC_MEDIUM || low_latency)
return IWL_SCAN_TYPE_MILD;
@@ -263,7 +309,8 @@ iwl_mvm_scan_type _iwl_mvm_get_scan_type(struct iwl_mvm *mvm, bool p2p_device,
}
static enum
-iwl_mvm_scan_type iwl_mvm_get_scan_type(struct iwl_mvm *mvm, bool p2p_device)
+iwl_mvm_scan_type iwl_mvm_get_scan_type(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif)
{
enum iwl_mvm_traffic_load load;
bool low_latency;
@@ -271,12 +318,12 @@ iwl_mvm_scan_type iwl_mvm_get_scan_type(struct iwl_mvm *mvm, bool p2p_device)
load = iwl_mvm_get_traffic_load(mvm);
low_latency = iwl_mvm_low_latency(mvm);
- return _iwl_mvm_get_scan_type(mvm, p2p_device, load, low_latency);
+ return _iwl_mvm_get_scan_type(mvm, vif, load, low_latency);
}
static enum
iwl_mvm_scan_type iwl_mvm_get_scan_type_band(struct iwl_mvm *mvm,
- bool p2p_device,
+ struct ieee80211_vif *vif,
enum nl80211_band band)
{
enum iwl_mvm_traffic_load load;
@@ -285,7 +332,7 @@ iwl_mvm_scan_type iwl_mvm_get_scan_type_band(struct iwl_mvm *mvm,
load = iwl_mvm_get_traffic_load_band(mvm, band);
low_latency = iwl_mvm_low_latency_band(mvm, band);
- return _iwl_mvm_get_scan_type(mvm, p2p_device, load, low_latency);
+ return _iwl_mvm_get_scan_type(mvm, vif, load, low_latency);
}
static int
@@ -836,16 +883,25 @@ static inline bool iwl_mvm_scan_use_ebs(struct iwl_mvm *mvm,
struct ieee80211_vif *vif)
{
const struct iwl_ucode_capabilities *capa = &mvm->fw->ucode_capa;
+ bool low_latency;
+
+ if (iwl_mvm_is_cdb_supported(mvm))
+ low_latency = iwl_mvm_low_latency_band(mvm, NL80211_BAND_5GHZ);
+ else
+ low_latency = iwl_mvm_low_latency(mvm);
/* We can only use EBS if:
* 1. the feature is supported;
* 2. the last EBS was successful;
* 3. if only single scan, the single scan EBS API is supported;
* 4. it's not a p2p find operation.
+ * 5. we are not in low latency mode,
+ * or if fragmented ebs is supported by the FW
*/
return ((capa->flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT) &&
mvm->last_ebs_successful && IWL_MVM_ENABLE_EBS &&
- vif->type != NL80211_IFTYPE_P2P_DEVICE);
+ vif->type != NL80211_IFTYPE_P2P_DEVICE &&
+ (!low_latency || iwl_mvm_is_frag_ebs_supported(mvm)));
}
static inline bool iwl_mvm_is_regular_scan(struct iwl_mvm_scan_params *params)
@@ -854,6 +910,12 @@ static inline bool iwl_mvm_is_regular_scan(struct iwl_mvm_scan_params *params)
params->scan_plans[0].iterations == 1;
}
+static bool iwl_mvm_is_scan_fragmented(enum iwl_mvm_scan_type type)
+{
+ return (type == IWL_SCAN_TYPE_FRAGMENTED ||
+ type == IWL_SCAN_TYPE_FAST_BALANCE);
+}
+
static int iwl_mvm_scan_lmac_flags(struct iwl_mvm *mvm,
struct iwl_mvm_scan_params *params,
struct ieee80211_vif *vif)
@@ -866,7 +928,7 @@ static int iwl_mvm_scan_lmac_flags(struct iwl_mvm *mvm,
if (params->n_ssids == 1 && params->ssids[0].ssid_len != 0)
flags |= IWL_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION;
- if (params->type == IWL_SCAN_TYPE_FRAGMENTED)
+ if (iwl_mvm_is_scan_fragmented(params->type))
flags |= IWL_MVM_LMAC_SCAN_FLAG_FRAGMENTED;
if (iwl_mvm_rrm_scan_needed(mvm) &&
@@ -889,7 +951,7 @@ static int iwl_mvm_scan_lmac_flags(struct iwl_mvm *mvm,
if (iwl_mvm_is_regular_scan(params) &&
vif->type != NL80211_IFTYPE_P2P_DEVICE &&
- params->type != IWL_SCAN_TYPE_FRAGMENTED)
+ !iwl_mvm_is_scan_fragmented(params->type))
flags |= IWL_MVM_LMAC_SCAN_FLAG_EXTENDED_DWELL;
return flags;
@@ -1038,7 +1100,7 @@ static void iwl_mvm_fill_channels(struct iwl_mvm *mvm, u8 *channels)
static void iwl_mvm_fill_scan_config_v1(struct iwl_mvm *mvm, void *config,
u32 flags, u8 channel_flags)
{
- enum iwl_mvm_scan_type type = iwl_mvm_get_scan_type(mvm, false);
+ enum iwl_mvm_scan_type type = iwl_mvm_get_scan_type(mvm, NULL);
struct iwl_scan_config_v1 *cfg = config;
cfg->flags = cpu_to_le32(flags);
@@ -1071,9 +1133,9 @@ static void iwl_mvm_fill_scan_config(struct iwl_mvm *mvm, void *config,
if (iwl_mvm_is_cdb_supported(mvm)) {
enum iwl_mvm_scan_type lb_type, hb_type;
- lb_type = iwl_mvm_get_scan_type_band(mvm, false,
+ lb_type = iwl_mvm_get_scan_type_band(mvm, NULL,
NL80211_BAND_2GHZ);
- hb_type = iwl_mvm_get_scan_type_band(mvm, false,
+ hb_type = iwl_mvm_get_scan_type_band(mvm, NULL,
NL80211_BAND_5GHZ);
cfg->out_of_channel_time[SCAN_LB_LMAC_IDX] =
@@ -1087,7 +1149,7 @@ static void iwl_mvm_fill_scan_config(struct iwl_mvm *mvm, void *config,
cpu_to_le32(scan_timing[hb_type].suspend_time);
} else {
enum iwl_mvm_scan_type type =
- iwl_mvm_get_scan_type(mvm, false);
+ iwl_mvm_get_scan_type(mvm, NULL);
cfg->out_of_channel_time[SCAN_LB_LMAC_IDX] =
cpu_to_le32(scan_timing[type].max_out_time);
@@ -1124,14 +1186,14 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm)
return -ENOBUFS;
if (iwl_mvm_is_cdb_supported(mvm)) {
- type = iwl_mvm_get_scan_type_band(mvm, false,
+ type = iwl_mvm_get_scan_type_band(mvm, NULL,
NL80211_BAND_2GHZ);
- hb_type = iwl_mvm_get_scan_type_band(mvm, false,
+ hb_type = iwl_mvm_get_scan_type_band(mvm, NULL,
NL80211_BAND_5GHZ);
if (type == mvm->scan_type && hb_type == mvm->hb_scan_type)
return 0;
} else {
- type = iwl_mvm_get_scan_type(mvm, false);
+ type = iwl_mvm_get_scan_type(mvm, NULL);
if (type == mvm->scan_type)
return 0;
}
@@ -1156,7 +1218,7 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm)
SCAN_CONFIG_FLAG_SET_MAC_ADDR |
SCAN_CONFIG_FLAG_SET_CHANNEL_FLAGS |
SCAN_CONFIG_N_CHANNELS(num_channels) |
- (type == IWL_SCAN_TYPE_FRAGMENTED ?
+ (iwl_mvm_is_scan_fragmented(type) ?
SCAN_CONFIG_FLAG_SET_FRAGMENTED :
SCAN_CONFIG_FLAG_CLEAR_FRAGMENTED);
@@ -1171,7 +1233,7 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm)
*/
if (iwl_mvm_cdb_scan_api(mvm)) {
if (iwl_mvm_is_cdb_supported(mvm))
- flags |= (hb_type == IWL_SCAN_TYPE_FRAGMENTED) ?
+ flags |= (iwl_mvm_is_scan_fragmented(hb_type)) ?
SCAN_CONFIG_FLAG_SET_LMAC2_FRAGMENTED :
SCAN_CONFIG_FLAG_CLEAR_LMAC2_FRAGMENTED;
iwl_mvm_fill_scan_config(mvm, cfg, flags, channel_flags);
@@ -1332,11 +1394,11 @@ static u16 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm,
if (params->n_ssids == 1 && params->ssids[0].ssid_len != 0)
flags |= IWL_UMAC_SCAN_GEN_FLAGS_PRE_CONNECT;
- if (params->type == IWL_SCAN_TYPE_FRAGMENTED)
+ if (iwl_mvm_is_scan_fragmented(params->type))
flags |= IWL_UMAC_SCAN_GEN_FLAGS_FRAGMENTED;
if (iwl_mvm_is_cdb_supported(mvm) &&
- params->hb_type == IWL_SCAN_TYPE_FRAGMENTED)
+ iwl_mvm_is_scan_fragmented(params->hb_type))
flags |= IWL_UMAC_SCAN_GEN_FLAGS_LMAC2_FRAGMENTED;
if (iwl_mvm_rrm_scan_needed(mvm) &&
@@ -1374,7 +1436,7 @@ static u16 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm,
*/
if (iwl_mvm_is_regular_scan(params) &&
vif->type != NL80211_IFTYPE_P2P_DEVICE &&
- params->type != IWL_SCAN_TYPE_FRAGMENTED &&
+ !iwl_mvm_is_scan_fragmented(params->type) &&
!iwl_mvm_is_adaptive_dwell_supported(mvm) &&
!iwl_mvm_is_oce_supported(mvm))
flags |= IWL_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL;
@@ -1442,6 +1504,9 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
if (gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_LMAC2_FRAGMENTED)
cmd->v8.num_of_fragments[SCAN_HB_LMAC_IDX] =
IWL_SCAN_NUM_OF_FRAGS;
+
+ cmd->v8.general_flags2 =
+ IWL_UMAC_SCAN_GEN_FLAGS2_ALLOW_CHNL_REORDER;
}
cmd->scan_start_mac_id = scan_vif->id;
@@ -1449,11 +1514,21 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
if (type == IWL_MVM_SCAN_SCHED || type == IWL_MVM_SCAN_NETDETECT)
cmd->flags = cpu_to_le32(IWL_UMAC_SCAN_FLAG_PREEMPTIVE);
- if (iwl_mvm_scan_use_ebs(mvm, vif))
+ if (iwl_mvm_scan_use_ebs(mvm, vif)) {
channel_flags = IWL_SCAN_CHANNEL_FLAG_EBS |
IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
IWL_SCAN_CHANNEL_FLAG_CACHE_ADD;
+ /* set fragmented ebs for fragmented scan on HB channels */
+ if (iwl_mvm_is_frag_ebs_supported(mvm)) {
+ if (gen_flags &
+ IWL_UMAC_SCAN_GEN_FLAGS_LMAC2_FRAGMENTED ||
+ (!iwl_mvm_is_cdb_supported(mvm) &&
+ gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_FRAGMENTED))
+ channel_flags |= IWL_SCAN_CHANNEL_FLAG_EBS_FRAG;
+ }
+ }
+
chan_param->flags = channel_flags;
chan_param->count = params->n_channels;
@@ -1570,19 +1645,20 @@ void iwl_mvm_scan_timeout_wk(struct work_struct *work)
static void iwl_mvm_fill_scan_type(struct iwl_mvm *mvm,
struct iwl_mvm_scan_params *params,
- bool p2p)
+ struct ieee80211_vif *vif)
{
if (iwl_mvm_is_cdb_supported(mvm)) {
params->type =
- iwl_mvm_get_scan_type_band(mvm, p2p,
+ iwl_mvm_get_scan_type_band(mvm, vif,
NL80211_BAND_2GHZ);
params->hb_type =
- iwl_mvm_get_scan_type_band(mvm, p2p,
+ iwl_mvm_get_scan_type_band(mvm, vif,
NL80211_BAND_5GHZ);
} else {
- params->type = iwl_mvm_get_scan_type(mvm, p2p);
+ params->type = iwl_mvm_get_scan_type(mvm, vif);
}
}
+
int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct cfg80211_scan_request *req,
struct ieee80211_scan_ies *ies)
@@ -1630,8 +1706,7 @@ int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
params.scan_plans = &scan_plan;
params.n_scan_plans = 1;
- iwl_mvm_fill_scan_type(mvm, &params,
- vif->type == NL80211_IFTYPE_P2P_DEVICE);
+ iwl_mvm_fill_scan_type(mvm, &params, vif);
ret = iwl_mvm_get_measurement_dwell(mvm, req, &params);
if (ret < 0)
@@ -1726,8 +1801,7 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
params.n_scan_plans = req->n_scan_plans;
params.scan_plans = req->scan_plans;
- iwl_mvm_fill_scan_type(mvm, &params,
- vif->type == NL80211_IFTYPE_P2P_DEVICE);
+ iwl_mvm_fill_scan_type(mvm, &params, vif);
/* In theory, LMAC scans can handle a 32-bit delay, but since
* waiting for over 18 hours to start the scan is a bit silly
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sf.c b/drivers/net/wireless/intel/iwlwifi/mvm/sf.c
index 539b06bf0803..d1d76bb9a750 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sf.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sf.c
@@ -17,11 +17,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
index 18db1ed92d9b..1887d2b9f185 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
@@ -19,11 +19,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
@@ -72,6 +67,14 @@
#include "sta.h"
#include "rs.h"
+static int iwl_mvm_set_fw_key_idx(struct iwl_mvm *mvm);
+
+static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
+ u32 sta_id,
+ struct ieee80211_key_conf *key, bool mcast,
+ u32 tkip_iv32, u16 *tkip_p1k, u32 cmd_flags,
+ u8 key_offset, bool mfp);
+
/*
* New version of ADD_STA_sta command added new fields at the end of the
* structure, so sending the size of the relevant API's structure is enough to
@@ -355,6 +358,108 @@ static int iwl_mvm_invalidate_sta_queue(struct iwl_mvm *mvm, int queue,
return ret;
}
+static int iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue,
+ int mac80211_queue, u8 tid, u8 flags)
+{
+ struct iwl_scd_txq_cfg_cmd cmd = {
+ .scd_queue = queue,
+ .action = SCD_CFG_DISABLE_QUEUE,
+ };
+ bool remove_mac_queue = mac80211_queue != IEEE80211_INVAL_HW_QUEUE;
+ int ret;
+
+ if (WARN_ON(remove_mac_queue && mac80211_queue >= IEEE80211_MAX_QUEUES))
+ return -EINVAL;
+
+ if (iwl_mvm_has_new_tx_api(mvm)) {
+ spin_lock_bh(&mvm->queue_info_lock);
+
+ if (remove_mac_queue)
+ mvm->hw_queue_to_mac80211[queue] &=
+ ~BIT(mac80211_queue);
+
+ spin_unlock_bh(&mvm->queue_info_lock);
+
+ iwl_trans_txq_free(mvm->trans, queue);
+
+ return 0;
+ }
+
+ spin_lock_bh(&mvm->queue_info_lock);
+
+ if (WARN_ON(mvm->queue_info[queue].tid_bitmap == 0)) {
+ spin_unlock_bh(&mvm->queue_info_lock);
+ return 0;
+ }
+
+ mvm->queue_info[queue].tid_bitmap &= ~BIT(tid);
+
+ /*
+ * If there is another TID with the same AC - don't remove the MAC queue
+ * from the mapping
+ */
+ if (tid < IWL_MAX_TID_COUNT) {
+ unsigned long tid_bitmap =
+ mvm->queue_info[queue].tid_bitmap;
+ int ac = tid_to_mac80211_ac[tid];
+ int i;
+
+ for_each_set_bit(i, &tid_bitmap, IWL_MAX_TID_COUNT) {
+ if (tid_to_mac80211_ac[i] == ac)
+ remove_mac_queue = false;
+ }
+ }
+
+ if (remove_mac_queue)
+ mvm->hw_queue_to_mac80211[queue] &=
+ ~BIT(mac80211_queue);
+
+ cmd.action = mvm->queue_info[queue].tid_bitmap ?
+ SCD_CFG_ENABLE_QUEUE : SCD_CFG_DISABLE_QUEUE;
+ if (cmd.action == SCD_CFG_DISABLE_QUEUE)
+ mvm->queue_info[queue].status = IWL_MVM_QUEUE_FREE;
+
+ IWL_DEBUG_TX_QUEUES(mvm,
+ "Disabling TXQ #%d tids=0x%x (mac80211 map:0x%x)\n",
+ queue,
+ mvm->queue_info[queue].tid_bitmap,
+ mvm->hw_queue_to_mac80211[queue]);
+
+ /* If the queue is still enabled - nothing left to do in this func */
+ if (cmd.action == SCD_CFG_ENABLE_QUEUE) {
+ spin_unlock_bh(&mvm->queue_info_lock);
+ return 0;
+ }
+
+ cmd.sta_id = mvm->queue_info[queue].ra_sta_id;
+ cmd.tid = mvm->queue_info[queue].txq_tid;
+
+ /* Make sure queue info is correct even though we overwrite it */
+ WARN(mvm->queue_info[queue].tid_bitmap ||
+ mvm->hw_queue_to_mac80211[queue],
+ "TXQ #%d info out-of-sync - mac map=0x%x, tids=0x%x\n",
+ queue, mvm->hw_queue_to_mac80211[queue],
+ mvm->queue_info[queue].tid_bitmap);
+
+ /* If we are here - the queue is freed and we can zero out these vals */
+ mvm->queue_info[queue].tid_bitmap = 0;
+ mvm->hw_queue_to_mac80211[queue] = 0;
+
+ /* Regardless if this is a reserved TXQ for a STA - mark it as false */
+ mvm->queue_info[queue].reserved = false;
+
+ spin_unlock_bh(&mvm->queue_info_lock);
+
+ iwl_trans_txq_disable(mvm->trans, queue, false);
+ ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, flags,
+ sizeof(struct iwl_scd_txq_cfg_cmd), &cmd);
+
+ if (ret)
+ IWL_ERR(mvm, "Failed to disable queue %d (ret=%d)\n",
+ queue, ret);
+ return ret;
+}
+
static int iwl_mvm_get_queue_agg_tids(struct iwl_mvm *mvm, int queue)
{
struct ieee80211_sta *sta;
@@ -444,11 +549,12 @@ static int iwl_mvm_remove_sta_queue_marking(struct iwl_mvm *mvm, int queue)
}
static int iwl_mvm_free_inactive_queue(struct iwl_mvm *mvm, int queue,
- bool same_sta)
+ u8 new_sta_id)
{
struct iwl_mvm_sta *mvmsta;
u8 txq_curr_ac, sta_id, tid;
unsigned long disable_agg_tids = 0;
+ bool same_sta;
int ret;
lockdep_assert_held(&mvm->mutex);
@@ -462,6 +568,8 @@ static int iwl_mvm_free_inactive_queue(struct iwl_mvm *mvm, int queue,
tid = mvm->queue_info[queue].txq_tid;
spin_unlock_bh(&mvm->queue_info_lock);
+ same_sta = sta_id == new_sta_id;
+
mvmsta = iwl_mvm_sta_from_staid_protected(mvm, sta_id);
if (WARN_ON(!mvmsta))
return -EINVAL;
@@ -476,10 +584,6 @@ static int iwl_mvm_free_inactive_queue(struct iwl_mvm *mvm, int queue,
mvmsta->vif->hw_queue[txq_curr_ac],
tid, 0);
if (ret) {
- /* Re-mark the inactive queue as inactive */
- spin_lock_bh(&mvm->queue_info_lock);
- mvm->queue_info[queue].status = IWL_MVM_QUEUE_INACTIVE;
- spin_unlock_bh(&mvm->queue_info_lock);
IWL_ERR(mvm,
"Failed to free inactive queue %d (ret=%d)\n",
queue, ret);
@@ -501,7 +605,13 @@ static int iwl_mvm_get_shared_queue(struct iwl_mvm *mvm,
u8 ac_to_queue[IEEE80211_NUM_ACS];
int i;
+ /*
+ * This protects us against grabbing a queue that's being reconfigured
+ * by the inactivity checker.
+ */
+ lockdep_assert_held(&mvm->mutex);
lockdep_assert_held(&mvm->queue_info_lock);
+
if (WARN_ON(iwl_mvm_has_new_tx_api(mvm)))
return -EINVAL;
@@ -514,11 +624,6 @@ static int iwl_mvm_get_shared_queue(struct iwl_mvm *mvm,
i != IWL_MVM_DQA_BSS_CLIENT_QUEUE)
continue;
- /* Don't try and take queues being reconfigured */
- if (mvm->queue_info[queue].status ==
- IWL_MVM_QUEUE_RECONFIGURING)
- continue;
-
ac_to_queue[mvm->queue_info[i].mac80211_ac] = i;
}
@@ -559,14 +664,6 @@ static int iwl_mvm_get_shared_queue(struct iwl_mvm *mvm,
return -ENOSPC;
}
- /* Make sure the queue isn't in the middle of being reconfigured */
- if (mvm->queue_info[queue].status == IWL_MVM_QUEUE_RECONFIGURING) {
- IWL_ERR(mvm,
- "TXQ %d is in the middle of re-config - try again\n",
- queue);
- return -EBUSY;
- }
-
return queue;
}
@@ -576,9 +673,9 @@ static int iwl_mvm_get_shared_queue(struct iwl_mvm *mvm,
* in such a case, otherwise - if no redirection required - it does nothing,
* unless the %force param is true.
*/
-int iwl_mvm_scd_queue_redirect(struct iwl_mvm *mvm, int queue, int tid,
- int ac, int ssn, unsigned int wdg_timeout,
- bool force)
+static int iwl_mvm_scd_queue_redirect(struct iwl_mvm *mvm, int queue, int tid,
+ int ac, int ssn, unsigned int wdg_timeout,
+ bool force)
{
struct iwl_scd_txq_cfg_cmd cmd = {
.scd_queue = queue,
@@ -613,7 +710,7 @@ int iwl_mvm_scd_queue_redirect(struct iwl_mvm *mvm, int queue, int tid,
cmd.tx_fifo = iwl_mvm_ac_to_tx_fifo[mvm->queue_info[queue].mac80211_ac];
cmd.tid = mvm->queue_info[queue].txq_tid;
mq = mvm->hw_queue_to_mac80211[queue];
- shared_queue = (mvm->queue_info[queue].hw_queue_refcount > 1);
+ shared_queue = hweight16(mvm->queue_info[queue].tid_bitmap) > 1;
spin_unlock_bh(&mvm->queue_info_lock);
IWL_DEBUG_TX_QUEUES(mvm, "Redirecting TXQ #%d to FIFO #%d\n",
@@ -671,6 +768,57 @@ out:
return ret;
}
+static int iwl_mvm_find_free_queue(struct iwl_mvm *mvm, u8 sta_id,
+ u8 minq, u8 maxq)
+{
+ int i;
+
+ lockdep_assert_held(&mvm->queue_info_lock);
+
+ /* This should not be hit with new TX path */
+ if (WARN_ON(iwl_mvm_has_new_tx_api(mvm)))
+ return -ENOSPC;
+
+ /* Start by looking for a free queue */
+ for (i = minq; i <= maxq; i++)
+ if (mvm->queue_info[i].tid_bitmap == 0 &&
+ mvm->queue_info[i].status == IWL_MVM_QUEUE_FREE)
+ return i;
+
+ return -ENOSPC;
+}
+
+static int iwl_mvm_tvqm_enable_txq(struct iwl_mvm *mvm, int mac80211_queue,
+ u8 sta_id, u8 tid, unsigned int timeout)
+{
+ int queue, size = IWL_DEFAULT_QUEUE_SIZE;
+
+ if (tid == IWL_MAX_TID_COUNT) {
+ tid = IWL_MGMT_TID;
+ size = IWL_MGMT_QUEUE_SIZE;
+ }
+ queue = iwl_trans_txq_alloc(mvm->trans,
+ cpu_to_le16(TX_QUEUE_CFG_ENABLE_QUEUE),
+ sta_id, tid, SCD_QUEUE_CFG, size, timeout);
+
+ if (queue < 0) {
+ IWL_DEBUG_TX_QUEUES(mvm,
+ "Failed allocating TXQ for sta %d tid %d, ret: %d\n",
+ sta_id, tid, queue);
+ return queue;
+ }
+
+ IWL_DEBUG_TX_QUEUES(mvm, "Enabling TXQ #%d for sta %d tid %d\n",
+ queue, sta_id, tid);
+
+ mvm->hw_queue_to_mac80211[queue] |= BIT(mac80211_queue);
+ IWL_DEBUG_TX_QUEUES(mvm,
+ "Enabling TXQ #%d (mac80211 map:0x%x)\n",
+ queue, mvm->hw_queue_to_mac80211[queue]);
+
+ return queue;
+}
+
static int iwl_mvm_sta_alloc_queue_tvqm(struct iwl_mvm *mvm,
struct ieee80211_sta *sta, u8 ac,
int tid)
@@ -695,12 +843,428 @@ static int iwl_mvm_sta_alloc_queue_tvqm(struct iwl_mvm *mvm,
spin_lock_bh(&mvmsta->lock);
mvmsta->tid_data[tid].txq_id = queue;
- mvmsta->tid_data[tid].is_tid_active = true;
spin_unlock_bh(&mvmsta->lock);
return 0;
}
+static bool iwl_mvm_update_txq_mapping(struct iwl_mvm *mvm, int queue,
+ int mac80211_queue, u8 sta_id, u8 tid)
+{
+ bool enable_queue = true;
+
+ spin_lock_bh(&mvm->queue_info_lock);
+
+ /* Make sure this TID isn't already enabled */
+ if (mvm->queue_info[queue].tid_bitmap & BIT(tid)) {
+ spin_unlock_bh(&mvm->queue_info_lock);
+ IWL_ERR(mvm, "Trying to enable TXQ %d with existing TID %d\n",
+ queue, tid);
+ return false;
+ }
+
+ /* Update mappings and refcounts */
+ if (mvm->queue_info[queue].tid_bitmap)
+ enable_queue = false;
+
+ if (mac80211_queue != IEEE80211_INVAL_HW_QUEUE) {
+ WARN(mac80211_queue >=
+ BITS_PER_BYTE * sizeof(mvm->hw_queue_to_mac80211[0]),
+ "cannot track mac80211 queue %d (queue %d, sta %d, tid %d)\n",
+ mac80211_queue, queue, sta_id, tid);
+ mvm->hw_queue_to_mac80211[queue] |= BIT(mac80211_queue);
+ }
+
+ mvm->queue_info[queue].tid_bitmap |= BIT(tid);
+ mvm->queue_info[queue].ra_sta_id = sta_id;
+
+ if (enable_queue) {
+ if (tid != IWL_MAX_TID_COUNT)
+ mvm->queue_info[queue].mac80211_ac =
+ tid_to_mac80211_ac[tid];
+ else
+ mvm->queue_info[queue].mac80211_ac = IEEE80211_AC_VO;
+
+ mvm->queue_info[queue].txq_tid = tid;
+ }
+
+ IWL_DEBUG_TX_QUEUES(mvm,
+ "Enabling TXQ #%d tids=0x%x (mac80211 map:0x%x)\n",
+ queue, mvm->queue_info[queue].tid_bitmap,
+ mvm->hw_queue_to_mac80211[queue]);
+
+ spin_unlock_bh(&mvm->queue_info_lock);
+
+ return enable_queue;
+}
+
+static bool iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue,
+ int mac80211_queue, u16 ssn,
+ const struct iwl_trans_txq_scd_cfg *cfg,
+ unsigned int wdg_timeout)
+{
+ struct iwl_scd_txq_cfg_cmd cmd = {
+ .scd_queue = queue,
+ .action = SCD_CFG_ENABLE_QUEUE,
+ .window = cfg->frame_limit,
+ .sta_id = cfg->sta_id,
+ .ssn = cpu_to_le16(ssn),
+ .tx_fifo = cfg->fifo,
+ .aggregate = cfg->aggregate,
+ .tid = cfg->tid,
+ };
+ bool inc_ssn;
+
+ if (WARN_ON(iwl_mvm_has_new_tx_api(mvm)))
+ return false;
+
+ /* Send the enabling command if we need to */
+ if (!iwl_mvm_update_txq_mapping(mvm, queue, mac80211_queue,
+ cfg->sta_id, cfg->tid))
+ return false;
+
+ inc_ssn = iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn,
+ NULL, wdg_timeout);
+ if (inc_ssn)
+ le16_add_cpu(&cmd.ssn, 1);
+
+ WARN(iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, sizeof(cmd), &cmd),
+ "Failed to configure queue %d on FIFO %d\n", queue, cfg->fifo);
+
+ return inc_ssn;
+}
+
+static void iwl_mvm_change_queue_tid(struct iwl_mvm *mvm, int queue)
+{
+ struct iwl_scd_txq_cfg_cmd cmd = {
+ .scd_queue = queue,
+ .action = SCD_CFG_UPDATE_QUEUE_TID,
+ };
+ int tid;
+ unsigned long tid_bitmap;
+ int ret;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ if (WARN_ON(iwl_mvm_has_new_tx_api(mvm)))
+ return;
+
+ spin_lock_bh(&mvm->queue_info_lock);
+ tid_bitmap = mvm->queue_info[queue].tid_bitmap;
+ spin_unlock_bh(&mvm->queue_info_lock);
+
+ if (WARN(!tid_bitmap, "TXQ %d has no tids assigned to it\n", queue))
+ return;
+
+ /* Find any TID for queue */
+ tid = find_first_bit(&tid_bitmap, IWL_MAX_TID_COUNT + 1);
+ cmd.tid = tid;
+ cmd.tx_fifo = iwl_mvm_ac_to_tx_fifo[tid_to_mac80211_ac[tid]];
+
+ ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, sizeof(cmd), &cmd);
+ if (ret) {
+ IWL_ERR(mvm, "Failed to update owner of TXQ %d (ret=%d)\n",
+ queue, ret);
+ return;
+ }
+
+ spin_lock_bh(&mvm->queue_info_lock);
+ mvm->queue_info[queue].txq_tid = tid;
+ spin_unlock_bh(&mvm->queue_info_lock);
+ IWL_DEBUG_TX_QUEUES(mvm, "Changed TXQ %d ownership to tid %d\n",
+ queue, tid);
+}
+
+static void iwl_mvm_unshare_queue(struct iwl_mvm *mvm, int queue)
+{
+ struct ieee80211_sta *sta;
+ struct iwl_mvm_sta *mvmsta;
+ u8 sta_id;
+ int tid = -1;
+ unsigned long tid_bitmap;
+ unsigned int wdg_timeout;
+ int ssn;
+ int ret = true;
+
+ /* queue sharing is disabled on new TX path */
+ if (WARN_ON(iwl_mvm_has_new_tx_api(mvm)))
+ return;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ spin_lock_bh(&mvm->queue_info_lock);
+ sta_id = mvm->queue_info[queue].ra_sta_id;
+ tid_bitmap = mvm->queue_info[queue].tid_bitmap;
+ spin_unlock_bh(&mvm->queue_info_lock);
+
+ /* Find TID for queue, and make sure it is the only one on the queue */
+ tid = find_first_bit(&tid_bitmap, IWL_MAX_TID_COUNT + 1);
+ if (tid_bitmap != BIT(tid)) {
+ IWL_ERR(mvm, "Failed to unshare q %d, active tids=0x%lx\n",
+ queue, tid_bitmap);
+ return;
+ }
+
+ IWL_DEBUG_TX_QUEUES(mvm, "Unsharing TXQ %d, keeping tid %d\n", queue,
+ tid);
+
+ sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
+ lockdep_is_held(&mvm->mutex));
+
+ if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta)))
+ return;
+
+ mvmsta = iwl_mvm_sta_from_mac80211(sta);
+ wdg_timeout = iwl_mvm_get_wd_timeout(mvm, mvmsta->vif, false, false);
+
+ ssn = IEEE80211_SEQ_TO_SN(mvmsta->tid_data[tid].seq_number);
+
+ ret = iwl_mvm_scd_queue_redirect(mvm, queue, tid,
+ tid_to_mac80211_ac[tid], ssn,
+ wdg_timeout, true);
+ if (ret) {
+ IWL_ERR(mvm, "Failed to redirect TXQ %d\n", queue);
+ return;
+ }
+
+ /* If aggs should be turned back on - do it */
+ if (mvmsta->tid_data[tid].state == IWL_AGG_ON) {
+ struct iwl_mvm_add_sta_cmd cmd = {0};
+
+ mvmsta->tid_disable_agg &= ~BIT(tid);
+
+ cmd.mac_id_n_color = cpu_to_le32(mvmsta->mac_id_n_color);
+ cmd.sta_id = mvmsta->sta_id;
+ cmd.add_modify = STA_MODE_MODIFY;
+ cmd.modify_mask = STA_MODIFY_TID_DISABLE_TX;
+ cmd.tfd_queue_msk = cpu_to_le32(mvmsta->tfd_queue_msk);
+ cmd.tid_disable_tx = cpu_to_le16(mvmsta->tid_disable_agg);
+
+ ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC,
+ iwl_mvm_add_sta_cmd_size(mvm), &cmd);
+ if (!ret) {
+ IWL_DEBUG_TX_QUEUES(mvm,
+ "TXQ #%d is now aggregated again\n",
+ queue);
+
+ /* Mark queue intenally as aggregating again */
+ iwl_trans_txq_set_shared_mode(mvm->trans, queue, false);
+ }
+ }
+
+ spin_lock_bh(&mvm->queue_info_lock);
+ mvm->queue_info[queue].status = IWL_MVM_QUEUE_READY;
+ spin_unlock_bh(&mvm->queue_info_lock);
+}
+
+/*
+ * Remove inactive TIDs of a given queue.
+ * If all queue TIDs are inactive - mark the queue as inactive
+ * If only some the queue TIDs are inactive - unmap them from the queue
+ *
+ * Returns %true if all TIDs were removed and the queue could be reused.
+ */
+static bool iwl_mvm_remove_inactive_tids(struct iwl_mvm *mvm,
+ struct iwl_mvm_sta *mvmsta, int queue,
+ unsigned long tid_bitmap,
+ unsigned long *unshare_queues,
+ unsigned long *changetid_queues)
+{
+ int tid;
+
+ lockdep_assert_held(&mvmsta->lock);
+ lockdep_assert_held(&mvm->queue_info_lock);
+
+ if (WARN_ON(iwl_mvm_has_new_tx_api(mvm)))
+ return false;
+
+ /* Go over all non-active TIDs, incl. IWL_MAX_TID_COUNT (for mgmt) */
+ for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) {
+ /* If some TFDs are still queued - don't mark TID as inactive */
+ if (iwl_mvm_tid_queued(mvm, &mvmsta->tid_data[tid]))
+ tid_bitmap &= ~BIT(tid);
+
+ /* Don't mark as inactive any TID that has an active BA */
+ if (mvmsta->tid_data[tid].state != IWL_AGG_OFF)
+ tid_bitmap &= ~BIT(tid);
+ }
+
+ /* If all TIDs in the queue are inactive - return it can be reused */
+ if (tid_bitmap == mvm->queue_info[queue].tid_bitmap) {
+ IWL_DEBUG_TX_QUEUES(mvm, "Queue %d is inactive\n", queue);
+ return true;
+ }
+
+ /*
+ * If we are here, this is a shared queue and not all TIDs timed-out.
+ * Remove the ones that did.
+ */
+ for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) {
+ int mac_queue = mvmsta->vif->hw_queue[tid_to_mac80211_ac[tid]];
+ u16 tid_bitmap;
+
+ mvmsta->tid_data[tid].txq_id = IWL_MVM_INVALID_QUEUE;
+ mvm->hw_queue_to_mac80211[queue] &= ~BIT(mac_queue);
+ mvm->queue_info[queue].tid_bitmap &= ~BIT(tid);
+
+ tid_bitmap = mvm->queue_info[queue].tid_bitmap;
+
+ /*
+ * We need to take into account a situation in which a TXQ was
+ * allocated to TID x, and then turned shared by adding TIDs y
+ * and z. If TID x becomes inactive and is removed from the TXQ,
+ * ownership must be given to one of the remaining TIDs.
+ * This is mainly because if TID x continues - a new queue can't
+ * be allocated for it as long as it is an owner of another TXQ.
+ *
+ * Mark this queue in the right bitmap, we'll send the command
+ * to the firmware later.
+ */
+ if (!(tid_bitmap & BIT(mvm->queue_info[queue].txq_tid)))
+ set_bit(queue, changetid_queues);
+
+ IWL_DEBUG_TX_QUEUES(mvm,
+ "Removing inactive TID %d from shared Q:%d\n",
+ tid, queue);
+ }
+
+ IWL_DEBUG_TX_QUEUES(mvm,
+ "TXQ #%d left with tid bitmap 0x%x\n", queue,
+ mvm->queue_info[queue].tid_bitmap);
+
+ /*
+ * There may be different TIDs with the same mac queues, so make
+ * sure all TIDs have existing corresponding mac queues enabled
+ */
+ tid_bitmap = mvm->queue_info[queue].tid_bitmap;
+ for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) {
+ mvm->hw_queue_to_mac80211[queue] |=
+ BIT(mvmsta->vif->hw_queue[tid_to_mac80211_ac[tid]]);
+ }
+
+ /* If the queue is marked as shared - "unshare" it */
+ if (hweight16(mvm->queue_info[queue].tid_bitmap) == 1 &&
+ mvm->queue_info[queue].status == IWL_MVM_QUEUE_SHARED) {
+ IWL_DEBUG_TX_QUEUES(mvm, "Marking Q:%d for reconfig\n",
+ queue);
+ set_bit(queue, unshare_queues);
+ }
+
+ return false;
+}
+
+/*
+ * Check for inactivity - this includes checking if any queue
+ * can be unshared and finding one (and only one) that can be
+ * reused.
+ * This function is also invoked as a sort of clean-up task,
+ * in which case @alloc_for_sta is IWL_MVM_INVALID_STA.
+ *
+ * Returns the queue number, or -ENOSPC.
+ */
+static int iwl_mvm_inactivity_check(struct iwl_mvm *mvm, u8 alloc_for_sta)
+{
+ unsigned long now = jiffies;
+ unsigned long unshare_queues = 0;
+ unsigned long changetid_queues = 0;
+ int i, ret, free_queue = -ENOSPC;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ if (iwl_mvm_has_new_tx_api(mvm))
+ return -ENOSPC;
+
+ spin_lock_bh(&mvm->queue_info_lock);
+
+ rcu_read_lock();
+
+ /* we skip the CMD queue below by starting at 1 */
+ BUILD_BUG_ON(IWL_MVM_DQA_CMD_QUEUE != 0);
+
+ for (i = 1; i < IWL_MAX_HW_QUEUES; i++) {
+ struct ieee80211_sta *sta;
+ struct iwl_mvm_sta *mvmsta;
+ u8 sta_id;
+ int tid;
+ unsigned long inactive_tid_bitmap = 0;
+ unsigned long queue_tid_bitmap;
+
+ queue_tid_bitmap = mvm->queue_info[i].tid_bitmap;
+ if (!queue_tid_bitmap)
+ continue;
+
+ /* If TXQ isn't in active use anyway - nothing to do here... */
+ if (mvm->queue_info[i].status != IWL_MVM_QUEUE_READY &&
+ mvm->queue_info[i].status != IWL_MVM_QUEUE_SHARED)
+ continue;
+
+ /* Check to see if there are inactive TIDs on this queue */
+ for_each_set_bit(tid, &queue_tid_bitmap,
+ IWL_MAX_TID_COUNT + 1) {
+ if (time_after(mvm->queue_info[i].last_frame_time[tid] +
+ IWL_MVM_DQA_QUEUE_TIMEOUT, now))
+ continue;
+
+ inactive_tid_bitmap |= BIT(tid);
+ }
+
+ /* If all TIDs are active - finish check on this queue */
+ if (!inactive_tid_bitmap)
+ continue;
+
+ /*
+ * If we are here - the queue hadn't been served recently and is
+ * in use
+ */
+
+ sta_id = mvm->queue_info[i].ra_sta_id;
+ sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
+
+ /*
+ * If the STA doesn't exist anymore, it isn't an error. It could
+ * be that it was removed since getting the queues, and in this
+ * case it should've inactivated its queues anyway.
+ */
+ if (IS_ERR_OR_NULL(sta))
+ continue;
+
+ mvmsta = iwl_mvm_sta_from_mac80211(sta);
+
+ /* this isn't so nice, but works OK due to the way we loop */
+ spin_unlock(&mvm->queue_info_lock);
+
+ /* and we need this locking order */
+ spin_lock(&mvmsta->lock);
+ spin_lock(&mvm->queue_info_lock);
+ ret = iwl_mvm_remove_inactive_tids(mvm, mvmsta, i,
+ inactive_tid_bitmap,
+ &unshare_queues,
+ &changetid_queues);
+ if (ret >= 0 && free_queue < 0)
+ free_queue = ret;
+ /* only unlock sta lock - we still need the queue info lock */
+ spin_unlock(&mvmsta->lock);
+ }
+
+ rcu_read_unlock();
+ spin_unlock_bh(&mvm->queue_info_lock);
+
+ /* Reconfigure queues requiring reconfiguation */
+ for_each_set_bit(i, &unshare_queues, IWL_MAX_HW_QUEUES)
+ iwl_mvm_unshare_queue(mvm, i);
+ for_each_set_bit(i, &changetid_queues, IWL_MAX_HW_QUEUES)
+ iwl_mvm_change_queue_tid(mvm, i);
+
+ if (free_queue >= 0 && alloc_for_sta != IWL_MVM_INVALID_STA) {
+ ret = iwl_mvm_free_inactive_queue(mvm, free_queue,
+ alloc_for_sta);
+ if (ret)
+ return ret;
+ }
+
+ return free_queue;
+}
+
static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm,
struct ieee80211_sta *sta, u8 ac, int tid,
struct ieee80211_hdr *hdr)
@@ -716,7 +1280,6 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm,
iwl_mvm_get_wd_timeout(mvm, mvmsta->vif, false, false);
u8 mac_queue = mvmsta->vif->hw_queue[ac];
int queue = -1;
- bool using_inactive_queue = false, same_sta = false;
unsigned long disable_agg_tids = 0;
enum iwl_mvm_agg_state queue_state;
bool shared_queue = false, inc_ssn;
@@ -753,9 +1316,7 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm,
if ((queue < 0 && mvmsta->reserved_queue != IEEE80211_INVAL_HW_QUEUE) &&
(mvm->queue_info[mvmsta->reserved_queue].status ==
- IWL_MVM_QUEUE_RESERVED ||
- mvm->queue_info[mvmsta->reserved_queue].status ==
- IWL_MVM_QUEUE_INACTIVE)) {
+ IWL_MVM_QUEUE_RESERVED)) {
queue = mvmsta->reserved_queue;
mvm->queue_info[queue].reserved = true;
IWL_DEBUG_TX_QUEUES(mvm, "Using reserved queue #%d\n", queue);
@@ -765,21 +1326,13 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm,
queue = iwl_mvm_find_free_queue(mvm, mvmsta->sta_id,
IWL_MVM_DQA_MIN_DATA_QUEUE,
IWL_MVM_DQA_MAX_DATA_QUEUE);
+ if (queue < 0) {
+ spin_unlock_bh(&mvm->queue_info_lock);
- /*
- * Check if this queue is already allocated but inactive.
- * In such a case, we'll need to first free this queue before enabling
- * it again, so we'll mark it as reserved to make sure no new traffic
- * arrives on it
- */
- if (queue > 0 &&
- mvm->queue_info[queue].status == IWL_MVM_QUEUE_INACTIVE) {
- mvm->queue_info[queue].status = IWL_MVM_QUEUE_RESERVED;
- using_inactive_queue = true;
- same_sta = mvm->queue_info[queue].ra_sta_id == mvmsta->sta_id;
- IWL_DEBUG_TX_QUEUES(mvm,
- "Re-assigning TXQ %d: sta_id=%d, tid=%d\n",
- queue, mvmsta->sta_id, tid);
+ /* try harder - perhaps kill an inactive queue */
+ queue = iwl_mvm_inactivity_check(mvm, mvmsta->sta_id);
+
+ spin_lock_bh(&mvm->queue_info_lock);
}
/* No free queue - we'll have to share */
@@ -797,7 +1350,7 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm,
* This will allow avoiding re-acquiring the lock at the end of the
* configuration. On error we'll mark it back as free.
*/
- if ((queue > 0) && !shared_queue)
+ if (queue > 0 && !shared_queue)
mvm->queue_info[queue].status = IWL_MVM_QUEUE_READY;
spin_unlock_bh(&mvm->queue_info_lock);
@@ -818,16 +1371,6 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm,
cfg.aggregate = (queue >= IWL_MVM_DQA_MIN_DATA_QUEUE ||
queue == IWL_MVM_DQA_BSS_CLIENT_QUEUE);
- /*
- * If this queue was previously inactive (idle) - we need to free it
- * first
- */
- if (using_inactive_queue) {
- ret = iwl_mvm_free_inactive_queue(mvm, queue, same_sta);
- if (ret)
- return ret;
- }
-
IWL_DEBUG_TX_QUEUES(mvm,
"Allocating %squeue #%d to sta %d on tid %d\n",
shared_queue ? "shared " : "", queue,
@@ -871,7 +1414,6 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm,
if (inc_ssn)
mvmsta->tid_data[tid].seq_number += 0x10;
mvmsta->tid_data[tid].txq_id = queue;
- mvmsta->tid_data[tid].is_tid_active = true;
mvmsta->tfd_queue_msk |= BIT(queue);
queue_state = mvmsta->tid_data[tid].state;
@@ -906,129 +1448,6 @@ out_err:
return ret;
}
-static void iwl_mvm_change_queue_owner(struct iwl_mvm *mvm, int queue)
-{
- struct iwl_scd_txq_cfg_cmd cmd = {
- .scd_queue = queue,
- .action = SCD_CFG_UPDATE_QUEUE_TID,
- };
- int tid;
- unsigned long tid_bitmap;
- int ret;
-
- lockdep_assert_held(&mvm->mutex);
-
- if (WARN_ON(iwl_mvm_has_new_tx_api(mvm)))
- return;
-
- spin_lock_bh(&mvm->queue_info_lock);
- tid_bitmap = mvm->queue_info[queue].tid_bitmap;
- spin_unlock_bh(&mvm->queue_info_lock);
-
- if (WARN(!tid_bitmap, "TXQ %d has no tids assigned to it\n", queue))
- return;
-
- /* Find any TID for queue */
- tid = find_first_bit(&tid_bitmap, IWL_MAX_TID_COUNT + 1);
- cmd.tid = tid;
- cmd.tx_fifo = iwl_mvm_ac_to_tx_fifo[tid_to_mac80211_ac[tid]];
-
- ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, sizeof(cmd), &cmd);
- if (ret) {
- IWL_ERR(mvm, "Failed to update owner of TXQ %d (ret=%d)\n",
- queue, ret);
- return;
- }
-
- spin_lock_bh(&mvm->queue_info_lock);
- mvm->queue_info[queue].txq_tid = tid;
- spin_unlock_bh(&mvm->queue_info_lock);
- IWL_DEBUG_TX_QUEUES(mvm, "Changed TXQ %d ownership to tid %d\n",
- queue, tid);
-}
-
-static void iwl_mvm_unshare_queue(struct iwl_mvm *mvm, int queue)
-{
- struct ieee80211_sta *sta;
- struct iwl_mvm_sta *mvmsta;
- u8 sta_id;
- int tid = -1;
- unsigned long tid_bitmap;
- unsigned int wdg_timeout;
- int ssn;
- int ret = true;
-
- /* queue sharing is disabled on new TX path */
- if (WARN_ON(iwl_mvm_has_new_tx_api(mvm)))
- return;
-
- lockdep_assert_held(&mvm->mutex);
-
- spin_lock_bh(&mvm->queue_info_lock);
- sta_id = mvm->queue_info[queue].ra_sta_id;
- tid_bitmap = mvm->queue_info[queue].tid_bitmap;
- spin_unlock_bh(&mvm->queue_info_lock);
-
- /* Find TID for queue, and make sure it is the only one on the queue */
- tid = find_first_bit(&tid_bitmap, IWL_MAX_TID_COUNT + 1);
- if (tid_bitmap != BIT(tid)) {
- IWL_ERR(mvm, "Failed to unshare q %d, active tids=0x%lx\n",
- queue, tid_bitmap);
- return;
- }
-
- IWL_DEBUG_TX_QUEUES(mvm, "Unsharing TXQ %d, keeping tid %d\n", queue,
- tid);
-
- sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
- lockdep_is_held(&mvm->mutex));
-
- if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta)))
- return;
-
- mvmsta = iwl_mvm_sta_from_mac80211(sta);
- wdg_timeout = iwl_mvm_get_wd_timeout(mvm, mvmsta->vif, false, false);
-
- ssn = IEEE80211_SEQ_TO_SN(mvmsta->tid_data[tid].seq_number);
-
- ret = iwl_mvm_scd_queue_redirect(mvm, queue, tid,
- tid_to_mac80211_ac[tid], ssn,
- wdg_timeout, true);
- if (ret) {
- IWL_ERR(mvm, "Failed to redirect TXQ %d\n", queue);
- return;
- }
-
- /* If aggs should be turned back on - do it */
- if (mvmsta->tid_data[tid].state == IWL_AGG_ON) {
- struct iwl_mvm_add_sta_cmd cmd = {0};
-
- mvmsta->tid_disable_agg &= ~BIT(tid);
-
- cmd.mac_id_n_color = cpu_to_le32(mvmsta->mac_id_n_color);
- cmd.sta_id = mvmsta->sta_id;
- cmd.add_modify = STA_MODE_MODIFY;
- cmd.modify_mask = STA_MODIFY_TID_DISABLE_TX;
- cmd.tfd_queue_msk = cpu_to_le32(mvmsta->tfd_queue_msk);
- cmd.tid_disable_tx = cpu_to_le16(mvmsta->tid_disable_agg);
-
- ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC,
- iwl_mvm_add_sta_cmd_size(mvm), &cmd);
- if (!ret) {
- IWL_DEBUG_TX_QUEUES(mvm,
- "TXQ #%d is now aggregated again\n",
- queue);
-
- /* Mark queue intenally as aggregating again */
- iwl_trans_txq_set_shared_mode(mvm->trans, queue, false);
- }
- }
-
- spin_lock_bh(&mvm->queue_info_lock);
- mvm->queue_info[queue].status = IWL_MVM_QUEUE_READY;
- spin_unlock_bh(&mvm->queue_info_lock);
-}
-
static inline u8 iwl_mvm_tid_to_ac_queue(int tid)
{
if (tid == IWL_MAX_TID_COUNT)
@@ -1097,47 +1516,12 @@ void iwl_mvm_add_new_dqa_stream_wk(struct work_struct *wk)
struct ieee80211_sta *sta;
struct iwl_mvm_sta *mvmsta;
unsigned long deferred_tid_traffic;
- int queue, sta_id, tid;
-
- /* Check inactivity of queues */
- iwl_mvm_inactivity_check(mvm);
+ int sta_id, tid;
mutex_lock(&mvm->mutex);
- /* No queue reconfiguration in TVQM mode */
- if (iwl_mvm_has_new_tx_api(mvm))
- goto alloc_queues;
-
- /* Reconfigure queues requiring reconfiguation */
- for (queue = 0; queue < ARRAY_SIZE(mvm->queue_info); queue++) {
- bool reconfig;
- bool change_owner;
-
- spin_lock_bh(&mvm->queue_info_lock);
- reconfig = (mvm->queue_info[queue].status ==
- IWL_MVM_QUEUE_RECONFIGURING);
+ iwl_mvm_inactivity_check(mvm, IWL_MVM_INVALID_STA);
- /*
- * We need to take into account a situation in which a TXQ was
- * allocated to TID x, and then turned shared by adding TIDs y
- * and z. If TID x becomes inactive and is removed from the TXQ,
- * ownership must be given to one of the remaining TIDs.
- * This is mainly because if TID x continues - a new queue can't
- * be allocated for it as long as it is an owner of another TXQ.
- */
- change_owner = !(mvm->queue_info[queue].tid_bitmap &
- BIT(mvm->queue_info[queue].txq_tid)) &&
- (mvm->queue_info[queue].status ==
- IWL_MVM_QUEUE_SHARED);
- spin_unlock_bh(&mvm->queue_info_lock);
-
- if (reconfig)
- iwl_mvm_unshare_queue(mvm, queue);
- else if (change_owner)
- iwl_mvm_change_queue_owner(mvm, queue);
- }
-
-alloc_queues:
/* Go over all stations with deferred traffic */
for_each_set_bit(sta_id, mvm->sta_deferred_frames,
IWL_MVM_STATION_COUNT) {
@@ -1164,23 +1548,19 @@ static int iwl_mvm_reserve_sta_stream(struct iwl_mvm *mvm,
{
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
int queue;
- bool using_inactive_queue = false, same_sta = false;
/* queue reserving is disabled on new TX path */
if (WARN_ON(iwl_mvm_has_new_tx_api(mvm)))
return 0;
- /*
- * Check for inactive queues, so we don't reach a situation where we
- * can't add a STA due to a shortage in queues that doesn't really exist
- */
- iwl_mvm_inactivity_check(mvm);
+ /* run the general cleanup/unsharing of queues */
+ iwl_mvm_inactivity_check(mvm, IWL_MVM_INVALID_STA);
spin_lock_bh(&mvm->queue_info_lock);
/* Make sure we have free resources for this STA */
if (vif_type == NL80211_IFTYPE_STATION && !sta->tdls &&
- !mvm->queue_info[IWL_MVM_DQA_BSS_CLIENT_QUEUE].hw_queue_refcount &&
+ !mvm->queue_info[IWL_MVM_DQA_BSS_CLIENT_QUEUE].tid_bitmap &&
(mvm->queue_info[IWL_MVM_DQA_BSS_CLIENT_QUEUE].status ==
IWL_MVM_QUEUE_FREE))
queue = IWL_MVM_DQA_BSS_CLIENT_QUEUE;
@@ -1190,16 +1570,13 @@ static int iwl_mvm_reserve_sta_stream(struct iwl_mvm *mvm,
IWL_MVM_DQA_MAX_DATA_QUEUE);
if (queue < 0) {
spin_unlock_bh(&mvm->queue_info_lock);
- IWL_ERR(mvm, "No available queues for new station\n");
- return -ENOSPC;
- } else if (mvm->queue_info[queue].status == IWL_MVM_QUEUE_INACTIVE) {
- /*
- * If this queue is already allocated but inactive we'll need to
- * first free this queue before enabling it again, we'll mark
- * it as reserved to make sure no new traffic arrives on it
- */
- using_inactive_queue = true;
- same_sta = mvm->queue_info[queue].ra_sta_id == mvmsta->sta_id;
+ /* try again - this time kick out a queue if needed */
+ queue = iwl_mvm_inactivity_check(mvm, mvmsta->sta_id);
+ if (queue < 0) {
+ IWL_ERR(mvm, "No available queues for new station\n");
+ return -ENOSPC;
+ }
+ spin_lock_bh(&mvm->queue_info_lock);
}
mvm->queue_info[queue].status = IWL_MVM_QUEUE_RESERVED;
@@ -1207,9 +1584,6 @@ static int iwl_mvm_reserve_sta_stream(struct iwl_mvm *mvm,
mvmsta->reserved_queue = queue;
- if (using_inactive_queue)
- iwl_mvm_free_inactive_queue(mvm, queue, same_sta);
-
IWL_DEBUG_TX_QUEUES(mvm, "Reserving data queue #%d for sta_id %d\n",
queue, mvmsta->sta_id);
@@ -2101,6 +2475,19 @@ int iwl_mvm_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
iwl_mvm_enable_txq(mvm, vif->cab_queue, vif->cab_queue, 0,
&cfg, timeout);
+ if (mvmvif->ap_wep_key) {
+ u8 key_offset = iwl_mvm_set_fw_key_idx(mvm);
+
+ if (key_offset == STA_KEY_IDX_INVALID)
+ return -ENOSPC;
+
+ ret = iwl_mvm_send_sta_key(mvm, mvmvif->mcast_sta.sta_id,
+ mvmvif->ap_wep_key, 1, 0, NULL, 0,
+ key_offset, 0);
+ if (ret)
+ return ret;
+ }
+
return 0;
}
@@ -3133,10 +3520,6 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
switch (keyconf->cipher) {
case WLAN_CIPHER_SUITE_TKIP:
- if (vif->type == NL80211_IFTYPE_AP) {
- ret = -EINVAL;
- break;
- }
addr = iwl_mvm_get_mac_addr(mvm, vif, sta);
/* get phase 1 key from mac80211 */
ieee80211_get_key_rx_seq(keyconf, 0, &seq);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
index 0fc211108149..de1a0a2d8723 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
@@ -312,9 +312,6 @@ enum iwl_mvm_agg_state {
* Basically when next_reclaimed reaches ssn, we can tell mac80211 that
* we are ready to finish the Tx AGG stop / start flow.
* @tx_time: medium time consumed by this A-MPDU
- * @is_tid_active: has this TID sent traffic in the last
- * %IWL_MVM_DQA_QUEUE_TIMEOUT time period. If %txq_id is invalid, this
- * field should be ignored.
* @tpt_meas_start: time of the throughput measurements start, is reset every HZ
* @tx_count_last: number of frames transmitted during the last second
* @tx_count: counts the number of frames transmitted since the last reset of
@@ -332,7 +329,6 @@ struct iwl_mvm_tid_data {
u16 txq_id;
u16 ssn;
u16 tx_time;
- bool is_tid_active;
unsigned long tpt_meas_start;
u32 tx_count_last;
u32 tx_count;
@@ -572,8 +568,4 @@ void iwl_mvm_modify_all_sta_disable_tx(struct iwl_mvm *mvm,
void iwl_mvm_csa_client_absent(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
void iwl_mvm_add_new_dqa_stream_wk(struct work_struct *wk);
-int iwl_mvm_scd_queue_redirect(struct iwl_mvm *mvm, int queue, int tid,
- int ac, int ssn, unsigned int wdg_timeout,
- bool force);
-
#endif /* __sta_h__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c b/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c
index 67f360c0d17e..e02f4eb20359 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c
@@ -18,9 +18,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program.
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/testmode.h b/drivers/net/wireless/intel/iwlwifi/mvm/testmode.h
index cbbc16fd006a..ff82af11de8d 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/testmode.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/testmode.h
@@ -17,11 +17,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
index cd91bc44259c..e1a6f4e22253 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
@@ -254,17 +254,14 @@ static void iwl_mvm_te_check_trigger(struct iwl_mvm *mvm,
struct iwl_fw_dbg_trigger_time_event *te_trig;
int i;
- if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_TIME_EVENT))
+ trig = iwl_fw_dbg_trigger_on(&mvm->fwrt,
+ ieee80211_vif_to_wdev(te_data->vif),
+ FW_DBG_TRIGGER_TIME_EVENT);
+ if (!trig)
return;
- trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_TIME_EVENT);
te_trig = (void *)trig->data;
- if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt,
- ieee80211_vif_to_wdev(te_data->vif),
- trig))
- return;
-
for (i = 0; i < ARRAY_SIZE(te_trig->time_events); i++) {
u32 trig_te_id = le32_to_cpu(te_trig->time_events[i].id);
u32 trig_action_bitmap =
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h
index 3d2e8b6159bb..1dd3d01245ea 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h
@@ -17,11 +17,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tof.c b/drivers/net/wireless/intel/iwlwifi/mvm/tof.c
index 2d0b8a391308..01e0a999063b 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tof.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tof.c
@@ -16,11 +16,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tof.h b/drivers/net/wireless/intel/iwlwifi/mvm/tof.h
index 2ff560aa1a82..8138d0606c52 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tof.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tof.h
@@ -16,11 +16,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c
index 1232f63278eb..0b3e5c99d316 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c
@@ -18,11 +18,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
index ff193dca2020..ec57682efe54 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
@@ -8,6 +8,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -18,11 +19,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
@@ -35,6 +31,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -82,15 +79,12 @@ iwl_mvm_bar_check_trigger(struct iwl_mvm *mvm, const u8 *addr,
struct iwl_fw_dbg_trigger_tlv *trig;
struct iwl_fw_dbg_trigger_ba *ba_trig;
- if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_BA))
+ trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, NULL, FW_DBG_TRIGGER_BA);
+ if (!trig)
return;
- trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_BA);
ba_trig = (void *)trig->data;
- if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, NULL, trig))
- return;
-
if (!(le16_to_cpu(ba_trig->tx_bar) & BIT(tid)))
return;
@@ -245,14 +239,18 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,
iwl_mvm_bar_check_trigger(mvm, bar->ra, tx_cmd->tid_tspec,
ssn);
} else {
- tx_cmd->tid_tspec = IWL_TID_NON_QOS;
+ if (ieee80211_is_data(fc))
+ tx_cmd->tid_tspec = IWL_TID_NON_QOS;
+ else
+ tx_cmd->tid_tspec = IWL_MAX_TID_COUNT;
+
if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
tx_flags |= TX_CMD_FLG_SEQ_CTL;
else
tx_flags &= ~TX_CMD_FLG_SEQ_CTL;
}
- /* Default to 0 (BE) when tid_spec is set to IWL_TID_NON_QOS */
+ /* Default to 0 (BE) when tid_spec is set to IWL_MAX_TID_COUNT */
if (tx_cmd->tid_tspec < IWL_MAX_TID_COUNT)
ac = tid_to_mac80211_ac[tx_cmd->tid_tspec];
else
@@ -620,6 +618,66 @@ static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm,
}
}
+static void iwl_mvm_probe_resp_set_noa(struct iwl_mvm *mvm,
+ struct sk_buff *skb)
+{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct iwl_mvm_vif *mvmvif =
+ iwl_mvm_vif_from_mac80211(info->control.vif);
+ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
+ int base_len = (u8 *)mgmt->u.probe_resp.variable - (u8 *)mgmt;
+ struct iwl_probe_resp_data *resp_data;
+ u8 *ie, *pos;
+ u8 match[] = {
+ (WLAN_OUI_WFA >> 16) & 0xff,
+ (WLAN_OUI_WFA >> 8) & 0xff,
+ WLAN_OUI_WFA & 0xff,
+ WLAN_OUI_TYPE_WFA_P2P,
+ };
+
+ rcu_read_lock();
+
+ resp_data = rcu_dereference(mvmvif->probe_resp_data);
+ if (!resp_data)
+ goto out;
+
+ if (!resp_data->notif.noa_active)
+ goto out;
+
+ ie = (u8 *)cfg80211_find_ie_match(WLAN_EID_VENDOR_SPECIFIC,
+ mgmt->u.probe_resp.variable,
+ skb->len - base_len,
+ match, 4, 2);
+ if (!ie) {
+ IWL_DEBUG_TX(mvm, "probe resp doesn't have P2P IE\n");
+ goto out;
+ }
+
+ if (skb_tailroom(skb) < resp_data->noa_len) {
+ if (pskb_expand_head(skb, 0, resp_data->noa_len, GFP_ATOMIC)) {
+ IWL_ERR(mvm,
+ "Failed to reallocate probe resp\n");
+ goto out;
+ }
+ }
+
+ pos = skb_put(skb, resp_data->noa_len);
+
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ /* Set length of IE body (not including ID and length itself) */
+ *pos++ = resp_data->noa_len - 2;
+ *pos++ = (WLAN_OUI_WFA >> 16) & 0xff;
+ *pos++ = (WLAN_OUI_WFA >> 8) & 0xff;
+ *pos++ = WLAN_OUI_WFA & 0xff;
+ *pos++ = WLAN_OUI_TYPE_WFA_P2P;
+
+ memcpy(pos, &resp_data->notif.noa_attr,
+ resp_data->noa_len - sizeof(struct ieee80211_vendor_ie));
+
+out:
+ rcu_read_unlock();
+}
+
int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
@@ -628,6 +686,7 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
struct iwl_device_cmd *dev_cmd;
u8 sta_id;
int hdrlen = ieee80211_hdrlen(hdr->frame_control);
+ __le16 fc = hdr->frame_control;
int queue;
/* IWL_MVM_OFFCHANNEL_QUEUE is used for ROC packets that can be used
@@ -668,7 +727,7 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
if (info.control.vif->type == NL80211_IFTYPE_P2P_DEVICE ||
info.control.vif->type == NL80211_IFTYPE_AP ||
info.control.vif->type == NL80211_IFTYPE_ADHOC) {
- if (info.control.vif->type == NL80211_IFTYPE_P2P_DEVICE)
+ if (!ieee80211_is_data(hdr->frame_control))
sta_id = mvmvif->bcast_sta.sta_id;
else
sta_id = mvmvif->mcast_sta.sta_id;
@@ -689,6 +748,9 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
}
}
+ if (unlikely(ieee80211_is_probe_resp(fc)))
+ iwl_mvm_probe_resp_set_noa(mvm, skb);
+
IWL_DEBUG_TX(mvm, "station Id %d, queue=%d\n", sta_id, queue);
dev_cmd = iwl_mvm_set_tx_params(mvm, skb, &info, hdrlen, NULL, sta_id);
@@ -775,6 +837,36 @@ iwl_mvm_tx_tso_segment(struct sk_buff *skb, unsigned int num_subframes,
return 0;
}
+static unsigned int iwl_mvm_max_amsdu_size(struct iwl_mvm *mvm,
+ struct ieee80211_sta *sta,
+ unsigned int tid)
+{
+ struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+ enum nl80211_band band = mvmsta->vif->bss_conf.chandef.chan->band;
+ u8 ac = tid_to_mac80211_ac[tid];
+ unsigned int txf;
+ int lmac = IWL_LMAC_24G_INDEX;
+
+ if (iwl_mvm_is_cdb_supported(mvm) &&
+ band == NL80211_BAND_5GHZ)
+ lmac = IWL_LMAC_5G_INDEX;
+
+ /* For HE redirect to trigger based fifos */
+ if (sta->he_cap.has_he && !WARN_ON(!iwl_mvm_has_new_tx_api(mvm)))
+ ac += 4;
+
+ txf = iwl_mvm_mac_ac_to_tx_fifo(mvm, ac);
+
+ /*
+ * Don't send an AMSDU that will be longer than the TXF.
+ * Add a security margin of 256 for the TX command + headers.
+ * We also want to have the start of the next packet inside the
+ * fifo to be able to send bursts.
+ */
+ return min_t(unsigned int, mvmsta->max_amsdu_len,
+ mvm->fwrt.smem_cfg.lmac[lmac].txfifo_size[txf] - 256);
+}
+
static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
struct ieee80211_tx_info *info,
struct ieee80211_sta *sta,
@@ -787,7 +879,7 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
u16 snap_ip_tcp, pad;
unsigned int dbg_max_amsdu_len;
netdev_features_t netdev_flags = NETIF_F_CSUM_MASK | NETIF_F_SG;
- u8 tid, txf;
+ u8 tid;
snap_ip_tcp = 8 + skb_transport_header(skb) - skb_network_header(skb) +
tcp_hdrlen(skb);
@@ -826,20 +918,7 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
!(mvmsta->amsdu_enabled & BIT(tid)))
return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb);
- max_amsdu_len = mvmsta->max_amsdu_len;
-
- /* the Tx FIFO to which this A-MSDU will be routed */
- txf = iwl_mvm_mac_ac_to_tx_fifo(mvm, tid_to_mac80211_ac[tid]);
-
- /*
- * Don't send an AMSDU that will be longer than the TXF.
- * Add a security margin of 256 for the TX command + headers.
- * We also want to have the start of the next packet inside the
- * fifo to be able to send bursts.
- */
- max_amsdu_len = min_t(unsigned int, max_amsdu_len,
- mvm->fwrt.smem_cfg.lmac[0].txfifo_size[txf] -
- 256);
+ max_amsdu_len = iwl_mvm_max_amsdu_size(mvm, sta, tid);
if (unlikely(dbg_max_amsdu_len))
max_amsdu_len = min_t(unsigned int, max_amsdu_len,
@@ -1010,6 +1089,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_probe_resp(fc)))
+ iwl_mvm_probe_resp_set_noa(mvm, skb);
+
dev_cmd = iwl_mvm_set_tx_params(mvm, skb, info, hdrlen,
sta, mvmsta->sta_id);
if (!dev_cmd)
@@ -1049,6 +1131,8 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
/* update the tx_cmd hdr as it was already copied */
tx_cmd->hdr->seq_ctrl = hdr->seq_ctrl;
}
+ } else if (ieee80211_is_data(fc) && !ieee80211_is_data_qos(fc)) {
+ tid = IWL_TID_NON_QOS;
}
txq_id = mvmsta->tid_data[tid].txq_id;
@@ -1056,32 +1140,16 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM);
/* Check if TXQ needs to be allocated or re-activated */
- if (unlikely(txq_id == IWL_MVM_INVALID_QUEUE ||
- !mvmsta->tid_data[tid].is_tid_active)) {
- /* If TXQ needs to be allocated... */
- if (txq_id == IWL_MVM_INVALID_QUEUE) {
- iwl_mvm_tx_add_stream(mvm, mvmsta, tid, skb);
-
- /*
- * The frame is now deferred, and the worker scheduled
- * will re-allocate it, so we can free it for now.
- */
- iwl_trans_free_tx_cmd(mvm->trans, dev_cmd);
- spin_unlock(&mvmsta->lock);
- return 0;
- }
-
- /* queue should always be active in new TX path */
- WARN_ON(iwl_mvm_has_new_tx_api(mvm));
-
- /* If we are here - TXQ exists and needs to be re-activated */
- spin_lock(&mvm->queue_info_lock);
- mvm->queue_info[txq_id].status = IWL_MVM_QUEUE_READY;
- mvmsta->tid_data[tid].is_tid_active = true;
- spin_unlock(&mvm->queue_info_lock);
+ if (unlikely(txq_id == IWL_MVM_INVALID_QUEUE)) {
+ iwl_mvm_tx_add_stream(mvm, mvmsta, tid, skb);
- IWL_DEBUG_TX_QUEUES(mvm, "Re-activating queue %d for TX\n",
- txq_id);
+ /*
+ * The frame is now deferred, and the worker scheduled
+ * will re-allocate it, so we can free it for now.
+ */
+ iwl_trans_free_tx_cmd(mvm->trans, dev_cmd);
+ spin_unlock(&mvmsta->lock);
+ return 0;
}
if (!iwl_mvm_has_new_tx_api(mvm)) {
@@ -1327,15 +1395,13 @@ static void iwl_mvm_tx_status_check_trigger(struct iwl_mvm *mvm,
struct iwl_fw_dbg_trigger_tx_status *status_trig;
int i;
- if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_TX_STATUS))
+ trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, NULL,
+ FW_DBG_TRIGGER_TX_STATUS);
+ if (!trig)
return;
- trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_TX_STATUS);
status_trig = (void *)trig->data;
- if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, NULL, trig))
- return;
-
for (i = 0; i < ARRAY_SIZE(status_trig->statuses); i++) {
/* don't collect on status 0 */
if (!status_trig->statuses[i].status)
@@ -1405,6 +1471,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
while (!skb_queue_empty(&skbs)) {
struct sk_buff *skb = __skb_dequeue(&skbs);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_hdr *hdr = (void *)skb->data;
bool flushed = false;
skb_freed++;
@@ -1434,6 +1501,14 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
break;
}
+ /*
+ * If we are freeing multiple frames, mark all the frames
+ * but the first one as acked, since they were acknowledged
+ * before
+ * */
+ if (skb_freed > 1)
+ info->flags |= IEEE80211_TX_STAT_ACK;
+
iwl_mvm_tx_status_check_trigger(mvm, status);
info->status.rates[0].count = tx_resp->failure_frame + 1;
@@ -1449,11 +1524,11 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
info->flags &= ~IEEE80211_TX_CTL_AMPDU;
- /* W/A FW bug: seq_ctl is wrong when the status isn't success */
- if (status != TX_STATUS_SUCCESS) {
- struct ieee80211_hdr *hdr = (void *)skb->data;
+ /* W/A FW bug: seq_ctl is wrong upon failure / BAR frame */
+ if (ieee80211_is_back_req(hdr->frame_control))
+ seq_ctl = 0;
+ else if (status != TX_STATUS_SUCCESS)
seq_ctl = le16_to_cpu(hdr->seq_ctrl);
- }
if (unlikely(!seq_ctl)) {
struct ieee80211_hdr *hdr = (void *)skb->data;
@@ -1525,7 +1600,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
iwl_mvm_tx_airtime(mvm, mvmsta,
le16_to_cpu(tx_resp->wireless_media_time));
- if (tid != IWL_TID_NON_QOS && tid != IWL_MGMT_TID) {
+ if (sta->wme && tid != IWL_MGMT_TID) {
struct iwl_mvm_tid_data *tid_data =
&mvmsta->tid_data[tid];
bool send_eosp_ndp = false;
@@ -1645,20 +1720,24 @@ static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm,
u16 sequence = le16_to_cpu(pkt->hdr.sequence);
struct iwl_mvm_sta *mvmsta;
int queue = SEQ_TO_QUEUE(sequence);
+ struct ieee80211_sta *sta;
if (WARN_ON_ONCE(queue < IWL_MVM_DQA_MIN_DATA_QUEUE &&
(queue != IWL_MVM_DQA_BSS_CLIENT_QUEUE)))
return;
- if (WARN_ON_ONCE(tid == IWL_TID_NON_QOS))
- return;
-
iwl_mvm_rx_tx_cmd_agg_dbg(mvm, pkt);
rcu_read_lock();
mvmsta = iwl_mvm_sta_from_staid_rcu(mvm, sta_id);
+ sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
+ if (WARN_ON_ONCE(!sta || !sta->wme)) {
+ rcu_read_unlock();
+ return;
+ }
+
if (!WARN_ON_ONCE(!mvmsta)) {
mvmsta->tid_data[tid].rate_n_flags =
le32_to_cpu(tx_resp->initial_rate);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
index b002a7afb5f5..818e1180bbdd 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
@@ -19,11 +19,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
@@ -551,7 +546,6 @@ static void iwl_mvm_dump_lmac_error_log(struct iwl_mvm *mvm, u32 base)
IWL_ERR(mvm, "Loaded firmware version: %s\n", mvm->fw->fw_version);
- trace_iwlwifi_dev_ucode_error(trans->dev, &table, table.hw_ver, table.brd_ver);
IWL_ERR(mvm, "0x%08X | %-28s\n", table.error_id,
desc_lookup(table.error_id));
IWL_ERR(mvm, "0x%08X | trm_hw_status0\n", table.trm_hw_status0);
@@ -605,36 +599,6 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
iwl_mvm_dump_umac_error_log(mvm);
}
-int iwl_mvm_find_free_queue(struct iwl_mvm *mvm, u8 sta_id, u8 minq, u8 maxq)
-{
- int i;
-
- lockdep_assert_held(&mvm->queue_info_lock);
-
- /* This should not be hit with new TX path */
- if (WARN_ON(iwl_mvm_has_new_tx_api(mvm)))
- return -ENOSPC;
-
- /* Start by looking for a free queue */
- for (i = minq; i <= maxq; i++)
- if (mvm->queue_info[i].hw_queue_refcount == 0 &&
- mvm->queue_info[i].status == IWL_MVM_QUEUE_FREE)
- return i;
-
- /*
- * If no free queue found - settle for an inactive one to reconfigure
- * Make sure that the inactive queue either already belongs to this STA,
- * or that if it belongs to another one - it isn't the reserved queue
- */
- for (i = minq; i <= maxq; i++)
- if (mvm->queue_info[i].status == IWL_MVM_QUEUE_INACTIVE &&
- (sta_id == mvm->queue_info[i].ra_sta_id ||
- !mvm->queue_info[i].reserved))
- return i;
-
- return -ENOSPC;
-}
-
int iwl_mvm_reconfig_scd(struct iwl_mvm *mvm, int queue, int fifo, int sta_id,
int tid, int frame_limit, u16 ssn)
{
@@ -655,7 +619,7 @@ int iwl_mvm_reconfig_scd(struct iwl_mvm *mvm, int queue, int fifo, int sta_id,
return -EINVAL;
spin_lock_bh(&mvm->queue_info_lock);
- if (WARN(mvm->queue_info[queue].hw_queue_refcount == 0,
+ if (WARN(mvm->queue_info[queue].tid_bitmap == 0,
"Trying to reconfig unallocated queue %d\n", queue)) {
spin_unlock_bh(&mvm->queue_info_lock);
return -ENXIO;
@@ -671,249 +635,21 @@ int iwl_mvm_reconfig_scd(struct iwl_mvm *mvm, int queue, int fifo, int sta_id,
return ret;
}
-static bool iwl_mvm_update_txq_mapping(struct iwl_mvm *mvm, int queue,
- int mac80211_queue, u8 sta_id, u8 tid)
-{
- bool enable_queue = true;
-
- spin_lock_bh(&mvm->queue_info_lock);
-
- /* Make sure this TID isn't already enabled */
- if (mvm->queue_info[queue].tid_bitmap & BIT(tid)) {
- spin_unlock_bh(&mvm->queue_info_lock);
- IWL_ERR(mvm, "Trying to enable TXQ %d with existing TID %d\n",
- queue, tid);
- return false;
- }
-
- /* Update mappings and refcounts */
- if (mvm->queue_info[queue].hw_queue_refcount > 0)
- enable_queue = false;
-
- if (mac80211_queue != IEEE80211_INVAL_HW_QUEUE) {
- WARN(mac80211_queue >=
- BITS_PER_BYTE * sizeof(mvm->hw_queue_to_mac80211[0]),
- "cannot track mac80211 queue %d (queue %d, sta %d, tid %d)\n",
- mac80211_queue, queue, sta_id, tid);
- mvm->hw_queue_to_mac80211[queue] |= BIT(mac80211_queue);
- }
-
- mvm->queue_info[queue].hw_queue_refcount++;
- mvm->queue_info[queue].tid_bitmap |= BIT(tid);
- mvm->queue_info[queue].ra_sta_id = sta_id;
-
- if (enable_queue) {
- if (tid != IWL_MAX_TID_COUNT)
- mvm->queue_info[queue].mac80211_ac =
- tid_to_mac80211_ac[tid];
- else
- mvm->queue_info[queue].mac80211_ac = IEEE80211_AC_VO;
-
- mvm->queue_info[queue].txq_tid = tid;
- }
-
- IWL_DEBUG_TX_QUEUES(mvm,
- "Enabling TXQ #%d refcount=%d (mac80211 map:0x%x)\n",
- queue, mvm->queue_info[queue].hw_queue_refcount,
- mvm->hw_queue_to_mac80211[queue]);
-
- spin_unlock_bh(&mvm->queue_info_lock);
-
- return enable_queue;
-}
-
-int iwl_mvm_tvqm_enable_txq(struct iwl_mvm *mvm, int mac80211_queue,
- u8 sta_id, u8 tid, unsigned int timeout)
-{
- struct iwl_tx_queue_cfg_cmd cmd = {
- .flags = cpu_to_le16(TX_QUEUE_CFG_ENABLE_QUEUE),
- .sta_id = sta_id,
- .tid = tid,
- };
- int queue, size = IWL_DEFAULT_QUEUE_SIZE;
-
- if (cmd.tid == IWL_MAX_TID_COUNT) {
- cmd.tid = IWL_MGMT_TID;
- size = IWL_MGMT_QUEUE_SIZE;
- }
- queue = iwl_trans_txq_alloc(mvm->trans, (void *)&cmd,
- SCD_QUEUE_CFG, size, timeout);
-
- if (queue < 0) {
- IWL_DEBUG_TX_QUEUES(mvm,
- "Failed allocating TXQ for sta %d tid %d, ret: %d\n",
- sta_id, tid, queue);
- return queue;
- }
-
- IWL_DEBUG_TX_QUEUES(mvm, "Enabling TXQ #%d for sta %d tid %d\n",
- queue, sta_id, tid);
-
- mvm->hw_queue_to_mac80211[queue] |= BIT(mac80211_queue);
- IWL_DEBUG_TX_QUEUES(mvm,
- "Enabling TXQ #%d (mac80211 map:0x%x)\n",
- queue, mvm->hw_queue_to_mac80211[queue]);
-
- return queue;
-}
-
-bool iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
- u16 ssn, const struct iwl_trans_txq_scd_cfg *cfg,
- unsigned int wdg_timeout)
-{
- struct iwl_scd_txq_cfg_cmd cmd = {
- .scd_queue = queue,
- .action = SCD_CFG_ENABLE_QUEUE,
- .window = cfg->frame_limit,
- .sta_id = cfg->sta_id,
- .ssn = cpu_to_le16(ssn),
- .tx_fifo = cfg->fifo,
- .aggregate = cfg->aggregate,
- .tid = cfg->tid,
- };
- bool inc_ssn;
-
- if (WARN_ON(iwl_mvm_has_new_tx_api(mvm)))
- return false;
-
- /* Send the enabling command if we need to */
- if (!iwl_mvm_update_txq_mapping(mvm, queue, mac80211_queue,
- cfg->sta_id, cfg->tid))
- return false;
-
- inc_ssn = iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn,
- NULL, wdg_timeout);
- if (inc_ssn)
- le16_add_cpu(&cmd.ssn, 1);
-
- WARN(iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, sizeof(cmd), &cmd),
- "Failed to configure queue %d on FIFO %d\n", queue, cfg->fifo);
-
- return inc_ssn;
-}
-
-int iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
- u8 tid, u8 flags)
-{
- struct iwl_scd_txq_cfg_cmd cmd = {
- .scd_queue = queue,
- .action = SCD_CFG_DISABLE_QUEUE,
- };
- bool remove_mac_queue = mac80211_queue != IEEE80211_INVAL_HW_QUEUE;
- int ret;
-
- if (WARN_ON(remove_mac_queue && mac80211_queue >= IEEE80211_MAX_QUEUES))
- return -EINVAL;
-
- if (iwl_mvm_has_new_tx_api(mvm)) {
- spin_lock_bh(&mvm->queue_info_lock);
-
- if (remove_mac_queue)
- mvm->hw_queue_to_mac80211[queue] &=
- ~BIT(mac80211_queue);
-
- spin_unlock_bh(&mvm->queue_info_lock);
-
- iwl_trans_txq_free(mvm->trans, queue);
-
- return 0;
- }
-
- spin_lock_bh(&mvm->queue_info_lock);
-
- if (WARN_ON(mvm->queue_info[queue].hw_queue_refcount == 0)) {
- spin_unlock_bh(&mvm->queue_info_lock);
- return 0;
- }
-
- mvm->queue_info[queue].tid_bitmap &= ~BIT(tid);
-
- /*
- * If there is another TID with the same AC - don't remove the MAC queue
- * from the mapping
- */
- if (tid < IWL_MAX_TID_COUNT) {
- unsigned long tid_bitmap =
- mvm->queue_info[queue].tid_bitmap;
- int ac = tid_to_mac80211_ac[tid];
- int i;
-
- for_each_set_bit(i, &tid_bitmap, IWL_MAX_TID_COUNT) {
- if (tid_to_mac80211_ac[i] == ac)
- remove_mac_queue = false;
- }
- }
-
- if (remove_mac_queue)
- mvm->hw_queue_to_mac80211[queue] &=
- ~BIT(mac80211_queue);
- mvm->queue_info[queue].hw_queue_refcount--;
-
- cmd.action = mvm->queue_info[queue].hw_queue_refcount ?
- SCD_CFG_ENABLE_QUEUE : SCD_CFG_DISABLE_QUEUE;
- if (cmd.action == SCD_CFG_DISABLE_QUEUE)
- mvm->queue_info[queue].status = IWL_MVM_QUEUE_FREE;
-
- IWL_DEBUG_TX_QUEUES(mvm,
- "Disabling TXQ #%d refcount=%d (mac80211 map:0x%x)\n",
- queue,
- mvm->queue_info[queue].hw_queue_refcount,
- mvm->hw_queue_to_mac80211[queue]);
-
- /* If the queue is still enabled - nothing left to do in this func */
- if (cmd.action == SCD_CFG_ENABLE_QUEUE) {
- spin_unlock_bh(&mvm->queue_info_lock);
- return 0;
- }
-
- cmd.sta_id = mvm->queue_info[queue].ra_sta_id;
- cmd.tid = mvm->queue_info[queue].txq_tid;
-
- /* Make sure queue info is correct even though we overwrite it */
- WARN(mvm->queue_info[queue].hw_queue_refcount ||
- mvm->queue_info[queue].tid_bitmap ||
- mvm->hw_queue_to_mac80211[queue],
- "TXQ #%d info out-of-sync - refcount=%d, mac map=0x%x, tid=0x%x\n",
- queue, mvm->queue_info[queue].hw_queue_refcount,
- mvm->hw_queue_to_mac80211[queue],
- mvm->queue_info[queue].tid_bitmap);
-
- /* If we are here - the queue is freed and we can zero out these vals */
- mvm->queue_info[queue].hw_queue_refcount = 0;
- mvm->queue_info[queue].tid_bitmap = 0;
- mvm->hw_queue_to_mac80211[queue] = 0;
-
- /* Regardless if this is a reserved TXQ for a STA - mark it as false */
- mvm->queue_info[queue].reserved = false;
-
- spin_unlock_bh(&mvm->queue_info_lock);
-
- iwl_trans_txq_disable(mvm->trans, queue, false);
- ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, flags,
- sizeof(struct iwl_scd_txq_cfg_cmd), &cmd);
-
- if (ret)
- IWL_ERR(mvm, "Failed to disable queue %d (ret=%d)\n",
- queue, ret);
- return ret;
-}
-
/**
* iwl_mvm_send_lq_cmd() - Send link quality command
- * @init: This command is sent as part of station initialization right
- * after station has been added.
+ * @sync: This command can be sent synchronously.
*
* The link quality command is sent as the last step of station creation.
* This is the special case in which init is set and we call a callback in
* this case to clear the state indicating that station creation is in
* progress.
*/
-int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool init)
+int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool sync)
{
struct iwl_host_cmd cmd = {
.id = LQ_CMD,
.len = { sizeof(struct iwl_lq_cmd), },
- .flags = init ? 0 : CMD_ASYNC,
+ .flags = sync ? 0 : CMD_ASYNC,
.data = { lq, },
};
@@ -1249,14 +985,12 @@ void iwl_mvm_connection_loss(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct iwl_fw_dbg_trigger_tlv *trig;
struct iwl_fw_dbg_trigger_mlme *trig_mlme;
- if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_MLME))
+ trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, ieee80211_vif_to_wdev(vif),
+ FW_DBG_TRIGGER_MLME);
+ if (!trig)
goto out;
- trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_MLME);
trig_mlme = (void *)trig->data;
- if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt,
- ieee80211_vif_to_wdev(vif), trig))
- goto out;
if (trig_mlme->stop_connection_loss &&
--trig_mlme->stop_connection_loss)
@@ -1268,171 +1002,6 @@ out:
ieee80211_connection_loss(vif);
}
-/*
- * Remove inactive TIDs of a given queue.
- * If all queue TIDs are inactive - mark the queue as inactive
- * If only some the queue TIDs are inactive - unmap them from the queue
- */
-static void iwl_mvm_remove_inactive_tids(struct iwl_mvm *mvm,
- struct iwl_mvm_sta *mvmsta, int queue,
- unsigned long tid_bitmap)
-{
- int tid;
-
- lockdep_assert_held(&mvmsta->lock);
- lockdep_assert_held(&mvm->queue_info_lock);
-
- if (WARN_ON(iwl_mvm_has_new_tx_api(mvm)))
- return;
-
- /* Go over all non-active TIDs, incl. IWL_MAX_TID_COUNT (for mgmt) */
- for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) {
- /* If some TFDs are still queued - don't mark TID as inactive */
- if (iwl_mvm_tid_queued(mvm, &mvmsta->tid_data[tid]))
- tid_bitmap &= ~BIT(tid);
-
- /* Don't mark as inactive any TID that has an active BA */
- if (mvmsta->tid_data[tid].state != IWL_AGG_OFF)
- tid_bitmap &= ~BIT(tid);
- }
-
- /* If all TIDs in the queue are inactive - mark queue as inactive. */
- if (tid_bitmap == mvm->queue_info[queue].tid_bitmap) {
- mvm->queue_info[queue].status = IWL_MVM_QUEUE_INACTIVE;
-
- for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1)
- mvmsta->tid_data[tid].is_tid_active = false;
-
- IWL_DEBUG_TX_QUEUES(mvm, "Queue %d marked as inactive\n",
- queue);
- return;
- }
-
- /*
- * If we are here, this is a shared queue and not all TIDs timed-out.
- * Remove the ones that did.
- */
- for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) {
- int mac_queue = mvmsta->vif->hw_queue[tid_to_mac80211_ac[tid]];
-
- mvmsta->tid_data[tid].txq_id = IWL_MVM_INVALID_QUEUE;
- mvm->hw_queue_to_mac80211[queue] &= ~BIT(mac_queue);
- mvm->queue_info[queue].hw_queue_refcount--;
- mvm->queue_info[queue].tid_bitmap &= ~BIT(tid);
- mvmsta->tid_data[tid].is_tid_active = false;
-
- IWL_DEBUG_TX_QUEUES(mvm,
- "Removing inactive TID %d from shared Q:%d\n",
- tid, queue);
- }
-
- IWL_DEBUG_TX_QUEUES(mvm,
- "TXQ #%d left with tid bitmap 0x%x\n", queue,
- mvm->queue_info[queue].tid_bitmap);
-
- /*
- * There may be different TIDs with the same mac queues, so make
- * sure all TIDs have existing corresponding mac queues enabled
- */
- tid_bitmap = mvm->queue_info[queue].tid_bitmap;
- for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) {
- mvm->hw_queue_to_mac80211[queue] |=
- BIT(mvmsta->vif->hw_queue[tid_to_mac80211_ac[tid]]);
- }
-
- /* If the queue is marked as shared - "unshare" it */
- if (mvm->queue_info[queue].hw_queue_refcount == 1 &&
- mvm->queue_info[queue].status == IWL_MVM_QUEUE_SHARED) {
- mvm->queue_info[queue].status = IWL_MVM_QUEUE_RECONFIGURING;
- IWL_DEBUG_TX_QUEUES(mvm, "Marking Q:%d for reconfig\n",
- queue);
- }
-}
-
-void iwl_mvm_inactivity_check(struct iwl_mvm *mvm)
-{
- unsigned long timeout_queues_map = 0;
- unsigned long now = jiffies;
- int i;
-
- if (iwl_mvm_has_new_tx_api(mvm))
- return;
-
- spin_lock_bh(&mvm->queue_info_lock);
- for (i = 0; i < IWL_MAX_HW_QUEUES; i++)
- if (mvm->queue_info[i].hw_queue_refcount > 0)
- timeout_queues_map |= BIT(i);
- spin_unlock_bh(&mvm->queue_info_lock);
-
- rcu_read_lock();
-
- /*
- * If a queue time outs - mark it as INACTIVE (don't remove right away
- * if we don't have to.) This is an optimization in case traffic comes
- * later, and we don't HAVE to use a currently-inactive queue
- */
- for_each_set_bit(i, &timeout_queues_map, IWL_MAX_HW_QUEUES) {
- struct ieee80211_sta *sta;
- struct iwl_mvm_sta *mvmsta;
- u8 sta_id;
- int tid;
- unsigned long inactive_tid_bitmap = 0;
- unsigned long queue_tid_bitmap;
-
- spin_lock_bh(&mvm->queue_info_lock);
- queue_tid_bitmap = mvm->queue_info[i].tid_bitmap;
-
- /* If TXQ isn't in active use anyway - nothing to do here... */
- if (mvm->queue_info[i].status != IWL_MVM_QUEUE_READY &&
- mvm->queue_info[i].status != IWL_MVM_QUEUE_SHARED) {
- spin_unlock_bh(&mvm->queue_info_lock);
- continue;
- }
-
- /* Check to see if there are inactive TIDs on this queue */
- for_each_set_bit(tid, &queue_tid_bitmap,
- IWL_MAX_TID_COUNT + 1) {
- if (time_after(mvm->queue_info[i].last_frame_time[tid] +
- IWL_MVM_DQA_QUEUE_TIMEOUT, now))
- continue;
-
- inactive_tid_bitmap |= BIT(tid);
- }
- spin_unlock_bh(&mvm->queue_info_lock);
-
- /* If all TIDs are active - finish check on this queue */
- if (!inactive_tid_bitmap)
- continue;
-
- /*
- * If we are here - the queue hadn't been served recently and is
- * in use
- */
-
- sta_id = mvm->queue_info[i].ra_sta_id;
- sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
-
- /*
- * If the STA doesn't exist anymore, it isn't an error. It could
- * be that it was removed since getting the queues, and in this
- * case it should've inactivated its queues anyway.
- */
- if (IS_ERR_OR_NULL(sta))
- continue;
-
- mvmsta = iwl_mvm_sta_from_mac80211(sta);
-
- spin_lock_bh(&mvmsta->lock);
- spin_lock(&mvm->queue_info_lock);
- iwl_mvm_remove_inactive_tids(mvm, mvmsta, i,
- inactive_tid_bitmap);
- spin_unlock(&mvm->queue_info_lock);
- spin_unlock_bh(&mvmsta->lock);
- }
-
- rcu_read_unlock();
-}
-
void iwl_mvm_event_frame_timeout_callback(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
const struct ieee80211_sta *sta,
@@ -1441,14 +1010,12 @@ void iwl_mvm_event_frame_timeout_callback(struct iwl_mvm *mvm,
struct iwl_fw_dbg_trigger_tlv *trig;
struct iwl_fw_dbg_trigger_ba *ba_trig;
- if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_BA))
+ trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, ieee80211_vif_to_wdev(vif),
+ FW_DBG_TRIGGER_BA);
+ if (!trig)
return;
- trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_BA);
ba_trig = (void *)trig->data;
- if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt,
- ieee80211_vif_to_wdev(vif), trig))
- return;
if (!(le16_to_cpu(ba_trig->frame_timeout) & BIT(tid)))
return;
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 2146fda8da2f..05ed4fb88e0c 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
@@ -96,9 +96,9 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans,
/* Configure debug, for integration */
iwl_pcie_alloc_fw_monitor(trans, 0);
prph_sc_ctrl->hwm_cfg.hwm_base_addr =
- cpu_to_le64(trans_pcie->fw_mon_phys);
+ cpu_to_le64(trans->fw_mon[0].physical);
prph_sc_ctrl->hwm_cfg.hwm_size =
- cpu_to_le32(trans_pcie->fw_mon_size);
+ cpu_to_le32(trans->fw_mon[0].size);
/* allocate ucode sections in dram and set addresses */
ret = iwl_pcie_init_fw_sec(trans, fw, &prph_scratch->dram);
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c
index b2cd7ef5fc3a..6f45a0303ddd 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c
@@ -162,7 +162,7 @@ int iwl_pcie_ctxt_info_init(struct iwl_trans *trans,
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_context_info *ctxt_info;
struct iwl_context_info_rbd_cfg *rx_cfg;
- u32 control_flags = 0;
+ u32 control_flags = 0, rb_size;
int ret;
ctxt_info = dma_alloc_coherent(trans->dev, sizeof(*ctxt_info),
@@ -177,11 +177,29 @@ int iwl_pcie_ctxt_info_init(struct iwl_trans *trans,
/* size is in DWs */
ctxt_info->version.size = cpu_to_le16(sizeof(*ctxt_info) / 4);
+ switch (trans_pcie->rx_buf_size) {
+ case IWL_AMSDU_2K:
+ rb_size = IWL_CTXT_INFO_RB_SIZE_2K;
+ break;
+ case IWL_AMSDU_4K:
+ rb_size = IWL_CTXT_INFO_RB_SIZE_4K;
+ break;
+ case IWL_AMSDU_8K:
+ rb_size = IWL_CTXT_INFO_RB_SIZE_8K;
+ break;
+ case IWL_AMSDU_12K:
+ rb_size = IWL_CTXT_INFO_RB_SIZE_12K;
+ break;
+ default:
+ WARN_ON(1);
+ rb_size = IWL_CTXT_INFO_RB_SIZE_4K;
+ }
+
BUILD_BUG_ON(RX_QUEUE_CB_SIZE(MQ_RX_TABLE_SIZE) > 0xF);
- control_flags = IWL_CTXT_INFO_RB_SIZE_4K |
- IWL_CTXT_INFO_TFD_FORMAT_LONG |
- RX_QUEUE_CB_SIZE(MQ_RX_TABLE_SIZE) <<
- IWL_CTXT_INFO_RB_CB_SIZE_POS;
+ control_flags = IWL_CTXT_INFO_TFD_FORMAT_LONG |
+ (RX_QUEUE_CB_SIZE(MQ_RX_TABLE_SIZE) <<
+ IWL_CTXT_INFO_RB_CB_SIZE_POS) |
+ (rb_size << IWL_CTXT_INFO_RB_SIZE_POS);
ctxt_info->control.control_flags = cpu_to_le32(control_flags);
/* initialize RX default queue */
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
index b150da4c6721..9e015212c2c0 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
@@ -19,11 +19,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
@@ -646,34 +641,33 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0x31DC, 0x40A4, iwl9462_2ac_cfg_shared_clk)},
{IWL_PCI_DEVICE(0x31DC, 0x4234, iwl9560_2ac_cfg_shared_clk)},
{IWL_PCI_DEVICE(0x31DC, 0x42A4, iwl9462_2ac_cfg_shared_clk)},
- {IWL_PCI_DEVICE(0x34F0, 0x0030, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x34F0, 0x0034, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x34F0, 0x0038, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x34F0, 0x003C, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x34F0, 0x0060, iwl9461_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x34F0, 0x0064, iwl9461_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x34F0, 0x00A0, iwl9462_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x34F0, 0x00A4, iwl9462_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x34F0, 0x0230, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x34F0, 0x0234, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x34F0, 0x0238, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x34F0, 0x023C, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x34F0, 0x0260, iwl9461_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x34F0, 0x0264, iwl9461_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x34F0, 0x02A0, iwl9462_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x34F0, 0x02A4, iwl9462_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x34F0, 0x1010, iwl9260_2ac_cfg)},
- {IWL_PCI_DEVICE(0x34F0, 0x1030, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x34F0, 0x1210, iwl9260_2ac_cfg)},
- {IWL_PCI_DEVICE(0x34F0, 0x1551, iwl9560_killer_s_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x34F0, 0x1552, iwl9560_killer_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x34F0, 0x2030, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x34F0, 0x2034, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x34F0, 0x4030, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x34F0, 0x4034, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x34F0, 0x40A4, iwl9462_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x34F0, 0x4234, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x34F0, 0x42A4, iwl9462_2ac_cfg_soc)},
+
+ {IWL_PCI_DEVICE(0x34F0, 0x0030, iwl9560_2ac_cfg_qu_b0_jf_b0)},
+ {IWL_PCI_DEVICE(0x34F0, 0x0034, iwl9560_2ac_cfg_qu_b0_jf_b0)},
+ {IWL_PCI_DEVICE(0x34F0, 0x0038, iwl9560_2ac_cfg_qu_b0_jf_b0)},
+ {IWL_PCI_DEVICE(0x34F0, 0x003C, iwl9560_2ac_cfg_qu_b0_jf_b0)},
+ {IWL_PCI_DEVICE(0x34F0, 0x0060, iwl9461_2ac_cfg_qu_b0_jf_b0)},
+ {IWL_PCI_DEVICE(0x34F0, 0x0064, iwl9461_2ac_cfg_qu_b0_jf_b0)},
+ {IWL_PCI_DEVICE(0x34F0, 0x00A0, iwl9462_2ac_cfg_qu_b0_jf_b0)},
+ {IWL_PCI_DEVICE(0x34F0, 0x00A4, iwl9462_2ac_cfg_qu_b0_jf_b0)},
+ {IWL_PCI_DEVICE(0x34F0, 0x0230, iwl9560_2ac_cfg_qu_b0_jf_b0)},
+ {IWL_PCI_DEVICE(0x34F0, 0x0234, iwl9560_2ac_cfg_qu_b0_jf_b0)},
+ {IWL_PCI_DEVICE(0x34F0, 0x0238, iwl9560_2ac_cfg_qu_b0_jf_b0)},
+ {IWL_PCI_DEVICE(0x34F0, 0x023C, iwl9560_2ac_cfg_qu_b0_jf_b0)},
+ {IWL_PCI_DEVICE(0x34F0, 0x0260, iwl9461_2ac_cfg_qu_b0_jf_b0)},
+ {IWL_PCI_DEVICE(0x34F0, 0x0264, iwl9461_2ac_cfg_qu_b0_jf_b0)},
+ {IWL_PCI_DEVICE(0x34F0, 0x02A0, iwl9462_2ac_cfg_qu_b0_jf_b0)},
+ {IWL_PCI_DEVICE(0x34F0, 0x02A4, iwl9462_2ac_cfg_qu_b0_jf_b0)},
+ {IWL_PCI_DEVICE(0x34F0, 0x1551, killer1550s_2ac_cfg_qu_b0_jf_b0)},
+ {IWL_PCI_DEVICE(0x34F0, 0x1552, killer1550i_2ac_cfg_qu_b0_jf_b0)},
+ {IWL_PCI_DEVICE(0x34F0, 0x2030, iwl9560_2ac_cfg_qu_b0_jf_b0)},
+ {IWL_PCI_DEVICE(0x34F0, 0x2034, iwl9560_2ac_cfg_qu_b0_jf_b0)},
+ {IWL_PCI_DEVICE(0x34F0, 0x4030, iwl9560_2ac_cfg_qu_b0_jf_b0)},
+ {IWL_PCI_DEVICE(0x34F0, 0x4034, iwl9560_2ac_cfg_qu_b0_jf_b0)},
+ {IWL_PCI_DEVICE(0x34F0, 0x40A4, iwl9462_2ac_cfg_qu_b0_jf_b0)},
+ {IWL_PCI_DEVICE(0x34F0, 0x4234, iwl9560_2ac_cfg_qu_b0_jf_b0)},
+ {IWL_PCI_DEVICE(0x34F0, 0x42A4, iwl9462_2ac_cfg_qu_b0_jf_b0)},
+
{IWL_PCI_DEVICE(0x3DF0, 0x0030, iwl9560_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x3DF0, 0x0034, iwl9560_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x3DF0, 0x0038, iwl9560_2ac_cfg_soc)},
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
index b63d44b7cd7c..f9c4c64dee66 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
@@ -17,9 +17,6 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
- * You should have received a copy of the GNU General Public License along with
- * this program.
- *
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
@@ -102,66 +99,6 @@ struct isr_statistics {
u32 unhandled;
};
-#define IWL_CD_STTS_OPTIMIZED_POS 0
-#define IWL_CD_STTS_OPTIMIZED_MSK 0x01
-#define IWL_CD_STTS_TRANSFER_STATUS_POS 1
-#define IWL_CD_STTS_TRANSFER_STATUS_MSK 0x0E
-#define IWL_CD_STTS_WIFI_STATUS_POS 4
-#define IWL_CD_STTS_WIFI_STATUS_MSK 0xF0
-
-/**
- * enum iwl_completion_desc_transfer_status - transfer status (bits 1-3)
- * @IWL_CD_STTS_END_TRANSFER: successful transfer complete.
- * In sniffer mode, when split is used, set in last CD completion. (RX)
- * @IWL_CD_STTS_OVERFLOW: In sniffer mode, when using split - used for
- * all CD completion. (RX)
- * @IWL_CD_STTS_ABORTED: CR abort / close flow. (RX)
- */
-enum iwl_completion_desc_transfer_status {
- IWL_CD_STTS_UNUSED,
- IWL_CD_STTS_UNUSED_2,
- IWL_CD_STTS_END_TRANSFER,
- IWL_CD_STTS_OVERFLOW,
- IWL_CD_STTS_ABORTED,
- IWL_CD_STTS_ERROR,
-};
-
-/**
- * enum iwl_completion_desc_wifi_status - wifi status (bits 4-7)
- * @IWL_CD_STTS_VALID: the packet is valid (RX)
- * @IWL_CD_STTS_FCS_ERR: frame check sequence error (RX)
- * @IWL_CD_STTS_SEC_KEY_ERR: error handling the security key of rx (RX)
- * @IWL_CD_STTS_DECRYPTION_ERR: error decrypting the frame (RX)
- * @IWL_CD_STTS_DUP: duplicate packet (RX)
- * @IWL_CD_STTS_ICV_MIC_ERR: MIC error (RX)
- * @IWL_CD_STTS_INTERNAL_SNAP_ERR: problems removing the snap (RX)
- * @IWL_CD_STTS_SEC_PORT_FAIL: security port fail (RX)
- * @IWL_CD_STTS_BA_OLD_SN: block ack received old SN (RX)
- * @IWL_CD_STTS_QOS_NULL: QoS null packet (RX)
- * @IWL_CD_STTS_MAC_HDR_ERR: MAC header conversion error (RX)
- * @IWL_CD_STTS_MAX_RETRANS: reached max number of retransmissions (TX)
- * @IWL_CD_STTS_EX_LIFETIME: exceeded lifetime (TX)
- * @IWL_CD_STTS_NOT_USED: completed but not used (RX)
- * @IWL_CD_STTS_REPLAY_ERR: pn check failed, replay error (RX)
- */
-enum iwl_completion_desc_wifi_status {
- IWL_CD_STTS_VALID,
- IWL_CD_STTS_FCS_ERR,
- IWL_CD_STTS_SEC_KEY_ERR,
- IWL_CD_STTS_DECRYPTION_ERR,
- IWL_CD_STTS_DUP,
- IWL_CD_STTS_ICV_MIC_ERR,
- IWL_CD_STTS_INTERNAL_SNAP_ERR,
- IWL_CD_STTS_SEC_PORT_FAIL,
- IWL_CD_STTS_BA_OLD_SN,
- IWL_CD_STTS_QOS_NULL,
- IWL_CD_STTS_MAC_HDR_ERR,
- IWL_CD_STTS_MAX_RETRANS,
- IWL_CD_STTS_EX_LIFETIME,
- IWL_CD_STTS_NOT_USED,
- IWL_CD_STTS_REPLAY_ERR,
-};
-
#define IWL_RX_TD_TYPE_MSK 0xff000000
#define IWL_RX_TD_SIZE_MSK 0x00ffffff
#define IWL_RX_TD_SIZE_2K BIT(11)
@@ -464,18 +401,6 @@ enum iwl_image_response_code {
};
/**
- * struct iwl_dram_data
- * @physical: page phy pointer
- * @block: pointer to the allocated block/page
- * @size: size of the block/page
- */
-struct iwl_dram_data {
- dma_addr_t physical;
- void *block;
- int size;
-};
-
-/**
* struct iwl_self_init_dram - dram data used by self init process
* @fw: lmac and umac dram data
* @fw_cnt: total number of items in array
@@ -516,6 +441,7 @@ struct iwl_self_init_dram {
* @ucode_write_complete: indicates that the ucode has been copied.
* @ucode_write_waitq: wait queue for uCode load
* @cmd_queue - command queue number
+ * @def_rx_queue - default rx queue number
* @rx_buf_size: Rx buffer size
* @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes)
* @scd_set_active: should the transport configure the SCD for HCMD queue
@@ -525,9 +451,6 @@ struct iwl_self_init_dram {
* @reg_lock: protect hw register access
* @mutex: to protect stop_device / start_fw / start_hw
* @cmd_in_flight: true when we have a host command in flight
- * @fw_mon_phys: physical address of the buffer for the firmware monitor
- * @fw_mon_page: points to the first page of the buffer for the firmware monitor
- * @fw_mon_size: size of the buffer for the firmware monitor
* @msix_entries: array of MSI-X entries
* @msix_enabled: true if managed to enable MSI-X
* @shared_vec_mask: the type of causes the shared vector handles
@@ -539,7 +462,6 @@ struct iwl_self_init_dram {
* @fh_mask: current unmasked fh causes
* @hw_mask: current unmasked hw causes
* @in_rescan: true if we have triggered a device rescan
- * @scheduled_for_removal: true if we have scheduled a device removal
*/
struct iwl_trans_pcie {
struct iwl_rxq *rxq;
@@ -596,6 +518,7 @@ struct iwl_trans_pcie {
u8 page_offs, dev_cmd_offs;
u8 cmd_queue;
+ u8 def_rx_queue;
u8 cmd_fifo;
unsigned int cmd_q_wdg_timeout;
u8 n_no_reclaim_cmds;
@@ -615,10 +538,6 @@ struct iwl_trans_pcie {
bool cmd_hold_nic_awake;
bool ref_cmd_in_flight;
- dma_addr_t fw_mon_phys;
- struct page *fw_mon_page;
- u32 fw_mon_size;
-
struct msix_entry msix_entries[IWL_MAX_RX_HW_QUEUES];
bool msix_enabled;
u8 shared_vec_mask;
@@ -631,7 +550,6 @@ struct iwl_trans_pcie {
cpumask_t affinity_mask[IWL_MAX_RX_HW_QUEUES];
u16 tx_cmd_queue_size;
bool in_rescan;
- bool scheduled_for_removal;
};
static inline struct iwl_trans_pcie *
@@ -673,6 +591,7 @@ void iwl_trans_pcie_free(struct iwl_trans *trans);
/*****************************************************
* RX
******************************************************/
+int _iwl_pcie_rx_init(struct iwl_trans *trans);
int iwl_pcie_rx_init(struct iwl_trans *trans);
int iwl_pcie_gen2_rx_init(struct iwl_trans *trans);
irqreturn_t iwl_pcie_msix_isr(int irq, void *data);
@@ -686,6 +605,7 @@ void iwl_pcie_rx_init_rxb_lists(struct iwl_rxq *rxq);
int iwl_pcie_dummy_napi_poll(struct napi_struct *napi, int budget);
void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority,
struct iwl_rxq *rxq);
+int iwl_pcie_rx_alloc(struct iwl_trans *trans);
/*****************************************************
* ICT - interrupt handling
@@ -700,7 +620,8 @@ void iwl_pcie_disable_ict(struct iwl_trans *trans);
* TX / HCMD
******************************************************/
int iwl_pcie_tx_init(struct iwl_trans *trans);
-int iwl_pcie_gen2_tx_init(struct iwl_trans *trans);
+int iwl_pcie_gen2_tx_init(struct iwl_trans *trans, int txq_id,
+ int queue_size);
void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr);
int iwl_pcie_tx_stop(struct iwl_trans *trans);
void iwl_pcie_tx_free(struct iwl_trans *trans);
@@ -717,11 +638,17 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
struct iwl_device_cmd *dev_cmd, int txq_id);
void iwl_pcie_txq_check_wrptrs(struct iwl_trans *trans);
int iwl_trans_pcie_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd);
+void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx);
+void iwl_pcie_gen2_txq_inc_wr_ptr(struct iwl_trans *trans,
+ struct iwl_txq *txq);
void iwl_pcie_hcmd_complete(struct iwl_trans *trans,
struct iwl_rx_cmd_buffer *rxb);
void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
struct sk_buff_head *skbs);
void iwl_trans_pcie_tx_reset(struct iwl_trans *trans);
+void iwl_pcie_gen2_update_byte_tbl(struct iwl_trans_pcie *trans_pcie,
+ struct iwl_txq *txq, u16 byte_cnt,
+ int num_tbs);
static inline u16 iwl_pcie_tfd_tb_get_len(struct iwl_trans *trans, void *_tfd,
u8 idx)
@@ -1039,6 +966,7 @@ static inline void __iwl_trans_pcie_set_bit(struct iwl_trans *trans,
}
void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state);
+void iwl_trans_pcie_dump_regs(struct iwl_trans *trans);
#ifdef CONFIG_IWLWIFI_DEBUGFS
int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans);
@@ -1057,6 +985,7 @@ void iwl_pcie_enable_rx_wake(struct iwl_trans *trans, bool enable);
void iwl_pcie_rx_allocator_work(struct work_struct *data);
/* common functions that are used by gen2 transport */
+int iwl_pcie_gen2_apm_init(struct iwl_trans *trans);
void iwl_pcie_apm_config(struct iwl_trans *trans);
int iwl_pcie_prepare_card_hw(struct iwl_trans *trans);
void iwl_pcie_synchronize_irqs(struct iwl_trans *trans);
@@ -1088,8 +1017,16 @@ void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans, u8 max_power);
int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans,
const struct fw_img *fw, bool run_in_rfkill);
void iwl_trans_pcie_gen2_fw_alive(struct iwl_trans *trans, u32 scd_addr);
+void iwl_pcie_gen2_txq_free_memory(struct iwl_trans *trans,
+ struct iwl_txq *txq);
+int iwl_trans_pcie_dyn_txq_alloc_dma(struct iwl_trans *trans,
+ struct iwl_txq **intxq, int size,
+ unsigned int timeout);
+int iwl_trans_pcie_txq_alloc_response(struct iwl_trans *trans,
+ struct iwl_txq *txq,
+ struct iwl_host_cmd *hcmd);
int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans,
- struct iwl_tx_queue_cfg_cmd *cmd,
+ __le16 flags, u8 sta_id, u8 tid,
int cmd_id, int size,
unsigned int timeout);
void iwl_trans_pcie_dyn_txq_free(struct iwl_trans *trans, int queue);
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
index d017aa2a0a8b..e965cc588850 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
@@ -17,9 +17,6 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
- * You should have received a copy of the GNU General Public License along with
- * this program.
- *
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
@@ -776,7 +773,7 @@ err:
return -ENOMEM;
}
-static int iwl_pcie_rx_alloc(struct iwl_trans *trans)
+int iwl_pcie_rx_alloc(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_rb_allocator *rba = &trans_pcie->rba;
@@ -1002,7 +999,7 @@ int iwl_pcie_dummy_napi_poll(struct napi_struct *napi, int budget)
return 0;
}
-static int _iwl_pcie_rx_init(struct iwl_trans *trans)
+int _iwl_pcie_rx_init(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_rxq *def_rxq;
@@ -1107,6 +1104,9 @@ int iwl_pcie_rx_init(struct iwl_trans *trans)
int iwl_pcie_gen2_rx_init(struct iwl_trans *trans)
{
+ /* Set interrupt coalescing timer to default (2048 usecs) */
+ iwl_write8(trans, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF);
+
/*
* We don't configure the RFH.
* Restock will be done at alive, after firmware configured the RFH.
@@ -1144,6 +1144,14 @@ void iwl_pcie_rx_free(struct iwl_trans *trans)
kfree(trans_pcie->rxq);
}
+static void iwl_pcie_rx_move_to_allocator(struct iwl_rxq *rxq,
+ struct iwl_rb_allocator *rba)
+{
+ spin_lock(&rba->lock);
+ list_splice_tail_init(&rxq->rx_used, &rba->rbd_empty);
+ spin_unlock(&rba->lock);
+}
+
/*
* iwl_pcie_rx_reuse_rbd - Recycle used RBDs
*
@@ -1175,9 +1183,7 @@ static void iwl_pcie_rx_reuse_rbd(struct iwl_trans *trans,
if ((rxq->used_count % RX_CLAIM_REQ_ALLOC) == RX_POST_REQ_ALLOC) {
/* Move the 2 RBDs to the allocator ownership.
Allocator has another 6 from pool for the request completion*/
- spin_lock(&rba->lock);
- list_splice_tail_init(&rxq->rx_used, &rba->rbd_empty);
- spin_unlock(&rba->lock);
+ iwl_pcie_rx_move_to_allocator(rxq, rba);
atomic_inc(&rba->req_pending);
queue_work(rba->alloc_wq, &rba->rx_alloc);
@@ -1187,7 +1193,8 @@ static void iwl_pcie_rx_reuse_rbd(struct iwl_trans *trans,
static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
struct iwl_rxq *rxq,
struct iwl_rx_mem_buffer *rxb,
- bool emergency)
+ bool emergency,
+ int i)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_txq *txq = trans_pcie->txq[trans_pcie->cmd_queue];
@@ -1213,6 +1220,9 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
.truesize = max_len,
};
+ if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_22560)
+ rxcb.status = rxq->cd[i].status;
+
pkt = rxb_addr(&rxcb);
if (pkt->len_n_flags == cpu_to_le32(FH_RSCSR_FRAME_INVALID)) {
@@ -1267,7 +1277,7 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
index = SEQ_TO_INDEX(sequence);
cmd_index = iwl_pcie_get_cmd_index(txq, index);
- if (rxq->id == 0)
+ if (rxq->id == trans_pcie->def_rx_queue)
iwl_op_mode_rx(trans->op_mode, &rxq->napi,
&rxcb);
else
@@ -1396,17 +1406,25 @@ restart:
IWL_DEBUG_RX(trans, "Q %d: HW = SW = %d\n", rxq->id, r);
while (i != r) {
+ struct iwl_rb_allocator *rba = &trans_pcie->rba;
struct iwl_rx_mem_buffer *rxb;
-
- if (unlikely(rxq->used_count == rxq->queue_size / 2))
+ /* number of RBDs still waiting for page allocation */
+ u32 rb_pending_alloc =
+ atomic_read(&trans_pcie->rba.req_pending) *
+ RX_CLAIM_REQ_ALLOC;
+
+ if (unlikely(rb_pending_alloc >= rxq->queue_size / 2 &&
+ !emergency)) {
+ iwl_pcie_rx_move_to_allocator(rxq, rba);
emergency = true;
+ }
rxb = iwl_pcie_get_rxb(trans, rxq, i);
if (!rxb)
goto out;
IWL_DEBUG_RX(trans, "Q %d: HW = %d, SW = %d\n", rxq->id, r, i);
- iwl_pcie_rx_handle_rb(trans, rxq, rxb, emergency);
+ iwl_pcie_rx_handle_rb(trans, rxq, rxb, emergency, i);
i = (i + 1) & (rxq->queue_size - 1);
@@ -1421,17 +1439,13 @@ restart:
iwl_pcie_rx_allocator_get(trans, rxq);
if (rxq->used_count % RX_CLAIM_REQ_ALLOC == 0 && !emergency) {
- struct iwl_rb_allocator *rba = &trans_pcie->rba;
-
/* Add the remaining empty RBDs for allocator use */
- spin_lock(&rba->lock);
- list_splice_tail_init(&rxq->rx_used, &rba->rbd_empty);
- spin_unlock(&rba->lock);
+ iwl_pcie_rx_move_to_allocator(rxq, rba);
} else if (emergency) {
count++;
if (count == 8) {
count = 0;
- if (rxq->used_count < rxq->queue_size / 3)
+ if (rb_pending_alloc < rxq->queue_size / 3)
emergency = false;
rxq->read = i;
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c
index 2bc67219ed3e..77f3610e5ca9 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c
@@ -55,13 +55,14 @@
#include "iwl-context-info.h"
#include "iwl-context-info-gen3.h"
#include "internal.h"
+#include "fw/dbg.h"
/*
* Start up NIC's basic functionality after it has been reset
* (e.g. after platform boot, or shutdown via iwl_pcie_apm_stop())
* NOTE: This does not load uCode nor start the embedded processor
*/
-static int iwl_pcie_gen2_apm_init(struct iwl_trans *trans)
+int iwl_pcie_gen2_apm_init(struct iwl_trans *trans)
{
int ret = 0;
@@ -164,9 +165,7 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power)
trans_pcie->is_down = true;
/* Stop dbgc before stopping device */
- iwl_write_prph(trans, DBGC_IN_SAMPLE, 0);
- udelay(100);
- iwl_write_prph(trans, DBGC_OUT_CTRL, 0);
+ _iwl_fw_dbg_stop_recording(trans, NULL);
/* tell the device to stop sending interrupts */
iwl_disable_interrupts(trans);
@@ -265,7 +264,7 @@ static int iwl_pcie_gen2_nic_init(struct iwl_trans *trans)
return -ENOMEM;
/* Allocate or reset and init all Tx and Command queues */
- if (iwl_pcie_gen2_tx_init(trans))
+ if (iwl_pcie_gen2_tx_init(trans, trans_pcie->cmd_queue, TFD_CMD_SLOTS))
return -ENOMEM;
/* enable shadow regs in HW */
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
index 7d319b6863fe..5bafb3f46eb8 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
@@ -19,11 +19,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
@@ -92,7 +87,7 @@
#define IWL_FW_MEM_EXTENDED_START 0x40000
#define IWL_FW_MEM_EXTENDED_END 0x57FFF
-static void iwl_trans_pcie_dump_regs(struct iwl_trans *trans)
+void iwl_trans_pcie_dump_regs(struct iwl_trans *trans)
{
#define PCI_DUMP_SIZE 64
#define PREFIX_LEN 32
@@ -190,72 +185,42 @@ static void iwl_trans_pcie_sw_reset(struct iwl_trans *trans)
static void iwl_pcie_free_fw_monitor(struct iwl_trans *trans)
{
- struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
- if (!trans_pcie->fw_mon_page)
- return;
+ int i;
- dma_unmap_page(trans->dev, trans_pcie->fw_mon_phys,
- trans_pcie->fw_mon_size, DMA_FROM_DEVICE);
- __free_pages(trans_pcie->fw_mon_page,
- get_order(trans_pcie->fw_mon_size));
- trans_pcie->fw_mon_page = NULL;
- trans_pcie->fw_mon_phys = 0;
- trans_pcie->fw_mon_size = 0;
+ for (i = 0; i < trans->num_blocks; i++) {
+ dma_free_coherent(trans->dev, trans->fw_mon[i].size,
+ trans->fw_mon[i].block,
+ trans->fw_mon[i].physical);
+ trans->fw_mon[i].block = NULL;
+ trans->fw_mon[i].physical = 0;
+ trans->fw_mon[i].size = 0;
+ trans->num_blocks--;
+ }
}
-void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans, u8 max_power)
+static void iwl_pcie_alloc_fw_monitor_block(struct iwl_trans *trans,
+ u8 max_power, u8 min_power)
{
- struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
- struct page *page = NULL;
- dma_addr_t phys;
+ void *cpu_addr = NULL;
+ dma_addr_t phys = 0;
u32 size = 0;
u8 power;
- if (!max_power) {
- /* default max_power is maximum */
- max_power = 26;
- } else {
- max_power += 11;
- }
-
- if (WARN(max_power > 26,
- "External buffer size for monitor is too big %d, check the FW TLV\n",
- max_power))
- return;
-
- if (trans_pcie->fw_mon_page) {
- dma_sync_single_for_device(trans->dev, trans_pcie->fw_mon_phys,
- trans_pcie->fw_mon_size,
- DMA_FROM_DEVICE);
- return;
- }
-
- phys = 0;
- for (power = max_power; power >= 11; power--) {
- int order;
-
+ for (power = max_power; power >= min_power; power--) {
size = BIT(power);
- order = get_order(size);
- page = alloc_pages(__GFP_COMP | __GFP_NOWARN | __GFP_ZERO,
- order);
- if (!page)
+ cpu_addr = dma_alloc_coherent(trans->dev, size, &phys,
+ GFP_KERNEL | __GFP_NOWARN |
+ __GFP_ZERO | __GFP_COMP);
+ if (!cpu_addr)
continue;
- phys = dma_map_page(trans->dev, page, 0, PAGE_SIZE << order,
- DMA_FROM_DEVICE);
- if (dma_mapping_error(trans->dev, phys)) {
- __free_pages(page, order);
- page = NULL;
- continue;
- }
IWL_INFO(trans,
- "Allocated 0x%08x bytes (order %d) for firmware monitor.\n",
- size, order);
+ "Allocated 0x%08x bytes for firmware monitor.\n",
+ size);
break;
}
- if (WARN_ON_ONCE(!page))
+ if (WARN_ON_ONCE(!cpu_addr))
return;
if (power != max_power)
@@ -264,9 +229,34 @@ void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans, u8 max_power)
(unsigned long)BIT(power - 10),
(unsigned long)BIT(max_power - 10));
- trans_pcie->fw_mon_page = page;
- trans_pcie->fw_mon_phys = phys;
- trans_pcie->fw_mon_size = size;
+ trans->fw_mon[trans->num_blocks].block = cpu_addr;
+ trans->fw_mon[trans->num_blocks].physical = phys;
+ trans->fw_mon[trans->num_blocks].size = size;
+ trans->num_blocks++;
+}
+
+void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans, u8 max_power)
+{
+ if (!max_power) {
+ /* default max_power is maximum */
+ max_power = 26;
+ } else {
+ max_power += 11;
+ }
+
+ if (WARN(max_power > 26,
+ "External buffer size for monitor is too big %d, check the FW TLV\n",
+ max_power))
+ return;
+
+ /*
+ * This function allocats the default fw monitor.
+ * The optional additional ones will be allocated in runtime
+ */
+ if (trans->num_blocks)
+ return;
+
+ iwl_pcie_alloc_fw_monitor_block(trans, max_power, 11);
}
static u32 iwl_trans_pcie_read_shr(struct iwl_trans *trans, u32 reg)
@@ -930,7 +920,6 @@ static int iwl_pcie_load_cpu_sections(struct iwl_trans *trans,
void iwl_pcie_apply_destination(struct iwl_trans *trans)
{
- struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
const struct iwl_fw_dbg_dest_tlv_v1 *dest = trans->dbg_dest_tlv;
int i;
@@ -942,7 +931,7 @@ void iwl_pcie_apply_destination(struct iwl_trans *trans)
else
IWL_WARN(trans, "PCI should have external buffer debug\n");
- for (i = 0; i < trans->dbg_dest_reg_num; i++) {
+ for (i = 0; i < trans->dbg_n_dest_reg; i++) {
u32 addr = le32_to_cpu(dest->reg_ops[i].addr);
u32 val = le32_to_cpu(dest->reg_ops[i].val);
@@ -981,18 +970,18 @@ void iwl_pcie_apply_destination(struct iwl_trans *trans)
}
monitor:
- if (dest->monitor_mode == EXTERNAL_MODE && trans_pcie->fw_mon_size) {
+ if (dest->monitor_mode == EXTERNAL_MODE && trans->fw_mon[0].size) {
iwl_write_prph(trans, le32_to_cpu(dest->base_reg),
- trans_pcie->fw_mon_phys >> dest->base_shift);
+ trans->fw_mon[0].physical >> dest->base_shift);
if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_8000)
iwl_write_prph(trans, le32_to_cpu(dest->end_reg),
- (trans_pcie->fw_mon_phys +
- trans_pcie->fw_mon_size - 256) >>
+ (trans->fw_mon[0].physical +
+ trans->fw_mon[0].size - 256) >>
dest->end_shift);
else
iwl_write_prph(trans, le32_to_cpu(dest->end_reg),
- (trans_pcie->fw_mon_phys +
- trans_pcie->fw_mon_size) >>
+ (trans->fw_mon[0].physical +
+ trans->fw_mon[0].size) >>
dest->end_shift);
}
}
@@ -1000,7 +989,6 @@ monitor:
static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
const struct fw_img *image)
{
- struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
int ret = 0;
int first_ucode_section;
@@ -1030,12 +1018,12 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
iwl_pcie_alloc_fw_monitor(trans, 0);
- if (trans_pcie->fw_mon_size) {
+ if (trans->fw_mon[0].size) {
iwl_write_prph(trans, MON_BUFF_BASE_ADDR,
- trans_pcie->fw_mon_phys >> 4);
+ trans->fw_mon[0].physical >> 4);
iwl_write_prph(trans, MON_BUFF_END_ADDR,
- (trans_pcie->fw_mon_phys +
- trans_pcie->fw_mon_size) >> 4);
+ (trans->fw_mon[0].physical +
+ trans->fw_mon[0].size) >> 4);
}
} else if (trans->dbg_dest_tlv) {
iwl_pcie_apply_destination(trans);
@@ -1262,13 +1250,7 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)
trans_pcie->is_down = true;
/* Stop dbgc before stopping device */
- if (trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
- iwl_set_bits_prph(trans, MON_BUFF_SAMPLE_CTL, 0x100);
- } else {
- iwl_write_prph(trans, DBGC_IN_SAMPLE, 0);
- udelay(100);
- iwl_write_prph(trans, DBGC_OUT_CTRL, 0);
- }
+ _iwl_fw_dbg_stop_recording(trans, NULL);
/* tell the device to stop sending interrupts */
iwl_disable_interrupts(trans);
@@ -1830,18 +1812,30 @@ static u32 iwl_trans_pcie_read32(struct iwl_trans *trans, u32 ofs)
return readl(IWL_TRANS_GET_PCIE_TRANS(trans)->hw_base + ofs);
}
+static u32 iwl_trans_pcie_prph_msk(struct iwl_trans *trans)
+{
+ if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_22560)
+ return 0x00FFFFFF;
+ else
+ return 0x000FFFFF;
+}
+
static u32 iwl_trans_pcie_read_prph(struct iwl_trans *trans, u32 reg)
{
+ u32 mask = iwl_trans_pcie_prph_msk(trans);
+
iwl_trans_pcie_write32(trans, HBUS_TARG_PRPH_RADDR,
- ((reg & 0x000FFFFF) | (3 << 24)));
+ ((reg & mask) | (3 << 24)));
return iwl_trans_pcie_read32(trans, HBUS_TARG_PRPH_RDAT);
}
static void iwl_trans_pcie_write_prph(struct iwl_trans *trans, u32 addr,
u32 val)
{
+ u32 mask = iwl_trans_pcie_prph_msk(trans);
+
iwl_trans_pcie_write32(trans, HBUS_TARG_PRPH_WADDR,
- ((addr & 0x000FFFFF) | (3 << 24)));
+ ((addr & mask) | (3 << 24)));
iwl_trans_pcie_write32(trans, HBUS_TARG_PRPH_WDAT, val);
}
@@ -2013,7 +2007,7 @@ static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans,
if (iwlwifi_mod_params.remove_when_gone && cntrl == ~0U) {
struct iwl_trans_pcie_removal *removal;
- if (trans_pcie->scheduled_for_removal)
+ if (test_bit(STATUS_TRANS_DEAD, &trans->status))
goto err;
IWL_ERR(trans, "Device gone - scheduling removal!\n");
@@ -2039,7 +2033,7 @@ static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans,
* we don't need to clear this flag, because
* the trans will be freed and reallocated.
*/
- trans_pcie->scheduled_for_removal = true;
+ set_bit(STATUS_TRANS_DEAD, &trans->status);
removal->pdev = to_pci_dev(trans->dev);
INIT_WORK(&removal->work, iwl_trans_pcie_removal_wk);
@@ -2266,6 +2260,10 @@ static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, int txq_idx)
unsigned long now = jiffies;
u8 wr_ptr;
+ /* Make sure the NIC is still alive in the bus */
+ if (test_bit(STATUS_TRANS_DEAD, &trans->status))
+ return -ENODEV;
+
if (!test_bit(txq_idx, trans_pcie->queue_used))
return -EINVAL;
@@ -2861,10 +2859,9 @@ iwl_trans_pcie_dump_monitor(struct iwl_trans *trans,
struct iwl_fw_error_dump_data **data,
u32 monitor_len)
{
- struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
u32 len = 0;
- if ((trans_pcie->fw_mon_page &&
+ if ((trans->num_blocks &&
trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) ||
trans->dbg_dest_tlv) {
struct iwl_fw_error_dump_fw_mon *fw_mon_data;
@@ -2892,22 +2889,12 @@ iwl_trans_pcie_dump_monitor(struct iwl_trans *trans,
cpu_to_le32(iwl_read_prph(trans, base));
len += sizeof(**data) + sizeof(*fw_mon_data);
- if (trans_pcie->fw_mon_page) {
- /*
- * The firmware is now asserted, it won't write anything
- * to the buffer. CPU can take ownership to fetch the
- * data. The buffer will be handed back to the device
- * before the firmware will be restarted.
- */
- dma_sync_single_for_cpu(trans->dev,
- trans_pcie->fw_mon_phys,
- trans_pcie->fw_mon_size,
- DMA_FROM_DEVICE);
+ if (trans->num_blocks) {
memcpy(fw_mon_data->data,
- page_address(trans_pcie->fw_mon_page),
- trans_pcie->fw_mon_size);
+ trans->fw_mon[0].block,
+ trans->fw_mon[0].size);
- monitor_len = trans_pcie->fw_mon_size;
+ monitor_len = trans->fw_mon[0].size;
} else if (trans->dbg_dest_tlv->monitor_mode == SMEM_MODE) {
/*
* Update pointers to reflect actual values after
@@ -2943,36 +2930,15 @@ iwl_trans_pcie_dump_monitor(struct iwl_trans *trans,
return len;
}
-static struct iwl_trans_dump_data
-*iwl_trans_pcie_dump_data(struct iwl_trans *trans,
- const struct iwl_fw_dbg_trigger_tlv *trigger)
+static int iwl_trans_get_fw_monitor_len(struct iwl_trans *trans, int *len)
{
- struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
- struct iwl_fw_error_dump_data *data;
- struct iwl_txq *cmdq = trans_pcie->txq[trans_pcie->cmd_queue];
- struct iwl_fw_error_dump_txcmd *txcmd;
- struct iwl_trans_dump_data *dump_data;
- u32 len, num_rbs = 0;
- u32 monitor_len;
- int i, ptr;
- bool dump_rbs = test_bit(STATUS_FW_ERROR, &trans->status) &&
- !trans->cfg->mq_rx_supported &&
- trans->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_RB);
-
- /* transport dump header */
- len = sizeof(*dump_data);
-
- /* host commands */
- len += sizeof(*data) +
- cmdq->n_window * (sizeof(*txcmd) + TFD_MAX_PAYLOAD_SIZE);
-
- /* FW monitor */
- if (trans_pcie->fw_mon_page) {
- len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_fw_mon) +
- trans_pcie->fw_mon_size;
- monitor_len = trans_pcie->fw_mon_size;
+ if (trans->num_blocks) {
+ *len += sizeof(struct iwl_fw_error_dump_data) +
+ sizeof(struct iwl_fw_error_dump_fw_mon) +
+ trans->fw_mon[0].size;
+ return trans->fw_mon[0].size;
} else if (trans->dbg_dest_tlv) {
- u32 base, end, cfg_reg;
+ u32 base, end, cfg_reg, monitor_len;
if (trans->dbg_dest_tlv->version == 1) {
cfg_reg = le32_to_cpu(trans->dbg_dest_tlv->base_reg);
@@ -3002,11 +2968,39 @@ static struct iwl_trans_dump_data
end += (1 << trans->dbg_dest_tlv->end_shift);
monitor_len = end - base;
}
- len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_fw_mon) +
- monitor_len;
- } else {
- monitor_len = 0;
+ *len += sizeof(struct iwl_fw_error_dump_data) +
+ sizeof(struct iwl_fw_error_dump_fw_mon) +
+ monitor_len;
+ return monitor_len;
}
+ return 0;
+}
+
+static struct iwl_trans_dump_data
+*iwl_trans_pcie_dump_data(struct iwl_trans *trans,
+ const struct iwl_fw_dbg_trigger_tlv *trigger)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_fw_error_dump_data *data;
+ struct iwl_txq *cmdq = trans_pcie->txq[trans_pcie->cmd_queue];
+ struct iwl_fw_error_dump_txcmd *txcmd;
+ struct iwl_trans_dump_data *dump_data;
+ u32 len, num_rbs = 0;
+ u32 monitor_len;
+ int i, ptr;
+ bool dump_rbs = test_bit(STATUS_FW_ERROR, &trans->status) &&
+ !trans->cfg->mq_rx_supported &&
+ trans->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_RB);
+
+ /* transport dump header */
+ len = sizeof(*dump_data);
+
+ /* host commands */
+ len += sizeof(*data) +
+ cmdq->n_window * (sizeof(*txcmd) + TFD_MAX_PAYLOAD_SIZE);
+
+ /* FW monitor */
+ monitor_len = iwl_trans_get_fw_monitor_len(trans, &len);
if (trigger && (trigger->mode & IWL_FW_DBG_TRIGGER_MONITOR_ONLY)) {
if (!(trans->dbg_dump_mask &
@@ -3175,7 +3169,6 @@ static void iwl_trans_pcie_resume(struct iwl_trans *trans)
.ref = iwl_trans_pcie_ref, \
.unref = iwl_trans_pcie_unref, \
.dump_data = iwl_trans_pcie_dump_data, \
- .dump_regs = iwl_trans_pcie_dump_regs, \
.d3_suspend = iwl_trans_pcie_d3_suspend, \
.d3_resume = iwl_trans_pcie_d3_resume
@@ -3277,6 +3270,8 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
PCIE_LINK_STATE_CLKPM);
}
+ trans_pcie->def_rx_queue = 0;
+
if (cfg->use_tfh) {
addr_size = 64;
trans_pcie->max_tbs = IWL_TFH_NUM_TBS;
@@ -3327,6 +3322,12 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
iwl_disable_interrupts(trans);
trans->hw_rev = iwl_read32(trans, CSR_HW_REV);
+ if (trans->hw_rev == 0xffffffff) {
+ dev_err(&pdev->dev, "HW_REV=0xFFFFFFFF, PCI issues?\n");
+ ret = -EIO;
+ goto out_no_pci;
+ }
+
/*
* In the 8000 HW family the format of the 4 bytes of CSR_HW_REV have
* changed, and now the revision step also includes bit 0-1 (no more
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c
index b99f33ff9123..e880f69eac26 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c
@@ -87,9 +87,9 @@ void iwl_pcie_gen2_tx_stop(struct iwl_trans *trans)
/*
* iwl_pcie_txq_update_byte_tbl - Set up entry in Tx byte-count array
*/
-static void iwl_pcie_gen2_update_byte_tbl(struct iwl_trans_pcie *trans_pcie,
- struct iwl_txq *txq, u16 byte_cnt,
- int num_tbs)
+void iwl_pcie_gen2_update_byte_tbl(struct iwl_trans_pcie *trans_pcie,
+ struct iwl_txq *txq, u16 byte_cnt,
+ int num_tbs)
{
struct iwlagn_scd_bc_tbl *scd_bc_tbl = txq->bc_tbl.addr;
struct iwl_trans *trans = iwl_trans_pcie_get_trans(trans_pcie);
@@ -127,8 +127,8 @@ static void iwl_pcie_gen2_update_byte_tbl(struct iwl_trans_pcie *trans_pcie,
/*
* iwl_pcie_gen2_txq_inc_wr_ptr - Send new write index to hardware
*/
-static void iwl_pcie_gen2_txq_inc_wr_ptr(struct iwl_trans *trans,
- struct iwl_txq *txq)
+void iwl_pcie_gen2_txq_inc_wr_ptr(struct iwl_trans *trans,
+ struct iwl_txq *txq)
{
lockdep_assert_held(&txq->lock);
@@ -330,7 +330,7 @@ static int iwl_pcie_gen2_build_amsdu(struct iwl_trans *trans,
goto out_err;
}
iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, tb_len);
- trace_iwlwifi_dev_tx_tso_chunk(trans->dev, start_hdr, tb_len);
+ trace_iwlwifi_dev_tx_tb(trans->dev, skb, start_hdr, tb_len);
/* add this subframe's headers' length to the tx_cmd */
le16_add_cpu(&tx_cmd->len, hdr_page->pos - subf_hdrs_start);
@@ -347,8 +347,8 @@ static int iwl_pcie_gen2_build_amsdu(struct iwl_trans *trans,
goto out_err;
}
iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, tb_len);
- trace_iwlwifi_dev_tx_tso_chunk(trans->dev, tso.data,
- tb_len);
+ trace_iwlwifi_dev_tx_tb(trans->dev, skb, tso.data,
+ tb_len);
data_left -= tb_len;
tso_build_data(skb, &tso, tb_len);
@@ -416,6 +416,40 @@ out_err:
return NULL;
}
+static int iwl_pcie_gen2_tx_add_frags(struct iwl_trans *trans,
+ struct sk_buff *skb,
+ struct iwl_tfh_tfd *tfd,
+ struct iwl_cmd_meta *out_meta)
+{
+ int i;
+
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+ const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ dma_addr_t tb_phys;
+ int tb_idx;
+
+ if (!skb_frag_size(frag))
+ continue;
+
+ tb_phys = skb_frag_dma_map(trans->dev, frag, 0,
+ skb_frag_size(frag), DMA_TO_DEVICE);
+
+ if (unlikely(dma_mapping_error(trans->dev, tb_phys)))
+ return -ENOMEM;
+ tb_idx = iwl_pcie_gen2_set_tb(trans, tfd, tb_phys,
+ skb_frag_size(frag));
+ trace_iwlwifi_dev_tx_tb(trans->dev, skb,
+ skb_frag_address(frag),
+ skb_frag_size(frag));
+ if (tb_idx < 0)
+ return tb_idx;
+
+ out_meta->tbs |= BIT(tb_idx);
+ }
+
+ return 0;
+}
+
static struct
iwl_tfh_tfd *iwl_pcie_gen2_build_tx(struct iwl_trans *trans,
struct iwl_txq *txq,
@@ -423,12 +457,13 @@ iwl_tfh_tfd *iwl_pcie_gen2_build_tx(struct iwl_trans *trans,
struct sk_buff *skb,
struct iwl_cmd_meta *out_meta,
int hdr_len,
- int tx_cmd_len)
+ int tx_cmd_len,
+ bool pad)
{
int idx = iwl_pcie_get_cmd_index(txq, txq->write_ptr);
struct iwl_tfh_tfd *tfd = iwl_pcie_get_tfd(trans, txq, idx);
dma_addr_t tb_phys;
- int i, len, tb1_len, tb2_len;
+ int len, tb1_len, tb2_len;
void *tb1_addr;
tb_phys = iwl_pcie_get_first_tb_dma(txq, idx);
@@ -447,7 +482,10 @@ iwl_tfh_tfd *iwl_pcie_gen2_build_tx(struct iwl_trans *trans,
len = tx_cmd_len + sizeof(struct iwl_cmd_header) + hdr_len -
IWL_FIRST_TB_SIZE;
- tb1_len = ALIGN(len, 4);
+ if (pad)
+ tb1_len = ALIGN(len, 4);
+ else
+ tb1_len = len;
/* map the data for TB1 */
tb1_addr = ((u8 *)&dev_cmd->hdr) + IWL_FIRST_TB_SIZE;
@@ -455,6 +493,8 @@ iwl_tfh_tfd *iwl_pcie_gen2_build_tx(struct iwl_trans *trans,
if (unlikely(dma_mapping_error(trans->dev, tb_phys)))
goto out_err;
iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, tb1_len);
+ trace_iwlwifi_dev_tx(trans->dev, skb, tfd, sizeof(*tfd), &dev_cmd->hdr,
+ IWL_FIRST_TB_SIZE + tb1_len, hdr_len);
/* set up TFD's third entry to point to remainder of skb's head */
tb2_len = skb_headlen(skb) - hdr_len;
@@ -465,30 +505,13 @@ iwl_tfh_tfd *iwl_pcie_gen2_build_tx(struct iwl_trans *trans,
if (unlikely(dma_mapping_error(trans->dev, tb_phys)))
goto out_err;
iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, tb2_len);
+ trace_iwlwifi_dev_tx_tb(trans->dev, skb,
+ skb->data + hdr_len,
+ tb2_len);
}
- /* set up the remaining entries to point to the data */
- for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- int tb_idx;
-
- if (!skb_frag_size(frag))
- continue;
-
- tb_phys = skb_frag_dma_map(trans->dev, frag, 0,
- skb_frag_size(frag), DMA_TO_DEVICE);
-
- if (unlikely(dma_mapping_error(trans->dev, tb_phys)))
- goto out_err;
- tb_idx = iwl_pcie_gen2_set_tb(trans, tfd, tb_phys,
- skb_frag_size(frag));
-
- out_meta->tbs |= BIT(tb_idx);
- }
-
- trace_iwlwifi_dev_tx(trans->dev, skb, tfd, sizeof(*tfd), &dev_cmd->hdr,
- IWL_FIRST_TB_SIZE + tb1_len, hdr_len);
- trace_iwlwifi_dev_tx_data(trans->dev, skb, hdr_len);
+ if (iwl_pcie_gen2_tx_add_frags(trans, skb, tfd, out_meta))
+ goto out_err;
return tfd;
@@ -526,12 +549,17 @@ struct iwl_tfh_tfd *iwl_pcie_gen2_build_tfd(struct iwl_trans *trans,
hdr_len = ieee80211_hdrlen(hdr->frame_control);
- if (amsdu)
+ /*
+ * Only build A-MSDUs here if doing so by GSO, otherwise it may be
+ * an A-MSDU for other reasons, e.g. NAN or an A-MSDU having been
+ * built in the higher layers already.
+ */
+ if (amsdu && skb_shinfo(skb)->gso_size)
return iwl_pcie_gen2_build_tx_amsdu(trans, txq, dev_cmd, skb,
out_meta, hdr_len, len);
return iwl_pcie_gen2_build_tx(trans, txq, dev_cmd, skb, out_meta,
- hdr_len, len);
+ hdr_len, len, !amsdu);
}
int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb,
@@ -1065,8 +1093,8 @@ void iwl_pcie_gen2_txq_unmap(struct iwl_trans *trans, int txq_id)
iwl_wake_queue(trans, txq);
}
-static void iwl_pcie_gen2_txq_free_memory(struct iwl_trans *trans,
- struct iwl_txq *txq)
+void iwl_pcie_gen2_txq_free_memory(struct iwl_trans *trans,
+ struct iwl_txq *txq)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct device *dev = trans->dev;
@@ -1120,23 +1148,13 @@ static void iwl_pcie_gen2_txq_free(struct iwl_trans *trans, int txq_id)
clear_bit(txq_id, trans_pcie->queue_used);
}
-int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans,
- struct iwl_tx_queue_cfg_cmd *cmd,
- int cmd_id, int size,
- unsigned int timeout)
+int iwl_trans_pcie_dyn_txq_alloc_dma(struct iwl_trans *trans,
+ struct iwl_txq **intxq, int size,
+ unsigned int timeout)
{
- struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
- struct iwl_tx_queue_cfg_rsp *rsp;
- struct iwl_txq *txq;
- struct iwl_host_cmd hcmd = {
- .id = cmd_id,
- .len = { sizeof(*cmd) },
- .data = { cmd, },
- .flags = CMD_WANT_SKB,
- };
- int ret, qid;
- u32 wr_ptr;
+ int ret;
+ struct iwl_txq *txq;
txq = kzalloc(sizeof(*txq), GFP_KERNEL);
if (!txq)
return -ENOMEM;
@@ -1164,20 +1182,30 @@ int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans,
txq->wd_timeout = msecs_to_jiffies(timeout);
- cmd->tfdq_addr = cpu_to_le64(txq->dma_addr);
- cmd->byte_cnt_addr = cpu_to_le64(txq->bc_tbl.dma);
- cmd->cb_size = cpu_to_le32(TFD_QUEUE_CB_SIZE(size));
+ *intxq = txq;
+ return 0;
- ret = iwl_trans_send_cmd(trans, &hcmd);
- if (ret)
- goto error;
+error:
+ iwl_pcie_gen2_txq_free_memory(trans, txq);
+ return ret;
+}
+
+int iwl_trans_pcie_txq_alloc_response(struct iwl_trans *trans,
+ struct iwl_txq *txq,
+ struct iwl_host_cmd *hcmd)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_tx_queue_cfg_rsp *rsp;
+ int ret, qid;
+ u32 wr_ptr;
- if (WARN_ON(iwl_rx_packet_payload_len(hcmd.resp_pkt) != sizeof(*rsp))) {
+ if (WARN_ON(iwl_rx_packet_payload_len(hcmd->resp_pkt) !=
+ sizeof(*rsp))) {
ret = -EINVAL;
goto error_free_resp;
}
- rsp = (void *)hcmd.resp_pkt->data;
+ rsp = (void *)hcmd->resp_pkt->data;
qid = le16_to_cpu(rsp->queue_number);
wr_ptr = le16_to_cpu(rsp->write_pointer);
@@ -1204,11 +1232,48 @@ int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans,
(txq->write_ptr) | (qid << 16));
IWL_DEBUG_TX_QUEUES(trans, "Activate queue %d\n", qid);
- iwl_free_resp(&hcmd);
+ iwl_free_resp(hcmd);
return qid;
error_free_resp:
- iwl_free_resp(&hcmd);
+ iwl_free_resp(hcmd);
+ iwl_pcie_gen2_txq_free_memory(trans, txq);
+ return ret;
+}
+
+int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans,
+ __le16 flags, u8 sta_id, u8 tid,
+ int cmd_id, int size,
+ unsigned int timeout)
+{
+ struct iwl_txq *txq = NULL;
+ struct iwl_tx_queue_cfg_cmd cmd = {
+ .flags = flags,
+ .sta_id = sta_id,
+ .tid = tid,
+ };
+ struct iwl_host_cmd hcmd = {
+ .id = cmd_id,
+ .len = { sizeof(cmd) },
+ .data = { &cmd, },
+ .flags = CMD_WANT_SKB,
+ };
+ int ret;
+
+ ret = iwl_trans_pcie_dyn_txq_alloc_dma(trans, &txq, size, timeout);
+ if (ret)
+ return ret;
+
+ cmd.tfdq_addr = cpu_to_le64(txq->dma_addr);
+ cmd.byte_cnt_addr = cpu_to_le64(txq->bc_tbl.dma);
+ cmd.cb_size = cpu_to_le32(TFD_QUEUE_CB_SIZE(size));
+
+ ret = iwl_trans_send_cmd(trans, &hcmd);
+ if (ret)
+ goto error;
+
+ return iwl_trans_pcie_txq_alloc_response(trans, txq, &hcmd);
+
error:
iwl_pcie_gen2_txq_free_memory(trans, txq);
return ret;
@@ -1251,30 +1316,31 @@ void iwl_pcie_gen2_tx_free(struct iwl_trans *trans)
}
}
-int iwl_pcie_gen2_tx_init(struct iwl_trans *trans)
+int iwl_pcie_gen2_tx_init(struct iwl_trans *trans, int txq_id, int queue_size)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
- struct iwl_txq *cmd_queue;
- int txq_id = trans_pcie->cmd_queue, ret;
+ struct iwl_txq *queue;
+ int ret;
- /* alloc and init the command queue */
+ /* alloc and init the tx queue */
if (!trans_pcie->txq[txq_id]) {
- cmd_queue = kzalloc(sizeof(*cmd_queue), GFP_KERNEL);
- if (!cmd_queue) {
- IWL_ERR(trans, "Not enough memory for command queue\n");
+ queue = kzalloc(sizeof(*queue), GFP_KERNEL);
+ if (!queue) {
+ IWL_ERR(trans, "Not enough memory for tx queue\n");
return -ENOMEM;
}
- trans_pcie->txq[txq_id] = cmd_queue;
- ret = iwl_pcie_txq_alloc(trans, cmd_queue, TFD_CMD_SLOTS, true);
+ trans_pcie->txq[txq_id] = queue;
+ ret = iwl_pcie_txq_alloc(trans, queue, queue_size, true);
if (ret) {
IWL_ERR(trans, "Tx %d queue init failed\n", txq_id);
goto error;
}
} else {
- cmd_queue = trans_pcie->txq[txq_id];
+ queue = trans_pcie->txq[txq_id];
}
- ret = iwl_pcie_txq_init(trans, cmd_queue, TFD_CMD_SLOTS, true);
+ ret = iwl_pcie_txq_init(trans, queue, queue_size,
+ (txq_id == trans_pcie->cmd_queue));
if (ret) {
IWL_ERR(trans, "Tx %d queue alloc failed\n", txq_id);
goto error;
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
index 93f0d387688a..87b7225fe289 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
@@ -17,10 +17,6 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
@@ -1101,7 +1097,7 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
if (!iwl_queue_used(txq, last_to_free)) {
IWL_ERR(trans,
- "%s: Read index for DMA queue txq id (%d), last_to_free %d is out of range [0-%d] %d %d.\n",
+ "%s: Read index for txq id (%d), last_to_free %d is out of range [0-%d] %d %d.\n",
__func__, txq_id, last_to_free,
trans->cfg->base_params->max_tfd_queue_size,
txq->write_ptr, txq->read_ptr);
@@ -1188,6 +1184,10 @@ static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans,
lockdep_assert_held(&trans_pcie->reg_lock);
+ /* Make sure the NIC is still alive in the bus */
+ if (test_bit(STATUS_TRANS_DEAD, &trans->status))
+ return -ENODEV;
+
if (!(cmd->flags & CMD_SEND_IN_IDLE) &&
!trans_pcie->ref_cmd_in_flight) {
trans_pcie->ref_cmd_in_flight = true;
@@ -1230,7 +1230,7 @@ static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans,
* need to be reclaimed. As result, some free space forms. If there is
* enough free space (> low mark), wake the stack that feeds us.
*/
-static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx)
+void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_txq *txq = trans_pcie->txq[txq_id];
@@ -1912,7 +1912,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
}
if (test_bit(STATUS_FW_ERROR, &trans->status)) {
- iwl_trans_dump_regs(trans);
+ iwl_trans_pcie_dump_regs(trans);
IWL_ERR(trans, "FW error in SYNC CMD %s\n",
iwl_get_cmd_string(trans, cmd->id));
dump_stack();
@@ -1957,6 +1957,10 @@ cancel:
int iwl_trans_pcie_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
{
+ /* Make sure the NIC is still alive in the bus */
+ if (test_bit(STATUS_TRANS_DEAD, &trans->status))
+ return -ENODEV;
+
if (!(cmd->flags & CMD_SEND_IN_RFKILL) &&
test_bit(STATUS_RFKILL_OPMODE, &trans->status)) {
IWL_DEBUG_RF_KILL(trans, "Dropping CMD 0x%x: RF KILL\n",
@@ -1973,29 +1977,27 @@ int iwl_trans_pcie_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
static int iwl_fill_data_tbs(struct iwl_trans *trans, struct sk_buff *skb,
struct iwl_txq *txq, u8 hdr_len,
- struct iwl_cmd_meta *out_meta,
- struct iwl_device_cmd *dev_cmd, u16 tb1_len)
+ struct iwl_cmd_meta *out_meta)
{
- struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
- u16 tb2_len;
+ u16 head_tb_len;
int i;
/*
* Set up TFD's third entry to point directly to remainder
* of skb's head, if any
*/
- tb2_len = skb_headlen(skb) - hdr_len;
+ head_tb_len = skb_headlen(skb) - hdr_len;
- if (tb2_len > 0) {
- dma_addr_t tb2_phys = dma_map_single(trans->dev,
- skb->data + hdr_len,
- tb2_len, DMA_TO_DEVICE);
- if (unlikely(dma_mapping_error(trans->dev, tb2_phys))) {
- iwl_pcie_tfd_unmap(trans, out_meta, txq,
- txq->write_ptr);
+ if (head_tb_len > 0) {
+ dma_addr_t tb_phys = dma_map_single(trans->dev,
+ skb->data + hdr_len,
+ head_tb_len, DMA_TO_DEVICE);
+ if (unlikely(dma_mapping_error(trans->dev, tb_phys)))
return -EINVAL;
- }
- iwl_pcie_txq_build_tfd(trans, txq, tb2_phys, tb2_len, false);
+ trace_iwlwifi_dev_tx_tb(trans->dev, skb,
+ skb->data + hdr_len,
+ head_tb_len);
+ iwl_pcie_txq_build_tfd(trans, txq, tb_phys, head_tb_len, false);
}
/* set up the remaining entries to point to the data */
@@ -2010,23 +2012,19 @@ static int iwl_fill_data_tbs(struct iwl_trans *trans, struct sk_buff *skb,
tb_phys = skb_frag_dma_map(trans->dev, frag, 0,
skb_frag_size(frag), DMA_TO_DEVICE);
- if (unlikely(dma_mapping_error(trans->dev, tb_phys))) {
- iwl_pcie_tfd_unmap(trans, out_meta, txq,
- txq->write_ptr);
+ if (unlikely(dma_mapping_error(trans->dev, tb_phys)))
return -EINVAL;
- }
+ trace_iwlwifi_dev_tx_tb(trans->dev, skb,
+ skb_frag_address(frag),
+ skb_frag_size(frag));
tb_idx = iwl_pcie_txq_build_tfd(trans, txq, tb_phys,
skb_frag_size(frag), false);
+ if (tb_idx < 0)
+ return tb_idx;
out_meta->tbs |= BIT(tb_idx);
}
- trace_iwlwifi_dev_tx(trans->dev, skb,
- iwl_pcie_get_tfd(trans, txq, txq->write_ptr),
- trans_pcie->tfd_size,
- &dev_cmd->hdr, IWL_FIRST_TB_SIZE + tb1_len,
- hdr_len);
- trace_iwlwifi_dev_tx_data(trans->dev, skb, hdr_len);
return 0;
}
@@ -2087,7 +2085,6 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb,
u8 *start_hdr;
struct iwl_tso_hdr_page *hdr_page;
struct page **page_ptr;
- int ret;
struct tso_t tso;
/* if the packet is protected, then it must be CCMP or GCMP */
@@ -2173,10 +2170,8 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb,
if (trans_pcie->sw_csum_tx) {
csum_skb = alloc_skb(data_left + tcp_hdrlen(skb),
GFP_ATOMIC);
- if (!csum_skb) {
- ret = -ENOMEM;
- goto out_unmap;
- }
+ if (!csum_skb)
+ return -ENOMEM;
iwl_compute_pseudo_hdr_csum(iph, tcph,
skb->protocol ==
@@ -2197,13 +2192,12 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb,
hdr_tb_len, DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(trans->dev, hdr_tb_phys))) {
dev_kfree_skb(csum_skb);
- ret = -EINVAL;
- goto out_unmap;
+ return -EINVAL;
}
iwl_pcie_txq_build_tfd(trans, txq, hdr_tb_phys,
hdr_tb_len, false);
- trace_iwlwifi_dev_tx_tso_chunk(trans->dev, start_hdr,
- hdr_tb_len);
+ trace_iwlwifi_dev_tx_tb(trans->dev, skb, start_hdr,
+ hdr_tb_len);
/* add this subframe's headers' length to the tx_cmd */
le16_add_cpu(&tx_cmd->len, hdr_page->pos - subf_hdrs_start);
@@ -2223,14 +2217,13 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb,
size, DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(trans->dev, tb_phys))) {
dev_kfree_skb(csum_skb);
- ret = -EINVAL;
- goto out_unmap;
+ return -EINVAL;
}
iwl_pcie_txq_build_tfd(trans, txq, tb_phys,
size, false);
- trace_iwlwifi_dev_tx_tso_chunk(trans->dev, tso.data,
- size);
+ trace_iwlwifi_dev_tx_tb(trans->dev, skb, tso.data,
+ size);
data_left -= size;
tso_build_data(skb, &tso, size);
@@ -2258,10 +2251,6 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb,
skb_push(skb, hdr_len + iv_len);
return 0;
-
-out_unmap:
- iwl_pcie_tfd_unmap(trans, out_meta, txq, txq->write_ptr);
- return ret;
}
#else /* CONFIG_INET */
static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb,
@@ -2415,6 +2404,13 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
goto out_err;
iwl_pcie_txq_build_tfd(trans, txq, tb1_phys, tb1_len, false);
+ trace_iwlwifi_dev_tx(trans->dev, skb,
+ iwl_pcie_get_tfd(trans, txq,
+ txq->write_ptr),
+ trans_pcie->tfd_size,
+ &dev_cmd->hdr, IWL_FIRST_TB_SIZE + tb1_len,
+ hdr_len);
+
/*
* If gso_size wasn't set, don't give the frame "amsdu treatment"
* (adding subframes, etc.).
@@ -2426,9 +2422,18 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
out_meta, dev_cmd,
tb1_len)))
goto out_err;
- } else if (unlikely(iwl_fill_data_tbs(trans, skb, txq, hdr_len,
- out_meta, dev_cmd, tb1_len))) {
- goto out_err;
+ } else {
+ struct sk_buff *frag;
+
+ if (unlikely(iwl_fill_data_tbs(trans, skb, txq, hdr_len,
+ out_meta)))
+ goto out_err;
+
+ skb_walk_frags(skb, frag) {
+ if (unlikely(iwl_fill_data_tbs(trans, frag, txq, 0,
+ out_meta)))
+ goto out_err;
+ }
}
/* building the A-MSDU might have changed this data, so memcpy it now */
@@ -2473,6 +2478,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
spin_unlock(&txq->lock);
return 0;
out_err:
+ iwl_pcie_tfd_unmap(trans, out_meta, txq, txq->write_ptr);
spin_unlock(&txq->lock);
return -1;
}
diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c b/drivers/net/wireless/intersil/orinoco/orinoco_usb.c
index 94ad6fe29e69..21bb68457cfe 100644
--- a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c
+++ b/drivers/net/wireless/intersil/orinoco/orinoco_usb.c
@@ -73,10 +73,6 @@
#define URB_ASYNC_UNLINK 0
#endif
-/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */
-static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
-#define ENCAPS_OVERHEAD (sizeof(encaps_hdr) + 2)
-
struct header_struct {
/* 802.3 */
u8 dest[ETH_ALEN];
@@ -915,7 +911,7 @@ static int ezusb_access_ltv(struct ezusb_priv *upriv,
default:
err("%s: Unexpected context state %d", __func__,
state);
- /* fall though */
+ /* fall through */
case EZUSB_CTX_REQ_TIMEOUT:
case EZUSB_CTX_REQ_FAILED:
case EZUSB_CTX_RESP_TIMEOUT:
diff --git a/drivers/net/wireless/intersil/p54/txrx.c b/drivers/net/wireless/intersil/p54/txrx.c
index 3a4214d362ff..790784568ad2 100644
--- a/drivers/net/wireless/intersil/p54/txrx.c
+++ b/drivers/net/wireless/intersil/p54/txrx.c
@@ -121,8 +121,8 @@ static int p54_assign_address(struct p54_common *priv, struct sk_buff *skb)
}
if (unlikely(!target_skb)) {
if (priv->rx_end - last_addr >= len) {
- target_skb = priv->tx_queue.prev;
- if (!skb_queue_empty(&priv->tx_queue)) {
+ target_skb = skb_peek_tail(&priv->tx_queue);
+ if (target_skb) {
info = IEEE80211_SKB_CB(target_skb);
range = (void *)info->rate_driver_data;
target_addr = range->end_addr;
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 1068757ec42e..aa8058264d5b 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -3,6 +3,7 @@
* Copyright (c) 2008, Jouni Malinen <j@w1.fi>
* Copyright (c) 2011, Javier Lopez <jlopex@gmail.com>
* Copyright (c) 2016 - 2017 Intel Deutschland GmbH
+ * Copyright (C) 2018 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -494,7 +495,6 @@ static const struct ieee80211_iface_combination hwsim_if_comb_p2p_dev[] = {
static spinlock_t hwsim_radio_lock;
static LIST_HEAD(hwsim_radios);
-static struct workqueue_struct *hwsim_wq;
static struct rhashtable hwsim_radios_rht;
static int hwsim_radio_idx;
static int hwsim_radios_generation = 1;
@@ -520,7 +520,6 @@ struct mac80211_hwsim_data {
int channels, idx;
bool use_chanctx;
bool destroy_on_close;
- struct work_struct destroy_work;
u32 portid;
char alpha2[2];
const struct ieee80211_regdomain *regd;
@@ -2529,23 +2528,20 @@ static const struct ieee80211_sband_iftype_data he_capa_2ghz = {
IEEE80211_HE_MAC_CAP0_HTC_HE,
.mac_cap_info[1] =
IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US |
- IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_8,
+ IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8,
.mac_cap_info[2] =
IEEE80211_HE_MAC_CAP2_BSR |
IEEE80211_HE_MAC_CAP2_MU_CASCADING |
IEEE80211_HE_MAC_CAP2_ACK_EN,
.mac_cap_info[3] =
- IEEE80211_HE_MAC_CAP3_GRP_ADDR_MULTI_STA_BA_DL_MU |
IEEE80211_HE_MAC_CAP3_OMI_CONTROL |
- IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_VHT_2,
+ IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2,
.mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU,
- .phy_cap_info[0] =
- IEEE80211_HE_PHY_CAP0_DUAL_BAND,
.phy_cap_info[1] =
IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK |
IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A |
IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD |
- IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_MAX_NSTS,
+ IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS,
.phy_cap_info[2] =
IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US |
IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ |
@@ -2579,18 +2575,16 @@ static const struct ieee80211_sband_iftype_data he_capa_5ghz = {
IEEE80211_HE_MAC_CAP0_HTC_HE,
.mac_cap_info[1] =
IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US |
- IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_8,
+ IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8,
.mac_cap_info[2] =
IEEE80211_HE_MAC_CAP2_BSR |
IEEE80211_HE_MAC_CAP2_MU_CASCADING |
IEEE80211_HE_MAC_CAP2_ACK_EN,
.mac_cap_info[3] =
- IEEE80211_HE_MAC_CAP3_GRP_ADDR_MULTI_STA_BA_DL_MU |
IEEE80211_HE_MAC_CAP3_OMI_CONTROL |
- IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_VHT_2,
+ IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2,
.mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU,
.phy_cap_info[0] =
- IEEE80211_HE_PHY_CAP0_DUAL_BAND |
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G,
@@ -2598,7 +2592,7 @@ static const struct ieee80211_sband_iftype_data he_capa_5ghz = {
IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK |
IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A |
IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD |
- IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_MAX_NSTS,
+ IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS,
.phy_cap_info[2] =
IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US |
IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ |
@@ -2935,8 +2929,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
hwsim_radios_generation++;
spin_unlock_bh(&hwsim_radio_lock);
- if (idx > 0)
- hwsim_mcast_new_radio(idx, info, param);
+ hwsim_mcast_new_radio(idx, info, param);
return idx;
@@ -3565,30 +3558,27 @@ static struct genl_family hwsim_genl_family __ro_after_init = {
.n_mcgrps = ARRAY_SIZE(hwsim_mcgrps),
};
-static void destroy_radio(struct work_struct *work)
-{
- struct mac80211_hwsim_data *data =
- container_of(work, struct mac80211_hwsim_data, destroy_work);
-
- hwsim_radios_generation++;
- mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy), NULL);
-}
-
static void remove_user_radios(u32 portid)
{
struct mac80211_hwsim_data *entry, *tmp;
+ LIST_HEAD(list);
spin_lock_bh(&hwsim_radio_lock);
list_for_each_entry_safe(entry, tmp, &hwsim_radios, list) {
if (entry->destroy_on_close && entry->portid == portid) {
- list_del(&entry->list);
+ list_move(&entry->list, &list);
rhashtable_remove_fast(&hwsim_radios_rht, &entry->rht,
hwsim_rht_params);
- INIT_WORK(&entry->destroy_work, destroy_radio);
- queue_work(hwsim_wq, &entry->destroy_work);
+ hwsim_radios_generation++;
}
}
spin_unlock_bh(&hwsim_radio_lock);
+
+ list_for_each_entry_safe(entry, tmp, &list, list) {
+ list_del(&entry->list);
+ mac80211_hwsim_del_radio(entry, wiphy_name(entry->hw->wiphy),
+ NULL);
+ }
}
static int mac80211_hwsim_netlink_notify(struct notifier_block *nb,
@@ -3646,6 +3636,7 @@ static __net_init int hwsim_init_net(struct net *net)
static void __net_exit hwsim_exit_net(struct net *net)
{
struct mac80211_hwsim_data *data, *tmp;
+ LIST_HEAD(list);
spin_lock_bh(&hwsim_radio_lock);
list_for_each_entry_safe(data, tmp, &hwsim_radios, list) {
@@ -3656,17 +3647,19 @@ static void __net_exit hwsim_exit_net(struct net *net)
if (data->netgroup == hwsim_net_get_netgroup(&init_net))
continue;
- list_del(&data->list);
+ list_move(&data->list, &list);
rhashtable_remove_fast(&hwsim_radios_rht, &data->rht,
hwsim_rht_params);
hwsim_radios_generation++;
- spin_unlock_bh(&hwsim_radio_lock);
+ }
+ spin_unlock_bh(&hwsim_radio_lock);
+
+ list_for_each_entry_safe(data, tmp, &list, list) {
+ list_del(&data->list);
mac80211_hwsim_del_radio(data,
wiphy_name(data->hw->wiphy),
NULL);
- spin_lock_bh(&hwsim_radio_lock);
}
- spin_unlock_bh(&hwsim_radio_lock);
ida_simple_remove(&hwsim_netgroup_ida, hwsim_net_get_netgroup(net));
}
@@ -3698,13 +3691,9 @@ static int __init init_mac80211_hwsim(void)
spin_lock_init(&hwsim_radio_lock);
- hwsim_wq = alloc_workqueue("hwsim_wq", 0, 0);
- if (!hwsim_wq)
- return -ENOMEM;
-
err = rhashtable_init(&hwsim_radios_rht, &hwsim_rht_params);
if (err)
- goto out_free_wq;
+ return err;
err = register_pernet_device(&hwsim_net_ops);
if (err)
@@ -3835,8 +3824,6 @@ out_unregister_pernet:
unregister_pernet_device(&hwsim_net_ops);
out_free_rht:
rhashtable_destroy(&hwsim_radios_rht);
-out_free_wq:
- destroy_workqueue(hwsim_wq);
return err;
}
module_init(init_mac80211_hwsim);
@@ -3848,12 +3835,10 @@ static void __exit exit_mac80211_hwsim(void)
hwsim_exit_netlink();
mac80211_hwsim_free();
- flush_workqueue(hwsim_wq);
rhashtable_destroy(&hwsim_radios_rht);
unregister_netdev(hwsim_mon);
platform_driver_unregister(&mac80211_hwsim_driver);
unregister_pernet_device(&hwsim_net_ops);
- destroy_workqueue(hwsim_wq);
}
module_exit(exit_mac80211_hwsim);
diff --git a/drivers/net/wireless/marvell/libertas/if_cs.c b/drivers/net/wireless/marvell/libertas/if_cs.c
index 7d88223f890b..cebf03c6a622 100644
--- a/drivers/net/wireless/marvell/libertas/if_cs.c
+++ b/drivers/net/wireless/marvell/libertas/if_cs.c
@@ -900,8 +900,8 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
/* Make this card known to the libertas driver */
priv = lbs_add_card(card, &p_dev->dev);
- if (!priv) {
- ret = -ENOMEM;
+ if (IS_ERR(priv)) {
+ ret = PTR_ERR(priv);
goto out2;
}
diff --git a/drivers/net/wireless/marvell/libertas/if_sdio.c b/drivers/net/wireless/marvell/libertas/if_sdio.c
index 43743c26c071..8d98e7fdd27c 100644
--- a/drivers/net/wireless/marvell/libertas/if_sdio.c
+++ b/drivers/net/wireless/marvell/libertas/if_sdio.c
@@ -1206,8 +1206,8 @@ static int if_sdio_probe(struct sdio_func *func,
priv = lbs_add_card(card, &func->dev);
- if (!priv) {
- ret = -ENOMEM;
+ if (IS_ERR(priv)) {
+ ret = PTR_ERR(priv);
goto free;
}
@@ -1317,6 +1317,10 @@ static int if_sdio_suspend(struct device *dev)
if (priv->wol_criteria == EHS_REMOVE_WAKEUP) {
dev_info(dev, "Suspend without wake params -- powering down card\n");
if (priv->fw_ready) {
+ ret = lbs_suspend(priv);
+ if (ret)
+ return ret;
+
priv->power_up_on_resume = true;
if_sdio_power_off(card);
}
diff --git a/drivers/net/wireless/marvell/libertas/if_spi.c b/drivers/net/wireless/marvell/libertas/if_spi.c
index e9aec6cb1105..504d6e096476 100644
--- a/drivers/net/wireless/marvell/libertas/if_spi.c
+++ b/drivers/net/wireless/marvell/libertas/if_spi.c
@@ -1146,8 +1146,8 @@ static int if_spi_probe(struct spi_device *spi)
* This will call alloc_etherdev.
*/
priv = lbs_add_card(card, &spi->dev);
- if (!priv) {
- err = -ENOMEM;
+ if (IS_ERR(priv)) {
+ err = PTR_ERR(priv);
goto free_card;
}
card->priv = priv;
diff --git a/drivers/net/wireless/marvell/libertas/if_usb.c b/drivers/net/wireless/marvell/libertas/if_usb.c
index c67a8e7be310..220dcdee8d2b 100644
--- a/drivers/net/wireless/marvell/libertas/if_usb.c
+++ b/drivers/net/wireless/marvell/libertas/if_usb.c
@@ -254,8 +254,11 @@ static int if_usb_probe(struct usb_interface *intf,
goto dealloc;
}
- if (!(priv = lbs_add_card(cardp, &intf->dev)))
+ priv = lbs_add_card(cardp, &intf->dev);
+ if (IS_ERR(priv)) {
+ r = PTR_ERR(priv);
goto err_add_card;
+ }
cardp->priv = priv;
@@ -456,8 +459,6 @@ static int __if_usb_submit_rx_urb(struct if_usb_card *cardp,
MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, callbackfn,
cardp);
- cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET;
-
lbs_deb_usb2(&cardp->udev->dev, "Pointer for rx_urb %p\n", cardp->rx_urb);
if ((ret = usb_submit_urb(cardp->rx_urb, GFP_ATOMIC))) {
lbs_deb_usbd(&cardp->udev->dev, "Submit Rx URB failed: %d\n", ret);
diff --git a/drivers/net/wireless/marvell/libertas/main.c b/drivers/net/wireless/marvell/libertas/main.c
index f22e1c220cba..f7db60bc7c7f 100644
--- a/drivers/net/wireless/marvell/libertas/main.c
+++ b/drivers/net/wireless/marvell/libertas/main.c
@@ -907,25 +907,29 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
struct net_device *dev;
struct wireless_dev *wdev;
struct lbs_private *priv = NULL;
+ int err;
/* Allocate an Ethernet device and register it */
wdev = lbs_cfg_alloc(dmdev);
if (IS_ERR(wdev)) {
+ err = PTR_ERR(wdev);
pr_err("cfg80211 init failed\n");
- goto done;
+ goto err_cfg;
}
wdev->iftype = NL80211_IFTYPE_STATION;
priv = wdev_priv(wdev);
priv->wdev = wdev;
- if (lbs_init_adapter(priv)) {
+ err = lbs_init_adapter(priv);
+ if (err) {
pr_err("failed to initialize adapter structure\n");
goto err_wdev;
}
dev = alloc_netdev(0, "wlan%d", NET_NAME_UNKNOWN, ether_setup);
if (!dev) {
+ err = -ENOMEM;
dev_err(dmdev, "no memory for network device instance\n");
goto err_adapter;
}
@@ -949,6 +953,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
init_waitqueue_head(&priv->waitq);
priv->main_thread = kthread_run(lbs_thread, dev, "lbs_main");
if (IS_ERR(priv->main_thread)) {
+ err = PTR_ERR(priv->main_thread);
lbs_deb_thread("Error creating main thread.\n");
goto err_ndev;
}
@@ -961,7 +966,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
priv->wol_gap = 20;
priv->ehs_remove_supported = true;
- goto done;
+ return priv;
err_ndev:
free_netdev(dev);
@@ -972,10 +977,8 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
err_wdev:
lbs_cfg_free(priv);
- priv = NULL;
-
-done:
- return priv;
+ err_cfg:
+ return ERR_PTR(err);
}
EXPORT_SYMBOL_GPL(lbs_add_card);
diff --git a/drivers/net/wireless/marvell/libertas_tf/if_usb.c b/drivers/net/wireless/marvell/libertas_tf/if_usb.c
index e92fc5001171..789337ea676a 100644
--- a/drivers/net/wireless/marvell/libertas_tf/if_usb.c
+++ b/drivers/net/wireless/marvell/libertas_tf/if_usb.c
@@ -605,9 +605,10 @@ static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff,
{
unsigned long flags;
- if (recvlength > LBS_CMD_BUFFER_SIZE) {
+ if (recvlength < MESSAGE_HEADER_LEN ||
+ recvlength > LBS_CMD_BUFFER_SIZE) {
lbtf_deb_usbd(&cardp->udev->dev,
- "The receive buffer is too large\n");
+ "The receive buffer is invalid: %d\n", recvlength);
kfree_skb(skb);
return;
}
diff --git a/drivers/net/wireless/marvell/mwifiex/usb.c b/drivers/net/wireless/marvell/mwifiex/usb.c
index 433c6a16870b..d445acc4786b 100644
--- a/drivers/net/wireless/marvell/mwifiex/usb.c
+++ b/drivers/net/wireless/marvell/mwifiex/usb.c
@@ -298,6 +298,19 @@ static int mwifiex_usb_submit_rx_urb(struct urb_context *ctx, int size)
struct mwifiex_adapter *adapter = ctx->adapter;
struct usb_card_rec *card = (struct usb_card_rec *)adapter->card;
+ if (test_bit(MWIFIEX_IS_SUSPENDED, &adapter->work_flags)) {
+ if (card->rx_cmd_ep == ctx->ep) {
+ mwifiex_dbg(adapter, INFO, "%s: free rx_cmd skb\n",
+ __func__);
+ dev_kfree_skb_any(ctx->skb);
+ ctx->skb = NULL;
+ }
+ mwifiex_dbg(adapter, ERROR,
+ "%s: card removed/suspended, EP %d rx_cmd URB submit skipped\n",
+ __func__, ctx->ep);
+ return -1;
+ }
+
if (card->rx_cmd_ep != ctx->ep) {
ctx->skb = dev_alloc_skb(size);
if (!ctx->skb) {
diff --git a/drivers/net/wireless/mediatek/mt76/Kconfig b/drivers/net/wireless/mediatek/mt76/Kconfig
index b6c5f17dca30..0ccbcd7e887d 100644
--- a/drivers/net/wireless/mediatek/mt76/Kconfig
+++ b/drivers/net/wireless/mediatek/mt76/Kconfig
@@ -5,33 +5,13 @@ config MT76_USB
tristate
depends on MT76_CORE
-config MT76x2_COMMON
+config MT76x02_LIB
tristate
- depends on MT76_CORE
-
-config MT76x0U
- tristate "MediaTek MT76x0U (USB) support"
- select MT76_CORE
- depends on MAC80211
- depends on USB
- help
- This adds support for MT7610U-based wireless USB dongles.
-
-config MT76x2E
- tristate "MediaTek MT76x2E (PCIe) support"
select MT76_CORE
- select MT76x2_COMMON
- depends on MAC80211
- depends on PCI
- ---help---
- This adds support for MT7612/MT7602/MT7662-based wireless PCIe devices.
-config MT76x2U
- tristate "MediaTek MT76x2U (USB) support"
- select MT76_CORE
+config MT76x02_USB
+ tristate
select MT76_USB
- select MT76x2_COMMON
- depends on MAC80211
- depends on USB
- help
- This adds support for MT7612U-based wireless USB dongles.
+
+source "drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig"
+source "drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig"
diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile
index 158d10d2716c..9b8d7488c545 100644
--- a/drivers/net/wireless/mediatek/mt76/Makefile
+++ b/drivers/net/wireless/mediatek/mt76/Makefile
@@ -1,9 +1,7 @@
obj-$(CONFIG_MT76_CORE) += mt76.o
obj-$(CONFIG_MT76_USB) += mt76-usb.o
-obj-$(CONFIG_MT76x0U) += mt76x0/
-obj-$(CONFIG_MT76x2_COMMON) += mt76x2-common.o
-obj-$(CONFIG_MT76x2E) += mt76x2e.o
-obj-$(CONFIG_MT76x2U) += mt76x2u.o
+obj-$(CONFIG_MT76x02_LIB) += mt76x02-lib.o
+obj-$(CONFIG_MT76x02_USB) += mt76x02-usb.o
mt76-y := \
mmio.o util.o trace.o dma.o mac80211.o debugfs.o eeprom.o tx.o agg-rx.o
@@ -12,20 +10,13 @@ mt76-usb-y := usb.o usb_trace.o usb_mcu.o
CFLAGS_trace.o := -I$(src)
CFLAGS_usb_trace.o := -I$(src)
+CFLAGS_mt76x02_trace.o := -I$(src)
-mt76x2-common-y := \
- mt76x2_eeprom.o mt76x2_tx_common.o mt76x2_mac_common.o \
- mt76x2_init_common.o mt76x2_common.o mt76x2_phy_common.o \
- mt76x2_debugfs.o
+mt76x02-lib-y := mt76x02_util.o mt76x02_mac.o mt76x02_mcu.o \
+ mt76x02_eeprom.o mt76x02_phy.o mt76x02_mmio.o \
+ mt76x02_txrx.o mt76x02_trace.o
-mt76x2e-y := \
- mt76x2_pci.o mt76x2_dma.o \
- mt76x2_main.o mt76x2_init.o mt76x2_tx.o \
- mt76x2_core.o mt76x2_mac.o mt76x2_mcu.o mt76x2_phy.o \
- mt76x2_dfs.o mt76x2_trace.o
+mt76x02-usb-y := mt76x02_usb_mcu.o mt76x02_usb_core.o
-mt76x2u-y := \
- mt76x2_usb.o mt76x2u_init.o mt76x2u_main.o mt76x2u_mac.o \
- mt76x2u_mcu.o mt76x2u_phy.o mt76x2u_core.o
-
-CFLAGS_mt76x2_trace.o := -I$(src)
+obj-$(CONFIG_MT76x0_COMMON) += mt76x0/
+obj-$(CONFIG_MT76x2_COMMON) += mt76x2/
diff --git a/drivers/net/wireless/mediatek/mt76/debugfs.c b/drivers/net/wireless/mediatek/mt76/debugfs.c
index a38d05dea599..a5adf22c3ffa 100644
--- a/drivers/net/wireless/mediatek/mt76/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/debugfs.c
@@ -56,6 +56,35 @@ mt76_queues_read(struct seq_file *s, void *data)
return 0;
}
+void mt76_seq_puts_array(struct seq_file *file, const char *str,
+ s8 *val, int len)
+{
+ int i;
+
+ seq_printf(file, "%10s:", str);
+ for (i = 0; i < len; i++)
+ seq_printf(file, " %2d", val[i]);
+ seq_puts(file, "\n");
+}
+EXPORT_SYMBOL_GPL(mt76_seq_puts_array);
+
+static int mt76_read_rate_txpower(struct seq_file *s, void *data)
+{
+ struct mt76_dev *dev = dev_get_drvdata(s->private);
+
+ mt76_seq_puts_array(s, "CCK", dev->rate_power.cck,
+ ARRAY_SIZE(dev->rate_power.cck));
+ mt76_seq_puts_array(s, "OFDM", dev->rate_power.ofdm,
+ ARRAY_SIZE(dev->rate_power.ofdm));
+ mt76_seq_puts_array(s, "STBC", dev->rate_power.stbc,
+ ARRAY_SIZE(dev->rate_power.stbc));
+ mt76_seq_puts_array(s, "HT", dev->rate_power.ht,
+ ARRAY_SIZE(dev->rate_power.ht));
+ mt76_seq_puts_array(s, "VHT", dev->rate_power.vht,
+ ARRAY_SIZE(dev->rate_power.vht));
+ return 0;
+}
+
struct dentry *mt76_register_debugfs(struct mt76_dev *dev)
{
struct dentry *dir;
@@ -72,6 +101,8 @@ struct dentry *mt76_register_debugfs(struct mt76_dev *dev)
if (dev->otp.data)
debugfs_create_blob("otp", 0400, dir, &dev->otp);
debugfs_create_devm_seqfile(dev->dev, "queues", dir, mt76_queues_read);
+ debugfs_create_devm_seqfile(dev->dev, "rate_txpower", dir,
+ mt76_read_rate_txpower);
return dir;
}
diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c
index c51da2205b93..f7fbd7016403 100644
--- a/drivers/net/wireless/mediatek/mt76/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/dma.c
@@ -322,19 +322,13 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q, bool napi)
int len = SKB_WITH_OVERHEAD(q->buf_size);
int offset = q->buf_offset;
int idx;
- void *(*alloc)(unsigned int fragsz);
-
- if (napi)
- alloc = napi_alloc_frag;
- else
- alloc = netdev_alloc_frag;
spin_lock_bh(&q->lock);
while (q->queued < q->ndesc - 1) {
struct mt76_queue_buf qbuf;
- buf = alloc(q->buf_size);
+ buf = page_frag_alloc(&q->rx_page, q->buf_size, GFP_ATOMIC);
if (!buf)
break;
@@ -361,6 +355,7 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q, bool napi)
static void
mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q)
{
+ struct page *page;
void *buf;
bool more;
@@ -373,6 +368,13 @@ mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q)
skb_free_frag(buf);
} while (1);
spin_unlock_bh(&q->lock);
+
+ if (!q->rx_page.va)
+ return;
+
+ page = virt_to_page(q->rx_page.va);
+ __page_frag_cache_drain(page, q->rx_page.pagecnt_bias);
+ memset(&q->rx_page, 0, sizeof(q->rx_page));
}
static void
diff --git a/drivers/net/wireless/mediatek/mt76/dma.h b/drivers/net/wireless/mediatek/mt76/dma.h
index 27248e24a19b..357cc356342d 100644
--- a/drivers/net/wireless/mediatek/mt76/dma.h
+++ b/drivers/net/wireless/mediatek/mt76/dma.h
@@ -25,34 +25,6 @@
#define MT_DMA_CTL_LAST_SEC0 BIT(30)
#define MT_DMA_CTL_DMA_DONE BIT(31)
-#define MT_TXD_INFO_LEN GENMASK(15, 0)
-#define MT_TXD_INFO_NEXT_VLD BIT(16)
-#define MT_TXD_INFO_TX_BURST BIT(17)
-#define MT_TXD_INFO_80211 BIT(19)
-#define MT_TXD_INFO_TSO BIT(20)
-#define MT_TXD_INFO_CSO BIT(21)
-#define MT_TXD_INFO_WIV BIT(24)
-#define MT_TXD_INFO_QSEL GENMASK(26, 25)
-#define MT_TXD_INFO_DPORT GENMASK(29, 27)
-#define MT_TXD_INFO_TYPE GENMASK(31, 30)
-
-#define MT_RX_FCE_INFO_LEN GENMASK(13, 0)
-#define MT_RX_FCE_INFO_SELF_GEN BIT(15)
-#define MT_RX_FCE_INFO_CMD_SEQ GENMASK(19, 16)
-#define MT_RX_FCE_INFO_EVT_TYPE GENMASK(23, 20)
-#define MT_RX_FCE_INFO_PCIE_INTR BIT(24)
-#define MT_RX_FCE_INFO_QSEL GENMASK(26, 25)
-#define MT_RX_FCE_INFO_D_PORT GENMASK(29, 27)
-#define MT_RX_FCE_INFO_TYPE GENMASK(31, 30)
-
-/* MCU request message header */
-#define MT_MCU_MSG_LEN GENMASK(15, 0)
-#define MT_MCU_MSG_CMD_SEQ GENMASK(19, 16)
-#define MT_MCU_MSG_CMD_TYPE GENMASK(26, 20)
-#define MT_MCU_MSG_PORT GENMASK(29, 27)
-#define MT_MCU_MSG_TYPE GENMASK(31, 30)
-#define MT_MCU_MSG_TYPE_CMD BIT(30)
-
#define MT_DMA_HDR_LEN 4
#define MT_RX_INFO_LEN 4
#define MT_FCE_INFO_LEN 4
@@ -65,14 +37,21 @@ struct mt76_desc {
__le32 info;
} __packed __aligned(4);
-enum dma_msg_port {
- WLAN_PORT,
- CPU_RX_PORT,
- CPU_TX_PORT,
- HOST_PORT,
- VIRTUAL_CPU_RX_PORT,
- VIRTUAL_CPU_TX_PORT,
- DISCARD,
+enum mt76_qsel {
+ MT_QSEL_MGMT,
+ MT_QSEL_HCCA,
+ MT_QSEL_EDCA,
+ MT_QSEL_EDCA_2,
+};
+
+enum mt76_mcu_evt_type {
+ EVT_CMD_DONE,
+ EVT_CMD_ERROR,
+ EVT_CMD_RETRY,
+ EVT_EVENT_PWR_RSP,
+ EVT_EVENT_WOW_RSP,
+ EVT_EVENT_CARRIER_DETECT_RSP,
+ EVT_EVENT_DFS_DETECT_RSP,
};
int mt76_dma_attach(struct mt76_dev *dev);
diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c
index 029d54bce9e8..2a699e8b79bf 100644
--- a/drivers/net/wireless/mediatek/mt76/mac80211.c
+++ b/drivers/net/wireless/mediatek/mt76/mac80211.c
@@ -283,6 +283,7 @@ mt76_alloc_device(unsigned int size, const struct ieee80211_ops *ops)
spin_lock_init(&dev->rx_lock);
spin_lock_init(&dev->lock);
spin_lock_init(&dev->cc_lock);
+ mutex_init(&dev->mutex);
init_waitqueue_head(&dev->tx_wait);
return dev;
@@ -305,6 +306,8 @@ int mt76_register_device(struct mt76_dev *dev, bool vht,
wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
+ wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
+
wiphy->available_antennas_tx = dev->antenna_mask;
wiphy->available_antennas_rx = dev->antenna_mask;
@@ -472,7 +475,7 @@ void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid,
}
EXPORT_SYMBOL(mt76_wcid_key_setup);
-static struct ieee80211_sta *mt76_rx_convert(struct sk_buff *skb)
+struct ieee80211_sta *mt76_rx_convert(struct sk_buff *skb)
{
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
struct mt76_rx_status mstat;
@@ -497,6 +500,7 @@ static struct ieee80211_sta *mt76_rx_convert(struct sk_buff *skb)
return wcid_to_sta(mstat.wcid);
}
+EXPORT_SYMBOL(mt76_rx_convert);
static int
mt76_check_ccmp_pn(struct sk_buff *skb)
@@ -546,6 +550,12 @@ mt76_check_ps(struct mt76_dev *dev, struct sk_buff *skb)
struct mt76_wcid *wcid = status->wcid;
bool ps;
+ if (ieee80211_is_pspoll(hdr->frame_control) && !wcid) {
+ sta = ieee80211_find_sta_by_ifaddr(dev->hw, hdr->addr2, NULL);
+ if (sta)
+ wcid = status->wcid = (struct mt76_wcid *) sta->drv_priv;
+ }
+
if (!wcid || !wcid->sta)
return;
diff --git a/drivers/net/wireless/mediatek/mt76/mmio.c b/drivers/net/wireless/mediatek/mt76/mmio.c
index 09a14dead6e3..1d6bbce76041 100644
--- a/drivers/net/wireless/mediatek/mt76/mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mmio.c
@@ -21,7 +21,7 @@ static u32 mt76_mmio_rr(struct mt76_dev *dev, u32 offset)
{
u32 val;
- val = ioread32(dev->regs + offset);
+ val = ioread32(dev->mmio.regs + offset);
trace_reg_rr(dev, offset, val);
return val;
@@ -30,7 +30,7 @@ static u32 mt76_mmio_rr(struct mt76_dev *dev, u32 offset)
static void mt76_mmio_wr(struct mt76_dev *dev, u32 offset, u32 val)
{
trace_reg_wr(dev, offset, val);
- iowrite32(val, dev->regs + offset);
+ iowrite32(val, dev->mmio.regs + offset);
}
static u32 mt76_mmio_rmw(struct mt76_dev *dev, u32 offset, u32 mask, u32 val)
@@ -43,7 +43,31 @@ static u32 mt76_mmio_rmw(struct mt76_dev *dev, u32 offset, u32 mask, u32 val)
static void mt76_mmio_copy(struct mt76_dev *dev, u32 offset, const void *data,
int len)
{
- __iowrite32_copy(dev->regs + offset, data, len >> 2);
+ __iowrite32_copy(dev->mmio.regs + offset, data, len >> 2);
+}
+
+static int mt76_mmio_wr_rp(struct mt76_dev *dev, u32 base,
+ const struct mt76_reg_pair *data, int len)
+{
+ while (len > 0) {
+ mt76_mmio_wr(dev, data->reg, data->value);
+ data++;
+ len--;
+ }
+
+ return 0;
+}
+
+static int mt76_mmio_rd_rp(struct mt76_dev *dev, u32 base,
+ struct mt76_reg_pair *data, int len)
+{
+ while (len > 0) {
+ data->value = mt76_mmio_rr(dev, data->reg);
+ data++;
+ len--;
+ }
+
+ return 0;
}
void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs)
@@ -53,9 +77,17 @@ void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs)
.rmw = mt76_mmio_rmw,
.wr = mt76_mmio_wr,
.copy = mt76_mmio_copy,
+ .wr_rp = mt76_mmio_wr_rp,
+ .rd_rp = mt76_mmio_rd_rp,
+ .type = MT76_BUS_MMIO,
};
dev->bus = &mt76_mmio_ops;
- dev->regs = regs;
+ dev->mmio.regs = regs;
+
+ skb_queue_head_init(&dev->mmio.mcu.res_q);
+ init_waitqueue_head(&dev->mmio.mcu.wait);
+ spin_lock_init(&dev->mmio.irq_lock);
+ mutex_init(&dev->mmio.mcu.mutex);
}
EXPORT_SYMBOL_GPL(mt76_mmio_init);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index 2eab35879163..3bfa7f5e3513 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -33,14 +33,32 @@
struct mt76_dev;
struct mt76_wcid;
+struct mt76_reg_pair {
+ u32 reg;
+ u32 value;
+};
+
+enum mt76_bus_type {
+ MT76_BUS_MMIO,
+ MT76_BUS_USB,
+};
+
struct mt76_bus_ops {
u32 (*rr)(struct mt76_dev *dev, u32 offset);
void (*wr)(struct mt76_dev *dev, u32 offset, u32 val);
u32 (*rmw)(struct mt76_dev *dev, u32 offset, u32 mask, u32 val);
void (*copy)(struct mt76_dev *dev, u32 offset, const void *data,
int len);
+ int (*wr_rp)(struct mt76_dev *dev, u32 base,
+ const struct mt76_reg_pair *rp, int len);
+ int (*rd_rp)(struct mt76_dev *dev, u32 base,
+ struct mt76_reg_pair *rp, int len);
+ enum mt76_bus_type type;
};
+#define mt76_is_usb(dev) ((dev)->mt76.bus->type == MT76_BUS_USB)
+#define mt76_is_mmio(dev) ((dev)->mt76.bus->type == MT76_BUS_MMIO)
+
enum mt76_txq_id {
MT_TXQ_VO = IEEE80211_AC_VO,
MT_TXQ_VI = IEEE80211_AC_VI,
@@ -112,6 +130,18 @@ struct mt76_queue {
dma_addr_t desc_dma;
struct sk_buff *rx_head;
+ struct page_frag_cache rx_page;
+ spinlock_t rx_page_lock;
+};
+
+struct mt76_mcu_ops {
+ struct sk_buff *(*mcu_msg_alloc)(const void *data, int len);
+ int (*mcu_send_msg)(struct mt76_dev *dev, struct sk_buff *skb,
+ int cmd, bool wait_resp);
+ int (*mcu_wr_rp)(struct mt76_dev *dev, u32 base,
+ const struct mt76_reg_pair *rp, int len);
+ int (*mcu_rd_rp)(struct mt76_dev *dev, u32 base,
+ struct mt76_reg_pair *rp, int len);
};
struct mt76_queue_ops {
@@ -143,6 +173,8 @@ enum mt76_wcid_flags {
MT_WCID_FLAG_PS,
};
+#define MT76_N_WCIDS 128
+
struct mt76_wcid {
struct mt76_rx_tid __rcu *aggr[IEEE80211_NUM_TIDS];
@@ -210,7 +242,6 @@ enum {
MT76_OFFCHANNEL,
MT76_REMOVED,
MT76_READING_STATS,
- MT76_MORE_STATS,
};
struct mt76_hw_cap {
@@ -252,6 +283,19 @@ struct mt76_sband {
struct mt76_channel_state *chan;
};
+struct mt76_rate_power {
+ union {
+ struct {
+ s8 cck[4];
+ s8 ofdm[8];
+ s8 stbc[10];
+ s8 ht[16];
+ s8 vht[10];
+ };
+ s8 all[48];
+ };
+};
+
/* addr req mask */
#define MT_VEND_TYPE_EEPROM BIT(31)
#define MT_VEND_TYPE_CFG BIT(30)
@@ -307,7 +351,27 @@ struct mt76_usb {
struct completion cmpl;
struct mt76u_buf res;
u32 msg_seq;
+
+ /* multiple reads */
+ struct mt76_reg_pair *rp;
+ int rp_len;
+ u32 base;
+ bool burst;
+ } mcu;
+};
+
+struct mt76_mmio {
+ struct mt76e_mcu {
+ struct mutex mutex;
+
+ wait_queue_head_t wait;
+ struct sk_buff_head res_q;
+
+ u32 msg_seq;
} mcu;
+ void __iomem *regs;
+ spinlock_t irq_lock;
+ u32 irqmask;
};
struct mt76_dev {
@@ -317,9 +381,12 @@ struct mt76_dev {
spinlock_t lock;
spinlock_t cc_lock;
+
+ struct mutex mutex;
+
const struct mt76_bus_ops *bus;
const struct mt76_driver_ops *drv;
- void __iomem *regs;
+ const struct mt76_mcu_ops *mcu_ops;
struct device *dev;
struct net_device napi_dev;
@@ -334,11 +401,17 @@ struct mt76_dev {
wait_queue_head_t tx_wait;
+ unsigned long wcid_mask[MT76_N_WCIDS / BITS_PER_LONG];
+
+ struct mt76_wcid global_wcid;
+ struct mt76_wcid __rcu *wcid[MT76_N_WCIDS];
+
u8 macaddr[ETH_ALEN];
u32 rev;
unsigned long state;
u8 antenna_mask;
+ u16 chainmask;
struct mt76_sband sband_2g;
struct mt76_sband sband_5g;
@@ -346,6 +419,10 @@ struct mt76_dev {
struct debugfs_blob_wrapper otp;
struct mt76_hw_cap cap;
+ struct mt76_rate_power rate_power;
+ int txpower_conf;
+ int txpower_cur;
+
u32 debugfs_reg;
struct led_classdev led_cdev;
@@ -353,7 +430,12 @@ struct mt76_dev {
bool led_al;
u8 led_pin;
- struct mt76_usb usb;
+ u32 rxfilter;
+
+ union {
+ struct mt76_mmio mmio;
+ struct mt76_usb usb;
+ };
};
enum mt76_phy_type {
@@ -364,18 +446,6 @@ enum mt76_phy_type {
MT_PHY_TYPE_VHT,
};
-struct mt76_rate_power {
- union {
- struct {
- s8 cck[4];
- s8 ofdm[8];
- s8 ht[16];
- s8 vht[10];
- };
- s8 all[38];
- };
-};
-
struct mt76_rx_status {
struct mt76_wcid *wcid;
@@ -399,10 +469,23 @@ struct mt76_rx_status {
s8 chain_signal[IEEE80211_MAX_CHAINS];
};
+#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__)
+#define __mt76_wr_copy(dev, ...) (dev)->bus->copy((dev), __VA_ARGS__)
+
+#define __mt76_set(dev, offset, val) __mt76_rmw(dev, offset, 0, val)
+#define __mt76_clear(dev, offset, val) __mt76_rmw(dev, offset, val, 0)
+
#define mt76_rr(dev, ...) (dev)->mt76.bus->rr(&((dev)->mt76), __VA_ARGS__)
#define mt76_wr(dev, ...) (dev)->mt76.bus->wr(&((dev)->mt76), __VA_ARGS__)
#define mt76_rmw(dev, ...) (dev)->mt76.bus->rmw(&((dev)->mt76), __VA_ARGS__)
#define mt76_wr_copy(dev, ...) (dev)->mt76.bus->copy(&((dev)->mt76), __VA_ARGS__)
+#define mt76_wr_rp(dev, ...) (dev)->mt76.bus->wr_rp(&((dev)->mt76), __VA_ARGS__)
+#define mt76_rd_rp(dev, ...) (dev)->mt76.bus->rd_rp(&((dev)->mt76), __VA_ARGS__)
+
+#define mt76_mcu_msg_alloc(dev, ...) (dev)->mt76.mcu_ops->mcu_msg_alloc(__VA_ARGS__)
+#define mt76_mcu_send_msg(dev, ...) (dev)->mt76.mcu_ops->mcu_send_msg(&((dev)->mt76), __VA_ARGS__)
#define mt76_set(dev, offset, val) mt76_rmw(dev, offset, 0, val)
#define mt76_clear(dev, offset, val) mt76_rmw(dev, offset, val, 0)
@@ -413,6 +496,9 @@ struct mt76_rx_status {
#define mt76_rmw_field(_dev, _reg, _field, _val) \
mt76_rmw(_dev, _reg, _field, FIELD_PREP(_field, _val))
+#define __mt76_rmw_field(_dev, _reg, _field, _val) \
+ __mt76_rmw(_dev, _reg, _field, FIELD_PREP(_field, _val))
+
#define mt76_hw(dev) (dev)->mt76.hw
bool __mt76_poll(struct mt76_dev *dev, u32 offset, u32 mask, u32 val,
@@ -469,6 +555,8 @@ int mt76_register_device(struct mt76_dev *dev, bool vht,
void mt76_unregister_device(struct mt76_dev *dev);
struct dentry *mt76_register_debugfs(struct mt76_dev *dev);
+void mt76_seq_puts_array(struct seq_file *file, const char *str,
+ s8 *val, int len);
int mt76_eeprom_init(struct mt76_dev *dev, int len);
void mt76_eeprom_override(struct mt76_dev *dev);
@@ -485,13 +573,7 @@ static inline int mt76_decr(int val, int size)
return (val - 1) & (size - 1);
}
-/* Hardware uses mirrored order of queues with Q3
- * having the highest priority
- */
-static inline u8 q2hwq(u8 q)
-{
- return q ^ 0x3;
-}
+u8 mt76_ac_to_hwq(u8 ac);
static inline struct ieee80211_txq *
mtxq_to_txq(struct mt76_txq *mtxq)
@@ -543,6 +625,8 @@ void mt76_rx_aggr_stop(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tid);
void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid,
struct ieee80211_key_conf *key);
+struct ieee80211_sta *mt76_rx_convert(struct sk_buff *skb);
+
/* internal */
void mt76_tx_free(struct mt76_dev *dev);
struct mt76_txwi_cache *mt76_get_txwi(struct mt76_dev *dev);
@@ -599,15 +683,9 @@ int mt76u_alloc_queues(struct mt76_dev *dev);
void mt76u_stop_queues(struct mt76_dev *dev);
void mt76u_stop_stat_wk(struct mt76_dev *dev);
void mt76u_queues_deinit(struct mt76_dev *dev);
-int mt76u_skb_dma_info(struct sk_buff *skb, int port, u32 flags);
-int mt76u_mcu_fw_send_data(struct mt76_dev *dev, const void *data,
- int data_len, u32 max_payload, u32 offset);
void mt76u_mcu_complete_urb(struct urb *urb);
-struct sk_buff *mt76u_mcu_msg_alloc(const void *data, int len);
-int mt76u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb,
- int cmd, bool wait_resp);
-void mt76u_mcu_fw_reset(struct mt76_dev *dev);
int mt76u_mcu_init_rx(struct mt76_dev *dev);
+void mt76u_mcu_deinit(struct mt76_dev *dev);
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig b/drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig
new file mode 100644
index 000000000000..9a6157db3893
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig
@@ -0,0 +1,20 @@
+config MT76x0_COMMON
+ tristate
+ select MT76x02_LIB
+
+config MT76x0U
+ tristate "MediaTek MT76x0U (USB) support"
+ select MT76x0_COMMON
+ select MT76x02_USB
+ depends on MAC80211
+ depends on USB
+ help
+ This adds support for MT7610U-based wireless USB dongles.
+
+config MT76x0E
+ tristate "MediaTek MT76x0E (PCIe) support"
+ select MT76x0_COMMON
+ depends on MAC80211
+ depends on PCI
+ help
+ This adds support for MT7610/MT7630-based wireless PCIe devices.
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/Makefile b/drivers/net/wireless/mediatek/mt76/mt76x0/Makefile
index 7843908261ba..20672978dceb 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/Makefile
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/Makefile
@@ -1,7 +1,12 @@
-obj-$(CONFIG_MT76x0U) += mt76x0.o
+obj-$(CONFIG_MT76x0U) += mt76x0u.o
+obj-$(CONFIG_MT76x0E) += mt76x0e.o
+obj-$(CONFIG_MT76x0_COMMON) += mt76x0-common.o
+
+mt76x0-common-y := \
+ init.o main.o trace.o eeprom.o phy.o \
+ mac.o debugfs.o
+mt76x0u-y := usb.o usb_mcu.o
+mt76x0e-y := pci.o pci_mcu.o
-mt76x0-objs = \
- usb.o init.o main.o mcu.o trace.o dma.o eeprom.o phy.o \
- mac.o util.o debugfs.o tx.o core.o
# ccflags-y := -DDEBUG
CFLAGS_trace.o := -I$(src)
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/core.c b/drivers/net/wireless/mediatek/mt76/mt76x0/core.c
deleted file mode 100644
index 892803fce842..000000000000
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/core.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
- * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include "mt76x0.h"
-
-int mt76x0_wait_asic_ready(struct mt76x0_dev *dev)
-{
- int i = 100;
- u32 val;
-
- do {
- if (test_bit(MT76_REMOVED, &dev->mt76.state))
- return -EIO;
-
- val = mt76_rr(dev, MT_MAC_CSR0);
- if (val && ~val)
- return 0;
-
- udelay(10);
- } while (i--);
-
- return -EIO;
-}
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c
index e7a77a886068..3224e5b1a1e5 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c
@@ -19,29 +19,9 @@
#include "eeprom.h"
static int
-mt76_reg_set(void *data, u64 val)
-{
- struct mt76x0_dev *dev = data;
-
- mt76_wr(dev, dev->debugfs_reg, val);
- return 0;
-}
-
-static int
-mt76_reg_get(void *data, u64 *val)
-{
- struct mt76x0_dev *dev = data;
-
- *val = mt76_rr(dev, dev->debugfs_reg);
- return 0;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(fops_regval, mt76_reg_get, mt76_reg_set, "0x%08llx\n");
-
-static int
mt76x0_ampdu_stat_read(struct seq_file *file, void *data)
{
- struct mt76x0_dev *dev = file->private;
+ struct mt76x02_dev *dev = file->private;
int i, j;
#define stat_printf(grp, off, name) \
@@ -95,72 +75,13 @@ static const struct file_operations fops_ampdu_stat = {
.release = single_release,
};
-static int
-mt76x0_eeprom_param_read(struct seq_file *file, void *data)
-{
- struct mt76x0_dev *dev = file->private;
- int i;
-
- seq_printf(file, "RF freq offset: %hhx\n", dev->ee->rf_freq_off);
- seq_printf(file, "RSSI offset 2GHz: %hhx %hhx\n",
- dev->ee->rssi_offset_2ghz[0], dev->ee->rssi_offset_2ghz[1]);
- seq_printf(file, "RSSI offset 5GHz: %hhx %hhx %hhx\n",
- dev->ee->rssi_offset_5ghz[0], dev->ee->rssi_offset_5ghz[1],
- dev->ee->rssi_offset_5ghz[2]);
- seq_printf(file, "Temperature offset: %hhx\n", dev->ee->temp_off);
- seq_printf(file, "LNA gain 2Ghz: %hhx\n", dev->ee->lna_gain_2ghz);
- seq_printf(file, "LNA gain 5Ghz: %hhx %hhx %hhx\n",
- dev->ee->lna_gain_5ghz[0], dev->ee->lna_gain_5ghz[1],
- dev->ee->lna_gain_5ghz[2]);
- seq_printf(file, "Power Amplifier type %hhx\n", dev->ee->pa_type);
- seq_printf(file, "Reg channels: %hhu-%hhu\n", dev->ee->reg.start,
- dev->ee->reg.start + dev->ee->reg.num - 1);
-
- seq_puts(file, "Per channel power:\n");
- for (i = 0; i < 58; i++)
- seq_printf(file, "\t%d chan:%d pwr:%d\n", i, i,
- dev->ee->tx_pwr_per_chan[i]);
-
- seq_puts(file, "Per rate power 2GHz:\n");
- for (i = 0; i < 5; i++)
- seq_printf(file, "\t %d bw20:%d bw40:%d\n",
- i, dev->ee->tx_pwr_cfg_2g[i][0],
- dev->ee->tx_pwr_cfg_5g[i][1]);
-
- seq_puts(file, "Per rate power 5GHz:\n");
- for (i = 0; i < 5; i++)
- seq_printf(file, "\t %d bw20:%d bw40:%d\n",
- i, dev->ee->tx_pwr_cfg_5g[i][0],
- dev->ee->tx_pwr_cfg_5g[i][1]);
-
- return 0;
-}
-
-static int
-mt76x0_eeprom_param_open(struct inode *inode, struct file *f)
-{
- return single_open(f, mt76x0_eeprom_param_read, inode->i_private);
-}
-
-static const struct file_operations fops_eeprom_param = {
- .open = mt76x0_eeprom_param_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-void mt76x0_init_debugfs(struct mt76x0_dev *dev)
+void mt76x0_init_debugfs(struct mt76x02_dev *dev)
{
struct dentry *dir;
- dir = debugfs_create_dir("mt76x0", dev->mt76.hw->wiphy->debugfsdir);
+ dir = mt76_register_debugfs(&dev->mt76);
if (!dir)
return;
- debugfs_create_u32("regidx", S_IRUSR | S_IWUSR, dir, &dev->debugfs_reg);
- debugfs_create_file("regval", S_IRUSR | S_IWUSR, dir, dev,
- &fops_regval);
debugfs_create_file("ampdu_stat", S_IRUSR, dir, dev, &fops_ampdu_stat);
- debugfs_create_file("eeprom_param", S_IRUSR, dir, dev,
- &fops_eeprom_param);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/dma.c b/drivers/net/wireless/mediatek/mt76/mt76x0/dma.c
deleted file mode 100644
index e2efb430419b..000000000000
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/dma.c
+++ /dev/null
@@ -1,522 +0,0 @@
-/*
- * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
- * Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include "mt76x0.h"
-#include "dma.h"
-#include "usb.h"
-#include "trace.h"
-
-static int mt76x0_submit_rx_buf(struct mt76x0_dev *dev,
- struct mt76x0_dma_buf_rx *e, gfp_t gfp);
-
-static unsigned int ieee80211_get_hdrlen_from_buf(const u8 *data, unsigned len)
-{
- const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *)data;
- unsigned int hdrlen;
-
- if (unlikely(len < 10))
- return 0;
- hdrlen = ieee80211_hdrlen(hdr->frame_control);
- if (unlikely(hdrlen > len))
- return 0;
- return hdrlen;
-}
-
-static struct sk_buff *
-mt76x0_rx_skb_from_seg(struct mt76x0_dev *dev, struct mt76x0_rxwi *rxwi,
- void *data, u32 seg_len, u32 truesize, struct page *p)
-{
- struct sk_buff *skb;
- u32 true_len, hdr_len = 0, copy, frag;
-
- skb = alloc_skb(p ? 128 : seg_len, GFP_ATOMIC);
- if (!skb)
- return NULL;
-
- true_len = mt76x0_mac_process_rx(dev, skb, data, rxwi);
- if (!true_len || true_len > seg_len)
- goto bad_frame;
-
- hdr_len = ieee80211_get_hdrlen_from_buf(data, true_len);
- if (!hdr_len)
- goto bad_frame;
-
- if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_L2PAD)) {
- memcpy(skb_put(skb, hdr_len), data, hdr_len);
-
- data += hdr_len + 2;
- true_len -= hdr_len;
- hdr_len = 0;
- }
-
- /* If not doing paged RX allocated skb will always have enough space */
- copy = (true_len <= skb_tailroom(skb)) ? true_len : hdr_len + 8;
- frag = true_len - copy;
-
- memcpy(skb_put(skb, copy), data, copy);
- data += copy;
-
- if (frag) {
- skb_add_rx_frag(skb, 0, p, data - page_address(p),
- frag, truesize);
- get_page(p);
- }
-
- return skb;
-
-bad_frame:
- dev_err_ratelimited(dev->mt76.dev, "Error: incorrect frame len:%u hdr:%u\n",
- true_len, hdr_len);
- dev_kfree_skb(skb);
- return NULL;
-}
-
-static void mt76x0_rx_process_seg(struct mt76x0_dev *dev, u8 *data,
- u32 seg_len, struct page *p)
-{
- struct sk_buff *skb;
- struct mt76x0_rxwi *rxwi;
- u32 fce_info, truesize = seg_len;
-
- /* DMA_INFO field at the beginning of the segment contains only some of
- * the information, we need to read the FCE descriptor from the end.
- */
- fce_info = get_unaligned_le32(data + seg_len - MT_FCE_INFO_LEN);
- seg_len -= MT_FCE_INFO_LEN;
-
- data += MT_DMA_HDR_LEN;
- seg_len -= MT_DMA_HDR_LEN;
-
- rxwi = (struct mt76x0_rxwi *) data;
- data += sizeof(struct mt76x0_rxwi);
- seg_len -= sizeof(struct mt76x0_rxwi);
-
- if (unlikely(FIELD_GET(MT_RXD_INFO_TYPE, fce_info)))
- dev_err_once(dev->mt76.dev, "Error: RX path seen a non-pkt urb\n");
-
- trace_mt76x0_rx(&dev->mt76, rxwi, fce_info);
-
- skb = mt76x0_rx_skb_from_seg(dev, rxwi, data, seg_len, truesize, p);
- if (!skb)
- return;
-
- spin_lock(&dev->mac_lock);
- ieee80211_rx(dev->mt76.hw, skb);
- spin_unlock(&dev->mac_lock);
-}
-
-static u16 mt76x0_rx_next_seg_len(u8 *data, u32 data_len)
-{
- u32 min_seg_len = MT_DMA_HDR_LEN + MT_RX_INFO_LEN +
- sizeof(struct mt76x0_rxwi) + MT_FCE_INFO_LEN;
- u16 dma_len = get_unaligned_le16(data);
-
- if (data_len < min_seg_len ||
- WARN_ON(!dma_len) ||
- WARN_ON(dma_len + MT_DMA_HDRS > data_len) ||
- WARN_ON(dma_len & 0x3))
- return 0;
-
- return MT_DMA_HDRS + dma_len;
-}
-
-static void
-mt76x0_rx_process_entry(struct mt76x0_dev *dev, struct mt76x0_dma_buf_rx *e)
-{
- u32 seg_len, data_len = e->urb->actual_length;
- u8 *data = page_address(e->p);
- struct page *new_p = NULL;
- int cnt = 0;
-
- if (!test_bit(MT76_STATE_INITIALIZED, &dev->mt76.state))
- return;
-
- /* Copy if there is very little data in the buffer. */
- if (data_len > 512)
- new_p = dev_alloc_pages(MT_RX_ORDER);
-
- while ((seg_len = mt76x0_rx_next_seg_len(data, data_len))) {
- mt76x0_rx_process_seg(dev, data, seg_len, new_p ? e->p : NULL);
-
- data_len -= seg_len;
- data += seg_len;
- cnt++;
- }
-
- if (cnt > 1)
- trace_mt76x0_rx_dma_aggr(&dev->mt76, cnt, !!new_p);
-
- if (new_p) {
- /* we have one extra ref from the allocator */
- __free_pages(e->p, MT_RX_ORDER);
-
- e->p = new_p;
- }
-}
-
-static struct mt76x0_dma_buf_rx *
-mt76x0_rx_get_pending_entry(struct mt76x0_dev *dev)
-{
- struct mt76x0_rx_queue *q = &dev->rx_q;
- struct mt76x0_dma_buf_rx *buf = NULL;
- unsigned long flags;
-
- spin_lock_irqsave(&dev->rx_lock, flags);
-
- if (!q->pending)
- goto out;
-
- buf = &q->e[q->start];
- q->pending--;
- q->start = (q->start + 1) % q->entries;
-out:
- spin_unlock_irqrestore(&dev->rx_lock, flags);
-
- return buf;
-}
-
-static void mt76x0_complete_rx(struct urb *urb)
-{
- struct mt76x0_dev *dev = urb->context;
- struct mt76x0_rx_queue *q = &dev->rx_q;
- unsigned long flags;
-
- spin_lock_irqsave(&dev->rx_lock, flags);
-
- if (mt76x0_urb_has_error(urb))
- dev_err(dev->mt76.dev, "Error: RX urb failed:%d\n", urb->status);
- if (WARN_ONCE(q->e[q->end].urb != urb, "RX urb mismatch"))
- goto out;
-
- q->end = (q->end + 1) % q->entries;
- q->pending++;
- tasklet_schedule(&dev->rx_tasklet);
-out:
- spin_unlock_irqrestore(&dev->rx_lock, flags);
-}
-
-static void mt76x0_rx_tasklet(unsigned long data)
-{
- struct mt76x0_dev *dev = (struct mt76x0_dev *) data;
- struct mt76x0_dma_buf_rx *e;
-
- while ((e = mt76x0_rx_get_pending_entry(dev))) {
- if (e->urb->status)
- continue;
-
- mt76x0_rx_process_entry(dev, e);
- mt76x0_submit_rx_buf(dev, e, GFP_ATOMIC);
- }
-}
-
-static void mt76x0_complete_tx(struct urb *urb)
-{
- struct mt76x0_tx_queue *q = urb->context;
- struct mt76x0_dev *dev = q->dev;
- struct sk_buff *skb;
- unsigned long flags;
-
- spin_lock_irqsave(&dev->tx_lock, flags);
-
- if (mt76x0_urb_has_error(urb))
- dev_err(dev->mt76.dev, "Error: TX urb failed:%d\n", urb->status);
- if (WARN_ONCE(q->e[q->start].urb != urb, "TX urb mismatch"))
- goto out;
-
- skb = q->e[q->start].skb;
- trace_mt76x0_tx_dma_done(&dev->mt76, skb);
-
- __skb_queue_tail(&dev->tx_skb_done, skb);
- tasklet_schedule(&dev->tx_tasklet);
-
- if (q->used == q->entries - q->entries / 8)
- ieee80211_wake_queue(dev->mt76.hw, skb_get_queue_mapping(skb));
-
- q->start = (q->start + 1) % q->entries;
- q->used--;
-out:
- spin_unlock_irqrestore(&dev->tx_lock, flags);
-}
-
-static void mt76x0_tx_tasklet(unsigned long data)
-{
- struct mt76x0_dev *dev = (struct mt76x0_dev *) data;
- struct sk_buff_head skbs;
- unsigned long flags;
-
- __skb_queue_head_init(&skbs);
-
- spin_lock_irqsave(&dev->tx_lock, flags);
-
- set_bit(MT76_MORE_STATS, &dev->mt76.state);
- if (!test_and_set_bit(MT76_READING_STATS, &dev->mt76.state))
- queue_delayed_work(dev->stat_wq, &dev->stat_work,
- msecs_to_jiffies(10));
-
- skb_queue_splice_init(&dev->tx_skb_done, &skbs);
-
- spin_unlock_irqrestore(&dev->tx_lock, flags);
-
- while (!skb_queue_empty(&skbs)) {
- struct sk_buff *skb = __skb_dequeue(&skbs);
-
- mt76x0_tx_status(dev, skb);
- }
-}
-
-static int mt76x0_dma_submit_tx(struct mt76x0_dev *dev,
- struct sk_buff *skb, u8 ep)
-{
- struct usb_device *usb_dev = mt76x0_to_usb_dev(dev);
- unsigned snd_pipe = usb_sndbulkpipe(usb_dev, dev->out_ep[ep]);
- struct mt76x0_dma_buf_tx *e;
- struct mt76x0_tx_queue *q = &dev->tx_q[ep];
- unsigned long flags;
- int ret;
-
- spin_lock_irqsave(&dev->tx_lock, flags);
-
- if (WARN_ON_ONCE(q->entries <= q->used)) {
- ret = -ENOSPC;
- goto out;
- }
-
- e = &q->e[q->end];
- e->skb = skb;
- usb_fill_bulk_urb(e->urb, usb_dev, snd_pipe, skb->data, skb->len,
- mt76x0_complete_tx, q);
- ret = usb_submit_urb(e->urb, GFP_ATOMIC);
- if (ret) {
- /* Special-handle ENODEV from TX urb submission because it will
- * often be the first ENODEV we see after device is removed.
- */
- if (ret == -ENODEV)
- set_bit(MT76_REMOVED, &dev->mt76.state);
- else
- dev_err(dev->mt76.dev, "Error: TX urb submit failed:%d\n",
- ret);
- goto out;
- }
-
- q->end = (q->end + 1) % q->entries;
- q->used++;
-
- if (q->used >= q->entries)
- ieee80211_stop_queue(dev->mt76.hw, skb_get_queue_mapping(skb));
-out:
- spin_unlock_irqrestore(&dev->tx_lock, flags);
-
- return ret;
-}
-
-/* Map USB endpoint number to Q id in the DMA engine */
-static enum mt76_qsel ep2dmaq(u8 ep)
-{
- if (ep == 5)
- return MT_QSEL_MGMT;
- return MT_QSEL_EDCA;
-}
-
-int mt76x0_dma_enqueue_tx(struct mt76x0_dev *dev, struct sk_buff *skb,
- struct mt76_wcid *wcid, int hw_q)
-{
- u8 ep = q2ep(hw_q);
- u32 dma_flags;
- int ret;
-
- dma_flags = MT_TXD_PKT_INFO_80211;
- if (wcid->hw_key_idx == 0xff)
- dma_flags |= MT_TXD_PKT_INFO_WIV;
-
- ret = mt76x0_dma_skb_wrap_pkt(skb, ep2dmaq(ep), dma_flags);
- if (ret)
- return ret;
-
- ret = mt76x0_dma_submit_tx(dev, skb, ep);
-
- if (ret) {
- ieee80211_free_txskb(dev->mt76.hw, skb);
- return ret;
- }
-
- return 0;
-}
-
-static void mt76x0_kill_rx(struct mt76x0_dev *dev)
-{
- int i;
- unsigned long flags;
-
- spin_lock_irqsave(&dev->rx_lock, flags);
-
- for (i = 0; i < dev->rx_q.entries; i++) {
- int next = dev->rx_q.end;
-
- spin_unlock_irqrestore(&dev->rx_lock, flags);
- usb_poison_urb(dev->rx_q.e[next].urb);
- spin_lock_irqsave(&dev->rx_lock, flags);
- }
-
- spin_unlock_irqrestore(&dev->rx_lock, flags);
-}
-
-static int mt76x0_submit_rx_buf(struct mt76x0_dev *dev,
- struct mt76x0_dma_buf_rx *e, gfp_t gfp)
-{
- struct usb_device *usb_dev = mt76x0_to_usb_dev(dev);
- u8 *buf = page_address(e->p);
- unsigned pipe;
- int ret;
-
- pipe = usb_rcvbulkpipe(usb_dev, dev->in_ep[MT_EP_IN_PKT_RX]);
-
- usb_fill_bulk_urb(e->urb, usb_dev, pipe, buf, MT_RX_URB_SIZE,
- mt76x0_complete_rx, dev);
-
- trace_mt76x0_submit_urb(&dev->mt76, e->urb);
- ret = usb_submit_urb(e->urb, gfp);
- if (ret)
- dev_err(dev->mt76.dev, "Error: submit RX URB failed:%d\n", ret);
-
- return ret;
-}
-
-static int mt76x0_submit_rx(struct mt76x0_dev *dev)
-{
- int i, ret;
-
- for (i = 0; i < dev->rx_q.entries; i++) {
- ret = mt76x0_submit_rx_buf(dev, &dev->rx_q.e[i], GFP_KERNEL);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-static void mt76x0_free_rx(struct mt76x0_dev *dev)
-{
- int i;
-
- for (i = 0; i < dev->rx_q.entries; i++) {
- __free_pages(dev->rx_q.e[i].p, MT_RX_ORDER);
- usb_free_urb(dev->rx_q.e[i].urb);
- }
-}
-
-static int mt76x0_alloc_rx(struct mt76x0_dev *dev)
-{
- int i;
-
- memset(&dev->rx_q, 0, sizeof(dev->rx_q));
- dev->rx_q.dev = dev;
- dev->rx_q.entries = N_RX_ENTRIES;
-
- for (i = 0; i < N_RX_ENTRIES; i++) {
- dev->rx_q.e[i].urb = usb_alloc_urb(0, GFP_KERNEL);
- dev->rx_q.e[i].p = dev_alloc_pages(MT_RX_ORDER);
-
- if (!dev->rx_q.e[i].urb || !dev->rx_q.e[i].p)
- return -ENOMEM;
- }
-
- return 0;
-}
-
-static void mt76x0_free_tx_queue(struct mt76x0_tx_queue *q)
-{
- int i;
-
- WARN_ON(q->used);
-
- for (i = 0; i < q->entries; i++) {
- usb_poison_urb(q->e[i].urb);
- usb_free_urb(q->e[i].urb);
- }
-}
-
-static void mt76x0_free_tx(struct mt76x0_dev *dev)
-{
- int i;
-
- for (i = 0; i < __MT_EP_OUT_MAX; i++)
- mt76x0_free_tx_queue(&dev->tx_q[i]);
-}
-
-static int mt76x0_alloc_tx_queue(struct mt76x0_dev *dev,
- struct mt76x0_tx_queue *q)
-{
- int i;
-
- q->dev = dev;
- q->entries = N_TX_ENTRIES;
-
- for (i = 0; i < N_TX_ENTRIES; i++) {
- q->e[i].urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!q->e[i].urb)
- return -ENOMEM;
- }
-
- return 0;
-}
-
-static int mt76x0_alloc_tx(struct mt76x0_dev *dev)
-{
- int i;
-
- dev->tx_q = devm_kcalloc(dev->mt76.dev, __MT_EP_OUT_MAX,
- sizeof(*dev->tx_q), GFP_KERNEL);
-
- for (i = 0; i < __MT_EP_OUT_MAX; i++)
- if (mt76x0_alloc_tx_queue(dev, &dev->tx_q[i]))
- return -ENOMEM;
-
- return 0;
-}
-
-int mt76x0_dma_init(struct mt76x0_dev *dev)
-{
- int ret = -ENOMEM;
-
- tasklet_init(&dev->tx_tasklet, mt76x0_tx_tasklet, (unsigned long) dev);
- tasklet_init(&dev->rx_tasklet, mt76x0_rx_tasklet, (unsigned long) dev);
-
- ret = mt76x0_alloc_tx(dev);
- if (ret)
- goto err;
- ret = mt76x0_alloc_rx(dev);
- if (ret)
- goto err;
-
- ret = mt76x0_submit_rx(dev);
- if (ret)
- goto err;
-
- return 0;
-err:
- mt76x0_dma_cleanup(dev);
- return ret;
-}
-
-void mt76x0_dma_cleanup(struct mt76x0_dev *dev)
-{
- mt76x0_kill_rx(dev);
-
- tasklet_kill(&dev->rx_tasklet);
-
- mt76x0_free_rx(dev);
- mt76x0_free_tx(dev);
-
- tasklet_kill(&dev->tx_tasklet);
-}
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/dma.h b/drivers/net/wireless/mediatek/mt76/mt76x0/dma.h
deleted file mode 100644
index 891ce1c3461f..000000000000
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/dma.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
- * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#ifndef __MT76X0U_DMA_H
-#define __MT76X0U_DMA_H
-
-#include <asm/unaligned.h>
-#include <linux/skbuff.h>
-
-#define MT_DMA_HDR_LEN 4
-#define MT_RX_INFO_LEN 4
-#define MT_FCE_INFO_LEN 4
-#define MT_DMA_HDRS (MT_DMA_HDR_LEN + MT_RX_INFO_LEN)
-
-/* Common Tx DMA descriptor fields */
-#define MT_TXD_INFO_LEN GENMASK(15, 0)
-#define MT_TXD_INFO_D_PORT GENMASK(29, 27)
-#define MT_TXD_INFO_TYPE GENMASK(31, 30)
-
-/* Tx DMA MCU command specific flags */
-#define MT_TXD_CMD_SEQ GENMASK(19, 16)
-#define MT_TXD_CMD_TYPE GENMASK(26, 20)
-
-enum mt76_msg_port {
- WLAN_PORT,
- CPU_RX_PORT,
- CPU_TX_PORT,
- HOST_PORT,
- VIRTUAL_CPU_RX_PORT,
- VIRTUAL_CPU_TX_PORT,
- DISCARD,
-};
-
-enum mt76_info_type {
- DMA_PACKET,
- DMA_COMMAND,
-};
-
-/* Tx DMA packet specific flags */
-#define MT_TXD_PKT_INFO_NEXT_VLD BIT(16)
-#define MT_TXD_PKT_INFO_TX_BURST BIT(17)
-#define MT_TXD_PKT_INFO_80211 BIT(19)
-#define MT_TXD_PKT_INFO_TSO BIT(20)
-#define MT_TXD_PKT_INFO_CSO BIT(21)
-#define MT_TXD_PKT_INFO_WIV BIT(24)
-#define MT_TXD_PKT_INFO_QSEL GENMASK(26, 25)
-
-enum mt76_qsel {
- MT_QSEL_MGMT,
- MT_QSEL_HCCA,
- MT_QSEL_EDCA,
- MT_QSEL_EDCA_2,
-};
-
-
-static inline int mt76x0_dma_skb_wrap(struct sk_buff *skb,
- enum mt76_msg_port d_port,
- enum mt76_info_type type, u32 flags)
-{
- u32 info;
-
- /* Buffer layout:
- * | 4B | xfer len | pad | 4B |
- * | TXINFO | pkt/cmd | zero pad to 4B | zero |
- *
- * length field of TXINFO should be set to 'xfer len'.
- */
-
- info = flags |
- FIELD_PREP(MT_TXD_INFO_LEN, round_up(skb->len, 4)) |
- FIELD_PREP(MT_TXD_INFO_D_PORT, d_port) |
- FIELD_PREP(MT_TXD_INFO_TYPE, type);
-
- put_unaligned_le32(info, skb_push(skb, sizeof(info)));
- return skb_put_padto(skb, round_up(skb->len, 4) + 4);
-}
-
-static inline int
-mt76x0_dma_skb_wrap_pkt(struct sk_buff *skb, enum mt76_qsel qsel, u32 flags)
-{
- flags |= FIELD_PREP(MT_TXD_PKT_INFO_QSEL, qsel);
- return mt76x0_dma_skb_wrap(skb, WLAN_PORT, DMA_PACKET, flags);
-}
-
-/* Common Rx DMA descriptor fields */
-#define MT_RXD_INFO_LEN GENMASK(13, 0)
-#define MT_RXD_INFO_PCIE_INTR BIT(24)
-#define MT_RXD_INFO_QSEL GENMASK(26, 25)
-#define MT_RXD_INFO_PORT GENMASK(29, 27)
-#define MT_RXD_INFO_TYPE GENMASK(31, 30)
-
-/* Rx DMA packet specific flags */
-#define MT_RXD_PKT_INFO_UDP_ERR BIT(16)
-#define MT_RXD_PKT_INFO_TCP_ERR BIT(17)
-#define MT_RXD_PKT_INFO_IP_ERR BIT(18)
-#define MT_RXD_PKT_INFO_PKT_80211 BIT(19)
-#define MT_RXD_PKT_INFO_L3L4_DONE BIT(20)
-#define MT_RXD_PKT_INFO_MAC_LEN GENMASK(23, 21)
-
-/* Rx DMA MCU command specific flags */
-#define MT_RXD_CMD_INFO_SELF_GEN BIT(15)
-#define MT_RXD_CMD_INFO_CMD_SEQ GENMASK(19, 16)
-#define MT_RXD_CMD_INFO_EVT_TYPE GENMASK(23, 20)
-
-enum mt76_evt_type {
- CMD_DONE,
- CMD_ERROR,
- CMD_RETRY,
- EVENT_PWR_RSP,
- EVENT_WOW_RSP,
- EVENT_CARRIER_DETECT_RSP,
- EVENT_DFS_DETECT_RSP,
-};
-
-#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c
index 36da1e6bc21a..ab4fd6e0f23a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c
@@ -13,6 +13,7 @@
* GNU General Public License for more details.
*/
+#include <linux/module.h>
#include <linux/of.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
@@ -20,81 +21,20 @@
#include <asm/unaligned.h>
#include "mt76x0.h"
#include "eeprom.h"
-
-static bool
-field_valid(u8 val)
-{
- return val != 0xff;
-}
-
-static s8
-field_validate(u8 val)
-{
- if (!field_valid(val))
- return 0;
-
- return val;
-}
-
-static inline int
-sign_extend(u32 val, unsigned int size)
-{
- bool sign = val & BIT(size - 1);
-
- val &= BIT(size - 1) - 1;
-
- return sign ? val : -val;
-}
-
-static int
-mt76x0_efuse_read(struct mt76x0_dev *dev, u16 addr, u8 *data,
- enum mt76x0_eeprom_access_modes mode)
-{
- u32 val;
- int i;
-
- val = mt76_rr(dev, MT_EFUSE_CTRL);
- val &= ~(MT_EFUSE_CTRL_AIN |
- MT_EFUSE_CTRL_MODE);
- val |= FIELD_PREP(MT_EFUSE_CTRL_AIN, addr & ~0xf) |
- FIELD_PREP(MT_EFUSE_CTRL_MODE, mode) |
- MT_EFUSE_CTRL_KICK;
- mt76_wr(dev, MT_EFUSE_CTRL, val);
-
- if (!mt76_poll(dev, MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK, 0, 1000))
- return -ETIMEDOUT;
-
- val = mt76_rr(dev, MT_EFUSE_CTRL);
- if ((val & MT_EFUSE_CTRL_AOUT) == MT_EFUSE_CTRL_AOUT) {
- /* Parts of eeprom not in the usage map (0x80-0xc0,0xf0)
- * will not return valid data but it's ok.
- */
- memset(data, 0xff, 16);
- return 0;
- }
-
- for (i = 0; i < 4; i++) {
- val = mt76_rr(dev, MT_EFUSE_DATA(i));
- put_unaligned_le32(val, data + 4 * i);
- }
-
- return 0;
-}
+#include "../mt76x02_phy.h"
#define MT_MAP_READS DIV_ROUND_UP(MT_EFUSE_USAGE_MAP_SIZE, 16)
static int
-mt76x0_efuse_physical_size_check(struct mt76x0_dev *dev)
+mt76x0_efuse_physical_size_check(struct mt76x02_dev *dev)
{
u8 data[MT_MAP_READS * 16];
int ret, i;
u32 start = 0, end = 0, cnt_free;
- for (i = 0; i < MT_MAP_READS; i++) {
- ret = mt76x0_efuse_read(dev, MT_EE_USAGE_MAP_START + i * 16,
- data + i * 16, MT_EE_PHYSICAL_READ);
- if (ret)
- return ret;
- }
+ ret = mt76x02_get_efuse_data(dev, MT_EE_USAGE_MAP_START, data,
+ sizeof(data), MT_EE_PHYSICAL_READ);
+ if (ret)
+ return ret;
for (i = 0; i < MT_EFUSE_USAGE_MAP_SIZE; i++)
if (!data[i]) {
@@ -105,341 +45,304 @@ mt76x0_efuse_physical_size_check(struct mt76x0_dev *dev)
cnt_free = end - start + 1;
if (MT_EFUSE_USAGE_MAP_SIZE - cnt_free < 5) {
- dev_err(dev->mt76.dev, "Error: your device needs default EEPROM file and this driver doesn't support it!\n");
+ dev_err(dev->mt76.dev,
+ "driver does not support default EEPROM\n");
return -EINVAL;
}
return 0;
}
-static void
-mt76x0_set_chip_cap(struct mt76x0_dev *dev, u8 *eeprom)
+static void mt76x0_set_chip_cap(struct mt76x02_dev *dev)
{
- enum mt76x2_board_type { BOARD_TYPE_2GHZ = 1, BOARD_TYPE_5GHZ = 2 };
- u16 nic_conf0 = get_unaligned_le16(eeprom + MT_EE_NIC_CONF_0);
- u16 nic_conf1 = get_unaligned_le16(eeprom + MT_EE_NIC_CONF_1);
-
- dev_dbg(dev->mt76.dev, "NIC_CONF0: %04x NIC_CONF1: %04x\n", nic_conf0, nic_conf1);
-
- switch (FIELD_GET(MT_EE_NIC_CONF_0_BOARD_TYPE, nic_conf0)) {
- case BOARD_TYPE_5GHZ:
- dev->ee->has_5ghz = true;
- break;
- case BOARD_TYPE_2GHZ:
- dev->ee->has_2ghz = true;
- break;
- default:
- dev->ee->has_2ghz = true;
- dev->ee->has_5ghz = true;
- break;
- }
+ u16 nic_conf0 = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_0);
+ u16 nic_conf1 = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1);
+
+ mt76x02_eeprom_parse_hw_cap(dev);
+ dev_dbg(dev->mt76.dev, "2GHz %d 5GHz %d\n",
+ dev->mt76.cap.has_2ghz, dev->mt76.cap.has_5ghz);
- dev_dbg(dev->mt76.dev, "Has 2GHZ %d 5GHZ %d\n", dev->ee->has_2ghz, dev->ee->has_5ghz);
+ if (dev->no_2ghz) {
+ dev->mt76.cap.has_2ghz = false;
+ dev_dbg(dev->mt76.dev, "mask out 2GHz support\n");
+ }
- if (!field_valid(nic_conf1 & 0xff))
+ if (!mt76x02_field_valid(nic_conf1 & 0xff))
nic_conf1 &= 0xff00;
if (nic_conf1 & MT_EE_NIC_CONF_1_HW_RF_CTRL)
dev_err(dev->mt76.dev,
- "Error: this driver does not support HW RF ctrl\n");
+ "driver does not support HW RF ctrl\n");
- if (!field_valid(nic_conf0 >> 8))
+ if (!mt76x02_field_valid(nic_conf0 >> 8))
return;
if (FIELD_GET(MT_EE_NIC_CONF_0_RX_PATH, nic_conf0) > 1 ||
FIELD_GET(MT_EE_NIC_CONF_0_TX_PATH, nic_conf0) > 1)
- dev_err(dev->mt76.dev,
- "Error: device has more than 1 RX/TX stream!\n");
-
- dev->ee->pa_type = FIELD_GET(MT_EE_NIC_CONF_0_PA_TYPE, nic_conf0);
- dev_dbg(dev->mt76.dev, "PA Type %d\n", dev->ee->pa_type);
+ dev_err(dev->mt76.dev, "invalid tx-rx stream\n");
}
-static int
-mt76x0_set_macaddr(struct mt76x0_dev *dev, const u8 *eeprom)
+static void mt76x0_set_temp_offset(struct mt76x02_dev *dev)
{
- const void *src = eeprom + MT_EE_MAC_ADDR;
-
- ether_addr_copy(dev->macaddr, src);
-
- if (!is_valid_ether_addr(dev->macaddr)) {
- eth_random_addr(dev->macaddr);
- dev_info(dev->mt76.dev,
- "Invalid MAC address, using random address %pM\n",
- dev->macaddr);
- }
+ u8 val;
- mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dev->macaddr));
- mt76_wr(dev, MT_MAC_ADDR_DW1, get_unaligned_le16(dev->macaddr + 4) |
- FIELD_PREP(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff));
-
- return 0;
-}
-
-static void
-mt76x0_set_temp_offset(struct mt76x0_dev *dev, u8 *eeprom)
-{
- u8 temp = eeprom[MT_EE_TEMP_OFFSET];
-
- if (field_valid(temp))
- dev->ee->temp_off = sign_extend(temp, 8);
+ val = mt76x02_eeprom_get(dev, MT_EE_2G_TARGET_POWER) >> 8;
+ if (mt76x02_field_valid(val))
+ dev->cal.rx.temp_offset = mt76x02_sign_extend(val, 8);
else
- dev->ee->temp_off = -10;
+ dev->cal.rx.temp_offset = -10;
}
-static void
-mt76x0_set_country_reg(struct mt76x0_dev *dev, u8 *eeprom)
+static void mt76x0_set_freq_offset(struct mt76x02_dev *dev)
{
- /* Note: - region 31 is not valid for mt76x0 (see rtmp_init.c)
- * - comments in rtmp_def.h are incorrect (see rt_channel.c)
- */
- static const struct reg_channel_bounds chan_bounds[] = {
- /* EEPROM country regions 0 - 7 */
- { 1, 11 }, { 1, 13 }, { 10, 2 }, { 10, 4 },
- { 14, 1 }, { 1, 14 }, { 3, 7 }, { 5, 9 },
- /* EEPROM country regions 32 - 33 */
- { 1, 11 }, { 1, 14 }
- };
- u8 val = eeprom[MT_EE_COUNTRY_REGION_2GHZ];
- int idx = -1;
-
- dev_dbg(dev->mt76.dev, "REG 2GHZ %u REG 5GHZ %u\n", val, eeprom[MT_EE_COUNTRY_REGION_5GHZ]);
- if (val < 8)
- idx = val;
- if (val > 31 && val < 33)
- idx = val - 32 + 8;
-
- if (idx != -1)
- dev_info(dev->mt76.dev,
- "EEPROM country region %02hhx (channels %hhd-%hhd)\n",
- val, chan_bounds[idx].start,
- chan_bounds[idx].start + chan_bounds[idx].num - 1);
- else
- idx = 5; /* channels 1 - 14 */
-
- dev->ee->reg = chan_bounds[idx];
+ struct mt76x02_rx_freq_cal *caldata = &dev->cal.rx;
+ u8 val;
- /* TODO: country region 33 is special - phy should be set to B-mode
- * before entering channel 14 (see sta/connect.c)
- */
-}
-
-static void
-mt76x0_set_rf_freq_off(struct mt76x0_dev *dev, u8 *eeprom)
-{
- u8 comp;
+ val = mt76x02_eeprom_get(dev, MT_EE_FREQ_OFFSET);
+ if (!mt76x02_field_valid(val))
+ val = 0;
+ caldata->freq_offset = val;
- dev->ee->rf_freq_off = field_validate(eeprom[MT_EE_FREQ_OFFSET]);
- comp = field_validate(eeprom[MT_EE_FREQ_OFFSET_COMPENSATION]);
+ val = mt76x02_eeprom_get(dev, MT_EE_TSSI_BOUND4) >> 8;
+ if (!mt76x02_field_valid(val))
+ val = 0;
- if (comp & BIT(7))
- dev->ee->rf_freq_off -= comp & 0x7f;
- else
- dev->ee->rf_freq_off += comp;
+ caldata->freq_offset -= mt76x02_sign_extend(val, 8);
}
-static void
-mt76x0_set_lna_gain(struct mt76x0_dev *dev, u8 *eeprom)
+void mt76x0_read_rx_gain(struct mt76x02_dev *dev)
{
- u8 gain;
+ struct ieee80211_channel *chan = dev->mt76.chandef.chan;
+ struct mt76x02_rx_freq_cal *caldata = &dev->cal.rx;
+ s8 val, lna_5g[3], lna_2g;
+ u16 rssi_offset;
+ int i;
- dev->ee->lna_gain_2ghz = eeprom[MT_EE_LNA_GAIN_2GHZ];
- dev->ee->lna_gain_5ghz[0] = eeprom[MT_EE_LNA_GAIN_5GHZ_0];
+ mt76x02_get_rx_gain(dev, chan->band, &rssi_offset, &lna_2g, lna_5g);
+ caldata->lna_gain = mt76x02_get_lna_gain(dev, &lna_2g, lna_5g, chan);
- gain = eeprom[MT_EE_LNA_GAIN_5GHZ_1];
- if (gain == 0xff || gain == 0)
- dev->ee->lna_gain_5ghz[1] = dev->ee->lna_gain_5ghz[0];
- else
- dev->ee->lna_gain_5ghz[1] = gain;
+ for (i = 0; i < ARRAY_SIZE(caldata->rssi_offset); i++) {
+ val = rssi_offset >> (8 * i);
+ if (val < -10 || val > 10)
+ val = 0;
- gain = eeprom[MT_EE_LNA_GAIN_5GHZ_2];
- if (gain == 0xff || gain == 0)
- dev->ee->lna_gain_5ghz[2] = dev->ee->lna_gain_5ghz[0];
- else
- dev->ee->lna_gain_5ghz[2] = gain;
+ caldata->rssi_offset[i] = val;
+ }
}
-static void
-mt76x0_set_rssi_offset(struct mt76x0_dev *dev, u8 *eeprom)
+static s8 mt76x0_get_delta(struct mt76x02_dev *dev)
{
- int i;
- s8 *rssi_offset = dev->ee->rssi_offset_2ghz;
-
- for (i = 0; i < 2; i++) {
- rssi_offset[i] = eeprom[MT_EE_RSSI_OFFSET + i];
+ struct cfg80211_chan_def *chandef = &dev->mt76.chandef;
+ u8 val;
- if (rssi_offset[i] < -10 || rssi_offset[i] > 10) {
- dev_warn(dev->mt76.dev,
- "Warning: EEPROM RSSI is invalid %02hhx\n",
- rssi_offset[i]);
- rssi_offset[i] = 0;
- }
- }
-
- rssi_offset = dev->ee->rssi_offset_5ghz;
+ if (mt76x0_tssi_enabled(dev))
+ return 0;
- for (i = 0; i < 3; i++) {
- rssi_offset[i] = eeprom[MT_EE_RSSI_OFFSET_5GHZ + i];
+ if (chandef->width == NL80211_CHAN_WIDTH_80) {
+ val = mt76x02_eeprom_get(dev, MT_EE_5G_TARGET_POWER) >> 8;
+ } else if (chandef->width == NL80211_CHAN_WIDTH_40) {
+ u16 data;
- if (rssi_offset[i] < -10 || rssi_offset[i] > 10) {
- dev_warn(dev->mt76.dev,
- "Warning: EEPROM RSSI is invalid %02hhx\n",
- rssi_offset[i]);
- rssi_offset[i] = 0;
- }
+ data = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_DELTA_BW40);
+ if (chandef->chan->band == NL80211_BAND_5GHZ)
+ val = data >> 8;
+ else
+ val = data;
+ } else {
+ return 0;
}
+
+ return mt76x02_rate_power_val(val);
}
-static u32
-calc_bw40_power_rate(u32 value, int delta)
+void mt76x0_get_tx_power_per_rate(struct mt76x02_dev *dev)
{
- u32 ret = 0;
- int i, tmp;
-
- for (i = 0; i < 4; i++) {
- tmp = s6_to_int((value >> i*8) & 0xff) + delta;
- ret |= (u32)(int_to_s6(tmp)) << i*8;
- }
-
- return ret;
+ struct ieee80211_channel *chan = dev->mt76.chandef.chan;
+ bool is_2ghz = chan->band == NL80211_BAND_2GHZ;
+ struct mt76_rate_power *t = &dev->mt76.rate_power;
+ s8 delta = mt76x0_get_delta(dev);
+ u16 val, addr;
+
+ memset(t, 0, sizeof(*t));
+
+ /* cck 1M, 2M, 5.5M, 11M */
+ val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_BYRATE_BASE);
+ t->cck[0] = t->cck[1] = s6_to_s8(val);
+ t->cck[2] = t->cck[3] = s6_to_s8(val >> 8);
+
+ /* ofdm 6M, 9M, 12M, 18M */
+ addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 2 : 0x120;
+ val = mt76x02_eeprom_get(dev, addr);
+ t->ofdm[0] = t->ofdm[1] = s6_to_s8(val);
+ t->ofdm[2] = t->ofdm[3] = s6_to_s8(val >> 8);
+
+ /* ofdm 24M, 36M, 48M, 54M */
+ addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 4 : 0x122;
+ val = mt76x02_eeprom_get(dev, addr);
+ t->ofdm[4] = t->ofdm[5] = s6_to_s8(val);
+ t->ofdm[6] = t->ofdm[7] = s6_to_s8(val >> 8);
+
+ /* ht-vht mcs 1ss 0, 1, 2, 3 */
+ addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 6 : 0x124;
+ val = mt76x02_eeprom_get(dev, addr);
+ t->ht[0] = t->ht[1] = t->vht[0] = t->vht[1] = s6_to_s8(val);
+ t->ht[2] = t->ht[3] = t->vht[2] = t->vht[3] = s6_to_s8(val >> 8);
+
+ /* ht-vht mcs 1ss 4, 5, 6 */
+ addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 8 : 0x126;
+ val = mt76x02_eeprom_get(dev, addr);
+ t->ht[4] = t->ht[5] = t->vht[4] = t->vht[5] = s6_to_s8(val);
+ t->ht[6] = t->vht[6] = s6_to_s8(val >> 8);
+
+ /* ht-vht mcs 1ss 0, 1, 2, 3 stbc */
+ addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 14 : 0xec;
+ val = mt76x02_eeprom_get(dev, addr);
+ t->stbc[0] = t->stbc[1] = s6_to_s8(val);
+ t->stbc[2] = t->stbc[3] = s6_to_s8(val >> 8);
+
+ /* ht-vht mcs 1ss 4, 5, 6 stbc */
+ addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 16 : 0xee;
+ val = mt76x02_eeprom_get(dev, addr);
+ t->stbc[4] = t->stbc[5] = s6_to_s8(val);
+ t->stbc[6] = t->stbc[7] = s6_to_s8(val >> 8);
+
+ /* vht mcs 8, 9 5GHz */
+ val = mt76x02_eeprom_get(dev, 0x132);
+ t->vht[7] = s6_to_s8(val);
+ t->vht[8] = s6_to_s8(val >> 8);
+
+ mt76x02_add_rate_power_offset(t, delta);
}
-static s8
-get_delta(u8 val)
+void mt76x0_get_power_info(struct mt76x02_dev *dev, u8 *info)
{
- s8 ret;
+ struct mt76x0_chan_map {
+ u8 chan;
+ u8 offset;
+ } chan_map[] = {
+ { 2, 0 }, { 4, 1 }, { 6, 2 }, { 8, 3 },
+ { 10, 4 }, { 12, 5 }, { 14, 6 }, { 38, 0 },
+ { 44, 1 }, { 48, 2 }, { 54, 3 }, { 60, 4 },
+ { 64, 5 }, { 102, 6 }, { 108, 7 }, { 112, 8 },
+ { 118, 9 }, { 124, 10 }, { 128, 11 }, { 134, 12 },
+ { 140, 13 }, { 151, 14 }, { 157, 15 }, { 161, 16 },
+ { 167, 17 }, { 171, 18 }, { 173, 19 },
+ };
+ struct ieee80211_channel *chan = dev->mt76.chandef.chan;
+ u8 offset, addr;
+ u16 data;
+ int i;
- if (!field_valid(val) || !(val & BIT(7)))
- return 0;
+ for (i = 0; i < ARRAY_SIZE(chan_map); i++) {
+ if (chan_map[i].chan <= chan->hw_value) {
+ offset = chan_map[i].offset;
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(chan_map))
+ offset = chan_map[0].offset;
+
+ if (chan->band == NL80211_BAND_2GHZ) {
+ addr = MT_EE_TX_POWER_DELTA_BW80 + offset;
+ } else {
+ switch (chan->hw_value) {
+ case 58:
+ offset = 8;
+ break;
+ case 106:
+ offset = 14;
+ break;
+ case 112:
+ offset = 20;
+ break;
+ case 155:
+ offset = 30;
+ break;
+ default:
+ break;
+ }
+ addr = MT_EE_TX_POWER_0_GRP4_TSSI_SLOPE + 2 + offset;
+ }
- ret = val & 0x1f;
- if (ret > 8)
- ret = 8;
- if (val & BIT(6))
- ret = -ret;
+ data = mt76x02_eeprom_get(dev, addr);
- return ret;
+ info[0] = data;
+ if (!info[0] || info[0] > 0x3f)
+ info[0] = 5;
+
+ info[1] = data >> 8;
+ if (!info[1] || info[1] > 0x3f)
+ info[1] = 5;
}
-static void
-mt76x0_set_tx_power_per_rate(struct mt76x0_dev *dev, u8 *eeprom)
+static int mt76x0_check_eeprom(struct mt76x02_dev *dev)
{
- s8 bw40_delta_2g, bw40_delta_5g;
- u32 val;
- int i;
-
- bw40_delta_2g = get_delta(eeprom[MT_EE_TX_POWER_DELTA_BW40]);
- bw40_delta_5g = get_delta(eeprom[MT_EE_TX_POWER_DELTA_BW40 + 1]);
-
- for (i = 0; i < 5; i++) {
- val = get_unaligned_le32(eeprom + MT_EE_TX_POWER_BYRATE(i));
+ u16 val;
- /* Skip last 16 bits. */
- if (i == 4)
- val &= 0x0000ffff;
+ val = get_unaligned_le16(dev->mt76.eeprom.data);
+ if (!val)
+ val = get_unaligned_le16(dev->mt76.eeprom.data +
+ MT_EE_PCI_ID);
- dev->ee->tx_pwr_cfg_2g[i][0] = val;
- dev->ee->tx_pwr_cfg_2g[i][1] = calc_bw40_power_rate(val, bw40_delta_2g);
+ switch (val) {
+ case 0x7650:
+ case 0x7610:
+ return 0;
+ default:
+ dev_err(dev->mt76.dev, "EEPROM data check failed: %04x\n",
+ val);
+ return -EINVAL;
}
-
- /* Reading per rate tx power for 5 GHz band is a bit more complex. Note
- * we mix 16 bit and 32 bit reads and sometimes do shifts.
- */
- val = get_unaligned_le16(eeprom + 0x120);
- val <<= 16;
- dev->ee->tx_pwr_cfg_5g[0][0] = val;
- dev->ee->tx_pwr_cfg_5g[0][1] = calc_bw40_power_rate(val, bw40_delta_5g);
-
- val = get_unaligned_le32(eeprom + 0x122);
- dev->ee->tx_pwr_cfg_5g[1][0] = val;
- dev->ee->tx_pwr_cfg_5g[1][1] = calc_bw40_power_rate(val, bw40_delta_5g);
-
- val = get_unaligned_le16(eeprom + 0x126);
- dev->ee->tx_pwr_cfg_5g[2][0] = val;
- dev->ee->tx_pwr_cfg_5g[2][1] = calc_bw40_power_rate(val, bw40_delta_5g);
-
- val = get_unaligned_le16(eeprom + 0xec);
- val <<= 16;
- dev->ee->tx_pwr_cfg_5g[3][0] = val;
- dev->ee->tx_pwr_cfg_5g[3][1] = calc_bw40_power_rate(val, bw40_delta_5g);
-
- val = get_unaligned_le16(eeprom + 0xee);
- dev->ee->tx_pwr_cfg_5g[4][0] = val;
- dev->ee->tx_pwr_cfg_5g[4][1] = calc_bw40_power_rate(val, bw40_delta_5g);
}
-static void
-mt76x0_set_tx_power_per_chan(struct mt76x0_dev *dev, u8 *eeprom)
+static int mt76x0_load_eeprom(struct mt76x02_dev *dev)
{
- int i;
- u8 tx_pwr;
+ int found;
- for (i = 0; i < 14; i++) {
- tx_pwr = eeprom[MT_EE_TX_POWER_OFFSET_2GHZ + i];
- if (tx_pwr <= 0x3f && tx_pwr > 0)
- dev->ee->tx_pwr_per_chan[i] = tx_pwr;
- else
- dev->ee->tx_pwr_per_chan[i] = 5;
- }
+ found = mt76_eeprom_init(&dev->mt76, MT76X0_EEPROM_SIZE);
+ if (found < 0)
+ return found;
- for (i = 0; i < 40; i++) {
- tx_pwr = eeprom[MT_EE_TX_POWER_OFFSET_5GHZ + i];
- if (tx_pwr <= 0x3f && tx_pwr > 0)
- dev->ee->tx_pwr_per_chan[14 + i] = tx_pwr;
- else
- dev->ee->tx_pwr_per_chan[14 + i] = 5;
- }
+ if (found && !mt76x0_check_eeprom(dev))
+ return 0;
+
+ found = mt76x0_efuse_physical_size_check(dev);
+ if (found < 0)
+ return found;
- dev->ee->tx_pwr_per_chan[54] = dev->ee->tx_pwr_per_chan[22];
- dev->ee->tx_pwr_per_chan[55] = dev->ee->tx_pwr_per_chan[28];
- dev->ee->tx_pwr_per_chan[56] = dev->ee->tx_pwr_per_chan[34];
- dev->ee->tx_pwr_per_chan[57] = dev->ee->tx_pwr_per_chan[44];
+ return mt76x02_get_efuse_data(dev, 0, dev->mt76.eeprom.data,
+ MT76X0_EEPROM_SIZE, MT_EE_READ);
}
-int
-mt76x0_eeprom_init(struct mt76x0_dev *dev)
+int mt76x0_eeprom_init(struct mt76x02_dev *dev)
{
- u8 *eeprom;
- int i, ret;
-
- ret = mt76x0_efuse_physical_size_check(dev);
- if (ret)
- return ret;
-
- dev->ee = devm_kzalloc(dev->mt76.dev, sizeof(*dev->ee), GFP_KERNEL);
- if (!dev->ee)
- return -ENOMEM;
+ u8 version, fae;
+ u16 data;
+ int err;
- eeprom = kmalloc(MT76X0_EEPROM_SIZE, GFP_KERNEL);
- if (!eeprom)
- return -ENOMEM;
+ err = mt76x0_load_eeprom(dev);
+ if (err < 0)
+ return err;
- for (i = 0; i + 16 <= MT76X0_EEPROM_SIZE; i += 16) {
- ret = mt76x0_efuse_read(dev, i, eeprom + i, MT_EE_READ);
- if (ret)
- goto out;
- }
+ data = mt76x02_eeprom_get(dev, MT_EE_VERSION);
+ version = data >> 8;
+ fae = data;
- if (eeprom[MT_EE_VERSION_EE] > MT76X0U_EE_MAX_VER)
+ if (version > MT76X0U_EE_MAX_VER)
dev_warn(dev->mt76.dev,
"Warning: unsupported EEPROM version %02hhx\n",
- eeprom[MT_EE_VERSION_EE]);
+ version);
dev_info(dev->mt76.dev, "EEPROM ver:%02hhx fae:%02hhx\n",
- eeprom[MT_EE_VERSION_EE], eeprom[MT_EE_VERSION_FAE]);
-
- mt76x0_set_macaddr(dev, eeprom);
- mt76x0_set_chip_cap(dev, eeprom);
- mt76x0_set_country_reg(dev, eeprom);
- mt76x0_set_rf_freq_off(dev, eeprom);
- mt76x0_set_temp_offset(dev, eeprom);
- mt76x0_set_lna_gain(dev, eeprom);
- mt76x0_set_rssi_offset(dev, eeprom);
- dev->chainmask = 0x0101;
-
- mt76x0_set_tx_power_per_rate(dev, eeprom);
- mt76x0_set_tx_power_per_chan(dev, eeprom);
-
-out:
- kfree(eeprom);
- return ret;
+ version, fae);
+
+ mt76x02_mac_setaddr(dev, dev->mt76.eeprom.data + MT_EE_MAC_ADDR);
+ mt76x0_set_chip_cap(dev);
+ mt76x0_set_freq_offset(dev);
+ mt76x0_set_temp_offset(dev);
+
+ dev->mt76.chainmask = 0x0101;
+
+ return 0;
}
+
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h
index e37b573aed7b..ee9ade9f3c8b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h
@@ -16,134 +16,31 @@
#ifndef __MT76X0U_EEPROM_H
#define __MT76X0U_EEPROM_H
-struct mt76x0_dev;
+#include "../mt76x02_eeprom.h"
-#define MT76X0U_EE_MAX_VER 0x0c
-#define MT76X0_EEPROM_SIZE 512
+struct mt76x02_dev;
-#define MT76X0U_DEFAULT_TX_POWER 6
+#define MT76X0U_EE_MAX_VER 0x0c
+#define MT76X0_EEPROM_SIZE 512
-enum mt76_eeprom_field {
- MT_EE_CHIP_ID = 0x00,
- MT_EE_VERSION_FAE = 0x02,
- MT_EE_VERSION_EE = 0x03,
- MT_EE_MAC_ADDR = 0x04,
- MT_EE_NIC_CONF_0 = 0x34,
- MT_EE_NIC_CONF_1 = 0x36,
- MT_EE_COUNTRY_REGION_5GHZ = 0x38,
- MT_EE_COUNTRY_REGION_2GHZ = 0x39,
- MT_EE_FREQ_OFFSET = 0x3a,
- MT_EE_NIC_CONF_2 = 0x42,
+int mt76x0_eeprom_init(struct mt76x02_dev *dev);
+void mt76x0_read_rx_gain(struct mt76x02_dev *dev);
+void mt76x0_get_tx_power_per_rate(struct mt76x02_dev *dev);
+void mt76x0_get_power_info(struct mt76x02_dev *dev, u8 *info);
- MT_EE_LNA_GAIN_2GHZ = 0x44,
- MT_EE_LNA_GAIN_5GHZ_0 = 0x45,
- MT_EE_RSSI_OFFSET = 0x46,
- MT_EE_RSSI_OFFSET_5GHZ = 0x4a,
- MT_EE_LNA_GAIN_5GHZ_1 = 0x49,
- MT_EE_LNA_GAIN_5GHZ_2 = 0x4d,
-
- MT_EE_TX_POWER_DELTA_BW40 = 0x50,
-
- MT_EE_TX_POWER_OFFSET_2GHZ = 0x52,
-
- MT_EE_TX_TSSI_SLOPE = 0x6e,
- MT_EE_TX_TSSI_OFFSET_GROUP = 0x6f,
- MT_EE_TX_TSSI_OFFSET = 0x76,
-
- MT_EE_TX_POWER_OFFSET_5GHZ = 0x78,
-
- MT_EE_TEMP_OFFSET = 0xd1,
- MT_EE_FREQ_OFFSET_COMPENSATION = 0xdb,
- MT_EE_TX_POWER_BYRATE_BASE = 0xde,
-
- MT_EE_TX_POWER_BYRATE_BASE_5GHZ = 0x120,
-
- MT_EE_USAGE_MAP_START = 0x1e0,
- MT_EE_USAGE_MAP_END = 0x1fc,
-};
-
-#define MT_EE_NIC_CONF_0_RX_PATH GENMASK(3, 0)
-#define MT_EE_NIC_CONF_0_TX_PATH GENMASK(7, 4)
-#define MT_EE_NIC_CONF_0_PA_TYPE GENMASK(9, 8)
-#define MT_EE_NIC_CONF_0_BOARD_TYPE GENMASK(13, 12)
-
-#define MT_EE_NIC_CONF_1_HW_RF_CTRL BIT(0)
-#define MT_EE_NIC_CONF_1_TEMP_TX_ALC BIT(1)
-#define MT_EE_NIC_CONF_1_LNA_EXT_2G BIT(2)
-#define MT_EE_NIC_CONF_1_LNA_EXT_5G BIT(3)
-#define MT_EE_NIC_CONF_1_TX_ALC_EN BIT(13)
-
-#define MT_EE_NIC_CONF_2_RX_STREAM GENMASK(3, 0)
-#define MT_EE_NIC_CONF_2_TX_STREAM GENMASK(7, 4)
-#define MT_EE_NIC_CONF_2_HW_ANTDIV BIT(8)
-#define MT_EE_NIC_CONF_2_XTAL_OPTION GENMASK(10, 9)
-#define MT_EE_NIC_CONF_2_TEMP_DISABLE BIT(11)
-#define MT_EE_NIC_CONF_2_COEX_METHOD GENMASK(15, 13)
-
-#define MT_EE_TX_POWER_BYRATE(i) (MT_EE_TX_POWER_BYRATE_BASE + \
- (i) * 4)
-
-#define MT_EFUSE_USAGE_MAP_SIZE (MT_EE_USAGE_MAP_END - \
- MT_EE_USAGE_MAP_START + 1)
-
-enum mt76x0_eeprom_access_modes {
- MT_EE_READ = 0,
- MT_EE_PHYSICAL_READ = 1,
-};
-
-struct reg_channel_bounds {
- u8 start;
- u8 num;
-};
-
-struct mt76x0_eeprom_params {
- u8 rf_freq_off;
- s16 temp_off;
- s8 rssi_offset_2ghz[2];
- s8 rssi_offset_5ghz[3];
- s8 lna_gain_2ghz;
- s8 lna_gain_5ghz[3];
- u8 pa_type;
-
- /* TX_PWR_CFG_* values from EEPROM for 20 and 40 Mhz bandwidths. */
- u32 tx_pwr_cfg_2g[5][2];
- u32 tx_pwr_cfg_5g[5][2];
-
- u8 tx_pwr_per_chan[58];
-
- struct reg_channel_bounds reg;
-
- bool has_2ghz;
- bool has_5ghz;
-};
-
-int mt76x0_eeprom_init(struct mt76x0_dev *dev);
-
-static inline u32 s6_validate(u32 reg)
-{
- WARN_ON(reg & ~GENMASK(5, 0));
- return reg & GENMASK(5, 0);
-}
-
-static inline int s6_to_int(u32 reg)
+static inline s8 s6_to_s8(u32 val)
{
- int s6;
-
- s6 = s6_validate(reg);
- if (s6 & BIT(5))
- s6 -= BIT(6);
+ s8 ret = val & GENMASK(5, 0);
- return s6;
+ if (ret & BIT(5))
+ ret -= BIT(6);
+ return ret;
}
-static inline u32 int_to_s6(int val)
+static inline bool mt76x0_tssi_enabled(struct mt76x02_dev *dev)
{
- if (val < -0x20)
- return 0x20;
- if (val > 0x1f)
- return 0x1f;
-
- return val & 0x3f;
+ return (mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1) &
+ MT_EE_NIC_CONF_1_TX_ALC_EN);
}
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c
index 7cdb3e740522..4a9408801260 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c
@@ -18,15 +18,31 @@
#include "eeprom.h"
#include "trace.h"
#include "mcu.h"
-#include "usb.h"
-
#include "initvals.h"
-static void
-mt76x0_set_wlan_state(struct mt76x0_dev *dev, u32 val, bool enable)
+static void mt76x0_vht_cap_mask(struct ieee80211_supported_band *sband)
{
+ struct ieee80211_sta_vht_cap *vht_cap = &sband->vht_cap;
+ u16 mcs_map = 0;
int i;
+ vht_cap->cap &= ~IEEE80211_VHT_CAP_RXLDPC;
+ for (i = 0; i < 8; i++) {
+ if (!i)
+ mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_7 << (i * 2));
+ else
+ mcs_map |=
+ (IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2));
+ }
+ vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
+ vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
+}
+
+static void
+mt76x0_set_wlan_state(struct mt76x02_dev *dev, u32 val, bool enable)
+{
+ u32 mask = MT_CMB_CTRL_XTAL_RDY | MT_CMB_CTRL_PLL_LD;
+
/* Note: we don't turn off WLAN_CLK because that makes the device
* not respond properly on the probe path.
* In case anyone (PSM?) wants to use this function we can
@@ -42,32 +58,18 @@ mt76x0_set_wlan_state(struct mt76x0_dev *dev, u32 val, bool enable)
mt76_wr(dev, MT_WLAN_FUN_CTRL, val);
udelay(20);
- if (!enable)
- return;
-
- for (i = 200; i; i--) {
- val = mt76_rr(dev, MT_CMB_CTRL);
-
- if (val & MT_CMB_CTRL_XTAL_RDY && val & MT_CMB_CTRL_PLL_LD)
- break;
-
- udelay(20);
- }
-
/* Note: vendor driver tries to disable/enable wlan here and retry
* but the code which does it is so buggy it must have never
* triggered, so don't bother.
*/
- if (!i)
- dev_err(dev->mt76.dev, "Error: PLL and XTAL check failed!\n");
+ if (enable && !mt76_poll(dev, MT_CMB_CTRL, mask, mask, 2000))
+ dev_err(dev->mt76.dev, "PLL and XTAL check failed\n");
}
-void mt76x0_chip_onoff(struct mt76x0_dev *dev, bool enable, bool reset)
+void mt76x0_chip_onoff(struct mt76x02_dev *dev, bool enable, bool reset)
{
u32 val;
- mutex_lock(&dev->hw_atomic_mutex);
-
val = mt76_rr(dev, MT_WLAN_FUN_CTRL);
if (reset) {
@@ -89,54 +91,25 @@ void mt76x0_chip_onoff(struct mt76x0_dev *dev, bool enable, bool reset)
udelay(20);
mt76x0_set_wlan_state(dev, val, enable);
-
- mutex_unlock(&dev->hw_atomic_mutex);
}
+EXPORT_SYMBOL_GPL(mt76x0_chip_onoff);
-static void mt76x0_reset_csr_bbp(struct mt76x0_dev *dev)
+static void mt76x0_reset_csr_bbp(struct mt76x02_dev *dev)
{
- u32 val;
-
- val = mt76_rr(dev, MT_PBF_SYS_CTRL);
- val &= ~0x2000;
- mt76_wr(dev, MT_PBF_SYS_CTRL, val);
-
- mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR |
- MT_MAC_SYS_CTRL_RESET_BBP);
-
+ mt76_wr(dev, MT_MAC_SYS_CTRL,
+ MT_MAC_SYS_CTRL_RESET_CSR |
+ MT_MAC_SYS_CTRL_RESET_BBP);
msleep(200);
+ mt76_clear(dev, MT_MAC_SYS_CTRL,
+ MT_MAC_SYS_CTRL_RESET_CSR |
+ MT_MAC_SYS_CTRL_RESET_BBP);
}
-static void mt76x0_init_usb_dma(struct mt76x0_dev *dev)
-{
- u32 val;
-
- val = mt76_rr(dev, MT_USB_DMA_CFG);
-
- val |= FIELD_PREP(MT_USB_DMA_CFG_RX_BULK_AGG_TOUT, MT_USB_AGGR_TIMEOUT) |
- FIELD_PREP(MT_USB_DMA_CFG_RX_BULK_AGG_LMT, MT_USB_AGGR_SIZE_LIMIT) |
- MT_USB_DMA_CFG_RX_BULK_EN |
- MT_USB_DMA_CFG_TX_BULK_EN;
- if (dev->in_max_packet == 512)
- val |= MT_USB_DMA_CFG_RX_BULK_AGG_EN;
- mt76_wr(dev, MT_USB_DMA_CFG, val);
-
- val = mt76_rr(dev, MT_COM_REG0);
- if (val & 1)
- dev_dbg(dev->mt76.dev, "MCU not ready\n");
-
- val = mt76_rr(dev, MT_USB_DMA_CFG);
-
- val |= MT_USB_DMA_CFG_RX_DROP_OR_PADDING;
- mt76_wr(dev, MT_USB_DMA_CFG, val);
- val &= ~MT_USB_DMA_CFG_RX_DROP_OR_PADDING;
- mt76_wr(dev, MT_USB_DMA_CFG, val);
-}
-
-#define RANDOM_WRITE(dev, tab) \
- mt76x0_write_reg_pairs(dev, MT_MCU_MEMMAP_WLAN, tab, ARRAY_SIZE(tab));
+#define RANDOM_WRITE(dev, tab) \
+ mt76_wr_rp(dev, MT_MCU_MEMMAP_WLAN, \
+ tab, ARRAY_SIZE(tab))
-static int mt76x0_init_bbp(struct mt76x0_dev *dev)
+static int mt76x0_init_bbp(struct mt76x02_dev *dev)
{
int ret, i;
@@ -159,30 +132,13 @@ static int mt76x0_init_bbp(struct mt76x0_dev *dev)
return 0;
}
-static void
-mt76_init_beacon_offsets(struct mt76x0_dev *dev)
-{
- u16 base = MT_BEACON_BASE;
- u32 regs[4] = {};
- int i;
-
- for (i = 0; i < 16; i++) {
- u16 addr = dev->beacon_offsets[i];
-
- regs[i / 4] |= ((addr - base) / 64) << (8 * (i % 4));
- }
-
- for (i = 0; i < 4; i++)
- mt76_wr(dev, MT_BCN_OFFSET(i), regs[i]);
-}
-
-static void mt76x0_init_mac_registers(struct mt76x0_dev *dev)
+static void mt76x0_init_mac_registers(struct mt76x02_dev *dev)
{
u32 reg;
RANDOM_WRITE(dev, common_mac_reg_table);
- mt76_init_beacon_offsets(dev);
+ mt76x02_set_beacon_offsets(dev);
/* Enable PBF and MAC clock SYS_CTRL[11:10] = 0x3 */
RANDOM_WRITE(dev, mt76x0_mac_reg_table);
@@ -192,13 +148,6 @@ static void mt76x0_init_mac_registers(struct mt76x0_dev *dev)
reg &= ~0x3;
mt76_wr(dev, MT_MAC_SYS_CTRL, reg);
- if (is_mt7610e(dev)) {
- /* Disable COEX_EN */
- reg = mt76_rr(dev, MT_COEXCFG0);
- reg &= 0xFFFFFFFE;
- mt76_wr(dev, MT_COEXCFG0, reg);
- }
-
/* Set 0x141C[15:12]=0xF */
reg = mt76_rr(dev, MT_EXT_CCA_CFG);
reg |= 0x0000F000;
@@ -216,115 +165,81 @@ static void mt76x0_init_mac_registers(struct mt76x0_dev *dev)
reg &= ~0x000003FF;
reg |= 0x00000201;
mt76_wr(dev, MT_WMM_CTRL, reg);
-
- /* TODO: Probably not needed */
- mt76_wr(dev, 0x7028, 0);
- mt76_wr(dev, 0x7010, 0);
- mt76_wr(dev, 0x7024, 0);
- msleep(10);
}
-static int mt76x0_init_wcid_mem(struct mt76x0_dev *dev)
+static int mt76x0_init_wcid_mem(struct mt76x02_dev *dev)
{
u32 *vals;
- int i, ret;
+ int i;
- vals = kmalloc(sizeof(*vals) * N_WCIDS * 2, GFP_KERNEL);
+ vals = kmalloc(sizeof(*vals) * MT76_N_WCIDS * 2, GFP_KERNEL);
if (!vals)
return -ENOMEM;
- for (i = 0; i < N_WCIDS; i++) {
+ for (i = 0; i < MT76_N_WCIDS; i++) {
vals[i * 2] = 0xffffffff;
vals[i * 2 + 1] = 0x00ffffff;
}
- ret = mt76x0_burst_write_regs(dev, MT_WCID_ADDR_BASE,
- vals, N_WCIDS * 2);
+ mt76_wr_copy(dev, MT_WCID_ADDR_BASE, vals, MT76_N_WCIDS * 2);
kfree(vals);
-
- return ret;
+ return 0;
}
-static int mt76x0_init_key_mem(struct mt76x0_dev *dev)
+static void mt76x0_init_key_mem(struct mt76x02_dev *dev)
{
u32 vals[4] = {};
- return mt76x0_burst_write_regs(dev, MT_SKEY_MODE_BASE_0,
- vals, ARRAY_SIZE(vals));
+ mt76_wr_copy(dev, MT_SKEY_MODE_BASE_0, vals, ARRAY_SIZE(vals));
}
-static int mt76x0_init_wcid_attr_mem(struct mt76x0_dev *dev)
+static int mt76x0_init_wcid_attr_mem(struct mt76x02_dev *dev)
{
u32 *vals;
- int i, ret;
+ int i;
- vals = kmalloc(sizeof(*vals) * N_WCIDS * 2, GFP_KERNEL);
+ vals = kmalloc(sizeof(*vals) * MT76_N_WCIDS * 2, GFP_KERNEL);
if (!vals)
return -ENOMEM;
- for (i = 0; i < N_WCIDS * 2; i++)
+ for (i = 0; i < MT76_N_WCIDS * 2; i++)
vals[i] = 1;
- ret = mt76x0_burst_write_regs(dev, MT_WCID_ATTR_BASE,
- vals, N_WCIDS * 2);
+ mt76_wr_copy(dev, MT_WCID_ATTR_BASE, vals, MT76_N_WCIDS * 2);
kfree(vals);
-
- return ret;
+ return 0;
}
-static void mt76x0_reset_counters(struct mt76x0_dev *dev)
+static void mt76x0_reset_counters(struct mt76x02_dev *dev)
{
- mt76_rr(dev, MT_RX_STA_CNT0);
- mt76_rr(dev, MT_RX_STA_CNT1);
- mt76_rr(dev, MT_RX_STA_CNT2);
- mt76_rr(dev, MT_TX_STA_CNT0);
- mt76_rr(dev, MT_TX_STA_CNT1);
- mt76_rr(dev, MT_TX_STA_CNT2);
+ mt76_rr(dev, MT_RX_STAT_0);
+ mt76_rr(dev, MT_RX_STAT_1);
+ mt76_rr(dev, MT_RX_STAT_2);
+ mt76_rr(dev, MT_TX_STA_0);
+ mt76_rr(dev, MT_TX_STA_1);
+ mt76_rr(dev, MT_TX_STA_2);
}
-int mt76x0_mac_start(struct mt76x0_dev *dev)
+int mt76x0_mac_start(struct mt76x02_dev *dev)
{
mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX);
- if (!mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_BUSY |
- MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 200000))
+ if (!mt76x02_wait_for_wpdma(&dev->mt76, 200000))
return -ETIMEDOUT;
- dev->rxfilter = MT_RX_FILTR_CFG_CRC_ERR |
- MT_RX_FILTR_CFG_PHY_ERR | MT_RX_FILTR_CFG_PROMISC |
- MT_RX_FILTR_CFG_VER_ERR | MT_RX_FILTR_CFG_DUP |
- MT_RX_FILTR_CFG_CFACK | MT_RX_FILTR_CFG_CFEND |
- MT_RX_FILTR_CFG_ACK | MT_RX_FILTR_CFG_CTS |
- MT_RX_FILTR_CFG_RTS | MT_RX_FILTR_CFG_PSPOLL |
- MT_RX_FILTR_CFG_BA | MT_RX_FILTR_CFG_CTRL_RSV;
- mt76_wr(dev, MT_RX_FILTR_CFG, dev->rxfilter);
-
+ mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter);
mt76_wr(dev, MT_MAC_SYS_CTRL,
- MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX);
-
- if (!mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_BUSY |
- MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 50))
- return -ETIMEDOUT;
+ MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX);
- return 0;
+ return !mt76x02_wait_for_wpdma(&dev->mt76, 50) ? -ETIMEDOUT : 0;
}
+EXPORT_SYMBOL_GPL(mt76x0_mac_start);
-static void mt76x0_mac_stop_hw(struct mt76x0_dev *dev)
+void mt76x0_mac_stop(struct mt76x02_dev *dev)
{
- int i, ok;
-
- if (test_bit(MT76_REMOVED, &dev->mt76.state))
- return;
-
- mt76_clear(dev, MT_BEACON_TIME_CFG, MT_BEACON_TIME_CFG_TIMER_EN |
- MT_BEACON_TIME_CFG_SYNC_MODE | MT_BEACON_TIME_CFG_TBTT_EN |
- MT_BEACON_TIME_CFG_BEACON_TX);
-
- if (!mt76_poll(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_TX_BUSY, 0, 1000))
- dev_warn(dev->mt76.dev, "Warning: TX DMA did not stop!\n");
+ int i = 200, ok = 0;
/* Page count on TxQ */
- i = 200;
while (i-- && ((mt76_rr(dev, 0x0438) & 0xffffffff) ||
(mt76_rr(dev, 0x0a30) & 0x000000ff) ||
(mt76_rr(dev, 0x0a34) & 0x00ff00ff)))
@@ -337,9 +252,7 @@ static void mt76x0_mac_stop_hw(struct mt76x0_dev *dev)
MT_MAC_SYS_CTRL_ENABLE_TX);
/* Page count on RxQ */
- ok = 0;
- i = 200;
- while (i--) {
+ for (i = 0; i < 200; i++) {
if (!(mt76_rr(dev, MT_RXQ_STA) & 0x00ff0000) &&
!mt76_rr(dev, 0x0a30) &&
!mt76_rr(dev, 0x0a34)) {
@@ -352,91 +265,45 @@ static void mt76x0_mac_stop_hw(struct mt76x0_dev *dev)
if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_RX, 0, 1000))
dev_warn(dev->mt76.dev, "Warning: MAC RX did not stop!\n");
-
- if (!mt76_poll(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_RX_BUSY, 0, 1000))
- dev_warn(dev->mt76.dev, "Warning: RX DMA did not stop!\n");
-}
-
-void mt76x0_mac_stop(struct mt76x0_dev *dev)
-{
- mt76x0_mac_stop_hw(dev);
- flush_delayed_work(&dev->stat_work);
- cancel_delayed_work_sync(&dev->stat_work);
-}
-
-static void mt76x0_stop_hardware(struct mt76x0_dev *dev)
-{
- mt76x0_chip_onoff(dev, false, false);
}
+EXPORT_SYMBOL_GPL(mt76x0_mac_stop);
-int mt76x0_init_hardware(struct mt76x0_dev *dev)
+int mt76x0_init_hardware(struct mt76x02_dev *dev)
{
- static const u16 beacon_offsets[16] = {
- /* 512 byte per beacon */
- 0xc000, 0xc200, 0xc400, 0xc600,
- 0xc800, 0xca00, 0xcc00, 0xce00,
- 0xd000, 0xd200, 0xd400, 0xd600,
- 0xd800, 0xda00, 0xdc00, 0xde00
- };
int ret;
- dev->beacon_offsets = beacon_offsets;
-
- mt76x0_chip_onoff(dev, true, true);
-
- ret = mt76x0_wait_asic_ready(dev);
- if (ret)
- goto err;
- ret = mt76x0_mcu_init(dev);
- if (ret)
- goto err;
-
- if (!mt76_poll_msec(dev, MT_WPDMA_GLO_CFG,
- MT_WPDMA_GLO_CFG_TX_DMA_BUSY |
- MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 100)) {
- ret = -EIO;
- goto err;
- }
+ if (!mt76x02_wait_for_wpdma(&dev->mt76, 1000))
+ return -EIO;
/* Wait for ASIC ready after FW load. */
- ret = mt76x0_wait_asic_ready(dev);
- if (ret)
- goto err;
+ if (!mt76x02_wait_for_mac(&dev->mt76))
+ return -ETIMEDOUT;
mt76x0_reset_csr_bbp(dev);
- mt76x0_init_usb_dma(dev);
-
- mt76_wr(dev, MT_HEADER_TRANS_CTRL_REG, 0x0);
- mt76_wr(dev, MT_TSO_CTRL, 0x0);
-
- ret = mt76x0_mcu_cmd_init(dev);
+ ret = mt76x02_mcu_function_select(dev, Q_SELECT, 1, false);
if (ret)
- goto err;
- ret = mt76x0_dma_init(dev);
- if (ret)
- goto err_mcu;
+ return ret;
mt76x0_init_mac_registers(dev);
- if (!mt76_poll_msec(dev, MT_MAC_STATUS,
- MT_MAC_STATUS_TX | MT_MAC_STATUS_RX, 0, 1000)) {
- ret = -EIO;
- goto err_rx;
- }
+ if (!mt76x02_wait_for_txrx_idle(&dev->mt76))
+ return -EIO;
ret = mt76x0_init_bbp(dev);
if (ret)
- goto err_rx;
+ return ret;
+
+ dev->mt76.rxfilter = mt76_rr(dev, MT_RX_FILTR_CFG);
ret = mt76x0_init_wcid_mem(dev);
if (ret)
- goto err_rx;
- ret = mt76x0_init_key_mem(dev);
- if (ret)
- goto err_rx;
+ return ret;
+
+ mt76x0_init_key_mem(dev);
+
ret = mt76x0_init_wcid_attr_mem(dev);
if (ret)
- goto err_rx;
+ return ret;
mt76_clear(dev, MT_BEACON_TIME_CFG, (MT_BEACON_TIME_CFG_TIMER_EN |
MT_BEACON_TIME_CFG_SYNC_MODE |
@@ -445,276 +312,85 @@ int mt76x0_init_hardware(struct mt76x0_dev *dev)
mt76x0_reset_counters(dev);
- mt76_rmw(dev, MT_US_CYC_CFG, MT_US_CYC_CNT, 0x1e);
-
- mt76_wr(dev, MT_TXOP_CTRL_CFG,
- FIELD_PREP(MT_TXOP_TRUN_EN, 0x3f) |
- FIELD_PREP(MT_TXOP_EXT_CCA_DLY, 0x58));
-
ret = mt76x0_eeprom_init(dev);
if (ret)
- goto err_rx;
+ return ret;
mt76x0_phy_init(dev);
- return 0;
-
-err_rx:
- mt76x0_dma_cleanup(dev);
-err_mcu:
- mt76x0_mcu_cmd_deinit(dev);
-err:
- mt76x0_chip_onoff(dev, false, false);
- return ret;
-}
-
-void mt76x0_cleanup(struct mt76x0_dev *dev)
-{
- if (!test_and_clear_bit(MT76_STATE_INITIALIZED, &dev->mt76.state))
- return;
- mt76x0_stop_hardware(dev);
- mt76x0_dma_cleanup(dev);
- mt76x0_mcu_cmd_deinit(dev);
+ return 0;
}
+EXPORT_SYMBOL_GPL(mt76x0_init_hardware);
-struct mt76x0_dev *mt76x0_alloc_device(struct device *pdev)
+struct mt76x02_dev *
+mt76x0_alloc_device(struct device *pdev,
+ const struct mt76_driver_ops *drv_ops,
+ const struct ieee80211_ops *ops)
{
- struct ieee80211_hw *hw;
- struct mt76x0_dev *dev;
+ struct mt76x02_dev *dev;
+ struct mt76_dev *mdev;
- hw = ieee80211_alloc_hw(sizeof(*dev), &mt76x0_ops);
- if (!hw)
+ mdev = mt76_alloc_device(sizeof(*dev), ops);
+ if (!mdev)
return NULL;
- dev = hw->priv;
- dev->mt76.dev = pdev;
- dev->mt76.hw = hw;
- mutex_init(&dev->usb_ctrl_mtx);
- mutex_init(&dev->reg_atomic_mutex);
- mutex_init(&dev->hw_atomic_mutex);
- mutex_init(&dev->mutex);
- spin_lock_init(&dev->tx_lock);
- spin_lock_init(&dev->rx_lock);
- spin_lock_init(&dev->mt76.lock);
- spin_lock_init(&dev->mac_lock);
- spin_lock_init(&dev->con_mon_lock);
- atomic_set(&dev->avg_ampdu_len, 1);
- skb_queue_head_init(&dev->tx_skb_done);
+ mdev->dev = pdev;
+ mdev->drv = drv_ops;
- dev->stat_wq = alloc_workqueue("mt76x0", WQ_UNBOUND, 0);
- if (!dev->stat_wq) {
- ieee80211_free_hw(hw);
- return NULL;
- }
+ dev = container_of(mdev, struct mt76x02_dev, mt76);
+ mutex_init(&dev->phy_mutex);
+ atomic_set(&dev->avg_ampdu_len, 1);
return dev;
}
+EXPORT_SYMBOL_GPL(mt76x0_alloc_device);
-#define CHAN2G(_idx, _freq) { \
- .band = NL80211_BAND_2GHZ, \
- .center_freq = (_freq), \
- .hw_value = (_idx), \
- .max_power = 30, \
-}
-
-static const struct ieee80211_channel mt76_channels_2ghz[] = {
- CHAN2G(1, 2412),
- CHAN2G(2, 2417),
- CHAN2G(3, 2422),
- CHAN2G(4, 2427),
- CHAN2G(5, 2432),
- CHAN2G(6, 2437),
- CHAN2G(7, 2442),
- CHAN2G(8, 2447),
- CHAN2G(9, 2452),
- CHAN2G(10, 2457),
- CHAN2G(11, 2462),
- CHAN2G(12, 2467),
- CHAN2G(13, 2472),
- CHAN2G(14, 2484),
-};
-
-#define CHAN5G(_idx, _freq) { \
- .band = NL80211_BAND_5GHZ, \
- .center_freq = (_freq), \
- .hw_value = (_idx), \
- .max_power = 30, \
-}
-
-static const struct ieee80211_channel mt76_channels_5ghz[] = {
- CHAN5G(36, 5180),
- CHAN5G(40, 5200),
- CHAN5G(44, 5220),
- CHAN5G(46, 5230),
- CHAN5G(48, 5240),
- CHAN5G(52, 5260),
- CHAN5G(56, 5280),
- CHAN5G(60, 5300),
- CHAN5G(64, 5320),
-
- CHAN5G(100, 5500),
- CHAN5G(104, 5520),
- CHAN5G(108, 5540),
- CHAN5G(112, 5560),
- CHAN5G(116, 5580),
- CHAN5G(120, 5600),
- CHAN5G(124, 5620),
- CHAN5G(128, 5640),
- CHAN5G(132, 5660),
- CHAN5G(136, 5680),
- CHAN5G(140, 5700),
-};
-
-#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) | (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, \
-}
-
-static struct ieee80211_rate mt76_rates[] = {
- CCK_RATE(0, 10),
- CCK_RATE(1, 20),
- CCK_RATE(2, 55),
- CCK_RATE(3, 110),
- OFDM_RATE(0, 60),
- OFDM_RATE(1, 90),
- OFDM_RATE(2, 120),
- OFDM_RATE(3, 180),
- OFDM_RATE(4, 240),
- OFDM_RATE(5, 360),
- OFDM_RATE(6, 480),
- OFDM_RATE(7, 540),
-};
-
-static int
-mt76_init_sband(struct mt76x0_dev *dev, struct ieee80211_supported_band *sband,
- const struct ieee80211_channel *chan, int n_chan,
- struct ieee80211_rate *rates, int n_rates)
-{
- struct ieee80211_sta_ht_cap *ht_cap;
- void *chanlist;
- int size;
-
- size = n_chan * sizeof(*chan);
- chanlist = devm_kmemdup(dev->mt76.dev, chan, size, GFP_KERNEL);
- if (!chanlist)
- return -ENOMEM;
-
- sband->channels = chanlist;
- sband->n_channels = n_chan;
- sband->bitrates = rates;
- sband->n_bitrates = n_rates;
-
- ht_cap = &sband->ht_cap;
- ht_cap->ht_supported = true;
- ht_cap->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
- IEEE80211_HT_CAP_GRN_FLD |
- IEEE80211_HT_CAP_SGI_20 |
- IEEE80211_HT_CAP_SGI_40 |
- (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
-
- ht_cap->mcs.rx_mask[0] = 0xff;
- ht_cap->mcs.rx_mask[4] = 0x1;
- ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
- ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
- ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_2;
-
- return 0;
-}
-
-static int
-mt76_init_sband_2g(struct mt76x0_dev *dev)
-{
- dev->mt76.hw->wiphy->bands[NL80211_BAND_2GHZ] = &dev->mt76.sband_2g.sband;
-
- WARN_ON(dev->ee->reg.start - 1 + dev->ee->reg.num >
- ARRAY_SIZE(mt76_channels_2ghz));
-
-
- return mt76_init_sband(dev, &dev->mt76.sband_2g.sband,
- mt76_channels_2ghz, ARRAY_SIZE(mt76_channels_2ghz),
- mt76_rates, ARRAY_SIZE(mt76_rates));
-}
-
-static int
-mt76_init_sband_5g(struct mt76x0_dev *dev)
-{
- dev->mt76.hw->wiphy->bands[NL80211_BAND_5GHZ] = &dev->mt76.sband_5g.sband;
-
- return mt76_init_sband(dev, &dev->mt76.sband_5g.sband,
- mt76_channels_5ghz, ARRAY_SIZE(mt76_channels_5ghz),
- mt76_rates + 4, ARRAY_SIZE(mt76_rates) - 4);
-}
-
-
-int mt76x0_register_device(struct mt76x0_dev *dev)
+int mt76x0_register_device(struct mt76x02_dev *dev)
{
- struct ieee80211_hw *hw = dev->mt76.hw;
+ struct mt76_dev *mdev = &dev->mt76;
+ struct ieee80211_hw *hw = mdev->hw;
struct wiphy *wiphy = hw->wiphy;
int ret;
/* Reserve WCID 0 for mcast - thanks to this APs WCID will go to
* entry no. 1 like it does in the vendor driver.
*/
- dev->wcid_mask[0] |= 1;
+ mdev->wcid_mask[0] |= 1;
/* init fake wcid for monitor interfaces */
- dev->mon_wcid = devm_kmalloc(dev->mt76.dev, sizeof(*dev->mon_wcid),
- GFP_KERNEL);
- if (!dev->mon_wcid)
- return -ENOMEM;
- dev->mon_wcid->idx = 0xff;
- dev->mon_wcid->hw_key_idx = -1;
+ mdev->global_wcid.idx = 0xff;
+ mdev->global_wcid.hw_key_idx = -1;
- SET_IEEE80211_DEV(hw, dev->mt76.dev);
+ /* init antenna configuration */
+ mdev->antenna_mask = 1;
hw->queues = 4;
- ieee80211_hw_set(hw, SIGNAL_DBM);
- ieee80211_hw_set(hw, PS_NULLFUNC_STACK);
- ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES);
- ieee80211_hw_set(hw, AMPDU_AGGREGATION);
- ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
hw->max_rates = 1;
hw->max_report_rates = 7;
hw->max_rate_tries = 1;
+ hw->extra_tx_headroom = 2;
+ if (mt76_is_usb(dev))
+ hw->extra_tx_headroom += sizeof(struct mt76x02_txwi) +
+ MT_DMA_HDR_LEN;
- hw->sta_data_size = sizeof(struct mt76_sta);
- hw->vif_data_size = sizeof(struct mt76_vif);
-
- SET_IEEE80211_PERM_ADDR(hw, dev->macaddr);
+ hw->sta_data_size = sizeof(struct mt76x02_sta);
+ hw->vif_data_size = sizeof(struct mt76x02_vif);
- wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
- if (dev->ee->has_2ghz) {
- ret = mt76_init_sband_2g(dev);
- if (ret)
- return ret;
- }
-
- if (dev->ee->has_5ghz) {
- ret = mt76_init_sband_5g(dev);
- if (ret)
- return ret;
- }
-
- dev->mt76.chandef.chan = &dev->mt76.sband_2g.sband.channels[0];
-
INIT_DELAYED_WORK(&dev->mac_work, mt76x0_mac_work);
- INIT_DELAYED_WORK(&dev->stat_work, mt76x0_tx_stat);
- ret = ieee80211_register_hw(hw);
+ ret = mt76_register_device(mdev, true, mt76x02_rates,
+ ARRAY_SIZE(mt76x02_rates));
if (ret)
return ret;
+ /* overwrite unsupported features */
+ if (mdev->cap.has_5ghz)
+ mt76x0_vht_cap_mask(&dev->mt76.sband_5g.sband);
+
mt76x0_init_debugfs(dev);
return 0;
}
+EXPORT_SYMBOL_GPL(mt76x0_register_device);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/initvals.h b/drivers/net/wireless/mediatek/mt76/mt76x0/initvals.h
index 24afcfd94b4e..236dce6860b4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/initvals.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/initvals.h
@@ -2,6 +2,7 @@
* (c) Copyright 2002-2010, Ralink Technology, Inc.
* Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
* Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl>
+ * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
@@ -19,264 +20,215 @@
#include "phy.h"
static const struct mt76_reg_pair common_mac_reg_table[] = {
-#if 1
- {MT_BCN_OFFSET(0), 0xf8f0e8e0}, /* 0x3800(e0), 0x3A00(e8), 0x3C00(f0), 0x3E00(f8), 512B for each beacon */
- {MT_BCN_OFFSET(1), 0x6f77d0c8}, /* 0x3200(c8), 0x3400(d0), 0x1DC0(77), 0x1BC0(6f), 512B for each beacon */
-#endif
-
- {MT_LEGACY_BASIC_RATE, 0x0000013f}, /* Basic rate set bitmap*/
- {MT_HT_BASIC_RATE, 0x00008003}, /* Basic HT rate set , 20M, MCS=3, MM. Format is the same as in TXWI.*/
- {MT_MAC_SYS_CTRL, 0x00}, /* 0x1004, , default Disable RX*/
- {MT_RX_FILTR_CFG, 0x17f97}, /*0x1400 , RX filter control, */
- {MT_BKOFF_SLOT_CFG, 0x209}, /* default set short slot time, CC_DELAY_TIME should be 2 */
- /*{TX_SW_CFG0, 0x40a06}, Gary,2006-08-23 */
- {MT_TX_SW_CFG0, 0x0}, /* Gary,2008-05-21 for CWC test */
- {MT_TX_SW_CFG1, 0x80606}, /* Gary,2006-08-23 */
- {MT_TX_LINK_CFG, 0x1020}, /* Gary,2006-08-23 */
- /*{TX_TIMEOUT_CFG, 0x00182090}, CCK has some problem. So increase timieout value. 2006-10-09 MArvek RT*/
- {MT_TX_TIMEOUT_CFG, 0x000a2090}, /* CCK has some problem. So increase timieout value. 2006-10-09 MArvek RT , Modify for 2860E ,2007-08-01*/
- {MT_MAX_LEN_CFG, 0xa0fff | 0x00001000}, /* 0x3018, MAX frame length. Max PSDU = 16kbytes.*/
- {MT_LED_CFG, 0x7f031e46}, /* Gary, 2006-08-23*/
-
- {MT_PBF_TX_MAX_PCNT, 0x1fbf1f1f /*0xbfbf3f1f*/},
- {MT_PBF_RX_MAX_PCNT, 0x9f},
-
- /*{TX_RTY_CFG, 0x6bb80408}, Jan, 2006/11/16*/
-/* WMM_ACM_SUPPORT */
-/* {TX_RTY_CFG, 0x6bb80101}, sample*/
- {MT_TX_RETRY_CFG, 0x47d01f0f}, /* Jan, 2006/11/16, Set TxWI->ACK =0 in Probe Rsp Modify for 2860E ,2007-08-03*/
-
- {MT_AUTO_RSP_CFG, 0x00000013}, /* Initial Auto_Responder, because QA will turn off Auto-Responder*/
- {MT_CCK_PROT_CFG, 0x05740003 /*0x01740003*/}, /* Initial Auto_Responder, because QA will turn off Auto-Responder. And RTS threshold is enabled. */
- {MT_OFDM_PROT_CFG, 0x05740003 /*0x01740003*/}, /* Initial Auto_Responder, because QA will turn off Auto-Responder. And RTS threshold is enabled. */
- {MT_PBF_CFG, 0xf40006}, /* Only enable Queue 2*/
- {MT_MM40_PROT_CFG, 0x3F44084}, /* Initial Auto_Responder, because QA will turn off Auto-Responder*/
- {MT_WPDMA_GLO_CFG, 0x00000030},
- {MT_GF20_PROT_CFG, 0x01744004}, /* set 19:18 --> Short NAV for MIMO PS*/
- {MT_GF40_PROT_CFG, 0x03F44084},
- {MT_MM20_PROT_CFG, 0x01744004},
- {MT_TXOP_CTRL_CFG, 0x0000583f, /*0x0000243f*/ /*0x000024bf*/}, /*Extension channel backoff.*/
- {MT_TX_RTS_CFG, 0x00092b20},
-
- {MT_EXP_ACK_TIME, 0x002400ca}, /* default value */
- {MT_TXOP_HLDR_ET, 0x00000002},
-
- /* Jerry comments 2008/01/16: we use SIFS = 10us in CCK defaultly, but it seems that 10us
- is too small for INTEL 2200bg card, so in MBSS mode, the delta time between beacon0
- and beacon1 is SIFS (10us), so if INTEL 2200bg card connects to BSS0, the ping
- will always lost. So we change the SIFS of CCK from 10us to 16us. */
- {MT_XIFS_TIME_CFG, 0x33a41010},
- {MT_PWR_PIN_CFG, 0x00000000},
+ { MT_BCN_OFFSET(0), 0xf8f0e8e0 },
+ { MT_BCN_OFFSET(1), 0x6f77d0c8 },
+ { MT_LEGACY_BASIC_RATE, 0x0000013f },
+ { MT_HT_BASIC_RATE, 0x00008003 },
+ { MT_MAC_SYS_CTRL, 0x00000000 },
+ { MT_RX_FILTR_CFG, 0x00017f97 },
+ { MT_BKOFF_SLOT_CFG, 0x00000209 },
+ { MT_TX_SW_CFG0, 0x00000000 },
+ { MT_TX_SW_CFG1, 0x00080606 },
+ { MT_TX_LINK_CFG, 0x00001020 },
+ { MT_TX_TIMEOUT_CFG, 0x000a2090 },
+ { MT_MAX_LEN_CFG, 0xa0fff | 0x00001000 },
+ { MT_LED_CFG, 0x7f031e46 },
+ { MT_PBF_TX_MAX_PCNT, 0x1fbf1f1f },
+ { MT_PBF_RX_MAX_PCNT, 0x0000fe9f },
+ { MT_TX_RETRY_CFG, 0x47d01f0f },
+ { MT_AUTO_RSP_CFG, 0x00000013 },
+ { MT_CCK_PROT_CFG, 0x05740003 },
+ { MT_OFDM_PROT_CFG, 0x05740003 },
+ { MT_PBF_CFG, 0x00f40006 },
+ { MT_WPDMA_GLO_CFG, 0x00000030 },
+ { MT_GF20_PROT_CFG, 0x01744004 },
+ { MT_GF40_PROT_CFG, 0x03f44084 },
+ { MT_MM20_PROT_CFG, 0x01744004 },
+ { MT_MM40_PROT_CFG, 0x03f54084 },
+ { MT_TXOP_CTRL_CFG, 0x0000583f },
+ { MT_TX_RTS_CFG, 0x00092b20 },
+ { MT_EXP_ACK_TIME, 0x002400ca },
+ { MT_TXOP_HLDR_ET, 0x00000002 },
+ { MT_XIFS_TIME_CFG, 0x33a41010 },
+ { MT_PWR_PIN_CFG, 0x00000000 },
};
static const struct mt76_reg_pair mt76x0_mac_reg_table[] = {
- /* {MT_IOCFG_6, 0xA0040080 }, */
- {MT_PBF_SYS_CTRL, 0x00080c00 },
- {MT_PBF_CFG, 0x77723c1f },
- {MT_FCE_PSE_CTRL, 0x00000001 },
-
- {MT_AMPDU_MAX_LEN_20M1S, 0xBAA99887 },
-
- /* Delay bb_tx_pe for proper tx_mcs_pwr update */
- {MT_TX_SW_CFG0, 0x00000601 },
-
- /* Set rf_tx_pe deassert time to 1us by Chee's comment @MT7650_CR_setting_1018.xlsx */
- {MT_TX_SW_CFG1, 0x00040000 },
- {MT_TX_SW_CFG2, 0x00000000 },
-
- /* disable Tx info report */
- {0xa44, 0x0000000 },
-
- {MT_HEADER_TRANS_CTRL_REG, 0x0},
- {MT_TSO_CTRL, 0x0},
-
- /* BB_PA_MODE_CFG0(0x1214) Keep default value @20120903 */
- {MT_BB_PA_MODE_CFG1, 0x00500055},
-
- /* RF_PA_MODE_CFG0(0x121C) Keep default value @20120903 */
- {MT_RF_PA_MODE_CFG1, 0x00500055},
-
- {MT_TX_ALC_CFG_0, 0x2F2F000C},
- {MT_TX0_BB_GAIN_ATTEN, 0x00000000}, /* set BBP atten gain = 0 */
-
- {MT_TX_PWR_CFG_0, 0x3A3A3A3A},
- {MT_TX_PWR_CFG_1, 0x3A3A3A3A},
- {MT_TX_PWR_CFG_2, 0x3A3A3A3A},
- {MT_TX_PWR_CFG_3, 0x3A3A3A3A},
- {MT_TX_PWR_CFG_4, 0x3A3A3A3A},
- {MT_TX_PWR_CFG_7, 0x3A3A3A3A},
- {MT_TX_PWR_CFG_8, 0x3A},
- {MT_TX_PWR_CFG_9, 0x3A},
- /* Enable Tx length > 4095 byte */
- {0x150C, 0x00000002},
-
- /* Disable bt_abort_tx_en(0x1238[21] = 0) which is not used at MT7650 */
- {0x1238, 0x001700C8},
- /* PMU_OCLEVEL<5:1> from default <5'b10010> to <5'b11011> for normal driver */
- /* {MT_LDO_CTRL_0, 0x00A647B6}, */
-
- /* Default LDO_DIG supply 1.26V, change to 1.2V */
- {MT_LDO_CTRL_1, 0x6B006464 },
-/*
- {MT_HT_BASIC_RATE, 0x00004003 },
- {MT_HT_CTRL_CFG, 0x000001FF },
-*/
+ { MT_IOCFG_6, 0xa0040080 },
+ { MT_PBF_SYS_CTRL, 0x00080c00 },
+ { MT_PBF_CFG, 0x77723c1f },
+ { MT_FCE_PSE_CTRL, 0x00000001 },
+ { MT_AMPDU_MAX_LEN_20M1S, 0xAAA99887 },
+ { MT_TX_SW_CFG0, 0x00000601 },
+ { MT_TX_SW_CFG1, 0x00040000 },
+ { MT_TX_SW_CFG2, 0x00000000 },
+ { 0xa44, 0x00000000 },
+ { MT_HEADER_TRANS_CTRL_REG, 0x00000000 },
+ { MT_TSO_CTRL, 0x00000000 },
+ { MT_BB_PA_MODE_CFG1, 0x00500055 },
+ { MT_RF_PA_MODE_CFG1, 0x00500055 },
+ { MT_TX_ALC_CFG_0, 0x2F2F000C },
+ { MT_TX0_BB_GAIN_ATTEN, 0x00000000 },
+ { MT_TX_PWR_CFG_0, 0x3A3A3A3A },
+ { MT_TX_PWR_CFG_1, 0x3A3A3A3A },
+ { MT_TX_PWR_CFG_2, 0x3A3A3A3A },
+ { MT_TX_PWR_CFG_3, 0x3A3A3A3A },
+ { MT_TX_PWR_CFG_4, 0x3A3A3A3A },
+ { MT_TX_PWR_CFG_7, 0x3A3A3A3A },
+ { MT_TX_PWR_CFG_8, 0x0000003A },
+ { MT_TX_PWR_CFG_9, 0x0000003A },
+ { 0x150C, 0x00000002 },
+ { 0x1238, 0x001700C8 },
+ { MT_LDO_CTRL_0, 0x00A647B6 },
+ { MT_LDO_CTRL_1, 0x6B006464 },
+ { MT_HT_BASIC_RATE, 0x00004003 },
+ { MT_HT_CTRL_CFG, 0x000001FF },
+ { MT_TXOP_HLDR_ET, 0x00000000 },
+ { MT_PN_PAD_MODE, 0x00000003 },
};
-
static const struct mt76_reg_pair mt76x0_bbp_init_tab[] = {
- {MT_BBP(CORE, 1), 0x00000002},
- {MT_BBP(CORE, 4), 0x00000000},
- {MT_BBP(CORE, 24), 0x00000000},
- {MT_BBP(CORE, 32), 0x4003000a},
- {MT_BBP(CORE, 42), 0x00000000},
- {MT_BBP(CORE, 44), 0x00000000},
-
- {MT_BBP(IBI, 11), 0x00000080},
-
- /*
- 0x2300[5] Default Antenna:
- 0 for WIFI main antenna
- 1 for WIFI aux antenna
-
- */
- {MT_BBP(AGC, 0), 0x00021400},
- {MT_BBP(AGC, 1), 0x00000003},
- {MT_BBP(AGC, 2), 0x003A6464},
- {MT_BBP(AGC, 15), 0x88A28CB8},
- {MT_BBP(AGC, 22), 0x00001E21},
- {MT_BBP(AGC, 23), 0x0000272C},
- {MT_BBP(AGC, 24), 0x00002F3A},
- {MT_BBP(AGC, 25), 0x8000005A},
- {MT_BBP(AGC, 26), 0x007C2005},
- {MT_BBP(AGC, 34), 0x000A0C0C},
- {MT_BBP(AGC, 37), 0x2121262C},
- {MT_BBP(AGC, 41), 0x38383E45},
- {MT_BBP(AGC, 57), 0x00001010},
- {MT_BBP(AGC, 59), 0xBAA20E96},
- {MT_BBP(AGC, 63), 0x00000001},
-
- {MT_BBP(TXC, 0), 0x00280403},
- {MT_BBP(TXC, 1), 0x00000000},
-
- {MT_BBP(RXC, 1), 0x00000012},
- {MT_BBP(RXC, 2), 0x00000011},
- {MT_BBP(RXC, 3), 0x00000005},
- {MT_BBP(RXC, 4), 0x00000000},
- {MT_BBP(RXC, 5), 0xF977C4EC},
- {MT_BBP(RXC, 7), 0x00000090},
-
- {MT_BBP(TXO, 8), 0x00000000},
-
- {MT_BBP(TXBE, 0), 0x00000000},
- {MT_BBP(TXBE, 4), 0x00000004},
- {MT_BBP(TXBE, 6), 0x00000000},
- {MT_BBP(TXBE, 8), 0x00000014},
- {MT_BBP(TXBE, 9), 0x20000000},
- {MT_BBP(TXBE, 10), 0x00000000},
- {MT_BBP(TXBE, 12), 0x00000000},
- {MT_BBP(TXBE, 13), 0x00000000},
- {MT_BBP(TXBE, 14), 0x00000000},
- {MT_BBP(TXBE, 15), 0x00000000},
- {MT_BBP(TXBE, 16), 0x00000000},
- {MT_BBP(TXBE, 17), 0x00000000},
-
- {MT_BBP(RXFE, 1), 0x00008800}, /* Add for E3 */
- {MT_BBP(RXFE, 3), 0x00000000},
- {MT_BBP(RXFE, 4), 0x00000000},
-
- {MT_BBP(RXO, 13), 0x00000092},
- {MT_BBP(RXO, 14), 0x00060612},
- {MT_BBP(RXO, 15), 0xC8321B18},
- {MT_BBP(RXO, 16), 0x0000001E},
- {MT_BBP(RXO, 17), 0x00000000},
- {MT_BBP(RXO, 18), 0xCC00A993},
- {MT_BBP(RXO, 19), 0xB9CB9CB9},
- {MT_BBP(RXO, 20), 0x26c00057},
- {MT_BBP(RXO, 21), 0x00000001},
- {MT_BBP(RXO, 24), 0x00000006},
+ { MT_BBP(CORE, 1), 0x00000002 },
+ { MT_BBP(CORE, 4), 0x00000000 },
+ { MT_BBP(CORE, 24), 0x00000000 },
+ { MT_BBP(CORE, 32), 0x4003000a },
+ { MT_BBP(CORE, 42), 0x00000000 },
+ { MT_BBP(CORE, 44), 0x00000000 },
+ { MT_BBP(IBI, 11), 0x0FDE8081 },
+ { MT_BBP(AGC, 0), 0x00021400 },
+ { MT_BBP(AGC, 1), 0x00000003 },
+ { MT_BBP(AGC, 2), 0x003A6464 },
+ { MT_BBP(AGC, 15), 0x88A28CB8 },
+ { MT_BBP(AGC, 22), 0x00001E21 },
+ { MT_BBP(AGC, 23), 0x0000272C },
+ { MT_BBP(AGC, 24), 0x00002F3A },
+ { MT_BBP(AGC, 25), 0x8000005A },
+ { MT_BBP(AGC, 26), 0x007C2005 },
+ { MT_BBP(AGC, 33), 0x00003238 },
+ { MT_BBP(AGC, 34), 0x000A0C0C },
+ { MT_BBP(AGC, 37), 0x2121262C },
+ { MT_BBP(AGC, 41), 0x38383E45 },
+ { MT_BBP(AGC, 57), 0x00001010 },
+ { MT_BBP(AGC, 59), 0xBAA20E96 },
+ { MT_BBP(AGC, 63), 0x00000001 },
+ { MT_BBP(TXC, 0), 0x00280403 },
+ { MT_BBP(TXC, 1), 0x00000000 },
+ { MT_BBP(RXC, 1), 0x00000012 },
+ { MT_BBP(RXC, 2), 0x00000011 },
+ { MT_BBP(RXC, 3), 0x00000005 },
+ { MT_BBP(RXC, 4), 0x00000000 },
+ { MT_BBP(RXC, 5), 0xF977C4EC },
+ { MT_BBP(RXC, 7), 0x00000090 },
+ { MT_BBP(TXO, 8), 0x00000000 },
+ { MT_BBP(TXBE, 0), 0x00000000 },
+ { MT_BBP(TXBE, 4), 0x00000004 },
+ { MT_BBP(TXBE, 6), 0x00000000 },
+ { MT_BBP(TXBE, 8), 0x00000014 },
+ { MT_BBP(TXBE, 9), 0x20000000 },
+ { MT_BBP(TXBE, 10), 0x00000000 },
+ { MT_BBP(TXBE, 12), 0x00000000 },
+ { MT_BBP(TXBE, 13), 0x00000000 },
+ { MT_BBP(TXBE, 14), 0x00000000 },
+ { MT_BBP(TXBE, 15), 0x00000000 },
+ { MT_BBP(TXBE, 16), 0x00000000 },
+ { MT_BBP(TXBE, 17), 0x00000000 },
+ { MT_BBP(RXFE, 1), 0x00008800 },
+ { MT_BBP(RXFE, 3), 0x00000000 },
+ { MT_BBP(RXFE, 4), 0x00000000 },
+ { MT_BBP(RXO, 13), 0x00000192 },
+ { MT_BBP(RXO, 14), 0x00060612 },
+ { MT_BBP(RXO, 15), 0xC8321B18 },
+ { MT_BBP(RXO, 16), 0x0000001E },
+ { MT_BBP(RXO, 17), 0x00000000 },
+ { MT_BBP(RXO, 18), 0xCC00A993 },
+ { MT_BBP(RXO, 19), 0xB9CB9CB9 },
+ { MT_BBP(RXO, 20), 0x26c00057 },
+ { MT_BBP(RXO, 21), 0x00000001 },
+ { MT_BBP(RXO, 24), 0x00000006 },
+ { MT_BBP(RXO, 28), 0x0000003F },
};
static const struct mt76x0_bbp_switch_item mt76x0_bbp_switch_tab[] = {
- {RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 8), 0x0E344EF0}},
- {RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 8), 0x122C54F2}},
+ { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 4), 0x1FEDA049 } },
+ { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 4), 0x1FECA054 } },
+
+ { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 6), 0x00000045 } },
+ { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 6), 0x0000000A } },
- {RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 14), 0x310F2E39}},
- {RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 14), 0x310F2A3F}},
+ { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 8), 0x16344EF0 } },
+ { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 8), 0x122C54F2 } },
- {RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 32), 0x00003230}},
- {RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 32), 0x0000181C}},
+ { RF_G_BAND | RF_BW_20, { MT_BBP(AGC, 12), 0x05052879 } },
+ { RF_G_BAND | RF_BW_40, { MT_BBP(AGC, 12), 0x050528F9 } },
+ { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 12), 0x050528F9 } },
- {RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 33), 0x00003240}},
- {RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 33), 0x00003218}},
+ { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 13), 0x35050004 } },
+ { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 13), 0x2C3A0406 } },
- {RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 35), 0x11112016}},
- {RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 35), 0x11112016}},
+ { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 14), 0x310F2E3C } },
+ { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 14), 0x310F2A3F } },
- {RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(RXO, 28), 0x0000008A}},
- {RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(RXO, 28), 0x0000008A}},
+ { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 26), 0x007C2005 } },
+ { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 26), 0x007C2005 } },
- {RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 4), 0x1FEDA049}},
- {RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 4), 0x1FECA054}},
+ { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 27), 0x000000E1 } },
+ { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 27), 0x000000EC } },
- {RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 6), 0x00000045}},
- {RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 6), 0x0000000A}},
+ { RF_G_BAND | RF_BW_20, { MT_BBP(AGC, 28), 0x00060806 } },
+ { RF_G_BAND | RF_BW_40, { MT_BBP(AGC, 28), 0x00050806 } },
+ { RF_A_BAND | RF_BW_40, { MT_BBP(AGC, 28), 0x00060801 } },
+ { RF_A_BAND | RF_BW_20 | RF_BW_80, { MT_BBP(AGC, 28), 0x00060806 } },
- {RF_G_BAND | RF_BW_20, {MT_BBP(AGC, 12), 0x05052879}},
- {RF_G_BAND | RF_BW_40, {MT_BBP(AGC, 12), 0x050528F9}},
- {RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 12), 0x050528F9}},
+ { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(RXO, 28), 0x0000008A } },
- {RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 13), 0x35050004}},
- {RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 13), 0x2C3A0406}},
+ { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 31), 0x00000E23 } },
+ { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 31), 0x00000E13 } },
- {RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 27), 0x000000E1}},
- {RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 27), 0x000000EC}},
+ { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 32), 0x00003218 } },
+ { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 32), 0x0000181C } },
- {RF_G_BAND | RF_BW_20, {MT_BBP(AGC, 28), 0x00060806}},
- {RF_G_BAND | RF_BW_40, {MT_BBP(AGC, 28), 0x00050806}},
- {RF_A_BAND | RF_BW_40, {MT_BBP(AGC, 28), 0x00060801}},
- {RF_A_BAND | RF_BW_20 | RF_BW_80, {MT_BBP(AGC, 28), 0x00060806}},
+ { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 33), 0x00003240 } },
+ { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 33), 0x00003218 } },
- {RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 31), 0x00000F23}},
- {RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 31), 0x00000F13}},
+ { RF_G_BAND | RF_BW_20, { MT_BBP(AGC, 35), 0x11111616 } },
+ { RF_G_BAND | RF_BW_40, { MT_BBP(AGC, 35), 0x11111516 } },
+ { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 35), 0x11111111 } },
- {RF_G_BAND | RF_BW_20, {MT_BBP(AGC, 39), 0x2A2A3036}},
- {RF_G_BAND | RF_BW_40, {MT_BBP(AGC, 39), 0x2A2A2C36}},
- {RF_A_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 39), 0x2A2A3036}},
- {RF_A_BAND | RF_BW_80, {MT_BBP(AGC, 39), 0x2A2A2A36}},
+ { RF_G_BAND | RF_BW_20, { MT_BBP(AGC, 39), 0x2A2A3036 } },
+ { RF_G_BAND | RF_BW_40, { MT_BBP(AGC, 39), 0x2A2A2C36 } },
+ { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 39), 0x2A2A2A2A } },
- {RF_G_BAND | RF_BW_20, {MT_BBP(AGC, 43), 0x27273438}},
- {RF_G_BAND | RF_BW_40, {MT_BBP(AGC, 43), 0x27272D38}},
- {RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 43), 0x27272B30}},
+ { RF_G_BAND | RF_BW_20, { MT_BBP(AGC, 43), 0x27273438 } },
+ { RF_G_BAND | RF_BW_40, { MT_BBP(AGC, 43), 0x27272D38 } },
+ { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 43), 0x27271A1A } },
- {RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 51), 0x17171C1C}},
- {RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 51), 0xFFFFFFFF}},
+ { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 51), 0x17171C1C } },
+ { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 51), 0xFFFFFFFF } },
- {RF_G_BAND | RF_BW_20, {MT_BBP(AGC, 53), 0x26262A2F}},
- {RF_G_BAND | RF_BW_40, {MT_BBP(AGC, 53), 0x2626322F}},
- {RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 53), 0xFFFFFFFF}},
+ { RF_G_BAND | RF_BW_20, { MT_BBP(AGC, 53), 0x26262A2F } },
+ { RF_G_BAND | RF_BW_40, { MT_BBP(AGC, 53), 0x2626322F } },
+ { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 53), 0xFFFFFFFF } },
- {RF_G_BAND | RF_BW_20, {MT_BBP(AGC, 55), 0x40404E58}},
- {RF_G_BAND | RF_BW_40, {MT_BBP(AGC, 55), 0x40405858}},
- {RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 55), 0xFFFFFFFF}},
+ { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 55), 0x40404040 } },
+ { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 55), 0xFFFFFFFF } },
- {RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(AGC, 58), 0x00001010}},
- {RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(AGC, 58), 0x00000000}},
+ { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 58), 0x00001010 } },
+ { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 58), 0x00000000 } },
- {RF_G_BAND | RF_BW_20 | RF_BW_40, {MT_BBP(RXFE, 0), 0x3D5000E0}},
- {RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, {MT_BBP(RXFE, 0), 0x895000E0}},
+ { RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(RXFE, 0), 0x3D5000E0 } },
+ { RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(RXFE, 0), 0x895000E0 } },
};
static const struct mt76_reg_pair mt76x0_dcoc_tab[] = {
- {MT_BBP(CAL, 47), 0x000010F0 },
- {MT_BBP(CAL, 48), 0x00008080 },
- {MT_BBP(CAL, 49), 0x00000F07 },
- {MT_BBP(CAL, 50), 0x00000040 },
- {MT_BBP(CAL, 51), 0x00000404 },
- {MT_BBP(CAL, 52), 0x00080803 },
- {MT_BBP(CAL, 53), 0x00000704 },
- {MT_BBP(CAL, 54), 0x00002828 },
- {MT_BBP(CAL, 55), 0x00005050 },
+ { MT_BBP(CAL, 47), 0x000010F0 },
+ { MT_BBP(CAL, 48), 0x00008080 },
+ { MT_BBP(CAL, 49), 0x00000F07 },
+ { MT_BBP(CAL, 50), 0x00000040 },
+ { MT_BBP(CAL, 51), 0x00000404 },
+ { MT_BBP(CAL, 52), 0x00080803 },
+ { MT_BBP(CAL, 53), 0x00000704 },
+ { MT_BBP(CAL, 54), 0x00002828 },
+ { MT_BBP(CAL, 55), 0x00005050 },
};
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c
index 91a84be36d3b..7a422c590211 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c
@@ -13,241 +13,13 @@
* GNU General Public License for more details.
*/
-#include "mt76x0.h"
-#include "trace.h"
#include <linux/etherdevice.h>
-static void
-mt76_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate,
- enum nl80211_band band)
-{
- u8 idx = FIELD_GET(MT_RXWI_RATE_INDEX, rate);
-
- txrate->idx = 0;
- txrate->flags = 0;
- txrate->count = 1;
-
- switch (FIELD_GET(MT_RXWI_RATE_PHY, rate)) {
- case MT_PHY_TYPE_OFDM:
- if (band == NL80211_BAND_2GHZ)
- idx += 4;
-
- txrate->idx = idx;
- return;
- case MT_PHY_TYPE_CCK:
- if (idx >= 8)
- idx -= 8;
-
- txrate->idx = idx;
- return;
- case MT_PHY_TYPE_HT_GF:
- txrate->flags |= IEEE80211_TX_RC_GREEN_FIELD;
- /* fall through */
- case MT_PHY_TYPE_HT:
- txrate->flags |= IEEE80211_TX_RC_MCS;
- txrate->idx = idx;
- break;
- case MT_PHY_TYPE_VHT:
- txrate->flags |= IEEE80211_TX_RC_VHT_MCS;
- txrate->idx = idx;
- break;
- default:
- WARN_ON(1);
- return;
- }
-
- switch (FIELD_GET(MT_RXWI_RATE_BW, rate)) {
- case MT_PHY_BW_20:
- break;
- case MT_PHY_BW_40:
- txrate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
- break;
- case MT_PHY_BW_80:
- txrate->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH;
- break;
- default:
- WARN_ON(1);
- return;
- }
-
- if (rate & MT_RXWI_RATE_SGI)
- txrate->flags |= IEEE80211_TX_RC_SHORT_GI;
-}
-
-static void
-mt76_mac_fill_tx_status(struct mt76x0_dev *dev, struct ieee80211_tx_info *info,
- struct mt76_tx_status *st, int n_frames)
-{
- struct ieee80211_tx_rate *rate = info->status.rates;
- int cur_idx, last_rate;
- int i;
-
- if (!n_frames)
- return;
-
- last_rate = min_t(int, st->retry, IEEE80211_TX_MAX_RATES - 1);
- mt76_mac_process_tx_rate(&rate[last_rate], st->rate,
- dev->mt76.chandef.chan->band);
- if (last_rate < IEEE80211_TX_MAX_RATES - 1)
- rate[last_rate + 1].idx = -1;
-
- cur_idx = rate[last_rate].idx + last_rate;
- for (i = 0; i <= last_rate; i++) {
- rate[i].flags = rate[last_rate].flags;
- rate[i].idx = max_t(int, 0, cur_idx - i);
- rate[i].count = 1;
- }
-
- rate[last_rate - 1].count = st->retry + 1 - last_rate;
-
- info->status.ampdu_len = n_frames;
- info->status.ampdu_ack_len = st->success ? n_frames : 0;
-
- if (st->pktid & MT_TXWI_PKTID_PROBE)
- info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
-
- if (st->aggr)
- info->flags |= IEEE80211_TX_CTL_AMPDU |
- IEEE80211_TX_STAT_AMPDU;
-
- if (!st->ack_req)
- info->flags |= IEEE80211_TX_CTL_NO_ACK;
- else if (st->success)
- info->flags |= IEEE80211_TX_STAT_ACK;
-}
-
-u16 mt76x0_mac_tx_rate_val(struct mt76x0_dev *dev,
- const struct ieee80211_tx_rate *rate, u8 *nss_val)
-{
- u16 rateval;
- u8 phy, rate_idx;
- u8 nss = 1;
- u8 bw = 0;
-
- if (rate->flags & IEEE80211_TX_RC_VHT_MCS) {
- rate_idx = rate->idx;
- nss = 1 + (rate->idx >> 4);
- phy = MT_PHY_TYPE_VHT;
- if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
- bw = 2;
- else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
- bw = 1;
- } else if (rate->flags & IEEE80211_TX_RC_MCS) {
- rate_idx = rate->idx;
- nss = 1 + (rate->idx >> 3);
- phy = MT_PHY_TYPE_HT;
- if (rate->flags & IEEE80211_TX_RC_GREEN_FIELD)
- phy = MT_PHY_TYPE_HT_GF;
- if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
- bw = 1;
- } else {
- const struct ieee80211_rate *r;
- int band = dev->mt76.chandef.chan->band;
- u16 val;
-
- r = &dev->mt76.hw->wiphy->bands[band]->bitrates[rate->idx];
- if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
- val = r->hw_value_short;
- else
- val = r->hw_value;
-
- phy = val >> 8;
- rate_idx = val & 0xff;
- bw = 0;
- }
-
- rateval = FIELD_PREP(MT_RXWI_RATE_INDEX, rate_idx);
- rateval |= FIELD_PREP(MT_RXWI_RATE_PHY, phy);
- rateval |= FIELD_PREP(MT_RXWI_RATE_BW, bw);
- if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
- rateval |= MT_RXWI_RATE_SGI;
-
- *nss_val = nss;
- return cpu_to_le16(rateval);
-}
-
-void mt76x0_mac_wcid_set_rate(struct mt76x0_dev *dev, struct mt76_wcid *wcid,
- const struct ieee80211_tx_rate *rate)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&dev->mt76.lock, flags);
- wcid->tx_rate = mt76x0_mac_tx_rate_val(dev, rate, &wcid->tx_rate_nss);
- wcid->tx_rate_set = true;
- spin_unlock_irqrestore(&dev->mt76.lock, flags);
-}
-
-struct mt76_tx_status mt76x0_mac_fetch_tx_status(struct mt76x0_dev *dev)
-{
- struct mt76_tx_status stat = {};
- u32 stat2, stat1;
-
- stat2 = mt76_rr(dev, MT_TX_STAT_FIFO_EXT);
- stat1 = mt76_rr(dev, MT_TX_STAT_FIFO);
-
- stat.valid = !!(stat1 & MT_TX_STAT_FIFO_VALID);
- stat.success = !!(stat1 & MT_TX_STAT_FIFO_SUCCESS);
- stat.aggr = !!(stat1 & MT_TX_STAT_FIFO_AGGR);
- stat.ack_req = !!(stat1 & MT_TX_STAT_FIFO_ACKREQ);
- stat.wcid = FIELD_GET(MT_TX_STAT_FIFO_WCID, stat1);
- stat.rate = FIELD_GET(MT_TX_STAT_FIFO_RATE, stat1);
-
- stat.retry = FIELD_GET(MT_TX_STAT_FIFO_EXT_RETRY, stat2);
- stat.pktid = FIELD_GET(MT_TX_STAT_FIFO_EXT_PKTID, stat2);
-
- return stat;
-}
-
-void mt76x0_send_tx_status(struct mt76x0_dev *dev, struct mt76_tx_status *stat, u8 *update)
-{
- struct ieee80211_tx_info info = {};
- struct ieee80211_sta *sta = NULL;
- struct mt76_wcid *wcid = NULL;
- struct mt76_sta *msta = NULL;
-
- rcu_read_lock();
- if (stat->wcid < ARRAY_SIZE(dev->wcid))
- wcid = rcu_dereference(dev->wcid[stat->wcid]);
-
- if (wcid) {
- void *priv;
- priv = msta = container_of(wcid, struct mt76_sta, wcid);
- sta = container_of(priv, struct ieee80211_sta, drv_priv);
- }
-
- if (msta && stat->aggr) {
- u32 stat_val, stat_cache;
-
- stat_val = stat->rate;
- stat_val |= ((u32) stat->retry) << 16;
- stat_cache = msta->status.rate;
- stat_cache |= ((u32) msta->status.retry) << 16;
-
- if (*update == 0 && stat_val == stat_cache &&
- stat->wcid == msta->status.wcid && msta->n_frames < 32) {
- msta->n_frames++;
- goto out;
- }
-
- mt76_mac_fill_tx_status(dev, &info, &msta->status,
- msta->n_frames);
- msta->status = *stat;
- msta->n_frames = 1;
- *update = 0;
- } else {
- mt76_mac_fill_tx_status(dev, &info, stat, 1);
- *update = 1;
- }
-
- spin_lock_bh(&dev->mac_lock);
- ieee80211_tx_status_noskb(dev->mt76.hw, sta, &info);
- spin_unlock_bh(&dev->mac_lock);
-out:
- rcu_read_unlock();
-}
+#include "mt76x0.h"
+#include "trace.h"
-void mt76x0_mac_set_protection(struct mt76x0_dev *dev, bool legacy_prot,
- int ht_mode)
+void mt76x0_mac_set_protection(struct mt76x02_dev *dev, bool legacy_prot,
+ int ht_mode)
{
int mode = ht_mode & IEEE80211_HT_OP_MODE_PROTECTION;
bool non_gf = !!(ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
@@ -305,7 +77,7 @@ void mt76x0_mac_set_protection(struct mt76x0_dev *dev, bool legacy_prot,
mt76_wr(dev, MT_CCK_PROT_CFG + i * 4, prot[i]);
}
-void mt76x0_mac_set_short_preamble(struct mt76x0_dev *dev, bool short_preamb)
+void mt76x0_mac_set_short_preamble(struct mt76x02_dev *dev, bool short_preamb)
{
if (short_preamb)
mt76_set(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_PREAMB_SHORT);
@@ -313,7 +85,7 @@ void mt76x0_mac_set_short_preamble(struct mt76x0_dev *dev, bool short_preamb)
mt76_clear(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_PREAMB_SHORT);
}
-void mt76x0_mac_config_tsf(struct mt76x0_dev *dev, bool enable, int interval)
+void mt76x0_mac_config_tsf(struct mt76x02_dev *dev, bool enable, int interval)
{
u32 val = mt76_rr(dev, MT_BEACON_TIME_CFG);
@@ -333,7 +105,7 @@ void mt76x0_mac_config_tsf(struct mt76x0_dev *dev, bool enable, int interval)
MT_BEACON_TIME_CFG_TBTT_EN;
}
-static void mt76x0_check_mac_err(struct mt76x0_dev *dev)
+static void mt76x0_check_mac_err(struct mt76x02_dev *dev)
{
u32 val = mt76_rr(dev, 0x10f4);
@@ -348,15 +120,15 @@ static void mt76x0_check_mac_err(struct mt76x0_dev *dev)
}
void mt76x0_mac_work(struct work_struct *work)
{
- struct mt76x0_dev *dev = container_of(work, struct mt76x0_dev,
+ struct mt76x02_dev *dev = container_of(work, struct mt76x02_dev,
mac_work.work);
struct {
u32 addr_base;
u32 span;
u64 *stat_base;
} spans[] = {
- { MT_RX_STA_CNT0, 3, dev->stats.rx_stat },
- { MT_TX_STA_CNT0, 3, dev->stats.tx_stat },
+ { MT_RX_STAT_0, 3, dev->stats.rx_stat },
+ { MT_TX_STA_0, 3, dev->stats.tx_stat },
{ MT_TX_AGG_STAT, 1, dev->stats.aggr_stat },
{ MT_MPDU_DENSITY_CNT, 1, dev->stats.zero_len_del },
{ MT_TX_AGG_CNT_BASE0, 8, &dev->stats.aggr_n[0] },
@@ -399,24 +171,7 @@ void mt76x0_mac_work(struct work_struct *work)
ieee80211_queue_delayed_work(dev->mt76.hw, &dev->mac_work, 10 * HZ);
}
-void
-mt76x0_mac_wcid_setup(struct mt76x0_dev *dev, u8 idx, u8 vif_idx, u8 *mac)
-{
- u8 zmac[ETH_ALEN] = {};
- u32 attr;
-
- attr = FIELD_PREP(MT_WCID_ATTR_BSS_IDX, vif_idx & 7) |
- FIELD_PREP(MT_WCID_ATTR_BSS_IDX_EXT, !!(vif_idx & 8));
-
- mt76_wr(dev, MT_WCID_ATTR(idx), attr);
-
- if (mac)
- memcpy(zmac, mac, sizeof(zmac));
-
- mt76x0_addr_wr(dev, MT_WCID_ADDR(idx), zmac);
-}
-
-void mt76x0_mac_set_ampdu_factor(struct mt76x0_dev *dev)
+void mt76x0_mac_set_ampdu_factor(struct mt76x02_dev *dev)
{
struct ieee80211_sta *sta;
struct mt76_wcid *wcid;
@@ -425,12 +180,12 @@ void mt76x0_mac_set_ampdu_factor(struct mt76x0_dev *dev)
int i;
rcu_read_lock();
- for (i = 0; i < ARRAY_SIZE(dev->wcid); i++) {
- wcid = rcu_dereference(dev->wcid[i]);
+ for (i = 0; i < ARRAY_SIZE(dev->mt76.wcid); i++) {
+ wcid = rcu_dereference(dev->mt76.wcid[i]);
if (!wcid)
continue;
- msta = container_of(wcid, struct mt76_sta, wcid);
+ msta = container_of(wcid, struct mt76x02_sta, wcid);
sta = container_of(msta, struct ieee80211_sta, drv_priv);
min_factor = min(min_factor, sta->ht_cap.ampdu_factor);
@@ -440,219 +195,3 @@ void mt76x0_mac_set_ampdu_factor(struct mt76x0_dev *dev)
mt76_wr(dev, MT_MAX_LEN_CFG, 0xa0fff |
FIELD_PREP(MT_MAX_LEN_CFG_AMPDU, min_factor));
}
-
-static void
-mt76_mac_process_rate(struct ieee80211_rx_status *status, u16 rate)
-{
- u8 idx = FIELD_GET(MT_RXWI_RATE_INDEX, rate);
-
- switch (FIELD_GET(MT_RXWI_RATE_PHY, rate)) {
- case MT_PHY_TYPE_OFDM:
- if (idx >= 8)
- idx = 0;
-
- if (status->band == NL80211_BAND_2GHZ)
- idx += 4;
-
- status->rate_idx = idx;
- return;
- case MT_PHY_TYPE_CCK:
- if (idx >= 8) {
- idx -= 8;
- status->enc_flags |= RX_ENC_FLAG_SHORTPRE;
- }
-
- if (idx >= 4)
- idx = 0;
-
- status->rate_idx = idx;
- return;
- case MT_PHY_TYPE_HT_GF:
- status->enc_flags |= RX_ENC_FLAG_HT_GF;
- /* fall through */
- case MT_PHY_TYPE_HT:
- status->encoding = RX_ENC_HT;
- status->rate_idx = idx;
- break;
- case MT_PHY_TYPE_VHT:
- status->encoding = RX_ENC_VHT;
- status->rate_idx = FIELD_GET(MT_RATE_INDEX_VHT_IDX, idx);
- status->nss = FIELD_GET(MT_RATE_INDEX_VHT_NSS, idx) + 1;
- break;
- default:
- WARN_ON(1);
- return;
- }
-
- if (rate & MT_RXWI_RATE_LDPC)
- status->enc_flags |= RX_ENC_FLAG_LDPC;
-
- if (rate & MT_RXWI_RATE_SGI)
- status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
-
- if (rate & MT_RXWI_RATE_STBC)
- status->enc_flags |= 1 << RX_ENC_FLAG_STBC_SHIFT;
-
- switch (FIELD_GET(MT_RXWI_RATE_BW, rate)) {
- case MT_PHY_BW_20:
- break;
- case MT_PHY_BW_40:
- status->bw = RATE_INFO_BW_40;
- break;
- case MT_PHY_BW_80:
- status->bw = RATE_INFO_BW_80;
- break;
- default:
- WARN_ON(1);
- break;
- }
-}
-
-static void
-mt76x0_rx_monitor_beacon(struct mt76x0_dev *dev, struct mt76x0_rxwi *rxwi,
- u16 rate, int rssi)
-{
- dev->bcn_phy_mode = FIELD_GET(MT_RXWI_RATE_PHY, rate);
- dev->avg_rssi = ((dev->avg_rssi * 15) / 16 + (rssi << 8)) / 256;
-}
-
-static int
-mt76x0_rx_is_our_beacon(struct mt76x0_dev *dev, u8 *data)
-{
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)data;
-
- return ieee80211_is_beacon(hdr->frame_control) &&
- ether_addr_equal(hdr->addr2, dev->ap_bssid);
-}
-
-u32 mt76x0_mac_process_rx(struct mt76x0_dev *dev, struct sk_buff *skb,
- u8 *data, void *rxi)
-{
- struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
- struct mt76x0_rxwi *rxwi = rxi;
- u32 len, ctl = le32_to_cpu(rxwi->ctl);
- u16 rate = le16_to_cpu(rxwi->rate);
- int rssi;
-
- len = FIELD_GET(MT_RXWI_CTL_MPDU_LEN, ctl);
- if (WARN_ON(len < 10))
- return 0;
-
- if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_DECRYPT)) {
- status->flag |= RX_FLAG_DECRYPTED;
- status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED;
- }
-
- status->chains = BIT(0);
- rssi = mt76x0_phy_get_rssi(dev, rxwi);
- status->chain_signal[0] = status->signal = rssi;
- status->freq = dev->mt76.chandef.chan->center_freq;
- status->band = dev->mt76.chandef.chan->band;
-
- mt76_mac_process_rate(status, rate);
-
- spin_lock_bh(&dev->con_mon_lock);
- if (mt76x0_rx_is_our_beacon(dev, data)) {
- mt76x0_rx_monitor_beacon(dev, rxwi, rate, rssi);
- } else if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_U2M)) {
- if (dev->avg_rssi == 0)
- dev->avg_rssi = rssi;
- else
- dev->avg_rssi = (dev->avg_rssi * 15) / 16 + rssi / 16;
-
- }
- spin_unlock_bh(&dev->con_mon_lock);
-
- return len;
-}
-
-static enum mt76_cipher_type
-mt76_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data)
-{
- memset(key_data, 0, 32);
- if (!key)
- return MT_CIPHER_NONE;
-
- if (key->keylen > 32)
- return MT_CIPHER_NONE;
-
- memcpy(key_data, key->key, key->keylen);
-
- switch (key->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_CCMP:
- return MT_CIPHER_AES_CCMP;
- default:
- return MT_CIPHER_NONE;
- }
-}
-
-int mt76x0_mac_wcid_set_key(struct mt76x0_dev *dev, u8 idx,
- struct ieee80211_key_conf *key)
-{
- enum mt76_cipher_type cipher;
- u8 key_data[32];
- u8 iv_data[8];
- u32 val;
-
- cipher = mt76_mac_get_key_info(key, key_data);
- if (cipher == MT_CIPHER_NONE && key)
- return -EINVAL;
-
- trace_mt76x0_set_key(&dev->mt76, idx);
-
- mt76_wr_copy(dev, MT_WCID_KEY(idx), key_data, sizeof(key_data));
-
- memset(iv_data, 0, sizeof(iv_data));
- if (key) {
- iv_data[3] = key->keyidx << 6;
- if (cipher >= MT_CIPHER_TKIP) {
- /* Note: start with 1 to comply with spec,
- * (see comment on common/cmm_wpa.c:4291).
- */
- iv_data[0] |= 1;
- iv_data[3] |= 0x20;
- }
- }
- mt76_wr_copy(dev, MT_WCID_IV(idx), iv_data, sizeof(iv_data));
-
- val = mt76_rr(dev, MT_WCID_ATTR(idx));
- val &= ~MT_WCID_ATTR_PKEY_MODE & ~MT_WCID_ATTR_PKEY_MODE_EXT;
- val |= FIELD_PREP(MT_WCID_ATTR_PKEY_MODE, cipher & 7) |
- FIELD_PREP(MT_WCID_ATTR_PKEY_MODE_EXT, cipher >> 3);
- val &= ~MT_WCID_ATTR_PAIRWISE;
- val |= MT_WCID_ATTR_PAIRWISE *
- !!(key && key->flags & IEEE80211_KEY_FLAG_PAIRWISE);
- mt76_wr(dev, MT_WCID_ATTR(idx), val);
-
- return 0;
-}
-
-int mt76x0_mac_shared_key_setup(struct mt76x0_dev *dev, u8 vif_idx, u8 key_idx,
- struct ieee80211_key_conf *key)
-{
- enum mt76_cipher_type cipher;
- u8 key_data[32];
- u32 val;
-
- cipher = mt76_mac_get_key_info(key, key_data);
- if (cipher == MT_CIPHER_NONE && key)
- return -EINVAL;
-
- trace_mt76x0_set_shared_key(&dev->mt76, vif_idx, key_idx);
-
- mt76_wr_copy(dev, MT_SKEY(vif_idx, key_idx),
- key_data, sizeof(key_data));
-
- val = mt76_rr(dev, MT_SKEY_MODE(vif_idx));
- val &= ~(MT_SKEY_MODE_MASK << MT_SKEY_MODE_SHIFT(vif_idx, key_idx));
- val |= cipher << MT_SKEY_MODE_SHIFT(vif_idx, key_idx);
- mt76_wr(dev, MT_SKEY_MODE(vif_idx), val);
-
- return 0;
-}
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h
deleted file mode 100644
index bea067b71c13..000000000000
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
- * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#ifndef __MT76_MAC_H
-#define __MT76_MAC_H
-
-/* Note: values in original "RSSI" and "SNR" fields are not actually what they
- * are called for MT76X0U, names used by this driver are educated guesses
- * (see vendor mac/ral_omac.c).
- */
-struct mt76x0_rxwi {
- __le32 rxinfo;
-
- __le32 ctl;
-
- __le16 tid_sn;
- __le16 rate;
-
- s8 rssi[4];
-
- __le32 bbp_rxinfo[4];
-} __packed __aligned(4);
-
-#define MT_RXINFO_BA BIT(0)
-#define MT_RXINFO_DATA BIT(1)
-#define MT_RXINFO_NULL BIT(2)
-#define MT_RXINFO_FRAG BIT(3)
-#define MT_RXINFO_U2M BIT(4)
-#define MT_RXINFO_MULTICAST BIT(5)
-#define MT_RXINFO_BROADCAST BIT(6)
-#define MT_RXINFO_MYBSS BIT(7)
-#define MT_RXINFO_CRCERR BIT(8)
-#define MT_RXINFO_ICVERR BIT(9)
-#define MT_RXINFO_MICERR BIT(10)
-#define MT_RXINFO_AMSDU BIT(11)
-#define MT_RXINFO_HTC BIT(12)
-#define MT_RXINFO_RSSI BIT(13)
-#define MT_RXINFO_L2PAD BIT(14)
-#define MT_RXINFO_AMPDU BIT(15)
-#define MT_RXINFO_DECRYPT BIT(16)
-#define MT_RXINFO_BSSIDX3 BIT(17)
-#define MT_RXINFO_WAPI_KEY BIT(18)
-#define MT_RXINFO_PN_LEN GENMASK(21, 19)
-#define MT_RXINFO_SW_PKT_80211 BIT(22)
-#define MT_RXINFO_TCP_SUM_BYPASS BIT(28)
-#define MT_RXINFO_IP_SUM_BYPASS BIT(29)
-#define MT_RXINFO_TCP_SUM_ERR BIT(30)
-#define MT_RXINFO_IP_SUM_ERR BIT(31)
-
-#define MT_RXWI_CTL_WCID GENMASK(7, 0)
-#define MT_RXWI_CTL_KEY_IDX GENMASK(9, 8)
-#define MT_RXWI_CTL_BSS_IDX GENMASK(12, 10)
-#define MT_RXWI_CTL_UDF GENMASK(15, 13)
-#define MT_RXWI_CTL_MPDU_LEN GENMASK(27, 16)
-#define MT_RXWI_CTL_TID GENMASK(31, 28)
-
-#define MT_RXWI_FRAG GENMASK(3, 0)
-#define MT_RXWI_SN GENMASK(15, 4)
-
-#define MT_RXWI_RATE_INDEX GENMASK(5, 0)
-#define MT_RXWI_RATE_LDPC BIT(6)
-#define MT_RXWI_RATE_BW GENMASK(8, 7)
-#define MT_RXWI_RATE_SGI BIT(9)
-#define MT_RXWI_RATE_STBC BIT(10)
-#define MT_RXWI_RATE_LDPC_ETXBF BIT(11)
-#define MT_RXWI_RATE_SND BIT(12)
-#define MT_RXWI_RATE_PHY GENMASK(15, 13)
-
-#define MT_RATE_INDEX_VHT_IDX GENMASK(3, 0)
-#define MT_RATE_INDEX_VHT_NSS GENMASK(5, 4)
-
-#define MT_RXWI_GAIN_RSSI_VAL GENMASK(5, 0)
-#define MT_RXWI_GAIN_RSSI_LNA_ID GENMASK(7, 6)
-#define MT_RXWI_ANT_AUX_LNA BIT(7)
-
-#define MT_RXWI_EANT_ENC_ANT_ID GENMASK(7, 0)
-
-enum mt76_phy_bandwidth {
- MT_PHY_BW_20,
- MT_PHY_BW_40,
- MT_PHY_BW_80,
-};
-
-struct mt76_txwi {
- __le16 flags;
- __le16 rate_ctl;
- u8 ack_ctl;
- u8 wcid;
- __le16 len_ctl;
- __le32 iv;
- __le32 eiv;
- u8 aid;
- u8 txstream;
- u8 ctl2;
- u8 pktid;
-} __packed __aligned(4);
-
-#define MT_TXWI_FLAGS_FRAG BIT(0)
-#define MT_TXWI_FLAGS_MMPS BIT(1)
-#define MT_TXWI_FLAGS_CFACK BIT(2)
-#define MT_TXWI_FLAGS_TS BIT(3)
-#define MT_TXWI_FLAGS_AMPDU BIT(4)
-#define MT_TXWI_FLAGS_MPDU_DENSITY GENMASK(7, 5)
-#define MT_TXWI_FLAGS_TXOP GENMASK(9, 8)
-#define MT_TXWI_FLAGS_CWMIN GENMASK(12, 10)
-#define MT_TXWI_FLAGS_NO_RATE_FALLBACK BIT(13)
-#define MT_TXWI_FLAGS_TX_RPT BIT(14)
-#define MT_TXWI_FLAGS_TX_RATE_LUT BIT(15)
-
-#define MT_TXWI_RATE_MCS GENMASK(6, 0)
-#define MT_TXWI_RATE_BW BIT(7)
-#define MT_TXWI_RATE_SGI BIT(8)
-#define MT_TXWI_RATE_STBC GENMASK(10, 9)
-#define MT_TXWI_RATE_PHY_MODE GENMASK(15, 14)
-
-#define MT_TXWI_ACK_CTL_REQ BIT(0)
-#define MT_TXWI_ACK_CTL_NSEQ BIT(1)
-#define MT_TXWI_ACK_CTL_BA_WINDOW GENMASK(7, 2)
-
-#define MT_TXWI_LEN_BYTE_CNT GENMASK(11, 0)
-
-#define MT_TXWI_CTL_TX_POWER_ADJ GENMASK(3, 0)
-#define MT_TXWI_CTL_CHAN_CHECK_PKT BIT(4)
-#define MT_TXWI_CTL_PIFS_REV BIT(6)
-
-#define MT_TXWI_PKTID_PROBE BIT(7)
-
-u32 mt76x0_mac_process_rx(struct mt76x0_dev *dev, struct sk_buff *skb,
- u8 *data, void *rxi);
-int mt76x0_mac_wcid_set_key(struct mt76x0_dev *dev, u8 idx,
- struct ieee80211_key_conf *key);
-void mt76x0_mac_wcid_set_rate(struct mt76x0_dev *dev, struct mt76_wcid *wcid,
- const struct ieee80211_tx_rate *rate);
-
-int mt76x0_mac_shared_key_setup(struct mt76x0_dev *dev, u8 vif_idx, u8 key_idx,
- struct ieee80211_key_conf *key);
-u16 mt76x0_mac_tx_rate_val(struct mt76x0_dev *dev,
- const struct ieee80211_tx_rate *rate, u8 *nss_val);
-struct mt76_tx_status
-mt76x0_mac_fetch_tx_status(struct mt76x0_dev *dev);
-void mt76x0_send_tx_status(struct mt76x0_dev *dev, struct mt76_tx_status *stat, u8 *update);
-
-#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c
index cf6ffb1ba4a2..9273d2d2764a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c
@@ -13,145 +13,72 @@
* GNU General Public License for more details.
*/
-#include "mt76x0.h"
-#include "mac.h"
#include <linux/etherdevice.h>
+#include "mt76x0.h"
-static int mt76x0_start(struct ieee80211_hw *hw)
+static int
+mt76x0_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef)
{
- struct mt76x0_dev *dev = hw->priv;
int ret;
- mutex_lock(&dev->mutex);
+ cancel_delayed_work_sync(&dev->cal_work);
- ret = mt76x0_mac_start(dev);
- if (ret)
- goto out;
+ mt76_set_channel(&dev->mt76);
+ ret = mt76x0_phy_set_channel(dev, chandef);
+ mt76_txq_schedule_all(&dev->mt76);
- ieee80211_queue_delayed_work(dev->mt76.hw, &dev->mac_work,
- MT_CALIBRATE_INTERVAL);
- ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work,
- MT_CALIBRATE_INTERVAL);
-out:
- mutex_unlock(&dev->mutex);
return ret;
}
-static void mt76x0_stop(struct ieee80211_hw *hw)
-{
- struct mt76x0_dev *dev = hw->priv;
-
- mutex_lock(&dev->mutex);
-
- cancel_delayed_work_sync(&dev->cal_work);
- cancel_delayed_work_sync(&dev->mac_work);
- mt76x0_mac_stop(dev);
-
- mutex_unlock(&dev->mutex);
-}
-
-
-static int mt76x0_add_interface(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif)
+int mt76x0_config(struct ieee80211_hw *hw, u32 changed)
{
- struct mt76x0_dev *dev = hw->priv;
- struct mt76_vif *mvif = (struct mt76_vif *) vif->drv_priv;
- unsigned int idx;
-
- idx = ffs(~dev->vif_mask);
- if (!idx || idx > 8)
- return -ENOSPC;
-
- idx--;
- dev->vif_mask |= BIT(idx);
-
- mvif->idx = idx;
- mvif->group_wcid.idx = GROUP_WCID(idx);
- mvif->group_wcid.hw_key_idx = -1;
-
- return 0;
-}
+ struct mt76x02_dev *dev = hw->priv;
+ int ret = 0;
-static void mt76x0_remove_interface(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif)
-{
- struct mt76x0_dev *dev = hw->priv;
- struct mt76_vif *mvif = (struct mt76_vif *) vif->drv_priv;
- unsigned int wcid = mvif->group_wcid.idx;
+ mutex_lock(&dev->mt76.mutex);
- dev->wcid_mask[wcid / BITS_PER_LONG] &= ~BIT(wcid % BITS_PER_LONG);
-}
+ if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+ ieee80211_stop_queues(hw);
+ ret = mt76x0_set_channel(dev, &hw->conf.chandef);
+ ieee80211_wake_queues(hw);
+ }
-static int mt76x0_config(struct ieee80211_hw *hw, u32 changed)
-{
- struct mt76x0_dev *dev = hw->priv;
- int ret = 0;
+ if (changed & IEEE80211_CONF_CHANGE_POWER) {
+ dev->mt76.txpower_conf = hw->conf.power_level * 2;
- mutex_lock(&dev->mutex);
+ if (test_bit(MT76_STATE_RUNNING, &dev->mt76.state))
+ mt76x0_phy_set_txpower(dev);
+ }
if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
if (!(hw->conf.flags & IEEE80211_CONF_MONITOR))
- dev->rxfilter |= MT_RX_FILTR_CFG_PROMISC;
+ dev->mt76.rxfilter |= MT_RX_FILTR_CFG_PROMISC;
else
- dev->rxfilter &= ~MT_RX_FILTR_CFG_PROMISC;
-
- mt76_wr(dev, MT_RX_FILTR_CFG, dev->rxfilter);
- }
+ dev->mt76.rxfilter &= ~MT_RX_FILTR_CFG_PROMISC;
- if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
- ieee80211_stop_queues(hw);
- ret = mt76x0_phy_set_channel(dev, &hw->conf.chandef);
- ieee80211_wake_queues(hw);
+ mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter);
}
- mutex_unlock(&dev->mutex);
+ mutex_unlock(&dev->mt76.mutex);
return ret;
}
+EXPORT_SYMBOL_GPL(mt76x0_config);
static void
-mt76_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
- unsigned int *total_flags, u64 multicast)
+mt76x0_addr_wr(struct mt76x02_dev *dev, const u32 offset, const u8 *addr)
{
- struct mt76x0_dev *dev = hw->priv;
- u32 flags = 0;
-
-#define MT76_FILTER(_flag, _hw) do { \
- flags |= *total_flags & FIF_##_flag; \
- dev->rxfilter &= ~(_hw); \
- dev->rxfilter |= !(flags & FIF_##_flag) * (_hw); \
- } while (0)
-
- mutex_lock(&dev->mutex);
-
- dev->rxfilter &= ~MT_RX_FILTR_CFG_OTHER_BSS;
-
- MT76_FILTER(FCSFAIL, MT_RX_FILTR_CFG_CRC_ERR);
- MT76_FILTER(PLCPFAIL, MT_RX_FILTR_CFG_PHY_ERR);
- MT76_FILTER(CONTROL, MT_RX_FILTR_CFG_ACK |
- MT_RX_FILTR_CFG_CTS |
- MT_RX_FILTR_CFG_CFEND |
- MT_RX_FILTR_CFG_CFACK |
- MT_RX_FILTR_CFG_BA |
- MT_RX_FILTR_CFG_CTRL_RSV);
- MT76_FILTER(PSPOLL, MT_RX_FILTR_CFG_PSPOLL);
-
- *total_flags = flags;
- mt76_wr(dev, MT_RX_FILTR_CFG, dev->rxfilter);
-
- mutex_unlock(&dev->mutex);
+ mt76_wr(dev, offset, get_unaligned_le32(addr));
+ mt76_wr(dev, offset + 4, addr[4] | addr[5] << 8);
}
-static void
-mt76x0_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *info, u32 changed)
+void mt76x0_bss_info_changed(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *info, u32 changed)
{
- struct mt76x0_dev *dev = hw->priv;
-
- mutex_lock(&dev->mutex);
+ struct mt76x02_dev *dev = hw->priv;
- if (changed & BSS_CHANGED_ASSOC)
- mt76x0_phy_con_cal_onoff(dev, info);
+ mutex_lock(&dev->mt76.mutex);
if (changed & BSS_CHANGED_BSSID) {
mt76x0_addr_wr(dev, MT_MAC_BSSID_DW0, info->bssid);
@@ -166,8 +93,8 @@ mt76x0_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
if (changed & BSS_CHANGED_BASIC_RATES) {
mt76_wr(dev, MT_LEGACY_BASIC_RATE, info->basic_rates);
- mt76_wr(dev, MT_HT_FBK_CFG0, 0x65432100);
- mt76_wr(dev, MT_HT_FBK_CFG1, 0xedcba980);
+ mt76_wr(dev, MT_VHT_HT_FBK_CFG0, 0x65432100);
+ mt76_wr(dev, MT_VHT_HT_FBK_CFG1, 0xedcba980);
mt76_wr(dev, MT_LG_FBK_CFG0, 0xedcba988);
mt76_wr(dev, MT_LG_FBK_CFG1, 0x00002100);
}
@@ -192,212 +119,34 @@ mt76x0_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
if (changed & BSS_CHANGED_ASSOC)
mt76x0_phy_recalibrate_after_assoc(dev);
- mutex_unlock(&dev->mutex);
-}
-
-static int
-mt76x0_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
-{
- struct mt76x0_dev *dev = hw->priv;
- struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv;
- struct mt76_vif *mvif = (struct mt76_vif *) vif->drv_priv;
- int ret = 0;
- int idx = 0;
-
- mutex_lock(&dev->mutex);
-
- idx = mt76_wcid_alloc(dev->wcid_mask, ARRAY_SIZE(dev->wcid));
- if (idx < 0) {
- ret = -ENOSPC;
- goto out;
- }
-
- msta->wcid.idx = idx;
- msta->wcid.hw_key_idx = -1;
- mt76x0_mac_wcid_setup(dev, idx, mvif->idx, sta->addr);
- mt76_clear(dev, MT_WCID_DROP(idx), MT_WCID_DROP_MASK(idx));
- rcu_assign_pointer(dev->wcid[idx], &msta->wcid);
- mt76x0_mac_set_ampdu_factor(dev);
-
-out:
- mutex_unlock(&dev->mutex);
-
- return ret;
-}
-
-static int
-mt76x0_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
-{
- struct mt76x0_dev *dev = hw->priv;
- struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv;
- int idx = msta->wcid.idx;
-
- mutex_lock(&dev->mutex);
- rcu_assign_pointer(dev->wcid[idx], NULL);
- mt76_set(dev, MT_WCID_DROP(idx), MT_WCID_DROP_MASK(idx));
- dev->wcid_mask[idx / BITS_PER_LONG] &= ~BIT(idx % BITS_PER_LONG);
- mt76x0_mac_wcid_setup(dev, idx, 0, NULL);
- mt76x0_mac_set_ampdu_factor(dev);
- mutex_unlock(&dev->mutex);
-
- return 0;
+ mutex_unlock(&dev->mt76.mutex);
}
+EXPORT_SYMBOL_GPL(mt76x0_bss_info_changed);
-static void
-mt76x0_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- enum sta_notify_cmd cmd, struct ieee80211_sta *sta)
-{
-}
-
-static void
-mt76x0_sw_scan(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- const u8 *mac_addr)
+void mt76x0_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ const u8 *mac_addr)
{
- struct mt76x0_dev *dev = hw->priv;
+ struct mt76x02_dev *dev = hw->priv;
- cancel_delayed_work_sync(&dev->cal_work);
- mt76x0_agc_save(dev);
set_bit(MT76_SCANNING, &dev->mt76.state);
}
+EXPORT_SYMBOL_GPL(mt76x0_sw_scan);
-static void
-mt76x0_sw_scan_complete(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif)
+void mt76x0_sw_scan_complete(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
{
- struct mt76x0_dev *dev = hw->priv;
+ struct mt76x02_dev *dev = hw->priv;
- mt76x0_agc_restore(dev);
clear_bit(MT76_SCANNING, &dev->mt76.state);
-
- ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work,
- MT_CALIBRATE_INTERVAL);
-}
-
-static int
-mt76x0_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
- struct ieee80211_vif *vif, struct ieee80211_sta *sta,
- struct ieee80211_key_conf *key)
-{
- struct mt76x0_dev *dev = hw->priv;
- struct mt76_vif *mvif = (struct mt76_vif *) vif->drv_priv;
- struct mt76_sta *msta = sta ? (struct mt76_sta *) sta->drv_priv : NULL;
- struct mt76_wcid *wcid = msta ? &msta->wcid : &mvif->group_wcid;
- int idx = key->keyidx;
- int ret;
-
- if (cmd == SET_KEY) {
- key->hw_key_idx = wcid->idx;
- wcid->hw_key_idx = idx;
- } else {
- if (idx == wcid->hw_key_idx)
- wcid->hw_key_idx = -1;
-
- key = NULL;
- }
-
- if (!msta) {
- if (key || wcid->hw_key_idx == idx) {
- ret = mt76x0_mac_wcid_set_key(dev, wcid->idx, key);
- if (ret)
- return ret;
- }
-
- return mt76x0_mac_shared_key_setup(dev, mvif->idx, idx, key);
- }
-
- return mt76x0_mac_wcid_set_key(dev, msta->wcid.idx, key);
}
+EXPORT_SYMBOL_GPL(mt76x0_sw_scan_complete);
-static int mt76x0_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
+int mt76x0_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
{
- struct mt76x0_dev *dev = hw->priv;
+ struct mt76x02_dev *dev = hw->priv;
mt76_rmw_field(dev, MT_TX_RTS_CFG, MT_TX_RTS_CFG_THRESH, value);
return 0;
}
-
-static int
-mt76_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_ampdu_params *params)
-{
- struct mt76x0_dev *dev = hw->priv;
- struct ieee80211_sta *sta = params->sta;
- enum ieee80211_ampdu_mlme_action action = params->action;
- u16 tid = params->tid;
- u16 *ssn = &params->ssn;
- struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv;
-
- WARN_ON(msta->wcid.idx > N_WCIDS);
-
- switch (action) {
- case IEEE80211_AMPDU_RX_START:
- mt76_set(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid));
- break;
- case IEEE80211_AMPDU_RX_STOP:
- mt76_clear(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid));
- break;
- case IEEE80211_AMPDU_TX_OPERATIONAL:
- ieee80211_send_bar(vif, sta->addr, tid, msta->agg_ssn[tid]);
- break;
- case IEEE80211_AMPDU_TX_STOP_FLUSH:
- case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
- break;
- case IEEE80211_AMPDU_TX_START:
- msta->agg_ssn[tid] = *ssn << 4;
- ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
- break;
- case IEEE80211_AMPDU_TX_STOP_CONT:
- ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
- break;
- }
-
- return 0;
-}
-
-static void
-mt76_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
-{
- struct mt76x0_dev *dev = hw->priv;
- struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv;
- struct ieee80211_sta_rates *rates;
- struct ieee80211_tx_rate rate = {};
-
- rcu_read_lock();
- rates = rcu_dereference(sta->rates);
-
- if (!rates)
- goto out;
-
- rate.idx = rates->rate[0].idx;
- rate.flags = rates->rate[0].flags;
- mt76x0_mac_wcid_set_rate(dev, &msta->wcid, &rate);
-
-out:
- rcu_read_unlock();
-}
-
-const struct ieee80211_ops mt76x0_ops = {
- .tx = mt76x0_tx,
- .start = mt76x0_start,
- .stop = mt76x0_stop,
- .add_interface = mt76x0_add_interface,
- .remove_interface = mt76x0_remove_interface,
- .config = mt76x0_config,
- .configure_filter = mt76_configure_filter,
- .bss_info_changed = mt76x0_bss_info_changed,
- .sta_add = mt76x0_sta_add,
- .sta_remove = mt76x0_sta_remove,
- .sta_notify = mt76x0_sta_notify,
- .set_key = mt76x0_set_key,
- .conf_tx = mt76x0_conf_tx,
- .sw_scan_start = mt76x0_sw_scan,
- .sw_scan_complete = mt76x0_sw_scan_complete,
- .ampdu_action = mt76_ampdu_action,
- .sta_rate_tbl_update = mt76_sta_rate_tbl_update,
- .set_rts_threshold = mt76x0_set_rts_threshold,
-};
+EXPORT_SYMBOL_GPL(mt76x0_set_rts_threshold);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c
deleted file mode 100644
index 8affacbab90a..000000000000
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.c
+++ /dev/null
@@ -1,656 +0,0 @@
-/*
- * (c) Copyright 2002-2010, Ralink Technology, Inc.
- * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
- * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
- * Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/firmware.h>
-#include <linux/delay.h>
-#include <linux/usb.h>
-#include <linux/skbuff.h>
-
-#include "mt76x0.h"
-#include "dma.h"
-#include "mcu.h"
-#include "usb.h"
-#include "trace.h"
-
-#define MCU_FW_URB_MAX_PAYLOAD 0x38f8
-#define MCU_FW_URB_SIZE (MCU_FW_URB_MAX_PAYLOAD + 12)
-#define MCU_RESP_URB_SIZE 1024
-
-static inline int firmware_running(struct mt76x0_dev *dev)
-{
- return mt76_rr(dev, MT_MCU_COM_REG0) == 1;
-}
-
-static inline void skb_put_le32(struct sk_buff *skb, u32 val)
-{
- put_unaligned_le32(val, skb_put(skb, 4));
-}
-
-static inline void mt76x0_dma_skb_wrap_cmd(struct sk_buff *skb,
- u8 seq, enum mcu_cmd cmd)
-{
- WARN_ON(mt76x0_dma_skb_wrap(skb, CPU_TX_PORT, DMA_COMMAND,
- FIELD_PREP(MT_TXD_CMD_SEQ, seq) |
- FIELD_PREP(MT_TXD_CMD_TYPE, cmd)));
-}
-
-static inline void trace_mt76x0_mcu_msg_send_cs(struct mt76_dev *dev,
- struct sk_buff *skb, bool need_resp)
-{
- u32 i, csum = 0;
-
- for (i = 0; i < skb->len / 4; i++)
- csum ^= get_unaligned_le32(skb->data + i * 4);
-
- trace_mt76x0_mcu_msg_send(dev, skb, csum, need_resp);
-}
-
-static struct sk_buff *
-mt76x0_mcu_msg_alloc(struct mt76x0_dev *dev, const void *data, int len)
-{
- struct sk_buff *skb;
-
- WARN_ON(len % 4); /* if length is not divisible by 4 we need to pad */
-
- skb = alloc_skb(len + MT_DMA_HDR_LEN + 4, GFP_KERNEL);
- if (skb) {
- skb_reserve(skb, MT_DMA_HDR_LEN);
- memcpy(skb_put(skb, len), data, len);
- }
- return skb;
-}
-
-static void mt76x0_read_resp_regs(struct mt76x0_dev *dev, int len)
-{
- int i;
- int n = dev->mcu.reg_pairs_len;
- u8 *buf = dev->mcu.resp.buf;
-
- buf += 4;
- len -= 8;
-
- if (dev->mcu.burst_read) {
- u32 reg = dev->mcu.reg_pairs[0].reg - dev->mcu.reg_base;
-
- WARN_ON_ONCE(len/4 != n);
- for (i = 0; i < n; i++) {
- u32 val = get_unaligned_le32(buf + 4*i);
-
- dev->mcu.reg_pairs[i].reg = reg++;
- dev->mcu.reg_pairs[i].value = val;
- }
- } else {
- WARN_ON_ONCE(len/8 != n);
- for (i = 0; i < n; i++) {
- u32 reg = get_unaligned_le32(buf + 8*i) - dev->mcu.reg_base;
- u32 val = get_unaligned_le32(buf + 8*i + 4);
-
- WARN_ON_ONCE(dev->mcu.reg_pairs[i].reg != reg);
- dev->mcu.reg_pairs[i].value = val;
- }
- }
-}
-
-static int mt76x0_mcu_wait_resp(struct mt76x0_dev *dev, u8 seq)
-{
- struct urb *urb = dev->mcu.resp.urb;
- u32 rxfce;
- int urb_status, ret, try = 5;
-
- while (try--) {
- if (!wait_for_completion_timeout(&dev->mcu.resp_cmpl,
- msecs_to_jiffies(300))) {
- dev_warn(dev->mt76.dev, "Warning: %s retrying\n", __func__);
- continue;
- }
-
- /* Make copies of important data before reusing the urb */
- rxfce = get_unaligned_le32(dev->mcu.resp.buf);
- urb_status = urb->status * mt76x0_urb_has_error(urb);
-
- if (urb_status == 0 && dev->mcu.reg_pairs)
- mt76x0_read_resp_regs(dev, urb->actual_length);
-
- ret = mt76x0_usb_submit_buf(dev, USB_DIR_IN, MT_EP_IN_CMD_RESP,
- &dev->mcu.resp, GFP_KERNEL,
- mt76x0_complete_urb,
- &dev->mcu.resp_cmpl);
- if (ret)
- return ret;
-
- if (urb_status)
- dev_err(dev->mt76.dev, "Error: MCU resp urb failed:%d\n",
- urb_status);
-
- if (FIELD_GET(MT_RXD_CMD_INFO_CMD_SEQ, rxfce) == seq &&
- FIELD_GET(MT_RXD_CMD_INFO_EVT_TYPE, rxfce) == CMD_DONE)
- return 0;
-
- dev_err(dev->mt76.dev, "Error: MCU resp evt:%lx seq:%hhx-%lx!\n",
- FIELD_GET(MT_RXD_CMD_INFO_EVT_TYPE, rxfce),
- seq, FIELD_GET(MT_RXD_CMD_INFO_CMD_SEQ, rxfce));
- }
-
- dev_err(dev->mt76.dev, "Error: %s timed out\n", __func__);
- return -ETIMEDOUT;
-}
-
-static int
-__mt76x0_mcu_msg_send(struct mt76x0_dev *dev, struct sk_buff *skb,
- enum mcu_cmd cmd, bool wait_resp)
-{
- struct usb_device *usb_dev = mt76x0_to_usb_dev(dev);
- unsigned cmd_pipe = usb_sndbulkpipe(usb_dev,
- dev->out_ep[MT_EP_OUT_INBAND_CMD]);
- int sent, ret;
- u8 seq = 0;
-
- if (wait_resp)
- while (!seq)
- seq = ++dev->mcu.msg_seq & 0xf;
-
- mt76x0_dma_skb_wrap_cmd(skb, seq, cmd);
-
- if (dev->mcu.resp_cmpl.done)
- dev_err(dev->mt76.dev, "Error: MCU response pre-completed!\n");
-
- trace_mt76x0_mcu_msg_send_cs(&dev->mt76, skb, wait_resp);
- trace_mt76x0_submit_urb_sync(&dev->mt76, cmd_pipe, skb->len);
-
- ret = usb_bulk_msg(usb_dev, cmd_pipe, skb->data, skb->len, &sent, 500);
- if (ret) {
- dev_err(dev->mt76.dev, "Error: send MCU cmd failed:%d\n", ret);
- goto out;
- }
- if (sent != skb->len)
- dev_err(dev->mt76.dev, "Error: %s sent != skb->len\n", __func__);
-
- if (wait_resp)
- ret = mt76x0_mcu_wait_resp(dev, seq);
-
-out:
- return ret;
-}
-
-static int
-mt76x0_mcu_msg_send(struct mt76x0_dev *dev, struct sk_buff *skb,
- enum mcu_cmd cmd, bool wait_resp)
-{
- int ret;
-
- if (test_bit(MT76_REMOVED, &dev->mt76.state))
- return 0;
-
- mutex_lock(&dev->mcu.mutex);
- ret = __mt76x0_mcu_msg_send(dev, skb, cmd, wait_resp);
- mutex_unlock(&dev->mcu.mutex);
-
- consume_skb(skb);
-
- return ret;
-}
-
-int mt76x0_mcu_function_select(struct mt76x0_dev *dev,
- enum mcu_function func, u32 val)
-{
- struct sk_buff *skb;
- struct {
- __le32 id;
- __le32 value;
- } __packed __aligned(4) msg = {
- .id = cpu_to_le32(func),
- .value = cpu_to_le32(val),
- };
-
- skb = mt76x0_mcu_msg_alloc(dev, &msg, sizeof(msg));
- if (!skb)
- return -ENOMEM;
- return mt76x0_mcu_msg_send(dev, skb, CMD_FUN_SET_OP, func == 5);
-}
-
-int
-mt76x0_mcu_calibrate(struct mt76x0_dev *dev, enum mcu_calibrate cal, u32 val)
-{
- struct sk_buff *skb;
- struct {
- __le32 id;
- __le32 value;
- } __packed __aligned(4) msg = {
- .id = cpu_to_le32(cal),
- .value = cpu_to_le32(val),
- };
-
- skb = mt76x0_mcu_msg_alloc(dev, &msg, sizeof(msg));
- if (!skb)
- return -ENOMEM;
- return mt76x0_mcu_msg_send(dev, skb, CMD_CALIBRATION_OP, true);
-}
-
-int mt76x0_write_reg_pairs(struct mt76x0_dev *dev, u32 base,
- const struct mt76_reg_pair *data, int n)
-{
- const int max_vals_per_cmd = INBAND_PACKET_MAX_LEN / 8;
- struct sk_buff *skb;
- int cnt, i, ret;
-
- if (!n)
- return 0;
-
- cnt = min(max_vals_per_cmd, n);
-
- skb = alloc_skb(cnt * 8 + MT_DMA_HDR_LEN + 4, GFP_KERNEL);
- if (!skb)
- return -ENOMEM;
- skb_reserve(skb, MT_DMA_HDR_LEN);
-
- for (i = 0; i < cnt; i++) {
- skb_put_le32(skb, base + data[i].reg);
- skb_put_le32(skb, data[i].value);
- }
-
- ret = mt76x0_mcu_msg_send(dev, skb, CMD_RANDOM_WRITE, cnt == n);
- if (ret)
- return ret;
-
- return mt76x0_write_reg_pairs(dev, base, data + cnt, n - cnt);
-}
-
-int mt76x0_read_reg_pairs(struct mt76x0_dev *dev, u32 base,
- struct mt76_reg_pair *data, int n)
-{
- const int max_vals_per_cmd = INBAND_PACKET_MAX_LEN / 8;
- struct sk_buff *skb;
- int cnt, i, ret;
-
- if (!n)
- return 0;
-
- cnt = min(max_vals_per_cmd, n);
- if (cnt != n)
- return -EINVAL;
-
- skb = alloc_skb(cnt * 8 + MT_DMA_HDR_LEN + 4, GFP_KERNEL);
- if (!skb)
- return -ENOMEM;
- skb_reserve(skb, MT_DMA_HDR_LEN);
-
- for (i = 0; i < cnt; i++) {
- skb_put_le32(skb, base + data[i].reg);
- skb_put_le32(skb, data[i].value);
- }
-
- mutex_lock(&dev->mcu.mutex);
-
- dev->mcu.reg_pairs = data;
- dev->mcu.reg_pairs_len = n;
- dev->mcu.reg_base = base;
- dev->mcu.burst_read = false;
-
- ret = __mt76x0_mcu_msg_send(dev, skb, CMD_RANDOM_READ, true);
-
- dev->mcu.reg_pairs = NULL;
-
- mutex_unlock(&dev->mcu.mutex);
-
- consume_skb(skb);
-
- return ret;
-
-}
-
-int mt76x0_burst_write_regs(struct mt76x0_dev *dev, u32 offset,
- const u32 *data, int n)
-{
- const int max_regs_per_cmd = INBAND_PACKET_MAX_LEN / 4 - 1;
- struct sk_buff *skb;
- int cnt, i, ret;
-
- if (!n)
- return 0;
-
- cnt = min(max_regs_per_cmd, n);
-
- skb = alloc_skb(cnt * 4 + MT_DMA_HDR_LEN + 4, GFP_KERNEL);
- if (!skb)
- return -ENOMEM;
- skb_reserve(skb, MT_DMA_HDR_LEN);
-
- skb_put_le32(skb, MT_MCU_MEMMAP_WLAN + offset);
- for (i = 0; i < cnt; i++)
- skb_put_le32(skb, data[i]);
-
- ret = mt76x0_mcu_msg_send(dev, skb, CMD_BURST_WRITE, cnt == n);
- if (ret)
- return ret;
-
- return mt76x0_burst_write_regs(dev, offset + cnt * 4,
- data + cnt, n - cnt);
-}
-
-#if 0
-static int mt76x0_burst_read_regs(struct mt76x0_dev *dev, u32 base,
- struct mt76_reg_pair *data, int n)
-{
- const int max_vals_per_cmd = INBAND_PACKET_MAX_LEN / 4 - 1;
- struct sk_buff *skb;
- int cnt, ret;
-
- if (!n)
- return 0;
-
- cnt = min(max_vals_per_cmd, n);
- if (cnt != n)
- return -EINVAL;
-
- skb = alloc_skb(cnt * 4 + MT_DMA_HDR_LEN + 4, GFP_KERNEL);
- if (!skb)
- return -ENOMEM;
- skb_reserve(skb, MT_DMA_HDR_LEN);
-
- skb_put_le32(skb, base + data[0].reg);
- skb_put_le32(skb, n);
-
- mutex_lock(&dev->mcu.mutex);
-
- dev->mcu.reg_pairs = data;
- dev->mcu.reg_pairs_len = n;
- dev->mcu.reg_base = base;
- dev->mcu.burst_read = true;
-
- ret = __mt76x0_mcu_msg_send(dev, skb, CMD_BURST_READ, true);
-
- dev->mcu.reg_pairs = NULL;
-
- mutex_unlock(&dev->mcu.mutex);
-
- consume_skb(skb);
-
- return ret;
-}
-#endif
-
-struct mt76_fw_header {
- __le32 ilm_len;
- __le32 dlm_len;
- __le16 build_ver;
- __le16 fw_ver;
- u8 pad[4];
- char build_time[16];
-};
-
-struct mt76_fw {
- struct mt76_fw_header hdr;
- u8 ivb[MT_MCU_IVB_SIZE];
- u8 ilm[];
-};
-
-static int __mt76x0_dma_fw(struct mt76x0_dev *dev,
- const struct mt76x0_dma_buf *dma_buf,
- const void *data, u32 len, u32 dst_addr)
-{
- DECLARE_COMPLETION_ONSTACK(cmpl);
- struct mt76x0_dma_buf buf = *dma_buf; /* we need to fake length */
- __le32 reg;
- u32 val;
- int ret;
-
- reg = cpu_to_le32(FIELD_PREP(MT_TXD_INFO_TYPE, DMA_COMMAND) |
- FIELD_PREP(MT_TXD_INFO_D_PORT, CPU_TX_PORT) |
- FIELD_PREP(MT_TXD_INFO_LEN, len));
- memcpy(buf.buf, &reg, sizeof(reg));
- memcpy(buf.buf + sizeof(reg), data, len);
- memset(buf.buf + sizeof(reg) + len, 0, 8);
-
- ret = mt76x0_vendor_single_wr(dev, MT_VEND_WRITE_FCE,
- MT_FCE_DMA_ADDR, dst_addr);
- if (ret)
- return ret;
- len = roundup(len, 4);
- ret = mt76x0_vendor_single_wr(dev, MT_VEND_WRITE_FCE,
- MT_FCE_DMA_LEN, len << 16);
- if (ret)
- return ret;
-
- buf.len = MT_DMA_HDR_LEN + len + 4;
- ret = mt76x0_usb_submit_buf(dev, USB_DIR_OUT, MT_EP_OUT_INBAND_CMD,
- &buf, GFP_KERNEL,
- mt76x0_complete_urb, &cmpl);
- if (ret)
- return ret;
-
- if (!wait_for_completion_timeout(&cmpl, msecs_to_jiffies(1000))) {
- dev_err(dev->mt76.dev, "Error: firmware upload timed out\n");
- usb_kill_urb(buf.urb);
- return -ETIMEDOUT;
- }
- if (mt76x0_urb_has_error(buf.urb)) {
- dev_err(dev->mt76.dev, "Error: firmware upload urb failed:%d\n",
- buf.urb->status);
- return buf.urb->status;
- }
-
- val = mt76_rr(dev, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX);
- val++;
- mt76_wr(dev, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX, val);
-
- msleep(5);
-
- return 0;
-}
-
-static int
-mt76x0_dma_fw(struct mt76x0_dev *dev, struct mt76x0_dma_buf *dma_buf,
- const void *data, int len, u32 dst_addr)
-{
- int n, ret;
-
- if (len == 0)
- return 0;
-
- n = min(MCU_FW_URB_MAX_PAYLOAD, len);
- ret = __mt76x0_dma_fw(dev, dma_buf, data, n, dst_addr);
- if (ret)
- return ret;
-
-#if 0
- if (!mt76_poll_msec(dev, MT_MCU_COM_REG1, BIT(31), BIT(31), 500))
- return -ETIMEDOUT;
-#endif
-
- return mt76x0_dma_fw(dev, dma_buf, data + n, len - n, dst_addr + n);
-}
-
-static int
-mt76x0_upload_firmware(struct mt76x0_dev *dev, const struct mt76_fw *fw)
-{
- struct mt76x0_dma_buf dma_buf;
- void *ivb;
- u32 ilm_len, dlm_len;
- int i, ret;
-
- ivb = kmemdup(fw->ivb, sizeof(fw->ivb), GFP_KERNEL);
- if (!ivb)
- return -ENOMEM;
- if (mt76x0_usb_alloc_buf(dev, MCU_FW_URB_SIZE, &dma_buf)) {
- ret = -ENOMEM;
- goto error;
- }
-
- ilm_len = le32_to_cpu(fw->hdr.ilm_len) - sizeof(fw->ivb);
- dev_dbg(dev->mt76.dev, "loading FW - ILM %u + IVB %zu\n",
- ilm_len, sizeof(fw->ivb));
- ret = mt76x0_dma_fw(dev, &dma_buf, fw->ilm, ilm_len, sizeof(fw->ivb));
- if (ret)
- goto error;
-
- dlm_len = le32_to_cpu(fw->hdr.dlm_len);
- dev_dbg(dev->mt76.dev, "loading FW - DLM %u\n", dlm_len);
- ret = mt76x0_dma_fw(dev, &dma_buf, fw->ilm + ilm_len,
- dlm_len, MT_MCU_DLM_OFFSET);
- if (ret)
- goto error;
-
- ret = mt76x0_vendor_request(dev, MT_VEND_DEV_MODE, USB_DIR_OUT,
- 0x12, 0, ivb, sizeof(fw->ivb));
- if (ret < 0)
- goto error;
- ret = 0;
-
- for (i = 100; i && !firmware_running(dev); i--)
- msleep(10);
- if (!i) {
- ret = -ETIMEDOUT;
- goto error;
- }
-
- dev_dbg(dev->mt76.dev, "Firmware running!\n");
-error:
- kfree(ivb);
- mt76x0_usb_free_buf(dev, &dma_buf);
-
- return ret;
-}
-
-static int mt76x0_load_firmware(struct mt76x0_dev *dev)
-{
- const struct firmware *fw;
- const struct mt76_fw_header *hdr;
- int len, ret;
- u32 val;
-
- mt76_wr(dev, MT_USB_DMA_CFG, (MT_USB_DMA_CFG_RX_BULK_EN |
- MT_USB_DMA_CFG_TX_BULK_EN));
-
- if (firmware_running(dev))
- return 0;
-
- ret = request_firmware(&fw, MT7610_FIRMWARE, dev->mt76.dev);
- if (ret)
- return ret;
-
- if (!fw || !fw->data || fw->size < sizeof(*hdr))
- goto err_inv_fw;
-
- hdr = (const struct mt76_fw_header *) fw->data;
-
- if (le32_to_cpu(hdr->ilm_len) <= MT_MCU_IVB_SIZE)
- goto err_inv_fw;
-
- len = sizeof(*hdr);
- len += le32_to_cpu(hdr->ilm_len);
- len += le32_to_cpu(hdr->dlm_len);
-
- if (fw->size != len)
- goto err_inv_fw;
-
- val = le16_to_cpu(hdr->fw_ver);
- dev_dbg(dev->mt76.dev,
- "Firmware Version: %d.%d.%02d Build: %x Build time: %.16s\n",
- (val >> 12) & 0xf, (val >> 8) & 0xf, val & 0xf,
- le16_to_cpu(hdr->build_ver), hdr->build_time);
-
- len = le32_to_cpu(hdr->ilm_len);
-
- mt76_wr(dev, 0x1004, 0x2c);
-
- mt76_set(dev, MT_USB_DMA_CFG, (MT_USB_DMA_CFG_RX_BULK_EN |
- MT_USB_DMA_CFG_TX_BULK_EN) |
- FIELD_PREP(MT_USB_DMA_CFG_RX_BULK_AGG_TOUT, 0x20));
- mt76x0_vendor_reset(dev);
- msleep(5);
-/*
- mt76x0_rmw(dev, MT_PBF_CFG, 0, (MT_PBF_CFG_TX0Q_EN |
- MT_PBF_CFG_TX1Q_EN |
- MT_PBF_CFG_TX2Q_EN |
- MT_PBF_CFG_TX3Q_EN));
-*/
-
- mt76_wr(dev, MT_FCE_PSE_CTRL, 1);
-
- /* FCE tx_fs_base_ptr */
- mt76_wr(dev, MT_TX_CPU_FROM_FCE_BASE_PTR, 0x400230);
- /* FCE tx_fs_max_cnt */
- mt76_wr(dev, MT_TX_CPU_FROM_FCE_MAX_COUNT, 1);
- /* FCE pdma enable */
- mt76_wr(dev, MT_FCE_PDMA_GLOBAL_CONF, 0x44);
- /* FCE skip_fs_en */
- mt76_wr(dev, MT_FCE_SKIP_FS, 3);
-
- val = mt76_rr(dev, MT_USB_DMA_CFG);
- val |= MT_USB_DMA_CFG_TX_WL_DROP;
- mt76_wr(dev, MT_USB_DMA_CFG, val);
- val &= ~MT_USB_DMA_CFG_TX_WL_DROP;
- mt76_wr(dev, MT_USB_DMA_CFG, val);
-
- ret = mt76x0_upload_firmware(dev, (const struct mt76_fw *)fw->data);
- release_firmware(fw);
-
- mt76_wr(dev, MT_FCE_PSE_CTRL, 1);
-
- return ret;
-
-err_inv_fw:
- dev_err(dev->mt76.dev, "Invalid firmware image\n");
- release_firmware(fw);
- return -ENOENT;
-}
-
-int mt76x0_mcu_init(struct mt76x0_dev *dev)
-{
- int ret;
-
- mutex_init(&dev->mcu.mutex);
-
- ret = mt76x0_load_firmware(dev);
- if (ret)
- return ret;
-
- set_bit(MT76_STATE_MCU_RUNNING, &dev->mt76.state);
-
- return 0;
-}
-
-int mt76x0_mcu_cmd_init(struct mt76x0_dev *dev)
-{
- int ret;
-
- ret = mt76x0_mcu_function_select(dev, Q_SELECT, 1);
- if (ret)
- return ret;
-
- init_completion(&dev->mcu.resp_cmpl);
- if (mt76x0_usb_alloc_buf(dev, MCU_RESP_URB_SIZE, &dev->mcu.resp)) {
- mt76x0_usb_free_buf(dev, &dev->mcu.resp);
- return -ENOMEM;
- }
-
- ret = mt76x0_usb_submit_buf(dev, USB_DIR_IN, MT_EP_IN_CMD_RESP,
- &dev->mcu.resp, GFP_KERNEL,
- mt76x0_complete_urb, &dev->mcu.resp_cmpl);
- if (ret) {
- mt76x0_usb_free_buf(dev, &dev->mcu.resp);
- return ret;
- }
-
- return 0;
-}
-
-void mt76x0_mcu_cmd_deinit(struct mt76x0_dev *dev)
-{
- usb_kill_urb(dev->mcu.resp.urb);
- mt76x0_usb_free_buf(dev, &dev->mcu.resp);
-}
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h
index 8c2f77f4c3f5..3b34e1d2769f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mcu.h
@@ -15,65 +15,18 @@
#ifndef __MT76X0U_MCU_H
#define __MT76X0U_MCU_H
-struct mt76x0_dev;
+#include "../mt76x02_mcu.h"
-/* Register definitions */
-#define MT_MCU_RESET_CTL 0x070C
-#define MT_MCU_INT_LEVEL 0x0718
-#define MT_MCU_COM_REG0 0x0730
-#define MT_MCU_COM_REG1 0x0734
-#define MT_MCU_COM_REG2 0x0738
-#define MT_MCU_COM_REG3 0x073C
+struct mt76x02_dev;
#define MT_MCU_IVB_SIZE 0x40
#define MT_MCU_DLM_OFFSET 0x80000
-#define MT_MCU_MEMMAP_WLAN 0x00410000
/* We use same space for BBP as for MAC regs
* #define MT_MCU_MEMMAP_BBP 0x40000000
*/
#define MT_MCU_MEMMAP_RF 0x80000000
-#define INBAND_PACKET_MAX_LEN 192
-
-enum mcu_cmd {
- CMD_FUN_SET_OP = 1,
- CMD_LOAD_CR = 2,
- CMD_INIT_GAIN_OP = 3,
- CMD_DYNC_VGA_OP = 6,
- CMD_TDLS_CH_SW = 7,
- CMD_BURST_WRITE = 8,
- CMD_READ_MODIFY_WRITE = 9,
- CMD_RANDOM_READ = 10,
- CMD_BURST_READ = 11,
- CMD_RANDOM_WRITE = 12,
- CMD_LED_MODE_OP = 16,
- CMD_POWER_SAVING_OP = 20,
- CMD_WOW_CONFIG = 21,
- CMD_WOW_QUERY = 22,
- CMD_WOW_FEATURE = 24,
- CMD_CARRIER_DETECT_OP = 28,
- CMD_RADOR_DETECT_OP = 29,
- CMD_SWITCH_CHANNEL_OP = 30,
- CMD_CALIBRATION_OP = 31,
- CMD_BEACON_OP = 32,
- CMD_ANTENNA_OP = 33,
-};
-
-enum mcu_function {
- Q_SELECT = 1,
- BW_SETTING = 2,
- ATOMIC_TSSI_SETTING = 5,
-};
-
-enum mcu_power_mode {
- RADIO_OFF = 0x30,
- RADIO_ON = 0x31,
- RADIO_OFF_AUTO_WAKEUP = 0x32,
- RADIO_OFF_ADVANCE = 0x33,
- RADIO_ON_ADVANCE = 0x34,
-};
-
enum mcu_calibrate {
MCU_CAL_R = 1,
MCU_CAL_RXDCOC,
@@ -86,16 +39,16 @@ enum mcu_calibrate {
MCU_CAL_TXDCOC,
MCU_CAL_RX_GROUP_DELAY,
MCU_CAL_TX_GROUP_DELAY,
+ MCU_CAL_VCO,
+ MCU_CAL_NO_SIGNAL = 0xfe,
+ MCU_CAL_FULL = 0xff,
};
-int mt76x0_mcu_init(struct mt76x0_dev *dev);
-int mt76x0_mcu_cmd_init(struct mt76x0_dev *dev);
-void mt76x0_mcu_cmd_deinit(struct mt76x0_dev *dev);
-
-int
-mt76x0_mcu_calibrate(struct mt76x0_dev *dev, enum mcu_calibrate cal, u32 val);
-
-int
-mt76x0_mcu_function_select(struct mt76x0_dev *dev, enum mcu_function func, u32 val);
+int mt76x0e_mcu_init(struct mt76x02_dev *dev);
+int mt76x0u_mcu_init(struct mt76x02_dev *dev);
+static inline int mt76x0_firmware_running(struct mt76x02_dev *dev)
+{
+ return mt76_rr(dev, MT_MCU_COM_REG0) == 1;
+}
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h
index fc9857f61771..2187bafaf2e9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h
@@ -25,306 +25,59 @@
#include <net/mac80211.h>
#include <linux/debugfs.h>
-#include "../mt76.h"
-#include "regs.h"
+#include "../mt76x02.h"
+#include "eeprom.h"
#define MT_CALIBRATE_INTERVAL (4 * HZ)
-#define MT_FREQ_CAL_INIT_DELAY (30 * HZ)
-#define MT_FREQ_CAL_CHECK_INTERVAL (10 * HZ)
-#define MT_FREQ_CAL_ADJ_INTERVAL (HZ / 2)
-
-#define MT_BBP_REG_VERSION 0x00
-
#define MT_USB_AGGR_SIZE_LIMIT 21 /* * 1024B */
#define MT_USB_AGGR_TIMEOUT 0x80 /* * 33ns */
-#define MT_RX_ORDER 3
-#define MT_RX_URB_SIZE (PAGE_SIZE << MT_RX_ORDER)
-
-struct mt76x0_dma_buf {
- struct urb *urb;
- void *buf;
- dma_addr_t dma;
- size_t len;
-};
-
-struct mt76x0_mcu {
- struct mutex mutex;
-
- u8 msg_seq;
-
- struct mt76x0_dma_buf resp;
- struct completion resp_cmpl;
-
- struct mt76_reg_pair *reg_pairs;
- unsigned int reg_pairs_len;
- u32 reg_base;
- bool burst_read;
-};
-
-struct mac_stats {
- u64 rx_stat[6];
- u64 tx_stat[6];
- u64 aggr_stat[2];
- u64 aggr_n[32];
- u64 zero_len_del[2];
-};
-
-#define N_RX_ENTRIES 16
-struct mt76x0_rx_queue {
- struct mt76x0_dev *dev;
-
- struct mt76x0_dma_buf_rx {
- struct urb *urb;
- struct page *p;
- } e[N_RX_ENTRIES];
-
- unsigned int start;
- unsigned int end;
- unsigned int entries;
- unsigned int pending;
-};
-
-#define N_TX_ENTRIES 64
-
-struct mt76x0_tx_queue {
- struct mt76x0_dev *dev;
-
- struct mt76x0_dma_buf_tx {
- struct urb *urb;
- struct sk_buff *skb;
- } e[N_TX_ENTRIES];
-
- unsigned int start;
- unsigned int end;
- unsigned int entries;
- unsigned int used;
- unsigned int fifo_seq;
-};
-
-/* WCID allocation:
- * 0: mcast wcid
- * 1: bssid wcid
- * 1...: STAs
- * ...7e: group wcids
- * 7f: reserved
- */
-#define N_WCIDS 128
-#define GROUP_WCID(idx) (254 - idx)
-
-struct mt76x0_eeprom_params;
-
-#define MT_EE_TEMPERATURE_SLOPE 39
-#define MT_FREQ_OFFSET_INVALID -128
-
-/* addr req mask */
-#define MT_VEND_TYPE_EEPROM BIT(31)
-#define MT_VEND_TYPE_CFG BIT(30)
-#define MT_VEND_TYPE_MASK (MT_VEND_TYPE_EEPROM | MT_VEND_TYPE_CFG)
-
-#define MT_VEND_ADDR(type, n) (MT_VEND_TYPE_##type | (n))
-
-enum mt_bw {
- MT_BW_20,
- MT_BW_40,
-};
-
-/**
- * struct mt76x0_dev - adapter structure
- * @lock: protects @wcid->tx_rate.
- * @mac_lock: locks out mac80211's tx status and rx paths.
- * @tx_lock: protects @tx_q and changes of MT76_STATE_*_STATS
- * flags in @state.
- * @rx_lock: protects @rx_q.
- * @con_mon_lock: protects @ap_bssid, @bcn_*, @avg_rssi.
- * @mutex: ensures exclusive access from mac80211 callbacks.
- * @reg_atomic_mutex: ensures atomicity of indirect register accesses
- * (accesses to RF and BBP).
- * @hw_atomic_mutex: ensures exclusive access to HW during critical
- * operations (power management, channel switch).
- */
-struct mt76x0_dev {
- struct mt76_dev mt76; /* must be first */
-
- struct mutex mutex;
-
- struct mutex usb_ctrl_mtx;
- u8 data[32];
-
- struct tasklet_struct rx_tasklet;
- struct tasklet_struct tx_tasklet;
-
- u8 out_ep[__MT_EP_OUT_MAX];
- u16 out_max_packet;
- u8 in_ep[__MT_EP_IN_MAX];
- u16 in_max_packet;
-
- unsigned long wcid_mask[DIV_ROUND_UP(N_WCIDS, BITS_PER_LONG)];
- unsigned long vif_mask;
-
- struct mt76x0_mcu mcu;
-
- struct delayed_work cal_work;
- struct delayed_work mac_work;
-
- struct workqueue_struct *stat_wq;
- struct delayed_work stat_work;
- struct mt76_wcid *mon_wcid;
- struct mt76_wcid __rcu *wcid[N_WCIDS];
-
- spinlock_t mac_lock;
-
- const u16 *beacon_offsets;
-
- u8 macaddr[ETH_ALEN];
- struct mt76x0_eeprom_params *ee;
-
- struct mutex reg_atomic_mutex;
- struct mutex hw_atomic_mutex;
-
- u32 rxfilter;
- u32 debugfs_reg;
-
- /* TX */
- spinlock_t tx_lock;
- struct mt76x0_tx_queue *tx_q;
- struct sk_buff_head tx_skb_done;
-
- atomic_t avg_ampdu_len;
-
- /* RX */
- spinlock_t rx_lock;
- struct mt76x0_rx_queue rx_q;
-
- /* Connection monitoring things */
- spinlock_t con_mon_lock;
- u8 ap_bssid[ETH_ALEN];
-
- s8 bcn_freq_off;
- u8 bcn_phy_mode;
-
- int avg_rssi; /* starts at 0 and converges */
-
- u8 agc_save;
- u16 chainmask;
-
- struct mac_stats stats;
-};
-
-struct mt76x0_wcid {
- u8 idx;
- u8 hw_key_idx;
-
- u16 tx_rate;
- bool tx_rate_set;
- u8 tx_rate_nss;
-};
-
-struct mt76_vif {
- u8 idx;
-
- struct mt76_wcid group_wcid;
-};
-
-struct mt76_tx_status {
- u8 valid:1;
- u8 success:1;
- u8 aggr:1;
- u8 ack_req:1;
- u8 is_probe:1;
- u8 wcid;
- u8 pktid;
- u8 retry;
- u16 rate;
-} __packed __aligned(2);
-
-struct mt76_sta {
- struct mt76_wcid wcid;
- struct mt76_tx_status status;
- int n_frames;
- u16 agg_ssn[IEEE80211_NUM_TIDS];
-};
-
-struct mt76_reg_pair {
- u32 reg;
- u32 value;
-};
-
-struct mt76x0_rxwi;
-
-extern const struct ieee80211_ops mt76x0_ops;
-
-static inline bool is_mt7610e(struct mt76x0_dev *dev)
+static inline bool is_mt7610e(struct mt76x02_dev *dev)
{
/* TODO */
return false;
}
-void mt76x0_init_debugfs(struct mt76x0_dev *dev);
-
-int mt76x0_wait_asic_ready(struct mt76x0_dev *dev);
-
-/* Compatibility with mt76 */
-#define mt76_rmw_field(_dev, _reg, _field, _val) \
- mt76_rmw(_dev, _reg, _field, FIELD_PREP(_field, _val))
-
-int mt76x0_write_reg_pairs(struct mt76x0_dev *dev, u32 base,
- const struct mt76_reg_pair *data, int len);
-int mt76x0_read_reg_pairs(struct mt76x0_dev *dev, u32 base,
- struct mt76_reg_pair *data, int len);
-int mt76x0_burst_write_regs(struct mt76x0_dev *dev, u32 offset,
- const u32 *data, int n);
-void mt76x0_addr_wr(struct mt76x0_dev *dev, const u32 offset, const u8 *addr);
+void mt76x0_init_debugfs(struct mt76x02_dev *dev);
/* Init */
-struct mt76x0_dev *mt76x0_alloc_device(struct device *dev);
-int mt76x0_init_hardware(struct mt76x0_dev *dev);
-int mt76x0_register_device(struct mt76x0_dev *dev);
-void mt76x0_cleanup(struct mt76x0_dev *dev);
-void mt76x0_chip_onoff(struct mt76x0_dev *dev, bool enable, bool reset);
-
-int mt76x0_mac_start(struct mt76x0_dev *dev);
-void mt76x0_mac_stop(struct mt76x0_dev *dev);
+struct mt76x02_dev *
+mt76x0_alloc_device(struct device *pdev,
+ const struct mt76_driver_ops *drv_ops,
+ const struct ieee80211_ops *ops);
+int mt76x0_init_hardware(struct mt76x02_dev *dev);
+int mt76x0_register_device(struct mt76x02_dev *dev);
+void mt76x0_chip_onoff(struct mt76x02_dev *dev, bool enable, bool reset);
+
+int mt76x0_mac_start(struct mt76x02_dev *dev);
+void mt76x0_mac_stop(struct mt76x02_dev *dev);
+
+int mt76x0_config(struct ieee80211_hw *hw, u32 changed);
+void mt76x0_bss_info_changed(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *info, u32 changed);
+void mt76x0_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ const u8 *mac_addr);
+void mt76x0_sw_scan_complete(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif);
+int mt76x0_set_rts_threshold(struct ieee80211_hw *hw, u32 value);
/* PHY */
-void mt76x0_phy_init(struct mt76x0_dev *dev);
-int mt76x0_wait_bbp_ready(struct mt76x0_dev *dev);
-void mt76x0_agc_save(struct mt76x0_dev *dev);
-void mt76x0_agc_restore(struct mt76x0_dev *dev);
-int mt76x0_phy_set_channel(struct mt76x0_dev *dev,
+void mt76x0_phy_init(struct mt76x02_dev *dev);
+int mt76x0_wait_bbp_ready(struct mt76x02_dev *dev);
+int mt76x0_phy_set_channel(struct mt76x02_dev *dev,
struct cfg80211_chan_def *chandef);
-void mt76x0_phy_recalibrate_after_assoc(struct mt76x0_dev *dev);
-int mt76x0_phy_get_rssi(struct mt76x0_dev *dev, struct mt76x0_rxwi *rxwi);
-void mt76x0_phy_con_cal_onoff(struct mt76x0_dev *dev,
- struct ieee80211_bss_conf *info);
+void mt76x0_phy_recalibrate_after_assoc(struct mt76x02_dev *dev);
+void mt76x0_phy_set_txpower(struct mt76x02_dev *dev);
+void mt76x0_phy_calibrate(struct mt76x02_dev *dev, bool power_on);
/* MAC */
void mt76x0_mac_work(struct work_struct *work);
-void mt76x0_mac_set_protection(struct mt76x0_dev *dev, bool legacy_prot,
+void mt76x0_mac_set_protection(struct mt76x02_dev *dev, bool legacy_prot,
int ht_mode);
-void mt76x0_mac_set_short_preamble(struct mt76x0_dev *dev, bool short_preamb);
-void mt76x0_mac_config_tsf(struct mt76x0_dev *dev, bool enable, int interval);
-void
-mt76x0_mac_wcid_setup(struct mt76x0_dev *dev, u8 idx, u8 vif_idx, u8 *mac);
-void mt76x0_mac_set_ampdu_factor(struct mt76x0_dev *dev);
-
-/* TX */
-void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
- struct sk_buff *skb);
-int mt76x0_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- u16 queue, const struct ieee80211_tx_queue_params *params);
-void mt76x0_tx_status(struct mt76x0_dev *dev, struct sk_buff *skb);
-void mt76x0_tx_stat(struct work_struct *work);
-
-/* util */
-void mt76x0_remove_hdr_pad(struct sk_buff *skb);
-int mt76x0_insert_hdr_pad(struct sk_buff *skb);
-
-int mt76x0_dma_init(struct mt76x0_dev *dev);
-void mt76x0_dma_cleanup(struct mt76x0_dev *dev);
-
-int mt76x0_dma_enqueue_tx(struct mt76x0_dev *dev, struct sk_buff *skb,
- struct mt76_wcid *wcid, int hw_q);
+void mt76x0_mac_set_short_preamble(struct mt76x02_dev *dev, bool short_preamb);
+void mt76x0_mac_config_tsf(struct mt76x02_dev *dev, bool enable, int interval);
+void mt76x0_mac_set_ampdu_factor(struct mt76x02_dev *dev);
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c
new file mode 100644
index 000000000000..522c86059bcb
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include "mt76x0.h"
+#include "mcu.h"
+
+static int mt76x0e_start(struct ieee80211_hw *hw)
+{
+ struct mt76x02_dev *dev = hw->priv;
+
+ mutex_lock(&dev->mt76.mutex);
+
+ mt76x02_mac_start(dev);
+ mt76x0_phy_calibrate(dev, true);
+ ieee80211_queue_delayed_work(dev->mt76.hw, &dev->mac_work,
+ MT_CALIBRATE_INTERVAL);
+ ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work,
+ MT_CALIBRATE_INTERVAL);
+ set_bit(MT76_STATE_RUNNING, &dev->mt76.state);
+
+ mutex_unlock(&dev->mt76.mutex);
+
+ return 0;
+}
+
+static void mt76x0e_stop_hw(struct mt76x02_dev *dev)
+{
+ cancel_delayed_work_sync(&dev->cal_work);
+ cancel_delayed_work_sync(&dev->mac_work);
+
+ if (!mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_BUSY,
+ 0, 1000))
+ dev_warn(dev->mt76.dev, "TX DMA did not stop\n");
+ mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_EN);
+
+ mt76x0_mac_stop(dev);
+
+ if (!mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_RX_DMA_BUSY,
+ 0, 1000))
+ dev_warn(dev->mt76.dev, "TX DMA did not stop\n");
+ mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_RX_DMA_EN);
+}
+
+static void mt76x0e_stop(struct ieee80211_hw *hw)
+{
+ struct mt76x02_dev *dev = hw->priv;
+
+ mutex_lock(&dev->mt76.mutex);
+ clear_bit(MT76_STATE_RUNNING, &dev->mt76.state);
+ mt76x0e_stop_hw(dev);
+ mutex_unlock(&dev->mt76.mutex);
+}
+
+static const struct ieee80211_ops mt76x0e_ops = {
+ .tx = mt76x02_tx,
+ .start = mt76x0e_start,
+ .stop = mt76x0e_stop,
+ .add_interface = mt76x02_add_interface,
+ .remove_interface = mt76x02_remove_interface,
+ .config = mt76x0_config,
+ .configure_filter = mt76x02_configure_filter,
+ .sta_add = mt76x02_sta_add,
+ .sta_remove = mt76x02_sta_remove,
+ .set_key = mt76x02_set_key,
+ .conf_tx = mt76x02_conf_tx,
+ .sw_scan_start = mt76x0_sw_scan,
+ .sw_scan_complete = mt76x0_sw_scan_complete,
+ .ampdu_action = mt76x02_ampdu_action,
+ .sta_rate_tbl_update = mt76x02_sta_rate_tbl_update,
+ .wake_tx_queue = mt76_wake_tx_queue,
+};
+
+static int mt76x0e_register_device(struct mt76x02_dev *dev)
+{
+ int err;
+
+ mt76x0_chip_onoff(dev, true, false);
+ if (!mt76x02_wait_for_mac(&dev->mt76))
+ return -ETIMEDOUT;
+
+ mt76x02_dma_disable(dev);
+ err = mt76x0e_mcu_init(dev);
+ if (err < 0)
+ return err;
+
+ err = mt76x02_dma_init(dev);
+ if (err < 0)
+ return err;
+
+ err = mt76x0_init_hardware(dev);
+ if (err < 0)
+ return err;
+
+ if (mt76_chip(&dev->mt76) == 0x7610) {
+ u16 val;
+
+ mt76_clear(dev, MT_COEXCFG0, BIT(0));
+
+ val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_0);
+ if (!(val & MT_EE_NIC_CONF_0_PA_IO_CURRENT))
+ mt76_set(dev, MT_XO_CTRL7, 0xc03);
+ }
+
+ mt76_clear(dev, 0x110, BIT(9));
+ mt76_set(dev, MT_MAX_LEN_CFG, BIT(13));
+
+ err = mt76x0_register_device(dev);
+ if (err < 0)
+ return err;
+
+ set_bit(MT76_STATE_INITIALIZED, &dev->mt76.state);
+
+ return 0;
+}
+
+static int
+mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ static const struct mt76_driver_ops drv_ops = {
+ .txwi_size = sizeof(struct mt76x02_txwi),
+ .tx_prepare_skb = mt76x02_tx_prepare_skb,
+ .tx_complete_skb = mt76x02_tx_complete_skb,
+ .rx_skb = mt76x02_queue_rx_skb,
+ .rx_poll_complete = mt76x02_rx_poll_complete,
+ };
+ struct mt76x02_dev *dev;
+ int ret;
+
+ ret = pcim_enable_device(pdev);
+ if (ret)
+ return ret;
+
+ ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev));
+ if (ret)
+ return ret;
+
+ pci_set_master(pdev);
+
+ ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
+
+ dev = mt76x0_alloc_device(&pdev->dev, &drv_ops, &mt76x0e_ops);
+ if (!dev)
+ return -ENOMEM;
+
+ mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]);
+
+ dev->mt76.rev = mt76_rr(dev, MT_ASIC_VERSION);
+ dev_info(dev->mt76.dev, "ASIC revision: %08x\n", dev->mt76.rev);
+
+ ret = devm_request_irq(dev->mt76.dev, pdev->irq, mt76x02_irq_handler,
+ IRQF_SHARED, KBUILD_MODNAME, dev);
+ if (ret)
+ goto error;
+
+ ret = mt76x0e_register_device(dev);
+ if (ret < 0)
+ goto error;
+
+ return 0;
+
+error:
+ ieee80211_free_hw(mt76_hw(dev));
+ return ret;
+}
+
+static void mt76x0e_cleanup(struct mt76x02_dev *dev)
+{
+ clear_bit(MT76_STATE_INITIALIZED, &dev->mt76.state);
+ mt76x0_chip_onoff(dev, false, false);
+ mt76x0e_stop_hw(dev);
+ mt76x02_dma_cleanup(dev);
+ mt76x02_mcu_cleanup(dev);
+}
+
+static void
+mt76x0e_remove(struct pci_dev *pdev)
+{
+ struct mt76_dev *mdev = pci_get_drvdata(pdev);
+ struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
+
+ mt76_unregister_device(mdev);
+ mt76x0e_cleanup(dev);
+ ieee80211_free_hw(mdev->hw);
+}
+
+static const struct pci_device_id mt76x0e_device_table[] = {
+ { PCI_DEVICE(0x14c3, 0x7630) },
+ { PCI_DEVICE(0x14c3, 0x7650) },
+ { },
+};
+
+MODULE_DEVICE_TABLE(pci, mt76x0e_device_table);
+MODULE_LICENSE("Dual BSD/GPL");
+
+static struct pci_driver mt76x0e_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = mt76x0e_device_table,
+ .probe = mt76x0e_probe,
+ .remove = mt76x0e_remove,
+};
+
+module_pci_driver(mt76x0e_driver);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci_mcu.c
new file mode 100644
index 000000000000..569861289aa5
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci_mcu.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <linux/kernel.h>
+#include <linux/firmware.h>
+
+#include "mt76x0.h"
+#include "mcu.h"
+
+#define MT7610E_FIRMWARE "mediatek/mt7610e.bin"
+#define MT7650E_FIRMWARE "mediatek/mt7650e.bin"
+
+#define MT_MCU_IVB_ADDR (MT_MCU_ILM_ADDR + 0x54000 - MT_MCU_IVB_SIZE)
+
+static int mt76x0e_load_firmware(struct mt76x02_dev *dev)
+{
+ bool is_combo_chip = mt76_chip(&dev->mt76) != 0x7610;
+ u32 val, ilm_len, dlm_len, offset = 0;
+ const struct mt76x02_fw_header *hdr;
+ const struct firmware *fw;
+ const char *firmware;
+ const u8 *fw_payload;
+ int len, err;
+
+ if (is_combo_chip)
+ firmware = MT7650E_FIRMWARE;
+ else
+ firmware = MT7610E_FIRMWARE;
+
+ err = request_firmware(&fw, firmware, dev->mt76.dev);
+ if (err)
+ return err;
+
+ if (!fw || !fw->data || fw->size < sizeof(*hdr)) {
+ err = -EIO;
+ goto out;
+ }
+
+ hdr = (const struct mt76x02_fw_header *)fw->data;
+
+ len = sizeof(*hdr);
+ len += le32_to_cpu(hdr->ilm_len);
+ len += le32_to_cpu(hdr->dlm_len);
+
+ if (fw->size != len) {
+ err = -EIO;
+ goto out;
+ }
+
+ fw_payload = fw->data + sizeof(*hdr);
+
+ val = le16_to_cpu(hdr->fw_ver);
+ dev_info(dev->mt76.dev, "Firmware Version: %d.%d.%02d\n",
+ (val >> 12) & 0xf, (val >> 8) & 0xf, val & 0xf);
+
+ val = le16_to_cpu(hdr->fw_ver);
+ dev_dbg(dev->mt76.dev,
+ "Firmware Version: %d.%d.%02d Build: %x Build time: %.16s\n",
+ (val >> 12) & 0xf, (val >> 8) & 0xf, val & 0xf,
+ le16_to_cpu(hdr->build_ver), hdr->build_time);
+
+ if (is_combo_chip && !mt76_poll(dev, MT_MCU_SEMAPHORE_00, 1, 1, 600)) {
+ dev_err(dev->mt76.dev,
+ "Could not get hardware semaphore for loading fw\n");
+ err = -ETIMEDOUT;
+ goto out;
+ }
+
+ /* upload ILM. */
+ mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, 0);
+ ilm_len = le32_to_cpu(hdr->ilm_len);
+ if (is_combo_chip) {
+ ilm_len -= MT_MCU_IVB_SIZE;
+ offset = MT_MCU_IVB_SIZE;
+ }
+ dev_dbg(dev->mt76.dev, "loading FW - ILM %u\n", ilm_len);
+ mt76_wr_copy(dev, MT_MCU_ILM_ADDR + offset, fw_payload + offset,
+ ilm_len);
+
+ /* upload IVB. */
+ if (is_combo_chip) {
+ dev_dbg(dev->mt76.dev, "loading FW - IVB %u\n",
+ MT_MCU_IVB_SIZE);
+ mt76_wr_copy(dev, MT_MCU_IVB_ADDR, fw_payload, MT_MCU_IVB_SIZE);
+ }
+
+ /* upload DLM. */
+ mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, MT_MCU_DLM_OFFSET);
+ dlm_len = le32_to_cpu(hdr->dlm_len);
+ dev_dbg(dev->mt76.dev, "loading FW - DLM %u\n", dlm_len);
+ mt76_wr_copy(dev, MT_MCU_ILM_ADDR,
+ fw_payload + le32_to_cpu(hdr->ilm_len), dlm_len);
+
+ /* trigger firmware */
+ mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, 0);
+ if (is_combo_chip)
+ mt76_wr(dev, MT_MCU_INT_LEVEL, 0x3);
+ else
+ mt76_wr(dev, MT_MCU_RESET_CTL, 0x300);
+
+ if (!mt76_poll_msec(dev, MT_MCU_COM_REG0, 1, 1, 1000)) {
+ dev_err(dev->mt76.dev, "Firmware failed to start\n");
+ err = -ETIMEDOUT;
+ goto out;
+ }
+
+ mt76x02_set_ethtool_fwver(dev, hdr);
+ dev_dbg(dev->mt76.dev, "Firmware running!\n");
+
+out:
+ if (is_combo_chip)
+ mt76_wr(dev, MT_MCU_SEMAPHORE_00, 0x1);
+ release_firmware(fw);
+
+ return err;
+}
+
+int mt76x0e_mcu_init(struct mt76x02_dev *dev)
+{
+ static const struct mt76_mcu_ops mt76x0e_mcu_ops = {
+ .mcu_msg_alloc = mt76x02_mcu_msg_alloc,
+ .mcu_send_msg = mt76x02_mcu_msg_send,
+ };
+ int err;
+
+ dev->mt76.mcu_ops = &mt76x0e_mcu_ops;
+
+ err = mt76x0e_load_firmware(dev);
+ if (err < 0)
+ return err;
+
+ set_bit(MT76_STATE_MCU_RUNNING, &dev->mt76.state);
+
+ return 0;
+}
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c
index 5da7bfbe907f..cf024950e0ed 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c
@@ -14,6 +14,9 @@
* GNU General Public License for more details.
*/
+#include <linux/kernel.h>
+#include <linux/etherdevice.h>
+
#include "mt76x0.h"
#include "mcu.h"
#include "eeprom.h"
@@ -21,11 +24,10 @@
#include "phy.h"
#include "initvals.h"
#include "initvals_phy.h"
-
-#include <linux/etherdevice.h>
+#include "../mt76x02_phy.h"
static int
-mt76x0_rf_csr_wr(struct mt76x0_dev *dev, u32 offset, u8 value)
+mt76x0_rf_csr_wr(struct mt76x02_dev *dev, u32 offset, u8 value)
{
int ret = 0;
u8 bank, reg;
@@ -36,10 +38,10 @@ mt76x0_rf_csr_wr(struct mt76x0_dev *dev, u32 offset, u8 value)
bank = MT_RF_BANK(offset);
reg = MT_RF_REG(offset);
- if (WARN_ON_ONCE(reg > 64) || WARN_ON_ONCE(bank) > 8)
+ if (WARN_ON_ONCE(reg > 127) || WARN_ON_ONCE(bank > 8))
return -EINVAL;
- mutex_lock(&dev->reg_atomic_mutex);
+ mutex_lock(&dev->phy_mutex);
if (!mt76_poll(dev, MT_RF_CSR_CFG, MT_RF_CSR_CFG_KICK, 0, 100)) {
ret = -ETIMEDOUT;
@@ -54,7 +56,7 @@ mt76x0_rf_csr_wr(struct mt76x0_dev *dev, u32 offset, u8 value)
MT_RF_CSR_CFG_KICK);
trace_mt76x0_rf_write(&dev->mt76, bank, offset, value);
out:
- mutex_unlock(&dev->reg_atomic_mutex);
+ mutex_unlock(&dev->phy_mutex);
if (ret < 0)
dev_err(dev->mt76.dev, "Error: RF write %d:%d failed:%d!!\n",
@@ -63,8 +65,7 @@ out:
return ret;
}
-static int
-mt76x0_rf_csr_rr(struct mt76x0_dev *dev, u32 offset)
+static int mt76x0_rf_csr_rr(struct mt76x02_dev *dev, u32 offset)
{
int ret = -ETIMEDOUT;
u32 val;
@@ -76,10 +77,10 @@ mt76x0_rf_csr_rr(struct mt76x0_dev *dev, u32 offset)
bank = MT_RF_BANK(offset);
reg = MT_RF_REG(offset);
- if (WARN_ON_ONCE(reg > 64) || WARN_ON_ONCE(bank) > 8)
+ if (WARN_ON_ONCE(reg > 127) || WARN_ON_ONCE(bank > 8))
return -EINVAL;
- mutex_lock(&dev->reg_atomic_mutex);
+ mutex_lock(&dev->phy_mutex);
if (!mt76_poll(dev, MT_RF_CSR_CFG, MT_RF_CSR_CFG_KICK, 0, 100))
goto out;
@@ -99,7 +100,7 @@ mt76x0_rf_csr_rr(struct mt76x0_dev *dev, u32 offset)
trace_mt76x0_rf_read(&dev->mt76, bank, offset, ret);
}
out:
- mutex_unlock(&dev->reg_atomic_mutex);
+ mutex_unlock(&dev->phy_mutex);
if (ret < 0)
dev_err(dev->mt76.dev, "Error: RF read %d:%d failed:%d!!\n",
@@ -109,36 +110,38 @@ out:
}
static int
-rf_wr(struct mt76x0_dev *dev, u32 offset, u8 val)
+rf_wr(struct mt76x02_dev *dev, u32 offset, u8 val)
{
- if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mt76.state)) {
+ if (mt76_is_usb(dev)) {
struct mt76_reg_pair pair = {
.reg = offset,
.value = val,
};
- return mt76x0_write_reg_pairs(dev, MT_MCU_MEMMAP_RF, &pair, 1);
+ WARN_ON_ONCE(!test_bit(MT76_STATE_MCU_RUNNING,
+ &dev->mt76.state));
+ return mt76_wr_rp(dev, MT_MCU_MEMMAP_RF, &pair, 1);
} else {
- WARN_ON_ONCE(1);
return mt76x0_rf_csr_wr(dev, offset, val);
}
}
static int
-rf_rr(struct mt76x0_dev *dev, u32 offset)
+rf_rr(struct mt76x02_dev *dev, u32 offset)
{
int ret;
u32 val;
- if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mt76.state)) {
+ if (mt76_is_usb(dev)) {
struct mt76_reg_pair pair = {
.reg = offset,
};
- ret = mt76x0_read_reg_pairs(dev, MT_MCU_MEMMAP_RF, &pair, 1);
+ WARN_ON_ONCE(!test_bit(MT76_STATE_MCU_RUNNING,
+ &dev->mt76.state));
+ ret = mt76_rd_rp(dev, MT_MCU_MEMMAP_RF, &pair, 1);
val = pair.value;
} else {
- WARN_ON_ONCE(1);
ret = val = mt76x0_rf_csr_rr(dev, offset);
}
@@ -146,7 +149,7 @@ rf_rr(struct mt76x0_dev *dev, u32 offset)
}
static int
-rf_rmw(struct mt76x0_dev *dev, u32 offset, u8 mask, u8 val)
+rf_rmw(struct mt76x02_dev *dev, u32 offset, u8 mask, u8 val)
{
int ret;
@@ -162,30 +165,43 @@ rf_rmw(struct mt76x0_dev *dev, u32 offset, u8 mask, u8 val)
}
static int
-rf_set(struct mt76x0_dev *dev, u32 offset, u8 val)
+rf_set(struct mt76x02_dev *dev, u32 offset, u8 val)
{
return rf_rmw(dev, offset, 0, val);
}
#if 0
static int
-rf_clear(struct mt76x0_dev *dev, u32 offset, u8 mask)
+rf_clear(struct mt76x02_dev *dev, u32 offset, u8 mask)
{
return rf_rmw(dev, offset, mask, 0);
}
#endif
-#define RF_RANDOM_WRITE(dev, tab) \
- mt76x0_write_reg_pairs(dev, MT_MCU_MEMMAP_RF, tab, ARRAY_SIZE(tab));
+static void
+mt76x0_rf_csr_wr_rp(struct mt76x02_dev *dev, const struct mt76_reg_pair *data,
+ int n)
+{
+ while (n-- > 0) {
+ mt76x0_rf_csr_wr(dev, data->reg, data->value);
+ data++;
+ }
+}
+
+#define RF_RANDOM_WRITE(dev, tab) do { \
+ if (mt76_is_mmio(dev)) \
+ mt76x0_rf_csr_wr_rp(dev, tab, ARRAY_SIZE(tab)); \
+ else \
+ mt76_wr_rp(dev, MT_MCU_MEMMAP_RF, tab, ARRAY_SIZE(tab));\
+} while (0)
-int mt76x0_wait_bbp_ready(struct mt76x0_dev *dev)
+int mt76x0_wait_bbp_ready(struct mt76x02_dev *dev)
{
int i = 20;
u32 val;
do {
val = mt76_rr(dev, MT_BBP(CORE, 0));
- printk("BBP version %08x\n", val);
if (val && ~val)
break;
} while (--i);
@@ -195,55 +211,11 @@ int mt76x0_wait_bbp_ready(struct mt76x0_dev *dev)
return -EIO;
}
+ dev_dbg(dev->mt76.dev, "BBP version %08x\n", val);
return 0;
}
-static void
-mt76x0_bbp_set_ctrlch(struct mt76x0_dev *dev, enum nl80211_chan_width width,
- u8 ctrl)
-{
- int core_val, agc_val;
-
- switch (width) {
- case NL80211_CHAN_WIDTH_80:
- core_val = 3;
- agc_val = 7;
- break;
- case NL80211_CHAN_WIDTH_40:
- core_val = 2;
- agc_val = 3;
- break;
- default:
- core_val = 0;
- agc_val = 1;
- break;
- }
-
- mt76_rmw_field(dev, MT_BBP(CORE, 1), MT_BBP_CORE_R1_BW, core_val);
- mt76_rmw_field(dev, MT_BBP(AGC, 0), MT_BBP_AGC_R0_BW, agc_val);
- mt76_rmw_field(dev, MT_BBP(AGC, 0), MT_BBP_AGC_R0_CTRL_CHAN, ctrl);
- mt76_rmw_field(dev, MT_BBP(TXBE, 0), MT_BBP_TXBE_R0_CTRL_CHAN, ctrl);
-}
-
-int mt76x0_phy_get_rssi(struct mt76x0_dev *dev, struct mt76x0_rxwi *rxwi)
-{
- s8 lna_gain, rssi_offset;
- int val;
-
- if (dev->mt76.chandef.chan->band == NL80211_BAND_2GHZ) {
- lna_gain = dev->ee->lna_gain_2ghz;
- rssi_offset = dev->ee->rssi_offset_2ghz[0];
- } else {
- lna_gain = dev->ee->lna_gain_5ghz[0];
- rssi_offset = dev->ee->rssi_offset_5ghz[0];
- }
-
- val = rxwi->rssi[0] + rssi_offset - lna_gain;
-
- return val;
-}
-
-static void mt76x0_vco_cal(struct mt76x0_dev *dev, u8 channel)
+static void mt76x0_vco_cal(struct mt76x02_dev *dev, u8 channel)
{
u8 val;
@@ -300,14 +272,7 @@ static void mt76x0_vco_cal(struct mt76x0_dev *dev, u8 channel)
}
static void
-mt76x0_mac_set_ctrlch(struct mt76x0_dev *dev, bool primary_upper)
-{
- mt76_rmw_field(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_UPPER_40M,
- primary_upper);
-}
-
-static void
-mt76x0_phy_set_band(struct mt76x0_dev *dev, enum nl80211_band band)
+mt76x0_phy_set_band(struct mt76x02_dev *dev, enum nl80211_band band)
{
switch (band) {
case NL80211_BAND_2GHZ:
@@ -316,9 +281,6 @@ mt76x0_phy_set_band(struct mt76x0_dev *dev, enum nl80211_band band)
rf_wr(dev, MT_RF(5, 0), 0x45);
rf_wr(dev, MT_RF(6, 0), 0x44);
- mt76_set(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_2G);
- mt76_clear(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_5G);
-
mt76_wr(dev, MT_TX_ALC_VGA3, 0x00050007);
mt76_wr(dev, MT_TX0_RF_GAIN_CORR, 0x003E0002);
break;
@@ -328,9 +290,6 @@ mt76x0_phy_set_band(struct mt76x0_dev *dev, enum nl80211_band band)
rf_wr(dev, MT_RF(5, 0), 0x44);
rf_wr(dev, MT_RF(6, 0), 0x45);
- mt76_clear(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_2G);
- mt76_set(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_5G);
-
mt76_wr(dev, MT_TX_ALC_VGA3, 0x00000005);
mt76_wr(dev, MT_TX0_RF_GAIN_CORR, 0x01010102);
break;
@@ -339,16 +298,12 @@ mt76x0_phy_set_band(struct mt76x0_dev *dev, enum nl80211_band band)
}
}
-#define EXT_PA_2G_5G 0x0
-#define EXT_PA_5G_ONLY 0x1
-#define EXT_PA_2G_ONLY 0x2
-#define INT_PA_2G_5G 0x3
-
static void
-mt76x0_phy_set_chan_rf_params(struct mt76x0_dev *dev, u8 channel, u16 rf_bw_band)
+mt76x0_phy_set_chan_rf_params(struct mt76x02_dev *dev, u8 channel, u16 rf_bw_band)
{
u16 rf_band = rf_bw_band & 0xff00;
u16 rf_bw = rf_bw_band & 0x00ff;
+ enum nl80211_band band;
u32 mac_reg;
u8 rf_val;
int i;
@@ -495,11 +450,8 @@ mt76x0_phy_set_chan_rf_params(struct mt76x0_dev *dev, u8 channel, u16 rf_bw_band
mac_reg &= ~0xC; /* Clear 0x518[3:2] */
mt76_wr(dev, MT_RF_MISC, mac_reg);
- if (dev->ee->pa_type == INT_PA_2G_5G ||
- (dev->ee->pa_type == EXT_PA_5G_ONLY && (rf_band & RF_G_BAND)) ||
- (dev->ee->pa_type == EXT_PA_2G_ONLY && (rf_band & RF_A_BAND))) {
- ; /* Internal PA - nothing to do. */
- } else {
+ band = (rf_band & RF_G_BAND) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
+ if (mt76x02_ext_pa_enabled(dev, band)) {
/*
MT_RF_MISC (offset: 0x0518)
[2]1'b1: enable external A band PA, 1'b0: disable external A band PA
@@ -538,7 +490,7 @@ mt76x0_phy_set_chan_rf_params(struct mt76x0_dev *dev, u8 channel, u16 rf_bw_band
}
static void
-mt76x0_phy_set_chan_bbp_params(struct mt76x0_dev *dev, u8 channel, u16 rf_bw_band)
+mt76x0_phy_set_chan_bbp_params(struct mt76x02_dev *dev, u16 rf_bw_band)
{
int i;
@@ -551,20 +503,10 @@ mt76x0_phy_set_chan_bbp_params(struct mt76x0_dev *dev, u8 channel, u16 rf_bw_ban
if (pair->reg == MT_BBP(AGC, 8)) {
u32 val = pair->value;
- u8 gain = FIELD_GET(MT_BBP_AGC_GAIN, val);
-
- if (channel > 14) {
- if (channel < 100)
- gain -= dev->ee->lna_gain_5ghz[0]*2;
- else if (channel < 137)
- gain -= dev->ee->lna_gain_5ghz[1]*2;
- else
- gain -= dev->ee->lna_gain_5ghz[2]*2;
-
- } else {
- gain -= dev->ee->lna_gain_2ghz*2;
- }
+ u8 gain;
+ gain = FIELD_GET(MT_BBP_AGC_GAIN, val);
+ gain -= dev->cal.rx.lna_gain * 2;
val &= ~MT_BBP_AGC_GAIN;
val |= FIELD_PREP(MT_BBP_AGC_GAIN, gain);
mt76_wr(dev, pair->reg, val);
@@ -574,46 +516,27 @@ mt76x0_phy_set_chan_bbp_params(struct mt76x0_dev *dev, u8 channel, u16 rf_bw_ban
}
}
-#if 0
-static void
-mt76x0_extra_power_over_mac(struct mt76x0_dev *dev)
+static void mt76x0_ant_select(struct mt76x02_dev *dev)
{
- u32 val;
-
- val = ((mt76_rr(dev, MT_TX_PWR_CFG_1) & 0x00003f00) >> 8);
- val |= ((mt76_rr(dev, MT_TX_PWR_CFG_2) & 0x00003f00) << 8);
- mt76_wr(dev, MT_TX_PWR_CFG_7, val);
-
- /* TODO: fix VHT */
- val = ((mt76_rr(dev, MT_TX_PWR_CFG_3) & 0x0000ff00) >> 8);
- mt76_wr(dev, MT_TX_PWR_CFG_8, val);
-
- val = ((mt76_rr(dev, MT_TX_PWR_CFG_4) & 0x0000ff00) >> 8);
- mt76_wr(dev, MT_TX_PWR_CFG_9, val);
-}
-
-static void
-mt76x0_phy_set_tx_power(struct mt76x0_dev *dev, u8 channel, u8 rf_bw_band)
-{
- u32 val;
- int i;
- int bw = (rf_bw_band & RF_BW_20) ? 0 : 1;
+ struct ieee80211_channel *chan = dev->mt76.chandef.chan;
- for (i = 0; i < 4; i++) {
- if (channel <= 14)
- val = dev->ee->tx_pwr_cfg_2g[i][bw];
- else
- val = dev->ee->tx_pwr_cfg_5g[i][bw];
-
- mt76_wr(dev, MT_TX_PWR_CFG_0 + 4*i, val);
+ /* single antenna mode */
+ if (chan->band == NL80211_BAND_2GHZ) {
+ mt76_rmw(dev, MT_COEXCFG3,
+ BIT(5) | BIT(4) | BIT(3) | BIT(2), BIT(1));
+ mt76_rmw(dev, MT_WLAN_FUN_CTRL, BIT(5), BIT(6));
+ } else {
+ mt76_rmw(dev, MT_COEXCFG3, BIT(5) | BIT(2),
+ BIT(4) | BIT(3));
+ mt76_clear(dev, MT_WLAN_FUN_CTRL,
+ BIT(6) | BIT(5));
}
-
- mt76x0_extra_power_over_mac(dev);
+ mt76_clear(dev, MT_CMB_CTRL, BIT(14) | BIT(12));
+ mt76_clear(dev, MT_COEXCFG0, BIT(2));
}
-#endif
static void
-mt76x0_bbp_set_bw(struct mt76x0_dev *dev, enum nl80211_chan_width width)
+mt76x0_bbp_set_bw(struct mt76x02_dev *dev, enum nl80211_chan_width width)
{
enum { BW_20 = 0, BW_40 = 1, BW_80 = 2, BW_10 = 4};
int bw;
@@ -640,39 +563,69 @@ mt76x0_bbp_set_bw(struct mt76x0_dev *dev, enum nl80211_chan_width width)
return ;
}
- mt76x0_mcu_function_select(dev, BW_SETTING, bw);
+ mt76x02_mcu_function_select(dev, BW_SETTING, bw, false);
}
-static void
-mt76x0_phy_set_chan_pwr(struct mt76x0_dev *dev, u8 channel)
+void mt76x0_phy_set_txpower(struct mt76x02_dev *dev)
{
- static const int mt76x0_tx_pwr_ch_list[] = {
- 1,2,3,4,5,6,7,8,9,10,11,12,13,14,
- 36,38,40,44,46,48,52,54,56,60,62,64,
- 100,102,104,108,110,112,116,118,120,124,126,128,132,134,136,140,
- 149,151,153,157,159,161,165,167,169,171,173,
- 42,58,106,122,155
- };
- int i;
- u32 val;
+ struct mt76_rate_power *t = &dev->mt76.rate_power;
+ u8 info[2];
- for (i = 0; i < ARRAY_SIZE(mt76x0_tx_pwr_ch_list); i++)
- if (mt76x0_tx_pwr_ch_list[i] == channel)
- break;
+ mt76x0_get_power_info(dev, info);
+ mt76x0_get_tx_power_per_rate(dev);
- if (WARN_ON(i == ARRAY_SIZE(mt76x0_tx_pwr_ch_list)))
- return;
+ mt76x02_add_rate_power_offset(t, info[0]);
+ mt76x02_limit_rate_power(t, dev->mt76.txpower_conf);
+ dev->mt76.txpower_cur = mt76x02_get_max_rate_power(t);
+ mt76x02_add_rate_power_offset(t, -info[0]);
- val = mt76_rr(dev, MT_TX_ALC_CFG_0);
- val &= ~0x3f3f;
- val |= dev->ee->tx_pwr_per_chan[i];
- val |= 0x2f2f << 16;
- mt76_wr(dev, MT_TX_ALC_CFG_0, val);
+ mt76x02_phy_set_txpower(dev, info[0], info[1]);
}
-static int
-__mt76x0_phy_set_channel(struct mt76x0_dev *dev,
- struct cfg80211_chan_def *chandef)
+void mt76x0_phy_calibrate(struct mt76x02_dev *dev, bool power_on)
+{
+ struct ieee80211_channel *chan = dev->mt76.chandef.chan;
+ u32 val, tx_alc, reg_val;
+
+ if (power_on) {
+ mt76x02_mcu_calibrate(dev, MCU_CAL_R, 0, false);
+ mt76x02_mcu_calibrate(dev, MCU_CAL_VCO, chan->hw_value,
+ false);
+ usleep_range(10, 20);
+ /* XXX: tssi */
+ }
+
+ tx_alc = mt76_rr(dev, MT_TX_ALC_CFG_0);
+ mt76_wr(dev, MT_TX_ALC_CFG_0, 0);
+ usleep_range(500, 700);
+
+ reg_val = mt76_rr(dev, MT_BBP(IBI, 9));
+ mt76_wr(dev, MT_BBP(IBI, 9), 0xffffff7e);
+
+ if (chan->band == NL80211_BAND_5GHZ) {
+ if (chan->hw_value < 100)
+ val = 0x701;
+ else if (chan->hw_value < 140)
+ val = 0x801;
+ else
+ val = 0x901;
+ } else {
+ val = 0x600;
+ }
+
+ mt76x02_mcu_calibrate(dev, MCU_CAL_FULL, val, false);
+ msleep(350);
+ mt76x02_mcu_calibrate(dev, MCU_CAL_LC, 1, false);
+ usleep_range(15000, 20000);
+
+ mt76_wr(dev, MT_BBP(IBI, 9), reg_val);
+ mt76_wr(dev, MT_TX_ALC_CFG_0, tx_alc);
+ mt76x02_mcu_calibrate(dev, MCU_CAL_RXDCOC, 1, false);
+}
+EXPORT_SYMBOL_GPL(mt76x0_phy_calibrate);
+
+int mt76x0_phy_set_channel(struct mt76x02_dev *dev,
+ struct cfg80211_chan_def *chandef)
{
u32 ext_cca_chan[4] = {
[0] = FIELD_PREP(MT_EXT_CCA_CFG_CCA0, 0) |
@@ -706,6 +659,7 @@ __mt76x0_phy_set_channel(struct mt76x0_dev *dev,
freq1 = chandef->center_freq1;
channel = chandef->chan->hw_value;
rf_bw_band = (channel <= 14) ? RF_G_BAND : RF_A_BAND;
+ dev->mt76.chandef = *chandef;
switch (chandef->width) {
case NL80211_CHAN_WIDTH_40:
@@ -729,9 +683,20 @@ __mt76x0_phy_set_channel(struct mt76x0_dev *dev,
break;
}
- mt76x0_bbp_set_bw(dev, chandef->width);
- mt76x0_bbp_set_ctrlch(dev, chandef->width, ch_group_index);
- mt76x0_mac_set_ctrlch(dev, ch_group_index & 1);
+ if (mt76_is_usb(dev)) {
+ mt76x0_bbp_set_bw(dev, chandef->width);
+ } else {
+ if (chandef->width == NL80211_CHAN_WIDTH_80 ||
+ chandef->width == NL80211_CHAN_WIDTH_40)
+ val = 0x201;
+ else
+ val = 0x601;
+ mt76_wr(dev, MT_TX_SW_CFG0, val);
+ }
+ mt76x02_phy_set_bw(dev, chandef->width, ch_group_index);
+ mt76x02_phy_set_band(dev, chandef->chan->band,
+ ch_group_index & 1);
+ mt76x0_ant_select(dev);
mt76_rmw(dev, MT_EXT_CCA_CFG,
(MT_EXT_CCA_CFG_CCA0 |
@@ -752,40 +717,37 @@ __mt76x0_phy_set_channel(struct mt76x0_dev *dev,
val &= ~0x20;
mt76_wr(dev, MT_BBP(CORE, 1), val);
- mt76x0_phy_set_chan_bbp_params(dev, channel, rf_bw_band);
-
- /* Vendor driver don't do it */
- /* mt76x0_phy_set_tx_power(dev, channel, rf_bw_band); */
+ mt76x0_read_rx_gain(dev);
+ mt76x0_phy_set_chan_bbp_params(dev, rf_bw_band);
+ mt76x02_init_agc_gain(dev);
- if (scan)
+ if (mt76_is_usb(dev)) {
mt76x0_vco_cal(dev, channel);
+ } else {
+ /* enable vco */
+ rf_set(dev, MT_RF(0, 4), BIT(7));
+ }
- mt76x0_mcu_calibrate(dev, MCU_CAL_RXDCOC, 1);
- mt76x0_phy_set_chan_pwr(dev, channel);
+ if (scan)
+ return 0;
- dev->mt76.chandef = *chandef;
- return 0;
-}
+ if (mt76_is_mmio(dev))
+ mt76x0_phy_calibrate(dev, false);
+ mt76x0_phy_set_txpower(dev);
-int mt76x0_phy_set_channel(struct mt76x0_dev *dev,
- struct cfg80211_chan_def *chandef)
-{
- int ret;
-
- mutex_lock(&dev->hw_atomic_mutex);
- ret = __mt76x0_phy_set_channel(dev, chandef);
- mutex_unlock(&dev->hw_atomic_mutex);
+ ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work,
+ MT_CALIBRATE_INTERVAL);
- return ret;
+ return 0;
}
-void mt76x0_phy_recalibrate_after_assoc(struct mt76x0_dev *dev)
+void mt76x0_phy_recalibrate_after_assoc(struct mt76x02_dev *dev)
{
u32 tx_alc, reg_val;
u8 channel = dev->mt76.chandef.chan->hw_value;
int is_5ghz = (dev->mt76.chandef.chan->band == NL80211_BAND_5GHZ) ? 1 : 0;
- mt76x0_mcu_calibrate(dev, MCU_CAL_R, 0);
+ mt76x02_mcu_calibrate(dev, MCU_CAL_R, 0, false);
mt76x0_vco_cal(dev, channel);
@@ -793,148 +755,119 @@ void mt76x0_phy_recalibrate_after_assoc(struct mt76x0_dev *dev)
mt76_wr(dev, MT_TX_ALC_CFG_0, 0);
usleep_range(500, 700);
- reg_val = mt76_rr(dev, 0x2124);
- reg_val &= 0xffffff7e;
- mt76_wr(dev, 0x2124, reg_val);
+ reg_val = mt76_rr(dev, MT_BBP(IBI, 9));
+ mt76_wr(dev, MT_BBP(IBI, 9), 0xffffff7e);
- mt76x0_mcu_calibrate(dev, MCU_CAL_RXDCOC, 0);
+ mt76x02_mcu_calibrate(dev, MCU_CAL_RXDCOC, 0, false);
- mt76x0_mcu_calibrate(dev, MCU_CAL_LC, is_5ghz);
- mt76x0_mcu_calibrate(dev, MCU_CAL_LOFT, is_5ghz);
- mt76x0_mcu_calibrate(dev, MCU_CAL_TXIQ, is_5ghz);
- mt76x0_mcu_calibrate(dev, MCU_CAL_TX_GROUP_DELAY, is_5ghz);
- mt76x0_mcu_calibrate(dev, MCU_CAL_RXIQ, is_5ghz);
- mt76x0_mcu_calibrate(dev, MCU_CAL_RX_GROUP_DELAY, is_5ghz);
+ mt76x02_mcu_calibrate(dev, MCU_CAL_LC, is_5ghz, false);
+ mt76x02_mcu_calibrate(dev, MCU_CAL_LOFT, is_5ghz, false);
+ mt76x02_mcu_calibrate(dev, MCU_CAL_TXIQ, is_5ghz, false);
+ mt76x02_mcu_calibrate(dev, MCU_CAL_TX_GROUP_DELAY, is_5ghz, false);
+ mt76x02_mcu_calibrate(dev, MCU_CAL_RXIQ, is_5ghz, false);
+ mt76x02_mcu_calibrate(dev, MCU_CAL_RX_GROUP_DELAY, is_5ghz, false);
- mt76_wr(dev, 0x2124, reg_val);
+ mt76_wr(dev, MT_BBP(IBI, 9), reg_val);
mt76_wr(dev, MT_TX_ALC_CFG_0, tx_alc);
msleep(100);
- mt76x0_mcu_calibrate(dev, MCU_CAL_RXDCOC, 1);
+ mt76x02_mcu_calibrate(dev, MCU_CAL_RXDCOC, 1, false);
}
-void mt76x0_agc_save(struct mt76x0_dev *dev)
-{
- /* Only one RX path */
- dev->agc_save = FIELD_GET(MT_BBP_AGC_GAIN, mt76_rr(dev, MT_BBP(AGC, 8)));
-}
-
-void mt76x0_agc_restore(struct mt76x0_dev *dev)
-{
- mt76_rmw_field(dev, MT_BBP(AGC, 8), MT_BBP_AGC_GAIN, dev->agc_save);
-}
-
-static void mt76x0_temp_sensor(struct mt76x0_dev *dev)
+static void mt76x0_temp_sensor(struct mt76x02_dev *dev)
{
u8 rf_b7_73, rf_b0_66, rf_b0_67;
- int cycle, temp;
- u32 val;
- s32 sval;
+ s8 val;
rf_b7_73 = rf_rr(dev, MT_RF(7, 73));
rf_b0_66 = rf_rr(dev, MT_RF(0, 66));
- rf_b0_67 = rf_rr(dev, MT_RF(0, 73));
+ rf_b0_67 = rf_rr(dev, MT_RF(0, 67));
rf_wr(dev, MT_RF(7, 73), 0x02);
rf_wr(dev, MT_RF(0, 66), 0x23);
- rf_wr(dev, MT_RF(0, 73), 0x01);
+ rf_wr(dev, MT_RF(0, 67), 0x01);
mt76_wr(dev, MT_BBP(CORE, 34), 0x00080055);
- for (cycle = 0; cycle < 2000; cycle++) {
- val = mt76_rr(dev, MT_BBP(CORE, 34));
- if (!(val & 0x10))
- break;
- udelay(3);
- }
-
- if (cycle >= 2000) {
- val &= 0x10;
- mt76_wr(dev, MT_BBP(CORE, 34), val);
+ if (!mt76_poll(dev, MT_BBP(CORE, 34), BIT(4), 0, 2000)) {
+ mt76_clear(dev, MT_BBP(CORE, 34), BIT(4));
goto done;
}
- sval = mt76_rr(dev, MT_BBP(CORE, 35)) & 0xff;
- if (!(sval & 0x80))
- sval &= 0x7f; /* Positive */
- else
- sval |= 0xffffff00; /* Negative */
+ val = mt76_rr(dev, MT_BBP(CORE, 35));
+ val = (35 * (val - dev->cal.rx.temp_offset)) / 10 + 25;
- temp = (35 * (sval - dev->ee->temp_off))/ 10 + 25;
+ if (abs(val - dev->cal.temp_vco) > 20) {
+ mt76x02_mcu_calibrate(dev, MCU_CAL_VCO,
+ dev->mt76.chandef.chan->hw_value,
+ false);
+ dev->cal.temp_vco = val;
+ }
+ if (abs(val - dev->cal.temp) > 30) {
+ mt76x0_phy_calibrate(dev, false);
+ dev->cal.temp = val;
+ }
done:
rf_wr(dev, MT_RF(7, 73), rf_b7_73);
rf_wr(dev, MT_RF(0, 66), rf_b0_66);
- rf_wr(dev, MT_RF(0, 73), rf_b0_67);
+ rf_wr(dev, MT_RF(0, 67), rf_b0_67);
}
-static void mt76x0_dynamic_vga_tuning(struct mt76x0_dev *dev)
+static void mt76x0_phy_set_gain_val(struct mt76x02_dev *dev)
{
- u32 val, init_vga;
-
- init_vga = (dev->mt76.chandef.chan->band == NL80211_BAND_5GHZ) ? 0x54 : 0x4E;
- if (dev->avg_rssi > -60)
- init_vga -= 0x20;
- else if (dev->avg_rssi > -70)
- init_vga -= 0x10;
-
- val = mt76_rr(dev, MT_BBP(AGC, 8));
- val &= 0xFFFF80FF;
- val |= init_vga << 8;
- mt76_wr(dev, MT_BBP(AGC,8), val);
+ u8 gain = dev->cal.agc_gain_cur[0] - dev->cal.agc_gain_adjust;
+ u32 val = 0x122c << 16 | 0xf2;
+
+ mt76_wr(dev, MT_BBP(AGC, 8),
+ val | FIELD_PREP(MT_BBP_AGC_GAIN, gain));
}
-static void mt76x0_phy_calibrate(struct work_struct *work)
+static void
+mt76x0_phy_update_channel_gain(struct mt76x02_dev *dev)
{
- struct mt76x0_dev *dev = container_of(work, struct mt76x0_dev,
- cal_work.work);
+ bool gain_change;
+ u8 gain_delta;
+ int low_gain;
- mt76x0_dynamic_vga_tuning(dev);
- mt76x0_temp_sensor(dev);
+ dev->cal.avg_rssi_all = mt76x02_phy_get_min_avg_rssi(dev);
- ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work,
- MT_CALIBRATE_INTERVAL);
-}
+ low_gain = (dev->cal.avg_rssi_all > mt76x02_get_rssi_gain_thresh(dev)) +
+ (dev->cal.avg_rssi_all > mt76x02_get_low_rssi_gain_thresh(dev));
-void mt76x0_phy_con_cal_onoff(struct mt76x0_dev *dev,
- struct ieee80211_bss_conf *info)
-{
- /* Start/stop collecting beacon data */
- spin_lock_bh(&dev->con_mon_lock);
- ether_addr_copy(dev->ap_bssid, info->bssid);
- dev->avg_rssi = 0;
- dev->bcn_freq_off = MT_FREQ_OFFSET_INVALID;
- spin_unlock_bh(&dev->con_mon_lock);
-}
+ gain_change = (dev->cal.low_gain & 2) ^ (low_gain & 2);
+ dev->cal.low_gain = low_gain;
-static void
-mt76x0_set_rx_chains(struct mt76x0_dev *dev)
-{
- u32 val;
-
- val = mt76_rr(dev, MT_BBP(AGC, 0));
- val &= ~(BIT(3) | BIT(4));
+ if (!gain_change) {
+ if (mt76x02_phy_adjust_vga_gain(dev))
+ mt76x0_phy_set_gain_val(dev);
+ return;
+ }
- if (dev->chainmask & BIT(1))
- val |= BIT(3);
+ dev->cal.agc_gain_adjust = (low_gain == 2) ? 0 : 10;
+ gain_delta = (low_gain == 2) ? 10 : 0;
- mt76_wr(dev, MT_BBP(AGC, 0), val);
+ dev->cal.agc_gain_cur[0] = dev->cal.agc_gain_init[0] - gain_delta;
+ mt76x0_phy_set_gain_val(dev);
- mb();
- val = mt76_rr(dev, MT_BBP(AGC, 0));
+ /* clear false CCA counters */
+ mt76_rr(dev, MT_RX_STAT_1);
}
-static void
-mt76x0_set_tx_dac(struct mt76x0_dev *dev)
+static void mt76x0_phy_calibration_work(struct work_struct *work)
{
- if (dev->chainmask & BIT(1))
- mt76_set(dev, MT_BBP(TXBE, 5), 3);
- else
- mt76_clear(dev, MT_BBP(TXBE, 5), 3);
+ struct mt76x02_dev *dev = container_of(work, struct mt76x02_dev,
+ cal_work.work);
+
+ mt76x0_phy_update_channel_gain(dev);
+ if (!mt76x0_tssi_enabled(dev))
+ mt76x0_temp_sensor(dev);
+
+ ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work,
+ MT_CALIBRATE_INTERVAL);
}
-static void
-mt76x0_rf_init(struct mt76x0_dev *dev)
+static void mt76x0_rf_init(struct mt76x02_dev *dev)
{
int i;
u8 val;
@@ -966,7 +899,8 @@ mt76x0_rf_init(struct mt76x0_dev *dev)
E1: B0.R22<6:0>: xo_cxo<6:0>
E2: B0.R21<0>: xo_cxo<0>, B0.R22<7:0>: xo_cxo<8:1>
*/
- rf_wr(dev, MT_RF(0, 22), min_t(u8, dev->ee->rf_freq_off, 0xBF));
+ rf_wr(dev, MT_RF(0, 22),
+ min_t(u8, dev->cal.rx.freq_offset, 0xbf));
val = rf_rr(dev, MT_RF(0, 22));
/*
@@ -986,23 +920,11 @@ mt76x0_rf_init(struct mt76x0_dev *dev)
rf_set(dev, MT_RF(0, 4), 0x80);
}
-static void mt76x0_ant_select(struct mt76x0_dev *dev)
+void mt76x0_phy_init(struct mt76x02_dev *dev)
{
- /* Single antenna mode. */
- mt76_rmw(dev, MT_WLAN_FUN_CTRL, BIT(5), BIT(6));
- mt76_clear(dev, MT_CMB_CTRL, BIT(14) | BIT(12));
- mt76_clear(dev, MT_COEXCFG0, BIT(2));
- mt76_rmw(dev, MT_COEXCFG3, BIT(5) | BIT(4) | BIT(3) | BIT(2), BIT(1));
-}
-
-void mt76x0_phy_init(struct mt76x0_dev *dev)
-{
- INIT_DELAYED_WORK(&dev->cal_work, mt76x0_phy_calibrate);
-
- mt76x0_ant_select(dev);
+ INIT_DELAYED_WORK(&dev->cal_work, mt76x0_phy_calibration_work);
mt76x0_rf_init(dev);
-
- mt76x0_set_rx_chains(dev);
- mt76x0_set_tx_dac(dev);
+ mt76x02_phy_set_rxpath(dev);
+ mt76x02_phy_set_txdac(dev);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/regs.h b/drivers/net/wireless/mediatek/mt76/mt76x0/regs.h
deleted file mode 100644
index 16bed4aaa242..000000000000
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/regs.h
+++ /dev/null
@@ -1,651 +0,0 @@
-/*
- * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
- * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
- * Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#ifndef __MT76_REGS_H
-#define __MT76_REGS_H
-
-#include <linux/bitops.h>
-
-#define MT_ASIC_VERSION 0x0000
-
-#define MT76XX_REV_E3 0x22
-#define MT76XX_REV_E4 0x33
-
-#define MT_CMB_CTRL 0x0020
-#define MT_CMB_CTRL_XTAL_RDY BIT(22)
-#define MT_CMB_CTRL_PLL_LD BIT(23)
-
-#define MT_EFUSE_CTRL 0x0024
-#define MT_EFUSE_CTRL_AOUT GENMASK(5, 0)
-#define MT_EFUSE_CTRL_MODE GENMASK(7, 6)
-#define MT_EFUSE_CTRL_LDO_OFF_TIME GENMASK(13, 8)
-#define MT_EFUSE_CTRL_LDO_ON_TIME GENMASK(15, 14)
-#define MT_EFUSE_CTRL_AIN GENMASK(25, 16)
-#define MT_EFUSE_CTRL_KICK BIT(30)
-#define MT_EFUSE_CTRL_SEL BIT(31)
-
-#define MT_EFUSE_DATA_BASE 0x0028
-#define MT_EFUSE_DATA(_n) (MT_EFUSE_DATA_BASE + ((_n) << 2))
-
-#define MT_COEXCFG0 0x0040
-#define MT_COEXCFG0_COEX_EN BIT(0)
-
-#define MT_COEXCFG3 0x004c
-
-#define MT_LDO_CTRL_0 0x006c
-#define MT_LDO_CTRL_1 0x0070
-
-#define MT_WLAN_FUN_CTRL 0x0080
-#define MT_WLAN_FUN_CTRL_WLAN_EN BIT(0)
-#define MT_WLAN_FUN_CTRL_WLAN_CLK_EN BIT(1)
-#define MT_WLAN_FUN_CTRL_WLAN_RESET_RF BIT(2)
-
-#define MT_WLAN_FUN_CTRL_WLAN_RESET BIT(3) /* MT76x0 */
-#define MT_WLAN_FUN_CTRL_CSR_F20M_CKEN BIT(3) /* MT76x2 */
-
-#define MT_WLAN_FUN_CTRL_PCIE_CLK_REQ BIT(4)
-#define MT_WLAN_FUN_CTRL_FRC_WL_ANT_SEL BIT(5)
-#define MT_WLAN_FUN_CTRL_INV_ANT_SEL BIT(6)
-#define MT_WLAN_FUN_CTRL_WAKE_HOST BIT(7)
-
-#define MT_WLAN_FUN_CTRL_THERM_RST BIT(8) /* MT76x2 */
-#define MT_WLAN_FUN_CTRL_THERM_CKEN BIT(9) /* MT76x2 */
-
-#define MT_WLAN_FUN_CTRL_GPIO_IN GENMASK(15, 8) /* MT76x0 */
-#define MT_WLAN_FUN_CTRL_GPIO_OUT GENMASK(23, 16) /* MT76x0 */
-#define MT_WLAN_FUN_CTRL_GPIO_OUT_EN GENMASK(31, 24) /* MT76x0 */
-
-#define MT_XO_CTRL0 0x0100
-#define MT_XO_CTRL1 0x0104
-#define MT_XO_CTRL2 0x0108
-#define MT_XO_CTRL3 0x010c
-#define MT_XO_CTRL4 0x0110
-
-#define MT_XO_CTRL5 0x0114
-#define MT_XO_CTRL5_C2_VAL GENMASK(14, 8)
-
-#define MT_XO_CTRL6 0x0118
-#define MT_XO_CTRL6_C2_CTRL GENMASK(14, 8)
-
-#define MT_XO_CTRL7 0x011c
-
-#define MT_IOCFG_6 0x0124
-#define MT_WLAN_MTC_CTRL 0x10148
-#define MT_WLAN_MTC_CTRL_MTCMOS_PWR_UP BIT(0)
-#define MT_WLAN_MTC_CTRL_PWR_ACK BIT(12)
-#define MT_WLAN_MTC_CTRL_PWR_ACK_S BIT(13)
-#define MT_WLAN_MTC_CTRL_BBP_MEM_PD GENMASK(19, 16)
-#define MT_WLAN_MTC_CTRL_PBF_MEM_PD BIT(20)
-#define MT_WLAN_MTC_CTRL_FCE_MEM_PD BIT(21)
-#define MT_WLAN_MTC_CTRL_TSO_MEM_PD BIT(22)
-#define MT_WLAN_MTC_CTRL_BBP_MEM_RB BIT(24)
-#define MT_WLAN_MTC_CTRL_PBF_MEM_RB BIT(25)
-#define MT_WLAN_MTC_CTRL_FCE_MEM_RB BIT(26)
-#define MT_WLAN_MTC_CTRL_TSO_MEM_RB BIT(27)
-#define MT_WLAN_MTC_CTRL_STATE_UP BIT(28)
-
-#define MT_INT_SOURCE_CSR 0x0200
-#define MT_INT_MASK_CSR 0x0204
-
-#define MT_INT_RX_DONE(_n) BIT(_n)
-#define MT_INT_RX_DONE_ALL GENMASK(1, 0)
-#define MT_INT_TX_DONE_ALL GENMASK(13, 4)
-#define MT_INT_TX_DONE(_n) BIT(_n + 4)
-#define MT_INT_RX_COHERENT BIT(16)
-#define MT_INT_TX_COHERENT BIT(17)
-#define MT_INT_ANY_COHERENT BIT(18)
-#define MT_INT_MCU_CMD BIT(19)
-#define MT_INT_TBTT BIT(20)
-#define MT_INT_PRE_TBTT BIT(21)
-#define MT_INT_TX_STAT BIT(22)
-#define MT_INT_AUTO_WAKEUP BIT(23)
-#define MT_INT_GPTIMER BIT(24)
-#define MT_INT_RXDELAYINT BIT(26)
-#define MT_INT_TXDELAYINT BIT(27)
-
-#define MT_WPDMA_GLO_CFG 0x0208
-#define MT_WPDMA_GLO_CFG_TX_DMA_EN BIT(0)
-#define MT_WPDMA_GLO_CFG_TX_DMA_BUSY BIT(1)
-#define MT_WPDMA_GLO_CFG_RX_DMA_EN BIT(2)
-#define MT_WPDMA_GLO_CFG_RX_DMA_BUSY BIT(3)
-#define MT_WPDMA_GLO_CFG_DMA_BURST_SIZE GENMASK(5, 4)
-#define MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE BIT(6)
-#define MT_WPDMA_GLO_CFG_BIG_ENDIAN BIT(7)
-#define MT_WPDMA_GLO_CFG_HDR_SEG_LEN GENMASK(15, 8)
-#define MT_WPDMA_GLO_CFG_CLK_GATE_DIS BIT(30)
-#define MT_WPDMA_GLO_CFG_RX_2B_OFFSET BIT(31)
-
-#define MT_WPDMA_RST_IDX 0x020c
-
-#define MT_WPDMA_DELAY_INT_CFG 0x0210
-
-#define MT_WMM_AIFSN 0x0214
-#define MT_WMM_AIFSN_MASK GENMASK(3, 0)
-#define MT_WMM_AIFSN_SHIFT(_n) ((_n) * 4)
-
-#define MT_WMM_CWMIN 0x0218
-#define MT_WMM_CWMIN_MASK GENMASK(3, 0)
-#define MT_WMM_CWMIN_SHIFT(_n) ((_n) * 4)
-
-#define MT_WMM_CWMAX 0x021c
-#define MT_WMM_CWMAX_MASK GENMASK(3, 0)
-#define MT_WMM_CWMAX_SHIFT(_n) ((_n) * 4)
-
-#define MT_WMM_TXOP_BASE 0x0220
-#define MT_WMM_TXOP(_n) (MT_WMM_TXOP_BASE + (((_n) / 2) << 2))
-#define MT_WMM_TXOP_SHIFT(_n) ((_n & 1) * 16)
-#define MT_WMM_TXOP_MASK GENMASK(15, 0)
-
-#define MT_WMM_CTRL 0x0230 /* MT76x0 */
-
-#define MT_FCE_DMA_ADDR 0x0230
-#define MT_FCE_DMA_LEN 0x0234
-
-#define MT_USB_DMA_CFG 0x238
-#define MT_USB_DMA_CFG_RX_BULK_AGG_TOUT GENMASK(7, 0)
-#define MT_USB_DMA_CFG_RX_BULK_AGG_LMT GENMASK(15, 8)
-#define MT_USB_DMA_CFG_TX_WL_DROP BIT(16)
-#define MT_USB_DMA_CFG_WAKEUP_EN BIT(17)
-#define MT_USB_DMA_CFG_RX_DROP_OR_PADDING BIT(18)
-#define MT_USB_DMA_CFG_TX_CLR BIT(19)
-#define MT_USB_DMA_CFG_WL_LPK_EN BIT(20)
-#define MT_USB_DMA_CFG_RX_BULK_AGG_EN BIT(21)
-#define MT_USB_DMA_CFG_RX_BULK_EN BIT(22)
-#define MT_USB_DMA_CFG_TX_BULK_EN BIT(23)
-#define MT_USB_DMA_CFG_EP_OUT_VALID GENMASK(29, 24)
-#define MT_USB_DMA_CFG_RX_BUSY BIT(30)
-#define MT_USB_DMA_CFG_TX_BUSY BIT(31)
-#if 0
-#define MT_USB_DMA_CFG_TX_CLR BIT(19)
-#define MT_USB_DMA_CFG_TXOP_HALT BIT(20)
-#define MT_USB_DMA_CFG_RX_BULK_AGG_EN BIT(21)
-#define MT_USB_DMA_CFG_RX_BULK_EN BIT(22)
-#define MT_USB_DMA_CFG_TX_BULK_EN BIT(23)
-#define MT_USB_DMA_CFG_UDMA_RX_WL_DROP BIT(25)
-#endif
-
-#define MT_TSO_CTRL 0x0250
-#define MT_HEADER_TRANS_CTRL_REG 0x0260
-
-#define MT_US_CYC_CFG 0x02a4
-#define MT_US_CYC_CNT GENMASK(7, 0)
-
-#define MT_TX_RING_BASE 0x0300
-#define MT_RX_RING_BASE 0x03c0
-#define MT_RING_SIZE 0x10
-
-#define MT_TX_HW_QUEUE_MCU 8
-#define MT_TX_HW_QUEUE_MGMT 9
-
-#define MT_PBF_SYS_CTRL 0x0400
-#define MT_PBF_SYS_CTRL_MCU_RESET BIT(0)
-#define MT_PBF_SYS_CTRL_DMA_RESET BIT(1)
-#define MT_PBF_SYS_CTRL_MAC_RESET BIT(2)
-#define MT_PBF_SYS_CTRL_PBF_RESET BIT(3)
-#define MT_PBF_SYS_CTRL_ASY_RESET BIT(4)
-
-#define MT_PBF_CFG 0x0404
-#define MT_PBF_CFG_TX0Q_EN BIT(0)
-#define MT_PBF_CFG_TX1Q_EN BIT(1)
-#define MT_PBF_CFG_TX2Q_EN BIT(2)
-#define MT_PBF_CFG_TX3Q_EN BIT(3)
-#define MT_PBF_CFG_RX0Q_EN BIT(4)
-#define MT_PBF_CFG_RX_DROP_EN BIT(8)
-
-#define MT_PBF_TX_MAX_PCNT 0x0408
-#define MT_PBF_RX_MAX_PCNT 0x040c
-
-#define MT_BCN_OFFSET_BASE 0x041c
-#define MT_BCN_OFFSET(_n) (MT_BCN_OFFSET_BASE + ((_n) << 2))
-
-#define MT_RXQ_STA 0x0430
-#define MT_TXQ_STA 0x0434
-#define MT_RF_CSR_CFG 0x0500
-#define MT_RF_CSR_CFG_DATA GENMASK(7, 0)
-#define MT_RF_CSR_CFG_REG_ID GENMASK(13, 8)
-#define MT_RF_CSR_CFG_REG_BANK GENMASK(17, 14)
-#define MT_RF_CSR_CFG_WR BIT(30)
-#define MT_RF_CSR_CFG_KICK BIT(31)
-
-#define MT_RF_BYPASS_0 0x0504
-#define MT_RF_BYPASS_1 0x0508
-#define MT_RF_SETTING_0 0x050c
-
-#define MT_RF_MISC 0x0518
-#define MT_RF_DATA_WRITE 0x0524
-
-#define MT_RF_CTRL 0x0528
-#define MT_RF_CTRL_ADDR GENMASK(11, 0)
-#define MT_RF_CTRL_WRITE BIT(12)
-#define MT_RF_CTRL_BUSY BIT(13)
-#define MT_RF_CTRL_IDX BIT(16)
-
-#define MT_RF_DATA_READ 0x052c
-
-#define MT_COM_REG0 0x0730
-#define MT_COM_REG1 0x0734
-#define MT_COM_REG2 0x0738
-#define MT_COM_REG3 0x073C
-
-#define MT_FCE_PSE_CTRL 0x0800
-#define MT_FCE_PARAMETERS 0x0804
-#define MT_FCE_CSO 0x0808
-
-#define MT_FCE_L2_STUFF 0x080c
-#define MT_FCE_L2_STUFF_HT_L2_EN BIT(0)
-#define MT_FCE_L2_STUFF_QOS_L2_EN BIT(1)
-#define MT_FCE_L2_STUFF_RX_STUFF_EN BIT(2)
-#define MT_FCE_L2_STUFF_TX_STUFF_EN BIT(3)
-#define MT_FCE_L2_STUFF_WR_MPDU_LEN_EN BIT(4)
-#define MT_FCE_L2_STUFF_MVINV_BSWAP BIT(5)
-#define MT_FCE_L2_STUFF_TS_CMD_QSEL_EN GENMASK(15, 8)
-#define MT_FCE_L2_STUFF_TS_LEN_EN GENMASK(23, 16)
-#define MT_FCE_L2_STUFF_OTHER_PORT GENMASK(25, 24)
-
-#define MT_FCE_WLAN_FLOW_CONTROL1 0x0824
-
-#define MT_TX_CPU_FROM_FCE_BASE_PTR 0x09a0
-#define MT_TX_CPU_FROM_FCE_MAX_COUNT 0x09a4
-#define MT_TX_CPU_FROM_FCE_CPU_DESC_IDX 0x09a8
-
-#define MT_FCE_PDMA_GLOBAL_CONF 0x09c4
-
-#define MT_PAUSE_ENABLE_CONTROL1 0x0a38
-
-#define MT_FCE_SKIP_FS 0x0a6c
-
-#define MT_MAC_CSR0 0x1000
-#define MT_MAC_SYS_CTRL 0x1004
-#define MT_MAC_SYS_CTRL_RESET_CSR BIT(0)
-#define MT_MAC_SYS_CTRL_RESET_BBP BIT(1)
-#define MT_MAC_SYS_CTRL_ENABLE_TX BIT(2)
-#define MT_MAC_SYS_CTRL_ENABLE_RX BIT(3)
-
-#define MT_MAC_ADDR_DW0 0x1008
-#define MT_MAC_ADDR_DW1 0x100c
-#define MT_MAC_ADDR_DW1_U2ME_MASK GENMASK(23, 16)
-
-#define MT_MAC_BSSID_DW0 0x1010
-#define MT_MAC_BSSID_DW1 0x1014
-#define MT_MAC_BSSID_DW1_ADDR GENMASK(15, 0)
-#define MT_MAC_BSSID_DW1_MBSS_MODE GENMASK(17, 16)
-#define MT_MAC_BSSID_DW1_MBEACON_N GENMASK(20, 18)
-#define MT_MAC_BSSID_DW1_MBSS_LOCAL_BIT BIT(21)
-#define MT_MAC_BSSID_DW1_MBSS_MODE_B2 BIT(22)
-#define MT_MAC_BSSID_DW1_MBEACON_N_B3 BIT(23)
-#define MT_MAC_BSSID_DW1_MBSS_IDX_BYTE GENMASK(26, 24)
-
-#define MT_MAX_LEN_CFG 0x1018
-#define MT_MAX_LEN_CFG_AMPDU GENMASK(13, 12)
-
-#define MT_LED_CFG 0x102c
-
-#define MT_AMPDU_MAX_LEN_20M1S 0x1030
-#define MT_AMPDU_MAX_LEN_20M2S 0x1034
-#define MT_AMPDU_MAX_LEN_40M1S 0x1038
-#define MT_AMPDU_MAX_LEN_40M2S 0x103c
-#define MT_AMPDU_MAX_LEN 0x1040
-
-#define MT_WCID_DROP_BASE 0x106c
-#define MT_WCID_DROP(_n) (MT_WCID_DROP_BASE + ((_n) >> 5) * 4)
-#define MT_WCID_DROP_MASK(_n) BIT((_n) % 32)
-
-#define MT_BCN_BYPASS_MASK 0x108c
-
-#define MT_MAC_APC_BSSID_BASE 0x1090
-#define MT_MAC_APC_BSSID_L(_n) (MT_MAC_APC_BSSID_BASE + ((_n) * 8))
-#define MT_MAC_APC_BSSID_H(_n) (MT_MAC_APC_BSSID_BASE + ((_n) * 8 + 4))
-#define MT_MAC_APC_BSSID_H_ADDR GENMASK(15, 0)
-#define MT_MAC_APC_BSSID0_H_EN BIT(16)
-
-#define MT_XIFS_TIME_CFG 0x1100
-#define MT_XIFS_TIME_CFG_CCK_SIFS GENMASK(7, 0)
-#define MT_XIFS_TIME_CFG_OFDM_SIFS GENMASK(15, 8)
-#define MT_XIFS_TIME_CFG_OFDM_XIFS GENMASK(19, 16)
-#define MT_XIFS_TIME_CFG_EIFS GENMASK(28, 20)
-#define MT_XIFS_TIME_CFG_BB_RXEND_EN BIT(29)
-
-#define MT_BKOFF_SLOT_CFG 0x1104
-#define MT_BKOFF_SLOT_CFG_SLOTTIME GENMASK(7, 0)
-#define MT_BKOFF_SLOT_CFG_CC_DELAY GENMASK(11, 8)
-
-#define MT_BEACON_TIME_CFG 0x1114
-#define MT_BEACON_TIME_CFG_INTVAL GENMASK(15, 0)
-#define MT_BEACON_TIME_CFG_TIMER_EN BIT(16)
-#define MT_BEACON_TIME_CFG_SYNC_MODE GENMASK(18, 17)
-#define MT_BEACON_TIME_CFG_TBTT_EN BIT(19)
-#define MT_BEACON_TIME_CFG_BEACON_TX BIT(20)
-#define MT_BEACON_TIME_CFG_TSF_COMP GENMASK(31, 24)
-
-#define MT_TBTT_SYNC_CFG 0x1118
-#define MT_TBTT_TIMER_CFG 0x1124
-
-#define MT_INT_TIMER_CFG 0x1128
-#define MT_INT_TIMER_CFG_PRE_TBTT GENMASK(15, 0)
-#define MT_INT_TIMER_CFG_GP_TIMER GENMASK(31, 16)
-
-#define MT_INT_TIMER_EN 0x112c
-#define MT_INT_TIMER_EN_PRE_TBTT_EN BIT(0)
-#define MT_INT_TIMER_EN_GP_TIMER_EN BIT(1)
-
-#define MT_MAC_STATUS 0x1200
-#define MT_MAC_STATUS_TX BIT(0)
-#define MT_MAC_STATUS_RX BIT(1)
-
-#define MT_PWR_PIN_CFG 0x1204
-#define MT_AUX_CLK_CFG 0x120c
-
-#define MT_BB_PA_MODE_CFG0 0x1214
-#define MT_BB_PA_MODE_CFG1 0x1218
-#define MT_RF_PA_MODE_CFG0 0x121c
-#define MT_RF_PA_MODE_CFG1 0x1220
-
-#define MT_RF_PA_MODE_ADJ0 0x1228
-#define MT_RF_PA_MODE_ADJ1 0x122c
-
-#define MT_DACCLK_EN_DLY_CFG 0x1264
-
-#define MT_EDCA_CFG_BASE 0x1300
-#define MT_EDCA_CFG_AC(_n) (MT_EDCA_CFG_BASE + ((_n) << 2))
-#define MT_EDCA_CFG_TXOP GENMASK(7, 0)
-#define MT_EDCA_CFG_AIFSN GENMASK(11, 8)
-#define MT_EDCA_CFG_CWMIN GENMASK(15, 12)
-#define MT_EDCA_CFG_CWMAX GENMASK(19, 16)
-
-#define MT_TX_PWR_CFG_0 0x1314
-#define MT_TX_PWR_CFG_1 0x1318
-#define MT_TX_PWR_CFG_2 0x131c
-#define MT_TX_PWR_CFG_3 0x1320
-#define MT_TX_PWR_CFG_4 0x1324
-
-#define MT_TX_BAND_CFG 0x132c
-#define MT_TX_BAND_CFG_UPPER_40M BIT(0)
-#define MT_TX_BAND_CFG_5G BIT(1)
-#define MT_TX_BAND_CFG_2G BIT(2)
-
-#define MT_HT_FBK_TO_LEGACY 0x1384
-#define MT_TX_MPDU_ADJ_INT 0x1388
-
-#define MT_TX_PWR_CFG_7 0x13d4
-#define MT_TX_PWR_CFG_8 0x13d8
-#define MT_TX_PWR_CFG_9 0x13dc
-
-#define MT_TX_SW_CFG0 0x1330
-#define MT_TX_SW_CFG1 0x1334
-#define MT_TX_SW_CFG2 0x1338
-
-#define MT_TXOP_CTRL_CFG 0x1340
-#define MT_TXOP_TRUN_EN GENMASK(5, 0)
-#define MT_TXOP_EXT_CCA_DLY GENMASK(15, 8)
-#define MT_TXOP_CTRL
-
-#define MT_TX_RTS_CFG 0x1344
-#define MT_TX_RTS_CFG_RETRY_LIMIT GENMASK(7, 0)
-#define MT_TX_RTS_CFG_THRESH GENMASK(23, 8)
-#define MT_TX_RTS_FALLBACK BIT(24)
-
-#define MT_TX_TIMEOUT_CFG 0x1348
-#define MT_TX_RETRY_CFG 0x134c
-#define MT_TX_LINK_CFG 0x1350
-#define MT_HT_FBK_CFG0 0x1354
-#define MT_HT_FBK_CFG1 0x1358
-#define MT_LG_FBK_CFG0 0x135c
-#define MT_LG_FBK_CFG1 0x1360
-
-#define MT_CCK_PROT_CFG 0x1364
-#define MT_OFDM_PROT_CFG 0x1368
-#define MT_MM20_PROT_CFG 0x136c
-#define MT_MM40_PROT_CFG 0x1370
-#define MT_GF20_PROT_CFG 0x1374
-#define MT_GF40_PROT_CFG 0x1378
-
-#define MT_PROT_RATE GENMASK(15, 0)
-#define MT_PROT_CTRL_RTS_CTS BIT(16)
-#define MT_PROT_CTRL_CTS2SELF BIT(17)
-#define MT_PROT_NAV_SHORT BIT(18)
-#define MT_PROT_NAV_LONG BIT(19)
-#define MT_PROT_TXOP_ALLOW_CCK BIT(20)
-#define MT_PROT_TXOP_ALLOW_OFDM BIT(21)
-#define MT_PROT_TXOP_ALLOW_MM20 BIT(22)
-#define MT_PROT_TXOP_ALLOW_MM40 BIT(23)
-#define MT_PROT_TXOP_ALLOW_GF20 BIT(24)
-#define MT_PROT_TXOP_ALLOW_GF40 BIT(25)
-#define MT_PROT_RTS_THR_EN BIT(26)
-#define MT_PROT_RATE_CCK_11 0x0003
-#define MT_PROT_RATE_OFDM_6 0x4000
-#define MT_PROT_RATE_OFDM_24 0x4004
-#define MT_PROT_RATE_DUP_OFDM_24 0x4084
-#define MT_PROT_TXOP_ALLOW_ALL GENMASK(25, 20)
-#define MT_PROT_TXOP_ALLOW_BW20 (MT_PROT_TXOP_ALLOW_ALL & \
- ~MT_PROT_TXOP_ALLOW_MM40 & \
- ~MT_PROT_TXOP_ALLOW_GF40)
-
-#define MT_EXP_ACK_TIME 0x1380
-
-#define MT_TX_PWR_CFG_0_EXT 0x1390
-#define MT_TX_PWR_CFG_1_EXT 0x1394
-
-#define MT_TX_FBK_LIMIT 0x1398
-#define MT_TX_FBK_LIMIT_MPDU_FBK GENMASK(7, 0)
-#define MT_TX_FBK_LIMIT_AMPDU_FBK GENMASK(15, 8)
-#define MT_TX_FBK_LIMIT_MPDU_UP_CLEAR BIT(16)
-#define MT_TX_FBK_LIMIT_AMPDU_UP_CLEAR BIT(17)
-#define MT_TX_FBK_LIMIT_RATE_LUT BIT(18)
-
-#define MT_TX0_RF_GAIN_CORR 0x13a0
-#define MT_TX1_RF_GAIN_CORR 0x13a4
-#define MT_TX0_RF_GAIN_ATTEN 0x13a8
-
-#define MT_TX_ALC_CFG_0 0x13b0
-#define MT_TX_ALC_CFG_0_CH_INIT_0 GENMASK(5, 0)
-#define MT_TX_ALC_CFG_0_CH_INIT_1 GENMASK(13, 8)
-#define MT_TX_ALC_CFG_0_LIMIT_0 GENMASK(21, 16)
-#define MT_TX_ALC_CFG_0_LIMIT_1 GENMASK(29, 24)
-
-#define MT_TX_ALC_CFG_1 0x13b4
-#define MT_TX_ALC_CFG_1_TEMP_COMP GENMASK(5, 0)
-
-#define MT_TX_ALC_CFG_2 0x13a8
-#define MT_TX_ALC_CFG_2_TEMP_COMP GENMASK(5, 0)
-
-#define MT_TX0_BB_GAIN_ATTEN 0x13c0
-
-#define MT_TX_ALC_VGA3 0x13c8
-
-#define MT_TX_PROT_CFG6 0x13e0
-#define MT_TX_PROT_CFG7 0x13e4
-#define MT_TX_PROT_CFG8 0x13e8
-
-#define MT_PIFS_TX_CFG 0x13ec
-
-#define MT_RX_FILTR_CFG 0x1400
-
-#define MT_RX_FILTR_CFG_CRC_ERR BIT(0)
-#define MT_RX_FILTR_CFG_PHY_ERR BIT(1)
-#define MT_RX_FILTR_CFG_PROMISC BIT(2)
-#define MT_RX_FILTR_CFG_OTHER_BSS BIT(3)
-#define MT_RX_FILTR_CFG_VER_ERR BIT(4)
-#define MT_RX_FILTR_CFG_MCAST BIT(5)
-#define MT_RX_FILTR_CFG_BCAST BIT(6)
-#define MT_RX_FILTR_CFG_DUP BIT(7)
-#define MT_RX_FILTR_CFG_CFACK BIT(8)
-#define MT_RX_FILTR_CFG_CFEND BIT(9)
-#define MT_RX_FILTR_CFG_ACK BIT(10)
-#define MT_RX_FILTR_CFG_CTS BIT(11)
-#define MT_RX_FILTR_CFG_RTS BIT(12)
-#define MT_RX_FILTR_CFG_PSPOLL BIT(13)
-#define MT_RX_FILTR_CFG_BA BIT(14)
-#define MT_RX_FILTR_CFG_BAR BIT(15)
-#define MT_RX_FILTR_CFG_CTRL_RSV BIT(16)
-
-#define MT_AUTO_RSP_CFG 0x1404
-
-#define MT_AUTO_RSP_PREAMB_SHORT BIT(4)
-
-#define MT_LEGACY_BASIC_RATE 0x1408
-#define MT_HT_BASIC_RATE 0x140c
-#define MT_HT_CTRL_CFG 0x1410
-#define MT_RX_PARSER_CFG 0x1418
-#define MT_RX_PARSER_RX_SET_NAV_ALL BIT(0)
-
-#define MT_EXT_CCA_CFG 0x141c
-#define MT_EXT_CCA_CFG_CCA0 GENMASK(1, 0)
-#define MT_EXT_CCA_CFG_CCA1 GENMASK(3, 2)
-#define MT_EXT_CCA_CFG_CCA2 GENMASK(5, 4)
-#define MT_EXT_CCA_CFG_CCA3 GENMASK(7, 6)
-#define MT_EXT_CCA_CFG_CCA_MASK GENMASK(11, 8)
-#define MT_EXT_CCA_CFG_ED_CCA_MASK GENMASK(15, 12)
-
-#define MT_TX_SW_CFG3 0x1478
-
-#define MT_PN_PAD_MODE 0x150c
-
-#define MT_TXOP_HLDR_ET 0x1608
-
-#define MT_PROT_AUTO_TX_CFG 0x1648
-
-#define MT_RX_STA_CNT0 0x1700
-#define MT_RX_STA_CNT1 0x1704
-#define MT_RX_STA_CNT2 0x1708
-#define MT_TX_STA_CNT0 0x170c
-#define MT_TX_STA_CNT1 0x1710
-#define MT_TX_STA_CNT2 0x1714
-
-/* Vendor driver defines content of the second word of STAT_FIFO as follows:
- * MT_TX_STAT_FIFO_RATE GENMASK(26, 16)
- * MT_TX_STAT_FIFO_ETXBF BIT(27)
- * MT_TX_STAT_FIFO_SND BIT(28)
- * MT_TX_STAT_FIFO_ITXBF BIT(29)
- * However, tests show that b16-31 have the same layout as TXWI rate_ctl
- * with rate set to rate at which frame was acked.
- */
-#define MT_TX_STAT_FIFO 0x1718
-#define MT_TX_STAT_FIFO_VALID BIT(0)
-#define MT_TX_STAT_FIFO_SUCCESS BIT(5)
-#define MT_TX_STAT_FIFO_AGGR BIT(6)
-#define MT_TX_STAT_FIFO_ACKREQ BIT(7)
-#define MT_TX_STAT_FIFO_WCID GENMASK(15, 8)
-#define MT_TX_STAT_FIFO_RATE GENMASK(31, 16)
-
-#define MT_TX_AGG_STAT 0x171c
-
-#define MT_TX_AGG_CNT_BASE0 0x1720
-
-#define MT_MPDU_DENSITY_CNT 0x1740
-
-#define MT_TX_AGG_CNT_BASE1 0x174c
-
-#define MT_TX_AGG_CNT(_id) ((_id) < 8 ? \
- MT_TX_AGG_CNT_BASE0 + ((_id) << 2) : \
- MT_TX_AGG_CNT_BASE1 + ((_id - 8) << 2))
-
-#define MT_TX_STAT_FIFO_EXT 0x1798
-#define MT_TX_STAT_FIFO_EXT_RETRY GENMASK(7, 0)
-#define MT_TX_STAT_FIFO_EXT_PKTID GENMASK(15, 8)
-
-#define MT_BBP_CORE_BASE 0x2000
-#define MT_BBP_IBI_BASE 0x2100
-#define MT_BBP_AGC_BASE 0x2300
-#define MT_BBP_TXC_BASE 0x2400
-#define MT_BBP_RXC_BASE 0x2500
-#define MT_BBP_TXO_BASE 0x2600
-#define MT_BBP_TXBE_BASE 0x2700
-#define MT_BBP_RXFE_BASE 0x2800
-#define MT_BBP_RXO_BASE 0x2900
-#define MT_BBP_DFS_BASE 0x2a00
-#define MT_BBP_TR_BASE 0x2b00
-#define MT_BBP_CAL_BASE 0x2c00
-#define MT_BBP_DSC_BASE 0x2e00
-#define MT_BBP_PFMU_BASE 0x2f00
-
-#define MT_BBP(_type, _n) (MT_BBP_##_type##_BASE + ((_n) << 2))
-
-#define MT_BBP_CORE_R1_BW GENMASK(4, 3)
-
-#define MT_BBP_AGC_R0_CTRL_CHAN GENMASK(9, 8)
-#define MT_BBP_AGC_R0_BW GENMASK(14, 12)
-
-/* AGC, R4/R5 */
-#define MT_BBP_AGC_LNA_GAIN GENMASK(21, 16)
-
-/* AGC, R8/R9 */
-#define MT_BBP_AGC_GAIN GENMASK(14, 8)
-
-#define MT_BBP_AGC20_RSSI0 GENMASK(7, 0)
-#define MT_BBP_AGC20_RSSI1 GENMASK(15, 8)
-
-#define MT_BBP_TXBE_R0_CTRL_CHAN GENMASK(1, 0)
-
-#define MT_WCID_ADDR_BASE 0x1800
-#define MT_WCID_ADDR(_n) (MT_WCID_ADDR_BASE + (_n) * 8)
-
-#define MT_SRAM_BASE 0x4000
-
-#define MT_WCID_KEY_BASE 0x8000
-#define MT_WCID_KEY(_n) (MT_WCID_KEY_BASE + (_n) * 32)
-
-#define MT_WCID_IV_BASE 0xa000
-#define MT_WCID_IV(_n) (MT_WCID_IV_BASE + (_n) * 8)
-
-#define MT_WCID_ATTR_BASE 0xa800
-#define MT_WCID_ATTR(_n) (MT_WCID_ATTR_BASE + (_n) * 4)
-
-#define MT_WCID_ATTR_PAIRWISE BIT(0)
-#define MT_WCID_ATTR_PKEY_MODE GENMASK(3, 1)
-#define MT_WCID_ATTR_BSS_IDX GENMASK(6, 4)
-#define MT_WCID_ATTR_RXWI_UDF GENMASK(9, 7)
-#define MT_WCID_ATTR_PKEY_MODE_EXT BIT(10)
-#define MT_WCID_ATTR_BSS_IDX_EXT BIT(11)
-#define MT_WCID_ATTR_WAPI_MCBC BIT(15)
-#define MT_WCID_ATTR_WAPI_KEYID GENMASK(31, 24)
-
-#define MT_SKEY_BASE_0 0xac00
-#define MT_SKEY_BASE_1 0xb400
-#define MT_SKEY_0(_bss, _idx) \
- (MT_SKEY_BASE_0 + (4 * (_bss) + _idx) * 32)
-#define MT_SKEY_1(_bss, _idx) \
- (MT_SKEY_BASE_1 + (4 * ((_bss) & 7) + _idx) * 32)
-#define MT_SKEY(_bss, _idx) \
- ((_bss & 8) ? MT_SKEY_1(_bss, _idx) : MT_SKEY_0(_bss, _idx))
-
-#define MT_SKEY_MODE_BASE_0 0xb000
-#define MT_SKEY_MODE_BASE_1 0xb3f0
-#define MT_SKEY_MODE_0(_bss) \
- (MT_SKEY_MODE_BASE_0 + ((_bss / 2) << 2))
-#define MT_SKEY_MODE_1(_bss) \
- (MT_SKEY_MODE_BASE_1 + ((((_bss) & 7) / 2) << 2))
-#define MT_SKEY_MODE(_bss) \
- ((_bss & 8) ? MT_SKEY_MODE_1(_bss) : MT_SKEY_MODE_0(_bss))
-#define MT_SKEY_MODE_MASK GENMASK(3, 0)
-#define MT_SKEY_MODE_SHIFT(_bss, _idx) (4 * ((_idx) + 4 * (_bss & 1)))
-
-#define MT_BEACON_BASE 0xc000
-
-#define MT_TEMP_SENSOR 0x1d000
-#define MT_TEMP_SENSOR_VAL GENMASK(6, 0)
-
-enum mt76_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,
-};
-
-#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/trace.h b/drivers/net/wireless/mediatek/mt76/mt76x0/trace.h
index 8a752a09f2dc..75d1d6738c34 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/trace.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/trace.h
@@ -17,7 +17,6 @@
#include <linux/tracepoint.h>
#include "mt76x0.h"
-#include "mac.h"
#undef TRACE_SYSTEM
#define TRACE_SYSTEM mt76x0
@@ -178,11 +177,11 @@ DECLARE_EVENT_CLASS(dev_simple_evt,
);
TRACE_EVENT(mt76x0_rx,
- TP_PROTO(struct mt76_dev *dev, struct mt76x0_rxwi *rxwi, u32 f),
+ TP_PROTO(struct mt76_dev *dev, struct mt76x02_rxwi *rxwi, u32 f),
TP_ARGS(dev, rxwi, f),
TP_STRUCT__entry(
DEV_ENTRY
- __field_struct(struct mt76x0_rxwi, rxwi)
+ __field_struct(struct mt76x02_rxwi, rxwi)
__field(u32, fce_info)
),
TP_fast_assign(
@@ -197,13 +196,13 @@ TRACE_EVENT(mt76x0_rx,
TRACE_EVENT(mt76x0_tx,
TP_PROTO(struct mt76_dev *dev, struct sk_buff *skb,
- struct mt76_sta *sta, struct mt76_txwi *h),
+ struct mt76x02_sta *sta, struct mt76x02_txwi *h),
TP_ARGS(dev, skb, sta, h),
TP_STRUCT__entry(
DEV_ENTRY
- __field_struct(struct mt76_txwi, h)
+ __field_struct(struct mt76x02_txwi, h)
__field(struct sk_buff *, skb)
- __field(struct mt76_sta *, sta)
+ __field(struct mt76x02_sta *, sta)
),
TP_fast_assign(
DEV_ASSIGN;
@@ -211,11 +210,11 @@ TRACE_EVENT(mt76x0_tx,
__entry->skb = skb;
__entry->sta = sta;
),
- TP_printk(DEV_PR_FMT "skb:%p sta:%p flg:%04hx rate_ctl:%04hx "
+ TP_printk(DEV_PR_FMT "skb:%p sta:%p flg:%04hx rate:%04hx "
"ack:%02hhx wcid:%02hhx len_ctl:%05hx", DEV_PR_ARG,
__entry->skb, __entry->sta,
le16_to_cpu(__entry->h.flags),
- le16_to_cpu(__entry->h.rate_ctl),
+ le16_to_cpu(__entry->h.rate),
__entry->h.ack_ctl, __entry->h.wcid,
le16_to_cpu(__entry->h.len_ctl))
);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c b/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c
deleted file mode 100644
index 751b49c28ae5..000000000000
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/tx.c
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
- * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include "mt76x0.h"
-#include "trace.h"
-
-/* Take mac80211 Q id from the skb and translate it to hardware Q id */
-static u8 skb2q(struct sk_buff *skb)
-{
- int qid = skb_get_queue_mapping(skb);
-
- if (WARN_ON(qid >= MT_TXQ_PSD)) {
- qid = MT_TXQ_BE;
- skb_set_queue_mapping(skb, qid);
- }
-
- return q2hwq(qid);
-}
-
-static void mt76x0_tx_skb_remove_dma_overhead(struct sk_buff *skb,
- struct ieee80211_tx_info *info)
-{
- int pkt_len = (unsigned long)info->status.status_driver_data[0];
-
- skb_pull(skb, sizeof(struct mt76_txwi) + 4);
- if (ieee80211_get_hdrlen_from_skb(skb) % 4)
- mt76x0_remove_hdr_pad(skb);
-
- skb_trim(skb, pkt_len);
-}
-
-void mt76x0_tx_status(struct mt76x0_dev *dev, struct sk_buff *skb)
-{
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-
- mt76x0_tx_skb_remove_dma_overhead(skb, info);
-
- ieee80211_tx_info_clear_status(info);
- info->status.rates[0].idx = -1;
- info->flags |= IEEE80211_TX_STAT_ACK;
-
- spin_lock(&dev->mac_lock);
- ieee80211_tx_status(dev->mt76.hw, skb);
- spin_unlock(&dev->mac_lock);
-}
-
-static int mt76x0_skb_rooms(struct mt76x0_dev *dev, struct sk_buff *skb)
-{
- int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
- u32 need_head;
-
- need_head = sizeof(struct mt76_txwi) + 4;
- if (hdr_len % 4)
- need_head += 2;
-
- return skb_cow(skb, need_head);
-}
-
-static struct mt76_txwi *
-mt76x0_push_txwi(struct mt76x0_dev *dev, struct sk_buff *skb,
- struct ieee80211_sta *sta, struct mt76_wcid *wcid,
- int pkt_len)
-{
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct ieee80211_tx_rate *rate = &info->control.rates[0];
- struct mt76_txwi *txwi;
- unsigned long flags;
- u16 txwi_flags = 0;
- u32 pkt_id;
- u16 rate_ctl;
- u8 nss;
-
- txwi = (struct mt76_txwi *)skb_push(skb, sizeof(struct mt76_txwi));
- memset(txwi, 0, sizeof(*txwi));
-
- if (!wcid->tx_rate_set)
- ieee80211_get_tx_rates(info->control.vif, sta, skb,
- info->control.rates, 1);
-
- spin_lock_irqsave(&dev->mt76.lock, flags);
- if (rate->idx < 0 || !rate->count) {
- rate_ctl = wcid->tx_rate;
- nss = wcid->tx_rate_nss;
- } else {
- rate_ctl = mt76x0_mac_tx_rate_val(dev, rate, &nss);
- }
- spin_unlock_irqrestore(&dev->mt76.lock, flags);
-
- txwi->rate_ctl = cpu_to_le16(rate_ctl);
-
- if (info->flags & IEEE80211_TX_CTL_LDPC)
- txwi->rate_ctl |= cpu_to_le16(MT_RXWI_RATE_LDPC);
- if ((info->flags & IEEE80211_TX_CTL_STBC) && nss == 1)
- txwi->rate_ctl |= cpu_to_le16(MT_RXWI_RATE_STBC);
- if (nss > 1 && sta && sta->smps_mode == IEEE80211_SMPS_DYNAMIC)
- txwi_flags |= MT_TXWI_FLAGS_MMPS;
-
- if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
- txwi->ack_ctl |= MT_TXWI_ACK_CTL_REQ;
- pkt_id = 1;
- } else {
- pkt_id = 0;
- }
-
- if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)
- pkt_id |= MT_TXWI_PKTID_PROBE;
-
- if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
- txwi->ack_ctl |= MT_TXWI_ACK_CTL_NSEQ;
-
- if ((info->flags & IEEE80211_TX_CTL_AMPDU) && sta) {
- u8 ba_size = IEEE80211_MIN_AMPDU_BUF;
-
- ba_size <<= sta->ht_cap.ampdu_factor;
- ba_size = min_t(int, 7, ba_size - 1);
- if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) {
- ba_size = 0;
- } else {
- txwi_flags |= MT_TXWI_FLAGS_AMPDU;
- txwi_flags |= FIELD_PREP(MT_TXWI_FLAGS_MPDU_DENSITY,
- sta->ht_cap.ampdu_density);
- }
- txwi->ack_ctl |= FIELD_PREP(MT_TXWI_ACK_CTL_BA_WINDOW, ba_size);
- }
-
- txwi->wcid = wcid->idx;
- txwi->flags |= cpu_to_le16(txwi_flags);
- txwi->len_ctl = cpu_to_le16(pkt_len);
- txwi->pktid = pkt_id;
-
- return txwi;
-}
-
-void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
- struct sk_buff *skb)
-{
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct mt76x0_dev *dev = hw->priv;
- struct ieee80211_vif *vif = info->control.vif;
- struct ieee80211_sta *sta = control->sta;
- struct mt76_sta *msta = NULL;
- struct mt76_wcid *wcid = dev->mon_wcid;
- struct mt76_txwi *txwi;
- int pkt_len = skb->len;
- int hw_q = skb2q(skb);
-
- BUILD_BUG_ON(ARRAY_SIZE(info->status.status_driver_data) < 1);
- info->status.status_driver_data[0] = (void *)(unsigned long)pkt_len;
-
- if (mt76x0_skb_rooms(dev, skb) || mt76x0_insert_hdr_pad(skb)) {
- ieee80211_free_txskb(dev->mt76.hw, skb);
- return;
- }
-
- if (sta) {
- msta = (struct mt76_sta *) sta->drv_priv;
- wcid = &msta->wcid;
- } else if (vif && (!info->control.hw_key && wcid->hw_key_idx != -1)) {
- struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
-
- wcid = &mvif->group_wcid;
- }
-
- txwi = mt76x0_push_txwi(dev, skb, sta, wcid, pkt_len);
-
- if (mt76x0_dma_enqueue_tx(dev, skb, wcid, hw_q))
- return;
-
- trace_mt76x0_tx(&dev->mt76, skb, msta, txwi);
-}
-
-void mt76x0_tx_stat(struct work_struct *work)
-{
- struct mt76x0_dev *dev = container_of(work, struct mt76x0_dev,
- stat_work.work);
- struct mt76_tx_status stat;
- unsigned long flags;
- int cleaned = 0;
- u8 update = 1;
-
- while (!test_bit(MT76_REMOVED, &dev->mt76.state)) {
- stat = mt76x0_mac_fetch_tx_status(dev);
- if (!stat.valid)
- break;
-
- mt76x0_send_tx_status(dev, &stat, &update);
-
- cleaned++;
- }
- trace_mt76x0_tx_status_cleaned(&dev->mt76, cleaned);
-
- spin_lock_irqsave(&dev->tx_lock, flags);
- if (cleaned)
- queue_delayed_work(dev->stat_wq, &dev->stat_work,
- msecs_to_jiffies(10));
- else if (test_and_clear_bit(MT76_MORE_STATS, &dev->mt76.state))
- queue_delayed_work(dev->stat_wq, &dev->stat_work,
- msecs_to_jiffies(20));
- else
- clear_bit(MT76_READING_STATS, &dev->mt76.state);
- spin_unlock_irqrestore(&dev->tx_lock, flags);
-}
-
-int mt76x0_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- u16 queue, const struct ieee80211_tx_queue_params *params)
-{
- struct mt76x0_dev *dev = hw->priv;
- u8 cw_min = 5, cw_max = 10, hw_q = q2hwq(queue);
- u32 val;
-
- /* TODO: should we do funny things with the parameters?
- * See what mt76x0_set_default_edca() used to do in init.c.
- */
-
- if (params->cw_min)
- cw_min = fls(params->cw_min);
- if (params->cw_max)
- cw_max = fls(params->cw_max);
-
- WARN_ON(params->txop > 0xff);
- WARN_ON(params->aifs > 0xf);
- WARN_ON(cw_min > 0xf);
- WARN_ON(cw_max > 0xf);
-
- val = FIELD_PREP(MT_EDCA_CFG_AIFSN, params->aifs) |
- FIELD_PREP(MT_EDCA_CFG_CWMIN, cw_min) |
- FIELD_PREP(MT_EDCA_CFG_CWMAX, cw_max);
- /* TODO: based on user-controlled EnableTxBurst var vendor drv sets
- * a really long txop on AC0 (see connect.c:2009) but only on
- * connect? When not connected should be 0.
- */
- if (!hw_q)
- val |= 0x60;
- else
- val |= FIELD_PREP(MT_EDCA_CFG_TXOP, params->txop);
- mt76_wr(dev, MT_EDCA_CFG_AC(hw_q), val);
-
- val = mt76_rr(dev, MT_WMM_TXOP(hw_q));
- val &= ~(MT_WMM_TXOP_MASK << MT_WMM_TXOP_SHIFT(hw_q));
- val |= params->txop << MT_WMM_TXOP_SHIFT(hw_q);
- mt76_wr(dev, MT_WMM_TXOP(hw_q), val);
-
- val = mt76_rr(dev, MT_WMM_AIFSN);
- val &= ~(MT_WMM_AIFSN_MASK << MT_WMM_AIFSN_SHIFT(hw_q));
- val |= params->aifs << MT_WMM_AIFSN_SHIFT(hw_q);
- mt76_wr(dev, MT_WMM_AIFSN, val);
-
- val = mt76_rr(dev, MT_WMM_CWMIN);
- val &= ~(MT_WMM_CWMIN_MASK << MT_WMM_CWMIN_SHIFT(hw_q));
- val |= cw_min << MT_WMM_CWMIN_SHIFT(hw_q);
- mt76_wr(dev, MT_WMM_CWMIN, val);
-
- val = mt76_rr(dev, MT_WMM_CWMAX);
- val &= ~(MT_WMM_CWMAX_MASK << MT_WMM_CWMAX_SHIFT(hw_q));
- val |= cw_max << MT_WMM_CWMAX_SHIFT(hw_q);
- mt76_wr(dev, MT_WMM_CWMAX, val);
-
- return 0;
-}
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c
index 54ae1f113be2..a7fd36c2f633 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c
@@ -16,8 +16,9 @@
#include <linux/usb.h>
#include "mt76x0.h"
-#include "usb.h"
+#include "mcu.h"
#include "trace.h"
+#include "../mt76x02_usb.h"
static struct usb_device_id mt76x0_device_table[] = {
{ USB_DEVICE(0x148F, 0x7610) }, /* MT7610U */
@@ -40,256 +41,215 @@ static struct usb_device_id mt76x0_device_table[] = {
{ USB_DEVICE(0x20f4, 0x806b) }, /* TRENDnet TEW-806UBH */
{ USB_DEVICE(0x7392, 0xc711) }, /* Devolo Wifi ac Stick */
{ USB_DEVICE(0x0df6, 0x0079) }, /* Sitecom Europe B.V. ac Stick */
- { USB_DEVICE(0x2357, 0x0105) }, /* TP-LINK Archer T1U */
+ { USB_DEVICE(0x2357, 0x0105),
+ .driver_info = 1, }, /* TP-LINK Archer T1U */
{ USB_DEVICE_AND_INTERFACE_INFO(0x0E8D, 0x7630, 0xff, 0x2, 0xff)}, /* MT7630U */
{ USB_DEVICE_AND_INTERFACE_INFO(0x0E8D, 0x7650, 0xff, 0x2, 0xff)}, /* MT7650U */
{ 0, }
};
-bool mt76x0_usb_alloc_buf(struct mt76x0_dev *dev, size_t len,
- struct mt76x0_dma_buf *buf)
+static void mt76x0_init_usb_dma(struct mt76x02_dev *dev)
{
- struct usb_device *usb_dev = mt76x0_to_usb_dev(dev);
+ u32 val;
- buf->len = len;
- buf->urb = usb_alloc_urb(0, GFP_KERNEL);
- buf->buf = usb_alloc_coherent(usb_dev, buf->len, GFP_KERNEL, &buf->dma);
+ val = mt76_rr(dev, MT_USB_DMA_CFG);
- return !buf->urb || !buf->buf;
-}
-
-void mt76x0_usb_free_buf(struct mt76x0_dev *dev, struct mt76x0_dma_buf *buf)
-{
- struct usb_device *usb_dev = mt76x0_to_usb_dev(dev);
-
- usb_free_coherent(usb_dev, buf->len, buf->buf, buf->dma);
- usb_free_urb(buf->urb);
-}
-
-int mt76x0_usb_submit_buf(struct mt76x0_dev *dev, int dir, int ep_idx,
- struct mt76x0_dma_buf *buf, gfp_t gfp,
- usb_complete_t complete_fn, void *context)
-{
- struct usb_device *usb_dev = mt76x0_to_usb_dev(dev);
- unsigned pipe;
- int ret;
-
- if (dir == USB_DIR_IN)
- pipe = usb_rcvbulkpipe(usb_dev, dev->in_ep[ep_idx]);
- else
- pipe = usb_sndbulkpipe(usb_dev, dev->out_ep[ep_idx]);
-
- usb_fill_bulk_urb(buf->urb, usb_dev, pipe, buf->buf, buf->len,
- complete_fn, context);
- buf->urb->transfer_dma = buf->dma;
- buf->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
- trace_mt76x0_submit_urb(&dev->mt76, buf->urb);
- ret = usb_submit_urb(buf->urb, gfp);
- if (ret)
- dev_err(dev->mt76.dev, "Error: submit URB dir:%d ep:%d failed:%d\n",
- dir, ep_idx, ret);
- return ret;
-}
-
-void mt76x0_complete_urb(struct urb *urb)
-{
- struct completion *cmpl = urb->context;
+ val |= MT_USB_DMA_CFG_RX_BULK_EN |
+ MT_USB_DMA_CFG_TX_BULK_EN;
- complete(cmpl);
-}
+ /* disable AGGR_BULK_RX in order to receive one
+ * frame in each rx urb and avoid copies
+ */
+ val &= ~MT_USB_DMA_CFG_RX_BULK_AGG_EN;
+ mt76_wr(dev, MT_USB_DMA_CFG, val);
-int mt76x0_vendor_request(struct mt76x0_dev *dev, const u8 req,
- const u8 direction, const u16 val, const u16 offset,
- void *buf, const size_t buflen)
-{
- int i, ret;
- struct usb_device *usb_dev = mt76x0_to_usb_dev(dev);
- const u8 req_type = direction | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
- const unsigned int pipe = (direction == USB_DIR_IN) ?
- usb_rcvctrlpipe(usb_dev, 0) : usb_sndctrlpipe(usb_dev, 0);
-
- for (i = 0; i < MT_VEND_REQ_MAX_RETRY; i++) {
- ret = usb_control_msg(usb_dev, pipe, req, req_type,
- val, offset, buf, buflen,
- MT_VEND_REQ_TOUT_MS);
- trace_mt76x0_vend_req(&dev->mt76, pipe, req, req_type, val, offset,
- buf, buflen, ret);
-
- if (ret == -ENODEV)
- set_bit(MT76_REMOVED, &dev->mt76.state);
- if (ret >= 0 || ret == -ENODEV)
- return ret;
-
- msleep(5);
- }
+ val = mt76_rr(dev, MT_COM_REG0);
+ if (val & 1)
+ dev_dbg(dev->mt76.dev, "MCU not ready\n");
- dev_err(dev->mt76.dev, "Vendor request req:%02x off:%04x failed:%d\n",
- req, offset, ret);
+ val = mt76_rr(dev, MT_USB_DMA_CFG);
- return ret;
+ val |= MT_USB_DMA_CFG_RX_DROP_OR_PAD;
+ mt76_wr(dev, MT_USB_DMA_CFG, val);
+ val &= ~MT_USB_DMA_CFG_RX_DROP_OR_PAD;
+ mt76_wr(dev, MT_USB_DMA_CFG, val);
}
-void mt76x0_vendor_reset(struct mt76x0_dev *dev)
+static void mt76x0u_cleanup(struct mt76x02_dev *dev)
{
- mt76x0_vendor_request(dev, MT_VEND_DEV_MODE, USB_DIR_OUT,
- MT_VEND_DEV_MODE_RESET, 0, NULL, 0);
+ clear_bit(MT76_STATE_INITIALIZED, &dev->mt76.state);
+ mt76x0_chip_onoff(dev, false, false);
+ mt76u_queues_deinit(&dev->mt76);
+ mt76u_mcu_deinit(&dev->mt76);
}
-static u32 mt76x0_rr(struct mt76_dev *dev, u32 offset)
+static void mt76x0u_mac_stop(struct mt76x02_dev *dev)
{
- struct mt76x0_dev *mdev = (struct mt76x0_dev *) dev;
- int ret;
- u32 val = ~0;
+ clear_bit(MT76_STATE_RUNNING, &dev->mt76.state);
+ cancel_delayed_work_sync(&dev->cal_work);
+ cancel_delayed_work_sync(&dev->mac_work);
+ mt76u_stop_stat_wk(&dev->mt76);
- WARN_ONCE(offset > USHRT_MAX, "read high off:%08x", offset);
+ if (test_bit(MT76_REMOVED, &dev->mt76.state))
+ return;
- mutex_lock(&mdev->usb_ctrl_mtx);
+ mt76_clear(dev, MT_BEACON_TIME_CFG, MT_BEACON_TIME_CFG_TIMER_EN |
+ MT_BEACON_TIME_CFG_SYNC_MODE | MT_BEACON_TIME_CFG_TBTT_EN |
+ MT_BEACON_TIME_CFG_BEACON_TX);
- ret = mt76x0_vendor_request((struct mt76x0_dev *)dev, MT_VEND_MULTI_READ, USB_DIR_IN,
- 0, offset, mdev->data, MT_VEND_BUF);
- if (ret == MT_VEND_BUF)
- val = get_unaligned_le32(mdev->data);
- else if (ret > 0)
- dev_err(dev->dev, "Error: wrong size read:%d off:%08x\n",
- ret, offset);
+ if (!mt76_poll(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_TX_BUSY, 0, 1000))
+ dev_warn(dev->mt76.dev, "TX DMA did not stop\n");
- mutex_unlock(&mdev->usb_ctrl_mtx);
+ mt76x0_mac_stop(dev);
- trace_mt76x0_reg_read(dev, offset, val);
- return val;
+ if (!mt76_poll(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_RX_BUSY, 0, 1000))
+ dev_warn(dev->mt76.dev, "RX DMA did not stop\n");
}
-int mt76x0_vendor_single_wr(struct mt76x0_dev *dev, const u8 req,
- const u16 offset, const u32 val)
+static int mt76x0u_start(struct ieee80211_hw *hw)
{
- struct mt76x0_dev *mdev = dev;
+ struct mt76x02_dev *dev = hw->priv;
int ret;
- mutex_lock(&mdev->usb_ctrl_mtx);
+ mutex_lock(&dev->mt76.mutex);
- ret = mt76x0_vendor_request(dev, req, USB_DIR_OUT,
- val & 0xffff, offset, NULL, 0);
- if (!ret)
- ret = mt76x0_vendor_request(dev, req, USB_DIR_OUT,
- val >> 16, offset + 2, NULL, 0);
+ ret = mt76x0_mac_start(dev);
+ if (ret)
+ goto out;
- mutex_unlock(&mdev->usb_ctrl_mtx);
+ ieee80211_queue_delayed_work(dev->mt76.hw, &dev->mac_work,
+ MT_CALIBRATE_INTERVAL);
+ ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work,
+ MT_CALIBRATE_INTERVAL);
+ set_bit(MT76_STATE_RUNNING, &dev->mt76.state);
+out:
+ mutex_unlock(&dev->mt76.mutex);
return ret;
}
-static void mt76x0_wr(struct mt76_dev *dev, u32 offset, u32 val)
+static void mt76x0u_stop(struct ieee80211_hw *hw)
{
- struct mt76x0_dev *mdev = (struct mt76x0_dev *) dev;
- int ret;
+ struct mt76x02_dev *dev = hw->priv;
- WARN_ONCE(offset > USHRT_MAX, "write high off:%08x", offset);
-
- mutex_lock(&mdev->usb_ctrl_mtx);
-
- put_unaligned_le32(val, mdev->data);
- ret = mt76x0_vendor_request(mdev, MT_VEND_MULTI_WRITE, USB_DIR_OUT,
- 0, offset, mdev->data, MT_VEND_BUF);
- trace_mt76x0_reg_write(dev, offset, val);
-
- mutex_unlock(&mdev->usb_ctrl_mtx);
+ mutex_lock(&dev->mt76.mutex);
+ mt76x0u_mac_stop(dev);
+ mutex_unlock(&dev->mt76.mutex);
}
-static u32 mt76x0_rmw(struct mt76_dev *dev, u32 offset, u32 mask, u32 val)
-{
- val |= mt76x0_rr(dev, offset) & ~mask;
- mt76x0_wr(dev, offset, val);
- return val;
-}
+static const struct ieee80211_ops mt76x0u_ops = {
+ .tx = mt76x02_tx,
+ .start = mt76x0u_start,
+ .stop = mt76x0u_stop,
+ .add_interface = mt76x02_add_interface,
+ .remove_interface = mt76x02_remove_interface,
+ .config = mt76x0_config,
+ .configure_filter = mt76x02_configure_filter,
+ .bss_info_changed = mt76x0_bss_info_changed,
+ .sta_add = mt76x02_sta_add,
+ .sta_remove = mt76x02_sta_remove,
+ .set_key = mt76x02_set_key,
+ .conf_tx = mt76x02_conf_tx,
+ .sw_scan_start = mt76x0_sw_scan,
+ .sw_scan_complete = mt76x0_sw_scan_complete,
+ .ampdu_action = mt76x02_ampdu_action,
+ .sta_rate_tbl_update = mt76x02_sta_rate_tbl_update,
+ .set_rts_threshold = mt76x0_set_rts_threshold,
+ .wake_tx_queue = mt76_wake_tx_queue,
+};
-static void mt76x0_wr_copy(struct mt76_dev *dev, u32 offset,
- const void *data, int len)
+static int mt76x0u_register_device(struct mt76x02_dev *dev)
{
- WARN_ONCE(offset & 3, "unaligned write copy off:%08x", offset);
- WARN_ONCE(len & 3, "short write copy off:%08x", offset);
+ struct ieee80211_hw *hw = dev->mt76.hw;
+ int err;
- mt76x0_burst_write_regs((struct mt76x0_dev *) dev, offset, data, len / 4);
-}
+ err = mt76u_alloc_queues(&dev->mt76);
+ if (err < 0)
+ goto out_err;
-void mt76x0_addr_wr(struct mt76x0_dev *dev, const u32 offset, const u8 *addr)
-{
- mt76_wr(dev, offset, get_unaligned_le32(addr));
- mt76_wr(dev, offset + 4, addr[4] | addr[5] << 8);
-}
+ err = mt76u_mcu_init_rx(&dev->mt76);
+ if (err < 0)
+ goto out_err;
-static int mt76x0_assign_pipes(struct usb_interface *usb_intf,
- struct mt76x0_dev *dev)
-{
- struct usb_endpoint_descriptor *ep_desc;
- struct usb_host_interface *intf_desc = usb_intf->cur_altsetting;
- unsigned i, ep_i = 0, ep_o = 0;
-
- BUILD_BUG_ON(sizeof(dev->in_ep) < __MT_EP_IN_MAX);
- BUILD_BUG_ON(sizeof(dev->out_ep) < __MT_EP_OUT_MAX);
-
- for (i = 0; i < intf_desc->desc.bNumEndpoints; i++) {
- ep_desc = &intf_desc->endpoint[i].desc;
-
- if (usb_endpoint_is_bulk_in(ep_desc) &&
- ep_i++ < __MT_EP_IN_MAX) {
- dev->in_ep[ep_i - 1] = usb_endpoint_num(ep_desc);
- dev->in_max_packet = usb_endpoint_maxp(ep_desc);
- /* Note: this is ignored by usb sub-system but vendor
- * code does it. We can drop this at some point.
- */
- dev->in_ep[ep_i - 1] |= USB_DIR_IN;
- } else if (usb_endpoint_is_bulk_out(ep_desc) &&
- ep_o++ < __MT_EP_OUT_MAX) {
- dev->out_ep[ep_o - 1] = usb_endpoint_num(ep_desc);
- dev->out_max_packet = usb_endpoint_maxp(ep_desc);
- }
+ mt76x0_chip_onoff(dev, true, true);
+ if (!mt76x02_wait_for_mac(&dev->mt76)) {
+ err = -ETIMEDOUT;
+ goto out_err;
}
- if (ep_i != __MT_EP_IN_MAX || ep_o != __MT_EP_OUT_MAX) {
- dev_err(dev->mt76.dev, "Error: wrong pipe number in:%d out:%d\n",
- ep_i, ep_o);
- return -EINVAL;
- }
+ err = mt76x0u_mcu_init(dev);
+ if (err < 0)
+ goto out_err;
+
+ mt76x0_init_usb_dma(dev);
+ err = mt76x0_init_hardware(dev);
+ if (err < 0)
+ goto out_err;
+
+ mt76_rmw(dev, MT_US_CYC_CFG, MT_US_CYC_CNT, 0x1e);
+ mt76_wr(dev, MT_TXOP_CTRL_CFG,
+ FIELD_PREP(MT_TXOP_TRUN_EN, 0x3f) |
+ FIELD_PREP(MT_TXOP_EXT_CCA_DLY, 0x58));
+
+ err = mt76x0_register_device(dev);
+ if (err < 0)
+ goto out_err;
+
+ /* check hw sg support in order to enable AMSDU */
+ if (mt76u_check_sg(&dev->mt76))
+ hw->max_tx_fragments = MT_SG_MAX_SIZE;
+ else
+ hw->max_tx_fragments = 1;
+
+ set_bit(MT76_STATE_INITIALIZED, &dev->mt76.state);
return 0;
+
+out_err:
+ mt76x0u_cleanup(dev);
+ return err;
}
-static int mt76x0_probe(struct usb_interface *usb_intf,
+static int mt76x0u_probe(struct usb_interface *usb_intf,
const struct usb_device_id *id)
{
+ static const struct mt76_driver_ops drv_ops = {
+ .tx_prepare_skb = mt76x02u_tx_prepare_skb,
+ .tx_complete_skb = mt76x02u_tx_complete_skb,
+ .tx_status_data = mt76x02_tx_status_data,
+ .rx_skb = mt76x02_queue_rx_skb,
+ };
struct usb_device *usb_dev = interface_to_usbdev(usb_intf);
- struct mt76x0_dev *dev;
+ struct mt76x02_dev *dev;
u32 asic_rev, mac_rev;
int ret;
- static const struct mt76_bus_ops usb_ops = {
- .rr = mt76x0_rr,
- .wr = mt76x0_wr,
- .rmw = mt76x0_rmw,
- .copy = mt76x0_wr_copy,
- };
- dev = mt76x0_alloc_device(&usb_intf->dev);
+ dev = mt76x0_alloc_device(&usb_intf->dev, &drv_ops,
+ &mt76x0u_ops);
if (!dev)
return -ENOMEM;
+ /* Quirk for Archer T1U */
+ if (id->driver_info)
+ dev->no_2ghz = true;
+
usb_dev = usb_get_dev(usb_dev);
usb_reset_device(usb_dev);
usb_set_intfdata(usb_intf, dev);
- dev->mt76.bus = &usb_ops;
-
- ret = mt76x0_assign_pipes(usb_intf, dev);
+ mt76x02u_init_mcu(&dev->mt76);
+ ret = mt76u_init(&dev->mt76, usb_intf);
if (ret)
goto err;
/* Disable the HW, otherwise MCU fail to initalize on hot reboot */
mt76x0_chip_onoff(dev, false, false);
- ret = mt76x0_wait_asic_ready(dev);
- if (ret)
+ if (!mt76x02_wait_for_mac(&dev->mt76)) {
+ ret = -ETIMEDOUT;
goto err;
+ }
asic_rev = mt76_rr(dev, MT_ASIC_VERSION);
mac_rev = mt76_rr(dev, MT_MAC_CSR0);
@@ -300,77 +260,89 @@ static int mt76x0_probe(struct usb_interface *usb_intf,
if (!(mt76_rr(dev, MT_EFUSE_CTRL) & MT_EFUSE_CTRL_SEL))
dev_warn(dev->mt76.dev, "Warning: eFUSE not present\n");
- ret = mt76x0_init_hardware(dev);
- if (ret)
+ ret = mt76x0u_register_device(dev);
+ if (ret < 0)
goto err;
- ret = mt76x0_register_device(dev);
- if (ret)
- goto err_hw;
-
- set_bit(MT76_STATE_INITIALIZED, &dev->mt76.state);
-
return 0;
-err_hw:
- mt76x0_cleanup(dev);
+
err:
usb_set_intfdata(usb_intf, NULL);
usb_put_dev(interface_to_usbdev(usb_intf));
- destroy_workqueue(dev->stat_wq);
ieee80211_free_hw(dev->mt76.hw);
return ret;
}
static void mt76x0_disconnect(struct usb_interface *usb_intf)
{
- struct mt76x0_dev *dev = usb_get_intfdata(usb_intf);
+ struct mt76x02_dev *dev = usb_get_intfdata(usb_intf);
bool initalized = test_bit(MT76_STATE_INITIALIZED, &dev->mt76.state);
if (!initalized)
return;
ieee80211_unregister_hw(dev->mt76.hw);
- mt76x0_cleanup(dev);
+ mt76x0u_cleanup(dev);
usb_set_intfdata(usb_intf, NULL);
usb_put_dev(interface_to_usbdev(usb_intf));
- destroy_workqueue(dev->stat_wq);
ieee80211_free_hw(dev->mt76.hw);
}
-static int mt76x0_suspend(struct usb_interface *usb_intf, pm_message_t state)
+static int __maybe_unused mt76x0_suspend(struct usb_interface *usb_intf,
+ pm_message_t state)
{
- struct mt76x0_dev *dev = usb_get_intfdata(usb_intf);
+ struct mt76x02_dev *dev = usb_get_intfdata(usb_intf);
+ struct mt76_usb *usb = &dev->mt76.usb;
- mt76x0_cleanup(dev);
+ mt76u_stop_queues(&dev->mt76);
+ mt76x0u_mac_stop(dev);
+ usb_kill_urb(usb->mcu.res.urb);
return 0;
}
-static int mt76x0_resume(struct usb_interface *usb_intf)
+static int __maybe_unused mt76x0_resume(struct usb_interface *usb_intf)
{
- struct mt76x0_dev *dev = usb_get_intfdata(usb_intf);
+ struct mt76x02_dev *dev = usb_get_intfdata(usb_intf);
+ struct mt76_usb *usb = &dev->mt76.usb;
int ret;
+ reinit_completion(&usb->mcu.cmpl);
+ ret = mt76u_submit_buf(&dev->mt76, USB_DIR_IN,
+ MT_EP_IN_CMD_RESP,
+ &usb->mcu.res, GFP_KERNEL,
+ mt76u_mcu_complete_urb,
+ &usb->mcu.cmpl);
+ if (ret < 0)
+ goto err;
+
+ ret = mt76u_submit_rx_buffers(&dev->mt76);
+ if (ret < 0)
+ goto err;
+
+ tasklet_enable(&usb->rx_tasklet);
+ tasklet_enable(&usb->tx_tasklet);
+
ret = mt76x0_init_hardware(dev);
if (ret)
- return ret;
-
- set_bit(MT76_STATE_INITIALIZED, &dev->mt76.state);
+ goto err;
return 0;
+err:
+ mt76x0u_cleanup(dev);
+ return ret;
}
MODULE_DEVICE_TABLE(usb, mt76x0_device_table);
-MODULE_FIRMWARE(MT7610_FIRMWARE);
MODULE_LICENSE("GPL");
static struct usb_driver mt76x0_driver = {
.name = KBUILD_MODNAME,
.id_table = mt76x0_device_table,
- .probe = mt76x0_probe,
+ .probe = mt76x0u_probe,
.disconnect = mt76x0_disconnect,
.suspend = mt76x0_suspend,
.resume = mt76x0_resume,
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.h b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.h
deleted file mode 100644
index 492e431390a8..000000000000
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#ifndef __MT76X0U_USB_H
-#define __MT76X0U_USB_H
-
-#include "mt76x0.h"
-
-#define MT7610_FIRMWARE "mediatek/mt7610u.bin"
-
-#define MT_VEND_REQ_MAX_RETRY 10
-#define MT_VEND_REQ_TOUT_MS 300
-
-#define MT_VEND_DEV_MODE_RESET 1
-
-#define MT_VEND_BUF sizeof(__le32)
-
-static inline struct usb_device *mt76x0_to_usb_dev(struct mt76x0_dev *mt76x0)
-{
- return interface_to_usbdev(to_usb_interface(mt76x0->mt76.dev));
-}
-
-static inline struct usb_device *mt76_to_usb_dev(struct mt76_dev *mt76)
-{
- return interface_to_usbdev(to_usb_interface(mt76->dev));
-}
-
-static inline bool mt76x0_urb_has_error(struct urb *urb)
-{
- return urb->status &&
- urb->status != -ENOENT &&
- urb->status != -ECONNRESET &&
- urb->status != -ESHUTDOWN;
-}
-
-bool mt76x0_usb_alloc_buf(struct mt76x0_dev *dev, size_t len,
- struct mt76x0_dma_buf *buf);
-void mt76x0_usb_free_buf(struct mt76x0_dev *dev, struct mt76x0_dma_buf *buf);
-int mt76x0_usb_submit_buf(struct mt76x0_dev *dev, int dir, int ep_idx,
- struct mt76x0_dma_buf *buf, gfp_t gfp,
- usb_complete_t complete_fn, void *context);
-void mt76x0_complete_urb(struct urb *urb);
-
-int mt76x0_vendor_request(struct mt76x0_dev *dev, const u8 req,
- const u8 direction, const u16 val, const u16 offset,
- void *buf, const size_t buflen);
-void mt76x0_vendor_reset(struct mt76x0_dev *dev);
-int mt76x0_vendor_single_wr(struct mt76x0_dev *dev, const u8 req,
- const u16 offset, const u32 val);
-
-#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb_mcu.c
new file mode 100644
index 000000000000..a9f14d5149d1
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb_mcu.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <linux/kernel.h>
+#include <linux/firmware.h>
+
+#include "mt76x0.h"
+#include "mcu.h"
+#include "../mt76x02_usb.h"
+
+#define MCU_FW_URB_MAX_PAYLOAD 0x38f8
+#define MCU_FW_URB_SIZE (MCU_FW_URB_MAX_PAYLOAD + 12)
+#define MT7610U_FIRMWARE "mediatek/mt7610u.bin"
+
+static int
+mt76x0u_upload_firmware(struct mt76x02_dev *dev,
+ const struct mt76x02_fw_header *hdr)
+{
+ u8 *fw_payload = (u8 *)(hdr + 1);
+ u32 ilm_len, dlm_len;
+ void *ivb;
+ int err;
+
+ ivb = kmemdup(fw_payload, MT_MCU_IVB_SIZE, GFP_KERNEL);
+ if (!ivb)
+ return -ENOMEM;
+
+ ilm_len = le32_to_cpu(hdr->ilm_len) - MT_MCU_IVB_SIZE;
+ dev_dbg(dev->mt76.dev, "loading FW - ILM %u + IVB %u\n",
+ ilm_len, MT_MCU_IVB_SIZE);
+ err = mt76x02u_mcu_fw_send_data(dev, fw_payload + MT_MCU_IVB_SIZE,
+ ilm_len, MCU_FW_URB_MAX_PAYLOAD,
+ MT_MCU_IVB_SIZE);
+ if (err)
+ goto out;
+
+ dlm_len = le32_to_cpu(hdr->dlm_len);
+ dev_dbg(dev->mt76.dev, "loading FW - DLM %u\n", dlm_len);
+ err = mt76x02u_mcu_fw_send_data(dev,
+ fw_payload + le32_to_cpu(hdr->ilm_len),
+ dlm_len, MCU_FW_URB_MAX_PAYLOAD,
+ MT_MCU_DLM_OFFSET);
+ if (err)
+ goto out;
+
+ err = mt76u_vendor_request(&dev->mt76, MT_VEND_DEV_MODE,
+ USB_DIR_OUT | USB_TYPE_VENDOR,
+ 0x12, 0, ivb, MT_MCU_IVB_SIZE);
+ if (err < 0)
+ goto out;
+
+ if (!mt76_poll_msec(dev, MT_MCU_COM_REG0, 1, 1, 1000)) {
+ dev_err(dev->mt76.dev, "Firmware failed to start\n");
+ err = -ETIMEDOUT;
+ goto out;
+ }
+
+ dev_dbg(dev->mt76.dev, "Firmware running!\n");
+
+out:
+ kfree(ivb);
+
+ return err;
+}
+
+static int mt76x0u_load_firmware(struct mt76x02_dev *dev)
+{
+ const struct firmware *fw;
+ const struct mt76x02_fw_header *hdr;
+ int len, ret;
+ u32 val;
+
+ mt76_wr(dev, MT_USB_DMA_CFG, (MT_USB_DMA_CFG_RX_BULK_EN |
+ MT_USB_DMA_CFG_TX_BULK_EN));
+
+ if (mt76x0_firmware_running(dev))
+ return 0;
+
+ ret = request_firmware(&fw, MT7610U_FIRMWARE, dev->mt76.dev);
+ if (ret)
+ return ret;
+
+ if (!fw || !fw->data || fw->size < sizeof(*hdr))
+ goto err_inv_fw;
+
+ hdr = (const struct mt76x02_fw_header *)fw->data;
+
+ if (le32_to_cpu(hdr->ilm_len) <= MT_MCU_IVB_SIZE)
+ goto err_inv_fw;
+
+ len = sizeof(*hdr);
+ len += le32_to_cpu(hdr->ilm_len);
+ len += le32_to_cpu(hdr->dlm_len);
+
+ if (fw->size != len)
+ goto err_inv_fw;
+
+ val = le16_to_cpu(hdr->fw_ver);
+ dev_dbg(dev->mt76.dev,
+ "Firmware Version: %d.%d.%02d Build: %x Build time: %.16s\n",
+ (val >> 12) & 0xf, (val >> 8) & 0xf, val & 0xf,
+ le16_to_cpu(hdr->build_ver), hdr->build_time);
+
+ len = le32_to_cpu(hdr->ilm_len);
+
+ mt76_wr(dev, 0x1004, 0x2c);
+
+ mt76_set(dev, MT_USB_DMA_CFG,
+ (MT_USB_DMA_CFG_RX_BULK_EN | MT_USB_DMA_CFG_TX_BULK_EN) |
+ FIELD_PREP(MT_USB_DMA_CFG_RX_BULK_AGG_TOUT, 0x20));
+ mt76x02u_mcu_fw_reset(dev);
+ usleep_range(5000, 6000);
+/*
+ mt76x0_rmw(dev, MT_PBF_CFG, 0, (MT_PBF_CFG_TX0Q_EN |
+ MT_PBF_CFG_TX1Q_EN |
+ MT_PBF_CFG_TX2Q_EN |
+ MT_PBF_CFG_TX3Q_EN));
+*/
+
+ mt76_wr(dev, MT_FCE_PSE_CTRL, 1);
+
+ /* FCE tx_fs_base_ptr */
+ mt76_wr(dev, MT_TX_CPU_FROM_FCE_BASE_PTR, 0x400230);
+ /* FCE tx_fs_max_cnt */
+ mt76_wr(dev, MT_TX_CPU_FROM_FCE_MAX_COUNT, 1);
+ /* FCE pdma enable */
+ mt76_wr(dev, MT_FCE_PDMA_GLOBAL_CONF, 0x44);
+ /* FCE skip_fs_en */
+ mt76_wr(dev, MT_FCE_SKIP_FS, 3);
+
+ val = mt76_rr(dev, MT_USB_DMA_CFG);
+ val |= MT_USB_DMA_CFG_UDMA_TX_WL_DROP;
+ mt76_wr(dev, MT_USB_DMA_CFG, val);
+ val &= ~MT_USB_DMA_CFG_UDMA_TX_WL_DROP;
+ mt76_wr(dev, MT_USB_DMA_CFG, val);
+
+ ret = mt76x0u_upload_firmware(dev, hdr);
+ release_firmware(fw);
+
+ mt76_wr(dev, MT_FCE_PSE_CTRL, 1);
+
+ return ret;
+
+err_inv_fw:
+ dev_err(dev->mt76.dev, "Invalid firmware image\n");
+ release_firmware(fw);
+ return -ENOENT;
+}
+
+int mt76x0u_mcu_init(struct mt76x02_dev *dev)
+{
+ int ret;
+
+ ret = mt76x0u_load_firmware(dev);
+ if (ret < 0)
+ return ret;
+
+ set_bit(MT76_STATE_MCU_RUNNING, &dev->mt76.state);
+
+ return 0;
+}
+
+MODULE_FIRMWARE(MT7610U_FIRMWARE);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/util.c b/drivers/net/wireless/mediatek/mt76/mt76x0/util.c
deleted file mode 100644
index 7856dd760419..000000000000
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/util.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include "mt76x0.h"
-
-void mt76x0_remove_hdr_pad(struct sk_buff *skb)
-{
- int len = ieee80211_get_hdrlen_from_skb(skb);
-
- memmove(skb->data + 2, skb->data, len);
- skb_pull(skb, 2);
-}
-
-int mt76x0_insert_hdr_pad(struct sk_buff *skb)
-{
- int len = ieee80211_get_hdrlen_from_skb(skb);
- int ret;
-
- if (len % 4 == 0)
- return 0;
-
- ret = skb_cow(skb, 2);
- if (ret)
- return ret;
-
- skb_push(skb, 2);
- memmove(skb->data, skb->data + 2, len);
-
- skb->data[len] = 0;
- skb->data[len + 1] = 0;
- return 0;
-}
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h
new file mode 100644
index 000000000000..47c42c607964
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
+ * Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __MT76X02_UTIL_H
+#define __MT76X02_UTIL_H
+
+#include <linux/kfifo.h>
+
+#include "mt76.h"
+#include "mt76x02_regs.h"
+#include "mt76x02_mac.h"
+#include "mt76x02_dfs.h"
+#include "mt76x02_dma.h"
+
+struct mt76x02_mac_stats {
+ u64 rx_stat[6];
+ u64 tx_stat[6];
+ u64 aggr_stat[2];
+ u64 aggr_n[32];
+ u64 zero_len_del[2];
+};
+
+#define MT_MAX_CHAINS 2
+struct mt76x02_rx_freq_cal {
+ s8 high_gain[MT_MAX_CHAINS];
+ s8 rssi_offset[MT_MAX_CHAINS];
+ s8 lna_gain;
+ u32 mcu_gain;
+ s16 temp_offset;
+ u8 freq_offset;
+};
+
+struct mt76x02_calibration {
+ struct mt76x02_rx_freq_cal rx;
+
+ u8 agc_gain_init[MT_MAX_CHAINS];
+ u8 agc_gain_cur[MT_MAX_CHAINS];
+
+ u16 false_cca;
+ s8 avg_rssi_all;
+ s8 agc_gain_adjust;
+ s8 low_gain;
+
+ s8 temp_vco;
+ s8 temp;
+
+ bool init_cal_done;
+ bool tssi_cal_done;
+ bool tssi_comp_pending;
+ bool dpd_cal_done;
+ bool channel_cal_done;
+};
+
+struct mt76x02_dev {
+ struct mt76_dev mt76; /* must be first */
+
+ struct mac_address macaddr_list[8];
+
+ struct mutex phy_mutex;
+ struct mutex mutex;
+
+ u8 txdone_seq;
+ DECLARE_KFIFO_PTR(txstatus_fifo, struct mt76x02_tx_status);
+
+ struct sk_buff *rx_head;
+
+ struct tasklet_struct tx_tasklet;
+ struct tasklet_struct pre_tbtt_tasklet;
+ struct delayed_work cal_work;
+ struct delayed_work mac_work;
+
+ struct mt76x02_mac_stats stats;
+ atomic_t avg_ampdu_len;
+ u32 aggr_stats[32];
+
+ struct sk_buff *beacons[8];
+ u8 beacon_mask;
+ u8 beacon_data_mask;
+
+ u8 tbtt_count;
+ u16 beacon_int;
+
+ struct mt76x02_calibration cal;
+
+ s8 target_power;
+ s8 target_power_delta[2];
+ bool enable_tpc;
+
+ bool no_2ghz;
+
+ u8 coverage_class;
+ u8 slottime;
+
+ struct mt76x02_dfs_pattern_detector dfs_pd;
+};
+
+extern struct ieee80211_rate mt76x02_rates[12];
+
+void mt76x02_configure_filter(struct ieee80211_hw *hw,
+ unsigned int changed_flags,
+ unsigned int *total_flags, u64 multicast);
+int mt76x02_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta);
+int mt76x02_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta);
+
+void mt76x02_vif_init(struct mt76x02_dev *dev, struct ieee80211_vif *vif,
+ unsigned int idx);
+int mt76x02_add_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif);
+void mt76x02_remove_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif);
+
+int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_ampdu_params *params);
+int mt76x02_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key);
+int mt76x02_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ u16 queue, const struct ieee80211_tx_queue_params *params);
+void mt76x02_sta_rate_tbl_update(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta);
+s8 mt76x02_tx_get_max_txpwr_adj(struct mt76x02_dev *dev,
+ const struct ieee80211_tx_rate *rate);
+s8 mt76x02_tx_get_txpwr_adj(struct mt76x02_dev *dev, s8 txpwr,
+ s8 max_txpwr_adj);
+void mt76x02_tx_set_txpwr_auto(struct mt76x02_dev *dev, s8 txpwr);
+int mt76x02_insert_hdr_pad(struct sk_buff *skb);
+void mt76x02_remove_hdr_pad(struct sk_buff *skb, int len);
+void mt76x02_tx_complete(struct mt76_dev *dev, struct sk_buff *skb);
+bool mt76x02_tx_status_data(struct mt76_dev *mdev, u8 *update);
+void mt76x02_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
+ struct sk_buff *skb);
+void mt76x02_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q);
+irqreturn_t mt76x02_irq_handler(int irq, void *dev_instance);
+void mt76x02_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
+ struct sk_buff *skb);
+int mt76x02_tx_prepare_skb(struct mt76_dev *mdev, void *txwi,
+ struct sk_buff *skb, struct mt76_queue *q,
+ struct mt76_wcid *wcid, struct ieee80211_sta *sta,
+ u32 *tx_info);
+
+extern const u16 mt76x02_beacon_offsets[16];
+void mt76x02_set_beacon_offsets(struct mt76x02_dev *dev);
+void mt76x02_set_irq_mask(struct mt76x02_dev *dev, u32 clear, u32 set);
+void mt76x02_mac_start(struct mt76x02_dev *dev);
+
+static inline bool is_mt76x2(struct mt76x02_dev *dev)
+{
+ return mt76_chip(&dev->mt76) == 0x7612 ||
+ mt76_chip(&dev->mt76) == 0x7662 ||
+ mt76_chip(&dev->mt76) == 0x7602;
+}
+
+static inline void mt76x02_irq_enable(struct mt76x02_dev *dev, u32 mask)
+{
+ mt76x02_set_irq_mask(dev, 0, mask);
+}
+
+static inline void mt76x02_irq_disable(struct mt76x02_dev *dev, u32 mask)
+{
+ mt76x02_set_irq_mask(dev, mask, 0);
+}
+
+static inline bool
+mt76x02_wait_for_txrx_idle(struct mt76_dev *dev)
+{
+ return __mt76_poll_msec(dev, MT_MAC_STATUS,
+ MT_MAC_STATUS_TX | MT_MAC_STATUS_RX,
+ 0, 100);
+}
+
+static inline struct mt76x02_sta *
+mt76x02_rx_get_sta(struct mt76_dev *dev, u8 idx)
+{
+ struct mt76_wcid *wcid;
+
+ if (idx >= ARRAY_SIZE(dev->wcid))
+ return NULL;
+
+ wcid = rcu_dereference(dev->wcid[idx]);
+ if (!wcid)
+ return NULL;
+
+ return container_of(wcid, struct mt76x02_sta, wcid);
+}
+
+static inline struct mt76_wcid *
+mt76x02_rx_get_sta_wcid(struct mt76x02_sta *sta, bool unicast)
+{
+ if (!sta)
+ return NULL;
+
+ if (unicast)
+ return &sta->wcid;
+ else
+ return &sta->vif->group_wcid;
+}
+
+#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_dfs.h b/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.h
index 693f421bf096..7e177c934592 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_dfs.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.h
@@ -14,8 +14,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifndef __MT76x2_DFS_H
-#define __MT76x2_DFS_H
+#ifndef __MT76x02_DFS_H
+#define __MT76x02_DFS_H
#include <linux/types.h>
#include <linux/nl80211.h>
@@ -49,7 +49,7 @@
#define MT_DFS_ETSI_MAX_PRI (133333 + 125000 + 117647 + 1000)
#define MT_DFS_ETSI_MIN_PRI (4500 - 20)
-struct mt76x2_radar_specs {
+struct mt76x02_radar_specs {
u8 mode;
u16 avg_len;
u16 e_low;
@@ -70,7 +70,7 @@ struct mt76x2_radar_specs {
#define MT_DFS_EVENT_ENGINE(x) (((x) & BIT(31)) ? 2 : 0)
#define MT_DFS_EVENT_TIMESTAMP(x) ((x) & GENMASK(21, 0))
#define MT_DFS_EVENT_WIDTH(x) ((x) & GENMASK(11, 0))
-struct mt76x2_dfs_event {
+struct mt76x02_dfs_event {
unsigned long fetch_ts;
u32 ts;
u16 width;
@@ -78,12 +78,12 @@ struct mt76x2_dfs_event {
};
#define MT_DFS_EVENT_BUFLEN 256
-struct mt76x2_dfs_event_rb {
- struct mt76x2_dfs_event data[MT_DFS_EVENT_BUFLEN];
+struct mt76x02_dfs_event_rb {
+ struct mt76x02_dfs_event data[MT_DFS_EVENT_BUFLEN];
int h_rb, t_rb;
};
-struct mt76x2_dfs_sequence {
+struct mt76x02_dfs_sequence {
struct list_head head;
u32 first_ts;
u32 last_ts;
@@ -92,7 +92,7 @@ struct mt76x2_dfs_sequence {
u8 engine;
};
-struct mt76x2_dfs_hw_pulse {
+struct mt76x02_dfs_hw_pulse {
u8 engine;
u32 period;
u32 w1;
@@ -100,47 +100,41 @@ struct mt76x2_dfs_hw_pulse {
u32 burst;
};
-struct mt76x2_dfs_sw_detector_params {
+struct mt76x02_dfs_sw_detector_params {
u32 min_pri;
u32 max_pri;
u32 pri_margin;
};
-struct mt76x2_dfs_engine_stats {
+struct mt76x02_dfs_engine_stats {
u32 hw_pattern;
u32 hw_pulse_discarded;
u32 sw_pattern;
};
-struct mt76x2_dfs_seq_stats {
+struct mt76x02_dfs_seq_stats {
u32 seq_pool_len;
u32 seq_len;
};
-struct mt76x2_dfs_pattern_detector {
+struct mt76x02_dfs_pattern_detector {
enum nl80211_dfs_regions region;
u8 chirp_pulse_cnt;
u32 chirp_pulse_ts;
- struct mt76x2_dfs_sw_detector_params sw_dpd_params;
- struct mt76x2_dfs_event_rb event_rb[2];
+ struct mt76x02_dfs_sw_detector_params sw_dpd_params;
+ struct mt76x02_dfs_event_rb event_rb[2];
struct list_head sequences;
struct list_head seq_pool;
- struct mt76x2_dfs_seq_stats seq_stats;
+ struct mt76x02_dfs_seq_stats seq_stats;
unsigned long last_sw_check;
u32 last_event_ts;
- struct mt76x2_dfs_engine_stats stats[MT_DFS_NUM_ENGINES];
+ struct mt76x02_dfs_engine_stats stats[MT_DFS_NUM_ENGINES];
struct tasklet_struct dfs_tasklet;
};
-void mt76x2_dfs_init_params(struct mt76x2_dev *dev);
-void mt76x2_dfs_init_detector(struct mt76x2_dev *dev);
-void mt76x2_dfs_adjust_agc(struct mt76x2_dev *dev);
-void mt76x2_dfs_set_domain(struct mt76x2_dev *dev,
- enum nl80211_dfs_regions region);
-
-#endif /* __MT76x2_DFS_H */
+#endif /* __MT76x02_DFS_H */
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h b/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h
new file mode 100644
index 000000000000..6394010a565f
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __MT76x02_DMA_H
+#define __MT76x02_DMA_H
+
+#include "mt76x02.h"
+#include "dma.h"
+
+#define MT_TXD_INFO_LEN GENMASK(15, 0)
+#define MT_TXD_INFO_NEXT_VLD BIT(16)
+#define MT_TXD_INFO_TX_BURST BIT(17)
+#define MT_TXD_INFO_80211 BIT(19)
+#define MT_TXD_INFO_TSO BIT(20)
+#define MT_TXD_INFO_CSO BIT(21)
+#define MT_TXD_INFO_WIV BIT(24)
+#define MT_TXD_INFO_QSEL GENMASK(26, 25)
+#define MT_TXD_INFO_DPORT GENMASK(29, 27)
+#define MT_TXD_INFO_TYPE GENMASK(31, 30)
+
+#define MT_RX_FCE_INFO_LEN GENMASK(13, 0)
+#define MT_RX_FCE_INFO_SELF_GEN BIT(15)
+#define MT_RX_FCE_INFO_CMD_SEQ GENMASK(19, 16)
+#define MT_RX_FCE_INFO_EVT_TYPE GENMASK(23, 20)
+#define MT_RX_FCE_INFO_PCIE_INTR BIT(24)
+#define MT_RX_FCE_INFO_QSEL GENMASK(26, 25)
+#define MT_RX_FCE_INFO_D_PORT GENMASK(29, 27)
+#define MT_RX_FCE_INFO_TYPE GENMASK(31, 30)
+
+/* MCU request message header */
+#define MT_MCU_MSG_LEN GENMASK(15, 0)
+#define MT_MCU_MSG_CMD_SEQ GENMASK(19, 16)
+#define MT_MCU_MSG_CMD_TYPE GENMASK(26, 20)
+#define MT_MCU_MSG_PORT GENMASK(29, 27)
+#define MT_MCU_MSG_TYPE GENMASK(31, 30)
+#define MT_MCU_MSG_TYPE_CMD BIT(30)
+
+#define MT_RX_HEADROOM 32
+#define MT76X02_RX_RING_SIZE 256
+
+enum dma_msg_port {
+ WLAN_PORT,
+ CPU_RX_PORT,
+ CPU_TX_PORT,
+ HOST_PORT,
+ VIRTUAL_CPU_RX_PORT,
+ VIRTUAL_CPU_TX_PORT,
+ DISCARD,
+};
+
+static inline bool
+mt76x02_wait_for_wpdma(struct mt76_dev *dev, int timeout)
+{
+ return __mt76_poll(dev, MT_WPDMA_GLO_CFG,
+ MT_WPDMA_GLO_CFG_TX_DMA_BUSY |
+ MT_WPDMA_GLO_CFG_RX_DMA_BUSY,
+ 0, timeout);
+}
+
+int mt76x02_dma_init(struct mt76x02_dev *dev);
+void mt76x02_dma_disable(struct mt76x02_dev *dev);
+void mt76x02_dma_cleanup(struct mt76x02_dev *dev);
+
+#endif /* __MT76x02_DMA_H */
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.c
new file mode 100644
index 000000000000..9390de2a323e
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
+ * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <asm/unaligned.h>
+
+#include "mt76x02_eeprom.h"
+
+static int
+mt76x02_efuse_read(struct mt76x02_dev *dev, u16 addr, u8 *data,
+ enum mt76x02_eeprom_modes mode)
+{
+ u32 val;
+ int i;
+
+ val = mt76_rr(dev, MT_EFUSE_CTRL);
+ val &= ~(MT_EFUSE_CTRL_AIN |
+ MT_EFUSE_CTRL_MODE);
+ val |= FIELD_PREP(MT_EFUSE_CTRL_AIN, addr & ~0xf);
+ val |= FIELD_PREP(MT_EFUSE_CTRL_MODE, mode);
+ val |= MT_EFUSE_CTRL_KICK;
+ mt76_wr(dev, MT_EFUSE_CTRL, val);
+
+ if (!mt76_poll_msec(dev, MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK, 0, 1000))
+ return -ETIMEDOUT;
+
+ udelay(2);
+
+ val = mt76_rr(dev, MT_EFUSE_CTRL);
+ if ((val & MT_EFUSE_CTRL_AOUT) == MT_EFUSE_CTRL_AOUT) {
+ memset(data, 0xff, 16);
+ return 0;
+ }
+
+ for (i = 0; i < 4; i++) {
+ val = mt76_rr(dev, MT_EFUSE_DATA(i));
+ put_unaligned_le32(val, data + 4 * i);
+ }
+
+ return 0;
+}
+
+int mt76x02_get_efuse_data(struct mt76x02_dev *dev, u16 base, void *buf,
+ int len, enum mt76x02_eeprom_modes mode)
+{
+ int ret, i;
+
+ for (i = 0; i + 16 <= len; i += 16) {
+ ret = mt76x02_efuse_read(dev, base + i, buf + i, mode);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt76x02_get_efuse_data);
+
+void mt76x02_eeprom_parse_hw_cap(struct mt76x02_dev *dev)
+{
+ u16 val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_0);
+
+ switch (FIELD_GET(MT_EE_NIC_CONF_0_BOARD_TYPE, val)) {
+ case BOARD_TYPE_5GHZ:
+ dev->mt76.cap.has_5ghz = true;
+ break;
+ case BOARD_TYPE_2GHZ:
+ dev->mt76.cap.has_2ghz = true;
+ break;
+ default:
+ dev->mt76.cap.has_2ghz = true;
+ dev->mt76.cap.has_5ghz = true;
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(mt76x02_eeprom_parse_hw_cap);
+
+bool mt76x02_ext_pa_enabled(struct mt76x02_dev *dev, enum nl80211_band band)
+{
+ u16 conf0 = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_0);
+
+ if (band == NL80211_BAND_5GHZ)
+ return !(conf0 & MT_EE_NIC_CONF_0_PA_INT_5G);
+ else
+ return !(conf0 & MT_EE_NIC_CONF_0_PA_INT_2G);
+}
+EXPORT_SYMBOL_GPL(mt76x02_ext_pa_enabled);
+
+void mt76x02_get_rx_gain(struct mt76x02_dev *dev, enum nl80211_band band,
+ u16 *rssi_offset, s8 *lna_2g, s8 *lna_5g)
+{
+ u16 val;
+
+ val = mt76x02_eeprom_get(dev, MT_EE_LNA_GAIN);
+ *lna_2g = val & 0xff;
+ lna_5g[0] = val >> 8;
+
+ val = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_2G_1);
+ lna_5g[1] = val >> 8;
+
+ val = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_5G_1);
+ lna_5g[2] = val >> 8;
+
+ if (!mt76x02_field_valid(lna_5g[1]))
+ lna_5g[1] = lna_5g[0];
+
+ if (!mt76x02_field_valid(lna_5g[2]))
+ lna_5g[2] = lna_5g[0];
+
+ if (band == NL80211_BAND_2GHZ)
+ *rssi_offset = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_2G_0);
+ else
+ *rssi_offset = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_5G_0);
+}
+EXPORT_SYMBOL_GPL(mt76x02_get_rx_gain);
+
+u8 mt76x02_get_lna_gain(struct mt76x02_dev *dev,
+ s8 *lna_2g, s8 *lna_5g,
+ struct ieee80211_channel *chan)
+{
+ u16 val;
+ u8 lna;
+
+ val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1);
+ if (val & MT_EE_NIC_CONF_1_LNA_EXT_2G)
+ *lna_2g = 0;
+ if (val & MT_EE_NIC_CONF_1_LNA_EXT_5G)
+ memset(lna_5g, 0, sizeof(s8) * 3);
+
+ if (chan->band == NL80211_BAND_2GHZ)
+ lna = *lna_2g;
+ else if (chan->hw_value <= 64)
+ lna = lna_5g[0];
+ else if (chan->hw_value <= 128)
+ lna = lna_5g[1];
+ else
+ lna = lna_5g[2];
+
+ return lna != 0xff ? lna : 0;
+}
+EXPORT_SYMBOL_GPL(mt76x02_get_lna_gain);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h
index 0f3e4d2f4fee..b3ec74835d10 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
+ * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -14,18 +15,21 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifndef __MT76x2_EEPROM_H
-#define __MT76x2_EEPROM_H
+#ifndef __MT76x02_EEPROM_H
+#define __MT76x02_EEPROM_H
-#include "mt76x2.h"
+#include "mt76x02.h"
-enum mt76x2_eeprom_field {
+enum mt76x02_eeprom_field {
MT_EE_CHIP_ID = 0x000,
MT_EE_VERSION = 0x002,
MT_EE_MAC_ADDR = 0x004,
MT_EE_PCI_ID = 0x00A,
MT_EE_NIC_CONF_0 = 0x034,
MT_EE_NIC_CONF_1 = 0x036,
+ MT_EE_COUNTRY_REGION_5GHZ = 0x038,
+ MT_EE_COUNTRY_REGION_2GHZ = 0x039,
+ MT_EE_FREQ_OFFSET = 0x03a,
MT_EE_NIC_CONF_2 = 0x042,
MT_EE_XTAL_TRIM_1 = 0x03a,
@@ -34,8 +38,10 @@ enum mt76x2_eeprom_field {
MT_EE_LNA_GAIN = 0x044,
MT_EE_RSSI_OFFSET_2G_0 = 0x046,
MT_EE_RSSI_OFFSET_2G_1 = 0x048,
+ MT_EE_LNA_GAIN_5GHZ_1 = 0x049,
MT_EE_RSSI_OFFSET_5G_0 = 0x04a,
MT_EE_RSSI_OFFSET_5G_1 = 0x04c,
+ MT_EE_LNA_GAIN_5GHZ_2 = 0x04d,
MT_EE_TX_POWER_DELTA_BW40 = 0x050,
MT_EE_TX_POWER_DELTA_BW80 = 0x052,
@@ -68,6 +74,17 @@ enum mt76x2_eeprom_field {
MT_EE_TX_POWER_VHT_MCS4 = 0x0bc,
MT_EE_TX_POWER_VHT_MCS8 = 0x0be,
+ MT_EE_2G_TARGET_POWER = 0x0d0,
+ MT_EE_TEMP_OFFSET = 0x0d1,
+ MT_EE_5G_TARGET_POWER = 0x0d2,
+ MT_EE_TSSI_BOUND1 = 0x0d4,
+ MT_EE_TSSI_BOUND2 = 0x0d6,
+ MT_EE_TSSI_BOUND3 = 0x0d8,
+ MT_EE_TSSI_BOUND4 = 0x0da,
+ MT_EE_FREQ_OFFSET_COMPENSATION = 0x0db,
+ MT_EE_TSSI_BOUND5 = 0x0dc,
+ MT_EE_TX_POWER_BYRATE_BASE = 0x0de,
+
MT_EE_RF_TEMP_COMP_SLOPE_5G = 0x0f2,
MT_EE_RF_TEMP_COMP_SLOPE_2G = 0x0f4,
@@ -81,13 +98,21 @@ enum mt76x2_eeprom_field {
MT_EE_BT_VCDL_CALIBRATION = 0x13c,
MT_EE_BT_PMUCFG = 0x13e,
+ MT_EE_USAGE_MAP_START = 0x1e0,
+ MT_EE_USAGE_MAP_END = 0x1fc,
+
__MT_EE_MAX
};
+#define MT_EE_NIC_CONF_0_RX_PATH GENMASK(3, 0)
+#define MT_EE_NIC_CONF_0_TX_PATH GENMASK(7, 4)
+#define MT_EE_NIC_CONF_0_PA_TYPE GENMASK(9, 8)
#define MT_EE_NIC_CONF_0_PA_INT_2G BIT(8)
#define MT_EE_NIC_CONF_0_PA_INT_5G BIT(9)
+#define MT_EE_NIC_CONF_0_PA_IO_CURRENT BIT(10)
#define MT_EE_NIC_CONF_0_BOARD_TYPE GENMASK(13, 12)
+#define MT_EE_NIC_CONF_1_HW_RF_CTRL BIT(0)
#define MT_EE_NIC_CONF_1_TEMP_TX_ALC BIT(1)
#define MT_EE_NIC_CONF_1_LNA_EXT_2G BIT(2)
#define MT_EE_NIC_CONF_1_LNA_EXT_5G BIT(3)
@@ -100,93 +125,68 @@ enum mt76x2_eeprom_field {
#define MT_EE_NIC_CONF_2_TEMP_DISABLE BIT(11)
#define MT_EE_NIC_CONF_2_COEX_METHOD GENMASK(15, 13)
-enum mt76x2_board_type {
- BOARD_TYPE_2GHZ = 1,
- BOARD_TYPE_5GHZ = 2,
-};
+#define MT_EFUSE_USAGE_MAP_SIZE (MT_EE_USAGE_MAP_END - \
+ MT_EE_USAGE_MAP_START + 1)
-enum mt76x2_cal_channel_group {
- MT_CH_5G_JAPAN,
- MT_CH_5G_UNII_1,
- MT_CH_5G_UNII_2,
- MT_CH_5G_UNII_2E_1,
- MT_CH_5G_UNII_2E_2,
- MT_CH_5G_UNII_3,
- __MT_CH_MAX
+enum mt76x02_eeprom_modes {
+ MT_EE_READ,
+ MT_EE_PHYSICAL_READ,
};
-struct mt76x2_tx_power_info {
- u8 target_power;
-
- s8 delta_bw40;
- s8 delta_bw80;
-
- struct {
- s8 tssi_slope;
- s8 tssi_offset;
- s8 target_power;
- s8 delta;
- } chain[MT_MAX_CHAINS];
+enum mt76x02_board_type {
+ BOARD_TYPE_2GHZ = 1,
+ BOARD_TYPE_5GHZ = 2,
};
-struct mt76x2_temp_comp {
- u8 temp_25_ref;
- int lower_bound; /* J */
- int upper_bound; /* J */
- unsigned int high_slope; /* J / dB */
- unsigned int low_slope; /* J / dB */
-};
+static inline bool mt76x02_field_valid(u8 val)
+{
+ return val != 0 && val != 0xff;
+}
static inline int
-mt76x2_eeprom_get(struct mt76x2_dev *dev, enum mt76x2_eeprom_field field)
+mt76x02_sign_extend(u32 val, unsigned int size)
{
- if ((field & 1) || field >= __MT_EE_MAX)
- return -1;
+ bool sign = val & BIT(size - 1);
- return get_unaligned_le16(dev->mt76.eeprom.data + field);
+ val &= BIT(size - 1) - 1;
+
+ return sign ? val : -val;
}
-void mt76x2_get_rate_power(struct mt76x2_dev *dev, struct mt76_rate_power *t,
- struct ieee80211_channel *chan);
-int mt76x2_get_max_rate_power(struct mt76_rate_power *r);
-void mt76x2_get_power_info(struct mt76x2_dev *dev,
- struct mt76x2_tx_power_info *t,
- struct ieee80211_channel *chan);
-int mt76x2_get_temp_comp(struct mt76x2_dev *dev, struct mt76x2_temp_comp *t);
-bool mt76x2_ext_pa_enabled(struct mt76x2_dev *dev, enum nl80211_band band);
-void mt76x2_read_rx_gain(struct mt76x2_dev *dev);
-void mt76x2_eeprom_parse_hw_cap(struct mt76x2_dev *dev);
-
-static inline bool
-mt76x2_temp_tx_alc_enabled(struct mt76x2_dev *dev)
+static inline int
+mt76x02_sign_extend_optional(u32 val, unsigned int size)
{
- u16 val;
-
- val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_EXT_PA_5G);
- if (!(val & BIT(15)))
- return false;
+ bool enable = val & BIT(size);
- return mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_1) &
- MT_EE_NIC_CONF_1_TEMP_TX_ALC;
+ return enable ? mt76x02_sign_extend(val, size) : 0;
}
-static inline bool
-mt76x2_tssi_enabled(struct mt76x2_dev *dev)
+static inline s8 mt76x02_rate_power_val(u8 val)
{
- return !mt76x2_temp_tx_alc_enabled(dev) &&
- (mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_1) &
- MT_EE_NIC_CONF_1_TX_ALC_EN);
+ if (!mt76x02_field_valid(val))
+ return 0;
+
+ return mt76x02_sign_extend_optional(val, 7);
}
-static inline bool
-mt76x2_has_ext_lna(struct mt76x2_dev *dev)
+static inline int
+mt76x02_eeprom_get(struct mt76x02_dev *dev,
+ enum mt76x02_eeprom_field field)
{
- u32 val = mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_1);
+ if ((field & 1) || field >= __MT_EE_MAX)
+ return -1;
- if (dev->mt76.chandef.chan->band == NL80211_BAND_2GHZ)
- return val & MT_EE_NIC_CONF_1_LNA_EXT_2G;
- else
- return val & MT_EE_NIC_CONF_1_LNA_EXT_5G;
+ return get_unaligned_le16(dev->mt76.eeprom.data + field);
}
-#endif
+bool mt76x02_ext_pa_enabled(struct mt76x02_dev *dev, enum nl80211_band band);
+int mt76x02_get_efuse_data(struct mt76x02_dev *dev, u16 base, void *buf,
+ int len, enum mt76x02_eeprom_modes mode);
+void mt76x02_get_rx_gain(struct mt76x02_dev *dev, enum nl80211_band band,
+ u16 *rssi_offset, s8 *lna_2g, s8 *lna_5g);
+u8 mt76x02_get_lna_gain(struct mt76x02_dev *dev,
+ s8 *lna_2g, s8 *lna_5g,
+ struct ieee80211_channel *chan);
+void mt76x02_eeprom_parse_hw_cap(struct mt76x02_dev *dev);
+
+#endif /* __MT76x02_EEPROM_H */
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
index 6542644bc325..10578e4cb269 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac_common.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
- * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
+ * Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -15,222 +15,11 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include "mt76x2.h"
+#include "mt76x02.h"
+#include "mt76x02_trace.h"
-void mt76x2_mac_stop(struct mt76x2_dev *dev, bool force)
-{
- bool stopped = false;
- u32 rts_cfg;
- int i;
-
- mt76_wr(dev, MT_MAC_SYS_CTRL, 0);
-
- rts_cfg = mt76_rr(dev, MT_TX_RTS_CFG);
- mt76_wr(dev, MT_TX_RTS_CFG, rts_cfg & ~MT_TX_RTS_CFG_RETRY_LIMIT);
-
- /* Wait for MAC to become idle */
- for (i = 0; i < 300; i++) {
- if ((mt76_rr(dev, MT_MAC_STATUS) &
- (MT_MAC_STATUS_RX | MT_MAC_STATUS_TX)) ||
- mt76_rr(dev, MT_BBP(IBI, 12))) {
- udelay(1);
- continue;
- }
-
- stopped = true;
- break;
- }
-
- if (force && !stopped) {
- mt76_set(dev, MT_BBP(CORE, 4), BIT(1));
- mt76_clear(dev, MT_BBP(CORE, 4), BIT(1));
-
- mt76_set(dev, MT_BBP(CORE, 4), BIT(0));
- mt76_clear(dev, MT_BBP(CORE, 4), BIT(0));
- }
-
- mt76_wr(dev, MT_TX_RTS_CFG, rts_cfg);
-}
-EXPORT_SYMBOL_GPL(mt76x2_mac_stop);
-
-bool mt76x2_mac_load_tx_status(struct mt76x2_dev *dev,
- struct mt76x2_tx_status *stat)
-{
- u32 stat1, stat2;
-
- stat2 = mt76_rr(dev, MT_TX_STAT_FIFO_EXT);
- stat1 = mt76_rr(dev, MT_TX_STAT_FIFO);
-
- stat->valid = !!(stat1 & MT_TX_STAT_FIFO_VALID);
- if (!stat->valid)
- return false;
-
- stat->success = !!(stat1 & MT_TX_STAT_FIFO_SUCCESS);
- stat->aggr = !!(stat1 & MT_TX_STAT_FIFO_AGGR);
- stat->ack_req = !!(stat1 & MT_TX_STAT_FIFO_ACKREQ);
- stat->wcid = FIELD_GET(MT_TX_STAT_FIFO_WCID, stat1);
- stat->rate = FIELD_GET(MT_TX_STAT_FIFO_RATE, stat1);
-
- stat->retry = FIELD_GET(MT_TX_STAT_FIFO_EXT_RETRY, stat2);
- stat->pktid = FIELD_GET(MT_TX_STAT_FIFO_EXT_PKTID, stat2);
-
- return true;
-}
-EXPORT_SYMBOL_GPL(mt76x2_mac_load_tx_status);
-
-static int
-mt76x2_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate,
- enum nl80211_band band)
-{
- u8 idx = FIELD_GET(MT_RXWI_RATE_INDEX, rate);
-
- txrate->idx = 0;
- txrate->flags = 0;
- txrate->count = 1;
-
- switch (FIELD_GET(MT_RXWI_RATE_PHY, rate)) {
- case MT_PHY_TYPE_OFDM:
- if (band == NL80211_BAND_2GHZ)
- idx += 4;
-
- txrate->idx = idx;
- return 0;
- case MT_PHY_TYPE_CCK:
- if (idx >= 8)
- idx -= 8;
-
- txrate->idx = idx;
- return 0;
- case MT_PHY_TYPE_HT_GF:
- txrate->flags |= IEEE80211_TX_RC_GREEN_FIELD;
- /* fall through */
- case MT_PHY_TYPE_HT:
- txrate->flags |= IEEE80211_TX_RC_MCS;
- txrate->idx = idx;
- break;
- case MT_PHY_TYPE_VHT:
- txrate->flags |= IEEE80211_TX_RC_VHT_MCS;
- txrate->idx = idx;
- break;
- default:
- return -EINVAL;
- }
-
- switch (FIELD_GET(MT_RXWI_RATE_BW, rate)) {
- case MT_PHY_BW_20:
- break;
- case MT_PHY_BW_40:
- txrate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
- break;
- case MT_PHY_BW_80:
- txrate->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH;
- break;
- default:
- return -EINVAL;
- }
-
- if (rate & MT_RXWI_RATE_SGI)
- txrate->flags |= IEEE80211_TX_RC_SHORT_GI;
-
- return 0;
-}
-
-static void
-mt76x2_mac_fill_tx_status(struct mt76x2_dev *dev,
- struct ieee80211_tx_info *info,
- struct mt76x2_tx_status *st, int n_frames)
-{
- struct ieee80211_tx_rate *rate = info->status.rates;
- int cur_idx, last_rate;
- int i;
-
- if (!n_frames)
- return;
-
- last_rate = min_t(int, st->retry, IEEE80211_TX_MAX_RATES - 1);
- mt76x2_mac_process_tx_rate(&rate[last_rate], st->rate,
- dev->mt76.chandef.chan->band);
- if (last_rate < IEEE80211_TX_MAX_RATES - 1)
- rate[last_rate + 1].idx = -1;
-
- cur_idx = rate[last_rate].idx + last_rate;
- for (i = 0; i <= last_rate; i++) {
- rate[i].flags = rate[last_rate].flags;
- rate[i].idx = max_t(int, 0, cur_idx - i);
- rate[i].count = 1;
- }
- rate[last_rate].count = st->retry + 1 - last_rate;
-
- info->status.ampdu_len = n_frames;
- info->status.ampdu_ack_len = st->success ? n_frames : 0;
-
- if (st->pktid & MT_TXWI_PKTID_PROBE)
- info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
-
- if (st->aggr)
- info->flags |= IEEE80211_TX_CTL_AMPDU |
- IEEE80211_TX_STAT_AMPDU;
-
- if (!st->ack_req)
- info->flags |= IEEE80211_TX_CTL_NO_ACK;
- else if (st->success)
- info->flags |= IEEE80211_TX_STAT_ACK;
-}
-
-void mt76x2_send_tx_status(struct mt76x2_dev *dev,
- struct mt76x2_tx_status *stat, u8 *update)
-{
- struct ieee80211_tx_info info = {};
- struct ieee80211_sta *sta = NULL;
- struct mt76_wcid *wcid = NULL;
- struct mt76x2_sta *msta = NULL;
-
- rcu_read_lock();
- if (stat->wcid < ARRAY_SIZE(dev->wcid))
- wcid = rcu_dereference(dev->wcid[stat->wcid]);
-
- if (wcid) {
- void *priv;
-
- priv = msta = container_of(wcid, struct mt76x2_sta, wcid);
- sta = container_of(priv, struct ieee80211_sta,
- drv_priv);
- }
-
- if (msta && stat->aggr) {
- u32 stat_val, stat_cache;
-
- stat_val = stat->rate;
- stat_val |= ((u32) stat->retry) << 16;
- stat_cache = msta->status.rate;
- stat_cache |= ((u32) msta->status.retry) << 16;
-
- if (*update == 0 && stat_val == stat_cache &&
- stat->wcid == msta->status.wcid && msta->n_frames < 32) {
- msta->n_frames++;
- goto out;
- }
-
- mt76x2_mac_fill_tx_status(dev, &info, &msta->status,
- msta->n_frames);
-
- msta->status = *stat;
- msta->n_frames = 1;
- *update = 0;
- } else {
- mt76x2_mac_fill_tx_status(dev, &info, stat, 1);
- *update = 1;
- }
-
- ieee80211_tx_status_noskb(mt76_hw(dev), sta, &info);
-
-out:
- rcu_read_unlock();
-}
-EXPORT_SYMBOL_GPL(mt76x2_send_tx_status);
-
-static enum mt76x2_cipher_type
-mt76x2_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data)
+enum mt76x02_cipher_type
+mt76x02_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data)
{
memset(key_data, 0, 32);
if (!key)
@@ -254,15 +43,16 @@ mt76x2_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data)
return MT_CIPHER_NONE;
}
}
+EXPORT_SYMBOL_GPL(mt76x02_mac_get_key_info);
-int mt76x2_mac_shared_key_setup(struct mt76x2_dev *dev, u8 vif_idx, u8 key_idx,
- struct ieee80211_key_conf *key)
+int mt76x02_mac_shared_key_setup(struct mt76x02_dev *dev, u8 vif_idx,
+ u8 key_idx, struct ieee80211_key_conf *key)
{
- enum mt76x2_cipher_type cipher;
+ enum mt76x02_cipher_type cipher;
u8 key_data[32];
u32 val;
- cipher = mt76x2_mac_get_key_info(key, key_data);
+ cipher = mt76x02_mac_get_key_info(key, key_data);
if (cipher == MT_CIPHER_NONE && key)
return -EOPNOTSUPP;
@@ -276,21 +66,21 @@ int mt76x2_mac_shared_key_setup(struct mt76x2_dev *dev, u8 vif_idx, u8 key_idx,
return 0;
}
-EXPORT_SYMBOL_GPL(mt76x2_mac_shared_key_setup);
+EXPORT_SYMBOL_GPL(mt76x02_mac_shared_key_setup);
-int mt76x2_mac_wcid_set_key(struct mt76x2_dev *dev, u8 idx,
- struct ieee80211_key_conf *key)
+int mt76x02_mac_wcid_set_key(struct mt76x02_dev *dev, u8 idx,
+ struct ieee80211_key_conf *key)
{
- enum mt76x2_cipher_type cipher;
+ enum mt76x02_cipher_type cipher;
u8 key_data[32];
u8 iv_data[8];
- cipher = mt76x2_mac_get_key_info(key, key_data);
+ cipher = mt76x02_mac_get_key_info(key, key_data);
if (cipher == MT_CIPHER_NONE && key)
return -EOPNOTSUPP;
- mt76_rmw_field(dev, MT_WCID_ATTR(idx), MT_WCID_ATTR_PKEY_MODE, cipher);
mt76_wr_copy(dev, MT_WCID_KEY(idx), key_data, sizeof(key_data));
+ mt76_rmw_field(dev, MT_WCID_ATTR(idx), MT_WCID_ATTR_PKEY_MODE, cipher);
memset(iv_data, 0, sizeof(iv_data));
if (key) {
@@ -305,11 +95,70 @@ int mt76x2_mac_wcid_set_key(struct mt76x2_dev *dev, u8 idx,
return 0;
}
-EXPORT_SYMBOL_GPL(mt76x2_mac_wcid_set_key);
+EXPORT_SYMBOL_GPL(mt76x02_mac_wcid_set_key);
+
+void mt76x02_mac_wcid_setup(struct mt76x02_dev *dev, u8 idx,
+ u8 vif_idx, u8 *mac)
+{
+ struct mt76_wcid_addr addr = {};
+ u32 attr;
+
+ attr = FIELD_PREP(MT_WCID_ATTR_BSS_IDX, vif_idx & 7) |
+ FIELD_PREP(MT_WCID_ATTR_BSS_IDX_EXT, !!(vif_idx & 8));
+
+ mt76_wr(dev, MT_WCID_ATTR(idx), attr);
+
+ mt76_wr(dev, MT_WCID_TX_RATE(idx), 0);
+ mt76_wr(dev, MT_WCID_TX_RATE(idx) + 4, 0);
+
+ if (idx >= 128)
+ return;
+
+ if (mac)
+ memcpy(addr.macaddr, mac, ETH_ALEN);
+
+ mt76_wr_copy(dev, MT_WCID_ADDR(idx), &addr, sizeof(addr));
+}
+EXPORT_SYMBOL_GPL(mt76x02_mac_wcid_setup);
+
+void mt76x02_mac_wcid_set_drop(struct mt76x02_dev *dev, u8 idx, bool drop)
+{
+ u32 val = mt76_rr(dev, MT_WCID_DROP(idx));
+ u32 bit = MT_WCID_DROP_MASK(idx);
+
+ /* prevent unnecessary writes */
+ if ((val & bit) != (bit * drop))
+ mt76_wr(dev, MT_WCID_DROP(idx), (val & ~bit) | (bit * drop));
+}
+EXPORT_SYMBOL_GPL(mt76x02_mac_wcid_set_drop);
+
+void mt76x02_txq_init(struct mt76x02_dev *dev, struct ieee80211_txq *txq)
+{
+ struct mt76_txq *mtxq;
+
+ if (!txq)
+ return;
+
+ mtxq = (struct mt76_txq *) txq->drv_priv;
+ if (txq->sta) {
+ struct mt76x02_sta *sta;
+
+ sta = (struct mt76x02_sta *) txq->sta->drv_priv;
+ mtxq->wcid = &sta->wcid;
+ } else {
+ struct mt76x02_vif *mvif;
+
+ mvif = (struct mt76x02_vif *) txq->vif->drv_priv;
+ mtxq->wcid = &mvif->group_wcid;
+ }
+
+ mt76_txq_init(&dev->mt76, txq);
+}
+EXPORT_SYMBOL_GPL(mt76x02_txq_init);
static __le16
-mt76x2_mac_tx_rate_val(struct mt76x2_dev *dev,
- const struct ieee80211_tx_rate *rate, u8 *nss_val)
+mt76x02_mac_tx_rate_val(struct mt76x02_dev *dev,
+ const struct ieee80211_tx_rate *rate, u8 *nss_val)
{
u16 rateval;
u8 phy, rate_idx;
@@ -337,7 +186,7 @@ mt76x2_mac_tx_rate_val(struct mt76x2_dev *dev,
int band = dev->mt76.chandef.chan->band;
u16 val;
- r = &mt76_hw(dev)->wiphy->bands[band]->bitrates[rate->idx];
+ r = &dev->mt76.hw->wiphy->bands[band]->bitrates[rate->idx];
if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
val = r->hw_value_short;
else
@@ -358,29 +207,110 @@ mt76x2_mac_tx_rate_val(struct mt76x2_dev *dev,
return cpu_to_le16(rateval);
}
-void mt76x2_mac_wcid_set_rate(struct mt76x2_dev *dev, struct mt76_wcid *wcid,
- const struct ieee80211_tx_rate *rate)
+void mt76x02_mac_wcid_set_rate(struct mt76x02_dev *dev, struct mt76_wcid *wcid,
+ const struct ieee80211_tx_rate *rate)
{
spin_lock_bh(&dev->mt76.lock);
- wcid->tx_rate = mt76x2_mac_tx_rate_val(dev, rate, &wcid->tx_rate_nss);
+ wcid->tx_rate = mt76x02_mac_tx_rate_val(dev, rate, &wcid->tx_rate_nss);
wcid->tx_rate_set = true;
spin_unlock_bh(&dev->mt76.lock);
}
-EXPORT_SYMBOL_GPL(mt76x2_mac_wcid_set_rate);
-void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x2_txwi *txwi,
- struct sk_buff *skb, struct mt76_wcid *wcid,
- struct ieee80211_sta *sta, int len)
+bool mt76x02_mac_load_tx_status(struct mt76x02_dev *dev,
+ struct mt76x02_tx_status *stat)
{
+ u32 stat1, stat2;
+
+ stat2 = mt76_rr(dev, MT_TX_STAT_FIFO_EXT);
+ stat1 = mt76_rr(dev, MT_TX_STAT_FIFO);
+
+ stat->valid = !!(stat1 & MT_TX_STAT_FIFO_VALID);
+ if (!stat->valid)
+ return false;
+
+ stat->success = !!(stat1 & MT_TX_STAT_FIFO_SUCCESS);
+ stat->aggr = !!(stat1 & MT_TX_STAT_FIFO_AGGR);
+ stat->ack_req = !!(stat1 & MT_TX_STAT_FIFO_ACKREQ);
+ stat->wcid = FIELD_GET(MT_TX_STAT_FIFO_WCID, stat1);
+ stat->rate = FIELD_GET(MT_TX_STAT_FIFO_RATE, stat1);
+
+ stat->retry = FIELD_GET(MT_TX_STAT_FIFO_EXT_RETRY, stat2);
+ stat->pktid = FIELD_GET(MT_TX_STAT_FIFO_EXT_PKTID, stat2);
+
+ return true;
+}
+EXPORT_SYMBOL_GPL(mt76x02_mac_load_tx_status);
+
+static int
+mt76x02_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate,
+ enum nl80211_band band)
+{
+ u8 idx = FIELD_GET(MT_RXWI_RATE_INDEX, rate);
+
+ txrate->idx = 0;
+ txrate->flags = 0;
+ txrate->count = 1;
+
+ switch (FIELD_GET(MT_RXWI_RATE_PHY, rate)) {
+ case MT_PHY_TYPE_OFDM:
+ if (band == NL80211_BAND_2GHZ)
+ idx += 4;
+
+ txrate->idx = idx;
+ return 0;
+ case MT_PHY_TYPE_CCK:
+ if (idx >= 8)
+ idx -= 8;
+
+ txrate->idx = idx;
+ return 0;
+ case MT_PHY_TYPE_HT_GF:
+ txrate->flags |= IEEE80211_TX_RC_GREEN_FIELD;
+ /* fall through */
+ case MT_PHY_TYPE_HT:
+ txrate->flags |= IEEE80211_TX_RC_MCS;
+ txrate->idx = idx;
+ break;
+ case MT_PHY_TYPE_VHT:
+ txrate->flags |= IEEE80211_TX_RC_VHT_MCS;
+ txrate->idx = idx;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (FIELD_GET(MT_RXWI_RATE_BW, rate)) {
+ case MT_PHY_BW_20:
+ break;
+ case MT_PHY_BW_40:
+ txrate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
+ break;
+ case MT_PHY_BW_80:
+ txrate->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (rate & MT_RXWI_RATE_SGI)
+ txrate->flags |= IEEE80211_TX_RC_SHORT_GI;
+
+ return 0;
+}
+
+void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi,
+ struct sk_buff *skb, struct mt76_wcid *wcid,
+ struct ieee80211_sta *sta, int len)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_tx_rate *rate = &info->control.rates[0];
struct ieee80211_key_conf *key = info->control.hw_key;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
u16 rate_ht_mask = FIELD_PREP(MT_RXWI_RATE_PHY, BIT(1) | BIT(2));
u16 txwi_flags = 0;
u8 nss;
s8 txpwr_adj, max_txpwr_adj;
- u8 ccmp_pn[8];
+ u8 ccmp_pn[8], nstreams = dev->mt76.chainmask & 0xf;
memset(txwi, 0, sizeof(*txwi));
@@ -411,22 +341,22 @@ void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x2_txwi *txwi,
max_txpwr_adj = wcid->max_txpwr_adj;
nss = wcid->tx_rate_nss;
} else {
- txwi->rate = mt76x2_mac_tx_rate_val(dev, rate, &nss);
- max_txpwr_adj = mt76x2_tx_get_max_txpwr_adj(dev, rate);
+ txwi->rate = mt76x02_mac_tx_rate_val(dev, rate, &nss);
+ max_txpwr_adj = mt76x02_tx_get_max_txpwr_adj(dev, rate);
}
spin_unlock_bh(&dev->mt76.lock);
- txpwr_adj = mt76x2_tx_get_txpwr_adj(dev, dev->txpower_conf,
- max_txpwr_adj);
+ txpwr_adj = mt76x02_tx_get_txpwr_adj(dev, dev->mt76.txpower_conf,
+ max_txpwr_adj);
txwi->ctl2 = FIELD_PREP(MT_TX_PWR_ADJ, txpwr_adj);
- if (mt76xx_rev(dev) >= MT76XX_REV_E4)
+ if (nstreams > 1 && mt76_rev(&dev->mt76) >= MT76XX_REV_E4)
txwi->txstream = 0x13;
- else if (mt76xx_rev(dev) >= MT76XX_REV_E3 &&
+ else if (nstreams > 1 && mt76_rev(&dev->mt76) >= MT76XX_REV_E3 &&
!(txwi->rate & cpu_to_le16(rate_ht_mask)))
txwi->txstream = 0x93;
- if (info->flags & IEEE80211_TX_CTL_LDPC)
+ if (is_mt76x2(dev) && (info->flags & IEEE80211_TX_CTL_LDPC))
txwi->rate |= cpu_to_le16(MT_RXWI_RATE_LDPC);
if ((info->flags & IEEE80211_TX_CTL_STBC) && nss == 1)
txwi->rate |= cpu_to_le16(MT_RXWI_RATE_STBC);
@@ -459,44 +389,104 @@ void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x2_txwi *txwi,
txwi->flags |= cpu_to_le16(txwi_flags);
txwi->len_ctl = cpu_to_le16(len);
}
-EXPORT_SYMBOL_GPL(mt76x2_mac_write_txwi);
+EXPORT_SYMBOL_GPL(mt76x02_mac_write_txwi);
-void mt76x2_mac_wcid_set_drop(struct mt76x2_dev *dev, u8 idx, bool drop)
+static void
+mt76x02_mac_fill_tx_status(struct mt76x02_dev *dev,
+ struct ieee80211_tx_info *info,
+ struct mt76x02_tx_status *st, int n_frames)
{
- u32 val = mt76_rr(dev, MT_WCID_DROP(idx));
- u32 bit = MT_WCID_DROP_MASK(idx);
+ struct ieee80211_tx_rate *rate = info->status.rates;
+ int cur_idx, last_rate;
+ int i;
- /* prevent unnecessary writes */
- if ((val & bit) != (bit * drop))
- mt76_wr(dev, MT_WCID_DROP(idx), (val & ~bit) | (bit * drop));
+ if (!n_frames)
+ return;
+
+ last_rate = min_t(int, st->retry, IEEE80211_TX_MAX_RATES - 1);
+ mt76x02_mac_process_tx_rate(&rate[last_rate], st->rate,
+ dev->mt76.chandef.chan->band);
+ if (last_rate < IEEE80211_TX_MAX_RATES - 1)
+ rate[last_rate + 1].idx = -1;
+
+ cur_idx = rate[last_rate].idx + last_rate;
+ for (i = 0; i <= last_rate; i++) {
+ rate[i].flags = rate[last_rate].flags;
+ rate[i].idx = max_t(int, 0, cur_idx - i);
+ rate[i].count = 1;
+ }
+ rate[last_rate].count = st->retry + 1 - last_rate;
+
+ info->status.ampdu_len = n_frames;
+ info->status.ampdu_ack_len = st->success ? n_frames : 0;
+
+ if (st->pktid & MT_TXWI_PKTID_PROBE)
+ info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
+
+ if (st->aggr)
+ info->flags |= IEEE80211_TX_CTL_AMPDU |
+ IEEE80211_TX_STAT_AMPDU;
+
+ if (!st->ack_req)
+ info->flags |= IEEE80211_TX_CTL_NO_ACK;
+ else if (st->success)
+ info->flags |= IEEE80211_TX_STAT_ACK;
}
-EXPORT_SYMBOL_GPL(mt76x2_mac_wcid_set_drop);
-void mt76x2_mac_wcid_setup(struct mt76x2_dev *dev, u8 idx, u8 vif_idx, u8 *mac)
+void mt76x02_send_tx_status(struct mt76x02_dev *dev,
+ struct mt76x02_tx_status *stat, u8 *update)
{
- struct mt76_wcid_addr addr = {};
- u32 attr;
+ struct ieee80211_tx_info info = {};
+ struct ieee80211_sta *sta = NULL;
+ struct mt76_wcid *wcid = NULL;
+ struct mt76x02_sta *msta = NULL;
- attr = FIELD_PREP(MT_WCID_ATTR_BSS_IDX, vif_idx & 7) |
- FIELD_PREP(MT_WCID_ATTR_BSS_IDX_EXT, !!(vif_idx & 8));
+ rcu_read_lock();
+ if (stat->wcid < ARRAY_SIZE(dev->mt76.wcid))
+ wcid = rcu_dereference(dev->mt76.wcid[stat->wcid]);
- mt76_wr(dev, MT_WCID_ATTR(idx), attr);
+ if (wcid) {
+ void *priv;
- mt76_wr(dev, MT_WCID_TX_RATE(idx), 0);
- mt76_wr(dev, MT_WCID_TX_RATE(idx) + 4, 0);
+ priv = msta = container_of(wcid, struct mt76x02_sta, wcid);
+ sta = container_of(priv, struct ieee80211_sta,
+ drv_priv);
+ }
- if (idx >= 128)
- return;
+ if (msta && stat->aggr) {
+ u32 stat_val, stat_cache;
- if (mac)
- memcpy(addr.macaddr, mac, ETH_ALEN);
+ stat_val = stat->rate;
+ stat_val |= ((u32) stat->retry) << 16;
+ stat_cache = msta->status.rate;
+ stat_cache |= ((u32) msta->status.retry) << 16;
- mt76_wr_copy(dev, MT_WCID_ADDR(idx), &addr, sizeof(addr));
+ if (*update == 0 && stat_val == stat_cache &&
+ stat->wcid == msta->status.wcid && msta->n_frames < 32) {
+ msta->n_frames++;
+ goto out;
+ }
+
+ mt76x02_mac_fill_tx_status(dev, &info, &msta->status,
+ msta->n_frames);
+
+ msta->status = *stat;
+ msta->n_frames = 1;
+ *update = 0;
+ } else {
+ mt76x02_mac_fill_tx_status(dev, &info, stat, 1);
+ *update = 1;
+ }
+
+ ieee80211_tx_status_noskb(dev->mt76.hw, sta, &info);
+
+out:
+ rcu_read_unlock();
}
-EXPORT_SYMBOL_GPL(mt76x2_mac_wcid_setup);
+EXPORT_SYMBOL_GPL(mt76x02_send_tx_status);
-static int
-mt76x2_mac_process_rate(struct mt76_rx_status *status, u16 rate)
+int
+mt76x02_mac_process_rate(struct mt76_rx_status *status, u16 rate)
{
u8 idx = FIELD_GET(MT_RXWI_RATE_INDEX, rate);
@@ -561,22 +551,30 @@ mt76x2_mac_process_rate(struct mt76_rx_status *status, u16 rate)
return 0;
}
+EXPORT_SYMBOL_GPL(mt76x02_mac_process_rate);
-static void mt76x2_remove_hdr_pad(struct sk_buff *skb, int len)
+void mt76x02_mac_setaddr(struct mt76x02_dev *dev, u8 *addr)
{
- int hdrlen;
+ ether_addr_copy(dev->mt76.macaddr, addr);
- if (!len)
- return;
+ if (!is_valid_ether_addr(dev->mt76.macaddr)) {
+ eth_random_addr(dev->mt76.macaddr);
+ dev_info(dev->mt76.dev,
+ "Invalid MAC address, using random address %pM\n",
+ dev->mt76.macaddr);
+ }
- hdrlen = ieee80211_get_hdrlen_from_skb(skb);
- memmove(skb->data + len, skb->data, hdrlen);
- skb_pull(skb, len);
+ mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dev->mt76.macaddr));
+ mt76_wr(dev, MT_MAC_ADDR_DW1,
+ get_unaligned_le16(dev->mt76.macaddr + 4) |
+ FIELD_PREP(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff));
}
+EXPORT_SYMBOL_GPL(mt76x02_mac_setaddr);
-int mt76x2_mac_get_rssi(struct mt76x2_dev *dev, s8 rssi, int chain)
+static int
+mt76x02_mac_get_rssi(struct mt76x02_dev *dev, s8 rssi, int chain)
{
- struct mt76x2_rx_freq_cal *cal = &dev->cal.rx;
+ struct mt76x02_rx_freq_cal *cal = &dev->cal.rx;
rssi += cal->rssi_offset[chain];
rssi -= cal->lna_gain;
@@ -584,46 +582,19 @@ int mt76x2_mac_get_rssi(struct mt76x2_dev *dev, s8 rssi, int chain)
return rssi;
}
-static struct mt76x2_sta *
-mt76x2_rx_get_sta(struct mt76x2_dev *dev, u8 idx)
-{
- struct mt76_wcid *wcid;
-
- if (idx >= ARRAY_SIZE(dev->wcid))
- return NULL;
-
- wcid = rcu_dereference(dev->wcid[idx]);
- if (!wcid)
- return NULL;
-
- return container_of(wcid, struct mt76x2_sta, wcid);
-}
-
-static struct mt76_wcid *
-mt76x2_rx_get_sta_wcid(struct mt76x2_dev *dev, struct mt76x2_sta *sta,
- bool unicast)
-{
- if (!sta)
- return NULL;
-
- if (unicast)
- return &sta->wcid;
- else
- return &sta->vif->group_wcid;
-}
-
-int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb,
- void *rxi)
+int mt76x02_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb,
+ void *rxi)
{
struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb;
- struct mt76x2_rxwi *rxwi = rxi;
- struct mt76x2_sta *sta;
+ struct mt76x02_rxwi *rxwi = rxi;
+ struct mt76x02_sta *sta;
u32 rxinfo = le32_to_cpu(rxwi->rxinfo);
u32 ctl = le32_to_cpu(rxwi->ctl);
u16 rate = le16_to_cpu(rxwi->rate);
u16 tid_sn = le16_to_cpu(rxwi->tid_sn);
bool unicast = rxwi->rxinfo & cpu_to_le32(MT_RXINFO_UNICAST);
- int pad_len = 0;
+ int i, pad_len = 0, nstreams = dev->mt76.chainmask & 0xf;
+ s8 signal;
u8 pn_len;
u8 wcid;
int len;
@@ -642,8 +613,8 @@ int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb,
}
wcid = FIELD_GET(MT_RXWI_CTL_WCID, ctl);
- sta = mt76x2_rx_get_sta(dev, wcid);
- status->wcid = mt76x2_rx_get_sta_wcid(dev, sta, unicast);
+ sta = mt76x02_rx_get_sta(&dev->mt76, wcid);
+ status->wcid = mt76x02_rx_get_sta_wcid(sta, unicast);
len = FIELD_GET(MT_RXWI_CTL_MPDU_LEN, ctl);
pn_len = FIELD_GET(MT_RXINFO_PN_LEN, rxinfo);
@@ -670,7 +641,7 @@ int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb,
}
}
- mt76x2_remove_hdr_pad(skb, pad_len);
+ mt76x02_remove_hdr_pad(skb, pad_len);
if ((rxinfo & MT_RXINFO_BA) && !(rxinfo & MT_RXINFO_NULL))
status->aggr = true;
@@ -679,10 +650,17 @@ int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb,
return -EINVAL;
pskb_trim(skb, len);
- status->chains = BIT(0) | BIT(1);
- status->chain_signal[0] = mt76x2_mac_get_rssi(dev, rxwi->rssi[0], 0);
- status->chain_signal[1] = mt76x2_mac_get_rssi(dev, rxwi->rssi[1], 1);
- status->signal = max(status->chain_signal[0], status->chain_signal[1]);
+
+ status->chains = BIT(0);
+ signal = mt76x02_mac_get_rssi(dev, rxwi->rssi[0], 0);
+ for (i = 1; i < nstreams; i++) {
+ status->chains |= BIT(i);
+ status->chain_signal[i] = mt76x02_mac_get_rssi(dev,
+ rxwi->rssi[i],
+ i);
+ signal = max_t(s8, signal, status->chain_signal[i]);
+ }
+ status->signal = signal;
status->freq = dev->mt76.chandef.chan->center_freq;
status->band = dev->mt76.chandef.chan->band;
@@ -694,6 +672,66 @@ int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb,
sta->inactive_count = 0;
}
- return mt76x2_mac_process_rate(status, rate);
+ return mt76x02_mac_process_rate(status, rate);
+}
+
+void mt76x02_mac_poll_tx_status(struct mt76x02_dev *dev, bool irq)
+{
+ struct mt76x02_tx_status stat = {};
+ unsigned long flags;
+ u8 update = 1;
+ bool ret;
+
+ if (!test_bit(MT76_STATE_RUNNING, &dev->mt76.state))
+ return;
+
+ trace_mac_txstat_poll(dev);
+
+ while (!irq || !kfifo_is_full(&dev->txstatus_fifo)) {
+ spin_lock_irqsave(&dev->mt76.mmio.irq_lock, flags);
+ ret = mt76x02_mac_load_tx_status(dev, &stat);
+ spin_unlock_irqrestore(&dev->mt76.mmio.irq_lock, flags);
+
+ if (!ret)
+ break;
+
+ trace_mac_txstat_fetch(dev, &stat);
+
+ if (!irq) {
+ mt76x02_send_tx_status(dev, &stat, &update);
+ continue;
+ }
+
+ kfifo_put(&dev->txstatus_fifo, stat);
+ }
+}
+EXPORT_SYMBOL_GPL(mt76x02_mac_poll_tx_status);
+
+static void
+mt76x02_mac_queue_txdone(struct mt76x02_dev *dev, struct sk_buff *skb,
+ void *txwi_ptr)
+{
+ struct mt76x02_tx_info *txi = mt76x02_skb_tx_info(skb);
+ struct mt76x02_txwi *txwi = txwi_ptr;
+
+ mt76x02_mac_poll_tx_status(dev, false);
+
+ txi->tries = 0;
+ txi->jiffies = jiffies;
+ txi->wcid = txwi->wcid;
+ txi->pktid = txwi->pktid;
+ trace_mac_txdone_add(dev, txwi->wcid, txwi->pktid);
+ mt76x02_tx_complete(&dev->mt76, skb);
+}
+
+void mt76x02_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q,
+ struct mt76_queue_entry *e, bool flush)
+{
+ struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
+
+ if (e->txwi)
+ mt76x02_mac_queue_txdone(dev, e->skb, &e->txwi->txwi);
+ else
+ dev_kfree_skb_any(e->skb);
}
-EXPORT_SYMBOL_GPL(mt76x2_mac_process_rx);
+EXPORT_SYMBOL_GPL(mt76x02_tx_complete_skb);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h
index 5af0107ba748..d99c18743969 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
+ * Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -14,17 +15,14 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifndef __MT76x2_MAC_H
-#define __MT76x2_MAC_H
+#ifndef __MT76X02_MAC_H
+#define __MT76X02_MAC_H
-#include "mt76.h"
+#include <linux/average.h>
-struct mt76x2_dev;
-struct mt76x2_sta;
-struct mt76x2_vif;
-struct mt76x2_txwi;
+struct mt76x02_dev;
-struct mt76x2_tx_status {
+struct mt76x02_tx_status {
u8 valid:1;
u8 success:1;
u8 aggr:1;
@@ -35,7 +33,16 @@ struct mt76x2_tx_status {
u16 rate;
} __packed __aligned(2);
-struct mt76x2_tx_info {
+#define MT_VIF_WCID(_n) (254 - ((_n) & 7))
+#define MT_MAX_VIFS 8
+
+struct mt76x02_vif {
+ u8 idx;
+
+ struct mt76_wcid group_wcid;
+};
+
+struct mt76x02_tx_info {
unsigned long jiffies;
u8 tries;
@@ -44,17 +51,17 @@ struct mt76x2_tx_info {
u8 retry;
};
-struct mt76x2_rxwi {
- __le32 rxinfo;
-
- __le32 ctl;
+DECLARE_EWMA(signal, 10, 8);
- __le16 tid_sn;
- __le16 rate;
+struct mt76x02_sta {
+ struct mt76_wcid wcid; /* must be first */
- u8 rssi[4];
+ struct mt76x02_vif *vif;
+ struct mt76x02_tx_status status;
+ int n_frames;
- __le32 bbp_rxinfo[4];
+ struct ewma_signal rssi;
+ int inactive_count;
};
#define MT_RXINFO_BA BIT(0)
@@ -108,6 +115,19 @@ struct mt76x2_rxwi {
#define MT_RATE_INDEX_VHT_IDX GENMASK(3, 0)
#define MT_RATE_INDEX_VHT_NSS GENMASK(5, 4)
+struct mt76x02_rxwi {
+ __le32 rxinfo;
+
+ __le32 ctl;
+
+ __le16 tid_sn;
+ __le16 rate;
+
+ u8 rssi[4];
+
+ __le32 bbp_rxinfo[4];
+};
+
#define MT_TX_PWR_ADJ GENMASK(3, 0)
enum mt76x2_phy_bandwidth {
@@ -135,7 +155,7 @@ enum mt76x2_phy_bandwidth {
#define MT_TXWI_PKTID_PROBE BIT(7)
-struct mt76x2_txwi {
+struct mt76x02_txwi {
__le16 flags;
__le16 rate;
u8 ack_ctl;
@@ -149,41 +169,61 @@ struct mt76x2_txwi {
u8 pktid;
} __packed __aligned(4);
-static inline struct mt76x2_tx_info *
-mt76x2_skb_tx_info(struct sk_buff *skb)
+static inline bool mt76x02_wait_for_mac(struct mt76_dev *dev)
{
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-
- return (void *) info->status.status_driver_data;
+ const u32 MAC_CSR0 = 0x1000;
+ int i;
+
+ for (i = 0; i < 500; i++) {
+ if (test_bit(MT76_REMOVED, &dev->state))
+ return false;
+
+ switch (dev->bus->rr(dev, MAC_CSR0)) {
+ case 0:
+ case ~0:
+ break;
+ default:
+ return true;
+ }
+ usleep_range(5000, 10000);
+ }
+ return false;
}
-int mt76x2_mac_start(struct mt76x2_dev *dev);
-void mt76x2_mac_stop(struct mt76x2_dev *dev, bool force);
-void mt76x2_mac_resume(struct mt76x2_dev *dev);
-void mt76x2_mac_set_bssid(struct mt76x2_dev *dev, u8 idx, const u8 *addr);
-
-int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb,
- void *rxi);
-void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x2_txwi *txwi,
- struct sk_buff *skb, struct mt76_wcid *wcid,
- struct ieee80211_sta *sta, int len);
-void mt76x2_mac_wcid_setup(struct mt76x2_dev *dev, u8 idx, u8 vif_idx, u8 *mac);
-int mt76x2_mac_wcid_set_key(struct mt76x2_dev *dev, u8 idx,
- struct ieee80211_key_conf *key);
-void mt76x2_mac_wcid_set_rate(struct mt76x2_dev *dev, struct mt76_wcid *wcid,
- const struct ieee80211_tx_rate *rate);
-void mt76x2_mac_wcid_set_drop(struct mt76x2_dev *dev, u8 idx, bool drop);
-
-int mt76x2_mac_shared_key_setup(struct mt76x2_dev *dev, u8 vif_idx, u8 key_idx,
- struct ieee80211_key_conf *key);
-
-int mt76x2_mac_set_beacon(struct mt76x2_dev *dev, u8 vif_idx,
- struct sk_buff *skb);
-void mt76x2_mac_set_beacon_enable(struct mt76x2_dev *dev, u8 vif_idx, bool val);
-
-void mt76x2_mac_poll_tx_status(struct mt76x2_dev *dev, bool irq);
-void mt76x2_mac_process_tx_status_fifo(struct mt76x2_dev *dev);
+static inline struct mt76x02_tx_info *
+mt76x02_skb_tx_info(struct sk_buff *skb)
+{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-void mt76x2_mac_work(struct work_struct *work);
+ return (void *)info->status.status_driver_data;
+}
+void mt76x02_txq_init(struct mt76x02_dev *dev, struct ieee80211_txq *txq);
+enum mt76x02_cipher_type
+mt76x02_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data);
+
+int mt76x02_mac_shared_key_setup(struct mt76x02_dev *dev, u8 vif_idx,
+ u8 key_idx, struct ieee80211_key_conf *key);
+int mt76x02_mac_wcid_set_key(struct mt76x02_dev *dev, u8 idx,
+ struct ieee80211_key_conf *key);
+void mt76x02_mac_wcid_setup(struct mt76x02_dev *dev, u8 idx, u8 vif_idx,
+ u8 *mac);
+void mt76x02_mac_wcid_set_drop(struct mt76x02_dev *dev, u8 idx, bool drop);
+void mt76x02_mac_wcid_set_rate(struct mt76x02_dev *dev, struct mt76_wcid *wcid,
+ const struct ieee80211_tx_rate *rate);
+bool mt76x02_mac_load_tx_status(struct mt76x02_dev *dev,
+ struct mt76x02_tx_status *stat);
+void mt76x02_send_tx_status(struct mt76x02_dev *dev,
+ struct mt76x02_tx_status *stat, u8 *update);
+int mt76x02_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb,
+ void *rxi);
+int
+mt76x02_mac_process_rate(struct mt76_rx_status *status, u16 rate);
+void mt76x02_mac_setaddr(struct mt76x02_dev *dev, u8 *addr);
+void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi,
+ struct sk_buff *skb, struct mt76_wcid *wcid,
+ 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 *q,
+ struct mt76_queue_entry *e, bool flush);
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c
new file mode 100644
index 000000000000..1b853bb723fb
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
+ * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+
+#include "mt76x02_mcu.h"
+
+struct sk_buff *mt76x02_mcu_msg_alloc(const void *data, int len)
+{
+ struct sk_buff *skb;
+
+ skb = alloc_skb(len, GFP_KERNEL);
+ if (!skb)
+ return NULL;
+ memcpy(skb_put(skb, len), data, len);
+
+ return skb;
+}
+EXPORT_SYMBOL_GPL(mt76x02_mcu_msg_alloc);
+
+static struct sk_buff *
+mt76x02_mcu_get_response(struct mt76x02_dev *dev, unsigned long expires)
+{
+ unsigned long timeout;
+
+ if (!time_is_after_jiffies(expires))
+ return NULL;
+
+ timeout = expires - jiffies;
+ wait_event_timeout(dev->mt76.mmio.mcu.wait,
+ !skb_queue_empty(&dev->mt76.mmio.mcu.res_q),
+ timeout);
+ return skb_dequeue(&dev->mt76.mmio.mcu.res_q);
+}
+
+static int
+mt76x02_tx_queue_mcu(struct mt76x02_dev *dev, enum mt76_txq_id qid,
+ struct sk_buff *skb, int cmd, int seq)
+{
+ struct mt76_queue *q = &dev->mt76.q_tx[qid];
+ struct mt76_queue_buf buf;
+ dma_addr_t addr;
+ u32 tx_info;
+
+ tx_info = MT_MCU_MSG_TYPE_CMD |
+ FIELD_PREP(MT_MCU_MSG_CMD_TYPE, cmd) |
+ FIELD_PREP(MT_MCU_MSG_CMD_SEQ, seq) |
+ FIELD_PREP(MT_MCU_MSG_PORT, CPU_TX_PORT) |
+ FIELD_PREP(MT_MCU_MSG_LEN, skb->len);
+
+ addr = dma_map_single(dev->mt76.dev, skb->data, skb->len,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(dev->mt76.dev, addr))
+ return -ENOMEM;
+
+ buf.addr = addr;
+ buf.len = skb->len;
+
+ spin_lock_bh(&q->lock);
+ mt76_queue_add_buf(dev, q, &buf, 1, tx_info, skb, NULL);
+ mt76_queue_kick(dev, q);
+ spin_unlock_bh(&q->lock);
+
+ return 0;
+}
+
+int mt76x02_mcu_msg_send(struct mt76_dev *mdev, struct sk_buff *skb,
+ int cmd, bool wait_resp)
+{
+ struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
+ unsigned long expires = jiffies + HZ;
+ int ret;
+ u8 seq;
+
+ if (!skb)
+ return -EINVAL;
+
+ mutex_lock(&mdev->mmio.mcu.mutex);
+
+ seq = ++mdev->mmio.mcu.msg_seq & 0xf;
+ if (!seq)
+ seq = ++mdev->mmio.mcu.msg_seq & 0xf;
+
+ ret = mt76x02_tx_queue_mcu(dev, MT_TXQ_MCU, skb, cmd, seq);
+ if (ret)
+ goto out;
+
+ while (wait_resp) {
+ u32 *rxfce;
+ bool check_seq = false;
+
+ skb = mt76x02_mcu_get_response(dev, expires);
+ if (!skb) {
+ dev_err(mdev->dev,
+ "MCU message %d (seq %d) timed out\n", cmd,
+ seq);
+ ret = -ETIMEDOUT;
+ break;
+ }
+
+ rxfce = (u32 *) skb->cb;
+
+ if (seq == FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, *rxfce))
+ check_seq = true;
+
+ dev_kfree_skb(skb);
+ if (check_seq)
+ break;
+ }
+
+out:
+ mutex_unlock(&mdev->mmio.mcu.mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mt76x02_mcu_msg_send);
+
+int mt76x02_mcu_function_select(struct mt76x02_dev *dev,
+ enum mcu_function func,
+ u32 val, bool wait_resp)
+{
+ struct sk_buff *skb;
+ struct {
+ __le32 id;
+ __le32 value;
+ } __packed __aligned(4) msg = {
+ .id = cpu_to_le32(func),
+ .value = cpu_to_le32(val),
+ };
+
+ skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg));
+ return mt76_mcu_send_msg(dev, skb, CMD_FUN_SET_OP, wait_resp);
+}
+EXPORT_SYMBOL_GPL(mt76x02_mcu_function_select);
+
+int mt76x02_mcu_set_radio_state(struct mt76x02_dev *dev, bool on,
+ bool wait_resp)
+{
+ struct sk_buff *skb;
+ struct {
+ __le32 mode;
+ __le32 level;
+ } __packed __aligned(4) msg = {
+ .mode = cpu_to_le32(on ? RADIO_ON : RADIO_OFF),
+ .level = cpu_to_le32(0),
+ };
+
+ skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg));
+ return mt76_mcu_send_msg(dev, skb, CMD_POWER_SAVING_OP, wait_resp);
+}
+EXPORT_SYMBOL_GPL(mt76x02_mcu_set_radio_state);
+
+int mt76x02_mcu_calibrate(struct mt76x02_dev *dev, int type,
+ u32 param, bool wait)
+{
+ struct sk_buff *skb;
+ struct {
+ __le32 id;
+ __le32 value;
+ } __packed __aligned(4) msg = {
+ .id = cpu_to_le32(type),
+ .value = cpu_to_le32(param),
+ };
+ int ret;
+
+ if (wait)
+ mt76_rmw(dev, MT_MCU_COM_REG0, BIT(31), 0);
+
+ skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg));
+ ret = mt76_mcu_send_msg(dev, skb, CMD_CALIBRATION_OP, true);
+ if (ret)
+ return ret;
+
+ if (wait &&
+ WARN_ON(!mt76_poll_msec(dev, MT_MCU_COM_REG0,
+ BIT(31), BIT(31), 100)))
+ return -ETIMEDOUT;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt76x02_mcu_calibrate);
+
+int mt76x02_mcu_cleanup(struct mt76x02_dev *dev)
+{
+ struct sk_buff *skb;
+
+ mt76_wr(dev, MT_MCU_INT_LEVEL, 1);
+ usleep_range(20000, 30000);
+
+ while ((skb = skb_dequeue(&dev->mt76.mmio.mcu.res_q)) != NULL)
+ dev_kfree_skb(skb);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt76x02_mcu_cleanup);
+
+void mt76x02_set_ethtool_fwver(struct mt76x02_dev *dev,
+ const struct mt76x02_fw_header *h)
+{
+ u16 bld = le16_to_cpu(h->build_ver);
+ u16 ver = le16_to_cpu(h->fw_ver);
+
+ snprintf(dev->mt76.hw->wiphy->fw_version,
+ sizeof(dev->mt76.hw->wiphy->fw_version),
+ "%d.%d.%02d-b%x",
+ (ver >> 12) & 0xf, (ver >> 8) & 0xf, ver & 0xf, bld);
+}
+EXPORT_SYMBOL_GPL(mt76x02_set_ethtool_fwver);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h
new file mode 100644
index 000000000000..2d8fd2514570
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __MT76x02_MCU_H
+#define __MT76x02_MCU_H
+
+#include "mt76x02.h"
+
+#define MT_MCU_RESET_CTL 0x070C
+#define MT_MCU_INT_LEVEL 0x0718
+#define MT_MCU_COM_REG0 0x0730
+#define MT_MCU_COM_REG1 0x0734
+#define MT_MCU_COM_REG2 0x0738
+#define MT_MCU_COM_REG3 0x073C
+
+#define MT_INBAND_PACKET_MAX_LEN 192
+#define MT_MCU_MEMMAP_WLAN 0x410000
+
+#define MT_MCU_PCIE_REMAP_BASE4 0x074C
+
+#define MT_MCU_SEMAPHORE_00 0x07B0
+#define MT_MCU_SEMAPHORE_01 0x07B4
+#define MT_MCU_SEMAPHORE_02 0x07B8
+#define MT_MCU_SEMAPHORE_03 0x07BC
+
+#define MT_MCU_ILM_ADDR 0x80000
+
+enum mcu_cmd {
+ CMD_FUN_SET_OP = 1,
+ CMD_LOAD_CR = 2,
+ CMD_INIT_GAIN_OP = 3,
+ CMD_DYNC_VGA_OP = 6,
+ CMD_TDLS_CH_SW = 7,
+ CMD_BURST_WRITE = 8,
+ CMD_READ_MODIFY_WRITE = 9,
+ CMD_RANDOM_READ = 10,
+ CMD_BURST_READ = 11,
+ CMD_RANDOM_WRITE = 12,
+ CMD_LED_MODE_OP = 16,
+ CMD_POWER_SAVING_OP = 20,
+ CMD_WOW_CONFIG = 21,
+ CMD_WOW_QUERY = 22,
+ CMD_WOW_FEATURE = 24,
+ CMD_CARRIER_DETECT_OP = 28,
+ CMD_RADOR_DETECT_OP = 29,
+ CMD_SWITCH_CHANNEL_OP = 30,
+ CMD_CALIBRATION_OP = 31,
+ CMD_BEACON_OP = 32,
+ CMD_ANTENNA_OP = 33,
+};
+
+enum mcu_power_mode {
+ RADIO_OFF = 0x30,
+ RADIO_ON = 0x31,
+ RADIO_OFF_AUTO_WAKEUP = 0x32,
+ RADIO_OFF_ADVANCE = 0x33,
+ RADIO_ON_ADVANCE = 0x34,
+};
+
+enum mcu_function {
+ Q_SELECT = 1,
+ BW_SETTING = 2,
+ USB2_SW_DISCONNECT = 2,
+ USB3_SW_DISCONNECT = 3,
+ LOG_FW_DEBUG_MSG = 4,
+ GET_FW_VERSION = 5,
+};
+
+struct mt76x02_fw_header {
+ __le32 ilm_len;
+ __le32 dlm_len;
+ __le16 build_ver;
+ __le16 fw_ver;
+ u8 pad[4];
+ char build_time[16];
+};
+
+struct mt76x02_patch_header {
+ char build_time[16];
+ char platform[4];
+ char hw_version[4];
+ char patch_version[4];
+ u8 pad[2];
+};
+
+int mt76x02_mcu_cleanup(struct mt76x02_dev *dev);
+int mt76x02_mcu_calibrate(struct mt76x02_dev *dev, int type,
+ u32 param, bool wait);
+struct sk_buff *mt76x02_mcu_msg_alloc(const void *data, int len);
+int mt76x02_mcu_msg_send(struct mt76_dev *mdev, struct sk_buff *skb,
+ int cmd, bool wait_resp);
+int mt76x02_mcu_function_select(struct mt76x02_dev *dev,
+ enum mcu_function func,
+ u32 val, bool wait_resp);
+int mt76x02_mcu_set_radio_state(struct mt76x02_dev *dev, bool on,
+ bool wait_resp);
+void mt76x02_set_ethtool_fwver(struct mt76x02_dev *dev,
+ const struct mt76x02_fw_header *h);
+
+#endif /* __MT76x02_MCU_H */
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
new file mode 100644
index 000000000000..39f092034240
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
+ * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/irq.h>
+
+#include "mt76x02.h"
+#include "mt76x02_trace.h"
+
+static int
+mt76x02_init_tx_queue(struct mt76x02_dev *dev, struct mt76_queue *q,
+ int idx, int n_desc)
+{
+ int ret;
+
+ q->regs = dev->mt76.mmio.regs + MT_TX_RING_BASE + idx * MT_RING_SIZE;
+ q->ndesc = n_desc;
+ q->hw_idx = idx;
+
+ ret = mt76_queue_alloc(dev, q);
+ if (ret)
+ return ret;
+
+ mt76x02_irq_enable(dev, MT_INT_TX_DONE(idx));
+
+ return 0;
+}
+
+static int
+mt76x02_init_rx_queue(struct mt76x02_dev *dev, struct mt76_queue *q,
+ int idx, int n_desc, int bufsize)
+{
+ int ret;
+
+ q->regs = dev->mt76.mmio.regs + MT_RX_RING_BASE + idx * MT_RING_SIZE;
+ q->ndesc = n_desc;
+ q->buf_size = bufsize;
+
+ ret = mt76_queue_alloc(dev, q);
+ if (ret)
+ return ret;
+
+ mt76x02_irq_enable(dev, MT_INT_RX_DONE(idx));
+
+ return 0;
+}
+
+static void mt76x02_process_tx_status_fifo(struct mt76x02_dev *dev)
+{
+ struct mt76x02_tx_status stat;
+ u8 update = 1;
+
+ while (kfifo_get(&dev->txstatus_fifo, &stat))
+ mt76x02_send_tx_status(dev, &stat, &update);
+}
+
+static void mt76x02_tx_tasklet(unsigned long data)
+{
+ struct mt76x02_dev *dev = (struct mt76x02_dev *)data;
+ int i;
+
+ mt76x02_process_tx_status_fifo(dev);
+
+ for (i = MT_TXQ_MCU; i >= 0; i--)
+ mt76_queue_tx_cleanup(dev, i, false);
+
+ mt76x02_mac_poll_tx_status(dev, false);
+ mt76x02_irq_enable(dev, MT_INT_TX_DONE_ALL);
+}
+
+int mt76x02_dma_init(struct mt76x02_dev *dev)
+{
+ struct mt76_txwi_cache __maybe_unused *t;
+ int i, ret, fifo_size;
+ struct mt76_queue *q;
+ void *status_fifo;
+
+ BUILD_BUG_ON(sizeof(t->txwi) < sizeof(struct mt76x02_txwi));
+ BUILD_BUG_ON(sizeof(struct mt76x02_rxwi) > MT_RX_HEADROOM);
+
+ fifo_size = roundup_pow_of_two(32 * sizeof(struct mt76x02_tx_status));
+ status_fifo = devm_kzalloc(dev->mt76.dev, fifo_size, GFP_KERNEL);
+ if (!status_fifo)
+ return -ENOMEM;
+
+ tasklet_init(&dev->tx_tasklet, mt76x02_tx_tasklet, (unsigned long) dev);
+ kfifo_init(&dev->txstatus_fifo, status_fifo, fifo_size);
+
+ mt76_dma_attach(&dev->mt76);
+
+ mt76_wr(dev, MT_WPDMA_RST_IDX, ~0);
+
+ for (i = 0; i < IEEE80211_NUM_ACS; i++) {
+ ret = mt76x02_init_tx_queue(dev, &dev->mt76.q_tx[i],
+ mt76_ac_to_hwq(i),
+ MT_TX_RING_SIZE);
+ if (ret)
+ return ret;
+ }
+
+ ret = mt76x02_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_PSD],
+ MT_TX_HW_QUEUE_MGMT, MT_TX_RING_SIZE);
+ if (ret)
+ return ret;
+
+ ret = mt76x02_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_MCU],
+ MT_TX_HW_QUEUE_MCU, MT_MCU_RING_SIZE);
+ if (ret)
+ return ret;
+
+ ret = mt76x02_init_rx_queue(dev, &dev->mt76.q_rx[MT_RXQ_MCU], 1,
+ MT_MCU_RING_SIZE, MT_RX_BUF_SIZE);
+ if (ret)
+ return ret;
+
+ q = &dev->mt76.q_rx[MT_RXQ_MAIN];
+ q->buf_offset = MT_RX_HEADROOM - sizeof(struct mt76x02_rxwi);
+ ret = mt76x02_init_rx_queue(dev, q, 0, MT76X02_RX_RING_SIZE,
+ MT_RX_BUF_SIZE);
+ if (ret)
+ return ret;
+
+ return mt76_init_queues(dev);
+}
+EXPORT_SYMBOL_GPL(mt76x02_dma_init);
+
+void mt76x02_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q)
+{
+ struct mt76x02_dev *dev;
+
+ dev = container_of(mdev, struct mt76x02_dev, mt76);
+ mt76x02_irq_enable(dev, MT_INT_RX_DONE(q));
+}
+EXPORT_SYMBOL_GPL(mt76x02_rx_poll_complete);
+
+irqreturn_t mt76x02_irq_handler(int irq, void *dev_instance)
+{
+ struct mt76x02_dev *dev = dev_instance;
+ u32 intr;
+
+ intr = mt76_rr(dev, MT_INT_SOURCE_CSR);
+ mt76_wr(dev, MT_INT_SOURCE_CSR, intr);
+
+ if (!test_bit(MT76_STATE_INITIALIZED, &dev->mt76.state))
+ return IRQ_NONE;
+
+ trace_dev_irq(dev, intr, dev->mt76.mmio.irqmask);
+
+ intr &= dev->mt76.mmio.irqmask;
+
+ if (intr & MT_INT_TX_DONE_ALL) {
+ mt76x02_irq_disable(dev, MT_INT_TX_DONE_ALL);
+ tasklet_schedule(&dev->tx_tasklet);
+ }
+
+ if (intr & MT_INT_RX_DONE(0)) {
+ mt76x02_irq_disable(dev, MT_INT_RX_DONE(0));
+ napi_schedule(&dev->mt76.napi[0]);
+ }
+
+ if (intr & MT_INT_RX_DONE(1)) {
+ mt76x02_irq_disable(dev, MT_INT_RX_DONE(1));
+ napi_schedule(&dev->mt76.napi[1]);
+ }
+
+ if (intr & MT_INT_PRE_TBTT)
+ tasklet_schedule(&dev->pre_tbtt_tasklet);
+
+ /* send buffered multicast frames now */
+ if (intr & MT_INT_TBTT)
+ mt76_queue_kick(dev, &dev->mt76.q_tx[MT_TXQ_PSD]);
+
+ if (intr & MT_INT_TX_STAT) {
+ mt76x02_mac_poll_tx_status(dev, true);
+ tasklet_schedule(&dev->tx_tasklet);
+ }
+
+ if (intr & MT_INT_GPTIMER) {
+ mt76x02_irq_disable(dev, MT_INT_GPTIMER);
+ tasklet_schedule(&dev->dfs_pd.dfs_tasklet);
+ }
+
+ return IRQ_HANDLED;
+}
+EXPORT_SYMBOL_GPL(mt76x02_irq_handler);
+
+void mt76x02_set_irq_mask(struct mt76x02_dev *dev, u32 clear, u32 set)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->mt76.mmio.irq_lock, flags);
+ dev->mt76.mmio.irqmask &= ~clear;
+ dev->mt76.mmio.irqmask |= set;
+ mt76_wr(dev, MT_INT_MASK_CSR, dev->mt76.mmio.irqmask);
+ spin_unlock_irqrestore(&dev->mt76.mmio.irq_lock, flags);
+}
+EXPORT_SYMBOL_GPL(mt76x02_set_irq_mask);
+
+static void mt76x02_dma_enable(struct mt76x02_dev *dev)
+{
+ u32 val;
+
+ mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX);
+ mt76x02_wait_for_wpdma(&dev->mt76, 1000);
+ usleep_range(50, 100);
+
+ val = FIELD_PREP(MT_WPDMA_GLO_CFG_DMA_BURST_SIZE, 3) |
+ MT_WPDMA_GLO_CFG_TX_DMA_EN |
+ MT_WPDMA_GLO_CFG_RX_DMA_EN;
+ mt76_set(dev, MT_WPDMA_GLO_CFG, val);
+ mt76_clear(dev, MT_WPDMA_GLO_CFG,
+ MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE);
+}
+EXPORT_SYMBOL_GPL(mt76x02_dma_enable);
+
+void mt76x02_dma_cleanup(struct mt76x02_dev *dev)
+{
+ tasklet_kill(&dev->tx_tasklet);
+ mt76_dma_cleanup(&dev->mt76);
+}
+EXPORT_SYMBOL_GPL(mt76x02_dma_cleanup);
+
+void mt76x02_dma_disable(struct mt76x02_dev *dev)
+{
+ u32 val = mt76_rr(dev, MT_WPDMA_GLO_CFG);
+
+ val &= MT_WPDMA_GLO_CFG_DMA_BURST_SIZE |
+ MT_WPDMA_GLO_CFG_BIG_ENDIAN |
+ MT_WPDMA_GLO_CFG_HDR_SEG_LEN;
+ val |= MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE;
+ mt76_wr(dev, MT_WPDMA_GLO_CFG, val);
+}
+EXPORT_SYMBOL_GPL(mt76x02_dma_disable);
+
+void mt76x02_mac_start(struct mt76x02_dev *dev)
+{
+ mt76x02_dma_enable(dev);
+ mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter);
+ mt76_wr(dev, MT_MAC_SYS_CTRL,
+ MT_MAC_SYS_CTRL_ENABLE_TX |
+ MT_MAC_SYS_CTRL_ENABLE_RX);
+ mt76x02_irq_enable(dev,
+ MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL |
+ MT_INT_TX_STAT);
+}
+EXPORT_SYMBOL_GPL(mt76x02_mac_start);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c
new file mode 100644
index 000000000000..0f1d7b5c9f68
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
+ * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+
+#include "mt76x02.h"
+#include "mt76x02_phy.h"
+
+void mt76x02_phy_set_rxpath(struct mt76x02_dev *dev)
+{
+ u32 val;
+
+ val = mt76_rr(dev, MT_BBP(AGC, 0));
+ val &= ~BIT(4);
+
+ switch (dev->mt76.chainmask & 0xf) {
+ case 2:
+ val |= BIT(3);
+ break;
+ default:
+ val &= ~BIT(3);
+ break;
+ }
+
+ mt76_wr(dev, MT_BBP(AGC, 0), val);
+ mb();
+ val = mt76_rr(dev, MT_BBP(AGC, 0));
+}
+EXPORT_SYMBOL_GPL(mt76x02_phy_set_rxpath);
+
+void mt76x02_phy_set_txdac(struct mt76x02_dev *dev)
+{
+ int txpath;
+
+ txpath = (dev->mt76.chainmask >> 8) & 0xf;
+ switch (txpath) {
+ case 2:
+ mt76_set(dev, MT_BBP(TXBE, 5), 0x3);
+ break;
+ default:
+ mt76_clear(dev, MT_BBP(TXBE, 5), 0x3);
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(mt76x02_phy_set_txdac);
+
+static u32
+mt76x02_tx_power_mask(u8 v1, u8 v2, u8 v3, u8 v4)
+{
+ u32 val = 0;
+
+ val |= (v1 & (BIT(6) - 1)) << 0;
+ val |= (v2 & (BIT(6) - 1)) << 8;
+ val |= (v3 & (BIT(6) - 1)) << 16;
+ val |= (v4 & (BIT(6) - 1)) << 24;
+ return val;
+}
+
+int mt76x02_get_max_rate_power(struct mt76_rate_power *r)
+{
+ s8 ret = 0;
+ int i;
+
+ for (i = 0; i < sizeof(r->all); i++)
+ ret = max(ret, r->all[i]);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mt76x02_get_max_rate_power);
+
+void mt76x02_limit_rate_power(struct mt76_rate_power *r, int limit)
+{
+ int i;
+
+ for (i = 0; i < sizeof(r->all); i++)
+ if (r->all[i] > limit)
+ r->all[i] = limit;
+}
+EXPORT_SYMBOL_GPL(mt76x02_limit_rate_power);
+
+void mt76x02_add_rate_power_offset(struct mt76_rate_power *r, int offset)
+{
+ int i;
+
+ for (i = 0; i < sizeof(r->all); i++)
+ r->all[i] += offset;
+}
+EXPORT_SYMBOL_GPL(mt76x02_add_rate_power_offset);
+
+void mt76x02_phy_set_txpower(struct mt76x02_dev *dev, int txp_0, int txp_1)
+{
+ struct mt76_rate_power *t = &dev->mt76.rate_power;
+
+ mt76_rmw_field(dev, MT_TX_ALC_CFG_0, MT_TX_ALC_CFG_0_CH_INIT_0, txp_0);
+ mt76_rmw_field(dev, MT_TX_ALC_CFG_0, MT_TX_ALC_CFG_0_CH_INIT_1, txp_1);
+
+ mt76_wr(dev, MT_TX_PWR_CFG_0,
+ mt76x02_tx_power_mask(t->cck[0], t->cck[2], t->ofdm[0],
+ t->ofdm[2]));
+ mt76_wr(dev, MT_TX_PWR_CFG_1,
+ mt76x02_tx_power_mask(t->ofdm[4], t->ofdm[6], t->ht[0],
+ t->ht[2]));
+ mt76_wr(dev, MT_TX_PWR_CFG_2,
+ mt76x02_tx_power_mask(t->ht[4], t->ht[6], t->ht[8],
+ t->ht[10]));
+ mt76_wr(dev, MT_TX_PWR_CFG_3,
+ mt76x02_tx_power_mask(t->ht[12], t->ht[14], t->stbc[0],
+ t->stbc[2]));
+ mt76_wr(dev, MT_TX_PWR_CFG_4,
+ mt76x02_tx_power_mask(t->stbc[4], t->stbc[6], 0, 0));
+ mt76_wr(dev, MT_TX_PWR_CFG_7,
+ mt76x02_tx_power_mask(t->ofdm[7], t->vht[8], t->ht[7],
+ t->vht[9]));
+ mt76_wr(dev, MT_TX_PWR_CFG_8,
+ mt76x02_tx_power_mask(t->ht[14], 0, t->vht[8], t->vht[9]));
+ mt76_wr(dev, MT_TX_PWR_CFG_9,
+ mt76x02_tx_power_mask(t->ht[7], 0, t->stbc[8], t->stbc[9]));
+}
+EXPORT_SYMBOL_GPL(mt76x02_phy_set_txpower);
+
+int mt76x02_phy_get_min_avg_rssi(struct mt76x02_dev *dev)
+{
+ struct mt76x02_sta *sta;
+ struct mt76_wcid *wcid;
+ int i, j, min_rssi = 0;
+ s8 cur_rssi;
+
+ local_bh_disable();
+ rcu_read_lock();
+
+ for (i = 0; i < ARRAY_SIZE(dev->mt76.wcid_mask); i++) {
+ unsigned long mask = dev->mt76.wcid_mask[i];
+
+ if (!mask)
+ continue;
+
+ for (j = i * BITS_PER_LONG; mask; j++, mask >>= 1) {
+ if (!(mask & 1))
+ continue;
+
+ wcid = rcu_dereference(dev->mt76.wcid[j]);
+ if (!wcid)
+ continue;
+
+ sta = container_of(wcid, struct mt76x02_sta, wcid);
+ spin_lock(&dev->mt76.rx_lock);
+ if (sta->inactive_count++ < 5)
+ cur_rssi = ewma_signal_read(&sta->rssi);
+ else
+ cur_rssi = 0;
+ spin_unlock(&dev->mt76.rx_lock);
+
+ if (cur_rssi < min_rssi)
+ min_rssi = cur_rssi;
+ }
+ }
+
+ rcu_read_unlock();
+ local_bh_enable();
+
+ if (!min_rssi)
+ return -75;
+
+ return min_rssi;
+}
+EXPORT_SYMBOL_GPL(mt76x02_phy_get_min_avg_rssi);
+
+void mt76x02_phy_set_bw(struct mt76x02_dev *dev, int width, u8 ctrl)
+{
+ int core_val, agc_val;
+
+ switch (width) {
+ case NL80211_CHAN_WIDTH_80:
+ core_val = 3;
+ agc_val = 7;
+ break;
+ case NL80211_CHAN_WIDTH_40:
+ core_val = 2;
+ agc_val = 3;
+ break;
+ default:
+ core_val = 0;
+ agc_val = 1;
+ break;
+ }
+
+ mt76_rmw_field(dev, MT_BBP(CORE, 1), MT_BBP_CORE_R1_BW, core_val);
+ mt76_rmw_field(dev, MT_BBP(AGC, 0), MT_BBP_AGC_R0_BW, agc_val);
+ mt76_rmw_field(dev, MT_BBP(AGC, 0), MT_BBP_AGC_R0_CTRL_CHAN, ctrl);
+ mt76_rmw_field(dev, MT_BBP(TXBE, 0), MT_BBP_TXBE_R0_CTRL_CHAN, ctrl);
+}
+EXPORT_SYMBOL_GPL(mt76x02_phy_set_bw);
+
+void mt76x02_phy_set_band(struct mt76x02_dev *dev, int band,
+ bool primary_upper)
+{
+ switch (band) {
+ case NL80211_BAND_2GHZ:
+ mt76_set(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_2G);
+ mt76_clear(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_5G);
+ break;
+ case NL80211_BAND_5GHZ:
+ mt76_clear(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_2G);
+ mt76_set(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_5G);
+ break;
+ }
+
+ mt76_rmw_field(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_UPPER_40M,
+ primary_upper);
+}
+EXPORT_SYMBOL_GPL(mt76x02_phy_set_band);
+
+bool mt76x02_phy_adjust_vga_gain(struct mt76x02_dev *dev)
+{
+ u8 limit = dev->cal.low_gain > 0 ? 16 : 4;
+ bool ret = false;
+ u32 false_cca;
+
+ false_cca = FIELD_GET(MT_RX_STAT_1_CCA_ERRORS, mt76_rr(dev, MT_RX_STAT_1));
+ dev->cal.false_cca = false_cca;
+ if (false_cca > 800 && dev->cal.agc_gain_adjust < limit) {
+ dev->cal.agc_gain_adjust += 2;
+ ret = true;
+ } else if ((false_cca < 10 && dev->cal.agc_gain_adjust > 0) ||
+ (dev->cal.agc_gain_adjust >= limit && false_cca < 500)) {
+ dev->cal.agc_gain_adjust -= 2;
+ ret = true;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mt76x02_phy_adjust_vga_gain);
+
+void mt76x02_init_agc_gain(struct mt76x02_dev *dev)
+{
+ dev->cal.agc_gain_init[0] = mt76_get_field(dev, MT_BBP(AGC, 8),
+ MT_BBP_AGC_GAIN);
+ dev->cal.agc_gain_init[1] = mt76_get_field(dev, MT_BBP(AGC, 9),
+ MT_BBP_AGC_GAIN);
+ memcpy(dev->cal.agc_gain_cur, dev->cal.agc_gain_init,
+ sizeof(dev->cal.agc_gain_cur));
+ dev->cal.low_gain = -1;
+}
+EXPORT_SYMBOL_GPL(mt76x02_init_agc_gain);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h
new file mode 100644
index 000000000000..2b316cf7c70c
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __MT76x02_PHY_H
+#define __MT76x02_PHY_H
+
+#include "mt76x02_regs.h"
+
+static inline int
+mt76x02_get_rssi_gain_thresh(struct mt76x02_dev *dev)
+{
+ switch (dev->mt76.chandef.width) {
+ case NL80211_CHAN_WIDTH_80:
+ return -62;
+ case NL80211_CHAN_WIDTH_40:
+ return -65;
+ default:
+ return -68;
+ }
+}
+
+static inline int
+mt76x02_get_low_rssi_gain_thresh(struct mt76x02_dev *dev)
+{
+ switch (dev->mt76.chandef.width) {
+ case NL80211_CHAN_WIDTH_80:
+ return -76;
+ case NL80211_CHAN_WIDTH_40:
+ return -79;
+ default:
+ return -82;
+ }
+}
+
+void mt76x02_add_rate_power_offset(struct mt76_rate_power *r, int offset);
+void mt76x02_phy_set_txpower(struct mt76x02_dev *dev, int txp_0, int txp_2);
+void mt76x02_limit_rate_power(struct mt76_rate_power *r, int limit);
+int mt76x02_get_max_rate_power(struct mt76_rate_power *r);
+void mt76x02_phy_set_rxpath(struct mt76x02_dev *dev);
+void mt76x02_phy_set_txdac(struct mt76x02_dev *dev);
+int mt76x02_phy_get_min_avg_rssi(struct mt76x02_dev *dev);
+void mt76x02_phy_set_bw(struct mt76x02_dev *dev, int width, u8 ctrl);
+void mt76x02_phy_set_band(struct mt76x02_dev *dev, int band,
+ bool primary_upper);
+bool mt76x02_phy_adjust_vga_gain(struct mt76x02_dev *dev);
+void mt76x02_init_agc_gain(struct mt76x02_dev *dev);
+
+#endif /* __MT76x02_PHY_H */
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_regs.h b/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h
index 1551ea453180..f7de77d09d28 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_regs.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h
@@ -14,8 +14,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifndef __MT76x2_REGS_H
-#define __MT76x2_REGS_H
+#ifndef __MT76X02_REGS_H
+#define __MT76X02_REGS_H
#define MT_ASIC_VERSION 0x0000
@@ -46,6 +46,11 @@
#define MT_WLAN_FUN_CTRL_WLAN_CLK_EN BIT(1)
#define MT_WLAN_FUN_CTRL_WLAN_RESET_RF BIT(2)
+#define MT_COEXCFG3 0x004c
+
+#define MT_LDO_CTRL_0 0x006c
+#define MT_LDO_CTRL_1 0x0070
+
#define MT_WLAN_FUN_CTRL_WLAN_RESET BIT(3) /* MT76x0 */
#define MT_WLAN_FUN_CTRL_CSR_F20M_CKEN BIT(3) /* MT76x2 */
@@ -75,6 +80,8 @@
#define MT_XO_CTRL7 0x011c
+#define MT_IOCFG_6 0x0124
+
#define MT_USB_U3DMA_CFG 0x9018
#define MT_USB_DMA_CFG_RX_BULK_AGG_TOUT GENMASK(7, 0)
#define MT_USB_DMA_CFG_RX_BULK_AGG_LMT GENMASK(15, 8)
@@ -156,18 +163,23 @@
#define MT_WMM_TXOP_SHIFT(_n) ((_n & 1) * 16)
#define MT_WMM_TXOP_MASK GENMASK(15, 0)
+#define MT_WMM_CTRL 0x0230 /* MT76x0 */
+#define MT_FCE_DMA_ADDR 0x0230
+#define MT_FCE_DMA_LEN 0x0234
+#define MT_USB_DMA_CFG 0x0238
+
#define MT_TSO_CTRL 0x0250
#define MT_HEADER_TRANS_CTRL_REG 0x0260
+#define MT_US_CYC_CFG 0x02a4
+#define MT_US_CYC_CNT GENMASK(7, 0)
+
#define MT_TX_RING_BASE 0x0300
#define MT_RX_RING_BASE 0x03c0
#define MT_TX_HW_QUEUE_MCU 8
#define MT_TX_HW_QUEUE_MGMT 9
-#define MT_US_CYC_CFG 0x02a4
-#define MT_US_CYC_CNT GENMASK(7, 0)
-
#define MT_PBF_SYS_CTRL 0x0400
#define MT_PBF_SYS_CTRL_MCU_RESET BIT(0)
#define MT_PBF_SYS_CTRL_DMA_RESET BIT(1)
@@ -189,10 +201,20 @@
#define MT_BCN_OFFSET_BASE 0x041c
#define MT_BCN_OFFSET(_n) (MT_BCN_OFFSET_BASE + ((_n) << 2))
+#define MT_RXQ_STA 0x0430
+#define MT_TXQ_STA 0x0434
+#define MT_RF_CSR_CFG 0x0500
+#define MT_RF_CSR_CFG_DATA GENMASK(7, 0)
+#define MT_RF_CSR_CFG_REG_ID GENMASK(14, 8)
+#define MT_RF_CSR_CFG_REG_BANK GENMASK(17, 15)
+#define MT_RF_CSR_CFG_WR BIT(30)
+#define MT_RF_CSR_CFG_KICK BIT(31)
+
#define MT_RF_BYPASS_0 0x0504
#define MT_RF_BYPASS_1 0x0508
#define MT_RF_SETTING_0 0x050c
+#define MT_RF_MISC 0x0518
#define MT_RF_DATA_WRITE 0x0524
#define MT_RF_CTRL 0x0528
@@ -203,6 +225,11 @@
#define MT_RF_DATA_READ 0x052c
+#define MT_COM_REG0 0x0730
+#define MT_COM_REG1 0x0734
+#define MT_COM_REG2 0x0738
+#define MT_COM_REG3 0x073C
+
#define MT_FCE_PSE_CTRL 0x0800
#define MT_FCE_PARAMETERS 0x0804
#define MT_FCE_CSO 0x0808
@@ -222,6 +249,7 @@
#define MT_TX_CPU_FROM_FCE_BASE_PTR 0x09a0
#define MT_TX_CPU_FROM_FCE_MAX_COUNT 0x09a4
+#define MT_TX_CPU_FROM_FCE_CPU_DESC_IDX 0x09a8
#define MT_FCE_PDMA_GLOBAL_CONF 0x09c4
#define MT_FCE_SKIP_FS 0x0a6c
@@ -250,6 +278,9 @@
#define MT_MAC_BSSID_DW1_MBSS_IDX_BYTE GENMASK(26, 24)
#define MT_MAX_LEN_CFG 0x1018
+#define MT_MAX_LEN_CFG_AMPDU GENMASK(13, 12)
+
+#define MT_LED_CFG 0x102c
#define MT_AMPDU_MAX_LEN_20M1S 0x1030
#define MT_AMPDU_MAX_LEN_20M2S 0x1034
@@ -365,6 +396,8 @@
#define MT_TX_SW_CFG2 0x1338
#define MT_TXOP_CTRL_CFG 0x1340
+#define MT_TXOP_TRUN_EN GENMASK(5, 0)
+#define MT_TXOP_EXT_CCA_DLY GENMASK(15, 8)
#define MT_TX_RTS_CFG 0x1344
#define MT_TX_RTS_CFG_RETRY_LIMIT GENMASK(7, 0)
@@ -376,7 +409,10 @@
#define MT_TX_RETRY_CFG 0x134c
#define MT_TX_LINK_CFG 0x1350
+#define MT_VHT_HT_FBK_CFG0 0x1354
#define MT_VHT_HT_FBK_CFG1 0x1358
+#define MT_LG_FBK_CFG0 0x135c
+#define MT_LG_FBK_CFG1 0x1360
#define MT_PROT_CFG_RATE GENMASK(15, 0)
#define MT_PROT_CFG_CTRL GENMASK(17, 16)
@@ -391,6 +427,27 @@
#define MT_GF20_PROT_CFG 0x1374
#define MT_GF40_PROT_CFG 0x1378
+#define MT_PROT_RATE GENMASK(15, 0)
+#define MT_PROT_CTRL_RTS_CTS BIT(16)
+#define MT_PROT_CTRL_CTS2SELF BIT(17)
+#define MT_PROT_NAV_SHORT BIT(18)
+#define MT_PROT_NAV_LONG BIT(19)
+#define MT_PROT_TXOP_ALLOW_CCK BIT(20)
+#define MT_PROT_TXOP_ALLOW_OFDM BIT(21)
+#define MT_PROT_TXOP_ALLOW_MM20 BIT(22)
+#define MT_PROT_TXOP_ALLOW_MM40 BIT(23)
+#define MT_PROT_TXOP_ALLOW_GF20 BIT(24)
+#define MT_PROT_TXOP_ALLOW_GF40 BIT(25)
+#define MT_PROT_RTS_THR_EN BIT(26)
+#define MT_PROT_RATE_CCK_11 0x0003
+#define MT_PROT_RATE_OFDM_6 0x4000
+#define MT_PROT_RATE_OFDM_24 0x4004
+#define MT_PROT_RATE_DUP_OFDM_24 0x4084
+#define MT_PROT_TXOP_ALLOW_ALL GENMASK(25, 20)
+#define MT_PROT_TXOP_ALLOW_BW20 (MT_PROT_TXOP_ALLOW_ALL & \
+ ~MT_PROT_TXOP_ALLOW_MM40 & \
+ ~MT_PROT_TXOP_ALLOW_GF40)
+
#define MT_EXP_ACK_TIME 0x1380
#define MT_TX_PWR_CFG_0_EXT 0x1390
@@ -405,6 +462,8 @@
#define MT_TX0_RF_GAIN_CORR 0x13a0
#define MT_TX1_RF_GAIN_CORR 0x13a4
+#define MT_TX0_RF_GAIN_ATTEN 0x13a8
+#define MT_TX0_RF_GAIN_ATTEN 0x13a8 /* MT76x0 */
#define MT_TX_ALC_CFG_0 0x13b0
#define MT_TX_ALC_CFG_0_CH_INIT_0 GENMASK(5, 0)
@@ -421,6 +480,7 @@
#define MT_TX_ALC_CFG_3 0x13ac
#define MT_TX_ALC_CFG_4 0x13c0
#define MT_TX_ALC_CFG_4_LOWGAIN_CH_EN BIT(31)
+#define MT_TX0_BB_GAIN_ATTEN 0x13c0 /* MT76x0 */
#define MT_TX_ALC_VGA3 0x13c8
@@ -451,10 +511,13 @@
#define MT_RX_FILTR_CFG_CTRL_RSV BIT(16)
#define MT_AUTO_RSP_CFG 0x1404
+#define MT_AUTO_RSP_PREAMB_SHORT BIT(4)
#define MT_LEGACY_BASIC_RATE 0x1408
#define MT_HT_BASIC_RATE 0x140c
#define MT_HT_CTRL_CFG 0x1410
+#define MT_RX_PARSER_CFG 0x1418
+#define MT_RX_PARSER_RX_SET_NAV_ALL BIT(0)
#define MT_EXT_CCA_CFG 0x141c
#define MT_EXT_CCA_CFG_CCA0 GENMASK(1, 0)
@@ -498,7 +561,10 @@
#define MT_TX_STAT_FIFO_WCID GENMASK(15, 8)
#define MT_TX_STAT_FIFO_RATE GENMASK(31, 16)
+#define MT_TX_AGG_STAT 0x171c
+
#define MT_TX_AGG_CNT_BASE0 0x1720
+#define MT_MPDU_DENSITY_CNT 0x1740
#define MT_TX_AGG_CNT_BASE1 0x174c
#define MT_TX_AGG_CNT(_id) ((_id) < 8 ? \
@@ -604,7 +670,7 @@ struct mt76_wcid_key {
u8 rx_mic[8];
} __packed __aligned(4);
-enum mt76x2_cipher_type {
+enum mt76x02_cipher_type {
MT_CIPHER_NONE,
MT_CIPHER_WEP40,
MT_CIPHER_WEP104,
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_trace.c b/drivers/net/wireless/mediatek/mt76/mt76x02_trace.c
index a09f117848d6..5b42d2c87937 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_trace.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_trace.c
@@ -18,6 +18,6 @@
#ifndef __CHECKER__
#define CREATE_TRACE_POINTS
-#include "mt76x2_trace.h"
+#include "mt76x02_trace.h"
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_trace.h b/drivers/net/wireless/mediatek/mt76/mt76x02_trace.h
index 4cd424148d4b..713f12d3c8de 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_trace.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_trace.h
@@ -14,14 +14,14 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#if !defined(__MT76x2_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
-#define __MT76x2_TRACE_H
+#if !defined(__MT76x02_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define __MT76x02_TRACE_H
#include <linux/tracepoint.h>
-#include "mt76x2.h"
+#include "mt76x02.h"
#undef TRACE_SYSTEM
-#define TRACE_SYSTEM mt76x2
+#define TRACE_SYSTEM mt76x02
#define MAXNAME 32
#define DEV_ENTRY __array(char, wiphy_name, 32)
@@ -35,7 +35,7 @@
#define TXID_PR_ARG __entry->wcid, __entry->pktid
DECLARE_EVENT_CLASS(dev_evt,
- TP_PROTO(struct mt76x2_dev *dev),
+ TP_PROTO(struct mt76x02_dev *dev),
TP_ARGS(dev),
TP_STRUCT__entry(
DEV_ENTRY
@@ -47,7 +47,7 @@ DECLARE_EVENT_CLASS(dev_evt,
);
DECLARE_EVENT_CLASS(dev_txid_evt,
- TP_PROTO(struct mt76x2_dev *dev, u8 wcid, u8 pktid),
+ TP_PROTO(struct mt76x02_dev *dev, u8 wcid, u8 pktid),
TP_ARGS(dev, wcid, pktid),
TP_STRUCT__entry(
DEV_ENTRY
@@ -63,19 +63,19 @@ DECLARE_EVENT_CLASS(dev_txid_evt,
)
);
-DEFINE_EVENT(dev_evt, mac_txstat_poll,
- TP_PROTO(struct mt76x2_dev *dev),
- TP_ARGS(dev)
-);
-
DEFINE_EVENT(dev_txid_evt, mac_txdone_add,
- TP_PROTO(struct mt76x2_dev *dev, u8 wcid, u8 pktid),
+ TP_PROTO(struct mt76x02_dev *dev, u8 wcid, u8 pktid),
TP_ARGS(dev, wcid, pktid)
);
+DEFINE_EVENT(dev_evt, mac_txstat_poll,
+ TP_PROTO(struct mt76x02_dev *dev),
+ TP_ARGS(dev)
+);
+
TRACE_EVENT(mac_txstat_fetch,
- TP_PROTO(struct mt76x2_dev *dev,
- struct mt76x2_tx_status *stat),
+ TP_PROTO(struct mt76x02_dev *dev,
+ struct mt76x02_tx_status *stat),
TP_ARGS(dev, stat),
@@ -110,9 +110,8 @@ TRACE_EVENT(mac_txstat_fetch,
)
);
-
TRACE_EVENT(dev_irq,
- TP_PROTO(struct mt76x2_dev *dev, u32 val, u32 mask),
+ TP_PROTO(struct mt76x02_dev *dev, u32 val, u32 mask),
TP_ARGS(dev, val, mask),
@@ -139,6 +138,6 @@ TRACE_EVENT(dev_irq,
#undef TRACE_INCLUDE_PATH
#define TRACE_INCLUDE_PATH .
#undef TRACE_INCLUDE_FILE
-#define TRACE_INCLUDE_FILE mt76x2_trace
+#define TRACE_INCLUDE_FILE mt76x02_trace
#include <trace/define_trace.h>
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c
new file mode 100644
index 000000000000..d3de08872d6e
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
+ * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+
+#include "mt76x02.h"
+
+void mt76x02_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
+ struct sk_buff *skb)
+{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct mt76x02_dev *dev = hw->priv;
+ struct ieee80211_vif *vif = info->control.vif;
+ struct mt76_wcid *wcid = &dev->mt76.global_wcid;
+
+ if (control->sta) {
+ struct mt76x02_sta *msta;
+
+ msta = (struct mt76x02_sta *)control->sta->drv_priv;
+ wcid = &msta->wcid;
+ /* sw encrypted frames */
+ if (!info->control.hw_key && wcid->hw_key_idx != 0xff)
+ control->sta = NULL;
+ }
+
+ if (vif && !control->sta) {
+ struct mt76x02_vif *mvif;
+
+ mvif = (struct mt76x02_vif *)vif->drv_priv;
+ wcid = &mvif->group_wcid;
+ }
+
+ mt76_tx(&dev->mt76, control->sta, wcid, skb);
+}
+EXPORT_SYMBOL_GPL(mt76x02_tx);
+
+void mt76x02_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
+ struct sk_buff *skb)
+{
+ struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
+ void *rxwi = skb->data;
+
+ if (q == MT_RXQ_MCU) {
+ /* this is used just by mmio code */
+ skb_queue_tail(&mdev->mmio.mcu.res_q, skb);
+ wake_up(&mdev->mmio.mcu.wait);
+ return;
+ }
+
+ skb_pull(skb, sizeof(struct mt76x02_rxwi));
+ if (mt76x02_mac_process_rx(dev, skb, rxwi)) {
+ dev_kfree_skb(skb);
+ return;
+ }
+
+ mt76_rx(mdev, q, skb);
+}
+EXPORT_SYMBOL_GPL(mt76x02_queue_rx_skb);
+
+s8 mt76x02_tx_get_max_txpwr_adj(struct mt76x02_dev *dev,
+ const struct ieee80211_tx_rate *rate)
+{
+ s8 max_txpwr;
+
+ if (rate->flags & IEEE80211_TX_RC_VHT_MCS) {
+ u8 mcs = ieee80211_rate_get_vht_mcs(rate);
+
+ if (mcs == 8 || mcs == 9) {
+ max_txpwr = dev->mt76.rate_power.vht[8];
+ } else {
+ u8 nss, idx;
+
+ nss = ieee80211_rate_get_vht_nss(rate);
+ idx = ((nss - 1) << 3) + mcs;
+ max_txpwr = dev->mt76.rate_power.ht[idx & 0xf];
+ }
+ } else if (rate->flags & IEEE80211_TX_RC_MCS) {
+ max_txpwr = dev->mt76.rate_power.ht[rate->idx & 0xf];
+ } else {
+ enum nl80211_band band = dev->mt76.chandef.chan->band;
+
+ if (band == NL80211_BAND_2GHZ) {
+ const struct ieee80211_rate *r;
+ struct wiphy *wiphy = dev->mt76.hw->wiphy;
+ struct mt76_rate_power *rp = &dev->mt76.rate_power;
+
+ r = &wiphy->bands[band]->bitrates[rate->idx];
+ if (r->flags & IEEE80211_RATE_SHORT_PREAMBLE)
+ max_txpwr = rp->cck[r->hw_value & 0x3];
+ else
+ max_txpwr = rp->ofdm[r->hw_value & 0x7];
+ } else {
+ max_txpwr = dev->mt76.rate_power.ofdm[rate->idx & 0x7];
+ }
+ }
+
+ return max_txpwr;
+}
+EXPORT_SYMBOL_GPL(mt76x02_tx_get_max_txpwr_adj);
+
+s8 mt76x02_tx_get_txpwr_adj(struct mt76x02_dev *dev, s8 txpwr, s8 max_txpwr_adj)
+{
+ txpwr = min_t(s8, txpwr, dev->mt76.txpower_conf);
+ txpwr -= (dev->target_power + dev->target_power_delta[0]);
+ txpwr = min_t(s8, txpwr, max_txpwr_adj);
+
+ if (!dev->enable_tpc)
+ return 0;
+ else if (txpwr >= 0)
+ return min_t(s8, txpwr, 7);
+ else
+ return (txpwr < -16) ? 8 : (txpwr + 32) / 2;
+}
+EXPORT_SYMBOL_GPL(mt76x02_tx_get_txpwr_adj);
+
+void mt76x02_tx_set_txpwr_auto(struct mt76x02_dev *dev, s8 txpwr)
+{
+ s8 txpwr_adj;
+
+ txpwr_adj = mt76x02_tx_get_txpwr_adj(dev, txpwr,
+ dev->mt76.rate_power.ofdm[4]);
+ mt76_rmw_field(dev, MT_PROT_AUTO_TX_CFG,
+ MT_PROT_AUTO_TX_CFG_PROT_PADJ, txpwr_adj);
+ mt76_rmw_field(dev, MT_PROT_AUTO_TX_CFG,
+ MT_PROT_AUTO_TX_CFG_AUTO_PADJ, txpwr_adj);
+}
+EXPORT_SYMBOL_GPL(mt76x02_tx_set_txpwr_auto);
+
+void mt76x02_tx_complete(struct mt76_dev *dev, struct sk_buff *skb)
+{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+ if (info->flags & IEEE80211_TX_CTL_AMPDU) {
+ ieee80211_free_txskb(dev->hw, skb);
+ } else {
+ ieee80211_tx_info_clear_status(info);
+ info->status.rates[0].idx = -1;
+ info->flags |= IEEE80211_TX_STAT_ACK;
+ ieee80211_tx_status(dev->hw, skb);
+ }
+}
+EXPORT_SYMBOL_GPL(mt76x02_tx_complete);
+
+bool mt76x02_tx_status_data(struct mt76_dev *mdev, u8 *update)
+{
+ struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
+ struct mt76x02_tx_status stat;
+
+ if (!mt76x02_mac_load_tx_status(dev, &stat))
+ return false;
+
+ mt76x02_send_tx_status(dev, &stat, update);
+
+ return true;
+}
+EXPORT_SYMBOL_GPL(mt76x02_tx_status_data);
+
+int mt76x02_tx_prepare_skb(struct mt76_dev *mdev, void *txwi,
+ struct sk_buff *skb, struct mt76_queue *q,
+ struct mt76_wcid *wcid, struct ieee80211_sta *sta,
+ u32 *tx_info)
+{
+ struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ int qsel = MT_QSEL_EDCA;
+ int ret;
+
+ if (q == &dev->mt76.q_tx[MT_TXQ_PSD] && wcid && wcid->idx < 128)
+ mt76x02_mac_wcid_set_drop(dev, wcid->idx, false);
+
+ mt76x02_mac_write_txwi(dev, txwi, skb, wcid, sta, skb->len);
+
+ ret = mt76x02_insert_hdr_pad(skb);
+ if (ret < 0)
+ return ret;
+
+ if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)
+ qsel = MT_QSEL_MGMT;
+
+ *tx_info = FIELD_PREP(MT_TXD_INFO_QSEL, qsel) |
+ MT_TXD_INFO_80211;
+
+ if (!wcid || wcid->hw_key_idx == 0xff || wcid->sw_iv)
+ *tx_info |= MT_TXD_INFO_WIV;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt76x02_tx_prepare_skb);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h b/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h
new file mode 100644
index 000000000000..0126e51d77ed
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __MT76x02_USB_H
+#define __MT76x02_USB_H
+
+#include "mt76x02.h"
+
+void mt76x02u_init_mcu(struct mt76_dev *dev);
+void mt76x02u_mcu_fw_reset(struct mt76x02_dev *dev);
+int mt76x02u_mcu_fw_send_data(struct mt76x02_dev *dev, const void *data,
+ int data_len, u32 max_payload, u32 offset);
+
+int mt76x02u_skb_dma_info(struct sk_buff *skb, int port, u32 flags);
+int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data,
+ struct sk_buff *skb, struct mt76_queue *q,
+ struct mt76_wcid *wcid, struct ieee80211_sta *sta,
+ u32 *tx_info);
+void mt76x02u_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q,
+ struct mt76_queue_entry *e, bool flush);
+#endif /* __MT76x02_USB_H */
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
new file mode 100644
index 000000000000..dc2226c722dd
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "mt76x02.h"
+
+static void mt76x02u_remove_dma_hdr(struct sk_buff *skb)
+{
+ int hdr_len;
+
+ skb_pull(skb, sizeof(struct mt76x02_txwi) + MT_DMA_HDR_LEN);
+ hdr_len = ieee80211_get_hdrlen_from_skb(skb);
+ if (hdr_len % 4)
+ mt76x02_remove_hdr_pad(skb, 2);
+}
+
+void mt76x02u_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q,
+ struct mt76_queue_entry *e, bool flush)
+{
+ mt76x02u_remove_dma_hdr(e->skb);
+ mt76x02_tx_complete(mdev, e->skb);
+}
+EXPORT_SYMBOL_GPL(mt76x02u_tx_complete_skb);
+
+int mt76x02u_skb_dma_info(struct sk_buff *skb, int port, u32 flags)
+{
+ struct sk_buff *iter, *last = skb;
+ u32 info, pad;
+
+ /* Buffer layout:
+ * | 4B | xfer len | pad | 4B |
+ * | TXINFO | pkt/cmd | zero pad to 4B | zero |
+ *
+ * length field of TXINFO should be set to 'xfer len'.
+ */
+ info = FIELD_PREP(MT_TXD_INFO_LEN, round_up(skb->len, 4)) |
+ FIELD_PREP(MT_TXD_INFO_DPORT, port) | flags;
+ put_unaligned_le32(info, skb_push(skb, sizeof(info)));
+
+ pad = round_up(skb->len, 4) + 4 - skb->len;
+ skb_walk_frags(skb, iter) {
+ last = iter;
+ if (!iter->next) {
+ skb->data_len += pad;
+ skb->len += pad;
+ break;
+ }
+ }
+
+ if (unlikely(pad)) {
+ if (skb_pad(last, pad))
+ return -ENOMEM;
+ __skb_put(last, pad);
+ }
+ return 0;
+}
+
+static int
+mt76x02u_set_txinfo(struct sk_buff *skb, struct mt76_wcid *wcid, u8 ep)
+{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ enum mt76_qsel qsel;
+ u32 flags;
+
+ if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) ||
+ ep == MT_EP_OUT_HCCA)
+ qsel = MT_QSEL_MGMT;
+ else
+ qsel = MT_QSEL_EDCA;
+
+ flags = FIELD_PREP(MT_TXD_INFO_QSEL, qsel) |
+ MT_TXD_INFO_80211;
+ if (!wcid || wcid->hw_key_idx == 0xff || wcid->sw_iv)
+ flags |= MT_TXD_INFO_WIV;
+
+ return mt76x02u_skb_dma_info(skb, WLAN_PORT, flags);
+}
+
+int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data,
+ struct sk_buff *skb, struct mt76_queue *q,
+ struct mt76_wcid *wcid, struct ieee80211_sta *sta,
+ u32 *tx_info)
+{
+ struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
+ struct mt76x02_txwi *txwi;
+ int len = skb->len;
+
+ mt76x02_insert_hdr_pad(skb);
+
+ txwi = skb_push(skb, sizeof(struct mt76x02_txwi));
+ mt76x02_mac_write_txwi(dev, txwi, skb, wcid, sta, len);
+
+ return mt76x02u_set_txinfo(skb, wcid, q2ep(q->hw_idx));
+}
+EXPORT_SYMBOL_GPL(mt76x02u_tx_prepare_skb);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c
new file mode 100644
index 000000000000..da299b8a1334
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/firmware.h>
+
+#include "mt76x02.h"
+#include "mt76x02_mcu.h"
+#include "mt76x02_usb.h"
+
+#define MT_CMD_HDR_LEN 4
+
+#define MT_FCE_DMA_ADDR 0x0230
+#define MT_FCE_DMA_LEN 0x0234
+
+#define MT_TX_CPU_FROM_FCE_CPU_DESC_IDX 0x09a8
+
+static struct sk_buff *
+mt76x02u_mcu_msg_alloc(const void *data, int len)
+{
+ struct sk_buff *skb;
+
+ skb = alloc_skb(MT_CMD_HDR_LEN + len + 8, GFP_KERNEL);
+ if (!skb)
+ return NULL;
+
+ skb_reserve(skb, MT_CMD_HDR_LEN);
+ skb_put_data(skb, data, len);
+
+ return skb;
+}
+
+static void
+mt76x02u_multiple_mcu_reads(struct mt76_dev *dev, u8 *data, int len)
+{
+ struct mt76_usb *usb = &dev->usb;
+ u32 reg, val;
+ int i;
+
+ if (usb->mcu.burst) {
+ WARN_ON_ONCE(len / 4 != usb->mcu.rp_len);
+
+ reg = usb->mcu.rp[0].reg - usb->mcu.base;
+ for (i = 0; i < usb->mcu.rp_len; i++) {
+ val = get_unaligned_le32(data + 4 * i);
+ usb->mcu.rp[i].reg = reg++;
+ usb->mcu.rp[i].value = val;
+ }
+ } else {
+ WARN_ON_ONCE(len / 8 != usb->mcu.rp_len);
+
+ for (i = 0; i < usb->mcu.rp_len; i++) {
+ reg = get_unaligned_le32(data + 8 * i) -
+ usb->mcu.base;
+ val = get_unaligned_le32(data + 8 * i + 4);
+
+ WARN_ON_ONCE(usb->mcu.rp[i].reg != reg);
+ usb->mcu.rp[i].value = val;
+ }
+ }
+}
+
+static int mt76x02u_mcu_wait_resp(struct mt76_dev *dev, u8 seq)
+{
+ struct mt76_usb *usb = &dev->usb;
+ struct mt76u_buf *buf = &usb->mcu.res;
+ struct urb *urb = buf->urb;
+ int i, ret;
+ u32 rxfce;
+ u8 *data;
+
+ for (i = 0; i < 5; i++) {
+ if (!wait_for_completion_timeout(&usb->mcu.cmpl,
+ msecs_to_jiffies(300)))
+ continue;
+
+ if (urb->status)
+ return -EIO;
+
+ data = sg_virt(&urb->sg[0]);
+ if (usb->mcu.rp)
+ mt76x02u_multiple_mcu_reads(dev, data + 4,
+ urb->actual_length - 8);
+
+ rxfce = get_unaligned_le32(data);
+ ret = mt76u_submit_buf(dev, USB_DIR_IN,
+ MT_EP_IN_CMD_RESP,
+ buf, GFP_KERNEL,
+ mt76u_mcu_complete_urb,
+ &usb->mcu.cmpl);
+ if (ret)
+ return ret;
+
+ if (seq == FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, rxfce) &&
+ FIELD_GET(MT_RX_FCE_INFO_EVT_TYPE, rxfce) == EVT_CMD_DONE)
+ return 0;
+
+ dev_err(dev->dev, "error: MCU resp evt:%lx seq:%hhx-%lx\n",
+ FIELD_GET(MT_RX_FCE_INFO_EVT_TYPE, rxfce),
+ seq, FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, rxfce));
+ }
+
+ dev_err(dev->dev, "error: %s timed out\n", __func__);
+ return -ETIMEDOUT;
+}
+
+static int
+__mt76x02u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb,
+ int cmd, bool wait_resp)
+{
+ struct usb_interface *intf = to_usb_interface(dev->dev);
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct mt76_usb *usb = &dev->usb;
+ unsigned int pipe;
+ int ret, sent;
+ u8 seq = 0;
+ u32 info;
+
+ if (!skb)
+ return -EINVAL;
+
+ if (test_bit(MT76_REMOVED, &dev->state))
+ return 0;
+
+ pipe = usb_sndbulkpipe(udev, usb->out_ep[MT_EP_OUT_INBAND_CMD]);
+ if (wait_resp) {
+ seq = ++usb->mcu.msg_seq & 0xf;
+ if (!seq)
+ seq = ++usb->mcu.msg_seq & 0xf;
+ }
+
+ info = FIELD_PREP(MT_MCU_MSG_CMD_SEQ, seq) |
+ FIELD_PREP(MT_MCU_MSG_CMD_TYPE, cmd) |
+ MT_MCU_MSG_TYPE_CMD;
+ ret = mt76x02u_skb_dma_info(skb, CPU_TX_PORT, info);
+ if (ret)
+ return ret;
+
+ ret = usb_bulk_msg(udev, pipe, skb->data, skb->len, &sent, 500);
+ if (ret)
+ return ret;
+
+ if (wait_resp)
+ ret = mt76x02u_mcu_wait_resp(dev, seq);
+
+ consume_skb(skb);
+
+ return ret;
+}
+
+static int
+mt76x02u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb,
+ int cmd, bool wait_resp)
+{
+ struct mt76_usb *usb = &dev->usb;
+ int err;
+
+ mutex_lock(&usb->mcu.mutex);
+ err = __mt76x02u_mcu_send_msg(dev, skb, cmd, wait_resp);
+ mutex_unlock(&usb->mcu.mutex);
+
+ return err;
+}
+
+static inline void skb_put_le32(struct sk_buff *skb, u32 val)
+{
+ put_unaligned_le32(val, skb_put(skb, 4));
+}
+
+static int
+mt76x02u_mcu_wr_rp(struct mt76_dev *dev, u32 base,
+ const struct mt76_reg_pair *data, int n)
+{
+ const int CMD_RANDOM_WRITE = 12;
+ const int max_vals_per_cmd = MT_INBAND_PACKET_MAX_LEN / 8;
+ struct sk_buff *skb;
+ int cnt, i, ret;
+
+ if (!n)
+ return 0;
+
+ cnt = min(max_vals_per_cmd, n);
+
+ skb = alloc_skb(cnt * 8 + MT_DMA_HDR_LEN + 4, GFP_KERNEL);
+ if (!skb)
+ return -ENOMEM;
+ skb_reserve(skb, MT_DMA_HDR_LEN);
+
+ for (i = 0; i < cnt; i++) {
+ skb_put_le32(skb, base + data[i].reg);
+ skb_put_le32(skb, data[i].value);
+ }
+
+ ret = mt76x02u_mcu_send_msg(dev, skb, CMD_RANDOM_WRITE, cnt == n);
+ if (ret)
+ return ret;
+
+ return mt76x02u_mcu_wr_rp(dev, base, data + cnt, n - cnt);
+}
+
+static int
+mt76x02u_mcu_rd_rp(struct mt76_dev *dev, u32 base,
+ struct mt76_reg_pair *data, int n)
+{
+ const int CMD_RANDOM_READ = 10;
+ const int max_vals_per_cmd = MT_INBAND_PACKET_MAX_LEN / 8;
+ struct mt76_usb *usb = &dev->usb;
+ struct sk_buff *skb;
+ int cnt, i, ret;
+
+ if (!n)
+ return 0;
+
+ cnt = min(max_vals_per_cmd, n);
+ if (cnt != n)
+ return -EINVAL;
+
+ skb = alloc_skb(cnt * 8 + MT_DMA_HDR_LEN + 4, GFP_KERNEL);
+ if (!skb)
+ return -ENOMEM;
+ skb_reserve(skb, MT_DMA_HDR_LEN);
+
+ for (i = 0; i < cnt; i++) {
+ skb_put_le32(skb, base + data[i].reg);
+ skb_put_le32(skb, data[i].value);
+ }
+
+ mutex_lock(&usb->mcu.mutex);
+
+ usb->mcu.rp = data;
+ usb->mcu.rp_len = n;
+ usb->mcu.base = base;
+ usb->mcu.burst = false;
+
+ ret = __mt76x02u_mcu_send_msg(dev, skb, CMD_RANDOM_READ, true);
+
+ usb->mcu.rp = NULL;
+
+ mutex_unlock(&usb->mcu.mutex);
+
+ return ret;
+}
+
+void mt76x02u_mcu_fw_reset(struct mt76x02_dev *dev)
+{
+ mt76u_vendor_request(&dev->mt76, MT_VEND_DEV_MODE,
+ USB_DIR_OUT | USB_TYPE_VENDOR,
+ 0x1, 0, NULL, 0);
+}
+EXPORT_SYMBOL_GPL(mt76x02u_mcu_fw_reset);
+
+static int
+__mt76x02u_mcu_fw_send_data(struct mt76x02_dev *dev, struct mt76u_buf *buf,
+ const void *fw_data, int len, u32 dst_addr)
+{
+ u8 *data = sg_virt(&buf->urb->sg[0]);
+ DECLARE_COMPLETION_ONSTACK(cmpl);
+ __le32 info;
+ u32 val;
+ int err;
+
+ info = cpu_to_le32(FIELD_PREP(MT_MCU_MSG_PORT, CPU_TX_PORT) |
+ FIELD_PREP(MT_MCU_MSG_LEN, len) |
+ MT_MCU_MSG_TYPE_CMD);
+
+ memcpy(data, &info, sizeof(info));
+ memcpy(data + sizeof(info), fw_data, len);
+ memset(data + sizeof(info) + len, 0, 4);
+
+ mt76u_single_wr(&dev->mt76, MT_VEND_WRITE_FCE,
+ MT_FCE_DMA_ADDR, dst_addr);
+ len = roundup(len, 4);
+ mt76u_single_wr(&dev->mt76, MT_VEND_WRITE_FCE,
+ MT_FCE_DMA_LEN, len << 16);
+
+ buf->len = MT_CMD_HDR_LEN + len + sizeof(info);
+ err = mt76u_submit_buf(&dev->mt76, USB_DIR_OUT,
+ MT_EP_OUT_INBAND_CMD,
+ buf, GFP_KERNEL,
+ mt76u_mcu_complete_urb, &cmpl);
+ if (err < 0)
+ return err;
+
+ if (!wait_for_completion_timeout(&cmpl,
+ msecs_to_jiffies(1000))) {
+ dev_err(dev->mt76.dev, "firmware upload timed out\n");
+ usb_kill_urb(buf->urb);
+ return -ETIMEDOUT;
+ }
+
+ if (mt76u_urb_error(buf->urb)) {
+ dev_err(dev->mt76.dev, "firmware upload failed: %d\n",
+ buf->urb->status);
+ return buf->urb->status;
+ }
+
+ val = mt76_rr(dev, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX);
+ val++;
+ mt76_wr(dev, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX, val);
+
+ return 0;
+}
+
+int mt76x02u_mcu_fw_send_data(struct mt76x02_dev *dev, const void *data,
+ int data_len, u32 max_payload, u32 offset)
+{
+ int err, len, pos = 0, max_len = max_payload - 8;
+ struct mt76u_buf buf;
+
+ err = mt76u_buf_alloc(&dev->mt76, &buf, 1, max_payload, max_payload,
+ GFP_KERNEL);
+ if (err < 0)
+ return err;
+
+ while (data_len > 0) {
+ len = min_t(int, data_len, max_len);
+ err = __mt76x02u_mcu_fw_send_data(dev, &buf, data + pos,
+ len, offset + pos);
+ if (err < 0)
+ break;
+
+ data_len -= len;
+ pos += len;
+ usleep_range(5000, 10000);
+ }
+ mt76u_buf_free(&buf);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(mt76x02u_mcu_fw_send_data);
+
+void mt76x02u_init_mcu(struct mt76_dev *dev)
+{
+ static const struct mt76_mcu_ops mt76x02u_mcu_ops = {
+ .mcu_msg_alloc = mt76x02u_mcu_msg_alloc,
+ .mcu_send_msg = mt76x02u_mcu_send_msg,
+ .mcu_wr_rp = mt76x02u_mcu_wr_rp,
+ .mcu_rd_rp = mt76x02u_mcu_rd_rp,
+ };
+
+ dev->mcu_ops = &mt76x02u_mcu_ops;
+}
+EXPORT_SYMBOL_GPL(mt76x02u_init_mcu);
+
+MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
new file mode 100644
index 000000000000..ca05332f81fc
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
@@ -0,0 +1,446 @@
+/*
+ * Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl>
+ * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include "mt76x02.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) | (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),
+ OFDM_RATE(0, 60),
+ OFDM_RATE(1, 90),
+ OFDM_RATE(2, 120),
+ OFDM_RATE(3, 180),
+ OFDM_RATE(4, 240),
+ OFDM_RATE(5, 360),
+ OFDM_RATE(6, 480),
+ OFDM_RATE(7, 540),
+};
+EXPORT_SYMBOL_GPL(mt76x02_rates);
+
+void mt76x02_configure_filter(struct ieee80211_hw *hw,
+ unsigned int changed_flags,
+ unsigned int *total_flags, u64 multicast)
+{
+ struct mt76x02_dev *dev = hw->priv;
+ u32 flags = 0;
+
+#define MT76_FILTER(_flag, _hw) do { \
+ flags |= *total_flags & FIF_##_flag; \
+ dev->mt76.rxfilter &= ~(_hw); \
+ dev->mt76.rxfilter |= !(flags & FIF_##_flag) * (_hw); \
+ } while (0)
+
+ mutex_lock(&dev->mt76.mutex);
+
+ dev->mt76.rxfilter &= ~MT_RX_FILTR_CFG_OTHER_BSS;
+
+ MT76_FILTER(FCSFAIL, MT_RX_FILTR_CFG_CRC_ERR);
+ MT76_FILTER(PLCPFAIL, MT_RX_FILTR_CFG_PHY_ERR);
+ MT76_FILTER(CONTROL, MT_RX_FILTR_CFG_ACK |
+ MT_RX_FILTR_CFG_CTS |
+ MT_RX_FILTR_CFG_CFEND |
+ MT_RX_FILTR_CFG_CFACK |
+ MT_RX_FILTR_CFG_BA |
+ MT_RX_FILTR_CFG_CTRL_RSV);
+ MT76_FILTER(PSPOLL, MT_RX_FILTR_CFG_PSPOLL);
+
+ *total_flags = flags;
+ mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter);
+
+ mutex_unlock(&dev->mt76.mutex);
+}
+EXPORT_SYMBOL_GPL(mt76x02_configure_filter);
+
+int mt76x02_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct mt76x02_dev *dev = hw->priv;
+ struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv;
+ struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv;
+ int ret = 0;
+ int idx = 0;
+ int i;
+
+ mutex_lock(&dev->mt76.mutex);
+
+ idx = mt76_wcid_alloc(dev->mt76.wcid_mask, ARRAY_SIZE(dev->mt76.wcid));
+ if (idx < 0) {
+ ret = -ENOSPC;
+ goto out;
+ }
+
+ msta->vif = mvif;
+ msta->wcid.sta = 1;
+ msta->wcid.idx = idx;
+ msta->wcid.hw_key_idx = -1;
+ mt76x02_mac_wcid_setup(dev, idx, mvif->idx, sta->addr);
+ mt76x02_mac_wcid_set_drop(dev, idx, false);
+ for (i = 0; i < ARRAY_SIZE(sta->txq); i++)
+ mt76x02_txq_init(dev, sta->txq[i]);
+
+ if (vif->type == NL80211_IFTYPE_AP)
+ set_bit(MT_WCID_FLAG_CHECK_PS, &msta->wcid.flags);
+
+ ewma_signal_init(&msta->rssi);
+
+ rcu_assign_pointer(dev->mt76.wcid[idx], &msta->wcid);
+
+out:
+ mutex_unlock(&dev->mt76.mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mt76x02_sta_add);
+
+int mt76x02_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct mt76x02_dev *dev = hw->priv;
+ struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv;
+ int idx = msta->wcid.idx;
+ int i;
+
+ mutex_lock(&dev->mt76.mutex);
+ rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
+ for (i = 0; i < ARRAY_SIZE(sta->txq); i++)
+ mt76_txq_remove(&dev->mt76, sta->txq[i]);
+ mt76x02_mac_wcid_set_drop(dev, idx, true);
+ mt76_wcid_free(dev->mt76.wcid_mask, idx);
+ mt76x02_mac_wcid_setup(dev, idx, 0, NULL);
+ mutex_unlock(&dev->mt76.mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt76x02_sta_remove);
+
+void mt76x02_vif_init(struct mt76x02_dev *dev, struct ieee80211_vif *vif,
+ unsigned int idx)
+{
+ struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv;
+
+ mvif->idx = idx;
+ mvif->group_wcid.idx = MT_VIF_WCID(idx);
+ mvif->group_wcid.hw_key_idx = -1;
+ mt76x02_txq_init(dev, vif->txq);
+}
+EXPORT_SYMBOL_GPL(mt76x02_vif_init);
+
+int
+mt76x02_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+{
+ struct mt76x02_dev *dev = hw->priv;
+ unsigned int idx = 0;
+
+ if (vif->addr[0] & BIT(1))
+ idx = 1 + (((dev->mt76.macaddr[0] ^ vif->addr[0]) >> 2) & 7);
+
+ /*
+ * Client mode typically only has one configurable BSSID register,
+ * which is used for bssidx=0. This is linked to the MAC address.
+ * Since mac80211 allows changing interface types, and we cannot
+ * force the use of the primary MAC address for a station mode
+ * interface, we need some other way of configuring a per-interface
+ * remote BSSID.
+ * The hardware provides an AP-Client feature, where bssidx 0-7 are
+ * used for AP mode and bssidx 8-15 for client mode.
+ * We shift the station interface bss index by 8 to force the
+ * hardware to recognize the BSSID.
+ * The resulting bssidx mismatch for unicast frames is ignored by hw.
+ */
+ if (vif->type == NL80211_IFTYPE_STATION)
+ idx += 8;
+
+ mt76x02_vif_init(dev, vif, idx);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt76x02_add_interface);
+
+void mt76x02_remove_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct mt76x02_dev *dev = hw->priv;
+
+ mt76_txq_remove(&dev->mt76, vif->txq);
+}
+EXPORT_SYMBOL_GPL(mt76x02_remove_interface);
+
+int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_ampdu_params *params)
+{
+ enum ieee80211_ampdu_mlme_action action = params->action;
+ struct ieee80211_sta *sta = params->sta;
+ struct mt76x02_dev *dev = hw->priv;
+ struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv;
+ struct ieee80211_txq *txq = sta->txq[params->tid];
+ u16 tid = params->tid;
+ u16 *ssn = &params->ssn;
+ struct mt76_txq *mtxq;
+
+ if (!txq)
+ return -EINVAL;
+
+ mtxq = (struct mt76_txq *)txq->drv_priv;
+
+ switch (action) {
+ case IEEE80211_AMPDU_RX_START:
+ mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid,
+ *ssn, params->buf_size);
+ mt76_set(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid));
+ break;
+ case IEEE80211_AMPDU_RX_STOP:
+ mt76_rx_aggr_stop(&dev->mt76, &msta->wcid, tid);
+ mt76_clear(dev, MT_WCID_ADDR(msta->wcid.idx) + 4,
+ BIT(16 + tid));
+ break;
+ case IEEE80211_AMPDU_TX_OPERATIONAL:
+ mtxq->aggr = true;
+ mtxq->send_bar = false;
+ ieee80211_send_bar(vif, sta->addr, tid, mtxq->agg_ssn);
+ break;
+ case IEEE80211_AMPDU_TX_STOP_FLUSH:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
+ mtxq->aggr = false;
+ ieee80211_send_bar(vif, sta->addr, tid, mtxq->agg_ssn);
+ break;
+ case IEEE80211_AMPDU_TX_START:
+ mtxq->agg_ssn = *ssn << 4;
+ ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+ break;
+ case IEEE80211_AMPDU_TX_STOP_CONT:
+ mtxq->aggr = false;
+ ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+ break;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt76x02_ampdu_action);
+
+int mt76x02_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key)
+{
+ struct mt76x02_dev *dev = hw->priv;
+ struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv;
+ struct mt76x02_sta *msta;
+ struct mt76_wcid *wcid;
+ int idx = key->keyidx;
+ int ret;
+
+ /* fall back to sw encryption for unsupported ciphers */
+ switch (key->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ case WLAN_CIPHER_SUITE_TKIP:
+ case WLAN_CIPHER_SUITE_CCMP:
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ /*
+ * The hardware does not support per-STA RX GTK, fall back
+ * to software mode for these.
+ */
+ if ((vif->type == NL80211_IFTYPE_ADHOC ||
+ vif->type == NL80211_IFTYPE_MESH_POINT) &&
+ (key->cipher == WLAN_CIPHER_SUITE_TKIP ||
+ key->cipher == WLAN_CIPHER_SUITE_CCMP) &&
+ !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
+ return -EOPNOTSUPP;
+
+ msta = sta ? (struct mt76x02_sta *) sta->drv_priv : NULL;
+ wcid = msta ? &msta->wcid : &mvif->group_wcid;
+
+ if (cmd == SET_KEY) {
+ key->hw_key_idx = wcid->idx;
+ wcid->hw_key_idx = idx;
+ if (key->flags & IEEE80211_KEY_FLAG_RX_MGMT) {
+ key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
+ wcid->sw_iv = true;
+ }
+ } else {
+ if (idx == wcid->hw_key_idx) {
+ wcid->hw_key_idx = -1;
+ wcid->sw_iv = true;
+ }
+
+ key = NULL;
+ }
+ mt76_wcid_key_setup(&dev->mt76, wcid, key);
+
+ if (!msta) {
+ if (key || wcid->hw_key_idx == idx) {
+ ret = mt76x02_mac_wcid_set_key(dev, wcid->idx, key);
+ if (ret)
+ return ret;
+ }
+
+ return mt76x02_mac_shared_key_setup(dev, mvif->idx, idx, key);
+ }
+
+ return mt76x02_mac_wcid_set_key(dev, msta->wcid.idx, key);
+}
+EXPORT_SYMBOL_GPL(mt76x02_set_key);
+
+int mt76x02_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ u16 queue, const struct ieee80211_tx_queue_params *params)
+{
+ struct mt76x02_dev *dev = hw->priv;
+ u8 cw_min = 5, cw_max = 10, qid;
+ u32 val;
+
+ qid = dev->mt76.q_tx[queue].hw_idx;
+
+ if (params->cw_min)
+ cw_min = fls(params->cw_min);
+ if (params->cw_max)
+ cw_max = fls(params->cw_max);
+
+ val = FIELD_PREP(MT_EDCA_CFG_TXOP, params->txop) |
+ FIELD_PREP(MT_EDCA_CFG_AIFSN, params->aifs) |
+ FIELD_PREP(MT_EDCA_CFG_CWMIN, cw_min) |
+ FIELD_PREP(MT_EDCA_CFG_CWMAX, cw_max);
+ mt76_wr(dev, MT_EDCA_CFG_AC(qid), val);
+
+ val = mt76_rr(dev, MT_WMM_TXOP(qid));
+ val &= ~(MT_WMM_TXOP_MASK << MT_WMM_TXOP_SHIFT(qid));
+ val |= params->txop << MT_WMM_TXOP_SHIFT(qid);
+ mt76_wr(dev, MT_WMM_TXOP(qid), val);
+
+ val = mt76_rr(dev, MT_WMM_AIFSN);
+ val &= ~(MT_WMM_AIFSN_MASK << MT_WMM_AIFSN_SHIFT(qid));
+ val |= params->aifs << MT_WMM_AIFSN_SHIFT(qid);
+ mt76_wr(dev, MT_WMM_AIFSN, val);
+
+ val = mt76_rr(dev, MT_WMM_CWMIN);
+ val &= ~(MT_WMM_CWMIN_MASK << MT_WMM_CWMIN_SHIFT(qid));
+ val |= cw_min << MT_WMM_CWMIN_SHIFT(qid);
+ mt76_wr(dev, MT_WMM_CWMIN, val);
+
+ val = mt76_rr(dev, MT_WMM_CWMAX);
+ val &= ~(MT_WMM_CWMAX_MASK << MT_WMM_CWMAX_SHIFT(qid));
+ val |= cw_max << MT_WMM_CWMAX_SHIFT(qid);
+ mt76_wr(dev, MT_WMM_CWMAX, val);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt76x02_conf_tx);
+
+void mt76x02_sta_rate_tbl_update(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct mt76x02_dev *dev = hw->priv;
+ struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv;
+ struct ieee80211_sta_rates *rates = rcu_dereference(sta->rates);
+ struct ieee80211_tx_rate rate = {};
+
+ if (!rates)
+ return;
+
+ rate.idx = rates->rate[0].idx;
+ rate.flags = rates->rate[0].flags;
+ mt76x02_mac_wcid_set_rate(dev, &msta->wcid, &rate);
+ msta->wcid.max_txpwr_adj = mt76x02_tx_get_max_txpwr_adj(dev, &rate);
+}
+EXPORT_SYMBOL_GPL(mt76x02_sta_rate_tbl_update);
+
+int mt76x02_insert_hdr_pad(struct sk_buff *skb)
+{
+ int len = ieee80211_get_hdrlen_from_skb(skb);
+
+ if (len % 4 == 0)
+ return 0;
+
+ skb_push(skb, 2);
+ memmove(skb->data, skb->data + 2, len);
+
+ skb->data[len] = 0;
+ skb->data[len + 1] = 0;
+ return 2;
+}
+EXPORT_SYMBOL_GPL(mt76x02_insert_hdr_pad);
+
+void mt76x02_remove_hdr_pad(struct sk_buff *skb, int len)
+{
+ int hdrlen;
+
+ if (!len)
+ return;
+
+ hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+ memmove(skb->data + len, skb->data, hdrlen);
+ skb_pull(skb, len);
+}
+EXPORT_SYMBOL_GPL(mt76x02_remove_hdr_pad);
+
+const u16 mt76x02_beacon_offsets[16] = {
+ /* 1024 byte per beacon */
+ 0xc000,
+ 0xc400,
+ 0xc800,
+ 0xcc00,
+ 0xd000,
+ 0xd400,
+ 0xd800,
+ 0xdc00,
+ /* BSS idx 8-15 not used for beacons */
+ 0xc000,
+ 0xc000,
+ 0xc000,
+ 0xc000,
+ 0xc000,
+ 0xc000,
+ 0xc000,
+ 0xc000,
+};
+EXPORT_SYMBOL_GPL(mt76x02_beacon_offsets);
+
+void mt76x02_set_beacon_offsets(struct mt76x02_dev *dev)
+{
+ u16 val, base = MT_BEACON_BASE;
+ u32 regs[4] = {};
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ val = mt76x02_beacon_offsets[i] - base;
+ regs[i / 4] |= (val / 64) << (8 * (i % 4));
+ }
+
+ for (i = 0; i < 4; i++)
+ mt76_wr(dev, MT_BCN_OFFSET(i), regs[i]);
+}
+EXPORT_SYMBOL_GPL(mt76x02_set_beacon_offsets);
+
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h
deleted file mode 100644
index dca3209bf5f1..000000000000
--- a/drivers/net/wireless/mediatek/mt76/mt76x2.h
+++ /dev/null
@@ -1,330 +0,0 @@
-/*
- * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef __MT76x2_H
-#define __MT76x2_H
-
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-#include <linux/spinlock.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/mutex.h>
-#include <linux/bitops.h>
-#include <linux/kfifo.h>
-#include <linux/average.h>
-
-#define MT7662_FIRMWARE "mt7662.bin"
-#define MT7662_ROM_PATCH "mt7662_rom_patch.bin"
-#define MT7662_EEPROM_SIZE 512
-
-#define MT7662U_FIRMWARE "mediatek/mt7662u.bin"
-#define MT7662U_ROM_PATCH "mediatek/mt7662u_rom_patch.bin"
-
-#define MT76x2_RX_RING_SIZE 256
-#define MT_RX_HEADROOM 32
-
-#define MT_MAX_CHAINS 2
-
-#define MT_CALIBRATE_INTERVAL HZ
-
-#define MT_MAX_VIFS 8
-#define MT_VIF_WCID(_n) (254 - ((_n) & 7))
-
-#include "mt76.h"
-#include "mt76x2_regs.h"
-#include "mt76x2_mac.h"
-#include "mt76x2_dfs.h"
-
-DECLARE_EWMA(signal, 10, 8)
-
-struct mt76x2_mcu {
- struct mutex mutex;
-
- wait_queue_head_t wait;
- struct sk_buff_head res_q;
- struct mt76u_buf res_u;
-
- u32 msg_seq;
-};
-
-struct mt76x2_rx_freq_cal {
- s8 high_gain[MT_MAX_CHAINS];
- s8 rssi_offset[MT_MAX_CHAINS];
- s8 lna_gain;
- u32 mcu_gain;
-};
-
-struct mt76x2_calibration {
- struct mt76x2_rx_freq_cal rx;
-
- u8 agc_gain_init[MT_MAX_CHAINS];
- u8 agc_gain_cur[MT_MAX_CHAINS];
-
- u16 false_cca;
- s8 avg_rssi_all;
- s8 agc_gain_adjust;
- s8 low_gain;
-
- u8 temp;
-
- bool init_cal_done;
- bool tssi_cal_done;
- bool tssi_comp_pending;
- bool dpd_cal_done;
- bool channel_cal_done;
-};
-
-struct mt76x2_dev {
- struct mt76_dev mt76; /* must be first */
-
- struct mac_address macaddr_list[8];
-
- struct mutex mutex;
-
- const u16 *beacon_offsets;
- unsigned long wcid_mask[128 / BITS_PER_LONG];
-
- int txpower_conf;
- int txpower_cur;
-
- u8 txdone_seq;
- DECLARE_KFIFO_PTR(txstatus_fifo, struct mt76x2_tx_status);
-
- struct mt76x2_mcu mcu;
- struct sk_buff *rx_head;
-
- struct tasklet_struct tx_tasklet;
- struct tasklet_struct pre_tbtt_tasklet;
- struct delayed_work cal_work;
- struct delayed_work mac_work;
-
- u32 aggr_stats[32];
-
- struct mt76_wcid global_wcid;
- struct mt76_wcid __rcu *wcid[128];
-
- spinlock_t irq_lock;
- u32 irqmask;
-
- struct sk_buff *beacons[8];
- u8 beacon_mask;
- u8 beacon_data_mask;
-
- u8 tbtt_count;
- u16 beacon_int;
-
- u16 chainmask;
-
- u32 rxfilter;
-
- struct mt76x2_calibration cal;
-
- s8 target_power;
- s8 target_power_delta[2];
- struct mt76_rate_power rate_power;
- bool enable_tpc;
-
- u8 coverage_class;
- u8 slottime;
-
- struct mt76x2_dfs_pattern_detector dfs_pd;
-};
-
-struct mt76x2_vif {
- u8 idx;
-
- struct mt76_wcid group_wcid;
-};
-
-struct mt76x2_sta {
- struct mt76_wcid wcid; /* must be first */
-
- struct mt76x2_vif *vif;
- struct mt76x2_tx_status status;
- int n_frames;
-
- struct ewma_signal rssi;
- int inactive_count;
-};
-
-static inline bool mt76x2_wait_for_mac(struct mt76x2_dev *dev)
-{
- int i;
-
- for (i = 0; i < 500; i++) {
- switch (mt76_rr(dev, MT_MAC_CSR0)) {
- case 0:
- case ~0:
- break;
- default:
- return true;
- }
- usleep_range(5000, 10000);
- }
- return false;
-}
-
-static inline bool is_mt7612(struct mt76x2_dev *dev)
-{
- return mt76_chip(&dev->mt76) == 0x7612;
-}
-
-void mt76x2_set_irq_mask(struct mt76x2_dev *dev, u32 clear, u32 set);
-
-static inline bool mt76x2_channel_silent(struct mt76x2_dev *dev)
-{
- struct ieee80211_channel *chan = dev->mt76.chandef.chan;
-
- return ((chan->flags & IEEE80211_CHAN_RADAR) &&
- chan->dfs_state != NL80211_DFS_AVAILABLE);
-}
-
-static inline void mt76x2_irq_enable(struct mt76x2_dev *dev, u32 mask)
-{
- mt76x2_set_irq_mask(dev, 0, mask);
-}
-
-static inline void mt76x2_irq_disable(struct mt76x2_dev *dev, u32 mask)
-{
- mt76x2_set_irq_mask(dev, mask, 0);
-}
-
-static inline bool mt76x2_wait_for_bbp(struct mt76x2_dev *dev)
-{
- return mt76_poll_msec(dev, MT_MAC_STATUS,
- MT_MAC_STATUS_TX | MT_MAC_STATUS_RX,
- 0, 100);
-}
-
-static inline bool wait_for_wpdma(struct mt76x2_dev *dev)
-{
- return mt76_poll(dev, MT_WPDMA_GLO_CFG,
- MT_WPDMA_GLO_CFG_TX_DMA_BUSY |
- MT_WPDMA_GLO_CFG_RX_DMA_BUSY,
- 0, 1000);
-}
-
-extern const struct ieee80211_ops mt76x2_ops;
-
-extern struct ieee80211_rate mt76x2_rates[12];
-
-struct mt76x2_dev *mt76x2_alloc_device(struct device *pdev);
-int mt76x2_register_device(struct mt76x2_dev *dev);
-void mt76x2_init_debugfs(struct mt76x2_dev *dev);
-void mt76x2_init_device(struct mt76x2_dev *dev);
-
-irqreturn_t mt76x2_irq_handler(int irq, void *dev_instance);
-void mt76x2_phy_power_on(struct mt76x2_dev *dev);
-int mt76x2_init_hardware(struct mt76x2_dev *dev);
-void mt76x2_stop_hardware(struct mt76x2_dev *dev);
-int mt76x2_eeprom_init(struct mt76x2_dev *dev);
-int mt76x2_apply_calibration_data(struct mt76x2_dev *dev, int channel);
-void mt76x2_set_tx_ackto(struct mt76x2_dev *dev);
-
-void mt76x2_phy_set_antenna(struct mt76x2_dev *dev);
-int mt76x2_phy_start(struct mt76x2_dev *dev);
-int mt76x2_phy_set_channel(struct mt76x2_dev *dev,
- struct cfg80211_chan_def *chandef);
-int mt76x2_mac_get_rssi(struct mt76x2_dev *dev, s8 rssi, int chain);
-void mt76x2_phy_calibrate(struct work_struct *work);
-void mt76x2_phy_set_txpower(struct mt76x2_dev *dev);
-
-int mt76x2_mcu_init(struct mt76x2_dev *dev);
-int mt76x2_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw,
- u8 bw_index, bool scan);
-int mt76x2_mcu_set_radio_state(struct mt76x2_dev *dev, bool on);
-int mt76x2_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level,
- u8 channel);
-int mt76x2_mcu_cleanup(struct mt76x2_dev *dev);
-
-int mt76x2_dma_init(struct mt76x2_dev *dev);
-void mt76x2_dma_cleanup(struct mt76x2_dev *dev);
-
-void mt76x2_cleanup(struct mt76x2_dev *dev);
-
-int mt76x2_tx_queue_mcu(struct mt76x2_dev *dev, enum mt76_txq_id qid,
- struct sk_buff *skb, int cmd, int seq);
-void mt76x2_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
- struct sk_buff *skb);
-void mt76x2_tx_complete(struct mt76x2_dev *dev, struct sk_buff *skb);
-int mt76x2_tx_prepare_skb(struct mt76_dev *mdev, void *txwi,
- struct sk_buff *skb, struct mt76_queue *q,
- struct mt76_wcid *wcid, struct ieee80211_sta *sta,
- u32 *tx_info);
-void mt76x2_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q,
- struct mt76_queue_entry *e, bool flush);
-void mt76x2_mac_set_tx_protection(struct mt76x2_dev *dev, u32 val);
-
-void mt76x2_pre_tbtt_tasklet(unsigned long arg);
-
-void mt76x2_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q);
-void mt76x2_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
- struct sk_buff *skb);
-
-void mt76x2_sta_ps(struct mt76_dev *dev, struct ieee80211_sta *sta, bool ps);
-
-void mt76x2_update_channel(struct mt76_dev *mdev);
-
-s8 mt76x2_tx_get_max_txpwr_adj(struct mt76x2_dev *dev,
- const struct ieee80211_tx_rate *rate);
-s8 mt76x2_tx_get_txpwr_adj(struct mt76x2_dev *dev, s8 txpwr, s8 max_txpwr_adj);
-void mt76x2_tx_set_txpwr_auto(struct mt76x2_dev *dev, s8 txpwr);
-
-int mt76x2_insert_hdr_pad(struct sk_buff *skb);
-
-bool mt76x2_mac_load_tx_status(struct mt76x2_dev *dev,
- struct mt76x2_tx_status *stat);
-void mt76x2_send_tx_status(struct mt76x2_dev *dev,
- struct mt76x2_tx_status *stat, u8 *update);
-void mt76x2_reset_wlan(struct mt76x2_dev *dev, bool enable);
-void mt76x2_init_txpower(struct mt76x2_dev *dev,
- struct ieee80211_supported_band *sband);
-void mt76_write_mac_initvals(struct mt76x2_dev *dev);
-
-int mt76x2_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_ampdu_params *params);
-int mt76x2_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta);
-int mt76x2_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta);
-void mt76x2_remove_interface(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif);
-int mt76x2_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
- struct ieee80211_vif *vif, struct ieee80211_sta *sta,
- struct ieee80211_key_conf *key);
-int mt76x2_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- u16 queue, const struct ieee80211_tx_queue_params *params);
-void mt76x2_configure_filter(struct ieee80211_hw *hw,
- unsigned int changed_flags,
- unsigned int *total_flags, u64 multicast);
-void mt76x2_txq_init(struct mt76x2_dev *dev, struct ieee80211_txq *txq);
-void mt76x2_sta_rate_tbl_update(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta);
-
-void mt76x2_phy_set_txpower_regs(struct mt76x2_dev *dev,
- enum nl80211_band band);
-void mt76x2_configure_tx_delay(struct mt76x2_dev *dev,
- enum nl80211_band band, u8 bw);
-void mt76x2_phy_set_bw(struct mt76x2_dev *dev, int width, u8 ctrl);
-void mt76x2_phy_set_band(struct mt76x2_dev *dev, int band, bool primary_upper);
-int mt76x2_phy_get_min_avg_rssi(struct mt76x2_dev *dev);
-void mt76x2_apply_gain_adj(struct mt76x2_dev *dev);
-
-#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig b/drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig
new file mode 100644
index 000000000000..2b414a0e9088
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig
@@ -0,0 +1,20 @@
+config MT76x2_COMMON
+ tristate
+ select MT76x02_LIB
+
+config MT76x2E
+ tristate "MediaTek MT76x2E (PCIe) support"
+ select MT76x2_COMMON
+ depends on MAC80211
+ depends on PCI
+ ---help---
+ This adds support for MT7612/MT7602/MT7662-based wireless PCIe devices.
+
+config MT76x2U
+ tristate "MediaTek MT76x2U (USB) support"
+ select MT76x2_COMMON
+ select MT76x02_USB
+ depends on MAC80211
+ depends on USB
+ help
+ This adds support for MT7612U-based wireless USB dongles.
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/Makefile b/drivers/net/wireless/mediatek/mt76/mt76x2/Makefile
new file mode 100644
index 000000000000..b71bb1049170
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/Makefile
@@ -0,0 +1,16 @@
+obj-$(CONFIG_MT76x2_COMMON) += mt76x2-common.o
+obj-$(CONFIG_MT76x2E) += mt76x2e.o
+obj-$(CONFIG_MT76x2U) += mt76x2u.o
+
+mt76x2-common-y := \
+ eeprom.o mac.o init.o phy.o debugfs.o mcu.o
+
+mt76x2e-y := \
+ pci.o pci_main.o pci_init.o pci_tx.o \
+ pci_mac.o pci_mcu.o pci_phy.o pci_dfs.o
+
+mt76x2u-y := \
+ usb.o usb_init.o usb_main.o usb_mac.o usb_mcu.o \
+ usb_phy.o
+
+CFLAGS_pci_trace.o := -I$(src)
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c b/drivers/net/wireless/mediatek/mt76/mt76x2/debugfs.c
index 77b5ff1be05f..e8f8ccc0a5ed 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/debugfs.c
@@ -20,7 +20,7 @@
static int
mt76x2_ampdu_stat_read(struct seq_file *file, void *data)
{
- struct mt76x2_dev *dev = file->private;
+ struct mt76x02_dev *dev = file->private;
int i, j;
for (i = 0; i < 4; i++) {
@@ -47,33 +47,14 @@ mt76x2_ampdu_stat_open(struct inode *inode, struct file *f)
return single_open(f, mt76x2_ampdu_stat_read, inode->i_private);
}
-static void
-seq_puts_array(struct seq_file *file, const char *str, s8 *val, int len)
-{
- int i;
-
- seq_printf(file, "%10s:", str);
- for (i = 0; i < len; i++)
- seq_printf(file, " %2d", val[i]);
- seq_puts(file, "\n");
-}
-
static int read_txpower(struct seq_file *file, void *data)
{
- struct mt76x2_dev *dev = dev_get_drvdata(file->private);
+ struct mt76x02_dev *dev = dev_get_drvdata(file->private);
seq_printf(file, "Target power: %d\n", dev->target_power);
- seq_puts_array(file, "Delta", dev->target_power_delta,
- ARRAY_SIZE(dev->target_power_delta));
- seq_puts_array(file, "CCK", dev->rate_power.cck,
- ARRAY_SIZE(dev->rate_power.cck));
- seq_puts_array(file, "OFDM", dev->rate_power.ofdm,
- ARRAY_SIZE(dev->rate_power.ofdm));
- seq_puts_array(file, "HT", dev->rate_power.ht,
- ARRAY_SIZE(dev->rate_power.ht));
- seq_puts_array(file, "VHT", dev->rate_power.vht,
- ARRAY_SIZE(dev->rate_power.vht));
+ mt76_seq_puts_array(file, "Delta", dev->target_power_delta,
+ ARRAY_SIZE(dev->target_power_delta));
return 0;
}
@@ -87,9 +68,9 @@ static const struct file_operations fops_ampdu_stat = {
static int
mt76x2_dfs_stat_read(struct seq_file *file, void *data)
{
+ struct mt76x02_dev *dev = file->private;
+ struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
int i;
- struct mt76x2_dev *dev = file->private;
- struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
seq_printf(file, "allocated sequences:\t%d\n",
dfs_pd->seq_stats.seq_pool_len);
@@ -125,7 +106,7 @@ static const struct file_operations fops_dfs_stat = {
static int read_agc(struct seq_file *file, void *data)
{
- struct mt76x2_dev *dev = dev_get_drvdata(file->private);
+ struct mt76x02_dev *dev = dev_get_drvdata(file->private);
seq_printf(file, "avg_rssi: %d\n", dev->cal.avg_rssi_all);
seq_printf(file, "low_gain: %d\n", dev->cal.low_gain);
@@ -135,7 +116,7 @@ static int read_agc(struct seq_file *file, void *data)
return 0;
}
-void mt76x2_init_debugfs(struct mt76x2_dev *dev)
+void mt76x2_init_debugfs(struct mt76x02_dev *dev)
{
struct dentry *dir;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_dma.h b/drivers/net/wireless/mediatek/mt76/mt76x2/dfs.h
index da294558c268..3cb9d1864286 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_dma.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/dfs.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
+ * Copyright (C) 2016 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -14,16 +14,13 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifndef __MT76x2_DMA_H
-#define __MT76x2_DMA_H
+#ifndef __DFS_H
+#define __DFS_H
-#include "dma.h"
+void mt76x2_dfs_init_params(struct mt76x02_dev *dev);
+void mt76x2_dfs_init_detector(struct mt76x02_dev *dev);
+void mt76x2_dfs_adjust_agc(struct mt76x02_dev *dev);
+void mt76x2_dfs_set_domain(struct mt76x02_dev *dev,
+ enum nl80211_dfs_regions region);
-enum mt76x2_qsel {
- MT_QSEL_MGMT,
- MT_QSEL_HCCA,
- MT_QSEL_EDCA,
- MT_QSEL_EDCA_2,
-};
-
-#endif
+#endif /* __DFS_H */
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c
index 1753bcb36356..f39b622d03f4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c
@@ -14,14 +14,15 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include <linux/module.h>
#include <asm/unaligned.h>
#include "mt76x2.h"
-#include "mt76x2_eeprom.h"
+#include "eeprom.h"
#define EE_FIELD(_name, _value) [MT_EE_##_name] = (_value) | 1
static int
-mt76x2_eeprom_copy(struct mt76x2_dev *dev, enum mt76x2_eeprom_field field,
+mt76x2_eeprom_copy(struct mt76x02_dev *dev, enum mt76x02_eeprom_field field,
void *dest, int len)
{
if (field + len > dev->mt76.eeprom.size)
@@ -32,7 +33,7 @@ mt76x2_eeprom_copy(struct mt76x2_dev *dev, enum mt76x2_eeprom_field field,
}
static int
-mt76x2_eeprom_get_macaddr(struct mt76x2_dev *dev)
+mt76x2_eeprom_get_macaddr(struct mt76x02_dev *dev)
{
void *src = dev->mt76.eeprom.data + MT_EE_MAC_ADDR;
@@ -40,73 +41,8 @@ mt76x2_eeprom_get_macaddr(struct mt76x2_dev *dev)
return 0;
}
-void mt76x2_eeprom_parse_hw_cap(struct mt76x2_dev *dev)
-{
- u16 val = mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_0);
-
- switch (FIELD_GET(MT_EE_NIC_CONF_0_BOARD_TYPE, val)) {
- case BOARD_TYPE_5GHZ:
- dev->mt76.cap.has_5ghz = true;
- break;
- case BOARD_TYPE_2GHZ:
- dev->mt76.cap.has_2ghz = true;
- break;
- default:
- dev->mt76.cap.has_2ghz = true;
- dev->mt76.cap.has_5ghz = true;
- break;
- }
-}
-EXPORT_SYMBOL_GPL(mt76x2_eeprom_parse_hw_cap);
-
-static int
-mt76x2_efuse_read(struct mt76x2_dev *dev, u16 addr, u8 *data)
-{
- u32 val;
- int i;
-
- val = mt76_rr(dev, MT_EFUSE_CTRL);
- val &= ~(MT_EFUSE_CTRL_AIN |
- MT_EFUSE_CTRL_MODE);
- val |= FIELD_PREP(MT_EFUSE_CTRL_AIN, addr & ~0xf);
- val |= MT_EFUSE_CTRL_KICK;
- mt76_wr(dev, MT_EFUSE_CTRL, val);
-
- if (!mt76_poll(dev, MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK, 0, 1000))
- return -ETIMEDOUT;
-
- udelay(2);
-
- val = mt76_rr(dev, MT_EFUSE_CTRL);
- if ((val & MT_EFUSE_CTRL_AOUT) == MT_EFUSE_CTRL_AOUT) {
- memset(data, 0xff, 16);
- return 0;
- }
-
- for (i = 0; i < 4; i++) {
- val = mt76_rr(dev, MT_EFUSE_DATA(i));
- put_unaligned_le32(val, data + 4 * i);
- }
-
- return 0;
-}
-
-static int
-mt76x2_get_efuse_data(struct mt76x2_dev *dev, void *buf, int len)
-{
- int ret, i;
-
- for (i = 0; i + 16 <= len; i += 16) {
- ret = mt76x2_efuse_read(dev, i, buf + i);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
static bool
-mt76x2_has_cal_free_data(struct mt76x2_dev *dev, u8 *efuse)
+mt76x2_has_cal_free_data(struct mt76x02_dev *dev, u8 *efuse)
{
u16 *efuse_w = (u16 *) efuse;
@@ -132,7 +68,7 @@ mt76x2_has_cal_free_data(struct mt76x2_dev *dev, u8 *efuse)
}
static void
-mt76x2_apply_cal_free_data(struct mt76x2_dev *dev, u8 *efuse)
+mt76x2_apply_cal_free_data(struct mt76x02_dev *dev, u8 *efuse)
{
#define GROUP_5G(_id) \
MT_EE_TX_POWER_0_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id), \
@@ -201,7 +137,7 @@ mt76x2_apply_cal_free_data(struct mt76x2_dev *dev, u8 *efuse)
eeprom[MT_EE_BT_PMUCFG] = val & 0xff;
}
-static int mt76x2_check_eeprom(struct mt76x2_dev *dev)
+static int mt76x2_check_eeprom(struct mt76x02_dev *dev)
{
u16 val = get_unaligned_le16(dev->mt76.eeprom.data);
@@ -219,7 +155,7 @@ static int mt76x2_check_eeprom(struct mt76x2_dev *dev)
}
static int
-mt76x2_eeprom_load(struct mt76x2_dev *dev)
+mt76x2_eeprom_load(struct mt76x02_dev *dev)
{
void *efuse;
bool found;
@@ -241,7 +177,8 @@ mt76x2_eeprom_load(struct mt76x2_dev *dev)
efuse = dev->mt76.otp.data;
- if (mt76x2_get_efuse_data(dev, efuse, MT7662_EEPROM_SIZE))
+ if (mt76x02_get_efuse_data(dev, 0, efuse, MT7662_EEPROM_SIZE,
+ MT_EE_READ))
goto out;
if (found) {
@@ -259,56 +196,32 @@ out:
return 0;
}
-static inline int
-mt76x2_sign_extend(u32 val, unsigned int size)
-{
- bool sign = val & BIT(size - 1);
-
- val &= BIT(size - 1) - 1;
-
- return sign ? val : -val;
-}
-
-static inline int
-mt76x2_sign_extend_optional(u32 val, unsigned int size)
-{
- bool enable = val & BIT(size);
-
- return enable ? mt76x2_sign_extend(val, size) : 0;
-}
-
-static bool
-field_valid(u8 val)
-{
- return val != 0 && val != 0xff;
-}
-
static void
-mt76x2_set_rx_gain_group(struct mt76x2_dev *dev, u8 val)
+mt76x2_set_rx_gain_group(struct mt76x02_dev *dev, u8 val)
{
s8 *dest = dev->cal.rx.high_gain;
- if (!field_valid(val)) {
+ if (!mt76x02_field_valid(val)) {
dest[0] = 0;
dest[1] = 0;
return;
}
- dest[0] = mt76x2_sign_extend(val, 4);
- dest[1] = mt76x2_sign_extend(val >> 4, 4);
+ dest[0] = mt76x02_sign_extend(val, 4);
+ dest[1] = mt76x02_sign_extend(val >> 4, 4);
}
static void
-mt76x2_set_rssi_offset(struct mt76x2_dev *dev, int chain, u8 val)
+mt76x2_set_rssi_offset(struct mt76x02_dev *dev, int chain, u8 val)
{
s8 *dest = dev->cal.rx.rssi_offset;
- if (!field_valid(val)) {
+ if (!mt76x02_field_valid(val)) {
dest[chain] = 0;
return;
}
- dest[chain] = mt76x2_sign_extend_optional(val, 7);
+ dest[chain] = mt76x02_sign_extend_optional(val, 7);
}
static enum mt76x2_cal_channel_group
@@ -328,28 +241,34 @@ mt76x2_get_cal_channel_group(int channel)
}
static u8
-mt76x2_get_5g_rx_gain(struct mt76x2_dev *dev, u8 channel)
+mt76x2_get_5g_rx_gain(struct mt76x02_dev *dev, u8 channel)
{
enum mt76x2_cal_channel_group group;
group = mt76x2_get_cal_channel_group(channel);
switch (group) {
case MT_CH_5G_JAPAN:
- return mt76x2_eeprom_get(dev, MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN);
+ return mt76x02_eeprom_get(dev,
+ MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN);
case MT_CH_5G_UNII_1:
- return mt76x2_eeprom_get(dev, MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN) >> 8;
+ return mt76x02_eeprom_get(dev,
+ MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN) >> 8;
case MT_CH_5G_UNII_2:
- return mt76x2_eeprom_get(dev, MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN);
+ return mt76x02_eeprom_get(dev,
+ MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN);
case MT_CH_5G_UNII_2E_1:
- return mt76x2_eeprom_get(dev, MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN) >> 8;
+ return mt76x02_eeprom_get(dev,
+ MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN) >> 8;
case MT_CH_5G_UNII_2E_2:
- return mt76x2_eeprom_get(dev, MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN);
+ return mt76x02_eeprom_get(dev,
+ MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN);
default:
- return mt76x2_eeprom_get(dev, MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN) >> 8;
+ return mt76x02_eeprom_get(dev,
+ MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN) >> 8;
}
}
-void mt76x2_read_rx_gain(struct mt76x2_dev *dev)
+void mt76x2_read_rx_gain(struct mt76x02_dev *dev)
{
struct ieee80211_channel *chan = dev->mt76.chandef.chan;
int channel = chan->hw_value;
@@ -358,75 +277,27 @@ void mt76x2_read_rx_gain(struct mt76x2_dev *dev)
u16 val;
if (chan->band == NL80211_BAND_2GHZ)
- val = mt76x2_eeprom_get(dev, MT_EE_RF_2G_RX_HIGH_GAIN) >> 8;
+ val = mt76x02_eeprom_get(dev, MT_EE_RF_2G_RX_HIGH_GAIN) >> 8;
else
val = mt76x2_get_5g_rx_gain(dev, channel);
mt76x2_set_rx_gain_group(dev, val);
- if (chan->band == NL80211_BAND_2GHZ) {
- val = mt76x2_eeprom_get(dev, MT_EE_RSSI_OFFSET_2G_0);
- mt76x2_set_rssi_offset(dev, 0, val);
- mt76x2_set_rssi_offset(dev, 1, val >> 8);
- } else {
- val = mt76x2_eeprom_get(dev, MT_EE_RSSI_OFFSET_5G_0);
- mt76x2_set_rssi_offset(dev, 0, val);
- mt76x2_set_rssi_offset(dev, 1, val >> 8);
- }
-
- val = mt76x2_eeprom_get(dev, MT_EE_LNA_GAIN);
- lna_2g = val & 0xff;
- lna_5g[0] = val >> 8;
-
- val = mt76x2_eeprom_get(dev, MT_EE_RSSI_OFFSET_2G_1);
- lna_5g[1] = val >> 8;
-
- val = mt76x2_eeprom_get(dev, MT_EE_RSSI_OFFSET_5G_1);
- lna_5g[2] = val >> 8;
-
- if (!field_valid(lna_5g[1]))
- lna_5g[1] = lna_5g[0];
-
- if (!field_valid(lna_5g[2]))
- lna_5g[2] = lna_5g[0];
+ mt76x02_get_rx_gain(dev, chan->band, &val, &lna_2g, lna_5g);
+ mt76x2_set_rssi_offset(dev, 0, val);
+ mt76x2_set_rssi_offset(dev, 1, val >> 8);
dev->cal.rx.mcu_gain = (lna_2g & 0xff);
dev->cal.rx.mcu_gain |= (lna_5g[0] & 0xff) << 8;
dev->cal.rx.mcu_gain |= (lna_5g[1] & 0xff) << 16;
dev->cal.rx.mcu_gain |= (lna_5g[2] & 0xff) << 24;
- val = mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_1);
- if (val & MT_EE_NIC_CONF_1_LNA_EXT_2G)
- lna_2g = 0;
- if (val & MT_EE_NIC_CONF_1_LNA_EXT_5G)
- memset(lna_5g, 0, sizeof(lna_5g));
-
- if (chan->band == NL80211_BAND_2GHZ)
- lna = lna_2g;
- else if (channel <= 64)
- lna = lna_5g[0];
- else if (channel <= 128)
- lna = lna_5g[1];
- else
- lna = lna_5g[2];
-
- if (lna == 0xff)
- lna = 0;
-
- dev->cal.rx.lna_gain = mt76x2_sign_extend(lna, 8);
+ lna = mt76x02_get_lna_gain(dev, &lna_2g, lna_5g, chan);
+ dev->cal.rx.lna_gain = mt76x02_sign_extend(lna, 8);
}
EXPORT_SYMBOL_GPL(mt76x2_read_rx_gain);
-static s8
-mt76x2_rate_power_val(u8 val)
-{
- if (!field_valid(val))
- return 0;
-
- return mt76x2_sign_extend_optional(val, 7);
-}
-
-void mt76x2_get_rate_power(struct mt76x2_dev *dev, struct mt76_rate_power *t,
+void mt76x2_get_rate_power(struct mt76x02_dev *dev, struct mt76_rate_power *t,
struct ieee80211_channel *chan)
{
bool is_5ghz;
@@ -436,70 +307,64 @@ void mt76x2_get_rate_power(struct mt76x2_dev *dev, struct mt76_rate_power *t,
memset(t, 0, sizeof(*t));
- val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_CCK);
- t->cck[0] = t->cck[1] = mt76x2_rate_power_val(val);
- t->cck[2] = t->cck[3] = mt76x2_rate_power_val(val >> 8);
+ val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_CCK);
+ t->cck[0] = t->cck[1] = mt76x02_rate_power_val(val);
+ t->cck[2] = t->cck[3] = mt76x02_rate_power_val(val >> 8);
if (is_5ghz)
- val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_OFDM_5G_6M);
+ val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_OFDM_5G_6M);
else
- val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_OFDM_2G_6M);
- t->ofdm[0] = t->ofdm[1] = mt76x2_rate_power_val(val);
- t->ofdm[2] = t->ofdm[3] = mt76x2_rate_power_val(val >> 8);
+ val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_OFDM_2G_6M);
+ t->ofdm[0] = t->ofdm[1] = mt76x02_rate_power_val(val);
+ t->ofdm[2] = t->ofdm[3] = mt76x02_rate_power_val(val >> 8);
if (is_5ghz)
- val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_OFDM_5G_24M);
+ val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_OFDM_5G_24M);
else
- val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_OFDM_2G_24M);
- t->ofdm[4] = t->ofdm[5] = mt76x2_rate_power_val(val);
- t->ofdm[6] = t->ofdm[7] = mt76x2_rate_power_val(val >> 8);
+ val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_OFDM_2G_24M);
+ t->ofdm[4] = t->ofdm[5] = mt76x02_rate_power_val(val);
+ t->ofdm[6] = t->ofdm[7] = mt76x02_rate_power_val(val >> 8);
- val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS0);
- t->ht[0] = t->ht[1] = mt76x2_rate_power_val(val);
- t->ht[2] = t->ht[3] = mt76x2_rate_power_val(val >> 8);
+ val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS0);
+ t->ht[0] = t->ht[1] = mt76x02_rate_power_val(val);
+ t->ht[2] = t->ht[3] = mt76x02_rate_power_val(val >> 8);
- val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS4);
- t->ht[4] = t->ht[5] = mt76x2_rate_power_val(val);
- t->ht[6] = t->ht[7] = mt76x2_rate_power_val(val >> 8);
+ val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS4);
+ t->ht[4] = t->ht[5] = mt76x02_rate_power_val(val);
+ t->ht[6] = t->ht[7] = mt76x02_rate_power_val(val >> 8);
- val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS8);
- t->ht[8] = t->ht[9] = mt76x2_rate_power_val(val);
- t->ht[10] = t->ht[11] = mt76x2_rate_power_val(val >> 8);
+ val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS8);
+ t->ht[8] = t->ht[9] = mt76x02_rate_power_val(val);
+ t->ht[10] = t->ht[11] = mt76x02_rate_power_val(val >> 8);
- val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS12);
- t->ht[12] = t->ht[13] = mt76x2_rate_power_val(val);
- t->ht[14] = t->ht[15] = mt76x2_rate_power_val(val >> 8);
+ val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS12);
+ t->ht[12] = t->ht[13] = mt76x02_rate_power_val(val);
+ t->ht[14] = t->ht[15] = mt76x02_rate_power_val(val >> 8);
- val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_VHT_MCS0);
- t->vht[0] = t->vht[1] = mt76x2_rate_power_val(val);
- t->vht[2] = t->vht[3] = mt76x2_rate_power_val(val >> 8);
+ val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_VHT_MCS0);
+ t->vht[0] = t->vht[1] = mt76x02_rate_power_val(val);
+ t->vht[2] = t->vht[3] = mt76x02_rate_power_val(val >> 8);
- val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_VHT_MCS4);
- t->vht[4] = t->vht[5] = mt76x2_rate_power_val(val);
- t->vht[6] = t->vht[7] = mt76x2_rate_power_val(val >> 8);
+ val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_VHT_MCS4);
+ t->vht[4] = t->vht[5] = mt76x02_rate_power_val(val);
+ t->vht[6] = t->vht[7] = mt76x02_rate_power_val(val >> 8);
- val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_VHT_MCS8);
+ val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_VHT_MCS8);
if (!is_5ghz)
val >>= 8;
- t->vht[8] = t->vht[9] = mt76x2_rate_power_val(val >> 8);
-}
-EXPORT_SYMBOL_GPL(mt76x2_get_rate_power);
+ t->vht[8] = t->vht[9] = mt76x02_rate_power_val(val >> 8);
-int mt76x2_get_max_rate_power(struct mt76_rate_power *r)
-{
- int i;
- s8 ret = 0;
-
- for (i = 0; i < sizeof(r->all); i++)
- ret = max(ret, r->all[i]);
-
- return ret;
+ memcpy(t->stbc, t->ht, sizeof(t->stbc[0]) * 8);
+ t->stbc[8] = t->vht[8];
+ t->stbc[9] = t->vht[9];
}
-EXPORT_SYMBOL_GPL(mt76x2_get_max_rate_power);
+EXPORT_SYMBOL_GPL(mt76x2_get_rate_power);
static void
-mt76x2_get_power_info_2g(struct mt76x2_dev *dev, struct mt76x2_tx_power_info *t,
- struct ieee80211_channel *chan, int chain, int offset)
+mt76x2_get_power_info_2g(struct mt76x02_dev *dev,
+ struct mt76x2_tx_power_info *t,
+ struct ieee80211_channel *chan,
+ int chain, int offset)
{
int channel = chan->hw_value;
int delta_idx;
@@ -518,15 +383,17 @@ mt76x2_get_power_info_2g(struct mt76x2_dev *dev, struct mt76x2_tx_power_info *t,
t->chain[chain].tssi_slope = data[0];
t->chain[chain].tssi_offset = data[1];
t->chain[chain].target_power = data[2];
- t->chain[chain].delta = mt76x2_sign_extend_optional(data[delta_idx], 7);
+ t->chain[chain].delta = mt76x02_sign_extend_optional(data[delta_idx], 7);
- val = mt76x2_eeprom_get(dev, MT_EE_RF_2G_TSSI_OFF_TXPOWER);
+ val = mt76x02_eeprom_get(dev, MT_EE_RF_2G_TSSI_OFF_TXPOWER);
t->target_power = val >> 8;
}
static void
-mt76x2_get_power_info_5g(struct mt76x2_dev *dev, struct mt76x2_tx_power_info *t,
- struct ieee80211_channel *chan, int chain, int offset)
+mt76x2_get_power_info_5g(struct mt76x02_dev *dev,
+ struct mt76x2_tx_power_info *t,
+ struct ieee80211_channel *chan,
+ int chain, int offset)
{
int channel = chan->hw_value;
enum mt76x2_cal_channel_group group;
@@ -567,13 +434,13 @@ mt76x2_get_power_info_5g(struct mt76x2_dev *dev, struct mt76x2_tx_power_info *t,
t->chain[chain].tssi_slope = data[0];
t->chain[chain].tssi_offset = data[1];
t->chain[chain].target_power = data[2];
- t->chain[chain].delta = mt76x2_sign_extend_optional(data[delta_idx], 7);
+ t->chain[chain].delta = mt76x02_sign_extend_optional(data[delta_idx], 7);
- val = mt76x2_eeprom_get(dev, MT_EE_RF_2G_RX_HIGH_GAIN);
+ val = mt76x02_eeprom_get(dev, MT_EE_RF_2G_RX_HIGH_GAIN);
t->target_power = val & 0xff;
}
-void mt76x2_get_power_info(struct mt76x2_dev *dev,
+void mt76x2_get_power_info(struct mt76x02_dev *dev,
struct mt76x2_tx_power_info *t,
struct ieee80211_channel *chan)
{
@@ -581,8 +448,8 @@ void mt76x2_get_power_info(struct mt76x2_dev *dev,
memset(t, 0, sizeof(*t));
- bw40 = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_DELTA_BW40);
- bw80 = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_DELTA_BW80);
+ bw40 = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_DELTA_BW40);
+ bw80 = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_DELTA_BW80);
if (chan->band == NL80211_BAND_5GHZ) {
bw40 >>= 8;
@@ -597,15 +464,16 @@ void mt76x2_get_power_info(struct mt76x2_dev *dev,
MT_EE_TX_POWER_1_START_2G);
}
- if (mt76x2_tssi_enabled(dev) || !field_valid(t->target_power))
+ if (mt76x2_tssi_enabled(dev) ||
+ !mt76x02_field_valid(t->target_power))
t->target_power = t->chain[0].target_power;
- t->delta_bw40 = mt76x2_rate_power_val(bw40);
- t->delta_bw80 = mt76x2_rate_power_val(bw80);
+ t->delta_bw40 = mt76x02_rate_power_val(bw40);
+ t->delta_bw80 = mt76x02_rate_power_val(bw80);
}
EXPORT_SYMBOL_GPL(mt76x2_get_power_info);
-int mt76x2_get_temp_comp(struct mt76x2_dev *dev, struct mt76x2_temp_comp *t)
+int mt76x2_get_temp_comp(struct mt76x02_dev *dev, struct mt76x2_temp_comp *t)
{
enum nl80211_band band = dev->mt76.chandef.chan->band;
u16 val, slope;
@@ -616,17 +484,18 @@ int mt76x2_get_temp_comp(struct mt76x2_dev *dev, struct mt76x2_temp_comp *t)
if (!mt76x2_temp_tx_alc_enabled(dev))
return -EINVAL;
- if (!mt76x2_ext_pa_enabled(dev, band))
+ if (!mt76x02_ext_pa_enabled(dev, band))
return -EINVAL;
- val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_EXT_PA_5G) >> 8;
+ val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_EXT_PA_5G) >> 8;
t->temp_25_ref = val & 0x7f;
if (band == NL80211_BAND_5GHZ) {
- slope = mt76x2_eeprom_get(dev, MT_EE_RF_TEMP_COMP_SLOPE_5G);
- bounds = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_EXT_PA_5G);
+ slope = mt76x02_eeprom_get(dev, MT_EE_RF_TEMP_COMP_SLOPE_5G);
+ bounds = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_EXT_PA_5G);
} else {
- slope = mt76x2_eeprom_get(dev, MT_EE_RF_TEMP_COMP_SLOPE_2G);
- bounds = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_DELTA_BW80) >> 8;
+ slope = mt76x02_eeprom_get(dev, MT_EE_RF_TEMP_COMP_SLOPE_2G);
+ bounds = mt76x02_eeprom_get(dev,
+ MT_EE_TX_POWER_DELTA_BW80) >> 8;
}
t->high_slope = slope & 0xff;
@@ -638,18 +507,7 @@ int mt76x2_get_temp_comp(struct mt76x2_dev *dev, struct mt76x2_temp_comp *t)
}
EXPORT_SYMBOL_GPL(mt76x2_get_temp_comp);
-bool mt76x2_ext_pa_enabled(struct mt76x2_dev *dev, enum nl80211_band band)
-{
- u16 conf0 = mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_0);
-
- if (band == NL80211_BAND_5GHZ)
- return !(conf0 & MT_EE_NIC_CONF_0_PA_INT_5G);
- else
- return !(conf0 & MT_EE_NIC_CONF_0_PA_INT_2G);
-}
-EXPORT_SYMBOL_GPL(mt76x2_ext_pa_enabled);
-
-int mt76x2_eeprom_init(struct mt76x2_dev *dev)
+int mt76x2_eeprom_init(struct mt76x02_dev *dev)
{
int ret;
@@ -657,7 +515,7 @@ int mt76x2_eeprom_init(struct mt76x2_dev *dev)
if (ret)
return ret;
- mt76x2_eeprom_parse_hw_cap(dev);
+ mt76x02_eeprom_parse_hw_cap(dev);
mt76x2_eeprom_get_macaddr(dev);
mt76_eeprom_override(&dev->mt76);
dev->mt76.macaddr[0] &= ~BIT(1);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.h
new file mode 100644
index 000000000000..9e735524d367
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __MT76x2_EEPROM_H
+#define __MT76x2_EEPROM_H
+
+#include "../mt76x02_eeprom.h"
+
+enum mt76x2_cal_channel_group {
+ MT_CH_5G_JAPAN,
+ MT_CH_5G_UNII_1,
+ MT_CH_5G_UNII_2,
+ MT_CH_5G_UNII_2E_1,
+ MT_CH_5G_UNII_2E_2,
+ MT_CH_5G_UNII_3,
+ __MT_CH_MAX
+};
+
+struct mt76x2_tx_power_info {
+ u8 target_power;
+
+ s8 delta_bw40;
+ s8 delta_bw80;
+
+ struct {
+ s8 tssi_slope;
+ s8 tssi_offset;
+ s8 target_power;
+ s8 delta;
+ } chain[MT_MAX_CHAINS];
+};
+
+struct mt76x2_temp_comp {
+ u8 temp_25_ref;
+ int lower_bound; /* J */
+ int upper_bound; /* J */
+ unsigned int high_slope; /* J / dB */
+ unsigned int low_slope; /* J / dB */
+};
+
+void mt76x2_get_rate_power(struct mt76x02_dev *dev, struct mt76_rate_power *t,
+ struct ieee80211_channel *chan);
+void mt76x2_get_power_info(struct mt76x02_dev *dev,
+ struct mt76x2_tx_power_info *t,
+ struct ieee80211_channel *chan);
+int mt76x2_get_temp_comp(struct mt76x02_dev *dev, struct mt76x2_temp_comp *t);
+void mt76x2_read_rx_gain(struct mt76x02_dev *dev);
+
+static inline bool
+mt76x2_has_ext_lna(struct mt76x02_dev *dev)
+{
+ u32 val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1);
+
+ if (dev->mt76.chandef.chan->band == NL80211_BAND_2GHZ)
+ return val & MT_EE_NIC_CONF_1_LNA_EXT_2G;
+ else
+ return val & MT_EE_NIC_CONF_1_LNA_EXT_5G;
+}
+
+static inline bool
+mt76x2_temp_tx_alc_enabled(struct mt76x02_dev *dev)
+{
+ u16 val;
+
+ val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_EXT_PA_5G);
+ if (!(val & BIT(15)))
+ return false;
+
+ return mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1) &
+ MT_EE_NIC_CONF_1_TEMP_TX_ALC;
+}
+
+static inline bool
+mt76x2_tssi_enabled(struct mt76x02_dev *dev)
+{
+ return !mt76x2_temp_tx_alc_enabled(dev) &&
+ (mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1) &
+ MT_EE_NIC_CONF_1_TX_ALC_EN);
+}
+
+#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2/init.c
index 324b2a4b8b67..3c73fdeaf30f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_init_common.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/init.c
@@ -16,44 +16,11 @@
*/
#include "mt76x2.h"
-#include "mt76x2_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) | (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 mt76x2_rates[] = {
- CCK_RATE(0, 10),
- CCK_RATE(1, 20),
- CCK_RATE(2, 55),
- CCK_RATE(3, 110),
- OFDM_RATE(0, 60),
- OFDM_RATE(1, 90),
- OFDM_RATE(2, 120),
- OFDM_RATE(3, 180),
- OFDM_RATE(4, 240),
- OFDM_RATE(5, 360),
- OFDM_RATE(6, 480),
- OFDM_RATE(7, 540),
-};
-EXPORT_SYMBOL_GPL(mt76x2_rates);
-
-struct mt76x2_reg_pair {
- u32 reg;
- u32 value;
-};
+#include "eeprom.h"
+#include "../mt76x02_phy.h"
static void
-mt76x2_set_wlan_state(struct mt76x2_dev *dev, bool enable)
+mt76x2_set_wlan_state(struct mt76x02_dev *dev, bool enable)
{
u32 val = mt76_rr(dev, MT_WLAN_FUN_CTRL);
@@ -68,10 +35,13 @@ mt76x2_set_wlan_state(struct mt76x2_dev *dev, bool enable)
udelay(20);
}
-void mt76x2_reset_wlan(struct mt76x2_dev *dev, bool enable)
+void mt76x2_reset_wlan(struct mt76x02_dev *dev, bool enable)
{
u32 val;
+ if (!enable)
+ goto out;
+
val = mt76_rr(dev, MT_WLAN_FUN_CTRL);
val &= ~MT_WLAN_FUN_CTRL_FRC_WL_ANT_SEL;
@@ -87,22 +57,12 @@ void mt76x2_reset_wlan(struct mt76x2_dev *dev, bool enable)
mt76_wr(dev, MT_WLAN_FUN_CTRL, val);
udelay(20);
+out:
mt76x2_set_wlan_state(dev, enable);
}
EXPORT_SYMBOL_GPL(mt76x2_reset_wlan);
-static void
-mt76x2_write_reg_pairs(struct mt76x2_dev *dev,
- const struct mt76x2_reg_pair *data, int len)
-{
- while (len > 0) {
- mt76_wr(dev, data->reg, data->value);
- len--;
- data++;
- }
-}
-
-void mt76_write_mac_initvals(struct mt76x2_dev *dev)
+void mt76_write_mac_initvals(struct mt76x02_dev *dev)
{
#define DEFAULT_PROT_CFG_CCK \
(FIELD_PREP(MT_PROT_CFG_RATE, 0x3) | \
@@ -128,7 +88,7 @@ void mt76_write_mac_initvals(struct mt76x2_dev *dev)
FIELD_PREP(MT_PROT_CFG_NAV, 1) | \
FIELD_PREP(MT_PROT_CFG_TXOP_ALLOW, 0x3f))
- static const struct mt76x2_reg_pair vals[] = {
+ static const struct mt76_reg_pair vals[] = {
/* Copied from MediaTek reference source */
{ MT_PBF_SYS_CTRL, 0x00080c00 },
{ MT_PBF_CFG, 0x1efebcff },
@@ -184,7 +144,7 @@ void mt76_write_mac_initvals(struct mt76x2_dev *dev)
{ MT_PROT_AUTO_TX_CFG, 0x00830083 },
{ MT_HT_CTRL_CFG, 0x000001ff },
};
- struct mt76x2_reg_pair prot_vals[] = {
+ struct mt76_reg_pair prot_vals[] = {
{ MT_CCK_PROT_CFG, DEFAULT_PROT_CFG_CCK },
{ MT_OFDM_PROT_CFG, DEFAULT_PROT_CFG_OFDM },
{ MT_MM20_PROT_CFG, DEFAULT_PROT_CFG_20 },
@@ -193,12 +153,12 @@ void mt76_write_mac_initvals(struct mt76x2_dev *dev)
{ MT_GF40_PROT_CFG, DEFAULT_PROT_CFG_40 },
};
- mt76x2_write_reg_pairs(dev, vals, ARRAY_SIZE(vals));
- mt76x2_write_reg_pairs(dev, prot_vals, ARRAY_SIZE(prot_vals));
+ mt76_wr_rp(dev, 0, vals, ARRAY_SIZE(vals));
+ mt76_wr_rp(dev, 0, prot_vals, ARRAY_SIZE(prot_vals));
}
EXPORT_SYMBOL_GPL(mt76_write_mac_initvals);
-void mt76x2_init_device(struct mt76x2_dev *dev)
+void mt76x2_init_device(struct mt76x02_dev *dev)
{
struct ieee80211_hw *hw = mt76_hw(dev);
@@ -207,9 +167,12 @@ void mt76x2_init_device(struct mt76x2_dev *dev)
hw->max_report_rates = 7;
hw->max_rate_tries = 1;
hw->extra_tx_headroom = 2;
+ if (mt76_is_usb(dev))
+ hw->extra_tx_headroom += sizeof(struct mt76x02_txwi) +
+ MT_DMA_HDR_LEN;
- hw->sta_data_size = sizeof(struct mt76x2_sta);
- hw->vif_data_size = sizeof(struct mt76x2_vif);
+ hw->sta_data_size = sizeof(struct mt76x02_sta);
+ hw->vif_data_size = sizeof(struct mt76x02_vif);
ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES);
ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);
@@ -217,9 +180,9 @@ void mt76x2_init_device(struct mt76x2_dev *dev)
dev->mt76.sband_2g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING;
dev->mt76.sband_5g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING;
- dev->chainmask = 0x202;
- dev->global_wcid.idx = 255;
- dev->global_wcid.hw_key_idx = -1;
+ dev->mt76.chainmask = 0x202;
+ dev->mt76.global_wcid.idx = 255;
+ dev->mt76.global_wcid.hw_key_idx = -1;
dev->slottime = 9;
/* init antenna configuration */
@@ -227,7 +190,7 @@ void mt76x2_init_device(struct mt76x2_dev *dev)
}
EXPORT_SYMBOL_GPL(mt76x2_init_device);
-void mt76x2_init_txpower(struct mt76x2_dev *dev,
+void mt76x2_init_txpower(struct mt76x02_dev *dev,
struct ieee80211_supported_band *sband)
{
struct ieee80211_channel *chan;
@@ -248,7 +211,7 @@ void mt76x2_init_txpower(struct mt76x2_dev *dev,
mt76x2_get_rate_power(dev, &t, chan);
- chan->max_power = mt76x2_get_max_rate_power(&t) +
+ chan->max_power = mt76x02_get_max_rate_power(&t) +
target_power;
chan->max_power /= 2;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c
new file mode 100644
index 000000000000..e25905c91ee2
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
+ * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "mt76x2.h"
+
+void mt76x2_mac_stop(struct mt76x02_dev *dev, bool force)
+{
+ bool stopped = false;
+ u32 rts_cfg;
+ int i;
+
+ mt76_wr(dev, MT_MAC_SYS_CTRL, 0);
+
+ rts_cfg = mt76_rr(dev, MT_TX_RTS_CFG);
+ mt76_wr(dev, MT_TX_RTS_CFG, rts_cfg & ~MT_TX_RTS_CFG_RETRY_LIMIT);
+
+ /* Wait for MAC to become idle */
+ for (i = 0; i < 300; i++) {
+ if ((mt76_rr(dev, MT_MAC_STATUS) &
+ (MT_MAC_STATUS_RX | MT_MAC_STATUS_TX)) ||
+ mt76_rr(dev, MT_BBP(IBI, 12))) {
+ udelay(1);
+ continue;
+ }
+
+ stopped = true;
+ break;
+ }
+
+ if (force && !stopped) {
+ mt76_set(dev, MT_BBP(CORE, 4), BIT(1));
+ mt76_clear(dev, MT_BBP(CORE, 4), BIT(1));
+
+ mt76_set(dev, MT_BBP(CORE, 4), BIT(0));
+ mt76_clear(dev, MT_BBP(CORE, 4), BIT(0));
+ }
+
+ mt76_wr(dev, MT_TX_RTS_CFG, rts_cfg);
+}
+EXPORT_SYMBOL_GPL(mt76x2_mac_stop);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h
new file mode 100644
index 000000000000..a31bd49ae6cb
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __MT76x2_MAC_H
+#define __MT76x2_MAC_H
+
+#include "mt76x2.h"
+
+struct mt76x02_dev;
+struct mt76x2_sta;
+struct mt76x02_vif;
+
+int mt76x2_mac_start(struct mt76x02_dev *dev);
+void mt76x2_mac_stop(struct mt76x02_dev *dev, bool force);
+void mt76x2_mac_resume(struct mt76x02_dev *dev);
+void mt76x2_mac_set_bssid(struct mt76x02_dev *dev, u8 idx, const u8 *addr);
+
+int mt76x2_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx,
+ struct sk_buff *skb);
+void mt76x2_mac_set_beacon_enable(struct mt76x02_dev *dev, u8 vif_idx, bool val);
+
+void mt76x2_mac_work(struct work_struct *work);
+
+#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c
new file mode 100644
index 000000000000..88bd62cfbdf9
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
+ * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+
+#include "mt76x2.h"
+#include "mcu.h"
+#include "eeprom.h"
+
+int mt76x2_mcu_set_channel(struct mt76x02_dev *dev, u8 channel, u8 bw,
+ u8 bw_index, bool scan)
+{
+ struct sk_buff *skb;
+ struct {
+ u8 idx;
+ u8 scan;
+ u8 bw;
+ u8 _pad0;
+
+ __le16 chainmask;
+ u8 ext_chan;
+ u8 _pad1;
+
+ } __packed __aligned(4) msg = {
+ .idx = channel,
+ .scan = scan,
+ .bw = bw,
+ .chainmask = cpu_to_le16(dev->mt76.chainmask),
+ };
+
+ /* first set the channel without the extension channel info */
+ skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg));
+ mt76_mcu_send_msg(dev, skb, CMD_SWITCH_CHANNEL_OP, true);
+
+ usleep_range(5000, 10000);
+
+ msg.ext_chan = 0xe0 + bw_index;
+ skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg));
+ return mt76_mcu_send_msg(dev, skb, CMD_SWITCH_CHANNEL_OP, true);
+}
+EXPORT_SYMBOL_GPL(mt76x2_mcu_set_channel);
+
+int mt76x2_mcu_load_cr(struct mt76x02_dev *dev, u8 type, u8 temp_level,
+ u8 channel)
+{
+ struct sk_buff *skb;
+ struct {
+ u8 cr_mode;
+ u8 temp;
+ u8 ch;
+ u8 _pad0;
+
+ __le32 cfg;
+ } __packed __aligned(4) msg = {
+ .cr_mode = type,
+ .temp = temp_level,
+ .ch = channel,
+ };
+ u32 val;
+
+ val = BIT(31);
+ val |= (mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_0) >> 8) & 0x00ff;
+ val |= (mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1) << 8) & 0xff00;
+ msg.cfg = cpu_to_le32(val);
+
+ /* first set the channel without the extension channel info */
+ skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg));
+ return mt76_mcu_send_msg(dev, skb, CMD_LOAD_CR, true);
+}
+EXPORT_SYMBOL_GPL(mt76x2_mcu_load_cr);
+
+int mt76x2_mcu_init_gain(struct mt76x02_dev *dev, u8 channel, u32 gain,
+ bool force)
+{
+ struct sk_buff *skb;
+ struct {
+ __le32 channel;
+ __le32 gain_val;
+ } __packed __aligned(4) msg = {
+ .channel = cpu_to_le32(channel),
+ .gain_val = cpu_to_le32(gain),
+ };
+
+ if (force)
+ msg.channel |= cpu_to_le32(BIT(31));
+
+ skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg));
+ return mt76_mcu_send_msg(dev, skb, CMD_INIT_GAIN_OP, true);
+}
+EXPORT_SYMBOL_GPL(mt76x2_mcu_init_gain);
+
+int mt76x2_mcu_tssi_comp(struct mt76x02_dev *dev,
+ struct mt76x2_tssi_comp *tssi_data)
+{
+ struct sk_buff *skb;
+ struct {
+ __le32 id;
+ struct mt76x2_tssi_comp data;
+ } __packed __aligned(4) msg = {
+ .id = cpu_to_le32(MCU_CAL_TSSI_COMP),
+ .data = *tssi_data,
+ };
+
+ skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg));
+ return mt76_mcu_send_msg(dev, skb, CMD_CALIBRATION_OP, true);
+}
+EXPORT_SYMBOL_GPL(mt76x2_mcu_tssi_comp);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.h
index e40293f21417..acfa2b570c7c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.h
@@ -17,19 +17,14 @@
#ifndef __MT76x2_MCU_H
#define __MT76x2_MCU_H
+#include "../mt76x02_mcu.h"
+
/* Register definitions */
#define MT_MCU_CPU_CTL 0x0704
#define MT_MCU_CLOCK_CTL 0x0708
-#define MT_MCU_RESET_CTL 0x070C
-#define MT_MCU_INT_LEVEL 0x0718
-#define MT_MCU_COM_REG0 0x0730
-#define MT_MCU_COM_REG1 0x0734
-#define MT_MCU_COM_REG2 0x0738
-#define MT_MCU_COM_REG3 0x073C
#define MT_MCU_PCIE_REMAP_BASE1 0x0740
#define MT_MCU_PCIE_REMAP_BASE2 0x0744
#define MT_MCU_PCIE_REMAP_BASE3 0x0748
-#define MT_MCU_PCIE_REMAP_BASE4 0x074C
#define MT_LED_CTRL 0x0770
#define MT_LED_CTRL_REPLAY(_n) BIT(0 + (8 * (_n)))
@@ -54,62 +49,15 @@
#define MT_LED_STATUS_DURATION(_v) (((_v) << __ffs(MT_LED_STATUS_DURATION_MASK)) & \
MT_LED_STATUS_DURATION_MASK)
-#define MT_MCU_SEMAPHORE_00 0x07B0
-#define MT_MCU_SEMAPHORE_01 0x07B4
-#define MT_MCU_SEMAPHORE_02 0x07B8
-#define MT_MCU_SEMAPHORE_03 0x07BC
-
#define MT_MCU_ROM_PATCH_OFFSET 0x80000
#define MT_MCU_ROM_PATCH_ADDR 0x90000
#define MT_MCU_ILM_OFFSET 0x80000
-#define MT_MCU_ILM_ADDR 0x80000
#define MT_MCU_DLM_OFFSET 0x100000
#define MT_MCU_DLM_ADDR 0x90000
#define MT_MCU_DLM_ADDR_E3 0x90800
-enum mcu_cmd {
- CMD_FUN_SET_OP = 1,
- CMD_LOAD_CR = 2,
- CMD_INIT_GAIN_OP = 3,
- CMD_DYNC_VGA_OP = 6,
- CMD_TDLS_CH_SW = 7,
- CMD_BURST_WRITE = 8,
- CMD_READ_MODIFY_WRITE = 9,
- CMD_RANDOM_READ = 10,
- CMD_BURST_READ = 11,
- CMD_RANDOM_WRITE = 12,
- CMD_LED_MODE_OP = 16,
- CMD_POWER_SAVING_OP = 20,
- CMD_WOW_CONFIG = 21,
- CMD_WOW_QUERY = 22,
- CMD_WOW_FEATURE = 24,
- CMD_CARRIER_DETECT_OP = 28,
- CMD_RADOR_DETECT_OP = 29,
- CMD_SWITCH_CHANNEL_OP = 30,
- CMD_CALIBRATION_OP = 31,
- CMD_BEACON_OP = 32,
- CMD_ANTENNA_OP = 33,
-};
-
-enum mcu_function {
- Q_SELECT = 1,
- BW_SETTING = 2,
- USB2_SW_DISCONNECT = 2,
- USB3_SW_DISCONNECT = 3,
- LOG_FW_DEBUG_MSG = 4,
- GET_FW_VERSION = 5,
-};
-
-enum mcu_power_mode {
- RADIO_OFF = 0x30,
- RADIO_ON = 0x31,
- RADIO_OFF_AUTO_WAKEUP = 0x32,
- RADIO_OFF_ADVANCE = 0x33,
- RADIO_ON_ADVANCE = 0x34,
-};
-
enum mcu_calibration {
MCU_CAL_R = 1,
MCU_CAL_TEMP_SENSOR,
@@ -146,27 +94,8 @@ struct mt76x2_tssi_comp {
u8 offset1;
} __packed __aligned(4);
-struct mt76x2_fw_header {
- __le32 ilm_len;
- __le32 dlm_len;
- __le16 build_ver;
- __le16 fw_ver;
- u8 pad[4];
- char build_time[16];
-};
-
-struct mt76x2_patch_header {
- char build_time[16];
- char platform[4];
- char hw_version[4];
- char patch_version[4];
- u8 pad[2];
-};
-
-int mt76x2_mcu_calibrate(struct mt76x2_dev *dev, enum mcu_calibration type,
- u32 param);
-int mt76x2_mcu_tssi_comp(struct mt76x2_dev *dev, struct mt76x2_tssi_comp *tssi_data);
-int mt76x2_mcu_init_gain(struct mt76x2_dev *dev, u8 channel, u32 gain,
+int mt76x2_mcu_tssi_comp(struct mt76x02_dev *dev, struct mt76x2_tssi_comp *tssi_data);
+int mt76x2_mcu_init_gain(struct mt76x02_dev *dev, u8 channel, u32 gain,
bool force);
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h
new file mode 100644
index 000000000000..ab93125f46de
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __MT76x2_H
+#define __MT76x2_H
+
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/spinlock.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/bitops.h>
+
+#define MT7662_FIRMWARE "mt7662.bin"
+#define MT7662_ROM_PATCH "mt7662_rom_patch.bin"
+#define MT7662_EEPROM_SIZE 512
+
+#define MT7662U_FIRMWARE "mediatek/mt7662u.bin"
+#define MT7662U_ROM_PATCH "mediatek/mt7662u_rom_patch.bin"
+
+#define MT_CALIBRATE_INTERVAL HZ
+
+#include "../mt76x02.h"
+#include "mac.h"
+#include "dfs.h"
+
+static inline bool is_mt7612(struct mt76x02_dev *dev)
+{
+ return mt76_chip(&dev->mt76) == 0x7612;
+}
+
+static inline bool mt76x2_channel_silent(struct mt76x02_dev *dev)
+{
+ struct ieee80211_channel *chan = dev->mt76.chandef.chan;
+
+ return ((chan->flags & IEEE80211_CHAN_RADAR) &&
+ chan->dfs_state != NL80211_DFS_AVAILABLE);
+}
+
+extern const struct ieee80211_ops mt76x2_ops;
+
+struct mt76x02_dev *mt76x2_alloc_device(struct device *pdev);
+int mt76x2_register_device(struct mt76x02_dev *dev);
+void mt76x2_init_debugfs(struct mt76x02_dev *dev);
+void mt76x2_init_device(struct mt76x02_dev *dev);
+
+void mt76x2_phy_power_on(struct mt76x02_dev *dev);
+int mt76x2_init_hardware(struct mt76x02_dev *dev);
+void mt76x2_stop_hardware(struct mt76x02_dev *dev);
+int mt76x2_eeprom_init(struct mt76x02_dev *dev);
+int mt76x2_apply_calibration_data(struct mt76x02_dev *dev, int channel);
+void mt76x2_set_tx_ackto(struct mt76x02_dev *dev);
+
+void mt76x2_phy_set_antenna(struct mt76x02_dev *dev);
+int mt76x2_phy_start(struct mt76x02_dev *dev);
+int mt76x2_phy_set_channel(struct mt76x02_dev *dev,
+ struct cfg80211_chan_def *chandef);
+void mt76x2_phy_calibrate(struct work_struct *work);
+void mt76x2_phy_set_txpower(struct mt76x02_dev *dev);
+
+int mt76x2_mcu_init(struct mt76x02_dev *dev);
+int mt76x2_mcu_set_channel(struct mt76x02_dev *dev, u8 channel, u8 bw,
+ u8 bw_index, bool scan);
+int mt76x2_mcu_load_cr(struct mt76x02_dev *dev, u8 type, u8 temp_level,
+ u8 channel);
+
+void mt76x2_cleanup(struct mt76x02_dev *dev);
+
+void mt76x2_mac_set_tx_protection(struct mt76x02_dev *dev, u32 val);
+
+void mt76x2_pre_tbtt_tasklet(unsigned long arg);
+
+void mt76x2_sta_ps(struct mt76_dev *dev, struct ieee80211_sta *sta, bool ps);
+
+void mt76x2_update_channel(struct mt76_dev *mdev);
+
+void mt76x2_reset_wlan(struct mt76x02_dev *dev, bool enable);
+void mt76x2_init_txpower(struct mt76x02_dev *dev,
+ struct ieee80211_supported_band *sband);
+void mt76_write_mac_initvals(struct mt76x02_dev *dev);
+
+void mt76x2_phy_tssi_compensate(struct mt76x02_dev *dev, bool wait);
+void mt76x2_phy_set_txpower_regs(struct mt76x02_dev *dev,
+ enum nl80211_band band);
+void mt76x2_configure_tx_delay(struct mt76x02_dev *dev,
+ enum nl80211_band band, u8 bw);
+void mt76x2_apply_gain_adj(struct mt76x02_dev *dev);
+
+#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h
new file mode 100644
index 000000000000..6e932b5010ef
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __MT76x2U_H
+#define __MT76x2U_H
+
+#include <linux/device.h>
+
+#include "mt76x2.h"
+#include "mcu.h"
+
+#define MT7612U_EEPROM_SIZE 512
+
+#define MT_USB_AGGR_SIZE_LIMIT 21 /* 1024B unit */
+#define MT_USB_AGGR_TIMEOUT 0x80 /* 33ns unit */
+
+extern const struct ieee80211_ops mt76x2u_ops;
+
+struct mt76x02_dev *mt76x2u_alloc_device(struct device *pdev);
+int mt76x2u_register_device(struct mt76x02_dev *dev);
+int mt76x2u_init_hardware(struct mt76x02_dev *dev);
+void mt76x2u_cleanup(struct mt76x02_dev *dev);
+void mt76x2u_stop_hw(struct mt76x02_dev *dev);
+
+int mt76x2u_mac_reset(struct mt76x02_dev *dev);
+void mt76x2u_mac_resume(struct mt76x02_dev *dev);
+int mt76x2u_mac_start(struct mt76x02_dev *dev);
+int mt76x2u_mac_stop(struct mt76x02_dev *dev);
+
+int mt76x2u_phy_set_channel(struct mt76x02_dev *dev,
+ struct cfg80211_chan_def *chandef);
+void mt76x2u_phy_calibrate(struct work_struct *work);
+void mt76x2u_phy_channel_calibrate(struct mt76x02_dev *dev);
+
+void mt76x2u_mcu_complete_urb(struct urb *urb);
+int mt76x2u_mcu_set_dynamic_vga(struct mt76x02_dev *dev, u8 channel, bool ap,
+ bool ext, int rssi, u32 false_cca);
+int mt76x2u_mcu_init(struct mt76x02_dev *dev);
+int mt76x2u_mcu_fw_init(struct mt76x02_dev *dev);
+
+int mt76x2u_alloc_queues(struct mt76x02_dev *dev);
+void mt76x2u_queues_deinit(struct mt76x02_dev *dev);
+void mt76x2u_stop_queues(struct mt76x02_dev *dev);
+int mt76x2u_skb_dma_info(struct sk_buff *skb, enum dma_msg_port port,
+ u32 flags);
+
+#endif /* __MT76x2U_H */
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_pci.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c
index e66f047ea448..92432fe97312 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c
@@ -19,7 +19,6 @@
#include <linux/pci.h>
#include "mt76x2.h"
-#include "mt76x2_trace.h"
static const struct pci_device_id mt76pci_device_table[] = {
{ PCI_DEVICE(0x14c3, 0x7662) },
@@ -31,7 +30,7 @@ static const struct pci_device_id mt76pci_device_table[] = {
static int
mt76pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
- struct mt76x2_dev *dev;
+ struct mt76x02_dev *dev;
int ret;
ret = pcim_enable_device(pdev);
@@ -53,11 +52,12 @@ mt76pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return -ENOMEM;
mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]);
+ mt76x2_reset_wlan(dev, false);
dev->mt76.rev = mt76_rr(dev, MT_ASIC_VERSION);
dev_info(dev->mt76.dev, "ASIC revision: %08x\n", dev->mt76.rev);
- ret = devm_request_irq(dev->mt76.dev, pdev->irq, mt76x2_irq_handler,
+ ret = devm_request_irq(dev->mt76.dev, pdev->irq, mt76x02_irq_handler,
IRQF_SHARED, KBUILD_MODNAME, dev);
if (ret)
goto error;
@@ -88,7 +88,7 @@ static void
mt76pci_remove(struct pci_dev *pdev)
{
struct mt76_dev *mdev = pci_get_drvdata(pdev);
- struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76);
+ struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
mt76_unregister_device(mdev);
mt76x2_cleanup(dev);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_dfs.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dfs.c
index 374cc655c11d..b56febae8945 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_dfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_dfs.c
@@ -36,7 +36,7 @@
.pwr_jmp = power_jmp \
}
-static const struct mt76x2_radar_specs etsi_radar_specs[] = {
+static const struct mt76x02_radar_specs etsi_radar_specs[] = {
/* 20MHz */
RADAR_SPEC(0, 8, 2, 15, 106, 150, 10, 4900, 100096, 10, 0,
0x7fffffff, 0x155cc0, 0x19cc),
@@ -66,7 +66,7 @@ static const struct mt76x2_radar_specs etsi_radar_specs[] = {
0x7fffffff, 0x2191c0, 0x15cc)
};
-static const struct mt76x2_radar_specs fcc_radar_specs[] = {
+static const struct mt76x02_radar_specs fcc_radar_specs[] = {
/* 20MHz */
RADAR_SPEC(0, 8, 2, 12, 106, 150, 5, 2900, 80100, 5, 0,
0x7fffffff, 0xfe808, 0x13dc),
@@ -96,7 +96,7 @@ static const struct mt76x2_radar_specs fcc_radar_specs[] = {
0x3938700, 0x57bcf00, 0x1289)
};
-static const struct mt76x2_radar_specs jp_w56_radar_specs[] = {
+static const struct mt76x02_radar_specs jp_w56_radar_specs[] = {
/* 20MHz */
RADAR_SPEC(0, 8, 2, 7, 106, 150, 5, 2900, 80100, 5, 0,
0x7fffffff, 0x14c080, 0x13dc),
@@ -126,7 +126,7 @@ static const struct mt76x2_radar_specs jp_w56_radar_specs[] = {
0x3938700, 0X57bcf00, 0x1289)
};
-static const struct mt76x2_radar_specs jp_w53_radar_specs[] = {
+static const struct mt76x02_radar_specs jp_w53_radar_specs[] = {
/* 20MHz */
RADAR_SPEC(0, 8, 2, 9, 106, 150, 20, 28400, 77000, 20, 0,
0x7fffffff, 0x14c080, 0x16cc),
@@ -150,8 +150,9 @@ static const struct mt76x2_radar_specs jp_w53_radar_specs[] = {
{ 0 }
};
-static void mt76x2_dfs_set_capture_mode_ctrl(struct mt76x2_dev *dev,
- u8 enable)
+static void
+mt76x2_dfs_set_capture_mode_ctrl(struct mt76x02_dev *dev,
+ u8 enable)
{
u32 data;
@@ -159,10 +160,10 @@ static void mt76x2_dfs_set_capture_mode_ctrl(struct mt76x2_dev *dev,
mt76_wr(dev, MT_BBP(DFS, 36), data);
}
-static void mt76x2_dfs_seq_pool_put(struct mt76x2_dev *dev,
- struct mt76x2_dfs_sequence *seq)
+static void mt76x2_dfs_seq_pool_put(struct mt76x02_dev *dev,
+ struct mt76x02_dfs_sequence *seq)
{
- struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
+ struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
list_add(&seq->head, &dfs_pd->seq_pool);
@@ -170,17 +171,17 @@ static void mt76x2_dfs_seq_pool_put(struct mt76x2_dev *dev,
dfs_pd->seq_stats.seq_len--;
}
-static
-struct mt76x2_dfs_sequence *mt76x2_dfs_seq_pool_get(struct mt76x2_dev *dev)
+static struct mt76x02_dfs_sequence *
+mt76x2_dfs_seq_pool_get(struct mt76x02_dev *dev)
{
- struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
- struct mt76x2_dfs_sequence *seq;
+ struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
+ struct mt76x02_dfs_sequence *seq;
if (list_empty(&dfs_pd->seq_pool)) {
seq = devm_kzalloc(dev->mt76.dev, sizeof(*seq), GFP_ATOMIC);
} else {
seq = list_first_entry(&dfs_pd->seq_pool,
- struct mt76x2_dfs_sequence,
+ struct mt76x02_dfs_sequence,
head);
list_del(&seq->head);
dfs_pd->seq_stats.seq_pool_len--;
@@ -213,10 +214,10 @@ static int mt76x2_dfs_get_multiple(int val, int frac, int margin)
return factor;
}
-static void mt76x2_dfs_detector_reset(struct mt76x2_dev *dev)
+static void mt76x2_dfs_detector_reset(struct mt76x02_dev *dev)
{
- struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
- struct mt76x2_dfs_sequence *seq, *tmp_seq;
+ struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
+ struct mt76x02_dfs_sequence *seq, *tmp_seq;
int i;
/* reset hw detector */
@@ -234,11 +235,11 @@ static void mt76x2_dfs_detector_reset(struct mt76x2_dev *dev)
}
}
-static bool mt76x2_dfs_check_chirp(struct mt76x2_dev *dev)
+static bool mt76x2_dfs_check_chirp(struct mt76x02_dev *dev)
{
bool ret = false;
u32 current_ts, delta_ts;
- struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
+ struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
current_ts = mt76_rr(dev, MT_PBF_LIFE_TIMER);
delta_ts = current_ts - dfs_pd->chirp_pulse_ts;
@@ -255,8 +256,8 @@ static bool mt76x2_dfs_check_chirp(struct mt76x2_dev *dev)
return ret;
}
-static void mt76x2_dfs_get_hw_pulse(struct mt76x2_dev *dev,
- struct mt76x2_dfs_hw_pulse *pulse)
+static void mt76x2_dfs_get_hw_pulse(struct mt76x02_dev *dev,
+ struct mt76x02_dfs_hw_pulse *pulse)
{
u32 data;
@@ -275,8 +276,8 @@ static void mt76x2_dfs_get_hw_pulse(struct mt76x2_dev *dev,
pulse->burst = mt76_rr(dev, MT_BBP(DFS, 22));
}
-static bool mt76x2_dfs_check_hw_pulse(struct mt76x2_dev *dev,
- struct mt76x2_dfs_hw_pulse *pulse)
+static bool mt76x2_dfs_check_hw_pulse(struct mt76x02_dev *dev,
+ struct mt76x02_dfs_hw_pulse *pulse)
{
bool ret = false;
@@ -370,8 +371,8 @@ static bool mt76x2_dfs_check_hw_pulse(struct mt76x2_dev *dev,
return ret;
}
-static bool mt76x2_dfs_fetch_event(struct mt76x2_dev *dev,
- struct mt76x2_dfs_event *event)
+static bool mt76x2_dfs_fetch_event(struct mt76x02_dev *dev,
+ struct mt76x02_dfs_event *event)
{
u32 data;
@@ -397,12 +398,12 @@ static bool mt76x2_dfs_fetch_event(struct mt76x2_dev *dev,
return true;
}
-static bool mt76x2_dfs_check_event(struct mt76x2_dev *dev,
- struct mt76x2_dfs_event *event)
+static bool mt76x2_dfs_check_event(struct mt76x02_dev *dev,
+ struct mt76x02_dfs_event *event)
{
if (event->engine == 2) {
- struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
- struct mt76x2_dfs_event_rb *event_buff = &dfs_pd->event_rb[1];
+ struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
+ struct mt76x02_dfs_event_rb *event_buff = &dfs_pd->event_rb[1];
u16 last_event_idx;
u32 delta_ts;
@@ -416,11 +417,11 @@ static bool mt76x2_dfs_check_event(struct mt76x2_dev *dev,
return true;
}
-static void mt76x2_dfs_queue_event(struct mt76x2_dev *dev,
- struct mt76x2_dfs_event *event)
+static void mt76x2_dfs_queue_event(struct mt76x02_dev *dev,
+ struct mt76x02_dfs_event *event)
{
- struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
- struct mt76x2_dfs_event_rb *event_buff;
+ struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
+ struct mt76x02_dfs_event_rb *event_buff;
/* add radar event to ring buffer */
event_buff = event->engine == 2 ? &dfs_pd->event_rb[1]
@@ -434,16 +435,16 @@ static void mt76x2_dfs_queue_event(struct mt76x2_dev *dev,
MT_DFS_EVENT_BUFLEN);
}
-static int mt76x2_dfs_create_sequence(struct mt76x2_dev *dev,
- struct mt76x2_dfs_event *event,
+static int mt76x2_dfs_create_sequence(struct mt76x02_dev *dev,
+ struct mt76x02_dfs_event *event,
u16 cur_len)
{
- struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
- struct mt76x2_dfs_sw_detector_params *sw_params;
+ struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
+ struct mt76x02_dfs_sw_detector_params *sw_params;
u32 width_delta, with_sum, factor, cur_pri;
- struct mt76x2_dfs_sequence seq, *seq_p;
- struct mt76x2_dfs_event_rb *event_rb;
- struct mt76x2_dfs_event *cur_event;
+ struct mt76x02_dfs_sequence seq, *seq_p;
+ struct mt76x02_dfs_event_rb *event_rb;
+ struct mt76x02_dfs_event *cur_event;
int i, j, end, pri;
event_rb = event->engine == 2 ? &dfs_pd->event_rb[1]
@@ -521,12 +522,12 @@ next:
return 0;
}
-static u16 mt76x2_dfs_add_event_to_sequence(struct mt76x2_dev *dev,
- struct mt76x2_dfs_event *event)
+static u16 mt76x2_dfs_add_event_to_sequence(struct mt76x02_dev *dev,
+ struct mt76x02_dfs_event *event)
{
- struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
- struct mt76x2_dfs_sw_detector_params *sw_params;
- struct mt76x2_dfs_sequence *seq, *tmp_seq;
+ struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
+ struct mt76x02_dfs_sw_detector_params *sw_params;
+ struct mt76x02_dfs_sequence *seq, *tmp_seq;
u16 max_seq_len = 0;
u32 factor, pri;
@@ -553,10 +554,10 @@ static u16 mt76x2_dfs_add_event_to_sequence(struct mt76x2_dev *dev,
return max_seq_len;
}
-static bool mt76x2_dfs_check_detection(struct mt76x2_dev *dev)
+static bool mt76x2_dfs_check_detection(struct mt76x02_dev *dev)
{
- struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
- struct mt76x2_dfs_sequence *seq;
+ struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
+ struct mt76x02_dfs_sequence *seq;
if (list_empty(&dfs_pd->sequences))
return false;
@@ -570,10 +571,10 @@ static bool mt76x2_dfs_check_detection(struct mt76x2_dev *dev)
return false;
}
-static void mt76x2_dfs_add_events(struct mt76x2_dev *dev)
+static void mt76x2_dfs_add_events(struct mt76x02_dev *dev)
{
- struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
- struct mt76x2_dfs_event event;
+ struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
+ struct mt76x02_dfs_event event;
int i, seq_len;
/* disable debug mode */
@@ -597,11 +598,11 @@ static void mt76x2_dfs_add_events(struct mt76x2_dev *dev)
mt76x2_dfs_set_capture_mode_ctrl(dev, true);
}
-static void mt76x2_dfs_check_event_window(struct mt76x2_dev *dev)
+static void mt76x2_dfs_check_event_window(struct mt76x02_dev *dev)
{
- struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
- struct mt76x2_dfs_event_rb *event_buff;
- struct mt76x2_dfs_event *event;
+ struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
+ struct mt76x02_dfs_event_rb *event_buff;
+ struct mt76x02_dfs_event *event;
int i;
for (i = 0; i < ARRAY_SIZE(dfs_pd->event_rb); i++) {
@@ -622,8 +623,8 @@ static void mt76x2_dfs_check_event_window(struct mt76x2_dev *dev)
static void mt76x2_dfs_tasklet(unsigned long arg)
{
- struct mt76x2_dev *dev = (struct mt76x2_dev *)arg;
- struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
+ struct mt76x02_dev *dev = (struct mt76x02_dev *)arg;
+ struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
u32 engine_mask;
int i;
@@ -653,7 +654,7 @@ static void mt76x2_dfs_tasklet(unsigned long arg)
goto out;
for (i = 0; i < MT_DFS_NUM_ENGINES; i++) {
- struct mt76x2_dfs_hw_pulse pulse;
+ struct mt76x02_dfs_hw_pulse pulse;
if (!(engine_mask & (1 << i)))
continue;
@@ -678,12 +679,12 @@ static void mt76x2_dfs_tasklet(unsigned long arg)
mt76_wr(dev, MT_BBP(DFS, 1), 0xf);
out:
- mt76x2_irq_enable(dev, MT_INT_GPTIMER);
+ mt76x02_irq_enable(dev, MT_INT_GPTIMER);
}
-static void mt76x2_dfs_init_sw_detector(struct mt76x2_dev *dev)
+static void mt76x2_dfs_init_sw_detector(struct mt76x02_dev *dev)
{
- struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
+ struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
switch (dev->dfs_pd.region) {
case NL80211_DFS_FCC:
@@ -707,11 +708,11 @@ static void mt76x2_dfs_init_sw_detector(struct mt76x2_dev *dev)
}
}
-static void mt76x2_dfs_set_bbp_params(struct mt76x2_dev *dev)
+static void mt76x2_dfs_set_bbp_params(struct mt76x02_dev *dev)
{
- u32 data;
+ const struct mt76x02_radar_specs *radar_specs;
u8 i, shift;
- const struct mt76x2_radar_specs *radar_specs;
+ u32 data;
switch (dev->mt76.chandef.width) {
case NL80211_CHAN_WIDTH_40:
@@ -802,7 +803,7 @@ static void mt76x2_dfs_set_bbp_params(struct mt76x2_dev *dev)
mt76_wr(dev, 0x212c, 0x0c350001);
}
-void mt76x2_dfs_adjust_agc(struct mt76x2_dev *dev)
+void mt76x2_dfs_adjust_agc(struct mt76x02_dev *dev)
{
u32 agc_r8, agc_r4, val_r8, val_r4, dfs_r31;
@@ -823,7 +824,7 @@ void mt76x2_dfs_adjust_agc(struct mt76x2_dev *dev)
mt76_wr(dev, MT_BBP(DFS, 32), 0x00040071);
}
-void mt76x2_dfs_init_params(struct mt76x2_dev *dev)
+void mt76x2_dfs_init_params(struct mt76x02_dev *dev)
{
struct cfg80211_chan_def *chandef = &dev->mt76.chandef;
@@ -834,7 +835,7 @@ void mt76x2_dfs_init_params(struct mt76x2_dev *dev)
/* enable debug mode */
mt76x2_dfs_set_capture_mode_ctrl(dev, true);
- mt76x2_irq_enable(dev, MT_INT_GPTIMER);
+ mt76x02_irq_enable(dev, MT_INT_GPTIMER);
mt76_rmw_field(dev, MT_INT_TIMER_EN,
MT_INT_TIMER_EN_GP_TIMER_EN, 1);
} else {
@@ -844,15 +845,15 @@ void mt76x2_dfs_init_params(struct mt76x2_dev *dev)
mt76_wr(dev, MT_BBP(DFS, 1), 0xf);
mt76_wr(dev, 0x212c, 0);
- mt76x2_irq_disable(dev, MT_INT_GPTIMER);
+ mt76x02_irq_disable(dev, MT_INT_GPTIMER);
mt76_rmw_field(dev, MT_INT_TIMER_EN,
MT_INT_TIMER_EN_GP_TIMER_EN, 0);
}
}
-void mt76x2_dfs_init_detector(struct mt76x2_dev *dev)
+void mt76x2_dfs_init_detector(struct mt76x02_dev *dev)
{
- struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
+ struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
INIT_LIST_HEAD(&dfs_pd->sequences);
INIT_LIST_HEAD(&dfs_pd->seq_pool);
@@ -862,10 +863,10 @@ void mt76x2_dfs_init_detector(struct mt76x2_dev *dev)
(unsigned long)dev);
}
-void mt76x2_dfs_set_domain(struct mt76x2_dev *dev,
+void mt76x2_dfs_set_domain(struct mt76x02_dev *dev,
enum nl80211_dfs_regions region)
{
- struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
+ struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
if (dfs_pd->region != region) {
tasklet_disable(&dfs_pd->dfs_tasklet);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c
index b814391f79ac..3824290b219d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c
@@ -16,11 +16,11 @@
#include <linux/delay.h>
#include "mt76x2.h"
-#include "mt76x2_eeprom.h"
-#include "mt76x2_mcu.h"
+#include "eeprom.h"
+#include "mcu.h"
static void
-mt76x2_mac_pbf_init(struct mt76x2_dev *dev)
+mt76x2_mac_pbf_init(struct mt76x02_dev *dev)
{
u32 val;
@@ -38,12 +38,12 @@ mt76x2_mac_pbf_init(struct mt76x2_dev *dev)
}
static void
-mt76x2_fixup_xtal(struct mt76x2_dev *dev)
+mt76x2_fixup_xtal(struct mt76x02_dev *dev)
{
u16 eep_val;
s8 offset = 0;
- eep_val = mt76x2_eeprom_get(dev, MT_EE_XTAL_TRIM_2);
+ eep_val = mt76x02_eeprom_get(dev, MT_EE_XTAL_TRIM_2);
offset = eep_val & 0x7f;
if ((eep_val & 0xff) == 0xff)
@@ -53,7 +53,7 @@ mt76x2_fixup_xtal(struct mt76x2_dev *dev)
eep_val >>= 8;
if (eep_val == 0x00 || eep_val == 0xff) {
- eep_val = mt76x2_eeprom_get(dev, MT_EE_XTAL_TRIM_1);
+ eep_val = mt76x02_eeprom_get(dev, MT_EE_XTAL_TRIM_1);
eep_val &= 0xff;
if (eep_val == 0x00 || eep_val == 0xff)
@@ -64,7 +64,7 @@ mt76x2_fixup_xtal(struct mt76x2_dev *dev)
mt76_rmw_field(dev, MT_XO_CTRL5, MT_XO_CTRL5_C2_VAL, eep_val + offset);
mt76_set(dev, MT_XO_CTRL6, MT_XO_CTRL6_C2_CTRL);
- eep_val = mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_2);
+ eep_val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_2);
switch (FIELD_GET(MT_EE_NIC_CONF_2_XTAL_OPTION, eep_val)) {
case 0:
mt76_wr(dev, MT_XO_CTRL7, 0x5c1fee80);
@@ -77,31 +77,14 @@ mt76x2_fixup_xtal(struct mt76x2_dev *dev)
}
}
-static void
-mt76x2_init_beacon_offsets(struct mt76x2_dev *dev)
-{
- u16 base = MT_BEACON_BASE;
- u32 regs[4] = {};
- int i;
-
- for (i = 0; i < 16; i++) {
- u16 addr = dev->beacon_offsets[i];
-
- regs[i / 4] |= ((addr - base) / 64) << (8 * (i % 4));
- }
-
- for (i = 0; i < 4; i++)
- mt76_wr(dev, MT_BCN_OFFSET(i), regs[i]);
-}
-
-static int mt76x2_mac_reset(struct mt76x2_dev *dev, bool hard)
+static int mt76x2_mac_reset(struct mt76x02_dev *dev, bool hard)
{
static const u8 null_addr[ETH_ALEN] = {};
const u8 *macaddr = dev->mt76.macaddr;
u32 val;
int i, k;
- if (!mt76x2_wait_for_mac(dev))
+ if (!mt76x02_wait_for_mac(&dev->mt76))
return -ETIMEDOUT;
val = mt76_rr(dev, MT_WPDMA_GLO_CFG);
@@ -160,14 +143,14 @@ static int mt76x2_mac_reset(struct mt76x2_dev *dev, bool hard)
mt76_wr(dev, MT_WCID_DROP_BASE + i * 4, 0);
for (i = 0; i < 256; i++)
- mt76x2_mac_wcid_setup(dev, i, 0, NULL);
+ mt76x02_mac_wcid_setup(dev, i, 0, NULL);
for (i = 0; i < MT_MAX_VIFS; i++)
- mt76x2_mac_wcid_setup(dev, MT_VIF_WCID(i), i, NULL);
+ mt76x02_mac_wcid_setup(dev, MT_VIF_WCID(i), i, NULL);
for (i = 0; i < 16; i++)
for (k = 0; k < 4; k++)
- mt76x2_mac_shared_key_setup(dev, i, k, NULL);
+ mt76x02_mac_shared_key_setup(dev, i, k, NULL);
for (i = 0; i < 8; i++) {
mt76x2_mac_set_bssid(dev, i, null_addr);
@@ -185,14 +168,14 @@ static int mt76x2_mac_reset(struct mt76x2_dev *dev, bool hard)
MT_CH_TIME_CFG_EIFS_AS_BUSY |
FIELD_PREP(MT_CH_TIME_CFG_CH_TIMER_CLR, 1));
- mt76x2_init_beacon_offsets(dev);
+ mt76x02_set_beacon_offsets(dev);
mt76x2_set_tx_ackto(dev);
return 0;
}
-int mt76x2_mac_start(struct mt76x2_dev *dev)
+int mt76x2_mac_start(struct mt76x02_dev *dev)
{
int i;
@@ -203,30 +186,12 @@ int mt76x2_mac_start(struct mt76x2_dev *dev)
mt76_rr(dev, MT_TX_STAT_FIFO);
memset(dev->aggr_stats, 0, sizeof(dev->aggr_stats));
-
- mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX);
- wait_for_wpdma(dev);
- usleep_range(50, 100);
-
- mt76_set(dev, MT_WPDMA_GLO_CFG,
- MT_WPDMA_GLO_CFG_TX_DMA_EN |
- MT_WPDMA_GLO_CFG_RX_DMA_EN);
-
- mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE);
-
- mt76_wr(dev, MT_RX_FILTR_CFG, dev->rxfilter);
-
- mt76_wr(dev, MT_MAC_SYS_CTRL,
- MT_MAC_SYS_CTRL_ENABLE_TX |
- MT_MAC_SYS_CTRL_ENABLE_RX);
-
- mt76x2_irq_enable(dev, MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL |
- MT_INT_TX_STAT);
+ mt76x02_mac_start(dev);
return 0;
}
-void mt76x2_mac_resume(struct mt76x2_dev *dev)
+void mt76x2_mac_resume(struct mt76x02_dev *dev)
{
mt76_wr(dev, MT_MAC_SYS_CTRL,
MT_MAC_SYS_CTRL_ENABLE_TX |
@@ -234,7 +199,7 @@ void mt76x2_mac_resume(struct mt76x2_dev *dev)
}
static void
-mt76x2_power_on_rf_patch(struct mt76x2_dev *dev)
+mt76x2_power_on_rf_patch(struct mt76x02_dev *dev)
{
mt76_set(dev, 0x10130, BIT(0) | BIT(16));
udelay(1);
@@ -255,7 +220,7 @@ mt76x2_power_on_rf_patch(struct mt76x2_dev *dev)
}
static void
-mt76x2_power_on_rf(struct mt76x2_dev *dev, int unit)
+mt76x2_power_on_rf(struct mt76x02_dev *dev, int unit)
{
int shift = unit ? 8 : 0;
@@ -277,7 +242,7 @@ mt76x2_power_on_rf(struct mt76x2_dev *dev, int unit)
}
static void
-mt76x2_power_on(struct mt76x2_dev *dev)
+mt76x2_power_on(struct mt76x02_dev *dev)
{
u32 val;
@@ -312,7 +277,7 @@ mt76x2_power_on(struct mt76x2_dev *dev)
mt76x2_power_on_rf(dev, 1);
}
-void mt76x2_set_tx_ackto(struct mt76x2_dev *dev)
+void mt76x2_set_tx_ackto(struct mt76x02_dev *dev)
{
u8 ackto, sifs, slottime = dev->slottime;
@@ -329,43 +294,14 @@ void mt76x2_set_tx_ackto(struct mt76x2_dev *dev)
MT_TX_TIMEOUT_CFG_ACKTO, ackto);
}
-int mt76x2_init_hardware(struct mt76x2_dev *dev)
+int mt76x2_init_hardware(struct mt76x02_dev *dev)
{
- static const u16 beacon_offsets[16] = {
- /* 1024 byte per beacon */
- 0xc000,
- 0xc400,
- 0xc800,
- 0xcc00,
- 0xd000,
- 0xd400,
- 0xd800,
- 0xdc00,
-
- /* BSS idx 8-15 not used for beacons */
- 0xc000,
- 0xc000,
- 0xc000,
- 0xc000,
- 0xc000,
- 0xc000,
- 0xc000,
- 0xc000,
- };
- u32 val;
int ret;
- dev->beacon_offsets = beacon_offsets;
tasklet_init(&dev->pre_tbtt_tasklet, mt76x2_pre_tbtt_tasklet,
(unsigned long) dev);
- val = mt76_rr(dev, MT_WPDMA_GLO_CFG);
- val &= MT_WPDMA_GLO_CFG_DMA_BURST_SIZE |
- MT_WPDMA_GLO_CFG_BIG_ENDIAN |
- MT_WPDMA_GLO_CFG_HDR_SEG_LEN;
- val |= MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE;
- mt76_wr(dev, MT_WPDMA_GLO_CFG, val);
-
+ mt76x02_dma_disable(dev);
mt76x2_reset_wlan(dev, true);
mt76x2_power_on(dev);
@@ -377,9 +313,9 @@ int mt76x2_init_hardware(struct mt76x2_dev *dev)
if (ret)
return ret;
- dev->rxfilter = mt76_rr(dev, MT_RX_FILTR_CFG);
+ dev->mt76.rxfilter = mt76_rr(dev, MT_RX_FILTR_CFG);
- ret = mt76x2_dma_init(dev);
+ ret = mt76x02_dma_init(dev);
if (ret)
return ret;
@@ -397,46 +333,44 @@ int mt76x2_init_hardware(struct mt76x2_dev *dev)
return 0;
}
-void mt76x2_stop_hardware(struct mt76x2_dev *dev)
+void mt76x2_stop_hardware(struct mt76x02_dev *dev)
{
cancel_delayed_work_sync(&dev->cal_work);
cancel_delayed_work_sync(&dev->mac_work);
- mt76x2_mcu_set_radio_state(dev, false);
+ mt76x02_mcu_set_radio_state(dev, false, true);
mt76x2_mac_stop(dev, false);
}
-void mt76x2_cleanup(struct mt76x2_dev *dev)
+void mt76x2_cleanup(struct mt76x02_dev *dev)
{
tasklet_disable(&dev->dfs_pd.dfs_tasklet);
tasklet_disable(&dev->pre_tbtt_tasklet);
mt76x2_stop_hardware(dev);
- mt76x2_dma_cleanup(dev);
- mt76x2_mcu_cleanup(dev);
+ mt76x02_dma_cleanup(dev);
+ mt76x02_mcu_cleanup(dev);
}
-struct mt76x2_dev *mt76x2_alloc_device(struct device *pdev)
+struct mt76x02_dev *mt76x2_alloc_device(struct device *pdev)
{
static const struct mt76_driver_ops drv_ops = {
- .txwi_size = sizeof(struct mt76x2_txwi),
+ .txwi_size = sizeof(struct mt76x02_txwi),
.update_survey = mt76x2_update_channel,
- .tx_prepare_skb = mt76x2_tx_prepare_skb,
- .tx_complete_skb = mt76x2_tx_complete_skb,
- .rx_skb = mt76x2_queue_rx_skb,
- .rx_poll_complete = mt76x2_rx_poll_complete,
+ .tx_prepare_skb = mt76x02_tx_prepare_skb,
+ .tx_complete_skb = mt76x02_tx_complete_skb,
+ .rx_skb = mt76x02_queue_rx_skb,
+ .rx_poll_complete = mt76x02_rx_poll_complete,
.sta_ps = mt76x2_sta_ps,
};
- struct mt76x2_dev *dev;
+ struct mt76x02_dev *dev;
struct mt76_dev *mdev;
mdev = mt76_alloc_device(sizeof(*dev), &mt76x2_ops);
if (!mdev)
return NULL;
- dev = container_of(mdev, struct mt76x2_dev, mt76);
+ dev = container_of(mdev, struct mt76x02_dev, mt76);
mdev->dev = pdev;
mdev->drv = &drv_ops;
- mutex_init(&dev->mutex);
- spin_lock_init(&dev->irq_lock);
return dev;
}
@@ -445,7 +379,7 @@ static void mt76x2_regd_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
{
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
- struct mt76x2_dev *dev = hw->priv;
+ struct mt76x02_dev *dev = hw->priv;
mt76x2_dfs_set_domain(dev, request->dfs_region);
}
@@ -481,8 +415,8 @@ static const struct ieee80211_iface_combination if_comb[] = {
static void mt76x2_led_set_config(struct mt76_dev *mt76, u8 delay_on,
u8 delay_off)
{
- struct mt76x2_dev *dev = container_of(mt76, struct mt76x2_dev,
- mt76);
+ struct mt76x02_dev *dev = container_of(mt76, struct mt76x02_dev,
+ mt76);
u32 val;
val = MT_LED_STATUS_DURATION(0xff) |
@@ -526,20 +460,12 @@ static void mt76x2_led_set_brightness(struct led_classdev *led_cdev,
mt76x2_led_set_config(mt76, 0xff, 0);
}
-int mt76x2_register_device(struct mt76x2_dev *dev)
+int mt76x2_register_device(struct mt76x02_dev *dev)
{
struct ieee80211_hw *hw = mt76_hw(dev);
struct wiphy *wiphy = hw->wiphy;
- void *status_fifo;
- int fifo_size;
int i, ret;
- fifo_size = roundup_pow_of_two(32 * sizeof(struct mt76x2_tx_status));
- status_fifo = devm_kzalloc(dev->mt76.dev, fifo_size, GFP_KERNEL);
- if (!status_fifo)
- return -ENOMEM;
-
- kfifo_init(&dev->txstatus_fifo, status_fifo, fifo_size);
INIT_DELAYED_WORK(&dev->cal_work, mt76x2_phy_calibrate);
INIT_DELAYED_WORK(&dev->mac_work, mt76x2_mac_work);
@@ -584,8 +510,8 @@ int mt76x2_register_device(struct mt76x2_dev *dev)
dev->mt76.led_cdev.brightness_set = mt76x2_led_set_brightness;
dev->mt76.led_cdev.blink_set = mt76x2_led_set_blink;
- ret = mt76_register_device(&dev->mt76, true, mt76x2_rates,
- ARRAY_SIZE(mt76x2_rates));
+ ret = mt76_register_device(&dev->mt76, true, mt76x02_rates,
+ ARRAY_SIZE(mt76x02_rates));
if (ret)
goto fail;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c
index 23cf437d14f9..4b331ed14bb2 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mac.c
@@ -16,11 +16,10 @@
#include <linux/delay.h>
#include "mt76x2.h"
-#include "mt76x2_mcu.h"
-#include "mt76x2_eeprom.h"
-#include "mt76x2_trace.h"
+#include "mcu.h"
+#include "eeprom.h"
-void mt76x2_mac_set_bssid(struct mt76x2_dev *dev, u8 idx, const u8 *addr)
+void mt76x2_mac_set_bssid(struct mt76x02_dev *dev, u8 idx, const u8 *addr)
{
idx &= 7;
mt76_wr(dev, MT_MAC_APC_BSSID_L(idx), get_unaligned_le32(addr));
@@ -28,84 +27,16 @@ void mt76x2_mac_set_bssid(struct mt76x2_dev *dev, u8 idx, const u8 *addr)
get_unaligned_le16(addr + 4));
}
-void mt76x2_mac_poll_tx_status(struct mt76x2_dev *dev, bool irq)
-{
- struct mt76x2_tx_status stat = {};
- unsigned long flags;
- u8 update = 1;
- bool ret;
-
- if (!test_bit(MT76_STATE_RUNNING, &dev->mt76.state))
- return;
-
- trace_mac_txstat_poll(dev);
-
- while (!irq || !kfifo_is_full(&dev->txstatus_fifo)) {
- spin_lock_irqsave(&dev->irq_lock, flags);
- ret = mt76x2_mac_load_tx_status(dev, &stat);
- spin_unlock_irqrestore(&dev->irq_lock, flags);
-
- if (!ret)
- break;
-
- trace_mac_txstat_fetch(dev, &stat);
-
- if (!irq) {
- mt76x2_send_tx_status(dev, &stat, &update);
- continue;
- }
-
- kfifo_put(&dev->txstatus_fifo, stat);
- }
-}
-
-static void
-mt76x2_mac_queue_txdone(struct mt76x2_dev *dev, struct sk_buff *skb,
- void *txwi_ptr)
-{
- struct mt76x2_tx_info *txi = mt76x2_skb_tx_info(skb);
- struct mt76x2_txwi *txwi = txwi_ptr;
-
- mt76x2_mac_poll_tx_status(dev, false);
-
- txi->tries = 0;
- txi->jiffies = jiffies;
- txi->wcid = txwi->wcid;
- txi->pktid = txwi->pktid;
- trace_mac_txdone_add(dev, txwi->wcid, txwi->pktid);
- mt76x2_tx_complete(dev, skb);
-}
-
-void mt76x2_mac_process_tx_status_fifo(struct mt76x2_dev *dev)
-{
- struct mt76x2_tx_status stat;
- u8 update = 1;
-
- while (kfifo_get(&dev->txstatus_fifo, &stat))
- mt76x2_send_tx_status(dev, &stat, &update);
-}
-
-void mt76x2_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q,
- struct mt76_queue_entry *e, bool flush)
-{
- struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76);
-
- if (e->txwi)
- mt76x2_mac_queue_txdone(dev, e->skb, &e->txwi->txwi);
- else
- dev_kfree_skb_any(e->skb);
-}
-
static int
-mt76_write_beacon(struct mt76x2_dev *dev, int offset, struct sk_buff *skb)
+mt76_write_beacon(struct mt76x02_dev *dev, int offset, struct sk_buff *skb)
{
- int beacon_len = dev->beacon_offsets[1] - dev->beacon_offsets[0];
- struct mt76x2_txwi txwi;
+ int beacon_len = mt76x02_beacon_offsets[1] - mt76x02_beacon_offsets[0];
+ struct mt76x02_txwi txwi;
- if (WARN_ON_ONCE(beacon_len < skb->len + sizeof(struct mt76x2_txwi)))
+ if (WARN_ON_ONCE(beacon_len < skb->len + sizeof(struct mt76x02_txwi)))
return -ENOSPC;
- mt76x2_mac_write_txwi(dev, &txwi, skb, NULL, NULL, skb->len);
+ mt76x02_mac_write_txwi(dev, &txwi, skb, NULL, NULL, skb->len);
mt76_wr_copy(dev, offset, &txwi, sizeof(txwi));
offset += sizeof(txwi);
@@ -115,10 +46,10 @@ mt76_write_beacon(struct mt76x2_dev *dev, int offset, struct sk_buff *skb)
}
static int
-__mt76x2_mac_set_beacon(struct mt76x2_dev *dev, u8 bcn_idx, struct sk_buff *skb)
+__mt76x2_mac_set_beacon(struct mt76x02_dev *dev, u8 bcn_idx, struct sk_buff *skb)
{
- int beacon_len = dev->beacon_offsets[1] - dev->beacon_offsets[0];
- int beacon_addr = dev->beacon_offsets[bcn_idx];
+ int beacon_len = mt76x02_beacon_offsets[1] - mt76x02_beacon_offsets[0];
+ int beacon_addr = mt76x02_beacon_offsets[bcn_idx];
int ret = 0;
int i;
@@ -128,8 +59,7 @@ __mt76x2_mac_set_beacon(struct mt76x2_dev *dev, u8 bcn_idx, struct sk_buff *skb)
if (skb) {
ret = mt76_write_beacon(dev, beacon_addr, skb);
if (!ret)
- dev->beacon_data_mask |= BIT(bcn_idx) &
- dev->beacon_mask;
+ dev->beacon_data_mask |= BIT(bcn_idx);
} else {
dev->beacon_data_mask &= ~BIT(bcn_idx);
for (i = 0; i < beacon_len; i += 4)
@@ -141,7 +71,7 @@ __mt76x2_mac_set_beacon(struct mt76x2_dev *dev, u8 bcn_idx, struct sk_buff *skb)
return ret;
}
-int mt76x2_mac_set_beacon(struct mt76x2_dev *dev, u8 vif_idx,
+int mt76x2_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx,
struct sk_buff *skb)
{
bool force_update = false;
@@ -176,7 +106,8 @@ int mt76x2_mac_set_beacon(struct mt76x2_dev *dev, u8 vif_idx,
return 0;
}
-void mt76x2_mac_set_beacon_enable(struct mt76x2_dev *dev, u8 vif_idx, bool val)
+void mt76x2_mac_set_beacon_enable(struct mt76x02_dev *dev,
+ u8 vif_idx, bool val)
{
u8 old_mask = dev->beacon_mask;
bool en;
@@ -201,14 +132,14 @@ void mt76x2_mac_set_beacon_enable(struct mt76x2_dev *dev, u8 vif_idx, bool val)
mt76_rmw(dev, MT_BEACON_TIME_CFG, reg, reg * en);
if (en)
- mt76x2_irq_enable(dev, MT_INT_PRE_TBTT | MT_INT_TBTT);
+ mt76x02_irq_enable(dev, MT_INT_PRE_TBTT | MT_INT_TBTT);
else
- mt76x2_irq_disable(dev, MT_INT_PRE_TBTT | MT_INT_TBTT);
+ mt76x02_irq_disable(dev, MT_INT_PRE_TBTT | MT_INT_TBTT);
}
void mt76x2_update_channel(struct mt76_dev *mdev)
{
- struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76);
+ struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
struct mt76_channel_state *state;
u32 active, busy;
@@ -225,8 +156,8 @@ void mt76x2_update_channel(struct mt76_dev *mdev)
void mt76x2_mac_work(struct work_struct *work)
{
- struct mt76x2_dev *dev = container_of(work, struct mt76x2_dev,
- mac_work.work);
+ struct mt76x02_dev *dev = container_of(work, struct mt76x02_dev,
+ mac_work.work);
int i, idx;
mt76x2_update_channel(&dev->mt76);
@@ -241,7 +172,7 @@ void mt76x2_mac_work(struct work_struct *work)
MT_CALIBRATE_INTERVAL);
}
-void mt76x2_mac_set_tx_protection(struct mt76x2_dev *dev, u32 val)
+void mt76x2_mac_set_tx_protection(struct mt76x02_dev *dev, u32 val)
{
u32 data = 0;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c
index 680a89f8aa87..034a06295668 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c
@@ -19,10 +19,10 @@
static int
mt76x2_start(struct ieee80211_hw *hw)
{
- struct mt76x2_dev *dev = hw->priv;
+ struct mt76x02_dev *dev = hw->priv;
int ret;
- mutex_lock(&dev->mutex);
+ mutex_lock(&dev->mt76.mutex);
ret = mt76x2_mac_start(dev);
if (ret)
@@ -38,57 +38,23 @@ mt76x2_start(struct ieee80211_hw *hw)
set_bit(MT76_STATE_RUNNING, &dev->mt76.state);
out:
- mutex_unlock(&dev->mutex);
+ mutex_unlock(&dev->mt76.mutex);
return ret;
}
static void
mt76x2_stop(struct ieee80211_hw *hw)
{
- struct mt76x2_dev *dev = hw->priv;
+ struct mt76x02_dev *dev = hw->priv;
- mutex_lock(&dev->mutex);
+ mutex_lock(&dev->mt76.mutex);
clear_bit(MT76_STATE_RUNNING, &dev->mt76.state);
mt76x2_stop_hardware(dev);
- mutex_unlock(&dev->mutex);
-}
-
-static int
-mt76x2_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
-{
- struct mt76x2_dev *dev = hw->priv;
- struct mt76x2_vif *mvif = (struct mt76x2_vif *) vif->drv_priv;
- unsigned int idx = 0;
-
- if (vif->addr[0] & BIT(1))
- idx = 1 + (((dev->mt76.macaddr[0] ^ vif->addr[0]) >> 2) & 7);
-
- /*
- * Client mode typically only has one configurable BSSID register,
- * which is used for bssidx=0. This is linked to the MAC address.
- * Since mac80211 allows changing interface types, and we cannot
- * force the use of the primary MAC address for a station mode
- * interface, we need some other way of configuring a per-interface
- * remote BSSID.
- * The hardware provides an AP-Client feature, where bssidx 0-7 are
- * used for AP mode and bssidx 8-15 for client mode.
- * We shift the station interface bss index by 8 to force the
- * hardware to recognize the BSSID.
- * The resulting bssidx mismatch for unicast frames is ignored by hw.
- */
- if (vif->type == NL80211_IFTYPE_STATION)
- idx += 8;
-
- mvif->idx = idx;
- mvif->group_wcid.idx = MT_VIF_WCID(idx);
- mvif->group_wcid.hw_key_idx = -1;
- mt76x2_txq_init(dev, vif->txq);
-
- return 0;
+ mutex_unlock(&dev->mt76.mutex);
}
static int
-mt76x2_set_channel(struct mt76x2_dev *dev, struct cfg80211_chan_def *chandef)
+mt76x2_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef)
{
int ret;
@@ -124,29 +90,29 @@ mt76x2_set_channel(struct mt76x2_dev *dev, struct cfg80211_chan_def *chandef)
static int
mt76x2_config(struct ieee80211_hw *hw, u32 changed)
{
- struct mt76x2_dev *dev = hw->priv;
+ struct mt76x02_dev *dev = hw->priv;
int ret = 0;
- mutex_lock(&dev->mutex);
+ mutex_lock(&dev->mt76.mutex);
if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
if (!(hw->conf.flags & IEEE80211_CONF_MONITOR))
- dev->rxfilter |= MT_RX_FILTR_CFG_PROMISC;
+ dev->mt76.rxfilter |= MT_RX_FILTR_CFG_PROMISC;
else
- dev->rxfilter &= ~MT_RX_FILTR_CFG_PROMISC;
+ dev->mt76.rxfilter &= ~MT_RX_FILTR_CFG_PROMISC;
- mt76_wr(dev, MT_RX_FILTR_CFG, dev->rxfilter);
+ mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter);
}
if (changed & IEEE80211_CONF_CHANGE_POWER) {
- dev->txpower_conf = hw->conf.power_level * 2;
+ dev->mt76.txpower_conf = hw->conf.power_level * 2;
/* convert to per-chain power for 2x2 devices */
- dev->txpower_conf -= 6;
+ dev->mt76.txpower_conf -= 6;
if (test_bit(MT76_STATE_RUNNING, &dev->mt76.state)) {
mt76x2_phy_set_txpower(dev);
- mt76x2_tx_set_txpwr_auto(dev, dev->txpower_conf);
+ mt76x02_tx_set_txpwr_auto(dev, dev->mt76.txpower_conf);
}
}
@@ -156,7 +122,7 @@ mt76x2_config(struct ieee80211_hw *hw, u32 changed)
ieee80211_wake_queues(hw);
}
- mutex_unlock(&dev->mutex);
+ mutex_unlock(&dev->mt76.mutex);
return ret;
}
@@ -165,10 +131,10 @@ static void
mt76x2_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *info, u32 changed)
{
- struct mt76x2_dev *dev = hw->priv;
- struct mt76x2_vif *mvif = (struct mt76x2_vif *) vif->drv_priv;
+ struct mt76x02_dev *dev = hw->priv;
+ struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv;
- mutex_lock(&dev->mutex);
+ mutex_lock(&dev->mt76.mutex);
if (changed & BSS_CHANGED_BSSID)
mt76x2_mac_set_bssid(dev, mvif->idx, info->bssid);
@@ -195,25 +161,25 @@ mt76x2_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
mt76x2_set_tx_ackto(dev);
}
- mutex_unlock(&dev->mutex);
+ mutex_unlock(&dev->mt76.mutex);
}
void
mt76x2_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps)
{
- struct mt76x2_sta *msta = (struct mt76x2_sta *) sta->drv_priv;
- struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76);
+ struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv;
+ struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
int idx = msta->wcid.idx;
mt76_stop_tx_queues(&dev->mt76, sta, true);
- mt76x2_mac_wcid_set_drop(dev, idx, ps);
+ mt76x02_mac_wcid_set_drop(dev, idx, ps);
}
static void
mt76x2_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
const u8 *mac)
{
- struct mt76x2_dev *dev = hw->priv;
+ struct mt76x02_dev *dev = hw->priv;
tasklet_disable(&dev->pre_tbtt_tasklet);
set_bit(MT76_SCANNING, &dev->mt76.state);
@@ -222,7 +188,7 @@ mt76x2_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
static void
mt76x2_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
- struct mt76x2_dev *dev = hw->priv;
+ struct mt76x02_dev *dev = hw->priv;
clear_bit(MT76_SCANNING, &dev->mt76.state);
tasklet_enable(&dev->pre_tbtt_tasklet);
@@ -237,9 +203,9 @@ mt76x2_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
static int
mt76x2_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int *dbm)
{
- struct mt76x2_dev *dev = hw->priv;
+ struct mt76x02_dev *dev = hw->priv;
- *dbm = dev->txpower_cur / 2;
+ *dbm = dev->mt76.txpower_cur / 2;
/* convert from per-chain power to combined output on 2x2 devices */
*dbm += 3;
@@ -250,12 +216,12 @@ mt76x2_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int *dbm)
static void mt76x2_set_coverage_class(struct ieee80211_hw *hw,
s16 coverage_class)
{
- struct mt76x2_dev *dev = hw->priv;
+ struct mt76x02_dev *dev = hw->priv;
- mutex_lock(&dev->mutex);
+ mutex_lock(&dev->mt76.mutex);
dev->coverage_class = coverage_class;
mt76x2_set_tx_ackto(dev);
- mutex_unlock(&dev->mutex);
+ mutex_unlock(&dev->mt76.mutex);
}
static int
@@ -267,20 +233,20 @@ mt76x2_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
static int mt76x2_set_antenna(struct ieee80211_hw *hw, u32 tx_ant,
u32 rx_ant)
{
- struct mt76x2_dev *dev = hw->priv;
+ struct mt76x02_dev *dev = hw->priv;
if (!tx_ant || tx_ant > 3 || tx_ant != rx_ant)
return -EINVAL;
- mutex_lock(&dev->mutex);
+ mutex_lock(&dev->mt76.mutex);
- dev->chainmask = (tx_ant == 3) ? 0x202 : 0x101;
+ dev->mt76.chainmask = (tx_ant == 3) ? 0x202 : 0x101;
dev->mt76.antenna_mask = tx_ant;
mt76_set_stream_caps(&dev->mt76, true);
mt76x2_phy_set_antenna(dev);
- mutex_unlock(&dev->mutex);
+ mutex_unlock(&dev->mt76.mutex);
return 0;
}
@@ -288,12 +254,12 @@ static int mt76x2_set_antenna(struct ieee80211_hw *hw, u32 tx_ant,
static int mt76x2_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant,
u32 *rx_ant)
{
- struct mt76x2_dev *dev = hw->priv;
+ struct mt76x02_dev *dev = hw->priv;
- mutex_lock(&dev->mutex);
+ mutex_lock(&dev->mt76.mutex);
*tx_ant = dev->mt76.antenna_mask;
*rx_ant = dev->mt76.antenna_mask;
- mutex_unlock(&dev->mutex);
+ mutex_unlock(&dev->mt76.mutex);
return 0;
}
@@ -301,7 +267,7 @@ static int mt76x2_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant,
static int
mt76x2_set_rts_threshold(struct ieee80211_hw *hw, u32 val)
{
- struct mt76x2_dev *dev = hw->priv;
+ struct mt76x02_dev *dev = hw->priv;
if (val != ~0 && val > 0xffff)
return -EINVAL;
@@ -314,25 +280,25 @@ mt76x2_set_rts_threshold(struct ieee80211_hw *hw, u32 val)
}
const struct ieee80211_ops mt76x2_ops = {
- .tx = mt76x2_tx,
+ .tx = mt76x02_tx,
.start = mt76x2_start,
.stop = mt76x2_stop,
- .add_interface = mt76x2_add_interface,
- .remove_interface = mt76x2_remove_interface,
+ .add_interface = mt76x02_add_interface,
+ .remove_interface = mt76x02_remove_interface,
.config = mt76x2_config,
- .configure_filter = mt76x2_configure_filter,
+ .configure_filter = mt76x02_configure_filter,
.bss_info_changed = mt76x2_bss_info_changed,
- .sta_add = mt76x2_sta_add,
- .sta_remove = mt76x2_sta_remove,
- .set_key = mt76x2_set_key,
- .conf_tx = mt76x2_conf_tx,
+ .sta_add = mt76x02_sta_add,
+ .sta_remove = mt76x02_sta_remove,
+ .set_key = mt76x02_set_key,
+ .conf_tx = mt76x02_conf_tx,
.sw_scan_start = mt76x2_sw_scan,
.sw_scan_complete = mt76x2_sw_scan_complete,
.flush = mt76x2_flush,
- .ampdu_action = mt76x2_ampdu_action,
+ .ampdu_action = mt76x02_ampdu_action,
.get_txpower = mt76x2_get_txpower,
.wake_tx_queue = mt76_wake_tx_queue,
- .sta_rate_tbl_update = mt76x2_sta_rate_tbl_update,
+ .sta_rate_tbl_update = mt76x02_sta_rate_tbl_update,
.release_buffered_frames = mt76_release_buffered_frames,
.set_coverage_class = mt76x2_set_coverage_class,
.get_survey = mt76_get_survey,
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mcu.c
new file mode 100644
index 000000000000..d8fa9ba56437
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mcu.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+
+#include "mt76x2.h"
+#include "mcu.h"
+#include "eeprom.h"
+
+static int
+mt76pci_load_rom_patch(struct mt76x02_dev *dev)
+{
+ const struct firmware *fw = NULL;
+ struct mt76x02_patch_header *hdr;
+ bool rom_protect = !is_mt7612(dev);
+ int len, ret = 0;
+ __le32 *cur;
+ u32 patch_mask, patch_reg;
+
+ if (rom_protect && !mt76_poll(dev, MT_MCU_SEMAPHORE_03, 1, 1, 600)) {
+ dev_err(dev->mt76.dev,
+ "Could not get hardware semaphore for ROM PATCH\n");
+ return -ETIMEDOUT;
+ }
+
+ if (mt76xx_rev(dev) >= MT76XX_REV_E3) {
+ patch_mask = BIT(0);
+ patch_reg = MT_MCU_CLOCK_CTL;
+ } else {
+ patch_mask = BIT(1);
+ patch_reg = MT_MCU_COM_REG0;
+ }
+
+ if (rom_protect && (mt76_rr(dev, patch_reg) & patch_mask)) {
+ dev_info(dev->mt76.dev, "ROM patch already applied\n");
+ goto out;
+ }
+
+ ret = request_firmware(&fw, MT7662_ROM_PATCH, dev->mt76.dev);
+ if (ret)
+ goto out;
+
+ if (!fw || !fw->data || fw->size <= sizeof(*hdr)) {
+ ret = -EIO;
+ dev_err(dev->mt76.dev, "Failed to load firmware\n");
+ goto out;
+ }
+
+ hdr = (struct mt76x02_patch_header *)fw->data;
+ dev_info(dev->mt76.dev, "ROM patch build: %.15s\n", hdr->build_time);
+
+ mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, MT_MCU_ROM_PATCH_OFFSET);
+
+ cur = (__le32 *) (fw->data + sizeof(*hdr));
+ len = fw->size - sizeof(*hdr);
+ mt76_wr_copy(dev, MT_MCU_ROM_PATCH_ADDR, cur, len);
+
+ mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, 0);
+
+ /* Trigger ROM */
+ mt76_wr(dev, MT_MCU_INT_LEVEL, 4);
+
+ if (!mt76_poll_msec(dev, patch_reg, patch_mask, patch_mask, 2000)) {
+ dev_err(dev->mt76.dev, "Failed to load ROM patch\n");
+ ret = -ETIMEDOUT;
+ }
+
+out:
+ /* release semaphore */
+ if (rom_protect)
+ mt76_wr(dev, MT_MCU_SEMAPHORE_03, 1);
+ release_firmware(fw);
+ return ret;
+}
+
+static int
+mt76pci_load_firmware(struct mt76x02_dev *dev)
+{
+ const struct firmware *fw;
+ const struct mt76x02_fw_header *hdr;
+ int len, ret;
+ __le32 *cur;
+ u32 offset, val;
+
+ ret = request_firmware(&fw, MT7662_FIRMWARE, dev->mt76.dev);
+ if (ret)
+ return ret;
+
+ if (!fw || !fw->data || fw->size < sizeof(*hdr))
+ goto error;
+
+ hdr = (const struct mt76x02_fw_header *)fw->data;
+
+ len = sizeof(*hdr);
+ len += le32_to_cpu(hdr->ilm_len);
+ len += le32_to_cpu(hdr->dlm_len);
+
+ if (fw->size != len)
+ goto error;
+
+ val = le16_to_cpu(hdr->fw_ver);
+ dev_info(dev->mt76.dev, "Firmware Version: %d.%d.%02d\n",
+ (val >> 12) & 0xf, (val >> 8) & 0xf, val & 0xf);
+
+ val = le16_to_cpu(hdr->build_ver);
+ dev_info(dev->mt76.dev, "Build: %x\n", val);
+ dev_info(dev->mt76.dev, "Build Time: %.16s\n", hdr->build_time);
+
+ cur = (__le32 *) (fw->data + sizeof(*hdr));
+ len = le32_to_cpu(hdr->ilm_len);
+
+ mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, MT_MCU_ILM_OFFSET);
+ mt76_wr_copy(dev, MT_MCU_ILM_ADDR, cur, len);
+
+ cur += len / sizeof(*cur);
+ len = le32_to_cpu(hdr->dlm_len);
+
+ if (mt76xx_rev(dev) >= MT76XX_REV_E3)
+ offset = MT_MCU_DLM_ADDR_E3;
+ else
+ offset = MT_MCU_DLM_ADDR;
+
+ mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, MT_MCU_DLM_OFFSET);
+ mt76_wr_copy(dev, offset, cur, len);
+
+ mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, 0);
+
+ val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_2);
+ if (FIELD_GET(MT_EE_NIC_CONF_2_XTAL_OPTION, val) == 1)
+ mt76_set(dev, MT_MCU_COM_REG0, BIT(30));
+
+ /* trigger firmware */
+ mt76_wr(dev, MT_MCU_INT_LEVEL, 2);
+ if (!mt76_poll_msec(dev, MT_MCU_COM_REG0, 1, 1, 200)) {
+ dev_err(dev->mt76.dev, "Firmware failed to start\n");
+ release_firmware(fw);
+ return -ETIMEDOUT;
+ }
+
+ mt76x02_set_ethtool_fwver(dev, hdr);
+ dev_info(dev->mt76.dev, "Firmware running!\n");
+
+ release_firmware(fw);
+
+ return ret;
+
+error:
+ dev_err(dev->mt76.dev, "Invalid firmware\n");
+ release_firmware(fw);
+ return -ENOENT;
+}
+
+int mt76x2_mcu_init(struct mt76x02_dev *dev)
+{
+ static const struct mt76_mcu_ops mt76x2_mcu_ops = {
+ .mcu_msg_alloc = mt76x02_mcu_msg_alloc,
+ .mcu_send_msg = mt76x02_mcu_msg_send,
+ };
+ int ret;
+
+ dev->mt76.mcu_ops = &mt76x2_mcu_ops;
+
+ ret = mt76pci_load_rom_patch(dev);
+ if (ret)
+ return ret;
+
+ ret = mt76pci_load_firmware(dev);
+ if (ret)
+ return ret;
+
+ mt76x02_mcu_function_select(dev, Q_SELECT, 1, true);
+ return 0;
+}
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c
index 84c96c0415b6..5bda44540225 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c
@@ -16,11 +16,12 @@
#include <linux/delay.h>
#include "mt76x2.h"
-#include "mt76x2_mcu.h"
-#include "mt76x2_eeprom.h"
+#include "mcu.h"
+#include "eeprom.h"
+#include "../mt76x02_phy.h"
static bool
-mt76x2_phy_tssi_init_cal(struct mt76x2_dev *dev)
+mt76x2_phy_tssi_init_cal(struct mt76x02_dev *dev)
{
struct ieee80211_channel *chan = dev->mt76.chandef.chan;
u32 flag = 0;
@@ -34,16 +35,16 @@ mt76x2_phy_tssi_init_cal(struct mt76x2_dev *dev)
if (chan->band == NL80211_BAND_5GHZ)
flag |= BIT(0);
- if (mt76x2_ext_pa_enabled(dev, chan->band))
+ if (mt76x02_ext_pa_enabled(dev, chan->band))
flag |= BIT(8);
- mt76x2_mcu_calibrate(dev, MCU_CAL_TSSI, flag);
+ mt76x02_mcu_calibrate(dev, MCU_CAL_TSSI, flag, true);
dev->cal.tssi_cal_done = true;
return true;
}
static void
-mt76x2_phy_channel_calibrate(struct mt76x2_dev *dev, bool mac_stopped)
+mt76x2_phy_channel_calibrate(struct mt76x02_dev *dev, bool mac_stopped)
{
struct ieee80211_channel *chan = dev->mt76.chandef.chan;
bool is_5ghz = chan->band == NL80211_BAND_5GHZ;
@@ -61,13 +62,13 @@ mt76x2_phy_channel_calibrate(struct mt76x2_dev *dev, bool mac_stopped)
mt76x2_mac_stop(dev, false);
if (is_5ghz)
- mt76x2_mcu_calibrate(dev, MCU_CAL_LC, 0);
+ mt76x02_mcu_calibrate(dev, MCU_CAL_LC, 0, true);
- mt76x2_mcu_calibrate(dev, MCU_CAL_TX_LOFT, is_5ghz);
- mt76x2_mcu_calibrate(dev, MCU_CAL_TXIQ, is_5ghz);
- mt76x2_mcu_calibrate(dev, MCU_CAL_RXIQC_FI, is_5ghz);
- mt76x2_mcu_calibrate(dev, MCU_CAL_TEMP_SENSOR, 0);
- mt76x2_mcu_calibrate(dev, MCU_CAL_TX_SHAPING, 0);
+ mt76x02_mcu_calibrate(dev, MCU_CAL_TX_LOFT, is_5ghz, true);
+ mt76x02_mcu_calibrate(dev, MCU_CAL_TXIQ, is_5ghz, true);
+ mt76x02_mcu_calibrate(dev, MCU_CAL_RXIQC_FI, is_5ghz, true);
+ mt76x02_mcu_calibrate(dev, MCU_CAL_TEMP_SENSOR, 0, true);
+ mt76x02_mcu_calibrate(dev, MCU_CAL_TX_SHAPING, 0, true);
if (!mac_stopped)
mt76x2_mac_resume(dev);
@@ -77,7 +78,7 @@ mt76x2_phy_channel_calibrate(struct mt76x2_dev *dev, bool mac_stopped)
dev->cal.channel_cal_done = true;
}
-void mt76x2_phy_set_antenna(struct mt76x2_dev *dev)
+void mt76x2_phy_set_antenna(struct mt76x02_dev *dev)
{
u32 val;
@@ -124,40 +125,7 @@ void mt76x2_phy_set_antenna(struct mt76x2_dev *dev)
}
static void
-mt76x2_get_agc_gain(struct mt76x2_dev *dev, u8 *dest)
-{
- dest[0] = mt76_get_field(dev, MT_BBP(AGC, 8), MT_BBP_AGC_GAIN);
- dest[1] = mt76_get_field(dev, MT_BBP(AGC, 9), MT_BBP_AGC_GAIN);
-}
-
-static int
-mt76x2_get_rssi_gain_thresh(struct mt76x2_dev *dev)
-{
- switch (dev->mt76.chandef.width) {
- case NL80211_CHAN_WIDTH_80:
- return -62;
- case NL80211_CHAN_WIDTH_40:
- return -65;
- default:
- return -68;
- }
-}
-
-static int
-mt76x2_get_low_rssi_gain_thresh(struct mt76x2_dev *dev)
-{
- switch (dev->mt76.chandef.width) {
- case NL80211_CHAN_WIDTH_80:
- return -76;
- case NL80211_CHAN_WIDTH_40:
- return -79;
- default:
- return -82;
- }
-}
-
-static void
-mt76x2_phy_set_gain_val(struct mt76x2_dev *dev)
+mt76x2_phy_set_gain_val(struct mt76x02_dev *dev)
{
u32 val;
u8 gain_val[2];
@@ -182,26 +150,7 @@ mt76x2_phy_set_gain_val(struct mt76x2_dev *dev)
}
static void
-mt76x2_phy_adjust_vga_gain(struct mt76x2_dev *dev)
-{
- u32 false_cca;
- u8 limit = dev->cal.low_gain > 0 ? 16 : 4;
-
- false_cca = FIELD_GET(MT_RX_STAT_1_CCA_ERRORS, mt76_rr(dev, MT_RX_STAT_1));
- dev->cal.false_cca = false_cca;
- if (false_cca > 800 && dev->cal.agc_gain_adjust < limit)
- dev->cal.agc_gain_adjust += 2;
- else if ((false_cca < 10 && dev->cal.agc_gain_adjust > 0) ||
- (dev->cal.agc_gain_adjust >= limit && false_cca < 500))
- dev->cal.agc_gain_adjust -= 2;
- else
- return;
-
- mt76x2_phy_set_gain_val(dev);
-}
-
-static void
-mt76x2_phy_update_channel_gain(struct mt76x2_dev *dev)
+mt76x2_phy_update_channel_gain(struct mt76x02_dev *dev)
{
u8 *gain = dev->cal.agc_gain_init;
u8 low_gain_delta, gain_delta;
@@ -209,16 +158,17 @@ mt76x2_phy_update_channel_gain(struct mt76x2_dev *dev)
int low_gain;
u32 val;
- dev->cal.avg_rssi_all = mt76x2_phy_get_min_avg_rssi(dev);
+ dev->cal.avg_rssi_all = mt76x02_phy_get_min_avg_rssi(dev);
- low_gain = (dev->cal.avg_rssi_all > mt76x2_get_rssi_gain_thresh(dev)) +
- (dev->cal.avg_rssi_all > mt76x2_get_low_rssi_gain_thresh(dev));
+ low_gain = (dev->cal.avg_rssi_all > mt76x02_get_rssi_gain_thresh(dev)) +
+ (dev->cal.avg_rssi_all > mt76x02_get_low_rssi_gain_thresh(dev));
gain_change = (dev->cal.low_gain & 2) ^ (low_gain & 2);
dev->cal.low_gain = low_gain;
if (!gain_change) {
- mt76x2_phy_adjust_vga_gain(dev);
+ if (mt76x02_phy_adjust_vga_gain(dev))
+ mt76x2_phy_set_gain_val(dev);
return;
}
@@ -264,7 +214,7 @@ mt76x2_phy_update_channel_gain(struct mt76x2_dev *dev)
mt76_rr(dev, MT_RX_STAT_1);
}
-int mt76x2_phy_set_channel(struct mt76x2_dev *dev,
+int mt76x2_phy_set_channel(struct mt76x02_dev *dev,
struct cfg80211_chan_def *chandef)
{
struct ieee80211_channel *chan = chandef->chan;
@@ -336,8 +286,8 @@ int mt76x2_phy_set_channel(struct mt76x2_dev *dev,
mt76x2_configure_tx_delay(dev, band, bw);
mt76x2_phy_set_txpower(dev);
- mt76x2_phy_set_band(dev, chan->band, ch_group_index & 1);
- mt76x2_phy_set_bw(dev, chandef->width, ch_group_index);
+ mt76x02_phy_set_band(dev, chan->band, ch_group_index & 1);
+ mt76x02_phy_set_bw(dev, chandef->width, ch_group_index);
mt76_rmw(dev, MT_EXT_CCA_CFG,
(MT_EXT_CCA_CFG_CCA0 |
@@ -360,17 +310,17 @@ int mt76x2_phy_set_channel(struct mt76x2_dev *dev,
mt76_set(dev, MT_BBP(RXO, 13), BIT(10));
if (!dev->cal.init_cal_done) {
- u8 val = mt76x2_eeprom_get(dev, MT_EE_BT_RCAL_RESULT);
+ u8 val = mt76x02_eeprom_get(dev, MT_EE_BT_RCAL_RESULT);
if (val != 0xff)
- mt76x2_mcu_calibrate(dev, MCU_CAL_R, 0);
+ mt76x02_mcu_calibrate(dev, MCU_CAL_R, 0, true);
}
- mt76x2_mcu_calibrate(dev, MCU_CAL_RXDCOC, channel);
+ mt76x02_mcu_calibrate(dev, MCU_CAL_RXDCOC, channel, true);
/* Rx LPF calibration */
if (!dev->cal.init_cal_done)
- mt76x2_mcu_calibrate(dev, MCU_CAL_RC, 0);
+ mt76x02_mcu_calibrate(dev, MCU_CAL_RC, 0, true);
dev->cal.init_cal_done = true;
@@ -383,11 +333,8 @@ int mt76x2_phy_set_channel(struct mt76x2_dev *dev,
if (scan)
return 0;
- dev->cal.low_gain = -1;
mt76x2_phy_channel_calibrate(dev, true);
- mt76x2_get_agc_gain(dev, dev->cal.agc_gain_init);
- memcpy(dev->cal.agc_gain_cur, dev->cal.agc_gain_init,
- sizeof(dev->cal.agc_gain_cur));
+ mt76x02_init_agc_gain(dev);
/* init default values for temp compensation */
if (mt76x2_tssi_enabled(dev)) {
@@ -404,48 +351,7 @@ int mt76x2_phy_set_channel(struct mt76x2_dev *dev,
}
static void
-mt76x2_phy_tssi_compensate(struct mt76x2_dev *dev)
-{
- struct ieee80211_channel *chan = dev->mt76.chandef.chan;
- struct mt76x2_tx_power_info txp;
- struct mt76x2_tssi_comp t = {};
-
- if (!dev->cal.tssi_cal_done)
- return;
-
- if (!dev->cal.tssi_comp_pending) {
- /* TSSI trigger */
- t.cal_mode = BIT(0);
- mt76x2_mcu_tssi_comp(dev, &t);
- dev->cal.tssi_comp_pending = true;
- } else {
- if (mt76_rr(dev, MT_BBP(CORE, 34)) & BIT(4))
- return;
-
- dev->cal.tssi_comp_pending = false;
- mt76x2_get_power_info(dev, &txp, chan);
-
- if (mt76x2_ext_pa_enabled(dev, chan->band))
- t.pa_mode = 1;
-
- t.cal_mode = BIT(1);
- t.slope0 = txp.chain[0].tssi_slope;
- t.offset0 = txp.chain[0].tssi_offset;
- t.slope1 = txp.chain[1].tssi_slope;
- t.offset1 = txp.chain[1].tssi_offset;
- mt76x2_mcu_tssi_comp(dev, &t);
-
- if (t.pa_mode || dev->cal.dpd_cal_done)
- return;
-
- usleep_range(10000, 20000);
- mt76x2_mcu_calibrate(dev, MCU_CAL_DPD, chan->hw_value);
- dev->cal.dpd_cal_done = true;
- }
-}
-
-static void
-mt76x2_phy_temp_compensate(struct mt76x2_dev *dev)
+mt76x2_phy_temp_compensate(struct mt76x02_dev *dev)
{
struct mt76x2_temp_comp t;
int temp, db_diff;
@@ -474,22 +380,22 @@ mt76x2_phy_temp_compensate(struct mt76x2_dev *dev)
void mt76x2_phy_calibrate(struct work_struct *work)
{
- struct mt76x2_dev *dev;
+ struct mt76x02_dev *dev;
- dev = container_of(work, struct mt76x2_dev, cal_work.work);
+ dev = container_of(work, struct mt76x02_dev, cal_work.work);
mt76x2_phy_channel_calibrate(dev, false);
- mt76x2_phy_tssi_compensate(dev);
+ mt76x2_phy_tssi_compensate(dev, true);
mt76x2_phy_temp_compensate(dev);
mt76x2_phy_update_channel_gain(dev);
ieee80211_queue_delayed_work(mt76_hw(dev), &dev->cal_work,
MT_CALIBRATE_INTERVAL);
}
-int mt76x2_phy_start(struct mt76x2_dev *dev)
+int mt76x2_phy_start(struct mt76x02_dev *dev)
{
int ret;
- ret = mt76x2_mcu_set_radio_state(dev, true);
+ ret = mt76x02_mcu_set_radio_state(dev, true, true);
if (ret)
return ret;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_tx.c
index 4c907882e8b0..3a2ec86d3e88 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_tx.c
@@ -15,50 +15,18 @@
*/
#include "mt76x2.h"
-#include "mt76x2_dma.h"
struct beacon_bc_data {
- struct mt76x2_dev *dev;
+ struct mt76x02_dev *dev;
struct sk_buff_head q;
struct sk_buff *tail[8];
};
-int mt76x2_tx_prepare_skb(struct mt76_dev *mdev, void *txwi,
- struct sk_buff *skb, struct mt76_queue *q,
- struct mt76_wcid *wcid, struct ieee80211_sta *sta,
- u32 *tx_info)
-{
- struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76);
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- int qsel = MT_QSEL_EDCA;
- int ret;
-
- if (q == &dev->mt76.q_tx[MT_TXQ_PSD] && wcid && wcid->idx < 128)
- mt76x2_mac_wcid_set_drop(dev, wcid->idx, false);
-
- mt76x2_mac_write_txwi(dev, txwi, skb, wcid, sta, skb->len);
-
- ret = mt76x2_insert_hdr_pad(skb);
- if (ret < 0)
- return ret;
-
- if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)
- qsel = MT_QSEL_MGMT;
-
- *tx_info = FIELD_PREP(MT_TXD_INFO_QSEL, qsel) |
- MT_TXD_INFO_80211;
-
- if (!wcid || wcid->hw_key_idx == 0xff || wcid->sw_iv)
- *tx_info |= MT_TXD_INFO_WIV;
-
- return 0;
-}
-
static void
mt76x2_update_beacon_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
{
- struct mt76x2_dev *dev = (struct mt76x2_dev *) priv;
- struct mt76x2_vif *mvif = (struct mt76x2_vif *) vif->drv_priv;
+ struct mt76x02_dev *dev = (struct mt76x02_dev *) priv;
+ struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv;
struct sk_buff *skb = NULL;
if (!(dev->beacon_mask & BIT(mvif->idx)))
@@ -75,8 +43,8 @@ static void
mt76x2_add_buffered_bc(void *priv, u8 *mac, struct ieee80211_vif *vif)
{
struct beacon_bc_data *data = priv;
- struct mt76x2_dev *dev = data->dev;
- struct mt76x2_vif *mvif = (struct mt76x2_vif *) vif->drv_priv;
+ struct mt76x02_dev *dev = data->dev;
+ struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv;
struct ieee80211_tx_info *info;
struct sk_buff *skb;
@@ -96,7 +64,7 @@ mt76x2_add_buffered_bc(void *priv, u8 *mac, struct ieee80211_vif *vif)
}
static void
-mt76x2_resync_beacon_timer(struct mt76x2_dev *dev)
+mt76x2_resync_beacon_timer(struct mt76x02_dev *dev)
{
u32 timer_val = dev->beacon_int << 4;
@@ -128,7 +96,7 @@ mt76x2_resync_beacon_timer(struct mt76x2_dev *dev)
void mt76x2_pre_tbtt_tasklet(unsigned long arg)
{
- struct mt76x2_dev *dev = (struct mt76x2_dev *) arg;
+ struct mt76x02_dev *dev = (struct mt76x02_dev *) arg;
struct mt76_queue *q = &dev->mt76.q_tx[MT_TXQ_PSD];
struct beacon_bc_data data = {};
struct sk_buff *skb;
@@ -164,7 +132,7 @@ void mt76x2_pre_tbtt_tasklet(unsigned long arg)
while ((skb = __skb_dequeue(&data.q)) != NULL) {
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_vif *vif = info->control.vif;
- struct mt76x2_vif *mvif = (struct mt76x2_vif *) vif->drv_priv;
+ struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv;
mt76_dma_tx_queue_skb(&dev->mt76, q, skb, &mvif->group_wcid,
NULL);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c
index 9fd6ab4cbb94..e9fff5b7f125 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_phy_common.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c
@@ -16,10 +16,12 @@
*/
#include "mt76x2.h"
-#include "mt76x2_eeprom.h"
+#include "eeprom.h"
+#include "mcu.h"
+#include "../mt76x02_phy.h"
static void
-mt76x2_adjust_high_lna_gain(struct mt76x2_dev *dev, int reg, s8 offset)
+mt76x2_adjust_high_lna_gain(struct mt76x02_dev *dev, int reg, s8 offset)
{
s8 gain;
@@ -29,7 +31,7 @@ mt76x2_adjust_high_lna_gain(struct mt76x2_dev *dev, int reg, s8 offset)
}
static void
-mt76x2_adjust_agc_gain(struct mt76x2_dev *dev, int reg, s8 offset)
+mt76x2_adjust_agc_gain(struct mt76x02_dev *dev, int reg, s8 offset)
{
s8 gain;
@@ -38,7 +40,7 @@ mt76x2_adjust_agc_gain(struct mt76x2_dev *dev, int reg, s8 offset)
mt76_rmw_field(dev, MT_BBP(AGC, reg), MT_BBP_AGC_GAIN, gain);
}
-void mt76x2_apply_gain_adj(struct mt76x2_dev *dev)
+void mt76x2_apply_gain_adj(struct mt76x02_dev *dev)
{
s8 *gain_adj = dev->cal.rx.high_gain;
@@ -50,7 +52,7 @@ void mt76x2_apply_gain_adj(struct mt76x2_dev *dev)
}
EXPORT_SYMBOL_GPL(mt76x2_apply_gain_adj);
-void mt76x2_phy_set_txpower_regs(struct mt76x2_dev *dev,
+void mt76x2_phy_set_txpower_regs(struct mt76x02_dev *dev,
enum nl80211_band band)
{
u32 pa_mode[2];
@@ -63,7 +65,7 @@ void mt76x2_phy_set_txpower_regs(struct mt76x2_dev *dev,
mt76_wr(dev, MT_TX_ALC_CFG_2, 0x35160a00);
mt76_wr(dev, MT_TX_ALC_CFG_3, 0x35160a06);
- if (mt76x2_ext_pa_enabled(dev, band)) {
+ if (mt76x02_ext_pa_enabled(dev, band)) {
mt76_wr(dev, MT_RF_PA_MODE_ADJ0, 0x0000ec00);
mt76_wr(dev, MT_RF_PA_MODE_ADJ1, 0x0000ec00);
} else {
@@ -74,7 +76,7 @@ void mt76x2_phy_set_txpower_regs(struct mt76x2_dev *dev,
pa_mode[0] = 0x0000ffff;
pa_mode[1] = 0x00ff00ff;
- if (mt76x2_ext_pa_enabled(dev, band)) {
+ if (mt76x02_ext_pa_enabled(dev, band)) {
mt76_wr(dev, MT_TX_ALC_CFG_2, 0x2f0f0400);
mt76_wr(dev, MT_TX_ALC_CFG_3, 0x2f0f0476);
} else {
@@ -82,7 +84,7 @@ void mt76x2_phy_set_txpower_regs(struct mt76x2_dev *dev,
mt76_wr(dev, MT_TX_ALC_CFG_3, 0x1b0f0476);
}
- if (mt76x2_ext_pa_enabled(dev, band))
+ if (mt76x02_ext_pa_enabled(dev, band))
pa_mode_adj = 0x04000000;
else
pa_mode_adj = 0;
@@ -96,7 +98,7 @@ void mt76x2_phy_set_txpower_regs(struct mt76x2_dev *dev,
mt76_wr(dev, MT_RF_PA_MODE_CFG0, pa_mode[0]);
mt76_wr(dev, MT_RF_PA_MODE_CFG1, pa_mode[1]);
- if (mt76x2_ext_pa_enabled(dev, band)) {
+ if (mt76x02_ext_pa_enabled(dev, band)) {
u32 val;
if (band == NL80211_BAND_2GHZ)
@@ -123,37 +125,6 @@ void mt76x2_phy_set_txpower_regs(struct mt76x2_dev *dev,
}
EXPORT_SYMBOL_GPL(mt76x2_phy_set_txpower_regs);
-static void
-mt76x2_limit_rate_power(struct mt76_rate_power *r, int limit)
-{
- int i;
-
- for (i = 0; i < sizeof(r->all); i++)
- if (r->all[i] > limit)
- r->all[i] = limit;
-}
-
-static u32
-mt76x2_tx_power_mask(u8 v1, u8 v2, u8 v3, u8 v4)
-{
- u32 val = 0;
-
- val |= (v1 & (BIT(6) - 1)) << 0;
- val |= (v2 & (BIT(6) - 1)) << 8;
- val |= (v3 & (BIT(6) - 1)) << 16;
- val |= (v4 & (BIT(6) - 1)) << 24;
- return val;
-}
-
-static void
-mt76x2_add_rate_power_offset(struct mt76_rate_power *r, int offset)
-{
- int i;
-
- for (i = 0; i < sizeof(r->all); i++)
- r->all[i] += offset;
-}
-
static int
mt76x2_get_min_rate_power(struct mt76_rate_power *r)
{
@@ -173,7 +144,7 @@ mt76x2_get_min_rate_power(struct mt76_rate_power *r)
return ret;
}
-void mt76x2_phy_set_txpower(struct mt76x2_dev *dev)
+void mt76x2_phy_set_txpower(struct mt76x02_dev *dev)
{
enum nl80211_chan_width width = dev->mt76.chandef.width;
struct ieee80211_channel *chan = dev->mt76.chandef.chan;
@@ -190,9 +161,9 @@ void mt76x2_phy_set_txpower(struct mt76x2_dev *dev)
delta = txp.delta_bw80;
mt76x2_get_rate_power(dev, &t, chan);
- mt76x2_add_rate_power_offset(&t, txp.chain[0].target_power);
- mt76x2_limit_rate_power(&t, dev->txpower_conf);
- dev->txpower_cur = mt76x2_get_max_rate_power(&t);
+ mt76x02_add_rate_power_offset(&t, txp.chain[0].target_power);
+ mt76x02_limit_rate_power(&t, dev->mt76.txpower_conf);
+ dev->mt76.txpower_cur = mt76x02_get_max_rate_power(&t);
base_power = mt76x2_get_min_rate_power(&t);
delta += base_power - txp.chain[0].target_power;
@@ -210,40 +181,22 @@ void mt76x2_phy_set_txpower(struct mt76x2_dev *dev)
txp_1 = 0x2f;
}
- mt76x2_add_rate_power_offset(&t, -base_power);
+ mt76x02_add_rate_power_offset(&t, -base_power);
dev->target_power = txp.chain[0].target_power;
dev->target_power_delta[0] = txp_0 - txp.chain[0].target_power;
dev->target_power_delta[1] = txp_1 - txp.chain[0].target_power;
- dev->rate_power = t;
-
- mt76_rmw_field(dev, MT_TX_ALC_CFG_0, MT_TX_ALC_CFG_0_CH_INIT_0, txp_0);
- mt76_rmw_field(dev, MT_TX_ALC_CFG_0, MT_TX_ALC_CFG_0_CH_INIT_1, txp_1);
-
- mt76_wr(dev, MT_TX_PWR_CFG_0,
- mt76x2_tx_power_mask(t.cck[0], t.cck[2], t.ofdm[0], t.ofdm[2]));
- mt76_wr(dev, MT_TX_PWR_CFG_1,
- mt76x2_tx_power_mask(t.ofdm[4], t.ofdm[6], t.ht[0], t.ht[2]));
- mt76_wr(dev, MT_TX_PWR_CFG_2,
- mt76x2_tx_power_mask(t.ht[4], t.ht[6], t.ht[8], t.ht[10]));
- mt76_wr(dev, MT_TX_PWR_CFG_3,
- mt76x2_tx_power_mask(t.ht[12], t.ht[14], t.ht[0], t.ht[2]));
- mt76_wr(dev, MT_TX_PWR_CFG_4,
- mt76x2_tx_power_mask(t.ht[4], t.ht[6], 0, 0));
- mt76_wr(dev, MT_TX_PWR_CFG_7,
- mt76x2_tx_power_mask(t.ofdm[6], t.vht[8], t.ht[6], t.vht[8]));
- mt76_wr(dev, MT_TX_PWR_CFG_8,
- mt76x2_tx_power_mask(t.ht[14], t.vht[8], t.vht[8], 0));
- mt76_wr(dev, MT_TX_PWR_CFG_9,
- mt76x2_tx_power_mask(t.ht[6], t.vht[8], t.vht[8], 0));
+ dev->mt76.rate_power = t;
+
+ mt76x02_phy_set_txpower(dev, txp_0, txp_1);
}
EXPORT_SYMBOL_GPL(mt76x2_phy_set_txpower);
-void mt76x2_configure_tx_delay(struct mt76x2_dev *dev,
+void mt76x2_configure_tx_delay(struct mt76x02_dev *dev,
enum nl80211_band band, u8 bw)
{
u32 cfg0, cfg1;
- if (mt76x2_ext_pa_enabled(dev, band)) {
+ if (mt76x02_ext_pa_enabled(dev, band)) {
cfg0 = bw ? 0x000b0c01 : 0x00101101;
cfg1 = 0x00011414;
} else {
@@ -257,93 +210,43 @@ void mt76x2_configure_tx_delay(struct mt76x2_dev *dev,
}
EXPORT_SYMBOL_GPL(mt76x2_configure_tx_delay);
-void mt76x2_phy_set_bw(struct mt76x2_dev *dev, int width, u8 ctrl)
+void mt76x2_phy_tssi_compensate(struct mt76x02_dev *dev, bool wait)
{
- int core_val, agc_val;
-
- switch (width) {
- case NL80211_CHAN_WIDTH_80:
- core_val = 3;
- agc_val = 7;
- break;
- case NL80211_CHAN_WIDTH_40:
- core_val = 2;
- agc_val = 3;
- break;
- default:
- core_val = 0;
- agc_val = 1;
- break;
- }
-
- mt76_rmw_field(dev, MT_BBP(CORE, 1), MT_BBP_CORE_R1_BW, core_val);
- mt76_rmw_field(dev, MT_BBP(AGC, 0), MT_BBP_AGC_R0_BW, agc_val);
- mt76_rmw_field(dev, MT_BBP(AGC, 0), MT_BBP_AGC_R0_CTRL_CHAN, ctrl);
- mt76_rmw_field(dev, MT_BBP(TXBE, 0), MT_BBP_TXBE_R0_CTRL_CHAN, ctrl);
-}
-EXPORT_SYMBOL_GPL(mt76x2_phy_set_bw);
-
-void mt76x2_phy_set_band(struct mt76x2_dev *dev, int band, bool primary_upper)
-{
- switch (band) {
- case NL80211_BAND_2GHZ:
- mt76_set(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_2G);
- mt76_clear(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_5G);
- break;
- case NL80211_BAND_5GHZ:
- mt76_clear(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_2G);
- mt76_set(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_5G);
- break;
- }
-
- mt76_rmw_field(dev, MT_TX_BAND_CFG, MT_TX_BAND_CFG_UPPER_40M,
- primary_upper);
-}
-EXPORT_SYMBOL_GPL(mt76x2_phy_set_band);
-
-int mt76x2_phy_get_min_avg_rssi(struct mt76x2_dev *dev)
-{
- struct mt76x2_sta *sta;
- struct mt76_wcid *wcid;
- int i, j, min_rssi = 0;
- s8 cur_rssi;
+ struct ieee80211_channel *chan = dev->mt76.chandef.chan;
+ struct mt76x2_tx_power_info txp;
+ struct mt76x2_tssi_comp t = {};
- local_bh_disable();
- rcu_read_lock();
+ if (!dev->cal.tssi_cal_done)
+ return;
- for (i = 0; i < ARRAY_SIZE(dev->wcid_mask); i++) {
- unsigned long mask = dev->wcid_mask[i];
+ if (!dev->cal.tssi_comp_pending) {
+ /* TSSI trigger */
+ t.cal_mode = BIT(0);
+ mt76x2_mcu_tssi_comp(dev, &t);
+ dev->cal.tssi_comp_pending = true;
+ } else {
+ if (mt76_rr(dev, MT_BBP(CORE, 34)) & BIT(4))
+ return;
- if (!mask)
- continue;
+ dev->cal.tssi_comp_pending = false;
+ mt76x2_get_power_info(dev, &txp, chan);
- for (j = i * BITS_PER_LONG; mask; j++, mask >>= 1) {
- if (!(mask & 1))
- continue;
+ if (mt76x02_ext_pa_enabled(dev, chan->band))
+ t.pa_mode = 1;
- wcid = rcu_dereference(dev->wcid[j]);
- if (!wcid)
- continue;
+ t.cal_mode = BIT(1);
+ t.slope0 = txp.chain[0].tssi_slope;
+ t.offset0 = txp.chain[0].tssi_offset;
+ t.slope1 = txp.chain[1].tssi_slope;
+ t.offset1 = txp.chain[1].tssi_offset;
+ mt76x2_mcu_tssi_comp(dev, &t);
- sta = container_of(wcid, struct mt76x2_sta, wcid);
- spin_lock(&dev->mt76.rx_lock);
- if (sta->inactive_count++ < 5)
- cur_rssi = ewma_signal_read(&sta->rssi);
- else
- cur_rssi = 0;
- spin_unlock(&dev->mt76.rx_lock);
+ if (t.pa_mode || dev->cal.dpd_cal_done)
+ return;
- if (cur_rssi < min_rssi)
- min_rssi = cur_rssi;
- }
+ usleep_range(10000, 20000);
+ mt76x02_mcu_calibrate(dev, MCU_CAL_DPD, chan->hw_value, wait);
+ dev->cal.dpd_cal_done = true;
}
-
- rcu_read_unlock();
- local_bh_enable();
-
- if (!min_rssi)
- return -75;
-
- return min_rssi;
}
-EXPORT_SYMBOL_GPL(mt76x2_phy_get_min_avg_rssi);
+EXPORT_SYMBOL_GPL(mt76x2_phy_tssi_compensate);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_usb.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c
index 1428cfdee579..57baf8d1c830 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c
@@ -17,9 +17,11 @@
#include <linux/kernel.h>
#include <linux/module.h>
+#include "../mt76x02_usb.h"
#include "mt76x2u.h"
static const struct usb_device_id mt76x2u_device_table[] = {
+ { USB_DEVICE(0x0e8d, 0x7612) }, /* Alfa AWUS036ACM */
{ USB_DEVICE(0x0b05, 0x1833) }, /* Asus USB-AC54 */
{ USB_DEVICE(0x0b05, 0x17eb) }, /* Asus USB-AC55 */
{ USB_DEVICE(0x0b05, 0x180b) }, /* Asus USB-N53 B1 */
@@ -35,7 +37,7 @@ static int mt76x2u_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_device *udev = interface_to_usbdev(intf);
- struct mt76x2_dev *dev;
+ struct mt76x02_dev *dev;
int err;
dev = mt76x2u_alloc_device(&intf->dev);
@@ -45,6 +47,7 @@ static int mt76x2u_probe(struct usb_interface *intf,
udev = usb_get_dev(udev);
usb_reset_device(udev);
+ mt76x02u_init_mcu(&dev->mt76);
err = mt76u_init(&dev->mt76, intf);
if (err < 0)
goto err;
@@ -69,7 +72,7 @@ err:
static void mt76x2u_disconnect(struct usb_interface *intf)
{
struct usb_device *udev = interface_to_usbdev(intf);
- struct mt76x2_dev *dev = usb_get_intfdata(intf);
+ struct mt76x02_dev *dev = usb_get_intfdata(intf);
struct ieee80211_hw *hw = mt76_hw(dev);
set_bit(MT76_REMOVED, &dev->mt76.state);
@@ -84,7 +87,7 @@ static void mt76x2u_disconnect(struct usb_interface *intf)
static int __maybe_unused mt76x2u_suspend(struct usb_interface *intf,
pm_message_t state)
{
- struct mt76x2_dev *dev = usb_get_intfdata(intf);
+ struct mt76x02_dev *dev = usb_get_intfdata(intf);
struct mt76_usb *usb = &dev->mt76.usb;
mt76u_stop_queues(&dev->mt76);
@@ -96,7 +99,7 @@ static int __maybe_unused mt76x2u_suspend(struct usb_interface *intf,
static int __maybe_unused mt76x2u_resume(struct usb_interface *intf)
{
- struct mt76x2_dev *dev = usb_get_intfdata(intf);
+ struct mt76x02_dev *dev = usb_get_intfdata(intf);
struct mt76_usb *usb = &dev->mt76.usb;
int err;
@@ -107,16 +110,24 @@ static int __maybe_unused mt76x2u_resume(struct usb_interface *intf)
mt76u_mcu_complete_urb,
&usb->mcu.cmpl);
if (err < 0)
- return err;
+ goto err;
err = mt76u_submit_rx_buffers(&dev->mt76);
if (err < 0)
- return err;
+ goto err;
tasklet_enable(&usb->rx_tasklet);
tasklet_enable(&usb->tx_tasklet);
- return mt76x2u_init_hardware(dev);
+ err = mt76x2u_init_hardware(dev);
+ if (err < 0)
+ goto err;
+
+ return 0;
+
+err:
+ mt76x2u_cleanup(dev);
+ return err;
}
MODULE_DEVICE_TABLE(usb, mt76x2u_device_table);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c
index 9b81e7641c06..13cce2937573 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2u_init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c
@@ -17,9 +17,11 @@
#include <linux/delay.h>
#include "mt76x2u.h"
-#include "mt76x2_eeprom.h"
+#include "eeprom.h"
+#include "../mt76x02_phy.h"
+#include "../mt76x02_usb.h"
-static void mt76x2u_init_dma(struct mt76x2_dev *dev)
+static void mt76x2u_init_dma(struct mt76x02_dev *dev)
{
u32 val = mt76_rr(dev, MT_VEND_ADDR(CFG, MT_USB_U3DMA_CFG));
@@ -34,7 +36,7 @@ static void mt76x2u_init_dma(struct mt76x2_dev *dev)
mt76_wr(dev, MT_VEND_ADDR(CFG, MT_USB_U3DMA_CFG), val);
}
-static void mt76x2u_power_on_rf_patch(struct mt76x2_dev *dev)
+static void mt76x2u_power_on_rf_patch(struct mt76x02_dev *dev)
{
mt76_set(dev, MT_VEND_ADDR(CFG, 0x130), BIT(0) | BIT(16));
udelay(1);
@@ -54,7 +56,7 @@ static void mt76x2u_power_on_rf_patch(struct mt76x2_dev *dev)
mt76_set(dev, MT_VEND_ADDR(CFG, 0x14c), BIT(19) | BIT(20));
}
-static void mt76x2u_power_on_rf(struct mt76x2_dev *dev, int unit)
+static void mt76x2u_power_on_rf(struct mt76x02_dev *dev, int unit)
{
int shift = unit ? 8 : 0;
u32 val = (BIT(1) | BIT(3) | BIT(4) | BIT(5)) << shift;
@@ -76,7 +78,7 @@ static void mt76x2u_power_on_rf(struct mt76x2_dev *dev, int unit)
mt76_set(dev, 0x530, 0xf);
}
-static void mt76x2u_power_on(struct mt76x2_dev *dev)
+static void mt76x2u_power_on(struct mt76x02_dev *dev)
{
u32 val;
@@ -112,7 +114,7 @@ static void mt76x2u_power_on(struct mt76x2_dev *dev)
mt76x2u_power_on_rf(dev, 1);
}
-static int mt76x2u_init_eeprom(struct mt76x2_dev *dev)
+static int mt76x2u_init_eeprom(struct mt76x02_dev *dev)
{
u32 val, i;
@@ -128,35 +130,33 @@ static int mt76x2u_init_eeprom(struct mt76x2_dev *dev)
put_unaligned_le32(val, dev->mt76.eeprom.data + i);
}
- mt76x2_eeprom_parse_hw_cap(dev);
+ mt76x02_eeprom_parse_hw_cap(dev);
return 0;
}
-struct mt76x2_dev *mt76x2u_alloc_device(struct device *pdev)
+struct mt76x02_dev *mt76x2u_alloc_device(struct device *pdev)
{
static const struct mt76_driver_ops drv_ops = {
- .tx_prepare_skb = mt76x2u_tx_prepare_skb,
- .tx_complete_skb = mt76x2u_tx_complete_skb,
- .tx_status_data = mt76x2u_tx_status_data,
- .rx_skb = mt76x2_queue_rx_skb,
+ .tx_prepare_skb = mt76x02u_tx_prepare_skb,
+ .tx_complete_skb = mt76x02u_tx_complete_skb,
+ .tx_status_data = mt76x02_tx_status_data,
+ .rx_skb = mt76x02_queue_rx_skb,
};
- struct mt76x2_dev *dev;
+ struct mt76x02_dev *dev;
struct mt76_dev *mdev;
mdev = mt76_alloc_device(sizeof(*dev), &mt76x2u_ops);
if (!mdev)
return NULL;
- dev = container_of(mdev, struct mt76x2_dev, mt76);
+ dev = container_of(mdev, struct mt76x02_dev, mt76);
mdev->dev = pdev;
mdev->drv = &drv_ops;
- mutex_init(&dev->mutex);
-
return dev;
}
-static void mt76x2u_init_beacon_offsets(struct mt76x2_dev *dev)
+static void mt76x2u_init_beacon_offsets(struct mt76x02_dev *dev)
{
mt76_wr(dev, MT_BCN_OFFSET(0), 0x18100800);
mt76_wr(dev, MT_BCN_OFFSET(1), 0x38302820);
@@ -164,27 +164,18 @@ static void mt76x2u_init_beacon_offsets(struct mt76x2_dev *dev)
mt76_wr(dev, MT_BCN_OFFSET(3), 0x78706860);
}
-int mt76x2u_init_hardware(struct mt76x2_dev *dev)
+int mt76x2u_init_hardware(struct mt76x02_dev *dev)
{
- static const u16 beacon_offsets[] = {
- /* 512 byte per beacon */
- 0xc000, 0xc200, 0xc400, 0xc600,
- 0xc800, 0xca00, 0xcc00, 0xce00,
- 0xd000, 0xd200, 0xd400, 0xd600,
- 0xd800, 0xda00, 0xdc00, 0xde00
- };
const struct mt76_wcid_addr addr = {
.macaddr = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
.ba_mask = 0,
};
int i, err;
- dev->beacon_offsets = beacon_offsets;
-
mt76x2_reset_wlan(dev, true);
mt76x2u_power_on(dev);
- if (!mt76x2_wait_for_mac(dev))
+ if (!mt76x02_wait_for_mac(&dev->mt76))
return -ETIMEDOUT;
err = mt76x2u_mcu_fw_init(dev);
@@ -197,7 +188,7 @@ int mt76x2u_init_hardware(struct mt76x2_dev *dev)
return -EIO;
/* wait for asic ready after fw load. */
- if (!mt76x2_wait_for_mac(dev))
+ if (!mt76x02_wait_for_mac(&dev->mt76))
return -ETIMEDOUT;
mt76_wr(dev, MT_HEADER_TRANS_CTRL_REG, 0);
@@ -213,12 +204,12 @@ int mt76x2u_init_hardware(struct mt76x2_dev *dev)
if (err < 0)
return err;
- mt76x2u_mac_setaddr(dev, dev->mt76.eeprom.data + MT_EE_MAC_ADDR);
- dev->rxfilter = mt76_rr(dev, MT_RX_FILTR_CFG);
+ mt76x02_mac_setaddr(dev, dev->mt76.eeprom.data + MT_EE_MAC_ADDR);
+ dev->mt76.rxfilter = mt76_rr(dev, MT_RX_FILTR_CFG);
mt76x2u_init_beacon_offsets(dev);
- if (!mt76x2_wait_for_bbp(dev))
+ if (!mt76x02_wait_for_txrx_idle(&dev->mt76))
return -ETIMEDOUT;
/* reset wcid table */
@@ -241,17 +232,17 @@ int mt76x2u_init_hardware(struct mt76x2_dev *dev)
mt76_rmw(dev, MT_US_CYC_CFG, MT_US_CYC_CNT, 0x1e);
mt76_wr(dev, MT_TXOP_CTRL_CFG, 0x583f);
- err = mt76x2u_mcu_load_cr(dev, MT_RF_BBP_CR, 0, 0);
+ err = mt76x2_mcu_load_cr(dev, MT_RF_BBP_CR, 0, 0);
if (err < 0)
return err;
- mt76x2u_phy_set_rxpath(dev);
- mt76x2u_phy_set_txdac(dev);
+ mt76x02_phy_set_rxpath(dev);
+ mt76x02_phy_set_txdac(dev);
return mt76x2u_mac_stop(dev);
}
-int mt76x2u_register_device(struct mt76x2_dev *dev)
+int mt76x2u_register_device(struct mt76x02_dev *dev)
{
struct ieee80211_hw *hw = mt76_hw(dev);
struct wiphy *wiphy = hw->wiphy;
@@ -264,11 +255,11 @@ int mt76x2u_register_device(struct mt76x2_dev *dev)
if (err < 0)
return err;
- err = mt76u_mcu_init_rx(&dev->mt76);
+ err = mt76u_alloc_queues(&dev->mt76);
if (err < 0)
- return err;
+ goto fail;
- err = mt76u_alloc_queues(&dev->mt76);
+ err = mt76u_mcu_init_rx(&dev->mt76);
if (err < 0)
goto fail;
@@ -278,8 +269,8 @@ int mt76x2u_register_device(struct mt76x2_dev *dev)
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
- err = mt76_register_device(&dev->mt76, true, mt76x2_rates,
- ARRAY_SIZE(mt76x2_rates));
+ err = mt76_register_device(&dev->mt76, true, mt76x02_rates,
+ ARRAY_SIZE(mt76x02_rates));
if (err)
goto fail;
@@ -302,17 +293,17 @@ fail:
return err;
}
-void mt76x2u_stop_hw(struct mt76x2_dev *dev)
+void mt76x2u_stop_hw(struct mt76x02_dev *dev)
{
mt76u_stop_stat_wk(&dev->mt76);
cancel_delayed_work_sync(&dev->cal_work);
mt76x2u_mac_stop(dev);
}
-void mt76x2u_cleanup(struct mt76x2_dev *dev)
+void mt76x2u_cleanup(struct mt76x02_dev *dev)
{
- mt76x2u_mcu_set_radio_state(dev, false);
+ mt76x02_mcu_set_radio_state(dev, false, false);
mt76x2u_stop_hw(dev);
mt76u_queues_deinit(&dev->mt76);
- mt76x2u_mcu_deinit(dev);
+ mt76u_mcu_deinit(&dev->mt76);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c
index eab7ab297aa6..db2194a92e67 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2u_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c
@@ -15,9 +15,9 @@
*/
#include "mt76x2u.h"
-#include "mt76x2_eeprom.h"
+#include "eeprom.h"
-static void mt76x2u_mac_reset_counters(struct mt76x2_dev *dev)
+static void mt76x2u_mac_reset_counters(struct mt76x02_dev *dev)
{
mt76_rr(dev, MT_RX_STAT_0);
mt76_rr(dev, MT_RX_STAT_1);
@@ -27,12 +27,12 @@ static void mt76x2u_mac_reset_counters(struct mt76x2_dev *dev)
mt76_rr(dev, MT_TX_STA_2);
}
-static void mt76x2u_mac_fixup_xtal(struct mt76x2_dev *dev)
+static void mt76x2u_mac_fixup_xtal(struct mt76x02_dev *dev)
{
s8 offset = 0;
u16 eep_val;
- eep_val = mt76x2_eeprom_get(dev, MT_EE_XTAL_TRIM_2);
+ eep_val = mt76x02_eeprom_get(dev, MT_EE_XTAL_TRIM_2);
offset = eep_val & 0x7f;
if ((eep_val & 0xff) == 0xff)
@@ -42,7 +42,7 @@ static void mt76x2u_mac_fixup_xtal(struct mt76x2_dev *dev)
eep_val >>= 8;
if (eep_val == 0x00 || eep_val == 0xff) {
- eep_val = mt76x2_eeprom_get(dev, MT_EE_XTAL_TRIM_1);
+ eep_val = mt76x02_eeprom_get(dev, MT_EE_XTAL_TRIM_1);
eep_val &= 0xff;
if (eep_val == 0x00 || eep_val == 0xff)
@@ -67,7 +67,7 @@ static void mt76x2u_mac_fixup_xtal(struct mt76x2_dev *dev)
/* init fce */
mt76_clear(dev, MT_FCE_L2_STUFF, MT_FCE_L2_STUFF_WR_MPDU_LEN_EN);
- eep_val = mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_2);
+ eep_val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_2);
switch (FIELD_GET(MT_EE_NIC_CONF_2_XTAL_OPTION, eep_val)) {
case 0:
mt76_wr(dev, MT_XO_CTRL7, 0x5c1fee80);
@@ -80,7 +80,7 @@ static void mt76x2u_mac_fixup_xtal(struct mt76x2_dev *dev)
}
}
-int mt76x2u_mac_reset(struct mt76x2_dev *dev)
+int mt76x2u_mac_reset(struct mt76x02_dev *dev)
{
mt76_wr(dev, MT_WPDMA_GLO_CFG, BIT(4) | BIT(5));
@@ -114,15 +114,15 @@ int mt76x2u_mac_reset(struct mt76x2_dev *dev)
return 0;
}
-int mt76x2u_mac_start(struct mt76x2_dev *dev)
+int mt76x2u_mac_start(struct mt76x02_dev *dev)
{
mt76x2u_mac_reset_counters(dev);
mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX);
- wait_for_wpdma(dev);
+ mt76x02_wait_for_wpdma(&dev->mt76, 1000);
usleep_range(50, 100);
- mt76_wr(dev, MT_RX_FILTR_CFG, dev->rxfilter);
+ mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter);
mt76_wr(dev, MT_MAC_SYS_CTRL,
MT_MAC_SYS_CTRL_ENABLE_TX |
@@ -131,7 +131,7 @@ int mt76x2u_mac_start(struct mt76x2_dev *dev)
return 0;
}
-int mt76x2u_mac_stop(struct mt76x2_dev *dev)
+int mt76x2u_mac_stop(struct mt76x02_dev *dev)
{
int i, count = 0, val;
bool stopped = false;
@@ -212,7 +212,7 @@ int mt76x2u_mac_stop(struct mt76x2_dev *dev)
return 0;
}
-void mt76x2u_mac_resume(struct mt76x2_dev *dev)
+void mt76x2u_mac_resume(struct mt76x02_dev *dev)
{
mt76_wr(dev, MT_MAC_SYS_CTRL,
MT_MAC_SYS_CTRL_ENABLE_TX |
@@ -220,21 +220,3 @@ void mt76x2u_mac_resume(struct mt76x2_dev *dev)
mt76_set(dev, MT_TXOP_CTRL_CFG, BIT(20));
mt76_set(dev, MT_TXOP_HLDR_ET, BIT(1));
}
-
-void mt76x2u_mac_setaddr(struct mt76x2_dev *dev, u8 *addr)
-{
- ether_addr_copy(dev->mt76.macaddr, addr);
-
- if (!is_valid_ether_addr(dev->mt76.macaddr)) {
- eth_random_addr(dev->mt76.macaddr);
- dev_info(dev->mt76.dev,
- "Invalid MAC address, using random address %pM\n",
- dev->mt76.macaddr);
- }
-
- mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dev->mt76.macaddr));
- mt76_wr(dev, MT_MAC_ADDR_DW1,
- get_unaligned_le16(dev->mt76.macaddr + 4) |
- FIELD_PREP(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff));
-}
-
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c
index 7367ba111119..1971a1b00038 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c
@@ -18,10 +18,10 @@
static int mt76x2u_start(struct ieee80211_hw *hw)
{
- struct mt76x2_dev *dev = hw->priv;
+ struct mt76x02_dev *dev = hw->priv;
int ret;
- mutex_lock(&dev->mutex);
+ mutex_lock(&dev->mt76.mutex);
ret = mt76x2u_mac_start(dev);
if (ret)
@@ -30,40 +30,34 @@ static int mt76x2u_start(struct ieee80211_hw *hw)
set_bit(MT76_STATE_RUNNING, &dev->mt76.state);
out:
- mutex_unlock(&dev->mutex);
+ mutex_unlock(&dev->mt76.mutex);
return ret;
}
static void mt76x2u_stop(struct ieee80211_hw *hw)
{
- struct mt76x2_dev *dev = hw->priv;
+ struct mt76x02_dev *dev = hw->priv;
- mutex_lock(&dev->mutex);
+ mutex_lock(&dev->mt76.mutex);
clear_bit(MT76_STATE_RUNNING, &dev->mt76.state);
mt76x2u_stop_hw(dev);
- mutex_unlock(&dev->mutex);
+ mutex_unlock(&dev->mt76.mutex);
}
static int mt76x2u_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
- struct mt76x2_dev *dev = hw->priv;
- struct mt76x2_vif *mvif = (struct mt76x2_vif *)vif->drv_priv;
- unsigned int idx = 0;
+ struct mt76x02_dev *dev = hw->priv;
if (!ether_addr_equal(dev->mt76.macaddr, vif->addr))
- mt76x2u_mac_setaddr(dev, vif->addr);
-
- mvif->idx = idx;
- mvif->group_wcid.idx = MT_VIF_WCID(idx);
- mvif->group_wcid.hw_key_idx = -1;
- mt76x2_txq_init(dev, vif->txq);
+ mt76x02_mac_setaddr(dev, vif->addr);
+ mt76x02_vif_init(dev, vif, 0);
return 0;
}
static int
-mt76x2u_set_channel(struct mt76x2_dev *dev,
+mt76x2u_set_channel(struct mt76x02_dev *dev,
struct cfg80211_chan_def *chandef)
{
int err;
@@ -91,9 +85,9 @@ static void
mt76x2u_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *info, u32 changed)
{
- struct mt76x2_dev *dev = hw->priv;
+ struct mt76x02_dev *dev = hw->priv;
- mutex_lock(&dev->mutex);
+ mutex_lock(&dev->mt76.mutex);
if (changed & BSS_CHANGED_ASSOC) {
mt76x2u_phy_channel_calibrate(dev);
@@ -107,23 +101,23 @@ mt76x2u_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
get_unaligned_le16(info->bssid + 4));
}
- mutex_unlock(&dev->mutex);
+ mutex_unlock(&dev->mt76.mutex);
}
static int
mt76x2u_config(struct ieee80211_hw *hw, u32 changed)
{
- struct mt76x2_dev *dev = hw->priv;
+ struct mt76x02_dev *dev = hw->priv;
int err = 0;
- mutex_lock(&dev->mutex);
+ mutex_lock(&dev->mt76.mutex);
if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
if (!(hw->conf.flags & IEEE80211_CONF_MONITOR))
- dev->rxfilter |= MT_RX_FILTR_CFG_PROMISC;
+ dev->mt76.rxfilter |= MT_RX_FILTR_CFG_PROMISC;
else
- dev->rxfilter &= ~MT_RX_FILTR_CFG_PROMISC;
- mt76_wr(dev, MT_RX_FILTR_CFG, dev->rxfilter);
+ dev->mt76.rxfilter &= ~MT_RX_FILTR_CFG_PROMISC;
+ mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter);
}
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
@@ -133,16 +127,16 @@ mt76x2u_config(struct ieee80211_hw *hw, u32 changed)
}
if (changed & IEEE80211_CONF_CHANGE_POWER) {
- dev->txpower_conf = hw->conf.power_level * 2;
+ dev->mt76.txpower_conf = hw->conf.power_level * 2;
/* convert to per-chain power for 2x2 devices */
- dev->txpower_conf -= 6;
+ dev->mt76.txpower_conf -= 6;
if (test_bit(MT76_STATE_RUNNING, &dev->mt76.state))
mt76x2_phy_set_txpower(dev);
}
- mutex_unlock(&dev->mutex);
+ mutex_unlock(&dev->mt76.mutex);
return err;
}
@@ -151,7 +145,7 @@ static void
mt76x2u_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
const u8 *mac)
{
- struct mt76x2_dev *dev = hw->priv;
+ struct mt76x02_dev *dev = hw->priv;
set_bit(MT76_SCANNING, &dev->mt76.state);
}
@@ -159,27 +153,27 @@ mt76x2u_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
static void
mt76x2u_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
- struct mt76x2_dev *dev = hw->priv;
+ struct mt76x02_dev *dev = hw->priv;
clear_bit(MT76_SCANNING, &dev->mt76.state);
}
const struct ieee80211_ops mt76x2u_ops = {
- .tx = mt76x2_tx,
+ .tx = mt76x02_tx,
.start = mt76x2u_start,
.stop = mt76x2u_stop,
.add_interface = mt76x2u_add_interface,
- .remove_interface = mt76x2_remove_interface,
- .sta_add = mt76x2_sta_add,
- .sta_remove = mt76x2_sta_remove,
- .set_key = mt76x2_set_key,
- .ampdu_action = mt76x2_ampdu_action,
+ .remove_interface = mt76x02_remove_interface,
+ .sta_add = mt76x02_sta_add,
+ .sta_remove = mt76x02_sta_remove,
+ .set_key = mt76x02_set_key,
+ .ampdu_action = mt76x02_ampdu_action,
.config = mt76x2u_config,
.wake_tx_queue = mt76_wake_tx_queue,
.bss_info_changed = mt76x2u_bss_info_changed,
- .configure_filter = mt76x2_configure_filter,
- .conf_tx = mt76x2_conf_tx,
+ .configure_filter = mt76x02_configure_filter,
+ .conf_tx = mt76x02_conf_tx,
.sw_scan_start = mt76x2u_sw_scan,
.sw_scan_complete = mt76x2u_sw_scan_complete,
- .sta_rate_tbl_update = mt76x2_sta_rate_tbl_update,
+ .sta_rate_tbl_update = mt76x02_sta_rate_tbl_update,
};
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mcu.c
index 22c16d638baa..3f1e558e5e6d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2u_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mcu.c
@@ -17,11 +17,10 @@
#include <linux/firmware.h>
#include "mt76x2u.h"
-#include "mt76x2_eeprom.h"
+#include "eeprom.h"
+#include "../mt76x02_usb.h"
#define MT_CMD_HDR_LEN 4
-#define MT_INBAND_PACKET_MAX_LEN 192
-#define MT_MCU_MEMMAP_WLAN 0x410000
#define MCU_FW_URB_MAX_PAYLOAD 0x3900
#define MCU_ROM_PATCH_MAX_PAYLOAD 2048
@@ -30,151 +29,7 @@
#define MT76U_MCU_DLM_OFFSET 0x110000
#define MT76U_MCU_ROM_PATCH_OFFSET 0x90000
-static int
-mt76x2u_mcu_function_select(struct mt76x2_dev *dev, enum mcu_function func,
- u32 val)
-{
- struct {
- __le32 id;
- __le32 value;
- } __packed __aligned(4) msg = {
- .id = cpu_to_le32(func),
- .value = cpu_to_le32(val),
- };
- struct sk_buff *skb;
-
- skb = mt76u_mcu_msg_alloc(&msg, sizeof(msg));
- if (!skb)
- return -ENOMEM;
- return mt76u_mcu_send_msg(&dev->mt76, skb, CMD_FUN_SET_OP,
- func != Q_SELECT);
-}
-
-int mt76x2u_mcu_set_radio_state(struct mt76x2_dev *dev, bool val)
-{
- struct {
- __le32 mode;
- __le32 level;
- } __packed __aligned(4) msg = {
- .mode = cpu_to_le32(val ? RADIO_ON : RADIO_OFF),
- .level = cpu_to_le32(0),
- };
- struct sk_buff *skb;
-
- skb = mt76u_mcu_msg_alloc(&msg, sizeof(msg));
- if (!skb)
- return -ENOMEM;
- return mt76u_mcu_send_msg(&dev->mt76, skb, CMD_POWER_SAVING_OP,
- false);
-}
-
-int mt76x2u_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level,
- u8 channel)
-{
- struct {
- u8 cr_mode;
- u8 temp;
- u8 ch;
- u8 _pad0;
- __le32 cfg;
- } __packed __aligned(4) msg = {
- .cr_mode = type,
- .temp = temp_level,
- .ch = channel,
- };
- struct sk_buff *skb;
- u32 val;
-
- val = BIT(31);
- val |= (mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_0) >> 8) & 0x00ff;
- val |= (mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_1) << 8) & 0xff00;
- msg.cfg = cpu_to_le32(val);
-
- /* first set the channel without the extension channel info */
- skb = mt76u_mcu_msg_alloc(&msg, sizeof(msg));
- if (!skb)
- return -ENOMEM;
- return mt76u_mcu_send_msg(&dev->mt76, skb, CMD_LOAD_CR, true);
-}
-
-int mt76x2u_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw,
- u8 bw_index, bool scan)
-{
- struct {
- u8 idx;
- u8 scan;
- u8 bw;
- u8 _pad0;
-
- __le16 chainmask;
- u8 ext_chan;
- u8 _pad1;
-
- } __packed __aligned(4) msg = {
- .idx = channel,
- .scan = scan,
- .bw = bw,
- .chainmask = cpu_to_le16(dev->chainmask),
- };
- struct sk_buff *skb;
-
- /* first set the channel without the extension channel info */
- skb = mt76u_mcu_msg_alloc(&msg, sizeof(msg));
- if (!skb)
- return -ENOMEM;
-
- mt76u_mcu_send_msg(&dev->mt76, skb, CMD_SWITCH_CHANNEL_OP, true);
-
- usleep_range(5000, 10000);
-
- msg.ext_chan = 0xe0 + bw_index;
- skb = mt76u_mcu_msg_alloc(&msg, sizeof(msg));
- if (!skb)
- return -ENOMEM;
-
- return mt76u_mcu_send_msg(&dev->mt76, skb, CMD_SWITCH_CHANNEL_OP, true);
-}
-
-int mt76x2u_mcu_calibrate(struct mt76x2_dev *dev, enum mcu_calibration type,
- u32 val)
-{
- struct {
- __le32 id;
- __le32 value;
- } __packed __aligned(4) msg = {
- .id = cpu_to_le32(type),
- .value = cpu_to_le32(val),
- };
- struct sk_buff *skb;
-
- skb = mt76u_mcu_msg_alloc(&msg, sizeof(msg));
- if (!skb)
- return -ENOMEM;
- return mt76u_mcu_send_msg(&dev->mt76, skb, CMD_CALIBRATION_OP, true);
-}
-
-int mt76x2u_mcu_init_gain(struct mt76x2_dev *dev, u8 channel, u32 gain,
- bool force)
-{
- struct {
- __le32 channel;
- __le32 gain_val;
- } __packed __aligned(4) msg = {
- .channel = cpu_to_le32(channel),
- .gain_val = cpu_to_le32(gain),
- };
- struct sk_buff *skb;
-
- if (force)
- msg.channel |= cpu_to_le32(BIT(31));
-
- skb = mt76u_mcu_msg_alloc(&msg, sizeof(msg));
- if (!skb)
- return -ENOMEM;
- return mt76u_mcu_send_msg(&dev->mt76, skb, CMD_INIT_GAIN_OP, true);
-}
-
-int mt76x2u_mcu_set_dynamic_vga(struct mt76x2_dev *dev, u8 channel, bool ap,
+int mt76x2u_mcu_set_dynamic_vga(struct mt76x02_dev *dev, u8 channel, bool ap,
bool ext, int rssi, u32 false_cca)
{
struct {
@@ -194,38 +49,18 @@ int mt76x2u_mcu_set_dynamic_vga(struct mt76x2_dev *dev, u8 channel, bool ap,
val |= BIT(30);
msg.channel = cpu_to_le32(val);
- skb = mt76u_mcu_msg_alloc(&msg, sizeof(msg));
- if (!skb)
- return -ENOMEM;
- return mt76u_mcu_send_msg(&dev->mt76, skb, CMD_DYNC_VGA_OP, true);
+ skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg));
+ return mt76_mcu_send_msg(dev, skb, CMD_DYNC_VGA_OP, true);
}
-int mt76x2u_mcu_tssi_comp(struct mt76x2_dev *dev,
- struct mt76x2_tssi_comp *tssi_data)
-{
- struct {
- __le32 id;
- struct mt76x2_tssi_comp data;
- } __packed __aligned(4) msg = {
- .id = cpu_to_le32(MCU_CAL_TSSI_COMP),
- .data = *tssi_data,
- };
- struct sk_buff *skb;
-
- skb = mt76u_mcu_msg_alloc(&msg, sizeof(msg));
- if (!skb)
- return -ENOMEM;
- return mt76u_mcu_send_msg(&dev->mt76, skb, CMD_CALIBRATION_OP, true);
-}
-
-static void mt76x2u_mcu_load_ivb(struct mt76x2_dev *dev)
+static void mt76x2u_mcu_load_ivb(struct mt76x02_dev *dev)
{
mt76u_vendor_request(&dev->mt76, MT_VEND_DEV_MODE,
USB_DIR_OUT | USB_TYPE_VENDOR,
0x12, 0, NULL, 0);
}
-static void mt76x2u_mcu_enable_patch(struct mt76x2_dev *dev)
+static void mt76x2u_mcu_enable_patch(struct mt76x02_dev *dev)
{
struct mt76_usb *usb = &dev->mt76.usb;
const u8 data[] = {
@@ -240,7 +75,7 @@ static void mt76x2u_mcu_enable_patch(struct mt76x2_dev *dev)
0x12, 0, usb->data, sizeof(data));
}
-static void mt76x2u_mcu_reset_wmt(struct mt76x2_dev *dev)
+static void mt76x2u_mcu_reset_wmt(struct mt76x02_dev *dev)
{
struct mt76_usb *usb = &dev->mt76.usb;
u8 data[] = {
@@ -254,10 +89,10 @@ static void mt76x2u_mcu_reset_wmt(struct mt76x2_dev *dev)
0x12, 0, usb->data, sizeof(data));
}
-static int mt76x2u_mcu_load_rom_patch(struct mt76x2_dev *dev)
+static int mt76x2u_mcu_load_rom_patch(struct mt76x02_dev *dev)
{
bool rom_protect = !is_mt7612(dev);
- struct mt76x2_patch_header *hdr;
+ struct mt76x02_patch_header *hdr;
u32 val, patch_mask, patch_reg;
const struct firmware *fw;
int err;
@@ -292,7 +127,7 @@ static int mt76x2u_mcu_load_rom_patch(struct mt76x2_dev *dev)
goto out;
}
- hdr = (struct mt76x2_patch_header *)fw->data;
+ hdr = (struct mt76x02_patch_header *)fw->data;
dev_info(dev->mt76.dev, "ROM patch build: %.15s\n", hdr->build_time);
/* enable USB_DMA_CFG */
@@ -302,7 +137,7 @@ static int mt76x2u_mcu_load_rom_patch(struct mt76x2_dev *dev)
mt76_wr(dev, MT_VEND_ADDR(CFG, MT_USB_U3DMA_CFG), val);
/* vendor reset */
- mt76u_mcu_fw_reset(&dev->mt76);
+ mt76x02u_mcu_fw_reset(dev);
usleep_range(5000, 10000);
/* enable FCE to send in-band cmd */
@@ -316,10 +151,10 @@ static int mt76x2u_mcu_load_rom_patch(struct mt76x2_dev *dev)
/* FCE skip_fs_en */
mt76_wr(dev, MT_FCE_SKIP_FS, 0x3);
- err = mt76u_mcu_fw_send_data(&dev->mt76, fw->data + sizeof(*hdr),
- fw->size - sizeof(*hdr),
- MCU_ROM_PATCH_MAX_PAYLOAD,
- MT76U_MCU_ROM_PATCH_OFFSET);
+ err = mt76x02u_mcu_fw_send_data(dev, fw->data + sizeof(*hdr),
+ fw->size - sizeof(*hdr),
+ MCU_ROM_PATCH_MAX_PAYLOAD,
+ MT76U_MCU_ROM_PATCH_OFFSET);
if (err < 0) {
err = -EIO;
goto out;
@@ -341,10 +176,10 @@ out:
return err;
}
-static int mt76x2u_mcu_load_firmware(struct mt76x2_dev *dev)
+static int mt76x2u_mcu_load_firmware(struct mt76x02_dev *dev)
{
u32 val, dlm_offset = MT76U_MCU_DLM_OFFSET;
- const struct mt76x2_fw_header *hdr;
+ const struct mt76x02_fw_header *hdr;
int err, len, ilm_len, dlm_len;
const struct firmware *fw;
@@ -357,7 +192,7 @@ static int mt76x2u_mcu_load_firmware(struct mt76x2_dev *dev)
goto out;
}
- hdr = (const struct mt76x2_fw_header *)fw->data;
+ hdr = (const struct mt76x02_fw_header *)fw->data;
ilm_len = le32_to_cpu(hdr->ilm_len);
dlm_len = le32_to_cpu(hdr->dlm_len);
len = sizeof(*hdr) + ilm_len + dlm_len;
@@ -375,7 +210,7 @@ static int mt76x2u_mcu_load_firmware(struct mt76x2_dev *dev)
dev_info(dev->mt76.dev, "Build Time: %.16s\n", hdr->build_time);
/* vendor reset */
- mt76u_mcu_fw_reset(&dev->mt76);
+ mt76x02u_mcu_fw_reset(dev);
usleep_range(5000, 10000);
/* enable USB_DMA_CFG */
@@ -395,9 +230,9 @@ static int mt76x2u_mcu_load_firmware(struct mt76x2_dev *dev)
mt76_wr(dev, MT_FCE_SKIP_FS, 0x3);
/* load ILM */
- err = mt76u_mcu_fw_send_data(&dev->mt76, fw->data + sizeof(*hdr),
- ilm_len, MCU_FW_URB_MAX_PAYLOAD,
- MT76U_MCU_ILM_OFFSET);
+ err = mt76x02u_mcu_fw_send_data(dev, fw->data + sizeof(*hdr),
+ ilm_len, MCU_FW_URB_MAX_PAYLOAD,
+ MT76U_MCU_ILM_OFFSET);
if (err < 0) {
err = -EIO;
goto out;
@@ -406,10 +241,9 @@ static int mt76x2u_mcu_load_firmware(struct mt76x2_dev *dev)
/* load DLM */
if (mt76xx_rev(dev) >= MT76XX_REV_E3)
dlm_offset += 0x800;
- err = mt76u_mcu_fw_send_data(&dev->mt76,
- fw->data + sizeof(*hdr) + ilm_len,
- dlm_len, MCU_FW_URB_MAX_PAYLOAD,
- dlm_offset);
+ err = mt76x02u_mcu_fw_send_data(dev, fw->data + sizeof(*hdr) + ilm_len,
+ dlm_len, MCU_FW_URB_MAX_PAYLOAD,
+ dlm_offset);
if (err < 0) {
err = -EIO;
goto out;
@@ -425,6 +259,7 @@ static int mt76x2u_mcu_load_firmware(struct mt76x2_dev *dev)
mt76_set(dev, MT_MCU_COM_REG0, BIT(1));
/* enable FCE to send in-band cmd */
mt76_wr(dev, MT_FCE_PSE_CTRL, 0x1);
+ mt76x02_set_ethtool_fwver(dev, hdr);
dev_dbg(dev->mt76.dev, "firmware running\n");
out:
@@ -432,7 +267,7 @@ out:
return err;
}
-int mt76x2u_mcu_fw_init(struct mt76x2_dev *dev)
+int mt76x2u_mcu_fw_init(struct mt76x02_dev *dev)
{
int err;
@@ -443,21 +278,13 @@ int mt76x2u_mcu_fw_init(struct mt76x2_dev *dev)
return mt76x2u_mcu_load_firmware(dev);
}
-int mt76x2u_mcu_init(struct mt76x2_dev *dev)
+int mt76x2u_mcu_init(struct mt76x02_dev *dev)
{
int err;
- err = mt76x2u_mcu_function_select(dev, Q_SELECT, 1);
+ err = mt76x02_mcu_function_select(dev, Q_SELECT, 1, false);
if (err < 0)
return err;
- return mt76x2u_mcu_set_radio_state(dev, true);
-}
-
-void mt76x2u_mcu_deinit(struct mt76x2_dev *dev)
-{
- struct mt76_usb *usb = &dev->mt76.usb;
-
- usb_kill_urb(usb->mcu.res.urb);
- mt76u_buf_free(&usb->mcu.res);
+ return mt76x02_mcu_set_radio_state(dev, true, false);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c
index 5158063d0c2e..ca96ba60510e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2u_phy.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c
@@ -15,42 +15,10 @@
*/
#include "mt76x2u.h"
-#include "mt76x2_eeprom.h"
+#include "eeprom.h"
+#include "../mt76x02_phy.h"
-void mt76x2u_phy_set_rxpath(struct mt76x2_dev *dev)
-{
- u32 val;
-
- val = mt76_rr(dev, MT_BBP(AGC, 0));
- val &= ~BIT(4);
-
- switch (dev->chainmask & 0xf) {
- case 2:
- val |= BIT(3);
- break;
- default:
- val &= ~BIT(3);
- break;
- }
- mt76_wr(dev, MT_BBP(AGC, 0), val);
-}
-
-void mt76x2u_phy_set_txdac(struct mt76x2_dev *dev)
-{
- int txpath;
-
- txpath = (dev->chainmask >> 8) & 0xf;
- switch (txpath) {
- case 2:
- mt76_set(dev, MT_BBP(TXBE, 5), 0x3);
- break;
- default:
- mt76_clear(dev, MT_BBP(TXBE, 5), 0x3);
- break;
- }
-}
-
-void mt76x2u_phy_channel_calibrate(struct mt76x2_dev *dev)
+void mt76x2u_phy_channel_calibrate(struct mt76x02_dev *dev)
{
struct ieee80211_channel *chan = dev->mt76.chandef.chan;
bool is_5ghz = chan->band == NL80211_BAND_5GHZ;
@@ -61,59 +29,18 @@ void mt76x2u_phy_channel_calibrate(struct mt76x2_dev *dev)
mt76x2u_mac_stop(dev);
if (is_5ghz)
- mt76x2u_mcu_calibrate(dev, MCU_CAL_LC, 0);
+ mt76x02_mcu_calibrate(dev, MCU_CAL_LC, 0, false);
- mt76x2u_mcu_calibrate(dev, MCU_CAL_TX_LOFT, is_5ghz);
- mt76x2u_mcu_calibrate(dev, MCU_CAL_TXIQ, is_5ghz);
- mt76x2u_mcu_calibrate(dev, MCU_CAL_RXIQC_FI, is_5ghz);
- mt76x2u_mcu_calibrate(dev, MCU_CAL_TEMP_SENSOR, 0);
+ mt76x02_mcu_calibrate(dev, MCU_CAL_TX_LOFT, is_5ghz, false);
+ mt76x02_mcu_calibrate(dev, MCU_CAL_TXIQ, is_5ghz, false);
+ mt76x02_mcu_calibrate(dev, MCU_CAL_RXIQC_FI, is_5ghz, false);
+ mt76x02_mcu_calibrate(dev, MCU_CAL_TEMP_SENSOR, 0, false);
mt76x2u_mac_resume(dev);
}
static void
-mt76x2u_phy_tssi_compensate(struct mt76x2_dev *dev)
-{
- struct ieee80211_channel *chan = dev->mt76.chandef.chan;
- struct mt76x2_tx_power_info txp;
- struct mt76x2_tssi_comp t = {};
-
- if (!dev->cal.tssi_cal_done)
- return;
-
- if (!dev->cal.tssi_comp_pending) {
- /* TSSI trigger */
- t.cal_mode = BIT(0);
- mt76x2u_mcu_tssi_comp(dev, &t);
- dev->cal.tssi_comp_pending = true;
- } else {
- if (mt76_rr(dev, MT_BBP(CORE, 34)) & BIT(4))
- return;
-
- dev->cal.tssi_comp_pending = false;
- mt76x2_get_power_info(dev, &txp, chan);
-
- if (mt76x2_ext_pa_enabled(dev, chan->band))
- t.pa_mode = 1;
-
- t.cal_mode = BIT(1);
- t.slope0 = txp.chain[0].tssi_slope;
- t.offset0 = txp.chain[0].tssi_offset;
- t.slope1 = txp.chain[1].tssi_slope;
- t.offset1 = txp.chain[1].tssi_offset;
- mt76x2u_mcu_tssi_comp(dev, &t);
-
- if (t.pa_mode || dev->cal.dpd_cal_done)
- return;
-
- usleep_range(10000, 20000);
- mt76x2u_mcu_calibrate(dev, MCU_CAL_DPD, chan->hw_value);
- dev->cal.dpd_cal_done = true;
- }
-}
-
-static void
-mt76x2u_phy_update_channel_gain(struct mt76x2_dev *dev)
+mt76x2u_phy_update_channel_gain(struct mt76x02_dev *dev)
{
u8 channel = dev->mt76.chandef.chan->hw_value;
int freq, freq1;
@@ -142,7 +69,7 @@ mt76x2u_phy_update_channel_gain(struct mt76x2_dev *dev)
break;
}
- dev->cal.avg_rssi_all = mt76x2_phy_get_min_avg_rssi(dev);
+ dev->cal.avg_rssi_all = mt76x02_phy_get_min_avg_rssi(dev);
false_cca = FIELD_GET(MT_RX_STAT_1_CCA_ERRORS,
mt76_rr(dev, MT_RX_STAT_1));
@@ -152,17 +79,17 @@ mt76x2u_phy_update_channel_gain(struct mt76x2_dev *dev)
void mt76x2u_phy_calibrate(struct work_struct *work)
{
- struct mt76x2_dev *dev;
+ struct mt76x02_dev *dev;
- dev = container_of(work, struct mt76x2_dev, cal_work.work);
- mt76x2u_phy_tssi_compensate(dev);
+ dev = container_of(work, struct mt76x02_dev, cal_work.work);
+ mt76x2_phy_tssi_compensate(dev, false);
mt76x2u_phy_update_channel_gain(dev);
ieee80211_queue_delayed_work(mt76_hw(dev), &dev->cal_work,
MT_CALIBRATE_INTERVAL);
}
-int mt76x2u_phy_set_channel(struct mt76x2_dev *dev,
+int mt76x2u_phy_set_channel(struct mt76x02_dev *dev,
struct cfg80211_chan_def *chandef)
{
u32 ext_cca_chan[4] = {
@@ -228,8 +155,8 @@ int mt76x2u_phy_set_channel(struct mt76x2_dev *dev,
mt76x2_configure_tx_delay(dev, chan->band, bw);
mt76x2_phy_set_txpower(dev);
- mt76x2_phy_set_band(dev, chan->band, ch_group_index & 1);
- mt76x2_phy_set_bw(dev, chandef->width, ch_group_index);
+ mt76x02_phy_set_band(dev, chan->band, ch_group_index & 1);
+ mt76x02_phy_set_bw(dev, chandef->width, ch_group_index);
mt76_rmw(dev, MT_EXT_CCA_CFG,
(MT_EXT_CCA_CFG_CCA0 |
@@ -239,28 +166,28 @@ int mt76x2u_phy_set_channel(struct mt76x2_dev *dev,
MT_EXT_CCA_CFG_CCA_MASK),
ext_cca_chan[ch_group_index]);
- ret = mt76x2u_mcu_set_channel(dev, channel, bw, bw_index, scan);
+ ret = mt76x2_mcu_set_channel(dev, channel, bw, bw_index, scan);
if (ret)
return ret;
- mt76x2u_mcu_init_gain(dev, channel, dev->cal.rx.mcu_gain, true);
+ mt76x2_mcu_init_gain(dev, channel, dev->cal.rx.mcu_gain, true);
/* Enable LDPC Rx */
if (mt76xx_rev(dev) >= MT76XX_REV_E3)
mt76_set(dev, MT_BBP(RXO, 13), BIT(10));
if (!dev->cal.init_cal_done) {
- u8 val = mt76x2_eeprom_get(dev, MT_EE_BT_RCAL_RESULT);
+ u8 val = mt76x02_eeprom_get(dev, MT_EE_BT_RCAL_RESULT);
if (val != 0xff)
- mt76x2u_mcu_calibrate(dev, MCU_CAL_R, 0);
+ mt76x02_mcu_calibrate(dev, MCU_CAL_R, 0, false);
}
- mt76x2u_mcu_calibrate(dev, MCU_CAL_RXDCOC, channel);
+ mt76x02_mcu_calibrate(dev, MCU_CAL_RXDCOC, channel, false);
/* Rx LPF calibration */
if (!dev->cal.init_cal_done)
- mt76x2u_mcu_calibrate(dev, MCU_CAL_RC, 0);
+ mt76x02_mcu_calibrate(dev, MCU_CAL_RC, 0, false);
dev->cal.init_cal_done = true;
mt76_wr(dev, MT_BBP(AGC, 61), 0xff64a4e2);
@@ -290,9 +217,9 @@ int mt76x2u_phy_set_channel(struct mt76x2_dev *dev,
chan = dev->mt76.chandef.chan;
if (chan->band == NL80211_BAND_5GHZ)
flag |= BIT(0);
- if (mt76x2_ext_pa_enabled(dev, chan->band))
+ if (mt76x02_ext_pa_enabled(dev, chan->band))
flag |= BIT(8);
- mt76x2u_mcu_calibrate(dev, MCU_CAL_TSSI, flag);
+ mt76x02_mcu_calibrate(dev, MCU_CAL_TSSI, flag, false);
dev->cal.tssi_cal_done = true;
}
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_common.c
deleted file mode 100644
index a2338ba139b4..000000000000
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_common.c
+++ /dev/null
@@ -1,350 +0,0 @@
-/*
- * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
- * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "mt76x2.h"
-
-void mt76x2_txq_init(struct mt76x2_dev *dev, struct ieee80211_txq *txq)
-{
- struct mt76_txq *mtxq;
-
- if (!txq)
- return;
-
- mtxq = (struct mt76_txq *) txq->drv_priv;
- if (txq->sta) {
- struct mt76x2_sta *sta;
-
- sta = (struct mt76x2_sta *) txq->sta->drv_priv;
- mtxq->wcid = &sta->wcid;
- } else {
- struct mt76x2_vif *mvif;
-
- mvif = (struct mt76x2_vif *) txq->vif->drv_priv;
- mtxq->wcid = &mvif->group_wcid;
- }
-
- mt76_txq_init(&dev->mt76, txq);
-}
-EXPORT_SYMBOL_GPL(mt76x2_txq_init);
-
-int mt76x2_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_ampdu_params *params)
-{
- enum ieee80211_ampdu_mlme_action action = params->action;
- struct ieee80211_sta *sta = params->sta;
- struct mt76x2_dev *dev = hw->priv;
- struct mt76x2_sta *msta = (struct mt76x2_sta *) sta->drv_priv;
- struct ieee80211_txq *txq = sta->txq[params->tid];
- u16 tid = params->tid;
- u16 *ssn = &params->ssn;
- struct mt76_txq *mtxq;
-
- if (!txq)
- return -EINVAL;
-
- mtxq = (struct mt76_txq *)txq->drv_priv;
-
- switch (action) {
- case IEEE80211_AMPDU_RX_START:
- mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, *ssn, params->buf_size);
- mt76_set(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid));
- break;
- case IEEE80211_AMPDU_RX_STOP:
- mt76_rx_aggr_stop(&dev->mt76, &msta->wcid, tid);
- mt76_clear(dev, MT_WCID_ADDR(msta->wcid.idx) + 4,
- BIT(16 + tid));
- break;
- case IEEE80211_AMPDU_TX_OPERATIONAL:
- mtxq->aggr = true;
- mtxq->send_bar = false;
- ieee80211_send_bar(vif, sta->addr, tid, mtxq->agg_ssn);
- break;
- case IEEE80211_AMPDU_TX_STOP_FLUSH:
- case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
- mtxq->aggr = false;
- ieee80211_send_bar(vif, sta->addr, tid, mtxq->agg_ssn);
- break;
- case IEEE80211_AMPDU_TX_START:
- mtxq->agg_ssn = *ssn << 4;
- ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
- break;
- case IEEE80211_AMPDU_TX_STOP_CONT:
- mtxq->aggr = false;
- ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
- break;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(mt76x2_ampdu_action);
-
-int mt76x2_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
-{
- struct mt76x2_dev *dev = hw->priv;
- struct mt76x2_sta *msta = (struct mt76x2_sta *) sta->drv_priv;
- struct mt76x2_vif *mvif = (struct mt76x2_vif *) vif->drv_priv;
- int ret = 0;
- int idx = 0;
- int i;
-
- mutex_lock(&dev->mutex);
-
- idx = mt76_wcid_alloc(dev->wcid_mask, ARRAY_SIZE(dev->wcid));
- if (idx < 0) {
- ret = -ENOSPC;
- goto out;
- }
-
- msta->vif = mvif;
- msta->wcid.sta = 1;
- msta->wcid.idx = idx;
- msta->wcid.hw_key_idx = -1;
- mt76x2_mac_wcid_setup(dev, idx, mvif->idx, sta->addr);
- mt76x2_mac_wcid_set_drop(dev, idx, false);
- for (i = 0; i < ARRAY_SIZE(sta->txq); i++)
- mt76x2_txq_init(dev, sta->txq[i]);
-
- if (vif->type == NL80211_IFTYPE_AP)
- set_bit(MT_WCID_FLAG_CHECK_PS, &msta->wcid.flags);
-
- ewma_signal_init(&msta->rssi);
-
- rcu_assign_pointer(dev->wcid[idx], &msta->wcid);
-
-out:
- mutex_unlock(&dev->mutex);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(mt76x2_sta_add);
-
-int mt76x2_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
-{
- struct mt76x2_dev *dev = hw->priv;
- struct mt76x2_sta *msta = (struct mt76x2_sta *) sta->drv_priv;
- int idx = msta->wcid.idx;
- int i;
-
- mutex_lock(&dev->mutex);
- rcu_assign_pointer(dev->wcid[idx], NULL);
- for (i = 0; i < ARRAY_SIZE(sta->txq); i++)
- mt76_txq_remove(&dev->mt76, sta->txq[i]);
- mt76x2_mac_wcid_set_drop(dev, idx, true);
- mt76_wcid_free(dev->wcid_mask, idx);
- mt76x2_mac_wcid_setup(dev, idx, 0, NULL);
- mutex_unlock(&dev->mutex);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(mt76x2_sta_remove);
-
-void mt76x2_remove_interface(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif)
-{
- struct mt76x2_dev *dev = hw->priv;
-
- mt76_txq_remove(&dev->mt76, vif->txq);
-}
-EXPORT_SYMBOL_GPL(mt76x2_remove_interface);
-
-int mt76x2_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
- struct ieee80211_vif *vif, struct ieee80211_sta *sta,
- struct ieee80211_key_conf *key)
-{
- struct mt76x2_dev *dev = hw->priv;
- struct mt76x2_vif *mvif = (struct mt76x2_vif *) vif->drv_priv;
- struct mt76x2_sta *msta;
- struct mt76_wcid *wcid;
- int idx = key->keyidx;
- int ret;
-
- /* fall back to sw encryption for unsupported ciphers */
- switch (key->cipher) {
- case WLAN_CIPHER_SUITE_WEP40:
- case WLAN_CIPHER_SUITE_WEP104:
- case WLAN_CIPHER_SUITE_TKIP:
- case WLAN_CIPHER_SUITE_CCMP:
- break;
- default:
- return -EOPNOTSUPP;
- }
-
- /*
- * The hardware does not support per-STA RX GTK, fall back
- * to software mode for these.
- */
- if ((vif->type == NL80211_IFTYPE_ADHOC ||
- vif->type == NL80211_IFTYPE_MESH_POINT) &&
- (key->cipher == WLAN_CIPHER_SUITE_TKIP ||
- key->cipher == WLAN_CIPHER_SUITE_CCMP) &&
- !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
- return -EOPNOTSUPP;
-
- msta = sta ? (struct mt76x2_sta *) sta->drv_priv : NULL;
- wcid = msta ? &msta->wcid : &mvif->group_wcid;
-
- if (cmd == SET_KEY) {
- key->hw_key_idx = wcid->idx;
- wcid->hw_key_idx = idx;
- if (key->flags & IEEE80211_KEY_FLAG_RX_MGMT) {
- key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
- wcid->sw_iv = true;
- }
- } else {
- if (idx == wcid->hw_key_idx) {
- wcid->hw_key_idx = -1;
- wcid->sw_iv = true;
- }
-
- key = NULL;
- }
- mt76_wcid_key_setup(&dev->mt76, wcid, key);
-
- if (!msta) {
- if (key || wcid->hw_key_idx == idx) {
- ret = mt76x2_mac_wcid_set_key(dev, wcid->idx, key);
- if (ret)
- return ret;
- }
-
- return mt76x2_mac_shared_key_setup(dev, mvif->idx, idx, key);
- }
-
- return mt76x2_mac_wcid_set_key(dev, msta->wcid.idx, key);
-}
-EXPORT_SYMBOL_GPL(mt76x2_set_key);
-
-int mt76x2_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- u16 queue, const struct ieee80211_tx_queue_params *params)
-{
- struct mt76x2_dev *dev = hw->priv;
- u8 cw_min = 5, cw_max = 10, qid;
- u32 val;
-
- qid = dev->mt76.q_tx[queue].hw_idx;
-
- if (params->cw_min)
- cw_min = fls(params->cw_min);
- if (params->cw_max)
- cw_max = fls(params->cw_max);
-
- val = FIELD_PREP(MT_EDCA_CFG_TXOP, params->txop) |
- FIELD_PREP(MT_EDCA_CFG_AIFSN, params->aifs) |
- FIELD_PREP(MT_EDCA_CFG_CWMIN, cw_min) |
- FIELD_PREP(MT_EDCA_CFG_CWMAX, cw_max);
- mt76_wr(dev, MT_EDCA_CFG_AC(qid), val);
-
- val = mt76_rr(dev, MT_WMM_TXOP(qid));
- val &= ~(MT_WMM_TXOP_MASK << MT_WMM_TXOP_SHIFT(qid));
- val |= params->txop << MT_WMM_TXOP_SHIFT(qid);
- mt76_wr(dev, MT_WMM_TXOP(qid), val);
-
- val = mt76_rr(dev, MT_WMM_AIFSN);
- val &= ~(MT_WMM_AIFSN_MASK << MT_WMM_AIFSN_SHIFT(qid));
- val |= params->aifs << MT_WMM_AIFSN_SHIFT(qid);
- mt76_wr(dev, MT_WMM_AIFSN, val);
-
- val = mt76_rr(dev, MT_WMM_CWMIN);
- val &= ~(MT_WMM_CWMIN_MASK << MT_WMM_CWMIN_SHIFT(qid));
- val |= cw_min << MT_WMM_CWMIN_SHIFT(qid);
- mt76_wr(dev, MT_WMM_CWMIN, val);
-
- val = mt76_rr(dev, MT_WMM_CWMAX);
- val &= ~(MT_WMM_CWMAX_MASK << MT_WMM_CWMAX_SHIFT(qid));
- val |= cw_max << MT_WMM_CWMAX_SHIFT(qid);
- mt76_wr(dev, MT_WMM_CWMAX, val);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(mt76x2_conf_tx);
-
-void mt76x2_configure_filter(struct ieee80211_hw *hw,
- unsigned int changed_flags,
- unsigned int *total_flags, u64 multicast)
-{
- struct mt76x2_dev *dev = hw->priv;
- u32 flags = 0;
-
-#define MT76_FILTER(_flag, _hw) do { \
- flags |= *total_flags & FIF_##_flag; \
- dev->rxfilter &= ~(_hw); \
- dev->rxfilter |= !(flags & FIF_##_flag) * (_hw); \
- } while (0)
-
- mutex_lock(&dev->mutex);
-
- dev->rxfilter &= ~MT_RX_FILTR_CFG_OTHER_BSS;
-
- MT76_FILTER(FCSFAIL, MT_RX_FILTR_CFG_CRC_ERR);
- MT76_FILTER(PLCPFAIL, MT_RX_FILTR_CFG_PHY_ERR);
- MT76_FILTER(CONTROL, MT_RX_FILTR_CFG_ACK |
- MT_RX_FILTR_CFG_CTS |
- MT_RX_FILTR_CFG_CFEND |
- MT_RX_FILTR_CFG_CFACK |
- MT_RX_FILTR_CFG_BA |
- MT_RX_FILTR_CFG_CTRL_RSV);
- MT76_FILTER(PSPOLL, MT_RX_FILTR_CFG_PSPOLL);
-
- *total_flags = flags;
- mt76_wr(dev, MT_RX_FILTR_CFG, dev->rxfilter);
-
- mutex_unlock(&dev->mutex);
-}
-EXPORT_SYMBOL_GPL(mt76x2_configure_filter);
-
-void mt76x2_sta_rate_tbl_update(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
-{
- struct mt76x2_dev *dev = hw->priv;
- struct mt76x2_sta *msta = (struct mt76x2_sta *) sta->drv_priv;
- struct ieee80211_sta_rates *rates = rcu_dereference(sta->rates);
- struct ieee80211_tx_rate rate = {};
-
- if (!rates)
- return;
-
- rate.idx = rates->rate[0].idx;
- rate.flags = rates->rate[0].flags;
- mt76x2_mac_wcid_set_rate(dev, &msta->wcid, &rate);
- msta->wcid.max_txpwr_adj = mt76x2_tx_get_max_txpwr_adj(dev, &rate);
-}
-EXPORT_SYMBOL_GPL(mt76x2_sta_rate_tbl_update);
-
-void mt76x2_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
- struct sk_buff *skb)
-{
- struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76);
- void *rxwi = skb->data;
-
- if (q == MT_RXQ_MCU) {
- skb_queue_tail(&dev->mcu.res_q, skb);
- wake_up(&dev->mcu.wait);
- return;
- }
-
- skb_pull(skb, sizeof(struct mt76x2_rxwi));
- if (mt76x2_mac_process_rx(dev, skb, rxwi)) {
- dev_kfree_skb(skb);
- return;
- }
-
- mt76_rx(&dev->mt76, q, skb);
-}
-EXPORT_SYMBOL_GPL(mt76x2_queue_rx_skb);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_core.c b/drivers/net/wireless/mediatek/mt76/mt76x2_core.c
deleted file mode 100644
index 2629779e8d3e..000000000000
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_core.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <linux/delay.h>
-#include "mt76x2.h"
-#include "mt76x2_trace.h"
-
-void mt76x2_set_irq_mask(struct mt76x2_dev *dev, u32 clear, u32 set)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&dev->irq_lock, flags);
- dev->irqmask &= ~clear;
- dev->irqmask |= set;
- mt76_wr(dev, MT_INT_MASK_CSR, dev->irqmask);
- spin_unlock_irqrestore(&dev->irq_lock, flags);
-}
-
-void mt76x2_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q)
-{
- struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76);
-
- mt76x2_irq_enable(dev, MT_INT_RX_DONE(q));
-}
-
-irqreturn_t mt76x2_irq_handler(int irq, void *dev_instance)
-{
- struct mt76x2_dev *dev = dev_instance;
- u32 intr;
-
- intr = mt76_rr(dev, MT_INT_SOURCE_CSR);
- mt76_wr(dev, MT_INT_SOURCE_CSR, intr);
-
- if (!test_bit(MT76_STATE_INITIALIZED, &dev->mt76.state))
- return IRQ_NONE;
-
- trace_dev_irq(dev, intr, dev->irqmask);
-
- intr &= dev->irqmask;
-
- if (intr & MT_INT_TX_DONE_ALL) {
- mt76x2_irq_disable(dev, MT_INT_TX_DONE_ALL);
- tasklet_schedule(&dev->tx_tasklet);
- }
-
- if (intr & MT_INT_RX_DONE(0)) {
- mt76x2_irq_disable(dev, MT_INT_RX_DONE(0));
- napi_schedule(&dev->mt76.napi[0]);
- }
-
- if (intr & MT_INT_RX_DONE(1)) {
- mt76x2_irq_disable(dev, MT_INT_RX_DONE(1));
- napi_schedule(&dev->mt76.napi[1]);
- }
-
- if (intr & MT_INT_PRE_TBTT)
- tasklet_schedule(&dev->pre_tbtt_tasklet);
-
- /* send buffered multicast frames now */
- if (intr & MT_INT_TBTT)
- mt76_queue_kick(dev, &dev->mt76.q_tx[MT_TXQ_PSD]);
-
- if (intr & MT_INT_TX_STAT) {
- mt76x2_mac_poll_tx_status(dev, true);
- tasklet_schedule(&dev->tx_tasklet);
- }
-
- if (intr & MT_INT_GPTIMER) {
- mt76x2_irq_disable(dev, MT_INT_GPTIMER);
- tasklet_schedule(&dev->dfs_pd.dfs_tasklet);
- }
-
- return IRQ_HANDLED;
-}
-
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c b/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c
deleted file mode 100644
index 6720a6a1313f..000000000000
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_dma.c
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "mt76x2.h"
-#include "mt76x2_dma.h"
-
-int
-mt76x2_tx_queue_mcu(struct mt76x2_dev *dev, enum mt76_txq_id qid,
- struct sk_buff *skb, int cmd, int seq)
-{
- struct mt76_queue *q = &dev->mt76.q_tx[qid];
- struct mt76_queue_buf buf;
- dma_addr_t addr;
- u32 tx_info;
-
- tx_info = MT_MCU_MSG_TYPE_CMD |
- FIELD_PREP(MT_MCU_MSG_CMD_TYPE, cmd) |
- FIELD_PREP(MT_MCU_MSG_CMD_SEQ, seq) |
- FIELD_PREP(MT_MCU_MSG_PORT, CPU_TX_PORT) |
- FIELD_PREP(MT_MCU_MSG_LEN, skb->len);
-
- addr = dma_map_single(dev->mt76.dev, skb->data, skb->len,
- DMA_TO_DEVICE);
- if (dma_mapping_error(dev->mt76.dev, addr))
- return -ENOMEM;
-
- buf.addr = addr;
- buf.len = skb->len;
- spin_lock_bh(&q->lock);
- mt76_queue_add_buf(dev, q, &buf, 1, tx_info, skb, NULL);
- mt76_queue_kick(dev, q);
- spin_unlock_bh(&q->lock);
-
- return 0;
-}
-
-static int
-mt76x2_init_tx_queue(struct mt76x2_dev *dev, struct mt76_queue *q,
- int idx, int n_desc)
-{
- int ret;
-
- q->regs = dev->mt76.regs + MT_TX_RING_BASE + idx * MT_RING_SIZE;
- q->ndesc = n_desc;
- q->hw_idx = idx;
-
- ret = mt76_queue_alloc(dev, q);
- if (ret)
- return ret;
-
- mt76x2_irq_enable(dev, MT_INT_TX_DONE(idx));
-
- return 0;
-}
-
-static int
-mt76x2_init_rx_queue(struct mt76x2_dev *dev, struct mt76_queue *q,
- int idx, int n_desc, int bufsize)
-{
- int ret;
-
- q->regs = dev->mt76.regs + MT_RX_RING_BASE + idx * MT_RING_SIZE;
- q->ndesc = n_desc;
- q->buf_size = bufsize;
-
- ret = mt76_queue_alloc(dev, q);
- if (ret)
- return ret;
-
- mt76x2_irq_enable(dev, MT_INT_RX_DONE(idx));
-
- return 0;
-}
-
-static void
-mt76x2_tx_tasklet(unsigned long data)
-{
- struct mt76x2_dev *dev = (struct mt76x2_dev *) data;
- int i;
-
- mt76x2_mac_process_tx_status_fifo(dev);
-
- for (i = MT_TXQ_MCU; i >= 0; i--)
- mt76_queue_tx_cleanup(dev, i, false);
-
- mt76x2_mac_poll_tx_status(dev, false);
- mt76x2_irq_enable(dev, MT_INT_TX_DONE_ALL);
-}
-
-int mt76x2_dma_init(struct mt76x2_dev *dev)
-{
- static const u8 wmm_queue_map[] = {
- [IEEE80211_AC_BE] = 0,
- [IEEE80211_AC_BK] = 1,
- [IEEE80211_AC_VI] = 2,
- [IEEE80211_AC_VO] = 3,
- };
- int ret;
- int i;
- struct mt76_txwi_cache __maybe_unused *t;
- struct mt76_queue *q;
-
- BUILD_BUG_ON(sizeof(t->txwi) < sizeof(struct mt76x2_txwi));
- BUILD_BUG_ON(sizeof(struct mt76x2_rxwi) > MT_RX_HEADROOM);
-
- mt76_dma_attach(&dev->mt76);
-
- init_waitqueue_head(&dev->mcu.wait);
- skb_queue_head_init(&dev->mcu.res_q);
-
- tasklet_init(&dev->tx_tasklet, mt76x2_tx_tasklet, (unsigned long) dev);
-
- mt76_wr(dev, MT_WPDMA_RST_IDX, ~0);
-
- for (i = 0; i < ARRAY_SIZE(wmm_queue_map); i++) {
- ret = mt76x2_init_tx_queue(dev, &dev->mt76.q_tx[i],
- wmm_queue_map[i], MT_TX_RING_SIZE);
- if (ret)
- return ret;
- }
-
- ret = mt76x2_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_PSD],
- MT_TX_HW_QUEUE_MGMT, MT_TX_RING_SIZE);
- if (ret)
- return ret;
-
- ret = mt76x2_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_MCU],
- MT_TX_HW_QUEUE_MCU, MT_MCU_RING_SIZE);
- if (ret)
- return ret;
-
- ret = mt76x2_init_rx_queue(dev, &dev->mt76.q_rx[MT_RXQ_MCU], 1,
- MT_MCU_RING_SIZE, MT_RX_BUF_SIZE);
- if (ret)
- return ret;
-
- q = &dev->mt76.q_rx[MT_RXQ_MAIN];
- q->buf_offset = MT_RX_HEADROOM - sizeof(struct mt76x2_rxwi);
- ret = mt76x2_init_rx_queue(dev, q, 0, MT76x2_RX_RING_SIZE, MT_RX_BUF_SIZE);
- if (ret)
- return ret;
-
- return mt76_init_queues(dev);
-}
-
-void mt76x2_dma_cleanup(struct mt76x2_dev *dev)
-{
- tasklet_kill(&dev->tx_tasklet);
- mt76_dma_cleanup(&dev->mt76);
-}
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c
deleted file mode 100644
index 743da57760dc..000000000000
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c
+++ /dev/null
@@ -1,427 +0,0 @@
-/*
- * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <linux/kernel.h>
-#include <linux/firmware.h>
-#include <linux/delay.h>
-
-#include "mt76x2.h"
-#include "mt76x2_mcu.h"
-#include "mt76x2_dma.h"
-#include "mt76x2_eeprom.h"
-
-static struct sk_buff *mt76x2_mcu_msg_alloc(const void *data, int len)
-{
- struct sk_buff *skb;
-
- skb = alloc_skb(len, GFP_KERNEL);
- if (!skb)
- return NULL;
- memcpy(skb_put(skb, len), data, len);
-
- return skb;
-}
-
-static struct sk_buff *
-mt76x2_mcu_get_response(struct mt76x2_dev *dev, unsigned long expires)
-{
- unsigned long timeout;
-
- if (!time_is_after_jiffies(expires))
- return NULL;
-
- timeout = expires - jiffies;
- wait_event_timeout(dev->mcu.wait, !skb_queue_empty(&dev->mcu.res_q),
- timeout);
- return skb_dequeue(&dev->mcu.res_q);
-}
-
-static int
-mt76x2_mcu_msg_send(struct mt76x2_dev *dev, struct sk_buff *skb,
- enum mcu_cmd cmd)
-{
- unsigned long expires = jiffies + HZ;
- int ret;
- u8 seq;
-
- if (!skb)
- return -EINVAL;
-
- mutex_lock(&dev->mcu.mutex);
-
- seq = ++dev->mcu.msg_seq & 0xf;
- if (!seq)
- seq = ++dev->mcu.msg_seq & 0xf;
-
- ret = mt76x2_tx_queue_mcu(dev, MT_TXQ_MCU, skb, cmd, seq);
- if (ret)
- goto out;
-
- while (1) {
- u32 *rxfce;
- bool check_seq = false;
-
- skb = mt76x2_mcu_get_response(dev, expires);
- if (!skb) {
- dev_err(dev->mt76.dev,
- "MCU message %d (seq %d) timed out\n", cmd,
- seq);
- ret = -ETIMEDOUT;
- break;
- }
-
- rxfce = (u32 *) skb->cb;
-
- if (seq == FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, *rxfce))
- check_seq = true;
-
- dev_kfree_skb(skb);
- if (check_seq)
- break;
- }
-
-out:
- mutex_unlock(&dev->mcu.mutex);
-
- return ret;
-}
-
-static int
-mt76pci_load_rom_patch(struct mt76x2_dev *dev)
-{
- const struct firmware *fw = NULL;
- struct mt76x2_patch_header *hdr;
- bool rom_protect = !is_mt7612(dev);
- int len, ret = 0;
- __le32 *cur;
- u32 patch_mask, patch_reg;
-
- if (rom_protect && !mt76_poll(dev, MT_MCU_SEMAPHORE_03, 1, 1, 600)) {
- dev_err(dev->mt76.dev,
- "Could not get hardware semaphore for ROM PATCH\n");
- return -ETIMEDOUT;
- }
-
- if (mt76xx_rev(dev) >= MT76XX_REV_E3) {
- patch_mask = BIT(0);
- patch_reg = MT_MCU_CLOCK_CTL;
- } else {
- patch_mask = BIT(1);
- patch_reg = MT_MCU_COM_REG0;
- }
-
- if (rom_protect && (mt76_rr(dev, patch_reg) & patch_mask)) {
- dev_info(dev->mt76.dev, "ROM patch already applied\n");
- goto out;
- }
-
- ret = request_firmware(&fw, MT7662_ROM_PATCH, dev->mt76.dev);
- if (ret)
- goto out;
-
- if (!fw || !fw->data || fw->size <= sizeof(*hdr)) {
- ret = -EIO;
- dev_err(dev->mt76.dev, "Failed to load firmware\n");
- goto out;
- }
-
- hdr = (struct mt76x2_patch_header *) fw->data;
- dev_info(dev->mt76.dev, "ROM patch build: %.15s\n", hdr->build_time);
-
- mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, MT_MCU_ROM_PATCH_OFFSET);
-
- cur = (__le32 *) (fw->data + sizeof(*hdr));
- len = fw->size - sizeof(*hdr);
- mt76_wr_copy(dev, MT_MCU_ROM_PATCH_ADDR, cur, len);
-
- mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, 0);
-
- /* Trigger ROM */
- mt76_wr(dev, MT_MCU_INT_LEVEL, 4);
-
- if (!mt76_poll_msec(dev, patch_reg, patch_mask, patch_mask, 2000)) {
- dev_err(dev->mt76.dev, "Failed to load ROM patch\n");
- ret = -ETIMEDOUT;
- }
-
-out:
- /* release semaphore */
- if (rom_protect)
- mt76_wr(dev, MT_MCU_SEMAPHORE_03, 1);
- release_firmware(fw);
- return ret;
-}
-
-static int
-mt76pci_load_firmware(struct mt76x2_dev *dev)
-{
- const struct firmware *fw;
- const struct mt76x2_fw_header *hdr;
- int len, ret;
- __le32 *cur;
- u32 offset, val;
-
- ret = request_firmware(&fw, MT7662_FIRMWARE, dev->mt76.dev);
- if (ret)
- return ret;
-
- if (!fw || !fw->data || fw->size < sizeof(*hdr))
- goto error;
-
- hdr = (const struct mt76x2_fw_header *) fw->data;
-
- len = sizeof(*hdr);
- len += le32_to_cpu(hdr->ilm_len);
- len += le32_to_cpu(hdr->dlm_len);
-
- if (fw->size != len)
- goto error;
-
- val = le16_to_cpu(hdr->fw_ver);
- dev_info(dev->mt76.dev, "Firmware Version: %d.%d.%02d\n",
- (val >> 12) & 0xf, (val >> 8) & 0xf, val & 0xf);
-
- val = le16_to_cpu(hdr->build_ver);
- dev_info(dev->mt76.dev, "Build: %x\n", val);
- dev_info(dev->mt76.dev, "Build Time: %.16s\n", hdr->build_time);
-
- cur = (__le32 *) (fw->data + sizeof(*hdr));
- len = le32_to_cpu(hdr->ilm_len);
-
- mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, MT_MCU_ILM_OFFSET);
- mt76_wr_copy(dev, MT_MCU_ILM_ADDR, cur, len);
-
- cur += len / sizeof(*cur);
- len = le32_to_cpu(hdr->dlm_len);
-
- if (mt76xx_rev(dev) >= MT76XX_REV_E3)
- offset = MT_MCU_DLM_ADDR_E3;
- else
- offset = MT_MCU_DLM_ADDR;
-
- mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, MT_MCU_DLM_OFFSET);
- mt76_wr_copy(dev, offset, cur, len);
-
- mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, 0);
-
- val = mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_2);
- if (FIELD_GET(MT_EE_NIC_CONF_2_XTAL_OPTION, val) == 1)
- mt76_set(dev, MT_MCU_COM_REG0, BIT(30));
-
- /* trigger firmware */
- mt76_wr(dev, MT_MCU_INT_LEVEL, 2);
- if (!mt76_poll_msec(dev, MT_MCU_COM_REG0, 1, 1, 200)) {
- dev_err(dev->mt76.dev, "Firmware failed to start\n");
- release_firmware(fw);
- return -ETIMEDOUT;
- }
-
- dev_info(dev->mt76.dev, "Firmware running!\n");
-
- release_firmware(fw);
-
- return ret;
-
-error:
- dev_err(dev->mt76.dev, "Invalid firmware\n");
- release_firmware(fw);
- return -ENOENT;
-}
-
-static int
-mt76x2_mcu_function_select(struct mt76x2_dev *dev, enum mcu_function func,
- u32 val)
-{
- struct sk_buff *skb;
- struct {
- __le32 id;
- __le32 value;
- } __packed __aligned(4) msg = {
- .id = cpu_to_le32(func),
- .value = cpu_to_le32(val),
- };
-
- skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg));
- return mt76x2_mcu_msg_send(dev, skb, CMD_FUN_SET_OP);
-}
-
-int mt76x2_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level,
- u8 channel)
-{
- struct sk_buff *skb;
- struct {
- u8 cr_mode;
- u8 temp;
- u8 ch;
- u8 _pad0;
-
- __le32 cfg;
- } __packed __aligned(4) msg = {
- .cr_mode = type,
- .temp = temp_level,
- .ch = channel,
- };
- u32 val;
-
- val = BIT(31);
- val |= (mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_0) >> 8) & 0x00ff;
- val |= (mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_1) << 8) & 0xff00;
- msg.cfg = cpu_to_le32(val);
-
- /* first set the channel without the extension channel info */
- skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg));
- return mt76x2_mcu_msg_send(dev, skb, CMD_LOAD_CR);
-}
-
-int mt76x2_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw,
- u8 bw_index, bool scan)
-{
- struct sk_buff *skb;
- struct {
- u8 idx;
- u8 scan;
- u8 bw;
- u8 _pad0;
-
- __le16 chainmask;
- u8 ext_chan;
- u8 _pad1;
-
- } __packed __aligned(4) msg = {
- .idx = channel,
- .scan = scan,
- .bw = bw,
- .chainmask = cpu_to_le16(dev->chainmask),
- };
-
- /* first set the channel without the extension channel info */
- skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg));
- mt76x2_mcu_msg_send(dev, skb, CMD_SWITCH_CHANNEL_OP);
-
- usleep_range(5000, 10000);
-
- msg.ext_chan = 0xe0 + bw_index;
- skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg));
- return mt76x2_mcu_msg_send(dev, skb, CMD_SWITCH_CHANNEL_OP);
-}
-
-int mt76x2_mcu_set_radio_state(struct mt76x2_dev *dev, bool on)
-{
- struct sk_buff *skb;
- struct {
- __le32 mode;
- __le32 level;
- } __packed __aligned(4) msg = {
- .mode = cpu_to_le32(on ? RADIO_ON : RADIO_OFF),
- .level = cpu_to_le32(0),
- };
-
- skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg));
- return mt76x2_mcu_msg_send(dev, skb, CMD_POWER_SAVING_OP);
-}
-
-int mt76x2_mcu_calibrate(struct mt76x2_dev *dev, enum mcu_calibration type,
- u32 param)
-{
- struct sk_buff *skb;
- struct {
- __le32 id;
- __le32 value;
- } __packed __aligned(4) msg = {
- .id = cpu_to_le32(type),
- .value = cpu_to_le32(param),
- };
- int ret;
-
- mt76_clear(dev, MT_MCU_COM_REG0, BIT(31));
-
- skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg));
- ret = mt76x2_mcu_msg_send(dev, skb, CMD_CALIBRATION_OP);
- if (ret)
- return ret;
-
- if (WARN_ON(!mt76_poll_msec(dev, MT_MCU_COM_REG0,
- BIT(31), BIT(31), 100)))
- return -ETIMEDOUT;
-
- return 0;
-}
-
-int mt76x2_mcu_tssi_comp(struct mt76x2_dev *dev,
- struct mt76x2_tssi_comp *tssi_data)
-{
- struct sk_buff *skb;
- struct {
- __le32 id;
- struct mt76x2_tssi_comp data;
- } __packed __aligned(4) msg = {
- .id = cpu_to_le32(MCU_CAL_TSSI_COMP),
- .data = *tssi_data,
- };
-
- skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg));
- return mt76x2_mcu_msg_send(dev, skb, CMD_CALIBRATION_OP);
-}
-
-int mt76x2_mcu_init_gain(struct mt76x2_dev *dev, u8 channel, u32 gain,
- bool force)
-{
- struct sk_buff *skb;
- struct {
- __le32 channel;
- __le32 gain_val;
- } __packed __aligned(4) msg = {
- .channel = cpu_to_le32(channel),
- .gain_val = cpu_to_le32(gain),
- };
-
- if (force)
- msg.channel |= cpu_to_le32(BIT(31));
-
- skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg));
- return mt76x2_mcu_msg_send(dev, skb, CMD_INIT_GAIN_OP);
-}
-
-int mt76x2_mcu_init(struct mt76x2_dev *dev)
-{
- int ret;
-
- mutex_init(&dev->mcu.mutex);
-
- ret = mt76pci_load_rom_patch(dev);
- if (ret)
- return ret;
-
- ret = mt76pci_load_firmware(dev);
- if (ret)
- return ret;
-
- mt76x2_mcu_function_select(dev, Q_SELECT, 1);
- return 0;
-}
-
-int mt76x2_mcu_cleanup(struct mt76x2_dev *dev)
-{
- struct sk_buff *skb;
-
- mt76_wr(dev, MT_MCU_INT_LEVEL, 1);
- usleep_range(20000, 30000);
-
- while ((skb = skb_dequeue(&dev->mcu.res_q)) != NULL)
- dev_kfree_skb(skb);
-
- return 0;
-}
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c b/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c
deleted file mode 100644
index 36afb166fa3f..000000000000
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_tx_common.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
- * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "mt76x2.h"
-#include "mt76x2_dma.h"
-
-void mt76x2_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
- struct sk_buff *skb)
-{
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct mt76x2_dev *dev = hw->priv;
- struct ieee80211_vif *vif = info->control.vif;
- struct mt76_wcid *wcid = &dev->global_wcid;
-
- if (control->sta) {
- struct mt76x2_sta *msta;
-
- msta = (struct mt76x2_sta *)control->sta->drv_priv;
- wcid = &msta->wcid;
- /* sw encrypted frames */
- if (!info->control.hw_key && wcid->hw_key_idx != -1)
- control->sta = NULL;
- }
-
- if (vif && !control->sta) {
- struct mt76x2_vif *mvif;
-
- mvif = (struct mt76x2_vif *)vif->drv_priv;
- wcid = &mvif->group_wcid;
- }
-
- mt76_tx(&dev->mt76, control->sta, wcid, skb);
-}
-EXPORT_SYMBOL_GPL(mt76x2_tx);
-
-int mt76x2_insert_hdr_pad(struct sk_buff *skb)
-{
- int len = ieee80211_get_hdrlen_from_skb(skb);
-
- if (len % 4 == 0)
- return 0;
-
- skb_push(skb, 2);
- memmove(skb->data, skb->data + 2, len);
-
- skb->data[len] = 0;
- skb->data[len + 1] = 0;
- return 2;
-}
-EXPORT_SYMBOL_GPL(mt76x2_insert_hdr_pad);
-
-s8 mt76x2_tx_get_max_txpwr_adj(struct mt76x2_dev *dev,
- const struct ieee80211_tx_rate *rate)
-{
- s8 max_txpwr;
-
- if (rate->flags & IEEE80211_TX_RC_VHT_MCS) {
- u8 mcs = ieee80211_rate_get_vht_mcs(rate);
-
- if (mcs == 8 || mcs == 9) {
- max_txpwr = dev->rate_power.vht[8];
- } else {
- u8 nss, idx;
-
- nss = ieee80211_rate_get_vht_nss(rate);
- idx = ((nss - 1) << 3) + mcs;
- max_txpwr = dev->rate_power.ht[idx & 0xf];
- }
- } else if (rate->flags & IEEE80211_TX_RC_MCS) {
- max_txpwr = dev->rate_power.ht[rate->idx & 0xf];
- } else {
- enum nl80211_band band = dev->mt76.chandef.chan->band;
-
- if (band == NL80211_BAND_2GHZ) {
- const struct ieee80211_rate *r;
- struct wiphy *wiphy = mt76_hw(dev)->wiphy;
- struct mt76_rate_power *rp = &dev->rate_power;
-
- r = &wiphy->bands[band]->bitrates[rate->idx];
- if (r->flags & IEEE80211_RATE_SHORT_PREAMBLE)
- max_txpwr = rp->cck[r->hw_value & 0x3];
- else
- max_txpwr = rp->ofdm[r->hw_value & 0x7];
- } else {
- max_txpwr = dev->rate_power.ofdm[rate->idx & 0x7];
- }
- }
-
- return max_txpwr;
-}
-EXPORT_SYMBOL_GPL(mt76x2_tx_get_max_txpwr_adj);
-
-s8 mt76x2_tx_get_txpwr_adj(struct mt76x2_dev *dev, s8 txpwr, s8 max_txpwr_adj)
-{
- txpwr = min_t(s8, txpwr, dev->txpower_conf);
- txpwr -= (dev->target_power + dev->target_power_delta[0]);
- txpwr = min_t(s8, txpwr, max_txpwr_adj);
-
- if (!dev->enable_tpc)
- return 0;
- else if (txpwr >= 0)
- return min_t(s8, txpwr, 7);
- else
- return (txpwr < -16) ? 8 : (txpwr + 32) / 2;
-}
-EXPORT_SYMBOL_GPL(mt76x2_tx_get_txpwr_adj);
-
-void mt76x2_tx_set_txpwr_auto(struct mt76x2_dev *dev, s8 txpwr)
-{
- s8 txpwr_adj;
-
- txpwr_adj = mt76x2_tx_get_txpwr_adj(dev, txpwr,
- dev->rate_power.ofdm[4]);
- mt76_rmw_field(dev, MT_PROT_AUTO_TX_CFG,
- MT_PROT_AUTO_TX_CFG_PROT_PADJ, txpwr_adj);
- mt76_rmw_field(dev, MT_PROT_AUTO_TX_CFG,
- MT_PROT_AUTO_TX_CFG_AUTO_PADJ, txpwr_adj);
-}
-EXPORT_SYMBOL_GPL(mt76x2_tx_set_txpwr_auto);
-
-void mt76x2_tx_complete(struct mt76x2_dev *dev, struct sk_buff *skb)
-{
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-
- if (info->flags & IEEE80211_TX_CTL_AMPDU) {
- ieee80211_free_txskb(mt76_hw(dev), skb);
- } else {
- ieee80211_tx_info_clear_status(info);
- info->status.rates[0].idx = -1;
- info->flags |= IEEE80211_TX_STAT_ACK;
- ieee80211_tx_status(mt76_hw(dev), skb);
- }
-}
-EXPORT_SYMBOL_GPL(mt76x2_tx_complete);
-
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u.h b/drivers/net/wireless/mediatek/mt76/mt76x2u.h
deleted file mode 100644
index 008092f0cd8a..000000000000
--- a/drivers/net/wireless/mediatek/mt76/mt76x2u.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef __MT76x2U_H
-#define __MT76x2U_H
-
-#include <linux/device.h>
-
-#include "mt76x2.h"
-#include "mt76x2_dma.h"
-#include "mt76x2_mcu.h"
-
-#define MT7612U_EEPROM_SIZE 512
-
-#define MT_USB_AGGR_SIZE_LIMIT 21 /* 1024B unit */
-#define MT_USB_AGGR_TIMEOUT 0x80 /* 33ns unit */
-
-extern const struct ieee80211_ops mt76x2u_ops;
-
-struct mt76x2_dev *mt76x2u_alloc_device(struct device *pdev);
-int mt76x2u_register_device(struct mt76x2_dev *dev);
-int mt76x2u_init_hardware(struct mt76x2_dev *dev);
-void mt76x2u_cleanup(struct mt76x2_dev *dev);
-void mt76x2u_stop_hw(struct mt76x2_dev *dev);
-
-void mt76x2u_mac_setaddr(struct mt76x2_dev *dev, u8 *addr);
-int mt76x2u_mac_reset(struct mt76x2_dev *dev);
-void mt76x2u_mac_resume(struct mt76x2_dev *dev);
-int mt76x2u_mac_start(struct mt76x2_dev *dev);
-int mt76x2u_mac_stop(struct mt76x2_dev *dev);
-
-int mt76x2u_phy_set_channel(struct mt76x2_dev *dev,
- struct cfg80211_chan_def *chandef);
-void mt76x2u_phy_calibrate(struct work_struct *work);
-void mt76x2u_phy_channel_calibrate(struct mt76x2_dev *dev);
-void mt76x2u_phy_set_txdac(struct mt76x2_dev *dev);
-void mt76x2u_phy_set_rxpath(struct mt76x2_dev *dev);
-
-void mt76x2u_mcu_complete_urb(struct urb *urb);
-int mt76x2u_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw,
- u8 bw_index, bool scan);
-int mt76x2u_mcu_calibrate(struct mt76x2_dev *dev, enum mcu_calibration type,
- u32 val);
-int mt76x2u_mcu_tssi_comp(struct mt76x2_dev *dev,
- struct mt76x2_tssi_comp *tssi_data);
-int mt76x2u_mcu_init_gain(struct mt76x2_dev *dev, u8 channel, u32 gain,
- bool force);
-int mt76x2u_mcu_set_dynamic_vga(struct mt76x2_dev *dev, u8 channel, bool ap,
- bool ext, int rssi, u32 false_cca);
-int mt76x2u_mcu_set_radio_state(struct mt76x2_dev *dev, bool val);
-int mt76x2u_mcu_load_cr(struct mt76x2_dev *dev, u8 type,
- u8 temp_level, u8 channel);
-int mt76x2u_mcu_init(struct mt76x2_dev *dev);
-int mt76x2u_mcu_fw_init(struct mt76x2_dev *dev);
-void mt76x2u_mcu_deinit(struct mt76x2_dev *dev);
-
-int mt76x2u_alloc_queues(struct mt76x2_dev *dev);
-void mt76x2u_queues_deinit(struct mt76x2_dev *dev);
-void mt76x2u_stop_queues(struct mt76x2_dev *dev);
-bool mt76x2u_tx_status_data(struct mt76_dev *mdev, u8 *update);
-int mt76x2u_tx_prepare_skb(struct mt76_dev *mdev, void *data,
- struct sk_buff *skb, struct mt76_queue *q,
- struct mt76_wcid *wcid, struct ieee80211_sta *sta,
- u32 *tx_info);
-void mt76x2u_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q,
- struct mt76_queue_entry *e, bool flush);
-int mt76x2u_skb_dma_info(struct sk_buff *skb, enum dma_msg_port port,
- u32 flags);
-
-#endif /* __MT76x2U_H */
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c
deleted file mode 100644
index 1ca5dd05b265..000000000000
--- a/drivers/net/wireless/mediatek/mt76/mt76x2u_core.c
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "mt76x2u.h"
-#include "dma.h"
-
-static void mt76x2u_remove_dma_hdr(struct sk_buff *skb)
-{
- int hdr_len;
-
- skb_pull(skb, sizeof(struct mt76x2_txwi) + MT_DMA_HDR_LEN);
- hdr_len = ieee80211_get_hdrlen_from_skb(skb);
- if (hdr_len % 4) {
- memmove(skb->data + 2, skb->data, hdr_len);
- skb_pull(skb, 2);
- }
-}
-
-static int
-mt76x2u_check_skb_rooms(struct sk_buff *skb)
-{
- int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
- u32 need_head;
-
- need_head = sizeof(struct mt76x2_txwi) + MT_DMA_HDR_LEN;
- if (hdr_len % 4)
- need_head += 2;
- return skb_cow(skb, need_head);
-}
-
-static int
-mt76x2u_set_txinfo(struct sk_buff *skb,
- struct mt76_wcid *wcid, u8 ep)
-{
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- enum mt76x2_qsel qsel;
- u32 flags;
-
- if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) ||
- ep == MT_EP_OUT_HCCA)
- qsel = MT_QSEL_MGMT;
- else
- qsel = MT_QSEL_EDCA;
-
- flags = FIELD_PREP(MT_TXD_INFO_QSEL, qsel) |
- MT_TXD_INFO_80211;
- if (!wcid || wcid->hw_key_idx == 0xff || wcid->sw_iv)
- flags |= MT_TXD_INFO_WIV;
-
- return mt76u_skb_dma_info(skb, WLAN_PORT, flags);
-}
-
-bool mt76x2u_tx_status_data(struct mt76_dev *mdev, u8 *update)
-{
- struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76);
- struct mt76x2_tx_status stat;
-
- if (!mt76x2_mac_load_tx_status(dev, &stat))
- return false;
-
- mt76x2_send_tx_status(dev, &stat, update);
-
- return true;
-}
-
-int mt76x2u_tx_prepare_skb(struct mt76_dev *mdev, void *data,
- struct sk_buff *skb, struct mt76_queue *q,
- struct mt76_wcid *wcid, struct ieee80211_sta *sta,
- u32 *tx_info)
-{
- struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76);
- struct mt76x2_txwi *txwi;
- int err, len = skb->len;
-
- err = mt76x2u_check_skb_rooms(skb);
- if (err < 0)
- return -ENOMEM;
-
- mt76x2_insert_hdr_pad(skb);
-
- txwi = skb_push(skb, sizeof(struct mt76x2_txwi));
- mt76x2_mac_write_txwi(dev, txwi, skb, wcid, sta, len);
-
- return mt76x2u_set_txinfo(skb, wcid, q2ep(q->hw_idx));
-}
-
-void mt76x2u_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q,
- struct mt76_queue_entry *e, bool flush)
-{
- struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76);
-
- mt76x2u_remove_dma_hdr(e->skb);
- mt76x2_tx_complete(dev, e->skb);
-}
-
diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c
index af48d43bb7dc..7cbce03aa65b 100644
--- a/drivers/net/wireless/mediatek/mt76/tx.c
+++ b/drivers/net/wireless/mediatek/mt76/tx.c
@@ -91,11 +91,24 @@ mt76_txq_get_qid(struct ieee80211_txq *txq)
return txq->ac;
}
+static void
+mt76_check_agg_ssn(struct mt76_txq *mtxq, struct sk_buff *skb)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+
+ if (!ieee80211_is_data_qos(hdr->frame_control) ||
+ !ieee80211_is_data_present(hdr->frame_control))
+ return;
+
+ mtxq->agg_ssn = le16_to_cpu(hdr->seq_ctrl) + 0x10;
+}
+
void
mt76_tx(struct mt76_dev *dev, struct ieee80211_sta *sta,
struct mt76_wcid *wcid, struct sk_buff *skb)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct mt76_queue *q;
int qid = skb_get_queue_mapping(skb);
@@ -108,6 +121,19 @@ mt76_tx(struct mt76_dev *dev, struct ieee80211_sta *sta,
ieee80211_get_tx_rates(info->control.vif, sta, skb,
info->control.rates, 1);
+ if (sta && ieee80211_is_data_qos(hdr->frame_control)) {
+ struct ieee80211_txq *txq;
+ struct mt76_txq *mtxq;
+ u8 tid;
+
+ tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
+ txq = sta->txq[tid];
+ mtxq = (struct mt76_txq *) txq->drv_priv;
+
+ if (mtxq->aggr)
+ mt76_check_agg_ssn(mtxq, skb);
+ }
+
q = &dev->q_tx[qid];
spin_lock_bh(&q->lock);
@@ -144,17 +170,6 @@ mt76_txq_dequeue(struct mt76_dev *dev, struct mt76_txq *mtxq, bool ps)
}
static void
-mt76_check_agg_ssn(struct mt76_txq *mtxq, struct sk_buff *skb)
-{
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-
- if (!ieee80211_is_data_qos(hdr->frame_control))
- return;
-
- mtxq->agg_ssn = le16_to_cpu(hdr->seq_ctrl) + 0x10;
-}
-
-static void
mt76_queue_ps_skb(struct mt76_dev *dev, struct ieee80211_sta *sta,
struct sk_buff *skb, bool last)
{
@@ -442,3 +457,19 @@ void mt76_txq_init(struct mt76_dev *dev, struct ieee80211_txq *txq)
mtxq->hwq = &dev->q_tx[mt76_txq_get_qid(txq)];
}
EXPORT_SYMBOL_GPL(mt76_txq_init);
+
+u8 mt76_ac_to_hwq(u8 ac)
+{
+ static const u8 wmm_queue_map[] = {
+ [IEEE80211_AC_BE] = 0,
+ [IEEE80211_AC_BK] = 1,
+ [IEEE80211_AC_VI] = 2,
+ [IEEE80211_AC_VO] = 3,
+ };
+
+ if (WARN_ON(ac >= IEEE80211_NUM_ACS))
+ return 0;
+
+ return wmm_queue_map[ac];
+}
+EXPORT_SYMBOL_GPL(mt76_ac_to_hwq);
diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c
index 7780b07543bb..5f0faf07c346 100644
--- a/drivers/net/wireless/mediatek/mt76/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/usb.c
@@ -14,6 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include <linux/module.h>
#include "mt76.h"
#include "usb_trace.h"
#include "dma.h"
@@ -109,6 +110,7 @@ u32 mt76u_rr(struct mt76_dev *dev, u32 addr)
return ret;
}
+EXPORT_SYMBOL_GPL(mt76u_rr);
/* should be called with usb_ctrl_mtx locked */
static void __mt76u_wr(struct mt76_dev *dev, u32 addr, u32 val)
@@ -140,6 +142,7 @@ void mt76u_wr(struct mt76_dev *dev, u32 addr, u32 val)
__mt76u_wr(dev, addr, val);
mutex_unlock(&dev->usb.usb_ctrl_mtx);
}
+EXPORT_SYMBOL_GPL(mt76u_wr);
static u32 mt76u_rmw(struct mt76_dev *dev, u32 addr,
u32 mask, u32 val)
@@ -187,6 +190,60 @@ void mt76u_single_wr(struct mt76_dev *dev, const u8 req,
EXPORT_SYMBOL_GPL(mt76u_single_wr);
static int
+mt76u_req_wr_rp(struct mt76_dev *dev, u32 base,
+ const struct mt76_reg_pair *data, int len)
+{
+ struct mt76_usb *usb = &dev->usb;
+
+ mutex_lock(&usb->usb_ctrl_mtx);
+ while (len > 0) {
+ __mt76u_wr(dev, base + data->reg, data->value);
+ len--;
+ data++;
+ }
+ mutex_unlock(&usb->usb_ctrl_mtx);
+
+ return 0;
+}
+
+static int
+mt76u_wr_rp(struct mt76_dev *dev, u32 base,
+ const struct mt76_reg_pair *data, int n)
+{
+ if (test_bit(MT76_STATE_MCU_RUNNING, &dev->state))
+ return dev->mcu_ops->mcu_wr_rp(dev, base, data, n);
+ else
+ return mt76u_req_wr_rp(dev, base, data, n);
+}
+
+static int
+mt76u_req_rd_rp(struct mt76_dev *dev, u32 base, struct mt76_reg_pair *data,
+ int len)
+{
+ struct mt76_usb *usb = &dev->usb;
+
+ mutex_lock(&usb->usb_ctrl_mtx);
+ while (len > 0) {
+ data->value = __mt76u_rr(dev, base + data->reg);
+ len--;
+ data++;
+ }
+ mutex_unlock(&usb->usb_ctrl_mtx);
+
+ return 0;
+}
+
+static int
+mt76u_rd_rp(struct mt76_dev *dev, u32 base,
+ struct mt76_reg_pair *data, int n)
+{
+ if (test_bit(MT76_STATE_MCU_RUNNING, &dev->state))
+ return dev->mcu_ops->mcu_rd_rp(dev, base, data, n);
+ else
+ return mt76u_req_rd_rp(dev, base, data, n);
+}
+
+static int
mt76u_set_endpoints(struct usb_interface *intf,
struct mt76_usb *usb)
{
@@ -219,15 +276,17 @@ static int
mt76u_fill_rx_sg(struct mt76_dev *dev, struct mt76u_buf *buf,
int nsgs, int len, int sglen)
{
+ struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN];
struct urb *urb = buf->urb;
int i;
+ spin_lock_bh(&q->rx_page_lock);
for (i = 0; i < nsgs; i++) {
struct page *page;
void *data;
int offset;
- data = netdev_alloc_frag(len);
+ data = page_frag_alloc(&q->rx_page, len, GFP_ATOMIC);
if (!data)
break;
@@ -235,6 +294,7 @@ mt76u_fill_rx_sg(struct mt76_dev *dev, struct mt76u_buf *buf,
offset = data - page_address(page);
sg_set_page(&urb->sg[i], page, sglen, offset);
}
+ spin_unlock_bh(&q->rx_page_lock);
if (i < nsgs) {
int j;
@@ -258,7 +318,7 @@ int mt76u_buf_alloc(struct mt76_dev *dev, struct mt76u_buf *buf,
if (!buf->urb)
return -ENOMEM;
- buf->urb->sg = devm_kzalloc(dev->dev, nsgs * sizeof(*buf->urb->sg),
+ buf->urb->sg = devm_kcalloc(dev->dev, nsgs, sizeof(*buf->urb->sg),
gfp);
if (!buf->urb->sg)
return -ENOMEM;
@@ -326,9 +386,9 @@ static int mt76u_get_rx_entry_len(u8 *data, u32 data_len)
min_len = MT_DMA_HDR_LEN + MT_RX_RXWI_LEN +
MT_FCE_INFO_LEN;
- if (data_len < min_len || WARN_ON(!dma_len) ||
- WARN_ON(dma_len + MT_DMA_HDR_LEN > data_len) ||
- WARN_ON(dma_len & 0x3))
+ if (data_len < min_len || !dma_len ||
+ dma_len + MT_DMA_HDR_LEN > data_len ||
+ (dma_len & 0x3))
return -EINVAL;
return dma_len;
}
@@ -463,9 +523,10 @@ static int mt76u_alloc_rx(struct mt76_dev *dev)
struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN];
int i, err, nsgs;
+ spin_lock_init(&q->rx_page_lock);
spin_lock_init(&q->lock);
- q->entry = devm_kzalloc(dev->dev,
- MT_NUM_RX_ENTRIES * sizeof(*q->entry),
+ q->entry = devm_kcalloc(dev->dev,
+ MT_NUM_RX_ENTRIES, sizeof(*q->entry),
GFP_KERNEL);
if (!q->entry)
return -ENOMEM;
@@ -494,10 +555,21 @@ static int mt76u_alloc_rx(struct mt76_dev *dev)
static void mt76u_free_rx(struct mt76_dev *dev)
{
struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN];
+ struct page *page;
int i;
for (i = 0; i < q->ndesc; i++)
mt76u_buf_free(&q->entry[i].ubuf);
+
+ spin_lock_bh(&q->rx_page_lock);
+ if (!q->rx_page.va)
+ goto out;
+
+ page = virt_to_page(q->rx_page.va);
+ __page_frag_cache_drain(page, q->rx_page.pagecnt_bias);
+ memset(&q->rx_page, 0, sizeof(q->rx_page));
+out:
+ spin_unlock_bh(&q->rx_page_lock);
}
static void mt76u_stop_rx(struct mt76_dev *dev)
@@ -509,40 +581,6 @@ static void mt76u_stop_rx(struct mt76_dev *dev)
usb_kill_urb(q->entry[i].ubuf.urb);
}
-int mt76u_skb_dma_info(struct sk_buff *skb, int port, u32 flags)
-{
- struct sk_buff *iter, *last = skb;
- u32 info, pad;
-
- /* Buffer layout:
- * | 4B | xfer len | pad | 4B |
- * | TXINFO | pkt/cmd | zero pad to 4B | zero |
- *
- * length field of TXINFO should be set to 'xfer len'.
- */
- info = FIELD_PREP(MT_TXD_INFO_LEN, round_up(skb->len, 4)) |
- FIELD_PREP(MT_TXD_INFO_DPORT, port) | flags;
- put_unaligned_le32(info, skb_push(skb, sizeof(info)));
-
- pad = round_up(skb->len, 4) + 4 - skb->len;
- skb_walk_frags(skb, iter) {
- last = iter;
- if (!iter->next) {
- skb->data_len += pad;
- skb->len += pad;
- break;
- }
- }
-
- if (unlikely(pad)) {
- if (__skb_pad(last, pad, true))
- return -ENOMEM;
- __skb_put(last, pad);
- }
- return 0;
-}
-EXPORT_SYMBOL_GPL(mt76u_skb_dma_info);
-
static void mt76u_tx_tasklet(unsigned long data)
{
struct mt76_dev *dev = (struct mt76_dev *)data;
@@ -715,10 +753,10 @@ static int mt76u_alloc_tx(struct mt76_dev *dev)
q = &dev->q_tx[i];
spin_lock_init(&q->lock);
INIT_LIST_HEAD(&q->swq);
- q->hw_idx = q2hwq(i);
+ q->hw_idx = mt76_ac_to_hwq(i);
- q->entry = devm_kzalloc(dev->dev,
- MT_NUM_TX_ENTRIES * sizeof(*q->entry),
+ q->entry = devm_kcalloc(dev->dev,
+ MT_NUM_TX_ENTRIES, sizeof(*q->entry),
GFP_KERNEL);
if (!q->entry)
return -ENOMEM;
@@ -822,6 +860,9 @@ int mt76u_init(struct mt76_dev *dev,
.wr = mt76u_wr,
.rmw = mt76u_rmw,
.copy = mt76u_copy,
+ .wr_rp = mt76u_wr_rp,
+ .rd_rp = mt76u_rd_rp,
+ .type = MT76_BUS_USB,
};
struct mt76_usb *usb = &dev->usb;
diff --git a/drivers/net/wireless/mediatek/mt76/usb_mcu.c b/drivers/net/wireless/mediatek/mt76/usb_mcu.c
index 070be803d463..036be4163e69 100644
--- a/drivers/net/wireless/mediatek/mt76/usb_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/usb_mcu.c
@@ -14,32 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include <linux/firmware.h>
-
#include "mt76.h"
-#include "dma.h"
-
-#define MT_CMD_HDR_LEN 4
-
-#define MT_FCE_DMA_ADDR 0x0230
-#define MT_FCE_DMA_LEN 0x0234
-
-#define MT_TX_CPU_FROM_FCE_CPU_DESC_IDX 0x09a8
-
-struct sk_buff *mt76u_mcu_msg_alloc(const void *data, int len)
-{
- struct sk_buff *skb;
-
- skb = alloc_skb(MT_CMD_HDR_LEN + len + 8, GFP_KERNEL);
- if (!skb)
- return NULL;
-
- skb_reserve(skb, MT_CMD_HDR_LEN);
- skb_put_data(skb, data, len);
-
- return skb;
-}
-EXPORT_SYMBOL_GPL(mt76u_mcu_msg_alloc);
void mt76u_mcu_complete_urb(struct urb *urb)
{
@@ -49,176 +24,6 @@ void mt76u_mcu_complete_urb(struct urb *urb)
}
EXPORT_SYMBOL_GPL(mt76u_mcu_complete_urb);
-static int mt76u_mcu_wait_resp(struct mt76_dev *dev, u8 seq)
-{
- struct mt76_usb *usb = &dev->usb;
- struct mt76u_buf *buf = &usb->mcu.res;
- int i, ret;
- u32 rxfce;
-
- for (i = 0; i < 5; i++) {
- if (!wait_for_completion_timeout(&usb->mcu.cmpl,
- msecs_to_jiffies(300)))
- continue;
-
- if (buf->urb->status)
- return -EIO;
-
- rxfce = get_unaligned_le32(sg_virt(&buf->urb->sg[0]));
- ret = mt76u_submit_buf(dev, USB_DIR_IN,
- MT_EP_IN_CMD_RESP,
- buf, GFP_KERNEL,
- mt76u_mcu_complete_urb,
- &usb->mcu.cmpl);
- if (ret)
- return ret;
-
- if (seq == FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, rxfce))
- return 0;
-
- dev_err(dev->dev, "error: MCU resp evt:%lx seq:%hhx-%lx\n",
- FIELD_GET(MT_RX_FCE_INFO_EVT_TYPE, rxfce),
- seq, FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, rxfce));
- }
-
- dev_err(dev->dev, "error: %s timed out\n", __func__);
- return -ETIMEDOUT;
-}
-
-int mt76u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb,
- int cmd, bool wait_resp)
-{
- struct usb_interface *intf = to_usb_interface(dev->dev);
- struct usb_device *udev = interface_to_usbdev(intf);
- struct mt76_usb *usb = &dev->usb;
- unsigned int pipe;
- int ret, sent;
- u8 seq = 0;
- u32 info;
-
- if (test_bit(MT76_REMOVED, &dev->state))
- return 0;
-
- mutex_lock(&usb->mcu.mutex);
-
- pipe = usb_sndbulkpipe(udev, usb->out_ep[MT_EP_OUT_INBAND_CMD]);
- if (wait_resp) {
- seq = ++usb->mcu.msg_seq & 0xf;
- if (!seq)
- seq = ++usb->mcu.msg_seq & 0xf;
- }
-
- info = FIELD_PREP(MT_MCU_MSG_CMD_SEQ, seq) |
- FIELD_PREP(MT_MCU_MSG_CMD_TYPE, cmd) |
- MT_MCU_MSG_TYPE_CMD;
- ret = mt76u_skb_dma_info(skb, CPU_TX_PORT, info);
- if (ret)
- goto out;
-
- ret = usb_bulk_msg(udev, pipe, skb->data, skb->len, &sent, 500);
- if (ret)
- goto out;
-
- if (wait_resp)
- ret = mt76u_mcu_wait_resp(dev, seq);
-
-out:
- mutex_unlock(&usb->mcu.mutex);
-
- consume_skb(skb);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(mt76u_mcu_send_msg);
-
-void mt76u_mcu_fw_reset(struct mt76_dev *dev)
-{
- mt76u_vendor_request(dev, MT_VEND_DEV_MODE,
- USB_DIR_OUT | USB_TYPE_VENDOR,
- 0x1, 0, NULL, 0);
-}
-EXPORT_SYMBOL_GPL(mt76u_mcu_fw_reset);
-
-static int
-__mt76u_mcu_fw_send_data(struct mt76_dev *dev, struct mt76u_buf *buf,
- const void *fw_data, int len, u32 dst_addr)
-{
- u8 *data = sg_virt(&buf->urb->sg[0]);
- DECLARE_COMPLETION_ONSTACK(cmpl);
- __le32 info;
- u32 val;
- int err;
-
- info = cpu_to_le32(FIELD_PREP(MT_MCU_MSG_PORT, CPU_TX_PORT) |
- FIELD_PREP(MT_MCU_MSG_LEN, len) |
- MT_MCU_MSG_TYPE_CMD);
-
- memcpy(data, &info, sizeof(info));
- memcpy(data + sizeof(info), fw_data, len);
- memset(data + sizeof(info) + len, 0, 4);
-
- mt76u_single_wr(dev, MT_VEND_WRITE_FCE,
- MT_FCE_DMA_ADDR, dst_addr);
- len = roundup(len, 4);
- mt76u_single_wr(dev, MT_VEND_WRITE_FCE,
- MT_FCE_DMA_LEN, len << 16);
-
- buf->len = MT_CMD_HDR_LEN + len + sizeof(info);
- err = mt76u_submit_buf(dev, USB_DIR_OUT,
- MT_EP_OUT_INBAND_CMD,
- buf, GFP_KERNEL,
- mt76u_mcu_complete_urb, &cmpl);
- if (err < 0)
- return err;
-
- if (!wait_for_completion_timeout(&cmpl,
- msecs_to_jiffies(1000))) {
- dev_err(dev->dev, "firmware upload timed out\n");
- usb_kill_urb(buf->urb);
- return -ETIMEDOUT;
- }
-
- if (mt76u_urb_error(buf->urb)) {
- dev_err(dev->dev, "firmware upload failed: %d\n",
- buf->urb->status);
- return buf->urb->status;
- }
-
- val = mt76u_rr(dev, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX);
- val++;
- mt76u_wr(dev, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX, val);
-
- return 0;
-}
-
-int mt76u_mcu_fw_send_data(struct mt76_dev *dev, const void *data,
- int data_len, u32 max_payload, u32 offset)
-{
- int err, len, pos = 0, max_len = max_payload - 8;
- struct mt76u_buf buf;
-
- err = mt76u_buf_alloc(dev, &buf, 1, max_payload, max_payload,
- GFP_KERNEL);
- if (err < 0)
- return err;
-
- while (data_len > 0) {
- len = min_t(int, data_len, max_len);
- err = __mt76u_mcu_fw_send_data(dev, &buf, data + pos,
- len, offset + pos);
- if (err < 0)
- break;
-
- data_len -= len;
- pos += len;
- usleep_range(5000, 10000);
- }
- mt76u_buf_free(&buf);
-
- return err;
-}
-EXPORT_SYMBOL_GPL(mt76u_mcu_fw_send_data);
-
int mt76u_mcu_init_rx(struct mt76_dev *dev)
{
struct mt76_usb *usb = &dev->usb;
@@ -240,3 +45,12 @@ int mt76u_mcu_init_rx(struct mt76_dev *dev)
return err;
}
EXPORT_SYMBOL_GPL(mt76u_mcu_init_rx);
+
+void mt76u_mcu_deinit(struct mt76_dev *dev)
+{
+ struct mt76_usb *usb = &dev->usb;
+
+ usb_kill_urb(usb->mcu.res.urb);
+ mt76u_buf_free(&usb->mcu.res);
+}
+EXPORT_SYMBOL_GPL(mt76u_mcu_deinit);
diff --git a/drivers/net/wireless/quantenna/Kconfig b/drivers/net/wireless/quantenna/Kconfig
index de84ce125c26..7628d9c1ea6a 100644
--- a/drivers/net/wireless/quantenna/Kconfig
+++ b/drivers/net/wireless/quantenna/Kconfig
@@ -1,7 +1,7 @@
config WLAN_VENDOR_QUANTENNA
bool "Quantenna wireless cards support"
default y
- ---help---
+ help
If you have a wireless card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
diff --git a/drivers/net/wireless/quantenna/qtnfmac/Kconfig b/drivers/net/wireless/quantenna/qtnfmac/Kconfig
index 8d1492a90bd1..b8c12a5f16b4 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/Kconfig
+++ b/drivers/net/wireless/quantenna/qtnfmac/Kconfig
@@ -11,7 +11,7 @@ config QTNFMAC_PEARL_PCIE
select QTNFMAC
select FW_LOADER
select CRC32
- ---help---
+ help
This option adds support for wireless adapters based on Quantenna
802.11ac QSR10g (aka Pearl) FullMAC chipset running over PCIe.
diff --git a/drivers/net/wireless/quantenna/qtnfmac/Makefile b/drivers/net/wireless/quantenna/qtnfmac/Makefile
index 97f760a3d599..17cd7adb4109 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/Makefile
+++ b/drivers/net/wireless/quantenna/qtnfmac/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_QTNFMAC_PEARL_PCIE) += qtnfmac_pearl_pcie.o
qtnfmac_pearl_pcie-objs += \
shm_ipc.o \
- pearl/pcie.o
+ pcie/pcie.o \
+ pcie/pearl_pcie.o
qtnfmac_pearl_pcie-$(CONFIG_DEBUG_FS) += debug.o
diff --git a/drivers/net/wireless/quantenna/qtnfmac/bus.h b/drivers/net/wireless/quantenna/qtnfmac/bus.h
index 323e47cea1e2..528ca7f5e070 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/bus.h
+++ b/drivers/net/wireless/quantenna/qtnfmac/bus.h
@@ -20,6 +20,9 @@
#include <linux/netdevice.h>
#include <linux/workqueue.h>
+#include "trans.h"
+#include "core.h"
+
#define QTNF_MAX_MAC 3
enum qtnf_fw_state {
@@ -57,10 +60,8 @@ struct qtnf_bus {
struct qtnf_wmac *mac[QTNF_MAX_MAC];
struct qtnf_qlink_transport trans;
struct qtnf_hw_info hw_info;
- char fwname[32];
struct napi_struct mux_napi;
struct net_device mux_dev;
- struct completion firmware_init_complete;
struct workqueue_struct *workqueue;
struct work_struct fw_work;
struct work_struct event_work;
diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
index 4aa332f4646b..51b33ec78fac 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
+++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
@@ -141,8 +141,8 @@ qtnf_change_virtual_intf(struct wiphy *wiphy,
ret = qtnf_cmd_send_change_intf_type(vif, type, mac_addr);
if (ret) {
- pr_err("VIF%u.%u: failed to change VIF type: %d\n",
- vif->mac->macid, vif->vifid, ret);
+ pr_err("VIF%u.%u: failed to change type to %d\n",
+ vif->mac->macid, vif->vifid, type);
return ret;
}
@@ -216,7 +216,6 @@ static struct wireless_dev *qtnf_add_virtual_intf(struct wiphy *wiphy,
eth_zero_addr(vif->mac_addr);
eth_zero_addr(vif->bssid);
vif->bss_priority = QTNF_DEF_BSS_PRIORITY;
- vif->sta_state = QTNF_STA_DISCONNECTED;
memset(&vif->wdev, 0, sizeof(vif->wdev));
vif->wdev.wiphy = wiphy;
vif->wdev.iftype = type;
@@ -229,18 +228,22 @@ static struct wireless_dev *qtnf_add_virtual_intf(struct wiphy *wiphy,
if (params)
mac_addr = params->macaddr;
- if (qtnf_cmd_send_add_intf(vif, type, mac_addr)) {
- pr_err("VIF%u.%u: failed to add VIF\n", mac->macid, vif->vifid);
+ ret = qtnf_cmd_send_add_intf(vif, type, mac_addr);
+ if (ret) {
+ pr_err("VIF%u.%u: failed to add VIF %pM\n",
+ mac->macid, vif->vifid, mac_addr);
goto err_cmd;
}
if (!is_valid_ether_addr(vif->mac_addr)) {
pr_err("VIF%u.%u: FW reported bad MAC: %pM\n",
mac->macid, vif->vifid, vif->mac_addr);
+ ret = -EINVAL;
goto err_mac;
}
- if (qtnf_core_net_attach(mac, vif, name, name_assign_t)) {
+ ret = qtnf_core_net_attach(mac, vif, name, name_assign_t);
+ if (ret) {
pr_err("VIF%u.%u: failed to attach netdev\n", mac->macid,
vif->vifid);
goto err_net;
@@ -256,7 +259,7 @@ err_mac:
err_cmd:
vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
- return ERR_PTR(-EFAULT);
+ return ERR_PTR(ret);
}
static int qtnf_mgmt_set_appie(struct qtnf_vif *vif,
@@ -335,12 +338,11 @@ static int qtnf_stop_ap(struct wiphy *wiphy, struct net_device *dev)
qtnf_scan_done(vif->mac, true);
ret = qtnf_cmd_send_stop_ap(vif);
- if (ret) {
+ if (ret)
pr_err("VIF%u.%u: failed to stop AP operation in FW\n",
vif->mac->macid, vif->vifid);
- netif_carrier_off(vif->netdev);
- }
+ netif_carrier_off(vif->netdev);
return ret;
}
@@ -478,19 +480,31 @@ qtnf_dump_station(struct wiphy *wiphy, struct net_device *dev,
const struct qtnf_sta_node *sta_node;
int ret;
- sta_node = qtnf_sta_list_lookup_index(&vif->sta_list, idx);
+ switch (vif->wdev.iftype) {
+ case NL80211_IFTYPE_STATION:
+ if (idx != 0 || !vif->wdev.current_bss)
+ return -ENOENT;
- if (unlikely(!sta_node))
- return -ENOENT;
+ ether_addr_copy(mac, vif->bssid);
+ break;
+ case NL80211_IFTYPE_AP:
+ sta_node = qtnf_sta_list_lookup_index(&vif->sta_list, idx);
+ if (unlikely(!sta_node))
+ return -ENOENT;
- ether_addr_copy(mac, sta_node->mac_addr);
+ ether_addr_copy(mac, sta_node->mac_addr);
+ break;
+ default:
+ return -ENOTSUPP;
+ }
- ret = qtnf_cmd_get_sta_info(vif, sta_node->mac_addr, sinfo);
+ ret = qtnf_cmd_get_sta_info(vif, mac, sinfo);
- if (unlikely(ret == -ENOENT)) {
- qtnf_sta_list_del(vif, mac);
- cfg80211_del_sta(vif->netdev, mac, GFP_KERNEL);
- sinfo->filled = 0;
+ if (vif->wdev.iftype == NL80211_IFTYPE_AP) {
+ if (ret == -ENOENT) {
+ cfg80211_del_sta(vif->netdev, mac, GFP_KERNEL);
+ sinfo->filled = 0;
+ }
}
sinfo->generation = vif->generation;
@@ -521,9 +535,16 @@ static int qtnf_del_key(struct wiphy *wiphy, struct net_device *dev,
int ret;
ret = qtnf_cmd_send_del_key(vif, key_index, pairwise, mac_addr);
- if (ret)
- pr_err("VIF%u.%u: failed to delete key: idx=%u pw=%u\n",
- vif->mac->macid, vif->vifid, key_index, pairwise);
+ if (ret) {
+ if (ret == -ENOENT) {
+ pr_debug("VIF%u.%u: key index %d out of bounds\n",
+ vif->mac->macid, vif->vifid, key_index);
+ } else {
+ pr_err("VIF%u.%u: failed to delete key: idx=%u pw=%u\n",
+ vif->mac->macid, vif->vifid,
+ key_index, pairwise);
+ }
+ }
return ret;
}
@@ -590,6 +611,7 @@ qtnf_del_station(struct wiphy *wiphy, struct net_device *dev,
if (ret)
pr_err("VIF%u.%u: failed to delete STA %pM\n",
vif->mac->macid, vif->vifid, params->mac);
+
return ret;
}
@@ -597,21 +619,25 @@ static int
qtnf_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
{
struct qtnf_wmac *mac = wiphy_priv(wiphy);
+ int ret;
cancel_delayed_work_sync(&mac->scan_timeout);
mac->scan_req = request;
- if (qtnf_cmd_send_scan(mac)) {
+ ret = qtnf_cmd_send_scan(mac);
+ if (ret) {
pr_err("MAC%u: failed to start scan\n", mac->macid);
mac->scan_req = NULL;
- return -EFAULT;
+ goto out;
}
+ pr_debug("MAC%u: scan started\n", mac->macid);
queue_delayed_work(mac->bus->workqueue, &mac->scan_timeout,
QTNF_SCAN_TIMEOUT_SEC * HZ);
- return 0;
+out:
+ return ret;
}
static int
@@ -624,9 +650,6 @@ qtnf_connect(struct wiphy *wiphy, struct net_device *dev,
if (vif->wdev.iftype != NL80211_IFTYPE_STATION)
return -EOPNOTSUPP;
- if (vif->sta_state != QTNF_STA_DISCONNECTED)
- return -EBUSY;
-
if (sme->bssid)
ether_addr_copy(vif->bssid, sme->bssid);
else
@@ -634,13 +657,13 @@ qtnf_connect(struct wiphy *wiphy, struct net_device *dev,
ret = qtnf_cmd_send_connect(vif, sme);
if (ret) {
- pr_err("VIF%u.%u: failed to connect\n", vif->mac->macid,
- vif->vifid);
- return ret;
+ pr_err("VIF%u.%u: failed to connect\n",
+ vif->mac->macid, vif->vifid);
+ goto out;
}
- vif->sta_state = QTNF_STA_CONNECTING;
- return 0;
+out:
+ return ret;
}
static int
@@ -662,22 +685,18 @@ qtnf_disconnect(struct wiphy *wiphy, struct net_device *dev,
goto out;
}
- qtnf_scan_done(mac, true);
-
- if (vif->sta_state == QTNF_STA_DISCONNECTED)
- goto out;
-
ret = qtnf_cmd_send_disconnect(vif, reason_code);
- if (ret) {
- pr_err("VIF%u.%u: failed to disconnect\n", mac->macid,
- vif->vifid);
- goto out;
+ if (ret)
+ pr_err("VIF%u.%u: failed to disconnect\n",
+ mac->macid, vif->vifid);
+
+ if (vif->wdev.current_bss) {
+ netif_carrier_off(vif->netdev);
+ cfg80211_disconnected(vif->netdev, reason_code,
+ NULL, 0, true, GFP_KERNEL);
}
out:
- if (vif->sta_state == QTNF_STA_CONNECTING)
- vif->sta_state = QTNF_STA_DISCONNECTED;
-
return ret;
}
@@ -691,11 +710,8 @@ qtnf_dump_survey(struct wiphy *wiphy, struct net_device *dev,
const struct cfg80211_chan_def *chandef = &wdev->chandef;
struct ieee80211_channel *chan;
struct qtnf_chan_stats stats;
- struct qtnf_vif *vif;
int ret;
- vif = qtnf_netdev_get_priv(dev);
-
sband = wiphy->bands[NL80211_BAND_2GHZ];
if (sband && idx >= sband->n_channels) {
idx -= sband->n_channels;
@@ -750,7 +766,6 @@ qtnf_dump_survey(struct wiphy *wiphy, struct net_device *dev,
default:
pr_debug("failed to get chan(%d) stats from card\n",
chan->hw_value);
- ret = -EINVAL;
break;
}
@@ -773,6 +788,7 @@ qtnf_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
ret = qtnf_cmd_get_channel(vif, chandef);
if (ret) {
pr_err("%s: failed to get channel: %d\n", ndev->name, ret);
+ ret = -ENODATA;
goto out;
}
@@ -782,6 +798,7 @@ qtnf_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
chandef->center_freq1, chandef->center_freq2,
chandef->width);
ret = -ENODATA;
+ goto out;
}
out:
@@ -851,10 +868,8 @@ static int qtnf_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
ret = qtnf_cmd_send_pm_set(vif, enabled ? QLINK_PM_AUTO_STANDBY :
QLINK_PM_OFF, timeout);
- if (ret) {
+ if (ret)
pr_err("%s: failed to set PM mode ret=%d\n", dev->name, ret);
- return ret;
- }
return ret;
}
@@ -974,9 +989,16 @@ static void qtnf_cfg80211_reg_notifier(struct wiphy *wiphy_in,
ret = qtnf_cmd_reg_notify(bus, req);
if (ret) {
- if (ret != -EOPNOTSUPP && ret != -EALREADY)
+ if (ret == -EOPNOTSUPP) {
+ pr_warn("reg update not supported\n");
+ } else if (ret == -EALREADY) {
+ pr_info("regulatory domain is already set to %c%c",
+ req->alpha2[0], req->alpha2[1]);
+ } else {
pr_err("failed to update reg domain to %c%c\n",
req->alpha2[0], req->alpha2[1]);
+ }
+
return;
}
@@ -1091,6 +1113,10 @@ int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac)
if (hw_info->hw_capab & QLINK_HW_CAPAB_DFS_OFFLOAD)
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_DFS_OFFLOAD);
+ if (hw_info->hw_capab & QLINK_HW_CAPAB_SCAN_DWELL)
+ wiphy_ext_feature_set(wiphy,
+ NL80211_EXT_FEATURE_SET_SCAN_DWELL);
+
wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2;
@@ -1109,6 +1135,9 @@ int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac)
if (hw_info->hw_capab & QLINK_HW_CAPAB_SCAN_RANDOM_MAC_ADDR)
wiphy->features |= NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
+ if (!(hw_info->hw_capab & QLINK_HW_CAPAB_OBSS_SCAN))
+ wiphy->features |= NL80211_FEATURE_NEED_OBSS_SCAN;
+
#ifdef CONFIG_PM
if (macinfo->wowlan)
wiphy->wowlan = macinfo->wowlan;
@@ -1123,6 +1152,15 @@ int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac)
wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED;
}
+ if (mac->macinfo.extended_capabilities_len) {
+ wiphy->extended_capabilities =
+ mac->macinfo.extended_capabilities;
+ wiphy->extended_capabilities_mask =
+ mac->macinfo.extended_capabilities_mask;
+ wiphy->extended_capabilities_len =
+ mac->macinfo.extended_capabilities_len;
+ }
+
strlcpy(wiphy->fw_version, hw_info->fw_version,
sizeof(wiphy->fw_version));
wiphy->hw_version = hw_info->hw_version;
@@ -1146,7 +1184,8 @@ void qtnf_netdev_updown(struct net_device *ndev, bool up)
struct qtnf_vif *vif = qtnf_netdev_get_priv(ndev);
if (qtnf_cmd_send_updown_intf(vif, up))
- pr_err("failed to send up/down command to FW\n");
+ pr_err("failed to send %s command to VIF%u.%u\n",
+ up ? "UP" : "DOWN", vif->mac->macid, vif->vifid);
}
void qtnf_virtual_intf_cleanup(struct net_device *ndev)
@@ -1154,57 +1193,20 @@ void qtnf_virtual_intf_cleanup(struct net_device *ndev)
struct qtnf_vif *vif = qtnf_netdev_get_priv(ndev);
struct qtnf_wmac *mac = wiphy_priv(vif->wdev.wiphy);
- if (vif->wdev.iftype == NL80211_IFTYPE_STATION) {
- switch (vif->sta_state) {
- case QTNF_STA_DISCONNECTED:
- break;
- case QTNF_STA_CONNECTING:
- cfg80211_connect_result(vif->netdev,
- vif->bssid, NULL, 0,
- NULL, 0,
- WLAN_STATUS_UNSPECIFIED_FAILURE,
- GFP_KERNEL);
- qtnf_disconnect(vif->wdev.wiphy, ndev,
- WLAN_REASON_DEAUTH_LEAVING);
- break;
- case QTNF_STA_CONNECTED:
- cfg80211_disconnected(vif->netdev,
- WLAN_REASON_DEAUTH_LEAVING,
- NULL, 0, 1, GFP_KERNEL);
- qtnf_disconnect(vif->wdev.wiphy, ndev,
- WLAN_REASON_DEAUTH_LEAVING);
- break;
- }
-
- vif->sta_state = QTNF_STA_DISCONNECTED;
- }
+ if (vif->wdev.iftype == NL80211_IFTYPE_STATION)
+ qtnf_disconnect(vif->wdev.wiphy, ndev,
+ WLAN_REASON_DEAUTH_LEAVING);
qtnf_scan_done(mac, true);
}
void qtnf_cfg80211_vif_reset(struct qtnf_vif *vif)
{
- if (vif->wdev.iftype == NL80211_IFTYPE_STATION) {
- switch (vif->sta_state) {
- case QTNF_STA_CONNECTING:
- cfg80211_connect_result(vif->netdev,
- vif->bssid, NULL, 0,
- NULL, 0,
- WLAN_STATUS_UNSPECIFIED_FAILURE,
- GFP_KERNEL);
- break;
- case QTNF_STA_CONNECTED:
- cfg80211_disconnected(vif->netdev,
- WLAN_REASON_DEAUTH_LEAVING,
- NULL, 0, 1, GFP_KERNEL);
- break;
- case QTNF_STA_DISCONNECTED:
- break;
- }
- }
+ if (vif->wdev.iftype == NL80211_IFTYPE_STATION)
+ cfg80211_disconnected(vif->netdev, WLAN_REASON_DEAUTH_LEAVING,
+ NULL, 0, 1, GFP_KERNEL);
cfg80211_shutdown_all_interfaces(vif->wdev.wiphy);
- vif->sta_state = QTNF_STA_DISCONNECTED;
}
void qtnf_band_init_rates(struct ieee80211_supported_band *band)
diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c b/drivers/net/wireless/quantenna/qtnfmac/commands.c
index ae9e77300533..bfdc1ad30c13 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/commands.c
+++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c
@@ -80,7 +80,6 @@ static int qtnf_cmd_resp_result_decode(enum qlink_cmd_result qcode)
static int qtnf_cmd_send_with_reply(struct qtnf_bus *bus,
struct sk_buff *cmd_skb,
struct sk_buff **response_skb,
- u16 *result_code,
size_t const_resp_size,
size_t *var_resp_size)
{
@@ -88,7 +87,8 @@ static int qtnf_cmd_send_with_reply(struct qtnf_bus *bus,
const struct qlink_resp *resp;
struct sk_buff *resp_skb = NULL;
u16 cmd_id;
- u8 mac_id, vif_id;
+ u8 mac_id;
+ u8 vif_id;
int ret;
cmd = (struct qlink_cmd *)cmd_skb->data;
@@ -97,8 +97,11 @@ static int qtnf_cmd_send_with_reply(struct qtnf_bus *bus,
vif_id = cmd->vifid;
cmd->mhdr.len = cpu_to_le16(cmd_skb->len);
- if (unlikely(bus->fw_state != QTNF_FW_STATE_ACTIVE &&
- le16_to_cpu(cmd->cmd_id) != QLINK_CMD_FW_INIT)) {
+ pr_debug("VIF%u.%u cmd=0x%.4X\n", mac_id, vif_id,
+ le16_to_cpu(cmd->cmd_id));
+
+ if (bus->fw_state != QTNF_FW_STATE_ACTIVE &&
+ le16_to_cpu(cmd->cmd_id) != QLINK_CMD_FW_INIT) {
pr_warn("VIF%u.%u: drop cmd 0x%.4X in fw state %d\n",
mac_id, vif_id, le16_to_cpu(cmd->cmd_id),
bus->fw_state);
@@ -106,24 +109,16 @@ static int qtnf_cmd_send_with_reply(struct qtnf_bus *bus,
return -ENODEV;
}
- pr_debug("VIF%u.%u cmd=0x%.4X\n", mac_id, vif_id,
- le16_to_cpu(cmd->cmd_id));
-
ret = qtnf_trans_send_cmd_with_resp(bus, cmd_skb, &resp_skb);
-
- if (unlikely(ret))
+ if (ret)
goto out;
resp = (const struct qlink_resp *)resp_skb->data;
ret = qtnf_cmd_check_reply_header(resp, cmd_id, mac_id, vif_id,
const_resp_size);
-
- if (unlikely(ret))
+ if (ret)
goto out;
- if (likely(result_code))
- *result_code = le16_to_cpu(resp->result);
-
/* Return length of variable part of response */
if (response_skb && var_resp_size)
*var_resp_size = le16_to_cpu(resp->mhdr.len) - const_resp_size;
@@ -134,14 +129,18 @@ out:
else
consume_skb(resp_skb);
+ if (!ret && resp)
+ return qtnf_cmd_resp_result_decode(le16_to_cpu(resp->result));
+
+ pr_warn("VIF%u.%u: cmd 0x%.4X failed: %d\n",
+ mac_id, vif_id, le16_to_cpu(cmd->cmd_id), ret);
+
return ret;
}
-static inline int qtnf_cmd_send(struct qtnf_bus *bus,
- struct sk_buff *cmd_skb,
- u16 *result_code)
+static inline int qtnf_cmd_send(struct qtnf_bus *bus, struct sk_buff *cmd_skb)
{
- return qtnf_cmd_send_with_reply(bus, cmd_skb, NULL, result_code,
+ return qtnf_cmd_send_with_reply(bus, cmd_skb, NULL,
sizeof(struct qlink_resp), NULL);
}
@@ -228,7 +227,6 @@ int qtnf_cmd_send_start_ap(struct qtnf_vif *vif,
struct sk_buff *cmd_skb;
struct qlink_cmd_start_ap *cmd;
struct qlink_auth_encr *aen;
- u16 res_code = QLINK_CMD_RESULT_OK;
int ret;
int i;
@@ -329,30 +327,21 @@ int qtnf_cmd_send_start_ap(struct qtnf_vif *vif,
}
qtnf_bus_lock(vif->mac->bus);
-
- ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code);
-
- if (unlikely(ret))
- goto out;
-
- if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
- pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid,
- vif->vifid, res_code);
- ret = -EFAULT;
+ ret = qtnf_cmd_send(vif->mac->bus, cmd_skb);
+ if (ret)
goto out;
- }
netif_carrier_on(vif->netdev);
out:
qtnf_bus_unlock(vif->mac->bus);
+
return ret;
}
int qtnf_cmd_send_stop_ap(struct qtnf_vif *vif)
{
struct sk_buff *cmd_skb;
- u16 res_code = QLINK_CMD_RESULT_OK;
int ret;
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
@@ -362,23 +351,13 @@ int qtnf_cmd_send_stop_ap(struct qtnf_vif *vif)
return -ENOMEM;
qtnf_bus_lock(vif->mac->bus);
-
- ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code);
-
- if (unlikely(ret))
- goto out;
-
- if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
- pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid,
- vif->vifid, res_code);
- ret = -EFAULT;
+ ret = qtnf_cmd_send(vif->mac->bus, cmd_skb);
+ if (ret)
goto out;
- }
-
- netif_carrier_off(vif->netdev);
out:
qtnf_bus_unlock(vif->mac->bus);
+
return ret;
}
@@ -386,7 +365,6 @@ int qtnf_cmd_send_register_mgmt(struct qtnf_vif *vif, u16 frame_type, bool reg)
{
struct sk_buff *cmd_skb;
struct qlink_cmd_mgmt_frame_register *cmd;
- u16 res_code = QLINK_CMD_RESULT_OK;
int ret;
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
@@ -401,20 +379,13 @@ int qtnf_cmd_send_register_mgmt(struct qtnf_vif *vif, u16 frame_type, bool reg)
cmd->frame_type = cpu_to_le16(frame_type);
cmd->do_register = reg;
- ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code);
-
- if (unlikely(ret))
- goto out;
-
- if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
- pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid,
- vif->vifid, res_code);
- ret = -EFAULT;
+ ret = qtnf_cmd_send(vif->mac->bus, cmd_skb);
+ if (ret)
goto out;
- }
out:
qtnf_bus_unlock(vif->mac->bus);
+
return ret;
}
@@ -423,7 +394,6 @@ int qtnf_cmd_send_mgmt_frame(struct qtnf_vif *vif, u32 cookie, u16 flags,
{
struct sk_buff *cmd_skb;
struct qlink_cmd_mgmt_frame_tx *cmd;
- u16 res_code = QLINK_CMD_RESULT_OK;
int ret;
if (sizeof(*cmd) + len > QTNF_MAX_CMD_BUF_SIZE) {
@@ -448,20 +418,13 @@ int qtnf_cmd_send_mgmt_frame(struct qtnf_vif *vif, u32 cookie, u16 flags,
if (len && buf)
qtnf_cmd_skb_put_buffer(cmd_skb, buf, len);
- ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code);
-
- if (unlikely(ret))
+ ret = qtnf_cmd_send(vif->mac->bus, cmd_skb);
+ if (ret)
goto out;
- if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
- pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid,
- vif->vifid, res_code);
- ret = -EFAULT;
- goto out;
- }
-
out:
qtnf_bus_unlock(vif->mac->bus);
+
return ret;
}
@@ -469,7 +432,6 @@ int qtnf_cmd_send_mgmt_set_appie(struct qtnf_vif *vif, u8 frame_type,
const u8 *buf, size_t len)
{
struct sk_buff *cmd_skb;
- u16 res_code = QLINK_CMD_RESULT_OK;
int ret;
if (len > QTNF_MAX_CMD_BUF_SIZE) {
@@ -487,21 +449,13 @@ int qtnf_cmd_send_mgmt_set_appie(struct qtnf_vif *vif, u8 frame_type,
qtnf_cmd_tlv_ie_set_add(cmd_skb, frame_type, buf, len);
qtnf_bus_lock(vif->mac->bus);
-
- ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code);
-
- if (unlikely(ret))
- goto out;
-
- if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
- pr_err("VIF%u.%u frame %u: CMD failed: %u\n", vif->mac->macid,
- vif->vifid, frame_type, res_code);
- ret = -EFAULT;
+ ret = qtnf_cmd_send(vif->mac->bus, cmd_skb);
+ if (ret)
goto out;
- }
out:
qtnf_bus_unlock(vif->mac->bus);
+
return ret;
}
@@ -544,6 +498,9 @@ qtnf_sta_info_parse_rate(struct rate_info *rate_dst,
rate_dst->flags |= RATE_INFO_FLAGS_MCS;
else if (rate_src->flags & QLINK_STA_INFO_RATE_FLAG_VHT_MCS)
rate_dst->flags |= RATE_INFO_FLAGS_VHT_MCS;
+
+ if (rate_src->flags & QLINK_STA_INFO_RATE_FLAG_SHORT_GI)
+ rate_dst->flags |= RATE_INFO_FLAGS_SHORT_GI;
}
static void
@@ -730,7 +687,6 @@ int qtnf_cmd_get_sta_info(struct qtnf_vif *vif, const u8 *sta_mac,
struct qlink_cmd_get_sta_info *cmd;
const struct qlink_resp_get_sta_info *resp;
size_t var_resp_len;
- u16 res_code = QLINK_CMD_RESULT_OK;
int ret = 0;
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
@@ -745,31 +701,13 @@ int qtnf_cmd_get_sta_info(struct qtnf_vif *vif, const u8 *sta_mac,
ether_addr_copy(cmd->sta_addr, sta_mac);
ret = qtnf_cmd_send_with_reply(vif->mac->bus, cmd_skb, &resp_skb,
- &res_code, sizeof(*resp),
- &var_resp_len);
-
- if (unlikely(ret))
- goto out;
-
- if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
- switch (res_code) {
- case QLINK_CMD_RESULT_ENOTFOUND:
- pr_warn("VIF%u.%u: %pM STA not found\n",
- vif->mac->macid, vif->vifid, sta_mac);
- ret = -ENOENT;
- break;
- default:
- pr_err("VIF%u.%u: can't get info for %pM: %u\n",
- vif->mac->macid, vif->vifid, sta_mac, res_code);
- ret = -EFAULT;
- break;
- }
+ sizeof(*resp), &var_resp_len);
+ if (ret)
goto out;
- }
resp = (const struct qlink_resp_get_sta_info *)resp_skb->data;
- if (unlikely(!ether_addr_equal(sta_mac, resp->sta_addr))) {
+ if (!ether_addr_equal(sta_mac, resp->sta_addr)) {
pr_err("VIF%u.%u: wrong mac in reply: %pM != %pM\n",
vif->mac->macid, vif->vifid, resp->sta_addr, sta_mac);
ret = -EINVAL;
@@ -795,7 +733,6 @@ static int qtnf_cmd_send_add_change_intf(struct qtnf_vif *vif,
struct sk_buff *cmd_skb, *resp_skb = NULL;
struct qlink_cmd_manage_intf *cmd;
const struct qlink_resp_manage_intf *resp;
- u16 res_code = QLINK_CMD_RESULT_OK;
int ret = 0;
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
@@ -828,17 +765,9 @@ static int qtnf_cmd_send_add_change_intf(struct qtnf_vif *vif,
eth_zero_addr(cmd->intf_info.mac_addr);
ret = qtnf_cmd_send_with_reply(vif->mac->bus, cmd_skb, &resp_skb,
- &res_code, sizeof(*resp), NULL);
-
- if (unlikely(ret))
- goto out;
-
- ret = qtnf_cmd_resp_result_decode(res_code);
- if (ret) {
- pr_err("VIF%u.%u: CMD %d failed: %u\n", vif->mac->macid,
- vif->vifid, cmd_type, res_code);
+ sizeof(*resp), NULL);
+ if (ret)
goto out;
- }
resp = (const struct qlink_resp_manage_intf *)resp_skb->data;
ether_addr_copy(vif->mac_addr, resp->intf_info.mac_addr);
@@ -868,7 +797,6 @@ int qtnf_cmd_send_del_intf(struct qtnf_vif *vif)
{
struct sk_buff *cmd_skb;
struct qlink_cmd_manage_intf *cmd;
- u16 res_code = QLINK_CMD_RESULT_OK;
int ret = 0;
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
@@ -897,17 +825,9 @@ int qtnf_cmd_send_del_intf(struct qtnf_vif *vif)
eth_zero_addr(cmd->intf_info.mac_addr);
- ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code);
-
- if (unlikely(ret))
- goto out;
-
- if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
- pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid,
- vif->vifid, res_code);
- ret = -EFAULT;
+ ret = qtnf_cmd_send(vif->mac->bus, cmd_skb);
+ if (ret)
goto out;
- }
out:
qtnf_bus_unlock(vif->mac->bus);
@@ -1353,8 +1273,7 @@ static int qtnf_parse_variable_mac_info(struct qtnf_wmac *mac,
ext_capa_mask = NULL;
}
- kfree(mac->macinfo.extended_capabilities);
- kfree(mac->macinfo.extended_capabilities_mask);
+ qtnf_mac_ext_caps_free(mac);
mac->macinfo.extended_capabilities = ext_capa;
mac->macinfo.extended_capabilities_mask = ext_capa_mask;
mac->macinfo.extended_capabilities_len = ext_capa_len;
@@ -1732,7 +1651,6 @@ int qtnf_cmd_get_mac_info(struct qtnf_wmac *mac)
struct sk_buff *cmd_skb, *resp_skb = NULL;
const struct qlink_resp_get_mac_info *resp;
size_t var_data_len;
- u16 res_code = QLINK_CMD_RESULT_OK;
int ret = 0;
cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, QLINK_VIFID_RSVD,
@@ -1742,18 +1660,11 @@ int qtnf_cmd_get_mac_info(struct qtnf_wmac *mac)
return -ENOMEM;
qtnf_bus_lock(mac->bus);
-
- ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, &res_code,
+ ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb,
sizeof(*resp), &var_data_len);
- if (unlikely(ret))
+ if (ret)
goto out;
- if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
- pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code);
- ret = -EFAULT;
- goto out;
- }
-
resp = (const struct qlink_resp_get_mac_info *)resp_skb->data;
qtnf_cmd_resp_proc_mac_info(mac, resp);
ret = qtnf_parse_variable_mac_info(mac, resp->var_info, var_data_len);
@@ -1769,7 +1680,6 @@ int qtnf_cmd_get_hw_info(struct qtnf_bus *bus)
{
struct sk_buff *cmd_skb, *resp_skb = NULL;
const struct qlink_resp_get_hw_info *resp;
- u16 res_code = QLINK_CMD_RESULT_OK;
int ret = 0;
size_t info_len;
@@ -1780,18 +1690,10 @@ int qtnf_cmd_get_hw_info(struct qtnf_bus *bus)
return -ENOMEM;
qtnf_bus_lock(bus);
-
- ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb, &res_code,
+ ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb,
sizeof(*resp), &info_len);
-
- if (unlikely(ret))
- goto out;
-
- if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
- pr_err("cmd exec failed: 0x%.4X\n", res_code);
- ret = -EFAULT;
+ if (ret)
goto out;
- }
resp = (const struct qlink_resp_get_hw_info *)resp_skb->data;
ret = qtnf_cmd_resp_proc_hw_info(bus, resp, info_len);
@@ -1810,7 +1712,6 @@ int qtnf_cmd_band_info_get(struct qtnf_wmac *mac,
size_t info_len;
struct qlink_cmd_band_info_get *cmd;
struct qlink_resp_band_info_get *resp;
- u16 res_code = QLINK_CMD_RESULT_OK;
int ret = 0;
u8 qband;
@@ -1838,18 +1739,10 @@ int qtnf_cmd_band_info_get(struct qtnf_wmac *mac,
cmd->band = qband;
qtnf_bus_lock(mac->bus);
-
- ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, &res_code,
+ ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb,
sizeof(*resp), &info_len);
-
- if (unlikely(ret))
- goto out;
-
- if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
- pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code);
- ret = -EFAULT;
+ if (ret)
goto out;
- }
resp = (struct qlink_resp_band_info_get *)resp_skb->data;
if (resp->band != qband) {
@@ -1873,7 +1766,6 @@ int qtnf_cmd_send_get_phy_params(struct qtnf_wmac *mac)
struct sk_buff *cmd_skb, *resp_skb = NULL;
size_t response_size;
struct qlink_resp_phy_params *resp;
- u16 res_code = QLINK_CMD_RESULT_OK;
int ret = 0;
cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, 0,
@@ -1883,19 +1775,11 @@ int qtnf_cmd_send_get_phy_params(struct qtnf_wmac *mac)
return -ENOMEM;
qtnf_bus_lock(mac->bus);
-
- ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, &res_code,
+ ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb,
sizeof(*resp), &response_size);
-
- if (unlikely(ret))
+ if (ret)
goto out;
- if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
- pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code);
- ret = -EFAULT;
- goto out;
- }
-
resp = (struct qlink_resp_phy_params *)resp_skb->data;
ret = qtnf_cmd_resp_proc_phy_params(mac, resp->info, response_size);
@@ -1910,7 +1794,6 @@ int qtnf_cmd_send_update_phy_params(struct qtnf_wmac *mac, u32 changed)
{
struct wiphy *wiphy = priv_to_wiphy(mac);
struct sk_buff *cmd_skb;
- u16 res_code = QLINK_CMD_RESULT_OK;
int ret = 0;
cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, 0,
@@ -1931,26 +1814,19 @@ int qtnf_cmd_send_update_phy_params(struct qtnf_wmac *mac, u32 changed)
qtnf_cmd_skb_put_tlv_u8(cmd_skb, QTN_TLV_ID_COVERAGE_CLASS,
wiphy->coverage_class);
- ret = qtnf_cmd_send(mac->bus, cmd_skb, &res_code);
-
- if (unlikely(ret))
- goto out;
-
- if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
- pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code);
- ret = -EFAULT;
+ ret = qtnf_cmd_send(mac->bus, cmd_skb);
+ if (ret)
goto out;
- }
out:
qtnf_bus_unlock(mac->bus);
+
return ret;
}
int qtnf_cmd_send_init_fw(struct qtnf_bus *bus)
{
struct sk_buff *cmd_skb;
- u16 res_code = QLINK_CMD_RESULT_OK;
int ret = 0;
cmd_skb = qtnf_cmd_alloc_new_cmdskb(QLINK_MACID_RSVD, QLINK_VIFID_RSVD,
@@ -1960,20 +1836,13 @@ int qtnf_cmd_send_init_fw(struct qtnf_bus *bus)
return -ENOMEM;
qtnf_bus_lock(bus);
-
- ret = qtnf_cmd_send(bus, cmd_skb, &res_code);
-
- if (unlikely(ret))
+ ret = qtnf_cmd_send(bus, cmd_skb);
+ if (ret)
goto out;
- if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
- pr_err("cmd exec failed: 0x%.4X\n", res_code);
- ret = -EFAULT;
- goto out;
- }
-
out:
qtnf_bus_unlock(bus);
+
return ret;
}
@@ -1988,9 +1857,7 @@ void qtnf_cmd_send_deinit_fw(struct qtnf_bus *bus)
return;
qtnf_bus_lock(bus);
-
- qtnf_cmd_send(bus, cmd_skb, NULL);
-
+ qtnf_cmd_send(bus, cmd_skb);
qtnf_bus_unlock(bus);
}
@@ -1999,7 +1866,6 @@ int qtnf_cmd_send_add_key(struct qtnf_vif *vif, u8 key_index, bool pairwise,
{
struct sk_buff *cmd_skb;
struct qlink_cmd_add_key *cmd;
- u16 res_code = QLINK_CMD_RESULT_OK;
int ret = 0;
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
@@ -2031,19 +1897,13 @@ int qtnf_cmd_send_add_key(struct qtnf_vif *vif, u8 key_index, bool pairwise,
params->seq,
params->seq_len);
- ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code);
- if (unlikely(ret))
+ ret = qtnf_cmd_send(vif->mac->bus, cmd_skb);
+ if (ret)
goto out;
- if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
- pr_err("VIF%u.%u: CMD failed: %u\n",
- vif->mac->macid, vif->vifid, res_code);
- ret = -EFAULT;
- goto out;
- }
-
out:
qtnf_bus_unlock(vif->mac->bus);
+
return ret;
}
@@ -2052,7 +1912,6 @@ int qtnf_cmd_send_del_key(struct qtnf_vif *vif, u8 key_index, bool pairwise,
{
struct sk_buff *cmd_skb;
struct qlink_cmd_del_key *cmd;
- u16 res_code = QLINK_CMD_RESULT_OK;
int ret = 0;
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
@@ -2072,19 +1931,14 @@ int qtnf_cmd_send_del_key(struct qtnf_vif *vif, u8 key_index, bool pairwise,
cmd->key_index = key_index;
cmd->pairwise = pairwise;
- ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code);
- if (unlikely(ret))
- goto out;
- if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
- pr_err("VIF%u.%u: CMD failed: %u\n",
- vif->mac->macid, vif->vifid, res_code);
- ret = -EFAULT;
+ ret = qtnf_cmd_send(vif->mac->bus, cmd_skb);
+ if (ret)
goto out;
- }
out:
qtnf_bus_unlock(vif->mac->bus);
+
return ret;
}
@@ -2093,7 +1947,6 @@ int qtnf_cmd_send_set_default_key(struct qtnf_vif *vif, u8 key_index,
{
struct sk_buff *cmd_skb;
struct qlink_cmd_set_def_key *cmd;
- u16 res_code = QLINK_CMD_RESULT_OK;
int ret = 0;
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
@@ -2108,19 +1961,14 @@ int qtnf_cmd_send_set_default_key(struct qtnf_vif *vif, u8 key_index,
cmd->key_index = key_index;
cmd->unicast = unicast;
cmd->multicast = multicast;
- ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code);
- if (unlikely(ret))
- goto out;
- if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
- pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid,
- vif->vifid, res_code);
- ret = -EFAULT;
+ ret = qtnf_cmd_send(vif->mac->bus, cmd_skb);
+ if (ret)
goto out;
- }
out:
qtnf_bus_unlock(vif->mac->bus);
+
return ret;
}
@@ -2128,7 +1976,6 @@ int qtnf_cmd_send_set_default_mgmt_key(struct qtnf_vif *vif, u8 key_index)
{
struct sk_buff *cmd_skb;
struct qlink_cmd_set_def_mgmt_key *cmd;
- u16 res_code = QLINK_CMD_RESULT_OK;
int ret = 0;
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
@@ -2141,19 +1988,14 @@ int qtnf_cmd_send_set_default_mgmt_key(struct qtnf_vif *vif, u8 key_index)
cmd = (struct qlink_cmd_set_def_mgmt_key *)cmd_skb->data;
cmd->key_index = key_index;
- ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code);
- if (unlikely(ret))
- goto out;
- if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
- pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid,
- vif->vifid, res_code);
- ret = -EFAULT;
+ ret = qtnf_cmd_send(vif->mac->bus, cmd_skb);
+ if (ret)
goto out;
- }
out:
qtnf_bus_unlock(vif->mac->bus);
+
return ret;
}
@@ -2183,7 +2025,6 @@ int qtnf_cmd_send_change_sta(struct qtnf_vif *vif, const u8 *mac,
{
struct sk_buff *cmd_skb;
struct qlink_cmd_change_sta *cmd;
- u16 res_code = QLINK_CMD_RESULT_OK;
int ret = 0;
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
@@ -2214,19 +2055,13 @@ int qtnf_cmd_send_change_sta(struct qtnf_vif *vif, const u8 *mac,
goto out;
}
- ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code);
- if (unlikely(ret))
- goto out;
-
- if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
- pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid,
- vif->vifid, res_code);
- ret = -EFAULT;
+ ret = qtnf_cmd_send(vif->mac->bus, cmd_skb);
+ if (ret)
goto out;
- }
out:
qtnf_bus_unlock(vif->mac->bus);
+
return ret;
}
@@ -2235,7 +2070,6 @@ int qtnf_cmd_send_del_sta(struct qtnf_vif *vif,
{
struct sk_buff *cmd_skb;
struct qlink_cmd_del_sta *cmd;
- u16 res_code = QLINK_CMD_RESULT_OK;
int ret = 0;
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
@@ -2256,19 +2090,13 @@ int qtnf_cmd_send_del_sta(struct qtnf_vif *vif,
cmd->subtype = params->subtype;
cmd->reason_code = cpu_to_le16(params->reason_code);
- ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code);
- if (unlikely(ret))
+ ret = qtnf_cmd_send(vif->mac->bus, cmd_skb);
+ if (ret)
goto out;
- if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
- pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid,
- vif->vifid, res_code);
- ret = -EFAULT;
- goto out;
- }
-
out:
qtnf_bus_unlock(vif->mac->bus);
+
return ret;
}
@@ -2312,7 +2140,6 @@ static void qtnf_cmd_randmac_tlv_add(struct sk_buff *cmd_skb,
int qtnf_cmd_send_scan(struct qtnf_wmac *mac)
{
struct sk_buff *cmd_skb;
- u16 res_code = QLINK_CMD_RESULT_OK;
struct ieee80211_channel *sc;
struct cfg80211_scan_request *scan_req = mac->scan_req;
int n_channels;
@@ -2370,20 +2197,28 @@ int qtnf_cmd_send_scan(struct qtnf_wmac *mac)
scan_req->mac_addr_mask);
}
- ret = qtnf_cmd_send(mac->bus, cmd_skb, &res_code);
+ if (scan_req->flags & NL80211_SCAN_FLAG_FLUSH) {
+ pr_debug("MAC%u: flush cache before scan\n", mac->macid);
- if (unlikely(ret))
- goto out;
+ qtnf_cmd_skb_put_tlv_tag(cmd_skb, QTN_TLV_ID_SCAN_FLUSH);
+ }
- pr_debug("MAC%u: scan started\n", mac->macid);
+ if (scan_req->duration) {
+ pr_debug("MAC%u: %s scan duration %u\n", mac->macid,
+ scan_req->duration_mandatory ? "mandatory" : "max",
+ scan_req->duration);
- if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
- pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code);
- ret = -EFAULT;
- goto out;
+ qtnf_cmd_skb_put_tlv_u16(cmd_skb, QTN_TLV_ID_SCAN_DWELL,
+ scan_req->duration);
}
+
+ ret = qtnf_cmd_send(mac->bus, cmd_skb);
+ if (ret)
+ goto out;
+
out:
qtnf_bus_unlock(mac->bus);
+
return ret;
}
@@ -2393,7 +2228,6 @@ int qtnf_cmd_send_connect(struct qtnf_vif *vif,
struct sk_buff *cmd_skb;
struct qlink_cmd_connect *cmd;
struct qlink_auth_encr *aen;
- u16 res_code = QLINK_CMD_RESULT_OK;
int ret;
int i;
u32 connect_flags = 0;
@@ -2474,20 +2308,13 @@ int qtnf_cmd_send_connect(struct qtnf_vif *vif,
qtnf_cmd_channel_tlv_add(cmd_skb, sme->channel);
qtnf_bus_lock(vif->mac->bus);
-
- ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code);
-
- if (unlikely(ret))
+ ret = qtnf_cmd_send(vif->mac->bus, cmd_skb);
+ if (ret)
goto out;
- if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
- pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid,
- vif->vifid, res_code);
- ret = -EFAULT;
- goto out;
- }
out:
qtnf_bus_unlock(vif->mac->bus);
+
return ret;
}
@@ -2495,7 +2322,6 @@ int qtnf_cmd_send_disconnect(struct qtnf_vif *vif, u16 reason_code)
{
struct sk_buff *cmd_skb;
struct qlink_cmd_disconnect *cmd;
- u16 res_code = QLINK_CMD_RESULT_OK;
int ret;
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
@@ -2509,19 +2335,13 @@ int qtnf_cmd_send_disconnect(struct qtnf_vif *vif, u16 reason_code)
cmd = (struct qlink_cmd_disconnect *)cmd_skb->data;
cmd->reason = cpu_to_le16(reason_code);
- ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code);
-
- if (unlikely(ret))
+ ret = qtnf_cmd_send(vif->mac->bus, cmd_skb);
+ if (ret)
goto out;
- if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
- pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid,
- vif->vifid, res_code);
- ret = -EFAULT;
- goto out;
- }
out:
qtnf_bus_unlock(vif->mac->bus);
+
return ret;
}
@@ -2529,7 +2349,6 @@ int qtnf_cmd_send_updown_intf(struct qtnf_vif *vif, bool up)
{
struct sk_buff *cmd_skb;
struct qlink_cmd_updown *cmd;
- u16 res_code = QLINK_CMD_RESULT_OK;
int ret;
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
@@ -2542,20 +2361,13 @@ int qtnf_cmd_send_updown_intf(struct qtnf_vif *vif, bool up)
cmd->if_up = !!up;
qtnf_bus_lock(vif->mac->bus);
-
- ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code);
-
- if (unlikely(ret))
+ ret = qtnf_cmd_send(vif->mac->bus, cmd_skb);
+ if (ret)
goto out;
- if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
- pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid,
- vif->vifid, res_code);
- ret = -EFAULT;
- goto out;
- }
out:
qtnf_bus_unlock(vif->mac->bus);
+
return ret;
}
@@ -2563,7 +2375,6 @@ int qtnf_cmd_reg_notify(struct qtnf_bus *bus, struct regulatory_request *req)
{
struct sk_buff *cmd_skb;
int ret;
- u16 res_code;
struct qlink_cmd_reg_notify *cmd;
cmd_skb = qtnf_cmd_alloc_new_cmdskb(QLINK_MACID_RSVD, QLINK_VIFID_RSVD,
@@ -2604,29 +2415,10 @@ int qtnf_cmd_reg_notify(struct qtnf_bus *bus, struct regulatory_request *req)
}
qtnf_bus_lock(bus);
-
- ret = qtnf_cmd_send(bus, cmd_skb, &res_code);
+ ret = qtnf_cmd_send(bus, cmd_skb);
if (ret)
goto out;
- switch (res_code) {
- case QLINK_CMD_RESULT_ENOTSUPP:
- pr_warn("reg update not supported\n");
- ret = -EOPNOTSUPP;
- break;
- case QLINK_CMD_RESULT_EALREADY:
- pr_info("regulatory domain is already set to %c%c",
- req->alpha2[0], req->alpha2[1]);
- ret = -EALREADY;
- break;
- case QLINK_CMD_RESULT_OK:
- ret = 0;
- break;
- default:
- ret = -EFAULT;
- break;
- }
-
out:
qtnf_bus_unlock(bus);
@@ -2640,7 +2432,6 @@ int qtnf_cmd_get_chan_stats(struct qtnf_wmac *mac, u16 channel,
struct qlink_cmd_get_chan_stats *cmd;
struct qlink_resp_get_chan_stats *resp;
size_t var_data_len;
- u16 res_code = QLINK_CMD_RESULT_OK;
int ret = 0;
cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, QLINK_VIFID_RSVD,
@@ -2654,25 +2445,10 @@ int qtnf_cmd_get_chan_stats(struct qtnf_wmac *mac, u16 channel,
cmd = (struct qlink_cmd_get_chan_stats *)cmd_skb->data;
cmd->channel = cpu_to_le16(channel);
- ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, &res_code,
+ ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb,
sizeof(*resp), &var_data_len);
- if (unlikely(ret)) {
- qtnf_bus_unlock(mac->bus);
- return ret;
- }
-
- if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
- switch (res_code) {
- case QLINK_CMD_RESULT_ENOTFOUND:
- ret = -ENOENT;
- break;
- default:
- pr_err("cmd exec failed: 0x%.4X\n", res_code);
- ret = -EFAULT;
- break;
- }
+ if (ret)
goto out;
- }
resp = (struct qlink_resp_get_chan_stats *)resp_skb->data;
ret = qtnf_cmd_resp_proc_chan_stat_info(stats, resp->info,
@@ -2681,6 +2457,7 @@ int qtnf_cmd_get_chan_stats(struct qtnf_wmac *mac, u16 channel,
out:
qtnf_bus_unlock(mac->bus);
consume_skb(resp_skb);
+
return ret;
}
@@ -2690,7 +2467,6 @@ int qtnf_cmd_send_chan_switch(struct qtnf_vif *vif,
struct qtnf_wmac *mac = vif->mac;
struct qlink_cmd_chan_switch *cmd;
struct sk_buff *cmd_skb;
- u16 res_code = QLINK_CMD_RESULT_OK;
int ret;
cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, vif->vifid,
@@ -2707,32 +2483,13 @@ int qtnf_cmd_send_chan_switch(struct qtnf_vif *vif,
cmd->block_tx = params->block_tx;
cmd->beacon_count = params->count;
- ret = qtnf_cmd_send(mac->bus, cmd_skb, &res_code);
-
- if (unlikely(ret))
+ ret = qtnf_cmd_send(mac->bus, cmd_skb);
+ if (ret)
goto out;
- switch (res_code) {
- case QLINK_CMD_RESULT_OK:
- ret = 0;
- break;
- case QLINK_CMD_RESULT_ENOTFOUND:
- ret = -ENOENT;
- break;
- case QLINK_CMD_RESULT_ENOTSUPP:
- ret = -EOPNOTSUPP;
- break;
- case QLINK_CMD_RESULT_EALREADY:
- ret = -EALREADY;
- break;
- case QLINK_CMD_RESULT_INVALID:
- default:
- ret = -EFAULT;
- break;
- }
-
out:
qtnf_bus_unlock(mac->bus);
+
return ret;
}
@@ -2742,7 +2499,6 @@ int qtnf_cmd_get_channel(struct qtnf_vif *vif, struct cfg80211_chan_def *chdef)
const struct qlink_resp_channel_get *resp;
struct sk_buff *cmd_skb;
struct sk_buff *resp_skb = NULL;
- u16 res_code = QLINK_CMD_RESULT_OK;
int ret;
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
@@ -2752,25 +2508,18 @@ int qtnf_cmd_get_channel(struct qtnf_vif *vif, struct cfg80211_chan_def *chdef)
return -ENOMEM;
qtnf_bus_lock(bus);
-
- ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb, &res_code,
+ ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb,
sizeof(*resp), NULL);
-
- qtnf_bus_unlock(bus);
-
- if (unlikely(ret))
+ if (ret)
goto out;
- if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
- ret = -ENODATA;
- goto out;
- }
-
resp = (const struct qlink_resp_channel_get *)resp_skb->data;
qlink_chandef_q2cfg(priv_to_wiphy(vif->mac), &resp->chan, chdef);
out:
+ qtnf_bus_unlock(bus);
consume_skb(resp_skb);
+
return ret;
}
@@ -2782,7 +2531,6 @@ int qtnf_cmd_start_cac(const struct qtnf_vif *vif,
struct sk_buff *cmd_skb;
struct qlink_cmd_start_cac *cmd;
int ret;
- u16 res_code;
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_START_CAC,
@@ -2795,19 +2543,12 @@ int qtnf_cmd_start_cac(const struct qtnf_vif *vif,
qlink_chandef_cfg2q(chdef, &cmd->chan);
qtnf_bus_lock(bus);
- ret = qtnf_cmd_send(bus, cmd_skb, &res_code);
- qtnf_bus_unlock(bus);
-
+ ret = qtnf_cmd_send(bus, cmd_skb);
if (ret)
- return ret;
+ goto out;
- switch (res_code) {
- case QLINK_CMD_RESULT_OK:
- break;
- default:
- ret = -EOPNOTSUPP;
- break;
- }
+out:
+ qtnf_bus_unlock(bus);
return ret;
}
@@ -2819,7 +2560,6 @@ int qtnf_cmd_set_mac_acl(const struct qtnf_vif *vif,
struct sk_buff *cmd_skb;
struct qlink_tlv_hdr *tlv;
size_t acl_size = qtnf_cmd_acl_data_size(params);
- u16 res_code;
int ret;
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
@@ -2834,22 +2574,12 @@ int qtnf_cmd_set_mac_acl(const struct qtnf_vif *vif,
qlink_acl_data_cfg2q(params, (struct qlink_acl_data *)tlv->val);
qtnf_bus_lock(bus);
- ret = qtnf_cmd_send(bus, cmd_skb, &res_code);
- qtnf_bus_unlock(bus);
-
- if (unlikely(ret))
- return ret;
+ ret = qtnf_cmd_send(bus, cmd_skb);
+ if (ret)
+ goto out;
- switch (res_code) {
- case QLINK_CMD_RESULT_OK:
- break;
- case QLINK_CMD_RESULT_INVALID:
- ret = -EINVAL;
- break;
- default:
- ret = -EOPNOTSUPP;
- break;
- }
+out:
+ qtnf_bus_unlock(bus);
return ret;
}
@@ -2858,7 +2588,6 @@ int qtnf_cmd_send_pm_set(const struct qtnf_vif *vif, u8 pm_mode, int timeout)
{
struct qtnf_bus *bus = vif->mac->bus;
struct sk_buff *cmd_skb;
- u16 res_code = QLINK_CMD_RESULT_OK;
struct qlink_cmd_pm_set *cmd;
int ret = 0;
@@ -2873,18 +2602,13 @@ int qtnf_cmd_send_pm_set(const struct qtnf_vif *vif, u8 pm_mode, int timeout)
qtnf_bus_lock(bus);
- ret = qtnf_cmd_send(bus, cmd_skb, &res_code);
-
- if (unlikely(ret))
+ ret = qtnf_cmd_send(bus, cmd_skb);
+ if (ret)
goto out;
- if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
- pr_err("cmd exec failed: 0x%.4X\n", res_code);
- ret = -EFAULT;
- }
-
out:
qtnf_bus_unlock(bus);
+
return ret;
}
@@ -2893,7 +2617,6 @@ int qtnf_cmd_send_wowlan_set(const struct qtnf_vif *vif,
{
struct qtnf_bus *bus = vif->mac->bus;
struct sk_buff *cmd_skb;
- u16 res_code = QLINK_CMD_RESULT_OK;
struct qlink_cmd_wowlan_set *cmd;
u32 triggers = 0;
int count = 0;
@@ -2929,16 +2652,10 @@ int qtnf_cmd_send_wowlan_set(const struct qtnf_vif *vif,
cmd->triggers = cpu_to_le32(triggers);
- ret = qtnf_cmd_send(bus, cmd_skb, &res_code);
-
- if (unlikely(ret))
+ ret = qtnf_cmd_send(bus, cmd_skb);
+ if (ret)
goto out;
- if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
- pr_err("cmd exec failed: 0x%.4X\n", res_code);
- ret = -EFAULT;
- }
-
out:
qtnf_bus_unlock(bus);
return ret;
diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.c b/drivers/net/wireless/quantenna/qtnfmac/core.c
index 19abbc4e23e0..5d18a4a917c9 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/core.c
+++ b/drivers/net/wireless/quantenna/qtnfmac/core.c
@@ -304,6 +304,19 @@ void qtnf_mac_iface_comb_free(struct qtnf_wmac *mac)
}
}
+void qtnf_mac_ext_caps_free(struct qtnf_wmac *mac)
+{
+ if (mac->macinfo.extended_capabilities_len) {
+ kfree(mac->macinfo.extended_capabilities);
+ mac->macinfo.extended_capabilities = NULL;
+
+ kfree(mac->macinfo.extended_capabilities_mask);
+ mac->macinfo.extended_capabilities_mask = NULL;
+
+ mac->macinfo.extended_capabilities_len = 0;
+ }
+}
+
static void qtnf_vif_reset_handler(struct work_struct *work)
{
struct qtnf_vif *vif = container_of(work, struct qtnf_vif, reset_work);
@@ -370,6 +383,7 @@ static void qtnf_mac_scan_timeout(struct work_struct *work)
static struct qtnf_wmac *qtnf_core_mac_alloc(struct qtnf_bus *bus,
unsigned int macid)
{
+ struct qtnf_vif *vif;
struct wiphy *wiphy;
struct qtnf_wmac *mac;
unsigned int i;
@@ -382,18 +396,20 @@ static struct qtnf_wmac *qtnf_core_mac_alloc(struct qtnf_bus *bus,
mac->macid = macid;
mac->bus = bus;
+ mutex_init(&mac->mac_lock);
+ INIT_DELAYED_WORK(&mac->scan_timeout, qtnf_mac_scan_timeout);
for (i = 0; i < QTNF_MAX_INTF; i++) {
- memset(&mac->iflist[i], 0, sizeof(struct qtnf_vif));
- mac->iflist[i].wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
- mac->iflist[i].mac = mac;
- mac->iflist[i].vifid = i;
- qtnf_sta_list_init(&mac->iflist[i].sta_list);
- mutex_init(&mac->mac_lock);
- INIT_DELAYED_WORK(&mac->scan_timeout, qtnf_mac_scan_timeout);
- mac->iflist[i].stats64 =
- netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
- if (!mac->iflist[i].stats64)
+ vif = &mac->iflist[i];
+
+ memset(vif, 0, sizeof(*vif));
+ vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
+ vif->mac = mac;
+ vif->vifid = i;
+ qtnf_sta_list_init(&vif->sta_list);
+
+ vif->stats64 = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
+ if (!vif->stats64)
pr_warn("VIF%u.%u: per cpu stats allocation failed\n",
macid, i);
}
@@ -493,8 +509,7 @@ static void qtnf_core_mac_detach(struct qtnf_bus *bus, unsigned int macid)
}
qtnf_mac_iface_comb_free(mac);
- kfree(mac->macinfo.extended_capabilities);
- kfree(mac->macinfo.extended_capabilities_mask);
+ qtnf_mac_ext_caps_free(mac);
kfree(mac->macinfo.wowlan);
wiphy_free(wiphy);
bus->mac[macid] = NULL;
diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.h b/drivers/net/wireless/quantenna/qtnfmac/core.h
index a1e338a1f055..293055049caa 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/core.h
+++ b/drivers/net/wireless/quantenna/qtnfmac/core.h
@@ -64,12 +64,6 @@ struct qtnf_sta_list {
atomic_t size;
};
-enum qtnf_sta_state {
- QTNF_STA_DISCONNECTED,
- QTNF_STA_CONNECTING,
- QTNF_STA_CONNECTED
-};
-
struct qtnf_vif {
struct wireless_dev wdev;
u8 bssid[ETH_ALEN];
@@ -77,7 +71,6 @@ struct qtnf_vif {
u8 vifid;
u8 bss_priority;
u8 bss_status;
- enum qtnf_sta_state sta_state;
u16 mgmt_frames_bitmask;
struct net_device *netdev;
struct qtnf_wmac *mac;
@@ -151,6 +144,7 @@ struct qtnf_hw_info {
struct qtnf_vif *qtnf_mac_get_free_vif(struct qtnf_wmac *mac);
struct qtnf_vif *qtnf_mac_get_base_vif(struct qtnf_wmac *mac);
void qtnf_mac_iface_comb_free(struct qtnf_wmac *mac);
+void qtnf_mac_ext_caps_free(struct qtnf_wmac *mac);
struct wiphy *qtnf_wiphy_allocate(struct qtnf_bus *bus);
int qtnf_core_net_attach(struct qtnf_wmac *mac, struct qtnf_vif *priv,
const char *name, unsigned char name_assign_type);
diff --git a/drivers/net/wireless/quantenna/qtnfmac/event.c b/drivers/net/wireless/quantenna/qtnfmac/event.c
index 68da81bec4e9..8b542b431b75 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/event.c
+++ b/drivers/net/wireless/quantenna/qtnfmac/event.c
@@ -171,24 +171,14 @@ qtnf_event_handle_bss_join(struct qtnf_vif *vif,
return -EPROTO;
}
- if (vif->sta_state != QTNF_STA_CONNECTING) {
- pr_err("VIF%u.%u: BSS_JOIN event when STA is not connecting\n",
- vif->mac->macid, vif->vifid);
- return -EPROTO;
- }
-
pr_debug("VIF%u.%u: BSSID:%pM\n", vif->mac->macid, vif->vifid,
join_info->bssid);
cfg80211_connect_result(vif->netdev, join_info->bssid, NULL, 0, NULL,
0, le16_to_cpu(join_info->status), GFP_KERNEL);
- if (le16_to_cpu(join_info->status) == WLAN_STATUS_SUCCESS) {
- vif->sta_state = QTNF_STA_CONNECTED;
+ if (le16_to_cpu(join_info->status) == WLAN_STATUS_SUCCESS)
netif_carrier_on(vif->netdev);
- } else {
- vif->sta_state = QTNF_STA_DISCONNECTED;
- }
return 0;
}
@@ -211,16 +201,10 @@ qtnf_event_handle_bss_leave(struct qtnf_vif *vif,
return -EPROTO;
}
- if (vif->sta_state != QTNF_STA_CONNECTED)
- pr_warn("VIF%u.%u: BSS_LEAVE event when STA is not connected\n",
- vif->mac->macid, vif->vifid);
-
pr_debug("VIF%u.%u: disconnected\n", vif->mac->macid, vif->vifid);
cfg80211_disconnected(vif->netdev, le16_to_cpu(leave_info->reason),
NULL, 0, 0, GFP_KERNEL);
-
- vif->sta_state = QTNF_STA_DISCONNECTED;
netif_carrier_off(vif->netdev);
return 0;
diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c
new file mode 100644
index 000000000000..16795dbe475b
--- /dev/null
+++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c
@@ -0,0 +1,392 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Copyright (c) 2018 Quantenna Communications, Inc. All rights reserved. */
+
+#include <linux/printk.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/netdevice.h>
+#include <linux/seq_file.h>
+#include <linux/workqueue.h>
+#include <linux/completion.h>
+
+#include "pcie_priv.h"
+#include "bus.h"
+#include "shm_ipc.h"
+#include "core.h"
+#include "debug.h"
+
+#undef pr_fmt
+#define pr_fmt(fmt) "qtnf_pcie: %s: " fmt, __func__
+
+#define QTN_SYSCTL_BAR 0
+#define QTN_SHMEM_BAR 2
+#define QTN_DMA_BAR 3
+
+int qtnf_pcie_control_tx(struct qtnf_bus *bus, struct sk_buff *skb)
+{
+ struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus);
+ int ret;
+
+ ret = qtnf_shm_ipc_send(&priv->shm_ipc_ep_in, skb->data, skb->len);
+
+ if (ret == -ETIMEDOUT) {
+ pr_err("EP firmware is dead\n");
+ bus->fw_state = QTNF_FW_STATE_EP_DEAD;
+ }
+
+ return ret;
+}
+
+int qtnf_pcie_alloc_skb_array(struct qtnf_pcie_bus_priv *priv)
+{
+ struct sk_buff **vaddr;
+ int len;
+
+ len = priv->tx_bd_num * sizeof(*priv->tx_skb) +
+ priv->rx_bd_num * sizeof(*priv->rx_skb);
+ vaddr = devm_kzalloc(&priv->pdev->dev, len, GFP_KERNEL);
+
+ if (!vaddr)
+ return -ENOMEM;
+
+ priv->tx_skb = vaddr;
+
+ vaddr += priv->tx_bd_num;
+ priv->rx_skb = vaddr;
+
+ return 0;
+}
+
+void qtnf_pcie_bringup_fw_async(struct qtnf_bus *bus)
+{
+ struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus);
+ struct pci_dev *pdev = priv->pdev;
+
+ get_device(&pdev->dev);
+ schedule_work(&bus->fw_work);
+}
+
+static int qtnf_dbg_mps_show(struct seq_file *s, void *data)
+{
+ struct qtnf_bus *bus = dev_get_drvdata(s->private);
+ struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus);
+
+ seq_printf(s, "%d\n", priv->mps);
+
+ return 0;
+}
+
+static int qtnf_dbg_msi_show(struct seq_file *s, void *data)
+{
+ struct qtnf_bus *bus = dev_get_drvdata(s->private);
+ struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus);
+
+ seq_printf(s, "%u\n", priv->msi_enabled);
+
+ return 0;
+}
+
+static int qtnf_dbg_shm_stats(struct seq_file *s, void *data)
+{
+ struct qtnf_bus *bus = dev_get_drvdata(s->private);
+ struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus);
+
+ seq_printf(s, "shm_ipc_ep_in.tx_packet_count(%zu)\n",
+ priv->shm_ipc_ep_in.tx_packet_count);
+ seq_printf(s, "shm_ipc_ep_in.rx_packet_count(%zu)\n",
+ priv->shm_ipc_ep_in.rx_packet_count);
+ seq_printf(s, "shm_ipc_ep_out.tx_packet_count(%zu)\n",
+ priv->shm_ipc_ep_out.tx_timeout_count);
+ seq_printf(s, "shm_ipc_ep_out.rx_packet_count(%zu)\n",
+ priv->shm_ipc_ep_out.rx_packet_count);
+
+ return 0;
+}
+
+void qtnf_pcie_fw_boot_done(struct qtnf_bus *bus, bool boot_success,
+ const char *drv_name)
+{
+ struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus);
+ struct pci_dev *pdev = priv->pdev;
+ int ret;
+
+ if (boot_success) {
+ bus->fw_state = QTNF_FW_STATE_FW_DNLD_DONE;
+
+ ret = qtnf_core_attach(bus);
+ if (ret) {
+ pr_err("failed to attach core\n");
+ boot_success = false;
+ }
+ }
+
+ if (boot_success) {
+ qtnf_debugfs_init(bus, drv_name);
+ qtnf_debugfs_add_entry(bus, "mps", qtnf_dbg_mps_show);
+ qtnf_debugfs_add_entry(bus, "msi_enabled", qtnf_dbg_msi_show);
+ qtnf_debugfs_add_entry(bus, "shm_stats", qtnf_dbg_shm_stats);
+ } else {
+ bus->fw_state = QTNF_FW_STATE_DETACHED;
+ }
+
+ put_device(&pdev->dev);
+}
+
+static void qtnf_tune_pcie_mps(struct qtnf_pcie_bus_priv *priv)
+{
+ struct pci_dev *pdev = priv->pdev;
+ struct pci_dev *parent;
+ int mps_p, mps_o, mps_m, mps;
+ int ret;
+
+ /* current mps */
+ mps_o = pcie_get_mps(pdev);
+
+ /* maximum supported mps */
+ mps_m = 128 << pdev->pcie_mpss;
+
+ /* suggested new mps value */
+ mps = mps_m;
+
+ if (pdev->bus && pdev->bus->self) {
+ /* parent (bus) mps */
+ parent = pdev->bus->self;
+
+ if (pci_is_pcie(parent)) {
+ mps_p = pcie_get_mps(parent);
+ mps = min(mps_m, mps_p);
+ }
+ }
+
+ ret = pcie_set_mps(pdev, mps);
+ if (ret) {
+ pr_err("failed to set mps to %d, keep using current %d\n",
+ mps, mps_o);
+ priv->mps = mps_o;
+ return;
+ }
+
+ pr_debug("set mps to %d (was %d, max %d)\n", mps, mps_o, mps_m);
+ priv->mps = mps;
+}
+
+static void qtnf_pcie_init_irq(struct qtnf_pcie_bus_priv *priv, bool use_msi)
+{
+ struct pci_dev *pdev = priv->pdev;
+
+ /* fall back to legacy INTx interrupts by default */
+ priv->msi_enabled = 0;
+
+ /* check if MSI capability is available */
+ if (use_msi) {
+ if (!pci_enable_msi(pdev)) {
+ pr_debug("enabled MSI interrupt\n");
+ priv->msi_enabled = 1;
+ } else {
+ pr_warn("failed to enable MSI interrupts");
+ }
+ }
+
+ if (!priv->msi_enabled) {
+ pr_warn("legacy PCIE interrupts enabled\n");
+ pci_intx(pdev, 1);
+ }
+}
+
+static void __iomem *qtnf_map_bar(struct qtnf_pcie_bus_priv *priv, u8 index)
+{
+ void __iomem *vaddr;
+ dma_addr_t busaddr;
+ size_t len;
+ int ret;
+
+ ret = pcim_iomap_regions(priv->pdev, 1 << index, "qtnfmac_pcie");
+ if (ret)
+ return IOMEM_ERR_PTR(ret);
+
+ busaddr = pci_resource_start(priv->pdev, index);
+ len = pci_resource_len(priv->pdev, index);
+ vaddr = pcim_iomap_table(priv->pdev)[index];
+ if (!vaddr)
+ return IOMEM_ERR_PTR(-ENOMEM);
+
+ pr_debug("BAR%u vaddr=0x%p busaddr=%pad len=%u\n",
+ index, vaddr, &busaddr, (int)len);
+
+ return vaddr;
+}
+
+static int qtnf_pcie_init_memory(struct qtnf_pcie_bus_priv *priv)
+{
+ int ret = -ENOMEM;
+
+ priv->sysctl_bar = qtnf_map_bar(priv, QTN_SYSCTL_BAR);
+ if (IS_ERR(priv->sysctl_bar)) {
+ pr_err("failed to map BAR%u\n", QTN_SYSCTL_BAR);
+ return ret;
+ }
+
+ priv->dmareg_bar = qtnf_map_bar(priv, QTN_DMA_BAR);
+ if (IS_ERR(priv->dmareg_bar)) {
+ pr_err("failed to map BAR%u\n", QTN_DMA_BAR);
+ return ret;
+ }
+
+ priv->epmem_bar = qtnf_map_bar(priv, QTN_SHMEM_BAR);
+ if (IS_ERR(priv->epmem_bar)) {
+ pr_err("failed to map BAR%u\n", QTN_SHMEM_BAR);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void qtnf_pcie_control_rx_callback(void *arg, const u8 __iomem *buf,
+ size_t len)
+{
+ struct qtnf_pcie_bus_priv *priv = arg;
+ struct qtnf_bus *bus = pci_get_drvdata(priv->pdev);
+ struct sk_buff *skb;
+
+ if (unlikely(len == 0)) {
+ pr_warn("zero length packet received\n");
+ return;
+ }
+
+ skb = __dev_alloc_skb(len, GFP_KERNEL);
+
+ if (unlikely(!skb)) {
+ pr_err("failed to allocate skb\n");
+ return;
+ }
+
+ memcpy_fromio(skb_put(skb, len), buf, len);
+
+ qtnf_trans_handle_rx_ctl_packet(bus, skb);
+}
+
+void qtnf_pcie_init_shm_ipc(struct qtnf_pcie_bus_priv *priv,
+ struct qtnf_shm_ipc_region __iomem *ipc_tx_reg,
+ struct qtnf_shm_ipc_region __iomem *ipc_rx_reg,
+ const struct qtnf_shm_ipc_int *ipc_int)
+{
+ const struct qtnf_shm_ipc_rx_callback rx_callback = {
+ qtnf_pcie_control_rx_callback, priv };
+
+ qtnf_shm_ipc_init(&priv->shm_ipc_ep_in, QTNF_SHM_IPC_OUTBOUND,
+ ipc_tx_reg, priv->workqueue,
+ ipc_int, &rx_callback);
+ qtnf_shm_ipc_init(&priv->shm_ipc_ep_out, QTNF_SHM_IPC_INBOUND,
+ ipc_rx_reg, priv->workqueue,
+ ipc_int, &rx_callback);
+}
+
+int qtnf_pcie_probe(struct pci_dev *pdev, size_t priv_size,
+ const struct qtnf_bus_ops *bus_ops, u64 dma_mask,
+ bool use_msi)
+{
+ struct qtnf_pcie_bus_priv *pcie_priv;
+ struct qtnf_bus *bus;
+ int ret;
+
+ bus = devm_kzalloc(&pdev->dev,
+ sizeof(*bus) + priv_size, GFP_KERNEL);
+ if (!bus)
+ return -ENOMEM;
+
+ pcie_priv = get_bus_priv(bus);
+
+ pci_set_drvdata(pdev, bus);
+ bus->bus_ops = bus_ops;
+ bus->dev = &pdev->dev;
+ bus->fw_state = QTNF_FW_STATE_RESET;
+ pcie_priv->pdev = pdev;
+ pcie_priv->tx_stopped = 0;
+
+ mutex_init(&bus->bus_lock);
+ spin_lock_init(&pcie_priv->tx_lock);
+ spin_lock_init(&pcie_priv->tx_reclaim_lock);
+
+ pcie_priv->tx_full_count = 0;
+ pcie_priv->tx_done_count = 0;
+ pcie_priv->pcie_irq_count = 0;
+ pcie_priv->tx_reclaim_done = 0;
+ pcie_priv->tx_reclaim_req = 0;
+
+ pcie_priv->workqueue = create_singlethread_workqueue("QTNF_PCIE");
+ if (!pcie_priv->workqueue) {
+ pr_err("failed to alloc bus workqueue\n");
+ ret = -ENODEV;
+ goto err_init;
+ }
+
+ init_dummy_netdev(&bus->mux_dev);
+
+ if (!pci_is_pcie(pdev)) {
+ pr_err("device %s is not PCI Express\n", pci_name(pdev));
+ ret = -EIO;
+ goto err_base;
+ }
+
+ qtnf_tune_pcie_mps(pcie_priv);
+
+ ret = pcim_enable_device(pdev);
+ if (ret) {
+ pr_err("failed to init PCI device %x\n", pdev->device);
+ goto err_base;
+ } else {
+ pr_debug("successful init of PCI device %x\n", pdev->device);
+ }
+
+ ret = dma_set_mask_and_coherent(&pdev->dev, dma_mask);
+ if (ret) {
+ pr_err("PCIE DMA coherent mask init failed\n");
+ goto err_base;
+ }
+
+ pci_set_master(pdev);
+ qtnf_pcie_init_irq(pcie_priv, use_msi);
+
+ ret = qtnf_pcie_init_memory(pcie_priv);
+ if (ret < 0) {
+ pr_err("PCIE memory init failed\n");
+ goto err_base;
+ }
+
+ pci_save_state(pdev);
+
+ return 0;
+
+err_base:
+ flush_workqueue(pcie_priv->workqueue);
+ destroy_workqueue(pcie_priv->workqueue);
+err_init:
+ pci_set_drvdata(pdev, NULL);
+
+ return ret;
+}
+
+static void qtnf_pcie_free_shm_ipc(struct qtnf_pcie_bus_priv *priv)
+{
+ qtnf_shm_ipc_free(&priv->shm_ipc_ep_in);
+ qtnf_shm_ipc_free(&priv->shm_ipc_ep_out);
+}
+
+void qtnf_pcie_remove(struct qtnf_bus *bus, struct qtnf_pcie_bus_priv *priv)
+{
+ cancel_work_sync(&bus->fw_work);
+
+ if (bus->fw_state == QTNF_FW_STATE_ACTIVE ||
+ bus->fw_state == QTNF_FW_STATE_EP_DEAD)
+ qtnf_core_detach(bus);
+
+ netif_napi_del(&bus->mux_napi);
+ flush_workqueue(priv->workqueue);
+ destroy_workqueue(priv->workqueue);
+ tasklet_kill(&priv->reclaim_tq);
+
+ qtnf_pcie_free_shm_ipc(priv);
+ qtnf_debugfs_remove(bus);
+ pci_set_drvdata(priv->pdev, NULL);
+}
diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie_priv.h b/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie_priv.h
new file mode 100644
index 000000000000..5c70fb4c0f92
--- /dev/null
+++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie_priv.h
@@ -0,0 +1,85 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Copyright (c) 2018 Quantenna Communications, Inc. All rights reserved. */
+
+#ifndef _QTN_FMAC_PCIE_H_
+#define _QTN_FMAC_PCIE_H_
+
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/skbuff.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+
+#include "shm_ipc.h"
+#include "bus.h"
+
+#define SKB_BUF_SIZE 2048
+
+#define QTN_FW_DL_TIMEOUT_MS 3000
+#define QTN_FW_QLINK_TIMEOUT_MS 30000
+#define QTN_EP_RESET_WAIT_MS 1000
+
+struct qtnf_pcie_bus_priv {
+ struct pci_dev *pdev;
+
+ spinlock_t tx_reclaim_lock;
+ spinlock_t tx_lock;
+ int mps;
+
+ struct workqueue_struct *workqueue;
+ struct tasklet_struct reclaim_tq;
+
+ void __iomem *sysctl_bar;
+ void __iomem *epmem_bar;
+ void __iomem *dmareg_bar;
+
+ struct qtnf_shm_ipc shm_ipc_ep_in;
+ struct qtnf_shm_ipc shm_ipc_ep_out;
+
+ u16 tx_bd_num;
+ u16 rx_bd_num;
+
+ struct sk_buff **tx_skb;
+ struct sk_buff **rx_skb;
+
+ u32 rx_bd_w_index;
+ u32 rx_bd_r_index;
+
+ u32 tx_bd_w_index;
+ u32 tx_bd_r_index;
+
+ /* diagnostics stats */
+ u32 pcie_irq_count;
+ u32 tx_full_count;
+ u32 tx_done_count;
+ u32 tx_reclaim_done;
+ u32 tx_reclaim_req;
+
+ u8 msi_enabled;
+ u8 tx_stopped;
+};
+
+int qtnf_pcie_control_tx(struct qtnf_bus *bus, struct sk_buff *skb);
+int qtnf_pcie_alloc_skb_array(struct qtnf_pcie_bus_priv *priv);
+void qtnf_pcie_bringup_fw_async(struct qtnf_bus *bus);
+void qtnf_pcie_fw_boot_done(struct qtnf_bus *bus, bool boot_success,
+ const char *drv_name);
+void qtnf_pcie_init_shm_ipc(struct qtnf_pcie_bus_priv *priv,
+ struct qtnf_shm_ipc_region __iomem *ipc_tx_reg,
+ struct qtnf_shm_ipc_region __iomem *ipc_rx_reg,
+ const struct qtnf_shm_ipc_int *ipc_int);
+int qtnf_pcie_probe(struct pci_dev *pdev, size_t priv_size,
+ const struct qtnf_bus_ops *bus_ops, u64 dma_mask,
+ bool use_msi);
+void qtnf_pcie_remove(struct qtnf_bus *bus, struct qtnf_pcie_bus_priv *priv);
+
+static inline void qtnf_non_posted_write(u32 val, void __iomem *basereg)
+{
+ writel(val, basereg);
+
+ /* flush posted write */
+ readl(basereg);
+}
+
+#endif /* _QTN_FMAC_PCIE_H_ */
diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c
new file mode 100644
index 000000000000..95c7b95c6f8a
--- /dev/null
+++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c
@@ -0,0 +1,1249 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Copyright (c) 2018 Quantenna Communications */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/firmware.h>
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/completion.h>
+#include <linux/crc32.h>
+#include <linux/spinlock.h>
+#include <linux/circ_buf.h>
+#include <linux/log2.h>
+
+#include "pcie_priv.h"
+#include "pearl_pcie_regs.h"
+#include "pearl_pcie_ipc.h"
+#include "qtn_hw_ids.h"
+#include "core.h"
+#include "bus.h"
+#include "shm_ipc.h"
+#include "debug.h"
+
+static bool use_msi = true;
+module_param(use_msi, bool, 0644);
+MODULE_PARM_DESC(use_msi, "set 0 to use legacy interrupt");
+
+static unsigned int tx_bd_size_param = 32;
+module_param(tx_bd_size_param, uint, 0644);
+MODULE_PARM_DESC(tx_bd_size_param, "Tx descriptors queue size, power of two");
+
+static unsigned int rx_bd_size_param = 256;
+module_param(rx_bd_size_param, uint, 0644);
+MODULE_PARM_DESC(rx_bd_size_param, "Rx descriptors queue size, power of two");
+
+static u8 flashboot = 1;
+module_param(flashboot, byte, 0644);
+MODULE_PARM_DESC(flashboot, "set to 0 to use FW binary file on FS");
+
+#define DRV_NAME "qtnfmac_pearl_pcie"
+
+struct qtnf_pearl_bda {
+ __le16 bda_len;
+ __le16 bda_version;
+ __le32 bda_pci_endian;
+ __le32 bda_ep_state;
+ __le32 bda_rc_state;
+ __le32 bda_dma_mask;
+ __le32 bda_msi_addr;
+ __le32 bda_flashsz;
+ u8 bda_boardname[PCIE_BDA_NAMELEN];
+ __le32 bda_rc_msi_enabled;
+ u8 bda_hhbm_list[PCIE_HHBM_MAX_SIZE];
+ __le32 bda_dsbw_start_index;
+ __le32 bda_dsbw_end_index;
+ __le32 bda_dsbw_total_bytes;
+ __le32 bda_rc_tx_bd_base;
+ __le32 bda_rc_tx_bd_num;
+ u8 bda_pcie_mac[QTN_ENET_ADDR_LENGTH];
+ struct qtnf_shm_ipc_region bda_shm_reg1 __aligned(4096); /* host TX */
+ struct qtnf_shm_ipc_region bda_shm_reg2 __aligned(4096); /* host RX */
+} __packed;
+
+struct qtnf_pearl_tx_bd {
+ __le32 addr;
+ __le32 addr_h;
+ __le32 info;
+ __le32 info_h;
+} __packed;
+
+struct qtnf_pearl_rx_bd {
+ __le32 addr;
+ __le32 addr_h;
+ __le32 info;
+ __le32 info_h;
+ __le32 next_ptr;
+ __le32 next_ptr_h;
+} __packed;
+
+struct qtnf_pearl_fw_hdr {
+ u8 boardflg[8];
+ __le32 fwsize;
+ __le32 seqnum;
+ __le32 type;
+ __le32 pktlen;
+ __le32 crc;
+} __packed;
+
+struct qtnf_pcie_pearl_state {
+ struct qtnf_pcie_bus_priv base;
+
+ /* lock for irq configuration changes */
+ spinlock_t irq_lock;
+
+ struct qtnf_pearl_bda __iomem *bda;
+ void __iomem *pcie_reg_base;
+
+ struct qtnf_pearl_tx_bd *tx_bd_vbase;
+ dma_addr_t tx_bd_pbase;
+
+ struct qtnf_pearl_rx_bd *rx_bd_vbase;
+ dma_addr_t rx_bd_pbase;
+
+ dma_addr_t bd_table_paddr;
+ void *bd_table_vaddr;
+ u32 bd_table_len;
+ u32 pcie_irq_mask;
+ u32 pcie_irq_rx_count;
+ u32 pcie_irq_tx_count;
+ u32 pcie_irq_uf_count;
+};
+
+static inline void qtnf_init_hdp_irqs(struct qtnf_pcie_pearl_state *ps)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ps->irq_lock, flags);
+ ps->pcie_irq_mask = (PCIE_HDP_INT_RX_BITS | PCIE_HDP_INT_TX_BITS);
+ spin_unlock_irqrestore(&ps->irq_lock, flags);
+}
+
+static inline void qtnf_enable_hdp_irqs(struct qtnf_pcie_pearl_state *ps)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ps->irq_lock, flags);
+ writel(ps->pcie_irq_mask, PCIE_HDP_INT_EN(ps->pcie_reg_base));
+ spin_unlock_irqrestore(&ps->irq_lock, flags);
+}
+
+static inline void qtnf_disable_hdp_irqs(struct qtnf_pcie_pearl_state *ps)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ps->irq_lock, flags);
+ writel(0x0, PCIE_HDP_INT_EN(ps->pcie_reg_base));
+ spin_unlock_irqrestore(&ps->irq_lock, flags);
+}
+
+static inline void qtnf_en_rxdone_irq(struct qtnf_pcie_pearl_state *ps)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ps->irq_lock, flags);
+ ps->pcie_irq_mask |= PCIE_HDP_INT_RX_BITS;
+ writel(ps->pcie_irq_mask, PCIE_HDP_INT_EN(ps->pcie_reg_base));
+ spin_unlock_irqrestore(&ps->irq_lock, flags);
+}
+
+static inline void qtnf_dis_rxdone_irq(struct qtnf_pcie_pearl_state *ps)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ps->irq_lock, flags);
+ ps->pcie_irq_mask &= ~PCIE_HDP_INT_RX_BITS;
+ writel(ps->pcie_irq_mask, PCIE_HDP_INT_EN(ps->pcie_reg_base));
+ spin_unlock_irqrestore(&ps->irq_lock, flags);
+}
+
+static inline void qtnf_en_txdone_irq(struct qtnf_pcie_pearl_state *ps)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ps->irq_lock, flags);
+ ps->pcie_irq_mask |= PCIE_HDP_INT_TX_BITS;
+ writel(ps->pcie_irq_mask, PCIE_HDP_INT_EN(ps->pcie_reg_base));
+ spin_unlock_irqrestore(&ps->irq_lock, flags);
+}
+
+static inline void qtnf_dis_txdone_irq(struct qtnf_pcie_pearl_state *ps)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ps->irq_lock, flags);
+ ps->pcie_irq_mask &= ~PCIE_HDP_INT_TX_BITS;
+ writel(ps->pcie_irq_mask, PCIE_HDP_INT_EN(ps->pcie_reg_base));
+ spin_unlock_irqrestore(&ps->irq_lock, flags);
+}
+
+static void qtnf_deassert_intx(struct qtnf_pcie_pearl_state *ps)
+{
+ void __iomem *reg = ps->base.sysctl_bar + PEARL_PCIE_CFG0_OFFSET;
+ u32 cfg;
+
+ cfg = readl(reg);
+ cfg &= ~PEARL_ASSERT_INTX;
+ qtnf_non_posted_write(cfg, reg);
+}
+
+static void qtnf_pearl_reset_ep(struct qtnf_pcie_pearl_state *ps)
+{
+ const u32 data = QTN_PEARL_IPC_IRQ_WORD(QTN_PEARL_LHOST_EP_RESET);
+ void __iomem *reg = ps->base.sysctl_bar +
+ QTN_PEARL_SYSCTL_LHOST_IRQ_OFFSET;
+
+ qtnf_non_posted_write(data, reg);
+ msleep(QTN_EP_RESET_WAIT_MS);
+ pci_restore_state(ps->base.pdev);
+}
+
+static void qtnf_pcie_pearl_ipc_gen_ep_int(void *arg)
+{
+ const struct qtnf_pcie_pearl_state *ps = arg;
+ const u32 data = QTN_PEARL_IPC_IRQ_WORD(QTN_PEARL_LHOST_IPC_IRQ);
+ void __iomem *reg = ps->base.sysctl_bar +
+ QTN_PEARL_SYSCTL_LHOST_IRQ_OFFSET;
+
+ qtnf_non_posted_write(data, reg);
+}
+
+static int qtnf_is_state(__le32 __iomem *reg, u32 state)
+{
+ u32 s = readl(reg);
+
+ return s & state;
+}
+
+static void qtnf_set_state(__le32 __iomem *reg, u32 state)
+{
+ u32 s = readl(reg);
+
+ qtnf_non_posted_write(state | s, reg);
+}
+
+static void qtnf_clear_state(__le32 __iomem *reg, u32 state)
+{
+ u32 s = readl(reg);
+
+ qtnf_non_posted_write(s & ~state, reg);
+}
+
+static int qtnf_poll_state(__le32 __iomem *reg, u32 state, u32 delay_in_ms)
+{
+ u32 timeout = 0;
+
+ while ((qtnf_is_state(reg, state) == 0)) {
+ usleep_range(1000, 1200);
+ if (++timeout > delay_in_ms)
+ return -1;
+ }
+
+ return 0;
+}
+
+static int pearl_alloc_bd_table(struct qtnf_pcie_pearl_state *ps)
+{
+ struct qtnf_pcie_bus_priv *priv = &ps->base;
+ dma_addr_t paddr;
+ void *vaddr;
+ int len;
+
+ len = priv->tx_bd_num * sizeof(struct qtnf_pearl_tx_bd) +
+ priv->rx_bd_num * sizeof(struct qtnf_pearl_rx_bd);
+
+ vaddr = dmam_alloc_coherent(&priv->pdev->dev, len, &paddr, GFP_KERNEL);
+ if (!vaddr)
+ return -ENOMEM;
+
+ /* tx bd */
+
+ memset(vaddr, 0, len);
+
+ ps->bd_table_vaddr = vaddr;
+ ps->bd_table_paddr = paddr;
+ ps->bd_table_len = len;
+
+ ps->tx_bd_vbase = vaddr;
+ ps->tx_bd_pbase = paddr;
+
+ pr_debug("TX descriptor table: vaddr=0x%p paddr=%pad\n", vaddr, &paddr);
+
+ priv->tx_bd_r_index = 0;
+ priv->tx_bd_w_index = 0;
+
+ /* rx bd */
+
+ vaddr = ((struct qtnf_pearl_tx_bd *)vaddr) + priv->tx_bd_num;
+ paddr += priv->tx_bd_num * sizeof(struct qtnf_pearl_tx_bd);
+
+ ps->rx_bd_vbase = vaddr;
+ ps->rx_bd_pbase = paddr;
+
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+ writel(QTN_HOST_HI32(paddr),
+ PCIE_HDP_TX_HOST_Q_BASE_H(ps->pcie_reg_base));
+#endif
+ writel(QTN_HOST_LO32(paddr),
+ PCIE_HDP_TX_HOST_Q_BASE_L(ps->pcie_reg_base));
+ writel(priv->rx_bd_num | (sizeof(struct qtnf_pearl_rx_bd)) << 16,
+ PCIE_HDP_TX_HOST_Q_SZ_CTRL(ps->pcie_reg_base));
+
+ pr_debug("RX descriptor table: vaddr=0x%p paddr=%pad\n", vaddr, &paddr);
+
+ return 0;
+}
+
+static int pearl_skb2rbd_attach(struct qtnf_pcie_pearl_state *ps, u16 index)
+{
+ struct qtnf_pcie_bus_priv *priv = &ps->base;
+ struct qtnf_pearl_rx_bd *rxbd;
+ struct sk_buff *skb;
+ dma_addr_t paddr;
+
+ skb = __netdev_alloc_skb_ip_align(NULL, SKB_BUF_SIZE, GFP_ATOMIC);
+ if (!skb) {
+ priv->rx_skb[index] = NULL;
+ return -ENOMEM;
+ }
+
+ priv->rx_skb[index] = skb;
+ rxbd = &ps->rx_bd_vbase[index];
+
+ paddr = pci_map_single(priv->pdev, skb->data,
+ SKB_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ if (pci_dma_mapping_error(priv->pdev, paddr)) {
+ pr_err("skb DMA mapping error: %pad\n", &paddr);
+ return -ENOMEM;
+ }
+
+ /* keep rx skb paddrs in rx buffer descriptors for cleanup purposes */
+ rxbd->addr = cpu_to_le32(QTN_HOST_LO32(paddr));
+ rxbd->addr_h = cpu_to_le32(QTN_HOST_HI32(paddr));
+ rxbd->info = 0x0;
+
+ priv->rx_bd_w_index = index;
+
+ /* sync up all descriptor updates */
+ wmb();
+
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+ writel(QTN_HOST_HI32(paddr),
+ PCIE_HDP_HHBM_BUF_PTR_H(ps->pcie_reg_base));
+#endif
+ writel(QTN_HOST_LO32(paddr),
+ PCIE_HDP_HHBM_BUF_PTR(ps->pcie_reg_base));
+
+ writel(index, PCIE_HDP_TX_HOST_Q_WR_PTR(ps->pcie_reg_base));
+ return 0;
+}
+
+static int pearl_alloc_rx_buffers(struct qtnf_pcie_pearl_state *ps)
+{
+ u16 i;
+ int ret = 0;
+
+ memset(ps->rx_bd_vbase, 0x0,
+ ps->base.rx_bd_num * sizeof(struct qtnf_pearl_rx_bd));
+
+ for (i = 0; i < ps->base.rx_bd_num; i++) {
+ ret = pearl_skb2rbd_attach(ps, i);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+/* all rx/tx activity should have ceased before calling this function */
+static void qtnf_pearl_free_xfer_buffers(struct qtnf_pcie_pearl_state *ps)
+{
+ struct qtnf_pcie_bus_priv *priv = &ps->base;
+ struct qtnf_pearl_tx_bd *txbd;
+ struct qtnf_pearl_rx_bd *rxbd;
+ struct sk_buff *skb;
+ dma_addr_t paddr;
+ int i;
+
+ /* free rx buffers */
+ for (i = 0; i < priv->rx_bd_num; i++) {
+ if (priv->rx_skb && priv->rx_skb[i]) {
+ rxbd = &ps->rx_bd_vbase[i];
+ skb = priv->rx_skb[i];
+ paddr = QTN_HOST_ADDR(le32_to_cpu(rxbd->addr_h),
+ le32_to_cpu(rxbd->addr));
+ pci_unmap_single(priv->pdev, paddr, SKB_BUF_SIZE,
+ PCI_DMA_FROMDEVICE);
+ dev_kfree_skb_any(skb);
+ priv->rx_skb[i] = NULL;
+ }
+ }
+
+ /* free tx buffers */
+ for (i = 0; i < priv->tx_bd_num; i++) {
+ if (priv->tx_skb && priv->tx_skb[i]) {
+ txbd = &ps->tx_bd_vbase[i];
+ skb = priv->tx_skb[i];
+ paddr = QTN_HOST_ADDR(le32_to_cpu(txbd->addr_h),
+ le32_to_cpu(txbd->addr));
+ pci_unmap_single(priv->pdev, paddr, skb->len,
+ PCI_DMA_TODEVICE);
+ dev_kfree_skb_any(skb);
+ priv->tx_skb[i] = NULL;
+ }
+ }
+}
+
+static int pearl_hhbm_init(struct qtnf_pcie_pearl_state *ps)
+{
+ u32 val;
+
+ val = readl(PCIE_HHBM_CONFIG(ps->pcie_reg_base));
+ val |= HHBM_CONFIG_SOFT_RESET;
+ writel(val, PCIE_HHBM_CONFIG(ps->pcie_reg_base));
+ usleep_range(50, 100);
+ val &= ~HHBM_CONFIG_SOFT_RESET;
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+ val |= HHBM_64BIT;
+#endif
+ writel(val, PCIE_HHBM_CONFIG(ps->pcie_reg_base));
+ writel(ps->base.rx_bd_num, PCIE_HHBM_Q_LIMIT_REG(ps->pcie_reg_base));
+
+ return 0;
+}
+
+static int qtnf_pcie_pearl_init_xfer(struct qtnf_pcie_pearl_state *ps)
+{
+ struct qtnf_pcie_bus_priv *priv = &ps->base;
+ int ret;
+ u32 val;
+
+ priv->tx_bd_num = tx_bd_size_param;
+ priv->rx_bd_num = rx_bd_size_param;
+ priv->rx_bd_w_index = 0;
+ priv->rx_bd_r_index = 0;
+
+ if (!priv->tx_bd_num || !is_power_of_2(priv->tx_bd_num)) {
+ pr_err("tx_bd_size_param %u is not power of two\n",
+ priv->tx_bd_num);
+ return -EINVAL;
+ }
+
+ val = priv->tx_bd_num * sizeof(struct qtnf_pearl_tx_bd);
+ if (val > PCIE_HHBM_MAX_SIZE) {
+ pr_err("tx_bd_size_param %u is too large\n",
+ priv->tx_bd_num);
+ return -EINVAL;
+ }
+
+ if (!priv->rx_bd_num || !is_power_of_2(priv->rx_bd_num)) {
+ pr_err("rx_bd_size_param %u is not power of two\n",
+ priv->rx_bd_num);
+ return -EINVAL;
+ }
+
+ val = priv->rx_bd_num * sizeof(dma_addr_t);
+ if (val > PCIE_HHBM_MAX_SIZE) {
+ pr_err("rx_bd_size_param %u is too large\n",
+ priv->rx_bd_num);
+ return -EINVAL;
+ }
+
+ ret = pearl_hhbm_init(ps);
+ if (ret) {
+ pr_err("failed to init h/w queues\n");
+ return ret;
+ }
+
+ ret = qtnf_pcie_alloc_skb_array(priv);
+ if (ret) {
+ pr_err("failed to allocate skb array\n");
+ return ret;
+ }
+
+ ret = pearl_alloc_bd_table(ps);
+ if (ret) {
+ pr_err("failed to allocate bd table\n");
+ return ret;
+ }
+
+ ret = pearl_alloc_rx_buffers(ps);
+ if (ret) {
+ pr_err("failed to allocate rx buffers\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+static void qtnf_pearl_data_tx_reclaim(struct qtnf_pcie_pearl_state *ps)
+{
+ struct qtnf_pcie_bus_priv *priv = &ps->base;
+ struct qtnf_pearl_tx_bd *txbd;
+ struct sk_buff *skb;
+ unsigned long flags;
+ dma_addr_t paddr;
+ u32 tx_done_index;
+ int count = 0;
+ int i;
+
+ spin_lock_irqsave(&priv->tx_reclaim_lock, flags);
+
+ tx_done_index = readl(PCIE_HDP_RX0DMA_CNT(ps->pcie_reg_base))
+ & (priv->tx_bd_num - 1);
+
+ i = priv->tx_bd_r_index;
+
+ while (CIRC_CNT(tx_done_index, i, priv->tx_bd_num)) {
+ skb = priv->tx_skb[i];
+ if (likely(skb)) {
+ txbd = &ps->tx_bd_vbase[i];
+ paddr = QTN_HOST_ADDR(le32_to_cpu(txbd->addr_h),
+ le32_to_cpu(txbd->addr));
+ pci_unmap_single(priv->pdev, paddr, skb->len,
+ PCI_DMA_TODEVICE);
+
+ if (skb->dev) {
+ qtnf_update_tx_stats(skb->dev, skb);
+ if (unlikely(priv->tx_stopped)) {
+ qtnf_wake_all_queues(skb->dev);
+ priv->tx_stopped = 0;
+ }
+ }
+
+ dev_kfree_skb_any(skb);
+ }
+
+ priv->tx_skb[i] = NULL;
+ count++;
+
+ if (++i >= priv->tx_bd_num)
+ i = 0;
+ }
+
+ priv->tx_reclaim_done += count;
+ priv->tx_reclaim_req++;
+ priv->tx_bd_r_index = i;
+
+ spin_unlock_irqrestore(&priv->tx_reclaim_lock, flags);
+}
+
+static int qtnf_tx_queue_ready(struct qtnf_pcie_pearl_state *ps)
+{
+ struct qtnf_pcie_bus_priv *priv = &ps->base;
+
+ if (!CIRC_SPACE(priv->tx_bd_w_index, priv->tx_bd_r_index,
+ priv->tx_bd_num)) {
+ qtnf_pearl_data_tx_reclaim(ps);
+
+ if (!CIRC_SPACE(priv->tx_bd_w_index, priv->tx_bd_r_index,
+ priv->tx_bd_num)) {
+ pr_warn_ratelimited("reclaim full Tx queue\n");
+ priv->tx_full_count++;
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int qtnf_pcie_data_tx(struct qtnf_bus *bus, struct sk_buff *skb)
+{
+ struct qtnf_pcie_pearl_state *ps = get_bus_priv(bus);
+ struct qtnf_pcie_bus_priv *priv = &ps->base;
+ dma_addr_t txbd_paddr, skb_paddr;
+ struct qtnf_pearl_tx_bd *txbd;
+ unsigned long flags;
+ int len, i;
+ u32 info;
+ int ret = 0;
+
+ spin_lock_irqsave(&priv->tx_lock, flags);
+
+ if (!qtnf_tx_queue_ready(ps)) {
+ if (skb->dev) {
+ netif_tx_stop_all_queues(skb->dev);
+ priv->tx_stopped = 1;
+ }
+
+ spin_unlock_irqrestore(&priv->tx_lock, flags);
+ return NETDEV_TX_BUSY;
+ }
+
+ i = priv->tx_bd_w_index;
+ priv->tx_skb[i] = skb;
+ len = skb->len;
+
+ skb_paddr = pci_map_single(priv->pdev, skb->data,
+ skb->len, PCI_DMA_TODEVICE);
+ if (pci_dma_mapping_error(priv->pdev, skb_paddr)) {
+ pr_err("skb DMA mapping error: %pad\n", &skb_paddr);
+ ret = -ENOMEM;
+ goto tx_done;
+ }
+
+ txbd = &ps->tx_bd_vbase[i];
+ txbd->addr = cpu_to_le32(QTN_HOST_LO32(skb_paddr));
+ txbd->addr_h = cpu_to_le32(QTN_HOST_HI32(skb_paddr));
+
+ info = (len & QTN_PCIE_TX_DESC_LEN_MASK) << QTN_PCIE_TX_DESC_LEN_SHIFT;
+ txbd->info = cpu_to_le32(info);
+
+ /* sync up all descriptor updates before passing them to EP */
+ dma_wmb();
+
+ /* write new TX descriptor to PCIE_RX_FIFO on EP */
+ txbd_paddr = ps->tx_bd_pbase + i * sizeof(struct qtnf_pearl_tx_bd);
+
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+ writel(QTN_HOST_HI32(txbd_paddr),
+ PCIE_HDP_HOST_WR_DESC0_H(ps->pcie_reg_base));
+#endif
+ writel(QTN_HOST_LO32(txbd_paddr),
+ PCIE_HDP_HOST_WR_DESC0(ps->pcie_reg_base));
+
+ if (++i >= priv->tx_bd_num)
+ i = 0;
+
+ priv->tx_bd_w_index = i;
+
+tx_done:
+ if (ret && skb) {
+ pr_err_ratelimited("drop skb\n");
+ if (skb->dev)
+ skb->dev->stats.tx_dropped++;
+ dev_kfree_skb_any(skb);
+ }
+
+ priv->tx_done_count++;
+ spin_unlock_irqrestore(&priv->tx_lock, flags);
+
+ qtnf_pearl_data_tx_reclaim(ps);
+
+ return NETDEV_TX_OK;
+}
+
+static irqreturn_t qtnf_pcie_pearl_interrupt(int irq, void *data)
+{
+ struct qtnf_bus *bus = (struct qtnf_bus *)data;
+ struct qtnf_pcie_pearl_state *ps = get_bus_priv(bus);
+ struct qtnf_pcie_bus_priv *priv = &ps->base;
+ u32 status;
+
+ priv->pcie_irq_count++;
+ status = readl(PCIE_HDP_INT_STATUS(ps->pcie_reg_base));
+
+ qtnf_shm_ipc_irq_handler(&priv->shm_ipc_ep_in);
+ qtnf_shm_ipc_irq_handler(&priv->shm_ipc_ep_out);
+
+ if (!(status & ps->pcie_irq_mask))
+ goto irq_done;
+
+ if (status & PCIE_HDP_INT_RX_BITS)
+ ps->pcie_irq_rx_count++;
+
+ if (status & PCIE_HDP_INT_TX_BITS)
+ ps->pcie_irq_tx_count++;
+
+ if (status & PCIE_HDP_INT_HHBM_UF)
+ ps->pcie_irq_uf_count++;
+
+ if (status & PCIE_HDP_INT_RX_BITS) {
+ qtnf_dis_rxdone_irq(ps);
+ napi_schedule(&bus->mux_napi);
+ }
+
+ if (status & PCIE_HDP_INT_TX_BITS) {
+ qtnf_dis_txdone_irq(ps);
+ tasklet_hi_schedule(&priv->reclaim_tq);
+ }
+
+irq_done:
+ /* H/W workaround: clean all bits, not only enabled */
+ qtnf_non_posted_write(~0U, PCIE_HDP_INT_STATUS(ps->pcie_reg_base));
+
+ if (!priv->msi_enabled)
+ qtnf_deassert_intx(ps);
+
+ return IRQ_HANDLED;
+}
+
+static int qtnf_rx_data_ready(struct qtnf_pcie_pearl_state *ps)
+{
+ u16 index = ps->base.rx_bd_r_index;
+ struct qtnf_pearl_rx_bd *rxbd;
+ u32 descw;
+
+ rxbd = &ps->rx_bd_vbase[index];
+ descw = le32_to_cpu(rxbd->info);
+
+ if (descw & QTN_TXDONE_MASK)
+ return 1;
+
+ return 0;
+}
+
+static int qtnf_pcie_pearl_rx_poll(struct napi_struct *napi, int budget)
+{
+ struct qtnf_bus *bus = container_of(napi, struct qtnf_bus, mux_napi);
+ struct qtnf_pcie_pearl_state *ps = get_bus_priv(bus);
+ struct qtnf_pcie_bus_priv *priv = &ps->base;
+ struct net_device *ndev = NULL;
+ struct sk_buff *skb = NULL;
+ int processed = 0;
+ struct qtnf_pearl_rx_bd *rxbd;
+ dma_addr_t skb_paddr;
+ int consume;
+ u32 descw;
+ u32 psize;
+ u16 r_idx;
+ u16 w_idx;
+ int ret;
+
+ while (processed < budget) {
+ if (!qtnf_rx_data_ready(ps))
+ goto rx_out;
+
+ r_idx = priv->rx_bd_r_index;
+ rxbd = &ps->rx_bd_vbase[r_idx];
+ descw = le32_to_cpu(rxbd->info);
+
+ skb = priv->rx_skb[r_idx];
+ psize = QTN_GET_LEN(descw);
+ consume = 1;
+
+ if (!(descw & QTN_TXDONE_MASK)) {
+ pr_warn("skip invalid rxbd[%d]\n", r_idx);
+ consume = 0;
+ }
+
+ if (!skb) {
+ pr_warn("skip missing rx_skb[%d]\n", r_idx);
+ consume = 0;
+ }
+
+ if (skb && (skb_tailroom(skb) < psize)) {
+ pr_err("skip packet with invalid length: %u > %u\n",
+ psize, skb_tailroom(skb));
+ consume = 0;
+ }
+
+ if (skb) {
+ skb_paddr = QTN_HOST_ADDR(le32_to_cpu(rxbd->addr_h),
+ le32_to_cpu(rxbd->addr));
+ pci_unmap_single(priv->pdev, skb_paddr, SKB_BUF_SIZE,
+ PCI_DMA_FROMDEVICE);
+ }
+
+ if (consume) {
+ skb_put(skb, psize);
+ ndev = qtnf_classify_skb(bus, skb);
+ if (likely(ndev)) {
+ qtnf_update_rx_stats(ndev, skb);
+ skb->protocol = eth_type_trans(skb, ndev);
+ napi_gro_receive(napi, skb);
+ } else {
+ pr_debug("drop untagged skb\n");
+ bus->mux_dev.stats.rx_dropped++;
+ dev_kfree_skb_any(skb);
+ }
+ } else {
+ if (skb) {
+ bus->mux_dev.stats.rx_dropped++;
+ dev_kfree_skb_any(skb);
+ }
+ }
+
+ priv->rx_skb[r_idx] = NULL;
+ if (++r_idx >= priv->rx_bd_num)
+ r_idx = 0;
+
+ priv->rx_bd_r_index = r_idx;
+
+ /* repalce processed buffer by a new one */
+ w_idx = priv->rx_bd_w_index;
+ while (CIRC_SPACE(priv->rx_bd_w_index, priv->rx_bd_r_index,
+ priv->rx_bd_num) > 0) {
+ if (++w_idx >= priv->rx_bd_num)
+ w_idx = 0;
+
+ ret = pearl_skb2rbd_attach(ps, w_idx);
+ if (ret) {
+ pr_err("failed to allocate new rx_skb[%d]\n",
+ w_idx);
+ break;
+ }
+ }
+
+ processed++;
+ }
+
+rx_out:
+ if (processed < budget) {
+ napi_complete(napi);
+ qtnf_en_rxdone_irq(ps);
+ }
+
+ return processed;
+}
+
+static void
+qtnf_pcie_data_tx_timeout(struct qtnf_bus *bus, struct net_device *ndev)
+{
+ struct qtnf_pcie_pearl_state *ps = (void *)get_bus_priv(bus);
+
+ tasklet_hi_schedule(&ps->base.reclaim_tq);
+}
+
+static void qtnf_pcie_data_rx_start(struct qtnf_bus *bus)
+{
+ struct qtnf_pcie_pearl_state *ps = (void *)get_bus_priv(bus);
+
+ qtnf_enable_hdp_irqs(ps);
+ napi_enable(&bus->mux_napi);
+}
+
+static void qtnf_pcie_data_rx_stop(struct qtnf_bus *bus)
+{
+ struct qtnf_pcie_pearl_state *ps = (void *)get_bus_priv(bus);
+
+ napi_disable(&bus->mux_napi);
+ qtnf_disable_hdp_irqs(ps);
+}
+
+static const struct qtnf_bus_ops qtnf_pcie_pearl_bus_ops = {
+ /* control path methods */
+ .control_tx = qtnf_pcie_control_tx,
+
+ /* data path methods */
+ .data_tx = qtnf_pcie_data_tx,
+ .data_tx_timeout = qtnf_pcie_data_tx_timeout,
+ .data_rx_start = qtnf_pcie_data_rx_start,
+ .data_rx_stop = qtnf_pcie_data_rx_stop,
+};
+
+static int qtnf_dbg_irq_stats(struct seq_file *s, void *data)
+{
+ struct qtnf_bus *bus = dev_get_drvdata(s->private);
+ struct qtnf_pcie_pearl_state *ps = get_bus_priv(bus);
+ u32 reg = readl(PCIE_HDP_INT_EN(ps->pcie_reg_base));
+ u32 status;
+
+ seq_printf(s, "pcie_irq_count(%u)\n", ps->base.pcie_irq_count);
+ seq_printf(s, "pcie_irq_tx_count(%u)\n", ps->pcie_irq_tx_count);
+ status = reg & PCIE_HDP_INT_TX_BITS;
+ seq_printf(s, "pcie_irq_tx_status(%s)\n",
+ (status == PCIE_HDP_INT_TX_BITS) ? "EN" : "DIS");
+ seq_printf(s, "pcie_irq_rx_count(%u)\n", ps->pcie_irq_rx_count);
+ status = reg & PCIE_HDP_INT_RX_BITS;
+ seq_printf(s, "pcie_irq_rx_status(%s)\n",
+ (status == PCIE_HDP_INT_RX_BITS) ? "EN" : "DIS");
+ seq_printf(s, "pcie_irq_uf_count(%u)\n", ps->pcie_irq_uf_count);
+ status = reg & PCIE_HDP_INT_HHBM_UF;
+ seq_printf(s, "pcie_irq_hhbm_uf_status(%s)\n",
+ (status == PCIE_HDP_INT_HHBM_UF) ? "EN" : "DIS");
+
+ return 0;
+}
+
+static int qtnf_dbg_hdp_stats(struct seq_file *s, void *data)
+{
+ struct qtnf_bus *bus = dev_get_drvdata(s->private);
+ struct qtnf_pcie_pearl_state *ps = get_bus_priv(bus);
+ struct qtnf_pcie_bus_priv *priv = &ps->base;
+
+ seq_printf(s, "tx_full_count(%u)\n", priv->tx_full_count);
+ seq_printf(s, "tx_done_count(%u)\n", priv->tx_done_count);
+ seq_printf(s, "tx_reclaim_done(%u)\n", priv->tx_reclaim_done);
+ seq_printf(s, "tx_reclaim_req(%u)\n", priv->tx_reclaim_req);
+
+ seq_printf(s, "tx_bd_r_index(%u)\n", priv->tx_bd_r_index);
+ seq_printf(s, "tx_bd_p_index(%u)\n",
+ readl(PCIE_HDP_RX0DMA_CNT(ps->pcie_reg_base))
+ & (priv->tx_bd_num - 1));
+ seq_printf(s, "tx_bd_w_index(%u)\n", priv->tx_bd_w_index);
+ seq_printf(s, "tx queue len(%u)\n",
+ CIRC_CNT(priv->tx_bd_w_index, priv->tx_bd_r_index,
+ priv->tx_bd_num));
+
+ seq_printf(s, "rx_bd_r_index(%u)\n", priv->rx_bd_r_index);
+ seq_printf(s, "rx_bd_p_index(%u)\n",
+ readl(PCIE_HDP_TX0DMA_CNT(ps->pcie_reg_base))
+ & (priv->rx_bd_num - 1));
+ seq_printf(s, "rx_bd_w_index(%u)\n", priv->rx_bd_w_index);
+ seq_printf(s, "rx alloc queue len(%u)\n",
+ CIRC_SPACE(priv->rx_bd_w_index, priv->rx_bd_r_index,
+ priv->rx_bd_num));
+
+ return 0;
+}
+
+static int qtnf_ep_fw_send(struct pci_dev *pdev, uint32_t size,
+ int blk, const u8 *pblk, const u8 *fw)
+{
+ struct qtnf_bus *bus = pci_get_drvdata(pdev);
+
+ struct qtnf_pearl_fw_hdr *hdr;
+ u8 *pdata;
+
+ int hds = sizeof(*hdr);
+ struct sk_buff *skb = NULL;
+ int len = 0;
+ int ret;
+
+ skb = __dev_alloc_skb(QTN_PCIE_FW_BUFSZ, GFP_KERNEL);
+ if (!skb)
+ return -ENOMEM;
+
+ skb->len = QTN_PCIE_FW_BUFSZ;
+ skb->dev = NULL;
+
+ hdr = (struct qtnf_pearl_fw_hdr *)skb->data;
+ memcpy(hdr->boardflg, QTN_PCIE_BOARDFLG, strlen(QTN_PCIE_BOARDFLG));
+ hdr->fwsize = cpu_to_le32(size);
+ hdr->seqnum = cpu_to_le32(blk);
+
+ if (blk)
+ hdr->type = cpu_to_le32(QTN_FW_DSUB);
+ else
+ hdr->type = cpu_to_le32(QTN_FW_DBEGIN);
+
+ pdata = skb->data + hds;
+
+ len = QTN_PCIE_FW_BUFSZ - hds;
+ if (pblk >= (fw + size - len)) {
+ len = fw + size - pblk;
+ hdr->type = cpu_to_le32(QTN_FW_DEND);
+ }
+
+ hdr->pktlen = cpu_to_le32(len);
+ memcpy(pdata, pblk, len);
+ hdr->crc = cpu_to_le32(~crc32(0, pdata, len));
+
+ ret = qtnf_pcie_data_tx(bus, skb);
+
+ return (ret == NETDEV_TX_OK) ? len : 0;
+}
+
+static int
+qtnf_ep_fw_load(struct qtnf_pcie_pearl_state *ps, const u8 *fw, u32 fw_size)
+{
+ int blk_size = QTN_PCIE_FW_BUFSZ - sizeof(struct qtnf_pearl_fw_hdr);
+ int blk_count = fw_size / blk_size + ((fw_size % blk_size) ? 1 : 0);
+ const u8 *pblk = fw;
+ int threshold = 0;
+ int blk = 0;
+ int len;
+
+ pr_debug("FW upload started: fw_addr=0x%p size=%d\n", fw, fw_size);
+
+ while (blk < blk_count) {
+ if (++threshold > 10000) {
+ pr_err("FW upload failed: too many retries\n");
+ return -ETIMEDOUT;
+ }
+
+ len = qtnf_ep_fw_send(ps->base.pdev, fw_size, blk, pblk, fw);
+ if (len <= 0)
+ continue;
+
+ if (!((blk + 1) & QTN_PCIE_FW_DLMASK) ||
+ (blk == (blk_count - 1))) {
+ qtnf_set_state(&ps->bda->bda_rc_state,
+ QTN_RC_FW_SYNC);
+ if (qtnf_poll_state(&ps->bda->bda_ep_state,
+ QTN_EP_FW_SYNC,
+ QTN_FW_DL_TIMEOUT_MS)) {
+ pr_err("FW upload failed: SYNC timed out\n");
+ return -ETIMEDOUT;
+ }
+
+ qtnf_clear_state(&ps->bda->bda_ep_state,
+ QTN_EP_FW_SYNC);
+
+ if (qtnf_is_state(&ps->bda->bda_ep_state,
+ QTN_EP_FW_RETRY)) {
+ if (blk == (blk_count - 1)) {
+ int last_round =
+ blk_count & QTN_PCIE_FW_DLMASK;
+ blk -= last_round;
+ pblk -= ((last_round - 1) *
+ blk_size + len);
+ } else {
+ blk -= QTN_PCIE_FW_DLMASK;
+ pblk -= QTN_PCIE_FW_DLMASK * blk_size;
+ }
+
+ qtnf_clear_state(&ps->bda->bda_ep_state,
+ QTN_EP_FW_RETRY);
+
+ pr_warn("FW upload retry: block #%d\n", blk);
+ continue;
+ }
+
+ qtnf_pearl_data_tx_reclaim(ps);
+ }
+
+ pblk += len;
+ blk++;
+ }
+
+ pr_debug("FW upload completed: totally sent %d blocks\n", blk);
+ return 0;
+}
+
+static void qtnf_pearl_fw_work_handler(struct work_struct *work)
+{
+ struct qtnf_bus *bus = container_of(work, struct qtnf_bus, fw_work);
+ struct qtnf_pcie_pearl_state *ps = (void *)get_bus_priv(bus);
+ struct pci_dev *pdev = ps->base.pdev;
+ const struct firmware *fw;
+ int ret;
+ u32 state = QTN_RC_FW_LOADRDY | QTN_RC_FW_QLINK;
+ const char *fwname = QTN_PCI_PEARL_FW_NAME;
+ bool fw_boot_success = false;
+
+ if (flashboot) {
+ state |= QTN_RC_FW_FLASHBOOT;
+ } else {
+ ret = request_firmware(&fw, fwname, &pdev->dev);
+ if (ret < 0) {
+ pr_err("failed to get firmware %s\n", fwname);
+ goto fw_load_exit;
+ }
+ }
+
+ qtnf_set_state(&ps->bda->bda_rc_state, state);
+
+ if (qtnf_poll_state(&ps->bda->bda_ep_state, QTN_EP_FW_LOADRDY,
+ QTN_FW_DL_TIMEOUT_MS)) {
+ pr_err("card is not ready\n");
+
+ if (!flashboot)
+ release_firmware(fw);
+
+ goto fw_load_exit;
+ }
+
+ qtnf_clear_state(&ps->bda->bda_ep_state, QTN_EP_FW_LOADRDY);
+
+ if (flashboot) {
+ pr_info("booting firmware from flash\n");
+
+ } else {
+ pr_info("starting firmware upload: %s\n", fwname);
+
+ ret = qtnf_ep_fw_load(ps, fw->data, fw->size);
+ release_firmware(fw);
+ if (ret) {
+ pr_err("firmware upload error\n");
+ goto fw_load_exit;
+ }
+ }
+
+ if (qtnf_poll_state(&ps->bda->bda_ep_state, QTN_EP_FW_DONE,
+ QTN_FW_DL_TIMEOUT_MS)) {
+ pr_err("firmware bringup timed out\n");
+ goto fw_load_exit;
+ }
+
+ pr_info("firmware is up and running\n");
+
+ if (qtnf_poll_state(&ps->bda->bda_ep_state,
+ QTN_EP_FW_QLINK_DONE, QTN_FW_QLINK_TIMEOUT_MS)) {
+ pr_err("firmware runtime failure\n");
+ goto fw_load_exit;
+ }
+
+ fw_boot_success = true;
+
+fw_load_exit:
+ qtnf_pcie_fw_boot_done(bus, fw_boot_success, DRV_NAME);
+
+ if (fw_boot_success) {
+ qtnf_debugfs_add_entry(bus, "hdp_stats", qtnf_dbg_hdp_stats);
+ qtnf_debugfs_add_entry(bus, "irq_stats", qtnf_dbg_irq_stats);
+ }
+}
+
+static void qtnf_pearl_reclaim_tasklet_fn(unsigned long data)
+{
+ struct qtnf_pcie_pearl_state *ps = (void *)data;
+
+ qtnf_pearl_data_tx_reclaim(ps);
+ qtnf_en_txdone_irq(ps);
+}
+
+static int qtnf_pearl_check_chip_id(struct qtnf_pcie_pearl_state *ps)
+{
+ unsigned int chipid;
+
+ chipid = qtnf_chip_id_get(ps->base.sysctl_bar);
+
+ switch (chipid) {
+ case QTN_CHIP_ID_PEARL:
+ case QTN_CHIP_ID_PEARL_B:
+ case QTN_CHIP_ID_PEARL_C:
+ pr_info("chip ID is 0x%x\n", chipid);
+ break;
+ default:
+ pr_err("incorrect chip ID 0x%x\n", chipid);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int qtnf_pcie_pearl_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct qtnf_shm_ipc_int ipc_int;
+ struct qtnf_pcie_pearl_state *ps;
+ struct qtnf_bus *bus;
+ int ret;
+ u64 dma_mask;
+
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+ dma_mask = DMA_BIT_MASK(64);
+#else
+ dma_mask = DMA_BIT_MASK(32);
+#endif
+
+ ret = qtnf_pcie_probe(pdev, sizeof(*ps), &qtnf_pcie_pearl_bus_ops,
+ dma_mask, use_msi);
+ if (ret)
+ return ret;
+
+ bus = pci_get_drvdata(pdev);
+ ps = get_bus_priv(bus);
+
+ spin_lock_init(&ps->irq_lock);
+
+ tasklet_init(&ps->base.reclaim_tq, qtnf_pearl_reclaim_tasklet_fn,
+ (unsigned long)ps);
+ netif_napi_add(&bus->mux_dev, &bus->mux_napi,
+ qtnf_pcie_pearl_rx_poll, 10);
+ INIT_WORK(&bus->fw_work, qtnf_pearl_fw_work_handler);
+
+ ps->pcie_reg_base = ps->base.dmareg_bar;
+ ps->bda = ps->base.epmem_bar;
+ writel(ps->base.msi_enabled, &ps->bda->bda_rc_msi_enabled);
+
+ ipc_int.fn = qtnf_pcie_pearl_ipc_gen_ep_int;
+ ipc_int.arg = ps;
+ qtnf_pcie_init_shm_ipc(&ps->base, &ps->bda->bda_shm_reg1,
+ &ps->bda->bda_shm_reg2, &ipc_int);
+
+ ret = qtnf_pearl_check_chip_id(ps);
+ if (ret)
+ goto error;
+
+ ret = qtnf_pcie_pearl_init_xfer(ps);
+ if (ret) {
+ pr_err("PCIE xfer init failed\n");
+ goto error;
+ }
+
+ /* init default irq settings */
+ qtnf_init_hdp_irqs(ps);
+
+ /* start with disabled irqs */
+ qtnf_disable_hdp_irqs(ps);
+
+ ret = devm_request_irq(&pdev->dev, pdev->irq,
+ &qtnf_pcie_pearl_interrupt, 0,
+ "qtnf_pcie_irq", (void *)bus);
+ if (ret) {
+ pr_err("failed to request pcie irq %d\n", pdev->irq);
+ goto err_xfer;
+ }
+
+ qtnf_pcie_bringup_fw_async(bus);
+
+ return 0;
+
+err_xfer:
+ qtnf_pearl_free_xfer_buffers(ps);
+error:
+ qtnf_pcie_remove(bus, &ps->base);
+
+ return ret;
+}
+
+static void qtnf_pcie_pearl_remove(struct pci_dev *pdev)
+{
+ struct qtnf_pcie_pearl_state *ps;
+ struct qtnf_bus *bus;
+
+ bus = pci_get_drvdata(pdev);
+ if (!bus)
+ return;
+
+ ps = get_bus_priv(bus);
+
+ qtnf_pcie_remove(bus, &ps->base);
+ qtnf_pearl_reset_ep(ps);
+ qtnf_pearl_free_xfer_buffers(ps);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int qtnf_pcie_pearl_suspend(struct device *dev)
+{
+ return -EOPNOTSUPP;
+}
+
+static int qtnf_pcie_pearl_resume(struct device *dev)
+{
+ return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+#ifdef CONFIG_PM_SLEEP
+/* Power Management Hooks */
+static SIMPLE_DEV_PM_OPS(qtnf_pcie_pearl_pm_ops, qtnf_pcie_pearl_suspend,
+ qtnf_pcie_pearl_resume);
+#endif
+
+static const struct pci_device_id qtnf_pcie_devid_table[] = {
+ {
+ PCIE_VENDOR_ID_QUANTENNA, PCIE_DEVICE_ID_QTN_PEARL,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ },
+ { },
+};
+
+MODULE_DEVICE_TABLE(pci, qtnf_pcie_devid_table);
+
+static struct pci_driver qtnf_pcie_pearl_drv_data = {
+ .name = DRV_NAME,
+ .id_table = qtnf_pcie_devid_table,
+ .probe = qtnf_pcie_pearl_probe,
+ .remove = qtnf_pcie_pearl_remove,
+#ifdef CONFIG_PM_SLEEP
+ .driver = {
+ .pm = &qtnf_pcie_pearl_pm_ops,
+ },
+#endif
+};
+
+static int __init qtnf_pcie_pearl_register(void)
+{
+ pr_info("register Quantenna QSR10g FullMAC PCIE driver\n");
+ return pci_register_driver(&qtnf_pcie_pearl_drv_data);
+}
+
+static void __exit qtnf_pcie_pearl_exit(void)
+{
+ pr_info("unregister Quantenna QSR10g FullMAC PCIE driver\n");
+ pci_unregister_driver(&qtnf_pcie_pearl_drv_data);
+}
+
+module_init(qtnf_pcie_pearl_register);
+module_exit(qtnf_pcie_pearl_exit);
+
+MODULE_AUTHOR("Quantenna Communications");
+MODULE_DESCRIPTION("Quantenna QSR10g PCIe bus driver for 802.11 wireless LAN.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_ipc.h b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_ipc.h
index 00bb21a1c47a..634480fe6a64 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_ipc.h
+++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_ipc.h
@@ -1,18 +1,5 @@
-/*
- * Copyright (c) 2015-2016 Quantenna Communications, 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 Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Copyright (c) 2015-2016 Quantenna Communications */
#ifndef _QTN_FMAC_PCIE_IPC_H_
#define _QTN_FMAC_PCIE_IPC_H_
@@ -43,11 +30,6 @@
#define QTN_RC_FW_LOADRDY BIT(8)
#define QTN_RC_FW_SYNC BIT(9)
-/* state transition timeouts */
-#define QTN_FW_DL_TIMEOUT_MS 3000
-#define QTN_FW_QLINK_TIMEOUT_MS 30000
-#define QTN_EP_RESET_WAIT_MS 1000
-
#define PCIE_HDP_INT_RX_BITS (0 \
| PCIE_HDP_INT_EP_TXDMA \
| PCIE_HDP_INT_EP_TXEMPTY \
@@ -68,17 +50,11 @@
#define QTN_HOST_ADDR(h, l) ((u32)l)
#endif
-#define QTN_SYSCTL_BAR 0
-#define QTN_SHMEM_BAR 2
-#define QTN_DMA_BAR 3
-
#define QTN_PCIE_BDA_VERSION 0x1002
#define PCIE_BDA_NAMELEN 32
#define PCIE_HHBM_MAX_SIZE 2048
-#define SKB_BUF_SIZE 2048
-
#define QTN_PCIE_BOARDFLG "PCIEQTN"
#define QTN_PCIE_FW_DLMASK 0xF
#define QTN_PCIE_FW_BUFSZ 2048
@@ -96,49 +72,6 @@
#define QTN_EP_LHOST_TQE_PORT 4
-enum qtnf_pcie_bda_ipc_flags {
- QTN_PCIE_IPC_FLAG_HBM_MAGIC = BIT(0),
- QTN_PCIE_IPC_FLAG_SHM_PIO = BIT(1),
-};
-
-struct qtnf_pcie_bda {
- __le16 bda_len;
- __le16 bda_version;
- __le32 bda_pci_endian;
- __le32 bda_ep_state;
- __le32 bda_rc_state;
- __le32 bda_dma_mask;
- __le32 bda_msi_addr;
- __le32 bda_flashsz;
- u8 bda_boardname[PCIE_BDA_NAMELEN];
- __le32 bda_rc_msi_enabled;
- u8 bda_hhbm_list[PCIE_HHBM_MAX_SIZE];
- __le32 bda_dsbw_start_index;
- __le32 bda_dsbw_end_index;
- __le32 bda_dsbw_total_bytes;
- __le32 bda_rc_tx_bd_base;
- __le32 bda_rc_tx_bd_num;
- u8 bda_pcie_mac[QTN_ENET_ADDR_LENGTH];
- struct qtnf_shm_ipc_region bda_shm_reg1 __aligned(4096); /* host TX */
- struct qtnf_shm_ipc_region bda_shm_reg2 __aligned(4096); /* host RX */
-} __packed;
-
-struct qtnf_tx_bd {
- __le32 addr;
- __le32 addr_h;
- __le32 info;
- __le32 info_h;
-} __packed;
-
-struct qtnf_rx_bd {
- __le32 addr;
- __le32 addr_h;
- __le32 info;
- __le32 info_h;
- __le32 next_ptr;
- __le32 next_ptr_h;
-} __packed;
-
enum qtnf_fw_loadtype {
QTN_FW_DBEGIN,
QTN_FW_DSUB,
@@ -146,13 +79,4 @@ enum qtnf_fw_loadtype {
QTN_FW_CTRL
};
-struct qtnf_pcie_fw_hdr {
- u8 boardflg[8];
- __le32 fwsize;
- __le32 seqnum;
- __le32 type;
- __le32 pktlen;
- __le32 crc;
-} __packed;
-
#endif /* _QTN_FMAC_PCIE_IPC_H_ */
diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_regs.h b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_regs.h
new file mode 100644
index 000000000000..6e9a5c61d46f
--- /dev/null
+++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_regs.h
@@ -0,0 +1,121 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Copyright (c) 2015 Quantenna Communications */
+
+#ifndef __PEARL_PCIE_H
+#define __PEARL_PCIE_H
+
+/* Pearl PCIe HDP registers */
+#define PCIE_HDP_CTRL(base) ((base) + 0x2c00)
+#define PCIE_HDP_AXI_CTRL(base) ((base) + 0x2c04)
+#define PCIE_HDP_HOST_WR_DESC0(base) ((base) + 0x2c10)
+#define PCIE_HDP_HOST_WR_DESC0_H(base) ((base) + 0x2c14)
+#define PCIE_HDP_HOST_WR_DESC1(base) ((base) + 0x2c18)
+#define PCIE_HDP_HOST_WR_DESC1_H(base) ((base) + 0x2c1c)
+#define PCIE_HDP_HOST_WR_DESC2(base) ((base) + 0x2c20)
+#define PCIE_HDP_HOST_WR_DESC2_H(base) ((base) + 0x2c24)
+#define PCIE_HDP_HOST_WR_DESC3(base) ((base) + 0x2c28)
+#define PCIE_HDP_HOST_WR_DESC4_H(base) ((base) + 0x2c2c)
+#define PCIE_HDP_RX_INT_CTRL(base) ((base) + 0x2c30)
+#define PCIE_HDP_TX_INT_CTRL(base) ((base) + 0x2c34)
+#define PCIE_HDP_INT_STATUS(base) ((base) + 0x2c38)
+#define PCIE_HDP_INT_EN(base) ((base) + 0x2c3c)
+#define PCIE_HDP_RX_DESC0_PTR(base) ((base) + 0x2c40)
+#define PCIE_HDP_RX_DESC0_NOE(base) ((base) + 0x2c44)
+#define PCIE_HDP_RX_DESC1_PTR(base) ((base) + 0x2c48)
+#define PCIE_HDP_RX_DESC1_NOE(base) ((base) + 0x2c4c)
+#define PCIE_HDP_RX_DESC2_PTR(base) ((base) + 0x2c50)
+#define PCIE_HDP_RX_DESC2_NOE(base) ((base) + 0x2c54)
+#define PCIE_HDP_RX_DESC3_PTR(base) ((base) + 0x2c58)
+#define PCIE_HDP_RX_DESC3_NOE(base) ((base) + 0x2c5c)
+
+#define PCIE_HDP_TX0_BASE_ADDR(base) ((base) + 0x2c60)
+#define PCIE_HDP_TX1_BASE_ADDR(base) ((base) + 0x2c64)
+#define PCIE_HDP_TX0_Q_CTRL(base) ((base) + 0x2c70)
+#define PCIE_HDP_TX1_Q_CTRL(base) ((base) + 0x2c74)
+#define PCIE_HDP_CFG0(base) ((base) + 0x2c80)
+#define PCIE_HDP_CFG1(base) ((base) + 0x2c84)
+#define PCIE_HDP_CFG2(base) ((base) + 0x2c88)
+#define PCIE_HDP_CFG3(base) ((base) + 0x2c8c)
+#define PCIE_HDP_CFG4(base) ((base) + 0x2c90)
+#define PCIE_HDP_CFG5(base) ((base) + 0x2c94)
+#define PCIE_HDP_CFG6(base) ((base) + 0x2c98)
+#define PCIE_HDP_CFG7(base) ((base) + 0x2c9c)
+#define PCIE_HDP_CFG8(base) ((base) + 0x2ca0)
+#define PCIE_HDP_CFG9(base) ((base) + 0x2ca4)
+#define PCIE_HDP_CFG10(base) ((base) + 0x2ca8)
+#define PCIE_HDP_CFG11(base) ((base) + 0x2cac)
+#define PCIE_INT(base) ((base) + 0x2cb0)
+#define PCIE_INT_MASK(base) ((base) + 0x2cb4)
+#define PCIE_MSI_MASK(base) ((base) + 0x2cb8)
+#define PCIE_MSI_PNDG(base) ((base) + 0x2cbc)
+#define PCIE_PRI_CFG(base) ((base) + 0x2cc0)
+#define PCIE_PHY_CR(base) ((base) + 0x2cc4)
+#define PCIE_HDP_CTAG_CTRL(base) ((base) + 0x2cf4)
+#define PCIE_HDP_HHBM_BUF_PTR(base) ((base) + 0x2d00)
+#define PCIE_HDP_HHBM_BUF_PTR_H(base) ((base) + 0x2d04)
+#define PCIE_HDP_HHBM_BUF_FIFO_NOE(base) ((base) + 0x2d04)
+#define PCIE_HDP_RX0DMA_CNT(base) ((base) + 0x2d10)
+#define PCIE_HDP_RX1DMA_CNT(base) ((base) + 0x2d14)
+#define PCIE_HDP_RX2DMA_CNT(base) ((base) + 0x2d18)
+#define PCIE_HDP_RX3DMA_CNT(base) ((base) + 0x2d1c)
+#define PCIE_HDP_TX0DMA_CNT(base) ((base) + 0x2d20)
+#define PCIE_HDP_TX1DMA_CNT(base) ((base) + 0x2d24)
+#define PCIE_HDP_RXDMA_CTRL(base) ((base) + 0x2d28)
+#define PCIE_HDP_TX_HOST_Q_SZ_CTRL(base) ((base) + 0x2d2c)
+#define PCIE_HDP_TX_HOST_Q_BASE_L(base) ((base) + 0x2d30)
+#define PCIE_HDP_TX_HOST_Q_BASE_H(base) ((base) + 0x2d34)
+#define PCIE_HDP_TX_HOST_Q_WR_PTR(base) ((base) + 0x2d38)
+#define PCIE_HDP_TX_HOST_Q_RD_PTR(base) ((base) + 0x2d3c)
+#define PCIE_HDP_TX_HOST_Q_STS(base) ((base) + 0x2d40)
+
+/* Pearl PCIe HBM pool registers */
+#define PCIE_HHBM_CSR_REG(base) ((base) + 0x2e00)
+#define PCIE_HHBM_Q_BASE_REG(base) ((base) + 0x2e04)
+#define PCIE_HHBM_Q_LIMIT_REG(base) ((base) + 0x2e08)
+#define PCIE_HHBM_Q_WR_REG(base) ((base) + 0x2e0c)
+#define PCIE_HHBM_Q_RD_REG(base) ((base) + 0x2e10)
+#define PCIE_HHBM_POOL_DATA_0_H(base) ((base) + 0x2e90)
+#define PCIE_HHBM_CONFIG(base) ((base) + 0x2f9c)
+#define PCIE_HHBM_POOL_REQ_0(base) ((base) + 0x2f10)
+#define PCIE_HHBM_POOL_DATA_0(base) ((base) + 0x2f40)
+#define PCIE_HHBM_WATERMARK_MASKED_INT(base) ((base) + 0x2f68)
+#define PCIE_HHBM_WATERMARK_INT(base) ((base) + 0x2f6c)
+#define PCIE_HHBM_POOL_WATERMARK(base) ((base) + 0x2f70)
+#define PCIE_HHBM_POOL_OVERFLOW_CNT(base) ((base) + 0x2f90)
+#define PCIE_HHBM_POOL_UNDERFLOW_CNT(base) ((base) + 0x2f94)
+#define HBM_INT_STATUS(base) ((base) + 0x2f9c)
+#define PCIE_HHBM_POOL_CNFIG(base) ((base) + 0x2f9c)
+
+/* Pearl PCIe HBM bit field definitions */
+#define HHBM_CONFIG_SOFT_RESET (BIT(8))
+#define HHBM_WR_REQ (BIT(0))
+#define HHBM_RD_REQ (BIT(1))
+#define HHBM_DONE (BIT(31))
+#define HHBM_64BIT (BIT(10))
+
+/* PCIe HDP interrupt status definition */
+#define PCIE_HDP_INT_EP_RXDMA (BIT(0))
+#define PCIE_HDP_INT_HBM_UF (BIT(1))
+#define PCIE_HDP_INT_RX_LEN_ERR (BIT(2))
+#define PCIE_HDP_INT_RX_HDR_LEN_ERR (BIT(3))
+#define PCIE_HDP_INT_EP_TXDMA (BIT(12))
+#define PCIE_HDP_INT_HHBM_UF (BIT(13))
+#define PCIE_HDP_INT_EP_TXEMPTY (BIT(15))
+#define PCIE_HDP_INT_IPC (BIT(29))
+
+/* PCIe interrupt status definition */
+#define PCIE_INT_MSI (BIT(24))
+#define PCIE_INT_INTX (BIT(23))
+
+/* PCIe legacy INTx */
+#define PEARL_PCIE_CFG0_OFFSET (0x6C)
+#define PEARL_ASSERT_INTX (BIT(9))
+
+/* SYS CTL regs */
+#define QTN_PEARL_SYSCTL_LHOST_IRQ_OFFSET (0x001C)
+
+#define QTN_PEARL_IPC_IRQ_WORD(irq) (BIT(irq) | BIT(irq + 16))
+#define QTN_PEARL_LHOST_IPC_IRQ (6)
+#define QTN_PEARL_LHOST_EP_RESET (7)
+
+#endif /* __PEARL_PCIE_H */
diff --git a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c
deleted file mode 100644
index 3120d49df565..000000000000
--- a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c
+++ /dev/null
@@ -1,1494 +0,0 @@
-/*
- * Copyright (c) 2015-2016 Quantenna Communications, 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 Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/firmware.h>
-#include <linux/pci.h>
-#include <linux/vmalloc.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/sched.h>
-#include <linux/completion.h>
-#include <linux/crc32.h>
-#include <linux/spinlock.h>
-#include <linux/circ_buf.h>
-#include <linux/log2.h>
-
-#include "qtn_hw_ids.h"
-#include "pcie_bus_priv.h"
-#include "core.h"
-#include "bus.h"
-#include "debug.h"
-
-static bool use_msi = true;
-module_param(use_msi, bool, 0644);
-MODULE_PARM_DESC(use_msi, "set 0 to use legacy interrupt");
-
-static unsigned int tx_bd_size_param = 32;
-module_param(tx_bd_size_param, uint, 0644);
-MODULE_PARM_DESC(tx_bd_size_param, "Tx descriptors queue size, power of two");
-
-static unsigned int rx_bd_size_param = 256;
-module_param(rx_bd_size_param, uint, 0644);
-MODULE_PARM_DESC(rx_bd_size_param, "Rx descriptors queue size, power of two");
-
-static u8 flashboot = 1;
-module_param(flashboot, byte, 0644);
-MODULE_PARM_DESC(flashboot, "set to 0 to use FW binary file on FS");
-
-#define DRV_NAME "qtnfmac_pearl_pcie"
-
-static inline void qtnf_non_posted_write(u32 val, void __iomem *basereg)
-{
- writel(val, basereg);
-
- /* flush posted write */
- readl(basereg);
-}
-
-static inline void qtnf_init_hdp_irqs(struct qtnf_pcie_bus_priv *priv)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&priv->irq_lock, flags);
- priv->pcie_irq_mask = (PCIE_HDP_INT_RX_BITS | PCIE_HDP_INT_TX_BITS);
- spin_unlock_irqrestore(&priv->irq_lock, flags);
-}
-
-static inline void qtnf_enable_hdp_irqs(struct qtnf_pcie_bus_priv *priv)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&priv->irq_lock, flags);
- writel(priv->pcie_irq_mask, PCIE_HDP_INT_EN(priv->pcie_reg_base));
- spin_unlock_irqrestore(&priv->irq_lock, flags);
-}
-
-static inline void qtnf_disable_hdp_irqs(struct qtnf_pcie_bus_priv *priv)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&priv->irq_lock, flags);
- writel(0x0, PCIE_HDP_INT_EN(priv->pcie_reg_base));
- spin_unlock_irqrestore(&priv->irq_lock, flags);
-}
-
-static inline void qtnf_en_rxdone_irq(struct qtnf_pcie_bus_priv *priv)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&priv->irq_lock, flags);
- priv->pcie_irq_mask |= PCIE_HDP_INT_RX_BITS;
- writel(priv->pcie_irq_mask, PCIE_HDP_INT_EN(priv->pcie_reg_base));
- spin_unlock_irqrestore(&priv->irq_lock, flags);
-}
-
-static inline void qtnf_dis_rxdone_irq(struct qtnf_pcie_bus_priv *priv)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&priv->irq_lock, flags);
- priv->pcie_irq_mask &= ~PCIE_HDP_INT_RX_BITS;
- writel(priv->pcie_irq_mask, PCIE_HDP_INT_EN(priv->pcie_reg_base));
- spin_unlock_irqrestore(&priv->irq_lock, flags);
-}
-
-static inline void qtnf_en_txdone_irq(struct qtnf_pcie_bus_priv *priv)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&priv->irq_lock, flags);
- priv->pcie_irq_mask |= PCIE_HDP_INT_TX_BITS;
- writel(priv->pcie_irq_mask, PCIE_HDP_INT_EN(priv->pcie_reg_base));
- spin_unlock_irqrestore(&priv->irq_lock, flags);
-}
-
-static inline void qtnf_dis_txdone_irq(struct qtnf_pcie_bus_priv *priv)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&priv->irq_lock, flags);
- priv->pcie_irq_mask &= ~PCIE_HDP_INT_TX_BITS;
- writel(priv->pcie_irq_mask, PCIE_HDP_INT_EN(priv->pcie_reg_base));
- spin_unlock_irqrestore(&priv->irq_lock, flags);
-}
-
-static void qtnf_pcie_init_irq(struct qtnf_pcie_bus_priv *priv)
-{
- struct pci_dev *pdev = priv->pdev;
-
- /* fall back to legacy INTx interrupts by default */
- priv->msi_enabled = 0;
-
- /* check if MSI capability is available */
- if (use_msi) {
- if (!pci_enable_msi(pdev)) {
- pr_debug("MSI interrupt enabled\n");
- priv->msi_enabled = 1;
- } else {
- pr_warn("failed to enable MSI interrupts");
- }
- }
-
- if (!priv->msi_enabled) {
- pr_warn("legacy PCIE interrupts enabled\n");
- pci_intx(pdev, 1);
- }
-}
-
-static void qtnf_deassert_intx(struct qtnf_pcie_bus_priv *priv)
-{
- void __iomem *reg = priv->sysctl_bar + PEARL_PCIE_CFG0_OFFSET;
- u32 cfg;
-
- cfg = readl(reg);
- cfg &= ~PEARL_ASSERT_INTX;
- qtnf_non_posted_write(cfg, reg);
-}
-
-static void qtnf_reset_card(struct qtnf_pcie_bus_priv *priv)
-{
- const u32 data = QTN_PEARL_IPC_IRQ_WORD(QTN_PEARL_LHOST_EP_RESET);
- void __iomem *reg = priv->sysctl_bar +
- QTN_PEARL_SYSCTL_LHOST_IRQ_OFFSET;
-
- qtnf_non_posted_write(data, reg);
- msleep(QTN_EP_RESET_WAIT_MS);
- pci_restore_state(priv->pdev);
-}
-
-static void qtnf_ipc_gen_ep_int(void *arg)
-{
- const struct qtnf_pcie_bus_priv *priv = arg;
- const u32 data = QTN_PEARL_IPC_IRQ_WORD(QTN_PEARL_LHOST_IPC_IRQ);
- void __iomem *reg = priv->sysctl_bar +
- QTN_PEARL_SYSCTL_LHOST_IRQ_OFFSET;
-
- qtnf_non_posted_write(data, reg);
-}
-
-static void __iomem *qtnf_map_bar(struct qtnf_pcie_bus_priv *priv, u8 index)
-{
- void __iomem *vaddr;
- dma_addr_t busaddr;
- size_t len;
- int ret;
-
- ret = pcim_iomap_regions(priv->pdev, 1 << index, DRV_NAME);
- if (ret)
- return IOMEM_ERR_PTR(ret);
-
- busaddr = pci_resource_start(priv->pdev, index);
- len = pci_resource_len(priv->pdev, index);
- vaddr = pcim_iomap_table(priv->pdev)[index];
- if (!vaddr)
- return IOMEM_ERR_PTR(-ENOMEM);
-
- pr_debug("BAR%u vaddr=0x%p busaddr=%pad len=%u\n",
- index, vaddr, &busaddr, (int)len);
-
- return vaddr;
-}
-
-static void qtnf_pcie_control_rx_callback(void *arg, const u8 *buf, size_t len)
-{
- struct qtnf_pcie_bus_priv *priv = arg;
- struct qtnf_bus *bus = pci_get_drvdata(priv->pdev);
- struct sk_buff *skb;
-
- if (unlikely(len == 0)) {
- pr_warn("zero length packet received\n");
- return;
- }
-
- skb = __dev_alloc_skb(len, GFP_KERNEL);
-
- if (unlikely(!skb)) {
- pr_err("failed to allocate skb\n");
- return;
- }
-
- skb_put_data(skb, buf, len);
-
- qtnf_trans_handle_rx_ctl_packet(bus, skb);
-}
-
-static int qtnf_pcie_init_shm_ipc(struct qtnf_pcie_bus_priv *priv)
-{
- struct qtnf_shm_ipc_region __iomem *ipc_tx_reg;
- struct qtnf_shm_ipc_region __iomem *ipc_rx_reg;
- const struct qtnf_shm_ipc_int ipc_int = { qtnf_ipc_gen_ep_int, priv };
- const struct qtnf_shm_ipc_rx_callback rx_callback = {
- qtnf_pcie_control_rx_callback, priv };
-
- ipc_tx_reg = &priv->bda->bda_shm_reg1;
- ipc_rx_reg = &priv->bda->bda_shm_reg2;
-
- qtnf_shm_ipc_init(&priv->shm_ipc_ep_in, QTNF_SHM_IPC_OUTBOUND,
- ipc_tx_reg, priv->workqueue,
- &ipc_int, &rx_callback);
- qtnf_shm_ipc_init(&priv->shm_ipc_ep_out, QTNF_SHM_IPC_INBOUND,
- ipc_rx_reg, priv->workqueue,
- &ipc_int, &rx_callback);
-
- return 0;
-}
-
-static void qtnf_pcie_free_shm_ipc(struct qtnf_pcie_bus_priv *priv)
-{
- qtnf_shm_ipc_free(&priv->shm_ipc_ep_in);
- qtnf_shm_ipc_free(&priv->shm_ipc_ep_out);
-}
-
-static int qtnf_pcie_init_memory(struct qtnf_pcie_bus_priv *priv)
-{
- int ret = -ENOMEM;
-
- priv->sysctl_bar = qtnf_map_bar(priv, QTN_SYSCTL_BAR);
- if (IS_ERR(priv->sysctl_bar)) {
- pr_err("failed to map BAR%u\n", QTN_SYSCTL_BAR);
- return ret;
- }
-
- priv->dmareg_bar = qtnf_map_bar(priv, QTN_DMA_BAR);
- if (IS_ERR(priv->dmareg_bar)) {
- pr_err("failed to map BAR%u\n", QTN_DMA_BAR);
- return ret;
- }
-
- priv->epmem_bar = qtnf_map_bar(priv, QTN_SHMEM_BAR);
- if (IS_ERR(priv->epmem_bar)) {
- pr_err("failed to map BAR%u\n", QTN_SHMEM_BAR);
- return ret;
- }
-
- priv->pcie_reg_base = priv->dmareg_bar;
- priv->bda = priv->epmem_bar;
- writel(priv->msi_enabled, &priv->bda->bda_rc_msi_enabled);
-
- return 0;
-}
-
-static void qtnf_tune_pcie_mps(struct qtnf_pcie_bus_priv *priv)
-{
- struct pci_dev *pdev = priv->pdev;
- struct pci_dev *parent;
- int mps_p, mps_o, mps_m, mps;
- int ret;
-
- /* current mps */
- mps_o = pcie_get_mps(pdev);
-
- /* maximum supported mps */
- mps_m = 128 << pdev->pcie_mpss;
-
- /* suggested new mps value */
- mps = mps_m;
-
- if (pdev->bus && pdev->bus->self) {
- /* parent (bus) mps */
- parent = pdev->bus->self;
-
- if (pci_is_pcie(parent)) {
- mps_p = pcie_get_mps(parent);
- mps = min(mps_m, mps_p);
- }
- }
-
- ret = pcie_set_mps(pdev, mps);
- if (ret) {
- pr_err("failed to set mps to %d, keep using current %d\n",
- mps, mps_o);
- priv->mps = mps_o;
- return;
- }
-
- pr_debug("set mps to %d (was %d, max %d)\n", mps, mps_o, mps_m);
- priv->mps = mps;
-}
-
-static int qtnf_is_state(__le32 __iomem *reg, u32 state)
-{
- u32 s = readl(reg);
-
- return s & state;
-}
-
-static void qtnf_set_state(__le32 __iomem *reg, u32 state)
-{
- u32 s = readl(reg);
-
- qtnf_non_posted_write(state | s, reg);
-}
-
-static void qtnf_clear_state(__le32 __iomem *reg, u32 state)
-{
- u32 s = readl(reg);
-
- qtnf_non_posted_write(s & ~state, reg);
-}
-
-static int qtnf_poll_state(__le32 __iomem *reg, u32 state, u32 delay_in_ms)
-{
- u32 timeout = 0;
-
- while ((qtnf_is_state(reg, state) == 0)) {
- usleep_range(1000, 1200);
- if (++timeout > delay_in_ms)
- return -1;
- }
-
- return 0;
-}
-
-static int alloc_skb_array(struct qtnf_pcie_bus_priv *priv)
-{
- struct sk_buff **vaddr;
- int len;
-
- len = priv->tx_bd_num * sizeof(*priv->tx_skb) +
- priv->rx_bd_num * sizeof(*priv->rx_skb);
- vaddr = devm_kzalloc(&priv->pdev->dev, len, GFP_KERNEL);
-
- if (!vaddr)
- return -ENOMEM;
-
- priv->tx_skb = vaddr;
-
- vaddr += priv->tx_bd_num;
- priv->rx_skb = vaddr;
-
- return 0;
-}
-
-static int alloc_bd_table(struct qtnf_pcie_bus_priv *priv)
-{
- dma_addr_t paddr;
- void *vaddr;
- int len;
-
- len = priv->tx_bd_num * sizeof(struct qtnf_tx_bd) +
- priv->rx_bd_num * sizeof(struct qtnf_rx_bd);
-
- vaddr = dmam_alloc_coherent(&priv->pdev->dev, len, &paddr, GFP_KERNEL);
- if (!vaddr)
- return -ENOMEM;
-
- /* tx bd */
-
- memset(vaddr, 0, len);
-
- priv->bd_table_vaddr = vaddr;
- priv->bd_table_paddr = paddr;
- priv->bd_table_len = len;
-
- priv->tx_bd_vbase = vaddr;
- priv->tx_bd_pbase = paddr;
-
- pr_debug("TX descriptor table: vaddr=0x%p paddr=%pad\n", vaddr, &paddr);
-
- priv->tx_bd_r_index = 0;
- priv->tx_bd_w_index = 0;
-
- /* rx bd */
-
- vaddr = ((struct qtnf_tx_bd *)vaddr) + priv->tx_bd_num;
- paddr += priv->tx_bd_num * sizeof(struct qtnf_tx_bd);
-
- priv->rx_bd_vbase = vaddr;
- priv->rx_bd_pbase = paddr;
-
-#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
- writel(QTN_HOST_HI32(paddr),
- PCIE_HDP_TX_HOST_Q_BASE_H(priv->pcie_reg_base));
-#endif
- writel(QTN_HOST_LO32(paddr),
- PCIE_HDP_TX_HOST_Q_BASE_L(priv->pcie_reg_base));
- writel(priv->rx_bd_num | (sizeof(struct qtnf_rx_bd)) << 16,
- PCIE_HDP_TX_HOST_Q_SZ_CTRL(priv->pcie_reg_base));
-
- pr_debug("RX descriptor table: vaddr=0x%p paddr=%pad\n", vaddr, &paddr);
-
- return 0;
-}
-
-static int skb2rbd_attach(struct qtnf_pcie_bus_priv *priv, u16 index)
-{
- struct qtnf_rx_bd *rxbd;
- struct sk_buff *skb;
- dma_addr_t paddr;
-
- skb = __netdev_alloc_skb_ip_align(NULL, SKB_BUF_SIZE, GFP_ATOMIC);
- if (!skb) {
- priv->rx_skb[index] = NULL;
- return -ENOMEM;
- }
-
- priv->rx_skb[index] = skb;
- rxbd = &priv->rx_bd_vbase[index];
-
- paddr = pci_map_single(priv->pdev, skb->data,
- SKB_BUF_SIZE, PCI_DMA_FROMDEVICE);
- if (pci_dma_mapping_error(priv->pdev, paddr)) {
- pr_err("skb DMA mapping error: %pad\n", &paddr);
- return -ENOMEM;
- }
-
- /* keep rx skb paddrs in rx buffer descriptors for cleanup purposes */
- rxbd->addr = cpu_to_le32(QTN_HOST_LO32(paddr));
- rxbd->addr_h = cpu_to_le32(QTN_HOST_HI32(paddr));
- rxbd->info = 0x0;
-
- priv->rx_bd_w_index = index;
-
- /* sync up all descriptor updates */
- wmb();
-
-#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
- writel(QTN_HOST_HI32(paddr),
- PCIE_HDP_HHBM_BUF_PTR_H(priv->pcie_reg_base));
-#endif
- writel(QTN_HOST_LO32(paddr),
- PCIE_HDP_HHBM_BUF_PTR(priv->pcie_reg_base));
-
- writel(index, PCIE_HDP_TX_HOST_Q_WR_PTR(priv->pcie_reg_base));
- return 0;
-}
-
-static int alloc_rx_buffers(struct qtnf_pcie_bus_priv *priv)
-{
- u16 i;
- int ret = 0;
-
- memset(priv->rx_bd_vbase, 0x0,
- priv->rx_bd_num * sizeof(struct qtnf_rx_bd));
-
- for (i = 0; i < priv->rx_bd_num; i++) {
- ret = skb2rbd_attach(priv, i);
- if (ret)
- break;
- }
-
- return ret;
-}
-
-/* all rx/tx activity should have ceased before calling this function */
-static void qtnf_free_xfer_buffers(struct qtnf_pcie_bus_priv *priv)
-{
- struct qtnf_tx_bd *txbd;
- struct qtnf_rx_bd *rxbd;
- struct sk_buff *skb;
- dma_addr_t paddr;
- int i;
-
- /* free rx buffers */
- for (i = 0; i < priv->rx_bd_num; i++) {
- if (priv->rx_skb && priv->rx_skb[i]) {
- rxbd = &priv->rx_bd_vbase[i];
- skb = priv->rx_skb[i];
- paddr = QTN_HOST_ADDR(le32_to_cpu(rxbd->addr_h),
- le32_to_cpu(rxbd->addr));
- pci_unmap_single(priv->pdev, paddr, SKB_BUF_SIZE,
- PCI_DMA_FROMDEVICE);
- dev_kfree_skb_any(skb);
- priv->rx_skb[i] = NULL;
- }
- }
-
- /* free tx buffers */
- for (i = 0; i < priv->tx_bd_num; i++) {
- if (priv->tx_skb && priv->tx_skb[i]) {
- txbd = &priv->tx_bd_vbase[i];
- skb = priv->tx_skb[i];
- paddr = QTN_HOST_ADDR(le32_to_cpu(txbd->addr_h),
- le32_to_cpu(txbd->addr));
- pci_unmap_single(priv->pdev, paddr, skb->len,
- PCI_DMA_TODEVICE);
- dev_kfree_skb_any(skb);
- priv->tx_skb[i] = NULL;
- }
- }
-}
-
-static int qtnf_hhbm_init(struct qtnf_pcie_bus_priv *priv)
-{
- u32 val;
-
- val = readl(PCIE_HHBM_CONFIG(priv->pcie_reg_base));
- val |= HHBM_CONFIG_SOFT_RESET;
- writel(val, PCIE_HHBM_CONFIG(priv->pcie_reg_base));
- usleep_range(50, 100);
- val &= ~HHBM_CONFIG_SOFT_RESET;
-#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
- val |= HHBM_64BIT;
-#endif
- writel(val, PCIE_HHBM_CONFIG(priv->pcie_reg_base));
- writel(priv->rx_bd_num, PCIE_HHBM_Q_LIMIT_REG(priv->pcie_reg_base));
-
- return 0;
-}
-
-static int qtnf_pcie_init_xfer(struct qtnf_pcie_bus_priv *priv)
-{
- int ret;
- u32 val;
-
- priv->tx_bd_num = tx_bd_size_param;
- priv->rx_bd_num = rx_bd_size_param;
- priv->rx_bd_w_index = 0;
- priv->rx_bd_r_index = 0;
-
- if (!priv->tx_bd_num || !is_power_of_2(priv->tx_bd_num)) {
- pr_err("tx_bd_size_param %u is not power of two\n",
- priv->tx_bd_num);
- return -EINVAL;
- }
-
- val = priv->tx_bd_num * sizeof(struct qtnf_tx_bd);
- if (val > PCIE_HHBM_MAX_SIZE) {
- pr_err("tx_bd_size_param %u is too large\n",
- priv->tx_bd_num);
- return -EINVAL;
- }
-
- if (!priv->rx_bd_num || !is_power_of_2(priv->rx_bd_num)) {
- pr_err("rx_bd_size_param %u is not power of two\n",
- priv->rx_bd_num);
- return -EINVAL;
- }
-
- val = priv->rx_bd_num * sizeof(dma_addr_t);
- if (val > PCIE_HHBM_MAX_SIZE) {
- pr_err("rx_bd_size_param %u is too large\n",
- priv->rx_bd_num);
- return -EINVAL;
- }
-
- ret = qtnf_hhbm_init(priv);
- if (ret) {
- pr_err("failed to init h/w queues\n");
- return ret;
- }
-
- ret = alloc_skb_array(priv);
- if (ret) {
- pr_err("failed to allocate skb array\n");
- return ret;
- }
-
- ret = alloc_bd_table(priv);
- if (ret) {
- pr_err("failed to allocate bd table\n");
- return ret;
- }
-
- ret = alloc_rx_buffers(priv);
- if (ret) {
- pr_err("failed to allocate rx buffers\n");
- return ret;
- }
-
- return ret;
-}
-
-static void qtnf_pcie_data_tx_reclaim(struct qtnf_pcie_bus_priv *priv)
-{
- struct qtnf_tx_bd *txbd;
- struct sk_buff *skb;
- unsigned long flags;
- dma_addr_t paddr;
- u32 tx_done_index;
- int count = 0;
- int i;
-
- spin_lock_irqsave(&priv->tx_reclaim_lock, flags);
-
- tx_done_index = readl(PCIE_HDP_RX0DMA_CNT(priv->pcie_reg_base))
- & (priv->tx_bd_num - 1);
-
- i = priv->tx_bd_r_index;
-
- while (CIRC_CNT(tx_done_index, i, priv->tx_bd_num)) {
- skb = priv->tx_skb[i];
- if (likely(skb)) {
- txbd = &priv->tx_bd_vbase[i];
- paddr = QTN_HOST_ADDR(le32_to_cpu(txbd->addr_h),
- le32_to_cpu(txbd->addr));
- pci_unmap_single(priv->pdev, paddr, skb->len,
- PCI_DMA_TODEVICE);
-
- if (skb->dev) {
- qtnf_update_tx_stats(skb->dev, skb);
- if (unlikely(priv->tx_stopped)) {
- qtnf_wake_all_queues(skb->dev);
- priv->tx_stopped = 0;
- }
- }
-
- dev_kfree_skb_any(skb);
- }
-
- priv->tx_skb[i] = NULL;
- count++;
-
- if (++i >= priv->tx_bd_num)
- i = 0;
- }
-
- priv->tx_reclaim_done += count;
- priv->tx_reclaim_req++;
- priv->tx_bd_r_index = i;
-
- spin_unlock_irqrestore(&priv->tx_reclaim_lock, flags);
-}
-
-static int qtnf_tx_queue_ready(struct qtnf_pcie_bus_priv *priv)
-{
- if (!CIRC_SPACE(priv->tx_bd_w_index, priv->tx_bd_r_index,
- priv->tx_bd_num)) {
- qtnf_pcie_data_tx_reclaim(priv);
-
- if (!CIRC_SPACE(priv->tx_bd_w_index, priv->tx_bd_r_index,
- priv->tx_bd_num)) {
- pr_warn_ratelimited("reclaim full Tx queue\n");
- priv->tx_full_count++;
- return 0;
- }
- }
-
- return 1;
-}
-
-static int qtnf_pcie_data_tx(struct qtnf_bus *bus, struct sk_buff *skb)
-{
- struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus);
- dma_addr_t txbd_paddr, skb_paddr;
- struct qtnf_tx_bd *txbd;
- unsigned long flags;
- int len, i;
- u32 info;
- int ret = 0;
-
- spin_lock_irqsave(&priv->tx0_lock, flags);
-
- if (!qtnf_tx_queue_ready(priv)) {
- if (skb->dev) {
- netif_tx_stop_all_queues(skb->dev);
- priv->tx_stopped = 1;
- }
-
- spin_unlock_irqrestore(&priv->tx0_lock, flags);
- return NETDEV_TX_BUSY;
- }
-
- i = priv->tx_bd_w_index;
- priv->tx_skb[i] = skb;
- len = skb->len;
-
- skb_paddr = pci_map_single(priv->pdev, skb->data,
- skb->len, PCI_DMA_TODEVICE);
- if (pci_dma_mapping_error(priv->pdev, skb_paddr)) {
- pr_err("skb DMA mapping error: %pad\n", &skb_paddr);
- ret = -ENOMEM;
- goto tx_done;
- }
-
- txbd = &priv->tx_bd_vbase[i];
- txbd->addr = cpu_to_le32(QTN_HOST_LO32(skb_paddr));
- txbd->addr_h = cpu_to_le32(QTN_HOST_HI32(skb_paddr));
-
- info = (len & QTN_PCIE_TX_DESC_LEN_MASK) << QTN_PCIE_TX_DESC_LEN_SHIFT;
- txbd->info = cpu_to_le32(info);
-
- /* sync up all descriptor updates before passing them to EP */
- dma_wmb();
-
- /* write new TX descriptor to PCIE_RX_FIFO on EP */
- txbd_paddr = priv->tx_bd_pbase + i * sizeof(struct qtnf_tx_bd);
-
-#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
- writel(QTN_HOST_HI32(txbd_paddr),
- PCIE_HDP_HOST_WR_DESC0_H(priv->pcie_reg_base));
-#endif
- writel(QTN_HOST_LO32(txbd_paddr),
- PCIE_HDP_HOST_WR_DESC0(priv->pcie_reg_base));
-
- if (++i >= priv->tx_bd_num)
- i = 0;
-
- priv->tx_bd_w_index = i;
-
-tx_done:
- if (ret && skb) {
- pr_err_ratelimited("drop skb\n");
- if (skb->dev)
- skb->dev->stats.tx_dropped++;
- dev_kfree_skb_any(skb);
- }
-
- priv->tx_done_count++;
- spin_unlock_irqrestore(&priv->tx0_lock, flags);
-
- qtnf_pcie_data_tx_reclaim(priv);
-
- return NETDEV_TX_OK;
-}
-
-static int qtnf_pcie_control_tx(struct qtnf_bus *bus, struct sk_buff *skb)
-{
- struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus);
- int ret;
-
- ret = qtnf_shm_ipc_send(&priv->shm_ipc_ep_in, skb->data, skb->len);
-
- if (ret == -ETIMEDOUT) {
- pr_err("EP firmware is dead\n");
- bus->fw_state = QTNF_FW_STATE_EP_DEAD;
- }
-
- return ret;
-}
-
-static irqreturn_t qtnf_interrupt(int irq, void *data)
-{
- struct qtnf_bus *bus = (struct qtnf_bus *)data;
- struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus);
- u32 status;
-
- priv->pcie_irq_count++;
- status = readl(PCIE_HDP_INT_STATUS(priv->pcie_reg_base));
-
- qtnf_shm_ipc_irq_handler(&priv->shm_ipc_ep_in);
- qtnf_shm_ipc_irq_handler(&priv->shm_ipc_ep_out);
-
- if (!(status & priv->pcie_irq_mask))
- goto irq_done;
-
- if (status & PCIE_HDP_INT_RX_BITS)
- priv->pcie_irq_rx_count++;
-
- if (status & PCIE_HDP_INT_TX_BITS)
- priv->pcie_irq_tx_count++;
-
- if (status & PCIE_HDP_INT_HHBM_UF)
- priv->pcie_irq_uf_count++;
-
- if (status & PCIE_HDP_INT_RX_BITS) {
- qtnf_dis_rxdone_irq(priv);
- napi_schedule(&bus->mux_napi);
- }
-
- if (status & PCIE_HDP_INT_TX_BITS) {
- qtnf_dis_txdone_irq(priv);
- tasklet_hi_schedule(&priv->reclaim_tq);
- }
-
-irq_done:
- /* H/W workaround: clean all bits, not only enabled */
- qtnf_non_posted_write(~0U, PCIE_HDP_INT_STATUS(priv->pcie_reg_base));
-
- if (!priv->msi_enabled)
- qtnf_deassert_intx(priv);
-
- return IRQ_HANDLED;
-}
-
-static int qtnf_rx_data_ready(struct qtnf_pcie_bus_priv *priv)
-{
- u16 index = priv->rx_bd_r_index;
- struct qtnf_rx_bd *rxbd;
- u32 descw;
-
- rxbd = &priv->rx_bd_vbase[index];
- descw = le32_to_cpu(rxbd->info);
-
- if (descw & QTN_TXDONE_MASK)
- return 1;
-
- return 0;
-}
-
-static int qtnf_rx_poll(struct napi_struct *napi, int budget)
-{
- struct qtnf_bus *bus = container_of(napi, struct qtnf_bus, mux_napi);
- struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus);
- struct net_device *ndev = NULL;
- struct sk_buff *skb = NULL;
- int processed = 0;
- struct qtnf_rx_bd *rxbd;
- dma_addr_t skb_paddr;
- int consume;
- u32 descw;
- u32 psize;
- u16 r_idx;
- u16 w_idx;
- int ret;
-
- while (processed < budget) {
-
-
- if (!qtnf_rx_data_ready(priv))
- goto rx_out;
-
- r_idx = priv->rx_bd_r_index;
- rxbd = &priv->rx_bd_vbase[r_idx];
- descw = le32_to_cpu(rxbd->info);
-
- skb = priv->rx_skb[r_idx];
- psize = QTN_GET_LEN(descw);
- consume = 1;
-
- if (!(descw & QTN_TXDONE_MASK)) {
- pr_warn("skip invalid rxbd[%d]\n", r_idx);
- consume = 0;
- }
-
- if (!skb) {
- pr_warn("skip missing rx_skb[%d]\n", r_idx);
- consume = 0;
- }
-
- if (skb && (skb_tailroom(skb) < psize)) {
- pr_err("skip packet with invalid length: %u > %u\n",
- psize, skb_tailroom(skb));
- consume = 0;
- }
-
- if (skb) {
- skb_paddr = QTN_HOST_ADDR(le32_to_cpu(rxbd->addr_h),
- le32_to_cpu(rxbd->addr));
- pci_unmap_single(priv->pdev, skb_paddr, SKB_BUF_SIZE,
- PCI_DMA_FROMDEVICE);
- }
-
- if (consume) {
- skb_put(skb, psize);
- ndev = qtnf_classify_skb(bus, skb);
- if (likely(ndev)) {
- qtnf_update_rx_stats(ndev, skb);
- skb->protocol = eth_type_trans(skb, ndev);
- napi_gro_receive(napi, skb);
- } else {
- pr_debug("drop untagged skb\n");
- bus->mux_dev.stats.rx_dropped++;
- dev_kfree_skb_any(skb);
- }
- } else {
- if (skb) {
- bus->mux_dev.stats.rx_dropped++;
- dev_kfree_skb_any(skb);
- }
- }
-
- priv->rx_skb[r_idx] = NULL;
- if (++r_idx >= priv->rx_bd_num)
- r_idx = 0;
-
- priv->rx_bd_r_index = r_idx;
-
- /* repalce processed buffer by a new one */
- w_idx = priv->rx_bd_w_index;
- while (CIRC_SPACE(priv->rx_bd_w_index, priv->rx_bd_r_index,
- priv->rx_bd_num) > 0) {
- if (++w_idx >= priv->rx_bd_num)
- w_idx = 0;
-
- ret = skb2rbd_attach(priv, w_idx);
- if (ret) {
- pr_err("failed to allocate new rx_skb[%d]\n",
- w_idx);
- break;
- }
- }
-
- processed++;
- }
-
-rx_out:
- if (processed < budget) {
- napi_complete(napi);
- qtnf_en_rxdone_irq(priv);
- }
-
- return processed;
-}
-
-static void
-qtnf_pcie_data_tx_timeout(struct qtnf_bus *bus, struct net_device *ndev)
-{
- struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus);
-
- tasklet_hi_schedule(&priv->reclaim_tq);
-}
-
-static void qtnf_pcie_data_rx_start(struct qtnf_bus *bus)
-{
- struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus);
-
- qtnf_enable_hdp_irqs(priv);
- napi_enable(&bus->mux_napi);
-}
-
-static void qtnf_pcie_data_rx_stop(struct qtnf_bus *bus)
-{
- struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus);
-
- napi_disable(&bus->mux_napi);
- qtnf_disable_hdp_irqs(priv);
-}
-
-static const struct qtnf_bus_ops qtnf_pcie_bus_ops = {
- /* control path methods */
- .control_tx = qtnf_pcie_control_tx,
-
- /* data path methods */
- .data_tx = qtnf_pcie_data_tx,
- .data_tx_timeout = qtnf_pcie_data_tx_timeout,
- .data_rx_start = qtnf_pcie_data_rx_start,
- .data_rx_stop = qtnf_pcie_data_rx_stop,
-};
-
-static int qtnf_dbg_mps_show(struct seq_file *s, void *data)
-{
- struct qtnf_bus *bus = dev_get_drvdata(s->private);
- struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus);
-
- seq_printf(s, "%d\n", priv->mps);
-
- return 0;
-}
-
-static int qtnf_dbg_msi_show(struct seq_file *s, void *data)
-{
- struct qtnf_bus *bus = dev_get_drvdata(s->private);
- struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus);
-
- seq_printf(s, "%u\n", priv->msi_enabled);
-
- return 0;
-}
-
-static int qtnf_dbg_irq_stats(struct seq_file *s, void *data)
-{
- struct qtnf_bus *bus = dev_get_drvdata(s->private);
- struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus);
- u32 reg = readl(PCIE_HDP_INT_EN(priv->pcie_reg_base));
- u32 status;
-
- seq_printf(s, "pcie_irq_count(%u)\n", priv->pcie_irq_count);
- seq_printf(s, "pcie_irq_tx_count(%u)\n", priv->pcie_irq_tx_count);
- status = reg & PCIE_HDP_INT_TX_BITS;
- seq_printf(s, "pcie_irq_tx_status(%s)\n",
- (status == PCIE_HDP_INT_TX_BITS) ? "EN" : "DIS");
- seq_printf(s, "pcie_irq_rx_count(%u)\n", priv->pcie_irq_rx_count);
- status = reg & PCIE_HDP_INT_RX_BITS;
- seq_printf(s, "pcie_irq_rx_status(%s)\n",
- (status == PCIE_HDP_INT_RX_BITS) ? "EN" : "DIS");
- seq_printf(s, "pcie_irq_uf_count(%u)\n", priv->pcie_irq_uf_count);
- status = reg & PCIE_HDP_INT_HHBM_UF;
- seq_printf(s, "pcie_irq_hhbm_uf_status(%s)\n",
- (status == PCIE_HDP_INT_HHBM_UF) ? "EN" : "DIS");
-
- return 0;
-}
-
-static int qtnf_dbg_hdp_stats(struct seq_file *s, void *data)
-{
- struct qtnf_bus *bus = dev_get_drvdata(s->private);
- struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus);
-
- seq_printf(s, "tx_full_count(%u)\n", priv->tx_full_count);
- seq_printf(s, "tx_done_count(%u)\n", priv->tx_done_count);
- seq_printf(s, "tx_reclaim_done(%u)\n", priv->tx_reclaim_done);
- seq_printf(s, "tx_reclaim_req(%u)\n", priv->tx_reclaim_req);
-
- seq_printf(s, "tx_bd_r_index(%u)\n", priv->tx_bd_r_index);
- seq_printf(s, "tx_bd_p_index(%u)\n",
- readl(PCIE_HDP_RX0DMA_CNT(priv->pcie_reg_base))
- & (priv->tx_bd_num - 1));
- seq_printf(s, "tx_bd_w_index(%u)\n", priv->tx_bd_w_index);
- seq_printf(s, "tx queue len(%u)\n",
- CIRC_CNT(priv->tx_bd_w_index, priv->tx_bd_r_index,
- priv->tx_bd_num));
-
- seq_printf(s, "rx_bd_r_index(%u)\n", priv->rx_bd_r_index);
- seq_printf(s, "rx_bd_p_index(%u)\n",
- readl(PCIE_HDP_TX0DMA_CNT(priv->pcie_reg_base))
- & (priv->rx_bd_num - 1));
- seq_printf(s, "rx_bd_w_index(%u)\n", priv->rx_bd_w_index);
- seq_printf(s, "rx alloc queue len(%u)\n",
- CIRC_SPACE(priv->rx_bd_w_index, priv->rx_bd_r_index,
- priv->rx_bd_num));
-
- return 0;
-}
-
-static int qtnf_dbg_shm_stats(struct seq_file *s, void *data)
-{
- struct qtnf_bus *bus = dev_get_drvdata(s->private);
- struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus);
-
- seq_printf(s, "shm_ipc_ep_in.tx_packet_count(%zu)\n",
- priv->shm_ipc_ep_in.tx_packet_count);
- seq_printf(s, "shm_ipc_ep_in.rx_packet_count(%zu)\n",
- priv->shm_ipc_ep_in.rx_packet_count);
- seq_printf(s, "shm_ipc_ep_out.tx_packet_count(%zu)\n",
- priv->shm_ipc_ep_out.tx_timeout_count);
- seq_printf(s, "shm_ipc_ep_out.rx_packet_count(%zu)\n",
- priv->shm_ipc_ep_out.rx_packet_count);
-
- return 0;
-}
-
-static int qtnf_ep_fw_send(struct qtnf_pcie_bus_priv *priv, uint32_t size,
- int blk, const u8 *pblk, const u8 *fw)
-{
- struct pci_dev *pdev = priv->pdev;
- struct qtnf_bus *bus = pci_get_drvdata(pdev);
-
- struct qtnf_pcie_fw_hdr *hdr;
- u8 *pdata;
-
- int hds = sizeof(*hdr);
- struct sk_buff *skb = NULL;
- int len = 0;
- int ret;
-
- skb = __dev_alloc_skb(QTN_PCIE_FW_BUFSZ, GFP_KERNEL);
- if (!skb)
- return -ENOMEM;
-
- skb->len = QTN_PCIE_FW_BUFSZ;
- skb->dev = NULL;
-
- hdr = (struct qtnf_pcie_fw_hdr *)skb->data;
- memcpy(hdr->boardflg, QTN_PCIE_BOARDFLG, strlen(QTN_PCIE_BOARDFLG));
- hdr->fwsize = cpu_to_le32(size);
- hdr->seqnum = cpu_to_le32(blk);
-
- if (blk)
- hdr->type = cpu_to_le32(QTN_FW_DSUB);
- else
- hdr->type = cpu_to_le32(QTN_FW_DBEGIN);
-
- pdata = skb->data + hds;
-
- len = QTN_PCIE_FW_BUFSZ - hds;
- if (pblk >= (fw + size - len)) {
- len = fw + size - pblk;
- hdr->type = cpu_to_le32(QTN_FW_DEND);
- }
-
- hdr->pktlen = cpu_to_le32(len);
- memcpy(pdata, pblk, len);
- hdr->crc = cpu_to_le32(~crc32(0, pdata, len));
-
- ret = qtnf_pcie_data_tx(bus, skb);
-
- return (ret == NETDEV_TX_OK) ? len : 0;
-}
-
-static int
-qtnf_ep_fw_load(struct qtnf_pcie_bus_priv *priv, const u8 *fw, u32 fw_size)
-{
- int blk_size = QTN_PCIE_FW_BUFSZ - sizeof(struct qtnf_pcie_fw_hdr);
- int blk_count = fw_size / blk_size + ((fw_size % blk_size) ? 1 : 0);
- const u8 *pblk = fw;
- int threshold = 0;
- int blk = 0;
- int len;
-
- pr_debug("FW upload started: fw_addr=0x%p size=%d\n", fw, fw_size);
-
- while (blk < blk_count) {
- if (++threshold > 10000) {
- pr_err("FW upload failed: too many retries\n");
- return -ETIMEDOUT;
- }
-
- len = qtnf_ep_fw_send(priv, fw_size, blk, pblk, fw);
- if (len <= 0)
- continue;
-
- if (!((blk + 1) & QTN_PCIE_FW_DLMASK) ||
- (blk == (blk_count - 1))) {
- qtnf_set_state(&priv->bda->bda_rc_state,
- QTN_RC_FW_SYNC);
- if (qtnf_poll_state(&priv->bda->bda_ep_state,
- QTN_EP_FW_SYNC,
- QTN_FW_DL_TIMEOUT_MS)) {
- pr_err("FW upload failed: SYNC timed out\n");
- return -ETIMEDOUT;
- }
-
- qtnf_clear_state(&priv->bda->bda_ep_state,
- QTN_EP_FW_SYNC);
-
- if (qtnf_is_state(&priv->bda->bda_ep_state,
- QTN_EP_FW_RETRY)) {
- if (blk == (blk_count - 1)) {
- int last_round =
- blk_count & QTN_PCIE_FW_DLMASK;
- blk -= last_round;
- pblk -= ((last_round - 1) *
- blk_size + len);
- } else {
- blk -= QTN_PCIE_FW_DLMASK;
- pblk -= QTN_PCIE_FW_DLMASK * blk_size;
- }
-
- qtnf_clear_state(&priv->bda->bda_ep_state,
- QTN_EP_FW_RETRY);
-
- pr_warn("FW upload retry: block #%d\n", blk);
- continue;
- }
-
- qtnf_pcie_data_tx_reclaim(priv);
- }
-
- pblk += len;
- blk++;
- }
-
- pr_debug("FW upload completed: totally sent %d blocks\n", blk);
- return 0;
-}
-
-static void qtnf_fw_work_handler(struct work_struct *work)
-{
- struct qtnf_bus *bus = container_of(work, struct qtnf_bus, fw_work);
- struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus);
- struct pci_dev *pdev = priv->pdev;
- const struct firmware *fw;
- int ret;
- u32 state = QTN_RC_FW_LOADRDY | QTN_RC_FW_QLINK;
-
- if (flashboot) {
- state |= QTN_RC_FW_FLASHBOOT;
- } else {
- ret = request_firmware(&fw, bus->fwname, &pdev->dev);
- if (ret < 0) {
- pr_err("failed to get firmware %s\n", bus->fwname);
- goto fw_load_fail;
- }
- }
-
- qtnf_set_state(&priv->bda->bda_rc_state, state);
-
- if (qtnf_poll_state(&priv->bda->bda_ep_state, QTN_EP_FW_LOADRDY,
- QTN_FW_DL_TIMEOUT_MS)) {
- pr_err("card is not ready\n");
-
- if (!flashboot)
- release_firmware(fw);
-
- goto fw_load_fail;
- }
-
- qtnf_clear_state(&priv->bda->bda_ep_state, QTN_EP_FW_LOADRDY);
-
- if (flashboot) {
- pr_info("booting firmware from flash\n");
- } else {
- pr_info("starting firmware upload: %s\n", bus->fwname);
-
- ret = qtnf_ep_fw_load(priv, fw->data, fw->size);
- release_firmware(fw);
- if (ret) {
- pr_err("firmware upload error\n");
- goto fw_load_fail;
- }
- }
-
- if (qtnf_poll_state(&priv->bda->bda_ep_state, QTN_EP_FW_DONE,
- QTN_FW_DL_TIMEOUT_MS)) {
- pr_err("firmware bringup timed out\n");
- goto fw_load_fail;
- }
-
- bus->fw_state = QTNF_FW_STATE_FW_DNLD_DONE;
- pr_info("firmware is up and running\n");
-
- if (qtnf_poll_state(&priv->bda->bda_ep_state,
- QTN_EP_FW_QLINK_DONE, QTN_FW_QLINK_TIMEOUT_MS)) {
- pr_err("firmware runtime failure\n");
- goto fw_load_fail;
- }
-
- ret = qtnf_core_attach(bus);
- if (ret) {
- pr_err("failed to attach core\n");
- goto fw_load_fail;
- }
-
- qtnf_debugfs_init(bus, DRV_NAME);
- qtnf_debugfs_add_entry(bus, "mps", qtnf_dbg_mps_show);
- qtnf_debugfs_add_entry(bus, "msi_enabled", qtnf_dbg_msi_show);
- qtnf_debugfs_add_entry(bus, "hdp_stats", qtnf_dbg_hdp_stats);
- qtnf_debugfs_add_entry(bus, "irq_stats", qtnf_dbg_irq_stats);
- qtnf_debugfs_add_entry(bus, "shm_stats", qtnf_dbg_shm_stats);
-
- goto fw_load_exit;
-
-fw_load_fail:
- bus->fw_state = QTNF_FW_STATE_DETACHED;
-
-fw_load_exit:
- complete(&bus->firmware_init_complete);
- put_device(&pdev->dev);
-}
-
-static void qtnf_bringup_fw_async(struct qtnf_bus *bus)
-{
- struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus);
- struct pci_dev *pdev = priv->pdev;
-
- get_device(&pdev->dev);
- INIT_WORK(&bus->fw_work, qtnf_fw_work_handler);
- schedule_work(&bus->fw_work);
-}
-
-static void qtnf_reclaim_tasklet_fn(unsigned long data)
-{
- struct qtnf_pcie_bus_priv *priv = (void *)data;
-
- qtnf_pcie_data_tx_reclaim(priv);
- qtnf_en_txdone_irq(priv);
-}
-
-static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
-{
- struct qtnf_pcie_bus_priv *pcie_priv;
- struct qtnf_bus *bus;
- int ret;
-
- bus = devm_kzalloc(&pdev->dev,
- sizeof(*bus) + sizeof(*pcie_priv), GFP_KERNEL);
- if (!bus)
- return -ENOMEM;
-
- pcie_priv = get_bus_priv(bus);
-
- pci_set_drvdata(pdev, bus);
- bus->bus_ops = &qtnf_pcie_bus_ops;
- bus->dev = &pdev->dev;
- bus->fw_state = QTNF_FW_STATE_RESET;
- pcie_priv->pdev = pdev;
-
- strcpy(bus->fwname, QTN_PCI_PEARL_FW_NAME);
- init_completion(&bus->firmware_init_complete);
- mutex_init(&bus->bus_lock);
- spin_lock_init(&pcie_priv->tx0_lock);
- spin_lock_init(&pcie_priv->irq_lock);
- spin_lock_init(&pcie_priv->tx_reclaim_lock);
-
- /* init stats */
- pcie_priv->tx_full_count = 0;
- pcie_priv->tx_done_count = 0;
- pcie_priv->pcie_irq_count = 0;
- pcie_priv->pcie_irq_rx_count = 0;
- pcie_priv->pcie_irq_tx_count = 0;
- pcie_priv->pcie_irq_uf_count = 0;
- pcie_priv->tx_reclaim_done = 0;
- pcie_priv->tx_reclaim_req = 0;
-
- tasklet_init(&pcie_priv->reclaim_tq, qtnf_reclaim_tasklet_fn,
- (unsigned long)pcie_priv);
-
- init_dummy_netdev(&bus->mux_dev);
- netif_napi_add(&bus->mux_dev, &bus->mux_napi,
- qtnf_rx_poll, 10);
-
- pcie_priv->workqueue = create_singlethread_workqueue("QTNF_PEARL_PCIE");
- if (!pcie_priv->workqueue) {
- pr_err("failed to alloc bus workqueue\n");
- ret = -ENODEV;
- goto err_init;
- }
-
- if (!pci_is_pcie(pdev)) {
- pr_err("device %s is not PCI Express\n", pci_name(pdev));
- ret = -EIO;
- goto err_base;
- }
-
- qtnf_tune_pcie_mps(pcie_priv);
-
- ret = pcim_enable_device(pdev);
- if (ret) {
- pr_err("failed to init PCI device %x\n", pdev->device);
- goto err_base;
- } else {
- pr_debug("successful init of PCI device %x\n", pdev->device);
- }
-
-#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
- ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
-#else
- ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
-#endif
- if (ret) {
- pr_err("PCIE DMA coherent mask init failed\n");
- goto err_base;
- }
-
- pci_set_master(pdev);
- qtnf_pcie_init_irq(pcie_priv);
-
- ret = qtnf_pcie_init_memory(pcie_priv);
- if (ret < 0) {
- pr_err("PCIE memory init failed\n");
- goto err_base;
- }
-
- pci_save_state(pdev);
-
- ret = qtnf_pcie_init_shm_ipc(pcie_priv);
- if (ret < 0) {
- pr_err("PCIE SHM IPC init failed\n");
- goto err_base;
- }
-
- ret = qtnf_pcie_init_xfer(pcie_priv);
- if (ret) {
- pr_err("PCIE xfer init failed\n");
- goto err_ipc;
- }
-
- /* init default irq settings */
- qtnf_init_hdp_irqs(pcie_priv);
-
- /* start with disabled irqs */
- qtnf_disable_hdp_irqs(pcie_priv);
-
- ret = devm_request_irq(&pdev->dev, pdev->irq, &qtnf_interrupt, 0,
- "qtnf_pcie_irq", (void *)bus);
- if (ret) {
- pr_err("failed to request pcie irq %d\n", pdev->irq);
- goto err_xfer;
- }
-
- qtnf_bringup_fw_async(bus);
-
- return 0;
-
-err_xfer:
- qtnf_free_xfer_buffers(pcie_priv);
-
-err_ipc:
- qtnf_pcie_free_shm_ipc(pcie_priv);
-
-err_base:
- flush_workqueue(pcie_priv->workqueue);
- destroy_workqueue(pcie_priv->workqueue);
- netif_napi_del(&bus->mux_napi);
-
-err_init:
- tasklet_kill(&pcie_priv->reclaim_tq);
- pci_set_drvdata(pdev, NULL);
-
- return ret;
-}
-
-static void qtnf_pcie_remove(struct pci_dev *pdev)
-{
- struct qtnf_pcie_bus_priv *priv;
- struct qtnf_bus *bus;
-
- bus = pci_get_drvdata(pdev);
- if (!bus)
- return;
-
- wait_for_completion(&bus->firmware_init_complete);
-
- if (bus->fw_state == QTNF_FW_STATE_ACTIVE ||
- bus->fw_state == QTNF_FW_STATE_EP_DEAD)
- qtnf_core_detach(bus);
-
- priv = get_bus_priv(bus);
-
- netif_napi_del(&bus->mux_napi);
- flush_workqueue(priv->workqueue);
- destroy_workqueue(priv->workqueue);
- tasklet_kill(&priv->reclaim_tq);
-
- qtnf_free_xfer_buffers(priv);
- qtnf_debugfs_remove(bus);
-
- qtnf_pcie_free_shm_ipc(priv);
- qtnf_reset_card(priv);
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int qtnf_pcie_suspend(struct device *dev)
-{
- return -EOPNOTSUPP;
-}
-
-static int qtnf_pcie_resume(struct device *dev)
-{
- return 0;
-}
-#endif /* CONFIG_PM_SLEEP */
-
-#ifdef CONFIG_PM_SLEEP
-/* Power Management Hooks */
-static SIMPLE_DEV_PM_OPS(qtnf_pcie_pm_ops, qtnf_pcie_suspend,
- qtnf_pcie_resume);
-#endif
-
-static const struct pci_device_id qtnf_pcie_devid_table[] = {
- {
- PCIE_VENDOR_ID_QUANTENNA, PCIE_DEVICE_ID_QTN_PEARL,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- },
- { },
-};
-
-MODULE_DEVICE_TABLE(pci, qtnf_pcie_devid_table);
-
-static struct pci_driver qtnf_pcie_drv_data = {
- .name = DRV_NAME,
- .id_table = qtnf_pcie_devid_table,
- .probe = qtnf_pcie_probe,
- .remove = qtnf_pcie_remove,
-#ifdef CONFIG_PM_SLEEP
- .driver = {
- .pm = &qtnf_pcie_pm_ops,
- },
-#endif
-};
-
-static int __init qtnf_pcie_register(void)
-{
- pr_info("register Quantenna QSR10g FullMAC PCIE driver\n");
- return pci_register_driver(&qtnf_pcie_drv_data);
-}
-
-static void __exit qtnf_pcie_exit(void)
-{
- pr_info("unregister Quantenna QSR10g FullMAC PCIE driver\n");
- pci_unregister_driver(&qtnf_pcie_drv_data);
-}
-
-module_init(qtnf_pcie_register);
-module_exit(qtnf_pcie_exit);
-
-MODULE_AUTHOR("Quantenna Communications");
-MODULE_DESCRIPTION("Quantenna QSR10g PCIe bus driver for 802.11 wireless LAN.");
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_bus_priv.h b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_bus_priv.h
deleted file mode 100644
index 397875a50fc2..000000000000
--- a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_bus_priv.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (c) 2015-2016 Quantenna Communications, 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 Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#ifndef _QTN_FMAC_PCIE_H_
-#define _QTN_FMAC_PCIE_H_
-
-#include <linux/dma-mapping.h>
-#include <linux/io.h>
-
-#include "pcie_regs_pearl.h"
-#include "pcie_ipc.h"
-#include "shm_ipc.h"
-
-struct bus;
-
-struct qtnf_pcie_bus_priv {
- struct pci_dev *pdev;
-
- /* lock for irq configuration changes */
- spinlock_t irq_lock;
-
- /* lock for tx reclaim operations */
- spinlock_t tx_reclaim_lock;
- /* lock for tx0 operations */
- spinlock_t tx0_lock;
- u8 msi_enabled;
- u8 tx_stopped;
- int mps;
-
- struct workqueue_struct *workqueue;
- struct tasklet_struct reclaim_tq;
-
- void __iomem *sysctl_bar;
- void __iomem *epmem_bar;
- void __iomem *dmareg_bar;
-
- struct qtnf_shm_ipc shm_ipc_ep_in;
- struct qtnf_shm_ipc shm_ipc_ep_out;
-
- struct qtnf_pcie_bda __iomem *bda;
- void __iomem *pcie_reg_base;
-
- u16 tx_bd_num;
- u16 rx_bd_num;
-
- struct sk_buff **tx_skb;
- struct sk_buff **rx_skb;
-
- struct qtnf_tx_bd *tx_bd_vbase;
- dma_addr_t tx_bd_pbase;
-
- struct qtnf_rx_bd *rx_bd_vbase;
- dma_addr_t rx_bd_pbase;
-
- dma_addr_t bd_table_paddr;
- void *bd_table_vaddr;
- u32 bd_table_len;
-
- u32 rx_bd_w_index;
- u32 rx_bd_r_index;
-
- u32 tx_bd_w_index;
- u32 tx_bd_r_index;
-
- u32 pcie_irq_mask;
-
- /* diagnostics stats */
- u32 pcie_irq_count;
- u32 pcie_irq_rx_count;
- u32 pcie_irq_tx_count;
- u32 pcie_irq_uf_count;
- u32 tx_full_count;
- u32 tx_done_count;
- u32 tx_reclaim_done;
- u32 tx_reclaim_req;
-};
-
-#endif /* _QTN_FMAC_PCIE_H_ */
diff --git a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_regs_pearl.h b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_regs_pearl.h
deleted file mode 100644
index 0bfe285b6b48..000000000000
--- a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_regs_pearl.h
+++ /dev/null
@@ -1,356 +0,0 @@
-/*
- * Copyright (c) 2015 Quantenna Communications, 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 Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#ifndef __PEARL_PCIE_H
-#define __PEARL_PCIE_H
-
-#define PCIE_GEN2_BASE (0xe9000000)
-#define PCIE_GEN3_BASE (0xe7000000)
-
-#define PEARL_CUR_PCIE_BASE (PCIE_GEN2_BASE)
-#define PCIE_HDP_OFFSET (0x2000)
-
-#define PCIE_HDP_CTRL(base) ((base) + 0x2c00)
-#define PCIE_HDP_AXI_CTRL(base) ((base) + 0x2c04)
-#define PCIE_HDP_HOST_WR_DESC0(base) ((base) + 0x2c10)
-#define PCIE_HDP_HOST_WR_DESC0_H(base) ((base) + 0x2c14)
-#define PCIE_HDP_HOST_WR_DESC1(base) ((base) + 0x2c18)
-#define PCIE_HDP_HOST_WR_DESC1_H(base) ((base) + 0x2c1c)
-#define PCIE_HDP_HOST_WR_DESC2(base) ((base) + 0x2c20)
-#define PCIE_HDP_HOST_WR_DESC2_H(base) ((base) + 0x2c24)
-#define PCIE_HDP_HOST_WR_DESC3(base) ((base) + 0x2c28)
-#define PCIE_HDP_HOST_WR_DESC4_H(base) ((base) + 0x2c2c)
-#define PCIE_HDP_RX_INT_CTRL(base) ((base) + 0x2c30)
-#define PCIE_HDP_TX_INT_CTRL(base) ((base) + 0x2c34)
-#define PCIE_HDP_INT_STATUS(base) ((base) + 0x2c38)
-#define PCIE_HDP_INT_EN(base) ((base) + 0x2c3c)
-#define PCIE_HDP_RX_DESC0_PTR(base) ((base) + 0x2c40)
-#define PCIE_HDP_RX_DESC0_NOE(base) ((base) + 0x2c44)
-#define PCIE_HDP_RX_DESC1_PTR(base) ((base) + 0x2c48)
-#define PCIE_HDP_RX_DESC1_NOE(base) ((base) + 0x2c4c)
-#define PCIE_HDP_RX_DESC2_PTR(base) ((base) + 0x2c50)
-#define PCIE_HDP_RX_DESC2_NOE(base) ((base) + 0x2c54)
-#define PCIE_HDP_RX_DESC3_PTR(base) ((base) + 0x2c58)
-#define PCIE_HDP_RX_DESC3_NOE(base) ((base) + 0x2c5c)
-
-#define PCIE_HDP_TX0_BASE_ADDR(base) ((base) + 0x2c60)
-#define PCIE_HDP_TX1_BASE_ADDR(base) ((base) + 0x2c64)
-#define PCIE_HDP_TX0_Q_CTRL(base) ((base) + 0x2c70)
-#define PCIE_HDP_TX1_Q_CTRL(base) ((base) + 0x2c74)
-#define PCIE_HDP_CFG0(base) ((base) + 0x2c80)
-#define PCIE_HDP_CFG1(base) ((base) + 0x2c84)
-#define PCIE_HDP_CFG2(base) ((base) + 0x2c88)
-#define PCIE_HDP_CFG3(base) ((base) + 0x2c8c)
-#define PCIE_HDP_CFG4(base) ((base) + 0x2c90)
-#define PCIE_HDP_CFG5(base) ((base) + 0x2c94)
-#define PCIE_HDP_CFG6(base) ((base) + 0x2c98)
-#define PCIE_HDP_CFG7(base) ((base) + 0x2c9c)
-#define PCIE_HDP_CFG8(base) ((base) + 0x2ca0)
-#define PCIE_HDP_CFG9(base) ((base) + 0x2ca4)
-#define PCIE_HDP_CFG10(base) ((base) + 0x2ca8)
-#define PCIE_HDP_CFG11(base) ((base) + 0x2cac)
-#define PCIE_INT(base) ((base) + 0x2cb0)
-#define PCIE_INT_MASK(base) ((base) + 0x2cb4)
-#define PCIE_MSI_MASK(base) ((base) + 0x2cb8)
-#define PCIE_MSI_PNDG(base) ((base) + 0x2cbc)
-#define PCIE_PRI_CFG(base) ((base) + 0x2cc0)
-#define PCIE_PHY_CR(base) ((base) + 0x2cc4)
-#define PCIE_HDP_CTAG_CTRL(base) ((base) + 0x2cf4)
-#define PCIE_HDP_HHBM_BUF_PTR(base) ((base) + 0x2d00)
-#define PCIE_HDP_HHBM_BUF_PTR_H(base) ((base) + 0x2d04)
-#define PCIE_HDP_HHBM_BUF_FIFO_NOE(base) ((base) + 0x2d04)
-#define PCIE_HDP_RX0DMA_CNT(base) ((base) + 0x2d10)
-#define PCIE_HDP_RX1DMA_CNT(base) ((base) + 0x2d14)
-#define PCIE_HDP_RX2DMA_CNT(base) ((base) + 0x2d18)
-#define PCIE_HDP_RX3DMA_CNT(base) ((base) + 0x2d1c)
-#define PCIE_HDP_TX0DMA_CNT(base) ((base) + 0x2d20)
-#define PCIE_HDP_TX1DMA_CNT(base) ((base) + 0x2d24)
-#define PCIE_HDP_RXDMA_CTRL(base) ((base) + 0x2d28)
-#define PCIE_HDP_TX_HOST_Q_SZ_CTRL(base) ((base) + 0x2d2c)
-#define PCIE_HDP_TX_HOST_Q_BASE_L(base) ((base) + 0x2d30)
-#define PCIE_HDP_TX_HOST_Q_BASE_H(base) ((base) + 0x2d34)
-#define PCIE_HDP_TX_HOST_Q_WR_PTR(base) ((base) + 0x2d38)
-#define PCIE_HDP_TX_HOST_Q_RD_PTR(base) ((base) + 0x2d3c)
-#define PCIE_HDP_TX_HOST_Q_STS(base) ((base) + 0x2d40)
-
-/* Host HBM pool registers */
-#define PCIE_HHBM_CSR_REG(base) ((base) + 0x2e00)
-#define PCIE_HHBM_Q_BASE_REG(base) ((base) + 0x2e04)
-#define PCIE_HHBM_Q_LIMIT_REG(base) ((base) + 0x2e08)
-#define PCIE_HHBM_Q_WR_REG(base) ((base) + 0x2e0c)
-#define PCIE_HHBM_Q_RD_REG(base) ((base) + 0x2e10)
-#define PCIE_HHBM_POOL_DATA_0_H(base) ((base) + 0x2e90)
-#define PCIE_HHBM_CONFIG(base) ((base) + 0x2f9c)
-#define PCIE_HHBM_POOL_REQ_0(base) ((base) + 0x2f10)
-#define PCIE_HHBM_POOL_DATA_0(base) ((base) + 0x2f40)
-#define PCIE_HHBM_WATERMARK_MASKED_INT(base) ((base) + 0x2f68)
-#define PCIE_HHBM_WATERMARK_INT(base) ((base) + 0x2f6c)
-#define PCIE_HHBM_POOL_WATERMARK(base) ((base) + 0x2f70)
-#define PCIE_HHBM_POOL_OVERFLOW_CNT(base) ((base) + 0x2f90)
-#define PCIE_HHBM_POOL_UNDERFLOW_CNT(base) ((base) + 0x2f94)
-#define HBM_INT_STATUS(base) ((base) + 0x2f9c)
-#define PCIE_HHBM_POOL_CNFIG(base) ((base) + 0x2f9c)
-
-/* host HBM bit field definition */
-#define HHBM_CONFIG_SOFT_RESET (BIT(8))
-#define HHBM_WR_REQ (BIT(0))
-#define HHBM_RD_REQ (BIT(1))
-#define HHBM_DONE (BIT(31))
-#define HHBM_64BIT (BIT(10))
-
-/* offsets for dual PCIE */
-#define PCIE_PORT_LINK_CTL(base) ((base) + 0x0710)
-#define PCIE_GEN2_CTL(base) ((base) + 0x080C)
-#define PCIE_GEN3_OFF(base) ((base) + 0x0890)
-#define PCIE_ATU_CTRL1(base) ((base) + 0x0904)
-#define PCIE_ATU_CTRL2(base) ((base) + 0x0908)
-#define PCIE_ATU_BASE_LOW(base) ((base) + 0x090C)
-#define PCIE_ATU_BASE_HIGH(base) ((base) + 0x0910)
-#define PCIE_ATU_BASE_LIMIT(base) ((base) + 0x0914)
-#define PCIE_ATU_TGT_LOW(base) ((base) + 0x0918)
-#define PCIE_ATU_TGT_HIGH(base) ((base) + 0x091C)
-#define PCIE_DMA_WR_ENABLE(base) ((base) + 0x097C)
-#define PCIE_DMA_WR_CHWTLOW(base) ((base) + 0x0988)
-#define PCIE_DMA_WR_CHWTHIG(base) ((base) + 0x098C)
-#define PCIE_DMA_WR_INTSTS(base) ((base) + 0x09BC)
-#define PCIE_DMA_WR_INTMASK(base) ((base) + 0x09C4)
-#define PCIE_DMA_WR_INTCLER(base) ((base) + 0x09C8)
-#define PCIE_DMA_WR_DONE_IMWR_ADDR_L(base) ((base) + 0x09D0)
-#define PCIE_DMA_WR_DONE_IMWR_ADDR_H(base) ((base) + 0x09D4)
-#define PCIE_DMA_WR_ABORT_IMWR_ADDR_L(base) ((base) + 0x09D8)
-#define PCIE_DMA_WR_ABORT_IMWR_ADDR_H(base) ((base) + 0x09DC)
-#define PCIE_DMA_WR_IMWR_DATA(base) ((base) + 0x09E0)
-#define PCIE_DMA_WR_LL_ERR_EN(base) ((base) + 0x0A00)
-#define PCIE_DMA_WR_DOORBELL(base) ((base) + 0x0980)
-#define PCIE_DMA_RD_ENABLE(base) ((base) + 0x099C)
-#define PCIE_DMA_RD_DOORBELL(base) ((base) + 0x09A0)
-#define PCIE_DMA_RD_CHWTLOW(base) ((base) + 0x09A8)
-#define PCIE_DMA_RD_CHWTHIG(base) ((base) + 0x09AC)
-#define PCIE_DMA_RD_INTSTS(base) ((base) + 0x0A10)
-#define PCIE_DMA_RD_INTMASK(base) ((base) + 0x0A18)
-#define PCIE_DMA_RD_INTCLER(base) ((base) + 0x0A1C)
-#define PCIE_DMA_RD_ERR_STS_L(base) ((base) + 0x0A24)
-#define PCIE_DMA_RD_ERR_STS_H(base) ((base) + 0x0A28)
-#define PCIE_DMA_RD_LL_ERR_EN(base) ((base) + 0x0A34)
-#define PCIE_DMA_RD_DONE_IMWR_ADDR_L(base) ((base) + 0x0A3C)
-#define PCIE_DMA_RD_DONE_IMWR_ADDR_H(base) ((base) + 0x0A40)
-#define PCIE_DMA_RD_ABORT_IMWR_ADDR_L(base) ((base) + 0x0A44)
-#define PCIE_DMA_RD_ABORT_IMWR_ADDR_H(base) ((base) + 0x0A48)
-#define PCIE_DMA_RD_IMWR_DATA(base) ((base) + 0x0A4C)
-#define PCIE_DMA_CHNL_CONTEXT(base) ((base) + 0x0A6C)
-#define PCIE_DMA_CHNL_CNTRL(base) ((base) + 0x0A70)
-#define PCIE_DMA_XFR_SIZE(base) ((base) + 0x0A78)
-#define PCIE_DMA_SAR_LOW(base) ((base) + 0x0A7C)
-#define PCIE_DMA_SAR_HIGH(base) ((base) + 0x0A80)
-#define PCIE_DMA_DAR_LOW(base) ((base) + 0x0A84)
-#define PCIE_DMA_DAR_HIGH(base) ((base) + 0x0A88)
-#define PCIE_DMA_LLPTR_LOW(base) ((base) + 0x0A8C)
-#define PCIE_DMA_LLPTR_HIGH(base) ((base) + 0x0A90)
-#define PCIE_DMA_WRLL_ERR_ENB(base) ((base) + 0x0A00)
-#define PCIE_DMA_RDLL_ERR_ENB(base) ((base) + 0x0A34)
-#define PCIE_DMABD_CHNL_CNTRL(base) ((base) + 0x8000)
-#define PCIE_DMABD_XFR_SIZE(base) ((base) + 0x8004)
-#define PCIE_DMABD_SAR_LOW(base) ((base) + 0x8008)
-#define PCIE_DMABD_SAR_HIGH(base) ((base) + 0x800c)
-#define PCIE_DMABD_DAR_LOW(base) ((base) + 0x8010)
-#define PCIE_DMABD_DAR_HIGH(base) ((base) + 0x8014)
-#define PCIE_DMABD_LLPTR_LOW(base) ((base) + 0x8018)
-#define PCIE_DMABD_LLPTR_HIGH(base) ((base) + 0x801c)
-#define PCIE_WRDMA0_CHNL_CNTRL(base) ((base) + 0x8000)
-#define PCIE_WRDMA0_XFR_SIZE(base) ((base) + 0x8004)
-#define PCIE_WRDMA0_SAR_LOW(base) ((base) + 0x8008)
-#define PCIE_WRDMA0_SAR_HIGH(base) ((base) + 0x800c)
-#define PCIE_WRDMA0_DAR_LOW(base) ((base) + 0x8010)
-#define PCIE_WRDMA0_DAR_HIGH(base) ((base) + 0x8014)
-#define PCIE_WRDMA0_LLPTR_LOW(base) ((base) + 0x8018)
-#define PCIE_WRDMA0_LLPTR_HIGH(base) ((base) + 0x801c)
-#define PCIE_WRDMA1_CHNL_CNTRL(base) ((base) + 0x8020)
-#define PCIE_WRDMA1_XFR_SIZE(base) ((base) + 0x8024)
-#define PCIE_WRDMA1_SAR_LOW(base) ((base) + 0x8028)
-#define PCIE_WRDMA1_SAR_HIGH(base) ((base) + 0x802c)
-#define PCIE_WRDMA1_DAR_LOW(base) ((base) + 0x8030)
-#define PCIE_WRDMA1_DAR_HIGH(base) ((base) + 0x8034)
-#define PCIE_WRDMA1_LLPTR_LOW(base) ((base) + 0x8038)
-#define PCIE_WRDMA1_LLPTR_HIGH(base) ((base) + 0x803c)
-#define PCIE_RDDMA0_CHNL_CNTRL(base) ((base) + 0x8040)
-#define PCIE_RDDMA0_XFR_SIZE(base) ((base) + 0x8044)
-#define PCIE_RDDMA0_SAR_LOW(base) ((base) + 0x8048)
-#define PCIE_RDDMA0_SAR_HIGH(base) ((base) + 0x804c)
-#define PCIE_RDDMA0_DAR_LOW(base) ((base) + 0x8050)
-#define PCIE_RDDMA0_DAR_HIGH(base) ((base) + 0x8054)
-#define PCIE_RDDMA0_LLPTR_LOW(base) ((base) + 0x8058)
-#define PCIE_RDDMA0_LLPTR_HIGH(base) ((base) + 0x805c)
-#define PCIE_RDDMA1_CHNL_CNTRL(base) ((base) + 0x8060)
-#define PCIE_RDDMA1_XFR_SIZE(base) ((base) + 0x8064)
-#define PCIE_RDDMA1_SAR_LOW(base) ((base) + 0x8068)
-#define PCIE_RDDMA1_SAR_HIGH(base) ((base) + 0x806c)
-#define PCIE_RDDMA1_DAR_LOW(base) ((base) + 0x8070)
-#define PCIE_RDDMA1_DAR_HIGH(base) ((base) + 0x8074)
-#define PCIE_RDDMA1_LLPTR_LOW(base) ((base) + 0x8078)
-#define PCIE_RDDMA1_LLPTR_HIGH(base) ((base) + 0x807c)
-
-#define PCIE_ID(base) ((base) + 0x0000)
-#define PCIE_CMD(base) ((base) + 0x0004)
-#define PCIE_BAR(base, n) ((base) + 0x0010 + ((n) << 2))
-#define PCIE_CAP_PTR(base) ((base) + 0x0034)
-#define PCIE_MSI_LBAR(base) ((base) + 0x0054)
-#define PCIE_MSI_CTRL(base) ((base) + 0x0050)
-#define PCIE_MSI_ADDR_L(base) ((base) + 0x0054)
-#define PCIE_MSI_ADDR_H(base) ((base) + 0x0058)
-#define PCIE_MSI_DATA(base) ((base) + 0x005C)
-#define PCIE_MSI_MASK_BIT(base) ((base) + 0x0060)
-#define PCIE_MSI_PEND_BIT(base) ((base) + 0x0064)
-#define PCIE_DEVCAP(base) ((base) + 0x0074)
-#define PCIE_DEVCTLSTS(base) ((base) + 0x0078)
-
-#define PCIE_CMDSTS(base) ((base) + 0x0004)
-#define PCIE_LINK_STAT(base) ((base) + 0x80)
-#define PCIE_LINK_CTL2(base) ((base) + 0xa0)
-#define PCIE_ASPM_L1_CTRL(base) ((base) + 0x70c)
-#define PCIE_ASPM_LINK_CTRL(base) (PCIE_LINK_STAT)
-#define PCIE_ASPM_L1_SUBSTATE_TIMING(base) ((base) + 0xB44)
-#define PCIE_L1SUB_CTRL1(base) ((base) + 0x150)
-#define PCIE_PMCSR(base) ((base) + 0x44)
-#define PCIE_CFG_SPACE_LIMIT(base) ((base) + 0x100)
-
-/* PCIe link defines */
-#define PEARL_PCIE_LINKUP (0x7)
-#define PEARL_PCIE_DATA_LINK (BIT(0))
-#define PEARL_PCIE_PHY_LINK (BIT(1))
-#define PEARL_PCIE_LINK_RST (BIT(3))
-#define PEARL_PCIE_FATAL_ERR (BIT(5))
-#define PEARL_PCIE_NONFATAL_ERR (BIT(6))
-
-/* PCIe Lane defines */
-#define PCIE_G2_LANE_X1 ((BIT(0)) << 16)
-#define PCIE_G2_LANE_X2 ((BIT(0) | BIT(1)) << 16)
-
-/* PCIe DLL link enable */
-#define PCIE_DLL_LINK_EN ((BIT(0)) << 5)
-
-#define PCIE_LINK_GEN1 (BIT(0))
-#define PCIE_LINK_GEN2 (BIT(1))
-#define PCIE_LINK_GEN3 (BIT(2))
-#define PCIE_LINK_MODE(x) (((x) >> 16) & 0x7)
-
-#define MSI_EN (BIT(0))
-#define MSI_64_EN (BIT(7))
-#define PCIE_MSI_ADDR_OFFSET(a) ((a) & 0xFFFF)
-#define PCIE_MSI_ADDR_ALIGN(a) ((a) & (~0xFFFF))
-
-#define PCIE_BAR_MASK(base, n) ((base) + 0x1010 + ((n) << 2))
-#define PCIE_MAX_BAR (6)
-
-#define PCIE_ATU_VIEW(base) ((base) + 0x0900)
-#define PCIE_ATU_CTL1(base) ((base) + 0x0904)
-#define PCIE_ATU_CTL2(base) ((base) + 0x0908)
-#define PCIE_ATU_LBAR(base) ((base) + 0x090c)
-#define PCIE_ATU_UBAR(base) ((base) + 0x0910)
-#define PCIE_ATU_LAR(base) ((base) + 0x0914)
-#define PCIE_ATU_LTAR(base) ((base) + 0x0918)
-#define PCIE_ATU_UTAR(base) ((base) + 0x091c)
-
-#define PCIE_MSI_ADDR_LOWER(base) ((base) + 0x0820)
-#define PCIE_MSI_ADDR_UPPER(base) ((base) + 0x0824)
-#define PCIE_MSI_ENABLE(base) ((base) + 0x0828)
-#define PCIE_MSI_MASK_RC(base) ((base) + 0x082c)
-#define PCIE_MSI_STATUS(base) ((base) + 0x0830)
-#define PEARL_PCIE_MSI_REGION (0xce000000)
-#define PEARL_PCIE_MSI_DATA (0)
-#define PCIE_MSI_GPIO(base) ((base) + 0x0888)
-
-#define PCIE_HDP_HOST_QUEUE_FULL (BIT(17))
-#define USE_BAR_MATCH_MODE
-#define PCIE_ATU_OB_REGION (BIT(0))
-#define PCIE_ATU_EN_REGION (BIT(31))
-#define PCIE_ATU_EN_MATCH (BIT(30))
-#define PCIE_BASE_REGION (0xb0000000)
-#define PCIE_MEM_MAP_SIZE (512 * 1024)
-
-#define PCIE_OB_REG_REGION (0xcf000000)
-#define PCIE_CONFIG_REGION (0xcf000000)
-#define PCIE_CONFIG_SIZE (4096)
-#define PCIE_CONFIG_CH (1)
-
-/* inbound mapping */
-#define PCIE_IB_BAR0 (0x00000000) /* ddr */
-#define PCIE_IB_BAR0_CH (0)
-#define PCIE_IB_BAR3 (0xe0000000) /* sys_reg */
-#define PCIE_IB_BAR3_CH (1)
-
-/* outbound mapping */
-#define PCIE_MEM_CH (0)
-#define PCIE_REG_CH (1)
-#define PCIE_MEM_REGION (0xc0000000)
-#define PCIE_MEM_SIZE (0x000fffff)
-#define PCIE_MEM_TAR (0x80000000)
-
-#define PCIE_MSI_REGION (0xce000000)
-#define PCIE_MSI_SIZE (KBYTE(4) - 1)
-#define PCIE_MSI_CH (1)
-
-/* size of config region */
-#define PCIE_CFG_SIZE (0x0000ffff)
-
-#define PCIE_ATU_DIR_IB (BIT(31))
-#define PCIE_ATU_DIR_OB (0)
-#define PCIE_ATU_DIR_CFG (2)
-#define PCIE_ATU_DIR_MATCH_IB (BIT(31) | BIT(30))
-
-#define PCIE_DMA_WR_0 (0)
-#define PCIE_DMA_WR_1 (1)
-#define PCIE_DMA_RD_0 (2)
-#define PCIE_DMA_RD_1 (3)
-
-#define PCIE_DMA_CHNL_CNTRL_CB (BIT(0))
-#define PCIE_DMA_CHNL_CNTRL_TCB (BIT(1))
-#define PCIE_DMA_CHNL_CNTRL_LLP (BIT(2))
-#define PCIE_DMA_CHNL_CNTRL_LIE (BIT(3))
-#define PCIE_DMA_CHNL_CNTRL_RIE (BIT(4))
-#define PCIE_DMA_CHNL_CNTRL_CSS (BIT(8))
-#define PCIE_DMA_CHNL_CNTRL_LLE (BIT(9))
-#define PCIE_DMA_CHNL_CNTRL_TLP (BIT(26))
-
-#define PCIE_DMA_CHNL_CONTEXT_RD (BIT(31))
-#define PCIE_DMA_CHNL_CONTEXT_WR (0)
-#define PCIE_MAX_BAR (6)
-
-/* PCIe HDP interrupt status definition */
-#define PCIE_HDP_INT_EP_RXDMA (BIT(0))
-#define PCIE_HDP_INT_HBM_UF (BIT(1))
-#define PCIE_HDP_INT_RX_LEN_ERR (BIT(2))
-#define PCIE_HDP_INT_RX_HDR_LEN_ERR (BIT(3))
-#define PCIE_HDP_INT_EP_TXDMA (BIT(12))
-#define PCIE_HDP_INT_HHBM_UF (BIT(13))
-#define PCIE_HDP_INT_EP_TXEMPTY (BIT(15))
-#define PCIE_HDP_INT_IPC (BIT(29))
-
-/* PCIe interrupt status definition */
-#define PCIE_INT_MSI (BIT(24))
-#define PCIE_INT_INTX (BIT(23))
-
-/* PCIe legacy INTx */
-#define PEARL_PCIE_CFG0_OFFSET (0x6C)
-#define PEARL_ASSERT_INTX (BIT(9))
-
-/* SYS CTL regs */
-#define QTN_PEARL_SYSCTL_LHOST_IRQ_OFFSET (0x001C)
-
-#define QTN_PEARL_IPC_IRQ_WORD(irq) (BIT(irq) | BIT(irq + 16))
-#define QTN_PEARL_LHOST_IPC_IRQ (6)
-#define QTN_PEARL_LHOST_EP_RESET (7)
-
-#endif /* __PEARL_PCIE_H */
diff --git a/drivers/net/wireless/quantenna/qtnfmac/qlink.h b/drivers/net/wireless/quantenna/qtnfmac/qlink.h
index 99d37e3efba6..8d62addea895 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/qlink.h
+++ b/drivers/net/wireless/quantenna/qtnfmac/qlink.h
@@ -71,6 +71,7 @@ struct qlink_msg_header {
* @QLINK_HW_CAPAB_DFS_OFFLOAD: device implements DFS offload functionality
* @QLINK_HW_CAPAB_SCAN_RANDOM_MAC_ADDR: device supports MAC Address
* Randomization in probe requests.
+ * @QLINK_HW_CAPAB_OBSS_SCAN: device can perform OBSS scanning.
*/
enum qlink_hw_capab {
QLINK_HW_CAPAB_REG_UPDATE = BIT(0),
@@ -78,6 +79,8 @@ enum qlink_hw_capab {
QLINK_HW_CAPAB_DFS_OFFLOAD = BIT(2),
QLINK_HW_CAPAB_SCAN_RANDOM_MAC_ADDR = BIT(3),
QLINK_HW_CAPAB_PWR_MGMT = BIT(4),
+ QLINK_HW_CAPAB_OBSS_SCAN = BIT(5),
+ QLINK_HW_CAPAB_SCAN_DWELL = BIT(6),
};
enum qlink_iface_type {
@@ -1149,6 +1152,8 @@ enum qlink_tlv_id {
QTN_TLV_ID_MAX_SCAN_SSIDS = 0x0409,
QTN_TLV_ID_WOWLAN_CAPAB = 0x0410,
QTN_TLV_ID_WOWLAN_PATTERN = 0x0411,
+ QTN_TLV_ID_SCAN_FLUSH = 0x0412,
+ QTN_TLV_ID_SCAN_DWELL = 0x0413,
};
struct qlink_tlv_hdr {
diff --git a/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h b/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h
index 54caeb38917c..960d5d97492f 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h
+++ b/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h
@@ -40,6 +40,14 @@ static inline void qtnf_cmd_skb_put_tlv_arr(struct sk_buff *skb,
memcpy(hdr->val, arr, arr_len);
}
+static inline void qtnf_cmd_skb_put_tlv_tag(struct sk_buff *skb, u16 tlv_id)
+{
+ struct qlink_tlv_hdr *hdr = skb_put(skb, sizeof(*hdr));
+
+ hdr->type = cpu_to_le16(tlv_id);
+ hdr->len = cpu_to_le16(0);
+}
+
static inline void qtnf_cmd_skb_put_tlv_u8(struct sk_buff *skb, u16 tlv_id,
u8 value)
{
diff --git a/drivers/net/wireless/quantenna/qtnfmac/qtn_hw_ids.h b/drivers/net/wireless/quantenna/qtnfmac/qtn_hw_ids.h
index c4ad40d59085..1fe798a9a667 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/qtn_hw_ids.h
+++ b/drivers/net/wireless/quantenna/qtnfmac/qtn_hw_ids.h
@@ -25,8 +25,22 @@
#define PCIE_DEVICE_ID_QTN_PEARL (0x0008)
+#define QTN_REG_SYS_CTRL_CSR 0x14
+#define QTN_CHIP_ID_MASK 0xF0
+#define QTN_CHIP_ID_TOPAZ 0x40
+#define QTN_CHIP_ID_PEARL 0x50
+#define QTN_CHIP_ID_PEARL_B 0x60
+#define QTN_CHIP_ID_PEARL_C 0x70
+
/* FW names */
#define QTN_PCI_PEARL_FW_NAME "qtn/fmac_qsr10g.img"
+static inline unsigned int qtnf_chip_id_get(const void __iomem *regs_base)
+{
+ u32 board_rev = readl(regs_base + QTN_REG_SYS_CTRL_CSR);
+
+ return board_rev & QTN_CHIP_ID_MASK;
+}
+
#endif /* _QTN_HW_IDS_H_ */
diff --git a/drivers/net/wireless/quantenna/qtnfmac/shm_ipc.c b/drivers/net/wireless/quantenna/qtnfmac/shm_ipc.c
index aa106dd0a14b..2ec334199c2b 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/shm_ipc.c
+++ b/drivers/net/wireless/quantenna/qtnfmac/shm_ipc.c
@@ -42,19 +42,18 @@ static void qtnf_shm_handle_new_data(struct qtnf_shm_ipc *ipc)
if (unlikely(size == 0 || size > QTN_IPC_MAX_DATA_SZ)) {
pr_err("wrong rx packet size: %zu\n", size);
rx_buff_ok = false;
- } else {
- memcpy_fromio(ipc->rx_data, ipc->shm_region->data, size);
+ }
+
+ if (likely(rx_buff_ok)) {
+ ipc->rx_packet_count++;
+ ipc->rx_callback.fn(ipc->rx_callback.arg,
+ ipc->shm_region->data, size);
}
writel(QTNF_SHM_IPC_ACK, &shm_reg_hdr->flags);
readl(&shm_reg_hdr->flags); /* flush PCIe write */
ipc->interrupt.fn(ipc->interrupt.arg);
-
- if (likely(rx_buff_ok)) {
- ipc->rx_packet_count++;
- ipc->rx_callback.fn(ipc->rx_callback.arg, ipc->rx_data, size);
- }
}
static void qtnf_shm_ipc_irq_work(struct work_struct *work)
diff --git a/drivers/net/wireless/quantenna/qtnfmac/shm_ipc.h b/drivers/net/wireless/quantenna/qtnfmac/shm_ipc.h
index 453dd6477b12..c2a3702a9ee7 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/shm_ipc.h
+++ b/drivers/net/wireless/quantenna/qtnfmac/shm_ipc.h
@@ -32,7 +32,7 @@ struct qtnf_shm_ipc_int {
};
struct qtnf_shm_ipc_rx_callback {
- void (*fn)(void *arg, const u8 *buf, size_t len);
+ void (*fn)(void *arg, const u8 __iomem *buf, size_t len);
void *arg;
};
@@ -51,8 +51,6 @@ struct qtnf_shm_ipc {
u8 waiting_for_ack;
- u8 rx_data[QTN_IPC_MAX_DATA_SZ] __aligned(sizeof(u32));
-
struct qtnf_shm_ipc_int interrupt;
struct qtnf_shm_ipc_rx_callback rx_callback;
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
index a567bc273ffc..9e7b8933d30c 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -957,6 +957,47 @@ static void rt2800_rate_from_status(struct skb_frame_desc *skbdesc,
skbdesc->tx_rate_flags = flags;
}
+static bool rt2800_txdone_entry_check(struct queue_entry *entry, u32 reg)
+{
+ __le32 *txwi;
+ u32 word;
+ int wcid, ack, pid;
+ int tx_wcid, tx_ack, tx_pid, is_agg;
+
+ /*
+ * This frames has returned with an IO error,
+ * so the status report is not intended for this
+ * frame.
+ */
+ if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags))
+ return false;
+
+ wcid = rt2x00_get_field32(reg, TX_STA_FIFO_WCID);
+ ack = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED);
+ pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE);
+ is_agg = rt2x00_get_field32(reg, TX_STA_FIFO_TX_AGGRE);
+
+ /*
+ * Validate if this TX status report is intended for
+ * this entry by comparing the WCID/ACK/PID fields.
+ */
+ txwi = rt2800_drv_get_txwi(entry);
+
+ word = rt2x00_desc_read(txwi, 1);
+ tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID);
+ tx_ack = rt2x00_get_field32(word, TXWI_W1_ACK);
+ tx_pid = rt2x00_get_field32(word, TXWI_W1_PACKETID);
+
+ if (wcid != tx_wcid || ack != tx_ack || (!is_agg && pid != tx_pid)) {
+ rt2x00_dbg(entry->queue->rt2x00dev,
+ "TX status report missed for queue %d entry %d\n",
+ entry->queue->qid, entry->entry_idx);
+ return false;
+ }
+
+ return true;
+}
+
void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi,
bool match)
{
@@ -1059,6 +1100,119 @@ void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi,
}
EXPORT_SYMBOL_GPL(rt2800_txdone_entry);
+void rt2800_txdone(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_queue *queue;
+ struct queue_entry *entry;
+ u32 reg;
+ u8 qid;
+ bool match;
+
+ while (kfifo_get(&rt2x00dev->txstatus_fifo, &reg)) {
+ /*
+ * TX_STA_FIFO_PID_QUEUE is a 2-bit field, thus qid is
+ * guaranteed to be one of the TX QIDs .
+ */
+ qid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE);
+ queue = rt2x00queue_get_tx_queue(rt2x00dev, qid);
+
+ if (unlikely(rt2x00queue_empty(queue))) {
+ rt2x00_dbg(rt2x00dev, "Got TX status for an empty queue %u, dropping\n",
+ qid);
+ break;
+ }
+
+ entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
+
+ if (unlikely(test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
+ !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))) {
+ rt2x00_warn(rt2x00dev, "Data pending for entry %u in queue %u\n",
+ entry->entry_idx, qid);
+ break;
+ }
+
+ match = rt2800_txdone_entry_check(entry, reg);
+ rt2800_txdone_entry(entry, reg, rt2800_drv_get_txwi(entry), match);
+ }
+}
+EXPORT_SYMBOL_GPL(rt2800_txdone);
+
+static inline bool rt2800_entry_txstatus_timeout(struct rt2x00_dev *rt2x00dev,
+ struct queue_entry *entry)
+{
+ bool ret;
+ unsigned long tout;
+
+ if (!test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
+ return false;
+
+ if (test_bit(DEVICE_STATE_FLUSHING, &rt2x00dev->flags))
+ tout = msecs_to_jiffies(50);
+ else
+ tout = msecs_to_jiffies(2000);
+
+ ret = time_after(jiffies, entry->last_action + tout);
+ if (unlikely(ret))
+ rt2x00_dbg(entry->queue->rt2x00dev,
+ "TX status timeout for entry %d in queue %d\n",
+ entry->entry_idx, entry->queue->qid);
+ return ret;
+}
+
+bool rt2800_txstatus_timeout(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_queue *queue;
+ struct queue_entry *entry;
+
+ if (!test_bit(DEVICE_STATE_FLUSHING, &rt2x00dev->flags)) {
+ unsigned long tout = msecs_to_jiffies(1000);
+
+ if (time_before(jiffies, rt2x00dev->last_nostatus_check + tout))
+ return false;
+ }
+
+ rt2x00dev->last_nostatus_check = jiffies;
+
+ tx_queue_for_each(rt2x00dev, queue) {
+ entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
+ if (rt2800_entry_txstatus_timeout(rt2x00dev, entry))
+ return true;
+ }
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(rt2800_txstatus_timeout);
+
+void rt2800_txdone_nostatus(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_queue *queue;
+ struct queue_entry *entry;
+
+ /*
+ * Process any trailing TX status reports for IO failures,
+ * we loop until we find the first non-IO error entry. This
+ * can either be a frame which is free, is being uploaded,
+ * or has completed the upload but didn't have an entry
+ * in the TX_STAT_FIFO register yet.
+ */
+ tx_queue_for_each(rt2x00dev, queue) {
+ while (!rt2x00queue_empty(queue)) {
+ entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
+
+ if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
+ !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
+ break;
+
+ if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags) ||
+ rt2800_entry_txstatus_timeout(rt2x00dev, entry))
+ rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE);
+ else
+ break;
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(rt2800_txdone_nostatus);
+
static unsigned int rt2800_hw_beacon_base(struct rt2x00_dev *rt2x00dev,
unsigned int index)
{
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
index 51d9c2a932cc..0dff2c7b3010 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
@@ -195,6 +195,9 @@ void rt2800_process_rxwi(struct queue_entry *entry, struct rxdone_entry_desc *tx
void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi,
bool match);
+void rt2800_txdone(struct rt2x00_dev *rt2x00dev);
+void rt2800_txdone_nostatus(struct rt2x00_dev *rt2x00dev);
+bool rt2800_txstatus_timeout(struct rt2x00_dev *rt2x00dev);
void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc);
void rt2800_clear_beacon(struct queue_entry *entry);
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
index e1a7ed7e4892..ddb88cfeace2 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
@@ -175,161 +175,6 @@ static void rt2800mmio_wakeup(struct rt2x00_dev *rt2x00dev)
rt2800_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS);
}
-static bool rt2800mmio_txdone_entry_check(struct queue_entry *entry, u32 status)
-{
- __le32 *txwi;
- u32 word;
- int wcid, tx_wcid;
-
- wcid = rt2x00_get_field32(status, TX_STA_FIFO_WCID);
-
- txwi = rt2800_drv_get_txwi(entry);
- word = rt2x00_desc_read(txwi, 1);
- tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID);
-
- return (tx_wcid == wcid);
-}
-
-static bool rt2800mmio_txdone_find_entry(struct queue_entry *entry, void *data)
-{
- u32 status = *(u32 *)data;
-
- /*
- * rt2800pci hardware might reorder frames when exchanging traffic
- * with multiple BA enabled STAs.
- *
- * For example, a tx queue
- * [ STA1 | STA2 | STA1 | STA2 ]
- * can result in tx status reports
- * [ STA1 | STA1 | STA2 | STA2 ]
- * when the hw decides to aggregate the frames for STA1 into one AMPDU.
- *
- * To mitigate this effect, associate the tx status to the first frame
- * in the tx queue with a matching wcid.
- */
- if (rt2800mmio_txdone_entry_check(entry, status) &&
- !test_bit(ENTRY_DATA_STATUS_SET, &entry->flags)) {
- /*
- * Got a matching frame, associate the tx status with
- * the frame
- */
- entry->status = status;
- set_bit(ENTRY_DATA_STATUS_SET, &entry->flags);
- return true;
- }
-
- /* Check the next frame */
- return false;
-}
-
-static bool rt2800mmio_txdone_match_first(struct queue_entry *entry, void *data)
-{
- u32 status = *(u32 *)data;
-
- /*
- * Find the first frame without tx status and assign this status to it
- * regardless if it matches or not.
- */
- if (!test_bit(ENTRY_DATA_STATUS_SET, &entry->flags)) {
- /*
- * Got a matching frame, associate the tx status with
- * the frame
- */
- entry->status = status;
- set_bit(ENTRY_DATA_STATUS_SET, &entry->flags);
- return true;
- }
-
- /* Check the next frame */
- return false;
-}
-static bool rt2800mmio_txdone_release_entries(struct queue_entry *entry,
- void *data)
-{
- if (test_bit(ENTRY_DATA_STATUS_SET, &entry->flags)) {
- rt2800_txdone_entry(entry, entry->status,
- rt2800mmio_get_txwi(entry), true);
- return false;
- }
-
- /* No more frames to release */
- return true;
-}
-
-static bool rt2800mmio_txdone(struct rt2x00_dev *rt2x00dev)
-{
- struct data_queue *queue;
- u32 status;
- u8 qid;
- int max_tx_done = 16;
-
- while (kfifo_get(&rt2x00dev->txstatus_fifo, &status)) {
- qid = rt2x00_get_field32(status, TX_STA_FIFO_PID_QUEUE);
- if (unlikely(qid >= QID_RX)) {
- /*
- * Unknown queue, this shouldn't happen. Just drop
- * this tx status.
- */
- rt2x00_warn(rt2x00dev, "Got TX status report with unexpected pid %u, dropping\n",
- qid);
- break;
- }
-
- queue = rt2x00queue_get_tx_queue(rt2x00dev, qid);
- if (unlikely(queue == NULL)) {
- /*
- * The queue is NULL, this shouldn't happen. Stop
- * processing here and drop the tx status
- */
- rt2x00_warn(rt2x00dev, "Got TX status for an unavailable queue %u, dropping\n",
- qid);
- break;
- }
-
- if (unlikely(rt2x00queue_empty(queue))) {
- /*
- * The queue is empty. Stop processing here
- * and drop the tx status.
- */
- rt2x00_warn(rt2x00dev, "Got TX status for an empty queue %u, dropping\n",
- qid);
- break;
- }
-
- /*
- * Let's associate this tx status with the first
- * matching frame.
- */
- if (!rt2x00queue_for_each_entry(queue, Q_INDEX_DONE,
- Q_INDEX, &status,
- rt2800mmio_txdone_find_entry)) {
- /*
- * We cannot match the tx status to any frame, so just
- * use the first one.
- */
- if (!rt2x00queue_for_each_entry(queue, Q_INDEX_DONE,
- Q_INDEX, &status,
- rt2800mmio_txdone_match_first)) {
- rt2x00_warn(rt2x00dev, "No frame found for TX status on queue %u, dropping\n",
- qid);
- break;
- }
- }
-
- /*
- * Release all frames with a valid tx status.
- */
- rt2x00queue_for_each_entry(queue, Q_INDEX_DONE,
- Q_INDEX, NULL,
- rt2800mmio_txdone_release_entries);
-
- if (--max_tx_done == 0)
- break;
- }
-
- return !max_tx_done;
-}
-
static inline void rt2800mmio_enable_interrupt(struct rt2x00_dev *rt2x00dev,
struct rt2x00_field32 irq_field)
{
@@ -346,20 +191,6 @@ static inline void rt2800mmio_enable_interrupt(struct rt2x00_dev *rt2x00dev,
spin_unlock_irq(&rt2x00dev->irqmask_lock);
}
-void rt2800mmio_txstatus_tasklet(unsigned long data)
-{
- struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
- if (rt2800mmio_txdone(rt2x00dev))
- tasklet_schedule(&rt2x00dev->txstatus_tasklet);
-
- /*
- * No need to enable the tx status interrupt here as we always
- * leave it enabled to minimize the possibility of a tx status
- * register overflow. See comment in interrupt handler.
- */
-}
-EXPORT_SYMBOL_GPL(rt2800mmio_txstatus_tasklet);
-
void rt2800mmio_pretbtt_tasklet(unsigned long data)
{
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
@@ -424,12 +255,26 @@ void rt2800mmio_autowake_tasklet(unsigned long data)
}
EXPORT_SYMBOL_GPL(rt2800mmio_autowake_tasklet);
-static void rt2800mmio_txstatus_interrupt(struct rt2x00_dev *rt2x00dev)
+static void rt2800mmio_txdone(struct rt2x00_dev *rt2x00dev)
+{
+ bool timeout = false;
+
+ while (!kfifo_is_empty(&rt2x00dev->txstatus_fifo) ||
+ (timeout = rt2800_txstatus_timeout(rt2x00dev))) {
+
+ rt2800_txdone(rt2x00dev);
+
+ if (timeout)
+ rt2800_txdone_nostatus(rt2x00dev);
+ }
+}
+
+static bool rt2800mmio_fetch_txstatus(struct rt2x00_dev *rt2x00dev)
{
u32 status;
- int i;
+ bool more = false;
- /*
+ /* FIXEME: rewrite this comment
* The TX_FIFO_STATUS interrupt needs special care. We should
* read TX_STA_FIFO but we should do it immediately as otherwise
* the register can overflow and we would lose status reports.
@@ -440,28 +285,36 @@ static void rt2800mmio_txstatus_interrupt(struct rt2x00_dev *rt2x00dev)
* because we can schedule the tasklet multiple times (when the
* interrupt fires again during tx status processing).
*
- * Furthermore we don't disable the TX_FIFO_STATUS
- * interrupt here but leave it enabled so that the TX_STA_FIFO
- * can also be read while the tx status tasklet gets executed.
- *
- * Since we have only one producer and one consumer we don't
+ * txstatus tasklet is called with INT_SOURCE_CSR_TX_FIFO_STATUS
+ * disabled so have only one producer and one consumer - we don't
* need to lock the kfifo.
*/
- for (i = 0; i < rt2x00dev->tx->limit; i++) {
+ while (!kfifo_is_full(&rt2x00dev->txstatus_fifo)) {
status = rt2x00mmio_register_read(rt2x00dev, TX_STA_FIFO);
-
if (!rt2x00_get_field32(status, TX_STA_FIFO_VALID))
break;
- if (!kfifo_put(&rt2x00dev->txstatus_fifo, status)) {
- rt2x00_warn(rt2x00dev, "TX status FIFO overrun, drop tx status report\n");
- break;
- }
+ kfifo_put(&rt2x00dev->txstatus_fifo, status);
+ more = true;
}
- /* Schedule the tasklet for processing the tx status. */
- tasklet_schedule(&rt2x00dev->txstatus_tasklet);
+ return more;
+}
+
+void rt2800mmio_txstatus_tasklet(unsigned long data)
+{
+ struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
+
+ do {
+ rt2800mmio_txdone(rt2x00dev);
+
+ } while (rt2800mmio_fetch_txstatus(rt2x00dev));
+
+ if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+ rt2800mmio_enable_interrupt(rt2x00dev,
+ INT_SOURCE_CSR_TX_FIFO_STATUS);
}
+EXPORT_SYMBOL_GPL(rt2800mmio_txstatus_tasklet);
irqreturn_t rt2800mmio_interrupt(int irq, void *dev_instance)
{
@@ -486,11 +339,8 @@ irqreturn_t rt2800mmio_interrupt(int irq, void *dev_instance)
mask = ~reg;
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS)) {
- rt2800mmio_txstatus_interrupt(rt2x00dev);
- /*
- * Never disable the TX_FIFO_STATUS interrupt.
- */
- rt2x00_set_field32(&mask, INT_MASK_CSR_TX_FIFO_STATUS, 1);
+ rt2800mmio_fetch_txstatus(rt2x00dev);
+ tasklet_schedule(&rt2x00dev->txstatus_tasklet);
}
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_PRE_TBTT))
@@ -616,6 +466,53 @@ void rt2800mmio_kick_queue(struct data_queue *queue)
}
EXPORT_SYMBOL_GPL(rt2800mmio_kick_queue);
+void rt2800mmio_flush_queue(struct data_queue *queue, bool drop)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ bool tx_queue = false;
+ unsigned int i;
+
+ switch (queue->qid) {
+ case QID_AC_VO:
+ case QID_AC_VI:
+ case QID_AC_BE:
+ case QID_AC_BK:
+ tx_queue = true;
+ break;
+ case QID_RX:
+ break;
+ default:
+ return;
+ }
+
+ for (i = 0; i < 5; i++) {
+ /*
+ * Check if the driver is already done, otherwise we
+ * have to sleep a little while to give the driver/hw
+ * the oppurtunity to complete interrupt process itself.
+ */
+ if (rt2x00queue_empty(queue))
+ break;
+
+ /*
+ * For TX queues schedule completion tasklet to catch
+ * tx status timeouts, othewise just wait.
+ */
+ if (tx_queue) {
+ tasklet_disable(&rt2x00dev->txstatus_tasklet);
+ rt2800mmio_txdone(rt2x00dev);
+ tasklet_enable(&rt2x00dev->txstatus_tasklet);
+ }
+
+ /*
+ * Wait for a little while to give the driver
+ * the oppurtunity to recover itself.
+ */
+ msleep(50);
+ }
+}
+EXPORT_SYMBOL_GPL(rt2800mmio_flush_queue);
+
void rt2800mmio_stop_queue(struct data_queue *queue)
{
struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.h b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.h
index b63312ce3f27..3a513273f414 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.h
@@ -148,6 +148,7 @@ void rt2800mmio_toggle_irq(struct rt2x00_dev *rt2x00dev,
/* Queue handlers */
void rt2800mmio_start_queue(struct data_queue *queue);
void rt2800mmio_kick_queue(struct data_queue *queue);
+void rt2800mmio_flush_queue(struct data_queue *queue, bool drop);
void rt2800mmio_stop_queue(struct data_queue *queue);
void rt2800mmio_queue_init(struct data_queue *queue);
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
index 71b1affc3885..0291441ac548 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
@@ -364,7 +364,7 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
.start_queue = rt2800mmio_start_queue,
.kick_queue = rt2800mmio_kick_queue,
.stop_queue = rt2800mmio_stop_queue,
- .flush_queue = rt2x00mmio_flush_queue,
+ .flush_queue = rt2800mmio_flush_queue,
.write_tx_desc = rt2800mmio_write_tx_desc,
.write_tx_data = rt2800_write_tx_data,
.write_beacon = rt2800_write_beacon,
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
index 98a7313fea4a..19eabf16147b 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
@@ -116,35 +116,6 @@ static bool rt2800usb_txstatus_pending(struct rt2x00_dev *rt2x00dev)
return false;
}
-static inline bool rt2800usb_entry_txstatus_timeout(struct queue_entry *entry)
-{
- bool tout;
-
- if (!test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
- return false;
-
- tout = time_after(jiffies, entry->last_action + msecs_to_jiffies(500));
- if (unlikely(tout))
- rt2x00_dbg(entry->queue->rt2x00dev,
- "TX status timeout for entry %d in queue %d\n",
- entry->entry_idx, entry->queue->qid);
- return tout;
-
-}
-
-static bool rt2800usb_txstatus_timeout(struct rt2x00_dev *rt2x00dev)
-{
- struct data_queue *queue;
- struct queue_entry *entry;
-
- tx_queue_for_each(rt2x00dev, queue) {
- entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
- if (rt2800usb_entry_txstatus_timeout(entry))
- return true;
- }
- return false;
-}
-
#define TXSTATUS_READ_INTERVAL 1000000
static bool rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev,
@@ -171,7 +142,7 @@ static bool rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev,
}
/* Check if there is any entry that timedout waiting on TX status */
- if (rt2800usb_txstatus_timeout(rt2x00dev))
+ if (rt2800_txstatus_timeout(rt2x00dev))
queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work);
if (rt2800usb_txstatus_pending(rt2x00dev)) {
@@ -501,123 +472,17 @@ static int rt2800usb_get_tx_data_len(struct queue_entry *entry)
/*
* TX control handlers
*/
-static bool rt2800usb_txdone_entry_check(struct queue_entry *entry, u32 reg)
-{
- __le32 *txwi;
- u32 word;
- int wcid, ack, pid;
- int tx_wcid, tx_ack, tx_pid, is_agg;
-
- /*
- * This frames has returned with an IO error,
- * so the status report is not intended for this
- * frame.
- */
- if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags))
- return false;
-
- wcid = rt2x00_get_field32(reg, TX_STA_FIFO_WCID);
- ack = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED);
- pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE);
- is_agg = rt2x00_get_field32(reg, TX_STA_FIFO_TX_AGGRE);
-
- /*
- * Validate if this TX status report is intended for
- * this entry by comparing the WCID/ACK/PID fields.
- */
- txwi = rt2800usb_get_txwi(entry);
-
- word = rt2x00_desc_read(txwi, 1);
- tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID);
- tx_ack = rt2x00_get_field32(word, TXWI_W1_ACK);
- tx_pid = rt2x00_get_field32(word, TXWI_W1_PACKETID);
-
- if (wcid != tx_wcid || ack != tx_ack || (!is_agg && pid != tx_pid)) {
- rt2x00_dbg(entry->queue->rt2x00dev,
- "TX status report missed for queue %d entry %d\n",
- entry->queue->qid, entry->entry_idx);
- return false;
- }
-
- return true;
-}
-
-static void rt2800usb_txdone(struct rt2x00_dev *rt2x00dev)
-{
- struct data_queue *queue;
- struct queue_entry *entry;
- u32 reg;
- u8 qid;
- bool match;
-
- while (kfifo_get(&rt2x00dev->txstatus_fifo, &reg)) {
- /*
- * TX_STA_FIFO_PID_QUEUE is a 2-bit field, thus qid is
- * guaranteed to be one of the TX QIDs .
- */
- qid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE);
- queue = rt2x00queue_get_tx_queue(rt2x00dev, qid);
-
- if (unlikely(rt2x00queue_empty(queue))) {
- rt2x00_dbg(rt2x00dev, "Got TX status for an empty queue %u, dropping\n",
- qid);
- break;
- }
-
- entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
-
- if (unlikely(test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
- !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))) {
- rt2x00_warn(rt2x00dev, "Data pending for entry %u in queue %u\n",
- entry->entry_idx, qid);
- break;
- }
-
- match = rt2800usb_txdone_entry_check(entry, reg);
- rt2800_txdone_entry(entry, reg, rt2800usb_get_txwi(entry), match);
- }
-}
-
-static void rt2800usb_txdone_nostatus(struct rt2x00_dev *rt2x00dev)
-{
- struct data_queue *queue;
- struct queue_entry *entry;
-
- /*
- * Process any trailing TX status reports for IO failures,
- * we loop until we find the first non-IO error entry. This
- * can either be a frame which is free, is being uploaded,
- * or has completed the upload but didn't have an entry
- * in the TX_STAT_FIFO register yet.
- */
- tx_queue_for_each(rt2x00dev, queue) {
- while (!rt2x00queue_empty(queue)) {
- entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
-
- if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
- !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
- break;
-
- if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags) ||
- rt2800usb_entry_txstatus_timeout(entry))
- rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE);
- else
- break;
- }
- }
-}
-
static void rt2800usb_work_txdone(struct work_struct *work)
{
struct rt2x00_dev *rt2x00dev =
container_of(work, struct rt2x00_dev, txdone_work);
while (!kfifo_is_empty(&rt2x00dev->txstatus_fifo) ||
- rt2800usb_txstatus_timeout(rt2x00dev)) {
+ rt2800_txstatus_timeout(rt2x00dev)) {
- rt2800usb_txdone(rt2x00dev);
+ rt2800_txdone(rt2x00dev);
- rt2800usb_txdone_nostatus(rt2x00dev);
+ rt2800_txdone_nostatus(rt2x00dev);
/*
* The hw may delay sending the packet after DMA complete
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00.h b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
index a279a4363bc1..4b1744e9fb78 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
@@ -665,6 +665,7 @@ enum rt2x00_state_flags {
DEVICE_STATE_STARTED,
DEVICE_STATE_ENABLED_RADIO,
DEVICE_STATE_SCANNING,
+ DEVICE_STATE_FLUSHING,
/*
* Driver configuration
@@ -980,6 +981,8 @@ struct rt2x00_dev {
*/
DECLARE_KFIFO_PTR(txstatus_fifo, u32);
+ unsigned long last_nostatus_check;
+
/*
* Timer to ensure tx status reports are read (rt2800usb).
*/
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c b/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c
index acc399b5574e..61ba573e8bf1 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c
@@ -464,11 +464,7 @@ static ssize_t rt2x00debug_read_##__name(struct file *file, \
\
size = sprintf(line, __format, value); \
\
- if (copy_to_user(buf, line, size)) \
- return -EFAULT; \
- \
- *offset += size; \
- return size; \
+ return simple_read_from_buffer(buf, length, offset, line, size); \
}
#define RT2X00DEBUGFS_OPS_WRITE(__name, __type) \
@@ -545,11 +541,7 @@ static ssize_t rt2x00debug_read_dev_flags(struct file *file,
size = sprintf(line, "0x%.8x\n", (unsigned int)intf->rt2x00dev->flags);
- if (copy_to_user(buf, line, size))
- return -EFAULT;
-
- *offset += size;
- return size;
+ return simple_read_from_buffer(buf, length, offset, line, size);
}
static const struct file_operations rt2x00debug_fop_dev_flags = {
@@ -574,11 +566,7 @@ static ssize_t rt2x00debug_read_cap_flags(struct file *file,
size = sprintf(line, "0x%.8x\n", (unsigned int)intf->rt2x00dev->cap_flags);
- if (copy_to_user(buf, line, size))
- return -EFAULT;
-
- *offset += size;
- return size;
+ return simple_read_from_buffer(buf, length, offset, line, size);
}
static const struct file_operations rt2x00debug_fop_cap_flags = {
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
index fa2fd64084ac..2825560e2424 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
@@ -720,8 +720,12 @@ void rt2x00mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
return;
+ set_bit(DEVICE_STATE_FLUSHING, &rt2x00dev->flags);
+
tx_queue_for_each(rt2x00dev, queue)
rt2x00queue_flush_queue(queue, drop);
+
+ clear_bit(DEVICE_STATE_FLUSHING, &rt2x00dev->flags);
}
EXPORT_SYMBOL_GPL(rt2x00mac_flush);
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
index 710e9641552e..92ddc19e7bf7 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
@@ -113,6 +113,7 @@ int rt2x00queue_map_txskb(struct queue_entry *entry)
return -ENOMEM;
skbdesc->flags |= SKBDESC_DMA_MAPPED_TX;
+ rt2x00lib_dmadone(entry);
return 0;
}
EXPORT_SYMBOL_GPL(rt2x00queue_map_txskb);
@@ -1038,6 +1039,7 @@ void rt2x00queue_start_queues(struct rt2x00_dev *rt2x00dev)
*/
tx_queue_for_each(rt2x00dev, queue)
rt2x00queue_start_queue(queue);
+ rt2x00dev->last_nostatus_check = jiffies;
rt2x00queue_start_queue(rt2x00dev->rx);
}
diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
index 9a1d15b3ce45..cec37787ecf8 100644
--- a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
+++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
@@ -499,7 +499,7 @@ static void rtl8187b_status_cb(struct urb *urb)
if (cmd_type == 1) {
unsigned int pkt_rc, seq_no;
bool tok;
- struct sk_buff *skb;
+ struct sk_buff *skb, *iter;
struct ieee80211_hdr *ieee80211hdr;
unsigned long flags;
@@ -508,8 +508,9 @@ static void rtl8187b_status_cb(struct urb *urb)
seq_no = (val >> 16) & 0xFFF;
spin_lock_irqsave(&priv->b_tx_status.queue.lock, flags);
- skb_queue_reverse_walk(&priv->b_tx_status.queue, skb) {
- ieee80211hdr = (struct ieee80211_hdr *)skb->data;
+ skb = NULL;
+ skb_queue_reverse_walk(&priv->b_tx_status.queue, iter) {
+ ieee80211hdr = (struct ieee80211_hdr *)iter->data;
/*
* While testing, it was discovered that the seq_no
@@ -522,10 +523,12 @@ static void rtl8187b_status_cb(struct urb *urb)
* it's unlikely we wrongly ack some sent data
*/
if ((le16_to_cpu(ieee80211hdr->seq_ctrl)
- & 0xFFF) == seq_no)
+ & 0xFFF) == seq_no) {
+ skb = iter;
break;
+ }
}
- if (skb != (struct sk_buff *) &priv->b_tx_status.queue) {
+ if (skb) {
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
__skb_unlink(skb, &priv->b_tx_status.queue);
diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/leds.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/leds.c
index c2d5b495c179..c089540116fa 100644
--- a/drivers/net/wireless/realtek/rtl818x/rtl8187/leds.c
+++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/leds.c
@@ -146,7 +146,7 @@ static int rtl8187_register_led(struct ieee80211_hw *dev,
led->dev = dev;
led->ledpin = ledpin;
led->is_radio = is_radio;
- strncpy(led->name, name, sizeof(led->name));
+ strlcpy(led->name, name, sizeof(led->name));
led->led_dev.name = led->name;
led->led_dev.default_trigger = default_trigger;
diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
index 505ab1b055ff..56040b181cf5 100644
--- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
@@ -4918,11 +4918,10 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw,
struct device *dev = &priv->udev->dev;
u32 queue, rts_rate;
u16 pktlen = skb->len;
- u16 seq_number;
u16 rate_flag = tx_info->control.rates[0].flags;
int tx_desc_size = priv->fops->tx_desc_size;
int ret;
- bool usedesc40, ampdu_enable, sgi = false, short_preamble = false;
+ bool ampdu_enable, sgi = false, short_preamble = false;
if (skb_headroom(skb) < tx_desc_size) {
dev_warn(dev,
@@ -4946,7 +4945,6 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw,
if (ieee80211_is_action(hdr->frame_control))
rtl8xxxu_dump_action(dev, hdr);
- usedesc40 = (tx_desc_size == 40);
tx_info->rate_driver_data[0] = hw;
if (control && control->sta)
@@ -5013,7 +5011,6 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw,
else
rts_rate = 0;
- seq_number = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl));
priv->fops->fill_txdesc(hw, hdr, tx_info, tx_desc, sgi, short_preamble,
ampdu_enable, rts_rate);
@@ -6231,6 +6228,8 @@ static const struct usb_device_id dev_table[] = {
{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3308, 0xff, 0xff, 0xff),
.driver_info = (unsigned long)&rtl8192cu_fops},
/* Currently untested 8188 series devices */
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x018a, 0xff, 0xff, 0xff),
+ .driver_info = (unsigned long)&rtl8192cu_fops},
{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8191, 0xff, 0xff, 0xff),
.driver_info = (unsigned long)&rtl8192cu_fops},
{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8170, 0xff, 0xff, 0xff),
diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c
index b026e80940a4..6fbf8845a2ab 100644
--- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c
+++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c
@@ -1324,13 +1324,13 @@ bool exhalbtc_initlize_variables_wifi_only(struct rtl_priv *rtlpriv)
switch (rtlpriv->rtlhal.interface) {
case INTF_PCI:
- wifionly_cfg->chip_interface = BTC_INTF_PCI;
+ wifionly_cfg->chip_interface = WIFIONLY_INTF_PCI;
break;
case INTF_USB:
- wifionly_cfg->chip_interface = BTC_INTF_USB;
+ wifionly_cfg->chip_interface = WIFIONLY_INTF_USB;
break;
default:
- wifionly_cfg->chip_interface = BTC_INTF_UNKNOWN;
+ wifionly_cfg->chip_interface = WIFIONLY_INTF_UNKNOWN;
break;
}
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c
index 988d5ac57d02..cfc8762c55f4 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c
@@ -951,12 +951,8 @@ static bool _rtl88ee_init_mac(struct ieee80211_hw *hw)
static void _rtl88ee_hw_configure(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
- u8 reg_bw_opmode;
- u32 reg_ratr, reg_prsr;
+ u32 reg_prsr;
- reg_bw_opmode = BW_OPMODE_20MHZ;
- reg_ratr = RATE_ALL_CCK | RATE_ALL_OFDM_AG |
- RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS;
reg_prsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
rtl_write_dword(rtlpriv, REG_RRSR, reg_prsr);
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c
index 545115db507e..f783e4a8083d 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c
@@ -799,11 +799,9 @@ static void _rtl8723e_hw_configure(struct ieee80211_hw *hw)
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
struct rtl_priv *rtlpriv = rtl_priv(hw);
u8 reg_bw_opmode;
- u32 reg_ratr, reg_prsr;
+ u32 reg_prsr;
reg_bw_opmode = BW_OPMODE_20MHZ;
- reg_ratr = RATE_ALL_CCK | RATE_ALL_OFDM_AG |
- RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS;
reg_prsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL, 0x8);
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c
index 317c1b3101da..ba258318ee9f 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c
@@ -3404,75 +3404,6 @@ static void rtl8821ae_update_hal_rate_table(struct ieee80211_hw *hw,
"%x\n", rtl_read_dword(rtlpriv, REG_ARFR0));
}
-static u8 _rtl8821ae_mrate_idx_to_arfr_id(
- struct ieee80211_hw *hw, u8 rate_index,
- enum wireless_mode wirelessmode)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_phy *rtlphy = &rtlpriv->phy;
- u8 ret = 0;
- switch (rate_index) {
- case RATR_INX_WIRELESS_NGB:
- if (rtlphy->rf_type == RF_1T1R)
- ret = 1;
- else
- ret = 0;
- ; break;
- case RATR_INX_WIRELESS_N:
- case RATR_INX_WIRELESS_NG:
- if (rtlphy->rf_type == RF_1T1R)
- ret = 5;
- else
- ret = 4;
- ; break;
- case RATR_INX_WIRELESS_NB:
- if (rtlphy->rf_type == RF_1T1R)
- ret = 3;
- else
- ret = 2;
- ; break;
- case RATR_INX_WIRELESS_GB:
- ret = 6;
- break;
- case RATR_INX_WIRELESS_G:
- ret = 7;
- break;
- case RATR_INX_WIRELESS_B:
- ret = 8;
- break;
- case RATR_INX_WIRELESS_MC:
- if ((wirelessmode == WIRELESS_MODE_B)
- || (wirelessmode == WIRELESS_MODE_G)
- || (wirelessmode == WIRELESS_MODE_N_24G)
- || (wirelessmode == WIRELESS_MODE_AC_24G))
- ret = 6;
- else
- ret = 7;
- case RATR_INX_WIRELESS_AC_5N:
- if (rtlphy->rf_type == RF_1T1R)
- ret = 10;
- else
- ret = 9;
- break;
- case RATR_INX_WIRELESS_AC_24N:
- if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_80) {
- if (rtlphy->rf_type == RF_1T1R)
- ret = 10;
- else
- ret = 9;
- } else {
- if (rtlphy->rf_type == RF_1T1R)
- ret = 11;
- else
- ret = 12;
- }
- break;
- default:
- ret = 0; break;
- }
- return ret;
-}
-
static u32 _rtl8821ae_rate_to_bitmap_2ssvht(__le16 vht_rate)
{
u8 i, j, tmp_rate;
@@ -3761,7 +3692,7 @@ static void rtl8821ae_update_hal_rate_mask(struct ieee80211_hw *hw,
break;
}
- ratr_index = _rtl8821ae_mrate_idx_to_arfr_id(hw, ratr_index, wirelessmode);
+ ratr_index = rtl_mrate_idx_to_arfr_id(hw, ratr_index, wirelessmode);
sta_entry->ratr_index = ratr_index;
ratr_bitmap = _rtl8821ae_set_ra_vht_ratr_bitmap(hw, wirelessmode,
ratr_bitmap);
diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h
index 0f3b98c5227f..87bc21bb5e8b 100644
--- a/drivers/net/wireless/realtek/rtlwifi/wifi.h
+++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h
@@ -1905,10 +1905,6 @@ struct rtl_efuse {
u8 efuse_map[2][EFUSE_MAX_LOGICAL_SIZE];
u16 efuse_usedbytes;
u8 efuse_usedpercentage;
-#ifdef EFUSE_REPG_WORKAROUND
- bool efuse_re_pg_sec1flag;
- u8 efuse_re_pg_data[8];
-#endif
u8 autoload_failflag;
u8 autoload_status;
diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c
index 01edf960ff3c..182b06629371 100644
--- a/drivers/net/wireless/rsi/rsi_91x_hal.c
+++ b/drivers/net/wireless/rsi/rsi_91x_hal.c
@@ -282,10 +282,8 @@ int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb)
struct rsi_hw *adapter = common->priv;
struct ieee80211_vif *vif;
struct ieee80211_tx_info *info;
- struct skb_info *tx_params;
struct ieee80211_bss_conf *bss;
int status = -EINVAL;
- u8 header_size;
if (!skb)
return 0;
@@ -297,8 +295,6 @@ int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb)
goto err;
vif = info->control.vif;
bss = &vif->bss_conf;
- tx_params = (struct skb_info *)info->driver_data;
- header_size = tx_params->internal_hdr_size;
if (((vif->type == NL80211_IFTYPE_STATION) ||
(vif->type == NL80211_IFTYPE_P2P_CLIENT)) &&
diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
index 4e510cbe0a89..e56fc83faf0e 100644
--- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c
+++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
@@ -924,7 +924,7 @@ static int rsi_hal_key_config(struct ieee80211_hw *hw,
if (status)
return status;
- if (vif->type == NL80211_IFTYPE_STATION && key->key &&
+ if (vif->type == NL80211_IFTYPE_STATION &&
(key->cipher == WLAN_CIPHER_SUITE_WEP104 ||
key->cipher == WLAN_CIPHER_SUITE_WEP40)) {
if (!rsi_send_block_unblock_frame(adapter->priv, false))
diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c
index c0a163e40402..f360690396dd 100644
--- a/drivers/net/wireless/rsi/rsi_91x_usb.c
+++ b/drivers/net/wireless/rsi/rsi_91x_usb.c
@@ -266,15 +266,17 @@ static void rsi_rx_done_handler(struct urb *urb)
if (urb->status)
goto out;
- if (urb->actual_length <= 0) {
- rsi_dbg(INFO_ZONE, "%s: Zero length packet\n", __func__);
+ if (urb->actual_length <= 0 ||
+ urb->actual_length > rx_cb->rx_skb->len) {
+ rsi_dbg(INFO_ZONE, "%s: Invalid packet length = %d\n",
+ __func__, urb->actual_length);
goto out;
}
if (skb_queue_len(&dev->rx_q) >= RSI_MAX_RX_PKTS) {
rsi_dbg(INFO_ZONE, "Max RX packets reached\n");
goto out;
}
- skb_put(rx_cb->rx_skb, urb->actual_length);
+ skb_trim(rx_cb->rx_skb, urb->actual_length);
skb_queue_tail(&dev->rx_q, rx_cb->rx_skb);
rsi_set_event(&dev->rx_thread.event);
@@ -308,6 +310,7 @@ static int rsi_rx_urb_submit(struct rsi_hw *adapter, u8 ep_num)
if (!skb)
return -ENOMEM;
skb_reserve(skb, MAX_DWORD_ALIGN_BYTES);
+ skb_put(skb, RSI_MAX_RX_USB_PKT_SIZE - MAX_DWORD_ALIGN_BYTES);
dword_align_bytes = (unsigned long)skb->data & 0x3f;
if (dword_align_bytes > 0)
skb_push(skb, dword_align_bytes);
@@ -319,7 +322,7 @@ static int rsi_rx_urb_submit(struct rsi_hw *adapter, u8 ep_num)
usb_rcvbulkpipe(dev->usbdev,
dev->bulkin_endpoint_addr[ep_num - 1]),
urb->transfer_buffer,
- RSI_MAX_RX_USB_PKT_SIZE,
+ skb->len,
rsi_rx_done_handler,
rx_cb);
diff --git a/drivers/net/wireless/rsi/rsi_common.h b/drivers/net/wireless/rsi/rsi_common.h
index d9ff3b8be86e..60f1f286b030 100644
--- a/drivers/net/wireless/rsi/rsi_common.h
+++ b/drivers/net/wireless/rsi/rsi_common.h
@@ -75,7 +75,6 @@ static inline int rsi_kill_thread(struct rsi_thread *handle)
atomic_inc(&handle->thread_done);
rsi_set_event(&handle->event);
- wait_for_completion(&handle->completion);
return kthread_stop(handle->task);
}
diff --git a/drivers/net/wireless/st/cw1200/txrx.c b/drivers/net/wireless/st/cw1200/txrx.c
index f7b1b0062db3..8c800ef23159 100644
--- a/drivers/net/wireless/st/cw1200/txrx.c
+++ b/drivers/net/wireless/st/cw1200/txrx.c
@@ -624,9 +624,9 @@ cw1200_tx_h_bt(struct cw1200_common *priv,
priority = WSM_EPTA_PRIORITY_ACTION;
else if (ieee80211_is_mgmt(t->hdr->frame_control))
priority = WSM_EPTA_PRIORITY_MGT;
- else if ((wsm->queue_id == WSM_QUEUE_VOICE))
+ else if (wsm->queue_id == WSM_QUEUE_VOICE)
priority = WSM_EPTA_PRIORITY_VOICE;
- else if ((wsm->queue_id == WSM_QUEUE_VIDEO))
+ else if (wsm->queue_id == WSM_QUEUE_VIDEO)
priority = WSM_EPTA_PRIORITY_VIDEO;
else
priority = WSM_EPTA_PRIORITY_DATA;
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index 89b0d0fade9f..26b187336875 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -27,6 +27,7 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/pm_runtime.h>
+#include <linux/pm_wakeirq.h>
#include "wlcore.h"
#include "debug.h"
@@ -957,6 +958,8 @@ static void wl1271_recovery_work(struct work_struct *work)
BUG_ON(wl->conf.recovery.bug_on_recovery &&
!test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags));
+ clear_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags);
+
if (wl->conf.recovery.no_recovery) {
wl1271_info("No recovery (chosen on module load). Fw will remain stuck.");
goto out_unlock;
@@ -6625,13 +6628,25 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context)
}
#ifdef CONFIG_PM
+ device_init_wakeup(wl->dev, true);
+
ret = enable_irq_wake(wl->irq);
if (!ret) {
wl->irq_wake_enabled = true;
- device_init_wakeup(wl->dev, 1);
if (pdev_data->pwr_in_suspend)
wl->hw->wiphy->wowlan = &wlcore_wowlan_support;
}
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+ if (res) {
+ wl->wakeirq = res->start;
+ wl->wakeirq_flags = res->flags & IRQF_TRIGGER_MASK;
+ ret = dev_pm_set_dedicated_wake_irq(wl->dev, wl->wakeirq);
+ if (ret)
+ wl->wakeirq = -ENODEV;
+ } else {
+ wl->wakeirq = -ENODEV;
+ }
#endif
disable_irq(wl->irq);
wl1271_power_off(wl);
@@ -6659,6 +6674,9 @@ out_unreg:
wl1271_unregister_hw(wl);
out_irq:
+ if (wl->wakeirq >= 0)
+ dev_pm_clear_wake_irq(wl->dev);
+ device_init_wakeup(wl->dev, false);
free_irq(wl->irq, wl);
out_free_nvs:
@@ -6710,6 +6728,7 @@ static int __maybe_unused wlcore_runtime_resume(struct device *dev)
int ret;
unsigned long start_time = jiffies;
bool pending = false;
+ bool recovery = false;
/* Nothing to do if no ELP mode requested */
if (!test_bit(WL1271_FLAG_IN_ELP, &wl->flags))
@@ -6726,7 +6745,7 @@ static int __maybe_unused wlcore_runtime_resume(struct device *dev)
ret = wlcore_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_WAKE_UP);
if (ret < 0) {
- wl12xx_queue_recovery_work(wl);
+ recovery = true;
goto err;
}
@@ -6734,11 +6753,12 @@ static int __maybe_unused wlcore_runtime_resume(struct device *dev)
ret = wait_for_completion_timeout(&compl,
msecs_to_jiffies(WL1271_WAKEUP_TIMEOUT));
if (ret == 0) {
- wl1271_error("ELP wakeup timeout!");
- wl12xx_queue_recovery_work(wl);
+ wl1271_warning("ELP wakeup timeout!");
/* Return no error for runtime PM for recovery */
- return 0;
+ ret = 0;
+ recovery = true;
+ goto err;
}
}
@@ -6753,6 +6773,12 @@ err:
spin_lock_irqsave(&wl->wl_lock, flags);
wl->elp_compl = NULL;
spin_unlock_irqrestore(&wl->wl_lock, flags);
+
+ if (recovery) {
+ set_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags);
+ wl12xx_queue_recovery_work(wl);
+ }
+
return ret;
}
@@ -6815,10 +6841,16 @@ int wlcore_remove(struct platform_device *pdev)
if (!wl->initialized)
return 0;
- if (wl->irq_wake_enabled) {
- device_init_wakeup(wl->dev, 0);
- disable_irq_wake(wl->irq);
+ if (wl->wakeirq >= 0) {
+ dev_pm_clear_wake_irq(wl->dev);
+ wl->wakeirq = -ENODEV;
}
+
+ device_init_wakeup(wl->dev, false);
+
+ if (wl->irq_wake_enabled)
+ disable_irq_wake(wl->irq);
+
wl1271_unregister_hw(wl);
pm_runtime_put_sync(wl->dev);
diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c
index 750bea3574ee..4c2154b9e6a3 100644
--- a/drivers/net/wireless/ti/wlcore/sdio.c
+++ b/drivers/net/wireless/ti/wlcore/sdio.c
@@ -241,7 +241,7 @@ static const struct of_device_id wlcore_sdio_of_match_table[] = {
{ }
};
-static int wlcore_probe_of(struct device *dev, int *irq,
+static int wlcore_probe_of(struct device *dev, int *irq, int *wakeirq,
struct wlcore_platdev_data *pdev_data)
{
struct device_node *np = dev->of_node;
@@ -259,6 +259,8 @@ static int wlcore_probe_of(struct device *dev, int *irq,
return -EINVAL;
}
+ *wakeirq = irq_of_parse_and_map(np, 1);
+
/* optional clock frequency params */
of_property_read_u32(np, "ref-clock-frequency",
&pdev_data->ref_clock_freq);
@@ -268,7 +270,7 @@ static int wlcore_probe_of(struct device *dev, int *irq,
return 0;
}
#else
-static int wlcore_probe_of(struct device *dev, int *irq,
+static int wlcore_probe_of(struct device *dev, int *irq, int *wakeirq,
struct wlcore_platdev_data *pdev_data)
{
return -ENODATA;
@@ -280,10 +282,10 @@ static int wl1271_probe(struct sdio_func *func,
{
struct wlcore_platdev_data *pdev_data;
struct wl12xx_sdio_glue *glue;
- struct resource res[1];
+ struct resource res[2];
mmc_pm_flag_t mmcflags;
int ret = -ENOMEM;
- int irq;
+ int irq, wakeirq;
const char *chip_family;
/* We are only able to handle the wlan function */
@@ -308,7 +310,7 @@ static int wl1271_probe(struct sdio_func *func,
/* Use block mode for transferring over one block size of data */
func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE;
- ret = wlcore_probe_of(&func->dev, &irq, pdev_data);
+ ret = wlcore_probe_of(&func->dev, &irq, &wakeirq, pdev_data);
if (ret)
goto out;
@@ -351,6 +353,11 @@ static int wl1271_probe(struct sdio_func *func,
irqd_get_trigger_type(irq_get_irq_data(irq));
res[0].name = "irq";
+ res[1].start = wakeirq;
+ res[1].flags = IORESOURCE_IRQ |
+ irqd_get_trigger_type(irq_get_irq_data(wakeirq));
+ res[1].name = "wakeirq";
+
ret = platform_device_add_resources(glue->core, res, ARRAY_SIZE(res));
if (ret) {
dev_err(glue->dev, "can't add resources\n");
diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h
index d4b1f66ef457..dd14850b0603 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore.h
@@ -199,8 +199,10 @@ struct wl1271 {
struct wl1271_if_operations *if_ops;
int irq;
+ int wakeirq;
int irq_flags;
+ int wakeirq_flags;
spinlock_t wl_lock;
diff --git a/drivers/net/wireless/zydas/zd1211rw/zd_mac.c b/drivers/net/wireless/zydas/zd1211rw/zd_mac.c
index 1f6d9f357e57..9ccd780695f0 100644
--- a/drivers/net/wireless/zydas/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zydas/zd1211rw/zd_mac.c
@@ -235,7 +235,7 @@ void zd_mac_clear(struct zd_mac *mac)
{
flush_workqueue(zd_workqueue);
zd_chip_clear(&mac->chip);
- ZD_ASSERT(!spin_is_locked(&mac->lock));
+ lockdep_assert_held(&mac->lock);
ZD_MEMCLEAR(mac, sizeof(struct zd_mac));
}
diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h
index a46a1e94505d..936c0b3e0ba2 100644
--- a/drivers/net/xen-netback/common.h
+++ b/drivers/net/xen-netback/common.h
@@ -241,8 +241,9 @@ struct xenvif_hash_cache {
struct xenvif_hash {
unsigned int alg;
u32 flags;
+ bool mapping_sel;
u8 key[XEN_NETBK_MAX_HASH_KEY_SIZE];
- u32 mapping[XEN_NETBK_MAX_HASH_MAPPING_SIZE];
+ u32 mapping[2][XEN_NETBK_MAX_HASH_MAPPING_SIZE];
unsigned int size;
struct xenvif_hash_cache cache;
};
diff --git a/drivers/net/xen-netback/hash.c b/drivers/net/xen-netback/hash.c
index 3c4c58b9fe76..0ccb021f1e78 100644
--- a/drivers/net/xen-netback/hash.c
+++ b/drivers/net/xen-netback/hash.c
@@ -324,7 +324,8 @@ u32 xenvif_set_hash_mapping_size(struct xenvif *vif, u32 size)
return XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER;
vif->hash.size = size;
- memset(vif->hash.mapping, 0, sizeof(u32) * size);
+ memset(vif->hash.mapping[vif->hash.mapping_sel], 0,
+ sizeof(u32) * size);
return XEN_NETIF_CTRL_STATUS_SUCCESS;
}
@@ -332,31 +333,49 @@ u32 xenvif_set_hash_mapping_size(struct xenvif *vif, u32 size)
u32 xenvif_set_hash_mapping(struct xenvif *vif, u32 gref, u32 len,
u32 off)
{
- u32 *mapping = &vif->hash.mapping[off];
- struct gnttab_copy copy_op = {
+ u32 *mapping = vif->hash.mapping[!vif->hash.mapping_sel];
+ unsigned int nr = 1;
+ struct gnttab_copy copy_op[2] = {{
.source.u.ref = gref,
.source.domid = vif->domid,
- .dest.u.gmfn = virt_to_gfn(mapping),
.dest.domid = DOMID_SELF,
- .dest.offset = xen_offset_in_page(mapping),
- .len = len * sizeof(u32),
+ .len = len * sizeof(*mapping),
.flags = GNTCOPY_source_gref
- };
+ }};
- if ((off + len > vif->hash.size) || copy_op.len > XEN_PAGE_SIZE)
+ if ((off + len < off) || (off + len > vif->hash.size) ||
+ len > XEN_PAGE_SIZE / sizeof(*mapping))
return XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER;
- while (len-- != 0)
- if (mapping[off++] >= vif->num_queues)
- return XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER;
+ copy_op[0].dest.u.gmfn = virt_to_gfn(mapping + off);
+ copy_op[0].dest.offset = xen_offset_in_page(mapping + off);
+ if (copy_op[0].dest.offset + copy_op[0].len > XEN_PAGE_SIZE) {
+ copy_op[1] = copy_op[0];
+ copy_op[1].source.offset = XEN_PAGE_SIZE - copy_op[0].dest.offset;
+ copy_op[1].dest.u.gmfn = virt_to_gfn(mapping + off + len);
+ copy_op[1].dest.offset = 0;
+ copy_op[1].len = copy_op[0].len - copy_op[1].source.offset;
+ copy_op[0].len = copy_op[1].source.offset;
+ nr = 2;
+ }
- if (copy_op.len != 0) {
- gnttab_batch_copy(&copy_op, 1);
+ memcpy(mapping, vif->hash.mapping[vif->hash.mapping_sel],
+ vif->hash.size * sizeof(*mapping));
- if (copy_op.status != GNTST_okay)
+ if (copy_op[0].len != 0) {
+ gnttab_batch_copy(copy_op, nr);
+
+ if (copy_op[0].status != GNTST_okay ||
+ copy_op[nr - 1].status != GNTST_okay)
return XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER;
}
+ while (len-- != 0)
+ if (mapping[off++] >= vif->num_queues)
+ return XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER;
+
+ vif->hash.mapping_sel = !vif->hash.mapping_sel;
+
return XEN_NETIF_CTRL_STATUS_SUCCESS;
}
@@ -408,6 +427,8 @@ void xenvif_dump_hash_info(struct xenvif *vif, struct seq_file *m)
}
if (vif->hash.size != 0) {
+ const u32 *mapping = vif->hash.mapping[vif->hash.mapping_sel];
+
seq_puts(m, "\nHash Mapping:\n");
for (i = 0; i < vif->hash.size; ) {
@@ -420,7 +441,7 @@ void xenvif_dump_hash_info(struct xenvif *vif, struct seq_file *m)
seq_printf(m, "[%4u - %4u]: ", i, i + n - 1);
for (j = 0; j < n; j++, i++)
- seq_printf(m, "%4u ", vif->hash.mapping[i]);
+ seq_printf(m, "%4u ", mapping[i]);
seq_puts(m, "\n");
}
diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
index 92274c237200..182d6770f102 100644
--- a/drivers/net/xen-netback/interface.c
+++ b/drivers/net/xen-netback/interface.c
@@ -162,10 +162,12 @@ static u16 xenvif_select_queue(struct net_device *dev, struct sk_buff *skb,
if (size == 0)
return skb_get_hash_raw(skb) % dev->real_num_tx_queues;
- return vif->hash.mapping[skb_get_hash_raw(skb) % size];
+ return vif->hash.mapping[vif->hash.mapping_sel]
+ [skb_get_hash_raw(skb) % size];
}
-static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t
+xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct xenvif *vif = netdev_priv(dev);
struct xenvif_queue *queue = NULL;
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
index 3621e05a7494..80aae3a32c2a 100644
--- a/drivers/net/xen-netback/netback.c
+++ b/drivers/net/xen-netback/netback.c
@@ -1660,8 +1660,7 @@ module_init(netback_init);
static void __exit netback_fini(void)
{
#ifdef CONFIG_DEBUG_FS
- if (!IS_ERR_OR_NULL(xen_netback_dbg_root))
- debugfs_remove_recursive(xen_netback_dbg_root);
+ debugfs_remove_recursive(xen_netback_dbg_root);
#endif /* CONFIG_DEBUG_FS */
xenvif_xenbus_fini();
}
diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c
index cd51492ae6c2..fe1d52247bbe 100644
--- a/drivers/net/xen-netback/xenbus.c
+++ b/drivers/net/xen-netback/xenbus.c
@@ -254,8 +254,7 @@ static void xenvif_debugfs_delif(struct xenvif *vif)
if (IS_ERR_OR_NULL(xen_netback_dbg_root))
return;
- if (!IS_ERR_OR_NULL(vif->xenvif_dbg_root))
- debugfs_remove_recursive(vif->xenvif_dbg_root);
+ debugfs_remove_recursive(vif->xenvif_dbg_root);
vif->xenvif_dbg_root = NULL;
}
#endif /* CONFIG_DEBUG_FS */
diff --git a/drivers/nfc/nfcmrvl/uart.c b/drivers/nfc/nfcmrvl/uart.c
index 91162f8e0366..9a22056e8d9e 100644
--- a/drivers/nfc/nfcmrvl/uart.c
+++ b/drivers/nfc/nfcmrvl/uart.c
@@ -73,10 +73,9 @@ static int nfcmrvl_uart_parse_dt(struct device_node *node,
struct device_node *matched_node;
int ret;
- matched_node = of_find_compatible_node(node, NULL, "marvell,nfc-uart");
+ matched_node = of_get_compatible_child(node, "marvell,nfc-uart");
if (!matched_node) {
- matched_node = of_find_compatible_node(node, NULL,
- "mrvl,nfc-uart");
+ matched_node = of_get_compatible_child(node, "mrvl,nfc-uart");
if (!matched_node)
return -ENODEV;
}
diff --git a/drivers/ntb/hw/idt/Kconfig b/drivers/ntb/hw/idt/Kconfig
index b360e5613b9f..f8948cf515ce 100644
--- a/drivers/ntb/hw/idt/Kconfig
+++ b/drivers/ntb/hw/idt/Kconfig
@@ -1,6 +1,7 @@
config NTB_IDT
tristate "IDT PCIe-switch Non-Transparent Bridge support"
depends on PCI
+ select HWMON
help
This driver supports NTB of cappable IDT PCIe-switches.
@@ -23,9 +24,7 @@ config NTB_IDT
BAR settings of peer NT-functions, the BAR setups can't be done over
kernel PCI fixups. That's why the alternative pre-initialization
techniques like BIOS using SMBus interface or EEPROM should be
- utilized. Additionally if one needs to have temperature sensor
- information printed to system log, the corresponding registers must
- be initialized within BIOS/EEPROM as well.
+ utilized.
If unsure, say N.
diff --git a/drivers/ntb/hw/idt/ntb_hw_idt.c b/drivers/ntb/hw/idt/ntb_hw_idt.c
index dbe72f116017..1dede87dd54f 100644
--- a/drivers/ntb/hw/idt/ntb_hw_idt.c
+++ b/drivers/ntb/hw/idt/ntb_hw_idt.c
@@ -4,7 +4,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright (C) 2016 T-Platforms All Rights Reserved.
+ * Copyright (C) 2016-2018 T-Platforms JSC 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,
@@ -49,11 +49,14 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
+#include <linux/mutex.h>
#include <linux/pci.h>
#include <linux/aer.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/debugfs.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
#include <linux/ntb.h>
#include "ntb_hw_idt.h"
@@ -1105,9 +1108,9 @@ static struct idt_mw_cfg *idt_scan_mws(struct idt_ntb_dev *ndev, int port,
}
/* Allocate memory for memory window descriptors */
- ret_mws = devm_kcalloc(&ndev->ntb.pdev->dev, *mw_cnt,
- sizeof(*ret_mws), GFP_KERNEL);
- if (IS_ERR_OR_NULL(ret_mws))
+ ret_mws = devm_kcalloc(&ndev->ntb.pdev->dev, *mw_cnt, sizeof(*ret_mws),
+ GFP_KERNEL);
+ if (!ret_mws)
return ERR_PTR(-ENOMEM);
/* Copy the info of detected memory windows */
@@ -1320,7 +1323,7 @@ static int idt_ntb_peer_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx,
idt_nt_write(ndev, bar->ltbase, (u32)addr);
idt_nt_write(ndev, bar->utbase, (u32)(addr >> 32));
/* Set the custom BAR aperture limit */
- limit = pci_resource_start(ntb->pdev, mw_cfg->bar) + size;
+ limit = pci_bus_address(ntb->pdev, mw_cfg->bar) + size;
idt_nt_write(ndev, bar->limit, (u32)limit);
if (IS_FLD_SET(BARSETUP_TYPE, data, 64))
idt_nt_write(ndev, (bar + 1)->limit, (limit >> 32));
@@ -1821,61 +1824,284 @@ static int idt_ntb_peer_msg_write(struct ntb_dev *ntb, int pidx, int midx,
* 7. Temperature sensor operations
*
* IDT PCIe-switch has an embedded temperature sensor, which can be used to
- * warn a user-space of possible chip overheating. Since workload temperature
- * can be different on different platforms, temperature thresholds as well as
- * general sensor settings must be setup in the framework of BIOS/EEPROM
- * initializations. It includes the actual sensor enabling as well.
+ * check current chip core temperature. Since a workload environment can be
+ * different on different platforms, an offset and ADC/filter settings can be
+ * specified. Although the offset configuration is only exposed to the sysfs
+ * hwmon interface at the moment. The rest of the settings can be adjusted
+ * for instance by the BIOS/EEPROM firmware.
*=============================================================================
*/
/*
+ * idt_get_deg() - convert millidegree Celsius value to just degree
+ * @mdegC: IN - millidegree Celsius value
+ *
+ * Return: Degree corresponding to the passed millidegree value
+ */
+static inline s8 idt_get_deg(long mdegC)
+{
+ return mdegC / 1000;
+}
+
+/*
+ * idt_get_frac() - retrieve 0/0.5 fraction of the millidegree Celsius value
+ * @mdegC: IN - millidegree Celsius value
+ *
+ * Return: 0/0.5 degree fraction of the passed millidegree value
+ */
+static inline u8 idt_get_deg_frac(long mdegC)
+{
+ return (mdegC % 1000) >= 500 ? 5 : 0;
+}
+
+/*
+ * idt_get_temp_fmt() - convert millidegree Celsius value to 0:7:1 format
+ * @mdegC: IN - millidegree Celsius value
+ *
+ * Return: 0:7:1 format acceptable by the IDT temperature sensor
+ */
+static inline u8 idt_temp_get_fmt(long mdegC)
+{
+ return (idt_get_deg(mdegC) << 1) | (idt_get_deg_frac(mdegC) ? 1 : 0);
+}
+
+/*
+ * idt_get_temp_sval() - convert temp sample to signed millidegree Celsius
+ * @data: IN - shifted to LSB 8-bits temperature sample
+ *
+ * Return: signed millidegree Celsius
+ */
+static inline long idt_get_temp_sval(u32 data)
+{
+ return ((s8)data / 2) * 1000 + (data & 0x1 ? 500 : 0);
+}
+
+/*
+ * idt_get_temp_sval() - convert temp sample to unsigned millidegree Celsius
+ * @data: IN - shifted to LSB 8-bits temperature sample
+ *
+ * Return: unsigned millidegree Celsius
+ */
+static inline long idt_get_temp_uval(u32 data)
+{
+ return (data / 2) * 1000 + (data & 0x1 ? 500 : 0);
+}
+
+/*
* idt_read_temp() - read temperature from chip sensor
* @ntb: NTB device context.
- * @val: OUT - integer value of temperature
- * @frac: OUT - fraction
+ * @type: IN - type of the temperature value to read
+ * @val: OUT - integer value of temperature in millidegree Celsius
*/
-static void idt_read_temp(struct idt_ntb_dev *ndev, unsigned char *val,
- unsigned char *frac)
+static void idt_read_temp(struct idt_ntb_dev *ndev,
+ const enum idt_temp_val type, long *val)
{
u32 data;
- /* Read the data from TEMP field of the TMPSTS register */
- data = idt_sw_read(ndev, IDT_SW_TMPSTS);
- data = GET_FIELD(TMPSTS_TEMP, data);
- /* TEMP field has one fractional bit and seven integer bits */
- *val = data >> 1;
- *frac = ((data & 0x1) ? 5 : 0);
+ /* Alter the temperature field in accordance with the passed type */
+ switch (type) {
+ case IDT_TEMP_CUR:
+ data = GET_FIELD(TMPSTS_TEMP,
+ idt_sw_read(ndev, IDT_SW_TMPSTS));
+ break;
+ case IDT_TEMP_LOW:
+ data = GET_FIELD(TMPSTS_LTEMP,
+ idt_sw_read(ndev, IDT_SW_TMPSTS));
+ break;
+ case IDT_TEMP_HIGH:
+ data = GET_FIELD(TMPSTS_HTEMP,
+ idt_sw_read(ndev, IDT_SW_TMPSTS));
+ break;
+ case IDT_TEMP_OFFSET:
+ /* This is the only field with signed 0:7:1 format */
+ data = GET_FIELD(TMPADJ_OFFSET,
+ idt_sw_read(ndev, IDT_SW_TMPADJ));
+ *val = idt_get_temp_sval(data);
+ return;
+ default:
+ data = GET_FIELD(TMPSTS_TEMP,
+ idt_sw_read(ndev, IDT_SW_TMPSTS));
+ break;
+ }
+
+ /* The rest of the fields accept unsigned 0:7:1 format */
+ *val = idt_get_temp_uval(data);
}
/*
- * idt_temp_isr() - temperature sensor alarm events ISR
- * @ndev: IDT NTB hardware driver descriptor
- * @ntint_sts: NT-function interrupt status
+ * idt_write_temp() - write temperature to the chip sensor register
+ * @ntb: NTB device context.
+ * @type: IN - type of the temperature value to change
+ * @val: IN - integer value of temperature in millidegree Celsius
+ */
+static void idt_write_temp(struct idt_ntb_dev *ndev,
+ const enum idt_temp_val type, const long val)
+{
+ unsigned int reg;
+ u32 data;
+ u8 fmt;
+
+ /* Retrieve the properly formatted temperature value */
+ fmt = idt_temp_get_fmt(val);
+
+ mutex_lock(&ndev->hwmon_mtx);
+ switch (type) {
+ case IDT_TEMP_LOW:
+ reg = IDT_SW_TMPALARM;
+ data = SET_FIELD(TMPALARM_LTEMP, idt_sw_read(ndev, reg), fmt) &
+ ~IDT_TMPALARM_IRQ_MASK;
+ break;
+ case IDT_TEMP_HIGH:
+ reg = IDT_SW_TMPALARM;
+ data = SET_FIELD(TMPALARM_HTEMP, idt_sw_read(ndev, reg), fmt) &
+ ~IDT_TMPALARM_IRQ_MASK;
+ break;
+ case IDT_TEMP_OFFSET:
+ reg = IDT_SW_TMPADJ;
+ data = SET_FIELD(TMPADJ_OFFSET, idt_sw_read(ndev, reg), fmt);
+ break;
+ default:
+ goto inval_spin_unlock;
+ }
+
+ idt_sw_write(ndev, reg, data);
+
+inval_spin_unlock:
+ mutex_unlock(&ndev->hwmon_mtx);
+}
+
+/*
+ * idt_sysfs_show_temp() - printout corresponding temperature value
+ * @dev: Pointer to the NTB device structure
+ * @da: Sensor device attribute structure
+ * @buf: Buffer to print temperature out
*
- * It handles events of temperature crossing alarm thresholds. Since reading
- * of TMPALARM register clears it up, the function doesn't analyze the
- * read value, instead the current temperature value just warningly printed to
- * log.
- * The method is called from PCIe ISR bottom-half routine.
+ * Return: Number of written symbols or negative error
*/
-static void idt_temp_isr(struct idt_ntb_dev *ndev, u32 ntint_sts)
+static ssize_t idt_sysfs_show_temp(struct device *dev,
+ struct device_attribute *da, char *buf)
{
- unsigned char val, frac;
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct idt_ntb_dev *ndev = dev_get_drvdata(dev);
+ enum idt_temp_val type = attr->index;
+ long mdeg;
- /* Read the current temperature value */
- idt_read_temp(ndev, &val, &frac);
+ idt_read_temp(ndev, type, &mdeg);
+ return sprintf(buf, "%ld\n", mdeg);
+}
- /* Read the temperature alarm to clean the alarm status out */
- /*(void)idt_sw_read(ndev, IDT_SW_TMPALARM);*/
+/*
+ * idt_sysfs_set_temp() - set corresponding temperature value
+ * @dev: Pointer to the NTB device structure
+ * @da: Sensor device attribute structure
+ * @buf: Buffer to print temperature out
+ * @count: Size of the passed buffer
+ *
+ * Return: Number of written symbols or negative error
+ */
+static ssize_t idt_sysfs_set_temp(struct device *dev,
+ struct device_attribute *da, const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct idt_ntb_dev *ndev = dev_get_drvdata(dev);
+ enum idt_temp_val type = attr->index;
+ long mdeg;
+ int ret;
- /* Clean the corresponding interrupt bit */
- idt_nt_write(ndev, IDT_NT_NTINTSTS, IDT_NTINTSTS_TMPSENSOR);
+ ret = kstrtol(buf, 10, &mdeg);
+ if (ret)
+ return ret;
+
+ /* Clamp the passed value in accordance with the type */
+ if (type == IDT_TEMP_OFFSET)
+ mdeg = clamp_val(mdeg, IDT_TEMP_MIN_OFFSET,
+ IDT_TEMP_MAX_OFFSET);
+ else
+ mdeg = clamp_val(mdeg, IDT_TEMP_MIN_MDEG, IDT_TEMP_MAX_MDEG);
+
+ idt_write_temp(ndev, type, mdeg);
+
+ return count;
+}
+
+/*
+ * idt_sysfs_reset_hist() - reset temperature history
+ * @dev: Pointer to the NTB device structure
+ * @da: Sensor device attribute structure
+ * @buf: Buffer to print temperature out
+ * @count: Size of the passed buffer
+ *
+ * Return: Number of written symbols or negative error
+ */
+static ssize_t idt_sysfs_reset_hist(struct device *dev,
+ struct device_attribute *da,
+ const char *buf, size_t count)
+{
+ struct idt_ntb_dev *ndev = dev_get_drvdata(dev);
+
+ /* Just set the maximal value to the lowest temperature field and
+ * minimal value to the highest temperature field
+ */
+ idt_write_temp(ndev, IDT_TEMP_LOW, IDT_TEMP_MAX_MDEG);
+ idt_write_temp(ndev, IDT_TEMP_HIGH, IDT_TEMP_MIN_MDEG);
- dev_dbg(&ndev->ntb.pdev->dev,
- "Temp sensor IRQ detected %#08x", ntint_sts);
+ return count;
+}
+
+/*
+ * Hwmon IDT sysfs attributes
+ */
+static SENSOR_DEVICE_ATTR(temp1_input, 0444, idt_sysfs_show_temp, NULL,
+ IDT_TEMP_CUR);
+static SENSOR_DEVICE_ATTR(temp1_lowest, 0444, idt_sysfs_show_temp, NULL,
+ IDT_TEMP_LOW);
+static SENSOR_DEVICE_ATTR(temp1_highest, 0444, idt_sysfs_show_temp, NULL,
+ IDT_TEMP_HIGH);
+static SENSOR_DEVICE_ATTR(temp1_offset, 0644, idt_sysfs_show_temp,
+ idt_sysfs_set_temp, IDT_TEMP_OFFSET);
+static DEVICE_ATTR(temp1_reset_history, 0200, NULL, idt_sysfs_reset_hist);
- /* Print temperature value to log */
- dev_warn(&ndev->ntb.pdev->dev, "Temperature %hhu.%hhu", val, frac);
+/*
+ * Hwmon IDT sysfs attributes group
+ */
+static struct attribute *idt_temp_attrs[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_lowest.dev_attr.attr,
+ &sensor_dev_attr_temp1_highest.dev_attr.attr,
+ &sensor_dev_attr_temp1_offset.dev_attr.attr,
+ &dev_attr_temp1_reset_history.attr,
+ NULL
+};
+ATTRIBUTE_GROUPS(idt_temp);
+
+/*
+ * idt_init_temp() - initialize temperature sensor interface
+ * @ndev: IDT NTB hardware driver descriptor
+ *
+ * Simple sensor initializarion method is responsible for device switching
+ * on and resource management based hwmon interface registration. Note, that
+ * since the device is shared we won't disable it on remove, but leave it
+ * working until the system is powered off.
+ */
+static void idt_init_temp(struct idt_ntb_dev *ndev)
+{
+ struct device *hwmon;
+
+ /* Enable sensor if it hasn't been already */
+ idt_sw_write(ndev, IDT_SW_TMPCTL, 0x0);
+
+ /* Initialize hwmon interface fields */
+ mutex_init(&ndev->hwmon_mtx);
+
+ hwmon = devm_hwmon_device_register_with_groups(&ndev->ntb.pdev->dev,
+ ndev->swcfg->name, ndev, idt_temp_groups);
+ if (IS_ERR(hwmon)) {
+ dev_err(&ndev->ntb.pdev->dev, "Couldn't create hwmon device");
+ return;
+ }
+
+ dev_dbg(&ndev->ntb.pdev->dev, "Temperature HWmon interface registered");
}
/*=============================================================================
@@ -1931,7 +2157,7 @@ static int idt_init_isr(struct idt_ntb_dev *ndev)
goto err_free_vectors;
}
- /* Unmask Message/Doorbell/SE/Temperature interrupts */
+ /* Unmask Message/Doorbell/SE interrupts */
ntint_mask = idt_nt_read(ndev, IDT_NT_NTINTMSK) & ~IDT_NTINTMSK_ALL;
idt_nt_write(ndev, IDT_NT_NTINTMSK, ntint_mask);
@@ -1946,7 +2172,6 @@ err_free_vectors:
return ret;
}
-
/*
* idt_deinit_ist() - deinitialize PCIe interrupt handler
* @ndev: IDT NTB hardware driver descriptor
@@ -2007,12 +2232,6 @@ static irqreturn_t idt_thread_isr(int irq, void *devid)
handled = true;
}
- /* Handle temperature sensor interrupt */
- if (ntint_sts & IDT_NTINTSTS_TMPSENSOR) {
- idt_temp_isr(ndev, ntint_sts);
- handled = true;
- }
-
dev_dbg(&ndev->ntb.pdev->dev, "IDT IRQs 0x%08x handled", ntint_sts);
return handled ? IRQ_HANDLED : IRQ_NONE;
@@ -2123,9 +2342,9 @@ static ssize_t idt_dbgfs_info_read(struct file *filp, char __user *ubuf,
size_t count, loff_t *offp)
{
struct idt_ntb_dev *ndev = filp->private_data;
- unsigned char temp, frac, idx, pidx, cnt;
+ unsigned char idx, pidx, cnt;
+ unsigned long irqflags, mdeg;
ssize_t ret = 0, off = 0;
- unsigned long irqflags;
enum ntb_speed speed;
enum ntb_width width;
char *strbuf;
@@ -2274,9 +2493,10 @@ static ssize_t idt_dbgfs_info_read(struct file *filp, char __user *ubuf,
off += scnprintf(strbuf + off, size - off, "\n");
/* Current temperature */
- idt_read_temp(ndev, &temp, &frac);
+ idt_read_temp(ndev, IDT_TEMP_CUR, &mdeg);
off += scnprintf(strbuf + off, size - off,
- "Switch temperature\t\t- %hhu.%hhuC\n", temp, frac);
+ "Switch temperature\t\t- %hhd.%hhuC\n",
+ idt_get_deg(mdeg), idt_get_deg_frac(mdeg));
/* Copy the buffer to the User Space */
ret = simple_read_from_buffer(ubuf, count, offp, strbuf, off);
@@ -2390,7 +2610,7 @@ static struct idt_ntb_dev *idt_create_dev(struct pci_dev *pdev,
/* Allocate memory for the IDT PCIe-device descriptor */
ndev = devm_kzalloc(&pdev->dev, sizeof(*ndev), GFP_KERNEL);
- if (IS_ERR_OR_NULL(ndev)) {
+ if (!ndev) {
dev_err(&pdev->dev, "Memory allocation failed for descriptor");
return ERR_PTR(-ENOMEM);
}
@@ -2571,6 +2791,9 @@ static int idt_pci_probe(struct pci_dev *pdev,
/* Initialize Messaging subsystem */
idt_init_msg(ndev);
+ /* Initialize hwmon interface */
+ idt_init_temp(ndev);
+
/* Initialize IDT interrupts handler */
ret = idt_init_isr(ndev);
if (ret != 0)
diff --git a/drivers/ntb/hw/idt/ntb_hw_idt.h b/drivers/ntb/hw/idt/ntb_hw_idt.h
index 856fd182f6f4..2f1aa121b0cf 100644
--- a/drivers/ntb/hw/idt/ntb_hw_idt.h
+++ b/drivers/ntb/hw/idt/ntb_hw_idt.h
@@ -4,7 +4,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright (C) 2016 T-Platforms All Rights Reserved.
+ * Copyright (C) 2016-2018 T-Platforms JSC 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,
@@ -47,9 +47,9 @@
#include <linux/pci_ids.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
+#include <linux/mutex.h>
#include <linux/ntb.h>
-
/*
* Macro is used to create the struct pci_device_id that matches
* the supported IDT PCIe-switches
@@ -688,15 +688,14 @@
* @IDT_NTINTMSK_DBELL: Doorbell interrupt mask bit
* @IDT_NTINTMSK_SEVENT: Switch Event interrupt mask bit
* @IDT_NTINTMSK_TMPSENSOR: Temperature sensor interrupt mask bit
- * @IDT_NTINTMSK_ALL: All the useful interrupts mask
+ * @IDT_NTINTMSK_ALL: NTB-related interrupts mask
*/
#define IDT_NTINTMSK_MSG 0x00000001U
#define IDT_NTINTMSK_DBELL 0x00000002U
#define IDT_NTINTMSK_SEVENT 0x00000008U
#define IDT_NTINTMSK_TMPSENSOR 0x00000080U
#define IDT_NTINTMSK_ALL \
- (IDT_NTINTMSK_MSG | IDT_NTINTMSK_DBELL | \
- IDT_NTINTMSK_SEVENT | IDT_NTINTMSK_TMPSENSOR)
+ (IDT_NTINTMSK_MSG | IDT_NTINTMSK_DBELL | IDT_NTINTMSK_SEVENT)
/*
* NTGSIGNAL register fields related constants
@@ -886,12 +885,60 @@
#define IDT_SWPxMSGCTL_PART_FLD 4
/*
+ * TMPCTL register fields related constants
+ * @IDT_TMPCTL_LTH_MASK: Low temperature threshold field mask
+ * @IDT_TMPCTL_LTH_FLD: Low temperature threshold field offset
+ * @IDT_TMPCTL_MTH_MASK: Middle temperature threshold field mask
+ * @IDT_TMPCTL_MTH_FLD: Middle temperature threshold field offset
+ * @IDT_TMPCTL_HTH_MASK: High temperature threshold field mask
+ * @IDT_TMPCTL_HTH_FLD: High temperature threshold field offset
+ * @IDT_TMPCTL_PDOWN: Temperature sensor power down
+ */
+#define IDT_TMPCTL_LTH_MASK 0x000000FFU
+#define IDT_TMPCTL_LTH_FLD 0
+#define IDT_TMPCTL_MTH_MASK 0x0000FF00U
+#define IDT_TMPCTL_MTH_FLD 8
+#define IDT_TMPCTL_HTH_MASK 0x00FF0000U
+#define IDT_TMPCTL_HTH_FLD 16
+#define IDT_TMPCTL_PDOWN 0x80000000U
+
+/*
* TMPSTS register fields related constants
* @IDT_TMPSTS_TEMP_MASK: Current temperature field mask
* @IDT_TMPSTS_TEMP_FLD: Current temperature field offset
+ * @IDT_TMPSTS_LTEMP_MASK: Lowest temperature field mask
+ * @IDT_TMPSTS_LTEMP_FLD: Lowest temperature field offset
+ * @IDT_TMPSTS_HTEMP_MASK: Highest temperature field mask
+ * @IDT_TMPSTS_HTEMP_FLD: Highest temperature field offset
*/
#define IDT_TMPSTS_TEMP_MASK 0x000000FFU
#define IDT_TMPSTS_TEMP_FLD 0
+#define IDT_TMPSTS_LTEMP_MASK 0x0000FF00U
+#define IDT_TMPSTS_LTEMP_FLD 8
+#define IDT_TMPSTS_HTEMP_MASK 0x00FF0000U
+#define IDT_TMPSTS_HTEMP_FLD 16
+
+/*
+ * TMPALARM register fields related constants
+ * @IDT_TMPALARM_LTEMP_MASK: Lowest temperature field mask
+ * @IDT_TMPALARM_LTEMP_FLD: Lowest temperature field offset
+ * @IDT_TMPALARM_HTEMP_MASK: Highest temperature field mask
+ * @IDT_TMPALARM_HTEMP_FLD: Highest temperature field offset
+ * @IDT_TMPALARM_IRQ_MASK: Alarm IRQ status mask
+ */
+#define IDT_TMPALARM_LTEMP_MASK 0x0000FF00U
+#define IDT_TMPALARM_LTEMP_FLD 8
+#define IDT_TMPALARM_HTEMP_MASK 0x00FF0000U
+#define IDT_TMPALARM_HTEMP_FLD 16
+#define IDT_TMPALARM_IRQ_MASK 0x3F000000U
+
+/*
+ * TMPADJ register fields related constants
+ * @IDT_TMPADJ_OFFSET_MASK: Temperature value offset field mask
+ * @IDT_TMPADJ_OFFSET_FLD: Temperature value offset field offset
+ */
+#define IDT_TMPADJ_OFFSET_MASK 0x000000FFU
+#define IDT_TMPADJ_OFFSET_FLD 0
/*
* Helper macro to get/set the corresponding field value
@@ -951,6 +998,32 @@
#define IDT_DIR_SIZE_ALIGN 1
/*
+ * IDT PCIe-switch temperature sensor value limits
+ * @IDT_TEMP_MIN_MDEG: Minimal integer value of temperature
+ * @IDT_TEMP_MAX_MDEG: Maximal integer value of temperature
+ * @IDT_TEMP_MIN_OFFSET:Minimal integer value of temperature offset
+ * @IDT_TEMP_MAX_OFFSET:Maximal integer value of temperature offset
+ */
+#define IDT_TEMP_MIN_MDEG 0
+#define IDT_TEMP_MAX_MDEG 127500
+#define IDT_TEMP_MIN_OFFSET -64000
+#define IDT_TEMP_MAX_OFFSET 63500
+
+/*
+ * Temperature sensor values enumeration
+ * @IDT_TEMP_CUR: Current temperature
+ * @IDT_TEMP_LOW: Lowest historical temperature
+ * @IDT_TEMP_HIGH: Highest historical temperature
+ * @IDT_TEMP_OFFSET: Current temperature offset
+ */
+enum idt_temp_val {
+ IDT_TEMP_CUR,
+ IDT_TEMP_LOW,
+ IDT_TEMP_HIGH,
+ IDT_TEMP_OFFSET
+};
+
+/*
* IDT Memory Windows type. Depending on the device settings, IDT supports
* Direct Address Translation MW registers and Lookup Table registers
* @IDT_MW_DIR: Direct address translation
@@ -1044,6 +1117,8 @@ struct idt_ntb_peer {
* @msg_mask_lock: Message mask register lock
* @gasa_lock: GASA registers access lock
*
+ * @hwmon_mtx: Temperature sensor interface update mutex
+ *
* @dbgfs_info: DebugFS info node
*/
struct idt_ntb_dev {
@@ -1071,6 +1146,8 @@ struct idt_ntb_dev {
spinlock_t msg_mask_lock;
spinlock_t gasa_lock;
+ struct mutex hwmon_mtx;
+
struct dentry *dbgfs_info;
};
#define to_ndev_ntb(__ntb) container_of(__ntb, struct idt_ntb_dev, ntb)
diff --git a/drivers/ntb/hw/intel/ntb_hw_gen1.c b/drivers/ntb/hw/intel/ntb_hw_gen1.c
index 6aa573227279..2ad263f708da 100644
--- a/drivers/ntb/hw/intel/ntb_hw_gen1.c
+++ b/drivers/ntb/hw/intel/ntb_hw_gen1.c
@@ -265,7 +265,7 @@ static inline int ndev_db_clear_mask(struct intel_ntb_dev *ndev, u64 db_bits,
return 0;
}
-static inline int ndev_vec_mask(struct intel_ntb_dev *ndev, int db_vector)
+static inline u64 ndev_vec_mask(struct intel_ntb_dev *ndev, int db_vector)
{
u64 shift, mask;
diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
index 939895966476..3bfdb4562408 100644
--- a/drivers/ntb/ntb_transport.c
+++ b/drivers/ntb/ntb_transport.c
@@ -194,6 +194,8 @@ struct ntb_transport_mw {
void __iomem *vbase;
size_t xlat_size;
size_t buff_size;
+ size_t alloc_size;
+ void *alloc_addr;
void *virt_addr;
dma_addr_t dma_addr;
};
@@ -672,13 +674,59 @@ static void ntb_free_mw(struct ntb_transport_ctx *nt, int num_mw)
return;
ntb_mw_clear_trans(nt->ndev, PIDX, num_mw);
- dma_free_coherent(&pdev->dev, mw->buff_size,
- mw->virt_addr, mw->dma_addr);
+ dma_free_coherent(&pdev->dev, mw->alloc_size,
+ mw->alloc_addr, mw->dma_addr);
mw->xlat_size = 0;
mw->buff_size = 0;
+ mw->alloc_size = 0;
+ mw->alloc_addr = NULL;
mw->virt_addr = NULL;
}
+static int ntb_alloc_mw_buffer(struct ntb_transport_mw *mw,
+ struct device *dma_dev, size_t align)
+{
+ dma_addr_t dma_addr;
+ void *alloc_addr, *virt_addr;
+ int rc;
+
+ alloc_addr = dma_alloc_coherent(dma_dev, mw->alloc_size,
+ &dma_addr, GFP_KERNEL);
+ if (!alloc_addr) {
+ dev_err(dma_dev, "Unable to alloc MW buff of size %zu\n",
+ mw->alloc_size);
+ return -ENOMEM;
+ }
+ virt_addr = alloc_addr;
+
+ /*
+ * we must ensure that the memory address allocated is BAR size
+ * aligned in order for the XLAT register to take the value. This
+ * is a requirement of the hardware. It is recommended to setup CMA
+ * for BAR sizes equal or greater than 4MB.
+ */
+ if (!IS_ALIGNED(dma_addr, align)) {
+ if (mw->alloc_size > mw->buff_size) {
+ virt_addr = PTR_ALIGN(alloc_addr, align);
+ dma_addr = ALIGN(dma_addr, align);
+ } else {
+ rc = -ENOMEM;
+ goto err;
+ }
+ }
+
+ mw->alloc_addr = alloc_addr;
+ mw->virt_addr = virt_addr;
+ mw->dma_addr = dma_addr;
+
+ return 0;
+
+err:
+ dma_free_coherent(dma_dev, mw->alloc_size, alloc_addr, dma_addr);
+
+ return rc;
+}
+
static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw,
resource_size_t size)
{
@@ -710,28 +758,20 @@ static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw,
/* Alloc memory for receiving data. Must be aligned */
mw->xlat_size = xlat_size;
mw->buff_size = buff_size;
+ mw->alloc_size = buff_size;
- mw->virt_addr = dma_alloc_coherent(&pdev->dev, buff_size,
- &mw->dma_addr, GFP_KERNEL);
- if (!mw->virt_addr) {
- mw->xlat_size = 0;
- mw->buff_size = 0;
- dev_err(&pdev->dev, "Unable to alloc MW buff of size %zu\n",
- buff_size);
- return -ENOMEM;
- }
-
- /*
- * we must ensure that the memory address allocated is BAR size
- * aligned in order for the XLAT register to take the value. This
- * is a requirement of the hardware. It is recommended to setup CMA
- * for BAR sizes equal or greater than 4MB.
- */
- if (!IS_ALIGNED(mw->dma_addr, xlat_align)) {
- dev_err(&pdev->dev, "DMA memory %pad is not aligned\n",
- &mw->dma_addr);
- ntb_free_mw(nt, num_mw);
- return -ENOMEM;
+ rc = ntb_alloc_mw_buffer(mw, &pdev->dev, xlat_align);
+ if (rc) {
+ mw->alloc_size *= 2;
+ rc = ntb_alloc_mw_buffer(mw, &pdev->dev, xlat_align);
+ if (rc) {
+ dev_err(&pdev->dev,
+ "Unable to alloc aligned MW buff\n");
+ mw->xlat_size = 0;
+ mw->buff_size = 0;
+ mw->alloc_size = 0;
+ return rc;
+ }
}
/* Notify HW the memory location of the receive buffer */
@@ -1278,6 +1318,7 @@ static void ntb_rx_copy_callback(void *data,
case DMA_TRANS_READ_FAILED:
case DMA_TRANS_WRITE_FAILED:
entry->errors++;
+ /* fall through */
case DMA_TRANS_ABORTED:
{
struct ntb_transport_qp *qp = entry->qp;
@@ -1533,6 +1574,7 @@ static void ntb_tx_copy_callback(void *data,
case DMA_TRANS_READ_FAILED:
case DMA_TRANS_WRITE_FAILED:
entry->errors++;
+ /* fall through */
case DMA_TRANS_ABORTED:
{
void __iomem *offset =
diff --git a/drivers/nvdimm/blk.c b/drivers/nvdimm/blk.c
index 62e9cb167aad..db45c6bbb7bb 100644
--- a/drivers/nvdimm/blk.c
+++ b/drivers/nvdimm/blk.c
@@ -290,7 +290,7 @@ static int nsblk_attach_disk(struct nd_namespace_blk *nsblk)
}
set_capacity(disk, available_disk_size >> SECTOR_SHIFT);
- device_add_disk(dev, disk);
+ device_add_disk(dev, disk, NULL);
revalidate_disk(disk);
return 0;
}
diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c
index 0360c015f658..b123b0dcf274 100644
--- a/drivers/nvdimm/btt.c
+++ b/drivers/nvdimm/btt.c
@@ -1556,7 +1556,7 @@ static int btt_blk_init(struct btt *btt)
}
}
set_capacity(btt->btt_disk, btt->nlba * btt->sector_size >> 9);
- device_add_disk(&btt->nd_btt->dev, btt->btt_disk);
+ device_add_disk(&btt->nd_btt->dev, btt->btt_disk, NULL);
btt->nd_btt->size = btt->nlba * (u64)btt->sector_size;
revalidate_disk(btt->btt_disk);
diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c
index 8aae6dcc839f..f1fb39921236 100644
--- a/drivers/nvdimm/bus.c
+++ b/drivers/nvdimm/bus.c
@@ -54,12 +54,6 @@ static int to_nd_device_type(struct device *dev)
static int nvdimm_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{
- /*
- * Ensure that region devices always have their numa node set as
- * early as possible.
- */
- if (is_nd_region(dev))
- set_dev_node(dev, to_nd_region(dev)->numa_node);
return add_uevent_var(env, "MODALIAS=" ND_DEVICE_MODALIAS_FMT,
to_nd_device_type(dev));
}
@@ -488,6 +482,8 @@ static void nd_async_device_register(void *d, async_cookie_t cookie)
put_device(dev);
}
put_device(dev);
+ if (dev->parent)
+ put_device(dev->parent);
}
static void nd_async_device_unregister(void *d, async_cookie_t cookie)
@@ -506,7 +502,19 @@ void __nd_device_register(struct device *dev)
{
if (!dev)
return;
+
+ /*
+ * Ensure that region devices always have their NUMA node set as
+ * early as possible. This way we are able to make certain that
+ * any memory associated with the creation and the creation
+ * itself of the region is associated with the correct node.
+ */
+ if (is_nd_region(dev))
+ set_dev_node(dev, to_nd_region(dev)->numa_node);
+
dev->bus = &nvdimm_bus_type;
+ if (dev->parent)
+ get_device(dev->parent);
get_device(dev);
async_schedule_domain(nd_async_device_register, dev,
&nd_async_domain);
diff --git a/drivers/nvdimm/dimm.c b/drivers/nvdimm/dimm.c
index 6c8fb7590838..9899c97138a3 100644
--- a/drivers/nvdimm/dimm.c
+++ b/drivers/nvdimm/dimm.c
@@ -75,7 +75,7 @@ static int nvdimm_probe(struct device *dev)
* DIMM capacity. We fail the dimm probe to prevent regions from
* attempting to parse the label area.
*/
- rc = nvdimm_init_config_data(ndd);
+ rc = nd_label_data_init(ndd);
if (rc == -EACCES)
nvdimm_set_locked(dev);
if (rc)
@@ -84,10 +84,6 @@ static int nvdimm_probe(struct device *dev)
dev_dbg(dev, "config data size: %d\n", ndd->nsarea.config_size);
nvdimm_bus_lock(dev);
- ndd->ns_current = nd_label_validate(ndd);
- ndd->ns_next = nd_label_next_nsindex(ndd->ns_current);
- nd_label_copy(ndd, to_next_namespace_index(ndd),
- to_current_namespace_index(ndd));
if (ndd->ns_current >= 0) {
rc = nd_label_reserve_dpa(ndd);
if (rc == 0)
diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c
index 863cabc35215..6c3de2317390 100644
--- a/drivers/nvdimm/dimm_devs.c
+++ b/drivers/nvdimm/dimm_devs.c
@@ -85,56 +85,48 @@ int nvdimm_init_nsarea(struct nvdimm_drvdata *ndd)
return cmd_rc;
}
-int nvdimm_init_config_data(struct nvdimm_drvdata *ndd)
+int nvdimm_get_config_data(struct nvdimm_drvdata *ndd, void *buf,
+ size_t offset, size_t len)
{
struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(ndd->dev);
+ struct nvdimm_bus_descriptor *nd_desc = nvdimm_bus->nd_desc;
int rc = validate_dimm(ndd), cmd_rc = 0;
struct nd_cmd_get_config_data_hdr *cmd;
- struct nvdimm_bus_descriptor *nd_desc;
- u32 max_cmd_size, config_size;
- size_t offset;
+ size_t max_cmd_size, buf_offset;
if (rc)
return rc;
- if (ndd->data)
- return 0;
-
- if (ndd->nsarea.status || ndd->nsarea.max_xfer == 0
- || ndd->nsarea.config_size < ND_LABEL_MIN_SIZE) {
- dev_dbg(ndd->dev, "failed to init config data area: (%d:%d)\n",
- ndd->nsarea.max_xfer, ndd->nsarea.config_size);
+ if (offset + len > ndd->nsarea.config_size)
return -ENXIO;
- }
- ndd->data = kvmalloc(ndd->nsarea.config_size, GFP_KERNEL);
- if (!ndd->data)
- return -ENOMEM;
-
- max_cmd_size = min_t(u32, PAGE_SIZE, ndd->nsarea.max_xfer);
- cmd = kzalloc(max_cmd_size + sizeof(*cmd), GFP_KERNEL);
+ max_cmd_size = min_t(u32, len, ndd->nsarea.max_xfer);
+ cmd = kvzalloc(max_cmd_size + sizeof(*cmd), GFP_KERNEL);
if (!cmd)
return -ENOMEM;
- nd_desc = nvdimm_bus->nd_desc;
- for (config_size = ndd->nsarea.config_size, offset = 0;
- config_size; config_size -= cmd->in_length,
- offset += cmd->in_length) {
- cmd->in_length = min(config_size, max_cmd_size);
- cmd->in_offset = offset;
+ for (buf_offset = 0; len;
+ len -= cmd->in_length, buf_offset += cmd->in_length) {
+ size_t cmd_size;
+
+ cmd->in_offset = offset + buf_offset;
+ cmd->in_length = min(max_cmd_size, len);
+
+ cmd_size = sizeof(*cmd) + cmd->in_length;
+
rc = nd_desc->ndctl(nd_desc, to_nvdimm(ndd->dev),
- ND_CMD_GET_CONFIG_DATA, cmd,
- cmd->in_length + sizeof(*cmd), &cmd_rc);
+ ND_CMD_GET_CONFIG_DATA, cmd, cmd_size, &cmd_rc);
if (rc < 0)
break;
if (cmd_rc < 0) {
rc = cmd_rc;
break;
}
- memcpy(ndd->data + offset, cmd->out_buf, cmd->in_length);
+
+ /* out_buf should be valid, copy it into our output buffer */
+ memcpy(buf + buf_offset, cmd->out_buf, cmd->in_length);
}
- dev_dbg(ndd->dev, "len: %zu rc: %d\n", offset, rc);
- kfree(cmd);
+ kvfree(cmd);
return rc;
}
@@ -151,15 +143,11 @@ int nvdimm_set_config_data(struct nvdimm_drvdata *ndd, size_t offset,
if (rc)
return rc;
- if (!ndd->data)
- return -ENXIO;
-
if (offset + len > ndd->nsarea.config_size)
return -ENXIO;
- max_cmd_size = min_t(u32, PAGE_SIZE, len);
- max_cmd_size = min_t(u32, max_cmd_size, ndd->nsarea.max_xfer);
- cmd = kzalloc(max_cmd_size + sizeof(*cmd) + sizeof(u32), GFP_KERNEL);
+ max_cmd_size = min_t(u32, len, ndd->nsarea.max_xfer);
+ cmd = kvzalloc(max_cmd_size + sizeof(*cmd) + sizeof(u32), GFP_KERNEL);
if (!cmd)
return -ENOMEM;
@@ -183,7 +171,7 @@ int nvdimm_set_config_data(struct nvdimm_drvdata *ndd, size_t offset,
break;
}
}
- kfree(cmd);
+ kvfree(cmd);
return rc;
}
diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c
index 1d28cd656536..750dbaa6ce82 100644
--- a/drivers/nvdimm/label.c
+++ b/drivers/nvdimm/label.c
@@ -75,7 +75,8 @@ size_t sizeof_namespace_index(struct nvdimm_drvdata *ndd)
/*
* Per UEFI 2.7, the minimum size of the Label Storage Area is large
* enough to hold 2 index blocks and 2 labels. The minimum index
- * block size is 256 bytes, and the minimum label size is 256 bytes.
+ * block size is 256 bytes. The label size is 128 for namespaces
+ * prior to version 1.2 and at minimum 256 for version 1.2 and later.
*/
nslot = nvdimm_num_label_slots(ndd);
space = ndd->nsarea.config_size - nslot * sizeof_namespace_label(ndd);
@@ -183,6 +184,13 @@ static int __nd_label_validate(struct nvdimm_drvdata *ndd)
__le64_to_cpu(nsindex[i]->otheroff));
continue;
}
+ if (__le64_to_cpu(nsindex[i]->labeloff)
+ != 2 * sizeof_namespace_index(ndd)) {
+ dev_dbg(dev, "nsindex%d labeloff: %#llx invalid\n",
+ i, (unsigned long long)
+ __le64_to_cpu(nsindex[i]->labeloff));
+ continue;
+ }
size = __le64_to_cpu(nsindex[i]->mysize);
if (size > sizeof_namespace_index(ndd)
@@ -227,7 +235,7 @@ static int __nd_label_validate(struct nvdimm_drvdata *ndd)
return -1;
}
-int nd_label_validate(struct nvdimm_drvdata *ndd)
+static int nd_label_validate(struct nvdimm_drvdata *ndd)
{
/*
* In order to probe for and validate namespace index blocks we
@@ -250,12 +258,12 @@ int nd_label_validate(struct nvdimm_drvdata *ndd)
return -1;
}
-void nd_label_copy(struct nvdimm_drvdata *ndd, struct nd_namespace_index *dst,
- struct nd_namespace_index *src)
+static void nd_label_copy(struct nvdimm_drvdata *ndd,
+ struct nd_namespace_index *dst,
+ struct nd_namespace_index *src)
{
- if (dst && src)
- /* pass */;
- else
+ /* just exit if either destination or source is NULL */
+ if (!dst || !src)
return;
memcpy(dst, src, sizeof_namespace_index(ndd));
@@ -410,6 +418,128 @@ int nd_label_reserve_dpa(struct nvdimm_drvdata *ndd)
return 0;
}
+int nd_label_data_init(struct nvdimm_drvdata *ndd)
+{
+ size_t config_size, read_size, max_xfer, offset;
+ struct nd_namespace_index *nsindex;
+ unsigned int i;
+ int rc = 0;
+ u32 nslot;
+
+ if (ndd->data)
+ return 0;
+
+ if (ndd->nsarea.status || ndd->nsarea.max_xfer == 0) {
+ dev_dbg(ndd->dev, "failed to init config data area: (%u:%u)\n",
+ ndd->nsarea.max_xfer, ndd->nsarea.config_size);
+ return -ENXIO;
+ }
+
+ /*
+ * We need to determine the maximum index area as this is the section
+ * we must read and validate before we can start processing labels.
+ *
+ * If the area is too small to contain the two indexes and 2 labels
+ * then we abort.
+ *
+ * Start at a label size of 128 as this should result in the largest
+ * possible namespace index size.
+ */
+ ndd->nslabel_size = 128;
+ read_size = sizeof_namespace_index(ndd) * 2;
+ if (!read_size)
+ return -ENXIO;
+
+ /* Allocate config data */
+ config_size = ndd->nsarea.config_size;
+ ndd->data = kvzalloc(config_size, GFP_KERNEL);
+ if (!ndd->data)
+ return -ENOMEM;
+
+ /*
+ * We want to guarantee as few reads as possible while conserving
+ * memory. To do that we figure out how much unused space will be left
+ * in the last read, divide that by the total number of reads it is
+ * going to take given our maximum transfer size, and then reduce our
+ * maximum transfer size based on that result.
+ */
+ max_xfer = min_t(size_t, ndd->nsarea.max_xfer, config_size);
+ if (read_size < max_xfer) {
+ /* trim waste */
+ max_xfer -= ((max_xfer - 1) - (config_size - 1) % max_xfer) /
+ DIV_ROUND_UP(config_size, max_xfer);
+ /* make certain we read indexes in exactly 1 read */
+ if (max_xfer < read_size)
+ max_xfer = read_size;
+ }
+
+ /* Make our initial read size a multiple of max_xfer size */
+ read_size = min(DIV_ROUND_UP(read_size, max_xfer) * max_xfer,
+ config_size);
+
+ /* Read the index data */
+ rc = nvdimm_get_config_data(ndd, ndd->data, 0, read_size);
+ if (rc)
+ goto out_err;
+
+ /* Validate index data, if not valid assume all labels are invalid */
+ ndd->ns_current = nd_label_validate(ndd);
+ if (ndd->ns_current < 0)
+ return 0;
+
+ /* Record our index values */
+ ndd->ns_next = nd_label_next_nsindex(ndd->ns_current);
+
+ /* Copy "current" index on top of the "next" index */
+ nsindex = to_current_namespace_index(ndd);
+ nd_label_copy(ndd, to_next_namespace_index(ndd), nsindex);
+
+ /* Determine starting offset for label data */
+ offset = __le64_to_cpu(nsindex->labeloff);
+ nslot = __le32_to_cpu(nsindex->nslot);
+
+ /* Loop through the free list pulling in any active labels */
+ for (i = 0; i < nslot; i++, offset += ndd->nslabel_size) {
+ size_t label_read_size;
+
+ /* zero out the unused labels */
+ if (test_bit_le(i, nsindex->free)) {
+ memset(ndd->data + offset, 0, ndd->nslabel_size);
+ continue;
+ }
+
+ /* if we already read past here then just continue */
+ if (offset + ndd->nslabel_size <= read_size)
+ continue;
+
+ /* if we haven't read in a while reset our read_size offset */
+ if (read_size < offset)
+ read_size = offset;
+
+ /* determine how much more will be read after this next call. */
+ label_read_size = offset + ndd->nslabel_size - read_size;
+ label_read_size = DIV_ROUND_UP(label_read_size, max_xfer) *
+ max_xfer;
+
+ /* truncate last read if needed */
+ if (read_size + label_read_size > config_size)
+ label_read_size = config_size - read_size;
+
+ /* Read the label data */
+ rc = nvdimm_get_config_data(ndd, ndd->data + read_size,
+ read_size, label_read_size);
+ if (rc)
+ goto out_err;
+
+ /* push read_size to next read offset */
+ read_size += label_read_size;
+ }
+
+ dev_dbg(ndd->dev, "len: %zu rc: %d\n", offset, rc);
+out_err:
+ return rc;
+}
+
int nd_label_active_count(struct nvdimm_drvdata *ndd)
{
struct nd_namespace_index *nsindex;
diff --git a/drivers/nvdimm/label.h b/drivers/nvdimm/label.h
index 18bbe183b3a9..e9a2ad3c2150 100644
--- a/drivers/nvdimm/label.h
+++ b/drivers/nvdimm/label.h
@@ -138,9 +138,7 @@ static inline int nd_label_next_nsindex(int index)
}
struct nvdimm_drvdata;
-int nd_label_validate(struct nvdimm_drvdata *ndd);
-void nd_label_copy(struct nvdimm_drvdata *ndd, struct nd_namespace_index *dst,
- struct nd_namespace_index *src);
+int nd_label_data_init(struct nvdimm_drvdata *ndd);
size_t sizeof_namespace_index(struct nvdimm_drvdata *ndd);
int nd_label_active_count(struct nvdimm_drvdata *ndd);
struct nd_namespace_label *nd_label_active(struct nvdimm_drvdata *ndd, int n);
diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c
index 4a4266250c28..681af3a8fd62 100644
--- a/drivers/nvdimm/namespace_devs.c
+++ b/drivers/nvdimm/namespace_devs.c
@@ -2099,7 +2099,6 @@ static struct device *nd_namespace_pmem_create(struct nd_region *nd_region)
return NULL;
}
dev_set_name(dev, "namespace%d.%d", nd_region->id, nspm->id);
- dev->parent = &nd_region->dev;
dev->groups = nd_namespace_attribute_groups;
nd_namespace_pmem_set_resource(nd_region, nspm, 0);
diff --git a/drivers/nvdimm/nd-core.h b/drivers/nvdimm/nd-core.h
index ac68072fb8cd..182258f64417 100644
--- a/drivers/nvdimm/nd-core.h
+++ b/drivers/nvdimm/nd-core.h
@@ -14,7 +14,6 @@
#define __ND_CORE_H__
#include <linux/libnvdimm.h>
#include <linux/device.h>
-#include <linux/libnvdimm.h>
#include <linux/sizes.h>
#include <linux/mutex.h>
#include <linux/nd.h>
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
index 98317e7ce5b5..e79cc8e5c114 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
@@ -241,6 +241,8 @@ struct nvdimm_drvdata *to_ndd(struct nd_mapping *nd_mapping);
int nvdimm_check_config_data(struct device *dev);
int nvdimm_init_nsarea(struct nvdimm_drvdata *ndd);
int nvdimm_init_config_data(struct nvdimm_drvdata *ndd);
+int nvdimm_get_config_data(struct nvdimm_drvdata *ndd, void *buf,
+ size_t offset, size_t len);
int nvdimm_set_config_data(struct nvdimm_drvdata *ndd, size_t offset,
void *buf, size_t len);
long nvdimm_clear_poison(struct device *dev, phys_addr_t phys,
diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c
index 3f7ad5bc443e..24c64090169e 100644
--- a/drivers/nvdimm/pfn_devs.c
+++ b/drivers/nvdimm/pfn_devs.c
@@ -361,6 +361,65 @@ struct device *nd_pfn_create(struct nd_region *nd_region)
return dev;
}
+/*
+ * nd_pfn_clear_memmap_errors() clears any errors in the volatile memmap
+ * space associated with the namespace. If the memmap is set to DRAM, then
+ * this is a no-op. Since the memmap area is freshly initialized during
+ * probe, we have an opportunity to clear any badblocks in this area.
+ */
+static int nd_pfn_clear_memmap_errors(struct nd_pfn *nd_pfn)
+{
+ struct nd_region *nd_region = to_nd_region(nd_pfn->dev.parent);
+ struct nd_namespace_common *ndns = nd_pfn->ndns;
+ void *zero_page = page_address(ZERO_PAGE(0));
+ struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb;
+ int num_bad, meta_num, rc, bb_present;
+ sector_t first_bad, meta_start;
+ struct nd_namespace_io *nsio;
+
+ if (nd_pfn->mode != PFN_MODE_PMEM)
+ return 0;
+
+ nsio = to_nd_namespace_io(&ndns->dev);
+ meta_start = (SZ_4K + sizeof(*pfn_sb)) >> 9;
+ meta_num = (le64_to_cpu(pfn_sb->dataoff) >> 9) - meta_start;
+
+ do {
+ unsigned long zero_len;
+ u64 nsoff;
+
+ bb_present = badblocks_check(&nd_region->bb, meta_start,
+ meta_num, &first_bad, &num_bad);
+ if (bb_present) {
+ dev_dbg(&nd_pfn->dev, "meta: %x badblocks at %lx\n",
+ num_bad, first_bad);
+ nsoff = ALIGN_DOWN((nd_region->ndr_start
+ + (first_bad << 9)) - nsio->res.start,
+ PAGE_SIZE);
+ zero_len = ALIGN(num_bad << 9, PAGE_SIZE);
+ while (zero_len) {
+ unsigned long chunk = min(zero_len, PAGE_SIZE);
+
+ rc = nvdimm_write_bytes(ndns, nsoff, zero_page,
+ chunk, 0);
+ if (rc)
+ break;
+
+ zero_len -= chunk;
+ nsoff += chunk;
+ }
+ if (rc) {
+ dev_err(&nd_pfn->dev,
+ "error clearing %x badblocks at %lx\n",
+ num_bad, first_bad);
+ return rc;
+ }
+ }
+ } while (bb_present);
+
+ return 0;
+}
+
int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig)
{
u64 checksum, offset;
@@ -477,7 +536,7 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig)
return -ENXIO;
}
- return 0;
+ return nd_pfn_clear_memmap_errors(nd_pfn);
}
EXPORT_SYMBOL(nd_pfn_validate);
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
index 6071e2942053..0e39e3d1846f 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
@@ -421,9 +421,11 @@ static int pmem_attach_disk(struct device *dev,
addr = devm_memremap_pages(dev, &pmem->pgmap);
pmem->pfn_flags |= PFN_MAP;
memcpy(&bb_res, &pmem->pgmap.res, sizeof(bb_res));
- } else
+ } else {
addr = devm_memremap(dev, pmem->phys_addr,
pmem->size, ARCH_MEMREMAP_PMEM);
+ memcpy(&bb_res, &nsio->res, sizeof(bb_res));
+ }
/*
* At release time the queue must be frozen before
@@ -474,7 +476,7 @@ static int pmem_attach_disk(struct device *dev,
gendev = disk_to_dev(disk);
gendev->groups = pmem_attribute_groups;
- device_add_disk(dev, disk);
+ device_add_disk(dev, disk, NULL);
if (devm_add_action_or_reset(dev, pmem_release_disk, pmem))
return -ENOMEM;
diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c
index fa37afcd43ff..174a418cb171 100644
--- a/drivers/nvdimm/region_devs.c
+++ b/drivers/nvdimm/region_devs.c
@@ -560,10 +560,17 @@ static ssize_t region_badblocks_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct nd_region *nd_region = to_nd_region(dev);
+ ssize_t rc;
- return badblocks_show(&nd_region->bb, buf, 0);
-}
+ device_lock(dev);
+ if (dev->driver)
+ rc = badblocks_show(&nd_region->bb, buf, 0);
+ else
+ rc = -ENXIO;
+ device_unlock(dev);
+ return rc;
+}
static DEVICE_ATTR(badblocks, 0444, region_badblocks_show, NULL);
static ssize_t resource_show(struct device *dev,
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index dd8ec1dd9219..559d567693b8 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -971,7 +971,7 @@ static int nvme_identify_ns_descs(struct nvme_ctrl *ctrl, unsigned nsid,
uuid_copy(&ids->uuid, data + pos + sizeof(*cur));
break;
default:
- /* Skip unnkown types */
+ /* Skip unknown types */
len = cur->nidl;
break;
}
@@ -1132,7 +1132,7 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
return nvme_submit_user_cmd(ns->queue, &c,
(void __user *)(uintptr_t)io.addr, length,
- metadata, meta_len, io.slba, NULL, 0);
+ metadata, meta_len, lower_32_bits(io.slba), NULL, 0);
}
static u32 nvme_known_admin_effects(u8 opcode)
@@ -1519,8 +1519,10 @@ static void __nvme_revalidate_disk(struct gendisk *disk, struct nvme_id_ns *id)
if (ns->ndev)
nvme_nvm_update_nvm_info(ns);
#ifdef CONFIG_NVME_MULTIPATH
- if (ns->head->disk)
+ if (ns->head->disk) {
nvme_update_disk_info(ns->head->disk, ns, id);
+ blk_queue_stack_limits(ns->head->disk->queue, ns->queue);
+ }
#endif
}
@@ -2076,7 +2078,7 @@ static void nvme_init_subnqn(struct nvme_subsystem *subsys, struct nvme_ctrl *ct
nqnlen = strnlen(id->subnqn, NVMF_NQN_SIZE);
if (nqnlen > 0 && nqnlen < NVMF_NQN_SIZE) {
- strncpy(subsys->subnqn, id->subnqn, NVMF_NQN_SIZE);
+ strlcpy(subsys->subnqn, id->subnqn, NVMF_NQN_SIZE);
return;
}
@@ -2729,11 +2731,19 @@ static umode_t nvme_ns_id_attrs_are_visible(struct kobject *kobj,
return a->mode;
}
-const struct attribute_group nvme_ns_id_attr_group = {
+static const struct attribute_group nvme_ns_id_attr_group = {
.attrs = nvme_ns_id_attrs,
.is_visible = nvme_ns_id_attrs_are_visible,
};
+const struct attribute_group *nvme_ns_id_attr_groups[] = {
+ &nvme_ns_id_attr_group,
+#ifdef CONFIG_NVM
+ &nvme_nvm_attr_group,
+#endif
+ NULL,
+};
+
#define nvme_show_str_function(field) \
static ssize_t field##_show(struct device *dev, \
struct device_attribute *attr, char *buf) \
@@ -2900,9 +2910,14 @@ static struct nvme_ns_head *nvme_alloc_ns_head(struct nvme_ctrl *ctrl,
unsigned nsid, struct nvme_id_ns *id)
{
struct nvme_ns_head *head;
+ size_t size = sizeof(*head);
int ret = -ENOMEM;
- head = kzalloc(sizeof(*head), GFP_KERNEL);
+#ifdef CONFIG_NVME_MULTIPATH
+ size += num_possible_nodes() * sizeof(struct nvme_ns *);
+#endif
+
+ head = kzalloc(size, GFP_KERNEL);
if (!head)
goto out;
ret = ida_simple_get(&ctrl->subsys->ns_ida, 1, 0, GFP_KERNEL);
@@ -3051,7 +3066,11 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
ns->queue = blk_mq_init_queue(ctrl->tagset);
if (IS_ERR(ns->queue))
goto out_free_ns;
+
blk_queue_flag_set(QUEUE_FLAG_NONROT, ns->queue);
+ if (ctrl->ops->flags & NVME_F_PCI_P2PDMA)
+ blk_queue_flag_set(QUEUE_FLAG_PCI_P2PDMA, ns->queue);
+
ns->queue->queuedata = ns;
ns->ctrl = ctrl;
@@ -3099,14 +3118,7 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
nvme_get_ctrl(ctrl);
- device_add_disk(ctrl->device, ns->disk);
- if (sysfs_create_group(&disk_to_dev(ns->disk)->kobj,
- &nvme_ns_id_attr_group))
- pr_warn("%s: failed to create sysfs group for identification\n",
- ns->disk->disk_name);
- if (ns->ndev && nvme_nvm_register_sysfs(ns))
- pr_warn("%s: failed to register lightnvm sysfs group for identification\n",
- ns->disk->disk_name);
+ device_add_disk(ctrl->device, ns->disk, nvme_ns_id_attr_groups);
nvme_mpath_add_disk(ns, id);
nvme_fault_inject_init(ns);
@@ -3132,10 +3144,6 @@ static void nvme_ns_remove(struct nvme_ns *ns)
nvme_fault_inject_fini(ns);
if (ns->disk && ns->disk->flags & GENHD_FL_UP) {
- sysfs_remove_group(&disk_to_dev(ns->disk)->kobj,
- &nvme_ns_id_attr_group);
- if (ns->ndev)
- nvme_nvm_unregister_sysfs(ns);
del_gendisk(ns->disk);
blk_cleanup_queue(ns->queue);
if (blk_get_integrity(ns->disk))
@@ -3143,8 +3151,8 @@ static void nvme_ns_remove(struct nvme_ns *ns)
}
mutex_lock(&ns->ctrl->subsys->lock);
- nvme_mpath_clear_current_path(ns);
list_del_rcu(&ns->siblings);
+ nvme_mpath_clear_current_path(ns);
mutex_unlock(&ns->ctrl->subsys->lock);
down_write(&ns->ctrl->namespaces_rwsem);
@@ -3411,16 +3419,21 @@ static void nvme_fw_act_work(struct work_struct *work)
static void nvme_handle_aen_notice(struct nvme_ctrl *ctrl, u32 result)
{
- switch ((result & 0xff00) >> 8) {
+ u32 aer_notice_type = (result & 0xff00) >> 8;
+
+ switch (aer_notice_type) {
case NVME_AER_NOTICE_NS_CHANGED:
+ trace_nvme_async_event(ctrl, aer_notice_type);
set_bit(NVME_AER_NOTICE_NS_CHANGED, &ctrl->events);
nvme_queue_scan(ctrl);
break;
case NVME_AER_NOTICE_FW_ACT_STARTING:
+ trace_nvme_async_event(ctrl, aer_notice_type);
queue_work(nvme_wq, &ctrl->fw_act_work);
break;
#ifdef CONFIG_NVME_MULTIPATH
case NVME_AER_NOTICE_ANA:
+ trace_nvme_async_event(ctrl, aer_notice_type);
if (!ctrl->ana_log_buf)
break;
queue_work(nvme_wq, &ctrl->ana_work);
@@ -3435,11 +3448,12 @@ void nvme_complete_async_event(struct nvme_ctrl *ctrl, __le16 status,
volatile union nvme_result *res)
{
u32 result = le32_to_cpu(res->u32);
+ u32 aer_type = result & 0x07;
if (le16_to_cpu(status) >> 1 != NVME_SC_SUCCESS)
return;
- switch (result & 0x7) {
+ switch (aer_type) {
case NVME_AER_NOTICE:
nvme_handle_aen_notice(ctrl, result);
break;
@@ -3447,6 +3461,7 @@ void nvme_complete_async_event(struct nvme_ctrl *ctrl, __le16 status,
case NVME_AER_SMART:
case NVME_AER_CSS:
case NVME_AER_VS:
+ trace_nvme_async_event(ctrl, aer_type);
ctrl->aen_result = result;
break;
default:
diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c
index 206d63cb1afc..bd0969db6225 100644
--- a/drivers/nvme/host/fabrics.c
+++ b/drivers/nvme/host/fabrics.c
@@ -552,8 +552,11 @@ blk_status_t nvmf_fail_nonready_command(struct nvme_ctrl *ctrl,
ctrl->state != NVME_CTRL_DEAD &&
!blk_noretry_request(rq) && !(rq->cmd_flags & REQ_NVME_MPATH))
return BLK_STS_RESOURCE;
- nvme_req(rq)->status = NVME_SC_ABORT_REQ;
- return BLK_STS_IOERR;
+
+ nvme_req(rq)->status = NVME_SC_HOST_PATH_ERROR;
+ blk_mq_start_request(rq);
+ nvme_complete_rq(rq);
+ return BLK_STS_OK;
}
EXPORT_SYMBOL_GPL(nvmf_fail_nonready_command);
@@ -865,6 +868,36 @@ static int nvmf_check_required_opts(struct nvmf_ctrl_options *opts,
return 0;
}
+bool nvmf_ip_options_match(struct nvme_ctrl *ctrl,
+ struct nvmf_ctrl_options *opts)
+{
+ if (!nvmf_ctlr_matches_baseopts(ctrl, opts) ||
+ strcmp(opts->traddr, ctrl->opts->traddr) ||
+ strcmp(opts->trsvcid, ctrl->opts->trsvcid))
+ return false;
+
+ /*
+ * Checking the local address is rough. In most cases, none is specified
+ * and the host port is selected by the stack.
+ *
+ * Assume no match if:
+ * - local address is specified and address is not the same
+ * - local address is not specified but remote is, or vice versa
+ * (admin using specific host_traddr when it matters).
+ */
+ if ((opts->mask & NVMF_OPT_HOST_TRADDR) &&
+ (ctrl->opts->mask & NVMF_OPT_HOST_TRADDR)) {
+ if (strcmp(opts->host_traddr, ctrl->opts->host_traddr))
+ return false;
+ } else if ((opts->mask & NVMF_OPT_HOST_TRADDR) ||
+ (ctrl->opts->mask & NVMF_OPT_HOST_TRADDR)) {
+ return false;
+ }
+
+ return true;
+}
+EXPORT_SYMBOL_GPL(nvmf_ip_options_match);
+
static int nvmf_check_allowed_opts(struct nvmf_ctrl_options *opts,
unsigned int allowed_opts)
{
diff --git a/drivers/nvme/host/fabrics.h b/drivers/nvme/host/fabrics.h
index aa2fdb2a2e8f..6ea6275f332a 100644
--- a/drivers/nvme/host/fabrics.h
+++ b/drivers/nvme/host/fabrics.h
@@ -166,6 +166,8 @@ blk_status_t nvmf_fail_nonready_command(struct nvme_ctrl *ctrl,
struct request *rq);
bool __nvmf_check_ready(struct nvme_ctrl *ctrl, struct request *rq,
bool queue_live);
+bool nvmf_ip_options_match(struct nvme_ctrl *ctrl,
+ struct nvmf_ctrl_options *opts);
static inline bool nvmf_check_ready(struct nvme_ctrl *ctrl, struct request *rq,
bool queue_live)
diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c
index 611e70cae754..0b70c8bab045 100644
--- a/drivers/nvme/host/fc.c
+++ b/drivers/nvme/host/fc.c
@@ -20,6 +20,7 @@
#include <uapi/scsi/fc/fc_fs.h>
#include <uapi/scsi/fc/fc_els.h>
#include <linux/delay.h>
+#include <linux/overflow.h>
#include "nvme.h"
#include "fabrics.h"
@@ -104,6 +105,12 @@ struct nvme_fc_fcp_op {
struct nvme_fc_ersp_iu rsp_iu;
};
+struct nvme_fcp_op_w_sgl {
+ struct nvme_fc_fcp_op op;
+ struct scatterlist sgl[SG_CHUNK_SIZE];
+ uint8_t priv[0];
+};
+
struct nvme_fc_lport {
struct nvme_fc_local_port localport;
@@ -122,6 +129,7 @@ struct nvme_fc_rport {
struct list_head endp_list; /* for lport->endp_list */
struct list_head ctrl_list;
struct list_head ls_req_list;
+ struct list_head disc_list;
struct device *dev; /* physical device for dma */
struct nvme_fc_lport *lport;
spinlock_t lock;
@@ -210,7 +218,6 @@ static DEFINE_IDA(nvme_fc_ctrl_cnt);
* These items are short-term. They will eventually be moved into
* a generic FC class. See comments in module init.
*/
-static struct class *fc_class;
static struct device *fc_udev_device;
@@ -317,7 +324,7 @@ out_done:
* @template: LLDD entrypoints and operational parameters for the port
* @dev: physical hardware device node port corresponds to. Will be
* used for DMA mappings
- * @lport_p: pointer to a local port pointer. Upon success, the routine
+ * @portptr: pointer to a local port pointer. Upon success, the routine
* will allocate a nvme_fc_local_port structure and place its
* address in the local port pointer. Upon failure, local port
* pointer will be set to 0.
@@ -425,8 +432,7 @@ EXPORT_SYMBOL_GPL(nvme_fc_register_localport);
* nvme_fc_unregister_localport - transport entry point called by an
* LLDD to deregister/remove a previously
* registered a NVME host FC port.
- * @localport: pointer to the (registered) local port that is to be
- * deregistered.
+ * @portptr: pointer to the (registered) local port that is to be deregistered.
*
* Returns:
* a completion status. Must be 0 upon success; a negative errno
@@ -507,6 +513,7 @@ nvme_fc_free_rport(struct kref *ref)
list_del(&rport->endp_list);
spin_unlock_irqrestore(&nvme_fc_lock, flags);
+ WARN_ON(!list_empty(&rport->disc_list));
ida_simple_remove(&lport->endp_cnt, rport->remoteport.port_num);
kfree(rport);
@@ -631,7 +638,7 @@ __nvme_fc_set_dev_loss_tmo(struct nvme_fc_rport *rport,
* @localport: pointer to the (registered) local port that the remote
* subsystem port is connected to.
* @pinfo: pointer to information about the port to be registered
- * @rport_p: pointer to a remote port pointer. Upon success, the routine
+ * @portptr: pointer to a remote port pointer. Upon success, the routine
* will allocate a nvme_fc_remote_port structure and place its
* address in the remote port pointer. Upon failure, remote port
* pointer will be set to 0.
@@ -694,6 +701,7 @@ nvme_fc_register_remoteport(struct nvme_fc_local_port *localport,
INIT_LIST_HEAD(&newrec->endp_list);
INIT_LIST_HEAD(&newrec->ctrl_list);
INIT_LIST_HEAD(&newrec->ls_req_list);
+ INIT_LIST_HEAD(&newrec->disc_list);
kref_init(&newrec->ref);
atomic_set(&newrec->act_ctrl_cnt, 0);
spin_lock_init(&newrec->lock);
@@ -807,8 +815,8 @@ nvme_fc_ctrl_connectivity_loss(struct nvme_fc_ctrl *ctrl)
* nvme_fc_unregister_remoteport - transport entry point called by an
* LLDD to deregister/remove a previously
* registered a NVME subsystem FC port.
- * @remoteport: pointer to the (registered) remote port that is to be
- * deregistered.
+ * @portptr: pointer to the (registered) remote port that is to be
+ * deregistered.
*
* Returns:
* a completion status. Must be 0 upon success; a negative errno
@@ -1385,7 +1393,7 @@ nvme_fc_disconnect_assoc_done(struct nvmefc_ls_req *lsreq, int status)
__nvme_fc_finish_ls_req(lsop);
- /* fc-nvme iniator doesn't care about success or failure of cmd */
+ /* fc-nvme initiator doesn't care about success or failure of cmd */
kfree(lsop);
}
@@ -1685,6 +1693,8 @@ __nvme_fc_init_request(struct nvme_fc_ctrl *ctrl,
struct nvme_fc_queue *queue, struct nvme_fc_fcp_op *op,
struct request *rq, u32 rqno)
{
+ struct nvme_fcp_op_w_sgl *op_w_sgl =
+ container_of(op, typeof(*op_w_sgl), op);
struct nvme_fc_cmd_iu *cmdiu = &op->cmd_iu;
int ret = 0;
@@ -1694,8 +1704,6 @@ __nvme_fc_init_request(struct nvme_fc_ctrl *ctrl,
op->fcp_req.rspaddr = &op->rsp_iu;
op->fcp_req.rsplen = sizeof(op->rsp_iu);
op->fcp_req.done = nvme_fc_fcpio_done;
- op->fcp_req.first_sgl = (struct scatterlist *)&op[1];
- op->fcp_req.private = &op->fcp_req.first_sgl[SG_CHUNK_SIZE];
op->ctrl = ctrl;
op->queue = queue;
op->rq = rq;
@@ -1733,12 +1741,18 @@ nvme_fc_init_request(struct blk_mq_tag_set *set, struct request *rq,
unsigned int hctx_idx, unsigned int numa_node)
{
struct nvme_fc_ctrl *ctrl = set->driver_data;
- struct nvme_fc_fcp_op *op = blk_mq_rq_to_pdu(rq);
+ struct nvme_fcp_op_w_sgl *op = blk_mq_rq_to_pdu(rq);
int queue_idx = (set == &ctrl->tag_set) ? hctx_idx + 1 : 0;
struct nvme_fc_queue *queue = &ctrl->queues[queue_idx];
+ int res;
nvme_req(rq)->ctrl = &ctrl->ctrl;
- return __nvme_fc_init_request(ctrl, queue, op, rq, queue->rqcnt++);
+ res = __nvme_fc_init_request(ctrl, queue, &op->op, rq, queue->rqcnt++);
+ if (res)
+ return res;
+ op->op.fcp_req.first_sgl = &op->sgl[0];
+ op->op.fcp_req.private = &op->priv[0];
+ return res;
}
static int
@@ -1768,7 +1782,6 @@ nvme_fc_init_aen_ops(struct nvme_fc_ctrl *ctrl)
}
aen_op->flags = FCOP_FLAGS_AEN;
- aen_op->fcp_req.first_sgl = NULL; /* no sg list */
aen_op->fcp_req.private = private;
memset(sqe, 0, sizeof(*sqe));
@@ -2422,10 +2435,9 @@ nvme_fc_create_io_queues(struct nvme_fc_ctrl *ctrl)
ctrl->tag_set.reserved_tags = 1; /* fabric connect */
ctrl->tag_set.numa_node = NUMA_NO_NODE;
ctrl->tag_set.flags = BLK_MQ_F_SHOULD_MERGE;
- ctrl->tag_set.cmd_size = sizeof(struct nvme_fc_fcp_op) +
- (SG_CHUNK_SIZE *
- sizeof(struct scatterlist)) +
- ctrl->lport->ops->fcprqst_priv_sz;
+ ctrl->tag_set.cmd_size =
+ struct_size((struct nvme_fcp_op_w_sgl *)NULL, priv,
+ ctrl->lport->ops->fcprqst_priv_sz);
ctrl->tag_set.driver_data = ctrl;
ctrl->tag_set.nr_hw_queues = ctrl->ctrl.queue_count - 1;
ctrl->tag_set.timeout = NVME_IO_TIMEOUT;
@@ -3027,10 +3039,9 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts,
ctrl->admin_tag_set.queue_depth = NVME_AQ_MQ_TAG_DEPTH;
ctrl->admin_tag_set.reserved_tags = 2; /* fabric connect + Keep-Alive */
ctrl->admin_tag_set.numa_node = NUMA_NO_NODE;
- ctrl->admin_tag_set.cmd_size = sizeof(struct nvme_fc_fcp_op) +
- (SG_CHUNK_SIZE *
- sizeof(struct scatterlist)) +
- ctrl->lport->ops->fcprqst_priv_sz;
+ ctrl->admin_tag_set.cmd_size =
+ struct_size((struct nvme_fcp_op_w_sgl *)NULL, priv,
+ ctrl->lport->ops->fcprqst_priv_sz);
ctrl->admin_tag_set.driver_data = ctrl;
ctrl->admin_tag_set.nr_hw_queues = 1;
ctrl->admin_tag_set.timeout = ADMIN_TIMEOUT;
@@ -3159,7 +3170,7 @@ nvme_fc_parse_traddr(struct nvmet_fc_traddr *traddr, char *buf, size_t blen)
substring_t wwn = { name, &name[sizeof(name)-1] };
int nnoffset, pnoffset;
- /* validate it string one of the 2 allowed formats */
+ /* validate if string is one of the 2 allowed formats */
if (strnlen(buf, blen) == NVME_FC_TRADDR_MAXLENGTH &&
!strncmp(buf, "nn-0x", NVME_FC_TRADDR_OXNNLEN) &&
!strncmp(&buf[NVME_FC_TRADDR_MAX_PN_OFFSET],
@@ -3254,6 +3265,90 @@ static struct nvmf_transport_ops nvme_fc_transport = {
.create_ctrl = nvme_fc_create_ctrl,
};
+/* Arbitrary successive failures max. With lots of subsystems could be high */
+#define DISCOVERY_MAX_FAIL 20
+
+static ssize_t nvme_fc_nvme_discovery_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ unsigned long flags;
+ LIST_HEAD(local_disc_list);
+ struct nvme_fc_lport *lport;
+ struct nvme_fc_rport *rport;
+ int failcnt = 0;
+
+ spin_lock_irqsave(&nvme_fc_lock, flags);
+restart:
+ list_for_each_entry(lport, &nvme_fc_lport_list, port_list) {
+ list_for_each_entry(rport, &lport->endp_list, endp_list) {
+ if (!nvme_fc_lport_get(lport))
+ continue;
+ if (!nvme_fc_rport_get(rport)) {
+ /*
+ * This is a temporary condition. Upon restart
+ * this rport will be gone from the list.
+ *
+ * Revert the lport put and retry. Anything
+ * added to the list already will be skipped (as
+ * they are no longer list_empty). Loops should
+ * resume at rports that were not yet seen.
+ */
+ nvme_fc_lport_put(lport);
+
+ if (failcnt++ < DISCOVERY_MAX_FAIL)
+ goto restart;
+
+ pr_err("nvme_discovery: too many reference "
+ "failures\n");
+ goto process_local_list;
+ }
+ if (list_empty(&rport->disc_list))
+ list_add_tail(&rport->disc_list,
+ &local_disc_list);
+ }
+ }
+
+process_local_list:
+ while (!list_empty(&local_disc_list)) {
+ rport = list_first_entry(&local_disc_list,
+ struct nvme_fc_rport, disc_list);
+ list_del_init(&rport->disc_list);
+ spin_unlock_irqrestore(&nvme_fc_lock, flags);
+
+ lport = rport->lport;
+ /* signal discovery. Won't hurt if it repeats */
+ nvme_fc_signal_discovery_scan(lport, rport);
+ nvme_fc_rport_put(rport);
+ nvme_fc_lport_put(lport);
+
+ spin_lock_irqsave(&nvme_fc_lock, flags);
+ }
+ spin_unlock_irqrestore(&nvme_fc_lock, flags);
+
+ return count;
+}
+static DEVICE_ATTR(nvme_discovery, 0200, NULL, nvme_fc_nvme_discovery_store);
+
+static struct attribute *nvme_fc_attrs[] = {
+ &dev_attr_nvme_discovery.attr,
+ NULL
+};
+
+static struct attribute_group nvme_fc_attr_group = {
+ .attrs = nvme_fc_attrs,
+};
+
+static const struct attribute_group *nvme_fc_attr_groups[] = {
+ &nvme_fc_attr_group,
+ NULL
+};
+
+static struct class fc_class = {
+ .name = "fc",
+ .dev_groups = nvme_fc_attr_groups,
+ .owner = THIS_MODULE,
+};
+
static int __init nvme_fc_init_module(void)
{
int ret;
@@ -3272,16 +3367,16 @@ static int __init nvme_fc_init_module(void)
* put in place, this code will move to a more generic
* location for the class.
*/
- fc_class = class_create(THIS_MODULE, "fc");
- if (IS_ERR(fc_class)) {
+ ret = class_register(&fc_class);
+ if (ret) {
pr_err("couldn't register class fc\n");
- return PTR_ERR(fc_class);
+ return ret;
}
/*
* Create a device for the FC-centric udev events
*/
- fc_udev_device = device_create(fc_class, NULL, MKDEV(0, 0), NULL,
+ fc_udev_device = device_create(&fc_class, NULL, MKDEV(0, 0), NULL,
"fc_udev_device");
if (IS_ERR(fc_udev_device)) {
pr_err("couldn't create fc_udev device!\n");
@@ -3296,9 +3391,9 @@ static int __init nvme_fc_init_module(void)
return 0;
out_destroy_device:
- device_destroy(fc_class, MKDEV(0, 0));
+ device_destroy(&fc_class, MKDEV(0, 0));
out_destroy_class:
- class_destroy(fc_class);
+ class_unregister(&fc_class);
return ret;
}
@@ -3313,8 +3408,8 @@ static void __exit nvme_fc_exit_module(void)
ida_destroy(&nvme_fc_local_port_cnt);
ida_destroy(&nvme_fc_ctrl_cnt);
- device_destroy(fc_class, MKDEV(0, 0));
- class_destroy(fc_class);
+ device_destroy(&fc_class, MKDEV(0, 0));
+ class_unregister(&fc_class);
}
module_init(nvme_fc_init_module);
diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
index 6fe5923c95d4..a4f3b263cd6c 100644
--- a/drivers/nvme/host/lightnvm.c
+++ b/drivers/nvme/host/lightnvm.c
@@ -567,13 +567,13 @@ static int nvme_nvm_set_bb_tbl(struct nvm_dev *nvmdev, struct ppa_addr *ppas,
* Expect the lba in device format
*/
static int nvme_nvm_get_chk_meta(struct nvm_dev *ndev,
- struct nvm_chk_meta *meta,
- sector_t slba, int nchks)
+ sector_t slba, int nchks,
+ struct nvm_chk_meta *meta)
{
struct nvm_geo *geo = &ndev->geo;
struct nvme_ns *ns = ndev->q->queuedata;
struct nvme_ctrl *ctrl = ns->ctrl;
- struct nvme_nvm_chk_meta *dev_meta = (struct nvme_nvm_chk_meta *)meta;
+ struct nvme_nvm_chk_meta *dev_meta, *dev_meta_off;
struct ppa_addr ppa;
size_t left = nchks * sizeof(struct nvme_nvm_chk_meta);
size_t log_pos, offset, len;
@@ -585,6 +585,10 @@ static int nvme_nvm_get_chk_meta(struct nvm_dev *ndev,
*/
max_len = min_t(unsigned int, ctrl->max_hw_sectors << 9, 256 * 1024);
+ dev_meta = kmalloc(max_len, GFP_KERNEL);
+ if (!dev_meta)
+ return -ENOMEM;
+
/* Normalize lba address space to obtain log offset */
ppa.ppa = slba;
ppa = dev_to_generic_addr(ndev, ppa);
@@ -598,6 +602,9 @@ static int nvme_nvm_get_chk_meta(struct nvm_dev *ndev,
while (left) {
len = min_t(unsigned int, left, max_len);
+ memset(dev_meta, 0, max_len);
+ dev_meta_off = dev_meta;
+
ret = nvme_get_log(ctrl, ns->head->ns_id,
NVME_NVM_LOG_REPORT_CHUNK, 0, dev_meta, len,
offset);
@@ -607,21 +614,23 @@ static int nvme_nvm_get_chk_meta(struct nvm_dev *ndev,
}
for (i = 0; i < len; i += sizeof(struct nvme_nvm_chk_meta)) {
- meta->state = dev_meta->state;
- meta->type = dev_meta->type;
- meta->wi = dev_meta->wi;
- meta->slba = le64_to_cpu(dev_meta->slba);
- meta->cnlb = le64_to_cpu(dev_meta->cnlb);
- meta->wp = le64_to_cpu(dev_meta->wp);
+ meta->state = dev_meta_off->state;
+ meta->type = dev_meta_off->type;
+ meta->wi = dev_meta_off->wi;
+ meta->slba = le64_to_cpu(dev_meta_off->slba);
+ meta->cnlb = le64_to_cpu(dev_meta_off->cnlb);
+ meta->wp = le64_to_cpu(dev_meta_off->wp);
meta++;
- dev_meta++;
+ dev_meta_off++;
}
offset += len;
left -= len;
}
+ kfree(dev_meta);
+
return ret;
}
@@ -968,6 +977,9 @@ void nvme_nvm_update_nvm_info(struct nvme_ns *ns)
struct nvm_dev *ndev = ns->ndev;
struct nvm_geo *geo = &ndev->geo;
+ if (geo->version == NVM_OCSSD_SPEC_12)
+ return;
+
geo->csecs = 1 << ns->lba_shift;
geo->sos = ns->ms;
}
@@ -1190,10 +1202,29 @@ static NVM_DEV_ATTR_12_RO(multiplane_modes);
static NVM_DEV_ATTR_12_RO(media_capabilities);
static NVM_DEV_ATTR_12_RO(max_phys_secs);
-static struct attribute *nvm_dev_attrs_12[] = {
+/* 2.0 values */
+static NVM_DEV_ATTR_20_RO(groups);
+static NVM_DEV_ATTR_20_RO(punits);
+static NVM_DEV_ATTR_20_RO(chunks);
+static NVM_DEV_ATTR_20_RO(clba);
+static NVM_DEV_ATTR_20_RO(ws_min);
+static NVM_DEV_ATTR_20_RO(ws_opt);
+static NVM_DEV_ATTR_20_RO(maxoc);
+static NVM_DEV_ATTR_20_RO(maxocpu);
+static NVM_DEV_ATTR_20_RO(mw_cunits);
+static NVM_DEV_ATTR_20_RO(write_typ);
+static NVM_DEV_ATTR_20_RO(write_max);
+static NVM_DEV_ATTR_20_RO(reset_typ);
+static NVM_DEV_ATTR_20_RO(reset_max);
+
+static struct attribute *nvm_dev_attrs[] = {
+ /* version agnostic attrs */
&dev_attr_version.attr,
&dev_attr_capabilities.attr,
+ &dev_attr_read_typ.attr,
+ &dev_attr_read_max.attr,
+ /* 1.2 attrs */
&dev_attr_vendor_opcode.attr,
&dev_attr_device_mode.attr,
&dev_attr_media_manager.attr,
@@ -1208,8 +1239,6 @@ static struct attribute *nvm_dev_attrs_12[] = {
&dev_attr_page_size.attr,
&dev_attr_hw_sector_size.attr,
&dev_attr_oob_sector_size.attr,
- &dev_attr_read_typ.attr,
- &dev_attr_read_max.attr,
&dev_attr_prog_typ.attr,
&dev_attr_prog_max.attr,
&dev_attr_erase_typ.attr,
@@ -1218,33 +1247,7 @@ static struct attribute *nvm_dev_attrs_12[] = {
&dev_attr_media_capabilities.attr,
&dev_attr_max_phys_secs.attr,
- NULL,
-};
-
-static const struct attribute_group nvm_dev_attr_group_12 = {
- .name = "lightnvm",
- .attrs = nvm_dev_attrs_12,
-};
-
-/* 2.0 values */
-static NVM_DEV_ATTR_20_RO(groups);
-static NVM_DEV_ATTR_20_RO(punits);
-static NVM_DEV_ATTR_20_RO(chunks);
-static NVM_DEV_ATTR_20_RO(clba);
-static NVM_DEV_ATTR_20_RO(ws_min);
-static NVM_DEV_ATTR_20_RO(ws_opt);
-static NVM_DEV_ATTR_20_RO(maxoc);
-static NVM_DEV_ATTR_20_RO(maxocpu);
-static NVM_DEV_ATTR_20_RO(mw_cunits);
-static NVM_DEV_ATTR_20_RO(write_typ);
-static NVM_DEV_ATTR_20_RO(write_max);
-static NVM_DEV_ATTR_20_RO(reset_typ);
-static NVM_DEV_ATTR_20_RO(reset_max);
-
-static struct attribute *nvm_dev_attrs_20[] = {
- &dev_attr_version.attr,
- &dev_attr_capabilities.attr,
-
+ /* 2.0 attrs */
&dev_attr_groups.attr,
&dev_attr_punits.attr,
&dev_attr_chunks.attr,
@@ -1255,8 +1258,6 @@ static struct attribute *nvm_dev_attrs_20[] = {
&dev_attr_maxocpu.attr,
&dev_attr_mw_cunits.attr,
- &dev_attr_read_typ.attr,
- &dev_attr_read_max.attr,
&dev_attr_write_typ.attr,
&dev_attr_write_max.attr,
&dev_attr_reset_typ.attr,
@@ -1265,44 +1266,38 @@ static struct attribute *nvm_dev_attrs_20[] = {
NULL,
};
-static const struct attribute_group nvm_dev_attr_group_20 = {
- .name = "lightnvm",
- .attrs = nvm_dev_attrs_20,
-};
-
-int nvme_nvm_register_sysfs(struct nvme_ns *ns)
+static umode_t nvm_dev_attrs_visible(struct kobject *kobj,
+ struct attribute *attr, int index)
{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct gendisk *disk = dev_to_disk(dev);
+ struct nvme_ns *ns = disk->private_data;
struct nvm_dev *ndev = ns->ndev;
- struct nvm_geo *geo = &ndev->geo;
+ struct device_attribute *dev_attr =
+ container_of(attr, typeof(*dev_attr), attr);
if (!ndev)
- return -EINVAL;
-
- switch (geo->major_ver_id) {
- case 1:
- return sysfs_create_group(&disk_to_dev(ns->disk)->kobj,
- &nvm_dev_attr_group_12);
- case 2:
- return sysfs_create_group(&disk_to_dev(ns->disk)->kobj,
- &nvm_dev_attr_group_20);
- }
+ return 0;
- return -EINVAL;
-}
+ if (dev_attr->show == nvm_dev_attr_show)
+ return attr->mode;
-void nvme_nvm_unregister_sysfs(struct nvme_ns *ns)
-{
- struct nvm_dev *ndev = ns->ndev;
- struct nvm_geo *geo = &ndev->geo;
-
- switch (geo->major_ver_id) {
+ switch (ndev->geo.major_ver_id) {
case 1:
- sysfs_remove_group(&disk_to_dev(ns->disk)->kobj,
- &nvm_dev_attr_group_12);
+ if (dev_attr->show == nvm_dev_attr_show_12)
+ return attr->mode;
break;
case 2:
- sysfs_remove_group(&disk_to_dev(ns->disk)->kobj,
- &nvm_dev_attr_group_20);
+ if (dev_attr->show == nvm_dev_attr_show_20)
+ return attr->mode;
break;
}
+
+ return 0;
}
+
+const struct attribute_group nvme_nvm_attr_group = {
+ .name = "lightnvm",
+ .attrs = nvm_dev_attrs,
+ .is_visible = nvm_dev_attrs_visible,
+};
diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
index 9fe3fff818b8..9901afd804ce 100644
--- a/drivers/nvme/host/multipath.c
+++ b/drivers/nvme/host/multipath.c
@@ -77,6 +77,13 @@ void nvme_failover_req(struct request *req)
queue_work(nvme_wq, &ns->ctrl->ana_work);
}
break;
+ case NVME_SC_HOST_PATH_ERROR:
+ /*
+ * Temporary transport disruption in talking to the controller.
+ * Try to send on a new path.
+ */
+ nvme_mpath_clear_current_path(ns);
+ break;
default:
/*
* Reset the controller for any non-ANA error as we don't know
@@ -110,29 +117,55 @@ static const char *nvme_ana_state_names[] = {
[NVME_ANA_CHANGE] = "change",
};
-static struct nvme_ns *__nvme_find_path(struct nvme_ns_head *head)
+void nvme_mpath_clear_current_path(struct nvme_ns *ns)
+{
+ struct nvme_ns_head *head = ns->head;
+ int node;
+
+ if (!head)
+ return;
+
+ for_each_node(node) {
+ if (ns == rcu_access_pointer(head->current_path[node]))
+ rcu_assign_pointer(head->current_path[node], NULL);
+ }
+}
+
+static struct nvme_ns *__nvme_find_path(struct nvme_ns_head *head, int node)
{
- struct nvme_ns *ns, *fallback = NULL;
+ int found_distance = INT_MAX, fallback_distance = INT_MAX, distance;
+ struct nvme_ns *found = NULL, *fallback = NULL, *ns;
list_for_each_entry_rcu(ns, &head->list, siblings) {
if (ns->ctrl->state != NVME_CTRL_LIVE ||
test_bit(NVME_NS_ANA_PENDING, &ns->flags))
continue;
+
+ distance = node_distance(node, dev_to_node(ns->ctrl->dev));
+
switch (ns->ana_state) {
case NVME_ANA_OPTIMIZED:
- rcu_assign_pointer(head->current_path, ns);
- return ns;
+ if (distance < found_distance) {
+ found_distance = distance;
+ found = ns;
+ }
+ break;
case NVME_ANA_NONOPTIMIZED:
- fallback = ns;
+ if (distance < fallback_distance) {
+ fallback_distance = distance;
+ fallback = ns;
+ }
break;
default:
break;
}
}
- if (fallback)
- rcu_assign_pointer(head->current_path, fallback);
- return fallback;
+ if (!found)
+ found = fallback;
+ if (found)
+ rcu_assign_pointer(head->current_path[node], found);
+ return found;
}
static inline bool nvme_path_is_optimized(struct nvme_ns *ns)
@@ -143,10 +176,12 @@ static inline bool nvme_path_is_optimized(struct nvme_ns *ns)
inline struct nvme_ns *nvme_find_path(struct nvme_ns_head *head)
{
- struct nvme_ns *ns = srcu_dereference(head->current_path, &head->srcu);
+ int node = numa_node_id();
+ struct nvme_ns *ns;
+ ns = srcu_dereference(head->current_path[node], &head->srcu);
if (unlikely(!ns || !nvme_path_is_optimized(ns)))
- ns = __nvme_find_path(head);
+ ns = __nvme_find_path(head, node);
return ns;
}
@@ -193,7 +228,7 @@ static bool nvme_ns_head_poll(struct request_queue *q, blk_qc_t qc)
int srcu_idx;
srcu_idx = srcu_read_lock(&head->srcu);
- ns = srcu_dereference(head->current_path, &head->srcu);
+ ns = srcu_dereference(head->current_path[numa_node_id()], &head->srcu);
if (likely(ns && nvme_path_is_optimized(ns)))
found = ns->queue->poll_fn(q, qc);
srcu_read_unlock(&head->srcu, srcu_idx);
@@ -250,6 +285,7 @@ int nvme_mpath_alloc_disk(struct nvme_ctrl *ctrl, struct nvme_ns_head *head)
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)
@@ -282,12 +318,17 @@ static void nvme_mpath_set_live(struct nvme_ns *ns)
if (!head->disk)
return;
- if (!(head->disk->flags & GENHD_FL_UP)) {
- device_add_disk(&head->subsys->dev, head->disk);
- if (sysfs_create_group(&disk_to_dev(head->disk)->kobj,
- &nvme_ns_id_attr_group))
- dev_warn(&head->subsys->dev,
- "failed to create id group.\n");
+ if (!(head->disk->flags & GENHD_FL_UP))
+ device_add_disk(&head->subsys->dev, head->disk,
+ nvme_ns_id_attr_groups);
+
+ if (nvme_path_is_optimized(ns)) {
+ int node, srcu_idx;
+
+ srcu_idx = srcu_read_lock(&head->srcu);
+ for_each_node(node)
+ __nvme_find_path(head, node);
+ srcu_read_unlock(&head->srcu, srcu_idx);
}
kblockd_schedule_work(&ns->head->requeue_work);
@@ -494,11 +535,8 @@ void nvme_mpath_remove_disk(struct nvme_ns_head *head)
{
if (!head->disk)
return;
- if (head->disk->flags & GENHD_FL_UP) {
- sysfs_remove_group(&disk_to_dev(head->disk)->kobj,
- &nvme_ns_id_attr_group);
+ if (head->disk->flags & GENHD_FL_UP)
del_gendisk(head->disk);
- }
blk_set_queue_dying(head->disk->queue);
/* make sure all pending bios are cleaned up */
kblockd_schedule_work(&head->requeue_work);
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index bb4a2003c097..cee79cb388af 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -277,14 +277,6 @@ struct nvme_ns_ids {
* only ever has a single entry for private namespaces.
*/
struct nvme_ns_head {
-#ifdef CONFIG_NVME_MULTIPATH
- struct gendisk *disk;
- struct nvme_ns __rcu *current_path;
- struct bio_list requeue_list;
- spinlock_t requeue_lock;
- struct work_struct requeue_work;
- struct mutex lock;
-#endif
struct list_head list;
struct srcu_struct srcu;
struct nvme_subsystem *subsys;
@@ -293,6 +285,14 @@ struct nvme_ns_head {
struct list_head entry;
struct kref ref;
int instance;
+#ifdef CONFIG_NVME_MULTIPATH
+ struct gendisk *disk;
+ struct bio_list requeue_list;
+ spinlock_t requeue_lock;
+ struct work_struct requeue_work;
+ struct mutex lock;
+ struct nvme_ns __rcu *current_path[];
+#endif
};
#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
@@ -343,6 +343,7 @@ struct nvme_ctrl_ops {
unsigned int flags;
#define NVME_F_FABRICS (1 << 0)
#define NVME_F_METADATA_SUPPORTED (1 << 1)
+#define NVME_F_PCI_P2PDMA (1 << 2)
int (*reg_read32)(struct nvme_ctrl *ctrl, u32 off, u32 *val);
int (*reg_write32)(struct nvme_ctrl *ctrl, u32 off, u32 val);
int (*reg_read64)(struct nvme_ctrl *ctrl, u32 off, u64 *val);
@@ -459,7 +460,7 @@ int nvme_delete_ctrl_sync(struct nvme_ctrl *ctrl);
int nvme_get_log(struct nvme_ctrl *ctrl, u32 nsid, u8 log_page, u8 lsp,
void *log, size_t size, u64 offset);
-extern const struct attribute_group nvme_ns_id_attr_group;
+extern const struct attribute_group *nvme_ns_id_attr_groups[];
extern const struct block_device_operations nvme_ns_head_ops;
#ifdef CONFIG_NVME_MULTIPATH
@@ -474,14 +475,7 @@ void nvme_mpath_remove_disk(struct nvme_ns_head *head);
int nvme_mpath_init(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id);
void nvme_mpath_uninit(struct nvme_ctrl *ctrl);
void nvme_mpath_stop(struct nvme_ctrl *ctrl);
-
-static inline void nvme_mpath_clear_current_path(struct nvme_ns *ns)
-{
- struct nvme_ns_head *head = ns->head;
-
- if (head && ns == rcu_access_pointer(head->current_path))
- rcu_assign_pointer(head->current_path, NULL);
-}
+void nvme_mpath_clear_current_path(struct nvme_ns *ns);
struct nvme_ns *nvme_find_path(struct nvme_ns_head *head);
static inline void nvme_mpath_check_last_path(struct nvme_ns *ns)
@@ -551,8 +545,7 @@ static inline void nvme_mpath_stop(struct nvme_ctrl *ctrl)
void nvme_nvm_update_nvm_info(struct nvme_ns *ns);
int nvme_nvm_register(struct nvme_ns *ns, char *disk_name, int node);
void nvme_nvm_unregister(struct nvme_ns *ns);
-int nvme_nvm_register_sysfs(struct nvme_ns *ns);
-void nvme_nvm_unregister_sysfs(struct nvme_ns *ns);
+extern const struct attribute_group nvme_nvm_attr_group;
int nvme_nvm_ioctl(struct nvme_ns *ns, unsigned int cmd, unsigned long arg);
#else
static inline void nvme_nvm_update_nvm_info(struct nvme_ns *ns) {};
@@ -563,11 +556,6 @@ static inline int nvme_nvm_register(struct nvme_ns *ns, char *disk_name,
}
static inline void nvme_nvm_unregister(struct nvme_ns *ns) {};
-static inline int nvme_nvm_register_sysfs(struct nvme_ns *ns)
-{
- return 0;
-}
-static inline void nvme_nvm_unregister_sysfs(struct nvme_ns *ns) {};
static inline int nvme_nvm_ioctl(struct nvme_ns *ns, unsigned int cmd,
unsigned long arg)
{
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index d668682f91df..c33bb201b884 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -30,6 +30,7 @@
#include <linux/types.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/sed-opal.h>
+#include <linux/pci-p2pdma.h>
#include "nvme.h"
@@ -99,9 +100,8 @@ struct nvme_dev {
struct work_struct remove_work;
struct mutex shutdown_lock;
bool subsystem;
- void __iomem *cmb;
- pci_bus_addr_t cmb_bus_addr;
u64 cmb_size;
+ bool cmb_use_sqes;
u32 cmbsz;
u32 cmbloc;
struct nvme_ctrl ctrl;
@@ -158,7 +158,7 @@ struct nvme_queue {
struct nvme_dev *dev;
spinlock_t sq_lock;
struct nvme_command *sq_cmds;
- struct nvme_command __iomem *sq_cmds_io;
+ bool sq_cmds_is_io;
spinlock_t cq_lock ____cacheline_aligned_in_smp;
volatile struct nvme_completion *cqes;
struct blk_mq_tags **tags;
@@ -447,11 +447,8 @@ static int nvme_pci_map_queues(struct blk_mq_tag_set *set)
static void nvme_submit_cmd(struct nvme_queue *nvmeq, struct nvme_command *cmd)
{
spin_lock(&nvmeq->sq_lock);
- if (nvmeq->sq_cmds_io)
- memcpy_toio(&nvmeq->sq_cmds_io[nvmeq->sq_tail], cmd,
- sizeof(*cmd));
- else
- memcpy(&nvmeq->sq_cmds[nvmeq->sq_tail], cmd, sizeof(*cmd));
+
+ memcpy(&nvmeq->sq_cmds[nvmeq->sq_tail], cmd, sizeof(*cmd));
if (++nvmeq->sq_tail == nvmeq->q_depth)
nvmeq->sq_tail = 0;
@@ -748,8 +745,13 @@ static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req,
goto out;
ret = BLK_STS_RESOURCE;
- nr_mapped = dma_map_sg_attrs(dev->dev, iod->sg, iod->nents, dma_dir,
- DMA_ATTR_NO_WARN);
+
+ if (is_pci_p2pdma_page(sg_page(iod->sg)))
+ nr_mapped = pci_p2pdma_map_sg(dev->dev, iod->sg, iod->nents,
+ dma_dir);
+ else
+ nr_mapped = dma_map_sg_attrs(dev->dev, iod->sg, iod->nents,
+ dma_dir, DMA_ATTR_NO_WARN);
if (!nr_mapped)
goto out;
@@ -772,10 +774,10 @@ static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req,
if (!dma_map_sg(dev->dev, &iod->meta_sg, 1, dma_dir))
goto out_unmap;
- }
- if (blk_integrity_rq(req))
cmnd->rw.metadata = cpu_to_le64(sg_dma_address(&iod->meta_sg));
+ }
+
return BLK_STS_OK;
out_unmap:
@@ -791,7 +793,10 @@ static void nvme_unmap_data(struct nvme_dev *dev, struct request *req)
DMA_TO_DEVICE : DMA_FROM_DEVICE;
if (iod->nents) {
- dma_unmap_sg(dev->dev, iod->sg, iod->nents, dma_dir);
+ /* P2PDMA requests do not need to be unmapped */
+ if (!is_pci_p2pdma_page(sg_page(iod->sg)))
+ dma_unmap_sg(dev->dev, iod->sg, iod->nents, dma_dir);
+
if (blk_integrity_rq(req))
dma_unmap_sg(dev->dev, &iod->meta_sg, 1, dma_dir);
}
@@ -1232,9 +1237,18 @@ static void nvme_free_queue(struct nvme_queue *nvmeq)
{
dma_free_coherent(nvmeq->q_dmadev, CQ_SIZE(nvmeq->q_depth),
(void *)nvmeq->cqes, nvmeq->cq_dma_addr);
- if (nvmeq->sq_cmds)
- dma_free_coherent(nvmeq->q_dmadev, SQ_SIZE(nvmeq->q_depth),
- nvmeq->sq_cmds, nvmeq->sq_dma_addr);
+
+ if (nvmeq->sq_cmds) {
+ if (nvmeq->sq_cmds_is_io)
+ pci_free_p2pmem(to_pci_dev(nvmeq->q_dmadev),
+ nvmeq->sq_cmds,
+ SQ_SIZE(nvmeq->q_depth));
+ else
+ dma_free_coherent(nvmeq->q_dmadev,
+ SQ_SIZE(nvmeq->q_depth),
+ nvmeq->sq_cmds,
+ nvmeq->sq_dma_addr);
+ }
}
static void nvme_free_queues(struct nvme_dev *dev, int lowest)
@@ -1249,7 +1263,7 @@ static void nvme_free_queues(struct nvme_dev *dev, int lowest)
/**
* nvme_suspend_queue - put queue into suspended state
- * @nvmeq - queue to suspend
+ * @nvmeq: queue to suspend
*/
static int nvme_suspend_queue(struct nvme_queue *nvmeq)
{
@@ -1323,12 +1337,21 @@ static int nvme_cmb_qdepth(struct nvme_dev *dev, int nr_io_queues,
static int nvme_alloc_sq_cmds(struct nvme_dev *dev, struct nvme_queue *nvmeq,
int qid, int depth)
{
- /* CMB SQEs will be mapped before creation */
- if (qid && dev->cmb && use_cmb_sqes && (dev->cmbsz & NVME_CMBSZ_SQS))
- return 0;
+ struct pci_dev *pdev = to_pci_dev(dev->dev);
+
+ if (qid && dev->cmb_use_sqes && (dev->cmbsz & NVME_CMBSZ_SQS)) {
+ nvmeq->sq_cmds = pci_alloc_p2pmem(pdev, SQ_SIZE(depth));
+ nvmeq->sq_dma_addr = pci_p2pmem_virt_to_bus(pdev,
+ nvmeq->sq_cmds);
+ nvmeq->sq_cmds_is_io = true;
+ }
+
+ if (!nvmeq->sq_cmds) {
+ nvmeq->sq_cmds = dma_alloc_coherent(dev->dev, SQ_SIZE(depth),
+ &nvmeq->sq_dma_addr, GFP_KERNEL);
+ nvmeq->sq_cmds_is_io = false;
+ }
- nvmeq->sq_cmds = dma_alloc_coherent(dev->dev, SQ_SIZE(depth),
- &nvmeq->sq_dma_addr, GFP_KERNEL);
if (!nvmeq->sq_cmds)
return -ENOMEM;
return 0;
@@ -1405,13 +1428,6 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid)
int result;
s16 vector;
- if (dev->cmb && use_cmb_sqes && (dev->cmbsz & NVME_CMBSZ_SQS)) {
- unsigned offset = (qid - 1) * roundup(SQ_SIZE(nvmeq->q_depth),
- dev->ctrl.page_size);
- nvmeq->sq_dma_addr = dev->cmb_bus_addr + offset;
- nvmeq->sq_cmds_io = dev->cmb + offset;
- }
-
/*
* A queue's vector matches the queue identifier unless the controller
* has only one vector available.
@@ -1647,14 +1663,14 @@ static void nvme_map_cmb(struct nvme_dev *dev)
struct pci_dev *pdev = to_pci_dev(dev->dev);
int bar;
+ if (dev->cmb_size)
+ return;
+
dev->cmbsz = readl(dev->bar + NVME_REG_CMBSZ);
if (!dev->cmbsz)
return;
dev->cmbloc = readl(dev->bar + NVME_REG_CMBLOC);
- if (!use_cmb_sqes)
- return;
-
size = nvme_cmb_size_unit(dev) * nvme_cmb_size(dev);
offset = nvme_cmb_size_unit(dev) * NVME_CMB_OFST(dev->cmbloc);
bar = NVME_CMB_BIR(dev->cmbloc);
@@ -1671,11 +1687,18 @@ static void nvme_map_cmb(struct nvme_dev *dev)
if (size > bar_size - offset)
size = bar_size - offset;
- dev->cmb = ioremap_wc(pci_resource_start(pdev, bar) + offset, size);
- if (!dev->cmb)
+ if (pci_p2pdma_add_resource(pdev, bar, size, offset)) {
+ dev_warn(dev->ctrl.device,
+ "failed to register the CMB\n");
return;
- dev->cmb_bus_addr = pci_bus_address(pdev, bar) + offset;
+ }
+
dev->cmb_size = size;
+ dev->cmb_use_sqes = use_cmb_sqes && (dev->cmbsz & NVME_CMBSZ_SQS);
+
+ if ((dev->cmbsz & (NVME_CMBSZ_WDS | NVME_CMBSZ_RDS)) ==
+ (NVME_CMBSZ_WDS | NVME_CMBSZ_RDS))
+ pci_p2pmem_publish(pdev, true);
if (sysfs_add_file_to_group(&dev->ctrl.device->kobj,
&dev_attr_cmb.attr, NULL))
@@ -1685,12 +1708,10 @@ static void nvme_map_cmb(struct nvme_dev *dev)
static inline void nvme_release_cmb(struct nvme_dev *dev)
{
- if (dev->cmb) {
- iounmap(dev->cmb);
- dev->cmb = NULL;
+ if (dev->cmb_size) {
sysfs_remove_file_from_group(&dev->ctrl.device->kobj,
&dev_attr_cmb.attr, NULL);
- dev->cmbsz = 0;
+ dev->cmb_size = 0;
}
}
@@ -1889,13 +1910,13 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
if (nr_io_queues == 0)
return 0;
- if (dev->cmb && (dev->cmbsz & NVME_CMBSZ_SQS)) {
+ if (dev->cmb_use_sqes) {
result = nvme_cmb_qdepth(dev, nr_io_queues,
sizeof(struct nvme_command));
if (result > 0)
dev->q_depth = result;
else
- nvme_release_cmb(dev);
+ dev->cmb_use_sqes = false;
}
do {
@@ -2129,7 +2150,6 @@ static void nvme_pci_disable(struct nvme_dev *dev)
{
struct pci_dev *pdev = to_pci_dev(dev->dev);
- nvme_release_cmb(dev);
pci_free_irq_vectors(pdev);
if (pci_is_enabled(pdev)) {
@@ -2390,7 +2410,8 @@ static int nvme_pci_get_address(struct nvme_ctrl *ctrl, char *buf, int size)
static const struct nvme_ctrl_ops nvme_pci_ctrl_ops = {
.name = "pcie",
.module = THIS_MODULE,
- .flags = NVME_F_METADATA_SUPPORTED,
+ .flags = NVME_F_METADATA_SUPPORTED |
+ NVME_F_PCI_P2PDMA,
.reg_read32 = nvme_pci_reg_read32,
.reg_write32 = nvme_pci_reg_write32,
.reg_read64 = nvme_pci_reg_read64,
@@ -2564,19 +2585,19 @@ static void nvme_remove(struct pci_dev *pdev)
struct nvme_dev *dev = pci_get_drvdata(pdev);
nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_DELETING);
-
- cancel_work_sync(&dev->ctrl.reset_work);
pci_set_drvdata(pdev, NULL);
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);
nvme_stop_ctrl(&dev->ctrl);
nvme_remove_namespaces(&dev->ctrl);
nvme_dev_disable(dev, true);
+ nvme_release_cmb(dev);
nvme_free_host_mem(dev);
nvme_dev_remove_admin(dev);
nvme_free_queues(dev, 0);
@@ -2649,7 +2670,6 @@ static void nvme_error_resume(struct pci_dev *pdev)
struct nvme_dev *dev = pci_get_drvdata(pdev);
flush_work(&dev->ctrl.reset_work);
- pci_cleanup_aer_uncorrect_error_status(pdev);
}
static const struct pci_error_handlers nvme_err_handler = {
diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
index dc042017c293..d181cafedc58 100644
--- a/drivers/nvme/host/rdma.c
+++ b/drivers/nvme/host/rdma.c
@@ -233,8 +233,15 @@ static void nvme_rdma_qp_event(struct ib_event *event, void *context)
static int nvme_rdma_wait_for_cm(struct nvme_rdma_queue *queue)
{
- wait_for_completion_interruptible_timeout(&queue->cm_done,
+ int ret;
+
+ ret = wait_for_completion_interruptible_timeout(&queue->cm_done,
msecs_to_jiffies(NVME_RDMA_CONNECT_TIMEOUT_MS) + 1);
+ if (ret < 0)
+ return ret;
+ if (ret == 0)
+ return -ETIMEDOUT;
+ WARN_ON_ONCE(queue->cm_error > 0);
return queue->cm_error;
}
@@ -1849,54 +1856,6 @@ static const struct nvme_ctrl_ops nvme_rdma_ctrl_ops = {
.stop_ctrl = nvme_rdma_stop_ctrl,
};
-static inline bool
-__nvme_rdma_options_match(struct nvme_rdma_ctrl *ctrl,
- struct nvmf_ctrl_options *opts)
-{
- char *stdport = __stringify(NVME_RDMA_IP_PORT);
-
-
- if (!nvmf_ctlr_matches_baseopts(&ctrl->ctrl, opts) ||
- strcmp(opts->traddr, ctrl->ctrl.opts->traddr))
- return false;
-
- if (opts->mask & NVMF_OPT_TRSVCID &&
- ctrl->ctrl.opts->mask & NVMF_OPT_TRSVCID) {
- if (strcmp(opts->trsvcid, ctrl->ctrl.opts->trsvcid))
- return false;
- } else if (opts->mask & NVMF_OPT_TRSVCID) {
- if (strcmp(opts->trsvcid, stdport))
- return false;
- } else if (ctrl->ctrl.opts->mask & NVMF_OPT_TRSVCID) {
- if (strcmp(stdport, ctrl->ctrl.opts->trsvcid))
- return false;
- }
- /* else, it's a match as both have stdport. Fall to next checks */
-
- /*
- * checking the local address is rough. In most cases, one
- * is not specified and the host port is selected by the stack.
- *
- * Assume no match if:
- * local address is specified and address is not the same
- * local address is not specified but remote is, or vice versa
- * (admin using specific host_traddr when it matters).
- */
- if (opts->mask & NVMF_OPT_HOST_TRADDR &&
- ctrl->ctrl.opts->mask & NVMF_OPT_HOST_TRADDR) {
- if (strcmp(opts->host_traddr, ctrl->ctrl.opts->host_traddr))
- return false;
- } else if (opts->mask & NVMF_OPT_HOST_TRADDR ||
- ctrl->ctrl.opts->mask & NVMF_OPT_HOST_TRADDR)
- return false;
- /*
- * if neither controller had an host port specified, assume it's
- * a match as everything else matched.
- */
-
- return true;
-}
-
/*
* Fails a connection request if it matches an existing controller
* (association) with the same tuple:
@@ -1917,7 +1876,7 @@ nvme_rdma_existing_controller(struct nvmf_ctrl_options *opts)
mutex_lock(&nvme_rdma_ctrl_mutex);
list_for_each_entry(ctrl, &nvme_rdma_ctrl_list, list) {
- found = __nvme_rdma_options_match(ctrl, opts);
+ found = nvmf_ip_options_match(&ctrl->ctrl, opts);
if (found)
break;
}
@@ -1932,7 +1891,6 @@ static struct nvme_ctrl *nvme_rdma_create_ctrl(struct device *dev,
struct nvme_rdma_ctrl *ctrl;
int ret;
bool changed;
- char *port;
ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
if (!ctrl)
@@ -1940,15 +1898,21 @@ static struct nvme_ctrl *nvme_rdma_create_ctrl(struct device *dev,
ctrl->ctrl.opts = opts;
INIT_LIST_HEAD(&ctrl->list);
- if (opts->mask & NVMF_OPT_TRSVCID)
- port = opts->trsvcid;
- else
- port = __stringify(NVME_RDMA_IP_PORT);
+ if (!(opts->mask & NVMF_OPT_TRSVCID)) {
+ opts->trsvcid =
+ kstrdup(__stringify(NVME_RDMA_IP_PORT), GFP_KERNEL);
+ if (!opts->trsvcid) {
+ ret = -ENOMEM;
+ goto out_free_ctrl;
+ }
+ opts->mask |= NVMF_OPT_TRSVCID;
+ }
ret = inet_pton_with_scope(&init_net, AF_UNSPEC,
- opts->traddr, port, &ctrl->addr);
+ opts->traddr, opts->trsvcid, &ctrl->addr);
if (ret) {
- pr_err("malformed address passed: %s:%s\n", opts->traddr, port);
+ pr_err("malformed address passed: %s:%s\n",
+ opts->traddr, opts->trsvcid);
goto out_free_ctrl;
}
diff --git a/drivers/nvme/host/trace.h b/drivers/nvme/host/trace.h
index a490790d6691..196d5bd56718 100644
--- a/drivers/nvme/host/trace.h
+++ b/drivers/nvme/host/trace.h
@@ -156,6 +156,34 @@ TRACE_EVENT(nvme_complete_rq,
);
+#define aer_name(aer) { aer, #aer }
+
+TRACE_EVENT(nvme_async_event,
+ TP_PROTO(struct nvme_ctrl *ctrl, u32 result),
+ TP_ARGS(ctrl, result),
+ TP_STRUCT__entry(
+ __field(int, ctrl_id)
+ __field(u32, result)
+ ),
+ TP_fast_assign(
+ __entry->ctrl_id = ctrl->instance;
+ __entry->result = result;
+ ),
+ TP_printk("nvme%d: NVME_AEN=%#08x [%s]",
+ __entry->ctrl_id, __entry->result,
+ __print_symbolic(__entry->result,
+ aer_name(NVME_AER_NOTICE_NS_CHANGED),
+ aer_name(NVME_AER_NOTICE_ANA),
+ aer_name(NVME_AER_NOTICE_FW_ACT_STARTING),
+ aer_name(NVME_AER_ERROR),
+ aer_name(NVME_AER_SMART),
+ aer_name(NVME_AER_CSS),
+ aer_name(NVME_AER_VS))
+ )
+);
+
+#undef aer_name
+
#endif /* _TRACE_NVME_H */
#undef TRACE_INCLUDE_PATH
diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
index 2008fa62a373..1179f6314323 100644
--- a/drivers/nvme/target/admin-cmd.c
+++ b/drivers/nvme/target/admin-cmd.c
@@ -58,7 +58,7 @@ static u16 nvmet_get_smart_log_nsid(struct nvmet_req *req,
ns = nvmet_find_namespace(req->sq->ctrl, req->cmd->get_log_page.nsid);
if (!ns) {
- pr_err("nvmet : Could not find namespace id : %d\n",
+ pr_err("Could not find namespace id : %d\n",
le32_to_cpu(req->cmd->get_log_page.nsid));
return NVME_SC_INVALID_NS;
}
@@ -353,7 +353,7 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
if (req->port->inline_data_size)
id->sgls |= cpu_to_le32(1 << 20);
- strcpy(id->subnqn, ctrl->subsys->subsysnqn);
+ strlcpy(id->subnqn, ctrl->subsys->subsysnqn, sizeof(id->subnqn));
/* Max command capsule size is sqe + single page of in-capsule data */
id->ioccsz = cpu_to_le32((sizeof(struct nvme_command) +
diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c
index b37a8e3e3f80..d895579b6c5d 100644
--- a/drivers/nvme/target/configfs.c
+++ b/drivers/nvme/target/configfs.c
@@ -17,6 +17,8 @@
#include <linux/slab.h>
#include <linux/stat.h>
#include <linux/ctype.h>
+#include <linux/pci.h>
+#include <linux/pci-p2pdma.h>
#include "nvmet.h"
@@ -340,6 +342,48 @@ out_unlock:
CONFIGFS_ATTR(nvmet_ns_, device_path);
+#ifdef CONFIG_PCI_P2PDMA
+static ssize_t nvmet_ns_p2pmem_show(struct config_item *item, char *page)
+{
+ struct nvmet_ns *ns = to_nvmet_ns(item);
+
+ return pci_p2pdma_enable_show(page, ns->p2p_dev, ns->use_p2pmem);
+}
+
+static ssize_t nvmet_ns_p2pmem_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct nvmet_ns *ns = to_nvmet_ns(item);
+ struct pci_dev *p2p_dev = NULL;
+ bool use_p2pmem;
+ int ret = count;
+ int error;
+
+ mutex_lock(&ns->subsys->lock);
+ if (ns->enabled) {
+ ret = -EBUSY;
+ goto out_unlock;
+ }
+
+ error = pci_p2pdma_enable_store(page, &p2p_dev, &use_p2pmem);
+ if (error) {
+ ret = error;
+ goto out_unlock;
+ }
+
+ ns->use_p2pmem = use_p2pmem;
+ pci_dev_put(ns->p2p_dev);
+ ns->p2p_dev = p2p_dev;
+
+out_unlock:
+ mutex_unlock(&ns->subsys->lock);
+
+ return ret;
+}
+
+CONFIGFS_ATTR(nvmet_ns_, p2pmem);
+#endif /* CONFIG_PCI_P2PDMA */
+
static ssize_t nvmet_ns_device_uuid_show(struct config_item *item, char *page)
{
return sprintf(page, "%pUb\n", &to_nvmet_ns(item)->uuid);
@@ -509,6 +553,9 @@ static struct configfs_attribute *nvmet_ns_attrs[] = {
&nvmet_ns_attr_ana_grpid,
&nvmet_ns_attr_enable,
&nvmet_ns_attr_buffered_io,
+#ifdef CONFIG_PCI_P2PDMA
+ &nvmet_ns_attr_p2pmem,
+#endif
NULL,
};
diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
index b5ec96abd048..a5f9bbce863f 100644
--- a/drivers/nvme/target/core.c
+++ b/drivers/nvme/target/core.c
@@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/random.h>
#include <linux/rculist.h>
+#include <linux/pci-p2pdma.h>
#include "nvmet.h"
@@ -365,9 +366,93 @@ static void nvmet_ns_dev_disable(struct nvmet_ns *ns)
nvmet_file_ns_disable(ns);
}
+static int nvmet_p2pmem_ns_enable(struct nvmet_ns *ns)
+{
+ int ret;
+ struct pci_dev *p2p_dev;
+
+ if (!ns->use_p2pmem)
+ return 0;
+
+ if (!ns->bdev) {
+ pr_err("peer-to-peer DMA is not supported by non-block device namespaces\n");
+ return -EINVAL;
+ }
+
+ if (!blk_queue_pci_p2pdma(ns->bdev->bd_queue)) {
+ pr_err("peer-to-peer DMA is not supported by the driver of %s\n",
+ ns->device_path);
+ return -EINVAL;
+ }
+
+ if (ns->p2p_dev) {
+ ret = pci_p2pdma_distance(ns->p2p_dev, nvmet_ns_dev(ns), true);
+ if (ret < 0)
+ return -EINVAL;
+ } else {
+ /*
+ * Right now we just check that there is p2pmem available so
+ * we can report an error to the user right away if there
+ * is not. We'll find the actual device to use once we
+ * setup the controller when the port's device is available.
+ */
+
+ p2p_dev = pci_p2pmem_find(nvmet_ns_dev(ns));
+ if (!p2p_dev) {
+ pr_err("no peer-to-peer memory is available for %s\n",
+ ns->device_path);
+ return -EINVAL;
+ }
+
+ pci_dev_put(p2p_dev);
+ }
+
+ return 0;
+}
+
+/*
+ * Note: ctrl->subsys->lock should be held when calling this function
+ */
+static void nvmet_p2pmem_ns_add_p2p(struct nvmet_ctrl *ctrl,
+ struct nvmet_ns *ns)
+{
+ struct device *clients[2];
+ struct pci_dev *p2p_dev;
+ int ret;
+
+ if (!ctrl->p2p_client || !ns->use_p2pmem)
+ return;
+
+ if (ns->p2p_dev) {
+ ret = pci_p2pdma_distance(ns->p2p_dev, ctrl->p2p_client, true);
+ if (ret < 0)
+ return;
+
+ p2p_dev = pci_dev_get(ns->p2p_dev);
+ } else {
+ clients[0] = ctrl->p2p_client;
+ clients[1] = nvmet_ns_dev(ns);
+
+ p2p_dev = pci_p2pmem_find_many(clients, ARRAY_SIZE(clients));
+ if (!p2p_dev) {
+ pr_err("no peer-to-peer memory is available that's supported by %s and %s\n",
+ dev_name(ctrl->p2p_client), ns->device_path);
+ return;
+ }
+ }
+
+ ret = radix_tree_insert(&ctrl->p2p_ns_map, ns->nsid, p2p_dev);
+ if (ret < 0)
+ pci_dev_put(p2p_dev);
+
+ pr_info("using p2pmem on %s for nsid %d\n", pci_name(p2p_dev),
+ ns->nsid);
+}
+
int nvmet_ns_enable(struct nvmet_ns *ns)
{
struct nvmet_subsys *subsys = ns->subsys;
+ struct nvmet_ctrl *ctrl;
int ret;
mutex_lock(&subsys->lock);
@@ -384,6 +469,13 @@ int nvmet_ns_enable(struct nvmet_ns *ns)
if (ret)
goto out_unlock;
+ ret = nvmet_p2pmem_ns_enable(ns);
+ if (ret)
+ goto out_unlock;
+
+ list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry)
+ nvmet_p2pmem_ns_add_p2p(ctrl, ns);
+
ret = percpu_ref_init(&ns->ref, nvmet_destroy_namespace,
0, GFP_KERNEL);
if (ret)
@@ -418,6 +510,9 @@ out_unlock:
mutex_unlock(&subsys->lock);
return ret;
out_dev_put:
+ list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry)
+ pci_dev_put(radix_tree_delete(&ctrl->p2p_ns_map, ns->nsid));
+
nvmet_ns_dev_disable(ns);
goto out_unlock;
}
@@ -425,6 +520,7 @@ out_dev_put:
void nvmet_ns_disable(struct nvmet_ns *ns)
{
struct nvmet_subsys *subsys = ns->subsys;
+ struct nvmet_ctrl *ctrl;
mutex_lock(&subsys->lock);
if (!ns->enabled)
@@ -434,6 +530,10 @@ void nvmet_ns_disable(struct nvmet_ns *ns)
list_del_rcu(&ns->dev_link);
if (ns->nsid == subsys->max_nsid)
subsys->max_nsid = nvmet_max_nsid(subsys);
+
+ list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry)
+ pci_dev_put(radix_tree_delete(&ctrl->p2p_ns_map, ns->nsid));
+
mutex_unlock(&subsys->lock);
/*
@@ -450,6 +550,7 @@ void nvmet_ns_disable(struct nvmet_ns *ns)
percpu_ref_exit(&ns->ref);
mutex_lock(&subsys->lock);
+
subsys->nr_namespaces--;
nvmet_ns_changed(subsys, ns->nsid);
nvmet_ns_dev_disable(ns);
@@ -725,6 +826,51 @@ void nvmet_req_execute(struct nvmet_req *req)
}
EXPORT_SYMBOL_GPL(nvmet_req_execute);
+int nvmet_req_alloc_sgl(struct nvmet_req *req)
+{
+ struct pci_dev *p2p_dev = NULL;
+
+ if (IS_ENABLED(CONFIG_PCI_P2PDMA)) {
+ if (req->sq->ctrl && req->ns)
+ p2p_dev = radix_tree_lookup(&req->sq->ctrl->p2p_ns_map,
+ req->ns->nsid);
+
+ req->p2p_dev = NULL;
+ if (req->sq->qid && p2p_dev) {
+ req->sg = pci_p2pmem_alloc_sgl(p2p_dev, &req->sg_cnt,
+ req->transfer_len);
+ if (req->sg) {
+ req->p2p_dev = p2p_dev;
+ return 0;
+ }
+ }
+
+ /*
+ * If no P2P memory was available we fallback to using
+ * regular memory
+ */
+ }
+
+ req->sg = sgl_alloc(req->transfer_len, GFP_KERNEL, &req->sg_cnt);
+ if (!req->sg)
+ return -ENOMEM;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(nvmet_req_alloc_sgl);
+
+void nvmet_req_free_sgl(struct nvmet_req *req)
+{
+ if (req->p2p_dev)
+ pci_p2pmem_free_sgl(req->p2p_dev, req->sg);
+ else
+ sgl_free(req->sg);
+
+ req->sg = NULL;
+ req->sg_cnt = 0;
+}
+EXPORT_SYMBOL_GPL(nvmet_req_free_sgl);
+
static inline bool nvmet_cc_en(u32 cc)
{
return (cc >> NVME_CC_EN_SHIFT) & 0x1;
@@ -921,6 +1067,37 @@ bool nvmet_host_allowed(struct nvmet_req *req, struct nvmet_subsys *subsys,
return __nvmet_host_allowed(subsys, hostnqn);
}
+/*
+ * Note: ctrl->subsys->lock should be held when calling this function
+ */
+static void nvmet_setup_p2p_ns_map(struct nvmet_ctrl *ctrl,
+ struct nvmet_req *req)
+{
+ struct nvmet_ns *ns;
+
+ if (!req->p2p_client)
+ return;
+
+ ctrl->p2p_client = get_device(req->p2p_client);
+
+ list_for_each_entry_rcu(ns, &ctrl->subsys->namespaces, dev_link)
+ nvmet_p2pmem_ns_add_p2p(ctrl, ns);
+}
+
+/*
+ * Note: ctrl->subsys->lock should be held when calling this function
+ */
+static void nvmet_release_p2p_ns_map(struct nvmet_ctrl *ctrl)
+{
+ struct radix_tree_iter iter;
+ void __rcu **slot;
+
+ radix_tree_for_each_slot(slot, &ctrl->p2p_ns_map, &iter, 0)
+ pci_dev_put(radix_tree_deref_slot(slot));
+
+ put_device(ctrl->p2p_client);
+}
+
u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn,
struct nvmet_req *req, u32 kato, struct nvmet_ctrl **ctrlp)
{
@@ -962,6 +1139,7 @@ u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn,
INIT_WORK(&ctrl->async_event_work, nvmet_async_event_work);
INIT_LIST_HEAD(&ctrl->async_events);
+ INIT_RADIX_TREE(&ctrl->p2p_ns_map, GFP_KERNEL);
memcpy(ctrl->subsysnqn, subsysnqn, NVMF_NQN_SIZE);
memcpy(ctrl->hostnqn, hostnqn, NVMF_NQN_SIZE);
@@ -1026,6 +1204,7 @@ u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn,
mutex_lock(&subsys->lock);
list_add_tail(&ctrl->subsys_entry, &subsys->ctrls);
+ nvmet_setup_p2p_ns_map(ctrl, req);
mutex_unlock(&subsys->lock);
*ctrlp = ctrl;
@@ -1053,6 +1232,7 @@ static void nvmet_ctrl_free(struct kref *ref)
struct nvmet_subsys *subsys = ctrl->subsys;
mutex_lock(&subsys->lock);
+ nvmet_release_p2p_ns_map(ctrl);
list_del(&ctrl->subsys_entry);
mutex_unlock(&subsys->lock);
@@ -1105,8 +1285,7 @@ static struct nvmet_subsys *nvmet_find_get_subsys(struct nvmet_port *port,
if (!port)
return NULL;
- if (!strncmp(NVME_DISC_SUBSYS_NAME, subsysnqn,
- NVMF_NQN_SIZE)) {
+ if (!strcmp(NVME_DISC_SUBSYS_NAME, subsysnqn)) {
if (!kref_get_unless_zero(&nvmet_disc_subsys->ref))
return NULL;
return nvmet_disc_subsys;
diff --git a/drivers/nvme/target/discovery.c b/drivers/nvme/target/discovery.c
index eae29f493a07..bc0aa0bf1543 100644
--- a/drivers/nvme/target/discovery.c
+++ b/drivers/nvme/target/discovery.c
@@ -174,7 +174,7 @@ static void nvmet_execute_identify_disc_ctrl(struct nvmet_req *req)
if (req->port->inline_data_size)
id->sgls |= cpu_to_le32(1 << 20);
- strcpy(id->subnqn, ctrl->subsys->subsysnqn);
+ strlcpy(id->subnqn, ctrl->subsys->subsysnqn, sizeof(id->subnqn));
status = nvmet_copy_to_sgl(req, 0, id, sizeof(*id));
@@ -219,12 +219,10 @@ u16 nvmet_parse_discovery_cmd(struct nvmet_req *req)
return NVME_SC_INVALID_OPCODE | NVME_SC_DNR;
}
default:
- pr_err("unsupported cmd %d\n", cmd->common.opcode);
+ pr_err("unhandled cmd %d\n", cmd->common.opcode);
return NVME_SC_INVALID_OPCODE | NVME_SC_DNR;
}
- pr_err("unhandled cmd %d\n", cmd->common.opcode);
- return NVME_SC_INVALID_OPCODE | NVME_SC_DNR;
}
int __init nvmet_init_discovery(void)
diff --git a/drivers/nvme/target/fc.c b/drivers/nvme/target/fc.c
index 29b4b236afd8..409081a03b24 100644
--- a/drivers/nvme/target/fc.c
+++ b/drivers/nvme/target/fc.c
@@ -110,11 +110,19 @@ struct nvmet_fc_tgtport {
struct list_head ls_busylist;
struct list_head assoc_list;
struct ida assoc_cnt;
- struct nvmet_port *port;
+ struct nvmet_fc_port_entry *pe;
struct kref ref;
u32 max_sg_cnt;
};
+struct nvmet_fc_port_entry {
+ struct nvmet_fc_tgtport *tgtport;
+ struct nvmet_port *port;
+ u64 node_name;
+ u64 port_name;
+ struct list_head pe_list;
+};
+
struct nvmet_fc_defer_fcp_req {
struct list_head req_list;
struct nvmefc_tgt_fcp_req *fcp_req;
@@ -132,7 +140,6 @@ struct nvmet_fc_tgt_queue {
atomic_t zrspcnt;
atomic_t rsn;
spinlock_t qlock;
- struct nvmet_port *port;
struct nvmet_cq nvme_cq;
struct nvmet_sq nvme_sq;
struct nvmet_fc_tgt_assoc *assoc;
@@ -221,6 +228,7 @@ static DEFINE_SPINLOCK(nvmet_fc_tgtlock);
static LIST_HEAD(nvmet_fc_target_list);
static DEFINE_IDA(nvmet_fc_tgtport_cnt);
+static LIST_HEAD(nvmet_fc_portentry_list);
static void nvmet_fc_handle_ls_rqst_work(struct work_struct *work);
@@ -645,7 +653,6 @@ nvmet_fc_alloc_target_queue(struct nvmet_fc_tgt_assoc *assoc,
queue->qid = qid;
queue->sqsize = sqsize;
queue->assoc = assoc;
- queue->port = assoc->tgtport->port;
queue->cpu = nvmet_fc_queue_to_cpu(assoc->tgtport, qid);
INIT_LIST_HEAD(&queue->fod_list);
INIT_LIST_HEAD(&queue->avail_defer_list);
@@ -957,6 +964,83 @@ nvmet_fc_find_target_assoc(struct nvmet_fc_tgtport *tgtport,
return ret;
}
+static void
+nvmet_fc_portentry_bind(struct nvmet_fc_tgtport *tgtport,
+ struct nvmet_fc_port_entry *pe,
+ struct nvmet_port *port)
+{
+ lockdep_assert_held(&nvmet_fc_tgtlock);
+
+ pe->tgtport = tgtport;
+ tgtport->pe = pe;
+
+ pe->port = port;
+ port->priv = pe;
+
+ pe->node_name = tgtport->fc_target_port.node_name;
+ pe->port_name = tgtport->fc_target_port.port_name;
+ INIT_LIST_HEAD(&pe->pe_list);
+
+ list_add_tail(&pe->pe_list, &nvmet_fc_portentry_list);
+}
+
+static void
+nvmet_fc_portentry_unbind(struct nvmet_fc_port_entry *pe)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&nvmet_fc_tgtlock, flags);
+ if (pe->tgtport)
+ pe->tgtport->pe = NULL;
+ list_del(&pe->pe_list);
+ spin_unlock_irqrestore(&nvmet_fc_tgtlock, flags);
+}
+
+/*
+ * called when a targetport deregisters. Breaks the relationship
+ * with the nvmet port, but leaves the port_entry in place so that
+ * re-registration can resume operation.
+ */
+static void
+nvmet_fc_portentry_unbind_tgt(struct nvmet_fc_tgtport *tgtport)
+{
+ struct nvmet_fc_port_entry *pe;
+ unsigned long flags;
+
+ spin_lock_irqsave(&nvmet_fc_tgtlock, flags);
+ pe = tgtport->pe;
+ if (pe)
+ pe->tgtport = NULL;
+ tgtport->pe = NULL;
+ spin_unlock_irqrestore(&nvmet_fc_tgtlock, flags);
+}
+
+/*
+ * called when a new targetport is registered. Looks in the
+ * existing nvmet port_entries to see if the nvmet layer is
+ * configured for the targetport's wwn's. (the targetport existed,
+ * nvmet configured, the lldd unregistered the tgtport, and is now
+ * reregistering the same targetport). If so, set the nvmet port
+ * port entry on the targetport.
+ */
+static void
+nvmet_fc_portentry_rebind_tgt(struct nvmet_fc_tgtport *tgtport)
+{
+ struct nvmet_fc_port_entry *pe;
+ unsigned long flags;
+
+ spin_lock_irqsave(&nvmet_fc_tgtlock, flags);
+ list_for_each_entry(pe, &nvmet_fc_portentry_list, pe_list) {
+ if (tgtport->fc_target_port.node_name == pe->node_name &&
+ tgtport->fc_target_port.port_name == pe->port_name) {
+ WARN_ON(pe->tgtport);
+ tgtport->pe = pe;
+ pe->tgtport = tgtport;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&nvmet_fc_tgtlock, flags);
+}
/**
* nvme_fc_register_targetport - transport entry point called by an
@@ -1034,6 +1118,8 @@ nvmet_fc_register_targetport(struct nvmet_fc_port_info *pinfo,
goto out_free_newrec;
}
+ nvmet_fc_portentry_rebind_tgt(newrec);
+
spin_lock_irqsave(&nvmet_fc_tgtlock, flags);
list_add_tail(&newrec->tgt_list, &nvmet_fc_target_list);
spin_unlock_irqrestore(&nvmet_fc_tgtlock, flags);
@@ -1159,8 +1245,8 @@ nvmet_fc_delete_ctrl(struct nvmet_ctrl *ctrl)
* nvme_fc_unregister_targetport - transport entry point called by an
* LLDD to deregister/remove a previously
* registered a local NVME subsystem FC port.
- * @tgtport: pointer to the (registered) target port that is to be
- * deregistered.
+ * @target_port: pointer to the (registered) target port that is to be
+ * deregistered.
*
* Returns:
* a completion status. Must be 0 upon success; a negative errno
@@ -1171,6 +1257,8 @@ nvmet_fc_unregister_targetport(struct nvmet_fc_target_port *target_port)
{
struct nvmet_fc_tgtport *tgtport = targetport_to_tgtport(target_port);
+ nvmet_fc_portentry_unbind_tgt(tgtport);
+
/* terminate any outstanding associations */
__nvmet_fc_free_assocs(tgtport);
@@ -1661,7 +1749,7 @@ nvmet_fc_handle_ls_rqst_work(struct work_struct *work)
*
* If this routine returns error, the LLDD should abort the exchange.
*
- * @tgtport: pointer to the (registered) target port the LS was
+ * @target_port: pointer to the (registered) target port the LS was
* received on.
* @lsreq: pointer to a lsreq request structure to be used to reference
* the exchange corresponding to the LS.
@@ -2147,7 +2235,7 @@ nvmet_fc_fcp_nvme_cmd_done(struct nvmet_req *nvme_req)
/*
- * Actual processing routine for received FC-NVME LS Requests from the LLD
+ * Actual processing routine for received FC-NVME I/O Requests from the LLD
*/
static void
nvmet_fc_handle_fcp_rqst(struct nvmet_fc_tgtport *tgtport,
@@ -2158,6 +2246,13 @@ 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.
*
@@ -2184,7 +2279,7 @@ nvmet_fc_handle_fcp_rqst(struct nvmet_fc_tgtport *tgtport,
fod->req.cmd = &fod->cmdiubuf.sqe;
fod->req.rsp = &fod->rspiubuf.cqe;
- fod->req.port = fod->queue->port;
+ fod->req.port = tgtport->pe->port;
/* clear any response payload */
memset(&fod->rspiubuf, 0, sizeof(fod->rspiubuf));
@@ -2468,7 +2563,7 @@ nvme_fc_parse_traddr(struct nvmet_fc_traddr *traddr, char *buf, size_t blen)
substring_t wwn = { name, &name[sizeof(name)-1] };
int nnoffset, pnoffset;
- /* validate it string one of the 2 allowed formats */
+ /* validate if string is one of the 2 allowed formats */
if (strnlen(buf, blen) == NVME_FC_TRADDR_MAXLENGTH &&
!strncmp(buf, "nn-0x", NVME_FC_TRADDR_OXNNLEN) &&
!strncmp(&buf[NVME_FC_TRADDR_MAX_PN_OFFSET],
@@ -2508,6 +2603,7 @@ static int
nvmet_fc_add_port(struct nvmet_port *port)
{
struct nvmet_fc_tgtport *tgtport;
+ struct nvmet_fc_port_entry *pe;
struct nvmet_fc_traddr traddr = { 0L, 0L };
unsigned long flags;
int ret;
@@ -2524,24 +2620,40 @@ nvmet_fc_add_port(struct nvmet_port *port)
if (ret)
return ret;
+ pe = kzalloc(sizeof(*pe), GFP_KERNEL);
+ if (!pe)
+ return -ENOMEM;
+
ret = -ENXIO;
spin_lock_irqsave(&nvmet_fc_tgtlock, flags);
list_for_each_entry(tgtport, &nvmet_fc_target_list, tgt_list) {
if ((tgtport->fc_target_port.node_name == traddr.nn) &&
(tgtport->fc_target_port.port_name == traddr.pn)) {
- tgtport->port = port;
- ret = 0;
+ /* a FC port can only be 1 nvmet port id */
+ if (!tgtport->pe) {
+ nvmet_fc_portentry_bind(tgtport, pe, port);
+ ret = 0;
+ } else
+ ret = -EALREADY;
break;
}
}
spin_unlock_irqrestore(&nvmet_fc_tgtlock, flags);
+
+ if (ret)
+ kfree(pe);
+
return ret;
}
static void
nvmet_fc_remove_port(struct nvmet_port *port)
{
- /* nothing to do */
+ struct nvmet_fc_port_entry *pe = port->priv;
+
+ nvmet_fc_portentry_unbind(pe);
+
+ kfree(pe);
}
static const struct nvmet_fabrics_ops nvmet_fc_tgt_fcp_ops = {
diff --git a/drivers/nvme/target/fcloop.c b/drivers/nvme/target/fcloop.c
index 5251689a1d9a..291f4121f516 100644
--- a/drivers/nvme/target/fcloop.c
+++ b/drivers/nvme/target/fcloop.c
@@ -648,6 +648,7 @@ fcloop_fcp_op(struct nvmet_fc_target_port *tgtport,
break;
/* Fall-Thru to RSP handling */
+ /* FALLTHRU */
case NVMET_FCOP_RSP:
if (fcpreq) {
diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c
index 7bc9f6240432..c1ec3475a140 100644
--- a/drivers/nvme/target/io-cmd-bdev.c
+++ b/drivers/nvme/target/io-cmd-bdev.c
@@ -58,7 +58,7 @@ static void nvmet_bio_done(struct bio *bio)
static void nvmet_bdev_execute_rw(struct nvmet_req *req)
{
int sg_cnt = req->sg_cnt;
- struct bio *bio = &req->b.inline_bio;
+ struct bio *bio;
struct scatterlist *sg;
sector_t sector;
blk_qc_t cookie;
@@ -78,10 +78,18 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req)
op = REQ_OP_READ;
}
+ if (is_pci_p2pdma_page(sg_page(req->sg)))
+ op_flags |= REQ_NOMERGE;
+
sector = le64_to_cpu(req->cmd->rw.slba);
sector <<= (req->ns->blksize_shift - 9);
- bio_init(bio, req->inline_bvec, ARRAY_SIZE(req->inline_bvec));
+ if (req->data_len <= NVMET_MAX_INLINE_DATA_LEN) {
+ bio = &req->b.inline_bio;
+ bio_init(bio, req->inline_bvec, ARRAY_SIZE(req->inline_bvec));
+ } else {
+ bio = bio_alloc(GFP_KERNEL, min(sg_cnt, BIO_MAX_PAGES));
+ }
bio_set_dev(bio, req->ns->bdev);
bio->bi_iter.bi_sector = sector;
bio->bi_private = req;
diff --git a/drivers/nvme/target/io-cmd-file.c b/drivers/nvme/target/io-cmd-file.c
index 81a9dc5290a8..01feebec29ea 100644
--- a/drivers/nvme/target/io-cmd-file.c
+++ b/drivers/nvme/target/io-cmd-file.c
@@ -101,7 +101,7 @@ static ssize_t nvmet_file_submit_bvec(struct nvmet_req *req, loff_t pos,
rw = READ;
}
- iov_iter_bvec(&iter, ITER_BVEC | rw, req->f.bvec, nr_segs, count);
+ iov_iter_bvec(&iter, rw, req->f.bvec, nr_segs, count);
iocb->ki_pos = pos;
iocb->ki_filp = req->ns->file;
@@ -246,7 +246,8 @@ static void nvmet_file_execute_discard(struct nvmet_req *req)
break;
offset = le64_to_cpu(range.slba) << req->ns->blksize_shift;
- len = le32_to_cpu(range.nlb) << req->ns->blksize_shift;
+ len = le32_to_cpu(range.nlb);
+ len <<= req->ns->blksize_shift;
if (offset + len > req->ns->size) {
ret = NVME_SC_LBA_RANGE | NVME_SC_DNR;
break;
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index ec9af4ee03b6..c2b4d9ee6391 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -26,6 +26,7 @@
#include <linux/configfs.h>
#include <linux/rcupdate.h>
#include <linux/blkdev.h>
+#include <linux/radix-tree.h>
#define NVMET_ASYNC_EVENTS 4
#define NVMET_ERROR_LOG_SLOTS 128
@@ -77,6 +78,9 @@ struct nvmet_ns {
struct completion disable_done;
mempool_t *bvec_pool;
struct kmem_cache *bvec_cache;
+
+ int use_p2pmem;
+ struct pci_dev *p2p_dev;
};
static inline struct nvmet_ns *to_nvmet_ns(struct config_item *item)
@@ -84,6 +88,11 @@ static inline struct nvmet_ns *to_nvmet_ns(struct config_item *item)
return container_of(to_config_group(item), struct nvmet_ns, group);
}
+static inline struct device *nvmet_ns_dev(struct nvmet_ns *ns)
+{
+ return ns->bdev ? disk_to_dev(ns->bdev->bd_disk) : NULL;
+}
+
struct nvmet_cq {
u16 qid;
u16 size;
@@ -184,6 +193,9 @@ struct nvmet_ctrl {
char subsysnqn[NVMF_NQN_FIELD_LEN];
char hostnqn[NVMF_NQN_FIELD_LEN];
+
+ struct device *p2p_client;
+ struct radix_tree_root p2p_ns_map;
};
struct nvmet_subsys {
@@ -264,6 +276,7 @@ struct nvmet_fabrics_ops {
};
#define NVMET_MAX_INLINE_BIOVEC 8
+#define NVMET_MAX_INLINE_DATA_LEN NVMET_MAX_INLINE_BIOVEC * PAGE_SIZE
struct nvmet_req {
struct nvme_command *cmd;
@@ -294,6 +307,9 @@ struct nvmet_req {
void (*execute)(struct nvmet_req *req);
const struct nvmet_fabrics_ops *ops;
+
+ struct pci_dev *p2p_dev;
+ struct device *p2p_client;
};
extern struct workqueue_struct *buffered_io_wq;
@@ -336,6 +352,8 @@ bool nvmet_req_init(struct nvmet_req *req, struct nvmet_cq *cq,
void nvmet_req_uninit(struct nvmet_req *req);
void nvmet_req_execute(struct nvmet_req *req);
void nvmet_req_complete(struct nvmet_req *req, u16 status);
+int nvmet_req_alloc_sgl(struct nvmet_req *req);
+void nvmet_req_free_sgl(struct nvmet_req *req);
void nvmet_cq_setup(struct nvmet_ctrl *ctrl, struct nvmet_cq *cq, u16 qid,
u16 size);
diff --git a/drivers/nvme/target/rdma.c b/drivers/nvme/target/rdma.c
index bfc4da660bb4..3f7971d3706d 100644
--- a/drivers/nvme/target/rdma.c
+++ b/drivers/nvme/target/rdma.c
@@ -503,7 +503,7 @@ static void nvmet_rdma_release_rsp(struct nvmet_rdma_rsp *rsp)
}
if (rsp->req.sg != rsp->cmd->inline_sg)
- sgl_free(rsp->req.sg);
+ nvmet_req_free_sgl(&rsp->req);
if (unlikely(!list_empty_careful(&queue->rsp_wr_wait_list)))
nvmet_rdma_process_wr_wait_list(queue);
@@ -652,24 +652,24 @@ static u16 nvmet_rdma_map_sgl_keyed(struct nvmet_rdma_rsp *rsp,
{
struct rdma_cm_id *cm_id = rsp->queue->cm_id;
u64 addr = le64_to_cpu(sgl->addr);
- u32 len = get_unaligned_le24(sgl->length);
u32 key = get_unaligned_le32(sgl->key);
int ret;
+ rsp->req.transfer_len = get_unaligned_le24(sgl->length);
+
/* no data command? */
- if (!len)
+ if (!rsp->req.transfer_len)
return 0;
- rsp->req.sg = sgl_alloc(len, GFP_KERNEL, &rsp->req.sg_cnt);
- if (!rsp->req.sg)
- return NVME_SC_INTERNAL;
+ ret = nvmet_req_alloc_sgl(&rsp->req);
+ if (ret < 0)
+ goto error_out;
ret = rdma_rw_ctx_init(&rsp->rw, cm_id->qp, cm_id->port_num,
rsp->req.sg, rsp->req.sg_cnt, 0, addr, key,
nvmet_data_dir(&rsp->req));
if (ret < 0)
- return NVME_SC_INTERNAL;
- rsp->req.transfer_len += len;
+ goto error_out;
rsp->n_rdma += ret;
if (invalidate) {
@@ -678,6 +678,10 @@ static u16 nvmet_rdma_map_sgl_keyed(struct nvmet_rdma_rsp *rsp,
}
return 0;
+
+error_out:
+ rsp->req.transfer_len = 0;
+ return NVME_SC_INTERNAL;
}
static u16 nvmet_rdma_map_sgl(struct nvmet_rdma_rsp *rsp)
@@ -745,6 +749,8 @@ static void nvmet_rdma_handle_command(struct nvmet_rdma_queue *queue,
cmd->send_sge.addr, cmd->send_sge.length,
DMA_TO_DEVICE);
+ cmd->req.p2p_client = &queue->dev->device->dev;
+
if (!nvmet_req_init(&cmd->req, &queue->nvme_cq,
&queue->nvme_sq, &nvmet_rdma_ops))
return;
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index aa1657831b70..9b18ce90f907 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* nvmem framework core.
*
* Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
* Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/device.h>
@@ -19,6 +11,7 @@
#include <linux/fs.h>
#include <linux/idr.h>
#include <linux/init.h>
+#include <linux/kref.h>
#include <linux/module.h>
#include <linux/nvmem-consumer.h>
#include <linux/nvmem-provider.h>
@@ -26,18 +19,18 @@
#include <linux/slab.h>
struct nvmem_device {
- const char *name;
struct module *owner;
struct device dev;
int stride;
int word_size;
int id;
- int users;
+ struct kref refcnt;
size_t size;
bool read_only;
int flags;
struct bin_attribute eeprom;
struct device *base_dev;
+ struct list_head cells;
nvmem_reg_read_t reg_read;
nvmem_reg_write_t reg_write;
void *priv;
@@ -58,8 +51,13 @@ struct nvmem_cell {
static DEFINE_MUTEX(nvmem_mutex);
static DEFINE_IDA(nvmem_ida);
-static LIST_HEAD(nvmem_cells);
-static DEFINE_MUTEX(nvmem_cells_mutex);
+static DEFINE_MUTEX(nvmem_cell_mutex);
+static LIST_HEAD(nvmem_cell_tables);
+
+static DEFINE_MUTEX(nvmem_lookup_mutex);
+static LIST_HEAD(nvmem_lookup_list);
+
+static BLOCKING_NOTIFIER_HEAD(nvmem_notifier);
#ifdef CONFIG_DEBUG_LOCK_ALLOC
static struct lock_class_key eeprom_lock_key;
@@ -156,7 +154,7 @@ static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj,
static struct bin_attribute bin_attr_rw_nvmem = {
.attr = {
.name = "nvmem",
- .mode = S_IWUSR | S_IRUGO,
+ .mode = 0644,
},
.read = bin_attr_nvmem_read,
.write = bin_attr_nvmem_write,
@@ -180,7 +178,7 @@ static const struct attribute_group *nvmem_rw_dev_groups[] = {
static struct bin_attribute bin_attr_ro_nvmem = {
.attr = {
.name = "nvmem",
- .mode = S_IRUGO,
+ .mode = 0444,
},
.read = bin_attr_nvmem_read,
};
@@ -203,7 +201,7 @@ static const struct attribute_group *nvmem_ro_dev_groups[] = {
static struct bin_attribute bin_attr_rw_root_nvmem = {
.attr = {
.name = "nvmem",
- .mode = S_IWUSR | S_IRUSR,
+ .mode = 0600,
},
.read = bin_attr_nvmem_read,
.write = bin_attr_nvmem_write,
@@ -227,7 +225,7 @@ static const struct attribute_group *nvmem_rw_root_dev_groups[] = {
static struct bin_attribute bin_attr_ro_root_nvmem = {
.attr = {
.name = "nvmem",
- .mode = S_IRUSR,
+ .mode = 0400,
},
.read = bin_attr_nvmem_read,
};
@@ -282,48 +280,42 @@ static struct nvmem_device *of_nvmem_find(struct device_node *nvmem_np)
return to_nvmem_device(d);
}
-static struct nvmem_cell *nvmem_find_cell(const char *cell_id)
+static struct nvmem_device *nvmem_find(const char *name)
{
- struct nvmem_cell *p;
-
- mutex_lock(&nvmem_cells_mutex);
+ struct device *d;
- list_for_each_entry(p, &nvmem_cells, node)
- if (!strcmp(p->name, cell_id)) {
- mutex_unlock(&nvmem_cells_mutex);
- return p;
- }
+ d = bus_find_device_by_name(&nvmem_bus_type, NULL, name);
- mutex_unlock(&nvmem_cells_mutex);
+ if (!d)
+ return NULL;
- return NULL;
+ return to_nvmem_device(d);
}
static void nvmem_cell_drop(struct nvmem_cell *cell)
{
- mutex_lock(&nvmem_cells_mutex);
+ blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_REMOVE, cell);
+ mutex_lock(&nvmem_mutex);
list_del(&cell->node);
- mutex_unlock(&nvmem_cells_mutex);
+ mutex_unlock(&nvmem_mutex);
+ kfree(cell->name);
kfree(cell);
}
static void nvmem_device_remove_all_cells(const struct nvmem_device *nvmem)
{
- struct nvmem_cell *cell;
- struct list_head *p, *n;
+ struct nvmem_cell *cell, *p;
- list_for_each_safe(p, n, &nvmem_cells) {
- cell = list_entry(p, struct nvmem_cell, node);
- if (cell->nvmem == nvmem)
- nvmem_cell_drop(cell);
- }
+ list_for_each_entry_safe(cell, p, &nvmem->cells, node)
+ nvmem_cell_drop(cell);
}
static void nvmem_cell_add(struct nvmem_cell *cell)
{
- mutex_lock(&nvmem_cells_mutex);
- list_add_tail(&cell->node, &nvmem_cells);
- mutex_unlock(&nvmem_cells_mutex);
+ mutex_lock(&nvmem_mutex);
+ list_add_tail(&cell->node, &cell->nvmem->cells);
+ mutex_unlock(&nvmem_mutex);
+ blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_ADD, cell);
}
static int nvmem_cell_info_to_nvmem_cell(struct nvmem_device *nvmem,
@@ -361,7 +353,7 @@ static int nvmem_cell_info_to_nvmem_cell(struct nvmem_device *nvmem,
*
* Return: 0 or negative error code on failure.
*/
-int nvmem_add_cells(struct nvmem_device *nvmem,
+static int nvmem_add_cells(struct nvmem_device *nvmem,
const struct nvmem_cell_info *info,
int ncells)
{
@@ -400,7 +392,6 @@ err:
return rval;
}
-EXPORT_SYMBOL_GPL(nvmem_add_cells);
/*
* nvmem_setup_compat() - Create an additional binary entry in
@@ -440,6 +431,136 @@ static int nvmem_setup_compat(struct nvmem_device *nvmem,
}
/**
+ * nvmem_register_notifier() - Register a notifier block for nvmem events.
+ *
+ * @nb: notifier block to be called on nvmem events.
+ *
+ * Return: 0 on success, negative error number on failure.
+ */
+int nvmem_register_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&nvmem_notifier, nb);
+}
+EXPORT_SYMBOL_GPL(nvmem_register_notifier);
+
+/**
+ * nvmem_unregister_notifier() - Unregister a notifier block for nvmem events.
+ *
+ * @nb: notifier block to be unregistered.
+ *
+ * Return: 0 on success, negative error number on failure.
+ */
+int nvmem_unregister_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_unregister(&nvmem_notifier, nb);
+}
+EXPORT_SYMBOL_GPL(nvmem_unregister_notifier);
+
+static int nvmem_add_cells_from_table(struct nvmem_device *nvmem)
+{
+ const struct nvmem_cell_info *info;
+ struct nvmem_cell_table *table;
+ struct nvmem_cell *cell;
+ int rval = 0, i;
+
+ mutex_lock(&nvmem_cell_mutex);
+ list_for_each_entry(table, &nvmem_cell_tables, node) {
+ if (strcmp(nvmem_dev_name(nvmem), table->nvmem_name) == 0) {
+ for (i = 0; i < table->ncells; i++) {
+ info = &table->cells[i];
+
+ cell = kzalloc(sizeof(*cell), GFP_KERNEL);
+ if (!cell) {
+ rval = -ENOMEM;
+ goto out;
+ }
+
+ rval = nvmem_cell_info_to_nvmem_cell(nvmem,
+ info,
+ cell);
+ if (rval) {
+ kfree(cell);
+ goto out;
+ }
+
+ nvmem_cell_add(cell);
+ }
+ }
+ }
+
+out:
+ mutex_unlock(&nvmem_cell_mutex);
+ return rval;
+}
+
+static struct nvmem_cell *
+nvmem_find_cell_by_name(struct nvmem_device *nvmem, const char *cell_id)
+{
+ struct nvmem_cell *cell = NULL;
+
+ mutex_lock(&nvmem_mutex);
+ list_for_each_entry(cell, &nvmem->cells, node) {
+ if (strcmp(cell_id, cell->name) == 0)
+ break;
+ }
+ mutex_unlock(&nvmem_mutex);
+
+ return cell;
+}
+
+static int nvmem_add_cells_from_of(struct nvmem_device *nvmem)
+{
+ struct device_node *parent, *child;
+ struct device *dev = &nvmem->dev;
+ struct nvmem_cell *cell;
+ const __be32 *addr;
+ int len;
+
+ parent = dev->of_node;
+
+ for_each_child_of_node(parent, child) {
+ addr = of_get_property(child, "reg", &len);
+ if (!addr || (len < 2 * sizeof(u32))) {
+ dev_err(dev, "nvmem: invalid reg on %pOF\n", child);
+ return -EINVAL;
+ }
+
+ cell = kzalloc(sizeof(*cell), GFP_KERNEL);
+ if (!cell)
+ return -ENOMEM;
+
+ cell->nvmem = nvmem;
+ cell->offset = be32_to_cpup(addr++);
+ cell->bytes = be32_to_cpup(addr);
+ cell->name = kasprintf(GFP_KERNEL, "%pOFn", child);
+
+ addr = of_get_property(child, "bits", &len);
+ if (addr && len == (2 * sizeof(u32))) {
+ cell->bit_offset = be32_to_cpup(addr++);
+ cell->nbits = be32_to_cpup(addr);
+ }
+
+ if (cell->nbits)
+ cell->bytes = DIV_ROUND_UP(
+ cell->nbits + cell->bit_offset,
+ BITS_PER_BYTE);
+
+ if (!IS_ALIGNED(cell->offset, nvmem->stride)) {
+ dev_err(dev, "cell %s unaligned to nvmem stride %d\n",
+ cell->name, nvmem->stride);
+ /* Cells already added will be freed later. */
+ kfree(cell->name);
+ kfree(cell);
+ return -EINVAL;
+ }
+
+ nvmem_cell_add(cell);
+ }
+
+ return 0;
+}
+
+/**
* nvmem_register() - Register a nvmem device for given nvmem_config.
* Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem
*
@@ -467,6 +588,9 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
return ERR_PTR(rval);
}
+ kref_init(&nvmem->refcnt);
+ INIT_LIST_HEAD(&nvmem->cells);
+
nvmem->id = rval;
nvmem->owner = config->owner;
if (!nvmem->owner && config->dev->driver)
@@ -516,11 +640,31 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
goto err_device_del;
}
- if (config->cells)
- nvmem_add_cells(nvmem, config->cells, config->ncells);
+ if (config->cells) {
+ rval = nvmem_add_cells(nvmem, config->cells, config->ncells);
+ if (rval)
+ goto err_teardown_compat;
+ }
+
+ rval = nvmem_add_cells_from_table(nvmem);
+ if (rval)
+ goto err_remove_cells;
+
+ rval = nvmem_add_cells_from_of(nvmem);
+ if (rval)
+ goto err_remove_cells;
+
+ rval = blocking_notifier_call_chain(&nvmem_notifier, NVMEM_ADD, nvmem);
+ if (rval)
+ goto err_remove_cells;
return nvmem;
+err_remove_cells:
+ nvmem_device_remove_all_cells(nvmem);
+err_teardown_compat:
+ if (config->compat)
+ device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom);
err_device_del:
device_del(&nvmem->dev);
err_put_device:
@@ -530,21 +674,13 @@ err_put_device:
}
EXPORT_SYMBOL_GPL(nvmem_register);
-/**
- * nvmem_unregister() - Unregister previously registered nvmem device
- *
- * @nvmem: Pointer to previously registered nvmem device.
- *
- * Return: Will be an negative on error or a zero on success.
- */
-int nvmem_unregister(struct nvmem_device *nvmem)
+static void nvmem_device_release(struct kref *kref)
{
- mutex_lock(&nvmem_mutex);
- if (nvmem->users) {
- mutex_unlock(&nvmem_mutex);
- return -EBUSY;
- }
- mutex_unlock(&nvmem_mutex);
+ struct nvmem_device *nvmem;
+
+ nvmem = container_of(kref, struct nvmem_device, refcnt);
+
+ blocking_notifier_call_chain(&nvmem_notifier, NVMEM_REMOVE, nvmem);
if (nvmem->flags & FLAG_COMPAT)
device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom);
@@ -552,14 +688,22 @@ int nvmem_unregister(struct nvmem_device *nvmem)
nvmem_device_remove_all_cells(nvmem);
device_del(&nvmem->dev);
put_device(&nvmem->dev);
+}
- return 0;
+/**
+ * nvmem_unregister() - Unregister previously registered nvmem device
+ *
+ * @nvmem: Pointer to previously registered nvmem device.
+ */
+void nvmem_unregister(struct nvmem_device *nvmem)
+{
+ kref_put(&nvmem->refcnt, nvmem_device_release);
}
EXPORT_SYMBOL_GPL(nvmem_unregister);
static void devm_nvmem_release(struct device *dev, void *res)
{
- WARN_ON(nvmem_unregister(*(struct nvmem_device **)res));
+ nvmem_unregister(*(struct nvmem_device **)res);
}
/**
@@ -617,71 +761,34 @@ int devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem)
}
EXPORT_SYMBOL(devm_nvmem_unregister);
-
static struct nvmem_device *__nvmem_device_get(struct device_node *np,
- struct nvmem_cell **cellp,
- const char *cell_id)
+ const char *nvmem_name)
{
struct nvmem_device *nvmem = NULL;
mutex_lock(&nvmem_mutex);
-
- if (np) {
- nvmem = of_nvmem_find(np);
- if (!nvmem) {
- mutex_unlock(&nvmem_mutex);
- return ERR_PTR(-EPROBE_DEFER);
- }
- } else {
- struct nvmem_cell *cell = nvmem_find_cell(cell_id);
-
- if (cell) {
- nvmem = cell->nvmem;
- *cellp = cell;
- }
-
- if (!nvmem) {
- mutex_unlock(&nvmem_mutex);
- return ERR_PTR(-ENOENT);
- }
- }
-
- nvmem->users++;
+ nvmem = np ? of_nvmem_find(np) : nvmem_find(nvmem_name);
mutex_unlock(&nvmem_mutex);
+ if (!nvmem)
+ return ERR_PTR(-EPROBE_DEFER);
if (!try_module_get(nvmem->owner)) {
dev_err(&nvmem->dev,
"could not increase module refcount for cell %s\n",
- nvmem->name);
-
- mutex_lock(&nvmem_mutex);
- nvmem->users--;
- mutex_unlock(&nvmem_mutex);
+ nvmem_dev_name(nvmem));
return ERR_PTR(-EINVAL);
}
+ kref_get(&nvmem->refcnt);
+
return nvmem;
}
static void __nvmem_device_put(struct nvmem_device *nvmem)
{
module_put(nvmem->owner);
- mutex_lock(&nvmem_mutex);
- nvmem->users--;
- mutex_unlock(&nvmem_mutex);
-}
-
-static struct nvmem_device *nvmem_find(const char *name)
-{
- struct device *d;
-
- d = bus_find_device_by_name(&nvmem_bus_type, NULL, name);
-
- if (!d)
- return NULL;
-
- return to_nvmem_device(d);
+ kref_put(&nvmem->refcnt, nvmem_device_release);
}
#if IS_ENABLED(CONFIG_OF)
@@ -706,7 +813,7 @@ struct nvmem_device *of_nvmem_device_get(struct device_node *np, const char *id)
if (!nvmem_np)
return ERR_PTR(-EINVAL);
- return __nvmem_device_get(nvmem_np, NULL, NULL);
+ return __nvmem_device_get(nvmem_np, NULL);
}
EXPORT_SYMBOL_GPL(of_nvmem_device_get);
#endif
@@ -810,44 +917,86 @@ struct nvmem_device *devm_nvmem_device_get(struct device *dev, const char *id)
}
EXPORT_SYMBOL_GPL(devm_nvmem_device_get);
-static struct nvmem_cell *nvmem_cell_get_from_list(const char *cell_id)
+static struct nvmem_cell *
+nvmem_cell_get_from_lookup(struct device *dev, const char *con_id)
{
- struct nvmem_cell *cell = NULL;
+ struct nvmem_cell *cell = ERR_PTR(-ENOENT);
+ struct nvmem_cell_lookup *lookup;
struct nvmem_device *nvmem;
+ const char *dev_id;
- nvmem = __nvmem_device_get(NULL, &cell, cell_id);
- if (IS_ERR(nvmem))
- return ERR_CAST(nvmem);
+ if (!dev)
+ return ERR_PTR(-EINVAL);
+ dev_id = dev_name(dev);
+
+ mutex_lock(&nvmem_lookup_mutex);
+
+ list_for_each_entry(lookup, &nvmem_lookup_list, node) {
+ if ((strcmp(lookup->dev_id, dev_id) == 0) &&
+ (strcmp(lookup->con_id, con_id) == 0)) {
+ /* This is the right entry. */
+ nvmem = __nvmem_device_get(NULL, lookup->nvmem_name);
+ if (IS_ERR(nvmem)) {
+ /* Provider may not be registered yet. */
+ cell = ERR_CAST(nvmem);
+ goto out;
+ }
+
+ cell = nvmem_find_cell_by_name(nvmem,
+ lookup->cell_name);
+ if (!cell) {
+ __nvmem_device_put(nvmem);
+ cell = ERR_PTR(-ENOENT);
+ goto out;
+ }
+ }
+ }
+
+out:
+ mutex_unlock(&nvmem_lookup_mutex);
return cell;
}
#if IS_ENABLED(CONFIG_OF)
+static struct nvmem_cell *
+nvmem_find_cell_by_index(struct nvmem_device *nvmem, int index)
+{
+ struct nvmem_cell *cell = NULL;
+ int i = 0;
+
+ mutex_lock(&nvmem_mutex);
+ list_for_each_entry(cell, &nvmem->cells, node) {
+ if (index == i++)
+ break;
+ }
+ mutex_unlock(&nvmem_mutex);
+
+ return cell;
+}
+
/**
* of_nvmem_cell_get() - Get a nvmem cell from given device node and cell id
*
* @np: Device tree node that uses the nvmem cell.
- * @name: nvmem cell name from nvmem-cell-names property, or NULL
- * for the cell at index 0 (the lone cell with no accompanying
- * nvmem-cell-names property).
+ * @id: nvmem cell name from nvmem-cell-names property, or NULL
+ * for the cell at index 0 (the lone cell with no accompanying
+ * nvmem-cell-names property).
*
* Return: Will be an ERR_PTR() on error or a valid pointer
* to a struct nvmem_cell. The nvmem_cell will be freed by the
* nvmem_cell_put().
*/
-struct nvmem_cell *of_nvmem_cell_get(struct device_node *np,
- const char *name)
+struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *id)
{
struct device_node *cell_np, *nvmem_np;
- struct nvmem_cell *cell;
struct nvmem_device *nvmem;
- const __be32 *addr;
- int rval, len;
+ struct nvmem_cell *cell;
int index = 0;
/* if cell name exists, find index to the name */
- if (name)
- index = of_property_match_string(np, "nvmem-cell-names", name);
+ if (id)
+ index = of_property_match_string(np, "nvmem-cell-names", id);
cell_np = of_parse_phandle(np, "nvmem-cells", index);
if (!cell_np)
@@ -857,59 +1006,18 @@ struct nvmem_cell *of_nvmem_cell_get(struct device_node *np,
if (!nvmem_np)
return ERR_PTR(-EINVAL);
- nvmem = __nvmem_device_get(nvmem_np, NULL, NULL);
+ nvmem = __nvmem_device_get(nvmem_np, NULL);
of_node_put(nvmem_np);
if (IS_ERR(nvmem))
return ERR_CAST(nvmem);
- addr = of_get_property(cell_np, "reg", &len);
- if (!addr || (len < 2 * sizeof(u32))) {
- dev_err(&nvmem->dev, "nvmem: invalid reg on %pOF\n",
- cell_np);
- rval = -EINVAL;
- goto err_mem;
- }
-
- cell = kzalloc(sizeof(*cell), GFP_KERNEL);
+ cell = nvmem_find_cell_by_index(nvmem, index);
if (!cell) {
- rval = -ENOMEM;
- goto err_mem;
- }
-
- cell->nvmem = nvmem;
- cell->offset = be32_to_cpup(addr++);
- cell->bytes = be32_to_cpup(addr);
- cell->name = cell_np->name;
-
- addr = of_get_property(cell_np, "bits", &len);
- if (addr && len == (2 * sizeof(u32))) {
- cell->bit_offset = be32_to_cpup(addr++);
- cell->nbits = be32_to_cpup(addr);
+ __nvmem_device_put(nvmem);
+ return ERR_PTR(-ENOENT);
}
- if (cell->nbits)
- cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset,
- BITS_PER_BYTE);
-
- if (!IS_ALIGNED(cell->offset, nvmem->stride)) {
- dev_err(&nvmem->dev,
- "cell %s unaligned to nvmem stride %d\n",
- cell->name, nvmem->stride);
- rval = -EINVAL;
- goto err_sanity;
- }
-
- nvmem_cell_add(cell);
-
return cell;
-
-err_sanity:
- kfree(cell);
-
-err_mem:
- __nvmem_device_put(nvmem);
-
- return ERR_PTR(rval);
}
EXPORT_SYMBOL_GPL(of_nvmem_cell_get);
#endif
@@ -918,27 +1026,29 @@ EXPORT_SYMBOL_GPL(of_nvmem_cell_get);
* nvmem_cell_get() - Get nvmem cell of device form a given cell name
*
* @dev: Device that requests the nvmem cell.
- * @cell_id: nvmem cell name to get.
+ * @id: nvmem cell name to get (this corresponds with the name from the
+ * nvmem-cell-names property for DT systems and with the con_id from
+ * the lookup entry for non-DT systems).
*
* Return: Will be an ERR_PTR() on error or a valid pointer
* to a struct nvmem_cell. The nvmem_cell will be freed by the
* nvmem_cell_put().
*/
-struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *cell_id)
+struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *id)
{
struct nvmem_cell *cell;
if (dev->of_node) { /* try dt first */
- cell = of_nvmem_cell_get(dev->of_node, cell_id);
+ cell = of_nvmem_cell_get(dev->of_node, id);
if (!IS_ERR(cell) || PTR_ERR(cell) == -EPROBE_DEFER)
return cell;
}
- /* NULL cell_id only allowed for device tree; invalid otherwise */
- if (!cell_id)
+ /* NULL cell id only allowed for device tree; invalid otherwise */
+ if (!id)
return ERR_PTR(-EINVAL);
- return nvmem_cell_get_from_list(cell_id);
+ return nvmem_cell_get_from_lookup(dev, id);
}
EXPORT_SYMBOL_GPL(nvmem_cell_get);
@@ -1015,7 +1125,6 @@ void nvmem_cell_put(struct nvmem_cell *cell)
struct nvmem_device *nvmem = cell->nvmem;
__nvmem_device_put(nvmem);
- nvmem_cell_drop(cell);
}
EXPORT_SYMBOL_GPL(nvmem_cell_put);
@@ -1267,7 +1376,7 @@ EXPORT_SYMBOL_GPL(nvmem_device_cell_read);
* @buf: buffer to be written to cell.
*
* Return: length of bytes written or negative error code on failure.
- * */
+ */
int nvmem_device_cell_write(struct nvmem_device *nvmem,
struct nvmem_cell_info *info, void *buf)
{
@@ -1323,7 +1432,7 @@ EXPORT_SYMBOL_GPL(nvmem_device_read);
* @buf: buffer to be written.
*
* Return: length of bytes written or negative error code on failure.
- * */
+ */
int nvmem_device_write(struct nvmem_device *nvmem,
unsigned int offset,
size_t bytes, void *buf)
@@ -1343,6 +1452,80 @@ int nvmem_device_write(struct nvmem_device *nvmem,
}
EXPORT_SYMBOL_GPL(nvmem_device_write);
+/**
+ * nvmem_add_cell_table() - register a table of cell info entries
+ *
+ * @table: table of cell info entries
+ */
+void nvmem_add_cell_table(struct nvmem_cell_table *table)
+{
+ mutex_lock(&nvmem_cell_mutex);
+ list_add_tail(&table->node, &nvmem_cell_tables);
+ mutex_unlock(&nvmem_cell_mutex);
+}
+EXPORT_SYMBOL_GPL(nvmem_add_cell_table);
+
+/**
+ * nvmem_del_cell_table() - remove a previously registered cell info table
+ *
+ * @table: table of cell info entries
+ */
+void nvmem_del_cell_table(struct nvmem_cell_table *table)
+{
+ mutex_lock(&nvmem_cell_mutex);
+ list_del(&table->node);
+ mutex_unlock(&nvmem_cell_mutex);
+}
+EXPORT_SYMBOL_GPL(nvmem_del_cell_table);
+
+/**
+ * nvmem_add_cell_lookups() - register a list of cell lookup entries
+ *
+ * @entries: array of cell lookup entries
+ * @nentries: number of cell lookup entries in the array
+ */
+void nvmem_add_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries)
+{
+ int i;
+
+ mutex_lock(&nvmem_lookup_mutex);
+ for (i = 0; i < nentries; i++)
+ list_add_tail(&entries[i].node, &nvmem_lookup_list);
+ mutex_unlock(&nvmem_lookup_mutex);
+}
+EXPORT_SYMBOL_GPL(nvmem_add_cell_lookups);
+
+/**
+ * nvmem_del_cell_lookups() - remove a list of previously added cell lookup
+ * entries
+ *
+ * @entries: array of cell lookup entries
+ * @nentries: number of cell lookup entries in the array
+ */
+void nvmem_del_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries)
+{
+ int i;
+
+ mutex_lock(&nvmem_lookup_mutex);
+ for (i = 0; i < nentries; i++)
+ list_del(&entries[i].node);
+ mutex_unlock(&nvmem_lookup_mutex);
+}
+EXPORT_SYMBOL_GPL(nvmem_del_cell_lookups);
+
+/**
+ * nvmem_dev_name() - Get the name of a given nvmem device.
+ *
+ * @nvmem: nvmem device.
+ *
+ * Return: name of the nvmem device.
+ */
+const char *nvmem_dev_name(struct nvmem_device *nvmem)
+{
+ return dev_name(&nvmem->dev);
+}
+EXPORT_SYMBOL_GPL(nvmem_dev_name);
+
static int __init nvmem_init(void)
{
return bus_register(&nvmem_bus_type);
diff --git a/drivers/nvmem/lpc18xx_eeprom.c b/drivers/nvmem/lpc18xx_eeprom.c
index a9534a6e8636..66cff1e2147a 100644
--- a/drivers/nvmem/lpc18xx_eeprom.c
+++ b/drivers/nvmem/lpc18xx_eeprom.c
@@ -236,7 +236,7 @@ static int lpc18xx_eeprom_probe(struct platform_device *pdev)
lpc18xx_nvmem_config.dev = dev;
lpc18xx_nvmem_config.priv = eeprom;
- eeprom->nvmem = nvmem_register(&lpc18xx_nvmem_config);
+ eeprom->nvmem = devm_nvmem_register(dev, &lpc18xx_nvmem_config);
if (IS_ERR(eeprom->nvmem)) {
ret = PTR_ERR(eeprom->nvmem);
goto err_clk;
@@ -255,11 +255,6 @@ err_clk:
static int lpc18xx_eeprom_remove(struct platform_device *pdev)
{
struct lpc18xx_eeprom_dev *eeprom = platform_get_drvdata(pdev);
- int ret;
-
- ret = nvmem_unregister(eeprom->nvmem);
- if (ret < 0)
- return ret;
clk_disable_unprepare(eeprom->clk);
diff --git a/drivers/nvmem/mxs-ocotp.c b/drivers/nvmem/mxs-ocotp.c
index 7018e2ef5714..53122f59c4b2 100644
--- a/drivers/nvmem/mxs-ocotp.c
+++ b/drivers/nvmem/mxs-ocotp.c
@@ -177,7 +177,7 @@ static int mxs_ocotp_probe(struct platform_device *pdev)
ocotp_config.size = data->size;
ocotp_config.priv = otp;
ocotp_config.dev = dev;
- otp->nvmem = nvmem_register(&ocotp_config);
+ otp->nvmem = devm_nvmem_register(dev, &ocotp_config);
if (IS_ERR(otp->nvmem)) {
ret = PTR_ERR(otp->nvmem);
goto err_clk;
@@ -199,7 +199,7 @@ static int mxs_ocotp_remove(struct platform_device *pdev)
clk_unprepare(otp->clk);
- return nvmem_unregister(otp->nvmem);
+ return 0;
}
static struct platform_driver mxs_ocotp_driver = {
diff --git a/drivers/nvmem/sunxi_sid.c b/drivers/nvmem/sunxi_sid.c
index d020f89248fd..570a2e354f30 100644
--- a/drivers/nvmem/sunxi_sid.c
+++ b/drivers/nvmem/sunxi_sid.c
@@ -154,7 +154,7 @@ static int sunxi_sid_probe(struct platform_device *pdev)
struct resource *res;
struct nvmem_device *nvmem;
struct sunxi_sid *sid;
- int ret, i, size;
+ int i, size;
char *randomness;
const struct sunxi_sid_cfg *cfg;
@@ -181,15 +181,13 @@ static int sunxi_sid_probe(struct platform_device *pdev)
else
econfig.reg_read = sunxi_sid_read;
econfig.priv = sid;
- nvmem = nvmem_register(&econfig);
+ nvmem = devm_nvmem_register(dev, &econfig);
if (IS_ERR(nvmem))
return PTR_ERR(nvmem);
randomness = kzalloc(size, GFP_KERNEL);
- if (!randomness) {
- ret = -EINVAL;
- goto err_unreg_nvmem;
- }
+ if (!randomness)
+ return -ENOMEM;
for (i = 0; i < size; i++)
econfig.reg_read(sid, i, &randomness[i], 1);
@@ -200,17 +198,6 @@ static int sunxi_sid_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, nvmem);
return 0;
-
-err_unreg_nvmem:
- nvmem_unregister(nvmem);
- return ret;
-}
-
-static int sunxi_sid_remove(struct platform_device *pdev)
-{
- struct nvmem_device *nvmem = platform_get_drvdata(pdev);
-
- return nvmem_unregister(nvmem);
}
static const struct sunxi_sid_cfg sun4i_a10_cfg = {
@@ -243,7 +230,6 @@ MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
static struct platform_driver sunxi_sid_driver = {
.probe = sunxi_sid_probe,
- .remove = sunxi_sid_remove,
.driver = {
.name = "eeprom-sunxi-sid",
.of_match_table = sunxi_sid_of_match,
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 74eaedd5b860..09692c9b32a7 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -16,6 +16,7 @@
#define pr_fmt(fmt) "OF: " fmt
+#include <linux/bitmap.h>
#include <linux/console.h>
#include <linux/ctype.h>
#include <linux/cpu.h>
@@ -67,6 +68,7 @@ bool of_node_name_eq(const struct device_node *np, const char *name)
return (strlen(name) == len) && (strncmp(node_name, name, len) == 0);
}
+EXPORT_SYMBOL(of_node_name_eq);
bool of_node_name_prefix(const struct device_node *np, const char *prefix)
{
@@ -75,6 +77,7 @@ bool of_node_name_prefix(const struct device_node *np, const char *prefix)
return strncmp(kbasename(np->full_name), prefix, strlen(prefix)) == 0;
}
+EXPORT_SYMBOL(of_node_name_prefix);
int of_n_addr_cells(struct device_node *np)
{
@@ -330,6 +333,8 @@ static bool __of_find_n_match_cpu_property(struct device_node *cpun,
ac = of_n_addr_cells(cpun);
cell = of_get_property(cpun, prop_name, &prop_len);
+ if (!cell && !ac && arch_match_cpu_phys_id(cpu, 0))
+ return true;
if (!cell || !ac)
return false;
prop_len /= sizeof(*cell) * ac;
@@ -390,7 +395,7 @@ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread)
{
struct device_node *cpun;
- for_each_node_by_type(cpun, "cpu") {
+ for_each_of_cpu_node(cpun) {
if (arch_find_n_match_cpu_physical_id(cpun, cpu, thread))
return cpun;
}
@@ -745,6 +750,43 @@ struct device_node *of_get_next_available_child(const struct device_node *node,
EXPORT_SYMBOL(of_get_next_available_child);
/**
+ * of_get_next_cpu_node - Iterate on cpu nodes
+ * @prev: previous child of the /cpus node, or NULL to get first
+ *
+ * Returns a cpu node pointer with refcount incremented, use of_node_put()
+ * on it when done. Returns NULL when prev is the last child. Decrements
+ * the refcount of prev.
+ */
+struct device_node *of_get_next_cpu_node(struct device_node *prev)
+{
+ struct device_node *next = NULL;
+ unsigned long flags;
+ struct device_node *node;
+
+ if (!prev)
+ node = of_find_node_by_path("/cpus");
+
+ raw_spin_lock_irqsave(&devtree_lock, flags);
+ if (prev)
+ next = prev->sibling;
+ else if (node) {
+ next = node->child;
+ of_node_put(node);
+ }
+ for (; next; next = next->sibling) {
+ if (!(of_node_name_eq(next, "cpu") ||
+ (next->type && !of_node_cmp(next->type, "cpu"))))
+ continue;
+ if (of_node_get(next))
+ break;
+ }
+ of_node_put(prev);
+ raw_spin_unlock_irqrestore(&devtree_lock, flags);
+ return next;
+}
+EXPORT_SYMBOL(of_get_next_cpu_node);
+
+/**
* of_get_compatible_child - Find compatible child node
* @parent: parent node
* @compatible: compatible string
@@ -1943,6 +1985,59 @@ int of_alias_get_id(struct device_node *np, const char *stem)
EXPORT_SYMBOL_GPL(of_alias_get_id);
/**
+ * of_alias_get_alias_list - Get alias list for the given device driver
+ * @matches: Array of OF device match structures to search in
+ * @stem: Alias stem of the given device_node
+ * @bitmap: Bitmap field pointer
+ * @nbits: Maximum number of alias IDs which can be recorded in bitmap
+ *
+ * The function travels the lookup table to record alias ids for the given
+ * device match structures and alias stem.
+ *
+ * Return: 0 or -ENOSYS when !CONFIG_OF or
+ * -EOVERFLOW if alias ID is greater then allocated nbits
+ */
+int of_alias_get_alias_list(const struct of_device_id *matches,
+ const char *stem, unsigned long *bitmap,
+ unsigned int nbits)
+{
+ struct alias_prop *app;
+ int ret = 0;
+
+ /* Zero bitmap field to make sure that all the time it is clean */
+ bitmap_zero(bitmap, nbits);
+
+ mutex_lock(&of_mutex);
+ pr_debug("%s: Looking for stem: %s\n", __func__, stem);
+ list_for_each_entry(app, &aliases_lookup, link) {
+ pr_debug("%s: stem: %s, id: %d\n",
+ __func__, app->stem, app->id);
+
+ if (strcmp(app->stem, stem) != 0) {
+ pr_debug("%s: stem comparison didn't pass %s\n",
+ __func__, app->stem);
+ continue;
+ }
+
+ if (of_match_node(matches, app->np)) {
+ pr_debug("%s: Allocated ID %d\n", __func__, app->id);
+
+ if (app->id >= nbits) {
+ pr_warn("%s: ID %d >= than bitmap field %d\n",
+ __func__, app->id, nbits);
+ ret = -EOVERFLOW;
+ } else {
+ set_bit(app->id, bitmap);
+ }
+ }
+ }
+ mutex_unlock(&of_mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(of_alias_get_alias_list);
+
+/**
* of_alias_get_highest_id - Get highest alias id for the given stem
* @stem: Alias stem to be examined
*
@@ -2013,7 +2108,7 @@ struct device_node *of_find_next_cache_node(const struct device_node *np)
/* OF on pmac has nodes instead of properties named "l2-cache"
* beneath CPU nodes.
*/
- if (!strcmp(np->type, "cpu"))
+ if (IS_ENABLED(CONFIG_PPC_PMAC) && !strcmp(np->type, "cpu"))
for_each_child_of_node(np, child)
if (!strcmp(child->type, "cache"))
return child;
@@ -2045,3 +2140,105 @@ int of_find_last_cache_level(unsigned int cpu)
return cache_level;
}
+
+/**
+ * of_map_rid - Translate a requester ID through a downstream mapping.
+ * @np: root complex device node.
+ * @rid: device requester ID to map.
+ * @map_name: property name of the map to use.
+ * @map_mask_name: optional property name of the mask to use.
+ * @target: optional pointer to a target device node.
+ * @id_out: optional pointer to receive the translated ID.
+ *
+ * Given a device requester ID, look up the appropriate implementation-defined
+ * platform ID and/or the target device which receives transactions on that
+ * ID, as per the "iommu-map" and "msi-map" bindings. Either of @target or
+ * @id_out may be NULL if only the other is required. If @target points to
+ * a non-NULL device node pointer, only entries targeting that node will be
+ * matched; if it points to a NULL value, it will receive the device node of
+ * the first matching target phandle, with a reference held.
+ *
+ * Return: 0 on success or a standard error code on failure.
+ */
+int of_map_rid(struct device_node *np, u32 rid,
+ const char *map_name, const char *map_mask_name,
+ struct device_node **target, u32 *id_out)
+{
+ u32 map_mask, masked_rid;
+ int map_len;
+ const __be32 *map = NULL;
+
+ if (!np || !map_name || (!target && !id_out))
+ return -EINVAL;
+
+ map = of_get_property(np, map_name, &map_len);
+ if (!map) {
+ if (target)
+ return -ENODEV;
+ /* Otherwise, no map implies no translation */
+ *id_out = rid;
+ return 0;
+ }
+
+ if (!map_len || map_len % (4 * sizeof(*map))) {
+ pr_err("%pOF: Error: Bad %s length: %d\n", np,
+ map_name, map_len);
+ return -EINVAL;
+ }
+
+ /* The default is to select all bits. */
+ map_mask = 0xffffffff;
+
+ /*
+ * Can be overridden by "{iommu,msi}-map-mask" property.
+ * If of_property_read_u32() fails, the default is used.
+ */
+ if (map_mask_name)
+ of_property_read_u32(np, map_mask_name, &map_mask);
+
+ masked_rid = map_mask & rid;
+ for ( ; map_len > 0; map_len -= 4 * sizeof(*map), map += 4) {
+ struct device_node *phandle_node;
+ u32 rid_base = be32_to_cpup(map + 0);
+ u32 phandle = be32_to_cpup(map + 1);
+ u32 out_base = be32_to_cpup(map + 2);
+ u32 rid_len = be32_to_cpup(map + 3);
+
+ if (rid_base & ~map_mask) {
+ pr_err("%pOF: Invalid %s translation - %s-mask (0x%x) ignores rid-base (0x%x)\n",
+ np, map_name, map_name,
+ map_mask, rid_base);
+ return -EFAULT;
+ }
+
+ if (masked_rid < rid_base || masked_rid >= rid_base + rid_len)
+ continue;
+
+ phandle_node = of_find_node_by_phandle(phandle);
+ if (!phandle_node)
+ return -ENODEV;
+
+ if (target) {
+ if (*target)
+ of_node_put(phandle_node);
+ else
+ *target = phandle_node;
+
+ if (*target != phandle_node)
+ continue;
+ }
+
+ if (id_out)
+ *id_out = masked_rid - rid_base + out_base;
+
+ pr_debug("%pOF: %s, using mask %08x, rid-base: %08x, out-base: %08x, length: %08x, rid: %08x -> %08x\n",
+ np, map_name, map_mask, rid_base, out_base,
+ rid_len, rid, masked_rid - rid_base + out_base);
+ return 0;
+ }
+
+ pr_err("%pOF: Invalid %s translation - no match for rid 0x%x on %pOF\n",
+ np, map_name, rid, target && *target ? *target : NULL);
+ return -EFAULT;
+}
+EXPORT_SYMBOL_GPL(of_map_rid);
diff --git a/drivers/of/device.c b/drivers/of/device.c
index 5957cd4fa262..5592437bb3d1 100644
--- a/drivers/of/device.c
+++ b/drivers/of/device.c
@@ -149,9 +149,11 @@ int of_dma_configure(struct device *dev, struct device_node *np, bool force_dma)
* set by the driver.
*/
mask = DMA_BIT_MASK(ilog2(dma_addr + size - 1) + 1);
- dev->bus_dma_mask = mask;
dev->coherent_dma_mask &= mask;
*dev->dma_mask &= mask;
+ /* ...but only set bus mask if we found valid dma-ranges earlier */
+ if (!ret)
+ dev->bus_dma_mask = mask;
coherent = of_dma_is_coherent(np);
dev_dbg(dev, "device is%sdma coherent\n",
@@ -170,18 +172,6 @@ int of_dma_configure(struct device *dev, struct device_node *np, bool force_dma)
}
EXPORT_SYMBOL_GPL(of_dma_configure);
-/**
- * of_dma_deconfigure - Clean up DMA configuration
- * @dev: Device for which to clean up DMA configuration
- *
- * Clean up all configuration performed by of_dma_configure_ops() and free all
- * resources that have been allocated.
- */
-void of_dma_deconfigure(struct device *dev)
-{
- arch_teardown_dma_ops(dev);
-}
-
int of_device_register(struct platform_device *pdev)
{
device_initialize(&pdev->dev);
@@ -219,7 +209,8 @@ static ssize_t of_device_get_modalias(struct device *dev, char *str, ssize_t len
return -ENODEV;
/* Name & Type */
- csize = snprintf(str, len, "of:N%sT%s", dev->of_node->name,
+ /* %p eats all alphanum characters, so %c must be used here */
+ csize = snprintf(str, len, "of:N%pOFn%c%s", dev->of_node, 'T',
dev->of_node->type);
tsize = csize;
len -= csize;
@@ -298,7 +289,7 @@ void of_device_uevent(struct device *dev, struct kobj_uevent_env *env)
if ((!dev) || (!dev->of_node))
return;
- add_uevent_var(env, "OF_NAME=%s", dev->of_node->name);
+ add_uevent_var(env, "OF_NAME=%pOFn", dev->of_node);
add_uevent_var(env, "OF_FULLNAME=%pOF", dev->of_node);
if (dev->of_node->type && strcmp("<NULL>", dev->of_node->type) != 0)
add_uevent_var(env, "OF_TYPE=%s", dev->of_node->type);
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 800ad252cf9c..bb532aae0d92 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -11,7 +11,6 @@
#include <linux/crc32.h>
#include <linux/kernel.h>
#include <linux/initrd.h>
-#include <linux/bootmem.h>
#include <linux/memblock.h>
#include <linux/mutex.h>
#include <linux/of.h>
@@ -1115,7 +1114,6 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
return 1;
}
-#ifdef CONFIG_HAVE_MEMBLOCK
#ifndef MIN_MEMBLOCK_ADDR
#define MIN_MEMBLOCK_ADDR __pa(PAGE_OFFSET)
#endif
@@ -1127,12 +1125,13 @@ void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
{
const u64 phys_offset = MIN_MEMBLOCK_ADDR;
+ if (size < PAGE_SIZE - (base & ~PAGE_MASK)) {
+ pr_warn("Ignoring memory block 0x%llx - 0x%llx\n",
+ base, base + size);
+ return;
+ }
+
if (!PAGE_ALIGNED(base)) {
- if (size < PAGE_SIZE - (base & ~PAGE_MASK)) {
- pr_warn("Ignoring memory block 0x%llx - 0x%llx\n",
- base, base + size);
- return;
- }
size -= PAGE_SIZE - (base & ~PAGE_MASK);
base = PAGE_ALIGN(base);
}
@@ -1177,29 +1176,9 @@ int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base,
return memblock_reserve(base, size);
}
-#else
-void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
-{
- WARN_ON(1);
-}
-
-int __init __weak early_init_dt_mark_hotplug_memory_arch(u64 base, u64 size)
-{
- return -ENOSYS;
-}
-
-int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base,
- phys_addr_t size, bool nomap)
-{
- pr_err("Reserved memory not supported, ignoring range %pa - %pa%s\n",
- &base, &size, nomap ? " (nomap)" : "");
- return -ENOSYS;
-}
-#endif
-
static void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
{
- return memblock_virt_alloc(size, align);
+ return memblock_alloc(size, align);
}
bool __init early_init_dt_verify(void *params)
diff --git a/drivers/of/irq.c b/drivers/of/irq.c
index 02ad93a304a4..e1f6f392a4c0 100644
--- a/drivers/of/irq.c
+++ b/drivers/of/irq.c
@@ -22,7 +22,6 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
-#include <linux/of_pci.h>
#include <linux/string.h>
#include <linux/slab.h>
@@ -588,8 +587,8 @@ static u32 __of_msi_map_rid(struct device *dev, struct device_node **np,
* "msi-map" property.
*/
for (parent_dev = dev; parent_dev; parent_dev = parent_dev->parent)
- if (!of_pci_map_rid(parent_dev->of_node, rid_in, "msi-map",
- "msi-map-mask", np, &rid_out))
+ if (!of_map_rid(parent_dev->of_node, rid_in, "msi-map",
+ "msi-map-mask", np, &rid_out))
break;
return rid_out;
}
diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c
index e92391d6d1bd..5ad1342f5682 100644
--- a/drivers/of/of_mdio.c
+++ b/drivers/of/of_mdio.c
@@ -97,8 +97,8 @@ static int of_mdiobus_register_phy(struct mii_bus *mdio,
return rc;
}
- dev_dbg(&mdio->dev, "registered phy %s at address %i\n",
- child->name, addr);
+ dev_dbg(&mdio->dev, "registered phy %pOFn at address %i\n",
+ child, addr);
return 0;
}
@@ -127,8 +127,8 @@ static int of_mdiobus_register_device(struct mii_bus *mdio,
return rc;
}
- dev_dbg(&mdio->dev, "registered mdio device %s at address %i\n",
- child->name, addr);
+ dev_dbg(&mdio->dev, "registered mdio device %pOFn at address %i\n",
+ child, addr);
return 0;
}
@@ -263,8 +263,8 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
continue;
/* be noisy to encourage people to set reg property */
- dev_info(&mdio->dev, "scan phy %s at address %i\n",
- child->name, addr);
+ dev_info(&mdio->dev, "scan phy %pOFn at address %i\n",
+ child, addr);
if (of_mdiobus_child_is_phy(child)) {
rc = of_mdiobus_register_phy(mdio, child, addr);
diff --git a/drivers/of/of_numa.c b/drivers/of/of_numa.c
index 27d9b4bba535..fe6b13608e51 100644
--- a/drivers/of/of_numa.c
+++ b/drivers/of/of_numa.c
@@ -24,18 +24,9 @@ static void __init of_numa_parse_cpu_nodes(void)
{
u32 nid;
int r;
- struct device_node *cpus;
- struct device_node *np = NULL;
-
- cpus = of_find_node_by_path("/cpus");
- if (!cpus)
- return;
-
- for_each_child_of_node(cpus, np) {
- /* Skip things that are not CPUs */
- if (of_node_cmp(np->type, "cpu") != 0)
- continue;
+ struct device_node *np;
+ for_each_of_cpu_node(np) {
r = of_property_read_u32(np, "numa-node-id", &nid);
if (r)
continue;
@@ -46,8 +37,6 @@ static void __init of_numa_parse_cpu_nodes(void)
else
node_set(nid, numa_nodes_parsed);
}
-
- of_node_put(cpus);
}
static int __init of_numa_parse_memory_nodes(void)
@@ -115,9 +104,14 @@ static int __init of_numa_parse_distance_map_v1(struct device_node *map)
distance = of_read_number(matrix, 1);
matrix++;
+ if ((nodea == nodeb && distance != LOCAL_DISTANCE) ||
+ (nodea != nodeb && distance <= LOCAL_DISTANCE)) {
+ pr_err("Invalid distance[node%d -> node%d] = %d\n",
+ nodea, nodeb, distance);
+ return -EINVAL;
+ }
+
numa_set_distance(nodea, nodeb, distance);
- pr_debug("distance[node%d -> node%d] = %d\n",
- nodea, nodeb, distance);
/* Set default distance of node B->A same as A->B */
if (nodeb > nodea)
@@ -163,8 +157,8 @@ int of_node_to_nid(struct device_node *device)
np = of_get_next_parent(np);
}
if (np && r)
- pr_warn("Invalid \"numa-node-id\" property in node %s\n",
- np->name);
+ pr_warn("Invalid \"numa-node-id\" property in node %pOFn\n",
+ np);
of_node_put(np);
/*
diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h
index 216175d11d3d..5d1567025358 100644
--- a/drivers/of/of_private.h
+++ b/drivers/of/of_private.h
@@ -27,6 +27,14 @@ struct alias_prop {
char stem[0];
};
+#if defined(CONFIG_SPARC)
+#define OF_ROOT_NODE_ADDR_CELLS_DEFAULT 2
+#else
+#define OF_ROOT_NODE_ADDR_CELLS_DEFAULT 1
+#endif
+
+#define OF_ROOT_NODE_SIZE_CELLS_DEFAULT 1
+
extern struct mutex of_mutex;
extern struct list_head aliases_lookup;
extern struct kset *of_kset;
diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
index 895c83e0c7b6..1977ee0adcb1 100644
--- a/drivers/of/of_reserved_mem.c
+++ b/drivers/of/of_reserved_mem.c
@@ -20,13 +20,12 @@
#include <linux/of_reserved_mem.h>
#include <linux/sort.h>
#include <linux/slab.h>
+#include <linux/memblock.h>
#define MAX_RESERVED_REGIONS 32
static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS];
static int reserved_mem_count;
-#if defined(CONFIG_HAVE_MEMBLOCK)
-#include <linux/memblock.h>
int __init __weak early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
phys_addr_t align, phys_addr_t start, phys_addr_t end, bool nomap,
phys_addr_t *res_base)
@@ -37,6 +36,7 @@ int __init __weak early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
* panic()s on allocation failure.
*/
end = !end ? MEMBLOCK_ALLOC_ANYWHERE : end;
+ align = !align ? SMP_CACHE_BYTES : align;
base = __memblock_alloc_base(size, align, end);
if (!base)
return -ENOMEM;
@@ -54,16 +54,6 @@ int __init __weak early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
return memblock_remove(base, size);
return 0;
}
-#else
-int __init __weak early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
- phys_addr_t align, phys_addr_t start, phys_addr_t end, bool nomap,
- phys_addr_t *res_base)
-{
- pr_err("Reserved memory not supported, ignoring region 0x%llx%s\n",
- size, nomap ? " (nomap)" : "");
- return -ENOSYS;
-}
-#endif
/**
* res_mem_save_node() - save fdt node for second pass initialization
diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
index eda57ef12fd0..42b1f73ac5f6 100644
--- a/drivers/of/overlay.c
+++ b/drivers/of/overlay.c
@@ -425,8 +425,8 @@ static int build_changeset_next_level(struct overlay_changeset *ovcs,
for_each_child_of_node(overlay_node, child) {
ret = add_changeset_node(ovcs, target_node, child);
if (ret) {
- pr_debug("Failed to apply node @%pOF/%s, err=%d\n",
- target_node, child->name, ret);
+ pr_debug("Failed to apply node @%pOF/%pOFn, err=%d\n",
+ target_node, child, ret);
of_node_put(child);
return ret;
}
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 6c59673933e9..04ad312fd85b 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -91,8 +91,8 @@ static void of_device_make_bus_id(struct device *dev)
*/
reg = of_get_property(node, "reg", NULL);
if (reg && (addr = of_translate_address(node, reg)) != OF_BAD_ADDR) {
- dev_set_name(dev, dev_name(dev) ? "%llx.%s:%s" : "%llx.%s",
- (unsigned long long)addr, node->name,
+ dev_set_name(dev, dev_name(dev) ? "%llx.%pOFn:%s" : "%llx.%pOFn",
+ (unsigned long long)addr, node,
dev_name(dev));
return;
}
@@ -142,8 +142,8 @@ struct platform_device *of_device_alloc(struct device_node *np,
WARN_ON(rc);
}
if (of_irq_to_resource_table(np, res, num_irq) != num_irq)
- pr_debug("not all legacy IRQ resources mapped for %s\n",
- np->name);
+ pr_debug("not all legacy IRQ resources mapped for %pOFn\n",
+ np);
}
dev->dev.of_node = of_node_get(np);
diff --git a/drivers/of/unittest-data/overlay_15.dts b/drivers/of/unittest-data/overlay_15.dts
index b98f2514df4b..5728490474f6 100644
--- a/drivers/of/unittest-data/overlay_15.dts
+++ b/drivers/of/unittest-data/overlay_15.dts
@@ -20,8 +20,8 @@
#size-cells = <0>;
reg = <0>;
- test-mux-dev {
- reg = <32>;
+ test-mux-dev@20 {
+ reg = <0x20>;
compatible = "unittest-i2c-dev";
status = "okay";
};
diff --git a/drivers/of/unittest-data/tests-overlay.dtsi b/drivers/of/unittest-data/tests-overlay.dtsi
index 25cf397b8f6b..4ea024d908ee 100644
--- a/drivers/of/unittest-data/tests-overlay.dtsi
+++ b/drivers/of/unittest-data/tests-overlay.dtsi
@@ -103,8 +103,8 @@
#size-cells = <0>;
reg = <0>;
- test-mux-dev {
- reg = <32>;
+ test-mux-dev@20 {
+ reg = <0x20>;
compatible = "unittest-i2c-dev";
status = "okay";
};
diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
index 722537e14848..49ae2aa744d6 100644
--- a/drivers/of/unittest.c
+++ b/drivers/of/unittest.c
@@ -5,7 +5,7 @@
#define pr_fmt(fmt) "### dt-test ### " fmt
-#include <linux/bootmem.h>
+#include <linux/memblock.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/errno.h>
@@ -212,8 +212,8 @@ static int __init of_unittest_check_node_linkage(struct device_node *np)
for_each_child_of_node(np, child) {
if (child->parent != np) {
- pr_err("Child node %s links to wrong parent %s\n",
- child->name, np->name);
+ pr_err("Child node %pOFn links to wrong parent %pOFn\n",
+ child, np);
rc = -EINVAL;
goto put_child;
}
@@ -299,6 +299,10 @@ static void __init of_unittest_printf(void)
of_unittest_printf_one(np, "%pOF", full_name);
of_unittest_printf_one(np, "%pOFf", full_name);
+ of_unittest_printf_one(np, "%pOFn", "dev");
+ of_unittest_printf_one(np, "%2pOFn", "dev");
+ of_unittest_printf_one(np, "%5pOFn", " dev");
+ of_unittest_printf_one(np, "%pOFnc", "dev:test-sub-device");
of_unittest_printf_one(np, "%pOFp", phandle_str);
of_unittest_printf_one(np, "%pOFP", "dev@100");
of_unittest_printf_one(np, "ABC %pOFP ABC", "ABC dev@100 ABC");
@@ -771,6 +775,9 @@ static void __init of_unittest_parse_interrupts(void)
struct of_phandle_args args;
int i, rc;
+ if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)
+ return;
+
np = of_find_node_by_path("/testcase-data/interrupts/interrupts0");
if (!np) {
pr_err("missing testcase data\n");
@@ -845,6 +852,9 @@ static void __init of_unittest_parse_interrupts_extended(void)
struct of_phandle_args args;
int i, rc;
+ if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)
+ return;
+
np = of_find_node_by_path("/testcase-data/interrupts/interrupts-extended0");
if (!np) {
pr_err("missing testcase data\n");
@@ -1001,15 +1011,19 @@ static void __init of_unittest_platform_populate(void)
pdev = of_find_device_by_node(np);
unittest(pdev, "device 1 creation failed\n");
- irq = platform_get_irq(pdev, 0);
- unittest(irq == -EPROBE_DEFER, "device deferred probe failed - %d\n", irq);
+ if (!(of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)) {
+ irq = platform_get_irq(pdev, 0);
+ unittest(irq == -EPROBE_DEFER,
+ "device deferred probe failed - %d\n", irq);
- /* Test that a parsing failure does not return -EPROBE_DEFER */
- np = of_find_node_by_path("/testcase-data/testcase-device2");
- pdev = of_find_device_by_node(np);
- unittest(pdev, "device 2 creation failed\n");
- irq = platform_get_irq(pdev, 0);
- unittest(irq < 0 && irq != -EPROBE_DEFER, "device parsing error failed - %d\n", irq);
+ /* Test that a parsing failure does not return -EPROBE_DEFER */
+ np = of_find_node_by_path("/testcase-data/testcase-device2");
+ pdev = of_find_device_by_node(np);
+ unittest(pdev, "device 2 creation failed\n");
+ irq = platform_get_irq(pdev, 0);
+ unittest(irq < 0 && irq != -EPROBE_DEFER,
+ "device parsing error failed - %d\n", irq);
+ }
np = of_find_node_by_path("/testcase-data/platform-tests");
unittest(np, "No testcase data in device tree\n");
@@ -1036,16 +1050,16 @@ static void __init of_unittest_platform_populate(void)
for_each_child_of_node(np, child) {
for_each_child_of_node(child, grandchild)
unittest(of_find_device_by_node(grandchild),
- "Could not create device for node '%s'\n",
- grandchild->name);
+ "Could not create device for node '%pOFn'\n",
+ grandchild);
}
of_platform_depopulate(&test_bus->dev);
for_each_child_of_node(np, child) {
for_each_child_of_node(child, grandchild)
unittest(!of_find_device_by_node(grandchild),
- "device didn't get destroyed '%s'\n",
- grandchild->name);
+ "device didn't get destroyed '%pOFn'\n",
+ grandchild);
}
platform_device_unregister(test_bus);
@@ -2178,7 +2192,7 @@ static struct device_node *overlay_base_root;
static void * __init dt_alloc_memory(u64 size, u64 align)
{
- return memblock_virt_alloc(size, align);
+ return memblock_alloc(size, align);
}
/*
@@ -2347,11 +2361,14 @@ static __init void of_unittest_overlay_high_level(void)
}
}
- for (np = overlay_base_root->child; np; np = np->sibling) {
- if (of_get_child_by_name(of_root, np->name)) {
- unittest(0, "illegal node name in overlay_base %s",
- np->name);
- return;
+ for_each_child_of_node(overlay_base_root, np) {
+ struct device_node *base_child;
+ for_each_child_of_node(of_root, base_child) {
+ if (!strcmp(np->full_name, base_child->full_name)) {
+ unittest(0, "illegal node name in overlay_base %pOFn",
+ np);
+ return;
+ }
}
}
diff --git a/drivers/opp/core.c b/drivers/opp/core.c
index 31ff03dbeb83..2c2df4e4fc14 100644
--- a/drivers/opp/core.c
+++ b/drivers/opp/core.c
@@ -48,9 +48,14 @@ static struct opp_device *_find_opp_dev(const struct device *dev,
static struct opp_table *_find_opp_table_unlocked(struct device *dev)
{
struct opp_table *opp_table;
+ bool found;
list_for_each_entry(opp_table, &opp_tables, node) {
- if (_find_opp_dev(dev, opp_table)) {
+ mutex_lock(&opp_table->lock);
+ found = !!_find_opp_dev(dev, opp_table);
+ mutex_unlock(&opp_table->lock);
+
+ if (found) {
_get_opp_table_kref(opp_table);
return opp_table;
@@ -313,7 +318,7 @@ int dev_pm_opp_get_opp_count(struct device *dev)
count = PTR_ERR(opp_table);
dev_dbg(dev, "%s: OPP table not found (%d)\n",
__func__, count);
- return 0;
+ return count;
}
count = _get_opp_count(opp_table);
@@ -754,8 +759,8 @@ static void _remove_opp_dev(struct opp_device *opp_dev,
kfree(opp_dev);
}
-struct opp_device *_add_opp_dev(const struct device *dev,
- struct opp_table *opp_table)
+static struct opp_device *_add_opp_dev_unlocked(const struct device *dev,
+ struct opp_table *opp_table)
{
struct opp_device *opp_dev;
int ret;
@@ -766,6 +771,7 @@ struct opp_device *_add_opp_dev(const struct device *dev,
/* Initialize opp-dev */
opp_dev->dev = dev;
+
list_add(&opp_dev->node, &opp_table->dev_list);
/* Create debugfs entries for the opp_table */
@@ -777,7 +783,19 @@ struct opp_device *_add_opp_dev(const struct device *dev,
return opp_dev;
}
-static struct opp_table *_allocate_opp_table(struct device *dev)
+struct opp_device *_add_opp_dev(const struct device *dev,
+ struct opp_table *opp_table)
+{
+ struct opp_device *opp_dev;
+
+ mutex_lock(&opp_table->lock);
+ opp_dev = _add_opp_dev_unlocked(dev, opp_table);
+ mutex_unlock(&opp_table->lock);
+
+ return opp_dev;
+}
+
+static struct opp_table *_allocate_opp_table(struct device *dev, int index)
{
struct opp_table *opp_table;
struct opp_device *opp_dev;
@@ -791,6 +809,7 @@ static struct opp_table *_allocate_opp_table(struct device *dev)
if (!opp_table)
return NULL;
+ mutex_init(&opp_table->lock);
INIT_LIST_HEAD(&opp_table->dev_list);
opp_dev = _add_opp_dev(dev, opp_table);
@@ -799,7 +818,7 @@ static struct opp_table *_allocate_opp_table(struct device *dev)
return NULL;
}
- _of_init_opp_table(opp_table, dev);
+ _of_init_opp_table(opp_table, dev, index);
/* Find clk for the device */
opp_table->clk = clk_get(dev, NULL);
@@ -812,7 +831,6 @@ static struct opp_table *_allocate_opp_table(struct device *dev)
BLOCKING_INIT_NOTIFIER_HEAD(&opp_table->head);
INIT_LIST_HEAD(&opp_table->opp_list);
- mutex_init(&opp_table->lock);
kref_init(&opp_table->kref);
/* Secure the device table modification */
@@ -825,7 +843,7 @@ void _get_opp_table_kref(struct opp_table *opp_table)
kref_get(&opp_table->kref);
}
-struct opp_table *dev_pm_opp_get_opp_table(struct device *dev)
+static struct opp_table *_opp_get_opp_table(struct device *dev, int index)
{
struct opp_table *opp_table;
@@ -836,31 +854,56 @@ struct opp_table *dev_pm_opp_get_opp_table(struct device *dev)
if (!IS_ERR(opp_table))
goto unlock;
- opp_table = _allocate_opp_table(dev);
+ opp_table = _managed_opp(dev, index);
+ if (opp_table) {
+ if (!_add_opp_dev_unlocked(dev, opp_table)) {
+ dev_pm_opp_put_opp_table(opp_table);
+ opp_table = NULL;
+ }
+ goto unlock;
+ }
+
+ opp_table = _allocate_opp_table(dev, index);
unlock:
mutex_unlock(&opp_table_lock);
return opp_table;
}
+
+struct opp_table *dev_pm_opp_get_opp_table(struct device *dev)
+{
+ return _opp_get_opp_table(dev, 0);
+}
EXPORT_SYMBOL_GPL(dev_pm_opp_get_opp_table);
+struct opp_table *dev_pm_opp_get_opp_table_indexed(struct device *dev,
+ int index)
+{
+ return _opp_get_opp_table(dev, index);
+}
+
static void _opp_table_kref_release(struct kref *kref)
{
struct opp_table *opp_table = container_of(kref, struct opp_table, kref);
- struct opp_device *opp_dev;
+ struct opp_device *opp_dev, *temp;
/* Release clk */
if (!IS_ERR(opp_table->clk))
clk_put(opp_table->clk);
- opp_dev = list_first_entry(&opp_table->dev_list, struct opp_device,
- node);
+ WARN_ON(!list_empty(&opp_table->opp_list));
- _remove_opp_dev(opp_dev, opp_table);
+ list_for_each_entry_safe(opp_dev, temp, &opp_table->dev_list, node) {
+ /*
+ * The OPP table is getting removed, drop the performance state
+ * constraints.
+ */
+ if (opp_table->genpd_performance_state)
+ dev_pm_genpd_set_performance_state((struct device *)(opp_dev->dev), 0);
- /* dev_list must be empty now */
- WARN_ON(!list_empty(&opp_table->dev_list));
+ _remove_opp_dev(opp_dev, opp_table);
+ }
mutex_destroy(&opp_table->lock);
list_del(&opp_table->node);
@@ -869,6 +912,33 @@ static void _opp_table_kref_release(struct kref *kref)
mutex_unlock(&opp_table_lock);
}
+void _opp_remove_all_static(struct opp_table *opp_table)
+{
+ struct dev_pm_opp *opp, *tmp;
+
+ list_for_each_entry_safe(opp, tmp, &opp_table->opp_list, node) {
+ if (!opp->dynamic)
+ dev_pm_opp_put(opp);
+ }
+
+ opp_table->parsed_static_opps = false;
+}
+
+static void _opp_table_list_kref_release(struct kref *kref)
+{
+ struct opp_table *opp_table = container_of(kref, struct opp_table,
+ list_kref);
+
+ _opp_remove_all_static(opp_table);
+ mutex_unlock(&opp_table_lock);
+}
+
+void _put_opp_list_kref(struct opp_table *opp_table)
+{
+ kref_put_mutex(&opp_table->list_kref, _opp_table_list_kref_release,
+ &opp_table_lock);
+}
+
void dev_pm_opp_put_opp_table(struct opp_table *opp_table)
{
kref_put_mutex(&opp_table->kref, _opp_table_kref_release,
@@ -896,7 +966,6 @@ static void _opp_kref_release(struct kref *kref)
kfree(opp);
mutex_unlock(&opp_table->lock);
- dev_pm_opp_put_opp_table(opp_table);
}
void dev_pm_opp_get(struct dev_pm_opp *opp)
@@ -940,11 +1009,15 @@ void dev_pm_opp_remove(struct device *dev, unsigned long freq)
if (found) {
dev_pm_opp_put(opp);
+
+ /* Drop the reference taken by dev_pm_opp_add() */
+ dev_pm_opp_put_opp_table(opp_table);
} else {
dev_warn(dev, "%s: Couldn't find OPP with freq: %lu\n",
__func__, freq);
}
+ /* Drop the reference taken by _find_opp_table() */
dev_pm_opp_put_opp_table(opp_table);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_remove);
@@ -1062,9 +1135,6 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
new_opp->opp_table = opp_table;
kref_init(&new_opp->kref);
- /* Get a reference to the OPP table */
- _get_opp_table_kref(opp_table);
-
ret = opp_debug_create_one(new_opp, opp_table);
if (ret)
dev_err(dev, "%s: Failed to register opp to debugfs (%d)\n",
@@ -1543,8 +1613,9 @@ int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
return -ENOMEM;
ret = _opp_add_v1(opp_table, dev, freq, u_volt, true);
+ if (ret)
+ dev_pm_opp_put_opp_table(opp_table);
- dev_pm_opp_put_opp_table(opp_table);
return ret;
}
EXPORT_SYMBOL_GPL(dev_pm_opp_add);
@@ -1707,35 +1778,7 @@ int dev_pm_opp_unregister_notifier(struct device *dev,
}
EXPORT_SYMBOL(dev_pm_opp_unregister_notifier);
-/*
- * Free OPPs either created using static entries present in DT or even the
- * dynamically added entries based on remove_all param.
- */
-void _dev_pm_opp_remove_table(struct opp_table *opp_table, struct device *dev,
- bool remove_all)
-{
- struct dev_pm_opp *opp, *tmp;
-
- /* Find if opp_table manages a single device */
- if (list_is_singular(&opp_table->dev_list)) {
- /* Free static OPPs */
- list_for_each_entry_safe(opp, tmp, &opp_table->opp_list, node) {
- if (remove_all || !opp->dynamic)
- dev_pm_opp_put(opp);
- }
-
- /*
- * The OPP table is getting removed, drop the performance state
- * constraints.
- */
- if (opp_table->genpd_performance_state)
- dev_pm_genpd_set_performance_state(dev, 0);
- } else {
- _remove_opp_dev(_find_opp_dev(dev, opp_table), opp_table);
- }
-}
-
-void _dev_pm_opp_find_and_remove_table(struct device *dev, bool remove_all)
+void _dev_pm_opp_find_and_remove_table(struct device *dev)
{
struct opp_table *opp_table;
@@ -1752,8 +1795,12 @@ void _dev_pm_opp_find_and_remove_table(struct device *dev, bool remove_all)
return;
}
- _dev_pm_opp_remove_table(opp_table, dev, remove_all);
+ _put_opp_list_kref(opp_table);
+
+ /* Drop reference taken by _find_opp_table() */
+ dev_pm_opp_put_opp_table(opp_table);
+ /* Drop reference taken while the OPP table was added */
dev_pm_opp_put_opp_table(opp_table);
}
@@ -1766,6 +1813,6 @@ void _dev_pm_opp_find_and_remove_table(struct device *dev, bool remove_all)
*/
void dev_pm_opp_remove_table(struct device *dev)
{
- _dev_pm_opp_find_and_remove_table(dev, true);
+ _dev_pm_opp_find_and_remove_table(dev);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_remove_table);
diff --git a/drivers/opp/cpu.c b/drivers/opp/cpu.c
index 0c0910709435..ab6d07e78945 100644
--- a/drivers/opp/cpu.c
+++ b/drivers/opp/cpu.c
@@ -108,7 +108,8 @@ void dev_pm_opp_free_cpufreq_table(struct device *dev,
EXPORT_SYMBOL_GPL(dev_pm_opp_free_cpufreq_table);
#endif /* CONFIG_CPU_FREQ */
-void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, bool of)
+void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask,
+ int last_cpu)
{
struct device *cpu_dev;
int cpu;
@@ -116,6 +117,9 @@ void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, bool of)
WARN_ON(cpumask_empty(cpumask));
for_each_cpu(cpu, cpumask) {
+ if (cpu == last_cpu)
+ break;
+
cpu_dev = get_cpu_device(cpu);
if (!cpu_dev) {
pr_err("%s: failed to get cpu%d device\n", __func__,
@@ -123,10 +127,7 @@ void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, bool of)
continue;
}
- if (of)
- dev_pm_opp_of_remove_table(cpu_dev);
- else
- dev_pm_opp_remove_table(cpu_dev);
+ _dev_pm_opp_find_and_remove_table(cpu_dev);
}
}
@@ -140,7 +141,7 @@ void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, bool of)
*/
void dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask)
{
- _dev_pm_opp_cpumask_remove_table(cpumask, false);
+ _dev_pm_opp_cpumask_remove_table(cpumask, -1);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_cpumask_remove_table);
@@ -222,8 +223,10 @@ int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask)
cpumask_clear(cpumask);
if (opp_table->shared_opp == OPP_TABLE_ACCESS_SHARED) {
+ mutex_lock(&opp_table->lock);
list_for_each_entry(opp_dev, &opp_table->dev_list, node)
cpumask_set_cpu(opp_dev->dev->id, cpumask);
+ mutex_unlock(&opp_table->lock);
} else {
cpumask_set_cpu(cpu_dev->id, cpumask);
}
diff --git a/drivers/opp/of.c b/drivers/opp/of.c
index 7af0ddec936b..5a4b47958073 100644
--- a/drivers/opp/of.c
+++ b/drivers/opp/of.c
@@ -23,11 +23,32 @@
#include "opp.h"
-static struct opp_table *_managed_opp(const struct device_node *np)
+/*
+ * Returns opp descriptor node for a device node, caller must
+ * do of_node_put().
+ */
+static struct device_node *_opp_of_get_opp_desc_node(struct device_node *np,
+ int index)
+{
+ /* "operating-points-v2" can be an array for power domain providers */
+ return of_parse_phandle(np, "operating-points-v2", index);
+}
+
+/* Returns opp descriptor node for a device, caller must do of_node_put() */
+struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device *dev)
+{
+ return _opp_of_get_opp_desc_node(dev->of_node, 0);
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_of_get_opp_desc_node);
+
+struct opp_table *_managed_opp(struct device *dev, int index)
{
struct opp_table *opp_table, *managed_table = NULL;
+ struct device_node *np;
- mutex_lock(&opp_table_lock);
+ np = _opp_of_get_opp_desc_node(dev->of_node, index);
+ if (!np)
+ return NULL;
list_for_each_entry(opp_table, &opp_tables, node) {
if (opp_table->np == np) {
@@ -47,29 +68,45 @@ static struct opp_table *_managed_opp(const struct device_node *np)
}
}
- mutex_unlock(&opp_table_lock);
+ of_node_put(np);
return managed_table;
}
-void _of_init_opp_table(struct opp_table *opp_table, struct device *dev)
+void _of_init_opp_table(struct opp_table *opp_table, struct device *dev,
+ int index)
{
- struct device_node *np;
+ struct device_node *np, *opp_np;
+ u32 val;
/*
* Only required for backward compatibility with v1 bindings, but isn't
* harmful for other cases. And so we do it unconditionally.
*/
np = of_node_get(dev->of_node);
- if (np) {
- u32 val;
-
- if (!of_property_read_u32(np, "clock-latency", &val))
- opp_table->clock_latency_ns_max = val;
- of_property_read_u32(np, "voltage-tolerance",
- &opp_table->voltage_tolerance_v1);
- of_node_put(np);
- }
+ if (!np)
+ return;
+
+ if (!of_property_read_u32(np, "clock-latency", &val))
+ opp_table->clock_latency_ns_max = val;
+ of_property_read_u32(np, "voltage-tolerance",
+ &opp_table->voltage_tolerance_v1);
+
+ /* Get OPP table node */
+ opp_np = _opp_of_get_opp_desc_node(np, index);
+ of_node_put(np);
+
+ if (!opp_np)
+ return;
+
+ if (of_property_read_bool(opp_np, "opp-shared"))
+ opp_table->shared_opp = OPP_TABLE_ACCESS_SHARED;
+ else
+ opp_table->shared_opp = OPP_TABLE_ACCESS_EXCLUSIVE;
+
+ opp_table->np = opp_np;
+
+ of_node_put(opp_np);
}
static bool _opp_is_supported(struct device *dev, struct opp_table *opp_table,
@@ -245,26 +282,10 @@ free_microvolt:
*/
void dev_pm_opp_of_remove_table(struct device *dev)
{
- _dev_pm_opp_find_and_remove_table(dev, false);
+ _dev_pm_opp_find_and_remove_table(dev);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_of_remove_table);
-/* Returns opp descriptor node for a device node, caller must
- * do of_node_put() */
-static struct device_node *_opp_of_get_opp_desc_node(struct device_node *np,
- int index)
-{
- /* "operating-points-v2" can be an array for power domain providers */
- return of_parse_phandle(np, "operating-points-v2", index);
-}
-
-/* Returns opp descriptor node for a device, caller must do of_node_put() */
-struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device *dev)
-{
- return _opp_of_get_opp_desc_node(dev->of_node, 0);
-}
-EXPORT_SYMBOL_GPL(dev_pm_opp_of_get_opp_desc_node);
-
/**
* _opp_add_static_v2() - Allocate static OPPs (As per 'v2' DT bindings)
* @opp_table: OPP table
@@ -276,15 +297,21 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_get_opp_desc_node);
* removed by dev_pm_opp_remove.
*
* Return:
- * 0 On success OR
+ * Valid OPP pointer:
+ * On success
+ * NULL:
* Duplicate OPPs (both freq and volt are same) and opp->available
- * -EEXIST Freq are same and volt are different OR
+ * OR if the OPP is not supported by hardware.
+ * ERR_PTR(-EEXIST):
+ * Freq are same and volt are different OR
* Duplicate OPPs (both freq and volt are same) and !opp->available
- * -ENOMEM Memory allocation failure
- * -EINVAL Failed parsing the OPP node
+ * ERR_PTR(-ENOMEM):
+ * Memory allocation failure
+ * ERR_PTR(-EINVAL):
+ * Failed parsing the OPP node
*/
-static int _opp_add_static_v2(struct opp_table *opp_table, struct device *dev,
- struct device_node *np)
+static struct dev_pm_opp *_opp_add_static_v2(struct opp_table *opp_table,
+ struct device *dev, struct device_node *np)
{
struct dev_pm_opp *new_opp;
u64 rate = 0;
@@ -294,7 +321,7 @@ static int _opp_add_static_v2(struct opp_table *opp_table, struct device *dev,
new_opp = _opp_allocate(opp_table);
if (!new_opp)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
ret = of_property_read_u64(np, "opp-hz", &rate);
if (ret < 0) {
@@ -369,52 +396,47 @@ static int _opp_add_static_v2(struct opp_table *opp_table, struct device *dev,
* frequency/voltage list.
*/
blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_ADD, new_opp);
- return 0;
+ return new_opp;
free_opp:
_opp_free(new_opp);
- return ret;
+ return ERR_PTR(ret);
}
/* Initializes OPP tables based on new bindings */
-static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np)
+static int _of_add_opp_table_v2(struct device *dev, struct opp_table *opp_table)
{
struct device_node *np;
- struct opp_table *opp_table;
- int ret = 0, count = 0, pstate_count = 0;
+ int ret, count = 0, pstate_count = 0;
struct dev_pm_opp *opp;
- opp_table = _managed_opp(opp_np);
- if (opp_table) {
- /* OPPs are already managed */
- if (!_add_opp_dev(dev, opp_table))
- ret = -ENOMEM;
- goto put_opp_table;
+ /* OPP table is already initialized for the device */
+ if (opp_table->parsed_static_opps) {
+ kref_get(&opp_table->list_kref);
+ return 0;
}
- opp_table = dev_pm_opp_get_opp_table(dev);
- if (!opp_table)
- return -ENOMEM;
+ kref_init(&opp_table->list_kref);
/* We have opp-table node now, iterate over it and add OPPs */
- for_each_available_child_of_node(opp_np, np) {
- count++;
-
- ret = _opp_add_static_v2(opp_table, dev, np);
- if (ret) {
+ for_each_available_child_of_node(opp_table->np, np) {
+ opp = _opp_add_static_v2(opp_table, dev, np);
+ if (IS_ERR(opp)) {
+ ret = PTR_ERR(opp);
dev_err(dev, "%s: Failed to add OPP, %d\n", __func__,
ret);
- _dev_pm_opp_remove_table(opp_table, dev, false);
of_node_put(np);
- goto put_opp_table;
+ goto put_list_kref;
+ } else if (opp) {
+ count++;
}
}
/* There should be one of more OPP defined */
if (WARN_ON(!count)) {
ret = -ENOENT;
- goto put_opp_table;
+ goto put_list_kref;
}
list_for_each_entry(opp, &opp_table->opp_list, node)
@@ -425,28 +447,25 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np)
dev_err(dev, "Not all nodes have performance state set (%d: %d)\n",
count, pstate_count);
ret = -ENOENT;
- goto put_opp_table;
+ goto put_list_kref;
}
if (pstate_count)
opp_table->genpd_performance_state = true;
- opp_table->np = opp_np;
- if (of_property_read_bool(opp_np, "opp-shared"))
- opp_table->shared_opp = OPP_TABLE_ACCESS_SHARED;
- else
- opp_table->shared_opp = OPP_TABLE_ACCESS_EXCLUSIVE;
+ opp_table->parsed_static_opps = true;
-put_opp_table:
- dev_pm_opp_put_opp_table(opp_table);
+ return 0;
+
+put_list_kref:
+ _put_opp_list_kref(opp_table);
return ret;
}
/* Initializes OPP tables based on old-deprecated bindings */
-static int _of_add_opp_table_v1(struct device *dev)
+static int _of_add_opp_table_v1(struct device *dev, struct opp_table *opp_table)
{
- struct opp_table *opp_table;
const struct property *prop;
const __be32 *val;
int nr, ret = 0;
@@ -467,9 +486,7 @@ static int _of_add_opp_table_v1(struct device *dev)
return -EINVAL;
}
- opp_table = dev_pm_opp_get_opp_table(dev);
- if (!opp_table)
- return -ENOMEM;
+ kref_init(&opp_table->list_kref);
val = prop->value;
while (nr) {
@@ -480,13 +497,12 @@ static int _of_add_opp_table_v1(struct device *dev)
if (ret) {
dev_err(dev, "%s: Failed to add OPP %ld (%d)\n",
__func__, freq, ret);
- _dev_pm_opp_remove_table(opp_table, dev, false);
- break;
+ _put_opp_list_kref(opp_table);
+ return ret;
}
nr -= 2;
}
- dev_pm_opp_put_opp_table(opp_table);
return ret;
}
@@ -509,24 +525,24 @@ static int _of_add_opp_table_v1(struct device *dev)
*/
int dev_pm_opp_of_add_table(struct device *dev)
{
- struct device_node *opp_np;
+ struct opp_table *opp_table;
int ret;
+ opp_table = dev_pm_opp_get_opp_table_indexed(dev, 0);
+ if (!opp_table)
+ return -ENOMEM;
+
/*
- * OPPs have two version of bindings now. The older one is deprecated,
- * try for the new binding first.
+ * OPPs have two version of bindings now. Also try the old (v1)
+ * bindings for backward compatibility with older dtbs.
*/
- opp_np = dev_pm_opp_of_get_opp_desc_node(dev);
- if (!opp_np) {
- /*
- * Try old-deprecated bindings for backward compatibility with
- * older dtbs.
- */
- return _of_add_opp_table_v1(dev);
- }
+ if (opp_table->np)
+ ret = _of_add_opp_table_v2(dev, opp_table);
+ else
+ ret = _of_add_opp_table_v1(dev, opp_table);
- ret = _of_add_opp_table_v2(dev, opp_np);
- of_node_put(opp_np);
+ if (ret)
+ dev_pm_opp_put_opp_table(opp_table);
return ret;
}
@@ -553,28 +569,29 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table);
*/
int dev_pm_opp_of_add_table_indexed(struct device *dev, int index)
{
- struct device_node *opp_np;
+ struct opp_table *opp_table;
int ret, count;
-again:
- opp_np = _opp_of_get_opp_desc_node(dev->of_node, index);
- if (!opp_np) {
+ if (index) {
/*
* If only one phandle is present, then the same OPP table
* applies for all index requests.
*/
count = of_count_phandle_with_args(dev->of_node,
"operating-points-v2", NULL);
- if (count == 1 && index) {
- index = 0;
- goto again;
- }
+ if (count != 1)
+ return -ENODEV;
- return -ENODEV;
+ index = 0;
}
- ret = _of_add_opp_table_v2(dev, opp_np);
- of_node_put(opp_np);
+ opp_table = dev_pm_opp_get_opp_table_indexed(dev, index);
+ if (!opp_table)
+ return -ENOMEM;
+
+ ret = _of_add_opp_table_v2(dev, opp_table);
+ if (ret)
+ dev_pm_opp_put_opp_table(opp_table);
return ret;
}
@@ -591,7 +608,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table_indexed);
*/
void dev_pm_opp_of_cpumask_remove_table(const struct cpumask *cpumask)
{
- _dev_pm_opp_cpumask_remove_table(cpumask, true);
+ _dev_pm_opp_cpumask_remove_table(cpumask, -1);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_of_cpumask_remove_table);
@@ -604,16 +621,18 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_cpumask_remove_table);
int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask)
{
struct device *cpu_dev;
- int cpu, ret = 0;
+ int cpu, ret;
- WARN_ON(cpumask_empty(cpumask));
+ if (WARN_ON(cpumask_empty(cpumask)))
+ return -ENODEV;
for_each_cpu(cpu, cpumask) {
cpu_dev = get_cpu_device(cpu);
if (!cpu_dev) {
pr_err("%s: failed to get cpu%d device\n", __func__,
cpu);
- continue;
+ ret = -ENODEV;
+ goto remove_table;
}
ret = dev_pm_opp_of_add_table(cpu_dev);
@@ -625,12 +644,16 @@ int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask)
pr_debug("%s: couldn't find opp table for cpu:%d, %d\n",
__func__, cpu, ret);
- /* Free all other OPPs */
- dev_pm_opp_of_cpumask_remove_table(cpumask);
- break;
+ goto remove_table;
}
}
+ return 0;
+
+remove_table:
+ /* Free all other OPPs */
+ _dev_pm_opp_cpumask_remove_table(cpumask, cpu);
+
return ret;
}
EXPORT_SYMBOL_GPL(dev_pm_opp_of_cpumask_add_table);
diff --git a/drivers/opp/opp.h b/drivers/opp/opp.h
index 7c540fd063b2..9c6544b4f4f9 100644
--- a/drivers/opp/opp.h
+++ b/drivers/opp/opp.h
@@ -126,9 +126,11 @@ enum opp_table_access {
* @dev_list: list of devices that share these OPPs
* @opp_list: table of opps
* @kref: for reference count of the table.
- * @lock: mutex protecting the opp_list.
+ * @list_kref: for reference count of the OPP list.
+ * @lock: mutex protecting the opp_list and dev_list.
* @np: struct device_node pointer for opp's DT node.
* @clock_latency_ns_max: Max clock latency in nanoseconds.
+ * @parsed_static_opps: True if OPPs are initialized from DT.
* @shared_opp: OPP is shared between multiple devices.
* @suspend_opp: Pointer to OPP to be used during device suspend.
* @supported_hw: Array of version number to support.
@@ -156,6 +158,7 @@ struct opp_table {
struct list_head dev_list;
struct list_head opp_list;
struct kref kref;
+ struct kref list_kref;
struct mutex lock;
struct device_node *np;
@@ -164,6 +167,7 @@ struct opp_table {
/* For backward compatibility with v1 bindings */
unsigned int voltage_tolerance_v1;
+ bool parsed_static_opps;
enum opp_table_access shared_opp;
struct dev_pm_opp *suspend_opp;
@@ -186,23 +190,26 @@ struct opp_table {
/* Routines internal to opp core */
void dev_pm_opp_get(struct dev_pm_opp *opp);
+void _opp_remove_all_static(struct opp_table *opp_table);
void _get_opp_table_kref(struct opp_table *opp_table);
int _get_opp_count(struct opp_table *opp_table);
struct opp_table *_find_opp_table(struct device *dev);
struct opp_device *_add_opp_dev(const struct device *dev, struct opp_table *opp_table);
-void _dev_pm_opp_remove_table(struct opp_table *opp_table, struct device *dev, bool remove_all);
-void _dev_pm_opp_find_and_remove_table(struct device *dev, bool remove_all);
+void _dev_pm_opp_find_and_remove_table(struct device *dev);
struct dev_pm_opp *_opp_allocate(struct opp_table *opp_table);
void _opp_free(struct dev_pm_opp *opp);
int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table, bool rate_not_available);
int _opp_add_v1(struct opp_table *opp_table, struct device *dev, unsigned long freq, long u_volt, bool dynamic);
-void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, bool of);
+void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, int last_cpu);
struct opp_table *_add_opp_table(struct device *dev);
+void _put_opp_list_kref(struct opp_table *opp_table);
#ifdef CONFIG_OF
-void _of_init_opp_table(struct opp_table *opp_table, struct device *dev);
+void _of_init_opp_table(struct opp_table *opp_table, struct device *dev, int index);
+struct opp_table *_managed_opp(struct device *dev, int index);
#else
-static inline void _of_init_opp_table(struct opp_table *opp_table, struct device *dev) {}
+static inline void _of_init_opp_table(struct opp_table *opp_table, struct device *dev, int index) {}
+static inline struct opp_table *_managed_opp(struct device *dev, int index) { return NULL; }
#endif
#ifdef CONFIG_DEBUG_FS
diff --git a/drivers/parisc/Makefile b/drivers/parisc/Makefile
index 3cd5e6cb8478..99fa6a89e0b9 100644
--- a/drivers/parisc/Makefile
+++ b/drivers/parisc/Makefile
@@ -8,9 +8,6 @@
obj-$(CONFIG_IOSAPIC) += iosapic.o
obj-$(CONFIG_IOMMU_SBA) += sba_iommu.o
obj-$(CONFIG_PCI_LBA) += lba_pci.o
-
-# Only use one of them: ccio-rm-dma is for PCX-W systems *only*
-# obj-$(CONFIG_IOMMU_CCIO) += ccio-rm-dma.o
obj-$(CONFIG_IOMMU_CCIO) += ccio-dma.o
obj-$(CONFIG_GSC) += gsc.o
diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c
index 614823617b8b..701a7d6a74d5 100644
--- a/drivers/parisc/ccio-dma.c
+++ b/drivers/parisc/ccio-dma.c
@@ -609,14 +609,13 @@ ccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba,
** PCX-T'? Don't know. (eg C110 or similar K-class)
**
** See PDC_MODEL/option 0/SW_CAP word for "Non-coherent IO-PDIR bit".
- ** Hopefully we can patch (NOP) these out at boot time somehow.
**
** "Since PCX-U employs an offset hash that is incompatible with
** the real mode coherence index generation of U2, the PDIR entry
** must be flushed to memory to retain coherence."
*/
- asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr));
- asm volatile("sync");
+ asm_io_fdc(pdir_ptr);
+ asm_io_sync();
}
/**
@@ -682,17 +681,14 @@ ccio_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt)
** FIXME: PCX_W platforms don't need FDC/SYNC. (eg C360)
** PCX-U/U+ do. (eg C200/C240)
** See PDC_MODEL/option 0/SW_CAP for "Non-coherent IO-PDIR bit".
- **
- ** Hopefully someone figures out how to patch (NOP) the
- ** FDC/SYNC out at boot time.
*/
- asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr[7]));
+ asm_io_fdc(pdir_ptr);
iovp += IOVP_SIZE;
byte_cnt -= IOVP_SIZE;
}
- asm volatile("sync");
+ asm_io_sync();
ccio_clear_io_tlb(ioc, CCIO_IOVP(iova), saved_byte_cnt);
}
diff --git a/drivers/parisc/ccio-rm-dma.c b/drivers/parisc/ccio-rm-dma.c
deleted file mode 100644
index df7932af48b7..000000000000
--- a/drivers/parisc/ccio-rm-dma.c
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * ccio-rm-dma.c:
- * DMA management routines for first generation cache-coherent machines.
- * "Real Mode" operation refers to U2/Uturn chip operation. The chip
- * can perform coherency checks w/o using the I/O MMU. That's all we
- * need until support for more than 4GB phys mem is needed.
- *
- * This is the trivial case - basically what x86 does.
- *
- * Drawbacks of using Real Mode are:
- * o outbound DMA is slower since one isn't using the prefetching
- * U2 can do for outbound DMA.
- * o Ability to do scatter/gather in HW is also lost.
- * o only known to work with PCX-W processor. (eg C360)
- * (PCX-U/U+ are not coherent with U2 in real mode.)
- *
- *
- * 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.
- *
- *
- * Original version/author:
- * CVSROOT=:pserver:anonymous@198.186.203.37:/cvsroot/linux-parisc
- * cvs -z3 co linux/arch/parisc/kernel/dma-rm.c
- *
- * (C) Copyright 2000 Philipp Rumpf <prumpf@tux.org>
- *
- *
- * Adopted for The Puffin Group's parisc-linux port by Grant Grundler.
- * (C) Copyright 2000 Grant Grundler <grundler@puffin.external.hp.com>
- *
- */
-
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/pci.h>
-#include <linux/gfp.h>
-
-#include <linux/uaccess.h>
-
-#include <asm/io.h>
-#include <asm/hardware.h>
-#include <asm/page.h>
-
-/* Only chose "ccio" since that's what HP-UX calls it....
-** Make it easier for folks to migrate from one to the other :^)
-*/
-#define MODULE_NAME "ccio"
-
-#define U2_IOA_RUNWAY 0x580
-#define U2_BC_GSC 0x501
-#define UTURN_IOA_RUNWAY 0x581
-#define UTURN_BC_GSC 0x502
-
-#define IS_U2(id) ( \
- (((id)->hw_type == HPHW_IOA) && ((id)->hversion == U2_IOA_RUNWAY)) || \
- (((id)->hw_type == HPHW_BCPORT) && ((id)->hversion == U2_BC_GSC)) \
-)
-
-#define IS_UTURN(id) ( \
- (((id)->hw_type == HPHW_IOA) && ((id)->hversion == UTURN_IOA_RUNWAY)) || \
- (((id)->hw_type == HPHW_BCPORT) && ((id)->hversion == UTURN_BC_GSC)) \
-)
-
-static int ccio_dma_supported( struct pci_dev *dev, u64 mask)
-{
- if (dev == NULL) {
- printk(KERN_ERR MODULE_NAME ": EISA/ISA/et al not supported\n");
- BUG();
- return(0);
- }
-
- /* only support 32-bit devices (ie PCI/GSC) */
- return((int) (mask >= 0xffffffffUL));
-}
-
-
-static void *ccio_alloc_consistent(struct pci_dev *dev, size_t size,
- dma_addr_t *handle)
-{
- void *ret;
-
- ret = (void *)__get_free_pages(GFP_ATOMIC, get_order(size));
-
- if (ret != NULL) {
- memset(ret, 0, size);
- *handle = virt_to_phys(ret);
- }
- return ret;
-}
-
-static void ccio_free_consistent(struct pci_dev *dev, size_t size,
- void *vaddr, dma_addr_t handle)
-{
- free_pages((unsigned long)vaddr, get_order(size));
-}
-
-static dma_addr_t ccio_map_single(struct pci_dev *dev, void *ptr, size_t size,
- int direction)
-{
- return virt_to_phys(ptr);
-}
-
-static void ccio_unmap_single(struct pci_dev *dev, dma_addr_t dma_addr,
- size_t size, int direction)
-{
- /* Nothing to do */
-}
-
-
-static int ccio_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction)
-{
- int tmp = nents;
-
- /* KISS: map each buffer separately. */
- while (nents) {
- sg_dma_address(sglist) = ccio_map_single(dev, sglist->address, sglist->length, direction);
- sg_dma_len(sglist) = sglist->length;
- nents--;
- sglist++;
- }
-
- return tmp;
-}
-
-
-static void ccio_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction)
-{
-#if 0
- while (nents) {
- ccio_unmap_single(dev, sg_dma_address(sglist), sg_dma_len(sglist), direction);
- nents--;
- sglist++;
- }
- return;
-#else
- /* Do nothing (copied from current ccio_unmap_single() :^) */
-#endif
-}
-
-
-static struct pci_dma_ops ccio_ops = {
- ccio_dma_supported,
- ccio_alloc_consistent,
- ccio_free_consistent,
- ccio_map_single,
- ccio_unmap_single,
- ccio_map_sg,
- ccio_unmap_sg,
- NULL, /* dma_sync_single_for_cpu : NOP for U2 */
- NULL, /* dma_sync_single_for_device : NOP for U2 */
- NULL, /* dma_sync_sg_for_cpu : ditto */
- NULL, /* dma_sync_sg_for_device : ditto */
-};
-
-
-/*
-** Determine if u2 should claim this chip (return 0) or not (return 1).
-** If so, initialize the chip and tell other partners in crime they
-** have work to do.
-*/
-static int __init
-ccio_probe(struct parisc_device *dev)
-{
- printk(KERN_INFO "%s found %s at 0x%lx\n", MODULE_NAME,
- dev->id.hversion == U2_BC_GSC ? "U2" : "UTurn",
- dev->hpa.start);
-
-/*
-** FIXME - should check U2 registers to verify it's really running
-** in "Real Mode".
-*/
-
-#if 0
-/* will need this for "Virtual Mode" operation */
- ccio_hw_init(ccio_dev);
- ccio_common_init(ccio_dev);
-#endif
- hppa_dma_ops = &ccio_ops;
- return 0;
-}
-
-static const struct parisc_device_id ccio_tbl[] __initconst = {
- { HPHW_BCPORT, HVERSION_REV_ANY_ID, U2_BC_GSC, 0xc },
- { HPHW_BCPORT, HVERSION_REV_ANY_ID, UTURN_BC_GSC, 0xc },
- { 0, }
-};
-
-static struct parisc_driver ccio_driver __refdata = {
- .name = "U2/Uturn",
- .id_table = ccio_tbl,
- .probe = ccio_probe,
-};
-
-void __init ccio_init(void)
-{
- register_parisc_driver(&ccio_driver);
-}
diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c
index 7390fb8ca9d1..dfeea458a789 100644
--- a/drivers/parisc/dino.c
+++ b/drivers/parisc/dino.c
@@ -382,7 +382,7 @@ ilr_again:
DBG(KERN_DEBUG "%s(%d, %p) mask 0x%x\n",
__func__, irq, intr_dev, mask);
generic_handle_irq(irq);
- mask &= ~(1 << local_irq);
+ mask &= ~DINO_MASK_IRQ(local_irq);
} while (mask);
/* Support for level triggered IRQ lines.
@@ -396,9 +396,8 @@ ilr_again:
if (mask) {
if (--ilr_loop > 0)
goto ilr_again;
- printk(KERN_ERR "Dino 0x%px: stuck interrupt %d\n",
+ pr_warn_ratelimited("Dino 0x%px: stuck interrupt %d\n",
dino_dev->hba.base_addr, mask);
- return IRQ_NONE;
}
return IRQ_HANDLED;
}
diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c
index 11de0eccf968..c1e599a429af 100644
--- a/drivers/parisc/sba_iommu.c
+++ b/drivers/parisc/sba_iommu.c
@@ -587,8 +587,7 @@ sba_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba,
* (bit #61, big endian), we have to flush and sync every time
* IO-PDIR is changed in Ike/Astro.
*/
- if (ioc_needs_fdc)
- asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr));
+ asm_io_fdc(pdir_ptr);
}
@@ -641,8 +640,8 @@ sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt)
do {
/* clear I/O Pdir entry "valid" bit first */
((u8 *) pdir_ptr)[7] = 0;
+ asm_io_fdc(pdir_ptr);
if (ioc_needs_fdc) {
- asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr));
#if 0
entries_per_cacheline = L1_CACHE_SHIFT - 3;
#endif
@@ -661,8 +660,7 @@ sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt)
** could dump core on HPMC.
*/
((u8 *) pdir_ptr)[7] = 0;
- if (ioc_needs_fdc)
- asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr));
+ asm_io_fdc(pdir_ptr);
WRITE_REG( SBA_IOVA(ioc, iovp, 0, 0), ioc->ioc_hpa+IOC_PCOM);
}
@@ -773,8 +771,7 @@ sba_map_single(struct device *dev, void *addr, size_t size,
}
/* force FDC ops in io_pdir_entry() to be visible to IOMMU */
- if (ioc_needs_fdc)
- asm volatile("sync" : : );
+ asm_io_sync();
#ifdef ASSERT_PDIR_SANITY
sba_check_pdir(ioc,"Check after sba_map_single()");
@@ -858,8 +855,7 @@ sba_unmap_page(struct device *dev, dma_addr_t iova, size_t size,
sba_free_range(ioc, iova, size);
/* If fdc's were issued, force fdc's to be visible now */
- if (ioc_needs_fdc)
- asm volatile("sync" : : );
+ asm_io_sync();
READ_REG(ioc->ioc_hpa+IOC_PCOM); /* flush purges */
#endif /* DELAYED_RESOURCE_CNT == 0 */
@@ -1008,8 +1004,7 @@ sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
filled = iommu_fill_pdir(ioc, sglist, nents, 0, sba_io_pdir_entry);
/* force FDC ops in io_pdir_entry() to be visible to IOMMU */
- if (ioc_needs_fdc)
- asm volatile("sync" : : );
+ asm_io_sync();
#ifdef ASSERT_PDIR_SANITY
if (sba_check_pdir(ioc,"Check after sba_map_sg()"))
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 56ff8f6d31fc..2dcc30429e8b 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -98,6 +98,9 @@ config PCI_ECAM
config PCI_LOCKLESS_CONFIG
bool
+config PCI_BRIDGE_EMUL
+ bool
+
config PCI_IOV
bool "PCI IOV support"
depends on PCI
@@ -132,6 +135,23 @@ config PCI_PASID
If unsure, say N.
+config PCI_P2PDMA
+ bool "PCI peer-to-peer transfer support"
+ depends on PCI && ZONE_DEVICE
+ select GENERIC_ALLOCATOR
+ help
+ Enableѕ drivers to do PCI peer-to-peer transactions to and from
+ BARs that are exposed in other devices that are the part of
+ the hierarchy where peer-to-peer DMA is guaranteed by the PCI
+ specification to work (ie. anything below a single PCI bridge).
+
+ Many PCIe root complexes do not support P2P transactions and
+ it's hard to tell which support it at all, so at this time,
+ P2P DMA transations must be between devices behind the same root
+ port.
+
+ If unsure, say N.
+
config PCI_LABEL
def_bool y if (DMI || ACPI)
depends on PCI
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 1b2cfe51e8d7..f2bda77a2df1 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_HOTPLUG_PCI) += hotplug/
obj-$(CONFIG_PCI_MSI) += msi.o
obj-$(CONFIG_PCI_ATS) += ats.o
obj-$(CONFIG_PCI_IOV) += iov.o
+obj-$(CONFIG_PCI_BRIDGE_EMUL) += pci-bridge-emul.o
obj-$(CONFIG_ACPI) += pci-acpi.o
obj-$(CONFIG_PCI_LABEL) += pci-label.o
obj-$(CONFIG_X86_INTEL_MID) += pci-mid.o
@@ -26,6 +27,7 @@ obj-$(CONFIG_PCI_SYSCALL) += syscall.o
obj-$(CONFIG_PCI_STUB) += pci-stub.o
obj-$(CONFIG_PCI_PF_STUB) += pci-pf-stub.o
obj-$(CONFIG_PCI_ECAM) += ecam.o
+obj-$(CONFIG_PCI_P2PDMA) += p2pdma.o
obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += xen-pcifront.o
# Endpoint library must be initialized before its users
diff --git a/drivers/pci/access.c b/drivers/pci/access.c
index a3ad2fe185b9..544922f097c0 100644
--- a/drivers/pci/access.c
+++ b/drivers/pci/access.c
@@ -33,7 +33,7 @@ DEFINE_RAW_SPINLOCK(pci_lock);
#endif
#define PCI_OP_READ(size, type, len) \
-int pci_bus_read_config_##size \
+int noinline pci_bus_read_config_##size \
(struct pci_bus *bus, unsigned int devfn, int pos, type *value) \
{ \
int res; \
@@ -48,7 +48,7 @@ int pci_bus_read_config_##size \
}
#define PCI_OP_WRITE(size, type, len) \
-int pci_bus_write_config_##size \
+int noinline pci_bus_write_config_##size \
(struct pci_bus *bus, unsigned int devfn, int pos, type value) \
{ \
int res; \
diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
index 028b287466fb..6671946dbf66 100644
--- a/drivers/pci/controller/Kconfig
+++ b/drivers/pci/controller/Kconfig
@@ -9,12 +9,14 @@ config PCI_MVEBU
depends on MVEBU_MBUS
depends on ARM
depends on OF
+ select PCI_BRIDGE_EMUL
config PCI_AARDVARK
bool "Aardvark PCIe controller"
depends on (ARCH_MVEBU && ARM64) || COMPILE_TEST
depends on OF
depends on PCI_MSI_IRQ_DOMAIN
+ select PCI_BRIDGE_EMUL
help
Add support for Aardvark 64bit PCIe Host Controller. This
controller is part of the South Bridge of the Marvel Armada
@@ -231,7 +233,7 @@ config PCIE_ROCKCHIP_EP
available to support GEN2 with 4 slots.
config PCIE_MEDIATEK
- bool "MediaTek PCIe controller"
+ tristate "MediaTek PCIe controller"
depends on ARCH_MEDIATEK || COMPILE_TEST
depends on OF
depends on PCI_MSI_IRQ_DOMAIN
diff --git a/drivers/pci/controller/dwc/Makefile b/drivers/pci/controller/dwc/Makefile
index 5d2ce72c7a52..fcf91eacfc63 100644
--- a/drivers/pci/controller/dwc/Makefile
+++ b/drivers/pci/controller/dwc/Makefile
@@ -7,7 +7,7 @@ obj-$(CONFIG_PCI_DRA7XX) += pci-dra7xx.o
obj-$(CONFIG_PCI_EXYNOS) += pci-exynos.o
obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o
-obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone-dw.o pci-keystone.o
+obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone.o
obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o
obj-$(CONFIG_PCIE_QCOM) += pcie-qcom.o
obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o
diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c
index ce9224a36f62..a32d6dde7a57 100644
--- a/drivers/pci/controller/dwc/pci-dra7xx.c
+++ b/drivers/pci/controller/dwc/pci-dra7xx.c
@@ -542,7 +542,7 @@ static const struct of_device_id of_dra7xx_pcie_match[] = {
};
/*
- * dra7xx_pcie_ep_unaligned_memaccess: workaround for AM572x/AM571x Errata i870
+ * dra7xx_pcie_unaligned_memaccess: workaround for AM572x/AM571x Errata i870
* @dra7xx: the dra7xx device where the workaround should be applied
*
* Access to the PCIe slave port that are not 32-bit aligned will result
@@ -552,7 +552,7 @@ static const struct of_device_id of_dra7xx_pcie_match[] = {
*
* To avoid this issue set PCIE_SS1_AXI2OCP_LEGACY_MODE_ENABLE to 1.
*/
-static int dra7xx_pcie_ep_unaligned_memaccess(struct device *dev)
+static int dra7xx_pcie_unaligned_memaccess(struct device *dev)
{
int ret;
struct device_node *np = dev->of_node;
@@ -704,6 +704,11 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
dra7xx_pcie_writel(dra7xx, PCIECTRL_TI_CONF_DEVICE_TYPE,
DEVICE_TYPE_RC);
+
+ ret = dra7xx_pcie_unaligned_memaccess(dev);
+ if (ret)
+ dev_err(dev, "WA for Errata i870 not applied\n");
+
ret = dra7xx_add_pcie_port(dra7xx, pdev);
if (ret < 0)
goto err_gpio;
@@ -717,7 +722,7 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
dra7xx_pcie_writel(dra7xx, PCIECTRL_TI_CONF_DEVICE_TYPE,
DEVICE_TYPE_EP);
- ret = dra7xx_pcie_ep_unaligned_memaccess(dev);
+ ret = dra7xx_pcie_unaligned_memaccess(dev);
if (ret)
goto err_gpio;
diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c
index 4a9a673b4777..2cbef2d7c207 100644
--- a/drivers/pci/controller/dwc/pci-imx6.c
+++ b/drivers/pci/controller/dwc/pci-imx6.c
@@ -50,6 +50,7 @@ struct imx6_pcie {
struct regmap *iomuxc_gpr;
struct reset_control *pciephy_reset;
struct reset_control *apps_reset;
+ struct reset_control *turnoff_reset;
enum imx6_pcie_variants variant;
u32 tx_deemph_gen1;
u32 tx_deemph_gen2_3p5db;
@@ -97,6 +98,16 @@ struct imx6_pcie {
#define PORT_LOGIC_SPEED_CHANGE (0x1 << 17)
/* PHY registers (not memory-mapped) */
+#define PCIE_PHY_ATEOVRD 0x10
+#define PCIE_PHY_ATEOVRD_EN (0x1 << 2)
+#define PCIE_PHY_ATEOVRD_REF_CLKDIV_SHIFT 0
+#define PCIE_PHY_ATEOVRD_REF_CLKDIV_MASK 0x1
+
+#define PCIE_PHY_MPLL_OVRD_IN_LO 0x11
+#define PCIE_PHY_MPLL_MULTIPLIER_SHIFT 2
+#define PCIE_PHY_MPLL_MULTIPLIER_MASK 0x7f
+#define PCIE_PHY_MPLL_MULTIPLIER_OVRD (0x1 << 9)
+
#define PCIE_PHY_RX_ASIC_OUT 0x100D
#define PCIE_PHY_RX_ASIC_OUT_VALID (1 << 0)
@@ -508,6 +519,50 @@ static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie)
IMX6Q_GPR12_DEVICE_TYPE, PCI_EXP_TYPE_ROOT_PORT << 12);
}
+static int imx6_setup_phy_mpll(struct imx6_pcie *imx6_pcie)
+{
+ unsigned long phy_rate = clk_get_rate(imx6_pcie->pcie_phy);
+ int mult, div;
+ u32 val;
+
+ switch (phy_rate) {
+ case 125000000:
+ /*
+ * The default settings of the MPLL are for a 125MHz input
+ * clock, so no need to reconfigure anything in that case.
+ */
+ return 0;
+ case 100000000:
+ mult = 25;
+ div = 0;
+ break;
+ case 200000000:
+ mult = 25;
+ div = 1;
+ break;
+ default:
+ dev_err(imx6_pcie->pci->dev,
+ "Unsupported PHY reference clock rate %lu\n", phy_rate);
+ return -EINVAL;
+ }
+
+ pcie_phy_read(imx6_pcie, PCIE_PHY_MPLL_OVRD_IN_LO, &val);
+ val &= ~(PCIE_PHY_MPLL_MULTIPLIER_MASK <<
+ PCIE_PHY_MPLL_MULTIPLIER_SHIFT);
+ val |= mult << PCIE_PHY_MPLL_MULTIPLIER_SHIFT;
+ val |= PCIE_PHY_MPLL_MULTIPLIER_OVRD;
+ pcie_phy_write(imx6_pcie, PCIE_PHY_MPLL_OVRD_IN_LO, val);
+
+ pcie_phy_read(imx6_pcie, PCIE_PHY_ATEOVRD, &val);
+ val &= ~(PCIE_PHY_ATEOVRD_REF_CLKDIV_MASK <<
+ PCIE_PHY_ATEOVRD_REF_CLKDIV_SHIFT);
+ val |= div << PCIE_PHY_ATEOVRD_REF_CLKDIV_SHIFT;
+ val |= PCIE_PHY_ATEOVRD_EN;
+ pcie_phy_write(imx6_pcie, PCIE_PHY_ATEOVRD, val);
+
+ return 0;
+}
+
static int imx6_pcie_wait_for_link(struct imx6_pcie *imx6_pcie)
{
struct dw_pcie *pci = imx6_pcie->pci;
@@ -542,6 +597,24 @@ static int imx6_pcie_wait_for_speed_change(struct imx6_pcie *imx6_pcie)
return -EINVAL;
}
+static void imx6_pcie_ltssm_enable(struct device *dev)
+{
+ struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev);
+
+ switch (imx6_pcie->variant) {
+ case IMX6Q:
+ case IMX6SX:
+ case IMX6QP:
+ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+ IMX6Q_GPR12_PCIE_CTL_2,
+ IMX6Q_GPR12_PCIE_CTL_2);
+ break;
+ case IMX7D:
+ reset_control_deassert(imx6_pcie->apps_reset);
+ break;
+ }
+}
+
static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
{
struct dw_pcie *pci = imx6_pcie->pci;
@@ -560,11 +633,7 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
dw_pcie_writel_dbi(pci, PCIE_RC_LCR, tmp);
/* Start LTSSM. */
- if (imx6_pcie->variant == IMX7D)
- reset_control_deassert(imx6_pcie->apps_reset);
- else
- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
- IMX6Q_GPR12_PCIE_CTL_2, 1 << 10);
+ imx6_pcie_ltssm_enable(dev);
ret = imx6_pcie_wait_for_link(imx6_pcie);
if (ret)
@@ -632,6 +701,7 @@ static int imx6_pcie_host_init(struct pcie_port *pp)
imx6_pcie_assert_core_reset(imx6_pcie);
imx6_pcie_init_phy(imx6_pcie);
imx6_pcie_deassert_core_reset(imx6_pcie);
+ imx6_setup_phy_mpll(imx6_pcie);
dw_pcie_setup_rc(pp);
imx6_pcie_establish_link(imx6_pcie);
@@ -682,6 +752,94 @@ static const struct dw_pcie_ops dw_pcie_ops = {
.link_up = imx6_pcie_link_up,
};
+#ifdef CONFIG_PM_SLEEP
+static void imx6_pcie_ltssm_disable(struct device *dev)
+{
+ struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev);
+
+ switch (imx6_pcie->variant) {
+ case IMX6SX:
+ case IMX6QP:
+ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+ IMX6Q_GPR12_PCIE_CTL_2, 0);
+ break;
+ case IMX7D:
+ reset_control_assert(imx6_pcie->apps_reset);
+ break;
+ default:
+ dev_err(dev, "ltssm_disable not supported\n");
+ }
+}
+
+static void imx6_pcie_pm_turnoff(struct imx6_pcie *imx6_pcie)
+{
+ reset_control_assert(imx6_pcie->turnoff_reset);
+ reset_control_deassert(imx6_pcie->turnoff_reset);
+
+ /*
+ * Components with an upstream port must respond to
+ * PME_Turn_Off with PME_TO_Ack but we can't check.
+ *
+ * The standard recommends a 1-10ms timeout after which to
+ * proceed anyway as if acks were received.
+ */
+ usleep_range(1000, 10000);
+}
+
+static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie)
+{
+ clk_disable_unprepare(imx6_pcie->pcie);
+ clk_disable_unprepare(imx6_pcie->pcie_phy);
+ clk_disable_unprepare(imx6_pcie->pcie_bus);
+
+ if (imx6_pcie->variant == IMX7D) {
+ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+ IMX7D_GPR12_PCIE_PHY_REFCLK_SEL,
+ IMX7D_GPR12_PCIE_PHY_REFCLK_SEL);
+ }
+}
+
+static int imx6_pcie_suspend_noirq(struct device *dev)
+{
+ struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev);
+
+ if (imx6_pcie->variant != IMX7D)
+ return 0;
+
+ imx6_pcie_pm_turnoff(imx6_pcie);
+ imx6_pcie_clk_disable(imx6_pcie);
+ imx6_pcie_ltssm_disable(dev);
+
+ return 0;
+}
+
+static int imx6_pcie_resume_noirq(struct device *dev)
+{
+ int ret;
+ struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev);
+ struct pcie_port *pp = &imx6_pcie->pci->pp;
+
+ if (imx6_pcie->variant != IMX7D)
+ return 0;
+
+ imx6_pcie_assert_core_reset(imx6_pcie);
+ imx6_pcie_init_phy(imx6_pcie);
+ imx6_pcie_deassert_core_reset(imx6_pcie);
+ dw_pcie_setup_rc(pp);
+
+ ret = imx6_pcie_establish_link(imx6_pcie);
+ if (ret < 0)
+ dev_info(dev, "pcie link is down after resume.\n");
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops imx6_pcie_pm_ops = {
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx6_pcie_suspend_noirq,
+ imx6_pcie_resume_noirq)
+};
+
static int imx6_pcie_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -776,6 +934,13 @@ static int imx6_pcie_probe(struct platform_device *pdev)
break;
}
+ /* Grab turnoff reset */
+ imx6_pcie->turnoff_reset = devm_reset_control_get_optional_exclusive(dev, "turnoff");
+ if (IS_ERR(imx6_pcie->turnoff_reset)) {
+ dev_err(dev, "Failed to get TURNOFF reset control\n");
+ return PTR_ERR(imx6_pcie->turnoff_reset);
+ }
+
/* Grab GPR config register range */
imx6_pcie->iomuxc_gpr =
syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
@@ -848,6 +1013,7 @@ static struct platform_driver imx6_pcie_driver = {
.name = "imx6q-pcie",
.of_match_table = imx6_pcie_of_match,
.suppress_bind_attrs = true,
+ .pm = &imx6_pcie_pm_ops,
},
.probe = imx6_pcie_probe,
.shutdown = imx6_pcie_shutdown,
diff --git a/drivers/pci/controller/dwc/pci-keystone-dw.c b/drivers/pci/controller/dwc/pci-keystone-dw.c
deleted file mode 100644
index 0682213328e9..000000000000
--- a/drivers/pci/controller/dwc/pci-keystone-dw.c
+++ /dev/null
@@ -1,484 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * DesignWare application register space functions for Keystone PCI controller
- *
- * Copyright (C) 2013-2014 Texas Instruments., Ltd.
- * http://www.ti.com
- *
- * Author: Murali Karicheri <m-karicheri2@ti.com>
- */
-
-#include <linux/irq.h>
-#include <linux/irqdomain.h>
-#include <linux/irqreturn.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_pci.h>
-#include <linux/pci.h>
-#include <linux/platform_device.h>
-
-#include "pcie-designware.h"
-#include "pci-keystone.h"
-
-/* Application register defines */
-#define LTSSM_EN_VAL 1
-#define LTSSM_STATE_MASK 0x1f
-#define LTSSM_STATE_L0 0x11
-#define DBI_CS2_EN_VAL 0x20
-#define OB_XLAT_EN_VAL 2
-
-/* Application registers */
-#define CMD_STATUS 0x004
-#define CFG_SETUP 0x008
-#define OB_SIZE 0x030
-#define CFG_PCIM_WIN_SZ_IDX 3
-#define CFG_PCIM_WIN_CNT 32
-#define SPACE0_REMOTE_CFG_OFFSET 0x1000
-#define OB_OFFSET_INDEX(n) (0x200 + (8 * n))
-#define OB_OFFSET_HI(n) (0x204 + (8 * n))
-
-/* IRQ register defines */
-#define IRQ_EOI 0x050
-#define IRQ_STATUS 0x184
-#define IRQ_ENABLE_SET 0x188
-#define IRQ_ENABLE_CLR 0x18c
-
-#define MSI_IRQ 0x054
-#define MSI0_IRQ_STATUS 0x104
-#define MSI0_IRQ_ENABLE_SET 0x108
-#define MSI0_IRQ_ENABLE_CLR 0x10c
-#define IRQ_STATUS 0x184
-#define MSI_IRQ_OFFSET 4
-
-/* Error IRQ bits */
-#define ERR_AER BIT(5) /* ECRC error */
-#define ERR_AXI BIT(4) /* AXI tag lookup fatal error */
-#define ERR_CORR BIT(3) /* Correctable error */
-#define ERR_NONFATAL BIT(2) /* Non-fatal error */
-#define ERR_FATAL BIT(1) /* Fatal error */
-#define ERR_SYS BIT(0) /* System (fatal, non-fatal, or correctable) */
-#define ERR_IRQ_ALL (ERR_AER | ERR_AXI | ERR_CORR | \
- ERR_NONFATAL | ERR_FATAL | ERR_SYS)
-#define ERR_FATAL_IRQ (ERR_FATAL | ERR_AXI)
-#define ERR_IRQ_STATUS_RAW 0x1c0
-#define ERR_IRQ_STATUS 0x1c4
-#define ERR_IRQ_ENABLE_SET 0x1c8
-#define ERR_IRQ_ENABLE_CLR 0x1cc
-
-/* Config space registers */
-#define DEBUG0 0x728
-
-#define to_keystone_pcie(x) dev_get_drvdata((x)->dev)
-
-static inline void update_reg_offset_bit_pos(u32 offset, u32 *reg_offset,
- u32 *bit_pos)
-{
- *reg_offset = offset % 8;
- *bit_pos = offset >> 3;
-}
-
-phys_addr_t ks_dw_pcie_get_msi_addr(struct pcie_port *pp)
-{
- struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
- struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
-
- return ks_pcie->app.start + MSI_IRQ;
-}
-
-static u32 ks_dw_app_readl(struct keystone_pcie *ks_pcie, u32 offset)
-{
- return readl(ks_pcie->va_app_base + offset);
-}
-
-static void ks_dw_app_writel(struct keystone_pcie *ks_pcie, u32 offset, u32 val)
-{
- writel(val, ks_pcie->va_app_base + offset);
-}
-
-void ks_dw_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie, int offset)
-{
- struct dw_pcie *pci = ks_pcie->pci;
- struct pcie_port *pp = &pci->pp;
- struct device *dev = pci->dev;
- u32 pending, vector;
- int src, virq;
-
- pending = ks_dw_app_readl(ks_pcie, MSI0_IRQ_STATUS + (offset << 4));
-
- /*
- * MSI0 status bit 0-3 shows vectors 0, 8, 16, 24, MSI1 status bit
- * shows 1, 9, 17, 25 and so forth
- */
- for (src = 0; src < 4; src++) {
- if (BIT(src) & pending) {
- vector = offset + (src << 3);
- virq = irq_linear_revmap(pp->irq_domain, vector);
- dev_dbg(dev, "irq: bit %d, vector %d, virq %d\n",
- src, vector, virq);
- generic_handle_irq(virq);
- }
- }
-}
-
-void ks_dw_pcie_msi_irq_ack(int irq, struct pcie_port *pp)
-{
- u32 reg_offset, bit_pos;
- struct keystone_pcie *ks_pcie;
- struct dw_pcie *pci;
-
- pci = to_dw_pcie_from_pp(pp);
- ks_pcie = to_keystone_pcie(pci);
- update_reg_offset_bit_pos(irq, &reg_offset, &bit_pos);
-
- ks_dw_app_writel(ks_pcie, MSI0_IRQ_STATUS + (reg_offset << 4),
- BIT(bit_pos));
- ks_dw_app_writel(ks_pcie, IRQ_EOI, reg_offset + MSI_IRQ_OFFSET);
-}
-
-void ks_dw_pcie_msi_set_irq(struct pcie_port *pp, int irq)
-{
- u32 reg_offset, bit_pos;
- struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
- struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
-
- update_reg_offset_bit_pos(irq, &reg_offset, &bit_pos);
- ks_dw_app_writel(ks_pcie, MSI0_IRQ_ENABLE_SET + (reg_offset << 4),
- BIT(bit_pos));
-}
-
-void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
-{
- u32 reg_offset, bit_pos;
- struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
- struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
-
- update_reg_offset_bit_pos(irq, &reg_offset, &bit_pos);
- ks_dw_app_writel(ks_pcie, MSI0_IRQ_ENABLE_CLR + (reg_offset << 4),
- BIT(bit_pos));
-}
-
-int ks_dw_pcie_msi_host_init(struct pcie_port *pp)
-{
- return dw_pcie_allocate_domains(pp);
-}
-
-void ks_dw_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie)
-{
- int i;
-
- for (i = 0; i < PCI_NUM_INTX; i++)
- ks_dw_app_writel(ks_pcie, IRQ_ENABLE_SET + (i << 4), 0x1);
-}
-
-void ks_dw_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, int offset)
-{
- struct dw_pcie *pci = ks_pcie->pci;
- struct device *dev = pci->dev;
- u32 pending;
- int virq;
-
- pending = ks_dw_app_readl(ks_pcie, IRQ_STATUS + (offset << 4));
-
- if (BIT(0) & pending) {
- virq = irq_linear_revmap(ks_pcie->legacy_irq_domain, offset);
- dev_dbg(dev, ": irq: irq_offset %d, virq %d\n", offset, virq);
- generic_handle_irq(virq);
- }
-
- /* EOI the INTx interrupt */
- ks_dw_app_writel(ks_pcie, IRQ_EOI, offset);
-}
-
-void ks_dw_pcie_enable_error_irq(struct keystone_pcie *ks_pcie)
-{
- ks_dw_app_writel(ks_pcie, ERR_IRQ_ENABLE_SET, ERR_IRQ_ALL);
-}
-
-irqreturn_t ks_dw_pcie_handle_error_irq(struct keystone_pcie *ks_pcie)
-{
- u32 status;
-
- status = ks_dw_app_readl(ks_pcie, ERR_IRQ_STATUS_RAW) & ERR_IRQ_ALL;
- if (!status)
- return IRQ_NONE;
-
- if (status & ERR_FATAL_IRQ)
- dev_err(ks_pcie->pci->dev, "fatal error (status %#010x)\n",
- status);
-
- /* Ack the IRQ; status bits are RW1C */
- ks_dw_app_writel(ks_pcie, ERR_IRQ_STATUS, status);
- return IRQ_HANDLED;
-}
-
-static void ks_dw_pcie_ack_legacy_irq(struct irq_data *d)
-{
-}
-
-static void ks_dw_pcie_mask_legacy_irq(struct irq_data *d)
-{
-}
-
-static void ks_dw_pcie_unmask_legacy_irq(struct irq_data *d)
-{
-}
-
-static struct irq_chip ks_dw_pcie_legacy_irq_chip = {
- .name = "Keystone-PCI-Legacy-IRQ",
- .irq_ack = ks_dw_pcie_ack_legacy_irq,
- .irq_mask = ks_dw_pcie_mask_legacy_irq,
- .irq_unmask = ks_dw_pcie_unmask_legacy_irq,
-};
-
-static int ks_dw_pcie_init_legacy_irq_map(struct irq_domain *d,
- unsigned int irq, irq_hw_number_t hw_irq)
-{
- irq_set_chip_and_handler(irq, &ks_dw_pcie_legacy_irq_chip,
- handle_level_irq);
- irq_set_chip_data(irq, d->host_data);
-
- return 0;
-}
-
-static const struct irq_domain_ops ks_dw_pcie_legacy_irq_domain_ops = {
- .map = ks_dw_pcie_init_legacy_irq_map,
- .xlate = irq_domain_xlate_onetwocell,
-};
-
-/**
- * ks_dw_pcie_set_dbi_mode() - Set DBI mode to access overlaid BAR mask
- * registers
- *
- * Since modification of dbi_cs2 involves different clock domain, read the
- * status back to ensure the transition is complete.
- */
-static void ks_dw_pcie_set_dbi_mode(struct keystone_pcie *ks_pcie)
-{
- u32 val;
-
- val = ks_dw_app_readl(ks_pcie, CMD_STATUS);
- ks_dw_app_writel(ks_pcie, CMD_STATUS, DBI_CS2_EN_VAL | val);
-
- do {
- val = ks_dw_app_readl(ks_pcie, CMD_STATUS);
- } while (!(val & DBI_CS2_EN_VAL));
-}
-
-/**
- * ks_dw_pcie_clear_dbi_mode() - Disable DBI mode
- *
- * Since modification of dbi_cs2 involves different clock domain, read the
- * status back to ensure the transition is complete.
- */
-static void ks_dw_pcie_clear_dbi_mode(struct keystone_pcie *ks_pcie)
-{
- u32 val;
-
- val = ks_dw_app_readl(ks_pcie, CMD_STATUS);
- ks_dw_app_writel(ks_pcie, CMD_STATUS, ~DBI_CS2_EN_VAL & val);
-
- do {
- val = ks_dw_app_readl(ks_pcie, CMD_STATUS);
- } while (val & DBI_CS2_EN_VAL);
-}
-
-void ks_dw_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie)
-{
- struct dw_pcie *pci = ks_pcie->pci;
- struct pcie_port *pp = &pci->pp;
- u32 start = pp->mem->start, end = pp->mem->end;
- int i, tr_size;
- u32 val;
-
- /* Disable BARs for inbound access */
- ks_dw_pcie_set_dbi_mode(ks_pcie);
- dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0);
- dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_1, 0);
- ks_dw_pcie_clear_dbi_mode(ks_pcie);
-
- /* Set outbound translation size per window division */
- ks_dw_app_writel(ks_pcie, OB_SIZE, CFG_PCIM_WIN_SZ_IDX & 0x7);
-
- tr_size = (1 << (CFG_PCIM_WIN_SZ_IDX & 0x7)) * SZ_1M;
-
- /* Using Direct 1:1 mapping of RC <-> PCI memory space */
- for (i = 0; (i < CFG_PCIM_WIN_CNT) && (start < end); i++) {
- ks_dw_app_writel(ks_pcie, OB_OFFSET_INDEX(i), start | 1);
- ks_dw_app_writel(ks_pcie, OB_OFFSET_HI(i), 0);
- start += tr_size;
- }
-
- /* Enable OB translation */
- val = ks_dw_app_readl(ks_pcie, CMD_STATUS);
- ks_dw_app_writel(ks_pcie, CMD_STATUS, OB_XLAT_EN_VAL | val);
-}
-
-/**
- * ks_pcie_cfg_setup() - Set up configuration space address for a device
- *
- * @ks_pcie: ptr to keystone_pcie structure
- * @bus: Bus number the device is residing on
- * @devfn: device, function number info
- *
- * Forms and returns the address of configuration space mapped in PCIESS
- * address space 0. Also configures CFG_SETUP for remote configuration space
- * access.
- *
- * The address space has two regions to access configuration - local and remote.
- * We access local region for bus 0 (as RC is attached on bus 0) and remote
- * region for others with TYPE 1 access when bus > 1. As for device on bus = 1,
- * we will do TYPE 0 access as it will be on our secondary bus (logical).
- * CFG_SETUP is needed only for remote configuration access.
- */
-static void __iomem *ks_pcie_cfg_setup(struct keystone_pcie *ks_pcie, u8 bus,
- unsigned int devfn)
-{
- u8 device = PCI_SLOT(devfn), function = PCI_FUNC(devfn);
- struct dw_pcie *pci = ks_pcie->pci;
- struct pcie_port *pp = &pci->pp;
- u32 regval;
-
- if (bus == 0)
- return pci->dbi_base;
-
- regval = (bus << 16) | (device << 8) | function;
-
- /*
- * Since Bus#1 will be a virtual bus, we need to have TYPE0
- * access only.
- * TYPE 1
- */
- if (bus != 1)
- regval |= BIT(24);
-
- ks_dw_app_writel(ks_pcie, CFG_SETUP, regval);
- return pp->va_cfg0_base;
-}
-
-int ks_dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
- unsigned int devfn, int where, int size, u32 *val)
-{
- struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
- struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
- u8 bus_num = bus->number;
- void __iomem *addr;
-
- addr = ks_pcie_cfg_setup(ks_pcie, bus_num, devfn);
-
- return dw_pcie_read(addr + where, size, val);
-}
-
-int ks_dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
- unsigned int devfn, int where, int size, u32 val)
-{
- struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
- struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
- u8 bus_num = bus->number;
- void __iomem *addr;
-
- addr = ks_pcie_cfg_setup(ks_pcie, bus_num, devfn);
-
- return dw_pcie_write(addr + where, size, val);
-}
-
-/**
- * ks_dw_pcie_v3_65_scan_bus() - keystone scan_bus post initialization
- *
- * This sets BAR0 to enable inbound access for MSI_IRQ register
- */
-void ks_dw_pcie_v3_65_scan_bus(struct pcie_port *pp)
-{
- struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
- struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
-
- /* Configure and set up BAR0 */
- ks_dw_pcie_set_dbi_mode(ks_pcie);
-
- /* Enable BAR0 */
- dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 1);
- dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, SZ_4K - 1);
-
- ks_dw_pcie_clear_dbi_mode(ks_pcie);
-
- /*
- * For BAR0, just setting bus address for inbound writes (MSI) should
- * be sufficient. Use physical address to avoid any conflicts.
- */
- dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, ks_pcie->app.start);
-}
-
-/**
- * ks_dw_pcie_link_up() - Check if link up
- */
-int ks_dw_pcie_link_up(struct dw_pcie *pci)
-{
- u32 val;
-
- val = dw_pcie_readl_dbi(pci, DEBUG0);
- return (val & LTSSM_STATE_MASK) == LTSSM_STATE_L0;
-}
-
-void ks_dw_pcie_initiate_link_train(struct keystone_pcie *ks_pcie)
-{
- u32 val;
-
- /* Disable Link training */
- val = ks_dw_app_readl(ks_pcie, CMD_STATUS);
- val &= ~LTSSM_EN_VAL;
- ks_dw_app_writel(ks_pcie, CMD_STATUS, LTSSM_EN_VAL | val);
-
- /* Initiate Link Training */
- val = ks_dw_app_readl(ks_pcie, CMD_STATUS);
- ks_dw_app_writel(ks_pcie, CMD_STATUS, LTSSM_EN_VAL | val);
-}
-
-/**
- * ks_dw_pcie_host_init() - initialize host for v3_65 dw hardware
- *
- * Ioremap the register resources, initialize legacy irq domain
- * and call dw_pcie_v3_65_host_init() API to initialize the Keystone
- * PCI host controller.
- */
-int __init ks_dw_pcie_host_init(struct keystone_pcie *ks_pcie,
- struct device_node *msi_intc_np)
-{
- struct dw_pcie *pci = ks_pcie->pci;
- struct pcie_port *pp = &pci->pp;
- struct device *dev = pci->dev;
- struct platform_device *pdev = to_platform_device(dev);
- struct resource *res;
-
- /* Index 0 is the config reg. space address */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- pci->dbi_base = devm_pci_remap_cfg_resource(dev, res);
- if (IS_ERR(pci->dbi_base))
- return PTR_ERR(pci->dbi_base);
-
- /*
- * We set these same and is used in pcie rd/wr_other_conf
- * functions
- */
- pp->va_cfg0_base = pci->dbi_base + SPACE0_REMOTE_CFG_OFFSET;
- pp->va_cfg1_base = pp->va_cfg0_base;
-
- /* Index 1 is the application reg. space address */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- ks_pcie->va_app_base = devm_ioremap_resource(dev, res);
- if (IS_ERR(ks_pcie->va_app_base))
- return PTR_ERR(ks_pcie->va_app_base);
-
- ks_pcie->app = *res;
-
- /* Create legacy IRQ domain */
- ks_pcie->legacy_irq_domain =
- irq_domain_add_linear(ks_pcie->legacy_intc_np,
- PCI_NUM_INTX,
- &ks_dw_pcie_legacy_irq_domain_ops,
- NULL);
- if (!ks_pcie->legacy_irq_domain) {
- dev_err(dev, "Failed to add irq domain for legacy irqs\n");
- return -EINVAL;
- }
-
- return dw_pcie_host_init(pp);
-}
diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c
index e88bd221fffe..14f2b0b4ed5e 100644
--- a/drivers/pci/controller/dwc/pci-keystone.c
+++ b/drivers/pci/controller/dwc/pci-keystone.c
@@ -9,40 +9,510 @@
* Implementation based on pci-exynos.c and pcie-designware.c
*/
-#include <linux/irqchip/chained_irq.h>
#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/init.h>
#include <linux/interrupt.h>
+#include <linux/irqchip/chained_irq.h>
#include <linux/irqdomain.h>
-#include <linux/init.h>
+#include <linux/mfd/syscon.h>
#include <linux/msi.h>
-#include <linux/of_irq.h>
#include <linux/of.h>
+#include <linux/of_irq.h>
#include <linux/of_pci.h>
-#include <linux/platform_device.h>
#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
#include <linux/resource.h>
#include <linux/signal.h>
#include "pcie-designware.h"
-#include "pci-keystone.h"
-#define DRIVER_NAME "keystone-pcie"
+#define PCIE_VENDORID_MASK 0xffff
+#define PCIE_DEVICEID_SHIFT 16
+
+/* Application registers */
+#define CMD_STATUS 0x004
+#define LTSSM_EN_VAL BIT(0)
+#define OB_XLAT_EN_VAL BIT(1)
+#define DBI_CS2 BIT(5)
+
+#define CFG_SETUP 0x008
+#define CFG_BUS(x) (((x) & 0xff) << 16)
+#define CFG_DEVICE(x) (((x) & 0x1f) << 8)
+#define CFG_FUNC(x) ((x) & 0x7)
+#define CFG_TYPE1 BIT(24)
+
+#define OB_SIZE 0x030
+#define SPACE0_REMOTE_CFG_OFFSET 0x1000
+#define OB_OFFSET_INDEX(n) (0x200 + (8 * (n)))
+#define OB_OFFSET_HI(n) (0x204 + (8 * (n)))
+#define OB_ENABLEN BIT(0)
+#define OB_WIN_SIZE 8 /* 8MB */
+
+/* IRQ register defines */
+#define IRQ_EOI 0x050
+#define IRQ_STATUS 0x184
+#define IRQ_ENABLE_SET 0x188
+#define IRQ_ENABLE_CLR 0x18c
+
+#define MSI_IRQ 0x054
+#define MSI0_IRQ_STATUS 0x104
+#define MSI0_IRQ_ENABLE_SET 0x108
+#define MSI0_IRQ_ENABLE_CLR 0x10c
+#define IRQ_STATUS 0x184
+#define MSI_IRQ_OFFSET 4
+
+#define ERR_IRQ_STATUS 0x1c4
+#define ERR_IRQ_ENABLE_SET 0x1c8
+#define ERR_AER BIT(5) /* ECRC error */
+#define ERR_AXI BIT(4) /* AXI tag lookup fatal error */
+#define ERR_CORR BIT(3) /* Correctable error */
+#define ERR_NONFATAL BIT(2) /* Non-fatal error */
+#define ERR_FATAL BIT(1) /* Fatal error */
+#define ERR_SYS BIT(0) /* System error */
+#define ERR_IRQ_ALL (ERR_AER | ERR_AXI | ERR_CORR | \
+ ERR_NONFATAL | ERR_FATAL | ERR_SYS)
+
+#define MAX_MSI_HOST_IRQS 8
+/* PCIE controller device IDs */
+#define PCIE_RC_K2HK 0xb008
+#define PCIE_RC_K2E 0xb009
+#define PCIE_RC_K2L 0xb00a
+#define PCIE_RC_K2G 0xb00b
+
+#define to_keystone_pcie(x) dev_get_drvdata((x)->dev)
+
+struct keystone_pcie {
+ struct dw_pcie *pci;
+ /* PCI Device ID */
+ u32 device_id;
+ int num_legacy_host_irqs;
+ int legacy_host_irqs[PCI_NUM_INTX];
+ struct device_node *legacy_intc_np;
+
+ int num_msi_host_irqs;
+ int msi_host_irqs[MAX_MSI_HOST_IRQS];
+ int num_lanes;
+ u32 num_viewport;
+ struct phy **phy;
+ struct device_link **link;
+ struct device_node *msi_intc_np;
+ struct irq_domain *legacy_irq_domain;
+ struct device_node *np;
+
+ int error_irq;
+
+ /* Application register space */
+ void __iomem *va_app_base; /* DT 1st resource */
+ struct resource app;
+};
-/* DEV_STAT_CTRL */
-#define PCIE_CAP_BASE 0x70
+static inline void update_reg_offset_bit_pos(u32 offset, u32 *reg_offset,
+ u32 *bit_pos)
+{
+ *reg_offset = offset % 8;
+ *bit_pos = offset >> 3;
+}
-/* PCIE controller device IDs */
-#define PCIE_RC_K2HK 0xb008
-#define PCIE_RC_K2E 0xb009
-#define PCIE_RC_K2L 0xb00a
+static phys_addr_t ks_pcie_get_msi_addr(struct pcie_port *pp)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
+
+ return ks_pcie->app.start + MSI_IRQ;
+}
+
+static u32 ks_pcie_app_readl(struct keystone_pcie *ks_pcie, u32 offset)
+{
+ return readl(ks_pcie->va_app_base + offset);
+}
+
+static void ks_pcie_app_writel(struct keystone_pcie *ks_pcie, u32 offset,
+ u32 val)
+{
+ writel(val, ks_pcie->va_app_base + offset);
+}
+
+static void ks_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie, int offset)
+{
+ struct dw_pcie *pci = ks_pcie->pci;
+ struct pcie_port *pp = &pci->pp;
+ struct device *dev = pci->dev;
+ u32 pending, vector;
+ int src, virq;
+
+ pending = ks_pcie_app_readl(ks_pcie, MSI0_IRQ_STATUS + (offset << 4));
+
+ /*
+ * MSI0 status bit 0-3 shows vectors 0, 8, 16, 24, MSI1 status bit
+ * shows 1, 9, 17, 25 and so forth
+ */
+ for (src = 0; src < 4; src++) {
+ if (BIT(src) & pending) {
+ vector = offset + (src << 3);
+ virq = irq_linear_revmap(pp->irq_domain, vector);
+ dev_dbg(dev, "irq: bit %d, vector %d, virq %d\n",
+ src, vector, virq);
+ generic_handle_irq(virq);
+ }
+ }
+}
+
+static void ks_pcie_msi_irq_ack(int irq, struct pcie_port *pp)
+{
+ u32 reg_offset, bit_pos;
+ struct keystone_pcie *ks_pcie;
+ struct dw_pcie *pci;
+
+ pci = to_dw_pcie_from_pp(pp);
+ ks_pcie = to_keystone_pcie(pci);
+ update_reg_offset_bit_pos(irq, &reg_offset, &bit_pos);
+
+ ks_pcie_app_writel(ks_pcie, MSI0_IRQ_STATUS + (reg_offset << 4),
+ BIT(bit_pos));
+ ks_pcie_app_writel(ks_pcie, IRQ_EOI, reg_offset + MSI_IRQ_OFFSET);
+}
+
+static void ks_pcie_msi_set_irq(struct pcie_port *pp, int irq)
+{
+ u32 reg_offset, bit_pos;
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
+
+ update_reg_offset_bit_pos(irq, &reg_offset, &bit_pos);
+ ks_pcie_app_writel(ks_pcie, MSI0_IRQ_ENABLE_SET + (reg_offset << 4),
+ BIT(bit_pos));
+}
+
+static void ks_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
+{
+ u32 reg_offset, bit_pos;
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
+
+ update_reg_offset_bit_pos(irq, &reg_offset, &bit_pos);
+ ks_pcie_app_writel(ks_pcie, MSI0_IRQ_ENABLE_CLR + (reg_offset << 4),
+ BIT(bit_pos));
+}
+
+static int ks_pcie_msi_host_init(struct pcie_port *pp)
+{
+ return dw_pcie_allocate_domains(pp);
+}
+
+static void ks_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie)
+{
+ int i;
+
+ for (i = 0; i < PCI_NUM_INTX; i++)
+ ks_pcie_app_writel(ks_pcie, IRQ_ENABLE_SET + (i << 4), 0x1);
+}
+
+static void ks_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie,
+ int offset)
+{
+ struct dw_pcie *pci = ks_pcie->pci;
+ struct device *dev = pci->dev;
+ u32 pending;
+ int virq;
+
+ pending = ks_pcie_app_readl(ks_pcie, IRQ_STATUS + (offset << 4));
+
+ if (BIT(0) & pending) {
+ virq = irq_linear_revmap(ks_pcie->legacy_irq_domain, offset);
+ dev_dbg(dev, ": irq: irq_offset %d, virq %d\n", offset, virq);
+ generic_handle_irq(virq);
+ }
+
+ /* EOI the INTx interrupt */
+ ks_pcie_app_writel(ks_pcie, IRQ_EOI, offset);
+}
+
+static void ks_pcie_enable_error_irq(struct keystone_pcie *ks_pcie)
+{
+ ks_pcie_app_writel(ks_pcie, ERR_IRQ_ENABLE_SET, ERR_IRQ_ALL);
+}
+
+static irqreturn_t ks_pcie_handle_error_irq(struct keystone_pcie *ks_pcie)
+{
+ u32 reg;
+ struct device *dev = ks_pcie->pci->dev;
+
+ reg = ks_pcie_app_readl(ks_pcie, ERR_IRQ_STATUS);
+ if (!reg)
+ return IRQ_NONE;
+
+ if (reg & ERR_SYS)
+ dev_err(dev, "System Error\n");
+
+ if (reg & ERR_FATAL)
+ dev_err(dev, "Fatal Error\n");
+
+ if (reg & ERR_NONFATAL)
+ dev_dbg(dev, "Non Fatal Error\n");
+
+ if (reg & ERR_CORR)
+ dev_dbg(dev, "Correctable Error\n");
+
+ if (reg & ERR_AXI)
+ dev_err(dev, "AXI tag lookup fatal Error\n");
+
+ if (reg & ERR_AER)
+ dev_err(dev, "ECRC Error\n");
+
+ ks_pcie_app_writel(ks_pcie, ERR_IRQ_STATUS, reg);
+
+ return IRQ_HANDLED;
+}
+
+static void ks_pcie_ack_legacy_irq(struct irq_data *d)
+{
+}
+
+static void ks_pcie_mask_legacy_irq(struct irq_data *d)
+{
+}
+
+static void ks_pcie_unmask_legacy_irq(struct irq_data *d)
+{
+}
+
+static struct irq_chip ks_pcie_legacy_irq_chip = {
+ .name = "Keystone-PCI-Legacy-IRQ",
+ .irq_ack = ks_pcie_ack_legacy_irq,
+ .irq_mask = ks_pcie_mask_legacy_irq,
+ .irq_unmask = ks_pcie_unmask_legacy_irq,
+};
+
+static int ks_pcie_init_legacy_irq_map(struct irq_domain *d,
+ unsigned int irq,
+ irq_hw_number_t hw_irq)
+{
+ irq_set_chip_and_handler(irq, &ks_pcie_legacy_irq_chip,
+ handle_level_irq);
+ irq_set_chip_data(irq, d->host_data);
+
+ return 0;
+}
+
+static const struct irq_domain_ops ks_pcie_legacy_irq_domain_ops = {
+ .map = ks_pcie_init_legacy_irq_map,
+ .xlate = irq_domain_xlate_onetwocell,
+};
+
+/**
+ * ks_pcie_set_dbi_mode() - Set DBI mode to access overlaid BAR mask
+ * registers
+ *
+ * Since modification of dbi_cs2 involves different clock domain, read the
+ * status back to ensure the transition is complete.
+ */
+static void ks_pcie_set_dbi_mode(struct keystone_pcie *ks_pcie)
+{
+ u32 val;
+
+ val = ks_pcie_app_readl(ks_pcie, CMD_STATUS);
+ val |= DBI_CS2;
+ ks_pcie_app_writel(ks_pcie, CMD_STATUS, val);
+
+ do {
+ val = ks_pcie_app_readl(ks_pcie, CMD_STATUS);
+ } while (!(val & DBI_CS2));
+}
+
+/**
+ * ks_pcie_clear_dbi_mode() - Disable DBI mode
+ *
+ * Since modification of dbi_cs2 involves different clock domain, read the
+ * status back to ensure the transition is complete.
+ */
+static void ks_pcie_clear_dbi_mode(struct keystone_pcie *ks_pcie)
+{
+ u32 val;
+
+ val = ks_pcie_app_readl(ks_pcie, CMD_STATUS);
+ val &= ~DBI_CS2;
+ ks_pcie_app_writel(ks_pcie, CMD_STATUS, val);
+
+ do {
+ val = ks_pcie_app_readl(ks_pcie, CMD_STATUS);
+ } while (val & DBI_CS2);
+}
+
+static void ks_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie)
+{
+ u32 val;
+ u32 num_viewport = ks_pcie->num_viewport;
+ struct dw_pcie *pci = ks_pcie->pci;
+ struct pcie_port *pp = &pci->pp;
+ u64 start = pp->mem->start;
+ u64 end = pp->mem->end;
+ int i;
+
+ /* Disable BARs for inbound access */
+ ks_pcie_set_dbi_mode(ks_pcie);
+ dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0);
+ dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_1, 0);
+ ks_pcie_clear_dbi_mode(ks_pcie);
+
+ val = ilog2(OB_WIN_SIZE);
+ ks_pcie_app_writel(ks_pcie, OB_SIZE, val);
+
+ /* Using Direct 1:1 mapping of RC <-> PCI memory space */
+ for (i = 0; i < num_viewport && (start < end); i++) {
+ ks_pcie_app_writel(ks_pcie, OB_OFFSET_INDEX(i),
+ lower_32_bits(start) | OB_ENABLEN);
+ ks_pcie_app_writel(ks_pcie, OB_OFFSET_HI(i),
+ upper_32_bits(start));
+ start += OB_WIN_SIZE;
+ }
+
+ val = ks_pcie_app_readl(ks_pcie, CMD_STATUS);
+ val |= OB_XLAT_EN_VAL;
+ ks_pcie_app_writel(ks_pcie, CMD_STATUS, val);
+}
+
+static int ks_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
+ unsigned int devfn, int where, int size,
+ u32 *val)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
+ u32 reg;
+
+ reg = CFG_BUS(bus->number) | CFG_DEVICE(PCI_SLOT(devfn)) |
+ CFG_FUNC(PCI_FUNC(devfn));
+ if (bus->parent->number != pp->root_bus_nr)
+ reg |= CFG_TYPE1;
+ ks_pcie_app_writel(ks_pcie, CFG_SETUP, reg);
+
+ return dw_pcie_read(pp->va_cfg0_base + where, size, val);
+}
+
+static int ks_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
+ unsigned int devfn, int where, int size,
+ u32 val)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
+ u32 reg;
+
+ reg = CFG_BUS(bus->number) | CFG_DEVICE(PCI_SLOT(devfn)) |
+ CFG_FUNC(PCI_FUNC(devfn));
+ if (bus->parent->number != pp->root_bus_nr)
+ reg |= CFG_TYPE1;
+ ks_pcie_app_writel(ks_pcie, CFG_SETUP, reg);
+
+ return dw_pcie_write(pp->va_cfg0_base + where, size, val);
+}
+
+/**
+ * ks_pcie_v3_65_scan_bus() - keystone scan_bus post initialization
+ *
+ * This sets BAR0 to enable inbound access for MSI_IRQ register
+ */
+static void ks_pcie_v3_65_scan_bus(struct pcie_port *pp)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
+
+ /* Configure and set up BAR0 */
+ ks_pcie_set_dbi_mode(ks_pcie);
+
+ /* Enable BAR0 */
+ dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 1);
+ dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, SZ_4K - 1);
+
+ ks_pcie_clear_dbi_mode(ks_pcie);
+
+ /*
+ * For BAR0, just setting bus address for inbound writes (MSI) should
+ * be sufficient. Use physical address to avoid any conflicts.
+ */
+ dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, ks_pcie->app.start);
+}
+
+/**
+ * ks_pcie_link_up() - Check if link up
+ */
+static int ks_pcie_link_up(struct dw_pcie *pci)
+{
+ u32 val;
+
+ val = dw_pcie_readl_dbi(pci, PCIE_PORT_DEBUG0);
+ val &= PORT_LOGIC_LTSSM_STATE_MASK;
+ return (val == PORT_LOGIC_LTSSM_STATE_L0);
+}
+
+static void ks_pcie_initiate_link_train(struct keystone_pcie *ks_pcie)
+{
+ u32 val;
-#define to_keystone_pcie(x) dev_get_drvdata((x)->dev)
+ /* Disable Link training */
+ val = ks_pcie_app_readl(ks_pcie, CMD_STATUS);
+ val &= ~LTSSM_EN_VAL;
+ ks_pcie_app_writel(ks_pcie, CMD_STATUS, LTSSM_EN_VAL | val);
-static void quirk_limit_mrrs(struct pci_dev *dev)
+ /* Initiate Link Training */
+ val = ks_pcie_app_readl(ks_pcie, CMD_STATUS);
+ ks_pcie_app_writel(ks_pcie, CMD_STATUS, LTSSM_EN_VAL | val);
+}
+
+/**
+ * ks_pcie_dw_host_init() - initialize host for v3_65 dw hardware
+ *
+ * Ioremap the register resources, initialize legacy irq domain
+ * and call dw_pcie_v3_65_host_init() API to initialize the Keystone
+ * PCI host controller.
+ */
+static int __init ks_pcie_dw_host_init(struct keystone_pcie *ks_pcie)
+{
+ struct dw_pcie *pci = ks_pcie->pci;
+ struct pcie_port *pp = &pci->pp;
+ struct device *dev = pci->dev;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct resource *res;
+
+ /* Index 0 is the config reg. space address */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ pci->dbi_base = devm_pci_remap_cfg_resource(dev, res);
+ if (IS_ERR(pci->dbi_base))
+ return PTR_ERR(pci->dbi_base);
+
+ /*
+ * We set these same and is used in pcie rd/wr_other_conf
+ * functions
+ */
+ pp->va_cfg0_base = pci->dbi_base + SPACE0_REMOTE_CFG_OFFSET;
+ pp->va_cfg1_base = pp->va_cfg0_base;
+
+ /* Index 1 is the application reg. space address */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ ks_pcie->va_app_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(ks_pcie->va_app_base))
+ return PTR_ERR(ks_pcie->va_app_base);
+
+ ks_pcie->app = *res;
+
+ /* Create legacy IRQ domain */
+ ks_pcie->legacy_irq_domain =
+ irq_domain_add_linear(ks_pcie->legacy_intc_np,
+ PCI_NUM_INTX,
+ &ks_pcie_legacy_irq_domain_ops,
+ NULL);
+ if (!ks_pcie->legacy_irq_domain) {
+ dev_err(dev, "Failed to add irq domain for legacy irqs\n");
+ return -EINVAL;
+ }
+
+ return dw_pcie_host_init(pp);
+}
+
+static void ks_pcie_quirk(struct pci_dev *dev)
{
struct pci_bus *bus = dev->bus;
- struct pci_dev *bridge = bus->self;
+ struct pci_dev *bridge;
static const struct pci_device_id rc_pci_devids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCIE_RC_K2HK),
.class = PCI_CLASS_BRIDGE_PCI << 8, .class_mask = ~0, },
@@ -50,11 +520,13 @@ static void quirk_limit_mrrs(struct pci_dev *dev)
.class = PCI_CLASS_BRIDGE_PCI << 8, .class_mask = ~0, },
{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCIE_RC_K2L),
.class = PCI_CLASS_BRIDGE_PCI << 8, .class_mask = ~0, },
+ { PCI_DEVICE(PCI_VENDOR_ID_TI, PCIE_RC_K2G),
+ .class = PCI_CLASS_BRIDGE_PCI << 8, .class_mask = ~0, },
{ 0, },
};
if (pci_is_root_bus(bus))
- return;
+ bridge = dev;
/* look for the host bridge */
while (!pci_is_root_bus(bus)) {
@@ -62,43 +534,39 @@ static void quirk_limit_mrrs(struct pci_dev *dev)
bus = bus->parent;
}
- if (bridge) {
- /*
- * Keystone PCI controller has a h/w limitation of
- * 256 bytes maximum read request size. It can't handle
- * anything higher than this. So force this limit on
- * all downstream devices.
- */
- if (pci_match_id(rc_pci_devids, bridge)) {
- if (pcie_get_readrq(dev) > 256) {
- dev_info(&dev->dev, "limiting MRRS to 256\n");
- pcie_set_readrq(dev, 256);
- }
+ if (!bridge)
+ return;
+
+ /*
+ * Keystone PCI controller has a h/w limitation of
+ * 256 bytes maximum read request size. It can't handle
+ * anything higher than this. So force this limit on
+ * all downstream devices.
+ */
+ if (pci_match_id(rc_pci_devids, bridge)) {
+ if (pcie_get_readrq(dev) > 256) {
+ dev_info(&dev->dev, "limiting MRRS to 256\n");
+ pcie_set_readrq(dev, 256);
}
}
}
-DECLARE_PCI_FIXUP_ENABLE(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_mrrs);
+DECLARE_PCI_FIXUP_ENABLE(PCI_ANY_ID, PCI_ANY_ID, ks_pcie_quirk);
static int ks_pcie_establish_link(struct keystone_pcie *ks_pcie)
{
struct dw_pcie *pci = ks_pcie->pci;
- struct pcie_port *pp = &pci->pp;
struct device *dev = pci->dev;
- unsigned int retries;
-
- dw_pcie_setup_rc(pp);
if (dw_pcie_link_up(pci)) {
dev_info(dev, "Link already up\n");
return 0;
}
+ ks_pcie_initiate_link_train(ks_pcie);
+
/* check if the link is up or not */
- for (retries = 0; retries < 5; retries++) {
- ks_dw_pcie_initiate_link_train(ks_pcie);
- if (!dw_pcie_wait_for_link(pci))
- return 0;
- }
+ if (!dw_pcie_wait_for_link(pci))
+ return 0;
dev_err(dev, "phy link never came up\n");
return -ETIMEDOUT;
@@ -121,7 +589,7 @@ static void ks_pcie_msi_irq_handler(struct irq_desc *desc)
* ack operation.
*/
chained_irq_enter(chip, desc);
- ks_dw_pcie_handle_msi_irq(ks_pcie, offset);
+ ks_pcie_handle_msi_irq(ks_pcie, offset);
chained_irq_exit(chip, desc);
}
@@ -150,7 +618,7 @@ static void ks_pcie_legacy_irq_handler(struct irq_desc *desc)
* ack operation.
*/
chained_irq_enter(chip, desc);
- ks_dw_pcie_handle_legacy_irq(ks_pcie, irq_offset);
+ ks_pcie_handle_legacy_irq(ks_pcie, irq_offset);
chained_irq_exit(chip, desc);
}
@@ -222,7 +690,7 @@ static void ks_pcie_setup_interrupts(struct keystone_pcie *ks_pcie)
ks_pcie_legacy_irq_handler,
ks_pcie);
}
- ks_dw_pcie_enable_legacy_irqs(ks_pcie);
+ ks_pcie_enable_legacy_irqs(ks_pcie);
/* MSI IRQ */
if (IS_ENABLED(CONFIG_PCI_MSI)) {
@@ -234,7 +702,7 @@ static void ks_pcie_setup_interrupts(struct keystone_pcie *ks_pcie)
}
if (ks_pcie->error_irq > 0)
- ks_dw_pcie_enable_error_irq(ks_pcie);
+ ks_pcie_enable_error_irq(ks_pcie);
}
/*
@@ -242,8 +710,8 @@ static void ks_pcie_setup_interrupts(struct keystone_pcie *ks_pcie)
* bus error instead of returning 0xffffffff. This handler always returns 0
* for this kind of faults.
*/
-static int keystone_pcie_fault(unsigned long addr, unsigned int fsr,
- struct pt_regs *regs)
+static int ks_pcie_fault(unsigned long addr, unsigned int fsr,
+ struct pt_regs *regs)
{
unsigned long instr = *(unsigned long *) instruction_pointer(regs);
@@ -257,59 +725,78 @@ static int keystone_pcie_fault(unsigned long addr, unsigned int fsr,
return 0;
}
+static int __init ks_pcie_init_id(struct keystone_pcie *ks_pcie)
+{
+ int ret;
+ unsigned int id;
+ struct regmap *devctrl_regs;
+ struct dw_pcie *pci = ks_pcie->pci;
+ struct device *dev = pci->dev;
+ struct device_node *np = dev->of_node;
+
+ devctrl_regs = syscon_regmap_lookup_by_phandle(np, "ti,syscon-pcie-id");
+ if (IS_ERR(devctrl_regs))
+ return PTR_ERR(devctrl_regs);
+
+ ret = regmap_read(devctrl_regs, 0, &id);
+ if (ret)
+ return ret;
+
+ dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, id & PCIE_VENDORID_MASK);
+ dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, id >> PCIE_DEVICEID_SHIFT);
+
+ return 0;
+}
+
static int __init ks_pcie_host_init(struct pcie_port *pp)
{
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
- u32 val;
+ int ret;
+
+ dw_pcie_setup_rc(pp);
ks_pcie_establish_link(ks_pcie);
- ks_dw_pcie_setup_rc_app_regs(ks_pcie);
+ ks_pcie_setup_rc_app_regs(ks_pcie);
ks_pcie_setup_interrupts(ks_pcie);
writew(PCI_IO_RANGE_TYPE_32 | (PCI_IO_RANGE_TYPE_32 << 8),
pci->dbi_base + PCI_IO_BASE);
- /* update the Vendor ID */
- writew(ks_pcie->device_id, pci->dbi_base + PCI_DEVICE_ID);
-
- /* update the DEV_STAT_CTRL to publish right mrrs */
- val = readl(pci->dbi_base + PCIE_CAP_BASE + PCI_EXP_DEVCTL);
- val &= ~PCI_EXP_DEVCTL_READRQ;
- /* set the mrrs to 256 bytes */
- val |= BIT(12);
- writel(val, pci->dbi_base + PCIE_CAP_BASE + PCI_EXP_DEVCTL);
+ ret = ks_pcie_init_id(ks_pcie);
+ if (ret < 0)
+ return ret;
/*
* PCIe access errors that result into OCP errors are caught by ARM as
* "External aborts"
*/
- hook_fault_code(17, keystone_pcie_fault, SIGBUS, 0,
+ hook_fault_code(17, ks_pcie_fault, SIGBUS, 0,
"Asynchronous external abort");
return 0;
}
-static const struct dw_pcie_host_ops keystone_pcie_host_ops = {
- .rd_other_conf = ks_dw_pcie_rd_other_conf,
- .wr_other_conf = ks_dw_pcie_wr_other_conf,
+static const struct dw_pcie_host_ops ks_pcie_host_ops = {
+ .rd_other_conf = ks_pcie_rd_other_conf,
+ .wr_other_conf = ks_pcie_wr_other_conf,
.host_init = ks_pcie_host_init,
- .msi_set_irq = ks_dw_pcie_msi_set_irq,
- .msi_clear_irq = ks_dw_pcie_msi_clear_irq,
- .get_msi_addr = ks_dw_pcie_get_msi_addr,
- .msi_host_init = ks_dw_pcie_msi_host_init,
- .msi_irq_ack = ks_dw_pcie_msi_irq_ack,
- .scan_bus = ks_dw_pcie_v3_65_scan_bus,
+ .msi_set_irq = ks_pcie_msi_set_irq,
+ .msi_clear_irq = ks_pcie_msi_clear_irq,
+ .get_msi_addr = ks_pcie_get_msi_addr,
+ .msi_host_init = ks_pcie_msi_host_init,
+ .msi_irq_ack = ks_pcie_msi_irq_ack,
+ .scan_bus = ks_pcie_v3_65_scan_bus,
};
-static irqreturn_t pcie_err_irq_handler(int irq, void *priv)
+static irqreturn_t ks_pcie_err_irq_handler(int irq, void *priv)
{
struct keystone_pcie *ks_pcie = priv;
- return ks_dw_pcie_handle_error_irq(ks_pcie);
+ return ks_pcie_handle_error_irq(ks_pcie);
}
-static int __init ks_add_pcie_port(struct keystone_pcie *ks_pcie,
- struct platform_device *pdev)
+static int __init ks_pcie_add_pcie_port(struct keystone_pcie *ks_pcie,
+ struct platform_device *pdev)
{
struct dw_pcie *pci = ks_pcie->pci;
struct pcie_port *pp = &pci->pp;
@@ -338,7 +825,7 @@ static int __init ks_add_pcie_port(struct keystone_pcie *ks_pcie,
if (ks_pcie->error_irq <= 0)
dev_info(dev, "no error IRQ defined\n");
else {
- ret = request_irq(ks_pcie->error_irq, pcie_err_irq_handler,
+ ret = request_irq(ks_pcie->error_irq, ks_pcie_err_irq_handler,
IRQF_SHARED, "pcie-error-irq", ks_pcie);
if (ret < 0) {
dev_err(dev, "failed to request error IRQ %d\n",
@@ -347,8 +834,8 @@ static int __init ks_add_pcie_port(struct keystone_pcie *ks_pcie,
}
}
- pp->ops = &keystone_pcie_host_ops;
- ret = ks_dw_pcie_host_init(ks_pcie, ks_pcie->msi_intc_np);
+ pp->ops = &ks_pcie_host_ops;
+ ret = ks_pcie_dw_host_init(ks_pcie);
if (ret) {
dev_err(dev, "failed to initialize host\n");
return ret;
@@ -365,28 +852,62 @@ static const struct of_device_id ks_pcie_of_match[] = {
{ },
};
-static const struct dw_pcie_ops dw_pcie_ops = {
- .link_up = ks_dw_pcie_link_up,
+static const struct dw_pcie_ops ks_pcie_dw_pcie_ops = {
+ .link_up = ks_pcie_link_up,
};
-static int __exit ks_pcie_remove(struct platform_device *pdev)
+static void ks_pcie_disable_phy(struct keystone_pcie *ks_pcie)
{
- struct keystone_pcie *ks_pcie = platform_get_drvdata(pdev);
+ int num_lanes = ks_pcie->num_lanes;
- clk_disable_unprepare(ks_pcie->clk);
+ while (num_lanes--) {
+ phy_power_off(ks_pcie->phy[num_lanes]);
+ phy_exit(ks_pcie->phy[num_lanes]);
+ }
+}
+
+static int ks_pcie_enable_phy(struct keystone_pcie *ks_pcie)
+{
+ int i;
+ int ret;
+ int num_lanes = ks_pcie->num_lanes;
+
+ for (i = 0; i < num_lanes; i++) {
+ ret = phy_init(ks_pcie->phy[i]);
+ if (ret < 0)
+ goto err_phy;
+
+ ret = phy_power_on(ks_pcie->phy[i]);
+ if (ret < 0) {
+ phy_exit(ks_pcie->phy[i]);
+ goto err_phy;
+ }
+ }
return 0;
+
+err_phy:
+ while (--i >= 0) {
+ phy_power_off(ks_pcie->phy[i]);
+ phy_exit(ks_pcie->phy[i]);
+ }
+
+ return ret;
}
static int __init ks_pcie_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
struct dw_pcie *pci;
struct keystone_pcie *ks_pcie;
- struct resource *res;
- void __iomem *reg_p;
- struct phy *phy;
+ struct device_link **link;
+ u32 num_viewport;
+ struct phy **phy;
+ u32 num_lanes;
+ char name[10];
int ret;
+ int i;
ks_pcie = devm_kzalloc(dev, sizeof(*ks_pcie), GFP_KERNEL);
if (!ks_pcie)
@@ -397,54 +918,99 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
return -ENOMEM;
pci->dev = dev;
- pci->ops = &dw_pcie_ops;
+ pci->ops = &ks_pcie_dw_pcie_ops;
- ks_pcie->pci = pci;
+ ret = of_property_read_u32(np, "num-viewport", &num_viewport);
+ if (ret < 0) {
+ dev_err(dev, "unable to read *num-viewport* property\n");
+ return ret;
+ }
- /* initialize SerDes Phy if present */
- phy = devm_phy_get(dev, "pcie-phy");
- if (PTR_ERR_OR_ZERO(phy) == -EPROBE_DEFER)
- return PTR_ERR(phy);
+ ret = of_property_read_u32(np, "num-lanes", &num_lanes);
+ if (ret)
+ num_lanes = 1;
- if (!IS_ERR_OR_NULL(phy)) {
- ret = phy_init(phy);
- if (ret < 0)
- return ret;
+ phy = devm_kzalloc(dev, sizeof(*phy) * num_lanes, GFP_KERNEL);
+ if (!phy)
+ return -ENOMEM;
+
+ link = devm_kzalloc(dev, sizeof(*link) * num_lanes, GFP_KERNEL);
+ if (!link)
+ return -ENOMEM;
+
+ for (i = 0; i < num_lanes; i++) {
+ snprintf(name, sizeof(name), "pcie-phy%d", i);
+ phy[i] = devm_phy_optional_get(dev, name);
+ if (IS_ERR(phy[i])) {
+ ret = PTR_ERR(phy[i]);
+ goto err_link;
+ }
+
+ if (!phy[i])
+ continue;
+
+ link[i] = device_link_add(dev, &phy[i]->dev, DL_FLAG_STATELESS);
+ if (!link[i]) {
+ ret = -EINVAL;
+ goto err_link;
+ }
}
- /* index 2 is to read PCI DEVICE_ID */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
- reg_p = devm_ioremap_resource(dev, res);
- if (IS_ERR(reg_p))
- return PTR_ERR(reg_p);
- ks_pcie->device_id = readl(reg_p) >> 16;
- devm_iounmap(dev, reg_p);
- devm_release_mem_region(dev, res->start, resource_size(res));
+ ks_pcie->np = np;
+ ks_pcie->pci = pci;
+ ks_pcie->link = link;
+ ks_pcie->num_lanes = num_lanes;
+ ks_pcie->num_viewport = num_viewport;
+ ks_pcie->phy = phy;
- ks_pcie->np = dev->of_node;
- platform_set_drvdata(pdev, ks_pcie);
- ks_pcie->clk = devm_clk_get(dev, "pcie");
- if (IS_ERR(ks_pcie->clk)) {
- dev_err(dev, "Failed to get pcie rc clock\n");
- return PTR_ERR(ks_pcie->clk);
+ ret = ks_pcie_enable_phy(ks_pcie);
+ if (ret) {
+ dev_err(dev, "failed to enable phy\n");
+ goto err_link;
}
- ret = clk_prepare_enable(ks_pcie->clk);
- if (ret)
- return ret;
platform_set_drvdata(pdev, ks_pcie);
+ pm_runtime_enable(dev);
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0) {
+ dev_err(dev, "pm_runtime_get_sync failed\n");
+ goto err_get_sync;
+ }
- ret = ks_add_pcie_port(ks_pcie, pdev);
+ ret = ks_pcie_add_pcie_port(ks_pcie, pdev);
if (ret < 0)
- goto fail_clk;
+ goto err_get_sync;
return 0;
-fail_clk:
- clk_disable_unprepare(ks_pcie->clk);
+
+err_get_sync:
+ pm_runtime_put(dev);
+ pm_runtime_disable(dev);
+ ks_pcie_disable_phy(ks_pcie);
+
+err_link:
+ while (--i >= 0 && link[i])
+ device_link_del(link[i]);
return ret;
}
+static int __exit ks_pcie_remove(struct platform_device *pdev)
+{
+ struct keystone_pcie *ks_pcie = platform_get_drvdata(pdev);
+ struct device_link **link = ks_pcie->link;
+ int num_lanes = ks_pcie->num_lanes;
+ struct device *dev = &pdev->dev;
+
+ pm_runtime_put(dev);
+ pm_runtime_disable(dev);
+ ks_pcie_disable_phy(ks_pcie);
+ while (num_lanes--)
+ device_link_del(link[num_lanes]);
+
+ return 0;
+}
+
static struct platform_driver ks_pcie_driver __refdata = {
.probe = ks_pcie_probe,
.remove = __exit_p(ks_pcie_remove),
diff --git a/drivers/pci/controller/dwc/pci-keystone.h b/drivers/pci/controller/dwc/pci-keystone.h
deleted file mode 100644
index 8a13da391543..000000000000
--- a/drivers/pci/controller/dwc/pci-keystone.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Keystone PCI Controller's common includes
- *
- * Copyright (C) 2013-2014 Texas Instruments., Ltd.
- * http://www.ti.com
- *
- * Author: Murali Karicheri <m-karicheri2@ti.com>
- */
-
-#define MAX_MSI_HOST_IRQS 8
-
-struct keystone_pcie {
- struct dw_pcie *pci;
- struct clk *clk;
- /* PCI Device ID */
- u32 device_id;
- int num_legacy_host_irqs;
- int legacy_host_irqs[PCI_NUM_INTX];
- struct device_node *legacy_intc_np;
-
- int num_msi_host_irqs;
- int msi_host_irqs[MAX_MSI_HOST_IRQS];
- struct device_node *msi_intc_np;
- struct irq_domain *legacy_irq_domain;
- struct device_node *np;
-
- int error_irq;
-
- /* Application register space */
- void __iomem *va_app_base; /* DT 1st resource */
- struct resource app;
-};
-
-/* Keystone DW specific MSI controller APIs/definitions */
-void ks_dw_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie, int offset);
-phys_addr_t ks_dw_pcie_get_msi_addr(struct pcie_port *pp);
-
-/* Keystone specific PCI controller APIs */
-void ks_dw_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie);
-void ks_dw_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, int offset);
-void ks_dw_pcie_enable_error_irq(struct keystone_pcie *ks_pcie);
-irqreturn_t ks_dw_pcie_handle_error_irq(struct keystone_pcie *ks_pcie);
-int ks_dw_pcie_host_init(struct keystone_pcie *ks_pcie,
- struct device_node *msi_intc_np);
-int ks_dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
- unsigned int devfn, int where, int size, u32 val);
-int ks_dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
- unsigned int devfn, int where, int size, u32 *val);
-void ks_dw_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie);
-void ks_dw_pcie_initiate_link_train(struct keystone_pcie *ks_pcie);
-void ks_dw_pcie_msi_irq_ack(int i, struct pcie_port *pp);
-void ks_dw_pcie_msi_set_irq(struct pcie_port *pp, int irq);
-void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq);
-void ks_dw_pcie_v3_65_scan_bus(struct pcie_port *pp);
-int ks_dw_pcie_msi_host_init(struct pcie_port *pp);
-int ks_dw_pcie_link_up(struct dw_pcie *pci);
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index 9f1a5e399b70..0989d880ac46 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -36,6 +36,10 @@
#define PORT_LINK_MODE_4_LANES (0x7 << 16)
#define PORT_LINK_MODE_8_LANES (0xf << 16)
+#define PCIE_PORT_DEBUG0 0x728
+#define PORT_LOGIC_LTSSM_STATE_MASK 0x1f
+#define PORT_LOGIC_LTSSM_STATE_L0 0x11
+
#define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C
#define PORT_LOGIC_SPEED_CHANGE (0x1 << 17)
#define PORT_LOGIC_LINK_WIDTH_MASK (0x1f << 8)
diff --git a/drivers/pci/controller/dwc/pcie-kirin.c b/drivers/pci/controller/dwc/pcie-kirin.c
index 5352e0c3be82..9b599296205d 100644
--- a/drivers/pci/controller/dwc/pcie-kirin.c
+++ b/drivers/pci/controller/dwc/pcie-kirin.c
@@ -467,8 +467,8 @@ static int kirin_pcie_add_msi(struct dw_pcie *pci,
return 0;
}
-static int __init kirin_add_pcie_port(struct dw_pcie *pci,
- struct platform_device *pdev)
+static int kirin_add_pcie_port(struct dw_pcie *pci,
+ struct platform_device *pdev)
{
int ret;
diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
index 4352c1cb926d..d185ea5fe996 100644
--- a/drivers/pci/controller/dwc/pcie-qcom.c
+++ b/drivers/pci/controller/dwc/pcie-qcom.c
@@ -1089,7 +1089,6 @@ static int qcom_pcie_host_init(struct pcie_port *pp)
struct qcom_pcie *pcie = to_qcom_pcie(pci);
int ret;
- pm_runtime_get_sync(pci->dev);
qcom_ep_reset_assert(pcie);
ret = pcie->ops->init(pcie);
@@ -1126,7 +1125,6 @@ err_disable_phy:
phy_power_off(pcie->phy);
err_deinit:
pcie->ops->deinit(pcie);
- pm_runtime_put(pci->dev);
return ret;
}
@@ -1216,6 +1214,12 @@ static int qcom_pcie_probe(struct platform_device *pdev)
return -ENOMEM;
pm_runtime_enable(dev);
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0) {
+ pm_runtime_disable(dev);
+ return ret;
+ }
+
pci->dev = dev;
pci->ops = &dw_pcie_ops;
pp = &pci->pp;
@@ -1225,44 +1229,56 @@ static int qcom_pcie_probe(struct platform_device *pdev)
pcie->ops = of_device_get_match_data(dev);
pcie->reset = devm_gpiod_get_optional(dev, "perst", GPIOD_OUT_LOW);
- if (IS_ERR(pcie->reset))
- return PTR_ERR(pcie->reset);
+ if (IS_ERR(pcie->reset)) {
+ ret = PTR_ERR(pcie->reset);
+ goto err_pm_runtime_put;
+ }
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "parf");
pcie->parf = devm_ioremap_resource(dev, res);
- if (IS_ERR(pcie->parf))
- return PTR_ERR(pcie->parf);
+ if (IS_ERR(pcie->parf)) {
+ ret = PTR_ERR(pcie->parf);
+ goto err_pm_runtime_put;
+ }
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
pci->dbi_base = devm_pci_remap_cfg_resource(dev, res);
- if (IS_ERR(pci->dbi_base))
- return PTR_ERR(pci->dbi_base);
+ if (IS_ERR(pci->dbi_base)) {
+ ret = PTR_ERR(pci->dbi_base);
+ goto err_pm_runtime_put;
+ }
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "elbi");
pcie->elbi = devm_ioremap_resource(dev, res);
- if (IS_ERR(pcie->elbi))
- return PTR_ERR(pcie->elbi);
+ if (IS_ERR(pcie->elbi)) {
+ ret = PTR_ERR(pcie->elbi);
+ goto err_pm_runtime_put;
+ }
pcie->phy = devm_phy_optional_get(dev, "pciephy");
- if (IS_ERR(pcie->phy))
- return PTR_ERR(pcie->phy);
+ if (IS_ERR(pcie->phy)) {
+ ret = PTR_ERR(pcie->phy);
+ goto err_pm_runtime_put;
+ }
ret = pcie->ops->get_resources(pcie);
if (ret)
- return ret;
+ goto err_pm_runtime_put;
pp->ops = &qcom_pcie_dw_ops;
if (IS_ENABLED(CONFIG_PCI_MSI)) {
pp->msi_irq = platform_get_irq_byname(pdev, "msi");
- if (pp->msi_irq < 0)
- return pp->msi_irq;
+ if (pp->msi_irq < 0) {
+ ret = pp->msi_irq;
+ goto err_pm_runtime_put;
+ }
}
ret = phy_init(pcie->phy);
if (ret) {
pm_runtime_disable(&pdev->dev);
- return ret;
+ goto err_pm_runtime_put;
}
platform_set_drvdata(pdev, pcie);
@@ -1271,10 +1287,16 @@ static int qcom_pcie_probe(struct platform_device *pdev)
if (ret) {
dev_err(dev, "cannot initialize host\n");
pm_runtime_disable(&pdev->dev);
- return ret;
+ goto err_pm_runtime_put;
}
return 0;
+
+err_pm_runtime_put:
+ pm_runtime_put(dev);
+ pm_runtime_disable(dev);
+
+ return ret;
}
static const struct of_device_id qcom_pcie_match[] = {
diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c
index 6b4555ff2548..750081c1cb48 100644
--- a/drivers/pci/controller/pci-aardvark.c
+++ b/drivers/pci/controller/pci-aardvark.c
@@ -20,12 +20,16 @@
#include <linux/of_pci.h>
#include "../pci.h"
+#include "../pci-bridge-emul.h"
/* PCIe core registers */
+#define PCIE_CORE_DEV_ID_REG 0x0
#define PCIE_CORE_CMD_STATUS_REG 0x4
#define PCIE_CORE_CMD_IO_ACCESS_EN BIT(0)
#define PCIE_CORE_CMD_MEM_ACCESS_EN BIT(1)
#define PCIE_CORE_CMD_MEM_IO_REQ_EN BIT(2)
+#define PCIE_CORE_DEV_REV_REG 0x8
+#define PCIE_CORE_PCIEXP_CAP 0xc0
#define PCIE_CORE_DEV_CTRL_STATS_REG 0xc8
#define PCIE_CORE_DEV_CTRL_STATS_RELAX_ORDER_DISABLE (0 << 4)
#define PCIE_CORE_DEV_CTRL_STATS_MAX_PAYLOAD_SZ_SHIFT 5
@@ -41,7 +45,10 @@
#define PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX_EN BIT(6)
#define PCIE_CORE_ERR_CAPCTL_ECRC_CHCK BIT(7)
#define PCIE_CORE_ERR_CAPCTL_ECRC_CHCK_RCV BIT(8)
-
+#define PCIE_CORE_INT_A_ASSERT_ENABLE 1
+#define PCIE_CORE_INT_B_ASSERT_ENABLE 2
+#define PCIE_CORE_INT_C_ASSERT_ENABLE 3
+#define PCIE_CORE_INT_D_ASSERT_ENABLE 4
/* PIO registers base address and register offsets */
#define PIO_BASE_ADDR 0x4000
#define PIO_CTRL (PIO_BASE_ADDR + 0x0)
@@ -93,7 +100,9 @@
#define PCIE_CORE_CTRL2_STRICT_ORDER_ENABLE BIT(5)
#define PCIE_CORE_CTRL2_OB_WIN_ENABLE BIT(6)
#define PCIE_CORE_CTRL2_MSI_ENABLE BIT(10)
+#define PCIE_MSG_LOG_REG (CONTROL_BASE_ADDR + 0x30)
#define PCIE_ISR0_REG (CONTROL_BASE_ADDR + 0x40)
+#define PCIE_MSG_PM_PME_MASK BIT(7)
#define PCIE_ISR0_MASK_REG (CONTROL_BASE_ADDR + 0x44)
#define PCIE_ISR0_MSI_INT_PENDING BIT(24)
#define PCIE_ISR0_INTX_ASSERT(val) BIT(16 + (val))
@@ -189,6 +198,7 @@ struct advk_pcie {
struct mutex msi_used_lock;
u16 msi_msg;
int root_bus_nr;
+ struct pci_bridge_emul bridge;
};
static inline void advk_writel(struct advk_pcie *pcie, u32 val, u64 reg)
@@ -390,6 +400,109 @@ static int advk_pcie_wait_pio(struct advk_pcie *pcie)
return -ETIMEDOUT;
}
+
+static pci_bridge_emul_read_status_t
+advk_pci_bridge_emul_pcie_conf_read(struct pci_bridge_emul *bridge,
+ int reg, u32 *value)
+{
+ struct advk_pcie *pcie = bridge->data;
+
+
+ switch (reg) {
+ case PCI_EXP_SLTCTL:
+ *value = PCI_EXP_SLTSTA_PDS << 16;
+ return PCI_BRIDGE_EMUL_HANDLED;
+
+ case PCI_EXP_RTCTL: {
+ u32 val = advk_readl(pcie, PCIE_ISR0_MASK_REG);
+ *value = (val & PCIE_MSG_PM_PME_MASK) ? PCI_EXP_RTCTL_PMEIE : 0;
+ return PCI_BRIDGE_EMUL_HANDLED;
+ }
+
+ case PCI_EXP_RTSTA: {
+ u32 isr0 = advk_readl(pcie, PCIE_ISR0_REG);
+ u32 msglog = advk_readl(pcie, PCIE_MSG_LOG_REG);
+ *value = (isr0 & PCIE_MSG_PM_PME_MASK) << 16 | (msglog >> 16);
+ return PCI_BRIDGE_EMUL_HANDLED;
+ }
+
+ case PCI_CAP_LIST_ID:
+ case PCI_EXP_DEVCAP:
+ case PCI_EXP_DEVCTL:
+ case PCI_EXP_LNKCAP:
+ case PCI_EXP_LNKCTL:
+ *value = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + reg);
+ return PCI_BRIDGE_EMUL_HANDLED;
+ default:
+ return PCI_BRIDGE_EMUL_NOT_HANDLED;
+ }
+
+}
+
+static void
+advk_pci_bridge_emul_pcie_conf_write(struct pci_bridge_emul *bridge,
+ int reg, u32 old, u32 new, u32 mask)
+{
+ struct advk_pcie *pcie = bridge->data;
+
+ switch (reg) {
+ case PCI_EXP_DEVCTL:
+ case PCI_EXP_LNKCTL:
+ advk_writel(pcie, new, PCIE_CORE_PCIEXP_CAP + reg);
+ break;
+
+ case PCI_EXP_RTCTL:
+ new = (new & PCI_EXP_RTCTL_PMEIE) << 3;
+ advk_writel(pcie, new, PCIE_ISR0_MASK_REG);
+ break;
+
+ case PCI_EXP_RTSTA:
+ new = (new & PCI_EXP_RTSTA_PME) >> 9;
+ advk_writel(pcie, new, PCIE_ISR0_REG);
+ break;
+
+ default:
+ break;
+ }
+}
+
+struct pci_bridge_emul_ops advk_pci_bridge_emul_ops = {
+ .read_pcie = advk_pci_bridge_emul_pcie_conf_read,
+ .write_pcie = advk_pci_bridge_emul_pcie_conf_write,
+};
+
+/*
+ * Initialize the configuration space of the PCI-to-PCI bridge
+ * associated with the given PCIe interface.
+ */
+static void advk_sw_pci_bridge_init(struct advk_pcie *pcie)
+{
+ struct pci_bridge_emul *bridge = &pcie->bridge;
+
+ bridge->conf.vendor = advk_readl(pcie, PCIE_CORE_DEV_ID_REG) & 0xffff;
+ bridge->conf.device = advk_readl(pcie, PCIE_CORE_DEV_ID_REG) >> 16;
+ bridge->conf.class_revision =
+ advk_readl(pcie, PCIE_CORE_DEV_REV_REG) & 0xff;
+
+ /* Support 32 bits I/O addressing */
+ bridge->conf.iobase = PCI_IO_RANGE_TYPE_32;
+ bridge->conf.iolimit = PCI_IO_RANGE_TYPE_32;
+
+ /* Support 64 bits memory pref */
+ bridge->conf.pref_mem_base = PCI_PREF_RANGE_TYPE_64;
+ bridge->conf.pref_mem_limit = PCI_PREF_RANGE_TYPE_64;
+
+ /* Support interrupt A for MSI feature */
+ bridge->conf.intpin = PCIE_CORE_INT_A_ASSERT_ENABLE;
+
+ bridge->has_pcie = true;
+ bridge->data = pcie;
+ bridge->ops = &advk_pci_bridge_emul_ops;
+
+ pci_bridge_emul_init(bridge);
+
+}
+
static bool advk_pcie_valid_device(struct advk_pcie *pcie, struct pci_bus *bus,
int devfn)
{
@@ -411,6 +524,10 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn,
return PCIBIOS_DEVICE_NOT_FOUND;
}
+ if (bus->number == pcie->root_bus_nr)
+ return pci_bridge_emul_conf_read(&pcie->bridge, where,
+ size, val);
+
/* Start PIO */
advk_writel(pcie, 0, PIO_START);
advk_writel(pcie, 1, PIO_ISR);
@@ -418,7 +535,7 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn,
/* Program the control register */
reg = advk_readl(pcie, PIO_CTRL);
reg &= ~PIO_CTRL_TYPE_MASK;
- if (bus->number == pcie->root_bus_nr)
+ if (bus->primary == pcie->root_bus_nr)
reg |= PCIE_CONFIG_RD_TYPE0;
else
reg |= PCIE_CONFIG_RD_TYPE1;
@@ -463,6 +580,10 @@ static int advk_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
if (!advk_pcie_valid_device(pcie, bus, devfn))
return PCIBIOS_DEVICE_NOT_FOUND;
+ if (bus->number == pcie->root_bus_nr)
+ return pci_bridge_emul_conf_write(&pcie->bridge, where,
+ size, val);
+
if (where % size)
return PCIBIOS_SET_FAILED;
@@ -473,7 +594,7 @@ static int advk_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
/* Program the control register */
reg = advk_readl(pcie, PIO_CTRL);
reg &= ~PIO_CTRL_TYPE_MASK;
- if (bus->number == pcie->root_bus_nr)
+ if (bus->primary == pcie->root_bus_nr)
reg |= PCIE_CONFIG_WR_TYPE0;
else
reg |= PCIE_CONFIG_WR_TYPE1;
@@ -875,6 +996,8 @@ static int advk_pcie_probe(struct platform_device *pdev)
advk_pcie_setup_hw(pcie);
+ advk_sw_pci_bridge_init(pcie);
+
ret = advk_pcie_init_irq_domain(pcie);
if (ret) {
dev_err(dev, "Failed to initialize irq\n");
diff --git a/drivers/pci/controller/pci-host-common.c b/drivers/pci/controller/pci-host-common.c
index d8f10451f273..c742881b5061 100644
--- a/drivers/pci/controller/pci-host-common.c
+++ b/drivers/pci/controller/pci-host-common.c
@@ -58,9 +58,7 @@ err_out:
int pci_host_common_probe(struct platform_device *pdev,
struct pci_ecam_ops *ops)
{
- const char *type;
struct device *dev = &pdev->dev;
- struct device_node *np = dev->of_node;
struct pci_host_bridge *bridge;
struct pci_config_window *cfg;
struct list_head resources;
@@ -70,12 +68,6 @@ int pci_host_common_probe(struct platform_device *pdev,
if (!bridge)
return -ENOMEM;
- type = of_get_property(np, "device_type", NULL);
- if (!type || strcmp(type, "pci")) {
- dev_err(dev, "invalid \"device_type\" %s\n", type);
- return -EINVAL;
- }
-
of_pci_check_probe_only();
/* Parse and map our Configuration Space windows */
diff --git a/drivers/pci/controller/pci-mvebu.c b/drivers/pci/controller/pci-mvebu.c
index 50eb0729385b..fa0fc46edb0c 100644
--- a/drivers/pci/controller/pci-mvebu.c
+++ b/drivers/pci/controller/pci-mvebu.c
@@ -22,6 +22,7 @@
#include <linux/of_platform.h>
#include "../pci.h"
+#include "../pci-bridge-emul.h"
/*
* PCIe unit register offsets.
@@ -63,61 +64,6 @@
#define PCIE_DEBUG_CTRL 0x1a60
#define PCIE_DEBUG_SOFT_RESET BIT(20)
-enum {
- PCISWCAP = PCI_BRIDGE_CONTROL + 2,
- PCISWCAP_EXP_LIST_ID = PCISWCAP + PCI_CAP_LIST_ID,
- PCISWCAP_EXP_DEVCAP = PCISWCAP + PCI_EXP_DEVCAP,
- PCISWCAP_EXP_DEVCTL = PCISWCAP + PCI_EXP_DEVCTL,
- PCISWCAP_EXP_LNKCAP = PCISWCAP + PCI_EXP_LNKCAP,
- PCISWCAP_EXP_LNKCTL = PCISWCAP + PCI_EXP_LNKCTL,
- PCISWCAP_EXP_SLTCAP = PCISWCAP + PCI_EXP_SLTCAP,
- PCISWCAP_EXP_SLTCTL = PCISWCAP + PCI_EXP_SLTCTL,
- PCISWCAP_EXP_RTCTL = PCISWCAP + PCI_EXP_RTCTL,
- PCISWCAP_EXP_RTSTA = PCISWCAP + PCI_EXP_RTSTA,
- PCISWCAP_EXP_DEVCAP2 = PCISWCAP + PCI_EXP_DEVCAP2,
- PCISWCAP_EXP_DEVCTL2 = PCISWCAP + PCI_EXP_DEVCTL2,
- PCISWCAP_EXP_LNKCAP2 = PCISWCAP + PCI_EXP_LNKCAP2,
- PCISWCAP_EXP_LNKCTL2 = PCISWCAP + PCI_EXP_LNKCTL2,
- PCISWCAP_EXP_SLTCAP2 = PCISWCAP + PCI_EXP_SLTCAP2,
- PCISWCAP_EXP_SLTCTL2 = PCISWCAP + PCI_EXP_SLTCTL2,
-};
-
-/* PCI configuration space of a PCI-to-PCI bridge */
-struct mvebu_sw_pci_bridge {
- u16 vendor;
- u16 device;
- u16 command;
- u16 status;
- u16 class;
- u8 interface;
- u8 revision;
- u8 bist;
- u8 header_type;
- u8 latency_timer;
- u8 cache_line_size;
- u32 bar[2];
- u8 primary_bus;
- u8 secondary_bus;
- u8 subordinate_bus;
- u8 secondary_latency_timer;
- u8 iobase;
- u8 iolimit;
- u16 secondary_status;
- u16 membase;
- u16 memlimit;
- u16 iobaseupper;
- u16 iolimitupper;
- u32 romaddr;
- u8 intline;
- u8 intpin;
- u16 bridgectrl;
-
- /* PCI express capability */
- u32 pcie_sltcap;
- u16 pcie_devctl;
- u16 pcie_rtctl;
-};
-
struct mvebu_pcie_port;
/* Structure representing all PCIe interfaces */
@@ -153,7 +99,7 @@ struct mvebu_pcie_port {
struct clk *clk;
struct gpio_desc *reset_gpio;
char *reset_name;
- struct mvebu_sw_pci_bridge bridge;
+ struct pci_bridge_emul bridge;
struct device_node *dn;
struct mvebu_pcie *pcie;
struct mvebu_pcie_window memwin;
@@ -415,11 +361,12 @@ static void mvebu_pcie_set_window(struct mvebu_pcie_port *port,
static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port)
{
struct mvebu_pcie_window desired = {};
+ struct pci_bridge_emul_conf *conf = &port->bridge.conf;
/* Are the new iobase/iolimit values invalid? */
- if (port->bridge.iolimit < port->bridge.iobase ||
- port->bridge.iolimitupper < port->bridge.iobaseupper ||
- !(port->bridge.command & PCI_COMMAND_IO)) {
+ if (conf->iolimit < conf->iobase ||
+ conf->iolimitupper < conf->iobaseupper ||
+ !(conf->command & PCI_COMMAND_IO)) {
mvebu_pcie_set_window(port, port->io_target, port->io_attr,
&desired, &port->iowin);
return;
@@ -438,11 +385,11 @@ static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port)
* specifications. iobase is the bus address, port->iowin_base
* is the CPU address.
*/
- desired.remap = ((port->bridge.iobase & 0xF0) << 8) |
- (port->bridge.iobaseupper << 16);
+ desired.remap = ((conf->iobase & 0xF0) << 8) |
+ (conf->iobaseupper << 16);
desired.base = port->pcie->io.start + desired.remap;
- desired.size = ((0xFFF | ((port->bridge.iolimit & 0xF0) << 8) |
- (port->bridge.iolimitupper << 16)) -
+ desired.size = ((0xFFF | ((conf->iolimit & 0xF0) << 8) |
+ (conf->iolimitupper << 16)) -
desired.remap) +
1;
@@ -453,10 +400,11 @@ static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port)
static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port)
{
struct mvebu_pcie_window desired = {.remap = MVEBU_MBUS_NO_REMAP};
+ struct pci_bridge_emul_conf *conf = &port->bridge.conf;
/* Are the new membase/memlimit values invalid? */
- if (port->bridge.memlimit < port->bridge.membase ||
- !(port->bridge.command & PCI_COMMAND_MEMORY)) {
+ if (conf->memlimit < conf->membase ||
+ !(conf->command & PCI_COMMAND_MEMORY)) {
mvebu_pcie_set_window(port, port->mem_target, port->mem_attr,
&desired, &port->memwin);
return;
@@ -468,130 +416,32 @@ static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port)
* window to setup, according to the PCI-to-PCI bridge
* specifications.
*/
- desired.base = ((port->bridge.membase & 0xFFF0) << 16);
- desired.size = (((port->bridge.memlimit & 0xFFF0) << 16) | 0xFFFFF) -
+ desired.base = ((conf->membase & 0xFFF0) << 16);
+ desired.size = (((conf->memlimit & 0xFFF0) << 16) | 0xFFFFF) -
desired.base + 1;
mvebu_pcie_set_window(port, port->mem_target, port->mem_attr, &desired,
&port->memwin);
}
-/*
- * Initialize the configuration space of the PCI-to-PCI bridge
- * associated with the given PCIe interface.
- */
-static void mvebu_sw_pci_bridge_init(struct mvebu_pcie_port *port)
-{
- struct mvebu_sw_pci_bridge *bridge = &port->bridge;
-
- memset(bridge, 0, sizeof(struct mvebu_sw_pci_bridge));
-
- bridge->class = PCI_CLASS_BRIDGE_PCI;
- bridge->vendor = PCI_VENDOR_ID_MARVELL;
- bridge->device = mvebu_readl(port, PCIE_DEV_ID_OFF) >> 16;
- bridge->revision = mvebu_readl(port, PCIE_DEV_REV_OFF) & 0xff;
- bridge->header_type = PCI_HEADER_TYPE_BRIDGE;
- bridge->cache_line_size = 0x10;
-
- /* We support 32 bits I/O addressing */
- bridge->iobase = PCI_IO_RANGE_TYPE_32;
- bridge->iolimit = PCI_IO_RANGE_TYPE_32;
-
- /* Add capabilities */
- bridge->status = PCI_STATUS_CAP_LIST;
-}
-
-/*
- * Read the configuration space of the PCI-to-PCI bridge associated to
- * the given PCIe interface.
- */
-static int mvebu_sw_pci_bridge_read(struct mvebu_pcie_port *port,
- unsigned int where, int size, u32 *value)
+static pci_bridge_emul_read_status_t
+mvebu_pci_bridge_emul_pcie_conf_read(struct pci_bridge_emul *bridge,
+ int reg, u32 *value)
{
- struct mvebu_sw_pci_bridge *bridge = &port->bridge;
-
- switch (where & ~3) {
- case PCI_VENDOR_ID:
- *value = bridge->device << 16 | bridge->vendor;
- break;
-
- case PCI_COMMAND:
- *value = bridge->command | bridge->status << 16;
- break;
-
- case PCI_CLASS_REVISION:
- *value = bridge->class << 16 | bridge->interface << 8 |
- bridge->revision;
- break;
+ struct mvebu_pcie_port *port = bridge->data;
- case PCI_CACHE_LINE_SIZE:
- *value = bridge->bist << 24 | bridge->header_type << 16 |
- bridge->latency_timer << 8 | bridge->cache_line_size;
- break;
-
- case PCI_BASE_ADDRESS_0 ... PCI_BASE_ADDRESS_1:
- *value = bridge->bar[((where & ~3) - PCI_BASE_ADDRESS_0) / 4];
- break;
-
- case PCI_PRIMARY_BUS:
- *value = (bridge->secondary_latency_timer << 24 |
- bridge->subordinate_bus << 16 |
- bridge->secondary_bus << 8 |
- bridge->primary_bus);
- break;
-
- case PCI_IO_BASE:
- if (!mvebu_has_ioport(port))
- *value = bridge->secondary_status << 16;
- else
- *value = (bridge->secondary_status << 16 |
- bridge->iolimit << 8 |
- bridge->iobase);
- break;
-
- case PCI_MEMORY_BASE:
- *value = (bridge->memlimit << 16 | bridge->membase);
- break;
-
- case PCI_PREF_MEMORY_BASE:
- *value = 0;
- break;
-
- case PCI_IO_BASE_UPPER16:
- *value = (bridge->iolimitupper << 16 | bridge->iobaseupper);
- break;
-
- case PCI_CAPABILITY_LIST:
- *value = PCISWCAP;
- break;
-
- case PCI_ROM_ADDRESS1:
- *value = 0;
- break;
-
- case PCI_INTERRUPT_LINE:
- /* LINE PIN MIN_GNT MAX_LAT */
- *value = 0;
- break;
-
- case PCISWCAP_EXP_LIST_ID:
- /* Set PCIe v2, root port, slot support */
- *value = (PCI_EXP_TYPE_ROOT_PORT << 4 | 2 |
- PCI_EXP_FLAGS_SLOT) << 16 | PCI_CAP_ID_EXP;
- break;
-
- case PCISWCAP_EXP_DEVCAP:
+ switch (reg) {
+ case PCI_EXP_DEVCAP:
*value = mvebu_readl(port, PCIE_CAP_PCIEXP + PCI_EXP_DEVCAP);
break;
- case PCISWCAP_EXP_DEVCTL:
+ case PCI_EXP_DEVCTL:
*value = mvebu_readl(port, PCIE_CAP_PCIEXP + PCI_EXP_DEVCTL) &
~(PCI_EXP_DEVCTL_URRE | PCI_EXP_DEVCTL_FERE |
PCI_EXP_DEVCTL_NFERE | PCI_EXP_DEVCTL_CERE);
- *value |= bridge->pcie_devctl;
break;
- case PCISWCAP_EXP_LNKCAP:
+ case PCI_EXP_LNKCAP:
/*
* PCIe requires the clock power management capability to be
* hard-wired to zero for downstream ports
@@ -600,176 +450,140 @@ static int mvebu_sw_pci_bridge_read(struct mvebu_pcie_port *port,
~PCI_EXP_LNKCAP_CLKPM;
break;
- case PCISWCAP_EXP_LNKCTL:
+ case PCI_EXP_LNKCTL:
*value = mvebu_readl(port, PCIE_CAP_PCIEXP + PCI_EXP_LNKCTL);
break;
- case PCISWCAP_EXP_SLTCAP:
- *value = bridge->pcie_sltcap;
- break;
-
- case PCISWCAP_EXP_SLTCTL:
+ case PCI_EXP_SLTCTL:
*value = PCI_EXP_SLTSTA_PDS << 16;
break;
- case PCISWCAP_EXP_RTCTL:
- *value = bridge->pcie_rtctl;
- break;
-
- case PCISWCAP_EXP_RTSTA:
+ case PCI_EXP_RTSTA:
*value = mvebu_readl(port, PCIE_RC_RTSTA);
break;
- /* PCIe requires the v2 fields to be hard-wired to zero */
- case PCISWCAP_EXP_DEVCAP2:
- case PCISWCAP_EXP_DEVCTL2:
- case PCISWCAP_EXP_LNKCAP2:
- case PCISWCAP_EXP_LNKCTL2:
- case PCISWCAP_EXP_SLTCAP2:
- case PCISWCAP_EXP_SLTCTL2:
default:
- /*
- * PCI defines configuration read accesses to reserved or
- * unimplemented registers to read as zero and complete
- * normally.
- */
- *value = 0;
- return PCIBIOS_SUCCESSFUL;
+ return PCI_BRIDGE_EMUL_NOT_HANDLED;
}
- if (size == 2)
- *value = (*value >> (8 * (where & 3))) & 0xffff;
- else if (size == 1)
- *value = (*value >> (8 * (where & 3))) & 0xff;
-
- return PCIBIOS_SUCCESSFUL;
+ return PCI_BRIDGE_EMUL_HANDLED;
}
-/* Write to the PCI-to-PCI bridge configuration space */
-static int mvebu_sw_pci_bridge_write(struct mvebu_pcie_port *port,
- unsigned int where, int size, u32 value)
+static void
+mvebu_pci_bridge_emul_base_conf_write(struct pci_bridge_emul *bridge,
+ int reg, u32 old, u32 new, u32 mask)
{
- struct mvebu_sw_pci_bridge *bridge = &port->bridge;
- u32 mask, reg;
- int err;
-
- if (size == 4)
- mask = 0x0;
- else if (size == 2)
- mask = ~(0xffff << ((where & 3) * 8));
- else if (size == 1)
- mask = ~(0xff << ((where & 3) * 8));
- else
- return PCIBIOS_BAD_REGISTER_NUMBER;
-
- err = mvebu_sw_pci_bridge_read(port, where & ~3, 4, &reg);
- if (err)
- return err;
+ struct mvebu_pcie_port *port = bridge->data;
+ struct pci_bridge_emul_conf *conf = &bridge->conf;
- value = (reg & mask) | value << ((where & 3) * 8);
-
- switch (where & ~3) {
+ switch (reg) {
case PCI_COMMAND:
{
- u32 old = bridge->command;
-
if (!mvebu_has_ioport(port))
- value &= ~PCI_COMMAND_IO;
+ conf->command &= ~PCI_COMMAND_IO;
- bridge->command = value & 0xffff;
- if ((old ^ bridge->command) & PCI_COMMAND_IO)
+ if ((old ^ new) & PCI_COMMAND_IO)
mvebu_pcie_handle_iobase_change(port);
- if ((old ^ bridge->command) & PCI_COMMAND_MEMORY)
+ if ((old ^ new) & PCI_COMMAND_MEMORY)
mvebu_pcie_handle_membase_change(port);
- break;
- }
- case PCI_BASE_ADDRESS_0 ... PCI_BASE_ADDRESS_1:
- bridge->bar[((where & ~3) - PCI_BASE_ADDRESS_0) / 4] = value;
break;
+ }
case PCI_IO_BASE:
/*
- * We also keep bit 1 set, it is a read-only bit that
+ * We keep bit 1 set, it is a read-only bit that
* indicates we support 32 bits addressing for the
* I/O
*/
- bridge->iobase = (value & 0xff) | PCI_IO_RANGE_TYPE_32;
- bridge->iolimit = ((value >> 8) & 0xff) | PCI_IO_RANGE_TYPE_32;
+ conf->iobase |= PCI_IO_RANGE_TYPE_32;
+ conf->iolimit |= PCI_IO_RANGE_TYPE_32;
mvebu_pcie_handle_iobase_change(port);
break;
case PCI_MEMORY_BASE:
- bridge->membase = value & 0xffff;
- bridge->memlimit = value >> 16;
mvebu_pcie_handle_membase_change(port);
break;
case PCI_IO_BASE_UPPER16:
- bridge->iobaseupper = value & 0xffff;
- bridge->iolimitupper = value >> 16;
mvebu_pcie_handle_iobase_change(port);
break;
case PCI_PRIMARY_BUS:
- bridge->primary_bus = value & 0xff;
- bridge->secondary_bus = (value >> 8) & 0xff;
- bridge->subordinate_bus = (value >> 16) & 0xff;
- bridge->secondary_latency_timer = (value >> 24) & 0xff;
- mvebu_pcie_set_local_bus_nr(port, bridge->secondary_bus);
+ mvebu_pcie_set_local_bus_nr(port, conf->secondary_bus);
+ break;
+
+ default:
break;
+ }
+}
+
+static void
+mvebu_pci_bridge_emul_pcie_conf_write(struct pci_bridge_emul *bridge,
+ int reg, u32 old, u32 new, u32 mask)
+{
+ struct mvebu_pcie_port *port = bridge->data;
- case PCISWCAP_EXP_DEVCTL:
+ switch (reg) {
+ case PCI_EXP_DEVCTL:
/*
* Armada370 data says these bits must always
* be zero when in root complex mode.
*/
- value &= ~(PCI_EXP_DEVCTL_URRE | PCI_EXP_DEVCTL_FERE |
- PCI_EXP_DEVCTL_NFERE | PCI_EXP_DEVCTL_CERE);
+ new &= ~(PCI_EXP_DEVCTL_URRE | PCI_EXP_DEVCTL_FERE |
+ PCI_EXP_DEVCTL_NFERE | PCI_EXP_DEVCTL_CERE);
- /*
- * If the mask is 0xffff0000, then we only want to write
- * the device control register, rather than clearing the
- * RW1C bits in the device status register. Mask out the
- * status register bits.
- */
- if (mask == 0xffff0000)
- value &= 0xffff;
-
- mvebu_writel(port, value, PCIE_CAP_PCIEXP + PCI_EXP_DEVCTL);
+ mvebu_writel(port, new, PCIE_CAP_PCIEXP + PCI_EXP_DEVCTL);
break;
- case PCISWCAP_EXP_LNKCTL:
+ case PCI_EXP_LNKCTL:
/*
* If we don't support CLKREQ, we must ensure that the
* CLKREQ enable bit always reads zero. Since we haven't
* had this capability, and it's dependent on board wiring,
* disable it for the time being.
*/
- value &= ~PCI_EXP_LNKCTL_CLKREQ_EN;
+ new &= ~PCI_EXP_LNKCTL_CLKREQ_EN;
- /*
- * If the mask is 0xffff0000, then we only want to write
- * the link control register, rather than clearing the
- * RW1C bits in the link status register. Mask out the
- * RW1C status register bits.
- */
- if (mask == 0xffff0000)
- value &= ~((PCI_EXP_LNKSTA_LABS |
- PCI_EXP_LNKSTA_LBMS) << 16);
-
- mvebu_writel(port, value, PCIE_CAP_PCIEXP + PCI_EXP_LNKCTL);
+ mvebu_writel(port, new, PCIE_CAP_PCIEXP + PCI_EXP_LNKCTL);
break;
- case PCISWCAP_EXP_RTSTA:
- mvebu_writel(port, value, PCIE_RC_RTSTA);
+ case PCI_EXP_RTSTA:
+ mvebu_writel(port, new, PCIE_RC_RTSTA);
break;
+ }
+}
- default:
- break;
+struct pci_bridge_emul_ops mvebu_pci_bridge_emul_ops = {
+ .write_base = mvebu_pci_bridge_emul_base_conf_write,
+ .read_pcie = mvebu_pci_bridge_emul_pcie_conf_read,
+ .write_pcie = mvebu_pci_bridge_emul_pcie_conf_write,
+};
+
+/*
+ * Initialize the configuration space of the PCI-to-PCI bridge
+ * associated with the given PCIe interface.
+ */
+static void mvebu_pci_bridge_emul_init(struct mvebu_pcie_port *port)
+{
+ struct pci_bridge_emul *bridge = &port->bridge;
+
+ bridge->conf.vendor = PCI_VENDOR_ID_MARVELL;
+ bridge->conf.device = mvebu_readl(port, PCIE_DEV_ID_OFF) >> 16;
+ bridge->conf.class_revision =
+ mvebu_readl(port, PCIE_DEV_REV_OFF) & 0xff;
+
+ if (mvebu_has_ioport(port)) {
+ /* We support 32 bits I/O addressing */
+ bridge->conf.iobase = PCI_IO_RANGE_TYPE_32;
+ bridge->conf.iolimit = PCI_IO_RANGE_TYPE_32;
}
- return PCIBIOS_SUCCESSFUL;
+ bridge->has_pcie = true;
+ bridge->data = port;
+ bridge->ops = &mvebu_pci_bridge_emul_ops;
+
+ pci_bridge_emul_init(bridge);
}
static inline struct mvebu_pcie *sys_to_pcie(struct pci_sys_data *sys)
@@ -789,8 +603,8 @@ static struct mvebu_pcie_port *mvebu_pcie_find_port(struct mvebu_pcie *pcie,
if (bus->number == 0 && port->devfn == devfn)
return port;
if (bus->number != 0 &&
- bus->number >= port->bridge.secondary_bus &&
- bus->number <= port->bridge.subordinate_bus)
+ bus->number >= port->bridge.conf.secondary_bus &&
+ bus->number <= port->bridge.conf.subordinate_bus)
return port;
}
@@ -811,7 +625,8 @@ static int mvebu_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
/* Access the emulated PCI-to-PCI bridge */
if (bus->number == 0)
- return mvebu_sw_pci_bridge_write(port, where, size, val);
+ return pci_bridge_emul_conf_write(&port->bridge, where,
+ size, val);
if (!mvebu_pcie_link_up(port))
return PCIBIOS_DEVICE_NOT_FOUND;
@@ -839,7 +654,8 @@ static int mvebu_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
/* Access the emulated PCI-to-PCI bridge */
if (bus->number == 0)
- return mvebu_sw_pci_bridge_read(port, where, size, val);
+ return pci_bridge_emul_conf_read(&port->bridge, where,
+ size, val);
if (!mvebu_pcie_link_up(port)) {
*val = 0xffffffff;
@@ -1145,7 +961,6 @@ static int mvebu_pcie_parse_request_resources(struct mvebu_pcie *pcie)
{
struct device *dev = &pcie->pdev->dev;
struct device_node *np = dev->of_node;
- unsigned int i;
int ret;
INIT_LIST_HEAD(&pcie->resources);
@@ -1179,13 +994,58 @@ static int mvebu_pcie_parse_request_resources(struct mvebu_pcie *pcie)
resource_size(&pcie->io) - 1);
pcie->realio.name = "PCI I/O";
+ pci_add_resource(&pcie->resources, &pcie->realio);
+ }
+
+ return devm_request_pci_bus_resources(dev, &pcie->resources);
+}
+
+/*
+ * This is a copy of pci_host_probe(), except that it does the I/O
+ * remap as the last step, once we are sure we won't fail.
+ *
+ * It should be removed once the I/O remap error handling issue has
+ * been sorted out.
+ */
+static int mvebu_pci_host_probe(struct pci_host_bridge *bridge)
+{
+ struct mvebu_pcie *pcie;
+ struct pci_bus *bus, *child;
+ int ret;
+
+ ret = pci_scan_root_bus_bridge(bridge);
+ if (ret < 0) {
+ dev_err(bridge->dev.parent, "Scanning root bridge failed");
+ return ret;
+ }
+
+ pcie = pci_host_bridge_priv(bridge);
+ if (resource_size(&pcie->io) != 0) {
+ unsigned int i;
+
for (i = 0; i < resource_size(&pcie->realio); i += SZ_64K)
pci_ioremap_io(i, pcie->io.start + i);
+ }
- pci_add_resource(&pcie->resources, &pcie->realio);
+ bus = bridge->bus;
+
+ /*
+ * We insert PCI resources into the iomem_resource and
+ * ioport_resource trees in either pci_bus_claim_resources()
+ * or pci_bus_assign_resources().
+ */
+ if (pci_has_flag(PCI_PROBE_ONLY)) {
+ pci_bus_claim_resources(bus);
+ } else {
+ pci_bus_size_bridges(bus);
+ pci_bus_assign_resources(bus);
+
+ list_for_each_entry(child, &bus->children, node)
+ pcie_bus_configure_settings(child);
}
- return devm_request_pci_bus_resources(dev, &pcie->resources);
+ pci_bus_add_devices(bus);
+ return 0;
}
static int mvebu_pcie_probe(struct platform_device *pdev)
@@ -1253,7 +1113,7 @@ static int mvebu_pcie_probe(struct platform_device *pdev)
mvebu_pcie_setup_hw(port);
mvebu_pcie_set_local_dev_nr(port, 1);
- mvebu_sw_pci_bridge_init(port);
+ mvebu_pci_bridge_emul_init(port);
}
pcie->nports = i;
@@ -1268,7 +1128,7 @@ static int mvebu_pcie_probe(struct platform_device *pdev)
bridge->align_resource = mvebu_pcie_align_resource;
bridge->msi = pcie->msi;
- return pci_host_probe(bridge);
+ return mvebu_pci_host_probe(bridge);
}
static const struct of_device_id mvebu_pcie_of_match_table[] = {
diff --git a/drivers/pci/controller/pcie-cadence-ep.c b/drivers/pci/controller/pcie-cadence-ep.c
index 9e87dd7f9ac3..c3a088910f48 100644
--- a/drivers/pci/controller/pcie-cadence-ep.c
+++ b/drivers/pci/controller/pcie-cadence-ep.c
@@ -258,7 +258,6 @@ static void cdns_pcie_ep_assert_intx(struct cdns_pcie_ep *ep, u8 fn,
u8 intx, bool is_asserted)
{
struct cdns_pcie *pcie = &ep->pcie;
- u32 r = ep->max_regions - 1;
u32 offset;
u16 status;
u8 msg_code;
@@ -268,8 +267,8 @@ static void cdns_pcie_ep_assert_intx(struct cdns_pcie_ep *ep, u8 fn,
/* Set the outbound region if needed. */
if (unlikely(ep->irq_pci_addr != CDNS_PCIE_EP_IRQ_PCI_ADDR_LEGACY ||
ep->irq_pci_fn != fn)) {
- /* Last region was reserved for IRQ writes. */
- cdns_pcie_set_outbound_region_for_normal_msg(pcie, fn, r,
+ /* First region was reserved for IRQ writes. */
+ cdns_pcie_set_outbound_region_for_normal_msg(pcie, fn, 0,
ep->irq_phys_addr);
ep->irq_pci_addr = CDNS_PCIE_EP_IRQ_PCI_ADDR_LEGACY;
ep->irq_pci_fn = fn;
@@ -347,8 +346,8 @@ static int cdns_pcie_ep_send_msi_irq(struct cdns_pcie_ep *ep, u8 fn,
/* Set the outbound region if needed. */
if (unlikely(ep->irq_pci_addr != (pci_addr & ~pci_addr_mask) ||
ep->irq_pci_fn != fn)) {
- /* Last region was reserved for IRQ writes. */
- cdns_pcie_set_outbound_region(pcie, fn, ep->max_regions - 1,
+ /* First region was reserved for IRQ writes. */
+ cdns_pcie_set_outbound_region(pcie, fn, 0,
false,
ep->irq_phys_addr,
pci_addr & ~pci_addr_mask,
@@ -356,7 +355,7 @@ static int cdns_pcie_ep_send_msi_irq(struct cdns_pcie_ep *ep, u8 fn,
ep->irq_pci_addr = (pci_addr & ~pci_addr_mask);
ep->irq_pci_fn = fn;
}
- writew(data, ep->irq_cpu_addr + (pci_addr & pci_addr_mask));
+ writel(data, ep->irq_cpu_addr + (pci_addr & pci_addr_mask));
return 0;
}
@@ -517,6 +516,8 @@ static int cdns_pcie_ep_probe(struct platform_device *pdev)
goto free_epc_mem;
}
ep->irq_pci_addr = CDNS_PCIE_EP_IRQ_PCI_ADDR_NONE;
+ /* Reserve region 0 for IRQs */
+ set_bit(0, &ep->ob_region_map);
return 0;
diff --git a/drivers/pci/controller/pcie-cadence-host.c b/drivers/pci/controller/pcie-cadence-host.c
index ec394f6a19c8..97e251090b4f 100644
--- a/drivers/pci/controller/pcie-cadence-host.c
+++ b/drivers/pci/controller/pcie-cadence-host.c
@@ -235,7 +235,6 @@ static int cdns_pcie_host_init(struct device *dev,
static int cdns_pcie_host_probe(struct platform_device *pdev)
{
- const char *type;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct pci_host_bridge *bridge;
@@ -268,12 +267,6 @@ static int cdns_pcie_host_probe(struct platform_device *pdev)
rc->device_id = 0xffff;
of_property_read_u16(np, "device-id", &rc->device_id);
- type = of_get_property(np, "device_type", NULL);
- if (!type || strcmp(type, "pci")) {
- dev_err(dev, "invalid \"device_type\" %s\n", type);
- return -EINVAL;
- }
-
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg");
pcie->reg_base = devm_ioremap_resource(dev, res);
if (IS_ERR(pcie->reg_base)) {
diff --git a/drivers/pci/controller/pcie-cadence.c b/drivers/pci/controller/pcie-cadence.c
index 86f1b002c846..cd795f6fc1e2 100644
--- a/drivers/pci/controller/pcie-cadence.c
+++ b/drivers/pci/controller/pcie-cadence.c
@@ -180,24 +180,26 @@ int cdns_pcie_init_phy(struct device *dev, struct cdns_pcie *pcie)
return 0;
}
- phy = devm_kzalloc(dev, sizeof(*phy) * phy_count, GFP_KERNEL);
+ phy = devm_kcalloc(dev, phy_count, sizeof(*phy), GFP_KERNEL);
if (!phy)
return -ENOMEM;
- link = devm_kzalloc(dev, sizeof(*link) * phy_count, GFP_KERNEL);
+ link = devm_kcalloc(dev, phy_count, sizeof(*link), GFP_KERNEL);
if (!link)
return -ENOMEM;
for (i = 0; i < phy_count; i++) {
of_property_read_string_index(np, "phy-names", i, &name);
- phy[i] = devm_phy_optional_get(dev, name);
- if (IS_ERR(phy))
- return PTR_ERR(phy);
-
+ phy[i] = devm_phy_get(dev, name);
+ if (IS_ERR(phy[i])) {
+ ret = PTR_ERR(phy[i]);
+ goto err_phy;
+ }
link[i] = device_link_add(dev, &phy[i]->dev, DL_FLAG_STATELESS);
if (!link[i]) {
+ devm_phy_put(dev, phy[i]);
ret = -EINVAL;
- goto err_link;
+ goto err_phy;
}
}
@@ -207,13 +209,15 @@ int cdns_pcie_init_phy(struct device *dev, struct cdns_pcie *pcie)
ret = cdns_pcie_enable_phy(pcie);
if (ret)
- goto err_link;
+ goto err_phy;
return 0;
-err_link:
- while (--i >= 0)
+err_phy:
+ while (--i >= 0) {
device_link_del(link[i]);
+ devm_phy_put(dev, phy[i]);
+ }
return ret;
}
diff --git a/drivers/pci/controller/pcie-iproc.c b/drivers/pci/controller/pcie-iproc.c
index 3160e9342a2f..c20fd6bd68fd 100644
--- a/drivers/pci/controller/pcie-iproc.c
+++ b/drivers/pci/controller/pcie-iproc.c
@@ -630,14 +630,6 @@ static void __iomem *iproc_pcie_map_cfg_bus(struct iproc_pcie *pcie,
return (pcie->base + offset);
}
- /*
- * PAXC is connected to an internally emulated EP within the SoC. It
- * allows only one device.
- */
- if (pcie->ep_is_internal)
- if (slot > 0)
- return NULL;
-
return iproc_pcie_map_ep_cfg_reg(pcie, busno, slot, fn, where);
}
diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c
index 861dda69f366..d069a76cbb95 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -15,6 +15,7 @@
#include <linux/irqdomain.h>
#include <linux/kernel.h>
#include <linux/msi.h>
+#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_pci.h>
#include <linux/of_platform.h>
@@ -162,6 +163,7 @@ struct mtk_pcie_soc {
* @phy: pointer to PHY control block
* @lane: lane count
* @slot: port slot
+ * @irq: GIC irq
* @irq_domain: legacy INTx IRQ domain
* @inner_domain: inner IRQ domain
* @msi_domain: MSI IRQ domain
@@ -182,6 +184,7 @@ struct mtk_pcie_port {
struct phy *phy;
u32 lane;
u32 slot;
+ int irq;
struct irq_domain *irq_domain;
struct irq_domain *inner_domain;
struct irq_domain *msi_domain;
@@ -225,10 +228,8 @@ static void mtk_pcie_subsys_powerdown(struct mtk_pcie *pcie)
clk_disable_unprepare(pcie->free_ck);
- if (dev->pm_domain) {
- pm_runtime_put_sync(dev);
- pm_runtime_disable(dev);
- }
+ pm_runtime_put_sync(dev);
+ pm_runtime_disable(dev);
}
static void mtk_pcie_port_free(struct mtk_pcie_port *port)
@@ -337,6 +338,17 @@ static struct mtk_pcie_port *mtk_pcie_find_port(struct pci_bus *bus,
{
struct mtk_pcie *pcie = bus->sysdata;
struct mtk_pcie_port *port;
+ struct pci_dev *dev = NULL;
+
+ /*
+ * Walk the bus hierarchy to get the devfn value
+ * of the port in the root bus.
+ */
+ while (bus && bus->number) {
+ dev = bus->self;
+ bus = dev->bus;
+ devfn = dev->devfn;
+ }
list_for_each_entry(port, &pcie->ports, list)
if (port->slot == PCI_SLOT(devfn))
@@ -383,75 +395,6 @@ static struct pci_ops mtk_pcie_ops_v2 = {
.write = mtk_pcie_config_write,
};
-static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port)
-{
- struct mtk_pcie *pcie = port->pcie;
- struct resource *mem = &pcie->mem;
- const struct mtk_pcie_soc *soc = port->pcie->soc;
- u32 val;
- size_t size;
- int err;
-
- /* MT7622 platforms need to enable LTSSM and ASPM from PCIe subsys */
- if (pcie->base) {
- val = readl(pcie->base + PCIE_SYS_CFG_V2);
- val |= PCIE_CSR_LTSSM_EN(port->slot) |
- PCIE_CSR_ASPM_L1_EN(port->slot);
- writel(val, pcie->base + PCIE_SYS_CFG_V2);
- }
-
- /* Assert all reset signals */
- writel(0, port->base + PCIE_RST_CTRL);
-
- /*
- * Enable PCIe link down reset, if link status changed from link up to
- * link down, this will reset MAC control registers and configuration
- * space.
- */
- writel(PCIE_LINKDOWN_RST_EN, port->base + PCIE_RST_CTRL);
-
- /* De-assert PHY, PE, PIPE, MAC and configuration reset */
- val = readl(port->base + PCIE_RST_CTRL);
- val |= PCIE_PHY_RSTB | PCIE_PERSTB | PCIE_PIPE_SRSTB |
- PCIE_MAC_SRSTB | PCIE_CRSTB;
- writel(val, port->base + PCIE_RST_CTRL);
-
- /* Set up vendor ID and class code */
- if (soc->need_fix_class_id) {
- val = PCI_VENDOR_ID_MEDIATEK;
- writew(val, port->base + PCIE_CONF_VEND_ID);
-
- val = PCI_CLASS_BRIDGE_HOST;
- writew(val, port->base + PCIE_CONF_CLASS_ID);
- }
-
- /* 100ms timeout value should be enough for Gen1/2 training */
- err = readl_poll_timeout(port->base + PCIE_LINK_STATUS_V2, val,
- !!(val & PCIE_PORT_LINKUP_V2), 20,
- 100 * USEC_PER_MSEC);
- if (err)
- return -ETIMEDOUT;
-
- /* Set INTx mask */
- val = readl(port->base + PCIE_INT_MASK);
- val &= ~INTX_MASK;
- writel(val, port->base + PCIE_INT_MASK);
-
- /* Set AHB to PCIe translation windows */
- size = mem->end - mem->start;
- val = lower_32_bits(mem->start) | AHB2PCIE_SIZE(fls(size));
- writel(val, port->base + PCIE_AHB_TRANS_BASE0_L);
-
- val = upper_32_bits(mem->start);
- writel(val, port->base + PCIE_AHB_TRANS_BASE0_H);
-
- /* Set PCIe to AXI translation memory space.*/
- val = fls(0xffffffff) | WIN_ENABLE;
- writel(val, port->base + PCIE_AXI_WINDOW0);
-
- return 0;
-}
-
static void mtk_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
{
struct mtk_pcie_port *port = irq_data_get_irq_chip_data(data);
@@ -590,6 +533,27 @@ static void mtk_pcie_enable_msi(struct mtk_pcie_port *port)
writel(val, port->base + PCIE_INT_MASK);
}
+static void mtk_pcie_irq_teardown(struct mtk_pcie *pcie)
+{
+ struct mtk_pcie_port *port, *tmp;
+
+ list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
+ irq_set_chained_handler_and_data(port->irq, NULL, NULL);
+
+ if (port->irq_domain)
+ irq_domain_remove(port->irq_domain);
+
+ if (IS_ENABLED(CONFIG_PCI_MSI)) {
+ if (port->msi_domain)
+ irq_domain_remove(port->msi_domain);
+ if (port->inner_domain)
+ irq_domain_remove(port->inner_domain);
+ }
+
+ irq_dispose_mapping(port->irq);
+ }
+}
+
static int mtk_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
irq_hw_number_t hwirq)
{
@@ -628,8 +592,6 @@ static int mtk_pcie_init_irq_domain(struct mtk_pcie_port *port,
ret = mtk_pcie_allocate_msi_domains(port);
if (ret)
return ret;
-
- mtk_pcie_enable_msi(port);
}
return 0;
@@ -682,7 +644,7 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port,
struct mtk_pcie *pcie = port->pcie;
struct device *dev = pcie->dev;
struct platform_device *pdev = to_platform_device(dev);
- int err, irq;
+ int err;
err = mtk_pcie_init_irq_domain(port, node);
if (err) {
@@ -690,8 +652,81 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port,
return err;
}
- irq = platform_get_irq(pdev, port->slot);
- irq_set_chained_handler_and_data(irq, mtk_pcie_intr_handler, port);
+ port->irq = platform_get_irq(pdev, port->slot);
+ irq_set_chained_handler_and_data(port->irq,
+ mtk_pcie_intr_handler, port);
+
+ return 0;
+}
+
+static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port)
+{
+ struct mtk_pcie *pcie = port->pcie;
+ struct resource *mem = &pcie->mem;
+ const struct mtk_pcie_soc *soc = port->pcie->soc;
+ u32 val;
+ size_t size;
+ int err;
+
+ /* MT7622 platforms need to enable LTSSM and ASPM from PCIe subsys */
+ if (pcie->base) {
+ val = readl(pcie->base + PCIE_SYS_CFG_V2);
+ val |= PCIE_CSR_LTSSM_EN(port->slot) |
+ PCIE_CSR_ASPM_L1_EN(port->slot);
+ writel(val, pcie->base + PCIE_SYS_CFG_V2);
+ }
+
+ /* Assert all reset signals */
+ writel(0, port->base + PCIE_RST_CTRL);
+
+ /*
+ * Enable PCIe link down reset, if link status changed from link up to
+ * link down, this will reset MAC control registers and configuration
+ * space.
+ */
+ writel(PCIE_LINKDOWN_RST_EN, port->base + PCIE_RST_CTRL);
+
+ /* De-assert PHY, PE, PIPE, MAC and configuration reset */
+ val = readl(port->base + PCIE_RST_CTRL);
+ val |= PCIE_PHY_RSTB | PCIE_PERSTB | PCIE_PIPE_SRSTB |
+ PCIE_MAC_SRSTB | PCIE_CRSTB;
+ writel(val, port->base + PCIE_RST_CTRL);
+
+ /* Set up vendor ID and class code */
+ if (soc->need_fix_class_id) {
+ val = PCI_VENDOR_ID_MEDIATEK;
+ writew(val, port->base + PCIE_CONF_VEND_ID);
+
+ val = PCI_CLASS_BRIDGE_PCI;
+ writew(val, port->base + PCIE_CONF_CLASS_ID);
+ }
+
+ /* 100ms timeout value should be enough for Gen1/2 training */
+ err = readl_poll_timeout(port->base + PCIE_LINK_STATUS_V2, val,
+ !!(val & PCIE_PORT_LINKUP_V2), 20,
+ 100 * USEC_PER_MSEC);
+ if (err)
+ return -ETIMEDOUT;
+
+ /* Set INTx mask */
+ val = readl(port->base + PCIE_INT_MASK);
+ val &= ~INTX_MASK;
+ writel(val, port->base + PCIE_INT_MASK);
+
+ if (IS_ENABLED(CONFIG_PCI_MSI))
+ mtk_pcie_enable_msi(port);
+
+ /* Set AHB to PCIe translation windows */
+ size = mem->end - mem->start;
+ val = lower_32_bits(mem->start) | AHB2PCIE_SIZE(fls(size));
+ writel(val, port->base + PCIE_AHB_TRANS_BASE0_L);
+
+ val = upper_32_bits(mem->start);
+ writel(val, port->base + PCIE_AHB_TRANS_BASE0_H);
+
+ /* Set PCIe to AXI translation memory space.*/
+ val = fls(0xffffffff) | WIN_ENABLE;
+ writel(val, port->base + PCIE_AXI_WINDOW0);
return 0;
}
@@ -987,10 +1022,8 @@ static int mtk_pcie_subsys_powerup(struct mtk_pcie *pcie)
pcie->free_ck = NULL;
}
- if (dev->pm_domain) {
- pm_runtime_enable(dev);
- pm_runtime_get_sync(dev);
- }
+ pm_runtime_enable(dev);
+ pm_runtime_get_sync(dev);
/* enable top level clock */
err = clk_prepare_enable(pcie->free_ck);
@@ -1002,10 +1035,8 @@ static int mtk_pcie_subsys_powerup(struct mtk_pcie *pcie)
return 0;
err_free_ck:
- if (dev->pm_domain) {
- pm_runtime_put_sync(dev);
- pm_runtime_disable(dev);
- }
+ pm_runtime_put_sync(dev);
+ pm_runtime_disable(dev);
return err;
}
@@ -1109,36 +1140,10 @@ static int mtk_pcie_request_resources(struct mtk_pcie *pcie)
if (err < 0)
return err;
- devm_pci_remap_iospace(dev, &pcie->pio, pcie->io.start);
-
- return 0;
-}
-
-static int mtk_pcie_register_host(struct pci_host_bridge *host)
-{
- struct mtk_pcie *pcie = pci_host_bridge_priv(host);
- struct pci_bus *child;
- int err;
-
- host->busnr = pcie->busn.start;
- host->dev.parent = pcie->dev;
- host->ops = pcie->soc->ops;
- host->map_irq = of_irq_parse_and_map_pci;
- host->swizzle_irq = pci_common_swizzle;
- host->sysdata = pcie;
-
- err = pci_scan_root_bus_bridge(host);
- if (err < 0)
+ err = devm_pci_remap_iospace(dev, &pcie->pio, pcie->io.start);
+ if (err)
return err;
- pci_bus_size_bridges(host->bus);
- pci_bus_assign_resources(host->bus);
-
- list_for_each_entry(child, &host->bus->children, node)
- pcie_bus_configure_settings(child);
-
- pci_bus_add_devices(host->bus);
-
return 0;
}
@@ -1168,7 +1173,14 @@ static int mtk_pcie_probe(struct platform_device *pdev)
if (err)
goto put_resources;
- err = mtk_pcie_register_host(host);
+ host->busnr = pcie->busn.start;
+ host->dev.parent = pcie->dev;
+ host->ops = pcie->soc->ops;
+ host->map_irq = of_irq_parse_and_map_pci;
+ host->swizzle_irq = pci_common_swizzle;
+ host->sysdata = pcie;
+
+ err = pci_host_probe(host);
if (err)
goto put_resources;
@@ -1181,6 +1193,80 @@ put_resources:
return err;
}
+
+static void mtk_pcie_free_resources(struct mtk_pcie *pcie)
+{
+ struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
+ struct list_head *windows = &host->windows;
+
+ pci_free_resource_list(windows);
+}
+
+static int mtk_pcie_remove(struct platform_device *pdev)
+{
+ struct mtk_pcie *pcie = platform_get_drvdata(pdev);
+ struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
+
+ pci_stop_root_bus(host->bus);
+ pci_remove_root_bus(host->bus);
+ mtk_pcie_free_resources(pcie);
+
+ mtk_pcie_irq_teardown(pcie);
+
+ mtk_pcie_put_resources(pcie);
+
+ return 0;
+}
+
+static int __maybe_unused mtk_pcie_suspend_noirq(struct device *dev)
+{
+ struct mtk_pcie *pcie = dev_get_drvdata(dev);
+ struct mtk_pcie_port *port;
+
+ if (list_empty(&pcie->ports))
+ return 0;
+
+ list_for_each_entry(port, &pcie->ports, list) {
+ clk_disable_unprepare(port->pipe_ck);
+ clk_disable_unprepare(port->obff_ck);
+ clk_disable_unprepare(port->axi_ck);
+ clk_disable_unprepare(port->aux_ck);
+ clk_disable_unprepare(port->ahb_ck);
+ clk_disable_unprepare(port->sys_ck);
+ phy_power_off(port->phy);
+ phy_exit(port->phy);
+ }
+
+ clk_disable_unprepare(pcie->free_ck);
+
+ return 0;
+}
+
+static int __maybe_unused mtk_pcie_resume_noirq(struct device *dev)
+{
+ struct mtk_pcie *pcie = dev_get_drvdata(dev);
+ struct mtk_pcie_port *port, *tmp;
+
+ if (list_empty(&pcie->ports))
+ return 0;
+
+ clk_prepare_enable(pcie->free_ck);
+
+ list_for_each_entry_safe(port, tmp, &pcie->ports, list)
+ mtk_pcie_enable_port(port);
+
+ /* In case of EP was removed while system suspend. */
+ if (list_empty(&pcie->ports))
+ clk_disable_unprepare(pcie->free_ck);
+
+ return 0;
+}
+
+static const struct dev_pm_ops mtk_pcie_pm_ops = {
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mtk_pcie_suspend_noirq,
+ mtk_pcie_resume_noirq)
+};
+
static const struct mtk_pcie_soc mtk_pcie_soc_v1 = {
.ops = &mtk_pcie_ops,
.startup = mtk_pcie_startup_port,
@@ -1209,10 +1295,13 @@ static const struct of_device_id mtk_pcie_ids[] = {
static struct platform_driver mtk_pcie_driver = {
.probe = mtk_pcie_probe,
+ .remove = mtk_pcie_remove,
.driver = {
.name = "mtk-pcie",
.of_match_table = mtk_pcie_ids,
.suppress_bind_attrs = true,
+ .pm = &mtk_pcie_pm_ops,
},
};
-builtin_platform_driver(mtk_pcie_driver);
+module_platform_driver(mtk_pcie_driver);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pci/controller/pcie-mobiveil.c b/drivers/pci/controller/pcie-mobiveil.c
index a939e8d31735..77052a0712d0 100644
--- a/drivers/pci/controller/pcie-mobiveil.c
+++ b/drivers/pci/controller/pcie-mobiveil.c
@@ -301,13 +301,6 @@ static int mobiveil_pcie_parse_dt(struct mobiveil_pcie *pcie)
struct platform_device *pdev = pcie->pdev;
struct device_node *node = dev->of_node;
struct resource *res;
- const char *type;
-
- type = of_get_property(node, "device_type", NULL);
- if (!type || strcmp(type, "pci")) {
- dev_err(dev, "invalid \"device_type\" %s\n", type);
- return -EINVAL;
- }
/* map config resource */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
diff --git a/drivers/pci/controller/pcie-xilinx-nwl.c b/drivers/pci/controller/pcie-xilinx-nwl.c
index fb32840ce8e6..81538d77f790 100644
--- a/drivers/pci/controller/pcie-xilinx-nwl.c
+++ b/drivers/pci/controller/pcie-xilinx-nwl.c
@@ -777,16 +777,7 @@ static int nwl_pcie_parse_dt(struct nwl_pcie *pcie,
struct platform_device *pdev)
{
struct device *dev = pcie->dev;
- struct device_node *node = dev->of_node;
struct resource *res;
- const char *type;
-
- /* Check for device type */
- type = of_get_property(node, "device_type", NULL);
- if (!type || strcmp(type, "pci")) {
- dev_err(dev, "invalid \"device_type\" %s\n", type);
- return -EINVAL;
- }
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "breg");
pcie->breg_base = devm_ioremap_resource(dev, res);
diff --git a/drivers/pci/controller/pcie-xilinx.c b/drivers/pci/controller/pcie-xilinx.c
index 7b1389d8e2a5..9bd1a35cd5d8 100644
--- a/drivers/pci/controller/pcie-xilinx.c
+++ b/drivers/pci/controller/pcie-xilinx.c
@@ -574,15 +574,8 @@ static int xilinx_pcie_parse_dt(struct xilinx_pcie_port *port)
struct device *dev = port->dev;
struct device_node *node = dev->of_node;
struct resource regs;
- const char *type;
int err;
- type = of_get_property(node, "device_type", NULL);
- if (!type || strcmp(type, "pci")) {
- dev_err(dev, "invalid \"device_type\" %s\n", type);
- return -EINVAL;
- }
-
err = of_address_to_resource(node, 0, &regs);
if (err) {
dev_err(dev, "missing \"reg\" property\n");
diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c
index fd2dbd7eed7b..e50b0b5815ff 100644
--- a/drivers/pci/controller/vmd.c
+++ b/drivers/pci/controller/vmd.c
@@ -404,12 +404,10 @@ static int vmd_dma_supported(struct device *dev, u64 mask)
return vmd_dma_ops(dev)->dma_supported(to_vmd_dev(dev), mask);
}
-#ifdef ARCH_HAS_DMA_GET_REQUIRED_MASK
static u64 vmd_get_required_mask(struct device *dev)
{
return vmd_dma_ops(dev)->get_required_mask(to_vmd_dev(dev));
}
-#endif
static void vmd_teardown_dma_ops(struct vmd_dev *vmd)
{
@@ -450,9 +448,7 @@ static void vmd_setup_dma_ops(struct vmd_dev *vmd)
ASSIGN_VMD_DMA_OPS(source, dest, sync_sg_for_device);
ASSIGN_VMD_DMA_OPS(source, dest, mapping_error);
ASSIGN_VMD_DMA_OPS(source, dest, dma_supported);
-#ifdef ARCH_HAS_DMA_GET_REQUIRED_MASK
ASSIGN_VMD_DMA_OPS(source, dest, get_required_mask);
-#endif
add_dma_domain(domain);
}
#undef ASSIGN_VMD_DMA_OPS
@@ -813,12 +809,12 @@ static void vmd_remove(struct pci_dev *dev)
{
struct vmd_dev *vmd = pci_get_drvdata(dev);
- vmd_detach_resources(vmd);
sysfs_remove_link(&vmd->dev->dev.kobj, "domain");
pci_stop_root_bus(vmd->bus);
pci_remove_root_bus(vmd->bus);
vmd_cleanup_srcu(vmd);
vmd_teardown_dma_ops(vmd);
+ vmd_detach_resources(vmd);
irq_domain_remove(vmd->irq_domain);
}
diff --git a/drivers/pci/hotplug/TODO b/drivers/pci/hotplug/TODO
new file mode 100644
index 000000000000..a32070be5adf
--- /dev/null
+++ b/drivers/pci/hotplug/TODO
@@ -0,0 +1,74 @@
+Contributions are solicited in particular to remedy the following issues:
+
+cpcihp:
+
+* There are no implementations of the ->hardware_test, ->get_power and
+ ->set_power callbacks in struct cpci_hp_controller_ops. Why were they
+ introduced? Can they be removed from the struct?
+
+cpqphp:
+
+* The driver spawns a kthread cpqhp_event_thread() which is woken by the
+ hardirq handler cpqhp_ctrl_intr(). Convert this to threaded IRQ handling.
+ The kthread is also woken from the timer pushbutton_helper_thread(),
+ convert it to call irq_wake_thread(). Use pciehp as a template.
+
+* A large portion of cpqphp_ctrl.c and cpqphp_pci.c concerns resource
+ management. Doesn't this duplicate functionality in the core?
+
+ibmphp:
+
+* Implementations of hotplug_slot_ops callbacks such as get_adapter_present()
+ in ibmphp_core.c create a copy of the struct slot on the stack, then perform
+ the actual operation on that copy. Determine if this overhead is necessary,
+ delete it if not. The functions also perform a NULL pointer check on the
+ struct hotplug_slot, this seems superfluous.
+
+* Several functions access the pci_slot member in struct hotplug_slot even
+ though pci_hotplug.h declares it private. See get_max_bus_speed() for an
+ example. Either the pci_slot member should no longer be declared private
+ or ibmphp should store a pointer to its bus in struct slot. Probably the
+ former.
+
+* The functions get_max_adapter_speed() and get_bus_name() are commented out.
+ Can they be deleted? There are also forward declarations at the top of
+ ibmphp_core.c as well as pointers in ibmphp_hotplug_slot_ops, likewise
+ commented out.
+
+* ibmphp_init_devno() takes a struct slot **, it could instead take a
+ struct slot *.
+
+* The return value of pci_hp_register() is not checked.
+
+* iounmap(io_mem) is called in the error path of ebda_rsrc_controller()
+ and once more in the error path of its caller ibmphp_access_ebda().
+
+* The various slot data structures are difficult to follow and need to be
+ simplified. A lot of functions are too large and too complex, they need
+ to be broken up into smaller, manageable pieces. Negative examples are
+ ebda_rsrc_controller() and configure_bridge().
+
+* A large portion of ibmphp_res.c and ibmphp_pci.c concerns resource
+ management. Doesn't this duplicate functionality in the core?
+
+sgi_hotplug:
+
+* Several functions access the pci_slot member in struct hotplug_slot even
+ though pci_hotplug.h declares it private. See sn_hp_destroy() for an
+ example. Either the pci_slot member should no longer be declared private
+ or sgi_hotplug should store a pointer to it in struct slot. Probably the
+ former.
+
+shpchp:
+
+* There is only a single implementation of struct hpc_ops. Can the struct be
+ removed and its functions invoked directly? This has already been done in
+ pciehp with commit 82a9e79ef132 ("PCI: pciehp: remove hpc_ops"). Clarify
+ if there was a specific reason not to apply the same change to shpchp.
+
+* The ->get_mode1_ECC_cap callback in shpchp_hpc_ops is never invoked.
+ Why was it introduced? Can it be removed?
+
+* The hardirq handler shpc_isr() queues events on a workqueue. It can be
+ simplified by converting it to threaded IRQ handling. Use pciehp as a
+ template.
diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h
index e438a2d734f2..a2094c07af6a 100644
--- a/drivers/pci/hotplug/acpiphp.h
+++ b/drivers/pci/hotplug/acpiphp.h
@@ -8,7 +8,7 @@
* Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
* Copyright (C) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
* Copyright (C) 2002,2003 NEC Corporation
- * Copyright (C) 2003-2005 Matthew Wilcox (matthew.wilcox@hp.com)
+ * Copyright (C) 2003-2005 Matthew Wilcox (willy@infradead.org)
* Copyright (C) 2003-2005 Hewlett Packard
*
* All rights reserved.
@@ -33,15 +33,19 @@ struct acpiphp_slot;
* struct slot - slot information for each *physical* slot
*/
struct slot {
- struct hotplug_slot *hotplug_slot;
+ struct hotplug_slot hotplug_slot;
struct acpiphp_slot *acpi_slot;
- struct hotplug_slot_info info;
unsigned int sun; /* ACPI _SUN (Slot User Number) value */
};
static inline const char *slot_name(struct slot *slot)
{
- return hotplug_slot_name(slot->hotplug_slot);
+ return hotplug_slot_name(&slot->hotplug_slot);
+}
+
+static inline struct slot *to_slot(struct hotplug_slot *hotplug_slot)
+{
+ return container_of(hotplug_slot, struct slot, hotplug_slot);
}
/*
diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c
index ad32ffbc4b91..853e04ad272c 100644
--- a/drivers/pci/hotplug/acpiphp_core.c
+++ b/drivers/pci/hotplug/acpiphp_core.c
@@ -8,7 +8,7 @@
* Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
* Copyright (C) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
* Copyright (C) 2002,2003 NEC Corporation
- * Copyright (C) 2003-2005 Matthew Wilcox (matthew.wilcox@hp.com)
+ * Copyright (C) 2003-2005 Matthew Wilcox (willy@infradead.org)
* Copyright (C) 2003-2005 Hewlett Packard
*
* All rights reserved.
@@ -40,7 +40,7 @@ bool acpiphp_disabled;
static struct acpiphp_attention_info *attention_info;
#define DRIVER_VERSION "0.5"
-#define DRIVER_AUTHOR "Greg Kroah-Hartman <gregkh@us.ibm.com>, Takayoshi Kochi <t-kochi@bq.jp.nec.com>, Matthew Wilcox <willy@hp.com>"
+#define DRIVER_AUTHOR "Greg Kroah-Hartman <gregkh@us.ibm.com>, Takayoshi Kochi <t-kochi@bq.jp.nec.com>, Matthew Wilcox <willy@infradead.org>"
#define DRIVER_DESC "ACPI Hot Plug PCI Controller Driver"
MODULE_AUTHOR(DRIVER_AUTHOR);
@@ -57,7 +57,7 @@ static int get_attention_status(struct hotplug_slot *slot, u8 *value);
static int get_latch_status(struct hotplug_slot *slot, u8 *value);
static int get_adapter_status(struct hotplug_slot *slot, u8 *value);
-static struct hotplug_slot_ops acpi_hotplug_slot_ops = {
+static const struct hotplug_slot_ops acpi_hotplug_slot_ops = {
.enable_slot = enable_slot,
.disable_slot = disable_slot,
.set_attention_status = set_attention_status,
@@ -118,7 +118,7 @@ EXPORT_SYMBOL_GPL(acpiphp_unregister_attention);
*/
static int enable_slot(struct hotplug_slot *hotplug_slot)
{
- struct slot *slot = hotplug_slot->private;
+ struct slot *slot = to_slot(hotplug_slot);
pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot));
@@ -135,7 +135,7 @@ static int enable_slot(struct hotplug_slot *hotplug_slot)
*/
static int disable_slot(struct hotplug_slot *hotplug_slot)
{
- struct slot *slot = hotplug_slot->private;
+ struct slot *slot = to_slot(hotplug_slot);
pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot));
@@ -179,7 +179,7 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
*/
static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
{
- struct slot *slot = hotplug_slot->private;
+ struct slot *slot = to_slot(hotplug_slot);
pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot));
@@ -225,7 +225,7 @@ static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
*/
static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
{
- struct slot *slot = hotplug_slot->private;
+ struct slot *slot = to_slot(hotplug_slot);
pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot));
@@ -245,7 +245,7 @@ static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
*/
static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
{
- struct slot *slot = hotplug_slot->private;
+ struct slot *slot = to_slot(hotplug_slot);
pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot));
@@ -266,39 +266,26 @@ int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot,
if (!slot)
goto error;
- slot->hotplug_slot = kzalloc(sizeof(*slot->hotplug_slot), GFP_KERNEL);
- if (!slot->hotplug_slot)
- goto error_slot;
-
- slot->hotplug_slot->info = &slot->info;
-
- slot->hotplug_slot->private = slot;
- slot->hotplug_slot->ops = &acpi_hotplug_slot_ops;
+ slot->hotplug_slot.ops = &acpi_hotplug_slot_ops;
slot->acpi_slot = acpiphp_slot;
- slot->hotplug_slot->info->power_status = acpiphp_get_power_status(slot->acpi_slot);
- slot->hotplug_slot->info->attention_status = 0;
- slot->hotplug_slot->info->latch_status = acpiphp_get_latch_status(slot->acpi_slot);
- slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot);
acpiphp_slot->slot = slot;
slot->sun = sun;
snprintf(name, SLOT_NAME_SIZE, "%u", sun);
- retval = pci_hp_register(slot->hotplug_slot, acpiphp_slot->bus,
+ retval = pci_hp_register(&slot->hotplug_slot, acpiphp_slot->bus,
acpiphp_slot->device, name);
if (retval == -EBUSY)
- goto error_hpslot;
+ goto error_slot;
if (retval) {
pr_err("pci_hp_register failed with error %d\n", retval);
- goto error_hpslot;
+ goto error_slot;
}
pr_info("Slot [%s] registered\n", slot_name(slot));
return 0;
-error_hpslot:
- kfree(slot->hotplug_slot);
error_slot:
kfree(slot);
error:
@@ -312,8 +299,7 @@ void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
pr_info("Slot [%s] unregistered\n", slot_name(slot));
- pci_hp_deregister(slot->hotplug_slot);
- kfree(slot->hotplug_slot);
+ pci_hp_deregister(&slot->hotplug_slot);
kfree(slot);
}
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 12afa7fdf77e..e4c46637f32f 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -5,7 +5,7 @@
* Copyright (C) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
* Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
* Copyright (C) 2002,2003 NEC Corporation
- * Copyright (C) 2003-2005 Matthew Wilcox (matthew.wilcox@hp.com)
+ * Copyright (C) 2003-2005 Matthew Wilcox (willy@infradead.org)
* Copyright (C) 2003-2005 Hewlett Packard
* Copyright (C) 2005 Rajesh Shah (rajesh.shah@intel.com)
* Copyright (C) 2005 Intel Corporation
diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c
index 41713f16ff97..df48b3b03ab4 100644
--- a/drivers/pci/hotplug/acpiphp_ibm.c
+++ b/drivers/pci/hotplug/acpiphp_ibm.c
@@ -41,7 +41,7 @@ MODULE_VERSION(DRIVER_VERSION);
#define IBM_HARDWARE_ID1 "IBM37D0"
#define IBM_HARDWARE_ID2 "IBM37D4"
-#define hpslot_to_sun(A) (((struct slot *)((A)->private))->sun)
+#define hpslot_to_sun(A) (to_slot(A)->sun)
/* union apci_descriptor - allows access to the
* various device descriptors that are embedded in the
diff --git a/drivers/pci/hotplug/cpci_hotplug.h b/drivers/pci/hotplug/cpci_hotplug.h
index 4658557be01a..f33ff2bca414 100644
--- a/drivers/pci/hotplug/cpci_hotplug.h
+++ b/drivers/pci/hotplug/cpci_hotplug.h
@@ -32,8 +32,10 @@ struct slot {
unsigned int devfn;
struct pci_bus *bus;
struct pci_dev *dev;
+ unsigned int latch_status:1;
+ unsigned int adapter_status:1;
unsigned int extracting;
- struct hotplug_slot *hotplug_slot;
+ struct hotplug_slot hotplug_slot;
struct list_head slot_list;
};
@@ -58,7 +60,12 @@ struct cpci_hp_controller {
static inline const char *slot_name(struct slot *slot)
{
- return hotplug_slot_name(slot->hotplug_slot);
+ return hotplug_slot_name(&slot->hotplug_slot);
+}
+
+static inline struct slot *to_slot(struct hotplug_slot *hotplug_slot)
+{
+ return container_of(hotplug_slot, struct slot, hotplug_slot);
}
int cpci_hp_register_controller(struct cpci_hp_controller *controller);
diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c
index 52a339baf06c..603eadf3d965 100644
--- a/drivers/pci/hotplug/cpci_hotplug_core.c
+++ b/drivers/pci/hotplug/cpci_hotplug_core.c
@@ -57,7 +57,7 @@ static int get_attention_status(struct hotplug_slot *slot, u8 *value);
static int get_adapter_status(struct hotplug_slot *slot, u8 *value);
static int get_latch_status(struct hotplug_slot *slot, u8 *value);
-static struct hotplug_slot_ops cpci_hotplug_slot_ops = {
+static const struct hotplug_slot_ops cpci_hotplug_slot_ops = {
.enable_slot = enable_slot,
.disable_slot = disable_slot,
.set_attention_status = set_attention_status,
@@ -68,29 +68,9 @@ static struct hotplug_slot_ops cpci_hotplug_slot_ops = {
};
static int
-update_latch_status(struct hotplug_slot *hotplug_slot, u8 value)
-{
- struct hotplug_slot_info info;
-
- memcpy(&info, hotplug_slot->info, sizeof(struct hotplug_slot_info));
- info.latch_status = value;
- return pci_hp_change_slot_info(hotplug_slot, &info);
-}
-
-static int
-update_adapter_status(struct hotplug_slot *hotplug_slot, u8 value)
-{
- struct hotplug_slot_info info;
-
- memcpy(&info, hotplug_slot->info, sizeof(struct hotplug_slot_info));
- info.adapter_status = value;
- return pci_hp_change_slot_info(hotplug_slot, &info);
-}
-
-static int
enable_slot(struct hotplug_slot *hotplug_slot)
{
- struct slot *slot = hotplug_slot->private;
+ struct slot *slot = to_slot(hotplug_slot);
int retval = 0;
dbg("%s - physical_slot = %s", __func__, slot_name(slot));
@@ -103,7 +83,7 @@ enable_slot(struct hotplug_slot *hotplug_slot)
static int
disable_slot(struct hotplug_slot *hotplug_slot)
{
- struct slot *slot = hotplug_slot->private;
+ struct slot *slot = to_slot(hotplug_slot);
int retval = 0;
dbg("%s - physical_slot = %s", __func__, slot_name(slot));
@@ -135,8 +115,7 @@ disable_slot(struct hotplug_slot *hotplug_slot)
goto disable_error;
}
- if (update_adapter_status(slot->hotplug_slot, 0))
- warn("failure to update adapter file");
+ slot->adapter_status = 0;
if (slot->extracting) {
slot->extracting = 0;
@@ -160,7 +139,7 @@ cpci_get_power_status(struct slot *slot)
static int
get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
{
- struct slot *slot = hotplug_slot->private;
+ struct slot *slot = to_slot(hotplug_slot);
*value = cpci_get_power_status(slot);
return 0;
@@ -169,7 +148,7 @@ get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
static int
get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
{
- struct slot *slot = hotplug_slot->private;
+ struct slot *slot = to_slot(hotplug_slot);
*value = cpci_get_attention_status(slot);
return 0;
@@ -178,27 +157,29 @@ get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
static int
set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
{
- return cpci_set_attention_status(hotplug_slot->private, status);
+ return cpci_set_attention_status(to_slot(hotplug_slot), status);
}
static int
get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
{
- *value = hotplug_slot->info->adapter_status;
+ struct slot *slot = to_slot(hotplug_slot);
+
+ *value = slot->adapter_status;
return 0;
}
static int
get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
{
- *value = hotplug_slot->info->latch_status;
+ struct slot *slot = to_slot(hotplug_slot);
+
+ *value = slot->latch_status;
return 0;
}
static void release_slot(struct slot *slot)
{
- kfree(slot->hotplug_slot->info);
- kfree(slot->hotplug_slot);
pci_dev_put(slot->dev);
kfree(slot);
}
@@ -209,8 +190,6 @@ int
cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last)
{
struct slot *slot;
- struct hotplug_slot *hotplug_slot;
- struct hotplug_slot_info *info;
char name[SLOT_NAME_SIZE];
int status;
int i;
@@ -229,43 +208,19 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last)
goto error;
}
- hotplug_slot =
- kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL);
- if (!hotplug_slot) {
- status = -ENOMEM;
- goto error_slot;
- }
- slot->hotplug_slot = hotplug_slot;
-
- info = kzalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL);
- if (!info) {
- status = -ENOMEM;
- goto error_hpslot;
- }
- hotplug_slot->info = info;
-
slot->bus = bus;
slot->number = i;
slot->devfn = PCI_DEVFN(i, 0);
snprintf(name, SLOT_NAME_SIZE, "%02x:%02x", bus->number, i);
- hotplug_slot->private = slot;
- hotplug_slot->ops = &cpci_hotplug_slot_ops;
-
- /*
- * Initialize the slot info structure with some known
- * good values.
- */
- dbg("initializing slot %s", name);
- info->power_status = cpci_get_power_status(slot);
- info->attention_status = cpci_get_attention_status(slot);
+ slot->hotplug_slot.ops = &cpci_hotplug_slot_ops;
dbg("registering slot %s", name);
- status = pci_hp_register(slot->hotplug_slot, bus, i, name);
+ status = pci_hp_register(&slot->hotplug_slot, bus, i, name);
if (status) {
err("pci_hp_register failed with error %d", status);
- goto error_info;
+ goto error_slot;
}
dbg("slot registered with name: %s", slot_name(slot));
@@ -276,10 +231,6 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last)
up_write(&list_rwsem);
}
return 0;
-error_info:
- kfree(info);
-error_hpslot:
- kfree(hotplug_slot);
error_slot:
kfree(slot);
error:
@@ -305,7 +256,7 @@ cpci_hp_unregister_bus(struct pci_bus *bus)
slots--;
dbg("deregistering slot %s", slot_name(slot));
- pci_hp_deregister(slot->hotplug_slot);
+ pci_hp_deregister(&slot->hotplug_slot);
release_slot(slot);
}
}
@@ -359,10 +310,8 @@ init_slots(int clear_ins)
__func__, slot_name(slot));
dev = pci_get_slot(slot->bus, PCI_DEVFN(slot->number, 0));
if (dev) {
- if (update_adapter_status(slot->hotplug_slot, 1))
- warn("failure to update adapter file");
- if (update_latch_status(slot->hotplug_slot, 1))
- warn("failure to update latch file");
+ slot->adapter_status = 1;
+ slot->latch_status = 1;
slot->dev = dev;
}
}
@@ -424,11 +373,8 @@ check_slots(void)
dbg("%s - slot %s HS_CSR (2) = %04x",
__func__, slot_name(slot), hs_csr);
- if (update_latch_status(slot->hotplug_slot, 1))
- warn("failure to update latch file");
-
- if (update_adapter_status(slot->hotplug_slot, 1))
- warn("failure to update adapter file");
+ slot->latch_status = 1;
+ slot->adapter_status = 1;
cpci_led_off(slot);
@@ -449,9 +395,7 @@ check_slots(void)
__func__, slot_name(slot), hs_csr);
if (!slot->extracting) {
- if (update_latch_status(slot->hotplug_slot, 0))
- warn("failure to update latch file");
-
+ slot->latch_status = 0;
slot->extracting = 1;
atomic_inc(&extracting);
}
@@ -465,8 +409,7 @@ check_slots(void)
*/
err("card in slot %s was improperly removed",
slot_name(slot));
- if (update_adapter_status(slot->hotplug_slot, 0))
- warn("failure to update adapter file");
+ slot->adapter_status = 0;
slot->extracting = 0;
atomic_dec(&extracting);
}
@@ -615,7 +558,7 @@ cleanup_slots(void)
goto cleanup_null;
list_for_each_entry_safe(slot, tmp, &slot_list, slot_list) {
list_del(&slot->slot_list);
- pci_hp_deregister(slot->hotplug_slot);
+ pci_hp_deregister(&slot->hotplug_slot);
release_slot(slot);
}
cleanup_null:
diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c
index 389b8fb50cd9..2c16adb7f4ec 100644
--- a/drivers/pci/hotplug/cpci_hotplug_pci.c
+++ b/drivers/pci/hotplug/cpci_hotplug_pci.c
@@ -194,8 +194,7 @@ int cpci_led_on(struct slot *slot)
slot->devfn,
hs_cap + 2,
hs_csr)) {
- err("Could not set LOO for slot %s",
- hotplug_slot_name(slot->hotplug_slot));
+ err("Could not set LOO for slot %s", slot_name(slot));
return -ENODEV;
}
}
@@ -223,8 +222,7 @@ int cpci_led_off(struct slot *slot)
slot->devfn,
hs_cap + 2,
hs_csr)) {
- err("Could not clear LOO for slot %s",
- hotplug_slot_name(slot->hotplug_slot));
+ err("Could not clear LOO for slot %s", slot_name(slot));
return -ENODEV;
}
}
diff --git a/drivers/pci/hotplug/cpqphp.h b/drivers/pci/hotplug/cpqphp.h
index db78b394a075..77e4e0142fbc 100644
--- a/drivers/pci/hotplug/cpqphp.h
+++ b/drivers/pci/hotplug/cpqphp.h
@@ -260,7 +260,7 @@ struct slot {
u8 hp_slot;
struct controller *ctrl;
void __iomem *p_sm_slot;
- struct hotplug_slot *hotplug_slot;
+ struct hotplug_slot hotplug_slot;
};
struct pci_resource {
@@ -445,7 +445,12 @@ extern u8 cpqhp_disk_irq;
static inline const char *slot_name(struct slot *slot)
{
- return hotplug_slot_name(slot->hotplug_slot);
+ return hotplug_slot_name(&slot->hotplug_slot);
+}
+
+static inline struct slot *to_slot(struct hotplug_slot *hotplug_slot)
+{
+ return container_of(hotplug_slot, struct slot, hotplug_slot);
}
/*
diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c
index 5a06636e910a..16bbb183695a 100644
--- a/drivers/pci/hotplug/cpqphp_core.c
+++ b/drivers/pci/hotplug/cpqphp_core.c
@@ -121,7 +121,6 @@ static int init_SERR(struct controller *ctrl)
{
u32 tempdword;
u32 number_of_slots;
- u8 physical_slot;
if (!ctrl)
return 1;
@@ -131,7 +130,6 @@ static int init_SERR(struct controller *ctrl)
number_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F;
/* Loop through slots */
while (number_of_slots) {
- physical_slot = tempdword;
writeb(0, ctrl->hpc_reg + SLOT_SERR);
tempdword++;
number_of_slots--;
@@ -275,9 +273,7 @@ static int ctrl_slot_cleanup(struct controller *ctrl)
while (old_slot) {
next_slot = old_slot->next;
- pci_hp_deregister(old_slot->hotplug_slot);
- kfree(old_slot->hotplug_slot->info);
- kfree(old_slot->hotplug_slot);
+ pci_hp_deregister(&old_slot->hotplug_slot);
kfree(old_slot);
old_slot = next_slot;
}
@@ -419,7 +415,7 @@ cpqhp_set_attention_status(struct controller *ctrl, struct pci_func *func,
static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
{
struct pci_func *slot_func;
- struct slot *slot = hotplug_slot->private;
+ struct slot *slot = to_slot(hotplug_slot);
struct controller *ctrl = slot->ctrl;
u8 bus;
u8 devfn;
@@ -446,7 +442,7 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
static int process_SI(struct hotplug_slot *hotplug_slot)
{
struct pci_func *slot_func;
- struct slot *slot = hotplug_slot->private;
+ struct slot *slot = to_slot(hotplug_slot);
struct controller *ctrl = slot->ctrl;
u8 bus;
u8 devfn;
@@ -478,7 +474,7 @@ static int process_SI(struct hotplug_slot *hotplug_slot)
static int process_SS(struct hotplug_slot *hotplug_slot)
{
struct pci_func *slot_func;
- struct slot *slot = hotplug_slot->private;
+ struct slot *slot = to_slot(hotplug_slot);
struct controller *ctrl = slot->ctrl;
u8 bus;
u8 devfn;
@@ -505,7 +501,7 @@ static int process_SS(struct hotplug_slot *hotplug_slot)
static int hardware_test(struct hotplug_slot *hotplug_slot, u32 value)
{
- struct slot *slot = hotplug_slot->private;
+ struct slot *slot = to_slot(hotplug_slot);
struct controller *ctrl = slot->ctrl;
dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
@@ -516,7 +512,7 @@ static int hardware_test(struct hotplug_slot *hotplug_slot, u32 value)
static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
{
- struct slot *slot = hotplug_slot->private;
+ struct slot *slot = to_slot(hotplug_slot);
struct controller *ctrl = slot->ctrl;
dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
@@ -527,7 +523,7 @@ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
{
- struct slot *slot = hotplug_slot->private;
+ struct slot *slot = to_slot(hotplug_slot);
struct controller *ctrl = slot->ctrl;
dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
@@ -538,7 +534,7 @@ static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
{
- struct slot *slot = hotplug_slot->private;
+ struct slot *slot = to_slot(hotplug_slot);
struct controller *ctrl = slot->ctrl;
dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
@@ -550,7 +546,7 @@ static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
{
- struct slot *slot = hotplug_slot->private;
+ struct slot *slot = to_slot(hotplug_slot);
struct controller *ctrl = slot->ctrl;
dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
@@ -560,7 +556,7 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
return 0;
}
-static struct hotplug_slot_ops cpqphp_hotplug_slot_ops = {
+static const struct hotplug_slot_ops cpqphp_hotplug_slot_ops = {
.set_attention_status = set_attention_status,
.enable_slot = process_SI,
.disable_slot = process_SS,
@@ -578,8 +574,6 @@ static int ctrl_slot_setup(struct controller *ctrl,
void __iomem *smbios_table)
{
struct slot *slot;
- struct hotplug_slot *hotplug_slot;
- struct hotplug_slot_info *hotplug_slot_info;
struct pci_bus *bus = ctrl->pci_bus;
u8 number_of_slots;
u8 slot_device;
@@ -605,22 +599,6 @@ static int ctrl_slot_setup(struct controller *ctrl,
goto error;
}
- slot->hotplug_slot = kzalloc(sizeof(*(slot->hotplug_slot)),
- GFP_KERNEL);
- if (!slot->hotplug_slot) {
- result = -ENOMEM;
- goto error_slot;
- }
- hotplug_slot = slot->hotplug_slot;
-
- hotplug_slot->info = kzalloc(sizeof(*(hotplug_slot->info)),
- GFP_KERNEL);
- if (!hotplug_slot->info) {
- result = -ENOMEM;
- goto error_hpslot;
- }
- hotplug_slot_info = hotplug_slot->info;
-
slot->ctrl = ctrl;
slot->bus = ctrl->bus;
slot->device = slot_device;
@@ -669,29 +647,20 @@ static int ctrl_slot_setup(struct controller *ctrl,
((read_slot_enable(ctrl) << 2) >> ctrl_slot) & 0x04;
/* register this slot with the hotplug pci core */
- hotplug_slot->private = slot;
snprintf(name, SLOT_NAME_SIZE, "%u", slot->number);
- hotplug_slot->ops = &cpqphp_hotplug_slot_ops;
-
- hotplug_slot_info->power_status = get_slot_enabled(ctrl, slot);
- hotplug_slot_info->attention_status =
- cpq_get_attention_status(ctrl, slot);
- hotplug_slot_info->latch_status =
- cpq_get_latch_status(ctrl, slot);
- hotplug_slot_info->adapter_status =
- get_presence_status(ctrl, slot);
+ slot->hotplug_slot.ops = &cpqphp_hotplug_slot_ops;
dbg("registering bus %d, dev %d, number %d, ctrl->slot_device_offset %d, slot %d\n",
slot->bus, slot->device,
slot->number, ctrl->slot_device_offset,
slot_number);
- result = pci_hp_register(hotplug_slot,
+ result = pci_hp_register(&slot->hotplug_slot,
ctrl->pci_dev->bus,
slot->device,
name);
if (result) {
err("pci_hp_register failed with error %d\n", result);
- goto error_info;
+ goto error_slot;
}
slot->next = ctrl->slot;
@@ -703,10 +672,6 @@ static int ctrl_slot_setup(struct controller *ctrl,
}
return 0;
-error_info:
- kfree(hotplug_slot_info);
-error_hpslot:
- kfree(hotplug_slot);
error_slot:
kfree(slot);
error:
diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c
index 616df442520b..b7f4e1f099d9 100644
--- a/drivers/pci/hotplug/cpqphp_ctrl.c
+++ b/drivers/pci/hotplug/cpqphp_ctrl.c
@@ -1130,9 +1130,7 @@ static u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_
for (slot = ctrl->slot; slot; slot = slot->next) {
if (slot->device == (hp_slot + ctrl->slot_device_offset))
continue;
- if (!slot->hotplug_slot || !slot->hotplug_slot->info)
- continue;
- if (slot->hotplug_slot->info->adapter_status == 0)
+ if (get_presence_status(ctrl, slot) == 0)
continue;
/* If another adapter is running on the same segment but at a
* lower speed/mode, we allow the new adapter to function at
@@ -1767,24 +1765,6 @@ void cpqhp_event_stop_thread(void)
}
-static int update_slot_info(struct controller *ctrl, struct slot *slot)
-{
- struct hotplug_slot_info *info;
- int result;
-
- info = kmalloc(sizeof(*info), GFP_KERNEL);
- if (!info)
- return -ENOMEM;
-
- info->power_status = get_slot_enabled(ctrl, slot);
- info->attention_status = cpq_get_attention_status(ctrl, slot);
- info->latch_status = cpq_get_latch_status(ctrl, slot);
- info->adapter_status = get_presence_status(ctrl, slot);
- result = pci_hp_change_slot_info(slot->hotplug_slot, info);
- kfree(info);
- return result;
-}
-
static void interrupt_event_handler(struct controller *ctrl)
{
int loop = 0;
@@ -1884,9 +1864,6 @@ static void interrupt_event_handler(struct controller *ctrl)
/***********POWER FAULT */
else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) {
dbg("power fault\n");
- } else {
- /* refresh notification */
- update_slot_info(ctrl, p_slot);
}
ctrl->event_queue[loop].event_type = 0;
@@ -2057,9 +2034,6 @@ int cpqhp_process_SI(struct controller *ctrl, struct pci_func *func)
if (rc)
dbg("%s: rc = %d\n", __func__, rc);
- if (p_slot)
- update_slot_info(ctrl, p_slot);
-
return rc;
}
@@ -2125,9 +2099,6 @@ int cpqhp_process_SS(struct controller *ctrl, struct pci_func *func)
rc = 1;
}
- if (p_slot)
- update_slot_info(ctrl, p_slot);
-
return rc;
}
diff --git a/drivers/pci/hotplug/ibmphp.h b/drivers/pci/hotplug/ibmphp.h
index fddb78606c74..b89f850c3a4e 100644
--- a/drivers/pci/hotplug/ibmphp.h
+++ b/drivers/pci/hotplug/ibmphp.h
@@ -698,7 +698,7 @@ struct slot {
u8 supported_bus_mode;
u8 flag; /* this is for disable slot and polling */
u8 ctlr_index;
- struct hotplug_slot *hotplug_slot;
+ struct hotplug_slot hotplug_slot;
struct controller *ctrl;
struct pci_func *func;
u8 irq[4];
@@ -740,7 +740,12 @@ int ibmphp_do_disable_slot(struct slot *slot_cur);
int ibmphp_update_slot_info(struct slot *); /* This function is called from HPC, so we need it to not be be static */
int ibmphp_configure_card(struct pci_func *, u8);
int ibmphp_unconfigure_card(struct slot **, int);
-extern struct hotplug_slot_ops ibmphp_hotplug_slot_ops;
+extern const struct hotplug_slot_ops ibmphp_hotplug_slot_ops;
+
+static inline struct slot *to_slot(struct hotplug_slot *hotplug_slot)
+{
+ return container_of(hotplug_slot, struct slot, hotplug_slot);
+}
#endif //__IBMPHP_H
diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c
index 4ea57e9019f1..08a58e911fc2 100644
--- a/drivers/pci/hotplug/ibmphp_core.c
+++ b/drivers/pci/hotplug/ibmphp_core.c
@@ -247,11 +247,8 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 value)
break;
}
if (rc == 0) {
- pslot = hotplug_slot->private;
- if (pslot)
- rc = ibmphp_hpc_writeslot(pslot, cmd);
- else
- rc = -ENODEV;
+ pslot = to_slot(hotplug_slot);
+ rc = ibmphp_hpc_writeslot(pslot, cmd);
}
} else
rc = -ENODEV;
@@ -273,19 +270,15 @@ static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
ibmphp_lock_operations();
if (hotplug_slot) {
- pslot = hotplug_slot->private;
- if (pslot) {
- memcpy(&myslot, pslot, sizeof(struct slot));
- rc = ibmphp_hpc_readslot(pslot, READ_SLOTSTATUS,
- &(myslot.status));
- if (!rc)
- rc = ibmphp_hpc_readslot(pslot,
- READ_EXTSLOTSTATUS,
- &(myslot.ext_status));
- if (!rc)
- *value = SLOT_ATTN(myslot.status,
- myslot.ext_status);
- }
+ pslot = to_slot(hotplug_slot);
+ memcpy(&myslot, pslot, sizeof(struct slot));
+ rc = ibmphp_hpc_readslot(pslot, READ_SLOTSTATUS,
+ &myslot.status);
+ if (!rc)
+ rc = ibmphp_hpc_readslot(pslot, READ_EXTSLOTSTATUS,
+ &myslot.ext_status);
+ if (!rc)
+ *value = SLOT_ATTN(myslot.status, myslot.ext_status);
}
ibmphp_unlock_operations();
@@ -303,14 +296,12 @@ static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
(ulong) hotplug_slot, (ulong) value);
ibmphp_lock_operations();
if (hotplug_slot) {
- pslot = hotplug_slot->private;
- if (pslot) {
- memcpy(&myslot, pslot, sizeof(struct slot));
- rc = ibmphp_hpc_readslot(pslot, READ_SLOTSTATUS,
- &(myslot.status));
- if (!rc)
- *value = SLOT_LATCH(myslot.status);
- }
+ pslot = to_slot(hotplug_slot);
+ memcpy(&myslot, pslot, sizeof(struct slot));
+ rc = ibmphp_hpc_readslot(pslot, READ_SLOTSTATUS,
+ &myslot.status);
+ if (!rc)
+ *value = SLOT_LATCH(myslot.status);
}
ibmphp_unlock_operations();
@@ -330,14 +321,12 @@ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
(ulong) hotplug_slot, (ulong) value);
ibmphp_lock_operations();
if (hotplug_slot) {
- pslot = hotplug_slot->private;
- if (pslot) {
- memcpy(&myslot, pslot, sizeof(struct slot));
- rc = ibmphp_hpc_readslot(pslot, READ_SLOTSTATUS,
- &(myslot.status));
- if (!rc)
- *value = SLOT_PWRGD(myslot.status);
- }
+ pslot = to_slot(hotplug_slot);
+ memcpy(&myslot, pslot, sizeof(struct slot));
+ rc = ibmphp_hpc_readslot(pslot, READ_SLOTSTATUS,
+ &myslot.status);
+ if (!rc)
+ *value = SLOT_PWRGD(myslot.status);
}
ibmphp_unlock_operations();
@@ -357,18 +346,16 @@ static int get_adapter_present(struct hotplug_slot *hotplug_slot, u8 *value)
(ulong) hotplug_slot, (ulong) value);
ibmphp_lock_operations();
if (hotplug_slot) {
- pslot = hotplug_slot->private;
- if (pslot) {
- memcpy(&myslot, pslot, sizeof(struct slot));
- rc = ibmphp_hpc_readslot(pslot, READ_SLOTSTATUS,
- &(myslot.status));
- if (!rc) {
- present = SLOT_PRESENT(myslot.status);
- if (present == HPC_SLOT_EMPTY)
- *value = 0;
- else
- *value = 1;
- }
+ pslot = to_slot(hotplug_slot);
+ memcpy(&myslot, pslot, sizeof(struct slot));
+ rc = ibmphp_hpc_readslot(pslot, READ_SLOTSTATUS,
+ &myslot.status);
+ if (!rc) {
+ present = SLOT_PRESENT(myslot.status);
+ if (present == HPC_SLOT_EMPTY)
+ *value = 0;
+ else
+ *value = 1;
}
}
@@ -382,7 +369,7 @@ static int get_max_bus_speed(struct slot *slot)
int rc = 0;
u8 mode = 0;
enum pci_bus_speed speed;
- struct pci_bus *bus = slot->hotplug_slot->pci_slot->bus;
+ struct pci_bus *bus = slot->hotplug_slot.pci_slot->bus;
debug("%s - Entry slot[%p]\n", __func__, slot);
@@ -582,29 +569,10 @@ static int validate(struct slot *slot_cur, int opn)
****************************************************************************/
int ibmphp_update_slot_info(struct slot *slot_cur)
{
- struct hotplug_slot_info *info;
- struct pci_bus *bus = slot_cur->hotplug_slot->pci_slot->bus;
- int rc;
+ struct pci_bus *bus = slot_cur->hotplug_slot.pci_slot->bus;
u8 bus_speed;
u8 mode;
- info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL);
- if (!info)
- return -ENOMEM;
-
- info->power_status = SLOT_PWRGD(slot_cur->status);
- info->attention_status = SLOT_ATTN(slot_cur->status,
- slot_cur->ext_status);
- info->latch_status = SLOT_LATCH(slot_cur->status);
- if (!SLOT_PRESENT(slot_cur->status)) {
- info->adapter_status = 0;
-/* info->max_adapter_speed_status = MAX_ADAPTER_NONE; */
- } else {
- info->adapter_status = 1;
-/* get_max_adapter_speed_1(slot_cur->hotplug_slot,
- &info->max_adapter_speed_status, 0); */
- }
-
bus_speed = slot_cur->bus_on->current_speed;
mode = slot_cur->bus_on->current_bus_mode;
@@ -630,9 +598,7 @@ int ibmphp_update_slot_info(struct slot *slot_cur)
bus->cur_bus_speed = bus_speed;
// To do: bus_names
- rc = pci_hp_change_slot_info(slot_cur->hotplug_slot, info);
- kfree(info);
- return rc;
+ return 0;
}
@@ -673,7 +639,7 @@ static void free_slots(void)
list_for_each_entry_safe(slot_cur, next, &ibmphp_slot_head,
ibm_slot_list) {
- pci_hp_del(slot_cur->hotplug_slot);
+ pci_hp_del(&slot_cur->hotplug_slot);
slot_cur->ctrl = NULL;
slot_cur->bus_on = NULL;
@@ -683,9 +649,7 @@ static void free_slots(void)
*/
ibmphp_unconfigure_card(&slot_cur, -1);
- pci_hp_destroy(slot_cur->hotplug_slot);
- kfree(slot_cur->hotplug_slot->info);
- kfree(slot_cur->hotplug_slot);
+ pci_hp_destroy(&slot_cur->hotplug_slot);
kfree(slot_cur);
}
debug("%s -- exit\n", __func__);
@@ -1007,7 +971,7 @@ static int enable_slot(struct hotplug_slot *hs)
ibmphp_lock_operations();
debug("ENABLING SLOT........\n");
- slot_cur = hs->private;
+ slot_cur = to_slot(hs);
rc = validate(slot_cur, ENABLE);
if (rc) {
@@ -1095,8 +1059,7 @@ static int enable_slot(struct hotplug_slot *hs)
slot_cur->func = kzalloc(sizeof(struct pci_func), GFP_KERNEL);
if (!slot_cur->func) {
- /* We cannot do update_slot_info here, since no memory for
- * kmalloc n.e.ways, and update_slot_info allocates some */
+ /* do update_slot_info here? */
rc = -ENOMEM;
goto error_power;
}
@@ -1169,7 +1132,7 @@ error_power:
**************************************************************/
static int ibmphp_disable_slot(struct hotplug_slot *hotplug_slot)
{
- struct slot *slot = hotplug_slot->private;
+ struct slot *slot = to_slot(hotplug_slot);
int rc;
ibmphp_lock_operations();
@@ -1259,7 +1222,7 @@ error:
goto exit;
}
-struct hotplug_slot_ops ibmphp_hotplug_slot_ops = {
+const struct hotplug_slot_ops ibmphp_hotplug_slot_ops = {
.set_attention_status = set_attention_status,
.enable_slot = enable_slot,
.disable_slot = ibmphp_disable_slot,
diff --git a/drivers/pci/hotplug/ibmphp_ebda.c b/drivers/pci/hotplug/ibmphp_ebda.c
index 6f8e90e3ec08..11a2661dc062 100644
--- a/drivers/pci/hotplug/ibmphp_ebda.c
+++ b/drivers/pci/hotplug/ibmphp_ebda.c
@@ -666,36 +666,8 @@ static int fillslotinfo(struct hotplug_slot *hotplug_slot)
struct slot *slot;
int rc = 0;
- if (!hotplug_slot || !hotplug_slot->private)
- return -EINVAL;
-
- slot = hotplug_slot->private;
+ slot = to_slot(hotplug_slot);
rc = ibmphp_hpc_readslot(slot, READ_ALLSTAT, NULL);
- if (rc)
- return rc;
-
- // power - enabled:1 not:0
- hotplug_slot->info->power_status = SLOT_POWER(slot->status);
-
- // attention - off:0, on:1, blinking:2
- hotplug_slot->info->attention_status = SLOT_ATTN(slot->status, slot->ext_status);
-
- // latch - open:1 closed:0
- hotplug_slot->info->latch_status = SLOT_LATCH(slot->status);
-
- // pci board - present:1 not:0
- if (SLOT_PRESENT(slot->status))
- hotplug_slot->info->adapter_status = 1;
- else
- hotplug_slot->info->adapter_status = 0;
-/*
- if (slot->bus_on->supported_bus_mode
- && (slot->bus_on->supported_speed == BUS_SPEED_66))
- hotplug_slot->info->max_bus_speed_status = BUS_SPEED_66PCIX;
- else
- hotplug_slot->info->max_bus_speed_status = slot->bus_on->supported_speed;
-*/
-
return rc;
}
@@ -712,7 +684,6 @@ static int __init ebda_rsrc_controller(void)
u8 ctlr_id, temp, bus_index;
u16 ctlr, slot, bus;
u16 slot_num, bus_num, index;
- struct hotplug_slot *hp_slot_ptr;
struct controller *hpc_ptr;
struct ebda_hpc_bus *bus_ptr;
struct ebda_hpc_slot *slot_ptr;
@@ -771,7 +742,7 @@ static int __init ebda_rsrc_controller(void)
bus_info_ptr1 = kzalloc(sizeof(struct bus_info), GFP_KERNEL);
if (!bus_info_ptr1) {
rc = -ENOMEM;
- goto error_no_hp_slot;
+ goto error_no_slot;
}
bus_info_ptr1->slot_min = slot_ptr->slot_num;
bus_info_ptr1->slot_max = slot_ptr->slot_num;
@@ -842,7 +813,7 @@ static int __init ebda_rsrc_controller(void)
(hpc_ptr->u.isa_ctlr.io_end - hpc_ptr->u.isa_ctlr.io_start + 1),
"ibmphp")) {
rc = -ENODEV;
- goto error_no_hp_slot;
+ goto error_no_slot;
}
hpc_ptr->irq = readb(io_mem + addr + 4);
addr += 5;
@@ -857,7 +828,7 @@ static int __init ebda_rsrc_controller(void)
break;
default:
rc = -ENODEV;
- goto error_no_hp_slot;
+ goto error_no_slot;
}
//reorganize chassis' linked list
@@ -870,19 +841,6 @@ static int __init ebda_rsrc_controller(void)
// register slots with hpc core as well as create linked list of ibm slot
for (index = 0; index < hpc_ptr->slot_count; index++) {
-
- hp_slot_ptr = kzalloc(sizeof(*hp_slot_ptr), GFP_KERNEL);
- if (!hp_slot_ptr) {
- rc = -ENOMEM;
- goto error_no_hp_slot;
- }
-
- hp_slot_ptr->info = kzalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL);
- if (!hp_slot_ptr->info) {
- rc = -ENOMEM;
- goto error_no_hp_info;
- }
-
tmp_slot = kzalloc(sizeof(*tmp_slot), GFP_KERNEL);
if (!tmp_slot) {
rc = -ENOMEM;
@@ -909,7 +867,6 @@ static int __init ebda_rsrc_controller(void)
bus_info_ptr1 = ibmphp_find_same_bus_num(hpc_ptr->slots[index].slot_bus_num);
if (!bus_info_ptr1) {
- kfree(tmp_slot);
rc = -ENODEV;
goto error;
}
@@ -919,22 +876,19 @@ static int __init ebda_rsrc_controller(void)
tmp_slot->ctlr_index = hpc_ptr->slots[index].ctl_index;
tmp_slot->number = hpc_ptr->slots[index].slot_num;
- tmp_slot->hotplug_slot = hp_slot_ptr;
-
- hp_slot_ptr->private = tmp_slot;
- rc = fillslotinfo(hp_slot_ptr);
+ rc = fillslotinfo(&tmp_slot->hotplug_slot);
if (rc)
goto error;
- rc = ibmphp_init_devno((struct slot **) &hp_slot_ptr->private);
+ rc = ibmphp_init_devno(&tmp_slot);
if (rc)
goto error;
- hp_slot_ptr->ops = &ibmphp_hotplug_slot_ops;
+ tmp_slot->hotplug_slot.ops = &ibmphp_hotplug_slot_ops;
// end of registering ibm slot with hotplug core
- list_add(&((struct slot *)(hp_slot_ptr->private))->ibm_slot_list, &ibmphp_slot_head);
+ list_add(&tmp_slot->ibm_slot_list, &ibmphp_slot_head);
}
print_bus_info();
@@ -944,7 +898,7 @@ static int __init ebda_rsrc_controller(void)
list_for_each_entry(tmp_slot, &ibmphp_slot_head, ibm_slot_list) {
snprintf(name, SLOT_NAME_SIZE, "%s", create_file_name(tmp_slot));
- pci_hp_register(tmp_slot->hotplug_slot,
+ pci_hp_register(&tmp_slot->hotplug_slot,
pci_find_bus(0, tmp_slot->bus), tmp_slot->device, name);
}
@@ -953,12 +907,8 @@ static int __init ebda_rsrc_controller(void)
return 0;
error:
- kfree(hp_slot_ptr->private);
+ kfree(tmp_slot);
error_no_slot:
- kfree(hp_slot_ptr->info);
-error_no_hp_info:
- kfree(hp_slot_ptr);
-error_no_hp_slot:
free_ebda_hpc(hpc_ptr);
error_no_hpc:
iounmap(io_mem);
diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c
index 90fde5f106d8..5ac31f683b85 100644
--- a/drivers/pci/hotplug/pci_hotplug_core.c
+++ b/drivers/pci/hotplug/pci_hotplug_core.c
@@ -49,15 +49,13 @@ static DEFINE_MUTEX(pci_hp_mutex);
#define GET_STATUS(name, type) \
static int get_##name(struct hotplug_slot *slot, type *value) \
{ \
- struct hotplug_slot_ops *ops = slot->ops; \
+ const struct hotplug_slot_ops *ops = slot->ops; \
int retval = 0; \
- if (!try_module_get(ops->owner)) \
+ if (!try_module_get(slot->owner)) \
return -ENODEV; \
if (ops->get_##name) \
retval = ops->get_##name(slot, value); \
- else \
- *value = slot->info->name; \
- module_put(ops->owner); \
+ module_put(slot->owner); \
return retval; \
}
@@ -90,7 +88,7 @@ static ssize_t power_write_file(struct pci_slot *pci_slot, const char *buf,
power = (u8)(lpower & 0xff);
dbg("power = %d\n", power);
- if (!try_module_get(slot->ops->owner)) {
+ if (!try_module_get(slot->owner)) {
retval = -ENODEV;
goto exit;
}
@@ -109,7 +107,7 @@ static ssize_t power_write_file(struct pci_slot *pci_slot, const char *buf,
err("Illegal value specified for power\n");
retval = -EINVAL;
}
- module_put(slot->ops->owner);
+ module_put(slot->owner);
exit:
if (retval)
@@ -138,7 +136,8 @@ static ssize_t attention_read_file(struct pci_slot *pci_slot, char *buf)
static ssize_t attention_write_file(struct pci_slot *pci_slot, const char *buf,
size_t count)
{
- struct hotplug_slot_ops *ops = pci_slot->hotplug->ops;
+ struct hotplug_slot *slot = pci_slot->hotplug;
+ const struct hotplug_slot_ops *ops = slot->ops;
unsigned long lattention;
u8 attention;
int retval = 0;
@@ -147,13 +146,13 @@ static ssize_t attention_write_file(struct pci_slot *pci_slot, const char *buf,
attention = (u8)(lattention & 0xff);
dbg(" - attention = %d\n", attention);
- if (!try_module_get(ops->owner)) {
+ if (!try_module_get(slot->owner)) {
retval = -ENODEV;
goto exit;
}
if (ops->set_attention_status)
- retval = ops->set_attention_status(pci_slot->hotplug, attention);
- module_put(ops->owner);
+ retval = ops->set_attention_status(slot, attention);
+ module_put(slot->owner);
exit:
if (retval)
@@ -213,13 +212,13 @@ static ssize_t test_write_file(struct pci_slot *pci_slot, const char *buf,
test = (u32)(ltest & 0xffffffff);
dbg("test = %d\n", test);
- if (!try_module_get(slot->ops->owner)) {
+ if (!try_module_get(slot->owner)) {
retval = -ENODEV;
goto exit;
}
if (slot->ops->hardware_test)
retval = slot->ops->hardware_test(slot, test);
- module_put(slot->ops->owner);
+ module_put(slot->owner);
exit:
if (retval)
@@ -444,11 +443,11 @@ int __pci_hp_initialize(struct hotplug_slot *slot, struct pci_bus *bus,
if (slot == NULL)
return -ENODEV;
- if ((slot->info == NULL) || (slot->ops == NULL))
+ if (slot->ops == NULL)
return -EINVAL;
- slot->ops->owner = owner;
- slot->ops->mod_name = mod_name;
+ slot->owner = owner;
+ slot->mod_name = mod_name;
/*
* No problems if we call this interface from both ACPI_PCI_SLOT
@@ -559,28 +558,6 @@ void pci_hp_destroy(struct hotplug_slot *slot)
}
EXPORT_SYMBOL_GPL(pci_hp_destroy);
-/**
- * pci_hp_change_slot_info - changes the slot's information structure in the core
- * @slot: pointer to the slot whose info has changed
- * @info: pointer to the info copy into the slot's info structure
- *
- * @slot must have been registered with the pci
- * hotplug subsystem previously with a call to pci_hp_register().
- *
- * Returns 0 if successful, anything else for an error.
- */
-int pci_hp_change_slot_info(struct hotplug_slot *slot,
- struct hotplug_slot_info *info)
-{
- if (!slot || !info)
- return -ENODEV;
-
- memcpy(slot->info, info, sizeof(struct hotplug_slot_info));
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(pci_hp_change_slot_info);
-
static int __init pci_hotplug_init(void)
{
int result;
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index 811cf83f956d..506e1d923a1f 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -19,7 +19,6 @@
#include <linux/pci.h>
#include <linux/pci_hotplug.h>
#include <linux/delay.h>
-#include <linux/sched/signal.h> /* signal_pending() */
#include <linux/mutex.h>
#include <linux/rwsem.h>
#include <linux/workqueue.h>
@@ -60,71 +59,63 @@ do { \
#define SLOT_NAME_SIZE 10
/**
- * struct slot - PCIe hotplug slot
- * @state: current state machine position
- * @ctrl: pointer to the slot's controller structure
- * @hotplug_slot: pointer to the structure registered with the PCI hotplug core
- * @work: work item to turn the slot on or off after 5 seconds in response to
- * an Attention Button press
- * @lock: protects reads and writes of @state;
- * protects scheduling, execution and cancellation of @work
- */
-struct slot {
- u8 state;
- struct controller *ctrl;
- struct hotplug_slot *hotplug_slot;
- struct delayed_work work;
- struct mutex lock;
-};
-
-/**
* struct controller - PCIe hotplug controller
- * @ctrl_lock: serializes writes to the Slot Control register
* @pcie: pointer to the controller's PCIe port service device
- * @reset_lock: prevents access to the Data Link Layer Link Active bit in the
- * Link Status register and to the Presence Detect State bit in the Slot
- * Status register during a slot reset which may cause them to flap
- * @slot: pointer to the controller's slot structure
- * @queue: wait queue to wake up on reception of a Command Completed event,
- * used for synchronous writes to the Slot Control register
* @slot_cap: cached copy of the Slot Capabilities register
* @slot_ctrl: cached copy of the Slot Control register
- * @poll_thread: thread to poll for slot events if no IRQ is available,
- * enabled with pciehp_poll_mode module parameter
+ * @ctrl_lock: serializes writes to the Slot Control register
* @cmd_started: jiffies when the Slot Control register was last written;
* the next write is allowed 1 second later, absent a Command Completed
* interrupt (PCIe r4.0, sec 6.7.3.2)
* @cmd_busy: flag set on Slot Control register write, cleared by IRQ handler
* on reception of a Command Completed event
- * @link_active_reporting: cached copy of Data Link Layer Link Active Reporting
- * Capable bit in Link Capabilities register; if this bit is zero, the
- * Data Link Layer Link Active bit in the Link Status register will never
- * be set and the driver is thus confined to wait 1 second before assuming
- * the link to a hotplugged device is up and accessing it
+ * @queue: wait queue to wake up on reception of a Command Completed event,
+ * used for synchronous writes to the Slot Control register
+ * @pending_events: used by the IRQ handler to save events retrieved from the
+ * Slot Status register for later consumption by the IRQ thread
* @notification_enabled: whether the IRQ was requested successfully
* @power_fault_detected: whether a power fault was detected by the hardware
* that has not yet been cleared by the user
- * @pending_events: used by the IRQ handler to save events retrieved from the
- * Slot Status register for later consumption by the IRQ thread
+ * @poll_thread: thread to poll for slot events if no IRQ is available,
+ * enabled with pciehp_poll_mode module parameter
+ * @state: current state machine position
+ * @state_lock: protects reads and writes of @state;
+ * protects scheduling, execution and cancellation of @button_work
+ * @button_work: work item to turn the slot on or off after 5 seconds
+ * in response to an Attention Button press
+ * @hotplug_slot: structure registered with the PCI hotplug core
+ * @reset_lock: prevents access to the Data Link Layer Link Active bit in the
+ * Link Status register and to the Presence Detect State bit in the Slot
+ * Status register during a slot reset which may cause them to flap
* @request_result: result of last user request submitted to the IRQ thread
* @requester: wait queue to wake up on completion of user request,
* used for synchronous slot enable/disable request via sysfs
+ *
+ * PCIe hotplug has a 1:1 relationship between controller and slot, hence
+ * unlike other drivers, the two aren't represented by separate structures.
*/
struct controller {
- struct mutex ctrl_lock;
struct pcie_device *pcie;
- struct rw_semaphore reset_lock;
- struct slot *slot;
- wait_queue_head_t queue;
- u32 slot_cap;
- u16 slot_ctrl;
- struct task_struct *poll_thread;
- unsigned long cmd_started; /* jiffies */
+
+ u32 slot_cap; /* capabilities and quirks */
+
+ u16 slot_ctrl; /* control register access */
+ struct mutex ctrl_lock;
+ unsigned long cmd_started;
unsigned int cmd_busy:1;
- unsigned int link_active_reporting:1;
+ wait_queue_head_t queue;
+
+ atomic_t pending_events; /* event handling */
unsigned int notification_enabled:1;
unsigned int power_fault_detected;
- atomic_t pending_events;
+ struct task_struct *poll_thread;
+
+ u8 state; /* state machine */
+ struct mutex state_lock;
+ struct delayed_work button_work;
+
+ struct hotplug_slot hotplug_slot; /* hotplug core interface */
+ struct rw_semaphore reset_lock;
int request_result;
wait_queue_head_t requester;
};
@@ -174,42 +165,50 @@ struct controller {
#define NO_CMD_CMPL(ctrl) ((ctrl)->slot_cap & PCI_EXP_SLTCAP_NCCS)
#define PSN(ctrl) (((ctrl)->slot_cap & PCI_EXP_SLTCAP_PSN) >> 19)
-int pciehp_sysfs_enable_slot(struct slot *slot);
-int pciehp_sysfs_disable_slot(struct slot *slot);
void pciehp_request(struct controller *ctrl, int action);
-void pciehp_handle_button_press(struct slot *slot);
-void pciehp_handle_disable_request(struct slot *slot);
-void pciehp_handle_presence_or_link_change(struct slot *slot, u32 events);
-int pciehp_configure_device(struct slot *p_slot);
-void pciehp_unconfigure_device(struct slot *p_slot);
+void pciehp_handle_button_press(struct controller *ctrl);
+void pciehp_handle_disable_request(struct controller *ctrl);
+void pciehp_handle_presence_or_link_change(struct controller *ctrl, u32 events);
+int pciehp_configure_device(struct controller *ctrl);
+void pciehp_unconfigure_device(struct controller *ctrl, bool presence);
void pciehp_queue_pushbutton_work(struct work_struct *work);
struct controller *pcie_init(struct pcie_device *dev);
int pcie_init_notification(struct controller *ctrl);
void pcie_shutdown_notification(struct controller *ctrl);
void pcie_clear_hotplug_events(struct controller *ctrl);
-int pciehp_power_on_slot(struct slot *slot);
-void pciehp_power_off_slot(struct slot *slot);
-void pciehp_get_power_status(struct slot *slot, u8 *status);
-void pciehp_get_attention_status(struct slot *slot, u8 *status);
-
-void pciehp_set_attention_status(struct slot *slot, u8 status);
-void pciehp_get_latch_status(struct slot *slot, u8 *status);
-void pciehp_get_adapter_status(struct slot *slot, u8 *status);
-int pciehp_query_power_fault(struct slot *slot);
-void pciehp_green_led_on(struct slot *slot);
-void pciehp_green_led_off(struct slot *slot);
-void pciehp_green_led_blink(struct slot *slot);
+void pcie_enable_interrupt(struct controller *ctrl);
+void pcie_disable_interrupt(struct controller *ctrl);
+int pciehp_power_on_slot(struct controller *ctrl);
+void pciehp_power_off_slot(struct controller *ctrl);
+void pciehp_get_power_status(struct controller *ctrl, u8 *status);
+
+void pciehp_set_attention_status(struct controller *ctrl, u8 status);
+void pciehp_get_latch_status(struct controller *ctrl, u8 *status);
+int pciehp_query_power_fault(struct controller *ctrl);
+void pciehp_green_led_on(struct controller *ctrl);
+void pciehp_green_led_off(struct controller *ctrl);
+void pciehp_green_led_blink(struct controller *ctrl);
+bool pciehp_card_present(struct controller *ctrl);
+bool pciehp_card_present_or_link_active(struct controller *ctrl);
int pciehp_check_link_status(struct controller *ctrl);
bool pciehp_check_link_active(struct controller *ctrl);
void pciehp_release_ctrl(struct controller *ctrl);
-int pciehp_reset_slot(struct slot *slot, int probe);
+int pciehp_sysfs_enable_slot(struct hotplug_slot *hotplug_slot);
+int pciehp_sysfs_disable_slot(struct hotplug_slot *hotplug_slot);
+int pciehp_reset_slot(struct hotplug_slot *hotplug_slot, int probe);
+int pciehp_get_attention_status(struct hotplug_slot *hotplug_slot, u8 *status);
int pciehp_set_raw_indicator_status(struct hotplug_slot *h_slot, u8 status);
int pciehp_get_raw_indicator_status(struct hotplug_slot *h_slot, u8 *status);
-static inline const char *slot_name(struct slot *slot)
+static inline const char *slot_name(struct controller *ctrl)
+{
+ return hotplug_slot_name(&ctrl->hotplug_slot);
+}
+
+static inline struct controller *to_ctrl(struct hotplug_slot *hotplug_slot)
{
- return hotplug_slot_name(slot->hotplug_slot);
+ return container_of(hotplug_slot, struct controller, hotplug_slot);
}
#endif /* _PCIEHP_H */
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index ec48c9433ae5..fc5366b50e95 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -23,8 +23,6 @@
#include <linux/types.h>
#include <linux/pci.h>
#include "pciehp.h"
-#include <linux/interrupt.h>
-#include <linux/time.h>
#include "../pci.h"
@@ -47,45 +45,30 @@ MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds");
#define PCIE_MODULE_NAME "pciehp"
static int set_attention_status(struct hotplug_slot *slot, u8 value);
-static int enable_slot(struct hotplug_slot *slot);
-static int disable_slot(struct hotplug_slot *slot);
static int get_power_status(struct hotplug_slot *slot, u8 *value);
-static int get_attention_status(struct hotplug_slot *slot, u8 *value);
static int get_latch_status(struct hotplug_slot *slot, u8 *value);
static int get_adapter_status(struct hotplug_slot *slot, u8 *value);
-static int reset_slot(struct hotplug_slot *slot, int probe);
static int init_slot(struct controller *ctrl)
{
- struct slot *slot = ctrl->slot;
- struct hotplug_slot *hotplug = NULL;
- struct hotplug_slot_info *info = NULL;
- struct hotplug_slot_ops *ops = NULL;
+ struct hotplug_slot_ops *ops;
char name[SLOT_NAME_SIZE];
- int retval = -ENOMEM;
-
- hotplug = kzalloc(sizeof(*hotplug), GFP_KERNEL);
- if (!hotplug)
- goto out;
-
- info = kzalloc(sizeof(*info), GFP_KERNEL);
- if (!info)
- goto out;
+ int retval;
/* Setup hotplug slot ops */
ops = kzalloc(sizeof(*ops), GFP_KERNEL);
if (!ops)
- goto out;
+ return -ENOMEM;
- ops->enable_slot = enable_slot;
- ops->disable_slot = disable_slot;
+ ops->enable_slot = pciehp_sysfs_enable_slot;
+ ops->disable_slot = pciehp_sysfs_disable_slot;
ops->get_power_status = get_power_status;
ops->get_adapter_status = get_adapter_status;
- ops->reset_slot = reset_slot;
+ ops->reset_slot = pciehp_reset_slot;
if (MRL_SENS(ctrl))
ops->get_latch_status = get_latch_status;
if (ATTN_LED(ctrl)) {
- ops->get_attention_status = get_attention_status;
+ ops->get_attention_status = pciehp_get_attention_status;
ops->set_attention_status = set_attention_status;
} else if (ctrl->pcie->port->hotplug_user_indicators) {
ops->get_attention_status = pciehp_get_raw_indicator_status;
@@ -93,33 +76,24 @@ static int init_slot(struct controller *ctrl)
}
/* register this slot with the hotplug pci core */
- hotplug->info = info;
- hotplug->private = slot;
- hotplug->ops = ops;
- slot->hotplug_slot = hotplug;
+ ctrl->hotplug_slot.ops = ops;
snprintf(name, SLOT_NAME_SIZE, "%u", PSN(ctrl));
- retval = pci_hp_initialize(hotplug,
+ retval = pci_hp_initialize(&ctrl->hotplug_slot,
ctrl->pcie->port->subordinate, 0, name);
- if (retval)
- ctrl_err(ctrl, "pci_hp_initialize failed: error %d\n", retval);
-out:
if (retval) {
+ ctrl_err(ctrl, "pci_hp_initialize failed: error %d\n", retval);
kfree(ops);
- kfree(info);
- kfree(hotplug);
}
return retval;
}
static void cleanup_slot(struct controller *ctrl)
{
- struct hotplug_slot *hotplug_slot = ctrl->slot->hotplug_slot;
+ struct hotplug_slot *hotplug_slot = &ctrl->hotplug_slot;
pci_hp_destroy(hotplug_slot);
kfree(hotplug_slot->ops);
- kfree(hotplug_slot->info);
- kfree(hotplug_slot);
}
/*
@@ -127,79 +101,48 @@ static void cleanup_slot(struct controller *ctrl)
*/
static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
{
- struct slot *slot = hotplug_slot->private;
- struct pci_dev *pdev = slot->ctrl->pcie->port;
+ struct controller *ctrl = to_ctrl(hotplug_slot);
+ struct pci_dev *pdev = ctrl->pcie->port;
pci_config_pm_runtime_get(pdev);
- pciehp_set_attention_status(slot, status);
+ pciehp_set_attention_status(ctrl, status);
pci_config_pm_runtime_put(pdev);
return 0;
}
-
-static int enable_slot(struct hotplug_slot *hotplug_slot)
-{
- struct slot *slot = hotplug_slot->private;
-
- return pciehp_sysfs_enable_slot(slot);
-}
-
-
-static int disable_slot(struct hotplug_slot *hotplug_slot)
-{
- struct slot *slot = hotplug_slot->private;
-
- return pciehp_sysfs_disable_slot(slot);
-}
-
static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
{
- struct slot *slot = hotplug_slot->private;
- struct pci_dev *pdev = slot->ctrl->pcie->port;
+ struct controller *ctrl = to_ctrl(hotplug_slot);
+ struct pci_dev *pdev = ctrl->pcie->port;
pci_config_pm_runtime_get(pdev);
- pciehp_get_power_status(slot, value);
+ pciehp_get_power_status(ctrl, value);
pci_config_pm_runtime_put(pdev);
return 0;
}
-static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
-{
- struct slot *slot = hotplug_slot->private;
-
- pciehp_get_attention_status(slot, value);
- return 0;
-}
-
static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
{
- struct slot *slot = hotplug_slot->private;
- struct pci_dev *pdev = slot->ctrl->pcie->port;
+ struct controller *ctrl = to_ctrl(hotplug_slot);
+ struct pci_dev *pdev = ctrl->pcie->port;
pci_config_pm_runtime_get(pdev);
- pciehp_get_latch_status(slot, value);
+ pciehp_get_latch_status(ctrl, value);
pci_config_pm_runtime_put(pdev);
return 0;
}
static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
{
- struct slot *slot = hotplug_slot->private;
- struct pci_dev *pdev = slot->ctrl->pcie->port;
+ struct controller *ctrl = to_ctrl(hotplug_slot);
+ struct pci_dev *pdev = ctrl->pcie->port;
pci_config_pm_runtime_get(pdev);
- pciehp_get_adapter_status(slot, value);
+ *value = pciehp_card_present_or_link_active(ctrl);
pci_config_pm_runtime_put(pdev);
return 0;
}
-static int reset_slot(struct hotplug_slot *hotplug_slot, int probe)
-{
- struct slot *slot = hotplug_slot->private;
-
- return pciehp_reset_slot(slot, probe);
-}
-
/**
* pciehp_check_presence() - synthesize event if presence has changed
*
@@ -212,20 +155,19 @@ static int reset_slot(struct hotplug_slot *hotplug_slot, int probe)
*/
static void pciehp_check_presence(struct controller *ctrl)
{
- struct slot *slot = ctrl->slot;
- u8 occupied;
+ bool occupied;
down_read(&ctrl->reset_lock);
- mutex_lock(&slot->lock);
+ mutex_lock(&ctrl->state_lock);
- pciehp_get_adapter_status(slot, &occupied);
- if ((occupied && (slot->state == OFF_STATE ||
- slot->state == BLINKINGON_STATE)) ||
- (!occupied && (slot->state == ON_STATE ||
- slot->state == BLINKINGOFF_STATE)))
+ occupied = pciehp_card_present_or_link_active(ctrl);
+ if ((occupied && (ctrl->state == OFF_STATE ||
+ ctrl->state == BLINKINGON_STATE)) ||
+ (!occupied && (ctrl->state == ON_STATE ||
+ ctrl->state == BLINKINGOFF_STATE)))
pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC);
- mutex_unlock(&slot->lock);
+ mutex_unlock(&ctrl->state_lock);
up_read(&ctrl->reset_lock);
}
@@ -233,7 +175,6 @@ static int pciehp_probe(struct pcie_device *dev)
{
int rc;
struct controller *ctrl;
- struct slot *slot;
/* If this is not a "hotplug" service, we have no business here. */
if (dev->service != PCIE_PORT_SERVICE_HP)
@@ -271,8 +212,7 @@ static int pciehp_probe(struct pcie_device *dev)
}
/* Publish to user space */
- slot = ctrl->slot;
- rc = pci_hp_add(slot->hotplug_slot);
+ rc = pci_hp_add(&ctrl->hotplug_slot);
if (rc) {
ctrl_err(ctrl, "Publication to user space failed (%d)\n", rc);
goto err_out_shutdown_notification;
@@ -295,29 +235,43 @@ static void pciehp_remove(struct pcie_device *dev)
{
struct controller *ctrl = get_service_data(dev);
- pci_hp_del(ctrl->slot->hotplug_slot);
+ pci_hp_del(&ctrl->hotplug_slot);
pcie_shutdown_notification(ctrl);
cleanup_slot(ctrl);
pciehp_release_ctrl(ctrl);
}
#ifdef CONFIG_PM
+static bool pme_is_native(struct pcie_device *dev)
+{
+ const struct pci_host_bridge *host;
+
+ host = pci_find_host_bridge(dev->port->bus);
+ return pcie_ports_native || host->native_pme;
+}
+
static int pciehp_suspend(struct pcie_device *dev)
{
+ /*
+ * Disable hotplug interrupt so that it does not trigger
+ * immediately when the downstream link goes down.
+ */
+ if (pme_is_native(dev))
+ pcie_disable_interrupt(get_service_data(dev));
+
return 0;
}
static int pciehp_resume_noirq(struct pcie_device *dev)
{
struct controller *ctrl = get_service_data(dev);
- struct slot *slot = ctrl->slot;
/* pci_restore_state() just wrote to the Slot Control register */
ctrl->cmd_started = jiffies;
ctrl->cmd_busy = true;
/* clear spurious events from rediscovery of inserted card */
- if (slot->state == ON_STATE || slot->state == BLINKINGOFF_STATE)
+ if (ctrl->state == ON_STATE || ctrl->state == BLINKINGOFF_STATE)
pcie_clear_hotplug_events(ctrl);
return 0;
@@ -327,10 +281,29 @@ static int pciehp_resume(struct pcie_device *dev)
{
struct controller *ctrl = get_service_data(dev);
+ if (pme_is_native(dev))
+ pcie_enable_interrupt(ctrl);
+
pciehp_check_presence(ctrl);
return 0;
}
+
+static int pciehp_runtime_resume(struct pcie_device *dev)
+{
+ struct controller *ctrl = get_service_data(dev);
+
+ /* pci_restore_state() just wrote to the Slot Control register */
+ ctrl->cmd_started = jiffies;
+ ctrl->cmd_busy = true;
+
+ /* clear spurious events from rediscovery of inserted card */
+ if ((ctrl->state == ON_STATE || ctrl->state == BLINKINGOFF_STATE) &&
+ pme_is_native(dev))
+ pcie_clear_hotplug_events(ctrl);
+
+ return pciehp_resume(dev);
+}
#endif /* PM */
static struct pcie_port_service_driver hpdriver_portdrv = {
@@ -345,10 +318,12 @@ static struct pcie_port_service_driver hpdriver_portdrv = {
.suspend = pciehp_suspend,
.resume_noirq = pciehp_resume_noirq,
.resume = pciehp_resume,
+ .runtime_suspend = pciehp_suspend,
+ .runtime_resume = pciehp_runtime_resume,
#endif /* PM */
};
-static int __init pcied_init(void)
+int __init pcie_hp_init(void)
{
int retval = 0;
@@ -359,4 +334,3 @@ static int __init pcied_init(void)
return retval;
}
-device_initcall(pcied_init);
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index da7c72372ffc..3f3df4c29f6e 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -13,24 +13,24 @@
*
*/
-#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
-#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/pci.h>
-#include "../pci.h"
#include "pciehp.h"
/* The following routines constitute the bulk of the
hotplug controller logic
*/
-static void set_slot_off(struct controller *ctrl, struct slot *pslot)
+#define SAFE_REMOVAL true
+#define SURPRISE_REMOVAL false
+
+static void set_slot_off(struct controller *ctrl)
{
/* turn off slot, turn on Amber LED, turn off Green LED if supported*/
if (POWER_CTRL(ctrl)) {
- pciehp_power_off_slot(pslot);
+ pciehp_power_off_slot(ctrl);
/*
* After turning power off, we must wait for at least 1 second
@@ -40,31 +40,30 @@ static void set_slot_off(struct controller *ctrl, struct slot *pslot)
msleep(1000);
}
- pciehp_green_led_off(pslot);
- pciehp_set_attention_status(pslot, 1);
+ pciehp_green_led_off(ctrl);
+ pciehp_set_attention_status(ctrl, 1);
}
/**
* board_added - Called after a board has been added to the system.
- * @p_slot: &slot where board is added
+ * @ctrl: PCIe hotplug controller where board is added
*
* Turns power on for the board.
* Configures board.
*/
-static int board_added(struct slot *p_slot)
+static int board_added(struct controller *ctrl)
{
int retval = 0;
- struct controller *ctrl = p_slot->ctrl;
struct pci_bus *parent = ctrl->pcie->port->subordinate;
if (POWER_CTRL(ctrl)) {
/* Power on slot */
- retval = pciehp_power_on_slot(p_slot);
+ retval = pciehp_power_on_slot(ctrl);
if (retval)
return retval;
}
- pciehp_green_led_blink(p_slot);
+ pciehp_green_led_blink(ctrl);
/* Check link training status */
retval = pciehp_check_link_status(ctrl);
@@ -74,13 +73,13 @@ static int board_added(struct slot *p_slot)
}
/* Check for a power fault */
- if (ctrl->power_fault_detected || pciehp_query_power_fault(p_slot)) {
- ctrl_err(ctrl, "Slot(%s): Power fault\n", slot_name(p_slot));
+ if (ctrl->power_fault_detected || pciehp_query_power_fault(ctrl)) {
+ ctrl_err(ctrl, "Slot(%s): Power fault\n", slot_name(ctrl));
retval = -EIO;
goto err_exit;
}
- retval = pciehp_configure_device(p_slot);
+ retval = pciehp_configure_device(ctrl);
if (retval) {
if (retval != -EEXIST) {
ctrl_err(ctrl, "Cannot add device at %04x:%02x:00\n",
@@ -89,27 +88,26 @@ static int board_added(struct slot *p_slot)
}
}
- pciehp_green_led_on(p_slot);
- pciehp_set_attention_status(p_slot, 0);
+ pciehp_green_led_on(ctrl);
+ pciehp_set_attention_status(ctrl, 0);
return 0;
err_exit:
- set_slot_off(ctrl, p_slot);
+ set_slot_off(ctrl);
return retval;
}
/**
* remove_board - Turns off slot and LEDs
- * @p_slot: slot where board is being removed
+ * @ctrl: PCIe hotplug controller where board is being removed
+ * @safe_removal: whether the board is safely removed (versus surprise removed)
*/
-static void remove_board(struct slot *p_slot)
+static void remove_board(struct controller *ctrl, bool safe_removal)
{
- struct controller *ctrl = p_slot->ctrl;
-
- pciehp_unconfigure_device(p_slot);
+ pciehp_unconfigure_device(ctrl, safe_removal);
if (POWER_CTRL(ctrl)) {
- pciehp_power_off_slot(p_slot);
+ pciehp_power_off_slot(ctrl);
/*
* After turning power off, we must wait for at least 1 second
@@ -120,11 +118,11 @@ static void remove_board(struct slot *p_slot)
}
/* turn off Green LED */
- pciehp_green_led_off(p_slot);
+ pciehp_green_led_off(ctrl);
}
-static int pciehp_enable_slot(struct slot *slot);
-static int pciehp_disable_slot(struct slot *slot);
+static int pciehp_enable_slot(struct controller *ctrl);
+static int pciehp_disable_slot(struct controller *ctrl, bool safe_removal);
void pciehp_request(struct controller *ctrl, int action)
{
@@ -135,11 +133,11 @@ void pciehp_request(struct controller *ctrl, int action)
void pciehp_queue_pushbutton_work(struct work_struct *work)
{
- struct slot *p_slot = container_of(work, struct slot, work.work);
- struct controller *ctrl = p_slot->ctrl;
+ struct controller *ctrl = container_of(work, struct controller,
+ button_work.work);
- mutex_lock(&p_slot->lock);
- switch (p_slot->state) {
+ mutex_lock(&ctrl->state_lock);
+ switch (ctrl->state) {
case BLINKINGOFF_STATE:
pciehp_request(ctrl, DISABLE_SLOT);
break;
@@ -149,30 +147,28 @@ void pciehp_queue_pushbutton_work(struct work_struct *work)
default:
break;
}
- mutex_unlock(&p_slot->lock);
+ mutex_unlock(&ctrl->state_lock);
}
-void pciehp_handle_button_press(struct slot *p_slot)
+void pciehp_handle_button_press(struct controller *ctrl)
{
- struct controller *ctrl = p_slot->ctrl;
-
- mutex_lock(&p_slot->lock);
- switch (p_slot->state) {
+ mutex_lock(&ctrl->state_lock);
+ switch (ctrl->state) {
case OFF_STATE:
case ON_STATE:
- if (p_slot->state == ON_STATE) {
- p_slot->state = BLINKINGOFF_STATE;
+ if (ctrl->state == ON_STATE) {
+ ctrl->state = BLINKINGOFF_STATE;
ctrl_info(ctrl, "Slot(%s): Powering off due to button press\n",
- slot_name(p_slot));
+ slot_name(ctrl));
} else {
- p_slot->state = BLINKINGON_STATE;
+ ctrl->state = BLINKINGON_STATE;
ctrl_info(ctrl, "Slot(%s) Powering on due to button press\n",
- slot_name(p_slot));
+ slot_name(ctrl));
}
/* blink green LED and turn off amber */
- pciehp_green_led_blink(p_slot);
- pciehp_set_attention_status(p_slot, 0);
- schedule_delayed_work(&p_slot->work, 5 * HZ);
+ pciehp_green_led_blink(ctrl);
+ pciehp_set_attention_status(ctrl, 0);
+ schedule_delayed_work(&ctrl->button_work, 5 * HZ);
break;
case BLINKINGOFF_STATE:
case BLINKINGON_STATE:
@@ -181,197 +177,184 @@ void pciehp_handle_button_press(struct slot *p_slot)
* press the attention again before the 5 sec. limit
* expires to cancel hot-add or hot-remove
*/
- ctrl_info(ctrl, "Slot(%s): Button cancel\n", slot_name(p_slot));
- cancel_delayed_work(&p_slot->work);
- if (p_slot->state == BLINKINGOFF_STATE) {
- p_slot->state = ON_STATE;
- pciehp_green_led_on(p_slot);
+ ctrl_info(ctrl, "Slot(%s): Button cancel\n", slot_name(ctrl));
+ cancel_delayed_work(&ctrl->button_work);
+ if (ctrl->state == BLINKINGOFF_STATE) {
+ ctrl->state = ON_STATE;
+ pciehp_green_led_on(ctrl);
} else {
- p_slot->state = OFF_STATE;
- pciehp_green_led_off(p_slot);
+ ctrl->state = OFF_STATE;
+ pciehp_green_led_off(ctrl);
}
- pciehp_set_attention_status(p_slot, 0);
+ pciehp_set_attention_status(ctrl, 0);
ctrl_info(ctrl, "Slot(%s): Action canceled due to button press\n",
- slot_name(p_slot));
+ slot_name(ctrl));
break;
default:
ctrl_err(ctrl, "Slot(%s): Ignoring invalid state %#x\n",
- slot_name(p_slot), p_slot->state);
+ slot_name(ctrl), ctrl->state);
break;
}
- mutex_unlock(&p_slot->lock);
+ mutex_unlock(&ctrl->state_lock);
}
-void pciehp_handle_disable_request(struct slot *slot)
+void pciehp_handle_disable_request(struct controller *ctrl)
{
- struct controller *ctrl = slot->ctrl;
-
- mutex_lock(&slot->lock);
- switch (slot->state) {
+ mutex_lock(&ctrl->state_lock);
+ switch (ctrl->state) {
case BLINKINGON_STATE:
case BLINKINGOFF_STATE:
- cancel_delayed_work(&slot->work);
+ cancel_delayed_work(&ctrl->button_work);
break;
}
- slot->state = POWEROFF_STATE;
- mutex_unlock(&slot->lock);
+ ctrl->state = POWEROFF_STATE;
+ mutex_unlock(&ctrl->state_lock);
- ctrl->request_result = pciehp_disable_slot(slot);
+ ctrl->request_result = pciehp_disable_slot(ctrl, SAFE_REMOVAL);
}
-void pciehp_handle_presence_or_link_change(struct slot *slot, u32 events)
+void pciehp_handle_presence_or_link_change(struct controller *ctrl, u32 events)
{
- struct controller *ctrl = slot->ctrl;
- bool link_active;
- u8 present;
+ bool present, link_active;
/*
* If the slot is on and presence or link has changed, turn it off.
* Even if it's occupied again, we cannot assume the card is the same.
*/
- mutex_lock(&slot->lock);
- switch (slot->state) {
+ mutex_lock(&ctrl->state_lock);
+ switch (ctrl->state) {
case BLINKINGOFF_STATE:
- cancel_delayed_work(&slot->work);
+ cancel_delayed_work(&ctrl->button_work);
/* fall through */
case ON_STATE:
- slot->state = POWEROFF_STATE;
- mutex_unlock(&slot->lock);
+ ctrl->state = POWEROFF_STATE;
+ mutex_unlock(&ctrl->state_lock);
if (events & PCI_EXP_SLTSTA_DLLSC)
ctrl_info(ctrl, "Slot(%s): Link Down\n",
- slot_name(slot));
+ slot_name(ctrl));
if (events & PCI_EXP_SLTSTA_PDC)
ctrl_info(ctrl, "Slot(%s): Card not present\n",
- slot_name(slot));
- pciehp_disable_slot(slot);
+ slot_name(ctrl));
+ pciehp_disable_slot(ctrl, SURPRISE_REMOVAL);
break;
default:
- mutex_unlock(&slot->lock);
+ mutex_unlock(&ctrl->state_lock);
break;
}
/* Turn the slot on if it's occupied or link is up */
- mutex_lock(&slot->lock);
- pciehp_get_adapter_status(slot, &present);
+ mutex_lock(&ctrl->state_lock);
+ present = pciehp_card_present(ctrl);
link_active = pciehp_check_link_active(ctrl);
if (!present && !link_active) {
- mutex_unlock(&slot->lock);
+ mutex_unlock(&ctrl->state_lock);
return;
}
- switch (slot->state) {
+ switch (ctrl->state) {
case BLINKINGON_STATE:
- cancel_delayed_work(&slot->work);
+ cancel_delayed_work(&ctrl->button_work);
/* fall through */
case OFF_STATE:
- slot->state = POWERON_STATE;
- mutex_unlock(&slot->lock);
+ ctrl->state = POWERON_STATE;
+ mutex_unlock(&ctrl->state_lock);
if (present)
ctrl_info(ctrl, "Slot(%s): Card present\n",
- slot_name(slot));
+ slot_name(ctrl));
if (link_active)
ctrl_info(ctrl, "Slot(%s): Link Up\n",
- slot_name(slot));
- ctrl->request_result = pciehp_enable_slot(slot);
+ slot_name(ctrl));
+ ctrl->request_result = pciehp_enable_slot(ctrl);
break;
default:
- mutex_unlock(&slot->lock);
+ mutex_unlock(&ctrl->state_lock);
break;
}
}
-static int __pciehp_enable_slot(struct slot *p_slot)
+static int __pciehp_enable_slot(struct controller *ctrl)
{
u8 getstatus = 0;
- struct controller *ctrl = p_slot->ctrl;
- pciehp_get_adapter_status(p_slot, &getstatus);
- if (!getstatus) {
- ctrl_info(ctrl, "Slot(%s): No adapter\n", slot_name(p_slot));
- return -ENODEV;
- }
- if (MRL_SENS(p_slot->ctrl)) {
- pciehp_get_latch_status(p_slot, &getstatus);
+ if (MRL_SENS(ctrl)) {
+ pciehp_get_latch_status(ctrl, &getstatus);
if (getstatus) {
ctrl_info(ctrl, "Slot(%s): Latch open\n",
- slot_name(p_slot));
+ slot_name(ctrl));
return -ENODEV;
}
}
- if (POWER_CTRL(p_slot->ctrl)) {
- pciehp_get_power_status(p_slot, &getstatus);
+ if (POWER_CTRL(ctrl)) {
+ pciehp_get_power_status(ctrl, &getstatus);
if (getstatus) {
ctrl_info(ctrl, "Slot(%s): Already enabled\n",
- slot_name(p_slot));
+ slot_name(ctrl));
return 0;
}
}
- return board_added(p_slot);
+ return board_added(ctrl);
}
-static int pciehp_enable_slot(struct slot *slot)
+static int pciehp_enable_slot(struct controller *ctrl)
{
- struct controller *ctrl = slot->ctrl;
int ret;
pm_runtime_get_sync(&ctrl->pcie->port->dev);
- ret = __pciehp_enable_slot(slot);
+ ret = __pciehp_enable_slot(ctrl);
if (ret && ATTN_BUTTN(ctrl))
- pciehp_green_led_off(slot); /* may be blinking */
+ pciehp_green_led_off(ctrl); /* may be blinking */
pm_runtime_put(&ctrl->pcie->port->dev);
- mutex_lock(&slot->lock);
- slot->state = ret ? OFF_STATE : ON_STATE;
- mutex_unlock(&slot->lock);
+ mutex_lock(&ctrl->state_lock);
+ ctrl->state = ret ? OFF_STATE : ON_STATE;
+ mutex_unlock(&ctrl->state_lock);
return ret;
}
-static int __pciehp_disable_slot(struct slot *p_slot)
+static int __pciehp_disable_slot(struct controller *ctrl, bool safe_removal)
{
u8 getstatus = 0;
- struct controller *ctrl = p_slot->ctrl;
- if (POWER_CTRL(p_slot->ctrl)) {
- pciehp_get_power_status(p_slot, &getstatus);
+ if (POWER_CTRL(ctrl)) {
+ pciehp_get_power_status(ctrl, &getstatus);
if (!getstatus) {
ctrl_info(ctrl, "Slot(%s): Already disabled\n",
- slot_name(p_slot));
+ slot_name(ctrl));
return -EINVAL;
}
}
- remove_board(p_slot);
+ remove_board(ctrl, safe_removal);
return 0;
}
-static int pciehp_disable_slot(struct slot *slot)
+static int pciehp_disable_slot(struct controller *ctrl, bool safe_removal)
{
- struct controller *ctrl = slot->ctrl;
int ret;
pm_runtime_get_sync(&ctrl->pcie->port->dev);
- ret = __pciehp_disable_slot(slot);
+ ret = __pciehp_disable_slot(ctrl, safe_removal);
pm_runtime_put(&ctrl->pcie->port->dev);
- mutex_lock(&slot->lock);
- slot->state = OFF_STATE;
- mutex_unlock(&slot->lock);
+ mutex_lock(&ctrl->state_lock);
+ ctrl->state = OFF_STATE;
+ mutex_unlock(&ctrl->state_lock);
return ret;
}
-int pciehp_sysfs_enable_slot(struct slot *p_slot)
+int pciehp_sysfs_enable_slot(struct hotplug_slot *hotplug_slot)
{
- struct controller *ctrl = p_slot->ctrl;
+ struct controller *ctrl = to_ctrl(hotplug_slot);
- mutex_lock(&p_slot->lock);
- switch (p_slot->state) {
+ mutex_lock(&ctrl->state_lock);
+ switch (ctrl->state) {
case BLINKINGON_STATE:
case OFF_STATE:
- mutex_unlock(&p_slot->lock);
+ mutex_unlock(&ctrl->state_lock);
/*
* The IRQ thread becomes a no-op if the user pulls out the
* card before the thread wakes up, so initialize to -ENODEV.
@@ -383,53 +366,53 @@ int pciehp_sysfs_enable_slot(struct slot *p_slot)
return ctrl->request_result;
case POWERON_STATE:
ctrl_info(ctrl, "Slot(%s): Already in powering on state\n",
- slot_name(p_slot));
+ slot_name(ctrl));
break;
case BLINKINGOFF_STATE:
case ON_STATE:
case POWEROFF_STATE:
ctrl_info(ctrl, "Slot(%s): Already enabled\n",
- slot_name(p_slot));
+ slot_name(ctrl));
break;
default:
ctrl_err(ctrl, "Slot(%s): Invalid state %#x\n",
- slot_name(p_slot), p_slot->state);
+ slot_name(ctrl), ctrl->state);
break;
}
- mutex_unlock(&p_slot->lock);
+ mutex_unlock(&ctrl->state_lock);
return -ENODEV;
}
-int pciehp_sysfs_disable_slot(struct slot *p_slot)
+int pciehp_sysfs_disable_slot(struct hotplug_slot *hotplug_slot)
{
- struct controller *ctrl = p_slot->ctrl;
+ struct controller *ctrl = to_ctrl(hotplug_slot);
- mutex_lock(&p_slot->lock);
- switch (p_slot->state) {
+ mutex_lock(&ctrl->state_lock);
+ switch (ctrl->state) {
case BLINKINGOFF_STATE:
case ON_STATE:
- mutex_unlock(&p_slot->lock);
+ mutex_unlock(&ctrl->state_lock);
pciehp_request(ctrl, DISABLE_SLOT);
wait_event(ctrl->requester,
!atomic_read(&ctrl->pending_events));
return ctrl->request_result;
case POWEROFF_STATE:
ctrl_info(ctrl, "Slot(%s): Already in powering off state\n",
- slot_name(p_slot));
+ slot_name(ctrl));
break;
case BLINKINGON_STATE:
case OFF_STATE:
case POWERON_STATE:
ctrl_info(ctrl, "Slot(%s): Already disabled\n",
- slot_name(p_slot));
+ slot_name(ctrl));
break;
default:
ctrl_err(ctrl, "Slot(%s): Invalid state %#x\n",
- slot_name(p_slot), p_slot->state);
+ slot_name(ctrl), ctrl->state);
break;
}
- mutex_unlock(&p_slot->lock);
+ mutex_unlock(&ctrl->state_lock);
return -ENODEV;
}
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index a938abdb41ce..7dd443aea5a5 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -13,15 +13,12 @@
*/
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/types.h>
-#include <linux/signal.h>
#include <linux/jiffies.h>
#include <linux/kthread.h>
#include <linux/pci.h>
#include <linux/pm_runtime.h>
#include <linux/interrupt.h>
-#include <linux/time.h>
#include <linux/slab.h>
#include "../pci.h"
@@ -43,7 +40,7 @@ static inline int pciehp_request_irq(struct controller *ctrl)
if (pciehp_poll_mode) {
ctrl->poll_thread = kthread_run(&pciehp_poll, ctrl,
"pciehp_poll-%s",
- slot_name(ctrl->slot));
+ slot_name(ctrl));
return PTR_ERR_OR_ZERO(ctrl->poll_thread);
}
@@ -217,13 +214,6 @@ bool pciehp_check_link_active(struct controller *ctrl)
return ret;
}
-static void pcie_wait_link_active(struct controller *ctrl)
-{
- struct pci_dev *pdev = ctrl_dev(ctrl);
-
- pcie_wait_for_link(pdev, true);
-}
-
static bool pci_bus_check_dev(struct pci_bus *bus, int devfn)
{
u32 l;
@@ -256,18 +246,9 @@ int pciehp_check_link_status(struct controller *ctrl)
bool found;
u16 lnk_status;
- /*
- * Data Link Layer Link Active Reporting must be capable for
- * hot-plug capable downstream port. But old controller might
- * not implement it. In this case, we wait for 1000 ms.
- */
- if (ctrl->link_active_reporting)
- pcie_wait_link_active(ctrl);
- else
- msleep(1000);
+ if (!pcie_wait_for_link(pdev, true))
+ return -1;
- /* wait 100ms before read pci conf, and try in 1s */
- msleep(100);
found = pci_bus_check_dev(ctrl->pcie->port->subordinate,
PCI_DEVFN(0, 0));
@@ -318,8 +299,8 @@ static int pciehp_link_enable(struct controller *ctrl)
int pciehp_get_raw_indicator_status(struct hotplug_slot *hotplug_slot,
u8 *status)
{
- struct slot *slot = hotplug_slot->private;
- struct pci_dev *pdev = ctrl_dev(slot->ctrl);
+ struct controller *ctrl = to_ctrl(hotplug_slot);
+ struct pci_dev *pdev = ctrl_dev(ctrl);
u16 slot_ctrl;
pci_config_pm_runtime_get(pdev);
@@ -329,9 +310,9 @@ int pciehp_get_raw_indicator_status(struct hotplug_slot *hotplug_slot,
return 0;
}
-void pciehp_get_attention_status(struct slot *slot, u8 *status)
+int pciehp_get_attention_status(struct hotplug_slot *hotplug_slot, u8 *status)
{
- struct controller *ctrl = slot->ctrl;
+ struct controller *ctrl = to_ctrl(hotplug_slot);
struct pci_dev *pdev = ctrl_dev(ctrl);
u16 slot_ctrl;
@@ -355,11 +336,12 @@ void pciehp_get_attention_status(struct slot *slot, u8 *status)
*status = 0xFF;
break;
}
+
+ return 0;
}
-void pciehp_get_power_status(struct slot *slot, u8 *status)
+void pciehp_get_power_status(struct controller *ctrl, u8 *status)
{
- struct controller *ctrl = slot->ctrl;
struct pci_dev *pdev = ctrl_dev(ctrl);
u16 slot_ctrl;
@@ -380,27 +362,41 @@ void pciehp_get_power_status(struct slot *slot, u8 *status)
}
}
-void pciehp_get_latch_status(struct slot *slot, u8 *status)
+void pciehp_get_latch_status(struct controller *ctrl, u8 *status)
{
- struct pci_dev *pdev = ctrl_dev(slot->ctrl);
+ struct pci_dev *pdev = ctrl_dev(ctrl);
u16 slot_status;
pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status);
*status = !!(slot_status & PCI_EXP_SLTSTA_MRLSS);
}
-void pciehp_get_adapter_status(struct slot *slot, u8 *status)
+bool pciehp_card_present(struct controller *ctrl)
{
- struct pci_dev *pdev = ctrl_dev(slot->ctrl);
+ struct pci_dev *pdev = ctrl_dev(ctrl);
u16 slot_status;
pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status);
- *status = !!(slot_status & PCI_EXP_SLTSTA_PDS);
+ return slot_status & PCI_EXP_SLTSTA_PDS;
}
-int pciehp_query_power_fault(struct slot *slot)
+/**
+ * pciehp_card_present_or_link_active() - whether given slot is occupied
+ * @ctrl: PCIe hotplug controller
+ *
+ * Unlike pciehp_card_present(), which determines presence solely from the
+ * Presence Detect State bit, this helper also returns true if the Link Active
+ * bit is set. This is a concession to broken hotplug ports which hardwire
+ * Presence Detect State to zero, such as Wilocity's [1ae9:0200].
+ */
+bool pciehp_card_present_or_link_active(struct controller *ctrl)
+{
+ return pciehp_card_present(ctrl) || pciehp_check_link_active(ctrl);
+}
+
+int pciehp_query_power_fault(struct controller *ctrl)
{
- struct pci_dev *pdev = ctrl_dev(slot->ctrl);
+ struct pci_dev *pdev = ctrl_dev(ctrl);
u16 slot_status;
pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status);
@@ -410,8 +406,7 @@ int pciehp_query_power_fault(struct slot *slot)
int pciehp_set_raw_indicator_status(struct hotplug_slot *hotplug_slot,
u8 status)
{
- struct slot *slot = hotplug_slot->private;
- struct controller *ctrl = slot->ctrl;
+ struct controller *ctrl = to_ctrl(hotplug_slot);
struct pci_dev *pdev = ctrl_dev(ctrl);
pci_config_pm_runtime_get(pdev);
@@ -421,9 +416,8 @@ int pciehp_set_raw_indicator_status(struct hotplug_slot *hotplug_slot,
return 0;
}
-void pciehp_set_attention_status(struct slot *slot, u8 value)
+void pciehp_set_attention_status(struct controller *ctrl, u8 value)
{
- struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
if (!ATTN_LED(ctrl))
@@ -447,10 +441,8 @@ void pciehp_set_attention_status(struct slot *slot, u8 value)
pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd);
}
-void pciehp_green_led_on(struct slot *slot)
+void pciehp_green_led_on(struct controller *ctrl)
{
- struct controller *ctrl = slot->ctrl;
-
if (!PWR_LED(ctrl))
return;
@@ -461,10 +453,8 @@ void pciehp_green_led_on(struct slot *slot)
PCI_EXP_SLTCTL_PWR_IND_ON);
}
-void pciehp_green_led_off(struct slot *slot)
+void pciehp_green_led_off(struct controller *ctrl)
{
- struct controller *ctrl = slot->ctrl;
-
if (!PWR_LED(ctrl))
return;
@@ -475,10 +465,8 @@ void pciehp_green_led_off(struct slot *slot)
PCI_EXP_SLTCTL_PWR_IND_OFF);
}
-void pciehp_green_led_blink(struct slot *slot)
+void pciehp_green_led_blink(struct controller *ctrl)
{
- struct controller *ctrl = slot->ctrl;
-
if (!PWR_LED(ctrl))
return;
@@ -489,9 +477,8 @@ void pciehp_green_led_blink(struct slot *slot)
PCI_EXP_SLTCTL_PWR_IND_BLINK);
}
-int pciehp_power_on_slot(struct slot *slot)
+int pciehp_power_on_slot(struct controller *ctrl)
{
- struct controller *ctrl = slot->ctrl;
struct pci_dev *pdev = ctrl_dev(ctrl);
u16 slot_status;
int retval;
@@ -515,10 +502,8 @@ int pciehp_power_on_slot(struct slot *slot)
return retval;
}
-void pciehp_power_off_slot(struct slot *slot)
+void pciehp_power_off_slot(struct controller *ctrl)
{
- struct controller *ctrl = slot->ctrl;
-
pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_OFF, PCI_EXP_SLTCTL_PCC);
ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL,
@@ -533,9 +518,11 @@ static irqreturn_t pciehp_isr(int irq, void *dev_id)
u16 status, events;
/*
- * Interrupts only occur in D3hot or shallower (PCIe r4.0, sec 6.7.3.4).
+ * Interrupts only occur in D3hot or shallower and only if enabled
+ * in the Slot Control register (PCIe r4.0, sec 6.7.3.4).
*/
- if (pdev->current_state == PCI_D3cold)
+ if (pdev->current_state == PCI_D3cold ||
+ (!(ctrl->slot_ctrl & PCI_EXP_SLTCTL_HPIE) && !pciehp_poll_mode))
return IRQ_NONE;
/*
@@ -616,7 +603,6 @@ static irqreturn_t pciehp_ist(int irq, void *dev_id)
{
struct controller *ctrl = (struct controller *)dev_id;
struct pci_dev *pdev = ctrl_dev(ctrl);
- struct slot *slot = ctrl->slot;
irqreturn_t ret;
u32 events;
@@ -642,16 +628,16 @@ static irqreturn_t pciehp_ist(int irq, void *dev_id)
/* Check Attention Button Pressed */
if (events & PCI_EXP_SLTSTA_ABP) {
ctrl_info(ctrl, "Slot(%s): Attention button pressed\n",
- slot_name(slot));
- pciehp_handle_button_press(slot);
+ slot_name(ctrl));
+ pciehp_handle_button_press(ctrl);
}
/* Check Power Fault Detected */
if ((events & PCI_EXP_SLTSTA_PFD) && !ctrl->power_fault_detected) {
ctrl->power_fault_detected = 1;
- ctrl_err(ctrl, "Slot(%s): Power fault\n", slot_name(slot));
- pciehp_set_attention_status(slot, 1);
- pciehp_green_led_off(slot);
+ ctrl_err(ctrl, "Slot(%s): Power fault\n", slot_name(ctrl));
+ pciehp_set_attention_status(ctrl, 1);
+ pciehp_green_led_off(ctrl);
}
/*
@@ -660,9 +646,9 @@ static irqreturn_t pciehp_ist(int irq, void *dev_id)
*/
down_read(&ctrl->reset_lock);
if (events & DISABLE_SLOT)
- pciehp_handle_disable_request(slot);
+ pciehp_handle_disable_request(ctrl);
else if (events & (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC))
- pciehp_handle_presence_or_link_change(slot, events);
+ pciehp_handle_presence_or_link_change(ctrl, events);
up_read(&ctrl->reset_lock);
pci_config_pm_runtime_put(pdev);
@@ -748,6 +734,16 @@ void pcie_clear_hotplug_events(struct controller *ctrl)
PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC);
}
+void pcie_enable_interrupt(struct controller *ctrl)
+{
+ pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_HPIE, PCI_EXP_SLTCTL_HPIE);
+}
+
+void pcie_disable_interrupt(struct controller *ctrl)
+{
+ pcie_write_cmd(ctrl, 0, PCI_EXP_SLTCTL_HPIE);
+}
+
/*
* pciehp has a 1:1 bus:slot relationship so we ultimately want a secondary
* bus reset of the bridge, but at the same time we want to ensure that it is
@@ -756,9 +752,9 @@ void pcie_clear_hotplug_events(struct controller *ctrl)
* momentarily, if we see that they could interfere. Also, clear any spurious
* events after.
*/
-int pciehp_reset_slot(struct slot *slot, int probe)
+int pciehp_reset_slot(struct hotplug_slot *hotplug_slot, int probe)
{
- struct controller *ctrl = slot->ctrl;
+ struct controller *ctrl = to_ctrl(hotplug_slot);
struct pci_dev *pdev = ctrl_dev(ctrl);
u16 stat_mask = 0, ctrl_mask = 0;
int rc;
@@ -808,34 +804,6 @@ void pcie_shutdown_notification(struct controller *ctrl)
}
}
-static int pcie_init_slot(struct controller *ctrl)
-{
- struct pci_bus *subordinate = ctrl_dev(ctrl)->subordinate;
- struct slot *slot;
-
- slot = kzalloc(sizeof(*slot), GFP_KERNEL);
- if (!slot)
- return -ENOMEM;
-
- down_read(&pci_bus_sem);
- slot->state = list_empty(&subordinate->devices) ? OFF_STATE : ON_STATE;
- up_read(&pci_bus_sem);
-
- slot->ctrl = ctrl;
- mutex_init(&slot->lock);
- INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work);
- ctrl->slot = slot;
- return 0;
-}
-
-static void pcie_cleanup_slot(struct controller *ctrl)
-{
- struct slot *slot = ctrl->slot;
-
- cancel_delayed_work_sync(&slot->work);
- kfree(slot);
-}
-
static inline void dbg_ctrl(struct controller *ctrl)
{
struct pci_dev *pdev = ctrl->pcie->port;
@@ -857,12 +825,13 @@ struct controller *pcie_init(struct pcie_device *dev)
{
struct controller *ctrl;
u32 slot_cap, link_cap;
- u8 occupied, poweron;
+ u8 poweron;
struct pci_dev *pdev = dev->port;
+ struct pci_bus *subordinate = pdev->subordinate;
ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
if (!ctrl)
- goto abort;
+ return NULL;
ctrl->pcie = dev;
pcie_capability_read_dword(pdev, PCI_EXP_SLTCAP, &slot_cap);
@@ -879,15 +848,19 @@ struct controller *pcie_init(struct pcie_device *dev)
ctrl->slot_cap = slot_cap;
mutex_init(&ctrl->ctrl_lock);
+ mutex_init(&ctrl->state_lock);
init_rwsem(&ctrl->reset_lock);
init_waitqueue_head(&ctrl->requester);
init_waitqueue_head(&ctrl->queue);
+ INIT_DELAYED_WORK(&ctrl->button_work, pciehp_queue_pushbutton_work);
dbg_ctrl(ctrl);
+ down_read(&pci_bus_sem);
+ ctrl->state = list_empty(&subordinate->devices) ? OFF_STATE : ON_STATE;
+ up_read(&pci_bus_sem);
+
/* Check if Data Link Layer Link Active Reporting is implemented */
pcie_capability_read_dword(pdev, PCI_EXP_LNKCAP, &link_cap);
- if (link_cap & PCI_EXP_LNKCAP_DLLLARC)
- ctrl->link_active_reporting = 1;
/* Clear all remaining event bits in Slot Status register. */
pcie_capability_write_word(pdev, PCI_EXP_SLTSTA,
@@ -909,33 +882,24 @@ struct controller *pcie_init(struct pcie_device *dev)
FLAG(link_cap, PCI_EXP_LNKCAP_DLLLARC),
pdev->broken_cmd_compl ? " (with Cmd Compl erratum)" : "");
- if (pcie_init_slot(ctrl))
- goto abort_ctrl;
-
/*
* If empty slot's power status is on, turn power off. The IRQ isn't
* requested yet, so avoid triggering a notification with this command.
*/
if (POWER_CTRL(ctrl)) {
- pciehp_get_adapter_status(ctrl->slot, &occupied);
- pciehp_get_power_status(ctrl->slot, &poweron);
- if (!occupied && poweron) {
+ pciehp_get_power_status(ctrl, &poweron);
+ if (!pciehp_card_present_or_link_active(ctrl) && poweron) {
pcie_disable_notification(ctrl);
- pciehp_power_off_slot(ctrl->slot);
+ pciehp_power_off_slot(ctrl);
}
}
return ctrl;
-
-abort_ctrl:
- kfree(ctrl);
-abort:
- return NULL;
}
void pciehp_release_ctrl(struct controller *ctrl)
{
- pcie_cleanup_slot(ctrl);
+ cancel_delayed_work_sync(&ctrl->button_work);
kfree(ctrl);
}
diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c
index 5c58c22e0c08..b9c1396db6fe 100644
--- a/drivers/pci/hotplug/pciehp_pci.c
+++ b/drivers/pci/hotplug/pciehp_pci.c
@@ -13,20 +13,26 @@
*
*/
-#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/pci.h>
#include "../pci.h"
#include "pciehp.h"
-int pciehp_configure_device(struct slot *p_slot)
+/**
+ * pciehp_configure_device() - enumerate PCI devices below a hotplug bridge
+ * @ctrl: PCIe hotplug controller
+ *
+ * Enumerate PCI devices below a hotplug bridge and add them to the system.
+ * Return 0 on success, %-EEXIST if the devices are already enumerated or
+ * %-ENODEV if enumeration failed.
+ */
+int pciehp_configure_device(struct controller *ctrl)
{
struct pci_dev *dev;
- struct pci_dev *bridge = p_slot->ctrl->pcie->port;
+ struct pci_dev *bridge = ctrl->pcie->port;
struct pci_bus *parent = bridge->subordinate;
int num, ret = 0;
- struct controller *ctrl = p_slot->ctrl;
pci_lock_rescan_remove();
@@ -62,17 +68,28 @@ int pciehp_configure_device(struct slot *p_slot)
return ret;
}
-void pciehp_unconfigure_device(struct slot *p_slot)
+/**
+ * pciehp_unconfigure_device() - remove PCI devices below a hotplug bridge
+ * @ctrl: PCIe hotplug controller
+ * @presence: whether the card is still present in the slot;
+ * true for safe removal via sysfs or an Attention Button press,
+ * false for surprise removal
+ *
+ * Unbind PCI devices below a hotplug bridge from their drivers and remove
+ * them from the system. Safely removed devices are quiesced. Surprise
+ * removed devices are marked as such to prevent further accesses.
+ */
+void pciehp_unconfigure_device(struct controller *ctrl, bool presence)
{
- u8 presence = 0;
struct pci_dev *dev, *temp;
- struct pci_bus *parent = p_slot->ctrl->pcie->port->subordinate;
+ struct pci_bus *parent = ctrl->pcie->port->subordinate;
u16 command;
- struct controller *ctrl = p_slot->ctrl;
ctrl_dbg(ctrl, "%s: domain:bus:dev = %04x:%02x:00\n",
__func__, pci_domain_nr(parent), parent->number);
- pciehp_get_adapter_status(p_slot, &presence);
+
+ if (!presence)
+ pci_walk_bus(parent, pci_dev_set_disconnected, NULL);
pci_lock_rescan_remove();
@@ -85,12 +102,6 @@ void pciehp_unconfigure_device(struct slot *p_slot)
list_for_each_entry_safe_reverse(dev, temp, &parent->devices,
bus_list) {
pci_dev_get(dev);
- if (!presence) {
- pci_dev_set_disconnected(dev, NULL);
- if (pci_has_subordinate(dev))
- pci_walk_bus(dev->subordinate,
- pci_dev_set_disconnected, NULL);
- }
pci_stop_and_remove_bus_device(dev);
/*
* Ensure that no new Requests will be generated from
diff --git a/drivers/pci/hotplug/pnv_php.c b/drivers/pci/hotplug/pnv_php.c
index 3276a5e4c430..6758fd7c382e 100644
--- a/drivers/pci/hotplug/pnv_php.c
+++ b/drivers/pci/hotplug/pnv_php.c
@@ -275,14 +275,13 @@ static int pnv_php_add_devtree(struct pnv_php_slot *php_slot)
goto free_fdt1;
}
- fdt = kzalloc(fdt_totalsize(fdt1), GFP_KERNEL);
+ fdt = kmemdup(fdt1, fdt_totalsize(fdt1), GFP_KERNEL);
if (!fdt) {
ret = -ENOMEM;
goto free_fdt1;
}
/* Unflatten device tree blob */
- memcpy(fdt, fdt1, fdt_totalsize(fdt1));
dt = of_fdt_unflatten_tree(fdt, php_slot->dn, NULL);
if (!dt) {
ret = -EINVAL;
@@ -328,10 +327,15 @@ out:
return ret;
}
+static inline struct pnv_php_slot *to_pnv_php_slot(struct hotplug_slot *slot)
+{
+ return container_of(slot, struct pnv_php_slot, slot);
+}
+
int pnv_php_set_slot_power_state(struct hotplug_slot *slot,
uint8_t state)
{
- struct pnv_php_slot *php_slot = slot->private;
+ struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
struct opal_msg msg;
int ret;
@@ -363,7 +367,7 @@ EXPORT_SYMBOL_GPL(pnv_php_set_slot_power_state);
static int pnv_php_get_power_state(struct hotplug_slot *slot, u8 *state)
{
- struct pnv_php_slot *php_slot = slot->private;
+ struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
uint8_t power_state = OPAL_PCI_SLOT_POWER_ON;
int ret;
@@ -378,7 +382,6 @@ static int pnv_php_get_power_state(struct hotplug_slot *slot, u8 *state)
ret);
} else {
*state = power_state;
- slot->info->power_status = power_state;
}
return 0;
@@ -386,7 +389,7 @@ static int pnv_php_get_power_state(struct hotplug_slot *slot, u8 *state)
static int pnv_php_get_adapter_state(struct hotplug_slot *slot, u8 *state)
{
- struct pnv_php_slot *php_slot = slot->private;
+ struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
uint8_t presence = OPAL_PCI_SLOT_EMPTY;
int ret;
@@ -397,7 +400,6 @@ static int pnv_php_get_adapter_state(struct hotplug_slot *slot, u8 *state)
ret = pnv_pci_get_presence_state(php_slot->id, &presence);
if (ret >= 0) {
*state = presence;
- slot->info->adapter_status = presence;
ret = 0;
} else {
pci_warn(php_slot->pdev, "Error %d getting presence\n", ret);
@@ -406,10 +408,20 @@ static int pnv_php_get_adapter_state(struct hotplug_slot *slot, u8 *state)
return ret;
}
+static int pnv_php_get_attention_state(struct hotplug_slot *slot, u8 *state)
+{
+ struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
+
+ *state = php_slot->attention_state;
+ return 0;
+}
+
static int pnv_php_set_attention_state(struct hotplug_slot *slot, u8 state)
{
+ struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
+
/* FIXME: Make it real once firmware supports it */
- slot->info->attention_status = state;
+ php_slot->attention_state = state;
return 0;
}
@@ -501,15 +513,14 @@ scan:
static int pnv_php_enable_slot(struct hotplug_slot *slot)
{
- struct pnv_php_slot *php_slot = container_of(slot,
- struct pnv_php_slot, slot);
+ struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
return pnv_php_enable(php_slot, true);
}
static int pnv_php_disable_slot(struct hotplug_slot *slot)
{
- struct pnv_php_slot *php_slot = slot->private;
+ struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
int ret;
if (php_slot->state != PNV_PHP_STATE_POPULATED)
@@ -530,9 +541,10 @@ static int pnv_php_disable_slot(struct hotplug_slot *slot)
return ret;
}
-static struct hotplug_slot_ops php_slot_ops = {
+static const struct hotplug_slot_ops php_slot_ops = {
.get_power_status = pnv_php_get_power_state,
.get_adapter_status = pnv_php_get_adapter_state,
+ .get_attention_status = pnv_php_get_attention_state,
.set_attention_status = pnv_php_set_attention_state,
.enable_slot = pnv_php_enable_slot,
.disable_slot = pnv_php_disable_slot,
@@ -594,8 +606,6 @@ static struct pnv_php_slot *pnv_php_alloc_slot(struct device_node *dn)
php_slot->id = id;
php_slot->power_state_check = false;
php_slot->slot.ops = &php_slot_ops;
- php_slot->slot.info = &php_slot->slot_info;
- php_slot->slot.private = php_slot;
INIT_LIST_HEAD(&php_slot->children);
INIT_LIST_HEAD(&php_slot->link);
@@ -736,7 +746,7 @@ static irqreturn_t pnv_php_interrupt(int irq, void *data)
pe = edev ? edev->pe : NULL;
if (pe) {
eeh_serialize_lock(&flags);
- eeh_pe_state_mark(pe, EEH_PE_ISOLATED);
+ eeh_pe_mark_isolated(pe);
eeh_serialize_unlock(flags);
eeh_pe_set_option(pe, EEH_OPT_FREEZE_PE);
}
diff --git a/drivers/pci/hotplug/rpaphp.h b/drivers/pci/hotplug/rpaphp.h
index c8311724bd76..bdc954d70869 100644
--- a/drivers/pci/hotplug/rpaphp.h
+++ b/drivers/pci/hotplug/rpaphp.h
@@ -63,16 +63,22 @@ struct slot {
u32 index;
u32 type;
u32 power_domain;
+ u8 attention_status;
char *name;
struct device_node *dn;
struct pci_bus *bus;
struct list_head *pci_devs;
- struct hotplug_slot *hotplug_slot;
+ struct hotplug_slot hotplug_slot;
};
-extern struct hotplug_slot_ops rpaphp_hotplug_slot_ops;
+extern const struct hotplug_slot_ops rpaphp_hotplug_slot_ops;
extern struct list_head rpaphp_slot_head;
+static inline struct slot *to_slot(struct hotplug_slot *hotplug_slot)
+{
+ return container_of(hotplug_slot, struct slot, hotplug_slot);
+}
+
/* function prototypes */
/* rpaphp_pci.c */
diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c
index 857c358b727b..bcd5d357ca23 100644
--- a/drivers/pci/hotplug/rpaphp_core.c
+++ b/drivers/pci/hotplug/rpaphp_core.c
@@ -52,7 +52,7 @@ module_param_named(debug, rpaphp_debug, bool, 0644);
static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 value)
{
int rc;
- struct slot *slot = (struct slot *)hotplug_slot->private;
+ struct slot *slot = to_slot(hotplug_slot);
switch (value) {
case 0:
@@ -66,7 +66,7 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 value)
rc = rtas_set_indicator(DR_INDICATOR, slot->index, value);
if (!rc)
- hotplug_slot->info->attention_status = value;
+ slot->attention_status = value;
return rc;
}
@@ -79,7 +79,7 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 value)
static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
{
int retval, level;
- struct slot *slot = (struct slot *)hotplug_slot->private;
+ struct slot *slot = to_slot(hotplug_slot);
retval = rtas_get_power_level(slot->power_domain, &level);
if (!retval)
@@ -94,14 +94,14 @@ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
*/
static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
{
- struct slot *slot = (struct slot *)hotplug_slot->private;
- *value = slot->hotplug_slot->info->attention_status;
+ struct slot *slot = to_slot(hotplug_slot);
+ *value = slot->attention_status;
return 0;
}
static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
{
- struct slot *slot = (struct slot *)hotplug_slot->private;
+ struct slot *slot = to_slot(hotplug_slot);
int rc, state;
rc = rpaphp_get_sensor_state(slot, &state);
@@ -409,7 +409,7 @@ static void __exit cleanup_slots(void)
list_for_each_entry_safe(slot, next, &rpaphp_slot_head,
rpaphp_slot_list) {
list_del(&slot->rpaphp_slot_list);
- pci_hp_deregister(slot->hotplug_slot);
+ pci_hp_deregister(&slot->hotplug_slot);
dealloc_slot_struct(slot);
}
return;
@@ -434,7 +434,7 @@ static void __exit rpaphp_exit(void)
static int enable_slot(struct hotplug_slot *hotplug_slot)
{
- struct slot *slot = (struct slot *)hotplug_slot->private;
+ struct slot *slot = to_slot(hotplug_slot);
int state;
int retval;
@@ -464,7 +464,7 @@ static int enable_slot(struct hotplug_slot *hotplug_slot)
static int disable_slot(struct hotplug_slot *hotplug_slot)
{
- struct slot *slot = (struct slot *)hotplug_slot->private;
+ struct slot *slot = to_slot(hotplug_slot);
if (slot->state == NOT_CONFIGURED)
return -EINVAL;
@@ -477,7 +477,7 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
return 0;
}
-struct hotplug_slot_ops rpaphp_hotplug_slot_ops = {
+const struct hotplug_slot_ops rpaphp_hotplug_slot_ops = {
.enable_slot = enable_slot,
.disable_slot = disable_slot,
.set_attention_status = set_attention_status,
diff --git a/drivers/pci/hotplug/rpaphp_pci.c b/drivers/pci/hotplug/rpaphp_pci.c
index 0aac33e15dab..beca61badeea 100644
--- a/drivers/pci/hotplug/rpaphp_pci.c
+++ b/drivers/pci/hotplug/rpaphp_pci.c
@@ -54,25 +54,21 @@ int rpaphp_get_sensor_state(struct slot *slot, int *state)
* rpaphp_enable_slot - record slot state, config pci device
* @slot: target &slot
*
- * Initialize values in the slot, and the hotplug_slot info
- * structures to indicate if there is a pci card plugged into
- * the slot. If the slot is not empty, run the pcibios routine
+ * Initialize values in the slot structure to indicate if there is a pci card
+ * plugged into the slot. If the slot is not empty, run the pcibios routine
* to get pcibios stuff correctly set up.
*/
int rpaphp_enable_slot(struct slot *slot)
{
int rc, level, state;
struct pci_bus *bus;
- struct hotplug_slot_info *info = slot->hotplug_slot->info;
- info->adapter_status = NOT_VALID;
slot->state = EMPTY;
/* Find out if the power is turned on for the slot */
rc = rtas_get_power_level(slot->power_domain, &level);
if (rc)
return rc;
- info->power_status = level;
/* Figure out if there is an adapter in the slot */
rc = rpaphp_get_sensor_state(slot, &state);
@@ -85,13 +81,11 @@ int rpaphp_enable_slot(struct slot *slot)
return -EINVAL;
}
- info->adapter_status = EMPTY;
slot->bus = bus;
slot->pci_devs = &bus->devices;
/* if there's an adapter in the slot, go add the pci devices */
if (state == PRESENT) {
- info->adapter_status = NOT_CONFIGURED;
slot->state = NOT_CONFIGURED;
/* non-empty slot has to have child */
@@ -105,7 +99,6 @@ int rpaphp_enable_slot(struct slot *slot)
pci_hp_add_devices(bus);
if (!list_empty(&bus->devices)) {
- info->adapter_status = CONFIGURED;
slot->state = CONFIGURED;
}
diff --git a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c
index b916c8e4372d..5282aa3e33c5 100644
--- a/drivers/pci/hotplug/rpaphp_slot.c
+++ b/drivers/pci/hotplug/rpaphp_slot.c
@@ -21,9 +21,7 @@
/* free up the memory used by a slot */
void dealloc_slot_struct(struct slot *slot)
{
- kfree(slot->hotplug_slot->info);
kfree(slot->name);
- kfree(slot->hotplug_slot);
kfree(slot);
}
@@ -35,28 +33,16 @@ struct slot *alloc_slot_struct(struct device_node *dn,
slot = kzalloc(sizeof(struct slot), GFP_KERNEL);
if (!slot)
goto error_nomem;
- slot->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL);
- if (!slot->hotplug_slot)
- goto error_slot;
- slot->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info),
- GFP_KERNEL);
- if (!slot->hotplug_slot->info)
- goto error_hpslot;
slot->name = kstrdup(drc_name, GFP_KERNEL);
if (!slot->name)
- goto error_info;
+ goto error_slot;
slot->dn = dn;
slot->index = drc_index;
slot->power_domain = power_domain;
- slot->hotplug_slot->private = slot;
- slot->hotplug_slot->ops = &rpaphp_hotplug_slot_ops;
+ slot->hotplug_slot.ops = &rpaphp_hotplug_slot_ops;
return (slot);
-error_info:
- kfree(slot->hotplug_slot->info);
-error_hpslot:
- kfree(slot->hotplug_slot);
error_slot:
kfree(slot);
error_nomem:
@@ -77,7 +63,7 @@ static int is_registered(struct slot *slot)
int rpaphp_deregister_slot(struct slot *slot)
{
int retval = 0;
- struct hotplug_slot *php_slot = slot->hotplug_slot;
+ struct hotplug_slot *php_slot = &slot->hotplug_slot;
dbg("%s - Entry: deregistering slot=%s\n",
__func__, slot->name);
@@ -93,7 +79,7 @@ EXPORT_SYMBOL_GPL(rpaphp_deregister_slot);
int rpaphp_register_slot(struct slot *slot)
{
- struct hotplug_slot *php_slot = slot->hotplug_slot;
+ struct hotplug_slot *php_slot = &slot->hotplug_slot;
struct device_node *child;
u32 my_index;
int retval;
diff --git a/drivers/pci/hotplug/s390_pci_hpc.c b/drivers/pci/hotplug/s390_pci_hpc.c
index 93b5341d282c..30ee72268790 100644
--- a/drivers/pci/hotplug/s390_pci_hpc.c
+++ b/drivers/pci/hotplug/s390_pci_hpc.c
@@ -32,10 +32,15 @@ static int zpci_fn_configured(enum zpci_state state)
*/
struct slot {
struct list_head slot_list;
- struct hotplug_slot *hotplug_slot;
+ struct hotplug_slot hotplug_slot;
struct zpci_dev *zdev;
};
+static inline struct slot *to_slot(struct hotplug_slot *hotplug_slot)
+{
+ return container_of(hotplug_slot, struct slot, hotplug_slot);
+}
+
static inline int slot_configure(struct slot *slot)
{
int ret = sclp_pci_configure(slot->zdev->fid);
@@ -60,7 +65,7 @@ static inline int slot_deconfigure(struct slot *slot)
static int enable_slot(struct hotplug_slot *hotplug_slot)
{
- struct slot *slot = hotplug_slot->private;
+ struct slot *slot = to_slot(hotplug_slot);
int rc;
if (slot->zdev->state != ZPCI_FN_STATE_STANDBY)
@@ -88,7 +93,7 @@ out_deconfigure:
static int disable_slot(struct hotplug_slot *hotplug_slot)
{
- struct slot *slot = hotplug_slot->private;
+ struct slot *slot = to_slot(hotplug_slot);
struct pci_dev *pdev;
int rc;
@@ -110,7 +115,7 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
{
- struct slot *slot = hotplug_slot->private;
+ struct slot *slot = to_slot(hotplug_slot);
switch (slot->zdev->state) {
case ZPCI_FN_STATE_STANDBY:
@@ -130,7 +135,7 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
return 0;
}
-static struct hotplug_slot_ops s390_hotplug_slot_ops = {
+static const struct hotplug_slot_ops s390_hotplug_slot_ops = {
.enable_slot = enable_slot,
.disable_slot = disable_slot,
.get_power_status = get_power_status,
@@ -139,8 +144,6 @@ static struct hotplug_slot_ops s390_hotplug_slot_ops = {
int zpci_init_slot(struct zpci_dev *zdev)
{
- struct hotplug_slot *hotplug_slot;
- struct hotplug_slot_info *info;
char name[SLOT_NAME_SIZE];
struct slot *slot;
int rc;
@@ -152,26 +155,11 @@ int zpci_init_slot(struct zpci_dev *zdev)
if (!slot)
goto error;
- hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL);
- if (!hotplug_slot)
- goto error_hp;
- hotplug_slot->private = slot;
-
- slot->hotplug_slot = hotplug_slot;
slot->zdev = zdev;
-
- info = kzalloc(sizeof(*info), GFP_KERNEL);
- if (!info)
- goto error_info;
- hotplug_slot->info = info;
-
- hotplug_slot->ops = &s390_hotplug_slot_ops;
-
- get_power_status(hotplug_slot, &info->power_status);
- get_adapter_status(hotplug_slot, &info->adapter_status);
+ slot->hotplug_slot.ops = &s390_hotplug_slot_ops;
snprintf(name, SLOT_NAME_SIZE, "%08x", zdev->fid);
- rc = pci_hp_register(slot->hotplug_slot, zdev->bus,
+ rc = pci_hp_register(&slot->hotplug_slot, zdev->bus,
ZPCI_DEVFN, name);
if (rc)
goto error_reg;
@@ -180,10 +168,6 @@ int zpci_init_slot(struct zpci_dev *zdev)
return 0;
error_reg:
- kfree(info);
-error_info:
- kfree(hotplug_slot);
-error_hp:
kfree(slot);
error:
return -ENOMEM;
@@ -198,9 +182,7 @@ void zpci_exit_slot(struct zpci_dev *zdev)
if (slot->zdev != zdev)
continue;
list_del(&slot->slot_list);
- pci_hp_deregister(slot->hotplug_slot);
- kfree(slot->hotplug_slot->info);
- kfree(slot->hotplug_slot);
+ pci_hp_deregister(&slot->hotplug_slot);
kfree(slot);
}
}
diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c
index babd23409f61..231f5bdd3d2d 100644
--- a/drivers/pci/hotplug/sgi_hotplug.c
+++ b/drivers/pci/hotplug/sgi_hotplug.c
@@ -56,7 +56,7 @@ struct slot {
int device_num;
struct pci_bus *pci_bus;
/* this struct for glue internal only */
- struct hotplug_slot *hotplug_slot;
+ struct hotplug_slot hotplug_slot;
struct list_head hp_list;
char physical_path[SN_SLOT_NAME_SIZE];
};
@@ -80,7 +80,7 @@ static int enable_slot(struct hotplug_slot *slot);
static int disable_slot(struct hotplug_slot *slot);
static inline int get_power_status(struct hotplug_slot *slot, u8 *value);
-static struct hotplug_slot_ops sn_hotplug_slot_ops = {
+static const struct hotplug_slot_ops sn_hotplug_slot_ops = {
.enable_slot = enable_slot,
.disable_slot = disable_slot,
.get_power_status = get_power_status,
@@ -88,10 +88,15 @@ static struct hotplug_slot_ops sn_hotplug_slot_ops = {
static DEFINE_MUTEX(sn_hotplug_mutex);
+static struct slot *to_slot(struct hotplug_slot *bss_hotplug_slot)
+{
+ return container_of(bss_hotplug_slot, struct slot, hotplug_slot);
+}
+
static ssize_t path_show(struct pci_slot *pci_slot, char *buf)
{
int retval = -ENOENT;
- struct slot *slot = pci_slot->hotplug->private;
+ struct slot *slot = to_slot(pci_slot->hotplug);
if (!slot)
return retval;
@@ -156,7 +161,7 @@ static int sn_pci_bus_valid(struct pci_bus *pci_bus)
return -EIO;
}
-static int sn_hp_slot_private_alloc(struct hotplug_slot *bss_hotplug_slot,
+static int sn_hp_slot_private_alloc(struct hotplug_slot **bss_hotplug_slot,
struct pci_bus *pci_bus, int device,
char *name)
{
@@ -168,7 +173,6 @@ static int sn_hp_slot_private_alloc(struct hotplug_slot *bss_hotplug_slot,
slot = kzalloc(sizeof(*slot), GFP_KERNEL);
if (!slot)
return -ENOMEM;
- bss_hotplug_slot->private = slot;
slot->device_num = device;
slot->pci_bus = pci_bus;
@@ -179,8 +183,8 @@ static int sn_hp_slot_private_alloc(struct hotplug_slot *bss_hotplug_slot,
sn_generate_path(pci_bus, slot->physical_path);
- slot->hotplug_slot = bss_hotplug_slot;
list_add(&slot->hp_list, &sn_hp_list);
+ *bss_hotplug_slot = &slot->hotplug_slot;
return 0;
}
@@ -192,10 +196,9 @@ static struct hotplug_slot *sn_hp_destroy(void)
struct hotplug_slot *bss_hotplug_slot = NULL;
list_for_each_entry(slot, &sn_hp_list, hp_list) {
- bss_hotplug_slot = slot->hotplug_slot;
+ bss_hotplug_slot = &slot->hotplug_slot;
pci_slot = bss_hotplug_slot->pci_slot;
- list_del(&((struct slot *)bss_hotplug_slot->private)->
- hp_list);
+ list_del(&slot->hp_list);
sysfs_remove_file(&pci_slot->kobj,
&sn_slot_path_attr.attr);
break;
@@ -227,7 +230,7 @@ static void sn_bus_free_data(struct pci_dev *dev)
static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot,
int device_num, char **ssdt)
{
- struct slot *slot = bss_hotplug_slot->private;
+ struct slot *slot = to_slot(bss_hotplug_slot);
struct pcibus_info *pcibus_info;
struct pcibr_slot_enable_resp resp;
int rc;
@@ -267,7 +270,7 @@ static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot,
static int sn_slot_disable(struct hotplug_slot *bss_hotplug_slot,
int device_num, int action)
{
- struct slot *slot = bss_hotplug_slot->private;
+ struct slot *slot = to_slot(bss_hotplug_slot);
struct pcibus_info *pcibus_info;
struct pcibr_slot_disable_resp resp;
int rc;
@@ -323,7 +326,7 @@ static int sn_slot_disable(struct hotplug_slot *bss_hotplug_slot,
*/
static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
{
- struct slot *slot = bss_hotplug_slot->private;
+ struct slot *slot = to_slot(bss_hotplug_slot);
struct pci_bus *new_bus = NULL;
struct pci_dev *dev;
int num_funcs;
@@ -469,7 +472,7 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
{
- struct slot *slot = bss_hotplug_slot->private;
+ struct slot *slot = to_slot(bss_hotplug_slot);
struct pci_dev *dev, *temp;
int rc;
acpi_handle ssdt_hdl = NULL;
@@ -571,7 +574,7 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
static inline int get_power_status(struct hotplug_slot *bss_hotplug_slot,
u8 *value)
{
- struct slot *slot = bss_hotplug_slot->private;
+ struct slot *slot = to_slot(bss_hotplug_slot);
struct pcibus_info *pcibus_info;
u32 power;
@@ -585,9 +588,7 @@ static inline int get_power_status(struct hotplug_slot *bss_hotplug_slot,
static void sn_release_slot(struct hotplug_slot *bss_hotplug_slot)
{
- kfree(bss_hotplug_slot->info);
- kfree(bss_hotplug_slot->private);
- kfree(bss_hotplug_slot);
+ kfree(to_slot(bss_hotplug_slot));
}
static int sn_hotplug_slot_register(struct pci_bus *pci_bus)
@@ -607,22 +608,7 @@ static int sn_hotplug_slot_register(struct pci_bus *pci_bus)
if (sn_pci_slot_valid(pci_bus, device) != 1)
continue;
- bss_hotplug_slot = kzalloc(sizeof(*bss_hotplug_slot),
- GFP_KERNEL);
- if (!bss_hotplug_slot) {
- rc = -ENOMEM;
- goto alloc_err;
- }
-
- bss_hotplug_slot->info =
- kzalloc(sizeof(struct hotplug_slot_info),
- GFP_KERNEL);
- if (!bss_hotplug_slot->info) {
- rc = -ENOMEM;
- goto alloc_err;
- }
-
- if (sn_hp_slot_private_alloc(bss_hotplug_slot,
+ if (sn_hp_slot_private_alloc(&bss_hotplug_slot,
pci_bus, device, name)) {
rc = -ENOMEM;
goto alloc_err;
@@ -637,7 +623,7 @@ static int sn_hotplug_slot_register(struct pci_bus *pci_bus)
rc = sysfs_create_file(&pci_slot->kobj,
&sn_slot_path_attr.attr);
if (rc)
- goto register_err;
+ goto alloc_err;
}
pci_dbg(pci_bus->self, "Registered bus with hotplug\n");
return rc;
@@ -646,14 +632,11 @@ register_err:
pci_dbg(pci_bus->self, "bus failed to register with err = %d\n",
rc);
-alloc_err:
- if (rc == -ENOMEM)
- pci_dbg(pci_bus->self, "Memory allocation error\n");
-
/* destroy THIS element */
- if (bss_hotplug_slot)
- sn_release_slot(bss_hotplug_slot);
+ sn_hp_destroy();
+ sn_release_slot(bss_hotplug_slot);
+alloc_err:
/* destroy anything else on the list */
while ((bss_hotplug_slot = sn_hp_destroy())) {
pci_hp_deregister(bss_hotplug_slot);
diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h
index 516e4835019c..f7f13ee5d06e 100644
--- a/drivers/pci/hotplug/shpchp.h
+++ b/drivers/pci/hotplug/shpchp.h
@@ -67,11 +67,13 @@ struct slot {
u32 number;
u8 is_a_board;
u8 state;
+ u8 attention_save;
u8 presence_save;
+ u8 latch_save;
u8 pwr_save;
struct controller *ctrl;
const struct hpc_ops *hpc_ops;
- struct hotplug_slot *hotplug_slot;
+ struct hotplug_slot hotplug_slot;
struct list_head slot_list;
struct delayed_work work; /* work for button event */
struct mutex lock;
@@ -169,7 +171,7 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev);
static inline const char *slot_name(struct slot *slot)
{
- return hotplug_slot_name(slot->hotplug_slot);
+ return hotplug_slot_name(&slot->hotplug_slot);
}
struct ctrl_reg {
@@ -207,7 +209,7 @@ enum ctrl_offsets {
static inline struct slot *get_slot(struct hotplug_slot *hotplug_slot)
{
- return hotplug_slot->private;
+ return container_of(hotplug_slot, struct slot, hotplug_slot);
}
static inline struct slot *shpchp_find_slot(struct controller *ctrl, u8 device)
diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c
index 97cee23f3d51..81a918d47895 100644
--- a/drivers/pci/hotplug/shpchp_core.c
+++ b/drivers/pci/hotplug/shpchp_core.c
@@ -51,7 +51,7 @@ static int get_attention_status(struct hotplug_slot *slot, u8 *value);
static int get_latch_status(struct hotplug_slot *slot, u8 *value);
static int get_adapter_status(struct hotplug_slot *slot, u8 *value);
-static struct hotplug_slot_ops shpchp_hotplug_slot_ops = {
+static const struct hotplug_slot_ops shpchp_hotplug_slot_ops = {
.set_attention_status = set_attention_status,
.enable_slot = enable_slot,
.disable_slot = disable_slot,
@@ -65,7 +65,6 @@ static int init_slots(struct controller *ctrl)
{
struct slot *slot;
struct hotplug_slot *hotplug_slot;
- struct hotplug_slot_info *info;
char name[SLOT_NAME_SIZE];
int retval;
int i;
@@ -77,19 +76,7 @@ static int init_slots(struct controller *ctrl)
goto error;
}
- hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL);
- if (!hotplug_slot) {
- retval = -ENOMEM;
- goto error_slot;
- }
- slot->hotplug_slot = hotplug_slot;
-
- info = kzalloc(sizeof(*info), GFP_KERNEL);
- if (!info) {
- retval = -ENOMEM;
- goto error_hpslot;
- }
- hotplug_slot->info = info;
+ hotplug_slot = &slot->hotplug_slot;
slot->hp_slot = i;
slot->ctrl = ctrl;
@@ -101,14 +88,13 @@ static int init_slots(struct controller *ctrl)
slot->wq = alloc_workqueue("shpchp-%d", 0, 0, slot->number);
if (!slot->wq) {
retval = -ENOMEM;
- goto error_info;
+ goto error_slot;
}
mutex_init(&slot->lock);
INIT_DELAYED_WORK(&slot->work, shpchp_queue_pushbutton_work);
/* register this slot with the hotplug pci core */
- hotplug_slot->private = slot;
snprintf(name, SLOT_NAME_SIZE, "%d", slot->number);
hotplug_slot->ops = &shpchp_hotplug_slot_ops;
@@ -116,7 +102,7 @@ static int init_slots(struct controller *ctrl)
pci_domain_nr(ctrl->pci_dev->subordinate),
slot->bus, slot->device, slot->hp_slot, slot->number,
ctrl->slot_device_offset);
- retval = pci_hp_register(slot->hotplug_slot,
+ retval = pci_hp_register(hotplug_slot,
ctrl->pci_dev->subordinate, slot->device, name);
if (retval) {
ctrl_err(ctrl, "pci_hp_register failed with error %d\n",
@@ -124,10 +110,10 @@ static int init_slots(struct controller *ctrl)
goto error_slotwq;
}
- get_power_status(hotplug_slot, &info->power_status);
- get_attention_status(hotplug_slot, &info->attention_status);
- get_latch_status(hotplug_slot, &info->latch_status);
- get_adapter_status(hotplug_slot, &info->adapter_status);
+ get_power_status(hotplug_slot, &slot->pwr_save);
+ get_attention_status(hotplug_slot, &slot->attention_save);
+ get_latch_status(hotplug_slot, &slot->latch_save);
+ get_adapter_status(hotplug_slot, &slot->presence_save);
list_add(&slot->slot_list, &ctrl->slot_list);
}
@@ -135,10 +121,6 @@ static int init_slots(struct controller *ctrl)
return 0;
error_slotwq:
destroy_workqueue(slot->wq);
-error_info:
- kfree(info);
-error_hpslot:
- kfree(hotplug_slot);
error_slot:
kfree(slot);
error:
@@ -153,9 +135,7 @@ void cleanup_slots(struct controller *ctrl)
list_del(&slot->slot_list);
cancel_delayed_work(&slot->work);
destroy_workqueue(slot->wq);
- pci_hp_deregister(slot->hotplug_slot);
- kfree(slot->hotplug_slot->info);
- kfree(slot->hotplug_slot);
+ pci_hp_deregister(&slot->hotplug_slot);
kfree(slot);
}
}
@@ -170,7 +150,7 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n",
__func__, slot_name(slot));
- hotplug_slot->info->attention_status = status;
+ slot->attention_save = status;
slot->hpc_ops->set_attention_status(slot, status);
return 0;
@@ -206,7 +186,7 @@ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
retval = slot->hpc_ops->get_power_status(slot, value);
if (retval < 0)
- *value = hotplug_slot->info->power_status;
+ *value = slot->pwr_save;
return 0;
}
@@ -221,7 +201,7 @@ static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
retval = slot->hpc_ops->get_attention_status(slot, value);
if (retval < 0)
- *value = hotplug_slot->info->attention_status;
+ *value = slot->attention_save;
return 0;
}
@@ -236,7 +216,7 @@ static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
retval = slot->hpc_ops->get_latch_status(slot, value);
if (retval < 0)
- *value = hotplug_slot->info->latch_status;
+ *value = slot->latch_save;
return 0;
}
@@ -251,7 +231,7 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
retval = slot->hpc_ops->get_adapter_status(slot, value);
if (retval < 0)
- *value = hotplug_slot->info->adapter_status;
+ *value = slot->presence_save;
return 0;
}
diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c
index 1267dcc5a531..078003dcde5b 100644
--- a/drivers/pci/hotplug/shpchp_ctrl.c
+++ b/drivers/pci/hotplug/shpchp_ctrl.c
@@ -446,23 +446,12 @@ void shpchp_queue_pushbutton_work(struct work_struct *work)
mutex_unlock(&p_slot->lock);
}
-static int update_slot_info (struct slot *slot)
+static void update_slot_info(struct slot *slot)
{
- struct hotplug_slot_info *info;
- int result;
-
- info = kmalloc(sizeof(*info), GFP_KERNEL);
- if (!info)
- return -ENOMEM;
-
- slot->hpc_ops->get_power_status(slot, &(info->power_status));
- slot->hpc_ops->get_attention_status(slot, &(info->attention_status));
- slot->hpc_ops->get_latch_status(slot, &(info->latch_status));
- slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status));
-
- result = pci_hp_change_slot_info(slot->hotplug_slot, info);
- kfree (info);
- return result;
+ slot->hpc_ops->get_power_status(slot, &slot->pwr_save);
+ slot->hpc_ops->get_attention_status(slot, &slot->attention_save);
+ slot->hpc_ops->get_latch_status(slot, &slot->latch_save);
+ slot->hpc_ops->get_adapter_status(slot, &slot->presence_save);
}
/*
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
index c5f3cd4ed766..9616eca3182f 100644
--- a/drivers/pci/iov.c
+++ b/drivers/pci/iov.c
@@ -13,7 +13,6 @@
#include <linux/export.h>
#include <linux/string.h>
#include <linux/delay.h>
-#include <linux/pci-ats.h>
#include "pci.h"
#define VIRTFN_ID_LEN 16
@@ -133,6 +132,8 @@ static void pci_read_vf_config_common(struct pci_dev *virtfn)
&physfn->sriov->subsystem_vendor);
pci_read_config_word(virtfn, PCI_SUBSYSTEM_ID,
&physfn->sriov->subsystem_device);
+
+ physfn->sriov->cfg_size = pci_cfg_space_size(virtfn);
}
int pci_iov_add_virtfn(struct pci_dev *dev, int id)
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index f2ef896464b3..af24ed50a245 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -958,7 +958,6 @@ static int __pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries,
}
}
}
- WARN_ON(!!dev->msix_enabled);
/* Check whether driver already requested for MSI irq */
if (dev->msi_enabled) {
@@ -1028,8 +1027,6 @@ static int __pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec,
if (!pci_msi_supported(dev, minvec))
return -EINVAL;
- WARN_ON(!!dev->msi_enabled);
-
/* Check whether driver already requested MSI-X irqs */
if (dev->msix_enabled) {
pci_info(dev, "can't enable MSI (MSI-X already enabled)\n");
@@ -1039,6 +1036,9 @@ static int __pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec,
if (maxvec < minvec)
return -ERANGE;
+ if (WARN_ON_ONCE(dev->msi_enabled))
+ return -EINVAL;
+
nvec = pci_msi_vec_count(dev);
if (nvec < 0)
return nvec;
@@ -1087,6 +1087,9 @@ static int __pci_enable_msix_range(struct pci_dev *dev,
if (maxvec < minvec)
return -ERANGE;
+ if (WARN_ON_ONCE(dev->msix_enabled))
+ return -EINVAL;
+
for (;;) {
if (affd) {
nvec = irq_calc_affinity_vectors(minvec, nvec, affd);
diff --git a/drivers/pci/of.c b/drivers/pci/of.c
index 1836b8ddf292..4c4217d0c3f1 100644
--- a/drivers/pci/of.c
+++ b/drivers/pci/of.c
@@ -355,107 +355,6 @@ failed:
EXPORT_SYMBOL_GPL(devm_of_pci_get_host_bridge_resources);
#endif /* CONFIG_OF_ADDRESS */
-/**
- * of_pci_map_rid - Translate a requester ID through a downstream mapping.
- * @np: root complex device node.
- * @rid: PCI requester ID to map.
- * @map_name: property name of the map to use.
- * @map_mask_name: optional property name of the mask to use.
- * @target: optional pointer to a target device node.
- * @id_out: optional pointer to receive the translated ID.
- *
- * Given a PCI requester ID, look up the appropriate implementation-defined
- * platform ID and/or the target device which receives transactions on that
- * ID, as per the "iommu-map" and "msi-map" bindings. Either of @target or
- * @id_out may be NULL if only the other is required. If @target points to
- * a non-NULL device node pointer, only entries targeting that node will be
- * matched; if it points to a NULL value, it will receive the device node of
- * the first matching target phandle, with a reference held.
- *
- * Return: 0 on success or a standard error code on failure.
- */
-int of_pci_map_rid(struct device_node *np, u32 rid,
- const char *map_name, const char *map_mask_name,
- struct device_node **target, u32 *id_out)
-{
- u32 map_mask, masked_rid;
- int map_len;
- const __be32 *map = NULL;
-
- if (!np || !map_name || (!target && !id_out))
- return -EINVAL;
-
- map = of_get_property(np, map_name, &map_len);
- if (!map) {
- if (target)
- return -ENODEV;
- /* Otherwise, no map implies no translation */
- *id_out = rid;
- return 0;
- }
-
- if (!map_len || map_len % (4 * sizeof(*map))) {
- pr_err("%pOF: Error: Bad %s length: %d\n", np,
- map_name, map_len);
- return -EINVAL;
- }
-
- /* The default is to select all bits. */
- map_mask = 0xffffffff;
-
- /*
- * Can be overridden by "{iommu,msi}-map-mask" property.
- * If of_property_read_u32() fails, the default is used.
- */
- if (map_mask_name)
- of_property_read_u32(np, map_mask_name, &map_mask);
-
- masked_rid = map_mask & rid;
- for ( ; map_len > 0; map_len -= 4 * sizeof(*map), map += 4) {
- struct device_node *phandle_node;
- u32 rid_base = be32_to_cpup(map + 0);
- u32 phandle = be32_to_cpup(map + 1);
- u32 out_base = be32_to_cpup(map + 2);
- u32 rid_len = be32_to_cpup(map + 3);
-
- if (rid_base & ~map_mask) {
- pr_err("%pOF: Invalid %s translation - %s-mask (0x%x) ignores rid-base (0x%x)\n",
- np, map_name, map_name,
- map_mask, rid_base);
- return -EFAULT;
- }
-
- if (masked_rid < rid_base || masked_rid >= rid_base + rid_len)
- continue;
-
- phandle_node = of_find_node_by_phandle(phandle);
- if (!phandle_node)
- return -ENODEV;
-
- if (target) {
- if (*target)
- of_node_put(phandle_node);
- else
- *target = phandle_node;
-
- if (*target != phandle_node)
- continue;
- }
-
- if (id_out)
- *id_out = masked_rid - rid_base + out_base;
-
- pr_debug("%pOF: %s, using mask %08x, rid-base: %08x, out-base: %08x, length: %08x, rid: %08x -> %08x\n",
- np, map_name, map_mask, rid_base, out_base,
- rid_len, rid, masked_rid - rid_base + out_base);
- return 0;
- }
-
- pr_err("%pOF: Invalid %s translation - no match for rid 0x%x on %pOF\n",
- np, map_name, rid, target && *target ? *target : NULL);
- return -EFAULT;
-}
-
#if IS_ENABLED(CONFIG_OF_IRQ)
/**
* of_irq_parse_pci - Resolve the interrupt for a PCI device
diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c
new file mode 100644
index 000000000000..ae3c5b25dcc7
--- /dev/null
+++ b/drivers/pci/p2pdma.c
@@ -0,0 +1,805 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PCI Peer 2 Peer DMA support.
+ *
+ * Copyright (c) 2016-2018, Logan Gunthorpe
+ * Copyright (c) 2016-2017, Microsemi Corporation
+ * Copyright (c) 2017, Christoph Hellwig
+ * Copyright (c) 2018, Eideticom Inc.
+ */
+
+#define pr_fmt(fmt) "pci-p2pdma: " fmt
+#include <linux/ctype.h>
+#include <linux/pci-p2pdma.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/genalloc.h>
+#include <linux/memremap.h>
+#include <linux/percpu-refcount.h>
+#include <linux/random.h>
+#include <linux/seq_buf.h>
+
+struct pci_p2pdma {
+ struct percpu_ref devmap_ref;
+ struct completion devmap_ref_done;
+ struct gen_pool *pool;
+ bool p2pmem_published;
+};
+
+static ssize_t size_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ size_t size = 0;
+
+ if (pdev->p2pdma->pool)
+ size = gen_pool_size(pdev->p2pdma->pool);
+
+ return snprintf(buf, PAGE_SIZE, "%zd\n", size);
+}
+static DEVICE_ATTR_RO(size);
+
+static ssize_t available_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ size_t avail = 0;
+
+ if (pdev->p2pdma->pool)
+ avail = gen_pool_avail(pdev->p2pdma->pool);
+
+ return snprintf(buf, PAGE_SIZE, "%zd\n", avail);
+}
+static DEVICE_ATTR_RO(available);
+
+static ssize_t published_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ pdev->p2pdma->p2pmem_published);
+}
+static DEVICE_ATTR_RO(published);
+
+static struct attribute *p2pmem_attrs[] = {
+ &dev_attr_size.attr,
+ &dev_attr_available.attr,
+ &dev_attr_published.attr,
+ NULL,
+};
+
+static const struct attribute_group p2pmem_group = {
+ .attrs = p2pmem_attrs,
+ .name = "p2pmem",
+};
+
+static void pci_p2pdma_percpu_release(struct percpu_ref *ref)
+{
+ struct pci_p2pdma *p2p =
+ container_of(ref, struct pci_p2pdma, devmap_ref);
+
+ complete_all(&p2p->devmap_ref_done);
+}
+
+static void pci_p2pdma_percpu_kill(void *data)
+{
+ struct percpu_ref *ref = data;
+
+ /*
+ * pci_p2pdma_add_resource() may be called multiple times
+ * by a driver and may register the percpu_kill devm action multiple
+ * times. We only want the first action to actually kill the
+ * percpu_ref.
+ */
+ if (percpu_ref_is_dying(ref))
+ return;
+
+ percpu_ref_kill(ref);
+}
+
+static void pci_p2pdma_release(void *data)
+{
+ struct pci_dev *pdev = data;
+
+ if (!pdev->p2pdma)
+ return;
+
+ wait_for_completion(&pdev->p2pdma->devmap_ref_done);
+ percpu_ref_exit(&pdev->p2pdma->devmap_ref);
+
+ gen_pool_destroy(pdev->p2pdma->pool);
+ sysfs_remove_group(&pdev->dev.kobj, &p2pmem_group);
+ pdev->p2pdma = NULL;
+}
+
+static int pci_p2pdma_setup(struct pci_dev *pdev)
+{
+ int error = -ENOMEM;
+ struct pci_p2pdma *p2p;
+
+ p2p = devm_kzalloc(&pdev->dev, sizeof(*p2p), GFP_KERNEL);
+ if (!p2p)
+ return -ENOMEM;
+
+ p2p->pool = gen_pool_create(PAGE_SHIFT, dev_to_node(&pdev->dev));
+ if (!p2p->pool)
+ goto out;
+
+ init_completion(&p2p->devmap_ref_done);
+ error = percpu_ref_init(&p2p->devmap_ref,
+ pci_p2pdma_percpu_release, 0, GFP_KERNEL);
+ if (error)
+ goto out_pool_destroy;
+
+ error = devm_add_action_or_reset(&pdev->dev, pci_p2pdma_release, 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;
+
+ return 0;
+
+out_pool_destroy:
+ pdev->p2pdma = NULL;
+ gen_pool_destroy(p2p->pool);
+out:
+ devm_kfree(&pdev->dev, p2p);
+ return error;
+}
+
+/**
+ * pci_p2pdma_add_resource - add memory for use as p2p memory
+ * @pdev: the device to add the memory to
+ * @bar: PCI BAR to add
+ * @size: size of the memory to add, may be zero to use the whole BAR
+ * @offset: offset into the PCI BAR
+ *
+ * The memory will be given ZONE_DEVICE struct pages so that it may
+ * be used with any DMA request.
+ */
+int pci_p2pdma_add_resource(struct pci_dev *pdev, int bar, size_t size,
+ u64 offset)
+{
+ struct dev_pagemap *pgmap;
+ void *addr;
+ int error;
+
+ if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
+ return -EINVAL;
+
+ if (offset >= pci_resource_len(pdev, bar))
+ return -EINVAL;
+
+ if (!size)
+ size = pci_resource_len(pdev, bar) - offset;
+
+ if (size + offset > pci_resource_len(pdev, bar))
+ return -EINVAL;
+
+ if (!pdev->p2pdma) {
+ error = pci_p2pdma_setup(pdev);
+ if (error)
+ return error;
+ }
+
+ pgmap = devm_kzalloc(&pdev->dev, sizeof(*pgmap), GFP_KERNEL);
+ if (!pgmap)
+ return -ENOMEM;
+
+ pgmap->res.start = pci_resource_start(pdev, bar) + offset;
+ pgmap->res.end = pgmap->res.start + size - 1;
+ pgmap->res.flags = pci_resource_flags(pdev, bar);
+ pgmap->ref = &pdev->p2pdma->devmap_ref;
+ pgmap->type = MEMORY_DEVICE_PCI_P2PDMA;
+ pgmap->pci_p2pdma_bus_offset = pci_bus_address(pdev, bar) -
+ pci_resource_start(pdev, bar);
+
+ addr = devm_memremap_pages(&pdev->dev, pgmap);
+ if (IS_ERR(addr)) {
+ error = PTR_ERR(addr);
+ goto pgmap_free;
+ }
+
+ error = gen_pool_add_virt(pdev->p2pdma->pool, (unsigned long)addr,
+ pci_bus_address(pdev, bar) + offset,
+ resource_size(&pgmap->res), dev_to_node(&pdev->dev));
+ if (error)
+ goto pgmap_free;
+
+ error = devm_add_action_or_reset(&pdev->dev, pci_p2pdma_percpu_kill,
+ &pdev->p2pdma->devmap_ref);
+ if (error)
+ goto pgmap_free;
+
+ pci_info(pdev, "added peer-to-peer DMA memory %pR\n",
+ &pgmap->res);
+
+ return 0;
+
+pgmap_free:
+ devm_kfree(&pdev->dev, pgmap);
+ return error;
+}
+EXPORT_SYMBOL_GPL(pci_p2pdma_add_resource);
+
+/*
+ * Note this function returns the parent PCI device with a
+ * reference taken. It is the caller's responsibily to drop
+ * the reference.
+ */
+static struct pci_dev *find_parent_pci_dev(struct device *dev)
+{
+ struct device *parent;
+
+ dev = get_device(dev);
+
+ while (dev) {
+ if (dev_is_pci(dev))
+ return to_pci_dev(dev);
+
+ parent = get_device(dev->parent);
+ put_device(dev);
+ dev = parent;
+ }
+
+ return NULL;
+}
+
+/*
+ * Check if a PCI bridge has its ACS redirection bits set to redirect P2P
+ * TLPs upstream via ACS. Returns 1 if the packets will be redirected
+ * upstream, 0 otherwise.
+ */
+static int pci_bridge_has_acs_redir(struct pci_dev *pdev)
+{
+ int pos;
+ u16 ctrl;
+
+ pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ACS);
+ if (!pos)
+ return 0;
+
+ pci_read_config_word(pdev, pos + PCI_ACS_CTRL, &ctrl);
+
+ if (ctrl & (PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_EC))
+ return 1;
+
+ return 0;
+}
+
+static void seq_buf_print_bus_devfn(struct seq_buf *buf, struct pci_dev *pdev)
+{
+ if (!buf)
+ return;
+
+ seq_buf_printf(buf, "%s;", pci_name(pdev));
+}
+
+/*
+ * 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 don't have a common upstream bridge will return -1.
+ * In this way devices on separate PCIe root ports will be rejected, which
+ * is what we want for peer-to-peer seeing each PCIe root port defines a
+ * separate hierarchy domain and there's no way to determine whether the root
+ * complex supports forwarding between them.
+ *
+ * In the case where two devices are connected to different PCIe switches,
+ * this function will still return a positive distance as long as both
+ * switches eventually have a common upstream bridge. Note this covers
+ * the case of using multiple PCIe switches to achieve a desired level of
+ * fan-out from a root port. The exact distance will be a function of the
+ * number of switches between Device A and Device B.
+ *
+ * If a bridge which has any ACS redirection bits set is in the path
+ * then this functions will return -2. This is so we reject any
+ * cases where the TLPs are forwarded up into the root complex.
+ * 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 int upstream_bridge_distance(struct pci_dev *a,
+ struct pci_dev *b,
+ struct seq_buf *acs_list)
+{
+ int dist_a = 0;
+ int dist_b = 0;
+ struct pci_dev *bb = NULL;
+ int acs_cnt = 0;
+
+ /*
+ * 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);
+ acs_cnt++;
+ }
+
+ bb = b;
+
+ while (bb) {
+ if (a == bb)
+ goto check_b_path_acs;
+
+ bb = pci_upstream_bridge(bb);
+ dist_b++;
+ }
+
+ a = pci_upstream_bridge(a);
+ dist_a++;
+ }
+
+ return -1;
+
+check_b_path_acs:
+ bb = b;
+
+ while (bb) {
+ if (a == bb)
+ break;
+
+ if (pci_bridge_has_acs_redir(bb)) {
+ seq_buf_print_bus_devfn(acs_list, bb);
+ acs_cnt++;
+ }
+
+ bb = pci_upstream_bridge(bb);
+ }
+
+ if (acs_cnt)
+ return -2;
+
+ return dist_a + dist_b;
+}
+
+static int upstream_bridge_distance_warn(struct pci_dev *provider,
+ struct pci_dev *client)
+{
+ struct seq_buf acs_list;
+ 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, &acs_list);
+ if (ret == -2) {
+ pci_warn(client, "cannot be used for peer-to-peer DMA as 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);
+
+ } else if (ret < 0) {
+ pci_warn(client, "cannot be used for peer-to-peer DMA as the client and provider (%s) do not share an upstream bridge\n",
+ pci_name(provider));
+ }
+
+ kfree(acs_list.buffer);
+
+ return ret;
+}
+
+/**
+ * pci_p2pdma_distance_many - Determive the cumulative distance between
+ * a p2pdma provider and the clients in use.
+ * @provider: p2pdma provider to check against the client list
+ * @clients: array of devices to check (NULL-terminated)
+ * @num_clients: number of clients in the array
+ * @verbose: if true, print warnings for devices when we return -1
+ *
+ * Returns -1 if any of the clients are not compatible (behind the same
+ * root port as the provider), otherwise returns a positive number where
+ * a lower number is the preferrable choice. (If there's one client
+ * that's the same as the provider it will return 0, which is best choice).
+ *
+ * For now, "compatible" means the provider and the clients are all behind
+ * the same PCI root port. This cuts out cases that may work but is safest
+ * for the user. Future work can expand this to white-list root complexes that
+ * can safely forward between each ports.
+ */
+int pci_p2pdma_distance_many(struct pci_dev *provider, struct device **clients,
+ int num_clients, bool verbose)
+{
+ bool not_supported = false;
+ struct pci_dev *pci_client;
+ int distance = 0;
+ int i, ret;
+
+ if (num_clients == 0)
+ return -1;
+
+ for (i = 0; i < num_clients; i++) {
+ pci_client = find_parent_pci_dev(clients[i]);
+ if (!pci_client) {
+ if (verbose)
+ dev_warn(clients[i],
+ "cannot be used for peer-to-peer DMA as it is not a PCI device\n");
+ return -1;
+ }
+
+ if (verbose)
+ ret = upstream_bridge_distance_warn(provider,
+ pci_client);
+ else
+ ret = upstream_bridge_distance(provider, pci_client,
+ NULL);
+
+ pci_dev_put(pci_client);
+
+ if (ret < 0)
+ not_supported = true;
+
+ if (not_supported && !verbose)
+ break;
+
+ distance += ret;
+ }
+
+ if (not_supported)
+ return -1;
+
+ return distance;
+}
+EXPORT_SYMBOL_GPL(pci_p2pdma_distance_many);
+
+/**
+ * pci_has_p2pmem - check if a given PCI device has published any p2pmem
+ * @pdev: PCI device to check
+ */
+bool pci_has_p2pmem(struct pci_dev *pdev)
+{
+ return pdev->p2pdma && pdev->p2pdma->p2pmem_published;
+}
+EXPORT_SYMBOL_GPL(pci_has_p2pmem);
+
+/**
+ * pci_p2pmem_find - find a peer-to-peer DMA memory device compatible with
+ * the specified list of clients and shortest distance (as determined
+ * by pci_p2pmem_dma())
+ * @clients: array of devices to check (NULL-terminated)
+ * @num_clients: number of client devices in the list
+ *
+ * If multiple devices are behind the same switch, the one "closest" to the
+ * client devices in use will be chosen first. (So if one of the providers are
+ * the same as one of the clients, that provider will be used ahead of any
+ * other providers that are unrelated). If multiple providers are an equal
+ * distance away, one will be chosen at random.
+ *
+ * Returns a pointer to the PCI device with a reference taken (use pci_dev_put
+ * to return the reference) or NULL if no compatible device is found. The
+ * found provider will also be assigned to the client list.
+ */
+struct pci_dev *pci_p2pmem_find_many(struct device **clients, int num_clients)
+{
+ struct pci_dev *pdev = NULL;
+ int distance;
+ int closest_distance = INT_MAX;
+ struct pci_dev **closest_pdevs;
+ int dev_cnt = 0;
+ const int max_devs = PAGE_SIZE / sizeof(*closest_pdevs);
+ int i;
+
+ closest_pdevs = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!closest_pdevs)
+ return NULL;
+
+ while ((pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pdev))) {
+ if (!pci_has_p2pmem(pdev))
+ continue;
+
+ distance = pci_p2pdma_distance_many(pdev, clients,
+ num_clients, false);
+ if (distance < 0 || distance > closest_distance)
+ continue;
+
+ if (distance == closest_distance && dev_cnt >= max_devs)
+ continue;
+
+ if (distance < closest_distance) {
+ for (i = 0; i < dev_cnt; i++)
+ pci_dev_put(closest_pdevs[i]);
+
+ dev_cnt = 0;
+ closest_distance = distance;
+ }
+
+ closest_pdevs[dev_cnt++] = pci_dev_get(pdev);
+ }
+
+ if (dev_cnt)
+ pdev = pci_dev_get(closest_pdevs[prandom_u32_max(dev_cnt)]);
+
+ for (i = 0; i < dev_cnt; i++)
+ pci_dev_put(closest_pdevs[i]);
+
+ kfree(closest_pdevs);
+ return pdev;
+}
+EXPORT_SYMBOL_GPL(pci_p2pmem_find_many);
+
+/**
+ * pci_alloc_p2p_mem - allocate peer-to-peer DMA memory
+ * @pdev: the device to allocate memory from
+ * @size: number of bytes to allocate
+ *
+ * Returns the allocated memory or NULL on error.
+ */
+void *pci_alloc_p2pmem(struct pci_dev *pdev, size_t size)
+{
+ void *ret;
+
+ if (unlikely(!pdev->p2pdma))
+ return NULL;
+
+ if (unlikely(!percpu_ref_tryget_live(&pdev->p2pdma->devmap_ref)))
+ return NULL;
+
+ ret = (void *)gen_pool_alloc(pdev->p2pdma->pool, size);
+
+ if (unlikely(!ret))
+ percpu_ref_put(&pdev->p2pdma->devmap_ref);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pci_alloc_p2pmem);
+
+/**
+ * pci_free_p2pmem - free peer-to-peer DMA memory
+ * @pdev: the device the memory was allocated from
+ * @addr: address of the memory that was allocated
+ * @size: number of bytes that was allocated
+ */
+void pci_free_p2pmem(struct pci_dev *pdev, void *addr, size_t size)
+{
+ gen_pool_free(pdev->p2pdma->pool, (uintptr_t)addr, size);
+ percpu_ref_put(&pdev->p2pdma->devmap_ref);
+}
+EXPORT_SYMBOL_GPL(pci_free_p2pmem);
+
+/**
+ * pci_virt_to_bus - return the PCI bus address for a given virtual
+ * address obtained with pci_alloc_p2pmem()
+ * @pdev: the device the memory was allocated from
+ * @addr: address of the memory that was allocated
+ */
+pci_bus_addr_t pci_p2pmem_virt_to_bus(struct pci_dev *pdev, void *addr)
+{
+ if (!addr)
+ return 0;
+ if (!pdev->p2pdma)
+ return 0;
+
+ /*
+ * Note: when we added the memory to the pool we used the PCI
+ * 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);
+}
+EXPORT_SYMBOL_GPL(pci_p2pmem_virt_to_bus);
+
+/**
+ * pci_p2pmem_alloc_sgl - allocate peer-to-peer DMA memory in a scatterlist
+ * @pdev: the device to allocate memory from
+ * @nents: the number of SG entries in the list
+ * @length: number of bytes to allocate
+ *
+ * Returns 0 on success
+ */
+struct scatterlist *pci_p2pmem_alloc_sgl(struct pci_dev *pdev,
+ unsigned int *nents, u32 length)
+{
+ struct scatterlist *sg;
+ void *addr;
+
+ sg = kzalloc(sizeof(*sg), GFP_KERNEL);
+ if (!sg)
+ return NULL;
+
+ sg_init_table(sg, 1);
+
+ addr = pci_alloc_p2pmem(pdev, length);
+ if (!addr)
+ goto out_free_sg;
+
+ sg_set_buf(sg, addr, length);
+ *nents = 1;
+ return sg;
+
+out_free_sg:
+ kfree(sg);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(pci_p2pmem_alloc_sgl);
+
+/**
+ * pci_p2pmem_free_sgl - free a scatterlist allocated by pci_p2pmem_alloc_sgl()
+ * @pdev: the device to allocate memory from
+ * @sgl: the allocated scatterlist
+ */
+void pci_p2pmem_free_sgl(struct pci_dev *pdev, struct scatterlist *sgl)
+{
+ struct scatterlist *sg;
+ int count;
+
+ for_each_sg(sgl, sg, INT_MAX, count) {
+ if (!sg)
+ break;
+
+ pci_free_p2pmem(pdev, sg_virt(sg), sg->length);
+ }
+ kfree(sgl);
+}
+EXPORT_SYMBOL_GPL(pci_p2pmem_free_sgl);
+
+/**
+ * pci_p2pmem_publish - publish the peer-to-peer DMA memory for use by
+ * other devices with pci_p2pmem_find()
+ * @pdev: the device with peer-to-peer DMA memory to publish
+ * @publish: set to true to publish the memory, false to unpublish it
+ *
+ * Published memory can be used by other PCI device drivers for
+ * peer-2-peer DMA operations. Non-published memory is reserved for
+ * exlusive use of the device driver that registers the peer-to-peer
+ * memory.
+ */
+void pci_p2pmem_publish(struct pci_dev *pdev, bool publish)
+{
+ if (pdev->p2pdma)
+ pdev->p2pdma->p2pmem_published = publish;
+}
+EXPORT_SYMBOL_GPL(pci_p2pmem_publish);
+
+/**
+ * pci_p2pdma_map_sg - map a PCI peer-to-peer scatterlist for DMA
+ * @dev: device doing the DMA request
+ * @sg: scatter list to map
+ * @nents: elements in the scatterlist
+ * @dir: DMA direction
+ *
+ * Scatterlists mapped with this function should not be unmapped in any way.
+ *
+ * Returns the number of SG entries mapped or 0 on error.
+ */
+int pci_p2pdma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+ enum dma_data_direction dir)
+{
+ struct dev_pagemap *pgmap;
+ struct scatterlist *s;
+ phys_addr_t paddr;
+ int i;
+
+ /*
+ * p2pdma mappings are not compatible with devices that use
+ * dma_virt_ops. If the upper layers do the right thing
+ * this should never happen because it will be prevented
+ * by the check in pci_p2pdma_add_client()
+ */
+ if (WARN_ON_ONCE(IS_ENABLED(CONFIG_DMA_VIRT_OPS) &&
+ dev->dma_ops == &dma_virt_ops))
+ return 0;
+
+ for_each_sg(sg, s, nents, i) {
+ pgmap = sg_page(s)->pgmap;
+ paddr = sg_phys(s);
+
+ s->dma_address = paddr - pgmap->pci_p2pdma_bus_offset;
+ sg_dma_len(s) = s->length;
+ }
+
+ return nents;
+}
+EXPORT_SYMBOL_GPL(pci_p2pdma_map_sg);
+
+/**
+ * pci_p2pdma_enable_store - parse a configfs/sysfs attribute store
+ * to enable p2pdma
+ * @page: contents of the value to be stored
+ * @p2p_dev: returns the PCI device that was selected to be used
+ * (if one was specified in the stored value)
+ * @use_p2pdma: returns whether to enable p2pdma or not
+ *
+ * Parses an attribute value to decide whether to enable p2pdma.
+ * The value can select a PCI device (using it's full BDF device
+ * name) or a boolean (in any format strtobool() accepts). A false
+ * value disables p2pdma, a true value expects the caller
+ * to automatically find a compatible device and specifying a PCI device
+ * expects the caller to use the specific provider.
+ *
+ * pci_p2pdma_enable_show() should be used as the show operation for
+ * the attribute.
+ *
+ * Returns 0 on success
+ */
+int pci_p2pdma_enable_store(const char *page, struct pci_dev **p2p_dev,
+ bool *use_p2pdma)
+{
+ struct device *dev;
+
+ dev = bus_find_device_by_name(&pci_bus_type, NULL, page);
+ if (dev) {
+ *use_p2pdma = true;
+ *p2p_dev = to_pci_dev(dev);
+
+ if (!pci_has_p2pmem(*p2p_dev)) {
+ pci_err(*p2p_dev,
+ "PCI device has no peer-to-peer memory: %s\n",
+ page);
+ pci_dev_put(*p2p_dev);
+ return -ENODEV;
+ }
+
+ return 0;
+ } else if ((page[0] == '0' || page[0] == '1') && !iscntrl(page[1])) {
+ /*
+ * If the user enters a PCI device that doesn't exist
+ * like "0000:01:00.1", we don't want strtobool to think
+ * it's a '0' when it's clearly not what the user wanted.
+ * So we require 0's and 1's to be exactly one character.
+ */
+ } else if (!strtobool(page, use_p2pdma)) {
+ return 0;
+ }
+
+ pr_err("No such PCI device: %.*s\n", (int)strcspn(page, "\n"), page);
+ return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(pci_p2pdma_enable_store);
+
+/**
+ * pci_p2pdma_enable_show - show a configfs/sysfs attribute indicating
+ * whether p2pdma is enabled
+ * @page: contents of the stored value
+ * @p2p_dev: the selected p2p device (NULL if no device is selected)
+ * @use_p2pdma: whether p2pdme has been enabled
+ *
+ * Attributes that use pci_p2pdma_enable_store() should use this function
+ * to show the value of the attribute.
+ *
+ * Returns 0 on success
+ */
+ssize_t pci_p2pdma_enable_show(char *page, struct pci_dev *p2p_dev,
+ bool use_p2pdma)
+{
+ if (!use_p2pdma)
+ return sprintf(page, "0\n");
+
+ if (!p2p_dev)
+ return sprintf(page, "1\n");
+
+ return sprintf(page, "%s\n", pci_name(p2p_dev));
+}
+EXPORT_SYMBOL_GPL(pci_p2pdma_enable_show);
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index c2ab57705043..921db6f80340 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -519,6 +519,46 @@ static pci_power_t acpi_pci_choose_state(struct pci_dev *pdev)
return PCI_POWER_ERROR;
}
+static struct acpi_device *acpi_pci_find_companion(struct device *dev);
+
+static bool acpi_pci_bridge_d3(struct pci_dev *dev)
+{
+ const struct fwnode_handle *fwnode;
+ struct acpi_device *adev;
+ struct pci_dev *root;
+ u8 val;
+
+ if (!dev->is_hotplug_bridge)
+ return false;
+
+ /*
+ * Look for a special _DSD property for the root port and if it
+ * is set we know the hierarchy behind it supports D3 just fine.
+ */
+ root = pci_find_pcie_root_port(dev);
+ if (!root)
+ return false;
+
+ adev = ACPI_COMPANION(&root->dev);
+ if (root == dev) {
+ /*
+ * It is possible that the ACPI companion is not yet bound
+ * for the root port so look it up manually here.
+ */
+ if (!adev && !pci_dev_is_added(root))
+ adev = acpi_pci_find_companion(&root->dev);
+ }
+
+ if (!adev)
+ return false;
+
+ fwnode = acpi_fwnode_handle(adev);
+ if (fwnode_property_read_u8(fwnode, "HotPlugSupportInD3", &val))
+ return false;
+
+ return val == 1;
+}
+
static bool acpi_pci_power_manageable(struct pci_dev *dev)
{
struct acpi_device *adev = ACPI_COMPANION(&dev->dev);
@@ -548,6 +588,7 @@ static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state)
error = -EBUSY;
break;
}
+ /* Fall through */
case PCI_D0:
case PCI_D1:
case PCI_D2:
@@ -635,6 +676,7 @@ static bool acpi_pci_need_resume(struct pci_dev *dev)
}
static const struct pci_platform_pm_ops acpi_pci_platform_pm = {
+ .bridge_d3 = acpi_pci_bridge_d3,
.is_manageable = acpi_pci_power_manageable,
.set_state = acpi_pci_set_power_state,
.get_state = acpi_pci_get_power_state,
@@ -762,19 +804,33 @@ static void pci_acpi_setup(struct device *dev)
return;
device_set_wakeup_capable(dev, true);
+ /*
+ * For bridges that can do D3 we enable wake automatically (as
+ * we do for the power management itself in that case). The
+ * reason is that the bridge may have additional methods such as
+ * _DSW that need to be called.
+ */
+ if (pci_dev->bridge_d3)
+ device_wakeup_enable(dev);
+
acpi_pci_wakeup(pci_dev, false);
}
static void pci_acpi_cleanup(struct device *dev)
{
struct acpi_device *adev = ACPI_COMPANION(dev);
+ struct pci_dev *pci_dev = to_pci_dev(dev);
if (!adev)
return;
pci_acpi_remove_pm_notifier(adev);
- if (adev->wakeup.flags.valid)
+ if (adev->wakeup.flags.valid) {
+ if (pci_dev->bridge_d3)
+ device_wakeup_disable(dev);
+
device_set_wakeup_capable(dev, false);
+ }
}
static bool pci_acpi_bus_match(struct device *dev)
diff --git a/drivers/pci/pci-bridge-emul.c b/drivers/pci/pci-bridge-emul.c
new file mode 100644
index 000000000000..129738362d90
--- /dev/null
+++ b/drivers/pci/pci-bridge-emul.c
@@ -0,0 +1,408 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Marvell
+ *
+ * Author: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
+ *
+ * This file helps PCI controller drivers implement a fake root port
+ * PCI bridge when the HW doesn't provide such a root port PCI
+ * bridge.
+ *
+ * It emulates a PCI bridge by providing a fake PCI configuration
+ * space (and optionally a PCIe capability configuration space) in
+ * memory. By default the read/write operations simply read and update
+ * this fake configuration space in memory. However, PCI controller
+ * drivers can provide through the 'struct pci_sw_bridge_ops'
+ * structure a set of operations to override or complement this
+ * default behavior.
+ */
+
+#include <linux/pci.h>
+#include "pci-bridge-emul.h"
+
+#define PCI_BRIDGE_CONF_END PCI_STD_HEADER_SIZEOF
+#define PCI_CAP_PCIE_START PCI_BRIDGE_CONF_END
+#define PCI_CAP_PCIE_END (PCI_CAP_PCIE_START + PCI_EXP_SLTSTA2 + 2)
+
+/*
+ * Initialize a pci_bridge_emul structure to represent a fake PCI
+ * bridge configuration space. The caller needs to have initialized
+ * the PCI configuration space with whatever values make sense
+ * (typically at least vendor, device, revision), the ->ops pointer,
+ * and optionally ->data and ->has_pcie.
+ */
+void pci_bridge_emul_init(struct pci_bridge_emul *bridge)
+{
+ bridge->conf.class_revision |= PCI_CLASS_BRIDGE_PCI << 16;
+ bridge->conf.header_type = PCI_HEADER_TYPE_BRIDGE;
+ bridge->conf.cache_line_size = 0x10;
+ bridge->conf.status = PCI_STATUS_CAP_LIST;
+
+ if (bridge->has_pcie) {
+ bridge->conf.capabilities_pointer = PCI_CAP_PCIE_START;
+ bridge->pcie_conf.cap_id = PCI_CAP_ID_EXP;
+ /* Set PCIe v2, root port, slot support */
+ bridge->pcie_conf.cap = PCI_EXP_TYPE_ROOT_PORT << 4 | 2 |
+ PCI_EXP_FLAGS_SLOT;
+ }
+}
+
+struct pci_bridge_reg_behavior {
+ /* Read-only bits */
+ u32 ro;
+
+ /* Read-write bits */
+ u32 rw;
+
+ /* Write-1-to-clear bits */
+ u32 w1c;
+
+ /* Reserved bits (hardwired to 0) */
+ u32 rsvd;
+};
+
+const static struct pci_bridge_reg_behavior pci_regs_behavior[] = {
+ [PCI_VENDOR_ID / 4] = { .ro = ~0 },
+ [PCI_COMMAND / 4] = {
+ .rw = (PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
+ PCI_COMMAND_MASTER | PCI_COMMAND_PARITY |
+ PCI_COMMAND_SERR),
+ .ro = ((PCI_COMMAND_SPECIAL | PCI_COMMAND_INVALIDATE |
+ PCI_COMMAND_VGA_PALETTE | PCI_COMMAND_WAIT |
+ PCI_COMMAND_FAST_BACK) |
+ (PCI_STATUS_CAP_LIST | PCI_STATUS_66MHZ |
+ PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MASK) << 16),
+ .rsvd = GENMASK(15, 10) | ((BIT(6) | GENMASK(3, 0)) << 16),
+ .w1c = (PCI_STATUS_PARITY |
+ PCI_STATUS_SIG_TARGET_ABORT |
+ PCI_STATUS_REC_TARGET_ABORT |
+ PCI_STATUS_REC_MASTER_ABORT |
+ PCI_STATUS_SIG_SYSTEM_ERROR |
+ PCI_STATUS_DETECTED_PARITY) << 16,
+ },
+ [PCI_CLASS_REVISION / 4] = { .ro = ~0 },
+
+ /*
+ * Cache Line Size register: implement as read-only, we do not
+ * pretend implementing "Memory Write and Invalidate"
+ * transactions"
+ *
+ * Latency Timer Register: implemented as read-only, as "A
+ * bridge that is not capable of a burst transfer of more than
+ * two data phases on its primary interface is permitted to
+ * hardwire the Latency Timer to a value of 16 or less"
+ *
+ * Header Type: always read-only
+ *
+ * BIST register: implemented as read-only, as "A bridge that
+ * does not support BIST must implement this register as a
+ * read-only register that returns 0 when read"
+ */
+ [PCI_CACHE_LINE_SIZE / 4] = { .ro = ~0 },
+
+ /*
+ * Base Address registers not used must be implemented as
+ * read-only registers that return 0 when read.
+ */
+ [PCI_BASE_ADDRESS_0 / 4] = { .ro = ~0 },
+ [PCI_BASE_ADDRESS_1 / 4] = { .ro = ~0 },
+
+ [PCI_PRIMARY_BUS / 4] = {
+ /* Primary, secondary and subordinate bus are RW */
+ .rw = GENMASK(24, 0),
+ /* Secondary latency is read-only */
+ .ro = GENMASK(31, 24),
+ },
+
+ [PCI_IO_BASE / 4] = {
+ /* The high four bits of I/O base/limit are RW */
+ .rw = (GENMASK(15, 12) | GENMASK(7, 4)),
+
+ /* The low four bits of I/O base/limit are RO */
+ .ro = (((PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK |
+ PCI_STATUS_DEVSEL_MASK) << 16) |
+ GENMASK(11, 8) | GENMASK(3, 0)),
+
+ .w1c = (PCI_STATUS_PARITY |
+ PCI_STATUS_SIG_TARGET_ABORT |
+ PCI_STATUS_REC_TARGET_ABORT |
+ PCI_STATUS_REC_MASTER_ABORT |
+ PCI_STATUS_SIG_SYSTEM_ERROR |
+ PCI_STATUS_DETECTED_PARITY) << 16,
+
+ .rsvd = ((BIT(6) | GENMASK(4, 0)) << 16),
+ },
+
+ [PCI_MEMORY_BASE / 4] = {
+ /* The high 12-bits of mem base/limit are RW */
+ .rw = GENMASK(31, 20) | GENMASK(15, 4),
+
+ /* The low four bits of mem base/limit are RO */
+ .ro = GENMASK(19, 16) | GENMASK(3, 0),
+ },
+
+ [PCI_PREF_MEMORY_BASE / 4] = {
+ /* The high 12-bits of pref mem base/limit are RW */
+ .rw = GENMASK(31, 20) | GENMASK(15, 4),
+
+ /* The low four bits of pref mem base/limit are RO */
+ .ro = GENMASK(19, 16) | GENMASK(3, 0),
+ },
+
+ [PCI_PREF_BASE_UPPER32 / 4] = {
+ .rw = ~0,
+ },
+
+ [PCI_PREF_LIMIT_UPPER32 / 4] = {
+ .rw = ~0,
+ },
+
+ [PCI_IO_BASE_UPPER16 / 4] = {
+ .rw = ~0,
+ },
+
+ [PCI_CAPABILITY_LIST / 4] = {
+ .ro = GENMASK(7, 0),
+ .rsvd = GENMASK(31, 8),
+ },
+
+ [PCI_ROM_ADDRESS1 / 4] = {
+ .rw = GENMASK(31, 11) | BIT(0),
+ .rsvd = GENMASK(10, 1),
+ },
+
+ /*
+ * Interrupt line (bits 7:0) are RW, interrupt pin (bits 15:8)
+ * are RO, and bridge control (31:16) are a mix of RW, RO,
+ * reserved and W1C bits
+ */
+ [PCI_INTERRUPT_LINE / 4] = {
+ /* Interrupt line is RW */
+ .rw = (GENMASK(7, 0) |
+ ((PCI_BRIDGE_CTL_PARITY |
+ PCI_BRIDGE_CTL_SERR |
+ PCI_BRIDGE_CTL_ISA |
+ PCI_BRIDGE_CTL_VGA |
+ PCI_BRIDGE_CTL_MASTER_ABORT |
+ PCI_BRIDGE_CTL_BUS_RESET |
+ BIT(8) | BIT(9) | BIT(11)) << 16)),
+
+ /* Interrupt pin is RO */
+ .ro = (GENMASK(15, 8) | ((PCI_BRIDGE_CTL_FAST_BACK) << 16)),
+
+ .w1c = BIT(10) << 16,
+
+ .rsvd = (GENMASK(15, 12) | BIT(4)) << 16,
+ },
+};
+
+const static struct pci_bridge_reg_behavior pcie_cap_regs_behavior[] = {
+ [PCI_CAP_LIST_ID / 4] = {
+ /*
+ * Capability ID, Next Capability Pointer and
+ * Capabilities register are all read-only.
+ */
+ .ro = ~0,
+ },
+
+ [PCI_EXP_DEVCAP / 4] = {
+ .ro = ~0,
+ },
+
+ [PCI_EXP_DEVCTL / 4] = {
+ /* Device control register is RW */
+ .rw = GENMASK(15, 0),
+
+ /*
+ * Device status register has 4 bits W1C, then 2 bits
+ * RO, the rest is reserved
+ */
+ .w1c = GENMASK(19, 16),
+ .ro = GENMASK(20, 19),
+ .rsvd = GENMASK(31, 21),
+ },
+
+ [PCI_EXP_LNKCAP / 4] = {
+ /* All bits are RO, except bit 23 which is reserved */
+ .ro = lower_32_bits(~BIT(23)),
+ .rsvd = BIT(23),
+ },
+
+ [PCI_EXP_LNKCTL / 4] = {
+ /*
+ * Link control has bits [1:0] and [11:3] RW, the
+ * other bits are reserved.
+ * Link status has bits [13:0] RO, and bits [14:15]
+ * W1C.
+ */
+ .rw = GENMASK(11, 3) | GENMASK(1, 0),
+ .ro = GENMASK(13, 0) << 16,
+ .w1c = GENMASK(15, 14) << 16,
+ .rsvd = GENMASK(15, 12) | BIT(2),
+ },
+
+ [PCI_EXP_SLTCAP / 4] = {
+ .ro = ~0,
+ },
+
+ [PCI_EXP_SLTCTL / 4] = {
+ /*
+ * Slot control has bits [12:0] RW, the rest is
+ * reserved.
+ *
+ * Slot status has a mix of W1C and RO bits, as well
+ * as reserved bits.
+ */
+ .rw = GENMASK(12, 0),
+ .w1c = (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD |
+ PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_PDC |
+ PCI_EXP_SLTSTA_CC | PCI_EXP_SLTSTA_DLLSC) << 16,
+ .ro = (PCI_EXP_SLTSTA_MRLSS | PCI_EXP_SLTSTA_PDS |
+ PCI_EXP_SLTSTA_EIS) << 16,
+ .rsvd = GENMASK(15, 12) | (GENMASK(15, 9) << 16),
+ },
+
+ [PCI_EXP_RTCTL / 4] = {
+ /*
+ * Root control has bits [4:0] RW, the rest is
+ * reserved.
+ *
+ * Root status has bit 0 RO, the rest is reserved.
+ */
+ .rw = (PCI_EXP_RTCTL_SECEE | PCI_EXP_RTCTL_SENFEE |
+ PCI_EXP_RTCTL_SEFEE | PCI_EXP_RTCTL_PMEIE |
+ PCI_EXP_RTCTL_CRSSVE),
+ .ro = PCI_EXP_RTCAP_CRSVIS << 16,
+ .rsvd = GENMASK(15, 5) | (GENMASK(15, 1) << 16),
+ },
+
+ [PCI_EXP_RTSTA / 4] = {
+ .ro = GENMASK(15, 0) | PCI_EXP_RTSTA_PENDING,
+ .w1c = PCI_EXP_RTSTA_PME,
+ .rsvd = GENMASK(31, 18),
+ },
+};
+
+/*
+ * Should be called by the PCI controller driver when reading the PCI
+ * configuration space of the fake bridge. It will call back the
+ * ->ops->read_base or ->ops->read_pcie operations.
+ */
+int pci_bridge_emul_conf_read(struct pci_bridge_emul *bridge, int where,
+ int size, u32 *value)
+{
+ int ret;
+ int reg = where & ~3;
+ pci_bridge_emul_read_status_t (*read_op)(struct pci_bridge_emul *bridge,
+ int reg, u32 *value);
+ u32 *cfgspace;
+ const struct pci_bridge_reg_behavior *behavior;
+
+ if (bridge->has_pcie && reg >= PCI_CAP_PCIE_END) {
+ *value = 0;
+ return PCIBIOS_SUCCESSFUL;
+ }
+
+ if (!bridge->has_pcie && reg >= PCI_BRIDGE_CONF_END) {
+ *value = 0;
+ return PCIBIOS_SUCCESSFUL;
+ }
+
+ if (bridge->has_pcie && reg >= PCI_CAP_PCIE_START) {
+ reg -= PCI_CAP_PCIE_START;
+ read_op = bridge->ops->read_pcie;
+ cfgspace = (u32 *) &bridge->pcie_conf;
+ behavior = pcie_cap_regs_behavior;
+ } else {
+ read_op = bridge->ops->read_base;
+ cfgspace = (u32 *) &bridge->conf;
+ behavior = pci_regs_behavior;
+ }
+
+ if (read_op)
+ ret = read_op(bridge, reg, value);
+ else
+ ret = PCI_BRIDGE_EMUL_NOT_HANDLED;
+
+ if (ret == PCI_BRIDGE_EMUL_NOT_HANDLED)
+ *value = cfgspace[reg / 4];
+
+ /*
+ * Make sure we never return any reserved bit with a value
+ * different from 0.
+ */
+ *value &= ~behavior[reg / 4].rsvd;
+
+ if (size == 1)
+ *value = (*value >> (8 * (where & 3))) & 0xff;
+ else if (size == 2)
+ *value = (*value >> (8 * (where & 3))) & 0xffff;
+ else if (size != 4)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+/*
+ * Should be called by the PCI controller driver when writing the PCI
+ * configuration space of the fake bridge. It will call back the
+ * ->ops->write_base or ->ops->write_pcie operations.
+ */
+int pci_bridge_emul_conf_write(struct pci_bridge_emul *bridge, int where,
+ int size, u32 value)
+{
+ int reg = where & ~3;
+ int mask, ret, old, new, shift;
+ void (*write_op)(struct pci_bridge_emul *bridge, int reg,
+ u32 old, u32 new, u32 mask);
+ u32 *cfgspace;
+ const struct pci_bridge_reg_behavior *behavior;
+
+ if (bridge->has_pcie && reg >= PCI_CAP_PCIE_END)
+ return PCIBIOS_SUCCESSFUL;
+
+ if (!bridge->has_pcie && reg >= PCI_BRIDGE_CONF_END)
+ return PCIBIOS_SUCCESSFUL;
+
+ shift = (where & 0x3) * 8;
+
+ if (size == 4)
+ mask = 0xffffffff;
+ else if (size == 2)
+ mask = 0xffff << shift;
+ else if (size == 1)
+ mask = 0xff << shift;
+ else
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ ret = pci_bridge_emul_conf_read(bridge, reg, 4, &old);
+ if (ret != PCIBIOS_SUCCESSFUL)
+ return ret;
+
+ if (bridge->has_pcie && reg >= PCI_CAP_PCIE_START) {
+ reg -= PCI_CAP_PCIE_START;
+ write_op = bridge->ops->write_pcie;
+ cfgspace = (u32 *) &bridge->pcie_conf;
+ behavior = pcie_cap_regs_behavior;
+ } else {
+ write_op = bridge->ops->write_base;
+ cfgspace = (u32 *) &bridge->conf;
+ behavior = pci_regs_behavior;
+ }
+
+ /* Keep all bits, except the RW bits */
+ new = old & (~mask | ~behavior[reg / 4].rw);
+
+ /* Update the value of the RW bits */
+ new |= (value << shift) & (behavior[reg / 4].rw & mask);
+
+ /* Clear the W1C bits */
+ new &= ~((value << shift) & (behavior[reg / 4].w1c & mask));
+
+ cfgspace[reg / 4] = new;
+
+ if (write_op)
+ write_op(bridge, reg, old, new, mask);
+
+ return PCIBIOS_SUCCESSFUL;
+}
diff --git a/drivers/pci/pci-bridge-emul.h b/drivers/pci/pci-bridge-emul.h
new file mode 100644
index 000000000000..9d510ccf738b
--- /dev/null
+++ b/drivers/pci/pci-bridge-emul.h
@@ -0,0 +1,124 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __PCI_BRIDGE_EMUL_H__
+#define __PCI_BRIDGE_EMUL_H__
+
+#include <linux/kernel.h>
+
+/* PCI configuration space of a PCI-to-PCI bridge. */
+struct pci_bridge_emul_conf {
+ u16 vendor;
+ u16 device;
+ u16 command;
+ u16 status;
+ u32 class_revision;
+ u8 cache_line_size;
+ u8 latency_timer;
+ u8 header_type;
+ u8 bist;
+ u32 bar[2];
+ u8 primary_bus;
+ u8 secondary_bus;
+ u8 subordinate_bus;
+ u8 secondary_latency_timer;
+ u8 iobase;
+ u8 iolimit;
+ u16 secondary_status;
+ u16 membase;
+ u16 memlimit;
+ u16 pref_mem_base;
+ u16 pref_mem_limit;
+ u32 prefbaseupper;
+ u32 preflimitupper;
+ u16 iobaseupper;
+ u16 iolimitupper;
+ u8 capabilities_pointer;
+ u8 reserve[3];
+ u32 romaddr;
+ u8 intline;
+ u8 intpin;
+ u16 bridgectrl;
+};
+
+/* PCI configuration space of the PCIe capabilities */
+struct pci_bridge_emul_pcie_conf {
+ u8 cap_id;
+ u8 next;
+ u16 cap;
+ u32 devcap;
+ u16 devctl;
+ u16 devsta;
+ u32 lnkcap;
+ u16 lnkctl;
+ u16 lnksta;
+ u32 slotcap;
+ u16 slotctl;
+ u16 slotsta;
+ u16 rootctl;
+ u16 rsvd;
+ u32 rootsta;
+ u32 devcap2;
+ u16 devctl2;
+ u16 devsta2;
+ u32 lnkcap2;
+ u16 lnkctl2;
+ u16 lnksta2;
+ u32 slotcap2;
+ u16 slotctl2;
+ u16 slotsta2;
+};
+
+struct pci_bridge_emul;
+
+typedef enum { PCI_BRIDGE_EMUL_HANDLED,
+ PCI_BRIDGE_EMUL_NOT_HANDLED } pci_bridge_emul_read_status_t;
+
+struct pci_bridge_emul_ops {
+ /*
+ * Called when reading from the regular PCI bridge
+ * configuration space. Return PCI_BRIDGE_EMUL_HANDLED when the
+ * operation has handled the read operation and filled in the
+ * *value, or PCI_BRIDGE_EMUL_NOT_HANDLED when the read should
+ * be emulated by the common code by reading from the
+ * in-memory copy of the configuration space.
+ */
+ pci_bridge_emul_read_status_t (*read_base)(struct pci_bridge_emul *bridge,
+ int reg, u32 *value);
+
+ /*
+ * Same as ->read_base(), except it is for reading from the
+ * PCIe capability configuration space.
+ */
+ pci_bridge_emul_read_status_t (*read_pcie)(struct pci_bridge_emul *bridge,
+ int reg, u32 *value);
+ /*
+ * Called when writing to the regular PCI bridge configuration
+ * space. old is the current value, new is the new value being
+ * written, and mask indicates which parts of the value are
+ * being changed.
+ */
+ void (*write_base)(struct pci_bridge_emul *bridge, int reg,
+ u32 old, u32 new, u32 mask);
+
+ /*
+ * Same as ->write_base(), except it is for writing from the
+ * PCIe capability configuration space.
+ */
+ void (*write_pcie)(struct pci_bridge_emul *bridge, int reg,
+ u32 old, u32 new, u32 mask);
+};
+
+struct pci_bridge_emul {
+ struct pci_bridge_emul_conf conf;
+ struct pci_bridge_emul_pcie_conf pcie_conf;
+ struct pci_bridge_emul_ops *ops;
+ void *data;
+ bool has_pcie;
+};
+
+void pci_bridge_emul_init(struct pci_bridge_emul *bridge);
+int pci_bridge_emul_conf_read(struct pci_bridge_emul *bridge, int where,
+ int size, u32 *value);
+int pci_bridge_emul_conf_write(struct pci_bridge_emul *bridge, int where,
+ int size, u32 value);
+
+#endif /* __PCI_BRIDGE_EMUL_H__ */
diff --git a/drivers/pci/pci-mid.c b/drivers/pci/pci-mid.c
index 314e135014dc..30fbe2ea6eab 100644
--- a/drivers/pci/pci-mid.c
+++ b/drivers/pci/pci-mid.c
@@ -62,8 +62,8 @@ static const struct pci_platform_pm_ops mid_pci_platform_pm = {
* arch/x86/platform/intel-mid/pwr.c.
*/
static const struct x86_cpu_id lpss_cpu_ids[] = {
- ICPU(INTEL_FAM6_ATOM_PENWELL),
- ICPU(INTEL_FAM6_ATOM_MERRIFIELD),
+ ICPU(INTEL_FAM6_ATOM_SALTWELL_MID),
+ ICPU(INTEL_FAM6_ATOM_SILVERMONT_MID),
{}
};
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 1835f3a7aa8d..d068f11d08a7 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -35,6 +35,8 @@
#include <linux/aer.h>
#include "pci.h"
+DEFINE_MUTEX(pci_slot_mutex);
+
const char *pci_power_names[] = {
"error", "D0", "D1", "D2", "D3hot", "D3cold", "unknown",
};
@@ -196,7 +198,7 @@ EXPORT_SYMBOL_GPL(pci_ioremap_wc_bar);
/**
* pci_dev_str_match_path - test if a path string matches a device
* @dev: the PCI device to test
- * @p: string to match the device against
+ * @path: string to match the device against
* @endptr: pointer to the string after the match
*
* Test if a string (typically from a kernel parameter) formatted as a
@@ -791,6 +793,11 @@ static inline bool platform_pci_need_resume(struct pci_dev *dev)
return pci_platform_pm ? pci_platform_pm->need_resume(dev) : false;
}
+static inline bool platform_pci_bridge_d3(struct pci_dev *dev)
+{
+ return pci_platform_pm ? pci_platform_pm->bridge_d3(dev) : false;
+}
+
/**
* pci_raw_set_power_state - Use PCI PM registers to set the power state of
* given PCI device
@@ -999,7 +1006,7 @@ static void __pci_start_power_transition(struct pci_dev *dev, pci_power_t state)
* because have already delayed for the bridge.
*/
if (dev->runtime_d3cold) {
- if (dev->d3cold_delay)
+ if (dev->d3cold_delay && !dev->imm_ready)
msleep(dev->d3cold_delay);
/*
* When powering on a bridge from D3cold, the
@@ -1284,17 +1291,18 @@ int pci_save_state(struct pci_dev *dev)
if (i != 0)
return i;
+ pci_save_dpc_state(dev);
return pci_save_vc_state(dev);
}
EXPORT_SYMBOL(pci_save_state);
static void pci_restore_config_dword(struct pci_dev *pdev, int offset,
- u32 saved_val, int retry)
+ u32 saved_val, int retry, bool force)
{
u32 val;
pci_read_config_dword(pdev, offset, &val);
- if (val == saved_val)
+ if (!force && val == saved_val)
return;
for (;;) {
@@ -1313,25 +1321,36 @@ static void pci_restore_config_dword(struct pci_dev *pdev, int offset,
}
static void pci_restore_config_space_range(struct pci_dev *pdev,
- int start, int end, int retry)
+ int start, int end, int retry,
+ bool force)
{
int index;
for (index = end; index >= start; index--)
pci_restore_config_dword(pdev, 4 * index,
pdev->saved_config_space[index],
- retry);
+ retry, force);
}
static void pci_restore_config_space(struct pci_dev *pdev)
{
if (pdev->hdr_type == PCI_HEADER_TYPE_NORMAL) {
- pci_restore_config_space_range(pdev, 10, 15, 0);
+ pci_restore_config_space_range(pdev, 10, 15, 0, false);
/* Restore BARs before the command register. */
- pci_restore_config_space_range(pdev, 4, 9, 10);
- pci_restore_config_space_range(pdev, 0, 3, 0);
+ pci_restore_config_space_range(pdev, 4, 9, 10, false);
+ pci_restore_config_space_range(pdev, 0, 3, 0, false);
+ } else if (pdev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
+ pci_restore_config_space_range(pdev, 12, 15, 0, false);
+
+ /*
+ * Force rewriting of prefetch registers to avoid S3 resume
+ * issues on Intel PCI bridges that occur when these
+ * registers are not explicitly written.
+ */
+ pci_restore_config_space_range(pdev, 9, 11, 0, true);
+ pci_restore_config_space_range(pdev, 0, 8, 0, false);
} else {
- pci_restore_config_space_range(pdev, 0, 15, 0);
+ pci_restore_config_space_range(pdev, 0, 15, 0, false);
}
}
@@ -1378,6 +1397,7 @@ void pci_restore_state(struct pci_dev *dev)
pci_restore_ats_state(dev);
pci_restore_vc_state(dev);
pci_restore_rebar_state(dev);
+ pci_restore_dpc_state(dev);
pci_cleanup_aer_error_status_regs(dev);
@@ -2133,10 +2153,13 @@ static int __pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable
int ret = 0;
/*
- * Bridges can only signal wakeup on behalf of subordinate devices,
- * but that is set up elsewhere, so skip them.
+ * Bridges that are not power-manageable directly only signal
+ * wakeup on behalf of subordinate devices which is set up
+ * elsewhere, so skip them. However, bridges that are
+ * power-manageable may signal wakeup for themselves (for example,
+ * on a hotplug event) and they need to be covered here.
*/
- if (pci_has_subordinate(dev))
+ if (!pci_power_manageable(dev))
return 0;
/* Don't do the same thing twice in a row for one device. */
@@ -2511,6 +2534,10 @@ bool pci_bridge_d3_possible(struct pci_dev *bridge)
if (bridge->is_thunderbolt)
return true;
+ /* Platform might know better if the bridge supports D3 */
+ if (platform_pci_bridge_d3(bridge))
+ return true;
+
/*
* Hotplug ports handled natively by the OS were not validated
* by vendors for runtime D3 at least until 2018 because there
@@ -2644,6 +2671,7 @@ EXPORT_SYMBOL_GPL(pci_d3cold_disable);
void pci_pm_init(struct pci_dev *dev)
{
int pm;
+ u16 status;
u16 pmc;
pm_runtime_forbid(&dev->dev);
@@ -2706,6 +2734,10 @@ void pci_pm_init(struct pci_dev *dev)
/* Disable the PME# generation functionality */
pci_pme_active(dev, false);
}
+
+ pci_read_config_word(dev, PCI_STATUS, &status);
+ if (status & PCI_STATUS_IMM_READY)
+ dev->imm_ready = 1;
}
static unsigned long pci_ea_flags(struct pci_dev *dev, u8 prop)
@@ -4376,6 +4408,9 @@ int pcie_flr(struct pci_dev *dev)
pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_BCR_FLR);
+ if (dev->imm_ready)
+ return 0;
+
/*
* Per PCIe r4.0, sec 6.6.2, a device must complete an FLR within
* 100ms, but may silently discard requests while the FLR is in
@@ -4417,6 +4452,9 @@ static int pci_af_flr(struct pci_dev *dev, int probe)
pci_write_config_byte(dev, pos + PCI_AF_CTRL, PCI_AF_CTRL_FLR);
+ if (dev->imm_ready)
+ return 0;
+
/*
* Per Advanced Capabilities for Conventional PCI ECN, 13 April 2006,
* updated 27 July 2006; a device must complete an FLR within
@@ -4485,21 +4523,42 @@ bool pcie_wait_for_link(struct pci_dev *pdev, bool active)
bool ret;
u16 lnk_status;
+ /*
+ * Some controllers might not implement link active reporting. In this
+ * case, we wait for 1000 + 100 ms.
+ */
+ if (!pdev->link_active_reporting) {
+ msleep(1100);
+ return true;
+ }
+
+ /*
+ * PCIe r4.0 sec 6.6.1, a component must enter LTSSM Detect within 20ms,
+ * after which we should expect an link active if the reset was
+ * successful. If so, software must wait a minimum 100ms before sending
+ * configuration requests to devices downstream this port.
+ *
+ * If the link fails to activate, either the device was physically
+ * removed or the link is permanently failed.
+ */
+ if (active)
+ msleep(20);
for (;;) {
pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnk_status);
ret = !!(lnk_status & PCI_EXP_LNKSTA_DLLLA);
if (ret == active)
- return true;
+ break;
if (timeout <= 0)
break;
msleep(10);
timeout -= 10;
}
-
- pci_info(pdev, "Data Link Layer Link Active not %s in 1000 msec\n",
- active ? "set" : "cleared");
-
- return false;
+ if (active && ret)
+ msleep(100);
+ else if (ret != active)
+ pci_info(pdev, "Data Link Layer Link Active not %s in 1000 msec\n",
+ active ? "set" : "cleared");
+ return ret == active;
}
void pci_reset_secondary_bus(struct pci_dev *dev)
@@ -4571,13 +4630,13 @@ static int pci_reset_hotplug_slot(struct hotplug_slot *hotplug, int probe)
{
int rc = -ENOTTY;
- if (!hotplug || !try_module_get(hotplug->ops->owner))
+ if (!hotplug || !try_module_get(hotplug->owner))
return rc;
if (hotplug->ops->reset_slot)
rc = hotplug->ops->reset_slot(hotplug, probe);
- module_put(hotplug->ops->owner);
+ module_put(hotplug->owner);
return rc;
}
@@ -5154,6 +5213,41 @@ static int pci_bus_reset(struct pci_bus *bus, int probe)
}
/**
+ * pci_bus_error_reset - reset the bridge's subordinate bus
+ * @bridge: The parent device that connects to the bus to reset
+ *
+ * This function will first try to reset the slots on this bus if the method is
+ * available. If slot reset fails or is not available, this will fall back to a
+ * secondary bus reset.
+ */
+int pci_bus_error_reset(struct pci_dev *bridge)
+{
+ struct pci_bus *bus = bridge->subordinate;
+ struct pci_slot *slot;
+
+ if (!bus)
+ return -ENOTTY;
+
+ mutex_lock(&pci_slot_mutex);
+ if (list_empty(&bus->slots))
+ goto bus_reset;
+
+ list_for_each_entry(slot, &bus->slots, list)
+ if (pci_probe_reset_slot(slot))
+ goto bus_reset;
+
+ list_for_each_entry(slot, &bus->slots, list)
+ if (pci_slot_reset(slot, 0))
+ goto bus_reset;
+
+ mutex_unlock(&pci_slot_mutex);
+ return 0;
+bus_reset:
+ mutex_unlock(&pci_slot_mutex);
+ return pci_bus_reset(bridge->subordinate, 0);
+}
+
+/**
* pci_probe_reset_bus - probe whether a PCI bus can be reset
* @bus: PCI bus to probe
*
@@ -5690,8 +5784,7 @@ int pci_set_vga_state(struct pci_dev *dev, bool decode,
void pci_add_dma_alias(struct pci_dev *dev, u8 devfn)
{
if (!dev->dma_alias_mask)
- dev->dma_alias_mask = kcalloc(BITS_TO_LONGS(U8_MAX),
- sizeof(long), GFP_KERNEL);
+ dev->dma_alias_mask = bitmap_zalloc(U8_MAX, GFP_KERNEL);
if (!dev->dma_alias_mask) {
pci_warn(dev, "Unable to allocate DMA alias mask\n");
return;
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 6e0d1528d471..662b7457db23 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -35,10 +35,13 @@ int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vmai,
int pci_probe_reset_function(struct pci_dev *dev);
int pci_bridge_secondary_bus_reset(struct pci_dev *dev);
+int pci_bus_error_reset(struct pci_dev *dev);
/**
* struct pci_platform_pm_ops - Firmware PM callbacks
*
+ * @bridge_d3: Does the bridge allow entering into D3
+ *
* @is_manageable: returns 'true' if given device is power manageable by the
* platform firmware
*
@@ -60,6 +63,7 @@ int pci_bridge_secondary_bus_reset(struct pci_dev *dev);
* these callbacks are mandatory.
*/
struct pci_platform_pm_ops {
+ bool (*bridge_d3)(struct pci_dev *dev);
bool (*is_manageable)(struct pci_dev *dev);
int (*set_state)(struct pci_dev *dev, pci_power_t state);
pci_power_t (*get_state)(struct pci_dev *dev);
@@ -136,6 +140,7 @@ static inline void pci_remove_legacy_files(struct pci_bus *bus) { return; }
/* Lock for read/write access to pci device and bus lists */
extern struct rw_semaphore pci_bus_sem;
+extern struct mutex pci_slot_mutex;
extern raw_spinlock_t pci_lock;
@@ -285,6 +290,7 @@ struct pci_sriov {
u16 driver_max_VFs; /* Max num VFs driver supports */
struct pci_dev *dev; /* Lowest numbered PF */
struct pci_dev *self; /* This PF */
+ u32 cfg_size; /* VF config space size */
u32 class; /* VF device */
u8 hdr_type; /* VF header type */
u16 subsystem_vendor; /* VF subsystem vendor */
@@ -293,21 +299,71 @@ struct pci_sriov {
bool drivers_autoprobe; /* Auto probing of VFs by driver */
};
-/* pci_dev priv_flags */
-#define PCI_DEV_DISCONNECTED 0
-#define PCI_DEV_ADDED 1
+/**
+ * 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
+ *
+ * Must be called with device_lock held.
+ *
+ * Returns true if state has been changed to the requested state.
+ */
+static inline bool pci_dev_set_io_state(struct pci_dev *dev,
+ pci_channel_state_t new)
+{
+ bool changed = false;
+
+ device_lock_assert(&dev->dev);
+ switch (new) {
+ case pci_channel_io_perm_failure:
+ switch (dev->error_state) {
+ case pci_channel_io_frozen:
+ case pci_channel_io_normal:
+ case pci_channel_io_perm_failure:
+ changed = true;
+ break;
+ }
+ break;
+ case pci_channel_io_frozen:
+ switch (dev->error_state) {
+ case pci_channel_io_frozen:
+ case pci_channel_io_normal:
+ changed = true;
+ break;
+ }
+ break;
+ case pci_channel_io_normal:
+ switch (dev->error_state) {
+ case pci_channel_io_frozen:
+ case pci_channel_io_normal:
+ changed = true;
+ break;
+ }
+ break;
+ }
+ if (changed)
+ dev->error_state = new;
+ return changed;
+}
static inline int pci_dev_set_disconnected(struct pci_dev *dev, void *unused)
{
- set_bit(PCI_DEV_DISCONNECTED, &dev->priv_flags);
+ device_lock(&dev->dev);
+ pci_dev_set_io_state(dev, pci_channel_io_perm_failure);
+ device_unlock(&dev->dev);
+
return 0;
}
static inline bool pci_dev_is_disconnected(const struct pci_dev *dev)
{
- return test_bit(PCI_DEV_DISCONNECTED, &dev->priv_flags);
+ return dev->error_state == pci_channel_io_perm_failure;
}
+/* pci_dev priv_flags */
+#define PCI_DEV_ADDED 0
+
static inline void pci_dev_assign_added(struct pci_dev *dev, bool added)
{
assign_bit(PCI_DEV_ADDED, &dev->priv_flags, added);
@@ -346,6 +402,14 @@ int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info);
void aer_print_error(struct pci_dev *dev, struct aer_err_info *info);
#endif /* CONFIG_PCIEAER */
+#ifdef CONFIG_PCIE_DPC
+void pci_save_dpc_state(struct pci_dev *dev);
+void pci_restore_dpc_state(struct pci_dev *dev);
+#else
+static inline void pci_save_dpc_state(struct pci_dev *dev) {}
+static inline void pci_restore_dpc_state(struct pci_dev *dev) {}
+#endif
+
#ifdef CONFIG_PCI_ATS
void pci_restore_ats_state(struct pci_dev *dev);
#else
@@ -423,8 +487,8 @@ static inline int pci_dev_specific_disable_acs_redir(struct pci_dev *dev)
#endif
/* PCI error reporting and recovery */
-void pcie_do_fatal_recovery(struct pci_dev *dev, u32 service);
-void pcie_do_nonfatal_recovery(struct pci_dev *dev);
+void pcie_do_recovery(struct pci_dev *dev, enum pci_channel_state state,
+ u32 service);
bool pcie_wait_for_link(struct pci_dev *pdev, bool active);
#ifdef CONFIG_PCIEASPM
diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig
index 0a1e9d379bc5..44742b2e1126 100644
--- a/drivers/pci/pcie/Kconfig
+++ b/drivers/pci/pcie/Kconfig
@@ -36,7 +36,6 @@ config PCIEAER
config PCIEAER_INJECT
tristate "PCI Express error injection support"
depends on PCIEAER
- default n
help
This enables PCI Express Root Port Advanced Error Reporting
(AER) software error injector.
@@ -84,7 +83,6 @@ config PCIEASPM
config PCIEASPM_DEBUG
bool "Debug PCI Express ASPM"
depends on PCIEASPM
- default n
help
This enables PCI Express ASPM debug support. It will add per-device
interface to control ASPM.
@@ -129,7 +127,6 @@ config PCIE_PME
config PCIE_DPC
bool "PCI Express Downstream Port Containment support"
depends on PCIEPORTBUS && PCIEAER
- default n
help
This enables PCI Express Downstream Port Containment (DPC)
driver support. DPC events from Root and Downstream ports
@@ -139,7 +136,6 @@ config PCIE_DPC
config PCIE_PTM
bool "PCI Express Precision Time Measurement support"
- default n
depends on PCIEPORTBUS
help
This enables PCI Express Precision Time Measurement (PTM)
diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
index 83180edd6ed4..a90a9194ac4a 100644
--- a/drivers/pci/pcie/aer.c
+++ b/drivers/pci/pcie/aer.c
@@ -30,7 +30,7 @@
#include "../pci.h"
#include "portdrv.h"
-#define AER_ERROR_SOURCES_MAX 100
+#define AER_ERROR_SOURCES_MAX 128
#define AER_MAX_TYPEOF_COR_ERRS 16 /* as per PCI_ERR_COR_STATUS */
#define AER_MAX_TYPEOF_UNCOR_ERRS 26 /* as per PCI_ERR_UNCOR_STATUS*/
@@ -42,21 +42,7 @@ struct aer_err_source {
struct aer_rpc {
struct pci_dev *rpd; /* Root Port device */
- struct work_struct dpc_handler;
- struct aer_err_source e_sources[AER_ERROR_SOURCES_MAX];
- struct aer_err_info e_info;
- unsigned short prod_idx; /* Error Producer Index */
- unsigned short cons_idx; /* Error Consumer Index */
- int isr;
- spinlock_t e_lock; /*
- * Lock access to Error Status/ID Regs
- * and error producer/consumer index
- */
- struct mutex rpc_mutex; /*
- * only one thread could do
- * recovery on the same
- * root port hierarchy
- */
+ DECLARE_KFIFO(aer_fifo, struct aer_err_source, AER_ERROR_SOURCES_MAX);
};
/* AER stats for the device */
@@ -866,7 +852,7 @@ void cper_print_aer(struct pci_dev *dev, int aer_severity,
static int add_error_device(struct aer_err_info *e_info, struct pci_dev *dev)
{
if (e_info->error_dev_num < AER_MAX_MULTI_ERR_DEVICES) {
- e_info->dev[e_info->error_dev_num] = dev;
+ e_info->dev[e_info->error_dev_num] = pci_dev_get(dev);
e_info->error_dev_num++;
return 0;
}
@@ -1010,9 +996,12 @@ static void handle_error_source(struct pci_dev *dev, struct aer_err_info *info)
info->status);
pci_aer_clear_device_status(dev);
} else if (info->severity == AER_NONFATAL)
- pcie_do_nonfatal_recovery(dev);
+ pcie_do_recovery(dev, pci_channel_io_normal,
+ PCIE_PORT_SERVICE_AER);
else if (info->severity == AER_FATAL)
- pcie_do_fatal_recovery(dev, PCIE_PORT_SERVICE_AER);
+ pcie_do_recovery(dev, pci_channel_io_frozen,
+ PCIE_PORT_SERVICE_AER);
+ pci_dev_put(dev);
}
#ifdef CONFIG_ACPI_APEI_PCIEAER
@@ -1047,9 +1036,11 @@ static void aer_recover_work_func(struct work_struct *work)
}
cper_print_aer(pdev, entry.severity, entry.regs);
if (entry.severity == AER_NONFATAL)
- pcie_do_nonfatal_recovery(pdev);
+ pcie_do_recovery(pdev, pci_channel_io_normal,
+ PCIE_PORT_SERVICE_AER);
else if (entry.severity == AER_FATAL)
- pcie_do_fatal_recovery(pdev, PCIE_PORT_SERVICE_AER);
+ pcie_do_recovery(pdev, pci_channel_io_frozen,
+ PCIE_PORT_SERVICE_AER);
pci_dev_put(pdev);
}
}
@@ -1065,7 +1056,6 @@ static DECLARE_WORK(aer_recover_work, aer_recover_work_func);
void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn,
int severity, struct aer_capability_regs *aer_regs)
{
- unsigned long flags;
struct aer_recover_entry entry = {
.bus = bus,
.devfn = devfn,
@@ -1074,13 +1064,12 @@ void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn,
.regs = aer_regs,
};
- spin_lock_irqsave(&aer_recover_ring_lock, flags);
- if (kfifo_put(&aer_recover_ring, entry))
+ if (kfifo_in_spinlocked(&aer_recover_ring, &entry, sizeof(entry),
+ &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",
domain, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
- spin_unlock_irqrestore(&aer_recover_ring_lock, flags);
}
EXPORT_SYMBOL_GPL(aer_recover_queue);
#endif
@@ -1115,8 +1104,9 @@ int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info)
&info->mask);
if (!(info->status & ~info->mask))
return 0;
- } else if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
- info->severity == AER_NONFATAL) {
+ } else if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT ||
+ pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM ||
+ info->severity == AER_NONFATAL) {
/* Link is still healthy for IO reads */
pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS,
@@ -1170,7 +1160,7 @@ static void aer_isr_one_error(struct aer_rpc *rpc,
struct aer_err_source *e_src)
{
struct pci_dev *pdev = rpc->rpd;
- struct aer_err_info *e_info = &rpc->e_info;
+ struct aer_err_info e_info;
pci_rootport_aer_stats_incr(pdev, e_src);
@@ -1179,83 +1169,57 @@ static void aer_isr_one_error(struct aer_rpc *rpc,
* uncorrectable error being logged. Report correctable error first.
*/
if (e_src->status & PCI_ERR_ROOT_COR_RCV) {
- e_info->id = ERR_COR_ID(e_src->id);
- e_info->severity = AER_CORRECTABLE;
+ e_info.id = ERR_COR_ID(e_src->id);
+ e_info.severity = AER_CORRECTABLE;
if (e_src->status & PCI_ERR_ROOT_MULTI_COR_RCV)
- e_info->multi_error_valid = 1;
+ e_info.multi_error_valid = 1;
else
- e_info->multi_error_valid = 0;
- aer_print_port_info(pdev, e_info);
+ e_info.multi_error_valid = 0;
+ aer_print_port_info(pdev, &e_info);
- if (find_source_device(pdev, e_info))
- aer_process_err_devices(e_info);
+ if (find_source_device(pdev, &e_info))
+ aer_process_err_devices(&e_info);
}
if (e_src->status & PCI_ERR_ROOT_UNCOR_RCV) {
- e_info->id = ERR_UNCOR_ID(e_src->id);
+ e_info.id = ERR_UNCOR_ID(e_src->id);
if (e_src->status & PCI_ERR_ROOT_FATAL_RCV)
- e_info->severity = AER_FATAL;
+ e_info.severity = AER_FATAL;
else
- e_info->severity = AER_NONFATAL;
+ e_info.severity = AER_NONFATAL;
if (e_src->status & PCI_ERR_ROOT_MULTI_UNCOR_RCV)
- e_info->multi_error_valid = 1;
+ e_info.multi_error_valid = 1;
else
- e_info->multi_error_valid = 0;
+ e_info.multi_error_valid = 0;
- aer_print_port_info(pdev, e_info);
+ aer_print_port_info(pdev, &e_info);
- if (find_source_device(pdev, e_info))
- aer_process_err_devices(e_info);
+ if (find_source_device(pdev, &e_info))
+ aer_process_err_devices(&e_info);
}
}
/**
- * get_e_source - retrieve an error source
- * @rpc: pointer to the root port which holds an error
- * @e_src: pointer to store retrieved error source
- *
- * Return 1 if an error source is retrieved, otherwise 0.
- *
- * Invoked by DPC handler to consume an error.
- */
-static int get_e_source(struct aer_rpc *rpc, struct aer_err_source *e_src)
-{
- unsigned long flags;
-
- /* Lock access to Root error producer/consumer index */
- spin_lock_irqsave(&rpc->e_lock, flags);
- if (rpc->prod_idx == rpc->cons_idx) {
- spin_unlock_irqrestore(&rpc->e_lock, flags);
- return 0;
- }
-
- *e_src = rpc->e_sources[rpc->cons_idx];
- rpc->cons_idx++;
- if (rpc->cons_idx == AER_ERROR_SOURCES_MAX)
- rpc->cons_idx = 0;
- spin_unlock_irqrestore(&rpc->e_lock, flags);
-
- return 1;
-}
-
-/**
* aer_isr - consume errors detected by root port
* @work: definition of this work item
*
* Invoked, as DPC, when root port records new detected error
*/
-static void aer_isr(struct work_struct *work)
+static irqreturn_t aer_isr(int irq, void *context)
{
- struct aer_rpc *rpc = container_of(work, struct aer_rpc, dpc_handler);
+ struct pcie_device *dev = (struct pcie_device *)context;
+ struct aer_rpc *rpc = get_service_data(dev);
struct aer_err_source uninitialized_var(e_src);
- mutex_lock(&rpc->rpc_mutex);
- while (get_e_source(rpc, &e_src))
+ if (kfifo_is_empty(&rpc->aer_fifo))
+ return IRQ_NONE;
+
+ while (kfifo_get(&rpc->aer_fifo, &e_src))
aer_isr_one_error(rpc, &e_src);
- mutex_unlock(&rpc->rpc_mutex);
+ return IRQ_HANDLED;
}
/**
@@ -1265,56 +1229,26 @@ static void aer_isr(struct work_struct *work)
*
* Invoked when Root Port detects AER messages.
*/
-irqreturn_t aer_irq(int irq, void *context)
+static irqreturn_t aer_irq(int irq, void *context)
{
- unsigned int status, id;
struct pcie_device *pdev = (struct pcie_device *)context;
struct aer_rpc *rpc = get_service_data(pdev);
- int next_prod_idx;
- unsigned long flags;
- int pos;
-
- pos = pdev->port->aer_cap;
- /*
- * Must lock access to Root Error Status Reg, Root Error ID Reg,
- * and Root error producer/consumer index
- */
- spin_lock_irqsave(&rpc->e_lock, flags);
+ struct pci_dev *rp = rpc->rpd;
+ struct aer_err_source e_src = {};
+ int pos = rp->aer_cap;
- /* Read error status */
- pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, &status);
- if (!(status & (PCI_ERR_ROOT_UNCOR_RCV|PCI_ERR_ROOT_COR_RCV))) {
- spin_unlock_irqrestore(&rpc->e_lock, flags);
+ pci_read_config_dword(rp, pos + PCI_ERR_ROOT_STATUS, &e_src.status);
+ if (!(e_src.status & (PCI_ERR_ROOT_UNCOR_RCV|PCI_ERR_ROOT_COR_RCV)))
return IRQ_NONE;
- }
- /* Read error source and clear error status */
- pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_ERR_SRC, &id);
- pci_write_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, status);
+ pci_read_config_dword(rp, pos + PCI_ERR_ROOT_ERR_SRC, &e_src.id);
+ pci_write_config_dword(rp, pos + PCI_ERR_ROOT_STATUS, e_src.status);
- /* Store error source for later DPC handler */
- next_prod_idx = rpc->prod_idx + 1;
- if (next_prod_idx == AER_ERROR_SOURCES_MAX)
- next_prod_idx = 0;
- if (next_prod_idx == rpc->cons_idx) {
- /*
- * Error Storm Condition - possibly the same error occurred.
- * Drop the error.
- */
- spin_unlock_irqrestore(&rpc->e_lock, flags);
+ if (!kfifo_put(&rpc->aer_fifo, e_src))
return IRQ_HANDLED;
- }
- rpc->e_sources[rpc->prod_idx].status = status;
- rpc->e_sources[rpc->prod_idx].id = id;
- rpc->prod_idx = next_prod_idx;
- spin_unlock_irqrestore(&rpc->e_lock, flags);
-
- /* Invoke DPC handler */
- schedule_work(&rpc->dpc_handler);
- return IRQ_HANDLED;
+ return IRQ_WAKE_THREAD;
}
-EXPORT_SYMBOL_GPL(aer_irq);
static int set_device_error_reporting(struct pci_dev *dev, void *data)
{
@@ -1423,33 +1357,6 @@ static void aer_disable_rootport(struct aer_rpc *rpc)
}
/**
- * aer_alloc_rpc - allocate Root Port data structure
- * @dev: pointer to the pcie_dev data structure
- *
- * Invoked when Root Port's AER service is loaded.
- */
-static struct aer_rpc *aer_alloc_rpc(struct pcie_device *dev)
-{
- struct aer_rpc *rpc;
-
- rpc = kzalloc(sizeof(struct aer_rpc), GFP_KERNEL);
- if (!rpc)
- return NULL;
-
- /* Initialize Root lock access, e_lock, to Root Error Status Reg */
- spin_lock_init(&rpc->e_lock);
-
- rpc->rpd = dev->port;
- INIT_WORK(&rpc->dpc_handler, aer_isr);
- mutex_init(&rpc->rpc_mutex);
-
- /* Use PCIe bus function to store rpc into PCIe device */
- set_service_data(dev, rpc);
-
- return rpc;
-}
-
-/**
* aer_remove - clean up resources
* @dev: pointer to the pcie_dev data structure
*
@@ -1459,16 +1366,7 @@ static void aer_remove(struct pcie_device *dev)
{
struct aer_rpc *rpc = get_service_data(dev);
- if (rpc) {
- /* If register interrupt service, it must be free. */
- if (rpc->isr)
- free_irq(dev->irq, dev);
-
- flush_work(&rpc->dpc_handler);
- aer_disable_rootport(rpc);
- kfree(rpc);
- set_service_data(dev, NULL);
- }
+ aer_disable_rootport(rpc);
}
/**
@@ -1481,27 +1379,24 @@ static int aer_probe(struct pcie_device *dev)
{
int status;
struct aer_rpc *rpc;
- struct device *device = &dev->port->dev;
+ struct device *device = &dev->device;
- /* Alloc rpc data structure */
- rpc = aer_alloc_rpc(dev);
+ rpc = devm_kzalloc(device, sizeof(struct aer_rpc), GFP_KERNEL);
if (!rpc) {
dev_printk(KERN_DEBUG, device, "alloc AER rpc failed\n");
- aer_remove(dev);
return -ENOMEM;
}
+ rpc->rpd = dev->port;
+ set_service_data(dev, rpc);
- /* Request IRQ ISR */
- status = request_irq(dev->irq, aer_irq, IRQF_SHARED, "aerdrv", dev);
+ status = devm_request_threaded_irq(device, dev->irq, aer_irq, aer_isr,
+ IRQF_SHARED, "aerdrv", dev);
if (status) {
dev_printk(KERN_DEBUG, device, "request AER IRQ %d failed\n",
dev->irq);
- aer_remove(dev);
return status;
}
- rpc->isr = 1;
-
aer_enable_rootport(rpc);
dev_info(device, "AER enabled with IRQ %d\n", dev->irq);
return 0;
@@ -1526,7 +1421,7 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK;
pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32);
- rc = pci_bridge_secondary_bus_reset(dev);
+ rc = pci_bus_error_reset(dev);
pci_printk(KERN_DEBUG, dev, "Root Port link has been reset\n");
/* Clear Root Error Status */
@@ -1541,18 +1436,6 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
return rc ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED;
}
-/**
- * aer_error_resume - clean up corresponding error status bits
- * @dev: pointer to Root Port's pci_dev data structure
- *
- * Invoked by Port Bus driver during nonfatal recovery.
- */
-static void aer_error_resume(struct pci_dev *dev)
-{
- pci_aer_clear_device_status(dev);
- pci_cleanup_aer_uncorrect_error_status(dev);
-}
-
static struct pcie_port_service_driver aerdriver = {
.name = "aer",
.port_type = PCI_EXP_TYPE_ROOT_PORT,
@@ -1560,7 +1443,6 @@ static struct pcie_port_service_driver aerdriver = {
.probe = aer_probe,
.remove = aer_remove,
- .error_resume = aer_error_resume,
.reset_link = aer_root_reset,
};
@@ -1569,10 +1451,9 @@ static struct pcie_port_service_driver aerdriver = {
*
* Invoked when AER root service driver is loaded.
*/
-static int __init aer_service_init(void)
+int __init pcie_aer_init(void)
{
if (!pci_aer_available() || aer_acpi_firmware_first())
return -ENXIO;
return pcie_port_service_register(&aerdriver);
}
-device_initcall(aer_service_init);
diff --git a/drivers/pci/pcie/aer_inject.c b/drivers/pci/pcie/aer_inject.c
index 0eb24346cad3..95d4759664b3 100644
--- a/drivers/pci/pcie/aer_inject.c
+++ b/drivers/pci/pcie/aer_inject.c
@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/irq.h>
#include <linux/miscdevice.h>
#include <linux/pci.h>
#include <linux/slab.h>
@@ -175,14 +176,48 @@ static u32 *find_pci_config_dword(struct aer_error *err, int where,
return target;
}
+static int aer_inj_read(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, u32 *val)
+{
+ struct pci_ops *ops, *my_ops;
+ int rv;
+
+ ops = __find_pci_bus_ops(bus);
+ if (!ops)
+ return -1;
+
+ my_ops = bus->ops;
+ bus->ops = ops;
+ rv = ops->read(bus, devfn, where, size, val);
+ bus->ops = my_ops;
+
+ return rv;
+}
+
+static int aer_inj_write(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, u32 val)
+{
+ struct pci_ops *ops, *my_ops;
+ int rv;
+
+ ops = __find_pci_bus_ops(bus);
+ if (!ops)
+ return -1;
+
+ my_ops = bus->ops;
+ bus->ops = ops;
+ rv = ops->write(bus, devfn, where, size, val);
+ bus->ops = my_ops;
+
+ return rv;
+}
+
static int aer_inj_read_config(struct pci_bus *bus, unsigned int devfn,
int where, int size, u32 *val)
{
u32 *sim;
struct aer_error *err;
unsigned long flags;
- struct pci_ops *ops;
- struct pci_ops *my_ops;
int domain;
int rv;
@@ -203,18 +238,7 @@ static int aer_inj_read_config(struct pci_bus *bus, unsigned int devfn,
return 0;
}
out:
- ops = __find_pci_bus_ops(bus);
- /*
- * pci_lock must already be held, so we can directly
- * manipulate bus->ops. Many config access functions,
- * including pci_generic_config_read() require the original
- * bus->ops be installed to function, so temporarily put them
- * back.
- */
- my_ops = bus->ops;
- bus->ops = ops;
- rv = ops->read(bus, devfn, where, size, val);
- bus->ops = my_ops;
+ rv = aer_inj_read(bus, devfn, where, size, val);
spin_unlock_irqrestore(&inject_lock, flags);
return rv;
}
@@ -226,8 +250,6 @@ static int aer_inj_write_config(struct pci_bus *bus, unsigned int devfn,
struct aer_error *err;
unsigned long flags;
int rw1cs;
- struct pci_ops *ops;
- struct pci_ops *my_ops;
int domain;
int rv;
@@ -251,18 +273,7 @@ static int aer_inj_write_config(struct pci_bus *bus, unsigned int devfn,
return 0;
}
out:
- ops = __find_pci_bus_ops(bus);
- /*
- * pci_lock must already be held, so we can directly
- * manipulate bus->ops. Many config access functions,
- * including pci_generic_config_write() require the original
- * bus->ops be installed to function, so temporarily put them
- * back.
- */
- my_ops = bus->ops;
- bus->ops = ops;
- rv = ops->write(bus, devfn, where, size, val);
- bus->ops = my_ops;
+ rv = aer_inj_write(bus, devfn, where, size, val);
spin_unlock_irqrestore(&inject_lock, flags);
return rv;
}
@@ -303,32 +314,13 @@ out:
return 0;
}
-static int find_aer_device_iter(struct device *device, void *data)
-{
- struct pcie_device **result = data;
- struct pcie_device *pcie_dev;
-
- if (device->bus == &pcie_port_bus_type) {
- pcie_dev = to_pcie_device(device);
- if (pcie_dev->service & PCIE_PORT_SERVICE_AER) {
- *result = pcie_dev;
- return 1;
- }
- }
- return 0;
-}
-
-static int find_aer_device(struct pci_dev *dev, struct pcie_device **result)
-{
- return device_for_each_child(&dev->dev, result, find_aer_device_iter);
-}
-
static int aer_inject(struct aer_error_inj *einj)
{
struct aer_error *err, *rperr;
struct aer_error *err_alloc = NULL, *rperr_alloc = NULL;
struct pci_dev *dev, *rpdev;
struct pcie_device *edev;
+ struct device *device;
unsigned long flags;
unsigned int devfn = PCI_DEVFN(einj->dev, einj->fn);
int pos_cap_err, rp_pos_cap_err;
@@ -464,7 +456,9 @@ static int aer_inject(struct aer_error_inj *einj)
if (ret)
goto out_put;
- if (find_aer_device(rpdev, &edev)) {
+ device = pcie_port_find_device(rpdev, PCIE_PORT_SERVICE_AER);
+ if (device) {
+ edev = to_pcie_device(device);
if (!get_service_data(edev)) {
dev_warn(&edev->device,
"aer_inject: AER service is not initialized\n");
@@ -474,7 +468,9 @@ static int aer_inject(struct aer_error_inj *einj)
dev_info(&edev->device,
"aer_inject: Injecting errors %08x/%08x into device %s\n",
einj->cor_status, einj->uncor_status, pci_name(dev));
- aer_irq(-1, edev);
+ local_irq_disable();
+ generic_handle_irq(edev->irq);
+ local_irq_enable();
} else {
pci_err(rpdev, "aer_inject: AER device not found\n");
ret = -ENODEV;
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 5326916715d2..dcb29cb76dc6 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -895,7 +895,7 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
struct pcie_link_state *link;
int blacklist = !!pcie_aspm_sanity_check(pdev);
- if (!aspm_support_enabled)
+ if (!aspm_support_enabled || aspm_disabled)
return;
if (pdev->link_state)
@@ -991,7 +991,7 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev)
* All PCIe functions are in one slot, remove one function will remove
* the whole slot, so just wait until we are the last function left.
*/
- if (!list_is_last(&pdev->bus_list, &parent->subordinate->devices))
+ if (!list_empty(&parent->subordinate->devices))
goto out;
link = parent->link_state;
diff --git a/drivers/pci/pcie/dpc.c b/drivers/pci/pcie/dpc.c
index f03279fc87cd..e435d12e61a0 100644
--- a/drivers/pci/pcie/dpc.c
+++ b/drivers/pci/pcie/dpc.c
@@ -44,6 +44,58 @@ static const char * const rp_pio_error_string[] = {
"Memory Request Completion Timeout", /* Bit Position 18 */
};
+static struct dpc_dev *to_dpc_dev(struct pci_dev *dev)
+{
+ struct device *device;
+
+ device = pcie_port_find_device(dev, PCIE_PORT_SERVICE_DPC);
+ if (!device)
+ return NULL;
+ return get_service_data(to_pcie_device(device));
+}
+
+void pci_save_dpc_state(struct pci_dev *dev)
+{
+ struct dpc_dev *dpc;
+ struct pci_cap_saved_state *save_state;
+ u16 *cap;
+
+ if (!pci_is_pcie(dev))
+ return;
+
+ dpc = to_dpc_dev(dev);
+ if (!dpc)
+ return;
+
+ save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_DPC);
+ if (!save_state)
+ return;
+
+ cap = (u16 *)&save_state->cap.data[0];
+ pci_read_config_word(dev, dpc->cap_pos + PCI_EXP_DPC_CTL, cap);
+}
+
+void pci_restore_dpc_state(struct pci_dev *dev)
+{
+ struct dpc_dev *dpc;
+ struct pci_cap_saved_state *save_state;
+ u16 *cap;
+
+ if (!pci_is_pcie(dev))
+ return;
+
+ dpc = to_dpc_dev(dev);
+ if (!dpc)
+ return;
+
+ save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_DPC);
+ if (!save_state)
+ return;
+
+ cap = (u16 *)&save_state->cap.data[0];
+ pci_write_config_word(dev, dpc->cap_pos + PCI_EXP_DPC_CTL, *cap);
+}
+
static int dpc_wait_rp_inactive(struct dpc_dev *dpc)
{
unsigned long timeout = jiffies + HZ;
@@ -67,18 +119,13 @@ static int dpc_wait_rp_inactive(struct dpc_dev *dpc)
static pci_ers_result_t dpc_reset_link(struct pci_dev *pdev)
{
struct dpc_dev *dpc;
- struct pcie_device *pciedev;
- struct device *devdpc;
-
u16 cap;
/*
* DPC disables the Link automatically in hardware, so it has
* already been reset by the time we get here.
*/
- devdpc = pcie_port_find_device(pdev, PCIE_PORT_SERVICE_DPC);
- pciedev = to_pcie_device(devdpc);
- dpc = get_service_data(pciedev);
+ dpc = to_dpc_dev(pdev);
cap = dpc->cap_pos;
/*
@@ -93,10 +140,12 @@ static pci_ers_result_t dpc_reset_link(struct pci_dev *pdev)
pci_write_config_word(pdev, cap + PCI_EXP_DPC_STATUS,
PCI_EXP_DPC_STATUS_TRIGGER);
+ if (!pcie_wait_for_link(pdev, true))
+ return PCI_ERS_RESULT_DISCONNECT;
+
return PCI_ERS_RESULT_RECOVERED;
}
-
static void dpc_process_rp_pio_error(struct dpc_dev *dpc)
{
struct device *dev = &dpc->dev->device;
@@ -169,7 +218,7 @@ static irqreturn_t dpc_handler(int irq, void *context)
reason = (status & PCI_EXP_DPC_STATUS_TRIGGER_RSN) >> 1;
ext_reason = (status & PCI_EXP_DPC_STATUS_TRIGGER_RSN_EXT) >> 5;
- dev_warn(dev, "DPC %s detected, remove downstream devices\n",
+ dev_warn(dev, "DPC %s detected\n",
(reason == 0) ? "unmasked uncorrectable error" :
(reason == 1) ? "ERR_NONFATAL" :
(reason == 2) ? "ERR_FATAL" :
@@ -186,7 +235,7 @@ static irqreturn_t dpc_handler(int irq, void *context)
}
/* We configure DPC so it only triggers on ERR_FATAL */
- pcie_do_fatal_recovery(pdev, PCIE_PORT_SERVICE_DPC);
+ pcie_do_recovery(pdev, pci_channel_io_frozen, PCIE_PORT_SERVICE_DPC);
return IRQ_HANDLED;
}
@@ -259,6 +308,8 @@ static int dpc_probe(struct pcie_device *dev)
FLAG(cap, PCI_EXP_DPC_CAP_POISONED_TLP),
FLAG(cap, PCI_EXP_DPC_CAP_SW_TRIGGER), dpc->rp_log_size,
FLAG(cap, PCI_EXP_DPC_CAP_DL_ACTIVE));
+
+ pci_add_ext_cap_save_buffer(pdev, PCI_EXT_CAP_ID_DPC, sizeof(u16));
return status;
}
@@ -282,8 +333,7 @@ static struct pcie_port_service_driver dpcdriver = {
.reset_link = dpc_reset_link,
};
-static int __init dpc_service_init(void)
+int __init pcie_dpc_init(void)
{
return pcie_port_service_register(&dpcdriver);
}
-device_initcall(dpc_service_init);
diff --git a/drivers/pci/pcie/err.c b/drivers/pci/pcie/err.c
index 708fd3a0d646..773197a12568 100644
--- a/drivers/pci/pcie/err.c
+++ b/drivers/pci/pcie/err.c
@@ -12,18 +12,12 @@
#include <linux/pci.h>
#include <linux/module.h>
-#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/aer.h>
#include "portdrv.h"
#include "../pci.h"
-struct aer_broadcast_data {
- enum pci_channel_state state;
- enum pci_ers_result result;
-};
-
static pci_ers_result_t merge_result(enum pci_ers_result orig,
enum pci_ers_result new)
{
@@ -49,66 +43,52 @@ static pci_ers_result_t merge_result(enum pci_ers_result orig,
return orig;
}
-static int report_error_detected(struct pci_dev *dev, void *data)
+static int report_error_detected(struct pci_dev *dev,
+ enum pci_channel_state state,
+ enum pci_ers_result *result)
{
pci_ers_result_t vote;
const struct pci_error_handlers *err_handler;
- struct aer_broadcast_data *result_data;
-
- result_data = (struct aer_broadcast_data *) data;
device_lock(&dev->dev);
- dev->error_state = result_data->state;
-
- if (!dev->driver ||
+ if (!pci_dev_set_io_state(dev, state) ||
+ !dev->driver ||
!dev->driver->err_handler ||
!dev->driver->err_handler->error_detected) {
- if (result_data->state == pci_channel_io_frozen &&
- dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {
- /*
- * In case of fatal recovery, if one of down-
- * stream device has no driver. We might be
- * unable to recover because a later insmod
- * of a driver for this device is unaware of
- * its hw state.
- */
- pci_printk(KERN_DEBUG, dev, "device has %s\n",
- dev->driver ?
- "no AER-aware driver" : "no driver");
- }
-
/*
- * If there's any device in the subtree that does not
- * have an error_detected callback, returning
- * PCI_ERS_RESULT_NO_AER_DRIVER prevents calling of
- * the subsequent mmio_enabled/slot_reset/resume
- * callbacks of "any" device in the subtree. All the
- * devices in the subtree are left in the error state
- * without recovery.
+ * If any device in the subtree does not have an error_detected
+ * callback, PCI_ERS_RESULT_NO_AER_DRIVER prevents subsequent
+ * error callbacks of "any" device in the subtree, and will
+ * exit in the disconnected error state.
*/
-
if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE)
vote = PCI_ERS_RESULT_NO_AER_DRIVER;
else
vote = PCI_ERS_RESULT_NONE;
} else {
err_handler = dev->driver->err_handler;
- vote = err_handler->error_detected(dev, result_data->state);
- pci_uevent_ers(dev, PCI_ERS_RESULT_NONE);
+ vote = err_handler->error_detected(dev, state);
}
-
- result_data->result = merge_result(result_data->result, vote);
+ pci_uevent_ers(dev, vote);
+ *result = merge_result(*result, vote);
device_unlock(&dev->dev);
return 0;
}
+static int report_frozen_detected(struct pci_dev *dev, void *data)
+{
+ return report_error_detected(dev, pci_channel_io_frozen, data);
+}
+
+static int report_normal_detected(struct pci_dev *dev, void *data)
+{
+ return report_error_detected(dev, pci_channel_io_normal, data);
+}
+
static int report_mmio_enabled(struct pci_dev *dev, void *data)
{
- pci_ers_result_t vote;
+ pci_ers_result_t vote, *result = data;
const struct pci_error_handlers *err_handler;
- struct aer_broadcast_data *result_data;
-
- result_data = (struct aer_broadcast_data *) data;
device_lock(&dev->dev);
if (!dev->driver ||
@@ -118,7 +98,7 @@ static int report_mmio_enabled(struct pci_dev *dev, void *data)
err_handler = dev->driver->err_handler;
vote = err_handler->mmio_enabled(dev);
- result_data->result = merge_result(result_data->result, vote);
+ *result = merge_result(*result, vote);
out:
device_unlock(&dev->dev);
return 0;
@@ -126,11 +106,8 @@ out:
static int report_slot_reset(struct pci_dev *dev, void *data)
{
- pci_ers_result_t vote;
+ pci_ers_result_t vote, *result = data;
const struct pci_error_handlers *err_handler;
- struct aer_broadcast_data *result_data;
-
- result_data = (struct aer_broadcast_data *) data;
device_lock(&dev->dev);
if (!dev->driver ||
@@ -140,7 +117,7 @@ static int report_slot_reset(struct pci_dev *dev, void *data)
err_handler = dev->driver->err_handler;
vote = err_handler->slot_reset(dev);
- result_data->result = merge_result(result_data->result, vote);
+ *result = merge_result(*result, vote);
out:
device_unlock(&dev->dev);
return 0;
@@ -151,17 +128,16 @@ static int report_resume(struct pci_dev *dev, void *data)
const struct pci_error_handlers *err_handler;
device_lock(&dev->dev);
- dev->error_state = pci_channel_io_normal;
-
- if (!dev->driver ||
+ if (!pci_dev_set_io_state(dev, pci_channel_io_normal) ||
+ !dev->driver ||
!dev->driver->err_handler ||
!dev->driver->err_handler->resume)
goto out;
err_handler = dev->driver->err_handler;
err_handler->resume(dev);
- pci_uevent_ers(dev, PCI_ERS_RESULT_RECOVERED);
out:
+ pci_uevent_ers(dev, PCI_ERS_RESULT_RECOVERED);
device_unlock(&dev->dev);
return 0;
}
@@ -177,207 +153,86 @@ static pci_ers_result_t default_reset_link(struct pci_dev *dev)
{
int rc;
- rc = pci_bridge_secondary_bus_reset(dev);
+ rc = pci_bus_error_reset(dev);
pci_printk(KERN_DEBUG, dev, "downstream link has been reset\n");
return rc ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED;
}
static pci_ers_result_t reset_link(struct pci_dev *dev, u32 service)
{
- struct pci_dev *udev;
pci_ers_result_t status;
struct pcie_port_service_driver *driver = NULL;
- if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
- /* Reset this port for all subordinates */
- udev = dev;
- } else {
- /* Reset the upstream component (likely downstream port) */
- udev = dev->bus->self;
- }
-
- /* Use the aer driver of the component firstly */
- driver = pcie_port_find_service(udev, service);
-
+ driver = pcie_port_find_service(dev, service);
if (driver && driver->reset_link) {
- status = driver->reset_link(udev);
- } else if (udev->has_secondary_link) {
- status = default_reset_link(udev);
+ status = driver->reset_link(dev);
+ } else if (dev->has_secondary_link) {
+ status = default_reset_link(dev);
} else {
pci_printk(KERN_DEBUG, dev, "no link-reset support at upstream device %s\n",
- pci_name(udev));
+ pci_name(dev));
return PCI_ERS_RESULT_DISCONNECT;
}
if (status != PCI_ERS_RESULT_RECOVERED) {
pci_printk(KERN_DEBUG, dev, "link reset at upstream device %s failed\n",
- pci_name(udev));
+ pci_name(dev));
return PCI_ERS_RESULT_DISCONNECT;
}
return status;
}
-/**
- * broadcast_error_message - handle message broadcast to downstream drivers
- * @dev: pointer to from where in a hierarchy message is broadcasted down
- * @state: error state
- * @error_mesg: message to print
- * @cb: callback to be broadcasted
- *
- * Invoked during error recovery process. Once being invoked, the content
- * of error severity will be broadcasted to all downstream drivers in a
- * hierarchy in question.
- */
-static pci_ers_result_t broadcast_error_message(struct pci_dev *dev,
- enum pci_channel_state state,
- char *error_mesg,
- int (*cb)(struct pci_dev *, void *))
-{
- struct aer_broadcast_data result_data;
-
- pci_printk(KERN_DEBUG, dev, "broadcast %s message\n", error_mesg);
- result_data.state = state;
- if (cb == report_error_detected)
- result_data.result = PCI_ERS_RESULT_CAN_RECOVER;
- else
- result_data.result = PCI_ERS_RESULT_RECOVERED;
-
- if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
- /*
- * If the error is reported by a bridge, we think this error
- * is related to the downstream link of the bridge, so we
- * do error recovery on all subordinates of the bridge instead
- * of the bridge and clear the error status of the bridge.
- */
- if (cb == report_error_detected)
- dev->error_state = state;
- pci_walk_bus(dev->subordinate, cb, &result_data);
- if (cb == report_resume) {
- pci_aer_clear_device_status(dev);
- pci_cleanup_aer_uncorrect_error_status(dev);
- dev->error_state = pci_channel_io_normal;
- }
- } else {
- /*
- * If the error is reported by an end point, we think this
- * error is related to the upstream link of the end point.
- * The error is non fatal so the bus is ok; just invoke
- * the callback for the function that logged the error.
- */
- cb(dev, &result_data);
- }
-
- return result_data.result;
-}
-
-/**
- * pcie_do_fatal_recovery - handle fatal error recovery process
- * @dev: pointer to a pci_dev data structure of agent detecting an error
- *
- * Invoked when an error is fatal. Once being invoked, removes the devices
- * beneath this AER agent, followed by reset link e.g. secondary bus reset
- * followed by re-enumeration of devices.
- */
-void pcie_do_fatal_recovery(struct pci_dev *dev, u32 service)
+void pcie_do_recovery(struct pci_dev *dev, enum pci_channel_state state,
+ u32 service)
{
- struct pci_dev *udev;
- struct pci_bus *parent;
- struct pci_dev *pdev, *temp;
- pci_ers_result_t result;
-
- if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)
- udev = dev;
+ pci_ers_result_t status = PCI_ERS_RESULT_CAN_RECOVER;
+ struct pci_bus *bus;
+
+ /*
+ * Error recovery runs on all subordinates of the first downstream port.
+ * If the downstream port detected the error, it is cleared at the end.
+ */
+ if (!(pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT ||
+ pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM))
+ dev = dev->bus->self;
+ bus = dev->subordinate;
+
+ pci_dbg(dev, "broadcast error_detected message\n");
+ if (state == pci_channel_io_frozen)
+ pci_walk_bus(bus, report_frozen_detected, &status);
else
- udev = dev->bus->self;
-
- parent = udev->subordinate;
- pci_lock_rescan_remove();
- pci_dev_get(dev);
- list_for_each_entry_safe_reverse(pdev, temp, &parent->devices,
- bus_list) {
- pci_dev_get(pdev);
- pci_dev_set_disconnected(pdev, NULL);
- if (pci_has_subordinate(pdev))
- pci_walk_bus(pdev->subordinate,
- pci_dev_set_disconnected, NULL);
- pci_stop_and_remove_bus_device(pdev);
- pci_dev_put(pdev);
- }
-
- result = reset_link(udev, service);
+ pci_walk_bus(bus, report_normal_detected, &status);
- if ((service == PCIE_PORT_SERVICE_AER) &&
- (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)) {
- /*
- * If the error is reported by a bridge, we think this error
- * is related to the downstream link of the bridge, so we
- * do error recovery on all subordinates of the bridge instead
- * of the bridge and clear the error status of the bridge.
- */
- pci_aer_clear_fatal_status(dev);
- pci_aer_clear_device_status(dev);
- }
+ if (state == pci_channel_io_frozen &&
+ reset_link(dev, service) != PCI_ERS_RESULT_RECOVERED)
+ goto failed;
- if (result == PCI_ERS_RESULT_RECOVERED) {
- if (pcie_wait_for_link(udev, true))
- pci_rescan_bus(udev->bus);
- pci_info(dev, "Device recovery from fatal error successful\n");
- } else {
- pci_uevent_ers(dev, PCI_ERS_RESULT_DISCONNECT);
- pci_info(dev, "Device recovery from fatal error failed\n");
+ if (status == PCI_ERS_RESULT_CAN_RECOVER) {
+ status = PCI_ERS_RESULT_RECOVERED;
+ pci_dbg(dev, "broadcast mmio_enabled message\n");
+ pci_walk_bus(bus, report_mmio_enabled, &status);
}
- pci_dev_put(dev);
- pci_unlock_rescan_remove();
-}
-
-/**
- * pcie_do_nonfatal_recovery - handle nonfatal error recovery process
- * @dev: pointer to a pci_dev data structure of agent detecting an error
- *
- * Invoked when an error is nonfatal/fatal. Once being invoked, broadcast
- * error detected message to all downstream drivers within a hierarchy in
- * question and return the returned code.
- */
-void pcie_do_nonfatal_recovery(struct pci_dev *dev)
-{
- pci_ers_result_t status;
- enum pci_channel_state state;
-
- state = pci_channel_io_normal;
-
- status = broadcast_error_message(dev,
- state,
- "error_detected",
- report_error_detected);
-
- if (status == PCI_ERS_RESULT_CAN_RECOVER)
- status = broadcast_error_message(dev,
- state,
- "mmio_enabled",
- report_mmio_enabled);
-
if (status == PCI_ERS_RESULT_NEED_RESET) {
/*
* TODO: Should call platform-specific
* functions to reset slot before calling
* drivers' slot_reset callbacks?
*/
- status = broadcast_error_message(dev,
- state,
- "slot_reset",
- report_slot_reset);
+ status = PCI_ERS_RESULT_RECOVERED;
+ pci_dbg(dev, "broadcast slot_reset message\n");
+ pci_walk_bus(bus, report_slot_reset, &status);
}
if (status != PCI_ERS_RESULT_RECOVERED)
goto failed;
- broadcast_error_message(dev,
- state,
- "resume",
- report_resume);
+ pci_dbg(dev, "broadcast resume message\n");
+ pci_walk_bus(bus, report_resume, &status);
+ pci_aer_clear_device_status(dev);
+ pci_cleanup_aer_uncorrect_error_status(dev);
pci_info(dev, "AER: Device recovery successful\n");
return;
diff --git a/drivers/pci/pcie/pme.c b/drivers/pci/pcie/pme.c
index 3ed67676ea2a..0dbcf429089f 100644
--- a/drivers/pci/pcie/pme.c
+++ b/drivers/pci/pcie/pme.c
@@ -432,6 +432,31 @@ static void pcie_pme_remove(struct pcie_device *srv)
kfree(get_service_data(srv));
}
+static int pcie_pme_runtime_suspend(struct pcie_device *srv)
+{
+ struct pcie_pme_service_data *data = get_service_data(srv);
+
+ spin_lock_irq(&data->lock);
+ pcie_pme_interrupt_enable(srv->port, false);
+ pcie_clear_root_pme_status(srv->port);
+ data->noirq = true;
+ spin_unlock_irq(&data->lock);
+
+ return 0;
+}
+
+static int pcie_pme_runtime_resume(struct pcie_device *srv)
+{
+ struct pcie_pme_service_data *data = get_service_data(srv);
+
+ spin_lock_irq(&data->lock);
+ pcie_pme_interrupt_enable(srv->port, true);
+ data->noirq = false;
+ spin_unlock_irq(&data->lock);
+
+ return 0;
+}
+
static struct pcie_port_service_driver pcie_pme_driver = {
.name = "pcie_pme",
.port_type = PCI_EXP_TYPE_ROOT_PORT,
@@ -439,6 +464,8 @@ static struct pcie_port_service_driver pcie_pme_driver = {
.probe = pcie_pme_probe,
.suspend = pcie_pme_suspend,
+ .runtime_suspend = pcie_pme_runtime_suspend,
+ .runtime_resume = pcie_pme_runtime_resume,
.resume = pcie_pme_resume,
.remove = pcie_pme_remove,
};
@@ -446,8 +473,7 @@ static struct pcie_port_service_driver pcie_pme_driver = {
/**
* pcie_pme_service_init - Register the PCIe PME service driver.
*/
-static int __init pcie_pme_service_init(void)
+int __init pcie_pme_init(void)
{
return pcie_port_service_register(&pcie_pme_driver);
}
-device_initcall(pcie_pme_service_init);
diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h
index d59afa42fc14..e495f04394d0 100644
--- a/drivers/pci/pcie/portdrv.h
+++ b/drivers/pci/pcie/portdrv.h
@@ -23,6 +23,30 @@
#define PCIE_PORT_DEVICE_MAXSERVICES 4
+#ifdef CONFIG_PCIEAER
+int pcie_aer_init(void);
+#else
+static inline int pcie_aer_init(void) { return 0; }
+#endif
+
+#ifdef CONFIG_HOTPLUG_PCI_PCIE
+int pcie_hp_init(void);
+#else
+static inline int pcie_hp_init(void) { return 0; }
+#endif
+
+#ifdef CONFIG_PCIE_PME
+int pcie_pme_init(void);
+#else
+static inline int pcie_pme_init(void) { return 0; }
+#endif
+
+#ifdef CONFIG_PCIE_DPC
+int pcie_dpc_init(void);
+#else
+static inline int pcie_dpc_init(void) { return 0; }
+#endif
+
/* Port Type */
#define PCIE_ANY_PORT (~0)
@@ -52,6 +76,8 @@ struct pcie_port_service_driver {
int (*suspend) (struct pcie_device *dev);
int (*resume_noirq) (struct pcie_device *dev);
int (*resume) (struct pcie_device *dev);
+ int (*runtime_suspend) (struct pcie_device *dev);
+ int (*runtime_resume) (struct pcie_device *dev);
/* Device driver may resume normal operations */
void (*error_resume)(struct pci_dev *dev);
@@ -85,6 +111,8 @@ int pcie_port_device_register(struct pci_dev *dev);
int pcie_port_device_suspend(struct device *dev);
int pcie_port_device_resume_noirq(struct device *dev);
int pcie_port_device_resume(struct device *dev);
+int pcie_port_device_runtime_suspend(struct device *dev);
+int pcie_port_device_runtime_resume(struct device *dev);
#endif
void pcie_port_device_remove(struct pci_dev *dev);
int __must_check pcie_port_bus_register(void);
@@ -123,10 +151,6 @@ static inline int pcie_aer_get_firmware_first(struct pci_dev *pci_dev)
}
#endif
-#ifdef CONFIG_PCIEAER
-irqreturn_t aer_irq(int irq, void *context);
-#endif
-
struct pcie_port_service_driver *pcie_port_find_service(struct pci_dev *dev,
u32 service);
struct device *pcie_port_find_device(struct pci_dev *dev, u32 service);
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c
index 7c37d815229e..f458ac9cb70c 100644
--- a/drivers/pci/pcie/portdrv_core.c
+++ b/drivers/pci/pcie/portdrv_core.c
@@ -395,6 +395,26 @@ int pcie_port_device_resume(struct device *dev)
size_t off = offsetof(struct pcie_port_service_driver, resume);
return device_for_each_child(dev, &off, pm_iter);
}
+
+/**
+ * pcie_port_device_runtime_suspend - runtime suspend port services
+ * @dev: PCI Express port to handle
+ */
+int pcie_port_device_runtime_suspend(struct device *dev)
+{
+ size_t off = offsetof(struct pcie_port_service_driver, runtime_suspend);
+ return device_for_each_child(dev, &off, pm_iter);
+}
+
+/**
+ * pcie_port_device_runtime_resume - runtime resume port services
+ * @dev: PCI Express port to handle
+ */
+int pcie_port_device_runtime_resume(struct device *dev)
+{
+ size_t off = offsetof(struct pcie_port_service_driver, runtime_resume);
+ return device_for_each_child(dev, &off, pm_iter);
+}
#endif /* PM */
static int remove_iter(struct device *dev, void *data)
@@ -466,6 +486,7 @@ struct device *pcie_port_find_device(struct pci_dev *dev,
device = pdrvs.dev;
return device;
}
+EXPORT_SYMBOL_GPL(pcie_port_find_device);
/**
* pcie_port_device_remove - unregister PCI Express port service devices
diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c
index eef22dc29140..0acca3596807 100644
--- a/drivers/pci/pcie/portdrv_pci.c
+++ b/drivers/pci/pcie/portdrv_pci.c
@@ -45,12 +45,10 @@ __setup("pcie_ports=", pcie_port_setup);
#ifdef CONFIG_PM
static int pcie_port_runtime_suspend(struct device *dev)
{
- return to_pci_dev(dev)->bridge_d3 ? 0 : -EBUSY;
-}
+ if (!to_pci_dev(dev)->bridge_d3)
+ return -EBUSY;
-static int pcie_port_runtime_resume(struct device *dev)
-{
- return 0;
+ return pcie_port_device_runtime_suspend(dev);
}
static int pcie_port_runtime_idle(struct device *dev)
@@ -73,7 +71,7 @@ static const struct dev_pm_ops pcie_portdrv_pm_ops = {
.restore_noirq = pcie_port_device_resume_noirq,
.restore = pcie_port_device_resume,
.runtime_suspend = pcie_port_runtime_suspend,
- .runtime_resume = pcie_port_runtime_resume,
+ .runtime_resume = pcie_port_device_runtime_resume,
.runtime_idle = pcie_port_runtime_idle,
};
@@ -109,8 +107,8 @@ static int pcie_portdrv_probe(struct pci_dev *dev,
pci_save_state(dev);
- dev_pm_set_driver_flags(&dev->dev, DPM_FLAG_SMART_SUSPEND |
- DPM_FLAG_LEAVE_SUSPENDED);
+ dev_pm_set_driver_flags(&dev->dev, DPM_FLAG_NEVER_SKIP |
+ DPM_FLAG_SMART_SUSPEND);
if (pci_bridge_d3_possible(dev)) {
/*
@@ -146,6 +144,13 @@ static pci_ers_result_t pcie_portdrv_error_detected(struct pci_dev *dev,
return PCI_ERS_RESULT_CAN_RECOVER;
}
+static pci_ers_result_t pcie_portdrv_slot_reset(struct pci_dev *dev)
+{
+ pci_restore_state(dev);
+ pci_save_state(dev);
+ return PCI_ERS_RESULT_RECOVERED;
+}
+
static pci_ers_result_t pcie_portdrv_mmio_enabled(struct pci_dev *dev)
{
return PCI_ERS_RESULT_RECOVERED;
@@ -185,6 +190,7 @@ static const struct pci_device_id port_pci_ids[] = { {
static const struct pci_error_handlers pcie_portdrv_err_handler = {
.error_detected = pcie_portdrv_error_detected,
+ .slot_reset = pcie_portdrv_slot_reset,
.mmio_enabled = pcie_portdrv_mmio_enabled,
.resume = pcie_portdrv_err_resume,
};
@@ -226,11 +232,20 @@ static const struct dmi_system_id pcie_portdrv_dmi_table[] __initconst = {
{}
};
+static void __init pcie_init_services(void)
+{
+ pcie_aer_init();
+ pcie_pme_init();
+ pcie_dpc_init();
+ pcie_hp_init();
+}
+
static int __init pcie_portdrv_init(void)
{
if (pcie_ports_disabled)
return -EACCES;
+ pcie_init_services();
dmi_check_system(pcie_portdrv_dmi_table);
return pci_register_driver(&pcie_portdriver);
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 201f9e5ff55c..b1c05b5054a0 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -713,6 +713,7 @@ static void pci_set_bus_speed(struct pci_bus *bus)
pcie_capability_read_dword(bridge, PCI_EXP_LNKCAP, &linkcap);
bus->max_bus_speed = pcie_link_speed[linkcap & PCI_EXP_LNKCAP_SLS];
+ bridge->link_active_reporting = !!(linkcap & PCI_EXP_LNKCAP_DLLLARC);
pcie_capability_read_word(bridge, PCI_EXP_LNKSTA, &linksta);
pcie_update_link_speed(bus, linksta);
@@ -1438,12 +1439,29 @@ static int pci_cfg_space_size_ext(struct pci_dev *dev)
return PCI_CFG_SPACE_EXP_SIZE;
}
+#ifdef CONFIG_PCI_IOV
+static bool is_vf0(struct pci_dev *dev)
+{
+ if (pci_iov_virtfn_devfn(dev->physfn, 0) == dev->devfn &&
+ pci_iov_virtfn_bus(dev->physfn, 0) == dev->bus->number)
+ return true;
+
+ return false;
+}
+#endif
+
int pci_cfg_space_size(struct pci_dev *dev)
{
int pos;
u32 status;
u16 class;
+#ifdef CONFIG_PCI_IOV
+ /* Read cached value for all VFs except for VF0 */
+ if (dev->is_virtfn && !is_vf0(dev))
+ return dev->physfn->sriov->cfg_size;
+#endif
+
if (dev->bus->bus_flags & PCI_BUS_FLAGS_NO_EXTCFG)
return PCI_CFG_SPACE_SIZE;
@@ -2143,7 +2161,7 @@ static void pci_release_dev(struct device *dev)
pcibios_release_device(pci_dev);
pci_bus_put(pci_dev->bus);
kfree(pci_dev->driver_override);
- kfree(pci_dev->dma_alias_mask);
+ bitmap_free(pci_dev->dma_alias_mask);
kfree(pci_dev);
}
@@ -2397,8 +2415,8 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
dev->dev.dma_parms = &dev->dma_parms;
dev->dev.coherent_dma_mask = 0xffffffffull;
- pci_set_dma_max_seg_size(dev, 65536);
- pci_set_dma_seg_boundary(dev, 0xffffffff);
+ dma_set_max_seg_size(&dev->dev, 65536);
+ dma_set_seg_boundary(&dev->dev, 0xffffffff);
/* Fix up broken headers */
pci_fixup_device(pci_fixup_header, dev);
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 6bc27b7fd452..4700d24e5d55 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -3190,7 +3190,11 @@ static void disable_igfx_irq(struct pci_dev *dev)
pci_iounmap(dev, regs);
}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0042, disable_igfx_irq);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0046, disable_igfx_irq);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x004a, disable_igfx_irq);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0102, disable_igfx_irq);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0106, disable_igfx_irq);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0152, disable_igfx_irq);
@@ -4987,7 +4991,6 @@ static void quirk_switchtec_ntb_dma_alias(struct pci_dev *pdev)
void __iomem *mmio;
struct ntb_info_regs __iomem *mmio_ntb;
struct ntb_ctrl_regs __iomem *mmio_ctrl;
- struct sys_info_regs __iomem *mmio_sys_info;
u64 partition_map;
u8 partition;
int pp;
@@ -5008,7 +5011,6 @@ static void quirk_switchtec_ntb_dma_alias(struct pci_dev *pdev)
mmio_ntb = mmio + SWITCHTEC_GAS_NTB_OFFSET;
mmio_ctrl = (void __iomem *) mmio_ntb + SWITCHTEC_NTB_REG_CTRL_OFFSET;
- mmio_sys_info = mmio + SWITCHTEC_GAS_SYS_INFO_OFFSET;
partition = ioread8(&mmio_ntb->partition_id);
@@ -5057,59 +5059,37 @@ static void quirk_switchtec_ntb_dma_alias(struct pci_dev *pdev)
pci_iounmap(pdev, mmio);
pci_disable_device(pdev);
}
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8531,
- quirk_switchtec_ntb_dma_alias);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8532,
- quirk_switchtec_ntb_dma_alias);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8533,
- quirk_switchtec_ntb_dma_alias);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8534,
- quirk_switchtec_ntb_dma_alias);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8535,
- quirk_switchtec_ntb_dma_alias);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8536,
- quirk_switchtec_ntb_dma_alias);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8543,
- quirk_switchtec_ntb_dma_alias);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8544,
- quirk_switchtec_ntb_dma_alias);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8545,
- quirk_switchtec_ntb_dma_alias);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8546,
- quirk_switchtec_ntb_dma_alias);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8551,
- quirk_switchtec_ntb_dma_alias);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8552,
- quirk_switchtec_ntb_dma_alias);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8553,
- quirk_switchtec_ntb_dma_alias);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8554,
- quirk_switchtec_ntb_dma_alias);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8555,
- quirk_switchtec_ntb_dma_alias);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8556,
- quirk_switchtec_ntb_dma_alias);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8561,
- quirk_switchtec_ntb_dma_alias);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8562,
- quirk_switchtec_ntb_dma_alias);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8563,
- quirk_switchtec_ntb_dma_alias);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8564,
- quirk_switchtec_ntb_dma_alias);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8565,
- quirk_switchtec_ntb_dma_alias);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8566,
- quirk_switchtec_ntb_dma_alias);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8571,
- quirk_switchtec_ntb_dma_alias);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8572,
- quirk_switchtec_ntb_dma_alias);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8573,
- quirk_switchtec_ntb_dma_alias);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8574,
- quirk_switchtec_ntb_dma_alias);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8575,
- quirk_switchtec_ntb_dma_alias);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8576,
- quirk_switchtec_ntb_dma_alias);
+#define SWITCHTEC_QUIRK(vid) \
+ DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_MICROSEMI, vid, \
+ PCI_CLASS_BRIDGE_OTHER, 8, quirk_switchtec_ntb_dma_alias)
+
+SWITCHTEC_QUIRK(0x8531); /* PFX 24xG3 */
+SWITCHTEC_QUIRK(0x8532); /* PFX 32xG3 */
+SWITCHTEC_QUIRK(0x8533); /* PFX 48xG3 */
+SWITCHTEC_QUIRK(0x8534); /* PFX 64xG3 */
+SWITCHTEC_QUIRK(0x8535); /* PFX 80xG3 */
+SWITCHTEC_QUIRK(0x8536); /* PFX 96xG3 */
+SWITCHTEC_QUIRK(0x8541); /* PSX 24xG3 */
+SWITCHTEC_QUIRK(0x8542); /* PSX 32xG3 */
+SWITCHTEC_QUIRK(0x8543); /* PSX 48xG3 */
+SWITCHTEC_QUIRK(0x8544); /* PSX 64xG3 */
+SWITCHTEC_QUIRK(0x8545); /* PSX 80xG3 */
+SWITCHTEC_QUIRK(0x8546); /* PSX 96xG3 */
+SWITCHTEC_QUIRK(0x8551); /* PAX 24XG3 */
+SWITCHTEC_QUIRK(0x8552); /* PAX 32XG3 */
+SWITCHTEC_QUIRK(0x8553); /* PAX 48XG3 */
+SWITCHTEC_QUIRK(0x8554); /* PAX 64XG3 */
+SWITCHTEC_QUIRK(0x8555); /* PAX 80XG3 */
+SWITCHTEC_QUIRK(0x8556); /* PAX 96XG3 */
+SWITCHTEC_QUIRK(0x8561); /* PFXL 24XG3 */
+SWITCHTEC_QUIRK(0x8562); /* PFXL 32XG3 */
+SWITCHTEC_QUIRK(0x8563); /* PFXL 48XG3 */
+SWITCHTEC_QUIRK(0x8564); /* PFXL 64XG3 */
+SWITCHTEC_QUIRK(0x8565); /* PFXL 80XG3 */
+SWITCHTEC_QUIRK(0x8566); /* PFXL 96XG3 */
+SWITCHTEC_QUIRK(0x8571); /* PFXI 24XG3 */
+SWITCHTEC_QUIRK(0x8572); /* PFXI 32XG3 */
+SWITCHTEC_QUIRK(0x8573); /* PFXI 48XG3 */
+SWITCHTEC_QUIRK(0x8574); /* PFXI 64XG3 */
+SWITCHTEC_QUIRK(0x8575); /* PFXI 80XG3 */
+SWITCHTEC_QUIRK(0x8576); /* PFXI 96XG3 */
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index 461e7fd2756f..e9c6b120cf45 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -25,9 +25,6 @@ static void pci_stop_dev(struct pci_dev *dev)
pci_dev_assign_added(dev, false);
}
-
- if (dev->bus->self)
- pcie_aspm_exit_link_state(dev);
}
static void pci_destroy_dev(struct pci_dev *dev)
@@ -41,6 +38,7 @@ static void pci_destroy_dev(struct pci_dev *dev)
list_del(&dev->bus_list);
up_write(&pci_bus_sem);
+ pcie_aspm_exit_link_state(dev);
pci_bridge_d3_update(dev);
pci_free_resources(dev);
put_device(&dev->dev);
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 79b1824e83b4..ed960436df5e 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -811,6 +811,8 @@ static struct resource *find_free_bus_resource(struct pci_bus *bus,
static resource_size_t calculate_iosize(resource_size_t size,
resource_size_t min_size,
resource_size_t size1,
+ resource_size_t add_size,
+ resource_size_t children_add_size,
resource_size_t old_size,
resource_size_t align)
{
@@ -823,15 +825,18 @@ static resource_size_t calculate_iosize(resource_size_t size,
#if defined(CONFIG_ISA) || defined(CONFIG_EISA)
size = (size & 0xff) + ((size & ~0xffUL) << 2);
#endif
- size = ALIGN(size + size1, align);
+ size = size + size1;
if (size < old_size)
size = old_size;
+
+ size = ALIGN(max(size, add_size) + children_add_size, align);
return size;
}
static resource_size_t calculate_memsize(resource_size_t size,
resource_size_t min_size,
- resource_size_t size1,
+ resource_size_t add_size,
+ resource_size_t children_add_size,
resource_size_t old_size,
resource_size_t align)
{
@@ -841,7 +846,8 @@ static resource_size_t calculate_memsize(resource_size_t size,
old_size = 0;
if (size < old_size)
size = old_size;
- size = ALIGN(size + size1, align);
+
+ size = ALIGN(max(size, add_size) + children_add_size, align);
return size;
}
@@ -930,12 +936,10 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
}
}
- size0 = calculate_iosize(size, min_size, size1,
+ size0 = calculate_iosize(size, min_size, size1, 0, 0,
resource_size(b_res), min_align);
- if (children_add_size > add_size)
- add_size = children_add_size;
- size1 = (!realloc_head || (realloc_head && !add_size)) ? size0 :
- calculate_iosize(size, min_size, add_size + size1,
+ size1 = (!realloc_head || (realloc_head && !add_size && !children_add_size)) ? size0 :
+ calculate_iosize(size, min_size, size1, add_size, children_add_size,
resource_size(b_res), min_align);
if (!size0 && !size1) {
if (b_res->start || b_res->end)
@@ -1079,12 +1083,10 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
min_align = calculate_mem_align(aligns, max_order);
min_align = max(min_align, window_alignment(bus, b_res->flags));
- size0 = calculate_memsize(size, min_size, 0, resource_size(b_res), min_align);
+ size0 = calculate_memsize(size, min_size, 0, 0, resource_size(b_res), min_align);
add_align = max(min_align, add_align);
- if (children_add_size > add_size)
- add_size = children_add_size;
- size1 = (!realloc_head || (realloc_head && !add_size)) ? size0 :
- calculate_memsize(size, min_size, add_size,
+ size1 = (!realloc_head || (realloc_head && !add_size && !children_add_size)) ? size0 :
+ calculate_memsize(size, min_size, add_size, children_add_size,
resource_size(b_res), add_align);
if (!size0 && !size1) {
if (b_res->start || b_res->end)
diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c
index e634229ece89..c46d5e1ff536 100644
--- a/drivers/pci/slot.c
+++ b/drivers/pci/slot.c
@@ -14,7 +14,6 @@
struct kset *pci_slots_kset;
EXPORT_SYMBOL_GPL(pci_slots_kset);
-static DEFINE_MUTEX(pci_slot_mutex);
static ssize_t pci_slot_attr_show(struct kobject *kobj,
struct attribute *attr, char *buf)
@@ -371,7 +370,7 @@ void pci_hp_create_module_link(struct pci_slot *pci_slot)
if (!slot || !slot->ops)
return;
- kobj = kset_find_obj(module_kset, slot->ops->mod_name);
+ kobj = kset_find_obj(module_kset, slot->mod_name);
if (!kobj)
return;
ret = sysfs_create_link(&pci_slot->kobj, kobj, "module");
diff --git a/drivers/pcmcia/electra_cf.c b/drivers/pcmcia/electra_cf.c
index 9671ded549f0..b31abe35ed2c 100644
--- a/drivers/pcmcia/electra_cf.c
+++ b/drivers/pcmcia/electra_cf.c
@@ -230,7 +230,7 @@ static int electra_cf_probe(struct platform_device *ofdev)
if (!cf->mem_base || !cf->io_virt || !cf->gpio_base ||
(__ioremap_at(io.start, cf->io_virt, cf->io_size,
- pgprot_val(pgprot_noncached(__pgprot(0)))) == NULL)) {
+ pgprot_noncached(PAGE_KERNEL)) == NULL)) {
dev_err(device, "can't ioremap ranges\n");
status = -ENOMEM;
goto fail1;
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c
index 18802096148e..41ce410f7f97 100644
--- a/drivers/pcmcia/pcmcia_resource.c
+++ b/drivers/pcmcia/pcmcia_resource.c
@@ -284,7 +284,7 @@ int pcmcia_fixup_iowidth(struct pcmcia_device *p_dev)
io_on.stop = s->io[i].res->end;
s->ops->set_io_map(s, &io_off);
- mdelay(40);
+ msleep(40);
s->ops->set_io_map(s, &io_on);
}
unlock:
@@ -567,7 +567,7 @@ int pcmcia_enable_device(struct pcmcia_device *p_dev)
!(flags & CONF_ENABLE_PULSE_IRQ))
option |= COR_LEVEL_REQ;
pcmcia_write_cis_mem(s, 1, (base + CISREG_COR)>>1, 1, &option);
- mdelay(40);
+ msleep(40);
}
if (p_dev->config_regs & PRESENT_STATUS)
pcmcia_write_cis_mem(s, 1, (base + CISREG_CCSR)>>1, 1, &status);
diff --git a/drivers/pcmcia/ricoh.h b/drivers/pcmcia/ricoh.h
index 01098c841f87..8ac7b138c094 100644
--- a/drivers/pcmcia/ricoh.h
+++ b/drivers/pcmcia/ricoh.h
@@ -119,6 +119,10 @@
#define RL5C4XX_MISC_CONTROL 0x2F /* 8 bit */
#define RL5C4XX_ZV_ENABLE 0x08
+/* Misc Control 3 Register */
+#define RL5C4XX_MISC3 0x00A2 /* 16 bit */
+#define RL5C47X_MISC3_CB_CLKRUN_DIS BIT(1)
+
#ifdef __YENTA_H
#define rl_misc(socket) ((socket)->private[0])
@@ -156,6 +160,35 @@ static void ricoh_set_zv(struct yenta_socket *socket)
}
}
+static void ricoh_set_clkrun(struct yenta_socket *socket, bool quiet)
+{
+ u16 misc3;
+
+ /*
+ * RL5C475II likely has this setting, too, however no datasheet
+ * is publicly available for this chip
+ */
+ if (socket->dev->device != PCI_DEVICE_ID_RICOH_RL5C476 &&
+ socket->dev->device != PCI_DEVICE_ID_RICOH_RL5C478)
+ return;
+
+ if (socket->dev->revision < 0x80)
+ return;
+
+ misc3 = config_readw(socket, RL5C4XX_MISC3);
+ if (misc3 & RL5C47X_MISC3_CB_CLKRUN_DIS) {
+ if (!quiet)
+ dev_dbg(&socket->dev->dev,
+ "CLKRUN feature already disabled\n");
+ } else if (disable_clkrun) {
+ if (!quiet)
+ dev_info(&socket->dev->dev,
+ "Disabling CLKRUN feature\n");
+ misc3 |= RL5C47X_MISC3_CB_CLKRUN_DIS;
+ config_writew(socket, RL5C4XX_MISC3, misc3);
+ }
+}
+
static void ricoh_save_state(struct yenta_socket *socket)
{
rl_misc(socket) = config_readw(socket, RL5C4XX_MISC);
@@ -172,6 +205,7 @@ static void ricoh_restore_state(struct yenta_socket *socket)
config_writew(socket, RL5C4XX_16BIT_IO_0, rl_io(socket));
config_writew(socket, RL5C4XX_16BIT_MEM_0, rl_mem(socket));
config_writew(socket, RL5C4XX_CONFIG, rl_config(socket));
+ ricoh_set_clkrun(socket, true);
}
@@ -197,6 +231,7 @@ static int ricoh_override(struct yenta_socket *socket)
config_writew(socket, RL5C4XX_CONFIG, config);
ricoh_set_zv(socket);
+ ricoh_set_clkrun(socket, false);
return 0;
}
diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c
index c5f2344c189b..3a8c84bb174d 100644
--- a/drivers/pcmcia/soc_common.c
+++ b/drivers/pcmcia/soc_common.c
@@ -351,19 +351,20 @@ static int soc_common_pcmcia_config_skt(
if (ret == 0) {
struct gpio_desc *descs[2];
- int values[2], n = 0;
+ DECLARE_BITMAP(values, 2);
+ int n = 0;
if (skt->gpio_reset) {
descs[n] = skt->gpio_reset;
- values[n++] = !!(state->flags & SS_RESET);
+ __assign_bit(n++, values, state->flags & SS_RESET);
}
if (skt->gpio_bus_enable) {
descs[n] = skt->gpio_bus_enable;
- values[n++] = !!(state->flags & SS_OUTPUT_ENA);
+ __assign_bit(n++, values, state->flags & SS_OUTPUT_ENA);
}
if (n)
- gpiod_set_array_value_cansleep(n, descs, values);
+ gpiod_set_array_value_cansleep(n, descs, NULL, values);
/*
* This really needs a better solution. The IRQ
diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c
index ab3da2262f0f..ac6a3f46b1e6 100644
--- a/drivers/pcmcia/yenta_socket.c
+++ b/drivers/pcmcia/yenta_socket.c
@@ -26,7 +26,8 @@
static bool disable_clkrun;
module_param(disable_clkrun, bool, 0444);
-MODULE_PARM_DESC(disable_clkrun, "If PC card doesn't function properly, please try this option");
+MODULE_PARM_DESC(disable_clkrun,
+ "If PC card doesn't function properly, please try this option (TI and Ricoh bridges only)");
static bool isa_probe = 1;
module_param(isa_probe, bool, 0444);
diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c
index 7f01f6f60b87..d0b7dd8fb184 100644
--- a/drivers/perf/arm_pmu.c
+++ b/drivers/perf/arm_pmu.c
@@ -485,7 +485,13 @@ static int armpmu_filter_match(struct perf_event *event)
{
struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
unsigned int cpu = smp_processor_id();
- return cpumask_test_cpu(cpu, &armpmu->supported_cpus);
+ int ret;
+
+ ret = cpumask_test_cpu(cpu, &armpmu->supported_cpus);
+ if (ret && armpmu->filter_match)
+ return armpmu->filter_match(event);
+
+ return ret;
}
static ssize_t armpmu_cpumask_show(struct device *dev,
diff --git a/drivers/perf/arm_pmu_platform.c b/drivers/perf/arm_pmu_platform.c
index 96075cecb0ae..933bd8410fc2 100644
--- a/drivers/perf/arm_pmu_platform.c
+++ b/drivers/perf/arm_pmu_platform.c
@@ -77,14 +77,14 @@ static int pmu_parse_irq_affinity(struct device_node *node, int i)
dn = of_parse_phandle(node, "interrupt-affinity", i);
if (!dn) {
- pr_warn("failed to parse interrupt-affinity[%d] for %s\n",
- i, node->name);
+ pr_warn("failed to parse interrupt-affinity[%d] for %pOFn\n",
+ i, node);
return -EINVAL;
}
cpu = of_cpu_node_to_id(dn);
if (cpu < 0) {
- pr_warn("failed to find logical CPU for %s\n", dn->name);
+ pr_warn("failed to find logical CPU for %pOFn\n", dn);
cpu = nr_cpu_ids;
}
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 5c8d452e35e2..60f949e2a684 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -43,16 +43,19 @@ config PHY_XGENE
source "drivers/phy/allwinner/Kconfig"
source "drivers/phy/amlogic/Kconfig"
source "drivers/phy/broadcom/Kconfig"
+source "drivers/phy/cadence/Kconfig"
source "drivers/phy/hisilicon/Kconfig"
source "drivers/phy/lantiq/Kconfig"
source "drivers/phy/marvell/Kconfig"
source "drivers/phy/mediatek/Kconfig"
source "drivers/phy/motorola/Kconfig"
+source "drivers/phy/mscc/Kconfig"
source "drivers/phy/qualcomm/Kconfig"
source "drivers/phy/ralink/Kconfig"
source "drivers/phy/renesas/Kconfig"
source "drivers/phy/rockchip/Kconfig"
source "drivers/phy/samsung/Kconfig"
+source "drivers/phy/socionext/Kconfig"
source "drivers/phy/st/Kconfig"
source "drivers/phy/tegra/Kconfig"
source "drivers/phy/ti/Kconfig"
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 84e3bd9c5665..0301e25d07c1 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -15,11 +15,14 @@ obj-$(CONFIG_ARCH_RENESAS) += renesas/
obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-y += broadcom/ \
+ cadence/ \
hisilicon/ \
marvell/ \
motorola/ \
+ mscc/ \
qualcomm/ \
ralink/ \
samsung/ \
+ socionext/ \
st/ \
ti/
diff --git a/drivers/phy/broadcom/Kconfig b/drivers/phy/broadcom/Kconfig
index 8786a9674471..aa917a61071d 100644
--- a/drivers/phy/broadcom/Kconfig
+++ b/drivers/phy/broadcom/Kconfig
@@ -60,7 +60,8 @@ config PHY_NS2_USB_DRD
config PHY_BRCM_SATA
tristate "Broadcom SATA PHY driver"
- depends on ARCH_BRCMSTB || ARCH_BCM_IPROC || BMIPS_GENERIC || COMPILE_TEST
+ depends on ARCH_BRCMSTB || ARCH_BCM_IPROC || BMIPS_GENERIC || \
+ ARCH_BCM_63XX || COMPILE_TEST
depends on OF
select GENERIC_PHY
default ARCH_BCM_IPROC
diff --git a/drivers/phy/broadcom/phy-bcm-cygnus-pcie.c b/drivers/phy/broadcom/phy-bcm-cygnus-pcie.c
index 0f4ac5d63cff..b074682d9dd8 100644
--- a/drivers/phy/broadcom/phy-bcm-cygnus-pcie.c
+++ b/drivers/phy/broadcom/phy-bcm-cygnus-pcie.c
@@ -153,8 +153,8 @@ static int cygnus_pcie_phy_probe(struct platform_device *pdev)
struct cygnus_pcie_phy *p;
if (of_property_read_u32(child, "reg", &id)) {
- dev_err(dev, "missing reg property for %s\n",
- child->name);
+ dev_err(dev, "missing reg property for %pOFn\n",
+ child);
ret = -EINVAL;
goto put_child;
}
diff --git a/drivers/phy/broadcom/phy-brcm-sata.c b/drivers/phy/broadcom/phy-brcm-sata.c
index 8708ea3b4d6d..0f4a06ff7fd3 100644
--- a/drivers/phy/broadcom/phy-brcm-sata.c
+++ b/drivers/phy/broadcom/phy-brcm-sata.c
@@ -47,6 +47,7 @@ enum brcm_sata_phy_version {
BRCM_SATA_PHY_IPROC_NS2,
BRCM_SATA_PHY_IPROC_NSP,
BRCM_SATA_PHY_IPROC_SR,
+ BRCM_SATA_PHY_DSL_28NM,
};
enum brcm_sata_phy_rxaeq_mode {
@@ -96,7 +97,10 @@ enum sata_phy_regs {
PLLCONTROL_0_FREQ_DET_RESTART = BIT(13),
PLLCONTROL_0_FREQ_MONITOR = BIT(12),
PLLCONTROL_0_SEQ_START = BIT(15),
+ PLL_CAP_CHARGE_TIME = 0x83,
+ PLL_VCO_CAL_THRESH = 0x84,
PLL_CAP_CONTROL = 0x85,
+ PLL_FREQ_DET_TIME = 0x86,
PLL_ACTRL2 = 0x8b,
PLL_ACTRL2_SELDIV_MASK = 0x1f,
PLL_ACTRL2_SELDIV_SHIFT = 9,
@@ -106,6 +110,9 @@ enum sata_phy_regs {
PLL1_ACTRL2 = 0x82,
PLL1_ACTRL3 = 0x83,
PLL1_ACTRL4 = 0x84,
+ PLL1_ACTRL5 = 0x85,
+ PLL1_ACTRL6 = 0x86,
+ PLL1_ACTRL7 = 0x87,
TX_REG_BANK = 0x070,
TX_ACTRL0 = 0x80,
@@ -119,6 +126,8 @@ enum sata_phy_regs {
AEQ_FRC_EQ_FORCE = BIT(0),
AEQ_FRC_EQ_FORCE_VAL = BIT(1),
AEQRX_REG_BANK_1 = 0xe0,
+ AEQRX_SLCAL0_CTRL0 = 0x82,
+ AEQRX_SLCAL1_CTRL0 = 0x86,
OOB_REG_BANK = 0x150,
OOB1_REG_BANK = 0x160,
@@ -168,6 +177,7 @@ static inline void __iomem *brcm_sata_pcb_base(struct brcm_sata_port *port)
switch (priv->version) {
case BRCM_SATA_PHY_STB_28NM:
case BRCM_SATA_PHY_IPROC_NS2:
+ case BRCM_SATA_PHY_DSL_28NM:
size = SATA_PCB_REG_28NM_SPACE_SIZE;
break;
case BRCM_SATA_PHY_STB_40NM:
@@ -482,6 +492,61 @@ static int brcm_sr_sata_init(struct brcm_sata_port *port)
return 0;
}
+static int brcm_dsl_sata_init(struct brcm_sata_port *port)
+{
+ void __iomem *base = brcm_sata_pcb_base(port);
+ struct device *dev = port->phy_priv->dev;
+ unsigned int try;
+ u32 tmp;
+
+ brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL7, 0, 0x873);
+
+ brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL6, 0, 0xc000);
+
+ brcm_sata_phy_wr(base, PLL_REG_BANK_0, PLL_REG_BANK_0_PLLCONTROL_0,
+ 0, 0x3089);
+ usleep_range(1000, 2000);
+
+ brcm_sata_phy_wr(base, PLL_REG_BANK_0, PLL_REG_BANK_0_PLLCONTROL_0,
+ 0, 0x3088);
+ usleep_range(1000, 2000);
+
+ brcm_sata_phy_wr(base, AEQRX_REG_BANK_1, AEQRX_SLCAL0_CTRL0,
+ 0, 0x3000);
+
+ brcm_sata_phy_wr(base, AEQRX_REG_BANK_1, AEQRX_SLCAL1_CTRL0,
+ 0, 0x3000);
+ usleep_range(1000, 2000);
+
+ brcm_sata_phy_wr(base, PLL_REG_BANK_0, PLL_CAP_CHARGE_TIME, 0, 0x32);
+
+ brcm_sata_phy_wr(base, PLL_REG_BANK_0, PLL_VCO_CAL_THRESH, 0, 0xa);
+
+ brcm_sata_phy_wr(base, PLL_REG_BANK_0, PLL_FREQ_DET_TIME, 0, 0x64);
+ usleep_range(1000, 2000);
+
+ /* Acquire PLL lock */
+ try = 50;
+ while (try) {
+ tmp = brcm_sata_phy_rd(base, BLOCK0_REG_BANK,
+ BLOCK0_XGXSSTATUS);
+ if (tmp & BLOCK0_XGXSSTATUS_PLL_LOCK)
+ break;
+ msleep(20);
+ try--;
+ };
+
+ if (!try) {
+ /* PLL did not lock; give up */
+ dev_err(dev, "port%d PLL did not lock\n", port->portnum);
+ return -ETIMEDOUT;
+ }
+
+ dev_dbg(dev, "port%d initialized\n", port->portnum);
+
+ return 0;
+}
+
static int brcm_sata_phy_init(struct phy *phy)
{
int rc;
@@ -501,6 +566,9 @@ static int brcm_sata_phy_init(struct phy *phy)
case BRCM_SATA_PHY_IPROC_SR:
rc = brcm_sr_sata_init(port);
break;
+ case BRCM_SATA_PHY_DSL_28NM:
+ rc = brcm_dsl_sata_init(port);
+ break;
default:
rc = -ENODEV;
}
@@ -552,6 +620,8 @@ static const struct of_device_id brcm_sata_phy_of_match[] = {
.data = (void *)BRCM_SATA_PHY_IPROC_NSP },
{ .compatible = "brcm,iproc-sr-sata-phy",
.data = (void *)BRCM_SATA_PHY_IPROC_SR },
+ { .compatible = "brcm,bcm63138-sata-phy",
+ .data = (void *)BRCM_SATA_PHY_DSL_28NM },
{},
};
MODULE_DEVICE_TABLE(of, brcm_sata_phy_of_match);
@@ -600,8 +670,8 @@ static int brcm_sata_phy_probe(struct platform_device *pdev)
struct brcm_sata_port *port;
if (of_property_read_u32(child, "reg", &id)) {
- dev_err(dev, "missing reg property in node %s\n",
- child->name);
+ dev_err(dev, "missing reg property in node %pOFn\n",
+ child);
ret = -EINVAL;
goto put_child;
}
diff --git a/drivers/phy/broadcom/phy-brcm-usb.c b/drivers/phy/broadcom/phy-brcm-usb.c
index d1dab36fa5b7..f59b1dc30399 100644
--- a/drivers/phy/broadcom/phy-brcm-usb.c
+++ b/drivers/phy/broadcom/phy-brcm-usb.c
@@ -372,10 +372,8 @@ static int brcm_usb_phy_probe(struct platform_device *pdev)
clk_disable(priv->usb_30_clk);
phy_provider = devm_of_phy_provider_register(dev, brcm_usb_phy_xlate);
- if (IS_ERR(phy_provider))
- return PTR_ERR(phy_provider);
- return 0;
+ return PTR_ERR_OR_ZERO(phy_provider);
}
#ifdef CONFIG_PM_SLEEP
diff --git a/drivers/phy/cadence/Kconfig b/drivers/phy/cadence/Kconfig
new file mode 100644
index 000000000000..57fff7de4031
--- /dev/null
+++ b/drivers/phy/cadence/Kconfig
@@ -0,0 +1,10 @@
+#
+# Phy driver for Cadence MHDP DisplayPort controller
+#
+config PHY_CADENCE_DP
+ tristate "Cadence MHDP DisplayPort PHY driver"
+ depends on OF
+ depends on HAS_IOMEM
+ select GENERIC_PHY
+ help
+ Support for Cadence MHDP DisplayPort PHY.
diff --git a/drivers/phy/cadence/Makefile b/drivers/phy/cadence/Makefile
new file mode 100644
index 000000000000..e5b0a11cf28a
--- /dev/null
+++ b/drivers/phy/cadence/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_PHY_CADENCE_DP) += phy-cadence-dp.o
diff --git a/drivers/phy/cadence/phy-cadence-dp.c b/drivers/phy/cadence/phy-cadence-dp.c
new file mode 100644
index 000000000000..bc10cb264b7a
--- /dev/null
+++ b/drivers/phy/cadence/phy-cadence-dp.c
@@ -0,0 +1,541 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Cadence MHDP DisplayPort SD0801 PHY driver.
+ *
+ * Copyright 2018 Cadence Design Systems, Inc.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/iopoll.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/phy/phy.h>
+#include <linux/platform_device.h>
+
+#define DEFAULT_NUM_LANES 2
+#define MAX_NUM_LANES 4
+#define DEFAULT_MAX_BIT_RATE 8100 /* in Mbps */
+
+#define POLL_TIMEOUT_US 2000
+#define LANE_MASK 0x7
+
+/*
+ * register offsets from DPTX PHY register block base (i.e MHDP
+ * register base + 0x30a00)
+ */
+#define PHY_AUX_CONFIG 0x00
+#define PHY_AUX_CTRL 0x04
+#define PHY_RESET 0x20
+#define PHY_PMA_XCVR_PLLCLK_EN 0x24
+#define PHY_PMA_XCVR_PLLCLK_EN_ACK 0x28
+#define PHY_PMA_XCVR_POWER_STATE_REQ 0x2c
+#define PHY_POWER_STATE_LN_0 0x0000
+#define PHY_POWER_STATE_LN_1 0x0008
+#define PHY_POWER_STATE_LN_2 0x0010
+#define PHY_POWER_STATE_LN_3 0x0018
+#define PHY_PMA_XCVR_POWER_STATE_ACK 0x30
+#define PHY_PMA_CMN_READY 0x34
+#define PHY_PMA_XCVR_TX_VMARGIN 0x38
+#define PHY_PMA_XCVR_TX_DEEMPH 0x3c
+
+/*
+ * register offsets from SD0801 PHY register block base (i.e MHDP
+ * register base + 0x500000)
+ */
+#define CMN_SSM_BANDGAP_TMR 0x00084
+#define CMN_SSM_BIAS_TMR 0x00088
+#define CMN_PLLSM0_PLLPRE_TMR 0x000a8
+#define CMN_PLLSM0_PLLLOCK_TMR 0x000b0
+#define CMN_PLLSM1_PLLPRE_TMR 0x000c8
+#define CMN_PLLSM1_PLLLOCK_TMR 0x000d0
+#define CMN_BGCAL_INIT_TMR 0x00190
+#define CMN_BGCAL_ITER_TMR 0x00194
+#define CMN_IBCAL_INIT_TMR 0x001d0
+#define CMN_PLL0_VCOCAL_INIT_TMR 0x00210
+#define CMN_PLL0_VCOCAL_ITER_TMR 0x00214
+#define CMN_PLL0_VCOCAL_REFTIM_START 0x00218
+#define CMN_PLL0_VCOCAL_PLLCNT_START 0x00220
+#define CMN_PLL0_INTDIV_M0 0x00240
+#define CMN_PLL0_FRACDIVL_M0 0x00244
+#define CMN_PLL0_FRACDIVH_M0 0x00248
+#define CMN_PLL0_HIGH_THR_M0 0x0024c
+#define CMN_PLL0_DSM_DIAG_M0 0x00250
+#define CMN_PLL0_LOCK_PLLCNT_START 0x00278
+#define CMN_PLL1_VCOCAL_INIT_TMR 0x00310
+#define CMN_PLL1_VCOCAL_ITER_TMR 0x00314
+#define CMN_PLL1_DSM_DIAG_M0 0x00350
+#define CMN_TXPUCAL_INIT_TMR 0x00410
+#define CMN_TXPUCAL_ITER_TMR 0x00414
+#define CMN_TXPDCAL_INIT_TMR 0x00430
+#define CMN_TXPDCAL_ITER_TMR 0x00434
+#define CMN_RXCAL_INIT_TMR 0x00450
+#define CMN_RXCAL_ITER_TMR 0x00454
+#define CMN_SD_CAL_INIT_TMR 0x00490
+#define CMN_SD_CAL_ITER_TMR 0x00494
+#define CMN_SD_CAL_REFTIM_START 0x00498
+#define CMN_SD_CAL_PLLCNT_START 0x004a0
+#define CMN_PDIAG_PLL0_CTRL_M0 0x00680
+#define CMN_PDIAG_PLL0_CLK_SEL_M0 0x00684
+#define CMN_PDIAG_PLL0_CP_PADJ_M0 0x00690
+#define CMN_PDIAG_PLL0_CP_IADJ_M0 0x00694
+#define CMN_PDIAG_PLL0_FILT_PADJ_M0 0x00698
+#define CMN_PDIAG_PLL0_CP_PADJ_M1 0x006d0
+#define CMN_PDIAG_PLL0_CP_IADJ_M1 0x006d4
+#define CMN_PDIAG_PLL1_CLK_SEL_M0 0x00704
+#define XCVR_DIAG_PLLDRC_CTRL 0x10394
+#define XCVR_DIAG_HSCLK_SEL 0x10398
+#define XCVR_DIAG_HSCLK_DIV 0x1039c
+#define TX_PSC_A0 0x10400
+#define TX_PSC_A1 0x10404
+#define TX_PSC_A2 0x10408
+#define TX_PSC_A3 0x1040c
+#define RX_PSC_A0 0x20000
+#define RX_PSC_A1 0x20004
+#define RX_PSC_A2 0x20008
+#define RX_PSC_A3 0x2000c
+#define PHY_PLL_CFG 0x30038
+
+struct cdns_dp_phy {
+ void __iomem *base; /* DPTX registers base */
+ void __iomem *sd_base; /* SD0801 registers base */
+ u32 num_lanes; /* Number of lanes to use */
+ u32 max_bit_rate; /* Maximum link bit rate to use (in Mbps) */
+ struct device *dev;
+};
+
+static int cdns_dp_phy_init(struct phy *phy);
+static void cdns_dp_phy_run(struct cdns_dp_phy *cdns_phy);
+static void cdns_dp_phy_wait_pma_cmn_ready(struct cdns_dp_phy *cdns_phy);
+static void cdns_dp_phy_pma_cfg(struct cdns_dp_phy *cdns_phy);
+static void cdns_dp_phy_pma_cmn_cfg_25mhz(struct cdns_dp_phy *cdns_phy);
+static void cdns_dp_phy_pma_lane_cfg(struct cdns_dp_phy *cdns_phy,
+ unsigned int lane);
+static void cdns_dp_phy_pma_cmn_vco_cfg_25mhz(struct cdns_dp_phy *cdns_phy);
+static void cdns_dp_phy_pma_cmn_rate(struct cdns_dp_phy *cdns_phy);
+static void cdns_dp_phy_write_field(struct cdns_dp_phy *cdns_phy,
+ unsigned int offset,
+ unsigned char start_bit,
+ unsigned char num_bits,
+ unsigned int val);
+
+static const struct phy_ops cdns_dp_phy_ops = {
+ .init = cdns_dp_phy_init,
+ .owner = THIS_MODULE,
+};
+
+static int cdns_dp_phy_init(struct phy *phy)
+{
+ unsigned char lane_bits;
+
+ struct cdns_dp_phy *cdns_phy = phy_get_drvdata(phy);
+
+ writel(0x0003, cdns_phy->base + PHY_AUX_CTRL); /* enable AUX */
+
+ /* PHY PMA registers configuration function */
+ cdns_dp_phy_pma_cfg(cdns_phy);
+
+ /*
+ * Set lines power state to A0
+ * Set lines pll clk enable to 0
+ */
+
+ cdns_dp_phy_write_field(cdns_phy, PHY_PMA_XCVR_POWER_STATE_REQ,
+ PHY_POWER_STATE_LN_0, 6, 0x0000);
+
+ if (cdns_phy->num_lanes >= 2) {
+ cdns_dp_phy_write_field(cdns_phy,
+ PHY_PMA_XCVR_POWER_STATE_REQ,
+ PHY_POWER_STATE_LN_1, 6, 0x0000);
+
+ if (cdns_phy->num_lanes == 4) {
+ cdns_dp_phy_write_field(cdns_phy,
+ PHY_PMA_XCVR_POWER_STATE_REQ,
+ PHY_POWER_STATE_LN_2, 6, 0);
+ cdns_dp_phy_write_field(cdns_phy,
+ PHY_PMA_XCVR_POWER_STATE_REQ,
+ PHY_POWER_STATE_LN_3, 6, 0);
+ }
+ }
+
+ cdns_dp_phy_write_field(cdns_phy, PHY_PMA_XCVR_PLLCLK_EN,
+ 0, 1, 0x0000);
+
+ if (cdns_phy->num_lanes >= 2) {
+ cdns_dp_phy_write_field(cdns_phy, PHY_PMA_XCVR_PLLCLK_EN,
+ 1, 1, 0x0000);
+ if (cdns_phy->num_lanes == 4) {
+ cdns_dp_phy_write_field(cdns_phy,
+ PHY_PMA_XCVR_PLLCLK_EN,
+ 2, 1, 0x0000);
+ cdns_dp_phy_write_field(cdns_phy,
+ PHY_PMA_XCVR_PLLCLK_EN,
+ 3, 1, 0x0000);
+ }
+ }
+
+ /*
+ * release phy_l0*_reset_n and pma_tx_elec_idle_ln_* based on
+ * used lanes
+ */
+ lane_bits = (1 << cdns_phy->num_lanes) - 1;
+ writel(((0xF & ~lane_bits) << 4) | (0xF & lane_bits),
+ cdns_phy->base + PHY_RESET);
+
+ /* release pma_xcvr_pllclk_en_ln_*, only for the master lane */
+ writel(0x0001, cdns_phy->base + PHY_PMA_XCVR_PLLCLK_EN);
+
+ /* PHY PMA registers configuration functions */
+ cdns_dp_phy_pma_cmn_vco_cfg_25mhz(cdns_phy);
+ cdns_dp_phy_pma_cmn_rate(cdns_phy);
+
+ /* take out of reset */
+ cdns_dp_phy_write_field(cdns_phy, PHY_RESET, 8, 1, 1);
+ cdns_dp_phy_wait_pma_cmn_ready(cdns_phy);
+ cdns_dp_phy_run(cdns_phy);
+
+ return 0;
+}
+
+static void cdns_dp_phy_wait_pma_cmn_ready(struct cdns_dp_phy *cdns_phy)
+{
+ unsigned int reg;
+ int ret;
+
+ ret = readl_poll_timeout(cdns_phy->base + PHY_PMA_CMN_READY, reg,
+ reg & 1, 0, 500);
+ if (ret == -ETIMEDOUT)
+ dev_err(cdns_phy->dev,
+ "timeout waiting for PMA common ready\n");
+}
+
+static void cdns_dp_phy_pma_cfg(struct cdns_dp_phy *cdns_phy)
+{
+ unsigned int i;
+
+ /* PMA common configuration */
+ cdns_dp_phy_pma_cmn_cfg_25mhz(cdns_phy);
+
+ /* PMA lane configuration to deal with multi-link operation */
+ for (i = 0; i < cdns_phy->num_lanes; i++)
+ cdns_dp_phy_pma_lane_cfg(cdns_phy, i);
+}
+
+static void cdns_dp_phy_pma_cmn_cfg_25mhz(struct cdns_dp_phy *cdns_phy)
+{
+ /* refclock registers - assumes 25 MHz refclock */
+ writel(0x0019, cdns_phy->sd_base + CMN_SSM_BIAS_TMR);
+ writel(0x0032, cdns_phy->sd_base + CMN_PLLSM0_PLLPRE_TMR);
+ writel(0x00D1, cdns_phy->sd_base + CMN_PLLSM0_PLLLOCK_TMR);
+ writel(0x0032, cdns_phy->sd_base + CMN_PLLSM1_PLLPRE_TMR);
+ writel(0x00D1, cdns_phy->sd_base + CMN_PLLSM1_PLLLOCK_TMR);
+ writel(0x007D, cdns_phy->sd_base + CMN_BGCAL_INIT_TMR);
+ writel(0x007D, cdns_phy->sd_base + CMN_BGCAL_ITER_TMR);
+ writel(0x0019, cdns_phy->sd_base + CMN_IBCAL_INIT_TMR);
+ writel(0x001E, cdns_phy->sd_base + CMN_TXPUCAL_INIT_TMR);
+ writel(0x0006, cdns_phy->sd_base + CMN_TXPUCAL_ITER_TMR);
+ writel(0x001E, cdns_phy->sd_base + CMN_TXPDCAL_INIT_TMR);
+ writel(0x0006, cdns_phy->sd_base + CMN_TXPDCAL_ITER_TMR);
+ writel(0x02EE, cdns_phy->sd_base + CMN_RXCAL_INIT_TMR);
+ writel(0x0006, cdns_phy->sd_base + CMN_RXCAL_ITER_TMR);
+ writel(0x0002, cdns_phy->sd_base + CMN_SD_CAL_INIT_TMR);
+ writel(0x0002, cdns_phy->sd_base + CMN_SD_CAL_ITER_TMR);
+ writel(0x000E, cdns_phy->sd_base + CMN_SD_CAL_REFTIM_START);
+ writel(0x012B, cdns_phy->sd_base + CMN_SD_CAL_PLLCNT_START);
+ /* PLL registers */
+ writel(0x0409, cdns_phy->sd_base + CMN_PDIAG_PLL0_CP_PADJ_M0);
+ writel(0x1001, cdns_phy->sd_base + CMN_PDIAG_PLL0_CP_IADJ_M0);
+ writel(0x0F08, cdns_phy->sd_base + CMN_PDIAG_PLL0_FILT_PADJ_M0);
+ writel(0x0004, cdns_phy->sd_base + CMN_PLL0_DSM_DIAG_M0);
+ writel(0x00FA, cdns_phy->sd_base + CMN_PLL0_VCOCAL_INIT_TMR);
+ writel(0x0004, cdns_phy->sd_base + CMN_PLL0_VCOCAL_ITER_TMR);
+ writel(0x00FA, cdns_phy->sd_base + CMN_PLL1_VCOCAL_INIT_TMR);
+ writel(0x0004, cdns_phy->sd_base + CMN_PLL1_VCOCAL_ITER_TMR);
+ writel(0x0318, cdns_phy->sd_base + CMN_PLL0_VCOCAL_REFTIM_START);
+}
+
+static void cdns_dp_phy_pma_cmn_vco_cfg_25mhz(struct cdns_dp_phy *cdns_phy)
+{
+ /* Assumes 25 MHz refclock */
+ switch (cdns_phy->max_bit_rate) {
+ /* Setting VCO for 10.8GHz */
+ case 2700:
+ case 5400:
+ writel(0x01B0, cdns_phy->sd_base + CMN_PLL0_INTDIV_M0);
+ writel(0x0000, cdns_phy->sd_base + CMN_PLL0_FRACDIVL_M0);
+ writel(0x0002, cdns_phy->sd_base + CMN_PLL0_FRACDIVH_M0);
+ writel(0x0120, cdns_phy->sd_base + CMN_PLL0_HIGH_THR_M0);
+ break;
+ /* Setting VCO for 9.72GHz */
+ case 2430:
+ case 3240:
+ writel(0x0184, cdns_phy->sd_base + CMN_PLL0_INTDIV_M0);
+ writel(0xCCCD, cdns_phy->sd_base + CMN_PLL0_FRACDIVL_M0);
+ writel(0x0002, cdns_phy->sd_base + CMN_PLL0_FRACDIVH_M0);
+ writel(0x0104, cdns_phy->sd_base + CMN_PLL0_HIGH_THR_M0);
+ break;
+ /* Setting VCO for 8.64GHz */
+ case 2160:
+ case 4320:
+ writel(0x0159, cdns_phy->sd_base + CMN_PLL0_INTDIV_M0);
+ writel(0x999A, cdns_phy->sd_base + CMN_PLL0_FRACDIVL_M0);
+ writel(0x0002, cdns_phy->sd_base + CMN_PLL0_FRACDIVH_M0);
+ writel(0x00E7, cdns_phy->sd_base + CMN_PLL0_HIGH_THR_M0);
+ break;
+ /* Setting VCO for 8.1GHz */
+ case 8100:
+ writel(0x0144, cdns_phy->sd_base + CMN_PLL0_INTDIV_M0);
+ writel(0x0000, cdns_phy->sd_base + CMN_PLL0_FRACDIVL_M0);
+ writel(0x0002, cdns_phy->sd_base + CMN_PLL0_FRACDIVH_M0);
+ writel(0x00D8, cdns_phy->sd_base + CMN_PLL0_HIGH_THR_M0);
+ break;
+ }
+
+ writel(0x0002, cdns_phy->sd_base + CMN_PDIAG_PLL0_CTRL_M0);
+ writel(0x0318, cdns_phy->sd_base + CMN_PLL0_VCOCAL_PLLCNT_START);
+}
+
+static void cdns_dp_phy_pma_cmn_rate(struct cdns_dp_phy *cdns_phy)
+{
+ unsigned int clk_sel_val = 0;
+ unsigned int hsclk_div_val = 0;
+ unsigned int i;
+
+ /* 16'h0000 for single DP link configuration */
+ writel(0x0000, cdns_phy->sd_base + PHY_PLL_CFG);
+
+ switch (cdns_phy->max_bit_rate) {
+ case 1620:
+ clk_sel_val = 0x0f01;
+ hsclk_div_val = 2;
+ break;
+ case 2160:
+ case 2430:
+ case 2700:
+ clk_sel_val = 0x0701;
+ hsclk_div_val = 1;
+ break;
+ case 3240:
+ clk_sel_val = 0x0b00;
+ hsclk_div_val = 2;
+ break;
+ case 4320:
+ case 5400:
+ clk_sel_val = 0x0301;
+ hsclk_div_val = 0;
+ break;
+ case 8100:
+ clk_sel_val = 0x0200;
+ hsclk_div_val = 0;
+ break;
+ }
+
+ writel(clk_sel_val, cdns_phy->sd_base + CMN_PDIAG_PLL0_CLK_SEL_M0);
+
+ /* PMA lane configuration to deal with multi-link operation */
+ for (i = 0; i < cdns_phy->num_lanes; i++) {
+ writel(hsclk_div_val,
+ cdns_phy->sd_base + (XCVR_DIAG_HSCLK_DIV | (i<<11)));
+ }
+}
+
+static void cdns_dp_phy_pma_lane_cfg(struct cdns_dp_phy *cdns_phy,
+ unsigned int lane)
+{
+ unsigned int lane_bits = (lane & LANE_MASK) << 11;
+
+ /* Writing Tx/Rx Power State Controllers registers */
+ writel(0x00FB, cdns_phy->sd_base + (TX_PSC_A0 | lane_bits));
+ writel(0x04AA, cdns_phy->sd_base + (TX_PSC_A2 | lane_bits));
+ writel(0x04AA, cdns_phy->sd_base + (TX_PSC_A3 | lane_bits));
+ writel(0x0000, cdns_phy->sd_base + (RX_PSC_A0 | lane_bits));
+ writel(0x0000, cdns_phy->sd_base + (RX_PSC_A2 | lane_bits));
+ writel(0x0000, cdns_phy->sd_base + (RX_PSC_A3 | lane_bits));
+
+ writel(0x0001, cdns_phy->sd_base + (XCVR_DIAG_PLLDRC_CTRL | lane_bits));
+ writel(0x0000, cdns_phy->sd_base + (XCVR_DIAG_HSCLK_SEL | lane_bits));
+}
+
+static void cdns_dp_phy_run(struct cdns_dp_phy *cdns_phy)
+{
+ unsigned int read_val;
+ u32 write_val1 = 0;
+ u32 write_val2 = 0;
+ u32 mask = 0;
+ int ret;
+
+ /*
+ * waiting for ACK of pma_xcvr_pllclk_en_ln_*, only for the
+ * master lane
+ */
+ ret = readl_poll_timeout(cdns_phy->base + PHY_PMA_XCVR_PLLCLK_EN_ACK,
+ read_val, read_val & 1, 0, POLL_TIMEOUT_US);
+ if (ret == -ETIMEDOUT)
+ dev_err(cdns_phy->dev,
+ "timeout waiting for link PLL clock enable ack\n");
+
+ ndelay(100);
+
+ switch (cdns_phy->num_lanes) {
+
+ case 1: /* lane 0 */
+ write_val1 = 0x00000004;
+ write_val2 = 0x00000001;
+ mask = 0x0000003f;
+ break;
+ case 2: /* lane 0-1 */
+ write_val1 = 0x00000404;
+ write_val2 = 0x00000101;
+ mask = 0x00003f3f;
+ break;
+ case 4: /* lane 0-3 */
+ write_val1 = 0x04040404;
+ write_val2 = 0x01010101;
+ mask = 0x3f3f3f3f;
+ break;
+ }
+
+ writel(write_val1, cdns_phy->base + PHY_PMA_XCVR_POWER_STATE_REQ);
+
+ ret = readl_poll_timeout(cdns_phy->base + PHY_PMA_XCVR_POWER_STATE_ACK,
+ read_val, (read_val & mask) == write_val1, 0,
+ POLL_TIMEOUT_US);
+ if (ret == -ETIMEDOUT)
+ dev_err(cdns_phy->dev,
+ "timeout waiting for link power state ack\n");
+
+ writel(0, cdns_phy->base + PHY_PMA_XCVR_POWER_STATE_REQ);
+ ndelay(100);
+
+ writel(write_val2, cdns_phy->base + PHY_PMA_XCVR_POWER_STATE_REQ);
+
+ ret = readl_poll_timeout(cdns_phy->base + PHY_PMA_XCVR_POWER_STATE_ACK,
+ read_val, (read_val & mask) == write_val2, 0,
+ POLL_TIMEOUT_US);
+ if (ret == -ETIMEDOUT)
+ dev_err(cdns_phy->dev,
+ "timeout waiting for link power state ack\n");
+
+ writel(0, cdns_phy->base + PHY_PMA_XCVR_POWER_STATE_REQ);
+ ndelay(100);
+}
+
+static void cdns_dp_phy_write_field(struct cdns_dp_phy *cdns_phy,
+ unsigned int offset,
+ unsigned char start_bit,
+ unsigned char num_bits,
+ unsigned int val)
+{
+ unsigned int read_val;
+
+ read_val = readl(cdns_phy->base + offset);
+ writel(((val << start_bit) | (read_val & ~(((1 << num_bits) - 1) <<
+ start_bit))), cdns_phy->base + offset);
+}
+
+static int cdns_dp_phy_probe(struct platform_device *pdev)
+{
+ struct resource *regs;
+ struct cdns_dp_phy *cdns_phy;
+ struct device *dev = &pdev->dev;
+ struct phy_provider *phy_provider;
+ struct phy *phy;
+ int err;
+
+ cdns_phy = devm_kzalloc(dev, sizeof(*cdns_phy), GFP_KERNEL);
+ if (!cdns_phy)
+ return -ENOMEM;
+
+ cdns_phy->dev = &pdev->dev;
+
+ phy = devm_phy_create(dev, NULL, &cdns_dp_phy_ops);
+ if (IS_ERR(phy)) {
+ dev_err(dev, "failed to create DisplayPort PHY\n");
+ return PTR_ERR(phy);
+ }
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ cdns_phy->base = devm_ioremap_resource(&pdev->dev, regs);
+ if (IS_ERR(cdns_phy->base))
+ return PTR_ERR(cdns_phy->base);
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ cdns_phy->sd_base = devm_ioremap_resource(&pdev->dev, regs);
+ if (IS_ERR(cdns_phy->sd_base))
+ return PTR_ERR(cdns_phy->sd_base);
+
+ err = device_property_read_u32(dev, "num_lanes",
+ &(cdns_phy->num_lanes));
+ if (err)
+ cdns_phy->num_lanes = DEFAULT_NUM_LANES;
+
+ switch (cdns_phy->num_lanes) {
+ case 1:
+ case 2:
+ case 4:
+ /* valid number of lanes */
+ break;
+ default:
+ dev_err(dev, "unsupported number of lanes: %d\n",
+ cdns_phy->num_lanes);
+ return -EINVAL;
+ }
+
+ err = device_property_read_u32(dev, "max_bit_rate",
+ &(cdns_phy->max_bit_rate));
+ if (err)
+ cdns_phy->max_bit_rate = DEFAULT_MAX_BIT_RATE;
+
+ switch (cdns_phy->max_bit_rate) {
+ case 2160:
+ case 2430:
+ case 2700:
+ case 3240:
+ case 4320:
+ case 5400:
+ case 8100:
+ /* valid bit rate */
+ break;
+ default:
+ dev_err(dev, "unsupported max bit rate: %dMbps\n",
+ cdns_phy->max_bit_rate);
+ return -EINVAL;
+ }
+
+ phy_set_drvdata(phy, cdns_phy);
+
+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+
+ dev_info(dev, "%d lanes, max bit rate %d.%03d Gbps\n",
+ cdns_phy->num_lanes,
+ cdns_phy->max_bit_rate / 1000,
+ cdns_phy->max_bit_rate % 1000);
+
+ return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static const struct of_device_id cdns_dp_phy_of_match[] = {
+ {
+ .compatible = "cdns,dp-phy"
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, cdns_dp_phy_of_match);
+
+static struct platform_driver cdns_dp_phy_driver = {
+ .probe = cdns_dp_phy_probe,
+ .driver = {
+ .name = "cdns-dp-phy",
+ .of_match_table = cdns_dp_phy_of_match,
+ }
+};
+module_platform_driver(cdns_dp_phy_driver);
+
+MODULE_AUTHOR("Cadence Design Systems, Inc.");
+MODULE_DESCRIPTION("Cadence MHDP PHY driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/lantiq/phy-lantiq-rcu-usb2.c b/drivers/phy/lantiq/phy-lantiq-rcu-usb2.c
index 986224fca9e9..f9e0dd19ff26 100644
--- a/drivers/phy/lantiq/phy-lantiq-rcu-usb2.c
+++ b/drivers/phy/lantiq/phy-lantiq-rcu-usb2.c
@@ -156,7 +156,6 @@ static int ltq_rcu_usb2_of_parse(struct ltq_rcu_usb2_priv *priv,
{
struct device *dev = priv->dev;
const __be32 *offset;
- int ret;
priv->reg_bits = of_device_get_match_data(dev);
@@ -196,10 +195,8 @@ static int ltq_rcu_usb2_of_parse(struct ltq_rcu_usb2_priv *priv,
}
priv->phy_reset = devm_reset_control_get_optional(dev, "phy");
- if (IS_ERR(priv->phy_reset))
- return PTR_ERR(priv->phy_reset);
- return 0;
+ return PTR_ERR_OR_ZERO(priv->phy_reset);
}
static int ltq_rcu_usb2_phy_probe(struct platform_device *pdev)
diff --git a/drivers/phy/marvell/Kconfig b/drivers/phy/marvell/Kconfig
index 68e321225400..6fb4b56e4c14 100644
--- a/drivers/phy/marvell/Kconfig
+++ b/drivers/phy/marvell/Kconfig
@@ -59,3 +59,14 @@ config PHY_PXA_28NM_USB2
The PHY driver will be used by Marvell udc/ehci/otg driver.
To compile this driver as a module, choose M here.
+
+config PHY_PXA_USB
+ tristate "Marvell PXA USB PHY Driver"
+ depends on ARCH_PXA || ARCH_MMP
+ select GENERIC_PHY
+ help
+ Enable this to support Marvell PXA USB PHY driver for Marvell
+ SoC. This driver will do the PHY initialization and shutdown.
+ The PHY driver will be used by Marvell udc/ehci/otg driver.
+
+ To compile this driver as a module, choose M here.
diff --git a/drivers/phy/marvell/Makefile b/drivers/phy/marvell/Makefile
index 5c3ec5d10e0d..3975b144f8ec 100644
--- a/drivers/phy/marvell/Makefile
+++ b/drivers/phy/marvell/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_PHY_MVEBU_CP110_COMPHY) += phy-mvebu-cp110-comphy.o
obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o
obj-$(CONFIG_PHY_PXA_28NM_HSIC) += phy-pxa-28nm-hsic.o
obj-$(CONFIG_PHY_PXA_28NM_USB2) += phy-pxa-28nm-usb2.o
+obj-$(CONFIG_PHY_PXA_USB) += phy-pxa-usb.o
diff --git a/drivers/phy/marvell/phy-berlin-sata.c b/drivers/phy/marvell/phy-berlin-sata.c
index c1bb6725e48f..a91fc67fc4e0 100644
--- a/drivers/phy/marvell/phy-berlin-sata.c
+++ b/drivers/phy/marvell/phy-berlin-sata.c
@@ -231,14 +231,14 @@ static int phy_berlin_sata_probe(struct platform_device *pdev)
struct phy_berlin_desc *phy_desc;
if (of_property_read_u32(child, "reg", &phy_id)) {
- dev_err(dev, "missing reg property in node %s\n",
- child->name);
+ dev_err(dev, "missing reg property in node %pOFn\n",
+ child);
ret = -EINVAL;
goto put_child;
}
if (phy_id >= ARRAY_SIZE(phy_berlin_power_down_bits)) {
- dev_err(dev, "invalid reg in node %s\n", child->name);
+ dev_err(dev, "invalid reg in node %pOFn\n", child);
ret = -EINVAL;
goto put_child;
}
diff --git a/drivers/phy/marvell/phy-pxa-usb.c b/drivers/phy/marvell/phy-pxa-usb.c
new file mode 100644
index 000000000000..87ff7550b912
--- /dev/null
+++ b/drivers/phy/marvell/phy-pxa-usb.c
@@ -0,0 +1,345 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
+ * Copyright (C) 2018 Lubomir Rintel <lkundrak@v3.sk>
+ */
+
+#include <dt-bindings/phy/phy.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+
+/* phy regs */
+#define UTMI_REVISION 0x0
+#define UTMI_CTRL 0x4
+#define UTMI_PLL 0x8
+#define UTMI_TX 0xc
+#define UTMI_RX 0x10
+#define UTMI_IVREF 0x14
+#define UTMI_T0 0x18
+#define UTMI_T1 0x1c
+#define UTMI_T2 0x20
+#define UTMI_T3 0x24
+#define UTMI_T4 0x28
+#define UTMI_T5 0x2c
+#define UTMI_RESERVE 0x30
+#define UTMI_USB_INT 0x34
+#define UTMI_DBG_CTL 0x38
+#define UTMI_OTG_ADDON 0x3c
+
+/* For UTMICTRL Register */
+#define UTMI_CTRL_USB_CLK_EN (1 << 31)
+/* pxa168 */
+#define UTMI_CTRL_SUSPEND_SET1 (1 << 30)
+#define UTMI_CTRL_SUSPEND_SET2 (1 << 29)
+#define UTMI_CTRL_RXBUF_PDWN (1 << 24)
+#define UTMI_CTRL_TXBUF_PDWN (1 << 11)
+
+#define UTMI_CTRL_INPKT_DELAY_SHIFT 30
+#define UTMI_CTRL_INPKT_DELAY_SOF_SHIFT 28
+#define UTMI_CTRL_PU_REF_SHIFT 20
+#define UTMI_CTRL_ARC_PULLDN_SHIFT 12
+#define UTMI_CTRL_PLL_PWR_UP_SHIFT 1
+#define UTMI_CTRL_PWR_UP_SHIFT 0
+
+/* For UTMI_PLL Register */
+#define UTMI_PLL_PLLCALI12_SHIFT 29
+#define UTMI_PLL_PLLCALI12_MASK (0x3 << 29)
+
+#define UTMI_PLL_PLLVDD18_SHIFT 27
+#define UTMI_PLL_PLLVDD18_MASK (0x3 << 27)
+
+#define UTMI_PLL_PLLVDD12_SHIFT 25
+#define UTMI_PLL_PLLVDD12_MASK (0x3 << 25)
+
+#define UTMI_PLL_CLK_BLK_EN_SHIFT 24
+#define CLK_BLK_EN (0x1 << 24)
+#define PLL_READY (0x1 << 23)
+#define KVCO_EXT (0x1 << 22)
+#define VCOCAL_START (0x1 << 21)
+
+#define UTMI_PLL_KVCO_SHIFT 15
+#define UTMI_PLL_KVCO_MASK (0x7 << 15)
+
+#define UTMI_PLL_ICP_SHIFT 12
+#define UTMI_PLL_ICP_MASK (0x7 << 12)
+
+#define UTMI_PLL_FBDIV_SHIFT 4
+#define UTMI_PLL_FBDIV_MASK (0xFF << 4)
+
+#define UTMI_PLL_REFDIV_SHIFT 0
+#define UTMI_PLL_REFDIV_MASK (0xF << 0)
+
+/* For UTMI_TX Register */
+#define UTMI_TX_REG_EXT_FS_RCAL_SHIFT 27
+#define UTMI_TX_REG_EXT_FS_RCAL_MASK (0xf << 27)
+
+#define UTMI_TX_REG_EXT_FS_RCAL_EN_SHIFT 26
+#define UTMI_TX_REG_EXT_FS_RCAL_EN_MASK (0x1 << 26)
+
+#define UTMI_TX_TXVDD12_SHIFT 22
+#define UTMI_TX_TXVDD12_MASK (0x3 << 22)
+
+#define UTMI_TX_CK60_PHSEL_SHIFT 17
+#define UTMI_TX_CK60_PHSEL_MASK (0xf << 17)
+
+#define UTMI_TX_IMPCAL_VTH_SHIFT 14
+#define UTMI_TX_IMPCAL_VTH_MASK (0x7 << 14)
+
+#define REG_RCAL_START (0x1 << 12)
+
+#define UTMI_TX_LOW_VDD_EN_SHIFT 11
+
+#define UTMI_TX_AMP_SHIFT 0
+#define UTMI_TX_AMP_MASK (0x7 << 0)
+
+/* For UTMI_RX Register */
+#define UTMI_REG_SQ_LENGTH_SHIFT 15
+#define UTMI_REG_SQ_LENGTH_MASK (0x3 << 15)
+
+#define UTMI_RX_SQ_THRESH_SHIFT 4
+#define UTMI_RX_SQ_THRESH_MASK (0xf << 4)
+
+#define UTMI_OTG_ADDON_OTG_ON (1 << 0)
+
+enum pxa_usb_phy_version {
+ PXA_USB_PHY_MMP2,
+ PXA_USB_PHY_PXA910,
+ PXA_USB_PHY_PXA168,
+};
+
+struct pxa_usb_phy {
+ struct phy *phy;
+ void __iomem *base;
+ enum pxa_usb_phy_version version;
+};
+
+/*****************************************************************************
+ * The registers read/write routines
+ *****************************************************************************/
+
+static unsigned int u2o_get(void __iomem *base, unsigned int offset)
+{
+ return readl_relaxed(base + offset);
+}
+
+static void u2o_set(void __iomem *base, unsigned int offset,
+ unsigned int value)
+{
+ u32 reg;
+
+ reg = readl_relaxed(base + offset);
+ reg |= value;
+ writel_relaxed(reg, base + offset);
+ readl_relaxed(base + offset);
+}
+
+static void u2o_clear(void __iomem *base, unsigned int offset,
+ unsigned int value)
+{
+ u32 reg;
+
+ reg = readl_relaxed(base + offset);
+ reg &= ~value;
+ writel_relaxed(reg, base + offset);
+ readl_relaxed(base + offset);
+}
+
+static void u2o_write(void __iomem *base, unsigned int offset,
+ unsigned int value)
+{
+ writel_relaxed(value, base + offset);
+ readl_relaxed(base + offset);
+}
+
+static int pxa_usb_phy_init(struct phy *phy)
+{
+ struct pxa_usb_phy *pxa_usb_phy = phy_get_drvdata(phy);
+ void __iomem *base = pxa_usb_phy->base;
+ int loops;
+
+ dev_info(&phy->dev, "initializing Marvell PXA USB PHY");
+
+ /* Initialize the USB PHY power */
+ if (pxa_usb_phy->version == PXA_USB_PHY_PXA910) {
+ u2o_set(base, UTMI_CTRL, (1<<UTMI_CTRL_INPKT_DELAY_SOF_SHIFT)
+ | (1<<UTMI_CTRL_PU_REF_SHIFT));
+ }
+
+ u2o_set(base, UTMI_CTRL, 1<<UTMI_CTRL_PLL_PWR_UP_SHIFT);
+ u2o_set(base, UTMI_CTRL, 1<<UTMI_CTRL_PWR_UP_SHIFT);
+
+ /* UTMI_PLL settings */
+ u2o_clear(base, UTMI_PLL, UTMI_PLL_PLLVDD18_MASK
+ | UTMI_PLL_PLLVDD12_MASK | UTMI_PLL_PLLCALI12_MASK
+ | UTMI_PLL_FBDIV_MASK | UTMI_PLL_REFDIV_MASK
+ | UTMI_PLL_ICP_MASK | UTMI_PLL_KVCO_MASK);
+
+ u2o_set(base, UTMI_PLL, 0xee<<UTMI_PLL_FBDIV_SHIFT
+ | 0xb<<UTMI_PLL_REFDIV_SHIFT | 3<<UTMI_PLL_PLLVDD18_SHIFT
+ | 3<<UTMI_PLL_PLLVDD12_SHIFT | 3<<UTMI_PLL_PLLCALI12_SHIFT
+ | 1<<UTMI_PLL_ICP_SHIFT | 3<<UTMI_PLL_KVCO_SHIFT);
+
+ /* UTMI_TX */
+ u2o_clear(base, UTMI_TX, UTMI_TX_REG_EXT_FS_RCAL_EN_MASK
+ | UTMI_TX_TXVDD12_MASK | UTMI_TX_CK60_PHSEL_MASK
+ | UTMI_TX_IMPCAL_VTH_MASK | UTMI_TX_REG_EXT_FS_RCAL_MASK
+ | UTMI_TX_AMP_MASK);
+ u2o_set(base, UTMI_TX, 3<<UTMI_TX_TXVDD12_SHIFT
+ | 4<<UTMI_TX_CK60_PHSEL_SHIFT | 4<<UTMI_TX_IMPCAL_VTH_SHIFT
+ | 8<<UTMI_TX_REG_EXT_FS_RCAL_SHIFT | 3<<UTMI_TX_AMP_SHIFT);
+
+ /* UTMI_RX */
+ u2o_clear(base, UTMI_RX, UTMI_RX_SQ_THRESH_MASK
+ | UTMI_REG_SQ_LENGTH_MASK);
+ u2o_set(base, UTMI_RX, 7<<UTMI_RX_SQ_THRESH_SHIFT
+ | 2<<UTMI_REG_SQ_LENGTH_SHIFT);
+
+ /* UTMI_IVREF */
+ if (pxa_usb_phy->version == PXA_USB_PHY_PXA168) {
+ /*
+ * fixing Microsoft Altair board interface with NEC hub issue -
+ * Set UTMI_IVREF from 0x4a3 to 0x4bf
+ */
+ u2o_write(base, UTMI_IVREF, 0x4bf);
+ }
+
+ /* toggle VCOCAL_START bit of UTMI_PLL */
+ udelay(200);
+ u2o_set(base, UTMI_PLL, VCOCAL_START);
+ udelay(40);
+ u2o_clear(base, UTMI_PLL, VCOCAL_START);
+
+ /* toggle REG_RCAL_START bit of UTMI_TX */
+ udelay(400);
+ u2o_set(base, UTMI_TX, REG_RCAL_START);
+ udelay(40);
+ u2o_clear(base, UTMI_TX, REG_RCAL_START);
+ udelay(400);
+
+ /* Make sure PHY PLL is ready */
+ loops = 0;
+ while ((u2o_get(base, UTMI_PLL) & PLL_READY) == 0) {
+ mdelay(1);
+ loops++;
+ if (loops > 100) {
+ dev_warn(&phy->dev, "calibrate timeout, UTMI_PLL %x\n",
+ u2o_get(base, UTMI_PLL));
+ break;
+ }
+ }
+
+ if (pxa_usb_phy->version == PXA_USB_PHY_PXA168) {
+ u2o_set(base, UTMI_RESERVE, 1 << 5);
+ /* Turn on UTMI PHY OTG extension */
+ u2o_write(base, UTMI_OTG_ADDON, 1);
+ }
+
+ return 0;
+
+}
+
+static int pxa_usb_phy_exit(struct phy *phy)
+{
+ struct pxa_usb_phy *pxa_usb_phy = phy_get_drvdata(phy);
+ void __iomem *base = pxa_usb_phy->base;
+
+ dev_info(&phy->dev, "deinitializing Marvell PXA USB PHY");
+
+ if (pxa_usb_phy->version == PXA_USB_PHY_PXA168)
+ u2o_clear(base, UTMI_OTG_ADDON, UTMI_OTG_ADDON_OTG_ON);
+
+ u2o_clear(base, UTMI_CTRL, UTMI_CTRL_RXBUF_PDWN);
+ u2o_clear(base, UTMI_CTRL, UTMI_CTRL_TXBUF_PDWN);
+ u2o_clear(base, UTMI_CTRL, UTMI_CTRL_USB_CLK_EN);
+ u2o_clear(base, UTMI_CTRL, 1<<UTMI_CTRL_PWR_UP_SHIFT);
+ u2o_clear(base, UTMI_CTRL, 1<<UTMI_CTRL_PLL_PWR_UP_SHIFT);
+
+ return 0;
+}
+
+static const struct phy_ops pxa_usb_phy_ops = {
+ .init = pxa_usb_phy_init,
+ .exit = pxa_usb_phy_exit,
+ .owner = THIS_MODULE,
+};
+
+static const struct of_device_id pxa_usb_phy_of_match[] = {
+ {
+ .compatible = "marvell,mmp2-usb-phy",
+ .data = (void *)PXA_USB_PHY_MMP2,
+ }, {
+ .compatible = "marvell,pxa910-usb-phy",
+ .data = (void *)PXA_USB_PHY_PXA910,
+ }, {
+ .compatible = "marvell,pxa168-usb-phy",
+ .data = (void *)PXA_USB_PHY_PXA168,
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, pxa_usb_phy_of_match);
+
+static int pxa_usb_phy_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *resource;
+ struct pxa_usb_phy *pxa_usb_phy;
+ struct phy_provider *provider;
+ const struct of_device_id *of_id;
+
+ pxa_usb_phy = devm_kzalloc(dev, sizeof(struct pxa_usb_phy), GFP_KERNEL);
+ if (!pxa_usb_phy)
+ return -ENOMEM;
+
+ of_id = of_match_node(pxa_usb_phy_of_match, dev->of_node);
+ if (of_id)
+ pxa_usb_phy->version = (enum pxa_usb_phy_version)of_id->data;
+ else
+ pxa_usb_phy->version = PXA_USB_PHY_MMP2;
+
+ resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ pxa_usb_phy->base = devm_ioremap_resource(dev, resource);
+ if (IS_ERR(pxa_usb_phy->base)) {
+ dev_err(dev, "failed to remap PHY regs\n");
+ return PTR_ERR(pxa_usb_phy->base);
+ }
+
+ pxa_usb_phy->phy = devm_phy_create(dev, NULL, &pxa_usb_phy_ops);
+ if (IS_ERR(pxa_usb_phy->phy)) {
+ dev_err(dev, "failed to create PHY\n");
+ return PTR_ERR(pxa_usb_phy->phy);
+ }
+
+ phy_set_drvdata(pxa_usb_phy->phy, pxa_usb_phy);
+ provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+ if (IS_ERR(provider)) {
+ dev_err(dev, "failed to register PHY provider\n");
+ return PTR_ERR(provider);
+ }
+
+ if (!dev->of_node) {
+ phy_create_lookup(pxa_usb_phy->phy, "usb", "mv-udc");
+ phy_create_lookup(pxa_usb_phy->phy, "usb", "pxa-u2oehci");
+ phy_create_lookup(pxa_usb_phy->phy, "usb", "mv-otg");
+ }
+
+ dev_info(dev, "Marvell PXA USB PHY");
+ return 0;
+}
+
+static struct platform_driver pxa_usb_phy_driver = {
+ .probe = pxa_usb_phy_probe,
+ .driver = {
+ .name = "pxa-usb-phy",
+ .of_match_table = pxa_usb_phy_of_match,
+ },
+};
+module_platform_driver(pxa_usb_phy_driver);
+
+MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>");
+MODULE_DESCRIPTION("Marvell PXA USB PHY Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/motorola/phy-mapphone-mdm6600.c b/drivers/phy/motorola/phy-mapphone-mdm6600.c
index 0075fb0bef8c..25d456a323c2 100644
--- a/drivers/phy/motorola/phy-mapphone-mdm6600.c
+++ b/drivers/phy/motorola/phy-mapphone-mdm6600.c
@@ -157,15 +157,13 @@ static const struct phy_ops gpio_usb_ops = {
*/
static void phy_mdm6600_cmd(struct phy_mdm6600 *ddata, int val)
{
- int values[PHY_MDM6600_NR_CMD_LINES];
- int i;
+ DECLARE_BITMAP(values, PHY_MDM6600_NR_CMD_LINES);
- val &= (1 << PHY_MDM6600_NR_CMD_LINES) - 1;
- for (i = 0; i < PHY_MDM6600_NR_CMD_LINES; i++)
- values[i] = (val & BIT(i)) >> i;
+ values[0] = val;
gpiod_set_array_value_cansleep(PHY_MDM6600_NR_CMD_LINES,
- ddata->cmd_gpios->desc, values);
+ ddata->cmd_gpios->desc,
+ ddata->cmd_gpios->info, values);
}
/**
@@ -176,7 +174,7 @@ static void phy_mdm6600_status(struct work_struct *work)
{
struct phy_mdm6600 *ddata;
struct device *dev;
- int values[PHY_MDM6600_NR_STATUS_LINES];
+ DECLARE_BITMAP(values, PHY_MDM6600_NR_STATUS_LINES);
int error, i, val = 0;
ddata = container_of(work, struct phy_mdm6600, status_work.work);
@@ -184,16 +182,17 @@ static void phy_mdm6600_status(struct work_struct *work)
error = gpiod_get_array_value_cansleep(PHY_MDM6600_NR_STATUS_LINES,
ddata->status_gpios->desc,
+ ddata->status_gpios->info,
values);
if (error)
return;
for (i = 0; i < PHY_MDM6600_NR_STATUS_LINES; i++) {
- val |= values[i] << i;
+ val |= test_bit(i, values) << i;
dev_dbg(ddata->dev, "XXX %s: i: %i values[i]: %i val: %i\n",
- __func__, i, values[i], val);
+ __func__, i, test_bit(i, values), val);
}
- ddata->status = val;
+ ddata->status = values[0];
dev_info(dev, "modem status: %i %s\n",
ddata->status,
diff --git a/drivers/phy/mscc/Kconfig b/drivers/phy/mscc/Kconfig
new file mode 100644
index 000000000000..2e2a466efd66
--- /dev/null
+++ b/drivers/phy/mscc/Kconfig
@@ -0,0 +1,11 @@
+#
+# Phy drivers for Microsemi devices
+#
+
+config PHY_OCELOT_SERDES
+ tristate "SerDes PHY driver for Microsemi Ocelot"
+ select GENERIC_PHY
+ depends on OF
+ depends on MFD_SYSCON
+ help
+ Enable this for supporting SerDes muxing with Microsemi Ocelot.
diff --git a/drivers/phy/mscc/Makefile b/drivers/phy/mscc/Makefile
new file mode 100644
index 000000000000..e14749170fc9
--- /dev/null
+++ b/drivers/phy/mscc/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Microsemi phy drivers.
+#
+
+obj-$(CONFIG_PHY_OCELOT_SERDES) := phy-ocelot-serdes.o
diff --git a/drivers/phy/mscc/phy-ocelot-serdes.c b/drivers/phy/mscc/phy-ocelot-serdes.c
new file mode 100644
index 000000000000..cbb49d9da6f9
--- /dev/null
+++ b/drivers/phy/mscc/phy-ocelot-serdes.c
@@ -0,0 +1,295 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * SerDes PHY driver for Microsemi Ocelot
+ *
+ * Copyright (c) 2018 Microsemi
+ *
+ */
+
+#include <linux/err.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/platform_device.h>
+#include <linux/regmap.h>
+#include <soc/mscc/ocelot_hsio.h>
+#include <dt-bindings/phy/phy-ocelot-serdes.h>
+
+struct serdes_ctrl {
+ struct regmap *regs;
+ struct device *dev;
+ struct phy *phys[SERDES_MAX];
+};
+
+struct serdes_macro {
+ u8 idx;
+ /* Not used when in QSGMII or PCIe mode */
+ int port;
+ struct serdes_ctrl *ctrl;
+};
+
+#define MCB_S1G_CFG_TIMEOUT 50
+
+static int __serdes_write_mcb_s1g(struct regmap *regmap, u8 macro, u32 op)
+{
+ unsigned int regval;
+
+ regmap_write(regmap, HSIO_MCB_S1G_ADDR_CFG, op |
+ HSIO_MCB_S1G_ADDR_CFG_SERDES1G_ADDR(BIT(macro)));
+
+ return regmap_read_poll_timeout(regmap, HSIO_MCB_S1G_ADDR_CFG, regval,
+ (regval & op) != op, 100,
+ MCB_S1G_CFG_TIMEOUT * 1000);
+}
+
+static int serdes_commit_mcb_s1g(struct regmap *regmap, u8 macro)
+{
+ return __serdes_write_mcb_s1g(regmap, macro,
+ HSIO_MCB_S1G_ADDR_CFG_SERDES1G_WR_ONE_SHOT);
+}
+
+static int serdes_update_mcb_s1g(struct regmap *regmap, u8 macro)
+{
+ return __serdes_write_mcb_s1g(regmap, macro,
+ HSIO_MCB_S1G_ADDR_CFG_SERDES1G_RD_ONE_SHOT);
+}
+
+static int serdes_init_s1g(struct regmap *regmap, u8 serdes)
+{
+ int ret;
+
+ ret = serdes_update_mcb_s1g(regmap, serdes);
+ if (ret)
+ return ret;
+
+ regmap_update_bits(regmap, HSIO_S1G_COMMON_CFG,
+ HSIO_S1G_COMMON_CFG_SYS_RST |
+ HSIO_S1G_COMMON_CFG_ENA_LANE |
+ HSIO_S1G_COMMON_CFG_ENA_ELOOP |
+ HSIO_S1G_COMMON_CFG_ENA_FLOOP,
+ HSIO_S1G_COMMON_CFG_ENA_LANE);
+
+ regmap_update_bits(regmap, HSIO_S1G_PLL_CFG,
+ HSIO_S1G_PLL_CFG_PLL_FSM_ENA |
+ HSIO_S1G_PLL_CFG_PLL_FSM_CTRL_DATA_M,
+ HSIO_S1G_PLL_CFG_PLL_FSM_CTRL_DATA(200) |
+ HSIO_S1G_PLL_CFG_PLL_FSM_ENA);
+
+ regmap_update_bits(regmap, HSIO_S1G_MISC_CFG,
+ HSIO_S1G_MISC_CFG_DES_100FX_CPMD_ENA |
+ HSIO_S1G_MISC_CFG_LANE_RST,
+ HSIO_S1G_MISC_CFG_LANE_RST);
+
+ ret = serdes_commit_mcb_s1g(regmap, serdes);
+ if (ret)
+ return ret;
+
+ regmap_update_bits(regmap, HSIO_S1G_COMMON_CFG,
+ HSIO_S1G_COMMON_CFG_SYS_RST,
+ HSIO_S1G_COMMON_CFG_SYS_RST);
+
+ regmap_update_bits(regmap, HSIO_S1G_MISC_CFG,
+ HSIO_S1G_MISC_CFG_LANE_RST, 0);
+
+ ret = serdes_commit_mcb_s1g(regmap, serdes);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+struct serdes_mux {
+ u8 idx;
+ u8 port;
+ enum phy_mode mode;
+ u32 mask;
+ u32 mux;
+};
+
+#define SERDES_MUX(_idx, _port, _mode, _mask, _mux) { \
+ .idx = _idx, \
+ .port = _port, \
+ .mode = _mode, \
+ .mask = _mask, \
+ .mux = _mux, \
+}
+
+#define SERDES_MUX_SGMII(i, p, m, c) SERDES_MUX(i, p, PHY_MODE_SGMII, m, c)
+#define SERDES_MUX_QSGMII(i, p, m, c) SERDES_MUX(i, p, PHY_MODE_QSGMII, m, c)
+
+static const struct serdes_mux ocelot_serdes_muxes[] = {
+ SERDES_MUX_SGMII(SERDES1G(0), 0, 0, 0),
+ SERDES_MUX_SGMII(SERDES1G(1), 1, HSIO_HW_CFG_DEV1G_5_MODE, 0),
+ SERDES_MUX_SGMII(SERDES1G(1), 5, HSIO_HW_CFG_QSGMII_ENA |
+ HSIO_HW_CFG_DEV1G_5_MODE, HSIO_HW_CFG_DEV1G_5_MODE),
+ SERDES_MUX_SGMII(SERDES1G(2), 2, HSIO_HW_CFG_DEV1G_4_MODE, 0),
+ SERDES_MUX_SGMII(SERDES1G(2), 4, HSIO_HW_CFG_QSGMII_ENA |
+ HSIO_HW_CFG_DEV1G_4_MODE, HSIO_HW_CFG_DEV1G_4_MODE),
+ SERDES_MUX_SGMII(SERDES1G(3), 3, HSIO_HW_CFG_DEV1G_6_MODE, 0),
+ SERDES_MUX_SGMII(SERDES1G(3), 6, HSIO_HW_CFG_QSGMII_ENA |
+ HSIO_HW_CFG_DEV1G_6_MODE, HSIO_HW_CFG_DEV1G_6_MODE),
+ SERDES_MUX_SGMII(SERDES1G(4), 4, HSIO_HW_CFG_QSGMII_ENA |
+ HSIO_HW_CFG_DEV1G_4_MODE | HSIO_HW_CFG_DEV1G_9_MODE,
+ 0),
+ SERDES_MUX_SGMII(SERDES1G(4), 9, HSIO_HW_CFG_DEV1G_4_MODE |
+ HSIO_HW_CFG_DEV1G_9_MODE, HSIO_HW_CFG_DEV1G_4_MODE |
+ HSIO_HW_CFG_DEV1G_9_MODE),
+ SERDES_MUX_SGMII(SERDES1G(5), 5, HSIO_HW_CFG_QSGMII_ENA |
+ HSIO_HW_CFG_DEV1G_5_MODE | HSIO_HW_CFG_DEV2G5_10_MODE,
+ 0),
+ SERDES_MUX_SGMII(SERDES1G(5), 10, HSIO_HW_CFG_PCIE_ENA |
+ HSIO_HW_CFG_DEV1G_5_MODE | HSIO_HW_CFG_DEV2G5_10_MODE,
+ HSIO_HW_CFG_DEV1G_5_MODE | HSIO_HW_CFG_DEV2G5_10_MODE),
+ SERDES_MUX_QSGMII(SERDES6G(0), 4, HSIO_HW_CFG_QSGMII_ENA,
+ HSIO_HW_CFG_QSGMII_ENA),
+ SERDES_MUX_QSGMII(SERDES6G(0), 5, HSIO_HW_CFG_QSGMII_ENA,
+ HSIO_HW_CFG_QSGMII_ENA),
+ SERDES_MUX_QSGMII(SERDES6G(0), 6, HSIO_HW_CFG_QSGMII_ENA,
+ HSIO_HW_CFG_QSGMII_ENA),
+ SERDES_MUX_SGMII(SERDES6G(0), 7, HSIO_HW_CFG_QSGMII_ENA, 0),
+ SERDES_MUX_QSGMII(SERDES6G(0), 7, HSIO_HW_CFG_QSGMII_ENA,
+ HSIO_HW_CFG_QSGMII_ENA),
+ SERDES_MUX_SGMII(SERDES6G(1), 8, 0, 0),
+ SERDES_MUX_SGMII(SERDES6G(2), 10, HSIO_HW_CFG_PCIE_ENA |
+ HSIO_HW_CFG_DEV2G5_10_MODE, 0),
+ SERDES_MUX(SERDES6G(2), 10, PHY_MODE_PCIE, HSIO_HW_CFG_PCIE_ENA,
+ HSIO_HW_CFG_PCIE_ENA),
+};
+
+static int serdes_set_mode(struct phy *phy, enum phy_mode mode)
+{
+ struct serdes_macro *macro = phy_get_drvdata(phy);
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < ARRAY_SIZE(ocelot_serdes_muxes); i++) {
+ if (macro->idx != ocelot_serdes_muxes[i].idx ||
+ mode != ocelot_serdes_muxes[i].mode)
+ continue;
+
+ if (mode != PHY_MODE_QSGMII &&
+ macro->port != ocelot_serdes_muxes[i].port)
+ continue;
+
+ ret = regmap_update_bits(macro->ctrl->regs, HSIO_HW_CFG,
+ ocelot_serdes_muxes[i].mask,
+ ocelot_serdes_muxes[i].mux);
+ if (ret)
+ return ret;
+
+ if (macro->idx <= SERDES1G_MAX)
+ return serdes_init_s1g(macro->ctrl->regs, macro->idx);
+
+ /* SERDES6G and PCIe not supported yet */
+ return -EOPNOTSUPP;
+ }
+
+ return -EINVAL;
+}
+
+static const struct phy_ops serdes_ops = {
+ .set_mode = serdes_set_mode,
+ .owner = THIS_MODULE,
+};
+
+static struct phy *serdes_simple_xlate(struct device *dev,
+ struct of_phandle_args *args)
+{
+ struct serdes_ctrl *ctrl = dev_get_drvdata(dev);
+ unsigned int port, idx, i;
+
+ if (args->args_count != 2)
+ return ERR_PTR(-EINVAL);
+
+ port = args->args[0];
+ idx = args->args[1];
+
+ for (i = 0; i < SERDES_MAX; i++) {
+ struct serdes_macro *macro = phy_get_drvdata(ctrl->phys[i]);
+
+ if (idx != macro->idx)
+ continue;
+
+ /* SERDES6G(0) is the only SerDes capable of QSGMII */
+ if (idx != SERDES6G(0) && macro->port >= 0)
+ return ERR_PTR(-EBUSY);
+
+ macro->port = port;
+ return ctrl->phys[i];
+ }
+
+ return ERR_PTR(-ENODEV);
+}
+
+static int serdes_phy_create(struct serdes_ctrl *ctrl, u8 idx, struct phy **phy)
+{
+ struct serdes_macro *macro;
+
+ *phy = devm_phy_create(ctrl->dev, NULL, &serdes_ops);
+ if (IS_ERR(*phy))
+ return PTR_ERR(*phy);
+
+ macro = devm_kzalloc(ctrl->dev, sizeof(*macro), GFP_KERNEL);
+ if (!macro)
+ return -ENOMEM;
+
+ macro->idx = idx;
+ macro->ctrl = ctrl;
+ macro->port = -1;
+
+ phy_set_drvdata(*phy, macro);
+
+ return 0;
+}
+
+static int serdes_probe(struct platform_device *pdev)
+{
+ struct phy_provider *provider;
+ struct serdes_ctrl *ctrl;
+ unsigned int i;
+ int ret;
+
+ ctrl = devm_kzalloc(&pdev->dev, sizeof(*ctrl), GFP_KERNEL);
+ if (!ctrl)
+ return -ENOMEM;
+
+ ctrl->dev = &pdev->dev;
+ ctrl->regs = syscon_node_to_regmap(pdev->dev.parent->of_node);
+ if (IS_ERR(ctrl->regs))
+ return PTR_ERR(ctrl->regs);
+
+ for (i = 0; i < SERDES_MAX; i++) {
+ ret = serdes_phy_create(ctrl, i, &ctrl->phys[i]);
+ if (ret)
+ return ret;
+ }
+
+ dev_set_drvdata(&pdev->dev, ctrl);
+
+ provider = devm_of_phy_provider_register(ctrl->dev,
+ serdes_simple_xlate);
+
+ return PTR_ERR_OR_ZERO(provider);
+}
+
+static const struct of_device_id serdes_ids[] = {
+ { .compatible = "mscc,vsc7514-serdes", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, serdes_ids);
+
+static struct platform_driver mscc_ocelot_serdes = {
+ .probe = serdes_probe,
+ .driver = {
+ .name = "mscc,ocelot-serdes",
+ .of_match_table = of_match_ptr(serdes_ids),
+ },
+};
+
+module_platform_driver(mscc_ocelot_serdes);
+
+MODULE_AUTHOR("Quentin Schulz <quentin.schulz@bootlin.com>");
+MODULE_DESCRIPTION("SerDes driver for Microsemi Ocelot");
+MODULE_LICENSE("Dual MIT/GPL");
diff --git a/drivers/phy/qualcomm/Kconfig b/drivers/phy/qualcomm/Kconfig
index 632a0e73ee10..32f7d34eb784 100644
--- a/drivers/phy/qualcomm/Kconfig
+++ b/drivers/phy/qualcomm/Kconfig
@@ -50,6 +50,23 @@ config PHY_QCOM_UFS
help
Support for UFS PHY on QCOM chipsets.
+if PHY_QCOM_UFS
+
+config PHY_QCOM_UFS_14NM
+ tristate
+ default PHY_QCOM_UFS
+ help
+ Support for 14nm UFS QMP phy present on QCOM chipsets.
+
+config PHY_QCOM_UFS_20NM
+ tristate
+ default PHY_QCOM_UFS
+ depends on BROKEN
+ help
+ Support for 20nm UFS QMP phy present on QCOM chipsets.
+
+endif
+
config PHY_QCOM_USB_HS
tristate "Qualcomm USB HS PHY module"
depends on USB_ULPI_BUS
diff --git a/drivers/phy/qualcomm/Makefile b/drivers/phy/qualcomm/Makefile
index deb831f453ae..c56efd3af205 100644
--- a/drivers/phy/qualcomm/Makefile
+++ b/drivers/phy/qualcomm/Makefile
@@ -5,7 +5,7 @@ obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o
obj-$(CONFIG_PHY_QCOM_QMP) += phy-qcom-qmp.o
obj-$(CONFIG_PHY_QCOM_QUSB2) += phy-qcom-qusb2.o
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o
-obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o
-obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o
+obj-$(CONFIG_PHY_QCOM_UFS_14NM) += phy-qcom-ufs-qmp-14nm.o
+obj-$(CONFIG_PHY_QCOM_UFS_20NM) += phy-qcom-ufs-qmp-20nm.o
obj-$(CONFIG_PHY_QCOM_USB_HS) += phy-qcom-usb-hs.o
obj-$(CONFIG_PHY_QCOM_USB_HSIC) += phy-qcom-usb-hsic.o
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c b/drivers/phy/qualcomm/phy-qcom-qmp.c
index 4c470104a0d6..a83332411026 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.c
@@ -156,6 +156,11 @@ static const unsigned int qmp_v3_usb3phy_regs_layout[] = {
[QPHY_PCS_LFPS_RXTERM_IRQ_STATUS] = 0x170,
};
+static const unsigned int sdm845_ufsphy_regs_layout[] = {
+ [QPHY_START_CTRL] = 0x00,
+ [QPHY_PCS_READY_STATUS] = 0x160,
+};
+
static const struct qmp_phy_init_tbl msm8996_pcie_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x1c),
QMP_PHY_INIT_CFG(QSERDES_COM_CLK_ENABLE1, 0x10),
@@ -601,6 +606,83 @@ static const struct qmp_phy_init_tbl qmp_v3_usb3_uniphy_pcs_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_V3_PCS_REFGEN_REQ_CONFIG2, 0x60),
};
+static const struct qmp_phy_init_tbl sdm845_ufsphy_serdes_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYS_CLK_CTRL, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_BG_TIMER, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_IVCO, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_CONFIG, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_EN_SEL, 0xd5),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_RESETSM_CNTRL, 0x20),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x30),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_HSCLK_SEL, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_EN, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_CTRL, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORE_CLK_EN, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_MAP, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_SVS_MODE_CLK_SEL, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_INITVAL1, 0xff),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_INITVAL2, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_DEC_START_MODE0, 0x82),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_CP_CTRL_MODE0, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_RCTRL_MODE0, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_CCTRL_MODE0, 0x36),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE0, 0x3f),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE1_MODE0, 0xda),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE2_MODE0, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP1_MODE0, 0xff),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP2_MODE0, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_DEC_START_MODE1, 0x98),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_CP_CTRL_MODE1, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_RCTRL_MODE1, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_CCTRL_MODE1, 0x36),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE1, 0x3f),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE1_MODE1, 0xc1),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE2_MODE1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP1_MODE1, 0x32),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP2_MODE1, 0x0f),
+
+ /* Rate B */
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_MAP, 0x44),
+};
+
+static const struct qmp_phy_init_tbl sdm845_ufsphy_tx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V3_TX_LANE_MODE_1, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_RX, 0x07),
+};
+
+static const struct qmp_phy_init_tbl sdm845_ufsphy_rx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_LVL, 0x24),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x1e),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_INTERFACE_MODE, 0x40),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_TERM_BW, 0x5b),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4, 0x1b),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SVS_SO_GAIN_HALF, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SVS_SO_GAIN_QUARTER, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SVS_SO_GAIN, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x4b),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_PI_CONTROLS, 0x81),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW, 0x80),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x59),
+};
+
+static const struct qmp_phy_init_tbl sdm845_ufsphy_pcs_tbl[] = {
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_CTRL2, 0x6e),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TX_LARGE_AMP_DRV_LVL, 0x0a),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TX_SMALL_AMP_DRV_LVL, 0x02),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SYM_RESYNC_CTRL, 0x03),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TX_MID_TERM_CTRL1, 0x43),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_CTRL1, 0x0f),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_MIN_HIBERN8_TIME, 0x9a),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_MULTI_LANE_CTRL1, 0x02),
+};
/* struct qmp_phy_cfg - per-PHY initialization config */
struct qmp_phy_cfg {
@@ -649,9 +731,14 @@ struct qmp_phy_cfg {
/* true, if PHY has a separate DP_COM control block */
bool has_phy_dp_com_ctrl;
+ /* true, if PHY has secondary tx/rx lanes to be configured */
+ bool is_dual_lane_phy;
/* Register offset of secondary tx/rx lanes for USB DP combo PHY */
unsigned int tx_b_lane_offset;
unsigned int rx_b_lane_offset;
+
+ /* true, if PCS block has no separate SW_RESET register */
+ bool no_pcs_sw_reset;
};
/**
@@ -748,6 +835,10 @@ static const char * const qmp_v3_phy_clk_l[] = {
"aux", "cfg_ahb", "ref", "com_aux",
};
+static const char * const sdm845_ufs_phy_clk_l[] = {
+ "ref", "ref_aux",
+};
+
/* list of resets */
static const char * const msm8996_pciephy_reset_l[] = {
"phy", "common", "cfg",
@@ -758,7 +849,7 @@ static const char * const msm8996_usb3phy_reset_l[] = {
};
/* list of regulators */
-static const char * const msm8996_phy_vreg_l[] = {
+static const char * const qmp_phy_vreg_l[] = {
"vdda-phy", "vdda-pll",
};
@@ -778,8 +869,8 @@ static const struct qmp_phy_cfg msm8996_pciephy_cfg = {
.num_clks = ARRAY_SIZE(msm8996_phy_clk_l),
.reset_list = msm8996_pciephy_reset_l,
.num_resets = ARRAY_SIZE(msm8996_pciephy_reset_l),
- .vreg_list = msm8996_phy_vreg_l,
- .num_vregs = ARRAY_SIZE(msm8996_phy_vreg_l),
+ .vreg_list = qmp_phy_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
.regs = pciephy_regs_layout,
.start_ctrl = PCS_START | PLL_READY_GATE_EN,
@@ -809,8 +900,8 @@ static const struct qmp_phy_cfg msm8996_usb3phy_cfg = {
.num_clks = ARRAY_SIZE(msm8996_phy_clk_l),
.reset_list = msm8996_usb3phy_reset_l,
.num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
- .vreg_list = msm8996_phy_vreg_l,
- .num_vregs = ARRAY_SIZE(msm8996_phy_vreg_l),
+ .vreg_list = qmp_phy_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
.regs = usb3phy_regs_layout,
.start_ctrl = SERDES_START | PCS_START,
@@ -870,8 +961,8 @@ static const struct qmp_phy_cfg qmp_v3_usb3phy_cfg = {
.num_clks = ARRAY_SIZE(qmp_v3_phy_clk_l),
.reset_list = msm8996_usb3phy_reset_l,
.num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
- .vreg_list = msm8996_phy_vreg_l,
- .num_vregs = ARRAY_SIZE(msm8996_phy_vreg_l),
+ .vreg_list = qmp_phy_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
.regs = qmp_v3_usb3phy_regs_layout,
.start_ctrl = SERDES_START | PCS_START,
@@ -883,6 +974,7 @@ static const struct qmp_phy_cfg qmp_v3_usb3phy_cfg = {
.pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX,
.has_phy_dp_com_ctrl = true,
+ .is_dual_lane_phy = true,
.tx_b_lane_offset = 0x400,
.rx_b_lane_offset = 0x400,
};
@@ -903,8 +995,8 @@ static const struct qmp_phy_cfg qmp_v3_usb3_uniphy_cfg = {
.num_clks = ARRAY_SIZE(qmp_v3_phy_clk_l),
.reset_list = msm8996_usb3phy_reset_l,
.num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
- .vreg_list = msm8996_phy_vreg_l,
- .num_vregs = ARRAY_SIZE(msm8996_phy_vreg_l),
+ .vreg_list = qmp_phy_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
.regs = qmp_v3_usb3phy_regs_layout,
.start_ctrl = SERDES_START | PCS_START,
@@ -916,6 +1008,35 @@ static const struct qmp_phy_cfg qmp_v3_usb3_uniphy_cfg = {
.pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX,
};
+static const struct qmp_phy_cfg sdm845_ufsphy_cfg = {
+ .type = PHY_TYPE_UFS,
+ .nlanes = 2,
+
+ .serdes_tbl = sdm845_ufsphy_serdes_tbl,
+ .serdes_tbl_num = ARRAY_SIZE(sdm845_ufsphy_serdes_tbl),
+ .tx_tbl = sdm845_ufsphy_tx_tbl,
+ .tx_tbl_num = ARRAY_SIZE(sdm845_ufsphy_tx_tbl),
+ .rx_tbl = sdm845_ufsphy_rx_tbl,
+ .rx_tbl_num = ARRAY_SIZE(sdm845_ufsphy_rx_tbl),
+ .pcs_tbl = sdm845_ufsphy_pcs_tbl,
+ .pcs_tbl_num = ARRAY_SIZE(sdm845_ufsphy_pcs_tbl),
+ .clk_list = sdm845_ufs_phy_clk_l,
+ .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
+ .vreg_list = qmp_phy_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
+ .regs = sdm845_ufsphy_regs_layout,
+
+ .start_ctrl = SERDES_START,
+ .pwrdn_ctrl = SW_PWRDN,
+ .mask_pcs_ready = PCS_READY,
+
+ .is_dual_lane_phy = true,
+ .tx_b_lane_offset = 0x400,
+ .rx_b_lane_offset = 0x400,
+
+ .no_pcs_sw_reset = true,
+};
+
static void qcom_qmp_phy_configure(void __iomem *base,
const unsigned int *regs,
const struct qmp_phy_init_tbl tbl[],
@@ -935,10 +1056,12 @@ static void qcom_qmp_phy_configure(void __iomem *base,
}
}
-static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
+static int qcom_qmp_phy_com_init(struct qmp_phy *qphy)
{
+ struct qcom_qmp *qmp = qphy->qmp;
const struct qmp_phy_cfg *cfg = qmp->cfg;
void __iomem *serdes = qmp->serdes;
+ void __iomem *pcs = qphy->pcs;
void __iomem *dp_com = qmp->dp_com;
int ret, i;
@@ -979,10 +1102,6 @@ static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
goto err_rst;
}
- if (cfg->has_phy_com_ctrl)
- qphy_setbits(serdes, cfg->regs[QPHY_COM_POWER_DOWN_CONTROL],
- SW_PWRDN);
-
if (cfg->has_phy_dp_com_ctrl) {
qphy_setbits(dp_com, QPHY_V3_DP_COM_POWER_DOWN_CTRL,
SW_PWRDN);
@@ -1000,6 +1119,12 @@ static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET);
}
+ if (cfg->has_phy_com_ctrl)
+ qphy_setbits(serdes, cfg->regs[QPHY_COM_POWER_DOWN_CONTROL],
+ SW_PWRDN);
+ else
+ qphy_setbits(pcs, QPHY_POWER_DOWN_CONTROL, cfg->pwrdn_ctrl);
+
/* Serdes configuration */
qcom_qmp_phy_configure(serdes, cfg->regs, cfg->serdes_tbl,
cfg->serdes_tbl_num);
@@ -1090,7 +1215,7 @@ static int qcom_qmp_phy_init(struct phy *phy)
dev_vdbg(qmp->dev, "Initializing QMP phy\n");
- ret = qcom_qmp_phy_com_init(qmp);
+ ret = qcom_qmp_phy_com_init(qphy);
if (ret)
return ret;
@@ -1112,22 +1237,31 @@ static int qcom_qmp_phy_init(struct phy *phy)
/* Tx, Rx, and PCS configurations */
qcom_qmp_phy_configure(tx, cfg->regs, cfg->tx_tbl, cfg->tx_tbl_num);
/* Configuration for other LANE for USB-DP combo PHY */
- if (cfg->has_phy_dp_com_ctrl)
+ if (cfg->is_dual_lane_phy)
qcom_qmp_phy_configure(tx + cfg->tx_b_lane_offset, cfg->regs,
cfg->tx_tbl, cfg->tx_tbl_num);
qcom_qmp_phy_configure(rx, cfg->regs, cfg->rx_tbl, cfg->rx_tbl_num);
- if (cfg->has_phy_dp_com_ctrl)
+ if (cfg->is_dual_lane_phy)
qcom_qmp_phy_configure(rx + cfg->rx_b_lane_offset, cfg->regs,
cfg->rx_tbl, cfg->rx_tbl_num);
qcom_qmp_phy_configure(pcs, cfg->regs, cfg->pcs_tbl, cfg->pcs_tbl_num);
/*
+ * UFS PHY requires the deassert of software reset before serdes start.
+ * For UFS PHYs that do not have software reset control bits, defer
+ * starting serdes until the power on callback.
+ */
+ if ((cfg->type == PHY_TYPE_UFS) && cfg->no_pcs_sw_reset)
+ goto out;
+
+ /*
* Pull out PHY from POWER DOWN state.
* This is active low enable signal to power-down PHY.
*/
- qphy_setbits(pcs, QPHY_POWER_DOWN_CONTROL, cfg->pwrdn_ctrl);
+ if(cfg->type == PHY_TYPE_PCIE)
+ qphy_setbits(pcs, QPHY_POWER_DOWN_CONTROL, cfg->pwrdn_ctrl);
if (cfg->has_pwrdn_delay)
usleep_range(cfg->pwrdn_delay_min, cfg->pwrdn_delay_max);
@@ -1151,6 +1285,7 @@ static int qcom_qmp_phy_init(struct phy *phy)
}
qmp->phy_initialized = true;
+out:
return ret;
err_pcs_ready:
@@ -1173,7 +1308,8 @@ static int qcom_qmp_phy_exit(struct phy *phy)
clk_disable_unprepare(qphy->pipe_clk);
/* PHY reset */
- qphy_setbits(qphy->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
+ if (!cfg->no_pcs_sw_reset)
+ qphy_setbits(qphy->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
/* stop SerDes and Phy-Coding-Sublayer */
qphy_clrbits(qphy->pcs, cfg->regs[QPHY_START_CTRL], cfg->start_ctrl);
@@ -1191,6 +1327,44 @@ static int qcom_qmp_phy_exit(struct phy *phy)
return 0;
}
+static int qcom_qmp_phy_poweron(struct phy *phy)
+{
+ struct qmp_phy *qphy = phy_get_drvdata(phy);
+ struct qcom_qmp *qmp = qphy->qmp;
+ const struct qmp_phy_cfg *cfg = qmp->cfg;
+ void __iomem *pcs = qphy->pcs;
+ void __iomem *status;
+ unsigned int mask, val;
+ int ret = 0;
+
+ if (cfg->type != PHY_TYPE_UFS)
+ return 0;
+
+ /*
+ * For UFS PHY that has not software reset control, serdes start
+ * should only happen when UFS driver explicitly calls phy_power_on
+ * after it deasserts software reset.
+ */
+ if (cfg->no_pcs_sw_reset && !qmp->phy_initialized &&
+ (qmp->init_count != 0)) {
+ /* start SerDes and Phy-Coding-Sublayer */
+ qphy_setbits(pcs, cfg->regs[QPHY_START_CTRL], cfg->start_ctrl);
+
+ status = pcs + cfg->regs[QPHY_PCS_READY_STATUS];
+ mask = cfg->mask_pcs_ready;
+
+ ret = readl_poll_timeout(status, val, !(val & mask), 1,
+ PHY_INIT_COMPLETE_TIMEOUT);
+ if (ret) {
+ dev_err(qmp->dev, "phy initialization timed-out\n");
+ return ret;
+ }
+ qmp->phy_initialized = true;
+ }
+
+ return ret;
+}
+
static int qcom_qmp_phy_set_mode(struct phy *phy, enum phy_mode mode)
{
struct qmp_phy *qphy = phy_get_drvdata(phy);
@@ -1400,7 +1574,7 @@ static int phy_pipe_clk_register(struct qcom_qmp *qmp, struct device_node *np)
ret = of_property_read_string(np, "clock-output-names", &init.name);
if (ret) {
- dev_err(qmp->dev, "%s: No clock-output-names\n", np->name);
+ dev_err(qmp->dev, "%pOFn: No clock-output-names\n", np);
return ret;
}
@@ -1420,6 +1594,7 @@ static int phy_pipe_clk_register(struct qcom_qmp *qmp, struct device_node *np)
static const struct phy_ops qcom_qmp_phy_gen_ops = {
.init = qcom_qmp_phy_init,
.exit = qcom_qmp_phy_exit,
+ .power_on = qcom_qmp_phy_poweron,
.set_mode = qcom_qmp_phy_set_mode,
.owner = THIS_MODULE,
};
@@ -1522,6 +1697,9 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = {
}, {
.compatible = "qcom,sdm845-qmp-usb3-uni-phy",
.data = &qmp_v3_usb3_uniphy_cfg,
+ }, {
+ .compatible = "qcom,sdm845-qmp-ufs-phy",
+ .data = &sdm845_ufsphy_cfg,
},
{ },
};
@@ -1586,7 +1764,9 @@ static int qcom_qmp_phy_probe(struct platform_device *pdev)
ret = qcom_qmp_phy_vreg_init(dev);
if (ret) {
- dev_err(dev, "failed to get regulator supplies\n");
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "failed to get regulator supplies: %d\n",
+ ret);
return ret;
}
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.h b/drivers/phy/qualcomm/phy-qcom-qmp.h
index 5d78d43ba9fc..d201cc307151 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.h
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.h
@@ -184,6 +184,8 @@
#define QSERDES_V3_COM_VCO_TUNE2_MODE0 0x0f8
#define QSERDES_V3_COM_VCO_TUNE1_MODE1 0x0fc
#define QSERDES_V3_COM_VCO_TUNE2_MODE1 0x100
+#define QSERDES_V3_COM_VCO_TUNE_INITVAL1 0x104
+#define QSERDES_V3_COM_VCO_TUNE_INITVAL2 0x108
#define QSERDES_V3_COM_VCO_TUNE_TIMER1 0x11c
#define QSERDES_V3_COM_VCO_TUNE_TIMER2 0x120
#define QSERDES_V3_COM_CLK_SELECT 0x138
@@ -211,8 +213,13 @@
/* Only for QMP V3 PHY - RX registers */
#define QSERDES_V3_RX_UCDR_SO_GAIN_HALF 0x00c
#define QSERDES_V3_RX_UCDR_SO_GAIN 0x014
+#define QSERDES_V3_RX_UCDR_SVS_SO_GAIN_HALF 0x024
+#define QSERDES_V3_RX_UCDR_SVS_SO_GAIN_QUARTER 0x028
+#define QSERDES_V3_RX_UCDR_SVS_SO_GAIN 0x02c
#define QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN 0x030
#define QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE 0x034
+#define QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW 0x03c
+#define QSERDES_V3_RX_UCDR_PI_CONTROLS 0x044
#define QSERDES_V3_RX_RX_TERM_BW 0x07c
#define QSERDES_V3_RX_VGA_CAL_CNTRL1 0x0bc
#define QSERDES_V3_RX_VGA_CAL_CNTRL2 0x0c0
@@ -239,6 +246,8 @@
#define QPHY_V3_PCS_TXMGN_V3 0x018
#define QPHY_V3_PCS_TXMGN_V4 0x01c
#define QPHY_V3_PCS_TXMGN_LS 0x020
+#define QPHY_V3_PCS_TX_LARGE_AMP_DRV_LVL 0x02c
+#define QPHY_V3_PCS_TX_SMALL_AMP_DRV_LVL 0x034
#define QPHY_V3_PCS_TXDEEMPH_M6DB_V0 0x024
#define QPHY_V3_PCS_TXDEEMPH_M3P5DB_V0 0x028
#define QPHY_V3_PCS_TXDEEMPH_M6DB_V1 0x02c
@@ -275,6 +284,12 @@
#define QPHY_V3_PCS_FLL_CNT_VAL_L 0x0cc
#define QPHY_V3_PCS_FLL_CNT_VAL_H_TOL 0x0d0
#define QPHY_V3_PCS_FLL_MAN_CODE 0x0d4
+#define QPHY_V3_PCS_RX_SYM_RESYNC_CTRL 0x134
+#define QPHY_V3_PCS_RX_MIN_HIBERN8_TIME 0x138
+#define QPHY_V3_PCS_RX_SIGDET_CTRL1 0x13c
+#define QPHY_V3_PCS_RX_SIGDET_CTRL2 0x140
+#define QPHY_V3_PCS_TX_MID_TERM_CTRL1 0x1bc
+#define QPHY_V3_PCS_MULTI_LANE_CTRL1 0x1c4
#define QPHY_V3_PCS_RX_SIGDET_LVL 0x1d8
#define QPHY_V3_PCS_REFGEN_REQ_CONFIG1 0x20c
#define QPHY_V3_PCS_REFGEN_REQ_CONFIG2 0x210
diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c b/drivers/phy/qualcomm/phy-qcom-qusb2.c
index e70e425f26f5..9ce531194f8a 100644
--- a/drivers/phy/qualcomm/phy-qcom-qusb2.c
+++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c
@@ -800,7 +800,9 @@ static int qusb2_phy_probe(struct platform_device *pdev)
ret = devm_regulator_bulk_get(dev, num, qphy->vregs);
if (ret) {
- dev_err(dev, "failed to get regulator supplies\n");
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "failed to get regulator supplies: %d\n",
+ ret);
return ret;
}
diff --git a/drivers/phy/qualcomm/phy-qcom-ufs-i.h b/drivers/phy/qualcomm/phy-qcom-ufs-i.h
index 822c83b8efcd..681644e43248 100644
--- a/drivers/phy/qualcomm/phy-qcom-ufs-i.h
+++ b/drivers/phy/qualcomm/phy-qcom-ufs-i.h
@@ -17,9 +17,9 @@
#include <linux/module.h>
#include <linux/clk.h>
+#include <linux/phy/phy.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
-#include <linux/phy/phy-qcom-ufs.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/delay.h>
diff --git a/drivers/phy/qualcomm/phy-qcom-ufs.c b/drivers/phy/qualcomm/phy-qcom-ufs.c
index c5493ea51282..f2979ccad00a 100644
--- a/drivers/phy/qualcomm/phy-qcom-ufs.c
+++ b/drivers/phy/qualcomm/phy-qcom-ufs.c
@@ -431,56 +431,6 @@ static void ufs_qcom_phy_disable_ref_clk(struct ufs_qcom_phy *phy)
}
}
-#define UFS_REF_CLK_EN (1 << 5)
-
-static void ufs_qcom_phy_dev_ref_clk_ctrl(struct phy *generic_phy, bool enable)
-{
- struct ufs_qcom_phy *phy = get_ufs_qcom_phy(generic_phy);
-
- if (phy->dev_ref_clk_ctrl_mmio &&
- (enable ^ phy->is_dev_ref_clk_enabled)) {
- u32 temp = readl_relaxed(phy->dev_ref_clk_ctrl_mmio);
-
- if (enable)
- temp |= UFS_REF_CLK_EN;
- else
- temp &= ~UFS_REF_CLK_EN;
-
- /*
- * If we are here to disable this clock immediately after
- * entering into hibern8, we need to make sure that device
- * ref_clk is active atleast 1us after the hibern8 enter.
- */
- if (!enable)
- udelay(1);
-
- writel_relaxed(temp, phy->dev_ref_clk_ctrl_mmio);
- /* ensure that ref_clk is enabled/disabled before we return */
- wmb();
- /*
- * If we call hibern8 exit after this, we need to make sure that
- * device ref_clk is stable for atleast 1us before the hibern8
- * exit command.
- */
- if (enable)
- udelay(1);
-
- phy->is_dev_ref_clk_enabled = enable;
- }
-}
-
-void ufs_qcom_phy_enable_dev_ref_clk(struct phy *generic_phy)
-{
- ufs_qcom_phy_dev_ref_clk_ctrl(generic_phy, true);
-}
-EXPORT_SYMBOL_GPL(ufs_qcom_phy_enable_dev_ref_clk);
-
-void ufs_qcom_phy_disable_dev_ref_clk(struct phy *generic_phy)
-{
- ufs_qcom_phy_dev_ref_clk_ctrl(generic_phy, false);
-}
-EXPORT_SYMBOL_GPL(ufs_qcom_phy_disable_dev_ref_clk);
-
/* Turn ON M-PHY RMMI interface clocks */
static int ufs_qcom_phy_enable_iface_clk(struct ufs_qcom_phy *phy)
{
diff --git a/drivers/phy/renesas/Kconfig b/drivers/phy/renesas/Kconfig
index 4bd390c79d21..e340a925bbb1 100644
--- a/drivers/phy/renesas/Kconfig
+++ b/drivers/phy/renesas/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
#
# Phy drivers for Renesas platforms
#
diff --git a/drivers/phy/renesas/Makefile b/drivers/phy/renesas/Makefile
index 4b76fc439ed6..b599ff8a4349 100644
--- a/drivers/phy/renesas/Makefile
+++ b/drivers/phy/renesas/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_PHY_RCAR_GEN2) += phy-rcar-gen2.o
obj-$(CONFIG_PHY_RCAR_GEN3_PCIE) += phy-rcar-gen3-pcie.o
obj-$(CONFIG_PHY_RCAR_GEN3_USB2) += phy-rcar-gen3-usb2.o
diff --git a/drivers/phy/renesas/phy-rcar-gen2.c b/drivers/phy/renesas/phy-rcar-gen2.c
index 97d4dd6ea924..72eeb066912d 100644
--- a/drivers/phy/renesas/phy-rcar-gen2.c
+++ b/drivers/phy/renesas/phy-rcar-gen2.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Renesas R-Car Gen2 PHY driver
*
* Copyright (C) 2014 Renesas Solutions Corp.
* Copyright (C) 2014 Cogent Embedded, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/clk.h>
diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
index fb8f05e39cf7..d0f412c25981 100644
--- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c
+++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Renesas R-Car Gen3 for USB2.0 PHY driver
*
@@ -6,10 +7,6 @@
* This is based on the phy-rcar-gen2 driver:
* Copyright (C) 2014 Renesas Solutions Corp.
* Copyright (C) 2014 Cogent Embedded, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/extcon-provider.h>
@@ -81,18 +78,29 @@
#define USB2_ADPCTRL_IDPULLUP BIT(5) /* 1 = ID sampling is enabled */
#define USB2_ADPCTRL_DRVVBUS BIT(4)
-#define RCAR_GEN3_PHY_HAS_DEDICATED_PINS 1
-
struct rcar_gen3_chan {
void __iomem *base;
struct extcon_dev *extcon;
struct phy *phy;
struct regulator *vbus;
struct work_struct work;
+ enum usb_dr_mode dr_mode;
bool extcon_host;
- bool has_otg_pins;
+ bool is_otg_channel;
+ bool uses_otg_pins;
};
+/*
+ * Combination about is_otg_channel and uses_otg_pins:
+ *
+ * Parameters || Behaviors
+ * is_otg_channel | uses_otg_pins || irqs | role sysfs
+ * ---------------------+---------------++--------------+------------
+ * true | true || enabled | enabled
+ * true | false || disabled | enabled
+ * false | any || disabled | disabled
+ */
+
static void rcar_gen3_phy_usb2_work(struct work_struct *work)
{
struct rcar_gen3_chan *ch = container_of(work, struct rcar_gen3_chan,
@@ -147,6 +155,18 @@ static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus)
writel(val, usb2_base + USB2_ADPCTRL);
}
+static void rcar_gen3_control_otg_irq(struct rcar_gen3_chan *ch, int enable)
+{
+ void __iomem *usb2_base = ch->base;
+ u32 val = readl(usb2_base + USB2_OBINTEN);
+
+ if (ch->uses_otg_pins && enable)
+ val |= USB2_OBINT_BITS;
+ else
+ val &= ~USB2_OBINT_BITS;
+ writel(val, usb2_base + USB2_OBINTEN);
+}
+
static void rcar_gen3_init_for_host(struct rcar_gen3_chan *ch)
{
rcar_gen3_set_linectrl(ch, 1, 1);
@@ -192,20 +212,19 @@ static void rcar_gen3_init_for_a_peri(struct rcar_gen3_chan *ch)
static void rcar_gen3_init_from_a_peri_to_a_host(struct rcar_gen3_chan *ch)
{
- void __iomem *usb2_base = ch->base;
- u32 val;
+ rcar_gen3_control_otg_irq(ch, 0);
- val = readl(usb2_base + USB2_OBINTEN);
- writel(val & ~USB2_OBINT_BITS, usb2_base + USB2_OBINTEN);
-
- rcar_gen3_enable_vbus_ctrl(ch, 0);
+ rcar_gen3_enable_vbus_ctrl(ch, 1);
rcar_gen3_init_for_host(ch);
- writel(val | USB2_OBINT_BITS, usb2_base + USB2_OBINTEN);
+ rcar_gen3_control_otg_irq(ch, 1);
}
static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch)
{
+ if (!ch->uses_otg_pins)
+ return (ch->dr_mode == USB_DR_MODE_HOST) ? false : true;
+
return !!(readl(ch->base + USB2_ADPCTRL) & USB2_ADPCTRL_IDDIG);
}
@@ -237,7 +256,7 @@ static ssize_t role_store(struct device *dev, struct device_attribute *attr,
bool is_b_device;
enum phy_mode cur_mode, new_mode;
- if (!ch->has_otg_pins || !ch->phy->init_count)
+ if (!ch->is_otg_channel || !ch->phy->init_count)
return -EIO;
if (!strncmp(buf, "host", strlen("host")))
@@ -275,7 +294,7 @@ static ssize_t role_show(struct device *dev, struct device_attribute *attr,
{
struct rcar_gen3_chan *ch = dev_get_drvdata(dev);
- if (!ch->has_otg_pins || !ch->phy->init_count)
+ if (!ch->is_otg_channel || !ch->phy->init_count)
return -EIO;
return sprintf(buf, "%s\n", rcar_gen3_is_host(ch) ? "host" :
@@ -291,8 +310,7 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch)
val = readl(usb2_base + USB2_VBCTRL);
writel(val | USB2_VBCTRL_DRVVBUSSEL, usb2_base + USB2_VBCTRL);
writel(USB2_OBINT_BITS, usb2_base + USB2_OBINTSTA);
- val = readl(usb2_base + USB2_OBINTEN);
- writel(val | USB2_OBINT_BITS, usb2_base + USB2_OBINTEN);
+ rcar_gen3_control_otg_irq(ch, 1);
val = readl(usb2_base + USB2_ADPCTRL);
writel(val | USB2_ADPCTRL_IDPULLUP, usb2_base + USB2_ADPCTRL);
val = readl(usb2_base + USB2_LINECTRL1);
@@ -314,7 +332,7 @@ static int rcar_gen3_phy_usb2_init(struct phy *p)
writel(USB2_OC_TIMSET_INIT, usb2_base + USB2_OC_TIMSET);
/* Initialize otg part */
- if (channel->has_otg_pins)
+ if (channel->is_otg_channel)
rcar_gen3_init_otg(channel);
return 0;
@@ -388,21 +406,10 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch)
}
static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = {
- {
- .compatible = "renesas,usb2-phy-r8a7795",
- .data = (void *)RCAR_GEN3_PHY_HAS_DEDICATED_PINS,
- },
- {
- .compatible = "renesas,usb2-phy-r8a7796",
- .data = (void *)RCAR_GEN3_PHY_HAS_DEDICATED_PINS,
- },
- {
- .compatible = "renesas,usb2-phy-r8a77965",
- .data = (void *)RCAR_GEN3_PHY_HAS_DEDICATED_PINS,
- },
- {
- .compatible = "renesas,rcar-gen3-usb2-phy",
- },
+ { .compatible = "renesas,usb2-phy-r8a7795" },
+ { .compatible = "renesas,usb2-phy-r8a7796" },
+ { .compatible = "renesas,usb2-phy-r8a77965" },
+ { .compatible = "renesas,rcar-gen3-usb2-phy" },
{ }
};
MODULE_DEVICE_TABLE(of, rcar_gen3_phy_usb2_match_table);
@@ -445,10 +452,13 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
dev_err(dev, "No irq handler (%d)\n", irq);
}
- if (of_usb_get_dr_mode_by_phy(dev->of_node, 0) == USB_DR_MODE_OTG) {
+ channel->dr_mode = of_usb_get_dr_mode_by_phy(dev->of_node, 0);
+ if (channel->dr_mode != USB_DR_MODE_UNKNOWN) {
int ret;
- channel->has_otg_pins = (uintptr_t)of_device_get_match_data(dev);
+ channel->is_otg_channel = true;
+ channel->uses_otg_pins = !of_property_read_bool(dev->of_node,
+ "renesas,no-otg-pins");
channel->extcon = devm_extcon_dev_allocate(dev,
rcar_gen3_phy_cable);
if (IS_ERR(channel->extcon))
@@ -490,7 +500,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
dev_err(dev, "Failed to register PHY provider\n");
ret = PTR_ERR(provider);
goto error;
- } else if (channel->has_otg_pins) {
+ } else if (channel->is_otg_channel) {
int ret;
ret = device_create_file(dev, &dev_attr_role);
@@ -510,7 +520,7 @@ static int rcar_gen3_phy_usb2_remove(struct platform_device *pdev)
{
struct rcar_gen3_chan *channel = platform_get_drvdata(pdev);
- if (channel->has_otg_pins)
+ if (channel->is_otg_channel)
device_remove_file(&pdev->dev, &dev_attr_role);
pm_runtime_disable(&pdev->dev);
diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb3.c b/drivers/phy/renesas/phy-rcar-gen3-usb3.c
index 88c83c9b8ff9..566b4cf4ff38 100644
--- a/drivers/phy/renesas/phy-rcar-gen3-usb3.c
+++ b/drivers/phy/renesas/phy-rcar-gen3-usb3.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Renesas R-Car Gen3 for USB3.0 PHY driver
*
* Copyright (C) 2017 Renesas Electronics Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/clk.h>
diff --git a/drivers/phy/rockchip/Kconfig b/drivers/phy/rockchip/Kconfig
index 0e15119ddfc6..990204a46eb6 100644
--- a/drivers/phy/rockchip/Kconfig
+++ b/drivers/phy/rockchip/Kconfig
@@ -15,6 +15,14 @@ config PHY_ROCKCHIP_EMMC
help
Enable this to support the Rockchip EMMC PHY.
+config PHY_ROCKCHIP_INNO_HDMI
+ tristate "Rockchip INNO HDMI PHY Driver"
+ depends on (ARCH_ROCKCHIP || COMPILE_TEST) && OF
+ depends on COMMON_CLK
+ select GENERIC_PHY
+ help
+ Enable this to support the Rockchip Innosilicon HDMI PHY.
+
config PHY_ROCKCHIP_INNO_USB2
tristate "Rockchip INNO USB2PHY Driver"
depends on (ARCH_ROCKCHIP || COMPILE_TEST) && OF
diff --git a/drivers/phy/rockchip/Makefile b/drivers/phy/rockchip/Makefile
index 7f149d989046..fd21cbaf40dd 100644
--- a/drivers/phy/rockchip/Makefile
+++ b/drivers/phy/rockchip/Makefile
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_PHY_ROCKCHIP_DP) += phy-rockchip-dp.o
obj-$(CONFIG_PHY_ROCKCHIP_EMMC) += phy-rockchip-emmc.o
+obj-$(CONFIG_PHY_ROCKCHIP_INNO_HDMI) += phy-rockchip-inno-hdmi.o
obj-$(CONFIG_PHY_ROCKCHIP_INNO_USB2) += phy-rockchip-inno-usb2.o
obj-$(CONFIG_PHY_ROCKCHIP_PCIE) += phy-rockchip-pcie.o
obj-$(CONFIG_PHY_ROCKCHIP_TYPEC) += phy-rockchip-typec.o
diff --git a/drivers/phy/rockchip/phy-rockchip-emmc.c b/drivers/phy/rockchip/phy-rockchip-emmc.c
index b237360f95f6..19bf84f0bc67 100644
--- a/drivers/phy/rockchip/phy-rockchip-emmc.c
+++ b/drivers/phy/rockchip/phy-rockchip-emmc.c
@@ -337,8 +337,8 @@ static int rockchip_emmc_phy_probe(struct platform_device *pdev)
return -ENOMEM;
if (of_property_read_u32(dev->of_node, "reg", &reg_offset)) {
- dev_err(dev, "missing reg property in node %s\n",
- dev->of_node->name);
+ dev_err(dev, "missing reg property in node %pOFn\n",
+ dev->of_node);
return -EINVAL;
}
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
new file mode 100644
index 000000000000..b10a84cab4a7
--- /dev/null
+++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
@@ -0,0 +1,1277 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2017 Rockchip Electronics Co. Ltd.
+ *
+ * Author: Zheng Yang <zhengyang@rock-chips.com>
+ * Heiko Stuebner <heiko@sntech.de>
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/phy/phy.h>
+#include <linux/slab.h>
+
+#define UPDATE(x, h, l) (((x) << (l)) & GENMASK((h), (l)))
+
+/* REG: 0x00 */
+#define RK3228_PRE_PLL_REFCLK_SEL_PCLK BIT(0)
+/* REG: 0x01 */
+#define RK3228_BYPASS_RXSENSE_EN BIT(2)
+#define RK3228_BYPASS_PWRON_EN BIT(1)
+#define RK3228_BYPASS_PLLPD_EN BIT(0)
+/* REG: 0x02 */
+#define RK3228_BYPASS_PDATA_EN BIT(4)
+#define RK3228_PDATAEN_DISABLE BIT(0)
+/* REG: 0x03 */
+#define RK3228_BYPASS_AUTO_TERM_RES_CAL BIT(7)
+#define RK3228_AUTO_TERM_RES_CAL_SPEED_14_8(x) UPDATE(x, 6, 0)
+/* REG: 0x04 */
+#define RK3228_AUTO_TERM_RES_CAL_SPEED_7_0(x) UPDATE(x, 7, 0)
+/* REG: 0xaa */
+#define RK3228_POST_PLL_CTRL_MANUAL BIT(0)
+/* REG: 0xe0 */
+#define RK3228_POST_PLL_POWER_DOWN BIT(5)
+#define RK3228_PRE_PLL_POWER_DOWN BIT(4)
+#define RK3228_RXSENSE_CLK_CH_ENABLE BIT(3)
+#define RK3228_RXSENSE_DATA_CH2_ENABLE BIT(2)
+#define RK3228_RXSENSE_DATA_CH1_ENABLE BIT(1)
+#define RK3228_RXSENSE_DATA_CH0_ENABLE BIT(0)
+/* REG: 0xe1 */
+#define RK3228_BANDGAP_ENABLE BIT(4)
+#define RK3228_TMDS_DRIVER_ENABLE GENMASK(3, 0)
+/* REG: 0xe2 */
+#define RK3228_PRE_PLL_FB_DIV_8_MASK BIT(7)
+#define RK3228_PRE_PLL_FB_DIV_8(x) UPDATE((x) >> 8, 7, 7)
+#define RK3228_PCLK_VCO_DIV_5_MASK BIT(5)
+#define RK3228_PCLK_VCO_DIV_5(x) UPDATE(x, 5, 5)
+#define RK3228_PRE_PLL_PRE_DIV_MASK GENMASK(4, 0)
+#define RK3228_PRE_PLL_PRE_DIV(x) UPDATE(x, 4, 0)
+/* REG: 0xe3 */
+#define RK3228_PRE_PLL_FB_DIV_7_0(x) UPDATE(x, 7, 0)
+/* REG: 0xe4 */
+#define RK3228_PRE_PLL_PCLK_DIV_B_MASK GENMASK(6, 5)
+#define RK3228_PRE_PLL_PCLK_DIV_B_SHIFT 5
+#define RK3228_PRE_PLL_PCLK_DIV_B(x) UPDATE(x, 6, 5)
+#define RK3228_PRE_PLL_PCLK_DIV_A_MASK GENMASK(4, 0)
+#define RK3228_PRE_PLL_PCLK_DIV_A(x) UPDATE(x, 4, 0)
+/* REG: 0xe5 */
+#define RK3228_PRE_PLL_PCLK_DIV_C_MASK GENMASK(6, 5)
+#define RK3228_PRE_PLL_PCLK_DIV_C(x) UPDATE(x, 6, 5)
+#define RK3228_PRE_PLL_PCLK_DIV_D_MASK GENMASK(4, 0)
+#define RK3228_PRE_PLL_PCLK_DIV_D(x) UPDATE(x, 4, 0)
+/* REG: 0xe6 */
+#define RK3228_PRE_PLL_TMDSCLK_DIV_C_MASK GENMASK(5, 4)
+#define RK3228_PRE_PLL_TMDSCLK_DIV_C(x) UPDATE(x, 5, 4)
+#define RK3228_PRE_PLL_TMDSCLK_DIV_A_MASK GENMASK(3, 2)
+#define RK3228_PRE_PLL_TMDSCLK_DIV_A(x) UPDATE(x, 3, 2)
+#define RK3228_PRE_PLL_TMDSCLK_DIV_B_MASK GENMASK(1, 0)
+#define RK3228_PRE_PLL_TMDSCLK_DIV_B(x) UPDATE(x, 1, 0)
+/* REG: 0xe8 */
+#define RK3228_PRE_PLL_LOCK_STATUS BIT(0)
+/* REG: 0xe9 */
+#define RK3228_POST_PLL_POST_DIV_ENABLE UPDATE(3, 7, 6)
+#define RK3228_POST_PLL_PRE_DIV_MASK GENMASK(4, 0)
+#define RK3228_POST_PLL_PRE_DIV(x) UPDATE(x, 4, 0)
+/* REG: 0xea */
+#define RK3228_POST_PLL_FB_DIV_7_0(x) UPDATE(x, 7, 0)
+/* REG: 0xeb */
+#define RK3228_POST_PLL_FB_DIV_8_MASK BIT(7)
+#define RK3228_POST_PLL_FB_DIV_8(x) UPDATE((x) >> 8, 7, 7)
+#define RK3228_POST_PLL_POST_DIV_MASK GENMASK(5, 4)
+#define RK3228_POST_PLL_POST_DIV(x) UPDATE(x, 5, 4)
+#define RK3228_POST_PLL_LOCK_STATUS BIT(0)
+/* REG: 0xee */
+#define RK3228_TMDS_CH_TA_ENABLE GENMASK(7, 4)
+/* REG: 0xef */
+#define RK3228_TMDS_CLK_CH_TA(x) UPDATE(x, 7, 6)
+#define RK3228_TMDS_DATA_CH2_TA(x) UPDATE(x, 5, 4)
+#define RK3228_TMDS_DATA_CH1_TA(x) UPDATE(x, 3, 2)
+#define RK3228_TMDS_DATA_CH0_TA(x) UPDATE(x, 1, 0)
+/* REG: 0xf0 */
+#define RK3228_TMDS_DATA_CH2_PRE_EMPHASIS_MASK GENMASK(5, 4)
+#define RK3228_TMDS_DATA_CH2_PRE_EMPHASIS(x) UPDATE(x, 5, 4)
+#define RK3228_TMDS_DATA_CH1_PRE_EMPHASIS_MASK GENMASK(3, 2)
+#define RK3228_TMDS_DATA_CH1_PRE_EMPHASIS(x) UPDATE(x, 3, 2)
+#define RK3228_TMDS_DATA_CH0_PRE_EMPHASIS_MASK GENMASK(1, 0)
+#define RK3228_TMDS_DATA_CH0_PRE_EMPHASIS(x) UPDATE(x, 1, 0)
+/* REG: 0xf1 */
+#define RK3228_TMDS_CLK_CH_OUTPUT_SWING(x) UPDATE(x, 7, 4)
+#define RK3228_TMDS_DATA_CH2_OUTPUT_SWING(x) UPDATE(x, 3, 0)
+/* REG: 0xf2 */
+#define RK3228_TMDS_DATA_CH1_OUTPUT_SWING(x) UPDATE(x, 7, 4)
+#define RK3228_TMDS_DATA_CH0_OUTPUT_SWING(x) UPDATE(x, 3, 0)
+
+/* REG: 0x01 */
+#define RK3328_BYPASS_RXSENSE_EN BIT(2)
+#define RK3328_BYPASS_POWERON_EN BIT(1)
+#define RK3328_BYPASS_PLLPD_EN BIT(0)
+/* REG: 0x02 */
+#define RK3328_INT_POL_HIGH BIT(7)
+#define RK3328_BYPASS_PDATA_EN BIT(4)
+#define RK3328_PDATA_EN BIT(0)
+/* REG:0x05 */
+#define RK3328_INT_TMDS_CLK(x) UPDATE(x, 7, 4)
+#define RK3328_INT_TMDS_D2(x) UPDATE(x, 3, 0)
+/* REG:0x07 */
+#define RK3328_INT_TMDS_D1(x) UPDATE(x, 7, 4)
+#define RK3328_INT_TMDS_D0(x) UPDATE(x, 3, 0)
+/* for all RK3328_INT_TMDS_*, ESD_DET as defined in 0xc8-0xcb */
+#define RK3328_INT_AGND_LOW_PULSE_LOCKED BIT(3)
+#define RK3328_INT_RXSENSE_LOW_PULSE_LOCKED BIT(2)
+#define RK3328_INT_VSS_AGND_ESD_DET BIT(1)
+#define RK3328_INT_AGND_VSS_ESD_DET BIT(0)
+/* REG: 0xa0 */
+#define RK3328_PCLK_VCO_DIV_5_MASK BIT(1)
+#define RK3328_PCLK_VCO_DIV_5(x) UPDATE(x, 1, 1)
+#define RK3328_PRE_PLL_POWER_DOWN BIT(0)
+/* REG: 0xa1 */
+#define RK3328_PRE_PLL_PRE_DIV_MASK GENMASK(5, 0)
+#define RK3328_PRE_PLL_PRE_DIV(x) UPDATE(x, 5, 0)
+/* REG: 0xa2 */
+/* unset means center spread */
+#define RK3328_SPREAD_SPECTRUM_MOD_DOWN BIT(7)
+#define RK3328_SPREAD_SPECTRUM_MOD_DISABLE BIT(6)
+#define RK3328_PRE_PLL_FRAC_DIV_DISABLE UPDATE(3, 5, 4)
+#define RK3328_PRE_PLL_FB_DIV_11_8_MASK GENMASK(3, 0)
+#define RK3328_PRE_PLL_FB_DIV_11_8(x) UPDATE((x) >> 8, 3, 0)
+/* REG: 0xa3 */
+#define RK3328_PRE_PLL_FB_DIV_7_0(x) UPDATE(x, 7, 0)
+/* REG: 0xa4*/
+#define RK3328_PRE_PLL_TMDSCLK_DIV_C_MASK GENMASK(1, 0)
+#define RK3328_PRE_PLL_TMDSCLK_DIV_C(x) UPDATE(x, 1, 0)
+#define RK3328_PRE_PLL_TMDSCLK_DIV_B_MASK GENMASK(3, 2)
+#define RK3328_PRE_PLL_TMDSCLK_DIV_B(x) UPDATE(x, 3, 2)
+#define RK3328_PRE_PLL_TMDSCLK_DIV_A_MASK GENMASK(5, 4)
+#define RK3328_PRE_PLL_TMDSCLK_DIV_A(x) UPDATE(x, 5, 4)
+/* REG: 0xa5 */
+#define RK3328_PRE_PLL_PCLK_DIV_B_SHIFT 5
+#define RK3328_PRE_PLL_PCLK_DIV_B_MASK GENMASK(6, 5)
+#define RK3328_PRE_PLL_PCLK_DIV_B(x) UPDATE(x, 6, 5)
+#define RK3328_PRE_PLL_PCLK_DIV_A_MASK GENMASK(4, 0)
+#define RK3328_PRE_PLL_PCLK_DIV_A(x) UPDATE(x, 4, 0)
+/* REG: 0xa6 */
+#define RK3328_PRE_PLL_PCLK_DIV_C_SHIFT 5
+#define RK3328_PRE_PLL_PCLK_DIV_C_MASK GENMASK(6, 5)
+#define RK3328_PRE_PLL_PCLK_DIV_C(x) UPDATE(x, 6, 5)
+#define RK3328_PRE_PLL_PCLK_DIV_D_MASK GENMASK(4, 0)
+#define RK3328_PRE_PLL_PCLK_DIV_D(x) UPDATE(x, 4, 0)
+/* REG: 0xa9 */
+#define RK3328_PRE_PLL_LOCK_STATUS BIT(0)
+/* REG: 0xaa */
+#define RK3328_POST_PLL_POST_DIV_ENABLE GENMASK(3, 2)
+#define RK3328_POST_PLL_REFCLK_SEL_TMDS BIT(1)
+#define RK3328_POST_PLL_POWER_DOWN BIT(0)
+/* REG:0xab */
+#define RK3328_POST_PLL_FB_DIV_8(x) UPDATE((x) >> 8, 7, 7)
+#define RK3328_POST_PLL_PRE_DIV(x) UPDATE(x, 4, 0)
+/* REG: 0xac */
+#define RK3328_POST_PLL_FB_DIV_7_0(x) UPDATE(x, 7, 0)
+/* REG: 0xad */
+#define RK3328_POST_PLL_POST_DIV_MASK GENMASK(1, 0)
+#define RK3328_POST_PLL_POST_DIV_2 0x0
+#define RK3328_POST_PLL_POST_DIV_4 0x1
+#define RK3328_POST_PLL_POST_DIV_8 0x3
+/* REG: 0xaf */
+#define RK3328_POST_PLL_LOCK_STATUS BIT(0)
+/* REG: 0xb0 */
+#define RK3328_BANDGAP_ENABLE BIT(2)
+/* REG: 0xb2 */
+#define RK3328_TMDS_CLK_DRIVER_EN BIT(3)
+#define RK3328_TMDS_D2_DRIVER_EN BIT(2)
+#define RK3328_TMDS_D1_DRIVER_EN BIT(1)
+#define RK3328_TMDS_D0_DRIVER_EN BIT(0)
+#define RK3328_TMDS_DRIVER_ENABLE (RK3328_TMDS_CLK_DRIVER_EN | \
+ RK3328_TMDS_D2_DRIVER_EN | \
+ RK3328_TMDS_D1_DRIVER_EN | \
+ RK3328_TMDS_D0_DRIVER_EN)
+/* REG:0xc5 */
+#define RK3328_BYPASS_TERM_RESISTOR_CALIB BIT(7)
+#define RK3328_TERM_RESISTOR_CALIB_SPEED_14_8(x) UPDATE((x) >> 8, 6, 0)
+/* REG:0xc6 */
+#define RK3328_TERM_RESISTOR_CALIB_SPEED_7_0(x) UPDATE(x, 7, 9)
+/* REG:0xc7 */
+#define RK3328_TERM_RESISTOR_50 UPDATE(0, 2, 1)
+#define RK3328_TERM_RESISTOR_62_5 UPDATE(1, 2, 1)
+#define RK3328_TERM_RESISTOR_75 UPDATE(2, 2, 1)
+#define RK3328_TERM_RESISTOR_100 UPDATE(3, 2, 1)
+/* REG 0xc8 - 0xcb */
+#define RK3328_ESD_DETECT_MASK GENMASK(7, 6)
+#define RK3328_ESD_DETECT_340MV (0x0 << 6)
+#define RK3328_ESD_DETECT_280MV (0x1 << 6)
+#define RK3328_ESD_DETECT_260MV (0x2 << 6)
+#define RK3328_ESD_DETECT_240MV (0x3 << 6)
+/* resistors can be used in parallel */
+#define RK3328_TMDS_TERM_RESIST_MASK GENMASK(5, 0)
+#define RK3328_TMDS_TERM_RESIST_75 BIT(5)
+#define RK3328_TMDS_TERM_RESIST_150 BIT(4)
+#define RK3328_TMDS_TERM_RESIST_300 BIT(3)
+#define RK3328_TMDS_TERM_RESIST_600 BIT(2)
+#define RK3328_TMDS_TERM_RESIST_1000 BIT(1)
+#define RK3328_TMDS_TERM_RESIST_2000 BIT(0)
+/* REG: 0xd1 */
+#define RK3328_PRE_PLL_FRAC_DIV_23_16(x) UPDATE((x) >> 16, 7, 0)
+/* REG: 0xd2 */
+#define RK3328_PRE_PLL_FRAC_DIV_15_8(x) UPDATE((x) >> 8, 7, 0)
+/* REG: 0xd3 */
+#define RK3328_PRE_PLL_FRAC_DIV_7_0(x) UPDATE(x, 7, 0)
+
+struct inno_hdmi_phy_drv_data;
+
+struct inno_hdmi_phy {
+ struct device *dev;
+ struct regmap *regmap;
+ int irq;
+
+ struct phy *phy;
+ struct clk *sysclk;
+ struct clk *refoclk;
+ struct clk *refpclk;
+
+ /* platform data */
+ const struct inno_hdmi_phy_drv_data *plat_data;
+ int chip_version;
+
+ /* clk provider */
+ struct clk_hw hw;
+ struct clk *phyclk;
+ unsigned long pixclock;
+};
+
+struct pre_pll_config {
+ unsigned long pixclock;
+ unsigned long tmdsclock;
+ u8 prediv;
+ u16 fbdiv;
+ u8 tmds_div_a;
+ u8 tmds_div_b;
+ u8 tmds_div_c;
+ u8 pclk_div_a;
+ u8 pclk_div_b;
+ u8 pclk_div_c;
+ u8 pclk_div_d;
+ u8 vco_div_5_en;
+ u32 fracdiv;
+};
+
+struct post_pll_config {
+ unsigned long tmdsclock;
+ u8 prediv;
+ u16 fbdiv;
+ u8 postdiv;
+ u8 version;
+};
+
+struct phy_config {
+ unsigned long tmdsclock;
+ u8 regs[14];
+};
+
+struct inno_hdmi_phy_ops {
+ int (*init)(struct inno_hdmi_phy *inno);
+ int (*power_on)(struct inno_hdmi_phy *inno,
+ const struct post_pll_config *cfg,
+ const struct phy_config *phy_cfg);
+ void (*power_off)(struct inno_hdmi_phy *inno);
+};
+
+struct inno_hdmi_phy_drv_data {
+ const struct inno_hdmi_phy_ops *ops;
+ const struct clk_ops *clk_ops;
+ const struct phy_config *phy_cfg_table;
+};
+
+static const struct pre_pll_config pre_pll_cfg_table[] = {
+ { 27000000, 27000000, 1, 90, 3, 2, 2, 10, 3, 3, 4, 0, 0},
+ { 27000000, 33750000, 1, 90, 1, 3, 3, 10, 3, 3, 4, 0, 0},
+ { 40000000, 40000000, 1, 80, 2, 2, 2, 12, 2, 2, 2, 0, 0},
+ { 59341000, 59341000, 1, 98, 3, 1, 2, 1, 3, 3, 4, 0, 0xE6AE6B},
+ { 59400000, 59400000, 1, 99, 3, 1, 1, 1, 3, 3, 4, 0, 0},
+ { 59341000, 74176250, 1, 98, 0, 3, 3, 1, 3, 3, 4, 0, 0xE6AE6B},
+ { 59400000, 74250000, 1, 99, 1, 2, 2, 1, 3, 3, 4, 0, 0},
+ { 74176000, 74176000, 1, 98, 1, 2, 2, 1, 2, 3, 4, 0, 0xE6AE6B},
+ { 74250000, 74250000, 1, 99, 1, 2, 2, 1, 2, 3, 4, 0, 0},
+ { 74176000, 92720000, 4, 494, 1, 2, 2, 1, 3, 3, 4, 0, 0x816817},
+ { 74250000, 92812500, 4, 495, 1, 2, 2, 1, 3, 3, 4, 0, 0},
+ {148352000, 148352000, 1, 98, 1, 1, 1, 1, 2, 2, 2, 0, 0xE6AE6B},
+ {148500000, 148500000, 1, 99, 1, 1, 1, 1, 2, 2, 2, 0, 0},
+ {148352000, 185440000, 4, 494, 0, 2, 2, 1, 3, 2, 2, 0, 0x816817},
+ {148500000, 185625000, 4, 495, 0, 2, 2, 1, 3, 2, 2, 0, 0},
+ {296703000, 296703000, 1, 98, 0, 1, 1, 1, 0, 2, 2, 0, 0xE6AE6B},
+ {297000000, 297000000, 1, 99, 0, 1, 1, 1, 0, 2, 2, 0, 0},
+ {296703000, 370878750, 4, 494, 1, 2, 0, 1, 3, 1, 1, 0, 0x816817},
+ {297000000, 371250000, 4, 495, 1, 2, 0, 1, 3, 1, 1, 0, 0},
+ {593407000, 296703500, 1, 98, 0, 1, 1, 1, 0, 2, 1, 0, 0xE6AE6B},
+ {594000000, 297000000, 1, 99, 0, 1, 1, 1, 0, 2, 1, 0, 0},
+ {593407000, 370879375, 4, 494, 1, 2, 0, 1, 3, 1, 1, 1, 0x816817},
+ {594000000, 371250000, 4, 495, 1, 2, 0, 1, 3, 1, 1, 1, 0},
+ {593407000, 593407000, 1, 98, 0, 2, 0, 1, 0, 1, 1, 0, 0xE6AE6B},
+ {594000000, 594000000, 1, 99, 0, 2, 0, 1, 0, 1, 1, 0, 0},
+ { /* sentinel */ }
+};
+
+static const struct post_pll_config post_pll_cfg_table[] = {
+ {33750000, 1, 40, 8, 1},
+ {33750000, 1, 80, 8, 2},
+ {74250000, 1, 40, 8, 1},
+ {74250000, 18, 80, 8, 2},
+ {148500000, 2, 40, 4, 3},
+ {297000000, 4, 40, 2, 3},
+ {594000000, 8, 40, 1, 3},
+ { /* sentinel */ }
+};
+
+/* phy tuning values for an undocumented set of registers */
+static const struct phy_config rk3228_phy_cfg[] = {
+ { 165000000, {
+ 0xaa, 0x00, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ }, {
+ 340000000, {
+ 0xaa, 0x15, 0x6a, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ }, {
+ 594000000, {
+ 0xaa, 0x15, 0x7a, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ }, { /* sentinel */ },
+};
+
+/* phy tuning values for an undocumented set of registers */
+static const struct phy_config rk3328_phy_cfg[] = {
+ { 165000000, {
+ 0x07, 0x0a, 0x0a, 0x0a, 0x00, 0x00, 0x08, 0x08, 0x08,
+ 0x00, 0xac, 0xcc, 0xcc, 0xcc,
+ },
+ }, {
+ 340000000, {
+ 0x0b, 0x0d, 0x0d, 0x0d, 0x07, 0x15, 0x08, 0x08, 0x08,
+ 0x3f, 0xac, 0xcc, 0xcd, 0xdd,
+ },
+ }, {
+ 594000000, {
+ 0x10, 0x1a, 0x1a, 0x1a, 0x07, 0x15, 0x08, 0x08, 0x08,
+ 0x00, 0xac, 0xcc, 0xcc, 0xcc,
+ },
+ }, { /* sentinel */ },
+};
+
+static inline struct inno_hdmi_phy *to_inno_hdmi_phy(struct clk_hw *hw)
+{
+ return container_of(hw, struct inno_hdmi_phy, hw);
+}
+
+/*
+ * The register description of the IP block does not use any distinct names
+ * but instead the databook simply numbers the registers in one-increments.
+ * As the registers are obviously 32bit sized, the inno_* functions
+ * translate the databook register names to the actual registers addresses.
+ */
+static inline void inno_write(struct inno_hdmi_phy *inno, u32 reg, u8 val)
+{
+ regmap_write(inno->regmap, reg * 4, val);
+}
+
+static inline u8 inno_read(struct inno_hdmi_phy *inno, u32 reg)
+{
+ u32 val;
+
+ regmap_read(inno->regmap, reg * 4, &val);
+
+ return val;
+}
+
+static inline void inno_update_bits(struct inno_hdmi_phy *inno, u8 reg,
+ u8 mask, u8 val)
+{
+ regmap_update_bits(inno->regmap, reg * 4, mask, val);
+}
+
+#define inno_poll(inno, reg, val, cond, sleep_us, timeout_us) \
+ regmap_read_poll_timeout((inno)->regmap, (reg) * 4, val, cond, \
+ sleep_us, timeout_us)
+
+static unsigned long inno_hdmi_phy_get_tmdsclk(struct inno_hdmi_phy *inno,
+ unsigned long rate)
+{
+ int bus_width = phy_get_bus_width(inno->phy);
+
+ switch (bus_width) {
+ case 4:
+ case 5:
+ case 6:
+ case 10:
+ case 12:
+ case 16:
+ return (u64)rate * bus_width / 8;
+ default:
+ return rate;
+ }
+}
+
+static irqreturn_t inno_hdmi_phy_rk3328_hardirq(int irq, void *dev_id)
+{
+ struct inno_hdmi_phy *inno = dev_id;
+ int intr_stat1, intr_stat2, intr_stat3;
+
+ intr_stat1 = inno_read(inno, 0x04);
+ intr_stat2 = inno_read(inno, 0x06);
+ intr_stat3 = inno_read(inno, 0x08);
+
+ if (intr_stat1)
+ inno_write(inno, 0x04, intr_stat1);
+ if (intr_stat2)
+ inno_write(inno, 0x06, intr_stat2);
+ if (intr_stat3)
+ inno_write(inno, 0x08, intr_stat3);
+
+ if (intr_stat1 || intr_stat2 || intr_stat3)
+ return IRQ_WAKE_THREAD;
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t inno_hdmi_phy_rk3328_irq(int irq, void *dev_id)
+{
+ struct inno_hdmi_phy *inno = dev_id;
+
+ inno_update_bits(inno, 0x02, RK3328_PDATA_EN, 0);
+ usleep_range(10, 20);
+ inno_update_bits(inno, 0x02, RK3328_PDATA_EN, RK3328_PDATA_EN);
+
+ return IRQ_HANDLED;
+}
+
+static int inno_hdmi_phy_power_on(struct phy *phy)
+{
+ struct inno_hdmi_phy *inno = phy_get_drvdata(phy);
+ const struct post_pll_config *cfg = post_pll_cfg_table;
+ const struct phy_config *phy_cfg = inno->plat_data->phy_cfg_table;
+ unsigned long tmdsclock = inno_hdmi_phy_get_tmdsclk(inno,
+ inno->pixclock);
+ int ret;
+
+ if (!tmdsclock) {
+ dev_err(inno->dev, "TMDS clock is zero!\n");
+ return -EINVAL;
+ }
+
+ if (!inno->plat_data->ops->power_on)
+ return -EINVAL;
+
+ for (; cfg->tmdsclock != 0; cfg++)
+ if (tmdsclock <= cfg->tmdsclock &&
+ cfg->version & inno->chip_version)
+ break;
+
+ for (; phy_cfg->tmdsclock != 0; phy_cfg++)
+ if (tmdsclock <= phy_cfg->tmdsclock)
+ break;
+
+ if (cfg->tmdsclock == 0 || phy_cfg->tmdsclock == 0)
+ return -EINVAL;
+
+ dev_dbg(inno->dev, "Inno HDMI PHY Power On\n");
+
+ ret = clk_prepare_enable(inno->phyclk);
+ if (ret)
+ return ret;
+
+ ret = inno->plat_data->ops->power_on(inno, cfg, phy_cfg);
+ if (ret) {
+ clk_disable_unprepare(inno->phyclk);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int inno_hdmi_phy_power_off(struct phy *phy)
+{
+ struct inno_hdmi_phy *inno = phy_get_drvdata(phy);
+
+ if (!inno->plat_data->ops->power_off)
+ return -EINVAL;
+
+ inno->plat_data->ops->power_off(inno);
+
+ clk_disable_unprepare(inno->phyclk);
+
+ dev_dbg(inno->dev, "Inno HDMI PHY Power Off\n");
+
+ return 0;
+}
+
+static const struct phy_ops inno_hdmi_phy_ops = {
+ .owner = THIS_MODULE,
+ .power_on = inno_hdmi_phy_power_on,
+ .power_off = inno_hdmi_phy_power_off,
+};
+
+static const
+struct pre_pll_config *inno_hdmi_phy_get_pre_pll_cfg(struct inno_hdmi_phy *inno,
+ unsigned long rate)
+{
+ const struct pre_pll_config *cfg = pre_pll_cfg_table;
+ unsigned long tmdsclock = inno_hdmi_phy_get_tmdsclk(inno, rate);
+
+ for (; cfg->pixclock != 0; cfg++)
+ if (cfg->pixclock == rate && cfg->tmdsclock == tmdsclock)
+ break;
+
+ if (cfg->pixclock == 0)
+ return ERR_PTR(-EINVAL);
+
+ return cfg;
+}
+
+static int inno_hdmi_phy_rk3228_clk_is_prepared(struct clk_hw *hw)
+{
+ struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw);
+ u8 status;
+
+ status = inno_read(inno, 0xe0) & RK3228_PRE_PLL_POWER_DOWN;
+ return status ? 0 : 1;
+}
+
+static int inno_hdmi_phy_rk3228_clk_prepare(struct clk_hw *hw)
+{
+ struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw);
+
+ inno_update_bits(inno, 0xe0, RK3228_PRE_PLL_POWER_DOWN, 0);
+ return 0;
+}
+
+static void inno_hdmi_phy_rk3228_clk_unprepare(struct clk_hw *hw)
+{
+ struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw);
+
+ inno_update_bits(inno, 0xe0, RK3228_PRE_PLL_POWER_DOWN,
+ RK3228_PRE_PLL_POWER_DOWN);
+}
+
+static
+unsigned long inno_hdmi_phy_rk3228_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw);
+ u8 nd, no_a, no_b, no_d;
+ u64 vco;
+ u16 nf;
+
+ nd = inno_read(inno, 0xe2) & RK3228_PRE_PLL_PRE_DIV_MASK;
+ nf = (inno_read(inno, 0xe2) & RK3228_PRE_PLL_FB_DIV_8_MASK) << 1;
+ nf |= inno_read(inno, 0xe3);
+ vco = parent_rate * nf;
+
+ if (inno_read(inno, 0xe2) & RK3228_PCLK_VCO_DIV_5_MASK) {
+ do_div(vco, nd * 5);
+ } else {
+ no_a = inno_read(inno, 0xe4) & RK3228_PRE_PLL_PCLK_DIV_A_MASK;
+ if (!no_a)
+ no_a = 1;
+ no_b = inno_read(inno, 0xe4) & RK3228_PRE_PLL_PCLK_DIV_B_MASK;
+ no_b >>= RK3228_PRE_PLL_PCLK_DIV_B_SHIFT;
+ no_b += 2;
+ no_d = inno_read(inno, 0xe5) & RK3228_PRE_PLL_PCLK_DIV_D_MASK;
+
+ do_div(vco, (nd * (no_a == 1 ? no_b : no_a) * no_d * 2));
+ }
+
+ inno->pixclock = vco;
+
+ dev_dbg(inno->dev, "%s rate %lu\n", __func__, inno->pixclock);
+
+ return vco;
+}
+
+static long inno_hdmi_phy_rk3228_clk_round_rate(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long *parent_rate)
+{
+ const struct pre_pll_config *cfg = pre_pll_cfg_table;
+
+ for (; cfg->pixclock != 0; cfg++)
+ if (cfg->pixclock == rate && !cfg->fracdiv)
+ break;
+
+ if (cfg->pixclock == 0)
+ return -EINVAL;
+
+ return cfg->pixclock;
+}
+
+static int inno_hdmi_phy_rk3228_clk_set_rate(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw);
+ const struct pre_pll_config *cfg = pre_pll_cfg_table;
+ unsigned long tmdsclock = inno_hdmi_phy_get_tmdsclk(inno, rate);
+ u32 v;
+ int ret;
+
+ dev_dbg(inno->dev, "%s rate %lu tmdsclk %lu\n",
+ __func__, rate, tmdsclock);
+
+ cfg = inno_hdmi_phy_get_pre_pll_cfg(inno, rate);
+ if (IS_ERR(cfg))
+ return PTR_ERR(cfg);
+
+ /* Power down PRE-PLL */
+ inno_update_bits(inno, 0xe0, RK3228_PRE_PLL_POWER_DOWN,
+ RK3228_PRE_PLL_POWER_DOWN);
+
+ inno_update_bits(inno, 0xe2, RK3228_PRE_PLL_FB_DIV_8_MASK |
+ RK3228_PCLK_VCO_DIV_5_MASK |
+ RK3228_PRE_PLL_PRE_DIV_MASK,
+ RK3228_PRE_PLL_FB_DIV_8(cfg->fbdiv) |
+ RK3228_PCLK_VCO_DIV_5(cfg->vco_div_5_en) |
+ RK3228_PRE_PLL_PRE_DIV(cfg->prediv));
+ inno_write(inno, 0xe3, RK3228_PRE_PLL_FB_DIV_7_0(cfg->fbdiv));
+ inno_update_bits(inno, 0xe4, RK3228_PRE_PLL_PCLK_DIV_B_MASK |
+ RK3228_PRE_PLL_PCLK_DIV_A_MASK,
+ RK3228_PRE_PLL_PCLK_DIV_B(cfg->pclk_div_b) |
+ RK3228_PRE_PLL_PCLK_DIV_A(cfg->pclk_div_a));
+ inno_update_bits(inno, 0xe5, RK3228_PRE_PLL_PCLK_DIV_C_MASK |
+ RK3228_PRE_PLL_PCLK_DIV_D_MASK,
+ RK3228_PRE_PLL_PCLK_DIV_C(cfg->pclk_div_c) |
+ RK3228_PRE_PLL_PCLK_DIV_D(cfg->pclk_div_d));
+ inno_update_bits(inno, 0xe6, RK3228_PRE_PLL_TMDSCLK_DIV_C_MASK |
+ RK3228_PRE_PLL_TMDSCLK_DIV_A_MASK |
+ RK3228_PRE_PLL_TMDSCLK_DIV_B_MASK,
+ RK3228_PRE_PLL_TMDSCLK_DIV_C(cfg->tmds_div_c) |
+ RK3228_PRE_PLL_TMDSCLK_DIV_A(cfg->tmds_div_a) |
+ RK3228_PRE_PLL_TMDSCLK_DIV_B(cfg->tmds_div_b));
+
+ /* Power up PRE-PLL */
+ inno_update_bits(inno, 0xe0, RK3228_PRE_PLL_POWER_DOWN, 0);
+
+ /* Wait for Pre-PLL lock */
+ ret = inno_poll(inno, 0xe8, v, v & RK3228_PRE_PLL_LOCK_STATUS,
+ 100, 100000);
+ if (ret) {
+ dev_err(inno->dev, "Pre-PLL locking failed\n");
+ return ret;
+ }
+
+ inno->pixclock = rate;
+
+ return 0;
+}
+
+static const struct clk_ops inno_hdmi_phy_rk3228_clk_ops = {
+ .prepare = inno_hdmi_phy_rk3228_clk_prepare,
+ .unprepare = inno_hdmi_phy_rk3228_clk_unprepare,
+ .is_prepared = inno_hdmi_phy_rk3228_clk_is_prepared,
+ .recalc_rate = inno_hdmi_phy_rk3228_clk_recalc_rate,
+ .round_rate = inno_hdmi_phy_rk3228_clk_round_rate,
+ .set_rate = inno_hdmi_phy_rk3228_clk_set_rate,
+};
+
+static int inno_hdmi_phy_rk3328_clk_is_prepared(struct clk_hw *hw)
+{
+ struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw);
+ u8 status;
+
+ status = inno_read(inno, 0xa0) & RK3328_PRE_PLL_POWER_DOWN;
+ return status ? 0 : 1;
+}
+
+static int inno_hdmi_phy_rk3328_clk_prepare(struct clk_hw *hw)
+{
+ struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw);
+
+ inno_update_bits(inno, 0xa0, RK3328_PRE_PLL_POWER_DOWN, 0);
+ return 0;
+}
+
+static void inno_hdmi_phy_rk3328_clk_unprepare(struct clk_hw *hw)
+{
+ struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw);
+
+ inno_update_bits(inno, 0xa0, RK3328_PRE_PLL_POWER_DOWN,
+ RK3328_PRE_PLL_POWER_DOWN);
+}
+
+static
+unsigned long inno_hdmi_phy_rk3328_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw);
+ unsigned long frac;
+ u8 nd, no_a, no_b, no_c, no_d;
+ u64 vco;
+ u16 nf;
+
+ nd = inno_read(inno, 0xa1) & RK3328_PRE_PLL_PRE_DIV_MASK;
+ nf = ((inno_read(inno, 0xa2) & RK3328_PRE_PLL_FB_DIV_11_8_MASK) << 8);
+ nf |= inno_read(inno, 0xa3);
+ vco = parent_rate * nf;
+
+ if (!(inno_read(inno, 0xa2) & RK3328_PRE_PLL_FRAC_DIV_DISABLE)) {
+ frac = inno_read(inno, 0xd3) |
+ (inno_read(inno, 0xd2) << 8) |
+ (inno_read(inno, 0xd1) << 16);
+ vco += DIV_ROUND_CLOSEST(parent_rate * frac, (1 << 24));
+ }
+
+ if (inno_read(inno, 0xa0) & RK3328_PCLK_VCO_DIV_5_MASK) {
+ do_div(vco, nd * 5);
+ } else {
+ no_a = inno_read(inno, 0xa5) & RK3328_PRE_PLL_PCLK_DIV_A_MASK;
+ no_b = inno_read(inno, 0xa5) & RK3328_PRE_PLL_PCLK_DIV_B_MASK;
+ no_b >>= RK3328_PRE_PLL_PCLK_DIV_B_SHIFT;
+ no_b += 2;
+ no_c = inno_read(inno, 0xa6) & RK3328_PRE_PLL_PCLK_DIV_C_MASK;
+ no_c >>= RK3328_PRE_PLL_PCLK_DIV_C_SHIFT;
+ no_c = 1 << no_c;
+ no_d = inno_read(inno, 0xa6) & RK3328_PRE_PLL_PCLK_DIV_D_MASK;
+
+ do_div(vco, (nd * (no_a == 1 ? no_b : no_a) * no_d * 2));
+ }
+
+ inno->pixclock = vco;
+ dev_dbg(inno->dev, "%s rate %lu\n", __func__, inno->pixclock);
+
+ return vco;
+}
+
+static long inno_hdmi_phy_rk3328_clk_round_rate(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long *parent_rate)
+{
+ const struct pre_pll_config *cfg = pre_pll_cfg_table;
+
+ for (; cfg->pixclock != 0; cfg++)
+ if (cfg->pixclock == rate)
+ break;
+
+ if (cfg->pixclock == 0)
+ return -EINVAL;
+
+ return cfg->pixclock;
+}
+
+static int inno_hdmi_phy_rk3328_clk_set_rate(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw);
+ const struct pre_pll_config *cfg = pre_pll_cfg_table;
+ unsigned long tmdsclock = inno_hdmi_phy_get_tmdsclk(inno, rate);
+ u32 val;
+ int ret;
+
+ dev_dbg(inno->dev, "%s rate %lu tmdsclk %lu\n",
+ __func__, rate, tmdsclock);
+
+ cfg = inno_hdmi_phy_get_pre_pll_cfg(inno, rate);
+ if (IS_ERR(cfg))
+ return PTR_ERR(cfg);
+
+ inno_update_bits(inno, 0xa0, RK3328_PRE_PLL_POWER_DOWN,
+ RK3328_PRE_PLL_POWER_DOWN);
+
+ /* Configure pre-pll */
+ inno_update_bits(inno, 0xa0, RK3228_PCLK_VCO_DIV_5_MASK,
+ RK3228_PCLK_VCO_DIV_5(cfg->vco_div_5_en));
+ inno_write(inno, 0xa1, RK3328_PRE_PLL_PRE_DIV(cfg->prediv));
+
+ val = RK3328_SPREAD_SPECTRUM_MOD_DISABLE;
+ if (!cfg->fracdiv)
+ val |= RK3328_PRE_PLL_FRAC_DIV_DISABLE;
+ inno_write(inno, 0xa2, RK3328_PRE_PLL_FB_DIV_11_8(cfg->fbdiv) | val);
+ inno_write(inno, 0xa3, RK3328_PRE_PLL_FB_DIV_7_0(cfg->fbdiv));
+ inno_write(inno, 0xa5, RK3328_PRE_PLL_PCLK_DIV_A(cfg->pclk_div_a) |
+ RK3328_PRE_PLL_PCLK_DIV_B(cfg->pclk_div_b));
+ inno_write(inno, 0xa6, RK3328_PRE_PLL_PCLK_DIV_C(cfg->pclk_div_c) |
+ RK3328_PRE_PLL_PCLK_DIV_D(cfg->pclk_div_d));
+ inno_write(inno, 0xa4, RK3328_PRE_PLL_TMDSCLK_DIV_C(cfg->tmds_div_c) |
+ RK3328_PRE_PLL_TMDSCLK_DIV_A(cfg->tmds_div_a) |
+ RK3328_PRE_PLL_TMDSCLK_DIV_B(cfg->tmds_div_b));
+ inno_write(inno, 0xd3, RK3328_PRE_PLL_FRAC_DIV_7_0(cfg->fracdiv));
+ inno_write(inno, 0xd2, RK3328_PRE_PLL_FRAC_DIV_15_8(cfg->fracdiv));
+ inno_write(inno, 0xd1, RK3328_PRE_PLL_FRAC_DIV_23_16(cfg->fracdiv));
+
+ inno_update_bits(inno, 0xa0, RK3328_PRE_PLL_POWER_DOWN, 0);
+
+ /* Wait for Pre-PLL lock */
+ ret = inno_poll(inno, 0xa9, val, val & RK3328_PRE_PLL_LOCK_STATUS,
+ 1000, 10000);
+ if (ret) {
+ dev_err(inno->dev, "Pre-PLL locking failed\n");
+ return ret;
+ }
+
+ inno->pixclock = rate;
+
+ return 0;
+}
+
+static const struct clk_ops inno_hdmi_phy_rk3328_clk_ops = {
+ .prepare = inno_hdmi_phy_rk3328_clk_prepare,
+ .unprepare = inno_hdmi_phy_rk3328_clk_unprepare,
+ .is_prepared = inno_hdmi_phy_rk3328_clk_is_prepared,
+ .recalc_rate = inno_hdmi_phy_rk3328_clk_recalc_rate,
+ .round_rate = inno_hdmi_phy_rk3328_clk_round_rate,
+ .set_rate = inno_hdmi_phy_rk3328_clk_set_rate,
+};
+
+static int inno_hdmi_phy_clk_register(struct inno_hdmi_phy *inno)
+{
+ struct device *dev = inno->dev;
+ struct device_node *np = dev->of_node;
+ struct clk_init_data init;
+ const char *parent_name;
+ int ret;
+
+ parent_name = __clk_get_name(inno->refoclk);
+
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+ init.flags = 0;
+ init.name = "pin_hd20_pclk";
+ init.ops = inno->plat_data->clk_ops;
+
+ /* optional override of the clock name */
+ of_property_read_string(np, "clock-output-names", &init.name);
+
+ inno->hw.init = &init;
+
+ inno->phyclk = devm_clk_register(dev, &inno->hw);
+ if (IS_ERR(inno->phyclk)) {
+ ret = PTR_ERR(inno->phyclk);
+ dev_err(dev, "failed to register clock: %d\n", ret);
+ return ret;
+ }
+
+ ret = of_clk_add_provider(np, of_clk_src_simple_get, inno->phyclk);
+ if (ret) {
+ dev_err(dev, "failed to register clock provider: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int inno_hdmi_phy_rk3228_init(struct inno_hdmi_phy *inno)
+{
+ /*
+ * Use phy internal register control
+ * rxsense/poweron/pllpd/pdataen signal.
+ */
+ inno_write(inno, 0x01, RK3228_BYPASS_RXSENSE_EN |
+ RK3228_BYPASS_PWRON_EN |
+ RK3228_BYPASS_PLLPD_EN);
+ inno_update_bits(inno, 0x02, RK3228_BYPASS_PDATA_EN,
+ RK3228_BYPASS_PDATA_EN);
+
+ /* manual power down post-PLL */
+ inno_update_bits(inno, 0xaa, RK3228_POST_PLL_CTRL_MANUAL,
+ RK3228_POST_PLL_CTRL_MANUAL);
+
+ inno->chip_version = 1;
+
+ return 0;
+}
+
+static int
+inno_hdmi_phy_rk3228_power_on(struct inno_hdmi_phy *inno,
+ const struct post_pll_config *cfg,
+ const struct phy_config *phy_cfg)
+{
+ int ret;
+ u32 v;
+
+ inno_update_bits(inno, 0x02, RK3228_PDATAEN_DISABLE,
+ RK3228_PDATAEN_DISABLE);
+ inno_update_bits(inno, 0xe0, RK3228_PRE_PLL_POWER_DOWN |
+ RK3228_POST_PLL_POWER_DOWN,
+ RK3228_PRE_PLL_POWER_DOWN |
+ RK3228_POST_PLL_POWER_DOWN);
+
+ /* Post-PLL update */
+ inno_update_bits(inno, 0xe9, RK3228_POST_PLL_PRE_DIV_MASK,
+ RK3228_POST_PLL_PRE_DIV(cfg->prediv));
+ inno_update_bits(inno, 0xeb, RK3228_POST_PLL_FB_DIV_8_MASK,
+ RK3228_POST_PLL_FB_DIV_8(cfg->fbdiv));
+ inno_write(inno, 0xea, RK3228_POST_PLL_FB_DIV_7_0(cfg->fbdiv));
+
+ if (cfg->postdiv == 1) {
+ inno_update_bits(inno, 0xe9, RK3228_POST_PLL_POST_DIV_ENABLE,
+ 0);
+ } else {
+ int div = cfg->postdiv / 2 - 1;
+
+ inno_update_bits(inno, 0xe9, RK3228_POST_PLL_POST_DIV_ENABLE,
+ RK3228_POST_PLL_POST_DIV_ENABLE);
+ inno_update_bits(inno, 0xeb, RK3228_POST_PLL_POST_DIV_MASK,
+ RK3228_POST_PLL_POST_DIV(div));
+ }
+
+ for (v = 0; v < 4; v++)
+ inno_write(inno, 0xef + v, phy_cfg->regs[v]);
+
+ inno_update_bits(inno, 0xe0, RK3228_PRE_PLL_POWER_DOWN |
+ RK3228_POST_PLL_POWER_DOWN, 0);
+ inno_update_bits(inno, 0xe1, RK3228_BANDGAP_ENABLE,
+ RK3228_BANDGAP_ENABLE);
+ inno_update_bits(inno, 0xe1, RK3228_TMDS_DRIVER_ENABLE,
+ RK3228_TMDS_DRIVER_ENABLE);
+
+ /* Wait for post PLL lock */
+ ret = inno_poll(inno, 0xeb, v, v & RK3228_POST_PLL_LOCK_STATUS,
+ 100, 100000);
+ if (ret) {
+ dev_err(inno->dev, "Post-PLL locking failed\n");
+ return ret;
+ }
+
+ if (cfg->tmdsclock > 340000000)
+ msleep(100);
+
+ inno_update_bits(inno, 0x02, RK3228_PDATAEN_DISABLE, 0);
+ return 0;
+}
+
+static void inno_hdmi_phy_rk3228_power_off(struct inno_hdmi_phy *inno)
+{
+ inno_update_bits(inno, 0xe1, RK3228_TMDS_DRIVER_ENABLE, 0);
+ inno_update_bits(inno, 0xe1, RK3228_BANDGAP_ENABLE, 0);
+ inno_update_bits(inno, 0xe0, RK3228_POST_PLL_POWER_DOWN,
+ RK3228_POST_PLL_POWER_DOWN);
+}
+
+static const struct inno_hdmi_phy_ops rk3228_hdmi_phy_ops = {
+ .init = inno_hdmi_phy_rk3228_init,
+ .power_on = inno_hdmi_phy_rk3228_power_on,
+ .power_off = inno_hdmi_phy_rk3228_power_off,
+};
+
+static int inno_hdmi_phy_rk3328_init(struct inno_hdmi_phy *inno)
+{
+ struct nvmem_cell *cell;
+ unsigned char *efuse_buf;
+ size_t len;
+
+ /*
+ * Use phy internal register control
+ * rxsense/poweron/pllpd/pdataen signal.
+ */
+ inno_write(inno, 0x01, RK3328_BYPASS_RXSENSE_EN |
+ RK3328_BYPASS_POWERON_EN |
+ RK3328_BYPASS_PLLPD_EN);
+ inno_write(inno, 0x02, RK3328_INT_POL_HIGH | RK3328_BYPASS_PDATA_EN |
+ RK3328_PDATA_EN);
+
+ /* Disable phy irq */
+ inno_write(inno, 0x05, 0);
+ inno_write(inno, 0x07, 0);
+
+ /* try to read the chip-version */
+ inno->chip_version = 1;
+ cell = nvmem_cell_get(inno->dev, "cpu-version");
+ if (IS_ERR(cell)) {
+ if (PTR_ERR(cell) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ return 0;
+ }
+
+ efuse_buf = nvmem_cell_read(cell, &len);
+ nvmem_cell_put(cell);
+
+ if (IS_ERR(efuse_buf))
+ return 0;
+ if (len == 1)
+ inno->chip_version = efuse_buf[0] + 1;
+ kfree(efuse_buf);
+
+ return 0;
+}
+
+static int
+inno_hdmi_phy_rk3328_power_on(struct inno_hdmi_phy *inno,
+ const struct post_pll_config *cfg,
+ const struct phy_config *phy_cfg)
+{
+ int ret;
+ u32 v;
+
+ inno_update_bits(inno, 0x02, RK3328_PDATA_EN, 0);
+ inno_update_bits(inno, 0xaa, RK3328_POST_PLL_POWER_DOWN,
+ RK3328_POST_PLL_POWER_DOWN);
+
+ inno_write(inno, 0xac, RK3328_POST_PLL_FB_DIV_7_0(cfg->fbdiv));
+ if (cfg->postdiv == 1) {
+ inno_write(inno, 0xaa, RK3328_POST_PLL_REFCLK_SEL_TMDS);
+ inno_write(inno, 0xab, RK3328_POST_PLL_FB_DIV_8(cfg->fbdiv) |
+ RK3328_POST_PLL_PRE_DIV(cfg->prediv));
+ } else {
+ v = (cfg->postdiv / 2) - 1;
+ v &= RK3328_POST_PLL_POST_DIV_MASK;
+ inno_write(inno, 0xad, v);
+ inno_write(inno, 0xab, RK3328_POST_PLL_FB_DIV_8(cfg->fbdiv) |
+ RK3328_POST_PLL_PRE_DIV(cfg->prediv));
+ inno_write(inno, 0xaa, RK3328_POST_PLL_POST_DIV_ENABLE |
+ RK3328_POST_PLL_REFCLK_SEL_TMDS);
+ }
+
+ for (v = 0; v < 14; v++)
+ inno_write(inno, 0xb5 + v, phy_cfg->regs[v]);
+
+ /* set ESD detection threshold for TMDS CLK, D2, D1 and D0 */
+ for (v = 0; v < 4; v++)
+ inno_update_bits(inno, 0xc8 + v, RK3328_ESD_DETECT_MASK,
+ RK3328_ESD_DETECT_340MV);
+
+ if (phy_cfg->tmdsclock > 340000000) {
+ /* Set termination resistor to 100ohm */
+ v = clk_get_rate(inno->sysclk) / 100000;
+ inno_write(inno, 0xc5, RK3328_TERM_RESISTOR_CALIB_SPEED_14_8(v)
+ | RK3328_BYPASS_TERM_RESISTOR_CALIB);
+ inno_write(inno, 0xc6, RK3328_TERM_RESISTOR_CALIB_SPEED_7_0(v));
+ inno_write(inno, 0xc7, RK3328_TERM_RESISTOR_100);
+ inno_update_bits(inno, 0xc5,
+ RK3328_BYPASS_TERM_RESISTOR_CALIB, 0);
+ } else {
+ inno_write(inno, 0xc5, RK3328_BYPASS_TERM_RESISTOR_CALIB);
+
+ /* clk termination resistor is 50ohm (parallel resistors) */
+ if (phy_cfg->tmdsclock > 165000000)
+ inno_update_bits(inno, 0xc8,
+ RK3328_TMDS_TERM_RESIST_MASK,
+ RK3328_TMDS_TERM_RESIST_75 |
+ RK3328_TMDS_TERM_RESIST_150);
+
+ /* data termination resistor for D2, D1 and D0 is 150ohm */
+ for (v = 0; v < 3; v++)
+ inno_update_bits(inno, 0xc9 + v,
+ RK3328_TMDS_TERM_RESIST_MASK,
+ RK3328_TMDS_TERM_RESIST_150);
+ }
+
+ inno_update_bits(inno, 0xaa, RK3328_POST_PLL_POWER_DOWN, 0);
+ inno_update_bits(inno, 0xb0, RK3328_BANDGAP_ENABLE,
+ RK3328_BANDGAP_ENABLE);
+ inno_update_bits(inno, 0xb2, RK3328_TMDS_DRIVER_ENABLE,
+ RK3328_TMDS_DRIVER_ENABLE);
+
+ /* Wait for post PLL lock */
+ ret = inno_poll(inno, 0xaf, v, v & RK3328_POST_PLL_LOCK_STATUS,
+ 1000, 10000);
+ if (ret) {
+ dev_err(inno->dev, "Post-PLL locking failed\n");
+ return ret;
+ }
+
+ if (phy_cfg->tmdsclock > 340000000)
+ msleep(100);
+
+ inno_update_bits(inno, 0x02, RK3328_PDATA_EN, RK3328_PDATA_EN);
+
+ /* Enable PHY IRQ */
+ inno_write(inno, 0x05, RK3328_INT_TMDS_CLK(RK3328_INT_VSS_AGND_ESD_DET)
+ | RK3328_INT_TMDS_D2(RK3328_INT_VSS_AGND_ESD_DET));
+ inno_write(inno, 0x07, RK3328_INT_TMDS_D1(RK3328_INT_VSS_AGND_ESD_DET)
+ | RK3328_INT_TMDS_D0(RK3328_INT_VSS_AGND_ESD_DET));
+ return 0;
+}
+
+static void inno_hdmi_phy_rk3328_power_off(struct inno_hdmi_phy *inno)
+{
+ inno_update_bits(inno, 0xb2, RK3328_TMDS_DRIVER_ENABLE, 0);
+ inno_update_bits(inno, 0xb0, RK3328_BANDGAP_ENABLE, 0);
+ inno_update_bits(inno, 0xaa, RK3328_POST_PLL_POWER_DOWN,
+ RK3328_POST_PLL_POWER_DOWN);
+
+ /* Disable PHY IRQ */
+ inno_write(inno, 0x05, 0);
+ inno_write(inno, 0x07, 0);
+}
+
+static const struct inno_hdmi_phy_ops rk3328_hdmi_phy_ops = {
+ .init = inno_hdmi_phy_rk3328_init,
+ .power_on = inno_hdmi_phy_rk3328_power_on,
+ .power_off = inno_hdmi_phy_rk3328_power_off,
+};
+
+static const struct inno_hdmi_phy_drv_data rk3228_hdmi_phy_drv_data = {
+ .ops = &rk3228_hdmi_phy_ops,
+ .clk_ops = &inno_hdmi_phy_rk3228_clk_ops,
+ .phy_cfg_table = rk3228_phy_cfg,
+};
+
+static const struct inno_hdmi_phy_drv_data rk3328_hdmi_phy_drv_data = {
+ .ops = &rk3328_hdmi_phy_ops,
+ .clk_ops = &inno_hdmi_phy_rk3328_clk_ops,
+ .phy_cfg_table = rk3328_phy_cfg,
+};
+
+static const struct regmap_config inno_hdmi_phy_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = 0x400,
+};
+
+static void inno_hdmi_phy_action(void *data)
+{
+ struct inno_hdmi_phy *inno = data;
+
+ clk_disable_unprepare(inno->refpclk);
+ clk_disable_unprepare(inno->sysclk);
+}
+
+static int inno_hdmi_phy_probe(struct platform_device *pdev)
+{
+ struct inno_hdmi_phy *inno;
+ struct phy_provider *phy_provider;
+ struct resource *res;
+ void __iomem *regs;
+ int ret;
+
+ inno = devm_kzalloc(&pdev->dev, sizeof(*inno), GFP_KERNEL);
+ if (!inno)
+ return -ENOMEM;
+
+ inno->dev = &pdev->dev;
+
+ inno->plat_data = of_device_get_match_data(inno->dev);
+ if (!inno->plat_data || !inno->plat_data->ops)
+ return -EINVAL;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ regs = devm_ioremap_resource(inno->dev, res);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+
+ inno->sysclk = devm_clk_get(inno->dev, "sysclk");
+ if (IS_ERR(inno->sysclk)) {
+ ret = PTR_ERR(inno->sysclk);
+ dev_err(inno->dev, "failed to get sysclk: %d\n", ret);
+ return ret;
+ }
+
+ inno->refpclk = devm_clk_get(inno->dev, "refpclk");
+ if (IS_ERR(inno->refpclk)) {
+ ret = PTR_ERR(inno->refpclk);
+ dev_err(inno->dev, "failed to get ref clock: %d\n", ret);
+ return ret;
+ }
+
+ inno->refoclk = devm_clk_get(inno->dev, "refoclk");
+ if (IS_ERR(inno->refoclk)) {
+ ret = PTR_ERR(inno->refoclk);
+ dev_err(inno->dev, "failed to get oscillator-ref clock: %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(inno->sysclk);
+ if (ret) {
+ dev_err(inno->dev, "Cannot enable inno phy sysclk: %d\n", ret);
+ return ret;
+ }
+
+ /*
+ * Refpclk needs to be on, on at least the rk3328 for still
+ * unknown reasons.
+ */
+ ret = clk_prepare_enable(inno->refpclk);
+ if (ret) {
+ dev_err(inno->dev, "failed to enable refpclk\n");
+ clk_disable_unprepare(inno->sysclk);
+ return ret;
+ }
+
+ ret = devm_add_action_or_reset(inno->dev, inno_hdmi_phy_action,
+ inno);
+ if (ret)
+ return ret;
+
+ inno->regmap = devm_regmap_init_mmio(inno->dev, regs,
+ &inno_hdmi_phy_regmap_config);
+ if (IS_ERR(inno->regmap))
+ return PTR_ERR(inno->regmap);
+
+ /* only the newer rk3328 hdmiphy has an interrupt */
+ inno->irq = platform_get_irq(pdev, 0);
+ if (inno->irq > 0) {
+ ret = devm_request_threaded_irq(inno->dev, inno->irq,
+ inno_hdmi_phy_rk3328_hardirq,
+ inno_hdmi_phy_rk3328_irq,
+ IRQF_SHARED,
+ dev_name(inno->dev), inno);
+ if (ret)
+ return ret;
+ }
+
+ inno->phy = devm_phy_create(inno->dev, NULL, &inno_hdmi_phy_ops);
+ if (IS_ERR(inno->phy)) {
+ dev_err(inno->dev, "failed to create HDMI PHY\n");
+ return PTR_ERR(inno->phy);
+ }
+
+ phy_set_drvdata(inno->phy, inno);
+ phy_set_bus_width(inno->phy, 8);
+
+ if (inno->plat_data->ops->init) {
+ ret = inno->plat_data->ops->init(inno);
+ if (ret)
+ return ret;
+ }
+
+ ret = inno_hdmi_phy_clk_register(inno);
+ if (ret)
+ return ret;
+
+ phy_provider = devm_of_phy_provider_register(inno->dev,
+ of_phy_simple_xlate);
+ return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static int inno_hdmi_phy_remove(struct platform_device *pdev)
+{
+ of_clk_del_provider(pdev->dev.of_node);
+
+ return 0;
+}
+
+static const struct of_device_id inno_hdmi_phy_of_match[] = {
+ {
+ .compatible = "rockchip,rk3228-hdmi-phy",
+ .data = &rk3228_hdmi_phy_drv_data
+ }, {
+ .compatible = "rockchip,rk3328-hdmi-phy",
+ .data = &rk3328_hdmi_phy_drv_data
+ }, { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, inno_hdmi_phy_of_match);
+
+static struct platform_driver inno_hdmi_phy_driver = {
+ .probe = inno_hdmi_phy_probe,
+ .remove = inno_hdmi_phy_remove,
+ .driver = {
+ .name = "inno-hdmi-phy",
+ .of_match_table = inno_hdmi_phy_of_match,
+ },
+};
+module_platform_driver(inno_hdmi_phy_driver);
+
+MODULE_AUTHOR("Zheng Yang <zhengyang@rock-chips.com>");
+MODULE_DESCRIPTION("Innosilion HDMI 2.0 Transmitter PHY Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
index 5049dac79bd0..24bd2717abdb 100644
--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
@@ -1116,8 +1116,8 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev)
}
if (of_property_read_u32(np, "reg", &reg)) {
- dev_err(dev, "the reg property is not assigned in %s node\n",
- np->name);
+ dev_err(dev, "the reg property is not assigned in %pOFn node\n",
+ np);
return -EINVAL;
}
@@ -1143,8 +1143,8 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev)
}
if (!rphy->phy_cfg) {
- dev_err(dev, "no phy-config can be matched with %s node\n",
- np->name);
+ dev_err(dev, "no phy-config can be matched with %pOFn node\n",
+ np);
return -EINVAL;
}
diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c
index 76a4b58ec771..c57e496f0b0c 100644
--- a/drivers/phy/rockchip/phy-rockchip-typec.c
+++ b/drivers/phy/rockchip/phy-rockchip-typec.c
@@ -1145,8 +1145,8 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev)
}
if (!tcphy->port_cfgs) {
- dev_err(dev, "no phy-config can be matched with %s node\n",
- np->name);
+ dev_err(dev, "no phy-config can be matched with %pOFn node\n",
+ np);
return -EINVAL;
}
@@ -1186,8 +1186,8 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev)
continue;
if (IS_ERR(phy)) {
- dev_err(dev, "failed to create phy: %s\n",
- child_np->name);
+ dev_err(dev, "failed to create phy: %pOFn\n",
+ child_np);
pm_runtime_disable(dev);
return PTR_ERR(phy);
}
diff --git a/drivers/phy/rockchip/phy-rockchip-usb.c b/drivers/phy/rockchip/phy-rockchip-usb.c
index 3378eeb7a562..b2899c744ad9 100644
--- a/drivers/phy/rockchip/phy-rockchip-usb.c
+++ b/drivers/phy/rockchip/phy-rockchip-usb.c
@@ -36,7 +36,22 @@ static int enable_usb_uart;
#define HIWORD_UPDATE(val, mask) \
((val) | (mask) << 16)
-#define UOC_CON0_SIDDQ BIT(13)
+#define UOC_CON0 0x00
+#define UOC_CON0_SIDDQ BIT(13)
+#define UOC_CON0_DISABLE BIT(4)
+#define UOC_CON0_COMMON_ON_N BIT(0)
+
+#define UOC_CON2 0x08
+#define UOC_CON2_SOFT_CON_SEL BIT(2)
+
+#define UOC_CON3 0x0c
+/* bits present on rk3188 and rk3288 phys */
+#define UOC_CON3_UTMI_TERMSEL_FULLSPEED BIT(5)
+#define UOC_CON3_UTMI_XCVRSEELCT_FSTRANSC (1 << 3)
+#define UOC_CON3_UTMI_XCVRSEELCT_MASK (3 << 3)
+#define UOC_CON3_UTMI_OPMODE_NODRIVING (1 << 1)
+#define UOC_CON3_UTMI_OPMODE_MASK (3 << 1)
+#define UOC_CON3_UTMI_SUSPENDN BIT(0)
struct rockchip_usb_phys {
int reg;
@@ -46,7 +61,8 @@ struct rockchip_usb_phys {
struct rockchip_usb_phy_base;
struct rockchip_usb_phy_pdata {
struct rockchip_usb_phys *phys;
- int (*init_usb_uart)(struct regmap *grf);
+ int (*init_usb_uart)(struct regmap *grf,
+ const struct rockchip_usb_phy_pdata *pdata);
int usb_uart_phy;
};
@@ -208,8 +224,8 @@ static int rockchip_usb_phy_init(struct rockchip_usb_phy_base *base,
rk_phy->np = child;
if (of_property_read_u32(child, "reg", &reg_offset)) {
- dev_err(base->dev, "missing reg property in node %s\n",
- child->name);
+ dev_err(base->dev, "missing reg property in node %pOFn\n",
+ child);
return -EINVAL;
}
@@ -313,28 +329,88 @@ static const struct rockchip_usb_phy_pdata rk3066a_pdata = {
},
};
+static int __init rockchip_init_usb_uart_common(struct regmap *grf,
+ const struct rockchip_usb_phy_pdata *pdata)
+{
+ int regoffs = pdata->phys[pdata->usb_uart_phy].reg;
+ int ret;
+ u32 val;
+
+ /*
+ * COMMON_ON and DISABLE settings are described in the TRM,
+ * but were not present in the original code.
+ * Also disable the analog phy components to save power.
+ */
+ val = HIWORD_UPDATE(UOC_CON0_COMMON_ON_N
+ | UOC_CON0_DISABLE
+ | UOC_CON0_SIDDQ,
+ UOC_CON0_COMMON_ON_N
+ | UOC_CON0_DISABLE
+ | UOC_CON0_SIDDQ);
+ ret = regmap_write(grf, regoffs + UOC_CON0, val);
+ if (ret)
+ return ret;
+
+ val = HIWORD_UPDATE(UOC_CON2_SOFT_CON_SEL,
+ UOC_CON2_SOFT_CON_SEL);
+ ret = regmap_write(grf, regoffs + UOC_CON2, val);
+ if (ret)
+ return ret;
+
+ val = HIWORD_UPDATE(UOC_CON3_UTMI_OPMODE_NODRIVING
+ | UOC_CON3_UTMI_XCVRSEELCT_FSTRANSC
+ | UOC_CON3_UTMI_TERMSEL_FULLSPEED,
+ UOC_CON3_UTMI_SUSPENDN
+ | UOC_CON3_UTMI_OPMODE_MASK
+ | UOC_CON3_UTMI_XCVRSEELCT_MASK
+ | UOC_CON3_UTMI_TERMSEL_FULLSPEED);
+ ret = regmap_write(grf, UOC_CON3, val);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+#define RK3188_UOC0_CON0 0x10c
+#define RK3188_UOC0_CON0_BYPASSSEL BIT(9)
+#define RK3188_UOC0_CON0_BYPASSDMEN BIT(8)
+
+/*
+ * Enable the bypass of uart2 data through the otg usb phy.
+ * See description of rk3288-variant for details.
+ */
+static int __init rk3188_init_usb_uart(struct regmap *grf,
+ const struct rockchip_usb_phy_pdata *pdata)
+{
+ u32 val;
+ int ret;
+
+ ret = rockchip_init_usb_uart_common(grf, pdata);
+ if (ret)
+ return ret;
+
+ val = HIWORD_UPDATE(RK3188_UOC0_CON0_BYPASSSEL
+ | RK3188_UOC0_CON0_BYPASSDMEN,
+ RK3188_UOC0_CON0_BYPASSSEL
+ | RK3188_UOC0_CON0_BYPASSDMEN);
+ ret = regmap_write(grf, RK3188_UOC0_CON0, val);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
static const struct rockchip_usb_phy_pdata rk3188_pdata = {
.phys = (struct rockchip_usb_phys[]){
{ .reg = 0x10c, .pll_name = "sclk_otgphy0_480m" },
{ .reg = 0x11c, .pll_name = "sclk_otgphy1_480m" },
{ /* sentinel */ }
},
+ .init_usb_uart = rk3188_init_usb_uart,
+ .usb_uart_phy = 0,
};
-#define RK3288_UOC0_CON0 0x320
-#define RK3288_UOC0_CON0_COMMON_ON_N BIT(0)
-#define RK3288_UOC0_CON0_DISABLE BIT(4)
-
-#define RK3288_UOC0_CON2 0x328
-#define RK3288_UOC0_CON2_SOFT_CON_SEL BIT(2)
-
#define RK3288_UOC0_CON3 0x32c
-#define RK3288_UOC0_CON3_UTMI_SUSPENDN BIT(0)
-#define RK3288_UOC0_CON3_UTMI_OPMODE_NODRIVING (1 << 1)
-#define RK3288_UOC0_CON3_UTMI_OPMODE_MASK (3 << 1)
-#define RK3288_UOC0_CON3_UTMI_XCVRSEELCT_FSTRANSC (1 << 3)
-#define RK3288_UOC0_CON3_UTMI_XCVRSEELCT_MASK (3 << 3)
-#define RK3288_UOC0_CON3_UTMI_TERMSEL_FULLSPEED BIT(5)
#define RK3288_UOC0_CON3_BYPASSDMEN BIT(6)
#define RK3288_UOC0_CON3_BYPASSSEL BIT(7)
@@ -353,40 +429,13 @@ static const struct rockchip_usb_phy_pdata rk3188_pdata = {
*
* The actual code in the vendor kernel does some things differently.
*/
-static int __init rk3288_init_usb_uart(struct regmap *grf)
+static int __init rk3288_init_usb_uart(struct regmap *grf,
+ const struct rockchip_usb_phy_pdata *pdata)
{
u32 val;
int ret;
- /*
- * COMMON_ON and DISABLE settings are described in the TRM,
- * but were not present in the original code.
- * Also disable the analog phy components to save power.
- */
- val = HIWORD_UPDATE(RK3288_UOC0_CON0_COMMON_ON_N
- | RK3288_UOC0_CON0_DISABLE
- | UOC_CON0_SIDDQ,
- RK3288_UOC0_CON0_COMMON_ON_N
- | RK3288_UOC0_CON0_DISABLE
- | UOC_CON0_SIDDQ);
- ret = regmap_write(grf, RK3288_UOC0_CON0, val);
- if (ret)
- return ret;
-
- val = HIWORD_UPDATE(RK3288_UOC0_CON2_SOFT_CON_SEL,
- RK3288_UOC0_CON2_SOFT_CON_SEL);
- ret = regmap_write(grf, RK3288_UOC0_CON2, val);
- if (ret)
- return ret;
-
- val = HIWORD_UPDATE(RK3288_UOC0_CON3_UTMI_OPMODE_NODRIVING
- | RK3288_UOC0_CON3_UTMI_XCVRSEELCT_FSTRANSC
- | RK3288_UOC0_CON3_UTMI_TERMSEL_FULLSPEED,
- RK3288_UOC0_CON3_UTMI_SUSPENDN
- | RK3288_UOC0_CON3_UTMI_OPMODE_MASK
- | RK3288_UOC0_CON3_UTMI_XCVRSEELCT_MASK
- | RK3288_UOC0_CON3_UTMI_TERMSEL_FULLSPEED);
- ret = regmap_write(grf, RK3288_UOC0_CON3, val);
+ ret = rockchip_init_usb_uart_common(grf, pdata);
if (ret)
return ret;
@@ -516,7 +565,7 @@ static int __init rockchip_init_usb_uart(void)
return PTR_ERR(grf);
}
- ret = data->init_usb_uart(grf);
+ ret = data->init_usb_uart(grf, data);
if (ret) {
pr_err("%s: could not init usb_uart, %d\n", __func__, ret);
enable_usb_uart = 0;
diff --git a/drivers/phy/socionext/Kconfig b/drivers/phy/socionext/Kconfig
new file mode 100644
index 000000000000..467e8147972b
--- /dev/null
+++ b/drivers/phy/socionext/Kconfig
@@ -0,0 +1,34 @@
+#
+# PHY drivers for Socionext platforms.
+#
+
+config PHY_UNIPHIER_USB2
+ tristate "UniPhier USB2 PHY driver"
+ depends on ARCH_UNIPHIER || COMPILE_TEST
+ depends on OF && HAS_IOMEM
+ select GENERIC_PHY
+ select MFD_SYSCON
+ help
+ Enable this to support USB PHY implemented on USB2 controller
+ on UniPhier SoCs. This driver provides interface to interact
+ with USB 2.0 PHY that is part of the UniPhier SoC.
+ In case of Pro4, it is necessary to specify this USB2 PHY instead
+ of USB3 HS-PHY.
+
+config PHY_UNIPHIER_USB3
+ tristate "UniPhier USB3 PHY driver"
+ depends on ARCH_UNIPHIER || COMPILE_TEST
+ depends on OF && HAS_IOMEM
+ select GENERIC_PHY
+ help
+ Enable this to support USB PHY implemented in USB3 controller
+ on UniPhier SoCs. This controller supports USB3.0 and lower speed.
+
+config PHY_UNIPHIER_PCIE
+ tristate "Uniphier PHY driver for PCIe controller"
+ depends on (ARCH_UNIPHIER || COMPILE_TEST) && OF
+ default PCIE_UNIPHIER
+ select GENERIC_PHY
+ help
+ Enable this to support PHY implemented in PCIe controller
+ on UniPhier SoCs. This driver supports LD20 and PXs3 SoCs.
diff --git a/drivers/phy/socionext/Makefile b/drivers/phy/socionext/Makefile
new file mode 100644
index 000000000000..7dc9095b5bb7
--- /dev/null
+++ b/drivers/phy/socionext/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the phy drivers.
+#
+
+obj-$(CONFIG_PHY_UNIPHIER_USB2) += phy-uniphier-usb2.o
+obj-$(CONFIG_PHY_UNIPHIER_USB3) += phy-uniphier-usb3hs.o phy-uniphier-usb3ss.o
+obj-$(CONFIG_PHY_UNIPHIER_PCIE) += phy-uniphier-pcie.o
diff --git a/drivers/phy/socionext/phy-uniphier-pcie.c b/drivers/phy/socionext/phy-uniphier-pcie.c
new file mode 100644
index 000000000000..93ffbd2940fa
--- /dev/null
+++ b/drivers/phy/socionext/phy-uniphier-pcie.c
@@ -0,0 +1,240 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * phy-uniphier-pcie.c - PHY driver for UniPhier PCIe controller
+ * Copyright 2018, Socionext Inc.
+ * Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <linux/resource.h>
+
+/* PHY */
+#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_RESET 0x200c
+#define PCL_PHY_RESET_N_MNMODE BIT(8) /* =1:manual */
+#define PCL_PHY_RESET_N BIT(0) /* =1:deasssert */
+
+/* SG */
+#define SG_USBPCIESEL 0x590
+#define SG_USBPCIESEL_PCIE BIT(0)
+
+#define PCL_PHY_R00 0
+#define RX_EQ_ADJ_EN BIT(3) /* enable for EQ adjustment */
+#define PCL_PHY_R06 6
+#define RX_EQ_ADJ GENMASK(5, 0) /* EQ adjustment value */
+#define RX_EQ_ADJ_VAL 0
+#define PCL_PHY_R26 26
+#define VCO_CTRL GENMASK(7, 4) /* Tx VCO adjustment value */
+#define VCO_CTRL_INIT_VAL 5
+
+struct uniphier_pciephy_priv {
+ void __iomem *base;
+ struct device *dev;
+ struct clk *clk;
+ struct reset_control *rst;
+ const struct uniphier_pciephy_soc_data *data;
+};
+
+struct uniphier_pciephy_soc_data {
+ bool has_syscon;
+};
+
+static void uniphier_pciephy_testio_write(struct uniphier_pciephy_priv *priv,
+ u32 data)
+{
+ /* need to read TESTO twice after accessing TESTI */
+ writel(data, priv->base + PCL_PHY_TEST_I);
+ readl(priv->base + PCL_PHY_TEST_O);
+ readl(priv->base + PCL_PHY_TEST_O);
+}
+
+static void uniphier_pciephy_set_param(struct uniphier_pciephy_priv *priv,
+ u32 reg, u32 mask, u32 param)
+{
+ u32 val;
+
+ /* read previous data */
+ 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);
+
+ /* update value */
+ val &= ~FIELD_PREP(TESTI_DAT_MASK, mask);
+ val = FIELD_PREP(TESTI_DAT_MASK, mask & param);
+ val |= FIELD_PREP(TESTI_ADR_MASK, reg);
+ uniphier_pciephy_testio_write(priv, val);
+ uniphier_pciephy_testio_write(priv, val | TESTI_WR_EN);
+ uniphier_pciephy_testio_write(priv, val);
+
+ /* read current data as dummy */
+ val = FIELD_PREP(TESTI_DAT_MASK, 1);
+ val |= FIELD_PREP(TESTI_ADR_MASK, reg);
+ uniphier_pciephy_testio_write(priv, val);
+ readl(priv->base + PCL_PHY_TEST_O);
+}
+
+static void uniphier_pciephy_assert(struct uniphier_pciephy_priv *priv)
+{
+ u32 val;
+
+ val = readl(priv->base + PCL_PHY_RESET);
+ val &= ~PCL_PHY_RESET_N;
+ val |= PCL_PHY_RESET_N_MNMODE;
+ writel(val, priv->base + PCL_PHY_RESET);
+}
+
+static void uniphier_pciephy_deassert(struct uniphier_pciephy_priv *priv)
+{
+ u32 val;
+
+ val = readl(priv->base + PCL_PHY_RESET);
+ val |= PCL_PHY_RESET_N_MNMODE | PCL_PHY_RESET_N;
+ writel(val, priv->base + PCL_PHY_RESET);
+}
+
+static int uniphier_pciephy_init(struct phy *phy)
+{
+ struct uniphier_pciephy_priv *priv = phy_get_drvdata(phy);
+ int ret;
+
+ ret = clk_prepare_enable(priv->clk);
+ if (ret)
+ return ret;
+
+ ret = reset_control_deassert(priv->rst);
+ if (ret)
+ goto out_clk_disable;
+
+ uniphier_pciephy_set_param(priv, PCL_PHY_R00,
+ RX_EQ_ADJ_EN, RX_EQ_ADJ_EN);
+ uniphier_pciephy_set_param(priv, PCL_PHY_R06, RX_EQ_ADJ,
+ FIELD_PREP(RX_EQ_ADJ, RX_EQ_ADJ_VAL));
+ uniphier_pciephy_set_param(priv, PCL_PHY_R26, VCO_CTRL,
+ FIELD_PREP(VCO_CTRL, VCO_CTRL_INIT_VAL));
+ usleep_range(1, 10);
+
+ uniphier_pciephy_deassert(priv);
+ usleep_range(1, 10);
+
+ return 0;
+
+out_clk_disable:
+ clk_disable_unprepare(priv->clk);
+
+ return ret;
+}
+
+static int uniphier_pciephy_exit(struct phy *phy)
+{
+ struct uniphier_pciephy_priv *priv = phy_get_drvdata(phy);
+
+ uniphier_pciephy_assert(priv);
+ reset_control_assert(priv->rst);
+ clk_disable_unprepare(priv->clk);
+
+ return 0;
+}
+
+static const struct phy_ops uniphier_pciephy_ops = {
+ .init = uniphier_pciephy_init,
+ .exit = uniphier_pciephy_exit,
+ .owner = THIS_MODULE,
+};
+
+static int uniphier_pciephy_probe(struct platform_device *pdev)
+{
+ struct uniphier_pciephy_priv *priv;
+ struct phy_provider *phy_provider;
+ struct device *dev = &pdev->dev;
+ struct regmap *regmap;
+ struct resource *res;
+ struct phy *phy;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->data = of_device_get_match_data(dev);
+ if (WARN_ON(!priv->data))
+ return -EINVAL;
+
+ priv->dev = dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ priv->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(priv->clk))
+ return PTR_ERR(priv->clk);
+
+ priv->rst = devm_reset_control_get_shared(dev, NULL);
+ if (IS_ERR(priv->rst))
+ return PTR_ERR(priv->rst);
+
+ phy = devm_phy_create(dev, dev->of_node, &uniphier_pciephy_ops);
+ if (IS_ERR(phy))
+ return PTR_ERR(phy);
+
+ regmap = syscon_regmap_lookup_by_phandle(dev->of_node,
+ "socionext,syscon");
+ if (!IS_ERR(regmap) && priv->data->has_syscon)
+ regmap_update_bits(regmap, SG_USBPCIESEL,
+ SG_USBPCIESEL_PCIE, SG_USBPCIESEL_PCIE);
+
+ phy_set_drvdata(phy, priv);
+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+
+ return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static const struct uniphier_pciephy_soc_data uniphier_ld20_data = {
+ .has_syscon = true,
+};
+
+static const struct uniphier_pciephy_soc_data uniphier_pxs3_data = {
+ .has_syscon = false,
+};
+
+static const struct of_device_id uniphier_pciephy_match[] = {
+ {
+ .compatible = "socionext,uniphier-ld20-pcie-phy",
+ .data = &uniphier_ld20_data,
+ },
+ {
+ .compatible = "socionext,uniphier-pxs3-pcie-phy",
+ .data = &uniphier_pxs3_data,
+ },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, uniphier_pciephy_match);
+
+static struct platform_driver uniphier_pciephy_driver = {
+ .probe = uniphier_pciephy_probe,
+ .driver = {
+ .name = "uniphier-pcie-phy",
+ .of_match_table = uniphier_pciephy_match,
+ },
+};
+module_platform_driver(uniphier_pciephy_driver);
+
+MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
+MODULE_DESCRIPTION("UniPhier PHY driver for PCIe controller");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/socionext/phy-uniphier-usb2.c b/drivers/phy/socionext/phy-uniphier-usb2.c
new file mode 100644
index 000000000000..3f2086ed4fe4
--- /dev/null
+++ b/drivers/phy/socionext/phy-uniphier-usb2.c
@@ -0,0 +1,244 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * phy-uniphier-usb2.c - PHY driver for UniPhier USB2 controller
+ * Copyright 2015-2018 Socionext Inc.
+ * Author:
+ * Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
+ */
+
+#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/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+#define SG_USBPHY1CTRL 0x500
+#define SG_USBPHY1CTRL2 0x504
+#define SG_USBPHY2CTRL 0x508
+#define SG_USBPHY2CTRL2 0x50c /* LD11 */
+#define SG_USBPHY12PLL 0x50c /* Pro4 */
+#define SG_USBPHY3CTRL 0x510
+#define SG_USBPHY3CTRL2 0x514
+#define SG_USBPHY4CTRL 0x518 /* Pro4 */
+#define SG_USBPHY4CTRL2 0x51c /* Pro4 */
+#define SG_USBPHY34PLL 0x51c /* Pro4 */
+
+struct uniphier_u2phy_param {
+ u32 offset;
+ u32 value;
+};
+
+struct uniphier_u2phy_soc_data {
+ struct uniphier_u2phy_param config0;
+ struct uniphier_u2phy_param config1;
+};
+
+struct uniphier_u2phy_priv {
+ struct regmap *regmap;
+ struct phy *phy;
+ struct regulator *vbus;
+ const struct uniphier_u2phy_soc_data *data;
+ struct uniphier_u2phy_priv *next;
+};
+
+static int uniphier_u2phy_power_on(struct phy *phy)
+{
+ struct uniphier_u2phy_priv *priv = phy_get_drvdata(phy);
+ int ret = 0;
+
+ if (priv->vbus)
+ ret = regulator_enable(priv->vbus);
+
+ return ret;
+}
+
+static int uniphier_u2phy_power_off(struct phy *phy)
+{
+ struct uniphier_u2phy_priv *priv = phy_get_drvdata(phy);
+
+ if (priv->vbus)
+ regulator_disable(priv->vbus);
+
+ return 0;
+}
+
+static int uniphier_u2phy_init(struct phy *phy)
+{
+ struct uniphier_u2phy_priv *priv = phy_get_drvdata(phy);
+
+ if (!priv->data)
+ return 0;
+
+ regmap_write(priv->regmap, priv->data->config0.offset,
+ priv->data->config0.value);
+ regmap_write(priv->regmap, priv->data->config1.offset,
+ priv->data->config1.value);
+
+ return 0;
+}
+
+static struct phy *uniphier_u2phy_xlate(struct device *dev,
+ struct of_phandle_args *args)
+{
+ struct uniphier_u2phy_priv *priv = dev_get_drvdata(dev);
+
+ while (priv && args->np != priv->phy->dev.of_node)
+ priv = priv->next;
+
+ if (!priv) {
+ dev_err(dev, "Failed to find appropriate phy\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ return priv->phy;
+}
+
+static const struct phy_ops uniphier_u2phy_ops = {
+ .init = uniphier_u2phy_init,
+ .power_on = uniphier_u2phy_power_on,
+ .power_off = uniphier_u2phy_power_off,
+ .owner = THIS_MODULE,
+};
+
+static int uniphier_u2phy_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *parent, *child;
+ struct uniphier_u2phy_priv *priv = NULL, *next = NULL;
+ struct phy_provider *phy_provider;
+ struct regmap *regmap;
+ const struct uniphier_u2phy_soc_data *data;
+ int ret, data_idx, ndatas;
+
+ data = of_device_get_match_data(dev);
+ if (WARN_ON(!data))
+ return -EINVAL;
+
+ /* get number of data */
+ for (ndatas = 0; data[ndatas].config0.offset; ndatas++)
+ ;
+
+ parent = of_get_parent(dev->of_node);
+ regmap = syscon_node_to_regmap(parent);
+ of_node_put(parent);
+ if (IS_ERR(regmap)) {
+ dev_err(dev, "Failed to get regmap\n");
+ return PTR_ERR(regmap);
+ }
+
+ for_each_child_of_node(dev->of_node, child) {
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ ret = -ENOMEM;
+ goto out_put_child;
+ }
+ priv->regmap = regmap;
+
+ priv->vbus = devm_regulator_get_optional(dev, "vbus");
+ if (IS_ERR(priv->vbus)) {
+ if (PTR_ERR(priv->vbus) == -EPROBE_DEFER) {
+ ret = PTR_ERR(priv->vbus);
+ goto out_put_child;
+ }
+ priv->vbus = NULL;
+ }
+
+ priv->phy = devm_phy_create(dev, child, &uniphier_u2phy_ops);
+ if (IS_ERR(priv->phy)) {
+ dev_err(dev, "Failed to create phy\n");
+ ret = PTR_ERR(priv->phy);
+ goto out_put_child;
+ }
+
+ ret = of_property_read_u32(child, "reg", &data_idx);
+ if (ret) {
+ dev_err(dev, "Failed to get reg property\n");
+ goto out_put_child;
+ }
+
+ if (data_idx < ndatas)
+ priv->data = &data[data_idx];
+ else
+ dev_warn(dev, "No phy configuration: %s\n",
+ child->full_name);
+
+ phy_set_drvdata(priv->phy, priv);
+ priv->next = next;
+ next = priv;
+ }
+
+ dev_set_drvdata(dev, priv);
+ phy_provider = devm_of_phy_provider_register(dev,
+ uniphier_u2phy_xlate);
+ return PTR_ERR_OR_ZERO(phy_provider);
+
+out_put_child:
+ of_node_put(child);
+
+ return ret;
+}
+
+static const struct uniphier_u2phy_soc_data uniphier_pro4_data[] = {
+ {
+ .config0 = { SG_USBPHY1CTRL, 0x05142400 },
+ .config1 = { SG_USBPHY12PLL, 0x00010010 },
+ },
+ {
+ .config0 = { SG_USBPHY2CTRL, 0x05142400 },
+ .config1 = { SG_USBPHY12PLL, 0x00010010 },
+ },
+ {
+ .config0 = { SG_USBPHY3CTRL, 0x05142400 },
+ .config1 = { SG_USBPHY34PLL, 0x00010010 },
+ },
+ {
+ .config0 = { SG_USBPHY4CTRL, 0x05142400 },
+ .config1 = { SG_USBPHY34PLL, 0x00010010 },
+ },
+ { /* sentinel */ }
+};
+
+static const struct uniphier_u2phy_soc_data uniphier_ld11_data[] = {
+ {
+ .config0 = { SG_USBPHY1CTRL, 0x82280000 },
+ .config1 = { SG_USBPHY1CTRL2, 0x00000106 },
+ },
+ {
+ .config0 = { SG_USBPHY2CTRL, 0x82280000 },
+ .config1 = { SG_USBPHY2CTRL2, 0x00000106 },
+ },
+ {
+ .config0 = { SG_USBPHY3CTRL, 0x82280000 },
+ .config1 = { SG_USBPHY3CTRL2, 0x00000106 },
+ },
+ { /* sentinel */ }
+};
+
+static const struct of_device_id uniphier_u2phy_match[] = {
+ {
+ .compatible = "socionext,uniphier-pro4-usb2-phy",
+ .data = &uniphier_pro4_data,
+ },
+ {
+ .compatible = "socionext,uniphier-ld11-usb2-phy",
+ .data = &uniphier_ld11_data,
+ },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, uniphier_u2phy_match);
+
+static struct platform_driver uniphier_u2phy_driver = {
+ .probe = uniphier_u2phy_probe,
+ .driver = {
+ .name = "uniphier-usb2-phy",
+ .of_match_table = uniphier_u2phy_match,
+ },
+};
+module_platform_driver(uniphier_u2phy_driver);
+
+MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
+MODULE_DESCRIPTION("UniPhier PHY driver for USB2 controller");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/socionext/phy-uniphier-usb3hs.c b/drivers/phy/socionext/phy-uniphier-usb3hs.c
new file mode 100644
index 000000000000..b1b048be6166
--- /dev/null
+++ b/drivers/phy/socionext/phy-uniphier-usb3hs.c
@@ -0,0 +1,422 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * phy-uniphier-usb3hs.c - HS-PHY driver for Socionext UniPhier USB3 controller
+ * Copyright 2015-2018 Socionext Inc.
+ * Author:
+ * Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
+ * Contributors:
+ * Motoya Tanigawa <tanigawa.motoya@socionext.com>
+ * Masami Hiramatsu <masami.hiramatsu@linaro.org>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+
+#define HSPHY_CFG0 0x0
+#define HSPHY_CFG0_HS_I_MASK GENMASK(31, 28)
+#define HSPHY_CFG0_HSDISC_MASK GENMASK(27, 26)
+#define HSPHY_CFG0_SWING_MASK GENMASK(17, 16)
+#define HSPHY_CFG0_SEL_T_MASK GENMASK(15, 12)
+#define HSPHY_CFG0_RTERM_MASK GENMASK(7, 6)
+#define HSPHY_CFG0_TRIMMASK (HSPHY_CFG0_HS_I_MASK \
+ | HSPHY_CFG0_SEL_T_MASK \
+ | HSPHY_CFG0_RTERM_MASK)
+
+#define HSPHY_CFG1 0x4
+#define HSPHY_CFG1_DAT_EN BIT(29)
+#define HSPHY_CFG1_ADR_EN BIT(28)
+#define HSPHY_CFG1_ADR_MASK GENMASK(27, 16)
+#define HSPHY_CFG1_DAT_MASK GENMASK(23, 16)
+
+#define PHY_F(regno, msb, lsb) { (regno), (msb), (lsb) }
+
+#define LS_SLEW PHY_F(10, 6, 6) /* LS mode slew rate */
+#define FS_LS_DRV PHY_F(10, 5, 5) /* FS/LS slew rate */
+
+#define MAX_PHY_PARAMS 2
+
+struct uniphier_u3hsphy_param {
+ struct {
+ int reg_no;
+ int msb;
+ int lsb;
+ } field;
+ u8 value;
+};
+
+struct uniphier_u3hsphy_trim_param {
+ unsigned int rterm;
+ unsigned int sel_t;
+ unsigned int hs_i;
+};
+
+#define trim_param_is_valid(p) ((p)->rterm || (p)->sel_t || (p)->hs_i)
+
+struct uniphier_u3hsphy_priv {
+ struct device *dev;
+ void __iomem *base;
+ struct clk *clk, *clk_parent, *clk_ext;
+ struct reset_control *rst, *rst_parent;
+ struct regulator *vbus;
+ const struct uniphier_u3hsphy_soc_data *data;
+};
+
+struct uniphier_u3hsphy_soc_data {
+ int nparams;
+ const struct uniphier_u3hsphy_param param[MAX_PHY_PARAMS];
+ u32 config0;
+ u32 config1;
+ void (*trim_func)(struct uniphier_u3hsphy_priv *priv, u32 *pconfig,
+ struct uniphier_u3hsphy_trim_param *pt);
+};
+
+static void uniphier_u3hsphy_trim_ld20(struct uniphier_u3hsphy_priv *priv,
+ u32 *pconfig,
+ struct uniphier_u3hsphy_trim_param *pt)
+{
+ *pconfig &= ~HSPHY_CFG0_RTERM_MASK;
+ *pconfig |= FIELD_PREP(HSPHY_CFG0_RTERM_MASK, pt->rterm);
+
+ *pconfig &= ~HSPHY_CFG0_SEL_T_MASK;
+ *pconfig |= FIELD_PREP(HSPHY_CFG0_SEL_T_MASK, pt->sel_t);
+
+ *pconfig &= ~HSPHY_CFG0_HS_I_MASK;
+ *pconfig |= FIELD_PREP(HSPHY_CFG0_HS_I_MASK, pt->hs_i);
+}
+
+static int uniphier_u3hsphy_get_nvparam(struct uniphier_u3hsphy_priv *priv,
+ const char *name, unsigned int *val)
+{
+ struct nvmem_cell *cell;
+ u8 *buf;
+
+ cell = devm_nvmem_cell_get(priv->dev, name);
+ if (IS_ERR(cell))
+ return PTR_ERR(cell);
+
+ buf = nvmem_cell_read(cell, NULL);
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
+
+ *val = *buf;
+
+ kfree(buf);
+
+ return 0;
+}
+
+static int uniphier_u3hsphy_get_nvparams(struct uniphier_u3hsphy_priv *priv,
+ struct uniphier_u3hsphy_trim_param *pt)
+{
+ int ret;
+
+ ret = uniphier_u3hsphy_get_nvparam(priv, "rterm", &pt->rterm);
+ if (ret)
+ return ret;
+
+ ret = uniphier_u3hsphy_get_nvparam(priv, "sel_t", &pt->sel_t);
+ if (ret)
+ return ret;
+
+ ret = uniphier_u3hsphy_get_nvparam(priv, "hs_i", &pt->hs_i);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int uniphier_u3hsphy_update_config(struct uniphier_u3hsphy_priv *priv,
+ u32 *pconfig)
+{
+ struct uniphier_u3hsphy_trim_param trim;
+ int ret, trimmed = 0;
+
+ if (priv->data->trim_func) {
+ ret = uniphier_u3hsphy_get_nvparams(priv, &trim);
+ if (ret == -EPROBE_DEFER)
+ return ret;
+
+ /*
+ * call trim_func only when trimming parameters that aren't
+ * all-zero can be acquired. All-zero parameters mean nothing
+ * has been written to nvmem.
+ */
+ if (!ret && trim_param_is_valid(&trim)) {
+ priv->data->trim_func(priv, pconfig, &trim);
+ trimmed = 1;
+ } else {
+ dev_dbg(priv->dev, "can't get parameter from nvmem\n");
+ }
+ }
+
+ /* use default parameters without trimming values */
+ if (!trimmed) {
+ *pconfig &= ~HSPHY_CFG0_HSDISC_MASK;
+ *pconfig |= FIELD_PREP(HSPHY_CFG0_HSDISC_MASK, 3);
+ }
+
+ return 0;
+}
+
+static void uniphier_u3hsphy_set_param(struct uniphier_u3hsphy_priv *priv,
+ const struct uniphier_u3hsphy_param *p)
+{
+ u32 val;
+ u32 field_mask = GENMASK(p->field.msb, p->field.lsb);
+ u8 data;
+
+ val = readl(priv->base + HSPHY_CFG1);
+ val &= ~HSPHY_CFG1_ADR_MASK;
+ val |= FIELD_PREP(HSPHY_CFG1_ADR_MASK, p->field.reg_no)
+ | HSPHY_CFG1_ADR_EN;
+ writel(val, priv->base + HSPHY_CFG1);
+
+ val = readl(priv->base + HSPHY_CFG1);
+ val &= ~HSPHY_CFG1_ADR_EN;
+ writel(val, priv->base + HSPHY_CFG1);
+
+ val = readl(priv->base + HSPHY_CFG1);
+ val &= ~FIELD_PREP(HSPHY_CFG1_DAT_MASK, field_mask);
+ data = field_mask & (p->value << p->field.lsb);
+ val |= FIELD_PREP(HSPHY_CFG1_DAT_MASK, data) | HSPHY_CFG1_DAT_EN;
+ writel(val, priv->base + HSPHY_CFG1);
+
+ val = readl(priv->base + HSPHY_CFG1);
+ val &= ~HSPHY_CFG1_DAT_EN;
+ writel(val, priv->base + HSPHY_CFG1);
+}
+
+static int uniphier_u3hsphy_power_on(struct phy *phy)
+{
+ struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy);
+ int ret;
+
+ ret = clk_prepare_enable(priv->clk_ext);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(priv->clk);
+ if (ret)
+ goto out_clk_ext_disable;
+
+ ret = reset_control_deassert(priv->rst);
+ if (ret)
+ goto out_clk_disable;
+
+ if (priv->vbus) {
+ ret = regulator_enable(priv->vbus);
+ if (ret)
+ goto out_rst_assert;
+ }
+
+ return 0;
+
+out_rst_assert:
+ reset_control_assert(priv->rst);
+out_clk_disable:
+ clk_disable_unprepare(priv->clk);
+out_clk_ext_disable:
+ clk_disable_unprepare(priv->clk_ext);
+
+ return ret;
+}
+
+static int uniphier_u3hsphy_power_off(struct phy *phy)
+{
+ struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy);
+
+ if (priv->vbus)
+ regulator_disable(priv->vbus);
+
+ reset_control_assert(priv->rst);
+ clk_disable_unprepare(priv->clk);
+ clk_disable_unprepare(priv->clk_ext);
+
+ return 0;
+}
+
+static int uniphier_u3hsphy_init(struct phy *phy)
+{
+ struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy);
+ u32 config0, config1;
+ int i, ret;
+
+ ret = clk_prepare_enable(priv->clk_parent);
+ if (ret)
+ return ret;
+
+ ret = reset_control_deassert(priv->rst_parent);
+ if (ret)
+ goto out_clk_disable;
+
+ if (!priv->data->config0 && !priv->data->config1)
+ return 0;
+
+ config0 = priv->data->config0;
+ config1 = priv->data->config1;
+
+ ret = uniphier_u3hsphy_update_config(priv, &config0);
+ if (ret)
+ goto out_rst_assert;
+
+ writel(config0, priv->base + HSPHY_CFG0);
+ writel(config1, priv->base + HSPHY_CFG1);
+
+ for (i = 0; i < priv->data->nparams; i++)
+ uniphier_u3hsphy_set_param(priv, &priv->data->param[i]);
+
+ return 0;
+
+out_rst_assert:
+ reset_control_assert(priv->rst_parent);
+out_clk_disable:
+ clk_disable_unprepare(priv->clk_parent);
+
+ return ret;
+}
+
+static int uniphier_u3hsphy_exit(struct phy *phy)
+{
+ struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy);
+
+ reset_control_assert(priv->rst_parent);
+ clk_disable_unprepare(priv->clk_parent);
+
+ return 0;
+}
+
+static const struct phy_ops uniphier_u3hsphy_ops = {
+ .init = uniphier_u3hsphy_init,
+ .exit = uniphier_u3hsphy_exit,
+ .power_on = uniphier_u3hsphy_power_on,
+ .power_off = uniphier_u3hsphy_power_off,
+ .owner = THIS_MODULE,
+};
+
+static int uniphier_u3hsphy_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct uniphier_u3hsphy_priv *priv;
+ struct phy_provider *phy_provider;
+ struct resource *res;
+ struct phy *phy;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->dev = dev;
+ priv->data = of_device_get_match_data(dev);
+ if (WARN_ON(!priv->data ||
+ priv->data->nparams > MAX_PHY_PARAMS))
+ return -EINVAL;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ priv->clk = devm_clk_get(dev, "phy");
+ if (IS_ERR(priv->clk))
+ return PTR_ERR(priv->clk);
+
+ priv->clk_parent = devm_clk_get(dev, "link");
+ if (IS_ERR(priv->clk_parent))
+ return PTR_ERR(priv->clk_parent);
+
+ priv->clk_ext = devm_clk_get(dev, "phy-ext");
+ if (IS_ERR(priv->clk_ext)) {
+ if (PTR_ERR(priv->clk_ext) == -ENOENT)
+ priv->clk_ext = NULL;
+ else
+ return PTR_ERR(priv->clk_ext);
+ }
+
+ priv->rst = devm_reset_control_get_shared(dev, "phy");
+ if (IS_ERR(priv->rst))
+ return PTR_ERR(priv->rst);
+
+ priv->rst_parent = devm_reset_control_get_shared(dev, "link");
+ if (IS_ERR(priv->rst_parent))
+ return PTR_ERR(priv->rst_parent);
+
+ priv->vbus = devm_regulator_get_optional(dev, "vbus");
+ if (IS_ERR(priv->vbus)) {
+ if (PTR_ERR(priv->vbus) == -EPROBE_DEFER)
+ return PTR_ERR(priv->vbus);
+ priv->vbus = NULL;
+ }
+
+ phy = devm_phy_create(dev, dev->of_node, &uniphier_u3hsphy_ops);
+ if (IS_ERR(phy))
+ return PTR_ERR(phy);
+
+ phy_set_drvdata(phy, priv);
+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+
+ return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static const struct uniphier_u3hsphy_soc_data uniphier_pxs2_data = {
+ .nparams = 0,
+};
+
+static const struct uniphier_u3hsphy_soc_data uniphier_ld20_data = {
+ .nparams = 2,
+ .param = {
+ { LS_SLEW, 1 },
+ { FS_LS_DRV, 1 },
+ },
+ .trim_func = uniphier_u3hsphy_trim_ld20,
+ .config0 = 0x92316680,
+ .config1 = 0x00000106,
+};
+
+static const struct uniphier_u3hsphy_soc_data uniphier_pxs3_data = {
+ .nparams = 0,
+ .trim_func = uniphier_u3hsphy_trim_ld20,
+ .config0 = 0x92316680,
+ .config1 = 0x00000106,
+};
+
+static const struct of_device_id uniphier_u3hsphy_match[] = {
+ {
+ .compatible = "socionext,uniphier-pxs2-usb3-hsphy",
+ .data = &uniphier_pxs2_data,
+ },
+ {
+ .compatible = "socionext,uniphier-ld20-usb3-hsphy",
+ .data = &uniphier_ld20_data,
+ },
+ {
+ .compatible = "socionext,uniphier-pxs3-usb3-hsphy",
+ .data = &uniphier_pxs3_data,
+ },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, uniphier_u3hsphy_match);
+
+static struct platform_driver uniphier_u3hsphy_driver = {
+ .probe = uniphier_u3hsphy_probe,
+ .driver = {
+ .name = "uniphier-usb3-hsphy",
+ .of_match_table = uniphier_u3hsphy_match,
+ },
+};
+
+module_platform_driver(uniphier_u3hsphy_driver);
+
+MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
+MODULE_DESCRIPTION("UniPhier HS-PHY driver for USB3 controller");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/socionext/phy-uniphier-usb3ss.c b/drivers/phy/socionext/phy-uniphier-usb3ss.c
new file mode 100644
index 000000000000..4be95679c7d8
--- /dev/null
+++ b/drivers/phy/socionext/phy-uniphier-usb3ss.c
@@ -0,0 +1,349 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * phy-uniphier-usb3ss.c - SS-PHY driver for Socionext UniPhier USB3 controller
+ * Copyright 2015-2018 Socionext Inc.
+ * Author:
+ * Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
+ * Contributors:
+ * Motoya Tanigawa <tanigawa.motoya@socionext.com>
+ * Masami Hiramatsu <masami.hiramatsu@linaro.org>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/io.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/regulator/consumer.h>
+#include <linux/reset.h>
+
+#define SSPHY_TESTI 0x0
+#define SSPHY_TESTO 0x4
+#define TESTI_DAT_MASK GENMASK(13, 6)
+#define TESTI_ADR_MASK GENMASK(5, 1)
+#define TESTI_WR_EN BIT(0)
+
+#define PHY_F(regno, msb, lsb) { (regno), (msb), (lsb) }
+
+#define CDR_CPD_TRIM PHY_F(7, 3, 0) /* RxPLL charge pump current */
+#define CDR_CPF_TRIM PHY_F(8, 3, 0) /* RxPLL charge pump current 2 */
+#define TX_PLL_TRIM PHY_F(9, 3, 0) /* TxPLL charge pump current */
+#define BGAP_TRIM PHY_F(11, 3, 0) /* Bandgap voltage */
+#define CDR_TRIM PHY_F(13, 6, 5) /* Clock Data Recovery setting */
+#define VCO_CTRL PHY_F(26, 7, 4) /* VCO control */
+#define VCOPLL_CTRL PHY_F(27, 2, 0) /* TxPLL VCO tuning */
+#define VCOPLL_CM PHY_F(28, 1, 0) /* TxPLL voltage */
+
+#define MAX_PHY_PARAMS 7
+
+struct uniphier_u3ssphy_param {
+ struct {
+ int reg_no;
+ int msb;
+ int lsb;
+ } field;
+ u8 value;
+};
+
+struct uniphier_u3ssphy_priv {
+ struct device *dev;
+ void __iomem *base;
+ struct clk *clk, *clk_ext, *clk_parent, *clk_parent_gio;
+ struct reset_control *rst, *rst_parent, *rst_parent_gio;
+ struct regulator *vbus;
+ const struct uniphier_u3ssphy_soc_data *data;
+};
+
+struct uniphier_u3ssphy_soc_data {
+ bool is_legacy;
+ int nparams;
+ const struct uniphier_u3ssphy_param param[MAX_PHY_PARAMS];
+};
+
+static void uniphier_u3ssphy_testio_write(struct uniphier_u3ssphy_priv *priv,
+ u32 data)
+{
+ /* need to read TESTO twice after accessing TESTI */
+ writel(data, priv->base + SSPHY_TESTI);
+ readl(priv->base + SSPHY_TESTO);
+ readl(priv->base + SSPHY_TESTO);
+}
+
+static void uniphier_u3ssphy_set_param(struct uniphier_u3ssphy_priv *priv,
+ const struct uniphier_u3ssphy_param *p)
+{
+ u32 val;
+ u8 field_mask = GENMASK(p->field.msb, p->field.lsb);
+ u8 data;
+
+ /* read previous data */
+ val = FIELD_PREP(TESTI_DAT_MASK, 1);
+ val |= FIELD_PREP(TESTI_ADR_MASK, p->field.reg_no);
+ uniphier_u3ssphy_testio_write(priv, val);
+ val = readl(priv->base + SSPHY_TESTO);
+
+ /* update value */
+ val &= ~FIELD_PREP(TESTI_DAT_MASK, field_mask);
+ data = field_mask & (p->value << p->field.lsb);
+ val = FIELD_PREP(TESTI_DAT_MASK, data);
+ val |= FIELD_PREP(TESTI_ADR_MASK, p->field.reg_no);
+ uniphier_u3ssphy_testio_write(priv, val);
+ uniphier_u3ssphy_testio_write(priv, val | TESTI_WR_EN);
+ uniphier_u3ssphy_testio_write(priv, val);
+
+ /* read current data as dummy */
+ val = FIELD_PREP(TESTI_DAT_MASK, 1);
+ val |= FIELD_PREP(TESTI_ADR_MASK, p->field.reg_no);
+ uniphier_u3ssphy_testio_write(priv, val);
+ readl(priv->base + SSPHY_TESTO);
+}
+
+static int uniphier_u3ssphy_power_on(struct phy *phy)
+{
+ struct uniphier_u3ssphy_priv *priv = phy_get_drvdata(phy);
+ int ret;
+
+ ret = clk_prepare_enable(priv->clk_ext);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(priv->clk);
+ if (ret)
+ goto out_clk_ext_disable;
+
+ ret = reset_control_deassert(priv->rst);
+ if (ret)
+ goto out_clk_disable;
+
+ if (priv->vbus) {
+ ret = regulator_enable(priv->vbus);
+ if (ret)
+ goto out_rst_assert;
+ }
+
+ return 0;
+
+out_rst_assert:
+ reset_control_assert(priv->rst);
+out_clk_disable:
+ clk_disable_unprepare(priv->clk);
+out_clk_ext_disable:
+ clk_disable_unprepare(priv->clk_ext);
+
+ return ret;
+}
+
+static int uniphier_u3ssphy_power_off(struct phy *phy)
+{
+ struct uniphier_u3ssphy_priv *priv = phy_get_drvdata(phy);
+
+ if (priv->vbus)
+ regulator_disable(priv->vbus);
+
+ reset_control_assert(priv->rst);
+ clk_disable_unprepare(priv->clk);
+ clk_disable_unprepare(priv->clk_ext);
+
+ return 0;
+}
+
+static int uniphier_u3ssphy_init(struct phy *phy)
+{
+ struct uniphier_u3ssphy_priv *priv = phy_get_drvdata(phy);
+ int i, ret;
+
+ ret = clk_prepare_enable(priv->clk_parent);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(priv->clk_parent_gio);
+ if (ret)
+ goto out_clk_disable;
+
+ ret = reset_control_deassert(priv->rst_parent);
+ if (ret)
+ goto out_clk_gio_disable;
+
+ ret = reset_control_deassert(priv->rst_parent_gio);
+ if (ret)
+ goto out_rst_assert;
+
+ if (priv->data->is_legacy)
+ return 0;
+
+ for (i = 0; i < priv->data->nparams; i++)
+ uniphier_u3ssphy_set_param(priv, &priv->data->param[i]);
+
+ return 0;
+
+out_rst_assert:
+ reset_control_assert(priv->rst_parent);
+out_clk_gio_disable:
+ clk_disable_unprepare(priv->clk_parent_gio);
+out_clk_disable:
+ clk_disable_unprepare(priv->clk_parent);
+
+ return ret;
+}
+
+static int uniphier_u3ssphy_exit(struct phy *phy)
+{
+ struct uniphier_u3ssphy_priv *priv = phy_get_drvdata(phy);
+
+ reset_control_assert(priv->rst_parent_gio);
+ reset_control_assert(priv->rst_parent);
+ clk_disable_unprepare(priv->clk_parent_gio);
+ clk_disable_unprepare(priv->clk_parent);
+
+ return 0;
+}
+
+static const struct phy_ops uniphier_u3ssphy_ops = {
+ .init = uniphier_u3ssphy_init,
+ .exit = uniphier_u3ssphy_exit,
+ .power_on = uniphier_u3ssphy_power_on,
+ .power_off = uniphier_u3ssphy_power_off,
+ .owner = THIS_MODULE,
+};
+
+static int uniphier_u3ssphy_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct uniphier_u3ssphy_priv *priv;
+ struct phy_provider *phy_provider;
+ struct resource *res;
+ struct phy *phy;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->dev = dev;
+ priv->data = of_device_get_match_data(dev);
+ if (WARN_ON(!priv->data ||
+ priv->data->nparams > MAX_PHY_PARAMS))
+ return -EINVAL;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ if (!priv->data->is_legacy) {
+ priv->clk = devm_clk_get(dev, "phy");
+ if (IS_ERR(priv->clk))
+ return PTR_ERR(priv->clk);
+
+ priv->clk_ext = devm_clk_get(dev, "phy-ext");
+ if (IS_ERR(priv->clk_ext)) {
+ if (PTR_ERR(priv->clk_ext) == -ENOENT)
+ priv->clk_ext = NULL;
+ else
+ return PTR_ERR(priv->clk_ext);
+ }
+
+ priv->rst = devm_reset_control_get_shared(dev, "phy");
+ if (IS_ERR(priv->rst))
+ return PTR_ERR(priv->rst);
+ } else {
+ priv->clk_parent_gio = devm_clk_get(dev, "gio");
+ if (IS_ERR(priv->clk_parent_gio))
+ return PTR_ERR(priv->clk_parent_gio);
+
+ priv->rst_parent_gio =
+ devm_reset_control_get_shared(dev, "gio");
+ if (IS_ERR(priv->rst_parent_gio))
+ return PTR_ERR(priv->rst_parent_gio);
+ }
+
+ priv->clk_parent = devm_clk_get(dev, "link");
+ if (IS_ERR(priv->clk_parent))
+ return PTR_ERR(priv->clk_parent);
+
+ priv->rst_parent = devm_reset_control_get_shared(dev, "link");
+ if (IS_ERR(priv->rst_parent))
+ return PTR_ERR(priv->rst_parent);
+
+ priv->vbus = devm_regulator_get_optional(dev, "vbus");
+ if (IS_ERR(priv->vbus)) {
+ if (PTR_ERR(priv->vbus) == -EPROBE_DEFER)
+ return PTR_ERR(priv->vbus);
+ priv->vbus = NULL;
+ }
+
+ phy = devm_phy_create(dev, dev->of_node, &uniphier_u3ssphy_ops);
+ if (IS_ERR(phy))
+ return PTR_ERR(phy);
+
+ phy_set_drvdata(phy, priv);
+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+
+ return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static const struct uniphier_u3ssphy_soc_data uniphier_pro4_data = {
+ .is_legacy = true,
+};
+
+static const struct uniphier_u3ssphy_soc_data uniphier_pxs2_data = {
+ .is_legacy = false,
+ .nparams = 7,
+ .param = {
+ { CDR_CPD_TRIM, 10 },
+ { CDR_CPF_TRIM, 3 },
+ { TX_PLL_TRIM, 5 },
+ { BGAP_TRIM, 9 },
+ { CDR_TRIM, 2 },
+ { VCOPLL_CTRL, 7 },
+ { VCOPLL_CM, 1 },
+ },
+};
+
+static const struct uniphier_u3ssphy_soc_data uniphier_ld20_data = {
+ .is_legacy = false,
+ .nparams = 3,
+ .param = {
+ { CDR_CPD_TRIM, 6 },
+ { CDR_TRIM, 2 },
+ { VCO_CTRL, 5 },
+ },
+};
+
+static const struct of_device_id uniphier_u3ssphy_match[] = {
+ {
+ .compatible = "socionext,uniphier-pro4-usb3-ssphy",
+ .data = &uniphier_pro4_data,
+ },
+ {
+ .compatible = "socionext,uniphier-pxs2-usb3-ssphy",
+ .data = &uniphier_pxs2_data,
+ },
+ {
+ .compatible = "socionext,uniphier-ld20-usb3-ssphy",
+ .data = &uniphier_ld20_data,
+ },
+ {
+ .compatible = "socionext,uniphier-pxs3-usb3-ssphy",
+ .data = &uniphier_ld20_data,
+ },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, uniphier_u3ssphy_match);
+
+static struct platform_driver uniphier_u3ssphy_driver = {
+ .probe = uniphier_u3ssphy_probe,
+ .driver = {
+ .name = "uniphier-usb3-ssphy",
+ .of_match_table = uniphier_u3ssphy_match,
+ },
+};
+
+module_platform_driver(uniphier_u3ssphy_driver);
+
+MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
+MODULE_DESCRIPTION("UniPhier SS-PHY driver for USB3 controller");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/tegra/xusb.c b/drivers/phy/tegra/xusb.c
index de1b4ebe4de2..5b3b8863363e 100644
--- a/drivers/phy/tegra/xusb.c
+++ b/drivers/phy/tegra/xusb.c
@@ -115,8 +115,8 @@ int tegra_xusb_lane_parse_dt(struct tegra_xusb_lane *lane,
err = match_string(lane->soc->funcs, lane->soc->num_funcs, function);
if (err < 0) {
- dev_err(dev, "invalid function \"%s\" for lane \"%s\"\n",
- function, np->name);
+ dev_err(dev, "invalid function \"%s\" for lane \"%pOFn\"\n",
+ function, np);
return err;
}
diff --git a/drivers/phy/ti/phy-twl4030-usb.c b/drivers/phy/ti/phy-twl4030-usb.c
index a44680d64f9b..c267afb68f07 100644
--- a/drivers/phy/ti/phy-twl4030-usb.c
+++ b/drivers/phy/ti/phy-twl4030-usb.c
@@ -144,6 +144,7 @@
#define PMBR1 0x0D
#define GPIO_USB_4PIN_ULPI_2430C (3 << 0)
+static irqreturn_t twl4030_usb_irq(int irq, void *_twl);
/*
* If VBUS is valid or ID is ground, then we know a
* cable is present and we need to be runtime-enabled
@@ -395,6 +396,33 @@ static void __twl4030_phy_power(struct twl4030_usb *twl, int on)
WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0);
}
+static int __maybe_unused twl4030_usb_suspend(struct device *dev)
+{
+ struct twl4030_usb *twl = dev_get_drvdata(dev);
+
+ /*
+ * we need enabled runtime on resume,
+ * so turn irq off here, so we do not get it early
+ * note: wakeup on usb plug works independently of this
+ */
+ dev_dbg(twl->dev, "%s\n", __func__);
+ disable_irq(twl->irq);
+
+ return 0;
+}
+
+static int __maybe_unused twl4030_usb_resume(struct device *dev)
+{
+ struct twl4030_usb *twl = dev_get_drvdata(dev);
+
+ dev_dbg(twl->dev, "%s\n", __func__);
+ enable_irq(twl->irq);
+ /* check whether cable status changed */
+ twl4030_usb_irq(0, twl);
+
+ return 0;
+}
+
static int __maybe_unused twl4030_usb_runtime_suspend(struct device *dev)
{
struct twl4030_usb *twl = dev_get_drvdata(dev);
@@ -655,6 +683,7 @@ static const struct phy_ops ops = {
static const struct dev_pm_ops twl4030_usb_pm_ops = {
SET_RUNTIME_PM_OPS(twl4030_usb_runtime_suspend,
twl4030_usb_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(twl4030_usb_suspend, twl4030_usb_resume)
};
static int twl4030_usb_probe(struct platform_device *pdev)
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index e86752be1f19..4d8c00eac742 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -195,6 +195,16 @@ config PINCTRL_RZA1
help
This selects pinctrl driver for Renesas RZ/A1 platforms.
+config PINCTRL_RZN1
+ bool "Renesas RZ/N1 pinctrl driver"
+ depends on OF
+ depends on ARCH_RZN1 || COMPILE_TEST
+ select GENERIC_PINCTRL_GROUPS
+ select GENERIC_PINMUX_FUNCTIONS
+ select GENERIC_PINCONF
+ help
+ This selects pinctrl driver for Renesas RZ/N1 devices.
+
config PINCTRL_SINGLE
tristate "One-register-per-pin type device tree based pinctrl driver"
depends on OF
@@ -309,12 +319,14 @@ config PINCTRL_ZYNQ
config PINCTRL_INGENIC
bool "Pinctrl driver for the Ingenic JZ47xx SoCs"
- default y
+ default MACH_INGENIC
depends on OF
- depends on MACH_INGENIC || COMPILE_TEST
+ depends on MIPS || COMPILE_TEST
select GENERIC_PINCONF
select GENERIC_PINCTRL_GROUPS
select GENERIC_PINMUX_FUNCTIONS
+ select GPIOLIB
+ select GPIOLIB_IRQCHIP
select REGMAP_MMIO
config PINCTRL_RK805
@@ -346,6 +358,7 @@ source "drivers/pinctrl/freescale/Kconfig"
source "drivers/pinctrl/intel/Kconfig"
source "drivers/pinctrl/mvebu/Kconfig"
source "drivers/pinctrl/nomadik/Kconfig"
+source "drivers/pinctrl/nuvoton/Kconfig"
source "drivers/pinctrl/pxa/Kconfig"
source "drivers/pinctrl/qcom/Kconfig"
source "drivers/pinctrl/samsung/Kconfig"
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 46ef9bd52096..18a13c1e2c21 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_PINCTRL_PIC32) += pinctrl-pic32.o
obj-$(CONFIG_PINCTRL_PISTACHIO) += pinctrl-pistachio.o
obj-$(CONFIG_PINCTRL_ROCKCHIP) += pinctrl-rockchip.o
obj-$(CONFIG_PINCTRL_RZA1) += pinctrl-rza1.o
+obj-$(CONFIG_PINCTRL_RZN1) += pinctrl-rzn1.o
obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o
obj-$(CONFIG_PINCTRL_SIRF) += sirf/
obj-$(CONFIG_PINCTRL_SX150X) += pinctrl-sx150x.o
@@ -51,6 +52,7 @@ obj-y += freescale/
obj-$(CONFIG_X86) += intel/
obj-y += mvebu/
obj-y += nomadik/
+obj-$(CONFIG_ARCH_NPCM7XX) += nuvoton/
obj-$(CONFIG_PINCTRL_PXA) += pxa/
obj-$(CONFIG_ARCH_QCOM) += qcom/
obj-$(CONFIG_PINCTRL_SAMSUNG) += samsung/
diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed.c b/drivers/pinctrl/aspeed/pinctrl-aspeed.c
index aefe3c33dffd..eb87ab774269 100644
--- a/drivers/pinctrl/aspeed/pinctrl-aspeed.c
+++ b/drivers/pinctrl/aspeed/pinctrl-aspeed.c
@@ -715,7 +715,7 @@ int aspeed_pin_config_set(struct pinctrl_dev *pctldev, unsigned int offset,
pmap = find_pinconf_map(param, MAP_TYPE_ARG, arg);
- if (unlikely(WARN_ON(!pmap)))
+ if (WARN_ON(!pmap))
return -EINVAL;
val = pmap->val << pconf->bit;
diff --git a/drivers/pinctrl/bcm/Kconfig b/drivers/pinctrl/bcm/Kconfig
index 0f38d51f47c6..c8575399d6f7 100644
--- a/drivers/pinctrl/bcm/Kconfig
+++ b/drivers/pinctrl/bcm/Kconfig
@@ -73,6 +73,19 @@ config PINCTRL_CYGNUS_MUX
configuration, with the exception that certain individual pins
can be overridden to GPIO function
+config PINCTRL_NS
+ bool "Broadcom Northstar pins driver"
+ depends on OF && (ARCH_BCM_5301X || COMPILE_TEST)
+ select PINMUX
+ select GENERIC_PINCONF
+ default ARCH_BCM_5301X
+ help
+ Say yes here to enable the Broadcom NS SoC pins driver.
+
+ The Broadcom Northstar pins driver supports muxing multi-purpose pins
+ that can be used for various functions (e.g. SPI, I2C, UART) as well
+ as GPIOs.
+
config PINCTRL_NSP_GPIO
bool "Broadcom NSP GPIO (with PINCONF) driver"
depends on OF_GPIO && (ARCH_BCM_NSP || COMPILE_TEST)
diff --git a/drivers/pinctrl/bcm/Makefile b/drivers/pinctrl/bcm/Makefile
index 80ceb9dae944..79d5e49fdd9a 100644
--- a/drivers/pinctrl/bcm/Makefile
+++ b/drivers/pinctrl/bcm/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_PINCTRL_BCM281XX) += pinctrl-bcm281xx.o
obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o
obj-$(CONFIG_PINCTRL_IPROC_GPIO) += pinctrl-iproc-gpio.o
obj-$(CONFIG_PINCTRL_CYGNUS_MUX) += pinctrl-cygnus-mux.o
+obj-$(CONFIG_PINCTRL_NS) += pinctrl-ns.o
obj-$(CONFIG_PINCTRL_NSP_GPIO) += pinctrl-nsp-gpio.o
obj-$(CONFIG_PINCTRL_NS2_MUX) += pinctrl-ns2-mux.o
obj-$(CONFIG_PINCTRL_NSP_MUX) += pinctrl-nsp-mux.o
diff --git a/drivers/pinctrl/bcm/pinctrl-ns.c b/drivers/pinctrl/bcm/pinctrl-ns.c
new file mode 100644
index 000000000000..d7f8175d2c1c
--- /dev/null
+++ b/drivers/pinctrl/bcm/pinctrl-ns.c
@@ -0,0 +1,372 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Rafał Miłecki <rafal@milecki.pl>
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define FLAG_BCM4708 BIT(1)
+#define FLAG_BCM4709 BIT(2)
+#define FLAG_BCM53012 BIT(3)
+
+struct ns_pinctrl {
+ struct device *dev;
+ unsigned int chipset_flag;
+ struct pinctrl_dev *pctldev;
+ void __iomem *base;
+
+ struct pinctrl_desc pctldesc;
+ struct ns_pinctrl_group *groups;
+ unsigned int num_groups;
+ struct ns_pinctrl_function *functions;
+ unsigned int num_functions;
+};
+
+/*
+ * Pins
+ */
+
+static const struct pinctrl_pin_desc ns_pinctrl_pins[] = {
+ { 0, "spi_clk", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) },
+ { 1, "spi_ss", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) },
+ { 2, "spi_mosi", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) },
+ { 3, "spi_miso", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) },
+ { 4, "i2c_scl", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) },
+ { 5, "i2c_sda", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) },
+ { 6, "mdc", (void *)(FLAG_BCM4709 | FLAG_BCM53012) },
+ { 7, "mdio", (void *)(FLAG_BCM4709 | FLAG_BCM53012) },
+ { 8, "pwm0", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) },
+ { 9, "pwm1", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) },
+ { 10, "pwm2", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) },
+ { 11, "pwm3", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) },
+ { 12, "uart1_rx", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) },
+ { 13, "uart1_tx", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) },
+ { 14, "uart1_cts", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) },
+ { 15, "uart1_rts", (void *)(FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012) },
+ { 16, "uart2_rx", (void *)(FLAG_BCM4709 | FLAG_BCM53012) },
+ { 17, "uart2_tx", (void *)(FLAG_BCM4709 | FLAG_BCM53012) },
+/* TODO { ??, "xtal_out", (void *)(FLAG_BCM4709) }, */
+ { 22, "sdio_pwr", (void *)(FLAG_BCM4709 | FLAG_BCM53012) },
+ { 23, "sdio_en_1p8v", (void *)(FLAG_BCM4709 | FLAG_BCM53012) },
+};
+
+/*
+ * Groups
+ */
+
+struct ns_pinctrl_group {
+ const char *name;
+ const unsigned int *pins;
+ const unsigned int num_pins;
+ unsigned int chipsets;
+};
+
+static const unsigned int spi_pins[] = { 0, 1, 2, 3 };
+static const unsigned int i2c_pins[] = { 4, 5 };
+static const unsigned int mdio_pins[] = { 6, 7 };
+static const unsigned int pwm0_pins[] = { 8 };
+static const unsigned int pwm1_pins[] = { 9 };
+static const unsigned int pwm2_pins[] = { 10 };
+static const unsigned int pwm3_pins[] = { 11 };
+static const unsigned int uart1_pins[] = { 12, 13, 14, 15 };
+static const unsigned int uart2_pins[] = { 16, 17 };
+static const unsigned int sdio_pwr_pins[] = { 22 };
+static const unsigned int sdio_1p8v_pins[] = { 23 };
+
+#define NS_GROUP(_name, _pins, _chipsets) \
+{ \
+ .name = _name, \
+ .pins = _pins, \
+ .num_pins = ARRAY_SIZE(_pins), \
+ .chipsets = _chipsets, \
+}
+
+static const struct ns_pinctrl_group ns_pinctrl_groups[] = {
+ NS_GROUP("spi_grp", spi_pins, FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012),
+ NS_GROUP("i2c_grp", i2c_pins, FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012),
+ NS_GROUP("mdio_grp", mdio_pins, FLAG_BCM4709 | FLAG_BCM53012),
+ NS_GROUP("pwm0_grp", pwm0_pins, FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012),
+ NS_GROUP("pwm1_grp", pwm1_pins, FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012),
+ NS_GROUP("pwm2_grp", pwm2_pins, FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012),
+ NS_GROUP("pwm3_grp", pwm3_pins, FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012),
+ NS_GROUP("uart1_grp", uart1_pins, FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012),
+ NS_GROUP("uart2_grp", uart2_pins, FLAG_BCM4709 | FLAG_BCM53012),
+ NS_GROUP("sdio_pwr_grp", sdio_pwr_pins, FLAG_BCM4709 | FLAG_BCM53012),
+ NS_GROUP("sdio_1p8v_grp", sdio_1p8v_pins, FLAG_BCM4709 | FLAG_BCM53012),
+};
+
+/*
+ * Functions
+ */
+
+struct ns_pinctrl_function {
+ const char *name;
+ const char * const *groups;
+ const unsigned int num_groups;
+ unsigned int chipsets;
+};
+
+static const char * const spi_groups[] = { "spi_grp" };
+static const char * const i2c_groups[] = { "i2c_grp" };
+static const char * const mdio_groups[] = { "mdio_grp" };
+static const char * const pwm_groups[] = { "pwm0_grp", "pwm1_grp", "pwm2_grp",
+ "pwm3_grp" };
+static const char * const uart1_groups[] = { "uart1_grp" };
+static const char * const uart2_groups[] = { "uart2_grp" };
+static const char * const sdio_groups[] = { "sdio_pwr_grp", "sdio_1p8v_grp" };
+
+#define NS_FUNCTION(_name, _groups, _chipsets) \
+{ \
+ .name = _name, \
+ .groups = _groups, \
+ .num_groups = ARRAY_SIZE(_groups), \
+ .chipsets = _chipsets, \
+}
+
+static const struct ns_pinctrl_function ns_pinctrl_functions[] = {
+ NS_FUNCTION("spi", spi_groups, FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012),
+ NS_FUNCTION("i2c", i2c_groups, FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012),
+ NS_FUNCTION("mdio", mdio_groups, FLAG_BCM4709 | FLAG_BCM53012),
+ NS_FUNCTION("pwm", pwm_groups, FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012),
+ NS_FUNCTION("uart1", uart1_groups, FLAG_BCM4708 | FLAG_BCM4709 | FLAG_BCM53012),
+ NS_FUNCTION("uart2", uart2_groups, FLAG_BCM4709 | FLAG_BCM53012),
+ NS_FUNCTION("sdio", sdio_groups, FLAG_BCM4709 | FLAG_BCM53012),
+};
+
+/*
+ * Groups code
+ */
+
+static int ns_pinctrl_get_groups_count(struct pinctrl_dev *pctrl_dev)
+{
+ struct ns_pinctrl *ns_pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+
+ return ns_pinctrl->num_groups;
+}
+
+static const char *ns_pinctrl_get_group_name(struct pinctrl_dev *pctrl_dev,
+ unsigned int selector)
+{
+ struct ns_pinctrl *ns_pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+
+ return ns_pinctrl->groups[selector].name;
+}
+
+static int ns_pinctrl_get_group_pins(struct pinctrl_dev *pctrl_dev,
+ unsigned int selector,
+ const unsigned int **pins,
+ unsigned int *num_pins)
+{
+ struct ns_pinctrl *ns_pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+
+ *pins = ns_pinctrl->groups[selector].pins;
+ *num_pins = ns_pinctrl->groups[selector].num_pins;
+
+ return 0;
+}
+
+static const struct pinctrl_ops ns_pinctrl_ops = {
+ .get_groups_count = ns_pinctrl_get_groups_count,
+ .get_group_name = ns_pinctrl_get_group_name,
+ .get_group_pins = ns_pinctrl_get_group_pins,
+ .dt_node_to_map = pinconf_generic_dt_node_to_map_group,
+ .dt_free_map = pinconf_generic_dt_free_map,
+};
+
+/*
+ * Functions code
+ */
+
+static int ns_pinctrl_get_functions_count(struct pinctrl_dev *pctrl_dev)
+{
+ struct ns_pinctrl *ns_pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+
+ return ns_pinctrl->num_functions;
+}
+
+static const char *ns_pinctrl_get_function_name(struct pinctrl_dev *pctrl_dev,
+ unsigned int selector)
+{
+ struct ns_pinctrl *ns_pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+
+ return ns_pinctrl->functions[selector].name;
+}
+
+static int ns_pinctrl_get_function_groups(struct pinctrl_dev *pctrl_dev,
+ unsigned int selector,
+ const char * const **groups,
+ unsigned * const num_groups)
+{
+ struct ns_pinctrl *ns_pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+
+ *groups = ns_pinctrl->functions[selector].groups;
+ *num_groups = ns_pinctrl->functions[selector].num_groups;
+
+ return 0;
+}
+
+static int ns_pinctrl_set_mux(struct pinctrl_dev *pctrl_dev,
+ unsigned int func_select,
+ unsigned int grp_select)
+{
+ struct ns_pinctrl *ns_pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
+ u32 unset = 0;
+ u32 tmp;
+ int i;
+
+ for (i = 0; i < ns_pinctrl->groups[grp_select].num_pins; i++) {
+ int pin_number = ns_pinctrl->groups[grp_select].pins[i];
+
+ unset |= BIT(pin_number);
+ }
+
+ tmp = readl(ns_pinctrl->base);
+ tmp &= ~unset;
+ writel(tmp, ns_pinctrl->base);
+
+ return 0;
+}
+
+static const struct pinmux_ops ns_pinctrl_pmxops = {
+ .get_functions_count = ns_pinctrl_get_functions_count,
+ .get_function_name = ns_pinctrl_get_function_name,
+ .get_function_groups = ns_pinctrl_get_function_groups,
+ .set_mux = ns_pinctrl_set_mux,
+};
+
+/*
+ * Controller code
+ */
+
+static struct pinctrl_desc ns_pinctrl_desc = {
+ .name = "pinctrl-ns",
+ .pctlops = &ns_pinctrl_ops,
+ .pmxops = &ns_pinctrl_pmxops,
+};
+
+static const struct of_device_id ns_pinctrl_of_match_table[] = {
+ { .compatible = "brcm,bcm4708-pinmux", .data = (void *)FLAG_BCM4708, },
+ { .compatible = "brcm,bcm4709-pinmux", .data = (void *)FLAG_BCM4709, },
+ { .compatible = "brcm,bcm53012-pinmux", .data = (void *)FLAG_BCM53012, },
+ { }
+};
+
+static int ns_pinctrl_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ const struct of_device_id *of_id;
+ struct ns_pinctrl *ns_pinctrl;
+ struct pinctrl_desc *pctldesc;
+ struct pinctrl_pin_desc *pin;
+ struct ns_pinctrl_group *group;
+ struct ns_pinctrl_function *function;
+ struct resource *res;
+ int i;
+
+ ns_pinctrl = devm_kzalloc(dev, sizeof(*ns_pinctrl), GFP_KERNEL);
+ if (!ns_pinctrl)
+ return -ENOMEM;
+ pctldesc = &ns_pinctrl->pctldesc;
+ platform_set_drvdata(pdev, ns_pinctrl);
+
+ /* Set basic properties */
+
+ ns_pinctrl->dev = dev;
+
+ of_id = of_match_device(ns_pinctrl_of_match_table, dev);
+ if (!of_id)
+ return -EINVAL;
+ ns_pinctrl->chipset_flag = (uintptr_t)of_id->data;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "cru_gpio_control");
+ ns_pinctrl->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(ns_pinctrl->base)) {
+ dev_err(dev, "Failed to map pinctrl regs\n");
+ return PTR_ERR(ns_pinctrl->base);
+ }
+
+ memcpy(pctldesc, &ns_pinctrl_desc, sizeof(*pctldesc));
+
+ /* Set pinctrl properties */
+
+ pctldesc->pins = devm_kcalloc(dev, ARRAY_SIZE(ns_pinctrl_pins),
+ sizeof(struct pinctrl_pin_desc),
+ GFP_KERNEL);
+ if (!pctldesc->pins)
+ return -ENOMEM;
+ for (i = 0, pin = (struct pinctrl_pin_desc *)&pctldesc->pins[0];
+ i < ARRAY_SIZE(ns_pinctrl_pins); i++) {
+ const struct pinctrl_pin_desc *src = &ns_pinctrl_pins[i];
+ unsigned int chipsets = (uintptr_t)src->drv_data;
+
+ if (chipsets & ns_pinctrl->chipset_flag) {
+ memcpy(pin++, src, sizeof(*src));
+ pctldesc->npins++;
+ }
+ }
+
+ ns_pinctrl->groups = devm_kcalloc(dev, ARRAY_SIZE(ns_pinctrl_groups),
+ sizeof(struct ns_pinctrl_group),
+ GFP_KERNEL);
+ if (!ns_pinctrl->groups)
+ return -ENOMEM;
+ for (i = 0, group = &ns_pinctrl->groups[0];
+ i < ARRAY_SIZE(ns_pinctrl_groups); i++) {
+ const struct ns_pinctrl_group *src = &ns_pinctrl_groups[i];
+
+ if (src->chipsets & ns_pinctrl->chipset_flag) {
+ memcpy(group++, src, sizeof(*src));
+ ns_pinctrl->num_groups++;
+ }
+ }
+
+ ns_pinctrl->functions = devm_kcalloc(dev,
+ ARRAY_SIZE(ns_pinctrl_functions),
+ sizeof(struct ns_pinctrl_function),
+ GFP_KERNEL);
+ if (!ns_pinctrl->functions)
+ return -ENOMEM;
+ for (i = 0, function = &ns_pinctrl->functions[0];
+ i < ARRAY_SIZE(ns_pinctrl_functions); i++) {
+ const struct ns_pinctrl_function *src = &ns_pinctrl_functions[i];
+
+ if (src->chipsets & ns_pinctrl->chipset_flag) {
+ memcpy(function++, src, sizeof(*src));
+ ns_pinctrl->num_functions++;
+ }
+ }
+
+ /* Register */
+
+ ns_pinctrl->pctldev = devm_pinctrl_register(dev, pctldesc, ns_pinctrl);
+ if (IS_ERR(ns_pinctrl->pctldev)) {
+ dev_err(dev, "Failed to register pinctrl\n");
+ return PTR_ERR(ns_pinctrl->pctldev);
+ }
+
+ return 0;
+}
+
+static struct platform_driver ns_pinctrl_driver = {
+ .probe = ns_pinctrl_probe,
+ .driver = {
+ .name = "ns-pinmux",
+ .of_match_table = ns_pinctrl_of_match_table,
+ },
+};
+
+module_platform_driver(ns_pinctrl_driver);
+
+MODULE_AUTHOR("Rafał Miłecki");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, ns_pinctrl_of_match_table);
diff --git a/drivers/pinctrl/berlin/berlin.c b/drivers/pinctrl/berlin/berlin.c
index b5903fffb3d0..b17a03cf87be 100644
--- a/drivers/pinctrl/berlin/berlin.c
+++ b/drivers/pinctrl/berlin/berlin.c
@@ -64,16 +64,14 @@ static int berlin_pinctrl_dt_node_to_map(struct pinctrl_dev *pctrl_dev,
ret = of_property_read_string(node, "function", &function_name);
if (ret) {
dev_err(pctrl->dev,
- "missing function property in node %s\n",
- node->name);
+ "missing function property in node %pOFn\n", node);
return -EINVAL;
}
ngroups = of_property_count_strings(node, "groups");
if (ngroups < 0) {
dev_err(pctrl->dev,
- "missing groups property in node %s\n",
- node->name);
+ "missing groups property in node %pOFn\n", node);
return -EINVAL;
}
diff --git a/drivers/pinctrl/cirrus/pinctrl-madera-core.c b/drivers/pinctrl/cirrus/pinctrl-madera-core.c
index c4f4d904e4a6..a5dda832024a 100644
--- a/drivers/pinctrl/cirrus/pinctrl-madera-core.c
+++ b/drivers/pinctrl/cirrus/pinctrl-madera-core.c
@@ -550,7 +550,7 @@ static void __maybe_unused madera_pin_dbg_show(struct pinctrl_dev *pctldev,
seq_printf(s, " DRV=%umA", madera_pin_unmake_drv_str(priv, conf[1]));
if (conf[0] & MADERA_GP1_IP_CFG_MASK)
- seq_puts(s, "SCHMITT");
+ seq_puts(s, " SCHMITT");
}
@@ -608,7 +608,7 @@ static int madera_mux_set_mux(struct pinctrl_dev *pctldev,
unsigned int n_chip_groups = priv->chip->n_pin_groups;
const char *func_name = madera_mux_funcs[selector].name;
unsigned int reg;
- int i, ret;
+ int i, ret = 0;
dev_dbg(priv->dev, "%s selecting %u (%s) for group %u (%s)\n",
__func__, selector, func_name, group,
@@ -801,7 +801,7 @@ static int madera_pin_conf_get(struct pinctrl_dev *pctldev, unsigned int pin,
result = 1;
break;
default:
- break;
+ return -ENOTSUPP;
}
*config = pinconf_to_config_packed(param, result);
@@ -905,7 +905,7 @@ static int madera_pin_conf_set(struct pinctrl_dev *pctldev, unsigned int pin,
conf[1] &= ~MADERA_GP1_DIR;
break;
default:
- break;
+ return -ENOTSUPP;
}
++configs;
@@ -971,10 +971,10 @@ static int madera_pin_conf_group_set(struct pinctrl_dev *pctldev,
}
static const struct pinconf_ops madera_pin_conf_ops = {
+ .is_generic = true,
.pin_config_get = madera_pin_conf_get,
.pin_config_set = madera_pin_conf_set,
.pin_config_group_set = madera_pin_conf_group_set,
-
};
static struct pinctrl_desc madera_pin_desc = {
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
index a3dd777e3ce8..c6ff4d5fa482 100644
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -627,7 +627,7 @@ static int pinctrl_generic_group_name_to_selector(struct pinctrl_dev *pctldev,
while (selector < ngroups) {
const char *gname = ops->get_group_name(pctldev, selector);
- if (!strcmp(function, gname))
+ if (gname && !strcmp(function, gname))
return selector;
selector++;
@@ -743,7 +743,7 @@ int pinctrl_get_group_selector(struct pinctrl_dev *pctldev,
while (group_selector < ngroups) {
const char *gname = pctlops->get_group_name(pctldev,
group_selector);
- if (!strcmp(gname, pin_group)) {
+ if (gname && !strcmp(gname, pin_group)) {
dev_dbg(pctldev->dev,
"found group selector %u for %s\n",
group_selector,
diff --git a/drivers/pinctrl/freescale/pinctrl-imx.c b/drivers/pinctrl/freescale/pinctrl-imx.c
index b04edc22dad7..4e8cf0e357c6 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx.c
@@ -69,8 +69,7 @@ static int imx_dt_node_to_map(struct pinctrl_dev *pctldev,
*/
grp = imx_pinctrl_find_group_by_name(pctldev, np->name);
if (!grp) {
- dev_err(ipctl->dev, "unable to find group for node %s\n",
- np->name);
+ dev_err(ipctl->dev, "unable to find group for node %pOFn\n", np);
return -EINVAL;
}
@@ -434,7 +433,7 @@ static int imx_pinctrl_parse_groups(struct device_node *np,
int i;
u32 config;
- dev_dbg(ipctl->dev, "group(%d): %s\n", index, np->name);
+ dev_dbg(ipctl->dev, "group(%d): %pOFn\n", index, np);
if (info->flags & SHARE_MUX_CONF_REG)
pin_size = FSL_PIN_SHARE_SIZE;
@@ -544,7 +543,7 @@ static int imx_pinctrl_parse_functions(struct device_node *np,
struct group_desc *grp;
u32 i = 0;
- dev_dbg(pctl->dev, "parse function(%d): %s\n", index, np->name);
+ dev_dbg(pctl->dev, "parse function(%d): %pOFn\n", index, np);
func = pinmux_generic_get_function(pctl, index);
if (!func)
diff --git a/drivers/pinctrl/freescale/pinctrl-imx1-core.c b/drivers/pinctrl/freescale/pinctrl-imx1-core.c
index deb7870b3d1a..7e29e3fecdb2 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx1-core.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx1-core.c
@@ -233,8 +233,8 @@ static int imx1_dt_node_to_map(struct pinctrl_dev *pctldev,
*/
grp = imx1_pinctrl_find_group_by_name(info, np->name);
if (!grp) {
- dev_err(info->dev, "unable to find group for node %s\n",
- np->name);
+ dev_err(info->dev, "unable to find group for node %pOFn\n",
+ np);
return -EINVAL;
}
@@ -466,7 +466,7 @@ static int imx1_pinctrl_parse_groups(struct device_node *np,
const __be32 *list;
int i;
- dev_dbg(info->dev, "group(%d): %s\n", index, np->name);
+ dev_dbg(info->dev, "group(%d): %pOFn\n", index, np);
/* Initialise group */
grp->name = np->name;
@@ -477,8 +477,8 @@ static int imx1_pinctrl_parse_groups(struct device_node *np,
list = of_get_property(np, "fsl,pins", &size);
/* we do not check return since it's safe node passed down */
if (!size || size % 12) {
- dev_notice(info->dev, "Not a valid fsl,pins property (%s)\n",
- np->name);
+ dev_notice(info->dev, "Not a valid fsl,pins property (%pOFn)\n",
+ np);
return -EINVAL;
}
@@ -513,7 +513,7 @@ static int imx1_pinctrl_parse_functions(struct device_node *np,
static u32 grp_index;
u32 i = 0;
- dev_dbg(info->dev, "parse function(%d): %s\n", index, np->name);
+ dev_dbg(info->dev, "parse function(%d): %pOFn\n", index, np);
func = &info->functions[index];
diff --git a/drivers/pinctrl/freescale/pinctrl-mxs.c b/drivers/pinctrl/freescale/pinctrl-mxs.c
index a612e46ca51c..641b3088876f 100644
--- a/drivers/pinctrl/freescale/pinctrl-mxs.c
+++ b/drivers/pinctrl/freescale/pinctrl-mxs.c
@@ -556,4 +556,3 @@ err:
iounmap(d->base);
return ret;
}
-EXPORT_SYMBOL_GPL(mxs_pinctrl_probe);
diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c
index f38d596efa05..6d1a43c0c251 100644
--- a/drivers/pinctrl/intel/pinctrl-baytrail.c
+++ b/drivers/pinctrl/intel/pinctrl-baytrail.c
@@ -6,18 +6,19 @@
* Author: Mathias Nyman <mathias.nyman@linux.intel.com>
*/
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/types.h>
+#include <linux/acpi.h>
#include <linux/bitops.h>
-#include <linux/interrupt.h>
-#include <linux/gpio.h>
#include <linux/gpio/driver.h>
-#include <linux/acpi.h>
-#include <linux/platform_device.h>
-#include <linux/seq_file.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/property.h>
+#include <linux/seq_file.h>
+
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/pinctrl/pinconf.h>
@@ -682,7 +683,7 @@ static const struct pinctrl_pin_desc byt_ncore_pins[] = {
PINCTRL_PIN(27, "GPIO_NCORE27"),
};
-static unsigned const byt_ncore_pins_map[BYT_NGPIO_NCORE] = {
+static const unsigned int byt_ncore_pins_map[BYT_NGPIO_NCORE] = {
19, 18, 17, 20, 21, 22, 24, 25, 23, 16,
14, 15, 12, 26, 27, 1, 4, 8, 11, 0,
3, 6, 10, 13, 2, 5, 9, 7,
@@ -926,7 +927,7 @@ static int byt_set_mux(struct pinctrl_dev *pctldev, unsigned int func_selector,
return 0;
}
-static u32 byt_get_gpio_mux(struct byt_gpio *vg, unsigned offset)
+static u32 byt_get_gpio_mux(struct byt_gpio *vg, unsigned int offset)
{
/* SCORE pin 92-93 */
if (!strcmp(vg->soc_data->uid, BYT_SCORE_ACPI_UID) &&
@@ -1310,7 +1311,7 @@ static const struct pinctrl_desc byt_pinctrl_desc = {
.owner = THIS_MODULE,
};
-static int byt_gpio_get(struct gpio_chip *chip, unsigned offset)
+static int byt_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
struct byt_gpio *vg = gpiochip_get_data(chip);
void __iomem *reg = byt_gpio_reg(vg, offset, BYT_VAL_REG);
@@ -1324,7 +1325,7 @@ static int byt_gpio_get(struct gpio_chip *chip, unsigned offset)
return !!(val & BYT_LEVEL);
}
-static void byt_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+static void byt_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
{
struct byt_gpio *vg = gpiochip_get_data(chip);
void __iomem *reg = byt_gpio_reg(vg, offset, BYT_VAL_REG);
@@ -1358,9 +1359,9 @@ static int byt_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
raw_spin_unlock_irqrestore(&vg->lock, flags);
if (!(value & BYT_OUTPUT_EN))
- return GPIOF_DIR_OUT;
+ return 0;
if (!(value & BYT_INPUT_EN))
- return GPIOF_DIR_IN;
+ return 1;
return -EINVAL;
}
@@ -1495,7 +1496,7 @@ static void byt_irq_ack(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct byt_gpio *vg = gpiochip_get_data(gc);
- unsigned offset = irqd_to_hwirq(d);
+ unsigned int offset = irqd_to_hwirq(d);
void __iomem *reg;
reg = byt_gpio_reg(vg, offset, BYT_INT_STAT_REG);
@@ -1519,7 +1520,7 @@ static void byt_irq_unmask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct byt_gpio *vg = gpiochip_get_data(gc);
- unsigned offset = irqd_to_hwirq(d);
+ unsigned int offset = irqd_to_hwirq(d);
unsigned long flags;
void __iomem *reg;
u32 value;
@@ -1775,13 +1776,11 @@ static const struct acpi_device_id byt_gpio_acpi_match[] = {
{ "INT33FC", (kernel_ulong_t)byt_soc_data },
{ }
};
-MODULE_DEVICE_TABLE(acpi, byt_gpio_acpi_match);
static int byt_pinctrl_probe(struct platform_device *pdev)
{
const struct byt_pinctrl_soc_data *soc_data = NULL;
const struct byt_pinctrl_soc_data **soc_table;
- const struct acpi_device_id *acpi_id;
struct acpi_device *acpi_dev;
struct byt_gpio *vg;
int i, ret;
@@ -1790,11 +1789,7 @@ static int byt_pinctrl_probe(struct platform_device *pdev)
if (!acpi_dev)
return -ENODEV;
- acpi_id = acpi_match_device(byt_gpio_acpi_match, &pdev->dev);
- if (!acpi_id)
- return -ENODEV;
-
- soc_table = (const struct byt_pinctrl_soc_data **)acpi_id->driver_data;
+ soc_table = (const struct byt_pinctrl_soc_data **)device_get_match_data(&pdev->dev);
for (i = 0; soc_table[i]; i++) {
if (!strcmp(acpi_dev->pnp.unique_id, soc_table[i]->uid)) {
diff --git a/drivers/pinctrl/intel/pinctrl-broxton.c b/drivers/pinctrl/intel/pinctrl-broxton.c
index 8b1c7b59ad3e..68fefd4618bd 100644
--- a/drivers/pinctrl/intel/pinctrl-broxton.c
+++ b/drivers/pinctrl/intel/pinctrl-broxton.c
@@ -6,10 +6,10 @@
* Author: Mika Westerberg <mika.westerberg@linux.intel.com>
*/
-#include <linux/acpi.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/pm.h>
+
#include <linux/pinctrl/pinctrl.h>
#include "pinctrl-intel.h"
@@ -117,17 +117,17 @@ static const struct pinctrl_pin_desc bxt_north_pins[] = {
PINCTRL_PIN(82, "TDO"),
};
-static const unsigned bxt_north_pwm0_pins[] = { 34 };
-static const unsigned bxt_north_pwm1_pins[] = { 35 };
-static const unsigned bxt_north_pwm2_pins[] = { 36 };
-static const unsigned bxt_north_pwm3_pins[] = { 37 };
-static const unsigned bxt_north_uart0_pins[] = { 38, 39, 40, 41 };
-static const unsigned bxt_north_uart1_pins[] = { 42, 43, 44, 45 };
-static const unsigned bxt_north_uart2_pins[] = { 46, 47, 48, 49 };
-static const unsigned bxt_north_uart0b_pins[] = { 50, 51, 52, 53 };
-static const unsigned bxt_north_uart1b_pins[] = { 54, 55, 56, 57 };
-static const unsigned bxt_north_uart2b_pins[] = { 58, 59, 60, 61 };
-static const unsigned bxt_north_uart3_pins[] = { 58, 59, 60, 61 };
+static const unsigned int bxt_north_pwm0_pins[] = { 34 };
+static const unsigned int bxt_north_pwm1_pins[] = { 35 };
+static const unsigned int bxt_north_pwm2_pins[] = { 36 };
+static const unsigned int bxt_north_pwm3_pins[] = { 37 };
+static const unsigned int bxt_north_uart0_pins[] = { 38, 39, 40, 41 };
+static const unsigned int bxt_north_uart1_pins[] = { 42, 43, 44, 45 };
+static const unsigned int bxt_north_uart2_pins[] = { 46, 47, 48, 49 };
+static const unsigned int bxt_north_uart0b_pins[] = { 50, 51, 52, 53 };
+static const unsigned int bxt_north_uart1b_pins[] = { 54, 55, 56, 57 };
+static const unsigned int bxt_north_uart2b_pins[] = { 58, 59, 60, 61 };
+static const unsigned int bxt_north_uart3_pins[] = { 58, 59, 60, 61 };
static const struct intel_pingroup bxt_north_groups[] = {
PIN_GROUP("pwm0_grp", bxt_north_pwm0_pins, 1),
@@ -260,12 +260,12 @@ static const struct pinctrl_pin_desc bxt_northwest_pins[] = {
PINCTRL_PIN(71, "GP_SSP_2_TXD"),
};
-static const unsigned bxt_northwest_ssp0_pins[] = { 53, 54, 55, 56, 57, 58 };
-static const unsigned bxt_northwest_ssp1_pins[] = {
+static const unsigned int bxt_northwest_ssp0_pins[] = { 53, 54, 55, 56, 57, 58 };
+static const unsigned int bxt_northwest_ssp1_pins[] = {
59, 60, 61, 62, 63, 64, 65
};
-static const unsigned bxt_northwest_ssp2_pins[] = { 66, 67, 68, 69, 70, 71 };
-static const unsigned bxt_northwest_uart3_pins[] = { 67, 68, 69, 70 };
+static const unsigned int bxt_northwest_ssp2_pins[] = { 66, 67, 68, 69, 70, 71 };
+static const unsigned int bxt_northwest_uart3_pins[] = { 67, 68, 69, 70 };
static const struct intel_pingroup bxt_northwest_groups[] = {
PIN_GROUP("ssp0_grp", bxt_northwest_ssp0_pins, 1),
@@ -347,17 +347,17 @@ static const struct pinctrl_pin_desc bxt_west_pins[] = {
PINCTRL_PIN(41, "OSC_CLK_OUT_3"),
};
-static const unsigned bxt_west_i2c0_pins[] = { 0, 1 };
-static const unsigned bxt_west_i2c1_pins[] = { 2, 3 };
-static const unsigned bxt_west_i2c2_pins[] = { 4, 5 };
-static const unsigned bxt_west_i2c3_pins[] = { 6, 7 };
-static const unsigned bxt_west_i2c4_pins[] = { 8, 9 };
-static const unsigned bxt_west_i2c5_pins[] = { 10, 11 };
-static const unsigned bxt_west_i2c6_pins[] = { 12, 13 };
-static const unsigned bxt_west_i2c7_pins[] = { 14, 15 };
-static const unsigned bxt_west_i2c5b_pins[] = { 16, 17 };
-static const unsigned bxt_west_i2c6b_pins[] = { 18, 19 };
-static const unsigned bxt_west_i2c7b_pins[] = { 20, 21 };
+static const unsigned int bxt_west_i2c0_pins[] = { 0, 1 };
+static const unsigned int bxt_west_i2c1_pins[] = { 2, 3 };
+static const unsigned int bxt_west_i2c2_pins[] = { 4, 5 };
+static const unsigned int bxt_west_i2c3_pins[] = { 6, 7 };
+static const unsigned int bxt_west_i2c4_pins[] = { 8, 9 };
+static const unsigned int bxt_west_i2c5_pins[] = { 10, 11 };
+static const unsigned int bxt_west_i2c6_pins[] = { 12, 13 };
+static const unsigned int bxt_west_i2c7_pins[] = { 14, 15 };
+static const unsigned int bxt_west_i2c5b_pins[] = { 16, 17 };
+static const unsigned int bxt_west_i2c6b_pins[] = { 18, 19 };
+static const unsigned int bxt_west_i2c7b_pins[] = { 20, 21 };
static const struct intel_pingroup bxt_west_groups[] = {
PIN_GROUP("i2c0_grp", bxt_west_i2c0_pins, 1),
@@ -443,13 +443,13 @@ static const struct pinctrl_pin_desc bxt_southwest_pins[] = {
PINCTRL_PIN(30, "SDCARD_LVL_WP"),
};
-static const unsigned bxt_southwest_emmc0_pins[] = {
+static const unsigned int bxt_southwest_emmc0_pins[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 26,
};
-static const unsigned bxt_southwest_sdio_pins[] = {
+static const unsigned int bxt_southwest_sdio_pins[] = {
10, 11, 12, 13, 14, 15, 27,
};
-static const unsigned bxt_southwest_sdcard_pins[] = {
+static const unsigned int bxt_southwest_sdcard_pins[] = {
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 28, 29, 30,
};
@@ -611,13 +611,13 @@ static const struct pinctrl_pin_desc apl_north_pins[] = {
PINCTRL_PIN(77, "SVID0_CLK"),
};
-static const unsigned apl_north_pwm0_pins[] = { 34 };
-static const unsigned apl_north_pwm1_pins[] = { 35 };
-static const unsigned apl_north_pwm2_pins[] = { 36 };
-static const unsigned apl_north_pwm3_pins[] = { 37 };
-static const unsigned apl_north_uart0_pins[] = { 38, 39, 40, 41 };
-static const unsigned apl_north_uart1_pins[] = { 42, 43, 44, 45 };
-static const unsigned apl_north_uart2_pins[] = { 46, 47, 48, 49 };
+static const unsigned int apl_north_pwm0_pins[] = { 34 };
+static const unsigned int apl_north_pwm1_pins[] = { 35 };
+static const unsigned int apl_north_pwm2_pins[] = { 36 };
+static const unsigned int apl_north_pwm3_pins[] = { 37 };
+static const unsigned int apl_north_uart0_pins[] = { 38, 39, 40, 41 };
+static const unsigned int apl_north_uart1_pins[] = { 42, 43, 44, 45 };
+static const unsigned int apl_north_uart2_pins[] = { 46, 47, 48, 49 };
static const struct intel_pingroup apl_north_groups[] = {
PIN_GROUP("pwm0_grp", apl_north_pwm0_pins, 1),
@@ -743,10 +743,10 @@ static const struct pinctrl_pin_desc apl_northwest_pins[] = {
PINCTRL_PIN(76, "GP_SSP_2_TXD"),
};
-static const unsigned apl_northwest_ssp0_pins[] = { 61, 62, 63, 64, 65 };
-static const unsigned apl_northwest_ssp1_pins[] = { 66, 67, 68, 69, 70 };
-static const unsigned apl_northwest_ssp2_pins[] = { 71, 72, 73, 74, 75, 76 };
-static const unsigned apl_northwest_uart3_pins[] = { 67, 68, 69, 70 };
+static const unsigned int apl_northwest_ssp0_pins[] = { 61, 62, 63, 64, 65 };
+static const unsigned int apl_northwest_ssp1_pins[] = { 66, 67, 68, 69, 70 };
+static const unsigned int apl_northwest_ssp2_pins[] = { 71, 72, 73, 74, 75, 76 };
+static const unsigned int apl_northwest_uart3_pins[] = { 67, 68, 69, 70 };
static const struct intel_pingroup apl_northwest_groups[] = {
PIN_GROUP("ssp0_grp", apl_northwest_ssp0_pins, 1),
@@ -833,15 +833,15 @@ static const struct pinctrl_pin_desc apl_west_pins[] = {
PINCTRL_PIN(46, "SUSPWRDNACK"),
};
-static const unsigned apl_west_i2c0_pins[] = { 0, 1 };
-static const unsigned apl_west_i2c1_pins[] = { 2, 3 };
-static const unsigned apl_west_i2c2_pins[] = { 4, 5 };
-static const unsigned apl_west_i2c3_pins[] = { 6, 7 };
-static const unsigned apl_west_i2c4_pins[] = { 8, 9 };
-static const unsigned apl_west_i2c5_pins[] = { 10, 11 };
-static const unsigned apl_west_i2c6_pins[] = { 12, 13 };
-static const unsigned apl_west_i2c7_pins[] = { 14, 15 };
-static const unsigned apl_west_uart2_pins[] = { 20, 21, 22, 34 };
+static const unsigned int apl_west_i2c0_pins[] = { 0, 1 };
+static const unsigned int apl_west_i2c1_pins[] = { 2, 3 };
+static const unsigned int apl_west_i2c2_pins[] = { 4, 5 };
+static const unsigned int apl_west_i2c3_pins[] = { 6, 7 };
+static const unsigned int apl_west_i2c4_pins[] = { 8, 9 };
+static const unsigned int apl_west_i2c5_pins[] = { 10, 11 };
+static const unsigned int apl_west_i2c6_pins[] = { 12, 13 };
+static const unsigned int apl_west_i2c7_pins[] = { 14, 15 };
+static const unsigned int apl_west_uart2_pins[] = { 20, 21, 22, 34 };
static const struct intel_pingroup apl_west_groups[] = {
PIN_GROUP("i2c0_grp", apl_west_i2c0_pins, 1),
@@ -939,16 +939,16 @@ static const struct pinctrl_pin_desc apl_southwest_pins[] = {
PINCTRL_PIN(42, "LPC_FRAMEB"),
};
-static const unsigned apl_southwest_emmc0_pins[] = {
+static const unsigned int apl_southwest_emmc0_pins[] = {
4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 29,
};
-static const unsigned apl_southwest_sdio_pins[] = {
+static const unsigned int apl_southwest_sdio_pins[] = {
14, 15, 16, 17, 18, 19, 30,
};
-static const unsigned apl_southwest_sdcard_pins[] = {
+static const unsigned int apl_southwest_sdcard_pins[] = {
20, 21, 22, 23, 24, 25, 26, 27, 28,
};
-static const unsigned apl_southwest_i2c7_pins[] = { 32, 33 };
+static const unsigned int apl_southwest_i2c7_pins[] = { 32, 33 };
static const struct intel_pingroup apl_southwest_groups[] = {
PIN_GROUP("emmc0_grp", apl_southwest_emmc0_pins, 1),
@@ -1008,50 +1008,10 @@ static const struct platform_device_id bxt_pinctrl_platform_ids[] = {
static int bxt_pinctrl_probe(struct platform_device *pdev)
{
- const struct intel_pinctrl_soc_data *soc_data = NULL;
- const struct intel_pinctrl_soc_data **soc_table;
- struct acpi_device *adev;
- int i;
-
- adev = ACPI_COMPANION(&pdev->dev);
- if (adev) {
- const struct acpi_device_id *id;
-
- id = acpi_match_device(bxt_pinctrl_acpi_match, &pdev->dev);
- if (!id)
- return -ENODEV;
-
- soc_table = (const struct intel_pinctrl_soc_data **)
- id->driver_data;
-
- for (i = 0; soc_table[i]; i++) {
- if (!strcmp(adev->pnp.unique_id, soc_table[i]->uid)) {
- soc_data = soc_table[i];
- break;
- }
- }
- } else {
- const struct platform_device_id *pid;
-
- pid = platform_get_device_id(pdev);
- if (!pid)
- return -ENODEV;
-
- soc_table = (const struct intel_pinctrl_soc_data **)
- pid->driver_data;
- soc_data = soc_table[pdev->id];
- }
-
- if (!soc_data)
- return -ENODEV;
-
- return intel_pinctrl_probe(pdev, soc_data);
+ return intel_pinctrl_probe_by_uid(pdev);
}
-static const struct dev_pm_ops bxt_pinctrl_pm_ops = {
- SET_LATE_SYSTEM_SLEEP_PM_OPS(intel_pinctrl_suspend,
- intel_pinctrl_resume)
-};
+static INTEL_PINCTRL_PM_OPS(bxt_pinctrl_pm_ops);
static struct platform_driver bxt_pinctrl_driver = {
.probe = bxt_pinctrl_probe,
diff --git a/drivers/pinctrl/intel/pinctrl-cannonlake.c b/drivers/pinctrl/intel/pinctrl-cannonlake.c
index e7f45d96b0cb..fb121b3ed2f2 100644
--- a/drivers/pinctrl/intel/pinctrl-cannonlake.c
+++ b/drivers/pinctrl/intel/pinctrl-cannonlake.c
@@ -7,10 +7,10 @@
* Mika Westerberg <mika.westerberg@linux.intel.com>
*/
-#include <linux/acpi.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/pm.h>
+
#include <linux/pinctrl/pinctrl.h>
#include "pinctrl-intel.h"
@@ -835,21 +835,10 @@ MODULE_DEVICE_TABLE(acpi, cnl_pinctrl_acpi_match);
static int cnl_pinctrl_probe(struct platform_device *pdev)
{
- const struct intel_pinctrl_soc_data *soc_data;
- const struct acpi_device_id *id;
-
- id = acpi_match_device(cnl_pinctrl_acpi_match, &pdev->dev);
- if (!id || !id->driver_data)
- return -ENODEV;
-
- soc_data = (const struct intel_pinctrl_soc_data *)id->driver_data;
- return intel_pinctrl_probe(pdev, soc_data);
+ return intel_pinctrl_probe_by_hid(pdev);
}
-static const struct dev_pm_ops cnl_pinctrl_pm_ops = {
- SET_LATE_SYSTEM_SLEEP_PM_OPS(intel_pinctrl_suspend,
- intel_pinctrl_resume)
-};
+static INTEL_PINCTRL_PM_OPS(cnl_pinctrl_pm_ops);
static struct platform_driver cnl_pinctrl_driver = {
.probe = cnl_pinctrl_probe,
diff --git a/drivers/pinctrl/intel/pinctrl-cedarfork.c b/drivers/pinctrl/intel/pinctrl-cedarfork.c
index c788e37e338e..7e068fc61ce1 100644
--- a/drivers/pinctrl/intel/pinctrl-cedarfork.c
+++ b/drivers/pinctrl/intel/pinctrl-cedarfork.c
@@ -9,7 +9,7 @@
#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/pm.h>
+
#include <linux/pinctrl/pinctrl.h>
#include "pinctrl-intel.h"
@@ -335,10 +335,7 @@ static int cdf_pinctrl_probe(struct platform_device *pdev)
return intel_pinctrl_probe(pdev, &cdf_soc_data);
}
-static const struct dev_pm_ops cdf_pinctrl_pm_ops = {
- SET_LATE_SYSTEM_SLEEP_PM_OPS(intel_pinctrl_suspend,
- intel_pinctrl_resume)
-};
+static INTEL_PINCTRL_PM_OPS(cdf_pinctrl_pm_ops);
static const struct acpi_device_id cdf_pinctrl_acpi_match[] = {
{ "INTC3001" },
diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c
index 6d31ad799987..9b0f4b9ef482 100644
--- a/drivers/pinctrl/intel/pinctrl-cherryview.c
+++ b/drivers/pinctrl/intel/pinctrl-cherryview.c
@@ -10,19 +10,20 @@
* Alan Cox <alan@linux.intel.com>
*/
+#include <linux/acpi.h>
#include <linux/dmi.h>
+#include <linux/gpio/driver.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
+#include <linux/platform_device.h>
#include <linux/types.h>
-#include <linux/gpio.h>
-#include <linux/gpio/driver.h>
-#include <linux/acpi.h>
+
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinconf-generic.h>
-#include <linux/platform_device.h>
+
+#include "pinctrl-intel.h"
#define CHV_INTSTAT 0x300
#define CHV_INTMASK 0x380
@@ -73,7 +74,7 @@
* @invert_oe: Invert OE for this pin
*/
struct chv_alternate_function {
- unsigned pin;
+ unsigned int pin;
u8 mode;
bool invert_oe;
};
@@ -90,7 +91,7 @@ struct chv_alternate_function {
*/
struct chv_pingroup {
const char *name;
- const unsigned *pins;
+ const unsigned int *pins;
size_t npins;
struct chv_alternate_function altfunc;
const struct chv_alternate_function *overrides;
@@ -98,25 +99,13 @@ struct chv_pingroup {
};
/**
- * struct chv_function - A CHV pinmux function
- * @name: Name of the function
- * @groups: An array of groups for this function
- * @ngroups: Number of groups in @groups
- */
-struct chv_function {
- const char *name;
- const char * const *groups;
- size_t ngroups;
-};
-
-/**
* struct chv_gpio_pinrange - A range of pins that can be used as GPIOs
* @base: Start pin number
* @npins: Number of pins in this range
*/
struct chv_gpio_pinrange {
- unsigned base;
- unsigned npins;
+ unsigned int base;
+ unsigned int npins;
};
/**
@@ -131,6 +120,7 @@ struct chv_gpio_pinrange {
* @gpio_ranges: An array of GPIO ranges in this community
* @ngpio_ranges: Number of GPIO ranges
* @nirqs: Total number of IRQs this community can generate
+ * @acpi_space_id: An address space ID for ACPI OpRegion handler
*/
struct chv_community {
const char *uid;
@@ -138,7 +128,7 @@ struct chv_community {
size_t npins;
const struct chv_pingroup *groups;
size_t ngroups;
- const struct chv_function *functions;
+ const struct intel_function *functions;
size_t nfunctions;
const struct chv_gpio_pinrange *gpio_ranges;
size_t ngpio_ranges;
@@ -161,6 +151,8 @@ struct chv_pin_context {
* @intr_lines: Stores mapping between 16 HW interrupt wires and GPIO
* offset (in GPIO number space)
* @community: Community this pinctrl instance represents
+ * @saved_intmask: Interrupt mask saved for system sleep
+ * @saved_pin_context: Pointer to a context of the pins saved for system sleep
*
* The first group in @groups is expected to contain all pins that can be
* used as GPIOs.
@@ -184,7 +176,7 @@ struct chv_pinctrl {
.invert_oe = (i), \
}
-#define PIN_GROUP(n, p, m, i) \
+#define PIN_GROUP_WITH_ALT(n, p, m, i) \
{ \
.name = (n), \
.pins = (p), \
@@ -204,13 +196,6 @@ struct chv_pinctrl {
.noverrides = ARRAY_SIZE((o)), \
}
-#define FUNCTION(n, g) \
- { \
- .name = (n), \
- .groups = (g), \
- .ngroups = ARRAY_SIZE((g)), \
- }
-
#define GPIO_PINRANGE(start, end) \
{ \
.base = (start), \
@@ -282,7 +267,6 @@ static const struct pinctrl_pin_desc southwest_pins[] = {
PINCTRL_PIN(97, "GP_SSP_2_TXD"),
};
-static const unsigned southwest_fspi_pins[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
static const unsigned southwest_uart0_pins[] = { 16, 20 };
static const unsigned southwest_uart1_pins[] = { 15, 16, 18, 20 };
static const unsigned southwest_uart2_pins[] = { 17, 19, 21, 22 };
@@ -298,7 +282,6 @@ static const unsigned southwest_i2c4_pins[] = { 46, 50 };
static const unsigned southwest_i2c5_pins[] = { 45, 48 };
static const unsigned southwest_i2c6_pins[] = { 47, 51 };
static const unsigned southwest_i2c_nfc_pins[] = { 49, 52 };
-static const unsigned southwest_smbus_pins[] = { 79, 81, 82 };
static const unsigned southwest_spi3_pins[] = { 76, 79, 80, 81, 82 };
/* LPE I2S TXD pins need to have invert_oe set */
@@ -318,18 +301,18 @@ static const struct chv_alternate_function southwest_spi3_altfuncs[] = {
};
static const struct chv_pingroup southwest_groups[] = {
- PIN_GROUP("uart0_grp", southwest_uart0_pins, 2, false),
- PIN_GROUP("uart1_grp", southwest_uart1_pins, 1, false),
- PIN_GROUP("uart2_grp", southwest_uart2_pins, 1, false),
- PIN_GROUP("hda_grp", southwest_hda_pins, 2, false),
- PIN_GROUP("i2c0_grp", southwest_i2c0_pins, 1, true),
- PIN_GROUP("i2c1_grp", southwest_i2c1_pins, 1, true),
- PIN_GROUP("i2c2_grp", southwest_i2c2_pins, 1, true),
- PIN_GROUP("i2c3_grp", southwest_i2c3_pins, 1, true),
- PIN_GROUP("i2c4_grp", southwest_i2c4_pins, 1, true),
- PIN_GROUP("i2c5_grp", southwest_i2c5_pins, 1, true),
- PIN_GROUP("i2c6_grp", southwest_i2c6_pins, 1, true),
- PIN_GROUP("i2c_nfc_grp", southwest_i2c_nfc_pins, 2, true),
+ PIN_GROUP_WITH_ALT("uart0_grp", southwest_uart0_pins, 2, false),
+ PIN_GROUP_WITH_ALT("uart1_grp", southwest_uart1_pins, 1, false),
+ PIN_GROUP_WITH_ALT("uart2_grp", southwest_uart2_pins, 1, false),
+ PIN_GROUP_WITH_ALT("hda_grp", southwest_hda_pins, 2, false),
+ PIN_GROUP_WITH_ALT("i2c0_grp", southwest_i2c0_pins, 1, true),
+ PIN_GROUP_WITH_ALT("i2c1_grp", southwest_i2c1_pins, 1, true),
+ PIN_GROUP_WITH_ALT("i2c2_grp", southwest_i2c2_pins, 1, true),
+ PIN_GROUP_WITH_ALT("i2c3_grp", southwest_i2c3_pins, 1, true),
+ PIN_GROUP_WITH_ALT("i2c4_grp", southwest_i2c4_pins, 1, true),
+ PIN_GROUP_WITH_ALT("i2c5_grp", southwest_i2c5_pins, 1, true),
+ PIN_GROUP_WITH_ALT("i2c6_grp", southwest_i2c6_pins, 1, true),
+ PIN_GROUP_WITH_ALT("i2c_nfc_grp", southwest_i2c_nfc_pins, 2, true),
PIN_GROUP_WITH_OVERRIDE("lpe_grp", southwest_lpe_pins, 1, false,
southwest_lpe_altfuncs),
@@ -356,7 +339,7 @@ static const char * const southwest_spi3_groups[] = { "spi3_grp" };
* Only do pinmuxing for certain LPSS devices for now. Rest of the pins are
* enabled only as GPIOs.
*/
-static const struct chv_function southwest_functions[] = {
+static const struct intel_function southwest_functions[] = {
FUNCTION("uart0", southwest_uart0_groups),
FUNCTION("uart1", southwest_uart1_groups),
FUNCTION("uart2", southwest_uart2_groups),
@@ -610,13 +593,13 @@ static const unsigned southeast_spi1_pins[] = { 60, 61, 62, 64, 66 };
static const unsigned southeast_spi2_pins[] = { 2, 3, 4, 6, 7 };
static const struct chv_pingroup southeast_groups[] = {
- PIN_GROUP("pwm0_grp", southeast_pwm0_pins, 1, false),
- PIN_GROUP("pwm1_grp", southeast_pwm1_pins, 1, false),
- PIN_GROUP("sdmmc1_grp", southeast_sdmmc1_pins, 1, false),
- PIN_GROUP("sdmmc2_grp", southeast_sdmmc2_pins, 1, false),
- PIN_GROUP("sdmmc3_grp", southeast_sdmmc3_pins, 1, false),
- PIN_GROUP("spi1_grp", southeast_spi1_pins, 1, false),
- PIN_GROUP("spi2_grp", southeast_spi2_pins, 4, false),
+ PIN_GROUP_WITH_ALT("pwm0_grp", southeast_pwm0_pins, 1, false),
+ PIN_GROUP_WITH_ALT("pwm1_grp", southeast_pwm1_pins, 1, false),
+ PIN_GROUP_WITH_ALT("sdmmc1_grp", southeast_sdmmc1_pins, 1, false),
+ PIN_GROUP_WITH_ALT("sdmmc2_grp", southeast_sdmmc2_pins, 1, false),
+ PIN_GROUP_WITH_ALT("sdmmc3_grp", southeast_sdmmc3_pins, 1, false),
+ PIN_GROUP_WITH_ALT("spi1_grp", southeast_spi1_pins, 1, false),
+ PIN_GROUP_WITH_ALT("spi2_grp", southeast_spi2_pins, 4, false),
};
static const char * const southeast_pwm0_groups[] = { "pwm0_grp" };
@@ -627,7 +610,7 @@ static const char * const southeast_sdmmc3_groups[] = { "sdmmc3_grp" };
static const char * const southeast_spi1_groups[] = { "spi1_grp" };
static const char * const southeast_spi2_groups[] = { "spi2_grp" };
-static const struct chv_function southeast_functions[] = {
+static const struct intel_function southeast_functions[] = {
FUNCTION("pwm0", southeast_pwm0_groups),
FUNCTION("pwm1", southeast_pwm1_groups),
FUNCTION("sdmmc1", southeast_sdmmc1_groups),
@@ -678,11 +661,11 @@ static const struct chv_community *chv_communities[] = {
*/
static DEFINE_RAW_SPINLOCK(chv_lock);
-static void __iomem *chv_padreg(struct chv_pinctrl *pctrl, unsigned offset,
- unsigned reg)
+static void __iomem *chv_padreg(struct chv_pinctrl *pctrl, unsigned int offset,
+ unsigned int reg)
{
- unsigned family_no = offset / MAX_FAMILY_PAD_GPIO_NO;
- unsigned pad_no = offset % MAX_FAMILY_PAD_GPIO_NO;
+ unsigned int family_no = offset / MAX_FAMILY_PAD_GPIO_NO;
+ unsigned int pad_no = offset % MAX_FAMILY_PAD_GPIO_NO;
offset = FAMILY_PAD_REGS_OFF + FAMILY_PAD_REGS_SIZE * family_no +
GPIO_REGS_SIZE * pad_no;
@@ -698,7 +681,7 @@ static void chv_writel(u32 value, void __iomem *reg)
}
/* When Pad Cfg is locked, driver can only change GPIOTXState or GPIORXState */
-static bool chv_pad_locked(struct chv_pinctrl *pctrl, unsigned offset)
+static bool chv_pad_locked(struct chv_pinctrl *pctrl, unsigned int offset)
{
void __iomem *reg;
@@ -714,15 +697,15 @@ static int chv_get_groups_count(struct pinctrl_dev *pctldev)
}
static const char *chv_get_group_name(struct pinctrl_dev *pctldev,
- unsigned group)
+ unsigned int group)
{
struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
return pctrl->community->groups[group].name;
}
-static int chv_get_group_pins(struct pinctrl_dev *pctldev, unsigned group,
- const unsigned **pins, unsigned *npins)
+static int chv_get_group_pins(struct pinctrl_dev *pctldev, unsigned int group,
+ const unsigned int **pins, unsigned int *npins)
{
struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
@@ -732,7 +715,7 @@ static int chv_get_group_pins(struct pinctrl_dev *pctldev, unsigned group,
}
static void chv_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
- unsigned offset)
+ unsigned int offset)
{
struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
unsigned long flags;
@@ -779,7 +762,7 @@ static int chv_get_functions_count(struct pinctrl_dev *pctldev)
}
static const char *chv_get_function_name(struct pinctrl_dev *pctldev,
- unsigned function)
+ unsigned int function)
{
struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
@@ -787,9 +770,9 @@ static const char *chv_get_function_name(struct pinctrl_dev *pctldev,
}
static int chv_get_function_groups(struct pinctrl_dev *pctldev,
- unsigned function,
+ unsigned int function,
const char * const **groups,
- unsigned * const ngroups)
+ unsigned int * const ngroups)
{
struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
@@ -798,8 +781,8 @@ static int chv_get_function_groups(struct pinctrl_dev *pctldev,
return 0;
}
-static int chv_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned function,
- unsigned group)
+static int chv_pinmux_set_mux(struct pinctrl_dev *pctldev,
+ unsigned int function, unsigned int group)
{
struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
const struct chv_pingroup *grp;
@@ -865,7 +848,7 @@ static int chv_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned function,
static int chv_gpio_request_enable(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
- unsigned offset)
+ unsigned int offset)
{
struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
unsigned long flags;
@@ -925,7 +908,7 @@ static int chv_gpio_request_enable(struct pinctrl_dev *pctldev,
static void chv_gpio_disable_free(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
- unsigned offset)
+ unsigned int offset)
{
struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
unsigned long flags;
@@ -943,7 +926,7 @@ static void chv_gpio_disable_free(struct pinctrl_dev *pctldev,
static int chv_gpio_set_direction(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
- unsigned offset, bool input)
+ unsigned int offset, bool input)
{
struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
void __iomem *reg = chv_padreg(pctrl, offset, CHV_PADCTRL0);
@@ -974,7 +957,7 @@ static const struct pinmux_ops chv_pinmux_ops = {
.gpio_set_direction = chv_gpio_set_direction,
};
-static int chv_config_get(struct pinctrl_dev *pctldev, unsigned pin,
+static int chv_config_get(struct pinctrl_dev *pctldev, unsigned int pin,
unsigned long *config)
{
struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
@@ -1054,7 +1037,7 @@ static int chv_config_get(struct pinctrl_dev *pctldev, unsigned pin,
return 0;
}
-static int chv_config_set_pull(struct chv_pinctrl *pctrl, unsigned pin,
+static int chv_config_set_pull(struct chv_pinctrl *pctrl, unsigned int pin,
enum pin_config_param param, u32 arg)
{
void __iomem *reg = chv_padreg(pctrl, pin, CHV_PADCTRL0);
@@ -1141,8 +1124,8 @@ static int chv_config_set_oden(struct chv_pinctrl *pctrl, unsigned int pin,
return 0;
}
-static int chv_config_set(struct pinctrl_dev *pctldev, unsigned pin,
- unsigned long *configs, unsigned nconfigs)
+static int chv_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
+ unsigned long *configs, unsigned int nconfigs)
{
struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
enum pin_config_param param;
@@ -1243,7 +1226,7 @@ static struct pinctrl_desc chv_pinctrl_desc = {
.owner = THIS_MODULE,
};
-static int chv_gpio_get(struct gpio_chip *chip, unsigned offset)
+static int chv_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
struct chv_pinctrl *pctrl = gpiochip_get_data(chip);
unsigned long flags;
@@ -1261,7 +1244,7 @@ static int chv_gpio_get(struct gpio_chip *chip, unsigned offset)
return !!(ctrl0 & CHV_PADCTRL0_GPIORXSTATE);
}
-static void chv_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+static void chv_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
{
struct chv_pinctrl *pctrl = gpiochip_get_data(chip);
unsigned long flags;
@@ -1283,7 +1266,7 @@ static void chv_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
raw_spin_unlock_irqrestore(&chv_lock, flags);
}
-static int chv_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
+static int chv_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
{
struct chv_pinctrl *pctrl = gpiochip_get_data(chip);
u32 ctrl0, direction;
@@ -1299,12 +1282,12 @@ static int chv_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
return direction != CHV_PADCTRL0_GPIOCFG_GPO;
}
-static int chv_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+static int chv_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
{
return pinctrl_gpio_direction_input(chip->base + offset);
}
-static int chv_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
+static int chv_gpio_direction_output(struct gpio_chip *chip, unsigned int offset,
int value)
{
chv_gpio_set(chip, offset, value);
@@ -1388,7 +1371,7 @@ static unsigned chv_gpio_irq_startup(struct irq_data *d)
if (irqd_get_trigger_type(d) == IRQ_TYPE_NONE) {
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct chv_pinctrl *pctrl = gpiochip_get_data(gc);
- unsigned pin = irqd_to_hwirq(d);
+ unsigned int pin = irqd_to_hwirq(d);
irq_flow_handler_t handler;
unsigned long flags;
u32 intsel, value;
@@ -1415,11 +1398,11 @@ static unsigned chv_gpio_irq_startup(struct irq_data *d)
return 0;
}
-static int chv_gpio_irq_type(struct irq_data *d, unsigned type)
+static int chv_gpio_irq_type(struct irq_data *d, unsigned int type)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct chv_pinctrl *pctrl = gpiochip_get_data(gc);
- unsigned pin = irqd_to_hwirq(d);
+ unsigned int pin = irqd_to_hwirq(d);
unsigned long flags;
u32 value;
diff --git a/drivers/pinctrl/intel/pinctrl-denverton.c b/drivers/pinctrl/intel/pinctrl-denverton.c
index f321ab0d76e5..88bc55281b83 100644
--- a/drivers/pinctrl/intel/pinctrl-denverton.c
+++ b/drivers/pinctrl/intel/pinctrl-denverton.c
@@ -9,7 +9,7 @@
#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/pm.h>
+
#include <linux/pinctrl/pinctrl.h>
#include "pinctrl-intel.h"
@@ -262,10 +262,7 @@ static int dnv_pinctrl_probe(struct platform_device *pdev)
return intel_pinctrl_probe(pdev, &dnv_soc_data);
}
-static const struct dev_pm_ops dnv_pinctrl_pm_ops = {
- SET_LATE_SYSTEM_SLEEP_PM_OPS(intel_pinctrl_suspend,
- intel_pinctrl_resume)
-};
+static INTEL_PINCTRL_PM_OPS(dnv_pinctrl_pm_ops);
static const struct acpi_device_id dnv_pinctrl_acpi_match[] = {
{ "INTC3000" },
diff --git a/drivers/pinctrl/intel/pinctrl-geminilake.c b/drivers/pinctrl/intel/pinctrl-geminilake.c
index 5c4c96752fc1..67600314454c 100644
--- a/drivers/pinctrl/intel/pinctrl-geminilake.c
+++ b/drivers/pinctrl/intel/pinctrl-geminilake.c
@@ -6,17 +6,17 @@
* Author: Mika Westerberg <mika.westerberg@linux.intel.com>
*/
-#include <linux/acpi.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/pm.h>
+
#include <linux/pinctrl/pinctrl.h>
#include "pinctrl-intel.h"
#define GLK_PAD_OWN 0x020
-#define GLK_HOSTSW_OWN 0x0b0
#define GLK_PADCFGLOCK 0x080
+#define GLK_HOSTSW_OWN 0x0b0
#define GLK_GPI_IE 0x110
#define GLK_COMMUNITY(s, e) \
@@ -58,16 +58,16 @@ static const struct pinctrl_pin_desc glk_northwest_pins[] = {
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(26, "ISH_GPIO_0"),
+ PINCTRL_PIN(27, "ISH_GPIO_1"),
+ PINCTRL_PIN(28, "ISH_GPIO_2"),
+ PINCTRL_PIN(29, "ISH_GPIO_3"),
+ PINCTRL_PIN(30, "ISH_GPIO_4"),
+ PINCTRL_PIN(31, "ISH_GPIO_5"),
+ PINCTRL_PIN(32, "ISH_GPIO_6"),
+ PINCTRL_PIN(33, "ISH_GPIO_7"),
+ PINCTRL_PIN(34, "ISH_GPIO_8"),
+ PINCTRL_PIN(35, "ISH_GPIO_9"),
PINCTRL_PIN(36, "GPIO_36"),
PINCTRL_PIN(37, "GPIO_37"),
PINCTRL_PIN(38, "GPIO_38"),
@@ -195,12 +195,12 @@ static const struct pinctrl_pin_desc glk_north_pins[] = {
PINCTRL_PIN(5, "LPSS_SPI_0_FS1"),
PINCTRL_PIN(6, "LPSS_SPI_0_RXD"),
PINCTRL_PIN(7, "LPSS_SPI_0_TXD"),
- PINCTRL_PIN(8, "LPSS_SPI_1_CLK"),
- PINCTRL_PIN(9, "LPSS_SPI_1_FS0"),
- PINCTRL_PIN(10, "LPSS_SPI_1_FS1"),
- PINCTRL_PIN(11, "LPSS_SPI_1_FS2"),
- PINCTRL_PIN(12, "LPSS_SPI_1_RXD"),
- PINCTRL_PIN(13, "LPSS_SPI_1_TXD"),
+ PINCTRL_PIN(8, "LPSS_SPI_2_CLK"),
+ PINCTRL_PIN(9, "LPSS_SPI_2_FS0"),
+ PINCTRL_PIN(10, "LPSS_SPI_2_FS1"),
+ PINCTRL_PIN(11, "LPSS_SPI_2_FS2"),
+ PINCTRL_PIN(12, "LPSS_SPI_2_RXD"),
+ PINCTRL_PIN(13, "LPSS_SPI_2_TXD"),
PINCTRL_PIN(14, "FST_SPI_CS0_B"),
PINCTRL_PIN(15, "FST_SPI_CS1_B"),
PINCTRL_PIN(16, "FST_SPI_MOSI_IO0"),
@@ -215,8 +215,8 @@ static const struct pinctrl_pin_desc glk_north_pins[] = {
PINCTRL_PIN(25, "PMU_SLP_S3_B"),
PINCTRL_PIN(26, "PMU_SLP_S4_B"),
PINCTRL_PIN(27, "SUSPWRDNACK"),
- PINCTRL_PIN(28, "EMMC_PWR_EN_B"),
- PINCTRL_PIN(29, "PMU_AC_PRESENT"),
+ PINCTRL_PIN(28, "EMMC_DNX_PWR_EN_B"),
+ PINCTRL_PIN(29, "GPIO_105"),
PINCTRL_PIN(30, "PMU_BATLOW_B"),
PINCTRL_PIN(31, "PMU_RESETBUTTON_B"),
PINCTRL_PIN(32, "PMU_SUSCLK"),
@@ -449,42 +449,15 @@ static const struct intel_pinctrl_soc_data *glk_pinctrl_soc_data[] = {
};
static const struct acpi_device_id glk_pinctrl_acpi_match[] = {
- { "INT3453" },
+ { "INT3453", (kernel_ulong_t)glk_pinctrl_soc_data },
{ }
};
MODULE_DEVICE_TABLE(acpi, glk_pinctrl_acpi_match);
-static int glk_pinctrl_probe(struct platform_device *pdev)
-{
- const struct intel_pinctrl_soc_data *soc_data = NULL;
- struct acpi_device *adev;
- int i;
-
- adev = ACPI_COMPANION(&pdev->dev);
- if (!adev)
- return -ENODEV;
-
- for (i = 0; glk_pinctrl_soc_data[i]; i++) {
- if (!strcmp(adev->pnp.unique_id,
- glk_pinctrl_soc_data[i]->uid)) {
- soc_data = glk_pinctrl_soc_data[i];
- break;
- }
- }
-
- if (!soc_data)
- return -ENODEV;
-
- return intel_pinctrl_probe(pdev, soc_data);
-}
-
-static const struct dev_pm_ops glk_pinctrl_pm_ops = {
- SET_LATE_SYSTEM_SLEEP_PM_OPS(intel_pinctrl_suspend,
- intel_pinctrl_resume)
-};
+static INTEL_PINCTRL_PM_OPS(glk_pinctrl_pm_ops);
static struct platform_driver glk_pinctrl_driver = {
- .probe = glk_pinctrl_probe,
+ .probe = intel_pinctrl_probe_by_uid,
.driver = {
.name = "geminilake-pinctrl",
.acpi_match_table = glk_pinctrl_acpi_match,
diff --git a/drivers/pinctrl/intel/pinctrl-icelake.c b/drivers/pinctrl/intel/pinctrl-icelake.c
index 630b966ce081..f33a5deafb97 100644
--- a/drivers/pinctrl/intel/pinctrl-icelake.c
+++ b/drivers/pinctrl/intel/pinctrl-icelake.c
@@ -10,7 +10,7 @@
#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/pm.h>
+
#include <linux/pinctrl/pinctrl.h>
#include "pinctrl-intel.h"
@@ -408,10 +408,7 @@ static int icl_pinctrl_probe(struct platform_device *pdev)
return intel_pinctrl_probe(pdev, &icllp_soc_data);
}
-static const struct dev_pm_ops icl_pinctrl_pm_ops = {
- SET_LATE_SYSTEM_SLEEP_PM_OPS(intel_pinctrl_suspend,
- intel_pinctrl_resume)
-};
+static INTEL_PINCTRL_PM_OPS(icl_pinctrl_pm_ops);
static const struct acpi_device_id icl_pinctrl_acpi_match[] = {
{ "INT3455" },
diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c
index 1ea3438ea67e..8cda7b535b02 100644
--- a/drivers/pinctrl/intel/pinctrl-intel.c
+++ b/drivers/pinctrl/intel/pinctrl-intel.c
@@ -7,11 +7,14 @@
* Mika Westerberg <mika.westerberg@linux.intel.com>
*/
+#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/gpio/driver.h>
#include <linux/log2.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
+
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/pinctrl/pinconf.h>
@@ -115,7 +118,7 @@ struct intel_pinctrl {
#define padgroup_offset(g, p) ((p) - (g)->base)
static struct intel_community *intel_get_community(struct intel_pinctrl *pctrl,
- unsigned pin)
+ unsigned int pin)
{
struct intel_community *community;
int i;
@@ -133,7 +136,7 @@ static struct intel_community *intel_get_community(struct intel_pinctrl *pctrl,
static const struct intel_padgroup *
intel_community_get_padgroup(const struct intel_community *community,
- unsigned pin)
+ unsigned int pin)
{
int i;
@@ -147,11 +150,11 @@ intel_community_get_padgroup(const struct intel_community *community,
return NULL;
}
-static void __iomem *intel_get_padcfg(struct intel_pinctrl *pctrl, unsigned pin,
- unsigned reg)
+static void __iomem *intel_get_padcfg(struct intel_pinctrl *pctrl,
+ unsigned int pin, unsigned int reg)
{
const struct intel_community *community;
- unsigned padno;
+ unsigned int padno;
size_t nregs;
community = intel_get_community(pctrl, pin);
@@ -167,11 +170,11 @@ static void __iomem *intel_get_padcfg(struct intel_pinctrl *pctrl, unsigned pin,
return community->pad_regs + reg + padno * nregs * 4;
}
-static bool intel_pad_owned_by_host(struct intel_pinctrl *pctrl, unsigned pin)
+static bool intel_pad_owned_by_host(struct intel_pinctrl *pctrl, unsigned int pin)
{
const struct intel_community *community;
const struct intel_padgroup *padgrp;
- unsigned gpp, offset, gpp_offset;
+ unsigned int gpp, offset, gpp_offset;
void __iomem *padown;
community = intel_get_community(pctrl, pin);
@@ -192,11 +195,11 @@ static bool intel_pad_owned_by_host(struct intel_pinctrl *pctrl, unsigned pin)
return !(readl(padown) & PADOWN_MASK(gpp_offset));
}
-static bool intel_pad_acpi_mode(struct intel_pinctrl *pctrl, unsigned pin)
+static bool intel_pad_acpi_mode(struct intel_pinctrl *pctrl, unsigned int pin)
{
const struct intel_community *community;
const struct intel_padgroup *padgrp;
- unsigned offset, gpp_offset;
+ unsigned int offset, gpp_offset;
void __iomem *hostown;
community = intel_get_community(pctrl, pin);
@@ -216,11 +219,11 @@ static bool intel_pad_acpi_mode(struct intel_pinctrl *pctrl, unsigned pin)
return !(readl(hostown) & BIT(gpp_offset));
}
-static bool intel_pad_locked(struct intel_pinctrl *pctrl, unsigned pin)
+static bool intel_pad_locked(struct intel_pinctrl *pctrl, unsigned int pin)
{
struct intel_community *community;
const struct intel_padgroup *padgrp;
- unsigned offset, gpp_offset;
+ unsigned int offset, gpp_offset;
u32 value;
community = intel_get_community(pctrl, pin);
@@ -253,7 +256,7 @@ static bool intel_pad_locked(struct intel_pinctrl *pctrl, unsigned pin)
return false;
}
-static bool intel_pad_usable(struct intel_pinctrl *pctrl, unsigned pin)
+static bool intel_pad_usable(struct intel_pinctrl *pctrl, unsigned int pin)
{
return intel_pad_owned_by_host(pctrl, pin) &&
!intel_pad_locked(pctrl, pin);
@@ -267,15 +270,15 @@ static int intel_get_groups_count(struct pinctrl_dev *pctldev)
}
static const char *intel_get_group_name(struct pinctrl_dev *pctldev,
- unsigned group)
+ unsigned int group)
{
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
return pctrl->soc->groups[group].name;
}
-static int intel_get_group_pins(struct pinctrl_dev *pctldev, unsigned group,
- const unsigned **pins, unsigned *npins)
+static int intel_get_group_pins(struct pinctrl_dev *pctldev, unsigned int group,
+ const unsigned int **pins, unsigned int *npins)
{
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
@@ -285,7 +288,7 @@ static int intel_get_group_pins(struct pinctrl_dev *pctldev, unsigned group,
}
static void intel_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
- unsigned pin)
+ unsigned int pin)
{
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
void __iomem *padcfg;
@@ -344,7 +347,7 @@ static int intel_get_functions_count(struct pinctrl_dev *pctldev)
}
static const char *intel_get_function_name(struct pinctrl_dev *pctldev,
- unsigned function)
+ unsigned int function)
{
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
@@ -352,9 +355,9 @@ static const char *intel_get_function_name(struct pinctrl_dev *pctldev,
}
static int intel_get_function_groups(struct pinctrl_dev *pctldev,
- unsigned function,
+ unsigned int function,
const char * const **groups,
- unsigned * const ngroups)
+ unsigned int * const ngroups)
{
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
@@ -363,8 +366,8 @@ static int intel_get_function_groups(struct pinctrl_dev *pctldev,
return 0;
}
-static int intel_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned function,
- unsigned group)
+static int intel_pinmux_set_mux(struct pinctrl_dev *pctldev,
+ unsigned int function, unsigned int group)
{
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
const struct intel_pingroup *grp = &pctrl->soc->groups[group];
@@ -436,7 +439,7 @@ static void intel_gpio_set_gpio_mode(void __iomem *padcfg0)
static int intel_gpio_request_enable(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
- unsigned pin)
+ unsigned int pin)
{
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
void __iomem *padcfg0;
@@ -461,7 +464,7 @@ static int intel_gpio_request_enable(struct pinctrl_dev *pctldev,
static int intel_gpio_set_direction(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
- unsigned pin, bool input)
+ unsigned int pin, bool input)
{
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
void __iomem *padcfg0;
@@ -486,7 +489,7 @@ static const struct pinmux_ops intel_pinmux_ops = {
.gpio_set_direction = intel_gpio_set_direction,
};
-static int intel_config_get(struct pinctrl_dev *pctldev, unsigned pin,
+static int intel_config_get(struct pinctrl_dev *pctldev, unsigned int pin,
unsigned long *config)
{
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
@@ -575,11 +578,11 @@ static int intel_config_get(struct pinctrl_dev *pctldev, unsigned pin,
return 0;
}
-static int intel_config_set_pull(struct intel_pinctrl *pctrl, unsigned pin,
+static int intel_config_set_pull(struct intel_pinctrl *pctrl, unsigned int pin,
unsigned long config)
{
- unsigned param = pinconf_to_config_param(config);
- unsigned arg = pinconf_to_config_argument(config);
+ unsigned int param = pinconf_to_config_param(config);
+ unsigned int arg = pinconf_to_config_argument(config);
const struct intel_community *community;
void __iomem *padcfg1;
unsigned long flags;
@@ -653,8 +656,8 @@ static int intel_config_set_pull(struct intel_pinctrl *pctrl, unsigned pin,
return ret;
}
-static int intel_config_set_debounce(struct intel_pinctrl *pctrl, unsigned pin,
- unsigned debounce)
+static int intel_config_set_debounce(struct intel_pinctrl *pctrl,
+ unsigned int pin, unsigned int debounce)
{
void __iomem *padcfg0, *padcfg2;
unsigned long flags;
@@ -700,8 +703,8 @@ exit_unlock:
return ret;
}
-static int intel_config_set(struct pinctrl_dev *pctldev, unsigned pin,
- unsigned long *configs, unsigned nconfigs)
+static int intel_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
+ unsigned long *configs, unsigned int nconfigs)
{
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
int i, ret;
@@ -751,14 +754,14 @@ static const struct pinctrl_desc intel_pinctrl_desc = {
* intel_gpio_to_pin() - Translate from GPIO offset to pin number
* @pctrl: Pinctrl structure
* @offset: GPIO offset from gpiolib
- * @commmunity: Community is filled here if not %NULL
+ * @community: Community is filled here if not %NULL
* @padgrp: Pad group is filled here if not %NULL
*
* When coming through gpiolib irqchip, the GPIO offset is not
* automatically translated to pinctrl pin number. This function can be
* used to find out the corresponding pinctrl pin.
*/
-static int intel_gpio_to_pin(struct intel_pinctrl *pctrl, unsigned offset,
+static int intel_gpio_to_pin(struct intel_pinctrl *pctrl, unsigned int offset,
const struct intel_community **community,
const struct intel_padgroup **padgrp)
{
@@ -792,7 +795,7 @@ static int intel_gpio_to_pin(struct intel_pinctrl *pctrl, unsigned offset,
return -EINVAL;
}
-static int intel_gpio_get(struct gpio_chip *chip, unsigned offset)
+static int intel_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
struct intel_pinctrl *pctrl = gpiochip_get_data(chip);
void __iomem *reg;
@@ -814,7 +817,8 @@ static int intel_gpio_get(struct gpio_chip *chip, unsigned offset)
return !!(padcfg0 & PADCFG0_GPIORXSTATE);
}
-static void intel_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+static void intel_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
{
struct intel_pinctrl *pctrl = gpiochip_get_data(chip);
unsigned long flags;
@@ -863,12 +867,12 @@ static int intel_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
return !!(padcfg0 & PADCFG0_GPIOTXDIS);
}
-static int intel_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+static int intel_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
{
return pinctrl_gpio_direction_input(chip->base + offset);
}
-static int intel_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
+static int intel_gpio_direction_output(struct gpio_chip *chip, unsigned int offset,
int value)
{
intel_gpio_set(chip, offset, value);
@@ -897,7 +901,7 @@ static void intel_gpio_irq_ack(struct irq_data *d)
pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), &community, &padgrp);
if (pin >= 0) {
- unsigned gpp, gpp_offset, is_offset;
+ unsigned int gpp, gpp_offset, is_offset;
gpp = padgrp->reg_num;
gpp_offset = padgroup_offset(padgrp, pin);
@@ -919,7 +923,7 @@ static void intel_gpio_irq_enable(struct irq_data *d)
pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), &community, &padgrp);
if (pin >= 0) {
- unsigned gpp, gpp_offset, is_offset;
+ unsigned int gpp, gpp_offset, is_offset;
unsigned long flags;
u32 value;
@@ -948,7 +952,7 @@ static void intel_gpio_irq_mask_unmask(struct irq_data *d, bool mask)
pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), &community, &padgrp);
if (pin >= 0) {
- unsigned gpp, gpp_offset;
+ unsigned int gpp, gpp_offset;
unsigned long flags;
void __iomem *reg;
u32 value;
@@ -979,11 +983,11 @@ static void intel_gpio_irq_unmask(struct irq_data *d)
intel_gpio_irq_mask_unmask(d, false);
}
-static int intel_gpio_irq_type(struct irq_data *d, unsigned type)
+static int intel_gpio_irq_type(struct irq_data *d, unsigned int type)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct intel_pinctrl *pctrl = gpiochip_get_data(gc);
- unsigned pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), NULL, NULL);
+ unsigned int pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), NULL, NULL);
unsigned long flags;
void __iomem *reg;
u32 value;
@@ -1040,7 +1044,7 @@ static int intel_gpio_irq_wake(struct irq_data *d, unsigned int on)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct intel_pinctrl *pctrl = gpiochip_get_data(gc);
- unsigned pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), NULL, NULL);
+ unsigned int pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), NULL, NULL);
if (on)
enable_irq_wake(pctrl->irq);
@@ -1135,7 +1139,7 @@ static int intel_gpio_add_pin_ranges(struct intel_pinctrl *pctrl,
static unsigned intel_gpio_ngpio(const struct intel_pinctrl *pctrl)
{
const struct intel_community *community;
- unsigned ngpio = 0;
+ unsigned int ngpio = 0;
int i, j;
for (i = 0; i < pctrl->ncommunities; i++) {
@@ -1211,8 +1215,8 @@ static int intel_pinctrl_add_padgroups(struct intel_pinctrl *pctrl,
struct intel_community *community)
{
struct intel_padgroup *gpps;
- unsigned npins = community->npins;
- unsigned padown_num = 0;
+ unsigned int npins = community->npins;
+ unsigned int padown_num = 0;
size_t ngpps, i;
if (community->gpps)
@@ -1228,7 +1232,7 @@ static int intel_pinctrl_add_padgroups(struct intel_pinctrl *pctrl,
if (community->gpps) {
gpps[i] = community->gpps[i];
} else {
- unsigned gpp_size = community->gpp_size;
+ unsigned int gpp_size = community->gpp_size;
gpps[i].reg_num = i;
gpps[i].base = community->pin_base + i * gpp_size;
@@ -1398,8 +1402,52 @@ int intel_pinctrl_probe(struct platform_device *pdev,
}
EXPORT_SYMBOL_GPL(intel_pinctrl_probe);
+int intel_pinctrl_probe_by_hid(struct platform_device *pdev)
+{
+ const struct intel_pinctrl_soc_data *data;
+
+ data = device_get_match_data(&pdev->dev);
+ return intel_pinctrl_probe(pdev, data);
+}
+EXPORT_SYMBOL_GPL(intel_pinctrl_probe_by_hid);
+
+int intel_pinctrl_probe_by_uid(struct platform_device *pdev)
+{
+ const struct intel_pinctrl_soc_data *data = NULL;
+ const struct intel_pinctrl_soc_data **table;
+ struct acpi_device *adev;
+ unsigned int i;
+
+ adev = ACPI_COMPANION(&pdev->dev);
+ if (adev) {
+ const void *match = device_get_match_data(&pdev->dev);
+
+ table = (const struct intel_pinctrl_soc_data **)match;
+ for (i = 0; table[i]; i++) {
+ if (!strcmp(adev->pnp.unique_id, table[i]->uid)) {
+ data = table[i];
+ break;
+ }
+ }
+ } else {
+ const struct platform_device_id *id;
+
+ id = platform_get_device_id(pdev);
+ if (!id)
+ return -ENODEV;
+
+ table = (const struct intel_pinctrl_soc_data **)id->driver_data;
+ data = table[pdev->id];
+ }
+ if (!data)
+ return -ENODEV;
+
+ return intel_pinctrl_probe(pdev, data);
+}
+EXPORT_SYMBOL_GPL(intel_pinctrl_probe_by_uid);
+
#ifdef CONFIG_PM_SLEEP
-static bool intel_pinctrl_should_save(struct intel_pinctrl *pctrl, unsigned pin)
+static bool intel_pinctrl_should_save(struct intel_pinctrl *pctrl, unsigned int pin)
{
const struct pin_desc *pd = pin_desc_get(pctrl->pctldev, pin);
@@ -1450,7 +1498,7 @@ int intel_pinctrl_suspend(struct device *dev)
for (i = 0; i < pctrl->ncommunities; i++) {
struct intel_community *community = &pctrl->communities[i];
void __iomem *base;
- unsigned gpp;
+ unsigned int gpp;
base = community->regs + community->ie_offset;
for (gpp = 0; gpp < community->ngpps; gpp++)
@@ -1468,7 +1516,7 @@ static void intel_gpio_irq_init(struct intel_pinctrl *pctrl)
for (i = 0; i < pctrl->ncommunities; i++) {
const struct intel_community *community;
void __iomem *base;
- unsigned gpp;
+ unsigned int gpp;
community = &pctrl->communities[i];
base = community->regs;
@@ -1532,7 +1580,7 @@ int intel_pinctrl_resume(struct device *dev)
for (i = 0; i < pctrl->ncommunities; i++) {
struct intel_community *community = &pctrl->communities[i];
void __iomem *base;
- unsigned gpp;
+ unsigned int gpp;
base = community->regs + community->ie_offset;
for (gpp = 0; gpp < community->ngpps; gpp++) {
diff --git a/drivers/pinctrl/intel/pinctrl-intel.h b/drivers/pinctrl/intel/pinctrl-intel.h
index 1785abf157e4..9fb4645f3c55 100644
--- a/drivers/pinctrl/intel/pinctrl-intel.h
+++ b/drivers/pinctrl/intel/pinctrl-intel.h
@@ -10,6 +10,8 @@
#ifndef PINCTRL_INTEL_H
#define PINCTRL_INTEL_H
+#include <linux/pm.h>
+
struct pinctrl_pin_desc;
struct platform_device;
struct device;
@@ -25,10 +27,10 @@ struct device;
*/
struct intel_pingroup {
const char *name;
- const unsigned *pins;
+ const unsigned int *pins;
size_t npins;
unsigned short mode;
- const unsigned *modes;
+ const unsigned int *modes;
};
/**
@@ -56,11 +58,11 @@ struct intel_function {
* to specify them.
*/
struct intel_padgroup {
- unsigned reg_num;
- unsigned base;
- unsigned size;
+ unsigned int reg_num;
+ unsigned int base;
+ unsigned int size;
int gpio_base;
- unsigned padown_num;
+ unsigned int padown_num;
};
/**
@@ -96,17 +98,17 @@ struct intel_padgroup {
* pass custom @gpps and @ngpps instead.
*/
struct intel_community {
- unsigned barno;
- unsigned padown_offset;
- unsigned padcfglock_offset;
- unsigned hostown_offset;
- unsigned is_offset;
- unsigned ie_offset;
- unsigned pin_base;
- unsigned gpp_size;
- unsigned gpp_num_padown_regs;
+ unsigned int barno;
+ unsigned int padown_offset;
+ unsigned int padcfglock_offset;
+ unsigned int hostown_offset;
+ unsigned int is_offset;
+ unsigned int ie_offset;
+ unsigned int pin_base;
+ unsigned int gpp_size;
+ unsigned int gpp_num_padown_regs;
size_t npins;
- unsigned features;
+ unsigned int features;
const struct intel_padgroup *gpps;
size_t ngpps;
/* Reserved for the core driver */
@@ -173,9 +175,17 @@ struct intel_pinctrl_soc_data {
int intel_pinctrl_probe(struct platform_device *pdev,
const struct intel_pinctrl_soc_data *soc_data);
+int intel_pinctrl_probe_by_hid(struct platform_device *pdev);
+int intel_pinctrl_probe_by_uid(struct platform_device *pdev);
+
#ifdef CONFIG_PM_SLEEP
int intel_pinctrl_suspend(struct device *dev);
int intel_pinctrl_resume(struct device *dev);
#endif
+#define INTEL_PINCTRL_PM_OPS(_name) \
+const struct dev_pm_ops _name = { \
+ SET_LATE_SYSTEM_SLEEP_PM_OPS(intel_pinctrl_suspend, intel_pinctrl_resume) \
+}
+
#endif /* PINCTRL_INTEL_H */
diff --git a/drivers/pinctrl/intel/pinctrl-lewisburg.c b/drivers/pinctrl/intel/pinctrl-lewisburg.c
index 99894647eddd..70ea9c518460 100644
--- a/drivers/pinctrl/intel/pinctrl-lewisburg.c
+++ b/drivers/pinctrl/intel/pinctrl-lewisburg.c
@@ -9,7 +9,7 @@
#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/pm.h>
+
#include <linux/pinctrl/pinctrl.h>
#include "pinctrl-intel.h"
@@ -313,10 +313,7 @@ static int lbg_pinctrl_probe(struct platform_device *pdev)
return intel_pinctrl_probe(pdev, &lbg_soc_data);
}
-static const struct dev_pm_ops lbg_pinctrl_pm_ops = {
- SET_LATE_SYSTEM_SLEEP_PM_OPS(intel_pinctrl_suspend,
- intel_pinctrl_resume)
-};
+static INTEL_PINCTRL_PM_OPS(lbg_pinctrl_pm_ops);
static const struct acpi_device_id lbg_pinctrl_acpi_match[] = {
{ "INT3536" },
diff --git a/drivers/pinctrl/intel/pinctrl-merrifield.c b/drivers/pinctrl/intel/pinctrl-merrifield.c
index 4fa69f988c7b..2e9988dac55f 100644
--- a/drivers/pinctrl/intel/pinctrl-merrifield.c
+++ b/drivers/pinctrl/intel/pinctrl-merrifield.c
@@ -476,6 +476,34 @@ static void __iomem *mrfld_get_bufcfg(struct mrfld_pinctrl *mp, unsigned int pin
return family->regs + BUFCFG_OFFSET + bufno * 4;
}
+static int mrfld_read_bufcfg(struct mrfld_pinctrl *mp, unsigned int pin, u32 *value)
+{
+ void __iomem *bufcfg;
+
+ if (!mrfld_buf_available(mp, pin))
+ return -EBUSY;
+
+ bufcfg = mrfld_get_bufcfg(mp, pin);
+ *value = readl(bufcfg);
+
+ return 0;
+}
+
+static void mrfld_update_bufcfg(struct mrfld_pinctrl *mp, unsigned int pin,
+ u32 bits, u32 mask)
+{
+ void __iomem *bufcfg;
+ u32 value;
+
+ bufcfg = mrfld_get_bufcfg(mp, pin);
+ value = readl(bufcfg);
+
+ value &= ~mask;
+ value |= bits & mask;
+
+ writel(value, bufcfg);
+}
+
static int mrfld_get_groups_count(struct pinctrl_dev *pctldev)
{
struct mrfld_pinctrl *mp = pinctrl_dev_get_drvdata(pctldev);
@@ -505,17 +533,15 @@ static void mrfld_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
unsigned int pin)
{
struct mrfld_pinctrl *mp = pinctrl_dev_get_drvdata(pctldev);
- void __iomem *bufcfg;
u32 value, mode;
+ int ret;
- if (!mrfld_buf_available(mp, pin)) {
+ ret = mrfld_read_bufcfg(mp, pin, &value);
+ if (ret) {
seq_puts(s, "not available");
return;
}
- bufcfg = mrfld_get_bufcfg(mp, pin);
- value = readl(bufcfg);
-
mode = (value & BUFCFG_PINMODE_MASK) >> BUFCFG_PINMODE_SHIFT;
if (!mode)
seq_puts(s, "GPIO ");
@@ -559,21 +585,6 @@ static int mrfld_get_function_groups(struct pinctrl_dev *pctldev,
return 0;
}
-static void mrfld_update_bufcfg(struct mrfld_pinctrl *mp, unsigned int pin,
- u32 bits, u32 mask)
-{
- void __iomem *bufcfg;
- u32 value;
-
- bufcfg = mrfld_get_bufcfg(mp, pin);
- value = readl(bufcfg);
-
- value &= ~mask;
- value |= bits & mask;
-
- writel(value, bufcfg);
-}
-
static int mrfld_pinmux_set_mux(struct pinctrl_dev *pctldev,
unsigned int function,
unsigned int group)
@@ -637,11 +648,12 @@ static int mrfld_config_get(struct pinctrl_dev *pctldev, unsigned int pin,
enum pin_config_param param = pinconf_to_config_param(*config);
u32 value, term;
u16 arg = 0;
+ int ret;
- if (!mrfld_buf_available(mp, pin))
+ ret = mrfld_read_bufcfg(mp, pin, &value);
+ if (ret)
return -ENOTSUPP;
- value = readl(mrfld_get_bufcfg(mp, pin));
term = (value & BUFCFG_PUPD_VAL_MASK) >> BUFCFG_PUPD_VAL_SHIFT;
switch (param) {
diff --git a/drivers/pinctrl/intel/pinctrl-sunrisepoint.c b/drivers/pinctrl/intel/pinctrl-sunrisepoint.c
index 7984392104fe..38a7c811ff58 100644
--- a/drivers/pinctrl/intel/pinctrl-sunrisepoint.c
+++ b/drivers/pinctrl/intel/pinctrl-sunrisepoint.c
@@ -7,10 +7,10 @@
* Mika Westerberg <mika.westerberg@linux.intel.com>
*/
-#include <linux/acpi.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/pm.h>
+
#include <linux/pinctrl/pinctrl.h>
#include "pinctrl-intel.h"
@@ -593,21 +593,10 @@ MODULE_DEVICE_TABLE(acpi, spt_pinctrl_acpi_match);
static int spt_pinctrl_probe(struct platform_device *pdev)
{
- const struct intel_pinctrl_soc_data *soc_data;
- const struct acpi_device_id *id;
-
- id = acpi_match_device(spt_pinctrl_acpi_match, &pdev->dev);
- if (!id || !id->driver_data)
- return -ENODEV;
-
- soc_data = (const struct intel_pinctrl_soc_data *)id->driver_data;
- return intel_pinctrl_probe(pdev, soc_data);
+ return intel_pinctrl_probe_by_hid(pdev);
}
-static const struct dev_pm_ops spt_pinctrl_pm_ops = {
- SET_LATE_SYSTEM_SLEEP_PM_OPS(intel_pinctrl_suspend,
- intel_pinctrl_resume)
-};
+static INTEL_PINCTRL_PM_OPS(spt_pinctrl_pm_ops);
static struct platform_driver spt_pinctrl_driver = {
.probe = spt_pinctrl_probe,
diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig
index 9905dc672f6b..9d142e1da567 100644
--- a/drivers/pinctrl/mediatek/Kconfig
+++ b/drivers/pinctrl/mediatek/Kconfig
@@ -3,7 +3,8 @@ menu "MediaTek pinctrl drivers"
config EINT_MTK
bool "MediaTek External Interrupt Support"
- depends on PINCTRL_MTK || PINCTRL_MT7622 || COMPILE_TEST
+ depends on PINCTRL_MTK || PINCTRL_MTK_MOORE || COMPILE_TEST
+ select GPIOLIB
select IRQ_DOMAIN
config PINCTRL_MTK
@@ -15,6 +16,24 @@ config PINCTRL_MTK
select EINT_MTK
select OF_GPIO
+config PINCTRL_MTK_MOORE
+ bool "MediaTek Moore Core that implements generic binding"
+ depends on OF
+ select GENERIC_PINCONF
+ select GENERIC_PINCTRL_GROUPS
+ select GENERIC_PINMUX_FUNCTIONS
+ select GPIOLIB
+ select OF_GPIO
+
+config PINCTRL_MTK_PARIS
+ bool "MediaTek Paris Core that implements vendor binding"
+ depends on OF
+ select PINMUX
+ select GENERIC_PINCONF
+ select GPIOLIB
+ select EINT_MTK
+ select OF_GPIO
+
# For ARMv7 SoCs
config PINCTRL_MT2701
bool "Mediatek MT2701 pin control"
@@ -23,6 +42,12 @@ config PINCTRL_MT2701
default MACH_MT2701
select PINCTRL_MTK
+config PINCTRL_MT7623
+ bool "Mediatek MT7623 pin control with generic binding"
+ depends on MACH_MT7623 || COMPILE_TEST
+ depends on PINCTRL_MTK_MOORE
+ default y
+
config PINCTRL_MT8135
bool "Mediatek MT8135 pin control"
depends on MACH_MT8135 || COMPILE_TEST
@@ -45,15 +70,18 @@ config PINCTRL_MT2712
default ARM64 && ARCH_MEDIATEK
select PINCTRL_MTK
+config PINCTRL_MT6765
+ bool "Mediatek MT6765 pin control"
+ depends on OF
+ depends on ARM64 || COMPILE_TEST
+ default ARM64 && ARCH_MEDIATEK
+ select PINCTRL_MTK_PARIS
+
config PINCTRL_MT7622
bool "MediaTek MT7622 pin control"
- depends on OF
depends on ARM64 || COMPILE_TEST
- select GENERIC_PINCONF
- select GENERIC_PINCTRL_GROUPS
- select GENERIC_PINMUX_FUNCTIONS
- select GPIOLIB
- select OF_GPIO
+ depends on PINCTRL_MTK_MOORE
+ default y
config PINCTRL_MT8173
bool "Mediatek MT8173 pin control"
@@ -62,6 +90,13 @@ config PINCTRL_MT8173
default ARM64 && ARCH_MEDIATEK
select PINCTRL_MTK
+config PINCTRL_MT8183
+ bool "Mediatek MT8183 pin control"
+ depends on OF
+ depends on ARM64 || COMPILE_TEST
+ default ARM64 && ARCH_MEDIATEK
+ select PINCTRL_MTK_PARIS
+
# For PMIC
config PINCTRL_MT6397
bool "Mediatek MT6397 pin control"
diff --git a/drivers/pinctrl/mediatek/Makefile b/drivers/pinctrl/mediatek/Makefile
index 3de7156df345..70d800054f69 100644
--- a/drivers/pinctrl/mediatek/Makefile
+++ b/drivers/pinctrl/mediatek/Makefile
@@ -2,12 +2,17 @@
# Core
obj-$(CONFIG_EINT_MTK) += mtk-eint.o
obj-$(CONFIG_PINCTRL_MTK) += pinctrl-mtk-common.o
+obj-$(CONFIG_PINCTRL_MTK_MOORE) += pinctrl-moore.o pinctrl-mtk-common-v2.o
+obj-$(CONFIG_PINCTRL_MTK_PARIS) += pinctrl-paris.o pinctrl-mtk-common-v2.o
# SoC Drivers
obj-$(CONFIG_PINCTRL_MT2701) += pinctrl-mt2701.o
obj-$(CONFIG_PINCTRL_MT2712) += pinctrl-mt2712.o
obj-$(CONFIG_PINCTRL_MT8135) += pinctrl-mt8135.o
obj-$(CONFIG_PINCTRL_MT8127) += pinctrl-mt8127.o
+obj-$(CONFIG_PINCTRL_MT6765) += pinctrl-mt6765.o
obj-$(CONFIG_PINCTRL_MT7622) += pinctrl-mt7622.o
+obj-$(CONFIG_PINCTRL_MT7623) += pinctrl-mt7623.o
obj-$(CONFIG_PINCTRL_MT8173) += pinctrl-mt8173.o
+obj-$(CONFIG_PINCTRL_MT8183) += pinctrl-mt8183.o
obj-$(CONFIG_PINCTRL_MT6397) += pinctrl-mt6397.o
diff --git a/drivers/pinctrl/mediatek/mtk-eint.c b/drivers/pinctrl/mediatek/mtk-eint.c
index a613e546717a..f464f8cd274b 100644
--- a/drivers/pinctrl/mediatek/mtk-eint.c
+++ b/drivers/pinctrl/mediatek/mtk-eint.c
@@ -11,7 +11,7 @@
#include <linux/delay.h>
#include <linux/err.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/io.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/irqdomain.h>
diff --git a/drivers/pinctrl/mediatek/mtk-eint.h b/drivers/pinctrl/mediatek/mtk-eint.h
index c286a9b940f2..48468d0fae68 100644
--- a/drivers/pinctrl/mediatek/mtk-eint.h
+++ b/drivers/pinctrl/mediatek/mtk-eint.h
@@ -92,13 +92,13 @@ static inline int mtk_eint_do_resume(struct mtk_eint *eint)
return -EOPNOTSUPP;
}
-int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_n,
+static inline int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_n,
unsigned int debounce)
{
return -EOPNOTSUPP;
}
-int mtk_eint_find_irq(struct mtk_eint *eint, unsigned long eint_n)
+static inline int mtk_eint_find_irq(struct mtk_eint *eint, unsigned long eint_n)
{
return -EOPNOTSUPP;
}
diff --git a/drivers/pinctrl/mediatek/pinctrl-moore.c b/drivers/pinctrl/mediatek/pinctrl-moore.c
new file mode 100644
index 000000000000..3133ec0f2e67
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-moore.c
@@ -0,0 +1,690 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek Pinctrl Moore Driver, which implement the generic dt-binding
+ * pinctrl-bindings.txt for MediaTek SoC.
+ *
+ * Copyright (C) 2017-2018 MediaTek Inc.
+ * Author: Sean Wang <sean.wang@mediatek.com>
+ *
+ */
+
+#include <linux/gpio/driver.h>
+#include "pinctrl-moore.h"
+
+#define PINCTRL_PINCTRL_DEV KBUILD_MODNAME
+
+/* Custom pinconf parameters */
+#define MTK_PIN_CONFIG_TDSEL (PIN_CONFIG_END + 1)
+#define MTK_PIN_CONFIG_RDSEL (PIN_CONFIG_END + 2)
+#define MTK_PIN_CONFIG_PU_ADV (PIN_CONFIG_END + 3)
+#define MTK_PIN_CONFIG_PD_ADV (PIN_CONFIG_END + 4)
+
+static const struct pinconf_generic_params mtk_custom_bindings[] = {
+ {"mediatek,tdsel", MTK_PIN_CONFIG_TDSEL, 0},
+ {"mediatek,rdsel", MTK_PIN_CONFIG_RDSEL, 0},
+ {"mediatek,pull-up-adv", MTK_PIN_CONFIG_PU_ADV, 1},
+ {"mediatek,pull-down-adv", MTK_PIN_CONFIG_PD_ADV, 1},
+};
+
+#ifdef CONFIG_DEBUG_FS
+static const struct pin_config_item mtk_conf_items[] = {
+ PCONFDUMP(MTK_PIN_CONFIG_TDSEL, "tdsel", NULL, true),
+ PCONFDUMP(MTK_PIN_CONFIG_RDSEL, "rdsel", NULL, true),
+ PCONFDUMP(MTK_PIN_CONFIG_PU_ADV, "pu-adv", NULL, true),
+ PCONFDUMP(MTK_PIN_CONFIG_PD_ADV, "pd-adv", NULL, true),
+};
+#endif
+
+static int mtk_pinmux_set_mux(struct pinctrl_dev *pctldev,
+ unsigned int selector, unsigned int group)
+{
+ struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev);
+ struct function_desc *func;
+ struct group_desc *grp;
+ int i;
+
+ func = pinmux_generic_get_function(pctldev, selector);
+ if (!func)
+ return -EINVAL;
+
+ grp = pinctrl_generic_get_group(pctldev, group);
+ if (!grp)
+ return -EINVAL;
+
+ dev_dbg(pctldev->dev, "enable function %s group %s\n",
+ func->name, grp->name);
+
+ for (i = 0; i < grp->num_pins; i++) {
+ const struct mtk_pin_desc *desc;
+ int *pin_modes = grp->data;
+ int pin = grp->pins[i];
+
+ desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin];
+
+ mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_MODE,
+ pin_modes[i]);
+ }
+
+ return 0;
+}
+
+static int mtk_pinmux_gpio_request_enable(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned int pin)
+{
+ struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev);
+ const struct mtk_pin_desc *desc;
+
+ desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin];
+
+ return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_MODE,
+ hw->soc->gpio_m);
+}
+
+static int mtk_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned int pin, bool input)
+{
+ struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev);
+ const struct mtk_pin_desc *desc;
+
+ desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin];
+
+ /* hardware would take 0 as input direction */
+ return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, !input);
+}
+
+static int mtk_pinconf_get(struct pinctrl_dev *pctldev,
+ unsigned int pin, unsigned long *config)
+{
+ struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev);
+ u32 param = pinconf_to_config_param(*config);
+ int val, val2, err, reg, ret = 1;
+ const struct mtk_pin_desc *desc;
+
+ desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin];
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ if (hw->soc->bias_disable_get) {
+ err = hw->soc->bias_disable_get(hw, desc, &ret);
+ if (err)
+ return err;
+ } else {
+ return -ENOTSUPP;
+ }
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ if (hw->soc->bias_get) {
+ err = hw->soc->bias_get(hw, desc, 1, &ret);
+ if (err)
+ return err;
+ } else {
+ return -ENOTSUPP;
+ }
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ if (hw->soc->bias_get) {
+ err = hw->soc->bias_get(hw, desc, 0, &ret);
+ if (err)
+ return err;
+ } else {
+ return -ENOTSUPP;
+ }
+ break;
+ case PIN_CONFIG_SLEW_RATE:
+ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_SR, &val);
+ if (err)
+ return err;
+
+ if (!val)
+ return -EINVAL;
+
+ break;
+ case PIN_CONFIG_INPUT_ENABLE:
+ case PIN_CONFIG_OUTPUT_ENABLE:
+ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DIR, &val);
+ if (err)
+ return err;
+
+ /* HW takes input mode as zero; output mode as non-zero */
+ if ((val && param == PIN_CONFIG_INPUT_ENABLE) ||
+ (!val && param == PIN_CONFIG_OUTPUT_ENABLE))
+ return -EINVAL;
+
+ break;
+ case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DIR, &val);
+ if (err)
+ return err;
+
+ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_SMT, &val2);
+ if (err)
+ return err;
+
+ if (val || !val2)
+ return -EINVAL;
+
+ break;
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ if (hw->soc->drive_get) {
+ err = hw->soc->drive_get(hw, desc, &ret);
+ if (err)
+ return err;
+ } else {
+ err = -ENOTSUPP;
+ }
+ break;
+ case MTK_PIN_CONFIG_TDSEL:
+ case MTK_PIN_CONFIG_RDSEL:
+ reg = (param == MTK_PIN_CONFIG_TDSEL) ?
+ PINCTRL_PIN_REG_TDSEL : PINCTRL_PIN_REG_RDSEL;
+
+ err = mtk_hw_get_value(hw, desc, reg, &val);
+ if (err)
+ return err;
+
+ ret = val;
+
+ break;
+ case MTK_PIN_CONFIG_PU_ADV:
+ case MTK_PIN_CONFIG_PD_ADV:
+ if (hw->soc->adv_pull_get) {
+ bool pullup;
+
+ pullup = param == MTK_PIN_CONFIG_PU_ADV;
+ err = hw->soc->adv_pull_get(hw, desc, pullup, &ret);
+ if (err)
+ return err;
+ } else {
+ return -ENOTSUPP;
+ }
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ *config = pinconf_to_config_packed(param, ret);
+
+ return 0;
+}
+
+static int mtk_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
+ unsigned long *configs, unsigned int num_configs)
+{
+ struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev);
+ const struct mtk_pin_desc *desc;
+ u32 reg, param, arg;
+ int cfg, err = 0;
+
+ desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin];
+
+ for (cfg = 0; cfg < num_configs; cfg++) {
+ param = pinconf_to_config_param(configs[cfg]);
+ arg = pinconf_to_config_argument(configs[cfg]);
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ if (hw->soc->bias_disable_set) {
+ err = hw->soc->bias_disable_set(hw, desc);
+ if (err)
+ return err;
+ } else {
+ return -ENOTSUPP;
+ }
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ if (hw->soc->bias_set) {
+ err = hw->soc->bias_set(hw, desc, 1);
+ if (err)
+ return err;
+ } else {
+ return -ENOTSUPP;
+ }
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ if (hw->soc->bias_set) {
+ err = hw->soc->bias_set(hw, desc, 0);
+ if (err)
+ return err;
+ } else {
+ return -ENOTSUPP;
+ }
+ break;
+ case PIN_CONFIG_OUTPUT_ENABLE:
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_SMT,
+ MTK_DISABLE);
+ if (err)
+ goto err;
+
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR,
+ MTK_OUTPUT);
+ if (err)
+ goto err;
+ break;
+ case PIN_CONFIG_INPUT_ENABLE:
+
+ if (hw->soc->ies_present) {
+ mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_IES,
+ MTK_ENABLE);
+ }
+
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR,
+ MTK_INPUT);
+ if (err)
+ goto err;
+ break;
+ case PIN_CONFIG_SLEW_RATE:
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_SR,
+ arg);
+ if (err)
+ goto err;
+
+ break;
+ case PIN_CONFIG_OUTPUT:
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR,
+ MTK_OUTPUT);
+ if (err)
+ goto err;
+
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DO,
+ arg);
+ if (err)
+ goto err;
+ break;
+ case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+ /* arg = 1: Input mode & SMT enable ;
+ * arg = 0: Output mode & SMT disable
+ */
+ arg = arg ? 2 : 1;
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR,
+ arg & 1);
+ if (err)
+ goto err;
+
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_SMT,
+ !!(arg & 2));
+ if (err)
+ goto err;
+ break;
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ if (hw->soc->drive_set) {
+ err = hw->soc->drive_set(hw, desc, arg);
+ if (err)
+ return err;
+ } else {
+ err = -ENOTSUPP;
+ }
+ break;
+ case MTK_PIN_CONFIG_TDSEL:
+ case MTK_PIN_CONFIG_RDSEL:
+ reg = (param == MTK_PIN_CONFIG_TDSEL) ?
+ PINCTRL_PIN_REG_TDSEL : PINCTRL_PIN_REG_RDSEL;
+
+ err = mtk_hw_set_value(hw, desc, reg, arg);
+ if (err)
+ goto err;
+ break;
+ case MTK_PIN_CONFIG_PU_ADV:
+ case MTK_PIN_CONFIG_PD_ADV:
+ if (hw->soc->adv_pull_set) {
+ bool pullup;
+
+ pullup = param == MTK_PIN_CONFIG_PU_ADV;
+ err = hw->soc->adv_pull_set(hw, desc, pullup,
+ arg);
+ if (err)
+ return err;
+ } else {
+ return -ENOTSUPP;
+ }
+ break;
+ default:
+ err = -ENOTSUPP;
+ }
+ }
+err:
+ return err;
+}
+
+static int mtk_pinconf_group_get(struct pinctrl_dev *pctldev,
+ unsigned int group, unsigned long *config)
+{
+ const unsigned int *pins;
+ unsigned int i, npins, old = 0;
+ int ret;
+
+ ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < npins; i++) {
+ if (mtk_pinconf_get(pctldev, pins[i], config))
+ return -ENOTSUPP;
+
+ /* configs do not match between two pins */
+ if (i && old != *config)
+ return -ENOTSUPP;
+
+ old = *config;
+ }
+
+ return 0;
+}
+
+static int mtk_pinconf_group_set(struct pinctrl_dev *pctldev,
+ unsigned int group, unsigned long *configs,
+ unsigned int num_configs)
+{
+ const unsigned int *pins;
+ unsigned int i, npins;
+ int ret;
+
+ ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < npins; i++) {
+ ret = mtk_pinconf_set(pctldev, pins[i], configs, num_configs);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct pinctrl_ops mtk_pctlops = {
+ .get_groups_count = pinctrl_generic_get_group_count,
+ .get_group_name = pinctrl_generic_get_group_name,
+ .get_group_pins = pinctrl_generic_get_group_pins,
+ .dt_node_to_map = pinconf_generic_dt_node_to_map_all,
+ .dt_free_map = pinconf_generic_dt_free_map,
+};
+
+static const struct pinmux_ops mtk_pmxops = {
+ .get_functions_count = pinmux_generic_get_function_count,
+ .get_function_name = pinmux_generic_get_function_name,
+ .get_function_groups = pinmux_generic_get_function_groups,
+ .set_mux = mtk_pinmux_set_mux,
+ .gpio_request_enable = mtk_pinmux_gpio_request_enable,
+ .gpio_set_direction = mtk_pinmux_gpio_set_direction,
+ .strict = true,
+};
+
+static const struct pinconf_ops mtk_confops = {
+ .is_generic = true,
+ .pin_config_get = mtk_pinconf_get,
+ .pin_config_set = mtk_pinconf_set,
+ .pin_config_group_get = mtk_pinconf_group_get,
+ .pin_config_group_set = mtk_pinconf_group_set,
+ .pin_config_config_dbg_show = pinconf_generic_dump_config,
+};
+
+static struct pinctrl_desc mtk_desc = {
+ .name = PINCTRL_PINCTRL_DEV,
+ .pctlops = &mtk_pctlops,
+ .pmxops = &mtk_pmxops,
+ .confops = &mtk_confops,
+ .owner = THIS_MODULE,
+};
+
+static int mtk_gpio_get(struct gpio_chip *chip, unsigned int gpio)
+{
+ struct mtk_pinctrl *hw = gpiochip_get_data(chip);
+ const struct mtk_pin_desc *desc;
+ int value, err;
+
+ desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio];
+
+ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DI, &value);
+ if (err)
+ return err;
+
+ return !!value;
+}
+
+static void mtk_gpio_set(struct gpio_chip *chip, unsigned int gpio, int value)
+{
+ struct mtk_pinctrl *hw = gpiochip_get_data(chip);
+ const struct mtk_pin_desc *desc;
+
+ desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio];
+
+ mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DO, !!value);
+}
+
+static int mtk_gpio_direction_input(struct gpio_chip *chip, unsigned int gpio)
+{
+ return pinctrl_gpio_direction_input(chip->base + gpio);
+}
+
+static int mtk_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio,
+ int value)
+{
+ mtk_gpio_set(chip, gpio, value);
+
+ return pinctrl_gpio_direction_output(chip->base + gpio);
+}
+
+static int mtk_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
+{
+ struct mtk_pinctrl *hw = gpiochip_get_data(chip);
+ const struct mtk_pin_desc *desc;
+
+ if (!hw->eint)
+ return -ENOTSUPP;
+
+ desc = (const struct mtk_pin_desc *)&hw->soc->pins[offset];
+
+ if (desc->eint.eint_n == (u16)EINT_NA)
+ return -ENOTSUPP;
+
+ return mtk_eint_find_irq(hw->eint, desc->eint.eint_n);
+}
+
+static int mtk_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
+ unsigned long config)
+{
+ struct mtk_pinctrl *hw = gpiochip_get_data(chip);
+ const struct mtk_pin_desc *desc;
+ u32 debounce;
+
+ desc = (const struct mtk_pin_desc *)&hw->soc->pins[offset];
+
+ if (!hw->eint ||
+ pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE ||
+ desc->eint.eint_n == (u16)EINT_NA)
+ return -ENOTSUPP;
+
+ debounce = pinconf_to_config_argument(config);
+
+ return mtk_eint_set_debounce(hw->eint, desc->eint.eint_n, debounce);
+}
+
+static int mtk_build_gpiochip(struct mtk_pinctrl *hw, struct device_node *np)
+{
+ struct gpio_chip *chip = &hw->chip;
+ int ret;
+
+ chip->label = PINCTRL_PINCTRL_DEV;
+ chip->parent = hw->dev;
+ chip->request = gpiochip_generic_request;
+ chip->free = gpiochip_generic_free;
+ chip->direction_input = mtk_gpio_direction_input;
+ chip->direction_output = mtk_gpio_direction_output;
+ chip->get = mtk_gpio_get;
+ chip->set = mtk_gpio_set;
+ chip->to_irq = mtk_gpio_to_irq,
+ chip->set_config = mtk_gpio_set_config,
+ chip->base = -1;
+ chip->ngpio = hw->soc->npins;
+ chip->of_node = np;
+ chip->of_gpio_n_cells = 2;
+
+ ret = gpiochip_add_data(chip, hw);
+ if (ret < 0)
+ return ret;
+
+ /* Just for backward compatible for these old pinctrl nodes without
+ * "gpio-ranges" property. Otherwise, called directly from a
+ * DeviceTree-supported pinctrl driver is DEPRECATED.
+ * Please see Section 2.1 of
+ * Documentation/devicetree/bindings/gpio/gpio.txt on how to
+ * bind pinctrl and gpio drivers via the "gpio-ranges" property.
+ */
+ if (!of_find_property(np, "gpio-ranges", NULL)) {
+ ret = gpiochip_add_pin_range(chip, dev_name(hw->dev), 0, 0,
+ chip->ngpio);
+ if (ret < 0) {
+ gpiochip_remove(chip);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int mtk_build_groups(struct mtk_pinctrl *hw)
+{
+ int err, i;
+
+ for (i = 0; i < hw->soc->ngrps; i++) {
+ const struct group_desc *group = hw->soc->grps + i;
+
+ err = pinctrl_generic_add_group(hw->pctrl, group->name,
+ group->pins, group->num_pins,
+ group->data);
+ if (err < 0) {
+ dev_err(hw->dev, "Failed to register group %s\n",
+ group->name);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static int mtk_build_functions(struct mtk_pinctrl *hw)
+{
+ int i, err;
+
+ for (i = 0; i < hw->soc->nfuncs ; i++) {
+ const struct function_desc *func = hw->soc->funcs + i;
+
+ err = pinmux_generic_add_function(hw->pctrl, func->name,
+ func->group_names,
+ func->num_group_names,
+ func->data);
+ if (err < 0) {
+ dev_err(hw->dev, "Failed to register function %s\n",
+ func->name);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+int mtk_moore_pinctrl_probe(struct platform_device *pdev,
+ const struct mtk_pin_soc *soc)
+{
+ struct pinctrl_pin_desc *pins;
+ struct resource *res;
+ struct mtk_pinctrl *hw;
+ int err, i;
+
+ hw = devm_kzalloc(&pdev->dev, sizeof(*hw), GFP_KERNEL);
+ if (!hw)
+ return -ENOMEM;
+
+ hw->soc = soc;
+ hw->dev = &pdev->dev;
+
+ if (!hw->soc->nbase_names) {
+ dev_err(&pdev->dev,
+ "SoC should be assigned at least one register base\n");
+ return -EINVAL;
+ }
+
+ hw->base = devm_kmalloc_array(&pdev->dev, hw->soc->nbase_names,
+ sizeof(*hw->base), GFP_KERNEL);
+ if (!hw->base)
+ return -ENOMEM;
+
+ for (i = 0; i < hw->soc->nbase_names; i++) {
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ hw->soc->base_names[i]);
+ if (!res) {
+ dev_err(&pdev->dev, "missing IO resource\n");
+ return -ENXIO;
+ }
+
+ hw->base[i] = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(hw->base[i]))
+ return PTR_ERR(hw->base[i]);
+ }
+
+ hw->nbase = hw->soc->nbase_names;
+
+ /* Copy from internal struct mtk_pin_desc to register to the core */
+ pins = devm_kmalloc_array(&pdev->dev, hw->soc->npins, sizeof(*pins),
+ GFP_KERNEL);
+ if (!pins)
+ return -ENOMEM;
+
+ for (i = 0; i < hw->soc->npins; i++) {
+ pins[i].number = hw->soc->pins[i].number;
+ pins[i].name = hw->soc->pins[i].name;
+ }
+
+ /* Setup pins descriptions per SoC types */
+ mtk_desc.pins = (const struct pinctrl_pin_desc *)pins;
+ mtk_desc.npins = hw->soc->npins;
+ mtk_desc.num_custom_params = ARRAY_SIZE(mtk_custom_bindings);
+ mtk_desc.custom_params = mtk_custom_bindings;
+#ifdef CONFIG_DEBUG_FS
+ mtk_desc.custom_conf_items = mtk_conf_items;
+#endif
+
+ err = devm_pinctrl_register_and_init(&pdev->dev, &mtk_desc, hw,
+ &hw->pctrl);
+ if (err)
+ return err;
+
+ /* Setup groups descriptions per SoC types */
+ err = mtk_build_groups(hw);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to build groups\n");
+ return err;
+ }
+
+ /* Setup functions descriptions per SoC types */
+ err = mtk_build_functions(hw);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to build functions\n");
+ return err;
+ }
+
+ /* For able to make pinctrl_claim_hogs, we must not enable pinctrl
+ * until all groups and functions are being added one.
+ */
+ err = pinctrl_enable(hw->pctrl);
+ if (err)
+ return err;
+
+ err = mtk_build_eint(hw, pdev);
+ if (err)
+ dev_warn(&pdev->dev,
+ "Failed to add EINT, but pinctrl still can work\n");
+
+ /* Build gpiochip should be after pinctrl_enable is done */
+ err = mtk_build_gpiochip(hw, pdev->dev.of_node);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to add gpio_chip\n");
+ return err;
+ }
+
+ platform_set_drvdata(pdev, hw);
+
+ return 0;
+}
diff --git a/drivers/pinctrl/mediatek/pinctrl-moore.h b/drivers/pinctrl/mediatek/pinctrl-moore.h
new file mode 100644
index 000000000000..e1b4b82b9d3d
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-moore.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2017-2018 MediaTek Inc.
+ *
+ * Author: Sean Wang <sean.wang@mediatek.com>
+ *
+ */
+#ifndef __PINCTRL_MOORE_H
+#define __PINCTRL_MOORE_H
+
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+
+#include "../core.h"
+#include "../pinconf.h"
+#include "../pinmux.h"
+#include "mtk-eint.h"
+#include "pinctrl-mtk-common-v2.h"
+
+#define MTK_RANGE(_a) { .range = (_a), .nranges = ARRAY_SIZE(_a), }
+
+#define MTK_PIN(_number, _name, _eint_m, _eint_n, _drv_n) { \
+ .number = _number, \
+ .name = _name, \
+ .eint = { \
+ .eint_m = _eint_m, \
+ .eint_n = _eint_n, \
+ }, \
+ .drv_n = _drv_n, \
+ .funcs = NULL, \
+ }
+
+#define PINCTRL_PIN_GROUP(name, id) \
+ { \
+ name, \
+ id##_pins, \
+ ARRAY_SIZE(id##_pins), \
+ id##_funcs, \
+ }
+
+int mtk_moore_pinctrl_probe(struct platform_device *pdev,
+ const struct mtk_pin_soc *soc);
+
+#endif /* __PINCTRL_MOORE_H */
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt6765.c b/drivers/pinctrl/mediatek/pinctrl-mt6765.c
new file mode 100644
index 000000000000..32451e8693be
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-mt6765.c
@@ -0,0 +1,1108 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ *
+ * Author: ZH Chen <zh.chen@mediatek.com>
+ *
+ */
+
+#include "pinctrl-mtk-mt6765.h"
+#include "pinctrl-paris.h"
+
+/* MT6765 have multiple bases to program pin configuration listed as the below:
+ * iocfg[0]:0x10005000, iocfg[1]:0x10002C00, iocfg[2]:0x10002800,
+ * iocfg[3]:0x10002A00, iocfg[4]:0x10002000, iocfg[5]:0x10002200,
+ * iocfg[6]:0x10002500, iocfg[7]:0x10002600.
+ * _i_base could be used to indicate what base the pin should be mapped into.
+ */
+
+#define PIN_FIELD_BASE(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, _x_bits) \
+ PIN_FIELD_CALC(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, \
+ _x_bits, 32, 0)
+
+#define PINS_FIELD_BASE(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, _x_bits) \
+ PIN_FIELD_CALC(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, \
+ _x_bits, 32, 1)
+
+static const struct mtk_pin_field_calc mt6765_pin_mode_range[] = {
+ PIN_FIELD(0, 202, 0x300, 0x10, 0, 4),
+};
+
+static const struct mtk_pin_field_calc mt6765_pin_dir_range[] = {
+ PIN_FIELD(0, 202, 0x0, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt6765_pin_di_range[] = {
+ PIN_FIELD(0, 202, 0x200, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt6765_pin_do_range[] = {
+ PIN_FIELD(0, 202, 0x100, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt6765_pin_smt_range[] = {
+ PINS_FIELD_BASE(0, 3, 2, 0x00b0, 0x10, 4, 1),
+ PINS_FIELD_BASE(4, 7, 2, 0x00b0, 0x10, 5, 1),
+ PIN_FIELD_BASE(8, 8, 3, 0x0080, 0x10, 3, 1),
+ PINS_FIELD_BASE(9, 11, 2, 0x00b0, 0x10, 6, 1),
+ PIN_FIELD_BASE(12, 12, 5, 0x0060, 0x10, 9, 1),
+ PINS_FIELD_BASE(13, 16, 6, 0x00b0, 0x10, 10, 1),
+ PINS_FIELD_BASE(17, 20, 6, 0x00b0, 0x10, 8, 1),
+ PINS_FIELD_BASE(21, 24, 6, 0x00b0, 0x10, 9, 1),
+ PINS_FIELD_BASE(25, 28, 6, 0x00b0, 0x10, 7, 1),
+ PIN_FIELD_BASE(29, 29, 6, 0x00b0, 0x10, 0, 1),
+ PIN_FIELD_BASE(30, 30, 6, 0x00b0, 0x10, 1, 1),
+ PINS_FIELD_BASE(31, 34, 6, 0x00b0, 0x10, 2, 1),
+ PINS_FIELD_BASE(35, 36, 6, 0x00b0, 0x10, 5, 1),
+ PIN_FIELD_BASE(37, 37, 6, 0x00b0, 0x10, 6, 1),
+ PIN_FIELD_BASE(38, 38, 6, 0x00b0, 0x10, 4, 1),
+ PINS_FIELD_BASE(39, 40, 6, 0x00b0, 0x10, 3, 1),
+ PINS_FIELD_BASE(41, 42, 7, 0x00c0, 0x10, 6, 1),
+ PIN_FIELD_BASE(43, 43, 7, 0x00c0, 0x10, 3, 1),
+ PIN_FIELD_BASE(44, 44, 7, 0x00c0, 0x10, 4, 1),
+ PIN_FIELD_BASE(45, 45, 7, 0x00c0, 0x10, 8, 1),
+ PINS_FIELD_BASE(46, 47, 7, 0x00c0, 0x10, 7, 1),
+ PIN_FIELD_BASE(48, 48, 7, 0x00c0, 0x10, 15, 1),
+ PIN_FIELD_BASE(49, 49, 7, 0x00c0, 0x10, 17, 1),
+ PIN_FIELD_BASE(50, 50, 7, 0x00c0, 0x10, 14, 1),
+ PIN_FIELD_BASE(51, 51, 7, 0x00c0, 0x10, 16, 1),
+ PINS_FIELD_BASE(52, 57, 7, 0x00c0, 0x10, 0, 1),
+ PINS_FIELD_BASE(58, 60, 7, 0x00c0, 0x10, 12, 1),
+ PINS_FIELD_BASE(61, 62, 3, 0x0080, 0x10, 5, 1),
+ PINS_FIELD_BASE(63, 64, 3, 0x0080, 0x10, 4, 1),
+ PINS_FIELD_BASE(65, 66, 3, 0x0080, 0x10, 7, 1),
+ PINS_FIELD_BASE(67, 68, 3, 0x0080, 0x10, 6, 1),
+ PINS_FIELD_BASE(69, 73, 3, 0x0080, 0x10, 1, 1),
+ PINS_FIELD_BASE(74, 78, 3, 0x0080, 0x10, 2, 1),
+ PINS_FIELD_BASE(79, 80, 3, 0x0080, 0x10, 0, 1),
+ PIN_FIELD_BASE(81, 81, 3, 0x0080, 0x10, 12, 1),
+ PIN_FIELD_BASE(82, 82, 3, 0x0080, 0x10, 11, 1),
+ PIN_FIELD_BASE(83, 83, 3, 0x0080, 0x10, 9, 1),
+ PIN_FIELD_BASE(84, 84, 3, 0x0080, 0x10, 10, 1),
+ PIN_FIELD_BASE(85, 85, 7, 0x00c0, 0x10, 12, 1),
+ PIN_FIELD_BASE(86, 86, 7, 0x00c0, 0x10, 13, 1),
+ PIN_FIELD_BASE(87, 87, 7, 0x00c0, 0x10, 2, 1),
+ PIN_FIELD_BASE(88, 88, 7, 0x00c0, 0x10, 1, 1),
+ PIN_FIELD_BASE(89, 89, 2, 0x00b0, 0x10, 13, 1),
+ PIN_FIELD_BASE(90, 90, 3, 0x0080, 0x10, 8, 1),
+ PINS_FIELD_BASE(91, 92, 2, 0x00b0, 0x10, 8, 1),
+ PINS_FIELD_BASE(93, 94, 2, 0x00b0, 0x10, 7, 1),
+ PINS_FIELD_BASE(95, 96, 2, 0x00b0, 0x10, 14, 1),
+ PINS_FIELD_BASE(97, 98, 2, 0x00b0, 0x10, 2, 1),
+ PIN_FIELD_BASE(99, 99, 2, 0x00b0, 0x10, 0, 1),
+ PIN_FIELD_BASE(100, 100, 2, 0x00b0, 0x10, 1, 1),
+ PINS_FIELD_BASE(101, 102, 2, 0x00b0, 0x10, 3, 1),
+ PIN_FIELD_BASE(103, 103, 2, 0x00b0, 0x10, 9, 1),
+ PIN_FIELD_BASE(104, 104, 2, 0x00b0, 0x10, 11, 1),
+ PIN_FIELD_BASE(105, 105, 2, 0x00b0, 0x10, 10, 1),
+ PIN_FIELD_BASE(106, 106, 2, 0x00b0, 0x10, 12, 1),
+ PIN_FIELD_BASE(107, 107, 1, 0x0080, 0x10, 4, 1),
+ PIN_FIELD_BASE(108, 108, 1, 0x0080, 0x10, 3, 1),
+ PIN_FIELD_BASE(109, 109, 1, 0x0080, 0x10, 5, 1),
+ PIN_FIELD_BASE(110, 110, 1, 0x0080, 0x10, 0, 1),
+ PIN_FIELD_BASE(111, 111, 1, 0x0080, 0x10, 1, 1),
+ PIN_FIELD_BASE(112, 112, 1, 0x0080, 0x10, 2, 1),
+ PIN_FIELD_BASE(113, 113, 1, 0x0080, 0x10, 9, 1),
+ PIN_FIELD_BASE(114, 114, 1, 0x0080, 0x10, 10, 1),
+ PIN_FIELD_BASE(115, 115, 1, 0x0080, 0x10, 6, 1),
+ PIN_FIELD_BASE(116, 116, 1, 0x0080, 0x10, 7, 1),
+ PIN_FIELD_BASE(117, 117, 1, 0x0080, 0x10, 12, 1),
+ PIN_FIELD_BASE(118, 118, 1, 0x0080, 0x10, 13, 1),
+ PIN_FIELD_BASE(119, 119, 1, 0x0080, 0x10, 14, 1),
+ PIN_FIELD_BASE(120, 120, 1, 0x0080, 0x10, 11, 1),
+ PIN_FIELD_BASE(121, 121, 1, 0x0080, 0x10, 8, 1),
+ PIN_FIELD_BASE(122, 122, 4, 0x0080, 0x10, 2, 1),
+ PIN_FIELD_BASE(123, 123, 4, 0x0080, 0x10, 3, 1),
+ PIN_FIELD_BASE(124, 124, 4, 0x0080, 0x10, 1, 1),
+ PIN_FIELD_BASE(125, 125, 4, 0x0080, 0x10, 5, 1),
+ PIN_FIELD_BASE(126, 126, 4, 0x0080, 0x10, 7, 1),
+ PIN_FIELD_BASE(127, 127, 4, 0x0080, 0x10, 9, 1),
+ PIN_FIELD_BASE(128, 128, 4, 0x0080, 0x10, 4, 1),
+ PIN_FIELD_BASE(129, 129, 4, 0x0080, 0x10, 8, 1),
+ PIN_FIELD_BASE(130, 130, 4, 0x0080, 0x10, 10, 1),
+ PIN_FIELD_BASE(131, 131, 4, 0x0080, 0x10, 11, 1),
+ PIN_FIELD_BASE(132, 132, 4, 0x0080, 0x10, 6, 1),
+ PIN_FIELD_BASE(133, 133, 4, 0x0080, 0x10, 12, 1),
+ PIN_FIELD_BASE(134, 134, 5, 0x0060, 0x10, 11, 1),
+ PIN_FIELD_BASE(135, 135, 5, 0x0060, 0x10, 13, 1),
+ PIN_FIELD_BASE(136, 136, 5, 0x0060, 0x10, 1, 1),
+ PIN_FIELD_BASE(137, 137, 5, 0x0060, 0x10, 7, 1),
+ PIN_FIELD_BASE(138, 138, 5, 0x0060, 0x10, 4, 1),
+ PIN_FIELD_BASE(139, 139, 5, 0x0060, 0x10, 5, 1),
+ PIN_FIELD_BASE(140, 140, 5, 0x0060, 0x10, 0, 1),
+ PIN_FIELD_BASE(141, 141, 5, 0x0060, 0x10, 6, 1),
+ PIN_FIELD_BASE(142, 142, 5, 0x0060, 0x10, 2, 1),
+ PIN_FIELD_BASE(143, 143, 5, 0x0060, 0x10, 3, 1),
+ PINS_FIELD_BASE(144, 147, 5, 0x0060, 0x10, 10, 1),
+ PINS_FIELD_BASE(148, 149, 5, 0x0060, 0x10, 12, 1),
+ PINS_FIELD_BASE(150, 151, 7, 0x00c0, 0x10, 9, 1),
+ PINS_FIELD_BASE(152, 153, 7, 0x00c0, 0x10, 10, 1),
+ PIN_FIELD_BASE(154, 154, 7, 0x00c0, 0x10, 11, 1),
+ PINS_FIELD_BASE(155, 158, 3, 0x0080, 0x10, 13, 1),
+ PIN_FIELD_BASE(159, 159, 7, 0x00c0, 0x10, 11, 1),
+ PIN_FIELD_BASE(160, 160, 5, 0x0060, 0x10, 8, 1),
+ PIN_FIELD_BASE(161, 161, 1, 0x0080, 0x10, 15, 1),
+ PIN_FIELD_BASE(162, 162, 1, 0x0080, 0x10, 16, 1),
+ PINS_FIELD_BASE(163, 170, 4, 0x0080, 0x10, 0, 1),
+ PINS_FIELD_BASE(171, 179, 7, 0x00c0, 0x10, 5, 1),
+};
+
+static const struct mtk_pin_field_calc mt6765_pin_pd_range[] = {
+ PIN_FIELD_BASE(0, 0, 2, 0x0040, 0x10, 6, 1),
+ PIN_FIELD_BASE(1, 1, 2, 0x0040, 0x10, 7, 1),
+ PIN_FIELD_BASE(2, 2, 2, 0x0040, 0x10, 10, 1),
+ PIN_FIELD_BASE(3, 3, 2, 0x0040, 0x10, 11, 1),
+ PIN_FIELD_BASE(4, 4, 2, 0x0040, 0x10, 12, 1),
+ PIN_FIELD_BASE(5, 5, 2, 0x0040, 0x10, 13, 1),
+ PIN_FIELD_BASE(6, 6, 2, 0x0040, 0x10, 14, 1),
+ PIN_FIELD_BASE(7, 7, 2, 0x0040, 0x10, 15, 1),
+ PIN_FIELD_BASE(8, 8, 3, 0x0040, 0x10, 12, 1),
+ PIN_FIELD_BASE(9, 9, 2, 0x0040, 0x10, 16, 1),
+ PIN_FIELD_BASE(10, 10, 2, 0x0040, 0x10, 8, 1),
+ PIN_FIELD_BASE(11, 11, 2, 0x0040, 0x10, 9, 1),
+ PIN_FIELD_BASE(12, 12, 5, 0x0030, 0x10, 9, 1),
+ PIN_FIELD_BASE(13, 13, 6, 0x0040, 0x10, 14, 1),
+ PIN_FIELD_BASE(14, 14, 6, 0x0040, 0x10, 13, 1),
+ PIN_FIELD_BASE(15, 15, 6, 0x0040, 0x10, 15, 1),
+ PIN_FIELD_BASE(16, 16, 6, 0x0040, 0x10, 12, 1),
+ PIN_FIELD_BASE(17, 17, 6, 0x0040, 0x10, 7, 1),
+ PIN_FIELD_BASE(18, 18, 6, 0x0040, 0x10, 4, 1),
+ PIN_FIELD_BASE(19, 19, 6, 0x0040, 0x10, 6, 1),
+ PIN_FIELD_BASE(20, 20, 6, 0x0040, 0x10, 5, 1),
+ PIN_FIELD_BASE(21, 21, 6, 0x0040, 0x10, 10, 1),
+ PIN_FIELD_BASE(22, 22, 6, 0x0040, 0x10, 9, 1),
+ PIN_FIELD_BASE(23, 23, 6, 0x0040, 0x10, 11, 1),
+ PIN_FIELD_BASE(24, 24, 6, 0x0040, 0x10, 8, 1),
+ PIN_FIELD_BASE(25, 25, 6, 0x0040, 0x10, 2, 1),
+ PIN_FIELD_BASE(26, 26, 6, 0x0040, 0x10, 1, 1),
+ PIN_FIELD_BASE(27, 27, 6, 0x0040, 0x10, 3, 1),
+ PINS_FIELD_BASE(28, 40, 6, 0x0040, 0x10, 0, 1),
+ PIN_FIELD_BASE(41, 41, 7, 0x0060, 0x10, 19, 1),
+ PIN_FIELD_BASE(42, 42, 7, 0x0060, 0x10, 9, 1),
+ PIN_FIELD_BASE(43, 43, 7, 0x0060, 0x10, 8, 1),
+ PIN_FIELD_BASE(44, 44, 7, 0x0060, 0x10, 10, 1),
+ PIN_FIELD_BASE(45, 45, 7, 0x0060, 0x10, 22, 1),
+ PIN_FIELD_BASE(46, 46, 7, 0x0060, 0x10, 21, 1),
+ PIN_FIELD_BASE(47, 47, 7, 0x0060, 0x10, 20, 1),
+ PIN_FIELD_BASE(48, 48, 7, 0x0070, 0x10, 3, 1),
+ PIN_FIELD_BASE(49, 49, 7, 0x0070, 0x10, 5, 1),
+ PIN_FIELD_BASE(50, 50, 7, 0x0070, 0x10, 2, 1),
+ PIN_FIELD_BASE(51, 51, 7, 0x0070, 0x10, 4, 1),
+ PIN_FIELD_BASE(52, 52, 7, 0x0060, 0x10, 1, 1),
+ PIN_FIELD_BASE(53, 53, 7, 0x0060, 0x10, 0, 1),
+ PIN_FIELD_BASE(54, 54, 7, 0x0060, 0x10, 5, 1),
+ PIN_FIELD_BASE(55, 55, 7, 0x0060, 0x10, 3, 1),
+ PIN_FIELD_BASE(56, 56, 7, 0x0060, 0x10, 4, 1),
+ PIN_FIELD_BASE(57, 57, 7, 0x0060, 0x10, 2, 1),
+ PIN_FIELD_BASE(58, 58, 7, 0x0070, 0x10, 0, 1),
+ PIN_FIELD_BASE(59, 59, 7, 0x0060, 0x10, 31, 1),
+ PIN_FIELD_BASE(60, 60, 7, 0x0060, 0x10, 30, 1),
+ PIN_FIELD_BASE(61, 61, 3, 0x0040, 0x10, 18, 1),
+ PIN_FIELD_BASE(62, 62, 3, 0x0040, 0x10, 14, 1),
+ PIN_FIELD_BASE(63, 63, 3, 0x0040, 0x10, 17, 1),
+ PIN_FIELD_BASE(64, 64, 3, 0x0040, 0x10, 13, 1),
+ PIN_FIELD_BASE(65, 65, 3, 0x0040, 0x10, 20, 1),
+ PIN_FIELD_BASE(66, 66, 3, 0x0040, 0x10, 16, 1),
+ PIN_FIELD_BASE(67, 67, 3, 0x0040, 0x10, 19, 1),
+ PIN_FIELD_BASE(68, 68, 3, 0x0040, 0x10, 15, 1),
+ PIN_FIELD_BASE(69, 69, 3, 0x0040, 0x10, 8, 1),
+ PIN_FIELD_BASE(70, 70, 3, 0x0040, 0x10, 7, 1),
+ PIN_FIELD_BASE(71, 71, 3, 0x0040, 0x10, 6, 1),
+ PIN_FIELD_BASE(72, 72, 3, 0x0040, 0x10, 5, 1),
+ PIN_FIELD_BASE(73, 73, 3, 0x0040, 0x10, 4, 1),
+ PIN_FIELD_BASE(74, 74, 3, 0x0040, 0x10, 3, 1),
+ PIN_FIELD_BASE(75, 75, 3, 0x0040, 0x10, 2, 1),
+ PIN_FIELD_BASE(76, 76, 3, 0x0040, 0x10, 1, 1),
+ PIN_FIELD_BASE(77, 77, 3, 0x0040, 0x10, 0, 1),
+ PIN_FIELD_BASE(78, 78, 3, 0x0040, 0x10, 9, 1),
+ PIN_FIELD_BASE(79, 79, 3, 0x0040, 0x10, 11, 1),
+ PIN_FIELD_BASE(80, 80, 3, 0x0040, 0x10, 10, 1),
+ PIN_FIELD_BASE(81, 81, 3, 0x0040, 0x10, 25, 1),
+ PIN_FIELD_BASE(82, 82, 3, 0x0040, 0x10, 24, 1),
+ PIN_FIELD_BASE(83, 83, 3, 0x0040, 0x10, 22, 1),
+ PIN_FIELD_BASE(84, 84, 3, 0x0040, 0x10, 23, 1),
+ PIN_FIELD_BASE(85, 85, 7, 0x0070, 0x10, 1, 1),
+ PIN_FIELD_BASE(86, 86, 7, 0x0060, 0x10, 29, 1),
+ PIN_FIELD_BASE(87, 87, 7, 0x0060, 0x10, 7, 1),
+ PIN_FIELD_BASE(88, 88, 7, 0x0060, 0x10, 6, 1),
+ PIN_FIELD_BASE(89, 89, 2, 0x0040, 0x10, 21, 1),
+ PINS_FIELD_BASE(90, 94, 3, 0x0040, 0x10, 21, 1),
+ PIN_FIELD_BASE(95, 95, 2, 0x0040, 0x10, 22, 1),
+ PIN_FIELD_BASE(96, 96, 2, 0x0040, 0x10, 23, 1),
+ PIN_FIELD_BASE(97, 97, 2, 0x0040, 0x10, 2, 1),
+ PIN_FIELD_BASE(98, 98, 2, 0x0040, 0x10, 3, 1),
+ PIN_FIELD_BASE(99, 99, 2, 0x0040, 0x10, 0, 1),
+ PIN_FIELD_BASE(100, 100, 2, 0x0040, 0x10, 1, 1),
+ PIN_FIELD_BASE(101, 101, 2, 0x0040, 0x10, 4, 1),
+ PIN_FIELD_BASE(102, 102, 2, 0x0040, 0x10, 5, 1),
+ PIN_FIELD_BASE(103, 103, 2, 0x0040, 0x10, 17, 1),
+ PIN_FIELD_BASE(104, 104, 2, 0x0040, 0x10, 19, 1),
+ PIN_FIELD_BASE(105, 105, 2, 0x0040, 0x10, 18, 1),
+ PIN_FIELD_BASE(106, 106, 2, 0x0040, 0x10, 20, 1),
+ PIN_FIELD_BASE(107, 107, 1, 0x0040, 0x10, 4, 1),
+ PIN_FIELD_BASE(108, 108, 1, 0x0040, 0x10, 3, 1),
+ PIN_FIELD_BASE(109, 109, 1, 0x0040, 0x10, 5, 1),
+ PIN_FIELD_BASE(110, 110, 1, 0x0040, 0x10, 0, 1),
+ PIN_FIELD_BASE(111, 111, 1, 0x0040, 0x10, 1, 1),
+ PIN_FIELD_BASE(112, 112, 1, 0x0040, 0x10, 2, 1),
+ PIN_FIELD_BASE(113, 113, 1, 0x0040, 0x10, 9, 1),
+ PIN_FIELD_BASE(114, 114, 1, 0x0040, 0x10, 10, 1),
+ PIN_FIELD_BASE(115, 115, 1, 0x0040, 0x10, 6, 1),
+ PIN_FIELD_BASE(116, 116, 1, 0x0040, 0x10, 7, 1),
+ PIN_FIELD_BASE(117, 117, 1, 0x0040, 0x10, 12, 1),
+ PIN_FIELD_BASE(118, 118, 1, 0x0040, 0x10, 13, 1),
+ PIN_FIELD_BASE(119, 119, 1, 0x0040, 0x10, 14, 1),
+ PIN_FIELD_BASE(120, 120, 1, 0x0040, 0x10, 11, 1),
+ PINS_FIELD_BASE(121, 133, 1, 0x0040, 0x10, 8, 1),
+ PIN_FIELD_BASE(134, 134, 5, 0x0030, 0x10, 14, 1),
+ PIN_FIELD_BASE(135, 135, 5, 0x0030, 0x10, 19, 1),
+ PIN_FIELD_BASE(136, 136, 5, 0x0030, 0x10, 1, 1),
+ PIN_FIELD_BASE(137, 137, 5, 0x0030, 0x10, 7, 1),
+ PIN_FIELD_BASE(138, 138, 5, 0x0030, 0x10, 4, 1),
+ PIN_FIELD_BASE(139, 139, 5, 0x0030, 0x10, 5, 1),
+ PIN_FIELD_BASE(140, 140, 5, 0x0030, 0x10, 0, 1),
+ PIN_FIELD_BASE(141, 141, 5, 0x0030, 0x10, 6, 1),
+ PIN_FIELD_BASE(142, 142, 5, 0x0030, 0x10, 2, 1),
+ PIN_FIELD_BASE(143, 143, 5, 0x0030, 0x10, 3, 1),
+ PIN_FIELD_BASE(144, 144, 5, 0x0030, 0x10, 12, 1),
+ PIN_FIELD_BASE(145, 145, 5, 0x0030, 0x10, 11, 1),
+ PIN_FIELD_BASE(146, 146, 5, 0x0030, 0x10, 13, 1),
+ PIN_FIELD_BASE(147, 147, 5, 0x0030, 0x10, 10, 1),
+ PIN_FIELD_BASE(148, 148, 5, 0x0030, 0x10, 15, 1),
+ PIN_FIELD_BASE(149, 149, 5, 0x0030, 0x10, 16, 1),
+ PIN_FIELD_BASE(150, 150, 7, 0x0060, 0x10, 23, 1),
+ PIN_FIELD_BASE(151, 151, 7, 0x0060, 0x10, 24, 1),
+ PIN_FIELD_BASE(152, 152, 7, 0x0060, 0x10, 25, 1),
+ PIN_FIELD_BASE(153, 153, 7, 0x0060, 0x10, 26, 1),
+ PIN_FIELD_BASE(154, 154, 7, 0x0060, 0x10, 28, 1),
+ PIN_FIELD_BASE(155, 155, 3, 0x0040, 0x10, 28, 1),
+ PIN_FIELD_BASE(156, 156, 3, 0x0040, 0x10, 27, 1),
+ PIN_FIELD_BASE(157, 157, 3, 0x0040, 0x10, 29, 1),
+ PIN_FIELD_BASE(158, 158, 3, 0x0040, 0x10, 26, 1),
+ PIN_FIELD_BASE(159, 159, 7, 0x0060, 0x10, 27, 1),
+ PIN_FIELD_BASE(160, 160, 5, 0x0030, 0x10, 8, 1),
+ PIN_FIELD_BASE(161, 161, 1, 0x0040, 0x10, 15, 1),
+ PIN_FIELD_BASE(162, 162, 1, 0x0040, 0x10, 16, 1),
+ PIN_FIELD_BASE(163, 163, 4, 0x0020, 0x10, 0, 1),
+ PIN_FIELD_BASE(164, 164, 4, 0x0020, 0x10, 1, 1),
+ PIN_FIELD_BASE(165, 165, 4, 0x0020, 0x10, 2, 1),
+ PIN_FIELD_BASE(166, 166, 4, 0x0020, 0x10, 3, 1),
+ PIN_FIELD_BASE(167, 167, 4, 0x0020, 0x10, 4, 1),
+ PIN_FIELD_BASE(168, 168, 4, 0x0020, 0x10, 5, 1),
+ PIN_FIELD_BASE(169, 169, 4, 0x0020, 0x10, 6, 1),
+ PIN_FIELD_BASE(170, 170, 4, 0x0020, 0x10, 7, 1),
+ PIN_FIELD_BASE(171, 171, 7, 0x0060, 0x10, 17, 1),
+ PIN_FIELD_BASE(172, 172, 7, 0x0060, 0x10, 18, 1),
+ PIN_FIELD_BASE(173, 173, 7, 0x0060, 0x10, 11, 1),
+ PIN_FIELD_BASE(174, 174, 7, 0x0060, 0x10, 12, 1),
+ PIN_FIELD_BASE(175, 175, 7, 0x0060, 0x10, 13, 1),
+ PIN_FIELD_BASE(176, 176, 7, 0x0060, 0x10, 14, 1),
+ PIN_FIELD_BASE(177, 177, 7, 0x0060, 0x10, 15, 1),
+ PINS_FIELD_BASE(178, 179, 7, 0x0060, 0x10, 16, 1),
+};
+
+static const struct mtk_pin_field_calc mt6765_pin_pu_range[] = {
+ PIN_FIELD_BASE(0, 0, 2, 0x0060, 0x10, 6, 1),
+ PIN_FIELD_BASE(1, 1, 2, 0x0060, 0x10, 7, 1),
+ PIN_FIELD_BASE(2, 2, 2, 0x0060, 0x10, 10, 1),
+ PIN_FIELD_BASE(3, 3, 2, 0x0060, 0x10, 11, 1),
+ PIN_FIELD_BASE(4, 4, 2, 0x0060, 0x10, 12, 1),
+ PIN_FIELD_BASE(5, 5, 2, 0x0060, 0x10, 13, 1),
+ PIN_FIELD_BASE(6, 6, 2, 0x0060, 0x10, 14, 1),
+ PIN_FIELD_BASE(7, 7, 2, 0x0060, 0x10, 15, 1),
+ PIN_FIELD_BASE(8, 8, 3, 0x0050, 0x10, 12, 1),
+ PIN_FIELD_BASE(9, 9, 2, 0x0060, 0x10, 16, 1),
+ PIN_FIELD_BASE(10, 10, 2, 0x0060, 0x10, 8, 1),
+ PIN_FIELD_BASE(11, 11, 2, 0x0060, 0x10, 9, 1),
+ PIN_FIELD_BASE(12, 12, 5, 0x0040, 0x10, 9, 1),
+ PIN_FIELD_BASE(13, 13, 6, 0x0060, 0x10, 14, 1),
+ PIN_FIELD_BASE(14, 14, 6, 0x0060, 0x10, 13, 1),
+ PIN_FIELD_BASE(15, 15, 6, 0x0060, 0x10, 15, 1),
+ PIN_FIELD_BASE(16, 16, 6, 0x0060, 0x10, 12, 1),
+ PIN_FIELD_BASE(17, 17, 6, 0x0060, 0x10, 7, 1),
+ PIN_FIELD_BASE(18, 18, 6, 0x0060, 0x10, 4, 1),
+ PIN_FIELD_BASE(19, 19, 6, 0x0060, 0x10, 6, 1),
+ PIN_FIELD_BASE(20, 20, 6, 0x0060, 0x10, 5, 1),
+ PIN_FIELD_BASE(21, 21, 6, 0x0060, 0x10, 10, 1),
+ PIN_FIELD_BASE(22, 22, 6, 0x0060, 0x10, 9, 1),
+ PIN_FIELD_BASE(23, 23, 6, 0x0060, 0x10, 11, 1),
+ PIN_FIELD_BASE(24, 24, 6, 0x0060, 0x10, 8, 1),
+ PIN_FIELD_BASE(25, 25, 6, 0x0060, 0x10, 2, 1),
+ PIN_FIELD_BASE(26, 26, 6, 0x0060, 0x10, 1, 1),
+ PIN_FIELD_BASE(27, 27, 6, 0x0060, 0x10, 3, 1),
+ PINS_FIELD_BASE(28, 40, 6, 0x0060, 0x10, 0, 1),
+ PIN_FIELD_BASE(41, 41, 7, 0x0080, 0x10, 19, 1),
+ PIN_FIELD_BASE(42, 42, 7, 0x0080, 0x10, 9, 1),
+ PIN_FIELD_BASE(43, 43, 7, 0x0080, 0x10, 8, 1),
+ PIN_FIELD_BASE(44, 44, 7, 0x0080, 0x10, 10, 1),
+ PIN_FIELD_BASE(45, 45, 7, 0x0080, 0x10, 22, 1),
+ PIN_FIELD_BASE(46, 46, 7, 0x0080, 0x10, 21, 1),
+ PIN_FIELD_BASE(47, 47, 7, 0x0080, 0x10, 20, 1),
+ PIN_FIELD_BASE(48, 48, 7, 0x0090, 0x10, 3, 1),
+ PIN_FIELD_BASE(49, 49, 7, 0x0090, 0x10, 5, 1),
+ PIN_FIELD_BASE(50, 50, 7, 0x0090, 0x10, 2, 1),
+ PIN_FIELD_BASE(51, 51, 7, 0x0090, 0x10, 4, 1),
+ PIN_FIELD_BASE(52, 52, 7, 0x0080, 0x10, 1, 1),
+ PIN_FIELD_BASE(53, 53, 7, 0x0080, 0x10, 0, 1),
+ PIN_FIELD_BASE(54, 54, 7, 0x0080, 0x10, 5, 1),
+ PIN_FIELD_BASE(55, 55, 7, 0x0080, 0x10, 3, 1),
+ PIN_FIELD_BASE(56, 56, 7, 0x0080, 0x10, 4, 1),
+ PIN_FIELD_BASE(57, 57, 7, 0x0080, 0x10, 2, 1),
+ PIN_FIELD_BASE(58, 58, 7, 0x0090, 0x10, 0, 1),
+ PIN_FIELD_BASE(59, 59, 7, 0x0080, 0x10, 31, 1),
+ PIN_FIELD_BASE(60, 60, 7, 0x0080, 0x10, 30, 1),
+ PIN_FIELD_BASE(61, 61, 3, 0x0050, 0x10, 18, 1),
+ PIN_FIELD_BASE(62, 62, 3, 0x0050, 0x10, 14, 1),
+ PIN_FIELD_BASE(63, 63, 3, 0x0050, 0x10, 17, 1),
+ PIN_FIELD_BASE(64, 64, 3, 0x0050, 0x10, 13, 1),
+ PIN_FIELD_BASE(65, 65, 3, 0x0050, 0x10, 20, 1),
+ PIN_FIELD_BASE(66, 66, 3, 0x0050, 0x10, 16, 1),
+ PIN_FIELD_BASE(67, 67, 3, 0x0050, 0x10, 19, 1),
+ PIN_FIELD_BASE(68, 68, 3, 0x0050, 0x10, 15, 1),
+ PIN_FIELD_BASE(69, 69, 3, 0x0050, 0x10, 8, 1),
+ PIN_FIELD_BASE(70, 70, 3, 0x0050, 0x10, 7, 1),
+ PIN_FIELD_BASE(71, 71, 3, 0x0050, 0x10, 6, 1),
+ PIN_FIELD_BASE(72, 72, 3, 0x0050, 0x10, 5, 1),
+ PIN_FIELD_BASE(73, 73, 3, 0x0050, 0x10, 4, 1),
+ PIN_FIELD_BASE(74, 74, 3, 0x0050, 0x10, 3, 1),
+ PIN_FIELD_BASE(75, 75, 3, 0x0050, 0x10, 2, 1),
+ PIN_FIELD_BASE(76, 76, 3, 0x0050, 0x10, 1, 1),
+ PIN_FIELD_BASE(77, 77, 3, 0x0050, 0x10, 0, 1),
+ PIN_FIELD_BASE(78, 78, 3, 0x0050, 0x10, 9, 1),
+ PIN_FIELD_BASE(79, 79, 3, 0x0050, 0x10, 11, 1),
+ PIN_FIELD_BASE(80, 80, 3, 0x0050, 0x10, 10, 1),
+ PIN_FIELD_BASE(81, 81, 3, 0x0050, 0x10, 25, 1),
+ PIN_FIELD_BASE(82, 82, 3, 0x0050, 0x10, 24, 1),
+ PIN_FIELD_BASE(83, 83, 3, 0x0050, 0x10, 22, 1),
+ PIN_FIELD_BASE(84, 84, 3, 0x0050, 0x10, 23, 1),
+ PIN_FIELD_BASE(85, 85, 7, 0x0090, 0x10, 1, 1),
+ PIN_FIELD_BASE(86, 86, 7, 0x0080, 0x10, 29, 1),
+ PIN_FIELD_BASE(87, 87, 7, 0x0080, 0x10, 7, 1),
+ PIN_FIELD_BASE(88, 88, 7, 0x0080, 0x10, 6, 1),
+ PIN_FIELD_BASE(89, 89, 2, 0x0060, 0x10, 21, 1),
+ PINS_FIELD_BASE(90, 94, 3, 0x0050, 0x10, 21, 1),
+ PIN_FIELD_BASE(95, 95, 2, 0x0060, 0x10, 22, 1),
+ PIN_FIELD_BASE(96, 96, 2, 0x0060, 0x10, 23, 1),
+ PIN_FIELD_BASE(97, 97, 2, 0x0060, 0x10, 2, 1),
+ PIN_FIELD_BASE(98, 98, 2, 0x0060, 0x10, 3, 1),
+ PIN_FIELD_BASE(99, 99, 2, 0x0060, 0x10, 0, 1),
+ PIN_FIELD_BASE(100, 100, 2, 0x0060, 0x10, 1, 1),
+ PIN_FIELD_BASE(101, 101, 2, 0x0060, 0x10, 4, 1),
+ PIN_FIELD_BASE(102, 102, 2, 0x0060, 0x10, 5, 1),
+ PIN_FIELD_BASE(103, 103, 2, 0x0060, 0x10, 17, 1),
+ PIN_FIELD_BASE(104, 104, 2, 0x0060, 0x10, 19, 1),
+ PIN_FIELD_BASE(105, 105, 2, 0x0060, 0x10, 18, 1),
+ PIN_FIELD_BASE(106, 106, 2, 0x0060, 0x10, 20, 1),
+ PIN_FIELD_BASE(107, 107, 1, 0x0050, 0x10, 4, 1),
+ PIN_FIELD_BASE(108, 108, 1, 0x0050, 0x10, 3, 1),
+ PIN_FIELD_BASE(109, 109, 1, 0x0050, 0x10, 5, 1),
+ PIN_FIELD_BASE(110, 110, 1, 0x0050, 0x10, 0, 1),
+ PIN_FIELD_BASE(111, 111, 1, 0x0050, 0x10, 1, 1),
+ PIN_FIELD_BASE(112, 112, 1, 0x0050, 0x10, 2, 1),
+ PIN_FIELD_BASE(113, 113, 1, 0x0050, 0x10, 9, 1),
+ PIN_FIELD_BASE(114, 114, 1, 0x0050, 0x10, 10, 1),
+ PIN_FIELD_BASE(115, 115, 1, 0x0050, 0x10, 6, 1),
+ PIN_FIELD_BASE(116, 116, 1, 0x0050, 0x10, 7, 1),
+ PIN_FIELD_BASE(117, 117, 1, 0x0050, 0x10, 12, 1),
+ PIN_FIELD_BASE(118, 118, 1, 0x0050, 0x10, 13, 1),
+ PIN_FIELD_BASE(119, 119, 1, 0x0050, 0x10, 14, 1),
+ PIN_FIELD_BASE(120, 120, 1, 0x0050, 0x10, 11, 1),
+ PINS_FIELD_BASE(121, 133, 1, 0x0050, 0x10, 8, 1),
+ PIN_FIELD_BASE(134, 134, 5, 0x0040, 0x10, 14, 1),
+ PIN_FIELD_BASE(135, 135, 5, 0x0040, 0x10, 19, 1),
+ PIN_FIELD_BASE(136, 136, 5, 0x0040, 0x10, 1, 1),
+ PIN_FIELD_BASE(137, 137, 5, 0x0040, 0x10, 7, 1),
+ PIN_FIELD_BASE(138, 138, 5, 0x0040, 0x10, 4, 1),
+ PIN_FIELD_BASE(139, 139, 5, 0x0040, 0x10, 5, 1),
+ PIN_FIELD_BASE(140, 140, 5, 0x0040, 0x10, 0, 1),
+ PIN_FIELD_BASE(141, 141, 5, 0x0040, 0x10, 6, 1),
+ PIN_FIELD_BASE(142, 142, 5, 0x0040, 0x10, 2, 1),
+ PIN_FIELD_BASE(143, 143, 5, 0x0040, 0x10, 3, 1),
+ PIN_FIELD_BASE(144, 144, 5, 0x0040, 0x10, 12, 1),
+ PIN_FIELD_BASE(145, 145, 5, 0x0040, 0x10, 11, 1),
+ PIN_FIELD_BASE(146, 146, 5, 0x0040, 0x10, 13, 1),
+ PIN_FIELD_BASE(147, 147, 5, 0x0040, 0x10, 10, 1),
+ PIN_FIELD_BASE(148, 148, 5, 0x0040, 0x10, 15, 1),
+ PIN_FIELD_BASE(149, 149, 5, 0x0040, 0x10, 16, 1),
+ PIN_FIELD_BASE(150, 150, 7, 0x0080, 0x10, 23, 1),
+ PIN_FIELD_BASE(151, 151, 7, 0x0080, 0x10, 24, 1),
+ PIN_FIELD_BASE(152, 152, 7, 0x0080, 0x10, 25, 1),
+ PIN_FIELD_BASE(153, 153, 7, 0x0080, 0x10, 26, 1),
+ PIN_FIELD_BASE(154, 154, 7, 0x0080, 0x10, 28, 1),
+ PIN_FIELD_BASE(155, 155, 3, 0x0050, 0x10, 28, 1),
+ PIN_FIELD_BASE(156, 156, 3, 0x0050, 0x10, 27, 1),
+ PIN_FIELD_BASE(157, 157, 3, 0x0050, 0x10, 29, 1),
+ PIN_FIELD_BASE(158, 158, 3, 0x0050, 0x10, 26, 1),
+ PIN_FIELD_BASE(159, 159, 7, 0x0080, 0x10, 27, 1),
+ PIN_FIELD_BASE(160, 160, 5, 0x0040, 0x10, 8, 1),
+ PIN_FIELD_BASE(161, 161, 1, 0x0050, 0x10, 15, 1),
+ PIN_FIELD_BASE(162, 162, 1, 0x0050, 0x10, 16, 1),
+ PIN_FIELD_BASE(163, 163, 4, 0x0040, 0x10, 0, 1),
+ PIN_FIELD_BASE(164, 164, 4, 0x0040, 0x10, 1, 1),
+ PIN_FIELD_BASE(165, 165, 4, 0x0040, 0x10, 2, 1),
+ PIN_FIELD_BASE(166, 166, 4, 0x0040, 0x10, 3, 1),
+ PIN_FIELD_BASE(167, 167, 4, 0x0040, 0x10, 4, 1),
+ PIN_FIELD_BASE(168, 168, 4, 0x0040, 0x10, 5, 1),
+ PIN_FIELD_BASE(169, 169, 4, 0x0040, 0x10, 6, 1),
+ PIN_FIELD_BASE(170, 170, 4, 0x0040, 0x10, 7, 1),
+ PIN_FIELD_BASE(171, 171, 7, 0x0080, 0x10, 17, 1),
+ PIN_FIELD_BASE(172, 172, 7, 0x0080, 0x10, 18, 1),
+ PIN_FIELD_BASE(173, 173, 7, 0x0080, 0x10, 11, 1),
+ PIN_FIELD_BASE(174, 174, 7, 0x0080, 0x10, 12, 1),
+ PIN_FIELD_BASE(175, 175, 7, 0x0080, 0x10, 13, 1),
+ PIN_FIELD_BASE(176, 176, 7, 0x0080, 0x10, 14, 1),
+ PIN_FIELD_BASE(177, 177, 7, 0x0080, 0x10, 15, 1),
+ PINS_FIELD_BASE(178, 179, 7, 0x0080, 0x10, 16, 1),
+};
+
+static const struct mtk_pin_field_calc mt6765_pin_tdsel_range[] = {
+ PINS_FIELD_BASE(0, 3, 2, 0x00c0, 0x10, 16, 4),
+ PINS_FIELD_BASE(4, 7, 2, 0x00c0, 0x10, 20, 4),
+ PIN_FIELD_BASE(8, 8, 3, 0x0090, 0x10, 12, 4),
+ PINS_FIELD_BASE(9, 11, 2, 0x00c0, 0x10, 24, 4),
+ PIN_FIELD_BASE(12, 12, 5, 0x0080, 0x10, 4, 4),
+ PINS_FIELD_BASE(13, 16, 6, 0x00e0, 0x10, 8, 4),
+ PINS_FIELD_BASE(17, 20, 6, 0x00e0, 0x10, 0, 4),
+ PINS_FIELD_BASE(21, 24, 6, 0x00e0, 0x10, 4, 4),
+ PINS_FIELD_BASE(25, 28, 6, 0x00d0, 0x10, 28, 4),
+ PIN_FIELD_BASE(29, 29, 6, 0x00d0, 0x10, 0, 4),
+ PIN_FIELD_BASE(30, 30, 6, 0x00d0, 0x10, 4, 4),
+ PINS_FIELD_BASE(31, 34, 6, 0x00d0, 0x10, 8, 4),
+ PINS_FIELD_BASE(35, 36, 6, 0x00d0, 0x10, 20, 4),
+ PIN_FIELD_BASE(37, 37, 6, 0x00d0, 0x10, 24, 4),
+ PIN_FIELD_BASE(38, 38, 6, 0x00d0, 0x10, 16, 4),
+ PINS_FIELD_BASE(39, 40, 6, 0x00d0, 0x10, 12, 4),
+ PINS_FIELD_BASE(41, 42, 7, 0x00d0, 0x10, 24, 4),
+ PIN_FIELD_BASE(43, 43, 7, 0x00d0, 0x10, 12, 4),
+ PIN_FIELD_BASE(44, 44, 7, 0x00d0, 0x10, 16, 4),
+ PIN_FIELD_BASE(45, 45, 7, 0x00e0, 0x10, 0, 4),
+ PINS_FIELD_BASE(46, 47, 7, 0x00d0, 0x10, 28, 4),
+ PINS_FIELD_BASE(48, 49, 7, 0x00e0, 0x10, 28, 4),
+ PINS_FIELD_BASE(50, 51, 7, 0x00e0, 0x10, 24, 4),
+ PINS_FIELD_BASE(52, 57, 7, 0x00d0, 0x10, 0, 4),
+ PINS_FIELD_BASE(58, 60, 7, 0x00e0, 0x10, 16, 4),
+ PINS_FIELD_BASE(61, 62, 3, 0x0090, 0x10, 20, 4),
+ PINS_FIELD_BASE(63, 64, 3, 0x0090, 0x10, 16, 4),
+ PINS_FIELD_BASE(65, 66, 3, 0x0090, 0x10, 28, 4),
+ PINS_FIELD_BASE(67, 68, 3, 0x0090, 0x10, 24, 4),
+ PINS_FIELD_BASE(69, 73, 3, 0x0090, 0x10, 4, 4),
+ PINS_FIELD_BASE(74, 78, 3, 0x0090, 0x10, 8, 4),
+ PINS_FIELD_BASE(79, 80, 3, 0x0090, 0x10, 0, 4),
+ PIN_FIELD_BASE(81, 81, 3, 0x00a0, 0x10, 8, 4),
+ PINS_FIELD_BASE(82, 83, 3, 0x00a0, 0x10, 4, 4),
+ PIN_FIELD_BASE(84, 84, 3, 0x00a0, 0x10, 8, 4),
+ PIN_FIELD_BASE(85, 85, 7, 0x00e0, 0x10, 16, 4),
+ PIN_FIELD_BASE(86, 86, 7, 0x00e0, 0x10, 20, 4),
+ PIN_FIELD_BASE(87, 87, 7, 0x00d0, 0x10, 8, 4),
+ PIN_FIELD_BASE(88, 88, 7, 0x00d0, 0x10, 4, 4),
+ PIN_FIELD_BASE(89, 89, 2, 0x00d0, 0x10, 12, 4),
+ PIN_FIELD_BASE(90, 90, 3, 0x00a0, 0x10, 0, 4),
+ PINS_FIELD_BASE(91, 92, 2, 0x00d0, 0x10, 0, 4),
+ PINS_FIELD_BASE(93, 94, 2, 0x00c0, 0x10, 28, 4),
+ PINS_FIELD_BASE(95, 96, 2, 0x00d0, 0x10, 16, 4),
+ PINS_FIELD_BASE(97, 98, 2, 0x00c0, 0x10, 8, 4),
+ PIN_FIELD_BASE(99, 99, 2, 0x00c0, 0x10, 0, 4),
+ PIN_FIELD_BASE(100, 100, 2, 0x00c0, 0x10, 4, 4),
+ PINS_FIELD_BASE(101, 102, 2, 0x00c0, 0x10, 12, 4),
+ PINS_FIELD_BASE(103, 104, 2, 0x00d0, 0x10, 4, 4),
+ PINS_FIELD_BASE(105, 106, 2, 0x00d0, 0x10, 8, 4),
+ PIN_FIELD_BASE(107, 107, 1, 0x0090, 0x10, 16, 4),
+ PIN_FIELD_BASE(108, 108, 1, 0x0090, 0x10, 12, 4),
+ PIN_FIELD_BASE(109, 109, 1, 0x0090, 0x10, 20, 4),
+ PIN_FIELD_BASE(110, 110, 1, 0x0090, 0x10, 0, 4),
+ PIN_FIELD_BASE(111, 111, 1, 0x0090, 0x10, 4, 4),
+ PIN_FIELD_BASE(112, 112, 1, 0x0090, 0x10, 8, 4),
+ PIN_FIELD_BASE(113, 113, 1, 0x00a0, 0x10, 4, 4),
+ PIN_FIELD_BASE(114, 114, 1, 0x00a0, 0x10, 8, 4),
+ PIN_FIELD_BASE(115, 115, 1, 0x0090, 0x10, 24, 4),
+ PIN_FIELD_BASE(116, 116, 1, 0x0090, 0x10, 28, 4),
+ PIN_FIELD_BASE(117, 117, 1, 0x00a0, 0x10, 16, 4),
+ PIN_FIELD_BASE(118, 118, 1, 0x00a0, 0x10, 20, 4),
+ PIN_FIELD_BASE(119, 119, 1, 0x00a0, 0x10, 24, 4),
+ PIN_FIELD_BASE(120, 120, 1, 0x00a0, 0x10, 12, 4),
+ PIN_FIELD_BASE(121, 121, 1, 0x00a0, 0x10, 0, 4),
+ PIN_FIELD_BASE(122, 122, 4, 0x0090, 0x10, 8, 4),
+ PIN_FIELD_BASE(123, 123, 4, 0x0090, 0x10, 12, 4),
+ PIN_FIELD_BASE(124, 124, 4, 0x0090, 0x10, 4, 4),
+ PINS_FIELD_BASE(125, 130, 4, 0x0090, 0x10, 12, 4),
+ PIN_FIELD_BASE(131, 131, 4, 0x0090, 0x10, 16, 4),
+ PIN_FIELD_BASE(132, 132, 4, 0x0090, 0x10, 12, 4),
+ PIN_FIELD_BASE(133, 133, 4, 0x0090, 0x10, 20, 4),
+ PIN_FIELD_BASE(134, 134, 5, 0x0080, 0x10, 12, 4),
+ PIN_FIELD_BASE(135, 135, 5, 0x0080, 0x10, 20, 4),
+ PIN_FIELD_BASE(136, 136, 5, 0x0070, 0x10, 4, 4),
+ PIN_FIELD_BASE(137, 137, 5, 0x0070, 0x10, 28, 4),
+ PIN_FIELD_BASE(138, 138, 5, 0x0070, 0x10, 16, 4),
+ PIN_FIELD_BASE(139, 139, 5, 0x0070, 0x10, 20, 4),
+ PIN_FIELD_BASE(140, 140, 5, 0x0070, 0x10, 0, 4),
+ PIN_FIELD_BASE(141, 141, 5, 0x0070, 0x10, 24, 4),
+ PIN_FIELD_BASE(142, 142, 5, 0x0070, 0x10, 8, 4),
+ PIN_FIELD_BASE(143, 143, 5, 0x0070, 0x10, 12, 4),
+ PINS_FIELD_BASE(144, 147, 5, 0x0080, 0x10, 8, 4),
+ PINS_FIELD_BASE(148, 149, 5, 0x0080, 0x10, 16, 4),
+ PINS_FIELD_BASE(150, 151, 7, 0x00e0, 0x10, 4, 4),
+ PINS_FIELD_BASE(152, 153, 7, 0x00e0, 0x10, 8, 4),
+ PIN_FIELD_BASE(154, 154, 7, 0x00e0, 0x10, 12, 4),
+ PINS_FIELD_BASE(155, 158, 3, 0x00a0, 0x10, 12, 4),
+ PIN_FIELD_BASE(159, 159, 7, 0x00e0, 0x10, 12, 4),
+ PIN_FIELD_BASE(160, 160, 5, 0x0080, 0x10, 0, 4),
+ PINS_FIELD_BASE(161, 162, 1, 0x00a0, 0x10, 28, 4),
+ PINS_FIELD_BASE(163, 170, 4, 0x0090, 0x10, 0, 4),
+ PINS_FIELD_BASE(171, 179, 7, 0x00d0, 0x10, 20, 4),
+};
+
+static const struct mtk_pin_field_calc mt6765_pin_rdsel_range[] = {
+ PINS_FIELD_BASE(0, 3, 2, 0x0090, 0x10, 8, 2),
+ PINS_FIELD_BASE(4, 7, 2, 0x0090, 0x10, 10, 2),
+ PIN_FIELD_BASE(8, 8, 3, 0x0060, 0x10, 6, 2),
+ PINS_FIELD_BASE(9, 11, 2, 0x0090, 0x10, 12, 2),
+ PIN_FIELD_BASE(12, 12, 5, 0x0050, 0x10, 18, 2),
+ PINS_FIELD_BASE(13, 16, 6, 0x00a0, 0x10, 18, 2),
+ PINS_FIELD_BASE(17, 20, 6, 0x00a0, 0x10, 14, 2),
+ PINS_FIELD_BASE(21, 24, 6, 0x00a0, 0x10, 16, 2),
+ PINS_FIELD_BASE(25, 28, 6, 0x00a0, 0x10, 12, 2),
+ PIN_FIELD_BASE(29, 29, 6, 0x0090, 0x10, 0, 6),
+ PIN_FIELD_BASE(30, 30, 6, 0x0090, 0x10, 6, 6),
+ PINS_FIELD_BASE(31, 34, 6, 0x0090, 0x10, 12, 6),
+ PINS_FIELD_BASE(35, 36, 6, 0x00a0, 0x10, 0, 6),
+ PIN_FIELD_BASE(37, 37, 6, 0x00a0, 0x10, 6, 6),
+ PIN_FIELD_BASE(38, 38, 6, 0x0090, 0x10, 24, 6),
+ PINS_FIELD_BASE(39, 40, 6, 0x0090, 0x10, 18, 6),
+ PINS_FIELD_BASE(41, 42, 7, 0x00a0, 0x10, 12, 2),
+ PIN_FIELD_BASE(43, 43, 7, 0x00a0, 0x10, 6, 2),
+ PIN_FIELD_BASE(44, 44, 7, 0x00a0, 0x10, 8, 2),
+ PIN_FIELD_BASE(45, 45, 7, 0x00a0, 0x10, 16, 2),
+ PINS_FIELD_BASE(46, 47, 7, 0x00a0, 0x10, 14, 2),
+ PINS_FIELD_BASE(48, 49, 7, 0x00a0, 0x10, 30, 2),
+ PINS_FIELD_BASE(50, 51, 7, 0x00a0, 0x10, 28, 2),
+ PINS_FIELD_BASE(52, 57, 7, 0x00a0, 0x10, 0, 2),
+ PINS_FIELD_BASE(58, 60, 7, 0x00a0, 0x10, 24, 2),
+ PINS_FIELD_BASE(61, 62, 3, 0x0060, 0x10, 10, 2),
+ PINS_FIELD_BASE(63, 64, 3, 0x0060, 0x10, 8, 2),
+ PINS_FIELD_BASE(65, 66, 3, 0x0060, 0x10, 14, 2),
+ PINS_FIELD_BASE(67, 68, 3, 0x0060, 0x10, 12, 2),
+ PINS_FIELD_BASE(69, 73, 3, 0x0060, 0x10, 2, 2),
+ PINS_FIELD_BASE(74, 78, 3, 0x0060, 0x10, 4, 2),
+ PINS_FIELD_BASE(79, 80, 3, 0x0060, 0x10, 0, 2),
+ PIN_FIELD_BASE(81, 81, 3, 0x0060, 0x10, 20, 2),
+ PINS_FIELD_BASE(82, 83, 3, 0x0060, 0x10, 18, 2),
+ PIN_FIELD_BASE(84, 84, 3, 0x0060, 0x10, 20, 2),
+ PIN_FIELD_BASE(85, 85, 7, 0x00a0, 0x10, 24, 2),
+ PIN_FIELD_BASE(86, 86, 7, 0x00a0, 0x10, 26, 2),
+ PIN_FIELD_BASE(87, 87, 7, 0x00a0, 0x10, 4, 2),
+ PIN_FIELD_BASE(88, 88, 7, 0x00a0, 0x10, 2, 2),
+ PIN_FIELD_BASE(89, 89, 2, 0x0090, 0x10, 22, 2),
+ PIN_FIELD_BASE(90, 90, 3, 0x0060, 0x10, 16, 2),
+ PINS_FIELD_BASE(91, 92, 2, 0x0090, 0x10, 16, 2),
+ PINS_FIELD_BASE(93, 94, 2, 0x0090, 0x10, 14, 2),
+ PINS_FIELD_BASE(95, 96, 2, 0x0090, 0x10, 24, 2),
+ PINS_FIELD_BASE(97, 98, 2, 0x0090, 0x10, 4, 2),
+ PIN_FIELD_BASE(99, 99, 2, 0x0090, 0x10, 0, 2),
+ PIN_FIELD_BASE(100, 100, 2, 0x0090, 0x10, 2, 2),
+ PINS_FIELD_BASE(101, 102, 2, 0x0090, 0x10, 6, 2),
+ PINS_FIELD_BASE(103, 104, 2, 0x0090, 0x10, 18, 2),
+ PINS_FIELD_BASE(105, 106, 2, 0x0090, 0x10, 20, 2),
+ PIN_FIELD_BASE(107, 107, 1, 0x0060, 0x10, 8, 2),
+ PIN_FIELD_BASE(108, 108, 1, 0x0060, 0x10, 6, 2),
+ PIN_FIELD_BASE(109, 109, 1, 0x0060, 0x10, 10, 2),
+ PIN_FIELD_BASE(110, 110, 1, 0x0060, 0x10, 0, 2),
+ PIN_FIELD_BASE(111, 111, 1, 0x0060, 0x10, 2, 2),
+ PIN_FIELD_BASE(112, 112, 1, 0x0060, 0x10, 4, 2),
+ PIN_FIELD_BASE(113, 113, 1, 0x0060, 0x10, 18, 2),
+ PIN_FIELD_BASE(114, 114, 1, 0x0060, 0x10, 20, 2),
+ PIN_FIELD_BASE(115, 115, 1, 0x0060, 0x10, 12, 2),
+ PIN_FIELD_BASE(116, 116, 1, 0x0060, 0x10, 14, 2),
+ PIN_FIELD_BASE(117, 117, 1, 0x0060, 0x10, 24, 2),
+ PIN_FIELD_BASE(118, 118, 1, 0x0060, 0x10, 26, 2),
+ PIN_FIELD_BASE(119, 119, 1, 0x0060, 0x10, 28, 2),
+ PIN_FIELD_BASE(120, 120, 1, 0x0060, 0x10, 22, 2),
+ PIN_FIELD_BASE(121, 121, 1, 0x0060, 0x10, 16, 2),
+ PIN_FIELD_BASE(122, 122, 4, 0x0070, 0x10, 8, 6),
+ PIN_FIELD_BASE(123, 123, 4, 0x0070, 0x10, 14, 6),
+ PIN_FIELD_BASE(124, 124, 4, 0x0070, 0x10, 2, 6),
+ PINS_FIELD_BASE(125, 130, 4, 0x0070, 0x10, 14, 6),
+ PIN_FIELD_BASE(131, 131, 4, 0x0070, 0x10, 20, 6),
+ PIN_FIELD_BASE(132, 132, 4, 0x0070, 0x10, 14, 6),
+ PIN_FIELD_BASE(133, 133, 4, 0x0070, 0x10, 26, 6),
+ PIN_FIELD_BASE(134, 134, 5, 0x0050, 0x10, 22, 2),
+ PIN_FIELD_BASE(135, 135, 5, 0x0050, 0x10, 30, 2),
+ PIN_FIELD_BASE(136, 136, 5, 0x0050, 0x10, 2, 2),
+ PIN_FIELD_BASE(137, 137, 5, 0x0050, 0x10, 14, 2),
+ PIN_FIELD_BASE(138, 138, 5, 0x0050, 0x10, 8, 2),
+ PIN_FIELD_BASE(139, 139, 5, 0x0050, 0x10, 10, 2),
+ PIN_FIELD_BASE(140, 140, 5, 0x0050, 0x10, 0, 2),
+ PIN_FIELD_BASE(141, 141, 5, 0x0050, 0x10, 12, 2),
+ PIN_FIELD_BASE(142, 142, 5, 0x0050, 0x10, 4, 2),
+ PIN_FIELD_BASE(143, 143, 5, 0x0050, 0x10, 6, 2),
+ PINS_FIELD_BASE(144, 147, 5, 0x0050, 0x10, 20, 2),
+ PINS_FIELD_BASE(148, 149, 5, 0x0050, 0x10, 24, 2),
+ PINS_FIELD_BASE(150, 151, 7, 0x00a0, 0x10, 18, 2),
+ PINS_FIELD_BASE(152, 153, 7, 0x00a0, 0x10, 20, 2),
+ PIN_FIELD_BASE(154, 154, 7, 0x00a0, 0x10, 22, 2),
+ PINS_FIELD_BASE(155, 158, 3, 0x0060, 0x10, 22, 2),
+ PIN_FIELD_BASE(159, 159, 7, 0x00a0, 0x10, 22, 2),
+ PIN_FIELD_BASE(160, 160, 5, 0x0050, 0x10, 16, 2),
+ PINS_FIELD_BASE(161, 162, 1, 0x0060, 0x10, 30, 2),
+ PINS_FIELD_BASE(163, 170, 4, 0x0070, 0x10, 0, 2),
+ PINS_FIELD_BASE(171, 179, 7, 0x00a0, 0x10, 10, 2),
+};
+
+static const struct mtk_pin_field_calc mt6765_pin_drv_range[] = {
+ PINS_FIELD_BASE(0, 2, 2, 0x0000, 0x10, 12, 3),
+ PIN_FIELD_BASE(3, 3, 2, 0x0000, 0x10, 15, 3),
+ PINS_FIELD_BASE(4, 6, 2, 0x0000, 0x10, 18, 3),
+ PIN_FIELD_BASE(7, 7, 2, 0x0000, 0x10, 21, 3),
+ PIN_FIELD_BASE(8, 8, 3, 0x0000, 0x10, 9, 3),
+ PINS_FIELD_BASE(9, 11, 2, 0x0000, 0x10, 24, 3),
+ PIN_FIELD_BASE(12, 12, 5, 0x0000, 0x10, 27, 3),
+ PINS_FIELD_BASE(13, 15, 6, 0x0010, 0x10, 3, 3),
+ PIN_FIELD_BASE(16, 16, 6, 0x0010, 0x10, 6, 3),
+ PIN_FIELD_BASE(17, 17, 6, 0x0000, 0x10, 23, 3),
+ PIN_FIELD_BASE(18, 18, 6, 0x0000, 0x10, 26, 3),
+ PINS_FIELD_BASE(19, 20, 6, 0x0000, 0x10, 23, 3),
+ PINS_FIELD_BASE(21, 23, 6, 0x0000, 0x10, 29, 3),
+ PIN_FIELD_BASE(24, 24, 6, 0x0010, 0x10, 0, 3),
+ PINS_FIELD_BASE(25, 27, 6, 0x0000, 0x10, 17, 3),
+ PIN_FIELD_BASE(28, 28, 6, 0x0000, 0x10, 20, 3),
+ PIN_FIELD_BASE(29, 29, 6, 0x0000, 0x10, 0, 3),
+ PIN_FIELD_BASE(30, 30, 6, 0x0000, 0x10, 3, 3),
+ PINS_FIELD_BASE(31, 34, 6, 0x0000, 0x10, 6, 3),
+ PINS_FIELD_BASE(35, 36, 6, 0x0000, 0x10, 13, 2),
+ PIN_FIELD_BASE(37, 37, 6, 0x0000, 0x10, 15, 2),
+ PIN_FIELD_BASE(38, 38, 6, 0x0000, 0x10, 11, 2),
+ PINS_FIELD_BASE(39, 40, 6, 0x0000, 0x10, 9, 2),
+ PINS_FIELD_BASE(41, 42, 7, 0x0000, 0x10, 21, 3),
+ PIN_FIELD_BASE(43, 43, 7, 0x0000, 0x10, 9, 3),
+ PIN_FIELD_BASE(44, 44, 7, 0x0000, 0x10, 12, 3),
+ PIN_FIELD_BASE(45, 45, 7, 0x0000, 0x10, 27, 3),
+ PINS_FIELD_BASE(46, 47, 7, 0x0000, 0x10, 24, 3),
+ PINS_FIELD_BASE(48, 49, 7, 0x0010, 0x10, 18, 3),
+ PINS_FIELD_BASE(50, 51, 7, 0x0010, 0x10, 15, 3),
+ PINS_FIELD_BASE(52, 57, 7, 0x0000, 0x10, 0, 3),
+ PINS_FIELD_BASE(58, 60, 7, 0x0010, 0x10, 9, 3),
+ PINS_FIELD_BASE(61, 62, 3, 0x0000, 0x10, 15, 3),
+ PINS_FIELD_BASE(63, 64, 3, 0x0000, 0x10, 12, 3),
+ PINS_FIELD_BASE(65, 66, 3, 0x0000, 0x10, 21, 3),
+ PINS_FIELD_BASE(67, 68, 3, 0x0000, 0x10, 18, 3),
+ PINS_FIELD_BASE(69, 73, 3, 0x0000, 0x10, 3, 3),
+ PINS_FIELD_BASE(74, 78, 3, 0x0000, 0x10, 6, 3),
+ PINS_FIELD_BASE(79, 80, 3, 0x0000, 0x10, 0, 3),
+ PIN_FIELD_BASE(81, 81, 3, 0x0010, 0x10, 0, 3),
+ PINS_FIELD_BASE(82, 83, 3, 0x0000, 0x10, 27, 3),
+ PIN_FIELD_BASE(84, 84, 3, 0x0010, 0x10, 0, 3),
+ PIN_FIELD_BASE(85, 85, 7, 0x0010, 0x10, 9, 3),
+ PIN_FIELD_BASE(86, 86, 7, 0x0010, 0x10, 12, 3),
+ PIN_FIELD_BASE(87, 87, 7, 0x0000, 0x10, 6, 3),
+ PIN_FIELD_BASE(88, 88, 7, 0x0000, 0x10, 3, 3),
+ PIN_FIELD_BASE(89, 89, 2, 0x0010, 0x10, 15, 3),
+ PIN_FIELD_BASE(90, 90, 3, 0x0000, 0x10, 24, 3),
+ PIN_FIELD_BASE(91, 91, 2, 0x0010, 0x10, 6, 3),
+ PIN_FIELD_BASE(92, 92, 2, 0x0010, 0x10, 3, 3),
+ PIN_FIELD_BASE(93, 93, 2, 0x0000, 0x10, 27, 3),
+ PIN_FIELD_BASE(94, 94, 2, 0x0010, 0x10, 0, 3),
+ PINS_FIELD_BASE(95, 96, 2, 0x0010, 0x10, 18, 3),
+ PINS_FIELD_BASE(97, 98, 2, 0x0000, 0x10, 6, 3),
+ PIN_FIELD_BASE(99, 99, 2, 0x0000, 0x10, 0, 3),
+ PIN_FIELD_BASE(100, 100, 2, 0x0000, 0x10, 3, 3),
+ PINS_FIELD_BASE(101, 102, 2, 0x0000, 0x10, 9, 3),
+ PINS_FIELD_BASE(103, 104, 2, 0x0010, 0x10, 9, 3),
+ PINS_FIELD_BASE(105, 106, 2, 0x0010, 0x10, 12, 3),
+ PIN_FIELD_BASE(107, 107, 1, 0x0000, 0x10, 12, 3),
+ PIN_FIELD_BASE(108, 108, 1, 0x0000, 0x10, 9, 3),
+ PIN_FIELD_BASE(109, 109, 1, 0x0000, 0x10, 15, 3),
+ PIN_FIELD_BASE(110, 110, 1, 0x0000, 0x10, 0, 3),
+ PIN_FIELD_BASE(111, 111, 1, 0x0000, 0x10, 3, 3),
+ PIN_FIELD_BASE(112, 112, 1, 0x0000, 0x10, 6, 3),
+ PIN_FIELD_BASE(113, 113, 1, 0x0000, 0x10, 27, 3),
+ PIN_FIELD_BASE(114, 114, 1, 0x0010, 0x10, 0, 3),
+ PIN_FIELD_BASE(115, 115, 1, 0x0000, 0x10, 18, 3),
+ PIN_FIELD_BASE(116, 116, 1, 0x0000, 0x10, 21, 3),
+ PIN_FIELD_BASE(117, 117, 1, 0x0010, 0x10, 6, 3),
+ PIN_FIELD_BASE(118, 118, 1, 0x0010, 0x10, 9, 3),
+ PIN_FIELD_BASE(119, 119, 1, 0x0010, 0x10, 12, 3),
+ PIN_FIELD_BASE(120, 120, 1, 0x0010, 0x10, 3, 3),
+ PIN_FIELD_BASE(121, 121, 1, 0x0000, 0x10, 24, 3),
+ PIN_FIELD_BASE(122, 122, 4, 0x0000, 0x10, 9, 3),
+ PIN_FIELD_BASE(123, 123, 4, 0x0000, 0x10, 12, 3),
+ PIN_FIELD_BASE(124, 124, 4, 0x0000, 0x10, 6, 3),
+ PINS_FIELD_BASE(125, 130, 4, 0x0000, 0x10, 12, 3),
+ PIN_FIELD_BASE(131, 131, 4, 0x0000, 0x10, 15, 3),
+ PIN_FIELD_BASE(132, 132, 4, 0x0000, 0x10, 12, 3),
+ PIN_FIELD_BASE(133, 133, 4, 0x0000, 0x10, 18, 3),
+ PIN_FIELD_BASE(134, 134, 5, 0x0010, 0x10, 6, 3),
+ PIN_FIELD_BASE(135, 135, 5, 0x0010, 0x10, 12, 3),
+ PIN_FIELD_BASE(136, 136, 5, 0x0000, 0x10, 3, 3),
+ PIN_FIELD_BASE(137, 137, 5, 0x0000, 0x10, 21, 3),
+ PIN_FIELD_BASE(138, 138, 5, 0x0000, 0x10, 12, 3),
+ PIN_FIELD_BASE(139, 139, 5, 0x0000, 0x10, 15, 3),
+ PIN_FIELD_BASE(140, 140, 5, 0x0000, 0x10, 0, 3),
+ PIN_FIELD_BASE(141, 141, 5, 0x0000, 0x10, 18, 3),
+ PIN_FIELD_BASE(142, 142, 5, 0x0000, 0x10, 6, 3),
+ PIN_FIELD_BASE(143, 143, 5, 0x0000, 0x10, 9, 3),
+ PINS_FIELD_BASE(144, 146, 5, 0x0010, 0x10, 0, 3),
+ PIN_FIELD_BASE(147, 147, 5, 0x0010, 0x10, 3, 3),
+ PINS_FIELD_BASE(148, 149, 5, 0x0010, 0x10, 9, 3),
+ PINS_FIELD_BASE(150, 151, 7, 0x0010, 0x10, 0, 3),
+ PINS_FIELD_BASE(152, 153, 7, 0x0010, 0x10, 3, 3),
+ PIN_FIELD_BASE(154, 154, 7, 0x0010, 0x10, 6, 3),
+ PINS_FIELD_BASE(155, 157, 3, 0x0010, 0x10, 3, 3),
+ PIN_FIELD_BASE(158, 158, 3, 0x0010, 0x10, 6, 3),
+ PIN_FIELD_BASE(159, 159, 7, 0x0010, 0x10, 6, 3),
+ PIN_FIELD_BASE(160, 160, 5, 0x0000, 0x10, 24, 3),
+ PINS_FIELD_BASE(161, 162, 1, 0x0010, 0x10, 15, 3),
+ PINS_FIELD_BASE(163, 166, 4, 0x0000, 0x10, 0, 3),
+ PINS_FIELD_BASE(167, 170, 4, 0x0000, 0x10, 3, 3),
+ PINS_FIELD_BASE(171, 174, 7, 0x0000, 0x10, 18, 3),
+ PINS_FIELD_BASE(175, 179, 7, 0x0000, 0x10, 15, 3),
+};
+
+static const struct mtk_pin_field_calc mt6765_pin_pupd_range[] = {
+ PINS_FIELD_BASE(0, 28, 0, 0x0050, 0x10, 18, 1),
+ PIN_FIELD_BASE(29, 29, 6, 0x0050, 0x10, 0, 1),
+ PIN_FIELD_BASE(30, 30, 6, 0x0050, 0x10, 1, 1),
+ PIN_FIELD_BASE(31, 31, 6, 0x0050, 0x10, 5, 1),
+ PIN_FIELD_BASE(32, 32, 6, 0x0050, 0x10, 2, 1),
+ PIN_FIELD_BASE(33, 33, 6, 0x0050, 0x10, 4, 1),
+ PIN_FIELD_BASE(34, 34, 6, 0x0050, 0x10, 3, 1),
+ PIN_FIELD_BASE(35, 35, 6, 0x0050, 0x10, 10, 1),
+ PIN_FIELD_BASE(36, 36, 6, 0x0050, 0x10, 11, 1),
+ PIN_FIELD_BASE(37, 37, 6, 0x0050, 0x10, 9, 1),
+ PIN_FIELD_BASE(38, 38, 6, 0x0050, 0x10, 6, 1),
+ PIN_FIELD_BASE(39, 39, 6, 0x0050, 0x10, 8, 1),
+ PINS_FIELD_BASE(40, 90, 6, 0x0050, 0x10, 7, 1),
+ PIN_FIELD_BASE(91, 91, 2, 0x0050, 0x10, 3, 1),
+ PIN_FIELD_BASE(92, 92, 2, 0x0050, 0x10, 2, 1),
+ PIN_FIELD_BASE(93, 93, 2, 0x0050, 0x10, 0, 1),
+ PINS_FIELD_BASE(94, 121, 2, 0x0050, 0x10, 1, 1),
+ PIN_FIELD_BASE(122, 122, 4, 0x0030, 0x10, 1, 1),
+ PIN_FIELD_BASE(123, 123, 4, 0x0030, 0x10, 2, 1),
+ PIN_FIELD_BASE(124, 124, 4, 0x0030, 0x10, 0, 1),
+ PIN_FIELD_BASE(125, 125, 4, 0x0030, 0x10, 4, 1),
+ PIN_FIELD_BASE(126, 126, 4, 0x0030, 0x10, 6, 1),
+ PIN_FIELD_BASE(127, 127, 4, 0x0030, 0x10, 8, 1),
+ PIN_FIELD_BASE(128, 128, 4, 0x0030, 0x10, 3, 1),
+ PIN_FIELD_BASE(129, 129, 4, 0x0030, 0x10, 7, 1),
+ PIN_FIELD_BASE(130, 130, 4, 0x0030, 0x10, 9, 1),
+ PIN_FIELD_BASE(131, 131, 4, 0x0030, 0x10, 10, 1),
+ PIN_FIELD_BASE(132, 132, 4, 0x0030, 0x10, 5, 1),
+ PINS_FIELD_BASE(133, 179, 4, 0x0030, 0x10, 11, 1),
+};
+
+static const struct mtk_pin_field_calc mt6765_pin_r0_range[] = {
+ PINS_FIELD_BASE(0, 28, 4, 0x0030, 0x10, 11, 1),
+ PIN_FIELD_BASE(29, 29, 6, 0x0070, 0x10, 0, 1),
+ PIN_FIELD_BASE(30, 30, 6, 0x0070, 0x10, 1, 1),
+ PIN_FIELD_BASE(31, 31, 6, 0x0070, 0x10, 5, 1),
+ PIN_FIELD_BASE(32, 32, 6, 0x0070, 0x10, 2, 1),
+ PIN_FIELD_BASE(33, 33, 6, 0x0070, 0x10, 4, 1),
+ PIN_FIELD_BASE(34, 34, 6, 0x0070, 0x10, 3, 1),
+ PIN_FIELD_BASE(35, 35, 6, 0x0070, 0x10, 10, 1),
+ PIN_FIELD_BASE(36, 36, 6, 0x0070, 0x10, 11, 1),
+ PIN_FIELD_BASE(37, 37, 6, 0x0070, 0x10, 9, 1),
+ PIN_FIELD_BASE(38, 38, 6, 0x0070, 0x10, 6, 1),
+ PIN_FIELD_BASE(39, 39, 6, 0x0070, 0x10, 8, 1),
+ PINS_FIELD_BASE(40, 90, 6, 0x0070, 0x10, 7, 1),
+ PIN_FIELD_BASE(91, 91, 2, 0x0070, 0x10, 3, 1),
+ PIN_FIELD_BASE(92, 92, 2, 0x0070, 0x10, 2, 1),
+ PIN_FIELD_BASE(93, 93, 2, 0x0070, 0x10, 0, 1),
+ PINS_FIELD_BASE(94, 121, 2, 0x0070, 0x10, 1, 1),
+ PIN_FIELD_BASE(122, 122, 4, 0x0050, 0x10, 1, 1),
+ PIN_FIELD_BASE(123, 123, 4, 0x0050, 0x10, 2, 1),
+ PIN_FIELD_BASE(124, 124, 4, 0x0050, 0x10, 0, 1),
+ PIN_FIELD_BASE(125, 125, 4, 0x0050, 0x10, 4, 1),
+ PIN_FIELD_BASE(126, 126, 4, 0x0050, 0x10, 6, 1),
+ PIN_FIELD_BASE(127, 127, 4, 0x0050, 0x10, 8, 1),
+ PIN_FIELD_BASE(128, 128, 4, 0x0050, 0x10, 3, 1),
+ PIN_FIELD_BASE(129, 129, 4, 0x0050, 0x10, 7, 1),
+ PIN_FIELD_BASE(130, 130, 4, 0x0050, 0x10, 9, 1),
+ PIN_FIELD_BASE(131, 131, 4, 0x0050, 0x10, 10, 1),
+ PIN_FIELD_BASE(132, 132, 4, 0x0050, 0x10, 5, 1),
+ PINS_FIELD_BASE(133, 179, 4, 0x0050, 0x10, 11, 1),
+};
+
+static const struct mtk_pin_field_calc mt6765_pin_r1_range[] = {
+ PINS_FIELD_BASE(0, 28, 4, 0x0050, 0x10, 11, 1),
+ PIN_FIELD_BASE(29, 29, 6, 0x0080, 0x10, 0, 1),
+ PIN_FIELD_BASE(30, 30, 6, 0x0080, 0x10, 1, 1),
+ PIN_FIELD_BASE(31, 31, 6, 0x0080, 0x10, 5, 1),
+ PIN_FIELD_BASE(32, 32, 6, 0x0080, 0x10, 2, 1),
+ PIN_FIELD_BASE(33, 33, 6, 0x0080, 0x10, 4, 1),
+ PIN_FIELD_BASE(34, 34, 6, 0x0080, 0x10, 3, 1),
+ PIN_FIELD_BASE(35, 35, 6, 0x0080, 0x10, 10, 1),
+ PIN_FIELD_BASE(36, 36, 6, 0x0080, 0x10, 11, 1),
+ PIN_FIELD_BASE(37, 37, 6, 0x0080, 0x10, 9, 1),
+ PIN_FIELD_BASE(38, 38, 6, 0x0080, 0x10, 6, 1),
+ PIN_FIELD_BASE(39, 39, 6, 0x0080, 0x10, 8, 1),
+ PINS_FIELD_BASE(40, 90, 6, 0x0080, 0x10, 7, 1),
+ PIN_FIELD_BASE(91, 91, 2, 0x0080, 0x10, 3, 1),
+ PIN_FIELD_BASE(92, 92, 2, 0x0080, 0x10, 2, 1),
+ PIN_FIELD_BASE(93, 93, 2, 0x0080, 0x10, 0, 1),
+ PINS_FIELD_BASE(94, 121, 2, 0x0080, 0x10, 1, 1),
+ PIN_FIELD_BASE(122, 122, 4, 0x0060, 0x10, 1, 1),
+ PIN_FIELD_BASE(123, 123, 4, 0x0060, 0x10, 2, 1),
+ PIN_FIELD_BASE(124, 124, 4, 0x0060, 0x10, 0, 1),
+ PIN_FIELD_BASE(125, 125, 4, 0x0060, 0x10, 4, 1),
+ PIN_FIELD_BASE(126, 126, 4, 0x0060, 0x10, 6, 1),
+ PIN_FIELD_BASE(127, 127, 4, 0x0060, 0x10, 8, 1),
+ PIN_FIELD_BASE(128, 128, 4, 0x0060, 0x10, 3, 1),
+ PIN_FIELD_BASE(129, 129, 4, 0x0060, 0x10, 7, 1),
+ PIN_FIELD_BASE(130, 130, 4, 0x0060, 0x10, 9, 1),
+ PIN_FIELD_BASE(131, 131, 4, 0x0060, 0x10, 10, 1),
+ PIN_FIELD_BASE(132, 132, 4, 0x0060, 0x10, 5, 1),
+ PINS_FIELD_BASE(133, 179, 4, 0x0060, 0x10, 11, 1),
+};
+
+static const struct mtk_pin_field_calc mt6765_pin_ies_range[] = {
+ PIN_FIELD_BASE(0, 0, 2, 0x0030, 0x10, 6, 1),
+ PIN_FIELD_BASE(1, 1, 2, 0x0030, 0x10, 7, 1),
+ PIN_FIELD_BASE(2, 2, 2, 0x0030, 0x10, 10, 1),
+ PIN_FIELD_BASE(3, 3, 2, 0x0030, 0x10, 11, 1),
+ PIN_FIELD_BASE(4, 4, 2, 0x0030, 0x10, 12, 1),
+ PIN_FIELD_BASE(5, 5, 2, 0x0030, 0x10, 13, 1),
+ PIN_FIELD_BASE(6, 6, 2, 0x0030, 0x10, 14, 1),
+ PIN_FIELD_BASE(7, 7, 2, 0x0030, 0x10, 15, 1),
+ PIN_FIELD_BASE(8, 8, 3, 0x0030, 0x10, 12, 1),
+ PIN_FIELD_BASE(9, 9, 2, 0x0030, 0x10, 16, 1),
+ PIN_FIELD_BASE(10, 10, 2, 0x0030, 0x10, 8, 1),
+ PIN_FIELD_BASE(11, 11, 2, 0x0030, 0x10, 9, 1),
+ PIN_FIELD_BASE(12, 12, 5, 0x0020, 0x10, 9, 1),
+ PIN_FIELD_BASE(13, 13, 6, 0x0020, 0x10, 26, 1),
+ PIN_FIELD_BASE(14, 14, 6, 0x0020, 0x10, 25, 1),
+ PIN_FIELD_BASE(15, 15, 6, 0x0020, 0x10, 27, 1),
+ PIN_FIELD_BASE(16, 16, 6, 0x0020, 0x10, 24, 1),
+ PIN_FIELD_BASE(17, 17, 6, 0x0020, 0x10, 19, 1),
+ PIN_FIELD_BASE(18, 18, 6, 0x0020, 0x10, 16, 1),
+ PIN_FIELD_BASE(19, 19, 6, 0x0020, 0x10, 18, 1),
+ PIN_FIELD_BASE(20, 20, 6, 0x0020, 0x10, 17, 1),
+ PIN_FIELD_BASE(21, 21, 6, 0x0020, 0x10, 22, 1),
+ PIN_FIELD_BASE(22, 22, 6, 0x0020, 0x10, 21, 1),
+ PIN_FIELD_BASE(23, 23, 6, 0x0020, 0x10, 23, 1),
+ PIN_FIELD_BASE(24, 24, 6, 0x0020, 0x10, 20, 1),
+ PIN_FIELD_BASE(25, 25, 6, 0x0020, 0x10, 14, 1),
+ PIN_FIELD_BASE(26, 26, 6, 0x0020, 0x10, 13, 1),
+ PIN_FIELD_BASE(27, 27, 6, 0x0020, 0x10, 15, 1),
+ PIN_FIELD_BASE(28, 28, 6, 0x0020, 0x10, 12, 1),
+ PIN_FIELD_BASE(29, 29, 6, 0x0020, 0x10, 0, 1),
+ PIN_FIELD_BASE(30, 30, 6, 0x0020, 0x10, 1, 1),
+ PIN_FIELD_BASE(31, 31, 6, 0x0020, 0x10, 5, 1),
+ PIN_FIELD_BASE(32, 32, 6, 0x0020, 0x10, 2, 1),
+ PIN_FIELD_BASE(33, 33, 6, 0x0020, 0x10, 4, 1),
+ PIN_FIELD_BASE(34, 34, 6, 0x0020, 0x10, 3, 1),
+ PIN_FIELD_BASE(35, 35, 6, 0x0020, 0x10, 10, 1),
+ PIN_FIELD_BASE(36, 36, 6, 0x0020, 0x10, 11, 1),
+ PIN_FIELD_BASE(37, 37, 6, 0x0020, 0x10, 9, 1),
+ PIN_FIELD_BASE(38, 38, 6, 0x0020, 0x10, 6, 1),
+ PIN_FIELD_BASE(39, 39, 6, 0x0020, 0x10, 8, 1),
+ PIN_FIELD_BASE(40, 40, 6, 0x0020, 0x10, 7, 1),
+ PIN_FIELD_BASE(41, 41, 7, 0x0040, 0x10, 19, 1),
+ PIN_FIELD_BASE(42, 42, 7, 0x0040, 0x10, 9, 1),
+ PIN_FIELD_BASE(43, 43, 7, 0x0040, 0x10, 8, 1),
+ PIN_FIELD_BASE(44, 44, 7, 0x0040, 0x10, 10, 1),
+ PIN_FIELD_BASE(45, 45, 7, 0x0040, 0x10, 22, 1),
+ PIN_FIELD_BASE(46, 46, 7, 0x0040, 0x10, 21, 1),
+ PIN_FIELD_BASE(47, 47, 7, 0x0040, 0x10, 20, 1),
+ PIN_FIELD_BASE(48, 48, 7, 0x0050, 0x10, 3, 1),
+ PIN_FIELD_BASE(49, 49, 7, 0x0050, 0x10, 5, 1),
+ PIN_FIELD_BASE(50, 50, 7, 0x0050, 0x10, 2, 1),
+ PIN_FIELD_BASE(51, 51, 7, 0x0050, 0x10, 4, 1),
+ PIN_FIELD_BASE(52, 52, 7, 0x0040, 0x10, 1, 1),
+ PIN_FIELD_BASE(53, 53, 7, 0x0040, 0x10, 0, 1),
+ PIN_FIELD_BASE(54, 54, 7, 0x0040, 0x10, 5, 1),
+ PIN_FIELD_BASE(55, 55, 7, 0x0040, 0x10, 3, 1),
+ PIN_FIELD_BASE(56, 56, 7, 0x0040, 0x10, 4, 1),
+ PIN_FIELD_BASE(57, 57, 7, 0x0040, 0x10, 2, 1),
+ PIN_FIELD_BASE(58, 58, 7, 0x0050, 0x10, 0, 1),
+ PIN_FIELD_BASE(59, 59, 7, 0x0040, 0x10, 31, 1),
+ PIN_FIELD_BASE(60, 60, 7, 0x0040, 0x10, 30, 1),
+ PIN_FIELD_BASE(61, 61, 3, 0x0030, 0x10, 18, 1),
+ PIN_FIELD_BASE(62, 62, 3, 0x0030, 0x10, 14, 1),
+ PIN_FIELD_BASE(63, 63, 3, 0x0030, 0x10, 17, 1),
+ PIN_FIELD_BASE(64, 64, 3, 0x0030, 0x10, 13, 1),
+ PIN_FIELD_BASE(65, 65, 3, 0x0030, 0x10, 20, 1),
+ PIN_FIELD_BASE(66, 66, 3, 0x0030, 0x10, 16, 1),
+ PIN_FIELD_BASE(67, 67, 3, 0x0030, 0x10, 19, 1),
+ PIN_FIELD_BASE(68, 68, 3, 0x0030, 0x10, 15, 1),
+ PIN_FIELD_BASE(69, 69, 3, 0x0030, 0x10, 8, 1),
+ PIN_FIELD_BASE(70, 70, 3, 0x0030, 0x10, 7, 1),
+ PIN_FIELD_BASE(71, 71, 3, 0x0030, 0x10, 6, 1),
+ PIN_FIELD_BASE(72, 72, 3, 0x0030, 0x10, 5, 1),
+ PIN_FIELD_BASE(73, 73, 3, 0x0030, 0x10, 4, 1),
+ PIN_FIELD_BASE(74, 74, 3, 0x0030, 0x10, 3, 1),
+ PIN_FIELD_BASE(75, 75, 3, 0x0030, 0x10, 2, 1),
+ PIN_FIELD_BASE(76, 76, 3, 0x0030, 0x10, 1, 1),
+ PIN_FIELD_BASE(77, 77, 3, 0x0030, 0x10, 0, 1),
+ PIN_FIELD_BASE(78, 78, 3, 0x0030, 0x10, 9, 1),
+ PIN_FIELD_BASE(79, 79, 3, 0x0030, 0x10, 11, 1),
+ PIN_FIELD_BASE(80, 80, 3, 0x0030, 0x10, 10, 1),
+ PIN_FIELD_BASE(81, 81, 3, 0x0030, 0x10, 25, 1),
+ PIN_FIELD_BASE(82, 82, 3, 0x0030, 0x10, 24, 1),
+ PIN_FIELD_BASE(83, 83, 3, 0x0030, 0x10, 22, 1),
+ PIN_FIELD_BASE(84, 84, 3, 0x0030, 0x10, 23, 1),
+ PIN_FIELD_BASE(85, 85, 7, 0x0050, 0x10, 1, 1),
+ PIN_FIELD_BASE(86, 86, 7, 0x0040, 0x10, 29, 1),
+ PIN_FIELD_BASE(87, 87, 7, 0x0040, 0x10, 7, 1),
+ PIN_FIELD_BASE(88, 88, 7, 0x0040, 0x10, 6, 1),
+ PIN_FIELD_BASE(89, 89, 2, 0x0030, 0x10, 25, 1),
+ PIN_FIELD_BASE(90, 90, 3, 0x0030, 0x10, 21, 1),
+ PIN_FIELD_BASE(91, 91, 2, 0x0030, 0x10, 20, 1),
+ PIN_FIELD_BASE(92, 92, 2, 0x0030, 0x10, 19, 1),
+ PIN_FIELD_BASE(93, 93, 2, 0x0030, 0x10, 17, 1),
+ PIN_FIELD_BASE(94, 94, 2, 0x0030, 0x10, 18, 1),
+ PIN_FIELD_BASE(95, 95, 2, 0x0030, 0x10, 26, 1),
+ PIN_FIELD_BASE(96, 96, 2, 0x0030, 0x10, 27, 1),
+ PIN_FIELD_BASE(97, 97, 2, 0x0030, 0x10, 2, 1),
+ PIN_FIELD_BASE(98, 98, 2, 0x0030, 0x10, 3, 1),
+ PIN_FIELD_BASE(99, 99, 2, 0x0030, 0x10, 0, 1),
+ PIN_FIELD_BASE(100, 100, 2, 0x0030, 0x10, 1, 1),
+ PIN_FIELD_BASE(101, 101, 2, 0x0030, 0x10, 4, 1),
+ PIN_FIELD_BASE(102, 102, 2, 0x0030, 0x10, 5, 1),
+ PIN_FIELD_BASE(103, 103, 2, 0x0030, 0x10, 21, 1),
+ PIN_FIELD_BASE(104, 104, 2, 0x0030, 0x10, 23, 1),
+ PIN_FIELD_BASE(105, 105, 2, 0x0030, 0x10, 22, 1),
+ PIN_FIELD_BASE(106, 106, 2, 0x0030, 0x10, 24, 1),
+ PIN_FIELD_BASE(107, 107, 1, 0x0030, 0x10, 4, 1),
+ PIN_FIELD_BASE(108, 108, 1, 0x0030, 0x10, 3, 1),
+ PIN_FIELD_BASE(109, 109, 1, 0x0030, 0x10, 5, 1),
+ PIN_FIELD_BASE(110, 110, 1, 0x0030, 0x10, 0, 1),
+ PIN_FIELD_BASE(111, 111, 1, 0x0030, 0x10, 1, 1),
+ PIN_FIELD_BASE(112, 112, 1, 0x0030, 0x10, 2, 1),
+ PIN_FIELD_BASE(113, 113, 1, 0x0030, 0x10, 9, 1),
+ PIN_FIELD_BASE(114, 114, 1, 0x0030, 0x10, 10, 1),
+ PIN_FIELD_BASE(115, 115, 1, 0x0030, 0x10, 6, 1),
+ PIN_FIELD_BASE(116, 116, 1, 0x0030, 0x10, 7, 1),
+ PIN_FIELD_BASE(117, 117, 1, 0x0030, 0x10, 12, 1),
+ PIN_FIELD_BASE(118, 118, 1, 0x0030, 0x10, 13, 1),
+ PIN_FIELD_BASE(119, 119, 1, 0x0030, 0x10, 14, 1),
+ PIN_FIELD_BASE(120, 120, 1, 0x0030, 0x10, 11, 1),
+ PIN_FIELD_BASE(121, 121, 1, 0x0030, 0x10, 8, 1),
+ PIN_FIELD_BASE(122, 122, 4, 0x0010, 0x10, 9, 1),
+ PIN_FIELD_BASE(123, 123, 4, 0x0010, 0x10, 10, 1),
+ PIN_FIELD_BASE(124, 124, 4, 0x0010, 0x10, 8, 1),
+ PIN_FIELD_BASE(125, 125, 4, 0x0010, 0x10, 12, 1),
+ PIN_FIELD_BASE(126, 126, 4, 0x0010, 0x10, 14, 1),
+ PIN_FIELD_BASE(127, 127, 4, 0x0010, 0x10, 16, 1),
+ PIN_FIELD_BASE(128, 128, 4, 0x0010, 0x10, 11, 1),
+ PIN_FIELD_BASE(129, 129, 4, 0x0010, 0x10, 15, 1),
+ PIN_FIELD_BASE(130, 130, 4, 0x0010, 0x10, 17, 1),
+ PIN_FIELD_BASE(131, 131, 4, 0x0010, 0x10, 18, 1),
+ PIN_FIELD_BASE(132, 132, 4, 0x0010, 0x10, 13, 1),
+ PIN_FIELD_BASE(133, 133, 4, 0x0010, 0x10, 19, 1),
+ PIN_FIELD_BASE(134, 134, 5, 0x0020, 0x10, 14, 1),
+ PIN_FIELD_BASE(135, 135, 5, 0x0020, 0x10, 17, 1),
+ PIN_FIELD_BASE(136, 136, 5, 0x0020, 0x10, 1, 1),
+ PIN_FIELD_BASE(137, 137, 5, 0x0020, 0x10, 7, 1),
+ PIN_FIELD_BASE(138, 138, 5, 0x0020, 0x10, 4, 1),
+ PIN_FIELD_BASE(139, 139, 5, 0x0020, 0x10, 5, 1),
+ PIN_FIELD_BASE(140, 140, 5, 0x0020, 0x10, 0, 1),
+ PIN_FIELD_BASE(141, 141, 5, 0x0020, 0x10, 6, 1),
+ PIN_FIELD_BASE(142, 142, 5, 0x0020, 0x10, 2, 1),
+ PIN_FIELD_BASE(143, 143, 5, 0x0020, 0x10, 3, 1),
+ PIN_FIELD_BASE(144, 144, 5, 0x0020, 0x10, 12, 1),
+ PIN_FIELD_BASE(145, 145, 5, 0x0020, 0x10, 11, 1),
+ PIN_FIELD_BASE(146, 146, 5, 0x0020, 0x10, 13, 1),
+ PIN_FIELD_BASE(147, 147, 5, 0x0020, 0x10, 10, 1),
+ PIN_FIELD_BASE(148, 148, 5, 0x0020, 0x10, 15, 1),
+ PIN_FIELD_BASE(149, 149, 5, 0x0020, 0x10, 16, 1),
+ PIN_FIELD_BASE(150, 150, 7, 0x0040, 0x10, 23, 1),
+ PIN_FIELD_BASE(151, 151, 7, 0x0040, 0x10, 24, 1),
+ PIN_FIELD_BASE(152, 152, 7, 0x0040, 0x10, 25, 1),
+ PIN_FIELD_BASE(153, 153, 7, 0x0040, 0x10, 26, 1),
+ PIN_FIELD_BASE(154, 154, 7, 0x0040, 0x10, 28, 1),
+ PIN_FIELD_BASE(155, 155, 3, 0x0030, 0x10, 28, 1),
+ PIN_FIELD_BASE(156, 156, 3, 0x0030, 0x10, 27, 1),
+ PIN_FIELD_BASE(157, 157, 3, 0x0030, 0x10, 29, 1),
+ PIN_FIELD_BASE(158, 158, 3, 0x0030, 0x10, 26, 1),
+ PIN_FIELD_BASE(159, 159, 7, 0x0040, 0x10, 27, 1),
+ PIN_FIELD_BASE(160, 160, 5, 0x0020, 0x10, 8, 1),
+ PIN_FIELD_BASE(161, 161, 1, 0x0030, 0x10, 15, 1),
+ PIN_FIELD_BASE(162, 162, 1, 0x0030, 0x10, 16, 1),
+ PIN_FIELD_BASE(163, 163, 4, 0x0010, 0x10, 0, 1),
+ PIN_FIELD_BASE(164, 164, 4, 0x0010, 0x10, 1, 1),
+ PIN_FIELD_BASE(165, 165, 4, 0x0010, 0x10, 2, 1),
+ PIN_FIELD_BASE(166, 166, 4, 0x0010, 0x10, 3, 1),
+ PIN_FIELD_BASE(167, 167, 4, 0x0010, 0x10, 4, 1),
+ PIN_FIELD_BASE(168, 168, 4, 0x0010, 0x10, 5, 1),
+ PIN_FIELD_BASE(169, 169, 4, 0x0010, 0x10, 6, 1),
+ PIN_FIELD_BASE(170, 170, 4, 0x0010, 0x10, 7, 1),
+ PIN_FIELD_BASE(171, 171, 7, 0x0040, 0x10, 17, 1),
+ PIN_FIELD_BASE(172, 172, 7, 0x0040, 0x10, 18, 1),
+ PIN_FIELD_BASE(173, 173, 7, 0x0040, 0x10, 11, 1),
+ PIN_FIELD_BASE(174, 174, 7, 0x0040, 0x10, 12, 1),
+ PIN_FIELD_BASE(175, 175, 7, 0x0040, 0x10, 13, 1),
+ PIN_FIELD_BASE(176, 176, 7, 0x0040, 0x10, 14, 1),
+ PIN_FIELD_BASE(177, 177, 7, 0x0040, 0x10, 15, 1),
+ PINS_FIELD_BASE(178, 179, 7, 0x0040, 0x10, 16, 1),
+};
+
+static const struct mtk_pin_reg_calc mt6765_reg_cals[PINCTRL_PIN_REG_MAX] = {
+ [PINCTRL_PIN_REG_MODE] = MTK_RANGE(mt6765_pin_mode_range),
+ [PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt6765_pin_dir_range),
+ [PINCTRL_PIN_REG_DI] = MTK_RANGE(mt6765_pin_di_range),
+ [PINCTRL_PIN_REG_DO] = MTK_RANGE(mt6765_pin_do_range),
+ [PINCTRL_PIN_REG_SMT] = MTK_RANGE(mt6765_pin_smt_range),
+ [PINCTRL_PIN_REG_PD] = MTK_RANGE(mt6765_pin_pd_range),
+ [PINCTRL_PIN_REG_PU] = MTK_RANGE(mt6765_pin_pu_range),
+ [PINCTRL_PIN_REG_TDSEL] = MTK_RANGE(mt6765_pin_tdsel_range),
+ [PINCTRL_PIN_REG_RDSEL] = MTK_RANGE(mt6765_pin_rdsel_range),
+ [PINCTRL_PIN_REG_DRV] = MTK_RANGE(mt6765_pin_drv_range),
+ [PINCTRL_PIN_REG_PUPD] = MTK_RANGE(mt6765_pin_pupd_range),
+ [PINCTRL_PIN_REG_R0] = MTK_RANGE(mt6765_pin_r0_range),
+ [PINCTRL_PIN_REG_R1] = MTK_RANGE(mt6765_pin_r1_range),
+ [PINCTRL_PIN_REG_IES] = MTK_RANGE(mt6765_pin_ies_range),
+};
+
+static const char * const mt6765_pinctrl_register_base_names[] = {
+ "iocfg0", "iocfg1", "iocfg2", "iocfg3", "iocfg4", "iocfg5",
+ "iocfg6", "iocfg7",
+};
+
+static const struct mtk_eint_hw mt6765_eint_hw = {
+ .port_mask = 7,
+ .ports = 6,
+ .ap_num = 160,
+ .db_cnt = 13,
+};
+
+static const struct mtk_pin_soc mt6765_data = {
+ .reg_cal = mt6765_reg_cals,
+ .pins = mtk_pins_mt6765,
+ .npins = ARRAY_SIZE(mtk_pins_mt6765),
+ .ngrps = ARRAY_SIZE(mtk_pins_mt6765),
+ .eint_hw = &mt6765_eint_hw,
+ .gpio_m = 0,
+ .ies_present = true,
+ .base_names = mt6765_pinctrl_register_base_names,
+ .nbase_names = ARRAY_SIZE(mt6765_pinctrl_register_base_names),
+ .bias_disable_set = mtk_pinconf_bias_disable_set,
+ .bias_disable_get = mtk_pinconf_bias_disable_get,
+ .bias_set = mtk_pinconf_bias_set,
+ .bias_get = mtk_pinconf_bias_get,
+ .drive_set = mtk_pinconf_drive_set_rev1,
+ .drive_get = mtk_pinconf_drive_get_rev1,
+ .adv_pull_get = mtk_pinconf_adv_pull_get,
+ .adv_pull_set = mtk_pinconf_adv_pull_set,
+};
+
+static const struct of_device_id mt6765_pinctrl_of_match[] = {
+ { .compatible = "mediatek,mt6765-pinctrl", },
+ { }
+};
+
+static int mt6765_pinctrl_probe(struct platform_device *pdev)
+{
+ return mtk_paris_pinctrl_probe(pdev, &mt6765_data);
+}
+
+static struct platform_driver mt6765_pinctrl_driver = {
+ .driver = {
+ .name = "mt6765-pinctrl",
+ .of_match_table = mt6765_pinctrl_of_match,
+ },
+ .probe = mt6765_pinctrl_probe,
+};
+
+static int __init mt6765_pinctrl_init(void)
+{
+ return platform_driver_register(&mt6765_pinctrl_driver);
+}
+arch_initcall(mt6765_pinctrl_init);
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7622.c b/drivers/pinctrl/mediatek/pinctrl-mt7622.c
index 6f931b85701b..ce4a8a0cc19c 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt7622.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt7622.c
@@ -1,297 +1,140 @@
+// SPDX-License-Identifier: GPL-2.0
/*
- * MediaTek MT7622 Pinctrl Driver
+ * Copyright (C) 2017-2018 MediaTek Inc.
*
- * Copyright (C) 2017 Sean Wang <sean.wang@mediatek.com>
+ * Author: Sean Wang <sean.wang@mediatek.com>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/gpio.h>
-#include <linux/gpio/driver.h>
-#include <linux/io.h>
-#include <linux/init.h>
-#include <linux/mfd/syscon.h>
-#include <linux/of.h>
-#include <linux/of_irq.h>
-#include <linux/of_platform.h>
-#include <linux/platform_device.h>
-#include <linux/pinctrl/pinctrl.h>
-#include <linux/pinctrl/pinmux.h>
-#include <linux/pinctrl/pinconf.h>
-#include <linux/pinctrl/pinconf-generic.h>
-#include <linux/regmap.h>
-
-#include "../core.h"
-#include "../pinconf.h"
-#include "../pinmux.h"
-#include "mtk-eint.h"
-
-#define PINCTRL_PINCTRL_DEV KBUILD_MODNAME
-#define MTK_RANGE(_a) { .range = (_a), .nranges = ARRAY_SIZE(_a), }
-#define PINCTRL_PIN_GROUP(name, id) \
- { \
- name, \
- id##_pins, \
- ARRAY_SIZE(id##_pins), \
- id##_funcs, \
- }
-
-#define MTK_GPIO_MODE 1
-#define MTK_INPUT 0
-#define MTK_OUTPUT 1
-#define MTK_DISABLE 0
-#define MTK_ENABLE 1
-
-/* Custom pinconf parameters */
-#define MTK_PIN_CONFIG_TDSEL (PIN_CONFIG_END + 1)
-#define MTK_PIN_CONFIG_RDSEL (PIN_CONFIG_END + 2)
-
-/* List these attributes which could be modified for the pin */
-enum {
- PINCTRL_PIN_REG_MODE,
- PINCTRL_PIN_REG_DIR,
- PINCTRL_PIN_REG_DI,
- PINCTRL_PIN_REG_DO,
- PINCTRL_PIN_REG_SR,
- PINCTRL_PIN_REG_SMT,
- PINCTRL_PIN_REG_PD,
- PINCTRL_PIN_REG_PU,
- PINCTRL_PIN_REG_E4,
- PINCTRL_PIN_REG_E8,
- PINCTRL_PIN_REG_TDSEL,
- PINCTRL_PIN_REG_RDSEL,
- PINCTRL_PIN_REG_MAX,
-};
-
-/* struct mtk_pin_field - the structure that holds the information of the field
- * used to describe the attribute for the pin
- * @offset: the register offset relative to the base address
- * @mask: the mask used to filter out the field from the register
- * @bitpos: the start bit relative to the register
- * @next: the indication that the field would be extended to the
- next register
*/
-struct mtk_pin_field {
- u32 offset;
- u32 mask;
- u8 bitpos;
- u8 next;
-};
-/* struct mtk_pin_field_calc - the structure that holds the range providing
- * the guide used to look up the relevant field
- * @s_pin: the start pin within the range
- * @e_pin: the end pin within the range
- * @s_addr: the start address for the range
- * @x_addrs: the address distance between two consecutive registers
- * within the range
- * @s_bit: the start bit for the first register within the range
- * @x_bits: the bit distance between two consecutive pins within
- * the range
- */
-struct mtk_pin_field_calc {
- u16 s_pin;
- u16 e_pin;
- u32 s_addr;
- u8 x_addrs;
- u8 s_bit;
- u8 x_bits;
-};
+#include "pinctrl-moore.h"
-/* struct mtk_pin_reg_calc - the structure that holds all ranges used to
- * determine which register the pin would make use of
- * for certain pin attribute.
- * @range: the start address for the range
- * @nranges: the number of items in the range
- */
-struct mtk_pin_reg_calc {
- const struct mtk_pin_field_calc *range;
- unsigned int nranges;
-};
-
-/* struct mtk_pin_soc - the structure that holds SoC-specific data */
-struct mtk_pin_soc {
- const struct mtk_pin_reg_calc *reg_cal;
- const struct pinctrl_pin_desc *pins;
- unsigned int npins;
- const struct group_desc *grps;
- unsigned int ngrps;
- const struct function_desc *funcs;
- unsigned int nfuncs;
- const struct mtk_eint_regs *eint_regs;
- const struct mtk_eint_hw *eint_hw;
-};
-
-struct mtk_pinctrl {
- struct pinctrl_dev *pctrl;
- void __iomem *base;
- struct device *dev;
- struct gpio_chip chip;
- const struct mtk_pin_soc *soc;
- struct mtk_eint *eint;
-};
+#define MT7622_PIN(_number, _name) \
+ MTK_PIN(_number, _name, 1, _number, DRV_GRP0)
static const struct mtk_pin_field_calc mt7622_pin_mode_range[] = {
- {0, 0, 0x320, 0x10, 16, 4},
- {1, 4, 0x3a0, 0x10, 16, 4},
- {5, 5, 0x320, 0x10, 0, 4},
- {6, 6, 0x300, 0x10, 4, 4},
- {7, 7, 0x300, 0x10, 4, 4},
- {8, 9, 0x350, 0x10, 20, 4},
- {10, 10, 0x300, 0x10, 8, 4},
- {11, 11, 0x300, 0x10, 8, 4},
- {12, 12, 0x300, 0x10, 8, 4},
- {13, 13, 0x300, 0x10, 8, 4},
- {14, 15, 0x320, 0x10, 4, 4},
- {16, 17, 0x320, 0x10, 20, 4},
- {18, 21, 0x310, 0x10, 16, 4},
- {22, 22, 0x380, 0x10, 16, 4},
- {23, 23, 0x300, 0x10, 24, 4},
- {24, 24, 0x300, 0x10, 24, 4},
- {25, 25, 0x300, 0x10, 12, 4},
- {25, 25, 0x300, 0x10, 12, 4},
- {26, 26, 0x300, 0x10, 12, 4},
- {27, 27, 0x300, 0x10, 12, 4},
- {28, 28, 0x300, 0x10, 12, 4},
- {29, 29, 0x300, 0x10, 12, 4},
- {30, 30, 0x300, 0x10, 12, 4},
- {31, 31, 0x300, 0x10, 12, 4},
- {32, 32, 0x300, 0x10, 12, 4},
- {33, 33, 0x300, 0x10, 12, 4},
- {34, 34, 0x300, 0x10, 12, 4},
- {35, 35, 0x300, 0x10, 12, 4},
- {36, 36, 0x300, 0x10, 12, 4},
- {37, 37, 0x300, 0x10, 20, 4},
- {38, 38, 0x300, 0x10, 20, 4},
- {39, 39, 0x300, 0x10, 20, 4},
- {40, 40, 0x300, 0x10, 20, 4},
- {41, 41, 0x300, 0x10, 20, 4},
- {42, 42, 0x300, 0x10, 20, 4},
- {43, 43, 0x300, 0x10, 20, 4},
- {44, 44, 0x300, 0x10, 20, 4},
- {45, 46, 0x300, 0x10, 20, 4},
- {47, 47, 0x300, 0x10, 20, 4},
- {48, 48, 0x300, 0x10, 20, 4},
- {49, 49, 0x300, 0x10, 20, 4},
- {50, 50, 0x300, 0x10, 20, 4},
- {51, 70, 0x330, 0x10, 4, 4},
- {71, 71, 0x300, 0x10, 16, 4},
- {72, 72, 0x300, 0x10, 16, 4},
- {73, 76, 0x310, 0x10, 0, 4},
- {77, 77, 0x320, 0x10, 28, 4},
- {78, 78, 0x320, 0x10, 12, 4},
- {79, 82, 0x3a0, 0x10, 0, 4},
- {83, 83, 0x350, 0x10, 28, 4},
- {84, 84, 0x330, 0x10, 0, 4},
- {85, 90, 0x360, 0x10, 4, 4},
- {91, 94, 0x390, 0x10, 16, 4},
- {95, 97, 0x380, 0x10, 20, 4},
- {98, 101, 0x390, 0x10, 0, 4},
- {102, 102, 0x360, 0x10, 0, 4},
+ PIN_FIELD(0, 0, 0x320, 0x10, 16, 4),
+ PIN_FIELD(1, 4, 0x3a0, 0x10, 16, 4),
+ PIN_FIELD(5, 5, 0x320, 0x10, 0, 4),
+ PINS_FIELD(6, 7, 0x300, 0x10, 4, 4),
+ PIN_FIELD(8, 9, 0x350, 0x10, 20, 4),
+ PINS_FIELD(10, 13, 0x300, 0x10, 8, 4),
+ PIN_FIELD(14, 15, 0x320, 0x10, 4, 4),
+ PIN_FIELD(16, 17, 0x320, 0x10, 20, 4),
+ PIN_FIELD(18, 21, 0x310, 0x10, 16, 4),
+ PIN_FIELD(22, 22, 0x380, 0x10, 16, 4),
+ PINS_FIELD(23, 24, 0x300, 0x10, 24, 4),
+ PINS_FIELD(25, 36, 0x300, 0x10, 12, 4),
+ PINS_FIELD(37, 50, 0x300, 0x10, 20, 4),
+ PIN_FIELD(51, 70, 0x330, 0x10, 4, 4),
+ PINS_FIELD(71, 72, 0x300, 0x10, 16, 4),
+ PIN_FIELD(73, 76, 0x310, 0x10, 0, 4),
+ PIN_FIELD(77, 77, 0x320, 0x10, 28, 4),
+ PIN_FIELD(78, 78, 0x320, 0x10, 12, 4),
+ PIN_FIELD(79, 82, 0x3a0, 0x10, 0, 4),
+ PIN_FIELD(83, 83, 0x350, 0x10, 28, 4),
+ PIN_FIELD(84, 84, 0x330, 0x10, 0, 4),
+ PIN_FIELD(85, 90, 0x360, 0x10, 4, 4),
+ PIN_FIELD(91, 94, 0x390, 0x10, 16, 4),
+ PIN_FIELD(95, 97, 0x380, 0x10, 20, 4),
+ PIN_FIELD(98, 101, 0x390, 0x10, 0, 4),
+ PIN_FIELD(102, 102, 0x360, 0x10, 0, 4),
};
static const struct mtk_pin_field_calc mt7622_pin_dir_range[] = {
- {0, 102, 0x0, 0x10, 0, 1},
+ PIN_FIELD(0, 102, 0x0, 0x10, 0, 1),
};
static const struct mtk_pin_field_calc mt7622_pin_di_range[] = {
- {0, 102, 0x200, 0x10, 0, 1},
+ PIN_FIELD(0, 102, 0x200, 0x10, 0, 1),
};
static const struct mtk_pin_field_calc mt7622_pin_do_range[] = {
- {0, 102, 0x100, 0x10, 0, 1},
+ PIN_FIELD(0, 102, 0x100, 0x10, 0, 1),
};
static const struct mtk_pin_field_calc mt7622_pin_sr_range[] = {
- {0, 31, 0x910, 0x10, 0, 1},
- {32, 50, 0xa10, 0x10, 0, 1},
- {51, 70, 0x810, 0x10, 0, 1},
- {71, 72, 0xb10, 0x10, 0, 1},
- {73, 86, 0xb10, 0x10, 4, 1},
- {87, 90, 0xc10, 0x10, 0, 1},
- {91, 102, 0xb10, 0x10, 18, 1},
+ PIN_FIELD(0, 31, 0x910, 0x10, 0, 1),
+ PIN_FIELD(32, 50, 0xa10, 0x10, 0, 1),
+ PIN_FIELD(51, 70, 0x810, 0x10, 0, 1),
+ PIN_FIELD(71, 72, 0xb10, 0x10, 0, 1),
+ PIN_FIELD(73, 86, 0xb10, 0x10, 4, 1),
+ PIN_FIELD(87, 90, 0xc10, 0x10, 0, 1),
+ PIN_FIELD(91, 102, 0xb10, 0x10, 18, 1),
};
static const struct mtk_pin_field_calc mt7622_pin_smt_range[] = {
- {0, 31, 0x920, 0x10, 0, 1},
- {32, 50, 0xa20, 0x10, 0, 1},
- {51, 70, 0x820, 0x10, 0, 1},
- {71, 72, 0xb20, 0x10, 0, 1},
- {73, 86, 0xb20, 0x10, 4, 1},
- {87, 90, 0xc20, 0x10, 0, 1},
- {91, 102, 0xb20, 0x10, 18, 1},
+ PIN_FIELD(0, 31, 0x920, 0x10, 0, 1),
+ PIN_FIELD(32, 50, 0xa20, 0x10, 0, 1),
+ PIN_FIELD(51, 70, 0x820, 0x10, 0, 1),
+ PIN_FIELD(71, 72, 0xb20, 0x10, 0, 1),
+ PIN_FIELD(73, 86, 0xb20, 0x10, 4, 1),
+ PIN_FIELD(87, 90, 0xc20, 0x10, 0, 1),
+ PIN_FIELD(91, 102, 0xb20, 0x10, 18, 1),
};
static const struct mtk_pin_field_calc mt7622_pin_pu_range[] = {
- {0, 31, 0x930, 0x10, 0, 1},
- {32, 50, 0xa30, 0x10, 0, 1},
- {51, 70, 0x830, 0x10, 0, 1},
- {71, 72, 0xb30, 0x10, 0, 1},
- {73, 86, 0xb30, 0x10, 4, 1},
- {87, 90, 0xc30, 0x10, 0, 1},
- {91, 102, 0xb30, 0x10, 18, 1},
+ PIN_FIELD(0, 31, 0x930, 0x10, 0, 1),
+ PIN_FIELD(32, 50, 0xa30, 0x10, 0, 1),
+ PIN_FIELD(51, 70, 0x830, 0x10, 0, 1),
+ PIN_FIELD(71, 72, 0xb30, 0x10, 0, 1),
+ PIN_FIELD(73, 86, 0xb30, 0x10, 4, 1),
+ PIN_FIELD(87, 90, 0xc30, 0x10, 0, 1),
+ PIN_FIELD(91, 102, 0xb30, 0x10, 18, 1),
};
static const struct mtk_pin_field_calc mt7622_pin_pd_range[] = {
- {0, 31, 0x940, 0x10, 0, 1},
- {32, 50, 0xa40, 0x10, 0, 1},
- {51, 70, 0x840, 0x10, 0, 1},
- {71, 72, 0xb40, 0x10, 0, 1},
- {73, 86, 0xb40, 0x10, 4, 1},
- {87, 90, 0xc40, 0x10, 0, 1},
- {91, 102, 0xb40, 0x10, 18, 1},
+ PIN_FIELD(0, 31, 0x940, 0x10, 0, 1),
+ PIN_FIELD(32, 50, 0xa40, 0x10, 0, 1),
+ PIN_FIELD(51, 70, 0x840, 0x10, 0, 1),
+ PIN_FIELD(71, 72, 0xb40, 0x10, 0, 1),
+ PIN_FIELD(73, 86, 0xb40, 0x10, 4, 1),
+ PIN_FIELD(87, 90, 0xc40, 0x10, 0, 1),
+ PIN_FIELD(91, 102, 0xb40, 0x10, 18, 1),
};
static const struct mtk_pin_field_calc mt7622_pin_e4_range[] = {
- {0, 31, 0x960, 0x10, 0, 1},
- {32, 50, 0xa60, 0x10, 0, 1},
- {51, 70, 0x860, 0x10, 0, 1},
- {71, 72, 0xb60, 0x10, 0, 1},
- {73, 86, 0xb60, 0x10, 4, 1},
- {87, 90, 0xc60, 0x10, 0, 1},
- {91, 102, 0xb60, 0x10, 18, 1},
+ PIN_FIELD(0, 31, 0x960, 0x10, 0, 1),
+ PIN_FIELD(32, 50, 0xa60, 0x10, 0, 1),
+ PIN_FIELD(51, 70, 0x860, 0x10, 0, 1),
+ PIN_FIELD(71, 72, 0xb60, 0x10, 0, 1),
+ PIN_FIELD(73, 86, 0xb60, 0x10, 4, 1),
+ PIN_FIELD(87, 90, 0xc60, 0x10, 0, 1),
+ PIN_FIELD(91, 102, 0xb60, 0x10, 18, 1),
};
static const struct mtk_pin_field_calc mt7622_pin_e8_range[] = {
- {0, 31, 0x970, 0x10, 0, 1},
- {32, 50, 0xa70, 0x10, 0, 1},
- {51, 70, 0x870, 0x10, 0, 1},
- {71, 72, 0xb70, 0x10, 0, 1},
- {73, 86, 0xb70, 0x10, 4, 1},
- {87, 90, 0xc70, 0x10, 0, 1},
- {91, 102, 0xb70, 0x10, 18, 1},
+ PIN_FIELD(0, 31, 0x970, 0x10, 0, 1),
+ PIN_FIELD(32, 50, 0xa70, 0x10, 0, 1),
+ PIN_FIELD(51, 70, 0x870, 0x10, 0, 1),
+ PIN_FIELD(71, 72, 0xb70, 0x10, 0, 1),
+ PIN_FIELD(73, 86, 0xb70, 0x10, 4, 1),
+ PIN_FIELD(87, 90, 0xc70, 0x10, 0, 1),
+ PIN_FIELD(91, 102, 0xb70, 0x10, 18, 1),
};
static const struct mtk_pin_field_calc mt7622_pin_tdsel_range[] = {
- {0, 31, 0x980, 0x4, 0, 4},
- {32, 50, 0xa80, 0x4, 0, 4},
- {51, 70, 0x880, 0x4, 0, 4},
- {71, 72, 0xb80, 0x4, 0, 4},
- {73, 86, 0xb80, 0x4, 16, 4},
- {87, 90, 0xc80, 0x4, 0, 4},
- {91, 102, 0xb88, 0x4, 8, 4},
+ PIN_FIELD(0, 31, 0x980, 0x4, 0, 4),
+ PIN_FIELD(32, 50, 0xa80, 0x4, 0, 4),
+ PIN_FIELD(51, 70, 0x880, 0x4, 0, 4),
+ PIN_FIELD(71, 72, 0xb80, 0x4, 0, 4),
+ PIN_FIELD(73, 86, 0xb80, 0x4, 16, 4),
+ PIN_FIELD(87, 90, 0xc80, 0x4, 0, 4),
+ PIN_FIELD(91, 102, 0xb88, 0x4, 8, 4),
};
static const struct mtk_pin_field_calc mt7622_pin_rdsel_range[] = {
- {0, 31, 0x990, 0x4, 0, 6},
- {32, 50, 0xa90, 0x4, 0, 6},
- {51, 58, 0x890, 0x4, 0, 6},
- {59, 60, 0x894, 0x4, 28, 6},
- {61, 62, 0x894, 0x4, 16, 6},
- {63, 66, 0x898, 0x4, 8, 6},
- {67, 68, 0x89c, 0x4, 12, 6},
- {69, 70, 0x89c, 0x4, 0, 6},
- {71, 72, 0xb90, 0x4, 0, 6},
- {73, 86, 0xb90, 0x4, 24, 6},
- {87, 90, 0xc90, 0x4, 0, 6},
- {91, 102, 0xb9c, 0x4, 12, 6},
+ PIN_FIELD(0, 31, 0x990, 0x4, 0, 6),
+ PIN_FIELD(32, 50, 0xa90, 0x4, 0, 6),
+ PIN_FIELD(51, 58, 0x890, 0x4, 0, 6),
+ PIN_FIELD(59, 60, 0x894, 0x4, 28, 6),
+ PIN_FIELD(61, 62, 0x894, 0x4, 16, 6),
+ PIN_FIELD(63, 66, 0x898, 0x4, 8, 6),
+ PIN_FIELD(67, 68, 0x89c, 0x4, 12, 6),
+ PIN_FIELD(69, 70, 0x89c, 0x4, 0, 6),
+ PIN_FIELD(71, 72, 0xb90, 0x4, 0, 6),
+ PIN_FIELD(73, 86, 0xb90, 0x4, 24, 6),
+ PIN_FIELD(87, 90, 0xc90, 0x4, 0, 6),
+ PIN_FIELD(91, 102, 0xb9c, 0x4, 12, 6),
};
static const struct mtk_pin_reg_calc mt7622_reg_cals[PINCTRL_PIN_REG_MAX] = {
@@ -309,110 +152,110 @@ static const struct mtk_pin_reg_calc mt7622_reg_cals[PINCTRL_PIN_REG_MAX] = {
[PINCTRL_PIN_REG_RDSEL] = MTK_RANGE(mt7622_pin_rdsel_range),
};
-static const struct pinctrl_pin_desc mt7622_pins[] = {
- PINCTRL_PIN(0, "GPIO_A"),
- PINCTRL_PIN(1, "I2S1_IN"),
- PINCTRL_PIN(2, "I2S1_OUT"),
- PINCTRL_PIN(3, "I2S_BCLK"),
- PINCTRL_PIN(4, "I2S_WS"),
- PINCTRL_PIN(5, "I2S_MCLK"),
- PINCTRL_PIN(6, "TXD0"),
- PINCTRL_PIN(7, "RXD0"),
- PINCTRL_PIN(8, "SPI_WP"),
- PINCTRL_PIN(9, "SPI_HOLD"),
- PINCTRL_PIN(10, "SPI_CLK"),
- PINCTRL_PIN(11, "SPI_MOSI"),
- PINCTRL_PIN(12, "SPI_MISO"),
- PINCTRL_PIN(13, "SPI_CS"),
- PINCTRL_PIN(14, "I2C_SDA"),
- PINCTRL_PIN(15, "I2C_SCL"),
- PINCTRL_PIN(16, "I2S2_IN"),
- PINCTRL_PIN(17, "I2S3_IN"),
- PINCTRL_PIN(18, "I2S4_IN"),
- PINCTRL_PIN(19, "I2S2_OUT"),
- PINCTRL_PIN(20, "I2S3_OUT"),
- PINCTRL_PIN(21, "I2S4_OUT"),
- PINCTRL_PIN(22, "GPIO_B"),
- PINCTRL_PIN(23, "MDC"),
- PINCTRL_PIN(24, "MDIO"),
- PINCTRL_PIN(25, "G2_TXD0"),
- PINCTRL_PIN(26, "G2_TXD1"),
- PINCTRL_PIN(27, "G2_TXD2"),
- PINCTRL_PIN(28, "G2_TXD3"),
- PINCTRL_PIN(29, "G2_TXEN"),
- PINCTRL_PIN(30, "G2_TXC"),
- PINCTRL_PIN(31, "G2_RXD0"),
- PINCTRL_PIN(32, "G2_RXD1"),
- PINCTRL_PIN(33, "G2_RXD2"),
- PINCTRL_PIN(34, "G2_RXD3"),
- PINCTRL_PIN(35, "G2_RXDV"),
- PINCTRL_PIN(36, "G2_RXC"),
- PINCTRL_PIN(37, "NCEB"),
- PINCTRL_PIN(38, "NWEB"),
- PINCTRL_PIN(39, "NREB"),
- PINCTRL_PIN(40, "NDL4"),
- PINCTRL_PIN(41, "NDL5"),
- PINCTRL_PIN(42, "NDL6"),
- PINCTRL_PIN(43, "NDL7"),
- PINCTRL_PIN(44, "NRB"),
- PINCTRL_PIN(45, "NCLE"),
- PINCTRL_PIN(46, "NALE"),
- PINCTRL_PIN(47, "NDL0"),
- PINCTRL_PIN(48, "NDL1"),
- PINCTRL_PIN(49, "NDL2"),
- PINCTRL_PIN(50, "NDL3"),
- PINCTRL_PIN(51, "MDI_TP_P0"),
- PINCTRL_PIN(52, "MDI_TN_P0"),
- PINCTRL_PIN(53, "MDI_RP_P0"),
- PINCTRL_PIN(54, "MDI_RN_P0"),
- PINCTRL_PIN(55, "MDI_TP_P1"),
- PINCTRL_PIN(56, "MDI_TN_P1"),
- PINCTRL_PIN(57, "MDI_RP_P1"),
- PINCTRL_PIN(58, "MDI_RN_P1"),
- PINCTRL_PIN(59, "MDI_RP_P2"),
- PINCTRL_PIN(60, "MDI_RN_P2"),
- PINCTRL_PIN(61, "MDI_TP_P2"),
- PINCTRL_PIN(62, "MDI_TN_P2"),
- PINCTRL_PIN(63, "MDI_TP_P3"),
- PINCTRL_PIN(64, "MDI_TN_P3"),
- PINCTRL_PIN(65, "MDI_RP_P3"),
- PINCTRL_PIN(66, "MDI_RN_P3"),
- PINCTRL_PIN(67, "MDI_RP_P4"),
- PINCTRL_PIN(68, "MDI_RN_P4"),
- PINCTRL_PIN(69, "MDI_TP_P4"),
- PINCTRL_PIN(70, "MDI_TN_P4"),
- PINCTRL_PIN(71, "PMIC_SCL"),
- PINCTRL_PIN(72, "PMIC_SDA"),
- PINCTRL_PIN(73, "SPIC1_CLK"),
- PINCTRL_PIN(74, "SPIC1_MOSI"),
- PINCTRL_PIN(75, "SPIC1_MISO"),
- PINCTRL_PIN(76, "SPIC1_CS"),
- PINCTRL_PIN(77, "GPIO_D"),
- PINCTRL_PIN(78, "WATCHDOG"),
- PINCTRL_PIN(79, "RTS3_N"),
- PINCTRL_PIN(80, "CTS3_N"),
- PINCTRL_PIN(81, "TXD3"),
- PINCTRL_PIN(82, "RXD3"),
- PINCTRL_PIN(83, "PERST0_N"),
- PINCTRL_PIN(84, "PERST1_N"),
- PINCTRL_PIN(85, "WLED_N"),
- PINCTRL_PIN(86, "EPHY_LED0_N"),
- PINCTRL_PIN(87, "AUXIN0"),
- PINCTRL_PIN(88, "AUXIN1"),
- PINCTRL_PIN(89, "AUXIN2"),
- PINCTRL_PIN(90, "AUXIN3"),
- PINCTRL_PIN(91, "TXD4"),
- PINCTRL_PIN(92, "RXD4"),
- PINCTRL_PIN(93, "RTS4_N"),
- PINCTRL_PIN(94, "CTS4_N"),
- PINCTRL_PIN(95, "PWM1"),
- PINCTRL_PIN(96, "PWM2"),
- PINCTRL_PIN(97, "PWM3"),
- PINCTRL_PIN(98, "PWM4"),
- PINCTRL_PIN(99, "PWM5"),
- PINCTRL_PIN(100, "PWM6"),
- PINCTRL_PIN(101, "PWM7"),
- PINCTRL_PIN(102, "GPIO_E"),
+static const struct mtk_pin_desc mt7622_pins[] = {
+ MT7622_PIN(0, "GPIO_A"),
+ MT7622_PIN(1, "I2S1_IN"),
+ MT7622_PIN(2, "I2S1_OUT"),
+ MT7622_PIN(3, "I2S_BCLK"),
+ MT7622_PIN(4, "I2S_WS"),
+ MT7622_PIN(5, "I2S_MCLK"),
+ MT7622_PIN(6, "TXD0"),
+ MT7622_PIN(7, "RXD0"),
+ MT7622_PIN(8, "SPI_WP"),
+ MT7622_PIN(9, "SPI_HOLD"),
+ MT7622_PIN(10, "SPI_CLK"),
+ MT7622_PIN(11, "SPI_MOSI"),
+ MT7622_PIN(12, "SPI_MISO"),
+ MT7622_PIN(13, "SPI_CS"),
+ MT7622_PIN(14, "I2C_SDA"),
+ MT7622_PIN(15, "I2C_SCL"),
+ MT7622_PIN(16, "I2S2_IN"),
+ MT7622_PIN(17, "I2S3_IN"),
+ MT7622_PIN(18, "I2S4_IN"),
+ MT7622_PIN(19, "I2S2_OUT"),
+ MT7622_PIN(20, "I2S3_OUT"),
+ MT7622_PIN(21, "I2S4_OUT"),
+ MT7622_PIN(22, "GPIO_B"),
+ MT7622_PIN(23, "MDC"),
+ MT7622_PIN(24, "MDIO"),
+ MT7622_PIN(25, "G2_TXD0"),
+ MT7622_PIN(26, "G2_TXD1"),
+ MT7622_PIN(27, "G2_TXD2"),
+ MT7622_PIN(28, "G2_TXD3"),
+ MT7622_PIN(29, "G2_TXEN"),
+ MT7622_PIN(30, "G2_TXC"),
+ MT7622_PIN(31, "G2_RXD0"),
+ MT7622_PIN(32, "G2_RXD1"),
+ MT7622_PIN(33, "G2_RXD2"),
+ MT7622_PIN(34, "G2_RXD3"),
+ MT7622_PIN(35, "G2_RXDV"),
+ MT7622_PIN(36, "G2_RXC"),
+ MT7622_PIN(37, "NCEB"),
+ MT7622_PIN(38, "NWEB"),
+ MT7622_PIN(39, "NREB"),
+ MT7622_PIN(40, "NDL4"),
+ MT7622_PIN(41, "NDL5"),
+ MT7622_PIN(42, "NDL6"),
+ MT7622_PIN(43, "NDL7"),
+ MT7622_PIN(44, "NRB"),
+ MT7622_PIN(45, "NCLE"),
+ MT7622_PIN(46, "NALE"),
+ MT7622_PIN(47, "NDL0"),
+ MT7622_PIN(48, "NDL1"),
+ MT7622_PIN(49, "NDL2"),
+ MT7622_PIN(50, "NDL3"),
+ MT7622_PIN(51, "MDI_TP_P0"),
+ MT7622_PIN(52, "MDI_TN_P0"),
+ MT7622_PIN(53, "MDI_RP_P0"),
+ MT7622_PIN(54, "MDI_RN_P0"),
+ MT7622_PIN(55, "MDI_TP_P1"),
+ MT7622_PIN(56, "MDI_TN_P1"),
+ MT7622_PIN(57, "MDI_RP_P1"),
+ MT7622_PIN(58, "MDI_RN_P1"),
+ MT7622_PIN(59, "MDI_RP_P2"),
+ MT7622_PIN(60, "MDI_RN_P2"),
+ MT7622_PIN(61, "MDI_TP_P2"),
+ MT7622_PIN(62, "MDI_TN_P2"),
+ MT7622_PIN(63, "MDI_TP_P3"),
+ MT7622_PIN(64, "MDI_TN_P3"),
+ MT7622_PIN(65, "MDI_RP_P3"),
+ MT7622_PIN(66, "MDI_RN_P3"),
+ MT7622_PIN(67, "MDI_RP_P4"),
+ MT7622_PIN(68, "MDI_RN_P4"),
+ MT7622_PIN(69, "MDI_TP_P4"),
+ MT7622_PIN(70, "MDI_TN_P4"),
+ MT7622_PIN(71, "PMIC_SCL"),
+ MT7622_PIN(72, "PMIC_SDA"),
+ MT7622_PIN(73, "SPIC1_CLK"),
+ MT7622_PIN(74, "SPIC1_MOSI"),
+ MT7622_PIN(75, "SPIC1_MISO"),
+ MT7622_PIN(76, "SPIC1_CS"),
+ MT7622_PIN(77, "GPIO_D"),
+ MT7622_PIN(78, "WATCHDOG"),
+ MT7622_PIN(79, "RTS3_N"),
+ MT7622_PIN(80, "CTS3_N"),
+ MT7622_PIN(81, "TXD3"),
+ MT7622_PIN(82, "RXD3"),
+ MT7622_PIN(83, "PERST0_N"),
+ MT7622_PIN(84, "PERST1_N"),
+ MT7622_PIN(85, "WLED_N"),
+ MT7622_PIN(86, "EPHY_LED0_N"),
+ MT7622_PIN(87, "AUXIN0"),
+ MT7622_PIN(88, "AUXIN1"),
+ MT7622_PIN(89, "AUXIN2"),
+ MT7622_PIN(90, "AUXIN3"),
+ MT7622_PIN(91, "TXD4"),
+ MT7622_PIN(92, "RXD4"),
+ MT7622_PIN(93, "RTS4_N"),
+ MT7622_PIN(94, "CTS4_N"),
+ MT7622_PIN(95, "PWM1"),
+ MT7622_PIN(96, "PWM2"),
+ MT7622_PIN(97, "PWM3"),
+ MT7622_PIN(98, "PWM4"),
+ MT7622_PIN(99, "PWM5"),
+ MT7622_PIN(100, "PWM6"),
+ MT7622_PIN(101, "PWM7"),
+ MT7622_PIN(102, "GPIO_E"),
};
/* List all groups consisting of these pins dedicated to the enablement of
@@ -906,18 +749,6 @@ static const struct function_desc mt7622_functions[] = {
{"watchdog", mt7622_wdt_groups, ARRAY_SIZE(mt7622_wdt_groups)},
};
-static const struct pinconf_generic_params mtk_custom_bindings[] = {
- {"mediatek,tdsel", MTK_PIN_CONFIG_TDSEL, 0},
- {"mediatek,rdsel", MTK_PIN_CONFIG_RDSEL, 0},
-};
-
-#ifdef CONFIG_DEBUG_FS
-static const struct pin_config_item mtk_conf_items[] = {
- PCONFDUMP(MTK_PIN_CONFIG_TDSEL, "tdsel", NULL, true),
- PCONFDUMP(MTK_PIN_CONFIG_RDSEL, "rdsel", NULL, true),
-};
-#endif
-
static const struct mtk_eint_hw mt7622_eint_hw = {
.port_mask = 7,
.ports = 7,
@@ -934,830 +765,38 @@ static const struct mtk_pin_soc mt7622_data = {
.funcs = mt7622_functions,
.nfuncs = ARRAY_SIZE(mt7622_functions),
.eint_hw = &mt7622_eint_hw,
-};
-
-static void mtk_w32(struct mtk_pinctrl *pctl, u32 reg, u32 val)
-{
- writel_relaxed(val, pctl->base + reg);
-}
-
-static u32 mtk_r32(struct mtk_pinctrl *pctl, u32 reg)
-{
- return readl_relaxed(pctl->base + reg);
-}
-
-static void mtk_rmw(struct mtk_pinctrl *pctl, u32 reg, u32 mask, u32 set)
-{
- u32 val;
-
- val = mtk_r32(pctl, reg);
- val &= ~mask;
- val |= set;
- mtk_w32(pctl, reg, val);
-}
-
-static int mtk_hw_pin_field_lookup(struct mtk_pinctrl *hw, int pin,
- const struct mtk_pin_reg_calc *rc,
- struct mtk_pin_field *pfd)
-{
- const struct mtk_pin_field_calc *c, *e;
- u32 bits;
-
- c = rc->range;
- e = c + rc->nranges;
-
- while (c < e) {
- if (pin >= c->s_pin && pin <= c->e_pin)
- break;
- c++;
- }
-
- if (c >= e) {
- dev_err(hw->dev, "Out of range for pin = %d\n", pin);
- return -EINVAL;
- }
-
- /* Caculated bits as the overall offset the pin is located at */
- bits = c->s_bit + (pin - c->s_pin) * (c->x_bits);
-
- /* Fill pfd from bits and 32-bit register applied is assumed */
- pfd->offset = c->s_addr + c->x_addrs * (bits / 32);
- pfd->bitpos = bits % 32;
- pfd->mask = (1 << c->x_bits) - 1;
-
- /* pfd->next is used for indicating that bit wrapping-around happens
- * which requires the manipulation for bit 0 starting in the next
- * register to form the complete field read/write.
- */
- pfd->next = pfd->bitpos + c->x_bits - 1 > 31 ? c->x_addrs : 0;
-
- return 0;
-}
-
-static int mtk_hw_pin_field_get(struct mtk_pinctrl *hw, int pin,
- int field, struct mtk_pin_field *pfd)
-{
- const struct mtk_pin_reg_calc *rc;
-
- if (field < 0 || field >= PINCTRL_PIN_REG_MAX) {
- dev_err(hw->dev, "Invalid Field %d\n", field);
- return -EINVAL;
- }
-
- if (hw->soc->reg_cal && hw->soc->reg_cal[field].range) {
- rc = &hw->soc->reg_cal[field];
- } else {
- dev_err(hw->dev, "Undefined range for field %d\n", field);
- return -EINVAL;
- }
-
- return mtk_hw_pin_field_lookup(hw, pin, rc, pfd);
-}
-
-static void mtk_hw_bits_part(struct mtk_pin_field *pf, int *h, int *l)
-{
- *l = 32 - pf->bitpos;
- *h = get_count_order(pf->mask) - *l;
-}
-
-static void mtk_hw_write_cross_field(struct mtk_pinctrl *hw,
- struct mtk_pin_field *pf, int value)
-{
- int nbits_l, nbits_h;
-
- mtk_hw_bits_part(pf, &nbits_h, &nbits_l);
-
- mtk_rmw(hw, pf->offset, pf->mask << pf->bitpos,
- (value & pf->mask) << pf->bitpos);
-
- mtk_rmw(hw, pf->offset + pf->next, BIT(nbits_h) - 1,
- (value & pf->mask) >> nbits_l);
-}
-
-static void mtk_hw_read_cross_field(struct mtk_pinctrl *hw,
- struct mtk_pin_field *pf, int *value)
-{
- int nbits_l, nbits_h, h, l;
-
- mtk_hw_bits_part(pf, &nbits_h, &nbits_l);
-
- l = (mtk_r32(hw, pf->offset) >> pf->bitpos) & (BIT(nbits_l) - 1);
- h = (mtk_r32(hw, pf->offset + pf->next)) & (BIT(nbits_h) - 1);
-
- *value = (h << nbits_l) | l;
-}
-
-static int mtk_hw_set_value(struct mtk_pinctrl *hw, int pin, int field,
- int value)
-{
- struct mtk_pin_field pf;
- int err;
-
- err = mtk_hw_pin_field_get(hw, pin, field, &pf);
- if (err)
- return err;
-
- if (!pf.next)
- mtk_rmw(hw, pf.offset, pf.mask << pf.bitpos,
- (value & pf.mask) << pf.bitpos);
- else
- mtk_hw_write_cross_field(hw, &pf, value);
-
- return 0;
-}
-
-static int mtk_hw_get_value(struct mtk_pinctrl *hw, int pin, int field,
- int *value)
-{
- struct mtk_pin_field pf;
- int err;
-
- err = mtk_hw_pin_field_get(hw, pin, field, &pf);
- if (err)
- return err;
-
- if (!pf.next)
- *value = (mtk_r32(hw, pf.offset) >> pf.bitpos) & pf.mask;
- else
- mtk_hw_read_cross_field(hw, &pf, value);
-
- return 0;
-}
-
-static int mtk_pinmux_set_mux(struct pinctrl_dev *pctldev,
- unsigned int selector, unsigned int group)
-{
- struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev);
- struct function_desc *func;
- struct group_desc *grp;
- int i;
-
- func = pinmux_generic_get_function(pctldev, selector);
- if (!func)
- return -EINVAL;
-
- grp = pinctrl_generic_get_group(pctldev, group);
- if (!grp)
- return -EINVAL;
-
- dev_dbg(pctldev->dev, "enable function %s group %s\n",
- func->name, grp->name);
-
- for (i = 0; i < grp->num_pins; i++) {
- int *pin_modes = grp->data;
-
- mtk_hw_set_value(hw, grp->pins[i], PINCTRL_PIN_REG_MODE,
- pin_modes[i]);
- }
-
- return 0;
-}
-
-static int mtk_pinmux_gpio_request_enable(struct pinctrl_dev *pctldev,
- struct pinctrl_gpio_range *range,
- unsigned int pin)
-{
- struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev);
-
- return mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_MODE, MTK_GPIO_MODE);
-}
-
-static int mtk_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
- struct pinctrl_gpio_range *range,
- unsigned int pin, bool input)
-{
- struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev);
-
- /* hardware would take 0 as input direction */
- return mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_DIR, !input);
-}
-
-static int mtk_pinconf_get(struct pinctrl_dev *pctldev,
- unsigned int pin, unsigned long *config)
-{
- struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev);
- u32 param = pinconf_to_config_param(*config);
- int val, val2, err, reg, ret = 1;
-
- switch (param) {
- case PIN_CONFIG_BIAS_DISABLE:
- err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_PU, &val);
- if (err)
- return err;
-
- err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_PD, &val2);
- if (err)
- return err;
-
- if (val || val2)
- return -EINVAL;
-
- break;
- case PIN_CONFIG_BIAS_PULL_UP:
- case PIN_CONFIG_BIAS_PULL_DOWN:
- case PIN_CONFIG_SLEW_RATE:
- reg = (param == PIN_CONFIG_BIAS_PULL_UP) ?
- PINCTRL_PIN_REG_PU :
- (param == PIN_CONFIG_BIAS_PULL_DOWN) ?
- PINCTRL_PIN_REG_PD : PINCTRL_PIN_REG_SR;
-
- err = mtk_hw_get_value(hw, pin, reg, &val);
- if (err)
- return err;
-
- if (!val)
- return -EINVAL;
-
- break;
- case PIN_CONFIG_INPUT_ENABLE:
- case PIN_CONFIG_OUTPUT_ENABLE:
- err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_DIR, &val);
- if (err)
- return err;
-
- /* HW takes input mode as zero; output mode as non-zero */
- if ((val && param == PIN_CONFIG_INPUT_ENABLE) ||
- (!val && param == PIN_CONFIG_OUTPUT_ENABLE))
- return -EINVAL;
-
- break;
- case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
- err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_DIR, &val);
- if (err)
- return err;
-
- err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_SMT, &val2);
- if (err)
- return err;
-
- if (val || !val2)
- return -EINVAL;
-
- break;
- case PIN_CONFIG_DRIVE_STRENGTH:
- err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_E4, &val);
- if (err)
- return err;
-
- err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_E8, &val2);
- if (err)
- return err;
-
- /* 4mA when (e8, e4) = (0, 0); 8mA when (e8, e4) = (0, 1)
- * 12mA when (e8, e4) = (1, 0); 16mA when (e8, e4) = (1, 1)
- */
- ret = ((val2 << 1) + val + 1) * 4;
-
- break;
- case MTK_PIN_CONFIG_TDSEL:
- case MTK_PIN_CONFIG_RDSEL:
- reg = (param == MTK_PIN_CONFIG_TDSEL) ?
- PINCTRL_PIN_REG_TDSEL : PINCTRL_PIN_REG_RDSEL;
-
- err = mtk_hw_get_value(hw, pin, reg, &val);
- if (err)
- return err;
-
- ret = val;
-
- break;
- default:
- return -ENOTSUPP;
- }
-
- *config = pinconf_to_config_packed(param, ret);
-
- return 0;
-}
-
-static int mtk_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
- unsigned long *configs, unsigned int num_configs)
-{
- struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev);
- u32 reg, param, arg;
- int cfg, err = 0;
-
- for (cfg = 0; cfg < num_configs; cfg++) {
- param = pinconf_to_config_param(configs[cfg]);
- arg = pinconf_to_config_argument(configs[cfg]);
-
- switch (param) {
- case PIN_CONFIG_BIAS_DISABLE:
- case PIN_CONFIG_BIAS_PULL_UP:
- case PIN_CONFIG_BIAS_PULL_DOWN:
- arg = (param == PIN_CONFIG_BIAS_DISABLE) ? 0 :
- (param == PIN_CONFIG_BIAS_PULL_UP) ? 1 : 2;
-
- err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_PU,
- arg & 1);
- if (err)
- goto err;
-
- err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_PD,
- !!(arg & 2));
- if (err)
- goto err;
- break;
- case PIN_CONFIG_OUTPUT_ENABLE:
- err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_SMT,
- MTK_DISABLE);
- if (err)
- goto err;
- /* else: fall through */
- case PIN_CONFIG_INPUT_ENABLE:
- case PIN_CONFIG_SLEW_RATE:
- reg = (param == PIN_CONFIG_SLEW_RATE) ?
- PINCTRL_PIN_REG_SR : PINCTRL_PIN_REG_DIR;
-
- arg = (param == PIN_CONFIG_INPUT_ENABLE) ? 0 :
- (param == PIN_CONFIG_OUTPUT_ENABLE) ? 1 : arg;
- err = mtk_hw_set_value(hw, pin, reg, arg);
- if (err)
- goto err;
-
- break;
- case PIN_CONFIG_OUTPUT:
- err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_DIR,
- MTK_OUTPUT);
- if (err)
- goto err;
-
- err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_DO,
- arg);
- if (err)
- goto err;
- break;
- case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
- /* arg = 1: Input mode & SMT enable ;
- * arg = 0: Output mode & SMT disable
- */
- arg = arg ? 2 : 1;
- err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_DIR,
- arg & 1);
- if (err)
- goto err;
-
- err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_SMT,
- !!(arg & 2));
- if (err)
- goto err;
- break;
- case PIN_CONFIG_DRIVE_STRENGTH:
- /* 4mA when (e8, e4) = (0, 0);
- * 8mA when (e8, e4) = (0, 1);
- * 12mA when (e8, e4) = (1, 0);
- * 16mA when (e8, e4) = (1, 1)
- */
- if (!(arg % 4) && (arg >= 4 && arg <= 16)) {
- arg = arg / 4 - 1;
- err = mtk_hw_set_value(hw, pin,
- PINCTRL_PIN_REG_E4,
- arg & 0x1);
- if (err)
- goto err;
-
- err = mtk_hw_set_value(hw, pin,
- PINCTRL_PIN_REG_E8,
- (arg & 0x2) >> 1);
- if (err)
- goto err;
- } else {
- err = -ENOTSUPP;
- }
- break;
- case MTK_PIN_CONFIG_TDSEL:
- case MTK_PIN_CONFIG_RDSEL:
- reg = (param == MTK_PIN_CONFIG_TDSEL) ?
- PINCTRL_PIN_REG_TDSEL : PINCTRL_PIN_REG_RDSEL;
-
- err = mtk_hw_set_value(hw, pin, reg, arg);
- if (err)
- goto err;
- break;
- default:
- err = -ENOTSUPP;
- }
- }
-err:
- return err;
-}
-
-static int mtk_pinconf_group_get(struct pinctrl_dev *pctldev,
- unsigned int group, unsigned long *config)
-{
- const unsigned int *pins;
- unsigned int i, npins, old = 0;
- int ret;
-
- ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins);
- if (ret)
- return ret;
-
- for (i = 0; i < npins; i++) {
- if (mtk_pinconf_get(pctldev, pins[i], config))
- return -ENOTSUPP;
-
- /* configs do not match between two pins */
- if (i && old != *config)
- return -ENOTSUPP;
-
- old = *config;
- }
-
- return 0;
-}
-
-static int mtk_pinconf_group_set(struct pinctrl_dev *pctldev,
- unsigned int group, unsigned long *configs,
- unsigned int num_configs)
-{
- const unsigned int *pins;
- unsigned int i, npins;
- int ret;
-
- ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins);
- if (ret)
- return ret;
-
- for (i = 0; i < npins; i++) {
- ret = mtk_pinconf_set(pctldev, pins[i], configs, num_configs);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-static const struct pinctrl_ops mtk_pctlops = {
- .get_groups_count = pinctrl_generic_get_group_count,
- .get_group_name = pinctrl_generic_get_group_name,
- .get_group_pins = pinctrl_generic_get_group_pins,
- .dt_node_to_map = pinconf_generic_dt_node_to_map_all,
- .dt_free_map = pinconf_generic_dt_free_map,
-};
-
-static const struct pinmux_ops mtk_pmxops = {
- .get_functions_count = pinmux_generic_get_function_count,
- .get_function_name = pinmux_generic_get_function_name,
- .get_function_groups = pinmux_generic_get_function_groups,
- .set_mux = mtk_pinmux_set_mux,
- .gpio_request_enable = mtk_pinmux_gpio_request_enable,
- .gpio_set_direction = mtk_pinmux_gpio_set_direction,
- .strict = true,
-};
-
-static const struct pinconf_ops mtk_confops = {
- .is_generic = true,
- .pin_config_get = mtk_pinconf_get,
- .pin_config_set = mtk_pinconf_set,
- .pin_config_group_get = mtk_pinconf_group_get,
- .pin_config_group_set = mtk_pinconf_group_set,
- .pin_config_config_dbg_show = pinconf_generic_dump_config,
-};
-
-static struct pinctrl_desc mtk_desc = {
- .name = PINCTRL_PINCTRL_DEV,
- .pctlops = &mtk_pctlops,
- .pmxops = &mtk_pmxops,
- .confops = &mtk_confops,
- .owner = THIS_MODULE,
-};
-
-static int mtk_gpio_get(struct gpio_chip *chip, unsigned int gpio)
-{
- struct mtk_pinctrl *hw = gpiochip_get_data(chip);
- int value, err;
-
- err = mtk_hw_get_value(hw, gpio, PINCTRL_PIN_REG_DI, &value);
- if (err)
- return err;
-
- return !!value;
-}
-
-static void mtk_gpio_set(struct gpio_chip *chip, unsigned int gpio, int value)
-{
- struct mtk_pinctrl *hw = gpiochip_get_data(chip);
-
- mtk_hw_set_value(hw, gpio, PINCTRL_PIN_REG_DO, !!value);
-}
-
-static int mtk_gpio_direction_input(struct gpio_chip *chip, unsigned int gpio)
-{
- return pinctrl_gpio_direction_input(chip->base + gpio);
-}
-
-static int mtk_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio,
- int value)
-{
- mtk_gpio_set(chip, gpio, value);
-
- return pinctrl_gpio_direction_output(chip->base + gpio);
-}
-
-static int mtk_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
-{
- struct mtk_pinctrl *hw = gpiochip_get_data(chip);
- unsigned long eint_n;
-
- if (!hw->eint)
- return -ENOTSUPP;
-
- eint_n = offset;
-
- return mtk_eint_find_irq(hw->eint, eint_n);
-}
-
-static int mtk_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
- unsigned long config)
-{
- struct mtk_pinctrl *hw = gpiochip_get_data(chip);
- unsigned long eint_n;
- u32 debounce;
-
- if (!hw->eint ||
- pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
- return -ENOTSUPP;
-
- debounce = pinconf_to_config_argument(config);
- eint_n = offset;
-
- return mtk_eint_set_debounce(hw->eint, eint_n, debounce);
-}
-
-static int mtk_build_gpiochip(struct mtk_pinctrl *hw, struct device_node *np)
-{
- struct gpio_chip *chip = &hw->chip;
- int ret;
-
- chip->label = PINCTRL_PINCTRL_DEV;
- chip->parent = hw->dev;
- chip->request = gpiochip_generic_request;
- chip->free = gpiochip_generic_free;
- chip->direction_input = mtk_gpio_direction_input;
- chip->direction_output = mtk_gpio_direction_output;
- chip->get = mtk_gpio_get;
- chip->set = mtk_gpio_set;
- chip->to_irq = mtk_gpio_to_irq,
- chip->set_config = mtk_gpio_set_config,
- chip->base = -1;
- chip->ngpio = hw->soc->npins;
- chip->of_node = np;
- chip->of_gpio_n_cells = 2;
-
- ret = gpiochip_add_data(chip, hw);
- if (ret < 0)
- return ret;
-
- /* Just for backward compatible for these old pinctrl nodes without
- * "gpio-ranges" property. Otherwise, called directly from a
- * DeviceTree-supported pinctrl driver is DEPRECATED.
- * Please see Section 2.1 of
- * Documentation/devicetree/bindings/gpio/gpio.txt on how to
- * bind pinctrl and gpio drivers via the "gpio-ranges" property.
- */
- if (!of_find_property(np, "gpio-ranges", NULL)) {
- ret = gpiochip_add_pin_range(chip, dev_name(hw->dev), 0, 0,
- chip->ngpio);
- if (ret < 0) {
- gpiochip_remove(chip);
- return ret;
- }
- }
-
- return 0;
-}
-
-static int mtk_build_groups(struct mtk_pinctrl *hw)
-{
- int err, i;
-
- for (i = 0; i < hw->soc->ngrps; i++) {
- const struct group_desc *group = hw->soc->grps + i;
-
- err = pinctrl_generic_add_group(hw->pctrl, group->name,
- group->pins, group->num_pins,
- group->data);
- if (err < 0) {
- dev_err(hw->dev, "Failed to register group %s\n",
- group->name);
- return err;
- }
- }
-
- return 0;
-}
-
-static int mtk_build_functions(struct mtk_pinctrl *hw)
-{
- int i, err;
-
- for (i = 0; i < hw->soc->nfuncs ; i++) {
- const struct function_desc *func = hw->soc->funcs + i;
-
- err = pinmux_generic_add_function(hw->pctrl, func->name,
- func->group_names,
- func->num_group_names,
- func->data);
- if (err < 0) {
- dev_err(hw->dev, "Failed to register function %s\n",
- func->name);
- return err;
- }
- }
-
- return 0;
-}
-
-static int mtk_xt_get_gpio_n(void *data, unsigned long eint_n,
- unsigned int *gpio_n,
- struct gpio_chip **gpio_chip)
-{
- struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data;
-
- *gpio_chip = &hw->chip;
- *gpio_n = eint_n;
-
- return 0;
-}
-
-static int mtk_xt_get_gpio_state(void *data, unsigned long eint_n)
-{
- struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data;
- struct gpio_chip *gpio_chip;
- unsigned int gpio_n;
- int err;
-
- err = mtk_xt_get_gpio_n(hw, eint_n, &gpio_n, &gpio_chip);
- if (err)
- return err;
-
- return mtk_gpio_get(gpio_chip, gpio_n);
-}
-
-static int mtk_xt_set_gpio_as_eint(void *data, unsigned long eint_n)
-{
- struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data;
- struct gpio_chip *gpio_chip;
- unsigned int gpio_n;
- int err;
-
- err = mtk_xt_get_gpio_n(hw, eint_n, &gpio_n, &gpio_chip);
- if (err)
- return err;
-
- err = mtk_hw_set_value(hw, gpio_n, PINCTRL_PIN_REG_MODE,
- MTK_GPIO_MODE);
- if (err)
- return err;
-
- err = mtk_hw_set_value(hw, gpio_n, PINCTRL_PIN_REG_DIR, MTK_INPUT);
- if (err)
- return err;
-
- err = mtk_hw_set_value(hw, gpio_n, PINCTRL_PIN_REG_SMT, MTK_ENABLE);
- if (err)
- return err;
-
- return 0;
-}
-
-static const struct mtk_eint_xt mtk_eint_xt = {
- .get_gpio_n = mtk_xt_get_gpio_n,
- .get_gpio_state = mtk_xt_get_gpio_state,
- .set_gpio_as_eint = mtk_xt_set_gpio_as_eint,
-};
-
-static int
-mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev)
-{
- struct device_node *np = pdev->dev.of_node;
- struct resource *res;
-
- if (!IS_ENABLED(CONFIG_EINT_MTK))
- return 0;
-
- if (!of_property_read_bool(np, "interrupt-controller"))
- return -ENODEV;
-
- hw->eint = devm_kzalloc(hw->dev, sizeof(*hw->eint), GFP_KERNEL);
- if (!hw->eint)
- return -ENOMEM;
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "eint");
- if (!res) {
- dev_err(&pdev->dev, "Unable to get eint resource\n");
- return -ENODEV;
- }
-
- hw->eint->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(hw->eint->base))
- return PTR_ERR(hw->eint->base);
-
- hw->eint->irq = irq_of_parse_and_map(np, 0);
- if (!hw->eint->irq)
- return -EINVAL;
-
- hw->eint->dev = &pdev->dev;
- hw->eint->hw = hw->soc->eint_hw;
- hw->eint->pctl = hw;
- hw->eint->gpio_xlate = &mtk_eint_xt;
-
- return mtk_eint_do_init(hw->eint);
-}
-
-static const struct of_device_id mtk_pinctrl_of_match[] = {
- { .compatible = "mediatek,mt7622-pinctrl", .data = &mt7622_data},
+ .gpio_m = 1,
+ .ies_present = false,
+ .base_names = mtk_default_register_base_names,
+ .nbase_names = ARRAY_SIZE(mtk_default_register_base_names),
+ .bias_disable_set = mtk_pinconf_bias_disable_set,
+ .bias_disable_get = mtk_pinconf_bias_disable_get,
+ .bias_set = mtk_pinconf_bias_set,
+ .bias_get = mtk_pinconf_bias_get,
+ .drive_set = mtk_pinconf_drive_set,
+ .drive_get = mtk_pinconf_drive_get,
+};
+
+static const struct of_device_id mt7622_pinctrl_of_match[] = {
+ { .compatible = "mediatek,mt7622-pinctrl", },
{ }
};
-static int mtk_pinctrl_probe(struct platform_device *pdev)
+static int mt7622_pinctrl_probe(struct platform_device *pdev)
{
- struct resource *res;
- struct mtk_pinctrl *hw;
- const struct of_device_id *of_id =
- of_match_device(mtk_pinctrl_of_match, &pdev->dev);
- int err;
-
- hw = devm_kzalloc(&pdev->dev, sizeof(*hw), GFP_KERNEL);
- if (!hw)
- return -ENOMEM;
-
- hw->soc = of_id->data;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "missing IO resource\n");
- return -ENXIO;
- }
-
- hw->dev = &pdev->dev;
- hw->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(hw->base))
- return PTR_ERR(hw->base);
-
- /* Setup pins descriptions per SoC types */
- mtk_desc.pins = hw->soc->pins;
- mtk_desc.npins = hw->soc->npins;
- mtk_desc.num_custom_params = ARRAY_SIZE(mtk_custom_bindings);
- mtk_desc.custom_params = mtk_custom_bindings;
-#ifdef CONFIG_DEBUG_FS
- mtk_desc.custom_conf_items = mtk_conf_items;
-#endif
-
- err = devm_pinctrl_register_and_init(&pdev->dev, &mtk_desc, hw,
- &hw->pctrl);
- if (err)
- return err;
-
- /* Setup groups descriptions per SoC types */
- err = mtk_build_groups(hw);
- if (err) {
- dev_err(&pdev->dev, "Failed to build groups\n");
- return err;
- }
-
- /* Setup functions descriptions per SoC types */
- err = mtk_build_functions(hw);
- if (err) {
- dev_err(&pdev->dev, "Failed to build functions\n");
- return err;
- }
-
- /* For able to make pinctrl_claim_hogs, we must not enable pinctrl
- * until all groups and functions are being added one.
- */
- err = pinctrl_enable(hw->pctrl);
- if (err)
- return err;
-
- err = mtk_build_eint(hw, pdev);
- if (err)
- dev_warn(&pdev->dev,
- "Failed to add EINT, but pinctrl still can work\n");
-
- /* Build gpiochip should be after pinctrl_enable is done */
- err = mtk_build_gpiochip(hw, pdev->dev.of_node);
- if (err) {
- dev_err(&pdev->dev, "Failed to add gpio_chip\n");
- return err;
- }
-
- platform_set_drvdata(pdev, hw);
-
- return 0;
+ return mtk_moore_pinctrl_probe(pdev, &mt7622_data);
}
-static struct platform_driver mtk_pinctrl_driver = {
+static struct platform_driver mt7622_pinctrl_driver = {
.driver = {
- .name = "mtk-pinctrl",
- .of_match_table = mtk_pinctrl_of_match,
+ .name = "mt7622-pinctrl",
+ .of_match_table = mt7622_pinctrl_of_match,
},
- .probe = mtk_pinctrl_probe,
+ .probe = mt7622_pinctrl_probe,
};
-static int __init mtk_pinctrl_init(void)
+static int __init mt7622_pinctrl_init(void)
{
- return platform_driver_register(&mtk_pinctrl_driver);
+ return platform_driver_register(&mt7622_pinctrl_driver);
}
-arch_initcall(mtk_pinctrl_init);
+arch_initcall(mt7622_pinctrl_init);
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7623.c b/drivers/pinctrl/mediatek/pinctrl-mt7623.c
new file mode 100644
index 000000000000..b8d9d31db74f
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-mt7623.c
@@ -0,0 +1,1441 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * The MT7623 driver based on Linux generic pinctrl binding.
+ *
+ * Copyright (C) 2015 - 2018 MediaTek Inc.
+ * Author: Biao Huang <biao.huang@mediatek.com>
+ * Ryder Lee <ryder.lee@mediatek.com>
+ * Sean Wang <sean.wang@mediatek.com>
+ */
+
+#include "pinctrl-moore.h"
+
+#define PIN_BOND_REG0 0xb10
+#define PIN_BOND_REG1 0xf20
+#define PIN_BOND_REG2 0xef0
+#define BOND_PCIE_CLR (0x77 << 3)
+#define BOND_I2S_CLR 0x3
+#define BOND_MSDC0E_CLR 0x1
+
+#define PIN_FIELD15(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit, _x_bits) \
+ PIN_FIELD_CALC(_s_pin, _e_pin, 0, _s_addr, _x_addrs, _s_bit, \
+ _x_bits, 15, false)
+
+#define PIN_FIELD16(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit, _x_bits) \
+ PIN_FIELD_CALC(_s_pin, _e_pin, 0, _s_addr, _x_addrs, _s_bit, \
+ _x_bits, 16, 0)
+
+#define PINS_FIELD16(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit, _x_bits) \
+ PIN_FIELD_CALC(_s_pin, _e_pin, 0, _s_addr, _x_addrs, _s_bit, \
+ _x_bits, 16, 1)
+
+#define MT7623_PIN(_number, _name, _eint_n, _drv_grp) \
+ MTK_PIN(_number, _name, 0, _eint_n, _drv_grp)
+
+static const struct mtk_pin_field_calc mt7623_pin_mode_range[] = {
+ PIN_FIELD15(0, 278, 0x760, 0x10, 0, 3),
+};
+
+static const struct mtk_pin_field_calc mt7623_pin_dir_range[] = {
+ PIN_FIELD16(0, 175, 0x0, 0x10, 0, 1),
+ PIN_FIELD16(176, 278, 0xc0, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7623_pin_di_range[] = {
+ PIN_FIELD16(0, 278, 0x630, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7623_pin_do_range[] = {
+ PIN_FIELD16(0, 278, 0x500, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7623_pin_ies_range[] = {
+ PINS_FIELD16(0, 6, 0xb20, 0x10, 0, 1),
+ PINS_FIELD16(7, 9, 0xb20, 0x10, 1, 1),
+ PINS_FIELD16(10, 13, 0xb30, 0x10, 3, 1),
+ PINS_FIELD16(14, 15, 0xb30, 0x10, 13, 1),
+ PINS_FIELD16(16, 17, 0xb40, 0x10, 7, 1),
+ PINS_FIELD16(18, 29, 0xb40, 0x10, 13, 1),
+ PINS_FIELD16(30, 32, 0xb40, 0x10, 7, 1),
+ PINS_FIELD16(33, 37, 0xb40, 0x10, 13, 1),
+ PIN_FIELD16(38, 38, 0xb20, 0x10, 13, 1),
+ PINS_FIELD16(39, 42, 0xb40, 0x10, 13, 1),
+ PINS_FIELD16(43, 45, 0xb20, 0x10, 10, 1),
+ PINS_FIELD16(47, 48, 0xb20, 0x10, 11, 1),
+ PIN_FIELD16(49, 49, 0xb20, 0x10, 12, 1),
+ PINS_FIELD16(50, 52, 0xb20, 0x10, 13, 1),
+ PINS_FIELD16(53, 56, 0xb20, 0x10, 14, 1),
+ PINS_FIELD16(57, 58, 0xb20, 0x10, 15, 1),
+ PIN_FIELD16(59, 59, 0xb30, 0x10, 10, 1),
+ PINS_FIELD16(60, 62, 0xb30, 0x10, 0, 1),
+ PINS_FIELD16(63, 65, 0xb30, 0x10, 1, 1),
+ PINS_FIELD16(66, 71, 0xb30, 0x10, 2, 1),
+ PINS_FIELD16(72, 74, 0xb20, 0x10, 12, 1),
+ PINS_FIELD16(75, 76, 0xb30, 0x10, 3, 1),
+ PINS_FIELD16(77, 78, 0xb30, 0x10, 4, 1),
+ PINS_FIELD16(79, 82, 0xb30, 0x10, 5, 1),
+ PINS_FIELD16(83, 84, 0xb30, 0x10, 2, 1),
+ PIN_FIELD16(85, 85, 0xda0, 0x10, 4, 1),
+ PIN_FIELD16(86, 86, 0xd90, 0x10, 4, 1),
+ PINS_FIELD16(87, 90, 0xdb0, 0x10, 4, 1),
+ PINS_FIELD16(101, 104, 0xb30, 0x10, 6, 1),
+ PIN_FIELD16(105, 105, 0xd40, 0x10, 4, 1),
+ PIN_FIELD16(106, 106, 0xd30, 0x10, 4, 1),
+ PINS_FIELD16(107, 110, 0xd50, 0x10, 4, 1),
+ PINS_FIELD16(111, 115, 0xce0, 0x10, 4, 1),
+ PIN_FIELD16(116, 116, 0xcd0, 0x10, 4, 1),
+ PIN_FIELD16(117, 117, 0xcc0, 0x10, 4, 1),
+ PINS_FIELD16(118, 121, 0xce0, 0x10, 4, 1),
+ PINS_FIELD16(122, 125, 0xb30, 0x10, 7, 1),
+ PIN_FIELD16(126, 126, 0xb20, 0x10, 12, 1),
+ PINS_FIELD16(127, 142, 0xb30, 0x10, 9, 1),
+ PINS_FIELD16(143, 160, 0xb30, 0x10, 10, 1),
+ PINS_FIELD16(161, 168, 0xb30, 0x10, 12, 1),
+ PINS_FIELD16(169, 183, 0xb30, 0x10, 10, 1),
+ PINS_FIELD16(184, 186, 0xb30, 0x10, 9, 1),
+ PIN_FIELD16(187, 187, 0xb30, 0x10, 14, 1),
+ PIN_FIELD16(188, 188, 0xb20, 0x10, 13, 1),
+ PINS_FIELD16(189, 193, 0xb30, 0x10, 15, 1),
+ PINS_FIELD16(194, 198, 0xb40, 0x10, 0, 1),
+ PIN_FIELD16(199, 199, 0xb20, 0x10, 1, 1),
+ PINS_FIELD16(200, 202, 0xb40, 0x10, 1, 1),
+ PINS_FIELD16(203, 207, 0xb40, 0x10, 2, 1),
+ PINS_FIELD16(208, 209, 0xb40, 0x10, 3, 1),
+ PIN_FIELD16(210, 210, 0xb40, 0x10, 4, 1),
+ PINS_FIELD16(211, 235, 0xb40, 0x10, 5, 1),
+ PINS_FIELD16(236, 241, 0xb40, 0x10, 6, 1),
+ PINS_FIELD16(242, 243, 0xb40, 0x10, 7, 1),
+ PINS_FIELD16(244, 247, 0xb40, 0x10, 8, 1),
+ PIN_FIELD16(248, 248, 0xb40, 0x10, 9, 1),
+ PINS_FIELD16(249, 257, 0xfc0, 0x10, 4, 1),
+ PIN_FIELD16(258, 258, 0xcb0, 0x10, 4, 1),
+ PIN_FIELD16(259, 259, 0xc90, 0x10, 4, 1),
+ PIN_FIELD16(260, 260, 0x3a0, 0x10, 4, 1),
+ PIN_FIELD16(261, 261, 0xd50, 0x10, 4, 1),
+ PINS_FIELD16(262, 277, 0xb40, 0x10, 12, 1),
+ PIN_FIELD16(278, 278, 0xb40, 0x10, 13, 1),
+};
+
+static const struct mtk_pin_field_calc mt7623_pin_smt_range[] = {
+ PINS_FIELD16(0, 6, 0xb50, 0x10, 0, 1),
+ PINS_FIELD16(7, 9, 0xb50, 0x10, 1, 1),
+ PINS_FIELD16(10, 13, 0xb60, 0x10, 3, 1),
+ PINS_FIELD16(14, 15, 0xb60, 0x10, 13, 1),
+ PINS_FIELD16(16, 17, 0xb70, 0x10, 7, 1),
+ PINS_FIELD16(18, 29, 0xb70, 0x10, 13, 1),
+ PINS_FIELD16(30, 32, 0xb70, 0x10, 7, 1),
+ PINS_FIELD16(33, 37, 0xb70, 0x10, 13, 1),
+ PIN_FIELD16(38, 38, 0xb50, 0x10, 13, 1),
+ PINS_FIELD16(39, 42, 0xb70, 0x10, 13, 1),
+ PINS_FIELD16(43, 45, 0xb50, 0x10, 10, 1),
+ PINS_FIELD16(47, 48, 0xb50, 0x10, 11, 1),
+ PIN_FIELD16(49, 49, 0xb50, 0x10, 12, 1),
+ PINS_FIELD16(50, 52, 0xb50, 0x10, 13, 1),
+ PINS_FIELD16(53, 56, 0xb50, 0x10, 14, 1),
+ PINS_FIELD16(57, 58, 0xb50, 0x10, 15, 1),
+ PIN_FIELD16(59, 59, 0xb60, 0x10, 10, 1),
+ PINS_FIELD16(60, 62, 0xb60, 0x10, 0, 1),
+ PINS_FIELD16(63, 65, 0xb60, 0x10, 1, 1),
+ PINS_FIELD16(66, 71, 0xb60, 0x10, 2, 1),
+ PINS_FIELD16(72, 74, 0xb50, 0x10, 12, 1),
+ PINS_FIELD16(75, 76, 0xb60, 0x10, 3, 1),
+ PINS_FIELD16(77, 78, 0xb60, 0x10, 4, 1),
+ PINS_FIELD16(79, 82, 0xb60, 0x10, 5, 1),
+ PINS_FIELD16(83, 84, 0xb60, 0x10, 2, 1),
+ PIN_FIELD16(85, 85, 0xda0, 0x10, 11, 1),
+ PIN_FIELD16(86, 86, 0xd90, 0x10, 11, 1),
+ PIN_FIELD16(87, 87, 0xdc0, 0x10, 3, 1),
+ PIN_FIELD16(88, 88, 0xdc0, 0x10, 7, 1),
+ PIN_FIELD16(89, 89, 0xdc0, 0x10, 11, 1),
+ PIN_FIELD16(90, 90, 0xdc0, 0x10, 15, 1),
+ PINS_FIELD16(101, 104, 0xb60, 0x10, 6, 1),
+ PIN_FIELD16(105, 105, 0xd40, 0x10, 11, 1),
+ PIN_FIELD16(106, 106, 0xd30, 0x10, 11, 1),
+ PIN_FIELD16(107, 107, 0xd60, 0x10, 3, 1),
+ PIN_FIELD16(108, 108, 0xd60, 0x10, 7, 1),
+ PIN_FIELD16(109, 109, 0xd60, 0x10, 11, 1),
+ PIN_FIELD16(110, 110, 0xd60, 0x10, 15, 1),
+ PIN_FIELD16(111, 111, 0xd00, 0x10, 15, 1),
+ PIN_FIELD16(112, 112, 0xd00, 0x10, 11, 1),
+ PIN_FIELD16(113, 113, 0xd00, 0x10, 7, 1),
+ PIN_FIELD16(114, 114, 0xd00, 0x10, 3, 1),
+ PIN_FIELD16(115, 115, 0xd10, 0x10, 3, 1),
+ PIN_FIELD16(116, 116, 0xcd0, 0x10, 11, 1),
+ PIN_FIELD16(117, 117, 0xcc0, 0x10, 11, 1),
+ PIN_FIELD16(118, 118, 0xcf0, 0x10, 15, 1),
+ PIN_FIELD16(119, 119, 0xcf0, 0x10, 7, 1),
+ PIN_FIELD16(120, 120, 0xcf0, 0x10, 3, 1),
+ PIN_FIELD16(121, 121, 0xcf0, 0x10, 7, 1),
+ PINS_FIELD16(122, 125, 0xb60, 0x10, 7, 1),
+ PIN_FIELD16(126, 126, 0xb50, 0x10, 12, 1),
+ PINS_FIELD16(127, 142, 0xb60, 0x10, 9, 1),
+ PINS_FIELD16(143, 160, 0xb60, 0x10, 10, 1),
+ PINS_FIELD16(161, 168, 0xb60, 0x10, 12, 1),
+ PINS_FIELD16(169, 183, 0xb60, 0x10, 10, 1),
+ PINS_FIELD16(184, 186, 0xb60, 0x10, 9, 1),
+ PIN_FIELD16(187, 187, 0xb60, 0x10, 14, 1),
+ PIN_FIELD16(188, 188, 0xb50, 0x10, 13, 1),
+ PINS_FIELD16(189, 193, 0xb60, 0x10, 15, 1),
+ PINS_FIELD16(194, 198, 0xb70, 0x10, 0, 1),
+ PIN_FIELD16(199, 199, 0xb50, 0x10, 1, 1),
+ PINS_FIELD16(200, 202, 0xb70, 0x10, 1, 1),
+ PINS_FIELD16(203, 207, 0xb70, 0x10, 2, 1),
+ PINS_FIELD16(208, 209, 0xb70, 0x10, 3, 1),
+ PIN_FIELD16(210, 210, 0xb70, 0x10, 4, 1),
+ PINS_FIELD16(211, 235, 0xb70, 0x10, 5, 1),
+ PINS_FIELD16(236, 241, 0xb70, 0x10, 6, 1),
+ PINS_FIELD16(242, 243, 0xb70, 0x10, 7, 1),
+ PINS_FIELD16(244, 247, 0xb70, 0x10, 8, 1),
+ PIN_FIELD16(248, 248, 0xb70, 0x10, 9, 10),
+ PIN_FIELD16(249, 249, 0x140, 0x10, 3, 1),
+ PIN_FIELD16(250, 250, 0x130, 0x10, 15, 1),
+ PIN_FIELD16(251, 251, 0x130, 0x10, 11, 1),
+ PIN_FIELD16(252, 252, 0x130, 0x10, 7, 1),
+ PIN_FIELD16(253, 253, 0x130, 0x10, 3, 1),
+ PIN_FIELD16(254, 254, 0xf40, 0x10, 15, 1),
+ PIN_FIELD16(255, 255, 0xf40, 0x10, 11, 1),
+ PIN_FIELD16(256, 256, 0xf40, 0x10, 7, 1),
+ PIN_FIELD16(257, 257, 0xf40, 0x10, 3, 1),
+ PIN_FIELD16(258, 258, 0xcb0, 0x10, 11, 1),
+ PIN_FIELD16(259, 259, 0xc90, 0x10, 11, 1),
+ PIN_FIELD16(260, 260, 0x3a0, 0x10, 11, 1),
+ PIN_FIELD16(261, 261, 0x0b0, 0x10, 3, 1),
+ PINS_FIELD16(262, 277, 0xb70, 0x10, 12, 1),
+ PIN_FIELD16(278, 278, 0xb70, 0x10, 13, 1),
+};
+
+static const struct mtk_pin_field_calc mt7623_pin_pullen_range[] = {
+ PIN_FIELD16(0, 278, 0x150, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7623_pin_pullsel_range[] = {
+ PIN_FIELD16(0, 278, 0x280, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7623_pin_drv_range[] = {
+ PINS_FIELD16(0, 6, 0xf50, 0x10, 0, 4),
+ PINS_FIELD16(7, 9, 0xf50, 0x10, 4, 4),
+ PINS_FIELD16(10, 13, 0xf50, 0x10, 4, 4),
+ PINS_FIELD16(14, 15, 0xf50, 0x10, 12, 4),
+ PINS_FIELD16(16, 17, 0xf60, 0x10, 0, 4),
+ PINS_FIELD16(18, 21, 0xf60, 0x10, 0, 4),
+ PINS_FIELD16(22, 26, 0xf60, 0x10, 8, 4),
+ PINS_FIELD16(27, 29, 0xf60, 0x10, 12, 4),
+ PINS_FIELD16(30, 32, 0xf60, 0x10, 0, 4),
+ PINS_FIELD16(33, 37, 0xf70, 0x10, 0, 4),
+ PIN_FIELD16(38, 38, 0xf70, 0x10, 4, 4),
+ PINS_FIELD16(39, 42, 0xf70, 0x10, 8, 4),
+ PINS_FIELD16(43, 45, 0xf70, 0x10, 12, 4),
+ PINS_FIELD16(47, 48, 0xf80, 0x10, 0, 4),
+ PIN_FIELD16(49, 49, 0xf80, 0x10, 4, 4),
+ PINS_FIELD16(50, 52, 0xf70, 0x10, 4, 4),
+ PINS_FIELD16(53, 56, 0xf80, 0x10, 12, 4),
+ PINS_FIELD16(60, 62, 0xf90, 0x10, 8, 4),
+ PINS_FIELD16(63, 65, 0xf90, 0x10, 12, 4),
+ PINS_FIELD16(66, 71, 0xfa0, 0x10, 0, 4),
+ PINS_FIELD16(72, 74, 0xf80, 0x10, 4, 4),
+ PIN_FIELD16(85, 85, 0xda0, 0x10, 0, 4),
+ PIN_FIELD16(86, 86, 0xd90, 0x10, 0, 4),
+ PINS_FIELD16(87, 90, 0xdb0, 0x10, 0, 4),
+ PIN_FIELD16(105, 105, 0xd40, 0x10, 0, 4),
+ PIN_FIELD16(106, 106, 0xd30, 0x10, 0, 4),
+ PINS_FIELD16(107, 110, 0xd50, 0x10, 0, 4),
+ PINS_FIELD16(111, 115, 0xce0, 0x10, 0, 4),
+ PIN_FIELD16(116, 116, 0xcd0, 0x10, 0, 4),
+ PIN_FIELD16(117, 117, 0xcc0, 0x10, 0, 4),
+ PINS_FIELD16(118, 121, 0xce0, 0x10, 0, 4),
+ PIN_FIELD16(126, 126, 0xf80, 0x10, 4, 4),
+ PIN_FIELD16(188, 188, 0xf70, 0x10, 4, 4),
+ PINS_FIELD16(189, 193, 0xfe0, 0x10, 8, 4),
+ PINS_FIELD16(194, 198, 0xfe0, 0x10, 12, 4),
+ PIN_FIELD16(199, 199, 0xf50, 0x10, 4, 4),
+ PINS_FIELD16(200, 202, 0xfd0, 0x10, 0, 4),
+ PINS_FIELD16(203, 207, 0xfd0, 0x10, 4, 4),
+ PINS_FIELD16(208, 209, 0xfd0, 0x10, 8, 4),
+ PIN_FIELD16(210, 210, 0xfd0, 0x10, 12, 4),
+ PINS_FIELD16(211, 235, 0xff0, 0x10, 0, 4),
+ PINS_FIELD16(236, 241, 0xff0, 0x10, 4, 4),
+ PINS_FIELD16(242, 243, 0xff0, 0x10, 8, 4),
+ PIN_FIELD16(248, 248, 0xf00, 0x10, 0, 4),
+ PINS_FIELD16(249, 256, 0xfc0, 0x10, 0, 4),
+ PIN_FIELD16(257, 257, 0xce0, 0x10, 0, 4),
+ PIN_FIELD16(258, 258, 0xcb0, 0x10, 0, 4),
+ PIN_FIELD16(259, 259, 0xc90, 0x10, 0, 4),
+ PIN_FIELD16(260, 260, 0x3a0, 0x10, 0, 4),
+ PIN_FIELD16(261, 261, 0xd50, 0x10, 0, 4),
+ PINS_FIELD16(262, 277, 0xf00, 0x10, 8, 4),
+ PIN_FIELD16(278, 278, 0xf70, 0x10, 8, 4),
+};
+
+static const struct mtk_pin_field_calc mt7623_pin_tdsel_range[] = {
+ PINS_FIELD16(262, 276, 0x4c0, 0x10, 0, 4),
+};
+
+static const struct mtk_pin_field_calc mt7623_pin_pupd_range[] = {
+ /* MSDC0 */
+ PIN_FIELD16(111, 111, 0xd00, 0x10, 12, 1),
+ PIN_FIELD16(112, 112, 0xd00, 0x10, 8, 1),
+ PIN_FIELD16(113, 113, 0xd00, 0x10, 4, 1),
+ PIN_FIELD16(114, 114, 0xd00, 0x10, 0, 1),
+ PIN_FIELD16(115, 115, 0xd10, 0x10, 0, 1),
+ PIN_FIELD16(116, 116, 0xcd0, 0x10, 8, 1),
+ PIN_FIELD16(117, 117, 0xcc0, 0x10, 8, 1),
+ PIN_FIELD16(118, 118, 0xcf0, 0x10, 12, 1),
+ PIN_FIELD16(119, 119, 0xcf0, 0x10, 8, 1),
+ PIN_FIELD16(120, 120, 0xcf0, 0x10, 4, 1),
+ PIN_FIELD16(121, 121, 0xcf0, 0x10, 0, 1),
+ /* MSDC1 */
+ PIN_FIELD16(105, 105, 0xd40, 0x10, 8, 1),
+ PIN_FIELD16(106, 106, 0xd30, 0x10, 8, 1),
+ PIN_FIELD16(107, 107, 0xd60, 0x10, 0, 1),
+ PIN_FIELD16(108, 108, 0xd60, 0x10, 10, 1),
+ PIN_FIELD16(109, 109, 0xd60, 0x10, 4, 1),
+ PIN_FIELD16(110, 110, 0xc60, 0x10, 12, 1),
+ /* MSDC1 */
+ PIN_FIELD16(85, 85, 0xda0, 0x10, 8, 1),
+ PIN_FIELD16(86, 86, 0xd90, 0x10, 8, 1),
+ PIN_FIELD16(87, 87, 0xdc0, 0x10, 0, 1),
+ PIN_FIELD16(88, 88, 0xdc0, 0x10, 10, 1),
+ PIN_FIELD16(89, 89, 0xdc0, 0x10, 4, 1),
+ PIN_FIELD16(90, 90, 0xdc0, 0x10, 12, 1),
+ /* MSDC0E */
+ PIN_FIELD16(249, 249, 0x140, 0x10, 0, 1),
+ PIN_FIELD16(250, 250, 0x130, 0x10, 12, 1),
+ PIN_FIELD16(251, 251, 0x130, 0x10, 8, 1),
+ PIN_FIELD16(252, 252, 0x130, 0x10, 4, 1),
+ PIN_FIELD16(253, 253, 0x130, 0x10, 0, 1),
+ PIN_FIELD16(254, 254, 0xf40, 0x10, 12, 1),
+ PIN_FIELD16(255, 255, 0xf40, 0x10, 8, 1),
+ PIN_FIELD16(256, 256, 0xf40, 0x10, 4, 1),
+ PIN_FIELD16(257, 257, 0xf40, 0x10, 0, 1),
+ PIN_FIELD16(258, 258, 0xcb0, 0x10, 8, 1),
+ PIN_FIELD16(259, 259, 0xc90, 0x10, 8, 1),
+ PIN_FIELD16(261, 261, 0x140, 0x10, 8, 1),
+};
+
+static const struct mtk_pin_field_calc mt7623_pin_r1_range[] = {
+ /* MSDC0 */
+ PIN_FIELD16(111, 111, 0xd00, 0x10, 13, 1),
+ PIN_FIELD16(112, 112, 0xd00, 0x10, 9, 1),
+ PIN_FIELD16(113, 113, 0xd00, 0x10, 5, 1),
+ PIN_FIELD16(114, 114, 0xd00, 0x10, 1, 1),
+ PIN_FIELD16(115, 115, 0xd10, 0x10, 1, 1),
+ PIN_FIELD16(116, 116, 0xcd0, 0x10, 9, 1),
+ PIN_FIELD16(117, 117, 0xcc0, 0x10, 9, 1),
+ PIN_FIELD16(118, 118, 0xcf0, 0x10, 13, 1),
+ PIN_FIELD16(119, 119, 0xcf0, 0x10, 9, 1),
+ PIN_FIELD16(120, 120, 0xcf0, 0x10, 5, 1),
+ PIN_FIELD16(121, 121, 0xcf0, 0x10, 1, 1),
+ /* MSDC1 */
+ PIN_FIELD16(105, 105, 0xd40, 0x10, 9, 1),
+ PIN_FIELD16(106, 106, 0xd30, 0x10, 9, 1),
+ PIN_FIELD16(107, 107, 0xd60, 0x10, 1, 1),
+ PIN_FIELD16(108, 108, 0xd60, 0x10, 9, 1),
+ PIN_FIELD16(109, 109, 0xd60, 0x10, 5, 1),
+ PIN_FIELD16(110, 110, 0xc60, 0x10, 13, 1),
+ /* MSDC2 */
+ PIN_FIELD16(85, 85, 0xda0, 0x10, 9, 1),
+ PIN_FIELD16(86, 86, 0xd90, 0x10, 9, 1),
+ PIN_FIELD16(87, 87, 0xdc0, 0x10, 1, 1),
+ PIN_FIELD16(88, 88, 0xdc0, 0x10, 9, 1),
+ PIN_FIELD16(89, 89, 0xdc0, 0x10, 5, 1),
+ PIN_FIELD16(90, 90, 0xdc0, 0x10, 13, 1),
+ /* MSDC0E */
+ PIN_FIELD16(249, 249, 0x140, 0x10, 1, 1),
+ PIN_FIELD16(250, 250, 0x130, 0x10, 13, 1),
+ PIN_FIELD16(251, 251, 0x130, 0x10, 9, 1),
+ PIN_FIELD16(252, 252, 0x130, 0x10, 5, 1),
+ PIN_FIELD16(253, 253, 0x130, 0x10, 1, 1),
+ PIN_FIELD16(254, 254, 0xf40, 0x10, 13, 1),
+ PIN_FIELD16(255, 255, 0xf40, 0x10, 9, 1),
+ PIN_FIELD16(256, 256, 0xf40, 0x10, 5, 1),
+ PIN_FIELD16(257, 257, 0xf40, 0x10, 1, 1),
+ PIN_FIELD16(258, 258, 0xcb0, 0x10, 9, 1),
+ PIN_FIELD16(259, 259, 0xc90, 0x10, 9, 1),
+ PIN_FIELD16(261, 261, 0x140, 0x10, 9, 1),
+};
+
+static const struct mtk_pin_field_calc mt7623_pin_r0_range[] = {
+ /* MSDC0 */
+ PIN_FIELD16(111, 111, 0xd00, 0x10, 14, 1),
+ PIN_FIELD16(112, 112, 0xd00, 0x10, 10, 1),
+ PIN_FIELD16(113, 113, 0xd00, 0x10, 6, 1),
+ PIN_FIELD16(114, 114, 0xd00, 0x10, 2, 1),
+ PIN_FIELD16(115, 115, 0xd10, 0x10, 2, 1),
+ PIN_FIELD16(116, 116, 0xcd0, 0x10, 10, 1),
+ PIN_FIELD16(117, 117, 0xcc0, 0x10, 10, 1),
+ PIN_FIELD16(118, 118, 0xcf0, 0x10, 14, 1),
+ PIN_FIELD16(119, 119, 0xcf0, 0x10, 10, 1),
+ PIN_FIELD16(120, 120, 0xcf0, 0x10, 6, 1),
+ PIN_FIELD16(121, 121, 0xcf0, 0x10, 2, 1),
+ /* MSDC1 */
+ PIN_FIELD16(105, 105, 0xd40, 0x10, 10, 1),
+ PIN_FIELD16(106, 106, 0xd30, 0x10, 10, 1),
+ PIN_FIELD16(107, 107, 0xd60, 0x10, 2, 1),
+ PIN_FIELD16(108, 108, 0xd60, 0x10, 8, 1),
+ PIN_FIELD16(109, 109, 0xd60, 0x10, 6, 1),
+ PIN_FIELD16(110, 110, 0xc60, 0x10, 14, 1),
+ /* MSDC2 */
+ PIN_FIELD16(85, 85, 0xda0, 0x10, 10, 1),
+ PIN_FIELD16(86, 86, 0xd90, 0x10, 10, 1),
+ PIN_FIELD16(87, 87, 0xdc0, 0x10, 2, 1),
+ PIN_FIELD16(88, 88, 0xdc0, 0x10, 8, 1),
+ PIN_FIELD16(89, 89, 0xdc0, 0x10, 6, 1),
+ PIN_FIELD16(90, 90, 0xdc0, 0x10, 14, 1),
+ /* MSDC0E */
+ PIN_FIELD16(249, 249, 0x140, 0x10, 2, 1),
+ PIN_FIELD16(250, 250, 0x130, 0x10, 14, 1),
+ PIN_FIELD16(251, 251, 0x130, 0x10, 10, 1),
+ PIN_FIELD16(252, 252, 0x130, 0x10, 6, 1),
+ PIN_FIELD16(253, 253, 0x130, 0x10, 2, 1),
+ PIN_FIELD16(254, 254, 0xf40, 0x10, 14, 1),
+ PIN_FIELD16(255, 255, 0xf40, 0x10, 10, 1),
+ PIN_FIELD16(256, 256, 0xf40, 0x10, 6, 1),
+ PIN_FIELD16(257, 257, 0xf40, 0x10, 5, 1),
+ PIN_FIELD16(258, 258, 0xcb0, 0x10, 10, 1),
+ PIN_FIELD16(259, 259, 0xc90, 0x10, 10, 1),
+ PIN_FIELD16(261, 261, 0x140, 0x10, 10, 1),
+};
+
+static const struct mtk_pin_reg_calc mt7623_reg_cals[] = {
+ [PINCTRL_PIN_REG_MODE] = MTK_RANGE(mt7623_pin_mode_range),
+ [PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt7623_pin_dir_range),
+ [PINCTRL_PIN_REG_DI] = MTK_RANGE(mt7623_pin_di_range),
+ [PINCTRL_PIN_REG_DO] = MTK_RANGE(mt7623_pin_do_range),
+ [PINCTRL_PIN_REG_SMT] = MTK_RANGE(mt7623_pin_smt_range),
+ [PINCTRL_PIN_REG_PULLSEL] = MTK_RANGE(mt7623_pin_pullsel_range),
+ [PINCTRL_PIN_REG_PULLEN] = MTK_RANGE(mt7623_pin_pullen_range),
+ [PINCTRL_PIN_REG_DRV] = MTK_RANGE(mt7623_pin_drv_range),
+ [PINCTRL_PIN_REG_TDSEL] = MTK_RANGE(mt7623_pin_tdsel_range),
+ [PINCTRL_PIN_REG_IES] = MTK_RANGE(mt7623_pin_ies_range),
+ [PINCTRL_PIN_REG_PUPD] = MTK_RANGE(mt7623_pin_pupd_range),
+ [PINCTRL_PIN_REG_R0] = MTK_RANGE(mt7623_pin_r0_range),
+ [PINCTRL_PIN_REG_R1] = MTK_RANGE(mt7623_pin_r1_range),
+};
+
+static const struct mtk_pin_desc mt7623_pins[] = {
+ MT7623_PIN(0, "PWRAP_SPI0_MI", 148, DRV_GRP3),
+ MT7623_PIN(1, "PWRAP_SPI0_MO", 149, DRV_GRP3),
+ MT7623_PIN(2, "PWRAP_INT", 150, DRV_GRP3),
+ MT7623_PIN(3, "PWRAP_SPI0_CK", 151, DRV_GRP3),
+ MT7623_PIN(4, "PWRAP_SPI0_CSN", 152, DRV_GRP3),
+ MT7623_PIN(5, "PWRAP_SPI0_CK2", 153, DRV_GRP3),
+ MT7623_PIN(6, "PWRAP_SPI0_CSN2", 154, DRV_GRP3),
+ MT7623_PIN(7, "SPI1_CSN", 155, DRV_GRP3),
+ MT7623_PIN(8, "SPI1_MI", 156, DRV_GRP3),
+ MT7623_PIN(9, "SPI1_MO", 157, DRV_GRP3),
+ MT7623_PIN(10, "RTC32K_CK", 158, DRV_GRP3),
+ MT7623_PIN(11, "WATCHDOG", 159, DRV_GRP3),
+ MT7623_PIN(12, "SRCLKENA", 160, DRV_GRP3),
+ MT7623_PIN(13, "SRCLKENAI", 161, DRV_GRP3),
+ MT7623_PIN(14, "URXD2", 162, DRV_GRP1),
+ MT7623_PIN(15, "UTXD2", 163, DRV_GRP1),
+ MT7623_PIN(16, "I2S5_DATA_IN", 164, DRV_GRP1),
+ MT7623_PIN(17, "I2S5_BCK", 165, DRV_GRP1),
+ MT7623_PIN(18, "PCM_CLK", 166, DRV_GRP1),
+ MT7623_PIN(19, "PCM_SYNC", 167, DRV_GRP1),
+ MT7623_PIN(20, "PCM_RX", EINT_NA, DRV_GRP1),
+ MT7623_PIN(21, "PCM_TX", EINT_NA, DRV_GRP1),
+ MT7623_PIN(22, "EINT0", 0, DRV_GRP1),
+ MT7623_PIN(23, "EINT1", 1, DRV_GRP1),
+ MT7623_PIN(24, "EINT2", 2, DRV_GRP1),
+ MT7623_PIN(25, "EINT3", 3, DRV_GRP1),
+ MT7623_PIN(26, "EINT4", 4, DRV_GRP1),
+ MT7623_PIN(27, "EINT5", 5, DRV_GRP1),
+ MT7623_PIN(28, "EINT6", 6, DRV_GRP1),
+ MT7623_PIN(29, "EINT7", 7, DRV_GRP1),
+ MT7623_PIN(30, "I2S5_LRCK", 12, DRV_GRP1),
+ MT7623_PIN(31, "I2S5_MCLK", 13, DRV_GRP1),
+ MT7623_PIN(32, "I2S5_DATA", 14, DRV_GRP1),
+ MT7623_PIN(33, "I2S1_DATA", 15, DRV_GRP1),
+ MT7623_PIN(34, "I2S1_DATA_IN", 16, DRV_GRP1),
+ MT7623_PIN(35, "I2S1_BCK", 17, DRV_GRP1),
+ MT7623_PIN(36, "I2S1_LRCK", 18, DRV_GRP1),
+ MT7623_PIN(37, "I2S1_MCLK", 19, DRV_GRP1),
+ MT7623_PIN(38, "I2S2_DATA", 20, DRV_GRP1),
+ MT7623_PIN(39, "JTMS", 21, DRV_GRP3),
+ MT7623_PIN(40, "JTCK", 22, DRV_GRP3),
+ MT7623_PIN(41, "JTDI", 23, DRV_GRP3),
+ MT7623_PIN(42, "JTDO", 24, DRV_GRP3),
+ MT7623_PIN(43, "NCLE", 25, DRV_GRP1),
+ MT7623_PIN(44, "NCEB1", 26, DRV_GRP1),
+ MT7623_PIN(45, "NCEB0", 27, DRV_GRP1),
+ MT7623_PIN(46, "IR", 28, DRV_FIXED),
+ MT7623_PIN(47, "NREB", 29, DRV_GRP1),
+ MT7623_PIN(48, "NRNB", 30, DRV_GRP1),
+ MT7623_PIN(49, "I2S0_DATA", 31, DRV_GRP1),
+ MT7623_PIN(50, "I2S2_BCK", 32, DRV_GRP1),
+ MT7623_PIN(51, "I2S2_DATA_IN", 33, DRV_GRP1),
+ MT7623_PIN(52, "I2S2_LRCK", 34, DRV_GRP1),
+ MT7623_PIN(53, "SPI0_CSN", 35, DRV_GRP1),
+ MT7623_PIN(54, "SPI0_CK", 36, DRV_GRP1),
+ MT7623_PIN(55, "SPI0_MI", 37, DRV_GRP1),
+ MT7623_PIN(56, "SPI0_MO", 38, DRV_GRP1),
+ MT7623_PIN(57, "SDA1", 39, DRV_FIXED),
+ MT7623_PIN(58, "SCL1", 40, DRV_FIXED),
+ MT7623_PIN(59, "RAMBUF_I_CLK", EINT_NA, DRV_FIXED),
+ MT7623_PIN(60, "WB_RSTB", 41, DRV_GRP3),
+ MT7623_PIN(61, "F2W_DATA", 42, DRV_GRP3),
+ MT7623_PIN(62, "F2W_CLK", 43, DRV_GRP3),
+ MT7623_PIN(63, "WB_SCLK", 44, DRV_GRP3),
+ MT7623_PIN(64, "WB_SDATA", 45, DRV_GRP3),
+ MT7623_PIN(65, "WB_SEN", 46, DRV_GRP3),
+ MT7623_PIN(66, "WB_CRTL0", 47, DRV_GRP3),
+ MT7623_PIN(67, "WB_CRTL1", 48, DRV_GRP3),
+ MT7623_PIN(68, "WB_CRTL2", 49, DRV_GRP3),
+ MT7623_PIN(69, "WB_CRTL3", 50, DRV_GRP3),
+ MT7623_PIN(70, "WB_CRTL4", 51, DRV_GRP3),
+ MT7623_PIN(71, "WB_CRTL5", 52, DRV_GRP3),
+ MT7623_PIN(72, "I2S0_DATA_IN", 53, DRV_GRP1),
+ MT7623_PIN(73, "I2S0_LRCK", 54, DRV_GRP1),
+ MT7623_PIN(74, "I2S0_BCK", 55, DRV_GRP1),
+ MT7623_PIN(75, "SDA0", 56, DRV_FIXED),
+ MT7623_PIN(76, "SCL0", 57, DRV_FIXED),
+ MT7623_PIN(77, "SDA2", 58, DRV_FIXED),
+ MT7623_PIN(78, "SCL2", 59, DRV_FIXED),
+ MT7623_PIN(79, "URXD0", 60, DRV_FIXED),
+ MT7623_PIN(80, "UTXD0", 61, DRV_FIXED),
+ MT7623_PIN(81, "URXD1", 62, DRV_FIXED),
+ MT7623_PIN(82, "UTXD1", 63, DRV_FIXED),
+ MT7623_PIN(83, "LCM_RST", 64, DRV_FIXED),
+ MT7623_PIN(84, "DSI_TE", 65, DRV_FIXED),
+ MT7623_PIN(85, "MSDC2_CMD", 66, DRV_GRP4),
+ MT7623_PIN(86, "MSDC2_CLK", 67, DRV_GRP4),
+ MT7623_PIN(87, "MSDC2_DAT0", 68, DRV_GRP4),
+ MT7623_PIN(88, "MSDC2_DAT1", 69, DRV_GRP4),
+ MT7623_PIN(89, "MSDC2_DAT2", 70, DRV_GRP4),
+ MT7623_PIN(90, "MSDC2_DAT3", 71, DRV_GRP4),
+ MT7623_PIN(91, "TDN3", EINT_NA, DRV_FIXED),
+ MT7623_PIN(92, "TDP3", EINT_NA, DRV_FIXED),
+ MT7623_PIN(93, "TDN2", EINT_NA, DRV_FIXED),
+ MT7623_PIN(94, "TDP2", EINT_NA, DRV_FIXED),
+ MT7623_PIN(95, "TCN", EINT_NA, DRV_FIXED),
+ MT7623_PIN(96, "TCP", EINT_NA, DRV_FIXED),
+ MT7623_PIN(97, "TDN1", EINT_NA, DRV_FIXED),
+ MT7623_PIN(98, "TDP1", EINT_NA, DRV_FIXED),
+ MT7623_PIN(99, "TDN0", EINT_NA, DRV_FIXED),
+ MT7623_PIN(100, "TDP0", EINT_NA, DRV_FIXED),
+ MT7623_PIN(101, "SPI2_CSN", 74, DRV_FIXED),
+ MT7623_PIN(102, "SPI2_MI", 75, DRV_FIXED),
+ MT7623_PIN(103, "SPI2_MO", 76, DRV_FIXED),
+ MT7623_PIN(104, "SPI2_CLK", 77, DRV_FIXED),
+ MT7623_PIN(105, "MSDC1_CMD", 78, DRV_GRP4),
+ MT7623_PIN(106, "MSDC1_CLK", 79, DRV_GRP4),
+ MT7623_PIN(107, "MSDC1_DAT0", 80, DRV_GRP4),
+ MT7623_PIN(108, "MSDC1_DAT1", 81, DRV_GRP4),
+ MT7623_PIN(109, "MSDC1_DAT2", 82, DRV_GRP4),
+ MT7623_PIN(110, "MSDC1_DAT3", 83, DRV_GRP4),
+ MT7623_PIN(111, "MSDC0_DAT7", 84, DRV_GRP4),
+ MT7623_PIN(112, "MSDC0_DAT6", 85, DRV_GRP4),
+ MT7623_PIN(113, "MSDC0_DAT5", 86, DRV_GRP4),
+ MT7623_PIN(114, "MSDC0_DAT4", 87, DRV_GRP4),
+ MT7623_PIN(115, "MSDC0_RSTB", 88, DRV_GRP4),
+ MT7623_PIN(116, "MSDC0_CMD", 89, DRV_GRP4),
+ MT7623_PIN(117, "MSDC0_CLK", 90, DRV_GRP4),
+ MT7623_PIN(118, "MSDC0_DAT3", 91, DRV_GRP4),
+ MT7623_PIN(119, "MSDC0_DAT2", 92, DRV_GRP4),
+ MT7623_PIN(120, "MSDC0_DAT1", 93, DRV_GRP4),
+ MT7623_PIN(121, "MSDC0_DAT0", 94, DRV_GRP4),
+ MT7623_PIN(122, "CEC", 95, DRV_FIXED),
+ MT7623_PIN(123, "HTPLG", 96, DRV_FIXED),
+ MT7623_PIN(124, "HDMISCK", 97, DRV_FIXED),
+ MT7623_PIN(125, "HDMISD", 98, DRV_FIXED),
+ MT7623_PIN(126, "I2S0_MCLK", 99, DRV_GRP1),
+ MT7623_PIN(127, "RAMBUF_IDATA0", EINT_NA, DRV_FIXED),
+ MT7623_PIN(128, "RAMBUF_IDATA1", EINT_NA, DRV_FIXED),
+ MT7623_PIN(129, "RAMBUF_IDATA2", EINT_NA, DRV_FIXED),
+ MT7623_PIN(130, "RAMBUF_IDATA3", EINT_NA, DRV_FIXED),
+ MT7623_PIN(131, "RAMBUF_IDATA4", EINT_NA, DRV_FIXED),
+ MT7623_PIN(132, "RAMBUF_IDATA5", EINT_NA, DRV_FIXED),
+ MT7623_PIN(133, "RAMBUF_IDATA6", EINT_NA, DRV_FIXED),
+ MT7623_PIN(134, "RAMBUF_IDATA7", EINT_NA, DRV_FIXED),
+ MT7623_PIN(135, "RAMBUF_IDATA8", EINT_NA, DRV_FIXED),
+ MT7623_PIN(136, "RAMBUF_IDATA9", EINT_NA, DRV_FIXED),
+ MT7623_PIN(137, "RAMBUF_IDATA10", EINT_NA, DRV_FIXED),
+ MT7623_PIN(138, "RAMBUF_IDATA11", EINT_NA, DRV_FIXED),
+ MT7623_PIN(139, "RAMBUF_IDATA12", EINT_NA, DRV_FIXED),
+ MT7623_PIN(140, "RAMBUF_IDATA13", EINT_NA, DRV_FIXED),
+ MT7623_PIN(141, "RAMBUF_IDATA14", EINT_NA, DRV_FIXED),
+ MT7623_PIN(142, "RAMBUF_IDATA15", EINT_NA, DRV_FIXED),
+ MT7623_PIN(143, "RAMBUF_ODATA0", EINT_NA, DRV_FIXED),
+ MT7623_PIN(144, "RAMBUF_ODATA1", EINT_NA, DRV_FIXED),
+ MT7623_PIN(145, "RAMBUF_ODATA2", EINT_NA, DRV_FIXED),
+ MT7623_PIN(146, "RAMBUF_ODATA3", EINT_NA, DRV_FIXED),
+ MT7623_PIN(147, "RAMBUF_ODATA4", EINT_NA, DRV_FIXED),
+ MT7623_PIN(148, "RAMBUF_ODATA5", EINT_NA, DRV_FIXED),
+ MT7623_PIN(149, "RAMBUF_ODATA6", EINT_NA, DRV_FIXED),
+ MT7623_PIN(150, "RAMBUF_ODATA7", EINT_NA, DRV_FIXED),
+ MT7623_PIN(151, "RAMBUF_ODATA8", EINT_NA, DRV_FIXED),
+ MT7623_PIN(152, "RAMBUF_ODATA9", EINT_NA, DRV_FIXED),
+ MT7623_PIN(153, "RAMBUF_ODATA10", EINT_NA, DRV_FIXED),
+ MT7623_PIN(154, "RAMBUF_ODATA11", EINT_NA, DRV_FIXED),
+ MT7623_PIN(155, "RAMBUF_ODATA12", EINT_NA, DRV_FIXED),
+ MT7623_PIN(156, "RAMBUF_ODATA13", EINT_NA, DRV_FIXED),
+ MT7623_PIN(157, "RAMBUF_ODATA14", EINT_NA, DRV_FIXED),
+ MT7623_PIN(158, "RAMBUF_ODATA15", EINT_NA, DRV_FIXED),
+ MT7623_PIN(159, "RAMBUF_BE0", EINT_NA, DRV_FIXED),
+ MT7623_PIN(160, "RAMBUF_BE1", EINT_NA, DRV_FIXED),
+ MT7623_PIN(161, "AP2PT_INT", EINT_NA, DRV_FIXED),
+ MT7623_PIN(162, "AP2PT_INT_CLR", EINT_NA, DRV_FIXED),
+ MT7623_PIN(163, "PT2AP_INT", EINT_NA, DRV_FIXED),
+ MT7623_PIN(164, "PT2AP_INT_CLR", EINT_NA, DRV_FIXED),
+ MT7623_PIN(165, "AP2UP_INT", EINT_NA, DRV_FIXED),
+ MT7623_PIN(166, "AP2UP_INT_CLR", EINT_NA, DRV_FIXED),
+ MT7623_PIN(167, "UP2AP_INT", EINT_NA, DRV_FIXED),
+ MT7623_PIN(168, "UP2AP_INT_CLR", EINT_NA, DRV_FIXED),
+ MT7623_PIN(169, "RAMBUF_ADDR0", EINT_NA, DRV_FIXED),
+ MT7623_PIN(170, "RAMBUF_ADDR1", EINT_NA, DRV_FIXED),
+ MT7623_PIN(171, "RAMBUF_ADDR2", EINT_NA, DRV_FIXED),
+ MT7623_PIN(172, "RAMBUF_ADDR3", EINT_NA, DRV_FIXED),
+ MT7623_PIN(173, "RAMBUF_ADDR4", EINT_NA, DRV_FIXED),
+ MT7623_PIN(174, "RAMBUF_ADDR5", EINT_NA, DRV_FIXED),
+ MT7623_PIN(175, "RAMBUF_ADDR6", EINT_NA, DRV_FIXED),
+ MT7623_PIN(176, "RAMBUF_ADDR7", EINT_NA, DRV_FIXED),
+ MT7623_PIN(177, "RAMBUF_ADDR8", EINT_NA, DRV_FIXED),
+ MT7623_PIN(178, "RAMBUF_ADDR9", EINT_NA, DRV_FIXED),
+ MT7623_PIN(179, "RAMBUF_ADDR10", EINT_NA, DRV_FIXED),
+ MT7623_PIN(180, "RAMBUF_RW", EINT_NA, DRV_FIXED),
+ MT7623_PIN(181, "RAMBUF_LAST", EINT_NA, DRV_FIXED),
+ MT7623_PIN(182, "RAMBUF_HP", EINT_NA, DRV_FIXED),
+ MT7623_PIN(183, "RAMBUF_REQ", EINT_NA, DRV_FIXED),
+ MT7623_PIN(184, "RAMBUF_ALE", EINT_NA, DRV_FIXED),
+ MT7623_PIN(185, "RAMBUF_DLE", EINT_NA, DRV_FIXED),
+ MT7623_PIN(186, "RAMBUF_WDLE", EINT_NA, DRV_FIXED),
+ MT7623_PIN(187, "RAMBUF_O_CLK", EINT_NA, DRV_FIXED),
+ MT7623_PIN(188, "I2S2_MCLK", 100, DRV_GRP1),
+ MT7623_PIN(189, "I2S3_DATA", 101, DRV_GRP1),
+ MT7623_PIN(190, "I2S3_DATA_IN", 102, DRV_GRP1),
+ MT7623_PIN(191, "I2S3_BCK", 103, DRV_GRP1),
+ MT7623_PIN(192, "I2S3_LRCK", 104, DRV_GRP1),
+ MT7623_PIN(193, "I2S3_MCLK", 105, DRV_GRP1),
+ MT7623_PIN(194, "I2S4_DATA", 106, DRV_GRP1),
+ MT7623_PIN(195, "I2S4_DATA_IN", 107, DRV_GRP1),
+ MT7623_PIN(196, "I2S4_BCK", 108, DRV_GRP1),
+ MT7623_PIN(197, "I2S4_LRCK", 109, DRV_GRP1),
+ MT7623_PIN(198, "I2S4_MCLK", 110, DRV_GRP1),
+ MT7623_PIN(199, "SPI1_CLK", 111, DRV_GRP3),
+ MT7623_PIN(200, "SPDIF_OUT", 112, DRV_GRP1),
+ MT7623_PIN(201, "SPDIF_IN0", 113, DRV_GRP1),
+ MT7623_PIN(202, "SPDIF_IN1", 114, DRV_GRP1),
+ MT7623_PIN(203, "PWM0", 115, DRV_GRP1),
+ MT7623_PIN(204, "PWM1", 116, DRV_GRP1),
+ MT7623_PIN(205, "PWM2", 117, DRV_GRP1),
+ MT7623_PIN(206, "PWM3", 118, DRV_GRP1),
+ MT7623_PIN(207, "PWM4", 119, DRV_GRP1),
+ MT7623_PIN(208, "AUD_EXT_CK1", 120, DRV_GRP1),
+ MT7623_PIN(209, "AUD_EXT_CK2", 121, DRV_GRP1),
+ MT7623_PIN(210, "AUD_CLOCK", EINT_NA, DRV_GRP3),
+ MT7623_PIN(211, "DVP_RESET", EINT_NA, DRV_GRP3),
+ MT7623_PIN(212, "DVP_CLOCK", EINT_NA, DRV_GRP3),
+ MT7623_PIN(213, "DVP_CS", EINT_NA, DRV_GRP3),
+ MT7623_PIN(214, "DVP_CK", EINT_NA, DRV_GRP3),
+ MT7623_PIN(215, "DVP_DI", EINT_NA, DRV_GRP3),
+ MT7623_PIN(216, "DVP_DO", EINT_NA, DRV_GRP3),
+ MT7623_PIN(217, "AP_CS", EINT_NA, DRV_GRP3),
+ MT7623_PIN(218, "AP_CK", EINT_NA, DRV_GRP3),
+ MT7623_PIN(219, "AP_DI", EINT_NA, DRV_GRP3),
+ MT7623_PIN(220, "AP_DO", EINT_NA, DRV_GRP3),
+ MT7623_PIN(221, "DVD_BCLK", EINT_NA, DRV_GRP3),
+ MT7623_PIN(222, "T8032_CLK", EINT_NA, DRV_GRP3),
+ MT7623_PIN(223, "AP_BCLK", EINT_NA, DRV_GRP3),
+ MT7623_PIN(224, "HOST_CS", EINT_NA, DRV_GRP3),
+ MT7623_PIN(225, "HOST_CK", EINT_NA, DRV_GRP3),
+ MT7623_PIN(226, "HOST_DO0", EINT_NA, DRV_GRP3),
+ MT7623_PIN(227, "HOST_DO1", EINT_NA, DRV_GRP3),
+ MT7623_PIN(228, "SLV_CS", EINT_NA, DRV_GRP3),
+ MT7623_PIN(229, "SLV_CK", EINT_NA, DRV_GRP3),
+ MT7623_PIN(230, "SLV_DI0", EINT_NA, DRV_GRP3),
+ MT7623_PIN(231, "SLV_DI1", EINT_NA, DRV_GRP3),
+ MT7623_PIN(232, "AP2DSP_INT", EINT_NA, DRV_GRP3),
+ MT7623_PIN(233, "AP2DSP_INT_CLR", EINT_NA, DRV_GRP3),
+ MT7623_PIN(234, "DSP2AP_INT", EINT_NA, DRV_GRP3),
+ MT7623_PIN(235, "DSP2AP_INT_CLR", EINT_NA, DRV_GRP3),
+ MT7623_PIN(236, "EXT_SDIO3", 122, DRV_GRP1),
+ MT7623_PIN(237, "EXT_SDIO2", 123, DRV_GRP1),
+ MT7623_PIN(238, "EXT_SDIO1", 124, DRV_GRP1),
+ MT7623_PIN(239, "EXT_SDIO0", 125, DRV_GRP1),
+ MT7623_PIN(240, "EXT_XCS", 126, DRV_GRP1),
+ MT7623_PIN(241, "EXT_SCK", 127, DRV_GRP1),
+ MT7623_PIN(242, "URTS2", 128, DRV_GRP1),
+ MT7623_PIN(243, "UCTS2", 129, DRV_GRP1),
+ MT7623_PIN(244, "HDMI_SDA_RX", 130, DRV_FIXED),
+ MT7623_PIN(245, "HDMI_SCL_RX", 131, DRV_FIXED),
+ MT7623_PIN(246, "MHL_SENCE", 132, DRV_FIXED),
+ MT7623_PIN(247, "HDMI_HPD_CBUS_RX", 69, DRV_FIXED),
+ MT7623_PIN(248, "HDMI_TESTOUTP_RX", 133, DRV_GRP1),
+ MT7623_PIN(249, "MSDC0E_RSTB", 134, DRV_GRP4),
+ MT7623_PIN(250, "MSDC0E_DAT7", 135, DRV_GRP4),
+ MT7623_PIN(251, "MSDC0E_DAT6", 136, DRV_GRP4),
+ MT7623_PIN(252, "MSDC0E_DAT5", 137, DRV_GRP4),
+ MT7623_PIN(253, "MSDC0E_DAT4", 138, DRV_GRP4),
+ MT7623_PIN(254, "MSDC0E_DAT3", 139, DRV_GRP4),
+ MT7623_PIN(255, "MSDC0E_DAT2", 140, DRV_GRP4),
+ MT7623_PIN(256, "MSDC0E_DAT1", 141, DRV_GRP4),
+ MT7623_PIN(257, "MSDC0E_DAT0", 142, DRV_GRP4),
+ MT7623_PIN(258, "MSDC0E_CMD", 143, DRV_GRP4),
+ MT7623_PIN(259, "MSDC0E_CLK", 144, DRV_GRP4),
+ MT7623_PIN(260, "MSDC0E_DSL", 145, DRV_GRP4),
+ MT7623_PIN(261, "MSDC1_INS", 146, DRV_GRP4),
+ MT7623_PIN(262, "G2_TXEN", 8, DRV_GRP1),
+ MT7623_PIN(263, "G2_TXD3", 9, DRV_GRP1),
+ MT7623_PIN(264, "G2_TXD2", 10, DRV_GRP1),
+ MT7623_PIN(265, "G2_TXD1", 11, DRV_GRP1),
+ MT7623_PIN(266, "G2_TXD0", EINT_NA, DRV_GRP1),
+ MT7623_PIN(267, "G2_TXC", EINT_NA, DRV_GRP1),
+ MT7623_PIN(268, "G2_RXC", EINT_NA, DRV_GRP1),
+ MT7623_PIN(269, "G2_RXD0", EINT_NA, DRV_GRP1),
+ MT7623_PIN(270, "G2_RXD1", EINT_NA, DRV_GRP1),
+ MT7623_PIN(271, "G2_RXD2", EINT_NA, DRV_GRP1),
+ MT7623_PIN(272, "G2_RXD3", EINT_NA, DRV_GRP1),
+ MT7623_PIN(273, "ESW_INT", 168, DRV_GRP1),
+ MT7623_PIN(274, "G2_RXDV", EINT_NA, DRV_GRP1),
+ MT7623_PIN(275, "MDC", EINT_NA, DRV_GRP1),
+ MT7623_PIN(276, "MDIO", EINT_NA, DRV_GRP1),
+ MT7623_PIN(277, "ESW_RST", EINT_NA, DRV_GRP1),
+ MT7623_PIN(278, "JTAG_RESET", 147, DRV_GRP3),
+ MT7623_PIN(279, "USB3_RES_BOND", EINT_NA, DRV_GRP1),
+};
+
+/* List all groups consisting of these pins dedicated to the enablement of
+ * certain hardware block and the corresponding mode for all of the pins.
+ * The hardware probably has multiple combinations of these pinouts.
+ */
+
+/* AUDIO EXT CLK */
+static int mt7623_aud_ext_clk0_pins[] = { 208, };
+static int mt7623_aud_ext_clk0_funcs[] = { 1, };
+static int mt7623_aud_ext_clk1_pins[] = { 209, };
+static int mt7623_aud_ext_clk1_funcs[] = { 1, };
+
+/* DISP PWM */
+static int mt7623_disp_pwm_0_pins[] = { 72, };
+static int mt7623_disp_pwm_0_funcs[] = { 5, };
+static int mt7623_disp_pwm_1_pins[] = { 203, };
+static int mt7623_disp_pwm_1_funcs[] = { 2, };
+static int mt7623_disp_pwm_2_pins[] = { 208, };
+static int mt7623_disp_pwm_2_funcs[] = { 5, };
+
+/* ESW */
+static int mt7623_esw_int_pins[] = { 273, };
+static int mt7623_esw_int_funcs[] = { 1, };
+static int mt7623_esw_rst_pins[] = { 277, };
+static int mt7623_esw_rst_funcs[] = { 1, };
+
+/* EPHY */
+static int mt7623_ephy_pins[] = { 262, 263, 264, 265, 266, 267, 268,
+ 269, 270, 271, 272, 274, };
+static int mt7623_ephy_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, };
+
+/* EXT_SDIO */
+static int mt7623_ext_sdio_pins[] = { 236, 237, 238, 239, 240, 241, };
+static int mt7623_ext_sdio_funcs[] = { 1, 1, 1, 1, 1, 1, };
+
+/* HDMI RX */
+static int mt7623_hdmi_rx_pins[] = { 247, 248, };
+static int mt7623_hdmi_rx_funcs[] = { 1, 1 };
+static int mt7623_hdmi_rx_i2c_pins[] = { 244, 245, };
+static int mt7623_hdmi_rx_i2c_funcs[] = { 1, 1 };
+
+/* HDMI TX */
+static int mt7623_hdmi_cec_pins[] = { 122, };
+static int mt7623_hdmi_cec_funcs[] = { 1, };
+static int mt7623_hdmi_htplg_pins[] = { 123, };
+static int mt7623_hdmi_htplg_funcs[] = { 1, };
+static int mt7623_hdmi_i2c_pins[] = { 124, 125, };
+static int mt7623_hdmi_i2c_funcs[] = { 1, 1 };
+
+/* I2C */
+static int mt7623_i2c0_pins[] = { 75, 76, };
+static int mt7623_i2c0_funcs[] = { 1, 1, };
+static int mt7623_i2c1_0_pins[] = { 57, 58, };
+static int mt7623_i2c1_0_funcs[] = { 1, 1, };
+static int mt7623_i2c1_1_pins[] = { 242, 243, };
+static int mt7623_i2c1_1_funcs[] = { 4, 4, };
+static int mt7623_i2c1_2_pins[] = { 85, 86, };
+static int mt7623_i2c1_2_funcs[] = { 3, 3, };
+static int mt7623_i2c1_3_pins[] = { 105, 106, };
+static int mt7623_i2c1_3_funcs[] = { 3, 3, };
+static int mt7623_i2c1_4_pins[] = { 124, 125, };
+static int mt7623_i2c1_4_funcs[] = { 4, 4, };
+static int mt7623_i2c2_0_pins[] = { 77, 78, };
+static int mt7623_i2c2_0_funcs[] = { 1, 1, };
+static int mt7623_i2c2_1_pins[] = { 89, 90, };
+static int mt7623_i2c2_1_funcs[] = { 3, 3, };
+static int mt7623_i2c2_2_pins[] = { 109, 110, };
+static int mt7623_i2c2_2_funcs[] = { 3, 3, };
+static int mt7623_i2c2_3_pins[] = { 122, 123, };
+static int mt7623_i2c2_3_funcs[] = { 4, 4, };
+
+/* I2S */
+static int mt7623_i2s0_pins[] = { 49, 72, 73, 74, 126, };
+static int mt7623_i2s0_funcs[] = { 1, 1, 1, 1, 1, };
+static int mt7623_i2s1_pins[] = { 33, 34, 35, 36, 37, };
+static int mt7623_i2s1_funcs[] = { 1, 1, 1, 1, 1, };
+static int mt7623_i2s2_bclk_lrclk_mclk_pins[] = { 50, 52, 188, };
+static int mt7623_i2s2_bclk_lrclk_mclk_funcs[] = { 1, 1, 1, };
+static int mt7623_i2s2_data_in_pins[] = { 51, };
+static int mt7623_i2s2_data_in_funcs[] = { 1, };
+static int mt7623_i2s2_data_0_pins[] = { 203, };
+static int mt7623_i2s2_data_0_funcs[] = { 9, };
+static int mt7623_i2s2_data_1_pins[] = { 38, };
+static int mt7623_i2s2_data_1_funcs[] = { 4, };
+static int mt7623_i2s3_bclk_lrclk_mclk_pins[] = { 191, 192, 193, };
+static int mt7623_i2s3_bclk_lrclk_mclk_funcs[] = { 1, 1, 1, };
+static int mt7623_i2s3_data_in_pins[] = { 190, };
+static int mt7623_i2s3_data_in_funcs[] = { 1, };
+static int mt7623_i2s3_data_0_pins[] = { 204, };
+static int mt7623_i2s3_data_0_funcs[] = { 9, };
+static int mt7623_i2s3_data_1_pins[] = { 2, };
+static int mt7623_i2s3_data_1_funcs[] = { 0, };
+static int mt7623_i2s4_pins[] = { 194, 195, 196, 197, 198, };
+static int mt7623_i2s4_funcs[] = { 1, 1, 1, 1, 1, };
+static int mt7623_i2s5_pins[] = { 16, 17, 30, 31, 32, };
+static int mt7623_i2s5_funcs[] = { 1, 1, 1, 1, 1, };
+
+/* IR */
+static int mt7623_ir_pins[] = { 46, };
+static int mt7623_ir_funcs[] = { 1, };
+
+/* LCD */
+static int mt7623_mipi_tx_pins[] = { 91, 92, 93, 94, 95, 96, 97, 98,
+ 99, 100, };
+static int mt7623_mipi_tx_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, };
+static int mt7623_dsi_te_pins[] = { 84, };
+static int mt7623_dsi_te_funcs[] = { 1, };
+static int mt7623_lcm_rst_pins[] = { 83, };
+static int mt7623_lcm_rst_funcs[] = { 1, };
+
+/* MDC/MDIO */
+static int mt7623_mdc_mdio_pins[] = { 275, 276, };
+static int mt7623_mdc_mdio_funcs[] = { 1, 1, };
+
+/* MSDC */
+static int mt7623_msdc0_pins[] = { 111, 112, 113, 114, 115, 116, 117, 118,
+ 119, 120, 121, };
+static int mt7623_msdc0_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, };
+static int mt7623_msdc1_pins[] = { 105, 106, 107, 108, 109, 110, };
+static int mt7623_msdc1_funcs[] = { 1, 1, 1, 1, 1, 1, };
+static int mt7623_msdc1_ins_pins[] = { 261, };
+static int mt7623_msdc1_ins_funcs[] = { 1, };
+static int mt7623_msdc1_wp_0_pins[] = { 29, };
+static int mt7623_msdc1_wp_0_funcs[] = { 1, };
+static int mt7623_msdc1_wp_1_pins[] = { 55, };
+static int mt7623_msdc1_wp_1_funcs[] = { 3, };
+static int mt7623_msdc1_wp_2_pins[] = { 209, };
+static int mt7623_msdc1_wp_2_funcs[] = { 2, };
+static int mt7623_msdc2_pins[] = { 85, 86, 87, 88, 89, 90, };
+static int mt7623_msdc2_funcs[] = { 1, 1, 1, 1, 1, 1, };
+static int mt7623_msdc3_pins[] = { 249, 250, 251, 252, 253, 254, 255, 256,
+ 257, 258, 259, 260, };
+static int mt7623_msdc3_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, };
+
+/* NAND */
+static int mt7623_nandc_pins[] = { 43, 47, 48, 111, 112, 113, 114, 115,
+ 116, 117, 118, 119, 120, 121, };
+static int mt7623_nandc_funcs[] = { 1, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, };
+static int mt7623_nandc_ceb0_pins[] = { 45, };
+static int mt7623_nandc_ceb0_funcs[] = { 1, };
+static int mt7623_nandc_ceb1_pins[] = { 44, };
+static int mt7623_nandc_ceb1_funcs[] = { 1, };
+
+/* RTC */
+static int mt7623_rtc_pins[] = { 10, };
+static int mt7623_rtc_funcs[] = { 1, };
+
+/* OTG */
+static int mt7623_otg_iddig0_0_pins[] = { 29, };
+static int mt7623_otg_iddig0_0_funcs[] = { 1, };
+static int mt7623_otg_iddig0_1_pins[] = { 44, };
+static int mt7623_otg_iddig0_1_funcs[] = { 2, };
+static int mt7623_otg_iddig0_2_pins[] = { 236, };
+static int mt7623_otg_iddig0_2_funcs[] = { 2, };
+static int mt7623_otg_iddig1_0_pins[] = { 27, };
+static int mt7623_otg_iddig1_0_funcs[] = { 2, };
+static int mt7623_otg_iddig1_1_pins[] = { 47, };
+static int mt7623_otg_iddig1_1_funcs[] = { 2, };
+static int mt7623_otg_iddig1_2_pins[] = { 238, };
+static int mt7623_otg_iddig1_2_funcs[] = { 2, };
+static int mt7623_otg_drv_vbus0_0_pins[] = { 28, };
+static int mt7623_otg_drv_vbus0_0_funcs[] = { 1, };
+static int mt7623_otg_drv_vbus0_1_pins[] = { 45, };
+static int mt7623_otg_drv_vbus0_1_funcs[] = { 2, };
+static int mt7623_otg_drv_vbus0_2_pins[] = { 237, };
+static int mt7623_otg_drv_vbus0_2_funcs[] = { 2, };
+static int mt7623_otg_drv_vbus1_0_pins[] = { 26, };
+static int mt7623_otg_drv_vbus1_0_funcs[] = { 2, };
+static int mt7623_otg_drv_vbus1_1_pins[] = { 48, };
+static int mt7623_otg_drv_vbus1_1_funcs[] = { 2, };
+static int mt7623_otg_drv_vbus1_2_pins[] = { 239, };
+static int mt7623_otg_drv_vbus1_2_funcs[] = { 2, };
+
+/* PCIE */
+static int mt7623_pcie0_0_perst_pins[] = { 208, };
+static int mt7623_pcie0_0_perst_funcs[] = { 3, };
+static int mt7623_pcie0_1_perst_pins[] = { 22, };
+static int mt7623_pcie0_1_perst_funcs[] = { 2, };
+static int mt7623_pcie1_0_perst_pins[] = { 209, };
+static int mt7623_pcie1_0_perst_funcs[] = { 3, };
+static int mt7623_pcie1_1_perst_pins[] = { 23, };
+static int mt7623_pcie1_1_perst_funcs[] = { 2, };
+static int mt7623_pcie2_0_perst_pins[] = { 24, };
+static int mt7623_pcie2_0_perst_funcs[] = { 2, };
+static int mt7623_pcie2_1_perst_pins[] = { 29, };
+static int mt7623_pcie2_1_perst_funcs[] = { 6, };
+static int mt7623_pcie0_0_wake_pins[] = { 28, };
+static int mt7623_pcie0_0_wake_funcs[] = { 6, };
+static int mt7623_pcie0_1_wake_pins[] = { 251, };
+static int mt7623_pcie0_1_wake_funcs[] = { 6, };
+static int mt7623_pcie1_0_wake_pins[] = { 27, };
+static int mt7623_pcie1_0_wake_funcs[] = { 6, };
+static int mt7623_pcie1_1_wake_pins[] = { 253, };
+static int mt7623_pcie1_1_wake_funcs[] = { 6, };
+static int mt7623_pcie2_0_wake_pins[] = { 26, };
+static int mt7623_pcie2_0_wake_funcs[] = { 6, };
+static int mt7623_pcie2_1_wake_pins[] = { 255, };
+static int mt7623_pcie2_1_wake_funcs[] = { 6, };
+static int mt7623_pcie0_clkreq_pins[] = { 250, };
+static int mt7623_pcie0_clkreq_funcs[] = { 6, };
+static int mt7623_pcie1_clkreq_pins[] = { 252, };
+static int mt7623_pcie1_clkreq_funcs[] = { 6, };
+static int mt7623_pcie2_clkreq_pins[] = { 254, };
+static int mt7623_pcie2_clkreq_funcs[] = { 6, };
+
+/* the pcie_*_rev are only used for MT7623 */
+static int mt7623_pcie0_0_rev_perst_pins[] = { 208, };
+static int mt7623_pcie0_0_rev_perst_funcs[] = { 11, };
+static int mt7623_pcie0_1_rev_perst_pins[] = { 22, };
+static int mt7623_pcie0_1_rev_perst_funcs[] = { 10, };
+static int mt7623_pcie1_0_rev_perst_pins[] = { 209, };
+static int mt7623_pcie1_0_rev_perst_funcs[] = { 11, };
+static int mt7623_pcie1_1_rev_perst_pins[] = { 23, };
+static int mt7623_pcie1_1_rev_perst_funcs[] = { 10, };
+static int mt7623_pcie2_0_rev_perst_pins[] = { 24, };
+static int mt7623_pcie2_0_rev_perst_funcs[] = { 11, };
+static int mt7623_pcie2_1_rev_perst_pins[] = { 29, };
+static int mt7623_pcie2_1_rev_perst_funcs[] = { 14, };
+
+/* PCM */
+static int mt7623_pcm_clk_0_pins[] = { 18, };
+static int mt7623_pcm_clk_0_funcs[] = { 1, };
+static int mt7623_pcm_clk_1_pins[] = { 17, };
+static int mt7623_pcm_clk_1_funcs[] = { 3, };
+static int mt7623_pcm_clk_2_pins[] = { 35, };
+static int mt7623_pcm_clk_2_funcs[] = { 3, };
+static int mt7623_pcm_clk_3_pins[] = { 50, };
+static int mt7623_pcm_clk_3_funcs[] = { 3, };
+static int mt7623_pcm_clk_4_pins[] = { 74, };
+static int mt7623_pcm_clk_4_funcs[] = { 3, };
+static int mt7623_pcm_clk_5_pins[] = { 191, };
+static int mt7623_pcm_clk_5_funcs[] = { 3, };
+static int mt7623_pcm_clk_6_pins[] = { 196, };
+static int mt7623_pcm_clk_6_funcs[] = { 3, };
+static int mt7623_pcm_sync_0_pins[] = { 19, };
+static int mt7623_pcm_sync_0_funcs[] = { 1, };
+static int mt7623_pcm_sync_1_pins[] = { 30, };
+static int mt7623_pcm_sync_1_funcs[] = { 3, };
+static int mt7623_pcm_sync_2_pins[] = { 36, };
+static int mt7623_pcm_sync_2_funcs[] = { 3, };
+static int mt7623_pcm_sync_3_pins[] = { 52, };
+static int mt7623_pcm_sync_3_funcs[] = { 31, };
+static int mt7623_pcm_sync_4_pins[] = { 73, };
+static int mt7623_pcm_sync_4_funcs[] = { 3, };
+static int mt7623_pcm_sync_5_pins[] = { 192, };
+static int mt7623_pcm_sync_5_funcs[] = { 3, };
+static int mt7623_pcm_sync_6_pins[] = { 197, };
+static int mt7623_pcm_sync_6_funcs[] = { 3, };
+static int mt7623_pcm_rx_0_pins[] = { 20, };
+static int mt7623_pcm_rx_0_funcs[] = { 1, };
+static int mt7623_pcm_rx_1_pins[] = { 16, };
+static int mt7623_pcm_rx_1_funcs[] = { 3, };
+static int mt7623_pcm_rx_2_pins[] = { 34, };
+static int mt7623_pcm_rx_2_funcs[] = { 3, };
+static int mt7623_pcm_rx_3_pins[] = { 51, };
+static int mt7623_pcm_rx_3_funcs[] = { 3, };
+static int mt7623_pcm_rx_4_pins[] = { 72, };
+static int mt7623_pcm_rx_4_funcs[] = { 3, };
+static int mt7623_pcm_rx_5_pins[] = { 190, };
+static int mt7623_pcm_rx_5_funcs[] = { 3, };
+static int mt7623_pcm_rx_6_pins[] = { 195, };
+static int mt7623_pcm_rx_6_funcs[] = { 3, };
+static int mt7623_pcm_tx_0_pins[] = { 21, };
+static int mt7623_pcm_tx_0_funcs[] = { 1, };
+static int mt7623_pcm_tx_1_pins[] = { 32, };
+static int mt7623_pcm_tx_1_funcs[] = { 3, };
+static int mt7623_pcm_tx_2_pins[] = { 33, };
+static int mt7623_pcm_tx_2_funcs[] = { 3, };
+static int mt7623_pcm_tx_3_pins[] = { 38, };
+static int mt7623_pcm_tx_3_funcs[] = { 3, };
+static int mt7623_pcm_tx_4_pins[] = { 49, };
+static int mt7623_pcm_tx_4_funcs[] = { 3, };
+static int mt7623_pcm_tx_5_pins[] = { 189, };
+static int mt7623_pcm_tx_5_funcs[] = { 3, };
+static int mt7623_pcm_tx_6_pins[] = { 194, };
+static int mt7623_pcm_tx_6_funcs[] = { 3, };
+
+/* PWM */
+static int mt7623_pwm_ch1_0_pins[] = { 203, };
+static int mt7623_pwm_ch1_0_funcs[] = { 1, };
+static int mt7623_pwm_ch1_1_pins[] = { 208, };
+static int mt7623_pwm_ch1_1_funcs[] = { 2, };
+static int mt7623_pwm_ch1_2_pins[] = { 72, };
+static int mt7623_pwm_ch1_2_funcs[] = { 4, };
+static int mt7623_pwm_ch1_3_pins[] = { 88, };
+static int mt7623_pwm_ch1_3_funcs[] = { 3, };
+static int mt7623_pwm_ch1_4_pins[] = { 108, };
+static int mt7623_pwm_ch1_4_funcs[] = { 3, };
+static int mt7623_pwm_ch2_0_pins[] = { 204, };
+static int mt7623_pwm_ch2_0_funcs[] = { 1, };
+static int mt7623_pwm_ch2_1_pins[] = { 53, };
+static int mt7623_pwm_ch2_1_funcs[] = { 5, };
+static int mt7623_pwm_ch2_2_pins[] = { 88, };
+static int mt7623_pwm_ch2_2_funcs[] = { 6, };
+static int mt7623_pwm_ch2_3_pins[] = { 108, };
+static int mt7623_pwm_ch2_3_funcs[] = { 6, };
+static int mt7623_pwm_ch2_4_pins[] = { 209, };
+static int mt7623_pwm_ch2_4_funcs[] = { 5, };
+static int mt7623_pwm_ch3_0_pins[] = { 205, };
+static int mt7623_pwm_ch3_0_funcs[] = { 1, };
+static int mt7623_pwm_ch3_1_pins[] = { 55, };
+static int mt7623_pwm_ch3_1_funcs[] = { 5, };
+static int mt7623_pwm_ch3_2_pins[] = { 89, };
+static int mt7623_pwm_ch3_2_funcs[] = { 6, };
+static int mt7623_pwm_ch3_3_pins[] = { 109, };
+static int mt7623_pwm_ch3_3_funcs[] = { 6, };
+static int mt7623_pwm_ch4_0_pins[] = { 206, };
+static int mt7623_pwm_ch4_0_funcs[] = { 1, };
+static int mt7623_pwm_ch4_1_pins[] = { 90, };
+static int mt7623_pwm_ch4_1_funcs[] = { 6, };
+static int mt7623_pwm_ch4_2_pins[] = { 110, };
+static int mt7623_pwm_ch4_2_funcs[] = { 6, };
+static int mt7623_pwm_ch4_3_pins[] = { 124, };
+static int mt7623_pwm_ch4_3_funcs[] = { 5, };
+static int mt7623_pwm_ch5_0_pins[] = { 207, };
+static int mt7623_pwm_ch5_0_funcs[] = { 1, };
+static int mt7623_pwm_ch5_1_pins[] = { 125, };
+static int mt7623_pwm_ch5_1_funcs[] = { 5, };
+
+/* PWRAP */
+static int mt7623_pwrap_pins[] = { 0, 1, 2, 3, 4, 5, 6, };
+static int mt7623_pwrap_funcs[] = { 1, 1, 1, 1, 1, 1, 1, };
+
+/* SPDIF */
+static int mt7623_spdif_in0_0_pins[] = { 56, };
+static int mt7623_spdif_in0_0_funcs[] = { 3, };
+static int mt7623_spdif_in0_1_pins[] = { 201, };
+static int mt7623_spdif_in0_1_funcs[] = { 1, };
+static int mt7623_spdif_in1_0_pins[] = { 54, };
+static int mt7623_spdif_in1_0_funcs[] = { 3, };
+static int mt7623_spdif_in1_1_pins[] = { 202, };
+static int mt7623_spdif_in1_1_funcs[] = { 1, };
+static int mt7623_spdif_out_pins[] = { 202, };
+static int mt7623_spdif_out_funcs[] = { 1, };
+
+/* SPI */
+static int mt7623_spi0_pins[] = { 53, 54, 55, 56, };
+static int mt7623_spi0_funcs[] = { 1, 1, 1, 1, };
+static int mt7623_spi1_pins[] = { 7, 199, 8, 9, };
+static int mt7623_spi1_funcs[] = { 1, 1, 1, 1, };
+static int mt7623_spi2_pins[] = { 101, 104, 102, 103, };
+static int mt7623_spi2_funcs[] = { 1, 1, 1, 1, };
+
+/* UART */
+static int mt7623_uart0_0_txd_rxd_pins[] = { 79, 80, };
+static int mt7623_uart0_0_txd_rxd_funcs[] = { 1, 1, };
+static int mt7623_uart0_1_txd_rxd_pins[] = { 87, 88, };
+static int mt7623_uart0_1_txd_rxd_funcs[] = { 5, 5, };
+static int mt7623_uart0_2_txd_rxd_pins[] = { 107, 108, };
+static int mt7623_uart0_2_txd_rxd_funcs[] = { 5, 5, };
+static int mt7623_uart0_3_txd_rxd_pins[] = { 123, 122, };
+static int mt7623_uart0_3_txd_rxd_funcs[] = { 5, 5, };
+static int mt7623_uart0_rts_cts_pins[] = { 22, 23, };
+static int mt7623_uart0_rts_cts_funcs[] = { 1, 1, };
+static int mt7623_uart1_0_txd_rxd_pins[] = { 81, 82, };
+static int mt7623_uart1_0_txd_rxd_funcs[] = { 1, 1, };
+static int mt7623_uart1_1_txd_rxd_pins[] = { 89, 90, };
+static int mt7623_uart1_1_txd_rxd_funcs[] = { 5, 5, };
+static int mt7623_uart1_2_txd_rxd_pins[] = { 109, 110, };
+static int mt7623_uart1_2_txd_rxd_funcs[] = { 5, 5, };
+static int mt7623_uart1_rts_cts_pins[] = { 24, 25, };
+static int mt7623_uart1_rts_cts_funcs[] = { 1, 1, };
+static int mt7623_uart2_0_txd_rxd_pins[] = { 14, 15, };
+static int mt7623_uart2_0_txd_rxd_funcs[] = { 1, 1, };
+static int mt7623_uart2_1_txd_rxd_pins[] = { 200, 201, };
+static int mt7623_uart2_1_txd_rxd_funcs[] = { 6, 6, };
+static int mt7623_uart2_rts_cts_pins[] = { 242, 243, };
+static int mt7623_uart2_rts_cts_funcs[] = { 1, 1, };
+static int mt7623_uart3_txd_rxd_pins[] = { 242, 243, };
+static int mt7623_uart3_txd_rxd_funcs[] = { 2, 2, };
+static int mt7623_uart3_rts_cts_pins[] = { 26, 27, };
+static int mt7623_uart3_rts_cts_funcs[] = { 1, 1, };
+
+/* Watchdog */
+static int mt7623_watchdog_0_pins[] = { 11, };
+static int mt7623_watchdog_0_funcs[] = { 1, };
+static int mt7623_watchdog_1_pins[] = { 121, };
+static int mt7623_watchdog_1_funcs[] = { 5, };
+
+static const struct group_desc mt7623_groups[] = {
+ PINCTRL_PIN_GROUP("aud_ext_clk0", mt7623_aud_ext_clk0),
+ PINCTRL_PIN_GROUP("aud_ext_clk1", mt7623_aud_ext_clk1),
+ PINCTRL_PIN_GROUP("dsi_te", mt7623_dsi_te),
+ PINCTRL_PIN_GROUP("disp_pwm_0", mt7623_disp_pwm_0),
+ PINCTRL_PIN_GROUP("disp_pwm_1", mt7623_disp_pwm_1),
+ PINCTRL_PIN_GROUP("disp_pwm_2", mt7623_disp_pwm_2),
+ PINCTRL_PIN_GROUP("ephy", mt7623_ephy),
+ PINCTRL_PIN_GROUP("esw_int", mt7623_esw_int),
+ PINCTRL_PIN_GROUP("esw_rst", mt7623_esw_rst),
+ PINCTRL_PIN_GROUP("ext_sdio", mt7623_ext_sdio),
+ PINCTRL_PIN_GROUP("hdmi_cec", mt7623_hdmi_cec),
+ PINCTRL_PIN_GROUP("hdmi_htplg", mt7623_hdmi_htplg),
+ PINCTRL_PIN_GROUP("hdmi_i2c", mt7623_hdmi_i2c),
+ PINCTRL_PIN_GROUP("hdmi_rx", mt7623_hdmi_rx),
+ PINCTRL_PIN_GROUP("hdmi_rx_i2c", mt7623_hdmi_rx_i2c),
+ PINCTRL_PIN_GROUP("i2c0", mt7623_i2c0),
+ PINCTRL_PIN_GROUP("i2c1_0", mt7623_i2c1_0),
+ PINCTRL_PIN_GROUP("i2c1_1", mt7623_i2c1_1),
+ PINCTRL_PIN_GROUP("i2c1_2", mt7623_i2c1_2),
+ PINCTRL_PIN_GROUP("i2c1_3", mt7623_i2c1_3),
+ PINCTRL_PIN_GROUP("i2c1_4", mt7623_i2c1_4),
+ PINCTRL_PIN_GROUP("i2c2_0", mt7623_i2c2_0),
+ PINCTRL_PIN_GROUP("i2c2_1", mt7623_i2c2_1),
+ PINCTRL_PIN_GROUP("i2c2_2", mt7623_i2c2_2),
+ PINCTRL_PIN_GROUP("i2c2_3", mt7623_i2c2_3),
+ PINCTRL_PIN_GROUP("i2s0", mt7623_i2s0),
+ PINCTRL_PIN_GROUP("i2s1", mt7623_i2s1),
+ PINCTRL_PIN_GROUP("i2s4", mt7623_i2s4),
+ PINCTRL_PIN_GROUP("i2s5", mt7623_i2s5),
+ PINCTRL_PIN_GROUP("i2s2_bclk_lrclk_mclk", mt7623_i2s2_bclk_lrclk_mclk),
+ PINCTRL_PIN_GROUP("i2s3_bclk_lrclk_mclk", mt7623_i2s3_bclk_lrclk_mclk),
+ PINCTRL_PIN_GROUP("i2s2_data_in", mt7623_i2s2_data_in),
+ PINCTRL_PIN_GROUP("i2s3_data_in", mt7623_i2s3_data_in),
+ PINCTRL_PIN_GROUP("i2s2_data_0", mt7623_i2s2_data_0),
+ PINCTRL_PIN_GROUP("i2s2_data_1", mt7623_i2s2_data_1),
+ PINCTRL_PIN_GROUP("i2s3_data_0", mt7623_i2s3_data_0),
+ PINCTRL_PIN_GROUP("i2s3_data_1", mt7623_i2s3_data_1),
+ PINCTRL_PIN_GROUP("ir", mt7623_ir),
+ PINCTRL_PIN_GROUP("lcm_rst", mt7623_lcm_rst),
+ PINCTRL_PIN_GROUP("mdc_mdio", mt7623_mdc_mdio),
+ PINCTRL_PIN_GROUP("mipi_tx", mt7623_mipi_tx),
+ PINCTRL_PIN_GROUP("msdc0", mt7623_msdc0),
+ PINCTRL_PIN_GROUP("msdc1", mt7623_msdc1),
+ PINCTRL_PIN_GROUP("msdc1_ins", mt7623_msdc1_ins),
+ PINCTRL_PIN_GROUP("msdc1_wp_0", mt7623_msdc1_wp_0),
+ PINCTRL_PIN_GROUP("msdc1_wp_1", mt7623_msdc1_wp_1),
+ PINCTRL_PIN_GROUP("msdc1_wp_2", mt7623_msdc1_wp_2),
+ PINCTRL_PIN_GROUP("msdc2", mt7623_msdc2),
+ PINCTRL_PIN_GROUP("msdc3", mt7623_msdc3),
+ PINCTRL_PIN_GROUP("nandc", mt7623_nandc),
+ PINCTRL_PIN_GROUP("nandc_ceb0", mt7623_nandc_ceb0),
+ PINCTRL_PIN_GROUP("nandc_ceb1", mt7623_nandc_ceb1),
+ PINCTRL_PIN_GROUP("otg_iddig0_0", mt7623_otg_iddig0_0),
+ PINCTRL_PIN_GROUP("otg_iddig0_1", mt7623_otg_iddig0_1),
+ PINCTRL_PIN_GROUP("otg_iddig0_2", mt7623_otg_iddig0_2),
+ PINCTRL_PIN_GROUP("otg_iddig1_0", mt7623_otg_iddig1_0),
+ PINCTRL_PIN_GROUP("otg_iddig1_1", mt7623_otg_iddig1_1),
+ PINCTRL_PIN_GROUP("otg_iddig1_2", mt7623_otg_iddig1_2),
+ PINCTRL_PIN_GROUP("otg_drv_vbus0_0", mt7623_otg_drv_vbus0_0),
+ PINCTRL_PIN_GROUP("otg_drv_vbus0_1", mt7623_otg_drv_vbus0_1),
+ PINCTRL_PIN_GROUP("otg_drv_vbus0_2", mt7623_otg_drv_vbus0_2),
+ PINCTRL_PIN_GROUP("otg_drv_vbus1_0", mt7623_otg_drv_vbus1_0),
+ PINCTRL_PIN_GROUP("otg_drv_vbus1_1", mt7623_otg_drv_vbus1_1),
+ PINCTRL_PIN_GROUP("otg_drv_vbus1_2", mt7623_otg_drv_vbus1_2),
+ PINCTRL_PIN_GROUP("pcie0_0_perst", mt7623_pcie0_0_perst),
+ PINCTRL_PIN_GROUP("pcie0_1_perst", mt7623_pcie0_1_perst),
+ PINCTRL_PIN_GROUP("pcie1_0_perst", mt7623_pcie1_0_perst),
+ PINCTRL_PIN_GROUP("pcie1_1_perst", mt7623_pcie1_1_perst),
+ PINCTRL_PIN_GROUP("pcie1_1_perst", mt7623_pcie1_1_perst),
+ PINCTRL_PIN_GROUP("pcie0_0_rev_perst", mt7623_pcie0_0_rev_perst),
+ PINCTRL_PIN_GROUP("pcie0_1_rev_perst", mt7623_pcie0_1_rev_perst),
+ PINCTRL_PIN_GROUP("pcie1_0_rev_perst", mt7623_pcie1_0_rev_perst),
+ PINCTRL_PIN_GROUP("pcie1_1_rev_perst", mt7623_pcie1_1_rev_perst),
+ PINCTRL_PIN_GROUP("pcie2_0_rev_perst", mt7623_pcie2_0_rev_perst),
+ PINCTRL_PIN_GROUP("pcie2_1_rev_perst", mt7623_pcie2_1_rev_perst),
+ PINCTRL_PIN_GROUP("pcie2_0_perst", mt7623_pcie2_0_perst),
+ PINCTRL_PIN_GROUP("pcie2_1_perst", mt7623_pcie2_1_perst),
+ PINCTRL_PIN_GROUP("pcie0_0_wake", mt7623_pcie0_0_wake),
+ PINCTRL_PIN_GROUP("pcie0_1_wake", mt7623_pcie0_1_wake),
+ PINCTRL_PIN_GROUP("pcie1_0_wake", mt7623_pcie1_0_wake),
+ PINCTRL_PIN_GROUP("pcie1_1_wake", mt7623_pcie1_1_wake),
+ PINCTRL_PIN_GROUP("pcie2_0_wake", mt7623_pcie2_0_wake),
+ PINCTRL_PIN_GROUP("pcie2_1_wake", mt7623_pcie2_1_wake),
+ PINCTRL_PIN_GROUP("pcie0_clkreq", mt7623_pcie0_clkreq),
+ PINCTRL_PIN_GROUP("pcie1_clkreq", mt7623_pcie1_clkreq),
+ PINCTRL_PIN_GROUP("pcie2_clkreq", mt7623_pcie2_clkreq),
+ PINCTRL_PIN_GROUP("pcm_clk_0", mt7623_pcm_clk_0),
+ PINCTRL_PIN_GROUP("pcm_clk_1", mt7623_pcm_clk_1),
+ PINCTRL_PIN_GROUP("pcm_clk_2", mt7623_pcm_clk_2),
+ PINCTRL_PIN_GROUP("pcm_clk_3", mt7623_pcm_clk_3),
+ PINCTRL_PIN_GROUP("pcm_clk_4", mt7623_pcm_clk_4),
+ PINCTRL_PIN_GROUP("pcm_clk_5", mt7623_pcm_clk_5),
+ PINCTRL_PIN_GROUP("pcm_clk_6", mt7623_pcm_clk_6),
+ PINCTRL_PIN_GROUP("pcm_sync_0", mt7623_pcm_sync_0),
+ PINCTRL_PIN_GROUP("pcm_sync_1", mt7623_pcm_sync_1),
+ PINCTRL_PIN_GROUP("pcm_sync_2", mt7623_pcm_sync_2),
+ PINCTRL_PIN_GROUP("pcm_sync_3", mt7623_pcm_sync_3),
+ PINCTRL_PIN_GROUP("pcm_sync_4", mt7623_pcm_sync_4),
+ PINCTRL_PIN_GROUP("pcm_sync_5", mt7623_pcm_sync_5),
+ PINCTRL_PIN_GROUP("pcm_sync_6", mt7623_pcm_sync_6),
+ PINCTRL_PIN_GROUP("pcm_rx_0", mt7623_pcm_rx_0),
+ PINCTRL_PIN_GROUP("pcm_rx_1", mt7623_pcm_rx_1),
+ PINCTRL_PIN_GROUP("pcm_rx_2", mt7623_pcm_rx_2),
+ PINCTRL_PIN_GROUP("pcm_rx_3", mt7623_pcm_rx_3),
+ PINCTRL_PIN_GROUP("pcm_rx_4", mt7623_pcm_rx_4),
+ PINCTRL_PIN_GROUP("pcm_rx_5", mt7623_pcm_rx_5),
+ PINCTRL_PIN_GROUP("pcm_rx_6", mt7623_pcm_rx_6),
+ PINCTRL_PIN_GROUP("pcm_tx_0", mt7623_pcm_tx_0),
+ PINCTRL_PIN_GROUP("pcm_tx_1", mt7623_pcm_tx_1),
+ PINCTRL_PIN_GROUP("pcm_tx_2", mt7623_pcm_tx_2),
+ PINCTRL_PIN_GROUP("pcm_tx_3", mt7623_pcm_tx_3),
+ PINCTRL_PIN_GROUP("pcm_tx_4", mt7623_pcm_tx_4),
+ PINCTRL_PIN_GROUP("pcm_tx_5", mt7623_pcm_tx_5),
+ PINCTRL_PIN_GROUP("pcm_tx_6", mt7623_pcm_tx_6),
+ PINCTRL_PIN_GROUP("pwm_ch1_0", mt7623_pwm_ch1_0),
+ PINCTRL_PIN_GROUP("pwm_ch1_1", mt7623_pwm_ch1_1),
+ PINCTRL_PIN_GROUP("pwm_ch1_2", mt7623_pwm_ch1_2),
+ PINCTRL_PIN_GROUP("pwm_ch1_3", mt7623_pwm_ch1_3),
+ PINCTRL_PIN_GROUP("pwm_ch1_4", mt7623_pwm_ch1_4),
+ PINCTRL_PIN_GROUP("pwm_ch2_0", mt7623_pwm_ch2_0),
+ PINCTRL_PIN_GROUP("pwm_ch2_1", mt7623_pwm_ch2_1),
+ PINCTRL_PIN_GROUP("pwm_ch2_2", mt7623_pwm_ch2_2),
+ PINCTRL_PIN_GROUP("pwm_ch2_3", mt7623_pwm_ch2_3),
+ PINCTRL_PIN_GROUP("pwm_ch2_4", mt7623_pwm_ch2_4),
+ PINCTRL_PIN_GROUP("pwm_ch3_0", mt7623_pwm_ch3_0),
+ PINCTRL_PIN_GROUP("pwm_ch3_1", mt7623_pwm_ch3_1),
+ PINCTRL_PIN_GROUP("pwm_ch3_2", mt7623_pwm_ch3_2),
+ PINCTRL_PIN_GROUP("pwm_ch3_3", mt7623_pwm_ch3_3),
+ PINCTRL_PIN_GROUP("pwm_ch4_0", mt7623_pwm_ch4_0),
+ PINCTRL_PIN_GROUP("pwm_ch4_1", mt7623_pwm_ch4_1),
+ PINCTRL_PIN_GROUP("pwm_ch4_2", mt7623_pwm_ch4_2),
+ PINCTRL_PIN_GROUP("pwm_ch4_3", mt7623_pwm_ch4_3),
+ PINCTRL_PIN_GROUP("pwm_ch5_0", mt7623_pwm_ch5_0),
+ PINCTRL_PIN_GROUP("pwm_ch5_1", mt7623_pwm_ch5_1),
+ PINCTRL_PIN_GROUP("pwrap", mt7623_pwrap),
+ PINCTRL_PIN_GROUP("rtc", mt7623_rtc),
+ PINCTRL_PIN_GROUP("spdif_in0_0", mt7623_spdif_in0_0),
+ PINCTRL_PIN_GROUP("spdif_in0_1", mt7623_spdif_in0_1),
+ PINCTRL_PIN_GROUP("spdif_in1_0", mt7623_spdif_in1_0),
+ PINCTRL_PIN_GROUP("spdif_in1_1", mt7623_spdif_in1_1),
+ PINCTRL_PIN_GROUP("spdif_out", mt7623_spdif_out),
+ PINCTRL_PIN_GROUP("spi0", mt7623_spi0),
+ PINCTRL_PIN_GROUP("spi1", mt7623_spi1),
+ PINCTRL_PIN_GROUP("spi2", mt7623_spi2),
+ PINCTRL_PIN_GROUP("uart0_0_txd_rxd", mt7623_uart0_0_txd_rxd),
+ PINCTRL_PIN_GROUP("uart0_1_txd_rxd", mt7623_uart0_1_txd_rxd),
+ PINCTRL_PIN_GROUP("uart0_2_txd_rxd", mt7623_uart0_2_txd_rxd),
+ PINCTRL_PIN_GROUP("uart0_3_txd_rxd", mt7623_uart0_3_txd_rxd),
+ PINCTRL_PIN_GROUP("uart1_0_txd_rxd", mt7623_uart1_0_txd_rxd),
+ PINCTRL_PIN_GROUP("uart1_1_txd_rxd", mt7623_uart1_1_txd_rxd),
+ PINCTRL_PIN_GROUP("uart1_2_txd_rxd", mt7623_uart1_2_txd_rxd),
+ PINCTRL_PIN_GROUP("uart2_0_txd_rxd", mt7623_uart2_0_txd_rxd),
+ PINCTRL_PIN_GROUP("uart2_1_txd_rxd", mt7623_uart2_1_txd_rxd),
+ PINCTRL_PIN_GROUP("uart3_txd_rxd", mt7623_uart3_txd_rxd),
+ PINCTRL_PIN_GROUP("uart0_rts_cts", mt7623_uart0_rts_cts),
+ PINCTRL_PIN_GROUP("uart1_rts_cts", mt7623_uart1_rts_cts),
+ PINCTRL_PIN_GROUP("uart2_rts_cts", mt7623_uart2_rts_cts),
+ PINCTRL_PIN_GROUP("uart3_rts_cts", mt7623_uart3_rts_cts),
+ PINCTRL_PIN_GROUP("watchdog_0", mt7623_watchdog_0),
+ PINCTRL_PIN_GROUP("watchdog_1", mt7623_watchdog_1),
+};
+
+/* Joint those groups owning the same capability in user point of view which
+ * allows that people tend to use through the device tree.
+ */
+static const char *mt7623_aud_clk_groups[] = { "aud_ext_clk0",
+ "aud_ext_clk1", };
+static const char *mt7623_disp_pwm_groups[] = { "disp_pwm_0", "disp_pwm_1",
+ "disp_pwm_2", };
+static const char *mt7623_ethernet_groups[] = { "esw_int", "esw_rst",
+ "ephy", "mdc_mdio", };
+static const char *mt7623_ext_sdio_groups[] = { "ext_sdio", };
+static const char *mt7623_hdmi_groups[] = { "hdmi_cec", "hdmi_htplg",
+ "hdmi_i2c", "hdmi_rx",
+ "hdmi_rx_i2c", };
+static const char *mt7623_i2c_groups[] = { "i2c0", "i2c1_0", "i2c1_1",
+ "i2c1_2", "i2c1_3", "i2c1_4",
+ "i2c2_0", "i2c2_1", "i2c2_2",
+ "i2c2_3", };
+static const char *mt7623_i2s_groups[] = { "i2s0", "i2s1",
+ "i2s2_bclk_lrclk_mclk",
+ "i2s3_bclk_lrclk_mclk",
+ "i2s4", "i2s5",
+ "i2s2_data_in", "i2s3_data_in",
+ "i2s2_data_0", "i2s2_data_1",
+ "i2s3_data_0", "i2s3_data_1", };
+static const char *mt7623_ir_groups[] = { "ir", };
+static const char *mt7623_lcd_groups[] = { "dsi_te", "lcm_rst", "mipi_tx", };
+static const char *mt7623_msdc_groups[] = { "msdc0", "msdc1", "msdc1_ins",
+ "msdc1_wp_0", "msdc1_wp_1",
+ "msdc1_wp_2", "msdc2",
+ "msdc3", };
+static const char *mt7623_nandc_groups[] = { "nandc", "nandc_ceb0",
+ "nandc_ceb1", };
+static const char *mt7623_otg_groups[] = { "otg_iddig0_0", "otg_iddig0_1",
+ "otg_iddig0_2", "otg_iddig1_0",
+ "otg_iddig1_1", "otg_iddig1_2",
+ "otg_drv_vbus0_0",
+ "otg_drv_vbus0_1",
+ "otg_drv_vbus0_2",
+ "otg_drv_vbus1_0",
+ "otg_drv_vbus1_1",
+ "otg_drv_vbus1_2", };
+static const char *mt7623_pcie_groups[] = { "pcie0_0_perst", "pcie0_1_perst",
+ "pcie1_0_perst", "pcie1_1_perst",
+ "pcie2_0_perst", "pcie2_1_perst",
+ "pcie0_0_rev_perst",
+ "pcie0_1_rev_perst",
+ "pcie1_0_rev_perst",
+ "pcie1_1_rev_perst",
+ "pcie2_0_rev_perst",
+ "pcie2_1_rev_perst",
+ "pcie0_0_wake", "pcie0_1_wake",
+ "pcie2_0_wake", "pcie2_1_wake",
+ "pcie0_clkreq", "pcie1_clkreq",
+ "pcie2_clkreq", };
+static const char *mt7623_pcm_groups[] = { "pcm_clk_0", "pcm_clk_1",
+ "pcm_clk_2", "pcm_clk_3",
+ "pcm_clk_4", "pcm_clk_5",
+ "pcm_clk_6", "pcm_sync_0",
+ "pcm_sync_1", "pcm_sync_2",
+ "pcm_sync_3", "pcm_sync_4",
+ "pcm_sync_5", "pcm_sync_6",
+ "pcm_rx_0", "pcm_rx_1",
+ "pcm_rx_2", "pcm_rx_3",
+ "pcm_rx_4", "pcm_rx_5",
+ "pcm_rx_6", "pcm_tx_0",
+ "pcm_tx_1", "pcm_tx_2",
+ "pcm_tx_3", "pcm_tx_4",
+ "pcm_tx_5", "pcm_tx_6", };
+static const char *mt7623_pwm_groups[] = { "pwm_ch1_0", "pwm_ch1_1",
+ "pwm_ch1_2", "pwm_ch2_0",
+ "pwm_ch2_1", "pwm_ch2_2",
+ "pwm_ch3_0", "pwm_ch3_1",
+ "pwm_ch3_2", "pwm_ch4_0",
+ "pwm_ch4_1", "pwm_ch4_2",
+ "pwm_ch4_3", "pwm_ch5_0",
+ "pwm_ch5_1", "pwm_ch5_2",
+ "pwm_ch6_0", "pwm_ch6_1",
+ "pwm_ch6_2", "pwm_ch6_3",
+ "pwm_ch7_0", "pwm_ch7_1",
+ "pwm_ch7_2", };
+static const char *mt7623_pwrap_groups[] = { "pwrap", };
+static const char *mt7623_rtc_groups[] = { "rtc", };
+static const char *mt7623_spi_groups[] = { "spi0", "spi2", "spi2", };
+static const char *mt7623_spdif_groups[] = { "spdif_in0_0", "spdif_in0_1",
+ "spdif_in1_0", "spdif_in1_1",
+ "spdif_out", };
+static const char *mt7623_uart_groups[] = { "uart0_0_txd_rxd",
+ "uart0_1_txd_rxd",
+ "uart0_2_txd_rxd",
+ "uart0_3_txd_rxd",
+ "uart1_0_txd_rxd",
+ "uart1_1_txd_rxd",
+ "uart1_2_txd_rxd",
+ "uart2_0_txd_rxd",
+ "uart2_1_txd_rxd",
+ "uart3_txd_rxd",
+ "uart0_rts_cts",
+ "uart1_rts_cts",
+ "uart2_rts_cts",
+ "uart3_rts_cts", };
+static const char *mt7623_wdt_groups[] = { "watchdog_0", "watchdog_1", };
+
+static const struct function_desc mt7623_functions[] = {
+ {"audck", mt7623_aud_clk_groups, ARRAY_SIZE(mt7623_aud_clk_groups)},
+ {"disp", mt7623_disp_pwm_groups, ARRAY_SIZE(mt7623_disp_pwm_groups)},
+ {"eth", mt7623_ethernet_groups, ARRAY_SIZE(mt7623_ethernet_groups)},
+ {"sdio", mt7623_ext_sdio_groups, ARRAY_SIZE(mt7623_ext_sdio_groups)},
+ {"hdmi", mt7623_hdmi_groups, ARRAY_SIZE(mt7623_hdmi_groups)},
+ {"i2c", mt7623_i2c_groups, ARRAY_SIZE(mt7623_i2c_groups)},
+ {"i2s", mt7623_i2s_groups, ARRAY_SIZE(mt7623_i2s_groups)},
+ {"ir", mt7623_ir_groups, ARRAY_SIZE(mt7623_ir_groups)},
+ {"lcd", mt7623_lcd_groups, ARRAY_SIZE(mt7623_lcd_groups)},
+ {"msdc", mt7623_msdc_groups, ARRAY_SIZE(mt7623_msdc_groups)},
+ {"nand", mt7623_nandc_groups, ARRAY_SIZE(mt7623_nandc_groups)},
+ {"otg", mt7623_otg_groups, ARRAY_SIZE(mt7623_otg_groups)},
+ {"pcie", mt7623_pcie_groups, ARRAY_SIZE(mt7623_pcie_groups)},
+ {"pcm", mt7623_pcm_groups, ARRAY_SIZE(mt7623_pcm_groups)},
+ {"pwm", mt7623_pwm_groups, ARRAY_SIZE(mt7623_pwm_groups)},
+ {"pwrap", mt7623_pwrap_groups, ARRAY_SIZE(mt7623_pwrap_groups)},
+ {"rtc", mt7623_rtc_groups, ARRAY_SIZE(mt7623_rtc_groups)},
+ {"spi", mt7623_spi_groups, ARRAY_SIZE(mt7623_spi_groups)},
+ {"spdif", mt7623_spdif_groups, ARRAY_SIZE(mt7623_spdif_groups)},
+ {"uart", mt7623_uart_groups, ARRAY_SIZE(mt7623_uart_groups)},
+ {"watchdog", mt7623_wdt_groups, ARRAY_SIZE(mt7623_wdt_groups)},
+};
+
+static const struct mtk_eint_hw mt7623_eint_hw = {
+ .port_mask = 6,
+ .ports = 6,
+ .ap_num = 169,
+ .db_cnt = 20,
+};
+
+static struct mtk_pin_soc mt7623_data = {
+ .reg_cal = mt7623_reg_cals,
+ .pins = mt7623_pins,
+ .npins = ARRAY_SIZE(mt7623_pins),
+ .grps = mt7623_groups,
+ .ngrps = ARRAY_SIZE(mt7623_groups),
+ .funcs = mt7623_functions,
+ .nfuncs = ARRAY_SIZE(mt7623_functions),
+ .eint_hw = &mt7623_eint_hw,
+ .gpio_m = 0,
+ .ies_present = true,
+ .base_names = mtk_default_register_base_names,
+ .nbase_names = ARRAY_SIZE(mtk_default_register_base_names),
+ .bias_disable_set = mtk_pinconf_bias_disable_set_rev1,
+ .bias_disable_get = mtk_pinconf_bias_disable_get_rev1,
+ .bias_set = mtk_pinconf_bias_set_rev1,
+ .bias_get = mtk_pinconf_bias_get_rev1,
+ .drive_set = mtk_pinconf_drive_set_rev1,
+ .drive_get = mtk_pinconf_drive_get_rev1,
+ .adv_pull_get = mtk_pinconf_adv_pull_get,
+ .adv_pull_set = mtk_pinconf_adv_pull_set,
+};
+
+/*
+ * There are some specific pins have mux functions greater than 8,
+ * and if we want to switch thees high modes we need to disable
+ * bonding constraints firstly.
+ */
+static void mt7623_bonding_disable(struct platform_device *pdev)
+{
+ struct mtk_pinctrl *hw = platform_get_drvdata(pdev);
+
+ mtk_rmw(hw, 0, PIN_BOND_REG0, BOND_PCIE_CLR, BOND_PCIE_CLR);
+ mtk_rmw(hw, 0, PIN_BOND_REG1, BOND_I2S_CLR, BOND_I2S_CLR);
+ mtk_rmw(hw, 0, PIN_BOND_REG2, BOND_MSDC0E_CLR, BOND_MSDC0E_CLR);
+}
+
+static const struct of_device_id mt7623_pctrl_match[] = {
+ { .compatible = "mediatek,mt7623-moore-pinctrl", },
+ {}
+};
+
+static int mt7623_pinctrl_probe(struct platform_device *pdev)
+{
+ int err;
+
+ err = mtk_moore_pinctrl_probe(pdev, &mt7623_data);
+ if (err)
+ return err;
+
+ mt7623_bonding_disable(pdev);
+
+ return 0;
+}
+
+static struct platform_driver mtk_pinctrl_driver = {
+ .probe = mt7623_pinctrl_probe,
+ .driver = {
+ .name = "mt7623-moore-pinctrl",
+ .of_match_table = mt7623_pctrl_match,
+ },
+};
+
+static int __init mtk_pinctrl_init(void)
+{
+ return platform_driver_register(&mtk_pinctrl_driver);
+}
+arch_initcall(mtk_pinctrl_init);
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8183.c b/drivers/pinctrl/mediatek/pinctrl-mt8183.c
new file mode 100644
index 000000000000..6262fd3678ea
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8183.c
@@ -0,0 +1,544 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ *
+ * Author: Zhiyong Tao <zhiyong.tao@mediatek.com>
+ *
+ */
+
+#include "pinctrl-mtk-mt8183.h"
+#include "pinctrl-paris.h"
+
+/* MT8183 have multiple bases to program pin configuration listed as the below:
+ * iocfg[0]:0x10005000, iocfg[1]:0x11F20000, iocfg[2]:0x11E80000,
+ * iocfg[3]:0x11E70000, iocfg[4]:0x11E90000, iocfg[5]:0x11D30000,
+ * iocfg[6]:0x11D20000, iocfg[7]:0x11C50000, iocfg[8]:0x11F30000.
+ * _i_based could be used to indicate what base the pin should be mapped into.
+ */
+
+#define PIN_FIELD_BASE(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, _x_bits) \
+ PIN_FIELD_CALC(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, \
+ _x_bits, 32, 0)
+
+#define PINS_FIELD_BASE(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, _x_bits) \
+ PIN_FIELD_CALC(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, \
+ _x_bits, 32, 1)
+
+static const struct mtk_pin_field_calc mt8183_pin_mode_range[] = {
+ PIN_FIELD(0, 192, 0x300, 0x10, 0, 4),
+};
+
+static const struct mtk_pin_field_calc mt8183_pin_dir_range[] = {
+ PIN_FIELD(0, 192, 0x0, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt8183_pin_di_range[] = {
+ PIN_FIELD(0, 192, 0x200, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt8183_pin_do_range[] = {
+ PIN_FIELD(0, 192, 0x100, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt8183_pin_ies_range[] = {
+ PINS_FIELD_BASE(0, 3, 6, 0x000, 0x10, 3, 1),
+ PINS_FIELD_BASE(4, 7, 6, 0x000, 0x10, 5, 1),
+ PIN_FIELD_BASE(8, 8, 6, 0x000, 0x10, 0, 1),
+ PINS_FIELD_BASE(9, 10, 6, 0x000, 0x10, 12, 1),
+ PIN_FIELD_BASE(11, 11, 1, 0x000, 0x10, 3, 1),
+ PIN_FIELD_BASE(12, 12, 1, 0x000, 0x10, 7, 1),
+ PINS_FIELD_BASE(13, 16, 2, 0x000, 0x10, 2, 1),
+ PINS_FIELD_BASE(17, 20, 2, 0x000, 0x10, 3, 1),
+ PINS_FIELD_BASE(21, 24, 2, 0x000, 0x10, 4, 1),
+ PINS_FIELD_BASE(25, 28, 2, 0x000, 0x10, 5, 1),
+ PIN_FIELD_BASE(29, 29, 2, 0x000, 0x10, 6, 1),
+ PIN_FIELD_BASE(30, 30, 2, 0x000, 0x10, 7, 1),
+ PINS_FIELD_BASE(31, 31, 2, 0x000, 0x10, 8, 1),
+ PINS_FIELD_BASE(32, 34, 2, 0x000, 0x10, 7, 1),
+ PINS_FIELD_BASE(35, 37, 3, 0x000, 0x10, 0, 1),
+ PINS_FIELD_BASE(38, 40, 3, 0x000, 0x10, 1, 1),
+ PINS_FIELD_BASE(41, 42, 3, 0x000, 0x10, 2, 1),
+ PINS_FIELD_BASE(43, 45, 3, 0x000, 0x10, 3, 1),
+ PINS_FIELD_BASE(46, 47, 3, 0x000, 0x10, 4, 1),
+ PINS_FIELD_BASE(48, 49, 3, 0x000, 0x10, 5, 1),
+ PINS_FIELD_BASE(50, 51, 4, 0x000, 0x10, 0, 1),
+ PINS_FIELD_BASE(52, 57, 4, 0x000, 0x10, 1, 1),
+ PINS_FIELD_BASE(58, 60, 4, 0x000, 0x10, 2, 1),
+ PINS_FIELD_BASE(61, 64, 5, 0x000, 0x10, 0, 1),
+ PINS_FIELD_BASE(65, 66, 5, 0x000, 0x10, 1, 1),
+ PINS_FIELD_BASE(67, 68, 5, 0x000, 0x10, 2, 1),
+ PINS_FIELD_BASE(69, 71, 5, 0x000, 0x10, 3, 1),
+ PINS_FIELD_BASE(72, 76, 5, 0x000, 0x10, 4, 1),
+ PINS_FIELD_BASE(77, 80, 5, 0x000, 0x10, 5, 1),
+ PIN_FIELD_BASE(81, 81, 5, 0x000, 0x10, 6, 1),
+ PINS_FIELD_BASE(82, 83, 5, 0x000, 0x10, 7, 1),
+ PIN_FIELD_BASE(84, 84, 5, 0x000, 0x10, 6, 1),
+ PINS_FIELD_BASE(85, 88, 5, 0x000, 0x10, 8, 1),
+ PIN_FIELD_BASE(89, 89, 6, 0x000, 0x10, 11, 1),
+ PIN_FIELD_BASE(90, 90, 6, 0x000, 0x10, 1, 1),
+ PINS_FIELD_BASE(91, 94, 6, 0x000, 0x10, 2, 1),
+ PINS_FIELD_BASE(95, 96, 6, 0x000, 0x10, 6, 1),
+ PINS_FIELD_BASE(97, 98, 6, 0x000, 0x10, 7, 1),
+ PIN_FIELD_BASE(99, 99, 6, 0x000, 0x10, 8, 1),
+ PIN_FIELD_BASE(100, 100, 6, 0x000, 0x10, 9, 1),
+ PINS_FIELD_BASE(101, 102, 6, 0x000, 0x10, 10, 1),
+ PINS_FIELD_BASE(103, 104, 6, 0x000, 0x10, 13, 1),
+ PINS_FIELD_BASE(105, 106, 6, 0x000, 0x10, 14, 1),
+ PIN_FIELD_BASE(107, 107, 7, 0x000, 0x10, 0, 1),
+ PIN_FIELD_BASE(108, 108, 7, 0x000, 0x10, 1, 1),
+ PIN_FIELD_BASE(109, 109, 7, 0x000, 0x10, 2, 1),
+ PIN_FIELD_BASE(110, 110, 7, 0x000, 0x10, 0, 1),
+ PIN_FIELD_BASE(111, 111, 7, 0x000, 0x10, 3, 1),
+ PIN_FIELD_BASE(112, 112, 7, 0x000, 0x10, 2, 1),
+ PIN_FIELD_BASE(113, 113, 7, 0x000, 0x10, 4, 1),
+ PIN_FIELD_BASE(114, 114, 7, 0x000, 0x10, 5, 1),
+ PIN_FIELD_BASE(115, 115, 7, 0x000, 0x10, 6, 1),
+ PIN_FIELD_BASE(116, 116, 7, 0x000, 0x10, 7, 1),
+ PIN_FIELD_BASE(117, 117, 7, 0x000, 0x10, 8, 1),
+ PIN_FIELD_BASE(118, 118, 7, 0x000, 0x10, 9, 1),
+ PIN_FIELD_BASE(119, 119, 7, 0x000, 0x10, 10, 1),
+ PIN_FIELD_BASE(120, 120, 7, 0x000, 0x10, 11, 1),
+ PIN_FIELD_BASE(121, 121, 7, 0x000, 0x10, 12, 1),
+ PIN_FIELD_BASE(122, 122, 8, 0x000, 0x10, 0, 1),
+ PIN_FIELD_BASE(123, 123, 8, 0x000, 0x10, 1, 1),
+ PIN_FIELD_BASE(124, 124, 8, 0x000, 0x10, 2, 1),
+ PINS_FIELD_BASE(125, 130, 8, 0x000, 0x10, 1, 1),
+ PIN_FIELD_BASE(131, 131, 8, 0x000, 0x10, 3, 1),
+ PIN_FIELD_BASE(132, 132, 8, 0x000, 0x10, 1, 1),
+ PIN_FIELD_BASE(133, 133, 8, 0x000, 0x10, 4, 1),
+ PIN_FIELD_BASE(134, 134, 1, 0x000, 0x10, 0, 1),
+ PIN_FIELD_BASE(135, 135, 1, 0x000, 0x10, 1, 1),
+ PINS_FIELD_BASE(136, 143, 1, 0x000, 0x10, 2, 1),
+ PINS_FIELD_BASE(144, 147, 1, 0x000, 0x10, 4, 1),
+ PIN_FIELD_BASE(148, 148, 1, 0x000, 0x10, 5, 1),
+ PIN_FIELD_BASE(149, 149, 1, 0x000, 0x10, 6, 1),
+ PINS_FIELD_BASE(150, 153, 1, 0x000, 0x10, 8, 1),
+ PIN_FIELD_BASE(154, 154, 1, 0x000, 0x10, 9, 1),
+ PINS_FIELD_BASE(155, 157, 1, 0x000, 0x10, 10, 1),
+ PINS_FIELD_BASE(158, 160, 1, 0x000, 0x10, 8, 1),
+ PINS_FIELD_BASE(161, 164, 2, 0x000, 0x10, 0, 1),
+ PINS_FIELD_BASE(165, 166, 2, 0x000, 0x10, 1, 1),
+ PINS_FIELD_BASE(167, 168, 4, 0x000, 0x10, 2, 1),
+ PIN_FIELD_BASE(169, 169, 4, 0x000, 0x10, 3, 1),
+ PINS_FIELD_BASE(170, 174, 4, 0x000, 0x10, 4, 1),
+ PINS_FIELD_BASE(175, 176, 4, 0x000, 0x10, 3, 1),
+ PINS_FIELD_BASE(177, 179, 6, 0x000, 0x10, 4, 1),
+};
+
+static const struct mtk_pin_field_calc mt8183_pin_smt_range[] = {
+ PINS_FIELD_BASE(0, 3, 6, 0x010, 0x10, 3, 1),
+ PINS_FIELD_BASE(4, 7, 6, 0x010, 0x10, 5, 1),
+ PIN_FIELD_BASE(8, 8, 6, 0x010, 0x10, 0, 1),
+ PINS_FIELD_BASE(9, 10, 6, 0x010, 0x10, 12, 1),
+ PIN_FIELD_BASE(11, 11, 1, 0x010, 0x10, 3, 1),
+ PIN_FIELD_BASE(12, 12, 1, 0x010, 0x10, 7, 1),
+ PINS_FIELD_BASE(13, 16, 2, 0x010, 0x10, 2, 1),
+ PINS_FIELD_BASE(17, 20, 2, 0x010, 0x10, 3, 1),
+ PINS_FIELD_BASE(21, 24, 2, 0x010, 0x10, 4, 1),
+ PINS_FIELD_BASE(25, 28, 2, 0x010, 0x10, 5, 1),
+ PIN_FIELD_BASE(29, 29, 2, 0x010, 0x10, 6, 1),
+ PIN_FIELD_BASE(30, 30, 2, 0x010, 0x10, 7, 1),
+ PINS_FIELD_BASE(31, 31, 2, 0x010, 0x10, 8, 1),
+ PINS_FIELD_BASE(32, 34, 2, 0x010, 0x10, 7, 1),
+ PINS_FIELD_BASE(35, 37, 3, 0x010, 0x10, 0, 1),
+ PINS_FIELD_BASE(38, 40, 3, 0x010, 0x10, 1, 1),
+ PINS_FIELD_BASE(41, 42, 3, 0x010, 0x10, 2, 1),
+ PINS_FIELD_BASE(43, 45, 3, 0x010, 0x10, 3, 1),
+ PINS_FIELD_BASE(46, 47, 3, 0x010, 0x10, 4, 1),
+ PINS_FIELD_BASE(48, 49, 3, 0x010, 0x10, 5, 1),
+ PINS_FIELD_BASE(50, 51, 4, 0x010, 0x10, 0, 1),
+ PINS_FIELD_BASE(52, 57, 4, 0x010, 0x10, 1, 1),
+ PINS_FIELD_BASE(58, 60, 4, 0x010, 0x10, 2, 1),
+ PINS_FIELD_BASE(61, 64, 5, 0x010, 0x10, 0, 1),
+ PINS_FIELD_BASE(65, 66, 5, 0x010, 0x10, 1, 1),
+ PINS_FIELD_BASE(67, 68, 5, 0x010, 0x10, 2, 1),
+ PINS_FIELD_BASE(69, 71, 5, 0x010, 0x10, 3, 1),
+ PINS_FIELD_BASE(72, 76, 5, 0x010, 0x10, 4, 1),
+ PINS_FIELD_BASE(77, 80, 5, 0x010, 0x10, 5, 1),
+ PIN_FIELD_BASE(81, 81, 5, 0x010, 0x10, 6, 1),
+ PINS_FIELD_BASE(82, 83, 5, 0x010, 0x10, 7, 1),
+ PIN_FIELD_BASE(84, 84, 5, 0x010, 0x10, 6, 1),
+ PINS_FIELD_BASE(85, 88, 5, 0x010, 0x10, 8, 1),
+ PIN_FIELD_BASE(89, 89, 6, 0x010, 0x10, 11, 1),
+ PIN_FIELD_BASE(90, 90, 6, 0x010, 0x10, 1, 1),
+ PINS_FIELD_BASE(91, 94, 6, 0x010, 0x10, 2, 1),
+ PINS_FIELD_BASE(95, 96, 6, 0x010, 0x10, 6, 1),
+ PINS_FIELD_BASE(97, 98, 6, 0x010, 0x10, 7, 1),
+ PIN_FIELD_BASE(99, 99, 6, 0x010, 0x10, 8, 1),
+ PIN_FIELD_BASE(100, 100, 6, 0x010, 0x10, 9, 1),
+ PINS_FIELD_BASE(101, 102, 6, 0x010, 0x10, 10, 1),
+ PINS_FIELD_BASE(103, 104, 6, 0x010, 0x10, 13, 1),
+ PINS_FIELD_BASE(105, 106, 6, 0x010, 0x10, 14, 1),
+ PIN_FIELD_BASE(107, 107, 7, 0x010, 0x10, 0, 1),
+ PIN_FIELD_BASE(108, 108, 7, 0x010, 0x10, 1, 1),
+ PIN_FIELD_BASE(109, 109, 7, 0x010, 0x10, 2, 1),
+ PIN_FIELD_BASE(110, 110, 7, 0x010, 0x10, 0, 1),
+ PIN_FIELD_BASE(111, 111, 7, 0x010, 0x10, 3, 1),
+ PIN_FIELD_BASE(112, 112, 7, 0x010, 0x10, 2, 1),
+ PIN_FIELD_BASE(113, 113, 7, 0x010, 0x10, 4, 1),
+ PIN_FIELD_BASE(114, 114, 7, 0x010, 0x10, 5, 1),
+ PIN_FIELD_BASE(115, 115, 7, 0x010, 0x10, 6, 1),
+ PIN_FIELD_BASE(116, 116, 7, 0x010, 0x10, 7, 1),
+ PIN_FIELD_BASE(117, 117, 7, 0x010, 0x10, 8, 1),
+ PIN_FIELD_BASE(118, 118, 7, 0x010, 0x10, 9, 1),
+ PIN_FIELD_BASE(119, 119, 7, 0x010, 0x10, 10, 1),
+ PIN_FIELD_BASE(120, 120, 7, 0x010, 0x10, 11, 1),
+ PIN_FIELD_BASE(121, 121, 7, 0x010, 0x10, 12, 1),
+ PIN_FIELD_BASE(122, 122, 8, 0x010, 0x10, 0, 1),
+ PIN_FIELD_BASE(123, 123, 8, 0x010, 0x10, 1, 1),
+ PIN_FIELD_BASE(124, 124, 8, 0x010, 0x10, 2, 1),
+ PINS_FIELD_BASE(125, 130, 8, 0x010, 0x10, 1, 1),
+ PIN_FIELD_BASE(131, 131, 8, 0x010, 0x10, 3, 1),
+ PIN_FIELD_BASE(132, 132, 8, 0x010, 0x10, 1, 1),
+ PIN_FIELD_BASE(133, 133, 8, 0x010, 0x10, 4, 1),
+ PIN_FIELD_BASE(134, 134, 1, 0x010, 0x10, 0, 1),
+ PIN_FIELD_BASE(135, 135, 1, 0x010, 0x10, 1, 1),
+ PINS_FIELD_BASE(136, 143, 1, 0x010, 0x10, 2, 1),
+ PINS_FIELD_BASE(144, 147, 1, 0x010, 0x10, 4, 1),
+ PIN_FIELD_BASE(148, 148, 1, 0x010, 0x10, 5, 1),
+ PIN_FIELD_BASE(149, 149, 1, 0x010, 0x10, 6, 1),
+ PINS_FIELD_BASE(150, 153, 1, 0x010, 0x10, 8, 1),
+ PIN_FIELD_BASE(154, 154, 1, 0x010, 0x10, 9, 1),
+ PINS_FIELD_BASE(155, 157, 1, 0x010, 0x10, 10, 1),
+ PINS_FIELD_BASE(158, 160, 1, 0x010, 0x10, 8, 1),
+ PINS_FIELD_BASE(161, 164, 2, 0x010, 0x10, 0, 1),
+ PINS_FIELD_BASE(165, 166, 2, 0x010, 0x10, 1, 1),
+ PINS_FIELD_BASE(167, 168, 4, 0x010, 0x10, 2, 1),
+ PIN_FIELD_BASE(169, 169, 4, 0x010, 0x10, 3, 1),
+ PINS_FIELD_BASE(170, 174, 4, 0x010, 0x10, 4, 1),
+ PINS_FIELD_BASE(175, 176, 4, 0x010, 0x10, 3, 1),
+ PINS_FIELD_BASE(177, 179, 6, 0x010, 0x10, 4, 1),
+};
+
+static const struct mtk_pin_field_calc mt8183_pin_pullen_range[] = {
+ PIN_FIELD_BASE(0, 3, 6, 0x060, 0x10, 6, 1),
+ PIN_FIELD_BASE(4, 7, 6, 0x060, 0x10, 11, 1),
+ PIN_FIELD_BASE(8, 8, 6, 0x060, 0x10, 0, 1),
+ PIN_FIELD_BASE(9, 10, 6, 0x060, 0x10, 26, 1),
+ PIN_FIELD_BASE(11, 11, 1, 0x060, 0x10, 10, 1),
+ PIN_FIELD_BASE(12, 12, 1, 0x060, 0x10, 17, 1),
+ PIN_FIELD_BASE(13, 28, 2, 0x060, 0x10, 6, 1),
+ PIN_FIELD_BASE(43, 49, 3, 0x060, 0x10, 8, 1),
+ PIN_FIELD_BASE(50, 60, 4, 0x060, 0x10, 0, 1),
+ PIN_FIELD_BASE(61, 88, 5, 0x060, 0x10, 0, 1),
+ PIN_FIELD_BASE(89, 89, 6, 0x060, 0x10, 24, 1),
+ PIN_FIELD_BASE(90, 90, 6, 0x060, 0x10, 1, 1),
+ PIN_FIELD_BASE(95, 95, 6, 0x060, 0x10, 15, 1),
+ PIN_FIELD_BASE(96, 102, 6, 0x060, 0x10, 17, 1),
+ PIN_FIELD_BASE(103, 106, 6, 0x060, 0x10, 28, 1),
+ PIN_FIELD_BASE(107, 121, 7, 0x060, 0x10, 0, 1),
+ PIN_FIELD_BASE(134, 143, 1, 0x060, 0x10, 0, 1),
+ PIN_FIELD_BASE(144, 149, 1, 0x060, 0x10, 11, 1),
+ PIN_FIELD_BASE(150, 160, 1, 0x060, 0x10, 18, 1),
+ PIN_FIELD_BASE(161, 166, 2, 0x060, 0x10, 0, 1),
+ PIN_FIELD_BASE(167, 176, 4, 0x060, 0x10, 11, 1),
+ PIN_FIELD_BASE(177, 177, 6, 0x060, 0x10, 10, 1),
+ PIN_FIELD_BASE(178, 178, 6, 0x060, 0x10, 16, 1),
+ PIN_FIELD_BASE(179, 179, 6, 0x060, 0x10, 25, 1),
+};
+
+static const struct mtk_pin_field_calc mt8183_pin_pullsel_range[] = {
+ PIN_FIELD_BASE(0, 3, 6, 0x080, 0x10, 6, 1),
+ PIN_FIELD_BASE(4, 7, 6, 0x080, 0x10, 11, 1),
+ PIN_FIELD_BASE(8, 8, 6, 0x080, 0x10, 0, 1),
+ PIN_FIELD_BASE(9, 10, 6, 0x080, 0x10, 26, 1),
+ PIN_FIELD_BASE(11, 11, 1, 0x080, 0x10, 10, 1),
+ PIN_FIELD_BASE(12, 12, 1, 0x080, 0x10, 17, 1),
+ PIN_FIELD_BASE(13, 28, 2, 0x080, 0x10, 6, 1),
+ PIN_FIELD_BASE(43, 49, 3, 0x080, 0x10, 8, 1),
+ PIN_FIELD_BASE(50, 60, 4, 0x080, 0x10, 0, 1),
+ PIN_FIELD_BASE(61, 88, 5, 0x080, 0x10, 0, 1),
+ PIN_FIELD_BASE(89, 89, 6, 0x080, 0x10, 24, 1),
+ PIN_FIELD_BASE(90, 90, 6, 0x080, 0x10, 1, 1),
+ PIN_FIELD_BASE(95, 95, 6, 0x080, 0x10, 15, 1),
+ PIN_FIELD_BASE(96, 102, 6, 0x080, 0x10, 17, 1),
+ PIN_FIELD_BASE(103, 106, 6, 0x080, 0x10, 28, 1),
+ PIN_FIELD_BASE(107, 121, 7, 0x080, 0x10, 0, 1),
+ PIN_FIELD_BASE(134, 143, 1, 0x080, 0x10, 0, 1),
+ PIN_FIELD_BASE(144, 149, 1, 0x080, 0x10, 11, 1),
+ PIN_FIELD_BASE(150, 160, 1, 0x080, 0x10, 18, 1),
+ PIN_FIELD_BASE(161, 166, 2, 0x080, 0x10, 0, 1),
+ PIN_FIELD_BASE(167, 176, 4, 0x080, 0x10, 11, 1),
+ PIN_FIELD_BASE(177, 177, 6, 0x080, 0x10, 10, 1),
+ PIN_FIELD_BASE(178, 178, 6, 0x080, 0x10, 16, 1),
+ PIN_FIELD_BASE(179, 179, 6, 0x080, 0x10, 25, 1),
+};
+
+static const struct mtk_pin_field_calc mt8183_pin_drv_range[] = {
+ PINS_FIELD_BASE(0, 3, 6, 0x0A0, 0x10, 12, 3),
+ PINS_FIELD_BASE(4, 7, 6, 0x0A0, 0x10, 20, 3),
+ PIN_FIELD_BASE(8, 8, 6, 0x0A0, 0x10, 0, 3),
+ PINS_FIELD_BASE(9, 10, 6, 0x0B0, 0x10, 16, 3),
+ PIN_FIELD_BASE(11, 11, 1, 0x0A0, 0x10, 12, 3),
+ PIN_FIELD_BASE(12, 12, 1, 0x0A0, 0x10, 28, 3),
+ PINS_FIELD_BASE(13, 16, 2, 0x0A0, 0x10, 8, 3),
+ PINS_FIELD_BASE(17, 20, 2, 0x0A0, 0x10, 12, 3),
+ PINS_FIELD_BASE(21, 24, 2, 0x0A0, 0x10, 16, 3),
+ PINS_FIELD_BASE(25, 28, 2, 0x0A0, 0x10, 20, 3),
+ PIN_FIELD_BASE(29, 29, 2, 0x0A0, 0x10, 24, 3),
+ PIN_FIELD_BASE(30, 30, 2, 0x0A0, 0x10, 28, 3),
+ PINS_FIELD_BASE(31, 31, 2, 0x0B0, 0x10, 0, 3),
+ PINS_FIELD_BASE(32, 34, 2, 0x0A0, 0x10, 28, 3),
+ PINS_FIELD_BASE(35, 37, 3, 0x0A0, 0x10, 0, 3),
+ PINS_FIELD_BASE(38, 40, 3, 0x0A0, 0x10, 4, 3),
+ PINS_FIELD_BASE(41, 42, 3, 0x0A0, 0x10, 8, 3),
+ PINS_FIELD_BASE(43, 45, 3, 0x0A0, 0x10, 12, 3),
+ PINS_FIELD_BASE(46, 47, 3, 0x0A0, 0x10, 16, 3),
+ PINS_FIELD_BASE(48, 49, 3, 0x0A0, 0x10, 20, 3),
+ PINS_FIELD_BASE(50, 51, 4, 0x0A0, 0x10, 0, 3),
+ PINS_FIELD_BASE(52, 57, 4, 0x0A0, 0x10, 4, 3),
+ PINS_FIELD_BASE(58, 60, 4, 0x0A0, 0x10, 8, 3),
+ PINS_FIELD_BASE(61, 64, 5, 0x0A0, 0x10, 0, 3),
+ PINS_FIELD_BASE(65, 66, 5, 0x0A0, 0x10, 4, 3),
+ PINS_FIELD_BASE(67, 68, 5, 0x0A0, 0x10, 8, 3),
+ PINS_FIELD_BASE(69, 71, 5, 0x0A0, 0x10, 12, 3),
+ PINS_FIELD_BASE(72, 76, 5, 0x0A0, 0x10, 16, 3),
+ PINS_FIELD_BASE(77, 80, 5, 0x0A0, 0x10, 20, 3),
+ PIN_FIELD_BASE(81, 81, 5, 0x0A0, 0x10, 24, 3),
+ PINS_FIELD_BASE(82, 83, 5, 0x0A0, 0x10, 28, 3),
+ PIN_FIELD_BASE(84, 84, 5, 0x0A0, 0x10, 24, 3),
+ PINS_FIELD_BASE(85, 88, 5, 0x0B0, 0x10, 0, 3),
+ PIN_FIELD_BASE(89, 89, 6, 0x0B0, 0x10, 12, 3),
+ PIN_FIELD_BASE(90, 90, 6, 0x0A0, 0x10, 4, 3),
+ PINS_FIELD_BASE(91, 94, 6, 0x0A0, 0x10, 8, 3),
+ PINS_FIELD_BASE(95, 96, 6, 0x0A0, 0x10, 24, 3),
+ PINS_FIELD_BASE(97, 98, 6, 0x0A0, 0x10, 28, 3),
+ PIN_FIELD_BASE(99, 99, 6, 0x0B0, 0x10, 0, 3),
+ PIN_FIELD_BASE(100, 100, 6, 0x0B0, 0x10, 4, 3),
+ PINS_FIELD_BASE(101, 102, 6, 0x0B0, 0x10, 8, 3),
+ PINS_FIELD_BASE(103, 104, 6, 0x0B0, 0x10, 20, 3),
+ PINS_FIELD_BASE(105, 106, 6, 0x0B0, 0x10, 24, 3),
+ PIN_FIELD_BASE(107, 107, 7, 0x0A0, 0x10, 0, 3),
+ PIN_FIELD_BASE(108, 108, 7, 0x0A0, 0x10, 4, 3),
+ PIN_FIELD_BASE(109, 109, 7, 0x0A0, 0x10, 8, 3),
+ PIN_FIELD_BASE(110, 110, 7, 0x0A0, 0x10, 0, 3),
+ PIN_FIELD_BASE(111, 111, 7, 0x0A0, 0x10, 4, 3),
+ PIN_FIELD_BASE(112, 112, 7, 0x0A0, 0x10, 8, 3),
+ PIN_FIELD_BASE(113, 113, 7, 0x0A0, 0x10, 16, 3),
+ PIN_FIELD_BASE(114, 114, 7, 0x0A0, 0x10, 20, 3),
+ PIN_FIELD_BASE(115, 115, 7, 0x0A0, 0x10, 24, 3),
+ PIN_FIELD_BASE(116, 116, 7, 0x0A0, 0x10, 28, 3),
+ PIN_FIELD_BASE(117, 117, 7, 0x0B0, 0x10, 0, 3),
+ PIN_FIELD_BASE(118, 118, 7, 0x0B0, 0x10, 4, 3),
+ PIN_FIELD_BASE(119, 119, 7, 0x0B0, 0x10, 8, 3),
+ PIN_FIELD_BASE(120, 120, 7, 0x0B0, 0x10, 12, 3),
+ PIN_FIELD_BASE(121, 121, 7, 0x0B0, 0x10, 16, 3),
+ PIN_FIELD_BASE(122, 122, 8, 0x0A0, 0x10, 0, 3),
+ PIN_FIELD_BASE(123, 123, 8, 0x0A0, 0x10, 4, 3),
+ PIN_FIELD_BASE(124, 124, 8, 0x0A0, 0x10, 8, 3),
+ PINS_FIELD_BASE(125, 130, 8, 0x0A0, 0x10, 4, 3),
+ PIN_FIELD_BASE(131, 131, 8, 0x0A0, 0x10, 12, 3),
+ PIN_FIELD_BASE(132, 132, 8, 0x0A0, 0x10, 4, 3),
+ PIN_FIELD_BASE(133, 133, 8, 0x0A0, 0x10, 16, 3),
+ PIN_FIELD_BASE(134, 134, 1, 0x0A0, 0x10, 0, 3),
+ PIN_FIELD_BASE(135, 135, 1, 0x0A0, 0x10, 4, 3),
+ PINS_FIELD_BASE(136, 143, 1, 0x0A0, 0x10, 8, 3),
+ PINS_FIELD_BASE(144, 147, 1, 0x0A0, 0x10, 16, 3),
+ PIN_FIELD_BASE(148, 148, 1, 0x0A0, 0x10, 20, 3),
+ PIN_FIELD_BASE(149, 149, 1, 0x0A0, 0x10, 24, 3),
+ PINS_FIELD_BASE(150, 153, 1, 0x0B0, 0x10, 0, 3),
+ PIN_FIELD_BASE(154, 154, 1, 0x0B0, 0x10, 4, 3),
+ PINS_FIELD_BASE(155, 157, 1, 0x0B0, 0x10, 8, 3),
+ PINS_FIELD_BASE(158, 160, 1, 0x0B0, 0x10, 0, 3),
+ PINS_FIELD_BASE(161, 164, 2, 0x0A0, 0x10, 0, 3),
+ PINS_FIELD_BASE(165, 166, 2, 0x0A0, 0x10, 4, 3),
+ PINS_FIELD_BASE(167, 168, 4, 0x0A0, 0x10, 8, 3),
+ PIN_FIELD_BASE(169, 169, 4, 0x0A0, 0x10, 12, 3),
+ PINS_FIELD_BASE(170, 174, 4, 0x0A0, 0x10, 16, 3),
+ PINS_FIELD_BASE(175, 176, 4, 0x0A0, 0x10, 12, 3),
+ PINS_FIELD_BASE(177, 179, 6, 0x0A0, 0x10, 16, 3),
+};
+
+static const struct mtk_pin_field_calc mt8183_pin_pupd_range[] = {
+ PIN_FIELD_BASE(29, 29, 2, 0x0C0, 0x10, 2, 1),
+ PIN_FIELD_BASE(30, 30, 2, 0x0C0, 0x10, 6, 1),
+ PIN_FIELD_BASE(31, 31, 2, 0x0C0, 0x10, 10, 1),
+ PIN_FIELD_BASE(32, 32, 2, 0x0C0, 0x10, 14, 1),
+ PIN_FIELD_BASE(33, 33, 2, 0x0C0, 0x10, 18, 1),
+ PIN_FIELD_BASE(34, 34, 2, 0x0C0, 0x10, 22, 1),
+ PIN_FIELD_BASE(35, 35, 3, 0x0C0, 0x10, 2, 1),
+ PIN_FIELD_BASE(36, 36, 3, 0x0C0, 0x10, 6, 1),
+ PIN_FIELD_BASE(37, 37, 3, 0x0C0, 0x10, 10, 1),
+ PIN_FIELD_BASE(38, 38, 3, 0x0C0, 0x10, 14, 1),
+ PIN_FIELD_BASE(39, 39, 3, 0x0C0, 0x10, 18, 1),
+ PIN_FIELD_BASE(40, 40, 3, 0x0C0, 0x10, 22, 1),
+ PIN_FIELD_BASE(41, 41, 3, 0x0C0, 0x10, 26, 1),
+ PIN_FIELD_BASE(42, 42, 3, 0x0C0, 0x10, 30, 1),
+ PIN_FIELD_BASE(91, 91, 6, 0x0C0, 0x10, 2, 1),
+ PIN_FIELD_BASE(92, 92, 6, 0x0C0, 0x10, 6, 1),
+ PIN_FIELD_BASE(93, 93, 6, 0x0C0, 0x10, 10, 1),
+ PIN_FIELD_BASE(94, 94, 6, 0x0C0, 0x10, 14, 1),
+ PIN_FIELD_BASE(122, 122, 8, 0x0C0, 0x10, 2, 1),
+ PIN_FIELD_BASE(123, 123, 8, 0x0C0, 0x10, 6, 1),
+ PIN_FIELD_BASE(124, 124, 8, 0x0C0, 0x10, 10, 1),
+ PIN_FIELD_BASE(125, 125, 8, 0x0C0, 0x10, 14, 1),
+ PIN_FIELD_BASE(126, 126, 8, 0x0C0, 0x10, 18, 1),
+ PIN_FIELD_BASE(127, 127, 8, 0x0C0, 0x10, 22, 1),
+ PIN_FIELD_BASE(128, 128, 8, 0x0C0, 0x10, 26, 1),
+ PIN_FIELD_BASE(129, 129, 8, 0x0C0, 0x10, 30, 1),
+ PIN_FIELD_BASE(130, 130, 8, 0x0D0, 0x10, 2, 1),
+ PIN_FIELD_BASE(131, 131, 8, 0x0D0, 0x10, 6, 1),
+ PIN_FIELD_BASE(132, 132, 8, 0x0D0, 0x10, 10, 1),
+ PIN_FIELD_BASE(133, 133, 8, 0x0D0, 0x10, 14, 1),
+};
+
+static const struct mtk_pin_field_calc mt8183_pin_r0_range[] = {
+ PIN_FIELD_BASE(29, 29, 2, 0x0C0, 0x10, 0, 1),
+ PIN_FIELD_BASE(30, 30, 2, 0x0C0, 0x10, 4, 1),
+ PIN_FIELD_BASE(31, 31, 2, 0x0C0, 0x10, 8, 1),
+ PIN_FIELD_BASE(32, 32, 2, 0x0C0, 0x10, 12, 1),
+ PIN_FIELD_BASE(33, 33, 2, 0x0C0, 0x10, 16, 1),
+ PIN_FIELD_BASE(34, 34, 2, 0x0C0, 0x10, 20, 1),
+ PIN_FIELD_BASE(35, 35, 3, 0x0C0, 0x10, 0, 1),
+ PIN_FIELD_BASE(36, 36, 3, 0x0C0, 0x10, 4, 1),
+ PIN_FIELD_BASE(37, 37, 3, 0x0C0, 0x10, 8, 1),
+ PIN_FIELD_BASE(38, 38, 3, 0x0C0, 0x10, 12, 1),
+ PIN_FIELD_BASE(39, 39, 3, 0x0C0, 0x10, 16, 1),
+ PIN_FIELD_BASE(40, 40, 3, 0x0C0, 0x10, 20, 1),
+ PIN_FIELD_BASE(41, 41, 3, 0x0C0, 0x10, 24, 1),
+ PIN_FIELD_BASE(42, 42, 3, 0x0C0, 0x10, 28, 1),
+ PIN_FIELD_BASE(48, 48, 3, 0x0F0, 0x10, 18, 1),
+ PIN_FIELD_BASE(49, 49, 3, 0x0F0, 0x10, 13, 1),
+ PIN_FIELD_BASE(50, 50, 4, 0x0F0, 0x10, 10, 1),
+ PIN_FIELD_BASE(51, 51, 4, 0x0F0, 0x10, 5, 1),
+ PIN_FIELD_BASE(81, 81, 5, 0x0F0, 0x10, 7, 1),
+ PIN_FIELD_BASE(82, 82, 5, 0x0F0, 0x10, 5, 1),
+ PIN_FIELD_BASE(83, 83, 5, 0x0F0, 0x10, 15, 1),
+ PIN_FIELD_BASE(84, 84, 5, 0x0F0, 0x10, 17, 1),
+ PIN_FIELD_BASE(91, 91, 6, 0x0C0, 0x10, 0, 1),
+ PIN_FIELD_BASE(92, 92, 6, 0x0C0, 0x10, 4, 1),
+ PIN_FIELD_BASE(93, 93, 6, 0x0C0, 0x10, 8, 1),
+ PIN_FIELD_BASE(94, 94, 6, 0x0C0, 0x10, 12, 1),
+ PIN_FIELD_BASE(103, 103, 6, 0x0F0, 0x10, 20, 1),
+ PIN_FIELD_BASE(104, 104, 6, 0x0F0, 0x10, 10, 1),
+ PIN_FIELD_BASE(105, 105, 6, 0x0F0, 0x10, 22, 1),
+ PIN_FIELD_BASE(106, 106, 6, 0x0F0, 0x10, 12, 1),
+ PIN_FIELD_BASE(122, 122, 8, 0x0C0, 0x10, 0, 1),
+ PIN_FIELD_BASE(123, 123, 8, 0x0C0, 0x10, 4, 1),
+ PIN_FIELD_BASE(124, 124, 8, 0x0C0, 0x10, 8, 1),
+ PIN_FIELD_BASE(125, 125, 8, 0x0C0, 0x10, 12, 1),
+ PIN_FIELD_BASE(126, 126, 8, 0x0C0, 0x10, 16, 1),
+ PIN_FIELD_BASE(127, 127, 8, 0x0C0, 0x10, 20, 1),
+ PIN_FIELD_BASE(128, 128, 8, 0x0C0, 0x10, 24, 1),
+ PIN_FIELD_BASE(129, 129, 8, 0x0C0, 0x10, 28, 1),
+ PIN_FIELD_BASE(130, 130, 8, 0x0D0, 0x10, 0, 1),
+ PIN_FIELD_BASE(131, 131, 8, 0x0D0, 0x10, 4, 1),
+ PIN_FIELD_BASE(132, 132, 8, 0x0D0, 0x10, 8, 1),
+ PIN_FIELD_BASE(133, 133, 8, 0x0D0, 0x10, 12, 1),
+};
+
+static const struct mtk_pin_field_calc mt8183_pin_r1_range[] = {
+ PIN_FIELD_BASE(29, 29, 2, 0x0C0, 0x10, 1, 1),
+ PIN_FIELD_BASE(30, 30, 2, 0x0C0, 0x10, 5, 1),
+ PIN_FIELD_BASE(31, 31, 2, 0x0C0, 0x10, 9, 1),
+ PIN_FIELD_BASE(32, 32, 2, 0x0C0, 0x10, 13, 1),
+ PIN_FIELD_BASE(33, 33, 2, 0x0C0, 0x10, 17, 1),
+ PIN_FIELD_BASE(34, 34, 2, 0x0C0, 0x10, 21, 1),
+ PIN_FIELD_BASE(35, 35, 3, 0x0C0, 0x10, 1, 1),
+ PIN_FIELD_BASE(36, 36, 3, 0x0C0, 0x10, 5, 1),
+ PIN_FIELD_BASE(37, 37, 3, 0x0C0, 0x10, 9, 1),
+ PIN_FIELD_BASE(38, 38, 3, 0x0C0, 0x10, 13, 1),
+ PIN_FIELD_BASE(39, 39, 3, 0x0C0, 0x10, 17, 1),
+ PIN_FIELD_BASE(40, 40, 3, 0x0C0, 0x10, 21, 1),
+ PIN_FIELD_BASE(41, 41, 3, 0x0C0, 0x10, 25, 1),
+ PIN_FIELD_BASE(42, 42, 3, 0x0C0, 0x10, 29, 1),
+ PIN_FIELD_BASE(48, 48, 3, 0x0F0, 0x10, 19, 1),
+ PIN_FIELD_BASE(49, 49, 3, 0x0F0, 0x10, 14, 1),
+ PIN_FIELD_BASE(50, 50, 4, 0x0F0, 0x10, 11, 1),
+ PIN_FIELD_BASE(51, 51, 4, 0x0F0, 0x10, 6, 1),
+ PIN_FIELD_BASE(81, 81, 5, 0x0F0, 0x10, 8, 1),
+ PIN_FIELD_BASE(82, 82, 5, 0x0F0, 0x10, 6, 1),
+ PIN_FIELD_BASE(83, 83, 5, 0x0F0, 0x10, 16, 1),
+ PIN_FIELD_BASE(84, 84, 5, 0x0F0, 0x10, 18, 1),
+ PIN_FIELD_BASE(91, 91, 6, 0x0C0, 0x10, 1, 1),
+ PIN_FIELD_BASE(92, 92, 6, 0x0C0, 0x10, 5, 1),
+ PIN_FIELD_BASE(93, 93, 6, 0x0C0, 0x10, 9, 1),
+ PIN_FIELD_BASE(94, 94, 6, 0x0C0, 0x10, 13, 1),
+ PIN_FIELD_BASE(103, 103, 6, 0x0F0, 0x10, 21, 1),
+ PIN_FIELD_BASE(104, 104, 6, 0x0F0, 0x10, 11, 1),
+ PIN_FIELD_BASE(105, 105, 6, 0x0F0, 0x10, 23, 1),
+ PIN_FIELD_BASE(106, 106, 6, 0x0F0, 0x10, 13, 1),
+ PIN_FIELD_BASE(122, 122, 8, 0x0C0, 0x10, 1, 1),
+ PIN_FIELD_BASE(123, 123, 8, 0x0C0, 0x10, 5, 1),
+ PIN_FIELD_BASE(124, 124, 8, 0x0C0, 0x10, 9, 1),
+ PIN_FIELD_BASE(125, 125, 8, 0x0C0, 0x10, 13, 1),
+ PIN_FIELD_BASE(126, 126, 8, 0x0C0, 0x10, 17, 1),
+ PIN_FIELD_BASE(127, 127, 8, 0x0C0, 0x10, 21, 1),
+ PIN_FIELD_BASE(128, 128, 8, 0x0C0, 0x10, 25, 1),
+ PIN_FIELD_BASE(129, 129, 8, 0x0C0, 0x10, 29, 1),
+ PIN_FIELD_BASE(130, 130, 8, 0x0D0, 0x10, 1, 1),
+ PIN_FIELD_BASE(131, 131, 8, 0x0D0, 0x10, 5, 1),
+ PIN_FIELD_BASE(132, 132, 8, 0x0D0, 0x10, 9, 1),
+ PIN_FIELD_BASE(133, 133, 8, 0x0D0, 0x10, 13, 1),
+};
+
+static const struct mtk_pin_reg_calc mt8183_reg_cals[PINCTRL_PIN_REG_MAX] = {
+ [PINCTRL_PIN_REG_MODE] = MTK_RANGE(mt8183_pin_mode_range),
+ [PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt8183_pin_dir_range),
+ [PINCTRL_PIN_REG_DI] = MTK_RANGE(mt8183_pin_di_range),
+ [PINCTRL_PIN_REG_DO] = MTK_RANGE(mt8183_pin_do_range),
+ [PINCTRL_PIN_REG_SMT] = MTK_RANGE(mt8183_pin_smt_range),
+ [PINCTRL_PIN_REG_IES] = MTK_RANGE(mt8183_pin_ies_range),
+ [PINCTRL_PIN_REG_PULLEN] = MTK_RANGE(mt8183_pin_pullen_range),
+ [PINCTRL_PIN_REG_PULLSEL] = MTK_RANGE(mt8183_pin_pullsel_range),
+ [PINCTRL_PIN_REG_DRV] = MTK_RANGE(mt8183_pin_drv_range),
+ [PINCTRL_PIN_REG_PUPD] = MTK_RANGE(mt8183_pin_pupd_range),
+ [PINCTRL_PIN_REG_R0] = MTK_RANGE(mt8183_pin_r0_range),
+ [PINCTRL_PIN_REG_R1] = MTK_RANGE(mt8183_pin_r1_range),
+};
+
+static const char * const mt8183_pinctrl_register_base_names[] = {
+ "iocfg0", "iocfg1", "iocfg2", "iocfg3", "iocfg4", "iocfg5",
+ "iocfg6", "iocfg7", "iocfg8",
+};
+
+static const struct mtk_eint_hw mt8183_eint_hw = {
+ .port_mask = 7,
+ .ports = 6,
+ .ap_num = 212,
+ .db_cnt = 13,
+};
+
+static const struct mtk_pin_soc mt8183_data = {
+ .reg_cal = mt8183_reg_cals,
+ .pins = mtk_pins_mt8183,
+ .npins = ARRAY_SIZE(mtk_pins_mt8183),
+ .ngrps = ARRAY_SIZE(mtk_pins_mt8183),
+ .eint_hw = &mt8183_eint_hw,
+ .gpio_m = 0,
+ .ies_present = true,
+ .base_names = mt8183_pinctrl_register_base_names,
+ .nbase_names = ARRAY_SIZE(mt8183_pinctrl_register_base_names),
+ .bias_disable_set = mtk_pinconf_bias_disable_set_rev1,
+ .bias_disable_get = mtk_pinconf_bias_disable_get_rev1,
+ .bias_set = mtk_pinconf_bias_set_rev1,
+ .bias_get = mtk_pinconf_bias_get_rev1,
+ .drive_set = mtk_pinconf_drive_set_rev1,
+ .drive_get = mtk_pinconf_drive_get_rev1,
+ .adv_pull_get = mtk_pinconf_adv_pull_get,
+ .adv_pull_set = mtk_pinconf_adv_pull_set,
+};
+
+static const struct of_device_id mt8183_pinctrl_of_match[] = {
+ { .compatible = "mediatek,mt8183-pinctrl", },
+ { }
+};
+
+static int mt8183_pinctrl_probe(struct platform_device *pdev)
+{
+ return mtk_paris_pinctrl_probe(pdev, &mt8183_data);
+}
+
+static struct platform_driver mt8183_pinctrl_driver = {
+ .driver = {
+ .name = "mt8183-pinctrl",
+ .of_match_table = mt8183_pinctrl_of_match,
+ },
+ .probe = mt8183_pinctrl_probe,
+};
+
+static int __init mt8183_pinctrl_init(void)
+{
+ return platform_driver_register(&mt8183_pinctrl_driver);
+}
+arch_initcall(mt8183_pinctrl_init);
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
new file mode 100644
index 000000000000..4a9e0d4c2bbc
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
@@ -0,0 +1,670 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ *
+ * Author: Sean Wang <sean.wang@mediatek.com>
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio/driver.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/of_irq.h>
+
+#include "mtk-eint.h"
+#include "pinctrl-mtk-common-v2.h"
+
+/**
+ * struct mtk_drive_desc - the structure that holds the information
+ * of the driving current
+ * @min: the minimum current of this group
+ * @max: the maximum current of this group
+ * @step: the step current of this group
+ * @scal: the weight factor
+ *
+ * formula: output = ((input) / step - 1) * scal
+ */
+struct mtk_drive_desc {
+ u8 min;
+ u8 max;
+ u8 step;
+ u8 scal;
+};
+
+/* The groups of drive strength */
+static const struct mtk_drive_desc mtk_drive[] = {
+ [DRV_GRP0] = { 4, 16, 4, 1 },
+ [DRV_GRP1] = { 4, 16, 4, 2 },
+ [DRV_GRP2] = { 2, 8, 2, 1 },
+ [DRV_GRP3] = { 2, 8, 2, 2 },
+ [DRV_GRP4] = { 2, 16, 2, 1 },
+};
+
+static void mtk_w32(struct mtk_pinctrl *pctl, u8 i, u32 reg, u32 val)
+{
+ writel_relaxed(val, pctl->base[i] + reg);
+}
+
+static u32 mtk_r32(struct mtk_pinctrl *pctl, u8 i, u32 reg)
+{
+ return readl_relaxed(pctl->base[i] + reg);
+}
+
+void mtk_rmw(struct mtk_pinctrl *pctl, u8 i, u32 reg, u32 mask, u32 set)
+{
+ u32 val;
+
+ val = mtk_r32(pctl, i, reg);
+ val &= ~mask;
+ val |= set;
+ mtk_w32(pctl, i, reg, val);
+}
+
+static int mtk_hw_pin_field_lookup(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc,
+ int field, struct mtk_pin_field *pfd)
+{
+ const struct mtk_pin_field_calc *c, *e;
+ const struct mtk_pin_reg_calc *rc;
+ u32 bits;
+
+ if (hw->soc->reg_cal && hw->soc->reg_cal[field].range) {
+ rc = &hw->soc->reg_cal[field];
+ } else {
+ dev_dbg(hw->dev,
+ "Not support field %d for pin %d (%s)\n",
+ field, desc->number, desc->name);
+ return -ENOTSUPP;
+ }
+
+ c = rc->range;
+ e = c + rc->nranges;
+
+ while (c < e) {
+ if (desc->number >= c->s_pin && desc->number <= c->e_pin)
+ break;
+ c++;
+ }
+
+ if (c >= e) {
+ dev_dbg(hw->dev, "Not support field %d for pin = %d (%s)\n",
+ field, desc->number, desc->name);
+ return -ENOTSUPP;
+ }
+
+ if (c->i_base > hw->nbase - 1) {
+ dev_err(hw->dev,
+ "Invalid base for field %d for pin = %d (%s)\n",
+ field, desc->number, desc->name);
+ return -EINVAL;
+ }
+
+ /* Calculated bits as the overall offset the pin is located at,
+ * if c->fixed is held, that determines the all the pins in the
+ * range use the same field with the s_pin.
+ */
+ bits = c->fixed ? c->s_bit : c->s_bit +
+ (desc->number - c->s_pin) * (c->x_bits);
+
+ /* Fill pfd from bits. For example 32-bit register applied is assumed
+ * when c->sz_reg is equal to 32.
+ */
+ pfd->index = c->i_base;
+ pfd->offset = c->s_addr + c->x_addrs * (bits / c->sz_reg);
+ pfd->bitpos = bits % c->sz_reg;
+ pfd->mask = (1 << c->x_bits) - 1;
+
+ /* pfd->next is used for indicating that bit wrapping-around happens
+ * which requires the manipulation for bit 0 starting in the next
+ * register to form the complete field read/write.
+ */
+ pfd->next = pfd->bitpos + c->x_bits > c->sz_reg ? c->x_addrs : 0;
+
+ return 0;
+}
+
+static int mtk_hw_pin_field_get(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc,
+ int field, struct mtk_pin_field *pfd)
+{
+ if (field < 0 || field >= PINCTRL_PIN_REG_MAX) {
+ dev_err(hw->dev, "Invalid Field %d\n", field);
+ return -EINVAL;
+ }
+
+ return mtk_hw_pin_field_lookup(hw, desc, field, pfd);
+}
+
+static void mtk_hw_bits_part(struct mtk_pin_field *pf, int *h, int *l)
+{
+ *l = 32 - pf->bitpos;
+ *h = get_count_order(pf->mask) - *l;
+}
+
+static void mtk_hw_write_cross_field(struct mtk_pinctrl *hw,
+ struct mtk_pin_field *pf, int value)
+{
+ int nbits_l, nbits_h;
+
+ mtk_hw_bits_part(pf, &nbits_h, &nbits_l);
+
+ mtk_rmw(hw, pf->index, pf->offset, pf->mask << pf->bitpos,
+ (value & pf->mask) << pf->bitpos);
+
+ mtk_rmw(hw, pf->index, pf->offset + pf->next, BIT(nbits_h) - 1,
+ (value & pf->mask) >> nbits_l);
+}
+
+static void mtk_hw_read_cross_field(struct mtk_pinctrl *hw,
+ struct mtk_pin_field *pf, int *value)
+{
+ int nbits_l, nbits_h, h, l;
+
+ mtk_hw_bits_part(pf, &nbits_h, &nbits_l);
+
+ l = (mtk_r32(hw, pf->index, pf->offset)
+ >> pf->bitpos) & (BIT(nbits_l) - 1);
+ h = (mtk_r32(hw, pf->index, pf->offset + pf->next))
+ & (BIT(nbits_h) - 1);
+
+ *value = (h << nbits_l) | l;
+}
+
+int mtk_hw_set_value(struct mtk_pinctrl *hw, const struct mtk_pin_desc *desc,
+ int field, int value)
+{
+ struct mtk_pin_field pf;
+ int err;
+
+ err = mtk_hw_pin_field_get(hw, desc, field, &pf);
+ if (err)
+ return err;
+
+ if (!pf.next)
+ mtk_rmw(hw, pf.index, pf.offset, pf.mask << pf.bitpos,
+ (value & pf.mask) << pf.bitpos);
+ else
+ mtk_hw_write_cross_field(hw, &pf, value);
+
+ return 0;
+}
+
+int mtk_hw_get_value(struct mtk_pinctrl *hw, const struct mtk_pin_desc *desc,
+ int field, int *value)
+{
+ struct mtk_pin_field pf;
+ int err;
+
+ err = mtk_hw_pin_field_get(hw, desc, field, &pf);
+ if (err)
+ return err;
+
+ if (!pf.next)
+ *value = (mtk_r32(hw, pf.index, pf.offset)
+ >> pf.bitpos) & pf.mask;
+ else
+ mtk_hw_read_cross_field(hw, &pf, value);
+
+ return 0;
+}
+
+static int mtk_xt_find_eint_num(struct mtk_pinctrl *hw, unsigned long eint_n)
+{
+ const struct mtk_pin_desc *desc;
+ int i = 0;
+
+ desc = (const struct mtk_pin_desc *)hw->soc->pins;
+
+ while (i < hw->soc->npins) {
+ if (desc[i].eint.eint_n == eint_n)
+ return desc[i].number;
+ i++;
+ }
+
+ return EINT_NA;
+}
+
+static int mtk_xt_get_gpio_n(void *data, unsigned long eint_n,
+ unsigned int *gpio_n,
+ struct gpio_chip **gpio_chip)
+{
+ struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data;
+ const struct mtk_pin_desc *desc;
+
+ desc = (const struct mtk_pin_desc *)hw->soc->pins;
+ *gpio_chip = &hw->chip;
+
+ /* Be greedy to guess first gpio_n is equal to eint_n */
+ if (desc[eint_n].eint.eint_n == eint_n)
+ *gpio_n = eint_n;
+ else
+ *gpio_n = mtk_xt_find_eint_num(hw, eint_n);
+
+ return *gpio_n == EINT_NA ? -EINVAL : 0;
+}
+
+static int mtk_xt_get_gpio_state(void *data, unsigned long eint_n)
+{
+ struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data;
+ const struct mtk_pin_desc *desc;
+ struct gpio_chip *gpio_chip;
+ unsigned int gpio_n;
+ int value, err;
+
+ err = mtk_xt_get_gpio_n(hw, eint_n, &gpio_n, &gpio_chip);
+ if (err)
+ return err;
+
+ desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio_n];
+
+ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DI, &value);
+ if (err)
+ return err;
+
+ return !!value;
+}
+
+static int mtk_xt_set_gpio_as_eint(void *data, unsigned long eint_n)
+{
+ struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data;
+ const struct mtk_pin_desc *desc;
+ struct gpio_chip *gpio_chip;
+ unsigned int gpio_n;
+ int err;
+
+ err = mtk_xt_get_gpio_n(hw, eint_n, &gpio_n, &gpio_chip);
+ if (err)
+ return err;
+
+ desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio_n];
+
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_MODE,
+ desc->eint.eint_m);
+ if (err)
+ return err;
+
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, MTK_INPUT);
+ if (err)
+ return err;
+
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_SMT, MTK_ENABLE);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static const struct mtk_eint_xt mtk_eint_xt = {
+ .get_gpio_n = mtk_xt_get_gpio_n,
+ .get_gpio_state = mtk_xt_get_gpio_state,
+ .set_gpio_as_eint = mtk_xt_set_gpio_as_eint,
+};
+
+int mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct resource *res;
+
+ if (!IS_ENABLED(CONFIG_EINT_MTK))
+ return 0;
+
+ if (!of_property_read_bool(np, "interrupt-controller"))
+ return -ENODEV;
+
+ hw->eint = devm_kzalloc(hw->dev, sizeof(*hw->eint), GFP_KERNEL);
+ if (!hw->eint)
+ return -ENOMEM;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "eint");
+ if (!res) {
+ dev_err(&pdev->dev, "Unable to get eint resource\n");
+ return -ENODEV;
+ }
+
+ hw->eint->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(hw->eint->base))
+ return PTR_ERR(hw->eint->base);
+
+ hw->eint->irq = irq_of_parse_and_map(np, 0);
+ if (!hw->eint->irq)
+ return -EINVAL;
+
+ if (!hw->soc->eint_hw)
+ return -ENODEV;
+
+ hw->eint->dev = &pdev->dev;
+ hw->eint->hw = hw->soc->eint_hw;
+ hw->eint->pctl = hw;
+ hw->eint->gpio_xlate = &mtk_eint_xt;
+
+ return mtk_eint_do_init(hw->eint);
+}
+
+/* Revision 0 */
+int mtk_pinconf_bias_disable_set(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc)
+{
+ int err;
+
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PU,
+ MTK_DISABLE);
+ if (err)
+ return err;
+
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PD,
+ MTK_DISABLE);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+int mtk_pinconf_bias_disable_get(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc, int *res)
+{
+ int v, v2;
+ int err;
+
+ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PU, &v);
+ if (err)
+ return err;
+
+ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PD, &v2);
+ if (err)
+ return err;
+
+ if (v == MTK_ENABLE || v2 == MTK_ENABLE)
+ return -EINVAL;
+
+ *res = 1;
+
+ return 0;
+}
+
+int mtk_pinconf_bias_set(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc, bool pullup)
+{
+ int err, arg;
+
+ arg = pullup ? 1 : 2;
+
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PU, arg & 1);
+ if (err)
+ return err;
+
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PD,
+ !!(arg & 2));
+ if (err)
+ return err;
+
+ return 0;
+}
+
+int mtk_pinconf_bias_get(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc, bool pullup, int *res)
+{
+ int reg, err, v;
+
+ reg = pullup ? PINCTRL_PIN_REG_PU : PINCTRL_PIN_REG_PD;
+
+ err = mtk_hw_get_value(hw, desc, reg, &v);
+ if (err)
+ return err;
+
+ if (!v)
+ return -EINVAL;
+
+ *res = 1;
+
+ return 0;
+}
+
+/* Revision 1 */
+int mtk_pinconf_bias_disable_set_rev1(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc)
+{
+ int err;
+
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PULLEN,
+ MTK_DISABLE);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+int mtk_pinconf_bias_disable_get_rev1(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc, int *res)
+{
+ int v, err;
+
+ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PULLEN, &v);
+ if (err)
+ return err;
+
+ if (v == MTK_ENABLE)
+ return -EINVAL;
+
+ *res = 1;
+
+ return 0;
+}
+
+int mtk_pinconf_bias_set_rev1(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc, bool pullup)
+{
+ int err, arg;
+
+ arg = pullup ? MTK_PULLUP : MTK_PULLDOWN;
+
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PULLEN,
+ MTK_ENABLE);
+ if (err)
+ return err;
+
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PULLSEL, arg);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+int mtk_pinconf_bias_get_rev1(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc, bool pullup,
+ int *res)
+{
+ int err, v;
+
+ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PULLEN, &v);
+ if (err)
+ return err;
+
+ if (v == MTK_DISABLE)
+ return -EINVAL;
+
+ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PULLSEL, &v);
+ if (err)
+ return err;
+
+ if (pullup ^ (v == MTK_PULLUP))
+ return -EINVAL;
+
+ *res = 1;
+
+ return 0;
+}
+
+/* Revision 0 */
+int mtk_pinconf_drive_set(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc, u32 arg)
+{
+ const struct mtk_drive_desc *tb;
+ int err = -ENOTSUPP;
+
+ tb = &mtk_drive[desc->drv_n];
+ /* 4mA when (e8, e4) = (0, 0)
+ * 8mA when (e8, e4) = (0, 1)
+ * 12mA when (e8, e4) = (1, 0)
+ * 16mA when (e8, e4) = (1, 1)
+ */
+ if ((arg >= tb->min && arg <= tb->max) && !(arg % tb->step)) {
+ arg = (arg / tb->step - 1) * tb->scal;
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_E4,
+ arg & 0x1);
+ if (err)
+ return err;
+
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_E8,
+ (arg & 0x2) >> 1);
+ if (err)
+ return err;
+ }
+
+ return err;
+}
+
+int mtk_pinconf_drive_get(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc, int *val)
+{
+ const struct mtk_drive_desc *tb;
+ int err, val1, val2;
+
+ tb = &mtk_drive[desc->drv_n];
+
+ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_E4, &val1);
+ if (err)
+ return err;
+
+ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_E8, &val2);
+ if (err)
+ return err;
+
+ /* 4mA when (e8, e4) = (0, 0); 8mA when (e8, e4) = (0, 1)
+ * 12mA when (e8, e4) = (1, 0); 16mA when (e8, e4) = (1, 1)
+ */
+ *val = (((val2 << 1) + val1) / tb->scal + 1) * tb->step;
+
+ return 0;
+}
+
+/* Revision 1 */
+int mtk_pinconf_drive_set_rev1(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc, u32 arg)
+{
+ const struct mtk_drive_desc *tb;
+ int err = -ENOTSUPP;
+
+ tb = &mtk_drive[desc->drv_n];
+
+ if ((arg >= tb->min && arg <= tb->max) && !(arg % tb->step)) {
+ arg = (arg / tb->step - 1) * tb->scal;
+
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DRV,
+ arg);
+ if (err)
+ return err;
+ }
+
+ return err;
+}
+
+int mtk_pinconf_drive_get_rev1(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc, int *val)
+{
+ const struct mtk_drive_desc *tb;
+ int err, val1;
+
+ tb = &mtk_drive[desc->drv_n];
+
+ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DRV, &val1);
+ if (err)
+ return err;
+
+ *val = ((val1 & 0x7) / tb->scal + 1) * tb->step;
+
+ return 0;
+}
+
+int mtk_pinconf_adv_pull_set(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc, bool pullup,
+ u32 arg)
+{
+ int err;
+
+ /* 10K off & 50K (75K) off, when (R0, R1) = (0, 0);
+ * 10K off & 50K (75K) on, when (R0, R1) = (0, 1);
+ * 10K on & 50K (75K) off, when (R0, R1) = (1, 0);
+ * 10K on & 50K (75K) on, when (R0, R1) = (1, 1)
+ */
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_R0, arg & 1);
+ if (err)
+ return 0;
+
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_R1,
+ !!(arg & 2));
+ if (err)
+ return 0;
+
+ arg = pullup ? 0 : 1;
+
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PUPD, arg);
+
+ /* If PUPD register is not supported for that pin, let's fallback to
+ * general bias control.
+ */
+ if (err == -ENOTSUPP) {
+ if (hw->soc->bias_set) {
+ err = hw->soc->bias_set(hw, desc, pullup);
+ if (err)
+ return err;
+ } else {
+ return -ENOTSUPP;
+ }
+ }
+
+ return err;
+}
+
+int mtk_pinconf_adv_pull_get(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc, bool pullup,
+ u32 *val)
+{
+ u32 t, t2;
+ int err;
+
+ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PUPD, &t);
+
+ /* If PUPD register is not supported for that pin, let's fallback to
+ * general bias control.
+ */
+ if (err == -ENOTSUPP) {
+ if (hw->soc->bias_get) {
+ err = hw->soc->bias_get(hw, desc, pullup, val);
+ if (err)
+ return err;
+ } else {
+ return -ENOTSUPP;
+ }
+ } else {
+ /* t == 0 supposes PULLUP for the customized PULL setup */
+ if (err)
+ return err;
+
+ if (pullup ^ !t)
+ return -EINVAL;
+ }
+
+ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_R0, &t);
+ if (err)
+ return err;
+
+ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_R1, &t2);
+ if (err)
+ return err;
+
+ *val = (t | t2 << 1) & 0x7;
+
+ return 0;
+}
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h
new file mode 100644
index 000000000000..6d24522739d9
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h
@@ -0,0 +1,291 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ *
+ * Author: Sean Wang <sean.wang@mediatek.com>
+ *
+ */
+
+#ifndef __PINCTRL_MTK_COMMON_V2_H
+#define __PINCTRL_MTK_COMMON_V2_H
+
+#include <linux/gpio/driver.h>
+
+#define MTK_INPUT 0
+#define MTK_OUTPUT 1
+#define MTK_DISABLE 0
+#define MTK_ENABLE 1
+#define MTK_PULLDOWN 0
+#define MTK_PULLUP 1
+
+#define EINT_NA U16_MAX
+#define NO_EINT_SUPPORT EINT_NA
+
+#define PIN_FIELD_CALC(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, \
+ _s_bit, _x_bits, _sz_reg, _fixed) { \
+ .s_pin = _s_pin, \
+ .e_pin = _e_pin, \
+ .i_base = _i_base, \
+ .s_addr = _s_addr, \
+ .x_addrs = _x_addrs, \
+ .s_bit = _s_bit, \
+ .x_bits = _x_bits, \
+ .sz_reg = _sz_reg, \
+ .fixed = _fixed, \
+ }
+
+#define PIN_FIELD(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit, _x_bits) \
+ PIN_FIELD_CALC(_s_pin, _e_pin, 0, _s_addr, _x_addrs, _s_bit, \
+ _x_bits, 32, 0)
+
+#define PINS_FIELD(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit, _x_bits) \
+ PIN_FIELD_CALC(_s_pin, _e_pin, 0, _s_addr, _x_addrs, _s_bit, \
+ _x_bits, 32, 1)
+
+/* List these attributes which could be modified for the pin */
+enum {
+ PINCTRL_PIN_REG_MODE,
+ PINCTRL_PIN_REG_DIR,
+ PINCTRL_PIN_REG_DI,
+ PINCTRL_PIN_REG_DO,
+ PINCTRL_PIN_REG_SR,
+ PINCTRL_PIN_REG_SMT,
+ PINCTRL_PIN_REG_PD,
+ PINCTRL_PIN_REG_PU,
+ PINCTRL_PIN_REG_E4,
+ PINCTRL_PIN_REG_E8,
+ PINCTRL_PIN_REG_TDSEL,
+ PINCTRL_PIN_REG_RDSEL,
+ PINCTRL_PIN_REG_DRV,
+ PINCTRL_PIN_REG_PUPD,
+ PINCTRL_PIN_REG_R0,
+ PINCTRL_PIN_REG_R1,
+ PINCTRL_PIN_REG_IES,
+ PINCTRL_PIN_REG_PULLEN,
+ PINCTRL_PIN_REG_PULLSEL,
+ PINCTRL_PIN_REG_MAX,
+};
+
+/* Group the pins by the driving current */
+enum {
+ DRV_FIXED,
+ DRV_GRP0,
+ DRV_GRP1,
+ DRV_GRP2,
+ DRV_GRP3,
+ DRV_GRP4,
+ DRV_GRP_MAX,
+};
+
+static const char * const mtk_default_register_base_names[] = {
+ "base",
+};
+
+/* struct mtk_pin_field - the structure that holds the information of the field
+ * used to describe the attribute for the pin
+ * @base: the index pointing to the entry in base address list
+ * @offset: the register offset relative to the base address
+ * @mask: the mask used to filter out the field from the register
+ * @bitpos: the start bit relative to the register
+ * @next: the indication that the field would be extended to the
+ next register
+ */
+struct mtk_pin_field {
+ u8 index;
+ u32 offset;
+ u32 mask;
+ u8 bitpos;
+ u8 next;
+};
+
+/* struct mtk_pin_field_calc - the structure that holds the range providing
+ * the guide used to look up the relevant field
+ * @s_pin: the start pin within the range
+ * @e_pin: the end pin within the range
+ * @i_base: the index pointing to the entry in base address list
+ * @s_addr: the start address for the range
+ * @x_addrs: the address distance between two consecutive registers
+ * within the range
+ * @s_bit: the start bit for the first register within the range
+ * @x_bits: the bit distance between two consecutive pins within
+ * the range
+ * @sz_reg: the size of bits in a register
+ * @fixed: the consecutive pins share the same bits with the 1st
+ * pin
+ */
+struct mtk_pin_field_calc {
+ u16 s_pin;
+ u16 e_pin;
+ u8 i_base;
+ u32 s_addr;
+ u8 x_addrs;
+ u8 s_bit;
+ u8 x_bits;
+ u8 sz_reg;
+ u8 fixed;
+};
+
+/* struct mtk_pin_reg_calc - the structure that holds all ranges used to
+ * determine which register the pin would make use of
+ * for certain pin attribute.
+ * @range: the start address for the range
+ * @nranges: the number of items in the range
+ */
+struct mtk_pin_reg_calc {
+ const struct mtk_pin_field_calc *range;
+ unsigned int nranges;
+};
+
+/**
+ * struct mtk_func_desc - the structure that providing information
+ * all the funcs for this pin
+ * @name: the name of function
+ * @muxval: the mux to the function
+ */
+struct mtk_func_desc {
+ const char *name;
+ u8 muxval;
+};
+
+/**
+ * struct mtk_eint_desc - the structure that providing information
+ * for eint data per pin
+ * @eint_m: the eint mux for this pin
+ * @eitn_n: the eint number for this pin
+ */
+struct mtk_eint_desc {
+ u16 eint_m;
+ u16 eint_n;
+};
+
+/**
+ * struct mtk_pin_desc - the structure that providing information
+ * for each pin of chips
+ * @number: unique pin number from the global pin number space
+ * @name: name for this pin
+ * @eint: the eint data for this pin
+ * @drv_n: the index with the driving group
+ * @funcs: all available functions for this pins (only used in
+ * those drivers compatible to pinctrl-mtk-common.c-like
+ * ones)
+ */
+struct mtk_pin_desc {
+ unsigned int number;
+ const char *name;
+ struct mtk_eint_desc eint;
+ u8 drv_n;
+ struct mtk_func_desc *funcs;
+};
+
+struct mtk_pinctrl_group {
+ const char *name;
+ unsigned long config;
+ unsigned pin;
+};
+
+struct mtk_pinctrl;
+
+/* struct mtk_pin_soc - the structure that holds SoC-specific data */
+struct mtk_pin_soc {
+ const struct mtk_pin_reg_calc *reg_cal;
+ const struct mtk_pin_desc *pins;
+ unsigned int npins;
+ const struct group_desc *grps;
+ unsigned int ngrps;
+ const struct function_desc *funcs;
+ unsigned int nfuncs;
+ const struct mtk_eint_regs *eint_regs;
+ const struct mtk_eint_hw *eint_hw;
+
+ /* Specific parameters per SoC */
+ u8 gpio_m;
+ bool ies_present;
+ const char * const *base_names;
+ unsigned int nbase_names;
+
+ /* Specific pinconfig operations */
+ int (*bias_disable_set)(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc);
+ int (*bias_disable_get)(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc, int *res);
+ int (*bias_set)(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc, bool pullup);
+ int (*bias_get)(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc, bool pullup, int *res);
+
+ int (*drive_set)(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc, u32 arg);
+ int (*drive_get)(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc, int *val);
+
+ int (*adv_pull_set)(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc, bool pullup,
+ u32 arg);
+ int (*adv_pull_get)(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc, bool pullup,
+ u32 *val);
+
+ /* Specific driver data */
+ void *driver_data;
+};
+
+struct mtk_pinctrl {
+ struct pinctrl_dev *pctrl;
+ void __iomem **base;
+ u8 nbase;
+ struct device *dev;
+ struct gpio_chip chip;
+ const struct mtk_pin_soc *soc;
+ struct mtk_eint *eint;
+ struct mtk_pinctrl_group *groups;
+ const char **grp_names;
+};
+
+void mtk_rmw(struct mtk_pinctrl *pctl, u8 i, u32 reg, u32 mask, u32 set);
+
+int mtk_hw_set_value(struct mtk_pinctrl *hw, const struct mtk_pin_desc *desc,
+ int field, int value);
+int mtk_hw_get_value(struct mtk_pinctrl *hw, const struct mtk_pin_desc *desc,
+ int field, int *value);
+
+int mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev);
+
+int mtk_pinconf_bias_disable_set(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc);
+int mtk_pinconf_bias_disable_get(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc, int *res);
+int mtk_pinconf_bias_set(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc, bool pullup);
+int mtk_pinconf_bias_get(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc, bool pullup,
+ int *res);
+
+int mtk_pinconf_bias_disable_set_rev1(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc);
+int mtk_pinconf_bias_disable_get_rev1(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc,
+ int *res);
+int mtk_pinconf_bias_set_rev1(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc, bool pullup);
+int mtk_pinconf_bias_get_rev1(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc, bool pullup,
+ int *res);
+
+int mtk_pinconf_drive_set(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc, u32 arg);
+int mtk_pinconf_drive_get(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc, int *val);
+
+int mtk_pinconf_drive_set_rev1(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc, u32 arg);
+int mtk_pinconf_drive_get_rev1(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc, int *val);
+
+int mtk_pinconf_adv_pull_set(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc, bool pullup,
+ u32 arg);
+int mtk_pinconf_adv_pull_get(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc, bool pullup,
+ u32 *val);
+
+#endif /* __PINCTRL_MTK_COMMON_V2_H */
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
index 16ff56f93501..071623873ca5 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
@@ -514,8 +514,8 @@ static int mtk_pctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
pins = of_find_property(node, "pinmux", NULL);
if (!pins) {
- dev_err(pctl->dev, "missing pins property in node %s .\n",
- node->name);
+ dev_err(pctl->dev, "missing pins property in node %pOFn .\n",
+ node);
return -EINVAL;
}
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-mt6765.h b/drivers/pinctrl/mediatek/pinctrl-mtk-mt6765.h
new file mode 100644
index 000000000000..772563720461
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-mt6765.h
@@ -0,0 +1,1754 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ *
+ * Author: ZH Chen <zh.chen@mediatek.com>
+ *
+ */
+
+#ifndef __PINCTRL_MTK_MT6765_H
+#define __PINCTRL_MTK_MT6765_H
+
+#include "pinctrl-paris.h"
+
+static struct mtk_pin_desc mtk_pins_mt6765[] = {
+ MTK_PIN(
+ 0, "GPIO0",
+ MTK_EINT_FUNCTION(0, 0),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO0"),
+ MTK_FUNCTION(1, "UTXD1"),
+ MTK_FUNCTION(2, "CLKM0"),
+ MTK_FUNCTION(3, "MD_INT0"),
+ MTK_FUNCTION(4, "I2S0_MCK"),
+ MTK_FUNCTION(5, "MD_UTXD1"),
+ MTK_FUNCTION(6, "TP_GPIO0_AO"),
+ MTK_FUNCTION(7, "DBG_MON_B9")
+ ),
+ MTK_PIN(
+ 1, "GPIO1",
+ MTK_EINT_FUNCTION(0, 1),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO1"),
+ MTK_FUNCTION(1, "URXD1"),
+ MTK_FUNCTION(2, "CLKM1"),
+ MTK_FUNCTION(4, "I2S0_BCK"),
+ MTK_FUNCTION(5, "MD_URXD1"),
+ MTK_FUNCTION(6, "TP_GPIO1_AO"),
+ MTK_FUNCTION(7, "DBG_MON_B10")
+ ),
+ MTK_PIN(
+ 2, "GPIO2",
+ MTK_EINT_FUNCTION(0, 2),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO2"),
+ MTK_FUNCTION(1, "UCTS0"),
+ MTK_FUNCTION(2, "CLKM2"),
+ MTK_FUNCTION(3, "UTXD1"),
+ MTK_FUNCTION(4, "I2S0_LRCK"),
+ MTK_FUNCTION(5, "ANT_SEL6"),
+ MTK_FUNCTION(6, "TP_GPIO2_AO"),
+ MTK_FUNCTION(7, "DBG_MON_B11")
+ ),
+ MTK_PIN(
+ 3, "GPIO3",
+ MTK_EINT_FUNCTION(0, 3),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO3"),
+ MTK_FUNCTION(1, "URTS0"),
+ MTK_FUNCTION(2, "CLKM3"),
+ MTK_FUNCTION(3, "URXD1"),
+ MTK_FUNCTION(4, "I2S0_DI"),
+ MTK_FUNCTION(5, "ANT_SEL7"),
+ MTK_FUNCTION(6, "TP_GPIO3_AO"),
+ MTK_FUNCTION(7, "DBG_MON_B12")
+ ),
+ MTK_PIN(
+ 4, "GPIO4",
+ MTK_EINT_FUNCTION(0, 4),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO4"),
+ MTK_FUNCTION(1, "SPI1_B_MI"),
+ MTK_FUNCTION(2, "SCP_SPI1_MI"),
+ MTK_FUNCTION(3, "UCTS0"),
+ MTK_FUNCTION(4, "I2S3_MCK"),
+ MTK_FUNCTION(5, "SSPM_URXD_AO"),
+ MTK_FUNCTION(6, "TP_GPIO4_AO")
+ ),
+ MTK_PIN(
+ 5, "GPIO5",
+ MTK_EINT_FUNCTION(0, 5),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO5"),
+ MTK_FUNCTION(1, "SPI1_B_CSB"),
+ MTK_FUNCTION(2, "SCP_SPI1_CS"),
+ MTK_FUNCTION(3, "URTS0"),
+ MTK_FUNCTION(4, "I2S3_BCK"),
+ MTK_FUNCTION(5, "SSPM_UTXD_AO"),
+ MTK_FUNCTION(6, "TP_GPIO5_AO")
+ ),
+ MTK_PIN(
+ 6, "GPIO6",
+ MTK_EINT_FUNCTION(0, 6),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO6"),
+ MTK_FUNCTION(1, "SPI1_B_MO"),
+ MTK_FUNCTION(2, "SCP_SPI1_MO"),
+ MTK_FUNCTION(3, "PWM0"),
+ MTK_FUNCTION(4, "I2S3_LRCK"),
+ MTK_FUNCTION(5, "MD_UTXD0"),
+ MTK_FUNCTION(6, "TP_GPIO6_AO")
+ ),
+ MTK_PIN(
+ 7, "GPIO7",
+ MTK_EINT_FUNCTION(0, 7),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO7"),
+ MTK_FUNCTION(1, "SPI1_B_CLK"),
+ MTK_FUNCTION(2, "SCP_SPI1_CK"),
+ MTK_FUNCTION(3, "PWM1"),
+ MTK_FUNCTION(4, "I2S3_DO"),
+ MTK_FUNCTION(5, "MD_URXD0"),
+ MTK_FUNCTION(6, "TP_GPIO7_AO")
+ ),
+ MTK_PIN(
+ 8, "GPIO8",
+ MTK_EINT_FUNCTION(0, 8),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO8"),
+ MTK_FUNCTION(1, "UTXD1"),
+ MTK_FUNCTION(2, "SRCLKENAI0"),
+ MTK_FUNCTION(3, "MD_INT1_C2K_UIM0_HOT_PLUG"),
+ MTK_FUNCTION(4, "ANT_SEL3"),
+ MTK_FUNCTION(5, "MFG_JTAG_TRSTN"),
+ MTK_FUNCTION(6, "I2S2_MCK"),
+ MTK_FUNCTION(7, "JTRSTN_SEL1")
+ ),
+ MTK_PIN(
+ 9, "GPIO9",
+ MTK_EINT_FUNCTION(0, 9),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO9"),
+ MTK_FUNCTION(1, "MD_INT0"),
+ MTK_FUNCTION(2, "CMMCLK2"),
+ MTK_FUNCTION(3, "CONN_MCU_TRST_B"),
+ MTK_FUNCTION(4, "IDDIG"),
+ MTK_FUNCTION(5, "SDA_6306"),
+ MTK_FUNCTION(6, "MCUPM_JTAG_TRSTN"),
+ MTK_FUNCTION(7, "DBG_MON_B22")
+ ),
+ MTK_PIN(
+ 10, "GPIO10",
+ MTK_EINT_FUNCTION(0, 10),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO10"),
+ MTK_FUNCTION(1, "MD_INT1_C2K_UIM0_HOT_PLUG"),
+ MTK_FUNCTION(3, "CONN_MCU_DBGI_N"),
+ MTK_FUNCTION(4, "SRCLKENAI1"),
+ MTK_FUNCTION(5, "EXT_FRAME_SYNC"),
+ MTK_FUNCTION(6, "CMVREF1"),
+ MTK_FUNCTION(7, "DBG_MON_B23")
+ ),
+ MTK_PIN(
+ 11, "GPIO11",
+ MTK_EINT_FUNCTION(0, 11),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO11"),
+ MTK_FUNCTION(1, "MD_INT2_C2K_UIM1_HOT_PLUG"),
+ MTK_FUNCTION(2, "CLKM3"),
+ MTK_FUNCTION(3, "ANT_SEL6"),
+ MTK_FUNCTION(4, "SRCLKENAI0"),
+ MTK_FUNCTION(5, "EXT_FRAME_SYNC"),
+ MTK_FUNCTION(6, "UCTS1"),
+ MTK_FUNCTION(7, "DBG_MON_B24")
+ ),
+ MTK_PIN(
+ 12, "GPIO12",
+ MTK_EINT_FUNCTION(0, 12),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO12"),
+ MTK_FUNCTION(1, "PWM0"),
+ MTK_FUNCTION(2, "SRCLKENAI1"),
+ MTK_FUNCTION(3, "EXT_FRAME_SYNC"),
+ MTK_FUNCTION(4, "MD_INT0"),
+ MTK_FUNCTION(5, "DVFSRC_EXT_REQ"),
+ MTK_FUNCTION(6, "URTS1")
+ ),
+ MTK_PIN(
+ 13, "GPIO13",
+ MTK_EINT_FUNCTION(0, 13),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO13"),
+ MTK_FUNCTION(1, "ANT_SEL0"),
+ MTK_FUNCTION(2, "SPI4_MI"),
+ MTK_FUNCTION(3, "SCP_SPI0_MI"),
+ MTK_FUNCTION(4, "MD_URXD0"),
+ MTK_FUNCTION(5, "CLKM0"),
+ MTK_FUNCTION(6, "I2S0_MCK"),
+ MTK_FUNCTION(7, "DBG_MON_A0")
+ ),
+ MTK_PIN(
+ 14, "GPIO14",
+ MTK_EINT_FUNCTION(0, 14),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO14"),
+ MTK_FUNCTION(1, "ANT_SEL1"),
+ MTK_FUNCTION(2, "SPI4_CSB"),
+ MTK_FUNCTION(3, "SCP_SPI0_CS"),
+ MTK_FUNCTION(4, "MD_UTXD0"),
+ MTK_FUNCTION(5, "CLKM1"),
+ MTK_FUNCTION(6, "I2S0_BCK"),
+ MTK_FUNCTION(7, "DBG_MON_A1")
+ ),
+ MTK_PIN(
+ 15, "GPIO15",
+ MTK_EINT_FUNCTION(0, 15),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO15"),
+ MTK_FUNCTION(1, "ANT_SEL2"),
+ MTK_FUNCTION(2, "SPI4_MO"),
+ MTK_FUNCTION(3, "SCP_SPI0_MO"),
+ MTK_FUNCTION(4, "MD_URXD1"),
+ MTK_FUNCTION(5, "CLKM2"),
+ MTK_FUNCTION(6, "I2S0_LRCK"),
+ MTK_FUNCTION(7, "DBG_MON_A2")
+ ),
+ MTK_PIN(
+ 16, "GPIO16",
+ MTK_EINT_FUNCTION(0, 16),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO16"),
+ MTK_FUNCTION(1, "ANT_SEL3"),
+ MTK_FUNCTION(2, "SPI4_CLK"),
+ MTK_FUNCTION(3, "SCP_SPI0_CK"),
+ MTK_FUNCTION(4, "MD_UTXD1"),
+ MTK_FUNCTION(5, "CLKM3"),
+ MTK_FUNCTION(6, "I2S3_MCK"),
+ MTK_FUNCTION(7, "DBG_MON_A3")
+ ),
+ MTK_PIN(
+ 17, "GPIO17",
+ MTK_EINT_FUNCTION(0, 17),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO17"),
+ MTK_FUNCTION(1, "ANT_SEL4"),
+ MTK_FUNCTION(2, "SPI2_MO"),
+ MTK_FUNCTION(3, "SCP_SPI0_MO"),
+ MTK_FUNCTION(4, "PWM1"),
+ MTK_FUNCTION(5, "IDDIG"),
+ MTK_FUNCTION(6, "I2S0_DI"),
+ MTK_FUNCTION(7, "DBG_MON_A4")
+ ),
+ MTK_PIN(
+ 18, "GPIO18",
+ MTK_EINT_FUNCTION(0, 18),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO18"),
+ MTK_FUNCTION(1, "ANT_SEL5"),
+ MTK_FUNCTION(2, "SPI2_CLK"),
+ MTK_FUNCTION(3, "SCP_SPI0_CK"),
+ MTK_FUNCTION(4, "MD_INT0"),
+ MTK_FUNCTION(5, "USB_DRVVBUS"),
+ MTK_FUNCTION(6, "I2S3_BCK"),
+ MTK_FUNCTION(7, "DBG_MON_A5")
+ ),
+ MTK_PIN(
+ 19, "GPIO19",
+ MTK_EINT_FUNCTION(0, 19),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO19"),
+ MTK_FUNCTION(1, "ANT_SEL6"),
+ MTK_FUNCTION(2, "SPI2_MI"),
+ MTK_FUNCTION(3, "SCP_SPI0_MI"),
+ MTK_FUNCTION(4, "MD_INT2_C2K_UIM1_HOT_PLUG"),
+ MTK_FUNCTION(6, "I2S3_LRCK"),
+ MTK_FUNCTION(7, "DBG_MON_A6")
+ ),
+ MTK_PIN(
+ 20, "GPIO20",
+ MTK_EINT_FUNCTION(0, 20),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO20"),
+ MTK_FUNCTION(1, "ANT_SEL7"),
+ MTK_FUNCTION(2, "SPI2_CSB"),
+ MTK_FUNCTION(3, "SCP_SPI0_CS"),
+ MTK_FUNCTION(4, "MD_INT1_C2K_UIM0_HOT_PLUG"),
+ MTK_FUNCTION(5, "CMMCLK3"),
+ MTK_FUNCTION(6, "I2S3_DO"),
+ MTK_FUNCTION(7, "DBG_MON_A7")
+ ),
+ MTK_PIN(
+ 21, "GPIO21",
+ MTK_EINT_FUNCTION(0, 21),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO21"),
+ MTK_FUNCTION(1, "SPI3_MI"),
+ MTK_FUNCTION(2, "SRCLKENAI1"),
+ MTK_FUNCTION(3, "DAP_MD32_SWD"),
+ MTK_FUNCTION(4, "CMVREF0"),
+ MTK_FUNCTION(5, "SCP_SPI0_MI"),
+ MTK_FUNCTION(6, "I2S2_MCK"),
+ MTK_FUNCTION(7, "DBG_MON_A8")
+ ),
+ MTK_PIN(
+ 22, "GPIO22",
+ MTK_EINT_FUNCTION(0, 22),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO22"),
+ MTK_FUNCTION(1, "SPI3_CSB"),
+ MTK_FUNCTION(2, "SRCLKENAI0"),
+ MTK_FUNCTION(3, "DAP_MD32_SWCK"),
+ MTK_FUNCTION(4, "CMVREF1"),
+ MTK_FUNCTION(5, "SCP_SPI0_CS"),
+ MTK_FUNCTION(6, "I2S2_BCK"),
+ MTK_FUNCTION(7, "DBG_MON_A9")
+ ),
+ MTK_PIN(
+ 23, "GPIO23",
+ MTK_EINT_FUNCTION(0, 23),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO23"),
+ MTK_FUNCTION(1, "SPI3_MO"),
+ MTK_FUNCTION(2, "PWM0"),
+ MTK_FUNCTION(3, "KPROW7"),
+ MTK_FUNCTION(4, "ANT_SEL3"),
+ MTK_FUNCTION(5, "SCP_SPI0_MO"),
+ MTK_FUNCTION(6, "I2S2_LRCK"),
+ MTK_FUNCTION(7, "DBG_MON_A10")
+ ),
+ MTK_PIN(
+ 24, "GPIO24",
+ MTK_EINT_FUNCTION(0, 24),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO24"),
+ MTK_FUNCTION(1, "SPI3_CLK"),
+ MTK_FUNCTION(2, "UDI_TCK"),
+ MTK_FUNCTION(3, "IO_JTAG_TCK"),
+ MTK_FUNCTION(4, "SSPM_JTAG_TCK"),
+ MTK_FUNCTION(5, "SCP_SPI0_CK"),
+ MTK_FUNCTION(6, "I2S2_DI"),
+ MTK_FUNCTION(7, "DBG_MON_A11")
+ ),
+ MTK_PIN(
+ 25, "GPIO25",
+ MTK_EINT_FUNCTION(0, 25),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO25"),
+ MTK_FUNCTION(1, "SPI1_A_MI"),
+ MTK_FUNCTION(2, "UDI_TMS"),
+ MTK_FUNCTION(3, "IO_JTAG_TMS"),
+ MTK_FUNCTION(4, "SSPM_JTAG_TMS"),
+ MTK_FUNCTION(5, "KPROW3"),
+ MTK_FUNCTION(6, "I2S1_MCK"),
+ MTK_FUNCTION(7, "DBG_MON_A12")
+ ),
+ MTK_PIN(
+ 26, "GPIO26",
+ MTK_EINT_FUNCTION(0, 26),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO26"),
+ MTK_FUNCTION(1, "SPI1_A_CSB"),
+ MTK_FUNCTION(2, "UDI_TDI"),
+ MTK_FUNCTION(3, "IO_JTAG_TDI"),
+ MTK_FUNCTION(4, "SSPM_JTAG_TDI"),
+ MTK_FUNCTION(5, "KPROW4"),
+ MTK_FUNCTION(6, "I2S1_BCK"),
+ MTK_FUNCTION(7, "DBG_MON_A13")
+ ),
+ MTK_PIN(
+ 27, "GPIO27",
+ MTK_EINT_FUNCTION(0, 27),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO27"),
+ MTK_FUNCTION(1, "SPI1_A_MO"),
+ MTK_FUNCTION(2, "UDI_TDO"),
+ MTK_FUNCTION(3, "IO_JTAG_TDO"),
+ MTK_FUNCTION(4, "SSPM_JTAG_TDO"),
+ MTK_FUNCTION(5, "KPROW5"),
+ MTK_FUNCTION(6, "I2S1_LRCK"),
+ MTK_FUNCTION(7, "DBG_MON_A14")
+ ),
+ MTK_PIN(
+ 28, "GPIO28",
+ MTK_EINT_FUNCTION(0, 28),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO28"),
+ MTK_FUNCTION(1, "SPI1_A_CLK"),
+ MTK_FUNCTION(2, "UDI_NTRST"),
+ MTK_FUNCTION(3, "IO_JTAG_TRSTN"),
+ MTK_FUNCTION(4, "SSPM_JTAG_TRSTN"),
+ MTK_FUNCTION(5, "KPROW6"),
+ MTK_FUNCTION(6, "I2S1_DO"),
+ MTK_FUNCTION(7, "DBG_MON_A15")
+ ),
+ MTK_PIN(
+ 29, "GPIO29",
+ MTK_EINT_FUNCTION(0, 29),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO29"),
+ MTK_FUNCTION(1, "MSDC1_CLK"),
+ MTK_FUNCTION(2, "IO_JTAG_TCK"),
+ MTK_FUNCTION(3, "UDI_TCK"),
+ MTK_FUNCTION(4, "CONN_DSP_JCK"),
+ MTK_FUNCTION(5, "SSPM_JTAG_TCK"),
+ MTK_FUNCTION(6, "CONN_MCU_AICE_TCKC"),
+ MTK_FUNCTION(7, "DAP_MD32_SWCK")
+ ),
+ MTK_PIN(
+ 30, "GPIO30",
+ MTK_EINT_FUNCTION(0, 30),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO30"),
+ MTK_FUNCTION(1, "MSDC1_CMD"),
+ MTK_FUNCTION(2, "IO_JTAG_TMS"),
+ MTK_FUNCTION(3, "UDI_TMS"),
+ MTK_FUNCTION(4, "CONN_DSP_JMS"),
+ MTK_FUNCTION(5, "SSPM_JTAG_TMS"),
+ MTK_FUNCTION(6, "CONN_MCU_AICE_TMSC"),
+ MTK_FUNCTION(7, "DAP_MD32_SWD")
+ ),
+ MTK_PIN(
+ 31, "GPIO31",
+ MTK_EINT_FUNCTION(0, 31),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO31"),
+ MTK_FUNCTION(1, "MSDC1_DAT3")
+ ),
+ MTK_PIN(
+ 32, "GPIO32",
+ MTK_EINT_FUNCTION(0, 32),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO32"),
+ MTK_FUNCTION(1, "MSDC1_DAT0"),
+ MTK_FUNCTION(2, "IO_JTAG_TDI"),
+ MTK_FUNCTION(3, "UDI_TDI"),
+ MTK_FUNCTION(4, "CONN_DSP_JDI"),
+ MTK_FUNCTION(5, "SSPM_JTAG_TDI")
+ ),
+ MTK_PIN(
+ 33, "GPIO33",
+ MTK_EINT_FUNCTION(0, 33),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO33"),
+ MTK_FUNCTION(1, "MSDC1_DAT2"),
+ MTK_FUNCTION(2, "IO_JTAG_TRSTN"),
+ MTK_FUNCTION(3, "UDI_NTRST"),
+ MTK_FUNCTION(4, "CONN_DSP_JINTP"),
+ MTK_FUNCTION(5, "SSPM_JTAG_TRSTN")
+ ),
+ MTK_PIN(
+ 34, "GPIO34",
+ MTK_EINT_FUNCTION(0, 34),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO34"),
+ MTK_FUNCTION(1, "MSDC1_DAT1"),
+ MTK_FUNCTION(2, "IO_JTAG_TDO"),
+ MTK_FUNCTION(3, "UDI_TDO"),
+ MTK_FUNCTION(4, "CONN_DSP_JDO"),
+ MTK_FUNCTION(5, "SSPM_JTAG_TDO")
+ ),
+ MTK_PIN(
+ 35, "GPIO35",
+ MTK_EINT_FUNCTION(0, 35),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO35"),
+ MTK_FUNCTION(1, "MD1_SIM2_SIO"),
+ MTK_FUNCTION(2, "CCU_JTAG_TDO"),
+ MTK_FUNCTION(3, "MD1_SIM1_SIO"),
+ MTK_FUNCTION(5, "SCP_JTAG_TDO"),
+ MTK_FUNCTION(6, "CONN_DSP_JDO"),
+ MTK_FUNCTION(7, "DBG_MON_A16")
+ ),
+ MTK_PIN(
+ 36, "GPIO36",
+ MTK_EINT_FUNCTION(0, 36),
+ DRV_GRP0,
+ MTK_FUNCTION(0, "GPIO36"),
+ MTK_FUNCTION(1, "MD1_SIM2_SRST"),
+ MTK_FUNCTION(2, "CCU_JTAG_TMS"),
+ MTK_FUNCTION(3, "MD1_SIM1_SRST"),
+ MTK_FUNCTION(4, "CONN_MCU_AICE_TMSC"),
+ MTK_FUNCTION(5, "SCP_JTAG_TMS"),
+ MTK_FUNCTION(6, "CONN_DSP_JMS"),
+ MTK_FUNCTION(7, "DBG_MON_A17")
+ ),
+ MTK_PIN(
+ 37, "GPIO37",
+ MTK_EINT_FUNCTION(0, 37),
+ DRV_GRP0,
+ MTK_FUNCTION(0, "GPIO37"),
+ MTK_FUNCTION(1, "MD1_SIM2_SCLK"),
+ MTK_FUNCTION(2, "CCU_JTAG_TDI"),
+ MTK_FUNCTION(3, "MD1_SIM1_SCLK"),
+ MTK_FUNCTION(5, "SCP_JTAG_TDI"),
+ MTK_FUNCTION(6, "CONN_DSP_JDI"),
+ MTK_FUNCTION(7, "DBG_MON_A18")
+ ),
+ MTK_PIN(
+ 38, "GPIO38",
+ MTK_EINT_FUNCTION(0, 38),
+ DRV_GRP0,
+ MTK_FUNCTION(0, "GPIO38"),
+ MTK_FUNCTION(1, "MD1_SIM1_SCLK"),
+ MTK_FUNCTION(3, "MD1_SIM2_SCLK"),
+ MTK_FUNCTION(7, "DBG_MON_A19")
+ ),
+ MTK_PIN(
+ 39, "GPIO39",
+ MTK_EINT_FUNCTION(0, 39),
+ DRV_GRP0,
+ MTK_FUNCTION(0, "GPIO39"),
+ MTK_FUNCTION(1, "MD1_SIM1_SRST"),
+ MTK_FUNCTION(2, "CCU_JTAG_TCK"),
+ MTK_FUNCTION(3, "MD1_SIM2_SRST"),
+ MTK_FUNCTION(4, "CONN_MCU_AICE_TCKC"),
+ MTK_FUNCTION(5, "SCP_JTAG_TCK"),
+ MTK_FUNCTION(6, "CONN_DSP_JCK"),
+ MTK_FUNCTION(7, "DBG_MON_A20")
+ ),
+ MTK_PIN(
+ 40, "GPIO40",
+ MTK_EINT_FUNCTION(0, 40),
+ DRV_GRP0,
+ MTK_FUNCTION(0, "GPIO40"),
+ MTK_FUNCTION(1, "MD1_SIM1_SIO"),
+ MTK_FUNCTION(2, "CCU_JTAG_TRST"),
+ MTK_FUNCTION(3, "MD1_SIM2_SIO"),
+ MTK_FUNCTION(5, "SCP_JTAG_TRSTN"),
+ MTK_FUNCTION(6, "CONN_DSP_JINTP"),
+ MTK_FUNCTION(7, "DBG_MON_A21")
+ ),
+ MTK_PIN(
+ 41, "GPIO41",
+ MTK_EINT_FUNCTION(0, 41),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO41"),
+ MTK_FUNCTION(1, "IDDIG"),
+ MTK_FUNCTION(2, "URXD1"),
+ MTK_FUNCTION(3, "UCTS0"),
+ MTK_FUNCTION(4, "KPCOL2"),
+ MTK_FUNCTION(5, "SSPM_UTXD_AO"),
+ MTK_FUNCTION(6, "MD_INT0"),
+ MTK_FUNCTION(7, "DBG_MON_A22")
+ ),
+ MTK_PIN(
+ 42, "GPIO42",
+ MTK_EINT_FUNCTION(0, 42),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO42"),
+ MTK_FUNCTION(1, "USB_DRVVBUS"),
+ MTK_FUNCTION(2, "UTXD1"),
+ MTK_FUNCTION(3, "URTS0"),
+ MTK_FUNCTION(4, "KPROW2"),
+ MTK_FUNCTION(5, "SSPM_URXD_AO"),
+ MTK_FUNCTION(6, "MD_INT1_C2K_UIM0_HOT_PLUG"),
+ MTK_FUNCTION(7, "DBG_MON_A23")
+ ),
+ MTK_PIN(
+ 43, "GPIO43",
+ MTK_EINT_FUNCTION(0, 43),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO43"),
+ MTK_FUNCTION(1, "DISP_PWM"),
+ MTK_FUNCTION(7, "DBG_MON_A24")
+ ),
+ MTK_PIN(
+ 44, "GPIO44",
+ MTK_EINT_FUNCTION(0, 44),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO44"),
+ MTK_FUNCTION(1, "DSI_TE"),
+ MTK_FUNCTION(7, "DBG_MON_A25")
+ ),
+ MTK_PIN(
+ 45, "GPIO45",
+ MTK_EINT_FUNCTION(0, 45),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO45"),
+ MTK_FUNCTION(1, "LCM_RST"),
+ MTK_FUNCTION(7, "DBG_MON_A26")
+ ),
+ MTK_PIN(
+ 46, "GPIO46",
+ MTK_EINT_FUNCTION(0, 46),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO46"),
+ MTK_FUNCTION(1, "MD_INT2_C2K_UIM1_HOT_PLUG"),
+ MTK_FUNCTION(2, "UCTS0"),
+ MTK_FUNCTION(3, "UCTS1"),
+ MTK_FUNCTION(4, "IDDIG"),
+ MTK_FUNCTION(5, "SCL_6306"),
+ MTK_FUNCTION(6, "TP_UCTS1_AO"),
+ MTK_FUNCTION(7, "DBG_MON_A27")
+ ),
+ MTK_PIN(
+ 47, "GPIO47",
+ MTK_EINT_FUNCTION(0, 47),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO47"),
+ MTK_FUNCTION(1, "MD_INT1_C2K_UIM0_HOT_PLUG"),
+ MTK_FUNCTION(2, "URTS0"),
+ MTK_FUNCTION(3, "URTS1"),
+ MTK_FUNCTION(4, "USB_DRVVBUS"),
+ MTK_FUNCTION(5, "SDA_6306"),
+ MTK_FUNCTION(6, "TP_URTS1_AO"),
+ MTK_FUNCTION(7, "DBG_MON_A28")
+ ),
+ MTK_PIN(
+ 48, "GPIO48",
+ MTK_EINT_FUNCTION(0, 48),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO48"),
+ MTK_FUNCTION(1, "SCL5"),
+ MTK_FUNCTION(7, "DBG_MON_A29")
+ ),
+ MTK_PIN(
+ 49, "GPIO49",
+ MTK_EINT_FUNCTION(0, 49),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO49"),
+ MTK_FUNCTION(1, "SDA5"),
+ MTK_FUNCTION(7, "DBG_MON_A30")
+ ),
+ MTK_PIN(
+ 50, "GPIO50",
+ MTK_EINT_FUNCTION(0, 50),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO50"),
+ MTK_FUNCTION(1, "SCL3"),
+ MTK_FUNCTION(2, "URXD1"),
+ MTK_FUNCTION(3, "MD_URXD1"),
+ MTK_FUNCTION(4, "SSPM_URXD_AO"),
+ MTK_FUNCTION(5, "IDDIG"),
+ MTK_FUNCTION(6, "TP_URXD1_AO"),
+ MTK_FUNCTION(7, "DBG_MON_A31")
+ ),
+ MTK_PIN(
+ 51, "GPIO51",
+ MTK_EINT_FUNCTION(0, 51),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO51"),
+ MTK_FUNCTION(1, "SDA3"),
+ MTK_FUNCTION(2, "UTXD1"),
+ MTK_FUNCTION(3, "MD_UTXD1"),
+ MTK_FUNCTION(4, "SSPM_UTXD_AO"),
+ MTK_FUNCTION(5, "USB_DRVVBUS"),
+ MTK_FUNCTION(6, "TP_UTXD1_AO"),
+ MTK_FUNCTION(7, "DBG_MON_A32")
+ ),
+ MTK_PIN(
+ 52, "GPIO52",
+ MTK_EINT_FUNCTION(0, 52),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO52"),
+ MTK_FUNCTION(1, "BPI_BUS15")
+ ),
+ MTK_PIN(
+ 53, "GPIO53",
+ MTK_EINT_FUNCTION(0, 53),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO53"),
+ MTK_FUNCTION(1, "BPI_BUS13")
+ ),
+ MTK_PIN(
+ 54, "GPIO54",
+ MTK_EINT_FUNCTION(0, 54),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO54"),
+ MTK_FUNCTION(1, "BPI_BUS12")
+ ),
+ MTK_PIN(
+ 55, "GPIO55",
+ MTK_EINT_FUNCTION(0, 55),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO55"),
+ MTK_FUNCTION(1, "BPI_BUS8")
+ ),
+ MTK_PIN(
+ 56, "GPIO56",
+ MTK_EINT_FUNCTION(0, 56),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO56"),
+ MTK_FUNCTION(1, "BPI_BUS9"),
+ MTK_FUNCTION(2, "SCL_6306")
+ ),
+ MTK_PIN(
+ 57, "GPIO57",
+ MTK_EINT_FUNCTION(0, 57),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO57"),
+ MTK_FUNCTION(1, "BPI_BUS10"),
+ MTK_FUNCTION(2, "SDA_6306")
+ ),
+ MTK_PIN(
+ 58, "GPIO58",
+ MTK_EINT_FUNCTION(0, 58),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO58"),
+ MTK_FUNCTION(1, "RFIC0_BSI_D2")
+ ),
+ MTK_PIN(
+ 59, "GPIO59",
+ MTK_EINT_FUNCTION(0, 59),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO59"),
+ MTK_FUNCTION(1, "RFIC0_BSI_D1")
+ ),
+ MTK_PIN(
+ 60, "GPIO60",
+ MTK_EINT_FUNCTION(0, 60),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO60"),
+ MTK_FUNCTION(1, "RFIC0_BSI_D0")
+ ),
+ MTK_PIN(
+ 61, "GPIO61",
+ MTK_EINT_FUNCTION(0, 61),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO61"),
+ MTK_FUNCTION(1, "MIPI1_SDATA")
+ ),
+ MTK_PIN(
+ 62, "GPIO62",
+ MTK_EINT_FUNCTION(0, 62),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO62"),
+ MTK_FUNCTION(1, "MIPI1_SCLK")
+ ),
+ MTK_PIN(
+ 63, "GPIO63",
+ MTK_EINT_FUNCTION(0, 63),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO63"),
+ MTK_FUNCTION(1, "MIPI0_SDATA")
+ ),
+ MTK_PIN(
+ 64, "GPIO64",
+ MTK_EINT_FUNCTION(0, 64),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO64"),
+ MTK_FUNCTION(1, "MIPI0_SCLK")
+ ),
+ MTK_PIN(
+ 65, "GPIO65",
+ MTK_EINT_FUNCTION(0, 65),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO65"),
+ MTK_FUNCTION(1, "MIPI3_SDATA"),
+ MTK_FUNCTION(2, "BPI_BUS16")
+ ),
+ MTK_PIN(
+ 66, "GPIO66",
+ MTK_EINT_FUNCTION(0, 66),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO66"),
+ MTK_FUNCTION(1, "MIPI3_SCLK"),
+ MTK_FUNCTION(2, "BPI_BUS17")
+ ),
+ MTK_PIN(
+ 67, "GPIO67",
+ MTK_EINT_FUNCTION(0, 67),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO67"),
+ MTK_FUNCTION(1, "MIPI2_SDATA")
+ ),
+ MTK_PIN(
+ 68, "GPIO68",
+ MTK_EINT_FUNCTION(0, 68),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO68"),
+ MTK_FUNCTION(1, "MIPI2_SCLK")
+ ),
+ MTK_PIN(
+ 69, "GPIO69",
+ MTK_EINT_FUNCTION(0, 69),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO69"),
+ MTK_FUNCTION(1, "BPI_BUS7")
+ ),
+ MTK_PIN(
+ 70, "GPIO70",
+ MTK_EINT_FUNCTION(0, 70),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO70"),
+ MTK_FUNCTION(1, "BPI_BUS6")
+ ),
+ MTK_PIN(
+ 71, "GPIO71",
+ MTK_EINT_FUNCTION(0, 71),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO71"),
+ MTK_FUNCTION(1, "BPI_BUS5")
+ ),
+ MTK_PIN(
+ 72, "GPIO72",
+ MTK_EINT_FUNCTION(0, 72),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO72"),
+ MTK_FUNCTION(1, "BPI_BUS4")
+ ),
+ MTK_PIN(
+ 73, "GPIO73",
+ MTK_EINT_FUNCTION(0, 73),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO73"),
+ MTK_FUNCTION(1, "BPI_BUS3")
+ ),
+ MTK_PIN(
+ 74, "GPIO74",
+ MTK_EINT_FUNCTION(0, 74),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO74"),
+ MTK_FUNCTION(1, "BPI_BUS2")
+ ),
+ MTK_PIN(
+ 75, "GPIO75",
+ MTK_EINT_FUNCTION(0, 75),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO75"),
+ MTK_FUNCTION(1, "BPI_BUS1")
+ ),
+ MTK_PIN(
+ 76, "GPIO76",
+ MTK_EINT_FUNCTION(0, 76),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO76"),
+ MTK_FUNCTION(1, "BPI_BUS0")
+ ),
+ MTK_PIN(
+ 77, "GPIO77",
+ MTK_EINT_FUNCTION(0, 77),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO77"),
+ MTK_FUNCTION(1, "BPI_BUS14")
+ ),
+ MTK_PIN(
+ 78, "GPIO78",
+ MTK_EINT_FUNCTION(0, 78),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO78"),
+ MTK_FUNCTION(1, "BPI_BUS11")
+ ),
+ MTK_PIN(
+ 79, "GPIO79",
+ MTK_EINT_FUNCTION(0, 79),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO79"),
+ MTK_FUNCTION(1, "BPI_PA_VM1"),
+ MTK_FUNCTION(2, "MIPI4_SDATA")
+ ),
+ MTK_PIN(
+ 80, "GPIO80",
+ MTK_EINT_FUNCTION(0, 80),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO80"),
+ MTK_FUNCTION(1, "BPI_PA_VM0"),
+ MTK_FUNCTION(2, "MIPI4_SCLK")
+ ),
+ MTK_PIN(
+ 81, "GPIO81",
+ MTK_EINT_FUNCTION(0, 81),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO81"),
+ MTK_FUNCTION(1, "SDA1"),
+ MTK_FUNCTION(7, "DBG_MON_B0")
+ ),
+ MTK_PIN(
+ 82, "GPIO82",
+ MTK_EINT_FUNCTION(0, 82),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO82"),
+ MTK_FUNCTION(1, "SDA0"),
+ MTK_FUNCTION(7, "DBG_MON_B1")
+ ),
+ MTK_PIN(
+ 83, "GPIO83",
+ MTK_EINT_FUNCTION(0, 83),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO83"),
+ MTK_FUNCTION(1, "SCL0"),
+ MTK_FUNCTION(7, "DBG_MON_B2")
+ ),
+ MTK_PIN(
+ 84, "GPIO84",
+ MTK_EINT_FUNCTION(0, 84),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO84"),
+ MTK_FUNCTION(1, "SCL1"),
+ MTK_FUNCTION(7, "DBG_MON_B3")
+ ),
+ MTK_PIN(
+ 85, "GPIO85",
+ MTK_EINT_FUNCTION(0, 85),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO85"),
+ MTK_FUNCTION(1, "RFIC0_BSI_EN")
+ ),
+ MTK_PIN(
+ 86, "GPIO86",
+ MTK_EINT_FUNCTION(0, 86),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO86"),
+ MTK_FUNCTION(1, "RFIC0_BSI_CK")
+ ),
+ MTK_PIN(
+ 87, "GPIO87",
+ MTK_EINT_FUNCTION(0, 87),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO87"),
+ MTK_FUNCTION(2, "MD_INT1_C2K_UIM0_HOT_PLUG"),
+ MTK_FUNCTION(3, "CMVREF0"),
+ MTK_FUNCTION(4, "MD_URXD0"),
+ MTK_FUNCTION(5, "AGPS_SYNC"),
+ MTK_FUNCTION(6, "EXT_FRAME_SYNC")
+ ),
+ MTK_PIN(
+ 88, "GPIO88",
+ MTK_EINT_FUNCTION(0, 88),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO88"),
+ MTK_FUNCTION(1, "CMMCLK3"),
+ MTK_FUNCTION(2, "MD_INT2_C2K_UIM1_HOT_PLUG"),
+ MTK_FUNCTION(3, "CMVREF1"),
+ MTK_FUNCTION(4, "MD_UTXD0"),
+ MTK_FUNCTION(5, "AGPS_SYNC"),
+ MTK_FUNCTION(6, "DVFSRC_EXT_REQ")
+ ),
+ MTK_PIN(
+ 89, "GPIO89",
+ MTK_EINT_FUNCTION(0, 89),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO89"),
+ MTK_FUNCTION(1, "SRCLKENAI0"),
+ MTK_FUNCTION(2, "PWM2"),
+ MTK_FUNCTION(3, "MD_INT0"),
+ MTK_FUNCTION(4, "USB_DRVVBUS"),
+ MTK_FUNCTION(5, "SCL_6306"),
+ MTK_FUNCTION(6, "TP_GPIO4_AO"),
+ MTK_FUNCTION(7, "DBG_MON_B21")
+ ),
+ MTK_PIN(
+ 90, "GPIO90",
+ MTK_EINT_FUNCTION(0, 90),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO90"),
+ MTK_FUNCTION(1, "URXD1"),
+ MTK_FUNCTION(2, "PWM0"),
+ MTK_FUNCTION(3, "MD_INT2_C2K_UIM1_HOT_PLUG"),
+ MTK_FUNCTION(4, "ANT_SEL4"),
+ MTK_FUNCTION(5, "USB_DRVVBUS"),
+ MTK_FUNCTION(6, "I2S2_BCK"),
+ MTK_FUNCTION(7, "DBG_MON_B4")
+ ),
+ MTK_PIN(
+ 91, "GPIO91",
+ MTK_EINT_FUNCTION(0, 91),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO91"),
+ MTK_FUNCTION(1, "KPROW1"),
+ MTK_FUNCTION(2, "PWM2"),
+ MTK_FUNCTION(3, "MD_INT0"),
+ MTK_FUNCTION(4, "ANT_SEL5"),
+ MTK_FUNCTION(5, "IDDIG"),
+ MTK_FUNCTION(6, "I2S2_LRCK"),
+ MTK_FUNCTION(7, "DBG_MON_B5")
+ ),
+ MTK_PIN(
+ 92, "GPIO92",
+ MTK_EINT_FUNCTION(0, 92),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO92"),
+ MTK_FUNCTION(1, "KPROW0"),
+ MTK_FUNCTION(5, "DVFSRC_EXT_REQ"),
+ MTK_FUNCTION(6, "I2S2_DI"),
+ MTK_FUNCTION(7, "DBG_MON_B6")
+ ),
+ MTK_PIN(
+ 93, "GPIO93",
+ MTK_EINT_FUNCTION(0, 93),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO93"),
+ MTK_FUNCTION(1, "KPCOL0"),
+ MTK_FUNCTION(7, "DBG_MON_B7")
+ ),
+ MTK_PIN(
+ 94, "GPIO94",
+ MTK_EINT_FUNCTION(0, 94),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO94"),
+ MTK_FUNCTION(1, "KPCOL1"),
+ MTK_FUNCTION(5, "CMFLASH"),
+ MTK_FUNCTION(6, "CMVREF0"),
+ MTK_FUNCTION(7, "DBG_MON_B8")
+ ),
+ MTK_PIN(
+ 95, "GPIO95",
+ MTK_EINT_FUNCTION(0, 95),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO95"),
+ MTK_FUNCTION(1, "URXD0"),
+ MTK_FUNCTION(2, "UTXD0"),
+ MTK_FUNCTION(3, "MD_URXD0"),
+ MTK_FUNCTION(4, "PTA_RXD"),
+ MTK_FUNCTION(5, "SSPM_URXD_AO"),
+ MTK_FUNCTION(6, "WIFI_RXD")
+ ),
+ MTK_PIN(
+ 96, "GPIO96",
+ MTK_EINT_FUNCTION(0, 96),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO96"),
+ MTK_FUNCTION(1, "UTXD0"),
+ MTK_FUNCTION(2, "URXD0"),
+ MTK_FUNCTION(3, "MD_UTXD0"),
+ MTK_FUNCTION(4, "PTA_TXD"),
+ MTK_FUNCTION(5, "SSPM_UTXD_AO"),
+ MTK_FUNCTION(6, "WIFI_TXD")
+ ),
+ MTK_PIN(
+ 97, "GPIO97",
+ MTK_EINT_FUNCTION(0, 97),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO97"),
+ MTK_FUNCTION(1, "UCTS0"),
+ MTK_FUNCTION(2, "I2S1_MCK"),
+ MTK_FUNCTION(3, "CONN_MCU_TDO"),
+ MTK_FUNCTION(4, "SPI5_MI"),
+ MTK_FUNCTION(5, "SCL_6306"),
+ MTK_FUNCTION(6, "MCUPM_JTAG_TDO"),
+ MTK_FUNCTION(7, "DBG_MON_B15")
+ ),
+ MTK_PIN(
+ 98, "GPIO98",
+ MTK_EINT_FUNCTION(0, 98),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO98"),
+ MTK_FUNCTION(1, "URTS0"),
+ MTK_FUNCTION(2, "I2S1_BCK"),
+ MTK_FUNCTION(3, "CONN_MCU_TMS"),
+ MTK_FUNCTION(4, "SPI5_CSB"),
+ MTK_FUNCTION(6, "MCUPM_JTAG_TMS"),
+ MTK_FUNCTION(7, "DBG_MON_B16")
+ ),
+ MTK_PIN(
+ 99, "GPIO99",
+ MTK_EINT_FUNCTION(0, 99),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO99"),
+ MTK_FUNCTION(1, "CMMCLK0"),
+ MTK_FUNCTION(4, "AUXIF_CLK"),
+ MTK_FUNCTION(5, "PTA_RXD"),
+ MTK_FUNCTION(6, "CONN_UART0_RXD"),
+ MTK_FUNCTION(7, "DBG_MON_B17")
+ ),
+
+ MTK_PIN(
+ 100, "GPIO100",
+ MTK_EINT_FUNCTION(0, 100),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO100"),
+ MTK_FUNCTION(1, "CMMCLK1"),
+ MTK_FUNCTION(4, "AUXIF_ST"),
+ MTK_FUNCTION(5, "PTA_TXD"),
+ MTK_FUNCTION(6, "CONN_UART0_TXD"),
+ MTK_FUNCTION(7, "DBG_MON_B18")
+ ),
+ MTK_PIN(
+ 101, "GPIO101",
+ MTK_EINT_FUNCTION(0, 101),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO101"),
+ MTK_FUNCTION(1, "CMFLASH"),
+ MTK_FUNCTION(2, "I2S1_LRCK"),
+ MTK_FUNCTION(3, "CONN_MCU_TCK"),
+ MTK_FUNCTION(4, "SPI5_MO"),
+ MTK_FUNCTION(6, "MCUPM_JTAG_TCK"),
+ MTK_FUNCTION(7, "DBG_MON_B19")
+ ),
+ MTK_PIN(
+ 102, "GPIO102",
+ MTK_EINT_FUNCTION(0, 102),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO102"),
+ MTK_FUNCTION(1, "CMVREF0"),
+ MTK_FUNCTION(2, "I2S1_DO"),
+ MTK_FUNCTION(3, "CONN_MCU_TDI"),
+ MTK_FUNCTION(4, "SPI5_CLK"),
+ MTK_FUNCTION(5, "AGPS_SYNC"),
+ MTK_FUNCTION(6, "MCUPM_JTAG_TDI"),
+ MTK_FUNCTION(7, "DBG_MON_B20")
+ ),
+ MTK_PIN(
+ 103, "GPIO103",
+ MTK_EINT_FUNCTION(0, 103),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO103"),
+ MTK_FUNCTION(1, "SCL2"),
+ MTK_FUNCTION(2, "TP_UTXD1_AO"),
+ MTK_FUNCTION(3, "MD_UTXD0"),
+ MTK_FUNCTION(4, "MD_UTXD1"),
+ MTK_FUNCTION(5, "TP_URTS2_AO"),
+ MTK_FUNCTION(6, "WIFI_TXD"),
+ MTK_FUNCTION(7, "DBG_MON_B25")
+ ),
+ MTK_PIN(
+ 104, "GPIO104",
+ MTK_EINT_FUNCTION(0, 104),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO104"),
+ MTK_FUNCTION(1, "SDA2"),
+ MTK_FUNCTION(2, "TP_URXD1_AO"),
+ MTK_FUNCTION(3, "MD_URXD0"),
+ MTK_FUNCTION(4, "MD_URXD1"),
+ MTK_FUNCTION(5, "TP_UCTS2_AO"),
+ MTK_FUNCTION(6, "WIFI_RXD"),
+ MTK_FUNCTION(7, "DBG_MON_B26")
+ ),
+ MTK_PIN(
+ 105, "GPIO105",
+ MTK_EINT_FUNCTION(0, 105),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO105"),
+ MTK_FUNCTION(1, "SCL4"),
+ MTK_FUNCTION(3, "MD_UTXD1"),
+ MTK_FUNCTION(4, "MD_UTXD0"),
+ MTK_FUNCTION(5, "TP_UTXD2_AO"),
+ MTK_FUNCTION(6, "PTA_TXD"),
+ MTK_FUNCTION(7, "DBG_MON_B27")
+ ),
+ MTK_PIN(
+ 106, "GPIO106",
+ MTK_EINT_FUNCTION(0, 106),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO106"),
+ MTK_FUNCTION(1, "SDA4"),
+ MTK_FUNCTION(3, "MD_URXD1"),
+ MTK_FUNCTION(4, "MD_URXD0"),
+ MTK_FUNCTION(5, "TP_URXD2_AO"),
+ MTK_FUNCTION(6, "PTA_RXD"),
+ MTK_FUNCTION(7, "DBG_MON_B28")
+ ),
+ MTK_PIN(
+ 107, "GPIO107",
+ MTK_EINT_FUNCTION(0, 107),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO107"),
+ MTK_FUNCTION(1, "UTXD1"),
+ MTK_FUNCTION(2, "MD_UTXD0"),
+ MTK_FUNCTION(3, "SDA_6306"),
+ MTK_FUNCTION(4, "KPCOL3"),
+ MTK_FUNCTION(5, "CMVREF0"),
+ MTK_FUNCTION(6, "URTS0"),
+ MTK_FUNCTION(7, "DBG_MON_B29")
+ ),
+ MTK_PIN(
+ 108, "GPIO108",
+ MTK_EINT_FUNCTION(0, 108),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO108"),
+ MTK_FUNCTION(1, "CMMCLK2"),
+ MTK_FUNCTION(2, "MD_INT0"),
+ MTK_FUNCTION(3, "CONN_MCU_DBGACK_N"),
+ MTK_FUNCTION(4, "KPCOL4"),
+ MTK_FUNCTION(6, "I2S3_MCK"),
+ MTK_FUNCTION(7, "DBG_MON_B30")
+ ),
+ MTK_PIN(
+ 109, "GPIO109",
+ MTK_EINT_FUNCTION(0, 109),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO109"),
+ MTK_FUNCTION(1, "URXD1"),
+ MTK_FUNCTION(2, "MD_URXD0"),
+ MTK_FUNCTION(3, "ANT_SEL7"),
+ MTK_FUNCTION(4, "KPCOL5"),
+ MTK_FUNCTION(5, "CMVREF1"),
+ MTK_FUNCTION(6, "UCTS0"),
+ MTK_FUNCTION(7, "DBG_MON_B31")
+ ),
+ MTK_PIN(
+ 110, "GPIO110",
+ MTK_EINT_FUNCTION(0, 110),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO110"),
+ MTK_FUNCTION(1, "ANT_SEL0"),
+ MTK_FUNCTION(2, "CLKM0"),
+ MTK_FUNCTION(3, "PWM3"),
+ MTK_FUNCTION(4, "MD_INT0"),
+ MTK_FUNCTION(5, "IDDIG"),
+ MTK_FUNCTION(6, "I2S3_BCK"),
+ MTK_FUNCTION(7, "DBG_MON_B13")
+ ),
+ MTK_PIN(
+ 111, "GPIO111",
+ MTK_EINT_FUNCTION(0, 111),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO111"),
+ MTK_FUNCTION(1, "ANT_SEL1"),
+ MTK_FUNCTION(2, "CLKM1"),
+ MTK_FUNCTION(3, "PWM4"),
+ MTK_FUNCTION(4, "PTA_RXD"),
+ MTK_FUNCTION(5, "CMVREF0"),
+ MTK_FUNCTION(6, "I2S3_LRCK"),
+ MTK_FUNCTION(7, "DBG_MON_B14")
+ ),
+ MTK_PIN(
+ 112, "GPIO112",
+ MTK_EINT_FUNCTION(0, 112),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO112"),
+ MTK_FUNCTION(1, "ANT_SEL2"),
+ MTK_FUNCTION(2, "CLKM2"),
+ MTK_FUNCTION(3, "PWM5"),
+ MTK_FUNCTION(4, "PTA_TXD"),
+ MTK_FUNCTION(5, "CMVREF1"),
+ MTK_FUNCTION(6, "I2S3_DO")
+ ),
+ MTK_PIN(
+ 113, "GPIO113",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO113"),
+ MTK_FUNCTION(1, "CONN_TOP_CLK")
+ ),
+ MTK_PIN(
+ 114, "GPIO114",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO114"),
+ MTK_FUNCTION(1, "CONN_TOP_DATA")
+ ),
+ MTK_PIN(
+ 115, "GPIO115",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO115"),
+ MTK_FUNCTION(1, "CONN_BT_CLK")
+ ),
+ MTK_PIN(
+ 116, "GPIO116",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO116"),
+ MTK_FUNCTION(1, "CONN_BT_DATA")
+ ),
+ MTK_PIN(
+ 117, "GPIO117",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO117"),
+ MTK_FUNCTION(1, "CONN_WF_CTRL0")
+ ),
+ MTK_PIN(
+ 118, "GPIO118",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO118"),
+ MTK_FUNCTION(1, "CONN_WF_CTRL1")
+ ),
+ MTK_PIN(
+ 119, "GPIO119",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO119"),
+ MTK_FUNCTION(1, "CONN_WF_CTRL2")
+ ),
+ MTK_PIN(
+ 120, "GPIO120",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO120"),
+ MTK_FUNCTION(1, "CONN_WB_PTA")
+ ),
+ MTK_PIN(
+ 121, "GPIO121",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO121"),
+ MTK_FUNCTION(1, "CONN_HRST_B")
+ ),
+ MTK_PIN(
+ 122, "GPIO122",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO122"),
+ MTK_FUNCTION(1, "MSDC0_CMD"),
+ MTK_FUNCTION(2, "MSDC0_CMD")
+ ),
+ MTK_PIN(
+ 123, "GPIO123",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO123"),
+ MTK_FUNCTION(1, "MSDC0_DAT0"),
+ MTK_FUNCTION(2, "MSDC0_DAT4")
+ ),
+ MTK_PIN(
+ 124, "GPIO124",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO124"),
+ MTK_FUNCTION(1, "MSDC0_CLK"),
+ MTK_FUNCTION(2, "MSDC0_CLK")
+ ),
+ MTK_PIN(
+ 125, "GPIO125",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO125"),
+ MTK_FUNCTION(1, "MSDC0_DAT2"),
+ MTK_FUNCTION(2, "MSDC0_DAT5")
+ ),
+ MTK_PIN(
+ 126, "GPIO126",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO126"),
+ MTK_FUNCTION(1, "MSDC0_DAT4"),
+ MTK_FUNCTION(2, "MSDC0_DAT2")
+ ),
+ MTK_PIN(
+ 127, "GPIO127",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO127"),
+ MTK_FUNCTION(1, "MSDC0_DAT6"),
+ MTK_FUNCTION(2, "MSDC0_DAT1")
+ ),
+ MTK_PIN(
+ 128, "GPIO128",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO128"),
+ MTK_FUNCTION(1, "MSDC0_DAT1"),
+ MTK_FUNCTION(2, "MSDC0_DAT6")
+ ),
+ MTK_PIN(
+ 129, "GPIO129",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO129"),
+ MTK_FUNCTION(1, "MSDC0_DAT5"),
+ MTK_FUNCTION(2, "MSDC0_DAT0")
+ ),
+ MTK_PIN(
+ 130, "GPIO130",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO130"),
+ MTK_FUNCTION(1, "MSDC0_DAT7"),
+ MTK_FUNCTION(2, "MSDC0_DAT7")
+ ),
+ MTK_PIN(
+ 131, "GPIO131",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO131"),
+ MTK_FUNCTION(1, "MSDC0_DSL"),
+ MTK_FUNCTION(2, "MSDC0_DSL")
+ ),
+ MTK_PIN(
+ 132, "GPIO132",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO132"),
+ MTK_FUNCTION(1, "MSDC0_DAT3"),
+ MTK_FUNCTION(2, "MSDC0_DAT3")
+ ),
+ MTK_PIN(
+ 133, "GPIO133",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO133"),
+ MTK_FUNCTION(1, "MSDC0_RSTB"),
+ MTK_FUNCTION(2, "MSDC0_RSTB")
+ ),
+ MTK_PIN(
+ 134, "GPIO134",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO134"),
+ MTK_FUNCTION(1, "RTC32K_CK")
+ ),
+ MTK_PIN(
+ 135, "GPIO135",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO135"),
+ MTK_FUNCTION(1, "WATCHDOG")
+ ),
+ MTK_PIN(
+ 136, "GPIO136",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO136"),
+ MTK_FUNCTION(1, "AUD_CLK_MOSI"),
+ MTK_FUNCTION(2, "AUD_CLK_MISO"),
+ MTK_FUNCTION(3, "I2S1_MCK")
+ ),
+ MTK_PIN(
+ 137, "GPIO137",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO137"),
+ MTK_FUNCTION(1, "AUD_SYNC_MOSI"),
+ MTK_FUNCTION(2, "AUD_SYNC_MISO"),
+ MTK_FUNCTION(3, "I2S1_BCK")
+ ),
+ MTK_PIN(
+ 138, "GPIO138",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO138"),
+ MTK_FUNCTION(1, "AUD_DAT_MOSI0"),
+ MTK_FUNCTION(2, "AUD_DAT_MISO0"),
+ MTK_FUNCTION(3, "I2S1_LRCK")
+ ),
+ MTK_PIN(
+ 139, "GPIO139",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO139"),
+ MTK_FUNCTION(1, "AUD_DAT_MOSI1"),
+ MTK_FUNCTION(2, "AUD_DAT_MISO1"),
+ MTK_FUNCTION(3, "I2S1_DO")
+ ),
+ MTK_PIN(
+ 140, "GPIO140",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO140"),
+ MTK_FUNCTION(1, "AUD_CLK_MISO"),
+ MTK_FUNCTION(2, "AUD_CLK_MOSI"),
+ MTK_FUNCTION(3, "I2S2_MCK")
+ ),
+ MTK_PIN(
+ 141, "GPIO141",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO141"),
+ MTK_FUNCTION(1, "AUD_SYNC_MISO"),
+ MTK_FUNCTION(2, "AUD_SYNC_MOSI"),
+ MTK_FUNCTION(3, "I2S2_BCK")
+ ),
+ MTK_PIN(
+ 142, "GPIO142",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO142"),
+ MTK_FUNCTION(1, "AUD_DAT_MISO0"),
+ MTK_FUNCTION(2, "AUD_DAT_MOSI0"),
+ MTK_FUNCTION(3, "I2S2_LRCK")
+ ),
+ MTK_PIN(
+ 143, "GPIO143",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO143"),
+ MTK_FUNCTION(1, "AUD_DAT_MISO1"),
+ MTK_FUNCTION(2, "AUD_DAT_MOSI1"),
+ MTK_FUNCTION(3, "I2S2_DI")
+ ),
+ MTK_PIN(
+ 144, "GPIO144",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO144"),
+ MTK_FUNCTION(1, "PWRAP_SPI0_MI"),
+ MTK_FUNCTION(2, "PWRAP_SPI0_MO")
+ ),
+ MTK_PIN(
+ 145, "GPIO145",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO145"),
+ MTK_FUNCTION(1, "PWRAP_SPI0_CSN")
+ ),
+ MTK_PIN(
+ 146, "GPIO146",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO146"),
+ MTK_FUNCTION(1, "PWRAP_SPI0_MO"),
+ MTK_FUNCTION(2, "PWRAP_SPI0_MI")
+ ),
+ MTK_PIN(
+ 147, "GPIO147",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO147"),
+ MTK_FUNCTION(1, "PWRAP_SPI0_CK")
+ ),
+ MTK_PIN(
+ 148, "GPIO148",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO148"),
+ MTK_FUNCTION(1, "SRCLKENA0")
+ ),
+ MTK_PIN(
+ 149, "GPIO149",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO149"),
+ MTK_FUNCTION(1, "SRCLKENA1")
+ ),
+ MTK_PIN(
+ 150, "GPIO150",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO150"),
+ MTK_FUNCTION(1, "PWM0"),
+ MTK_FUNCTION(2, "CMFLASH"),
+ MTK_FUNCTION(3, "ANT_SEL3"),
+ MTK_FUNCTION(5, "MD_URXD0"),
+ MTK_FUNCTION(6, "TP_URXD2_AO")
+ ),
+ MTK_PIN(
+ 151, "GPIO151",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO151"),
+ MTK_FUNCTION(1, "PWM1"),
+ MTK_FUNCTION(2, "CMVREF0"),
+ MTK_FUNCTION(3, "ANT_SEL4"),
+ MTK_FUNCTION(5, "MD_UTXD0"),
+ MTK_FUNCTION(6, "TP_UTXD2_AO")
+ ),
+ MTK_PIN(
+ 152, "GPIO152",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO152"),
+ MTK_FUNCTION(1, "PWM2"),
+ MTK_FUNCTION(2, "CMVREF1"),
+ MTK_FUNCTION(3, "ANT_SEL5"),
+ MTK_FUNCTION(5, "MD_URXD1"),
+ MTK_FUNCTION(6, "TP_UCTS1_AO")
+ ),
+ MTK_PIN(
+ 153, "GPIO153",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO153"),
+ MTK_FUNCTION(1, "PWM3"),
+ MTK_FUNCTION(2, "CLKM0"),
+ MTK_FUNCTION(3, "ANT_SEL6"),
+ MTK_FUNCTION(5, "MD_UTXD1"),
+ MTK_FUNCTION(6, "TP_URTS1_AO")
+ ),
+ MTK_PIN(
+ 154, "GPIO154",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO154"),
+ MTK_FUNCTION(1, "PWM5"),
+ MTK_FUNCTION(2, "CLKM2"),
+ MTK_FUNCTION(3, "USB_DRVVBUS"),
+ MTK_FUNCTION(5, "PTA_TXD"),
+ MTK_FUNCTION(6, "CONN_UART0_TXD")
+ ),
+ MTK_PIN(
+ 155, "GPIO155",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO155"),
+ MTK_FUNCTION(1, "SPI0_MI"),
+ MTK_FUNCTION(2, "IDDIG"),
+ MTK_FUNCTION(3, "AGPS_SYNC"),
+ MTK_FUNCTION(4, "TP_GPIO0_AO"),
+ MTK_FUNCTION(5, "MFG_JTAG_TDO"),
+ MTK_FUNCTION(6, "DFD_TDO"),
+ MTK_FUNCTION(7, "JTDO_SEL1")
+ ),
+ MTK_PIN(
+ 156, "GPIO156",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO156"),
+ MTK_FUNCTION(1, "SPI0_CSB"),
+ MTK_FUNCTION(2, "USB_DRVVBUS"),
+ MTK_FUNCTION(3, "DVFSRC_EXT_REQ"),
+ MTK_FUNCTION(4, "TP_GPIO1_AO"),
+ MTK_FUNCTION(5, "MFG_JTAG_TMS"),
+ MTK_FUNCTION(6, "DFD_TMS"),
+ MTK_FUNCTION(7, "JTMS_SEL1")
+ ),
+ MTK_PIN(
+ 157, "GPIO157",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO157"),
+ MTK_FUNCTION(1, "SPI0_MO"),
+ MTK_FUNCTION(2, "MD_INT1_C2K_UIM0_HOT_PLUG"),
+ MTK_FUNCTION(3, "CLKM0"),
+ MTK_FUNCTION(4, "TP_GPIO2_AO"),
+ MTK_FUNCTION(5, "MFG_JTAG_TDI"),
+ MTK_FUNCTION(6, "DFD_TDI"),
+ MTK_FUNCTION(7, "JTDI_SEL1")
+ ),
+ MTK_PIN(
+ 158, "GPIO158",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO158"),
+ MTK_FUNCTION(1, "SPI0_CLK"),
+ MTK_FUNCTION(2, "MD_INT2_C2K_UIM1_HOT_PLUG"),
+ MTK_FUNCTION(3, "EXT_FRAME_SYNC"),
+ MTK_FUNCTION(4, "TP_GPIO3_AO"),
+ MTK_FUNCTION(5, "MFG_JTAG_TCK"),
+ MTK_FUNCTION(6, "DFD_TCK_XI"),
+ MTK_FUNCTION(7, "JTCK_SEL1")
+ ),
+ MTK_PIN(
+ 159, "GPIO159",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO159"),
+ MTK_FUNCTION(1, "PWM4"),
+ MTK_FUNCTION(2, "CLKM1"),
+ MTK_FUNCTION(3, "ANT_SEL7"),
+ MTK_FUNCTION(5, "PTA_RXD"),
+ MTK_FUNCTION(6, "CONN_UART0_RXD")
+ ),
+ MTK_PIN(
+ 160, "GPIO160",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO160"),
+ MTK_FUNCTION(1, "CLKM0"),
+ MTK_FUNCTION(2, "PWM2"),
+ MTK_FUNCTION(3, "EXT_FRAME_SYNC"),
+ MTK_FUNCTION(4, "TP_GPIO5_AO"),
+ MTK_FUNCTION(5, "AGPS_SYNC"),
+ MTK_FUNCTION(6, "DVFSRC_EXT_REQ")
+ ),
+ MTK_PIN(
+ 161, "GPIO161",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO161"),
+ MTK_FUNCTION(1, "SCL6"),
+ MTK_FUNCTION(2, "SCL_6306"),
+ MTK_FUNCTION(3, "TP_GPIO6_AO"),
+ MTK_FUNCTION(4, "KPCOL6"),
+ MTK_FUNCTION(5, "PTA_RXD"),
+ MTK_FUNCTION(6, "CONN_UART0_RXD")
+ ),
+ MTK_PIN(
+ 162, "GPIO162",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO162"),
+ MTK_FUNCTION(1, "SDA6"),
+ MTK_FUNCTION(2, "SDA_6306"),
+ MTK_FUNCTION(3, "TP_GPIO7_AO"),
+ MTK_FUNCTION(4, "KPCOL7"),
+ MTK_FUNCTION(5, "PTA_TXD"),
+ MTK_FUNCTION(6, "CONN_UART0_TXD")
+ ),
+ MTK_PIN(
+ 163, "GPIO163",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO163")
+ ),
+ MTK_PIN(
+ 164, "GPIO164",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO164")
+ ),
+ MTK_PIN(
+ 165, "GPIO165",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO165")
+ ),
+ MTK_PIN(
+ 166, "GPIO166",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO166")
+ ),
+ MTK_PIN(
+ 167, "GPIO167",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO167")
+ ),
+ MTK_PIN(
+ 168, "GPIO168",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO168")
+ ),
+ MTK_PIN(
+ 169, "GPIO169",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO169")
+ ),
+ MTK_PIN(
+ 170, "GPIO170",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO170")
+ ),
+ MTK_PIN(
+ 171, "GPIO171",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO171")
+ ),
+ MTK_PIN(
+ 172, "GPIO172",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO172")
+ ),
+ MTK_PIN(
+ 173, "GPIO173",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO173")
+ ),
+ MTK_PIN(
+ 174, "GPIO174",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO174")
+ ),
+ MTK_PIN(
+ 175, "GPIO175",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO175")
+ ),
+ MTK_PIN(
+ 176, "GPIO176",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO176")
+ ),
+ MTK_PIN(
+ 177, "GPIO177",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO177")
+ ),
+ MTK_PIN(
+ 178, "GPIO178",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO178")
+ ),
+ MTK_PIN(
+ 179, "GPIO179",
+ MTK_EINT_FUNCTION(0, 151),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO179")
+ ),
+};
+
+#endif /* __PINCTRL_MTK_MT6765_H */
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-mt8183.h b/drivers/pinctrl/mediatek/pinctrl-mtk-mt8183.h
new file mode 100644
index 000000000000..79adf5b8a186
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-mt8183.h
@@ -0,0 +1,1916 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ *
+ * Author: Zhiyong Tao <zhiyong.tao@mediatek.com>
+ *
+ */
+
+#ifndef __PINCTRL_MTK_MT8183_H
+#define __PINCTRL_MTK_MT8183_H
+
+#include "pinctrl-paris.h"
+
+static struct mtk_pin_desc mtk_pins_mt8183[] = {
+ MTK_PIN(
+ 0, "GPIO0",
+ MTK_EINT_FUNCTION(0, 0),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO0"),
+ MTK_FUNCTION(1, "MRG_SYNC"),
+ MTK_FUNCTION(2, "PCM0_SYNC"),
+ MTK_FUNCTION(3, "TP_GPIO0_AO"),
+ MTK_FUNCTION(4, "SRCLKENAI0"),
+ MTK_FUNCTION(5, "SCP_SPI2_CS"),
+ MTK_FUNCTION(6, "I2S3_MCK"),
+ MTK_FUNCTION(7, "SPI2_CSB")
+ ),
+ MTK_PIN(
+ 1, "GPIO1",
+ MTK_EINT_FUNCTION(0, 1),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO1"),
+ MTK_FUNCTION(1, "MRG_CLK"),
+ MTK_FUNCTION(2, "PCM0_CLK"),
+ MTK_FUNCTION(3, "TP_GPIO1_AO"),
+ MTK_FUNCTION(4, "CLKM3"),
+ MTK_FUNCTION(5, "SCP_SPI2_MO"),
+ MTK_FUNCTION(6, "I2S3_BCK"),
+ MTK_FUNCTION(7, "SPI2_MO")
+ ),
+ MTK_PIN(
+ 2, "GPIO2",
+ MTK_EINT_FUNCTION(0, 2),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO2"),
+ MTK_FUNCTION(1, "MRG_DO"),
+ MTK_FUNCTION(2, "PCM0_DO"),
+ MTK_FUNCTION(3, "TP_GPIO2_AO"),
+ MTK_FUNCTION(4, "SCL6"),
+ MTK_FUNCTION(5, "SCP_SPI2_CK"),
+ MTK_FUNCTION(6, "I2S3_LRCK"),
+ MTK_FUNCTION(7, "SPI2_CLK")
+ ),
+ MTK_PIN(
+ 3, "GPIO3",
+ MTK_EINT_FUNCTION(0, 3),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO3"),
+ MTK_FUNCTION(1, "MRG_DI"),
+ MTK_FUNCTION(2, "PCM0_DI"),
+ MTK_FUNCTION(3, "TP_GPIO3_AO"),
+ MTK_FUNCTION(4, "SDA6"),
+ MTK_FUNCTION(5, "TDM_MCK"),
+ MTK_FUNCTION(6, "I2S3_DO"),
+ MTK_FUNCTION(7, "SCP_VREQ_VAO")
+ ),
+ MTK_PIN(
+ 4, "GPIO4",
+ MTK_EINT_FUNCTION(0, 4),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO4"),
+ MTK_FUNCTION(1, "PWM_B"),
+ MTK_FUNCTION(2, "I2S0_MCK"),
+ MTK_FUNCTION(3, "SSPM_UTXD_AO"),
+ MTK_FUNCTION(4, "MD_URXD1"),
+ MTK_FUNCTION(5, "TDM_BCK"),
+ MTK_FUNCTION(6, "TP_GPIO4_AO"),
+ MTK_FUNCTION(7, "DAP_MD32_SWD")
+ ),
+ MTK_PIN(
+ 5, "GPIO5",
+ MTK_EINT_FUNCTION(0, 5),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO5"),
+ MTK_FUNCTION(1, "PWM_C"),
+ MTK_FUNCTION(2, "I2S0_BCK"),
+ MTK_FUNCTION(3, "SSPM_URXD_AO"),
+ MTK_FUNCTION(4, "MD_UTXD1"),
+ MTK_FUNCTION(5, "TDM_LRCK"),
+ MTK_FUNCTION(6, "TP_GPIO5_AO"),
+ MTK_FUNCTION(7, "DAP_MD32_SWCK")
+ ),
+ MTK_PIN(
+ 6, "GPIO6",
+ MTK_EINT_FUNCTION(0, 6),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO6"),
+ MTK_FUNCTION(1, "PWM_A"),
+ MTK_FUNCTION(2, "I2S0_LRCK"),
+ MTK_FUNCTION(3, "IDDIG"),
+ MTK_FUNCTION(4, "MD_URXD0"),
+ MTK_FUNCTION(5, "TDM_DATA0"),
+ MTK_FUNCTION(6, "TP_GPIO6_AO"),
+ MTK_FUNCTION(7, "CMFLASH")
+ ),
+ MTK_PIN(
+ 7, "GPIO7",
+ MTK_EINT_FUNCTION(0, 7),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO7"),
+ MTK_FUNCTION(1, "SPI1_B_MI"),
+ MTK_FUNCTION(2, "I2S0_DI"),
+ MTK_FUNCTION(3, "USB_DRVVBUS"),
+ MTK_FUNCTION(4, "MD_UTXD0"),
+ MTK_FUNCTION(5, "TDM_DATA1"),
+ MTK_FUNCTION(6, "TP_GPIO7_AO"),
+ MTK_FUNCTION(7, "DVFSRC_EXT_REQ")
+ ),
+ MTK_PIN(
+ 8, "GPIO8",
+ MTK_EINT_FUNCTION(0, 8),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO8"),
+ MTK_FUNCTION(1, "SPI1_B_CSB"),
+ MTK_FUNCTION(2, "ANT_SEL3"),
+ MTK_FUNCTION(3, "SCL7"),
+ MTK_FUNCTION(4, "CONN_MCU_TRST_B"),
+ MTK_FUNCTION(5, "TDM_DATA2"),
+ MTK_FUNCTION(6, "MD_INT0"),
+ MTK_FUNCTION(7, "JTRSTN_SEL1")
+ ),
+ MTK_PIN(
+ 9, "GPIO9",
+ MTK_EINT_FUNCTION(0, 9),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO9"),
+ MTK_FUNCTION(1, "SPI1_B_MO"),
+ MTK_FUNCTION(2, "ANT_SEL4"),
+ MTK_FUNCTION(3, "CMMCLK2"),
+ MTK_FUNCTION(4, "CONN_MCU_DBGACK_N"),
+ MTK_FUNCTION(5, "SSPM_JTAG_TRSTN"),
+ MTK_FUNCTION(6, "IO_JTAG_TRSTN"),
+ MTK_FUNCTION(7, "DBG_MON_B10")
+ ),
+ MTK_PIN(
+ 10, "GPIO10",
+ MTK_EINT_FUNCTION(0, 10),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO10"),
+ MTK_FUNCTION(1, "SPI1_B_CLK"),
+ MTK_FUNCTION(2, "ANT_SEL5"),
+ MTK_FUNCTION(3, "CMMCLK3"),
+ MTK_FUNCTION(4, "CONN_MCU_DBGI_N"),
+ MTK_FUNCTION(5, "TDM_DATA3"),
+ MTK_FUNCTION(6, "EXT_FRAME_SYNC"),
+ MTK_FUNCTION(7, "DBG_MON_B11")
+ ),
+ MTK_PIN(
+ 11, "GPIO11",
+ MTK_EINT_FUNCTION(0, 11),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO11"),
+ MTK_FUNCTION(1, "TP_URXD1_AO"),
+ MTK_FUNCTION(2, "IDDIG"),
+ MTK_FUNCTION(3, "SCL6"),
+ MTK_FUNCTION(4, "UCTS1"),
+ MTK_FUNCTION(5, "UCTS0"),
+ MTK_FUNCTION(6, "SRCLKENAI1"),
+ MTK_FUNCTION(7, "I2S5_MCK")
+ ),
+ MTK_PIN(
+ 12, "GPIO12",
+ MTK_EINT_FUNCTION(0, 12),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO12"),
+ MTK_FUNCTION(1, "TP_UTXD1_AO"),
+ MTK_FUNCTION(2, "USB_DRVVBUS"),
+ MTK_FUNCTION(3, "SDA6"),
+ MTK_FUNCTION(4, "URTS1"),
+ MTK_FUNCTION(5, "URTS0"),
+ MTK_FUNCTION(6, "I2S2_DI2"),
+ MTK_FUNCTION(7, "I2S5_BCK")
+ ),
+ MTK_PIN(
+ 13, "GPIO13",
+ MTK_EINT_FUNCTION(0, 13),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO13"),
+ MTK_FUNCTION(1, "DBPI_D0"),
+ MTK_FUNCTION(2, "SPI5_MI"),
+ MTK_FUNCTION(3, "PCM0_SYNC"),
+ MTK_FUNCTION(4, "MD_URXD0"),
+ MTK_FUNCTION(5, "ANT_SEL3"),
+ MTK_FUNCTION(6, "I2S0_MCK"),
+ MTK_FUNCTION(7, "DBG_MON_B15")
+ ),
+ MTK_PIN(
+ 14, "GPIO14",
+ MTK_EINT_FUNCTION(0, 14),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO14"),
+ MTK_FUNCTION(1, "DBPI_D1"),
+ MTK_FUNCTION(2, "SPI5_CSB"),
+ MTK_FUNCTION(3, "PCM0_CLK"),
+ MTK_FUNCTION(4, "MD_UTXD0"),
+ MTK_FUNCTION(5, "ANT_SEL4"),
+ MTK_FUNCTION(6, "I2S0_BCK"),
+ MTK_FUNCTION(7, "DBG_MON_B16")
+ ),
+ MTK_PIN(
+ 15, "GPIO15",
+ MTK_EINT_FUNCTION(0, 15),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO15"),
+ MTK_FUNCTION(1, "DBPI_D2"),
+ MTK_FUNCTION(2, "SPI5_MO"),
+ MTK_FUNCTION(3, "PCM0_DO"),
+ MTK_FUNCTION(4, "MD_URXD1"),
+ MTK_FUNCTION(5, "ANT_SEL5"),
+ MTK_FUNCTION(6, "I2S0_LRCK"),
+ MTK_FUNCTION(7, "DBG_MON_B17")
+ ),
+ MTK_PIN(
+ 16, "GPIO16",
+ MTK_EINT_FUNCTION(0, 16),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO16"),
+ MTK_FUNCTION(1, "DBPI_D3"),
+ MTK_FUNCTION(2, "SPI5_CLK"),
+ MTK_FUNCTION(3, "PCM0_DI"),
+ MTK_FUNCTION(4, "MD_UTXD1"),
+ MTK_FUNCTION(5, "ANT_SEL6"),
+ MTK_FUNCTION(6, "I2S0_DI"),
+ MTK_FUNCTION(7, "DBG_MON_B23")
+ ),
+ MTK_PIN(
+ 17, "GPIO17",
+ MTK_EINT_FUNCTION(0, 17),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO17"),
+ MTK_FUNCTION(1, "DBPI_D4"),
+ MTK_FUNCTION(2, "SPI4_MI"),
+ MTK_FUNCTION(3, "CONN_MCU_TRST_B"),
+ MTK_FUNCTION(4, "MD_INT0"),
+ MTK_FUNCTION(5, "ANT_SEL7"),
+ MTK_FUNCTION(6, "I2S3_MCK"),
+ MTK_FUNCTION(7, "DBG_MON_A1")
+ ),
+ MTK_PIN(
+ 18, "GPIO18",
+ MTK_EINT_FUNCTION(0, 18),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO18"),
+ MTK_FUNCTION(1, "DBPI_D5"),
+ MTK_FUNCTION(2, "SPI4_CSB"),
+ MTK_FUNCTION(3, "CONN_MCU_DBGI_N"),
+ MTK_FUNCTION(4, "MD_INT0"),
+ MTK_FUNCTION(5, "SCP_VREQ_VAO"),
+ MTK_FUNCTION(6, "I2S3_BCK"),
+ MTK_FUNCTION(7, "DBG_MON_A2")
+ ),
+ MTK_PIN(
+ 19, "GPIO19",
+ MTK_EINT_FUNCTION(0, 19),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO19"),
+ MTK_FUNCTION(1, "DBPI_D6"),
+ MTK_FUNCTION(2, "SPI4_MO"),
+ MTK_FUNCTION(3, "CONN_MCU_TDO"),
+ MTK_FUNCTION(4, "MD_INT2_C2K_UIM1_HOT_PLUG"),
+ MTK_FUNCTION(5, "URXD1"),
+ MTK_FUNCTION(6, "I2S3_LRCK"),
+ MTK_FUNCTION(7, "DBG_MON_A3")
+ ),
+ MTK_PIN(
+ 20, "GPIO20",
+ MTK_EINT_FUNCTION(0, 20),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO20"),
+ MTK_FUNCTION(1, "DBPI_D7"),
+ MTK_FUNCTION(2, "SPI4_CLK"),
+ MTK_FUNCTION(3, "CONN_MCU_DBGACK_N"),
+ MTK_FUNCTION(4, "MD_INT1_C2K_UIM0_HOT_PLUG"),
+ MTK_FUNCTION(5, "UTXD1"),
+ MTK_FUNCTION(6, "I2S3_DO"),
+ MTK_FUNCTION(7, "DBG_MON_A19")
+ ),
+ MTK_PIN(
+ 21, "GPIO21",
+ MTK_EINT_FUNCTION(0, 21),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO21"),
+ MTK_FUNCTION(1, "DBPI_D8"),
+ MTK_FUNCTION(2, "SPI3_MI"),
+ MTK_FUNCTION(3, "CONN_MCU_TMS"),
+ MTK_FUNCTION(4, "DAP_MD32_SWD"),
+ MTK_FUNCTION(5, "CONN_MCU_AICE_TMSC"),
+ MTK_FUNCTION(6, "I2S2_MCK"),
+ MTK_FUNCTION(7, "DBG_MON_B5")
+ ),
+ MTK_PIN(
+ 22, "GPIO22",
+ MTK_EINT_FUNCTION(0, 22),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO22"),
+ MTK_FUNCTION(1, "DBPI_D9"),
+ MTK_FUNCTION(2, "SPI3_CSB"),
+ MTK_FUNCTION(3, "CONN_MCU_TCK"),
+ MTK_FUNCTION(4, "DAP_MD32_SWCK"),
+ MTK_FUNCTION(5, "CONN_MCU_AICE_TCKC"),
+ MTK_FUNCTION(6, "I2S2_BCK"),
+ MTK_FUNCTION(7, "DBG_MON_B6")
+ ),
+ MTK_PIN(
+ 23, "GPIO23",
+ MTK_EINT_FUNCTION(0, 23),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO23"),
+ MTK_FUNCTION(1, "DBPI_D10"),
+ MTK_FUNCTION(2, "SPI3_MO"),
+ MTK_FUNCTION(3, "CONN_MCU_TDI"),
+ MTK_FUNCTION(4, "UCTS1"),
+ MTK_FUNCTION(5, "EXT_FRAME_SYNC"),
+ MTK_FUNCTION(6, "I2S2_LRCK"),
+ MTK_FUNCTION(7, "DBG_MON_B7")
+ ),
+ MTK_PIN(
+ 24, "GPIO24",
+ MTK_EINT_FUNCTION(0, 24),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO24"),
+ MTK_FUNCTION(1, "DBPI_D11"),
+ MTK_FUNCTION(2, "SPI3_CLK"),
+ MTK_FUNCTION(3, "SRCLKENAI0"),
+ MTK_FUNCTION(4, "URTS1"),
+ MTK_FUNCTION(5, "IO_JTAG_TCK"),
+ MTK_FUNCTION(6, "I2S2_DI"),
+ MTK_FUNCTION(7, "DBG_MON_B31")
+ ),
+ MTK_PIN(
+ 25, "GPIO25",
+ MTK_EINT_FUNCTION(0, 25),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO25"),
+ MTK_FUNCTION(1, "DBPI_HSYNC"),
+ MTK_FUNCTION(2, "ANT_SEL0"),
+ MTK_FUNCTION(3, "SCL6"),
+ MTK_FUNCTION(4, "KPCOL2"),
+ MTK_FUNCTION(5, "IO_JTAG_TMS"),
+ MTK_FUNCTION(6, "I2S1_MCK"),
+ MTK_FUNCTION(7, "DBG_MON_B0")
+ ),
+ MTK_PIN(
+ 26, "GPIO26",
+ MTK_EINT_FUNCTION(0, 26),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO26"),
+ MTK_FUNCTION(1, "DBPI_VSYNC"),
+ MTK_FUNCTION(2, "ANT_SEL1"),
+ MTK_FUNCTION(3, "SDA6"),
+ MTK_FUNCTION(4, "KPROW2"),
+ MTK_FUNCTION(5, "IO_JTAG_TDI"),
+ MTK_FUNCTION(6, "I2S1_BCK"),
+ MTK_FUNCTION(7, "DBG_MON_B1")
+ ),
+ MTK_PIN(
+ 27, "GPIO27",
+ MTK_EINT_FUNCTION(0, 27),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO27"),
+ MTK_FUNCTION(1, "DBPI_DE"),
+ MTK_FUNCTION(2, "ANT_SEL2"),
+ MTK_FUNCTION(3, "SCL7"),
+ MTK_FUNCTION(4, "DMIC_CLK"),
+ MTK_FUNCTION(5, "IO_JTAG_TDO"),
+ MTK_FUNCTION(6, "I2S1_LRCK"),
+ MTK_FUNCTION(7, "DBG_MON_B9")
+ ),
+ MTK_PIN(
+ 28, "GPIO28",
+ MTK_EINT_FUNCTION(0, 28),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO28"),
+ MTK_FUNCTION(1, "DBPI_CK"),
+ MTK_FUNCTION(2, "DVFSRC_EXT_REQ"),
+ MTK_FUNCTION(3, "SDA7"),
+ MTK_FUNCTION(4, "DMIC_DAT"),
+ MTK_FUNCTION(5, "IO_JTAG_TRSTN"),
+ MTK_FUNCTION(6, "I2S1_DO"),
+ MTK_FUNCTION(7, "DBG_MON_B32")
+ ),
+ MTK_PIN(
+ 29, "GPIO29",
+ MTK_EINT_FUNCTION(0, 29),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO29"),
+ MTK_FUNCTION(1, "MSDC1_CLK"),
+ MTK_FUNCTION(2, "IO_JTAG_TCK"),
+ MTK_FUNCTION(3, "UDI_TCK"),
+ MTK_FUNCTION(4, "CONN_DSP_JCK"),
+ MTK_FUNCTION(5, "SSPM_JTAG_TCK"),
+ MTK_FUNCTION(6, "PCM1_CLK"),
+ MTK_FUNCTION(7, "DBG_MON_A6")
+ ),
+ MTK_PIN(
+ 30, "GPIO30",
+ MTK_EINT_FUNCTION(0, 30),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO30"),
+ MTK_FUNCTION(1, "MSDC1_DAT3"),
+ MTK_FUNCTION(2, "DAP_MD32_SWD"),
+ MTK_FUNCTION(3, "CONN_MCU_AICE_TMSC"),
+ MTK_FUNCTION(4, "CONN_DSP_JINTP"),
+ MTK_FUNCTION(5, "SSPM_JTAG_TRSTN"),
+ MTK_FUNCTION(6, "PCM1_DI"),
+ MTK_FUNCTION(7, "DBG_MON_A7")
+ ),
+ MTK_PIN(
+ 31, "GPIO31",
+ MTK_EINT_FUNCTION(0, 31),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO31"),
+ MTK_FUNCTION(1, "MSDC1_CMD"),
+ MTK_FUNCTION(2, "IO_JTAG_TMS"),
+ MTK_FUNCTION(3, "UDI_TMS"),
+ MTK_FUNCTION(4, "CONN_DSP_JMS"),
+ MTK_FUNCTION(5, "SSPM_JTAG_TMS"),
+ MTK_FUNCTION(6, "PCM1_SYNC"),
+ MTK_FUNCTION(7, "DBG_MON_A8")
+ ),
+ MTK_PIN(
+ 32, "GPIO32",
+ MTK_EINT_FUNCTION(0, 32),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO32"),
+ MTK_FUNCTION(1, "MSDC1_DAT0"),
+ MTK_FUNCTION(2, "IO_JTAG_TDI"),
+ MTK_FUNCTION(3, "UDI_TDI"),
+ MTK_FUNCTION(4, "CONN_DSP_JDI"),
+ MTK_FUNCTION(5, "SSPM_JTAG_TDI"),
+ MTK_FUNCTION(6, "PCM1_DO0"),
+ MTK_FUNCTION(7, "DBG_MON_A9")
+ ),
+ MTK_PIN(
+ 33, "GPIO33",
+ MTK_EINT_FUNCTION(0, 33),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO33"),
+ MTK_FUNCTION(1, "MSDC1_DAT2"),
+ MTK_FUNCTION(2, "IO_JTAG_TRSTN"),
+ MTK_FUNCTION(3, "UDI_NTRST"),
+ MTK_FUNCTION(4, "DAP_MD32_SWCK"),
+ MTK_FUNCTION(5, "CONN_MCU_AICE_TCKC"),
+ MTK_FUNCTION(6, "PCM1_DO2"),
+ MTK_FUNCTION(7, "DBG_MON_A10")
+ ),
+ MTK_PIN(
+ 34, "GPIO34",
+ MTK_EINT_FUNCTION(0, 34),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO34"),
+ MTK_FUNCTION(1, "MSDC1_DAT1"),
+ MTK_FUNCTION(2, "IO_JTAG_TDO"),
+ MTK_FUNCTION(3, "UDI_TDO"),
+ MTK_FUNCTION(4, "CONN_DSP_JDO"),
+ MTK_FUNCTION(5, "SSPM_JTAG_TDO"),
+ MTK_FUNCTION(6, "PCM1_DO1"),
+ MTK_FUNCTION(7, "DBG_MON_A11")
+ ),
+ MTK_PIN(
+ 35, "GPIO35",
+ MTK_EINT_FUNCTION(0, 35),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO35"),
+ MTK_FUNCTION(1, "MD1_SIM2_SIO"),
+ MTK_FUNCTION(2, "CCU_JTAG_TDO"),
+ MTK_FUNCTION(3, "MD1_SIM1_SIO"),
+ MTK_FUNCTION(5, "SCP_JTAG_TDO"),
+ MTK_FUNCTION(6, "CONN_DSP_JMS"),
+ MTK_FUNCTION(7, "DBG_MON_A28")
+ ),
+ MTK_PIN(
+ 36, "GPIO36",
+ MTK_EINT_FUNCTION(0, 36),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO36"),
+ MTK_FUNCTION(1, "MD1_SIM2_SRST"),
+ MTK_FUNCTION(2, "CCU_JTAG_TMS"),
+ MTK_FUNCTION(3, "MD1_SIM1_SRST"),
+ MTK_FUNCTION(4, "CONN_MCU_AICE_TMSC"),
+ MTK_FUNCTION(5, "SCP_JTAG_TMS"),
+ MTK_FUNCTION(6, "CONN_DSP_JINTP"),
+ MTK_FUNCTION(7, "DBG_MON_A29")
+ ),
+ MTK_PIN(
+ 37, "GPIO37",
+ MTK_EINT_FUNCTION(0, 37),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO37"),
+ MTK_FUNCTION(1, "MD1_SIM2_SCLK"),
+ MTK_FUNCTION(2, "CCU_JTAG_TDI"),
+ MTK_FUNCTION(3, "MD1_SIM1_SCLK"),
+ MTK_FUNCTION(5, "SCP_JTAG_TDI"),
+ MTK_FUNCTION(6, "CONN_DSP_JDO"),
+ MTK_FUNCTION(7, "DBG_MON_A30")
+ ),
+ MTK_PIN(
+ 38, "GPIO38",
+ MTK_EINT_FUNCTION(0, 38),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO38"),
+ MTK_FUNCTION(1, "MD1_SIM1_SCLK"),
+ MTK_FUNCTION(3, "MD1_SIM2_SCLK"),
+ MTK_FUNCTION(4, "CONN_MCU_AICE_TCKC"),
+ MTK_FUNCTION(7, "DBG_MON_A20")
+ ),
+ MTK_PIN(
+ 39, "GPIO39",
+ MTK_EINT_FUNCTION(0, 39),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO39"),
+ MTK_FUNCTION(1, "MD1_SIM1_SRST"),
+ MTK_FUNCTION(2, "CCU_JTAG_TCK"),
+ MTK_FUNCTION(3, "MD1_SIM2_SRST"),
+ MTK_FUNCTION(5, "SCP_JTAG_TCK"),
+ MTK_FUNCTION(6, "CONN_DSP_JCK"),
+ MTK_FUNCTION(7, "DBG_MON_A31")
+ ),
+ MTK_PIN(
+ 40, "GPIO40",
+ MTK_EINT_FUNCTION(0, 40),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO40"),
+ MTK_FUNCTION(1, "MD1_SIM1_SIO"),
+ MTK_FUNCTION(2, "CCU_JTAG_TRST"),
+ MTK_FUNCTION(3, "MD1_SIM2_SIO"),
+ MTK_FUNCTION(5, "SCP_JTAG_TRSTN"),
+ MTK_FUNCTION(6, "CONN_DSP_JDI"),
+ MTK_FUNCTION(7, "DBG_MON_A32")
+ ),
+ MTK_PIN(
+ 41, "GPIO41",
+ MTK_EINT_FUNCTION(0, 41),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO41"),
+ MTK_FUNCTION(1, "IDDIG"),
+ MTK_FUNCTION(2, "URXD1"),
+ MTK_FUNCTION(3, "UCTS0"),
+ MTK_FUNCTION(4, "SSPM_UTXD_AO"),
+ MTK_FUNCTION(5, "EXT_FRAME_SYNC"),
+ MTK_FUNCTION(6, "DMIC_CLK")
+ ),
+ MTK_PIN(
+ 42, "GPIO42",
+ MTK_EINT_FUNCTION(0, 42),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO42"),
+ MTK_FUNCTION(1, "USB_DRVVBUS"),
+ MTK_FUNCTION(2, "UTXD1"),
+ MTK_FUNCTION(3, "URTS0"),
+ MTK_FUNCTION(4, "SSPM_URXD_AO"),
+ MTK_FUNCTION(5, "EXT_FRAME_SYNC"),
+ MTK_FUNCTION(6, "DMIC_DAT")
+ ),
+ MTK_PIN(
+ 43, "GPIO43",
+ MTK_EINT_FUNCTION(0, 43),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO43"),
+ MTK_FUNCTION(1, "DISP_PWM")
+ ),
+ MTK_PIN(
+ 44, "GPIO44",
+ MTK_EINT_FUNCTION(0, 44),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO44"),
+ MTK_FUNCTION(1, "DSI_TE")
+ ),
+ MTK_PIN(
+ 45, "GPIO45",
+ MTK_EINT_FUNCTION(0, 45),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO45"),
+ MTK_FUNCTION(1, "LCM_RST")
+ ),
+ MTK_PIN(
+ 46, "GPIO46",
+ MTK_EINT_FUNCTION(0, 46),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO46"),
+ MTK_FUNCTION(1, "MD_INT2_C2K_UIM1_HOT_PLUG"),
+ MTK_FUNCTION(2, "URXD1"),
+ MTK_FUNCTION(3, "UCTS1"),
+ MTK_FUNCTION(4, "CCU_UTXD_AO"),
+ MTK_FUNCTION(5, "TP_UCTS1_AO"),
+ MTK_FUNCTION(6, "IDDIG"),
+ MTK_FUNCTION(7, "I2S5_LRCK")
+ ),
+ MTK_PIN(
+ 47, "GPIO47",
+ MTK_EINT_FUNCTION(0, 47),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO47"),
+ MTK_FUNCTION(1, "MD_INT1_C2K_UIM0_HOT_PLUG"),
+ MTK_FUNCTION(2, "UTXD1"),
+ MTK_FUNCTION(3, "URTS1"),
+ MTK_FUNCTION(4, "CCU_URXD_AO"),
+ MTK_FUNCTION(5, "TP_URTS1_AO"),
+ MTK_FUNCTION(6, "USB_DRVVBUS"),
+ MTK_FUNCTION(7, "I2S5_DO")
+ ),
+ MTK_PIN(
+ 48, "GPIO48",
+ MTK_EINT_FUNCTION(0, 48),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO48"),
+ MTK_FUNCTION(1, "SCL5")
+ ),
+ MTK_PIN(
+ 49, "GPIO49",
+ MTK_EINT_FUNCTION(0, 49),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO49"),
+ MTK_FUNCTION(1, "SDA5")
+ ),
+ MTK_PIN(
+ 50, "GPIO50",
+ MTK_EINT_FUNCTION(0, 50),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO50"),
+ MTK_FUNCTION(1, "SCL3")
+ ),
+ MTK_PIN(
+ 51, "GPIO51",
+ MTK_EINT_FUNCTION(0, 51),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO51"),
+ MTK_FUNCTION(1, "SDA3")
+ ),
+ MTK_PIN(
+ 52, "GPIO52",
+ MTK_EINT_FUNCTION(0, 52),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO52"),
+ MTK_FUNCTION(1, "BPI_ANT2")
+ ),
+ MTK_PIN(
+ 53, "GPIO53",
+ MTK_EINT_FUNCTION(0, 53),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO53"),
+ MTK_FUNCTION(1, "BPI_ANT0")
+ ),
+ MTK_PIN(
+ 54, "GPIO54",
+ MTK_EINT_FUNCTION(0, 54),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO54"),
+ MTK_FUNCTION(1, "BPI_OLAT1")
+ ),
+ MTK_PIN(
+ 55, "GPIO55",
+ MTK_EINT_FUNCTION(0, 55),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO55"),
+ MTK_FUNCTION(1, "BPI_BUS8")
+ ),
+ MTK_PIN(
+ 56, "GPIO56",
+ MTK_EINT_FUNCTION(0, 56),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO56"),
+ MTK_FUNCTION(1, "BPI_BUS9"),
+ MTK_FUNCTION(2, "SCL_6306")
+ ),
+ MTK_PIN(
+ 57, "GPIO57",
+ MTK_EINT_FUNCTION(0, 57),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO57"),
+ MTK_FUNCTION(1, "BPI_BUS10"),
+ MTK_FUNCTION(2, "SDA_6306")
+ ),
+ MTK_PIN(
+ 58, "GPIO58",
+ MTK_EINT_FUNCTION(0, 58),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO58"),
+ MTK_FUNCTION(1, "RFIC0_BSI_D2"),
+ MTK_FUNCTION(2, "SPM_BSI_D2"),
+ MTK_FUNCTION(3, "PWM_B")
+ ),
+ MTK_PIN(
+ 59, "GPIO59",
+ MTK_EINT_FUNCTION(0, 59),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO59"),
+ MTK_FUNCTION(1, "RFIC0_BSI_D1"),
+ MTK_FUNCTION(2, "SPM_BSI_D1")
+ ),
+ MTK_PIN(
+ 60, "GPIO60",
+ MTK_EINT_FUNCTION(0, 60),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO60"),
+ MTK_FUNCTION(1, "RFIC0_BSI_D0"),
+ MTK_FUNCTION(2, "SPM_BSI_D0")
+ ),
+ MTK_PIN(
+ 61, "GPIO61",
+ MTK_EINT_FUNCTION(0, 61),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO61"),
+ MTK_FUNCTION(1, "MIPI1_SDATA")
+ ),
+ MTK_PIN(
+ 62, "GPIO62",
+ MTK_EINT_FUNCTION(0, 62),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO62"),
+ MTK_FUNCTION(1, "MIPI1_SCLK")
+ ),
+ MTK_PIN(
+ 63, "GPIO63",
+ MTK_EINT_FUNCTION(0, 63),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO63"),
+ MTK_FUNCTION(1, "MIPI0_SDATA")
+ ),
+ MTK_PIN(
+ 64, "GPIO64",
+ MTK_EINT_FUNCTION(0, 64),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO64"),
+ MTK_FUNCTION(1, "MIPI0_SCLK")
+ ),
+ MTK_PIN(
+ 65, "GPIO65",
+ MTK_EINT_FUNCTION(0, 65),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO65"),
+ MTK_FUNCTION(1, "MIPI3_SDATA"),
+ MTK_FUNCTION(2, "BPI_OLAT2")
+ ),
+ MTK_PIN(
+ 66, "GPIO66",
+ MTK_EINT_FUNCTION(0, 66),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO66"),
+ MTK_FUNCTION(1, "MIPI3_SCLK"),
+ MTK_FUNCTION(2, "BPI_OLAT3")
+ ),
+ MTK_PIN(
+ 67, "GPIO67",
+ MTK_EINT_FUNCTION(0, 67),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO67"),
+ MTK_FUNCTION(1, "MIPI2_SDATA")
+ ),
+ MTK_PIN(
+ 68, "GPIO68",
+ MTK_EINT_FUNCTION(0, 68),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO68"),
+ MTK_FUNCTION(1, "MIPI2_SCLK")
+ ),
+ MTK_PIN(
+ 69, "GPIO69",
+ MTK_EINT_FUNCTION(0, 69),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO69"),
+ MTK_FUNCTION(1, "BPI_BUS7")
+ ),
+ MTK_PIN(
+ 70, "GPIO70",
+ MTK_EINT_FUNCTION(0, 70),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO70"),
+ MTK_FUNCTION(1, "BPI_BUS6")
+ ),
+ MTK_PIN(
+ 71, "GPIO71",
+ MTK_EINT_FUNCTION(0, 71),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO71"),
+ MTK_FUNCTION(1, "BPI_BUS5")
+ ),
+ MTK_PIN(
+ 72, "GPIO72",
+ MTK_EINT_FUNCTION(0, 72),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO72"),
+ MTK_FUNCTION(1, "BPI_BUS4")
+ ),
+ MTK_PIN(
+ 73, "GPIO73",
+ MTK_EINT_FUNCTION(0, 73),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO73"),
+ MTK_FUNCTION(1, "BPI_BUS3")
+ ),
+ MTK_PIN(
+ 74, "GPIO74",
+ MTK_EINT_FUNCTION(0, 74),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO74"),
+ MTK_FUNCTION(1, "BPI_BUS2")
+ ),
+ MTK_PIN(
+ 75, "GPIO75",
+ MTK_EINT_FUNCTION(0, 75),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO75"),
+ MTK_FUNCTION(1, "BPI_BUS1")
+ ),
+ MTK_PIN(
+ 76, "GPIO76",
+ MTK_EINT_FUNCTION(0, 76),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO76"),
+ MTK_FUNCTION(1, "BPI_BUS0")
+ ),
+ MTK_PIN(
+ 77, "GPIO77",
+ MTK_EINT_FUNCTION(0, 77),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO77"),
+ MTK_FUNCTION(1, "BPI_ANT1")
+ ),
+ MTK_PIN(
+ 78, "GPIO78",
+ MTK_EINT_FUNCTION(0, 78),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO78"),
+ MTK_FUNCTION(1, "BPI_OLAT0")
+ ),
+ MTK_PIN(
+ 79, "GPIO79",
+ MTK_EINT_FUNCTION(0, 79),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO79"),
+ MTK_FUNCTION(1, "BPI_PA_VM1"),
+ MTK_FUNCTION(2, "MIPI4_SDATA")
+ ),
+ MTK_PIN(
+ 80, "GPIO80",
+ MTK_EINT_FUNCTION(0, 80),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO80"),
+ MTK_FUNCTION(1, "BPI_PA_VM0"),
+ MTK_FUNCTION(2, "MIPI4_SCLK")
+ ),
+ MTK_PIN(
+ 81, "GPIO81",
+ MTK_EINT_FUNCTION(0, 81),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO81"),
+ MTK_FUNCTION(1, "SDA1")
+ ),
+ MTK_PIN(
+ 82, "GPIO82",
+ MTK_EINT_FUNCTION(0, 82),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO82"),
+ MTK_FUNCTION(1, "SDA0")
+ ),
+ MTK_PIN(
+ 83, "GPIO83",
+ MTK_EINT_FUNCTION(0, 83),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO83"),
+ MTK_FUNCTION(1, "SCL0")
+ ),
+ MTK_PIN(
+ 84, "GPIO84",
+ MTK_EINT_FUNCTION(0, 84),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO84"),
+ MTK_FUNCTION(1, "SCL1")
+ ),
+ MTK_PIN(
+ 85, "GPIO85",
+ MTK_EINT_FUNCTION(0, 85),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO85"),
+ MTK_FUNCTION(1, "SPI0_MI"),
+ MTK_FUNCTION(2, "SCP_SPI0_MI"),
+ MTK_FUNCTION(3, "CLKM3"),
+ MTK_FUNCTION(4, "I2S1_BCK"),
+ MTK_FUNCTION(5, "MFG_DFD_JTAG_TDO"),
+ MTK_FUNCTION(6, "DFD_TDO"),
+ MTK_FUNCTION(7, "JTDO_SEL1")
+ ),
+ MTK_PIN(
+ 86, "GPIO86",
+ MTK_EINT_FUNCTION(0, 86),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO86"),
+ MTK_FUNCTION(1, "SPI0_CSB"),
+ MTK_FUNCTION(2, "SCP_SPI0_CS"),
+ MTK_FUNCTION(3, "CLKM0"),
+ MTK_FUNCTION(4, "I2S1_LRCK"),
+ MTK_FUNCTION(5, "MFG_DFD_JTAG_TMS"),
+ MTK_FUNCTION(6, "DFD_TMS"),
+ MTK_FUNCTION(7, "JTMS_SEL1")
+ ),
+ MTK_PIN(
+ 87, "GPIO87",
+ MTK_EINT_FUNCTION(0, 87),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO87"),
+ MTK_FUNCTION(1, "SPI0_MO"),
+ MTK_FUNCTION(2, "SCP_SPI0_MO"),
+ MTK_FUNCTION(3, "SDA1"),
+ MTK_FUNCTION(4, "I2S1_DO"),
+ MTK_FUNCTION(5, "MFG_DFD_JTAG_TDI"),
+ MTK_FUNCTION(6, "DFD_TDI"),
+ MTK_FUNCTION(7, "JTDI_SEL1")
+ ),
+ MTK_PIN(
+ 88, "GPIO88",
+ MTK_EINT_FUNCTION(0, 88),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO88"),
+ MTK_FUNCTION(1, "SPI0_CLK"),
+ MTK_FUNCTION(2, "SCP_SPI0_CK"),
+ MTK_FUNCTION(3, "SCL1"),
+ MTK_FUNCTION(4, "I2S1_MCK"),
+ MTK_FUNCTION(5, "MFG_DFD_JTAG_TCK"),
+ MTK_FUNCTION(6, "DFD_TCK_XI"),
+ MTK_FUNCTION(7, "JTCK_SEL1")
+ ),
+ MTK_PIN(
+ 89, "GPIO89",
+ MTK_EINT_FUNCTION(0, 89),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO89"),
+ MTK_FUNCTION(1, "SRCLKENAI0"),
+ MTK_FUNCTION(2, "PWM_C"),
+ MTK_FUNCTION(3, "I2S5_BCK"),
+ MTK_FUNCTION(4, "ANT_SEL6"),
+ MTK_FUNCTION(5, "SDA8"),
+ MTK_FUNCTION(6, "CMVREF0"),
+ MTK_FUNCTION(7, "DBG_MON_A21")
+ ),
+ MTK_PIN(
+ 90, "GPIO90",
+ MTK_EINT_FUNCTION(0, 90),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO90"),
+ MTK_FUNCTION(1, "PWM_A"),
+ MTK_FUNCTION(2, "CMMCLK2"),
+ MTK_FUNCTION(3, "I2S5_LRCK"),
+ MTK_FUNCTION(4, "SCP_VREQ_VAO"),
+ MTK_FUNCTION(5, "SCL8"),
+ MTK_FUNCTION(6, "PTA_RXD"),
+ MTK_FUNCTION(7, "DBG_MON_A22")
+ ),
+ MTK_PIN(
+ 91, "GPIO91",
+ MTK_EINT_FUNCTION(0, 91),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO91"),
+ MTK_FUNCTION(1, "KPROW1"),
+ MTK_FUNCTION(2, "PWM_B"),
+ MTK_FUNCTION(3, "I2S5_DO"),
+ MTK_FUNCTION(4, "ANT_SEL7"),
+ MTK_FUNCTION(5, "CMMCLK3"),
+ MTK_FUNCTION(6, "PTA_TXD")
+ ),
+ MTK_PIN(
+ 92, "GPIO92",
+ MTK_EINT_FUNCTION(0, 92),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO92"),
+ MTK_FUNCTION(1, "KPROW0")
+ ),
+ MTK_PIN(
+ 93, "GPIO93",
+ MTK_EINT_FUNCTION(0, 93),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO93"),
+ MTK_FUNCTION(1, "KPCOL0"),
+ MTK_FUNCTION(7, "DBG_MON_B27")
+ ),
+ MTK_PIN(
+ 94, "GPIO94",
+ MTK_EINT_FUNCTION(0, 94),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO94"),
+ MTK_FUNCTION(1, "KPCOL1"),
+ MTK_FUNCTION(2, "I2S2_DI2"),
+ MTK_FUNCTION(3, "I2S5_MCK"),
+ MTK_FUNCTION(4, "CMMCLK2"),
+ MTK_FUNCTION(5, "SCP_SPI2_MI"),
+ MTK_FUNCTION(6, "SRCLKENAI1"),
+ MTK_FUNCTION(7, "SPI2_MI")
+ ),
+ MTK_PIN(
+ 95, "GPIO95",
+ MTK_EINT_FUNCTION(0, 95),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO95"),
+ MTK_FUNCTION(1, "URXD0"),
+ MTK_FUNCTION(2, "UTXD0"),
+ MTK_FUNCTION(3, "MD_URXD0"),
+ MTK_FUNCTION(4, "MD_URXD1"),
+ MTK_FUNCTION(5, "SSPM_URXD_AO"),
+ MTK_FUNCTION(6, "CCU_URXD_AO")
+ ),
+ MTK_PIN(
+ 96, "GPIO96",
+ MTK_EINT_FUNCTION(0, 96),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO96"),
+ MTK_FUNCTION(1, "UTXD0"),
+ MTK_FUNCTION(2, "URXD0"),
+ MTK_FUNCTION(3, "MD_UTXD0"),
+ MTK_FUNCTION(4, "MD_UTXD1"),
+ MTK_FUNCTION(5, "SSPM_UTXD_AO"),
+ MTK_FUNCTION(6, "CCU_UTXD_AO"),
+ MTK_FUNCTION(7, "DBG_MON_B2")
+ ),
+ MTK_PIN(
+ 97, "GPIO97",
+ MTK_EINT_FUNCTION(0, 97),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO97"),
+ MTK_FUNCTION(1, "UCTS0"),
+ MTK_FUNCTION(2, "I2S2_MCK"),
+ MTK_FUNCTION(3, "IDDIG"),
+ MTK_FUNCTION(4, "CONN_MCU_TDO"),
+ MTK_FUNCTION(5, "SSPM_JTAG_TDO"),
+ MTK_FUNCTION(6, "IO_JTAG_TDO"),
+ MTK_FUNCTION(7, "DBG_MON_B3")
+ ),
+ MTK_PIN(
+ 98, "GPIO98",
+ MTK_EINT_FUNCTION(0, 98),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO98"),
+ MTK_FUNCTION(1, "URTS0"),
+ MTK_FUNCTION(2, "I2S2_BCK"),
+ MTK_FUNCTION(3, "USB_DRVVBUS"),
+ MTK_FUNCTION(4, "CONN_MCU_TMS"),
+ MTK_FUNCTION(5, "SSPM_JTAG_TMS"),
+ MTK_FUNCTION(6, "IO_JTAG_TMS"),
+ MTK_FUNCTION(7, "DBG_MON_B4")
+ ),
+ MTK_PIN(
+ 99, "GPIO99",
+ MTK_EINT_FUNCTION(0, 99),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO99"),
+ MTK_FUNCTION(1, "CMMCLK0"),
+ MTK_FUNCTION(4, "CONN_MCU_AICE_TMSC"),
+ MTK_FUNCTION(7, "DBG_MON_B28")
+ ),
+ MTK_PIN(
+ 100, "GPIO100",
+ MTK_EINT_FUNCTION(0, 100),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO100"),
+ MTK_FUNCTION(1, "CMMCLK1"),
+ MTK_FUNCTION(2, "PWM_C"),
+ MTK_FUNCTION(3, "MD_INT1_C2K_UIM0_HOT_PLUG"),
+ MTK_FUNCTION(4, "CONN_MCU_AICE_TCKC"),
+ MTK_FUNCTION(7, "DBG_MON_B29")
+ ),
+ MTK_PIN(
+ 101, "GPIO101",
+ MTK_EINT_FUNCTION(0, 101),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO101"),
+ MTK_FUNCTION(1, "CLKM2"),
+ MTK_FUNCTION(2, "I2S2_LRCK"),
+ MTK_FUNCTION(3, "CMVREF1"),
+ MTK_FUNCTION(4, "CONN_MCU_TCK"),
+ MTK_FUNCTION(5, "SSPM_JTAG_TCK"),
+ MTK_FUNCTION(6, "IO_JTAG_TCK")
+ ),
+ MTK_PIN(
+ 102, "GPIO102",
+ MTK_EINT_FUNCTION(0, 102),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO102"),
+ MTK_FUNCTION(1, "CLKM1"),
+ MTK_FUNCTION(2, "I2S2_DI"),
+ MTK_FUNCTION(3, "DVFSRC_EXT_REQ"),
+ MTK_FUNCTION(4, "CONN_MCU_TDI"),
+ MTK_FUNCTION(5, "SSPM_JTAG_TDI"),
+ MTK_FUNCTION(6, "IO_JTAG_TDI"),
+ MTK_FUNCTION(7, "DBG_MON_B8")
+ ),
+ MTK_PIN(
+ 103, "GPIO103",
+ MTK_EINT_FUNCTION(0, 103),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO103"),
+ MTK_FUNCTION(1, "SCL2")
+ ),
+ MTK_PIN(
+ 104, "GPIO104",
+ MTK_EINT_FUNCTION(0, 104),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO104"),
+ MTK_FUNCTION(1, "SDA2")
+ ),
+ MTK_PIN(
+ 105, "GPIO105",
+ MTK_EINT_FUNCTION(0, 105),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO105"),
+ MTK_FUNCTION(1, "SCL4")
+ ),
+ MTK_PIN(
+ 106, "GPIO106",
+ MTK_EINT_FUNCTION(0, 106),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO106"),
+ MTK_FUNCTION(1, "SDA4")
+ ),
+ MTK_PIN(
+ 107, "GPIO107",
+ MTK_EINT_FUNCTION(0, 107),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO107"),
+ MTK_FUNCTION(1, "DMIC_CLK"),
+ MTK_FUNCTION(2, "ANT_SEL0"),
+ MTK_FUNCTION(3, "CLKM0"),
+ MTK_FUNCTION(4, "SDA7"),
+ MTK_FUNCTION(5, "EXT_FRAME_SYNC"),
+ MTK_FUNCTION(6, "PWM_A"),
+ MTK_FUNCTION(7, "DBG_MON_B12")
+ ),
+ MTK_PIN(
+ 108, "GPIO108",
+ MTK_EINT_FUNCTION(0, 108),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO108"),
+ MTK_FUNCTION(1, "CMMCLK2"),
+ MTK_FUNCTION(2, "ANT_SEL1"),
+ MTK_FUNCTION(3, "CLKM1"),
+ MTK_FUNCTION(4, "SCL8"),
+ MTK_FUNCTION(5, "DAP_MD32_SWD"),
+ MTK_FUNCTION(6, "PWM_B"),
+ MTK_FUNCTION(7, "DBG_MON_B13")
+ ),
+ MTK_PIN(
+ 109, "GPIO109",
+ MTK_EINT_FUNCTION(0, 109),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO109"),
+ MTK_FUNCTION(1, "DMIC_DAT"),
+ MTK_FUNCTION(2, "ANT_SEL2"),
+ MTK_FUNCTION(3, "CLKM2"),
+ MTK_FUNCTION(4, "SDA8"),
+ MTK_FUNCTION(5, "DAP_MD32_SWCK"),
+ MTK_FUNCTION(6, "PWM_C"),
+ MTK_FUNCTION(7, "DBG_MON_B14")
+ ),
+ MTK_PIN(
+ 110, "GPIO110",
+ MTK_EINT_FUNCTION(0, 110),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO110"),
+ MTK_FUNCTION(1, "SCL7"),
+ MTK_FUNCTION(2, "ANT_SEL0"),
+ MTK_FUNCTION(3, "TP_URXD1_AO"),
+ MTK_FUNCTION(4, "USB_DRVVBUS"),
+ MTK_FUNCTION(5, "SRCLKENAI1"),
+ MTK_FUNCTION(6, "KPCOL2"),
+ MTK_FUNCTION(7, "URXD1")
+ ),
+ MTK_PIN(
+ 111, "GPIO111",
+ MTK_EINT_FUNCTION(0, 111),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO111"),
+ MTK_FUNCTION(1, "CMMCLK3"),
+ MTK_FUNCTION(2, "ANT_SEL1"),
+ MTK_FUNCTION(3, "SRCLKENAI0"),
+ MTK_FUNCTION(4, "SCP_VREQ_VAO"),
+ MTK_FUNCTION(5, "MD_INT2_C2K_UIM1_HOT_PLUG"),
+ MTK_FUNCTION(7, "DVFSRC_EXT_REQ")
+ ),
+ MTK_PIN(
+ 112, "GPIO112",
+ MTK_EINT_FUNCTION(0, 112),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO112"),
+ MTK_FUNCTION(1, "SDA7"),
+ MTK_FUNCTION(2, "ANT_SEL2"),
+ MTK_FUNCTION(3, "TP_UTXD1_AO"),
+ MTK_FUNCTION(4, "IDDIG"),
+ MTK_FUNCTION(5, "AGPS_SYNC"),
+ MTK_FUNCTION(6, "KPROW2"),
+ MTK_FUNCTION(7, "UTXD1")
+ ),
+ MTK_PIN(
+ 113, "GPIO113",
+ MTK_EINT_FUNCTION(0, 113),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO113"),
+ MTK_FUNCTION(1, "CONN_TOP_CLK"),
+ MTK_FUNCTION(3, "SCL6"),
+ MTK_FUNCTION(4, "AUXIF_CLK0"),
+ MTK_FUNCTION(6, "TP_UCTS1_AO")
+ ),
+ MTK_PIN(
+ 114, "GPIO114",
+ MTK_EINT_FUNCTION(0, 114),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO114"),
+ MTK_FUNCTION(1, "CONN_TOP_DATA"),
+ MTK_FUNCTION(3, "SDA6"),
+ MTK_FUNCTION(4, "AUXIF_ST0"),
+ MTK_FUNCTION(6, "TP_URTS1_AO")
+ ),
+ MTK_PIN(
+ 115, "GPIO115",
+ MTK_EINT_FUNCTION(0, 115),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO115"),
+ MTK_FUNCTION(1, "CONN_BT_CLK"),
+ MTK_FUNCTION(2, "UTXD1"),
+ MTK_FUNCTION(3, "PTA_TXD"),
+ MTK_FUNCTION(4, "AUXIF_CLK1"),
+ MTK_FUNCTION(5, "DAP_MD32_SWD"),
+ MTK_FUNCTION(6, "TP_UTXD1_AO")
+ ),
+ MTK_PIN(
+ 116, "GPIO116",
+ MTK_EINT_FUNCTION(0, 116),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO116"),
+ MTK_FUNCTION(1, "CONN_BT_DATA"),
+ MTK_FUNCTION(2, "IPU_JTAG_TRST"),
+ MTK_FUNCTION(4, "AUXIF_ST1"),
+ MTK_FUNCTION(5, "DAP_MD32_SWCK"),
+ MTK_FUNCTION(6, "TP_URXD2_AO"),
+ MTK_FUNCTION(7, "DBG_MON_A0")
+ ),
+ MTK_PIN(
+ 117, "GPIO117",
+ MTK_EINT_FUNCTION(0, 117),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO117"),
+ MTK_FUNCTION(1, "CONN_WF_HB0"),
+ MTK_FUNCTION(2, "IPU_JTAG_TDO"),
+ MTK_FUNCTION(6, "TP_UTXD2_AO"),
+ MTK_FUNCTION(7, "DBG_MON_A4")
+ ),
+ MTK_PIN(
+ 118, "GPIO118",
+ MTK_EINT_FUNCTION(0, 118),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO118"),
+ MTK_FUNCTION(1, "CONN_WF_HB1"),
+ MTK_FUNCTION(2, "IPU_JTAG_TDI"),
+ MTK_FUNCTION(5, "SSPM_URXD_AO"),
+ MTK_FUNCTION(6, "TP_UCTS2_AO"),
+ MTK_FUNCTION(7, "DBG_MON_A5")
+ ),
+ MTK_PIN(
+ 119, "GPIO119",
+ MTK_EINT_FUNCTION(0, 119),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO119"),
+ MTK_FUNCTION(1, "CONN_WF_HB2"),
+ MTK_FUNCTION(2, "IPU_JTAG_TCK"),
+ MTK_FUNCTION(5, "SSPM_UTXD_AO"),
+ MTK_FUNCTION(6, "TP_URTS2_AO")
+ ),
+ MTK_PIN(
+ 120, "GPIO120",
+ MTK_EINT_FUNCTION(0, 120),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO120"),
+ MTK_FUNCTION(1, "CONN_WB_PTA"),
+ MTK_FUNCTION(2, "IPU_JTAG_TMS"),
+ MTK_FUNCTION(5, "CCU_URXD_AO")
+ ),
+ MTK_PIN(
+ 121, "GPIO121",
+ MTK_EINT_FUNCTION(0, 121),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO121"),
+ MTK_FUNCTION(1, "CONN_HRST_B"),
+ MTK_FUNCTION(2, "URXD1"),
+ MTK_FUNCTION(3, "PTA_RXD"),
+ MTK_FUNCTION(5, "CCU_UTXD_AO"),
+ MTK_FUNCTION(6, "TP_URXD1_AO")
+ ),
+ MTK_PIN(
+ 122, "GPIO122",
+ MTK_EINT_FUNCTION(0, 122),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO122"),
+ MTK_FUNCTION(1, "MSDC0_CMD"),
+ MTK_FUNCTION(2, "SSPM_URXD2_AO"),
+ MTK_FUNCTION(3, "ANT_SEL1"),
+ MTK_FUNCTION(7, "DBG_MON_A12")
+ ),
+ MTK_PIN(
+ 123, "GPIO123",
+ MTK_EINT_FUNCTION(0, 123),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO123"),
+ MTK_FUNCTION(1, "MSDC0_DAT0"),
+ MTK_FUNCTION(3, "ANT_SEL0"),
+ MTK_FUNCTION(7, "DBG_MON_A13")
+ ),
+ MTK_PIN(
+ 124, "GPIO124",
+ MTK_EINT_FUNCTION(0, 124),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO124"),
+ MTK_FUNCTION(1, "MSDC0_CLK"),
+ MTK_FUNCTION(7, "DBG_MON_A14")
+ ),
+ MTK_PIN(
+ 125, "GPIO125",
+ MTK_EINT_FUNCTION(0, 125),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO125"),
+ MTK_FUNCTION(1, "MSDC0_DAT2"),
+ MTK_FUNCTION(3, "MRG_CLK"),
+ MTK_FUNCTION(7, "DBG_MON_A15")
+ ),
+ MTK_PIN(
+ 126, "GPIO126",
+ MTK_EINT_FUNCTION(0, 126),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO126"),
+ MTK_FUNCTION(1, "MSDC0_DAT4"),
+ MTK_FUNCTION(3, "ANT_SEL5"),
+ MTK_FUNCTION(6, "UFS_MPHY_SCL"),
+ MTK_FUNCTION(7, "DBG_MON_A16")
+ ),
+ MTK_PIN(
+ 127, "GPIO127",
+ MTK_EINT_FUNCTION(0, 127),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO127"),
+ MTK_FUNCTION(1, "MSDC0_DAT6"),
+ MTK_FUNCTION(3, "ANT_SEL4"),
+ MTK_FUNCTION(6, "UFS_MPHY_SDA"),
+ MTK_FUNCTION(7, "DBG_MON_A17")
+ ),
+ MTK_PIN(
+ 128, "GPIO128",
+ MTK_EINT_FUNCTION(0, 128),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO128"),
+ MTK_FUNCTION(1, "MSDC0_DAT1"),
+ MTK_FUNCTION(3, "ANT_SEL2"),
+ MTK_FUNCTION(6, "UFS_UNIPRO_SDA"),
+ MTK_FUNCTION(7, "DBG_MON_A18")
+ ),
+ MTK_PIN(
+ 129, "GPIO129",
+ MTK_EINT_FUNCTION(0, 129),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO129"),
+ MTK_FUNCTION(1, "MSDC0_DAT5"),
+ MTK_FUNCTION(3, "ANT_SEL3"),
+ MTK_FUNCTION(6, "UFS_UNIPRO_SCL"),
+ MTK_FUNCTION(7, "DBG_MON_A23")
+ ),
+ MTK_PIN(
+ 130, "GPIO130",
+ MTK_EINT_FUNCTION(0, 130),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO130"),
+ MTK_FUNCTION(1, "MSDC0_DAT7"),
+ MTK_FUNCTION(3, "MRG_DO"),
+ MTK_FUNCTION(7, "DBG_MON_A24")
+ ),
+ MTK_PIN(
+ 131, "GPIO131",
+ MTK_EINT_FUNCTION(0, 131),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO131"),
+ MTK_FUNCTION(1, "MSDC0_DSL"),
+ MTK_FUNCTION(3, "MRG_SYNC"),
+ MTK_FUNCTION(7, "DBG_MON_A25")
+ ),
+ MTK_PIN(
+ 132, "GPIO132",
+ MTK_EINT_FUNCTION(0, 132),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO132"),
+ MTK_FUNCTION(1, "MSDC0_DAT3"),
+ MTK_FUNCTION(3, "MRG_DI"),
+ MTK_FUNCTION(7, "DBG_MON_A26")
+ ),
+ MTK_PIN(
+ 133, "GPIO133",
+ MTK_EINT_FUNCTION(0, 133),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO133"),
+ MTK_FUNCTION(1, "MSDC0_RSTB"),
+ MTK_FUNCTION(3, "AGPS_SYNC"),
+ MTK_FUNCTION(7, "DBG_MON_A27")
+ ),
+ MTK_PIN(
+ 134, "GPIO134",
+ MTK_EINT_FUNCTION(0, 134),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO134"),
+ MTK_FUNCTION(1, "RTC32K_CK")
+ ),
+ MTK_PIN(
+ 135, "GPIO135",
+ MTK_EINT_FUNCTION(0, 135),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO135"),
+ MTK_FUNCTION(1, "WATCHDOG")
+ ),
+ MTK_PIN(
+ 136, "GPIO136",
+ MTK_EINT_FUNCTION(0, 136),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO136"),
+ MTK_FUNCTION(1, "AUD_CLK_MOSI"),
+ MTK_FUNCTION(2, "AUD_CLK_MISO"),
+ MTK_FUNCTION(3, "I2S1_MCK"),
+ MTK_FUNCTION(6, "UFS_UNIPRO_SCL")
+ ),
+ MTK_PIN(
+ 137, "GPIO137",
+ MTK_EINT_FUNCTION(0, 137),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO137"),
+ MTK_FUNCTION(1, "AUD_SYNC_MOSI"),
+ MTK_FUNCTION(2, "AUD_SYNC_MISO"),
+ MTK_FUNCTION(3, "I2S1_BCK")
+ ),
+ MTK_PIN(
+ 138, "GPIO138",
+ MTK_EINT_FUNCTION(0, 138),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO138"),
+ MTK_FUNCTION(1, "AUD_DAT_MOSI0"),
+ MTK_FUNCTION(2, "AUD_DAT_MISO0"),
+ MTK_FUNCTION(3, "I2S1_LRCK"),
+ MTK_FUNCTION(7, "DBG_MON_B24")
+ ),
+ MTK_PIN(
+ 139, "GPIO139",
+ MTK_EINT_FUNCTION(0, 139),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO139"),
+ MTK_FUNCTION(1, "AUD_DAT_MOSI1"),
+ MTK_FUNCTION(2, "AUD_DAT_MISO1"),
+ MTK_FUNCTION(3, "I2S1_DO"),
+ MTK_FUNCTION(6, "UFS_MPHY_SDA")
+ ),
+ MTK_PIN(
+ 140, "GPIO140",
+ MTK_EINT_FUNCTION(0, 140),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO140"),
+ MTK_FUNCTION(1, "AUD_CLK_MISO"),
+ MTK_FUNCTION(2, "AUD_CLK_MOSI"),
+ MTK_FUNCTION(3, "I2S0_MCK"),
+ MTK_FUNCTION(6, "UFS_UNIPRO_SDA")
+ ),
+ MTK_PIN(
+ 141, "GPIO141",
+ MTK_EINT_FUNCTION(0, 141),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO141"),
+ MTK_FUNCTION(1, "AUD_SYNC_MISO"),
+ MTK_FUNCTION(2, "AUD_SYNC_MOSI"),
+ MTK_FUNCTION(3, "I2S0_BCK")
+ ),
+ MTK_PIN(
+ 142, "GPIO142",
+ MTK_EINT_FUNCTION(0, 142),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO142"),
+ MTK_FUNCTION(1, "AUD_DAT_MISO0"),
+ MTK_FUNCTION(2, "AUD_DAT_MOSI0"),
+ MTK_FUNCTION(3, "I2S0_LRCK"),
+ MTK_FUNCTION(4, "VOW_DAT_MISO"),
+ MTK_FUNCTION(7, "DBG_MON_B25")
+ ),
+ MTK_PIN(
+ 143, "GPIO143",
+ MTK_EINT_FUNCTION(0, 143),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO143"),
+ MTK_FUNCTION(1, "AUD_DAT_MISO1"),
+ MTK_FUNCTION(2, "AUD_DAT_MOSI1"),
+ MTK_FUNCTION(3, "I2S0_DI"),
+ MTK_FUNCTION(4, "VOW_CLK_MISO"),
+ MTK_FUNCTION(6, "UFS_MPHY_SCL"),
+ MTK_FUNCTION(7, "DBG_MON_B26")
+ ),
+ MTK_PIN(
+ 144, "GPIO144",
+ MTK_EINT_FUNCTION(0, 144),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO144"),
+ MTK_FUNCTION(1, "PWRAP_SPI0_MI"),
+ MTK_FUNCTION(2, "PWRAP_SPI0_MO")
+ ),
+ MTK_PIN(
+ 145, "GPIO145",
+ MTK_EINT_FUNCTION(0, 145),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO145"),
+ MTK_FUNCTION(1, "PWRAP_SPI0_CSN")
+ ),
+ MTK_PIN(
+ 146, "GPIO146",
+ MTK_EINT_FUNCTION(0, 146),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO146"),
+ MTK_FUNCTION(1, "PWRAP_SPI0_MO"),
+ MTK_FUNCTION(2, "PWRAP_SPI0_MI")
+ ),
+ MTK_PIN(
+ 147, "GPIO147",
+ MTK_EINT_FUNCTION(0, 147),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO147"),
+ MTK_FUNCTION(1, "PWRAP_SPI0_CK")
+ ),
+ MTK_PIN(
+ 148, "GPIO148",
+ MTK_EINT_FUNCTION(0, 148),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO148"),
+ MTK_FUNCTION(1, "SRCLKENA0")
+ ),
+ MTK_PIN(
+ 149, "GPIO149",
+ MTK_EINT_FUNCTION(0, 149),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO149"),
+ MTK_FUNCTION(1, "SRCLKENA1")
+ ),
+ MTK_PIN(
+ 150, "GPIO150",
+ MTK_EINT_FUNCTION(0, 150),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO150"),
+ MTK_FUNCTION(1, "PWM_A"),
+ MTK_FUNCTION(2, "CMFLASH"),
+ MTK_FUNCTION(3, "CLKM0"),
+ MTK_FUNCTION(7, "DBG_MON_B30")
+ ),
+ MTK_PIN(
+ 151, "GPIO151",
+ MTK_EINT_FUNCTION(0, 151),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO151"),
+ MTK_FUNCTION(1, "PWM_B"),
+ MTK_FUNCTION(2, "CMVREF0"),
+ MTK_FUNCTION(3, "CLKM1"),
+ MTK_FUNCTION(7, "DBG_MON_B20")
+ ),
+ MTK_PIN(
+ 152, "GPIO152",
+ MTK_EINT_FUNCTION(0, 152),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO152"),
+ MTK_FUNCTION(1, "PWM_C"),
+ MTK_FUNCTION(2, "CMFLASH"),
+ MTK_FUNCTION(3, "CLKM2"),
+ MTK_FUNCTION(7, "DBG_MON_B21")
+ ),
+ MTK_PIN(
+ 153, "GPIO153",
+ MTK_EINT_FUNCTION(0, 153),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO153"),
+ MTK_FUNCTION(1, "PWM_A"),
+ MTK_FUNCTION(2, "CMVREF0"),
+ MTK_FUNCTION(3, "CLKM3"),
+ MTK_FUNCTION(7, "DBG_MON_B22")
+ ),
+ MTK_PIN(
+ 154, "GPIO154",
+ MTK_EINT_FUNCTION(0, 154),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO154"),
+ MTK_FUNCTION(1, "SCP_VREQ_VAO"),
+ MTK_FUNCTION(2, "DVFSRC_EXT_REQ"),
+ MTK_FUNCTION(7, "DBG_MON_B18")
+ ),
+ MTK_PIN(
+ 155, "GPIO155",
+ MTK_EINT_FUNCTION(0, 155),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO155"),
+ MTK_FUNCTION(1, "ANT_SEL0"),
+ MTK_FUNCTION(2, "DVFSRC_EXT_REQ"),
+ MTK_FUNCTION(3, "CMVREF1"),
+ MTK_FUNCTION(7, "SCP_JTAG_TDI")
+ ),
+ MTK_PIN(
+ 156, "GPIO156",
+ MTK_EINT_FUNCTION(0, 156),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO156"),
+ MTK_FUNCTION(1, "ANT_SEL1"),
+ MTK_FUNCTION(2, "SRCLKENAI0"),
+ MTK_FUNCTION(3, "SCL6"),
+ MTK_FUNCTION(4, "KPCOL2"),
+ MTK_FUNCTION(5, "IDDIG"),
+ MTK_FUNCTION(7, "SCP_JTAG_TCK")
+ ),
+ MTK_PIN(
+ 157, "GPIO157",
+ MTK_EINT_FUNCTION(0, 157),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO157"),
+ MTK_FUNCTION(1, "ANT_SEL2"),
+ MTK_FUNCTION(2, "SRCLKENAI1"),
+ MTK_FUNCTION(3, "SDA6"),
+ MTK_FUNCTION(4, "KPROW2"),
+ MTK_FUNCTION(5, "USB_DRVVBUS"),
+ MTK_FUNCTION(7, "SCP_JTAG_TRSTN")
+ ),
+ MTK_PIN(
+ 158, "GPIO158",
+ MTK_EINT_FUNCTION(0, 158),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO158"),
+ MTK_FUNCTION(1, "ANT_SEL3")
+ ),
+ MTK_PIN(
+ 159, "GPIO159",
+ MTK_EINT_FUNCTION(0, 159),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO159"),
+ MTK_FUNCTION(1, "ANT_SEL4")
+ ),
+ MTK_PIN(
+ 160, "GPIO160",
+ MTK_EINT_FUNCTION(0, 160),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO160"),
+ MTK_FUNCTION(1, "ANT_SEL5")
+ ),
+ MTK_PIN(
+ 161, "GPIO161",
+ MTK_EINT_FUNCTION(0, 161),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO161"),
+ MTK_FUNCTION(1, "SPI1_A_MI"),
+ MTK_FUNCTION(2, "SCP_SPI1_MI"),
+ MTK_FUNCTION(3, "IDDIG"),
+ MTK_FUNCTION(4, "ANT_SEL6"),
+ MTK_FUNCTION(5, "KPCOL2"),
+ MTK_FUNCTION(6, "PTA_RXD"),
+ MTK_FUNCTION(7, "DBG_MON_B19")
+ ),
+ MTK_PIN(
+ 162, "GPIO162",
+ MTK_EINT_FUNCTION(0, 162),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO162"),
+ MTK_FUNCTION(1, "SPI1_A_CSB"),
+ MTK_FUNCTION(2, "SCP_SPI1_CS"),
+ MTK_FUNCTION(3, "USB_DRVVBUS"),
+ MTK_FUNCTION(4, "ANT_SEL5"),
+ MTK_FUNCTION(5, "KPROW2"),
+ MTK_FUNCTION(6, "PTA_TXD")
+ ),
+ MTK_PIN(
+ 163, "GPIO163",
+ MTK_EINT_FUNCTION(0, 163),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO163"),
+ MTK_FUNCTION(1, "SPI1_A_MO"),
+ MTK_FUNCTION(2, "SCP_SPI1_MO"),
+ MTK_FUNCTION(3, "SDA1"),
+ MTK_FUNCTION(4, "ANT_SEL4"),
+ MTK_FUNCTION(5, "CMMCLK2"),
+ MTK_FUNCTION(6, "DMIC_CLK")
+ ),
+ MTK_PIN(
+ 164, "GPIO164",
+ MTK_EINT_FUNCTION(0, 164),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO164"),
+ MTK_FUNCTION(1, "SPI1_A_CLK"),
+ MTK_FUNCTION(2, "SCP_SPI1_CK"),
+ MTK_FUNCTION(3, "SCL1"),
+ MTK_FUNCTION(4, "ANT_SEL3"),
+ MTK_FUNCTION(5, "CMMCLK3"),
+ MTK_FUNCTION(6, "DMIC_DAT")
+ ),
+ MTK_PIN(
+ 165, "GPIO165",
+ MTK_EINT_FUNCTION(0, 165),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO165"),
+ MTK_FUNCTION(1, "PWM_B"),
+ MTK_FUNCTION(2, "CMMCLK2"),
+ MTK_FUNCTION(3, "SCP_VREQ_VAO"),
+ MTK_FUNCTION(6, "TDM_MCK_2ND"),
+ MTK_FUNCTION(7, "SCP_JTAG_TDO")
+ ),
+ MTK_PIN(
+ 166, "GPIO166",
+ MTK_EINT_FUNCTION(0, 166),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO166"),
+ MTK_FUNCTION(1, "ANT_SEL6")
+ ),
+ MTK_PIN(
+ 167, "GPIO167",
+ MTK_EINT_FUNCTION(0, 167),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO167"),
+ MTK_FUNCTION(1, "RFIC0_BSI_EN"),
+ MTK_FUNCTION(2, "SPM_BSI_EN")
+ ),
+ MTK_PIN(
+ 168, "GPIO168",
+ MTK_EINT_FUNCTION(0, 168),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO168"),
+ MTK_FUNCTION(1, "RFIC0_BSI_CK"),
+ MTK_FUNCTION(2, "SPM_BSI_CK")
+ ),
+ MTK_PIN(
+ 169, "GPIO169",
+ MTK_EINT_FUNCTION(0, 169),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO169"),
+ MTK_FUNCTION(1, "PWM_C"),
+ MTK_FUNCTION(2, "CMMCLK3"),
+ MTK_FUNCTION(3, "CMVREF1"),
+ MTK_FUNCTION(4, "ANT_SEL7"),
+ MTK_FUNCTION(5, "AGPS_SYNC"),
+ MTK_FUNCTION(6, "TDM_BCK_2ND"),
+ MTK_FUNCTION(7, "SCP_JTAG_TMS")
+ ),
+ MTK_PIN(
+ 170, "GPIO170",
+ MTK_EINT_FUNCTION(0, 170),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO170"),
+ MTK_FUNCTION(1, "I2S1_BCK"),
+ MTK_FUNCTION(2, "I2S3_BCK"),
+ MTK_FUNCTION(3, "SCL7"),
+ MTK_FUNCTION(4, "I2S5_BCK"),
+ MTK_FUNCTION(5, "EXT_FRAME_SYNC"),
+ MTK_FUNCTION(6, "TDM_LRCK_2ND"),
+ MTK_FUNCTION(7, "ANT_SEL3")
+ ),
+ MTK_PIN(
+ 171, "GPIO171",
+ MTK_EINT_FUNCTION(0, 184),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO171"),
+ MTK_FUNCTION(1, "I2S1_LRCK"),
+ MTK_FUNCTION(2, "I2S3_LRCK"),
+ MTK_FUNCTION(3, "SDA7"),
+ MTK_FUNCTION(4, "I2S5_LRCK"),
+ MTK_FUNCTION(5, "URXD1"),
+ MTK_FUNCTION(6, "TDM_DATA0_2ND"),
+ MTK_FUNCTION(7, "ANT_SEL4")
+ ),
+ MTK_PIN(
+ 172, "GPIO172",
+ MTK_EINT_FUNCTION(0, 185),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO172"),
+ MTK_FUNCTION(1, "I2S1_DO"),
+ MTK_FUNCTION(2, "I2S3_DO"),
+ MTK_FUNCTION(3, "SCL8"),
+ MTK_FUNCTION(4, "I2S5_DO"),
+ MTK_FUNCTION(5, "UTXD1"),
+ MTK_FUNCTION(6, "TDM_DATA1_2ND"),
+ MTK_FUNCTION(7, "ANT_SEL5")
+ ),
+ MTK_PIN(
+ 173, "GPIO173",
+ MTK_EINT_FUNCTION(0, 186),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO173"),
+ MTK_FUNCTION(1, "I2S1_MCK"),
+ MTK_FUNCTION(2, "I2S3_MCK"),
+ MTK_FUNCTION(3, "SDA8"),
+ MTK_FUNCTION(4, "I2S5_MCK"),
+ MTK_FUNCTION(5, "UCTS0"),
+ MTK_FUNCTION(6, "TDM_DATA2_2ND"),
+ MTK_FUNCTION(7, "ANT_SEL6")
+ ),
+ MTK_PIN(
+ 174, "GPIO174",
+ MTK_EINT_FUNCTION(0, 187),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO174"),
+ MTK_FUNCTION(1, "I2S2_DI"),
+ MTK_FUNCTION(2, "I2S0_DI"),
+ MTK_FUNCTION(3, "DVFSRC_EXT_REQ"),
+ MTK_FUNCTION(4, "I2S2_DI2"),
+ MTK_FUNCTION(5, "URTS0"),
+ MTK_FUNCTION(6, "TDM_DATA3_2ND"),
+ MTK_FUNCTION(7, "ANT_SEL7")
+ ),
+ MTK_PIN(
+ 175, "GPIO175",
+ MTK_EINT_FUNCTION(0, 188),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO175"),
+ MTK_FUNCTION(1, "ANT_SEL7")
+ ),
+ MTK_PIN(
+ 176, "GPIO176",
+ MTK_EINT_FUNCTION(0, 189),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO176")
+ ),
+ MTK_PIN(
+ 177, "GPIO177",
+ MTK_EINT_FUNCTION(0, 190),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO177")
+ ),
+ MTK_PIN(
+ 178, "GPIO178",
+ MTK_EINT_FUNCTION(0, 191),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO178")
+ ),
+ MTK_PIN(
+ 179, "GPIO179",
+ MTK_EINT_FUNCTION(0, 192),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO179")
+ ),
+ MTK_PIN(
+ 180, "GPIO180",
+ MTK_EINT_FUNCTION(0, 171),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO180")
+ ),
+ MTK_PIN(
+ 181, "GPIO181",
+ MTK_EINT_FUNCTION(0, 172),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO181")
+ ),
+ MTK_PIN(
+ 182, "GPIO182",
+ MTK_EINT_FUNCTION(0, 173),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO182")
+ ),
+ MTK_PIN(
+ 183, "GPIO183",
+ MTK_EINT_FUNCTION(0, 174),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO183")
+ ),
+ MTK_PIN(
+ 184, "GPIO184",
+ MTK_EINT_FUNCTION(0, 175),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO184")
+ ),
+ MTK_PIN(
+ 185, "GPIO185",
+ MTK_EINT_FUNCTION(0, 177),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO185")
+ ),
+ MTK_PIN(
+ 186, "GPIO186",
+ MTK_EINT_FUNCTION(0, 178),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO186")
+ ),
+ MTK_PIN(
+ 187, "GPIO187",
+ MTK_EINT_FUNCTION(0, 179),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO187")
+ ),
+ MTK_PIN(
+ 188, "GPIO188",
+ MTK_EINT_FUNCTION(0, 180),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO188")
+ ),
+ MTK_PIN(
+ 189, "GPIO189",
+ MTK_EINT_FUNCTION(0, 181),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO189")
+ ),
+ MTK_PIN(
+ 190, "GPIO190",
+ MTK_EINT_FUNCTION(0, 182),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO190")
+ ),
+ MTK_PIN(
+ 191, "GPIO191",
+ MTK_EINT_FUNCTION(0, 183),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO191")
+ ),
+};
+
+#endif /* __PINCTRL_MTK_MT8183_H */
diff --git a/drivers/pinctrl/mediatek/pinctrl-paris.c b/drivers/pinctrl/mediatek/pinctrl-paris.c
new file mode 100644
index 000000000000..d2179028f134
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-paris.c
@@ -0,0 +1,907 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek Pinctrl Paris Driver, which implement the vendor per-pin
+ * bindings for MediaTek SoC.
+ *
+ * Copyright (C) 2018 MediaTek Inc.
+ * Author: Sean Wang <sean.wang@mediatek.com>
+ * Zhiyong Tao <zhiyong.tao@mediatek.com>
+ * Hongzhou.Yang <hongzhou.yang@mediatek.com>
+ */
+
+#include <linux/gpio/driver.h>
+#include <dt-bindings/pinctrl/mt65xx.h>
+#include "pinctrl-paris.h"
+
+#define PINCTRL_PINCTRL_DEV KBUILD_MODNAME
+
+/* Custom pinconf parameters */
+#define MTK_PIN_CONFIG_TDSEL (PIN_CONFIG_END + 1)
+#define MTK_PIN_CONFIG_RDSEL (PIN_CONFIG_END + 2)
+#define MTK_PIN_CONFIG_PU_ADV (PIN_CONFIG_END + 3)
+#define MTK_PIN_CONFIG_PD_ADV (PIN_CONFIG_END + 4)
+
+static const struct pinconf_generic_params mtk_custom_bindings[] = {
+ {"mediatek,tdsel", MTK_PIN_CONFIG_TDSEL, 0},
+ {"mediatek,rdsel", MTK_PIN_CONFIG_RDSEL, 0},
+ {"mediatek,pull-up-adv", MTK_PIN_CONFIG_PU_ADV, 1},
+ {"mediatek,pull-down-adv", MTK_PIN_CONFIG_PD_ADV, 1},
+};
+
+#ifdef CONFIG_DEBUG_FS
+static const struct pin_config_item mtk_conf_items[] = {
+ PCONFDUMP(MTK_PIN_CONFIG_TDSEL, "tdsel", NULL, true),
+ PCONFDUMP(MTK_PIN_CONFIG_RDSEL, "rdsel", NULL, true),
+ PCONFDUMP(MTK_PIN_CONFIG_PU_ADV, "pu-adv", NULL, true),
+ PCONFDUMP(MTK_PIN_CONFIG_PD_ADV, "pd-adv", NULL, true),
+};
+#endif
+
+static const char * const mtk_gpio_functions[] = {
+ "func0", "func1", "func2", "func3",
+ "func4", "func5", "func6", "func7",
+ "func8", "func9", "func10", "func11",
+ "func12", "func13", "func14", "func15",
+};
+
+static int mtk_pinmux_gpio_request_enable(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned int pin)
+{
+ struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev);
+ const struct mtk_pin_desc *desc;
+
+ desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin];
+
+ return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_MODE,
+ hw->soc->gpio_m);
+}
+
+static int mtk_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned int pin, bool input)
+{
+ struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev);
+ const struct mtk_pin_desc *desc;
+
+ desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin];
+
+ /* hardware would take 0 as input direction */
+ return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, !input);
+}
+
+static int mtk_pinconf_get(struct pinctrl_dev *pctldev,
+ unsigned int pin, unsigned long *config)
+{
+ struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev);
+ u32 param = pinconf_to_config_param(*config);
+ int val, val2, err, reg, ret = 1;
+ const struct mtk_pin_desc *desc;
+
+ desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin];
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ if (hw->soc->bias_disable_get) {
+ err = hw->soc->bias_disable_get(hw, desc, &ret);
+ if (err)
+ return err;
+ } else {
+ return -ENOTSUPP;
+ }
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ if (hw->soc->bias_get) {
+ err = hw->soc->bias_get(hw, desc, 1, &ret);
+ if (err)
+ return err;
+ } else {
+ return -ENOTSUPP;
+ }
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ if (hw->soc->bias_get) {
+ err = hw->soc->bias_get(hw, desc, 0, &ret);
+ if (err)
+ return err;
+ } else {
+ return -ENOTSUPP;
+ }
+ break;
+ case PIN_CONFIG_SLEW_RATE:
+ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_SR, &val);
+ if (err)
+ return err;
+
+ if (!val)
+ return -EINVAL;
+
+ break;
+ case PIN_CONFIG_INPUT_ENABLE:
+ case PIN_CONFIG_OUTPUT_ENABLE:
+ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DIR, &val);
+ if (err)
+ return err;
+
+ /* HW takes input mode as zero; output mode as non-zero */
+ if ((val && param == PIN_CONFIG_INPUT_ENABLE) ||
+ (!val && param == PIN_CONFIG_OUTPUT_ENABLE))
+ return -EINVAL;
+
+ break;
+ case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DIR, &val);
+ if (err)
+ return err;
+
+ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_SMT, &val2);
+ if (err)
+ return err;
+
+ if (val || !val2)
+ return -EINVAL;
+
+ break;
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ if (hw->soc->drive_get) {
+ err = hw->soc->drive_get(hw, desc, &ret);
+ if (err)
+ return err;
+ } else {
+ err = -ENOTSUPP;
+ }
+ break;
+ case MTK_PIN_CONFIG_TDSEL:
+ case MTK_PIN_CONFIG_RDSEL:
+ reg = (param == MTK_PIN_CONFIG_TDSEL) ?
+ PINCTRL_PIN_REG_TDSEL : PINCTRL_PIN_REG_RDSEL;
+
+ err = mtk_hw_get_value(hw, desc, reg, &val);
+ if (err)
+ return err;
+
+ ret = val;
+
+ break;
+ case MTK_PIN_CONFIG_PU_ADV:
+ case MTK_PIN_CONFIG_PD_ADV:
+ if (hw->soc->adv_pull_get) {
+ bool pullup;
+
+ pullup = param == MTK_PIN_CONFIG_PU_ADV;
+ err = hw->soc->adv_pull_get(hw, desc, pullup, &ret);
+ if (err)
+ return err;
+ } else {
+ return -ENOTSUPP;
+ }
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ *config = pinconf_to_config_packed(param, ret);
+
+ return 0;
+}
+
+static int mtk_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
+ enum pin_config_param param,
+ enum pin_config_param arg)
+{
+ struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev);
+ const struct mtk_pin_desc *desc;
+ int err = 0;
+ u32 reg;
+
+ desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin];
+
+ switch ((u32)param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ if (hw->soc->bias_disable_set) {
+ err = hw->soc->bias_disable_set(hw, desc);
+ if (err)
+ return err;
+ } else {
+ return -ENOTSUPP;
+ }
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ if (hw->soc->bias_set) {
+ err = hw->soc->bias_set(hw, desc, 1);
+ if (err)
+ return err;
+ } else {
+ return -ENOTSUPP;
+ }
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ if (hw->soc->bias_set) {
+ err = hw->soc->bias_set(hw, desc, 0);
+ if (err)
+ return err;
+ } else {
+ return -ENOTSUPP;
+ }
+ break;
+ case PIN_CONFIG_OUTPUT_ENABLE:
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_SMT,
+ MTK_DISABLE);
+ if (err)
+ goto err;
+
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR,
+ MTK_OUTPUT);
+ if (err)
+ goto err;
+ break;
+ case PIN_CONFIG_INPUT_ENABLE:
+ if (hw->soc->ies_present) {
+ mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_IES,
+ MTK_ENABLE);
+ }
+
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR,
+ MTK_INPUT);
+ if (err)
+ goto err;
+ break;
+ case PIN_CONFIG_SLEW_RATE:
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_SR,
+ arg);
+ if (err)
+ goto err;
+
+ break;
+ case PIN_CONFIG_OUTPUT:
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR,
+ MTK_OUTPUT);
+ if (err)
+ goto err;
+
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DO,
+ arg);
+ if (err)
+ goto err;
+ break;
+ case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+ /* arg = 1: Input mode & SMT enable ;
+ * arg = 0: Output mode & SMT disable
+ */
+ arg = arg ? 2 : 1;
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR,
+ arg & 1);
+ if (err)
+ goto err;
+
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_SMT,
+ !!(arg & 2));
+ if (err)
+ goto err;
+ break;
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ if (hw->soc->drive_set) {
+ err = hw->soc->drive_set(hw, desc, arg);
+ if (err)
+ return err;
+ } else {
+ return -ENOTSUPP;
+ }
+ break;
+ case MTK_PIN_CONFIG_TDSEL:
+ case MTK_PIN_CONFIG_RDSEL:
+ reg = (param == MTK_PIN_CONFIG_TDSEL) ?
+ PINCTRL_PIN_REG_TDSEL : PINCTRL_PIN_REG_RDSEL;
+
+ err = mtk_hw_set_value(hw, desc, reg, arg);
+ if (err)
+ goto err;
+ break;
+ case MTK_PIN_CONFIG_PU_ADV:
+ case MTK_PIN_CONFIG_PD_ADV:
+ if (hw->soc->adv_pull_set) {
+ bool pullup;
+
+ pullup = param == MTK_PIN_CONFIG_PU_ADV;
+ err = hw->soc->adv_pull_set(hw, desc, pullup,
+ arg);
+ if (err)
+ return err;
+ } else {
+ return -ENOTSUPP;
+ }
+ break;
+ default:
+ err = -ENOTSUPP;
+ }
+
+err:
+ return err;
+}
+
+static struct mtk_pinctrl_group *
+mtk_pctrl_find_group_by_pin(struct mtk_pinctrl *hw, u32 pin)
+{
+ int i;
+
+ for (i = 0; i < hw->soc->ngrps; i++) {
+ struct mtk_pinctrl_group *grp = hw->groups + i;
+
+ if (grp->pin == pin)
+ return grp;
+ }
+
+ return NULL;
+}
+
+static const struct mtk_func_desc *
+mtk_pctrl_find_function_by_pin(struct mtk_pinctrl *hw, u32 pin_num, u32 fnum)
+{
+ const struct mtk_pin_desc *pin = hw->soc->pins + pin_num;
+ const struct mtk_func_desc *func = pin->funcs;
+
+ while (func && func->name) {
+ if (func->muxval == fnum)
+ return func;
+ func++;
+ }
+
+ return NULL;
+}
+
+static bool mtk_pctrl_is_function_valid(struct mtk_pinctrl *hw, u32 pin_num,
+ u32 fnum)
+{
+ int i;
+
+ for (i = 0; i < hw->soc->npins; i++) {
+ const struct mtk_pin_desc *pin = hw->soc->pins + i;
+
+ if (pin->number == pin_num) {
+ const struct mtk_func_desc *func = pin->funcs;
+
+ while (func && func->name) {
+ if (func->muxval == fnum)
+ return true;
+ func++;
+ }
+
+ break;
+ }
+ }
+
+ return false;
+}
+
+static int mtk_pctrl_dt_node_to_map_func(struct mtk_pinctrl *pctl,
+ u32 pin, u32 fnum,
+ struct mtk_pinctrl_group *grp,
+ struct pinctrl_map **map,
+ unsigned *reserved_maps,
+ unsigned *num_maps)
+{
+ bool ret;
+
+ if (*num_maps == *reserved_maps)
+ return -ENOSPC;
+
+ (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP;
+ (*map)[*num_maps].data.mux.group = grp->name;
+
+ ret = mtk_pctrl_is_function_valid(pctl, pin, fnum);
+ if (!ret) {
+ dev_err(pctl->dev, "invalid function %d on pin %d .\n",
+ fnum, pin);
+ return -EINVAL;
+ }
+
+ (*map)[*num_maps].data.mux.function = mtk_gpio_functions[fnum];
+ (*num_maps)++;
+
+ return 0;
+}
+
+static int mtk_pctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *node,
+ struct pinctrl_map **map,
+ unsigned *reserved_maps,
+ unsigned *num_maps)
+{
+ struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev);
+ int num_pins, num_funcs, maps_per_pin, i, err;
+ struct mtk_pinctrl_group *grp;
+ unsigned int num_configs;
+ bool has_config = false;
+ unsigned long *configs;
+ u32 pinfunc, pin, func;
+ struct property *pins;
+ unsigned reserve = 0;
+
+ pins = of_find_property(node, "pinmux", NULL);
+ if (!pins) {
+ dev_err(hw->dev, "missing pins property in node %s .\n",
+ node->name);
+ return -EINVAL;
+ }
+
+ err = pinconf_generic_parse_dt_config(node, pctldev, &configs,
+ &num_configs);
+ if (err)
+ return err;
+
+ if (num_configs)
+ has_config = true;
+
+ num_pins = pins->length / sizeof(u32);
+ num_funcs = num_pins;
+ maps_per_pin = 0;
+ if (num_funcs)
+ maps_per_pin++;
+ if (has_config && num_pins >= 1)
+ maps_per_pin++;
+
+ if (!num_pins || !maps_per_pin) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ reserve = num_pins * maps_per_pin;
+
+ err = pinctrl_utils_reserve_map(pctldev, map, reserved_maps, num_maps,
+ reserve);
+ if (err < 0)
+ goto exit;
+
+ for (i = 0; i < num_pins; i++) {
+ err = of_property_read_u32_index(node, "pinmux", i, &pinfunc);
+ if (err)
+ goto exit;
+
+ pin = MTK_GET_PIN_NO(pinfunc);
+ func = MTK_GET_PIN_FUNC(pinfunc);
+
+ if (pin >= hw->soc->npins ||
+ func >= ARRAY_SIZE(mtk_gpio_functions)) {
+ dev_err(hw->dev, "invalid pins value.\n");
+ err = -EINVAL;
+ goto exit;
+ }
+
+ grp = mtk_pctrl_find_group_by_pin(hw, pin);
+ if (!grp) {
+ dev_err(hw->dev, "unable to match pin %d to group\n",
+ pin);
+ err = -EINVAL;
+ goto exit;
+ }
+
+ err = mtk_pctrl_dt_node_to_map_func(hw, pin, func, grp, map,
+ reserved_maps, num_maps);
+ if (err < 0)
+ goto exit;
+
+ if (has_config) {
+ err = pinctrl_utils_add_map_configs(pctldev, map,
+ reserved_maps,
+ num_maps,
+ grp->name,
+ configs,
+ num_configs,
+ PIN_MAP_TYPE_CONFIGS_GROUP);
+ if (err < 0)
+ goto exit;
+ }
+ }
+
+ err = 0;
+
+exit:
+ kfree(configs);
+ return err;
+}
+
+static int mtk_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *np_config,
+ struct pinctrl_map **map,
+ unsigned *num_maps)
+{
+ struct device_node *np;
+ unsigned reserved_maps;
+ int ret;
+
+ *map = NULL;
+ *num_maps = 0;
+ reserved_maps = 0;
+
+ for_each_child_of_node(np_config, np) {
+ ret = mtk_pctrl_dt_subnode_to_map(pctldev, np, map,
+ &reserved_maps,
+ num_maps);
+ if (ret < 0) {
+ pinctrl_utils_free_map(pctldev, *map, *num_maps);
+ of_node_put(np);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int mtk_pctrl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+ struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev);
+
+ return hw->soc->ngrps;
+}
+
+static const char *mtk_pctrl_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned group)
+{
+ struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev);
+
+ return hw->groups[group].name;
+}
+
+static int mtk_pctrl_get_group_pins(struct pinctrl_dev *pctldev,
+ unsigned group, const unsigned **pins,
+ unsigned *num_pins)
+{
+ struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev);
+
+ *pins = (unsigned *)&hw->groups[group].pin;
+ *num_pins = 1;
+
+ return 0;
+}
+
+static const struct pinctrl_ops mtk_pctlops = {
+ .dt_node_to_map = mtk_pctrl_dt_node_to_map,
+ .dt_free_map = pinctrl_utils_free_map,
+ .get_groups_count = mtk_pctrl_get_groups_count,
+ .get_group_name = mtk_pctrl_get_group_name,
+ .get_group_pins = mtk_pctrl_get_group_pins,
+};
+
+static int mtk_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev)
+{
+ return ARRAY_SIZE(mtk_gpio_functions);
+}
+
+static const char *mtk_pmx_get_func_name(struct pinctrl_dev *pctldev,
+ unsigned selector)
+{
+ return mtk_gpio_functions[selector];
+}
+
+static int mtk_pmx_get_func_groups(struct pinctrl_dev *pctldev,
+ unsigned function,
+ const char * const **groups,
+ unsigned * const num_groups)
+{
+ struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev);
+
+ *groups = hw->grp_names;
+ *num_groups = hw->soc->ngrps;
+
+ return 0;
+}
+
+static int mtk_pmx_set_mux(struct pinctrl_dev *pctldev,
+ unsigned function,
+ unsigned group)
+{
+ struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev);
+ struct mtk_pinctrl_group *grp = hw->groups + group;
+ const struct mtk_func_desc *desc_func;
+ const struct mtk_pin_desc *desc;
+ bool ret;
+
+ ret = mtk_pctrl_is_function_valid(hw, grp->pin, function);
+ if (!ret) {
+ dev_err(hw->dev, "invalid function %d on group %d .\n",
+ function, group);
+ return -EINVAL;
+ }
+
+ desc_func = mtk_pctrl_find_function_by_pin(hw, grp->pin, function);
+ if (!desc_func)
+ return -EINVAL;
+
+ desc = (const struct mtk_pin_desc *)&hw->soc->pins[grp->pin];
+ mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_MODE, desc_func->muxval);
+
+ return 0;
+}
+
+static const struct pinmux_ops mtk_pmxops = {
+ .get_functions_count = mtk_pmx_get_funcs_cnt,
+ .get_function_name = mtk_pmx_get_func_name,
+ .get_function_groups = mtk_pmx_get_func_groups,
+ .set_mux = mtk_pmx_set_mux,
+ .gpio_set_direction = mtk_pinmux_gpio_set_direction,
+ .gpio_request_enable = mtk_pinmux_gpio_request_enable,
+};
+
+static int mtk_pconf_group_get(struct pinctrl_dev *pctldev, unsigned group,
+ unsigned long *config)
+{
+ struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev);
+
+ *config = hw->groups[group].config;
+
+ return 0;
+}
+
+static int mtk_pconf_group_set(struct pinctrl_dev *pctldev, unsigned group,
+ unsigned long *configs, unsigned num_configs)
+{
+ struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev);
+ struct mtk_pinctrl_group *grp = &hw->groups[group];
+ int i, ret;
+
+ for (i = 0; i < num_configs; i++) {
+ ret = mtk_pinconf_set(pctldev, grp->pin,
+ pinconf_to_config_param(configs[i]),
+ pinconf_to_config_argument(configs[i]));
+ if (ret < 0)
+ return ret;
+
+ grp->config = configs[i];
+ }
+
+ return 0;
+}
+
+static const struct pinconf_ops mtk_confops = {
+ .pin_config_get = mtk_pinconf_get,
+ .pin_config_group_get = mtk_pconf_group_get,
+ .pin_config_group_set = mtk_pconf_group_set,
+};
+
+static struct pinctrl_desc mtk_desc = {
+ .name = PINCTRL_PINCTRL_DEV,
+ .pctlops = &mtk_pctlops,
+ .pmxops = &mtk_pmxops,
+ .confops = &mtk_confops,
+ .owner = THIS_MODULE,
+};
+
+static int mtk_gpio_get_direction(struct gpio_chip *chip, unsigned int gpio)
+{
+ struct mtk_pinctrl *hw = gpiochip_get_data(chip);
+ const struct mtk_pin_desc *desc;
+ int value, err;
+
+ desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio];
+
+ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DIR, &value);
+ if (err)
+ return err;
+
+ return !value;
+}
+
+static int mtk_gpio_get(struct gpio_chip *chip, unsigned int gpio)
+{
+ struct mtk_pinctrl *hw = gpiochip_get_data(chip);
+ const struct mtk_pin_desc *desc;
+ int value, err;
+
+ desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio];
+
+ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DI, &value);
+ if (err)
+ return err;
+
+ return !!value;
+}
+
+static void mtk_gpio_set(struct gpio_chip *chip, unsigned int gpio, int value)
+{
+ struct mtk_pinctrl *hw = gpiochip_get_data(chip);
+ const struct mtk_pin_desc *desc;
+
+ desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio];
+
+ mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DO, !!value);
+}
+
+static int mtk_gpio_direction_input(struct gpio_chip *chip, unsigned int gpio)
+{
+ return pinctrl_gpio_direction_input(chip->base + gpio);
+}
+
+static int mtk_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio,
+ int value)
+{
+ mtk_gpio_set(chip, gpio, value);
+
+ return pinctrl_gpio_direction_output(chip->base + gpio);
+}
+
+static int mtk_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
+{
+ struct mtk_pinctrl *hw = gpiochip_get_data(chip);
+ const struct mtk_pin_desc *desc;
+
+ if (!hw->eint)
+ return -ENOTSUPP;
+
+ desc = (const struct mtk_pin_desc *)&hw->soc->pins[offset];
+
+ if (desc->eint.eint_n == EINT_NA)
+ return -ENOTSUPP;
+
+ return mtk_eint_find_irq(hw->eint, desc->eint.eint_n);
+}
+
+static int mtk_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
+ unsigned long config)
+{
+ struct mtk_pinctrl *hw = gpiochip_get_data(chip);
+ const struct mtk_pin_desc *desc;
+ u32 debounce;
+
+ desc = (const struct mtk_pin_desc *)&hw->soc->pins[offset];
+
+ if (!hw->eint ||
+ pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE ||
+ desc->eint.eint_n == EINT_NA)
+ return -ENOTSUPP;
+
+ debounce = pinconf_to_config_argument(config);
+
+ return mtk_eint_set_debounce(hw->eint, desc->eint.eint_n, debounce);
+}
+
+static int mtk_build_gpiochip(struct mtk_pinctrl *hw, struct device_node *np)
+{
+ struct gpio_chip *chip = &hw->chip;
+ int ret;
+
+ chip->label = PINCTRL_PINCTRL_DEV;
+ chip->parent = hw->dev;
+ chip->request = gpiochip_generic_request;
+ chip->free = gpiochip_generic_free;
+ chip->get_direction = mtk_gpio_get_direction;
+ chip->direction_input = mtk_gpio_direction_input;
+ chip->direction_output = mtk_gpio_direction_output;
+ chip->get = mtk_gpio_get;
+ chip->set = mtk_gpio_set;
+ chip->to_irq = mtk_gpio_to_irq,
+ chip->set_config = mtk_gpio_set_config,
+ chip->base = -1;
+ chip->ngpio = hw->soc->npins;
+ chip->of_node = np;
+ chip->of_gpio_n_cells = 2;
+
+ ret = gpiochip_add_data(chip, hw);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int mtk_pctrl_build_state(struct platform_device *pdev)
+{
+ struct mtk_pinctrl *hw = platform_get_drvdata(pdev);
+ int i;
+
+ /* Allocate groups */
+ hw->groups = devm_kmalloc_array(&pdev->dev, hw->soc->ngrps,
+ sizeof(*hw->groups), GFP_KERNEL);
+ if (!hw->groups)
+ return -ENOMEM;
+
+ /* We assume that one pin is one group, use pin name as group name. */
+ hw->grp_names = devm_kmalloc_array(&pdev->dev, hw->soc->ngrps,
+ sizeof(*hw->grp_names), GFP_KERNEL);
+ if (!hw->grp_names)
+ return -ENOMEM;
+
+ for (i = 0; i < hw->soc->npins; i++) {
+ const struct mtk_pin_desc *pin = hw->soc->pins + i;
+ struct mtk_pinctrl_group *group = hw->groups + i;
+
+ group->name = pin->name;
+ group->pin = pin->number;
+
+ hw->grp_names[i] = pin->name;
+ }
+
+ return 0;
+}
+
+int mtk_paris_pinctrl_probe(struct platform_device *pdev,
+ const struct mtk_pin_soc *soc)
+{
+ struct pinctrl_pin_desc *pins;
+ struct mtk_pinctrl *hw;
+ struct resource *res;
+ int err, i;
+
+ hw = devm_kzalloc(&pdev->dev, sizeof(*hw), GFP_KERNEL);
+ if (!hw)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, hw);
+ hw->soc = soc;
+ hw->dev = &pdev->dev;
+
+ if (!hw->soc->nbase_names) {
+ dev_err(&pdev->dev,
+ "SoC should be assigned at least one register base\n");
+ return -EINVAL;
+ }
+
+ hw->base = devm_kmalloc_array(&pdev->dev, hw->soc->nbase_names,
+ sizeof(*hw->base), GFP_KERNEL);
+ if (!hw->base)
+ return -ENOMEM;
+
+ for (i = 0; i < hw->soc->nbase_names; i++) {
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ hw->soc->base_names[i]);
+ if (!res) {
+ dev_err(&pdev->dev, "missing IO resource\n");
+ return -ENXIO;
+ }
+
+ hw->base[i] = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(hw->base[i]))
+ return PTR_ERR(hw->base[i]);
+ }
+
+ hw->nbase = hw->soc->nbase_names;
+
+ err = mtk_pctrl_build_state(pdev);
+ if (err) {
+ dev_err(&pdev->dev, "build state failed: %d\n", err);
+ return -EINVAL;
+ }
+
+ /* Copy from internal struct mtk_pin_desc to register to the core */
+ pins = devm_kmalloc_array(&pdev->dev, hw->soc->npins, sizeof(*pins),
+ GFP_KERNEL);
+ if (!pins)
+ return -ENOMEM;
+
+ for (i = 0; i < hw->soc->npins; i++) {
+ pins[i].number = hw->soc->pins[i].number;
+ pins[i].name = hw->soc->pins[i].name;
+ }
+
+ /* Setup pins descriptions per SoC types */
+ mtk_desc.pins = (const struct pinctrl_pin_desc *)pins;
+ mtk_desc.npins = hw->soc->npins;
+ mtk_desc.num_custom_params = ARRAY_SIZE(mtk_custom_bindings);
+ mtk_desc.custom_params = mtk_custom_bindings;
+#ifdef CONFIG_DEBUG_FS
+ mtk_desc.custom_conf_items = mtk_conf_items;
+#endif
+
+ err = devm_pinctrl_register_and_init(&pdev->dev, &mtk_desc, hw,
+ &hw->pctrl);
+ if (err)
+ return err;
+
+ err = pinctrl_enable(hw->pctrl);
+ if (err)
+ return err;
+
+ err = mtk_build_eint(hw, pdev);
+ if (err)
+ dev_warn(&pdev->dev,
+ "Failed to add EINT, but pinctrl still can work\n");
+
+ /* Build gpiochip should be after pinctrl_enable is done */
+ err = mtk_build_gpiochip(hw, pdev->dev.of_node);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to add gpio_chip\n");
+ return err;
+ }
+
+ platform_set_drvdata(pdev, hw);
+
+ return 0;
+}
diff --git a/drivers/pinctrl/mediatek/pinctrl-paris.h b/drivers/pinctrl/mediatek/pinctrl-paris.h
new file mode 100644
index 000000000000..37146caa667d
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-paris.h
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ *
+ * Author: Sean Wang <sean.wang@mediatek.com>
+ * Zhiyong Tao <zhiyong.tao@mediatek.com>
+ * Hongzhou.Yang <hongzhou.yang@mediatek.com>
+ */
+#ifndef __PINCTRL_PARIS_H
+#define __PINCTRL_PARIS_H
+
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+
+#include "../core.h"
+#include "../pinconf.h"
+#include "../pinctrl-utils.h"
+#include "../pinmux.h"
+#include "mtk-eint.h"
+#include "pinctrl-mtk-common-v2.h"
+
+#define MTK_RANGE(_a) { .range = (_a), .nranges = ARRAY_SIZE(_a), }
+
+#define MTK_EINT_FUNCTION(_eintmux, _eintnum) \
+ { \
+ .eint_m = _eintmux, \
+ .eint_n = _eintnum, \
+ }
+
+#define MTK_FUNCTION(_val, _name) \
+ { \
+ .muxval = _val, \
+ .name = _name, \
+ }
+
+#define MTK_PIN(_number, _name, _eint, _drv_n, ...) { \
+ .number = _number, \
+ .name = _name, \
+ .eint = _eint, \
+ .drv_n = _drv_n, \
+ .funcs = (struct mtk_func_desc[]){ \
+ __VA_ARGS__, { } }, \
+ }
+
+#define PINCTRL_PIN_GROUP(name, id) \
+ { \
+ name, \
+ id##_pins, \
+ ARRAY_SIZE(id##_pins), \
+ id##_funcs, \
+ }
+
+int mtk_paris_pinctrl_probe(struct platform_device *pdev,
+ const struct mtk_pin_soc *soc);
+
+#endif /* __PINCTRL_PARIS_H */
diff --git a/drivers/pinctrl/meson/Kconfig b/drivers/pinctrl/meson/Kconfig
index c80951d6caff..9ab537eb78a3 100644
--- a/drivers/pinctrl/meson/Kconfig
+++ b/drivers/pinctrl/meson/Kconfig
@@ -47,4 +47,10 @@ config PINCTRL_MESON_AXG
config PINCTRL_MESON_AXG_PMX
bool
+config PINCTRL_MESON_G12A
+ bool "Meson g12a Soc pinctrl driver"
+ depends on ARM64
+ select PINCTRL_MESON_AXG_PMX
+ default y
+
endif
diff --git a/drivers/pinctrl/meson/Makefile b/drivers/pinctrl/meson/Makefile
index 3c6580c2d9d7..cf283f48f9d8 100644
--- a/drivers/pinctrl/meson/Makefile
+++ b/drivers/pinctrl/meson/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_PINCTRL_MESON_GXBB) += pinctrl-meson-gxbb.o
obj-$(CONFIG_PINCTRL_MESON_GXL) += pinctrl-meson-gxl.o
obj-$(CONFIG_PINCTRL_MESON_AXG_PMX) += pinctrl-meson-axg-pmx.o
obj-$(CONFIG_PINCTRL_MESON_AXG) += pinctrl-meson-axg.o
+obj-$(CONFIG_PINCTRL_MESON_G12A) += pinctrl-meson-g12a.o
diff --git a/drivers/pinctrl/meson/pinctrl-meson-g12a.c b/drivers/pinctrl/meson/pinctrl-meson-g12a.c
new file mode 100644
index 000000000000..d494492e98e9
--- /dev/null
+++ b/drivers/pinctrl/meson/pinctrl-meson-g12a.c
@@ -0,0 +1,1404 @@
+// SPDX-License-Identifier: (GPL-2.0+ or MIT)
+/*
+ * Pin controller and GPIO driver for Amlogic Meson G12A SoC.
+ *
+ * Copyright (c) 2018 Amlogic, Inc. All rights reserved.
+ * Author: Xingyu Chen <xingyu.chen@amlogic.com>
+ * Author: Yixun Lan <yixun.lan@amlogic.com>
+ */
+
+#include <dt-bindings/gpio/meson-g12a-gpio.h>
+#include "pinctrl-meson.h"
+#include "pinctrl-meson-axg-pmx.h"
+
+static const struct pinctrl_pin_desc meson_g12a_periphs_pins[] = {
+ MESON_PIN(GPIOZ_0),
+ MESON_PIN(GPIOZ_1),
+ MESON_PIN(GPIOZ_2),
+ MESON_PIN(GPIOZ_3),
+ MESON_PIN(GPIOZ_4),
+ MESON_PIN(GPIOZ_5),
+ MESON_PIN(GPIOZ_6),
+ MESON_PIN(GPIOZ_7),
+ MESON_PIN(GPIOZ_8),
+ MESON_PIN(GPIOZ_9),
+ MESON_PIN(GPIOZ_10),
+ MESON_PIN(GPIOZ_11),
+ MESON_PIN(GPIOZ_12),
+ MESON_PIN(GPIOZ_13),
+ MESON_PIN(GPIOZ_14),
+ MESON_PIN(GPIOZ_15),
+ MESON_PIN(GPIOH_0),
+ MESON_PIN(GPIOH_1),
+ MESON_PIN(GPIOH_2),
+ MESON_PIN(GPIOH_3),
+ MESON_PIN(GPIOH_4),
+ MESON_PIN(GPIOH_5),
+ MESON_PIN(GPIOH_6),
+ MESON_PIN(GPIOH_7),
+ MESON_PIN(GPIOH_8),
+ MESON_PIN(BOOT_0),
+ MESON_PIN(BOOT_1),
+ MESON_PIN(BOOT_2),
+ MESON_PIN(BOOT_3),
+ MESON_PIN(BOOT_4),
+ MESON_PIN(BOOT_5),
+ MESON_PIN(BOOT_6),
+ MESON_PIN(BOOT_7),
+ MESON_PIN(BOOT_8),
+ MESON_PIN(BOOT_9),
+ MESON_PIN(BOOT_10),
+ MESON_PIN(BOOT_11),
+ MESON_PIN(BOOT_12),
+ MESON_PIN(BOOT_13),
+ MESON_PIN(BOOT_14),
+ MESON_PIN(BOOT_15),
+ MESON_PIN(GPIOC_0),
+ MESON_PIN(GPIOC_1),
+ MESON_PIN(GPIOC_2),
+ MESON_PIN(GPIOC_3),
+ MESON_PIN(GPIOC_4),
+ MESON_PIN(GPIOC_5),
+ MESON_PIN(GPIOC_6),
+ MESON_PIN(GPIOC_7),
+ MESON_PIN(GPIOA_0),
+ MESON_PIN(GPIOA_1),
+ MESON_PIN(GPIOA_2),
+ MESON_PIN(GPIOA_3),
+ MESON_PIN(GPIOA_4),
+ MESON_PIN(GPIOA_5),
+ MESON_PIN(GPIOA_6),
+ MESON_PIN(GPIOA_7),
+ MESON_PIN(GPIOA_8),
+ MESON_PIN(GPIOA_9),
+ MESON_PIN(GPIOA_10),
+ MESON_PIN(GPIOA_11),
+ MESON_PIN(GPIOA_12),
+ MESON_PIN(GPIOA_13),
+ MESON_PIN(GPIOA_14),
+ MESON_PIN(GPIOA_15),
+ MESON_PIN(GPIOX_0),
+ MESON_PIN(GPIOX_1),
+ MESON_PIN(GPIOX_2),
+ MESON_PIN(GPIOX_3),
+ MESON_PIN(GPIOX_4),
+ MESON_PIN(GPIOX_5),
+ MESON_PIN(GPIOX_6),
+ MESON_PIN(GPIOX_7),
+ MESON_PIN(GPIOX_8),
+ MESON_PIN(GPIOX_9),
+ MESON_PIN(GPIOX_10),
+ MESON_PIN(GPIOX_11),
+ MESON_PIN(GPIOX_12),
+ MESON_PIN(GPIOX_13),
+ MESON_PIN(GPIOX_14),
+ MESON_PIN(GPIOX_15),
+ MESON_PIN(GPIOX_16),
+ MESON_PIN(GPIOX_17),
+ MESON_PIN(GPIOX_18),
+ MESON_PIN(GPIOX_19),
+};
+
+static const struct pinctrl_pin_desc meson_g12a_aobus_pins[] = {
+ MESON_PIN(GPIOAO_0),
+ MESON_PIN(GPIOAO_1),
+ MESON_PIN(GPIOAO_2),
+ MESON_PIN(GPIOAO_3),
+ MESON_PIN(GPIOAO_4),
+ MESON_PIN(GPIOAO_5),
+ MESON_PIN(GPIOAO_6),
+ MESON_PIN(GPIOAO_7),
+ MESON_PIN(GPIOAO_8),
+ MESON_PIN(GPIOAO_9),
+ MESON_PIN(GPIOAO_10),
+ MESON_PIN(GPIOAO_11),
+ MESON_PIN(GPIOE_0),
+ MESON_PIN(GPIOE_1),
+ MESON_PIN(GPIOE_2),
+};
+
+/* emmc */
+static const unsigned int emmc_nand_d0_pins[] = { BOOT_0 };
+static const unsigned int emmc_nand_d1_pins[] = { BOOT_1 };
+static const unsigned int emmc_nand_d2_pins[] = { BOOT_2 };
+static const unsigned int emmc_nand_d3_pins[] = { BOOT_3 };
+static const unsigned int emmc_nand_d4_pins[] = { BOOT_4 };
+static const unsigned int emmc_nand_d5_pins[] = { BOOT_5 };
+static const unsigned int emmc_nand_d6_pins[] = { BOOT_6 };
+static const unsigned int emmc_nand_d7_pins[] = { BOOT_7 };
+static const unsigned int emmc_clk_pins[] = { BOOT_8 };
+static const unsigned int emmc_cmd_pins[] = { BOOT_10 };
+static const unsigned int emmc_nand_ds_pins[] = { BOOT_13 };
+
+/* nand */
+static const unsigned int nand_wen_clk_pins[] = { BOOT_8 };
+static const unsigned int nand_ale_pins[] = { BOOT_9 };
+static const unsigned int nand_cle_pins[] = { BOOT_10 };
+static const unsigned int nand_ce0_pins[] = { BOOT_11 };
+static const unsigned int nand_ren_wr_pins[] = { BOOT_12 };
+static const unsigned int nand_rb0_pins[] = { BOOT_14 };
+static const unsigned int nand_ce1_pins[] = { BOOT_15 };
+
+/* nor */
+static const unsigned int nor_hold_pins[] = { BOOT_3 };
+static const unsigned int nor_d_pins[] = { BOOT_4 };
+static const unsigned int nor_q_pins[] = { BOOT_5 };
+static const unsigned int nor_c_pins[] = { BOOT_6 };
+static const unsigned int nor_wp_pins[] = { BOOT_7 };
+static const unsigned int nor_cs_pins[] = { BOOT_14 };
+
+/* sdio */
+static const unsigned int sdio_d0_pins[] = { GPIOX_0 };
+static const unsigned int sdio_d1_pins[] = { GPIOX_1 };
+static const unsigned int sdio_d2_pins[] = { GPIOX_2 };
+static const unsigned int sdio_d3_pins[] = { GPIOX_3 };
+static const unsigned int sdio_clk_pins[] = { GPIOX_4 };
+static const unsigned int sdio_cmd_pins[] = { GPIOX_5 };
+
+/* sdcard */
+static const unsigned int sdcard_d0_c_pins[] = { GPIOC_0 };
+static const unsigned int sdcard_d1_c_pins[] = { GPIOC_1 };
+static const unsigned int sdcard_d2_c_pins[] = { GPIOC_2 };
+static const unsigned int sdcard_d3_c_pins[] = { GPIOC_3 };
+static const unsigned int sdcard_clk_c_pins[] = { GPIOC_4 };
+static const unsigned int sdcard_cmd_c_pins[] = { GPIOC_5 };
+
+static const unsigned int sdcard_d0_z_pins[] = { GPIOZ_2 };
+static const unsigned int sdcard_d1_z_pins[] = { GPIOZ_3 };
+static const unsigned int sdcard_d2_z_pins[] = { GPIOZ_4 };
+static const unsigned int sdcard_d3_z_pins[] = { GPIOZ_5 };
+static const unsigned int sdcard_clk_z_pins[] = { GPIOZ_6 };
+static const unsigned int sdcard_cmd_z_pins[] = { GPIOZ_7 };
+
+/* spi0 */
+static const unsigned int spi0_mosi_c_pins[] = { GPIOC_0 };
+static const unsigned int spi0_miso_c_pins[] = { GPIOC_1 };
+static const unsigned int spi0_ss0_c_pins[] = { GPIOC_2 };
+static const unsigned int spi0_clk_c_pins[] = { GPIOC_3 };
+
+static const unsigned int spi0_mosi_x_pins[] = { GPIOX_8 };
+static const unsigned int spi0_miso_x_pins[] = { GPIOX_9 };
+static const unsigned int spi0_ss0_x_pins[] = { GPIOX_10 };
+static const unsigned int spi0_clk_x_pins[] = { GPIOX_11 };
+
+/* spi1 */
+static const unsigned int spi1_mosi_pins[] = { GPIOH_4 };
+static const unsigned int spi1_miso_pins[] = { GPIOH_5 };
+static const unsigned int spi1_ss0_pins[] = { GPIOH_6 };
+static const unsigned int spi1_clk_pins[] = { GPIOH_7 };
+
+/* i2c0 */
+static const unsigned int i2c0_sda_c_pins[] = { GPIOC_5 };
+static const unsigned int i2c0_sck_c_pins[] = { GPIOC_6 };
+static const unsigned int i2c0_sda_z0_pins[] = { GPIOZ_0 };
+static const unsigned int i2c0_sck_z1_pins[] = { GPIOZ_1 };
+static const unsigned int i2c0_sda_z7_pins[] = { GPIOZ_7 };
+static const unsigned int i2c0_sck_z8_pins[] = { GPIOZ_8 };
+
+/* i2c1 */
+static const unsigned int i2c1_sda_x_pins[] = { GPIOX_10 };
+static const unsigned int i2c1_sck_x_pins[] = { GPIOX_11 };
+static const unsigned int i2c1_sda_h2_pins[] = { GPIOH_2 };
+static const unsigned int i2c1_sck_h3_pins[] = { GPIOH_3 };
+static const unsigned int i2c1_sda_h6_pins[] = { GPIOH_6 };
+static const unsigned int i2c1_sck_h7_pins[] = { GPIOH_7 };
+
+/* i2c2 */
+static const unsigned int i2c2_sda_x_pins[] = { GPIOX_17 };
+static const unsigned int i2c2_sck_x_pins[] = { GPIOX_18 };
+static const unsigned int i2c2_sda_z_pins[] = { GPIOZ_14 };
+static const unsigned int i2c2_sck_z_pins[] = { GPIOZ_15 };
+
+/* i2c3 */
+static const unsigned int i2c3_sda_h_pins[] = { GPIOH_0 };
+static const unsigned int i2c3_sck_h_pins[] = { GPIOH_1 };
+static const unsigned int i2c3_sda_a_pins[] = { GPIOA_14 };
+static const unsigned int i2c3_sck_a_pins[] = { GPIOA_15 };
+
+/* uart_a */
+static const unsigned int uart_a_tx_pins[] = { GPIOX_12 };
+static const unsigned int uart_a_rx_pins[] = { GPIOX_13 };
+static const unsigned int uart_a_cts_pins[] = { GPIOX_14 };
+static const unsigned int uart_a_rts_pins[] = { GPIOX_15 };
+
+/* uart_b */
+static const unsigned int uart_b_tx_pins[] = { GPIOX_6 };
+static const unsigned int uart_b_rx_pins[] = { GPIOX_7 };
+
+/* uart_c */
+static const unsigned int uart_c_rts_pins[] = { GPIOH_4 };
+static const unsigned int uart_c_cts_pins[] = { GPIOH_5 };
+static const unsigned int uart_c_rx_pins[] = { GPIOH_6 };
+static const unsigned int uart_c_tx_pins[] = { GPIOH_7 };
+
+/* uart_ao_a_c */
+static const unsigned int uart_ao_a_rx_c_pins[] = { GPIOC_2 };
+static const unsigned int uart_ao_a_tx_c_pins[] = { GPIOC_3 };
+
+/* iso7816 */
+static const unsigned int iso7816_clk_c_pins[] = { GPIOC_5 };
+static const unsigned int iso7816_data_c_pins[] = { GPIOC_6 };
+static const unsigned int iso7816_clk_x_pins[] = { GPIOX_8 };
+static const unsigned int iso7816_data_x_pins[] = { GPIOX_9 };
+static const unsigned int iso7816_clk_h_pins[] = { GPIOH_6 };
+static const unsigned int iso7816_data_h_pins[] = { GPIOH_7 };
+static const unsigned int iso7816_clk_z_pins[] = { GPIOZ_0 };
+static const unsigned int iso7816_data_z_pins[] = { GPIOZ_1 };
+
+/* eth */
+static const unsigned int eth_mdio_pins[] = { GPIOZ_0 };
+static const unsigned int eth_mdc_pins[] = { GPIOZ_1 };
+static const unsigned int eth_rgmii_rx_clk_pins[] = { GPIOZ_2 };
+static const unsigned int eth_rx_dv_pins[] = { GPIOZ_3 };
+static const unsigned int eth_rxd0_pins[] = { GPIOZ_4 };
+static const unsigned int eth_rxd1_pins[] = { GPIOZ_5 };
+static const unsigned int eth_rxd2_rgmii_pins[] = { GPIOZ_6 };
+static const unsigned int eth_rxd3_rgmii_pins[] = { GPIOZ_7 };
+static const unsigned int eth_rgmii_tx_clk_pins[] = { GPIOZ_8 };
+static const unsigned int eth_txen_pins[] = { GPIOZ_9 };
+static const unsigned int eth_txd0_pins[] = { GPIOZ_10 };
+static const unsigned int eth_txd1_pins[] = { GPIOZ_11 };
+static const unsigned int eth_txd2_rgmii_pins[] = { GPIOZ_12 };
+static const unsigned int eth_txd3_rgmii_pins[] = { GPIOZ_13 };
+static const unsigned int eth_link_led_pins[] = { GPIOZ_14 };
+static const unsigned int eth_act_led_pins[] = { GPIOZ_15 };
+
+/* pwm_a */
+static const unsigned int pwm_a_pins[] = { GPIOX_6 };
+
+/* pwm_b */
+static const unsigned int pwm_b_x7_pins[] = { GPIOX_7 };
+static const unsigned int pwm_b_x19_pins[] = { GPIOX_19 };
+
+/* pwm_c */
+static const unsigned int pwm_c_c_pins[] = { GPIOC_4 };
+static const unsigned int pwm_c_x5_pins[] = { GPIOX_5 };
+static const unsigned int pwm_c_x8_pins[] = { GPIOX_8 };
+
+/* pwm_d */
+static const unsigned int pwm_d_x3_pins[] = { GPIOX_3 };
+static const unsigned int pwm_d_x6_pins[] = { GPIOX_6 };
+
+/* pwm_e */
+static const unsigned int pwm_e_pins[] = { GPIOX_16 };
+
+/* pwm_f */
+static const unsigned int pwm_f_x_pins[] = { GPIOX_7 };
+static const unsigned int pwm_f_h_pins[] = { GPIOH_5 };
+
+/* cec_ao */
+static const unsigned int cec_ao_a_h_pins[] = { GPIOH_3 };
+static const unsigned int cec_ao_b_h_pins[] = { GPIOH_3 };
+
+/* jtag_b */
+static const unsigned int jtag_b_tdo_pins[] = { GPIOC_0 };
+static const unsigned int jtag_b_tdi_pins[] = { GPIOC_1 };
+static const unsigned int jtag_b_clk_pins[] = { GPIOC_4 };
+static const unsigned int jtag_b_tms_pins[] = { GPIOC_5 };
+
+/* bt565_a */
+static const unsigned int bt565_a_vs_pins[] = { GPIOZ_0 };
+static const unsigned int bt565_a_hs_pins[] = { GPIOZ_1 };
+static const unsigned int bt565_a_clk_pins[] = { GPIOZ_3 };
+static const unsigned int bt565_a_din0_pins[] = { GPIOZ_4 };
+static const unsigned int bt565_a_din1_pins[] = { GPIOZ_5 };
+static const unsigned int bt565_a_din2_pins[] = { GPIOZ_6 };
+static const unsigned int bt565_a_din3_pins[] = { GPIOZ_7 };
+static const unsigned int bt565_a_din4_pins[] = { GPIOZ_8 };
+static const unsigned int bt565_a_din5_pins[] = { GPIOZ_9 };
+static const unsigned int bt565_a_din6_pins[] = { GPIOZ_10 };
+static const unsigned int bt565_a_din7_pins[] = { GPIOZ_11 };
+
+/* tsin_a */
+static const unsigned int tsin_a_valid_pins[] = { GPIOX_2 };
+static const unsigned int tsin_a_sop_pins[] = { GPIOX_1 };
+static const unsigned int tsin_a_din0_pins[] = { GPIOX_0 };
+static const unsigned int tsin_a_clk_pins[] = { GPIOX_3 };
+
+/* tsin_b */
+static const unsigned int tsin_b_valid_x_pins[] = { GPIOX_9 };
+static const unsigned int tsin_b_sop_x_pins[] = { GPIOX_8 };
+static const unsigned int tsin_b_din0_x_pins[] = { GPIOX_10 };
+static const unsigned int tsin_b_clk_x_pins[] = { GPIOX_11 };
+
+static const unsigned int tsin_b_valid_z_pins[] = { GPIOZ_2 };
+static const unsigned int tsin_b_sop_z_pins[] = { GPIOZ_3 };
+static const unsigned int tsin_b_din0_z_pins[] = { GPIOZ_4 };
+static const unsigned int tsin_b_clk_z_pins[] = { GPIOZ_5 };
+
+static const unsigned int tsin_b_fail_pins[] = { GPIOZ_6 };
+static const unsigned int tsin_b_din1_pins[] = { GPIOZ_7 };
+static const unsigned int tsin_b_din2_pins[] = { GPIOZ_8 };
+static const unsigned int tsin_b_din3_pins[] = { GPIOZ_9 };
+static const unsigned int tsin_b_din4_pins[] = { GPIOZ_10 };
+static const unsigned int tsin_b_din5_pins[] = { GPIOZ_11 };
+static const unsigned int tsin_b_din6_pins[] = { GPIOZ_12 };
+static const unsigned int tsin_b_din7_pins[] = { GPIOZ_13 };
+
+/* hdmitx */
+static const unsigned int hdmitx_sda_pins[] = { GPIOH_0 };
+static const unsigned int hdmitx_sck_pins[] = { GPIOH_1 };
+static const unsigned int hdmitx_hpd_in_pins[] = { GPIOH_2 };
+
+/* pdm */
+static const unsigned int pdm_din0_c_pins[] = { GPIOC_0 };
+static const unsigned int pdm_din1_c_pins[] = { GPIOC_1 };
+static const unsigned int pdm_din2_c_pins[] = { GPIOC_2 };
+static const unsigned int pdm_din3_c_pins[] = { GPIOC_3 };
+static const unsigned int pdm_dclk_c_pins[] = { GPIOC_4 };
+
+static const unsigned int pdm_din0_x_pins[] = { GPIOX_0 };
+static const unsigned int pdm_din1_x_pins[] = { GPIOX_1 };
+static const unsigned int pdm_din2_x_pins[] = { GPIOX_2 };
+static const unsigned int pdm_din3_x_pins[] = { GPIOX_3 };
+static const unsigned int pdm_dclk_x_pins[] = { GPIOX_4 };
+
+static const unsigned int pdm_din0_z_pins[] = { GPIOZ_2 };
+static const unsigned int pdm_din1_z_pins[] = { GPIOZ_3 };
+static const unsigned int pdm_din2_z_pins[] = { GPIOZ_4 };
+static const unsigned int pdm_din3_z_pins[] = { GPIOZ_5 };
+static const unsigned int pdm_dclk_z_pins[] = { GPIOZ_6 };
+
+static const unsigned int pdm_din0_a_pins[] = { GPIOA_8 };
+static const unsigned int pdm_din1_a_pins[] = { GPIOA_9 };
+static const unsigned int pdm_din2_a_pins[] = { GPIOA_6 };
+static const unsigned int pdm_din3_a_pins[] = { GPIOA_5 };
+static const unsigned int pdm_dclk_a_pins[] = { GPIOA_7 };
+
+/* spdif_in */
+static const unsigned int spdif_in_h_pins[] = { GPIOH_5 };
+static const unsigned int spdif_in_a10_pins[] = { GPIOA_10 };
+static const unsigned int spdif_in_a12_pins[] = { GPIOA_12 };
+
+/* spdif_out */
+static const unsigned int spdif_out_h_pins[] = { GPIOH_4 };
+static const unsigned int spdif_out_a11_pins[] = { GPIOA_11 };
+static const unsigned int spdif_out_a13_pins[] = { GPIOA_13 };
+
+/* mclk0 */
+static const unsigned int mclk0_a_pins[] = { GPIOA_0 };
+
+/* mclk1 */
+static const unsigned int mclk1_x_pins[] = { GPIOX_5 };
+static const unsigned int mclk1_z_pins[] = { GPIOZ_8 };
+static const unsigned int mclk1_a_pins[] = { GPIOA_11 };
+
+/* tdm */
+static const unsigned int tdm_a_slv_sclk_pins[] = { GPIOX_11 };
+static const unsigned int tdm_a_slv_fs_pins[] = { GPIOX_10 };
+static const unsigned int tdm_a_sclk_pins[] = { GPIOX_11 };
+static const unsigned int tdm_a_fs_pins[] = { GPIOX_10 };
+static const unsigned int tdm_a_din0_pins[] = { GPIOX_9 };
+static const unsigned int tdm_a_din1_pins[] = { GPIOX_8 };
+static const unsigned int tdm_a_dout0_pins[] = { GPIOX_9 };
+static const unsigned int tdm_a_dout1_pins[] = { GPIOX_8 };
+
+static const unsigned int tdm_b_slv_sclk_pins[] = { GPIOA_1 };
+static const unsigned int tdm_b_slv_fs_pins[] = { GPIOA_2 };
+static const unsigned int tdm_b_sclk_pins[] = { GPIOA_1 };
+static const unsigned int tdm_b_fs_pins[] = { GPIOA_2 };
+static const unsigned int tdm_b_din0_pins[] = { GPIOA_3 };
+static const unsigned int tdm_b_din1_pins[] = { GPIOA_4 };
+static const unsigned int tdm_b_din2_pins[] = { GPIOA_5 };
+static const unsigned int tdm_b_din3_a_pins[] = { GPIOA_6 };
+static const unsigned int tdm_b_din3_h_pins[] = { GPIOH_5 };
+static const unsigned int tdm_b_dout0_pins[] = { GPIOA_3 };
+static const unsigned int tdm_b_dout1_pins[] = { GPIOA_4 };
+static const unsigned int tdm_b_dout2_pins[] = { GPIOA_5 };
+static const unsigned int tdm_b_dout3_a_pins[] = { GPIOA_6 };
+static const unsigned int tdm_b_dout3_h_pins[] = { GPIOH_5 };
+
+static const unsigned int tdm_c_slv_sclk_a_pins[] = { GPIOA_12 };
+static const unsigned int tdm_c_slv_fs_a_pins[] = { GPIOA_13 };
+static const unsigned int tdm_c_slv_sclk_z_pins[] = { GPIOZ_7 };
+static const unsigned int tdm_c_slv_fs_z_pins[] = { GPIOZ_6 };
+static const unsigned int tdm_c_sclk_a_pins[] = { GPIOA_12 };
+static const unsigned int tdm_c_fs_a_pins[] = { GPIOA_13 };
+static const unsigned int tdm_c_sclk_z_pins[] = { GPIOZ_7 };
+static const unsigned int tdm_c_fs_z_pins[] = { GPIOZ_6 };
+static const unsigned int tdm_c_din0_a_pins[] = { GPIOA_10 };
+static const unsigned int tdm_c_din1_a_pins[] = { GPIOA_9 };
+static const unsigned int tdm_c_din2_a_pins[] = { GPIOA_8 };
+static const unsigned int tdm_c_din3_a_pins[] = { GPIOA_7 };
+static const unsigned int tdm_c_din0_z_pins[] = { GPIOZ_2 };
+static const unsigned int tdm_c_din1_z_pins[] = { GPIOZ_3 };
+static const unsigned int tdm_c_din2_z_pins[] = { GPIOZ_4 };
+static const unsigned int tdm_c_din3_z_pins[] = { GPIOZ_5 };
+static const unsigned int tdm_c_dout0_a_pins[] = { GPIOA_10 };
+static const unsigned int tdm_c_dout1_a_pins[] = { GPIOA_9 };
+static const unsigned int tdm_c_dout2_a_pins[] = { GPIOA_8 };
+static const unsigned int tdm_c_dout3_a_pins[] = { GPIOA_7 };
+static const unsigned int tdm_c_dout0_z_pins[] = { GPIOZ_2 };
+static const unsigned int tdm_c_dout1_z_pins[] = { GPIOZ_3 };
+static const unsigned int tdm_c_dout2_z_pins[] = { GPIOZ_4 };
+static const unsigned int tdm_c_dout3_z_pins[] = { GPIOZ_5 };
+
+static struct meson_pmx_group meson_g12a_periphs_groups[] = {
+ GPIO_GROUP(GPIOZ_0),
+ GPIO_GROUP(GPIOZ_1),
+ GPIO_GROUP(GPIOZ_2),
+ GPIO_GROUP(GPIOZ_3),
+ GPIO_GROUP(GPIOZ_4),
+ GPIO_GROUP(GPIOZ_5),
+ GPIO_GROUP(GPIOZ_6),
+ GPIO_GROUP(GPIOZ_7),
+ GPIO_GROUP(GPIOZ_8),
+ GPIO_GROUP(GPIOZ_9),
+ GPIO_GROUP(GPIOZ_10),
+ GPIO_GROUP(GPIOZ_11),
+ GPIO_GROUP(GPIOZ_12),
+ GPIO_GROUP(GPIOZ_13),
+ GPIO_GROUP(GPIOZ_14),
+ GPIO_GROUP(GPIOZ_15),
+ GPIO_GROUP(GPIOH_0),
+ GPIO_GROUP(GPIOH_1),
+ GPIO_GROUP(GPIOH_2),
+ GPIO_GROUP(GPIOH_3),
+ GPIO_GROUP(GPIOH_4),
+ GPIO_GROUP(GPIOH_5),
+ GPIO_GROUP(GPIOH_6),
+ GPIO_GROUP(GPIOH_7),
+ GPIO_GROUP(GPIOH_8),
+ GPIO_GROUP(BOOT_0),
+ GPIO_GROUP(BOOT_1),
+ GPIO_GROUP(BOOT_2),
+ GPIO_GROUP(BOOT_3),
+ GPIO_GROUP(BOOT_4),
+ GPIO_GROUP(BOOT_5),
+ GPIO_GROUP(BOOT_6),
+ GPIO_GROUP(BOOT_7),
+ GPIO_GROUP(BOOT_8),
+ GPIO_GROUP(BOOT_9),
+ GPIO_GROUP(BOOT_10),
+ GPIO_GROUP(BOOT_11),
+ GPIO_GROUP(BOOT_12),
+ GPIO_GROUP(BOOT_13),
+ GPIO_GROUP(BOOT_14),
+ GPIO_GROUP(BOOT_15),
+ GPIO_GROUP(GPIOC_0),
+ GPIO_GROUP(GPIOC_1),
+ GPIO_GROUP(GPIOC_2),
+ GPIO_GROUP(GPIOC_3),
+ GPIO_GROUP(GPIOC_4),
+ GPIO_GROUP(GPIOC_5),
+ GPIO_GROUP(GPIOC_6),
+ GPIO_GROUP(GPIOC_7),
+ GPIO_GROUP(GPIOA_0),
+ GPIO_GROUP(GPIOA_1),
+ GPIO_GROUP(GPIOA_2),
+ GPIO_GROUP(GPIOA_3),
+ GPIO_GROUP(GPIOA_4),
+ GPIO_GROUP(GPIOA_5),
+ GPIO_GROUP(GPIOA_6),
+ GPIO_GROUP(GPIOA_7),
+ GPIO_GROUP(GPIOA_8),
+ GPIO_GROUP(GPIOA_9),
+ GPIO_GROUP(GPIOA_10),
+ GPIO_GROUP(GPIOA_11),
+ GPIO_GROUP(GPIOA_12),
+ GPIO_GROUP(GPIOA_13),
+ GPIO_GROUP(GPIOA_14),
+ GPIO_GROUP(GPIOA_15),
+ GPIO_GROUP(GPIOX_0),
+ GPIO_GROUP(GPIOX_1),
+ GPIO_GROUP(GPIOX_2),
+ GPIO_GROUP(GPIOX_3),
+ GPIO_GROUP(GPIOX_4),
+ GPIO_GROUP(GPIOX_5),
+ GPIO_GROUP(GPIOX_6),
+ GPIO_GROUP(GPIOX_7),
+ GPIO_GROUP(GPIOX_8),
+ GPIO_GROUP(GPIOX_9),
+ GPIO_GROUP(GPIOX_10),
+ GPIO_GROUP(GPIOX_11),
+ GPIO_GROUP(GPIOX_12),
+ GPIO_GROUP(GPIOX_13),
+ GPIO_GROUP(GPIOX_14),
+ GPIO_GROUP(GPIOX_15),
+ GPIO_GROUP(GPIOX_16),
+ GPIO_GROUP(GPIOX_17),
+ GPIO_GROUP(GPIOX_18),
+ GPIO_GROUP(GPIOX_19),
+
+ /* bank BOOT */
+ GROUP(emmc_nand_d0, 1),
+ GROUP(emmc_nand_d1, 1),
+ GROUP(emmc_nand_d2, 1),
+ GROUP(emmc_nand_d3, 1),
+ GROUP(emmc_nand_d4, 1),
+ GROUP(emmc_nand_d5, 1),
+ GROUP(emmc_nand_d6, 1),
+ GROUP(emmc_nand_d7, 1),
+ GROUP(emmc_clk, 1),
+ GROUP(emmc_cmd, 1),
+ GROUP(emmc_nand_ds, 1),
+ GROUP(nand_ce0, 2),
+ GROUP(nand_ale, 2),
+ GROUP(nand_cle, 2),
+ GROUP(nand_wen_clk, 2),
+ GROUP(nand_ren_wr, 2),
+ GROUP(nand_rb0, 2),
+ GROUP(nand_ce1, 2),
+ GROUP(nor_hold, 3),
+ GROUP(nor_d, 3),
+ GROUP(nor_q, 3),
+ GROUP(nor_c, 3),
+ GROUP(nor_wp, 3),
+ GROUP(nor_cs, 3),
+
+ /* bank GPIOZ */
+ GROUP(sdcard_d0_z, 5),
+ GROUP(sdcard_d1_z, 5),
+ GROUP(sdcard_d2_z, 5),
+ GROUP(sdcard_d3_z, 5),
+ GROUP(sdcard_clk_z, 5),
+ GROUP(sdcard_cmd_z, 5),
+ GROUP(i2c0_sda_z0, 4),
+ GROUP(i2c0_sck_z1, 4),
+ GROUP(i2c0_sda_z7, 7),
+ GROUP(i2c0_sck_z8, 7),
+ GROUP(i2c2_sda_z, 3),
+ GROUP(i2c2_sck_z, 3),
+ GROUP(iso7816_clk_z, 3),
+ GROUP(iso7816_data_z, 3),
+ GROUP(eth_mdio, 1),
+ GROUP(eth_mdc, 1),
+ GROUP(eth_rgmii_rx_clk, 1),
+ GROUP(eth_rx_dv, 1),
+ GROUP(eth_rxd0, 1),
+ GROUP(eth_rxd1, 1),
+ GROUP(eth_rxd2_rgmii, 1),
+ GROUP(eth_rxd3_rgmii, 1),
+ GROUP(eth_rgmii_tx_clk, 1),
+ GROUP(eth_txen, 1),
+ GROUP(eth_txd0, 1),
+ GROUP(eth_txd1, 1),
+ GROUP(eth_txd2_rgmii, 1),
+ GROUP(eth_txd3_rgmii, 1),
+ GROUP(eth_link_led, 1),
+ GROUP(eth_act_led, 1),
+ GROUP(bt565_a_vs, 2),
+ GROUP(bt565_a_hs, 2),
+ GROUP(bt565_a_clk, 2),
+ GROUP(bt565_a_din0, 2),
+ GROUP(bt565_a_din1, 2),
+ GROUP(bt565_a_din2, 2),
+ GROUP(bt565_a_din3, 2),
+ GROUP(bt565_a_din4, 2),
+ GROUP(bt565_a_din5, 2),
+ GROUP(bt565_a_din6, 2),
+ GROUP(bt565_a_din7, 2),
+ GROUP(tsin_b_valid_z, 3),
+ GROUP(tsin_b_sop_z, 3),
+ GROUP(tsin_b_din0_z, 3),
+ GROUP(tsin_b_clk_z, 3),
+ GROUP(tsin_b_fail, 3),
+ GROUP(tsin_b_din1, 3),
+ GROUP(tsin_b_din2, 3),
+ GROUP(tsin_b_din3, 3),
+ GROUP(tsin_b_din4, 3),
+ GROUP(tsin_b_din5, 3),
+ GROUP(tsin_b_din6, 3),
+ GROUP(tsin_b_din7, 3),
+ GROUP(pdm_din0_z, 7),
+ GROUP(pdm_din1_z, 7),
+ GROUP(pdm_din2_z, 7),
+ GROUP(pdm_din3_z, 7),
+ GROUP(pdm_dclk_z, 7),
+ GROUP(tdm_c_slv_sclk_z, 6),
+ GROUP(tdm_c_slv_fs_z, 6),
+ GROUP(tdm_c_din0_z, 6),
+ GROUP(tdm_c_din1_z, 6),
+ GROUP(tdm_c_din2_z, 6),
+ GROUP(tdm_c_din3_z, 6),
+ GROUP(tdm_c_sclk_z, 4),
+ GROUP(tdm_c_fs_z, 4),
+ GROUP(tdm_c_dout0_z, 4),
+ GROUP(tdm_c_dout1_z, 4),
+ GROUP(tdm_c_dout2_z, 4),
+ GROUP(tdm_c_dout3_z, 4),
+ GROUP(mclk1_z, 4),
+
+ /* bank GPIOX */
+ GROUP(sdio_d0, 1),
+ GROUP(sdio_d1, 1),
+ GROUP(sdio_d2, 1),
+ GROUP(sdio_d3, 1),
+ GROUP(sdio_clk, 1),
+ GROUP(sdio_cmd, 1),
+ GROUP(spi0_mosi_x, 4),
+ GROUP(spi0_miso_x, 4),
+ GROUP(spi0_ss0_x, 4),
+ GROUP(spi0_clk_x, 4),
+ GROUP(i2c1_sda_x, 5),
+ GROUP(i2c1_sck_x, 5),
+ GROUP(i2c2_sda_x, 1),
+ GROUP(i2c2_sck_x, 1),
+ GROUP(uart_a_tx, 1),
+ GROUP(uart_a_rx, 1),
+ GROUP(uart_a_cts, 1),
+ GROUP(uart_a_rts, 1),
+ GROUP(uart_b_tx, 2),
+ GROUP(uart_b_rx, 2),
+ GROUP(iso7816_clk_x, 6),
+ GROUP(iso7816_data_x, 6),
+ GROUP(pwm_a, 1),
+ GROUP(pwm_b_x7, 4),
+ GROUP(pwm_b_x19, 1),
+ GROUP(pwm_c_x5, 4),
+ GROUP(pwm_c_x8, 5),
+ GROUP(pwm_d_x3, 4),
+ GROUP(pwm_d_x6, 4),
+ GROUP(pwm_e, 1),
+ GROUP(pwm_f_x, 1),
+ GROUP(tsin_a_valid, 3),
+ GROUP(tsin_a_sop, 3),
+ GROUP(tsin_a_din0, 3),
+ GROUP(tsin_a_clk, 3),
+ GROUP(tsin_b_valid_x, 3),
+ GROUP(tsin_b_sop_x, 3),
+ GROUP(tsin_b_din0_x, 3),
+ GROUP(tsin_b_clk_x, 3),
+ GROUP(pdm_din0_x, 2),
+ GROUP(pdm_din1_x, 2),
+ GROUP(pdm_din2_x, 2),
+ GROUP(pdm_din3_x, 2),
+ GROUP(pdm_dclk_x, 2),
+ GROUP(tdm_a_slv_sclk, 2),
+ GROUP(tdm_a_slv_fs, 2),
+ GROUP(tdm_a_din0, 2),
+ GROUP(tdm_a_din1, 2),
+ GROUP(tdm_a_sclk, 1),
+ GROUP(tdm_a_fs, 1),
+ GROUP(tdm_a_dout0, 1),
+ GROUP(tdm_a_dout1, 1),
+ GROUP(mclk1_x, 2),
+
+ /* bank GPIOC */
+ GROUP(sdcard_d0_c, 1),
+ GROUP(sdcard_d1_c, 1),
+ GROUP(sdcard_d2_c, 1),
+ GROUP(sdcard_d3_c, 1),
+ GROUP(sdcard_clk_c, 1),
+ GROUP(sdcard_cmd_c, 1),
+ GROUP(spi0_mosi_c, 5),
+ GROUP(spi0_miso_c, 5),
+ GROUP(spi0_ss0_c, 5),
+ GROUP(spi0_clk_c, 5),
+ GROUP(i2c0_sda_c, 3),
+ GROUP(i2c0_sck_c, 3),
+ GROUP(uart_ao_a_rx_c, 2),
+ GROUP(uart_ao_a_tx_c, 2),
+ GROUP(iso7816_clk_c, 5),
+ GROUP(iso7816_data_c, 5),
+ GROUP(pwm_c_c, 5),
+ GROUP(jtag_b_tdo, 2),
+ GROUP(jtag_b_tdi, 2),
+ GROUP(jtag_b_clk, 2),
+ GROUP(jtag_b_tms, 2),
+ GROUP(pdm_din0_c, 4),
+ GROUP(pdm_din1_c, 4),
+ GROUP(pdm_din2_c, 4),
+ GROUP(pdm_din3_c, 4),
+ GROUP(pdm_dclk_c, 4),
+
+ /* bank GPIOH */
+ GROUP(spi1_mosi, 3),
+ GROUP(spi1_miso, 3),
+ GROUP(spi1_ss0, 3),
+ GROUP(spi1_clk, 3),
+ GROUP(i2c1_sda_h2, 2),
+ GROUP(i2c1_sck_h3, 2),
+ GROUP(i2c1_sda_h6, 4),
+ GROUP(i2c1_sck_h7, 4),
+ GROUP(i2c3_sda_h, 2),
+ GROUP(i2c3_sck_h, 2),
+ GROUP(uart_c_tx, 2),
+ GROUP(uart_c_rx, 2),
+ GROUP(uart_c_cts, 2),
+ GROUP(uart_c_rts, 2),
+ GROUP(iso7816_clk_h, 1),
+ GROUP(iso7816_data_h, 1),
+ GROUP(pwm_f_h, 4),
+ GROUP(cec_ao_a_h, 4),
+ GROUP(cec_ao_b_h, 5),
+ GROUP(hdmitx_sda, 1),
+ GROUP(hdmitx_sck, 1),
+ GROUP(hdmitx_hpd_in, 1),
+ GROUP(spdif_out_h, 1),
+ GROUP(spdif_in_h, 1),
+ GROUP(tdm_b_din3_h, 6),
+ GROUP(tdm_b_dout3_h, 5),
+
+ /* bank GPIOA */
+ GROUP(i2c3_sda_a, 2),
+ GROUP(i2c3_sck_a, 2),
+ GROUP(pdm_din0_a, 1),
+ GROUP(pdm_din1_a, 1),
+ GROUP(pdm_din2_a, 1),
+ GROUP(pdm_din3_a, 1),
+ GROUP(pdm_dclk_a, 1),
+ GROUP(spdif_in_a10, 1),
+ GROUP(spdif_in_a12, 1),
+ GROUP(spdif_out_a11, 1),
+ GROUP(spdif_out_a13, 1),
+ GROUP(tdm_b_slv_sclk, 2),
+ GROUP(tdm_b_slv_fs, 2),
+ GROUP(tdm_b_din0, 2),
+ GROUP(tdm_b_din1, 2),
+ GROUP(tdm_b_din2, 2),
+ GROUP(tdm_b_din3_a, 2),
+ GROUP(tdm_b_sclk, 1),
+ GROUP(tdm_b_fs, 1),
+ GROUP(tdm_b_dout0, 1),
+ GROUP(tdm_b_dout1, 1),
+ GROUP(tdm_b_dout2, 3),
+ GROUP(tdm_b_dout3_a, 3),
+ GROUP(tdm_c_slv_sclk_a, 3),
+ GROUP(tdm_c_slv_fs_a, 3),
+ GROUP(tdm_c_din0_a, 3),
+ GROUP(tdm_c_din1_a, 3),
+ GROUP(tdm_c_din2_a, 3),
+ GROUP(tdm_c_din3_a, 3),
+ GROUP(tdm_c_sclk_a, 2),
+ GROUP(tdm_c_fs_a, 2),
+ GROUP(tdm_c_dout0_a, 2),
+ GROUP(tdm_c_dout1_a, 2),
+ GROUP(tdm_c_dout2_a, 2),
+ GROUP(tdm_c_dout3_a, 2),
+ GROUP(mclk0_a, 1),
+ GROUP(mclk1_a, 2),
+};
+
+/* uart_ao_a */
+static const unsigned int uart_ao_a_tx_pins[] = { GPIOAO_0 };
+static const unsigned int uart_ao_a_rx_pins[] = { GPIOAO_1 };
+static const unsigned int uart_ao_a_cts_pins[] = { GPIOE_0 };
+static const unsigned int uart_ao_a_rts_pins[] = { GPIOE_1 };
+
+/* uart_ao_b */
+static const unsigned int uart_ao_b_tx_2_pins[] = { GPIOAO_2 };
+static const unsigned int uart_ao_b_rx_3_pins[] = { GPIOAO_3 };
+static const unsigned int uart_ao_b_tx_8_pins[] = { GPIOAO_8 };
+static const unsigned int uart_ao_b_rx_9_pins[] = { GPIOAO_9 };
+static const unsigned int uart_ao_b_cts_pins[] = { GPIOE_0 };
+static const unsigned int uart_ao_b_rts_pins[] = { GPIOE_1 };
+
+/* i2c_ao */
+static const unsigned int i2c_ao_sck_pins[] = { GPIOAO_2 };
+static const unsigned int i2c_ao_sda_pins[] = { GPIOAO_3 };
+
+static const unsigned int i2c_ao_sck_e_pins[] = { GPIOE_0 };
+static const unsigned int i2c_ao_sda_e_pins[] = { GPIOE_1 };
+
+/* i2c_ao_slave */
+static const unsigned int i2c_ao_slave_sck_pins[] = { GPIOAO_2 };
+static const unsigned int i2c_ao_slave_sda_pins[] = { GPIOAO_3 };
+
+/* ir_in */
+static const unsigned int remote_ao_input_pins[] = { GPIOAO_5 };
+
+/* ir_out */
+static const unsigned int remote_ao_out_pins[] = { GPIOAO_4 };
+
+/* pwm_ao_a */
+static const unsigned int pwm_ao_a_pins[] = { GPIOAO_11 };
+static const unsigned int pwm_ao_a_hiz_pins[] = { GPIOAO_11 };
+
+/* pwm_ao_b */
+static const unsigned int pwm_ao_b_pins[] = { GPIOE_0 };
+
+/* pwm_ao_c */
+static const unsigned int pwm_ao_c_4_pins[] = { GPIOAO_4 };
+static const unsigned int pwm_ao_c_hiz_pins[] = { GPIOAO_4 };
+static const unsigned int pwm_ao_c_6_pins[] = { GPIOAO_6 };
+
+/* pwm_ao_d */
+static const unsigned int pwm_ao_d_5_pins[] = { GPIOAO_5 };
+static const unsigned int pwm_ao_d_10_pins[] = { GPIOAO_10 };
+static const unsigned int pwm_ao_d_e_pins[] = { GPIOE_1 };
+
+/* jtag_a */
+static const unsigned int jtag_a_tdi_pins[] = { GPIOAO_8 };
+static const unsigned int jtag_a_tdo_pins[] = { GPIOAO_9 };
+static const unsigned int jtag_a_clk_pins[] = { GPIOAO_6 };
+static const unsigned int jtag_a_tms_pins[] = { GPIOAO_7 };
+
+/* cec_ao */
+static const unsigned int cec_ao_a_pins[] = { GPIOAO_10 };
+static const unsigned int cec_ao_b_pins[] = { GPIOAO_10 };
+
+/* tsin_ao_a */
+static const unsigned int tsin_ao_asop_pins[] = { GPIOAO_6 };
+static const unsigned int tsin_ao_adin0_pins[] = { GPIOAO_7 };
+static const unsigned int tsin_ao_aclk_pins[] = { GPIOAO_8 };
+static const unsigned int tsin_ao_a_valid_pins[] = { GPIOAO_9 };
+
+/* spdif_ao_out */
+static const unsigned int spdif_ao_out_pins[] = { GPIOAO_10 };
+
+/* tdm_ao_b */
+static const unsigned int tdm_ao_b_slv_fs_pins[] = { GPIOAO_7 };
+static const unsigned int tdm_ao_b_slv_sclk_pins[] = { GPIOAO_8 };
+static const unsigned int tdm_ao_b_fs_pins[] = { GPIOAO_7 };
+static const unsigned int tdm_ao_b_sclk_pins[] = { GPIOAO_8 };
+static const unsigned int tdm_ao_b_din0_pins[] = { GPIOAO_4 };
+static const unsigned int tdm_ao_b_din1_pins[] = { GPIOAO_10 };
+static const unsigned int tdm_ao_b_din2_pins[] = { GPIOAO_6 };
+static const unsigned int tdm_ao_b_dout0_pins[] = { GPIOAO_4 };
+static const unsigned int tdm_ao_b_dout1_pins[] = { GPIOAO_10 };
+static const unsigned int tdm_ao_b_dout2_pins[] = { GPIOAO_6 };
+
+/* mclk0_ao */
+static const unsigned int mclk0_ao_pins[] = { GPIOAO_9 };
+
+static struct meson_pmx_group meson_g12a_aobus_groups[] = {
+ GPIO_GROUP(GPIOAO_0),
+ GPIO_GROUP(GPIOAO_1),
+ GPIO_GROUP(GPIOAO_2),
+ GPIO_GROUP(GPIOAO_3),
+ GPIO_GROUP(GPIOAO_4),
+ GPIO_GROUP(GPIOAO_5),
+ GPIO_GROUP(GPIOAO_6),
+ GPIO_GROUP(GPIOAO_7),
+ GPIO_GROUP(GPIOAO_8),
+ GPIO_GROUP(GPIOAO_9),
+ GPIO_GROUP(GPIOAO_10),
+ GPIO_GROUP(GPIOAO_11),
+ GPIO_GROUP(GPIOE_0),
+ GPIO_GROUP(GPIOE_1),
+ GPIO_GROUP(GPIOE_2),
+
+ /* bank AO */
+ GROUP(uart_ao_a_tx, 1),
+ GROUP(uart_ao_a_rx, 1),
+ GROUP(uart_ao_a_cts, 1),
+ GROUP(uart_ao_a_rts, 1),
+ GROUP(uart_ao_b_tx_2, 2),
+ GROUP(uart_ao_b_rx_3, 2),
+ GROUP(uart_ao_b_tx_8, 3),
+ GROUP(uart_ao_b_rx_9, 3),
+ GROUP(uart_ao_b_cts, 2),
+ GROUP(uart_ao_b_rts, 2),
+ GROUP(i2c_ao_sck, 1),
+ GROUP(i2c_ao_sda, 1),
+ GROUP(i2c_ao_sck_e, 4),
+ GROUP(i2c_ao_sda_e, 4),
+ GROUP(i2c_ao_slave_sck, 3),
+ GROUP(i2c_ao_slave_sda, 3),
+ GROUP(remote_ao_input, 1),
+ GROUP(remote_ao_out, 1),
+ GROUP(pwm_ao_a, 3),
+ GROUP(pwm_ao_a_hiz, 2),
+ GROUP(pwm_ao_b, 3),
+ GROUP(pwm_ao_c_4, 3),
+ GROUP(pwm_ao_c_hiz, 4),
+ GROUP(pwm_ao_c_6, 3),
+ GROUP(pwm_ao_d_5, 3),
+ GROUP(pwm_ao_d_10, 3),
+ GROUP(pwm_ao_d_e, 3),
+ GROUP(jtag_a_tdi, 1),
+ GROUP(jtag_a_tdo, 1),
+ GROUP(jtag_a_clk, 1),
+ GROUP(jtag_a_tms, 1),
+ GROUP(cec_ao_a, 1),
+ GROUP(cec_ao_b, 2),
+ GROUP(tsin_ao_asop, 4),
+ GROUP(tsin_ao_adin0, 4),
+ GROUP(tsin_ao_aclk, 4),
+ GROUP(tsin_ao_a_valid, 4),
+ GROUP(spdif_ao_out, 4),
+ GROUP(tdm_ao_b_dout0, 5),
+ GROUP(tdm_ao_b_dout1, 5),
+ GROUP(tdm_ao_b_dout2, 5),
+ GROUP(tdm_ao_b_fs, 5),
+ GROUP(tdm_ao_b_sclk, 5),
+ GROUP(tdm_ao_b_din0, 6),
+ GROUP(tdm_ao_b_din1, 6),
+ GROUP(tdm_ao_b_din2, 6),
+ GROUP(tdm_ao_b_slv_fs, 6),
+ GROUP(tdm_ao_b_slv_sclk, 6),
+ GROUP(mclk0_ao, 5),
+};
+
+static const char * const gpio_periphs_groups[] = {
+ "GPIOZ_0", "GPIOZ_1", "GPIOZ_2", "GPIOZ_3", "GPIOZ_4",
+ "GPIOZ_5", "GPIOZ_6", "GPIOZ_7", "GPIOZ_8", "GPIOZ_9",
+ "GPIOZ_10", "GPIOZ_11", "GPIOZ_12", "GPIOZ_13", "GPIOZ_14",
+ "GPIOZ_15",
+
+ "GPIOH_0", "GPIOH_1", "GPIOH_2", "GPIOH_3", "GPIOH_4",
+ "GPIOH_5", "GPIOH_6", "GPIOH_7", "GPIOH_8",
+
+ "BOOT_0", "BOOT_1", "BOOT_2", "BOOT_3", "BOOT_4",
+ "BOOT_5", "BOOT_6", "BOOT_7", "BOOT_8", "BOOT_9",
+ "BOOT_10", "BOOT_11", "BOOT_12", "BOOT_13", "BOOT_14",
+ "BOOT_15",
+
+ "GPIOC_0", "GPIOC_1", "GPIOC_2", "GPIOC_3", "GPIOC_4",
+ "GPIOC_5", "GPIOC_6", "GPIOC_7",
+
+ "GPIOA_0", "GPIOA_1", "GPIOA_2", "GPIOA_3", "GPIOA_4",
+ "GPIOA_5", "GPIOA_6", "GPIOA_7", "GPIOA_8", "GPIOA_9",
+ "GPIOA_10", "GPIOA_11", "GPIOA_12", "GPIOA_13", "GPIOA_14",
+ "GPIOA_15",
+
+ "GPIOX_0", "GPIOX_1", "GPIOX_2", "GPIOX_3", "GPIOX_4",
+ "GPIOX_5", "GPIOX_6", "GPIOX_7", "GPIOX_8", "GPIOX_9",
+ "GPIOX_10", "GPIOX_11", "GPIOX_12", "GPIOX_13", "GPIOX_14",
+ "GPIOX_15", "GPIOX_16", "GPIOX_17", "GPIOX_18", "GPIOX_19",
+};
+
+static const char * const emmc_groups[] = {
+ "emmc_nand_d0", "emmc_nand_d1", "emmc_nand_d2",
+ "emmc_nand_d3", "emmc_nand_d4", "emmc_nand_d5",
+ "emmc_nand_d6", "emmc_nand_d7",
+ "emmc_clk", "emmc_cmd", "emmc_nand_ds",
+};
+
+static const char * const nand_groups[] = {
+ "emmc_nand_d0", "emmc_nand_d1", "emmc_nand_d2",
+ "emmc_nand_d3", "emmc_nand_d4", "emmc_nand_d5",
+ "emmc_nand_d6", "emmc_nand_d7",
+ "nand_ce0", "nand_ale", "nand_cle",
+ "nand_wen_clk", "nand_ren_wr", "nand_rb0",
+ "emmc_nand_ds", "nand_ce1",
+};
+
+static const char * const nor_groups[] = {
+ "nor_d", "nor_q", "nor_c", "nor_cs",
+ "nor_hold", "nor_wp",
+};
+
+static const char * const sdio_groups[] = {
+ "sdio_d0", "sdio_d1", "sdio_d2", "sdio_d3",
+ "sdio_cmd", "sdio_clk", "sdio_dummy",
+};
+
+static const char * const sdcard_groups[] = {
+ "sdcard_d0_c", "sdcard_d1_c", "sdcard_d2_c", "sdcard_d3_c",
+ "sdcard_clk_c", "sdcard_cmd_c",
+ "sdcard_d0_z", "sdcard_d1_z", "sdcard_d2_z", "sdcard_d3_z",
+ "sdcard_clk_z", "sdcard_cmd_z",
+};
+
+static const char * const spi0_groups[] = {
+ "spi0_mosi_c", "spi0_miso_c", "spi0_ss0_c", "spi0_clk_c",
+ "spi0_mosi_x", "spi0_miso_x", "spi0_ss0_x", "spi0_clk_x",
+};
+
+static const char * const spi1_groups[] = {
+ "spi1_mosi", "spi1_miso", "spi1_ss0", "spi1_clk",
+};
+
+static const char * const i2c0_groups[] = {
+ "i2c0_sda_c", "i2c0_sck_c",
+ "i2c0_sda_z0", "i2c0_sck_z1",
+ "i2c0_sda_z7", "i2c0_sck_z8",
+};
+
+static const char * const i2c1_groups[] = {
+ "i2c1_sda_x", "i2c1_sck_x",
+ "i2c1_sda_h2", "i2c1_sck_h3",
+ "i2c1_sda_h6", "i2c1_sck_h7",
+};
+
+static const char * const i2c2_groups[] = {
+ "i2c2_sda_x", "i2c2_sck_x",
+ "i2c2_sda_z", "i2c2_sck_z",
+};
+
+static const char * const i2c3_groups[] = {
+ "i2c3_sda_h", "i2c3_sck_h",
+ "i2c3_sda_a", "i2c3_sck_a",
+};
+
+static const char * const uart_a_groups[] = {
+ "uart_a_tx", "uart_a_rx", "uart_a_cts", "uart_a_rts",
+};
+
+static const char * const uart_b_groups[] = {
+ "uart_b_tx", "uart_b_rx",
+};
+
+static const char * const uart_c_groups[] = {
+ "uart_c_tx", "uart_c_rx", "uart_c_cts", "uart_c_rts",
+};
+
+static const char * const uart_ao_a_c_groups[] = {
+ "uart_ao_a_rx_c", "uart_ao_a_tx_c",
+};
+
+static const char * const iso7816_groups[] = {
+ "iso7816_clk_c", "iso7816_data_c",
+ "iso7816_clk_x", "iso7816_data_x",
+ "iso7816_clk_h", "iso7816_data_h",
+ "iso7816_clk_z", "iso7816_data_z",
+};
+
+static const char * const eth_groups[] = {
+ "eth_rxd2_rgmii", "eth_rxd3_rgmii", "eth_rgmii_tx_clk",
+ "eth_txd2_rgmii", "eth_txd3_rgmii", "eth_rgmii_rx_clk",
+ "eth_txd0", "eth_txd1", "eth_txen", "eth_mdc",
+ "eth_rxd0", "eth_rxd1", "eth_rx_dv", "eth_mdio",
+ "eth_link_led", "eth_act_led",
+};
+
+static const char * const pwm_a_groups[] = {
+ "pwm_a",
+};
+
+static const char * const pwm_b_groups[] = {
+ "pwm_b_x7", "pwm_b_x19",
+};
+
+static const char * const pwm_c_groups[] = {
+ "pwm_c_c", "pwm_c_x5", "pwm_c_x8",
+};
+
+static const char * const pwm_d_groups[] = {
+ "pwm_d_x3", "pwm_d_x6",
+};
+
+static const char * const pwm_e_groups[] = {
+ "pwm_e",
+};
+
+static const char * const pwm_f_groups[] = {
+ "pwm_f_x", "pwm_f_h",
+};
+
+static const char * const cec_ao_a_h_groups[] = {
+ "cec_ao_a_h",
+};
+
+static const char * const cec_ao_b_h_groups[] = {
+ "cec_ao_b_h",
+};
+
+static const char * const jtag_b_groups[] = {
+ "jtag_b_tdi", "jtag_b_tdo", "jtag_b_clk", "jtag_b_tms",
+};
+
+static const char * const bt565_a_groups[] = {
+ "bt565_a_vs", "bt565_a_hs", "bt565_a_clk",
+ "bt565_a_din0", "bt565_a_din1", "bt565_a_din2",
+ "bt565_a_din3", "bt565_a_din4", "bt565_a_din5",
+ "bt565_a_din6", "bt565_a_din7",
+};
+
+static const char * const tsin_a_groups[] = {
+ "tsin_a_valid", "tsin_a_sop", "tsin_a_din0",
+ "tsin_a_clk",
+};
+
+static const char * const tsin_b_groups[] = {
+ "tsin_b_valid_x", "tsin_b_sop_x", "tsin_b_din0_x", "tsin_b_clk_x",
+ "tsin_b_valid_z", "tsin_b_sop_z", "tsin_b_din0_z", "tsin_b_clk_z",
+ "tsin_b_fail", "tsin_b_din1", "tsin_b_din2", "tsin_b_din3",
+ "tsin_b_din4", "tsin_b_din5", "tsin_b_din6", "tsin_b_din7",
+};
+
+static const char * const hdmitx_groups[] = {
+ "hdmitx_sda", "hdmitx_sck", "hdmitx_hpd_in",
+};
+
+static const char * const pdm_groups[] = {
+ "pdm_din0_c", "pdm_din1_c", "pdm_din2_c", "pdm_din3_c",
+ "pdm_dclk_c",
+ "pdm_din0_x", "pdm_din1_x", "pdm_din2_x", "pdm_din3_x",
+ "pdm_dclk_x",
+ "pdm_din0_z", "pdm_din1_z", "pdm_din2_z", "pdm_din3_z",
+ "pdm_dclk_z",
+ "pdm_din0_a", "pdm_din1_a", "pdm_din2_a", "pdm_din3_a",
+ "pdm_dclk_a",
+};
+
+static const char * const spdif_in_groups[] = {
+ "spdif_in_h", "spdif_in_a10", "spdif_in_a12",
+};
+
+static const char * const spdif_out_groups[] = {
+ "spdif_out_h", "spdif_out_a11", "spdif_out_a13",
+};
+
+static const char * const mclk0_groups[] = {
+ "mclk0_a",
+};
+
+static const char * const mclk1_groups[] = {
+ "mclk1_x", "mclk1_z", "mclk1_a",
+};
+
+static const char * const tdm_a_groups[] = {
+ "tdm_a_slv_sclk", "tdm_a_slv_fs", "tdm_a_sclk", "tdm_a_fs",
+ "tdm_a_din0", "tdm_a_din1", "tdm_a_dout0", "tdm_a_dout1",
+};
+
+static const char * const tdm_b_groups[] = {
+ "tdm_b_slv_sclk", "tdm_b_slv_fs", "tdm_b_sclk", "tdm_b_fs",
+ "tdm_b_din0", "tdm_b_din1", "tdm_b_din2",
+ "tdm_b_din3_a", "tdm_b_din3_h",
+ "tdm_b_dout0", "tdm_b_dout1", "tdm_b_dout2",
+ "tdm_b_dout3_a", "tdm_b_dout3_h",
+};
+
+static const char * const tdm_c_groups[] = {
+ "tdm_c_slv_sclk_a", "tdm_c_slv_fs_a",
+ "tdm_c_slv_sclk_z", "tdm_c_slv_fs_z",
+ "tdm_c_sclk_a", "tdm_c_fs_a",
+ "tdm_c_sclk_z", "tdm_c_fs_z",
+ "tdm_c_din0_a", "tdm_c_din1_a",
+ "tdm_c_din2_a", "tdm_c_din3_a",
+ "tdm_c_din0_z", "tdm_c_din1_z",
+ "tdm_c_din2_z", "tdm_c_din3_z",
+ "tdm_c_dout0_a", "tdm_c_dout1_a",
+ "tdm_c_dout2_a", "tdm_c_dout3_a",
+ "tdm_c_dout0_z", "tdm_c_dout1_z",
+ "tdm_c_dout2_z", "tdm_c_dout3_z",
+};
+
+static const char * const gpio_aobus_groups[] = {
+ "GPIOAO_0", "GPIOAO_1", "GPIOAO_2", "GPIOAO_3", "GPIOAO_4",
+ "GPIOAO_5", "GPIOAO_6", "GPIOAO_7", "GPIOAO_8", "GPIOAO_9",
+ "GPIOAO_10", "GPIOAO_11", "GPIOE_0", "GPIOE_1", "GPIOE_2",
+};
+
+static const char * const uart_ao_a_groups[] = {
+ "uart_ao_a_tx", "uart_ao_a_rx",
+ "uart_ao_a_cts", "uart_ao_a_rts",
+};
+
+static const char * const uart_ao_b_groups[] = {
+ "uart_ao_b_tx_2", "uart_ao_b_rx_3",
+ "uart_ao_b_tx_8", "uart_ao_b_rx_9",
+ "uart_ao_b_cts", "uart_ao_b_rts",
+};
+
+static const char * const i2c_ao_groups[] = {
+ "i2c_ao_sck", "i2c_ao_sda",
+ "i2c_ao_sck_e", "i2c_ao_sda_e",
+};
+
+static const char * const i2c_ao_slave_groups[] = {
+ "i2c_ao_slave_sck", "i2c_ao_slave_sda",
+};
+
+static const char * const remote_ao_input_groups[] = {
+ "remote_ao_input",
+};
+
+static const char * const remote_ao_out_groups[] = {
+ "remote_ao_out",
+};
+
+static const char * const pwm_ao_a_groups[] = {
+ "pwm_ao_a", "pwm_ao_a_hiz",
+};
+
+static const char * const pwm_ao_b_groups[] = {
+ "pwm_ao_b",
+};
+
+static const char * const pwm_ao_c_groups[] = {
+ "pwm_ao_c_4", "pwm_ao_c_hiz",
+ "pwm_ao_c_6",
+};
+
+static const char * const pwm_ao_d_groups[] = {
+ "pwm_ao_d_5", "pwm_ao_d_10", "pwm_ao_d_e",
+};
+
+static const char * const jtag_a_groups[] = {
+ "jtag_a_tdi", "jtag_a_tdo", "jtag_a_clk", "jtag_a_tms",
+};
+
+static const char * const cec_ao_a_groups[] = {
+ "cec_ao_a",
+};
+
+static const char * const cec_ao_b_groups[] = {
+ "cec_ao_b",
+};
+
+static const char * const tsin_ao_a_groups[] = {
+ "tsin_ao_asop", "tsin_ao_adin0", "tsin_ao_aclk", "tsin_ao_a_valid",
+};
+
+static const char * const spdif_ao_out_groups[] = {
+ "spdif_ao_out",
+};
+
+static const char * const tdm_ao_b_groups[] = {
+ "tdm_ao_b_dout0", "tdm_ao_b_dout1", "tdm_ao_b_dout2",
+ "tdm_ao_b_fs", "tdm_ao_b_sclk",
+ "tdm_ao_b_din0", "tdm_ao_b_din1", "tdm_ao_b_din2",
+ "tdm_ao_b_slv_fs", "tdm_ao_b_slv_sclk",
+};
+
+static const char * const mclk0_ao_groups[] = {
+ "mclk0_ao",
+};
+
+static struct meson_pmx_func meson_g12a_periphs_functions[] = {
+ FUNCTION(gpio_periphs),
+ FUNCTION(emmc),
+ FUNCTION(nor),
+ FUNCTION(spi0),
+ FUNCTION(spi1),
+ FUNCTION(sdio),
+ FUNCTION(nand),
+ FUNCTION(sdcard),
+ FUNCTION(i2c0),
+ FUNCTION(i2c1),
+ FUNCTION(i2c2),
+ FUNCTION(i2c3),
+ FUNCTION(uart_a),
+ FUNCTION(uart_b),
+ FUNCTION(uart_c),
+ FUNCTION(uart_ao_a_c),
+ FUNCTION(iso7816),
+ FUNCTION(eth),
+ FUNCTION(pwm_a),
+ FUNCTION(pwm_b),
+ FUNCTION(pwm_c),
+ FUNCTION(pwm_d),
+ FUNCTION(pwm_e),
+ FUNCTION(pwm_f),
+ FUNCTION(cec_ao_a_h),
+ FUNCTION(cec_ao_b_h),
+ FUNCTION(jtag_b),
+ FUNCTION(bt565_a),
+ FUNCTION(tsin_a),
+ FUNCTION(tsin_b),
+ FUNCTION(hdmitx),
+ FUNCTION(pdm),
+ FUNCTION(spdif_out),
+ FUNCTION(spdif_in),
+ FUNCTION(mclk0),
+ FUNCTION(mclk1),
+ FUNCTION(tdm_a),
+ FUNCTION(tdm_b),
+ FUNCTION(tdm_c),
+};
+
+static struct meson_pmx_func meson_g12a_aobus_functions[] = {
+ FUNCTION(gpio_aobus),
+ FUNCTION(uart_ao_a),
+ FUNCTION(uart_ao_b),
+ FUNCTION(i2c_ao),
+ FUNCTION(i2c_ao_slave),
+ FUNCTION(remote_ao_input),
+ FUNCTION(remote_ao_out),
+ FUNCTION(pwm_ao_a),
+ FUNCTION(pwm_ao_b),
+ FUNCTION(pwm_ao_c),
+ FUNCTION(pwm_ao_d),
+ FUNCTION(jtag_a),
+ FUNCTION(cec_ao_a),
+ FUNCTION(cec_ao_b),
+ FUNCTION(tsin_ao_a),
+ FUNCTION(spdif_ao_out),
+ FUNCTION(tdm_ao_b),
+ FUNCTION(mclk0_ao),
+};
+
+static struct meson_bank meson_g12a_periphs_banks[] = {
+ /* name first last irq pullen pull dir out in */
+ BANK("Z", GPIOZ_0, GPIOZ_15, 12, 27,
+ 4, 0, 4, 0, 12, 0, 13, 0, 14, 0),
+ BANK("H", GPIOH_0, GPIOH_8, 28, 36,
+ 3, 0, 3, 0, 9, 0, 10, 0, 11, 0),
+ BANK("BOOT", BOOT_0, BOOT_15, 37, 52,
+ 0, 0, 0, 0, 0, 0, 1, 0, 2, 0),
+ BANK("C", GPIOC_0, GPIOC_7, 53, 60,
+ 1, 0, 1, 0, 3, 0, 4, 0, 5, 0),
+ BANK("A", GPIOA_0, GPIOA_15, 61, 76,
+ 5, 0, 5, 0, 16, 0, 17, 0, 18, 0),
+ BANK("X", GPIOX_0, GPIOX_19, 77, 96,
+ 2, 0, 2, 0, 6, 0, 7, 0, 8, 0),
+};
+
+static struct meson_bank meson_g12a_aobus_banks[] = {
+ /* name first last irq pullen pull dir out in */
+ BANK("AO", GPIOAO_0, GPIOAO_11, 0, 11,
+ 3, 0, 2, 0, 0, 0, 4, 0, 1, 0),
+ /* GPIOE actually located in the AO bank */
+ BANK("E", GPIOE_0, GPIOE_2, 97, 99,
+ 3, 16, 2, 16, 0, 16, 4, 16, 1, 16),
+};
+
+static struct meson_pmx_bank meson_g12a_periphs_pmx_banks[] = {
+ /* name first lask reg offset */
+ BANK_PMX("Z", GPIOZ_0, GPIOZ_15, 0x6, 0),
+ BANK_PMX("H", GPIOH_0, GPIOH_8, 0xb, 0),
+ BANK_PMX("BOOT", BOOT_0, BOOT_15, 0x0, 0),
+ BANK_PMX("C", GPIOC_0, GPIOC_7, 0x9, 0),
+ BANK_PMX("A", GPIOA_0, GPIOA_15, 0xd, 0),
+ BANK_PMX("X", GPIOX_0, GPIOX_19, 0x3, 0),
+};
+
+static struct meson_axg_pmx_data meson_g12a_periphs_pmx_banks_data = {
+ .pmx_banks = meson_g12a_periphs_pmx_banks,
+ .num_pmx_banks = ARRAY_SIZE(meson_g12a_periphs_pmx_banks),
+};
+
+static struct meson_pmx_bank meson_g12a_aobus_pmx_banks[] = {
+ BANK_PMX("AO", GPIOAO_0, GPIOAO_11, 0x0, 0),
+ BANK_PMX("E", GPIOE_0, GPIOE_2, 0x1, 16),
+};
+
+static struct meson_axg_pmx_data meson_g12a_aobus_pmx_banks_data = {
+ .pmx_banks = meson_g12a_aobus_pmx_banks,
+ .num_pmx_banks = ARRAY_SIZE(meson_g12a_aobus_pmx_banks),
+};
+
+static struct meson_pinctrl_data meson_g12a_periphs_pinctrl_data = {
+ .name = "periphs-banks",
+ .pins = meson_g12a_periphs_pins,
+ .groups = meson_g12a_periphs_groups,
+ .funcs = meson_g12a_periphs_functions,
+ .banks = meson_g12a_periphs_banks,
+ .num_pins = ARRAY_SIZE(meson_g12a_periphs_pins),
+ .num_groups = ARRAY_SIZE(meson_g12a_periphs_groups),
+ .num_funcs = ARRAY_SIZE(meson_g12a_periphs_functions),
+ .num_banks = ARRAY_SIZE(meson_g12a_periphs_banks),
+ .pmx_ops = &meson_axg_pmx_ops,
+ .pmx_data = &meson_g12a_periphs_pmx_banks_data,
+};
+
+static struct meson_pinctrl_data meson_g12a_aobus_pinctrl_data = {
+ .name = "aobus-banks",
+ .pins = meson_g12a_aobus_pins,
+ .groups = meson_g12a_aobus_groups,
+ .funcs = meson_g12a_aobus_functions,
+ .banks = meson_g12a_aobus_banks,
+ .num_pins = ARRAY_SIZE(meson_g12a_aobus_pins),
+ .num_groups = ARRAY_SIZE(meson_g12a_aobus_groups),
+ .num_funcs = ARRAY_SIZE(meson_g12a_aobus_functions),
+ .num_banks = ARRAY_SIZE(meson_g12a_aobus_banks),
+ .pmx_ops = &meson_axg_pmx_ops,
+ .pmx_data = &meson_g12a_aobus_pmx_banks_data,
+};
+
+static const struct of_device_id meson_g12a_pinctrl_dt_match[] = {
+ {
+ .compatible = "amlogic,meson-g12a-periphs-pinctrl",
+ .data = &meson_g12a_periphs_pinctrl_data,
+ },
+ {
+ .compatible = "amlogic,meson-g12a-aobus-pinctrl",
+ .data = &meson_g12a_aobus_pinctrl_data,
+ },
+ { },
+};
+
+static struct platform_driver meson_g12a_pinctrl_driver = {
+ .probe = meson_pinctrl_probe,
+ .driver = {
+ .name = "meson-g12a-pinctrl",
+ .of_match_table = meson_g12a_pinctrl_dt_match,
+ },
+};
+
+builtin_platform_driver(meson_g12a_pinctrl_driver);
diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
index 4ceb06f8a33c..4edeb4cae72a 100644
--- a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
+++ b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
@@ -830,7 +830,7 @@ static struct meson_bank meson_gxbb_periphs_banks[] = {
static struct meson_bank meson_gxbb_aobus_banks[] = {
/* name first last irq pullen pull dir out in */
- BANK("AO", GPIOAO_0, GPIOAO_13, 0, 13, 0, 0, 0, 16, 0, 0, 0, 16, 1, 0),
+ BANK("AO", GPIOAO_0, GPIOAO_13, 0, 13, 0, 16, 0, 0, 0, 0, 0, 16, 1, 0),
};
static struct meson_pinctrl_data meson_gxbb_periphs_pinctrl_data = {
diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxl.c b/drivers/pinctrl/meson/pinctrl-meson-gxl.c
index 7dae1d7bf6b0..158f618f1695 100644
--- a/drivers/pinctrl/meson/pinctrl-meson-gxl.c
+++ b/drivers/pinctrl/meson/pinctrl-meson-gxl.c
@@ -807,7 +807,7 @@ static struct meson_bank meson_gxl_periphs_banks[] = {
static struct meson_bank meson_gxl_aobus_banks[] = {
/* name first last irq pullen pull dir out in */
- BANK("AO", GPIOAO_0, GPIOAO_9, 0, 9, 0, 0, 0, 16, 0, 0, 0, 16, 1, 0),
+ BANK("AO", GPIOAO_0, GPIOAO_9, 0, 9, 0, 16, 0, 0, 0, 0, 0, 16, 1, 0),
};
static struct meson_pinctrl_data meson_gxl_periphs_pinctrl_data = {
diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c
index 29a458da78db..53d449076dee 100644
--- a/drivers/pinctrl/meson/pinctrl-meson.c
+++ b/drivers/pinctrl/meson/pinctrl-meson.c
@@ -41,7 +41,7 @@
*/
#include <linux/device.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/of.h>
@@ -192,7 +192,7 @@ static int meson_pinconf_set(struct pinctrl_dev *pcdev, unsigned int pin,
dev_dbg(pc->dev, "pin %u: disable bias\n", pin);
meson_calc_reg_and_bit(bank, pin, REG_PULL, &reg, &bit);
- ret = regmap_update_bits(pc->reg_pull, reg,
+ ret = regmap_update_bits(pc->reg_pullen, reg,
BIT(bit), 0);
if (ret)
return ret;
@@ -451,7 +451,7 @@ static struct regmap *meson_map_resource(struct meson_pinctrl *pc,
meson_regmap_config.max_register = resource_size(&res) - 4;
meson_regmap_config.name = devm_kasprintf(pc->dev, GFP_KERNEL,
- "%s-%s", node->name,
+ "%pOFn-%s", node,
name);
if (!meson_regmap_config.name)
return ERR_PTR(-ENOMEM);
diff --git a/drivers/pinctrl/meson/pinctrl-meson.h b/drivers/pinctrl/meson/pinctrl-meson.h
index 12a391109329..eff61ea1c67e 100644
--- a/drivers/pinctrl/meson/pinctrl-meson.h
+++ b/drivers/pinctrl/meson/pinctrl-meson.h
@@ -11,7 +11,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
diff --git a/drivers/pinctrl/meson/pinctrl-meson8.c b/drivers/pinctrl/meson/pinctrl-meson8.c
index c6d79315218f..86466173114d 100644
--- a/drivers/pinctrl/meson/pinctrl-meson8.c
+++ b/drivers/pinctrl/meson/pinctrl-meson8.c
@@ -1053,7 +1053,7 @@ static struct meson_bank meson8_cbus_banks[] = {
static struct meson_bank meson8_aobus_banks[] = {
/* name first last irq pullen pull dir out in */
- BANK("AO", GPIOAO_0, GPIO_TEST_N, 0, 13, 0, 0, 0, 16, 0, 0, 0, 16, 1, 0),
+ BANK("AO", GPIOAO_0, GPIO_TEST_N, 0, 13, 0, 16, 0, 0, 0, 0, 0, 16, 1, 0),
};
static struct meson_pinctrl_data meson8_cbus_pinctrl_data = {
diff --git a/drivers/pinctrl/meson/pinctrl-meson8b.c b/drivers/pinctrl/meson/pinctrl-meson8b.c
index bb2a30964fc6..647ad15d5c3c 100644
--- a/drivers/pinctrl/meson/pinctrl-meson8b.c
+++ b/drivers/pinctrl/meson/pinctrl-meson8b.c
@@ -906,7 +906,7 @@ static struct meson_bank meson8b_cbus_banks[] = {
static struct meson_bank meson8b_aobus_banks[] = {
/* name first lastc irq pullen pull dir out in */
- BANK("AO", GPIOAO_0, GPIO_TEST_N, 0, 13, 0, 0, 0, 16, 0, 0, 0, 16, 1, 0),
+ BANK("AO", GPIOAO_0, GPIO_TEST_N, 0, 13, 0, 16, 0, 0, 0, 0, 0, 16, 1, 0),
};
static struct meson_pinctrl_data meson8b_cbus_pinctrl_data = {
diff --git a/drivers/pinctrl/mvebu/pinctrl-mvebu.c b/drivers/pinctrl/mvebu/pinctrl-mvebu.c
index d7ec7119701b..35ecb92483d5 100644
--- a/drivers/pinctrl/mvebu/pinctrl-mvebu.c
+++ b/drivers/pinctrl/mvebu/pinctrl-mvebu.c
@@ -17,7 +17,7 @@
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/err.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/pinctrl/machine.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinctrl.h>
@@ -413,14 +413,14 @@ static int mvebu_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
ret = of_property_read_string(np, "marvell,function", &function);
if (ret) {
dev_err(pctl->dev,
- "missing marvell,function in node %s\n", np->name);
+ "missing marvell,function in node %pOFn\n", np);
return 0;
}
nmaps = of_property_count_strings(np, "marvell,pins");
if (nmaps < 0) {
dev_err(pctl->dev,
- "missing marvell,pins in node %s\n", np->name);
+ "missing marvell,pins in node %pOFn\n", np);
return 0;
}
diff --git a/drivers/pinctrl/nomadik/pinctrl-ab8500.c b/drivers/pinctrl/nomadik/pinctrl-ab8500.c
index 2ac2d0ad3025..0723627c7bc2 100644
--- a/drivers/pinctrl/nomadik/pinctrl-ab8500.c
+++ b/drivers/pinctrl/nomadik/pinctrl-ab8500.c
@@ -9,7 +9,7 @@
*/
#include <linux/kernel.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/mfd/abx500/ab8500.h>
#include "pinctrl-abx500.h"
diff --git a/drivers/pinctrl/nomadik/pinctrl-ab8505.c b/drivers/pinctrl/nomadik/pinctrl-ab8505.c
index 42c6e1f7886b..2683509c1410 100644
--- a/drivers/pinctrl/nomadik/pinctrl-ab8505.c
+++ b/drivers/pinctrl/nomadik/pinctrl-ab8505.c
@@ -9,7 +9,7 @@
*/
#include <linux/kernel.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/mfd/abx500/ab8500.h>
#include "pinctrl-abx500.h"
diff --git a/drivers/pinctrl/nomadik/pinctrl-abx500.c b/drivers/pinctrl/nomadik/pinctrl-abx500.c
index e3689cc62a41..3d630a0544e1 100644
--- a/drivers/pinctrl/nomadik/pinctrl-abx500.c
+++ b/drivers/pinctrl/nomadik/pinctrl-abx500.c
@@ -18,7 +18,7 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/interrupt.h>
diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.c b/drivers/pinctrl/nomadik/pinctrl-nomadik.c
index f0e7a8c114b2..4cc2c47f8778 100644
--- a/drivers/pinctrl/nomadik/pinctrl-nomadik.c
+++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.c
@@ -17,7 +17,7 @@
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/err.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
@@ -203,7 +203,7 @@ typedef unsigned long pin_cfg_t;
#define GPIO_BLOCK_SHIFT 5
#define NMK_GPIO_PER_CHIP (1 << GPIO_BLOCK_SHIFT)
-#define NMK_MAX_BANKS DIV_ROUND_UP(ARCH_NR_GPIOS, NMK_GPIO_PER_CHIP)
+#define NMK_MAX_BANKS DIV_ROUND_UP(512, NMK_GPIO_PER_CHIP)
/* Register in the logic block */
#define NMK_GPIO_DAT 0x00
@@ -971,7 +971,7 @@ static void nmk_gpio_dbg_show_one(struct seq_file *s,
data_out ? "hi" : "lo",
(mode < 0) ? "unknown" : modes[mode]);
} else {
- int irq = gpio_to_irq(gpio);
+ int irq = chip->to_irq(chip, offset);
struct irq_desc *desc = irq_to_desc(irq);
int pullidx = 0;
int val;
@@ -1051,7 +1051,7 @@ static struct nmk_gpio_chip *nmk_gpio_populate_chip(struct device_node *np,
gpio_pdev = of_find_device_by_node(np);
if (!gpio_pdev) {
- pr_err("populate \"%s\": device not found\n", np->name);
+ pr_err("populate \"%pOFn\": device not found\n", np);
return ERR_PTR(-ENODEV);
}
if (of_property_read_u32(np, "gpio-bank", &id)) {
@@ -1904,8 +1904,8 @@ static int nmk_pinctrl_probe(struct platform_device *pdev)
gpio_np = of_parse_phandle(np, "nomadik-gpio-chips", i);
if (gpio_np) {
dev_info(&pdev->dev,
- "populate NMK GPIO %d \"%s\"\n",
- i, gpio_np->name);
+ "populate NMK GPIO %d \"%pOFn\"\n",
+ i, gpio_np);
nmk_chip = nmk_gpio_populate_chip(gpio_np, pdev);
if (IS_ERR(nmk_chip))
dev_err(&pdev->dev,
diff --git a/drivers/pinctrl/nuvoton/Kconfig b/drivers/pinctrl/nuvoton/Kconfig
new file mode 100644
index 000000000000..6056841a3c32
--- /dev/null
+++ b/drivers/pinctrl/nuvoton/Kconfig
@@ -0,0 +1,12 @@
+config PINCTRL_NPCM7XX
+ bool "Pinctrl and GPIO driver for Nuvoton NPCM7XX"
+ depends on (ARCH_NPCM7XX || COMPILE_TEST) && OF
+ select PINMUX
+ select PINCONF
+ select GENERIC_PINCONF
+ select GPIOLIB
+ select GPIO_GENERIC
+ select GPIOLIB_IRQCHIP
+ help
+ Say Y here to enable pin controller and GPIO support
+ for Nuvoton NPCM750/730/715/705 SoCs.
diff --git a/drivers/pinctrl/nuvoton/Makefile b/drivers/pinctrl/nuvoton/Makefile
new file mode 100644
index 000000000000..886d00784cef
--- /dev/null
+++ b/drivers/pinctrl/nuvoton/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
+# Nuvoton pinctrl support
+
+obj-$(CONFIG_PINCTRL_NPCM7XX) += pinctrl-npcm7xx.o
diff --git a/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c b/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c
new file mode 100644
index 000000000000..7ad50d9268aa
--- /dev/null
+++ b/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c
@@ -0,0 +1,2072 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2016-2018 Nuvoton Technology corporation.
+// Copyright (c) 2016, Dell Inc
+
+#include <linux/device.h>
+#include <linux/gpio/driver.h>
+#include <linux/interrupt.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_irq.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+/* GCR registers */
+#define NPCM7XX_GCR_PDID 0x00
+#define NPCM7XX_GCR_MFSEL1 0x0C
+#define NPCM7XX_GCR_MFSEL2 0x10
+#define NPCM7XX_GCR_MFSEL3 0x64
+#define NPCM7XX_GCR_MFSEL4 0xb0
+#define NPCM7XX_GCR_CPCTL 0xD0
+#define NPCM7XX_GCR_CP2BST 0xD4
+#define NPCM7XX_GCR_B2CPNT 0xD8
+#define NPCM7XX_GCR_I2CSEGSEL 0xE0
+#define NPCM7XX_GCR_I2CSEGCTL 0xE4
+#define NPCM7XX_GCR_SRCNT 0x68
+#define NPCM7XX_GCR_FLOCKR1 0x74
+#define NPCM7XX_GCR_DSCNT 0x78
+
+#define SRCNT_ESPI BIT(3)
+
+/* GPIO registers */
+#define NPCM7XX_GP_N_TLOCK1 0x00
+#define NPCM7XX_GP_N_DIN 0x04 /* Data IN */
+#define NPCM7XX_GP_N_POL 0x08 /* Polarity */
+#define NPCM7XX_GP_N_DOUT 0x0c /* Data OUT */
+#define NPCM7XX_GP_N_OE 0x10 /* Output Enable */
+#define NPCM7XX_GP_N_OTYP 0x14
+#define NPCM7XX_GP_N_MP 0x18
+#define NPCM7XX_GP_N_PU 0x1c /* Pull-up */
+#define NPCM7XX_GP_N_PD 0x20 /* Pull-down */
+#define NPCM7XX_GP_N_DBNC 0x24 /* Debounce */
+#define NPCM7XX_GP_N_EVTYP 0x28 /* Event Type */
+#define NPCM7XX_GP_N_EVBE 0x2c /* Event Both Edge */
+#define NPCM7XX_GP_N_OBL0 0x30
+#define NPCM7XX_GP_N_OBL1 0x34
+#define NPCM7XX_GP_N_OBL2 0x38
+#define NPCM7XX_GP_N_OBL3 0x3c
+#define NPCM7XX_GP_N_EVEN 0x40 /* Event Enable */
+#define NPCM7XX_GP_N_EVENS 0x44 /* Event Set (enable) */
+#define NPCM7XX_GP_N_EVENC 0x48 /* Event Clear (disable) */
+#define NPCM7XX_GP_N_EVST 0x4c /* Event Status */
+#define NPCM7XX_GP_N_SPLCK 0x50
+#define NPCM7XX_GP_N_MPLCK 0x54
+#define NPCM7XX_GP_N_IEM 0x58 /* Input Enable */
+#define NPCM7XX_GP_N_OSRC 0x5c
+#define NPCM7XX_GP_N_ODSC 0x60
+#define NPCM7XX_GP_N_DOS 0x68 /* Data OUT Set */
+#define NPCM7XX_GP_N_DOC 0x6c /* Data OUT Clear */
+#define NPCM7XX_GP_N_OES 0x70 /* Output Enable Set */
+#define NPCM7XX_GP_N_OEC 0x74 /* Output Enable Clear */
+#define NPCM7XX_GP_N_TLOCK2 0x7c
+
+#define NPCM7XX_GPIO_PER_BANK 32
+#define NPCM7XX_GPIO_BANK_NUM 8
+#define NPCM7XX_GCR_NONE 0
+
+/* Structure for register banks */
+struct npcm7xx_gpio {
+ void __iomem *base;
+ struct gpio_chip gc;
+ int irqbase;
+ int irq;
+ void *priv;
+ struct irq_chip irq_chip;
+ u32 pinctrl_id;
+ int (*direction_input)(struct gpio_chip *chip, unsigned offset);
+ int (*direction_output)(struct gpio_chip *chip, unsigned offset,
+ int value);
+ int (*request)(struct gpio_chip *chip, unsigned offset);
+ void (*free)(struct gpio_chip *chip, unsigned offset);
+};
+
+struct npcm7xx_pinctrl {
+ struct pinctrl_dev *pctldev;
+ struct device *dev;
+ struct npcm7xx_gpio gpio_bank[NPCM7XX_GPIO_BANK_NUM];
+ struct irq_domain *domain;
+ struct regmap *gcr_regmap;
+ void __iomem *regs;
+ u32 bank_num;
+};
+
+/* GPIO handling in the pinctrl driver */
+static void npcm_gpio_set(struct gpio_chip *gc, void __iomem *reg,
+ unsigned int pinmask)
+{
+ unsigned long flags;
+ unsigned long val;
+
+ spin_lock_irqsave(&gc->bgpio_lock, flags);
+
+ val = ioread32(reg) | pinmask;
+ iowrite32(val, reg);
+
+ spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+}
+
+static void npcm_gpio_clr(struct gpio_chip *gc, void __iomem *reg,
+ unsigned int pinmask)
+{
+ unsigned long flags;
+ unsigned long val;
+
+ spin_lock_irqsave(&gc->bgpio_lock, flags);
+
+ val = ioread32(reg) & ~pinmask;
+ iowrite32(val, reg);
+
+ spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+}
+
+static void npcmgpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
+{
+ struct npcm7xx_gpio *bank = gpiochip_get_data(chip);
+
+ seq_printf(s, "-- module %d [gpio%d - %d]\n",
+ bank->gc.base / bank->gc.ngpio,
+ bank->gc.base,
+ bank->gc.base + bank->gc.ngpio);
+ seq_printf(s, "DIN :%.8x DOUT:%.8x IE :%.8x OE :%.8x\n",
+ ioread32(bank->base + NPCM7XX_GP_N_DIN),
+ ioread32(bank->base + NPCM7XX_GP_N_DOUT),
+ ioread32(bank->base + NPCM7XX_GP_N_IEM),
+ ioread32(bank->base + NPCM7XX_GP_N_OE));
+ seq_printf(s, "PU :%.8x PD :%.8x DB :%.8x POL :%.8x\n",
+ ioread32(bank->base + NPCM7XX_GP_N_PU),
+ ioread32(bank->base + NPCM7XX_GP_N_PD),
+ ioread32(bank->base + NPCM7XX_GP_N_DBNC),
+ ioread32(bank->base + NPCM7XX_GP_N_POL));
+ seq_printf(s, "ETYP:%.8x EVBE:%.8x EVEN:%.8x EVST:%.8x\n",
+ ioread32(bank->base + NPCM7XX_GP_N_EVTYP),
+ ioread32(bank->base + NPCM7XX_GP_N_EVBE),
+ ioread32(bank->base + NPCM7XX_GP_N_EVEN),
+ ioread32(bank->base + NPCM7XX_GP_N_EVST));
+ seq_printf(s, "OTYP:%.8x OSRC:%.8x ODSC:%.8x\n",
+ ioread32(bank->base + NPCM7XX_GP_N_OTYP),
+ ioread32(bank->base + NPCM7XX_GP_N_OSRC),
+ ioread32(bank->base + NPCM7XX_GP_N_ODSC));
+ seq_printf(s, "OBL0:%.8x OBL1:%.8x OBL2:%.8x OBL3:%.8x\n",
+ ioread32(bank->base + NPCM7XX_GP_N_OBL0),
+ ioread32(bank->base + NPCM7XX_GP_N_OBL1),
+ ioread32(bank->base + NPCM7XX_GP_N_OBL2),
+ ioread32(bank->base + NPCM7XX_GP_N_OBL3));
+ seq_printf(s, "SLCK:%.8x MLCK:%.8x\n",
+ ioread32(bank->base + NPCM7XX_GP_N_SPLCK),
+ ioread32(bank->base + NPCM7XX_GP_N_MPLCK));
+}
+
+static int npcmgpio_direction_input(struct gpio_chip *chip, unsigned int offset)
+{
+ struct npcm7xx_gpio *bank = gpiochip_get_data(chip);
+ int ret;
+
+ ret = pinctrl_gpio_direction_input(offset + chip->base);
+ if (ret)
+ return ret;
+
+ return bank->direction_input(chip, offset);
+}
+
+/* Set GPIO to Output with initial value */
+static int npcmgpio_direction_output(struct gpio_chip *chip,
+ unsigned int offset, int value)
+{
+ struct npcm7xx_gpio *bank = gpiochip_get_data(chip);
+ int ret;
+
+ dev_dbg(chip->parent, "gpio_direction_output: offset%d = %x\n", offset,
+ value);
+
+ ret = pinctrl_gpio_direction_output(offset + chip->base);
+ if (ret)
+ return ret;
+
+ return bank->direction_output(chip, offset, value);
+}
+
+static int npcmgpio_gpio_request(struct gpio_chip *chip, unsigned int offset)
+{
+ struct npcm7xx_gpio *bank = gpiochip_get_data(chip);
+ int ret;
+
+ dev_dbg(chip->parent, "gpio_request: offset%d\n", offset);
+ ret = pinctrl_gpio_request(offset + chip->base);
+ if (ret)
+ return ret;
+
+ return bank->request(chip, offset);
+}
+
+static void npcmgpio_gpio_free(struct gpio_chip *chip, unsigned int offset)
+{
+ dev_dbg(chip->parent, "gpio_free: offset%d\n", offset);
+ pinctrl_gpio_free(offset + chip->base);
+}
+
+static void npcmgpio_irq_handler(struct irq_desc *desc)
+{
+ struct gpio_chip *gc;
+ struct irq_chip *chip;
+ struct npcm7xx_gpio *bank;
+ u32 sts, en, bit;
+
+ gc = irq_desc_get_handler_data(desc);
+ bank = gpiochip_get_data(gc);
+ chip = irq_desc_get_chip(desc);
+
+ chained_irq_enter(chip, desc);
+ sts = ioread32(bank->base + NPCM7XX_GP_N_EVST);
+ en = ioread32(bank->base + NPCM7XX_GP_N_EVEN);
+ dev_dbg(chip->parent_device, "==> got irq sts %.8x %.8x\n", sts,
+ en);
+
+ sts &= en;
+ for_each_set_bit(bit, (const void *)&sts, NPCM7XX_GPIO_PER_BANK)
+ generic_handle_irq(irq_linear_revmap(gc->irq.domain, bit));
+ chained_irq_exit(chip, desc);
+}
+
+static int npcmgpio_set_irq_type(struct irq_data *d, unsigned int type)
+{
+ struct npcm7xx_gpio *bank =
+ gpiochip_get_data(irq_data_get_irq_chip_data(d));
+ unsigned int gpio = BIT(d->hwirq);
+
+ dev_dbg(d->chip->parent_device, "setirqtype: %u.%u = %u\n", gpio,
+ d->irq, type);
+ switch (type) {
+ case IRQ_TYPE_EDGE_RISING:
+ dev_dbg(d->chip->parent_device, "edge.rising\n");
+ npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_EVBE, gpio);
+ npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_POL, gpio);
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ dev_dbg(d->chip->parent_device, "edge.falling\n");
+ npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_EVBE, gpio);
+ npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_POL, gpio);
+ break;
+ case IRQ_TYPE_EDGE_BOTH:
+ dev_dbg(d->chip->parent_device, "edge.both\n");
+ npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_EVBE, gpio);
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ dev_dbg(d->chip->parent_device, "level.low\n");
+ npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_POL, gpio);
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ dev_dbg(d->chip->parent_device, "level.high\n");
+ npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_POL, gpio);
+ break;
+ default:
+ dev_dbg(d->chip->parent_device, "invalid irq type\n");
+ return -EINVAL;
+ }
+
+ if (type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
+ npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_EVTYP, gpio);
+ irq_set_handler_locked(d, handle_level_irq);
+ } else if (type & (IRQ_TYPE_EDGE_BOTH | IRQ_TYPE_EDGE_RISING
+ | IRQ_TYPE_EDGE_FALLING)) {
+ npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_EVTYP, gpio);
+ irq_set_handler_locked(d, handle_edge_irq);
+ }
+
+ return 0;
+}
+
+static void npcmgpio_irq_ack(struct irq_data *d)
+{
+ struct npcm7xx_gpio *bank =
+ gpiochip_get_data(irq_data_get_irq_chip_data(d));
+ unsigned int gpio = d->hwirq;
+
+ dev_dbg(d->chip->parent_device, "irq_ack: %u.%u\n", gpio, d->irq);
+ iowrite32(BIT(gpio), bank->base + NPCM7XX_GP_N_EVST);
+}
+
+/* Disable GPIO interrupt */
+static void npcmgpio_irq_mask(struct irq_data *d)
+{
+ struct npcm7xx_gpio *bank =
+ gpiochip_get_data(irq_data_get_irq_chip_data(d));
+ unsigned int gpio = d->hwirq;
+
+ /* Clear events */
+ dev_dbg(d->chip->parent_device, "irq_mask: %u.%u\n", gpio, d->irq);
+ iowrite32(BIT(gpio), bank->base + NPCM7XX_GP_N_EVENC);
+}
+
+/* Enable GPIO interrupt */
+static void npcmgpio_irq_unmask(struct irq_data *d)
+{
+ struct npcm7xx_gpio *bank =
+ gpiochip_get_data(irq_data_get_irq_chip_data(d));
+ unsigned int gpio = d->hwirq;
+
+ /* Enable events */
+ dev_dbg(d->chip->parent_device, "irq_unmask: %u.%u\n", gpio, d->irq);
+ iowrite32(BIT(gpio), bank->base + NPCM7XX_GP_N_EVENS);
+}
+
+static unsigned int npcmgpio_irq_startup(struct irq_data *d)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ unsigned int gpio = d->hwirq;
+
+ /* active-high, input, clear interrupt, enable interrupt */
+ dev_dbg(d->chip->parent_device, "startup: %u.%u\n", gpio, d->irq);
+ npcmgpio_direction_input(gc, gpio);
+ npcmgpio_irq_ack(d);
+ npcmgpio_irq_unmask(d);
+
+ return 0;
+}
+
+static struct irq_chip npcmgpio_irqchip = {
+ .name = "NPCM7XX-GPIO-IRQ",
+ .irq_ack = npcmgpio_irq_ack,
+ .irq_unmask = npcmgpio_irq_unmask,
+ .irq_mask = npcmgpio_irq_mask,
+ .irq_set_type = npcmgpio_set_irq_type,
+ .irq_startup = npcmgpio_irq_startup,
+};
+
+/* pinmux handing in the pinctrl driver*/
+static const int smb0_pins[] = { 115, 114 };
+static const int smb0b_pins[] = { 195, 194 };
+static const int smb0c_pins[] = { 202, 196 };
+static const int smb0d_pins[] = { 198, 199 };
+static const int smb0den_pins[] = { 197 };
+
+static const int smb1_pins[] = { 117, 116 };
+static const int smb1b_pins[] = { 126, 127 };
+static const int smb1c_pins[] = { 124, 125 };
+static const int smb1d_pins[] = { 4, 5 };
+
+static const int smb2_pins[] = { 119, 118 };
+static const int smb2b_pins[] = { 122, 123 };
+static const int smb2c_pins[] = { 120, 121 };
+static const int smb2d_pins[] = { 6, 7 };
+
+static const int smb3_pins[] = { 30, 31 };
+static const int smb3b_pins[] = { 39, 40 };
+static const int smb3c_pins[] = { 37, 38 };
+static const int smb3d_pins[] = { 59, 60 };
+
+static const int smb4_pins[] = { 28, 29 };
+static const int smb4b_pins[] = { 18, 19 };
+static const int smb4c_pins[] = { 20, 21 };
+static const int smb4d_pins[] = { 22, 23 };
+static const int smb4den_pins[] = { 17 };
+
+static const int smb5_pins[] = { 26, 27 };
+static const int smb5b_pins[] = { 13, 12 };
+static const int smb5c_pins[] = { 15, 14 };
+static const int smb5d_pins[] = { 94, 93 };
+static const int ga20kbc_pins[] = { 94, 93 };
+
+static const int smb6_pins[] = { 172, 171 };
+static const int smb7_pins[] = { 174, 173 };
+static const int smb8_pins[] = { 129, 128 };
+static const int smb9_pins[] = { 131, 130 };
+static const int smb10_pins[] = { 133, 132 };
+static const int smb11_pins[] = { 135, 134 };
+static const int smb12_pins[] = { 221, 220 };
+static const int smb13_pins[] = { 223, 222 };
+static const int smb14_pins[] = { 22, 23 };
+static const int smb15_pins[] = { 20, 21 };
+
+static const int fanin0_pins[] = { 64 };
+static const int fanin1_pins[] = { 65 };
+static const int fanin2_pins[] = { 66 };
+static const int fanin3_pins[] = { 67 };
+static const int fanin4_pins[] = { 68 };
+static const int fanin5_pins[] = { 69 };
+static const int fanin6_pins[] = { 70 };
+static const int fanin7_pins[] = { 71 };
+static const int fanin8_pins[] = { 72 };
+static const int fanin9_pins[] = { 73 };
+static const int fanin10_pins[] = { 74 };
+static const int fanin11_pins[] = { 75 };
+static const int fanin12_pins[] = { 76 };
+static const int fanin13_pins[] = { 77 };
+static const int fanin14_pins[] = { 78 };
+static const int fanin15_pins[] = { 79 };
+static const int faninx_pins[] = { 175, 176, 177, 203 };
+
+static const int pwm0_pins[] = { 80 };
+static const int pwm1_pins[] = { 81 };
+static const int pwm2_pins[] = { 82 };
+static const int pwm3_pins[] = { 83 };
+static const int pwm4_pins[] = { 144 };
+static const int pwm5_pins[] = { 145 };
+static const int pwm6_pins[] = { 146 };
+static const int pwm7_pins[] = { 147 };
+
+static const int uart1_pins[] = { 43, 44, 45, 46, 47, 61, 62, 63 };
+static const int uart2_pins[] = { 48, 49, 50, 51, 52, 53, 54, 55 };
+
+/* RGMII 1 pin group */
+static const int rg1_pins[] = { 96, 97, 98, 99, 100, 101, 102, 103, 104, 105,
+ 106, 107 };
+/* RGMII 1 MD interface pin group */
+static const int rg1mdio_pins[] = { 108, 109 };
+
+/* RGMII 2 pin group */
+static const int rg2_pins[] = { 110, 111, 112, 113, 208, 209, 210, 211, 212,
+ 213, 214, 215 };
+/* RGMII 2 MD interface pin group */
+static const int rg2mdio_pins[] = { 216, 217 };
+
+static const int ddr_pins[] = { 110, 111, 112, 113, 208, 209, 210, 211, 212,
+ 213, 214, 215, 216, 217 };
+/* Serial I/O Expander 1 */
+static const int iox1_pins[] = { 0, 1, 2, 3 };
+/* Serial I/O Expander 2 */
+static const int iox2_pins[] = { 4, 5, 6, 7 };
+/* Host Serial I/O Expander 2 */
+static const int ioxh_pins[] = { 10, 11, 24, 25 };
+
+static const int mmc_pins[] = { 152, 154, 156, 157, 158, 159 };
+static const int mmcwp_pins[] = { 153 };
+static const int mmccd_pins[] = { 155 };
+static const int mmcrst_pins[] = { 155 };
+static const int mmc8_pins[] = { 148, 149, 150, 151 };
+
+/* RMII 1 pin groups */
+static const int r1_pins[] = { 178, 179, 180, 181, 182, 193, 201 };
+static const int r1err_pins[] = { 56 };
+static const int r1md_pins[] = { 57, 58 };
+
+/* RMII 2 pin groups */
+static const int r2_pins[] = { 84, 85, 86, 87, 88, 89, 200 };
+static const int r2err_pins[] = { 90 };
+static const int r2md_pins[] = { 91, 92 };
+
+static const int sd1_pins[] = { 136, 137, 138, 139, 140, 141, 142, 143 };
+static const int sd1pwr_pins[] = { 143 };
+
+static const int wdog1_pins[] = { 218 };
+static const int wdog2_pins[] = { 219 };
+
+/* BMC serial port 0 */
+static const int bmcuart0a_pins[] = { 41, 42 };
+static const int bmcuart0b_pins[] = { 48, 49 };
+
+static const int bmcuart1_pins[] = { 43, 44, 62, 63 };
+
+/* System Control Interrupt and Power Management Event pin group */
+static const int scipme_pins[] = { 169 };
+/* System Management Interrupt pin group */
+static const int sci_pins[] = { 170 };
+/* Serial Interrupt Line pin group */
+static const int serirq_pins[] = { 162 };
+
+static const int clkout_pins[] = { 160 };
+static const int clkreq_pins[] = { 231 };
+
+static const int jtag2_pins[] = { 43, 44, 45, 46, 47 };
+/* Graphics SPI Clock pin group */
+static const int gspi_pins[] = { 12, 13, 14, 15 };
+
+static const int spix_pins[] = { 224, 225, 226, 227, 229, 230 };
+static const int spixcs1_pins[] = { 228 };
+
+static const int pspi1_pins[] = { 175, 176, 177 };
+static const int pspi2_pins[] = { 17, 18, 19 };
+
+static const int spi0cs1_pins[] = { 32 };
+
+static const int spi3_pins[] = { 183, 184, 185, 186 };
+static const int spi3cs1_pins[] = { 187 };
+static const int spi3quad_pins[] = { 188, 189 };
+static const int spi3cs2_pins[] = { 188 };
+static const int spi3cs3_pins[] = { 189 };
+
+static const int ddc_pins[] = { 204, 205, 206, 207 };
+
+static const int lpc_pins[] = { 95, 161, 163, 164, 165, 166, 167 };
+static const int lpcclk_pins[] = { 168 };
+static const int espi_pins[] = { 95, 161, 163, 164, 165, 166, 167, 168 };
+
+static const int lkgpo0_pins[] = { 16 };
+static const int lkgpo1_pins[] = { 8 };
+static const int lkgpo2_pins[] = { 9 };
+
+static const int nprd_smi_pins[] = { 190 };
+
+/*
+ * pin: name, number
+ * group: name, npins, pins
+ * function: name, ngroups, groups
+ */
+struct npcm7xx_group {
+ const char *name;
+ const unsigned int *pins;
+ int npins;
+};
+
+#define NPCM7XX_GRPS \
+ NPCM7XX_GRP(smb0), \
+ NPCM7XX_GRP(smb0b), \
+ NPCM7XX_GRP(smb0c), \
+ NPCM7XX_GRP(smb0d), \
+ NPCM7XX_GRP(smb0den), \
+ NPCM7XX_GRP(smb1), \
+ NPCM7XX_GRP(smb1b), \
+ NPCM7XX_GRP(smb1c), \
+ NPCM7XX_GRP(smb1d), \
+ NPCM7XX_GRP(smb2), \
+ NPCM7XX_GRP(smb2b), \
+ NPCM7XX_GRP(smb2c), \
+ NPCM7XX_GRP(smb2d), \
+ NPCM7XX_GRP(smb3), \
+ NPCM7XX_GRP(smb3b), \
+ NPCM7XX_GRP(smb3c), \
+ NPCM7XX_GRP(smb3d), \
+ NPCM7XX_GRP(smb4), \
+ NPCM7XX_GRP(smb4b), \
+ NPCM7XX_GRP(smb4c), \
+ NPCM7XX_GRP(smb4d), \
+ NPCM7XX_GRP(smb4den), \
+ NPCM7XX_GRP(smb5), \
+ NPCM7XX_GRP(smb5b), \
+ NPCM7XX_GRP(smb5c), \
+ NPCM7XX_GRP(smb5d), \
+ NPCM7XX_GRP(ga20kbc), \
+ NPCM7XX_GRP(smb6), \
+ NPCM7XX_GRP(smb7), \
+ NPCM7XX_GRP(smb8), \
+ NPCM7XX_GRP(smb9), \
+ NPCM7XX_GRP(smb10), \
+ NPCM7XX_GRP(smb11), \
+ NPCM7XX_GRP(smb12), \
+ NPCM7XX_GRP(smb13), \
+ NPCM7XX_GRP(smb14), \
+ NPCM7XX_GRP(smb15), \
+ NPCM7XX_GRP(fanin0), \
+ NPCM7XX_GRP(fanin1), \
+ NPCM7XX_GRP(fanin2), \
+ NPCM7XX_GRP(fanin3), \
+ NPCM7XX_GRP(fanin4), \
+ NPCM7XX_GRP(fanin5), \
+ NPCM7XX_GRP(fanin6), \
+ NPCM7XX_GRP(fanin7), \
+ NPCM7XX_GRP(fanin8), \
+ NPCM7XX_GRP(fanin9), \
+ NPCM7XX_GRP(fanin10), \
+ NPCM7XX_GRP(fanin11), \
+ NPCM7XX_GRP(fanin12), \
+ NPCM7XX_GRP(fanin13), \
+ NPCM7XX_GRP(fanin14), \
+ NPCM7XX_GRP(fanin15), \
+ NPCM7XX_GRP(faninx), \
+ NPCM7XX_GRP(pwm0), \
+ NPCM7XX_GRP(pwm1), \
+ NPCM7XX_GRP(pwm2), \
+ NPCM7XX_GRP(pwm3), \
+ NPCM7XX_GRP(pwm4), \
+ NPCM7XX_GRP(pwm5), \
+ NPCM7XX_GRP(pwm6), \
+ NPCM7XX_GRP(pwm7), \
+ NPCM7XX_GRP(rg1), \
+ NPCM7XX_GRP(rg1mdio), \
+ NPCM7XX_GRP(rg2), \
+ NPCM7XX_GRP(rg2mdio), \
+ NPCM7XX_GRP(ddr), \
+ NPCM7XX_GRP(uart1), \
+ NPCM7XX_GRP(uart2), \
+ NPCM7XX_GRP(bmcuart0a), \
+ NPCM7XX_GRP(bmcuart0b), \
+ NPCM7XX_GRP(bmcuart1), \
+ NPCM7XX_GRP(iox1), \
+ NPCM7XX_GRP(iox2), \
+ NPCM7XX_GRP(ioxh), \
+ NPCM7XX_GRP(gspi), \
+ NPCM7XX_GRP(mmc), \
+ NPCM7XX_GRP(mmcwp), \
+ NPCM7XX_GRP(mmccd), \
+ NPCM7XX_GRP(mmcrst), \
+ NPCM7XX_GRP(mmc8), \
+ NPCM7XX_GRP(r1), \
+ NPCM7XX_GRP(r1err), \
+ NPCM7XX_GRP(r1md), \
+ NPCM7XX_GRP(r2), \
+ NPCM7XX_GRP(r2err), \
+ NPCM7XX_GRP(r2md), \
+ NPCM7XX_GRP(sd1), \
+ NPCM7XX_GRP(sd1pwr), \
+ NPCM7XX_GRP(wdog1), \
+ NPCM7XX_GRP(wdog2), \
+ NPCM7XX_GRP(scipme), \
+ NPCM7XX_GRP(sci), \
+ NPCM7XX_GRP(serirq), \
+ NPCM7XX_GRP(jtag2), \
+ NPCM7XX_GRP(spix), \
+ NPCM7XX_GRP(spixcs1), \
+ NPCM7XX_GRP(pspi1), \
+ NPCM7XX_GRP(pspi2), \
+ NPCM7XX_GRP(ddc), \
+ NPCM7XX_GRP(clkreq), \
+ NPCM7XX_GRP(clkout), \
+ NPCM7XX_GRP(spi3), \
+ NPCM7XX_GRP(spi3cs1), \
+ NPCM7XX_GRP(spi3quad), \
+ NPCM7XX_GRP(spi3cs2), \
+ NPCM7XX_GRP(spi3cs3), \
+ NPCM7XX_GRP(spi0cs1), \
+ NPCM7XX_GRP(lpc), \
+ NPCM7XX_GRP(lpcclk), \
+ NPCM7XX_GRP(espi), \
+ NPCM7XX_GRP(lkgpo0), \
+ NPCM7XX_GRP(lkgpo1), \
+ NPCM7XX_GRP(lkgpo2), \
+ NPCM7XX_GRP(nprd_smi), \
+ \
+
+enum {
+#define NPCM7XX_GRP(x) fn_ ## x
+ NPCM7XX_GRPS
+ /* add placeholder for none/gpio */
+ NPCM7XX_GRP(none),
+ NPCM7XX_GRP(gpio),
+#undef NPCM7XX_GRP
+};
+
+static struct npcm7xx_group npcm7xx_groups[] = {
+#define NPCM7XX_GRP(x) { .name = #x, .pins = x ## _pins, \
+ .npins = ARRAY_SIZE(x ## _pins) }
+ NPCM7XX_GRPS
+#undef NPCM7XX_GRP
+};
+
+#define NPCM7XX_SFUNC(a) NPCM7XX_FUNC(a, #a)
+#define NPCM7XX_FUNC(a, b...) static const char *a ## _grp[] = { b }
+#define NPCM7XX_MKFUNC(nm) { .name = #nm, .ngroups = ARRAY_SIZE(nm ## _grp), \
+ .groups = nm ## _grp }
+struct npcm7xx_func {
+ const char *name;
+ const unsigned int ngroups;
+ const char *const *groups;
+};
+
+NPCM7XX_SFUNC(smb0);
+NPCM7XX_SFUNC(smb0b);
+NPCM7XX_SFUNC(smb0c);
+NPCM7XX_SFUNC(smb0d);
+NPCM7XX_SFUNC(smb0den);
+NPCM7XX_SFUNC(smb1);
+NPCM7XX_SFUNC(smb1b);
+NPCM7XX_SFUNC(smb1c);
+NPCM7XX_SFUNC(smb1d);
+NPCM7XX_SFUNC(smb2);
+NPCM7XX_SFUNC(smb2b);
+NPCM7XX_SFUNC(smb2c);
+NPCM7XX_SFUNC(smb2d);
+NPCM7XX_SFUNC(smb3);
+NPCM7XX_SFUNC(smb3b);
+NPCM7XX_SFUNC(smb3c);
+NPCM7XX_SFUNC(smb3d);
+NPCM7XX_SFUNC(smb4);
+NPCM7XX_SFUNC(smb4b);
+NPCM7XX_SFUNC(smb4c);
+NPCM7XX_SFUNC(smb4d);
+NPCM7XX_SFUNC(smb4den);
+NPCM7XX_SFUNC(smb5);
+NPCM7XX_SFUNC(smb5b);
+NPCM7XX_SFUNC(smb5c);
+NPCM7XX_SFUNC(smb5d);
+NPCM7XX_SFUNC(ga20kbc);
+NPCM7XX_SFUNC(smb6);
+NPCM7XX_SFUNC(smb7);
+NPCM7XX_SFUNC(smb8);
+NPCM7XX_SFUNC(smb9);
+NPCM7XX_SFUNC(smb10);
+NPCM7XX_SFUNC(smb11);
+NPCM7XX_SFUNC(smb12);
+NPCM7XX_SFUNC(smb13);
+NPCM7XX_SFUNC(smb14);
+NPCM7XX_SFUNC(smb15);
+NPCM7XX_SFUNC(fanin0);
+NPCM7XX_SFUNC(fanin1);
+NPCM7XX_SFUNC(fanin2);
+NPCM7XX_SFUNC(fanin3);
+NPCM7XX_SFUNC(fanin4);
+NPCM7XX_SFUNC(fanin5);
+NPCM7XX_SFUNC(fanin6);
+NPCM7XX_SFUNC(fanin7);
+NPCM7XX_SFUNC(fanin8);
+NPCM7XX_SFUNC(fanin9);
+NPCM7XX_SFUNC(fanin10);
+NPCM7XX_SFUNC(fanin11);
+NPCM7XX_SFUNC(fanin12);
+NPCM7XX_SFUNC(fanin13);
+NPCM7XX_SFUNC(fanin14);
+NPCM7XX_SFUNC(fanin15);
+NPCM7XX_SFUNC(faninx);
+NPCM7XX_SFUNC(pwm0);
+NPCM7XX_SFUNC(pwm1);
+NPCM7XX_SFUNC(pwm2);
+NPCM7XX_SFUNC(pwm3);
+NPCM7XX_SFUNC(pwm4);
+NPCM7XX_SFUNC(pwm5);
+NPCM7XX_SFUNC(pwm6);
+NPCM7XX_SFUNC(pwm7);
+NPCM7XX_SFUNC(rg1);
+NPCM7XX_SFUNC(rg1mdio);
+NPCM7XX_SFUNC(rg2);
+NPCM7XX_SFUNC(rg2mdio);
+NPCM7XX_SFUNC(ddr);
+NPCM7XX_SFUNC(uart1);
+NPCM7XX_SFUNC(uart2);
+NPCM7XX_SFUNC(bmcuart0a);
+NPCM7XX_SFUNC(bmcuart0b);
+NPCM7XX_SFUNC(bmcuart1);
+NPCM7XX_SFUNC(iox1);
+NPCM7XX_SFUNC(iox2);
+NPCM7XX_SFUNC(ioxh);
+NPCM7XX_SFUNC(gspi);
+NPCM7XX_SFUNC(mmc);
+NPCM7XX_SFUNC(mmcwp);
+NPCM7XX_SFUNC(mmccd);
+NPCM7XX_SFUNC(mmcrst);
+NPCM7XX_SFUNC(mmc8);
+NPCM7XX_SFUNC(r1);
+NPCM7XX_SFUNC(r1err);
+NPCM7XX_SFUNC(r1md);
+NPCM7XX_SFUNC(r2);
+NPCM7XX_SFUNC(r2err);
+NPCM7XX_SFUNC(r2md);
+NPCM7XX_SFUNC(sd1);
+NPCM7XX_SFUNC(sd1pwr);
+NPCM7XX_SFUNC(wdog1);
+NPCM7XX_SFUNC(wdog2);
+NPCM7XX_SFUNC(scipme);
+NPCM7XX_SFUNC(sci);
+NPCM7XX_SFUNC(serirq);
+NPCM7XX_SFUNC(jtag2);
+NPCM7XX_SFUNC(spix);
+NPCM7XX_SFUNC(spixcs1);
+NPCM7XX_SFUNC(pspi1);
+NPCM7XX_SFUNC(pspi2);
+NPCM7XX_SFUNC(ddc);
+NPCM7XX_SFUNC(clkreq);
+NPCM7XX_SFUNC(clkout);
+NPCM7XX_SFUNC(spi3);
+NPCM7XX_SFUNC(spi3cs1);
+NPCM7XX_SFUNC(spi3quad);
+NPCM7XX_SFUNC(spi3cs2);
+NPCM7XX_SFUNC(spi3cs3);
+NPCM7XX_SFUNC(spi0cs1);
+NPCM7XX_SFUNC(lpc);
+NPCM7XX_SFUNC(lpcclk);
+NPCM7XX_SFUNC(espi);
+NPCM7XX_SFUNC(lkgpo0);
+NPCM7XX_SFUNC(lkgpo1);
+NPCM7XX_SFUNC(lkgpo2);
+NPCM7XX_SFUNC(nprd_smi);
+
+/* Function names */
+static struct npcm7xx_func npcm7xx_funcs[] = {
+ NPCM7XX_MKFUNC(smb0),
+ NPCM7XX_MKFUNC(smb0b),
+ NPCM7XX_MKFUNC(smb0c),
+ NPCM7XX_MKFUNC(smb0d),
+ NPCM7XX_MKFUNC(smb0den),
+ NPCM7XX_MKFUNC(smb1),
+ NPCM7XX_MKFUNC(smb1b),
+ NPCM7XX_MKFUNC(smb1c),
+ NPCM7XX_MKFUNC(smb1d),
+ NPCM7XX_MKFUNC(smb2),
+ NPCM7XX_MKFUNC(smb2b),
+ NPCM7XX_MKFUNC(smb2c),
+ NPCM7XX_MKFUNC(smb2d),
+ NPCM7XX_MKFUNC(smb3),
+ NPCM7XX_MKFUNC(smb3b),
+ NPCM7XX_MKFUNC(smb3c),
+ NPCM7XX_MKFUNC(smb3d),
+ NPCM7XX_MKFUNC(smb4),
+ NPCM7XX_MKFUNC(smb4b),
+ NPCM7XX_MKFUNC(smb4c),
+ NPCM7XX_MKFUNC(smb4d),
+ NPCM7XX_MKFUNC(smb4den),
+ NPCM7XX_MKFUNC(smb5),
+ NPCM7XX_MKFUNC(smb5b),
+ NPCM7XX_MKFUNC(smb5c),
+ NPCM7XX_MKFUNC(smb5d),
+ NPCM7XX_MKFUNC(ga20kbc),
+ NPCM7XX_MKFUNC(smb6),
+ NPCM7XX_MKFUNC(smb7),
+ NPCM7XX_MKFUNC(smb8),
+ NPCM7XX_MKFUNC(smb9),
+ NPCM7XX_MKFUNC(smb10),
+ NPCM7XX_MKFUNC(smb11),
+ NPCM7XX_MKFUNC(smb12),
+ NPCM7XX_MKFUNC(smb13),
+ NPCM7XX_MKFUNC(smb14),
+ NPCM7XX_MKFUNC(smb15),
+ NPCM7XX_MKFUNC(fanin0),
+ NPCM7XX_MKFUNC(fanin1),
+ NPCM7XX_MKFUNC(fanin2),
+ NPCM7XX_MKFUNC(fanin3),
+ NPCM7XX_MKFUNC(fanin4),
+ NPCM7XX_MKFUNC(fanin5),
+ NPCM7XX_MKFUNC(fanin6),
+ NPCM7XX_MKFUNC(fanin7),
+ NPCM7XX_MKFUNC(fanin8),
+ NPCM7XX_MKFUNC(fanin9),
+ NPCM7XX_MKFUNC(fanin10),
+ NPCM7XX_MKFUNC(fanin11),
+ NPCM7XX_MKFUNC(fanin12),
+ NPCM7XX_MKFUNC(fanin13),
+ NPCM7XX_MKFUNC(fanin14),
+ NPCM7XX_MKFUNC(fanin15),
+ NPCM7XX_MKFUNC(faninx),
+ NPCM7XX_MKFUNC(pwm0),
+ NPCM7XX_MKFUNC(pwm1),
+ NPCM7XX_MKFUNC(pwm2),
+ NPCM7XX_MKFUNC(pwm3),
+ NPCM7XX_MKFUNC(pwm4),
+ NPCM7XX_MKFUNC(pwm5),
+ NPCM7XX_MKFUNC(pwm6),
+ NPCM7XX_MKFUNC(pwm7),
+ NPCM7XX_MKFUNC(rg1),
+ NPCM7XX_MKFUNC(rg1mdio),
+ NPCM7XX_MKFUNC(rg2),
+ NPCM7XX_MKFUNC(rg2mdio),
+ NPCM7XX_MKFUNC(ddr),
+ NPCM7XX_MKFUNC(uart1),
+ NPCM7XX_MKFUNC(uart2),
+ NPCM7XX_MKFUNC(bmcuart0a),
+ NPCM7XX_MKFUNC(bmcuart0b),
+ NPCM7XX_MKFUNC(bmcuart1),
+ NPCM7XX_MKFUNC(iox1),
+ NPCM7XX_MKFUNC(iox2),
+ NPCM7XX_MKFUNC(ioxh),
+ NPCM7XX_MKFUNC(gspi),
+ NPCM7XX_MKFUNC(mmc),
+ NPCM7XX_MKFUNC(mmcwp),
+ NPCM7XX_MKFUNC(mmccd),
+ NPCM7XX_MKFUNC(mmcrst),
+ NPCM7XX_MKFUNC(mmc8),
+ NPCM7XX_MKFUNC(r1),
+ NPCM7XX_MKFUNC(r1err),
+ NPCM7XX_MKFUNC(r1md),
+ NPCM7XX_MKFUNC(r2),
+ NPCM7XX_MKFUNC(r2err),
+ NPCM7XX_MKFUNC(r2md),
+ NPCM7XX_MKFUNC(sd1),
+ NPCM7XX_MKFUNC(sd1pwr),
+ NPCM7XX_MKFUNC(wdog1),
+ NPCM7XX_MKFUNC(wdog2),
+ NPCM7XX_MKFUNC(scipme),
+ NPCM7XX_MKFUNC(sci),
+ NPCM7XX_MKFUNC(serirq),
+ NPCM7XX_MKFUNC(jtag2),
+ NPCM7XX_MKFUNC(spix),
+ NPCM7XX_MKFUNC(spixcs1),
+ NPCM7XX_MKFUNC(pspi1),
+ NPCM7XX_MKFUNC(pspi2),
+ NPCM7XX_MKFUNC(ddc),
+ NPCM7XX_MKFUNC(clkreq),
+ NPCM7XX_MKFUNC(clkout),
+ NPCM7XX_MKFUNC(spi3),
+ NPCM7XX_MKFUNC(spi3cs1),
+ NPCM7XX_MKFUNC(spi3quad),
+ NPCM7XX_MKFUNC(spi3cs2),
+ NPCM7XX_MKFUNC(spi3cs3),
+ NPCM7XX_MKFUNC(spi0cs1),
+ NPCM7XX_MKFUNC(lpc),
+ NPCM7XX_MKFUNC(lpcclk),
+ NPCM7XX_MKFUNC(espi),
+ NPCM7XX_MKFUNC(lkgpo0),
+ NPCM7XX_MKFUNC(lkgpo1),
+ NPCM7XX_MKFUNC(lkgpo2),
+ NPCM7XX_MKFUNC(nprd_smi),
+};
+
+#define NPCM7XX_PINCFG(a, b, c, d, e, f, g, h, i, j, k) \
+ [a] { .fn0 = fn_ ## b, .reg0 = NPCM7XX_GCR_ ## c, .bit0 = d, \
+ .fn1 = fn_ ## e, .reg1 = NPCM7XX_GCR_ ## f, .bit1 = g, \
+ .fn2 = fn_ ## h, .reg2 = NPCM7XX_GCR_ ## i, .bit2 = j, \
+ .flag = k }
+
+/* Drive strength controlled by NPCM7XX_GP_N_ODSC */
+#define DRIVE_STRENGTH_LO_SHIFT 8
+#define DRIVE_STRENGTH_HI_SHIFT 12
+#define DRIVE_STRENGTH_MASK 0x0000FF00
+
+#define DS(lo, hi) (((lo) << DRIVE_STRENGTH_LO_SHIFT) | \
+ ((hi) << DRIVE_STRENGTH_HI_SHIFT))
+#define DSLO(x) (((x) >> DRIVE_STRENGTH_LO_SHIFT) & 0xF)
+#define DSHI(x) (((x) >> DRIVE_STRENGTH_HI_SHIFT) & 0xF)
+
+#define GPI 0x1 /* Not GPO */
+#define GPO 0x2 /* Not GPI */
+#define SLEW 0x4 /* Has Slew Control, NPCM7XX_GP_N_OSRC */
+#define SLEWLPC 0x8 /* Has Slew Control, SRCNT.3 */
+
+struct npcm7xx_pincfg {
+ int flag;
+ int fn0, reg0, bit0;
+ int fn1, reg1, bit1;
+ int fn2, reg2, bit2;
+};
+
+static const struct npcm7xx_pincfg pincfg[] = {
+ /* PIN FUNCTION 1 FUNCTION 2 FUNCTION 3 FLAGS */
+ NPCM7XX_PINCFG(0, iox1, MFSEL1, 30, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(1, iox1, MFSEL1, 30, none, NONE, 0, none, NONE, 0, DS(8, 12)),
+ NPCM7XX_PINCFG(2, iox1, MFSEL1, 30, none, NONE, 0, none, NONE, 0, DS(8, 12)),
+ NPCM7XX_PINCFG(3, iox1, MFSEL1, 30, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(4, iox2, MFSEL3, 14, smb1d, I2CSEGSEL, 7, none, NONE, 0, SLEW),
+ NPCM7XX_PINCFG(5, iox2, MFSEL3, 14, smb1d, I2CSEGSEL, 7, none, NONE, 0, SLEW),
+ NPCM7XX_PINCFG(6, iox2, MFSEL3, 14, smb2d, I2CSEGSEL, 10, none, NONE, 0, SLEW),
+ NPCM7XX_PINCFG(7, iox2, MFSEL3, 14, smb2d, I2CSEGSEL, 10, none, NONE, 0, SLEW),
+ NPCM7XX_PINCFG(8, lkgpo1, FLOCKR1, 4, none, NONE, 0, none, NONE, 0, DS(8, 12)),
+ NPCM7XX_PINCFG(9, lkgpo2, FLOCKR1, 8, none, NONE, 0, none, NONE, 0, DS(8, 12)),
+ NPCM7XX_PINCFG(10, ioxh, MFSEL3, 18, none, NONE, 0, none, NONE, 0, DS(8, 12)),
+ NPCM7XX_PINCFG(11, ioxh, MFSEL3, 18, none, NONE, 0, none, NONE, 0, DS(8, 12)),
+ NPCM7XX_PINCFG(12, gspi, MFSEL1, 24, smb5b, I2CSEGSEL, 19, none, NONE, 0, SLEW),
+ NPCM7XX_PINCFG(13, gspi, MFSEL1, 24, smb5b, I2CSEGSEL, 19, none, NONE, 0, SLEW),
+ NPCM7XX_PINCFG(14, gspi, MFSEL1, 24, smb5c, I2CSEGSEL, 20, none, NONE, 0, SLEW),
+ NPCM7XX_PINCFG(15, gspi, MFSEL1, 24, smb5c, I2CSEGSEL, 20, none, NONE, 0, SLEW),
+ NPCM7XX_PINCFG(16, lkgpo0, FLOCKR1, 0, none, NONE, 0, none, NONE, 0, DS(8, 12)),
+ NPCM7XX_PINCFG(17, pspi2, MFSEL3, 13, smb4den, I2CSEGSEL, 23, none, NONE, 0, DS(8, 12)),
+ NPCM7XX_PINCFG(18, pspi2, MFSEL3, 13, smb4b, I2CSEGSEL, 14, none, NONE, 0, DS(8, 12)),
+ NPCM7XX_PINCFG(19, pspi2, MFSEL3, 13, smb4b, I2CSEGSEL, 14, none, NONE, 0, DS(8, 12)),
+ NPCM7XX_PINCFG(20, smb4c, I2CSEGSEL, 15, smb15, MFSEL3, 8, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(21, smb4c, I2CSEGSEL, 15, smb15, MFSEL3, 8, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(22, smb4d, I2CSEGSEL, 16, smb14, MFSEL3, 7, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(23, smb4d, I2CSEGSEL, 16, smb14, MFSEL3, 7, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(24, ioxh, MFSEL3, 18, none, NONE, 0, none, NONE, 0, DS(8, 12)),
+ NPCM7XX_PINCFG(25, ioxh, MFSEL3, 18, none, NONE, 0, none, NONE, 0, DS(8, 12)),
+ NPCM7XX_PINCFG(26, smb5, MFSEL1, 2, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(27, smb5, MFSEL1, 2, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(28, smb4, MFSEL1, 1, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(29, smb4, MFSEL1, 1, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(30, smb3, MFSEL1, 0, none, NONE, 0, none, NONE, 0, 0),
+ 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(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),
+ NPCM7XX_PINCFG(40, smb3b, I2CSEGSEL, 11, none, NONE, 0, none, NONE, 0, SLEW),
+ NPCM7XX_PINCFG(41, bmcuart0a, MFSEL1, 9, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(42, bmcuart0a, MFSEL1, 9, none, NONE, 0, none, NONE, 0, DS(2, 4) | GPO),
+ NPCM7XX_PINCFG(43, uart1, MFSEL1, 10, jtag2, MFSEL4, 0, bmcuart1, MFSEL3, 24, 0),
+ NPCM7XX_PINCFG(44, uart1, MFSEL1, 10, jtag2, MFSEL4, 0, bmcuart1, MFSEL3, 24, 0),
+ NPCM7XX_PINCFG(45, uart1, MFSEL1, 10, jtag2, MFSEL4, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(46, uart1, MFSEL1, 10, jtag2, MFSEL4, 0, none, NONE, 0, DS(2, 8)),
+ NPCM7XX_PINCFG(47, uart1, MFSEL1, 10, jtag2, MFSEL4, 0, none, NONE, 0, DS(2, 8)),
+ NPCM7XX_PINCFG(48, uart2, MFSEL1, 11, bmcuart0b, MFSEL4, 1, none, NONE, 0, GPO),
+ NPCM7XX_PINCFG(49, uart2, MFSEL1, 11, bmcuart0b, MFSEL4, 1, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(50, uart2, MFSEL1, 11, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(51, uart2, MFSEL1, 11, none, NONE, 0, none, NONE, 0, GPO),
+ NPCM7XX_PINCFG(52, uart2, MFSEL1, 11, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(53, uart2, MFSEL1, 11, none, NONE, 0, none, NONE, 0, GPO),
+ NPCM7XX_PINCFG(54, uart2, MFSEL1, 11, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(55, uart2, MFSEL1, 11, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(56, r1err, MFSEL1, 12, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(57, r1md, MFSEL1, 13, none, NONE, 0, none, NONE, 0, DS(2, 4)),
+ NPCM7XX_PINCFG(58, r1md, MFSEL1, 13, none, NONE, 0, none, NONE, 0, DS(2, 4)),
+ NPCM7XX_PINCFG(59, smb3d, I2CSEGSEL, 13, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(60, smb3d, I2CSEGSEL, 13, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(61, uart1, MFSEL1, 10, none, NONE, 0, none, NONE, 0, GPO),
+ NPCM7XX_PINCFG(62, uart1, MFSEL1, 10, bmcuart1, MFSEL3, 24, none, NONE, 0, GPO),
+ NPCM7XX_PINCFG(63, uart1, MFSEL1, 10, bmcuart1, MFSEL3, 24, none, NONE, 0, GPO),
+
+ NPCM7XX_PINCFG(64, fanin0, MFSEL2, 0, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(65, fanin1, MFSEL2, 1, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(66, fanin2, MFSEL2, 2, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(67, fanin3, MFSEL2, 3, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(68, fanin4, MFSEL2, 4, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(69, fanin5, MFSEL2, 5, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(70, fanin6, MFSEL2, 6, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(71, fanin7, MFSEL2, 7, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(72, fanin8, MFSEL2, 8, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(73, fanin9, MFSEL2, 9, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(74, fanin10, MFSEL2, 10, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(75, fanin11, MFSEL2, 11, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(76, fanin12, MFSEL2, 12, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(77, fanin13, MFSEL2, 13, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(78, fanin14, MFSEL2, 14, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(79, fanin15, MFSEL2, 15, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(80, pwm0, MFSEL2, 16, none, NONE, 0, none, NONE, 0, DS(4, 8)),
+ NPCM7XX_PINCFG(81, pwm1, MFSEL2, 17, none, NONE, 0, none, NONE, 0, DS(4, 8)),
+ NPCM7XX_PINCFG(82, pwm2, MFSEL2, 18, none, NONE, 0, none, NONE, 0, DS(4, 8)),
+ NPCM7XX_PINCFG(83, pwm3, MFSEL2, 19, none, NONE, 0, none, NONE, 0, DS(4, 8)),
+ NPCM7XX_PINCFG(84, r2, MFSEL1, 14, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW),
+ NPCM7XX_PINCFG(85, r2, MFSEL1, 14, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW),
+ NPCM7XX_PINCFG(86, r2, MFSEL1, 14, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW),
+ NPCM7XX_PINCFG(87, r2, MFSEL1, 14, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(88, r2, MFSEL1, 14, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(89, r2, MFSEL1, 14, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(90, r2err, MFSEL1, 15, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(91, r2md, MFSEL1, 16, none, NONE, 0, none, NONE, 0, DS(2, 4)),
+ NPCM7XX_PINCFG(92, r2md, MFSEL1, 16, none, NONE, 0, none, NONE, 0, DS(2, 4)),
+ NPCM7XX_PINCFG(93, ga20kbc, MFSEL1, 17, smb5d, I2CSEGSEL, 21, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(94, ga20kbc, MFSEL1, 17, smb5d, I2CSEGSEL, 21, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(95, lpc, NONE, 0, espi, MFSEL4, 8, gpio, MFSEL1, 26, 0),
+
+ NPCM7XX_PINCFG(96, rg1, MFSEL4, 22, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(97, rg1, MFSEL4, 22, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(98, rg1, MFSEL4, 22, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(99, rg1, MFSEL4, 22, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(100, rg1, MFSEL4, 22, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(101, rg1, MFSEL4, 22, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(102, rg1, MFSEL4, 22, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(103, rg1, MFSEL4, 22, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(104, rg1, MFSEL4, 22, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(105, rg1, MFSEL4, 22, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(106, rg1, MFSEL4, 22, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(107, rg1, MFSEL4, 22, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(108, rg1mdio, MFSEL4, 21, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(109, rg1mdio, MFSEL4, 21, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(110, rg2, MFSEL4, 24, ddr, MFSEL3, 26, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(111, rg2, MFSEL4, 24, ddr, MFSEL3, 26, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(112, rg2, MFSEL4, 24, ddr, MFSEL3, 26, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(113, rg2, MFSEL4, 24, ddr, MFSEL3, 26, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(114, smb0, MFSEL1, 6, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(115, smb0, MFSEL1, 6, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(116, smb1, MFSEL1, 7, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(117, smb1, MFSEL1, 7, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(118, smb2, MFSEL1, 8, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(119, smb2, MFSEL1, 8, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(120, smb2c, I2CSEGSEL, 9, none, NONE, 0, none, NONE, 0, SLEW),
+ NPCM7XX_PINCFG(121, smb2c, I2CSEGSEL, 9, none, NONE, 0, none, NONE, 0, SLEW),
+ NPCM7XX_PINCFG(122, smb2b, I2CSEGSEL, 8, none, NONE, 0, none, NONE, 0, SLEW),
+ NPCM7XX_PINCFG(123, smb2b, I2CSEGSEL, 8, none, NONE, 0, none, NONE, 0, SLEW),
+ NPCM7XX_PINCFG(124, smb1c, I2CSEGSEL, 6, none, NONE, 0, none, NONE, 0, SLEW),
+ NPCM7XX_PINCFG(125, smb1c, I2CSEGSEL, 6, none, NONE, 0, none, NONE, 0, SLEW),
+ NPCM7XX_PINCFG(126, smb1b, I2CSEGSEL, 5, none, NONE, 0, none, NONE, 0, SLEW),
+ NPCM7XX_PINCFG(127, smb1b, I2CSEGSEL, 5, none, NONE, 0, none, NONE, 0, SLEW),
+
+ NPCM7XX_PINCFG(128, smb8, MFSEL4, 11, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(129, smb8, MFSEL4, 11, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(130, smb9, MFSEL4, 12, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(131, smb9, MFSEL4, 12, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(132, smb10, MFSEL4, 13, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(133, smb10, MFSEL4, 13, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(134, smb11, MFSEL4, 14, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(135, smb11, MFSEL4, 14, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(136, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW),
+ NPCM7XX_PINCFG(137, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW),
+ NPCM7XX_PINCFG(138, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW),
+ NPCM7XX_PINCFG(139, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW),
+ NPCM7XX_PINCFG(140, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW),
+ NPCM7XX_PINCFG(141, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(142, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW),
+ NPCM7XX_PINCFG(143, sd1, MFSEL3, 12, sd1pwr, MFSEL4, 5, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(144, pwm4, MFSEL2, 20, none, NONE, 0, none, NONE, 0, DS(4, 8)),
+ NPCM7XX_PINCFG(145, pwm5, MFSEL2, 21, none, NONE, 0, none, NONE, 0, DS(4, 8)),
+ NPCM7XX_PINCFG(146, pwm6, MFSEL2, 22, none, NONE, 0, none, NONE, 0, DS(4, 8)),
+ NPCM7XX_PINCFG(147, pwm7, MFSEL2, 23, none, NONE, 0, none, NONE, 0, DS(4, 8)),
+ NPCM7XX_PINCFG(148, mmc8, MFSEL3, 11, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW),
+ NPCM7XX_PINCFG(149, mmc8, MFSEL3, 11, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW),
+ NPCM7XX_PINCFG(150, mmc8, MFSEL3, 11, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW),
+ NPCM7XX_PINCFG(151, mmc8, MFSEL3, 11, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW),
+ NPCM7XX_PINCFG(152, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW),
+ NPCM7XX_PINCFG(153, mmcwp, FLOCKR1, 24, none, NONE, 0, none, NONE, 0, 0), /* Z1/A1 */
+ NPCM7XX_PINCFG(154, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW),
+ NPCM7XX_PINCFG(155, mmccd, MFSEL3, 25, mmcrst, MFSEL4, 6, none, NONE, 0, 0), /* Z1/A1 */
+ NPCM7XX_PINCFG(156, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW),
+ NPCM7XX_PINCFG(157, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW),
+ NPCM7XX_PINCFG(158, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW),
+ NPCM7XX_PINCFG(159, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW),
+
+ NPCM7XX_PINCFG(160, clkout, MFSEL1, 21, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW),
+ NPCM7XX_PINCFG(161, lpc, NONE, 0, espi, MFSEL4, 8, gpio, MFSEL1, 26, DS(8, 12)),
+ NPCM7XX_PINCFG(162, serirq, NONE, 0, gpio, MFSEL1, 31, none, NONE, 0, DS(8, 12)),
+ NPCM7XX_PINCFG(163, lpc, NONE, 0, espi, MFSEL4, 8, gpio, MFSEL1, 26, 0),
+ NPCM7XX_PINCFG(164, lpc, NONE, 0, espi, MFSEL4, 8, gpio, MFSEL1, 26, SLEWLPC),
+ NPCM7XX_PINCFG(165, lpc, NONE, 0, espi, MFSEL4, 8, gpio, MFSEL1, 26, SLEWLPC),
+ NPCM7XX_PINCFG(166, lpc, NONE, 0, espi, MFSEL4, 8, gpio, MFSEL1, 26, SLEWLPC),
+ NPCM7XX_PINCFG(167, lpc, NONE, 0, espi, MFSEL4, 8, gpio, MFSEL1, 26, SLEWLPC),
+ NPCM7XX_PINCFG(168, lpcclk, NONE, 0, espi, MFSEL4, 8, gpio, MFSEL3, 16, 0),
+ NPCM7XX_PINCFG(169, scipme, MFSEL3, 0, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(170, sci, MFSEL1, 22, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(171, smb6, MFSEL3, 1, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(172, smb6, MFSEL3, 1, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(173, smb7, MFSEL3, 2, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(174, smb7, MFSEL3, 2, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(175, pspi1, MFSEL3, 4, faninx, MFSEL3, 3, none, NONE, 0, DS(8, 12)),
+ NPCM7XX_PINCFG(176, pspi1, MFSEL3, 4, faninx, MFSEL3, 3, none, NONE, 0, DS(8, 12)),
+ NPCM7XX_PINCFG(177, pspi1, MFSEL3, 4, faninx, MFSEL3, 3, none, NONE, 0, DS(8, 12)),
+ NPCM7XX_PINCFG(178, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW),
+ NPCM7XX_PINCFG(179, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW),
+ NPCM7XX_PINCFG(180, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW),
+ NPCM7XX_PINCFG(181, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(182, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(183, spi3, MFSEL4, 16, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW),
+ NPCM7XX_PINCFG(184, spi3, MFSEL4, 16, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW | GPO),
+ NPCM7XX_PINCFG(185, spi3, MFSEL4, 16, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW | GPO),
+ NPCM7XX_PINCFG(186, spi3, MFSEL4, 16, none, NONE, 0, none, NONE, 0, DS(8, 12)),
+ NPCM7XX_PINCFG(187, spi3cs1, MFSEL4, 17, none, NONE, 0, none, NONE, 0, DS(8, 12)),
+ NPCM7XX_PINCFG(188, spi3quad, MFSEL4, 20, spi3cs2, MFSEL4, 18, none, NONE, 0, DS(8, 12) | SLEW),
+ NPCM7XX_PINCFG(189, spi3quad, MFSEL4, 20, spi3cs3, MFSEL4, 19, none, NONE, 0, DS(8, 12) | SLEW),
+ NPCM7XX_PINCFG(190, gpio, FLOCKR1, 20, nprd_smi, NONE, 0, none, NONE, 0, DS(2, 4)),
+ NPCM7XX_PINCFG(191, none, NONE, 0, none, NONE, 0, none, NONE, 0, DS(8, 12)), /* XX */
+
+ NPCM7XX_PINCFG(192, none, NONE, 0, none, NONE, 0, none, NONE, 0, DS(8, 12)), /* XX */
+ NPCM7XX_PINCFG(193, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(194, smb0b, I2CSEGSEL, 0, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(195, smb0b, I2CSEGSEL, 0, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(196, smb0c, I2CSEGSEL, 1, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(197, smb0den, I2CSEGSEL, 22, none, NONE, 0, none, NONE, 0, SLEW),
+ NPCM7XX_PINCFG(198, smb0d, I2CSEGSEL, 2, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(199, smb0d, I2CSEGSEL, 2, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(200, r2, MFSEL1, 14, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(201, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(202, smb0c, I2CSEGSEL, 1, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(203, faninx, MFSEL3, 3, none, NONE, 0, none, NONE, 0, DS(8, 12)),
+ NPCM7XX_PINCFG(204, ddc, NONE, 0, gpio, MFSEL3, 22, none, NONE, 0, SLEW),
+ NPCM7XX_PINCFG(205, ddc, NONE, 0, gpio, MFSEL3, 22, none, NONE, 0, SLEW),
+ NPCM7XX_PINCFG(206, ddc, NONE, 0, gpio, MFSEL3, 22, none, NONE, 0, DS(4, 8)),
+ NPCM7XX_PINCFG(207, ddc, NONE, 0, gpio, MFSEL3, 22, none, NONE, 0, DS(4, 8)),
+ NPCM7XX_PINCFG(208, rg2, MFSEL4, 24, ddr, MFSEL3, 26, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(209, rg2, MFSEL4, 24, ddr, MFSEL3, 26, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(210, rg2, MFSEL4, 24, ddr, MFSEL3, 26, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(211, rg2, MFSEL4, 24, ddr, MFSEL3, 26, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(212, rg2, MFSEL4, 24, ddr, MFSEL3, 26, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(213, rg2, MFSEL4, 24, ddr, MFSEL3, 26, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(214, rg2, MFSEL4, 24, ddr, MFSEL3, 26, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(215, rg2, MFSEL4, 24, ddr, MFSEL3, 26, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(216, rg2mdio, MFSEL4, 23, ddr, MFSEL3, 26, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(217, rg2mdio, MFSEL4, 23, ddr, MFSEL3, 26, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(218, wdog1, MFSEL3, 19, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(219, wdog2, MFSEL3, 20, none, NONE, 0, none, NONE, 0, DS(4, 8)),
+ NPCM7XX_PINCFG(220, smb12, MFSEL3, 5, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(221, smb12, MFSEL3, 5, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(222, smb13, MFSEL3, 6, none, NONE, 0, none, NONE, 0, 0),
+ NPCM7XX_PINCFG(223, smb13, MFSEL3, 6, none, NONE, 0, none, NONE, 0, 0),
+
+ NPCM7XX_PINCFG(224, spix, MFSEL4, 27, none, NONE, 0, none, NONE, 0, SLEW),
+ NPCM7XX_PINCFG(225, spix, MFSEL4, 27, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW | GPO),
+ NPCM7XX_PINCFG(226, spix, MFSEL4, 27, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW | GPO),
+ NPCM7XX_PINCFG(227, spix, MFSEL4, 27, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW),
+ NPCM7XX_PINCFG(228, spixcs1, MFSEL4, 28, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW),
+ NPCM7XX_PINCFG(229, spix, MFSEL4, 27, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW),
+ NPCM7XX_PINCFG(230, spix, MFSEL4, 27, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW),
+ NPCM7XX_PINCFG(231, clkreq, MFSEL4, 9, none, NONE, 0, none, NONE, 0, DS(8, 12)),
+ NPCM7XX_PINCFG(253, none, NONE, 0, none, NONE, 0, none, NONE, 0, GPI), /* SDHC1 power */
+ NPCM7XX_PINCFG(254, none, NONE, 0, none, NONE, 0, none, NONE, 0, GPI), /* SDHC2 power */
+ NPCM7XX_PINCFG(255, none, NONE, 0, none, NONE, 0, none, NONE, 0, GPI), /* DACOSEL */
+};
+
+/* number, name, drv_data */
+static const struct pinctrl_pin_desc npcm7xx_pins[] = {
+ PINCTRL_PIN(0, "GPIO0/IOX1DI"),
+ PINCTRL_PIN(1, "GPIO1/IOX1LD"),
+ PINCTRL_PIN(2, "GPIO2/IOX1CK"),
+ PINCTRL_PIN(3, "GPIO3/IOX1D0"),
+ PINCTRL_PIN(4, "GPIO4/IOX2DI/SMB1DSDA"),
+ PINCTRL_PIN(5, "GPIO5/IOX2LD/SMB1DSCL"),
+ PINCTRL_PIN(6, "GPIO6/IOX2CK/SMB2DSDA"),
+ PINCTRL_PIN(7, "GPIO7/IOX2D0/SMB2DSCL"),
+ PINCTRL_PIN(8, "GPIO8/LKGPO1"),
+ PINCTRL_PIN(9, "GPIO9/LKGPO2"),
+ PINCTRL_PIN(10, "GPIO10/IOXHLD"),
+ PINCTRL_PIN(11, "GPIO11/IOXHCK"),
+ PINCTRL_PIN(12, "GPIO12/GSPICK/SMB5BSCL"),
+ PINCTRL_PIN(13, "GPIO13/GSPIDO/SMB5BSDA"),
+ PINCTRL_PIN(14, "GPIO14/GSPIDI/SMB5CSCL"),
+ PINCTRL_PIN(15, "GPIO15/GSPICS/SMB5CSDA"),
+ PINCTRL_PIN(16, "GPIO16/LKGPO0"),
+ PINCTRL_PIN(17, "GPIO17/PSPI2DI/SMB4DEN"),
+ PINCTRL_PIN(18, "GPIO18/PSPI2D0/SMB4BSDA"),
+ PINCTRL_PIN(19, "GPIO19/PSPI2CK/SMB4BSCL"),
+ PINCTRL_PIN(20, "GPIO20/SMB4CSDA/SMB15SDA"),
+ PINCTRL_PIN(21, "GPIO21/SMB4CSCL/SMB15SCL"),
+ PINCTRL_PIN(22, "GPIO22/SMB4DSDA/SMB14SDA"),
+ PINCTRL_PIN(23, "GPIO23/SMB4DSCL/SMB14SCL"),
+ PINCTRL_PIN(24, "GPIO24/IOXHDO"),
+ PINCTRL_PIN(25, "GPIO25/IOXHDI"),
+ PINCTRL_PIN(26, "GPIO26/SMB5SDA"),
+ PINCTRL_PIN(27, "GPIO27/SMB5SCL"),
+ PINCTRL_PIN(28, "GPIO28/SMB4SDA"),
+ PINCTRL_PIN(29, "GPIO29/SMB4SCL"),
+ PINCTRL_PIN(30, "GPIO30/SMB3SDA"),
+ PINCTRL_PIN(31, "GPIO31/SMB3SCL"),
+
+ PINCTRL_PIN(32, "GPIO32/nSPI0CS1"),
+ PINCTRL_PIN(33, "SPI0D2"),
+ PINCTRL_PIN(34, "SPI0D3"),
+ PINCTRL_PIN(37, "GPIO37/SMB3CSDA"),
+ PINCTRL_PIN(38, "GPIO38/SMB3CSCL"),
+ PINCTRL_PIN(39, "GPIO39/SMB3BSDA"),
+ PINCTRL_PIN(40, "GPIO40/SMB3BSCL"),
+ PINCTRL_PIN(41, "GPIO41/BSPRXD"),
+ PINCTRL_PIN(42, "GPO42/BSPTXD/STRAP11"),
+ PINCTRL_PIN(43, "GPIO43/RXD1/JTMS2/BU1RXD"),
+ PINCTRL_PIN(44, "GPIO44/nCTS1/JTDI2/BU1CTS"),
+ PINCTRL_PIN(45, "GPIO45/nDCD1/JTDO2"),
+ PINCTRL_PIN(46, "GPIO46/nDSR1/JTCK2"),
+ PINCTRL_PIN(47, "GPIO47/nRI1/JCP_RDY2"),
+ PINCTRL_PIN(48, "GPIO48/TXD2/BSPTXD"),
+ PINCTRL_PIN(49, "GPIO49/RXD2/BSPRXD"),
+ PINCTRL_PIN(50, "GPIO50/nCTS2"),
+ PINCTRL_PIN(51, "GPO51/nRTS2/STRAP2"),
+ PINCTRL_PIN(52, "GPIO52/nDCD2"),
+ PINCTRL_PIN(53, "GPO53/nDTR2_BOUT2/STRAP1"),
+ PINCTRL_PIN(54, "GPIO54/nDSR2"),
+ PINCTRL_PIN(55, "GPIO55/nRI2"),
+ PINCTRL_PIN(56, "GPIO56/R1RXERR"),
+ PINCTRL_PIN(57, "GPIO57/R1MDC"),
+ PINCTRL_PIN(58, "GPIO58/R1MDIO"),
+ PINCTRL_PIN(59, "GPIO59/SMB3DSDA"),
+ PINCTRL_PIN(60, "GPIO60/SMB3DSCL"),
+ PINCTRL_PIN(61, "GPO61/nDTR1_BOUT1/STRAP6"),
+ PINCTRL_PIN(62, "GPO62/nRTST1/STRAP5"),
+ PINCTRL_PIN(63, "GPO63/TXD1/STRAP4"),
+
+ PINCTRL_PIN(64, "GPIO64/FANIN0"),
+ PINCTRL_PIN(65, "GPIO65/FANIN1"),
+ PINCTRL_PIN(66, "GPIO66/FANIN2"),
+ PINCTRL_PIN(67, "GPIO67/FANIN3"),
+ PINCTRL_PIN(68, "GPIO68/FANIN4"),
+ PINCTRL_PIN(69, "GPIO69/FANIN5"),
+ PINCTRL_PIN(70, "GPIO70/FANIN6"),
+ PINCTRL_PIN(71, "GPIO71/FANIN7"),
+ PINCTRL_PIN(72, "GPIO72/FANIN8"),
+ PINCTRL_PIN(73, "GPIO73/FANIN9"),
+ PINCTRL_PIN(74, "GPIO74/FANIN10"),
+ PINCTRL_PIN(75, "GPIO75/FANIN11"),
+ PINCTRL_PIN(76, "GPIO76/FANIN12"),
+ PINCTRL_PIN(77, "GPIO77/FANIN13"),
+ PINCTRL_PIN(78, "GPIO78/FANIN14"),
+ PINCTRL_PIN(79, "GPIO79/FANIN15"),
+ PINCTRL_PIN(80, "GPIO80/PWM0"),
+ PINCTRL_PIN(81, "GPIO81/PWM1"),
+ PINCTRL_PIN(82, "GPIO82/PWM2"),
+ PINCTRL_PIN(83, "GPIO83/PWM3"),
+ PINCTRL_PIN(84, "GPIO84/R2TXD0"),
+ PINCTRL_PIN(85, "GPIO85/R2TXD1"),
+ PINCTRL_PIN(86, "GPIO86/R2TXEN"),
+ PINCTRL_PIN(87, "GPIO87/R2RXD0"),
+ PINCTRL_PIN(88, "GPIO88/R2RXD1"),
+ PINCTRL_PIN(89, "GPIO89/R2CRSDV"),
+ PINCTRL_PIN(90, "GPIO90/R2RXERR"),
+ PINCTRL_PIN(91, "GPIO91/R2MDC"),
+ PINCTRL_PIN(92, "GPIO92/R2MDIO"),
+ PINCTRL_PIN(93, "GPIO93/GA20/SMB5DSCL"),
+ PINCTRL_PIN(94, "GPIO94/nKBRST/SMB5DSDA"),
+ PINCTRL_PIN(95, "GPIO95/nLRESET/nESPIRST"),
+
+ PINCTRL_PIN(96, "GPIO96/RG1TXD0"),
+ PINCTRL_PIN(97, "GPIO97/RG1TXD1"),
+ PINCTRL_PIN(98, "GPIO98/RG1TXD2"),
+ PINCTRL_PIN(99, "GPIO99/RG1TXD3"),
+ PINCTRL_PIN(100, "GPIO100/RG1TXC"),
+ PINCTRL_PIN(101, "GPIO101/RG1TXCTL"),
+ PINCTRL_PIN(102, "GPIO102/RG1RXD0"),
+ PINCTRL_PIN(103, "GPIO103/RG1RXD1"),
+ PINCTRL_PIN(104, "GPIO104/RG1RXD2"),
+ PINCTRL_PIN(105, "GPIO105/RG1RXD3"),
+ PINCTRL_PIN(106, "GPIO106/RG1RXC"),
+ PINCTRL_PIN(107, "GPIO107/RG1RXCTL"),
+ PINCTRL_PIN(108, "GPIO108/RG1MDC"),
+ PINCTRL_PIN(109, "GPIO109/RG1MDIO"),
+ PINCTRL_PIN(110, "GPIO110/RG2TXD0/DDRV0"),
+ PINCTRL_PIN(111, "GPIO111/RG2TXD1/DDRV1"),
+ PINCTRL_PIN(112, "GPIO112/RG2TXD2/DDRV2"),
+ PINCTRL_PIN(113, "GPIO113/RG2TXD3/DDRV3"),
+ PINCTRL_PIN(114, "GPIO114/SMB0SCL"),
+ PINCTRL_PIN(115, "GPIO115/SMB0SDA"),
+ PINCTRL_PIN(116, "GPIO116/SMB1SCL"),
+ PINCTRL_PIN(117, "GPIO117/SMB1SDA"),
+ PINCTRL_PIN(118, "GPIO118/SMB2SCL"),
+ PINCTRL_PIN(119, "GPIO119/SMB2SDA"),
+ PINCTRL_PIN(120, "GPIO120/SMB2CSDA"),
+ PINCTRL_PIN(121, "GPIO121/SMB2CSCL"),
+ PINCTRL_PIN(122, "GPIO122/SMB2BSDA"),
+ PINCTRL_PIN(123, "GPIO123/SMB2BSCL"),
+ PINCTRL_PIN(124, "GPIO124/SMB1CSDA"),
+ PINCTRL_PIN(125, "GPIO125/SMB1CSCL"),
+ PINCTRL_PIN(126, "GPIO126/SMB1BSDA"),
+ PINCTRL_PIN(127, "GPIO127/SMB1BSCL"),
+
+ PINCTRL_PIN(128, "GPIO128/SMB8SCL"),
+ PINCTRL_PIN(129, "GPIO129/SMB8SDA"),
+ PINCTRL_PIN(130, "GPIO130/SMB9SCL"),
+ PINCTRL_PIN(131, "GPIO131/SMB9SDA"),
+ PINCTRL_PIN(132, "GPIO132/SMB10SCL"),
+ PINCTRL_PIN(133, "GPIO133/SMB10SDA"),
+ PINCTRL_PIN(134, "GPIO134/SMB11SCL"),
+ PINCTRL_PIN(135, "GPIO135/SMB11SDA"),
+ PINCTRL_PIN(136, "GPIO136/SD1DT0"),
+ PINCTRL_PIN(137, "GPIO137/SD1DT1"),
+ PINCTRL_PIN(138, "GPIO138/SD1DT2"),
+ PINCTRL_PIN(139, "GPIO139/SD1DT3"),
+ PINCTRL_PIN(140, "GPIO140/SD1CLK"),
+ PINCTRL_PIN(141, "GPIO141/SD1WP"),
+ PINCTRL_PIN(142, "GPIO142/SD1CMD"),
+ PINCTRL_PIN(143, "GPIO143/SD1CD/SD1PWR"),
+ PINCTRL_PIN(144, "GPIO144/PWM4"),
+ PINCTRL_PIN(145, "GPIO145/PWM5"),
+ PINCTRL_PIN(146, "GPIO146/PWM6"),
+ PINCTRL_PIN(147, "GPIO147/PWM7"),
+ PINCTRL_PIN(148, "GPIO148/MMCDT4"),
+ PINCTRL_PIN(149, "GPIO149/MMCDT5"),
+ PINCTRL_PIN(150, "GPIO150/MMCDT6"),
+ PINCTRL_PIN(151, "GPIO151/MMCDT7"),
+ PINCTRL_PIN(152, "GPIO152/MMCCLK"),
+ PINCTRL_PIN(153, "GPIO153/MMCWP"),
+ PINCTRL_PIN(154, "GPIO154/MMCCMD"),
+ PINCTRL_PIN(155, "GPIO155/nMMCCD/nMMCRST"),
+ PINCTRL_PIN(156, "GPIO156/MMCDT0"),
+ PINCTRL_PIN(157, "GPIO157/MMCDT1"),
+ PINCTRL_PIN(158, "GPIO158/MMCDT2"),
+ PINCTRL_PIN(159, "GPIO159/MMCDT3"),
+
+ PINCTRL_PIN(160, "GPIO160/CLKOUT/RNGOSCOUT"),
+ PINCTRL_PIN(161, "GPIO161/nLFRAME/nESPICS"),
+ PINCTRL_PIN(162, "GPIO162/SERIRQ"),
+ PINCTRL_PIN(163, "GPIO163/LCLK/ESPICLK"),
+ PINCTRL_PIN(164, "GPIO164/LAD0/ESPI_IO0"/*dscnt6*/),
+ PINCTRL_PIN(165, "GPIO165/LAD1/ESPI_IO1"/*dscnt6*/),
+ PINCTRL_PIN(166, "GPIO166/LAD2/ESPI_IO2"/*dscnt6*/),
+ PINCTRL_PIN(167, "GPIO167/LAD3/ESPI_IO3"/*dscnt6*/),
+ PINCTRL_PIN(168, "GPIO168/nCLKRUN/nESPIALERT"),
+ PINCTRL_PIN(169, "GPIO169/nSCIPME"),
+ PINCTRL_PIN(170, "GPIO170/nSMI"),
+ PINCTRL_PIN(171, "GPIO171/SMB6SCL"),
+ PINCTRL_PIN(172, "GPIO172/SMB6SDA"),
+ PINCTRL_PIN(173, "GPIO173/SMB7SCL"),
+ PINCTRL_PIN(174, "GPIO174/SMB7SDA"),
+ PINCTRL_PIN(175, "GPIO175/PSPI1CK/FANIN19"),
+ PINCTRL_PIN(176, "GPIO176/PSPI1DO/FANIN18"),
+ PINCTRL_PIN(177, "GPIO177/PSPI1DI/FANIN17"),
+ PINCTRL_PIN(178, "GPIO178/R1TXD0"),
+ PINCTRL_PIN(179, "GPIO179/R1TXD1"),
+ PINCTRL_PIN(180, "GPIO180/R1TXEN"),
+ PINCTRL_PIN(181, "GPIO181/R1RXD0"),
+ PINCTRL_PIN(182, "GPIO182/R1RXD1"),
+ PINCTRL_PIN(183, "GPIO183/SPI3CK"),
+ PINCTRL_PIN(184, "GPO184/SPI3D0/STRAP9"),
+ PINCTRL_PIN(185, "GPO185/SPI3D1/STRAP10"),
+ PINCTRL_PIN(186, "GPIO186/nSPI3CS0"),
+ PINCTRL_PIN(187, "GPIO187/nSPI3CS1"),
+ PINCTRL_PIN(188, "GPIO188/SPI3D2/nSPI3CS2"),
+ PINCTRL_PIN(189, "GPIO189/SPI3D3/nSPI3CS3"),
+ PINCTRL_PIN(190, "GPIO190/nPRD_SMI"),
+ PINCTRL_PIN(191, "GPIO191"),
+
+ PINCTRL_PIN(192, "GPIO192"),
+ PINCTRL_PIN(193, "GPIO193/R1CRSDV"),
+ PINCTRL_PIN(194, "GPIO194/SMB0BSCL"),
+ PINCTRL_PIN(195, "GPIO195/SMB0BSDA"),
+ PINCTRL_PIN(196, "GPIO196/SMB0CSCL"),
+ PINCTRL_PIN(197, "GPIO197/SMB0DEN"),
+ PINCTRL_PIN(198, "GPIO198/SMB0DSDA"),
+ PINCTRL_PIN(199, "GPIO199/SMB0DSCL"),
+ PINCTRL_PIN(200, "GPIO200/R2CK"),
+ PINCTRL_PIN(201, "GPIO201/R1CK"),
+ PINCTRL_PIN(202, "GPIO202/SMB0CSDA"),
+ PINCTRL_PIN(203, "GPIO203/FANIN16"),
+ PINCTRL_PIN(204, "GPIO204/DDC2SCL"),
+ PINCTRL_PIN(205, "GPIO205/DDC2SDA"),
+ PINCTRL_PIN(206, "GPIO206/HSYNC2"),
+ PINCTRL_PIN(207, "GPIO207/VSYNC2"),
+ PINCTRL_PIN(208, "GPIO208/RG2TXC/DVCK"),
+ PINCTRL_PIN(209, "GPIO209/RG2TXCTL/DDRV4"),
+ PINCTRL_PIN(210, "GPIO210/RG2RXD0/DDRV5"),
+ PINCTRL_PIN(211, "GPIO211/RG2RXD1/DDRV6"),
+ PINCTRL_PIN(212, "GPIO212/RG2RXD2/DDRV7"),
+ PINCTRL_PIN(213, "GPIO213/RG2RXD3/DDRV8"),
+ PINCTRL_PIN(214, "GPIO214/RG2RXC/DDRV9"),
+ PINCTRL_PIN(215, "GPIO215/RG2RXCTL/DDRV10"),
+ PINCTRL_PIN(216, "GPIO216/RG2MDC/DDRV11"),
+ PINCTRL_PIN(217, "GPIO217/RG2MDIO/DVHSYNC"),
+ PINCTRL_PIN(218, "GPIO218/nWDO1"),
+ PINCTRL_PIN(219, "GPIO219/nWDO2"),
+ PINCTRL_PIN(220, "GPIO220/SMB12SCL"),
+ PINCTRL_PIN(221, "GPIO221/SMB12SDA"),
+ PINCTRL_PIN(222, "GPIO222/SMB13SCL"),
+ PINCTRL_PIN(223, "GPIO223/SMB13SDA"),
+
+ PINCTRL_PIN(224, "GPIO224/SPIXCK"),
+ PINCTRL_PIN(225, "GPO225/SPIXD0/STRAP12"),
+ PINCTRL_PIN(226, "GPO226/SPIXD1/STRAP13"),
+ PINCTRL_PIN(227, "GPIO227/nSPIXCS0"),
+ PINCTRL_PIN(228, "GPIO228/nSPIXCS1"),
+ PINCTRL_PIN(229, "GPO229/SPIXD2/STRAP3"),
+ PINCTRL_PIN(230, "GPIO230/SPIXD3"),
+ PINCTRL_PIN(231, "GPIO231/nCLKREQ"),
+ PINCTRL_PIN(255, "GPI255/DACOSEL"),
+};
+
+/* Enable mode in pin group */
+static void npcm7xx_setfunc(struct regmap *gcr_regmap, const unsigned int *pin,
+ int pin_number, int mode)
+{
+ const struct npcm7xx_pincfg *cfg;
+ int i;
+
+ for (i = 0 ; i < pin_number ; i++) {
+ cfg = &pincfg[pin[i]];
+ if (mode == fn_gpio || cfg->fn0 == mode || cfg->fn1 == mode || cfg->fn2 == mode) {
+ if (cfg->reg0)
+ regmap_update_bits(gcr_regmap, cfg->reg0,
+ BIT(cfg->bit0),
+ !!(cfg->fn0 == mode) ?
+ BIT(cfg->bit0) : 0);
+ if (cfg->reg1)
+ regmap_update_bits(gcr_regmap, cfg->reg1,
+ BIT(cfg->bit1),
+ !!(cfg->fn1 == mode) ?
+ BIT(cfg->bit1) : 0);
+ if (cfg->reg2)
+ regmap_update_bits(gcr_regmap, cfg->reg2,
+ BIT(cfg->bit2),
+ !!(cfg->fn2 == mode) ?
+ BIT(cfg->bit2) : 0);
+ }
+ }
+}
+
+/* Get slew rate of pin (high/low) */
+static int npcm7xx_get_slew_rate(struct npcm7xx_gpio *bank,
+ struct regmap *gcr_regmap, unsigned int pin)
+{
+ u32 val;
+ int gpio = (pin % bank->gc.ngpio);
+ unsigned long pinmask = BIT(gpio);
+
+ if (pincfg[pin].flag & SLEW)
+ return ioread32(bank->base + NPCM7XX_GP_N_OSRC)
+ & pinmask;
+ /* LPC Slew rate in SRCNT register */
+ if (pincfg[pin].flag & SLEWLPC) {
+ regmap_read(gcr_regmap, NPCM7XX_GCR_SRCNT, &val);
+ return !!(val & SRCNT_ESPI);
+ }
+
+ return -EINVAL;
+}
+
+/* Set slew rate of pin (high/low) */
+static int npcm7xx_set_slew_rate(struct npcm7xx_gpio *bank,
+ struct regmap *gcr_regmap, unsigned int pin,
+ int arg)
+{
+ int gpio = BIT(pin % bank->gc.ngpio);
+
+ if (pincfg[pin].flag & SLEW) {
+ switch (arg) {
+ case 0:
+ npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_OSRC,
+ gpio);
+ return 0;
+ case 1:
+ npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_OSRC,
+ gpio);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+ }
+ /* LPC Slew rate in SRCNT register */
+ if (pincfg[pin].flag & SLEWLPC) {
+ switch (arg) {
+ case 0:
+ regmap_update_bits(gcr_regmap, NPCM7XX_GCR_SRCNT,
+ SRCNT_ESPI, 0);
+ return 0;
+ case 1:
+ regmap_update_bits(gcr_regmap, NPCM7XX_GCR_SRCNT,
+ SRCNT_ESPI, SRCNT_ESPI);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ return -EINVAL;
+}
+
+/* Get drive strength for a pin, if supported */
+static int npcm7xx_get_drive_strength(struct pinctrl_dev *pctldev,
+ unsigned int pin)
+{
+ struct npcm7xx_pinctrl *npcm = pinctrl_dev_get_drvdata(pctldev);
+ struct npcm7xx_gpio *bank =
+ &npcm->gpio_bank[pin / NPCM7XX_GPIO_PER_BANK];
+ int gpio = (pin % bank->gc.ngpio);
+ unsigned long pinmask = BIT(gpio);
+ u32 ds = 0;
+ int flg, val;
+
+ flg = pincfg[pin].flag;
+ if (flg & DRIVE_STRENGTH_MASK) {
+ /* Get standard reading */
+ val = ioread32(bank->base + NPCM7XX_GP_N_ODSC)
+ & pinmask;
+ ds = val ? DSHI(flg) : DSLO(flg);
+ dev_dbg(bank->gc.parent,
+ "pin %d strength %d = %d\n", pin, val, ds);
+ return ds;
+ }
+
+ return -EINVAL;
+}
+
+/* Set drive strength for a pin, if supported */
+static int npcm7xx_set_drive_strength(struct npcm7xx_pinctrl *npcm,
+ unsigned int pin, int nval)
+{
+ int v;
+ struct npcm7xx_gpio *bank =
+ &npcm->gpio_bank[pin / NPCM7XX_GPIO_PER_BANK];
+ int gpio = BIT(pin % bank->gc.ngpio);
+
+ v = (pincfg[pin].flag & DRIVE_STRENGTH_MASK);
+ if (!nval || !v)
+ return -ENOTSUPP;
+ if (DSLO(v) == nval) {
+ dev_dbg(bank->gc.parent,
+ "setting pin %d to low strength [%d]\n", pin, nval);
+ npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_ODSC, gpio);
+ return 0;
+ } else if (DSHI(v) == nval) {
+ dev_dbg(bank->gc.parent,
+ "setting pin %d to high strength [%d]\n", pin, nval);
+ npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_ODSC, gpio);
+ return 0;
+ }
+
+ return -ENOTSUPP;
+}
+
+/* pinctrl_ops */
+static void npcm7xx_pin_dbg_show(struct pinctrl_dev *pctldev,
+ struct seq_file *s, unsigned int offset)
+{
+ seq_printf(s, "pinctrl_ops.dbg: %d", offset);
+}
+
+static int npcm7xx_get_groups_count(struct pinctrl_dev *pctldev)
+{
+ struct npcm7xx_pinctrl *npcm = pinctrl_dev_get_drvdata(pctldev);
+
+ dev_dbg(npcm->dev, "group size: %d\n", ARRAY_SIZE(npcm7xx_groups));
+ return ARRAY_SIZE(npcm7xx_groups);
+}
+
+static const char *npcm7xx_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned int selector)
+{
+ return npcm7xx_groups[selector].name;
+}
+
+static int npcm7xx_get_group_pins(struct pinctrl_dev *pctldev,
+ unsigned int selector,
+ const unsigned int **pins,
+ unsigned int *npins)
+{
+ *npins = npcm7xx_groups[selector].npins;
+ *pins = npcm7xx_groups[selector].pins;
+
+ return 0;
+}
+
+static int npcm7xx_dt_node_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *np_config,
+ struct pinctrl_map **map,
+ u32 *num_maps)
+{
+ struct npcm7xx_pinctrl *npcm = pinctrl_dev_get_drvdata(pctldev);
+
+ dev_dbg(npcm->dev, "dt_node_to_map: %s\n", np_config->name);
+ return pinconf_generic_dt_node_to_map(pctldev, np_config,
+ map, num_maps,
+ PIN_MAP_TYPE_INVALID);
+}
+
+static void npcm7xx_dt_free_map(struct pinctrl_dev *pctldev,
+ struct pinctrl_map *map, u32 num_maps)
+{
+ kfree(map);
+}
+
+static struct pinctrl_ops npcm7xx_pinctrl_ops = {
+ .get_groups_count = npcm7xx_get_groups_count,
+ .get_group_name = npcm7xx_get_group_name,
+ .get_group_pins = npcm7xx_get_group_pins,
+ .pin_dbg_show = npcm7xx_pin_dbg_show,
+ .dt_node_to_map = npcm7xx_dt_node_to_map,
+ .dt_free_map = npcm7xx_dt_free_map,
+};
+
+/* pinmux_ops */
+static int npcm7xx_get_functions_count(struct pinctrl_dev *pctldev)
+{
+ return ARRAY_SIZE(npcm7xx_funcs);
+}
+
+static const char *npcm7xx_get_function_name(struct pinctrl_dev *pctldev,
+ unsigned int function)
+{
+ return npcm7xx_funcs[function].name;
+}
+
+static int npcm7xx_get_function_groups(struct pinctrl_dev *pctldev,
+ unsigned int function,
+ const char * const **groups,
+ unsigned int * const ngroups)
+{
+ *ngroups = npcm7xx_funcs[function].ngroups;
+ *groups = npcm7xx_funcs[function].groups;
+
+ return 0;
+}
+
+static int npcm7xx_pinmux_set_mux(struct pinctrl_dev *pctldev,
+ unsigned int function,
+ unsigned int group)
+{
+ struct npcm7xx_pinctrl *npcm = pinctrl_dev_get_drvdata(pctldev);
+
+ dev_dbg(npcm->dev, "set_mux: %d, %d[%s]\n", function, group,
+ npcm7xx_groups[group].name);
+
+ npcm7xx_setfunc(npcm->gcr_regmap, npcm7xx_groups[group].pins,
+ npcm7xx_groups[group].npins, group);
+
+ return 0;
+}
+
+static int npcm7xx_gpio_request_enable(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned int offset)
+{
+ struct npcm7xx_pinctrl *npcm = pinctrl_dev_get_drvdata(pctldev);
+
+ if (!range) {
+ dev_err(npcm->dev, "invalid range\n");
+ return -EINVAL;
+ }
+ if (!range->gc) {
+ dev_err(npcm->dev, "invalid gpiochip\n");
+ return -EINVAL;
+ }
+
+ npcm7xx_setfunc(npcm->gcr_regmap, &offset, 1, fn_gpio);
+
+ return 0;
+}
+
+/* Release GPIO back to pinctrl mode */
+static void npcm7xx_gpio_request_free(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned int offset)
+{
+ struct npcm7xx_pinctrl *npcm = pinctrl_dev_get_drvdata(pctldev);
+ int virq;
+
+ virq = irq_find_mapping(npcm->domain, offset);
+ if (virq)
+ irq_dispose_mapping(virq);
+}
+
+/* Set GPIO direction */
+static int npcm_gpio_set_direction(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned int offset, bool input)
+{
+ struct npcm7xx_pinctrl *npcm = pinctrl_dev_get_drvdata(pctldev);
+ struct npcm7xx_gpio *bank =
+ &npcm->gpio_bank[offset / NPCM7XX_GPIO_PER_BANK];
+ int gpio = BIT(offset % bank->gc.ngpio);
+
+ dev_dbg(bank->gc.parent, "GPIO Set Direction: %d = %d\n", offset,
+ input);
+ if (input)
+ iowrite32(gpio, bank->base + NPCM7XX_GP_N_OEC);
+ else
+ iowrite32(gpio, bank->base + NPCM7XX_GP_N_OES);
+
+ return 0;
+}
+
+static struct pinmux_ops npcm7xx_pinmux_ops = {
+ .get_functions_count = npcm7xx_get_functions_count,
+ .get_function_name = npcm7xx_get_function_name,
+ .get_function_groups = npcm7xx_get_function_groups,
+ .set_mux = npcm7xx_pinmux_set_mux,
+ .gpio_request_enable = npcm7xx_gpio_request_enable,
+ .gpio_disable_free = npcm7xx_gpio_request_free,
+ .gpio_set_direction = npcm_gpio_set_direction,
+};
+
+/* pinconf_ops */
+static int npcm7xx_config_get(struct pinctrl_dev *pctldev, unsigned int pin,
+ unsigned long *config)
+{
+ enum pin_config_param param = pinconf_to_config_param(*config);
+ struct npcm7xx_pinctrl *npcm = pinctrl_dev_get_drvdata(pctldev);
+ struct npcm7xx_gpio *bank =
+ &npcm->gpio_bank[pin / NPCM7XX_GPIO_PER_BANK];
+ int gpio = (pin % bank->gc.ngpio);
+ unsigned long pinmask = BIT(gpio);
+ u32 ie, oe, pu, pd;
+ int rc = 0;
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ case PIN_CONFIG_BIAS_PULL_UP:
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ pu = ioread32(bank->base + NPCM7XX_GP_N_PU) & pinmask;
+ pd = ioread32(bank->base + NPCM7XX_GP_N_PD) & pinmask;
+ if (param == PIN_CONFIG_BIAS_DISABLE)
+ rc = (!pu && !pd);
+ else if (param == PIN_CONFIG_BIAS_PULL_UP)
+ rc = (pu && !pd);
+ else if (param == PIN_CONFIG_BIAS_PULL_DOWN)
+ rc = (!pu && pd);
+ break;
+ case PIN_CONFIG_OUTPUT:
+ case PIN_CONFIG_INPUT_ENABLE:
+ ie = ioread32(bank->base + NPCM7XX_GP_N_IEM) & pinmask;
+ oe = ioread32(bank->base + NPCM7XX_GP_N_OE) & pinmask;
+ if (param == PIN_CONFIG_INPUT_ENABLE)
+ rc = (ie && !oe);
+ else if (param == PIN_CONFIG_OUTPUT)
+ rc = (!ie && oe);
+ break;
+ case PIN_CONFIG_DRIVE_PUSH_PULL:
+ rc = !(ioread32(bank->base + NPCM7XX_GP_N_OTYP) & pinmask);
+ break;
+ case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+ rc = ioread32(bank->base + NPCM7XX_GP_N_OTYP) & pinmask;
+ break;
+ case PIN_CONFIG_INPUT_DEBOUNCE:
+ rc = ioread32(bank->base + NPCM7XX_GP_N_DBNC) & pinmask;
+ break;
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ rc = npcm7xx_get_drive_strength(pctldev, pin);
+ if (rc)
+ *config = pinconf_to_config_packed(param, rc);
+ break;
+ case PIN_CONFIG_SLEW_RATE:
+ rc = npcm7xx_get_slew_rate(bank, npcm->gcr_regmap, pin);
+ if (rc >= 0)
+ *config = pinconf_to_config_packed(param, rc);
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ if (!rc)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int npcm7xx_config_set_one(struct npcm7xx_pinctrl *npcm,
+ unsigned int pin, unsigned long config)
+{
+ enum pin_config_param param = pinconf_to_config_param(config);
+ u16 arg = pinconf_to_config_argument(config);
+ struct npcm7xx_gpio *bank =
+ &npcm->gpio_bank[pin / NPCM7XX_GPIO_PER_BANK];
+ int gpio = BIT(pin % bank->gc.ngpio);
+
+ dev_dbg(bank->gc.parent, "param=%d %d[GPIO]\n", param, pin);
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_PU, gpio);
+ npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_PD, gpio);
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_PU, gpio);
+ npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_PD, gpio);
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_PD, gpio);
+ npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_PU, gpio);
+ break;
+ case PIN_CONFIG_INPUT_ENABLE:
+ if (arg) {
+ iowrite32(gpio, bank->base + NPCM7XX_GP_N_OEC);
+ npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_IEM,
+ gpio);
+ } else
+ npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_IEM,
+ gpio);
+ break;
+ case PIN_CONFIG_OUTPUT:
+ npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_IEM, gpio);
+ iowrite32(gpio, arg ? bank->base + NPCM7XX_GP_N_DOS :
+ bank->base + NPCM7XX_GP_N_DOC);
+ iowrite32(gpio, bank->base + NPCM7XX_GP_N_OES);
+ break;
+ case PIN_CONFIG_DRIVE_PUSH_PULL:
+ npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_OTYP, gpio);
+ break;
+ case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+ npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_OTYP, gpio);
+ break;
+ case PIN_CONFIG_INPUT_DEBOUNCE:
+ npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_DBNC, gpio);
+ break;
+ case PIN_CONFIG_SLEW_RATE:
+ return npcm7xx_set_slew_rate(bank, npcm->gcr_regmap, pin, arg);
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ return npcm7xx_set_drive_strength(npcm, pin, arg);
+ default:
+ return -ENOTSUPP;
+ }
+
+ return 0;
+}
+
+/* Set multiple configuration settings for a pin */
+static int npcm7xx_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
+ unsigned long *configs, unsigned int num_configs)
+{
+ struct npcm7xx_pinctrl *npcm = pinctrl_dev_get_drvdata(pctldev);
+ int rc;
+
+ while (num_configs--) {
+ rc = npcm7xx_config_set_one(npcm, pin, *configs++);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
+static struct pinconf_ops npcm7xx_pinconf_ops = {
+ .is_generic = true,
+ .pin_config_get = npcm7xx_config_get,
+ .pin_config_set = npcm7xx_config_set,
+};
+
+/* pinctrl_desc */
+static struct pinctrl_desc npcm7xx_pinctrl_desc = {
+ .name = "npcm7xx-pinctrl",
+ .pins = npcm7xx_pins,
+ .npins = ARRAY_SIZE(npcm7xx_pins),
+ .pctlops = &npcm7xx_pinctrl_ops,
+ .pmxops = &npcm7xx_pinmux_ops,
+ .confops = &npcm7xx_pinconf_ops,
+ .owner = THIS_MODULE,
+};
+
+static int npcm7xx_gpio_of(struct npcm7xx_pinctrl *pctrl)
+{
+ int ret = -ENXIO;
+ struct resource res;
+ int id = 0, irq;
+ struct device_node *np;
+ struct of_phandle_args pinspec;
+
+ for_each_available_child_of_node(pctrl->dev->of_node, np)
+ if (of_find_property(np, "gpio-controller", NULL)) {
+ ret = of_address_to_resource(np, 0, &res);
+ if (ret < 0) {
+ dev_err(pctrl->dev,
+ "Resource fail for GPIO bank %u\n", id);
+ return ret;
+ }
+
+ pctrl->gpio_bank[id].base =
+ ioremap(res.start, resource_size(&res));
+
+ irq = irq_of_parse_and_map(np, 0);
+ if (irq < 0) {
+ dev_err(pctrl->dev,
+ "No IRQ for GPIO bank %u\n", id);
+ ret = irq;
+ return ret;
+ }
+
+ ret = bgpio_init(&pctrl->gpio_bank[id].gc,
+ pctrl->dev, 4,
+ pctrl->gpio_bank[id].base +
+ NPCM7XX_GP_N_DIN,
+ pctrl->gpio_bank[id].base +
+ NPCM7XX_GP_N_DOUT,
+ NULL,
+ NULL,
+ pctrl->gpio_bank[id].base +
+ NPCM7XX_GP_N_IEM,
+ BGPIOF_READ_OUTPUT_REG_SET);
+ if (ret) {
+ dev_err(pctrl->dev, "bgpio_init() failed\n");
+ return ret;
+ }
+
+ ret = of_parse_phandle_with_fixed_args(np,
+ "gpio-ranges", 3,
+ 0, &pinspec);
+ if (ret < 0) {
+ dev_err(pctrl->dev,
+ "gpio-ranges fail for GPIO bank %u\n",
+ id);
+ return ret;
+ }
+
+ pctrl->gpio_bank[id].irq = irq;
+ pctrl->gpio_bank[id].irq_chip = npcmgpio_irqchip;
+ pctrl->gpio_bank[id].gc.parent = pctrl->dev;
+ pctrl->gpio_bank[id].irqbase =
+ id * NPCM7XX_GPIO_PER_BANK;
+ pctrl->gpio_bank[id].pinctrl_id = pinspec.args[0];
+ pctrl->gpio_bank[id].gc.base = pinspec.args[1];
+ pctrl->gpio_bank[id].gc.ngpio = pinspec.args[2];
+ pctrl->gpio_bank[id].gc.owner = THIS_MODULE;
+ pctrl->gpio_bank[id].gc.label =
+ devm_kasprintf(pctrl->dev, GFP_KERNEL, "%pOF",
+ np);
+ pctrl->gpio_bank[id].gc.dbg_show = npcmgpio_dbg_show;
+ pctrl->gpio_bank[id].direction_input =
+ pctrl->gpio_bank[id].gc.direction_input;
+ pctrl->gpio_bank[id].gc.direction_input =
+ npcmgpio_direction_input;
+ pctrl->gpio_bank[id].direction_output =
+ pctrl->gpio_bank[id].gc.direction_output;
+ pctrl->gpio_bank[id].gc.direction_output =
+ npcmgpio_direction_output;
+ pctrl->gpio_bank[id].request =
+ pctrl->gpio_bank[id].gc.request;
+ pctrl->gpio_bank[id].gc.request = npcmgpio_gpio_request;
+ pctrl->gpio_bank[id].gc.free = npcmgpio_gpio_free;
+ pctrl->gpio_bank[id].gc.of_node = np;
+ id++;
+ }
+
+ pctrl->bank_num = id;
+ return ret;
+}
+
+static int npcm7xx_gpio_register(struct npcm7xx_pinctrl *pctrl)
+{
+ int ret, id;
+
+ for (id = 0 ; id < pctrl->bank_num ; id++) {
+ ret = devm_gpiochip_add_data(pctrl->dev,
+ &pctrl->gpio_bank[id].gc,
+ &pctrl->gpio_bank[id]);
+ if (ret) {
+ dev_err(pctrl->dev, "Failed to add GPIO chip %u\n", id);
+ goto err_register;
+ }
+
+ ret = gpiochip_add_pin_range(&pctrl->gpio_bank[id].gc,
+ dev_name(pctrl->dev),
+ pctrl->gpio_bank[id].pinctrl_id,
+ pctrl->gpio_bank[id].gc.base,
+ pctrl->gpio_bank[id].gc.ngpio);
+ if (ret < 0) {
+ dev_err(pctrl->dev, "Failed to add GPIO bank %u\n", id);
+ gpiochip_remove(&pctrl->gpio_bank[id].gc);
+ goto err_register;
+ }
+
+ ret = gpiochip_irqchip_add(&pctrl->gpio_bank[id].gc,
+ &pctrl->gpio_bank[id].irq_chip,
+ 0, handle_level_irq,
+ IRQ_TYPE_NONE);
+ if (ret < 0) {
+ dev_err(pctrl->dev,
+ "Failed to add IRQ chip %u\n", id);
+ gpiochip_remove(&pctrl->gpio_bank[id].gc);
+ goto err_register;
+ }
+
+ gpiochip_set_chained_irqchip(&pctrl->gpio_bank[id].gc,
+ &pctrl->gpio_bank[id].irq_chip,
+ pctrl->gpio_bank[id].irq,
+ npcmgpio_irq_handler);
+ }
+
+ return 0;
+
+err_register:
+ for (; id > 0; id--)
+ gpiochip_remove(&pctrl->gpio_bank[id - 1].gc);
+
+ return ret;
+}
+
+static int npcm7xx_pinctrl_probe(struct platform_device *pdev)
+{
+ struct npcm7xx_pinctrl *pctrl;
+ int ret;
+
+ pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL);
+ if (!pctrl)
+ return -ENOMEM;
+
+ pctrl->dev = &pdev->dev;
+ dev_set_drvdata(&pdev->dev, pctrl);
+
+ pctrl->gcr_regmap =
+ syscon_regmap_lookup_by_compatible("nuvoton,npcm750-gcr");
+ if (IS_ERR(pctrl->gcr_regmap)) {
+ dev_err(pctrl->dev, "didn't find nuvoton,npcm750-gcr\n");
+ return PTR_ERR(pctrl->gcr_regmap);
+ }
+
+ ret = npcm7xx_gpio_of(pctrl);
+ if (ret < 0) {
+ dev_err(pctrl->dev, "Failed to gpio dt-binding %u\n", ret);
+ return ret;
+ }
+
+ pctrl->pctldev = devm_pinctrl_register(&pdev->dev,
+ &npcm7xx_pinctrl_desc, pctrl);
+ if (IS_ERR(pctrl->pctldev)) {
+ dev_err(&pdev->dev, "Failed to register pinctrl device\n");
+ return PTR_ERR(pctrl->pctldev);
+ }
+
+ ret = npcm7xx_gpio_register(pctrl);
+ if (ret < 0) {
+ dev_err(pctrl->dev, "Failed to register gpio %u\n", ret);
+ return ret;
+ }
+
+ pr_info("NPCM7xx Pinctrl driver probed\n");
+ return 0;
+}
+
+static const struct of_device_id npcm7xx_pinctrl_match[] = {
+ { .compatible = "nuvoton,npcm750-pinctrl" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, npcm7xx_pinctrl_match);
+
+static struct platform_driver npcm7xx_pinctrl_driver = {
+ .probe = npcm7xx_pinctrl_probe,
+ .driver = {
+ .name = "npcm7xx-pinctrl",
+ .of_match_table = npcm7xx_pinctrl_match,
+ .suppress_bind_attrs = true,
+ },
+};
+
+static int __init npcm7xx_pinctrl_register(void)
+{
+ return platform_driver_register(&npcm7xx_pinctrl_driver);
+}
+arch_initcall(npcm7xx_pinctrl_register);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("jordan_hargrave@dell.com");
+MODULE_AUTHOR("tomer.maimon@nuvoton.com");
+MODULE_DESCRIPTION("Nuvoton NPCM7XX Pinctrl and GPIO driver");
diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c
index 1425c2874d40..67718b0f978d 100644
--- a/drivers/pinctrl/pinctrl-amd.c
+++ b/drivers/pinctrl/pinctrl-amd.c
@@ -24,7 +24,7 @@
#include <linux/errno.h>
#include <linux/log2.h>
#include <linux/io.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
diff --git a/drivers/pinctrl/pinctrl-as3722.c b/drivers/pinctrl/pinctrl-as3722.c
index 4e9fe7854e8a..13c193156363 100644
--- a/drivers/pinctrl/pinctrl-as3722.c
+++ b/drivers/pinctrl/pinctrl-as3722.c
@@ -21,7 +21,7 @@
*/
#include <linux/delay.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mfd/as3722.h>
diff --git a/drivers/pinctrl/pinctrl-at91-pio4.c b/drivers/pinctrl/pinctrl-at91-pio4.c
index ef7ab208b951..5a850491a5cb 100644
--- a/drivers/pinctrl/pinctrl-at91-pio4.c
+++ b/drivers/pinctrl/pinctrl-at91-pio4.c
@@ -17,8 +17,6 @@
#include <dt-bindings/pinctrl/at91.h>
#include <linux/clk.h>
#include <linux/gpio/driver.h>
-/* FIXME: needed for gpio_to_irq(), get rid of this */
-#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/init.h>
@@ -264,6 +262,13 @@ static struct irq_chip atmel_gpio_irq_chip = {
.irq_set_wake = atmel_gpio_irq_set_wake,
};
+static int atmel_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ struct atmel_pioctrl *atmel_pioctrl = gpiochip_get_data(chip);
+
+ return irq_find_mapping(atmel_pioctrl->irq_domain, offset);
+}
+
static void atmel_gpio_irq_handler(struct irq_desc *desc)
{
unsigned int irq = irq_desc_get_irq(desc);
@@ -297,8 +302,9 @@ static void atmel_gpio_irq_handler(struct irq_desc *desc)
break;
for_each_set_bit(n, &isr, BITS_PER_LONG)
- generic_handle_irq(gpio_to_irq(bank *
- ATMEL_PIO_NPINS_PER_BANK + n));
+ generic_handle_irq(atmel_gpio_to_irq(
+ atmel_pioctrl->gpio_chip,
+ bank * ATMEL_PIO_NPINS_PER_BANK + n));
}
chained_irq_exit(chip, desc);
@@ -360,13 +366,6 @@ static void atmel_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
BIT(pin->line));
}
-static int atmel_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
- struct atmel_pioctrl *atmel_pioctrl = gpiochip_get_data(chip);
-
- return irq_find_mapping(atmel_pioctrl->irq_domain, offset);
-}
-
static struct gpio_chip atmel_gpio_chip = {
.direction_input = atmel_gpio_direction_input,
.get = atmel_gpio_get,
@@ -493,7 +492,6 @@ static int atmel_pctl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
unsigned num_pins, num_configs, reserve;
unsigned long *configs;
struct property *pins;
- bool has_config;
u32 pinfunc;
int ret, i;
@@ -509,9 +507,6 @@ static int atmel_pctl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
return ret;
}
- if (num_configs)
- has_config = true;
-
num_pins = pins->length / sizeof(u32);
if (!num_pins) {
dev_err(pctldev->dev, "no pins found in node %pOF\n", np);
@@ -524,7 +519,7 @@ static int atmel_pctl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
* map for each pin.
*/
reserve = 1;
- if (has_config && num_pins >= 1)
+ if (num_configs)
reserve++;
reserve *= num_pins;
ret = pinctrl_utils_reserve_map(pctldev, map, reserved_maps, num_maps,
@@ -547,7 +542,7 @@ static int atmel_pctl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
pinctrl_utils_add_map_mux(pctldev, map, reserved_maps, num_maps,
group, func);
- if (has_config) {
+ if (num_configs) {
ret = pinctrl_utils_add_map_configs(pctldev, map,
reserved_maps, num_maps, group,
configs, num_configs,
diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
index 50f0ec42c637..3d49bbbcdbc7 100644
--- a/drivers/pinctrl/pinctrl-at91.c
+++ b/drivers/pinctrl/pinctrl-at91.c
@@ -16,7 +16,7 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/io.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/pinctrl/machine.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinctrl.h>
@@ -263,8 +263,8 @@ static int at91_dt_node_to_map(struct pinctrl_dev *pctldev,
*/
grp = at91_pinctrl_find_group_by_name(info, np->name);
if (!grp) {
- dev_err(info->dev, "unable to find group for node %s\n",
- np->name);
+ dev_err(info->dev, "unable to find group for node %pOFn\n",
+ np);
return -EINVAL;
}
@@ -1071,7 +1071,7 @@ static int at91_pinctrl_parse_groups(struct device_node *np,
const __be32 *list;
int i, j;
- dev_dbg(info->dev, "group(%d): %s\n", index, np->name);
+ dev_dbg(info->dev, "group(%d): %pOFn\n", index, np);
/* Initialise group */
grp->name = np->name;
@@ -1122,7 +1122,7 @@ static int at91_pinctrl_parse_functions(struct device_node *np,
static u32 grp_index;
u32 i = 0;
- dev_dbg(info->dev, "parse function(%d): %s\n", index, np->name);
+ dev_dbg(info->dev, "parse function(%d): %pOFn\n", index, np);
func = &info->functions[index];
@@ -1487,7 +1487,7 @@ static int alt_gpio_irq_type(struct irq_data *d, unsigned type)
return 0;
case IRQ_TYPE_NONE:
default:
- pr_warn("AT91: No type for irq %d\n", gpio_to_irq(d->irq));
+ pr_warn("AT91: No type for GPIO irq offset %d\n", d->irq);
return -EINVAL;
}
@@ -1574,16 +1574,6 @@ void at91_pinctrl_gpio_resume(void)
#define gpio_irq_set_wake NULL
#endif /* CONFIG_PM */
-static struct irq_chip gpio_irqchip = {
- .name = "GPIO",
- .irq_ack = gpio_irq_ack,
- .irq_disable = gpio_irq_mask,
- .irq_mask = gpio_irq_mask,
- .irq_unmask = gpio_irq_unmask,
- /* .irq_set_type is set dynamically */
- .irq_set_wake = gpio_irq_set_wake,
-};
-
static void gpio_irq_handler(struct irq_desc *desc)
{
struct irq_chip *chip = irq_desc_get_chip(desc);
@@ -1624,12 +1614,22 @@ static int at91_gpio_of_irq_setup(struct platform_device *pdev,
struct gpio_chip *gpiochip_prev = NULL;
struct at91_gpio_chip *prev = NULL;
struct irq_data *d = irq_get_irq_data(at91_gpio->pioc_virq);
+ struct irq_chip *gpio_irqchip;
int ret, i;
+ gpio_irqchip = devm_kzalloc(&pdev->dev, sizeof(*gpio_irqchip), GFP_KERNEL);
+ if (!gpio_irqchip)
+ return -ENOMEM;
+
at91_gpio->pioc_hwirq = irqd_to_hwirq(d);
- /* Setup proper .irq_set_type function */
- gpio_irqchip.irq_set_type = at91_gpio->ops->irq_type;
+ gpio_irqchip->name = "GPIO";
+ gpio_irqchip->irq_ack = gpio_irq_ack;
+ gpio_irqchip->irq_disable = gpio_irq_mask;
+ gpio_irqchip->irq_mask = gpio_irq_mask;
+ gpio_irqchip->irq_unmask = gpio_irq_unmask;
+ gpio_irqchip->irq_set_wake = gpio_irq_set_wake,
+ gpio_irqchip->irq_set_type = at91_gpio->ops->irq_type;
/* Disable irqs of this PIO controller */
writel_relaxed(~0, at91_gpio->regbase + PIO_IDR);
@@ -1640,7 +1640,7 @@ static int at91_gpio_of_irq_setup(struct platform_device *pdev,
* interrupt.
*/
ret = gpiochip_irqchip_add(&at91_gpio->chip,
- &gpio_irqchip,
+ gpio_irqchip,
0,
handle_edge_irq,
IRQ_TYPE_NONE);
@@ -1658,7 +1658,7 @@ static int at91_gpio_of_irq_setup(struct platform_device *pdev,
if (!gpiochip_prev) {
/* Then register the chain on the parent IRQ */
gpiochip_set_chained_irqchip(&at91_gpio->chip,
- &gpio_irqchip,
+ gpio_irqchip,
at91_gpio->pioc_virq,
gpio_irq_handler);
return 0;
diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c
index 7939b178c6ae..63035181dfde 100644
--- a/drivers/pinctrl/pinctrl-coh901.c
+++ b/drivers/pinctrl/pinctrl-coh901.c
@@ -15,7 +15,7 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/platform_device.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/slab.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/pinconf-generic.h>
diff --git a/drivers/pinctrl/pinctrl-digicolor.c b/drivers/pinctrl/pinctrl-digicolor.c
index 5353b23f775c..b7533726340d 100644
--- a/drivers/pinctrl/pinctrl-digicolor.c
+++ b/drivers/pinctrl/pinctrl-digicolor.c
@@ -20,7 +20,6 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/io.h>
-#include <linux/gpio.h>
#include <linux/gpio/driver.h>
#include <linux/spinlock.h>
#include <linux/pinctrl/machine.h>
diff --git a/drivers/pinctrl/pinctrl-falcon.c b/drivers/pinctrl/pinctrl-falcon.c
index fb73dcbb5ef3..4d032e637f5c 100644
--- a/drivers/pinctrl/pinctrl-falcon.c
+++ b/drivers/pinctrl/pinctrl-falcon.c
@@ -10,7 +10,7 @@
* Copyright (C) 2012 John Crispin <john@phrozen.org>
*/
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/export.h>
diff --git a/drivers/pinctrl/pinctrl-gemini.c b/drivers/pinctrl/pinctrl-gemini.c
index fa7d998e1d5a..f75bf6f16a2e 100644
--- a/drivers/pinctrl/pinctrl-gemini.c
+++ b/drivers/pinctrl/pinctrl-gemini.c
@@ -591,13 +591,16 @@ static const unsigned int tvc_3512_pins[] = {
319, /* TVC_DATA[1] */
301, /* TVC_DATA[2] */
283, /* TVC_DATA[3] */
- 265, /* TVC_CLK */
320, /* TVC_DATA[4] */
302, /* TVC_DATA[5] */
284, /* TVC_DATA[6] */
266, /* TVC_DATA[7] */
};
+static const unsigned int tvc_clk_3512_pins[] = {
+ 265, /* TVC_CLK */
+};
+
/* NAND flash pins */
static const unsigned int nflash_3512_pins[] = {
199, 200, 201, 202, 216, 217, 218, 219, 220, 234, 235, 236, 237, 252,
@@ -629,7 +632,7 @@ static const unsigned int pflash_3512_pins_extended[] = {
/* Serial flash pins CE0, CE1, DI, DO, CK */
static const unsigned int sflash_3512_pins[] = { 230, 231, 232, 233, 211 };
-/* The GPIO0A (0) pin overlap with TVC and extended parallel flash */
+/* The GPIO0A (0) pin overlap with TVC CLK and extended parallel flash */
static const unsigned int gpio0a_3512_pins[] = { 265 };
/* The GPIO0B (1-4) pins overlap with TVC and ICE */
@@ -823,7 +826,13 @@ static const struct gemini_pin_group gemini_3512_pin_groups[] = {
.num_pins = ARRAY_SIZE(tvc_3512_pins),
/* Conflict with character LCD and ICE */
.mask = LCD_PADS_ENABLE,
- .value = TVC_PADS_ENABLE | TVC_CLK_PAD_ENABLE,
+ .value = TVC_PADS_ENABLE,
+ },
+ {
+ .name = "tvcclkgrp",
+ .pins = tvc_clk_3512_pins,
+ .num_pins = ARRAY_SIZE(tvc_clk_3512_pins),
+ .value = TVC_CLK_PAD_ENABLE,
},
/*
* The construction is done such that it is possible to use a serial
@@ -860,8 +869,8 @@ static const struct gemini_pin_group gemini_3512_pin_groups[] = {
.name = "gpio0agrp",
.pins = gpio0a_3512_pins,
.num_pins = ARRAY_SIZE(gpio0a_3512_pins),
- /* Conflict with TVC */
- .mask = TVC_PADS_ENABLE,
+ /* Conflict with TVC CLK */
+ .mask = TVC_CLK_PAD_ENABLE,
},
{
.name = "gpio0bgrp",
@@ -1531,13 +1540,16 @@ static const unsigned int tvc_3516_pins[] = {
311, /* TVC_DATA[1] */
394, /* TVC_DATA[2] */
374, /* TVC_DATA[3] */
- 333, /* TVC_CLK */
354, /* TVC_DATA[4] */
395, /* TVC_DATA[5] */
312, /* TVC_DATA[6] */
334, /* TVC_DATA[7] */
};
+static const unsigned int tvc_clk_3516_pins[] = {
+ 333, /* TVC_CLK */
+};
+
/* NAND flash pins */
static const unsigned int nflash_3516_pins[] = {
243, 260, 261, 224, 280, 262, 281, 264, 300, 263, 282, 301, 320, 283,
@@ -1570,7 +1582,7 @@ static const unsigned int pflash_3516_pins_extended[] = {
static const unsigned int sflash_3516_pins[] = { 296, 338, 295, 359, 339 };
/* The GPIO0A (0-4) pins overlap with TVC and extended parallel flash */
-static const unsigned int gpio0a_3516_pins[] = { 333, 354, 395, 312, 334 };
+static const unsigned int gpio0a_3516_pins[] = { 354, 395, 312, 334 };
/* The GPIO0B (5-7) pins overlap with ICE */
static const unsigned int gpio0b_3516_pins[] = { 375, 396, 376 };
@@ -1602,6 +1614,9 @@ static const unsigned int gpio0j_3516_pins[] = { 359, 339 };
/* The GPIO0K (30,31) pins overlap with NAND flash */
static const unsigned int gpio0k_3516_pins[] = { 275, 298 };
+/* The GPIO0L (0) pins overlap with TVC_CLK */
+static const unsigned int gpio0l_3516_pins[] = { 333 };
+
/* The GPIO1A (0-4) pins that overlap with IDE and parallel flash */
static const unsigned int gpio1a_3516_pins[] = { 221, 200, 222, 201, 220 };
@@ -1761,7 +1776,13 @@ static const struct gemini_pin_group gemini_3516_pin_groups[] = {
.num_pins = ARRAY_SIZE(tvc_3516_pins),
/* Conflict with character LCD */
.mask = LCD_PADS_ENABLE,
- .value = TVC_PADS_ENABLE | TVC_CLK_PAD_ENABLE,
+ .value = TVC_PADS_ENABLE,
+ },
+ {
+ .name = "tvcclkgrp",
+ .pins = tvc_clk_3516_pins,
+ .num_pins = ARRAY_SIZE(tvc_clk_3516_pins),
+ .value = TVC_CLK_PAD_ENABLE,
},
/*
* The construction is done such that it is possible to use a serial
@@ -1873,6 +1894,13 @@ static const struct gemini_pin_group gemini_3516_pin_groups[] = {
.value = PFLASH_PADS_DISABLE | NAND_PADS_DISABLE,
},
{
+ .name = "gpio0lgrp",
+ .pins = gpio0l_3516_pins,
+ .num_pins = ARRAY_SIZE(gpio0l_3516_pins),
+ /* Conflict with TVE CLK */
+ .mask = TVC_CLK_PAD_ENABLE,
+ },
+ {
.name = "gpio1agrp",
.pins = gpio1a_3516_pins,
.num_pins = ARRAY_SIZE(gpio1a_3516_pins),
@@ -2179,12 +2207,13 @@ static int gemini_pmx_set_mux(struct pinctrl_dev *pctldev,
return -ENODEV;
}
- dev_info(pmx->dev,
- "ACTIVATE function \"%s\" with group \"%s\"\n",
- func->name, grp->name);
+ dev_dbg(pmx->dev,
+ "ACTIVATE function \"%s\" with group \"%s\"\n",
+ func->name, grp->name);
regmap_read(pmx->map, GLOBAL_MISC_CTRL, &before);
- regmap_update_bits(pmx->map, GLOBAL_MISC_CTRL, grp->mask,
+ regmap_update_bits(pmx->map, GLOBAL_MISC_CTRL,
+ grp->mask | grp->value,
grp->value);
regmap_read(pmx->map, GLOBAL_MISC_CTRL, &after);
@@ -2211,10 +2240,10 @@ static int gemini_pmx_set_mux(struct pinctrl_dev *pctldev,
"GLOBAL MISC CTRL before: %08x, after %08x, expected %08x\n",
before, after, expected);
} else {
- dev_info(pmx->dev,
- "padgroup %s %s\n",
- gemini_padgroups[i],
- enabled ? "enabled" : "disabled");
+ dev_dbg(pmx->dev,
+ "padgroup %s %s\n",
+ gemini_padgroups[i],
+ enabled ? "enabled" : "disabled");
}
}
@@ -2233,10 +2262,10 @@ static int gemini_pmx_set_mux(struct pinctrl_dev *pctldev,
"GLOBAL MISC CTRL before: %08x, after %08x, expected %08x\n",
before, after, expected);
} else {
- dev_info(pmx->dev,
- "padgroup %s %s\n",
- gemini_padgroups[i],
- enabled ? "enabled" : "disabled");
+ dev_dbg(pmx->dev,
+ "padgroup %s %s\n",
+ gemini_padgroups[i],
+ enabled ? "enabled" : "disabled");
}
}
@@ -2463,9 +2492,9 @@ static int gemini_pinconf_group_set(struct pinctrl_dev *pctldev,
regmap_update_bits(pmx->map, GLOBAL_IODRIVE,
grp->driving_mask,
val);
- dev_info(pmx->dev,
- "set group %s to %d mA drive strength mask %08x val %08x\n",
- grp->name, arg, grp->driving_mask, val);
+ dev_dbg(pmx->dev,
+ "set group %s to %d mA drive strength mask %08x val %08x\n",
+ grp->name, arg, grp->driving_mask, val);
break;
default:
dev_err(pmx->dev, "invalid config param %04x\n", param);
@@ -2556,8 +2585,8 @@ static int gemini_pmx_probe(struct platform_device *pdev)
/* Print initial state */
tmp = val;
for_each_set_bit(i, &tmp, PADS_MAXBIT) {
- dev_info(dev, "pad group %s %s\n", gemini_padgroups[i],
- (val & BIT(i)) ? "enabled" : "disabled");
+ dev_dbg(dev, "pad group %s %s\n", gemini_padgroups[i],
+ (val & BIT(i)) ? "enabled" : "disabled");
}
/* Check if flash pin is set */
diff --git a/drivers/pinctrl/pinctrl-ingenic.c b/drivers/pinctrl/pinctrl-ingenic.c
index 628817c40e3b..db6b48ea5f47 100644
--- a/drivers/pinctrl/pinctrl-ingenic.c
+++ b/drivers/pinctrl/pinctrl-ingenic.c
@@ -7,10 +7,11 @@
*/
#include <linux/compiler.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/of_device.h>
+#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
@@ -24,6 +25,9 @@
#include "pinconf.h"
#include "pinmux.h"
+#define GPIO_PIN 0x00
+#define GPIO_MSK 0x20
+
#define JZ4740_GPIO_DATA 0x10
#define JZ4740_GPIO_PULL_DIS 0x30
#define JZ4740_GPIO_FUNC 0x40
@@ -33,7 +37,6 @@
#define JZ4740_GPIO_FLAG 0x80
#define JZ4770_GPIO_INT 0x10
-#define JZ4770_GPIO_MSK 0x20
#define JZ4770_GPIO_PAT1 0x30
#define JZ4770_GPIO_PAT0 0x40
#define JZ4770_GPIO_FLAG 0x50
@@ -46,6 +49,7 @@
enum jz_version {
ID_JZ4740,
+ ID_JZ4725B,
ID_JZ4770,
ID_JZ4780,
};
@@ -72,6 +76,13 @@ struct ingenic_pinctrl {
const struct ingenic_chip_info *info;
};
+struct ingenic_gpio_chip {
+ struct ingenic_pinctrl *jzpc;
+ struct gpio_chip gc;
+ struct irq_chip irq_chip;
+ unsigned int irq, reg_base;
+};
+
static const u32 jz4740_pull_ups[4] = {
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
};
@@ -205,6 +216,99 @@ static const struct ingenic_chip_info jz4740_chip_info = {
.pull_downs = jz4740_pull_downs,
};
+static int jz4725b_mmc0_1bit_pins[] = { 0x48, 0x49, 0x5c, };
+static int jz4725b_mmc0_4bit_pins[] = { 0x5d, 0x5b, 0x56, };
+static int jz4725b_mmc1_1bit_pins[] = { 0x7a, 0x7b, 0x7c, };
+static int jz4725b_mmc1_4bit_pins[] = { 0x7d, 0x7e, 0x7f, };
+static int jz4725b_uart_data_pins[] = { 0x4c, 0x4d, };
+static int jz4725b_nand_cs1_pins[] = { 0x55, };
+static int jz4725b_nand_cs2_pins[] = { 0x56, };
+static int jz4725b_nand_cs3_pins[] = { 0x57, };
+static int jz4725b_nand_cs4_pins[] = { 0x58, };
+static int jz4725b_nand_cle_ale_pins[] = { 0x48, 0x49 };
+static int jz4725b_nand_fre_fwe_pins[] = { 0x5c, 0x5d };
+static int jz4725b_pwm_pwm0_pins[] = { 0x4a, };
+static int jz4725b_pwm_pwm1_pins[] = { 0x4b, };
+static int jz4725b_pwm_pwm2_pins[] = { 0x4c, };
+static int jz4725b_pwm_pwm3_pins[] = { 0x4d, };
+static int jz4725b_pwm_pwm4_pins[] = { 0x4e, };
+static int jz4725b_pwm_pwm5_pins[] = { 0x4f, };
+
+static int jz4725b_mmc0_1bit_funcs[] = { 1, 1, 1, };
+static int jz4725b_mmc0_4bit_funcs[] = { 1, 0, 1, };
+static int jz4725b_mmc1_1bit_funcs[] = { 0, 0, 0, };
+static int jz4725b_mmc1_4bit_funcs[] = { 0, 0, 0, };
+static int jz4725b_uart_data_funcs[] = { 1, 1, };
+static int jz4725b_nand_cs1_funcs[] = { 0, };
+static int jz4725b_nand_cs2_funcs[] = { 0, };
+static int jz4725b_nand_cs3_funcs[] = { 0, };
+static int jz4725b_nand_cs4_funcs[] = { 0, };
+static int jz4725b_nand_cle_ale_funcs[] = { 0, 0, };
+static int jz4725b_nand_fre_fwe_funcs[] = { 0, 0, };
+static int jz4725b_pwm_pwm0_funcs[] = { 0, };
+static int jz4725b_pwm_pwm1_funcs[] = { 0, };
+static int jz4725b_pwm_pwm2_funcs[] = { 0, };
+static int jz4725b_pwm_pwm3_funcs[] = { 0, };
+static int jz4725b_pwm_pwm4_funcs[] = { 0, };
+static int jz4725b_pwm_pwm5_funcs[] = { 0, };
+
+static const struct group_desc jz4725b_groups[] = {
+ INGENIC_PIN_GROUP("mmc0-1bit", jz4725b_mmc0_1bit),
+ INGENIC_PIN_GROUP("mmc0-4bit", jz4725b_mmc0_4bit),
+ INGENIC_PIN_GROUP("mmc1-1bit", jz4725b_mmc1_1bit),
+ INGENIC_PIN_GROUP("mmc1-4bit", jz4725b_mmc1_4bit),
+ INGENIC_PIN_GROUP("uart-data", jz4725b_uart_data),
+ INGENIC_PIN_GROUP("nand-cs1", jz4725b_nand_cs1),
+ INGENIC_PIN_GROUP("nand-cs2", jz4725b_nand_cs2),
+ INGENIC_PIN_GROUP("nand-cs3", jz4725b_nand_cs3),
+ INGENIC_PIN_GROUP("nand-cs4", jz4725b_nand_cs4),
+ INGENIC_PIN_GROUP("nand-cle-ale", jz4725b_nand_cle_ale),
+ INGENIC_PIN_GROUP("nand-fre-fwe", jz4725b_nand_fre_fwe),
+ INGENIC_PIN_GROUP("pwm0", jz4725b_pwm_pwm0),
+ INGENIC_PIN_GROUP("pwm1", jz4725b_pwm_pwm1),
+ INGENIC_PIN_GROUP("pwm2", jz4725b_pwm_pwm2),
+ INGENIC_PIN_GROUP("pwm3", jz4725b_pwm_pwm3),
+ INGENIC_PIN_GROUP("pwm4", jz4725b_pwm_pwm4),
+ INGENIC_PIN_GROUP("pwm5", jz4725b_pwm_pwm5),
+};
+
+static const char *jz4725b_mmc0_groups[] = { "mmc0-1bit", "mmc0-4bit", };
+static const char *jz4725b_mmc1_groups[] = { "mmc1-1bit", "mmc1-4bit", };
+static const char *jz4725b_uart_groups[] = { "uart-data", };
+static const char *jz4725b_nand_groups[] = {
+ "nand-cs1", "nand-cs2", "nand-cs3", "nand-cs4",
+ "nand-cle-ale", "nand-fre-fwe",
+};
+static const char *jz4725b_pwm0_groups[] = { "pwm0", };
+static const char *jz4725b_pwm1_groups[] = { "pwm1", };
+static const char *jz4725b_pwm2_groups[] = { "pwm2", };
+static const char *jz4725b_pwm3_groups[] = { "pwm3", };
+static const char *jz4725b_pwm4_groups[] = { "pwm4", };
+static const char *jz4725b_pwm5_groups[] = { "pwm5", };
+
+static const struct function_desc jz4725b_functions[] = {
+ { "mmc0", jz4725b_mmc0_groups, ARRAY_SIZE(jz4725b_mmc0_groups), },
+ { "mmc1", jz4725b_mmc1_groups, ARRAY_SIZE(jz4725b_mmc1_groups), },
+ { "uart", jz4725b_uart_groups, ARRAY_SIZE(jz4725b_uart_groups), },
+ { "nand", jz4725b_nand_groups, ARRAY_SIZE(jz4725b_nand_groups), },
+ { "pwm0", jz4725b_pwm0_groups, ARRAY_SIZE(jz4725b_pwm0_groups), },
+ { "pwm1", jz4725b_pwm1_groups, ARRAY_SIZE(jz4725b_pwm1_groups), },
+ { "pwm2", jz4725b_pwm2_groups, ARRAY_SIZE(jz4725b_pwm2_groups), },
+ { "pwm3", jz4725b_pwm3_groups, ARRAY_SIZE(jz4725b_pwm3_groups), },
+ { "pwm4", jz4725b_pwm4_groups, ARRAY_SIZE(jz4725b_pwm4_groups), },
+ { "pwm5", jz4725b_pwm5_groups, ARRAY_SIZE(jz4725b_pwm5_groups), },
+};
+
+static const struct ingenic_chip_info jz4725b_chip_info = {
+ .num_chips = 4,
+ .groups = jz4725b_groups,
+ .num_groups = ARRAY_SIZE(jz4725b_groups),
+ .functions = jz4725b_functions,
+ .num_functions = ARRAY_SIZE(jz4725b_functions),
+ .pull_ups = jz4740_pull_ups,
+ .pull_downs = jz4740_pull_downs,
+};
+
static const u32 jz4770_pull_ups[6] = {
0x3fffffff, 0xfff0030c, 0xffffffff, 0xffff4fff, 0xfffffb7c, 0xffa7f00f,
};
@@ -438,6 +542,235 @@ static const struct ingenic_chip_info jz4770_chip_info = {
.pull_downs = jz4770_pull_downs,
};
+static u32 gpio_ingenic_read_reg(struct ingenic_gpio_chip *jzgc, u8 reg)
+{
+ unsigned int val;
+
+ regmap_read(jzgc->jzpc->map, jzgc->reg_base + reg, &val);
+
+ return (u32) val;
+}
+
+static void gpio_ingenic_set_bit(struct ingenic_gpio_chip *jzgc,
+ u8 reg, u8 offset, bool set)
+{
+ if (set)
+ reg = REG_SET(reg);
+ else
+ reg = REG_CLEAR(reg);
+
+ regmap_write(jzgc->jzpc->map, jzgc->reg_base + reg, BIT(offset));
+}
+
+static inline bool ingenic_gpio_get_value(struct ingenic_gpio_chip *jzgc,
+ u8 offset)
+{
+ unsigned int val = gpio_ingenic_read_reg(jzgc, GPIO_PIN);
+
+ return !!(val & BIT(offset));
+}
+
+static void ingenic_gpio_set_value(struct ingenic_gpio_chip *jzgc,
+ u8 offset, int value)
+{
+ if (jzgc->jzpc->version >= ID_JZ4770)
+ gpio_ingenic_set_bit(jzgc, JZ4770_GPIO_PAT0, offset, !!value);
+ else
+ gpio_ingenic_set_bit(jzgc, JZ4740_GPIO_DATA, offset, !!value);
+}
+
+static void irq_set_type(struct ingenic_gpio_chip *jzgc,
+ u8 offset, unsigned int type)
+{
+ u8 reg1, reg2;
+
+ if (jzgc->jzpc->version >= ID_JZ4770) {
+ reg1 = JZ4770_GPIO_PAT1;
+ reg2 = JZ4770_GPIO_PAT0;
+ } else {
+ reg1 = JZ4740_GPIO_TRIG;
+ reg2 = JZ4740_GPIO_DIR;
+ }
+
+ switch (type) {
+ case IRQ_TYPE_EDGE_RISING:
+ gpio_ingenic_set_bit(jzgc, reg2, offset, true);
+ gpio_ingenic_set_bit(jzgc, reg1, offset, true);
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ gpio_ingenic_set_bit(jzgc, reg2, offset, false);
+ gpio_ingenic_set_bit(jzgc, reg1, offset, true);
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ gpio_ingenic_set_bit(jzgc, reg2, offset, true);
+ gpio_ingenic_set_bit(jzgc, reg1, offset, false);
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ default:
+ gpio_ingenic_set_bit(jzgc, reg2, offset, false);
+ gpio_ingenic_set_bit(jzgc, reg1, offset, false);
+ break;
+ }
+}
+
+static void ingenic_gpio_irq_mask(struct irq_data *irqd)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+ struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+
+ gpio_ingenic_set_bit(jzgc, GPIO_MSK, irqd->hwirq, true);
+}
+
+static void ingenic_gpio_irq_unmask(struct irq_data *irqd)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+ struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+
+ gpio_ingenic_set_bit(jzgc, GPIO_MSK, irqd->hwirq, false);
+}
+
+static void ingenic_gpio_irq_enable(struct irq_data *irqd)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+ struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+ int irq = irqd->hwirq;
+
+ if (jzgc->jzpc->version >= ID_JZ4770)
+ gpio_ingenic_set_bit(jzgc, JZ4770_GPIO_INT, irq, true);
+ else
+ gpio_ingenic_set_bit(jzgc, JZ4740_GPIO_SELECT, irq, true);
+
+ ingenic_gpio_irq_unmask(irqd);
+}
+
+static void ingenic_gpio_irq_disable(struct irq_data *irqd)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+ struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+ int irq = irqd->hwirq;
+
+ ingenic_gpio_irq_mask(irqd);
+
+ if (jzgc->jzpc->version >= ID_JZ4770)
+ gpio_ingenic_set_bit(jzgc, JZ4770_GPIO_INT, irq, false);
+ else
+ gpio_ingenic_set_bit(jzgc, JZ4740_GPIO_SELECT, irq, false);
+}
+
+static void ingenic_gpio_irq_ack(struct irq_data *irqd)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+ struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+ int irq = irqd->hwirq;
+ bool high;
+
+ if (irqd_get_trigger_type(irqd) == IRQ_TYPE_EDGE_BOTH) {
+ /*
+ * Switch to an interrupt for the opposite edge to the one that
+ * triggered the interrupt being ACKed.
+ */
+ high = ingenic_gpio_get_value(jzgc, irq);
+ if (high)
+ irq_set_type(jzgc, irq, IRQ_TYPE_EDGE_FALLING);
+ else
+ irq_set_type(jzgc, irq, IRQ_TYPE_EDGE_RISING);
+ }
+
+ if (jzgc->jzpc->version >= ID_JZ4770)
+ gpio_ingenic_set_bit(jzgc, JZ4770_GPIO_FLAG, irq, false);
+ else
+ gpio_ingenic_set_bit(jzgc, JZ4740_GPIO_DATA, irq, true);
+}
+
+static int ingenic_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+ struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+
+ switch (type) {
+ case IRQ_TYPE_EDGE_BOTH:
+ case IRQ_TYPE_EDGE_RISING:
+ case IRQ_TYPE_EDGE_FALLING:
+ irq_set_handler_locked(irqd, handle_edge_irq);
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ case IRQ_TYPE_LEVEL_LOW:
+ irq_set_handler_locked(irqd, handle_level_irq);
+ break;
+ default:
+ irq_set_handler_locked(irqd, handle_bad_irq);
+ }
+
+ if (type == IRQ_TYPE_EDGE_BOTH) {
+ /*
+ * The hardware does not support interrupts on both edges. The
+ * best we can do is to set up a single-edge interrupt and then
+ * switch to the opposing edge when ACKing the interrupt.
+ */
+ bool high = ingenic_gpio_get_value(jzgc, irqd->hwirq);
+
+ type = high ? IRQ_TYPE_EDGE_FALLING : IRQ_TYPE_EDGE_RISING;
+ }
+
+ irq_set_type(jzgc, irqd->hwirq, type);
+ return 0;
+}
+
+static int ingenic_gpio_irq_set_wake(struct irq_data *irqd, unsigned int on)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+ struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+
+ return irq_set_irq_wake(jzgc->irq, on);
+}
+
+static void ingenic_gpio_irq_handler(struct irq_desc *desc)
+{
+ struct gpio_chip *gc = irq_desc_get_handler_data(desc);
+ struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+ struct irq_chip *irq_chip = irq_data_get_irq_chip(&desc->irq_data);
+ unsigned long flag, i;
+
+ chained_irq_enter(irq_chip, desc);
+
+ if (jzgc->jzpc->version >= ID_JZ4770)
+ flag = gpio_ingenic_read_reg(jzgc, JZ4770_GPIO_FLAG);
+ else
+ flag = gpio_ingenic_read_reg(jzgc, JZ4740_GPIO_FLAG);
+
+ for_each_set_bit(i, &flag, 32)
+ generic_handle_irq(irq_linear_revmap(gc->irq.domain, i));
+ chained_irq_exit(irq_chip, desc);
+}
+
+static void ingenic_gpio_set(struct gpio_chip *gc,
+ unsigned int offset, int value)
+{
+ struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+
+ ingenic_gpio_set_value(jzgc, offset, value);
+}
+
+static int ingenic_gpio_get(struct gpio_chip *gc, unsigned int offset)
+{
+ struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+
+ return (int) ingenic_gpio_get_value(jzgc, offset);
+}
+
+static int ingenic_gpio_direction_input(struct gpio_chip *gc,
+ unsigned int offset)
+{
+ return pinctrl_gpio_direction_input(gc->base + offset);
+}
+
+static int ingenic_gpio_direction_output(struct gpio_chip *gc,
+ unsigned int offset, int value)
+{
+ ingenic_gpio_set(gc, offset, value);
+ return pinctrl_gpio_direction_output(gc->base + offset);
+}
+
static inline void ingenic_config_pin(struct ingenic_pinctrl *jzpc,
unsigned int pin, u8 reg, bool set)
{
@@ -460,6 +793,21 @@ static inline bool ingenic_get_pin_config(struct ingenic_pinctrl *jzpc,
return val & BIT(idx);
}
+static int ingenic_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+ struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+ struct ingenic_pinctrl *jzpc = jzgc->jzpc;
+ unsigned int pin = gc->base + offset;
+
+ if (jzpc->version >= ID_JZ4770)
+ return ingenic_get_pin_config(jzpc, pin, JZ4770_GPIO_PAT1);
+
+ if (ingenic_get_pin_config(jzpc, pin, JZ4740_GPIO_SELECT))
+ return true;
+
+ return !ingenic_get_pin_config(jzpc, pin, JZ4740_GPIO_DIR);
+}
+
static const struct pinctrl_ops ingenic_pctlops = {
.get_groups_count = pinctrl_generic_get_group_count,
.get_group_name = pinctrl_generic_get_group_name,
@@ -479,7 +827,7 @@ static int ingenic_pinmux_set_pin_fn(struct ingenic_pinctrl *jzpc,
if (jzpc->version >= ID_JZ4770) {
ingenic_config_pin(jzpc, pin, JZ4770_GPIO_INT, false);
- ingenic_config_pin(jzpc, pin, JZ4770_GPIO_MSK, false);
+ ingenic_config_pin(jzpc, pin, GPIO_MSK, false);
ingenic_config_pin(jzpc, pin, JZ4770_GPIO_PAT1, func & 0x2);
ingenic_config_pin(jzpc, pin, JZ4770_GPIO_PAT0, func & 0x1);
} else {
@@ -532,7 +880,7 @@ static int ingenic_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
if (jzpc->version >= ID_JZ4770) {
ingenic_config_pin(jzpc, pin, JZ4770_GPIO_INT, false);
- ingenic_config_pin(jzpc, pin, JZ4770_GPIO_MSK, true);
+ ingenic_config_pin(jzpc, pin, GPIO_MSK, true);
ingenic_config_pin(jzpc, pin, JZ4770_GPIO_PAT1, input);
} else {
ingenic_config_pin(jzpc, pin, JZ4740_GPIO_SELECT, false);
@@ -712,12 +1060,95 @@ static const struct regmap_config ingenic_pinctrl_regmap_config = {
static const struct of_device_id ingenic_pinctrl_of_match[] = {
{ .compatible = "ingenic,jz4740-pinctrl", .data = (void *) ID_JZ4740 },
+ { .compatible = "ingenic,jz4725b-pinctrl", .data = (void *)ID_JZ4725B },
{ .compatible = "ingenic,jz4770-pinctrl", .data = (void *) ID_JZ4770 },
{ .compatible = "ingenic,jz4780-pinctrl", .data = (void *) ID_JZ4780 },
{},
};
-static int ingenic_pinctrl_probe(struct platform_device *pdev)
+static const struct of_device_id ingenic_gpio_of_match[] __initconst = {
+ { .compatible = "ingenic,jz4740-gpio", },
+ { .compatible = "ingenic,jz4770-gpio", },
+ { .compatible = "ingenic,jz4780-gpio", },
+ {},
+};
+
+static int __init ingenic_gpio_probe(struct ingenic_pinctrl *jzpc,
+ struct device_node *node)
+{
+ struct ingenic_gpio_chip *jzgc;
+ struct device *dev = jzpc->dev;
+ unsigned int bank;
+ int err;
+
+ err = of_property_read_u32(node, "reg", &bank);
+ if (err) {
+ dev_err(dev, "Cannot read \"reg\" property: %i\n", err);
+ return err;
+ }
+
+ jzgc = devm_kzalloc(dev, sizeof(*jzgc), GFP_KERNEL);
+ if (!jzgc)
+ return -ENOMEM;
+
+ jzgc->jzpc = jzpc;
+ jzgc->reg_base = bank * 0x100;
+
+ jzgc->gc.label = devm_kasprintf(dev, GFP_KERNEL, "GPIO%c", 'A' + bank);
+ if (!jzgc->gc.label)
+ return -ENOMEM;
+
+ /* DO NOT EXPAND THIS: FOR BACKWARD GPIO NUMBERSPACE COMPATIBIBILITY
+ * ONLY: WORK TO TRANSITION CONSUMERS TO USE THE GPIO DESCRIPTOR API IN
+ * <linux/gpio/consumer.h> INSTEAD.
+ */
+ jzgc->gc.base = bank * 32;
+
+ jzgc->gc.ngpio = 32;
+ jzgc->gc.parent = dev;
+ jzgc->gc.of_node = node;
+ jzgc->gc.owner = THIS_MODULE;
+
+ jzgc->gc.set = ingenic_gpio_set;
+ jzgc->gc.get = ingenic_gpio_get;
+ jzgc->gc.direction_input = ingenic_gpio_direction_input;
+ jzgc->gc.direction_output = ingenic_gpio_direction_output;
+ jzgc->gc.get_direction = ingenic_gpio_get_direction;
+
+ if (of_property_read_bool(node, "gpio-ranges")) {
+ jzgc->gc.request = gpiochip_generic_request;
+ jzgc->gc.free = gpiochip_generic_free;
+ }
+
+ err = devm_gpiochip_add_data(dev, &jzgc->gc, jzgc);
+ if (err)
+ return err;
+
+ jzgc->irq = irq_of_parse_and_map(node, 0);
+ if (!jzgc->irq)
+ return -EINVAL;
+
+ jzgc->irq_chip.name = jzgc->gc.label;
+ jzgc->irq_chip.irq_enable = ingenic_gpio_irq_enable;
+ jzgc->irq_chip.irq_disable = ingenic_gpio_irq_disable;
+ jzgc->irq_chip.irq_unmask = ingenic_gpio_irq_unmask;
+ jzgc->irq_chip.irq_mask = ingenic_gpio_irq_mask;
+ jzgc->irq_chip.irq_ack = ingenic_gpio_irq_ack;
+ jzgc->irq_chip.irq_set_type = ingenic_gpio_irq_set_type;
+ jzgc->irq_chip.irq_set_wake = ingenic_gpio_irq_set_wake;
+ jzgc->irq_chip.flags = IRQCHIP_MASK_ON_SUSPEND;
+
+ err = gpiochip_irqchip_add(&jzgc->gc, &jzgc->irq_chip, 0,
+ handle_level_irq, IRQ_TYPE_NONE);
+ if (err)
+ return err;
+
+ gpiochip_set_chained_irqchip(&jzgc->gc, &jzgc->irq_chip,
+ jzgc->irq, ingenic_gpio_irq_handler);
+ return 0;
+}
+
+static int __init ingenic_pinctrl_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct ingenic_pinctrl *jzpc;
@@ -727,6 +1158,7 @@ static int ingenic_pinctrl_probe(struct platform_device *pdev)
const struct of_device_id *of_id = of_match_device(
ingenic_pinctrl_of_match, dev);
const struct ingenic_chip_info *chip_info;
+ struct device_node *node;
unsigned int i;
int err;
@@ -755,6 +1187,8 @@ static int ingenic_pinctrl_probe(struct platform_device *pdev)
if (jzpc->version >= ID_JZ4770)
chip_info = &jz4770_chip_info;
+ else if (jzpc->version >= ID_JZ4725B)
+ chip_info = &jz4725b_chip_info;
else
chip_info = &jz4740_chip_info;
jzpc->info = chip_info;
@@ -815,11 +1249,11 @@ static int ingenic_pinctrl_probe(struct platform_device *pdev)
dev_set_drvdata(dev, jzpc->map);
- if (dev->of_node) {
- err = of_platform_populate(dev->of_node, NULL, NULL, dev);
- if (err) {
- dev_err(dev, "Failed to probe GPIO devices\n");
- return err;
+ for_each_child_of_node(dev->of_node, node) {
+ if (of_match_node(ingenic_gpio_of_match, node)) {
+ err = ingenic_gpio_probe(jzpc, node);
+ if (err)
+ return err;
}
}
@@ -828,6 +1262,7 @@ static int ingenic_pinctrl_probe(struct platform_device *pdev)
static const struct platform_device_id ingenic_pinctrl_ids[] = {
{ "jz4740-pinctrl", ID_JZ4740 },
+ { "jz4725b-pinctrl", ID_JZ4725B },
{ "jz4770-pinctrl", ID_JZ4770 },
{ "jz4780-pinctrl", ID_JZ4780 },
{},
@@ -837,14 +1272,13 @@ static struct platform_driver ingenic_pinctrl_driver = {
.driver = {
.name = "pinctrl-ingenic",
.of_match_table = of_match_ptr(ingenic_pinctrl_of_match),
- .suppress_bind_attrs = true,
},
- .probe = ingenic_pinctrl_probe,
.id_table = ingenic_pinctrl_ids,
};
static int __init ingenic_pinctrl_drv_register(void)
{
- return platform_driver_register(&ingenic_pinctrl_driver);
+ return platform_driver_probe(&ingenic_pinctrl_driver,
+ ingenic_pinctrl_probe);
}
-postcore_initcall(ingenic_pinctrl_drv_register);
+subsys_initcall(ingenic_pinctrl_drv_register);
diff --git a/drivers/pinctrl/pinctrl-lantiq.c b/drivers/pinctrl/pinctrl-lantiq.c
index 81632af3a86a..22e80613e269 100644
--- a/drivers/pinctrl/pinctrl-lantiq.c
+++ b/drivers/pinctrl/pinctrl-lantiq.c
@@ -80,14 +80,14 @@ static void ltq_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
int ret, i;
if (!pins && !groups) {
- dev_err(pctldev->dev, "%s defines neither pins nor groups\n",
- np->name);
+ dev_err(pctldev->dev, "%pOFn defines neither pins nor groups\n",
+ np);
return;
}
if (pins && groups) {
- dev_err(pctldev->dev, "%s defines both pins and groups\n",
- np->name);
+ dev_err(pctldev->dev, "%pOFn defines both pins and groups\n",
+ np);
return;
}
diff --git a/drivers/pinctrl/pinctrl-lpc18xx.c b/drivers/pinctrl/pinctrl-lpc18xx.c
index 190f17e4bbda..a14bc5e5fc24 100644
--- a/drivers/pinctrl/pinctrl-lpc18xx.c
+++ b/drivers/pinctrl/pinctrl-lpc18xx.c
@@ -844,8 +844,11 @@ static int lpc18xx_pconf_get_pin(struct pinctrl_dev *pctldev, unsigned param,
*arg = (reg & LPC18XX_SCU_PIN_EHD_MASK) >> LPC18XX_SCU_PIN_EHD_POS;
switch (*arg) {
case 3: *arg += 5;
+ /* fall through */
case 2: *arg += 5;
+ /* fall through */
case 1: *arg += 3;
+ /* fall through */
case 0: *arg += 4;
}
break;
@@ -1060,8 +1063,11 @@ static int lpc18xx_pconf_set_pin(struct pinctrl_dev *pctldev, unsigned param,
switch (param_val) {
case 20: param_val -= 5;
+ /* fall through */
case 14: param_val -= 5;
+ /* fall through */
case 8: param_val -= 3;
+ /* fall through */
case 4: param_val -= 4;
break;
default:
diff --git a/drivers/pinctrl/pinctrl-mcp23s08.c b/drivers/pinctrl/pinctrl-mcp23s08.c
index 4a8a8efadefa..b03481ef99a1 100644
--- a/drivers/pinctrl/pinctrl-mcp23s08.c
+++ b/drivers/pinctrl/pinctrl-mcp23s08.c
@@ -4,7 +4,7 @@
#include <linux/device.h>
#include <linux/mutex.h>
#include <linux/module.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/i2c.h>
#include <linux/spi/spi.h>
#include <linux/spi/mcp23s08.h>
@@ -636,6 +636,14 @@ static int mcp23s08_irq_setup(struct mcp23s08 *mcp)
return err;
}
+ return 0;
+}
+
+static int mcp23s08_irqchip_setup(struct mcp23s08 *mcp)
+{
+ struct gpio_chip *chip = &mcp->chip;
+ int err;
+
err = gpiochip_irqchip_add_nested(chip,
&mcp23s08_irq_chip,
0,
@@ -912,7 +920,7 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
}
if (mcp->irq && mcp->irq_controller) {
- ret = mcp23s08_irq_setup(mcp);
+ ret = mcp23s08_irqchip_setup(mcp);
if (ret)
goto fail;
}
@@ -944,6 +952,9 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
goto fail;
}
+ if (mcp->irq)
+ ret = mcp23s08_irq_setup(mcp);
+
fail:
if (ret < 0)
dev_dbg(dev, "can't setup chip %d, --> %d\n", addr, ret);
diff --git a/drivers/pinctrl/pinctrl-pistachio.c b/drivers/pinctrl/pinctrl-pistachio.c
index 302190d1558d..aa5f949ef219 100644
--- a/drivers/pinctrl/pinctrl-pistachio.c
+++ b/drivers/pinctrl/pinctrl-pistachio.c
@@ -9,7 +9,6 @@
* version 2, as published by the Free Software Foundation.
*/
-#include <linux/gpio.h>
#include <linux/gpio/driver.h>
#include <linux/interrupt.h>
#include <linux/io.h>
diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
index f4a61429e06e..95e4a06de019 100644
--- a/drivers/pinctrl/pinctrl-rockchip.c
+++ b/drivers/pinctrl/pinctrl-rockchip.c
@@ -27,7 +27,7 @@
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/bitops.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/pinctrl/machine.h>
@@ -501,8 +501,8 @@ static int rockchip_dt_node_to_map(struct pinctrl_dev *pctldev,
*/
grp = pinctrl_name_to_group(info, np->name);
if (!grp) {
- dev_err(info->dev, "unable to find group for node %s\n",
- np->name);
+ dev_err(info->dev, "unable to find group for node %pOFn\n",
+ np);
return -EINVAL;
}
@@ -2454,7 +2454,7 @@ static int rockchip_pinctrl_parse_groups(struct device_node *np,
int i, j;
int ret;
- dev_dbg(info->dev, "group(%d): %s\n", index, np->name);
+ dev_dbg(info->dev, "group(%d): %pOFn\n", index, np);
/* Initialise group */
grp->name = np->name;
@@ -2519,7 +2519,7 @@ static int rockchip_pinctrl_parse_functions(struct device_node *np,
static u32 grp_index;
u32 i = 0;
- dev_dbg(info->dev, "parse function(%d): %s\n", index, np->name);
+ dev_dbg(info->dev, "parse function(%d): %pOFn\n", index, np);
func = &info->functions[index];
diff --git a/drivers/pinctrl/pinctrl-rza1.c b/drivers/pinctrl/pinctrl-rza1.c
index f76edf664539..14eb576c04a2 100644
--- a/drivers/pinctrl/pinctrl-rza1.c
+++ b/drivers/pinctrl/pinctrl-rza1.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Combined GPIO and pin controller support for Renesas RZ/A1 (r7s72100) SoC
*
* Copyright (C) 2017 Jacopo Mondi
- *
- * 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.
*/
/*
@@ -930,8 +927,8 @@ static int rza1_parse_pinmux_node(struct rza1_pinctrl *rza1_pctl,
&npin_configs);
if (ret) {
dev_err(rza1_pctl->dev,
- "Unable to parse pin configuration options for %s\n",
- np->name);
+ "Unable to parse pin configuration options for %pOFn\n",
+ np);
return ret;
}
@@ -1226,8 +1223,8 @@ static int rza1_parse_gpiochip(struct rza1_pinctrl *rza1_pctl,
*chip = rza1_gpiochip_template;
chip->base = -1;
- chip->label = devm_kasprintf(rza1_pctl->dev, GFP_KERNEL, "%s",
- np->name);
+ chip->label = devm_kasprintf(rza1_pctl->dev, GFP_KERNEL, "%pOFn",
+ np);
chip->ngpio = of_args.args[2];
chip->of_node = np;
chip->parent = rza1_pctl->dev;
@@ -1287,7 +1284,7 @@ static int rza1_gpio_register(struct rza1_pinctrl *rza1_pctl)
ret = rza1_parse_gpiochip(rza1_pctl, child, &gpio_chips[i],
&gpio_ranges[i]);
if (ret)
- goto gpiochip_remove;
+ return ret;
++i;
}
@@ -1295,12 +1292,6 @@ static int rza1_gpio_register(struct rza1_pinctrl *rza1_pctl)
dev_info(rza1_pctl->dev, "Registered %u gpio controllers\n", i);
return 0;
-
-gpiochip_remove:
- for (; i > 0; i--)
- devm_gpiochip_remove(rza1_pctl->dev, &gpio_chips[i - 1]);
-
- return ret;
}
/**
diff --git a/drivers/pinctrl/pinctrl-rzn1.c b/drivers/pinctrl/pinctrl-rzn1.c
new file mode 100644
index 000000000000..57886dcff53d
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-rzn1.c
@@ -0,0 +1,947 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2014-2018 Renesas Electronics Europe Limited
+ *
+ * Phil Edworthy <phil.edworthy@renesas.com>
+ * Based on a driver originally written by Michel Pollet at Renesas.
+ */
+
+#include <dt-bindings/pinctrl/rzn1-pinctrl.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include "core.h"
+#include "pinconf.h"
+#include "pinctrl-utils.h"
+
+/* Field positions and masks in the pinmux registers */
+#define RZN1_L1_PIN_DRIVE_STRENGTH 10
+#define RZN1_L1_PIN_DRIVE_STRENGTH_4MA 0
+#define RZN1_L1_PIN_DRIVE_STRENGTH_6MA 1
+#define RZN1_L1_PIN_DRIVE_STRENGTH_8MA 2
+#define RZN1_L1_PIN_DRIVE_STRENGTH_12MA 3
+#define RZN1_L1_PIN_PULL 8
+#define RZN1_L1_PIN_PULL_NONE 0
+#define RZN1_L1_PIN_PULL_UP 1
+#define RZN1_L1_PIN_PULL_DOWN 3
+#define RZN1_L1_FUNCTION 0
+#define RZN1_L1_FUNC_MASK 0xf
+#define RZN1_L1_FUNCTION_L2 0xf
+
+/*
+ * The hardware manual describes two levels of multiplexing, but it's more
+ * logical to think of the hardware as three levels, with level 3 consisting of
+ * the multiplexing for Ethernet MDIO signals.
+ *
+ * Level 1 functions go from 0 to 9, with level 1 function '15' (0xf) specifying
+ * that level 2 functions are used instead. Level 2 has a lot more options,
+ * going from 0 to 61. Level 3 allows selection of MDIO functions which can be
+ * floating, or one of seven internal peripherals. Unfortunately, there are two
+ * level 2 functions that can select MDIO, and two MDIO channels so we have four
+ * sets of level 3 functions.
+ *
+ * For this driver, we've compounded the numbers together, so:
+ * 0 to 9 is level 1
+ * 10 to 71 is 10 + level 2 number
+ * 72 to 79 is 72 + MDIO0 source for level 2 MDIO function.
+ * 80 to 87 is 80 + MDIO0 source for level 2 MDIO_E1 function.
+ * 88 to 95 is 88 + MDIO1 source for level 2 MDIO function.
+ * 96 to 103 is 96 + MDIO1 source for level 2 MDIO_E1 function.
+ * Examples:
+ * Function 28 corresponds UART0
+ * Function 73 corresponds to MDIO0 to GMAC0
+ *
+ * There are 170 configurable pins (called PL_GPIO in the datasheet).
+ */
+
+/*
+ * Structure detailing the HW registers on the RZ/N1 devices.
+ * Both the Level 1 mux registers and Level 2 mux registers have the same
+ * structure. The only difference is that Level 2 has additional MDIO registers
+ * at the end.
+ */
+struct rzn1_pinctrl_regs {
+ u32 conf[170];
+ u32 pad0[86];
+ u32 status_protect; /* 0x400 */
+ /* MDIO mux registers, level2 only */
+ u32 l2_mdio[2];
+};
+
+/**
+ * struct rzn1_pmx_func - describes rzn1 pinmux functions
+ * @name: the name of this specific function
+ * @groups: corresponding pin groups
+ * @num_groups: the number of groups
+ */
+struct rzn1_pmx_func {
+ const char *name;
+ const char **groups;
+ unsigned int num_groups;
+};
+
+/**
+ * struct rzn1_pin_group - describes an rzn1 pin group
+ * @name: the name of this specific pin group
+ * @func: the name of the function selected by this group
+ * @npins: the number of pins in this group array, i.e. the number of
+ * elements in .pins so we can iterate over that array
+ * @pins: array of pins. Needed due to pinctrl_ops.get_group_pins()
+ * @pin_ids: array of pin_ids, i.e. the value used to select the mux
+ */
+struct rzn1_pin_group {
+ const char *name;
+ const char *func;
+ unsigned int npins;
+ unsigned int *pins;
+ u8 *pin_ids;
+};
+
+struct rzn1_pinctrl {
+ struct device *dev;
+ struct clk *clk;
+ struct pinctrl_dev *pctl;
+ struct rzn1_pinctrl_regs __iomem *lev1;
+ struct rzn1_pinctrl_regs __iomem *lev2;
+ u32 lev1_protect_phys;
+ u32 lev2_protect_phys;
+ u32 mdio_func[2];
+
+ struct rzn1_pin_group *groups;
+ unsigned int ngroups;
+
+ struct rzn1_pmx_func *functions;
+ unsigned int nfunctions;
+};
+
+#define RZN1_PINS_PROP "pinmux"
+
+#define RZN1_PIN(pin) PINCTRL_PIN(pin, "pl_gpio"#pin)
+
+static const struct pinctrl_pin_desc rzn1_pins[] = {
+ RZN1_PIN(0), RZN1_PIN(1), RZN1_PIN(2), RZN1_PIN(3), RZN1_PIN(4),
+ RZN1_PIN(5), RZN1_PIN(6), RZN1_PIN(7), RZN1_PIN(8), RZN1_PIN(9),
+ RZN1_PIN(10), RZN1_PIN(11), RZN1_PIN(12), RZN1_PIN(13), RZN1_PIN(14),
+ RZN1_PIN(15), RZN1_PIN(16), RZN1_PIN(17), RZN1_PIN(18), RZN1_PIN(19),
+ RZN1_PIN(20), RZN1_PIN(21), RZN1_PIN(22), RZN1_PIN(23), RZN1_PIN(24),
+ RZN1_PIN(25), RZN1_PIN(26), RZN1_PIN(27), RZN1_PIN(28), RZN1_PIN(29),
+ RZN1_PIN(30), RZN1_PIN(31), RZN1_PIN(32), RZN1_PIN(33), RZN1_PIN(34),
+ RZN1_PIN(35), RZN1_PIN(36), RZN1_PIN(37), RZN1_PIN(38), RZN1_PIN(39),
+ RZN1_PIN(40), RZN1_PIN(41), RZN1_PIN(42), RZN1_PIN(43), RZN1_PIN(44),
+ RZN1_PIN(45), RZN1_PIN(46), RZN1_PIN(47), RZN1_PIN(48), RZN1_PIN(49),
+ RZN1_PIN(50), RZN1_PIN(51), RZN1_PIN(52), RZN1_PIN(53), RZN1_PIN(54),
+ RZN1_PIN(55), RZN1_PIN(56), RZN1_PIN(57), RZN1_PIN(58), RZN1_PIN(59),
+ RZN1_PIN(60), RZN1_PIN(61), RZN1_PIN(62), RZN1_PIN(63), RZN1_PIN(64),
+ RZN1_PIN(65), RZN1_PIN(66), RZN1_PIN(67), RZN1_PIN(68), RZN1_PIN(69),
+ RZN1_PIN(70), RZN1_PIN(71), RZN1_PIN(72), RZN1_PIN(73), RZN1_PIN(74),
+ RZN1_PIN(75), RZN1_PIN(76), RZN1_PIN(77), RZN1_PIN(78), RZN1_PIN(79),
+ RZN1_PIN(80), RZN1_PIN(81), RZN1_PIN(82), RZN1_PIN(83), RZN1_PIN(84),
+ RZN1_PIN(85), RZN1_PIN(86), RZN1_PIN(87), RZN1_PIN(88), RZN1_PIN(89),
+ RZN1_PIN(90), RZN1_PIN(91), RZN1_PIN(92), RZN1_PIN(93), RZN1_PIN(94),
+ RZN1_PIN(95), RZN1_PIN(96), RZN1_PIN(97), RZN1_PIN(98), RZN1_PIN(99),
+ RZN1_PIN(100), RZN1_PIN(101), RZN1_PIN(102), RZN1_PIN(103),
+ RZN1_PIN(104), RZN1_PIN(105), RZN1_PIN(106), RZN1_PIN(107),
+ RZN1_PIN(108), RZN1_PIN(109), RZN1_PIN(110), RZN1_PIN(111),
+ RZN1_PIN(112), RZN1_PIN(113), RZN1_PIN(114), RZN1_PIN(115),
+ RZN1_PIN(116), RZN1_PIN(117), RZN1_PIN(118), RZN1_PIN(119),
+ RZN1_PIN(120), RZN1_PIN(121), RZN1_PIN(122), RZN1_PIN(123),
+ RZN1_PIN(124), RZN1_PIN(125), RZN1_PIN(126), RZN1_PIN(127),
+ RZN1_PIN(128), RZN1_PIN(129), RZN1_PIN(130), RZN1_PIN(131),
+ RZN1_PIN(132), RZN1_PIN(133), RZN1_PIN(134), RZN1_PIN(135),
+ RZN1_PIN(136), RZN1_PIN(137), RZN1_PIN(138), RZN1_PIN(139),
+ RZN1_PIN(140), RZN1_PIN(141), RZN1_PIN(142), RZN1_PIN(143),
+ RZN1_PIN(144), RZN1_PIN(145), RZN1_PIN(146), RZN1_PIN(147),
+ RZN1_PIN(148), RZN1_PIN(149), RZN1_PIN(150), RZN1_PIN(151),
+ RZN1_PIN(152), RZN1_PIN(153), RZN1_PIN(154), RZN1_PIN(155),
+ RZN1_PIN(156), RZN1_PIN(157), RZN1_PIN(158), RZN1_PIN(159),
+ RZN1_PIN(160), RZN1_PIN(161), RZN1_PIN(162), RZN1_PIN(163),
+ RZN1_PIN(164), RZN1_PIN(165), RZN1_PIN(166), RZN1_PIN(167),
+ RZN1_PIN(168), RZN1_PIN(169),
+};
+
+enum {
+ LOCK_LEVEL1 = 0x1,
+ LOCK_LEVEL2 = 0x2,
+ LOCK_ALL = LOCK_LEVEL1 | LOCK_LEVEL2,
+};
+
+static void rzn1_hw_set_lock(struct rzn1_pinctrl *ipctl, u8 lock, u8 value)
+{
+ /*
+ * The pinmux configuration is locked by writing the physical address of
+ * the status_protect register to itself. It is unlocked by writing the
+ * address | 1.
+ */
+ if (lock & LOCK_LEVEL1) {
+ u32 val = ipctl->lev1_protect_phys | !(value & LOCK_LEVEL1);
+
+ writel(val, &ipctl->lev1->status_protect);
+ }
+
+ if (lock & LOCK_LEVEL2) {
+ u32 val = ipctl->lev2_protect_phys | !(value & LOCK_LEVEL2);
+
+ writel(val, &ipctl->lev2->status_protect);
+ }
+}
+
+static void rzn1_pinctrl_mdio_select(struct rzn1_pinctrl *ipctl, int mdio,
+ u32 func)
+{
+ if (ipctl->mdio_func[mdio] >= 0 && ipctl->mdio_func[mdio] != func)
+ dev_warn(ipctl->dev, "conflicting setting for mdio%d!\n", mdio);
+ ipctl->mdio_func[mdio] = func;
+
+ dev_dbg(ipctl->dev, "setting mdio%d to %u\n", mdio, func);
+
+ writel(func, &ipctl->lev2->l2_mdio[mdio]);
+}
+
+/*
+ * Using a composite pin description, set the hardware pinmux registers
+ * with the corresponding values.
+ * Make sure to unlock write protection and reset it afterward.
+ *
+ * NOTE: There is no protection for potential concurrency, it is assumed these
+ * calls are serialized already.
+ */
+static int rzn1_set_hw_pin_func(struct rzn1_pinctrl *ipctl, unsigned int pin,
+ u32 pin_config, u8 use_locks)
+{
+ u32 l1_cache;
+ u32 l2_cache;
+ u32 l1;
+ u32 l2;
+
+ /* Level 3 MDIO multiplexing */
+ if (pin_config >= RZN1_FUNC_MDIO0_HIGHZ &&
+ pin_config <= RZN1_FUNC_MDIO1_E1_SWITCH) {
+ int mdio_channel;
+ u32 mdio_func;
+
+ if (pin_config <= RZN1_FUNC_MDIO1_HIGHZ)
+ mdio_channel = 0;
+ else
+ mdio_channel = 1;
+
+ /* Get MDIO func, and convert the func to the level 2 number */
+ if (pin_config <= RZN1_FUNC_MDIO0_SWITCH) {
+ mdio_func = pin_config - RZN1_FUNC_MDIO0_HIGHZ;
+ pin_config = RZN1_FUNC_ETH_MDIO;
+ } else if (pin_config <= RZN1_FUNC_MDIO0_E1_SWITCH) {
+ mdio_func = pin_config - RZN1_FUNC_MDIO0_E1_HIGHZ;
+ pin_config = RZN1_FUNC_ETH_MDIO_E1;
+ } else if (pin_config <= RZN1_FUNC_MDIO1_SWITCH) {
+ mdio_func = pin_config - RZN1_FUNC_MDIO1_HIGHZ;
+ pin_config = RZN1_FUNC_ETH_MDIO;
+ } else {
+ mdio_func = pin_config - RZN1_FUNC_MDIO1_E1_HIGHZ;
+ pin_config = RZN1_FUNC_ETH_MDIO_E1;
+ }
+ rzn1_pinctrl_mdio_select(ipctl, mdio_channel, mdio_func);
+ }
+
+ /* Note here, we do not allow anything past the MDIO Mux values */
+ if (pin >= ARRAY_SIZE(ipctl->lev1->conf) ||
+ pin_config >= RZN1_FUNC_MDIO0_HIGHZ)
+ return -EINVAL;
+
+ l1 = readl(&ipctl->lev1->conf[pin]);
+ l1_cache = l1;
+ l2 = readl(&ipctl->lev2->conf[pin]);
+ l2_cache = l2;
+
+ dev_dbg(ipctl->dev, "setting func for pin %u to %u\n", pin, pin_config);
+
+ l1 &= ~(RZN1_L1_FUNC_MASK << RZN1_L1_FUNCTION);
+
+ if (pin_config < RZN1_FUNC_L2_OFFSET) {
+ l1 |= (pin_config << RZN1_L1_FUNCTION);
+ } else {
+ l1 |= (RZN1_L1_FUNCTION_L2 << RZN1_L1_FUNCTION);
+
+ l2 = pin_config - RZN1_FUNC_L2_OFFSET;
+ }
+
+ /* If either configuration changes, we update both anyway */
+ if (l1 != l1_cache || l2 != l2_cache) {
+ writel(l1, &ipctl->lev1->conf[pin]);
+ writel(l2, &ipctl->lev2->conf[pin]);
+ }
+
+ return 0;
+}
+
+static const struct rzn1_pin_group *rzn1_pinctrl_find_group_by_name(
+ const struct rzn1_pinctrl *ipctl, const char *name)
+{
+ unsigned int i;
+
+ for (i = 0; i < ipctl->ngroups; i++) {
+ if (!strcmp(ipctl->groups[i].name, name))
+ return &ipctl->groups[i];
+ }
+
+ return NULL;
+}
+
+static int rzn1_get_groups_count(struct pinctrl_dev *pctldev)
+{
+ struct rzn1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+
+ return ipctl->ngroups;
+}
+
+static const char *rzn1_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned int selector)
+{
+ struct rzn1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+
+ return ipctl->groups[selector].name;
+}
+
+static int rzn1_get_group_pins(struct pinctrl_dev *pctldev,
+ unsigned int selector, const unsigned int **pins,
+ unsigned int *npins)
+{
+ struct rzn1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+
+ if (selector >= ipctl->ngroups)
+ return -EINVAL;
+
+ *pins = ipctl->groups[selector].pins;
+ *npins = ipctl->groups[selector].npins;
+
+ return 0;
+}
+
+/*
+ * This function is called for each pinctl 'Function' node.
+ * Sub-nodes can be used to describe multiple 'Groups' for the 'Function'
+ * If there aren't any sub-nodes, the 'Group' is essentially the 'Function'.
+ * Each 'Group' uses pinmux = <...> to detail the pins and data used to select
+ * the functionality. Each 'Group' has optional pin configurations that apply
+ * to all pins in the 'Group'.
+ */
+static int rzn1_dt_node_to_map_one(struct pinctrl_dev *pctldev,
+ struct device_node *np,
+ struct pinctrl_map **map,
+ unsigned int *num_maps)
+{
+ struct rzn1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+ const struct rzn1_pin_group *grp;
+ unsigned long *configs = NULL;
+ unsigned int reserved_maps = *num_maps;
+ unsigned int num_configs = 0;
+ unsigned int reserve = 1;
+ int ret;
+
+ dev_dbg(ipctl->dev, "processing node %pOF\n", np);
+
+ grp = rzn1_pinctrl_find_group_by_name(ipctl, np->name);
+ if (!grp) {
+ dev_err(ipctl->dev, "unable to find group for node %pOF\n", np);
+
+ return -EINVAL;
+ }
+
+ /* Get the group's pin configuration */
+ ret = pinconf_generic_parse_dt_config(np, pctldev, &configs,
+ &num_configs);
+ if (ret < 0) {
+ dev_err(ipctl->dev, "%pOF: could not parse property\n", np);
+
+ return ret;
+ }
+
+ if (num_configs)
+ reserve++;
+
+ /* Increase the number of maps to cover this group */
+ ret = pinctrl_utils_reserve_map(pctldev, map, &reserved_maps, num_maps,
+ reserve);
+ if (ret < 0)
+ goto out;
+
+ /* Associate the group with the function */
+ ret = pinctrl_utils_add_map_mux(pctldev, map, &reserved_maps, num_maps,
+ grp->name, grp->func);
+ if (ret < 0)
+ goto out;
+
+ if (num_configs) {
+ /* Associate the group's pin configuration with the group */
+ ret = pinctrl_utils_add_map_configs(pctldev, map,
+ &reserved_maps, num_maps, grp->name,
+ configs, num_configs,
+ PIN_MAP_TYPE_CONFIGS_GROUP);
+ if (ret < 0)
+ goto out;
+ }
+
+ dev_dbg(pctldev->dev, "maps: function %s group %s (%d pins)\n",
+ grp->func, grp->name, grp->npins);
+
+out:
+ kfree(configs);
+
+ return ret;
+}
+
+static int rzn1_dt_node_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *np,
+ struct pinctrl_map **map,
+ unsigned int *num_maps)
+{
+ struct device_node *child;
+ int ret;
+
+ *map = NULL;
+ *num_maps = 0;
+
+ ret = rzn1_dt_node_to_map_one(pctldev, np, map, num_maps);
+ if (ret < 0)
+ return ret;
+
+ for_each_child_of_node(np, child) {
+ ret = rzn1_dt_node_to_map_one(pctldev, child, map, num_maps);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct pinctrl_ops rzn1_pctrl_ops = {
+ .get_groups_count = rzn1_get_groups_count,
+ .get_group_name = rzn1_get_group_name,
+ .get_group_pins = rzn1_get_group_pins,
+ .dt_node_to_map = rzn1_dt_node_to_map,
+ .dt_free_map = pinctrl_utils_free_map,
+};
+
+static int rzn1_pmx_get_funcs_count(struct pinctrl_dev *pctldev)
+{
+ struct rzn1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+
+ return ipctl->nfunctions;
+}
+
+static const char *rzn1_pmx_get_func_name(struct pinctrl_dev *pctldev,
+ unsigned int selector)
+{
+ struct rzn1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+
+ return ipctl->functions[selector].name;
+}
+
+static int rzn1_pmx_get_groups(struct pinctrl_dev *pctldev,
+ unsigned int selector,
+ const char * const **groups,
+ unsigned int * const num_groups)
+{
+ struct rzn1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+
+ *groups = ipctl->functions[selector].groups;
+ *num_groups = ipctl->functions[selector].num_groups;
+
+ return 0;
+}
+
+static int rzn1_set_mux(struct pinctrl_dev *pctldev, unsigned int selector,
+ unsigned int group)
+{
+ struct rzn1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+ struct rzn1_pin_group *grp = &ipctl->groups[group];
+ unsigned int i, grp_pins = grp->npins;
+
+ dev_dbg(ipctl->dev, "set mux %s(%d) group %s(%d)\n",
+ ipctl->functions[selector].name, selector, grp->name, group);
+
+ rzn1_hw_set_lock(ipctl, LOCK_ALL, LOCK_ALL);
+ for (i = 0; i < grp_pins; i++)
+ rzn1_set_hw_pin_func(ipctl, grp->pins[i], grp->pin_ids[i], 0);
+ rzn1_hw_set_lock(ipctl, LOCK_ALL, 0);
+
+ return 0;
+}
+
+static const struct pinmux_ops rzn1_pmx_ops = {
+ .get_functions_count = rzn1_pmx_get_funcs_count,
+ .get_function_name = rzn1_pmx_get_func_name,
+ .get_function_groups = rzn1_pmx_get_groups,
+ .set_mux = rzn1_set_mux,
+};
+
+static int rzn1_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin,
+ unsigned long *config)
+{
+ struct rzn1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+ enum pin_config_param param = pinconf_to_config_param(*config);
+ const u32 reg_drive[4] = { 4, 6, 8, 12 };
+ u32 pull, drive, l1mux;
+ u32 l1, l2, arg = 0;
+
+ if (pin >= ARRAY_SIZE(ipctl->lev1->conf))
+ return -EINVAL;
+
+ l1 = readl(&ipctl->lev1->conf[pin]);
+
+ l1mux = l1 & RZN1_L1_FUNC_MASK;
+ pull = (l1 >> RZN1_L1_PIN_PULL) & 0x3;
+ drive = (l1 >> RZN1_L1_PIN_DRIVE_STRENGTH) & 0x3;
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_PULL_UP:
+ if (pull != RZN1_L1_PIN_PULL_UP)
+ return -EINVAL;
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ if (pull != RZN1_L1_PIN_PULL_DOWN)
+ return -EINVAL;
+ break;
+ case PIN_CONFIG_BIAS_DISABLE:
+ if (pull != RZN1_L1_PIN_PULL_NONE)
+ return -EINVAL;
+ break;
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ arg = reg_drive[drive];
+ break;
+ case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
+ l2 = readl(&ipctl->lev2->conf[pin]);
+ if (l1mux == RZN1_L1_FUNCTION_L2) {
+ if (l2 != 0)
+ return -EINVAL;
+ } else if (l1mux != RZN1_FUNC_HIGHZ) {
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ *config = pinconf_to_config_packed(param, arg);
+
+ return 0;
+}
+
+static int rzn1_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
+ unsigned long *configs, unsigned int num_configs)
+{
+ struct rzn1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+ enum pin_config_param param;
+ unsigned int i;
+ u32 l1, l1_cache;
+ u32 drv;
+ u32 arg;
+
+ if (pin >= ARRAY_SIZE(ipctl->lev1->conf))
+ return -EINVAL;
+
+ l1 = readl(&ipctl->lev1->conf[pin]);
+ l1_cache = l1;
+
+ for (i = 0; i < num_configs; i++) {
+ param = pinconf_to_config_param(configs[i]);
+ arg = pinconf_to_config_argument(configs[i]);
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_PULL_UP:
+ dev_dbg(ipctl->dev, "set pin %d pull up\n", pin);
+ l1 &= ~(0x3 << RZN1_L1_PIN_PULL);
+ l1 |= (RZN1_L1_PIN_PULL_UP << RZN1_L1_PIN_PULL);
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ dev_dbg(ipctl->dev, "set pin %d pull down\n", pin);
+ l1 &= ~(0x3 << RZN1_L1_PIN_PULL);
+ l1 |= (RZN1_L1_PIN_PULL_DOWN << RZN1_L1_PIN_PULL);
+ break;
+ case PIN_CONFIG_BIAS_DISABLE:
+ dev_dbg(ipctl->dev, "set pin %d bias off\n", pin);
+ l1 &= ~(0x3 << RZN1_L1_PIN_PULL);
+ l1 |= (RZN1_L1_PIN_PULL_NONE << RZN1_L1_PIN_PULL);
+ break;
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ dev_dbg(ipctl->dev, "set pin %d drv %umA\n", pin, arg);
+ switch (arg) {
+ case 4:
+ drv = RZN1_L1_PIN_DRIVE_STRENGTH_4MA;
+ break;
+ case 6:
+ drv = RZN1_L1_PIN_DRIVE_STRENGTH_6MA;
+ break;
+ case 8:
+ drv = RZN1_L1_PIN_DRIVE_STRENGTH_8MA;
+ break;
+ case 12:
+ drv = RZN1_L1_PIN_DRIVE_STRENGTH_12MA;
+ break;
+ default:
+ dev_err(ipctl->dev,
+ "Drive strength %umA not supported\n",
+ arg);
+
+ return -EINVAL;
+ }
+
+ l1 &= ~(0x3 << RZN1_L1_PIN_DRIVE_STRENGTH);
+ l1 |= (drv << RZN1_L1_PIN_DRIVE_STRENGTH);
+ break;
+
+ case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
+ dev_dbg(ipctl->dev, "set pin %d High-Z\n", pin);
+ l1 &= ~RZN1_L1_FUNC_MASK;
+ l1 |= RZN1_FUNC_HIGHZ;
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+ }
+
+ if (l1 != l1_cache) {
+ rzn1_hw_set_lock(ipctl, LOCK_LEVEL1, LOCK_LEVEL1);
+ writel(l1, &ipctl->lev1->conf[pin]);
+ rzn1_hw_set_lock(ipctl, LOCK_LEVEL1, 0);
+ }
+
+ return 0;
+}
+
+static int rzn1_pinconf_group_get(struct pinctrl_dev *pctldev,
+ unsigned int selector,
+ unsigned long *config)
+{
+ struct rzn1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+ struct rzn1_pin_group *grp = &ipctl->groups[selector];
+ unsigned long old = 0;
+ unsigned int i;
+
+ dev_dbg(ipctl->dev, "group get %s selector:%u\n", grp->name, selector);
+
+ for (i = 0; i < grp->npins; i++) {
+ if (rzn1_pinconf_get(pctldev, grp->pins[i], config))
+ return -ENOTSUPP;
+
+ /* configs do not match between two pins */
+ if (i && (old != *config))
+ return -ENOTSUPP;
+
+ old = *config;
+ }
+
+ return 0;
+}
+
+static int rzn1_pinconf_group_set(struct pinctrl_dev *pctldev,
+ unsigned int selector,
+ unsigned long *configs,
+ unsigned int num_configs)
+{
+ struct rzn1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+ struct rzn1_pin_group *grp = &ipctl->groups[selector];
+ unsigned int i;
+ int ret;
+
+ dev_dbg(ipctl->dev, "group set %s selector:%u configs:%p/%d\n",
+ grp->name, selector, configs, num_configs);
+
+ for (i = 0; i < grp->npins; i++) {
+ unsigned int pin = grp->pins[i];
+
+ ret = rzn1_pinconf_set(pctldev, pin, configs, num_configs);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct pinconf_ops rzn1_pinconf_ops = {
+ .is_generic = true,
+ .pin_config_get = rzn1_pinconf_get,
+ .pin_config_set = rzn1_pinconf_set,
+ .pin_config_group_get = rzn1_pinconf_group_get,
+ .pin_config_group_set = rzn1_pinconf_group_set,
+ .pin_config_config_dbg_show = pinconf_generic_dump_config,
+};
+
+static struct pinctrl_desc rzn1_pinctrl_desc = {
+ .pctlops = &rzn1_pctrl_ops,
+ .pmxops = &rzn1_pmx_ops,
+ .confops = &rzn1_pinconf_ops,
+ .owner = THIS_MODULE,
+};
+
+static int rzn1_pinctrl_parse_groups(struct device_node *np,
+ struct rzn1_pin_group *grp,
+ struct rzn1_pinctrl *ipctl)
+{
+ const __be32 *list;
+ unsigned int i;
+ int size;
+
+ dev_dbg(ipctl->dev, "%s: %s\n", __func__, np->name);
+
+ /* Initialise group */
+ grp->name = np->name;
+
+ /*
+ * The binding format is
+ * pinmux = <PIN_FUNC_ID CONFIG ...>,
+ * do sanity check and calculate pins number
+ */
+ list = of_get_property(np, RZN1_PINS_PROP, &size);
+ if (!list) {
+ dev_err(ipctl->dev,
+ "no " RZN1_PINS_PROP " property in node %pOF\n", np);
+
+ return -EINVAL;
+ }
+
+ if (!size) {
+ dev_err(ipctl->dev, "Invalid " RZN1_PINS_PROP " in node %pOF\n",
+ np);
+
+ return -EINVAL;
+ }
+
+ grp->npins = size / sizeof(list[0]);
+ grp->pin_ids = devm_kmalloc_array(ipctl->dev,
+ grp->npins, sizeof(grp->pin_ids[0]),
+ GFP_KERNEL);
+ grp->pins = devm_kmalloc_array(ipctl->dev,
+ grp->npins, sizeof(grp->pins[0]),
+ GFP_KERNEL);
+ if (!grp->pin_ids || !grp->pins)
+ return -ENOMEM;
+
+ for (i = 0; i < grp->npins; i++) {
+ u32 pin_id = be32_to_cpu(*list++);
+
+ grp->pins[i] = pin_id & 0xff;
+ grp->pin_ids[i] = (pin_id >> 8) & 0x7f;
+ }
+
+ return grp->npins;
+}
+
+static int rzn1_pinctrl_count_function_groups(struct device_node *np)
+{
+ struct device_node *child;
+ int count = 0;
+
+ if (of_property_count_u32_elems(np, RZN1_PINS_PROP) > 0)
+ count++;
+
+ for_each_child_of_node(np, child) {
+ if (of_property_count_u32_elems(child, RZN1_PINS_PROP) > 0)
+ count++;
+ }
+
+ return count;
+}
+
+static int rzn1_pinctrl_parse_functions(struct device_node *np,
+ struct rzn1_pinctrl *ipctl,
+ unsigned int index)
+{
+ struct rzn1_pmx_func *func;
+ struct rzn1_pin_group *grp;
+ struct device_node *child;
+ unsigned int i = 0;
+ int ret;
+
+ func = &ipctl->functions[index];
+
+ /* Initialise function */
+ func->name = np->name;
+ func->num_groups = rzn1_pinctrl_count_function_groups(np);
+ if (func->num_groups == 0) {
+ dev_err(ipctl->dev, "no groups defined in %pOF\n", np);
+ return -EINVAL;
+ }
+ dev_dbg(ipctl->dev, "function %s has %d groups\n",
+ np->name, func->num_groups);
+
+ func->groups = devm_kmalloc_array(ipctl->dev,
+ func->num_groups, sizeof(char *),
+ GFP_KERNEL);
+ if (!func->groups)
+ return -ENOMEM;
+
+ if (of_property_count_u32_elems(np, RZN1_PINS_PROP) > 0) {
+ func->groups[i] = np->name;
+ grp = &ipctl->groups[ipctl->ngroups];
+ grp->func = func->name;
+ ret = rzn1_pinctrl_parse_groups(np, grp, ipctl);
+ if (ret < 0)
+ return ret;
+ i++;
+ ipctl->ngroups++;
+ }
+
+ for_each_child_of_node(np, child) {
+ func->groups[i] = child->name;
+ grp = &ipctl->groups[ipctl->ngroups];
+ grp->func = func->name;
+ ret = rzn1_pinctrl_parse_groups(child, grp, ipctl);
+ if (ret < 0)
+ return ret;
+ i++;
+ ipctl->ngroups++;
+ }
+
+ dev_dbg(ipctl->dev, "function %s parsed %u/%u groups\n",
+ np->name, i, func->num_groups);
+
+ return 0;
+}
+
+static int rzn1_pinctrl_probe_dt(struct platform_device *pdev,
+ struct rzn1_pinctrl *ipctl)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *child;
+ unsigned int maxgroups = 0;
+ unsigned int nfuncs = 0;
+ unsigned int i = 0;
+ int ret;
+
+ nfuncs = of_get_child_count(np);
+ if (nfuncs <= 0)
+ return 0;
+
+ ipctl->nfunctions = nfuncs;
+ ipctl->functions = devm_kmalloc_array(&pdev->dev, nfuncs,
+ sizeof(*ipctl->functions),
+ GFP_KERNEL);
+ if (!ipctl->functions)
+ return -ENOMEM;
+
+ ipctl->ngroups = 0;
+ for_each_child_of_node(np, child)
+ maxgroups += rzn1_pinctrl_count_function_groups(child);
+
+ ipctl->groups = devm_kmalloc_array(&pdev->dev,
+ maxgroups,
+ sizeof(*ipctl->groups),
+ GFP_KERNEL);
+ if (!ipctl->groups)
+ return -ENOMEM;
+
+ for_each_child_of_node(np, child) {
+ ret = rzn1_pinctrl_parse_functions(child, ipctl, i++);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rzn1_pinctrl_probe(struct platform_device *pdev)
+{
+ struct rzn1_pinctrl *ipctl;
+ struct resource *res;
+ int ret;
+
+ /* Create state holders etc for this driver */
+ ipctl = devm_kzalloc(&pdev->dev, sizeof(*ipctl), GFP_KERNEL);
+ if (!ipctl)
+ return -ENOMEM;
+
+ ipctl->mdio_func[0] = -1;
+ ipctl->mdio_func[1] = -1;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ ipctl->lev1_protect_phys = (u32)res->start + 0x400;
+ ipctl->lev1 = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(ipctl->lev1))
+ return PTR_ERR(ipctl->lev1);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ ipctl->lev2_protect_phys = (u32)res->start + 0x400;
+ ipctl->lev2 = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(ipctl->lev2))
+ return PTR_ERR(ipctl->lev2);
+
+ ipctl->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(ipctl->clk))
+ return PTR_ERR(ipctl->clk);
+ ret = clk_prepare_enable(ipctl->clk);
+ if (ret)
+ return ret;
+
+ ipctl->dev = &pdev->dev;
+ rzn1_pinctrl_desc.name = dev_name(&pdev->dev);
+ rzn1_pinctrl_desc.pins = rzn1_pins;
+ rzn1_pinctrl_desc.npins = ARRAY_SIZE(rzn1_pins);
+
+ ret = rzn1_pinctrl_probe_dt(pdev, ipctl);
+ if (ret) {
+ dev_err(&pdev->dev, "fail to probe dt properties\n");
+ goto err_clk;
+ }
+
+ platform_set_drvdata(pdev, ipctl);
+
+ ret = devm_pinctrl_register_and_init(&pdev->dev, &rzn1_pinctrl_desc,
+ ipctl, &ipctl->pctl);
+ if (ret) {
+ dev_err(&pdev->dev, "could not register rzn1 pinctrl driver\n");
+ goto err_clk;
+ }
+
+ ret = pinctrl_enable(ipctl->pctl);
+ if (ret)
+ goto err_clk;
+
+ dev_info(&pdev->dev, "probed\n");
+
+ return 0;
+
+err_clk:
+ clk_disable_unprepare(ipctl->clk);
+
+ return ret;
+}
+
+static int rzn1_pinctrl_remove(struct platform_device *pdev)
+{
+ struct rzn1_pinctrl *ipctl = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(ipctl->clk);
+
+ return 0;
+}
+
+static const struct of_device_id rzn1_pinctrl_match[] = {
+ { .compatible = "renesas,rzn1-pinctrl", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, rzn1_pinctrl_match);
+
+static struct platform_driver rzn1_pinctrl_driver = {
+ .probe = rzn1_pinctrl_probe,
+ .remove = rzn1_pinctrl_remove,
+ .driver = {
+ .name = "rzn1-pinctrl",
+ .of_match_table = rzn1_pinctrl_match,
+ },
+};
+
+static int __init _pinctrl_drv_register(void)
+{
+ return platform_driver_register(&rzn1_pinctrl_driver);
+}
+subsys_initcall(_pinctrl_drv_register);
+
+MODULE_AUTHOR("Phil Edworthy <phil.edworthy@renesas.com>");
+MODULE_DESCRIPTION("Renesas RZ/N1 pinctrl driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index 7ec72ff2419a..1e0614daee9b 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -1022,14 +1022,14 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs,
vals[found].reg = pcs->base + offset;
vals[found].val = pinctrl_spec.args[1];
- dev_dbg(pcs->dev, "%s index: 0x%x value: 0x%x\n",
- pinctrl_spec.np->name, offset, pinctrl_spec.args[1]);
+ dev_dbg(pcs->dev, "%pOFn index: 0x%x value: 0x%x\n",
+ pinctrl_spec.np, offset, pinctrl_spec.args[1]);
pin = pcs_get_pin_by_offset(pcs, offset);
if (pin < 0) {
dev_err(pcs->dev,
- "could not add functions for %s %ux\n",
- np->name, offset);
+ "could not add functions for %pOFn %ux\n",
+ np, offset);
break;
}
pins[found++] = pin;
@@ -1135,8 +1135,8 @@ static int pcs_parse_bits_in_pinctrl_entry(struct pcs_device *pcs,
val = pinctrl_spec.args[1];
mask = pinctrl_spec.args[2];
- dev_dbg(pcs->dev, "%s index: 0x%x value: 0x%x mask: 0x%x\n",
- pinctrl_spec.np->name, offset, val, mask);
+ dev_dbg(pcs->dev, "%pOFn index: 0x%x value: 0x%x mask: 0x%x\n",
+ pinctrl_spec.np, offset, val, mask);
/* Parse pins in each row from LSB */
while (mask) {
@@ -1148,8 +1148,8 @@ static int pcs_parse_bits_in_pinctrl_entry(struct pcs_device *pcs,
if ((mask & mask_pos) == 0) {
dev_err(pcs->dev,
- "Invalid mask for %s at 0x%x\n",
- np->name, offset);
+ "Invalid mask for %pOFn at 0x%x\n",
+ np, offset);
break;
}
@@ -1157,8 +1157,8 @@ static int pcs_parse_bits_in_pinctrl_entry(struct pcs_device *pcs,
if (submask != mask_pos) {
dev_warn(pcs->dev,
- "Invalid submask 0x%x for %s at 0x%x\n",
- submask, np->name, offset);
+ "Invalid submask 0x%x for %pOFn at 0x%x\n",
+ submask, np, offset);
continue;
}
@@ -1169,8 +1169,8 @@ static int pcs_parse_bits_in_pinctrl_entry(struct pcs_device *pcs,
pin = pcs_get_pin_by_offset(pcs, offset);
if (pin < 0) {
dev_err(pcs->dev,
- "could not add functions for %s %ux\n",
- np->name, offset);
+ "could not add functions for %pOFn %ux\n",
+ np, offset);
break;
}
pins[found++] = pin + pin_num_from_lsb;
@@ -1254,16 +1254,16 @@ static int pcs_dt_node_to_map(struct pinctrl_dev *pctldev,
ret = pcs_parse_bits_in_pinctrl_entry(pcs, np_config, map,
num_maps, pgnames);
if (ret < 0) {
- dev_err(pcs->dev, "no pins entries for %s\n",
- np_config->name);
+ dev_err(pcs->dev, "no pins entries for %pOFn\n",
+ np_config);
goto free_pgnames;
}
} else {
ret = pcs_parse_one_pinctrl_entry(pcs, np_config, map,
num_maps, pgnames);
if (ret < 0) {
- dev_err(pcs->dev, "no pins entries for %s\n",
- np_config->name);
+ dev_err(pcs->dev, "no pins entries for %pOFn\n",
+ np_config);
goto free_pgnames;
}
}
diff --git a/drivers/pinctrl/pinctrl-st.c b/drivers/pinctrl/pinctrl-st.c
index 0966bb0bf71f..e66af93f2cbf 100644
--- a/drivers/pinctrl/pinctrl-st.c
+++ b/drivers/pinctrl/pinctrl-st.c
@@ -817,8 +817,8 @@ static int st_pctl_dt_node_to_map(struct pinctrl_dev *pctldev,
grp = st_pctl_find_group_by_name(info, np->name);
if (!grp) {
- dev_err(info->dev, "unable to find group for node %s\n",
- np->name);
+ dev_err(info->dev, "unable to find group for node %pOFn\n",
+ np);
return -EINVAL;
}
@@ -1184,7 +1184,7 @@ static int st_pctl_dt_parse_groups(struct device_node *np,
if (pp->length / sizeof(__be32) >= OF_GPIO_ARGS_MIN) {
npins++;
} else {
- pr_warn("Invalid st,pins in %s node\n", np->name);
+ pr_warn("Invalid st,pins in %pOFn node\n", np);
return -EINVAL;
}
}
diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig
index 195492033075..836e9f3eae4c 100644
--- a/drivers/pinctrl/qcom/Kconfig
+++ b/drivers/pinctrl/qcom/Kconfig
@@ -114,6 +114,14 @@ config PINCTRL_MSM8998
This is the pinctrl, pinmux, pinconf and gpiolib driver for the
Qualcomm TLMM block found in the Qualcomm MSM8998 platform.
+config PINCTRL_QCS404
+ tristate "Qualcomm QCS404 pin controller driver"
+ depends on GPIOLIB && OF
+ select PINCTRL_MSM
+ help
+ This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+ TLMM block found in the Qualcomm QCS404 platform.
+
config PINCTRL_QDF2XXX
tristate "Qualcomm Technologies QDF2xxx pin controller driver"
depends on GPIOLIB && ACPI
@@ -147,6 +155,15 @@ config PINCTRL_QCOM_SSBI_PMIC
which are using SSBI for communication with SoC. Example PMIC's
devices are pm8058 and pm8921.
+config PINCTRL_SDM660
+ tristate "Qualcomm Technologies Inc SDM660 pin controller driver"
+ depends on GPIOLIB && OF
+ select PINCTRL_MSM
+ help
+ This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+ Qualcomm Technologies Inc TLMM block found on the Qualcomm
+ Technologies Inc SDM660 platform.
+
config PINCTRL_SDM845
tristate "Qualcomm Technologies Inc SDM845 pin controller driver"
depends on GPIOLIB && OF
diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile
index 0c6f3ddc296d..344b4c6a6c6e 100644
--- a/drivers/pinctrl/qcom/Makefile
+++ b/drivers/pinctrl/qcom/Makefile
@@ -13,10 +13,12 @@ obj-$(CONFIG_PINCTRL_MSM8916) += pinctrl-msm8916.o
obj-$(CONFIG_PINCTRL_MSM8994) += pinctrl-msm8994.o
obj-$(CONFIG_PINCTRL_MSM8996) += pinctrl-msm8996.o
obj-$(CONFIG_PINCTRL_MSM8998) += pinctrl-msm8998.o
+obj-$(CONFIG_PINCTRL_QCS404) += pinctrl-qcs404.o
obj-$(CONFIG_PINCTRL_QDF2XXX) += pinctrl-qdf2xxx.o
obj-$(CONFIG_PINCTRL_MDM9615) += pinctrl-mdm9615.o
obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-gpio.o
obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-mpp.o
obj-$(CONFIG_PINCTRL_QCOM_SSBI_PMIC) += pinctrl-ssbi-gpio.o
obj-$(CONFIG_PINCTRL_QCOM_SSBI_PMIC) += pinctrl-ssbi-mpp.o
+obj-$(CONFIG_PINCTRL_SDM660) += pinctrl-sdm660.o
obj-$(CONFIG_PINCTRL_SDM845) += pinctrl-sdm845.o
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c
index 5d72ffad32c2..7c7d083e2c0d 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm.c
@@ -24,7 +24,7 @@
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/slab.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/reboot.h>
@@ -37,6 +37,7 @@
#include "../pinctrl-utils.h"
#define MAX_NR_GPIO 300
+#define MAX_NR_TILES 4
#define PS_HOLD_OFFSET 0x820
/**
@@ -52,7 +53,7 @@
* @dual_edge_irqs: Bitmap of irqs that need sw emulated dual edge
* detection.
* @soc; Reference to soc_data of platform specific data.
- * @regs: Base address for the TLMM register map.
+ * @regs: Base addresses for the TLMM tiles.
*/
struct msm_pinctrl {
struct device *dev;
@@ -70,9 +71,27 @@ struct msm_pinctrl {
DECLARE_BITMAP(enabled_irqs, MAX_NR_GPIO);
const struct msm_pinctrl_soc_data *soc;
- void __iomem *regs;
+ void __iomem *regs[MAX_NR_TILES];
};
+#define MSM_ACCESSOR(name) \
+static u32 msm_readl_##name(struct msm_pinctrl *pctrl, \
+ const struct msm_pingroup *g) \
+{ \
+ return readl(pctrl->regs[g->tile] + g->name##_reg); \
+} \
+static void msm_writel_##name(u32 val, struct msm_pinctrl *pctrl, \
+ const struct msm_pingroup *g) \
+{ \
+ writel(val, pctrl->regs[g->tile] + g->name##_reg); \
+}
+
+MSM_ACCESSOR(ctl)
+MSM_ACCESSOR(io)
+MSM_ACCESSOR(intr_cfg)
+MSM_ACCESSOR(intr_status)
+MSM_ACCESSOR(intr_target)
+
static int msm_get_groups_count(struct pinctrl_dev *pctldev)
{
struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
@@ -166,21 +185,37 @@ static int msm_pinmux_set_mux(struct pinctrl_dev *pctldev,
raw_spin_lock_irqsave(&pctrl->lock, flags);
- val = readl(pctrl->regs + g->ctl_reg);
+ val = msm_readl_ctl(pctrl, g);
val &= ~mask;
val |= i << g->mux_bit;
- writel(val, pctrl->regs + g->ctl_reg);
+ msm_writel_ctl(val, pctrl, g);
raw_spin_unlock_irqrestore(&pctrl->lock, flags);
return 0;
}
+static int msm_pinmux_request_gpio(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned offset)
+{
+ struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ const struct msm_pingroup *g = &pctrl->soc->groups[offset];
+
+ /* No funcs? Probably ACPI so can't do anything here */
+ if (!g->nfuncs)
+ return 0;
+
+ /* For now assume function 0 is GPIO because it always is */
+ return msm_pinmux_set_mux(pctldev, g->funcs[0], offset);
+}
+
static const struct pinmux_ops msm_pinmux_ops = {
.request = msm_pinmux_request,
.get_functions_count = msm_get_functions_count,
.get_function_name = msm_get_function_name,
.get_function_groups = msm_get_function_groups,
+ .gpio_request_enable = msm_pinmux_request_gpio,
.set_mux = msm_pinmux_set_mux,
};
@@ -244,7 +279,7 @@ static int msm_config_group_get(struct pinctrl_dev *pctldev,
if (ret < 0)
return ret;
- val = readl(pctrl->regs + g->ctl_reg);
+ val = msm_readl_ctl(pctrl, g);
arg = (val >> bit) & mask;
/* Convert register value to pinconf value */
@@ -283,7 +318,7 @@ static int msm_config_group_get(struct pinctrl_dev *pctldev,
if (!arg)
return -EINVAL;
- val = readl(pctrl->regs + g->io_reg);
+ val = msm_readl_io(pctrl, g);
arg = !!(val & BIT(g->in_bit));
break;
case PIN_CONFIG_INPUT_ENABLE:
@@ -357,12 +392,12 @@ static int msm_config_group_set(struct pinctrl_dev *pctldev,
case PIN_CONFIG_OUTPUT:
/* set output value */
raw_spin_lock_irqsave(&pctrl->lock, flags);
- val = readl(pctrl->regs + g->io_reg);
+ val = msm_readl_io(pctrl, g);
if (arg)
val |= BIT(g->out_bit);
else
val &= ~BIT(g->out_bit);
- writel(val, pctrl->regs + g->io_reg);
+ msm_writel_io(val, pctrl, g);
raw_spin_unlock_irqrestore(&pctrl->lock, flags);
/* enable output */
@@ -385,10 +420,10 @@ static int msm_config_group_set(struct pinctrl_dev *pctldev,
}
raw_spin_lock_irqsave(&pctrl->lock, flags);
- val = readl(pctrl->regs + g->ctl_reg);
+ val = msm_readl_ctl(pctrl, g);
val &= ~(mask << bit);
val |= arg << bit;
- writel(val, pctrl->regs + g->ctl_reg);
+ msm_writel_ctl(val, pctrl, g);
raw_spin_unlock_irqrestore(&pctrl->lock, flags);
}
@@ -412,9 +447,9 @@ static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
raw_spin_lock_irqsave(&pctrl->lock, flags);
- val = readl(pctrl->regs + g->ctl_reg);
+ val = msm_readl_ctl(pctrl, g);
val &= ~BIT(g->oe_bit);
- writel(val, pctrl->regs + g->ctl_reg);
+ msm_writel_ctl(val, pctrl, g);
raw_spin_unlock_irqrestore(&pctrl->lock, flags);
@@ -432,16 +467,16 @@ static int msm_gpio_direction_output(struct gpio_chip *chip, unsigned offset, in
raw_spin_lock_irqsave(&pctrl->lock, flags);
- val = readl(pctrl->regs + g->io_reg);
+ val = msm_readl_io(pctrl, g);
if (value)
val |= BIT(g->out_bit);
else
val &= ~BIT(g->out_bit);
- writel(val, pctrl->regs + g->io_reg);
+ msm_writel_io(val, pctrl, g);
- val = readl(pctrl->regs + g->ctl_reg);
+ val = msm_readl_ctl(pctrl, g);
val |= BIT(g->oe_bit);
- writel(val, pctrl->regs + g->ctl_reg);
+ msm_writel_ctl(val, pctrl, g);
raw_spin_unlock_irqrestore(&pctrl->lock, flags);
@@ -456,7 +491,7 @@ static int msm_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
g = &pctrl->soc->groups[offset];
- val = readl(pctrl->regs + g->ctl_reg);
+ val = msm_readl_ctl(pctrl, g);
/* 0 = output, 1 = input */
return val & BIT(g->oe_bit) ? 0 : 1;
@@ -470,7 +505,7 @@ static int msm_gpio_get(struct gpio_chip *chip, unsigned offset)
g = &pctrl->soc->groups[offset];
- val = readl(pctrl->regs + g->io_reg);
+ val = msm_readl_io(pctrl, g);
return !!(val & BIT(g->in_bit));
}
@@ -485,12 +520,12 @@ static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
raw_spin_lock_irqsave(&pctrl->lock, flags);
- val = readl(pctrl->regs + g->io_reg);
+ val = msm_readl_io(pctrl, g);
if (value)
val |= BIT(g->out_bit);
else
val &= ~BIT(g->out_bit);
- writel(val, pctrl->regs + g->io_reg);
+ msm_writel_io(val, pctrl, g);
raw_spin_unlock_irqrestore(&pctrl->lock, flags);
}
@@ -530,8 +565,8 @@ static void msm_gpio_dbg_show_one(struct seq_file *s,
return;
g = &pctrl->soc->groups[offset];
- ctl_reg = readl(pctrl->regs + g->ctl_reg);
- io_reg = readl(pctrl->regs + g->io_reg);
+ ctl_reg = msm_readl_ctl(pctrl, g);
+ io_reg = msm_readl_io(pctrl, g);
is_out = !!(ctl_reg & BIT(g->oe_bit));
func = (ctl_reg >> g->mux_bit) & 7;
@@ -566,6 +601,42 @@ static void msm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
#define msm_gpio_dbg_show NULL
#endif
+static int msm_gpio_init_valid_mask(struct gpio_chip *chip)
+{
+ struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
+ int ret;
+ unsigned int len, i;
+ unsigned int max_gpios = pctrl->soc->ngpios;
+ u16 *tmp;
+
+ /* The number of GPIOs in the ACPI tables */
+ len = ret = device_property_read_u16_array(pctrl->dev, "gpios", NULL,
+ 0);
+ if (ret < 0)
+ return 0;
+
+ if (ret > max_gpios)
+ return -EINVAL;
+
+ tmp = kmalloc_array(len, sizeof(*tmp), GFP_KERNEL);
+ if (!tmp)
+ return -ENOMEM;
+
+ ret = device_property_read_u16_array(pctrl->dev, "gpios", tmp, len);
+ if (ret < 0) {
+ dev_err(pctrl->dev, "could not read list of GPIOs\n");
+ goto out;
+ }
+
+ bitmap_zero(chip->valid_mask, max_gpios);
+ for (i = 0; i < len; i++)
+ set_bit(tmp[i], chip->valid_mask);
+
+out:
+ kfree(tmp);
+ return ret;
+}
+
static const struct gpio_chip msm_gpio_template = {
.direction_input = msm_gpio_direction_input,
.direction_output = msm_gpio_direction_output,
@@ -575,6 +646,7 @@ static const struct gpio_chip msm_gpio_template = {
.request = gpiochip_generic_request,
.free = gpiochip_generic_free,
.dbg_show = msm_gpio_dbg_show,
+ .init_valid_mask = msm_gpio_init_valid_mask,
};
/* For dual-edge interrupts in software, since some hardware has no
@@ -606,14 +678,14 @@ static void msm_gpio_update_dual_edge_pos(struct msm_pinctrl *pctrl,
unsigned pol;
do {
- val = readl(pctrl->regs + g->io_reg) & BIT(g->in_bit);
+ val = msm_readl_io(pctrl, g) & BIT(g->in_bit);
- pol = readl(pctrl->regs + g->intr_cfg_reg);
+ pol = msm_readl_intr_cfg(pctrl, g);
pol ^= BIT(g->intr_polarity_bit);
- writel(pol, pctrl->regs + g->intr_cfg_reg);
+ msm_writel_intr_cfg(val, pctrl, g);
- val2 = readl(pctrl->regs + g->io_reg) & BIT(g->in_bit);
- intstat = readl(pctrl->regs + g->intr_status_reg);
+ val2 = msm_readl_io(pctrl, g) & BIT(g->in_bit);
+ intstat = msm_readl_intr_status(pctrl, g);
if (intstat || (val == val2))
return;
} while (loop_limit-- > 0);
@@ -633,7 +705,7 @@ static void msm_gpio_irq_mask(struct irq_data *d)
raw_spin_lock_irqsave(&pctrl->lock, flags);
- val = readl(pctrl->regs + g->intr_cfg_reg);
+ val = msm_readl_intr_cfg(pctrl, g);
/*
* There are two bits that control interrupt forwarding to the CPU. The
* RAW_STATUS_EN bit causes the level or edge sensed on the line to be
@@ -658,7 +730,7 @@ static void msm_gpio_irq_mask(struct irq_data *d)
val &= ~BIT(g->intr_raw_status_bit);
val &= ~BIT(g->intr_enable_bit);
- writel(val, pctrl->regs + g->intr_cfg_reg);
+ msm_writel_intr_cfg(val, pctrl, g);
clear_bit(d->hwirq, pctrl->enabled_irqs);
@@ -677,10 +749,10 @@ static void msm_gpio_irq_unmask(struct irq_data *d)
raw_spin_lock_irqsave(&pctrl->lock, flags);
- val = readl(pctrl->regs + g->intr_cfg_reg);
+ val = msm_readl_intr_cfg(pctrl, g);
val |= BIT(g->intr_raw_status_bit);
val |= BIT(g->intr_enable_bit);
- writel(val, pctrl->regs + g->intr_cfg_reg);
+ msm_writel_intr_cfg(val, pctrl, g);
set_bit(d->hwirq, pctrl->enabled_irqs);
@@ -699,12 +771,12 @@ static void msm_gpio_irq_ack(struct irq_data *d)
raw_spin_lock_irqsave(&pctrl->lock, flags);
- val = readl(pctrl->regs + g->intr_status_reg);
+ val = msm_readl_intr_status(pctrl, g);
if (g->intr_ack_high)
val |= BIT(g->intr_status_bit);
else
val &= ~BIT(g->intr_status_bit);
- writel(val, pctrl->regs + g->intr_status_reg);
+ msm_writel_intr_status(val, pctrl, g);
if (test_bit(d->hwirq, pctrl->dual_edge_irqs))
msm_gpio_update_dual_edge_pos(pctrl, g, d);
@@ -733,17 +805,17 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type)
clear_bit(d->hwirq, pctrl->dual_edge_irqs);
/* Route interrupts to application cpu */
- val = readl(pctrl->regs + g->intr_target_reg);
+ val = msm_readl_intr_target(pctrl, g);
val &= ~(7 << g->intr_target_bit);
val |= g->intr_target_kpss_val << g->intr_target_bit;
- writel(val, pctrl->regs + g->intr_target_reg);
+ msm_writel_intr_target(val, pctrl, g);
/* Update configuration for gpio.
* RAW_STATUS_EN is left on for all gpio irqs. Due to the
* internal circuitry of TLMM, toggling the RAW_STATUS
* could cause the INTR_STATUS to be set for EDGE interrupts.
*/
- val = readl(pctrl->regs + g->intr_cfg_reg);
+ val = msm_readl_intr_cfg(pctrl, g);
val |= BIT(g->intr_raw_status_bit);
if (g->intr_detection_width == 2) {
val &= ~(3 << g->intr_detection_bit);
@@ -791,7 +863,7 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type)
} else {
BUG();
}
- writel(val, pctrl->regs + g->intr_cfg_reg);
+ msm_writel_intr_cfg(val, pctrl, g);
if (test_bit(d->hwirq, pctrl->dual_edge_irqs))
msm_gpio_update_dual_edge_pos(pctrl, g, d);
@@ -821,6 +893,41 @@ static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
return 0;
}
+static int msm_gpio_irq_reqres(struct irq_data *d)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
+ int ret;
+
+ if (!try_module_get(gc->owner))
+ return -ENODEV;
+
+ ret = msm_pinmux_request_gpio(pctrl->pctrl, NULL, d->hwirq);
+ if (ret)
+ goto out;
+ msm_gpio_direction_input(gc, d->hwirq);
+
+ if (gpiochip_lock_as_irq(gc, d->hwirq)) {
+ dev_err(gc->parent,
+ "unable to lock HW IRQ %lu for IRQ\n",
+ d->hwirq);
+ ret = -EINVAL;
+ goto out;
+ }
+ return 0;
+out:
+ module_put(gc->owner);
+ return ret;
+}
+
+static void msm_gpio_irq_relres(struct irq_data *d)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+
+ gpiochip_unlock_as_irq(gc, d->hwirq);
+ module_put(gc->owner);
+}
+
static void msm_gpio_irq_handler(struct irq_desc *desc)
{
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
@@ -840,7 +947,7 @@ static void msm_gpio_irq_handler(struct irq_desc *desc)
*/
for_each_set_bit(i, pctrl->enabled_irqs, pctrl->chip.ngpio) {
g = &pctrl->soc->groups[i];
- val = readl(pctrl->regs + g->intr_status_reg);
+ val = msm_readl_intr_status(pctrl, g);
if (val & BIT(g->intr_status_bit)) {
irq_pin = irq_find_mapping(gc->irq.domain, i);
generic_handle_irq(irq_pin);
@@ -855,41 +962,6 @@ static void msm_gpio_irq_handler(struct irq_desc *desc)
chained_irq_exit(chip, desc);
}
-static int msm_gpio_init_valid_mask(struct gpio_chip *chip,
- struct msm_pinctrl *pctrl)
-{
- int ret;
- unsigned int len, i;
- unsigned int max_gpios = pctrl->soc->ngpios;
- u16 *tmp;
-
- /* The number of GPIOs in the ACPI tables */
- len = ret = device_property_read_u16_array(pctrl->dev, "gpios", NULL, 0);
- if (ret < 0)
- return 0;
-
- if (ret > max_gpios)
- return -EINVAL;
-
- tmp = kmalloc_array(len, sizeof(*tmp), GFP_KERNEL);
- if (!tmp)
- return -ENOMEM;
-
- ret = device_property_read_u16_array(pctrl->dev, "gpios", tmp, len);
- if (ret < 0) {
- dev_err(pctrl->dev, "could not read list of GPIOs\n");
- goto out;
- }
-
- bitmap_zero(chip->valid_mask, max_gpios);
- for (i = 0; i < len; i++)
- set_bit(tmp[i], chip->valid_mask);
-
-out:
- kfree(tmp);
- return ret;
-}
-
static bool msm_gpio_needs_valid_mask(struct msm_pinctrl *pctrl)
{
return device_property_read_u16_array(pctrl->dev, "gpios", NULL, 0) > 0;
@@ -919,6 +991,8 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
pctrl->irq_chip.irq_ack = msm_gpio_irq_ack;
pctrl->irq_chip.irq_set_type = msm_gpio_irq_set_type;
pctrl->irq_chip.irq_set_wake = msm_gpio_irq_set_wake;
+ pctrl->irq_chip.irq_request_resources = msm_gpio_irq_reqres;
+ pctrl->irq_chip.irq_release_resources = msm_gpio_irq_relres;
ret = gpiochip_add_data(&pctrl->chip, pctrl);
if (ret) {
@@ -926,13 +1000,6 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
return ret;
}
- ret = msm_gpio_init_valid_mask(chip, pctrl);
- if (ret) {
- dev_err(pctrl->dev, "Failed to setup irq valid bits\n");
- gpiochip_remove(&pctrl->chip);
- return ret;
- }
-
/*
* For DeviceTree-supported systems, the gpio core checks the
* pinctrl's device node for the "gpio-ranges" property.
@@ -975,7 +1042,7 @@ static int msm_ps_hold_restart(struct notifier_block *nb, unsigned long action,
{
struct msm_pinctrl *pctrl = container_of(nb, struct msm_pinctrl, restart_nb);
- writel(0, pctrl->regs + PS_HOLD_OFFSET);
+ writel(0, pctrl->regs[0] + PS_HOLD_OFFSET);
mdelay(1000);
return NOTIFY_DONE;
}
@@ -1011,6 +1078,7 @@ int msm_pinctrl_probe(struct platform_device *pdev,
struct msm_pinctrl *pctrl;
struct resource *res;
int ret;
+ int i;
pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL);
if (!pctrl)
@@ -1022,10 +1090,20 @@ int msm_pinctrl_probe(struct platform_device *pdev,
raw_spin_lock_init(&pctrl->lock);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- pctrl->regs = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(pctrl->regs))
- return PTR_ERR(pctrl->regs);
+ if (soc_data->tiles) {
+ for (i = 0; i < soc_data->ntiles; i++) {
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ soc_data->tiles[i]);
+ pctrl->regs[i] = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(pctrl->regs[i]))
+ return PTR_ERR(pctrl->regs[i]);
+ }
+ } else {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ pctrl->regs[0] = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(pctrl->regs[0]))
+ return PTR_ERR(pctrl->regs[0]);
+ }
msm_pinctrl_setup_pm_reset(pctrl);
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.h b/drivers/pinctrl/qcom/pinctrl-msm.h
index 9b9feea540ff..29172fdf5882 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.h
+++ b/drivers/pinctrl/qcom/pinctrl-msm.h
@@ -76,6 +76,8 @@ struct msm_pingroup {
u32 intr_status_reg;
u32 intr_target_reg;
+ unsigned int tile:2;
+
unsigned mux_bit:5;
unsigned pull_bit:5;
@@ -117,6 +119,8 @@ struct msm_pinctrl_soc_data {
unsigned ngroups;
unsigned ngpios;
bool pull_no_keeper;
+ const char *const *tiles;
+ unsigned int ntiles;
};
int msm_pinctrl_probe(struct platform_device *pdev,
diff --git a/drivers/pinctrl/qcom/pinctrl-qcs404.c b/drivers/pinctrl/qcom/pinctrl-qcs404.c
new file mode 100644
index 000000000000..7aae52a09ff0
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-qcs404.c
@@ -0,0 +1,1697 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-msm.h"
+
+static const char * const qcs404_tiles[] = {
+ "north",
+ "south",
+ "east"
+};
+
+enum {
+ NORTH,
+ SOUTH,
+ EAST
+};
+
+#define FUNCTION(fname) \
+ [msm_mux_##fname] = { \
+ .name = #fname, \
+ .groups = fname##_groups, \
+ .ngroups = ARRAY_SIZE(fname##_groups), \
+ }
+
+#define PINGROUP(id, _tile, f1, f2, f3, f4, f5, f6, f7, f8, f9) \
+ { \
+ .name = "gpio" #id, \
+ .pins = gpio##id##_pins, \
+ .npins = (unsigned int)ARRAY_SIZE(gpio##id##_pins), \
+ .funcs = (int[]){ \
+ msm_mux_gpio, /* gpio mode */ \
+ msm_mux_##f1, \
+ msm_mux_##f2, \
+ msm_mux_##f3, \
+ msm_mux_##f4, \
+ msm_mux_##f5, \
+ msm_mux_##f6, \
+ msm_mux_##f7, \
+ msm_mux_##f8, \
+ msm_mux_##f9 \
+ }, \
+ .nfuncs = 10, \
+ .ctl_reg = 0x1000 * id, \
+ .io_reg = 0x1000 * id + 0x4, \
+ .intr_cfg_reg = 0x1000 * id + 0x8, \
+ .intr_status_reg = 0x1000 * id + 0xc, \
+ .intr_target_reg = 0x1000 * id + 0x8, \
+ .tile = _tile, \
+ .mux_bit = 2, \
+ .pull_bit = 0, \
+ .drv_bit = 6, \
+ .oe_bit = 9, \
+ .in_bit = 0, \
+ .out_bit = 1, \
+ .intr_enable_bit = 0, \
+ .intr_status_bit = 0, \
+ .intr_target_bit = 5, \
+ .intr_target_kpss_val = 4, \
+ .intr_raw_status_bit = 4, \
+ .intr_polarity_bit = 1, \
+ .intr_detection_bit = 2, \
+ .intr_detection_width = 2, \
+ }
+
+#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \
+ { \
+ .name = #pg_name, \
+ .pins = pg_name##_pins, \
+ .npins = (unsigned int)ARRAY_SIZE(pg_name##_pins), \
+ .ctl_reg = ctl, \
+ .io_reg = 0, \
+ .intr_cfg_reg = 0, \
+ .intr_status_reg = 0, \
+ .intr_target_reg = 0, \
+ .tile = NORTH, \
+ .mux_bit = -1, \
+ .pull_bit = pull, \
+ .drv_bit = drv, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = -1, \
+ .intr_enable_bit = -1, \
+ .intr_status_bit = -1, \
+ .intr_target_bit = -1, \
+ .intr_raw_status_bit = -1, \
+ .intr_polarity_bit = -1, \
+ .intr_detection_bit = -1, \
+ .intr_detection_width = -1, \
+ }
+
+#define UFS_RESET(pg_name, offset) \
+ { \
+ .name = #pg_name, \
+ .pins = pg_name##_pins, \
+ .npins = (unsigned int)ARRAY_SIZE(pg_name##_pins), \
+ .ctl_reg = offset, \
+ .io_reg = offset + 0x4, \
+ .intr_cfg_reg = 0, \
+ .intr_status_reg = 0, \
+ .intr_target_reg = 0, \
+ .tile = NORTH, \
+ .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 qcs404_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, "SDC1_RCLK"),
+ PINCTRL_PIN(121, "SDC1_CLK"),
+ PINCTRL_PIN(122, "SDC1_CMD"),
+ PINCTRL_PIN(123, "SDC1_DATA"),
+ PINCTRL_PIN(124, "SDC2_CLK"),
+ PINCTRL_PIN(125, "SDC2_CMD"),
+ PINCTRL_PIN(126, "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);
+
+static const unsigned int sdc1_rclk_pins[] = { 120 };
+static const unsigned int sdc1_clk_pins[] = { 121 };
+static const unsigned int sdc1_cmd_pins[] = { 122 };
+static const unsigned int sdc1_data_pins[] = { 123 };
+static const unsigned int sdc2_clk_pins[] = { 124 };
+static const unsigned int sdc2_cmd_pins[] = { 125 };
+static const unsigned int sdc2_data_pins[] = { 126 };
+
+enum qcs404_functions {
+ msm_mux_gpio,
+ msm_mux_hdmi_tx,
+ msm_mux_hdmi_ddc,
+ msm_mux_blsp_uart_tx_a2,
+ msm_mux_blsp_spi2,
+ msm_mux_m_voc,
+ msm_mux_qdss_cti_trig_in_a0,
+ msm_mux_blsp_uart_rx_a2,
+ msm_mux_qdss_tracectl_a,
+ msm_mux_blsp_uart2,
+ msm_mux_aud_cdc,
+ msm_mux_blsp_i2c_sda_a2,
+ msm_mux_qdss_tracedata_a,
+ msm_mux_blsp_i2c_scl_a2,
+ msm_mux_qdss_tracectl_b,
+ msm_mux_qdss_cti_trig_in_b0,
+ msm_mux_blsp_uart1,
+ msm_mux_blsp_spi_mosi_a1,
+ msm_mux_blsp_spi_miso_a1,
+ msm_mux_qdss_tracedata_b,
+ msm_mux_blsp_i2c1,
+ msm_mux_blsp_spi_cs_n_a1,
+ msm_mux_gcc_plltest,
+ msm_mux_blsp_spi_clk_a1,
+ msm_mux_rgb_data0,
+ msm_mux_blsp_uart5,
+ msm_mux_blsp_spi5,
+ msm_mux_adsp_ext,
+ msm_mux_rgb_data1,
+ msm_mux_prng_rosc,
+ msm_mux_rgb_data2,
+ msm_mux_blsp_i2c5,
+ msm_mux_gcc_gp1_clk_b,
+ msm_mux_rgb_data3,
+ msm_mux_gcc_gp2_clk_b,
+ msm_mux_blsp_spi0,
+ msm_mux_blsp_uart0,
+ msm_mux_gcc_gp3_clk_b,
+ msm_mux_blsp_i2c0,
+ msm_mux_qdss_traceclk_b,
+ msm_mux_pcie_clk,
+ msm_mux_nfc_irq,
+ msm_mux_blsp_spi4,
+ msm_mux_nfc_dwl,
+ msm_mux_audio_ts,
+ msm_mux_rgb_data4,
+ msm_mux_spi_lcd,
+ msm_mux_blsp_uart_tx_b2,
+ msm_mux_gcc_gp3_clk_a,
+ msm_mux_rgb_data5,
+ msm_mux_blsp_uart_rx_b2,
+ msm_mux_blsp_i2c_sda_b2,
+ msm_mux_blsp_i2c_scl_b2,
+ msm_mux_pwm_led11,
+ msm_mux_i2s_3_data0_a,
+ msm_mux_ebi2_lcd,
+ msm_mux_i2s_3_data1_a,
+ msm_mux_i2s_3_data2_a,
+ msm_mux_atest_char,
+ msm_mux_pwm_led3,
+ msm_mux_i2s_3_data3_a,
+ msm_mux_pwm_led4,
+ msm_mux_i2s_4,
+ msm_mux_ebi2_a,
+ msm_mux_dsd_clk_b,
+ msm_mux_pwm_led5,
+ msm_mux_pwm_led6,
+ msm_mux_pwm_led7,
+ msm_mux_pwm_led8,
+ msm_mux_pwm_led24,
+ msm_mux_spkr_dac0,
+ msm_mux_blsp_i2c4,
+ msm_mux_pwm_led9,
+ msm_mux_pwm_led10,
+ msm_mux_spdifrx_opt,
+ msm_mux_pwm_led12,
+ msm_mux_pwm_led13,
+ msm_mux_pwm_led14,
+ msm_mux_wlan1_adc1,
+ msm_mux_rgb_data_b0,
+ msm_mux_pwm_led15,
+ msm_mux_blsp_spi_mosi_b1,
+ msm_mux_wlan1_adc0,
+ msm_mux_rgb_data_b1,
+ msm_mux_pwm_led16,
+ msm_mux_blsp_spi_miso_b1,
+ msm_mux_qdss_cti_trig_out_b0,
+ msm_mux_wlan2_adc1,
+ msm_mux_rgb_data_b2,
+ msm_mux_pwm_led17,
+ msm_mux_blsp_spi_cs_n_b1,
+ msm_mux_wlan2_adc0,
+ msm_mux_rgb_data_b3,
+ msm_mux_pwm_led18,
+ msm_mux_blsp_spi_clk_b1,
+ msm_mux_rgb_data_b4,
+ msm_mux_pwm_led19,
+ msm_mux_ext_mclk1_b,
+ msm_mux_qdss_traceclk_a,
+ msm_mux_rgb_data_b5,
+ msm_mux_pwm_led20,
+ msm_mux_atest_char3,
+ msm_mux_i2s_3_sck_b,
+ msm_mux_ldo_update,
+ msm_mux_bimc_dte0,
+ msm_mux_rgb_hsync,
+ msm_mux_pwm_led21,
+ msm_mux_i2s_3_ws_b,
+ msm_mux_dbg_out,
+ msm_mux_rgb_vsync,
+ msm_mux_i2s_3_data0_b,
+ msm_mux_ldo_en,
+ msm_mux_hdmi_dtest,
+ msm_mux_rgb_de,
+ msm_mux_i2s_3_data1_b,
+ msm_mux_hdmi_lbk9,
+ msm_mux_rgb_clk,
+ msm_mux_atest_char1,
+ msm_mux_i2s_3_data2_b,
+ msm_mux_ebi_cdc,
+ msm_mux_hdmi_lbk8,
+ msm_mux_rgb_mdp,
+ msm_mux_atest_char0,
+ msm_mux_i2s_3_data3_b,
+ msm_mux_hdmi_lbk7,
+ msm_mux_rgb_data_b6,
+ msm_mux_rgb_data_b7,
+ msm_mux_hdmi_lbk6,
+ msm_mux_rgmii_int,
+ msm_mux_cri_trng1,
+ msm_mux_rgmii_wol,
+ msm_mux_cri_trng0,
+ msm_mux_gcc_tlmm,
+ msm_mux_rgmii_ck,
+ msm_mux_rgmii_tx,
+ msm_mux_hdmi_lbk5,
+ msm_mux_hdmi_pixel,
+ msm_mux_hdmi_rcv,
+ msm_mux_hdmi_lbk4,
+ msm_mux_rgmii_ctl,
+ msm_mux_ext_lpass,
+ msm_mux_rgmii_rx,
+ msm_mux_cri_trng,
+ msm_mux_hdmi_lbk3,
+ msm_mux_hdmi_lbk2,
+ msm_mux_qdss_cti_trig_out_b1,
+ msm_mux_rgmii_mdio,
+ msm_mux_hdmi_lbk1,
+ msm_mux_rgmii_mdc,
+ msm_mux_hdmi_lbk0,
+ msm_mux_ir_in,
+ msm_mux_wsa_en,
+ msm_mux_rgb_data6,
+ msm_mux_rgb_data7,
+ msm_mux_atest_char2,
+ msm_mux_ebi_ch0,
+ msm_mux_blsp_uart3,
+ msm_mux_blsp_spi3,
+ msm_mux_sd_write,
+ msm_mux_blsp_i2c3,
+ msm_mux_gcc_gp1_clk_a,
+ msm_mux_qdss_cti_trig_in_b1,
+ msm_mux_gcc_gp2_clk_a,
+ msm_mux_ext_mclk0,
+ msm_mux_mclk_in1,
+ msm_mux_i2s_1,
+ msm_mux_dsd_clk_a,
+ msm_mux_qdss_cti_trig_in_a1,
+ msm_mux_rgmi_dll1,
+ msm_mux_pwm_led22,
+ msm_mux_pwm_led23,
+ msm_mux_qdss_cti_trig_out_a0,
+ msm_mux_rgmi_dll2,
+ msm_mux_pwm_led1,
+ msm_mux_qdss_cti_trig_out_a1,
+ msm_mux_pwm_led2,
+ msm_mux_i2s_2,
+ msm_mux_pll_bist,
+ msm_mux_ext_mclk1_a,
+ msm_mux_mclk_in2,
+ msm_mux_bimc_dte1,
+ msm_mux_i2s_3_sck_a,
+ msm_mux_i2s_3_ws_a,
+ msm_mux__,
+};
+
+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",
+ "gpio21", "gpio21", "gpio22", "gpio22", "gpio23", "gpio23", "gpio24",
+ "gpio25", "gpio26", "gpio27", "gpio28", "gpio29", "gpio30", "gpio31",
+ "gpio32", "gpio33", "gpio34", "gpio35", "gpio36", "gpio36", "gpio36",
+ "gpio36", "gpio37", "gpio37", "gpio37", "gpio38", "gpio38", "gpio38",
+ "gpio39", "gpio39", "gpio40", "gpio40", "gpio41", "gpio41", "gpio41",
+ "gpio42", "gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48",
+ "gpio49", "gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55",
+ "gpio56", "gpio57", "gpio58", "gpio59", "gpio59", "gpio60", "gpio61",
+ "gpio62", "gpio63", "gpio64", "gpio65", "gpio66", "gpio67", "gpio68",
+ "gpio69", "gpio70", "gpio71", "gpio72", "gpio73", "gpio74", "gpio75",
+ "gpio76", "gpio77", "gpio77", "gpio78", "gpio78", "gpio78", "gpio79",
+ "gpio79", "gpio79", "gpio80", "gpio81", "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", "gpio108",
+ "gpio108", "gpio109", "gpio109", "gpio110", "gpio111", "gpio112",
+ "gpio113", "gpio114", "gpio115", "gpio116", "gpio117", "gpio118",
+ "gpio119",
+};
+
+static const char * const hdmi_tx_groups[] = {
+ "gpio14",
+};
+
+static const char * const hdmi_ddc_groups[] = {
+ "gpio15", "gpio16",
+};
+
+static const char * const blsp_uart_tx_a2_groups[] = {
+ "gpio17",
+};
+
+static const char * const blsp_spi2_groups[] = {
+ "gpio17", "gpio18", "gpio19", "gpio20",
+};
+
+static const char * const m_voc_groups[] = {
+ "gpio17", "gpio21",
+};
+
+static const char * const qdss_cti_trig_in_a0_groups[] = {
+ "gpio17",
+};
+
+static const char * const blsp_uart_rx_a2_groups[] = {
+ "gpio18",
+};
+
+static const char * const qdss_tracectl_a_groups[] = {
+ "gpio18",
+};
+
+static const char * const blsp_uart2_groups[] = {
+ "gpio19", "gpio20",
+};
+
+static const char * const aud_cdc_groups[] = {
+ "gpio19", "gpio20",
+};
+
+static const char * const blsp_i2c_sda_a2_groups[] = {
+ "gpio19",
+};
+
+static const char * const qdss_tracedata_a_groups[] = {
+ "gpio19", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28", "gpio30",
+ "gpio31", "gpio32", "gpio36", "gpio38", "gpio39", "gpio42", "gpio43",
+ "gpio82", "gpio83",
+};
+
+static const char * const blsp_i2c_scl_a2_groups[] = {
+ "gpio20",
+};
+
+static const char * const qdss_tracectl_b_groups[] = {
+ "gpio20",
+};
+
+static const char * const qdss_cti_trig_in_b0_groups[] = {
+ "gpio21",
+};
+
+static const char * const blsp_uart1_groups[] = {
+ "gpio22", "gpio23", "gpio24", "gpio25",
+};
+
+static const char * const blsp_spi_mosi_a1_groups[] = {
+ "gpio22",
+};
+
+static const char * const blsp_spi_miso_a1_groups[] = {
+ "gpio23",
+};
+
+static const char * const qdss_tracedata_b_groups[] = {
+ "gpio23", "gpio35", "gpio40", "gpio41", "gpio44", "gpio45", "gpio46",
+ "gpio47", "gpio49", "gpio50", "gpio55", "gpio61", "gpio62", "gpio85",
+ "gpio89", "gpio93",
+};
+
+static const char * const blsp_i2c1_groups[] = {
+ "gpio24", "gpio25",
+};
+
+static const char * const blsp_spi_cs_n_a1_groups[] = {
+ "gpio24",
+};
+
+static const char * const gcc_plltest_groups[] = {
+ "gpio24", "gpio25",
+};
+
+static const char * const blsp_spi_clk_a1_groups[] = {
+ "gpio25",
+};
+
+static const char * const rgb_data0_groups[] = {
+ "gpio26", "gpio41",
+};
+
+static const char * const blsp_uart5_groups[] = {
+ "gpio26", "gpio27", "gpio28", "gpio29",
+};
+
+static const char * const blsp_spi5_groups[] = {
+ "gpio26", "gpio27", "gpio28", "gpio29", "gpio44", "gpio45", "gpio46",
+};
+
+static const char * const adsp_ext_groups[] = {
+ "gpio26",
+};
+
+static const char * const rgb_data1_groups[] = {
+ "gpio27", "gpio42",
+};
+
+static const char * const prng_rosc_groups[] = {
+ "gpio27",
+};
+
+static const char * const rgb_data2_groups[] = {
+ "gpio28", "gpio43",
+};
+
+static const char * const blsp_i2c5_groups[] = {
+ "gpio28", "gpio29",
+};
+
+static const char * const gcc_gp1_clk_b_groups[] = {
+ "gpio28",
+};
+
+static const char * const rgb_data3_groups[] = {
+ "gpio29", "gpio44",
+};
+
+static const char * const gcc_gp2_clk_b_groups[] = {
+ "gpio29",
+};
+
+static const char * const blsp_spi0_groups[] = {
+ "gpio30", "gpio31", "gpio32", "gpio33",
+};
+
+static const char * const blsp_uart0_groups[] = {
+ "gpio30", "gpio31", "gpio32", "gpio33",
+};
+
+static const char * const gcc_gp3_clk_b_groups[] = {
+ "gpio30",
+};
+
+static const char * const blsp_i2c0_groups[] = {
+ "gpio32", "gpio33",
+};
+
+static const char * const qdss_traceclk_b_groups[] = {
+ "gpio34",
+};
+
+static const char * const pcie_clk_groups[] = {
+ "gpio35",
+};
+
+static const char * const nfc_irq_groups[] = {
+ "gpio37",
+};
+
+static const char * const blsp_spi4_groups[] = {
+ "gpio37", "gpio38", "gpio117", "gpio118",
+};
+
+static const char * const nfc_dwl_groups[] = {
+ "gpio38",
+};
+
+static const char * const audio_ts_groups[] = {
+ "gpio38",
+};
+
+static const char * const rgb_data4_groups[] = {
+ "gpio39", "gpio45",
+};
+
+static const char * const spi_lcd_groups[] = {
+ "gpio39", "gpio40",
+};
+
+static const char * const blsp_uart_tx_b2_groups[] = {
+ "gpio39",
+};
+
+static const char * const gcc_gp3_clk_a_groups[] = {
+ "gpio39",
+};
+
+static const char * const rgb_data5_groups[] = {
+ "gpio40", "gpio46",
+};
+
+static const char * const blsp_uart_rx_b2_groups[] = {
+ "gpio40",
+};
+
+static const char * const blsp_i2c_sda_b2_groups[] = {
+ "gpio41",
+};
+
+static const char * const blsp_i2c_scl_b2_groups[] = {
+ "gpio42",
+};
+
+static const char * const pwm_led11_groups[] = {
+ "gpio43",
+};
+
+static const char * const i2s_3_data0_a_groups[] = {
+ "gpio106",
+};
+
+static const char * const ebi2_lcd_groups[] = {
+ "gpio106", "gpio107", "gpio108", "gpio109",
+};
+
+static const char * const i2s_3_data1_a_groups[] = {
+ "gpio107",
+};
+
+static const char * const i2s_3_data2_a_groups[] = {
+ "gpio108",
+};
+
+static const char * const atest_char_groups[] = {
+ "gpio108",
+};
+
+static const char * const pwm_led3_groups[] = {
+ "gpio108",
+};
+
+static const char * const i2s_3_data3_a_groups[] = {
+ "gpio109",
+};
+
+static const char * const pwm_led4_groups[] = {
+ "gpio109",
+};
+
+static const char * const i2s_4_groups[] = {
+ "gpio110", "gpio111", "gpio111", "gpio112", "gpio112", "gpio113",
+ "gpio113", "gpio114", "gpio114", "gpio115", "gpio115", "gpio116",
+};
+
+static const char * const ebi2_a_groups[] = {
+ "gpio110",
+};
+
+static const char * const dsd_clk_b_groups[] = {
+ "gpio110",
+};
+
+static const char * const pwm_led5_groups[] = {
+ "gpio110",
+};
+
+static const char * const pwm_led6_groups[] = {
+ "gpio111",
+};
+
+static const char * const pwm_led7_groups[] = {
+ "gpio112",
+};
+
+static const char * const pwm_led8_groups[] = {
+ "gpio113",
+};
+
+static const char * const pwm_led24_groups[] = {
+ "gpio114",
+};
+
+static const char * const spkr_dac0_groups[] = {
+ "gpio116",
+};
+
+static const char * const blsp_i2c4_groups[] = {
+ "gpio117", "gpio118",
+};
+
+static const char * const pwm_led9_groups[] = {
+ "gpio117",
+};
+
+static const char * const pwm_led10_groups[] = {
+ "gpio118",
+};
+
+static const char * const spdifrx_opt_groups[] = {
+ "gpio119",
+};
+
+static const char * const pwm_led12_groups[] = {
+ "gpio44",
+};
+
+static const char * const pwm_led13_groups[] = {
+ "gpio45",
+};
+
+static const char * const pwm_led14_groups[] = {
+ "gpio46",
+};
+
+static const char * const wlan1_adc1_groups[] = {
+ "gpio46",
+};
+
+static const char * const rgb_data_b0_groups[] = {
+ "gpio47",
+};
+
+static const char * const pwm_led15_groups[] = {
+ "gpio47",
+};
+
+static const char * const blsp_spi_mosi_b1_groups[] = {
+ "gpio47",
+};
+
+static const char * const wlan1_adc0_groups[] = {
+ "gpio47",
+};
+
+static const char * const rgb_data_b1_groups[] = {
+ "gpio48",
+};
+
+static const char * const pwm_led16_groups[] = {
+ "gpio48",
+};
+
+static const char * const blsp_spi_miso_b1_groups[] = {
+ "gpio48",
+};
+
+static const char * const qdss_cti_trig_out_b0_groups[] = {
+ "gpio48",
+};
+
+static const char * const wlan2_adc1_groups[] = {
+ "gpio48",
+};
+
+static const char * const rgb_data_b2_groups[] = {
+ "gpio49",
+};
+
+static const char * const pwm_led17_groups[] = {
+ "gpio49",
+};
+
+static const char * const blsp_spi_cs_n_b1_groups[] = {
+ "gpio49",
+};
+
+static const char * const wlan2_adc0_groups[] = {
+ "gpio49",
+};
+
+static const char * const rgb_data_b3_groups[] = {
+ "gpio50",
+};
+
+static const char * const pwm_led18_groups[] = {
+ "gpio50",
+};
+
+static const char * const blsp_spi_clk_b1_groups[] = {
+ "gpio50",
+};
+
+static const char * const rgb_data_b4_groups[] = {
+ "gpio51",
+};
+
+static const char * const pwm_led19_groups[] = {
+ "gpio51",
+};
+
+static const char * const ext_mclk1_b_groups[] = {
+ "gpio51",
+};
+
+static const char * const qdss_traceclk_a_groups[] = {
+ "gpio51",
+};
+
+static const char * const rgb_data_b5_groups[] = {
+ "gpio52",
+};
+
+static const char * const pwm_led20_groups[] = {
+ "gpio52",
+};
+
+static const char * const atest_char3_groups[] = {
+ "gpio52",
+};
+
+static const char * const i2s_3_sck_b_groups[] = {
+ "gpio52",
+};
+
+static const char * const ldo_update_groups[] = {
+ "gpio52",
+};
+
+static const char * const bimc_dte0_groups[] = {
+ "gpio52", "gpio54",
+};
+
+static const char * const rgb_hsync_groups[] = {
+ "gpio53",
+};
+
+static const char * const pwm_led21_groups[] = {
+ "gpio53",
+};
+
+static const char * const i2s_3_ws_b_groups[] = {
+ "gpio53",
+};
+
+static const char * const dbg_out_groups[] = {
+ "gpio53",
+};
+
+static const char * const rgb_vsync_groups[] = {
+ "gpio54",
+};
+
+static const char * const i2s_3_data0_b_groups[] = {
+ "gpio54",
+};
+
+static const char * const ldo_en_groups[] = {
+ "gpio54",
+};
+
+static const char * const hdmi_dtest_groups[] = {
+ "gpio54",
+};
+
+static const char * const rgb_de_groups[] = {
+ "gpio55",
+};
+
+static const char * const i2s_3_data1_b_groups[] = {
+ "gpio55",
+};
+
+static const char * const hdmi_lbk9_groups[] = {
+ "gpio55",
+};
+
+static const char * const rgb_clk_groups[] = {
+ "gpio56",
+};
+
+static const char * const atest_char1_groups[] = {
+ "gpio56",
+};
+
+static const char * const i2s_3_data2_b_groups[] = {
+ "gpio56",
+};
+
+static const char * const ebi_cdc_groups[] = {
+ "gpio56", "gpio58", "gpio106", "gpio107", "gpio108", "gpio111",
+};
+
+static const char * const hdmi_lbk8_groups[] = {
+ "gpio56",
+};
+
+static const char * const rgb_mdp_groups[] = {
+ "gpio57",
+};
+
+static const char * const atest_char0_groups[] = {
+ "gpio57",
+};
+
+static const char * const i2s_3_data3_b_groups[] = {
+ "gpio57",
+};
+
+static const char * const hdmi_lbk7_groups[] = {
+ "gpio57",
+};
+
+static const char * const rgb_data_b6_groups[] = {
+ "gpio58",
+};
+
+static const char * const rgb_data_b7_groups[] = {
+ "gpio59",
+};
+
+static const char * const hdmi_lbk6_groups[] = {
+ "gpio59",
+};
+
+static const char * const rgmii_int_groups[] = {
+ "gpio61",
+};
+
+static const char * const cri_trng1_groups[] = {
+ "gpio61",
+};
+
+static const char * const rgmii_wol_groups[] = {
+ "gpio62",
+};
+
+static const char * const cri_trng0_groups[] = {
+ "gpio62",
+};
+
+static const char * const gcc_tlmm_groups[] = {
+ "gpio62",
+};
+
+static const char * const rgmii_ck_groups[] = {
+ "gpio63", "gpio69",
+};
+
+static const char * const rgmii_tx_groups[] = {
+ "gpio64", "gpio65", "gpio66", "gpio67",
+};
+
+static const char * const hdmi_lbk5_groups[] = {
+ "gpio64",
+};
+
+static const char * const hdmi_pixel_groups[] = {
+ "gpio65",
+};
+
+static const char * const hdmi_rcv_groups[] = {
+ "gpio66",
+};
+
+static const char * const hdmi_lbk4_groups[] = {
+ "gpio67",
+};
+
+static const char * const rgmii_ctl_groups[] = {
+ "gpio68", "gpio74",
+};
+
+static const char * const ext_lpass_groups[] = {
+ "gpio69",
+};
+
+static const char * const rgmii_rx_groups[] = {
+ "gpio70", "gpio71", "gpio72", "gpio73",
+};
+
+static const char * const cri_trng_groups[] = {
+ "gpio70",
+};
+
+static const char * const hdmi_lbk3_groups[] = {
+ "gpio71",
+};
+
+static const char * const hdmi_lbk2_groups[] = {
+ "gpio72",
+};
+
+static const char * const qdss_cti_trig_out_b1_groups[] = {
+ "gpio73",
+};
+
+static const char * const rgmii_mdio_groups[] = {
+ "gpio75",
+};
+
+static const char * const hdmi_lbk1_groups[] = {
+ "gpio75",
+};
+
+static const char * const rgmii_mdc_groups[] = {
+ "gpio76",
+};
+
+static const char * const hdmi_lbk0_groups[] = {
+ "gpio76",
+};
+
+static const char * const ir_in_groups[] = {
+ "gpio77",
+};
+
+static const char * const wsa_en_groups[] = {
+ "gpio77",
+};
+
+static const char * const rgb_data6_groups[] = {
+ "gpio78", "gpio80",
+};
+
+static const char * const rgb_data7_groups[] = {
+ "gpio79", "gpio81",
+};
+
+static const char * const atest_char2_groups[] = {
+ "gpio80",
+};
+
+static const char * const ebi_ch0_groups[] = {
+ "gpio81",
+};
+
+static const char * const blsp_uart3_groups[] = {
+ "gpio82", "gpio83", "gpio84", "gpio85",
+};
+
+static const char * const blsp_spi3_groups[] = {
+ "gpio82", "gpio83", "gpio84", "gpio85",
+};
+
+static const char * const sd_write_groups[] = {
+ "gpio82",
+};
+
+static const char * const blsp_i2c3_groups[] = {
+ "gpio84", "gpio85",
+};
+
+static const char * const gcc_gp1_clk_a_groups[] = {
+ "gpio84",
+};
+
+static const char * const qdss_cti_trig_in_b1_groups[] = {
+ "gpio84",
+};
+
+static const char * const gcc_gp2_clk_a_groups[] = {
+ "gpio85",
+};
+
+static const char * const ext_mclk0_groups[] = {
+ "gpio86",
+};
+
+static const char * const mclk_in1_groups[] = {
+ "gpio86",
+};
+
+static const char * const i2s_1_groups[] = {
+ "gpio87", "gpio88", "gpio88", "gpio89", "gpio89", "gpio90", "gpio90",
+ "gpio91", "gpio91", "gpio92", "gpio92", "gpio93", "gpio93", "gpio94",
+ "gpio94", "gpio95", "gpio95", "gpio96",
+};
+
+static const char * const dsd_clk_a_groups[] = {
+ "gpio87",
+};
+
+static const char * const qdss_cti_trig_in_a1_groups[] = {
+ "gpio92",
+};
+
+static const char * const rgmi_dll1_groups[] = {
+ "gpio92",
+};
+
+static const char * const pwm_led22_groups[] = {
+ "gpio93",
+};
+
+static const char * const pwm_led23_groups[] = {
+ "gpio94",
+};
+
+static const char * const qdss_cti_trig_out_a0_groups[] = {
+ "gpio94",
+};
+
+static const char * const rgmi_dll2_groups[] = {
+ "gpio94",
+};
+
+static const char * const pwm_led1_groups[] = {
+ "gpio95",
+};
+
+static const char * const qdss_cti_trig_out_a1_groups[] = {
+ "gpio95",
+};
+
+static const char * const pwm_led2_groups[] = {
+ "gpio96",
+};
+
+static const char * const i2s_2_groups[] = {
+ "gpio97", "gpio98", "gpio99", "gpio100", "gpio101", "gpio102",
+};
+
+static const char * const pll_bist_groups[] = {
+ "gpio100",
+};
+
+static const char * const ext_mclk1_a_groups[] = {
+ "gpio103",
+};
+
+static const char * const mclk_in2_groups[] = {
+ "gpio103",
+};
+
+static const char * const bimc_dte1_groups[] = {
+ "gpio103", "gpio109",
+};
+
+static const char * const i2s_3_sck_a_groups[] = {
+ "gpio104",
+};
+
+static const char * const i2s_3_ws_a_groups[] = {
+ "gpio105",
+};
+
+static const struct msm_function qcs404_functions[] = {
+ FUNCTION(gpio),
+ FUNCTION(hdmi_tx),
+ FUNCTION(hdmi_ddc),
+ FUNCTION(blsp_uart_tx_a2),
+ FUNCTION(blsp_spi2),
+ FUNCTION(m_voc),
+ FUNCTION(qdss_cti_trig_in_a0),
+ FUNCTION(blsp_uart_rx_a2),
+ FUNCTION(qdss_tracectl_a),
+ FUNCTION(blsp_uart2),
+ FUNCTION(aud_cdc),
+ FUNCTION(blsp_i2c_sda_a2),
+ FUNCTION(qdss_tracedata_a),
+ FUNCTION(blsp_i2c_scl_a2),
+ FUNCTION(qdss_tracectl_b),
+ FUNCTION(qdss_cti_trig_in_b0),
+ FUNCTION(blsp_uart1),
+ FUNCTION(blsp_spi_mosi_a1),
+ FUNCTION(blsp_spi_miso_a1),
+ FUNCTION(qdss_tracedata_b),
+ FUNCTION(blsp_i2c1),
+ FUNCTION(blsp_spi_cs_n_a1),
+ FUNCTION(gcc_plltest),
+ FUNCTION(blsp_spi_clk_a1),
+ FUNCTION(rgb_data0),
+ FUNCTION(blsp_uart5),
+ FUNCTION(blsp_spi5),
+ FUNCTION(adsp_ext),
+ FUNCTION(rgb_data1),
+ FUNCTION(prng_rosc),
+ FUNCTION(rgb_data2),
+ FUNCTION(blsp_i2c5),
+ FUNCTION(gcc_gp1_clk_b),
+ FUNCTION(rgb_data3),
+ FUNCTION(gcc_gp2_clk_b),
+ FUNCTION(blsp_spi0),
+ FUNCTION(blsp_uart0),
+ FUNCTION(gcc_gp3_clk_b),
+ FUNCTION(blsp_i2c0),
+ FUNCTION(qdss_traceclk_b),
+ FUNCTION(pcie_clk),
+ FUNCTION(nfc_irq),
+ FUNCTION(blsp_spi4),
+ FUNCTION(nfc_dwl),
+ FUNCTION(audio_ts),
+ FUNCTION(rgb_data4),
+ FUNCTION(spi_lcd),
+ FUNCTION(blsp_uart_tx_b2),
+ FUNCTION(gcc_gp3_clk_a),
+ FUNCTION(rgb_data5),
+ FUNCTION(blsp_uart_rx_b2),
+ FUNCTION(blsp_i2c_sda_b2),
+ FUNCTION(blsp_i2c_scl_b2),
+ FUNCTION(pwm_led11),
+ FUNCTION(i2s_3_data0_a),
+ FUNCTION(ebi2_lcd),
+ FUNCTION(i2s_3_data1_a),
+ FUNCTION(i2s_3_data2_a),
+ FUNCTION(atest_char),
+ FUNCTION(pwm_led3),
+ FUNCTION(i2s_3_data3_a),
+ FUNCTION(pwm_led4),
+ FUNCTION(i2s_4),
+ FUNCTION(ebi2_a),
+ FUNCTION(dsd_clk_b),
+ FUNCTION(pwm_led5),
+ FUNCTION(pwm_led6),
+ FUNCTION(pwm_led7),
+ FUNCTION(pwm_led8),
+ FUNCTION(pwm_led24),
+ FUNCTION(spkr_dac0),
+ FUNCTION(blsp_i2c4),
+ FUNCTION(pwm_led9),
+ FUNCTION(pwm_led10),
+ FUNCTION(spdifrx_opt),
+ FUNCTION(pwm_led12),
+ FUNCTION(pwm_led13),
+ FUNCTION(pwm_led14),
+ FUNCTION(wlan1_adc1),
+ FUNCTION(rgb_data_b0),
+ FUNCTION(pwm_led15),
+ FUNCTION(blsp_spi_mosi_b1),
+ FUNCTION(wlan1_adc0),
+ FUNCTION(rgb_data_b1),
+ FUNCTION(pwm_led16),
+ FUNCTION(blsp_spi_miso_b1),
+ FUNCTION(qdss_cti_trig_out_b0),
+ FUNCTION(wlan2_adc1),
+ FUNCTION(rgb_data_b2),
+ FUNCTION(pwm_led17),
+ FUNCTION(blsp_spi_cs_n_b1),
+ FUNCTION(wlan2_adc0),
+ FUNCTION(rgb_data_b3),
+ FUNCTION(pwm_led18),
+ FUNCTION(blsp_spi_clk_b1),
+ FUNCTION(rgb_data_b4),
+ FUNCTION(pwm_led19),
+ FUNCTION(ext_mclk1_b),
+ FUNCTION(qdss_traceclk_a),
+ FUNCTION(rgb_data_b5),
+ FUNCTION(pwm_led20),
+ FUNCTION(atest_char3),
+ FUNCTION(i2s_3_sck_b),
+ FUNCTION(ldo_update),
+ FUNCTION(bimc_dte0),
+ FUNCTION(rgb_hsync),
+ FUNCTION(pwm_led21),
+ FUNCTION(i2s_3_ws_b),
+ FUNCTION(dbg_out),
+ FUNCTION(rgb_vsync),
+ FUNCTION(i2s_3_data0_b),
+ FUNCTION(ldo_en),
+ FUNCTION(hdmi_dtest),
+ FUNCTION(rgb_de),
+ FUNCTION(i2s_3_data1_b),
+ FUNCTION(hdmi_lbk9),
+ FUNCTION(rgb_clk),
+ FUNCTION(atest_char1),
+ FUNCTION(i2s_3_data2_b),
+ FUNCTION(ebi_cdc),
+ FUNCTION(hdmi_lbk8),
+ FUNCTION(rgb_mdp),
+ FUNCTION(atest_char0),
+ FUNCTION(i2s_3_data3_b),
+ FUNCTION(hdmi_lbk7),
+ FUNCTION(rgb_data_b6),
+ FUNCTION(rgb_data_b7),
+ FUNCTION(hdmi_lbk6),
+ FUNCTION(rgmii_int),
+ FUNCTION(cri_trng1),
+ FUNCTION(rgmii_wol),
+ FUNCTION(cri_trng0),
+ FUNCTION(gcc_tlmm),
+ FUNCTION(rgmii_ck),
+ FUNCTION(rgmii_tx),
+ FUNCTION(hdmi_lbk5),
+ FUNCTION(hdmi_pixel),
+ FUNCTION(hdmi_rcv),
+ FUNCTION(hdmi_lbk4),
+ FUNCTION(rgmii_ctl),
+ FUNCTION(ext_lpass),
+ FUNCTION(rgmii_rx),
+ FUNCTION(cri_trng),
+ FUNCTION(hdmi_lbk3),
+ FUNCTION(hdmi_lbk2),
+ FUNCTION(qdss_cti_trig_out_b1),
+ FUNCTION(rgmii_mdio),
+ FUNCTION(hdmi_lbk1),
+ FUNCTION(rgmii_mdc),
+ FUNCTION(hdmi_lbk0),
+ FUNCTION(ir_in),
+ FUNCTION(wsa_en),
+ FUNCTION(rgb_data6),
+ FUNCTION(rgb_data7),
+ FUNCTION(atest_char2),
+ FUNCTION(ebi_ch0),
+ FUNCTION(blsp_uart3),
+ FUNCTION(blsp_spi3),
+ FUNCTION(sd_write),
+ FUNCTION(blsp_i2c3),
+ FUNCTION(gcc_gp1_clk_a),
+ FUNCTION(qdss_cti_trig_in_b1),
+ FUNCTION(gcc_gp2_clk_a),
+ FUNCTION(ext_mclk0),
+ FUNCTION(mclk_in1),
+ FUNCTION(i2s_1),
+ FUNCTION(dsd_clk_a),
+ FUNCTION(qdss_cti_trig_in_a1),
+ FUNCTION(rgmi_dll1),
+ FUNCTION(pwm_led22),
+ FUNCTION(pwm_led23),
+ FUNCTION(qdss_cti_trig_out_a0),
+ FUNCTION(rgmi_dll2),
+ FUNCTION(pwm_led1),
+ FUNCTION(qdss_cti_trig_out_a1),
+ FUNCTION(pwm_led2),
+ FUNCTION(i2s_2),
+ FUNCTION(pll_bist),
+ FUNCTION(ext_mclk1_a),
+ FUNCTION(mclk_in2),
+ FUNCTION(bimc_dte1),
+ FUNCTION(i2s_3_sck_a),
+ FUNCTION(i2s_3_ws_a),
+};
+
+/* 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 qcs404_groups[] = {
+ [0] = PINGROUP(0, SOUTH, _, _, _, _, _, _, _, _, _),
+ [1] = PINGROUP(1, SOUTH, _, _, _, _, _, _, _, _, _),
+ [2] = PINGROUP(2, SOUTH, _, _, _, _, _, _, _, _, _),
+ [3] = PINGROUP(3, SOUTH, _, _, _, _, _, _, _, _, _),
+ [4] = PINGROUP(4, SOUTH, _, _, _, _, _, _, _, _, _),
+ [5] = PINGROUP(5, SOUTH, _, _, _, _, _, _, _, _, _),
+ [6] = PINGROUP(6, SOUTH, _, _, _, _, _, _, _, _, _),
+ [7] = PINGROUP(7, SOUTH, _, _, _, _, _, _, _, _, _),
+ [8] = PINGROUP(8, SOUTH, _, _, _, _, _, _, _, _, _),
+ [9] = PINGROUP(9, SOUTH, _, _, _, _, _, _, _, _, _),
+ [10] = PINGROUP(10, SOUTH, _, _, _, _, _, _, _, _, _),
+ [11] = PINGROUP(11, SOUTH, _, _, _, _, _, _, _, _, _),
+ [12] = PINGROUP(12, SOUTH, _, _, _, _, _, _, _, _, _),
+ [13] = PINGROUP(13, SOUTH, _, _, _, _, _, _, _, _, _),
+ [14] = PINGROUP(14, SOUTH, hdmi_tx, _, _, _, _, _, _, _, _),
+ [15] = PINGROUP(15, SOUTH, hdmi_ddc, _, _, _, _, _, _, _, _),
+ [16] = PINGROUP(16, SOUTH, hdmi_ddc, _, _, _, _, _, _, _, _),
+ [17] = PINGROUP(17, NORTH, blsp_uart_tx_a2, blsp_spi2, m_voc, _, _, _, _, _, _),
+ [18] = PINGROUP(18, NORTH, blsp_uart_rx_a2, blsp_spi2, _, _, _, _, _, qdss_tracectl_a, _),
+ [19] = PINGROUP(19, NORTH, blsp_uart2, aud_cdc, blsp_i2c_sda_a2, blsp_spi2, _, qdss_tracedata_a, _, _, _),
+ [20] = PINGROUP(20, NORTH, blsp_uart2, aud_cdc, blsp_i2c_scl_a2, blsp_spi2, _, _, _, _, _),
+ [21] = PINGROUP(21, SOUTH, m_voc, _, _, _, _, _, _, _, qdss_cti_trig_in_b0),
+ [22] = PINGROUP(22, NORTH, blsp_uart1, blsp_spi_mosi_a1, _, _, _, _, _, _, _),
+ [23] = PINGROUP(23, NORTH, blsp_uart1, blsp_spi_miso_a1, _, _, _, _, _, qdss_tracedata_b, _),
+ [24] = PINGROUP(24, NORTH, blsp_uart1, blsp_i2c1, blsp_spi_cs_n_a1, gcc_plltest, _, _, _, _, _),
+ [25] = PINGROUP(25, NORTH, blsp_uart1, blsp_i2c1, blsp_spi_clk_a1, gcc_plltest, _, _, _, _, _),
+ [26] = PINGROUP(26, EAST, rgb_data0, blsp_uart5, blsp_spi5, adsp_ext, _, _, _, _, _),
+ [27] = PINGROUP(27, EAST, rgb_data1, blsp_uart5, blsp_spi5, prng_rosc, _, _, _, _, _),
+ [28] = PINGROUP(28, EAST, rgb_data2, blsp_uart5, blsp_i2c5, blsp_spi5, gcc_gp1_clk_b, _, _, _, _),
+ [29] = PINGROUP(29, EAST, rgb_data3, blsp_uart5, blsp_i2c5, blsp_spi5, gcc_gp2_clk_b, _, _, _, _),
+ [30] = PINGROUP(30, NORTH, blsp_spi0, blsp_uart0, gcc_gp3_clk_b, _, _, _, _, _, _),
+ [31] = PINGROUP(31, NORTH, blsp_spi0, blsp_uart0, _, _, _, _, _, _, _),
+ [32] = PINGROUP(32, NORTH, blsp_spi0, blsp_uart0, blsp_i2c0, _, _, _, _, _, _),
+ [33] = PINGROUP(33, NORTH, blsp_spi0, blsp_uart0, blsp_i2c0, _, _, _, _, _, _),
+ [34] = PINGROUP(34, SOUTH, _, qdss_traceclk_b, _, _, _, _, _, _, _),
+ [35] = PINGROUP(35, SOUTH, pcie_clk, _, qdss_tracedata_b, _, _, _, _, _, _),
+ [36] = PINGROUP(36, NORTH, _, _, _, _, _, _, qdss_tracedata_a, _, _),
+ [37] = PINGROUP(37, NORTH, nfc_irq, blsp_spi4, _, _, _, _, _, _, _),
+ [38] = PINGROUP(38, NORTH, nfc_dwl, blsp_spi4, audio_ts, _, _, _, _, _, _),
+ [39] = PINGROUP(39, EAST, rgb_data4, spi_lcd, blsp_uart_tx_b2, gcc_gp3_clk_a, qdss_tracedata_a, _, _, _, _),
+ [40] = PINGROUP(40, EAST, rgb_data5, spi_lcd, blsp_uart_rx_b2, _, qdss_tracedata_b, _, _, _, _),
+ [41] = PINGROUP(41, EAST, rgb_data0, blsp_i2c_sda_b2, _, qdss_tracedata_b, _, _, _, _, _),
+ [42] = PINGROUP(42, EAST, rgb_data1, blsp_i2c_scl_b2, _, _, _, _, _, qdss_tracedata_a, _),
+ [43] = PINGROUP(43, EAST, rgb_data2, pwm_led11, _, _, _, _, _, _, _),
+ [44] = PINGROUP(44, EAST, rgb_data3, pwm_led12, blsp_spi5, _, _, _, _, _, _),
+ [45] = PINGROUP(45, EAST, rgb_data4, pwm_led13, blsp_spi5, qdss_tracedata_b, _, _, _, _, _),
+ [46] = PINGROUP(46, EAST, rgb_data5, pwm_led14, blsp_spi5, qdss_tracedata_b, _, wlan1_adc1, _, _, _),
+ [47] = PINGROUP(47, EAST, rgb_data_b0, pwm_led15, blsp_spi_mosi_b1, qdss_tracedata_b, _, wlan1_adc0, _, _, _),
+ [48] = PINGROUP(48, EAST, rgb_data_b1, pwm_led16, blsp_spi_miso_b1, _, qdss_cti_trig_out_b0, _, wlan2_adc1, _, _),
+ [49] = PINGROUP(49, EAST, rgb_data_b2, pwm_led17, blsp_spi_cs_n_b1, _, qdss_tracedata_b, _, wlan2_adc0, _, _),
+ [50] = PINGROUP(50, EAST, rgb_data_b3, pwm_led18, blsp_spi_clk_b1, qdss_tracedata_b, _, _, _, _, _),
+ [51] = PINGROUP(51, EAST, rgb_data_b4, pwm_led19, ext_mclk1_b, qdss_traceclk_a, _, _, _, _, _),
+ [52] = PINGROUP(52, EAST, rgb_data_b5, pwm_led20, atest_char3, i2s_3_sck_b, ldo_update, bimc_dte0, _, _, _),
+ [53] = PINGROUP(53, EAST, rgb_hsync, pwm_led21, i2s_3_ws_b, dbg_out, _, _, _, _, _),
+ [54] = PINGROUP(54, EAST, rgb_vsync, i2s_3_data0_b, ldo_en, bimc_dte0, _, hdmi_dtest, _, _, _),
+ [55] = PINGROUP(55, EAST, rgb_de, i2s_3_data1_b, _, qdss_tracedata_b, _, hdmi_lbk9, _, _, _),
+ [56] = PINGROUP(56, EAST, rgb_clk, atest_char1, i2s_3_data2_b, ebi_cdc, _, hdmi_lbk8, _, _, _),
+ [57] = PINGROUP(57, EAST, rgb_mdp, atest_char0, i2s_3_data3_b, _, hdmi_lbk7, _, _, _, _),
+ [58] = PINGROUP(58, EAST, rgb_data_b6, _, ebi_cdc, _, _, _, _, _, _),
+ [59] = PINGROUP(59, EAST, rgb_data_b7, _, hdmi_lbk6, _, _, _, _, _, _),
+ [60] = PINGROUP(60, NORTH, _, _, _, _, _, _, _, _, _),
+ [61] = PINGROUP(61, NORTH, rgmii_int, cri_trng1, qdss_tracedata_b, _, _, _, _, _, _),
+ [62] = PINGROUP(62, NORTH, rgmii_wol, cri_trng0, qdss_tracedata_b, gcc_tlmm, _, _, _, _, _),
+ [63] = PINGROUP(63, NORTH, rgmii_ck, _, _, _, _, _, _, _, _),
+ [64] = PINGROUP(64, NORTH, rgmii_tx, _, hdmi_lbk5, _, _, _, _, _, _),
+ [65] = PINGROUP(65, NORTH, rgmii_tx, _, hdmi_pixel, _, _, _, _, _, _),
+ [66] = PINGROUP(66, NORTH, rgmii_tx, _, hdmi_rcv, _, _, _, _, _, _),
+ [67] = PINGROUP(67, NORTH, rgmii_tx, _, hdmi_lbk4, _, _, _, _, _, _),
+ [68] = PINGROUP(68, NORTH, rgmii_ctl, _, _, _, _, _, _, _, _),
+ [69] = PINGROUP(69, NORTH, rgmii_ck, ext_lpass, _, _, _, _, _, _, _),
+ [70] = PINGROUP(70, NORTH, rgmii_rx, cri_trng, _, _, _, _, _, _, _),
+ [71] = PINGROUP(71, NORTH, rgmii_rx, _, hdmi_lbk3, _, _, _, _, _, _),
+ [72] = PINGROUP(72, NORTH, rgmii_rx, _, hdmi_lbk2, _, _, _, _, _, _),
+ [73] = PINGROUP(73, NORTH, rgmii_rx, _, _, _, _, qdss_cti_trig_out_b1, _, _, _),
+ [74] = PINGROUP(74, NORTH, rgmii_ctl, _, _, _, _, _, _, _, _),
+ [75] = PINGROUP(75, NORTH, rgmii_mdio, _, hdmi_lbk1, _, _, _, _, _, _),
+ [76] = PINGROUP(76, NORTH, rgmii_mdc, _, _, _, _, _, hdmi_lbk0, _, _),
+ [77] = PINGROUP(77, NORTH, ir_in, wsa_en, _, _, _, _, _, _, _),
+ [78] = PINGROUP(78, EAST, rgb_data6, _, _, _, _, _, _, _, _),
+ [79] = PINGROUP(79, EAST, rgb_data7, _, _, _, _, _, _, _, _),
+ [80] = PINGROUP(80, EAST, rgb_data6, atest_char2, _, _, _, _, _, _, _),
+ [81] = PINGROUP(81, EAST, rgb_data7, ebi_ch0, _, _, _, _, _, _, _),
+ [82] = PINGROUP(82, NORTH, blsp_uart3, blsp_spi3, sd_write, _, _, _, _, _, qdss_tracedata_a),
+ [83] = PINGROUP(83, NORTH, blsp_uart3, blsp_spi3, _, _, _, _, qdss_tracedata_a, _, _),
+ [84] = PINGROUP(84, NORTH, blsp_uart3, blsp_i2c3, blsp_spi3, gcc_gp1_clk_a, qdss_cti_trig_in_b1, _, _, _, _),
+ [85] = PINGROUP(85, NORTH, blsp_uart3, blsp_i2c3, blsp_spi3, gcc_gp2_clk_a, qdss_tracedata_b, _, _, _, _),
+ [86] = PINGROUP(86, EAST, ext_mclk0, mclk_in1, _, _, _, _, _, _, _),
+ [87] = PINGROUP(87, EAST, i2s_1, dsd_clk_a, _, _, _, _, _, _, _),
+ [88] = PINGROUP(88, EAST, i2s_1, i2s_1, _, _, _, _, _, _, _),
+ [89] = PINGROUP(89, EAST, i2s_1, i2s_1, _, _, _, _, _, _, qdss_tracedata_b),
+ [90] = PINGROUP(90, EAST, i2s_1, i2s_1, _, _, _, _, _, _, _),
+ [91] = PINGROUP(91, EAST, i2s_1, i2s_1, _, _, _, _, _, _, _),
+ [92] = PINGROUP(92, EAST, i2s_1, i2s_1, _, _, _, _, _, qdss_cti_trig_in_a1, _),
+ [93] = PINGROUP(93, EAST, i2s_1, pwm_led22, i2s_1, _, _, _, _, _, qdss_tracedata_b),
+ [94] = PINGROUP(94, EAST, i2s_1, pwm_led23, i2s_1, _, qdss_cti_trig_out_a0, _, rgmi_dll2, _, _),
+ [95] = PINGROUP(95, EAST, i2s_1, pwm_led1, i2s_1, _, qdss_cti_trig_out_a1, _, _, _, _),
+ [96] = PINGROUP(96, EAST, i2s_1, pwm_led2, _, _, _, _, _, _, _),
+ [97] = PINGROUP(97, EAST, i2s_2, _, _, _, _, _, _, _, _),
+ [98] = PINGROUP(98, EAST, i2s_2, _, _, _, _, _, _, _, _),
+ [99] = PINGROUP(99, EAST, i2s_2, _, _, _, _, _, _, _, _),
+ [100] = PINGROUP(100, EAST, i2s_2, pll_bist, _, _, _, _, _, _, _),
+ [101] = PINGROUP(101, EAST, i2s_2, _, _, _, _, _, _, _, _),
+ [102] = PINGROUP(102, EAST, i2s_2, _, _, _, _, _, _, _, _),
+ [103] = PINGROUP(103, EAST, ext_mclk1_a, mclk_in2, bimc_dte1, _, _, _, _, _, _),
+ [104] = PINGROUP(104, EAST, i2s_3_sck_a, _, _, _, _, _, _, _, _),
+ [105] = PINGROUP(105, EAST, i2s_3_ws_a, _, _, _, _, _, _, _, _),
+ [106] = PINGROUP(106, EAST, i2s_3_data0_a, ebi2_lcd, _, _, ebi_cdc, _, _, _, _),
+ [107] = PINGROUP(107, EAST, i2s_3_data1_a, ebi2_lcd, _, _, ebi_cdc, _, _, _, _),
+ [108] = PINGROUP(108, EAST, i2s_3_data2_a, ebi2_lcd, atest_char, pwm_led3, ebi_cdc, _, _, _, _),
+ [109] = PINGROUP(109, EAST, i2s_3_data3_a, ebi2_lcd, pwm_led4, bimc_dte1, _, _, _, _, _),
+ [110] = PINGROUP(110, EAST, i2s_4, ebi2_a, dsd_clk_b, pwm_led5, _, _, _, _, _),
+ [111] = PINGROUP(111, EAST, i2s_4, i2s_4, pwm_led6, ebi_cdc, _, _, _, _, _),
+ [112] = PINGROUP(112, EAST, i2s_4, i2s_4, pwm_led7, _, _, _, _, _, _),
+ [113] = PINGROUP(113, EAST, i2s_4, i2s_4, pwm_led8, _, _, _, _, _, _),
+ [114] = PINGROUP(114, EAST, i2s_4, i2s_4, pwm_led24, _, _, _, _, _, _),
+ [115] = PINGROUP(115, EAST, i2s_4, i2s_4, _, _, _, _, _, _, _),
+ [116] = PINGROUP(116, EAST, i2s_4, spkr_dac0, _, _, _, _, _, _, _),
+ [117] = PINGROUP(117, NORTH, blsp_i2c4, blsp_spi4, pwm_led9, _, _, _, _, _, _),
+ [118] = PINGROUP(118, NORTH, blsp_i2c4, blsp_spi4, pwm_led10, _, _, _, _, _, _),
+ [119] = PINGROUP(119, EAST, spdifrx_opt, _, _, _, _, _, _, _, _),
+ [120] = SDC_QDSD_PINGROUP(sdc1_rclk, 0xc2000, 15, 0),
+ [121] = SDC_QDSD_PINGROUP(sdc1_clk, 0xc2000, 13, 6),
+ [122] = SDC_QDSD_PINGROUP(sdc1_cmd, 0xc2000, 11, 3),
+ [123] = SDC_QDSD_PINGROUP(sdc1_data, 0xc2000, 9, 0),
+ [124] = SDC_QDSD_PINGROUP(sdc2_clk, 0xc3000, 14, 6),
+ [125] = SDC_QDSD_PINGROUP(sdc2_cmd, 0xc3000, 11, 3),
+ [126] = SDC_QDSD_PINGROUP(sdc2_data, 0xc3000, 9, 0),
+};
+
+static const struct msm_pinctrl_soc_data qcs404_pinctrl = {
+ .pins = qcs404_pins,
+ .npins = ARRAY_SIZE(qcs404_pins),
+ .functions = qcs404_functions,
+ .nfunctions = ARRAY_SIZE(qcs404_functions),
+ .groups = qcs404_groups,
+ .ngroups = ARRAY_SIZE(qcs404_groups),
+ .ngpios = 120,
+ .tiles = qcs404_tiles,
+ .ntiles = ARRAY_SIZE(qcs404_tiles),
+};
+
+static int qcs404_pinctrl_probe(struct platform_device *pdev)
+{
+ return msm_pinctrl_probe(pdev, &qcs404_pinctrl);
+}
+
+static const struct of_device_id qcs404_pinctrl_of_match[] = {
+ { .compatible = "qcom,qcs404-pinctrl", },
+ { },
+};
+
+static struct platform_driver qcs404_pinctrl_driver = {
+ .driver = {
+ .name = "qcs404-pinctrl",
+ .of_match_table = qcs404_pinctrl_of_match,
+ },
+ .probe = qcs404_pinctrl_probe,
+ .remove = msm_pinctrl_remove,
+};
+
+static int __init qcs404_pinctrl_init(void)
+{
+ return platform_driver_register(&qcs404_pinctrl_driver);
+}
+arch_initcall(qcs404_pinctrl_init);
+
+static void __exit qcs404_pinctrl_exit(void)
+{
+ platform_driver_unregister(&qcs404_pinctrl_driver);
+}
+module_exit(qcs404_pinctrl_exit);
+
+MODULE_DESCRIPTION("Qualcomm QCS404 pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, qcs404_pinctrl_of_match);
diff --git a/drivers/pinctrl/qcom/pinctrl-sdm660.c b/drivers/pinctrl/qcom/pinctrl-sdm660.c
new file mode 100644
index 000000000000..6838b38555a1
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-sdm660.c
@@ -0,0 +1,1455 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018, Craig Tatlor.
+ */
+
+#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 sdm660_tiles[] = {
+ "north",
+ "center",
+ "south"
+};
+
+enum {
+ NORTH,
+ CENTER,
+ SOUTH
+};
+
+#define REG_SIZE 0x1000
+
+#define FUNCTION(fname) \
+ [msm_mux_##fname] = { \
+ .name = #fname, \
+ .groups = fname##_groups, \
+ .ngroups = ARRAY_SIZE(fname##_groups), \
+ }
+
+
+#define PINGROUP(id, base, f1, f2, f3, f4, f5, f6, f7, f8, f9) \
+ { \
+ .name = "gpio" #id, \
+ .pins = gpio##id##_pins, \
+ .npins = (unsigned)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 = base + REG_SIZE * id, \
+ .io_reg = base + 0x4 + REG_SIZE * id, \
+ .intr_cfg_reg = base + 0x8 + REG_SIZE * id, \
+ .intr_status_reg = base + 0xc + REG_SIZE * id, \
+ .intr_target_reg = base + 0x8 + REG_SIZE * id, \
+ .mux_bit = 2, \
+ .pull_bit = 0, \
+ .drv_bit = 6, \
+ .oe_bit = 9, \
+ .in_bit = 0, \
+ .out_bit = 1, \
+ .intr_enable_bit = 0, \
+ .intr_status_bit = 0, \
+ .intr_target_bit = 5, \
+ .intr_target_kpss_val = 3, \
+ .intr_raw_status_bit = 4, \
+ .intr_polarity_bit = 1, \
+ .intr_detection_bit = 2, \
+ .intr_detection_width = 2, \
+ }
+
+#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \
+ { \
+ .name = #pg_name, \
+ .pins = pg_name##_pins, \
+ .npins = (unsigned)ARRAY_SIZE(pg_name##_pins), \
+ .ctl_reg = ctl, \
+ .io_reg = 0, \
+ .intr_cfg_reg = 0, \
+ .intr_status_reg = 0, \
+ .intr_target_reg = 0, \
+ .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, \
+ }
+
+static const struct pinctrl_pin_desc sdm660_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, "SDC1_CLK"),
+ PINCTRL_PIN(115, "SDC1_CMD"),
+ PINCTRL_PIN(116, "SDC1_DATA"),
+ PINCTRL_PIN(117, "SDC2_CLK"),
+ PINCTRL_PIN(118, "SDC2_CMD"),
+ PINCTRL_PIN(119, "SDC2_DATA"),
+ PINCTRL_PIN(120, "SDC1_RCLK"),
+};
+
+#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);
+
+static const unsigned int sdc1_clk_pins[] = { 114 };
+static const unsigned int sdc1_cmd_pins[] = { 115 };
+static const unsigned int sdc1_data_pins[] = { 116 };
+static const unsigned int sdc1_rclk_pins[] = { 120 };
+static const unsigned int sdc2_clk_pins[] = { 117 };
+static const unsigned int sdc2_cmd_pins[] = { 118 };
+static const unsigned int sdc2_data_pins[] = { 119 };
+
+enum sdm660_functions {
+ msm_mux_adsp_ext,
+ msm_mux_agera_pll,
+ msm_mux_atest_char,
+ msm_mux_atest_char0,
+ msm_mux_atest_char1,
+ msm_mux_atest_char2,
+ msm_mux_atest_char3,
+ msm_mux_atest_gpsadc0,
+ msm_mux_atest_gpsadc1,
+ msm_mux_atest_tsens,
+ msm_mux_atest_tsens2,
+ msm_mux_atest_usb1,
+ msm_mux_atest_usb10,
+ msm_mux_atest_usb11,
+ msm_mux_atest_usb12,
+ msm_mux_atest_usb13,
+ msm_mux_atest_usb2,
+ msm_mux_atest_usb20,
+ msm_mux_atest_usb21,
+ msm_mux_atest_usb22,
+ msm_mux_atest_usb23,
+ msm_mux_audio_ref,
+ msm_mux_bimc_dte0,
+ msm_mux_bimc_dte1,
+ msm_mux_blsp_i2c1,
+ msm_mux_blsp_i2c2,
+ msm_mux_blsp_i2c3,
+ msm_mux_blsp_i2c4,
+ msm_mux_blsp_i2c5,
+ msm_mux_blsp_i2c6,
+ msm_mux_blsp_i2c7,
+ msm_mux_blsp_i2c8_a,
+ msm_mux_blsp_i2c8_b,
+ msm_mux_blsp_spi1,
+ msm_mux_blsp_spi2,
+ msm_mux_blsp_spi3,
+ msm_mux_blsp_spi3_cs1,
+ msm_mux_blsp_spi3_cs2,
+ msm_mux_blsp_spi4,
+ msm_mux_blsp_spi5,
+ msm_mux_blsp_spi6,
+ msm_mux_blsp_spi7,
+ msm_mux_blsp_spi8_a,
+ msm_mux_blsp_spi8_b,
+ msm_mux_blsp_spi8_cs1,
+ msm_mux_blsp_spi8_cs2,
+ msm_mux_blsp_uart1,
+ msm_mux_blsp_uart2,
+ msm_mux_blsp_uart5,
+ msm_mux_blsp_uart6_a,
+ msm_mux_blsp_uart6_b,
+ msm_mux_blsp_uim1,
+ msm_mux_blsp_uim2,
+ msm_mux_blsp_uim5,
+ msm_mux_blsp_uim6,
+ msm_mux_cam_mclk,
+ msm_mux_cci_async,
+ msm_mux_cci_i2c,
+ msm_mux_cri_trng,
+ msm_mux_cri_trng0,
+ msm_mux_cri_trng1,
+ msm_mux_dbg_out,
+ msm_mux_ddr_bist,
+ msm_mux_gcc_gp1,
+ msm_mux_gcc_gp2,
+ msm_mux_gcc_gp3,
+ msm_mux_gpio,
+ msm_mux_gps_tx_a,
+ msm_mux_gps_tx_b,
+ msm_mux_gps_tx_c,
+ msm_mux_isense_dbg,
+ msm_mux_jitter_bist,
+ msm_mux_ldo_en,
+ msm_mux_ldo_update,
+ msm_mux_m_voc,
+ msm_mux_mdp_vsync,
+ msm_mux_mdss_vsync0,
+ msm_mux_mdss_vsync1,
+ msm_mux_mdss_vsync2,
+ msm_mux_mdss_vsync3,
+ msm_mux_mss_lte,
+ msm_mux_nav_pps_a,
+ msm_mux_nav_pps_b,
+ msm_mux_nav_pps_c,
+ msm_mux_pa_indicator,
+ msm_mux_phase_flag0,
+ msm_mux_phase_flag1,
+ msm_mux_phase_flag2,
+ msm_mux_phase_flag3,
+ msm_mux_phase_flag4,
+ msm_mux_phase_flag5,
+ msm_mux_phase_flag6,
+ msm_mux_phase_flag7,
+ msm_mux_phase_flag8,
+ msm_mux_phase_flag9,
+ msm_mux_phase_flag10,
+ msm_mux_phase_flag11,
+ msm_mux_phase_flag12,
+ msm_mux_phase_flag13,
+ msm_mux_phase_flag14,
+ msm_mux_phase_flag15,
+ msm_mux_phase_flag16,
+ msm_mux_phase_flag17,
+ msm_mux_phase_flag18,
+ msm_mux_phase_flag19,
+ msm_mux_phase_flag20,
+ msm_mux_phase_flag21,
+ msm_mux_phase_flag22,
+ msm_mux_phase_flag23,
+ msm_mux_phase_flag24,
+ msm_mux_phase_flag25,
+ msm_mux_phase_flag26,
+ msm_mux_phase_flag27,
+ msm_mux_phase_flag28,
+ msm_mux_phase_flag29,
+ msm_mux_phase_flag30,
+ msm_mux_phase_flag31,
+ msm_mux_pll_bypassnl,
+ msm_mux_pll_reset,
+ msm_mux_pri_mi2s,
+ msm_mux_pri_mi2s_ws,
+ msm_mux_prng_rosc,
+ msm_mux_pwr_crypto,
+ msm_mux_pwr_modem,
+ msm_mux_pwr_nav,
+ msm_mux_qdss_cti0_a,
+ msm_mux_qdss_cti0_b,
+ msm_mux_qdss_cti1_a,
+ msm_mux_qdss_cti1_b,
+ msm_mux_qdss_gpio,
+ msm_mux_qdss_gpio0,
+ msm_mux_qdss_gpio1,
+ msm_mux_qdss_gpio10,
+ msm_mux_qdss_gpio11,
+ msm_mux_qdss_gpio12,
+ msm_mux_qdss_gpio13,
+ msm_mux_qdss_gpio14,
+ msm_mux_qdss_gpio15,
+ msm_mux_qdss_gpio2,
+ msm_mux_qdss_gpio3,
+ msm_mux_qdss_gpio4,
+ msm_mux_qdss_gpio5,
+ msm_mux_qdss_gpio6,
+ msm_mux_qdss_gpio7,
+ msm_mux_qdss_gpio8,
+ msm_mux_qdss_gpio9,
+ msm_mux_qlink_enable,
+ msm_mux_qlink_request,
+ msm_mux_qspi_clk,
+ msm_mux_qspi_cs,
+ msm_mux_qspi_data0,
+ msm_mux_qspi_data1,
+ msm_mux_qspi_data2,
+ msm_mux_qspi_data3,
+ msm_mux_qspi_resetn,
+ msm_mux_sec_mi2s,
+ msm_mux_sndwire_clk,
+ msm_mux_sndwire_data,
+ msm_mux_sp_cmu,
+ msm_mux_ssc_irq,
+ msm_mux_tgu_ch0,
+ msm_mux_tgu_ch1,
+ msm_mux_tsense_pwm1,
+ msm_mux_tsense_pwm2,
+ msm_mux_uim1_clk,
+ msm_mux_uim1_data,
+ msm_mux_uim1_present,
+ msm_mux_uim1_reset,
+ msm_mux_uim2_clk,
+ msm_mux_uim2_data,
+ msm_mux_uim2_present,
+ msm_mux_uim2_reset,
+ msm_mux_uim_batt,
+ msm_mux_vfr_1,
+ msm_mux_vsense_clkout,
+ msm_mux_vsense_data0,
+ msm_mux_vsense_data1,
+ msm_mux_vsense_mode,
+ msm_mux_wlan1_adc0,
+ msm_mux_wlan1_adc1,
+ msm_mux_wlan2_adc0,
+ msm_mux_wlan2_adc1,
+ msm_mux__,
+};
+
+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",
+};
+
+static const char * const adsp_ext_groups[] = {
+ "gpio65",
+};
+static const char * const agera_pll_groups[] = {
+ "gpio34", "gpio36",
+};
+static const char * const atest_char0_groups[] = {
+ "gpio62",
+};
+static const char * const atest_char1_groups[] = {
+ "gpio61",
+};
+static const char * const atest_char2_groups[] = {
+ "gpio60",
+};
+static const char * const atest_char3_groups[] = {
+ "gpio59",
+};
+static const char * const atest_char_groups[] = {
+ "gpio58",
+};
+static const char * const atest_gpsadc0_groups[] = {
+ "gpio1",
+};
+static const char * const atest_gpsadc1_groups[] = {
+ "gpio0",
+};
+static const char * const atest_tsens2_groups[] = {
+ "gpio3",
+};
+static const char * const atest_tsens_groups[] = {
+ "gpio36",
+};
+static const char * const atest_usb10_groups[] = {
+ "gpio11",
+};
+static const char * const atest_usb11_groups[] = {
+ "gpio10",
+};
+static const char * const atest_usb12_groups[] = {
+ "gpio9",
+};
+static const char * const atest_usb13_groups[] = {
+ "gpio8",
+};
+static const char * const atest_usb1_groups[] = {
+ "gpio3",
+};
+static const char * const atest_usb20_groups[] = {
+ "gpio56",
+};
+static const char * const atest_usb21_groups[] = {
+ "gpio36",
+};
+static const char * const atest_usb22_groups[] = {
+ "gpio57",
+};
+static const char * const atest_usb23_groups[] = {
+ "gpio37",
+};
+static const char * const atest_usb2_groups[] = {
+ "gpio35",
+};
+static const char * const audio_ref_groups[] = {
+ "gpio62",
+};
+static const char * const bimc_dte0_groups[] = {
+ "gpio9", "gpio11",
+};
+static const char * const bimc_dte1_groups[] = {
+ "gpio8", "gpio10",
+};
+static const char * const blsp_i2c1_groups[] = {
+ "gpio2", "gpio3",
+};
+static const char * const blsp_i2c2_groups[] = {
+ "gpio6", "gpio7",
+};
+static const char * const blsp_i2c3_groups[] = {
+ "gpio10", "gpio11",
+};
+static const char * const blsp_i2c4_groups[] = {
+ "gpio14", "gpio15",
+};
+static const char * const blsp_i2c5_groups[] = {
+ "gpio18", "gpio19",
+};
+static const char * const blsp_i2c6_groups[] = {
+ "gpio22", "gpio23",
+};
+static const char * const blsp_i2c7_groups[] = {
+ "gpio26", "gpio27",
+};
+static const char * const blsp_i2c8_a_groups[] = {
+ "gpio30", "gpio31",
+};
+static const char * const blsp_i2c8_b_groups[] = {
+ "gpio44", "gpio52",
+};
+static const char * const blsp_spi1_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3", "gpio46",
+};
+static const char * const blsp_spi2_groups[] = {
+ "gpio4", "gpio5", "gpio6", "gpio7",
+};
+static const char * const blsp_spi3_cs1_groups[] = {
+ "gpio30",
+};
+static const char * const blsp_spi3_cs2_groups[] = {
+ "gpio65",
+};
+static const char * const blsp_spi3_groups[] = {
+ "gpio8", "gpio9", "gpio10", "gpio11",
+};
+static const char * const blsp_spi4_groups[] = {
+ "gpio12", "gpio13", "gpio14", "gpio15",
+};
+static const char * const blsp_spi5_groups[] = {
+ "gpio16", "gpio17", "gpio18", "gpio19",
+};
+static const char * const blsp_spi6_groups[] = {
+ "gpio49", "gpio52", "gpio22", "gpio23",
+};
+static const char * const blsp_spi7_groups[] = {
+ "gpio24", "gpio25", "gpio26", "gpio27",
+};
+static const char * const blsp_spi8_a_groups[] = {
+ "gpio28", "gpio29", "gpio30", "gpio31",
+};
+static const char * const blsp_spi8_b_groups[] = {
+ "gpio40", "gpio41", "gpio44", "gpio52",
+};
+static const char * const blsp_spi8_cs1_groups[] = {
+ "gpio64",
+};
+static const char * const blsp_spi8_cs2_groups[] = {
+ "gpio76",
+};
+static const char * const blsp_uart1_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3",
+};
+static const char * const blsp_uart2_groups[] = {
+ "gpio4", "gpio5", "gpio6", "gpio7",
+};
+static const char * const blsp_uart5_groups[] = {
+ "gpio16", "gpio17", "gpio18", "gpio19",
+};
+static const char * const blsp_uart6_a_groups[] = {
+ "gpio24", "gpio25", "gpio26", "gpio27",
+};
+static const char * const blsp_uart6_b_groups[] = {
+ "gpio28", "gpio29", "gpio30", "gpio31",
+};
+static const char * const blsp_uim1_groups[] = {
+ "gpio0", "gpio1",
+};
+static const char * const blsp_uim2_groups[] = {
+ "gpio4", "gpio5",
+};
+static const char * const blsp_uim5_groups[] = {
+ "gpio16", "gpio17",
+};
+static const char * const blsp_uim6_groups[] = {
+ "gpio20", "gpio21",
+};
+static const char * const cam_mclk_groups[] = {
+ "gpio32", "gpio33", "gpio34", "gpio35",
+};
+static const char * const cci_async_groups[] = {
+ "gpio45",
+};
+static const char * const cci_i2c_groups[] = {
+ "gpio36", "gpio37", "gpio38", "gpio39",
+};
+static const char * const cri_trng0_groups[] = {
+ "gpio60",
+};
+static const char * const cri_trng1_groups[] = {
+ "gpio61",
+};
+static const char * const cri_trng_groups[] = {
+ "gpio62",
+};
+static const char * const dbg_out_groups[] = {
+ "gpio11",
+};
+static const char * const ddr_bist_groups[] = {
+ "gpio3", "gpio8", "gpio9", "gpio10",
+};
+static const char * const gcc_gp1_groups[] = {
+ "gpio57", "gpio78",
+};
+static const char * const gcc_gp2_groups[] = {
+ "gpio58", "gpio81",
+};
+static const char * const gcc_gp3_groups[] = {
+ "gpio59", "gpio82",
+};
+static const char * const gps_tx_a_groups[] = {
+ "gpio65",
+};
+static const char * const gps_tx_b_groups[] = {
+ "gpio98",
+};
+static const char * const gps_tx_c_groups[] = {
+ "gpio80",
+};
+static const char * const isense_dbg_groups[] = {
+ "gpio68",
+};
+static const char * const jitter_bist_groups[] = {
+ "gpio35",
+};
+static const char * const ldo_en_groups[] = {
+ "gpio97",
+};
+static const char * const ldo_update_groups[] = {
+ "gpio98",
+};
+static const char * const m_voc_groups[] = {
+ "gpio28",
+};
+static const char * const mdp_vsync_groups[] = {
+ "gpio59", "gpio74",
+};
+static const char * const mdss_vsync0_groups[] = {
+ "gpio42",
+};
+static const char * const mdss_vsync1_groups[] = {
+ "gpio42",
+};
+static const char * const mdss_vsync2_groups[] = {
+ "gpio42",
+};
+static const char * const mdss_vsync3_groups[] = {
+ "gpio42",
+};
+static const char * const mss_lte_groups[] = {
+ "gpio81", "gpio82",
+};
+static const char * const nav_pps_a_groups[] = {
+ "gpio65",
+};
+static const char * const nav_pps_b_groups[] = {
+ "gpio98",
+};
+static const char * const nav_pps_c_groups[] = {
+ "gpio80",
+};
+static const char * const pa_indicator_groups[] = {
+ "gpio92",
+};
+static const char * const phase_flag0_groups[] = {
+ "gpio68",
+};
+static const char * const phase_flag1_groups[] = {
+ "gpio48",
+};
+static const char * const phase_flag2_groups[] = {
+ "gpio49",
+};
+static const char * const phase_flag3_groups[] = {
+ "gpio4",
+};
+static const char * const phase_flag4_groups[] = {
+ "gpio57",
+};
+static const char * const phase_flag5_groups[] = {
+ "gpio17",
+};
+static const char * const phase_flag6_groups[] = {
+ "gpio53",
+};
+static const char * const phase_flag7_groups[] = {
+ "gpio69",
+};
+static const char * const phase_flag8_groups[] = {
+ "gpio70",
+};
+static const char * const phase_flag9_groups[] = {
+ "gpio50",
+};
+static const char * const phase_flag10_groups[] = {
+ "gpio56",
+};
+static const char * const phase_flag11_groups[] = {
+ "gpio21",
+};
+static const char * const phase_flag12_groups[] = {
+ "gpio22",
+};
+static const char * const phase_flag13_groups[] = {
+ "gpio23",
+};
+static const char * const phase_flag14_groups[] = {
+ "gpio5",
+};
+static const char * const phase_flag15_groups[] = {
+ "gpio51",
+};
+static const char * const phase_flag16_groups[] = {
+ "gpio52",
+};
+static const char * const phase_flag17_groups[] = {
+ "gpio24",
+};
+static const char * const phase_flag18_groups[] = {
+ "gpio25",
+};
+static const char * const phase_flag19_groups[] = {
+ "gpio26",
+};
+static const char * const phase_flag20_groups[] = {
+ "gpio27",
+};
+static const char * const phase_flag21_groups[] = {
+ "gpio28",
+};
+static const char * const phase_flag22_groups[] = {
+ "gpio29",
+};
+static const char * const phase_flag23_groups[] = {
+ "gpio30",
+};
+static const char * const phase_flag24_groups[] = {
+ "gpio31",
+};
+static const char * const phase_flag25_groups[] = {
+ "gpio55",
+};
+static const char * const phase_flag26_groups[] = {
+ "gpio12",
+};
+static const char * const phase_flag27_groups[] = {
+ "gpio13",
+};
+static const char * const phase_flag28_groups[] = {
+ "gpio14",
+};
+static const char * const phase_flag29_groups[] = {
+ "gpio54",
+};
+static const char * const phase_flag30_groups[] = {
+ "gpio47",
+};
+static const char * const phase_flag31_groups[] = {
+ "gpio6",
+};
+static const char * const pll_bypassnl_groups[] = {
+ "gpio36",
+};
+static const char * const pll_reset_groups[] = {
+ "gpio37",
+};
+static const char * const pri_mi2s_groups[] = {
+ "gpio12", "gpio14", "gpio15", "gpio61",
+};
+static const char * const pri_mi2s_ws_groups[] = {
+ "gpio13",
+};
+static const char * const prng_rosc_groups[] = {
+ "gpio102",
+};
+static const char * const pwr_crypto_groups[] = {
+ "gpio33",
+};
+static const char * const pwr_modem_groups[] = {
+ "gpio31",
+};
+static const char * const pwr_nav_groups[] = {
+ "gpio32",
+};
+static const char * const qdss_cti0_a_groups[] = {
+ "gpio49", "gpio50",
+};
+static const char * const qdss_cti0_b_groups[] = {
+ "gpio13", "gpio21",
+};
+static const char * const qdss_cti1_a_groups[] = {
+ "gpio53", "gpio55",
+};
+static const char * const qdss_cti1_b_groups[] = {
+ "gpio12", "gpio66",
+};
+static const char * const qdss_gpio0_groups[] = {
+ "gpio32", "gpio67",
+};
+static const char * const qdss_gpio10_groups[] = {
+ "gpio43", "gpio77",
+};
+static const char * const qdss_gpio11_groups[] = {
+ "gpio44", "gpio79",
+};
+static const char * const qdss_gpio12_groups[] = {
+ "gpio45", "gpio80",
+};
+static const char * const qdss_gpio13_groups[] = {
+ "gpio46", "gpio78",
+};
+static const char * const qdss_gpio14_groups[] = {
+ "gpio47", "gpio72",
+};
+static const char * const qdss_gpio15_groups[] = {
+ "gpio48", "gpio73",
+};
+static const char * const qdss_gpio1_groups[] = {
+ "gpio33", "gpio63",
+};
+static const char * const qdss_gpio2_groups[] = {
+ "gpio34", "gpio64",
+};
+static const char * const qdss_gpio3_groups[] = {
+ "gpio35", "gpio56",
+};
+static const char * const qdss_gpio4_groups[] = {
+ "gpio0", "gpio36",
+};
+static const char * const qdss_gpio5_groups[] = {
+ "gpio1", "gpio37",
+};
+static const char * const qdss_gpio6_groups[] = {
+ "gpio38", "gpio70",
+};
+static const char * const qdss_gpio7_groups[] = {
+ "gpio39", "gpio71",
+};
+static const char * const qdss_gpio8_groups[] = {
+ "gpio51", "gpio75",
+};
+static const char * const qdss_gpio9_groups[] = {
+ "gpio42", "gpio76",
+};
+static const char * const qdss_gpio_groups[] = {
+ "gpio31", "gpio52", "gpio68", "gpio69",
+};
+static const char * const qlink_enable_groups[] = {
+ "gpio100",
+};
+static const char * const qlink_request_groups[] = {
+ "gpio99",
+};
+static const char * const qspi_clk_groups[] = {
+ "gpio47",
+};
+static const char * const qspi_cs_groups[] = {
+ "gpio43", "gpio50",
+};
+static const char * const qspi_data0_groups[] = {
+ "gpio33",
+};
+static const char * const qspi_data1_groups[] = {
+ "gpio34",
+};
+static const char * const qspi_data2_groups[] = {
+ "gpio35",
+};
+static const char * const qspi_data3_groups[] = {
+ "gpio51",
+};
+static const char * const qspi_resetn_groups[] = {
+ "gpio48",
+};
+static const char * const sec_mi2s_groups[] = {
+ "gpio24", "gpio25", "gpio26", "gpio27", "gpio62",
+};
+static const char * const sndwire_clk_groups[] = {
+ "gpio24",
+};
+static const char * const sndwire_data_groups[] = {
+ "gpio25",
+};
+static const char * const sp_cmu_groups[] = {
+ "gpio64",
+};
+static const char * const ssc_irq_groups[] = {
+ "gpio67", "gpio68", "gpio69", "gpio70", "gpio71", "gpio72", "gpio74",
+ "gpio75", "gpio76",
+};
+static const char * const tgu_ch0_groups[] = {
+ "gpio0",
+};
+static const char * const tgu_ch1_groups[] = {
+ "gpio1",
+};
+static const char * const tsense_pwm1_groups[] = {
+ "gpio71",
+};
+static const char * const tsense_pwm2_groups[] = {
+ "gpio71",
+};
+static const char * const uim1_clk_groups[] = {
+ "gpio88",
+};
+static const char * const uim1_data_groups[] = {
+ "gpio87",
+};
+static const char * const uim1_present_groups[] = {
+ "gpio90",
+};
+static const char * const uim1_reset_groups[] = {
+ "gpio89",
+};
+static const char * const uim2_clk_groups[] = {
+ "gpio84",
+};
+static const char * const uim2_data_groups[] = {
+ "gpio83",
+};
+static const char * const uim2_present_groups[] = {
+ "gpio86",
+};
+static const char * const uim2_reset_groups[] = {
+ "gpio85",
+};
+static const char * const uim_batt_groups[] = {
+ "gpio91",
+};
+static const char * const vfr_1_groups[] = {
+ "gpio27",
+};
+static const char * const vsense_clkout_groups[] = {
+ "gpio24",
+};
+static const char * const vsense_data0_groups[] = {
+ "gpio21",
+};
+static const char * const vsense_data1_groups[] = {
+ "gpio22",
+};
+static const char * const vsense_mode_groups[] = {
+ "gpio23",
+};
+static const char * const wlan1_adc0_groups[] = {
+ "gpio9",
+};
+static const char * const wlan1_adc1_groups[] = {
+ "gpio8",
+};
+static const char * const wlan2_adc0_groups[] = {
+ "gpio11",
+};
+static const char * const wlan2_adc1_groups[] = {
+ "gpio10",
+};
+
+static const struct msm_function sdm660_functions[] = {
+ FUNCTION(adsp_ext),
+ FUNCTION(agera_pll),
+ FUNCTION(atest_char),
+ FUNCTION(atest_char0),
+ FUNCTION(atest_char1),
+ FUNCTION(atest_char2),
+ FUNCTION(atest_char3),
+ FUNCTION(atest_gpsadc0),
+ FUNCTION(atest_gpsadc1),
+ FUNCTION(atest_tsens),
+ FUNCTION(atest_tsens2),
+ FUNCTION(atest_usb1),
+ FUNCTION(atest_usb10),
+ FUNCTION(atest_usb11),
+ FUNCTION(atest_usb12),
+ FUNCTION(atest_usb13),
+ FUNCTION(atest_usb2),
+ FUNCTION(atest_usb20),
+ FUNCTION(atest_usb21),
+ FUNCTION(atest_usb22),
+ FUNCTION(atest_usb23),
+ FUNCTION(audio_ref),
+ FUNCTION(bimc_dte0),
+ FUNCTION(bimc_dte1),
+ FUNCTION(blsp_i2c1),
+ FUNCTION(blsp_i2c2),
+ FUNCTION(blsp_i2c3),
+ FUNCTION(blsp_i2c4),
+ FUNCTION(blsp_i2c5),
+ FUNCTION(blsp_i2c6),
+ FUNCTION(blsp_i2c7),
+ FUNCTION(blsp_i2c8_a),
+ FUNCTION(blsp_i2c8_b),
+ FUNCTION(blsp_spi1),
+ FUNCTION(blsp_spi2),
+ FUNCTION(blsp_spi3),
+ FUNCTION(blsp_spi3_cs1),
+ FUNCTION(blsp_spi3_cs2),
+ FUNCTION(blsp_spi4),
+ FUNCTION(blsp_spi5),
+ FUNCTION(blsp_spi6),
+ FUNCTION(blsp_spi7),
+ FUNCTION(blsp_spi8_a),
+ FUNCTION(blsp_spi8_b),
+ FUNCTION(blsp_spi8_cs1),
+ FUNCTION(blsp_spi8_cs2),
+ FUNCTION(blsp_uart1),
+ FUNCTION(blsp_uart2),
+ FUNCTION(blsp_uart5),
+ FUNCTION(blsp_uart6_a),
+ FUNCTION(blsp_uart6_b),
+ FUNCTION(blsp_uim1),
+ FUNCTION(blsp_uim2),
+ FUNCTION(blsp_uim5),
+ FUNCTION(blsp_uim6),
+ FUNCTION(cam_mclk),
+ FUNCTION(cci_async),
+ FUNCTION(cci_i2c),
+ FUNCTION(cri_trng),
+ FUNCTION(cri_trng0),
+ FUNCTION(cri_trng1),
+ FUNCTION(dbg_out),
+ FUNCTION(ddr_bist),
+ FUNCTION(gcc_gp1),
+ FUNCTION(gcc_gp2),
+ FUNCTION(gcc_gp3),
+ FUNCTION(gpio),
+ FUNCTION(gps_tx_a),
+ FUNCTION(gps_tx_b),
+ FUNCTION(gps_tx_c),
+ FUNCTION(isense_dbg),
+ FUNCTION(jitter_bist),
+ FUNCTION(ldo_en),
+ FUNCTION(ldo_update),
+ FUNCTION(m_voc),
+ FUNCTION(mdp_vsync),
+ FUNCTION(mdss_vsync0),
+ FUNCTION(mdss_vsync1),
+ FUNCTION(mdss_vsync2),
+ FUNCTION(mdss_vsync3),
+ FUNCTION(mss_lte),
+ FUNCTION(nav_pps_a),
+ FUNCTION(nav_pps_b),
+ FUNCTION(nav_pps_c),
+ FUNCTION(pa_indicator),
+ FUNCTION(phase_flag0),
+ FUNCTION(phase_flag1),
+ FUNCTION(phase_flag2),
+ FUNCTION(phase_flag3),
+ FUNCTION(phase_flag4),
+ FUNCTION(phase_flag5),
+ FUNCTION(phase_flag6),
+ FUNCTION(phase_flag7),
+ FUNCTION(phase_flag8),
+ FUNCTION(phase_flag9),
+ FUNCTION(phase_flag10),
+ FUNCTION(phase_flag11),
+ FUNCTION(phase_flag12),
+ FUNCTION(phase_flag13),
+ FUNCTION(phase_flag14),
+ FUNCTION(phase_flag15),
+ FUNCTION(phase_flag16),
+ FUNCTION(phase_flag17),
+ FUNCTION(phase_flag18),
+ FUNCTION(phase_flag19),
+ FUNCTION(phase_flag20),
+ FUNCTION(phase_flag21),
+ FUNCTION(phase_flag22),
+ FUNCTION(phase_flag23),
+ FUNCTION(phase_flag24),
+ FUNCTION(phase_flag25),
+ FUNCTION(phase_flag26),
+ FUNCTION(phase_flag27),
+ FUNCTION(phase_flag28),
+ FUNCTION(phase_flag29),
+ FUNCTION(phase_flag30),
+ FUNCTION(phase_flag31),
+ FUNCTION(pll_bypassnl),
+ FUNCTION(pll_reset),
+ FUNCTION(pri_mi2s),
+ FUNCTION(pri_mi2s_ws),
+ FUNCTION(prng_rosc),
+ FUNCTION(pwr_crypto),
+ FUNCTION(pwr_modem),
+ FUNCTION(pwr_nav),
+ FUNCTION(qdss_cti0_a),
+ FUNCTION(qdss_cti0_b),
+ FUNCTION(qdss_cti1_a),
+ FUNCTION(qdss_cti1_b),
+ FUNCTION(qdss_gpio),
+ FUNCTION(qdss_gpio0),
+ FUNCTION(qdss_gpio1),
+ FUNCTION(qdss_gpio10),
+ FUNCTION(qdss_gpio11),
+ FUNCTION(qdss_gpio12),
+ FUNCTION(qdss_gpio13),
+ FUNCTION(qdss_gpio14),
+ FUNCTION(qdss_gpio15),
+ FUNCTION(qdss_gpio2),
+ FUNCTION(qdss_gpio3),
+ FUNCTION(qdss_gpio4),
+ FUNCTION(qdss_gpio5),
+ FUNCTION(qdss_gpio6),
+ FUNCTION(qdss_gpio7),
+ FUNCTION(qdss_gpio8),
+ FUNCTION(qdss_gpio9),
+ FUNCTION(qlink_enable),
+ FUNCTION(qlink_request),
+ FUNCTION(qspi_clk),
+ FUNCTION(qspi_cs),
+ FUNCTION(qspi_data0),
+ FUNCTION(qspi_data1),
+ FUNCTION(qspi_data2),
+ FUNCTION(qspi_data3),
+ FUNCTION(qspi_resetn),
+ FUNCTION(sec_mi2s),
+ FUNCTION(sndwire_clk),
+ FUNCTION(sndwire_data),
+ FUNCTION(sp_cmu),
+ FUNCTION(ssc_irq),
+ FUNCTION(tgu_ch0),
+ FUNCTION(tgu_ch1),
+ FUNCTION(tsense_pwm1),
+ FUNCTION(tsense_pwm2),
+ FUNCTION(uim1_clk),
+ FUNCTION(uim1_data),
+ FUNCTION(uim1_present),
+ FUNCTION(uim1_reset),
+ FUNCTION(uim2_clk),
+ FUNCTION(uim2_data),
+ FUNCTION(uim2_present),
+ FUNCTION(uim2_reset),
+ FUNCTION(uim_batt),
+ FUNCTION(vfr_1),
+ FUNCTION(vsense_clkout),
+ FUNCTION(vsense_data0),
+ FUNCTION(vsense_data1),
+ FUNCTION(vsense_mode),
+ FUNCTION(wlan1_adc0),
+ FUNCTION(wlan1_adc1),
+ FUNCTION(wlan2_adc0),
+ FUNCTION(wlan2_adc1),
+};
+
+static const struct msm_pingroup sdm660_groups[] = {
+ PINGROUP(0, SOUTH, blsp_spi1, blsp_uart1, blsp_uim1, tgu_ch0, _, _, qdss_gpio4, atest_gpsadc1, _),
+ PINGROUP(1, SOUTH, blsp_spi1, blsp_uart1, blsp_uim1, tgu_ch1, _, _, qdss_gpio5, atest_gpsadc0, _),
+ PINGROUP(2, SOUTH, blsp_spi1, blsp_uart1, blsp_i2c1, _, _, _, _, _, _),
+ PINGROUP(3, SOUTH, blsp_spi1, blsp_uart1, blsp_i2c1, ddr_bist, _, _, atest_tsens2, atest_usb1, _),
+ PINGROUP(4, NORTH, blsp_spi2, blsp_uim2, blsp_uart2, phase_flag3, _, _, _, _, _),
+ PINGROUP(5, SOUTH, blsp_spi2, blsp_uim2, blsp_uart2, phase_flag14, _, _, _, _, _),
+ PINGROUP(6, SOUTH, blsp_spi2, blsp_i2c2, blsp_uart2, phase_flag31, _, _, _, _, _),
+ PINGROUP(7, SOUTH, blsp_spi2, blsp_i2c2, blsp_uart2, _, _, _, _, _, _),
+ PINGROUP(8, NORTH, blsp_spi3, ddr_bist, _, _, _, wlan1_adc1, atest_usb13, bimc_dte1, _),
+ PINGROUP(9, NORTH, blsp_spi3, ddr_bist, _, _, _, wlan1_adc0, atest_usb12, bimc_dte0, _),
+ PINGROUP(10, NORTH, blsp_spi3, blsp_i2c3, ddr_bist, _, _, wlan2_adc1, atest_usb11, bimc_dte1, _),
+ PINGROUP(11, NORTH, blsp_spi3, blsp_i2c3, _, dbg_out, wlan2_adc0, atest_usb10, bimc_dte0, _, _),
+ PINGROUP(12, NORTH, blsp_spi4, pri_mi2s, _, phase_flag26, qdss_cti1_b, _, _, _, _),
+ PINGROUP(13, NORTH, blsp_spi4, _, pri_mi2s_ws, _, _, phase_flag27, qdss_cti0_b, _, _),
+ PINGROUP(14, NORTH, blsp_spi4, blsp_i2c4, pri_mi2s, _, phase_flag28, _, _, _, _),
+ PINGROUP(15, NORTH, blsp_spi4, blsp_i2c4, pri_mi2s, _, _, _, _, _, _),
+ PINGROUP(16, CENTER, blsp_uart5, blsp_spi5, blsp_uim5, _, _, _, _, _, _),
+ PINGROUP(17, CENTER, blsp_uart5, blsp_spi5, blsp_uim5, _, phase_flag5, _, _, _, _),
+ PINGROUP(18, CENTER, blsp_uart5, blsp_spi5, blsp_i2c5, _, _, _, _, _, _),
+ PINGROUP(19, CENTER, blsp_uart5, blsp_spi5, blsp_i2c5, _, _, _, _, _, _),
+ PINGROUP(20, SOUTH, _, _, blsp_uim6, _, _, _, _, _, _),
+ PINGROUP(21, SOUTH, _, _, blsp_uim6, _, phase_flag11, qdss_cti0_b, vsense_data0, _, _),
+ PINGROUP(22, CENTER, blsp_spi6, _, blsp_i2c6, _, phase_flag12, vsense_data1, _, _, _),
+ PINGROUP(23, CENTER, blsp_spi6, _, blsp_i2c6, _, phase_flag13, vsense_mode, _, _, _),
+ PINGROUP(24, NORTH, blsp_spi7, blsp_uart6_a, sec_mi2s, sndwire_clk, _, _, phase_flag17, vsense_clkout, _),
+ PINGROUP(25, NORTH, blsp_spi7, blsp_uart6_a, sec_mi2s, sndwire_data, _, _, phase_flag18, _, _),
+ PINGROUP(26, NORTH, blsp_spi7, blsp_uart6_a, blsp_i2c7, sec_mi2s, _, phase_flag19, _, _, _),
+ PINGROUP(27, NORTH, blsp_spi7, blsp_uart6_a, blsp_i2c7, vfr_1, sec_mi2s, _, phase_flag20, _, _),
+ PINGROUP(28, CENTER, blsp_spi8_a, blsp_uart6_b, m_voc, _, phase_flag21, _, _, _, _),
+ PINGROUP(29, CENTER, blsp_spi8_a, blsp_uart6_b, _, _, phase_flag22, _, _, _, _),
+ PINGROUP(30, CENTER, blsp_spi8_a, blsp_uart6_b, blsp_i2c8_a, blsp_spi3_cs1, _, phase_flag23, _, _, _),
+ PINGROUP(31, CENTER, blsp_spi8_a, blsp_uart6_b, blsp_i2c8_a, pwr_modem, _, phase_flag24, qdss_gpio, _, _),
+ PINGROUP(32, SOUTH, cam_mclk, pwr_nav, _, _, qdss_gpio0, _, _, _, _),
+ PINGROUP(33, SOUTH, cam_mclk, qspi_data0, pwr_crypto, _, _, qdss_gpio1, _, _, _),
+ PINGROUP(34, SOUTH, cam_mclk, qspi_data1, agera_pll, _, _, qdss_gpio2, _, _, _),
+ PINGROUP(35, SOUTH, cam_mclk, qspi_data2, jitter_bist, _, _, qdss_gpio3, _, atest_usb2, _),
+ PINGROUP(36, SOUTH, cci_i2c, pll_bypassnl, agera_pll, _, _, qdss_gpio4, atest_tsens, atest_usb21, _),
+ PINGROUP(37, SOUTH, cci_i2c, pll_reset, _, _, qdss_gpio5, atest_usb23, _, _, _),
+ PINGROUP(38, SOUTH, cci_i2c, _, _, qdss_gpio6, _, _, _, _, _),
+ PINGROUP(39, SOUTH, cci_i2c, _, _, qdss_gpio7, _, _, _, _, _),
+ PINGROUP(40, SOUTH, _, _, blsp_spi8_b, _, _, _, _, _, _),
+ PINGROUP(41, SOUTH, _, _, blsp_spi8_b, _, _, _, _, _, _),
+ PINGROUP(42, SOUTH, mdss_vsync0, mdss_vsync1, mdss_vsync2, mdss_vsync3, _, _, qdss_gpio9, _, _),
+ PINGROUP(43, SOUTH, _, _, qspi_cs, _, _, qdss_gpio10, _, _, _),
+ PINGROUP(44, SOUTH, _, _, blsp_spi8_b, blsp_i2c8_b, _, _, qdss_gpio11, _, _),
+ PINGROUP(45, SOUTH, cci_async, _, _, qdss_gpio12, _, _, _, _, _),
+ PINGROUP(46, SOUTH, blsp_spi1, _, _, qdss_gpio13, _, _, _, _, _),
+ PINGROUP(47, SOUTH, qspi_clk, _, phase_flag30, qdss_gpio14, _, _, _, _, _),
+ PINGROUP(48, SOUTH, _, phase_flag1, qdss_gpio15, _, _, _, _, _, _),
+ PINGROUP(49, SOUTH, blsp_spi6, phase_flag2, qdss_cti0_a, _, _, _, _, _, _),
+ PINGROUP(50, SOUTH, qspi_cs, _, phase_flag9, qdss_cti0_a, _, _, _, _, _),
+ PINGROUP(51, SOUTH, qspi_data3, _, phase_flag15, qdss_gpio8, _, _, _, _, _),
+ PINGROUP(52, SOUTH, _, blsp_spi8_b, blsp_i2c8_b, blsp_spi6, phase_flag16, qdss_gpio, _, _, _),
+ PINGROUP(53, NORTH, _, phase_flag6, qdss_cti1_a, _, _, _, _, _, _),
+ PINGROUP(54, NORTH, _, _, phase_flag29, _, _, _, _, _, _),
+ PINGROUP(55, SOUTH, _, phase_flag25, qdss_cti1_a, _, _, _, _, _, _),
+ PINGROUP(56, SOUTH, _, phase_flag10, qdss_gpio3, _, atest_usb20, _, _, _, _),
+ PINGROUP(57, SOUTH, gcc_gp1, _, phase_flag4, atest_usb22, _, _, _, _, _),
+ PINGROUP(58, SOUTH, _, gcc_gp2, _, _, atest_char, _, _, _, _),
+ PINGROUP(59, NORTH, mdp_vsync, gcc_gp3, _, _, atest_char3, _, _, _, _),
+ PINGROUP(60, NORTH, cri_trng0, _, _, atest_char2, _, _, _, _, _),
+ PINGROUP(61, NORTH, pri_mi2s, cri_trng1, _, _, atest_char1, _, _, _, _),
+ PINGROUP(62, NORTH, sec_mi2s, audio_ref, _, cri_trng, _, _, atest_char0, _, _),
+ PINGROUP(63, NORTH, _, _, _, qdss_gpio1, _, _, _, _, _),
+ PINGROUP(64, SOUTH, blsp_spi8_cs1, sp_cmu, _, _, qdss_gpio2, _, _, _, _),
+ PINGROUP(65, SOUTH, _, nav_pps_a, nav_pps_a, gps_tx_a, blsp_spi3_cs2, adsp_ext, _, _, _),
+ PINGROUP(66, NORTH, _, _, qdss_cti1_b, _, _, _, _, _, _),
+ PINGROUP(67, NORTH, _, _, qdss_gpio0, _, _, _, _, _, _),
+ PINGROUP(68, NORTH, isense_dbg, _, phase_flag0, qdss_gpio, _, _, _, _, _),
+ PINGROUP(69, NORTH, _, phase_flag7, qdss_gpio, _, _, _, _, _, _),
+ PINGROUP(70, NORTH, _, phase_flag8, qdss_gpio6, _, _, _, _, _, _),
+ PINGROUP(71, NORTH, _, _, qdss_gpio7, tsense_pwm1, tsense_pwm2, _, _, _, _),
+ PINGROUP(72, NORTH, _, qdss_gpio14, _, _, _, _, _, _, _),
+ PINGROUP(73, NORTH, _, _, qdss_gpio15, _, _, _, _, _, _),
+ PINGROUP(74, NORTH, mdp_vsync, _, _, _, _, _, _, _, _),
+ PINGROUP(75, NORTH, _, _, qdss_gpio8, _, _, _, _, _, _),
+ PINGROUP(76, NORTH, blsp_spi8_cs2, _, _, _, qdss_gpio9, _, _, _, _),
+ PINGROUP(77, NORTH, _, _, qdss_gpio10, _, _, _, _, _, _),
+ PINGROUP(78, NORTH, gcc_gp1, _, qdss_gpio13, _, _, _, _, _, _),
+ PINGROUP(79, SOUTH, _, _, qdss_gpio11, _, _, _, _, _, _),
+ PINGROUP(80, SOUTH, nav_pps_b, nav_pps_b, gps_tx_c, _, _, qdss_gpio12, _, _, _),
+ PINGROUP(81, CENTER, mss_lte, gcc_gp2, _, _, _, _, _, _, _),
+ PINGROUP(82, CENTER, mss_lte, gcc_gp3, _, _, _, _, _, _, _),
+ PINGROUP(83, SOUTH, uim2_data, _, _, _, _, _, _, _, _),
+ PINGROUP(84, SOUTH, uim2_clk, _, _, _, _, _, _, _, _),
+ PINGROUP(85, SOUTH, uim2_reset, _, _, _, _, _, _, _, _),
+ PINGROUP(86, SOUTH, uim2_present, _, _, _, _, _, _, _, _),
+ PINGROUP(87, SOUTH, uim1_data, _, _, _, _, _, _, _, _),
+ PINGROUP(88, SOUTH, uim1_clk, _, _, _, _, _, _, _, _),
+ PINGROUP(89, SOUTH, uim1_reset, _, _, _, _, _, _, _, _),
+ PINGROUP(90, SOUTH, uim1_present, _, _, _, _, _, _, _, _),
+ PINGROUP(91, SOUTH, uim_batt, _, _, _, _, _, _, _, _),
+ PINGROUP(92, SOUTH, _, _, pa_indicator, _, _, _, _, _, _),
+ PINGROUP(93, SOUTH, _, _, _, _, _, _, _, _, _),
+ PINGROUP(94, SOUTH, _, _, _, _, _, _, _, _, _),
+ PINGROUP(95, SOUTH, _, _, _, _, _, _, _, _, _),
+ PINGROUP(96, SOUTH, _, _, _, _, _, _, _, _, _),
+ PINGROUP(97, SOUTH, _, ldo_en, _, _, _, _, _, _, _),
+ PINGROUP(98, SOUTH, _, nav_pps_c, nav_pps_c, gps_tx_b, ldo_update, _, _, _, _),
+ PINGROUP(99, SOUTH, qlink_request, _, _, _, _, _, _, _, _),
+ PINGROUP(100, SOUTH, qlink_enable, _, _, _, _, _, _, _, _),
+ PINGROUP(101, SOUTH, _, _, _, _, _, _, _, _, _),
+ PINGROUP(102, SOUTH, _, prng_rosc, _, _, _, _, _, _, _),
+ PINGROUP(103, SOUTH, _, _, _, _, _, _, _, _, _),
+ PINGROUP(104, SOUTH, _, _, _, _, _, _, _, _, _),
+ PINGROUP(105, SOUTH, _, _, _, _, _, _, _, _, _),
+ PINGROUP(106, SOUTH, _, _, _, _, _, _, _, _, _),
+ PINGROUP(107, SOUTH, _, _, _, _, _, _, _, _, _),
+ PINGROUP(108, SOUTH, _, _, _, _, _, _, _, _, _),
+ PINGROUP(109, SOUTH, _, _, _, _, _, _, _, _, _),
+ PINGROUP(110, SOUTH, _, _, _, _, _, _, _, _, _),
+ PINGROUP(111, SOUTH, _, _, _, _, _, _, _, _, _),
+ PINGROUP(112, SOUTH, _, _, _, _, _, _, _, _, _),
+ PINGROUP(113, SOUTH, _, _, _, _, _, _, _, _, _),
+ SDC_QDSD_PINGROUP(sdc1_clk, 0x99a000, 13, 6),
+ SDC_QDSD_PINGROUP(sdc1_cmd, 0x99a000, 11, 3),
+ SDC_QDSD_PINGROUP(sdc1_data, 0x99a000, 9, 0),
+ SDC_QDSD_PINGROUP(sdc2_clk, 0x99b000, 14, 6),
+ SDC_QDSD_PINGROUP(sdc2_cmd, 0x99b000, 11, 3),
+ SDC_QDSD_PINGROUP(sdc2_data, 0x99b000, 9, 0),
+ SDC_QDSD_PINGROUP(sdc1_rclk, 0x99a000, 15, 0),
+};
+
+static const struct msm_pinctrl_soc_data sdm660_pinctrl = {
+ .pins = sdm660_pins,
+ .npins = ARRAY_SIZE(sdm660_pins),
+ .functions = sdm660_functions,
+ .nfunctions = ARRAY_SIZE(sdm660_functions),
+ .groups = sdm660_groups,
+ .ngroups = ARRAY_SIZE(sdm660_groups),
+ .ngpios = 114,
+ .tiles = sdm660_tiles,
+ .ntiles = ARRAY_SIZE(sdm660_tiles),
+};
+
+static int sdm660_pinctrl_probe(struct platform_device *pdev)
+{
+ return msm_pinctrl_probe(pdev, &sdm660_pinctrl);
+}
+
+static const struct of_device_id sdm660_pinctrl_of_match[] = {
+ { .compatible = "qcom,sdm660-pinctrl", },
+ { .compatible = "qcom,sdm630-pinctrl", },
+ { },
+};
+
+static struct platform_driver sdm660_pinctrl_driver = {
+ .driver = {
+ .name = "sdm660-pinctrl",
+ .of_match_table = sdm660_pinctrl_of_match,
+ },
+ .probe = sdm660_pinctrl_probe,
+ .remove = msm_pinctrl_remove,
+};
+
+static int __init sdm660_pinctrl_init(void)
+{
+ return platform_driver_register(&sdm660_pinctrl_driver);
+}
+arch_initcall(sdm660_pinctrl_init);
+
+static void __exit sdm660_pinctrl_exit(void)
+{
+ platform_driver_unregister(&sdm660_pinctrl_driver);
+}
+module_exit(sdm660_pinctrl_exit);
+
+MODULE_DESCRIPTION("QTI sdm660 pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, sdm660_pinctrl_of_match);
diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
index cf82db78e69e..a29efbe08f48 100644
--- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
+++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
@@ -11,7 +11,7 @@
* GNU General Public License for more details.
*/
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c
index 6556dbeae65e..d6ddc47b57ec 100644
--- a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c
+++ b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c
@@ -11,7 +11,7 @@
* GNU General Public License for more details.
*/
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
@@ -319,6 +319,8 @@ static int pmic_mpp_set_mux(struct pinctrl_dev *pctldev, unsigned function,
pad->function = function;
ret = pmic_mpp_write_mode_ctl(state, pad);
+ if (ret < 0)
+ return ret;
val = pad->is_enabled << PMIC_MPP_REG_MASTER_EN_SHIFT;
@@ -343,13 +345,12 @@ static int pmic_mpp_config_get(struct pinctrl_dev *pctldev,
switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
- arg = pad->pullup == PMIC_MPP_PULL_UP_OPEN;
+ if (pad->pullup != PMIC_MPP_PULL_UP_OPEN)
+ return -EINVAL;
+ arg = 1;
break;
case PIN_CONFIG_BIAS_PULL_UP:
switch (pad->pullup) {
- case PMIC_MPP_PULL_UP_OPEN:
- arg = 0;
- break;
case PMIC_MPP_PULL_UP_0P6KOHM:
arg = 600;
break;
@@ -364,13 +365,17 @@ static int pmic_mpp_config_get(struct pinctrl_dev *pctldev,
}
break;
case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
- arg = !pad->is_enabled;
+ if (pad->is_enabled)
+ return -EINVAL;
+ arg = 1;
break;
case PIN_CONFIG_POWER_SOURCE:
arg = pad->power_source;
break;
case PIN_CONFIG_INPUT_ENABLE:
- arg = pad->input_enabled;
+ if (!pad->input_enabled)
+ return -EINVAL;
+ arg = 1;
break;
case PIN_CONFIG_OUTPUT:
arg = pad->out_value;
@@ -382,7 +387,9 @@ static int pmic_mpp_config_get(struct pinctrl_dev *pctldev,
arg = pad->amux_input;
break;
case PMIC_MPP_CONF_PAIRED:
- arg = pad->paired;
+ if (!pad->paired)
+ return -EINVAL;
+ arg = 1;
break;
case PIN_CONFIG_DRIVE_STRENGTH:
arg = pad->drive_strength;
@@ -455,7 +462,7 @@ static int pmic_mpp_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
pad->dtest = arg;
break;
case PIN_CONFIG_DRIVE_STRENGTH:
- arg = pad->drive_strength;
+ pad->drive_strength = arg;
break;
case PMIC_MPP_CONF_AMUX_ROUTE:
if (arg >= PMIC_MPP_AMUX_ROUTE_ABUS4)
@@ -502,6 +509,10 @@ static int pmic_mpp_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
if (ret < 0)
return ret;
+ ret = pmic_mpp_write(state, pad, PMIC_MPP_REG_SINK_CTL, pad->drive_strength);
+ if (ret < 0)
+ return ret;
+
val = pad->is_enabled << PMIC_MPP_REG_MASTER_EN_SHIFT;
return pmic_mpp_write(state, pad, PMIC_MPP_REG_EN_CTL, val);
diff --git a/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c b/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c
index f53e32a9d8fc..6b30bef829ab 100644
--- a/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c
+++ b/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c
@@ -20,7 +20,7 @@
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/slab.h>
#include <linux/regmap.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/interrupt.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
@@ -260,22 +260,32 @@ static int pm8xxx_pin_config_get(struct pinctrl_dev *pctldev,
switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
- arg = pin->bias == PM8XXX_GPIO_BIAS_NP;
+ if (pin->bias != PM8XXX_GPIO_BIAS_NP)
+ return -EINVAL;
+ arg = 1;
break;
case PIN_CONFIG_BIAS_PULL_DOWN:
- arg = pin->bias == PM8XXX_GPIO_BIAS_PD;
+ if (pin->bias != PM8XXX_GPIO_BIAS_PD)
+ return -EINVAL;
+ arg = 1;
break;
case PIN_CONFIG_BIAS_PULL_UP:
- arg = pin->bias <= PM8XXX_GPIO_BIAS_PU_1P5_30;
+ if (pin->bias > PM8XXX_GPIO_BIAS_PU_1P5_30)
+ return -EINVAL;
+ arg = 1;
break;
case PM8XXX_QCOM_PULL_UP_STRENGTH:
arg = pin->pull_up_strength;
break;
case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
- arg = pin->disable;
+ if (!pin->disable)
+ return -EINVAL;
+ arg = 1;
break;
case PIN_CONFIG_INPUT_ENABLE:
- arg = pin->mode == PM8XXX_GPIO_MODE_INPUT;
+ if (pin->mode != PM8XXX_GPIO_MODE_INPUT)
+ return -EINVAL;
+ arg = 1;
break;
case PIN_CONFIG_OUTPUT:
if (pin->mode & PM8XXX_GPIO_MODE_OUTPUT)
@@ -290,10 +300,14 @@ static int pm8xxx_pin_config_get(struct pinctrl_dev *pctldev,
arg = pin->output_strength;
break;
case PIN_CONFIG_DRIVE_PUSH_PULL:
- arg = !pin->open_drain;
+ if (pin->open_drain)
+ return -EINVAL;
+ arg = 1;
break;
case PIN_CONFIG_DRIVE_OPEN_DRAIN:
- arg = pin->open_drain;
+ if (!pin->open_drain)
+ return -EINVAL;
+ arg = 1;
break;
default:
return -EINVAL;
diff --git a/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c b/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c
index 1e513bd6d0a9..1a7dab150ef6 100644
--- a/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c
+++ b/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c
@@ -20,7 +20,7 @@
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/slab.h>
#include <linux/regmap.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/interrupt.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c
index 698c7d8c9a08..ee6ee2338606 100644
--- a/drivers/pinctrl/samsung/pinctrl-samsung.c
+++ b/drivers/pinctrl/samsung/pinctrl-samsung.c
@@ -20,7 +20,7 @@
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/err.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/irqdomain.h>
#include <linux/of_device.h>
#include <linux/spinlock.h>
diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.h b/drivers/pinctrl/samsung/pinctrl-samsung.h
index e571bbd7139b..379f34a9a482 100644
--- a/drivers/pinctrl/samsung/pinctrl-samsung.h
+++ b/drivers/pinctrl/samsung/pinctrl-samsung.h
@@ -19,7 +19,7 @@
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/machine.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
/**
* enum pincfg_type - possible pin configuration types supported.
diff --git a/drivers/pinctrl/sh-pfc/Kconfig b/drivers/pinctrl/sh-pfc/Kconfig
index 43d950c16528..e941ba60d4b7 100644
--- a/drivers/pinctrl/sh-pfc/Kconfig
+++ b/drivers/pinctrl/sh-pfc/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
#
# Renesas SH and SH Mobile PINCTRL drivers
#
@@ -39,6 +40,11 @@ config PINCTRL_PFC_R8A7743
depends on ARCH_R8A7743
select PINCTRL_SH_PFC
+config PINCTRL_PFC_R8A7744
+ def_bool y
+ depends on ARCH_R8A7744
+ select PINCTRL_SH_PFC
+
config PINCTRL_PFC_R8A7745
def_bool y
depends on ARCH_R8A7745
@@ -49,6 +55,16 @@ config PINCTRL_PFC_R8A77470
depends on ARCH_R8A77470
select PINCTRL_SH_PFC
+config PINCTRL_PFC_R8A774A1
+ def_bool y
+ depends on ARCH_R8A774A1
+ select PINCTRL_SH_PFC
+
+config PINCTRL_PFC_R8A774C0
+ def_bool y
+ depends on ARCH_R8A774C0
+ select PINCTRL_SH_PFC
+
config PINCTRL_PFC_R8A7778
def_bool y
depends on ARCH_R8A7778
diff --git a/drivers/pinctrl/sh-pfc/Makefile b/drivers/pinctrl/sh-pfc/Makefile
index d0b29c51c159..82ebb2a91ee0 100644
--- a/drivers/pinctrl/sh-pfc/Makefile
+++ b/drivers/pinctrl/sh-pfc/Makefile
@@ -5,8 +5,11 @@ obj-$(CONFIG_PINCTRL_PFC_EMEV2) += pfc-emev2.o
obj-$(CONFIG_PINCTRL_PFC_R8A73A4) += pfc-r8a73a4.o
obj-$(CONFIG_PINCTRL_PFC_R8A7740) += pfc-r8a7740.o
obj-$(CONFIG_PINCTRL_PFC_R8A7743) += pfc-r8a7791.o
+obj-$(CONFIG_PINCTRL_PFC_R8A7744) += pfc-r8a7791.o
obj-$(CONFIG_PINCTRL_PFC_R8A7745) += pfc-r8a7794.o
obj-$(CONFIG_PINCTRL_PFC_R8A77470) += pfc-r8a77470.o
+obj-$(CONFIG_PINCTRL_PFC_R8A774A1) += pfc-r8a7796.o
+obj-$(CONFIG_PINCTRL_PFC_R8A774C0) += pfc-r8a77990.o
obj-$(CONFIG_PINCTRL_PFC_R8A7778) += pfc-r8a7778.o
obj-$(CONFIG_PINCTRL_PFC_R8A7779) += pfc-r8a7779.o
obj-$(CONFIG_PINCTRL_PFC_R8A7790) += pfc-r8a7790.o
diff --git a/drivers/pinctrl/sh-pfc/core.c b/drivers/pinctrl/sh-pfc/core.c
index c671c3c4aca6..a10f7050a74f 100644
--- a/drivers/pinctrl/sh-pfc/core.c
+++ b/drivers/pinctrl/sh-pfc/core.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Pin Control and GPIO driver for SuperH Pin Function Controller.
*
@@ -5,10 +6,6 @@
*
* Copyright (C) 2008 Magnus Damm
* Copyright (C) 2009 - 2012 Paul Mundt
- *
- * 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.
*/
#define DRV_NAME "sh-pfc"
@@ -497,6 +494,12 @@ static const struct of_device_id sh_pfc_of_table[] = {
.data = &r8a7743_pinmux_info,
},
#endif
+#ifdef CONFIG_PINCTRL_PFC_R8A7744
+ {
+ .compatible = "renesas,pfc-r8a7744",
+ .data = &r8a7744_pinmux_info,
+ },
+#endif
#ifdef CONFIG_PINCTRL_PFC_R8A7745
{
.compatible = "renesas,pfc-r8a7745",
@@ -509,6 +512,18 @@ static const struct of_device_id sh_pfc_of_table[] = {
.data = &r8a77470_pinmux_info,
},
#endif
+#ifdef CONFIG_PINCTRL_PFC_R8A774A1
+ {
+ .compatible = "renesas,pfc-r8a774a1",
+ .data = &r8a774a1_pinmux_info,
+ },
+#endif
+#ifdef CONFIG_PINCTRL_PFC_R8A774C0
+ {
+ .compatible = "renesas,pfc-r8a774c0",
+ .data = &r8a774c0_pinmux_info,
+ },
+#endif
#ifdef CONFIG_PINCTRL_PFC_R8A7778
{
.compatible = "renesas,pfc-r8a7778",
diff --git a/drivers/pinctrl/sh-pfc/core.h b/drivers/pinctrl/sh-pfc/core.h
index 5af8ee26c03e..b5b1d163e98a 100644
--- a/drivers/pinctrl/sh-pfc/core.h
+++ b/drivers/pinctrl/sh-pfc/core.h
@@ -1,11 +1,8 @@
-/*
+/* SPDX-License-Identifier: GPL-2.0
+ *
* SuperH Pin Function Controller support.
*
* Copyright (C) 2012 Renesas Solutions Corp.
- *
- * 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.
*/
#ifndef __SH_PFC_CORE_H__
#define __SH_PFC_CORE_H__
diff --git a/drivers/pinctrl/sh-pfc/gpio.c b/drivers/pinctrl/sh-pfc/gpio.c
index 6ffdc6beb203..4f3a34ee1cd4 100644
--- a/drivers/pinctrl/sh-pfc/gpio.c
+++ b/drivers/pinctrl/sh-pfc/gpio.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* SuperH Pin Function Controller GPIO driver.
*
* Copyright (C) 2008 Magnus Damm
* Copyright (C) 2009 - 2012 Paul Mundt
- *
- * 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/device.h>
diff --git a/drivers/pinctrl/sh-pfc/pfc-emev2.c b/drivers/pinctrl/sh-pfc/pfc-emev2.c
index 1cbbe04d7df6..dc271c3243df 100644
--- a/drivers/pinctrl/sh-pfc/pfc-emev2.c
+++ b/drivers/pinctrl/sh-pfc/pfc-emev2.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Pin Function Controller Support
*
* Copyright (C) 2015 Niklas Söderlund
- *
- * 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/init.h>
#include <linux/kernel.h>
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a73a4.c b/drivers/pinctrl/sh-pfc/pfc-r8a73a4.c
index ff5655dee67e..5acbacb3727f 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a73a4.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a73a4.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2012-2013 Renesas Solutions Corp.
* Copyright (C) 2013 Magnus Damm
* Copyright (C) 2012 Kuninori Morimoto <kuninori.morimoto.gx@renesas.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 of the
- * License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/io.h>
#include <linux/kernel.h>
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7740.c b/drivers/pinctrl/sh-pfc/pfc-r8a7740.c
index 35f436bcb849..d4f81491996d 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7740.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7740.c
@@ -1,22 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* R8A7740 processor support
*
* Copyright (C) 2011 Renesas Solutions Corp.
* Copyright (C) 2011 Kuninori Morimoto <kuninori.morimoto.gx@renesas.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 of the
- * License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/io.h>
#include <linux/kernel.h>
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a77470.c b/drivers/pinctrl/sh-pfc/pfc-r8a77470.c
index 9d3ed438ec7b..3d36e5f4ca7b 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a77470.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a77470.c
@@ -1093,6 +1093,233 @@ static const struct sh_pfc_pin pinmux_pins[] = {
PINMUX_GPIO_GP_ALL(),
};
+/* - AVB -------------------------------------------------------------------- */
+static const unsigned int avb_col_pins[] = {
+ RCAR_GP_PIN(5, 18),
+};
+static const unsigned int avb_col_mux[] = {
+ AVB_COL_MARK,
+};
+static const unsigned int avb_crs_pins[] = {
+ RCAR_GP_PIN(5, 17),
+};
+static const unsigned int avb_crs_mux[] = {
+ AVB_CRS_MARK,
+};
+static const unsigned int avb_link_pins[] = {
+ RCAR_GP_PIN(5, 14),
+};
+static const unsigned int avb_link_mux[] = {
+ AVB_LINK_MARK,
+};
+static const unsigned int avb_magic_pins[] = {
+ RCAR_GP_PIN(5, 15),
+};
+static const unsigned int avb_magic_mux[] = {
+ AVB_MAGIC_MARK,
+};
+static const unsigned int avb_phy_int_pins[] = {
+ RCAR_GP_PIN(5, 16),
+};
+static const unsigned int avb_phy_int_mux[] = {
+ AVB_PHY_INT_MARK,
+};
+static const unsigned int avb_mdio_pins[] = {
+ RCAR_GP_PIN(5, 12), RCAR_GP_PIN(5, 13),
+};
+static const unsigned int avb_mdio_mux[] = {
+ AVB_MDC_MARK, AVB_MDIO_MARK,
+};
+static const unsigned int avb_mii_tx_rx_pins[] = {
+ RCAR_GP_PIN(3, 12), RCAR_GP_PIN(3, 14), RCAR_GP_PIN(3, 15),
+ RCAR_GP_PIN(3, 16), RCAR_GP_PIN(3, 27), RCAR_GP_PIN(3, 13),
+
+ RCAR_GP_PIN(3, 0), RCAR_GP_PIN(3, 2), RCAR_GP_PIN(3, 3),
+ RCAR_GP_PIN(3, 4), RCAR_GP_PIN(3, 5), RCAR_GP_PIN(3, 1),
+ RCAR_GP_PIN(3, 10),
+};
+static const unsigned int avb_mii_tx_rx_mux[] = {
+ AVB_TX_CLK_MARK, AVB_TXD0_MARK, AVB_TXD1_MARK, AVB_TXD2_MARK,
+ AVB_TXD3_MARK, AVB_TX_EN_MARK,
+
+ AVB_RX_CLK_MARK, AVB_RXD0_MARK, AVB_RXD1_MARK, AVB_RXD2_MARK,
+ AVB_RXD3_MARK, AVB_RX_DV_MARK, AVB_RX_ER_MARK,
+};
+static const unsigned int avb_mii_tx_er_pins[] = {
+ RCAR_GP_PIN(5, 23),
+};
+static const unsigned int avb_mii_tx_er_mux[] = {
+ AVB_TX_ER_MARK,
+};
+static const unsigned int avb_gmii_tx_rx_pins[] = {
+ RCAR_GP_PIN(4, 1), RCAR_GP_PIN(3, 11), RCAR_GP_PIN(3, 12),
+ RCAR_GP_PIN(3, 14), RCAR_GP_PIN(3, 15), RCAR_GP_PIN(3, 16),
+ RCAR_GP_PIN(3, 27), RCAR_GP_PIN(3, 28), RCAR_GP_PIN(3, 29),
+ RCAR_GP_PIN(4, 0), RCAR_GP_PIN(5, 22), RCAR_GP_PIN(3, 13),
+ RCAR_GP_PIN(5, 23),
+
+ RCAR_GP_PIN(3, 0), RCAR_GP_PIN(3, 2), RCAR_GP_PIN(3, 3),
+ RCAR_GP_PIN(3, 4), RCAR_GP_PIN(3, 5), RCAR_GP_PIN(3, 6),
+ RCAR_GP_PIN(3, 7), RCAR_GP_PIN(3, 8), RCAR_GP_PIN(3, 9),
+ RCAR_GP_PIN(3, 1), RCAR_GP_PIN(3, 10),
+};
+static const unsigned int avb_gmii_tx_rx_mux[] = {
+ AVB_GTX_CLK_MARK, AVB_GTXREFCLK_MARK, AVB_TX_CLK_MARK, AVB_TXD0_MARK,
+ AVB_TXD1_MARK, AVB_TXD2_MARK, AVB_TXD3_MARK, AVB_TXD4_MARK,
+ AVB_TXD5_MARK, AVB_TXD6_MARK, AVB_TXD7_MARK, AVB_TX_EN_MARK,
+ AVB_TX_ER_MARK,
+
+ AVB_RX_CLK_MARK, AVB_RXD0_MARK, AVB_RXD1_MARK, AVB_RXD2_MARK,
+ AVB_RXD3_MARK, AVB_RXD4_MARK, AVB_RXD5_MARK, AVB_RXD6_MARK,
+ AVB_RXD7_MARK, AVB_RX_DV_MARK, AVB_RX_ER_MARK,
+};
+static const unsigned int avb_avtp_match_a_pins[] = {
+ RCAR_GP_PIN(1, 15),
+};
+static const unsigned int avb_avtp_match_a_mux[] = {
+ AVB_AVTP_MATCH_A_MARK,
+};
+static const unsigned int avb_avtp_capture_a_pins[] = {
+ RCAR_GP_PIN(1, 14),
+};
+static const unsigned int avb_avtp_capture_a_mux[] = {
+ AVB_AVTP_CAPTURE_A_MARK,
+};
+static const unsigned int avb_avtp_match_b_pins[] = {
+ RCAR_GP_PIN(5, 20),
+};
+static const unsigned int avb_avtp_match_b_mux[] = {
+ AVB_AVTP_MATCH_B_MARK,
+};
+static const unsigned int avb_avtp_capture_b_pins[] = {
+ RCAR_GP_PIN(5, 19),
+};
+static const unsigned int avb_avtp_capture_b_mux[] = {
+ AVB_AVTP_CAPTURE_B_MARK,
+};
+/* - DU --------------------------------------------------------------------- */
+static const unsigned int du0_rgb666_pins[] = {
+ /* R[7:2], G[7:2], B[7:2] */
+ RCAR_GP_PIN(2, 7), RCAR_GP_PIN(2, 6), RCAR_GP_PIN(2, 5),
+ RCAR_GP_PIN(2, 4), RCAR_GP_PIN(2, 3), RCAR_GP_PIN(2, 2),
+ RCAR_GP_PIN(2, 15), RCAR_GP_PIN(2, 14), RCAR_GP_PIN(2, 13),
+ RCAR_GP_PIN(2, 12), RCAR_GP_PIN(2, 11), RCAR_GP_PIN(2, 10),
+ RCAR_GP_PIN(2, 23), RCAR_GP_PIN(2, 22), RCAR_GP_PIN(2, 21),
+ RCAR_GP_PIN(2, 20), RCAR_GP_PIN(2, 19), RCAR_GP_PIN(2, 18),
+};
+static const unsigned int du0_rgb666_mux[] = {
+ DU0_DR7_MARK, DU0_DR6_MARK, DU0_DR5_MARK, DU0_DR4_MARK,
+ DU0_DR3_MARK, DU0_DR2_MARK,
+ DU0_DG7_MARK, DU0_DG6_MARK, DU0_DG5_MARK, DU0_DG4_MARK,
+ DU0_DG3_MARK, DU0_DG2_MARK,
+ DU0_DB7_MARK, DU0_DB6_MARK, DU0_DB5_MARK, DU0_DB4_MARK,
+ DU0_DB3_MARK, DU0_DB2_MARK,
+};
+static const unsigned int du0_rgb888_pins[] = {
+ /* R[7:0], G[7:0], B[7:0] */
+ RCAR_GP_PIN(2, 7), RCAR_GP_PIN(2, 6), RCAR_GP_PIN(2, 5),
+ RCAR_GP_PIN(2, 4), RCAR_GP_PIN(2, 3), RCAR_GP_PIN(2, 2),
+ RCAR_GP_PIN(2, 1), RCAR_GP_PIN(2, 0),
+ RCAR_GP_PIN(2, 15), RCAR_GP_PIN(2, 14), RCAR_GP_PIN(2, 13),
+ RCAR_GP_PIN(2, 12), RCAR_GP_PIN(2, 11), RCAR_GP_PIN(2, 10),
+ RCAR_GP_PIN(2, 9), RCAR_GP_PIN(2, 8),
+ RCAR_GP_PIN(2, 23), RCAR_GP_PIN(2, 22), RCAR_GP_PIN(2, 21),
+ RCAR_GP_PIN(2, 20), RCAR_GP_PIN(2, 19), RCAR_GP_PIN(2, 18),
+ RCAR_GP_PIN(2, 17), RCAR_GP_PIN(2, 16),
+};
+static const unsigned int du0_rgb888_mux[] = {
+ DU0_DR7_MARK, DU0_DR6_MARK, DU0_DR5_MARK, DU0_DR4_MARK,
+ DU0_DR3_MARK, DU0_DR2_MARK, DU0_DR1_MARK, DU0_DR0_MARK,
+ DU0_DG7_MARK, DU0_DG6_MARK, DU0_DG5_MARK, DU0_DG4_MARK,
+ DU0_DG3_MARK, DU0_DG2_MARK, DU0_DG1_MARK, DU0_DG0_MARK,
+ DU0_DB7_MARK, DU0_DB6_MARK, DU0_DB5_MARK, DU0_DB4_MARK,
+ DU0_DB3_MARK, DU0_DB2_MARK, DU0_DB1_MARK, DU0_DB0_MARK,
+};
+static const unsigned int du0_clk0_out_pins[] = {
+ /* DOTCLKOUT0 */
+ RCAR_GP_PIN(2, 25),
+};
+static const unsigned int du0_clk0_out_mux[] = {
+ DU0_DOTCLKOUT0_MARK
+};
+static const unsigned int du0_clk1_out_pins[] = {
+ /* DOTCLKOUT1 */
+ RCAR_GP_PIN(2, 26),
+};
+static const unsigned int du0_clk1_out_mux[] = {
+ DU0_DOTCLKOUT1_MARK
+};
+static const unsigned int du0_clk_in_pins[] = {
+ /* CLKIN */
+ RCAR_GP_PIN(2, 24),
+};
+static const unsigned int du0_clk_in_mux[] = {
+ DU0_DOTCLKIN_MARK
+};
+static const unsigned int du0_sync_pins[] = {
+ /* EXVSYNC/VSYNC, EXHSYNC/HSYNC */
+ RCAR_GP_PIN(2, 28), RCAR_GP_PIN(2, 27),
+};
+static const unsigned int du0_sync_mux[] = {
+ DU0_EXVSYNC_DU0_VSYNC_MARK, DU0_EXHSYNC_DU0_HSYNC_MARK
+};
+static const unsigned int du0_oddf_pins[] = {
+ /* EXODDF/ODDF/DISP/CDE */
+ RCAR_GP_PIN(2, 29),
+};
+static const unsigned int du0_oddf_mux[] = {
+ DU0_EXODDF_DU0_ODDF_DISP_CDE_MARK,
+};
+static const unsigned int du0_cde_pins[] = {
+ /* CDE */
+ RCAR_GP_PIN(2, 31),
+};
+static const unsigned int du0_cde_mux[] = {
+ DU0_CDE_MARK,
+};
+static const unsigned int du0_disp_pins[] = {
+ /* DISP */
+ RCAR_GP_PIN(2, 30),
+};
+static const unsigned int du0_disp_mux[] = {
+ DU0_DISP_MARK
+};
+/* - I2C4 ------------------------------------------------------------------- */
+static const unsigned int i2c4_a_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(4, 10), RCAR_GP_PIN(4, 11),
+};
+static const unsigned int i2c4_a_mux[] = {
+ SCL4_A_MARK, SDA4_A_MARK,
+};
+static const unsigned int i2c4_b_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(5, 30), RCAR_GP_PIN(5, 31),
+};
+static const unsigned int i2c4_b_mux[] = {
+ SCL4_B_MARK, SDA4_B_MARK,
+};
+static const unsigned int i2c4_c_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(5, 4), RCAR_GP_PIN(5, 5),
+};
+static const unsigned int i2c4_c_mux[] = {
+ SCL4_C_MARK, SDA4_C_MARK,
+};
+static const unsigned int i2c4_d_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(2, 16), RCAR_GP_PIN(2, 17),
+};
+static const unsigned int i2c4_d_mux[] = {
+ SCL4_D_MARK, SDA4_D_MARK,
+};
+static const unsigned int i2c4_e_pins[] = {
+ /* SCL, SDA */
+ RCAR_GP_PIN(5, 7), RCAR_GP_PIN(5, 6),
+};
+static const unsigned int i2c4_e_mux[] = {
+ SCL4_E_MARK, SDA4_E_MARK,
+};
/* - MMC -------------------------------------------------------------------- */
static const unsigned int mmc_data1_pins[] = {
/* D0 */
@@ -1130,6 +1357,30 @@ static const unsigned int mmc_ctrl_pins[] = {
static const unsigned int mmc_ctrl_mux[] = {
MMC0_CLK_SDHI1_CLK_MARK, MMC0_CMD_SDHI1_CMD_MARK,
};
+/* - QSPI ------------------------------------------------------------------- */
+static const unsigned int qspi0_ctrl_pins[] = {
+ /* SPCLK, SSL */
+ RCAR_GP_PIN(1, 16), RCAR_GP_PIN(1, 21),
+};
+static const unsigned int qspi0_ctrl_mux[] = {
+ QSPI0_SPCLK_MARK, QSPI0_SSL_MARK,
+};
+static const unsigned int qspi0_data2_pins[] = {
+ /* MOSI_IO0, MISO_IO1 */
+ RCAR_GP_PIN(1, 17), RCAR_GP_PIN(1, 18),
+};
+static const unsigned int qspi0_data2_mux[] = {
+ QSPI0_MOSI_QSPI0_IO0_MARK, QSPI0_MISO_QSPI0_IO1_MARK,
+};
+static const unsigned int qspi0_data4_pins[] = {
+ /* MOSI_IO0, MISO_IO1, IO2, IO3 */
+ RCAR_GP_PIN(1, 17), RCAR_GP_PIN(1, 18), RCAR_GP_PIN(1, 19),
+ RCAR_GP_PIN(1, 20),
+};
+static const unsigned int qspi0_data4_mux[] = {
+ QSPI0_MOSI_QSPI0_IO0_MARK, QSPI0_MISO_QSPI0_IO1_MARK,
+ QSPI0_IO2_MARK, QSPI0_IO3_MARK,
+};
/* - SCIF0 ------------------------------------------------------------------ */
static const unsigned int scif0_data_a_pins[] = {
/* RX, TX */
@@ -1368,12 +1619,97 @@ static const unsigned int scif_clk_b_pins[] = {
static const unsigned int scif_clk_b_mux[] = {
SCIF_CLK_B_MARK,
};
+/* - SDHI2 ------------------------------------------------------------------ */
+static const unsigned int sdhi2_data1_pins[] = {
+ /* D0 */
+ RCAR_GP_PIN(4, 16),
+};
+static const unsigned int sdhi2_data1_mux[] = {
+ SD2_DAT0_MARK,
+};
+static const unsigned int sdhi2_data4_pins[] = {
+ /* D[0:3] */
+ RCAR_GP_PIN(4, 16), RCAR_GP_PIN(4, 17),
+ RCAR_GP_PIN(4, 18), RCAR_GP_PIN(4, 19),
+};
+static const unsigned int sdhi2_data4_mux[] = {
+ SD2_DAT0_MARK, SD2_DAT1_MARK, SD2_DAT2_MARK, SD2_DAT3_MARK,
+};
+static const unsigned int sdhi2_ctrl_pins[] = {
+ /* CLK, CMD */
+ RCAR_GP_PIN(4, 14), RCAR_GP_PIN(4, 15),
+};
+static const unsigned int sdhi2_ctrl_mux[] = {
+ SD2_CLK_MARK, SD2_CMD_MARK,
+};
+static const unsigned int sdhi2_cd_pins[] = {
+ /* CD */
+ RCAR_GP_PIN(4, 20),
+};
+static const unsigned int sdhi2_cd_mux[] = {
+ SD2_CD_MARK,
+};
+static const unsigned int sdhi2_wp_pins[] = {
+ /* WP */
+ RCAR_GP_PIN(4, 21),
+};
+static const unsigned int sdhi2_wp_mux[] = {
+ SD2_WP_MARK,
+};
+/* - USB0 ------------------------------------------------------------------- */
+static const unsigned int usb0_pins[] = {
+ RCAR_GP_PIN(0, 0), /* PWEN */
+ RCAR_GP_PIN(0, 1), /* OVC */
+};
+static const unsigned int usb0_mux[] = {
+ USB0_PWEN_MARK,
+ USB0_OVC_MARK,
+};
+/* - USB1 ------------------------------------------------------------------- */
+static const unsigned int usb1_pins[] = {
+ RCAR_GP_PIN(0, 2), /* PWEN */
+ RCAR_GP_PIN(0, 3), /* OVC */
+};
+static const unsigned int usb1_mux[] = {
+ USB1_PWEN_MARK,
+ USB1_OVC_MARK,
+};
static const struct sh_pfc_pin_group pinmux_groups[] = {
+ SH_PFC_PIN_GROUP(avb_col),
+ SH_PFC_PIN_GROUP(avb_crs),
+ SH_PFC_PIN_GROUP(avb_link),
+ SH_PFC_PIN_GROUP(avb_magic),
+ SH_PFC_PIN_GROUP(avb_phy_int),
+ SH_PFC_PIN_GROUP(avb_mdio),
+ SH_PFC_PIN_GROUP(avb_mii_tx_rx),
+ SH_PFC_PIN_GROUP(avb_mii_tx_er),
+ SH_PFC_PIN_GROUP(avb_gmii_tx_rx),
+ SH_PFC_PIN_GROUP(avb_avtp_match_a),
+ SH_PFC_PIN_GROUP(avb_avtp_capture_a),
+ SH_PFC_PIN_GROUP(avb_avtp_match_b),
+ SH_PFC_PIN_GROUP(avb_avtp_capture_b),
+ SH_PFC_PIN_GROUP(du0_rgb666),
+ SH_PFC_PIN_GROUP(du0_rgb888),
+ SH_PFC_PIN_GROUP(du0_clk0_out),
+ SH_PFC_PIN_GROUP(du0_clk1_out),
+ SH_PFC_PIN_GROUP(du0_clk_in),
+ SH_PFC_PIN_GROUP(du0_sync),
+ SH_PFC_PIN_GROUP(du0_oddf),
+ SH_PFC_PIN_GROUP(du0_cde),
+ SH_PFC_PIN_GROUP(du0_disp),
+ SH_PFC_PIN_GROUP(i2c4_a),
+ SH_PFC_PIN_GROUP(i2c4_b),
+ SH_PFC_PIN_GROUP(i2c4_c),
+ SH_PFC_PIN_GROUP(i2c4_d),
+ SH_PFC_PIN_GROUP(i2c4_e),
SH_PFC_PIN_GROUP(mmc_data1),
SH_PFC_PIN_GROUP(mmc_data4),
SH_PFC_PIN_GROUP(mmc_data8),
SH_PFC_PIN_GROUP(mmc_ctrl),
+ SH_PFC_PIN_GROUP(qspi0_ctrl),
+ SH_PFC_PIN_GROUP(qspi0_data2),
+ SH_PFC_PIN_GROUP(qspi0_data4),
SH_PFC_PIN_GROUP(scif0_data_a),
SH_PFC_PIN_GROUP(scif0_data_b),
SH_PFC_PIN_GROUP(scif0_data_c),
@@ -1407,6 +1743,49 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(scif5_data_f),
SH_PFC_PIN_GROUP(scif_clk_a),
SH_PFC_PIN_GROUP(scif_clk_b),
+ SH_PFC_PIN_GROUP(sdhi2_data1),
+ SH_PFC_PIN_GROUP(sdhi2_data4),
+ SH_PFC_PIN_GROUP(sdhi2_ctrl),
+ SH_PFC_PIN_GROUP(sdhi2_cd),
+ SH_PFC_PIN_GROUP(sdhi2_wp),
+ SH_PFC_PIN_GROUP(usb0),
+ SH_PFC_PIN_GROUP(usb1),
+};
+
+static const char * const avb_groups[] = {
+ "avb_col",
+ "avb_crs",
+ "avb_link",
+ "avb_magic",
+ "avb_phy_int",
+ "avb_mdio",
+ "avb_mii_tx_rx",
+ "avb_mii_tx_er",
+ "avb_gmii_tx_rx",
+ "avb_avtp_match_a",
+ "avb_avtp_capture_a",
+ "avb_avtp_match_b",
+ "avb_avtp_capture_b",
+};
+
+static const char * const du0_groups[] = {
+ "du0_rgb666",
+ "du0_rgb888",
+ "du0_clk0_out",
+ "du0_clk1_out",
+ "du0_clk_in",
+ "du0_sync",
+ "du0_oddf",
+ "du0_cde",
+ "du0_disp",
+};
+
+static const char * const i2c4_groups[] = {
+ "i2c4_a",
+ "i2c4_b",
+ "i2c4_c",
+ "i2c4_d",
+ "i2c4_e",
};
static const char * const mmc_groups[] = {
@@ -1416,6 +1795,12 @@ static const char * const mmc_groups[] = {
"mmc_ctrl",
};
+static const char * const qspi0_groups[] = {
+ "qspi0_ctrl",
+ "qspi0_data2",
+ "qspi0_data4",
+};
+
static const char * const scif0_groups[] = {
"scif0_data_a",
"scif0_data_b",
@@ -1470,8 +1855,28 @@ static const char * const scif_clk_groups[] = {
"scif_clk_b",
};
+static const char * const sdhi2_groups[] = {
+ "sdhi2_data1",
+ "sdhi2_data4",
+ "sdhi2_ctrl",
+ "sdhi2_cd",
+ "sdhi2_wp",
+};
+
+static const char * const usb0_groups[] = {
+ "usb0",
+};
+
+static const char * const usb1_groups[] = {
+ "usb1",
+};
+
static const struct sh_pfc_function pinmux_functions[] = {
+ SH_PFC_FUNCTION(avb),
+ SH_PFC_FUNCTION(du0),
+ SH_PFC_FUNCTION(i2c4),
SH_PFC_FUNCTION(mmc),
+ SH_PFC_FUNCTION(qspi0),
SH_PFC_FUNCTION(scif0),
SH_PFC_FUNCTION(scif1),
SH_PFC_FUNCTION(scif2),
@@ -1479,6 +1884,9 @@ static const struct sh_pfc_function pinmux_functions[] = {
SH_PFC_FUNCTION(scif4),
SH_PFC_FUNCTION(scif5),
SH_PFC_FUNCTION(scif_clk),
+ SH_PFC_FUNCTION(sdhi2),
+ SH_PFC_FUNCTION(usb0),
+ SH_PFC_FUNCTION(usb1),
};
static const struct pinmux_cfg_reg pinmux_config_regs[] = {
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7778.c b/drivers/pinctrl/sh-pfc/pfc-r8a7778.c
index 00d61d175249..6bcdb4b5e69e 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7778.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7778.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* r8a7778 processor support - PFC hardware block
*
@@ -9,15 +10,6 @@
* based on
* Copyright (C) 2011 Renesas Solutions Corp.
* Copyright (C) 2011 Magnus Damm
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/io.h>
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7779.c b/drivers/pinctrl/sh-pfc/pfc-r8a7779.c
index 5bef934f823d..64bace100316 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7779.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7779.c
@@ -1,22 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* r8a7779 processor support - PFC hardware block
*
* Copyright (C) 2011, 2013 Renesas Solutions Corp.
* Copyright (C) 2011 Magnus Damm
* Copyright (C) 2013 Cogent Embedded, 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; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/kernel.h>
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7790.c b/drivers/pinctrl/sh-pfc/pfc-r8a7790.c
index f6332f247368..ab7a35392cd8 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7790.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7790.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* R8A7790 processor support
*
@@ -5,20 +6,6 @@
* Copyright (C) 2013 Magnus Damm
* Copyright (C) 2012 Renesas Solutions Corp.
* Copyright (C) 2012 Kuninori Morimoto <kuninori.morimoto.gx@renesas.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 of the
- * License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/io.h>
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c
index 5811784d88cb..209f74a6e6ce 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* r8a7791/r8a7743 processor support - PFC hardware block.
*
* Copyright (C) 2013 Renesas Electronics Corporation
* Copyright (C) 2014-2017 Cogent Embedded, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
*/
#include <linux/kernel.h>
@@ -4458,7 +4455,7 @@ static const unsigned int vin2_clk_mux[] = {
static const struct {
struct sh_pfc_pin_group common[346];
- struct sh_pfc_pin_group r8a779x[9];
+ struct sh_pfc_pin_group automotive[9];
} pinmux_groups = {
.common = {
SH_PFC_PIN_GROUP(audio_clk_a),
@@ -4808,7 +4805,7 @@ static const struct {
SH_PFC_PIN_GROUP(vin2_clkenb),
SH_PFC_PIN_GROUP(vin2_clk),
},
- .r8a779x = {
+ .automotive = {
SH_PFC_PIN_GROUP(adi_common),
SH_PFC_PIN_GROUP(adi_chsel0),
SH_PFC_PIN_GROUP(adi_chsel1),
@@ -5365,7 +5362,7 @@ static const char * const vin2_groups[] = {
static const struct {
struct sh_pfc_function common[58];
- struct sh_pfc_function r8a779x[2];
+ struct sh_pfc_function automotive[2];
} pinmux_functions = {
.common = {
SH_PFC_FUNCTION(audio_clk),
@@ -5427,7 +5424,7 @@ static const struct {
SH_PFC_FUNCTION(vin1),
SH_PFC_FUNCTION(vin2),
},
- .r8a779x = {
+ .automotive = {
SH_PFC_FUNCTION(adi),
SH_PFC_FUNCTION(mlb),
}
@@ -6634,6 +6631,28 @@ const struct sh_pfc_soc_info r8a7743_pinmux_info = {
};
#endif
+#ifdef CONFIG_PINCTRL_PFC_R8A7744
+const struct sh_pfc_soc_info r8a7744_pinmux_info = {
+ .name = "r8a77440_pfc",
+ .ops = &r8a7791_pinmux_ops,
+ .unlock_reg = 0xe6060000, /* PMMR */
+
+ .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
+
+ .pins = pinmux_pins,
+ .nr_pins = ARRAY_SIZE(pinmux_pins),
+ .groups = pinmux_groups.common,
+ .nr_groups = ARRAY_SIZE(pinmux_groups.common),
+ .functions = pinmux_functions.common,
+ .nr_functions = ARRAY_SIZE(pinmux_functions.common),
+
+ .cfg_regs = pinmux_config_regs,
+
+ .pinmux_data = pinmux_data,
+ .pinmux_data_size = ARRAY_SIZE(pinmux_data),
+};
+#endif
+
#ifdef CONFIG_PINCTRL_PFC_R8A7791
const struct sh_pfc_soc_info r8a7791_pinmux_info = {
.name = "r8a77910_pfc",
@@ -6646,10 +6665,10 @@ const struct sh_pfc_soc_info r8a7791_pinmux_info = {
.nr_pins = ARRAY_SIZE(pinmux_pins),
.groups = pinmux_groups.common,
.nr_groups = ARRAY_SIZE(pinmux_groups.common) +
- ARRAY_SIZE(pinmux_groups.r8a779x),
+ ARRAY_SIZE(pinmux_groups.automotive),
.functions = pinmux_functions.common,
.nr_functions = ARRAY_SIZE(pinmux_functions.common) +
- ARRAY_SIZE(pinmux_functions.r8a779x),
+ ARRAY_SIZE(pinmux_functions.automotive),
.cfg_regs = pinmux_config_regs,
@@ -6670,10 +6689,10 @@ const struct sh_pfc_soc_info r8a7793_pinmux_info = {
.nr_pins = ARRAY_SIZE(pinmux_pins),
.groups = pinmux_groups.common,
.nr_groups = ARRAY_SIZE(pinmux_groups.common) +
- ARRAY_SIZE(pinmux_groups.r8a779x),
+ ARRAY_SIZE(pinmux_groups.automotive),
.functions = pinmux_functions.common,
.nr_functions = ARRAY_SIZE(pinmux_functions.common) +
- ARRAY_SIZE(pinmux_functions.r8a779x),
+ ARRAY_SIZE(pinmux_functions.automotive),
.cfg_regs = pinmux_config_regs,
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7792.c b/drivers/pinctrl/sh-pfc/pfc-r8a7792.c
index cc3597f66605..bf0681b38181 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7792.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7792.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* r8a7792 processor support - PFC hardware block.
*
* Copyright (C) 2013-2014 Renesas Electronics Corporation
* Copyright (C) 2016 Cogent Embedded, Inc., <source@cogentembedded.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
*/
#include <linux/kernel.h>
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7794.c b/drivers/pinctrl/sh-pfc/pfc-r8a7794.c
index 164002437594..6d1e5fdc03f8 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7794.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7794.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* r8a7794/r8a7745 processor support - PFC hardware block.
*
* Copyright (C) 2014-2015 Renesas Electronics Corporation
* Copyright (C) 2015 Renesas Solutions Corp.
* Copyright (C) 2015-2017 Cogent Embedded, Inc. <source@cogentembedded.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
*/
#include <linux/kernel.h>
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7795-es1.c b/drivers/pinctrl/sh-pfc/pfc-r8a7795-es1.c
index a6c5d50557e6..8c7de44615d1 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7795-es1.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7795-es1.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* R8A7795 ES1.x processor support - PFC hardware block.
*
* Copyright (C) 2015-2017 Renesas Electronics Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
*/
#include <linux/kernel.h>
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7795.c b/drivers/pinctrl/sh-pfc/pfc-r8a7795.c
index 4f55b1562ad4..0af737d11403 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7795.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7795.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* R8A7795 ES2.0+ processor support - PFC hardware block.
*
* Copyright (C) 2015-2017 Renesas Electronics Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
*/
#include <linux/kernel.h>
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7796.c b/drivers/pinctrl/sh-pfc/pfc-r8a7796.c
index 3ea133cfb241..3a6d21d87107 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7796.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7796.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* R8A7796 processor support - PFC hardware block.
*
@@ -8,10 +9,6 @@
* R-Car Gen3 processor support - PFC hardware block.
*
* Copyright (C) 2015 Renesas Electronics Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
*/
#include <linux/kernel.h>
@@ -4126,347 +4123,354 @@ static const unsigned int vin5_clk_mux[] = {
VI5_CLK_MARK,
};
-static const struct sh_pfc_pin_group pinmux_groups[] = {
- SH_PFC_PIN_GROUP(audio_clk_a_a),
- SH_PFC_PIN_GROUP(audio_clk_a_b),
- SH_PFC_PIN_GROUP(audio_clk_a_c),
- SH_PFC_PIN_GROUP(audio_clk_b_a),
- SH_PFC_PIN_GROUP(audio_clk_b_b),
- SH_PFC_PIN_GROUP(audio_clk_c_a),
- SH_PFC_PIN_GROUP(audio_clk_c_b),
- SH_PFC_PIN_GROUP(audio_clkout_a),
- SH_PFC_PIN_GROUP(audio_clkout_b),
- SH_PFC_PIN_GROUP(audio_clkout_c),
- SH_PFC_PIN_GROUP(audio_clkout_d),
- SH_PFC_PIN_GROUP(audio_clkout1_a),
- SH_PFC_PIN_GROUP(audio_clkout1_b),
- SH_PFC_PIN_GROUP(audio_clkout2_a),
- SH_PFC_PIN_GROUP(audio_clkout2_b),
- SH_PFC_PIN_GROUP(audio_clkout3_a),
- SH_PFC_PIN_GROUP(audio_clkout3_b),
- 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(avb_mdio),
- SH_PFC_PIN_GROUP(avb_mii),
- SH_PFC_PIN_GROUP(avb_avtp_pps),
- SH_PFC_PIN_GROUP(avb_avtp_match_a),
- SH_PFC_PIN_GROUP(avb_avtp_capture_a),
- SH_PFC_PIN_GROUP(avb_avtp_match_b),
- SH_PFC_PIN_GROUP(avb_avtp_capture_b),
- SH_PFC_PIN_GROUP(can0_data_a),
- SH_PFC_PIN_GROUP(can0_data_b),
- SH_PFC_PIN_GROUP(can1_data),
- SH_PFC_PIN_GROUP(can_clk),
- SH_PFC_PIN_GROUP(canfd0_data_a),
- SH_PFC_PIN_GROUP(canfd0_data_b),
- SH_PFC_PIN_GROUP(canfd1_data),
- SH_PFC_PIN_GROUP(drif0_ctrl_a),
- SH_PFC_PIN_GROUP(drif0_data0_a),
- SH_PFC_PIN_GROUP(drif0_data1_a),
- SH_PFC_PIN_GROUP(drif0_ctrl_b),
- SH_PFC_PIN_GROUP(drif0_data0_b),
- SH_PFC_PIN_GROUP(drif0_data1_b),
- SH_PFC_PIN_GROUP(drif0_ctrl_c),
- SH_PFC_PIN_GROUP(drif0_data0_c),
- SH_PFC_PIN_GROUP(drif0_data1_c),
- SH_PFC_PIN_GROUP(drif1_ctrl_a),
- SH_PFC_PIN_GROUP(drif1_data0_a),
- SH_PFC_PIN_GROUP(drif1_data1_a),
- SH_PFC_PIN_GROUP(drif1_ctrl_b),
- SH_PFC_PIN_GROUP(drif1_data0_b),
- SH_PFC_PIN_GROUP(drif1_data1_b),
- SH_PFC_PIN_GROUP(drif1_ctrl_c),
- SH_PFC_PIN_GROUP(drif1_data0_c),
- SH_PFC_PIN_GROUP(drif1_data1_c),
- SH_PFC_PIN_GROUP(drif2_ctrl_a),
- SH_PFC_PIN_GROUP(drif2_data0_a),
- SH_PFC_PIN_GROUP(drif2_data1_a),
- SH_PFC_PIN_GROUP(drif2_ctrl_b),
- SH_PFC_PIN_GROUP(drif2_data0_b),
- SH_PFC_PIN_GROUP(drif2_data1_b),
- SH_PFC_PIN_GROUP(drif3_ctrl_a),
- SH_PFC_PIN_GROUP(drif3_data0_a),
- SH_PFC_PIN_GROUP(drif3_data1_a),
- SH_PFC_PIN_GROUP(drif3_ctrl_b),
- SH_PFC_PIN_GROUP(drif3_data0_b),
- SH_PFC_PIN_GROUP(drif3_data1_b),
- SH_PFC_PIN_GROUP(du_rgb666),
- SH_PFC_PIN_GROUP(du_rgb888),
- SH_PFC_PIN_GROUP(du_clk_out_0),
- SH_PFC_PIN_GROUP(du_clk_out_1),
- SH_PFC_PIN_GROUP(du_sync),
- SH_PFC_PIN_GROUP(du_oddf),
- SH_PFC_PIN_GROUP(du_cde),
- SH_PFC_PIN_GROUP(du_disp),
- SH_PFC_PIN_GROUP(hdmi0_cec),
- SH_PFC_PIN_GROUP(hscif0_data),
- SH_PFC_PIN_GROUP(hscif0_clk),
- SH_PFC_PIN_GROUP(hscif0_ctrl),
- SH_PFC_PIN_GROUP(hscif1_data_a),
- SH_PFC_PIN_GROUP(hscif1_clk_a),
- SH_PFC_PIN_GROUP(hscif1_ctrl_a),
- SH_PFC_PIN_GROUP(hscif1_data_b),
- SH_PFC_PIN_GROUP(hscif1_clk_b),
- SH_PFC_PIN_GROUP(hscif1_ctrl_b),
- SH_PFC_PIN_GROUP(hscif2_data_a),
- SH_PFC_PIN_GROUP(hscif2_clk_a),
- SH_PFC_PIN_GROUP(hscif2_ctrl_a),
- SH_PFC_PIN_GROUP(hscif2_data_b),
- SH_PFC_PIN_GROUP(hscif2_clk_b),
- SH_PFC_PIN_GROUP(hscif2_ctrl_b),
- SH_PFC_PIN_GROUP(hscif2_data_c),
- SH_PFC_PIN_GROUP(hscif2_clk_c),
- SH_PFC_PIN_GROUP(hscif2_ctrl_c),
- SH_PFC_PIN_GROUP(hscif3_data_a),
- SH_PFC_PIN_GROUP(hscif3_clk),
- SH_PFC_PIN_GROUP(hscif3_ctrl),
- SH_PFC_PIN_GROUP(hscif3_data_b),
- SH_PFC_PIN_GROUP(hscif3_data_c),
- SH_PFC_PIN_GROUP(hscif3_data_d),
- SH_PFC_PIN_GROUP(hscif4_data_a),
- SH_PFC_PIN_GROUP(hscif4_clk),
- SH_PFC_PIN_GROUP(hscif4_ctrl),
- SH_PFC_PIN_GROUP(hscif4_data_b),
- SH_PFC_PIN_GROUP(i2c1_a),
- SH_PFC_PIN_GROUP(i2c1_b),
- SH_PFC_PIN_GROUP(i2c2_a),
- SH_PFC_PIN_GROUP(i2c2_b),
- SH_PFC_PIN_GROUP(i2c6_a),
- SH_PFC_PIN_GROUP(i2c6_b),
- SH_PFC_PIN_GROUP(i2c6_c),
- SH_PFC_PIN_GROUP(intc_ex_irq0),
- SH_PFC_PIN_GROUP(intc_ex_irq1),
- SH_PFC_PIN_GROUP(intc_ex_irq2),
- SH_PFC_PIN_GROUP(intc_ex_irq3),
- SH_PFC_PIN_GROUP(intc_ex_irq4),
- SH_PFC_PIN_GROUP(intc_ex_irq5),
- SH_PFC_PIN_GROUP(msiof0_clk),
- SH_PFC_PIN_GROUP(msiof0_sync),
- SH_PFC_PIN_GROUP(msiof0_ss1),
- SH_PFC_PIN_GROUP(msiof0_ss2),
- SH_PFC_PIN_GROUP(msiof0_txd),
- SH_PFC_PIN_GROUP(msiof0_rxd),
- SH_PFC_PIN_GROUP(msiof1_clk_a),
- SH_PFC_PIN_GROUP(msiof1_sync_a),
- SH_PFC_PIN_GROUP(msiof1_ss1_a),
- SH_PFC_PIN_GROUP(msiof1_ss2_a),
- SH_PFC_PIN_GROUP(msiof1_txd_a),
- SH_PFC_PIN_GROUP(msiof1_rxd_a),
- SH_PFC_PIN_GROUP(msiof1_clk_b),
- SH_PFC_PIN_GROUP(msiof1_sync_b),
- SH_PFC_PIN_GROUP(msiof1_ss1_b),
- SH_PFC_PIN_GROUP(msiof1_ss2_b),
- SH_PFC_PIN_GROUP(msiof1_txd_b),
- SH_PFC_PIN_GROUP(msiof1_rxd_b),
- SH_PFC_PIN_GROUP(msiof1_clk_c),
- SH_PFC_PIN_GROUP(msiof1_sync_c),
- SH_PFC_PIN_GROUP(msiof1_ss1_c),
- SH_PFC_PIN_GROUP(msiof1_ss2_c),
- SH_PFC_PIN_GROUP(msiof1_txd_c),
- SH_PFC_PIN_GROUP(msiof1_rxd_c),
- SH_PFC_PIN_GROUP(msiof1_clk_d),
- SH_PFC_PIN_GROUP(msiof1_sync_d),
- SH_PFC_PIN_GROUP(msiof1_ss1_d),
- SH_PFC_PIN_GROUP(msiof1_ss2_d),
- SH_PFC_PIN_GROUP(msiof1_txd_d),
- SH_PFC_PIN_GROUP(msiof1_rxd_d),
- SH_PFC_PIN_GROUP(msiof1_clk_e),
- SH_PFC_PIN_GROUP(msiof1_sync_e),
- SH_PFC_PIN_GROUP(msiof1_ss1_e),
- SH_PFC_PIN_GROUP(msiof1_ss2_e),
- SH_PFC_PIN_GROUP(msiof1_txd_e),
- SH_PFC_PIN_GROUP(msiof1_rxd_e),
- SH_PFC_PIN_GROUP(msiof1_clk_f),
- SH_PFC_PIN_GROUP(msiof1_sync_f),
- SH_PFC_PIN_GROUP(msiof1_ss1_f),
- SH_PFC_PIN_GROUP(msiof1_ss2_f),
- SH_PFC_PIN_GROUP(msiof1_txd_f),
- SH_PFC_PIN_GROUP(msiof1_rxd_f),
- SH_PFC_PIN_GROUP(msiof1_clk_g),
- SH_PFC_PIN_GROUP(msiof1_sync_g),
- SH_PFC_PIN_GROUP(msiof1_ss1_g),
- SH_PFC_PIN_GROUP(msiof1_ss2_g),
- SH_PFC_PIN_GROUP(msiof1_txd_g),
- SH_PFC_PIN_GROUP(msiof1_rxd_g),
- SH_PFC_PIN_GROUP(msiof2_clk_a),
- SH_PFC_PIN_GROUP(msiof2_sync_a),
- SH_PFC_PIN_GROUP(msiof2_ss1_a),
- SH_PFC_PIN_GROUP(msiof2_ss2_a),
- SH_PFC_PIN_GROUP(msiof2_txd_a),
- SH_PFC_PIN_GROUP(msiof2_rxd_a),
- SH_PFC_PIN_GROUP(msiof2_clk_b),
- SH_PFC_PIN_GROUP(msiof2_sync_b),
- SH_PFC_PIN_GROUP(msiof2_ss1_b),
- SH_PFC_PIN_GROUP(msiof2_ss2_b),
- SH_PFC_PIN_GROUP(msiof2_txd_b),
- SH_PFC_PIN_GROUP(msiof2_rxd_b),
- SH_PFC_PIN_GROUP(msiof2_clk_c),
- SH_PFC_PIN_GROUP(msiof2_sync_c),
- SH_PFC_PIN_GROUP(msiof2_ss1_c),
- SH_PFC_PIN_GROUP(msiof2_ss2_c),
- SH_PFC_PIN_GROUP(msiof2_txd_c),
- SH_PFC_PIN_GROUP(msiof2_rxd_c),
- SH_PFC_PIN_GROUP(msiof2_clk_d),
- SH_PFC_PIN_GROUP(msiof2_sync_d),
- SH_PFC_PIN_GROUP(msiof2_ss1_d),
- SH_PFC_PIN_GROUP(msiof2_ss2_d),
- SH_PFC_PIN_GROUP(msiof2_txd_d),
- SH_PFC_PIN_GROUP(msiof2_rxd_d),
- SH_PFC_PIN_GROUP(msiof3_clk_a),
- SH_PFC_PIN_GROUP(msiof3_sync_a),
- SH_PFC_PIN_GROUP(msiof3_ss1_a),
- SH_PFC_PIN_GROUP(msiof3_ss2_a),
- SH_PFC_PIN_GROUP(msiof3_txd_a),
- SH_PFC_PIN_GROUP(msiof3_rxd_a),
- SH_PFC_PIN_GROUP(msiof3_clk_b),
- SH_PFC_PIN_GROUP(msiof3_sync_b),
- SH_PFC_PIN_GROUP(msiof3_ss1_b),
- SH_PFC_PIN_GROUP(msiof3_ss2_b),
- SH_PFC_PIN_GROUP(msiof3_txd_b),
- SH_PFC_PIN_GROUP(msiof3_rxd_b),
- SH_PFC_PIN_GROUP(msiof3_clk_c),
- SH_PFC_PIN_GROUP(msiof3_sync_c),
- SH_PFC_PIN_GROUP(msiof3_txd_c),
- SH_PFC_PIN_GROUP(msiof3_rxd_c),
- SH_PFC_PIN_GROUP(msiof3_clk_d),
- SH_PFC_PIN_GROUP(msiof3_sync_d),
- SH_PFC_PIN_GROUP(msiof3_ss1_d),
- SH_PFC_PIN_GROUP(msiof3_txd_d),
- SH_PFC_PIN_GROUP(msiof3_rxd_d),
- SH_PFC_PIN_GROUP(msiof3_clk_e),
- SH_PFC_PIN_GROUP(msiof3_sync_e),
- SH_PFC_PIN_GROUP(msiof3_ss1_e),
- SH_PFC_PIN_GROUP(msiof3_ss2_e),
- SH_PFC_PIN_GROUP(msiof3_txd_e),
- SH_PFC_PIN_GROUP(msiof3_rxd_e),
- SH_PFC_PIN_GROUP(pwm0),
- SH_PFC_PIN_GROUP(pwm1_a),
- SH_PFC_PIN_GROUP(pwm1_b),
- SH_PFC_PIN_GROUP(pwm2_a),
- SH_PFC_PIN_GROUP(pwm2_b),
- SH_PFC_PIN_GROUP(pwm3_a),
- SH_PFC_PIN_GROUP(pwm3_b),
- SH_PFC_PIN_GROUP(pwm4_a),
- SH_PFC_PIN_GROUP(pwm4_b),
- SH_PFC_PIN_GROUP(pwm5_a),
- SH_PFC_PIN_GROUP(pwm5_b),
- SH_PFC_PIN_GROUP(pwm6_a),
- SH_PFC_PIN_GROUP(pwm6_b),
- SH_PFC_PIN_GROUP(scif0_data),
- SH_PFC_PIN_GROUP(scif0_clk),
- SH_PFC_PIN_GROUP(scif0_ctrl),
- SH_PFC_PIN_GROUP(scif1_data_a),
- SH_PFC_PIN_GROUP(scif1_clk),
- SH_PFC_PIN_GROUP(scif1_ctrl),
- SH_PFC_PIN_GROUP(scif1_data_b),
- SH_PFC_PIN_GROUP(scif2_data_a),
- SH_PFC_PIN_GROUP(scif2_clk),
- SH_PFC_PIN_GROUP(scif2_data_b),
- SH_PFC_PIN_GROUP(scif3_data_a),
- SH_PFC_PIN_GROUP(scif3_clk),
- SH_PFC_PIN_GROUP(scif3_ctrl),
- SH_PFC_PIN_GROUP(scif3_data_b),
- SH_PFC_PIN_GROUP(scif4_data_a),
- SH_PFC_PIN_GROUP(scif4_clk_a),
- SH_PFC_PIN_GROUP(scif4_ctrl_a),
- SH_PFC_PIN_GROUP(scif4_data_b),
- SH_PFC_PIN_GROUP(scif4_clk_b),
- SH_PFC_PIN_GROUP(scif4_ctrl_b),
- SH_PFC_PIN_GROUP(scif4_data_c),
- SH_PFC_PIN_GROUP(scif4_clk_c),
- SH_PFC_PIN_GROUP(scif4_ctrl_c),
- SH_PFC_PIN_GROUP(scif5_data_a),
- SH_PFC_PIN_GROUP(scif5_clk_a),
- SH_PFC_PIN_GROUP(scif5_data_b),
- SH_PFC_PIN_GROUP(scif5_clk_b),
- SH_PFC_PIN_GROUP(scif_clk_a),
- SH_PFC_PIN_GROUP(scif_clk_b),
- SH_PFC_PIN_GROUP(sdhi0_data1),
- SH_PFC_PIN_GROUP(sdhi0_data4),
- SH_PFC_PIN_GROUP(sdhi0_ctrl),
- SH_PFC_PIN_GROUP(sdhi0_cd),
- SH_PFC_PIN_GROUP(sdhi0_wp),
- SH_PFC_PIN_GROUP(sdhi1_data1),
- SH_PFC_PIN_GROUP(sdhi1_data4),
- SH_PFC_PIN_GROUP(sdhi1_ctrl),
- SH_PFC_PIN_GROUP(sdhi1_cd),
- SH_PFC_PIN_GROUP(sdhi1_wp),
- SH_PFC_PIN_GROUP(sdhi2_data1),
- SH_PFC_PIN_GROUP(sdhi2_data4),
- SH_PFC_PIN_GROUP(sdhi2_data8),
- SH_PFC_PIN_GROUP(sdhi2_ctrl),
- SH_PFC_PIN_GROUP(sdhi2_cd_a),
- SH_PFC_PIN_GROUP(sdhi2_wp_a),
- SH_PFC_PIN_GROUP(sdhi2_cd_b),
- SH_PFC_PIN_GROUP(sdhi2_wp_b),
- SH_PFC_PIN_GROUP(sdhi2_ds),
- SH_PFC_PIN_GROUP(sdhi3_data1),
- SH_PFC_PIN_GROUP(sdhi3_data4),
- SH_PFC_PIN_GROUP(sdhi3_data8),
- SH_PFC_PIN_GROUP(sdhi3_ctrl),
- SH_PFC_PIN_GROUP(sdhi3_cd),
- SH_PFC_PIN_GROUP(sdhi3_wp),
- SH_PFC_PIN_GROUP(sdhi3_ds),
- SH_PFC_PIN_GROUP(ssi0_data),
- SH_PFC_PIN_GROUP(ssi01239_ctrl),
- SH_PFC_PIN_GROUP(ssi1_data_a),
- SH_PFC_PIN_GROUP(ssi1_data_b),
- SH_PFC_PIN_GROUP(ssi1_ctrl_a),
- SH_PFC_PIN_GROUP(ssi1_ctrl_b),
- SH_PFC_PIN_GROUP(ssi2_data_a),
- SH_PFC_PIN_GROUP(ssi2_data_b),
- SH_PFC_PIN_GROUP(ssi2_ctrl_a),
- SH_PFC_PIN_GROUP(ssi2_ctrl_b),
- SH_PFC_PIN_GROUP(ssi3_data),
- SH_PFC_PIN_GROUP(ssi349_ctrl),
- SH_PFC_PIN_GROUP(ssi4_data),
- SH_PFC_PIN_GROUP(ssi4_ctrl),
- SH_PFC_PIN_GROUP(ssi5_data),
- SH_PFC_PIN_GROUP(ssi5_ctrl),
- SH_PFC_PIN_GROUP(ssi6_data),
- SH_PFC_PIN_GROUP(ssi6_ctrl),
- SH_PFC_PIN_GROUP(ssi7_data),
- SH_PFC_PIN_GROUP(ssi78_ctrl),
- SH_PFC_PIN_GROUP(ssi8_data),
- SH_PFC_PIN_GROUP(ssi9_data_a),
- SH_PFC_PIN_GROUP(ssi9_data_b),
- SH_PFC_PIN_GROUP(ssi9_ctrl_a),
- SH_PFC_PIN_GROUP(ssi9_ctrl_b),
- SH_PFC_PIN_GROUP(tmu_tclk1_a),
- SH_PFC_PIN_GROUP(tmu_tclk1_b),
- SH_PFC_PIN_GROUP(tmu_tclk2_a),
- SH_PFC_PIN_GROUP(tmu_tclk2_b),
- SH_PFC_PIN_GROUP(usb0),
- SH_PFC_PIN_GROUP(usb1),
- SH_PFC_PIN_GROUP(usb30),
- VIN_DATA_PIN_GROUP(vin4_data_a, 8),
- VIN_DATA_PIN_GROUP(vin4_data_a, 10),
- VIN_DATA_PIN_GROUP(vin4_data_a, 12),
- VIN_DATA_PIN_GROUP(vin4_data_a, 16),
- SH_PFC_PIN_GROUP(vin4_data18_a),
- VIN_DATA_PIN_GROUP(vin4_data_a, 20),
- VIN_DATA_PIN_GROUP(vin4_data_a, 24),
- VIN_DATA_PIN_GROUP(vin4_data_b, 8),
- VIN_DATA_PIN_GROUP(vin4_data_b, 10),
- VIN_DATA_PIN_GROUP(vin4_data_b, 12),
- VIN_DATA_PIN_GROUP(vin4_data_b, 16),
- SH_PFC_PIN_GROUP(vin4_data18_b),
- VIN_DATA_PIN_GROUP(vin4_data_b, 20),
- VIN_DATA_PIN_GROUP(vin4_data_b, 24),
- SH_PFC_PIN_GROUP(vin4_sync),
- SH_PFC_PIN_GROUP(vin4_field),
- SH_PFC_PIN_GROUP(vin4_clkenb),
- SH_PFC_PIN_GROUP(vin4_clk),
- SH_PFC_PIN_GROUP(vin5_data8),
- SH_PFC_PIN_GROUP(vin5_data10),
- SH_PFC_PIN_GROUP(vin5_data12),
- SH_PFC_PIN_GROUP(vin5_data16),
- SH_PFC_PIN_GROUP(vin5_sync),
- SH_PFC_PIN_GROUP(vin5_field),
- SH_PFC_PIN_GROUP(vin5_clkenb),
- SH_PFC_PIN_GROUP(vin5_clk),
+static const struct {
+ struct sh_pfc_pin_group common[307];
+ struct sh_pfc_pin_group automotive[33];
+} pinmux_groups = {
+ .common = {
+ SH_PFC_PIN_GROUP(audio_clk_a_a),
+ SH_PFC_PIN_GROUP(audio_clk_a_b),
+ SH_PFC_PIN_GROUP(audio_clk_a_c),
+ SH_PFC_PIN_GROUP(audio_clk_b_a),
+ SH_PFC_PIN_GROUP(audio_clk_b_b),
+ SH_PFC_PIN_GROUP(audio_clk_c_a),
+ SH_PFC_PIN_GROUP(audio_clk_c_b),
+ SH_PFC_PIN_GROUP(audio_clkout_a),
+ SH_PFC_PIN_GROUP(audio_clkout_b),
+ SH_PFC_PIN_GROUP(audio_clkout_c),
+ SH_PFC_PIN_GROUP(audio_clkout_d),
+ SH_PFC_PIN_GROUP(audio_clkout1_a),
+ SH_PFC_PIN_GROUP(audio_clkout1_b),
+ SH_PFC_PIN_GROUP(audio_clkout2_a),
+ SH_PFC_PIN_GROUP(audio_clkout2_b),
+ SH_PFC_PIN_GROUP(audio_clkout3_a),
+ SH_PFC_PIN_GROUP(audio_clkout3_b),
+ 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(avb_mdio),
+ SH_PFC_PIN_GROUP(avb_mii),
+ SH_PFC_PIN_GROUP(avb_avtp_pps),
+ SH_PFC_PIN_GROUP(avb_avtp_match_a),
+ SH_PFC_PIN_GROUP(avb_avtp_capture_a),
+ SH_PFC_PIN_GROUP(avb_avtp_match_b),
+ SH_PFC_PIN_GROUP(avb_avtp_capture_b),
+ SH_PFC_PIN_GROUP(can0_data_a),
+ SH_PFC_PIN_GROUP(can0_data_b),
+ SH_PFC_PIN_GROUP(can1_data),
+ SH_PFC_PIN_GROUP(can_clk),
+ SH_PFC_PIN_GROUP(du_rgb666),
+ SH_PFC_PIN_GROUP(du_rgb888),
+ SH_PFC_PIN_GROUP(du_clk_out_0),
+ SH_PFC_PIN_GROUP(du_clk_out_1),
+ SH_PFC_PIN_GROUP(du_sync),
+ SH_PFC_PIN_GROUP(du_oddf),
+ SH_PFC_PIN_GROUP(du_cde),
+ SH_PFC_PIN_GROUP(du_disp),
+ SH_PFC_PIN_GROUP(hdmi0_cec),
+ SH_PFC_PIN_GROUP(hscif0_data),
+ SH_PFC_PIN_GROUP(hscif0_clk),
+ SH_PFC_PIN_GROUP(hscif0_ctrl),
+ SH_PFC_PIN_GROUP(hscif1_data_a),
+ SH_PFC_PIN_GROUP(hscif1_clk_a),
+ SH_PFC_PIN_GROUP(hscif1_ctrl_a),
+ SH_PFC_PIN_GROUP(hscif1_data_b),
+ SH_PFC_PIN_GROUP(hscif1_clk_b),
+ SH_PFC_PIN_GROUP(hscif1_ctrl_b),
+ SH_PFC_PIN_GROUP(hscif2_data_a),
+ SH_PFC_PIN_GROUP(hscif2_clk_a),
+ SH_PFC_PIN_GROUP(hscif2_ctrl_a),
+ SH_PFC_PIN_GROUP(hscif2_data_b),
+ SH_PFC_PIN_GROUP(hscif2_clk_b),
+ SH_PFC_PIN_GROUP(hscif2_ctrl_b),
+ SH_PFC_PIN_GROUP(hscif2_data_c),
+ SH_PFC_PIN_GROUP(hscif2_clk_c),
+ SH_PFC_PIN_GROUP(hscif2_ctrl_c),
+ SH_PFC_PIN_GROUP(hscif3_data_a),
+ SH_PFC_PIN_GROUP(hscif3_clk),
+ SH_PFC_PIN_GROUP(hscif3_ctrl),
+ SH_PFC_PIN_GROUP(hscif3_data_b),
+ SH_PFC_PIN_GROUP(hscif3_data_c),
+ SH_PFC_PIN_GROUP(hscif3_data_d),
+ SH_PFC_PIN_GROUP(hscif4_data_a),
+ SH_PFC_PIN_GROUP(hscif4_clk),
+ SH_PFC_PIN_GROUP(hscif4_ctrl),
+ SH_PFC_PIN_GROUP(hscif4_data_b),
+ SH_PFC_PIN_GROUP(i2c1_a),
+ SH_PFC_PIN_GROUP(i2c1_b),
+ SH_PFC_PIN_GROUP(i2c2_a),
+ SH_PFC_PIN_GROUP(i2c2_b),
+ SH_PFC_PIN_GROUP(i2c6_a),
+ SH_PFC_PIN_GROUP(i2c6_b),
+ SH_PFC_PIN_GROUP(i2c6_c),
+ SH_PFC_PIN_GROUP(intc_ex_irq0),
+ SH_PFC_PIN_GROUP(intc_ex_irq1),
+ SH_PFC_PIN_GROUP(intc_ex_irq2),
+ SH_PFC_PIN_GROUP(intc_ex_irq3),
+ SH_PFC_PIN_GROUP(intc_ex_irq4),
+ SH_PFC_PIN_GROUP(intc_ex_irq5),
+ SH_PFC_PIN_GROUP(msiof0_clk),
+ SH_PFC_PIN_GROUP(msiof0_sync),
+ SH_PFC_PIN_GROUP(msiof0_ss1),
+ SH_PFC_PIN_GROUP(msiof0_ss2),
+ SH_PFC_PIN_GROUP(msiof0_txd),
+ SH_PFC_PIN_GROUP(msiof0_rxd),
+ SH_PFC_PIN_GROUP(msiof1_clk_a),
+ SH_PFC_PIN_GROUP(msiof1_sync_a),
+ SH_PFC_PIN_GROUP(msiof1_ss1_a),
+ SH_PFC_PIN_GROUP(msiof1_ss2_a),
+ SH_PFC_PIN_GROUP(msiof1_txd_a),
+ SH_PFC_PIN_GROUP(msiof1_rxd_a),
+ SH_PFC_PIN_GROUP(msiof1_clk_b),
+ SH_PFC_PIN_GROUP(msiof1_sync_b),
+ SH_PFC_PIN_GROUP(msiof1_ss1_b),
+ SH_PFC_PIN_GROUP(msiof1_ss2_b),
+ SH_PFC_PIN_GROUP(msiof1_txd_b),
+ SH_PFC_PIN_GROUP(msiof1_rxd_b),
+ SH_PFC_PIN_GROUP(msiof1_clk_c),
+ SH_PFC_PIN_GROUP(msiof1_sync_c),
+ SH_PFC_PIN_GROUP(msiof1_ss1_c),
+ SH_PFC_PIN_GROUP(msiof1_ss2_c),
+ SH_PFC_PIN_GROUP(msiof1_txd_c),
+ SH_PFC_PIN_GROUP(msiof1_rxd_c),
+ SH_PFC_PIN_GROUP(msiof1_clk_d),
+ SH_PFC_PIN_GROUP(msiof1_sync_d),
+ SH_PFC_PIN_GROUP(msiof1_ss1_d),
+ SH_PFC_PIN_GROUP(msiof1_ss2_d),
+ SH_PFC_PIN_GROUP(msiof1_txd_d),
+ SH_PFC_PIN_GROUP(msiof1_rxd_d),
+ SH_PFC_PIN_GROUP(msiof1_clk_e),
+ SH_PFC_PIN_GROUP(msiof1_sync_e),
+ SH_PFC_PIN_GROUP(msiof1_ss1_e),
+ SH_PFC_PIN_GROUP(msiof1_ss2_e),
+ SH_PFC_PIN_GROUP(msiof1_txd_e),
+ SH_PFC_PIN_GROUP(msiof1_rxd_e),
+ SH_PFC_PIN_GROUP(msiof1_clk_f),
+ SH_PFC_PIN_GROUP(msiof1_sync_f),
+ SH_PFC_PIN_GROUP(msiof1_ss1_f),
+ SH_PFC_PIN_GROUP(msiof1_ss2_f),
+ SH_PFC_PIN_GROUP(msiof1_txd_f),
+ SH_PFC_PIN_GROUP(msiof1_rxd_f),
+ SH_PFC_PIN_GROUP(msiof1_clk_g),
+ SH_PFC_PIN_GROUP(msiof1_sync_g),
+ SH_PFC_PIN_GROUP(msiof1_ss1_g),
+ SH_PFC_PIN_GROUP(msiof1_ss2_g),
+ SH_PFC_PIN_GROUP(msiof1_txd_g),
+ SH_PFC_PIN_GROUP(msiof1_rxd_g),
+ SH_PFC_PIN_GROUP(msiof2_clk_a),
+ SH_PFC_PIN_GROUP(msiof2_sync_a),
+ SH_PFC_PIN_GROUP(msiof2_ss1_a),
+ SH_PFC_PIN_GROUP(msiof2_ss2_a),
+ SH_PFC_PIN_GROUP(msiof2_txd_a),
+ SH_PFC_PIN_GROUP(msiof2_rxd_a),
+ SH_PFC_PIN_GROUP(msiof2_clk_b),
+ SH_PFC_PIN_GROUP(msiof2_sync_b),
+ SH_PFC_PIN_GROUP(msiof2_ss1_b),
+ SH_PFC_PIN_GROUP(msiof2_ss2_b),
+ SH_PFC_PIN_GROUP(msiof2_txd_b),
+ SH_PFC_PIN_GROUP(msiof2_rxd_b),
+ SH_PFC_PIN_GROUP(msiof2_clk_c),
+ SH_PFC_PIN_GROUP(msiof2_sync_c),
+ SH_PFC_PIN_GROUP(msiof2_ss1_c),
+ SH_PFC_PIN_GROUP(msiof2_ss2_c),
+ SH_PFC_PIN_GROUP(msiof2_txd_c),
+ SH_PFC_PIN_GROUP(msiof2_rxd_c),
+ SH_PFC_PIN_GROUP(msiof2_clk_d),
+ SH_PFC_PIN_GROUP(msiof2_sync_d),
+ SH_PFC_PIN_GROUP(msiof2_ss1_d),
+ SH_PFC_PIN_GROUP(msiof2_ss2_d),
+ SH_PFC_PIN_GROUP(msiof2_txd_d),
+ SH_PFC_PIN_GROUP(msiof2_rxd_d),
+ SH_PFC_PIN_GROUP(msiof3_clk_a),
+ SH_PFC_PIN_GROUP(msiof3_sync_a),
+ SH_PFC_PIN_GROUP(msiof3_ss1_a),
+ SH_PFC_PIN_GROUP(msiof3_ss2_a),
+ SH_PFC_PIN_GROUP(msiof3_txd_a),
+ SH_PFC_PIN_GROUP(msiof3_rxd_a),
+ SH_PFC_PIN_GROUP(msiof3_clk_b),
+ SH_PFC_PIN_GROUP(msiof3_sync_b),
+ SH_PFC_PIN_GROUP(msiof3_ss1_b),
+ SH_PFC_PIN_GROUP(msiof3_ss2_b),
+ SH_PFC_PIN_GROUP(msiof3_txd_b),
+ SH_PFC_PIN_GROUP(msiof3_rxd_b),
+ SH_PFC_PIN_GROUP(msiof3_clk_c),
+ SH_PFC_PIN_GROUP(msiof3_sync_c),
+ SH_PFC_PIN_GROUP(msiof3_txd_c),
+ SH_PFC_PIN_GROUP(msiof3_rxd_c),
+ SH_PFC_PIN_GROUP(msiof3_clk_d),
+ SH_PFC_PIN_GROUP(msiof3_sync_d),
+ SH_PFC_PIN_GROUP(msiof3_ss1_d),
+ SH_PFC_PIN_GROUP(msiof3_txd_d),
+ SH_PFC_PIN_GROUP(msiof3_rxd_d),
+ SH_PFC_PIN_GROUP(msiof3_clk_e),
+ SH_PFC_PIN_GROUP(msiof3_sync_e),
+ SH_PFC_PIN_GROUP(msiof3_ss1_e),
+ SH_PFC_PIN_GROUP(msiof3_ss2_e),
+ SH_PFC_PIN_GROUP(msiof3_txd_e),
+ SH_PFC_PIN_GROUP(msiof3_rxd_e),
+ SH_PFC_PIN_GROUP(pwm0),
+ SH_PFC_PIN_GROUP(pwm1_a),
+ SH_PFC_PIN_GROUP(pwm1_b),
+ SH_PFC_PIN_GROUP(pwm2_a),
+ SH_PFC_PIN_GROUP(pwm2_b),
+ SH_PFC_PIN_GROUP(pwm3_a),
+ SH_PFC_PIN_GROUP(pwm3_b),
+ SH_PFC_PIN_GROUP(pwm4_a),
+ SH_PFC_PIN_GROUP(pwm4_b),
+ SH_PFC_PIN_GROUP(pwm5_a),
+ SH_PFC_PIN_GROUP(pwm5_b),
+ SH_PFC_PIN_GROUP(pwm6_a),
+ SH_PFC_PIN_GROUP(pwm6_b),
+ SH_PFC_PIN_GROUP(scif0_data),
+ SH_PFC_PIN_GROUP(scif0_clk),
+ SH_PFC_PIN_GROUP(scif0_ctrl),
+ SH_PFC_PIN_GROUP(scif1_data_a),
+ SH_PFC_PIN_GROUP(scif1_clk),
+ SH_PFC_PIN_GROUP(scif1_ctrl),
+ SH_PFC_PIN_GROUP(scif1_data_b),
+ SH_PFC_PIN_GROUP(scif2_data_a),
+ SH_PFC_PIN_GROUP(scif2_clk),
+ SH_PFC_PIN_GROUP(scif2_data_b),
+ SH_PFC_PIN_GROUP(scif3_data_a),
+ SH_PFC_PIN_GROUP(scif3_clk),
+ SH_PFC_PIN_GROUP(scif3_ctrl),
+ SH_PFC_PIN_GROUP(scif3_data_b),
+ SH_PFC_PIN_GROUP(scif4_data_a),
+ SH_PFC_PIN_GROUP(scif4_clk_a),
+ SH_PFC_PIN_GROUP(scif4_ctrl_a),
+ SH_PFC_PIN_GROUP(scif4_data_b),
+ SH_PFC_PIN_GROUP(scif4_clk_b),
+ SH_PFC_PIN_GROUP(scif4_ctrl_b),
+ SH_PFC_PIN_GROUP(scif4_data_c),
+ SH_PFC_PIN_GROUP(scif4_clk_c),
+ SH_PFC_PIN_GROUP(scif4_ctrl_c),
+ SH_PFC_PIN_GROUP(scif5_data_a),
+ SH_PFC_PIN_GROUP(scif5_clk_a),
+ SH_PFC_PIN_GROUP(scif5_data_b),
+ SH_PFC_PIN_GROUP(scif5_clk_b),
+ SH_PFC_PIN_GROUP(scif_clk_a),
+ SH_PFC_PIN_GROUP(scif_clk_b),
+ SH_PFC_PIN_GROUP(sdhi0_data1),
+ SH_PFC_PIN_GROUP(sdhi0_data4),
+ SH_PFC_PIN_GROUP(sdhi0_ctrl),
+ SH_PFC_PIN_GROUP(sdhi0_cd),
+ SH_PFC_PIN_GROUP(sdhi0_wp),
+ SH_PFC_PIN_GROUP(sdhi1_data1),
+ SH_PFC_PIN_GROUP(sdhi1_data4),
+ SH_PFC_PIN_GROUP(sdhi1_ctrl),
+ SH_PFC_PIN_GROUP(sdhi1_cd),
+ SH_PFC_PIN_GROUP(sdhi1_wp),
+ SH_PFC_PIN_GROUP(sdhi2_data1),
+ SH_PFC_PIN_GROUP(sdhi2_data4),
+ SH_PFC_PIN_GROUP(sdhi2_data8),
+ SH_PFC_PIN_GROUP(sdhi2_ctrl),
+ SH_PFC_PIN_GROUP(sdhi2_cd_a),
+ SH_PFC_PIN_GROUP(sdhi2_wp_a),
+ SH_PFC_PIN_GROUP(sdhi2_cd_b),
+ SH_PFC_PIN_GROUP(sdhi2_wp_b),
+ SH_PFC_PIN_GROUP(sdhi2_ds),
+ SH_PFC_PIN_GROUP(sdhi3_data1),
+ SH_PFC_PIN_GROUP(sdhi3_data4),
+ SH_PFC_PIN_GROUP(sdhi3_data8),
+ SH_PFC_PIN_GROUP(sdhi3_ctrl),
+ SH_PFC_PIN_GROUP(sdhi3_cd),
+ SH_PFC_PIN_GROUP(sdhi3_wp),
+ SH_PFC_PIN_GROUP(sdhi3_ds),
+ SH_PFC_PIN_GROUP(ssi0_data),
+ SH_PFC_PIN_GROUP(ssi01239_ctrl),
+ SH_PFC_PIN_GROUP(ssi1_data_a),
+ SH_PFC_PIN_GROUP(ssi1_data_b),
+ SH_PFC_PIN_GROUP(ssi1_ctrl_a),
+ SH_PFC_PIN_GROUP(ssi1_ctrl_b),
+ SH_PFC_PIN_GROUP(ssi2_data_a),
+ SH_PFC_PIN_GROUP(ssi2_data_b),
+ SH_PFC_PIN_GROUP(ssi2_ctrl_a),
+ SH_PFC_PIN_GROUP(ssi2_ctrl_b),
+ SH_PFC_PIN_GROUP(ssi3_data),
+ SH_PFC_PIN_GROUP(ssi349_ctrl),
+ SH_PFC_PIN_GROUP(ssi4_data),
+ SH_PFC_PIN_GROUP(ssi4_ctrl),
+ SH_PFC_PIN_GROUP(ssi5_data),
+ SH_PFC_PIN_GROUP(ssi5_ctrl),
+ SH_PFC_PIN_GROUP(ssi6_data),
+ SH_PFC_PIN_GROUP(ssi6_ctrl),
+ SH_PFC_PIN_GROUP(ssi7_data),
+ SH_PFC_PIN_GROUP(ssi78_ctrl),
+ SH_PFC_PIN_GROUP(ssi8_data),
+ SH_PFC_PIN_GROUP(ssi9_data_a),
+ SH_PFC_PIN_GROUP(ssi9_data_b),
+ SH_PFC_PIN_GROUP(ssi9_ctrl_a),
+ SH_PFC_PIN_GROUP(ssi9_ctrl_b),
+ SH_PFC_PIN_GROUP(tmu_tclk1_a),
+ SH_PFC_PIN_GROUP(tmu_tclk1_b),
+ SH_PFC_PIN_GROUP(tmu_tclk2_a),
+ SH_PFC_PIN_GROUP(tmu_tclk2_b),
+ SH_PFC_PIN_GROUP(usb0),
+ SH_PFC_PIN_GROUP(usb1),
+ SH_PFC_PIN_GROUP(usb30),
+ VIN_DATA_PIN_GROUP(vin4_data_a, 8),
+ VIN_DATA_PIN_GROUP(vin4_data_a, 10),
+ VIN_DATA_PIN_GROUP(vin4_data_a, 12),
+ VIN_DATA_PIN_GROUP(vin4_data_a, 16),
+ SH_PFC_PIN_GROUP(vin4_data18_a),
+ VIN_DATA_PIN_GROUP(vin4_data_a, 20),
+ VIN_DATA_PIN_GROUP(vin4_data_a, 24),
+ VIN_DATA_PIN_GROUP(vin4_data_b, 8),
+ VIN_DATA_PIN_GROUP(vin4_data_b, 10),
+ VIN_DATA_PIN_GROUP(vin4_data_b, 12),
+ VIN_DATA_PIN_GROUP(vin4_data_b, 16),
+ SH_PFC_PIN_GROUP(vin4_data18_b),
+ VIN_DATA_PIN_GROUP(vin4_data_b, 20),
+ VIN_DATA_PIN_GROUP(vin4_data_b, 24),
+ SH_PFC_PIN_GROUP(vin4_sync),
+ SH_PFC_PIN_GROUP(vin4_field),
+ SH_PFC_PIN_GROUP(vin4_clkenb),
+ SH_PFC_PIN_GROUP(vin4_clk),
+ SH_PFC_PIN_GROUP(vin5_data8),
+ SH_PFC_PIN_GROUP(vin5_data10),
+ SH_PFC_PIN_GROUP(vin5_data12),
+ SH_PFC_PIN_GROUP(vin5_data16),
+ SH_PFC_PIN_GROUP(vin5_sync),
+ SH_PFC_PIN_GROUP(vin5_field),
+ SH_PFC_PIN_GROUP(vin5_clkenb),
+ SH_PFC_PIN_GROUP(vin5_clk),
+ },
+ .automotive = {
+ SH_PFC_PIN_GROUP(canfd0_data_a),
+ SH_PFC_PIN_GROUP(canfd0_data_b),
+ SH_PFC_PIN_GROUP(canfd1_data),
+ SH_PFC_PIN_GROUP(drif0_ctrl_a),
+ SH_PFC_PIN_GROUP(drif0_data0_a),
+ SH_PFC_PIN_GROUP(drif0_data1_a),
+ SH_PFC_PIN_GROUP(drif0_ctrl_b),
+ SH_PFC_PIN_GROUP(drif0_data0_b),
+ SH_PFC_PIN_GROUP(drif0_data1_b),
+ SH_PFC_PIN_GROUP(drif0_ctrl_c),
+ SH_PFC_PIN_GROUP(drif0_data0_c),
+ SH_PFC_PIN_GROUP(drif0_data1_c),
+ SH_PFC_PIN_GROUP(drif1_ctrl_a),
+ SH_PFC_PIN_GROUP(drif1_data0_a),
+ SH_PFC_PIN_GROUP(drif1_data1_a),
+ SH_PFC_PIN_GROUP(drif1_ctrl_b),
+ SH_PFC_PIN_GROUP(drif1_data0_b),
+ SH_PFC_PIN_GROUP(drif1_data1_b),
+ SH_PFC_PIN_GROUP(drif1_ctrl_c),
+ SH_PFC_PIN_GROUP(drif1_data0_c),
+ SH_PFC_PIN_GROUP(drif1_data1_c),
+ SH_PFC_PIN_GROUP(drif2_ctrl_a),
+ SH_PFC_PIN_GROUP(drif2_data0_a),
+ SH_PFC_PIN_GROUP(drif2_data1_a),
+ SH_PFC_PIN_GROUP(drif2_ctrl_b),
+ SH_PFC_PIN_GROUP(drif2_data0_b),
+ SH_PFC_PIN_GROUP(drif2_data1_b),
+ SH_PFC_PIN_GROUP(drif3_ctrl_a),
+ SH_PFC_PIN_GROUP(drif3_data0_a),
+ SH_PFC_PIN_GROUP(drif3_data1_a),
+ SH_PFC_PIN_GROUP(drif3_ctrl_b),
+ SH_PFC_PIN_GROUP(drif3_data0_b),
+ SH_PFC_PIN_GROUP(drif3_data1_b),
+ }
};
static const char * const audio_clk_groups[] = {
@@ -4962,58 +4966,65 @@ static const char * const vin5_groups[] = {
"vin5_clk",
};
-static const struct sh_pfc_function pinmux_functions[] = {
- SH_PFC_FUNCTION(audio_clk),
- SH_PFC_FUNCTION(avb),
- SH_PFC_FUNCTION(can0),
- SH_PFC_FUNCTION(can1),
- SH_PFC_FUNCTION(can_clk),
- SH_PFC_FUNCTION(canfd0),
- SH_PFC_FUNCTION(canfd1),
- SH_PFC_FUNCTION(drif0),
- SH_PFC_FUNCTION(drif1),
- SH_PFC_FUNCTION(drif2),
- SH_PFC_FUNCTION(drif3),
- SH_PFC_FUNCTION(du),
- SH_PFC_FUNCTION(hdmi0),
- SH_PFC_FUNCTION(hscif0),
- SH_PFC_FUNCTION(hscif1),
- SH_PFC_FUNCTION(hscif2),
- SH_PFC_FUNCTION(hscif3),
- SH_PFC_FUNCTION(hscif4),
- SH_PFC_FUNCTION(i2c1),
- SH_PFC_FUNCTION(i2c2),
- SH_PFC_FUNCTION(i2c6),
- SH_PFC_FUNCTION(intc_ex),
- SH_PFC_FUNCTION(msiof0),
- SH_PFC_FUNCTION(msiof1),
- SH_PFC_FUNCTION(msiof2),
- SH_PFC_FUNCTION(msiof3),
- SH_PFC_FUNCTION(pwm0),
- SH_PFC_FUNCTION(pwm1),
- SH_PFC_FUNCTION(pwm2),
- SH_PFC_FUNCTION(pwm3),
- SH_PFC_FUNCTION(pwm4),
- SH_PFC_FUNCTION(pwm5),
- SH_PFC_FUNCTION(pwm6),
- SH_PFC_FUNCTION(scif0),
- SH_PFC_FUNCTION(scif1),
- SH_PFC_FUNCTION(scif2),
- SH_PFC_FUNCTION(scif3),
- SH_PFC_FUNCTION(scif4),
- SH_PFC_FUNCTION(scif5),
- SH_PFC_FUNCTION(scif_clk),
- SH_PFC_FUNCTION(sdhi0),
- SH_PFC_FUNCTION(sdhi1),
- SH_PFC_FUNCTION(sdhi2),
- SH_PFC_FUNCTION(sdhi3),
- SH_PFC_FUNCTION(ssi),
- SH_PFC_FUNCTION(tmu),
- SH_PFC_FUNCTION(usb0),
- SH_PFC_FUNCTION(usb1),
- SH_PFC_FUNCTION(usb30),
- SH_PFC_FUNCTION(vin4),
- SH_PFC_FUNCTION(vin5),
+static const struct {
+ struct sh_pfc_function common[45];
+ struct sh_pfc_function automotive[6];
+} pinmux_functions = {
+ .common = {
+ SH_PFC_FUNCTION(audio_clk),
+ SH_PFC_FUNCTION(avb),
+ SH_PFC_FUNCTION(can0),
+ SH_PFC_FUNCTION(can1),
+ SH_PFC_FUNCTION(can_clk),
+ SH_PFC_FUNCTION(du),
+ SH_PFC_FUNCTION(hdmi0),
+ SH_PFC_FUNCTION(hscif0),
+ SH_PFC_FUNCTION(hscif1),
+ SH_PFC_FUNCTION(hscif2),
+ SH_PFC_FUNCTION(hscif3),
+ SH_PFC_FUNCTION(hscif4),
+ SH_PFC_FUNCTION(i2c1),
+ SH_PFC_FUNCTION(i2c2),
+ SH_PFC_FUNCTION(i2c6),
+ SH_PFC_FUNCTION(intc_ex),
+ SH_PFC_FUNCTION(msiof0),
+ SH_PFC_FUNCTION(msiof1),
+ SH_PFC_FUNCTION(msiof2),
+ SH_PFC_FUNCTION(msiof3),
+ SH_PFC_FUNCTION(pwm0),
+ SH_PFC_FUNCTION(pwm1),
+ SH_PFC_FUNCTION(pwm2),
+ SH_PFC_FUNCTION(pwm3),
+ SH_PFC_FUNCTION(pwm4),
+ SH_PFC_FUNCTION(pwm5),
+ SH_PFC_FUNCTION(pwm6),
+ SH_PFC_FUNCTION(scif0),
+ SH_PFC_FUNCTION(scif1),
+ SH_PFC_FUNCTION(scif2),
+ SH_PFC_FUNCTION(scif3),
+ SH_PFC_FUNCTION(scif4),
+ SH_PFC_FUNCTION(scif5),
+ SH_PFC_FUNCTION(scif_clk),
+ SH_PFC_FUNCTION(sdhi0),
+ SH_PFC_FUNCTION(sdhi1),
+ SH_PFC_FUNCTION(sdhi2),
+ SH_PFC_FUNCTION(sdhi3),
+ SH_PFC_FUNCTION(ssi),
+ SH_PFC_FUNCTION(tmu),
+ SH_PFC_FUNCTION(usb0),
+ SH_PFC_FUNCTION(usb1),
+ SH_PFC_FUNCTION(usb30),
+ SH_PFC_FUNCTION(vin4),
+ SH_PFC_FUNCTION(vin5),
+ },
+ .automotive = {
+ SH_PFC_FUNCTION(canfd0),
+ SH_PFC_FUNCTION(canfd1),
+ SH_PFC_FUNCTION(drif0),
+ SH_PFC_FUNCTION(drif1),
+ SH_PFC_FUNCTION(drif2),
+ SH_PFC_FUNCTION(drif3),
+ }
};
static const struct pinmux_cfg_reg pinmux_config_regs[] = {
@@ -6137,6 +6148,32 @@ static const struct sh_pfc_soc_operations r8a7796_pinmux_ops = {
.set_bias = r8a7796_pinmux_set_bias,
};
+#ifdef CONFIG_PINCTRL_PFC_R8A774A1
+const struct sh_pfc_soc_info r8a774a1_pinmux_info = {
+ .name = "r8a774a1_pfc",
+ .ops = &r8a7796_pinmux_ops,
+ .unlock_reg = 0xe6060000, /* PMMR */
+
+ .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
+
+ .pins = pinmux_pins,
+ .nr_pins = ARRAY_SIZE(pinmux_pins),
+ .groups = pinmux_groups.common,
+ .nr_groups = ARRAY_SIZE(pinmux_groups.common),
+ .functions = pinmux_functions.common,
+ .nr_functions = ARRAY_SIZE(pinmux_functions.common),
+
+ .cfg_regs = pinmux_config_regs,
+ .drive_regs = pinmux_drive_regs,
+ .bias_regs = pinmux_bias_regs,
+ .ioctrl_regs = pinmux_ioctrl_regs,
+
+ .pinmux_data = pinmux_data,
+ .pinmux_data_size = ARRAY_SIZE(pinmux_data),
+};
+#endif
+
+#ifdef CONFIG_PINCTRL_PFC_R8A7796
const struct sh_pfc_soc_info r8a7796_pinmux_info = {
.name = "r8a77960_pfc",
.ops = &r8a7796_pinmux_ops,
@@ -6146,10 +6183,12 @@ const struct sh_pfc_soc_info r8a7796_pinmux_info = {
.pins = pinmux_pins,
.nr_pins = ARRAY_SIZE(pinmux_pins),
- .groups = pinmux_groups,
- .nr_groups = ARRAY_SIZE(pinmux_groups),
- .functions = pinmux_functions,
- .nr_functions = ARRAY_SIZE(pinmux_functions),
+ .groups = pinmux_groups.common,
+ .nr_groups = ARRAY_SIZE(pinmux_groups.common) +
+ ARRAY_SIZE(pinmux_groups.automotive),
+ .functions = pinmux_functions.common,
+ .nr_functions = ARRAY_SIZE(pinmux_functions.common) +
+ ARRAY_SIZE(pinmux_functions.automotive),
.cfg_regs = pinmux_config_regs,
.drive_regs = pinmux_drive_regs,
@@ -6159,3 +6198,4 @@ const struct sh_pfc_soc_info r8a7796_pinmux_info = {
.pinmux_data = pinmux_data,
.pinmux_data_size = ARRAY_SIZE(pinmux_data),
};
+#endif
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a77965.c b/drivers/pinctrl/sh-pfc/pfc-r8a77965.c
index cfd7de67e3e3..dfdd982984d4 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a77965.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a77965.c
@@ -1575,6 +1575,128 @@ static const struct sh_pfc_pin pinmux_pins[] = {
SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 30, ASEBRK, CFG_FLAGS),
};
+/* - AUDIO CLOCK ------------------------------------------------------------ */
+static const unsigned int audio_clk_a_a_pins[] = {
+ /* CLK A */
+ RCAR_GP_PIN(6, 22),
+};
+static const unsigned int audio_clk_a_a_mux[] = {
+ AUDIO_CLKA_A_MARK,
+};
+static const unsigned int audio_clk_a_b_pins[] = {
+ /* CLK A */
+ RCAR_GP_PIN(5, 4),
+};
+static const unsigned int audio_clk_a_b_mux[] = {
+ AUDIO_CLKA_B_MARK,
+};
+static const unsigned int audio_clk_a_c_pins[] = {
+ /* CLK A */
+ RCAR_GP_PIN(5, 19),
+};
+static const unsigned int audio_clk_a_c_mux[] = {
+ AUDIO_CLKA_C_MARK,
+};
+static const unsigned int audio_clk_b_a_pins[] = {
+ /* CLK B */
+ RCAR_GP_PIN(5, 12),
+};
+static const unsigned int audio_clk_b_a_mux[] = {
+ AUDIO_CLKB_A_MARK,
+};
+static const unsigned int audio_clk_b_b_pins[] = {
+ /* CLK B */
+ RCAR_GP_PIN(6, 23),
+};
+static const unsigned int audio_clk_b_b_mux[] = {
+ AUDIO_CLKB_B_MARK,
+};
+static const unsigned int audio_clk_c_a_pins[] = {
+ /* CLK C */
+ RCAR_GP_PIN(5, 21),
+};
+static const unsigned int audio_clk_c_a_mux[] = {
+ AUDIO_CLKC_A_MARK,
+};
+static const unsigned int audio_clk_c_b_pins[] = {
+ /* CLK C */
+ RCAR_GP_PIN(5, 0),
+};
+static const unsigned int audio_clk_c_b_mux[] = {
+ AUDIO_CLKC_B_MARK,
+};
+static const unsigned int audio_clkout_a_pins[] = {
+ /* CLKOUT */
+ RCAR_GP_PIN(5, 18),
+};
+static const unsigned int audio_clkout_a_mux[] = {
+ AUDIO_CLKOUT_A_MARK,
+};
+static const unsigned int audio_clkout_b_pins[] = {
+ /* CLKOUT */
+ RCAR_GP_PIN(6, 28),
+};
+static const unsigned int audio_clkout_b_mux[] = {
+ AUDIO_CLKOUT_B_MARK,
+};
+static const unsigned int audio_clkout_c_pins[] = {
+ /* CLKOUT */
+ RCAR_GP_PIN(5, 3),
+};
+static const unsigned int audio_clkout_c_mux[] = {
+ AUDIO_CLKOUT_C_MARK,
+};
+static const unsigned int audio_clkout_d_pins[] = {
+ /* CLKOUT */
+ RCAR_GP_PIN(5, 21),
+};
+static const unsigned int audio_clkout_d_mux[] = {
+ AUDIO_CLKOUT_D_MARK,
+};
+static const unsigned int audio_clkout1_a_pins[] = {
+ /* CLKOUT1 */
+ RCAR_GP_PIN(5, 15),
+};
+static const unsigned int audio_clkout1_a_mux[] = {
+ AUDIO_CLKOUT1_A_MARK,
+};
+static const unsigned int audio_clkout1_b_pins[] = {
+ /* CLKOUT1 */
+ RCAR_GP_PIN(6, 29),
+};
+static const unsigned int audio_clkout1_b_mux[] = {
+ AUDIO_CLKOUT1_B_MARK,
+};
+static const unsigned int audio_clkout2_a_pins[] = {
+ /* CLKOUT2 */
+ RCAR_GP_PIN(5, 16),
+};
+static const unsigned int audio_clkout2_a_mux[] = {
+ AUDIO_CLKOUT2_A_MARK,
+};
+static const unsigned int audio_clkout2_b_pins[] = {
+ /* CLKOUT2 */
+ RCAR_GP_PIN(6, 30),
+};
+static const unsigned int audio_clkout2_b_mux[] = {
+ AUDIO_CLKOUT2_B_MARK,
+};
+
+static const unsigned int audio_clkout3_a_pins[] = {
+ /* CLKOUT3 */
+ RCAR_GP_PIN(5, 19),
+};
+static const unsigned int audio_clkout3_a_mux[] = {
+ AUDIO_CLKOUT3_A_MARK,
+};
+static const unsigned int audio_clkout3_b_pins[] = {
+ /* CLKOUT3 */
+ RCAR_GP_PIN(6, 31),
+};
+static const unsigned int audio_clkout3_b_mux[] = {
+ AUDIO_CLKOUT3_B_MARK,
+};
+
/* - EtherAVB --------------------------------------------------------------- */
static const unsigned int avb_link_pins[] = {
/* AVB_LINK */
@@ -2907,6 +3029,25 @@ static const unsigned int pwm6_b_mux[] = {
PWM6_B_MARK,
};
+/* - SATA --------------------------------------------------------------------*/
+static const unsigned int sata0_devslp_a_pins[] = {
+ /* DEVSLP */
+ RCAR_GP_PIN(6, 16),
+};
+
+static const unsigned int sata0_devslp_a_mux[] = {
+ SATA_DEVSLP_A_MARK,
+};
+
+static const unsigned int sata0_devslp_b_pins[] = {
+ /* DEVSLP */
+ RCAR_GP_PIN(4, 6),
+};
+
+static const unsigned int sata0_devslp_b_mux[] = {
+ SATA_DEVSLP_B_MARK,
+};
+
/* - SCIF0 ------------------------------------------------------------------ */
static const unsigned int scif0_data_pins[] = {
/* RX, TX */
@@ -3376,6 +3517,184 @@ static const unsigned int sdhi3_ds_mux[] = {
SD3_DS_MARK,
};
+/* - SSI -------------------------------------------------------------------- */
+static const unsigned int ssi0_data_pins[] = {
+ /* SDATA */
+ RCAR_GP_PIN(6, 2),
+};
+static const unsigned int ssi0_data_mux[] = {
+ SSI_SDATA0_MARK,
+};
+static const unsigned int ssi01239_ctrl_pins[] = {
+ /* SCK, WS */
+ RCAR_GP_PIN(6, 0), RCAR_GP_PIN(6, 1),
+};
+static const unsigned int ssi01239_ctrl_mux[] = {
+ SSI_SCK01239_MARK, SSI_WS01239_MARK,
+};
+static const unsigned int ssi1_data_a_pins[] = {
+ /* SDATA */
+ RCAR_GP_PIN(6, 3),
+};
+static const unsigned int ssi1_data_a_mux[] = {
+ SSI_SDATA1_A_MARK,
+};
+static const unsigned int ssi1_data_b_pins[] = {
+ /* SDATA */
+ RCAR_GP_PIN(5, 12),
+};
+static const unsigned int ssi1_data_b_mux[] = {
+ SSI_SDATA1_B_MARK,
+};
+static const unsigned int ssi1_ctrl_a_pins[] = {
+ /* SCK, WS */
+ RCAR_GP_PIN(6, 26), RCAR_GP_PIN(6, 27),
+};
+static const unsigned int ssi1_ctrl_a_mux[] = {
+ SSI_SCK1_A_MARK, SSI_WS1_A_MARK,
+};
+static const unsigned int ssi1_ctrl_b_pins[] = {
+ /* SCK, WS */
+ RCAR_GP_PIN(6, 4), RCAR_GP_PIN(6, 21),
+};
+static const unsigned int ssi1_ctrl_b_mux[] = {
+ SSI_SCK1_B_MARK, SSI_WS1_B_MARK,
+};
+static const unsigned int ssi2_data_a_pins[] = {
+ /* SDATA */
+ RCAR_GP_PIN(6, 4),
+};
+static const unsigned int ssi2_data_a_mux[] = {
+ SSI_SDATA2_A_MARK,
+};
+static const unsigned int ssi2_data_b_pins[] = {
+ /* SDATA */
+ RCAR_GP_PIN(5, 13),
+};
+static const unsigned int ssi2_data_b_mux[] = {
+ SSI_SDATA2_B_MARK,
+};
+static const unsigned int ssi2_ctrl_a_pins[] = {
+ /* SCK, WS */
+ RCAR_GP_PIN(5, 19), RCAR_GP_PIN(5, 21),
+};
+static const unsigned int ssi2_ctrl_a_mux[] = {
+ SSI_SCK2_A_MARK, SSI_WS2_A_MARK,
+};
+static const unsigned int ssi2_ctrl_b_pins[] = {
+ /* SCK, WS */
+ RCAR_GP_PIN(6, 28), RCAR_GP_PIN(6, 29),
+};
+static const unsigned int ssi2_ctrl_b_mux[] = {
+ SSI_SCK2_B_MARK, SSI_WS2_B_MARK,
+};
+static const unsigned int ssi3_data_pins[] = {
+ /* SDATA */
+ RCAR_GP_PIN(6, 7),
+};
+static const unsigned int ssi3_data_mux[] = {
+ SSI_SDATA3_MARK,
+};
+static const unsigned int ssi349_ctrl_pins[] = {
+ /* SCK, WS */
+ RCAR_GP_PIN(6, 5), RCAR_GP_PIN(6, 6),
+};
+static const unsigned int ssi349_ctrl_mux[] = {
+ SSI_SCK349_MARK, SSI_WS349_MARK,
+};
+static const unsigned int ssi4_data_pins[] = {
+ /* SDATA */
+ RCAR_GP_PIN(6, 10),
+};
+static const unsigned int ssi4_data_mux[] = {
+ SSI_SDATA4_MARK,
+};
+static const unsigned int ssi4_ctrl_pins[] = {
+ /* SCK, WS */
+ RCAR_GP_PIN(6, 8), RCAR_GP_PIN(6, 9),
+};
+static const unsigned int ssi4_ctrl_mux[] = {
+ SSI_SCK4_MARK, SSI_WS4_MARK,
+};
+static const unsigned int ssi5_data_pins[] = {
+ /* SDATA */
+ RCAR_GP_PIN(6, 13),
+};
+static const unsigned int ssi5_data_mux[] = {
+ SSI_SDATA5_MARK,
+};
+static const unsigned int ssi5_ctrl_pins[] = {
+ /* SCK, WS */
+ RCAR_GP_PIN(6, 11), RCAR_GP_PIN(6, 12),
+};
+static const unsigned int ssi5_ctrl_mux[] = {
+ SSI_SCK5_MARK, SSI_WS5_MARK,
+};
+static const unsigned int ssi6_data_pins[] = {
+ /* SDATA */
+ RCAR_GP_PIN(6, 16),
+};
+static const unsigned int ssi6_data_mux[] = {
+ SSI_SDATA6_MARK,
+};
+static const unsigned int ssi6_ctrl_pins[] = {
+ /* SCK, WS */
+ RCAR_GP_PIN(6, 14), RCAR_GP_PIN(6, 15),
+};
+static const unsigned int ssi6_ctrl_mux[] = {
+ SSI_SCK6_MARK, SSI_WS6_MARK,
+};
+static const unsigned int ssi7_data_pins[] = {
+ /* SDATA */
+ RCAR_GP_PIN(6, 19),
+};
+static const unsigned int ssi7_data_mux[] = {
+ SSI_SDATA7_MARK,
+};
+static const unsigned int ssi78_ctrl_pins[] = {
+ /* SCK, WS */
+ RCAR_GP_PIN(6, 17), RCAR_GP_PIN(6, 18),
+};
+static const unsigned int ssi78_ctrl_mux[] = {
+ SSI_SCK78_MARK, SSI_WS78_MARK,
+};
+static const unsigned int ssi8_data_pins[] = {
+ /* SDATA */
+ RCAR_GP_PIN(6, 20),
+};
+static const unsigned int ssi8_data_mux[] = {
+ SSI_SDATA8_MARK,
+};
+static const unsigned int ssi9_data_a_pins[] = {
+ /* SDATA */
+ RCAR_GP_PIN(6, 21),
+};
+static const unsigned int ssi9_data_a_mux[] = {
+ SSI_SDATA9_A_MARK,
+};
+static const unsigned int ssi9_data_b_pins[] = {
+ /* SDATA */
+ RCAR_GP_PIN(5, 14),
+};
+static const unsigned int ssi9_data_b_mux[] = {
+ SSI_SDATA9_B_MARK,
+};
+static const unsigned int ssi9_ctrl_a_pins[] = {
+ /* SCK, WS */
+ RCAR_GP_PIN(5, 15), RCAR_GP_PIN(5, 16),
+};
+static const unsigned int ssi9_ctrl_a_mux[] = {
+ SSI_SCK9_A_MARK, SSI_WS9_A_MARK,
+};
+static const unsigned int ssi9_ctrl_b_pins[] = {
+ /* SCK, WS */
+ RCAR_GP_PIN(6, 30), RCAR_GP_PIN(6, 31),
+};
+static const unsigned int ssi9_ctrl_b_mux[] = {
+ SSI_SCK9_B_MARK, SSI_WS9_B_MARK,
+};
+
+
/* - USB0 ------------------------------------------------------------------- */
static const unsigned int usb0_pins[] = {
/* PWEN, OVC */
@@ -3407,6 +3726,23 @@ static const unsigned int usb30_mux[] = {
};
static const struct sh_pfc_pin_group pinmux_groups[] = {
+ SH_PFC_PIN_GROUP(audio_clk_a_a),
+ SH_PFC_PIN_GROUP(audio_clk_a_b),
+ SH_PFC_PIN_GROUP(audio_clk_a_c),
+ SH_PFC_PIN_GROUP(audio_clk_b_a),
+ SH_PFC_PIN_GROUP(audio_clk_b_b),
+ SH_PFC_PIN_GROUP(audio_clk_c_a),
+ SH_PFC_PIN_GROUP(audio_clk_c_b),
+ SH_PFC_PIN_GROUP(audio_clkout_a),
+ SH_PFC_PIN_GROUP(audio_clkout_b),
+ SH_PFC_PIN_GROUP(audio_clkout_c),
+ SH_PFC_PIN_GROUP(audio_clkout_d),
+ SH_PFC_PIN_GROUP(audio_clkout1_a),
+ SH_PFC_PIN_GROUP(audio_clkout1_b),
+ SH_PFC_PIN_GROUP(audio_clkout2_a),
+ SH_PFC_PIN_GROUP(audio_clkout2_b),
+ SH_PFC_PIN_GROUP(audio_clkout3_a),
+ SH_PFC_PIN_GROUP(audio_clkout3_b),
SH_PFC_PIN_GROUP(avb_link),
SH_PFC_PIN_GROUP(avb_magic),
SH_PFC_PIN_GROUP(avb_phy_int),
@@ -3579,6 +3915,8 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(pwm5_b),
SH_PFC_PIN_GROUP(pwm6_a),
SH_PFC_PIN_GROUP(pwm6_b),
+ SH_PFC_PIN_GROUP(sata0_devslp_a),
+ SH_PFC_PIN_GROUP(sata0_devslp_b),
SH_PFC_PIN_GROUP(scif0_data),
SH_PFC_PIN_GROUP(scif0_clk),
SH_PFC_PIN_GROUP(scif0_ctrl),
@@ -3634,11 +3972,56 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(sdhi3_cd),
SH_PFC_PIN_GROUP(sdhi3_wp),
SH_PFC_PIN_GROUP(sdhi3_ds),
+ SH_PFC_PIN_GROUP(ssi0_data),
+ SH_PFC_PIN_GROUP(ssi01239_ctrl),
+ SH_PFC_PIN_GROUP(ssi1_data_a),
+ SH_PFC_PIN_GROUP(ssi1_data_b),
+ SH_PFC_PIN_GROUP(ssi1_ctrl_a),
+ SH_PFC_PIN_GROUP(ssi1_ctrl_b),
+ SH_PFC_PIN_GROUP(ssi2_data_a),
+ SH_PFC_PIN_GROUP(ssi2_data_b),
+ SH_PFC_PIN_GROUP(ssi2_ctrl_a),
+ SH_PFC_PIN_GROUP(ssi2_ctrl_b),
+ SH_PFC_PIN_GROUP(ssi3_data),
+ SH_PFC_PIN_GROUP(ssi349_ctrl),
+ SH_PFC_PIN_GROUP(ssi4_data),
+ SH_PFC_PIN_GROUP(ssi4_ctrl),
+ SH_PFC_PIN_GROUP(ssi5_data),
+ SH_PFC_PIN_GROUP(ssi5_ctrl),
+ SH_PFC_PIN_GROUP(ssi6_data),
+ SH_PFC_PIN_GROUP(ssi6_ctrl),
+ SH_PFC_PIN_GROUP(ssi7_data),
+ SH_PFC_PIN_GROUP(ssi78_ctrl),
+ SH_PFC_PIN_GROUP(ssi8_data),
+ SH_PFC_PIN_GROUP(ssi9_data_a),
+ SH_PFC_PIN_GROUP(ssi9_data_b),
+ SH_PFC_PIN_GROUP(ssi9_ctrl_a),
+ SH_PFC_PIN_GROUP(ssi9_ctrl_b),
SH_PFC_PIN_GROUP(usb0),
SH_PFC_PIN_GROUP(usb1),
SH_PFC_PIN_GROUP(usb30),
};
+static const char * const audio_clk_groups[] = {
+ "audio_clk_a_a",
+ "audio_clk_a_b",
+ "audio_clk_a_c",
+ "audio_clk_b_a",
+ "audio_clk_b_b",
+ "audio_clk_c_a",
+ "audio_clk_c_b",
+ "audio_clkout_a",
+ "audio_clkout_b",
+ "audio_clkout_c",
+ "audio_clkout_d",
+ "audio_clkout1_a",
+ "audio_clkout1_b",
+ "audio_clkout2_a",
+ "audio_clkout2_b",
+ "audio_clkout3_a",
+ "audio_clkout3_b",
+};
+
static const char * const avb_groups[] = {
"avb_link",
"avb_magic",
@@ -3877,6 +4260,11 @@ static const char * const pwm6_groups[] = {
"pwm6_b",
};
+static const char * const sata0_groups[] = {
+ "sata0_devslp_a",
+ "sata0_devslp_b",
+};
+
static const char * const scif0_groups[] = {
"scif0_data",
"scif0_clk",
@@ -3964,6 +4352,34 @@ static const char * const sdhi3_groups[] = {
"sdhi3_ds",
};
+static const char * const ssi_groups[] = {
+ "ssi0_data",
+ "ssi01239_ctrl",
+ "ssi1_data_a",
+ "ssi1_data_b",
+ "ssi1_ctrl_a",
+ "ssi1_ctrl_b",
+ "ssi2_data_a",
+ "ssi2_data_b",
+ "ssi2_ctrl_a",
+ "ssi2_ctrl_b",
+ "ssi3_data",
+ "ssi349_ctrl",
+ "ssi4_data",
+ "ssi4_ctrl",
+ "ssi5_data",
+ "ssi5_ctrl",
+ "ssi6_data",
+ "ssi6_ctrl",
+ "ssi7_data",
+ "ssi78_ctrl",
+ "ssi8_data",
+ "ssi9_data_a",
+ "ssi9_data_b",
+ "ssi9_ctrl_a",
+ "ssi9_ctrl_b",
+};
+
static const char * const usb0_groups[] = {
"usb0",
};
@@ -3977,6 +4393,7 @@ static const char * const usb30_groups[] = {
};
static const struct sh_pfc_function pinmux_functions[] = {
+ SH_PFC_FUNCTION(audio_clk),
SH_PFC_FUNCTION(avb),
SH_PFC_FUNCTION(du),
SH_PFC_FUNCTION(hscif0),
@@ -3999,6 +4416,7 @@ static const struct sh_pfc_function pinmux_functions[] = {
SH_PFC_FUNCTION(pwm4),
SH_PFC_FUNCTION(pwm5),
SH_PFC_FUNCTION(pwm6),
+ SH_PFC_FUNCTION(sata0),
SH_PFC_FUNCTION(scif0),
SH_PFC_FUNCTION(scif1),
SH_PFC_FUNCTION(scif2),
@@ -4010,6 +4428,7 @@ static const struct sh_pfc_function pinmux_functions[] = {
SH_PFC_FUNCTION(sdhi1),
SH_PFC_FUNCTION(sdhi2),
SH_PFC_FUNCTION(sdhi3),
+ SH_PFC_FUNCTION(ssi),
SH_PFC_FUNCTION(usb0),
SH_PFC_FUNCTION(usb1),
SH_PFC_FUNCTION(usb30),
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a77970.c b/drivers/pinctrl/sh-pfc/pfc-r8a77970.c
index eeb58b3bbc9a..44f9eefc86b5 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a77970.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a77970.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* R8A77970 processor support - PFC hardware block.
*
@@ -9,10 +10,6 @@
* R-Car Gen3 processor support - PFC hardware block.
*
* Copyright (C) 2015 Renesas Electronics Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
*/
#include <linux/io.h>
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a77990.c b/drivers/pinctrl/sh-pfc/pfc-r8a77990.c
index b81c807ac54d..1fdafa48479c 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a77990.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a77990.c
@@ -1371,6 +1371,94 @@ static const unsigned int avb_avtp_capture_a_mux[] = {
AVB_AVTP_CAPTURE_A_MARK,
};
+/* - DU --------------------------------------------------------------------- */
+static const unsigned int du_rgb666_pins[] = {
+ /* R[7:2], G[7:2], B[7:2] */
+ RCAR_GP_PIN(0, 8), RCAR_GP_PIN(0, 6), RCAR_GP_PIN(0, 5),
+ RCAR_GP_PIN(0, 3), RCAR_GP_PIN(0, 2), RCAR_GP_PIN(0, 0),
+ RCAR_GP_PIN(1, 9), RCAR_GP_PIN(1, 12), RCAR_GP_PIN(1, 10),
+ RCAR_GP_PIN(1, 4), RCAR_GP_PIN(0, 15), RCAR_GP_PIN(0, 11),
+ RCAR_GP_PIN(0, 1), RCAR_GP_PIN(1, 17), RCAR_GP_PIN(1, 16),
+ RCAR_GP_PIN(1, 15), RCAR_GP_PIN(1, 14), RCAR_GP_PIN(1, 13),
+};
+static const unsigned int du_rgb666_mux[] = {
+ DU_DR7_MARK, DU_DR6_MARK, DU_DR5_MARK, DU_DR4_MARK,
+ DU_DR3_MARK, DU_DR2_MARK,
+ DU_DG7_MARK, DU_DG6_MARK, DU_DG5_MARK, DU_DG4_MARK,
+ DU_DG3_MARK, DU_DG2_MARK,
+ DU_DB7_MARK, DU_DB6_MARK, DU_DB5_MARK, DU_DB4_MARK,
+ DU_DB3_MARK, DU_DB2_MARK,
+};
+static const unsigned int du_rgb888_pins[] = {
+ /* R[7:0], G[7:0], B[7:0] */
+ RCAR_GP_PIN(0, 8), RCAR_GP_PIN(0, 6), RCAR_GP_PIN(0, 5),
+ RCAR_GP_PIN(0, 3), RCAR_GP_PIN(0, 2), RCAR_GP_PIN(0, 0),
+ RCAR_GP_PIN(1, 22), RCAR_GP_PIN(1, 21),
+ RCAR_GP_PIN(1, 9), RCAR_GP_PIN(1, 12), RCAR_GP_PIN(1, 10),
+ RCAR_GP_PIN(1, 4), RCAR_GP_PIN(0, 15), RCAR_GP_PIN(0, 11),
+ RCAR_GP_PIN(0, 10), RCAR_GP_PIN(0, 9),
+ RCAR_GP_PIN(0, 1), RCAR_GP_PIN(1, 17), RCAR_GP_PIN(1, 16),
+ RCAR_GP_PIN(1, 15), RCAR_GP_PIN(1, 14), RCAR_GP_PIN(1, 13),
+ RCAR_GP_PIN(1, 19), RCAR_GP_PIN(1, 18),
+};
+static const unsigned int du_rgb888_mux[] = {
+ DU_DR7_MARK, DU_DR6_MARK, DU_DR5_MARK, DU_DR4_MARK,
+ DU_DR3_MARK, DU_DR2_MARK, DU_DR1_MARK, DU_DR0_MARK,
+ DU_DG7_MARK, DU_DG6_MARK, DU_DG5_MARK, DU_DG4_MARK,
+ DU_DG3_MARK, DU_DG2_MARK, DU_DG1_MARK, DU_DG0_MARK,
+ DU_DB7_MARK, DU_DB6_MARK, DU_DB5_MARK, DU_DB4_MARK,
+ DU_DB3_MARK, DU_DB2_MARK, DU_DB1_MARK, DU_DB0_MARK,
+};
+static const unsigned int du_clk_in_0_pins[] = {
+ /* CLKIN0 */
+ RCAR_GP_PIN(0, 16),
+};
+static const unsigned int du_clk_in_0_mux[] = {
+ DU_DOTCLKIN0_MARK
+};
+static const unsigned int du_clk_in_1_pins[] = {
+ /* CLKIN1 */
+ RCAR_GP_PIN(1, 1),
+};
+static const unsigned int du_clk_in_1_mux[] = {
+ DU_DOTCLKIN1_MARK
+};
+static const unsigned int du_clk_out_0_pins[] = {
+ /* CLKOUT */
+ RCAR_GP_PIN(1, 3),
+};
+static const unsigned int du_clk_out_0_mux[] = {
+ DU_DOTCLKOUT0_MARK
+};
+static const unsigned int du_sync_pins[] = {
+ /* VSYNC, HSYNC */
+ RCAR_GP_PIN(1, 11), RCAR_GP_PIN(1, 8),
+};
+static const unsigned int du_sync_mux[] = {
+ DU_VSYNC_MARK, DU_HSYNC_MARK
+};
+static const unsigned int du_disp_cde_pins[] = {
+ /* DISP_CDE */
+ RCAR_GP_PIN(1, 1),
+};
+static const unsigned int du_disp_cde_mux[] = {
+ DU_DISP_CDE_MARK,
+};
+static const unsigned int du_cde_pins[] = {
+ /* CDE */
+ RCAR_GP_PIN(1, 0),
+};
+static const unsigned int du_cde_mux[] = {
+ DU_CDE_MARK,
+};
+static const unsigned int du_disp_pins[] = {
+ /* DISP */
+ RCAR_GP_PIN(1, 2),
+};
+static const unsigned int du_disp_mux[] = {
+ DU_DISP_MARK,
+};
+
/* - I2C -------------------------------------------------------------------- */
static const unsigned int i2c1_a_pins[] = {
/* SCL, SDA */
@@ -1507,6 +1595,520 @@ static const unsigned int i2c7_b_mux[] = {
SCL7_B_MARK, SDA7_B_MARK,
};
+/* - INTC-EX ---------------------------------------------------------------- */
+static const unsigned int intc_ex_irq0_pins[] = {
+ /* IRQ0 */
+ RCAR_GP_PIN(1, 0),
+};
+static const unsigned int intc_ex_irq0_mux[] = {
+ IRQ0_MARK,
+};
+static const unsigned int intc_ex_irq1_pins[] = {
+ /* IRQ1 */
+ RCAR_GP_PIN(1, 1),
+};
+static const unsigned int intc_ex_irq1_mux[] = {
+ IRQ1_MARK,
+};
+static const unsigned int intc_ex_irq2_pins[] = {
+ /* IRQ2 */
+ RCAR_GP_PIN(1, 2),
+};
+static const unsigned int intc_ex_irq2_mux[] = {
+ IRQ2_MARK,
+};
+static const unsigned int intc_ex_irq3_pins[] = {
+ /* IRQ3 */
+ RCAR_GP_PIN(1, 9),
+};
+static const unsigned int intc_ex_irq3_mux[] = {
+ IRQ3_MARK,
+};
+static const unsigned int intc_ex_irq4_pins[] = {
+ /* IRQ4 */
+ RCAR_GP_PIN(1, 10),
+};
+static const unsigned int intc_ex_irq4_mux[] = {
+ IRQ4_MARK,
+};
+static const unsigned int intc_ex_irq5_pins[] = {
+ /* IRQ5 */
+ RCAR_GP_PIN(0, 7),
+};
+static const unsigned int intc_ex_irq5_mux[] = {
+ IRQ5_MARK,
+};
+
+/* - MSIOF0 ----------------------------------------------------------------- */
+static const unsigned int msiof0_clk_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(5, 10),
+};
+
+static const unsigned int msiof0_clk_mux[] = {
+ MSIOF0_SCK_MARK,
+};
+
+static const unsigned int msiof0_sync_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(5, 13),
+};
+
+static const unsigned int msiof0_sync_mux[] = {
+ MSIOF0_SYNC_MARK,
+};
+
+static const unsigned int msiof0_ss1_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(5, 14),
+};
+
+static const unsigned int msiof0_ss1_mux[] = {
+ MSIOF0_SS1_MARK,
+};
+
+static const unsigned int msiof0_ss2_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(5, 15),
+};
+
+static const unsigned int msiof0_ss2_mux[] = {
+ MSIOF0_SS2_MARK,
+};
+
+static const unsigned int msiof0_txd_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(5, 12),
+};
+
+static const unsigned int msiof0_txd_mux[] = {
+ MSIOF0_TXD_MARK,
+};
+
+static const unsigned int msiof0_rxd_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(5, 11),
+};
+
+static const unsigned int msiof0_rxd_mux[] = {
+ MSIOF0_RXD_MARK,
+};
+
+/* - MSIOF1 ----------------------------------------------------------------- */
+static const unsigned int msiof1_clk_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(1, 19),
+};
+
+static const unsigned int msiof1_clk_mux[] = {
+ MSIOF1_SCK_MARK,
+};
+
+static const unsigned int msiof1_sync_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(1, 16),
+};
+
+static const unsigned int msiof1_sync_mux[] = {
+ MSIOF1_SYNC_MARK,
+};
+
+static const unsigned int msiof1_ss1_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(1, 14),
+};
+
+static const unsigned int msiof1_ss1_mux[] = {
+ MSIOF1_SS1_MARK,
+};
+
+static const unsigned int msiof1_ss2_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(1, 15),
+};
+
+static const unsigned int msiof1_ss2_mux[] = {
+ MSIOF1_SS2_MARK,
+};
+
+static const unsigned int msiof1_txd_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(1, 18),
+};
+
+static const unsigned int msiof1_txd_mux[] = {
+ MSIOF1_TXD_MARK,
+};
+
+static const unsigned int msiof1_rxd_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(1, 17),
+};
+
+static const unsigned int msiof1_rxd_mux[] = {
+ MSIOF1_RXD_MARK,
+};
+
+/* - MSIOF2 ----------------------------------------------------------------- */
+static const unsigned int msiof2_clk_a_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(0, 8),
+};
+
+static const unsigned int msiof2_clk_a_mux[] = {
+ MSIOF2_SCK_A_MARK,
+};
+
+static const unsigned int msiof2_sync_a_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(0, 9),
+};
+
+static const unsigned int msiof2_sync_a_mux[] = {
+ MSIOF2_SYNC_A_MARK,
+};
+
+static const unsigned int msiof2_ss1_a_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(0, 15),
+};
+
+static const unsigned int msiof2_ss1_a_mux[] = {
+ MSIOF2_SS1_A_MARK,
+};
+
+static const unsigned int msiof2_ss2_a_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(0, 14),
+};
+
+static const unsigned int msiof2_ss2_a_mux[] = {
+ MSIOF2_SS2_A_MARK,
+};
+
+static const unsigned int msiof2_txd_a_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(0, 11),
+};
+
+static const unsigned int msiof2_txd_a_mux[] = {
+ MSIOF2_TXD_A_MARK,
+};
+
+static const unsigned int msiof2_rxd_a_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(0, 10),
+};
+
+static const unsigned int msiof2_rxd_a_mux[] = {
+ MSIOF2_RXD_A_MARK,
+};
+
+static const unsigned int msiof2_clk_b_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(1, 13),
+};
+
+static const unsigned int msiof2_clk_b_mux[] = {
+ MSIOF2_SCK_B_MARK,
+};
+
+static const unsigned int msiof2_sync_b_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(1, 10),
+};
+
+static const unsigned int msiof2_sync_b_mux[] = {
+ MSIOF2_SYNC_B_MARK,
+};
+
+static const unsigned int msiof2_ss1_b_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(1, 16),
+};
+
+static const unsigned int msiof2_ss1_b_mux[] = {
+ MSIOF2_SS1_B_MARK,
+};
+
+static const unsigned int msiof2_ss2_b_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(1, 12),
+};
+
+static const unsigned int msiof2_ss2_b_mux[] = {
+ MSIOF2_SS2_B_MARK,
+};
+
+static const unsigned int msiof2_txd_b_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(1, 15),
+};
+
+static const unsigned int msiof2_txd_b_mux[] = {
+ MSIOF2_TXD_B_MARK,
+};
+
+static const unsigned int msiof2_rxd_b_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(1, 14),
+};
+
+static const unsigned int msiof2_rxd_b_mux[] = {
+ MSIOF2_RXD_B_MARK,
+};
+
+/* - MSIOF3 ----------------------------------------------------------------- */
+static const unsigned int msiof3_clk_a_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(0, 0),
+};
+
+static const unsigned int msiof3_clk_a_mux[] = {
+ MSIOF3_SCK_A_MARK,
+};
+
+static const unsigned int msiof3_sync_a_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(0, 1),
+};
+
+static const unsigned int msiof3_sync_a_mux[] = {
+ MSIOF3_SYNC_A_MARK,
+};
+
+static const unsigned int msiof3_ss1_a_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(0, 15),
+};
+
+static const unsigned int msiof3_ss1_a_mux[] = {
+ MSIOF3_SS1_A_MARK,
+};
+
+static const unsigned int msiof3_ss2_a_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(0, 4),
+};
+
+static const unsigned int msiof3_ss2_a_mux[] = {
+ MSIOF3_SS2_A_MARK,
+};
+
+static const unsigned int msiof3_txd_a_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(0, 3),
+};
+
+static const unsigned int msiof3_txd_a_mux[] = {
+ MSIOF3_TXD_A_MARK,
+};
+
+static const unsigned int msiof3_rxd_a_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(0, 2),
+};
+
+static const unsigned int msiof3_rxd_a_mux[] = {
+ MSIOF3_RXD_A_MARK,
+};
+
+static const unsigned int msiof3_clk_b_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(1, 5),
+};
+
+static const unsigned int msiof3_clk_b_mux[] = {
+ MSIOF3_SCK_B_MARK,
+};
+
+static const unsigned int msiof3_sync_b_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(1, 4),
+};
+
+static const unsigned int msiof3_sync_b_mux[] = {
+ MSIOF3_SYNC_B_MARK,
+};
+
+static const unsigned int msiof3_ss1_b_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(1, 0),
+};
+
+static const unsigned int msiof3_ss1_b_mux[] = {
+ MSIOF3_SS1_B_MARK,
+};
+
+static const unsigned int msiof3_txd_b_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(1, 7),
+};
+
+static const unsigned int msiof3_txd_b_mux[] = {
+ MSIOF3_TXD_B_MARK,
+};
+
+static const unsigned int msiof3_rxd_b_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(1, 6),
+};
+
+static const unsigned int msiof3_rxd_b_mux[] = {
+ MSIOF3_RXD_B_MARK,
+};
+
+/* - PWM0 --------------------------------------------------------------------*/
+static const unsigned int pwm0_a_pins[] = {
+ /* PWM */
+ RCAR_GP_PIN(2, 22),
+};
+
+static const unsigned int pwm0_a_mux[] = {
+ PWM0_A_MARK,
+};
+
+static const unsigned int pwm0_b_pins[] = {
+ /* PWM */
+ RCAR_GP_PIN(6, 3),
+};
+
+static const unsigned int pwm0_b_mux[] = {
+ PWM0_B_MARK,
+};
+
+/* - PWM1 --------------------------------------------------------------------*/
+static const unsigned int pwm1_a_pins[] = {
+ /* PWM */
+ RCAR_GP_PIN(2, 23),
+};
+
+static const unsigned int pwm1_a_mux[] = {
+ PWM1_A_MARK,
+};
+
+static const unsigned int pwm1_b_pins[] = {
+ /* PWM */
+ RCAR_GP_PIN(6, 4),
+};
+
+static const unsigned int pwm1_b_mux[] = {
+ PWM1_B_MARK,
+};
+
+/* - PWM2 --------------------------------------------------------------------*/
+static const unsigned int pwm2_a_pins[] = {
+ /* PWM */
+ RCAR_GP_PIN(1, 0),
+};
+
+static const unsigned int pwm2_a_mux[] = {
+ PWM2_A_MARK,
+};
+
+static const unsigned int pwm2_b_pins[] = {
+ /* PWM */
+ RCAR_GP_PIN(1, 4),
+};
+
+static const unsigned int pwm2_b_mux[] = {
+ PWM2_B_MARK,
+};
+
+static const unsigned int pwm2_c_pins[] = {
+ /* PWM */
+ RCAR_GP_PIN(6, 5),
+};
+
+static const unsigned int pwm2_c_mux[] = {
+ PWM2_C_MARK,
+};
+
+/* - PWM3 --------------------------------------------------------------------*/
+static const unsigned int pwm3_a_pins[] = {
+ /* PWM */
+ RCAR_GP_PIN(1, 1),
+};
+
+static const unsigned int pwm3_a_mux[] = {
+ PWM3_A_MARK,
+};
+
+static const unsigned int pwm3_b_pins[] = {
+ /* PWM */
+ RCAR_GP_PIN(1, 5),
+};
+
+static const unsigned int pwm3_b_mux[] = {
+ PWM3_B_MARK,
+};
+
+static const unsigned int pwm3_c_pins[] = {
+ /* PWM */
+ RCAR_GP_PIN(6, 6),
+};
+
+static const unsigned int pwm3_c_mux[] = {
+ PWM3_C_MARK,
+};
+
+/* - PWM4 --------------------------------------------------------------------*/
+static const unsigned int pwm4_a_pins[] = {
+ /* PWM */
+ RCAR_GP_PIN(1, 3),
+};
+
+static const unsigned int pwm4_a_mux[] = {
+ PWM4_A_MARK,
+};
+
+static const unsigned int pwm4_b_pins[] = {
+ /* PWM */
+ RCAR_GP_PIN(6, 7),
+};
+
+static const unsigned int pwm4_b_mux[] = {
+ PWM4_B_MARK,
+};
+
+/* - PWM5 --------------------------------------------------------------------*/
+static const unsigned int pwm5_a_pins[] = {
+ /* PWM */
+ RCAR_GP_PIN(2, 24),
+};
+
+static const unsigned int pwm5_a_mux[] = {
+ PWM5_A_MARK,
+};
+
+static const unsigned int pwm5_b_pins[] = {
+ /* PWM */
+ RCAR_GP_PIN(6, 10),
+};
+
+static const unsigned int pwm5_b_mux[] = {
+ PWM5_B_MARK,
+};
+
+/* - PWM6 --------------------------------------------------------------------*/
+static const unsigned int pwm6_a_pins[] = {
+ /* PWM */
+ RCAR_GP_PIN(2, 25),
+};
+
+static const unsigned int pwm6_a_mux[] = {
+ PWM6_A_MARK,
+};
+
+static const unsigned int pwm6_b_pins[] = {
+ /* PWM */
+ RCAR_GP_PIN(6, 11),
+};
+
+static const unsigned int pwm6_b_mux[] = {
+ PWM6_B_MARK,
+};
+
/* - SCIF0 ------------------------------------------------------------------ */
static const unsigned int scif0_data_a_pins[] = {
/* RX, TX */
@@ -1831,64 +2433,135 @@ static const unsigned int usb30_id_mux[] = {
USB3HS0_ID_MARK,
};
-static const struct sh_pfc_pin_group pinmux_groups[] = {
- SH_PFC_PIN_GROUP(avb_link),
- SH_PFC_PIN_GROUP(avb_magic),
- SH_PFC_PIN_GROUP(avb_phy_int),
- SH_PFC_PIN_GROUP(avb_mii),
- SH_PFC_PIN_GROUP(avb_avtp_pps),
- SH_PFC_PIN_GROUP(avb_avtp_match_a),
- SH_PFC_PIN_GROUP(avb_avtp_capture_a),
- SH_PFC_PIN_GROUP(i2c1_a),
- SH_PFC_PIN_GROUP(i2c1_b),
- SH_PFC_PIN_GROUP(i2c1_c),
- SH_PFC_PIN_GROUP(i2c1_d),
- SH_PFC_PIN_GROUP(i2c2_a),
- SH_PFC_PIN_GROUP(i2c2_b),
- SH_PFC_PIN_GROUP(i2c2_c),
- SH_PFC_PIN_GROUP(i2c2_d),
- SH_PFC_PIN_GROUP(i2c2_e),
- SH_PFC_PIN_GROUP(i2c4),
- SH_PFC_PIN_GROUP(i2c5),
- SH_PFC_PIN_GROUP(i2c6_a),
- SH_PFC_PIN_GROUP(i2c6_b),
- SH_PFC_PIN_GROUP(i2c7_a),
- SH_PFC_PIN_GROUP(i2c7_b),
- SH_PFC_PIN_GROUP(scif0_data_a),
- SH_PFC_PIN_GROUP(scif0_clk_a),
- SH_PFC_PIN_GROUP(scif0_ctrl_a),
- SH_PFC_PIN_GROUP(scif0_data_b),
- SH_PFC_PIN_GROUP(scif0_clk_b),
- SH_PFC_PIN_GROUP(scif1_data),
- SH_PFC_PIN_GROUP(scif1_clk),
- SH_PFC_PIN_GROUP(scif1_ctrl),
- SH_PFC_PIN_GROUP(scif2_data_a),
- SH_PFC_PIN_GROUP(scif2_clk_a),
- SH_PFC_PIN_GROUP(scif2_data_b),
- SH_PFC_PIN_GROUP(scif3_data_a),
- SH_PFC_PIN_GROUP(scif3_clk_a),
- SH_PFC_PIN_GROUP(scif3_ctrl_a),
- SH_PFC_PIN_GROUP(scif3_data_b),
- SH_PFC_PIN_GROUP(scif3_data_c),
- SH_PFC_PIN_GROUP(scif3_clk_c),
- SH_PFC_PIN_GROUP(scif4_data_a),
- SH_PFC_PIN_GROUP(scif4_clk_a),
- SH_PFC_PIN_GROUP(scif4_ctrl_a),
- SH_PFC_PIN_GROUP(scif4_data_b),
- SH_PFC_PIN_GROUP(scif4_clk_b),
- SH_PFC_PIN_GROUP(scif4_data_c),
- SH_PFC_PIN_GROUP(scif4_ctrl_c),
- SH_PFC_PIN_GROUP(scif5_data_a),
- SH_PFC_PIN_GROUP(scif5_clk_a),
- SH_PFC_PIN_GROUP(scif5_data_b),
- SH_PFC_PIN_GROUP(scif5_data_c),
- SH_PFC_PIN_GROUP(scif_clk_a),
- SH_PFC_PIN_GROUP(scif_clk_b),
- SH_PFC_PIN_GROUP(usb0_a),
- SH_PFC_PIN_GROUP(usb0_b),
- SH_PFC_PIN_GROUP(usb0_id),
- SH_PFC_PIN_GROUP(usb30),
- SH_PFC_PIN_GROUP(usb30_id),
+static const struct {
+ struct sh_pfc_pin_group common[123];
+ struct sh_pfc_pin_group automotive[0];
+} pinmux_groups = {
+ .common = {
+ SH_PFC_PIN_GROUP(avb_link),
+ SH_PFC_PIN_GROUP(avb_magic),
+ SH_PFC_PIN_GROUP(avb_phy_int),
+ SH_PFC_PIN_GROUP(avb_mii),
+ SH_PFC_PIN_GROUP(avb_avtp_pps),
+ SH_PFC_PIN_GROUP(avb_avtp_match_a),
+ SH_PFC_PIN_GROUP(avb_avtp_capture_a),
+ SH_PFC_PIN_GROUP(du_rgb666),
+ SH_PFC_PIN_GROUP(du_rgb888),
+ SH_PFC_PIN_GROUP(du_clk_in_0),
+ SH_PFC_PIN_GROUP(du_clk_in_1),
+ SH_PFC_PIN_GROUP(du_clk_out_0),
+ SH_PFC_PIN_GROUP(du_sync),
+ SH_PFC_PIN_GROUP(du_disp_cde),
+ SH_PFC_PIN_GROUP(du_cde),
+ SH_PFC_PIN_GROUP(du_disp),
+ SH_PFC_PIN_GROUP(i2c1_a),
+ SH_PFC_PIN_GROUP(i2c1_b),
+ SH_PFC_PIN_GROUP(i2c1_c),
+ SH_PFC_PIN_GROUP(i2c1_d),
+ SH_PFC_PIN_GROUP(i2c2_a),
+ SH_PFC_PIN_GROUP(i2c2_b),
+ SH_PFC_PIN_GROUP(i2c2_c),
+ SH_PFC_PIN_GROUP(i2c2_d),
+ SH_PFC_PIN_GROUP(i2c2_e),
+ SH_PFC_PIN_GROUP(i2c4),
+ SH_PFC_PIN_GROUP(i2c5),
+ SH_PFC_PIN_GROUP(i2c6_a),
+ SH_PFC_PIN_GROUP(i2c6_b),
+ SH_PFC_PIN_GROUP(i2c7_a),
+ SH_PFC_PIN_GROUP(i2c7_b),
+ SH_PFC_PIN_GROUP(intc_ex_irq0),
+ SH_PFC_PIN_GROUP(intc_ex_irq1),
+ SH_PFC_PIN_GROUP(intc_ex_irq2),
+ SH_PFC_PIN_GROUP(intc_ex_irq3),
+ SH_PFC_PIN_GROUP(intc_ex_irq4),
+ SH_PFC_PIN_GROUP(intc_ex_irq5),
+ SH_PFC_PIN_GROUP(msiof0_clk),
+ SH_PFC_PIN_GROUP(msiof0_sync),
+ SH_PFC_PIN_GROUP(msiof0_ss1),
+ SH_PFC_PIN_GROUP(msiof0_ss2),
+ SH_PFC_PIN_GROUP(msiof0_txd),
+ SH_PFC_PIN_GROUP(msiof0_rxd),
+ SH_PFC_PIN_GROUP(msiof1_clk),
+ SH_PFC_PIN_GROUP(msiof1_sync),
+ SH_PFC_PIN_GROUP(msiof1_ss1),
+ SH_PFC_PIN_GROUP(msiof1_ss2),
+ SH_PFC_PIN_GROUP(msiof1_txd),
+ SH_PFC_PIN_GROUP(msiof1_rxd),
+ SH_PFC_PIN_GROUP(msiof2_clk_a),
+ SH_PFC_PIN_GROUP(msiof2_sync_a),
+ SH_PFC_PIN_GROUP(msiof2_ss1_a),
+ SH_PFC_PIN_GROUP(msiof2_ss2_a),
+ SH_PFC_PIN_GROUP(msiof2_txd_a),
+ SH_PFC_PIN_GROUP(msiof2_rxd_a),
+ SH_PFC_PIN_GROUP(msiof2_clk_b),
+ SH_PFC_PIN_GROUP(msiof2_sync_b),
+ SH_PFC_PIN_GROUP(msiof2_ss1_b),
+ SH_PFC_PIN_GROUP(msiof2_ss2_b),
+ SH_PFC_PIN_GROUP(msiof2_txd_b),
+ SH_PFC_PIN_GROUP(msiof2_rxd_b),
+ SH_PFC_PIN_GROUP(msiof3_clk_a),
+ SH_PFC_PIN_GROUP(msiof3_sync_a),
+ SH_PFC_PIN_GROUP(msiof3_ss1_a),
+ SH_PFC_PIN_GROUP(msiof3_ss2_a),
+ SH_PFC_PIN_GROUP(msiof3_txd_a),
+ SH_PFC_PIN_GROUP(msiof3_rxd_a),
+ SH_PFC_PIN_GROUP(msiof3_clk_b),
+ SH_PFC_PIN_GROUP(msiof3_sync_b),
+ SH_PFC_PIN_GROUP(msiof3_ss1_b),
+ SH_PFC_PIN_GROUP(msiof3_txd_b),
+ SH_PFC_PIN_GROUP(msiof3_rxd_b),
+ SH_PFC_PIN_GROUP(pwm0_a),
+ SH_PFC_PIN_GROUP(pwm0_b),
+ SH_PFC_PIN_GROUP(pwm1_a),
+ SH_PFC_PIN_GROUP(pwm1_b),
+ SH_PFC_PIN_GROUP(pwm2_a),
+ SH_PFC_PIN_GROUP(pwm2_b),
+ SH_PFC_PIN_GROUP(pwm2_c),
+ SH_PFC_PIN_GROUP(pwm3_a),
+ SH_PFC_PIN_GROUP(pwm3_b),
+ SH_PFC_PIN_GROUP(pwm3_c),
+ SH_PFC_PIN_GROUP(pwm4_a),
+ SH_PFC_PIN_GROUP(pwm4_b),
+ SH_PFC_PIN_GROUP(pwm5_a),
+ SH_PFC_PIN_GROUP(pwm5_b),
+ SH_PFC_PIN_GROUP(pwm6_a),
+ SH_PFC_PIN_GROUP(pwm6_b),
+ SH_PFC_PIN_GROUP(scif0_data_a),
+ SH_PFC_PIN_GROUP(scif0_clk_a),
+ SH_PFC_PIN_GROUP(scif0_ctrl_a),
+ SH_PFC_PIN_GROUP(scif0_data_b),
+ SH_PFC_PIN_GROUP(scif0_clk_b),
+ SH_PFC_PIN_GROUP(scif1_data),
+ SH_PFC_PIN_GROUP(scif1_clk),
+ SH_PFC_PIN_GROUP(scif1_ctrl),
+ SH_PFC_PIN_GROUP(scif2_data_a),
+ SH_PFC_PIN_GROUP(scif2_clk_a),
+ SH_PFC_PIN_GROUP(scif2_data_b),
+ SH_PFC_PIN_GROUP(scif3_data_a),
+ SH_PFC_PIN_GROUP(scif3_clk_a),
+ SH_PFC_PIN_GROUP(scif3_ctrl_a),
+ SH_PFC_PIN_GROUP(scif3_data_b),
+ SH_PFC_PIN_GROUP(scif3_data_c),
+ SH_PFC_PIN_GROUP(scif3_clk_c),
+ SH_PFC_PIN_GROUP(scif4_data_a),
+ SH_PFC_PIN_GROUP(scif4_clk_a),
+ SH_PFC_PIN_GROUP(scif4_ctrl_a),
+ SH_PFC_PIN_GROUP(scif4_data_b),
+ SH_PFC_PIN_GROUP(scif4_clk_b),
+ SH_PFC_PIN_GROUP(scif4_data_c),
+ SH_PFC_PIN_GROUP(scif4_ctrl_c),
+ SH_PFC_PIN_GROUP(scif5_data_a),
+ SH_PFC_PIN_GROUP(scif5_clk_a),
+ SH_PFC_PIN_GROUP(scif5_data_b),
+ SH_PFC_PIN_GROUP(scif5_data_c),
+ SH_PFC_PIN_GROUP(scif_clk_a),
+ SH_PFC_PIN_GROUP(scif_clk_b),
+ SH_PFC_PIN_GROUP(usb0_a),
+ SH_PFC_PIN_GROUP(usb0_b),
+ SH_PFC_PIN_GROUP(usb0_id),
+ SH_PFC_PIN_GROUP(usb30),
+ SH_PFC_PIN_GROUP(usb30_id),
+ }
};
static const char * const avb_groups[] = {
@@ -1901,6 +2574,18 @@ static const char * const avb_groups[] = {
"avb_avtp_capture_a",
};
+static const char * const du_groups[] = {
+ "du_rgb666",
+ "du_rgb888",
+ "du_clk_in_0",
+ "du_clk_in_1",
+ "du_clk_out_0",
+ "du_sync",
+ "du_disp_cde",
+ "du_cde",
+ "du_disp",
+};
+
static const char * const i2c1_groups[] = {
"i2c1_a",
"i2c1_b",
@@ -1934,6 +2619,99 @@ static const char * const i2c7_groups[] = {
"i2c7_b",
};
+static const char * const intc_ex_groups[] = {
+ "intc_ex_irq0",
+ "intc_ex_irq1",
+ "intc_ex_irq2",
+ "intc_ex_irq3",
+ "intc_ex_irq4",
+ "intc_ex_irq5",
+};
+
+static const char * const msiof0_groups[] = {
+ "msiof0_clk",
+ "msiof0_sync",
+ "msiof0_ss1",
+ "msiof0_ss2",
+ "msiof0_txd",
+ "msiof0_rxd",
+};
+
+static const char * const msiof1_groups[] = {
+ "msiof1_clk",
+ "msiof1_sync",
+ "msiof1_ss1",
+ "msiof1_ss2",
+ "msiof1_txd",
+ "msiof1_rxd",
+};
+
+static const char * const msiof2_groups[] = {
+ "msiof2_clk_a",
+ "msiof2_sync_a",
+ "msiof2_ss1_a",
+ "msiof2_ss2_a",
+ "msiof2_txd_a",
+ "msiof2_rxd_a",
+ "msiof2_clk_b",
+ "msiof2_sync_b",
+ "msiof2_ss1_b",
+ "msiof2_ss2_b",
+ "msiof2_txd_b",
+ "msiof2_rxd_b",
+};
+
+static const char * const msiof3_groups[] = {
+ "msiof3_clk_a",
+ "msiof3_sync_a",
+ "msiof3_ss1_a",
+ "msiof3_ss2_a",
+ "msiof3_txd_a",
+ "msiof3_rxd_a",
+ "msiof3_clk_b",
+ "msiof3_sync_b",
+ "msiof3_ss1_b",
+ "msiof3_txd_b",
+ "msiof3_rxd_b",
+};
+
+static const char * const pwm0_groups[] = {
+ "pwm0_a",
+ "pwm0_b",
+};
+
+static const char * const pwm1_groups[] = {
+ "pwm1_a",
+ "pwm1_b",
+};
+
+static const char * const pwm2_groups[] = {
+ "pwm2_a",
+ "pwm2_b",
+ "pwm2_c",
+};
+
+static const char * const pwm3_groups[] = {
+ "pwm3_a",
+ "pwm3_b",
+ "pwm3_c",
+};
+
+static const char * const pwm4_groups[] = {
+ "pwm4_a",
+ "pwm4_b",
+};
+
+static const char * const pwm5_groups[] = {
+ "pwm5_a",
+ "pwm5_b",
+};
+
+static const char * const pwm6_groups[] = {
+ "pwm6_a",
+ "pwm6_b",
+};
+
static const char * const scif0_groups[] = {
"scif0_data_a",
"scif0_clk_a",
@@ -1996,23 +2774,41 @@ static const char * const usb30_groups[] = {
"usb30_id",
};
-static const struct sh_pfc_function pinmux_functions[] = {
- SH_PFC_FUNCTION(avb),
- SH_PFC_FUNCTION(i2c1),
- SH_PFC_FUNCTION(i2c2),
- SH_PFC_FUNCTION(i2c4),
- SH_PFC_FUNCTION(i2c5),
- SH_PFC_FUNCTION(i2c6),
- SH_PFC_FUNCTION(i2c7),
- SH_PFC_FUNCTION(scif0),
- SH_PFC_FUNCTION(scif1),
- SH_PFC_FUNCTION(scif2),
- SH_PFC_FUNCTION(scif3),
- SH_PFC_FUNCTION(scif4),
- SH_PFC_FUNCTION(scif5),
- SH_PFC_FUNCTION(scif_clk),
- SH_PFC_FUNCTION(usb0),
- SH_PFC_FUNCTION(usb30),
+static const struct {
+ struct sh_pfc_function common[29];
+ struct sh_pfc_function automotive[0];
+} pinmux_functions = {
+ .common = {
+ SH_PFC_FUNCTION(avb),
+ SH_PFC_FUNCTION(du),
+ SH_PFC_FUNCTION(i2c1),
+ SH_PFC_FUNCTION(i2c2),
+ SH_PFC_FUNCTION(i2c4),
+ SH_PFC_FUNCTION(i2c5),
+ SH_PFC_FUNCTION(i2c6),
+ SH_PFC_FUNCTION(i2c7),
+ SH_PFC_FUNCTION(intc_ex),
+ SH_PFC_FUNCTION(msiof0),
+ SH_PFC_FUNCTION(msiof1),
+ SH_PFC_FUNCTION(msiof2),
+ SH_PFC_FUNCTION(msiof3),
+ SH_PFC_FUNCTION(pwm0),
+ SH_PFC_FUNCTION(pwm1),
+ SH_PFC_FUNCTION(pwm2),
+ SH_PFC_FUNCTION(pwm3),
+ SH_PFC_FUNCTION(pwm4),
+ SH_PFC_FUNCTION(pwm5),
+ SH_PFC_FUNCTION(pwm6),
+ SH_PFC_FUNCTION(scif0),
+ SH_PFC_FUNCTION(scif1),
+ SH_PFC_FUNCTION(scif2),
+ SH_PFC_FUNCTION(scif3),
+ SH_PFC_FUNCTION(scif4),
+ SH_PFC_FUNCTION(scif5),
+ SH_PFC_FUNCTION(scif_clk),
+ SH_PFC_FUNCTION(usb0),
+ SH_PFC_FUNCTION(usb30),
+ }
};
static const struct pinmux_cfg_reg pinmux_config_regs[] = {
@@ -2738,6 +3534,30 @@ static const struct sh_pfc_soc_operations r8a77990_pinmux_ops = {
.set_bias = r8a77990_pinmux_set_bias,
};
+#ifdef CONFIG_PINCTRL_PFC_R8A774C0
+const struct sh_pfc_soc_info r8a774c0_pinmux_info = {
+ .name = "r8a774c0_pfc",
+ .ops = &r8a77990_pinmux_ops,
+ .unlock_reg = 0xe6060000, /* PMMR */
+
+ .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
+
+ .pins = pinmux_pins,
+ .nr_pins = ARRAY_SIZE(pinmux_pins),
+ .groups = pinmux_groups.common,
+ .nr_groups = ARRAY_SIZE(pinmux_groups.common),
+ .functions = pinmux_functions.common,
+ .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),
+};
+#endif
+
+#ifdef CONFIG_PINCTRL_PFC_R8A77990
const struct sh_pfc_soc_info r8a77990_pinmux_info = {
.name = "r8a77990_pfc",
.ops = &r8a77990_pinmux_ops,
@@ -2747,10 +3567,12 @@ const struct sh_pfc_soc_info r8a77990_pinmux_info = {
.pins = pinmux_pins,
.nr_pins = ARRAY_SIZE(pinmux_pins),
- .groups = pinmux_groups,
- .nr_groups = ARRAY_SIZE(pinmux_groups),
- .functions = pinmux_functions,
- .nr_functions = ARRAY_SIZE(pinmux_functions),
+ .groups = pinmux_groups.common,
+ .nr_groups = ARRAY_SIZE(pinmux_groups.common) +
+ ARRAY_SIZE(pinmux_groups.automotive),
+ .functions = pinmux_functions.common,
+ .nr_functions = ARRAY_SIZE(pinmux_functions.common) +
+ ARRAY_SIZE(pinmux_functions.automotive),
.cfg_regs = pinmux_config_regs,
.bias_regs = pinmux_bias_regs,
@@ -2758,3 +3580,4 @@ const struct sh_pfc_soc_info r8a77990_pinmux_info = {
.pinmux_data = pinmux_data,
.pinmux_data_size = ARRAY_SIZE(pinmux_data),
};
+#endif
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a77995.c b/drivers/pinctrl/sh-pfc/pfc-r8a77995.c
index adade5b7ffbc..9484eaa8522a 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a77995.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a77995.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* R8A77995 processor support - PFC hardware block.
*
@@ -8,10 +9,6 @@
* R-Car Gen3 processor support - PFC hardware block.
*
* Copyright (C) 2015 Renesas Electronics Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
*/
#include <linux/kernel.h>
@@ -520,6 +517,10 @@ static const u16 pinmux_data[] = {
PINMUX_SINGLE(QSPI0_SPCLK),
PINMUX_SINGLE(SCL0),
PINMUX_SINGLE(SDA0),
+ PINMUX_SINGLE(MSIOF0_RXD),
+ PINMUX_SINGLE(MSIOF0_TXD),
+ PINMUX_SINGLE(MSIOF0_SYNC),
+ PINMUX_SINGLE(MSIOF0_SCK),
/* IPSR0 */
PINMUX_IPSR_MSEL(IP0_3_0, IRQ0_A, SEL_IRQ_0_0),
@@ -1277,6 +1278,289 @@ static const unsigned int mmc_ctrl_mux[] = {
MMC_CLK_MARK, MMC_CMD_MARK,
};
+/* - MSIOF0 ----------------------------------------------------------------- */
+static const unsigned int msiof0_clk_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(4, 12),
+};
+
+static const unsigned int msiof0_clk_mux[] = {
+ MSIOF0_SCK_MARK,
+};
+
+static const unsigned int msiof0_sync_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(4, 13),
+};
+
+static const unsigned int msiof0_sync_mux[] = {
+ MSIOF0_SYNC_MARK,
+};
+
+static const unsigned int msiof0_ss1_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(4, 20),
+};
+
+static const unsigned int msiof0_ss1_mux[] = {
+ MSIOF0_SS1_MARK,
+};
+
+static const unsigned int msiof0_ss2_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(4, 21),
+};
+
+static const unsigned int msiof0_ss2_mux[] = {
+ MSIOF0_SS2_MARK,
+};
+
+static const unsigned int msiof0_txd_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(4, 14),
+};
+
+static const unsigned int msiof0_txd_mux[] = {
+ MSIOF0_TXD_MARK,
+};
+
+static const unsigned int msiof0_rxd_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(4, 15),
+};
+
+static const unsigned int msiof0_rxd_mux[] = {
+ MSIOF0_RXD_MARK,
+};
+
+/* - MSIOF1 ----------------------------------------------------------------- */
+static const unsigned int msiof1_clk_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(4, 16),
+};
+
+static const unsigned int msiof1_clk_mux[] = {
+ MSIOF1_SCK_MARK,
+};
+
+static const unsigned int msiof1_sync_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(4, 19),
+};
+
+static const unsigned int msiof1_sync_mux[] = {
+ MSIOF1_SYNC_MARK,
+};
+
+static const unsigned int msiof1_ss1_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(4, 25),
+};
+
+static const unsigned int msiof1_ss1_mux[] = {
+ MSIOF1_SS1_MARK,
+};
+
+static const unsigned int msiof1_ss2_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(4, 22),
+};
+
+static const unsigned int msiof1_ss2_mux[] = {
+ MSIOF1_SS2_MARK,
+};
+
+static const unsigned int msiof1_txd_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(4, 17),
+};
+
+static const unsigned int msiof1_txd_mux[] = {
+ MSIOF1_TXD_MARK,
+};
+
+static const unsigned int msiof1_rxd_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(4, 18),
+};
+
+static const unsigned int msiof1_rxd_mux[] = {
+ MSIOF1_RXD_MARK,
+};
+
+/* - MSIOF2 ----------------------------------------------------------------- */
+static const unsigned int msiof2_clk_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(0, 3),
+};
+
+static const unsigned int msiof2_clk_mux[] = {
+ MSIOF2_SCK_MARK,
+};
+
+static const unsigned int msiof2_sync_a_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(0, 6),
+};
+
+static const unsigned int msiof2_sync_a_mux[] = {
+ MSIOF2_SYNC_A_MARK,
+};
+
+static const unsigned int msiof2_sync_b_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(0, 2),
+};
+
+static const unsigned int msiof2_sync_b_mux[] = {
+ MSIOF2_SYNC_B_MARK,
+};
+
+static const unsigned int msiof2_ss1_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(0, 7),
+};
+
+static const unsigned int msiof2_ss1_mux[] = {
+ MSIOF2_SS1_MARK,
+};
+
+static const unsigned int msiof2_ss2_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(0, 8),
+};
+
+static const unsigned int msiof2_ss2_mux[] = {
+ MSIOF2_SS2_MARK,
+};
+
+static const unsigned int msiof2_txd_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(0, 4),
+};
+
+static const unsigned int msiof2_txd_mux[] = {
+ MSIOF2_TXD_MARK,
+};
+
+static const unsigned int msiof2_rxd_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(0, 5),
+};
+
+static const unsigned int msiof2_rxd_mux[] = {
+ MSIOF2_RXD_MARK,
+};
+
+/* - MSIOF3 ----------------------------------------------------------------- */
+static const unsigned int msiof3_clk_a_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(2, 24),
+};
+
+static const unsigned int msiof3_clk_a_mux[] = {
+ MSIOF3_SCK_A_MARK,
+};
+
+static const unsigned int msiof3_sync_a_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(2, 21),
+};
+
+static const unsigned int msiof3_sync_a_mux[] = {
+ MSIOF3_SYNC_A_MARK,
+};
+
+static const unsigned int msiof3_ss1_a_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(2, 14),
+};
+
+static const unsigned int msiof3_ss1_a_mux[] = {
+ MSIOF3_SS1_A_MARK,
+};
+
+static const unsigned int msiof3_ss2_a_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(2, 10),
+};
+
+static const unsigned int msiof3_ss2_a_mux[] = {
+ MSIOF3_SS2_A_MARK,
+};
+
+static const unsigned int msiof3_txd_a_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(2, 22),
+};
+
+static const unsigned int msiof3_txd_a_mux[] = {
+ MSIOF3_TXD_A_MARK,
+};
+
+static const unsigned int msiof3_rxd_a_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(2, 23),
+};
+
+static const unsigned int msiof3_rxd_a_mux[] = {
+ MSIOF3_RXD_A_MARK,
+};
+
+static const unsigned int msiof3_clk_b_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(1, 8),
+};
+
+static const unsigned int msiof3_clk_b_mux[] = {
+ MSIOF3_SCK_B_MARK,
+};
+
+static const unsigned int msiof3_sync_b_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(1, 9),
+};
+
+static const unsigned int msiof3_sync_b_mux[] = {
+ MSIOF3_SYNC_B_MARK,
+};
+
+static const unsigned int msiof3_ss1_b_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(1, 6),
+};
+
+static const unsigned int msiof3_ss1_b_mux[] = {
+ MSIOF3_SS1_B_MARK,
+};
+
+static const unsigned int msiof3_ss2_b_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(1, 7),
+};
+
+static const unsigned int msiof3_ss2_b_mux[] = {
+ MSIOF3_SS2_B_MARK,
+};
+
+static const unsigned int msiof3_txd_b_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(1, 0),
+};
+
+static const unsigned int msiof3_txd_b_mux[] = {
+ MSIOF3_TXD_B_MARK,
+};
+
+static const unsigned int msiof3_rxd_b_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(1, 1),
+};
+
+static const unsigned int msiof3_rxd_b_mux[] = {
+ MSIOF3_RXD_B_MARK,
+};
+
/* - PWM0 ------------------------------------------------------------------ */
static const unsigned int pwm0_a_pins[] = {
/* PWM */
@@ -1752,6 +2036,37 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(mmc_data4),
SH_PFC_PIN_GROUP(mmc_data8),
SH_PFC_PIN_GROUP(mmc_ctrl),
+ SH_PFC_PIN_GROUP(msiof0_clk),
+ SH_PFC_PIN_GROUP(msiof0_sync),
+ SH_PFC_PIN_GROUP(msiof0_ss1),
+ SH_PFC_PIN_GROUP(msiof0_ss2),
+ SH_PFC_PIN_GROUP(msiof0_txd),
+ SH_PFC_PIN_GROUP(msiof0_rxd),
+ SH_PFC_PIN_GROUP(msiof1_clk),
+ SH_PFC_PIN_GROUP(msiof1_sync),
+ SH_PFC_PIN_GROUP(msiof1_ss1),
+ SH_PFC_PIN_GROUP(msiof1_ss2),
+ SH_PFC_PIN_GROUP(msiof1_txd),
+ SH_PFC_PIN_GROUP(msiof1_rxd),
+ SH_PFC_PIN_GROUP(msiof2_clk),
+ SH_PFC_PIN_GROUP(msiof2_sync_a),
+ SH_PFC_PIN_GROUP(msiof2_sync_b),
+ SH_PFC_PIN_GROUP(msiof2_ss1),
+ SH_PFC_PIN_GROUP(msiof2_ss2),
+ SH_PFC_PIN_GROUP(msiof2_txd),
+ SH_PFC_PIN_GROUP(msiof2_rxd),
+ SH_PFC_PIN_GROUP(msiof3_clk_a),
+ SH_PFC_PIN_GROUP(msiof3_sync_a),
+ SH_PFC_PIN_GROUP(msiof3_ss1_a),
+ SH_PFC_PIN_GROUP(msiof3_ss2_a),
+ SH_PFC_PIN_GROUP(msiof3_txd_a),
+ SH_PFC_PIN_GROUP(msiof3_rxd_a),
+ SH_PFC_PIN_GROUP(msiof3_clk_b),
+ SH_PFC_PIN_GROUP(msiof3_sync_b),
+ SH_PFC_PIN_GROUP(msiof3_ss1_b),
+ SH_PFC_PIN_GROUP(msiof3_ss2_b),
+ SH_PFC_PIN_GROUP(msiof3_txd_b),
+ SH_PFC_PIN_GROUP(msiof3_rxd_b),
SH_PFC_PIN_GROUP(pwm0_a),
SH_PFC_PIN_GROUP(pwm0_b),
SH_PFC_PIN_GROUP(pwm0_c),
@@ -1982,6 +2297,49 @@ static const char * const vin4_groups[] = {
"vin4_clk",
};
+static const char * const msiof0_groups[] = {
+ "msiof0_clk",
+ "msiof0_sync",
+ "msiof0_ss1",
+ "msiof0_ss2",
+ "msiof0_txd",
+ "msiof0_rxd",
+};
+
+static const char * const msiof1_groups[] = {
+ "msiof1_clk",
+ "msiof1_sync",
+ "msiof1_ss1",
+ "msiof1_ss2",
+ "msiof1_txd",
+ "msiof1_rxd",
+};
+
+static const char * const msiof2_groups[] = {
+ "msiof2_clk",
+ "msiof2_sync_a",
+ "msiof2_sync_b",
+ "msiof2_ss1",
+ "msiof2_ss2",
+ "msiof2_txd",
+ "msiof2_rxd",
+};
+
+static const char * const msiof3_groups[] = {
+ "msiof3_clk_a",
+ "msiof3_sync_a",
+ "msiof3_ss1_a",
+ "msiof3_ss2_a",
+ "msiof3_txd_a",
+ "msiof3_rxd_a",
+ "msiof3_clk_b",
+ "msiof3_sync_b",
+ "msiof3_ss1_b",
+ "msiof3_ss2_b",
+ "msiof3_txd_b",
+ "msiof3_rxd_b",
+};
+
static const struct sh_pfc_function pinmux_functions[] = {
SH_PFC_FUNCTION(audio_clk),
SH_PFC_FUNCTION(avb0),
@@ -1996,6 +2354,10 @@ static const struct sh_pfc_function pinmux_functions[] = {
SH_PFC_FUNCTION(i2c2),
SH_PFC_FUNCTION(i2c3),
SH_PFC_FUNCTION(mmc),
+ SH_PFC_FUNCTION(msiof0),
+ SH_PFC_FUNCTION(msiof1),
+ SH_PFC_FUNCTION(msiof2),
+ SH_PFC_FUNCTION(msiof3),
SH_PFC_FUNCTION(pwm0),
SH_PFC_FUNCTION(pwm1),
SH_PFC_FUNCTION(pwm2),
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7203.c b/drivers/pinctrl/sh-pfc/pfc-sh7203.c
index 61b27ec48876..9ee468a9bd0e 100644
--- a/drivers/pinctrl/sh-pfc/pfc-sh7203.c
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7203.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* SH7203 Pinmux
*
* Copyright (C) 2008 Magnus Damm
- *
- * 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/kernel.h>
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7264.c b/drivers/pinctrl/sh-pfc/pfc-sh7264.c
index 8070765311db..4f44ce0d7237 100644
--- a/drivers/pinctrl/sh-pfc/pfc-sh7264.c
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7264.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* SH7264 Pinmux
*
* Copyright (C) 2012 Renesas Electronics Europe Ltd
- *
- * 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/kernel.h>
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7269.c b/drivers/pinctrl/sh-pfc/pfc-sh7269.c
index a50d22bef1f4..5b48a0368e55 100644
--- a/drivers/pinctrl/sh-pfc/pfc-sh7269.c
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7269.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* SH7269 Pinmux
*
* Copyright (C) 2012 Renesas Electronics Europe Ltd
* Copyright (C) 2012 Phil Edworthy
- *
- * 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/kernel.h>
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh73a0.c b/drivers/pinctrl/sh-pfc/pfc-sh73a0.c
index d25e6f674d0a..654029fc8d96 100644
--- a/drivers/pinctrl/sh-pfc/pfc-sh73a0.c
+++ b/drivers/pinctrl/sh-pfc/pfc-sh73a0.c
@@ -1,22 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* sh73a0 processor support - PFC hardware block
*
* Copyright (C) 2010 Renesas Solutions Corp.
* Copyright (C) 2010 NISHIMOTO Hiroki
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; version 2 of the
- * License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/io.h>
#include <linux/kernel.h>
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7720.c b/drivers/pinctrl/sh-pfc/pfc-sh7720.c
index e07a82df42c8..65694bfaa08d 100644
--- a/drivers/pinctrl/sh-pfc/pfc-sh7720.c
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7720.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* SH7720 Pinmux
*
* Copyright (C) 2008 Magnus Damm
- *
- * 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/kernel.h>
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7723.c b/drivers/pinctrl/sh-pfc/pfc-sh7723.c
index 8ea18df03492..86f9a88726b7 100644
--- a/drivers/pinctrl/sh-pfc/pfc-sh7723.c
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7723.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* SH7723 Pinmux
*
* Copyright (C) 2008 Magnus Damm
- *
- * 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/init.h>
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7724.c b/drivers/pinctrl/sh-pfc/pfc-sh7724.c
index 7f6c36c1a8fa..2cc4aa7df613 100644
--- a/drivers/pinctrl/sh-pfc/pfc-sh7724.c
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7724.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* SH7724 Pinmux
*
@@ -7,10 +8,6 @@
*
* Based on SH7723 Pinmux
* Copyright (C) 2008 Magnus Damm
- *
- * 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/init.h>
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7734.c b/drivers/pinctrl/sh-pfc/pfc-sh7734.c
index 6502e676d368..b0533c86053a 100644
--- a/drivers/pinctrl/sh-pfc/pfc-sh7734.c
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7734.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* SH7734 processor support - PFC hardware block
*
* Copyright (C) 2012 Renesas Solutions Corp.
* Copyright (C) 2012 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.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.
*/
#include <linux/init.h>
#include <linux/kernel.h>
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7757.c b/drivers/pinctrl/sh-pfc/pfc-sh7757.c
index 6d8c31caefc1..b16090690ee3 100644
--- a/drivers/pinctrl/sh-pfc/pfc-sh7757.c
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7757.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* SH7757 (B0 step) Pinmux
*
@@ -7,10 +8,6 @@
*
* Based on SH7723 Pinmux
* Copyright (C) 2008 Magnus Damm
- *
- * 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/init.h>
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7785.c b/drivers/pinctrl/sh-pfc/pfc-sh7785.c
index 1934cbec3965..193179f7fdd9 100644
--- a/drivers/pinctrl/sh-pfc/pfc-sh7785.c
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7785.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* SH7785 Pinmux
*
* Copyright (C) 2008 Magnus Damm
- *
- * 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/init.h>
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7786.c b/drivers/pinctrl/sh-pfc/pfc-sh7786.c
index c98585d80de8..cc2657c4f85c 100644
--- a/drivers/pinctrl/sh-pfc/pfc-sh7786.c
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7786.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* SH7786 Pinmux
*
@@ -7,10 +8,6 @@
* Based on SH7785 pinmux
*
* Copyright (C) 2008 Magnus Damm
- *
- * 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/init.h>
diff --git a/drivers/pinctrl/sh-pfc/pfc-shx3.c b/drivers/pinctrl/sh-pfc/pfc-shx3.c
index 3f60c900645e..905ae00cc6f1 100644
--- a/drivers/pinctrl/sh-pfc/pfc-shx3.c
+++ b/drivers/pinctrl/sh-pfc/pfc-shx3.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* SH-X3 prototype CPU pinmux
*
* Copyright (C) 2010 Paul Mundt
- *
- * 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/init.h>
#include <linux/kernel.h>
diff --git a/drivers/pinctrl/sh-pfc/pinctrl.c b/drivers/pinctrl/sh-pfc/pinctrl.c
index 654dc20e171b..274d5ff87078 100644
--- a/drivers/pinctrl/sh-pfc/pinctrl.c
+++ b/drivers/pinctrl/sh-pfc/pinctrl.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* SuperH Pin Function Controller pinmux support.
*
* Copyright (C) 2012 Paul Mundt
- *
- * 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.
*/
#define DRV_NAME "sh-pfc"
diff --git a/drivers/pinctrl/sh-pfc/sh_pfc.h b/drivers/pinctrl/sh-pfc/sh_pfc.h
index 3d0b31636d6d..458ae0a6b540 100644
--- a/drivers/pinctrl/sh-pfc/sh_pfc.h
+++ b/drivers/pinctrl/sh-pfc/sh_pfc.h
@@ -1,11 +1,8 @@
-/*
+/* SPDX-License-Identifier: GPL-2.0
+ *
* SuperH Pin Function Controller Support
*
* Copyright (c) 2008 Magnus Damm
- *
- * 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.
*/
#ifndef __SH_PFC_H
@@ -273,8 +270,11 @@ extern const struct sh_pfc_soc_info emev2_pinmux_info;
extern const struct sh_pfc_soc_info r8a73a4_pinmux_info;
extern const struct sh_pfc_soc_info r8a7740_pinmux_info;
extern const struct sh_pfc_soc_info r8a7743_pinmux_info;
+extern const struct sh_pfc_soc_info r8a7744_pinmux_info;
extern const struct sh_pfc_soc_info r8a7745_pinmux_info;
extern const struct sh_pfc_soc_info r8a77470_pinmux_info;
+extern const struct sh_pfc_soc_info r8a774a1_pinmux_info;
+extern const struct sh_pfc_soc_info r8a774c0_pinmux_info;
extern const struct sh_pfc_soc_info r8a7778_pinmux_info;
extern const struct sh_pfc_soc_info r8a7779_pinmux_info;
extern const struct sh_pfc_soc_info r8a7790_pinmux_info;
diff --git a/drivers/pinctrl/sirf/pinctrl-atlas7.c b/drivers/pinctrl/sirf/pinctrl-atlas7.c
index 3abb028f6158..4ba171827428 100644
--- a/drivers/pinctrl/sirf/pinctrl-atlas7.c
+++ b/drivers/pinctrl/sirf/pinctrl-atlas7.c
@@ -19,14 +19,13 @@
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/of_irq.h>
-#include <linux/of_gpio.h>
#include <linux/pinctrl/machine.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/pinconf-generic.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
/* Definition of Pad&Mux Properties */
#define N 0
@@ -5540,14 +5539,10 @@ static int atlas7_pinmux_resume_noirq(struct device *dev)
{
struct atlas7_pmx *pmx = dev_get_drvdata(dev);
struct atlas7_pad_status *status;
- struct atlas7_pad_config *conf;
int idx;
- u32 bank;
for (idx = 0; idx < pmx->pctl_desc.npins; idx++) {
/* Get this Pad's descriptor from PINCTRL */
- conf = &pmx->pctl_data->confs[idx];
- bank = atlas7_pin_to_bank(idx);
status = &pmx->sleep_data[idx];
/* Restore Function selector */
@@ -6058,8 +6053,8 @@ static int atlas7_gpio_probe(struct platform_device *pdev)
ret = gpiochip_add_data(chip, a7gc);
if (ret) {
dev_err(&pdev->dev,
- "%s: error in probe function with status %d\n",
- np->name, ret);
+ "%pOF: error in probe function with status %d\n",
+ np, ret);
goto failed;
}
diff --git a/drivers/pinctrl/sirf/pinctrl-sirf.c b/drivers/pinctrl/sirf/pinctrl-sirf.c
index 505845c66dd0..2e42d738b589 100644
--- a/drivers/pinctrl/sirf/pinctrl-sirf.c
+++ b/drivers/pinctrl/sirf/pinctrl-sirf.c
@@ -27,7 +27,7 @@
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/bitops.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/of_gpio.h>
#include "pinctrl-sirf.h"
diff --git a/drivers/pinctrl/spear/pinctrl-spear.h b/drivers/pinctrl/spear/pinctrl-spear.h
index aa5cf7032231..db029b148c87 100644
--- a/drivers/pinctrl/spear/pinctrl-spear.h
+++ b/drivers/pinctrl/spear/pinctrl-spear.h
@@ -12,7 +12,7 @@
#ifndef __PINMUX_SPEAR_H__
#define __PINMUX_SPEAR_H__
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/io.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/types.h>
diff --git a/drivers/pinctrl/sprd/pinctrl-sprd.c b/drivers/pinctrl/sprd/pinctrl-sprd.c
index 78c2f548b25f..4537b5453996 100644
--- a/drivers/pinctrl/sprd/pinctrl-sprd.c
+++ b/drivers/pinctrl/sprd/pinctrl-sprd.c
@@ -1059,6 +1059,12 @@ int sprd_pinctrl_core_probe(struct platform_device *pdev,
return ret;
}
+ ret = sprd_pinctrl_parse_dt(sprd_pctl);
+ if (ret) {
+ dev_err(&pdev->dev, "fail to parse dt properties\n");
+ return ret;
+ }
+
pin_desc = devm_kcalloc(&pdev->dev,
pinctrl_info->npins,
sizeof(struct pinctrl_pin_desc),
@@ -1083,13 +1089,6 @@ int sprd_pinctrl_core_probe(struct platform_device *pdev,
return PTR_ERR(sprd_pctl->pctl);
}
- ret = sprd_pinctrl_parse_dt(sprd_pctl);
- if (ret) {
- dev_err(&pdev->dev, "fail to parse dt properties\n");
- pinctrl_unregister(sprd_pctl->pctl);
- return ret;
- }
-
return 0;
}
diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.c b/drivers/pinctrl/stm32/pinctrl-stm32.c
index a9bec6e6fdd1..0fbfcc9ea07c 100644
--- a/drivers/pinctrl/stm32/pinctrl-stm32.c
+++ b/drivers/pinctrl/stm32/pinctrl-stm32.c
@@ -416,8 +416,8 @@ static int stm32_pctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
pins = of_find_property(node, "pinmux", NULL);
if (!pins) {
- dev_err(pctl->dev, "missing pins property in node %s .\n",
- node->name);
+ dev_err(pctl->dev, "missing pins property in node %pOFn .\n",
+ node);
return -EINVAL;
}
diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
index 4d9bf9b3e9f3..34e17376ef99 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
@@ -332,15 +332,15 @@ static int sunxi_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
function = sunxi_pctrl_parse_function_prop(node);
if (!function) {
- dev_err(pctl->dev, "missing function property in node %s\n",
- node->name);
+ dev_err(pctl->dev, "missing function property in node %pOFn\n",
+ node);
return -EINVAL;
}
pin_prop = sunxi_pctrl_find_pins_prop(node, &npins);
if (!pin_prop) {
- dev_err(pctl->dev, "missing pins property in node %s\n",
- node->name);
+ dev_err(pctl->dev, "missing pins property in node %pOFn\n",
+ node);
return -EINVAL;
}
@@ -1042,6 +1042,7 @@ static int sunxi_pinctrl_add_function(struct sunxi_pinctrl *pctl,
static int sunxi_pinctrl_build_state(struct platform_device *pdev)
{
struct sunxi_pinctrl *pctl = platform_get_drvdata(pdev);
+ void *ptr;
int i;
/*
@@ -1079,10 +1080,9 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev)
* We suppose that we won't have any more functions than pins,
* we'll reallocate that later anyway
*/
- pctl->functions = devm_kcalloc(&pdev->dev,
- pctl->ngroups,
- sizeof(*pctl->functions),
- GFP_KERNEL);
+ pctl->functions = kcalloc(pctl->ngroups,
+ sizeof(*pctl->functions),
+ GFP_KERNEL);
if (!pctl->functions)
return -ENOMEM;
@@ -1109,13 +1109,15 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev)
}
/* And now allocated and fill the array for real */
- pctl->functions = krealloc(pctl->functions,
- pctl->nfunctions * sizeof(*pctl->functions),
- GFP_KERNEL);
- if (!pctl->functions) {
+ ptr = krealloc(pctl->functions,
+ pctl->nfunctions * sizeof(*pctl->functions),
+ GFP_KERNEL);
+ if (!ptr) {
kfree(pctl->functions);
+ pctl->functions = NULL;
return -ENOMEM;
}
+ pctl->functions = ptr;
for (i = 0; i < pctl->desc->npins; i++) {
const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
@@ -1133,8 +1135,10 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev)
func_item = sunxi_pinctrl_find_function_by_name(pctl,
func->name);
- if (!func_item)
+ if (!func_item) {
+ kfree(pctl->functions);
return -EINVAL;
+ }
if (!func_item->groups) {
func_item->groups =
@@ -1142,8 +1146,10 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev)
func_item->ngroups,
sizeof(*func_item->groups),
GFP_KERNEL);
- if (!func_item->groups)
+ if (!func_item->groups) {
+ kfree(pctl->functions);
return -ENOMEM;
+ }
}
func_grp = func_item->groups;
diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c
index 1aba75897d14..a5008c066bac 100644
--- a/drivers/pinctrl/tegra/pinctrl-tegra.c
+++ b/drivers/pinctrl/tegra/pinctrl-tegra.c
@@ -737,4 +737,3 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
return 0;
}
-EXPORT_SYMBOL_GPL(tegra_pinctrl_probe);
diff --git a/drivers/pinctrl/ti/pinctrl-ti-iodelay.c b/drivers/pinctrl/ti/pinctrl-ti-iodelay.c
index 8782c348ebe9..a4bc506a01a3 100644
--- a/drivers/pinctrl/ti/pinctrl-ti-iodelay.c
+++ b/drivers/pinctrl/ti/pinctrl-ti-iodelay.c
@@ -452,8 +452,8 @@ static int ti_iodelay_node_iterator(struct pinctrl_dev *pctldev,
pin = ti_iodelay_offset_to_pin(iod, cfg[pin_index].offset);
if (pin < 0) {
- dev_err(iod->dev, "could not add functions for %s %ux\n",
- np->name, cfg[pin_index].offset);
+ dev_err(iod->dev, "could not add functions for %pOFn %ux\n",
+ np, cfg[pin_index].offset);
return -ENODEV;
}
pins[pin_index] = pin;
@@ -461,8 +461,8 @@ static int ti_iodelay_node_iterator(struct pinctrl_dev *pctldev,
pd = &iod->pa[pin];
pd->drv_data = &cfg[pin_index];
- dev_dbg(iod->dev, "%s offset=%x a_delay = %d g_delay = %d\n",
- np->name, cfg[pin_index].offset, cfg[pin_index].a_delay,
+ dev_dbg(iod->dev, "%pOFn offset=%x a_delay = %d g_delay = %d\n",
+ np, cfg[pin_index].offset, cfg[pin_index].a_delay,
cfg[pin_index].g_delay);
return 0;
diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier-pro4.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-pro4.c
index 60722898d5c7..4326f5c3683c 100644
--- a/drivers/pinctrl/uniphier/pinctrl-uniphier-pro4.c
+++ b/drivers/pinctrl/uniphier/pinctrl-uniphier-pro4.c
@@ -1048,9 +1048,8 @@ static const unsigned nand_cs1_pins[] = {131, 132};
static const int nand_cs1_muxvals[] = {1, 1};
static const unsigned sd_pins[] = {150, 151, 152, 153, 154, 155, 156, 157, 158};
static const int sd_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
-static const unsigned sd1_pins[] = {319, 320, 321, 322, 323, 324, 325, 326,
- 327};
-static const int sd1_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
+static const unsigned int sd1_pins[] = {319, 320, 321, 322, 323, 324, 325, 326};
+static const int sd1_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0};
static const unsigned spi0_pins[] = {199, 200, 201, 202};
static const int spi0_muxvals[] = {11, 11, 11, 11};
static const unsigned spi1_pins[] = {195, 196, 197, 198, 235, 238, 239};
diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier.h b/drivers/pinctrl/uniphier/pinctrl-uniphier.h
index 0a3d2ac27503..c63e3c8b97cd 100644
--- a/drivers/pinctrl/uniphier/pinctrl-uniphier.h
+++ b/drivers/pinctrl/uniphier/pinctrl-uniphier.h
@@ -16,7 +16,7 @@
#ifndef __PINCTRL_UNIPHIER_H__
#define __PINCTRL_UNIPHIER_H__
-#include <linux/bitops.h>
+#include <linux/bits.h>
#include <linux/build_bug.h>
#include <linux/kernel.h>
#include <linux/types.h>
diff --git a/drivers/pinctrl/vt8500/pinctrl-wmt.c b/drivers/pinctrl/vt8500/pinctrl-wmt.c
index c08318a5a91b..ccdf68e766b8 100644
--- a/drivers/pinctrl/vt8500/pinctrl-wmt.c
+++ b/drivers/pinctrl/vt8500/pinctrl-wmt.c
@@ -494,10 +494,8 @@ static int wmt_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
u32 val;
val = readl_relaxed(data->base + reg_dir);
- if (val & BIT(bit))
- return GPIOF_DIR_OUT;
- else
- return GPIOF_DIR_IN;
+ /* Return 0 == output, 1 == input */
+ return !(val & BIT(bit));
}
static int wmt_gpio_get_value(struct gpio_chip *chip, unsigned offset)
diff --git a/drivers/pinctrl/vt8500/pinctrl-wmt.h b/drivers/pinctrl/vt8500/pinctrl-wmt.h
index 885613396fe7..ade8be3b98b0 100644
--- a/drivers/pinctrl/vt8500/pinctrl-wmt.h
+++ b/drivers/pinctrl/vt8500/pinctrl-wmt.h
@@ -13,7 +13,7 @@
* more details.
*/
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
/* VT8500 has no enable register in the extgpio bank. */
#define NO_REG 0xFFFF
diff --git a/drivers/platform/chrome/chromeos_tbmc.c b/drivers/platform/chrome/chromeos_tbmc.c
index 1e81f8144c0d..ce259ec9f990 100644
--- a/drivers/platform/chrome/chromeos_tbmc.c
+++ b/drivers/platform/chrome/chromeos_tbmc.c
@@ -99,7 +99,7 @@ static const struct acpi_device_id chromeos_tbmc_acpi_device_ids[] = {
};
MODULE_DEVICE_TABLE(acpi, chromeos_tbmc_acpi_device_ids);
-static const SIMPLE_DEV_PM_OPS(chromeos_tbmc_pm_ops, NULL,
+static SIMPLE_DEV_PM_OPS(chromeos_tbmc_pm_ops, NULL,
chromeos_tbmc_resume);
static struct acpi_driver chromeos_tbmc_driver = {
diff --git a/drivers/platform/chrome/cros_ec_lpc.c b/drivers/platform/chrome/cros_ec_lpc.c
index 31c8b8c49e45..e1b75775cd4a 100644
--- a/drivers/platform/chrome/cros_ec_lpc.c
+++ b/drivers/platform/chrome/cros_ec_lpc.c
@@ -25,14 +25,16 @@
#include <linux/dmi.h>
#include <linux/delay.h>
#include <linux/io.h>
+#include <linux/interrupt.h>
#include <linux/mfd/cros_ec.h>
#include <linux/mfd/cros_ec_commands.h>
-#include <linux/mfd/cros_ec_lpc_reg.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/printk.h>
#include <linux/suspend.h>
+#include "cros_ec_lpc_reg.h"
+
#define DRV_NAME "cros_ec_lpcs"
#define ACPI_DRV_NAME "GOOG0004"
@@ -248,7 +250,7 @@ static int cros_ec_lpc_probe(struct platform_device *pdev)
acpi_status status;
struct cros_ec_device *ec_dev;
u8 buf[2];
- int ret;
+ int irq, ret;
if (!devm_request_region(dev, EC_LPC_ADDR_MEMMAP, EC_MEMMAP_SIZE,
dev_name(dev))) {
@@ -287,6 +289,18 @@ static int cros_ec_lpc_probe(struct platform_device *pdev)
sizeof(struct ec_response_get_protocol_info);
ec_dev->dout_size = sizeof(struct ec_host_request);
+ /*
+ * Some boards do not have an IRQ allotted for cros_ec_lpc,
+ * which makes ENXIO an expected (and safe) scenario.
+ */
+ irq = platform_get_irq(pdev, 0);
+ if (irq > 0)
+ ec_dev->irq = irq;
+ else if (irq != -ENXIO) {
+ dev_err(dev, "couldn't retrieve IRQ number (%d)\n", irq);
+ return irq;
+ }
+
ret = cros_ec_register(ec_dev);
if (ret) {
dev_err(dev, "couldn't register ec_dev (%d)\n", ret);
diff --git a/drivers/platform/chrome/cros_ec_lpc_mec.c b/drivers/platform/chrome/cros_ec_lpc_mec.c
index 2eda2c2fc210..c4edfa83e493 100644
--- a/drivers/platform/chrome/cros_ec_lpc_mec.c
+++ b/drivers/platform/chrome/cros_ec_lpc_mec.c
@@ -24,10 +24,11 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/mfd/cros_ec_commands.h>
-#include <linux/mfd/cros_ec_lpc_mec.h>
#include <linux/mutex.h>
#include <linux/types.h>
+#include "cros_ec_lpc_mec.h"
+
/*
* This mutex must be held while accessing the EMI unit. We can't rely on the
* EC mutex because memmap data may be accessed without it being held.
diff --git a/drivers/platform/chrome/cros_ec_lpc_mec.h b/drivers/platform/chrome/cros_ec_lpc_mec.h
new file mode 100644
index 000000000000..105068c0e919
--- /dev/null
+++ b/drivers/platform/chrome/cros_ec_lpc_mec.h
@@ -0,0 +1,90 @@
+/*
+ * cros_ec_lpc_mec - LPC variant I/O for Microchip EC
+ *
+ * Copyright (C) 2016 Google, Inc
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * This driver uses the Chrome OS EC byte-level message-based protocol for
+ * communicating the keyboard state (which keys are pressed) from a keyboard EC
+ * to the AP over some bus (such as i2c, lpc, spi). The EC does debouncing,
+ * but everything else (including deghosting) is done here. The main
+ * motivation for this is to keep the EC firmware as simple as possible, since
+ * it cannot be easily upgraded and EC flash/IRAM space is relatively
+ * expensive.
+ */
+
+#ifndef __CROS_EC_LPC_MEC_H
+#define __CROS_EC_LPC_MEC_H
+
+#include <linux/mfd/cros_ec_commands.h>
+
+enum cros_ec_lpc_mec_emi_access_mode {
+ /* 8-bit access */
+ ACCESS_TYPE_BYTE = 0x0,
+ /* 16-bit access */
+ ACCESS_TYPE_WORD = 0x1,
+ /* 32-bit access */
+ ACCESS_TYPE_LONG = 0x2,
+ /*
+ * 32-bit access, read or write of MEC_EMI_EC_DATA_B3 causes the
+ * EC data register to be incremented.
+ */
+ ACCESS_TYPE_LONG_AUTO_INCREMENT = 0x3,
+};
+
+enum cros_ec_lpc_mec_io_type {
+ MEC_IO_READ,
+ MEC_IO_WRITE,
+};
+
+/* Access IO ranges 0x800 thru 0x9ff using EMI interface instead of LPC */
+#define MEC_EMI_RANGE_START EC_HOST_CMD_REGION0
+#define MEC_EMI_RANGE_END (EC_LPC_ADDR_MEMMAP + EC_MEMMAP_SIZE)
+
+/* EMI registers are relative to base */
+#define MEC_EMI_BASE 0x800
+#define MEC_EMI_HOST_TO_EC (MEC_EMI_BASE + 0)
+#define MEC_EMI_EC_TO_HOST (MEC_EMI_BASE + 1)
+#define MEC_EMI_EC_ADDRESS_B0 (MEC_EMI_BASE + 2)
+#define MEC_EMI_EC_ADDRESS_B1 (MEC_EMI_BASE + 3)
+#define MEC_EMI_EC_DATA_B0 (MEC_EMI_BASE + 4)
+#define MEC_EMI_EC_DATA_B1 (MEC_EMI_BASE + 5)
+#define MEC_EMI_EC_DATA_B2 (MEC_EMI_BASE + 6)
+#define MEC_EMI_EC_DATA_B3 (MEC_EMI_BASE + 7)
+
+/*
+ * cros_ec_lpc_mec_init
+ *
+ * Initialize MEC I/O.
+ */
+void cros_ec_lpc_mec_init(void);
+
+/*
+ * cros_ec_lpc_mec_destroy
+ *
+ * Cleanup MEC I/O.
+ */
+void cros_ec_lpc_mec_destroy(void);
+
+/**
+ * cros_ec_lpc_io_bytes_mec - Read / write bytes to MEC EMI port
+ *
+ * @io_type: MEC_IO_READ or MEC_IO_WRITE, depending on request
+ * @offset: Base read / write address
+ * @length: Number of bytes to read / write
+ * @buf: Destination / source buffer
+ *
+ * @return 8-bit checksum of all bytes read / written
+ */
+u8 cros_ec_lpc_io_bytes_mec(enum cros_ec_lpc_mec_io_type io_type,
+ unsigned int offset, unsigned int length, u8 *buf);
+
+#endif /* __CROS_EC_LPC_MEC_H */
diff --git a/drivers/platform/chrome/cros_ec_lpc_reg.c b/drivers/platform/chrome/cros_ec_lpc_reg.c
index dcc7a3e30604..fc23d535c404 100644
--- a/drivers/platform/chrome/cros_ec_lpc_reg.c
+++ b/drivers/platform/chrome/cros_ec_lpc_reg.c
@@ -24,7 +24,8 @@
#include <linux/io.h>
#include <linux/mfd/cros_ec.h>
#include <linux/mfd/cros_ec_commands.h>
-#include <linux/mfd/cros_ec_lpc_mec.h>
+
+#include "cros_ec_lpc_mec.h"
static u8 lpc_read_bytes(unsigned int offset, unsigned int length, u8 *dest)
{
diff --git a/drivers/platform/chrome/cros_ec_lpc_reg.h b/drivers/platform/chrome/cros_ec_lpc_reg.h
new file mode 100644
index 000000000000..1c12c38b306a
--- /dev/null
+++ b/drivers/platform/chrome/cros_ec_lpc_reg.h
@@ -0,0 +1,61 @@
+/*
+ * cros_ec_lpc_reg - LPC access to the Chrome OS Embedded Controller
+ *
+ * Copyright (C) 2016 Google, Inc
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * This driver uses the Chrome OS EC byte-level message-based protocol for
+ * communicating the keyboard state (which keys are pressed) from a keyboard EC
+ * to the AP over some bus (such as i2c, lpc, spi). The EC does debouncing,
+ * but everything else (including deghosting) is done here. The main
+ * motivation for this is to keep the EC firmware as simple as possible, since
+ * it cannot be easily upgraded and EC flash/IRAM space is relatively
+ * expensive.
+ */
+
+#ifndef __CROS_EC_LPC_REG_H
+#define __CROS_EC_LPC_REG_H
+
+/**
+ * cros_ec_lpc_read_bytes - Read bytes from a given LPC-mapped address.
+ * Returns 8-bit checksum of all bytes read.
+ *
+ * @offset: Base read address
+ * @length: Number of bytes to read
+ * @dest: Destination buffer
+ */
+u8 cros_ec_lpc_read_bytes(unsigned int offset, unsigned int length, u8 *dest);
+
+/**
+ * cros_ec_lpc_write_bytes - Write bytes to a given LPC-mapped address.
+ * Returns 8-bit checksum of all bytes written.
+ *
+ * @offset: Base write address
+ * @length: Number of bytes to write
+ * @msg: Write data buffer
+ */
+u8 cros_ec_lpc_write_bytes(unsigned int offset, unsigned int length, u8 *msg);
+
+/**
+ * cros_ec_lpc_reg_init
+ *
+ * Initialize register I/O.
+ */
+void cros_ec_lpc_reg_init(void);
+
+/**
+ * cros_ec_lpc_reg_destroy
+ *
+ * Cleanup reg I/O.
+ */
+void cros_ec_lpc_reg_destroy(void);
+
+#endif /* __CROS_EC_LPC_REG_H */
diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c
index 398393ab5df8..b6fd4838f60f 100644
--- a/drivers/platform/chrome/cros_ec_proto.c
+++ b/drivers/platform/chrome/cros_ec_proto.c
@@ -520,7 +520,7 @@ static int get_next_event_xfer(struct cros_ec_device *ec_dev,
ret = cros_ec_cmd_xfer(ec_dev, msg);
if (ret > 0) {
ec_dev->event_size = ret - 1;
- memcpy(&ec_dev->event_data, msg->data, ec_dev->event_size);
+ memcpy(&ec_dev->event_data, msg->data, ret);
}
return ret;
diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c
index 2da567540c2d..7c639006252e 100644
--- a/drivers/platform/goldfish/goldfish_pipe.c
+++ b/drivers/platform/goldfish/goldfish_pipe.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2012 Intel, Inc.
* Copyright (C) 2013 Intel, Inc.
@@ -46,7 +47,6 @@
* exchange is properly mapped during a transfer.
*/
-
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/interrupt.h>
@@ -59,10 +59,11 @@
#include <linux/bitops.h>
#include <linux/slab.h>
#include <linux/io.h>
-#include <linux/goldfish.h>
#include <linux/dma-mapping.h>
#include <linux/mm.h>
#include <linux/acpi.h>
+#include <linux/bug.h>
+#include "goldfish_pipe_qemu.h"
/*
* Update this when something changes in the driver's behavior so the host
@@ -73,71 +74,6 @@ enum {
PIPE_CURRENT_DEVICE_VERSION = 2
};
-/*
- * IMPORTANT: The following constants must match the ones used and defined
- * in external/qemu/hw/goldfish_pipe.c in the Android source tree.
- */
-
-/* List of bitflags returned in status of CMD_POLL command */
-enum PipePollFlags {
- PIPE_POLL_IN = 1 << 0,
- PIPE_POLL_OUT = 1 << 1,
- PIPE_POLL_HUP = 1 << 2
-};
-
-/* Possible status values used to signal errors - see goldfish_pipe_error_convert */
-enum PipeErrors {
- PIPE_ERROR_INVAL = -1,
- PIPE_ERROR_AGAIN = -2,
- PIPE_ERROR_NOMEM = -3,
- PIPE_ERROR_IO = -4
-};
-
-/* Bit-flags used to signal events from the emulator */
-enum PipeWakeFlags {
- PIPE_WAKE_CLOSED = 1 << 0, /* emulator closed pipe */
- PIPE_WAKE_READ = 1 << 1, /* pipe can now be read from */
- PIPE_WAKE_WRITE = 1 << 2 /* pipe can now be written to */
-};
-
-/* Bit flags for the 'flags' field */
-enum PipeFlagsBits {
- BIT_CLOSED_ON_HOST = 0, /* pipe closed by host */
- BIT_WAKE_ON_WRITE = 1, /* want to be woken on writes */
- BIT_WAKE_ON_READ = 2, /* want to be woken on reads */
-};
-
-enum PipeRegs {
- PIPE_REG_CMD = 0,
-
- PIPE_REG_SIGNAL_BUFFER_HIGH = 4,
- PIPE_REG_SIGNAL_BUFFER = 8,
- PIPE_REG_SIGNAL_BUFFER_COUNT = 12,
-
- PIPE_REG_OPEN_BUFFER_HIGH = 20,
- PIPE_REG_OPEN_BUFFER = 24,
-
- PIPE_REG_VERSION = 36,
-
- PIPE_REG_GET_SIGNALLED = 48,
-};
-
-enum PipeCmdCode {
- PIPE_CMD_OPEN = 1, /* to be used by the pipe device itself */
- PIPE_CMD_CLOSE,
- PIPE_CMD_POLL,
- PIPE_CMD_WRITE,
- PIPE_CMD_WAKE_ON_WRITE,
- PIPE_CMD_READ,
- PIPE_CMD_WAKE_ON_READ,
-
- /*
- * TODO(zyy): implement a deferred read/write execution to allow
- * parallel processing of pipe operations on the host.
- */
- PIPE_CMD_WAKE_ON_DONE_IO,
-};
-
enum {
MAX_BUFFERS_PER_COMMAND = 336,
MAX_SIGNALLED_PIPES = 64,
@@ -145,14 +81,12 @@ enum {
};
struct goldfish_pipe_dev;
-struct goldfish_pipe;
-struct goldfish_pipe_command;
/* A per-pipe command structure, shared with the host */
struct goldfish_pipe_command {
- s32 cmd; /* PipeCmdCode, guest -> host */
- s32 id; /* pipe id, guest -> host */
- s32 status; /* command execution status, host -> guest */
+ s32 cmd; /* PipeCmdCode, guest -> host */
+ s32 id; /* pipe id, guest -> host */
+ s32 status; /* command execution status, host -> guest */
s32 reserved; /* to pad to 64-bit boundary */
union {
/* Parameters for PIPE_CMD_{READ,WRITE} */
@@ -184,19 +118,21 @@ struct open_command_param {
/* Device-level set of buffers shared with the host */
struct goldfish_pipe_dev_buffers {
struct open_command_param open_command_params;
- struct signalled_pipe_buffer signalled_pipe_buffers[
- MAX_SIGNALLED_PIPES];
+ struct signalled_pipe_buffer
+ signalled_pipe_buffers[MAX_SIGNALLED_PIPES];
};
/* This data type models a given pipe instance */
struct goldfish_pipe {
/* pipe ID - index into goldfish_pipe_dev::pipes array */
u32 id;
+
/* The wake flags pipe is waiting for
* Note: not protected with any lock, uses atomic operations
* and barriers to make it thread-safe.
*/
unsigned long flags;
+
/* wake flags host have signalled,
* - protected by goldfish_pipe_dev::lock
*/
@@ -220,8 +156,12 @@ struct goldfish_pipe {
/* A wake queue for sleeping until host signals an event */
wait_queue_head_t wake_queue;
+
/* Pointer to the parent goldfish_pipe_dev instance */
struct goldfish_pipe_dev *dev;
+
+ /* A buffer of pages, too large to fit into a stack frame */
+ struct page *pages[MAX_BUFFERS_PER_COMMAND];
};
/* The global driver data. Holds a reference to the i/o page used to
@@ -229,6 +169,9 @@ struct goldfish_pipe {
* waiting to be awoken.
*/
struct goldfish_pipe_dev {
+ /* A magic number to check if this is an instance of this struct */
+ void *magic;
+
/*
* Global device spinlock. Protects the following members:
* - pipes, pipes_capacity
@@ -261,15 +204,22 @@ struct goldfish_pipe_dev {
/* Head of a doubly linked list of signalled pipes */
struct goldfish_pipe *first_signalled_pipe;
+ /* ptr to platform device's device struct */
+ struct device *pdev_dev;
+
/* Some device-specific data */
int irq;
int version;
unsigned char __iomem *base;
-};
-static struct goldfish_pipe_dev pipe_dev[1] = {};
+ /* an irq tasklet to run goldfish_interrupt_task */
+ struct tasklet_struct irq_tasklet;
-static int goldfish_cmd_locked(struct goldfish_pipe *pipe, enum PipeCmdCode cmd)
+ struct miscdevice miscdev;
+};
+
+static int goldfish_pipe_cmd_locked(struct goldfish_pipe *pipe,
+ enum PipeCmdCode cmd)
{
pipe->command_buffer->cmd = cmd;
/* failure by default */
@@ -278,13 +228,13 @@ static int goldfish_cmd_locked(struct goldfish_pipe *pipe, enum PipeCmdCode cmd)
return pipe->command_buffer->status;
}
-static int goldfish_cmd(struct goldfish_pipe *pipe, enum PipeCmdCode cmd)
+static int goldfish_pipe_cmd(struct goldfish_pipe *pipe, enum PipeCmdCode cmd)
{
int status;
if (mutex_lock_interruptible(&pipe->lock))
return PIPE_ERROR_IO;
- status = goldfish_cmd_locked(pipe, cmd);
+ status = goldfish_pipe_cmd_locked(pipe, cmd);
mutex_unlock(&pipe->lock);
return status;
}
@@ -307,10 +257,12 @@ static int goldfish_pipe_error_convert(int status)
}
}
-static int pin_user_pages(unsigned long first_page, unsigned long last_page,
- unsigned int last_page_size, int is_write,
- struct page *pages[MAX_BUFFERS_PER_COMMAND],
- unsigned int *iter_last_page_size)
+static int pin_user_pages(unsigned long first_page,
+ unsigned long last_page,
+ unsigned int last_page_size,
+ int is_write,
+ struct page *pages[MAX_BUFFERS_PER_COMMAND],
+ unsigned int *iter_last_page_size)
{
int ret;
int requested_pages = ((last_page - first_page) >> PAGE_SHIFT) + 1;
@@ -322,18 +274,18 @@ static int pin_user_pages(unsigned long first_page, unsigned long last_page,
*iter_last_page_size = last_page_size;
}
- ret = get_user_pages_fast(
- first_page, requested_pages, !is_write, pages);
+ ret = get_user_pages_fast(first_page, requested_pages, !is_write,
+ pages);
if (ret <= 0)
return -EFAULT;
if (ret < requested_pages)
*iter_last_page_size = PAGE_SIZE;
- return ret;
+ return ret;
}
static void release_user_pages(struct page **pages, int pages_count,
- int is_write, s32 consumed_size)
+ int is_write, s32 consumed_size)
{
int i;
@@ -345,12 +297,15 @@ static void release_user_pages(struct page **pages, int pages_count,
}
/* Populate the call parameters, merging adjacent pages together */
-static void populate_rw_params(
- struct page **pages, int pages_count,
- unsigned long address, unsigned long address_end,
- unsigned long first_page, unsigned long last_page,
- unsigned int iter_last_page_size, int is_write,
- struct goldfish_pipe_command *command)
+static void populate_rw_params(struct page **pages,
+ int pages_count,
+ unsigned long address,
+ unsigned long address_end,
+ unsigned long first_page,
+ unsigned long last_page,
+ unsigned int iter_last_page_size,
+ int is_write,
+ struct goldfish_pipe_command *command)
{
/*
* Process the first page separately - it's the only page that
@@ -382,55 +337,59 @@ static void populate_rw_params(
}
static int transfer_max_buffers(struct goldfish_pipe *pipe,
- unsigned long address, unsigned long address_end, int is_write,
- unsigned long last_page, unsigned int last_page_size,
- s32 *consumed_size, int *status)
+ unsigned long address,
+ unsigned long address_end,
+ int is_write,
+ unsigned long last_page,
+ unsigned int last_page_size,
+ s32 *consumed_size,
+ int *status)
{
- static struct page *pages[MAX_BUFFERS_PER_COMMAND];
unsigned long first_page = address & PAGE_MASK;
unsigned int iter_last_page_size;
- int pages_count = pin_user_pages(first_page, last_page,
- last_page_size, is_write,
- pages, &iter_last_page_size);
-
- if (pages_count < 0)
- return pages_count;
+ int pages_count;
/* Serialize access to the pipe command buffers */
if (mutex_lock_interruptible(&pipe->lock))
return -ERESTARTSYS;
- populate_rw_params(pages, pages_count, address, address_end,
- first_page, last_page, iter_last_page_size, is_write,
- pipe->command_buffer);
+ pages_count = pin_user_pages(first_page, last_page,
+ last_page_size, is_write,
+ pipe->pages, &iter_last_page_size);
+ if (pages_count < 0) {
+ mutex_unlock(&pipe->lock);
+ return pages_count;
+ }
+
+ populate_rw_params(pipe->pages, pages_count, address, address_end,
+ first_page, last_page, iter_last_page_size, is_write,
+ pipe->command_buffer);
/* Transfer the data */
- *status = goldfish_cmd_locked(pipe,
+ *status = goldfish_pipe_cmd_locked(pipe,
is_write ? PIPE_CMD_WRITE : PIPE_CMD_READ);
*consumed_size = pipe->command_buffer->rw_params.consumed_size;
- release_user_pages(pages, pages_count, is_write, *consumed_size);
+ release_user_pages(pipe->pages, pages_count, is_write, *consumed_size);
mutex_unlock(&pipe->lock);
-
return 0;
}
static int wait_for_host_signal(struct goldfish_pipe *pipe, int is_write)
{
- u32 wakeBit = is_write ? BIT_WAKE_ON_WRITE : BIT_WAKE_ON_READ;
+ u32 wake_bit = is_write ? BIT_WAKE_ON_WRITE : BIT_WAKE_ON_READ;
- set_bit(wakeBit, &pipe->flags);
+ set_bit(wake_bit, &pipe->flags);
/* Tell the emulator we're going to wait for a wake event */
- (void)goldfish_cmd(pipe,
+ goldfish_pipe_cmd(pipe,
is_write ? PIPE_CMD_WAKE_ON_WRITE : PIPE_CMD_WAKE_ON_READ);
- while (test_bit(wakeBit, &pipe->flags)) {
- if (wait_event_interruptible(
- pipe->wake_queue,
- !test_bit(wakeBit, &pipe->flags)))
+ while (test_bit(wake_bit, &pipe->flags)) {
+ if (wait_event_interruptible(pipe->wake_queue,
+ !test_bit(wake_bit, &pipe->flags)))
return -ERESTARTSYS;
if (test_bit(BIT_CLOSED_ON_HOST, &pipe->flags))
@@ -441,7 +400,9 @@ static int wait_for_host_signal(struct goldfish_pipe *pipe, int is_write)
}
static ssize_t goldfish_pipe_read_write(struct file *filp,
- char __user *buffer, size_t bufflen, int is_write)
+ char __user *buffer,
+ size_t bufflen,
+ int is_write)
{
struct goldfish_pipe *pipe = filp->private_data;
int count = 0, ret = -EINVAL;
@@ -456,7 +417,7 @@ static ssize_t goldfish_pipe_read_write(struct file *filp,
return 0;
/* Check the buffer range for access */
if (unlikely(!access_ok(is_write ? VERIFY_WRITE : VERIFY_READ,
- buffer, bufflen)))
+ buffer, bufflen)))
return -EFAULT;
address = (unsigned long)buffer;
@@ -469,8 +430,8 @@ static ssize_t goldfish_pipe_read_write(struct file *filp,
int status;
ret = transfer_max_buffers(pipe, address, address_end, is_write,
- last_page, last_page_size, &consumed_size,
- &status);
+ last_page, last_page_size,
+ &consumed_size, &status);
if (ret < 0)
break;
@@ -496,7 +457,8 @@ static ssize_t goldfish_pipe_read_write(struct file *filp,
* err.
*/
if (status != PIPE_ERROR_AGAIN)
- pr_info_ratelimited("goldfish_pipe: backend error %d on %s\n",
+ dev_err_ratelimited(pipe->dev->pdev_dev,
+ "backend error %d on %s\n",
status, is_write ? "write" : "read");
break;
}
@@ -522,19 +484,21 @@ static ssize_t goldfish_pipe_read_write(struct file *filp,
}
static ssize_t goldfish_pipe_read(struct file *filp, char __user *buffer,
- size_t bufflen, loff_t *ppos)
+ size_t bufflen, loff_t *ppos)
{
return goldfish_pipe_read_write(filp, buffer, bufflen,
- /* is_write */ 0);
+ /* is_write */ 0);
}
static ssize_t goldfish_pipe_write(struct file *filp,
- const char __user *buffer, size_t bufflen,
- loff_t *ppos)
+ const char __user *buffer, size_t bufflen,
+ loff_t *ppos)
{
- return goldfish_pipe_read_write(filp,
- /* cast away the const */(char __user *)buffer, bufflen,
- /* is_write */ 1);
+ /* cast away the const */
+ char __user *no_const_buffer = (char __user *)buffer;
+
+ return goldfish_pipe_read_write(filp, no_const_buffer, bufflen,
+ /* is_write */ 1);
}
static __poll_t goldfish_pipe_poll(struct file *filp, poll_table *wait)
@@ -545,7 +509,7 @@ static __poll_t goldfish_pipe_poll(struct file *filp, poll_table *wait)
poll_wait(filp, &pipe->wake_queue, wait);
- status = goldfish_cmd(pipe, PIPE_CMD_POLL);
+ status = goldfish_pipe_cmd(pipe, PIPE_CMD_POLL);
if (status < 0)
return -ERESTARTSYS;
@@ -562,7 +526,7 @@ static __poll_t goldfish_pipe_poll(struct file *filp, poll_table *wait)
}
static void signalled_pipes_add_locked(struct goldfish_pipe_dev *dev,
- u32 id, u32 flags)
+ u32 id, u32 flags)
{
struct goldfish_pipe *pipe;
@@ -574,8 +538,8 @@ static void signalled_pipes_add_locked(struct goldfish_pipe_dev *dev,
return;
pipe->signalled_flags |= flags;
- if (pipe->prev_signalled || pipe->next_signalled
- || dev->first_signalled_pipe == pipe)
+ if (pipe->prev_signalled || pipe->next_signalled ||
+ dev->first_signalled_pipe == pipe)
return; /* already in the list */
pipe->next_signalled = dev->first_signalled_pipe;
if (dev->first_signalled_pipe)
@@ -584,7 +548,8 @@ static void signalled_pipes_add_locked(struct goldfish_pipe_dev *dev,
}
static void signalled_pipes_remove_locked(struct goldfish_pipe_dev *dev,
- struct goldfish_pipe *pipe) {
+ struct goldfish_pipe *pipe)
+{
if (pipe->prev_signalled)
pipe->prev_signalled->next_signalled = pipe->next_signalled;
if (pipe->next_signalled)
@@ -623,10 +588,10 @@ static struct goldfish_pipe *signalled_pipes_pop_front(
return pipe;
}
-static void goldfish_interrupt_task(unsigned long unused)
+static void goldfish_interrupt_task(unsigned long dev_addr)
{
- struct goldfish_pipe_dev *dev = pipe_dev;
/* Iterate over the signalled pipes and wake them one by one */
+ struct goldfish_pipe_dev *dev = (struct goldfish_pipe_dev *)dev_addr;
struct goldfish_pipe *pipe;
int wakes;
@@ -646,7 +611,9 @@ static void goldfish_interrupt_task(unsigned long unused)
wake_up_interruptible(&pipe->wake_queue);
}
}
-static DECLARE_TASKLET(goldfish_interrupt_tasklet, goldfish_interrupt_task, 0);
+
+static void goldfish_pipe_device_deinit(struct platform_device *pdev,
+ struct goldfish_pipe_dev *dev);
/*
* The general idea of the interrupt handling:
@@ -668,7 +635,7 @@ static irqreturn_t goldfish_pipe_interrupt(int irq, void *dev_id)
unsigned long flags;
struct goldfish_pipe_dev *dev = dev_id;
- if (dev != pipe_dev)
+ if (dev->magic != &goldfish_pipe_device_deinit)
return IRQ_NONE;
/* Request the signalled pipes from the device */
@@ -689,7 +656,7 @@ static irqreturn_t goldfish_pipe_interrupt(int irq, void *dev_id)
spin_unlock_irqrestore(&dev->lock, flags);
- tasklet_schedule(&goldfish_interrupt_tasklet);
+ tasklet_schedule(&dev->irq_tasklet);
return IRQ_HANDLED;
}
@@ -702,7 +669,10 @@ static int get_free_pipe_id_locked(struct goldfish_pipe_dev *dev)
return id;
{
- /* Reallocate the array */
+ /* Reallocate the array.
+ * Since get_free_pipe_id_locked runs with interrupts disabled,
+ * we don't want to make calls that could lead to sleep.
+ */
u32 new_capacity = 2 * dev->pipes_capacity;
struct goldfish_pipe **pipes =
kcalloc(new_capacity, sizeof(*pipes), GFP_ATOMIC);
@@ -717,6 +687,14 @@ static int get_free_pipe_id_locked(struct goldfish_pipe_dev *dev)
return id;
}
+/* A helper function to get the instance of goldfish_pipe_dev from file */
+static struct goldfish_pipe_dev *to_goldfish_pipe_dev(struct file *file)
+{
+ struct miscdevice *miscdev = file->private_data;
+
+ return container_of(miscdev, struct goldfish_pipe_dev, miscdev);
+}
+
/**
* goldfish_pipe_open - open a channel to the AVD
* @inode: inode of device
@@ -730,14 +708,15 @@ static int get_free_pipe_id_locked(struct goldfish_pipe_dev *dev)
*/
static int goldfish_pipe_open(struct inode *inode, struct file *file)
{
- struct goldfish_pipe_dev *dev = pipe_dev;
+ struct goldfish_pipe_dev *dev = to_goldfish_pipe_dev(file);
unsigned long flags;
int id;
int status;
/* Allocate new pipe kernel object */
struct goldfish_pipe *pipe = kzalloc(sizeof(*pipe), GFP_KERNEL);
- if (pipe == NULL)
+
+ if (!pipe)
return -ENOMEM;
pipe->dev = dev;
@@ -748,6 +727,7 @@ static int goldfish_pipe_open(struct inode *inode, struct file *file)
* Command buffer needs to be allocated on its own page to make sure
* it is physically contiguous in host's address space.
*/
+ BUILD_BUG_ON(sizeof(struct goldfish_pipe_command) > PAGE_SIZE);
pipe->command_buffer =
(struct goldfish_pipe_command *)__get_free_page(GFP_KERNEL);
if (!pipe->command_buffer) {
@@ -772,7 +752,7 @@ static int goldfish_pipe_open(struct inode *inode, struct file *file)
MAX_BUFFERS_PER_COMMAND;
dev->buffers->open_command_params.command_buffer_ptr =
(u64)(unsigned long)__pa(pipe->command_buffer);
- status = goldfish_cmd_locked(pipe, PIPE_CMD_OPEN);
+ status = goldfish_pipe_cmd_locked(pipe, PIPE_CMD_OPEN);
spin_unlock_irqrestore(&dev->lock, flags);
if (status < 0)
goto err_cmd;
@@ -798,7 +778,7 @@ static int goldfish_pipe_release(struct inode *inode, struct file *filp)
struct goldfish_pipe_dev *dev = pipe->dev;
/* The guest is closing the channel, so tell the emulator right now */
- (void)goldfish_cmd(pipe, PIPE_CMD_CLOSE);
+ goldfish_pipe_cmd(pipe, PIPE_CMD_CLOSE);
spin_lock_irqsave(&dev->lock, flags);
dev->pipes[pipe->id] = NULL;
@@ -820,36 +800,55 @@ static const struct file_operations goldfish_pipe_fops = {
.release = goldfish_pipe_release,
};
-static struct miscdevice goldfish_pipe_dev = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = "goldfish_pipe",
- .fops = &goldfish_pipe_fops,
-};
+static void init_miscdevice(struct miscdevice *miscdev)
+{
+ memset(miscdev, 0, sizeof(*miscdev));
+
+ miscdev->minor = MISC_DYNAMIC_MINOR;
+ miscdev->name = "goldfish_pipe";
+ miscdev->fops = &goldfish_pipe_fops;
+}
+
+static void write_pa_addr(void *addr, void __iomem *portl, void __iomem *porth)
+{
+ const unsigned long paddr = __pa(addr);
+
+ writel(upper_32_bits(paddr), porth);
+ writel(lower_32_bits(paddr), portl);
+}
-static int goldfish_pipe_device_init(struct platform_device *pdev)
+static int goldfish_pipe_device_init(struct platform_device *pdev,
+ struct goldfish_pipe_dev *dev)
{
- char *page;
- struct goldfish_pipe_dev *dev = pipe_dev;
- int err = devm_request_irq(&pdev->dev, dev->irq,
- goldfish_pipe_interrupt,
- IRQF_SHARED, "goldfish_pipe", dev);
+ int err;
+
+ tasklet_init(&dev->irq_tasklet, &goldfish_interrupt_task,
+ (unsigned long)dev);
+
+ err = devm_request_irq(&pdev->dev, dev->irq,
+ goldfish_pipe_interrupt,
+ IRQF_SHARED, "goldfish_pipe", dev);
if (err) {
dev_err(&pdev->dev, "unable to allocate IRQ for v2\n");
return err;
}
- err = misc_register(&goldfish_pipe_dev);
+ init_miscdevice(&dev->miscdev);
+ err = misc_register(&dev->miscdev);
if (err) {
dev_err(&pdev->dev, "unable to register v2 device\n");
return err;
}
+ dev->pdev_dev = &pdev->dev;
dev->first_signalled_pipe = NULL;
dev->pipes_capacity = INITIAL_PIPES_CAPACITY;
dev->pipes = kcalloc(dev->pipes_capacity, sizeof(*dev->pipes),
- GFP_KERNEL);
- if (!dev->pipes)
+ GFP_KERNEL);
+ if (!dev->pipes) {
+ misc_deregister(&dev->miscdev);
return -ENOMEM;
+ }
/*
* We're going to pass two buffers, open_command_params and
@@ -857,75 +856,67 @@ static int goldfish_pipe_device_init(struct platform_device *pdev)
* needs to be contained in a single physical page. The easiest choice
* is to just allocate a page and place the buffers in it.
*/
- if (WARN_ON(sizeof(*dev->buffers) > PAGE_SIZE))
- return -ENOMEM;
-
- page = (char *)__get_free_page(GFP_KERNEL);
- if (!page) {
+ BUILD_BUG_ON(sizeof(struct goldfish_pipe_dev_buffers) > PAGE_SIZE);
+ dev->buffers = (struct goldfish_pipe_dev_buffers *)
+ __get_free_page(GFP_KERNEL);
+ if (!dev->buffers) {
kfree(dev->pipes);
+ misc_deregister(&dev->miscdev);
return -ENOMEM;
}
- dev->buffers = (struct goldfish_pipe_dev_buffers *)page;
/* Send the buffer addresses to the host */
- {
- u64 paddr = __pa(&dev->buffers->signalled_pipe_buffers);
-
- writel((u32)(unsigned long)(paddr >> 32),
- dev->base + PIPE_REG_SIGNAL_BUFFER_HIGH);
- writel((u32)(unsigned long)paddr,
- dev->base + PIPE_REG_SIGNAL_BUFFER);
- writel((u32)MAX_SIGNALLED_PIPES,
- dev->base + PIPE_REG_SIGNAL_BUFFER_COUNT);
-
- paddr = __pa(&dev->buffers->open_command_params);
- writel((u32)(unsigned long)(paddr >> 32),
- dev->base + PIPE_REG_OPEN_BUFFER_HIGH);
- writel((u32)(unsigned long)paddr,
- dev->base + PIPE_REG_OPEN_BUFFER);
- }
+ write_pa_addr(&dev->buffers->signalled_pipe_buffers,
+ dev->base + PIPE_REG_SIGNAL_BUFFER,
+ dev->base + PIPE_REG_SIGNAL_BUFFER_HIGH);
+
+ writel(MAX_SIGNALLED_PIPES,
+ dev->base + PIPE_REG_SIGNAL_BUFFER_COUNT);
+
+ write_pa_addr(&dev->buffers->open_command_params,
+ dev->base + PIPE_REG_OPEN_BUFFER,
+ dev->base + PIPE_REG_OPEN_BUFFER_HIGH);
+
+ platform_set_drvdata(pdev, dev);
return 0;
}
-static void goldfish_pipe_device_deinit(struct platform_device *pdev)
+static void goldfish_pipe_device_deinit(struct platform_device *pdev,
+ struct goldfish_pipe_dev *dev)
{
- struct goldfish_pipe_dev *dev = pipe_dev;
-
- misc_deregister(&goldfish_pipe_dev);
+ misc_deregister(&dev->miscdev);
+ tasklet_kill(&dev->irq_tasklet);
kfree(dev->pipes);
free_page((unsigned long)dev->buffers);
}
static int goldfish_pipe_probe(struct platform_device *pdev)
{
- int err;
struct resource *r;
- struct goldfish_pipe_dev *dev = pipe_dev;
+ struct goldfish_pipe_dev *dev;
- if (WARN_ON(sizeof(struct goldfish_pipe_command) > PAGE_SIZE))
+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev)
return -ENOMEM;
- /* not thread safe, but this should not happen */
- WARN_ON(dev->base != NULL);
-
+ dev->magic = &goldfish_pipe_device_deinit;
spin_lock_init(&dev->lock);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (r == NULL || resource_size(r) < PAGE_SIZE) {
+ if (!r || resource_size(r) < PAGE_SIZE) {
dev_err(&pdev->dev, "can't allocate i/o page\n");
return -EINVAL;
}
dev->base = devm_ioremap(&pdev->dev, r->start, PAGE_SIZE);
- if (dev->base == NULL) {
+ if (!dev->base) {
dev_err(&pdev->dev, "ioremap failed\n");
return -EINVAL;
}
r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (r == NULL) {
- err = -EINVAL;
- goto error;
- }
+ if (!r)
+ return -EINVAL;
+
dev->irq = r->start;
/*
@@ -935,25 +926,19 @@ static int goldfish_pipe_probe(struct platform_device *pdev)
* reading device version back: this allows the host implementation to
* detect the old driver (if there was no version write before read).
*/
- writel((u32)PIPE_DRIVER_VERSION, dev->base + PIPE_REG_VERSION);
+ writel(PIPE_DRIVER_VERSION, dev->base + PIPE_REG_VERSION);
dev->version = readl(dev->base + PIPE_REG_VERSION);
if (WARN_ON(dev->version < PIPE_CURRENT_DEVICE_VERSION))
return -EINVAL;
- err = goldfish_pipe_device_init(pdev);
- if (!err)
- return 0;
-
-error:
- dev->base = NULL;
- return err;
+ return goldfish_pipe_device_init(pdev, dev);
}
static int goldfish_pipe_remove(struct platform_device *pdev)
{
- struct goldfish_pipe_dev *dev = pipe_dev;
- goldfish_pipe_device_deinit(pdev);
- dev->base = NULL;
+ struct goldfish_pipe_dev *dev = platform_get_drvdata(pdev);
+
+ goldfish_pipe_device_deinit(pdev, dev);
return 0;
}
@@ -981,4 +966,4 @@ static struct platform_driver goldfish_pipe_driver = {
module_platform_driver(goldfish_pipe_driver);
MODULE_AUTHOR("David Turner <digit@google.com>");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/platform/goldfish/goldfish_pipe_qemu.h b/drivers/platform/goldfish/goldfish_pipe_qemu.h
new file mode 100644
index 000000000000..b4d78c108afd
--- /dev/null
+++ b/drivers/platform/goldfish/goldfish_pipe_qemu.h
@@ -0,0 +1,98 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * IMPORTANT: The following constants must match the ones used and defined in
+ * external/qemu/include/hw/misc/goldfish_pipe.h
+ */
+
+#ifndef GOLDFISH_PIPE_QEMU_H
+#define GOLDFISH_PIPE_QEMU_H
+
+/* List of bitflags returned in status of CMD_POLL command */
+enum PipePollFlags {
+ PIPE_POLL_IN = 1 << 0,
+ PIPE_POLL_OUT = 1 << 1,
+ PIPE_POLL_HUP = 1 << 2
+};
+
+/* Possible status values used to signal errors */
+enum PipeErrors {
+ PIPE_ERROR_INVAL = -1,
+ PIPE_ERROR_AGAIN = -2,
+ PIPE_ERROR_NOMEM = -3,
+ PIPE_ERROR_IO = -4
+};
+
+/* Bit-flags used to signal events from the emulator */
+enum PipeWakeFlags {
+ /* emulator closed pipe */
+ PIPE_WAKE_CLOSED = 1 << 0,
+
+ /* pipe can now be read from */
+ PIPE_WAKE_READ = 1 << 1,
+
+ /* pipe can now be written to */
+ PIPE_WAKE_WRITE = 1 << 2,
+
+ /* unlock this pipe's DMA buffer */
+ PIPE_WAKE_UNLOCK_DMA = 1 << 3,
+
+ /* unlock DMA buffer of the pipe shared to this pipe */
+ PIPE_WAKE_UNLOCK_DMA_SHARED = 1 << 4,
+};
+
+/* Possible pipe closing reasons */
+enum PipeCloseReason {
+ /* guest sent a close command */
+ PIPE_CLOSE_GRACEFUL = 0,
+
+ /* guest rebooted, we're closing the pipes */
+ PIPE_CLOSE_REBOOT = 1,
+
+ /* close old pipes on snapshot load */
+ PIPE_CLOSE_LOAD_SNAPSHOT = 2,
+
+ /* some unrecoverable error on the pipe */
+ PIPE_CLOSE_ERROR = 3,
+};
+
+/* Bit flags for the 'flags' field */
+enum PipeFlagsBits {
+ BIT_CLOSED_ON_HOST = 0, /* pipe closed by host */
+ BIT_WAKE_ON_WRITE = 1, /* want to be woken on writes */
+ BIT_WAKE_ON_READ = 2, /* want to be woken on reads */
+};
+
+enum PipeRegs {
+ PIPE_REG_CMD = 0,
+
+ PIPE_REG_SIGNAL_BUFFER_HIGH = 4,
+ PIPE_REG_SIGNAL_BUFFER = 8,
+ PIPE_REG_SIGNAL_BUFFER_COUNT = 12,
+
+ PIPE_REG_OPEN_BUFFER_HIGH = 20,
+ PIPE_REG_OPEN_BUFFER = 24,
+
+ PIPE_REG_VERSION = 36,
+
+ PIPE_REG_GET_SIGNALLED = 48,
+};
+
+enum PipeCmdCode {
+ /* to be used by the pipe device itself */
+ PIPE_CMD_OPEN = 1,
+
+ PIPE_CMD_CLOSE,
+ PIPE_CMD_POLL,
+ PIPE_CMD_WRITE,
+ PIPE_CMD_WAKE_ON_WRITE,
+ PIPE_CMD_READ,
+ PIPE_CMD_WAKE_ON_READ,
+
+ /*
+ * TODO(zyy): implement a deferred read/write execution to allow
+ * parallel processing of pipe operations on the host.
+ */
+ PIPE_CMD_WAKE_ON_DONE_IO,
+};
+
+#endif /* GOLDFISH_PIPE_QEMU_H */
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 0c1aa6c314f5..54f6a40c75c6 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -60,7 +60,10 @@ config ACERHDF
After loading this driver the BIOS is still in control of the fan.
To let the kernel handle the fan, do:
- echo -n enabled > /sys/class/thermal/thermal_zone0/mode
+ echo -n enabled > /sys/class/thermal/thermal_zoneN/mode
+ where N=0,1,2... depending on the number of thermal nodes and the
+ detection order of your particular system. The "type" parameter
+ in the same node directory will tell you if it is "acerhdf".
For more information about this driver see
<http://piie.net/files/acerhdf_README.txt>
@@ -105,6 +108,22 @@ config ASUS_LAPTOP
If you have an ACPI-compatible ASUS laptop, say Y or M here.
+config DCDBAS
+ tristate "Dell Systems Management Base Driver"
+ depends on X86
+ help
+ The Dell Systems Management Base Driver provides a sysfs interface
+ for systems management software to perform System Management
+ Interrupts (SMIs) and Host Control Actions (system power cycle or
+ power off after OS shutdown) on certain Dell systems.
+
+ See <file:Documentation/dcdbas.txt> for more details on the driver
+ and the Dell systems on which Dell systems management software makes
+ use of this driver.
+
+ Say Y or M here to enable the driver for use by Dell systems
+ management software such as Dell OpenManage.
+
#
# The DELL_SMBIOS driver depends on ACPI_WMI and/or DCDBAS if those
# backends are selected. The "depends" line prevents a configuration
@@ -227,6 +246,18 @@ config DELL_RBTN
To compile this driver as a module, choose M here: the module will
be called dell-rbtn.
+config DELL_RBU
+ tristate "BIOS update support for DELL systems via sysfs"
+ depends on X86
+ select FW_LOADER
+ select FW_LOADER_USER_HELPER
+ help
+ Say m if you want to have the option of updating the BIOS for your
+ DELL system. Note you need a Dell OpenManage or Dell Update package (DUP)
+ supporting application to communicate with the BIOS regarding the new
+ image for the image update to take effect.
+ See <file:Documentation/dell_rbu.txt> for more details on the driver.
+
config FUJITSU_LAPTOP
tristate "Fujitsu Laptop Extras"
@@ -336,6 +367,20 @@ config HP_WMI
To compile this driver as a module, choose M here: the module will
be called hp-wmi.
+config LG_LAPTOP
+ tristate "LG Laptop Extras"
+ depends on ACPI
+ depends on ACPI_WMI
+ depends on INPUT
+ select INPUT_SPARSEKMAP
+ select LEDS_CLASS
+ help
+ This driver adds support for hotkeys as well as control of keyboard
+ backlight, battery maximum charge level and various other ACPI
+ features.
+
+ If you have an LG Gram laptop, say Y or M here.
+
config MSI_LAPTOP
tristate "MSI Laptop Extras"
depends on ACPI
@@ -867,6 +912,8 @@ 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.
@@ -1229,6 +1276,18 @@ config I2C_MULTI_INSTANTIATE
To compile this driver as a module, choose M here: the module
will be called i2c-multi-instantiate.
+config INTEL_ATOMISP2_PM
+ tristate "Intel AtomISP2 dummy / power-management driver"
+ depends on PCI && IOSF_MBI && PM
+ help
+ Power-management driver for Intel's Image Signal Processor found on
+ Bay and Cherry Trail devices. This dummy driver's sole purpose is to
+ turn the ISP off (put it in D3) to save power and to allow entering
+ of S0ix modes.
+
+ To compile this driver as a module, choose M here: the module
+ will be called intel_atomisp2_pm.
+
endif # X86_PLATFORM_DEVICES
config PMC_ATOM
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index e6d1becf81ce..39ae94135406 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -9,9 +9,11 @@ obj-$(CONFIG_ASUS_NB_WMI) += asus-nb-wmi.o
obj-$(CONFIG_ASUS_WIRELESS) += asus-wireless.o
obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o
obj-$(CONFIG_EEEPC_WMI) += eeepc-wmi.o
+obj-$(CONFIG_LG_LAPTOP) += lg-laptop.o
obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
obj-$(CONFIG_ACPI_CMPC) += classmate-laptop.o
obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o
+obj-$(CONFIG_DCDBAS) += dcdbas.o
obj-$(CONFIG_DELL_SMBIOS) += dell-smbios.o
dell-smbios-objs := dell-smbios-base.o
dell-smbios-$(CONFIG_DELL_SMBIOS_WMI) += dell-smbios-wmi.o
@@ -23,6 +25,7 @@ obj-$(CONFIG_DELL_WMI_AIO) += dell-wmi-aio.o
obj-$(CONFIG_DELL_WMI_LED) += dell-wmi-led.o
obj-$(CONFIG_DELL_SMO8800) += dell-smo8800.o
obj-$(CONFIG_DELL_RBTN) += dell-rbtn.o
+obj-$(CONFIG_DELL_RBU) += dell_rbu.o
obj-$(CONFIG_ACER_WMI) += acer-wmi.o
obj-$(CONFIG_ACER_WIRELESS) += acer-wireless.o
obj-$(CONFIG_ACERHDF) += acerhdf.o
@@ -92,3 +95,4 @@ obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o
obj-$(CONFIG_INTEL_TURBO_MAX_3) += intel_turbo_max_3.o
obj-$(CONFIG_INTEL_CHTDC_TI_PWRBTN) += intel_chtdc_ti_pwrbtn.o
obj-$(CONFIG_I2C_MULTI_INSTANTIATE) += i2c-multi-instantiate.o
+obj-$(CONFIG_INTEL_ATOMISP2_PM) += intel_atomisp2_pm.o
diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
index ea22591ee66f..505224225378 100644
--- a/drivers/platform/x86/acerhdf.c
+++ b/drivers/platform/x86/acerhdf.c
@@ -86,6 +86,7 @@ static unsigned int interval = 10;
static unsigned int fanon = 60000;
static unsigned int fanoff = 53000;
static unsigned int verbose;
+static unsigned int list_supported;
static unsigned int fanstate = ACERHDF_FAN_AUTO;
static char force_bios[16];
static char force_product[16];
@@ -104,10 +105,12 @@ module_param(fanoff, uint, 0600);
MODULE_PARM_DESC(fanoff, "Turn the fan off below this temperature");
module_param(verbose, uint, 0600);
MODULE_PARM_DESC(verbose, "Enable verbose dmesg output");
+module_param(list_supported, uint, 0600);
+MODULE_PARM_DESC(list_supported, "List supported models and BIOS versions");
module_param_string(force_bios, force_bios, 16, 0);
-MODULE_PARM_DESC(force_bios, "Force BIOS version and omit BIOS check");
+MODULE_PARM_DESC(force_bios, "Pretend system has this known supported BIOS version");
module_param_string(force_product, force_product, 16, 0);
-MODULE_PARM_DESC(force_product, "Force BIOS product and omit BIOS check");
+MODULE_PARM_DESC(force_product, "Pretend system is this known supported model");
/*
* cmd_off: to switch the fan completely off and check if the fan is off
@@ -130,7 +133,7 @@ static const struct manualcmd mcmd = {
.moff = 0xff,
};
-/* BIOS settings */
+/* BIOS settings - only used during probe */
struct bios_settings {
const char *vendor;
const char *product;
@@ -141,8 +144,18 @@ struct bios_settings {
int mcmd_enable;
};
+/* This could be a daughter struct in the above, but not worth the redirect */
+struct ctrl_settings {
+ u8 fanreg;
+ u8 tempreg;
+ struct fancmd cmd;
+ int mcmd_enable;
+};
+
+static struct ctrl_settings ctrl_cfg __read_mostly;
+
/* Register addresses and values for different BIOS versions */
-static const struct bios_settings bios_tbl[] = {
+static const struct bios_settings bios_tbl[] __initconst = {
/* AOA110 */
{"Acer", "AOA110", "v0.3109", 0x55, 0x58, {0x1f, 0x00}, 0},
{"Acer", "AOA110", "v0.3114", 0x55, 0x58, {0x1f, 0x00}, 0},
@@ -233,6 +246,7 @@ static const struct bios_settings bios_tbl[] = {
{"Gateway", "LT31", "v1.3201", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Gateway", "LT31", "v1.3302", 0x55, 0x58, {0x9e, 0x00}, 0},
{"Gateway", "LT31", "v1.3303t", 0x55, 0x58, {0x9e, 0x00}, 0},
+ {"Gateway", "LT31", "v1.3307", 0x55, 0x58, {0x9e, 0x00}, 0},
/* Packard Bell */
{"Packard Bell", "DOA150", "v0.3104", 0x55, 0x58, {0x21, 0x00}, 0},
{"Packard Bell", "DOA150", "v0.3105", 0x55, 0x58, {0x20, 0x00}, 0},
@@ -256,8 +270,6 @@ static const struct bios_settings bios_tbl[] = {
{"", "", "", 0, 0, {0, 0}, 0}
};
-static const struct bios_settings *bios_cfg __read_mostly;
-
/*
* this struct is used to instruct thermal layer to use bang_bang instead of
* default governor for acerhdf
@@ -270,7 +282,7 @@ static int acerhdf_get_temp(int *temp)
{
u8 read_temp;
- if (ec_read(bios_cfg->tempreg, &read_temp))
+ if (ec_read(ctrl_cfg.tempreg, &read_temp))
return -EINVAL;
*temp = read_temp * 1000;
@@ -282,10 +294,10 @@ static int acerhdf_get_fanstate(int *state)
{
u8 fan;
- if (ec_read(bios_cfg->fanreg, &fan))
+ if (ec_read(ctrl_cfg.fanreg, &fan))
return -EINVAL;
- if (fan != bios_cfg->cmd.cmd_off)
+ if (fan != ctrl_cfg.cmd.cmd_off)
*state = ACERHDF_FAN_AUTO;
else
*state = ACERHDF_FAN_OFF;
@@ -306,13 +318,13 @@ static void acerhdf_change_fanstate(int state)
state = ACERHDF_FAN_AUTO;
}
- cmd = (state == ACERHDF_FAN_OFF) ? bios_cfg->cmd.cmd_off
- : bios_cfg->cmd.cmd_auto;
+ cmd = (state == ACERHDF_FAN_OFF) ? ctrl_cfg.cmd.cmd_off
+ : ctrl_cfg.cmd.cmd_auto;
fanstate = state;
- ec_write(bios_cfg->fanreg, cmd);
+ ec_write(ctrl_cfg.fanreg, cmd);
- if (bios_cfg->mcmd_enable && state == ACERHDF_FAN_OFF) {
+ if (ctrl_cfg.mcmd_enable && state == ACERHDF_FAN_OFF) {
if (verbose)
pr_notice("turning off fan manually\n");
ec_write(mcmd.mreg, mcmd.moff);
@@ -615,10 +627,11 @@ static int str_starts_with(const char *str, const char *start)
}
/* check hardware */
-static int acerhdf_check_hardware(void)
+static int __init acerhdf_check_hardware(void)
{
char const *vendor, *version, *product;
const struct bios_settings *bt = NULL;
+ int found = 0;
/* get BIOS data */
vendor = dmi_get_system_info(DMI_SYS_VENDOR);
@@ -632,6 +645,17 @@ static int acerhdf_check_hardware(void)
pr_info("Acer Aspire One Fan driver, v.%s\n", DRV_VER);
+ if (list_supported) {
+ pr_info("List of supported Manufacturer/Model/BIOS:\n");
+ pr_info("---------------------------------------------------\n");
+ for (bt = bios_tbl; bt->vendor[0]; bt++) {
+ pr_info("%-13s | %-17s | %-10s\n", bt->vendor,
+ bt->product, bt->version);
+ }
+ pr_info("---------------------------------------------------\n");
+ return -ECANCELED;
+ }
+
if (force_bios[0]) {
version = force_bios;
pr_info("forcing BIOS version: %s\n", version);
@@ -657,30 +681,36 @@ static int acerhdf_check_hardware(void)
if (str_starts_with(vendor, bt->vendor) &&
str_starts_with(product, bt->product) &&
str_starts_with(version, bt->version)) {
- bios_cfg = bt;
+ found = 1;
break;
}
}
- if (!bios_cfg) {
+ if (!found) {
pr_err("unknown (unsupported) BIOS version %s/%s/%s, please report, aborting!\n",
vendor, product, version);
return -EINVAL;
}
+ /* Copy control settings from BIOS table before we free it. */
+ ctrl_cfg.fanreg = bt->fanreg;
+ ctrl_cfg.tempreg = bt->tempreg;
+ memcpy(&ctrl_cfg.cmd, &bt->cmd, sizeof(struct fancmd));
+ ctrl_cfg.mcmd_enable = bt->mcmd_enable;
+
/*
* if started with kernel mode off, prevent the kernel from switching
* off the fan
*/
if (!kernelmode) {
pr_notice("Fan control off, to enable do:\n");
- pr_notice("echo -n \"enabled\" > /sys/class/thermal/thermal_zone0/mode\n");
+ pr_notice("echo -n \"enabled\" > /sys/class/thermal/thermal_zoneN/mode # N=0,1,2...\n");
}
return 0;
}
-static int acerhdf_register_platform(void)
+static int __init acerhdf_register_platform(void)
{
int err = 0;
@@ -712,7 +742,7 @@ static void acerhdf_unregister_platform(void)
platform_driver_unregister(&acerhdf_driver);
}
-static int acerhdf_register_thermal(void)
+static int __init acerhdf_register_thermal(void)
{
cl_dev = thermal_cooling_device_register("acerhdf-fan", NULL,
&acerhdf_cooling_ops);
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index 2d6e272315a8..c285a16675ee 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -43,6 +43,7 @@
#include <linux/hwmon-sysfs.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
+#include <linux/platform_data/x86/asus-wmi.h>
#include <linux/platform_device.h>
#include <linux/thermal.h>
#include <linux/acpi.h>
@@ -69,89 +70,6 @@ MODULE_LICENSE("GPL");
#define NOTIFY_KBD_BRTDWN 0xc5
#define NOTIFY_KBD_BRTTOGGLE 0xc7
-/* WMI Methods */
-#define ASUS_WMI_METHODID_SPEC 0x43455053 /* BIOS SPECification */
-#define ASUS_WMI_METHODID_SFBD 0x44424653 /* Set First Boot Device */
-#define ASUS_WMI_METHODID_GLCD 0x44434C47 /* Get LCD status */
-#define ASUS_WMI_METHODID_GPID 0x44495047 /* Get Panel ID?? (Resol) */
-#define ASUS_WMI_METHODID_QMOD 0x444F4D51 /* Quiet MODe */
-#define ASUS_WMI_METHODID_SPLV 0x4C425053 /* Set Panel Light Value */
-#define ASUS_WMI_METHODID_AGFN 0x4E464741 /* FaN? */
-#define ASUS_WMI_METHODID_SFUN 0x4E554653 /* FUNCtionalities */
-#define ASUS_WMI_METHODID_SDSP 0x50534453 /* Set DiSPlay output */
-#define ASUS_WMI_METHODID_GDSP 0x50534447 /* Get DiSPlay output */
-#define ASUS_WMI_METHODID_DEVP 0x50564544 /* DEVice Policy */
-#define ASUS_WMI_METHODID_OSVR 0x5256534F /* OS VeRsion */
-#define ASUS_WMI_METHODID_DSTS 0x53544344 /* Device STatuS */
-#define ASUS_WMI_METHODID_DSTS2 0x53545344 /* Device STatuS #2*/
-#define ASUS_WMI_METHODID_BSTS 0x53545342 /* Bios STatuS ? */
-#define ASUS_WMI_METHODID_DEVS 0x53564544 /* DEVice Set */
-#define ASUS_WMI_METHODID_CFVS 0x53564643 /* CPU Frequency Volt Set */
-#define ASUS_WMI_METHODID_KBFT 0x5446424B /* KeyBoard FilTer */
-#define ASUS_WMI_METHODID_INIT 0x54494E49 /* INITialize */
-#define ASUS_WMI_METHODID_HKEY 0x59454B48 /* Hot KEY ?? */
-
-#define ASUS_WMI_UNSUPPORTED_METHOD 0xFFFFFFFE
-
-/* Wireless */
-#define ASUS_WMI_DEVID_HW_SWITCH 0x00010001
-#define ASUS_WMI_DEVID_WIRELESS_LED 0x00010002
-#define ASUS_WMI_DEVID_CWAP 0x00010003
-#define ASUS_WMI_DEVID_WLAN 0x00010011
-#define ASUS_WMI_DEVID_WLAN_LED 0x00010012
-#define ASUS_WMI_DEVID_BLUETOOTH 0x00010013
-#define ASUS_WMI_DEVID_GPS 0x00010015
-#define ASUS_WMI_DEVID_WIMAX 0x00010017
-#define ASUS_WMI_DEVID_WWAN3G 0x00010019
-#define ASUS_WMI_DEVID_UWB 0x00010021
-
-/* Leds */
-/* 0x000200XX and 0x000400XX */
-#define ASUS_WMI_DEVID_LED1 0x00020011
-#define ASUS_WMI_DEVID_LED2 0x00020012
-#define ASUS_WMI_DEVID_LED3 0x00020013
-#define ASUS_WMI_DEVID_LED4 0x00020014
-#define ASUS_WMI_DEVID_LED5 0x00020015
-#define ASUS_WMI_DEVID_LED6 0x00020016
-
-/* Backlight and Brightness */
-#define ASUS_WMI_DEVID_ALS_ENABLE 0x00050001 /* Ambient Light Sensor */
-#define ASUS_WMI_DEVID_BACKLIGHT 0x00050011
-#define ASUS_WMI_DEVID_BRIGHTNESS 0x00050012
-#define ASUS_WMI_DEVID_KBD_BACKLIGHT 0x00050021
-#define ASUS_WMI_DEVID_LIGHT_SENSOR 0x00050022 /* ?? */
-#define ASUS_WMI_DEVID_LIGHTBAR 0x00050025
-
-/* Misc */
-#define ASUS_WMI_DEVID_CAMERA 0x00060013
-
-/* Storage */
-#define ASUS_WMI_DEVID_CARDREADER 0x00080013
-
-/* Input */
-#define ASUS_WMI_DEVID_TOUCHPAD 0x00100011
-#define ASUS_WMI_DEVID_TOUCHPAD_LED 0x00100012
-
-/* Fan, Thermal */
-#define ASUS_WMI_DEVID_THERMAL_CTRL 0x00110011
-#define ASUS_WMI_DEVID_FAN_CTRL 0x00110012
-
-/* Power */
-#define ASUS_WMI_DEVID_PROCESSOR_STATE 0x00120012
-
-/* Deep S3 / Resume on LID open */
-#define ASUS_WMI_DEVID_LID_RESUME 0x00120031
-
-/* DSTS masks */
-#define ASUS_WMI_DSTS_STATUS_BIT 0x00000001
-#define ASUS_WMI_DSTS_UNKNOWN_BIT 0x00000002
-#define ASUS_WMI_DSTS_PRESENCE_BIT 0x00010000
-#define ASUS_WMI_DSTS_USER_BIT 0x00020000
-#define ASUS_WMI_DSTS_BIOS_BIT 0x00040000
-#define ASUS_WMI_DSTS_BRIGHTNESS_MASK 0x000000FF
-#define ASUS_WMI_DSTS_MAX_BRIGTH_MASK 0x0000FF00
-#define ASUS_WMI_DSTS_LIGHTBAR_MASK 0x0000000F
-
#define ASUS_FAN_DESC "cpu_fan"
#define ASUS_FAN_MFUN 0x13
#define ASUS_FAN_SFUN_READ 0x06
@@ -239,7 +157,6 @@ struct asus_wmi {
int lightbar_led_wk;
struct workqueue_struct *led_workqueue;
struct work_struct tpd_led_work;
- struct work_struct kbd_led_work;
struct work_struct wlan_led_work;
struct work_struct lightbar_led_work;
@@ -254,7 +171,7 @@ struct asus_wmi {
int asus_hwmon_num_fans;
int asus_hwmon_pwm;
- struct hotplug_slot *hotplug_slot;
+ struct hotplug_slot hotplug_slot;
struct mutex hotplug_lock;
struct mutex wmi_lock;
struct workqueue_struct *hotplug_workqueue;
@@ -302,8 +219,7 @@ static void asus_wmi_input_exit(struct asus_wmi *asus)
asus->inputdev = NULL;
}
-static int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1,
- u32 *retval)
+int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, u32 *retval)
{
struct bios_args args = {
.arg0 = arg0,
@@ -339,6 +255,7 @@ exit:
return 0;
}
+EXPORT_SYMBOL_GPL(asus_wmi_evaluate_method);
static int asus_wmi_evaluate_method_agfn(const struct acpi_buffer args)
{
@@ -456,12 +373,9 @@ static enum led_brightness tpd_led_get(struct led_classdev *led_cdev)
return read_tpd_led_state(asus);
}
-static void kbd_led_update(struct work_struct *work)
+static void kbd_led_update(struct asus_wmi *asus)
{
int ctrl_param = 0;
- struct asus_wmi *asus;
-
- asus = container_of(work, struct asus_wmi, kbd_led_work);
/*
* bits 0-2: level
@@ -471,7 +385,6 @@ static void kbd_led_update(struct work_struct *work)
ctrl_param = 0x80 | (asus->kbd_led_wk & 0x7F);
asus_wmi_set_devstate(ASUS_WMI_DEVID_KBD_BACKLIGHT, ctrl_param, NULL);
- led_classdev_notify_brightness_hw_changed(&asus->kbd_led, asus->kbd_led_wk);
}
static int kbd_led_read(struct asus_wmi *asus, int *level, int *env)
@@ -516,7 +429,7 @@ static void do_kbd_led_set(struct led_classdev *led_cdev, int value)
value = 0;
asus->kbd_led_wk = value;
- queue_work(asus->led_workqueue, &asus->kbd_led_work);
+ kbd_led_update(asus);
}
static void kbd_led_set(struct led_classdev *led_cdev,
@@ -525,6 +438,14 @@ static void kbd_led_set(struct led_classdev *led_cdev,
do_kbd_led_set(led_cdev, value);
}
+static void kbd_led_set_by_kbd(struct asus_wmi *asus, enum led_brightness value)
+{
+ struct led_classdev *led_cdev = &asus->kbd_led;
+
+ do_kbd_led_set(led_cdev, value);
+ led_classdev_notify_brightness_hw_changed(led_cdev, asus->kbd_led_wk);
+}
+
static enum led_brightness kbd_led_get(struct led_classdev *led_cdev)
{
struct asus_wmi *asus;
@@ -671,8 +592,6 @@ static int asus_wmi_led_init(struct asus_wmi *asus)
led_val = kbd_led_read(asus, NULL, NULL);
if (led_val >= 0) {
- INIT_WORK(&asus->kbd_led_work, kbd_led_update);
-
asus->kbd_led_wk = led_val;
asus->kbd_led.name = "asus::kbd_backlight";
asus->kbd_led.flags = LED_BRIGHT_HW_CHANGED;
@@ -753,7 +672,7 @@ static void asus_rfkill_hotplug(struct asus_wmi *asus)
if (asus->wlan.rfkill)
rfkill_set_sw_state(asus->wlan.rfkill, blocked);
- if (asus->hotplug_slot) {
+ if (asus->hotplug_slot.ops) {
bus = pci_find_bus(0, 1);
if (!bus) {
pr_warn("Unable to find PCI bus 1?\n");
@@ -858,7 +777,8 @@ static void asus_unregister_rfkill_notifier(struct asus_wmi *asus, char *node)
static int asus_get_adapter_status(struct hotplug_slot *hotplug_slot,
u8 *value)
{
- struct asus_wmi *asus = hotplug_slot->private;
+ struct asus_wmi *asus = container_of(hotplug_slot,
+ struct asus_wmi, hotplug_slot);
int result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WLAN);
if (result < 0)
@@ -868,8 +788,7 @@ static int asus_get_adapter_status(struct hotplug_slot *hotplug_slot,
return 0;
}
-static struct hotplug_slot_ops asus_hotplug_slot_ops = {
- .owner = THIS_MODULE,
+static const struct hotplug_slot_ops asus_hotplug_slot_ops = {
.get_adapter_status = asus_get_adapter_status,
.get_power_status = asus_get_adapter_status,
};
@@ -899,21 +818,9 @@ static int asus_setup_pci_hotplug(struct asus_wmi *asus)
INIT_WORK(&asus->hotplug_work, asus_hotplug_work);
- asus->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL);
- if (!asus->hotplug_slot)
- goto error_slot;
+ asus->hotplug_slot.ops = &asus_hotplug_slot_ops;
- asus->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info),
- GFP_KERNEL);
- if (!asus->hotplug_slot->info)
- goto error_info;
-
- asus->hotplug_slot->private = asus;
- asus->hotplug_slot->ops = &asus_hotplug_slot_ops;
- asus_get_adapter_status(asus->hotplug_slot,
- &asus->hotplug_slot->info->adapter_status);
-
- ret = pci_hp_register(asus->hotplug_slot, bus, 0, "asus-wifi");
+ ret = pci_hp_register(&asus->hotplug_slot, bus, 0, "asus-wifi");
if (ret) {
pr_err("Unable to register hotplug slot - %d\n", ret);
goto error_register;
@@ -922,11 +829,7 @@ static int asus_setup_pci_hotplug(struct asus_wmi *asus)
return 0;
error_register:
- kfree(asus->hotplug_slot->info);
-error_info:
- kfree(asus->hotplug_slot);
- asus->hotplug_slot = NULL;
-error_slot:
+ asus->hotplug_slot.ops = NULL;
destroy_workqueue(asus->hotplug_workqueue);
error_workqueue:
return ret;
@@ -1054,11 +957,8 @@ static void asus_wmi_rfkill_exit(struct asus_wmi *asus)
* asus_unregister_rfkill_notifier()
*/
asus_rfkill_hotplug(asus);
- if (asus->hotplug_slot) {
- pci_hp_deregister(asus->hotplug_slot);
- kfree(asus->hotplug_slot->info);
- kfree(asus->hotplug_slot);
- }
+ if (asus->hotplug_slot.ops)
+ pci_hp_deregister(&asus->hotplug_slot);
if (asus->hotplug_workqueue)
destroy_workqueue(asus->hotplug_workqueue);
@@ -1765,18 +1665,18 @@ static void asus_wmi_notify(u32 value, void *context)
}
if (code == NOTIFY_KBD_BRTUP) {
- do_kbd_led_set(&asus->kbd_led, asus->kbd_led_wk + 1);
+ kbd_led_set_by_kbd(asus, asus->kbd_led_wk + 1);
goto exit;
}
if (code == NOTIFY_KBD_BRTDWN) {
- do_kbd_led_set(&asus->kbd_led, asus->kbd_led_wk - 1);
+ kbd_led_set_by_kbd(asus, asus->kbd_led_wk - 1);
goto exit;
}
if (code == NOTIFY_KBD_BRTTOGGLE) {
if (asus->kbd_led_wk == asus->kbd_led.max_brightness)
- do_kbd_led_set(&asus->kbd_led, 0);
+ kbd_led_set_by_kbd(asus, 0);
else
- do_kbd_led_set(&asus->kbd_led, asus->kbd_led_wk + 1);
+ kbd_led_set_by_kbd(asus, asus->kbd_led_wk + 1);
goto exit;
}
@@ -2310,7 +2210,7 @@ static int asus_hotk_resume(struct device *device)
struct asus_wmi *asus = dev_get_drvdata(device);
if (!IS_ERR_OR_NULL(asus->kbd_led.dev))
- queue_work(asus->led_workqueue, &asus->kbd_led_work);
+ kbd_led_update(asus);
return 0;
}
@@ -2346,7 +2246,7 @@ static int asus_hotk_restore(struct device *device)
rfkill_set_sw_state(asus->uwb.rfkill, bl);
}
if (!IS_ERR_OR_NULL(asus->kbd_led.dev))
- queue_work(asus->led_workqueue, &asus->kbd_led_work);
+ kbd_led_update(asus);
return 0;
}
diff --git a/drivers/firmware/dcdbas.c b/drivers/platform/x86/dcdbas.c
index 0bdea60c65dd..88bd7efafe14 100644
--- a/drivers/firmware/dcdbas.c
+++ b/drivers/platform/x86/dcdbas.c
@@ -21,11 +21,13 @@
*/
#include <linux/platform_device.h>
+#include <linux/acpi.h>
#include <linux/dma-mapping.h>
#include <linux/errno.h>
#include <linux/cpu.h>
#include <linux/gfp.h>
#include <linux/init.h>
+#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/mc146818rtc.h>
#include <linux/module.h>
@@ -36,12 +38,11 @@
#include <linux/string.h>
#include <linux/types.h>
#include <linux/mutex.h>
-#include <asm/io.h>
#include "dcdbas.h"
#define DRIVER_NAME "dcdbas"
-#define DRIVER_VERSION "5.6.0-3.2"
+#define DRIVER_VERSION "5.6.0-3.3"
#define DRIVER_DESCRIPTION "Dell Systems Management Base Driver"
static struct platform_device *dcdbas_pdev;
@@ -49,19 +50,23 @@ static struct platform_device *dcdbas_pdev;
static u8 *smi_data_buf;
static dma_addr_t smi_data_buf_handle;
static unsigned long smi_data_buf_size;
+static unsigned long max_smi_data_buf_size = MAX_SMI_DATA_BUF_SIZE;
static u32 smi_data_buf_phys_addr;
static DEFINE_MUTEX(smi_data_lock);
+static u8 *eps_buffer;
static unsigned int host_control_action;
static unsigned int host_control_smi_type;
static unsigned int host_control_on_shutdown;
+static bool wsmt_enabled;
+
/**
* smi_data_buf_free: free SMI data buffer
*/
static void smi_data_buf_free(void)
{
- if (!smi_data_buf)
+ if (!smi_data_buf || wsmt_enabled)
return;
dev_dbg(&dcdbas_pdev->dev, "%s: phys: %x size: %lu\n",
@@ -86,7 +91,7 @@ static int smi_data_buf_realloc(unsigned long size)
if (smi_data_buf_size >= size)
return 0;
- if (size > MAX_SMI_DATA_BUF_SIZE)
+ if (size > max_smi_data_buf_size)
return -EINVAL;
/* new buffer is needed */
@@ -169,7 +174,7 @@ static ssize_t smi_data_write(struct file *filp, struct kobject *kobj,
{
ssize_t ret;
- if ((pos + count) > MAX_SMI_DATA_BUF_SIZE)
+ if ((pos + count) > max_smi_data_buf_size)
return -EINVAL;
mutex_lock(&smi_data_lock);
@@ -322,8 +327,20 @@ static ssize_t smi_request_store(struct device *dev,
ret = count;
break;
case 1:
- /* Calling Interface SMI */
- smi_cmd->ebx = (u32) virt_to_phys(smi_cmd->command_buffer);
+ /*
+ * Calling Interface SMI
+ *
+ * Provide physical address of command buffer field within
+ * the struct smi_cmd to BIOS.
+ *
+ * Because the address that smi_cmd (smi_data_buf) points to
+ * will be from memremap() of a non-memory address if WSMT
+ * is present, we can't use virt_to_phys() on smi_cmd, so
+ * we have to use the physical address that was saved when
+ * the virtual address for smi_cmd was received.
+ */
+ smi_cmd->ebx = smi_data_buf_phys_addr +
+ offsetof(struct smi_cmd, command_buffer);
ret = dcdbas_smi_request(smi_cmd);
if (!ret)
ret = count;
@@ -482,6 +499,93 @@ static void dcdbas_host_control(void)
}
}
+/* WSMT */
+
+static u8 checksum(u8 *buffer, u8 length)
+{
+ u8 sum = 0;
+ u8 *end = buffer + length;
+
+ while (buffer < end)
+ sum += *buffer++;
+ return sum;
+}
+
+static inline struct smm_eps_table *check_eps_table(u8 *addr)
+{
+ struct smm_eps_table *eps = (struct smm_eps_table *)addr;
+
+ if (strncmp(eps->smm_comm_buff_anchor, SMM_EPS_SIG, 4) != 0)
+ return NULL;
+
+ if (checksum(addr, eps->length) != 0)
+ return NULL;
+
+ return eps;
+}
+
+static int dcdbas_check_wsmt(void)
+{
+ struct acpi_table_wsmt *wsmt = NULL;
+ struct smm_eps_table *eps = NULL;
+ u64 remap_size;
+ u8 *addr;
+
+ acpi_get_table(ACPI_SIG_WSMT, 0, (struct acpi_table_header **)&wsmt);
+ if (!wsmt)
+ return 0;
+
+ /* Check if WSMT ACPI table shows that protection is enabled */
+ if (!(wsmt->protection_flags & ACPI_WSMT_FIXED_COMM_BUFFERS) ||
+ !(wsmt->protection_flags & ACPI_WSMT_COMM_BUFFER_NESTED_PTR_PROTECTION))
+ return 0;
+
+ /* Scan for EPS (entry point structure) */
+ for (addr = (u8 *)__va(0xf0000);
+ addr < (u8 *)__va(0x100000 - sizeof(struct smm_eps_table));
+ addr += 16) {
+ eps = check_eps_table(addr);
+ if (eps)
+ break;
+ }
+
+ if (!eps) {
+ dev_dbg(&dcdbas_pdev->dev, "found WSMT, but no EPS found\n");
+ return -ENODEV;
+ }
+
+ /*
+ * Get physical address of buffer and map to virtual address.
+ * Table gives size in 4K pages, regardless of actual system page size.
+ */
+ if (upper_32_bits(eps->smm_comm_buff_addr + 8)) {
+ dev_warn(&dcdbas_pdev->dev, "found WSMT, but EPS buffer address is above 4GB\n");
+ return -EINVAL;
+ }
+ /*
+ * Limit remap size to MAX_SMI_DATA_BUF_SIZE + 8 (since the first 8
+ * bytes are used for a semaphore, not the data buffer itself).
+ */
+ remap_size = eps->num_of_4k_pages * PAGE_SIZE;
+ if (remap_size > MAX_SMI_DATA_BUF_SIZE + 8)
+ remap_size = MAX_SMI_DATA_BUF_SIZE + 8;
+ eps_buffer = memremap(eps->smm_comm_buff_addr, remap_size, MEMREMAP_WB);
+ if (!eps_buffer) {
+ dev_warn(&dcdbas_pdev->dev, "found WSMT, but failed to map EPS buffer\n");
+ return -ENOMEM;
+ }
+
+ /* First 8 bytes is for a semaphore, not part of the smi_data_buf */
+ smi_data_buf_phys_addr = eps->smm_comm_buff_addr + 8;
+ smi_data_buf = eps_buffer + 8;
+ smi_data_buf_size = remap_size - 8;
+ max_smi_data_buf_size = smi_data_buf_size;
+ wsmt_enabled = true;
+ dev_info(&dcdbas_pdev->dev,
+ "WSMT found, using firmware-provided SMI buffer.\n");
+ return 1;
+}
+
/**
* dcdbas_reboot_notify: handle reboot notification for host control
*/
@@ -548,6 +652,11 @@ static int dcdbas_probe(struct platform_device *dev)
dcdbas_pdev = dev;
+ /* Check if ACPI WSMT table specifies protected SMI buffer address */
+ error = dcdbas_check_wsmt();
+ if (error < 0)
+ return error;
+
/*
* BIOS SMI calls require buffer addresses be in 32-bit address space.
* This is done by setting the DMA mask below.
@@ -635,6 +744,8 @@ static void __exit dcdbas_exit(void)
*/
if (dcdbas_pdev)
smi_data_buf_free();
+ if (eps_buffer)
+ memunmap(eps_buffer);
platform_device_unregister(dcdbas_pdev_reg);
platform_driver_unregister(&dcdbas_driver);
}
diff --git a/drivers/firmware/dcdbas.h b/drivers/platform/x86/dcdbas.h
index ca3cb0a54ab6..52729a494b00 100644
--- a/drivers/firmware/dcdbas.h
+++ b/drivers/platform/x86/dcdbas.h
@@ -53,6 +53,7 @@
#define EXPIRED_TIMER (0)
#define SMI_CMD_MAGIC (0x534D4931)
+#define SMM_EPS_SIG "$SCB"
#define DCDBAS_DEV_ATTR_RW(_name) \
DEVICE_ATTR(_name,0600,_name##_show,_name##_store);
@@ -103,5 +104,14 @@ struct apm_cmd {
int dcdbas_smi_request(struct smi_cmd *smi_cmd);
+struct smm_eps_table {
+ char smm_comm_buff_anchor[4];
+ u8 length;
+ u8 checksum;
+ u8 version;
+ u64 smm_comm_buff_addr;
+ u64 num_of_4k_pages;
+} __packed;
+
#endif /* _DCDBAS_H_ */
diff --git a/drivers/platform/x86/dell-smbios-smm.c b/drivers/platform/x86/dell-smbios-smm.c
index 97a90bebc360..ab9b822a6dfe 100644
--- a/drivers/platform/x86/dell-smbios-smm.c
+++ b/drivers/platform/x86/dell-smbios-smm.c
@@ -18,7 +18,7 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
-#include "../../firmware/dcdbas.h"
+#include "dcdbas.h"
#include "dell-smbios.h"
static int da_command_address;
diff --git a/drivers/firmware/dell_rbu.c b/drivers/platform/x86/dell_rbu.c
index fb8af5cb7c9b..ccefa84f7305 100644
--- a/drivers/firmware/dell_rbu.c
+++ b/drivers/platform/x86/dell_rbu.c
@@ -45,6 +45,7 @@
#include <linux/moduleparam.h>
#include <linux/firmware.h>
#include <linux/dma-mapping.h>
+#include <asm/set_memory.h>
MODULE_AUTHOR("Abhay Salunke <abhay_salunke@dell.com>");
MODULE_DESCRIPTION("Driver for updating BIOS image on DELL systems");
@@ -181,6 +182,11 @@ static int create_packet(void *data, size_t length)
packet_data_temp_buf = NULL;
}
}
+ /*
+ * set to uncachable or it may never get written back before reboot
+ */
+ set_memory_uc((unsigned long)packet_data_temp_buf, 1 << ordernum);
+
spin_lock(&rbu_data.lock);
newpacket->data = packet_data_temp_buf;
@@ -349,6 +355,8 @@ static void packet_empty_list(void)
* to make sure there are no stale RBU packets left in memory
*/
memset(newpacket->data, 0, rbu_data.packetsize);
+ set_memory_wb((unsigned long)newpacket->data,
+ 1 << newpacket->ordernum);
free_pages((unsigned long) newpacket->data,
newpacket->ordernum);
kfree(newpacket);
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index a4bbf6ecd1f0..e6946a9beb5a 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -177,7 +177,7 @@ struct eeepc_laptop {
struct rfkill *wwan3g_rfkill;
struct rfkill *wimax_rfkill;
- struct hotplug_slot *hotplug_slot;
+ struct hotplug_slot hotplug_slot;
struct mutex hotplug_lock;
struct led_classdev tpd_led;
@@ -582,7 +582,7 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc, acpi_handle handle)
mutex_lock(&eeepc->hotplug_lock);
pci_lock_rescan_remove();
- if (!eeepc->hotplug_slot)
+ if (!eeepc->hotplug_slot.ops)
goto out_unlock;
port = acpi_get_pci_dev(handle);
@@ -715,8 +715,11 @@ static void eeepc_unregister_rfkill_notifier(struct eeepc_laptop *eeepc,
static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot,
u8 *value)
{
- struct eeepc_laptop *eeepc = hotplug_slot->private;
- int val = get_acpi(eeepc, CM_ASL_WLAN);
+ struct eeepc_laptop *eeepc;
+ int val;
+
+ eeepc = container_of(hotplug_slot, struct eeepc_laptop, hotplug_slot);
+ val = get_acpi(eeepc, CM_ASL_WLAN);
if (val == 1 || val == 0)
*value = val;
@@ -726,8 +729,7 @@ static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot,
return 0;
}
-static struct hotplug_slot_ops eeepc_hotplug_slot_ops = {
- .owner = THIS_MODULE,
+static const struct hotplug_slot_ops eeepc_hotplug_slot_ops = {
.get_adapter_status = eeepc_get_adapter_status,
.get_power_status = eeepc_get_adapter_status,
};
@@ -742,21 +744,9 @@ static int eeepc_setup_pci_hotplug(struct eeepc_laptop *eeepc)
return -ENODEV;
}
- eeepc->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL);
- if (!eeepc->hotplug_slot)
- goto error_slot;
+ eeepc->hotplug_slot.ops = &eeepc_hotplug_slot_ops;
- eeepc->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info),
- GFP_KERNEL);
- if (!eeepc->hotplug_slot->info)
- goto error_info;
-
- eeepc->hotplug_slot->private = eeepc;
- eeepc->hotplug_slot->ops = &eeepc_hotplug_slot_ops;
- eeepc_get_adapter_status(eeepc->hotplug_slot,
- &eeepc->hotplug_slot->info->adapter_status);
-
- ret = pci_hp_register(eeepc->hotplug_slot, bus, 0, "eeepc-wifi");
+ ret = pci_hp_register(&eeepc->hotplug_slot, bus, 0, "eeepc-wifi");
if (ret) {
pr_err("Unable to register hotplug slot - %d\n", ret);
goto error_register;
@@ -765,11 +755,7 @@ static int eeepc_setup_pci_hotplug(struct eeepc_laptop *eeepc)
return 0;
error_register:
- kfree(eeepc->hotplug_slot->info);
-error_info:
- kfree(eeepc->hotplug_slot);
- eeepc->hotplug_slot = NULL;
-error_slot:
+ eeepc->hotplug_slot.ops = NULL;
return ret;
}
@@ -830,11 +816,8 @@ static void eeepc_rfkill_exit(struct eeepc_laptop *eeepc)
eeepc->wlan_rfkill = NULL;
}
- if (eeepc->hotplug_slot) {
- pci_hp_deregister(eeepc->hotplug_slot);
- kfree(eeepc->hotplug_slot->info);
- kfree(eeepc->hotplug_slot);
- }
+ if (eeepc->hotplug_slot.ops)
+ pci_hp_deregister(&eeepc->hotplug_slot);
if (eeepc->bluetooth_rfkill) {
rfkill_unregister(eeepc->bluetooth_rfkill);
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c
index d4f1259ff5a2..b6489cba2985 100644
--- a/drivers/platform/x86/ideapad-laptop.c
+++ b/drivers/platform/x86/ideapad-laptop.c
@@ -212,7 +212,7 @@ static int read_ec_data(acpi_handle handle, int cmd, unsigned long *data)
return 0;
}
}
- pr_err("timeout in read_ec_cmd\n");
+ pr_err("timeout in %s\n", __func__);
return -1;
}
@@ -1147,6 +1147,13 @@ static const struct dmi_system_id no_hw_rfkill_list[] = {
},
},
{
+ .ident = "Lenovo Legion Y530-15ICH",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Legion Y530-15ICH"),
+ },
+ },
+ {
.ident = "Lenovo Legion Y720-15IKB",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
diff --git a/drivers/platform/x86/intel-hid.c b/drivers/platform/x86/intel-hid.c
index 6cf9b7fa5bf0..e28bcf61b126 100644
--- a/drivers/platform/x86/intel-hid.c
+++ b/drivers/platform/x86/intel-hid.c
@@ -1,19 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Intel HID event & 5 button array driver
*
* Copyright (C) 2015 Alex Hung <alex.hung@canonical.com>
* Copyright (C) 2015 Andrew Lutomirski <luto@kernel.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 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.
- *
*/
#include <linux/acpi.h>
diff --git a/drivers/platform/x86/intel-rst.c b/drivers/platform/x86/intel-rst.c
index 7344d841f4d9..3b81cb896fed 100644
--- a/drivers/platform/x86/intel-rst.c
+++ b/drivers/platform/x86/intel-rst.c
@@ -1,26 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2013 Matthew Garrett <mjg59@srcf.ucam.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-
-#include <linux/init.h>
+#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <linux/acpi.h>
MODULE_LICENSE("GPL");
@@ -53,12 +38,10 @@ static ssize_t irst_store_wakeup_events(struct device *dev,
acpi = to_acpi_device(dev);
error = kstrtoul(buf, 0, &value);
-
if (error)
return error;
status = acpi_execute_simple_method(acpi->handle, "SFFS", value);
-
if (ACPI_FAILURE(status))
return -EINVAL;
@@ -99,12 +82,10 @@ static ssize_t irst_store_wakeup_time(struct device *dev,
acpi = to_acpi_device(dev);
error = kstrtoul(buf, 0, &value);
-
if (error)
return error;
status = acpi_execute_simple_method(acpi->handle, "SFTV", value);
-
if (ACPI_FAILURE(status))
return -EINVAL;
diff --git a/drivers/platform/x86/intel-smartconnect.c b/drivers/platform/x86/intel-smartconnect.c
index bbe4c06c769f..64c2dc93472f 100644
--- a/drivers/platform/x86/intel-smartconnect.c
+++ b/drivers/platform/x86/intel-smartconnect.c
@@ -1,25 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2013 Matthew Garrett <mjg59@srcf.ucam.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-
-#include <linux/init.h>
-#include <linux/module.h>
#include <linux/acpi.h>
+#include <linux/module.h>
MODULE_LICENSE("GPL");
@@ -44,6 +29,7 @@ static const struct acpi_device_id smartconnect_ids[] = {
{"INT33A0", 0},
{"", 0}
};
+MODULE_DEVICE_TABLE(acpi, smartconnect_ids);
static struct acpi_driver smartconnect_driver = {
.owner = THIS_MODULE,
@@ -56,5 +42,3 @@ static struct acpi_driver smartconnect_driver = {
};
module_acpi_driver(smartconnect_driver);
-
-MODULE_DEVICE_TABLE(acpi, smartconnect_ids);
diff --git a/drivers/platform/x86/intel-wmi-thunderbolt.c b/drivers/platform/x86/intel-wmi-thunderbolt.c
index c2257bd06f18..9ded8e2af312 100644
--- a/drivers/platform/x86/intel-wmi-thunderbolt.c
+++ b/drivers/platform/x86/intel-wmi-thunderbolt.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* WMI Thunderbolt driver
*
* Copyright (C) 2017 Dell Inc. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -38,12 +30,16 @@ static ssize_t force_power_store(struct device *dev,
input.length = sizeof(u8);
input.pointer = &mode;
mode = hex_to_bin(buf[0]);
+ dev_dbg(dev, "force_power: storing %#x\n", mode);
if (mode == 0 || mode == 1) {
status = wmi_evaluate_method(INTEL_WMI_THUNDERBOLT_GUID, 0, 1,
&input, NULL);
- if (ACPI_FAILURE(status))
+ if (ACPI_FAILURE(status)) {
+ dev_dbg(dev, "force_power: failed to evaluate ACPI method\n");
return -ENODEV;
+ }
} else {
+ dev_dbg(dev, "force_power: unsupported mode\n");
return -EINVAL;
}
return count;
@@ -95,4 +91,4 @@ module_wmi_driver(intel_wmi_thunderbolt_driver);
MODULE_ALIAS("wmi:" INTEL_WMI_THUNDERBOLT_GUID);
MODULE_AUTHOR("Mario Limonciello <mario.limonciello@dell.com>");
MODULE_DESCRIPTION("Intel WMI Thunderbolt force power driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/platform/x86/intel_atomisp2_pm.c b/drivers/platform/x86/intel_atomisp2_pm.c
new file mode 100644
index 000000000000..9371603a0ac9
--- /dev/null
+++ b/drivers/platform/x86/intel_atomisp2_pm.c
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Dummy driver for Intel's Image Signal Processor found on Bay and Cherry
+ * Trail devices. The sole purpose of this driver is to allow the ISP to
+ * be put in D3.
+ *
+ * Copyright (C) 2018 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Based on various non upstream patches for ISP support:
+ * Copyright (C) 2010-2017 Intel Corporation. All rights reserved.
+ * Copyright (c) 2010 Silicon Hive www.siliconhive.com.
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/pci.h>
+#include <linux/pm_runtime.h>
+#include <asm/iosf_mbi.h>
+
+/* PCI configuration regs */
+#define PCI_INTERRUPT_CTRL 0x9c
+
+#define PCI_CSI_CONTROL 0xe8
+#define PCI_CSI_CONTROL_PORTS_OFF_MASK 0x7
+
+/* IOSF BT_MBI_UNIT_PMC regs */
+#define ISPSSPM0 0x39
+#define ISPSSPM0_ISPSSC_OFFSET 0
+#define ISPSSPM0_ISPSSC_MASK 0x00000003
+#define ISPSSPM0_ISPSSS_OFFSET 24
+#define ISPSSPM0_ISPSSS_MASK 0x03000000
+#define ISPSSPM0_IUNIT_POWER_ON 0x0
+#define ISPSSPM0_IUNIT_POWER_OFF 0x3
+
+static int isp_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ unsigned long timeout;
+ u32 val;
+
+ pci_write_config_dword(dev, PCI_INTERRUPT_CTRL, 0);
+
+ /*
+ * MRFLD IUNIT DPHY is located in an always-power-on island
+ * MRFLD HW design need all CSI ports are disabled before
+ * powering down the IUNIT.
+ */
+ pci_read_config_dword(dev, PCI_CSI_CONTROL, &val);
+ val |= PCI_CSI_CONTROL_PORTS_OFF_MASK;
+ pci_write_config_dword(dev, PCI_CSI_CONTROL, val);
+
+ /* Write 0x3 to ISPSSPM0 bit[1:0] to power off the IUNIT */
+ iosf_mbi_modify(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM0,
+ ISPSSPM0_IUNIT_POWER_OFF, ISPSSPM0_ISPSSC_MASK);
+
+ /*
+ * There should be no IUNIT access while power-down is
+ * in progress HW sighting: 4567865
+ * Wait up to 50 ms for the IUNIT to shut down.
+ */
+ timeout = jiffies + msecs_to_jiffies(50);
+ while (1) {
+ /* Wait until ISPSSPM0 bit[25:24] shows 0x3 */
+ iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM0, &val);
+ val = (val & ISPSSPM0_ISPSSS_MASK) >> ISPSSPM0_ISPSSS_OFFSET;
+ if (val == ISPSSPM0_IUNIT_POWER_OFF)
+ break;
+
+ if (time_after(jiffies, timeout)) {
+ dev_err(&dev->dev, "IUNIT power-off timeout.\n");
+ return -EBUSY;
+ }
+ usleep_range(1000, 2000);
+ }
+
+ pm_runtime_allow(&dev->dev);
+ pm_runtime_put_sync_suspend(&dev->dev);
+
+ return 0;
+}
+
+static void isp_remove(struct pci_dev *dev)
+{
+ pm_runtime_get_sync(&dev->dev);
+ pm_runtime_forbid(&dev->dev);
+}
+
+static int isp_pci_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static int isp_pci_resume(struct device *dev)
+{
+ return 0;
+}
+
+static UNIVERSAL_DEV_PM_OPS(isp_pm_ops, isp_pci_suspend,
+ isp_pci_resume, NULL);
+
+static const struct pci_device_id isp_id_table[] = {
+ { PCI_VDEVICE(INTEL, 0x22b8), },
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, isp_id_table);
+
+static struct pci_driver isp_pci_driver = {
+ .name = "intel_atomisp2_pm",
+ .id_table = isp_id_table,
+ .probe = isp_probe,
+ .remove = isp_remove,
+ .driver.pm = &isp_pm_ops,
+};
+
+module_pci_driver(isp_pci_driver);
+
+MODULE_DESCRIPTION("Intel AtomISP2 dummy / power-management drv (for suspend)");
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/platform/x86/intel_bxtwc_tmu.c b/drivers/platform/x86/intel_bxtwc_tmu.c
index 227943a20212..951c105bafc1 100644
--- a/drivers/platform/x86/intel_bxtwc_tmu.c
+++ b/drivers/platform/x86/intel_bxtwc_tmu.c
@@ -1,21 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
/*
- * intel_bxtwc_tmu.c - Intel BXT Whiskey Cove PMIC TMU driver
+ * Intel BXT Whiskey Cove PMIC TMU driver
*
* Copyright (C) 2016 Intel Corporation. All rights reserved.
*
* This driver adds TMU (Time Management Unit) support for Intel BXT platform.
* It enables the alarm wake-up functionality in the TMU unit of Whiskey Cove
* PMIC.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <linux/module.h>
diff --git a/drivers/platform/x86/intel_cht_int33fe.c b/drivers/platform/x86/intel_cht_int33fe.c
index 39d4100c60a2..464fe93657b5 100644
--- a/drivers/platform/x86/intel_cht_int33fe.c
+++ b/drivers/platform/x86/intel_cht_int33fe.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Intel Cherry Trail ACPI INT33FE pseudo device driver
*
* Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
* Some Intel Cherry Trail based device which ship with Windows 10, have
* this weird INT33FE ACPI device with a CRS table with 4 I2cSerialBusV2
* resources, for 4 different chips attached to various i2c busses:
@@ -24,6 +21,7 @@
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/module.h>
+#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
@@ -34,7 +32,7 @@ struct cht_int33fe_data {
struct i2c_client *fusb302;
struct i2c_client *pi3usb30532;
/* Contain a list-head must be per device */
- struct device_connection connections[3];
+ struct device_connection connections[5];
};
/*
@@ -88,9 +86,9 @@ static const struct property_entry fusb302_props[] = {
{ }
};
-static int cht_int33fe_probe(struct i2c_client *client)
+static int cht_int33fe_probe(struct platform_device *pdev)
{
- struct device *dev = &client->dev;
+ struct device *dev = &pdev->dev;
struct i2c_board_info board_info;
struct cht_int33fe_data *data;
struct i2c_client *max17047;
@@ -174,19 +172,20 @@ static int cht_int33fe_probe(struct i2c_client *client)
return -EPROBE_DEFER; /* Wait for i2c-adapter to load */
}
- data->connections[0].endpoint[0] = "i2c-fusb302";
+ data->connections[0].endpoint[0] = "port0";
data->connections[0].endpoint[1] = "i2c-pi3usb30532";
data->connections[0].id = "typec-switch";
- data->connections[1].endpoint[0] = "i2c-fusb302";
+ data->connections[1].endpoint[0] = "port0";
data->connections[1].endpoint[1] = "i2c-pi3usb30532";
data->connections[1].id = "typec-mux";
- data->connections[2].endpoint[0] = "i2c-fusb302";
- data->connections[2].endpoint[1] = "intel_xhci_usb_sw-role-switch";
- data->connections[2].id = "usb-role-switch";
+ data->connections[2].endpoint[0] = "port0";
+ data->connections[2].endpoint[1] = "i2c-pi3usb30532";
+ data->connections[2].id = "idff01m01";
+ data->connections[3].endpoint[0] = "i2c-fusb302";
+ data->connections[3].endpoint[1] = "intel_xhci_usb_sw-role-switch";
+ data->connections[3].id = "usb-role-switch";
- device_connection_add(&data->connections[0]);
- device_connection_add(&data->connections[1]);
- device_connection_add(&data->connections[2]);
+ device_connections_add(data->connections);
memset(&board_info, 0, sizeof(board_info));
strlcpy(board_info.type, "typec_fusb302", I2C_NAME_SIZE);
@@ -206,7 +205,7 @@ static int cht_int33fe_probe(struct i2c_client *client)
if (!data->pi3usb30532)
goto out_unregister_fusb302;
- i2c_set_clientdata(client, data);
+ platform_set_drvdata(pdev, data);
return 0;
@@ -217,53 +216,42 @@ out_unregister_max17047:
if (data->max17047)
i2c_unregister_device(data->max17047);
- device_connection_remove(&data->connections[2]);
- device_connection_remove(&data->connections[1]);
- device_connection_remove(&data->connections[0]);
+ device_connections_remove(data->connections);
return -EPROBE_DEFER; /* Wait for the i2c-adapter to load */
}
-static int cht_int33fe_remove(struct i2c_client *i2c)
+static int cht_int33fe_remove(struct platform_device *pdev)
{
- struct cht_int33fe_data *data = i2c_get_clientdata(i2c);
+ struct cht_int33fe_data *data = platform_get_drvdata(pdev);
i2c_unregister_device(data->pi3usb30532);
i2c_unregister_device(data->fusb302);
if (data->max17047)
i2c_unregister_device(data->max17047);
- device_connection_remove(&data->connections[2]);
- device_connection_remove(&data->connections[1]);
- device_connection_remove(&data->connections[0]);
+ device_connections_remove(data->connections);
return 0;
}
-static const struct i2c_device_id cht_int33fe_i2c_id[] = {
- { }
-};
-MODULE_DEVICE_TABLE(i2c, cht_int33fe_i2c_id);
-
static const struct acpi_device_id cht_int33fe_acpi_ids[] = {
{ "INT33FE", },
{ }
};
MODULE_DEVICE_TABLE(acpi, cht_int33fe_acpi_ids);
-static struct i2c_driver cht_int33fe_driver = {
+static struct platform_driver cht_int33fe_driver = {
.driver = {
.name = "Intel Cherry Trail ACPI INT33FE driver",
.acpi_match_table = ACPI_PTR(cht_int33fe_acpi_ids),
},
- .probe_new = cht_int33fe_probe,
+ .probe = cht_int33fe_probe,
.remove = cht_int33fe_remove,
- .id_table = cht_int33fe_i2c_id,
- .disable_i2c_core_irq_mapping = true,
};
-module_i2c_driver(cht_int33fe_driver);
+module_platform_driver(cht_int33fe_driver);
MODULE_DESCRIPTION("Intel Cherry Trail ACPI INT33FE pseudo device driver");
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/platform/x86/intel_chtdc_ti_pwrbtn.c b/drivers/platform/x86/intel_chtdc_ti_pwrbtn.c
index 38b8e7cfe88c..0df2e82dd249 100644
--- a/drivers/platform/x86/intel_chtdc_ti_pwrbtn.c
+++ b/drivers/platform/x86/intel_chtdc_ti_pwrbtn.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Power-button driver for Dollar Cove TI PMIC
* Copyright (C) 2014 Intel Corp
diff --git a/drivers/platform/x86/intel_int0002_vgpio.c b/drivers/platform/x86/intel_int0002_vgpio.c
index a473dc51b18d..4b8f7305fc8a 100644
--- a/drivers/platform/x86/intel_int0002_vgpio.c
+++ b/drivers/platform/x86/intel_int0002_vgpio.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Intel INT0002 "Virtual GPIO" driver
*
@@ -9,10 +10,6 @@
*
* Author: Dyut Kumar Sil <dyut.k.sil@intel.com>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
* Some peripherals on Bay Trail and Cherry Trail platforms signal a Power
* Management Event (PME) to the Power Management Controller (PMC) to wakeup
* the system. When this happens software needs to clear the PME bus 0 status
@@ -57,11 +54,7 @@
#define ICPU(model) { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, }
static const struct x86_cpu_id int0002_cpu_ids[] = {
-/*
- * Limit ourselves to Cherry Trail for now, until testing shows we
- * need to handle the INT0002 device on Baytrail too.
- * ICPU(INTEL_FAM6_ATOM_SILVERMONT1), * Valleyview, Bay Trail *
- */
+ ICPU(INTEL_FAM6_ATOM_SILVERMONT), /* Valleyview, Bay Trail */
ICPU(INTEL_FAM6_ATOM_AIRMONT), /* Braswell, Cherry Trail */
{}
};
@@ -110,6 +103,21 @@ static void int0002_irq_mask(struct irq_data *data)
outl(gpe_en_reg, GPE0A_EN_PORT);
}
+static int int0002_irq_set_wake(struct irq_data *data, unsigned int on)
+{
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+ struct platform_device *pdev = to_platform_device(chip->parent);
+ int irq = platform_get_irq(pdev, 0);
+
+ /* Propagate to parent irq */
+ if (on)
+ enable_irq_wake(irq);
+ else
+ disable_irq_wake(irq);
+
+ return 0;
+}
+
static irqreturn_t int0002_irq(int irq, void *data)
{
struct gpio_chip *chip = data;
@@ -132,6 +140,7 @@ static struct irq_chip int0002_irqchip = {
.irq_ack = int0002_irq_ack,
.irq_mask = int0002_irq_mask,
.irq_unmask = int0002_irq_unmask,
+ .irq_set_wake = int0002_irq_set_wake,
};
static int int0002_probe(struct platform_device *pdev)
@@ -216,4 +225,4 @@ module_platform_driver(int0002_driver);
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
MODULE_DESCRIPTION("Intel INT0002 Virtual GPIO driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/platform/x86/intel_ips.c b/drivers/platform/x86/intel_ips.c
index c5ece7ef08c6..225638a1b09e 100644
--- a/drivers/platform/x86/intel_ips.c
+++ b/drivers/platform/x86/intel_ips.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2009-2010 Intel Corporation
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
* Authors:
* Jesse Barnes <jbarnes@virtuousgeek.org>
*/
@@ -1697,6 +1686,6 @@ static struct pci_driver ips_pci_driver = {
module_pci_driver(ips_pci_driver);
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Jesse Barnes <jbarnes@virtuousgeek.org>");
MODULE_DESCRIPTION("Intelligent Power Sharing Driver");
diff --git a/drivers/platform/x86/intel_ips.h b/drivers/platform/x86/intel_ips.h
index 60f4e3ddbe9f..512ad234ad0d 100644
--- a/drivers/platform/x86/intel_ips.h
+++ b/drivers/platform/x86/intel_ips.h
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2010 Intel Corporation
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
*/
void ips_link_to_i915_driver(void);
diff --git a/drivers/platform/x86/intel_menlow.c b/drivers/platform/x86/intel_menlow.c
index ef9b0af8cdd3..77eb8709c931 100644
--- a/drivers/platform/x86/intel_menlow.c
+++ b/drivers/platform/x86/intel_menlow.c
@@ -1,25 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
- * intel_menlow.c - Intel menlow Driver for thermal management extension
+ * Intel menlow Driver for thermal management extension
*
* Copyright (C) 2008 Intel Corp
* Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
* Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This driver creates the sys I/F for programming the sensors.
* It also implements the driver for intel menlow memory controller (hardware
@@ -29,20 +14,19 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/acpi.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/types.h>
#include <linux/pci.h>
#include <linux/pm.h>
+#include <linux/slab.h>
#include <linux/thermal.h>
-#include <linux/acpi.h>
+#include <linux/types.h>
MODULE_AUTHOR("Thomas Sujith");
MODULE_AUTHOR("Zhang Rui");
MODULE_DESCRIPTION("Intel Menlow platform specific driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
/*
* Memory controller device control
diff --git a/drivers/platform/x86/intel_mid_powerbtn.c b/drivers/platform/x86/intel_mid_powerbtn.c
index d79fbf924b13..292bace83f1e 100644
--- a/drivers/platform/x86/intel_mid_powerbtn.c
+++ b/drivers/platform/x86/intel_mid_powerbtn.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Power button driver for Intel MID platforms.
*
@@ -5,18 +6,8 @@
*
* Author: Hong Liu <hong.liu@intel.com>
* Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
*/
-#include <linux/init.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/mfd/intel_msic.h>
@@ -121,12 +112,9 @@ static const struct mid_pb_ddata mrfld_ddata = {
.setup = mrfld_setup,
};
-#define ICPU(model, ddata) \
- { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (kernel_ulong_t)&ddata }
-
static const struct x86_cpu_id mid_pb_cpu_ids[] = {
- ICPU(INTEL_FAM6_ATOM_PENWELL, mfld_ddata),
- ICPU(INTEL_FAM6_ATOM_MERRIFIELD, mrfld_ddata),
+ INTEL_CPU_FAM6(ATOM_SALTWELL_MID, mfld_ddata),
+ INTEL_CPU_FAM6(ATOM_SILVERMONT_MID, mrfld_ddata),
{}
};
diff --git a/drivers/platform/x86/intel_mid_thermal.c b/drivers/platform/x86/intel_mid_thermal.c
index 008a76903cbf..f402e2e74a38 100644
--- a/drivers/platform/x86/intel_mid_thermal.c
+++ b/drivers/platform/x86/intel_mid_thermal.c
@@ -1,39 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0
/*
- * intel_mid_thermal.c - Intel MID platform thermal driver
+ * Intel MID platform thermal driver
*
* Copyright (C) 2011 Intel Corporation
*
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Author: Durgadoss R <durgadoss.r@intel.com>
*/
#define pr_fmt(fmt) "intel_mid_thermal: " fmt
-#include <linux/module.h>
-#include <linux/init.h>
+#include <linux/device.h>
#include <linux/err.h>
+#include <linux/mfd/intel_msic.h>
+#include <linux/module.h>
#include <linux/param.h>
-#include <linux/device.h>
#include <linux/platform_device.h>
-#include <linux/slab.h>
#include <linux/pm.h>
+#include <linux/slab.h>
#include <linux/thermal.h>
-#include <linux/mfd/intel_msic.h>
/* Number of thermal sensors */
#define MSIC_THERMAL_SENSORS 4
@@ -567,4 +551,4 @@ module_platform_driver(mid_thermal_driver);
MODULE_AUTHOR("Durgadoss R <durgadoss.r@intel.com>");
MODULE_DESCRIPTION("Intel Medfield Platform Thermal Driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/platform/x86/intel_oaktrail.c b/drivers/platform/x86/intel_oaktrail.c
index 5747f63c8d9f..3c0438ba385e 100644
--- a/drivers/platform/x86/intel_oaktrail.c
+++ b/drivers/platform/x86/intel_oaktrail.c
@@ -1,5 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
- * intel_oaktrail.c - Intel OakTrail Platform support.
+ * Intel OakTrail Platform support
*
* Copyright (C) 2010-2011 Intel Corporation
* Author: Yin Kangkai (kangkai.yin@intel.com)
@@ -8,21 +9,6 @@
* <cezary.jackiewicz (at) gmail.com>, based on MSI driver
* Copyright (C) 2006 Lennart Poettering <mzxreary (at) 0pointer (dot) de>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
* This driver does below things:
* 1. registers itself in the Linux backlight control in
* /sys/class/backlight/intel_oaktrail/
@@ -38,18 +24,18 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/acpi.h>
-#include <linux/fb.h>
-#include <linux/mutex.h>
+#include <linux/backlight.h>
+#include <linux/dmi.h>
#include <linux/err.h>
+#include <linux/fb.h>
#include <linux/i2c.h>
-#include <linux/backlight.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/platform_device.h>
-#include <linux/dmi.h>
#include <linux/rfkill.h>
+
#include <acpi/video.h>
#define DRIVER_NAME "intel_oaktrail"
diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c
index 2d272a3e0176..6b31d410cb09 100644
--- a/drivers/platform/x86/intel_pmc_core.c
+++ b/drivers/platform/x86/intel_pmc_core.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Intel Core SoC Power Management Controller Driver
*
@@ -6,16 +7,6 @@
*
* Authors: Rajneesh Bhardwaj <rajneesh.bhardwaj@intel.com>
* Vishwanath Somayaji <vishwanath.somayaji@intel.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/platform/x86/intel_pmc_core.h b/drivers/platform/x86/intel_pmc_core.h
index 93a7e99e1f8b..be045348ad86 100644
--- a/drivers/platform/x86/intel_pmc_core.h
+++ b/drivers/platform/x86/intel_pmc_core.h
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Intel Core SoC Power Management Controller Header File
*
@@ -6,16 +7,6 @@
*
* Authors: Rajneesh Bhardwaj <rajneesh.bhardwaj@intel.com>
* Vishwanath Somayaji <vishwanath.somayaji@intel.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
*/
#ifndef PMC_CORE_H
diff --git a/drivers/platform/x86/intel_pmc_ipc.c b/drivers/platform/x86/intel_pmc_ipc.c
index e7edc8c63936..7964ba22ef8d 100644
--- a/drivers/platform/x86/intel_pmc_ipc.c
+++ b/drivers/platform/x86/intel_pmc_ipc.c
@@ -1,39 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0
/*
- * intel_pmc_ipc.c: Driver for the Intel PMC IPC mechanism
+ * Driver for the Intel PMC IPC mechanism
*
* (C) Copyright 2014-2015 Intel Corporation
*
- * This driver is based on Intel SCU IPC driver(intel_scu_opc.c) by
+ * This driver is based on Intel SCU IPC driver(intel_scu_ipc.c) by
* Sreedhara DS <sreedhara.ds@intel.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
- * of the License.
- *
* PMC running in ARC processor communicates with other entity running in IA
* core through IPC mechanism which in turn messaging between IA core ad PMC.
*/
-#include <linux/module.h>
+#include <linux/acpi.h>
+#include <linux/atomic.h>
+#include <linux/bitops.h>
#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/device.h>
-#include <linux/pm.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
-#include <linux/interrupt.h>
+#include <linux/pm.h>
#include <linux/pm_qos.h>
-#include <linux/kernel.h>
-#include <linux/bitops.h>
#include <linux/sched.h>
-#include <linux/atomic.h>
-#include <linux/notifier.h>
-#include <linux/suspend.h>
-#include <linux/acpi.h>
-#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/spinlock.h>
+#include <linux/suspend.h>
#include <asm/intel_pmc_ipc.h>
@@ -1029,7 +1024,7 @@ static void __exit intel_pmc_ipc_exit(void)
MODULE_AUTHOR("Zha Qipeng <qipeng.zha@intel.com>");
MODULE_DESCRIPTION("Intel PMC IPC driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
/* Some modules are dependent on this, so init earlier */
fs_initcall(intel_pmc_ipc_init);
diff --git a/drivers/platform/x86/intel_punit_ipc.c b/drivers/platform/x86/intel_punit_ipc.c
index 2efeab650345..79671927f4ef 100644
--- a/drivers/platform/x86/intel_punit_ipc.c
+++ b/drivers/platform/x86/intel_punit_ipc.c
@@ -1,25 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Driver for the Intel P-Unit Mailbox IPC mechanism
*
* (C) Copyright 2015 Intel Corporation
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
* The heart of the P-Unit is the Foxton microcontroller and its firmware,
* which provide mailbox interface for power management usage.
*/
-#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/acpi.h>
-#include <linux/delay.h>
#include <linux/bitops.h>
+#include <linux/delay.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
#include <linux/platform_device.h>
+
#include <asm/intel_punit_ipc.h>
/* IPC Mailbox registers */
diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c
index 75c8fef7a482..cdab916fbf92 100644
--- a/drivers/platform/x86/intel_scu_ipc.c
+++ b/drivers/platform/x86/intel_scu_ipc.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
- * intel_scu_ipc.c: Driver for the Intel SCU IPC mechanism
+ * Driver for the Intel SCU IPC mechanism
*
* (C) Copyright 2008-2010,2015 Intel Corporation
* Author: Sreedhara DS (sreedhara.ds@intel.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
- * of the License.
- *
* SCU running in ARC processor communicates with other entity running in IA
* core through IPC mechanism which in turn messaging between IA core ad SCU.
* SCU has two IPC mechanism IPC-1 and IPC-2. IPC-1 is used between IA32 and
@@ -16,14 +12,16 @@
* IPC-1 Driver provides an API for power control unit registers (e.g. MSIC)
* along with other APIs.
*/
+
#include <linux/delay.h>
+#include <linux/device.h>
#include <linux/errno.h>
#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/pm.h>
-#include <linux/pci.h>
#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/pm.h>
#include <linux/sfi.h>
+
#include <asm/intel-mid.h>
#include <asm/intel_scu_ipc.h>
diff --git a/drivers/platform/x86/intel_scu_ipcutil.c b/drivers/platform/x86/intel_scu_ipcutil.c
index aa454241489c..8afe6fa06d7b 100644
--- a/drivers/platform/x86/intel_scu_ipcutil.c
+++ b/drivers/platform/x86/intel_scu_ipcutil.c
@@ -1,32 +1,28 @@
+// SPDX-License-Identifier: GPL-2.0
/*
- * intel_scu_ipc.c: Driver for the Intel SCU IPC mechanism
+ * Driver for the Intel SCU IPC mechanism
*
* (C) Copyright 2008-2010 Intel Corporation
* Author: Sreedhara DS (sreedhara.ds@intel.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
- * of the License.
- *
- * This driver provides ioctl interfaces to call intel scu ipc driver api
+ * This driver provides IOCTL interfaces to call Intel SCU IPC driver API.
*/
-#include <linux/module.h>
-#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/fs.h>
#include <linux/fcntl.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/sched.h>
-#include <linux/uaccess.h>
#include <linux/slab.h>
-#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+
#include <asm/intel_scu_ipc.h>
static int major;
-/* ioctl commnds */
+/* IOCTL commands */
#define INTE_SCU_IPC_REGISTER_READ 0
#define INTE_SCU_IPC_REGISTER_WRITE 1
#define INTE_SCU_IPC_REGISTER_UPDATE 2
diff --git a/drivers/platform/x86/intel_telemetry_core.c b/drivers/platform/x86/intel_telemetry_core.c
index f378621b5fe9..d4040bb222b4 100644
--- a/drivers/platform/x86/intel_telemetry_core.c
+++ b/drivers/platform/x86/intel_telemetry_core.c
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Intel SoC Core Telemetry Driver
* Copyright (C) 2015, Intel Corporation.
* All Rights Reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
* Telemetry Framework provides platform related PM and performance statistics.
* This file provides the core telemetry API implementation.
*/
@@ -460,4 +452,4 @@ module_exit(telemetry_module_exit);
MODULE_AUTHOR("Souvik Kumar Chakravarty <souvik.k.chakravarty@intel.com>");
MODULE_DESCRIPTION("Intel SoC Telemetry Interface");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/platform/x86/intel_telemetry_debugfs.c b/drivers/platform/x86/intel_telemetry_debugfs.c
index ffd0474b0531..40bce560eb30 100644
--- a/drivers/platform/x86/intel_telemetry_debugfs.c
+++ b/drivers/platform/x86/intel_telemetry_debugfs.c
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Intel SOC Telemetry debugfs Driver: Currently supports APL
* Copyright (c) 2015, Intel Corporation.
* All Rights Reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
* This file provides the debugfs interfaces for telemetry.
* /sys/kernel/debug/telemetry/pss_info: Shows Primary Control Sub-Sys Counters
* /sys/kernel/debug/telemetry/ioss_info: Shows IO Sub-System Counters
@@ -72,9 +64,6 @@
#define TELEM_IOSS_DX_D0IX_EVTS 25
#define TELEM_IOSS_PG_EVTS 30
-#define TELEM_DEBUGFS_CPU(model, data) \
- { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&data}
-
#define TELEM_CHECK_AND_PARSE_EVTS(EVTID, EVTNUM, BUF, EVTLOG, EVTDAT, MASK) { \
if (evtlog[index].telem_evtid == (EVTID)) { \
for (idx = 0; idx < (EVTNUM); idx++) \
@@ -319,8 +308,8 @@ static struct telemetry_debugfs_conf telem_apl_debugfs_conf = {
};
static const struct x86_cpu_id telemetry_debugfs_cpu_ids[] = {
- TELEM_DEBUGFS_CPU(INTEL_FAM6_ATOM_GOLDMONT, telem_apl_debugfs_conf),
- TELEM_DEBUGFS_CPU(INTEL_FAM6_ATOM_GEMINI_LAKE, telem_apl_debugfs_conf),
+ INTEL_CPU_FAM6(ATOM_GOLDMONT, telem_apl_debugfs_conf),
+ INTEL_CPU_FAM6(ATOM_GOLDMONT_PLUS, telem_apl_debugfs_conf),
{}
};
@@ -951,12 +940,16 @@ static int __init telemetry_debugfs_init(void)
debugfs_conf = (struct telemetry_debugfs_conf *)id->driver_data;
err = telemetry_pltconfig_valid();
- if (err < 0)
+ if (err < 0) {
+ pr_info("Invalid pltconfig, ensure IPC1 device is enabled in BIOS\n");
return -ENODEV;
+ }
err = telemetry_debugfs_check_evts();
- if (err < 0)
+ if (err < 0) {
+ pr_info("telemetry_debugfs_check_evts failed\n");
return -EINVAL;
+ }
register_pm_notifier(&pm_notifier);
@@ -1037,4 +1030,4 @@ module_exit(telemetry_debugfs_exit);
MODULE_AUTHOR("Souvik Kumar Chakravarty <souvik.k.chakravarty@intel.com>");
MODULE_DESCRIPTION("Intel SoC Telemetry debugfs Interface");
MODULE_VERSION(DRIVER_VERSION);
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/platform/x86/intel_telemetry_pltdrv.c b/drivers/platform/x86/intel_telemetry_pltdrv.c
index 2f889d6c270e..df8565bad595 100644
--- a/drivers/platform/x86/intel_telemetry_pltdrv.c
+++ b/drivers/platform/x86/intel_telemetry_pltdrv.c
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Intel SOC Telemetry Platform Driver: Currently supports APL
* Copyright (c) 2015, Intel Corporation.
* All Rights Reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
* This file provides the platform specific telemetry implementation for APL.
* It used the PUNIT and PMC IPC interfaces for configuring the counters.
* The accumulated results are fetched from SRAM.
@@ -192,7 +184,7 @@ static struct telemetry_plt_config telem_glk_config = {
static const struct x86_cpu_id telemetry_cpu_ids[] = {
TELEM_CPU(INTEL_FAM6_ATOM_GOLDMONT, telem_apl_config),
- TELEM_CPU(INTEL_FAM6_ATOM_GEMINI_LAKE, telem_glk_config),
+ TELEM_CPU(INTEL_FAM6_ATOM_GOLDMONT_PLUS, telem_glk_config),
{}
};
@@ -1242,4 +1234,4 @@ module_exit(telemetry_module_exit);
MODULE_AUTHOR("Souvik Kumar Chakravarty <souvik.k.chakravarty@intel.com>");
MODULE_DESCRIPTION("Intel SoC Telemetry Platform Driver");
MODULE_VERSION(DRIVER_VERSION);
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/platform/x86/intel_turbo_max_3.c b/drivers/platform/x86/intel_turbo_max_3.c
index a6d5aa0c3c47..7b9cc841ab65 100644
--- a/drivers/platform/x86/intel_turbo_max_3.c
+++ b/drivers/platform/x86/intel_turbo_max_3.c
@@ -1,28 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Intel Turbo Boost Max Technology 3.0 legacy (non HWP) enumeration driver
* Copyright (c) 2017, Intel Corporation.
* All rights reserved.
*
* Author: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#include <linux/kernel.h>
+#include <linux/cpufeature.h>
+#include <linux/cpuhotplug.h>
#include <linux/init.h>
+#include <linux/kernel.h>
#include <linux/topology.h>
#include <linux/workqueue.h>
-#include <linux/cpuhotplug.h>
-#include <linux/cpufeature.h>
+
#include <asm/cpu_device_id.h>
#include <asm/intel-family.h>
diff --git a/drivers/platform/x86/lg-laptop.c b/drivers/platform/x86/lg-laptop.c
new file mode 100644
index 000000000000..c0bb1f864dfe
--- /dev/null
+++ b/drivers/platform/x86/lg-laptop.c
@@ -0,0 +1,700 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * lg-laptop.c - LG Gram ACPI features and hotkeys Driver
+ *
+ * Copyright (C) 2018 Matan Ziv-Av <matan@svgalib.org>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/acpi.h>
+#include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
+#include <linux/kernel.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+
+#define LED_DEVICE(_name, max) struct led_classdev _name = { \
+ .name = __stringify(_name), \
+ .max_brightness = max, \
+ .brightness_set = _name##_set, \
+ .brightness_get = _name##_get, \
+}
+
+MODULE_AUTHOR("Matan Ziv-Av");
+MODULE_DESCRIPTION("LG WMI Hotkey Driver");
+MODULE_LICENSE("GPL");
+
+#define WMI_EVENT_GUID0 "E4FB94F9-7F2B-4173-AD1A-CD1D95086248"
+#define WMI_EVENT_GUID1 "023B133E-49D1-4E10-B313-698220140DC2"
+#define WMI_EVENT_GUID2 "37BE1AC0-C3F2-4B1F-BFBE-8FDEAF2814D6"
+#define WMI_EVENT_GUID3 "911BAD44-7DF8-4FBB-9319-BABA1C4B293B"
+#define WMI_METHOD_WMAB "C3A72B38-D3EF-42D3-8CBB-D5A57049F66D"
+#define WMI_METHOD_WMBB "2B4F501A-BD3C-4394-8DCF-00A7D2BC8210"
+#define WMI_EVENT_GUID WMI_EVENT_GUID0
+
+#define WMAB_METHOD "\\XINI.WMAB"
+#define WMBB_METHOD "\\XINI.WMBB"
+#define SB_GGOV_METHOD "\\_SB.GGOV"
+#define GOV_TLED 0x2020008
+#define WM_GET 1
+#define WM_SET 2
+#define WM_KEY_LIGHT 0x400
+#define WM_TLED 0x404
+#define WM_FN_LOCK 0x407
+#define WM_BATT_LIMIT 0x61
+#define WM_READER_MODE 0xBF
+#define WM_FAN_MODE 0x33
+#define WMBB_USB_CHARGE 0x10B
+#define WMBB_BATT_LIMIT 0x10C
+
+#define PLATFORM_NAME "lg-laptop"
+
+MODULE_ALIAS("wmi:" WMI_EVENT_GUID0);
+MODULE_ALIAS("wmi:" WMI_EVENT_GUID1);
+MODULE_ALIAS("wmi:" WMI_EVENT_GUID2);
+MODULE_ALIAS("wmi:" WMI_EVENT_GUID3);
+MODULE_ALIAS("wmi:" WMI_METHOD_WMAB);
+MODULE_ALIAS("wmi:" WMI_METHOD_WMBB);
+MODULE_ALIAS("acpi*:LGEX0815:*");
+
+static struct platform_device *pf_device;
+static struct input_dev *wmi_input_dev;
+
+static u32 inited;
+#define INIT_INPUT_WMI_0 0x01
+#define INIT_INPUT_WMI_2 0x02
+#define INIT_INPUT_ACPI 0x04
+#define INIT_TPAD_LED 0x08
+#define INIT_KBD_LED 0x10
+#define INIT_SPARSE_KEYMAP 0x80
+
+static const struct key_entry wmi_keymap[] = {
+ {KE_KEY, 0x70, {KEY_F15} }, /* LG control panel (F1) */
+ {KE_KEY, 0x74, {KEY_F13} }, /* Touchpad toggle (F5) */
+ {KE_KEY, 0xf020000, {KEY_F14} }, /* Read mode (F9) */
+ {KE_KEY, 0x10000000, {KEY_F16} },/* Keyboard backlight (F8) - pressing
+ * this key both sends an event and
+ * changes backlight level.
+ */
+ {KE_KEY, 0x80, {KEY_RFKILL} },
+ {KE_END, 0}
+};
+
+static int ggov(u32 arg0)
+{
+ union acpi_object args[1];
+ union acpi_object *r;
+ acpi_status status;
+ acpi_handle handle;
+ struct acpi_object_list arg;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ int res;
+
+ args[0].type = ACPI_TYPE_INTEGER;
+ args[0].integer.value = arg0;
+
+ status = acpi_get_handle(NULL, (acpi_string) SB_GGOV_METHOD, &handle);
+ if (ACPI_FAILURE(status)) {
+ pr_err("Cannot get handle");
+ return -ENODEV;
+ }
+
+ arg.count = 1;
+ arg.pointer = args;
+
+ status = acpi_evaluate_object(handle, NULL, &arg, &buffer);
+ if (ACPI_FAILURE(status)) {
+ acpi_handle_err(handle, "GGOV: call failed.\n");
+ return -EINVAL;
+ }
+
+ r = buffer.pointer;
+ if (r->type != ACPI_TYPE_INTEGER) {
+ kfree(r);
+ return -EINVAL;
+ }
+
+ res = r->integer.value;
+ kfree(r);
+
+ return res;
+}
+
+static union acpi_object *lg_wmab(u32 method, u32 arg1, u32 arg2)
+{
+ union acpi_object args[3];
+ acpi_status status;
+ acpi_handle handle;
+ struct acpi_object_list arg;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+
+ args[0].type = ACPI_TYPE_INTEGER;
+ args[0].integer.value = method;
+ args[1].type = ACPI_TYPE_INTEGER;
+ args[1].integer.value = arg1;
+ args[2].type = ACPI_TYPE_INTEGER;
+ args[2].integer.value = arg2;
+
+ status = acpi_get_handle(NULL, (acpi_string) WMAB_METHOD, &handle);
+ if (ACPI_FAILURE(status)) {
+ pr_err("Cannot get handle");
+ return NULL;
+ }
+
+ arg.count = 3;
+ arg.pointer = args;
+
+ status = acpi_evaluate_object(handle, NULL, &arg, &buffer);
+ if (ACPI_FAILURE(status)) {
+ acpi_handle_err(handle, "WMAB: call failed.\n");
+ return NULL;
+ }
+
+ return buffer.pointer;
+}
+
+static union acpi_object *lg_wmbb(u32 method_id, u32 arg1, u32 arg2)
+{
+ union acpi_object args[3];
+ acpi_status status;
+ acpi_handle handle;
+ struct acpi_object_list arg;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ u8 buf[32];
+
+ *(u32 *)buf = method_id;
+ *(u32 *)(buf + 4) = arg1;
+ *(u32 *)(buf + 16) = arg2;
+ args[0].type = ACPI_TYPE_INTEGER;
+ args[0].integer.value = 0; /* ignored */
+ args[1].type = ACPI_TYPE_INTEGER;
+ args[1].integer.value = 1; /* Must be 1 or 2. Does not matter which */
+ args[2].type = ACPI_TYPE_BUFFER;
+ args[2].buffer.length = 32;
+ args[2].buffer.pointer = buf;
+
+ status = acpi_get_handle(NULL, (acpi_string)WMBB_METHOD, &handle);
+ if (ACPI_FAILURE(status)) {
+ pr_err("Cannot get handle");
+ return NULL;
+ }
+
+ arg.count = 3;
+ arg.pointer = args;
+
+ status = acpi_evaluate_object(handle, NULL, &arg, &buffer);
+ if (ACPI_FAILURE(status)) {
+ acpi_handle_err(handle, "WMAB: call failed.\n");
+ return NULL;
+ }
+
+ return (union acpi_object *)buffer.pointer;
+}
+
+static void wmi_notify(u32 value, void *context)
+{
+ struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *obj;
+ acpi_status status;
+ long data = (long)context;
+
+ pr_debug("event guid %li\n", data);
+ status = wmi_get_event_data(value, &response);
+ if (ACPI_FAILURE(status)) {
+ pr_err("Bad event status 0x%x\n", status);
+ return;
+ }
+
+ obj = (union acpi_object *)response.pointer;
+ if (!obj)
+ return;
+
+ if (obj->type == ACPI_TYPE_INTEGER) {
+ int eventcode = obj->integer.value;
+ struct key_entry *key;
+
+ key =
+ sparse_keymap_entry_from_scancode(wmi_input_dev, eventcode);
+ if (key && key->type == KE_KEY)
+ sparse_keymap_report_entry(wmi_input_dev, key, 1, true);
+ }
+
+ pr_debug("Type: %i Eventcode: 0x%llx\n", obj->type,
+ obj->integer.value);
+ kfree(response.pointer);
+}
+
+static void wmi_input_setup(void)
+{
+ acpi_status status;
+
+ wmi_input_dev = input_allocate_device();
+ if (wmi_input_dev) {
+ wmi_input_dev->name = "LG WMI hotkeys";
+ wmi_input_dev->phys = "wmi/input0";
+ wmi_input_dev->id.bustype = BUS_HOST;
+
+ if (sparse_keymap_setup(wmi_input_dev, wmi_keymap, NULL) ||
+ input_register_device(wmi_input_dev)) {
+ pr_info("Cannot initialize input device");
+ input_free_device(wmi_input_dev);
+ return;
+ }
+
+ inited |= INIT_SPARSE_KEYMAP;
+ status = wmi_install_notify_handler(WMI_EVENT_GUID0, wmi_notify,
+ (void *)0);
+ if (ACPI_SUCCESS(status))
+ inited |= INIT_INPUT_WMI_0;
+
+ status = wmi_install_notify_handler(WMI_EVENT_GUID2, wmi_notify,
+ (void *)2);
+ if (ACPI_SUCCESS(status))
+ inited |= INIT_INPUT_WMI_2;
+ } else {
+ pr_info("Cannot allocate input device");
+ }
+}
+
+static void acpi_notify(struct acpi_device *device, u32 event)
+{
+ struct key_entry *key;
+
+ acpi_handle_debug(device->handle, "notify: %d\n", event);
+ if (inited & INIT_SPARSE_KEYMAP) {
+ key = sparse_keymap_entry_from_scancode(wmi_input_dev, 0x80);
+ if (key && key->type == KE_KEY)
+ sparse_keymap_report_entry(wmi_input_dev, key, 1, true);
+ }
+}
+
+static ssize_t fan_mode_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buffer, size_t count)
+{
+ bool value;
+ union acpi_object *r;
+ u32 m;
+ int ret;
+
+ ret = kstrtobool(buffer, &value);
+ if (ret)
+ return ret;
+
+ r = lg_wmab(WM_FAN_MODE, WM_GET, 0);
+ if (!r)
+ return -EIO;
+
+ if (r->type != ACPI_TYPE_INTEGER) {
+ kfree(r);
+ return -EIO;
+ }
+
+ m = r->integer.value;
+ kfree(r);
+ r = lg_wmab(WM_FAN_MODE, WM_SET, (m & 0xffffff0f) | (value << 4));
+ kfree(r);
+ r = lg_wmab(WM_FAN_MODE, WM_SET, (m & 0xfffffff0) | value);
+ kfree(r);
+
+ return count;
+}
+
+static ssize_t fan_mode_show(struct device *dev,
+ struct device_attribute *attr, char *buffer)
+{
+ unsigned int status;
+ union acpi_object *r;
+
+ r = lg_wmab(WM_FAN_MODE, WM_GET, 0);
+ if (!r)
+ return -EIO;
+
+ if (r->type != ACPI_TYPE_INTEGER) {
+ kfree(r);
+ return -EIO;
+ }
+
+ status = r->integer.value & 0x01;
+ kfree(r);
+
+ return snprintf(buffer, PAGE_SIZE, "%d\n", status);
+}
+
+static ssize_t usb_charge_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buffer, size_t count)
+{
+ bool value;
+ union acpi_object *r;
+ int ret;
+
+ ret = kstrtobool(buffer, &value);
+ if (ret)
+ return ret;
+
+ r = lg_wmbb(WMBB_USB_CHARGE, WM_SET, value);
+ if (!r)
+ return -EIO;
+
+ kfree(r);
+ return count;
+}
+
+static ssize_t usb_charge_show(struct device *dev,
+ struct device_attribute *attr, char *buffer)
+{
+ unsigned int status;
+ union acpi_object *r;
+
+ r = lg_wmbb(WMBB_USB_CHARGE, WM_GET, 0);
+ if (!r)
+ return -EIO;
+
+ if (r->type != ACPI_TYPE_BUFFER) {
+ kfree(r);
+ return -EIO;
+ }
+
+ status = !!r->buffer.pointer[0x10];
+
+ kfree(r);
+
+ return snprintf(buffer, PAGE_SIZE, "%d\n", status);
+}
+
+static ssize_t reader_mode_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buffer, size_t count)
+{
+ bool value;
+ union acpi_object *r;
+ int ret;
+
+ ret = kstrtobool(buffer, &value);
+ if (ret)
+ return ret;
+
+ r = lg_wmab(WM_READER_MODE, WM_SET, value);
+ if (!r)
+ return -EIO;
+
+ kfree(r);
+ return count;
+}
+
+static ssize_t reader_mode_show(struct device *dev,
+ struct device_attribute *attr, char *buffer)
+{
+ unsigned int status;
+ union acpi_object *r;
+
+ r = lg_wmab(WM_READER_MODE, WM_GET, 0);
+ if (!r)
+ return -EIO;
+
+ if (r->type != ACPI_TYPE_INTEGER) {
+ kfree(r);
+ return -EIO;
+ }
+
+ status = !!r->integer.value;
+
+ kfree(r);
+
+ return snprintf(buffer, PAGE_SIZE, "%d\n", status);
+}
+
+static ssize_t fn_lock_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buffer, size_t count)
+{
+ bool value;
+ union acpi_object *r;
+ int ret;
+
+ ret = kstrtobool(buffer, &value);
+ if (ret)
+ return ret;
+
+ r = lg_wmab(WM_FN_LOCK, WM_SET, value);
+ if (!r)
+ return -EIO;
+
+ kfree(r);
+ return count;
+}
+
+static ssize_t fn_lock_show(struct device *dev,
+ struct device_attribute *attr, char *buffer)
+{
+ unsigned int status;
+ union acpi_object *r;
+
+ r = lg_wmab(WM_FN_LOCK, WM_GET, 0);
+ if (!r)
+ return -EIO;
+
+ if (r->type != ACPI_TYPE_BUFFER) {
+ kfree(r);
+ return -EIO;
+ }
+
+ status = !!r->buffer.pointer[0];
+ kfree(r);
+
+ return snprintf(buffer, PAGE_SIZE, "%d\n", status);
+}
+
+static ssize_t battery_care_limit_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buffer, size_t count)
+{
+ unsigned long value;
+ int ret;
+
+ ret = kstrtoul(buffer, 10, &value);
+ if (ret)
+ return ret;
+
+ if (value == 100 || value == 80) {
+ union acpi_object *r;
+
+ r = lg_wmab(WM_BATT_LIMIT, WM_SET, value);
+ if (!r)
+ return -EIO;
+
+ kfree(r);
+ return count;
+ }
+
+ return -EINVAL;
+}
+
+static ssize_t battery_care_limit_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buffer)
+{
+ unsigned int status;
+ union acpi_object *r;
+
+ r = lg_wmab(WM_BATT_LIMIT, WM_GET, 0);
+ if (!r)
+ return -EIO;
+
+ if (r->type != ACPI_TYPE_INTEGER) {
+ kfree(r);
+ return -EIO;
+ }
+
+ status = r->integer.value;
+ kfree(r);
+ if (status != 80 && status != 100)
+ status = 0;
+
+ return snprintf(buffer, PAGE_SIZE, "%d\n", status);
+}
+
+static DEVICE_ATTR_RW(fan_mode);
+static DEVICE_ATTR_RW(usb_charge);
+static DEVICE_ATTR_RW(reader_mode);
+static DEVICE_ATTR_RW(fn_lock);
+static DEVICE_ATTR_RW(battery_care_limit);
+
+static struct attribute *dev_attributes[] = {
+ &dev_attr_fan_mode.attr,
+ &dev_attr_usb_charge.attr,
+ &dev_attr_reader_mode.attr,
+ &dev_attr_fn_lock.attr,
+ &dev_attr_battery_care_limit.attr,
+ NULL
+};
+
+static const struct attribute_group dev_attribute_group = {
+ .attrs = dev_attributes,
+};
+
+static void tpad_led_set(struct led_classdev *cdev,
+ enum led_brightness brightness)
+{
+ union acpi_object *r;
+
+ r = lg_wmab(WM_TLED, WM_SET, brightness > LED_OFF);
+ kfree(r);
+}
+
+static enum led_brightness tpad_led_get(struct led_classdev *cdev)
+{
+ return ggov(GOV_TLED) > 0 ? LED_ON : LED_OFF;
+}
+
+static LED_DEVICE(tpad_led, 1);
+
+static void kbd_backlight_set(struct led_classdev *cdev,
+ enum led_brightness brightness)
+{
+ u32 val;
+ union acpi_object *r;
+
+ val = 0x22;
+ if (brightness <= LED_OFF)
+ val = 0;
+ if (brightness >= LED_FULL)
+ val = 0x24;
+ r = lg_wmab(WM_KEY_LIGHT, WM_SET, val);
+ kfree(r);
+}
+
+static enum led_brightness kbd_backlight_get(struct led_classdev *cdev)
+{
+ union acpi_object *r;
+ int val;
+
+ r = lg_wmab(WM_KEY_LIGHT, WM_GET, 0);
+
+ if (!r)
+ return LED_OFF;
+
+ if (r->type != ACPI_TYPE_BUFFER || r->buffer.pointer[1] != 0x05) {
+ kfree(r);
+ return LED_OFF;
+ }
+
+ switch (r->buffer.pointer[0] & 0x27) {
+ case 0x24:
+ val = LED_FULL;
+ break;
+ case 0x22:
+ val = LED_HALF;
+ break;
+ default:
+ val = LED_OFF;
+ }
+
+ kfree(r);
+
+ return val;
+}
+
+static LED_DEVICE(kbd_backlight, 255);
+
+static void wmi_input_destroy(void)
+{
+ if (inited & INIT_INPUT_WMI_2)
+ wmi_remove_notify_handler(WMI_EVENT_GUID2);
+
+ if (inited & INIT_INPUT_WMI_0)
+ wmi_remove_notify_handler(WMI_EVENT_GUID0);
+
+ if (inited & INIT_SPARSE_KEYMAP)
+ input_unregister_device(wmi_input_dev);
+
+ inited &= ~(INIT_INPUT_WMI_0 | INIT_INPUT_WMI_2 | INIT_SPARSE_KEYMAP);
+}
+
+static struct platform_driver pf_driver = {
+ .driver = {
+ .name = PLATFORM_NAME,
+ }
+};
+
+static int acpi_add(struct acpi_device *device)
+{
+ int ret;
+
+ if (pf_device)
+ return 0;
+
+ ret = platform_driver_register(&pf_driver);
+ if (ret)
+ return ret;
+
+ pf_device = platform_device_register_simple(PLATFORM_NAME,
+ PLATFORM_DEVID_NONE,
+ NULL, 0);
+ if (IS_ERR(pf_device)) {
+ ret = PTR_ERR(pf_device);
+ pf_device = NULL;
+ pr_err("unable to register platform device\n");
+ goto out_platform_registered;
+ }
+
+ ret = sysfs_create_group(&pf_device->dev.kobj, &dev_attribute_group);
+ if (ret)
+ goto out_platform_device;
+
+ if (!led_classdev_register(&pf_device->dev, &kbd_backlight))
+ inited |= INIT_KBD_LED;
+
+ if (!led_classdev_register(&pf_device->dev, &tpad_led))
+ inited |= INIT_TPAD_LED;
+
+ wmi_input_setup();
+
+ return 0;
+
+out_platform_device:
+ platform_device_unregister(pf_device);
+out_platform_registered:
+ platform_driver_unregister(&pf_driver);
+ return ret;
+}
+
+static int acpi_remove(struct acpi_device *device)
+{
+ sysfs_remove_group(&pf_device->dev.kobj, &dev_attribute_group);
+ if (inited & INIT_KBD_LED)
+ led_classdev_unregister(&kbd_backlight);
+
+ if (inited & INIT_TPAD_LED)
+ led_classdev_unregister(&tpad_led);
+
+ wmi_input_destroy();
+ platform_device_unregister(pf_device);
+ pf_device = NULL;
+ platform_driver_unregister(&pf_driver);
+
+ return 0;
+}
+
+static const struct acpi_device_id device_ids[] = {
+ {"LGEX0815", 0},
+ {"", 0}
+};
+MODULE_DEVICE_TABLE(acpi, device_ids);
+
+static struct acpi_driver acpi_driver = {
+ .name = "LG Gram Laptop Support",
+ .class = "lg-laptop",
+ .ids = device_ids,
+ .ops = {
+ .add = acpi_add,
+ .remove = acpi_remove,
+ .notify = acpi_notify,
+ },
+ .owner = THIS_MODULE,
+};
+
+static int __init acpi_init(void)
+{
+ int result;
+
+ result = acpi_bus_register_driver(&acpi_driver);
+ if (result < 0) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error registering driver\n"));
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void __exit acpi_exit(void)
+{
+ acpi_bus_unregister_driver(&acpi_driver);
+}
+
+module_init(acpi_init);
+module_exit(acpi_exit);
diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c
index d89936c93ba0..c2c3a1a19879 100644
--- a/drivers/platform/x86/mlx-platform.c
+++ b/drivers/platform/x86/mlx-platform.c
@@ -575,7 +575,7 @@ static struct mlxreg_core_item mlxplat_mlxcpld_msn201x_items[] = {
static
struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn201x_data = {
- .items = mlxplat_mlxcpld_msn21xx_items,
+ .items = mlxplat_mlxcpld_msn201x_items,
.counter = ARRAY_SIZE(mlxplat_mlxcpld_msn201x_items),
.cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
.mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
diff --git a/drivers/platform/x86/touchscreen_dmi.c b/drivers/platform/x86/touchscreen_dmi.c
index cb204f973491..5f2d7ea912b5 100644
--- a/drivers/platform/x86/touchscreen_dmi.c
+++ b/drivers/platform/x86/touchscreen_dmi.c
@@ -42,10 +42,13 @@ static const struct ts_dmi_data chuwi_hi8_data = {
};
static const struct property_entry chuwi_hi8_pro_props[] = {
+ PROPERTY_ENTRY_U32("touchscreen-min-x", 6),
+ PROPERTY_ENTRY_U32("touchscreen-min-y", 3),
PROPERTY_ENTRY_U32("touchscreen-size-x", 1728),
PROPERTY_ENTRY_U32("touchscreen-size-y", 1148),
PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
PROPERTY_ENTRY_STRING("firmware-name", "gsl3680-chuwi-hi8-pro.fw"),
+ PROPERTY_ENTRY_U32("silead,max-fingers", 10),
PROPERTY_ENTRY_BOOL("silead,home-button"),
{ }
};
@@ -56,6 +59,8 @@ static const struct ts_dmi_data chuwi_hi8_pro_data = {
};
static const struct property_entry chuwi_vi8_props[] = {
+ PROPERTY_ENTRY_U32("touchscreen-min-x", 4),
+ PROPERTY_ENTRY_U32("touchscreen-min-y", 6),
PROPERTY_ENTRY_U32("touchscreen-size-x", 1724),
PROPERTY_ENTRY_U32("touchscreen-size-y", 1140),
PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
@@ -88,9 +93,9 @@ static const struct ts_dmi_data chuwi_vi10_data = {
static const struct property_entry connect_tablet9_props[] = {
PROPERTY_ENTRY_U32("touchscreen-min-x", 9),
- PROPERTY_ENTRY_U32("touchscreen-min-y", 8),
+ PROPERTY_ENTRY_U32("touchscreen-min-y", 10),
PROPERTY_ENTRY_U32("touchscreen-size-x", 1664),
- PROPERTY_ENTRY_U32("touchscreen-size-y", 878),
+ PROPERTY_ENTRY_U32("touchscreen-size-y", 880),
PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-connect-tablet9.fw"),
@@ -104,8 +109,10 @@ static const struct ts_dmi_data connect_tablet9_data = {
};
static const struct property_entry cube_iwork8_air_props[] = {
- PROPERTY_ENTRY_U32("touchscreen-size-x", 1660),
- PROPERTY_ENTRY_U32("touchscreen-size-y", 900),
+ PROPERTY_ENTRY_U32("touchscreen-min-x", 1),
+ PROPERTY_ENTRY_U32("touchscreen-min-y", 3),
+ PROPERTY_ENTRY_U32("touchscreen-size-x", 1664),
+ PROPERTY_ENTRY_U32("touchscreen-size-y", 896),
PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
PROPERTY_ENTRY_STRING("firmware-name", "gsl3670-cube-iwork8-air.fw"),
PROPERTY_ENTRY_U32("silead,max-fingers", 10),
@@ -179,11 +186,14 @@ static const struct ts_dmi_data gp_electronic_t701_data = {
};
static const struct property_entry itworks_tw891_props[] = {
+ PROPERTY_ENTRY_U32("touchscreen-min-x", 1),
+ PROPERTY_ENTRY_U32("touchscreen-min-y", 5),
PROPERTY_ENTRY_U32("touchscreen-size-x", 1600),
- PROPERTY_ENTRY_U32("touchscreen-size-y", 890),
+ PROPERTY_ENTRY_U32("touchscreen-size-y", 896),
PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
PROPERTY_ENTRY_STRING("firmware-name", "gsl3670-itworks-tw891.fw"),
+ PROPERTY_ENTRY_U32("silead,max-fingers", 10),
{ }
};
@@ -207,8 +217,10 @@ static const struct ts_dmi_data jumper_ezpad_6_pro_data = {
};
static const struct property_entry jumper_ezpad_mini3_props[] = {
+ PROPERTY_ENTRY_U32("touchscreen-min-x", 23),
+ PROPERTY_ENTRY_U32("touchscreen-min-y", 16),
PROPERTY_ENTRY_U32("touchscreen-size-x", 1700),
- PROPERTY_ENTRY_U32("touchscreen-size-y", 1150),
+ PROPERTY_ENTRY_U32("touchscreen-size-y", 1138),
PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
PROPERTY_ENTRY_STRING("firmware-name", "gsl3676-jumper-ezpad-mini3.fw"),
PROPERTY_ENTRY_U32("silead,max-fingers", 10),
@@ -237,6 +249,24 @@ static const struct ts_dmi_data onda_obook_20_plus_data = {
.properties = onda_obook_20_plus_props,
};
+static const struct property_entry onda_v80_plus_v3_props[] = {
+ PROPERTY_ENTRY_U32("touchscreen-min-x", 22),
+ PROPERTY_ENTRY_U32("touchscreen-min-y", 15),
+ PROPERTY_ENTRY_U32("touchscreen-size-x", 1698),
+ PROPERTY_ENTRY_U32("touchscreen-size-y", 1140),
+ PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
+ PROPERTY_ENTRY_STRING("firmware-name",
+ "gsl3676-onda-v80-plus-v3.fw"),
+ PROPERTY_ENTRY_U32("silead,max-fingers", 10),
+ PROPERTY_ENTRY_BOOL("silead,home-button"),
+ { }
+};
+
+static const struct ts_dmi_data onda_v80_plus_v3_data = {
+ .acpi_name = "MSSL1680:00",
+ .properties = onda_v80_plus_v3_props,
+};
+
static const struct property_entry onda_v820w_32g_props[] = {
PROPERTY_ENTRY_U32("touchscreen-size-x", 1665),
PROPERTY_ENTRY_U32("touchscreen-size-y", 1140),
@@ -322,11 +352,14 @@ static const struct ts_dmi_data pov_mobii_wintab_p800w_v20_data = {
};
static const struct property_entry pov_mobii_wintab_p800w_v21_props[] = {
- PROPERTY_ENTRY_U32("touchscreen-size-x", 1800),
- PROPERTY_ENTRY_U32("touchscreen-size-y", 1150),
+ PROPERTY_ENTRY_U32("touchscreen-min-x", 1),
+ PROPERTY_ENTRY_U32("touchscreen-min-y", 8),
+ PROPERTY_ENTRY_U32("touchscreen-size-x", 1794),
+ PROPERTY_ENTRY_U32("touchscreen-size-y", 1148),
PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
PROPERTY_ENTRY_STRING("firmware-name",
"gsl3692-pov-mobii-wintab-p800w.fw"),
+ PROPERTY_ENTRY_U32("silead,max-fingers", 10),
PROPERTY_ENTRY_BOOL("silead,home-button"),
{ }
};
@@ -366,6 +399,22 @@ static const struct ts_dmi_data teclast_x98plus2_data = {
.properties = teclast_x98plus2_props,
};
+static const struct property_entry trekstor_primebook_c11_props[] = {
+ PROPERTY_ENTRY_U32("touchscreen-size-x", 1970),
+ PROPERTY_ENTRY_U32("touchscreen-size-y", 1530),
+ PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
+ PROPERTY_ENTRY_STRING("firmware-name",
+ "gsl1680-trekstor-primebook-c11.fw"),
+ PROPERTY_ENTRY_U32("silead,max-fingers", 10),
+ PROPERTY_ENTRY_BOOL("silead,home-button"),
+ { }
+};
+
+static const struct ts_dmi_data trekstor_primebook_c11_data = {
+ .acpi_name = "MSSL1680:00",
+ .properties = trekstor_primebook_c11_props,
+};
+
static const struct property_entry trekstor_primebook_c13_props[] = {
PROPERTY_ENTRY_U32("touchscreen-size-x", 2624),
PROPERTY_ENTRY_U32("touchscreen-size-y", 1920),
@@ -381,6 +430,22 @@ static const struct ts_dmi_data trekstor_primebook_c13_data = {
.properties = trekstor_primebook_c13_props,
};
+static const struct property_entry trekstor_primetab_t13b_props[] = {
+ PROPERTY_ENTRY_U32("touchscreen-size-x", 2500),
+ PROPERTY_ENTRY_U32("touchscreen-size-y", 1900),
+ PROPERTY_ENTRY_STRING("firmware-name",
+ "gsl1680-trekstor-primetab-t13b.fw"),
+ PROPERTY_ENTRY_U32("silead,max-fingers", 10),
+ PROPERTY_ENTRY_BOOL("silead,home-button"),
+ PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
+ { }
+};
+
+static const struct ts_dmi_data trekstor_primetab_t13b_data = {
+ .acpi_name = "MSSL1680:00",
+ .properties = trekstor_primetab_t13b_props,
+};
+
static const struct property_entry trekstor_surftab_twin_10_1_props[] = {
PROPERTY_ENTRY_U32("touchscreen-size-x", 1900),
PROPERTY_ENTRY_U32("touchscreen-size-y", 1280),
@@ -397,6 +462,8 @@ static const struct ts_dmi_data trekstor_surftab_twin_10_1_data = {
};
static const struct property_entry trekstor_surftab_wintron70_props[] = {
+ PROPERTY_ENTRY_U32("touchscreen-min-x", 12),
+ PROPERTY_ENTRY_U32("touchscreen-min-y", 8),
PROPERTY_ENTRY_U32("touchscreen-size-x", 884),
PROPERTY_ENTRY_U32("touchscreen-size-y", 632),
PROPERTY_ENTRY_STRING("firmware-name",
@@ -556,6 +623,14 @@ static const struct dmi_system_id touchscreen_dmi_table[] = {
},
},
{
+ /* ONDA V80 plus v3 (P80PSBG9V3A01501) */
+ .driver_data = (void *)&onda_v80_plus_v3_data,
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ONDA"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "V80 PLUS")
+ },
+ },
+ {
/* ONDA V820w DualOS */
.driver_data = (void *)&onda_v820w_32g_data,
.matches = {
@@ -641,6 +716,14 @@ static const struct dmi_system_id touchscreen_dmi_table[] = {
},
},
{
+ /* Trekstor Primebook C11 */
+ .driver_data = (void *)&trekstor_primebook_c11_data,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TREKSTOR"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Primebook C11"),
+ },
+ },
+ {
/* Trekstor Primebook C13 */
.driver_data = (void *)&trekstor_primebook_c13_data,
.matches = {
@@ -649,6 +732,14 @@ static const struct dmi_system_id touchscreen_dmi_table[] = {
},
},
{
+ /* Trekstor Primetab T13B */
+ .driver_data = (void *)&trekstor_primetab_t13b_data,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TREKSTOR"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Primetab T13B"),
+ },
+ },
+ {
/* TrekStor SurfTab twin 10.1 ST10432-8 */
.driver_data = (void *)&trekstor_surftab_twin_10_1_data,
.matches = {
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
index 04791ea5d97b..bea35be68706 100644
--- a/drivers/platform/x86/wmi.c
+++ b/drivers/platform/x86/wmi.c
@@ -987,19 +987,19 @@ static struct bus_type wmi_bus_type = {
.remove = wmi_dev_remove,
};
-static struct device_type wmi_type_event = {
+static const struct device_type wmi_type_event = {
.name = "event",
.groups = wmi_event_groups,
.release = wmi_dev_release,
};
-static struct device_type wmi_type_method = {
+static const struct device_type wmi_type_method = {
.name = "method",
.groups = wmi_method_groups,
.release = wmi_dev_release,
};
-static struct device_type wmi_type_data = {
+static const struct device_type wmi_type_data = {
.name = "data",
.groups = wmi_data_groups,
.release = wmi_dev_release,
diff --git a/drivers/power/reset/at91-sama5d2_shdwc.c b/drivers/power/reset/at91-sama5d2_shdwc.c
index 0206cce328b3..2b686c55b717 100644
--- a/drivers/power/reset/at91-sama5d2_shdwc.c
+++ b/drivers/power/reset/at91-sama5d2_shdwc.c
@@ -19,6 +19,7 @@
*/
#include <linux/clk.h>
+#include <linux/clk/at91_pmc.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -69,7 +70,10 @@ struct shdwc_config {
struct shdwc {
const struct shdwc_config *cfg;
- void __iomem *at91_shdwc_base;
+ struct clk *sclk;
+ void __iomem *shdwc_base;
+ void __iomem *mpddrc_base;
+ void __iomem *pmc_base;
};
/*
@@ -77,8 +81,6 @@ struct shdwc {
* since pm_power_off itself is global.
*/
static struct shdwc *at91_shdwc;
-static struct clk *sclk;
-static void __iomem *mpddrc_base;
static const unsigned long long sdwc_dbc_period[] = {
0, 3, 32, 512, 4096, 32768,
@@ -90,7 +92,7 @@ static void __init at91_wakeup_status(struct platform_device *pdev)
u32 reg;
char *reason = "unknown";
- reg = readl(shdw->at91_shdwc_base + AT91_SHDW_SR);
+ reg = readl(shdw->shdwc_base + AT91_SHDW_SR);
dev_dbg(&pdev->dev, "%s: status = %#x\n", __func__, reg);
@@ -108,12 +110,6 @@ static void __init at91_wakeup_status(struct platform_device *pdev)
static void at91_poweroff(void)
{
- writel(AT91_SHDW_KEY | AT91_SHDW_SHDW,
- at91_shdwc->at91_shdwc_base + AT91_SHDW_CR);
-}
-
-static void at91_lpddr_poweroff(void)
-{
asm volatile(
/* Align to cache lines */
".balign 32\n\t"
@@ -122,16 +118,29 @@ static void at91_lpddr_poweroff(void)
" ldr r6, [%2, #" __stringify(AT91_SHDW_CR) "]\n\t"
/* Power down SDRAM0 */
+ " tst %0, #0\n\t"
+ " beq 1f\n\t"
" str %1, [%0, #" __stringify(AT91_DDRSDRC_LPR) "]\n\t"
+
+ /* Switch the master clock source to slow clock. */
+ "1: ldr r6, [%4, #" __stringify(AT91_PMC_MCKR) "]\n\t"
+ " bic r6, r6, #" __stringify(AT91_PMC_CSS) "\n\t"
+ " str r6, [%4, #" __stringify(AT91_PMC_MCKR) "]\n\t"
+ /* Wait for clock switch. */
+ "2: ldr r6, [%4, #" __stringify(AT91_PMC_SR) "]\n\t"
+ " tst r6, #" __stringify(AT91_PMC_MCKRDY) "\n\t"
+ " beq 2b\n\t"
+
/* Shutdown CPU */
" str %3, [%2, #" __stringify(AT91_SHDW_CR) "]\n\t"
" b .\n\t"
:
- : "r" (mpddrc_base),
+ : "r" (at91_shdwc->mpddrc_base),
"r" cpu_to_le32(AT91_DDRSDRC_LPDDR2_PWOFF),
- "r" (at91_shdwc->at91_shdwc_base),
- "r" cpu_to_le32(AT91_SHDW_KEY | AT91_SHDW_SHDW)
+ "r" (at91_shdwc->shdwc_base),
+ "r" cpu_to_le32(AT91_SHDW_KEY | AT91_SHDW_SHDW),
+ "r" (at91_shdwc->pmc_base)
: "r6");
}
@@ -213,10 +222,10 @@ static void at91_shdwc_dt_configure(struct platform_device *pdev)
mode |= SHDW_RTCWKEN(shdw->cfg);
dev_dbg(&pdev->dev, "%s: mode = %#x\n", __func__, mode);
- writel(mode, shdw->at91_shdwc_base + AT91_SHDW_MR);
+ writel(mode, shdw->shdwc_base + AT91_SHDW_MR);
input = at91_shdwc_get_wakeup_input(pdev, np);
- writel(input, shdw->at91_shdwc_base + AT91_SHDW_WUIR);
+ writel(input, shdw->shdwc_base + AT91_SHDW_WUIR);
}
static const struct shdwc_config sama5d2_shdwc_config = {
@@ -246,6 +255,9 @@ static int __init at91_shdwc_probe(struct platform_device *pdev)
if (!pdev->dev.of_node)
return -ENODEV;
+ if (at91_shdwc)
+ return -EBUSY;
+
at91_shdwc = devm_kzalloc(&pdev->dev, sizeof(*at91_shdwc), GFP_KERNEL);
if (!at91_shdwc)
return -ENOMEM;
@@ -253,20 +265,20 @@ static int __init at91_shdwc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, at91_shdwc);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- at91_shdwc->at91_shdwc_base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(at91_shdwc->at91_shdwc_base)) {
+ 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");
- return PTR_ERR(at91_shdwc->at91_shdwc_base);
+ return PTR_ERR(at91_shdwc->shdwc_base);
}
match = of_match_node(at91_shdwc_of_match, pdev->dev.of_node);
at91_shdwc->cfg = match->data;
- sclk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(sclk))
- return PTR_ERR(sclk);
+ at91_shdwc->sclk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(at91_shdwc->sclk))
+ return PTR_ERR(at91_shdwc->sclk);
- ret = clk_prepare_enable(sclk);
+ ret = clk_prepare_enable(at91_shdwc->sclk);
if (ret) {
dev_err(&pdev->dev, "Could not enable slow clock\n");
return ret;
@@ -276,41 +288,70 @@ static int __init at91_shdwc_probe(struct platform_device *pdev)
at91_shdwc_dt_configure(pdev);
- pm_power_off = at91_poweroff;
+ np = of_find_compatible_node(NULL, NULL, "atmel,sama5d2-pmc");
+ if (!np) {
+ ret = -ENODEV;
+ goto clk_disable;
+ }
+
+ at91_shdwc->pmc_base = of_iomap(np, 0);
+ of_node_put(np);
+
+ if (!at91_shdwc->pmc_base) {
+ ret = -ENOMEM;
+ goto clk_disable;
+ }
np = of_find_compatible_node(NULL, NULL, "atmel,sama5d3-ddramc");
- if (!np)
- return 0;
+ if (!np) {
+ ret = -ENODEV;
+ goto unmap;
+ }
- mpddrc_base = of_iomap(np, 0);
+ at91_shdwc->mpddrc_base = of_iomap(np, 0);
of_node_put(np);
- if (!mpddrc_base)
- return 0;
+ if (!at91_shdwc->mpddrc_base) {
+ ret = -ENOMEM;
+ goto unmap;
+ }
- ddr_type = readl(mpddrc_base + AT91_DDRSDRC_MDR) & AT91_DDRSDRC_MD;
- if ((ddr_type == AT91_DDRSDRC_MD_LPDDR2) ||
- (ddr_type == AT91_DDRSDRC_MD_LPDDR3))
- pm_power_off = at91_lpddr_poweroff;
- else
- iounmap(mpddrc_base);
+ pm_power_off = at91_poweroff;
+
+ ddr_type = readl(at91_shdwc->mpddrc_base + AT91_DDRSDRC_MDR) &
+ AT91_DDRSDRC_MD;
+ if (ddr_type != AT91_DDRSDRC_MD_LPDDR2 &&
+ ddr_type != AT91_DDRSDRC_MD_LPDDR3) {
+ iounmap(at91_shdwc->mpddrc_base);
+ at91_shdwc->mpddrc_base = NULL;
+ }
return 0;
+
+unmap:
+ iounmap(at91_shdwc->pmc_base);
+clk_disable:
+ clk_disable_unprepare(at91_shdwc->sclk);
+
+ return ret;
}
static int __exit at91_shdwc_remove(struct platform_device *pdev)
{
struct shdwc *shdw = platform_get_drvdata(pdev);
- if (pm_power_off == at91_poweroff ||
- pm_power_off == at91_lpddr_poweroff)
+ if (pm_power_off == at91_poweroff)
pm_power_off = NULL;
/* Reset values to disable wake-up features */
- writel(0, shdw->at91_shdwc_base + AT91_SHDW_MR);
- writel(0, shdw->at91_shdwc_base + AT91_SHDW_WUIR);
+ writel(0, shdw->shdwc_base + AT91_SHDW_MR);
+ writel(0, shdw->shdwc_base + AT91_SHDW_WUIR);
+
+ if (shdw->mpddrc_base)
+ iounmap(shdw->mpddrc_base);
+ iounmap(shdw->pmc_base);
- clk_disable_unprepare(sclk);
+ clk_disable_unprepare(shdw->sclk);
return 0;
}
diff --git a/drivers/power/reset/qcom-pon.c b/drivers/power/reset/qcom-pon.c
index 0c4caaa7e88f..3fa1642d4c54 100644
--- a/drivers/power/reset/qcom-pon.c
+++ b/drivers/power/reset/qcom-pon.c
@@ -74,6 +74,7 @@ static int pm8916_pon_probe(struct platform_device *pdev)
static const struct of_device_id pm8916_pon_id_table[] = {
{ .compatible = "qcom,pm8916-pon" },
+ { .compatible = "qcom,pms405-pon" },
{ }
};
MODULE_DEVICE_TABLE(of, pm8916_pon_id_table);
diff --git a/drivers/power/reset/rmobile-reset.c b/drivers/power/reset/rmobile-reset.c
index e6569df76941..bd3b396558e0 100644
--- a/drivers/power/reset/rmobile-reset.c
+++ b/drivers/power/reset/rmobile-reset.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Renesas R-Mobile Reset Driver
*
* Copyright (C) 2014 Glider bvba
- *
- * 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/io.h>
diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index ff6dab0bf0dd..f27cf0709500 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -645,4 +645,11 @@ config CHARGER_CROS_USBPD
what is connected to USB PD ports from the EC and converts
that into power_supply properties.
+config CHARGER_SC2731
+ tristate "Spreadtrum SC2731 charger driver"
+ depends on MFD_SC27XX_PMIC || COMPILE_TEST
+ help
+ Say Y here to enable support for battery charging with SC2731
+ PMIC chips.
+
endif # POWER_SUPPLY
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index a26b402c45d9..767105b88d00 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -85,3 +85,4 @@ obj-$(CONFIG_CHARGER_TPS65217) += tps65217_charger.o
obj-$(CONFIG_AXP288_FUEL_GAUGE) += axp288_fuel_gauge.o
obj-$(CONFIG_AXP288_CHARGER) += axp288_charger.o
obj-$(CONFIG_CHARGER_CROS_USBPD) += cros_usbpd-charger.o
+obj-$(CONFIG_CHARGER_SC2731) += sc2731_charger.o
diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c
index 02356f9b5f22..776102c31305 100644
--- a/drivers/power/supply/ab8500_fg.c
+++ b/drivers/power/supply/ab8500_fg.c
@@ -2433,17 +2433,14 @@ static ssize_t charge_full_store(struct ab8500_fg *di, const char *buf,
size_t count)
{
unsigned long charge_full;
- ssize_t ret;
+ int ret;
ret = kstrtoul(buf, 10, &charge_full);
+ if (ret)
+ return ret;
- dev_dbg(di->dev, "Ret %zd charge_full %lu", ret, charge_full);
-
- if (!ret) {
- di->bat_cap.max_mah = (int) charge_full;
- ret = count;
- }
- return ret;
+ di->bat_cap.max_mah = (int) charge_full;
+ return count;
}
static ssize_t charge_now_show(struct ab8500_fg *di, char *buf)
@@ -2455,20 +2452,16 @@ static ssize_t charge_now_store(struct ab8500_fg *di, const char *buf,
size_t count)
{
unsigned long charge_now;
- ssize_t ret;
+ int ret;
ret = kstrtoul(buf, 10, &charge_now);
+ if (ret)
+ return ret;
- dev_dbg(di->dev, "Ret %zd charge_now %lu was %d",
- ret, charge_now, di->bat_cap.prev_mah);
-
- if (!ret) {
- di->bat_cap.user_mah = (int) charge_now;
- di->flags.user_cap = true;
- ret = count;
- queue_delayed_work(di->fg_wq, &di->fg_periodic_work, 0);
- }
- return ret;
+ di->bat_cap.user_mah = (int) charge_now;
+ di->flags.user_cap = true;
+ queue_delayed_work(di->fg_wq, &di->fg_periodic_work, 0);
+ return count;
}
static struct ab8500_fg_sysfs_entry charge_full_attr =
@@ -2582,11 +2575,12 @@ static ssize_t ab8505_powercut_flagtime_write(struct device *dev,
const char *buf, size_t count)
{
int ret;
- long unsigned reg_value;
+ int reg_value;
struct power_supply *psy = dev_get_drvdata(dev);
struct ab8500_fg *di = power_supply_get_drvdata(psy);
- reg_value = simple_strtoul(buf, NULL, 10);
+ if (kstrtoint(buf, 10, &reg_value))
+ goto fail;
if (reg_value > 0x7F) {
dev_err(dev, "Incorrect parameter, echo 0 (1.98s) - 127 (15.625ms) for flagtime\n");
@@ -2636,7 +2630,9 @@ static ssize_t ab8505_powercut_maxtime_write(struct device *dev,
struct power_supply *psy = dev_get_drvdata(dev);
struct ab8500_fg *di = power_supply_get_drvdata(psy);
- reg_value = simple_strtoul(buf, NULL, 10);
+ if (kstrtoint(buf, 10, &reg_value))
+ goto fail;
+
if (reg_value > 0x7F) {
dev_err(dev, "Incorrect parameter, echo 0 (0.0s) - 127 (1.98s) for maxtime\n");
goto fail;
@@ -2684,7 +2680,9 @@ static ssize_t ab8505_powercut_restart_write(struct device *dev,
struct power_supply *psy = dev_get_drvdata(dev);
struct ab8500_fg *di = power_supply_get_drvdata(psy);
- reg_value = simple_strtoul(buf, NULL, 10);
+ if (kstrtoint(buf, 10, &reg_value))
+ goto fail;
+
if (reg_value > 0xF) {
dev_err(dev, "Incorrect parameter, echo 0 - 15 for number of restart\n");
goto fail;
@@ -2777,7 +2775,9 @@ static ssize_t ab8505_powercut_write(struct device *dev,
struct power_supply *psy = dev_get_drvdata(dev);
struct ab8500_fg *di = power_supply_get_drvdata(psy);
- reg_value = simple_strtoul(buf, NULL, 10);
+ if (kstrtoint(buf, 10, &reg_value))
+ goto fail;
+
if (reg_value > 0x1) {
dev_err(dev, "Incorrect parameter, echo 0/1 to disable/enable Pcut feature\n");
goto fail;
@@ -2849,7 +2849,9 @@ static ssize_t ab8505_powercut_debounce_write(struct device *dev,
struct power_supply *psy = dev_get_drvdata(dev);
struct ab8500_fg *di = power_supply_get_drvdata(psy);
- reg_value = simple_strtoul(buf, NULL, 10);
+ if (kstrtoint(buf, 10, &reg_value))
+ goto fail;
+
if (reg_value > 0x7) {
dev_err(dev, "Incorrect parameter, echo 0 to 7 for debounce setting\n");
goto fail;
diff --git a/drivers/power/supply/bq25890_charger.c b/drivers/power/supply/bq25890_charger.c
index 8e2c41ded171..70b90db5ae38 100644
--- a/drivers/power/supply/bq25890_charger.c
+++ b/drivers/power/supply/bq25890_charger.c
@@ -32,6 +32,7 @@
#define BQ25890_IRQ_PIN "bq25890_irq"
#define BQ25890_ID 3
+#define BQ25896_ID 0
enum bq25890_fields {
F_EN_HIZ, F_EN_ILIM, F_IILIM, /* Reg00 */
@@ -153,8 +154,8 @@ static const struct reg_field bq25890_reg_fields[] = {
[F_CONV_RATE] = REG_FIELD(0x02, 6, 6),
[F_BOOSTF] = REG_FIELD(0x02, 5, 5),
[F_ICO_EN] = REG_FIELD(0x02, 4, 4),
- [F_HVDCP_EN] = REG_FIELD(0x02, 3, 3),
- [F_MAXC_EN] = REG_FIELD(0x02, 2, 2),
+ [F_HVDCP_EN] = REG_FIELD(0x02, 3, 3), // reserved on BQ25896
+ [F_MAXC_EN] = REG_FIELD(0x02, 2, 2), // reserved on BQ25896
[F_FORCE_DPM] = REG_FIELD(0x02, 1, 1),
[F_AUTO_DPDM_EN] = REG_FIELD(0x02, 0, 0),
/* REG03 */
@@ -163,6 +164,7 @@ static const struct reg_field bq25890_reg_fields[] = {
[F_OTG_CFG] = REG_FIELD(0x03, 5, 5),
[F_CHG_CFG] = REG_FIELD(0x03, 4, 4),
[F_SYSVMIN] = REG_FIELD(0x03, 1, 3),
+ /* MIN_VBAT_SEL on BQ25896 */
/* REG04 */
[F_PUMPX_EN] = REG_FIELD(0x04, 7, 7),
[F_ICHG] = REG_FIELD(0x04, 0, 6),
@@ -181,7 +183,7 @@ static const struct reg_field bq25890_reg_fields[] = {
[F_CHG_TMR] = REG_FIELD(0x07, 1, 2),
[F_JEITA_ISET] = REG_FIELD(0x07, 0, 0),
/* REG08 */
- [F_BATCMP] = REG_FIELD(0x08, 6, 7),
+ [F_BATCMP] = REG_FIELD(0x08, 6, 7), // 5-7 on BQ25896
[F_VCLAMP] = REG_FIELD(0x08, 2, 4),
[F_TREG] = REG_FIELD(0x08, 0, 1),
/* REG09 */
@@ -195,12 +197,13 @@ static const struct reg_field bq25890_reg_fields[] = {
[F_PUMPX_DN] = REG_FIELD(0x09, 0, 0),
/* REG0A */
[F_BOOSTV] = REG_FIELD(0x0A, 4, 7),
+ /* PFM_OTG_DIS 3 on BQ25896 */
[F_BOOSTI] = REG_FIELD(0x0A, 0, 2),
/* REG0B */
[F_VBUS_STAT] = REG_FIELD(0x0B, 5, 7),
[F_CHG_STAT] = REG_FIELD(0x0B, 3, 4),
[F_PG_STAT] = REG_FIELD(0x0B, 2, 2),
- [F_SDP_STAT] = REG_FIELD(0x0B, 1, 1),
+ [F_SDP_STAT] = REG_FIELD(0x0B, 1, 1), // reserved on BQ25896
[F_VSYS_STAT] = REG_FIELD(0x0B, 0, 0),
/* REG0C */
[F_WD_FAULT] = REG_FIELD(0x0C, 7, 7),
@@ -244,10 +247,7 @@ enum bq25890_table_ids {
/* range tables */
TBL_ICHG,
TBL_ITERM,
- TBL_IPRECHG,
TBL_VREG,
- TBL_BATCMP,
- TBL_VCLAMP,
TBL_BOOSTV,
TBL_SYSVMIN,
@@ -287,8 +287,6 @@ static const union {
[TBL_ICHG] = { .rt = {0, 5056000, 64000} }, /* uA */
[TBL_ITERM] = { .rt = {64000, 1024000, 64000} }, /* uA */
[TBL_VREG] = { .rt = {3840000, 4608000, 16000} }, /* uV */
- [TBL_BATCMP] = { .rt = {0, 140, 20} }, /* mOhm */
- [TBL_VCLAMP] = { .rt = {0, 224000, 32000} }, /* uV */
[TBL_BOOSTV] = { .rt = {4550000, 5510000, 64000} }, /* uV */
[TBL_SYSVMIN] = { .rt = {3000000, 3700000, 100000} }, /* uV */
@@ -401,6 +399,16 @@ static int bq25890_power_supply_get_property(struct power_supply *psy,
val->strval = BQ25890_MANUFACTURER;
break;
+ case POWER_SUPPLY_PROP_MODEL_NAME:
+ if (bq->chip_id == BQ25890_ID)
+ val->strval = "BQ25890";
+ else if (bq->chip_id == BQ25896_ID)
+ val->strval = "BQ25896";
+ else
+ val->strval = "UNKNOWN";
+
+ break;
+
case POWER_SUPPLY_PROP_ONLINE:
val->intval = state.online;
break;
@@ -453,6 +461,15 @@ static int bq25890_power_supply_get_property(struct power_supply *psy,
val->intval = bq25890_find_val(bq->init_data.iterm, TBL_ITERM);
break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ ret = bq25890_field_read(bq, F_SYSV); /* read measured value */
+ if (ret < 0)
+ return ret;
+
+ /* converted_val = 2.304V + ADC_val * 20mV (table 10.3.15) */
+ val->intval = 2304000 + ret * 20000;
+ break;
+
default:
return -EINVAL;
}
@@ -608,30 +625,40 @@ static int bq25890_hw_init(struct bq25890_device *bq)
};
ret = bq25890_chip_reset(bq);
- if (ret < 0)
+ if (ret < 0) {
+ dev_dbg(bq->dev, "Reset failed %d\n", ret);
return ret;
+ }
/* disable watchdog */
ret = bq25890_field_write(bq, F_WD, 0);
- if (ret < 0)
+ if (ret < 0) {
+ dev_dbg(bq->dev, "Disabling watchdog failed %d\n", ret);
return ret;
+ }
/* initialize currents/voltages and other parameters */
for (i = 0; i < ARRAY_SIZE(init_data); i++) {
ret = bq25890_field_write(bq, init_data[i].id,
init_data[i].value);
- if (ret < 0)
+ if (ret < 0) {
+ dev_dbg(bq->dev, "Writing init data failed %d\n", ret);
return ret;
+ }
}
/* Configure ADC for continuous conversions. This does not enable it. */
ret = bq25890_field_write(bq, F_CONV_RATE, 1);
- if (ret < 0)
+ if (ret < 0) {
+ dev_dbg(bq->dev, "Config ADC failed %d\n", ret);
return ret;
+ }
ret = bq25890_get_chip_state(bq, &state);
- if (ret < 0)
+ if (ret < 0) {
+ dev_dbg(bq->dev, "Get state failed %d\n", ret);
return ret;
+ }
mutex_lock(&bq->lock);
bq->state = state;
@@ -642,6 +669,7 @@ static int bq25890_hw_init(struct bq25890_device *bq)
static enum power_supply_property bq25890_power_supply_props[] = {
POWER_SUPPLY_PROP_MANUFACTURER,
+ POWER_SUPPLY_PROP_MODEL_NAME,
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_ONLINE,
POWER_SUPPLY_PROP_HEALTH,
@@ -650,6 +678,7 @@ static enum power_supply_property bq25890_power_supply_props[] = {
POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
};
static char *bq25890_charger_supplied_to[] = {
@@ -767,6 +796,9 @@ static int bq25890_fw_read_u32_props(struct bq25890_device *bq)
if (props[i].optional)
continue;
+ dev_err(bq->dev, "Unable to read property %d %s\n", ret,
+ props[i].name);
+
return ret;
}
@@ -840,7 +872,7 @@ static int bq25890_probe(struct i2c_client *client,
return bq->chip_id;
}
- if (bq->chip_id != BQ25890_ID) {
+ if ((bq->chip_id != BQ25890_ID) && (bq->chip_id != BQ25896_ID)) {
dev_err(dev, "Chip with ID=%d, not supported!\n", bq->chip_id);
return -ENODEV;
}
diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
index f022e1b550df..6dbbe95844a3 100644
--- a/drivers/power/supply/bq27xxx_battery.c
+++ b/drivers/power/supply/bq27xxx_battery.c
@@ -432,6 +432,7 @@ static u8
[BQ27XXX_REG_AP] = 0x18,
BQ27XXX_DM_REG_ROWS,
};
+#define bq27411_regs bq27421_regs
#define bq27425_regs bq27421_regs
#define bq27426_regs bq27421_regs
#define bq27441_regs bq27421_regs
@@ -665,6 +666,7 @@ static enum power_supply_property bq27421_props[] = {
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
POWER_SUPPLY_PROP_MANUFACTURER,
};
+#define bq27411_props bq27421_props
#define bq27425_props bq27421_props
#define bq27426_props bq27421_props
#define bq27441_props bq27421_props
@@ -725,6 +727,12 @@ static struct bq27xxx_dm_reg bq27545_dm_regs[] = {
#define bq27545_dm_regs 0
#endif
+static struct bq27xxx_dm_reg bq27411_dm_regs[] = {
+ [BQ27XXX_DM_DESIGN_CAPACITY] = { 82, 10, 2, 0, 32767 },
+ [BQ27XXX_DM_DESIGN_ENERGY] = { 82, 12, 2, 0, 32767 },
+ [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 16, 2, 2800, 3700 },
+};
+
static struct bq27xxx_dm_reg bq27421_dm_regs[] = {
[BQ27XXX_DM_DESIGN_CAPACITY] = { 82, 10, 2, 0, 8000 },
[BQ27XXX_DM_DESIGN_ENERGY] = { 82, 12, 2, 0, 32767 },
@@ -802,6 +810,7 @@ static struct {
[BQ27546] = BQ27XXX_DATA(bq27546, 0 , BQ27XXX_O_OTDC),
[BQ27742] = BQ27XXX_DATA(bq27742, 0 , BQ27XXX_O_OTDC),
[BQ27545] = BQ27XXX_DATA(bq27545, 0x04143672, BQ27XXX_O_OTDC),
+ [BQ27411] = BQ27XXX_DATA(bq27411, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM),
[BQ27421] = BQ27XXX_DATA(bq27421, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM),
[BQ27425] = BQ27XXX_DATA(bq27425, 0x04143672, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP),
[BQ27426] = BQ27XXX_DATA(bq27426, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM),
diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c
index 40069128ad44..2677c38a8a42 100644
--- a/drivers/power/supply/bq27xxx_battery_i2c.c
+++ b/drivers/power/supply/bq27xxx_battery_i2c.c
@@ -247,6 +247,7 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
{ "bq27546", BQ27546 },
{ "bq27742", BQ27742 },
{ "bq27545", BQ27545 },
+ { "bq27411", BQ27411 },
{ "bq27421", BQ27421 },
{ "bq27425", BQ27425 },
{ "bq27426", BQ27426 },
@@ -279,6 +280,7 @@ static const struct of_device_id bq27xxx_battery_i2c_of_match_table[] = {
{ .compatible = "ti,bq27546" },
{ .compatible = "ti,bq27742" },
{ .compatible = "ti,bq27545" },
+ { .compatible = "ti,bq27411" },
{ .compatible = "ti,bq27421" },
{ .compatible = "ti,bq27425" },
{ .compatible = "ti,bq27426" },
diff --git a/drivers/power/supply/cros_usbpd-charger.c b/drivers/power/supply/cros_usbpd-charger.c
index 688a16bacfbb..7e9c3984ef6a 100644
--- a/drivers/power/supply/cros_usbpd-charger.c
+++ b/drivers/power/supply/cros_usbpd-charger.c
@@ -12,8 +12,12 @@
#include <linux/power_supply.h>
#include <linux/slab.h>
-#define CHARGER_DIR_NAME "CROS_USBPD_CHARGER%d"
-#define CHARGER_DIR_NAME_LENGTH sizeof(CHARGER_DIR_NAME)
+#define CHARGER_USBPD_DIR_NAME "CROS_USBPD_CHARGER%d"
+#define CHARGER_DEDICATED_DIR_NAME "CROS_DEDICATED_CHARGER"
+#define CHARGER_DIR_NAME_LENGTH (sizeof(CHARGER_USBPD_DIR_NAME) >= \
+ sizeof(CHARGER_DEDICATED_DIR_NAME) ? \
+ sizeof(CHARGER_USBPD_DIR_NAME) : \
+ sizeof(CHARGER_DEDICATED_DIR_NAME))
#define CHARGER_CACHE_UPDATE_DELAY msecs_to_jiffies(500)
#define CHARGER_MANUFACTURER_MODEL_LENGTH 32
@@ -42,6 +46,7 @@ struct charger_data {
struct cros_ec_dev *ec_dev;
struct cros_ec_device *ec_device;
int num_charger_ports;
+ int num_usbpd_ports;
int num_registered_psy;
struct port_data *ports[EC_USB_PD_MAX_PORTS];
struct notifier_block notifier;
@@ -58,6 +63,12 @@ static enum power_supply_property cros_usbpd_charger_props[] = {
POWER_SUPPLY_PROP_USB_TYPE
};
+static enum power_supply_property cros_usbpd_dedicated_charger_props[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+};
+
static enum power_supply_usb_type cros_usbpd_charger_usb_types[] = {
POWER_SUPPLY_USB_TYPE_UNKNOWN,
POWER_SUPPLY_USB_TYPE_SDP,
@@ -69,6 +80,11 @@ static enum power_supply_usb_type cros_usbpd_charger_usb_types[] = {
POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID
};
+static bool cros_usbpd_charger_port_is_dedicated(struct port_data *port)
+{
+ return port->port_number >= port->charger->num_usbpd_ports;
+}
+
static int cros_usbpd_charger_ec_command(struct charger_data *charger,
unsigned int version,
unsigned int command,
@@ -103,6 +119,23 @@ static int cros_usbpd_charger_ec_command(struct charger_data *charger,
static int cros_usbpd_charger_get_num_ports(struct charger_data *charger)
{
+ struct ec_response_charge_port_count resp;
+ int ret;
+
+ ret = cros_usbpd_charger_ec_command(charger, 0,
+ EC_CMD_CHARGE_PORT_COUNT,
+ NULL, 0, &resp, sizeof(resp));
+ if (ret < 0) {
+ dev_err(charger->dev,
+ "Unable to get the number of ports (err:0x%x)\n", ret);
+ return ret;
+ }
+
+ return resp.port_count;
+}
+
+static int cros_usbpd_charger_get_usbpd_num_ports(struct charger_data *charger)
+{
struct ec_response_usb_pd_ports resp;
int ret;
@@ -246,7 +279,10 @@ static int cros_usbpd_charger_get_power_info(struct port_data *port)
port->psy_usb_type = POWER_SUPPLY_USB_TYPE_SDP;
}
- port->psy_desc.type = POWER_SUPPLY_TYPE_USB;
+ if (cros_usbpd_charger_port_is_dedicated(port))
+ port->psy_desc.type = POWER_SUPPLY_TYPE_MAINS;
+ else
+ port->psy_desc.type = POWER_SUPPLY_TYPE_USB;
dev_dbg(dev,
"Port %d: type=%d vmax=%d vnow=%d cmax=%d clim=%d pmax=%d\n",
@@ -281,7 +317,8 @@ static int cros_usbpd_charger_get_port_status(struct port_data *port,
if (ret < 0)
return ret;
- ret = cros_usbpd_charger_get_discovery_info(port);
+ if (!cros_usbpd_charger_port_is_dedicated(port))
+ ret = cros_usbpd_charger_get_discovery_info(port);
port->last_update = jiffies;
return ret;
@@ -378,12 +415,10 @@ static int cros_usbpd_charger_ec_event(struct notifier_block *nb,
{
struct cros_ec_device *ec_device;
struct charger_data *charger;
- struct device *dev;
u32 host_event;
charger = container_of(nb, struct charger_data, notifier);
ec_device = charger->ec_device;
- dev = charger->dev;
host_event = cros_ec_get_host_event(ec_device);
if (host_event & EC_HOST_EVENT_MASK(EC_HOST_EVENT_PD_MCU)) {
@@ -426,17 +461,56 @@ static int cros_usbpd_charger_probe(struct platform_device *pd)
platform_set_drvdata(pd, charger);
+ /*
+ * We need to know the number of USB PD ports in order to know whether
+ * there is a dedicated port. The dedicated port will always be
+ * after the USB PD ports, and there should be only one.
+ */
+ charger->num_usbpd_ports =
+ cros_usbpd_charger_get_usbpd_num_ports(charger);
+ if (charger->num_usbpd_ports <= 0) {
+ /*
+ * This can happen on a system that doesn't support USB PD.
+ * Log a message, but no need to warn.
+ */
+ dev_info(dev, "No USB PD charging ports found\n");
+ }
+
charger->num_charger_ports = cros_usbpd_charger_get_num_ports(charger);
- if (charger->num_charger_ports <= 0) {
+ if (charger->num_charger_ports < 0) {
/*
* This can happen on a system that doesn't support USB PD.
* Log a message, but no need to warn.
+ * Older ECs do not support the above command, in that case
+ * let's set up the number of charger ports equal to the number
+ * of USB PD ports
+ */
+ dev_info(dev, "Could not get charger port count\n");
+ charger->num_charger_ports = charger->num_usbpd_ports;
+ }
+
+ if (charger->num_charger_ports <= 0) {
+ /*
+ * This can happen on a system that doesn't support USB PD and
+ * doesn't have a dedicated port.
+ * Log a message, but no need to warn.
*/
dev_info(dev, "No charging ports found\n");
ret = -ENODEV;
goto fail_nowarn;
}
+ /*
+ * Sanity checks on the number of ports:
+ * there should be at most 1 dedicated port
+ */
+ if (charger->num_charger_ports < charger->num_usbpd_ports ||
+ charger->num_charger_ports > (charger->num_usbpd_ports + 1)) {
+ dev_err(dev, "Unexpected number of charge port count\n");
+ ret = -EPROTO;
+ goto fail_nowarn;
+ }
+
for (i = 0; i < charger->num_charger_ports; i++) {
struct power_supply_config psy_cfg = {};
@@ -448,22 +522,33 @@ static int cros_usbpd_charger_probe(struct platform_device *pd)
port->charger = charger;
port->port_number = i;
- sprintf(port->name, CHARGER_DIR_NAME, i);
psy_desc = &port->psy_desc;
- psy_desc->name = port->name;
- psy_desc->type = POWER_SUPPLY_TYPE_USB;
psy_desc->get_property = cros_usbpd_charger_get_prop;
psy_desc->external_power_changed =
cros_usbpd_charger_power_changed;
- psy_desc->properties = cros_usbpd_charger_props;
- psy_desc->num_properties =
- ARRAY_SIZE(cros_usbpd_charger_props);
- psy_desc->usb_types = cros_usbpd_charger_usb_types;
- psy_desc->num_usb_types =
- ARRAY_SIZE(cros_usbpd_charger_usb_types);
psy_cfg.drv_data = port;
+ if (cros_usbpd_charger_port_is_dedicated(port)) {
+ sprintf(port->name, CHARGER_DEDICATED_DIR_NAME);
+ psy_desc->type = POWER_SUPPLY_TYPE_MAINS;
+ psy_desc->properties =
+ cros_usbpd_dedicated_charger_props;
+ psy_desc->num_properties =
+ ARRAY_SIZE(cros_usbpd_dedicated_charger_props);
+ } else {
+ sprintf(port->name, CHARGER_USBPD_DIR_NAME, i);
+ psy_desc->type = POWER_SUPPLY_TYPE_USB;
+ psy_desc->properties = cros_usbpd_charger_props;
+ psy_desc->num_properties =
+ ARRAY_SIZE(cros_usbpd_charger_props);
+ psy_desc->usb_types = cros_usbpd_charger_usb_types;
+ psy_desc->num_usb_types =
+ ARRAY_SIZE(cros_usbpd_charger_usb_types);
+ }
+
+ psy_desc->name = port->name;
+
psy = devm_power_supply_register_no_ws(dev, psy_desc,
&psy_cfg);
if (IS_ERR(psy)) {
diff --git a/drivers/power/supply/ds2780_battery.c b/drivers/power/supply/ds2780_battery.c
index 370e9109342b..cad14ba1b648 100644
--- a/drivers/power/supply/ds2780_battery.c
+++ b/drivers/power/supply/ds2780_battery.c
@@ -829,5 +829,5 @@ module_platform_driver(ds2780_battery_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Clifton Barnes <cabarnes@indesign-llc.com>");
-MODULE_DESCRIPTION("Maxim/Dallas DS2780 Stand-Alone Fuel Gauage IC driver");
+MODULE_DESCRIPTION("Maxim/Dallas DS2780 Stand-Alone Fuel Gauge IC driver");
MODULE_ALIAS("platform:ds2780-battery");
diff --git a/drivers/power/supply/ds2781_battery.c b/drivers/power/supply/ds2781_battery.c
index d1b5a19aae7c..5e794607f732 100644
--- a/drivers/power/supply/ds2781_battery.c
+++ b/drivers/power/supply/ds2781_battery.c
@@ -829,6 +829,6 @@ module_platform_driver(ds2781_battery_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Renata Sayakhova <renata@oktetlabs.ru>");
-MODULE_DESCRIPTION("Maxim/Dallas DS2781 Stand-Alone Fuel Gauage IC driver");
+MODULE_DESCRIPTION("Maxim/Dallas DS2781 Stand-Alone Fuel Gauge IC driver");
MODULE_ALIAS("platform:ds2781-battery");
diff --git a/drivers/power/supply/ds2782_battery.c b/drivers/power/supply/ds2782_battery.c
index a1b7e0592245..019c58493e3d 100644
--- a/drivers/power/supply/ds2782_battery.c
+++ b/drivers/power/supply/ds2782_battery.c
@@ -471,5 +471,5 @@ static struct i2c_driver ds278x_battery_driver = {
module_i2c_driver(ds278x_battery_driver);
MODULE_AUTHOR("Ryan Mallon");
-MODULE_DESCRIPTION("Maxim/Dallas DS2782 Stand-Alone Fuel Gauage IC driver");
+MODULE_DESCRIPTION("Maxim/Dallas DS2782 Stand-Alone Fuel Gauge IC driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/power/supply/max14577_charger.c b/drivers/power/supply/max14577_charger.c
index 449fc56f09eb..8a59feac6468 100644
--- a/drivers/power/supply/max14577_charger.c
+++ b/drivers/power/supply/max14577_charger.c
@@ -1,19 +1,9 @@
-/*
- * max14577_charger.c - Battery charger driver for the Maxim 14577/77836
- *
- * Copyright (C) 2013,2014 Samsung Electronics
- * Krzysztof Kozlowski <krzk@kernel.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 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.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// max14577_charger.c - Battery charger driver for the Maxim 14577/77836
+//
+// Copyright (C) 2013,2014 Samsung Electronics
+// Krzysztof Kozlowski <krzk@kernel.org>
#include <linux/module.h>
#include <linux/platform_device.h>
diff --git a/drivers/power/supply/max17040_battery.c b/drivers/power/supply/max17040_battery.c
index 33c40f79d23d..91cafc7bed30 100644
--- a/drivers/power/supply/max17040_battery.c
+++ b/drivers/power/supply/max17040_battery.c
@@ -1,14 +1,10 @@
-/*
- * max17040_battery.c
- * fuel-gauge systems for lithium-ion (Li+) batteries
- *
- * Copyright (C) 2009 Samsung Electronics
- * Minkyu Kang <mk7.kang@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// max17040_battery.c
+// fuel-gauge systems for lithium-ion (Li+) batteries
+//
+// Copyright (C) 2009 Samsung Electronics
+// Minkyu Kang <mk7.kang@samsung.com>
#include <linux/module.h>
#include <linux/init.h>
diff --git a/drivers/power/supply/max17042_battery.c b/drivers/power/supply/max17042_battery.c
index 1a568df383db..2a8d75e5e930 100644
--- a/drivers/power/supply/max17042_battery.c
+++ b/drivers/power/supply/max17042_battery.c
@@ -1,26 +1,12 @@
-/*
- * Fuel gauge driver for Maxim 17042 / 8966 / 8997
- * Note that Maxim 8966 and 8997 are mfd and this is its subdevice.
- *
- * Copyright (C) 2011 Samsung Electronics
- * MyungJoo Ham <myungjoo.ham@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * This driver is based on max17040_battery.c
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Fuel gauge driver for Maxim 17042 / 8966 / 8997
+// Note that Maxim 8966 and 8997 are mfd and this is its subdevice.
+//
+// Copyright (C) 2011 Samsung Electronics
+// MyungJoo Ham <myungjoo.ham@samsung.com>
+//
+// This driver is based on max17040_battery.c
#include <linux/acpi.h>
#include <linux/init.h>
diff --git a/drivers/power/supply/max77693_charger.c b/drivers/power/supply/max77693_charger.c
index 749c7926e3c9..a2c5c9858639 100644
--- a/drivers/power/supply/max77693_charger.c
+++ b/drivers/power/supply/max77693_charger.c
@@ -1,19 +1,9 @@
-/*
- * max77693_charger.c - Battery charger driver for the Maxim 77693
- *
- * Copyright (C) 2014 Samsung Electronics
- * Krzysztof Kozlowski <krzk@kernel.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 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.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// max77693_charger.c - Battery charger driver for the Maxim 77693
+//
+// Copyright (C) 2014 Samsung Electronics
+// Krzysztof Kozlowski <krzk@kernel.org>
#include <linux/module.h>
#include <linux/platform_device.h>
diff --git a/drivers/power/supply/max8925_power.c b/drivers/power/supply/max8925_power.c
index 3b94620ce5c1..39b4d5b6ac39 100644
--- a/drivers/power/supply/max8925_power.c
+++ b/drivers/power/supply/max8925_power.c
@@ -124,6 +124,7 @@ static irqreturn_t max8925_charger_handler(int irq, void *data)
case MAX8925_IRQ_VCHG_THM_OK_F:
/* Battery is not ready yet */
dev_dbg(chip->dev, "Battery temperature is out of range\n");
+ /* Fall through */
case MAX8925_IRQ_VCHG_DC_OVP:
dev_dbg(chip->dev, "Error detection\n");
__set_charger(info, 0);
diff --git a/drivers/power/supply/max8997_charger.c b/drivers/power/supply/max8997_charger.c
index c73fb4221695..f5e84cd47924 100644
--- a/drivers/power/supply/max8997_charger.c
+++ b/drivers/power/supply/max8997_charger.c
@@ -1,23 +1,9 @@
-/*
- * max8997_charger.c - Power supply consumer driver for the Maxim 8997/8966
- *
- * Copyright (C) 2011 Samsung Electronics
- * MyungJoo Ham <myungjoo.ham@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// max8997_charger.c - Power supply consumer driver for the Maxim 8997/8966
+//
+// Copyright (C) 2011 Samsung Electronics
+// MyungJoo Ham <myungjoo.ham@samsung.com>
#include <linux/err.h>
#include <linux/module.h>
diff --git a/drivers/power/supply/max8998_charger.c b/drivers/power/supply/max8998_charger.c
index cad7d1a8feec..9a926c7c0f22 100644
--- a/drivers/power/supply/max8998_charger.c
+++ b/drivers/power/supply/max8998_charger.c
@@ -1,23 +1,9 @@
-/*
- * max8998_charger.c - Power supply consumer driver for the Maxim 8998/LP3974
- *
- * Copyright (C) 2009-2010 Samsung Electronics
- * MyungJoo Ham <myungjoo.ham@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// max8998_charger.c - Power supply consumer driver for the Maxim 8998/LP3974
+//
+// Copyright (C) 2009-2010 Samsung Electronics
+// MyungJoo Ham <myungjoo.ham@samsung.com>
#include <linux/err.h>
#include <linux/module.h>
@@ -86,7 +72,7 @@ static const struct power_supply_desc max8998_battery_desc = {
static int max8998_battery_probe(struct platform_device *pdev)
{
struct max8998_dev *iodev = dev_get_drvdata(pdev->dev.parent);
- struct max8998_platform_data *pdata = dev_get_platdata(iodev->dev);
+ struct max8998_platform_data *pdata = iodev->pdata;
struct power_supply_config psy_cfg = {};
struct max8998_battery_data *max8998;
struct i2c_client *i2c;
diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
index 6170ed8b6854..dce24f596160 100644
--- a/drivers/power/supply/power_supply_sysfs.c
+++ b/drivers/power/supply/power_supply_sysfs.c
@@ -131,7 +131,8 @@ static ssize_t power_supply_show_property(struct device *dev,
dev_dbg(dev, "driver has no data for `%s' property\n",
attr->attr.name);
else if (ret != -ENODEV && ret != -EAGAIN)
- dev_err(dev, "driver failed to report `%s' property: %zd\n",
+ dev_err_ratelimited(dev,
+ "driver failed to report `%s' property: %zd\n",
attr->attr.name, ret);
return ret;
}
diff --git a/drivers/power/supply/sc2731_charger.c b/drivers/power/supply/sc2731_charger.c
new file mode 100644
index 000000000000..525a820537bf
--- /dev/null
+++ b/drivers/power/supply/sc2731_charger.c
@@ -0,0 +1,504 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2018 Spreadtrum Communications Inc.
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/usb/phy.h>
+#include <linux/regmap.h>
+#include <linux/notifier.h>
+#include <linux/of.h>
+
+/* PMIC global registers definition */
+#define SC2731_CHARGE_STATUS 0xedc
+#define SC2731_CHARGE_FULL BIT(4)
+#define SC2731_MODULE_EN1 0xc0c
+#define SC2731_CHARGE_EN BIT(5)
+
+/* SC2731 switch charger registers definition */
+#define SC2731_CHG_CFG0 0x0
+#define SC2731_CHG_CFG1 0x4
+#define SC2731_CHG_CFG2 0x8
+#define SC2731_CHG_CFG3 0xc
+#define SC2731_CHG_CFG4 0x10
+#define SC2731_CHG_CFG5 0x28
+
+/* SC2731_CHG_CFG0 register definition */
+#define SC2731_PRECHG_RNG_SHIFT 11
+#define SC2731_PRECHG_RNG_MASK GENMASK(12, 11)
+
+#define SC2731_TERMINATION_VOL_MASK GENMASK(2, 1)
+#define SC2731_TERMINATION_VOL_SHIFT 1
+#define SC2731_TERMINATION_VOL_CAL_MASK GENMASK(8, 3)
+#define SC2731_TERMINATION_VOL_CAL_SHIFT 3
+#define SC2731_TERMINATION_CUR_MASK GENMASK(2, 0)
+
+#define SC2731_CC_EN BIT(13)
+#define SC2731_CHARGER_PD BIT(0)
+
+/* SC2731_CHG_CFG1 register definition */
+#define SC2731_CUR_MASK GENMASK(5, 0)
+
+/* SC2731_CHG_CFG5 register definition */
+#define SC2731_CUR_LIMIT_SHIFT 8
+#define SC2731_CUR_LIMIT_MASK GENMASK(9, 8)
+
+/* Default current definition (unit is mA) */
+#define SC2731_CURRENT_LIMIT_100 100
+#define SC2731_CURRENT_LIMIT_500 500
+#define SC2731_CURRENT_LIMIT_900 900
+#define SC2731_CURRENT_LIMIT_2000 2000
+#define SC2731_CURRENT_PRECHG 450
+#define SC2731_CURRENT_STEP 50
+
+struct sc2731_charger_info {
+ struct device *dev;
+ struct regmap *regmap;
+ struct usb_phy *usb_phy;
+ struct notifier_block usb_notify;
+ struct power_supply *psy_usb;
+ struct mutex lock;
+ bool charging;
+ u32 base;
+};
+
+static void sc2731_charger_stop_charge(struct sc2731_charger_info *info)
+{
+ regmap_update_bits(info->regmap, info->base + SC2731_CHG_CFG0,
+ SC2731_CC_EN, 0);
+
+ regmap_update_bits(info->regmap, info->base + SC2731_CHG_CFG0,
+ SC2731_CHARGER_PD, SC2731_CHARGER_PD);
+}
+
+static int sc2731_charger_start_charge(struct sc2731_charger_info *info)
+{
+ int ret;
+
+ /* Enable charger constant current mode */
+ ret = regmap_update_bits(info->regmap, info->base + SC2731_CHG_CFG0,
+ SC2731_CC_EN, SC2731_CC_EN);
+ if (ret)
+ return ret;
+
+ /* Start charging */
+ return regmap_update_bits(info->regmap, info->base + SC2731_CHG_CFG0,
+ SC2731_CHARGER_PD, 0);
+}
+
+static int sc2731_charger_set_current_limit(struct sc2731_charger_info *info,
+ u32 limit)
+{
+ u32 val;
+
+ if (limit <= SC2731_CURRENT_LIMIT_100)
+ val = 0;
+ else if (limit <= SC2731_CURRENT_LIMIT_500)
+ val = 3;
+ else if (limit <= SC2731_CURRENT_LIMIT_900)
+ val = 2;
+ else
+ val = 1;
+
+ return regmap_update_bits(info->regmap, info->base + SC2731_CHG_CFG5,
+ SC2731_CUR_LIMIT_MASK,
+ val << SC2731_CUR_LIMIT_SHIFT);
+}
+
+static int sc2731_charger_set_current(struct sc2731_charger_info *info, u32 cur)
+{
+ u32 val;
+ int ret;
+
+ if (cur > SC2731_CURRENT_LIMIT_2000)
+ cur = SC2731_CURRENT_LIMIT_2000;
+ else if (cur < SC2731_CURRENT_PRECHG)
+ cur = SC2731_CURRENT_PRECHG;
+
+ /* Calculate the step value, each step is 50 mA */
+ val = (cur - SC2731_CURRENT_PRECHG) / SC2731_CURRENT_STEP;
+
+ /* Set pre-charge current as 450 mA */
+ ret = regmap_update_bits(info->regmap, info->base + SC2731_CHG_CFG0,
+ SC2731_PRECHG_RNG_MASK,
+ 0x3 << SC2731_PRECHG_RNG_SHIFT);
+ if (ret)
+ return ret;
+
+ return regmap_update_bits(info->regmap, info->base + SC2731_CHG_CFG1,
+ SC2731_CUR_MASK, val);
+}
+
+static int sc2731_charger_get_status(struct sc2731_charger_info *info)
+{
+ u32 val;
+ int ret;
+
+ ret = regmap_read(info->regmap, SC2731_CHARGE_STATUS, &val);
+ if (ret)
+ return ret;
+
+ if (val & SC2731_CHARGE_FULL)
+ return POWER_SUPPLY_STATUS_FULL;
+
+ return POWER_SUPPLY_STATUS_CHARGING;
+}
+
+static int sc2731_charger_get_current(struct sc2731_charger_info *info,
+ u32 *cur)
+{
+ int ret;
+ u32 val;
+
+ ret = regmap_read(info->regmap, info->base + SC2731_CHG_CFG1, &val);
+ if (ret)
+ return ret;
+
+ val &= SC2731_CUR_MASK;
+ *cur = val * SC2731_CURRENT_STEP + SC2731_CURRENT_PRECHG;
+
+ return 0;
+}
+
+static int sc2731_charger_get_current_limit(struct sc2731_charger_info *info,
+ u32 *cur)
+{
+ int ret;
+ u32 val;
+
+ ret = regmap_read(info->regmap, info->base + SC2731_CHG_CFG5, &val);
+ if (ret)
+ return ret;
+
+ val = (val & SC2731_CUR_LIMIT_MASK) >> SC2731_CUR_LIMIT_SHIFT;
+
+ switch (val) {
+ case 0:
+ *cur = SC2731_CURRENT_LIMIT_100;
+ break;
+
+ case 1:
+ *cur = SC2731_CURRENT_LIMIT_2000;
+ break;
+
+ case 2:
+ *cur = SC2731_CURRENT_LIMIT_900;
+ break;
+
+ case 3:
+ *cur = SC2731_CURRENT_LIMIT_500;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+sc2731_charger_usb_set_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ struct sc2731_charger_info *info = power_supply_get_drvdata(psy);
+ int ret;
+
+ mutex_lock(&info->lock);
+
+ if (!info->charging) {
+ mutex_unlock(&info->lock);
+ return -ENODEV;
+ }
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+ ret = sc2731_charger_set_current(info, val->intval / 1000);
+ if (ret < 0)
+ dev_err(info->dev, "set charge current failed\n");
+ break;
+
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+ ret = sc2731_charger_set_current_limit(info,
+ val->intval / 1000);
+ if (ret < 0)
+ dev_err(info->dev, "set input current limit failed\n");
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+
+ mutex_unlock(&info->lock);
+ return ret;
+}
+
+static int sc2731_charger_usb_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct sc2731_charger_info *info = power_supply_get_drvdata(psy);
+ int ret = 0;
+ u32 cur;
+
+ mutex_lock(&info->lock);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ if (info->charging)
+ val->intval = sc2731_charger_get_status(info);
+ else
+ val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ break;
+
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+ if (!info->charging) {
+ val->intval = 0;
+ } else {
+ ret = sc2731_charger_get_current(info, &cur);
+ if (ret)
+ goto out;
+
+ val->intval = cur * 1000;
+ }
+ break;
+
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+ if (!info->charging) {
+ val->intval = 0;
+ } else {
+ ret = sc2731_charger_get_current_limit(info, &cur);
+ if (ret)
+ goto out;
+
+ val->intval = cur * 1000;
+ }
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+
+out:
+ mutex_unlock(&info->lock);
+ return ret;
+}
+
+static int sc2731_charger_property_is_writeable(struct power_supply *psy,
+ enum power_supply_property psp)
+{
+ int ret;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+ ret = 1;
+ break;
+
+ default:
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static enum power_supply_property sc2731_usb_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
+ POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
+};
+
+static const struct power_supply_desc sc2731_charger_desc = {
+ .name = "sc2731_charger",
+ .type = POWER_SUPPLY_TYPE_USB,
+ .properties = sc2731_usb_props,
+ .num_properties = ARRAY_SIZE(sc2731_usb_props),
+ .get_property = sc2731_charger_usb_get_property,
+ .set_property = sc2731_charger_usb_set_property,
+ .property_is_writeable = sc2731_charger_property_is_writeable,
+};
+
+static int sc2731_charger_usb_change(struct notifier_block *nb,
+ unsigned long limit, void *data)
+{
+ struct sc2731_charger_info *info =
+ container_of(nb, struct sc2731_charger_info, usb_notify);
+ int ret = 0;
+
+ mutex_lock(&info->lock);
+
+ if (limit > 0) {
+ /* set current limitation and start to charge */
+ ret = sc2731_charger_set_current_limit(info, limit);
+ if (ret)
+ goto out;
+
+ ret = sc2731_charger_set_current(info, limit);
+ if (ret)
+ goto out;
+
+ ret = sc2731_charger_start_charge(info);
+ if (ret)
+ goto out;
+
+ info->charging = true;
+ } else {
+ /* Stop charging */
+ info->charging = false;
+ sc2731_charger_stop_charge(info);
+ }
+
+out:
+ mutex_unlock(&info->lock);
+ return ret;
+}
+
+static int sc2731_charger_hw_init(struct sc2731_charger_info *info)
+{
+ struct power_supply_battery_info bat_info = { };
+ u32 term_currrent, term_voltage, cur_val, vol_val;
+ int ret;
+
+ /* Enable charger module */
+ ret = regmap_update_bits(info->regmap, SC2731_MODULE_EN1,
+ SC2731_CHARGE_EN, SC2731_CHARGE_EN);
+ if (ret)
+ return ret;
+
+ ret = power_supply_get_battery_info(info->psy_usb, &bat_info);
+ if (ret) {
+ dev_warn(info->dev, "no battery information is supplied\n");
+
+ /*
+ * If no battery information is supplied, we should set
+ * default charge termination current to 120 mA, and default
+ * charge termination voltage to 4.35V.
+ */
+ cur_val = 0x2;
+ vol_val = 0x1;
+ } else {
+ term_currrent = bat_info.charge_term_current_ua / 1000;
+
+ if (term_currrent <= 90)
+ cur_val = 0;
+ else if (term_currrent >= 265)
+ cur_val = 0x7;
+ else
+ cur_val = ((term_currrent - 90) / 25) + 1;
+
+ term_voltage = bat_info.constant_charge_voltage_max_uv / 1000;
+
+ if (term_voltage > 4500)
+ term_voltage = 4500;
+
+ if (term_voltage > 4200)
+ vol_val = (term_voltage - 4200) / 100;
+ else
+ vol_val = 0;
+ }
+
+ /* Set charge termination current */
+ ret = regmap_update_bits(info->regmap, info->base + SC2731_CHG_CFG2,
+ SC2731_TERMINATION_CUR_MASK, cur_val);
+ if (ret)
+ goto error;
+
+ /* Set charge termination voltage */
+ ret = regmap_update_bits(info->regmap, info->base + SC2731_CHG_CFG0,
+ SC2731_TERMINATION_VOL_MASK |
+ SC2731_TERMINATION_VOL_CAL_MASK,
+ (vol_val << SC2731_TERMINATION_VOL_SHIFT) |
+ (0x6 << SC2731_TERMINATION_VOL_CAL_SHIFT));
+ if (ret)
+ goto error;
+
+ return 0;
+
+error:
+ regmap_update_bits(info->regmap, SC2731_MODULE_EN1, SC2731_CHARGE_EN, 0);
+ return ret;
+}
+
+static int sc2731_charger_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct sc2731_charger_info *info;
+ struct power_supply_config charger_cfg = { };
+ int ret;
+
+ info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ mutex_init(&info->lock);
+ info->dev = &pdev->dev;
+
+ info->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ if (!info->regmap) {
+ dev_err(&pdev->dev, "failed to get charger regmap\n");
+ return -ENODEV;
+ }
+
+ ret = of_property_read_u32(np, "reg", &info->base);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to get register address\n");
+ return -ENODEV;
+ }
+
+ charger_cfg.drv_data = info;
+ charger_cfg.of_node = np;
+ info->psy_usb = devm_power_supply_register(&pdev->dev,
+ &sc2731_charger_desc,
+ &charger_cfg);
+ if (IS_ERR(info->psy_usb)) {
+ dev_err(&pdev->dev, "failed to register power supply\n");
+ return PTR_ERR(info->psy_usb);
+ }
+
+ ret = sc2731_charger_hw_init(info);
+ if (ret)
+ return ret;
+
+ info->usb_phy = devm_usb_get_phy_by_phandle(&pdev->dev, "phys", 0);
+ if (IS_ERR(info->usb_phy)) {
+ dev_err(&pdev->dev, "failed to find USB phy\n");
+ return PTR_ERR(info->usb_phy);
+ }
+
+ info->usb_notify.notifier_call = sc2731_charger_usb_change;
+ ret = usb_register_notifier(info->usb_phy, &info->usb_notify);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register notifier: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int sc2731_charger_remove(struct platform_device *pdev)
+{
+ struct sc2731_charger_info *info = platform_get_drvdata(pdev);
+
+ usb_unregister_notifier(info->usb_phy, &info->usb_notify);
+
+ return 0;
+}
+
+static const struct of_device_id sc2731_charger_of_match[] = {
+ { .compatible = "sprd,sc2731-charger", },
+ { }
+};
+
+static struct platform_driver sc2731_charger_driver = {
+ .driver = {
+ .name = "sc2731-charger",
+ .of_match_table = sc2731_charger_of_match,
+ },
+ .probe = sc2731_charger_probe,
+ .remove = sc2731_charger_remove,
+};
+
+module_platform_driver(sc2731_charger_driver);
+
+MODULE_DESCRIPTION("Spreadtrum SC2731 Charger Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/power/supply/twl4030_charger.c b/drivers/power/supply/twl4030_charger.c
index bbcaee56db9d..0e202d4273fb 100644
--- a/drivers/power/supply/twl4030_charger.c
+++ b/drivers/power/supply/twl4030_charger.c
@@ -420,7 +420,8 @@ static void twl4030_current_worker(struct work_struct *data)
if (v < USB_MIN_VOLT) {
/* Back up and stop adjusting. */
- bci->usb_cur -= USB_CUR_STEP;
+ if (bci->usb_cur >= USB_CUR_STEP)
+ bci->usb_cur -= USB_CUR_STEP;
bci->usb_cur_target = bci->usb_cur;
} else if (bci->usb_cur >= bci->usb_cur_target ||
bci->usb_cur + USB_CUR_STEP > USB_MAX_CURRENT) {
@@ -439,6 +440,7 @@ static void twl4030_current_worker(struct work_struct *data)
static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable)
{
int ret;
+ u32 reg;
if (bci->usb_mode == CHARGE_OFF)
enable = false;
@@ -452,14 +454,38 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable)
bci->usb_enabled = 1;
}
- if (bci->usb_mode == CHARGE_AUTO)
+ if (bci->usb_mode == CHARGE_AUTO) {
+ /* Enable interrupts now. */
+ reg = ~(u32)(TWL4030_ICHGLOW | TWL4030_ICHGEOC |
+ TWL4030_TBATOR2 | TWL4030_TBATOR1 |
+ TWL4030_BATSTS);
+ ret = twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, reg,
+ TWL4030_INTERRUPTS_BCIIMR1A);
+ if (ret < 0) {
+ dev_err(bci->dev,
+ "failed to unmask interrupts: %d\n",
+ ret);
+ return ret;
+ }
/* forcing the field BCIAUTOUSB (BOOT_BCI[1]) to 1 */
ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOUSB);
+ }
/* forcing USBFASTMCHG(BCIMFSTS4[2]) to 1 */
ret = twl4030_clear_set(TWL_MODULE_MAIN_CHARGE, 0,
TWL4030_USBFASTMCHG, TWL4030_BCIMFSTS4);
if (bci->usb_mode == CHARGE_LINEAR) {
+ /* Enable interrupts now. */
+ reg = ~(u32)(TWL4030_ICHGLOW | TWL4030_TBATOR2 |
+ TWL4030_TBATOR1 | TWL4030_BATSTS);
+ ret = twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, reg,
+ TWL4030_INTERRUPTS_BCIIMR1A);
+ if (ret < 0) {
+ dev_err(bci->dev,
+ "failed to unmask interrupts: %d\n",
+ ret);
+ return ret;
+ }
twl4030_clear_set_boot_bci(TWL4030_BCIAUTOAC|TWL4030_CVENAC, 0);
/* Watch dog key: WOVF acknowledge */
ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x33,
@@ -996,12 +1022,13 @@ static int twl4030_bci_probe(struct platform_device *pdev)
if (bci->dev->of_node) {
struct device_node *phynode;
- phynode = of_find_compatible_node(bci->dev->of_node->parent,
- NULL, "ti,twl4030-usb");
+ phynode = of_get_compatible_child(bci->dev->of_node->parent,
+ "ti,twl4030-usb");
if (phynode) {
bci->usb_nb.notifier_call = twl4030_bci_usb_ncb;
bci->transceiver = devm_usb_get_phy_by_node(
bci->dev, phynode, &bci->usb_nb);
+ of_node_put(phynode);
if (IS_ERR(bci->transceiver)) {
ret = PTR_ERR(bci->transceiver);
if (ret == -EPROBE_DEFER)
diff --git a/drivers/powercap/intel_rapl.c b/drivers/powercap/intel_rapl.c
index 295d8dcba48c..6cdb2c14eee4 100644
--- a/drivers/powercap/intel_rapl.c
+++ b/drivers/powercap/intel_rapl.c
@@ -1133,47 +1133,40 @@ static const struct rapl_defaults rapl_defaults_cht = {
.compute_time_window = rapl_compute_time_window_atom,
};
-#define RAPL_CPU(_model, _ops) { \
- .vendor = X86_VENDOR_INTEL, \
- .family = 6, \
- .model = _model, \
- .driver_data = (kernel_ulong_t)&_ops, \
- }
-
static const struct x86_cpu_id rapl_ids[] __initconst = {
- RAPL_CPU(INTEL_FAM6_SANDYBRIDGE, rapl_defaults_core),
- RAPL_CPU(INTEL_FAM6_SANDYBRIDGE_X, rapl_defaults_core),
-
- RAPL_CPU(INTEL_FAM6_IVYBRIDGE, rapl_defaults_core),
- RAPL_CPU(INTEL_FAM6_IVYBRIDGE_X, rapl_defaults_core),
-
- RAPL_CPU(INTEL_FAM6_HASWELL_CORE, rapl_defaults_core),
- RAPL_CPU(INTEL_FAM6_HASWELL_ULT, rapl_defaults_core),
- RAPL_CPU(INTEL_FAM6_HASWELL_GT3E, rapl_defaults_core),
- RAPL_CPU(INTEL_FAM6_HASWELL_X, rapl_defaults_hsw_server),
-
- RAPL_CPU(INTEL_FAM6_BROADWELL_CORE, rapl_defaults_core),
- RAPL_CPU(INTEL_FAM6_BROADWELL_GT3E, rapl_defaults_core),
- RAPL_CPU(INTEL_FAM6_BROADWELL_XEON_D, rapl_defaults_core),
- RAPL_CPU(INTEL_FAM6_BROADWELL_X, rapl_defaults_hsw_server),
-
- RAPL_CPU(INTEL_FAM6_SKYLAKE_DESKTOP, rapl_defaults_core),
- RAPL_CPU(INTEL_FAM6_SKYLAKE_MOBILE, rapl_defaults_core),
- RAPL_CPU(INTEL_FAM6_SKYLAKE_X, rapl_defaults_hsw_server),
- RAPL_CPU(INTEL_FAM6_KABYLAKE_MOBILE, rapl_defaults_core),
- RAPL_CPU(INTEL_FAM6_KABYLAKE_DESKTOP, rapl_defaults_core),
- RAPL_CPU(INTEL_FAM6_CANNONLAKE_MOBILE, rapl_defaults_core),
-
- RAPL_CPU(INTEL_FAM6_ATOM_SILVERMONT1, rapl_defaults_byt),
- RAPL_CPU(INTEL_FAM6_ATOM_AIRMONT, rapl_defaults_cht),
- RAPL_CPU(INTEL_FAM6_ATOM_MERRIFIELD, rapl_defaults_tng),
- RAPL_CPU(INTEL_FAM6_ATOM_MOOREFIELD, rapl_defaults_ann),
- RAPL_CPU(INTEL_FAM6_ATOM_GOLDMONT, rapl_defaults_core),
- RAPL_CPU(INTEL_FAM6_ATOM_GEMINI_LAKE, rapl_defaults_core),
- RAPL_CPU(INTEL_FAM6_ATOM_DENVERTON, rapl_defaults_core),
-
- RAPL_CPU(INTEL_FAM6_XEON_PHI_KNL, rapl_defaults_hsw_server),
- RAPL_CPU(INTEL_FAM6_XEON_PHI_KNM, rapl_defaults_hsw_server),
+ INTEL_CPU_FAM6(SANDYBRIDGE, rapl_defaults_core),
+ INTEL_CPU_FAM6(SANDYBRIDGE_X, rapl_defaults_core),
+
+ INTEL_CPU_FAM6(IVYBRIDGE, rapl_defaults_core),
+ INTEL_CPU_FAM6(IVYBRIDGE_X, rapl_defaults_core),
+
+ INTEL_CPU_FAM6(HASWELL_CORE, rapl_defaults_core),
+ INTEL_CPU_FAM6(HASWELL_ULT, rapl_defaults_core),
+ INTEL_CPU_FAM6(HASWELL_GT3E, rapl_defaults_core),
+ INTEL_CPU_FAM6(HASWELL_X, rapl_defaults_hsw_server),
+
+ INTEL_CPU_FAM6(BROADWELL_CORE, rapl_defaults_core),
+ INTEL_CPU_FAM6(BROADWELL_GT3E, rapl_defaults_core),
+ INTEL_CPU_FAM6(BROADWELL_XEON_D, rapl_defaults_core),
+ INTEL_CPU_FAM6(BROADWELL_X, rapl_defaults_hsw_server),
+
+ INTEL_CPU_FAM6(SKYLAKE_DESKTOP, rapl_defaults_core),
+ INTEL_CPU_FAM6(SKYLAKE_MOBILE, rapl_defaults_core),
+ INTEL_CPU_FAM6(SKYLAKE_X, rapl_defaults_hsw_server),
+ INTEL_CPU_FAM6(KABYLAKE_MOBILE, rapl_defaults_core),
+ INTEL_CPU_FAM6(KABYLAKE_DESKTOP, rapl_defaults_core),
+ INTEL_CPU_FAM6(CANNONLAKE_MOBILE, rapl_defaults_core),
+
+ INTEL_CPU_FAM6(ATOM_SILVERMONT, rapl_defaults_byt),
+ INTEL_CPU_FAM6(ATOM_AIRMONT, rapl_defaults_cht),
+ INTEL_CPU_FAM6(ATOM_SILVERMONT_MID, rapl_defaults_tng),
+ INTEL_CPU_FAM6(ATOM_AIRMONT_MID, rapl_defaults_ann),
+ INTEL_CPU_FAM6(ATOM_GOLDMONT, rapl_defaults_core),
+ INTEL_CPU_FAM6(ATOM_GOLDMONT_PLUS, rapl_defaults_core),
+ INTEL_CPU_FAM6(ATOM_GOLDMONT_X, rapl_defaults_core),
+
+ INTEL_CPU_FAM6(XEON_PHI_KNL, rapl_defaults_hsw_server),
+ INTEL_CPU_FAM6(XEON_PHI_KNM, rapl_defaults_hsw_server),
{}
};
MODULE_DEVICE_TABLE(x86cpu, rapl_ids);
diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c
index 01b0e2bb3319..2012551d93e0 100644
--- a/drivers/ptp/ptp_chardev.c
+++ b/drivers/ptp/ptp_chardev.c
@@ -24,6 +24,8 @@
#include <linux/slab.h>
#include <linux/timekeeping.h>
+#include <linux/nospec.h>
+
#include "ptp_private.h"
static int ptp_disable_pinfunc(struct ptp_clock_info *ops,
@@ -248,6 +250,7 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg)
err = -EINVAL;
break;
}
+ pin_index = array_index_nospec(pin_index, ops->n_pins);
if (mutex_lock_interruptible(&ptp->pincfg_mux))
return -ERESTARTSYS;
pd = ops->pin_config[pin_index];
@@ -266,6 +269,7 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg)
err = -EINVAL;
break;
}
+ pin_index = array_index_nospec(pin_index, ops->n_pins);
if (mutex_lock_interruptible(&ptp->pincfg_mux))
return -ERESTARTSYS;
err = ptp_set_pinfunc(ptp, pin_index, pd.func, pd.chan);
diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c
index 7eacc1c4b3b1..5419a89d300e 100644
--- a/drivers/ptp/ptp_clock.c
+++ b/drivers/ptp/ptp_clock.c
@@ -232,12 +232,8 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info,
init_waitqueue_head(&ptp->tsev_wq);
if (ptp->info->do_aux_work) {
- char *worker_name = kasprintf(GFP_KERNEL, "ptp%d", ptp->index);
-
kthread_init_delayed_work(&ptp->aux_work, ptp_aux_kworker);
- ptp->kworker = kthread_create_worker(0, worker_name ?
- worker_name : info->name);
- kfree(worker_name);
+ ptp->kworker = kthread_create_worker(0, "ptp%d", ptp->index);
if (IS_ERR(ptp->kworker)) {
err = PTR_ERR(ptp->kworker);
pr_err("failed to create ptp aux_worker %d\n", err);
diff --git a/drivers/ptp/ptp_dte.c b/drivers/ptp/ptp_dte.c
index a7dc43368df4..5b6393e3ea27 100644
--- a/drivers/ptp/ptp_dte.c
+++ b/drivers/ptp/ptp_dte.c
@@ -288,8 +288,7 @@ static int ptp_dte_remove(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP
static int ptp_dte_suspend(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct ptp_dte *ptp_dte = platform_get_drvdata(pdev);
+ struct ptp_dte *ptp_dte = dev_get_drvdata(dev);
u8 i;
for (i = 0; i < DTE_NUM_REGS_TO_RESTORE; i++) {
@@ -305,8 +304,7 @@ static int ptp_dte_suspend(struct device *dev)
static int ptp_dte_resume(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct ptp_dte *ptp_dte = platform_get_drvdata(pdev);
+ struct ptp_dte *ptp_dte = dev_get_drvdata(dev);
u8 i;
for (i = 0; i < DTE_NUM_REGS_TO_RESTORE; i++) {
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 504d252716f2..27e5dd47a01f 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -447,10 +447,9 @@ config PWM_TEGRA
config PWM_TIECAP
tristate "ECAP PWM support"
- depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX || ARCH_KEYSTONE
+ depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX || ARCH_KEYSTONE || ARCH_K3
help
- PWM driver support for the ECAP APWM controller found on AM33XX
- TI SOC
+ PWM driver support for the ECAP APWM controller found on TI SOCs
To compile this driver as a module, choose M here: the module
will be called pwm-tiecap.
diff --git a/drivers/pwm/pwm-lpss-platform.c b/drivers/pwm/pwm-lpss-platform.c
index 5561b9e190f8..757230e1f575 100644
--- a/drivers/pwm/pwm-lpss-platform.c
+++ b/drivers/pwm/pwm-lpss-platform.c
@@ -30,6 +30,7 @@ static const struct pwm_lpss_boardinfo pwm_lpss_bsw_info = {
.clk_rate = 19200000,
.npwm = 1,
.base_unit_bits = 16,
+ .other_devices_aml_touches_pwm_regs = true,
};
/* Broxton */
@@ -60,6 +61,7 @@ static int pwm_lpss_probe_platform(struct platform_device *pdev)
platform_set_drvdata(pdev, lpwm);
+ dev_pm_set_driver_flags(&pdev->dev, DPM_FLAG_SMART_PREPARE);
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
@@ -74,13 +76,29 @@ static int pwm_lpss_remove_platform(struct platform_device *pdev)
return pwm_lpss_remove(lpwm);
}
-static SIMPLE_DEV_PM_OPS(pwm_lpss_platform_pm_ops,
- pwm_lpss_suspend,
- pwm_lpss_resume);
+static int pwm_lpss_prepare(struct device *dev)
+{
+ struct pwm_lpss_chip *lpwm = dev_get_drvdata(dev);
+
+ /*
+ * If other device's AML code touches the PWM regs on suspend/resume
+ * force runtime-resume the PWM controller to allow this.
+ */
+ if (lpwm->info->other_devices_aml_touches_pwm_regs)
+ return 0; /* Force runtime-resume */
+
+ return 1; /* If runtime-suspended leave as is */
+}
+
+static const struct dev_pm_ops pwm_lpss_platform_pm_ops = {
+ .prepare = pwm_lpss_prepare,
+ SET_SYSTEM_SLEEP_PM_OPS(pwm_lpss_suspend, pwm_lpss_resume)
+};
static const struct acpi_device_id pwm_lpss_acpi_match[] = {
{ "80860F09", (unsigned long)&pwm_lpss_byt_info },
{ "80862288", (unsigned long)&pwm_lpss_bsw_info },
+ { "80862289", (unsigned long)&pwm_lpss_bsw_info },
{ "80865AC8", (unsigned long)&pwm_lpss_bxt_info },
{ },
};
diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c
index 4721a264bac2..2ac3a2aa9e53 100644
--- a/drivers/pwm/pwm-lpss.c
+++ b/drivers/pwm/pwm-lpss.c
@@ -32,15 +32,6 @@
/* Size of each PWM register space if multiple */
#define PWM_SIZE 0x400
-#define MAX_PWMS 4
-
-struct pwm_lpss_chip {
- struct pwm_chip chip;
- void __iomem *regs;
- const struct pwm_lpss_boardinfo *info;
- u32 saved_ctrl[MAX_PWMS];
-};
-
static inline struct pwm_lpss_chip *to_lpwm(struct pwm_chip *chip)
{
return container_of(chip, struct pwm_lpss_chip, chip);
@@ -97,7 +88,7 @@ static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, struct pwm_device *pwm,
unsigned long long on_time_div;
unsigned long c = lpwm->info->clk_rate, base_unit_range;
unsigned long long base_unit, freq = NSEC_PER_SEC;
- u32 ctrl;
+ u32 orig_ctrl, ctrl;
do_div(freq, period_ns);
@@ -114,13 +105,17 @@ static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, struct pwm_device *pwm,
do_div(on_time_div, period_ns);
on_time_div = 255ULL - on_time_div;
- ctrl = pwm_lpss_read(pwm);
+ orig_ctrl = ctrl = pwm_lpss_read(pwm);
ctrl &= ~PWM_ON_TIME_DIV_MASK;
ctrl &= ~(base_unit_range << PWM_BASE_UNIT_SHIFT);
base_unit &= base_unit_range;
ctrl |= (u32) base_unit << PWM_BASE_UNIT_SHIFT;
ctrl |= on_time_div;
- pwm_lpss_write(pwm, ctrl);
+
+ if (orig_ctrl != ctrl) {
+ pwm_lpss_write(pwm, ctrl);
+ pwm_lpss_write(pwm, ctrl | PWM_SW_UPDATE);
+ }
}
static inline void pwm_lpss_cond_enable(struct pwm_device *pwm, bool cond)
@@ -144,7 +139,6 @@ static int pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return ret;
}
pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, state->period);
- pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_SW_UPDATE);
pwm_lpss_cond_enable(pwm, lpwm->info->bypass == false);
ret = pwm_lpss_wait_for_update(pwm);
if (ret) {
@@ -157,7 +151,6 @@ static int pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm,
if (ret)
return ret;
pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, state->period);
- pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_SW_UPDATE);
return pwm_lpss_wait_for_update(pwm);
}
} else if (pwm_is_enabled(pwm)) {
@@ -168,8 +161,42 @@ static int pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return 0;
}
+/* This function gets called once from pwmchip_add to get the initial state */
+static void pwm_lpss_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
+ struct pwm_state *state)
+{
+ struct pwm_lpss_chip *lpwm = to_lpwm(chip);
+ unsigned long base_unit_range;
+ unsigned long long base_unit, freq, on_time_div;
+ u32 ctrl;
+
+ base_unit_range = BIT(lpwm->info->base_unit_bits);
+
+ ctrl = pwm_lpss_read(pwm);
+ on_time_div = 255 - (ctrl & PWM_ON_TIME_DIV_MASK);
+ base_unit = (ctrl >> PWM_BASE_UNIT_SHIFT) & (base_unit_range - 1);
+
+ freq = base_unit * lpwm->info->clk_rate;
+ do_div(freq, base_unit_range);
+ if (freq == 0)
+ state->period = NSEC_PER_SEC;
+ else
+ state->period = NSEC_PER_SEC / (unsigned long)freq;
+
+ on_time_div *= state->period;
+ do_div(on_time_div, 255);
+ state->duty_cycle = on_time_div;
+
+ state->polarity = PWM_POLARITY_NORMAL;
+ state->enabled = !!(ctrl & PWM_ENABLE);
+
+ if (state->enabled)
+ pm_runtime_get(chip->dev);
+}
+
static const struct pwm_ops pwm_lpss_ops = {
.apply = pwm_lpss_apply,
+ .get_state = pwm_lpss_get_state,
.owner = THIS_MODULE,
};
@@ -214,6 +241,12 @@ EXPORT_SYMBOL_GPL(pwm_lpss_probe);
int pwm_lpss_remove(struct pwm_lpss_chip *lpwm)
{
+ int i;
+
+ for (i = 0; i < lpwm->info->npwm; i++) {
+ if (pwm_is_enabled(&lpwm->chip.pwms[i]))
+ pm_runtime_put(lpwm->chip.dev);
+ }
return pwmchip_remove(&lpwm->chip);
}
EXPORT_SYMBOL_GPL(pwm_lpss_remove);
diff --git a/drivers/pwm/pwm-lpss.h b/drivers/pwm/pwm-lpss.h
index 7a4238ad1fcb..3236be835bd9 100644
--- a/drivers/pwm/pwm-lpss.h
+++ b/drivers/pwm/pwm-lpss.h
@@ -16,13 +16,25 @@
#include <linux/device.h>
#include <linux/pwm.h>
-struct pwm_lpss_chip;
+#define MAX_PWMS 4
+
+struct pwm_lpss_chip {
+ struct pwm_chip chip;
+ void __iomem *regs;
+ const struct pwm_lpss_boardinfo *info;
+ u32 saved_ctrl[MAX_PWMS];
+};
struct pwm_lpss_boardinfo {
unsigned long clk_rate;
unsigned int npwm;
unsigned long base_unit_bits;
bool bypass;
+ /*
+ * On some devices the _PS0/_PS3 AML code of the GPU (GFX0) device
+ * messes with the PWM0 controllers state,
+ */
+ bool other_devices_aml_touches_pwm_regs;
};
struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r,
diff --git a/drivers/pwm/pwm-rcar.c b/drivers/pwm/pwm-rcar.c
index 748f614d5375..a41812fc6f95 100644
--- a/drivers/pwm/pwm-rcar.c
+++ b/drivers/pwm/pwm-rcar.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* R-Car PWM Timer driver
*
* Copyright (C) 2015 Renesas Electronics Corporation
- *
- * This is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
*/
#include <linux/clk.h>
diff --git a/drivers/pwm/pwm-renesas-tpu.c b/drivers/pwm/pwm-renesas-tpu.c
index 29267d12fb4c..4a855a21b782 100644
--- a/drivers/pwm/pwm-renesas-tpu.c
+++ b/drivers/pwm/pwm-renesas-tpu.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* R-Mobile TPU PWM driver
*
* Copyright (C) 2012 Renesas Solutions Corp.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/clk.h>
diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c
index f8ebbece57b7..48c4595a0ffc 100644
--- a/drivers/pwm/pwm-tegra.c
+++ b/drivers/pwm/pwm-tegra.c
@@ -300,7 +300,6 @@ static const struct of_device_id tegra_pwm_of_match[] = {
{ .compatible = "nvidia,tegra186-pwm", .data = &tegra186_pwm_soc },
{ }
};
-
MODULE_DEVICE_TABLE(of, tegra_pwm_of_match);
static const struct dev_pm_ops tegra_pwm_pm_ops = {
diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c
index 7c71cdb8a9d8..ceb233dd6048 100644
--- a/drivers/pwm/sysfs.c
+++ b/drivers/pwm/sysfs.c
@@ -249,6 +249,7 @@ static void pwm_export_release(struct device *child)
static int pwm_export_child(struct device *parent, struct pwm_device *pwm)
{
struct pwm_export *export;
+ char *pwm_prop[2];
int ret;
if (test_and_set_bit(PWMF_EXPORTED, &pwm->flags))
@@ -263,7 +264,6 @@ static int pwm_export_child(struct device *parent, struct pwm_device *pwm)
export->pwm = pwm;
mutex_init(&export->lock);
- export->child.class = parent->class;
export->child.release = pwm_export_release;
export->child.parent = parent;
export->child.devt = MKDEV(0, 0);
@@ -277,6 +277,10 @@ static int pwm_export_child(struct device *parent, struct pwm_device *pwm)
export = NULL;
return ret;
}
+ pwm_prop[0] = kasprintf(GFP_KERNEL, "EXPORT=pwm%u", pwm->hwpwm);
+ pwm_prop[1] = NULL;
+ kobject_uevent_env(&parent->kobj, KOBJ_CHANGE, pwm_prop);
+ kfree(pwm_prop[0]);
return 0;
}
@@ -289,6 +293,7 @@ static int pwm_unexport_match(struct device *child, void *data)
static int pwm_unexport_child(struct device *parent, struct pwm_device *pwm)
{
struct device *child;
+ char *pwm_prop[2];
if (!test_and_clear_bit(PWMF_EXPORTED, &pwm->flags))
return -ENODEV;
@@ -297,6 +302,11 @@ static int pwm_unexport_child(struct device *parent, struct pwm_device *pwm)
if (!child)
return -ENODEV;
+ pwm_prop[0] = kasprintf(GFP_KERNEL, "UNEXPORT=pwm%u", pwm->hwpwm);
+ pwm_prop[1] = NULL;
+ kobject_uevent_env(&parent->kobj, KOBJ_CHANGE, pwm_prop);
+ kfree(pwm_prop[0]);
+
/* for device_find_child() */
put_device(child);
device_unregister(child);
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 329cdd33ed62..926cee0d0b5f 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -189,7 +189,7 @@ config REGULATOR_BD718XX
and LDO regulators.
This driver can also be built as a module. If so, the module
- will be called bd71837-regulator.
+ will be called bd718x7-regulator.
config REGULATOR_BD9571MWV
tristate "ROHM BD9571MWV Regulators"
@@ -356,6 +356,13 @@ config REGULATOR_LM363X
One boost output voltage is configurable and always on.
Other LDOs are used for the display module.
+config REGULATOR_LOCHNAGAR
+ tristate "Cirrus Logic Lochnagar regulator driver"
+ depends on MFD_LOCHNAGAR
+ help
+ This enables regulator support on the Cirrus Logic Lochnagar audio
+ development board.
+
config REGULATOR_LP3971
tristate "National Semiconductors LP3971 PMIC regulator driver"
depends on I2C
@@ -803,6 +810,18 @@ config REGULATOR_STM32_VREFBUF
This driver can also be built as a module. If so, the module
will be called stm32-vrefbuf.
+config REGULATOR_STPMIC1
+ tristate "STMicroelectronics STPMIC1 PMIC Regulators"
+ depends on MFD_STPMIC1
+ help
+ This driver supports STMicroelectronics STPMIC1 PMIC voltage
+ regulators and switches. The STPMIC1 regulators supply power to
+ an application processor as well as to external system
+ peripherals such as DDR, Flash memories and system devices.
+
+ To compile this driver as a module, choose M here: the
+ module will be called stpmic1_regulator.
+
config REGULATOR_TI_ABB
tristate "TI Adaptive Body Bias on-chip LDO"
depends on ARCH_OMAP
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 801d9a34a203..72488ef11b8a 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -27,7 +27,7 @@ obj-$(CONFIG_REGULATOR_AS3711) += as3711-regulator.o
obj-$(CONFIG_REGULATOR_AS3722) += as3722-regulator.o
obj-$(CONFIG_REGULATOR_AXP20X) += axp20x-regulator.o
obj-$(CONFIG_REGULATOR_BCM590XX) += bcm590xx-regulator.o
-obj-$(CONFIG_REGULATOR_BD718XX) += bd71837-regulator.o
+obj-$(CONFIG_REGULATOR_BD718XX) += bd718x7-regulator.o
obj-$(CONFIG_REGULATOR_BD9571MWV) += bd9571mwv-regulator.o
obj-$(CONFIG_REGULATOR_DA903X) += da903x.o
obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o
@@ -46,6 +46,7 @@ obj-$(CONFIG_REGULATOR_HI655X) += hi655x-regulator.o
obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
obj-$(CONFIG_REGULATOR_ISL9305) += isl9305.o
obj-$(CONFIG_REGULATOR_LM363X) += lm363x-regulator.o
+obj-$(CONFIG_REGULATOR_LOCHNAGAR) += lochnagar-regulator.o
obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o
obj-$(CONFIG_REGULATOR_LP872X) += lp872x.o
@@ -101,6 +102,7 @@ obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
obj-$(CONFIG_REGULATOR_SC2731) += sc2731-regulator.o
obj-$(CONFIG_REGULATOR_SKY81452) += sky81452-regulator.o
obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o
+obj-$(CONFIG_REGULATOR_STPMIC1) += stpmic1_regulator.o
obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o
obj-$(CONFIG_REGULATOR_SY8106A) += sy8106a-regulator.o
obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o
diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c
index e976d073f28d..9a72eae4926d 100644
--- a/drivers/regulator/arizona-ldo1.c
+++ b/drivers/regulator/arizona-ldo1.c
@@ -260,7 +260,7 @@ static int arizona_ldo1_common_init(struct platform_device *pdev,
* so clean up would happen at the wrong time
*/
config.ena_gpiod = gpiod_get_optional(parent_dev, "wlf,ldoena",
- GPIOD_OUT_LOW);
+ GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
if (IS_ERR(config.ena_gpiod))
return PTR_ERR(config.ena_gpiod);
diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c
index 91b8ff8bac15..a3734039a86a 100644
--- a/drivers/regulator/axp20x-regulator.c
+++ b/drivers/regulator/axp20x-regulator.c
@@ -509,10 +509,10 @@ static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
/*
* AXP803/AXP813 DCDC work frequency setting has the same
* range and step as AXP22X, but at a different register.
- * Fall through to the check below.
* (See include/linux/mfd/axp20x.h)
*/
reg = AXP803_DCDC_FREQ_CTRL;
+ /* Fall through to the check below.*/
case AXP806_ID:
/*
* AXP806 also have DCDC work frequency setting register at a
@@ -520,6 +520,7 @@ static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
*/
if (axp20x->variant == AXP806_ID)
reg = AXP806_DCDC_FREQ_CTRL;
+ /* Fall through */
case AXP221_ID:
case AXP223_ID:
case AXP809_ID:
diff --git a/drivers/regulator/bd71837-regulator.c b/drivers/regulator/bd71837-regulator.c
deleted file mode 100644
index a1bd8aaf4d98..000000000000
--- a/drivers/regulator/bd71837-regulator.c
+++ /dev/null
@@ -1,645 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-// Copyright (C) 2018 ROHM Semiconductors
-// bd71837-regulator.c ROHM BD71837MWV regulator driver
-
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/gpio.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/mfd/rohm-bd718x7.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/regulator/driver.h>
-#include <linux/regulator/machine.h>
-#include <linux/regulator/of_regulator.h>
-#include <linux/slab.h>
-
-struct bd71837_pmic {
- struct regulator_desc descs[BD71837_REGULATOR_CNT];
- struct bd71837 *mfd;
- struct platform_device *pdev;
- struct regulator_dev *rdev[BD71837_REGULATOR_CNT];
-};
-
-/*
- * BUCK1/2/3/4
- * BUCK1RAMPRATE[1:0] BUCK1 DVS ramp rate setting
- * 00: 10.00mV/usec 10mV 1uS
- * 01: 5.00mV/usec 10mV 2uS
- * 10: 2.50mV/usec 10mV 4uS
- * 11: 1.25mV/usec 10mV 8uS
- */
-static int bd71837_buck1234_set_ramp_delay(struct regulator_dev *rdev,
- int ramp_delay)
-{
- struct bd71837_pmic *pmic = rdev_get_drvdata(rdev);
- struct bd71837 *mfd = pmic->mfd;
- int id = rdev->desc->id;
- unsigned int ramp_value = BUCK_RAMPRATE_10P00MV;
-
- dev_dbg(&pmic->pdev->dev, "Buck[%d] Set Ramp = %d\n", id + 1,
- ramp_delay);
- switch (ramp_delay) {
- case 1 ... 1250:
- ramp_value = BUCK_RAMPRATE_1P25MV;
- break;
- case 1251 ... 2500:
- ramp_value = BUCK_RAMPRATE_2P50MV;
- break;
- case 2501 ... 5000:
- ramp_value = BUCK_RAMPRATE_5P00MV;
- break;
- case 5001 ... 10000:
- ramp_value = BUCK_RAMPRATE_10P00MV;
- break;
- default:
- ramp_value = BUCK_RAMPRATE_10P00MV;
- dev_err(&pmic->pdev->dev,
- "%s: ramp_delay: %d not supported, setting 10000mV//us\n",
- rdev->desc->name, ramp_delay);
- }
-
- return regmap_update_bits(mfd->regmap, BD71837_REG_BUCK1_CTRL + id,
- BUCK_RAMPRATE_MASK, ramp_value << 6);
-}
-
-/* Bucks 1 to 4 support DVS. PWM mode is used when voltage is changed.
- * Bucks 5 to 8 and LDOs can use PFM and must be disabled when voltage
- * is changed. Hence we return -EBUSY for these if voltage is changed
- * when BUCK/LDO is enabled.
- */
-static int bd71837_set_voltage_sel_restricted(struct regulator_dev *rdev,
- unsigned int sel)
-{
- if (regulator_is_enabled_regmap(rdev))
- return -EBUSY;
-
- return regulator_set_voltage_sel_regmap(rdev, sel);
-}
-
-static struct regulator_ops bd71837_ldo_regulator_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 = bd71837_set_voltage_sel_restricted,
- .get_voltage_sel = regulator_get_voltage_sel_regmap,
-};
-
-static struct regulator_ops bd71837_ldo_regulator_nolinear_ops = {
- .enable = regulator_enable_regmap,
- .disable = regulator_disable_regmap,
- .is_enabled = regulator_is_enabled_regmap,
- .list_voltage = regulator_list_voltage_table,
- .set_voltage_sel = bd71837_set_voltage_sel_restricted,
- .get_voltage_sel = regulator_get_voltage_sel_regmap,
-};
-
-static struct regulator_ops bd71837_buck_regulator_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 = bd71837_set_voltage_sel_restricted,
- .get_voltage_sel = regulator_get_voltage_sel_regmap,
- .set_voltage_time_sel = regulator_set_voltage_time_sel,
-};
-
-static struct regulator_ops bd71837_buck_regulator_nolinear_ops = {
- .enable = regulator_enable_regmap,
- .disable = regulator_disable_regmap,
- .is_enabled = regulator_is_enabled_regmap,
- .list_voltage = regulator_list_voltage_table,
- .set_voltage_sel = bd71837_set_voltage_sel_restricted,
- .get_voltage_sel = regulator_get_voltage_sel_regmap,
- .set_voltage_time_sel = regulator_set_voltage_time_sel,
-};
-
-static struct regulator_ops bd71837_buck1234_regulator_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 = bd71837_buck1234_set_ramp_delay,
-};
-
-/*
- * BUCK1/2/3/4
- * 0.70 to 1.30V (10mV step)
- */
-static const struct regulator_linear_range bd71837_buck1234_voltage_ranges[] = {
- REGULATOR_LINEAR_RANGE(700000, 0x00, 0x3C, 10000),
- REGULATOR_LINEAR_RANGE(1300000, 0x3D, 0x3F, 0),
-};
-
-/*
- * BUCK5
- * 0.9V to 1.35V ()
- */
-static const struct regulator_linear_range bd71837_buck5_voltage_ranges[] = {
- REGULATOR_LINEAR_RANGE(700000, 0x00, 0x03, 100000),
- REGULATOR_LINEAR_RANGE(1050000, 0x04, 0x05, 50000),
- REGULATOR_LINEAR_RANGE(1200000, 0x06, 0x07, 150000),
-};
-
-/*
- * BUCK6
- * 3.0V to 3.3V (step 100mV)
- */
-static const struct regulator_linear_range bd71837_buck6_voltage_ranges[] = {
- REGULATOR_LINEAR_RANGE(3000000, 0x00, 0x03, 100000),
-};
-
-/*
- * BUCK7
- * 000 = 1.605V
- * 001 = 1.695V
- * 010 = 1.755V
- * 011 = 1.8V (Initial)
- * 100 = 1.845V
- * 101 = 1.905V
- * 110 = 1.95V
- * 111 = 1.995V
- */
-static const unsigned int buck_7_volts[] = {
- 1605000, 1695000, 1755000, 1800000, 1845000, 1905000, 1950000, 1995000
-};
-
-/*
- * BUCK8
- * 0.8V to 1.40V (step 10mV)
- */
-static const struct regulator_linear_range bd71837_buck8_voltage_ranges[] = {
- REGULATOR_LINEAR_RANGE(800000, 0x00, 0x3C, 10000),
- REGULATOR_LINEAR_RANGE(1400000, 0x3D, 0x3F, 0),
-};
-
-/*
- * LDO1
- * 3.0 to 3.3V (100mV step)
- */
-static const struct regulator_linear_range bd71837_ldo1_voltage_ranges[] = {
- REGULATOR_LINEAR_RANGE(3000000, 0x00, 0x03, 100000),
-};
-
-/*
- * LDO2
- * 0.8 or 0.9V
- */
-static const unsigned int ldo_2_volts[] = {
- 900000, 800000
-};
-
-/*
- * LDO3
- * 1.8 to 3.3V (100mV step)
- */
-static const struct regulator_linear_range bd71837_ldo3_voltage_ranges[] = {
- REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
-};
-
-/*
- * LDO4
- * 0.9 to 1.8V (100mV step)
- */
-static const struct regulator_linear_range bd71837_ldo4_voltage_ranges[] = {
- REGULATOR_LINEAR_RANGE(900000, 0x00, 0x09, 100000),
- REGULATOR_LINEAR_RANGE(1800000, 0x0A, 0x0F, 0),
-};
-
-/*
- * LDO5
- * 1.8 to 3.3V (100mV step)
- */
-static const struct regulator_linear_range bd71837_ldo5_voltage_ranges[] = {
- REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
-};
-
-/*
- * LDO6
- * 0.9 to 1.8V (100mV step)
- */
-static const struct regulator_linear_range bd71837_ldo6_voltage_ranges[] = {
- REGULATOR_LINEAR_RANGE(900000, 0x00, 0x09, 100000),
- REGULATOR_LINEAR_RANGE(1800000, 0x0A, 0x0F, 0),
-};
-
-/*
- * LDO7
- * 1.8 to 3.3V (100mV step)
- */
-static const struct regulator_linear_range bd71837_ldo7_voltage_ranges[] = {
- REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
-};
-
-static const struct regulator_desc bd71837_regulators[] = {
- {
- .name = "buck1",
- .of_match = of_match_ptr("BUCK1"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD71837_BUCK1,
- .ops = &bd71837_buck1234_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .n_voltages = BD71837_BUCK1_VOLTAGE_NUM,
- .linear_ranges = bd71837_buck1234_voltage_ranges,
- .n_linear_ranges = ARRAY_SIZE(bd71837_buck1234_voltage_ranges),
- .vsel_reg = BD71837_REG_BUCK1_VOLT_RUN,
- .vsel_mask = BUCK1_RUN_MASK,
- .enable_reg = BD71837_REG_BUCK1_CTRL,
- .enable_mask = BD71837_BUCK_EN,
- .owner = THIS_MODULE,
- },
- {
- .name = "buck2",
- .of_match = of_match_ptr("BUCK2"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD71837_BUCK2,
- .ops = &bd71837_buck1234_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .n_voltages = BD71837_BUCK2_VOLTAGE_NUM,
- .linear_ranges = bd71837_buck1234_voltage_ranges,
- .n_linear_ranges = ARRAY_SIZE(bd71837_buck1234_voltage_ranges),
- .vsel_reg = BD71837_REG_BUCK2_VOLT_RUN,
- .vsel_mask = BUCK2_RUN_MASK,
- .enable_reg = BD71837_REG_BUCK2_CTRL,
- .enable_mask = BD71837_BUCK_EN,
- .owner = THIS_MODULE,
- },
- {
- .name = "buck3",
- .of_match = of_match_ptr("BUCK3"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD71837_BUCK3,
- .ops = &bd71837_buck1234_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .n_voltages = BD71837_BUCK3_VOLTAGE_NUM,
- .linear_ranges = bd71837_buck1234_voltage_ranges,
- .n_linear_ranges = ARRAY_SIZE(bd71837_buck1234_voltage_ranges),
- .vsel_reg = BD71837_REG_BUCK3_VOLT_RUN,
- .vsel_mask = BUCK3_RUN_MASK,
- .enable_reg = BD71837_REG_BUCK3_CTRL,
- .enable_mask = BD71837_BUCK_EN,
- .owner = THIS_MODULE,
- },
- {
- .name = "buck4",
- .of_match = of_match_ptr("BUCK4"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD71837_BUCK4,
- .ops = &bd71837_buck1234_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .n_voltages = BD71837_BUCK4_VOLTAGE_NUM,
- .linear_ranges = bd71837_buck1234_voltage_ranges,
- .n_linear_ranges = ARRAY_SIZE(bd71837_buck1234_voltage_ranges),
- .vsel_reg = BD71837_REG_BUCK4_VOLT_RUN,
- .vsel_mask = BUCK4_RUN_MASK,
- .enable_reg = BD71837_REG_BUCK4_CTRL,
- .enable_mask = BD71837_BUCK_EN,
- .owner = THIS_MODULE,
- },
- {
- .name = "buck5",
- .of_match = of_match_ptr("BUCK5"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD71837_BUCK5,
- .ops = &bd71837_buck_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .n_voltages = BD71837_BUCK5_VOLTAGE_NUM,
- .linear_ranges = bd71837_buck5_voltage_ranges,
- .n_linear_ranges = ARRAY_SIZE(bd71837_buck5_voltage_ranges),
- .vsel_reg = BD71837_REG_BUCK5_VOLT,
- .vsel_mask = BUCK5_MASK,
- .enable_reg = BD71837_REG_BUCK5_CTRL,
- .enable_mask = BD71837_BUCK_EN,
- .owner = THIS_MODULE,
- },
- {
- .name = "buck6",
- .of_match = of_match_ptr("BUCK6"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD71837_BUCK6,
- .ops = &bd71837_buck_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .n_voltages = BD71837_BUCK6_VOLTAGE_NUM,
- .linear_ranges = bd71837_buck6_voltage_ranges,
- .n_linear_ranges = ARRAY_SIZE(bd71837_buck6_voltage_ranges),
- .vsel_reg = BD71837_REG_BUCK6_VOLT,
- .vsel_mask = BUCK6_MASK,
- .enable_reg = BD71837_REG_BUCK6_CTRL,
- .enable_mask = BD71837_BUCK_EN,
- .owner = THIS_MODULE,
- },
- {
- .name = "buck7",
- .of_match = of_match_ptr("BUCK7"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD71837_BUCK7,
- .ops = &bd71837_buck_regulator_nolinear_ops,
- .type = REGULATOR_VOLTAGE,
- .volt_table = &buck_7_volts[0],
- .n_voltages = ARRAY_SIZE(buck_7_volts),
- .vsel_reg = BD71837_REG_BUCK7_VOLT,
- .vsel_mask = BUCK7_MASK,
- .enable_reg = BD71837_REG_BUCK7_CTRL,
- .enable_mask = BD71837_BUCK_EN,
- .owner = THIS_MODULE,
- },
- {
- .name = "buck8",
- .of_match = of_match_ptr("BUCK8"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD71837_BUCK8,
- .ops = &bd71837_buck_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .n_voltages = BD71837_BUCK8_VOLTAGE_NUM,
- .linear_ranges = bd71837_buck8_voltage_ranges,
- .n_linear_ranges = ARRAY_SIZE(bd71837_buck8_voltage_ranges),
- .vsel_reg = BD71837_REG_BUCK8_VOLT,
- .vsel_mask = BUCK8_MASK,
- .enable_reg = BD71837_REG_BUCK8_CTRL,
- .enable_mask = BD71837_BUCK_EN,
- .owner = THIS_MODULE,
- },
- {
- .name = "ldo1",
- .of_match = of_match_ptr("LDO1"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD71837_LDO1,
- .ops = &bd71837_ldo_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .n_voltages = BD71837_LDO1_VOLTAGE_NUM,
- .linear_ranges = bd71837_ldo1_voltage_ranges,
- .n_linear_ranges = ARRAY_SIZE(bd71837_ldo1_voltage_ranges),
- .vsel_reg = BD71837_REG_LDO1_VOLT,
- .vsel_mask = LDO1_MASK,
- .enable_reg = BD71837_REG_LDO1_VOLT,
- .enable_mask = BD71837_LDO_EN,
- .owner = THIS_MODULE,
- },
- {
- .name = "ldo2",
- .of_match = of_match_ptr("LDO2"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD71837_LDO2,
- .ops = &bd71837_ldo_regulator_nolinear_ops,
- .type = REGULATOR_VOLTAGE,
- .volt_table = &ldo_2_volts[0],
- .vsel_reg = BD71837_REG_LDO2_VOLT,
- .vsel_mask = LDO2_MASK,
- .n_voltages = ARRAY_SIZE(ldo_2_volts),
- .n_voltages = BD71837_LDO2_VOLTAGE_NUM,
- .enable_reg = BD71837_REG_LDO2_VOLT,
- .enable_mask = BD71837_LDO_EN,
- .owner = THIS_MODULE,
- },
- {
- .name = "ldo3",
- .of_match = of_match_ptr("LDO3"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD71837_LDO3,
- .ops = &bd71837_ldo_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .n_voltages = BD71837_LDO3_VOLTAGE_NUM,
- .linear_ranges = bd71837_ldo3_voltage_ranges,
- .n_linear_ranges = ARRAY_SIZE(bd71837_ldo3_voltage_ranges),
- .vsel_reg = BD71837_REG_LDO3_VOLT,
- .vsel_mask = LDO3_MASK,
- .enable_reg = BD71837_REG_LDO3_VOLT,
- .enable_mask = BD71837_LDO_EN,
- .owner = THIS_MODULE,
- },
- {
- .name = "ldo4",
- .of_match = of_match_ptr("LDO4"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD71837_LDO4,
- .ops = &bd71837_ldo_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .n_voltages = BD71837_LDO4_VOLTAGE_NUM,
- .linear_ranges = bd71837_ldo4_voltage_ranges,
- .n_linear_ranges = ARRAY_SIZE(bd71837_ldo4_voltage_ranges),
- .vsel_reg = BD71837_REG_LDO4_VOLT,
- .vsel_mask = LDO4_MASK,
- .enable_reg = BD71837_REG_LDO4_VOLT,
- .enable_mask = BD71837_LDO_EN,
- .owner = THIS_MODULE,
- },
- {
- .name = "ldo5",
- .of_match = of_match_ptr("LDO5"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD71837_LDO5,
- .ops = &bd71837_ldo_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .n_voltages = BD71837_LDO5_VOLTAGE_NUM,
- .linear_ranges = bd71837_ldo5_voltage_ranges,
- .n_linear_ranges = ARRAY_SIZE(bd71837_ldo5_voltage_ranges),
- /* LDO5 is supplied by buck6 */
- .supply_name = "buck6",
- .vsel_reg = BD71837_REG_LDO5_VOLT,
- .vsel_mask = LDO5_MASK,
- .enable_reg = BD71837_REG_LDO5_VOLT,
- .enable_mask = BD71837_LDO_EN,
- .owner = THIS_MODULE,
- },
- {
- .name = "ldo6",
- .of_match = of_match_ptr("LDO6"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD71837_LDO6,
- .ops = &bd71837_ldo_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .n_voltages = BD71837_LDO6_VOLTAGE_NUM,
- .linear_ranges = bd71837_ldo6_voltage_ranges,
- .n_linear_ranges = ARRAY_SIZE(bd71837_ldo6_voltage_ranges),
- /* LDO6 is supplied by buck7 */
- .supply_name = "buck7",
- .vsel_reg = BD71837_REG_LDO6_VOLT,
- .vsel_mask = LDO6_MASK,
- .enable_reg = BD71837_REG_LDO6_VOLT,
- .enable_mask = BD71837_LDO_EN,
- .owner = THIS_MODULE,
- },
- {
- .name = "ldo7",
- .of_match = of_match_ptr("LDO7"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD71837_LDO7,
- .ops = &bd71837_ldo_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .n_voltages = BD71837_LDO7_VOLTAGE_NUM,
- .linear_ranges = bd71837_ldo7_voltage_ranges,
- .n_linear_ranges = ARRAY_SIZE(bd71837_ldo7_voltage_ranges),
- .vsel_reg = BD71837_REG_LDO7_VOLT,
- .vsel_mask = LDO7_MASK,
- .enable_reg = BD71837_REG_LDO7_VOLT,
- .enable_mask = BD71837_LDO_EN,
- .owner = THIS_MODULE,
- },
-};
-
-struct reg_init {
- unsigned int reg;
- unsigned int mask;
-};
-
-static int bd71837_probe(struct platform_device *pdev)
-{
- struct bd71837_pmic *pmic;
- struct regulator_config config = { 0 };
- struct reg_init pmic_regulator_inits[] = {
- {
- .reg = BD71837_REG_BUCK1_CTRL,
- .mask = BD71837_BUCK_SEL,
- }, {
- .reg = BD71837_REG_BUCK2_CTRL,
- .mask = BD71837_BUCK_SEL,
- }, {
- .reg = BD71837_REG_BUCK3_CTRL,
- .mask = BD71837_BUCK_SEL,
- }, {
- .reg = BD71837_REG_BUCK4_CTRL,
- .mask = BD71837_BUCK_SEL,
- }, {
- .reg = BD71837_REG_BUCK5_CTRL,
- .mask = BD71837_BUCK_SEL,
- }, {
- .reg = BD71837_REG_BUCK6_CTRL,
- .mask = BD71837_BUCK_SEL,
- }, {
- .reg = BD71837_REG_BUCK7_CTRL,
- .mask = BD71837_BUCK_SEL,
- }, {
- .reg = BD71837_REG_BUCK8_CTRL,
- .mask = BD71837_BUCK_SEL,
- }, {
- .reg = BD71837_REG_LDO1_VOLT,
- .mask = BD71837_LDO_SEL,
- }, {
- .reg = BD71837_REG_LDO2_VOLT,
- .mask = BD71837_LDO_SEL,
- }, {
- .reg = BD71837_REG_LDO3_VOLT,
- .mask = BD71837_LDO_SEL,
- }, {
- .reg = BD71837_REG_LDO4_VOLT,
- .mask = BD71837_LDO_SEL,
- }, {
- .reg = BD71837_REG_LDO5_VOLT,
- .mask = BD71837_LDO_SEL,
- }, {
- .reg = BD71837_REG_LDO6_VOLT,
- .mask = BD71837_LDO_SEL,
- }, {
- .reg = BD71837_REG_LDO7_VOLT,
- .mask = BD71837_LDO_SEL,
- }
- };
-
- int i, err;
-
- pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
- if (!pmic)
- return -ENOMEM;
-
- memcpy(pmic->descs, bd71837_regulators, sizeof(pmic->descs));
-
- pmic->pdev = pdev;
- pmic->mfd = dev_get_drvdata(pdev->dev.parent);
-
- if (!pmic->mfd) {
- dev_err(&pdev->dev, "No MFD driver data\n");
- err = -EINVAL;
- goto err;
- }
- platform_set_drvdata(pdev, pmic);
-
- /* Register LOCK release */
- err = regmap_update_bits(pmic->mfd->regmap, BD71837_REG_REGLOCK,
- (REGLOCK_PWRSEQ | REGLOCK_VREG), 0);
- if (err) {
- dev_err(&pmic->pdev->dev, "Failed to unlock PMIC (%d)\n", err);
- goto err;
- } else {
- dev_dbg(&pmic->pdev->dev, "Unlocked lock register 0x%x\n",
- BD71837_REG_REGLOCK);
- }
-
- /*
- * There is a HW quirk in BD71837. The shutdown sequence timings for
- * bucks/LDOs which are controlled via register interface are changed.
- * At PMIC poweroff the voltage for BUCK6/7 is cut immediately at the
- * beginning of shut-down sequence. As bucks 6 and 7 are parent
- * supplies for LDO5 and LDO6 - this causes LDO5/6 voltage
- * monitoring to errorneously detect under voltage and force PMIC to
- * emergency state instead of poweroff. In order to avoid this we
- * disable voltage monitoring for LDO5 and LDO6
- */
- err = regmap_update_bits(pmic->mfd->regmap, BD718XX_REG_MVRFLTMASK2,
- BD718XX_LDO5_VRMON80 | BD718XX_LDO6_VRMON80,
- BD718XX_LDO5_VRMON80 | BD718XX_LDO6_VRMON80);
- if (err) {
- dev_err(&pmic->pdev->dev,
- "Failed to disable voltage monitoring\n");
- goto err;
- }
-
- for (i = 0; i < ARRAY_SIZE(pmic_regulator_inits); i++) {
-
- struct regulator_desc *desc;
- struct regulator_dev *rdev;
-
- desc = &pmic->descs[i];
-
- config.dev = pdev->dev.parent;
- config.driver_data = pmic;
- config.regmap = pmic->mfd->regmap;
-
- rdev = devm_regulator_register(&pdev->dev, desc, &config);
- if (IS_ERR(rdev)) {
- dev_err(pmic->mfd->dev,
- "failed to register %s regulator\n",
- desc->name);
- err = PTR_ERR(rdev);
- goto err;
- }
- /* Regulator register gets the regulator constraints and
- * applies them (set_machine_constraints). This should have
- * turned the control register(s) to correct values and we
- * can now switch the control from PMIC state machine to the
- * register interface
- */
- err = regmap_update_bits(pmic->mfd->regmap,
- pmic_regulator_inits[i].reg,
- pmic_regulator_inits[i].mask,
- 0xFFFFFFFF);
- if (err) {
- dev_err(&pmic->pdev->dev,
- "Failed to write BUCK/LDO SEL bit for (%s)\n",
- desc->name);
- goto err;
- }
-
- pmic->rdev[i] = rdev;
- }
-
-err:
- return err;
-}
-
-static struct platform_driver bd71837_regulator = {
- .driver = {
- .name = "bd71837-pmic",
- },
- .probe = bd71837_probe,
-};
-
-module_platform_driver(bd71837_regulator);
-
-MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
-MODULE_DESCRIPTION("BD71837 voltage regulator driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/bd718x7-regulator.c b/drivers/regulator/bd718x7-regulator.c
new file mode 100644
index 000000000000..3a47e0372e77
--- /dev/null
+++ b/drivers/regulator/bd718x7-regulator.c
@@ -0,0 +1,1119 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2018 ROHM Semiconductors
+// bd71837-regulator.c ROHM BD71837MWV/BD71847MWV regulator driver
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/rohm-bd718x7.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/slab.h>
+
+/*
+ * BUCK1/2/3/4
+ * BUCK1RAMPRATE[1:0] BUCK1 DVS ramp rate setting
+ * 00: 10.00mV/usec 10mV 1uS
+ * 01: 5.00mV/usec 10mV 2uS
+ * 10: 2.50mV/usec 10mV 4uS
+ * 11: 1.25mV/usec 10mV 8uS
+ */
+static int bd718xx_buck1234_set_ramp_delay(struct regulator_dev *rdev,
+ int ramp_delay)
+{
+ int id = rdev->desc->id;
+ unsigned int ramp_value = BUCK_RAMPRATE_10P00MV;
+
+ dev_dbg(&rdev->dev, "Buck[%d] Set Ramp = %d\n", id + 1,
+ ramp_delay);
+ switch (ramp_delay) {
+ case 1 ... 1250:
+ ramp_value = BUCK_RAMPRATE_1P25MV;
+ break;
+ case 1251 ... 2500:
+ ramp_value = BUCK_RAMPRATE_2P50MV;
+ break;
+ case 2501 ... 5000:
+ ramp_value = BUCK_RAMPRATE_5P00MV;
+ break;
+ case 5001 ... 10000:
+ ramp_value = BUCK_RAMPRATE_10P00MV;
+ break;
+ default:
+ ramp_value = BUCK_RAMPRATE_10P00MV;
+ dev_err(&rdev->dev,
+ "%s: ramp_delay: %d not supported, setting 10000mV//us\n",
+ rdev->desc->name, ramp_delay);
+ }
+
+ return regmap_update_bits(rdev->regmap, BD718XX_REG_BUCK1_CTRL + id,
+ BUCK_RAMPRATE_MASK, ramp_value << 6);
+}
+
+/* Bucks 1 to 4 support DVS. PWM mode is used when voltage is changed.
+ * Bucks 5 to 8 and LDOs can use PFM and must be disabled when voltage
+ * is changed. Hence we return -EBUSY for these if voltage is changed
+ * when BUCK/LDO is enabled.
+ */
+static int bd718xx_set_voltage_sel_restricted(struct regulator_dev *rdev,
+ unsigned int sel)
+{
+ if (regulator_is_enabled_regmap(rdev))
+ return -EBUSY;
+
+ return regulator_set_voltage_sel_regmap(rdev, sel);
+}
+
+static int bd718xx_set_voltage_sel_pickable_restricted(
+ struct regulator_dev *rdev, unsigned int sel)
+{
+ if (regulator_is_enabled_regmap(rdev))
+ return -EBUSY;
+
+ return regulator_set_voltage_sel_pickable_regmap(rdev, sel);
+}
+
+static struct regulator_ops bd718xx_pickable_range_ldo_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_pickable_linear_range,
+ .set_voltage_sel = bd718xx_set_voltage_sel_pickable_restricted,
+ .get_voltage_sel = regulator_get_voltage_sel_pickable_regmap,
+};
+
+static struct regulator_ops bd718xx_pickable_range_buck_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_pickable_linear_range,
+ .set_voltage_sel = bd718xx_set_voltage_sel_pickable_restricted,
+ .get_voltage_sel = regulator_get_voltage_sel_pickable_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+};
+
+static struct regulator_ops bd718xx_ldo_regulator_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 = bd718xx_set_voltage_sel_restricted,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+};
+
+static struct regulator_ops bd718xx_ldo_regulator_nolinear_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_table,
+ .set_voltage_sel = bd718xx_set_voltage_sel_restricted,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+};
+
+static struct regulator_ops bd718xx_buck_regulator_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 = bd718xx_set_voltage_sel_restricted,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+};
+
+static struct regulator_ops bd718xx_buck_regulator_nolinear_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_table,
+ .set_voltage_sel = bd718xx_set_voltage_sel_restricted,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+};
+
+static struct regulator_ops bd718xx_dvs_buck_regulator_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 = bd718xx_buck1234_set_ramp_delay,
+};
+
+/*
+ * BD71837 BUCK1/2/3/4
+ * BD71847 BUCK1/2
+ * 0.70 to 1.30V (10mV step)
+ */
+static const struct regulator_linear_range bd718xx_dvs_buck_volts[] = {
+ REGULATOR_LINEAR_RANGE(700000, 0x00, 0x3C, 10000),
+ REGULATOR_LINEAR_RANGE(1300000, 0x3D, 0x3F, 0),
+};
+
+/*
+ * BD71837 BUCK5
+ * 0.7V to 1.35V (range 0)
+ * and
+ * 0.675 to 1.325 (range 1)
+ */
+static const struct regulator_linear_range bd71837_buck5_volts[] = {
+ /* Ranges when VOLT_SEL bit is 0 */
+ REGULATOR_LINEAR_RANGE(700000, 0x00, 0x03, 100000),
+ REGULATOR_LINEAR_RANGE(1050000, 0x04, 0x05, 50000),
+ REGULATOR_LINEAR_RANGE(1200000, 0x06, 0x07, 150000),
+ /* Ranges when VOLT_SEL bit is 1 */
+ REGULATOR_LINEAR_RANGE(675000, 0x0, 0x3, 100000),
+ REGULATOR_LINEAR_RANGE(1025000, 0x4, 0x5, 50000),
+ REGULATOR_LINEAR_RANGE(1175000, 0x6, 0x7, 150000),
+};
+
+/*
+ * Range selector for first 3 linear ranges is 0x0
+ * and 0x1 for last 3 ranges.
+ */
+static const unsigned int bd71837_buck5_volt_range_sel[] = {
+ 0x0, 0x0, 0x0, 0x80, 0x80, 0x80
+};
+
+/*
+ * BD71847 BUCK3
+ */
+static const struct regulator_linear_range bd71847_buck3_volts[] = {
+ /* Ranges when VOLT_SEL bits are 00 */
+ REGULATOR_LINEAR_RANGE(700000, 0x00, 0x03, 100000),
+ REGULATOR_LINEAR_RANGE(1050000, 0x04, 0x05, 50000),
+ REGULATOR_LINEAR_RANGE(1200000, 0x06, 0x07, 150000),
+ /* Ranges when VOLT_SEL bits are 01 */
+ REGULATOR_LINEAR_RANGE(550000, 0x0, 0x7, 50000),
+ /* Ranges when VOLT_SEL bits are 11 */
+ REGULATOR_LINEAR_RANGE(675000, 0x0, 0x3, 100000),
+ REGULATOR_LINEAR_RANGE(1025000, 0x4, 0x5, 50000),
+ REGULATOR_LINEAR_RANGE(1175000, 0x6, 0x7, 150000),
+};
+
+static const unsigned int bd71847_buck3_volt_range_sel[] = {
+ 0x0, 0x0, 0x0, 0x40, 0x80, 0x80, 0x80
+};
+
+static const struct regulator_linear_range bd71847_buck4_volts[] = {
+ REGULATOR_LINEAR_RANGE(3000000, 0x00, 0x03, 100000),
+ REGULATOR_LINEAR_RANGE(2600000, 0x00, 0x03, 100000),
+};
+
+static const unsigned int bd71847_buck4_volt_range_sel[] = { 0x0, 0x40 };
+
+/*
+ * BUCK6
+ * 3.0V to 3.3V (step 100mV)
+ */
+static const struct regulator_linear_range bd71837_buck6_volts[] = {
+ REGULATOR_LINEAR_RANGE(3000000, 0x00, 0x03, 100000),
+};
+
+/*
+ * BD71837 BUCK7
+ * BD71847 BUCK5
+ * 000 = 1.605V
+ * 001 = 1.695V
+ * 010 = 1.755V
+ * 011 = 1.8V (Initial)
+ * 100 = 1.845V
+ * 101 = 1.905V
+ * 110 = 1.95V
+ * 111 = 1.995V
+ */
+static const unsigned int bd718xx_3rd_nodvs_buck_volts[] = {
+ 1605000, 1695000, 1755000, 1800000, 1845000, 1905000, 1950000, 1995000
+};
+
+/*
+ * BUCK8
+ * 0.8V to 1.40V (step 10mV)
+ */
+static const struct regulator_linear_range bd718xx_4th_nodvs_buck_volts[] = {
+ REGULATOR_LINEAR_RANGE(800000, 0x00, 0x3C, 10000),
+};
+
+/*
+ * LDO1
+ * 3.0 to 3.3V (100mV step)
+ */
+static const struct regulator_linear_range bd718xx_ldo1_volts[] = {
+ REGULATOR_LINEAR_RANGE(3000000, 0x00, 0x03, 100000),
+ REGULATOR_LINEAR_RANGE(1600000, 0x00, 0x03, 100000),
+};
+
+static const unsigned int bd718xx_ldo1_volt_range_sel[] = { 0x0, 0x20 };
+
+/*
+ * LDO2
+ * 0.8 or 0.9V
+ */
+static const unsigned int ldo_2_volts[] = {
+ 900000, 800000
+};
+
+/*
+ * LDO3
+ * 1.8 to 3.3V (100mV step)
+ */
+static const struct regulator_linear_range bd718xx_ldo3_volts[] = {
+ REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
+};
+
+/*
+ * LDO4
+ * 0.9 to 1.8V (100mV step)
+ */
+static const struct regulator_linear_range bd718xx_ldo4_volts[] = {
+ REGULATOR_LINEAR_RANGE(900000, 0x00, 0x09, 100000),
+};
+
+/*
+ * LDO5 for BD71837
+ * 1.8 to 3.3V (100mV step)
+ */
+static const struct regulator_linear_range bd71837_ldo5_volts[] = {
+ REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
+};
+
+/*
+ * LDO5 for BD71837
+ * 1.8 to 3.3V (100mV step)
+ */
+static const struct regulator_linear_range bd71847_ldo5_volts[] = {
+ REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
+ REGULATOR_LINEAR_RANGE(800000, 0x00, 0x0F, 100000),
+};
+
+static const unsigned int bd71847_ldo5_volt_range_sel[] = { 0x0, 0x20 };
+
+/*
+ * LDO6
+ * 0.9 to 1.8V (100mV step)
+ */
+static const struct regulator_linear_range bd718xx_ldo6_volts[] = {
+ REGULATOR_LINEAR_RANGE(900000, 0x00, 0x09, 100000),
+};
+
+/*
+ * LDO7
+ * 1.8 to 3.3V (100mV step)
+ */
+static const struct regulator_linear_range bd71837_ldo7_volts[] = {
+ REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
+};
+
+struct reg_init {
+ unsigned int reg;
+ unsigned int mask;
+ unsigned int val;
+};
+struct bd718xx_regulator_data {
+ struct regulator_desc desc;
+ const struct reg_init init;
+ const struct reg_init *additional_inits;
+ int additional_init_amnt;
+};
+
+/*
+ * There is a HW quirk in BD71837. The shutdown sequence timings for
+ * bucks/LDOs which are controlled via register interface are changed.
+ * At PMIC poweroff the voltage for BUCK6/7 is cut immediately at the
+ * beginning of shut-down sequence. As bucks 6 and 7 are parent
+ * supplies for LDO5 and LDO6 - this causes LDO5/6 voltage
+ * monitoring to errorneously detect under voltage and force PMIC to
+ * emergency state instead of poweroff. In order to avoid this we
+ * disable voltage monitoring for LDO5 and LDO6
+ */
+static const struct reg_init bd71837_ldo5_inits[] = {
+ {
+ .reg = BD718XX_REG_MVRFLTMASK2,
+ .mask = BD718XX_LDO5_VRMON80,
+ .val = BD718XX_LDO5_VRMON80,
+ },
+};
+
+static const struct reg_init bd71837_ldo6_inits[] = {
+ {
+ .reg = BD718XX_REG_MVRFLTMASK2,
+ .mask = BD718XX_LDO6_VRMON80,
+ .val = BD718XX_LDO6_VRMON80,
+ },
+};
+
+static const struct bd718xx_regulator_data bd71847_regulators[] = {
+ {
+ .desc = {
+ .name = "buck1",
+ .of_match = of_match_ptr("BUCK1"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_BUCK1,
+ .ops = &bd718xx_dvs_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD718XX_DVS_BUCK_VOLTAGE_NUM,
+ .linear_ranges = bd718xx_dvs_buck_volts,
+ .n_linear_ranges =
+ ARRAY_SIZE(bd718xx_dvs_buck_volts),
+ .vsel_reg = BD718XX_REG_BUCK1_VOLT_RUN,
+ .vsel_mask = DVS_BUCK_RUN_MASK,
+ .enable_reg = BD718XX_REG_BUCK1_CTRL,
+ .enable_mask = BD718XX_BUCK_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_BUCK1_CTRL,
+ .mask = BD718XX_BUCK_SEL,
+ .val = BD718XX_BUCK_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck2",
+ .of_match = of_match_ptr("BUCK2"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_BUCK2,
+ .ops = &bd718xx_dvs_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD718XX_DVS_BUCK_VOLTAGE_NUM,
+ .linear_ranges = bd718xx_dvs_buck_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd718xx_dvs_buck_volts),
+ .vsel_reg = BD718XX_REG_BUCK2_VOLT_RUN,
+ .vsel_mask = DVS_BUCK_RUN_MASK,
+ .enable_reg = BD718XX_REG_BUCK2_CTRL,
+ .enable_mask = BD718XX_BUCK_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_BUCK2_CTRL,
+ .mask = BD718XX_BUCK_SEL,
+ .val = BD718XX_BUCK_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck3",
+ .of_match = of_match_ptr("BUCK3"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_BUCK3,
+ .ops = &bd718xx_pickable_range_buck_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71847_BUCK3_VOLTAGE_NUM,
+ .linear_ranges = bd71847_buck3_volts,
+ .n_linear_ranges =
+ ARRAY_SIZE(bd71847_buck3_volts),
+ .vsel_reg = BD718XX_REG_1ST_NODVS_BUCK_VOLT,
+ .vsel_mask = BD718XX_1ST_NODVS_BUCK_MASK,
+ .vsel_range_reg = BD718XX_REG_1ST_NODVS_BUCK_VOLT,
+ .vsel_range_mask = BD71847_BUCK3_RANGE_MASK,
+ .linear_range_selectors = bd71847_buck3_volt_range_sel,
+ .enable_reg = BD718XX_REG_1ST_NODVS_BUCK_CTRL,
+ .enable_mask = BD718XX_BUCK_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_1ST_NODVS_BUCK_CTRL,
+ .mask = BD718XX_BUCK_SEL,
+ .val = BD718XX_BUCK_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck4",
+ .of_match = of_match_ptr("BUCK4"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_BUCK4,
+ .ops = &bd718xx_pickable_range_buck_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71847_BUCK4_VOLTAGE_NUM,
+ .linear_ranges = bd71847_buck4_volts,
+ .n_linear_ranges =
+ ARRAY_SIZE(bd71847_buck4_volts),
+ .enable_reg = BD718XX_REG_2ND_NODVS_BUCK_CTRL,
+ .vsel_reg = BD718XX_REG_2ND_NODVS_BUCK_VOLT,
+ .vsel_mask = BD71847_BUCK4_MASK,
+ .vsel_range_reg = BD718XX_REG_2ND_NODVS_BUCK_VOLT,
+ .vsel_range_mask = BD71847_BUCK4_RANGE_MASK,
+ .linear_range_selectors = bd71847_buck4_volt_range_sel,
+ .enable_mask = BD718XX_BUCK_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_2ND_NODVS_BUCK_CTRL,
+ .mask = BD718XX_BUCK_SEL,
+ .val = BD718XX_BUCK_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck5",
+ .of_match = of_match_ptr("BUCK5"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_BUCK5,
+ .ops = &bd718xx_buck_regulator_nolinear_ops,
+ .type = REGULATOR_VOLTAGE,
+ .volt_table = &bd718xx_3rd_nodvs_buck_volts[0],
+ .n_voltages = ARRAY_SIZE(bd718xx_3rd_nodvs_buck_volts),
+ .vsel_reg = BD718XX_REG_3RD_NODVS_BUCK_VOLT,
+ .vsel_mask = BD718XX_3RD_NODVS_BUCK_MASK,
+ .enable_reg = BD718XX_REG_3RD_NODVS_BUCK_CTRL,
+ .enable_mask = BD718XX_BUCK_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_3RD_NODVS_BUCK_CTRL,
+ .mask = BD718XX_BUCK_SEL,
+ .val = BD718XX_BUCK_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck6",
+ .of_match = of_match_ptr("BUCK6"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_BUCK6,
+ .ops = &bd718xx_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD718XX_4TH_NODVS_BUCK_VOLTAGE_NUM,
+ .linear_ranges = bd718xx_4th_nodvs_buck_volts,
+ .n_linear_ranges =
+ ARRAY_SIZE(bd718xx_4th_nodvs_buck_volts),
+ .vsel_reg = BD718XX_REG_4TH_NODVS_BUCK_VOLT,
+ .vsel_mask = BD718XX_4TH_NODVS_BUCK_MASK,
+ .enable_reg = BD718XX_REG_4TH_NODVS_BUCK_CTRL,
+ .enable_mask = BD718XX_BUCK_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_4TH_NODVS_BUCK_CTRL,
+ .mask = BD718XX_BUCK_SEL,
+ .val = BD718XX_BUCK_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo1",
+ .of_match = of_match_ptr("LDO1"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_LDO1,
+ .ops = &bd718xx_pickable_range_ldo_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD718XX_LDO1_VOLTAGE_NUM,
+ .linear_ranges = bd718xx_ldo1_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd718xx_ldo1_volts),
+ .vsel_reg = BD718XX_REG_LDO1_VOLT,
+ .vsel_mask = BD718XX_LDO1_MASK,
+ .vsel_range_reg = BD718XX_REG_LDO1_VOLT,
+ .vsel_range_mask = BD718XX_LDO1_RANGE_MASK,
+ .linear_range_selectors = bd718xx_ldo1_volt_range_sel,
+ .enable_reg = BD718XX_REG_LDO1_VOLT,
+ .enable_mask = BD718XX_LDO_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_LDO1_VOLT,
+ .mask = BD718XX_LDO_SEL,
+ .val = BD718XX_LDO_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo2",
+ .of_match = of_match_ptr("LDO2"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_LDO2,
+ .ops = &bd718xx_ldo_regulator_nolinear_ops,
+ .type = REGULATOR_VOLTAGE,
+ .volt_table = &ldo_2_volts[0],
+ .vsel_reg = BD718XX_REG_LDO2_VOLT,
+ .vsel_mask = BD718XX_LDO2_MASK,
+ .n_voltages = ARRAY_SIZE(ldo_2_volts),
+ .enable_reg = BD718XX_REG_LDO2_VOLT,
+ .enable_mask = BD718XX_LDO_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_LDO2_VOLT,
+ .mask = BD718XX_LDO_SEL,
+ .val = BD718XX_LDO_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo3",
+ .of_match = of_match_ptr("LDO3"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_LDO3,
+ .ops = &bd718xx_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD718XX_LDO3_VOLTAGE_NUM,
+ .linear_ranges = bd718xx_ldo3_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd718xx_ldo3_volts),
+ .vsel_reg = BD718XX_REG_LDO3_VOLT,
+ .vsel_mask = BD718XX_LDO3_MASK,
+ .enable_reg = BD718XX_REG_LDO3_VOLT,
+ .enable_mask = BD718XX_LDO_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_LDO3_VOLT,
+ .mask = BD718XX_LDO_SEL,
+ .val = BD718XX_LDO_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo4",
+ .of_match = of_match_ptr("LDO4"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_LDO4,
+ .ops = &bd718xx_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD718XX_LDO4_VOLTAGE_NUM,
+ .linear_ranges = bd718xx_ldo4_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd718xx_ldo4_volts),
+ .vsel_reg = BD718XX_REG_LDO4_VOLT,
+ .vsel_mask = BD718XX_LDO4_MASK,
+ .enable_reg = BD718XX_REG_LDO4_VOLT,
+ .enable_mask = BD718XX_LDO_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_LDO4_VOLT,
+ .mask = BD718XX_LDO_SEL,
+ .val = BD718XX_LDO_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo5",
+ .of_match = of_match_ptr("LDO5"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_LDO5,
+ .ops = &bd718xx_pickable_range_ldo_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71847_LDO5_VOLTAGE_NUM,
+ .linear_ranges = bd71847_ldo5_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd71847_ldo5_volts),
+ .vsel_reg = BD718XX_REG_LDO5_VOLT,
+ .vsel_mask = BD71847_LDO5_MASK,
+ .vsel_range_reg = BD718XX_REG_LDO5_VOLT,
+ .vsel_range_mask = BD71847_LDO5_RANGE_MASK,
+ .linear_range_selectors = bd71847_ldo5_volt_range_sel,
+ .enable_reg = BD718XX_REG_LDO5_VOLT,
+ .enable_mask = BD718XX_LDO_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_LDO5_VOLT,
+ .mask = BD718XX_LDO_SEL,
+ .val = BD718XX_LDO_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo6",
+ .of_match = of_match_ptr("LDO6"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_LDO6,
+ .ops = &bd718xx_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD718XX_LDO6_VOLTAGE_NUM,
+ .linear_ranges = bd718xx_ldo6_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd718xx_ldo6_volts),
+ /* LDO6 is supplied by buck5 */
+ .supply_name = "buck5",
+ .vsel_reg = BD718XX_REG_LDO6_VOLT,
+ .vsel_mask = BD718XX_LDO6_MASK,
+ .enable_reg = BD718XX_REG_LDO6_VOLT,
+ .enable_mask = BD718XX_LDO_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_LDO6_VOLT,
+ .mask = BD718XX_LDO_SEL,
+ .val = BD718XX_LDO_SEL,
+ },
+ },
+};
+
+static const struct bd718xx_regulator_data bd71837_regulators[] = {
+ {
+ .desc = {
+ .name = "buck1",
+ .of_match = of_match_ptr("BUCK1"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_BUCK1,
+ .ops = &bd718xx_dvs_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD718XX_DVS_BUCK_VOLTAGE_NUM,
+ .linear_ranges = bd718xx_dvs_buck_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd718xx_dvs_buck_volts),
+ .vsel_reg = BD718XX_REG_BUCK1_VOLT_RUN,
+ .vsel_mask = DVS_BUCK_RUN_MASK,
+ .enable_reg = BD718XX_REG_BUCK1_CTRL,
+ .enable_mask = BD718XX_BUCK_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_BUCK1_CTRL,
+ .mask = BD718XX_BUCK_SEL,
+ .val = BD718XX_BUCK_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck2",
+ .of_match = of_match_ptr("BUCK2"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_BUCK2,
+ .ops = &bd718xx_dvs_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD718XX_DVS_BUCK_VOLTAGE_NUM,
+ .linear_ranges = bd718xx_dvs_buck_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd718xx_dvs_buck_volts),
+ .vsel_reg = BD718XX_REG_BUCK2_VOLT_RUN,
+ .vsel_mask = DVS_BUCK_RUN_MASK,
+ .enable_reg = BD718XX_REG_BUCK2_CTRL,
+ .enable_mask = BD718XX_BUCK_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_BUCK2_CTRL,
+ .mask = BD718XX_BUCK_SEL,
+ .val = BD718XX_BUCK_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck3",
+ .of_match = of_match_ptr("BUCK3"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_BUCK3,
+ .ops = &bd718xx_dvs_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD718XX_DVS_BUCK_VOLTAGE_NUM,
+ .linear_ranges = bd718xx_dvs_buck_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd718xx_dvs_buck_volts),
+ .vsel_reg = BD71837_REG_BUCK3_VOLT_RUN,
+ .vsel_mask = DVS_BUCK_RUN_MASK,
+ .enable_reg = BD71837_REG_BUCK3_CTRL,
+ .enable_mask = BD718XX_BUCK_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD71837_REG_BUCK3_CTRL,
+ .mask = BD718XX_BUCK_SEL,
+ .val = BD718XX_BUCK_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck4",
+ .of_match = of_match_ptr("BUCK4"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_BUCK4,
+ .ops = &bd718xx_dvs_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD718XX_DVS_BUCK_VOLTAGE_NUM,
+ .linear_ranges = bd718xx_dvs_buck_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd718xx_dvs_buck_volts),
+ .vsel_reg = BD71837_REG_BUCK4_VOLT_RUN,
+ .vsel_mask = DVS_BUCK_RUN_MASK,
+ .enable_reg = BD71837_REG_BUCK4_CTRL,
+ .enable_mask = BD718XX_BUCK_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD71837_REG_BUCK4_CTRL,
+ .mask = BD718XX_BUCK_SEL,
+ .val = BD718XX_BUCK_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck5",
+ .of_match = of_match_ptr("BUCK5"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_BUCK5,
+ .ops = &bd718xx_pickable_range_buck_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71837_BUCK5_VOLTAGE_NUM,
+ .linear_ranges = bd71837_buck5_volts,
+ .n_linear_ranges =
+ ARRAY_SIZE(bd71837_buck5_volts),
+ .vsel_reg = BD718XX_REG_1ST_NODVS_BUCK_VOLT,
+ .vsel_mask = BD71837_BUCK5_MASK,
+ .vsel_range_reg = BD718XX_REG_1ST_NODVS_BUCK_VOLT,
+ .vsel_range_mask = BD71837_BUCK5_RANGE_MASK,
+ .linear_range_selectors = bd71837_buck5_volt_range_sel,
+ .enable_reg = BD718XX_REG_1ST_NODVS_BUCK_CTRL,
+ .enable_mask = BD718XX_BUCK_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_1ST_NODVS_BUCK_CTRL,
+ .mask = BD718XX_BUCK_SEL,
+ .val = BD718XX_BUCK_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck6",
+ .of_match = of_match_ptr("BUCK6"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_BUCK6,
+ .ops = &bd718xx_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71837_BUCK6_VOLTAGE_NUM,
+ .linear_ranges = bd71837_buck6_volts,
+ .n_linear_ranges =
+ ARRAY_SIZE(bd71837_buck6_volts),
+ .vsel_reg = BD718XX_REG_2ND_NODVS_BUCK_VOLT,
+ .vsel_mask = BD71837_BUCK6_MASK,
+ .enable_reg = BD718XX_REG_2ND_NODVS_BUCK_CTRL,
+ .enable_mask = BD718XX_BUCK_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_2ND_NODVS_BUCK_CTRL,
+ .mask = BD718XX_BUCK_SEL,
+ .val = BD718XX_BUCK_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck7",
+ .of_match = of_match_ptr("BUCK7"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_BUCK7,
+ .ops = &bd718xx_buck_regulator_nolinear_ops,
+ .type = REGULATOR_VOLTAGE,
+ .volt_table = &bd718xx_3rd_nodvs_buck_volts[0],
+ .n_voltages = ARRAY_SIZE(bd718xx_3rd_nodvs_buck_volts),
+ .vsel_reg = BD718XX_REG_3RD_NODVS_BUCK_VOLT,
+ .vsel_mask = BD718XX_3RD_NODVS_BUCK_MASK,
+ .enable_reg = BD718XX_REG_3RD_NODVS_BUCK_CTRL,
+ .enable_mask = BD718XX_BUCK_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_3RD_NODVS_BUCK_CTRL,
+ .mask = BD718XX_BUCK_SEL,
+ .val = BD718XX_BUCK_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck8",
+ .of_match = of_match_ptr("BUCK8"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_BUCK8,
+ .ops = &bd718xx_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD718XX_4TH_NODVS_BUCK_VOLTAGE_NUM,
+ .linear_ranges = bd718xx_4th_nodvs_buck_volts,
+ .n_linear_ranges =
+ ARRAY_SIZE(bd718xx_4th_nodvs_buck_volts),
+ .vsel_reg = BD718XX_REG_4TH_NODVS_BUCK_VOLT,
+ .vsel_mask = BD718XX_4TH_NODVS_BUCK_MASK,
+ .enable_reg = BD718XX_REG_4TH_NODVS_BUCK_CTRL,
+ .enable_mask = BD718XX_BUCK_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_4TH_NODVS_BUCK_CTRL,
+ .mask = BD718XX_BUCK_SEL,
+ .val = BD718XX_BUCK_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo1",
+ .of_match = of_match_ptr("LDO1"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_LDO1,
+ .ops = &bd718xx_pickable_range_ldo_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD718XX_LDO1_VOLTAGE_NUM,
+ .linear_ranges = bd718xx_ldo1_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd718xx_ldo1_volts),
+ .vsel_reg = BD718XX_REG_LDO1_VOLT,
+ .vsel_mask = BD718XX_LDO1_MASK,
+ .vsel_range_reg = BD718XX_REG_LDO1_VOLT,
+ .vsel_range_mask = BD718XX_LDO1_RANGE_MASK,
+ .linear_range_selectors = bd718xx_ldo1_volt_range_sel,
+ .enable_reg = BD718XX_REG_LDO1_VOLT,
+ .enable_mask = BD718XX_LDO_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_LDO1_VOLT,
+ .mask = BD718XX_LDO_SEL,
+ .val = BD718XX_LDO_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo2",
+ .of_match = of_match_ptr("LDO2"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_LDO2,
+ .ops = &bd718xx_ldo_regulator_nolinear_ops,
+ .type = REGULATOR_VOLTAGE,
+ .volt_table = &ldo_2_volts[0],
+ .vsel_reg = BD718XX_REG_LDO2_VOLT,
+ .vsel_mask = BD718XX_LDO2_MASK,
+ .n_voltages = ARRAY_SIZE(ldo_2_volts),
+ .enable_reg = BD718XX_REG_LDO2_VOLT,
+ .enable_mask = BD718XX_LDO_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_LDO2_VOLT,
+ .mask = BD718XX_LDO_SEL,
+ .val = BD718XX_LDO_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo3",
+ .of_match = of_match_ptr("LDO3"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_LDO3,
+ .ops = &bd718xx_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD718XX_LDO3_VOLTAGE_NUM,
+ .linear_ranges = bd718xx_ldo3_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd718xx_ldo3_volts),
+ .vsel_reg = BD718XX_REG_LDO3_VOLT,
+ .vsel_mask = BD718XX_LDO3_MASK,
+ .enable_reg = BD718XX_REG_LDO3_VOLT,
+ .enable_mask = BD718XX_LDO_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_LDO3_VOLT,
+ .mask = BD718XX_LDO_SEL,
+ .val = BD718XX_LDO_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo4",
+ .of_match = of_match_ptr("LDO4"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_LDO4,
+ .ops = &bd718xx_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD718XX_LDO4_VOLTAGE_NUM,
+ .linear_ranges = bd718xx_ldo4_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd718xx_ldo4_volts),
+ .vsel_reg = BD718XX_REG_LDO4_VOLT,
+ .vsel_mask = BD718XX_LDO4_MASK,
+ .enable_reg = BD718XX_REG_LDO4_VOLT,
+ .enable_mask = BD718XX_LDO_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_LDO4_VOLT,
+ .mask = BD718XX_LDO_SEL,
+ .val = BD718XX_LDO_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo5",
+ .of_match = of_match_ptr("LDO5"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_LDO5,
+ .ops = &bd718xx_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71837_LDO5_VOLTAGE_NUM,
+ .linear_ranges = bd71837_ldo5_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd71837_ldo5_volts),
+ /* LDO5 is supplied by buck6 */
+ .supply_name = "buck6",
+ .vsel_reg = BD718XX_REG_LDO5_VOLT,
+ .vsel_mask = BD71837_LDO5_MASK,
+ .enable_reg = BD718XX_REG_LDO5_VOLT,
+ .enable_mask = BD718XX_LDO_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_LDO5_VOLT,
+ .mask = BD718XX_LDO_SEL,
+ .val = BD718XX_LDO_SEL,
+ },
+ .additional_inits = bd71837_ldo5_inits,
+ .additional_init_amnt = ARRAY_SIZE(bd71837_ldo5_inits),
+ },
+ {
+ .desc = {
+ .name = "ldo6",
+ .of_match = of_match_ptr("LDO6"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_LDO6,
+ .ops = &bd718xx_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD718XX_LDO6_VOLTAGE_NUM,
+ .linear_ranges = bd718xx_ldo6_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd718xx_ldo6_volts),
+ /* LDO6 is supplied by buck7 */
+ .supply_name = "buck7",
+ .vsel_reg = BD718XX_REG_LDO6_VOLT,
+ .vsel_mask = BD718XX_LDO6_MASK,
+ .enable_reg = BD718XX_REG_LDO6_VOLT,
+ .enable_mask = BD718XX_LDO_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_LDO6_VOLT,
+ .mask = BD718XX_LDO_SEL,
+ .val = BD718XX_LDO_SEL,
+ },
+ .additional_inits = bd71837_ldo6_inits,
+ .additional_init_amnt = ARRAY_SIZE(bd71837_ldo6_inits),
+ },
+ {
+ .desc = {
+ .name = "ldo7",
+ .of_match = of_match_ptr("LDO7"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_LDO7,
+ .ops = &bd718xx_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71837_LDO7_VOLTAGE_NUM,
+ .linear_ranges = bd71837_ldo7_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd71837_ldo7_volts),
+ .vsel_reg = BD71837_REG_LDO7_VOLT,
+ .vsel_mask = BD71837_LDO7_MASK,
+ .enable_reg = BD71837_REG_LDO7_VOLT,
+ .enable_mask = BD718XX_LDO_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD71837_REG_LDO7_VOLT,
+ .mask = BD718XX_LDO_SEL,
+ .val = BD718XX_LDO_SEL,
+ },
+ },
+};
+
+struct bd718xx_pmic_inits {
+ const struct bd718xx_regulator_data (*r_datas)[];
+ unsigned int r_amount;
+};
+
+static int bd718xx_probe(struct platform_device *pdev)
+{
+ struct bd718xx *mfd;
+ struct regulator_config config = { 0 };
+ struct bd718xx_pmic_inits pmic_regulators[] = {
+ [BD718XX_TYPE_BD71837] = {
+ .r_datas = &bd71837_regulators,
+ .r_amount = ARRAY_SIZE(bd71837_regulators),
+ },
+ [BD718XX_TYPE_BD71847] = {
+ .r_datas = &bd71847_regulators,
+ .r_amount = ARRAY_SIZE(bd71847_regulators),
+ },
+ };
+
+ int i, j, err;
+
+ mfd = dev_get_drvdata(pdev->dev.parent);
+ if (!mfd) {
+ dev_err(&pdev->dev, "No MFD driver data\n");
+ err = -EINVAL;
+ goto err;
+ }
+
+ if (mfd->chip_type >= BD718XX_TYPE_AMOUNT ||
+ !pmic_regulators[mfd->chip_type].r_datas) {
+ dev_err(&pdev->dev, "Unsupported chip type\n");
+ err = -EINVAL;
+ goto err;
+ }
+
+ /* Register LOCK release */
+ err = regmap_update_bits(mfd->regmap, BD718XX_REG_REGLOCK,
+ (REGLOCK_PWRSEQ | REGLOCK_VREG), 0);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to unlock PMIC (%d)\n", err);
+ goto err;
+ } else {
+ dev_dbg(&pdev->dev, "Unlocked lock register 0x%x\n",
+ BD718XX_REG_REGLOCK);
+ }
+
+ for (i = 0; i < pmic_regulators[mfd->chip_type].r_amount; i++) {
+
+ const struct regulator_desc *desc;
+ struct regulator_dev *rdev;
+ const struct bd718xx_regulator_data *r;
+
+ r = &(*pmic_regulators[mfd->chip_type].r_datas)[i];
+ desc = &r->desc;
+
+ config.dev = pdev->dev.parent;
+ config.regmap = mfd->regmap;
+
+ rdev = devm_regulator_register(&pdev->dev, desc, &config);
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev,
+ "failed to register %s regulator\n",
+ desc->name);
+ err = PTR_ERR(rdev);
+ goto err;
+ }
+ /* Regulator register gets the regulator constraints and
+ * applies them (set_machine_constraints). This should have
+ * turned the control register(s) to correct values and we
+ * can now switch the control from PMIC state machine to the
+ * register interface
+ */
+ err = regmap_update_bits(mfd->regmap, r->init.reg,
+ r->init.mask, r->init.val);
+ if (err) {
+ dev_err(&pdev->dev,
+ "Failed to write BUCK/LDO SEL bit for (%s)\n",
+ desc->name);
+ goto err;
+ }
+ for (j = 0; j < r->additional_init_amnt; j++) {
+ err = regmap_update_bits(mfd->regmap,
+ r->additional_inits[j].reg,
+ r->additional_inits[j].mask,
+ r->additional_inits[j].val);
+ if (err) {
+ dev_err(&pdev->dev,
+ "Buck (%s) initialization failed\n",
+ desc->name);
+ goto err;
+ }
+ }
+ }
+
+err:
+ return err;
+}
+
+static struct platform_driver bd718xx_regulator = {
+ .driver = {
+ .name = "bd718xx-pmic",
+ },
+ .probe = bd718xx_probe,
+};
+
+module_platform_driver(bd718xx_regulator);
+
+MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
+MODULE_DESCRIPTION("BD71837/BD71847 voltage regulator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 9577d8941846..2c66b528aede 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -426,19 +426,24 @@ static ssize_t name_show(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR_RO(name);
-static ssize_t regulator_print_opmode(char *buf, int mode)
+static const char *regulator_opmode_to_str(int mode)
{
switch (mode) {
case REGULATOR_MODE_FAST:
- return sprintf(buf, "fast\n");
+ return "fast";
case REGULATOR_MODE_NORMAL:
- return sprintf(buf, "normal\n");
+ return "normal";
case REGULATOR_MODE_IDLE:
- return sprintf(buf, "idle\n");
+ return "idle";
case REGULATOR_MODE_STANDBY:
- return sprintf(buf, "standby\n");
+ return "standby";
}
- return sprintf(buf, "unknown\n");
+ return "unknown";
+}
+
+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,
@@ -2783,6 +2788,11 @@ static int regulator_map_voltage(struct regulator_dev *rdev, int min_uV,
if (desc->ops->list_voltage == regulator_list_voltage_linear_range)
return regulator_map_voltage_linear_range(rdev, min_uV, max_uV);
+ if (desc->ops->list_voltage ==
+ regulator_list_voltage_pickable_linear_range)
+ return regulator_map_voltage_pickable_linear_range(rdev,
+ min_uV, max_uV);
+
return regulator_map_voltage_iterate(rdev, min_uV, max_uV);
}
@@ -3470,21 +3480,23 @@ out:
}
EXPORT_SYMBOL_GPL(regulator_set_current_limit);
+static int _regulator_get_current_limit_unlocked(struct regulator_dev *rdev)
+{
+ /* sanity check */
+ if (!rdev->desc->ops->get_current_limit)
+ return -EINVAL;
+
+ return rdev->desc->ops->get_current_limit(rdev);
+}
+
static int _regulator_get_current_limit(struct regulator_dev *rdev)
{
int ret;
regulator_lock(rdev);
-
- /* sanity check */
- if (!rdev->desc->ops->get_current_limit) {
- ret = -EINVAL;
- goto out;
- }
-
- ret = rdev->desc->ops->get_current_limit(rdev);
-out:
+ ret = _regulator_get_current_limit_unlocked(rdev);
regulator_unlock(rdev);
+
return ret;
}
@@ -3549,21 +3561,23 @@ out:
}
EXPORT_SYMBOL_GPL(regulator_set_mode);
+static unsigned int _regulator_get_mode_unlocked(struct regulator_dev *rdev)
+{
+ /* sanity check */
+ if (!rdev->desc->ops->get_mode)
+ return -EINVAL;
+
+ return rdev->desc->ops->get_mode(rdev);
+}
+
static unsigned int _regulator_get_mode(struct regulator_dev *rdev)
{
int ret;
regulator_lock(rdev);
-
- /* sanity check */
- if (!rdev->desc->ops->get_mode) {
- ret = -EINVAL;
- goto out;
- }
-
- ret = rdev->desc->ops->get_mode(rdev);
-out:
+ ret = _regulator_get_mode_unlocked(rdev);
regulator_unlock(rdev);
+
return ret;
}
@@ -4455,41 +4469,33 @@ void regulator_unregister(struct regulator_dev *rdev)
EXPORT_SYMBOL_GPL(regulator_unregister);
#ifdef CONFIG_SUSPEND
-static int _regulator_suspend(struct device *dev, void *data)
-{
- struct regulator_dev *rdev = dev_to_rdev(dev);
- suspend_state_t *state = data;
- int ret;
-
- regulator_lock(rdev);
- ret = suspend_set_state(rdev, *state);
- regulator_unlock(rdev);
-
- return ret;
-}
-
/**
* regulator_suspend - prepare regulators for system wide suspend
- * @state: system suspend state
+ * @dev: ``&struct device`` pointer that is passed to _regulator_suspend()
*
* Configure each regulator with it's suspend operating parameters for state.
*/
static int regulator_suspend(struct device *dev)
{
+ struct regulator_dev *rdev = dev_to_rdev(dev);
suspend_state_t state = pm_suspend_target_state;
+ int ret;
+
+ regulator_lock(rdev);
+ ret = suspend_set_state(rdev, state);
+ regulator_unlock(rdev);
- return class_for_each_device(&regulator_class, NULL, &state,
- _regulator_suspend);
+ return ret;
}
-static int _regulator_resume(struct device *dev, void *data)
+static int regulator_resume(struct device *dev)
{
- int ret = 0;
+ suspend_state_t state = pm_suspend_target_state;
struct regulator_dev *rdev = dev_to_rdev(dev);
- suspend_state_t *state = data;
struct regulator_state *rstate;
+ int ret = 0;
- rstate = regulator_get_suspend_state(rdev, *state);
+ rstate = regulator_get_suspend_state(rdev, state);
if (rstate == NULL)
return 0;
@@ -4504,15 +4510,6 @@ static int _regulator_resume(struct device *dev, void *data)
return ret;
}
-
-static int regulator_resume(struct device *dev)
-{
- suspend_state_t state = pm_suspend_target_state;
-
- return class_for_each_device(&regulator_class, NULL, &state,
- _regulator_resume);
-}
-
#else /* !CONFIG_SUSPEND */
#define regulator_suspend NULL
@@ -4670,17 +4667,23 @@ static void regulator_summary_show_subtree(struct seq_file *s,
struct regulation_constraints *c;
struct regulator *consumer;
struct summary_data summary_data;
+ unsigned int opmode;
if (!rdev)
return;
- seq_printf(s, "%*s%-*s %3d %4d %6d ",
+ regulator_lock_nested(rdev, level);
+
+ opmode = _regulator_get_mode_unlocked(rdev);
+ seq_printf(s, "%*s%-*s %3d %4d %6d %7s ",
level * 3 + 1, "",
30 - level * 3, rdev_get_name(rdev),
- rdev->use_count, rdev->open_count, rdev->bypass_count);
+ rdev->use_count, rdev->open_count, rdev->bypass_count,
+ regulator_opmode_to_str(opmode));
seq_printf(s, "%5dmV ", _regulator_get_voltage(rdev) / 1000);
- seq_printf(s, "%5dmA ", _regulator_get_current_limit(rdev) / 1000);
+ seq_printf(s, "%5dmA ",
+ _regulator_get_current_limit_unlocked(rdev) / 1000);
c = rdev->constraints;
if (c) {
@@ -4709,7 +4712,8 @@ static void regulator_summary_show_subtree(struct seq_file *s,
switch (rdev->desc->type) {
case REGULATOR_VOLTAGE:
- seq_printf(s, "%37dmV %5dmV",
+ seq_printf(s, "%37dmA %5dmV %5dmV",
+ consumer->uA_load / 1000,
consumer->voltage[PM_SUSPEND_ON].min_uV / 1000,
consumer->voltage[PM_SUSPEND_ON].max_uV / 1000);
break;
@@ -4726,6 +4730,8 @@ static void regulator_summary_show_subtree(struct seq_file *s,
class_for_each_device(&regulator_class, NULL, &summary_data,
regulator_summary_show_children);
+
+ regulator_unlock(rdev);
}
static int regulator_summary_show_roots(struct device *dev, void *data)
@@ -4741,8 +4747,8 @@ static int regulator_summary_show_roots(struct device *dev, void *data)
static int regulator_summary_show(struct seq_file *s, void *data)
{
- seq_puts(s, " regulator use open bypass voltage current min max\n");
- seq_puts(s, "-------------------------------------------------------------------------------\n");
+ seq_puts(s, " regulator use open bypass opmode voltage current min max\n");
+ seq_puts(s, "---------------------------------------------------------------------------------------\n");
class_for_each_device(&regulator_class, NULL, s,
regulator_summary_show_roots);
diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c
index 9ececfef42d6..37e4025203e3 100644
--- a/drivers/regulator/da9052-regulator.c
+++ b/drivers/regulator/da9052-regulator.c
@@ -420,7 +420,7 @@ static int da9052_regulator_probe(struct platform_device *pdev)
config.dev = &pdev->dev;
config.driver_data = regulator;
config.regmap = da9052->regmap;
- if (pdata && pdata->regulators) {
+ if (pdata) {
config.init_data = pdata->regulators[cell->id];
} else {
#ifdef CONFIG_OF
diff --git a/drivers/regulator/da9055-regulator.c b/drivers/regulator/da9055-regulator.c
index f40c3b8644ae..588c3d2445cf 100644
--- a/drivers/regulator/da9055-regulator.c
+++ b/drivers/regulator/da9055-regulator.c
@@ -612,7 +612,7 @@ static int da9055_regulator_probe(struct platform_device *pdev)
config.driver_data = regulator;
config.regmap = da9055->regmap;
- if (pdata && pdata->regulators) {
+ if (pdata) {
config.init_data = pdata->regulators[pdev->id];
} else {
ret = da9055_regulator_dt_init(pdev, regulator, &config,
diff --git a/drivers/regulator/da9211-regulator.c b/drivers/regulator/da9211-regulator.c
index 6c122b3df5d0..8f68c7a05d27 100644
--- a/drivers/regulator/da9211-regulator.c
+++ b/drivers/regulator/da9211-regulator.c
@@ -294,11 +294,11 @@ static struct da9211_pdata *da9211_parse_regulators_dt(
pdata->init_data[n] = da9211_matches[i].init_data;
pdata->reg_node[n] = da9211_matches[i].of_node;
pdata->gpiod_ren[n] = devm_gpiod_get_from_of_node(dev,
- da9211_matches[i].of_node,
- "enable",
- 0,
- GPIOD_OUT_HIGH,
- "da9211-enable");
+ da9211_matches[i].of_node,
+ "enable",
+ 0,
+ GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE,
+ "da9211-enable");
n++;
}
diff --git a/drivers/regulator/fixed-helper.c b/drivers/regulator/fixed-helper.c
index 777fac6fb4cb..2c6098e6f4bc 100644
--- a/drivers/regulator/fixed-helper.c
+++ b/drivers/regulator/fixed-helper.c
@@ -43,7 +43,6 @@ struct platform_device *regulator_register_always_on(int id, const char *name,
}
data->cfg.microvolts = uv;
- data->cfg.gpio = -EINVAL;
data->cfg.enabled_at_boot = 1;
data->cfg.init_data = &data->init_data;
diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c
index 988a7472c2ab..ccc29038f19a 100644
--- a/drivers/regulator/fixed.c
+++ b/drivers/regulator/fixed.c
@@ -24,10 +24,9 @@
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/fixed.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/slab.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/machine.h>
@@ -78,15 +77,16 @@ of_get_fixed_voltage_config(struct device *dev,
if (init_data->constraints.boot_on)
config->enabled_at_boot = true;
- config->gpio = of_get_named_gpio(np, "gpio", 0);
- if ((config->gpio < 0) && (config->gpio != -ENOENT))
- return ERR_PTR(config->gpio);
-
of_property_read_u32(np, "startup-delay-us", &config->startup_delay);
- config->enable_high = of_property_read_bool(np, "enable-active-high");
- config->gpio_is_open_drain = of_property_read_bool(np,
- "gpio-open-drain");
+ /*
+ * FIXME: we pulled active low/high and open drain handling into
+ * gpiolib so it will be handled there. Delete this in the second
+ * step when we also remove the custom inversion handling for all
+ * legacy boardfiles.
+ */
+ config->enable_high = 1;
+ config->gpio_is_open_drain = 0;
if (of_find_property(np, "vin-supply", NULL))
config->input_supply = "vin";
@@ -102,6 +102,7 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
struct fixed_voltage_config *config;
struct fixed_voltage_data *drvdata;
struct regulator_config cfg = { };
+ enum gpiod_flags gflags;
int ret;
drvdata = devm_kzalloc(&pdev->dev, sizeof(struct fixed_voltage_data),
@@ -150,25 +151,41 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
drvdata->desc.fixed_uV = config->microvolts;
- if (gpio_is_valid(config->gpio)) {
- cfg.ena_gpio = config->gpio;
- if (pdev->dev.of_node)
- cfg.ena_gpio_initialized = true;
- }
cfg.ena_gpio_invert = !config->enable_high;
if (config->enabled_at_boot) {
if (config->enable_high)
- cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH;
+ gflags = GPIOD_OUT_HIGH;
else
- cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW;
+ gflags = GPIOD_OUT_LOW;
} else {
if (config->enable_high)
- cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW;
+ gflags = GPIOD_OUT_LOW;
else
- cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH;
+ gflags = GPIOD_OUT_HIGH;
}
- if (config->gpio_is_open_drain)
- cfg.ena_gpio_flags |= GPIOF_OPEN_DRAIN;
+ if (config->gpio_is_open_drain) {
+ if (gflags == GPIOD_OUT_HIGH)
+ gflags = GPIOD_OUT_HIGH_OPEN_DRAIN;
+ else
+ gflags = GPIOD_OUT_LOW_OPEN_DRAIN;
+ }
+
+ /*
+ * Some fixed regulators share the enable line between two
+ * regulators which makes it necessary to get a handle on the
+ * same descriptor for two different consumers. This will get
+ * the GPIO descriptor, but only the first call will initialize
+ * it so any flags such as inversion or open drain will only
+ * be set up by the first caller and assumed identical on the
+ * next caller.
+ *
+ * FIXME: find a better way to deal with this.
+ */
+ gflags |= GPIOD_FLAGS_BIT_NONEXCLUSIVE;
+
+ cfg.ena_gpiod = devm_gpiod_get_optional(&pdev->dev, NULL, gflags);
+ if (IS_ERR(cfg.ena_gpiod))
+ return PTR_ERR(cfg.ena_gpiod);
cfg.dev = &pdev->dev;
cfg.init_data = config->init_data;
diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c
index 2ae7c3ac5940..5686a1335bd3 100644
--- a/drivers/regulator/helpers.c
+++ b/drivers/regulator/helpers.c
@@ -103,6 +103,128 @@ int regulator_disable_regmap(struct regulator_dev *rdev)
}
EXPORT_SYMBOL_GPL(regulator_disable_regmap);
+static int regulator_range_selector_to_index(struct regulator_dev *rdev,
+ unsigned int rval)
+{
+ int i;
+
+ if (!rdev->desc->linear_range_selectors)
+ return -EINVAL;
+
+ rval &= rdev->desc->vsel_range_mask;
+
+ for (i = 0; i < rdev->desc->n_linear_ranges; i++) {
+ if (rdev->desc->linear_range_selectors[i] == rval)
+ return i;
+ }
+ return -EINVAL;
+}
+
+/**
+ * regulator_get_voltage_sel_pickable_regmap - pickable range get_voltage_sel
+ *
+ * @rdev: regulator to operate on
+ *
+ * Regulators that use regmap for their register I/O and use pickable
+ * ranges can set the vsel_reg, vsel_mask, vsel_range_reg and vsel_range_mask
+ * fields in their descriptor and then use this as their get_voltage_vsel
+ * operation, saving some code.
+ */
+int regulator_get_voltage_sel_pickable_regmap(struct regulator_dev *rdev)
+{
+ unsigned int r_val;
+ int range;
+ unsigned int val;
+ int ret, i;
+ unsigned int voltages_in_range = 0;
+
+ if (!rdev->desc->linear_ranges)
+ return -EINVAL;
+
+ ret = regmap_read(rdev->regmap, rdev->desc->vsel_reg, &val);
+ if (ret != 0)
+ return ret;
+
+ ret = regmap_read(rdev->regmap, rdev->desc->vsel_range_reg, &r_val);
+ if (ret != 0)
+ return ret;
+
+ val &= rdev->desc->vsel_mask;
+ val >>= ffs(rdev->desc->vsel_mask) - 1;
+
+ range = regulator_range_selector_to_index(rdev, r_val);
+ if (range < 0)
+ return -EINVAL;
+
+ for (i = 0; i < range; i++)
+ voltages_in_range += (rdev->desc->linear_ranges[i].max_sel -
+ rdev->desc->linear_ranges[i].min_sel) + 1;
+
+ return val + voltages_in_range;
+}
+EXPORT_SYMBOL_GPL(regulator_get_voltage_sel_pickable_regmap);
+
+/**
+ * regulator_set_voltage_sel_pickable_regmap - pickable range set_voltage_sel
+ *
+ * @rdev: regulator to operate on
+ * @sel: Selector to set
+ *
+ * Regulators that use regmap for their register I/O and use pickable
+ * ranges can set the vsel_reg, vsel_mask, vsel_range_reg and vsel_range_mask
+ * fields in their descriptor and then use this as their set_voltage_vsel
+ * operation, saving some code.
+ */
+int regulator_set_voltage_sel_pickable_regmap(struct regulator_dev *rdev,
+ unsigned int sel)
+{
+ unsigned int range;
+ int ret, i;
+ unsigned int voltages_in_range = 0;
+
+ for (i = 0; i < rdev->desc->n_linear_ranges; i++) {
+ voltages_in_range = (rdev->desc->linear_ranges[i].max_sel -
+ rdev->desc->linear_ranges[i].min_sel) + 1;
+ if (sel < voltages_in_range)
+ break;
+ sel -= voltages_in_range;
+ }
+
+ if (i == rdev->desc->n_linear_ranges)
+ return -EINVAL;
+
+ sel <<= ffs(rdev->desc->vsel_mask) - 1;
+ sel += rdev->desc->linear_ranges[i].min_sel;
+
+ range = rdev->desc->linear_range_selectors[i];
+
+ if (rdev->desc->vsel_reg == rdev->desc->vsel_range_reg) {
+ ret = regmap_update_bits(rdev->regmap,
+ rdev->desc->vsel_reg,
+ rdev->desc->vsel_range_mask |
+ rdev->desc->vsel_mask, sel | range);
+ } else {
+ ret = regmap_update_bits(rdev->regmap,
+ rdev->desc->vsel_range_reg,
+ rdev->desc->vsel_range_mask, range);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg,
+ rdev->desc->vsel_mask, sel);
+ }
+
+ if (ret)
+ return ret;
+
+ if (rdev->desc->apply_bit)
+ ret = regmap_update_bits(rdev->regmap, rdev->desc->apply_reg,
+ rdev->desc->apply_bit,
+ rdev->desc->apply_bit);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_set_voltage_sel_pickable_regmap);
+
/**
* regulator_get_voltage_sel_regmap - standard get_voltage_sel for regmap users
*
@@ -321,20 +443,91 @@ int regulator_map_voltage_linear_range(struct regulator_dev *rdev,
ret += range->min_sel;
- break;
+ /*
+ * Map back into a voltage to verify we're still in bounds.
+ * If we are not, then continue checking rest of the ranges.
+ */
+ voltage = rdev->desc->ops->list_voltage(rdev, ret);
+ if (voltage >= min_uV && voltage <= max_uV)
+ break;
}
if (i == rdev->desc->n_linear_ranges)
return -EINVAL;
- /* Map back into a voltage to verify we're still in bounds */
- voltage = rdev->desc->ops->list_voltage(rdev, ret);
- if (voltage < min_uV || voltage > max_uV)
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_map_voltage_linear_range);
+
+/**
+ * regulator_map_voltage_pickable_linear_range - map_voltage, pickable ranges
+ *
+ * @rdev: Regulator to operate on
+ * @min_uV: Lower bound for voltage
+ * @max_uV: Upper bound for voltage
+ *
+ * Drivers providing pickable linear_ranges in their descriptor can use
+ * this as their map_voltage() callback.
+ */
+int regulator_map_voltage_pickable_linear_range(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ const struct regulator_linear_range *range;
+ int ret = -EINVAL;
+ int voltage, i;
+ unsigned int selector = 0;
+
+ if (!rdev->desc->n_linear_ranges) {
+ BUG_ON(!rdev->desc->n_linear_ranges);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < rdev->desc->n_linear_ranges; i++) {
+ int linear_max_uV;
+
+ range = &rdev->desc->linear_ranges[i];
+ linear_max_uV = range->min_uV +
+ (range->max_sel - range->min_sel) * range->uV_step;
+
+ if (!(min_uV <= linear_max_uV && max_uV >= range->min_uV)) {
+ selector += (range->max_sel - range->min_sel + 1);
+ continue;
+ }
+
+ if (min_uV <= range->min_uV)
+ min_uV = range->min_uV;
+
+ /* range->uV_step == 0 means fixed voltage range */
+ if (range->uV_step == 0) {
+ ret = 0;
+ } else {
+ ret = DIV_ROUND_UP(min_uV - range->min_uV,
+ range->uV_step);
+ if (ret < 0)
+ return ret;
+ }
+
+ ret += selector;
+
+ voltage = rdev->desc->ops->list_voltage(rdev, ret);
+
+ /*
+ * Map back into a voltage to verify we're still in bounds.
+ * We may have overlapping voltage ranges. Hence we don't
+ * exit but retry until we have checked all ranges.
+ */
+ if (voltage < min_uV || voltage > max_uV)
+ selector += (range->max_sel - range->min_sel + 1);
+ else
+ break;
+ }
+
+ if (i == rdev->desc->n_linear_ranges)
return -EINVAL;
return ret;
}
-EXPORT_SYMBOL_GPL(regulator_map_voltage_linear_range);
+EXPORT_SYMBOL_GPL(regulator_map_voltage_pickable_linear_range);
/**
* regulator_list_voltage_linear - List voltages with simple calculation
@@ -361,6 +554,46 @@ int regulator_list_voltage_linear(struct regulator_dev *rdev,
EXPORT_SYMBOL_GPL(regulator_list_voltage_linear);
/**
+ * regulator_list_voltage_pickable_linear_range - pickable range list voltages
+ *
+ * @rdev: Regulator device
+ * @selector: Selector to convert into a voltage
+ *
+ * list_voltage() operation, intended to be used by drivers utilizing pickable
+ * ranges helpers.
+ */
+int regulator_list_voltage_pickable_linear_range(struct regulator_dev *rdev,
+ unsigned int selector)
+{
+ const struct regulator_linear_range *range;
+ int i;
+ unsigned int all_sels = 0;
+
+ if (!rdev->desc->n_linear_ranges) {
+ BUG_ON(!rdev->desc->n_linear_ranges);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < rdev->desc->n_linear_ranges; i++) {
+ unsigned int sels_in_range;
+
+ range = &rdev->desc->linear_ranges[i];
+
+ sels_in_range = range->max_sel - range->min_sel;
+
+ if (all_sels + sels_in_range >= selector) {
+ selector -= all_sels;
+ return range->min_uV + (range->uV_step * selector);
+ }
+
+ all_sels += (sels_in_range + 1);
+ }
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(regulator_list_voltage_pickable_linear_range);
+
+/**
* regulator_list_voltage_linear_range - List voltages for linear ranges
*
* @rdev: Regulator device
diff --git a/drivers/regulator/isl9305.c b/drivers/regulator/isl9305.c
index 257c1943e753..9c2607e912cf 100644
--- a/drivers/regulator/isl9305.c
+++ b/drivers/regulator/isl9305.c
@@ -84,6 +84,7 @@ static const struct regulator_desc isl9305_regulators[] = {
.enable_mask = ISL9305_DCD1_EN,
.supply_name = "VINDCD1",
.ops = &isl9305_ops,
+ .owner = THIS_MODULE,
},
[ISL9305_DCD2] = {
.name = "DCD2",
@@ -98,6 +99,7 @@ static const struct regulator_desc isl9305_regulators[] = {
.enable_mask = ISL9305_DCD2_EN,
.supply_name = "VINDCD2",
.ops = &isl9305_ops,
+ .owner = THIS_MODULE,
},
[ISL9305_LDO1] = {
.name = "LDO1",
@@ -112,6 +114,7 @@ static const struct regulator_desc isl9305_regulators[] = {
.enable_mask = ISL9305_LDO1_EN,
.supply_name = "VINLDO1",
.ops = &isl9305_ops,
+ .owner = THIS_MODULE,
},
[ISL9305_LDO2] = {
.name = "LDO2",
@@ -126,6 +129,7 @@ static const struct regulator_desc isl9305_regulators[] = {
.enable_mask = ISL9305_LDO2_EN,
.supply_name = "VINLDO2",
.ops = &isl9305_ops,
+ .owner = THIS_MODULE,
},
};
diff --git a/drivers/regulator/lm363x-regulator.c b/drivers/regulator/lm363x-regulator.c
index b615a413ca9f..bbedb08d257b 100644
--- a/drivers/regulator/lm363x-regulator.c
+++ b/drivers/regulator/lm363x-regulator.c
@@ -227,9 +227,11 @@ static struct gpio_desc *lm363x_regulator_of_get_enable_gpio(struct device *dev,
*/
switch (id) {
case LM3632_LDO_POS:
- return devm_gpiod_get_index_optional(dev, "enable", 0, GPIOD_OUT_LOW);
+ return devm_gpiod_get_index_optional(dev, "enable", 0,
+ GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
case LM3632_LDO_NEG:
- return devm_gpiod_get_index_optional(dev, "enable", 1, GPIOD_OUT_LOW);
+ return devm_gpiod_get_index_optional(dev, "enable", 1,
+ GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
default:
return NULL;
}
diff --git a/drivers/regulator/lochnagar-regulator.c b/drivers/regulator/lochnagar-regulator.c
new file mode 100644
index 000000000000..2b5073b9ff86
--- /dev/null
+++ b/drivers/regulator/lochnagar-regulator.c
@@ -0,0 +1,254 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Lochnagar regulator driver
+//
+// Copyright (c) 2017-2018 Cirrus Logic, Inc. and
+// Cirrus Logic International Semiconductor Ltd.
+//
+// Author: Charles Keepax <ckeepax@opensource.cirrus.com>
+
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/mutex.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/mfd/lochnagar.h>
+
+static const struct regulator_ops lochnagar_micvdd_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
+
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+};
+
+static const struct regulator_linear_range lochnagar_micvdd_ranges[] = {
+ REGULATOR_LINEAR_RANGE(1000000, 0, 0xC, 50000),
+ REGULATOR_LINEAR_RANGE(1700000, 0xD, 0x1F, 100000),
+};
+
+static int lochnagar_micbias_enable(struct regulator_dev *rdev)
+{
+ struct lochnagar *lochnagar = rdev_get_drvdata(rdev);
+ int ret;
+
+ mutex_lock(&lochnagar->analogue_config_lock);
+
+ ret = regulator_enable_regmap(rdev);
+ if (ret < 0)
+ goto err;
+
+ ret = lochnagar_update_config(lochnagar);
+
+err:
+ mutex_unlock(&lochnagar->analogue_config_lock);
+
+ return ret;
+}
+
+static int lochnagar_micbias_disable(struct regulator_dev *rdev)
+{
+ struct lochnagar *lochnagar = rdev_get_drvdata(rdev);
+ int ret;
+
+ mutex_lock(&lochnagar->analogue_config_lock);
+
+ ret = regulator_disable_regmap(rdev);
+ if (ret < 0)
+ goto err;
+
+ ret = lochnagar_update_config(lochnagar);
+
+err:
+ mutex_unlock(&lochnagar->analogue_config_lock);
+
+ return ret;
+}
+
+static const struct regulator_ops lochnagar_micbias_ops = {
+ .enable = lochnagar_micbias_enable,
+ .disable = lochnagar_micbias_disable,
+ .is_enabled = regulator_is_enabled_regmap,
+};
+
+static const struct regulator_ops lochnagar_vddcore_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
+
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+};
+
+static const struct regulator_linear_range lochnagar_vddcore_ranges[] = {
+ REGULATOR_LINEAR_RANGE(600000, 0x8, 0x41, 12500),
+};
+
+enum lochnagar_regulators {
+ LOCHNAGAR_MICVDD,
+ LOCHNAGAR_MIC1VDD,
+ LOCHNAGAR_MIC2VDD,
+ LOCHNAGAR_VDDCORE,
+};
+
+static int lochnagar_micbias_of_parse(struct device_node *np,
+ const struct regulator_desc *desc,
+ struct regulator_config *config)
+{
+ struct lochnagar *lochnagar = config->driver_data;
+ int shift = (desc->id - LOCHNAGAR_MIC1VDD) *
+ LOCHNAGAR2_P2_MICBIAS_SRC_SHIFT;
+ int mask = LOCHNAGAR2_P1_MICBIAS_SRC_MASK << shift;
+ unsigned int val;
+ int ret;
+
+ ret = of_property_read_u32(np, "cirrus,micbias-input", &val);
+ if (ret >= 0) {
+ mutex_lock(&lochnagar->analogue_config_lock);
+ ret = regmap_update_bits(lochnagar->regmap,
+ LOCHNAGAR2_ANALOGUE_PATH_CTRL2,
+ mask, val << shift);
+ mutex_unlock(&lochnagar->analogue_config_lock);
+ if (ret < 0) {
+ dev_err(lochnagar->dev,
+ "Failed to update micbias source: %d\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static const struct regulator_desc lochnagar_regulators[] = {
+ [LOCHNAGAR_MICVDD] = {
+ .name = "MICVDD",
+ .supply_name = "SYSVDD",
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = 32,
+ .ops = &lochnagar_micvdd_ops,
+
+ .id = LOCHNAGAR_MICVDD,
+ .of_match = of_match_ptr("MICVDD"),
+
+ .enable_reg = LOCHNAGAR2_MICVDD_CTRL1,
+ .enable_mask = LOCHNAGAR2_MICVDD_REG_ENA_MASK,
+ .vsel_reg = LOCHNAGAR2_MICVDD_CTRL2,
+ .vsel_mask = LOCHNAGAR2_MICVDD_VSEL_MASK,
+
+ .linear_ranges = lochnagar_micvdd_ranges,
+ .n_linear_ranges = ARRAY_SIZE(lochnagar_micvdd_ranges),
+
+ .enable_time = 3000,
+ .ramp_delay = 1000,
+
+ .owner = THIS_MODULE,
+ },
+ [LOCHNAGAR_MIC1VDD] = {
+ .name = "MIC1VDD",
+ .supply_name = "MICBIAS1",
+ .type = REGULATOR_VOLTAGE,
+ .ops = &lochnagar_micbias_ops,
+
+ .id = LOCHNAGAR_MIC1VDD,
+ .of_match = of_match_ptr("MIC1VDD"),
+ .of_parse_cb = lochnagar_micbias_of_parse,
+
+ .enable_reg = LOCHNAGAR2_ANALOGUE_PATH_CTRL2,
+ .enable_mask = LOCHNAGAR2_P1_INPUT_BIAS_ENA_MASK,
+
+ .owner = THIS_MODULE,
+ },
+ [LOCHNAGAR_MIC2VDD] = {
+ .name = "MIC2VDD",
+ .supply_name = "MICBIAS2",
+ .type = REGULATOR_VOLTAGE,
+ .ops = &lochnagar_micbias_ops,
+
+ .id = LOCHNAGAR_MIC2VDD,
+ .of_match = of_match_ptr("MIC2VDD"),
+ .of_parse_cb = lochnagar_micbias_of_parse,
+
+ .enable_reg = LOCHNAGAR2_ANALOGUE_PATH_CTRL2,
+ .enable_mask = LOCHNAGAR2_P2_INPUT_BIAS_ENA_MASK,
+
+ .owner = THIS_MODULE,
+ },
+ [LOCHNAGAR_VDDCORE] = {
+ .name = "VDDCORE",
+ .supply_name = "SYSVDD",
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = 57,
+ .ops = &lochnagar_vddcore_ops,
+
+ .id = LOCHNAGAR_VDDCORE,
+ .of_match = of_match_ptr("VDDCORE"),
+
+ .enable_reg = LOCHNAGAR2_VDDCORE_CDC_CTRL1,
+ .enable_mask = LOCHNAGAR2_VDDCORE_CDC_REG_ENA_MASK,
+ .vsel_reg = LOCHNAGAR2_VDDCORE_CDC_CTRL2,
+ .vsel_mask = LOCHNAGAR2_VDDCORE_CDC_VSEL_MASK,
+
+ .linear_ranges = lochnagar_vddcore_ranges,
+ .n_linear_ranges = ARRAY_SIZE(lochnagar_vddcore_ranges),
+
+ .enable_time = 3000,
+ .ramp_delay = 1000,
+
+ .owner = THIS_MODULE,
+ },
+};
+
+static int lochnagar_regulator_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct lochnagar *lochnagar = dev_get_drvdata(dev->parent);
+ struct regulator_config config = { };
+ struct regulator_dev *rdev;
+ int ret, i;
+
+ config.dev = lochnagar->dev;
+ config.regmap = lochnagar->regmap;
+ config.driver_data = lochnagar;
+
+ for (i = 0; i < ARRAY_SIZE(lochnagar_regulators); i++) {
+ const struct regulator_desc *desc = &lochnagar_regulators[i];
+
+ rdev = devm_regulator_register(dev, desc, &config);
+ if (IS_ERR(rdev)) {
+ ret = PTR_ERR(rdev);
+ dev_err(dev, "Failed to register %s regulator: %d\n",
+ desc->name, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static struct platform_driver lochnagar_regulator_driver = {
+ .driver = {
+ .name = "lochnagar-regulator",
+ },
+
+ .probe = lochnagar_regulator_probe,
+};
+module_platform_driver(lochnagar_regulator_driver);
+
+MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.cirrus.com>");
+MODULE_DESCRIPTION("Regulator driver for Cirrus Logic Lochnagar Board");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:lochnagar-regulator");
diff --git a/drivers/regulator/lp8788-ldo.c b/drivers/regulator/lp8788-ldo.c
index f2347474a106..553b4790050f 100644
--- a/drivers/regulator/lp8788-ldo.c
+++ b/drivers/regulator/lp8788-ldo.c
@@ -503,9 +503,10 @@ static int lp8788_config_ldo_enable_mode(struct platform_device *pdev,
/* FIXME: check default mode for GPIO here: high or low? */
ldo->ena_gpiod = devm_gpiod_get_index_optional(&pdev->dev,
- "enable",
- enable_id,
- GPIOD_OUT_HIGH);
+ "enable",
+ enable_id,
+ GPIOD_OUT_HIGH |
+ GPIOD_FLAGS_BIT_NONEXCLUSIVE);
if (IS_ERR(ldo->ena_gpiod))
return PTR_ERR(ldo->ena_gpiod);
diff --git a/drivers/regulator/ltc3589.c b/drivers/regulator/ltc3589.c
index 18d5b01ddcb2..63f724f260ef 100644
--- a/drivers/regulator/ltc3589.c
+++ b/drivers/regulator/ltc3589.c
@@ -404,7 +404,8 @@ static const struct regmap_config ltc3589_regmap_config = {
.max_register = LTC3589_L2DTV2,
.reg_defaults = ltc3589_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(ltc3589_reg_defaults),
- .use_single_rw = true,
+ .use_single_read = true,
+ .use_single_write = true,
.cache_type = REGCACHE_RBTREE,
};
diff --git a/drivers/regulator/ltc3676.c b/drivers/regulator/ltc3676.c
index 9dec1609ff66..71fd0f2a4b76 100644
--- a/drivers/regulator/ltc3676.c
+++ b/drivers/regulator/ltc3676.c
@@ -321,7 +321,8 @@ static const struct regmap_config ltc3676_regmap_config = {
.readable_reg = ltc3676_readable_reg,
.volatile_reg = ltc3676_volatile_reg,
.max_register = LTC3676_CLIRQ,
- .use_single_rw = true,
+ .use_single_read = true,
+ .use_single_write = true,
.cache_type = REGCACHE_RBTREE,
};
diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c
index f1e77ed5dfec..6c39fff73b8a 100644
--- a/drivers/regulator/max8952.c
+++ b/drivers/regulator/max8952.c
@@ -230,6 +230,7 @@ static int max8952_pmic_probe(struct i2c_client *client,
gflags = GPIOD_OUT_HIGH;
else
gflags = GPIOD_OUT_LOW;
+ gflags |= GPIOD_FLAGS_BIT_NONEXCLUSIVE;
gpiod = devm_gpiod_get_optional(&client->dev,
"max8952,en",
gflags);
diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c
index 7cd493ec6315..e7a58b509032 100644
--- a/drivers/regulator/max8973-regulator.c
+++ b/drivers/regulator/max8973-regulator.c
@@ -758,6 +758,7 @@ static int max8973_probe(struct i2c_client *client,
gflags = GPIOD_OUT_HIGH;
else
gflags = GPIOD_OUT_LOW;
+ gflags |= GPIOD_FLAGS_BIT_NONEXCLUSIVE;
gpiod = devm_gpiod_get_optional(&client->dev,
"maxim,enable",
gflags);
diff --git a/drivers/regulator/max8997-regulator.c b/drivers/regulator/max8997-regulator.c
index ad0c806b0737..3bf5ddfaaea8 100644
--- a/drivers/regulator/max8997-regulator.c
+++ b/drivers/regulator/max8997-regulator.c
@@ -929,8 +929,8 @@ static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev,
break;
if (i == ARRAY_SIZE(regulators)) {
- dev_warn(&pdev->dev, "don't know how to configure regulator %s\n",
- reg_np->name);
+ dev_warn(&pdev->dev, "don't know how to configure regulator %pOFn\n",
+ reg_np);
continue;
}
diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c
index da4fb9824757..65eb1e0350cf 100644
--- a/drivers/regulator/mc13xxx-regulator-core.c
+++ b/drivers/regulator/mc13xxx-regulator-core.c
@@ -203,7 +203,7 @@ struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(
if (!found)
dev_warn(&pdev->dev,
- "Unknown regulator: %s\n", child->name);
+ "Unknown regulator: %pOFn\n", child);
}
of_node_put(parent);
diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c
index 210fc20f7de7..c4223b3e0dff 100644
--- a/drivers/regulator/of_regulator.c
+++ b/drivers/regulator/of_regulator.c
@@ -95,8 +95,8 @@ static void of_get_regulation_constraints(struct device_node *np,
if (!ret)
constraints->settling_time_up = pval;
if (constraints->settling_time_up && constraints->settling_time) {
- pr_warn("%s: ambiguous configuration for settling time, ignoring 'regulator-settling-time-up-us'\n",
- np->name);
+ pr_warn("%pOFn: ambiguous configuration for settling time, ignoring 'regulator-settling-time-up-us'\n",
+ np);
constraints->settling_time_up = 0;
}
@@ -105,8 +105,8 @@ static void of_get_regulation_constraints(struct device_node *np,
if (!ret)
constraints->settling_time_down = pval;
if (constraints->settling_time_down && constraints->settling_time) {
- pr_warn("%s: ambiguous configuration for settling time, ignoring 'regulator-settling-time-down-us'\n",
- np->name);
+ pr_warn("%pOFn: ambiguous configuration for settling time, ignoring 'regulator-settling-time-down-us'\n",
+ np);
constraints->settling_time_down = 0;
}
@@ -127,12 +127,12 @@ static void of_get_regulation_constraints(struct device_node *np,
if (desc && desc->of_map_mode) {
mode = desc->of_map_mode(pval);
if (mode == REGULATOR_MODE_INVALID)
- pr_err("%s: invalid mode %u\n", np->name, pval);
+ pr_err("%pOFn: invalid mode %u\n", np, pval);
else
constraints->initial_mode = mode;
} else {
- pr_warn("%s: mapping for mode %d not defined\n",
- np->name, pval);
+ pr_warn("%pOFn: mapping for mode %d not defined\n",
+ np, pval);
}
}
@@ -144,14 +144,14 @@ static void of_get_regulation_constraints(struct device_node *np,
ret = of_property_read_u32_index(np,
"regulator-allowed-modes", i, &pval);
if (ret) {
- pr_err("%s: couldn't read allowed modes index %d, ret=%d\n",
- np->name, i, ret);
+ pr_err("%pOFn: couldn't read allowed modes index %d, ret=%d\n",
+ np, i, ret);
break;
}
mode = desc->of_map_mode(pval);
if (mode == REGULATOR_MODE_INVALID)
- pr_err("%s: invalid regulator-allowed-modes element %u\n",
- np->name, pval);
+ pr_err("%pOFn: invalid regulator-allowed-modes element %u\n",
+ np, pval);
else
constraints->valid_modes_mask |= mode;
}
@@ -159,7 +159,7 @@ static void of_get_regulation_constraints(struct device_node *np,
constraints->valid_ops_mask
|= REGULATOR_CHANGE_MODE;
} else {
- pr_warn("%s: mode mapping not defined\n", np->name);
+ pr_warn("%pOFn: mode mapping not defined\n", np);
}
}
@@ -197,13 +197,13 @@ static void of_get_regulation_constraints(struct device_node *np,
if (desc && desc->of_map_mode) {
mode = desc->of_map_mode(pval);
if (mode == REGULATOR_MODE_INVALID)
- pr_err("%s: invalid mode %u\n",
- np->name, pval);
+ pr_err("%pOFn: invalid mode %u\n",
+ np, pval);
else
suspend_state->mode = mode;
} else {
- pr_warn("%s: mapping for mode %d not defined\n",
- np->name, pval);
+ pr_warn("%pOFn: mapping for mode %d not defined\n",
+ np, pval);
}
}
@@ -349,8 +349,8 @@ int of_regulator_match(struct device *dev, struct device_node *node,
match->desc);
if (!match->init_data) {
dev_err(dev,
- "failed to parse DT for regulator %s\n",
- child->name);
+ "failed to parse DT for regulator %pOFn\n",
+ child);
of_node_put(child);
return -EINVAL;
}
@@ -399,16 +399,16 @@ struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
init_data = of_get_regulator_init_data(dev, child, desc);
if (!init_data) {
dev_err(dev,
- "failed to parse DT for regulator %s\n",
- child->name);
+ "failed to parse DT for regulator %pOFn\n",
+ child);
break;
}
if (desc->of_parse_cb) {
if (desc->of_parse_cb(child, desc, config)) {
dev_err(dev,
- "driver callback failed to parse DT for regulator %s\n",
- child->name);
+ "driver callback failed to parse DT for regulator %pOFn\n",
+ child);
init_data = NULL;
break;
}
diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c
index 31c3a236120a..dd41a9bb3f5c 100644
--- a/drivers/regulator/pfuze100-regulator.c
+++ b/drivers/regulator/pfuze100-regulator.c
@@ -31,11 +31,17 @@
#define PFUZE100_COINVOL 0x1a
#define PFUZE100_SW1ABVOL 0x20
+#define PFUZE100_SW1ABMODE 0x23
#define PFUZE100_SW1CVOL 0x2e
+#define PFUZE100_SW1CMODE 0x31
#define PFUZE100_SW2VOL 0x35
+#define PFUZE100_SW2MODE 0x38
#define PFUZE100_SW3AVOL 0x3c
+#define PFUZE100_SW3AMODE 0x3f
#define PFUZE100_SW3BVOL 0x43
+#define PFUZE100_SW3BMODE 0x46
#define PFUZE100_SW4VOL 0x4a
+#define PFUZE100_SW4MODE 0x4d
#define PFUZE100_SWBSTCON1 0x66
#define PFUZE100_VREFDDRCON 0x6a
#define PFUZE100_VSNVSVOL 0x6b
@@ -46,6 +52,13 @@
#define PFUZE100_VGEN5VOL 0x70
#define PFUZE100_VGEN6VOL 0x71
+#define PFUZE100_SWxMODE_MASK 0xf
+#define PFUZE100_SWxMODE_APS_APS 0x8
+#define PFUZE100_SWxMODE_APS_OFF 0x4
+
+#define PFUZE100_VGENxLPWR BIT(6)
+#define PFUZE100_VGENxSTBY BIT(5)
+
enum chips { PFUZE100, PFUZE200, PFUZE3000 = 3, PFUZE3001 = 0x31, };
struct pfuze_regulator {
@@ -559,6 +572,69 @@ static inline struct device_node *match_of_node(int index)
}
#endif
+static struct pfuze_chip *syspm_pfuze_chip;
+
+static void pfuze_power_off_prepare(void)
+{
+ dev_info(syspm_pfuze_chip->dev, "Configure standby mode for power off");
+
+ /* Switch from default mode: APS/APS to APS/Off */
+ regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW1ABMODE,
+ PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF);
+ regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW1CMODE,
+ PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF);
+ regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW2MODE,
+ PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF);
+ regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW3AMODE,
+ PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF);
+ regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW3BMODE,
+ PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF);
+ regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW4MODE,
+ PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF);
+
+ regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN1VOL,
+ PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
+ PFUZE100_VGENxSTBY);
+ regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN2VOL,
+ PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
+ PFUZE100_VGENxSTBY);
+ regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN3VOL,
+ PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
+ PFUZE100_VGENxSTBY);
+ regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN4VOL,
+ PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
+ PFUZE100_VGENxSTBY);
+ regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN5VOL,
+ PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
+ PFUZE100_VGENxSTBY);
+ regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN6VOL,
+ PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
+ PFUZE100_VGENxSTBY);
+}
+
+static int pfuze_power_off_prepare_init(struct pfuze_chip *pfuze_chip)
+{
+ if (pfuze_chip->chip_id != PFUZE100) {
+ dev_warn(pfuze_chip->dev, "Requested pm_power_off_prepare handler for not supported chip\n");
+ return -ENODEV;
+ }
+
+ if (pm_power_off_prepare) {
+ dev_warn(pfuze_chip->dev, "pm_power_off_prepare is already registered.\n");
+ return -EBUSY;
+ }
+
+ if (syspm_pfuze_chip) {
+ dev_warn(pfuze_chip->dev, "syspm_pfuze_chip is already set.\n");
+ return -EBUSY;
+ }
+
+ syspm_pfuze_chip = pfuze_chip;
+ pm_power_off_prepare = pfuze_power_off_prepare;
+
+ return 0;
+}
+
static int pfuze_identify(struct pfuze_chip *pfuze_chip)
{
unsigned int value;
@@ -753,6 +829,20 @@ static int pfuze100_regulator_probe(struct i2c_client *client,
}
}
+ if (of_property_read_bool(client->dev.of_node,
+ "fsl,pmic-stby-poweroff"))
+ return pfuze_power_off_prepare_init(pfuze_chip);
+
+ return 0;
+}
+
+static int pfuze100_regulator_remove(struct i2c_client *client)
+{
+ if (syspm_pfuze_chip) {
+ syspm_pfuze_chip = NULL;
+ pm_power_off_prepare = NULL;
+ }
+
return 0;
}
@@ -763,6 +853,7 @@ static struct i2c_driver pfuze_driver = {
.of_match_table = pfuze_dt_ids,
},
.probe = pfuze100_regulator_probe,
+ .remove = pfuze100_regulator_remove,
};
module_i2c_driver(pfuze_driver);
diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c
index 9f27daebd8c8..39ccf53fdeb3 100644
--- a/drivers/regulator/qcom-rpmh-regulator.c
+++ b/drivers/regulator/qcom-rpmh-regulator.c
@@ -414,7 +414,7 @@ static int rpmh_regulator_init_vreg(struct rpmh_vreg *vreg, struct device *dev,
break;
if (!rpmh_data->name) {
- dev_err(dev, "Unknown regulator %s\n", node->name);
+ dev_err(dev, "Unknown regulator %pOFn\n", node);
return -EINVAL;
}
@@ -423,8 +423,8 @@ static int rpmh_regulator_init_vreg(struct rpmh_vreg *vreg, struct device *dev,
vreg->addr = cmd_db_read_addr(rpmh_resource_name);
if (!vreg->addr) {
- dev_err(dev, "%s: could not find RPMh address for resource %s\n",
- node->name, rpmh_resource_name);
+ dev_err(dev, "%pOFn: could not find RPMh address for resource %s\n",
+ node, rpmh_resource_name);
return -ENODEV;
}
@@ -469,13 +469,13 @@ static int rpmh_regulator_init_vreg(struct rpmh_vreg *vreg, struct device *dev,
rdev = devm_regulator_register(dev, &vreg->rdesc, &reg_config);
if (IS_ERR(rdev)) {
ret = PTR_ERR(rdev);
- dev_err(dev, "%s: devm_regulator_register() failed, ret=%d\n",
- node->name, ret);
+ dev_err(dev, "%pOFn: devm_regulator_register() failed, ret=%d\n",
+ node, ret);
return ret;
}
- dev_dbg(dev, "%s regulator registered for RPMh resource %s @ 0x%05X\n",
- node->name, rpmh_resource_name, vreg->addr);
+ dev_dbg(dev, "%pOFn regulator registered for RPMh resource %s @ 0x%05X\n",
+ node, rpmh_resource_name, vreg->addr);
return 0;
}
@@ -504,6 +504,7 @@ static unsigned int rpmh_regulator_pmic4_ldo_of_map_mode(unsigned int rpmh_mode)
break;
default:
mode = REGULATOR_MODE_INVALID;
+ break;
}
return mode;
@@ -537,6 +538,7 @@ rpmh_regulator_pmic4_smps_of_map_mode(unsigned int rpmh_mode)
break;
default:
mode = REGULATOR_MODE_INVALID;
+ break;
}
return mode;
@@ -566,6 +568,7 @@ static unsigned int rpmh_regulator_pmic4_bob_of_map_mode(unsigned int rpmh_mode)
break;
default:
mode = REGULATOR_MODE_INVALID;
+ break;
}
return mode;
diff --git a/drivers/regulator/qcom_smd-regulator.c b/drivers/regulator/qcom_smd-regulator.c
index fe2fb36803e0..f5bca77d67c1 100644
--- a/drivers/regulator/qcom_smd-regulator.c
+++ b/drivers/regulator/qcom_smd-regulator.c
@@ -420,6 +420,60 @@ static const struct regulator_desc pmi8998_bob = {
.ops = &rpm_bob_ops,
};
+static const struct regulator_desc pms405_hfsmps3 = {
+ .linear_ranges = (struct regulator_linear_range[]) {
+ REGULATOR_LINEAR_RANGE(320000, 0, 215, 8000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 216,
+ .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pms405_nldo300 = {
+ .linear_ranges = (struct regulator_linear_range[]) {
+ REGULATOR_LINEAR_RANGE(312000, 0, 127, 8000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 128,
+ .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pms405_nldo1200 = {
+ .linear_ranges = (struct regulator_linear_range[]) {
+ REGULATOR_LINEAR_RANGE(312000, 0, 127, 8000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 128,
+ .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pms405_pldo50 = {
+ .linear_ranges = (struct regulator_linear_range[]) {
+ REGULATOR_LINEAR_RANGE(1664000, 0, 128, 16000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 129,
+ .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pms405_pldo150 = {
+ .linear_ranges = (struct regulator_linear_range[]) {
+ REGULATOR_LINEAR_RANGE(1664000, 0, 128, 16000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 129,
+ .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pms405_pldo600 = {
+ .linear_ranges = (struct regulator_linear_range[]) {
+ REGULATOR_LINEAR_RANGE(1256000, 0, 98, 8000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 99,
+ .ops = &rpm_smps_ldo_ops,
+};
+
struct rpm_regulator_data {
const char *name;
u32 type;
@@ -661,6 +715,28 @@ static const struct rpm_regulator_data rpm_pmi8998_regulators[] = {
{}
};
+static const struct rpm_regulator_data rpm_pms405_regulators[] = {
+ { "s1", QCOM_SMD_RPM_SMPA, 1, &pms405_hfsmps3, "vdd_s1" },
+ { "s2", QCOM_SMD_RPM_SMPA, 2, &pms405_hfsmps3, "vdd_s2" },
+ { "s3", QCOM_SMD_RPM_SMPA, 3, &pms405_hfsmps3, "vdd_s3" },
+ { "s4", QCOM_SMD_RPM_SMPA, 4, &pms405_hfsmps3, "vdd_s4" },
+ { "s5", QCOM_SMD_RPM_SMPA, 5, &pms405_hfsmps3, "vdd_s5" },
+ { "l1", QCOM_SMD_RPM_LDOA, 1, &pms405_nldo1200, "vdd_l1_l2" },
+ { "l2", QCOM_SMD_RPM_LDOA, 2, &pms405_nldo1200, "vdd_l1_l2" },
+ { "l3", QCOM_SMD_RPM_LDOA, 3, &pms405_nldo1200, "vdd_l3_l8" },
+ { "l4", QCOM_SMD_RPM_LDOA, 4, &pms405_nldo300, "vdd_l4" },
+ { "l5", QCOM_SMD_RPM_LDOA, 5, &pms405_pldo600, "vdd_l5_l6" },
+ { "l6", QCOM_SMD_RPM_LDOA, 6, &pms405_pldo600, "vdd_l5_l6" },
+ { "l7", QCOM_SMD_RPM_LDOA, 7, &pms405_pldo150, "vdd_l7" },
+ { "l8", QCOM_SMD_RPM_LDOA, 8, &pms405_nldo1200, "vdd_l3_l8" },
+ { "l9", QCOM_SMD_RPM_LDOA, 9, &pms405_nldo1200, "vdd_l9" },
+ { "l10", QCOM_SMD_RPM_LDOA, 10, &pms405_pldo50, "vdd_l10_l11_l12_l13" },
+ { "l11", QCOM_SMD_RPM_LDOA, 11, &pms405_pldo150, "vdd_l10_l11_l12_l13" },
+ { "l12", QCOM_SMD_RPM_LDOA, 12, &pms405_pldo150, "vdd_l10_l11_l12_l13" },
+ { "l13", QCOM_SMD_RPM_LDOA, 13, &pms405_pldo150, "vdd_l10_l11_l12_l13" },
+ {}
+};
+
static const struct of_device_id rpm_of_match[] = {
{ .compatible = "qcom,rpm-pm8841-regulators", .data = &rpm_pm8841_regulators },
{ .compatible = "qcom,rpm-pm8916-regulators", .data = &rpm_pm8916_regulators },
@@ -669,6 +745,7 @@ static const struct of_device_id rpm_of_match[] = {
{ .compatible = "qcom,rpm-pm8998-regulators", .data = &rpm_pm8998_regulators },
{ .compatible = "qcom,rpm-pma8084-regulators", .data = &rpm_pma8084_regulators },
{ .compatible = "qcom,rpm-pmi8998-regulators", .data = &rpm_pmi8998_regulators },
+ { .compatible = "qcom,rpm-pms405-regulators", .data = &rpm_pms405_regulators },
{}
};
MODULE_DEVICE_TABLE(of, rpm_of_match);
diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c
index 667d16dc83ce..219b9afda0cb 100644
--- a/drivers/regulator/s5m8767.c
+++ b/drivers/regulator/s5m8767.c
@@ -447,15 +447,15 @@ static void s5m8767_regulator_config_ext_control(struct s5m8767_info *s5m8767,
}
if (mode != S5M8767_ENCTRL_USE_GPIO) {
dev_warn(s5m8767->dev,
- "ext-control for %s: mismatched op_mode (%x), ignoring\n",
- rdata->reg_node->name, mode);
+ "ext-control for %pOFn: mismatched op_mode (%x), ignoring\n",
+ rdata->reg_node, mode);
return;
}
if (!rdata->ext_control_gpiod) {
dev_warn(s5m8767->dev,
- "ext-control for %s: GPIO not valid, ignoring\n",
- rdata->reg_node->name);
+ "ext-control for %pOFn: GPIO not valid, ignoring\n",
+ rdata->reg_node);
return;
}
@@ -566,17 +566,18 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
if (i == ARRAY_SIZE(regulators)) {
dev_warn(iodev->dev,
- "don't know how to configure regulator %s\n",
- reg_np->name);
+ "don't know how to configure regulator %pOFn\n",
+ reg_np);
continue;
}
- rdata->ext_control_gpiod = devm_gpiod_get_from_of_node(&pdev->dev,
- reg_np,
- "s5m8767,pmic-ext-control-gpios",
- 0,
- GPIOD_OUT_HIGH,
- "s5m8767");
+ rdata->ext_control_gpiod = devm_gpiod_get_from_of_node(
+ &pdev->dev,
+ reg_np,
+ "s5m8767,pmic-ext-control-gpios",
+ 0,
+ GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE,
+ "s5m8767");
if (IS_ERR(rdata->ext_control_gpiod))
return PTR_ERR(rdata->ext_control_gpiod);
diff --git a/drivers/regulator/stpmic1_regulator.c b/drivers/regulator/stpmic1_regulator.c
new file mode 100644
index 000000000000..e15634edb8ce
--- /dev/null
+++ b/drivers/regulator/stpmic1_regulator.c
@@ -0,0 +1,674 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) STMicroelectronics 2018
+// Author: Pascal Paillet <p.paillet@st.com> for STMicroelectronics.
+
+#include <linux/interrupt.h>
+#include <linux/mfd/stpmic1.h>
+#include <linux/module.h>
+#include <linux/of_irq.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>
+
+/**
+ * stpmic1 regulator description
+ * @desc: regulator framework description
+ * @mask_reset_reg: mask reset register address
+ * @mask_reset_mask: mask rank and mask reset register mask
+ * @icc_reg: icc register address
+ * @icc_mask: icc register mask
+ */
+struct stpmic1_regulator_cfg {
+ struct regulator_desc desc;
+ u8 mask_reset_reg;
+ u8 mask_reset_mask;
+ u8 icc_reg;
+ u8 icc_mask;
+};
+
+/**
+ * stpmic1 regulator data: this structure is used as driver data
+ * @regul_id: regulator id
+ * @reg_node: DT node of regulator (unused on non-DT platforms)
+ * @cfg: stpmic specific regulator description
+ * @mask_reset: mask_reset bit value
+ * @irq_curlim: current limit interrupt number
+ * @regmap: point to parent regmap structure
+ */
+struct stpmic1_regulator {
+ unsigned int regul_id;
+ struct device_node *reg_node;
+ struct stpmic1_regulator_cfg *cfg;
+ u8 mask_reset;
+ int irq_curlim;
+ struct regmap *regmap;
+};
+
+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_regulator_parse_dt(void *driver_data);
+static unsigned int stpmic1_map_mode(unsigned int mode);
+
+enum {
+ STPMIC1_BUCK1 = 0,
+ STPMIC1_BUCK2 = 1,
+ STPMIC1_BUCK3 = 2,
+ STPMIC1_BUCK4 = 3,
+ STPMIC1_LDO1 = 4,
+ STPMIC1_LDO2 = 5,
+ STPMIC1_LDO3 = 6,
+ STPMIC1_LDO4 = 7,
+ STPMIC1_LDO5 = 8,
+ STPMIC1_LDO6 = 9,
+ STPMIC1_VREF_DDR = 10,
+ STPMIC1_BOOST = 11,
+ STPMIC1_VBUS_OTG = 12,
+ STPMIC1_SW_OUT = 13,
+};
+
+/* Enable time worst case is 5000mV/(2250uV/uS) */
+#define PMIC_ENABLE_TIME_US 2200
+
+#define STPMIC1_BUCK_MODE_NORMAL 0
+#define STPMIC1_BUCK_MODE_LP BUCK_HPLP_ENABLE_MASK
+
+struct regulator_linear_range buck1_ranges[] = {
+ REGULATOR_LINEAR_RANGE(600000, 0, 30, 25000),
+ REGULATOR_LINEAR_RANGE(1350000, 31, 63, 0),
+};
+
+struct regulator_linear_range buck2_ranges[] = {
+ REGULATOR_LINEAR_RANGE(1000000, 0, 17, 0),
+ REGULATOR_LINEAR_RANGE(1050000, 18, 19, 0),
+ REGULATOR_LINEAR_RANGE(1100000, 20, 21, 0),
+ REGULATOR_LINEAR_RANGE(1150000, 22, 23, 0),
+ REGULATOR_LINEAR_RANGE(1200000, 24, 25, 0),
+ REGULATOR_LINEAR_RANGE(1250000, 26, 27, 0),
+ REGULATOR_LINEAR_RANGE(1300000, 28, 29, 0),
+ REGULATOR_LINEAR_RANGE(1350000, 30, 31, 0),
+ REGULATOR_LINEAR_RANGE(1400000, 32, 33, 0),
+ REGULATOR_LINEAR_RANGE(1450000, 34, 35, 0),
+ REGULATOR_LINEAR_RANGE(1500000, 36, 63, 0),
+};
+
+struct regulator_linear_range buck3_ranges[] = {
+ REGULATOR_LINEAR_RANGE(1000000, 0, 19, 0),
+ REGULATOR_LINEAR_RANGE(1100000, 20, 23, 0),
+ REGULATOR_LINEAR_RANGE(1200000, 24, 27, 0),
+ REGULATOR_LINEAR_RANGE(1300000, 28, 31, 0),
+ REGULATOR_LINEAR_RANGE(1400000, 32, 35, 0),
+ REGULATOR_LINEAR_RANGE(1500000, 36, 55, 100000),
+ REGULATOR_LINEAR_RANGE(3400000, 56, 63, 0),
+
+};
+
+struct regulator_linear_range buck4_ranges[] = {
+ REGULATOR_LINEAR_RANGE(600000, 0, 27, 25000),
+ REGULATOR_LINEAR_RANGE(1300000, 28, 29, 0),
+ REGULATOR_LINEAR_RANGE(1350000, 30, 31, 0),
+ REGULATOR_LINEAR_RANGE(1400000, 32, 33, 0),
+ REGULATOR_LINEAR_RANGE(1450000, 34, 35, 0),
+ REGULATOR_LINEAR_RANGE(1500000, 36, 60, 100000),
+ REGULATOR_LINEAR_RANGE(3900000, 61, 63, 0),
+
+};
+
+struct regulator_linear_range ldo1_ranges[] = {
+ REGULATOR_LINEAR_RANGE(1700000, 0, 7, 0),
+ REGULATOR_LINEAR_RANGE(1700000, 8, 24, 100000),
+ REGULATOR_LINEAR_RANGE(3300000, 25, 31, 0),
+
+};
+
+struct regulator_linear_range ldo2_ranges[] = {
+ REGULATOR_LINEAR_RANGE(1700000, 0, 7, 0),
+ REGULATOR_LINEAR_RANGE(1700000, 8, 24, 100000),
+ REGULATOR_LINEAR_RANGE(3300000, 25, 30, 0),
+
+};
+
+struct regulator_linear_range ldo3_ranges[] = {
+ REGULATOR_LINEAR_RANGE(1700000, 0, 7, 0),
+ REGULATOR_LINEAR_RANGE(1700000, 8, 24, 100000),
+ REGULATOR_LINEAR_RANGE(3300000, 25, 30, 0),
+ /* with index 31 LDO3 is in DDR mode */
+ REGULATOR_LINEAR_RANGE(500000, 31, 31, 0),
+};
+
+struct regulator_linear_range ldo5_ranges[] = {
+ REGULATOR_LINEAR_RANGE(1700000, 0, 7, 0),
+ REGULATOR_LINEAR_RANGE(1700000, 8, 30, 100000),
+ REGULATOR_LINEAR_RANGE(3900000, 31, 31, 0),
+};
+
+struct regulator_linear_range ldo6_ranges[] = {
+ REGULATOR_LINEAR_RANGE(900000, 0, 24, 100000),
+ REGULATOR_LINEAR_RANGE(3300000, 25, 31, 0),
+};
+
+static struct regulator_ops stpmic1_ldo_ops = {
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
+ .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,
+ .set_pull_down = regulator_set_pull_down_regmap,
+ .set_over_current_protection = stpmic1_set_icc,
+};
+
+static struct regulator_ops stpmic1_ldo3_ops = {
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_iterate,
+ .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,
+ .set_pull_down = regulator_set_pull_down_regmap,
+ .get_bypass = regulator_get_bypass_regmap,
+ .set_bypass = regulator_set_bypass_regmap,
+ .set_over_current_protection = stpmic1_set_icc,
+};
+
+static struct regulator_ops stpmic1_ldo4_fixed_regul_ops = {
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .set_pull_down = regulator_set_pull_down_regmap,
+ .set_over_current_protection = stpmic1_set_icc,
+};
+
+static struct regulator_ops stpmic1_buck_ops = {
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
+ .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,
+ .set_pull_down = regulator_set_pull_down_regmap,
+ .set_mode = stpmic1_set_mode,
+ .get_mode = stpmic1_get_mode,
+ .set_over_current_protection = stpmic1_set_icc,
+};
+
+static struct regulator_ops stpmic1_vref_ddr_ops = {
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .set_pull_down = regulator_set_pull_down_regmap,
+};
+
+static struct regulator_ops stpmic1_switch_regul_ops = {
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .set_over_current_protection = stpmic1_set_icc,
+};
+
+#define REG_LDO(ids, base) { \
+ .name = #ids, \
+ .id = STPMIC1_##ids, \
+ .n_voltages = 32, \
+ .ops = &stpmic1_ldo_ops, \
+ .linear_ranges = base ## _ranges, \
+ .n_linear_ranges = ARRAY_SIZE(base ## _ranges), \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .vsel_reg = ids##_ACTIVE_CR, \
+ .vsel_mask = LDO_VOLTAGE_MASK, \
+ .enable_reg = ids##_ACTIVE_CR, \
+ .enable_mask = LDO_ENABLE_MASK, \
+ .enable_val = 1, \
+ .disable_val = 0, \
+ .enable_time = PMIC_ENABLE_TIME_US, \
+ .pull_down_reg = ids##_PULL_DOWN_REG, \
+ .pull_down_mask = ids##_PULL_DOWN_MASK, \
+ .supply_name = #base, \
+}
+
+#define REG_LDO3(ids, base) { \
+ .name = #ids, \
+ .id = STPMIC1_##ids, \
+ .n_voltages = 32, \
+ .ops = &stpmic1_ldo3_ops, \
+ .linear_ranges = ldo3_ranges, \
+ .n_linear_ranges = ARRAY_SIZE(ldo3_ranges), \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .vsel_reg = LDO3_ACTIVE_CR, \
+ .vsel_mask = LDO_VOLTAGE_MASK, \
+ .enable_reg = LDO3_ACTIVE_CR, \
+ .enable_mask = LDO_ENABLE_MASK, \
+ .enable_val = 1, \
+ .disable_val = 0, \
+ .enable_time = PMIC_ENABLE_TIME_US, \
+ .bypass_reg = LDO3_ACTIVE_CR, \
+ .bypass_mask = LDO_BYPASS_MASK, \
+ .bypass_val_on = LDO_BYPASS_MASK, \
+ .bypass_val_off = 0, \
+ .pull_down_reg = ids##_PULL_DOWN_REG, \
+ .pull_down_mask = ids##_PULL_DOWN_MASK, \
+ .supply_name = #base, \
+}
+
+#define REG_LDO4(ids, base) { \
+ .name = #ids, \
+ .id = STPMIC1_##ids, \
+ .n_voltages = 1, \
+ .ops = &stpmic1_ldo4_fixed_regul_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = 3300000, \
+ .fixed_uV = 3300000, \
+ .enable_reg = LDO4_ACTIVE_CR, \
+ .enable_mask = LDO_ENABLE_MASK, \
+ .enable_val = 1, \
+ .disable_val = 0, \
+ .enable_time = PMIC_ENABLE_TIME_US, \
+ .pull_down_reg = ids##_PULL_DOWN_REG, \
+ .pull_down_mask = ids##_PULL_DOWN_MASK, \
+ .supply_name = #base, \
+}
+
+#define REG_BUCK(ids, base) { \
+ .name = #ids, \
+ .id = STPMIC1_##ids, \
+ .ops = &stpmic1_buck_ops, \
+ .n_voltages = 64, \
+ .linear_ranges = base ## _ranges, \
+ .n_linear_ranges = ARRAY_SIZE(base ## _ranges), \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .vsel_reg = ids##_ACTIVE_CR, \
+ .vsel_mask = BUCK_VOLTAGE_MASK, \
+ .enable_reg = ids##_ACTIVE_CR, \
+ .enable_mask = BUCK_ENABLE_MASK, \
+ .enable_val = 1, \
+ .disable_val = 0, \
+ .enable_time = PMIC_ENABLE_TIME_US, \
+ .of_map_mode = stpmic1_map_mode, \
+ .pull_down_reg = ids##_PULL_DOWN_REG, \
+ .pull_down_mask = ids##_PULL_DOWN_MASK, \
+ .supply_name = #base, \
+}
+
+#define REG_VREF_DDR(ids, base) { \
+ .name = #ids, \
+ .id = STPMIC1_##ids, \
+ .n_voltages = 1, \
+ .ops = &stpmic1_vref_ddr_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = 500000, \
+ .fixed_uV = 500000, \
+ .enable_reg = VREF_DDR_ACTIVE_CR, \
+ .enable_mask = BUCK_ENABLE_MASK, \
+ .enable_val = 1, \
+ .disable_val = 0, \
+ .enable_time = PMIC_ENABLE_TIME_US, \
+ .pull_down_reg = ids##_PULL_DOWN_REG, \
+ .pull_down_mask = ids##_PULL_DOWN_MASK, \
+ .supply_name = #base, \
+}
+
+#define REG_SWITCH(ids, base, reg, mask, val) { \
+ .name = #ids, \
+ .id = STPMIC1_##ids, \
+ .n_voltages = 1, \
+ .ops = &stpmic1_switch_regul_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = 0, \
+ .fixed_uV = 5000000, \
+ .enable_reg = (reg), \
+ .enable_mask = (mask), \
+ .enable_val = (val), \
+ .disable_val = 0, \
+ .enable_time = PMIC_ENABLE_TIME_US, \
+ .supply_name = #base, \
+}
+
+struct stpmic1_regulator_cfg stpmic1_regulator_cfgs[] = {
+ [STPMIC1_BUCK1] = {
+ .desc = REG_BUCK(BUCK1, buck1),
+ .icc_reg = BUCKS_ICCTO_CR,
+ .icc_mask = BIT(0),
+ .mask_reset_reg = BUCKS_MASK_RESET_CR,
+ .mask_reset_mask = BIT(0),
+ },
+ [STPMIC1_BUCK2] = {
+ .desc = REG_BUCK(BUCK2, buck2),
+ .icc_reg = BUCKS_ICCTO_CR,
+ .icc_mask = BIT(1),
+ .mask_reset_reg = BUCKS_MASK_RESET_CR,
+ .mask_reset_mask = BIT(1),
+ },
+ [STPMIC1_BUCK3] = {
+ .desc = REG_BUCK(BUCK3, buck3),
+ .icc_reg = BUCKS_ICCTO_CR,
+ .icc_mask = BIT(2),
+ .mask_reset_reg = BUCKS_MASK_RESET_CR,
+ .mask_reset_mask = BIT(2),
+ },
+ [STPMIC1_BUCK4] = {
+ .desc = REG_BUCK(BUCK4, buck4),
+ .icc_reg = BUCKS_ICCTO_CR,
+ .icc_mask = BIT(3),
+ .mask_reset_reg = BUCKS_MASK_RESET_CR,
+ .mask_reset_mask = BIT(3),
+ },
+ [STPMIC1_LDO1] = {
+ .desc = REG_LDO(LDO1, ldo1),
+ .icc_reg = LDOS_ICCTO_CR,
+ .icc_mask = BIT(0),
+ .mask_reset_reg = LDOS_MASK_RESET_CR,
+ .mask_reset_mask = BIT(0),
+ },
+ [STPMIC1_LDO2] = {
+ .desc = REG_LDO(LDO2, ldo2),
+ .icc_reg = LDOS_ICCTO_CR,
+ .icc_mask = BIT(1),
+ .mask_reset_reg = LDOS_MASK_RESET_CR,
+ .mask_reset_mask = BIT(1),
+ },
+ [STPMIC1_LDO3] = {
+ .desc = REG_LDO3(LDO3, ldo3),
+ .icc_reg = LDOS_ICCTO_CR,
+ .icc_mask = BIT(2),
+ .mask_reset_reg = LDOS_MASK_RESET_CR,
+ .mask_reset_mask = BIT(2),
+ },
+ [STPMIC1_LDO4] = {
+ .desc = REG_LDO4(LDO4, ldo4),
+ .icc_reg = LDOS_ICCTO_CR,
+ .icc_mask = BIT(3),
+ .mask_reset_reg = LDOS_MASK_RESET_CR,
+ .mask_reset_mask = BIT(3),
+ },
+ [STPMIC1_LDO5] = {
+ .desc = REG_LDO(LDO5, ldo5),
+ .icc_reg = LDOS_ICCTO_CR,
+ .icc_mask = BIT(4),
+ .mask_reset_reg = LDOS_MASK_RESET_CR,
+ .mask_reset_mask = BIT(4),
+ },
+ [STPMIC1_LDO6] = {
+ .desc = REG_LDO(LDO6, ldo6),
+ .icc_reg = LDOS_ICCTO_CR,
+ .icc_mask = BIT(5),
+ .mask_reset_reg = LDOS_MASK_RESET_CR,
+ .mask_reset_mask = BIT(5),
+ },
+ [STPMIC1_VREF_DDR] = {
+ .desc = REG_VREF_DDR(VREF_DDR, vref_ddr),
+ .mask_reset_reg = LDOS_MASK_RESET_CR,
+ .mask_reset_mask = BIT(6),
+ },
+ [STPMIC1_BOOST] = {
+ .desc = REG_SWITCH(BOOST, boost, BST_SW_CR,
+ BOOST_ENABLED,
+ BOOST_ENABLED),
+ .icc_reg = BUCKS_ICCTO_CR,
+ .icc_mask = BIT(6),
+ },
+ [STPMIC1_VBUS_OTG] = {
+ .desc = REG_SWITCH(VBUS_OTG, pwr_sw1, BST_SW_CR,
+ USBSW_OTG_SWITCH_ENABLED,
+ USBSW_OTG_SWITCH_ENABLED),
+ .icc_reg = BUCKS_ICCTO_CR,
+ .icc_mask = BIT(4),
+ },
+ [STPMIC1_SW_OUT] = {
+ .desc = REG_SWITCH(SW_OUT, pwr_sw2, BST_SW_CR,
+ SWIN_SWOUT_ENABLED,
+ SWIN_SWOUT_ENABLED),
+ .icc_reg = BUCKS_ICCTO_CR,
+ .icc_mask = BIT(5),
+ },
+};
+
+static unsigned int stpmic1_map_mode(unsigned int mode)
+{
+ switch (mode) {
+ case STPMIC1_BUCK_MODE_NORMAL:
+ return REGULATOR_MODE_NORMAL;
+ case STPMIC1_BUCK_MODE_LP:
+ return REGULATOR_MODE_STANDBY;
+ default:
+ return REGULATOR_MODE_INVALID;
+ }
+}
+
+static unsigned int stpmic1_get_mode(struct regulator_dev *rdev)
+{
+ int value;
+
+ regmap_read(rdev->regmap, rdev->desc->enable_reg, &value);
+
+ if (value & STPMIC1_BUCK_MODE_LP)
+ return REGULATOR_MODE_STANDBY;
+
+ return REGULATOR_MODE_NORMAL;
+}
+
+static int stpmic1_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+ int value;
+
+ switch (mode) {
+ case REGULATOR_MODE_NORMAL:
+ value = STPMIC1_BUCK_MODE_NORMAL;
+ break;
+ case REGULATOR_MODE_STANDBY:
+ value = STPMIC1_BUCK_MODE_LP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+ STPMIC1_BUCK_MODE_LP, value);
+}
+
+static int stpmic1_set_icc(struct regulator_dev *rdev)
+{
+ struct stpmic1_regulator *regul = rdev_get_drvdata(rdev);
+
+ /* enable switch off in case of over current */
+ return regmap_update_bits(regul->regmap, regul->cfg->icc_reg,
+ regul->cfg->icc_mask, regul->cfg->icc_mask);
+}
+
+static irqreturn_t stpmic1_curlim_irq_handler(int irq, void *data)
+{
+ struct regulator_dev *rdev = (struct regulator_dev *)data;
+
+ mutex_lock(&rdev->mutex);
+
+ /* Send an overcurrent notification */
+ regulator_notifier_call_chain(rdev,
+ REGULATOR_EVENT_OVER_CURRENT,
+ NULL);
+
+ mutex_unlock(&rdev->mutex);
+
+ return IRQ_HANDLED;
+}
+
+static int stpmic1_regulator_init(struct platform_device *pdev,
+ struct regulator_dev *rdev)
+{
+ struct stpmic1_regulator *regul = rdev_get_drvdata(rdev);
+ int ret = 0;
+
+ /* set mask reset */
+ if (regul->mask_reset && regul->cfg->mask_reset_reg != 0) {
+ ret = regmap_update_bits(regul->regmap,
+ regul->cfg->mask_reset_reg,
+ regul->cfg->mask_reset_mask,
+ regul->cfg->mask_reset_mask);
+ if (ret) {
+ dev_err(&pdev->dev, "set mask reset failed\n");
+ return ret;
+ }
+ }
+
+ /* setup an irq handler for over-current detection */
+ if (regul->irq_curlim > 0) {
+ ret = devm_request_threaded_irq(&pdev->dev,
+ regul->irq_curlim, NULL,
+ stpmic1_curlim_irq_handler,
+ IRQF_ONESHOT | IRQF_SHARED,
+ pdev->name, rdev);
+ if (ret) {
+ dev_err(&pdev->dev, "Request IRQ failed\n");
+ return ret;
+ }
+ }
+ return 0;
+}
+
+#define MATCH(_name, _id) \
+ [STPMIC1_##_id] = { \
+ .name = #_name, \
+ .desc = &stpmic1_regulator_cfgs[STPMIC1_##_id].desc, \
+ }
+
+static struct of_regulator_match stpmic1_regulators_matches[] = {
+ MATCH(buck1, BUCK1),
+ MATCH(buck2, BUCK2),
+ MATCH(buck3, BUCK3),
+ MATCH(buck4, BUCK4),
+ MATCH(ldo1, LDO1),
+ MATCH(ldo2, LDO2),
+ MATCH(ldo3, LDO3),
+ MATCH(ldo4, LDO4),
+ MATCH(ldo5, LDO5),
+ MATCH(ldo6, LDO6),
+ MATCH(vref_ddr, VREF_DDR),
+ MATCH(boost, BOOST),
+ MATCH(pwr_sw1, VBUS_OTG),
+ MATCH(pwr_sw2, SW_OUT),
+};
+
+static int stpmic1_regulator_parse_dt(void *driver_data)
+{
+ struct stpmic1_regulator *regul =
+ (struct stpmic1_regulator *)driver_data;
+
+ if (!regul)
+ return -EINVAL;
+
+ if (of_get_property(regul->reg_node, "st,mask-reset", NULL))
+ regul->mask_reset = 1;
+
+ regul->irq_curlim = of_irq_get(regul->reg_node, 0);
+
+ return 0;
+}
+
+static struct
+regulator_dev *stpmic1_regulator_register(struct platform_device *pdev, int id,
+ struct regulator_init_data *init_data,
+ struct stpmic1_regulator *regul)
+{
+ struct stpmic1 *pmic_dev = dev_get_drvdata(pdev->dev.parent);
+ struct regulator_dev *rdev;
+ struct regulator_config config = {};
+
+ config.dev = &pdev->dev;
+ config.init_data = init_data;
+ config.of_node = stpmic1_regulators_matches[id].of_node;
+ config.regmap = pmic_dev->regmap;
+ config.driver_data = regul;
+
+ regul->regul_id = id;
+ regul->reg_node = config.of_node;
+ regul->cfg = &stpmic1_regulator_cfgs[id];
+ regul->regmap = pmic_dev->regmap;
+
+ rdev = devm_regulator_register(&pdev->dev, &regul->cfg->desc, &config);
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev, "failed to register %s regulator\n",
+ regul->cfg->desc.name);
+ }
+
+ return rdev;
+}
+
+static int stpmic1_regulator_probe(struct platform_device *pdev)
+{
+ struct regulator_dev *rdev;
+ struct stpmic1_regulator *regul;
+ struct regulator_init_data *init_data;
+ struct device_node *np;
+ int i, ret;
+
+ np = pdev->dev.of_node;
+
+ ret = of_regulator_match(&pdev->dev, np,
+ stpmic1_regulators_matches,
+ ARRAY_SIZE(stpmic1_regulators_matches));
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "Error in PMIC regulator device tree node");
+ return ret;
+ }
+
+ regul = devm_kzalloc(&pdev->dev, ARRAY_SIZE(stpmic1_regulator_cfgs) *
+ sizeof(struct stpmic1_regulator),
+ GFP_KERNEL);
+ if (!regul)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(stpmic1_regulator_cfgs); i++) {
+ /* Parse DT & find regulators to register */
+ init_data = stpmic1_regulators_matches[i].init_data;
+ if (init_data)
+ init_data->regulator_init = &stpmic1_regulator_parse_dt;
+
+ rdev = stpmic1_regulator_register(pdev, i, init_data, regul);
+ if (IS_ERR(rdev))
+ return PTR_ERR(rdev);
+
+ ret = stpmic1_regulator_init(pdev, rdev);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "failed to initialize regulator %d\n", ret);
+ return ret;
+ }
+
+ regul++;
+ }
+
+ dev_dbg(&pdev->dev, "stpmic1_regulator driver probed\n");
+
+ return 0;
+}
+
+static const struct of_device_id of_pmic_regulator_match[] = {
+ { .compatible = "st,stpmic1-regulators" },
+ { },
+};
+
+MODULE_DEVICE_TABLE(of, of_pmic_regulator_match);
+
+static struct platform_driver stpmic1_regulator_driver = {
+ .driver = {
+ .name = "stpmic1-regulator",
+ .of_match_table = of_match_ptr(of_pmic_regulator_match),
+ },
+ .probe = stpmic1_regulator_probe,
+};
+
+module_platform_driver(stpmic1_regulator_driver);
+
+MODULE_DESCRIPTION("STPMIC1 PMIC voltage regulator driver");
+MODULE_AUTHOR("Pascal Paillet <p.paillet@st.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/tps65090-regulator.c b/drivers/regulator/tps65090-regulator.c
index edaef9e4dc74..db714d5edafc 100644
--- a/drivers/regulator/tps65090-regulator.c
+++ b/drivers/regulator/tps65090-regulator.c
@@ -374,6 +374,7 @@ static struct tps65090_platform_data *tps65090_parse_dt_reg_data(
gflags = GPIOD_OUT_HIGH;
else
gflags = GPIOD_OUT_LOW;
+ gflags |= GPIOD_FLAGS_BIT_NONEXCLUSIVE;
rpdata->gpiod = devm_gpiod_get_from_of_node(&pdev->dev,
tps65090_matches[idx].of_node,
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index 052d4dd347f9..f0abd2608044 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -84,8 +84,16 @@ config KEYSTONE_REMOTEPROC
It's safe to say N here if you're not interested in the Keystone
DSPs or just want to use a bare minimum kernel.
-config QCOM_ADSP_PIL
- tristate "Qualcomm ADSP Peripheral Image Loader"
+config QCOM_RPROC_COMMON
+ tristate
+
+config QCOM_Q6V5_COMMON
+ tristate
+ depends on ARCH_QCOM
+ depends on QCOM_SMEM
+
+config QCOM_Q6V5_ADSP
+ tristate "Qualcomm Technology Inc ADSP Peripheral Image Loader"
depends on OF && ARCH_QCOM
depends on QCOM_SMEM
depends on RPMSG_QCOM_SMD || (COMPILE_TEST && RPMSG_QCOM_SMD=n)
@@ -95,33 +103,41 @@ config QCOM_ADSP_PIL
select QCOM_MDT_LOADER
select QCOM_Q6V5_COMMON
select QCOM_RPROC_COMMON
- select QCOM_SCM
help
- Say y here to support the TrustZone based Peripherial Image Loader
- for the Qualcomm ADSP remote processors.
+ Say y here to support the Peripheral Image Loader
+ for the Qualcomm Technology Inc. ADSP remote processors.
-config QCOM_RPROC_COMMON
- tristate
-
-config QCOM_Q6V5_COMMON
- tristate
- depends on ARCH_QCOM
+config QCOM_Q6V5_MSS
+ tristate "Qualcomm Hexagon V5 self-authenticating modem subsystem support"
+ depends on OF && ARCH_QCOM
depends on QCOM_SMEM
+ depends on RPMSG_QCOM_SMD || (COMPILE_TEST && RPMSG_QCOM_SMD=n)
+ depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n
+ depends on QCOM_SYSMON || QCOM_SYSMON=n
+ select MFD_SYSCON
+ select QCOM_Q6V5_COMMON
+ select QCOM_RPROC_COMMON
+ select QCOM_SCM
+ help
+ Say y here to support the Qualcomm self-authenticating modem
+ subsystem based on Hexagon V5.
-config QCOM_Q6V5_PIL
- tristate "Qualcomm Hexagon V5 Peripherial Image Loader"
+config QCOM_Q6V5_PAS
+ tristate "Qualcomm Hexagon v5 Peripheral Authentication Service support"
depends on OF && ARCH_QCOM
depends on QCOM_SMEM
depends on RPMSG_QCOM_SMD || (COMPILE_TEST && RPMSG_QCOM_SMD=n)
depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n
depends on QCOM_SYSMON || QCOM_SYSMON=n
select MFD_SYSCON
+ select QCOM_MDT_LOADER
select QCOM_Q6V5_COMMON
select QCOM_RPROC_COMMON
select QCOM_SCM
help
- Say y here to support the Qualcomm Peripherial Image Loader for the
- Hexagon V5 based remote processors.
+ Say y here to support the TrustZone based Peripherial Image Loader
+ for the Qualcomm Hexagon v5 based remote processors. This is commonly
+ used to control subsystems such as ADSP, Compute and Sensor.
config QCOM_Q6V5_WCSS
tristate "Qualcomm Hexagon based WCSS Peripheral Image Loader"
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index 03332fa7e2ee..ce5d061e92be 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -14,10 +14,11 @@ obj-$(CONFIG_OMAP_REMOTEPROC) += omap_remoteproc.o
obj-$(CONFIG_WKUP_M3_RPROC) += wkup_m3_rproc.o
obj-$(CONFIG_DA8XX_REMOTEPROC) += da8xx_remoteproc.o
obj-$(CONFIG_KEYSTONE_REMOTEPROC) += keystone_remoteproc.o
-obj-$(CONFIG_QCOM_ADSP_PIL) += qcom_adsp_pil.o
obj-$(CONFIG_QCOM_RPROC_COMMON) += qcom_common.o
obj-$(CONFIG_QCOM_Q6V5_COMMON) += qcom_q6v5.o
-obj-$(CONFIG_QCOM_Q6V5_PIL) += qcom_q6v5_pil.o
+obj-$(CONFIG_QCOM_Q6V5_ADSP) += qcom_q6v5_adsp.o
+obj-$(CONFIG_QCOM_Q6V5_MSS) += qcom_q6v5_mss.o
+obj-$(CONFIG_QCOM_Q6V5_PAS) += qcom_q6v5_pas.o
obj-$(CONFIG_QCOM_Q6V5_WCSS) += qcom_q6v5_wcss.o
obj-$(CONFIG_QCOM_SYSMON) += qcom_sysmon.o
obj-$(CONFIG_QCOM_WCNSS_PIL) += qcom_wcnss_pil.o
diff --git a/drivers/remoteproc/da8xx_remoteproc.c b/drivers/remoteproc/da8xx_remoteproc.c
index e230bef71be1..d200334577f6 100644
--- a/drivers/remoteproc/da8xx_remoteproc.c
+++ b/drivers/remoteproc/da8xx_remoteproc.c
@@ -226,7 +226,7 @@ static int da8xx_rproc_get_internal_memories(struct platform_device *pdev,
res->start & DA8XX_RPROC_LOCAL_ADDRESS_MASK;
drproc->mem[i].size = resource_size(res);
- dev_dbg(dev, "memory %8s: bus addr %pa size 0x%x va %p da 0x%x\n",
+ dev_dbg(dev, "memory %8s: bus addr %pa size 0x%zx va %p da 0x%x\n",
mem_names[i], &drproc->mem[i].bus_addr,
drproc->mem[i].size, drproc->mem[i].cpu_addr,
drproc->mem[i].dev_addr);
diff --git a/drivers/remoteproc/qcom_q6v5.c b/drivers/remoteproc/qcom_q6v5.c
index 61a760ee4aac..0d33e3079f0d 100644
--- a/drivers/remoteproc/qcom_q6v5.c
+++ b/drivers/remoteproc/qcom_q6v5.c
@@ -84,6 +84,7 @@ static irqreturn_t q6v5_fatal_interrupt(int irq, void *data)
else
dev_err(q6v5->dev, "fatal error without message\n");
+ q6v5->running = false;
rproc_report_crash(q6v5->rproc, RPROC_FATAL_ERROR);
return IRQ_HANDLED;
@@ -150,8 +151,6 @@ int qcom_q6v5_request_stop(struct qcom_q6v5 *q6v5)
{
int ret;
- q6v5->running = false;
-
qcom_smem_state_update_bits(q6v5->state,
BIT(q6v5->stop_bit), BIT(q6v5->stop_bit));
@@ -188,6 +187,14 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
init_completion(&q6v5->stop_done);
q6v5->wdog_irq = platform_get_irq_byname(pdev, "wdog");
+ if (q6v5->wdog_irq < 0) {
+ if (q6v5->wdog_irq != -EPROBE_DEFER)
+ dev_err(&pdev->dev,
+ "failed to retrieve wdog IRQ: %d\n",
+ q6v5->wdog_irq);
+ return q6v5->wdog_irq;
+ }
+
ret = devm_request_threaded_irq(&pdev->dev, q6v5->wdog_irq,
NULL, q6v5_wdog_interrupt,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
@@ -198,6 +205,14 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
}
q6v5->fatal_irq = platform_get_irq_byname(pdev, "fatal");
+ if (q6v5->fatal_irq < 0) {
+ if (q6v5->fatal_irq != -EPROBE_DEFER)
+ dev_err(&pdev->dev,
+ "failed to retrieve fatal IRQ: %d\n",
+ q6v5->fatal_irq);
+ return q6v5->fatal_irq;
+ }
+
ret = devm_request_threaded_irq(&pdev->dev, q6v5->fatal_irq,
NULL, q6v5_fatal_interrupt,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
@@ -208,6 +223,14 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
}
q6v5->ready_irq = platform_get_irq_byname(pdev, "ready");
+ if (q6v5->ready_irq < 0) {
+ if (q6v5->ready_irq != -EPROBE_DEFER)
+ dev_err(&pdev->dev,
+ "failed to retrieve ready IRQ: %d\n",
+ q6v5->ready_irq);
+ return q6v5->ready_irq;
+ }
+
ret = devm_request_threaded_irq(&pdev->dev, q6v5->ready_irq,
NULL, q6v5_ready_interrupt,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
@@ -218,6 +241,14 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
}
q6v5->handover_irq = platform_get_irq_byname(pdev, "handover");
+ if (q6v5->handover_irq < 0) {
+ if (q6v5->handover_irq != -EPROBE_DEFER)
+ dev_err(&pdev->dev,
+ "failed to retrieve handover IRQ: %d\n",
+ q6v5->handover_irq);
+ return q6v5->handover_irq;
+ }
+
ret = devm_request_threaded_irq(&pdev->dev, q6v5->handover_irq,
NULL, q6v5_handover_interrupt,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
@@ -229,6 +260,14 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
disable_irq(q6v5->handover_irq);
q6v5->stop_irq = platform_get_irq_byname(pdev, "stop-ack");
+ if (q6v5->stop_irq < 0) {
+ if (q6v5->stop_irq != -EPROBE_DEFER)
+ dev_err(&pdev->dev,
+ "failed to retrieve stop-ack IRQ: %d\n",
+ q6v5->stop_irq);
+ return q6v5->stop_irq;
+ }
+
ret = devm_request_threaded_irq(&pdev->dev, q6v5->stop_irq,
NULL, q6v5_stop_interrupt,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c
new file mode 100644
index 000000000000..79374d1de311
--- /dev/null
+++ b/drivers/remoteproc/qcom_q6v5_adsp.c
@@ -0,0 +1,497 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Qualcomm Technology Inc. ADSP Peripheral Image Loader for SDM845.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#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/remoteproc.h>
+#include <linux/reset.h>
+#include <linux/soc/qcom/mdt_loader.h>
+#include <linux/soc/qcom/smem.h>
+#include <linux/soc/qcom/smem_state.h>
+
+#include "qcom_common.h"
+#include "qcom_q6v5.h"
+#include "remoteproc_internal.h"
+
+/* time out value */
+#define ACK_TIMEOUT 1000
+#define BOOT_FSM_TIMEOUT 10000
+/* mask values */
+#define EVB_MASK GENMASK(27, 4)
+/*QDSP6SS register offsets*/
+#define RST_EVB_REG 0x10
+#define CORE_START_REG 0x400
+#define BOOT_CMD_REG 0x404
+#define BOOT_STATUS_REG 0x408
+#define RET_CFG_REG 0x1C
+/*TCSR register offsets*/
+#define LPASS_MASTER_IDLE_REG 0x8
+#define LPASS_HALTACK_REG 0x4
+#define LPASS_PWR_ON_REG 0x10
+#define LPASS_HALTREQ_REG 0x0
+
+/* list of clocks required by ADSP PIL */
+static const char * const adsp_clk_id[] = {
+ "sway_cbcr", "lpass_aon", "lpass_ahbs_aon_cbcr", "lpass_ahbm_aon_cbcr",
+ "qdsp6ss_xo", "qdsp6ss_sleep", "qdsp6ss_core",
+};
+
+struct adsp_pil_data {
+ int crash_reason_smem;
+ const char *firmware_name;
+
+ const char *ssr_name;
+ const char *sysmon_name;
+ int ssctl_id;
+};
+
+struct qcom_adsp {
+ struct device *dev;
+ struct rproc *rproc;
+
+ struct qcom_q6v5 q6v5;
+
+ struct clk *xo;
+
+ int num_clks;
+ struct clk_bulk_data *clks;
+
+ void __iomem *qdsp6ss_base;
+
+ struct reset_control *pdc_sync_reset;
+ struct reset_control *cc_lpass_restart;
+
+ struct regmap *halt_map;
+ unsigned int halt_lpass;
+
+ int crash_reason_smem;
+
+ struct completion start_done;
+ struct completion stop_done;
+
+ phys_addr_t mem_phys;
+ phys_addr_t mem_reloc;
+ void *mem_region;
+ size_t mem_size;
+
+ struct qcom_rproc_glink glink_subdev;
+ struct qcom_rproc_ssr ssr_subdev;
+ struct qcom_sysmon *sysmon;
+};
+
+static int qcom_adsp_shutdown(struct qcom_adsp *adsp)
+{
+ unsigned long timeout;
+ unsigned int val;
+ int ret;
+
+ /* Reset the retention logic */
+ val = readl(adsp->qdsp6ss_base + RET_CFG_REG);
+ val |= 0x1;
+ writel(val, adsp->qdsp6ss_base + RET_CFG_REG);
+
+ clk_bulk_disable_unprepare(adsp->num_clks, adsp->clks);
+
+ /* QDSP6 master port needs to be explicitly halted */
+ ret = regmap_read(adsp->halt_map,
+ adsp->halt_lpass + LPASS_PWR_ON_REG, &val);
+ if (ret || !val)
+ goto reset;
+
+ ret = regmap_read(adsp->halt_map,
+ adsp->halt_lpass + LPASS_MASTER_IDLE_REG,
+ &val);
+ if (ret || val)
+ goto reset;
+
+ regmap_write(adsp->halt_map,
+ adsp->halt_lpass + LPASS_HALTREQ_REG, 1);
+
+ /* Wait for halt ACK from QDSP6 */
+ timeout = jiffies + msecs_to_jiffies(ACK_TIMEOUT);
+ for (;;) {
+ ret = regmap_read(adsp->halt_map,
+ adsp->halt_lpass + LPASS_HALTACK_REG, &val);
+ if (ret || val || time_after(jiffies, timeout))
+ break;
+
+ usleep_range(1000, 1100);
+ }
+
+ ret = regmap_read(adsp->halt_map,
+ adsp->halt_lpass + LPASS_MASTER_IDLE_REG, &val);
+ if (ret || !val)
+ dev_err(adsp->dev, "port failed halt\n");
+
+reset:
+ /* Assert the LPASS PDC Reset */
+ reset_control_assert(adsp->pdc_sync_reset);
+ /* Place the LPASS processor into reset */
+ reset_control_assert(adsp->cc_lpass_restart);
+ /* wait after asserting subsystem restart from AOSS */
+ usleep_range(200, 300);
+
+ /* Clear the halt request for the AXIM and AHBM for Q6 */
+ regmap_write(adsp->halt_map, adsp->halt_lpass + LPASS_HALTREQ_REG, 0);
+
+ /* De-assert the LPASS PDC Reset */
+ reset_control_deassert(adsp->pdc_sync_reset);
+ /* Remove the LPASS reset */
+ reset_control_deassert(adsp->cc_lpass_restart);
+ /* wait after de-asserting subsystem restart from AOSS */
+ usleep_range(200, 300);
+
+ return 0;
+}
+
+static int adsp_load(struct rproc *rproc, const struct firmware *fw)
+{
+ struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
+
+ return qcom_mdt_load_no_init(adsp->dev, fw, rproc->firmware, 0,
+ adsp->mem_region, adsp->mem_phys, adsp->mem_size,
+ &adsp->mem_reloc);
+}
+
+static int adsp_start(struct rproc *rproc)
+{
+ struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
+ int ret;
+ unsigned int val;
+
+ qcom_q6v5_prepare(&adsp->q6v5);
+
+ ret = clk_prepare_enable(adsp->xo);
+ if (ret)
+ goto disable_irqs;
+
+ dev_pm_genpd_set_performance_state(adsp->dev, INT_MAX);
+ ret = pm_runtime_get_sync(adsp->dev);
+ if (ret)
+ goto disable_xo_clk;
+
+ ret = clk_bulk_prepare_enable(adsp->num_clks, adsp->clks);
+ if (ret) {
+ dev_err(adsp->dev, "adsp clk_enable failed\n");
+ goto disable_power_domain;
+ }
+
+ /* Program boot address */
+ writel(adsp->mem_phys >> 4, adsp->qdsp6ss_base + RST_EVB_REG);
+
+ /* De-assert QDSP6 stop core. QDSP6 will execute after out of reset */
+ writel(0x1, adsp->qdsp6ss_base + CORE_START_REG);
+
+ /* Trigger boot FSM to start QDSP6 */
+ writel(0x1, adsp->qdsp6ss_base + BOOT_CMD_REG);
+
+ /* Wait for core to come out of reset */
+ ret = readl_poll_timeout(adsp->qdsp6ss_base + BOOT_STATUS_REG,
+ val, (val & BIT(0)) != 0, 10, BOOT_FSM_TIMEOUT);
+ if (ret) {
+ dev_err(adsp->dev, "failed to bootup adsp\n");
+ goto disable_adsp_clks;
+ }
+
+ ret = qcom_q6v5_wait_for_start(&adsp->q6v5, msecs_to_jiffies(5 * HZ));
+ if (ret == -ETIMEDOUT) {
+ dev_err(adsp->dev, "start timed out\n");
+ goto disable_adsp_clks;
+ }
+
+ return 0;
+
+disable_adsp_clks:
+ clk_bulk_disable_unprepare(adsp->num_clks, adsp->clks);
+disable_power_domain:
+ dev_pm_genpd_set_performance_state(adsp->dev, 0);
+ pm_runtime_put(adsp->dev);
+disable_xo_clk:
+ clk_disable_unprepare(adsp->xo);
+disable_irqs:
+ qcom_q6v5_unprepare(&adsp->q6v5);
+
+ return ret;
+}
+
+static void qcom_adsp_pil_handover(struct qcom_q6v5 *q6v5)
+{
+ struct qcom_adsp *adsp = container_of(q6v5, struct qcom_adsp, q6v5);
+
+ clk_disable_unprepare(adsp->xo);
+ dev_pm_genpd_set_performance_state(adsp->dev, 0);
+ pm_runtime_put(adsp->dev);
+}
+
+static int adsp_stop(struct rproc *rproc)
+{
+ struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
+ int handover;
+ int ret;
+
+ ret = qcom_q6v5_request_stop(&adsp->q6v5);
+ if (ret == -ETIMEDOUT)
+ dev_err(adsp->dev, "timed out on wait\n");
+
+ ret = qcom_adsp_shutdown(adsp);
+ if (ret)
+ dev_err(adsp->dev, "failed to shutdown: %d\n", ret);
+
+ handover = qcom_q6v5_unprepare(&adsp->q6v5);
+ if (handover)
+ qcom_adsp_pil_handover(&adsp->q6v5);
+
+ return ret;
+}
+
+static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
+{
+ struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
+ int offset;
+
+ offset = da - adsp->mem_reloc;
+ if (offset < 0 || offset + len > adsp->mem_size)
+ return NULL;
+
+ return adsp->mem_region + offset;
+}
+
+static const struct rproc_ops adsp_ops = {
+ .start = adsp_start,
+ .stop = adsp_stop,
+ .da_to_va = adsp_da_to_va,
+ .parse_fw = qcom_register_dump_segments,
+ .load = adsp_load,
+};
+
+static int adsp_init_clock(struct qcom_adsp *adsp)
+{
+ int i, ret;
+
+ adsp->xo = devm_clk_get(adsp->dev, "xo");
+ if (IS_ERR(adsp->xo)) {
+ ret = PTR_ERR(adsp->xo);
+ if (ret != -EPROBE_DEFER)
+ dev_err(adsp->dev, "failed to get xo clock");
+ return ret;
+ }
+
+ adsp->num_clks = ARRAY_SIZE(adsp_clk_id);
+ adsp->clks = devm_kcalloc(adsp->dev, adsp->num_clks,
+ sizeof(*adsp->clks), GFP_KERNEL);
+ if (!adsp->clks)
+ return -ENOMEM;
+
+ for (i = 0; i < adsp->num_clks; i++)
+ adsp->clks[i].id = adsp_clk_id[i];
+
+ return devm_clk_bulk_get(adsp->dev, adsp->num_clks, adsp->clks);
+}
+
+static int adsp_init_reset(struct qcom_adsp *adsp)
+{
+ adsp->pdc_sync_reset = devm_reset_control_get_exclusive(adsp->dev,
+ "pdc_sync");
+ if (IS_ERR(adsp->pdc_sync_reset)) {
+ dev_err(adsp->dev, "failed to acquire pdc_sync reset\n");
+ return PTR_ERR(adsp->pdc_sync_reset);
+ }
+
+ adsp->cc_lpass_restart = devm_reset_control_get_exclusive(adsp->dev,
+ "cc_lpass");
+ if (IS_ERR(adsp->cc_lpass_restart)) {
+ dev_err(adsp->dev, "failed to acquire cc_lpass restart\n");
+ return PTR_ERR(adsp->cc_lpass_restart);
+ }
+
+ return 0;
+}
+
+static int adsp_init_mmio(struct qcom_adsp *adsp,
+ struct platform_device *pdev)
+{
+ struct device_node *syscon;
+ struct resource *res;
+ int ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ adsp->qdsp6ss_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!adsp->qdsp6ss_base) {
+ dev_err(adsp->dev, "failed to map QDSP6SS registers\n");
+ return -ENOMEM;
+ }
+
+ syscon = of_parse_phandle(pdev->dev.of_node, "qcom,halt-regs", 0);
+ if (!syscon) {
+ dev_err(&pdev->dev, "failed to parse qcom,halt-regs\n");
+ return -EINVAL;
+ }
+
+ adsp->halt_map = syscon_node_to_regmap(syscon);
+ of_node_put(syscon);
+ if (IS_ERR(adsp->halt_map))
+ return PTR_ERR(adsp->halt_map);
+
+ ret = of_property_read_u32_index(pdev->dev.of_node, "qcom,halt-regs",
+ 1, &adsp->halt_lpass);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "no offset in syscon\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int adsp_alloc_memory_region(struct qcom_adsp *adsp)
+{
+ struct device_node *node;
+ struct resource r;
+ int ret;
+
+ node = of_parse_phandle(adsp->dev->of_node, "memory-region", 0);
+ if (!node) {
+ dev_err(adsp->dev, "no memory-region specified\n");
+ return -EINVAL;
+ }
+
+ ret = of_address_to_resource(node, 0, &r);
+ if (ret)
+ return ret;
+
+ adsp->mem_phys = adsp->mem_reloc = r.start;
+ adsp->mem_size = resource_size(&r);
+ adsp->mem_region = devm_ioremap_wc(adsp->dev,
+ adsp->mem_phys, adsp->mem_size);
+ if (!adsp->mem_region) {
+ dev_err(adsp->dev, "unable to map memory region: %pa+%zx\n",
+ &r.start, adsp->mem_size);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static int adsp_probe(struct platform_device *pdev)
+{
+ const struct adsp_pil_data *desc;
+ struct qcom_adsp *adsp;
+ struct rproc *rproc;
+ int ret;
+
+ desc = of_device_get_match_data(&pdev->dev);
+ if (!desc)
+ return -EINVAL;
+
+ rproc = rproc_alloc(&pdev->dev, pdev->name, &adsp_ops,
+ desc->firmware_name, sizeof(*adsp));
+ if (!rproc) {
+ dev_err(&pdev->dev, "unable to allocate remoteproc\n");
+ return -ENOMEM;
+ }
+
+ adsp = (struct qcom_adsp *)rproc->priv;
+ adsp->dev = &pdev->dev;
+ adsp->rproc = rproc;
+ platform_set_drvdata(pdev, adsp);
+
+ ret = adsp_alloc_memory_region(adsp);
+ if (ret)
+ goto free_rproc;
+
+ ret = adsp_init_clock(adsp);
+ if (ret)
+ goto free_rproc;
+
+ pm_runtime_enable(adsp->dev);
+
+ ret = adsp_init_reset(adsp);
+ if (ret)
+ goto disable_pm;
+
+ ret = adsp_init_mmio(adsp, pdev);
+ if (ret)
+ goto disable_pm;
+
+ ret = qcom_q6v5_init(&adsp->q6v5, pdev, rproc, desc->crash_reason_smem,
+ qcom_adsp_pil_handover);
+ if (ret)
+ goto disable_pm;
+
+ qcom_add_glink_subdev(rproc, &adsp->glink_subdev);
+ qcom_add_ssr_subdev(rproc, &adsp->ssr_subdev, desc->ssr_name);
+ adsp->sysmon = qcom_add_sysmon_subdev(rproc,
+ desc->sysmon_name,
+ desc->ssctl_id);
+
+ ret = rproc_add(rproc);
+ if (ret)
+ goto disable_pm;
+
+ return 0;
+
+disable_pm:
+ pm_runtime_disable(adsp->dev);
+free_rproc:
+ rproc_free(rproc);
+
+ return ret;
+}
+
+static int adsp_remove(struct platform_device *pdev)
+{
+ struct qcom_adsp *adsp = platform_get_drvdata(pdev);
+
+ rproc_del(adsp->rproc);
+
+ qcom_remove_glink_subdev(adsp->rproc, &adsp->glink_subdev);
+ qcom_remove_sysmon_subdev(adsp->sysmon);
+ qcom_remove_ssr_subdev(adsp->rproc, &adsp->ssr_subdev);
+ pm_runtime_disable(adsp->dev);
+ rproc_free(adsp->rproc);
+
+ return 0;
+}
+
+static const struct adsp_pil_data adsp_resource_init = {
+ .crash_reason_smem = 423,
+ .firmware_name = "adsp.mdt",
+ .ssr_name = "lpass",
+ .sysmon_name = "adsp",
+ .ssctl_id = 0x14,
+};
+
+static const struct of_device_id adsp_of_match[] = {
+ { .compatible = "qcom,sdm845-adsp-pil", .data = &adsp_resource_init },
+ { },
+};
+MODULE_DEVICE_TABLE(of, adsp_of_match);
+
+static struct platform_driver adsp_pil_driver = {
+ .probe = adsp_probe,
+ .remove = adsp_remove,
+ .driver = {
+ .name = "qcom_q6v5_adsp",
+ .of_match_table = adsp_of_match,
+ },
+};
+
+module_platform_driver(adsp_pil_driver);
+MODULE_DESCRIPTION("QTI SDM845 ADSP Peripheral Image Loader");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/remoteproc/qcom_q6v5_pil.c b/drivers/remoteproc/qcom_q6v5_mss.c
index d7a4b9eca5d2..01be7314e176 100644
--- a/drivers/remoteproc/qcom_q6v5_pil.c
+++ b/drivers/remoteproc/qcom_q6v5_mss.c
@@ -1,5 +1,5 @@
/*
- * Qualcomm Peripheral Image Loader
+ * Qualcomm self-authenticating modem subsystem remoteproc driver
*
* Copyright (C) 2016 Linaro Ltd.
* Copyright (C) 2014 Sony Mobile Communications AB
@@ -149,6 +149,7 @@ struct q6v5 {
u32 halt_nc;
struct reset_control *mss_restart;
+ struct reset_control *pdc_reset;
struct qcom_q6v5 q6v5;
@@ -166,6 +167,10 @@ struct q6v5 {
bool running;
+ bool dump_mba_loaded;
+ unsigned long dump_segment_mask;
+ unsigned long dump_complete_mask;
+
phys_addr_t mba_phys;
void *mba_region;
size_t mba_size;
@@ -347,10 +352,17 @@ static int q6v5_load(struct rproc *rproc, const struct firmware *fw)
static int q6v5_reset_assert(struct q6v5 *qproc)
{
- if (qproc->has_alt_reset)
- return reset_control_reset(qproc->mss_restart);
- else
- return reset_control_assert(qproc->mss_restart);
+ int ret;
+
+ if (qproc->has_alt_reset) {
+ reset_control_assert(qproc->pdc_reset);
+ ret = reset_control_reset(qproc->mss_restart);
+ reset_control_deassert(qproc->pdc_reset);
+ } else {
+ ret = reset_control_assert(qproc->mss_restart);
+ }
+
+ return ret;
}
static int q6v5_reset_deassert(struct q6v5 *qproc)
@@ -358,9 +370,11 @@ static int q6v5_reset_deassert(struct q6v5 *qproc)
int ret;
if (qproc->has_alt_reset) {
+ reset_control_assert(qproc->pdc_reset);
writel(1, qproc->rmb_base + RMB_MBA_ALT_RESET);
ret = reset_control_reset(qproc->mss_restart);
writel(0, qproc->rmb_base + RMB_MBA_ALT_RESET);
+ reset_control_deassert(qproc->pdc_reset);
} else {
ret = reset_control_deassert(qproc->mss_restart);
}
@@ -669,6 +683,171 @@ static bool q6v5_phdr_valid(const struct elf32_phdr *phdr)
return true;
}
+static int q6v5_mba_load(struct q6v5 *qproc)
+{
+ int ret;
+ int xfermemop_ret;
+
+ qcom_q6v5_prepare(&qproc->q6v5);
+
+ ret = q6v5_regulator_enable(qproc, qproc->proxy_regs,
+ qproc->proxy_reg_count);
+ if (ret) {
+ dev_err(qproc->dev, "failed to enable proxy supplies\n");
+ goto disable_irqs;
+ }
+
+ ret = q6v5_clk_enable(qproc->dev, qproc->proxy_clks,
+ qproc->proxy_clk_count);
+ if (ret) {
+ dev_err(qproc->dev, "failed to enable proxy clocks\n");
+ goto disable_proxy_reg;
+ }
+
+ ret = q6v5_regulator_enable(qproc, qproc->active_regs,
+ qproc->active_reg_count);
+ if (ret) {
+ dev_err(qproc->dev, "failed to enable supplies\n");
+ goto disable_proxy_clk;
+ }
+
+ ret = q6v5_clk_enable(qproc->dev, qproc->reset_clks,
+ qproc->reset_clk_count);
+ if (ret) {
+ dev_err(qproc->dev, "failed to enable reset clocks\n");
+ goto disable_vdd;
+ }
+
+ ret = q6v5_reset_deassert(qproc);
+ if (ret) {
+ dev_err(qproc->dev, "failed to deassert mss restart\n");
+ goto disable_reset_clks;
+ }
+
+ ret = q6v5_clk_enable(qproc->dev, qproc->active_clks,
+ qproc->active_clk_count);
+ if (ret) {
+ dev_err(qproc->dev, "failed to enable clocks\n");
+ goto assert_reset;
+ }
+
+ /* Assign MBA image access in DDR to q6 */
+ ret = q6v5_xfer_mem_ownership(qproc, &qproc->mba_perm, true,
+ qproc->mba_phys, qproc->mba_size);
+ if (ret) {
+ dev_err(qproc->dev,
+ "assigning Q6 access to mba memory failed: %d\n", ret);
+ goto disable_active_clks;
+ }
+
+ writel(qproc->mba_phys, qproc->rmb_base + RMB_MBA_IMAGE_REG);
+
+ ret = q6v5proc_reset(qproc);
+ if (ret)
+ goto reclaim_mba;
+
+ ret = q6v5_rmb_mba_wait(qproc, 0, 5000);
+ if (ret == -ETIMEDOUT) {
+ dev_err(qproc->dev, "MBA boot timed out\n");
+ goto halt_axi_ports;
+ } else if (ret != RMB_MBA_XPU_UNLOCKED &&
+ ret != RMB_MBA_XPU_UNLOCKED_SCRIBBLED) {
+ dev_err(qproc->dev, "MBA returned unexpected status %d\n", ret);
+ ret = -EINVAL;
+ goto halt_axi_ports;
+ }
+
+ qproc->dump_mba_loaded = true;
+ return 0;
+
+halt_axi_ports:
+ q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_q6);
+ q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_modem);
+ q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_nc);
+
+reclaim_mba:
+ xfermemop_ret = q6v5_xfer_mem_ownership(qproc, &qproc->mba_perm, false,
+ qproc->mba_phys,
+ qproc->mba_size);
+ if (xfermemop_ret) {
+ dev_err(qproc->dev,
+ "Failed to reclaim mba buffer, system may become unstable\n");
+ }
+
+disable_active_clks:
+ q6v5_clk_disable(qproc->dev, qproc->active_clks,
+ qproc->active_clk_count);
+assert_reset:
+ q6v5_reset_assert(qproc);
+disable_reset_clks:
+ q6v5_clk_disable(qproc->dev, qproc->reset_clks,
+ qproc->reset_clk_count);
+disable_vdd:
+ q6v5_regulator_disable(qproc, qproc->active_regs,
+ qproc->active_reg_count);
+disable_proxy_clk:
+ q6v5_clk_disable(qproc->dev, qproc->proxy_clks,
+ qproc->proxy_clk_count);
+disable_proxy_reg:
+ q6v5_regulator_disable(qproc, qproc->proxy_regs,
+ qproc->proxy_reg_count);
+disable_irqs:
+ qcom_q6v5_unprepare(&qproc->q6v5);
+
+ return ret;
+}
+
+static void q6v5_mba_reclaim(struct q6v5 *qproc)
+{
+ int ret;
+ u32 val;
+
+ qproc->dump_mba_loaded = false;
+
+ q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_q6);
+ q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_modem);
+ q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_nc);
+ if (qproc->version == MSS_MSM8996) {
+ /*
+ * To avoid high MX current during LPASS/MSS restart.
+ */
+ val = readl(qproc->reg_base + QDSP6SS_PWR_CTL_REG);
+ val |= Q6SS_CLAMP_IO | QDSP6v56_CLAMP_WL |
+ QDSP6v56_CLAMP_QMC_MEM;
+ writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
+ }
+
+ ret = q6v5_xfer_mem_ownership(qproc, &qproc->mpss_perm,
+ false, qproc->mpss_phys,
+ qproc->mpss_size);
+ WARN_ON(ret);
+
+ q6v5_reset_assert(qproc);
+
+ q6v5_clk_disable(qproc->dev, qproc->reset_clks,
+ qproc->reset_clk_count);
+ q6v5_clk_disable(qproc->dev, qproc->active_clks,
+ qproc->active_clk_count);
+ q6v5_regulator_disable(qproc, qproc->active_regs,
+ qproc->active_reg_count);
+
+ /* In case of failure or coredump scenario where reclaiming MBA memory
+ * could not happen reclaim it here.
+ */
+ ret = q6v5_xfer_mem_ownership(qproc, &qproc->mba_perm, false,
+ qproc->mba_phys,
+ qproc->mba_size);
+ WARN_ON(ret);
+
+ ret = qcom_q6v5_unprepare(&qproc->q6v5);
+ if (ret) {
+ q6v5_clk_disable(qproc->dev, qproc->proxy_clks,
+ qproc->proxy_clk_count);
+ q6v5_regulator_disable(qproc, qproc->proxy_regs,
+ qproc->proxy_reg_count);
+ }
+}
+
static int q6v5_mpss_load(struct q6v5 *qproc)
{
const struct elf32_phdr *phdrs;
@@ -721,6 +900,7 @@ static int q6v5_mpss_load(struct q6v5 *qproc)
}
mpss_reloc = relocate ? min_addr : qproc->mpss_phys;
+ qproc->mpss_reloc = mpss_reloc;
/* Load firmware segments */
for (i = 0; i < ehdr->e_phnum; i++) {
phdr = &phdrs[i];
@@ -784,80 +964,42 @@ release_firmware:
return ret < 0 ? ret : 0;
}
-static int q6v5_start(struct rproc *rproc)
+static void qcom_q6v5_dump_segment(struct rproc *rproc,
+ struct rproc_dump_segment *segment,
+ void *dest)
{
- struct q6v5 *qproc = (struct q6v5 *)rproc->priv;
- int xfermemop_ret;
- int ret;
-
- qcom_q6v5_prepare(&qproc->q6v5);
-
- ret = q6v5_regulator_enable(qproc, qproc->proxy_regs,
- qproc->proxy_reg_count);
- if (ret) {
- dev_err(qproc->dev, "failed to enable proxy supplies\n");
- goto disable_irqs;
- }
-
- ret = q6v5_clk_enable(qproc->dev, qproc->proxy_clks,
- qproc->proxy_clk_count);
- if (ret) {
- dev_err(qproc->dev, "failed to enable proxy clocks\n");
- goto disable_proxy_reg;
- }
+ int ret = 0;
+ struct q6v5 *qproc = rproc->priv;
+ unsigned long mask = BIT((unsigned long)segment->priv);
+ void *ptr = rproc_da_to_va(rproc, segment->da, segment->size);
- ret = q6v5_regulator_enable(qproc, qproc->active_regs,
- qproc->active_reg_count);
- if (ret) {
- dev_err(qproc->dev, "failed to enable supplies\n");
- goto disable_proxy_clk;
- }
+ /* Unlock mba before copying segments */
+ if (!qproc->dump_mba_loaded)
+ ret = q6v5_mba_load(qproc);
- ret = q6v5_clk_enable(qproc->dev, qproc->reset_clks,
- qproc->reset_clk_count);
- if (ret) {
- dev_err(qproc->dev, "failed to enable reset clocks\n");
- goto disable_vdd;
- }
+ if (!ptr || ret)
+ memset(dest, 0xff, segment->size);
+ else
+ memcpy(dest, ptr, segment->size);
- ret = q6v5_reset_deassert(qproc);
- if (ret) {
- dev_err(qproc->dev, "failed to deassert mss restart\n");
- goto disable_reset_clks;
- }
+ qproc->dump_segment_mask |= mask;
- ret = q6v5_clk_enable(qproc->dev, qproc->active_clks,
- qproc->active_clk_count);
- if (ret) {
- dev_err(qproc->dev, "failed to enable clocks\n");
- goto assert_reset;
- }
-
- /* Assign MBA image access in DDR to q6 */
- ret = q6v5_xfer_mem_ownership(qproc, &qproc->mba_perm, true,
- qproc->mba_phys, qproc->mba_size);
- if (ret) {
- dev_err(qproc->dev,
- "assigning Q6 access to mba memory failed: %d\n", ret);
- goto disable_active_clks;
+ /* Reclaim mba after copying segments */
+ if (qproc->dump_segment_mask == qproc->dump_complete_mask) {
+ if (qproc->dump_mba_loaded)
+ q6v5_mba_reclaim(qproc);
}
+}
- writel(qproc->mba_phys, qproc->rmb_base + RMB_MBA_IMAGE_REG);
+static int q6v5_start(struct rproc *rproc)
+{
+ struct q6v5 *qproc = (struct q6v5 *)rproc->priv;
+ int xfermemop_ret;
+ int ret;
- ret = q6v5proc_reset(qproc);
+ ret = q6v5_mba_load(qproc);
if (ret)
- goto reclaim_mba;
-
- ret = q6v5_rmb_mba_wait(qproc, 0, 5000);
- if (ret == -ETIMEDOUT) {
- dev_err(qproc->dev, "MBA boot timed out\n");
- goto halt_axi_ports;
- } else if (ret != RMB_MBA_XPU_UNLOCKED &&
- ret != RMB_MBA_XPU_UNLOCKED_SCRIBBLED) {
- dev_err(qproc->dev, "MBA returned unexpected status %d\n", ret);
- ret = -EINVAL;
- goto halt_axi_ports;
- }
+ return ret;
dev_info(qproc->dev, "MBA booted, loading mpss\n");
@@ -877,6 +1019,9 @@ static int q6v5_start(struct rproc *rproc)
if (xfermemop_ret)
dev_err(qproc->dev,
"Failed to reclaim mba buffer system may become unstable\n");
+
+ /* Reset Dump Segment Mask */
+ qproc->dump_segment_mask = 0;
qproc->running = true;
return 0;
@@ -886,42 +1031,7 @@ reclaim_mpss:
false, qproc->mpss_phys,
qproc->mpss_size);
WARN_ON(xfermemop_ret);
-
-halt_axi_ports:
- q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_q6);
- q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_modem);
- q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_nc);
-
-reclaim_mba:
- xfermemop_ret = q6v5_xfer_mem_ownership(qproc, &qproc->mba_perm, false,
- qproc->mba_phys,
- qproc->mba_size);
- if (xfermemop_ret) {
- dev_err(qproc->dev,
- "Failed to reclaim mba buffer, system may become unstable\n");
- }
-
-disable_active_clks:
- q6v5_clk_disable(qproc->dev, qproc->active_clks,
- qproc->active_clk_count);
-
-assert_reset:
- q6v5_reset_assert(qproc);
-disable_reset_clks:
- q6v5_clk_disable(qproc->dev, qproc->reset_clks,
- qproc->reset_clk_count);
-disable_vdd:
- q6v5_regulator_disable(qproc, qproc->active_regs,
- qproc->active_reg_count);
-disable_proxy_clk:
- q6v5_clk_disable(qproc->dev, qproc->proxy_clks,
- qproc->proxy_clk_count);
-disable_proxy_reg:
- q6v5_regulator_disable(qproc, qproc->proxy_regs,
- qproc->proxy_reg_count);
-
-disable_irqs:
- qcom_q6v5_unprepare(&qproc->q6v5);
+ q6v5_mba_reclaim(qproc);
return ret;
}
@@ -930,7 +1040,6 @@ static int q6v5_stop(struct rproc *rproc)
{
struct q6v5 *qproc = (struct q6v5 *)rproc->priv;
int ret;
- u32 val;
qproc->running = false;
@@ -938,40 +1047,7 @@ static int q6v5_stop(struct rproc *rproc)
if (ret == -ETIMEDOUT)
dev_err(qproc->dev, "timed out on wait\n");
- q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_q6);
- q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_modem);
- q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_nc);
- if (qproc->version == MSS_MSM8996) {
- /*
- * To avoid high MX current during LPASS/MSS restart.
- */
- val = readl(qproc->reg_base + QDSP6SS_PWR_CTL_REG);
- val |= Q6SS_CLAMP_IO | QDSP6v56_CLAMP_WL |
- QDSP6v56_CLAMP_QMC_MEM;
- writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
- }
-
-
- ret = q6v5_xfer_mem_ownership(qproc, &qproc->mpss_perm, false,
- qproc->mpss_phys, qproc->mpss_size);
- WARN_ON(ret);
-
- q6v5_reset_assert(qproc);
-
- ret = qcom_q6v5_unprepare(&qproc->q6v5);
- if (ret) {
- q6v5_clk_disable(qproc->dev, qproc->proxy_clks,
- qproc->proxy_clk_count);
- q6v5_regulator_disable(qproc, qproc->proxy_regs,
- qproc->proxy_reg_count);
- }
-
- q6v5_clk_disable(qproc->dev, qproc->reset_clks,
- qproc->reset_clk_count);
- q6v5_clk_disable(qproc->dev, qproc->active_clks,
- qproc->active_clk_count);
- q6v5_regulator_disable(qproc, qproc->active_regs,
- qproc->active_reg_count);
+ q6v5_mba_reclaim(qproc);
return 0;
}
@@ -988,10 +1064,52 @@ static void *q6v5_da_to_va(struct rproc *rproc, u64 da, int len)
return qproc->mpss_region + offset;
}
+static int qcom_q6v5_register_dump_segments(struct rproc *rproc,
+ const struct firmware *mba_fw)
+{
+ const struct firmware *fw;
+ const struct elf32_phdr *phdrs;
+ const struct elf32_phdr *phdr;
+ const struct elf32_hdr *ehdr;
+ struct q6v5 *qproc = rproc->priv;
+ unsigned long i;
+ int ret;
+
+ ret = request_firmware(&fw, "modem.mdt", qproc->dev);
+ if (ret < 0) {
+ dev_err(qproc->dev, "unable to load modem.mdt\n");
+ return ret;
+ }
+
+ ehdr = (struct elf32_hdr *)fw->data;
+ phdrs = (struct elf32_phdr *)(ehdr + 1);
+ qproc->dump_complete_mask = 0;
+
+ for (i = 0; i < ehdr->e_phnum; i++) {
+ phdr = &phdrs[i];
+
+ if (!q6v5_phdr_valid(phdr))
+ continue;
+
+ ret = rproc_coredump_add_custom_segment(rproc, phdr->p_paddr,
+ phdr->p_memsz,
+ qcom_q6v5_dump_segment,
+ (void *)i);
+ if (ret)
+ break;
+
+ qproc->dump_complete_mask |= BIT(i);
+ }
+
+ release_firmware(fw);
+ return ret;
+}
+
static const struct rproc_ops q6v5_ops = {
.start = q6v5_start,
.stop = q6v5_stop,
.da_to_va = q6v5_da_to_va,
+ .parse_fw = qcom_q6v5_register_dump_segments,
.load = q6v5_load,
};
@@ -1066,12 +1184,21 @@ static int q6v5_init_clocks(struct device *dev, struct clk **clks,
static int q6v5_init_reset(struct q6v5 *qproc)
{
qproc->mss_restart = devm_reset_control_get_exclusive(qproc->dev,
- NULL);
+ "mss_restart");
if (IS_ERR(qproc->mss_restart)) {
dev_err(qproc->dev, "failed to acquire mss restart\n");
return PTR_ERR(qproc->mss_restart);
}
+ if (qproc->has_alt_reset) {
+ qproc->pdc_reset = devm_reset_control_get_exclusive(qproc->dev,
+ "pdc_reset");
+ if (IS_ERR(qproc->pdc_reset)) {
+ dev_err(qproc->dev, "failed to acquire pdc reset\n");
+ return PTR_ERR(qproc->pdc_reset);
+ }
+ }
+
return 0;
}
@@ -1132,6 +1259,9 @@ static int q6v5_probe(struct platform_device *pdev)
if (!desc)
return -EINVAL;
+ if (desc->need_mem_protection && !qcom_scm_is_available())
+ return -EPROBE_DEFER;
+
rproc = rproc_alloc(&pdev->dev, pdev->name, &q6v5_ops,
desc->hexagon_mba_image, sizeof(*qproc));
if (!rproc) {
@@ -1192,12 +1322,12 @@ static int q6v5_probe(struct platform_device *pdev)
}
qproc->active_reg_count = ret;
+ qproc->has_alt_reset = desc->has_alt_reset;
ret = q6v5_init_reset(qproc);
if (ret)
goto free_rproc;
qproc->version = desc->version;
- qproc->has_alt_reset = desc->has_alt_reset;
qproc->need_mem_protection = desc->need_mem_protection;
ret = qcom_q6v5_init(&qproc->q6v5, pdev, rproc, MPSS_CRASH_REASON_SMEM,
@@ -1368,11 +1498,11 @@ static struct platform_driver q6v5_driver = {
.probe = q6v5_probe,
.remove = q6v5_remove,
.driver = {
- .name = "qcom-q6v5-pil",
+ .name = "qcom-q6v5-mss",
.of_match_table = q6v5_of_match,
},
};
module_platform_driver(q6v5_driver);
-MODULE_DESCRIPTION("Peripheral Image Loader for Hexagon");
+MODULE_DESCRIPTION("Qualcomm Self-authenticating modem remoteproc driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/remoteproc/qcom_adsp_pil.c b/drivers/remoteproc/qcom_q6v5_pas.c
index d4339a6da616..b1e63fcd5fdf 100644
--- a/drivers/remoteproc/qcom_adsp_pil.c
+++ b/drivers/remoteproc/qcom_q6v5_pas.c
@@ -342,6 +342,16 @@ static const struct adsp_data adsp_resource_init = {
.ssctl_id = 0x14,
};
+static const struct adsp_data cdsp_resource_init = {
+ .crash_reason_smem = 601,
+ .firmware_name = "cdsp.mdt",
+ .pas_id = 18,
+ .has_aggre2_clk = false,
+ .ssr_name = "cdsp",
+ .sysmon_name = "cdsp",
+ .ssctl_id = 0x17,
+};
+
static const struct adsp_data slpi_resource_init = {
.crash_reason_smem = 424,
.firmware_name = "slpi.mdt",
@@ -352,10 +362,24 @@ static const struct adsp_data slpi_resource_init = {
.ssctl_id = 0x16,
};
+static const struct adsp_data wcss_resource_init = {
+ .crash_reason_smem = 421,
+ .firmware_name = "wcnss.mdt",
+ .pas_id = 6,
+ .ssr_name = "mpss",
+ .sysmon_name = "wcnss",
+ .ssctl_id = 0x12,
+};
+
static const struct of_device_id adsp_of_match[] = {
{ .compatible = "qcom,msm8974-adsp-pil", .data = &adsp_resource_init},
{ .compatible = "qcom,msm8996-adsp-pil", .data = &adsp_resource_init},
{ .compatible = "qcom,msm8996-slpi-pil", .data = &slpi_resource_init},
+ { .compatible = "qcom,qcs404-adsp-pas", .data = &adsp_resource_init },
+ { .compatible = "qcom,qcs404-cdsp-pas", .data = &cdsp_resource_init },
+ { .compatible = "qcom,qcs404-wcss-pas", .data = &wcss_resource_init },
+ { .compatible = "qcom,sdm845-adsp-pas", .data = &adsp_resource_init},
+ { .compatible = "qcom,sdm845-cdsp-pas", .data = &cdsp_resource_init},
{ },
};
MODULE_DEVICE_TABLE(of, adsp_of_match);
@@ -364,11 +388,11 @@ static struct platform_driver adsp_driver = {
.probe = adsp_probe,
.remove = adsp_remove,
.driver = {
- .name = "qcom_adsp_pil",
+ .name = "qcom_q6v5_pas",
.of_match_table = adsp_of_match,
},
};
module_platform_driver(adsp_driver);
-MODULE_DESCRIPTION("Qualcomm MSM8974/MSM8996 ADSP Peripherial Image Loader");
+MODULE_DESCRIPTION("Qualcomm Hexagon v5 Peripheral Authentication Service driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index aa6206706fe3..54ec38fc5dca 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -53,6 +53,11 @@ typedef int (*rproc_handle_resources_t)(struct rproc *rproc,
typedef int (*rproc_handle_resource_t)(struct rproc *rproc,
void *, int offset, int avail);
+static int rproc_alloc_carveout(struct rproc *rproc,
+ struct rproc_mem_entry *mem);
+static int rproc_release_carveout(struct rproc *rproc,
+ struct rproc_mem_entry *mem);
+
/* Unique indices for remoteproc devices */
static DEFINE_IDA(rproc_dev_index);
@@ -140,6 +145,22 @@ static void rproc_disable_iommu(struct rproc *rproc)
iommu_domain_free(domain);
}
+static phys_addr_t rproc_va_to_pa(void *cpu_addr)
+{
+ /*
+ * Return physical address according to virtual address location
+ * - in vmalloc: if region ioremapped or defined as dma_alloc_coherent
+ * - in kernel: if region allocated in generic dma memory pool
+ */
+ if (is_vmalloc_addr(cpu_addr)) {
+ return page_to_phys(vmalloc_to_page(cpu_addr)) +
+ offset_in_page(cpu_addr);
+ }
+
+ WARN_ON(!virt_addr_valid(cpu_addr));
+ return virt_to_phys(cpu_addr);
+}
+
/**
* rproc_da_to_va() - lookup the kernel virtual address for a remoteproc address
* @rproc: handle of a remote processor
@@ -201,27 +222,128 @@ out:
}
EXPORT_SYMBOL(rproc_da_to_va);
+/**
+ * rproc_find_carveout_by_name() - lookup the carveout region by a name
+ * @rproc: handle of a remote processor
+ * @name,..: carveout name to find (standard printf format)
+ *
+ * Platform driver has the capability to register some pre-allacoted carveout
+ * (physically contiguous memory regions) before rproc firmware loading and
+ * associated resource table analysis. These regions may be dedicated memory
+ * regions internal to the coprocessor or specified DDR region with specific
+ * attributes
+ *
+ * This function is a helper function with which we can go over the
+ * allocated carveouts and return associated region characteristics like
+ * coprocessor address, length or processor virtual address.
+ *
+ * Return: a valid pointer on carveout entry on success or NULL on failure.
+ */
+struct rproc_mem_entry *
+rproc_find_carveout_by_name(struct rproc *rproc, const char *name, ...)
+{
+ va_list args;
+ char _name[32];
+ struct rproc_mem_entry *carveout, *mem = NULL;
+
+ if (!name)
+ return NULL;
+
+ va_start(args, name);
+ vsnprintf(_name, sizeof(_name), name, args);
+ va_end(args);
+
+ list_for_each_entry(carveout, &rproc->carveouts, node) {
+ /* Compare carveout and requested names */
+ if (!strcmp(carveout->name, _name)) {
+ mem = carveout;
+ break;
+ }
+ }
+
+ return mem;
+}
+
+/**
+ * rproc_check_carveout_da() - Check specified carveout da configuration
+ * @rproc: handle of a remote processor
+ * @mem: pointer on carveout to check
+ * @da: area device address
+ * @len: associated area size
+ *
+ * This function is a helper function to verify requested device area (couple
+ * da, len) is part of specified carevout.
+ *
+ * Return: 0 if carveout match request else -ENOMEM
+ */
+int rproc_check_carveout_da(struct rproc *rproc, struct rproc_mem_entry *mem,
+ u32 da, u32 len)
+{
+ struct device *dev = &rproc->dev;
+ int delta = 0;
+
+ /* Check requested resource length */
+ if (len > mem->len) {
+ dev_err(dev, "Registered carveout doesn't fit len request\n");
+ return -ENOMEM;
+ }
+
+ if (da != FW_RSC_ADDR_ANY && mem->da == FW_RSC_ADDR_ANY) {
+ /* Update existing carveout da */
+ mem->da = da;
+ } else if (da != FW_RSC_ADDR_ANY && mem->da != FW_RSC_ADDR_ANY) {
+ delta = da - mem->da;
+
+ /* Check requested resource belongs to registered carveout */
+ if (delta < 0) {
+ dev_err(dev,
+ "Registered carveout doesn't fit da request\n");
+ return -ENOMEM;
+ }
+
+ if (delta + len > mem->len) {
+ dev_err(dev,
+ "Registered carveout doesn't fit len request\n");
+ return -ENOMEM;
+ }
+ }
+
+ return 0;
+}
+
int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
{
struct rproc *rproc = rvdev->rproc;
struct device *dev = &rproc->dev;
struct rproc_vring *rvring = &rvdev->vring[i];
struct fw_rsc_vdev *rsc;
- dma_addr_t dma;
- void *va;
int ret, size, notifyid;
+ struct rproc_mem_entry *mem;
/* actual size of vring (in bytes) */
size = PAGE_ALIGN(vring_size(rvring->len, rvring->align));
- /*
- * Allocate non-cacheable memory for the vring. In the future
- * this call will also configure the IOMMU for us
- */
- va = dma_alloc_coherent(dev->parent, size, &dma, GFP_KERNEL);
- if (!va) {
- dev_err(dev->parent, "dma_alloc_coherent failed\n");
- return -EINVAL;
+ rsc = (void *)rproc->table_ptr + rvdev->rsc_offset;
+
+ /* Search for pre-registered carveout */
+ mem = rproc_find_carveout_by_name(rproc, "vdev%dvring%d", rvdev->index,
+ i);
+ if (mem) {
+ if (rproc_check_carveout_da(rproc, mem, rsc->vring[i].da, size))
+ return -ENOMEM;
+ } else {
+ /* Register carveout in in list */
+ mem = rproc_mem_entry_init(dev, 0, 0, size, rsc->vring[i].da,
+ rproc_alloc_carveout,
+ rproc_release_carveout,
+ "vdev%dvring%d",
+ rvdev->index, i);
+ if (!mem) {
+ dev_err(dev, "Can't allocate memory entry structure\n");
+ return -ENOMEM;
+ }
+
+ rproc_add_carveout(rproc, mem);
}
/*
@@ -232,7 +354,6 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
ret = idr_alloc(&rproc->notifyids, rvring, 0, 0, GFP_KERNEL);
if (ret < 0) {
dev_err(dev, "idr_alloc failed: %d\n", ret);
- dma_free_coherent(dev->parent, size, va, dma);
return ret;
}
notifyid = ret;
@@ -241,21 +362,9 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
if (notifyid > rproc->max_notifyid)
rproc->max_notifyid = notifyid;
- dev_dbg(dev, "vring%d: va %pK dma %pad size 0x%x idr %d\n",
- i, va, &dma, size, notifyid);
-
- rvring->va = va;
- rvring->dma = dma;
rvring->notifyid = notifyid;
- /*
- * Let the rproc know the notifyid and da of this vring.
- * Not all platforms use dma_alloc_coherent to automatically
- * set up the iommu. In this case the device address (da) will
- * hold the physical address and not the device address.
- */
- rsc = (void *)rproc->table_ptr + rvdev->rsc_offset;
- rsc->vring[i].da = dma;
+ /* Let the rproc know the notifyid of this vring.*/
rsc->vring[i].notifyid = notifyid;
return 0;
}
@@ -287,12 +396,10 @@ rproc_parse_vring(struct rproc_vdev *rvdev, struct fw_rsc_vdev *rsc, int i)
void rproc_free_vring(struct rproc_vring *rvring)
{
- int size = PAGE_ALIGN(vring_size(rvring->len, rvring->align));
struct rproc *rproc = rvring->rvdev->rproc;
int idx = rvring->rvdev->vring - rvring;
struct fw_rsc_vdev *rsc;
- dma_free_coherent(rproc->dev.parent, size, rvring->va, rvring->dma);
idr_remove(&rproc->notifyids, rvring->notifyid);
/* reset resource entry info */
@@ -379,6 +486,7 @@ static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc,
rvdev->id = rsc->id;
rvdev->rproc = rproc;
+ rvdev->index = rproc->nb_vdev++;
/* parse the vrings */
for (i = 0; i < rsc->num_of_vrings; i++) {
@@ -423,9 +531,6 @@ void rproc_vdev_release(struct kref *ref)
for (id = 0; id < ARRAY_SIZE(rvdev->vring); id++) {
rvring = &rvdev->vring[id];
- if (!rvring->va)
- continue;
-
rproc_free_vring(rvring);
}
@@ -584,61 +689,31 @@ out:
}
/**
- * rproc_handle_carveout() - handle phys contig memory allocation requests
+ * rproc_alloc_carveout() - allocated specified carveout
* @rproc: rproc handle
- * @rsc: the resource entry
- * @avail: size of available data (for image validation)
- *
- * This function will handle firmware requests for allocation of physically
- * contiguous memory regions.
- *
- * These request entries should come first in the firmware's resource table,
- * as other firmware entries might request placing other data objects inside
- * these memory regions (e.g. data/code segments, trace resource entries, ...).
+ * @mem: the memory entry to allocate
*
- * Allocating memory this way helps utilizing the reserved physical memory
- * (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.
+ * This function allocate specified memory entry @mem using
+ * dma_alloc_coherent() as default allocator
*/
-static int rproc_handle_carveout(struct rproc *rproc,
- struct fw_rsc_carveout *rsc,
- int offset, int avail)
+static int rproc_alloc_carveout(struct rproc *rproc,
+ struct rproc_mem_entry *mem)
{
- struct rproc_mem_entry *carveout, *mapping;
+ struct rproc_mem_entry *mapping = NULL;
struct device *dev = &rproc->dev;
dma_addr_t dma;
void *va;
int ret;
- if (sizeof(*rsc) > avail) {
- dev_err(dev, "carveout rsc is truncated\n");
- return -EINVAL;
- }
-
- /* make sure reserved bytes are zeroes */
- if (rsc->reserved) {
- dev_err(dev, "carveout rsc has non zero reserved bytes\n");
- return -EINVAL;
- }
-
- dev_dbg(dev, "carveout rsc: name: %s, da 0x%x, pa 0x%x, len 0x%x, flags 0x%x\n",
- rsc->name, rsc->da, rsc->pa, rsc->len, rsc->flags);
-
- carveout = kzalloc(sizeof(*carveout), GFP_KERNEL);
- if (!carveout)
- return -ENOMEM;
-
- va = dma_alloc_coherent(dev->parent, rsc->len, &dma, GFP_KERNEL);
+ va = dma_alloc_coherent(dev->parent, mem->len, &dma, GFP_KERNEL);
if (!va) {
dev_err(dev->parent,
- "failed to allocate dma memory: len 0x%x\n", rsc->len);
- ret = -ENOMEM;
- goto free_carv;
+ "failed to allocate dma memory: len 0x%x\n", mem->len);
+ return -ENOMEM;
}
dev_dbg(dev, "carveout va %pK, dma %pad, len 0x%x\n",
- va, &dma, rsc->len);
+ va, &dma, mem->len);
/*
* Ok, this is non-standard.
@@ -657,15 +732,23 @@ static int rproc_handle_carveout(struct rproc *rproc,
* to use the iommu-based DMA API: we expect 'dma' to contain the
* physical address in this case.
*/
- if (rproc->domain) {
+
+ if (mem->da != FW_RSC_ADDR_ANY) {
+ if (!rproc->domain) {
+ dev_err(dev->parent,
+ "Bad carveout rsc configuration\n");
+ ret = -ENOMEM;
+ goto dma_free;
+ }
+
mapping = kzalloc(sizeof(*mapping), GFP_KERNEL);
if (!mapping) {
ret = -ENOMEM;
goto dma_free;
}
- ret = iommu_map(rproc->domain, rsc->da, dma, rsc->len,
- rsc->flags);
+ ret = iommu_map(rproc->domain, mem->da, dma, mem->len,
+ mem->flags);
if (ret) {
dev_err(dev, "iommu_map failed: %d\n", ret);
goto free_mapping;
@@ -678,52 +761,219 @@ static int rproc_handle_carveout(struct rproc *rproc,
* We can't trust the remote processor not to change the
* resource table, so we must maintain this info independently.
*/
- mapping->da = rsc->da;
- mapping->len = rsc->len;
+ mapping->da = mem->da;
+ mapping->len = mem->len;
list_add_tail(&mapping->node, &rproc->mappings);
dev_dbg(dev, "carveout mapped 0x%x to %pad\n",
- rsc->da, &dma);
+ mem->da, &dma);
+ } else {
+ mem->da = (u32)dma;
}
- /*
- * Some remote processors might need to know the pa
- * even though they are behind an IOMMU. E.g., OMAP4's
- * remote M3 processor needs this so it can control
- * on-chip hardware accelerators that are not behind
- * the IOMMU, and therefor must know the pa.
- *
- * Generally we don't want to expose physical addresses
- * if we don't have to (remote processors are generally
- * _not_ trusted), so we might want to do this only for
- * remote processor that _must_ have this (e.g. OMAP4's
- * dual M3 subsystem).
- *
- * Non-IOMMU processors might also want to have this info.
- * In this case, the device address and the physical address
- * are the same.
- */
- rsc->pa = dma;
-
- carveout->va = va;
- carveout->len = rsc->len;
- carveout->dma = dma;
- carveout->da = rsc->da;
-
- list_add_tail(&carveout->node, &rproc->carveouts);
+ mem->dma = (u32)dma;
+ mem->va = va;
return 0;
free_mapping:
kfree(mapping);
dma_free:
- dma_free_coherent(dev->parent, rsc->len, va, dma);
-free_carv:
- kfree(carveout);
+ dma_free_coherent(dev->parent, mem->len, va, dma);
return ret;
}
-/*
+/**
+ * rproc_release_carveout() - release acquired carveout
+ * @rproc: rproc handle
+ * @mem: the memory entry to release
+ *
+ * This function releases specified memory entry @mem allocated via
+ * rproc_alloc_carveout() function by @rproc.
+ */
+static int rproc_release_carveout(struct rproc *rproc,
+ struct rproc_mem_entry *mem)
+{
+ struct device *dev = &rproc->dev;
+
+ /* clean up carveout allocations */
+ dma_free_coherent(dev->parent, mem->len, mem->va, mem->dma);
+ return 0;
+}
+
+/**
+ * rproc_handle_carveout() - handle phys contig memory allocation requests
+ * @rproc: rproc handle
+ * @rsc: the resource entry
+ * @avail: size of available data (for image validation)
+ *
+ * This function will handle firmware requests for allocation of physically
+ * contiguous memory regions.
+ *
+ * These request entries should come first in the firmware's resource table,
+ * as other firmware entries might request placing other data objects inside
+ * these memory regions (e.g. data/code segments, trace resource entries, ...).
+ *
+ * Allocating memory this way helps utilizing the reserved physical memory
+ * (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.
+ */
+static int rproc_handle_carveout(struct rproc *rproc,
+ struct fw_rsc_carveout *rsc,
+ int offset, int avail)
+{
+ struct rproc_mem_entry *carveout;
+ struct device *dev = &rproc->dev;
+
+ if (sizeof(*rsc) > avail) {
+ dev_err(dev, "carveout rsc is truncated\n");
+ return -EINVAL;
+ }
+
+ /* make sure reserved bytes are zeroes */
+ if (rsc->reserved) {
+ dev_err(dev, "carveout rsc has non zero reserved bytes\n");
+ return -EINVAL;
+ }
+
+ dev_dbg(dev, "carveout rsc: name: %s, da 0x%x, pa 0x%x, len 0x%x, flags 0x%x\n",
+ rsc->name, rsc->da, rsc->pa, rsc->len, rsc->flags);
+
+ /*
+ * Check carveout rsc already part of a registered carveout,
+ * Search by name, then check the da and length
+ */
+ carveout = rproc_find_carveout_by_name(rproc, rsc->name);
+
+ if (carveout) {
+ if (carveout->rsc_offset != FW_RSC_ADDR_ANY) {
+ dev_err(dev,
+ "Carveout already associated to resource table\n");
+ return -ENOMEM;
+ }
+
+ if (rproc_check_carveout_da(rproc, carveout, rsc->da, rsc->len))
+ return -ENOMEM;
+
+ /* Update memory carveout with resource table info */
+ carveout->rsc_offset = offset;
+ carveout->flags = rsc->flags;
+
+ return 0;
+ }
+
+ /* Register carveout in in list */
+ carveout = rproc_mem_entry_init(dev, 0, 0, rsc->len, rsc->da,
+ rproc_alloc_carveout,
+ rproc_release_carveout, rsc->name);
+ if (!carveout) {
+ dev_err(dev, "Can't allocate memory entry structure\n");
+ return -ENOMEM;
+ }
+
+ carveout->flags = rsc->flags;
+ carveout->rsc_offset = offset;
+ rproc_add_carveout(rproc, carveout);
+
+ return 0;
+}
+
+/**
+ * rproc_add_carveout() - register an allocated carveout region
+ * @rproc: rproc handle
+ * @mem: memory entry to register
+ *
+ * This function registers specified memory entry in @rproc carveouts list.
+ * Specified carveout should have been allocated before registering.
+ */
+void rproc_add_carveout(struct rproc *rproc, struct rproc_mem_entry *mem)
+{
+ list_add_tail(&mem->node, &rproc->carveouts);
+}
+EXPORT_SYMBOL(rproc_add_carveout);
+
+/**
+ * rproc_mem_entry_init() - allocate and initialize rproc_mem_entry struct
+ * @dev: pointer on device struct
+ * @va: virtual address
+ * @dma: dma address
+ * @len: memory carveout length
+ * @da: device address
+ * @release: memory carveout function
+ * @name: carveout name
+ *
+ * This function allocates a rproc_mem_entry struct and fill it with parameters
+ * provided by client.
+ */
+struct rproc_mem_entry *
+rproc_mem_entry_init(struct device *dev,
+ void *va, dma_addr_t dma, int len, u32 da,
+ int (*alloc)(struct rproc *, struct rproc_mem_entry *),
+ int (*release)(struct rproc *, struct rproc_mem_entry *),
+ const char *name, ...)
+{
+ struct rproc_mem_entry *mem;
+ va_list args;
+
+ mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+ if (!mem)
+ return mem;
+
+ mem->va = va;
+ mem->dma = dma;
+ mem->da = da;
+ mem->len = len;
+ mem->alloc = alloc;
+ mem->release = release;
+ mem->rsc_offset = FW_RSC_ADDR_ANY;
+ mem->of_resm_idx = -1;
+
+ va_start(args, name);
+ vsnprintf(mem->name, sizeof(mem->name), name, args);
+ va_end(args);
+
+ return mem;
+}
+EXPORT_SYMBOL(rproc_mem_entry_init);
+
+/**
+ * rproc_of_resm_mem_entry_init() - allocate and initialize rproc_mem_entry struct
+ * from a reserved memory phandle
+ * @dev: pointer on device struct
+ * @of_resm_idx: reserved memory phandle index in "memory-region"
+ * @len: memory carveout length
+ * @da: device address
+ * @name: carveout name
+ *
+ * This function allocates a rproc_mem_entry struct and fill it with parameters
+ * provided by client.
+ */
+struct rproc_mem_entry *
+rproc_of_resm_mem_entry_init(struct device *dev, u32 of_resm_idx, int len,
+ u32 da, const char *name, ...)
+{
+ struct rproc_mem_entry *mem;
+ va_list args;
+
+ mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+ if (!mem)
+ return mem;
+
+ mem->da = da;
+ mem->len = len;
+ mem->rsc_offset = FW_RSC_ADDR_ANY;
+ mem->of_resm_idx = of_resm_idx;
+
+ va_start(args, name);
+ vsnprintf(mem->name, sizeof(mem->name), name, args);
+ va_end(args);
+
+ return mem;
+}
+EXPORT_SYMBOL(rproc_of_resm_mem_entry_init);
+
+/**
* A lookup table for resource handlers. The indices are defined in
* enum fw_resource_type.
*/
@@ -845,6 +1095,70 @@ static void rproc_unprepare_subdevices(struct rproc *rproc)
}
/**
+ * rproc_alloc_registered_carveouts() - allocate all carveouts registered
+ * in the list
+ * @rproc: the remote processor handle
+ *
+ * This function parses registered carveout list, performs allocation
+ * if alloc() ops registered and updates resource table information
+ * if rsc_offset set.
+ *
+ * Return: 0 on success
+ */
+static int rproc_alloc_registered_carveouts(struct rproc *rproc)
+{
+ struct rproc_mem_entry *entry, *tmp;
+ struct fw_rsc_carveout *rsc;
+ struct device *dev = &rproc->dev;
+ int ret;
+
+ list_for_each_entry_safe(entry, tmp, &rproc->carveouts, node) {
+ if (entry->alloc) {
+ ret = entry->alloc(rproc, entry);
+ if (ret) {
+ dev_err(dev, "Unable to allocate carveout %s: %d\n",
+ entry->name, ret);
+ return -ENOMEM;
+ }
+ }
+
+ if (entry->rsc_offset != FW_RSC_ADDR_ANY) {
+ /* update resource table */
+ rsc = (void *)rproc->table_ptr + entry->rsc_offset;
+
+ /*
+ * Some remote processors might need to know the pa
+ * even though they are behind an IOMMU. E.g., OMAP4's
+ * remote M3 processor needs this so it can control
+ * on-chip hardware accelerators that are not behind
+ * the IOMMU, and therefor must know the pa.
+ *
+ * Generally we don't want to expose physical addresses
+ * if we don't have to (remote processors are generally
+ * _not_ trusted), so we might want to do this only for
+ * remote processor that _must_ have this (e.g. OMAP4's
+ * dual M3 subsystem).
+ *
+ * Non-IOMMU processors might also want to have this info.
+ * In this case, the device address and the physical address
+ * are the same.
+ */
+
+ /* Use va if defined else dma to generate pa */
+ if (entry->va)
+ rsc->pa = (u32)rproc_va_to_pa(entry->va);
+ else
+ rsc->pa = (u32)entry->dma;
+
+ rsc->da = entry->da;
+ rsc->len = entry->len;
+ }
+ }
+
+ return 0;
+}
+
+/**
* rproc_coredump_cleanup() - clean up dump_segments list
* @rproc: the remote processor handle
*/
@@ -896,8 +1210,8 @@ static void rproc_resource_cleanup(struct rproc *rproc)
/* clean up carveout allocations */
list_for_each_entry_safe(entry, tmp, &rproc->carveouts, node) {
- dma_free_coherent(dev->parent, entry->len, entry->va,
- entry->dma);
+ if (entry->release)
+ entry->release(rproc, entry);
list_del(&entry->node);
kfree(entry);
}
@@ -1009,6 +1323,9 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
/* reset max_notifyid */
rproc->max_notifyid = -1;
+ /* reset handled vdev */
+ rproc->nb_vdev = 0;
+
/* handle fw resources which are required to boot rproc */
ret = rproc_handle_resources(rproc, rproc_loading_handlers);
if (ret) {
@@ -1016,6 +1333,14 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
goto clean_up_resources;
}
+ /* Allocate carveout resources associated to rproc */
+ ret = rproc_alloc_registered_carveouts(rproc);
+ if (ret) {
+ dev_err(dev, "Failed to allocate associated carveouts: %d\n",
+ ret);
+ goto clean_up_resources;
+ }
+
ret = rproc_start(rproc, fw);
if (ret)
goto clean_up_resources;
@@ -1122,6 +1447,44 @@ int rproc_coredump_add_segment(struct rproc *rproc, dma_addr_t da, size_t size)
EXPORT_SYMBOL(rproc_coredump_add_segment);
/**
+ * rproc_coredump_add_custom_segment() - add custom coredump segment
+ * @rproc: handle of a remote processor
+ * @da: device address
+ * @size: size of segment
+ * @dumpfn: custom dump function called for each segment during coredump
+ * @priv: private data
+ *
+ * Add device memory to the list of segments to be included in the coredump
+ * and associate the segment with the given custom dump function and private
+ * data.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int rproc_coredump_add_custom_segment(struct rproc *rproc,
+ dma_addr_t da, size_t size,
+ void (*dumpfn)(struct rproc *rproc,
+ struct rproc_dump_segment *segment,
+ void *dest),
+ void *priv)
+{
+ struct rproc_dump_segment *segment;
+
+ segment = kzalloc(sizeof(*segment), GFP_KERNEL);
+ if (!segment)
+ return -ENOMEM;
+
+ segment->da = da;
+ segment->size = size;
+ segment->priv = priv;
+ segment->dump = dumpfn;
+
+ list_add_tail(&segment->node, &rproc->dump_segments);
+
+ return 0;
+}
+EXPORT_SYMBOL(rproc_coredump_add_custom_segment);
+
+/**
* rproc_coredump() - perform coredump
* @rproc: rproc handle
*
@@ -1183,14 +1546,18 @@ static void rproc_coredump(struct rproc *rproc)
phdr->p_flags = PF_R | PF_W | PF_X;
phdr->p_align = 0;
- ptr = rproc_da_to_va(rproc, segment->da, segment->size);
- if (!ptr) {
- dev_err(&rproc->dev,
- "invalid coredump segment (%pad, %zu)\n",
- &segment->da, segment->size);
- memset(data + offset, 0xff, segment->size);
+ if (segment->dump) {
+ segment->dump(rproc, segment, data + offset);
} else {
- memcpy(data + offset, ptr, segment->size);
+ ptr = rproc_da_to_va(rproc, segment->da, segment->size);
+ if (!ptr) {
+ dev_err(&rproc->dev,
+ "invalid coredump segment (%pad, %zu)\n",
+ &segment->da, segment->size);
+ memset(data + offset, 0xff, segment->size);
+ } else {
+ memcpy(data + offset, ptr, segment->size);
+ }
}
offset += phdr->p_filesz;
diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c
index a5c29f2764a3..e90135c64af0 100644
--- a/drivers/remoteproc/remoteproc_debugfs.c
+++ b/drivers/remoteproc/remoteproc_debugfs.c
@@ -260,6 +260,7 @@ static int rproc_carveouts_show(struct seq_file *seq, void *p)
list_for_each_entry(carveout, &rproc->carveouts, node) {
seq_puts(seq, "Carveout memory entry:\n");
+ seq_printf(seq, "\tName: %s\n", carveout->name);
seq_printf(seq, "\tVirtual address: %pK\n", carveout->va);
seq_printf(seq, "\tDMA address: %pad\n", &carveout->dma);
seq_printf(seq, "\tDevice address: 0x%x\n", carveout->da);
diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
index 7570beb035b5..f6cad243d7ca 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -60,6 +60,8 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw);
int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw);
struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
const struct firmware *fw);
+struct rproc_mem_entry *
+rproc_find_carveout_by_name(struct rproc *rproc, const char *name, ...);
static inline
int rproc_fw_sanity_check(struct rproc *rproc, const struct firmware *fw)
diff --git a/drivers/remoteproc/remoteproc_sysfs.c b/drivers/remoteproc/remoteproc_sysfs.c
index 47be411400e5..3a4c3d7cafca 100644
--- a/drivers/remoteproc/remoteproc_sysfs.c
+++ b/drivers/remoteproc/remoteproc_sysfs.c
@@ -48,6 +48,11 @@ static ssize_t firmware_store(struct device *dev,
}
len = strcspn(buf, "\n");
+ if (!len) {
+ dev_err(dev, "can't provide a NULL firmware\n");
+ err = -EINVAL;
+ goto out;
+ }
p = kstrndup(buf, len, GFP_KERNEL);
if (!p) {
diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c
index bbecd44df7e8..de21f620b882 100644
--- a/drivers/remoteproc/remoteproc_virtio.c
+++ b/drivers/remoteproc/remoteproc_virtio.c
@@ -76,7 +76,9 @@ static struct virtqueue *rp_find_vq(struct virtio_device *vdev,
struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
struct rproc *rproc = vdev_to_rproc(vdev);
struct device *dev = &rproc->dev;
+ struct rproc_mem_entry *mem;
struct rproc_vring *rvring;
+ struct fw_rsc_vdev *rsc;
struct virtqueue *vq;
void *addr;
int len, size;
@@ -88,8 +90,14 @@ static struct virtqueue *rp_find_vq(struct virtio_device *vdev,
if (!name)
return NULL;
+ /* Search allocated memory region by name */
+ mem = rproc_find_carveout_by_name(rproc, "vdev%dvring%d", rvdev->index,
+ id);
+ if (!mem || !mem->va)
+ return ERR_PTR(-ENOMEM);
+
rvring = &rvdev->vring[id];
- addr = rvring->va;
+ addr = mem->va;
len = rvring->len;
/* zero vring */
@@ -114,6 +122,10 @@ static struct virtqueue *rp_find_vq(struct virtio_device *vdev,
rvring->vq = vq;
vq->priv = rvring;
+ /* Update vring in resource table */
+ rsc = (void *)rproc->table_ptr + rvdev->rsc_offset;
+ rsc->vring[id].da = mem->da;
+
return vq;
}
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 13d28fdbdbb5..c21da9fe51ec 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -98,6 +98,15 @@ config RESET_QCOM_AOSS
reset signals provided by AOSS for Modem, Venus, ADSP,
GPU, Camera, Wireless, Display subsystem. Otherwise, say N.
+config RESET_QCOM_PDC
+ tristate "Qualcomm PDC Reset Driver"
+ depends on ARCH_QCOM || COMPILE_TEST
+ help
+ This enables the PDC (Power Domain Controller) reset driver
+ for Qualcomm Technologies Inc SDM845 SoCs. Say Y if you want
+ to control reset signals provided by PDC for Modem, Compute,
+ Display, GPU, Debug, AOP, Sensors, Audio, SP and APPS.
+
config RESET_SIMPLE
bool "Simple Reset Controller Driver" if COMPILE_TEST
default ARCH_SOCFPGA || ARCH_STM32 || ARCH_STRATIX10 || ARCH_SUNXI || ARCH_ZX || ARCH_ASPEED
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 4243c38228e2..d08e8b90046a 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_RESET_MESON_AUDIO_ARB) += reset-meson-audio-arb.o
obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o
obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o
obj-$(CONFIG_RESET_QCOM_AOSS) += reset-qcom-aoss.o
+obj-$(CONFIG_RESET_QCOM_PDC) += reset-qcom-pdc.o
obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o
obj-$(CONFIG_RESET_STM32MP157) += reset-stm32mp1.o
obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o
diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index 225e34c56b94..d1887c0ed5d3 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -496,28 +496,29 @@ struct reset_control *__of_reset_control_get(struct device_node *node,
break;
}
}
- of_node_put(args.np);
if (!rcdev) {
- mutex_unlock(&reset_list_mutex);
- return ERR_PTR(-EPROBE_DEFER);
+ rstc = ERR_PTR(-EPROBE_DEFER);
+ goto out;
}
if (WARN_ON(args.args_count != rcdev->of_reset_n_cells)) {
- mutex_unlock(&reset_list_mutex);
- return ERR_PTR(-EINVAL);
+ rstc = ERR_PTR(-EINVAL);
+ goto out;
}
rstc_id = rcdev->of_xlate(rcdev, &args);
if (rstc_id < 0) {
- mutex_unlock(&reset_list_mutex);
- return ERR_PTR(rstc_id);
+ rstc = ERR_PTR(rstc_id);
+ goto out;
}
/* reset_list_mutex also protects the rcdev's reset_control list */
rstc = __reset_control_get_internal(rcdev, rstc_id, shared);
+out:
mutex_unlock(&reset_list_mutex);
+ of_node_put(args.np);
return rstc;
}
diff --git a/drivers/reset/reset-imx7.c b/drivers/reset/reset-imx7.c
index 97d9f08271c5..77911fa8f31d 100644
--- a/drivers/reset/reset-imx7.c
+++ b/drivers/reset/reset-imx7.c
@@ -67,6 +67,7 @@ static const struct imx7_src_signal imx7_src_signals[IMX7_RESET_NUM] = {
[IMX7_RESET_PCIEPHY] = { SRC_PCIEPHY_RCR, BIT(2) | BIT(1) },
[IMX7_RESET_PCIEPHY_PERST] = { SRC_PCIEPHY_RCR, BIT(3) },
[IMX7_RESET_PCIE_CTRL_APPS_EN] = { SRC_PCIEPHY_RCR, BIT(6) },
+ [IMX7_RESET_PCIE_CTRL_APPS_TURNOFF] = { SRC_PCIEPHY_RCR, BIT(11) },
[IMX7_RESET_DDRC_PRST] = { SRC_DDRC_RCR, BIT(0) },
[IMX7_RESET_DDRC_CORE_RST] = { SRC_DDRC_RCR, BIT(1) },
};
diff --git a/drivers/reset/reset-qcom-pdc.c b/drivers/reset/reset-qcom-pdc.c
new file mode 100644
index 000000000000..ab74bccd4a5b
--- /dev/null
+++ b/drivers/reset/reset-qcom-pdc.c
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset-controller.h>
+
+#include <dt-bindings/reset/qcom,sdm845-pdc.h>
+
+#define RPMH_PDC_SYNC_RESET 0x100
+
+struct qcom_pdc_reset_map {
+ u8 bit;
+};
+
+struct qcom_pdc_reset_data {
+ struct reset_controller_dev rcdev;
+ struct regmap *regmap;
+};
+
+static const struct regmap_config sdm845_pdc_regmap_config = {
+ .name = "pdc-reset",
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x20000,
+ .fast_io = true,
+};
+
+static const struct qcom_pdc_reset_map sdm845_pdc_resets[] = {
+ [PDC_APPS_SYNC_RESET] = {0},
+ [PDC_SP_SYNC_RESET] = {1},
+ [PDC_AUDIO_SYNC_RESET] = {2},
+ [PDC_SENSORS_SYNC_RESET] = {3},
+ [PDC_AOP_SYNC_RESET] = {4},
+ [PDC_DEBUG_SYNC_RESET] = {5},
+ [PDC_GPU_SYNC_RESET] = {6},
+ [PDC_DISPLAY_SYNC_RESET] = {7},
+ [PDC_COMPUTE_SYNC_RESET] = {8},
+ [PDC_MODEM_SYNC_RESET] = {9},
+};
+
+static inline struct qcom_pdc_reset_data *to_qcom_pdc_reset_data(
+ struct reset_controller_dev *rcdev)
+{
+ return container_of(rcdev, struct qcom_pdc_reset_data, rcdev);
+}
+
+static int qcom_pdc_control_assert(struct reset_controller_dev *rcdev,
+ unsigned long idx)
+{
+ struct qcom_pdc_reset_data *data = to_qcom_pdc_reset_data(rcdev);
+
+ return regmap_update_bits(data->regmap, RPMH_PDC_SYNC_RESET,
+ BIT(sdm845_pdc_resets[idx].bit),
+ BIT(sdm845_pdc_resets[idx].bit));
+}
+
+static int qcom_pdc_control_deassert(struct reset_controller_dev *rcdev,
+ unsigned long idx)
+{
+ struct qcom_pdc_reset_data *data = to_qcom_pdc_reset_data(rcdev);
+
+ return regmap_update_bits(data->regmap, RPMH_PDC_SYNC_RESET,
+ BIT(sdm845_pdc_resets[idx].bit), 0);
+}
+
+static const struct reset_control_ops qcom_pdc_reset_ops = {
+ .assert = qcom_pdc_control_assert,
+ .deassert = qcom_pdc_control_deassert,
+};
+
+static int qcom_pdc_reset_probe(struct platform_device *pdev)
+{
+ struct qcom_pdc_reset_data *data;
+ struct device *dev = &pdev->dev;
+ void __iomem *base;
+ struct resource *res;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ data->regmap = devm_regmap_init_mmio(dev, base,
+ &sdm845_pdc_regmap_config);
+ if (IS_ERR(data->regmap)) {
+ dev_err(dev, "Unable to initialize regmap\n");
+ return PTR_ERR(data->regmap);
+ }
+
+ data->rcdev.owner = THIS_MODULE;
+ data->rcdev.ops = &qcom_pdc_reset_ops;
+ data->rcdev.nr_resets = ARRAY_SIZE(sdm845_pdc_resets);
+ data->rcdev.of_node = dev->of_node;
+
+ return devm_reset_controller_register(dev, &data->rcdev);
+}
+
+static const struct of_device_id qcom_pdc_reset_of_match[] = {
+ { .compatible = "qcom,sdm845-pdc-global" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, qcom_pdc_reset_of_match);
+
+static struct platform_driver qcom_pdc_reset_driver = {
+ .probe = qcom_pdc_reset_probe,
+ .driver = {
+ .name = "qcom_pdc_reset",
+ .of_match_table = qcom_pdc_reset_of_match,
+ },
+};
+module_platform_driver(qcom_pdc_reset_driver);
+
+MODULE_DESCRIPTION("Qualcomm PDC Reset Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
index e2ce4e638258..f46c787733e8 100644
--- a/drivers/rpmsg/qcom_glink_native.c
+++ b/drivers/rpmsg/qcom_glink_native.c
@@ -792,9 +792,6 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
return -EAGAIN;
}
- if (WARN(chunk_size % 4, "Incoming data must be word aligned\n"))
- return -EINVAL;
-
rcid = le16_to_cpu(hdr.msg.param1);
spin_lock_irqsave(&glink->idr_lock, flags);
channel = idr_find(&glink->rcids, rcid);
diff --git a/drivers/rpmsg/qcom_glink_smem.c b/drivers/rpmsg/qcom_glink_smem.c
index 2b5cf2790954..64a5ce324c7f 100644
--- a/drivers/rpmsg/qcom_glink_smem.c
+++ b/drivers/rpmsg/qcom_glink_smem.c
@@ -89,15 +89,11 @@ static void glink_smem_rx_peak(struct qcom_glink_pipe *np,
tail -= pipe->native.length;
len = min_t(size_t, count, pipe->native.length - tail);
- if (len) {
- __ioread32_copy(data, pipe->fifo + tail,
- len / sizeof(u32));
- }
+ if (len)
+ memcpy_fromio(data, pipe->fifo + tail, len);
- if (len != count) {
- __ioread32_copy(data + len, pipe->fifo,
- (count - len) / sizeof(u32));
- }
+ if (len != count)
+ memcpy_fromio(data + len, pipe->fifo, (count - len));
}
static void glink_smem_rx_advance(struct qcom_glink_pipe *np,
@@ -205,7 +201,7 @@ struct qcom_glink *qcom_glink_smem_register(struct device *parent,
dev->parent = parent;
dev->of_node = node;
dev->release = qcom_glink_smem_release;
- dev_set_name(dev, "%s:%s", node->parent->name, node->name);
+ dev_set_name(dev, "%pOFn:%pOFn", node->parent, node);
ret = device_register(dev);
if (ret) {
pr_err("failed to register glink edge\n");
diff --git a/drivers/rpmsg/qcom_smd.c b/drivers/rpmsg/qcom_smd.c
index 8da83a4ebadc..4abbeea782fa 100644
--- a/drivers/rpmsg/qcom_smd.c
+++ b/drivers/rpmsg/qcom_smd.c
@@ -1122,8 +1122,10 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed
channel->edge = edge;
channel->name = kstrdup(name, GFP_KERNEL);
- if (!channel->name)
- return ERR_PTR(-ENOMEM);
+ if (!channel->name) {
+ ret = -ENOMEM;
+ goto free_channel;
+ }
spin_lock_init(&channel->tx_lock);
spin_lock_init(&channel->recv_lock);
@@ -1173,6 +1175,7 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed
free_name_and_channel:
kfree(channel->name);
+free_channel:
kfree(channel);
return ERR_PTR(ret);
@@ -1454,7 +1457,7 @@ struct qcom_smd_edge *qcom_smd_register_edge(struct device *parent,
edge->dev.release = qcom_smd_edge_release;
edge->dev.of_node = node;
edge->dev.groups = qcom_smd_edge_groups;
- dev_set_name(&edge->dev, "%s:%s", dev_name(parent), node->name);
+ dev_set_name(&edge->dev, "%s:%pOFn", dev_name(parent), node);
ret = device_register(&edge->dev);
if (ret) {
pr_err("failed to register smd edge\n");
diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
index a76b963a7e50..eea5ebbb5119 100644
--- a/drivers/rpmsg/rpmsg_char.c
+++ b/drivers/rpmsg/rpmsg_char.c
@@ -167,9 +167,9 @@ static int rpmsg_eptdev_release(struct inode *inode, struct file *filp)
return 0;
}
-static ssize_t rpmsg_eptdev_read(struct file *filp, char __user *buf,
- size_t len, loff_t *f_pos)
+static ssize_t rpmsg_eptdev_read_iter(struct kiocb *iocb, struct iov_iter *to)
{
+ struct file *filp = iocb->ki_filp;
struct rpmsg_eptdev *eptdev = filp->private_data;
unsigned long flags;
struct sk_buff *skb;
@@ -205,8 +205,8 @@ static ssize_t rpmsg_eptdev_read(struct file *filp, char __user *buf,
if (!skb)
return -EFAULT;
- use = min_t(size_t, len, skb->len);
- if (copy_to_user(buf, skb->data, use))
+ use = min_t(size_t, iov_iter_count(to), skb->len);
+ if (copy_to_iter(skb->data, use, to) != use)
use = -EFAULT;
kfree_skb(skb);
@@ -214,16 +214,21 @@ static ssize_t rpmsg_eptdev_read(struct file *filp, char __user *buf,
return use;
}
-static ssize_t rpmsg_eptdev_write(struct file *filp, const char __user *buf,
- size_t len, loff_t *f_pos)
+static ssize_t rpmsg_eptdev_write_iter(struct kiocb *iocb,
+ struct iov_iter *from)
{
+ struct file *filp = iocb->ki_filp;
struct rpmsg_eptdev *eptdev = filp->private_data;
+ size_t len = iov_iter_count(from);
void *kbuf;
int ret;
- kbuf = memdup_user(buf, len);
- if (IS_ERR(kbuf))
- return PTR_ERR(kbuf);
+ kbuf = kzalloc(len, GFP_KERNEL);
+ if (!kbuf)
+ return -ENOMEM;
+
+ if (!copy_from_iter_full(kbuf, len, from))
+ return -EFAULT;
if (mutex_lock_interruptible(&eptdev->ept_lock)) {
ret = -ERESTARTSYS;
@@ -281,8 +286,8 @@ static const struct file_operations rpmsg_eptdev_fops = {
.owner = THIS_MODULE,
.open = rpmsg_eptdev_open,
.release = rpmsg_eptdev_release,
- .read = rpmsg_eptdev_read,
- .write = rpmsg_eptdev_write,
+ .read_iter = rpmsg_eptdev_read_iter,
+ .write_iter = rpmsg_eptdev_write_iter,
.poll = rpmsg_eptdev_poll,
.unlocked_ioctl = rpmsg_eptdev_ioctl,
.compat_ioctl = rpmsg_eptdev_ioctl,
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 7d7be60a2413..a819ef07b7ec 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -187,6 +187,7 @@ config RTC_DRV_ABB5ZES3
config RTC_DRV_ABX80X
tristate "Abracon ABx80x"
+ select WATCHDOG_CORE if WATCHDOG
help
If you say yes here you get support for Abracon AB080X and AB180X
families of ultra-low-power battery- and capacitor-backed real-time
@@ -1007,17 +1008,6 @@ config RTC_DRV_DS17885
endchoice
-config RTC_DS1685_PROC_REGS
- bool "Display register values in /proc"
- depends on RTC_DRV_DS1685_FAMILY && PROC_FS
- help
- Enable this to display a readout of all of the RTC registers in
- /proc/drivers/rtc. Keep in mind that this can potentially lead
- to lost interrupts, as reading Control Register C will clear
- all pending IRQ flags.
-
- Unless you are debugging this driver, choose N.
-
config RTC_DRV_DS1742
tristate "Maxim/Dallas DS1742/1743"
depends on HAS_IOMEM
@@ -1587,7 +1577,7 @@ config RTC_DRV_MPC5121
config RTC_DRV_JZ4740
tristate "Ingenic JZ4740 SoC"
- depends on MACH_INGENIC || COMPILE_TEST
+ depends on MIPS || COMPILE_TEST
help
If you say yes here you get support for the Ingenic JZ47xx SoCs RTC
controllers.
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 5ff2fc0c361a..290c1730fb0a 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -36,9 +36,9 @@ obj-$(CONFIG_RTC_DRV_ASM9260) += rtc-asm9260.o
obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o
obj-$(CONFIG_RTC_DRV_AU1XXX) += rtc-au1xxx.o
-obj-$(CONFIG_RTC_DRV_BRCMSTB) += rtc-brcmstb-waketimer.o
obj-$(CONFIG_RTC_DRV_BQ32K) += rtc-bq32k.o
obj-$(CONFIG_RTC_DRV_BQ4802) += rtc-bq4802.o
+obj-$(CONFIG_RTC_DRV_BRCMSTB) += rtc-brcmstb-waketimer.o
obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o
obj-$(CONFIG_RTC_DRV_COH901331) += rtc-coh901331.o
obj-$(CONFIG_RTC_DRV_CPCAP) += rtc-cpcap.o
@@ -71,6 +71,7 @@ obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o
obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o
obj-$(CONFIG_RTC_DRV_FTRTC010) += rtc-ftrtc010.o
obj-$(CONFIG_RTC_DRV_GENERIC) += rtc-generic.o
+obj-$(CONFIG_RTC_DRV_GOLDFISH) += rtc-goldfish.o
obj-$(CONFIG_RTC_DRV_HID_SENSOR_TIME) += rtc-hid-sensor-time.o
obj-$(CONFIG_RTC_DRV_HYM8563) += rtc-hym8563.o
obj-$(CONFIG_RTC_DRV_IMXDI) += rtc-imxdi.o
@@ -78,10 +79,10 @@ obj-$(CONFIG_RTC_DRV_ISL12022) += rtc-isl12022.o
obj-$(CONFIG_RTC_DRV_ISL12026) += rtc-isl12026.o
obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
obj-$(CONFIG_RTC_DRV_JZ4740) += rtc-jz4740.o
+obj-$(CONFIG_RTC_DRV_LOONGSON1) += rtc-ls1x.o
obj-$(CONFIG_RTC_DRV_LP8788) += rtc-lp8788.o
obj-$(CONFIG_RTC_DRV_LPC24XX) += rtc-lpc24xx.o
obj-$(CONFIG_RTC_DRV_LPC32XX) += rtc-lpc32xx.o
-obj-$(CONFIG_RTC_DRV_LOONGSON1) += rtc-ls1x.o
obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o
obj-$(CONFIG_RTC_DRV_M41T93) += rtc-m41t93.o
obj-$(CONFIG_RTC_DRV_M41T94) += rtc-m41t94.o
@@ -100,7 +101,6 @@ obj-$(CONFIG_RTC_DRV_MC13XXX) += rtc-mc13xxx.o
obj-$(CONFIG_RTC_DRV_MCP795) += rtc-mcp795.o
obj-$(CONFIG_RTC_DRV_MOXART) += rtc-moxart.o
obj-$(CONFIG_RTC_DRV_MPC5121) += rtc-mpc5121.o
-obj-$(CONFIG_RTC_DRV_VRTC) += rtc-mrst.o
obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o
obj-$(CONFIG_RTC_DRV_MT6397) += rtc-mt6397.o
obj-$(CONFIG_RTC_DRV_MT7622) += rtc-mt7622.o
@@ -116,8 +116,8 @@ obj-$(CONFIG_RTC_DRV_PCF2123) += rtc-pcf2123.o
obj-$(CONFIG_RTC_DRV_PCF2127) += rtc-pcf2127.o
obj-$(CONFIG_RTC_DRV_PCF50633) += rtc-pcf50633.o
obj-$(CONFIG_RTC_DRV_PCF85063) += rtc-pcf85063.o
-obj-$(CONFIG_RTC_DRV_PCF85363) += rtc-pcf85363.o
obj-$(CONFIG_RTC_DRV_PCF8523) += rtc-pcf8523.o
+obj-$(CONFIG_RTC_DRV_PCF85363) += rtc-pcf85363.o
obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o
obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o
obj-$(CONFIG_RTC_DRV_PIC32) += rtc-pic32.o
@@ -154,9 +154,9 @@ obj-$(CONFIG_RTC_DRV_SNVS) += rtc-snvs.o
obj-$(CONFIG_RTC_DRV_SPEAR) += rtc-spear.o
obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o
obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o
+obj-$(CONFIG_RTC_DRV_ST_LPC) += rtc-st-lpc.o
obj-$(CONFIG_RTC_DRV_STM32) += rtc-stm32.o
obj-$(CONFIG_RTC_DRV_STMP) += rtc-stmp3xxx.o
-obj-$(CONFIG_RTC_DRV_ST_LPC) += rtc-st-lpc.o
obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o
obj-$(CONFIG_RTC_DRV_SUN6I) += rtc-sun6i.o
obj-$(CONFIG_RTC_DRV_SUNXI) += rtc-sunxi.o
@@ -169,10 +169,10 @@ obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl.o
obj-$(CONFIG_RTC_DRV_TX4939) += rtc-tx4939.o
obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o
obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o
+obj-$(CONFIG_RTC_DRV_VRTC) += rtc-mrst.o
obj-$(CONFIG_RTC_DRV_VT8500) += rtc-vt8500.o
obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o
obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o
obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o
obj-$(CONFIG_RTC_DRV_XGENE) += rtc-xgene.o
obj-$(CONFIG_RTC_DRV_ZYNQMP) += rtc-zynqmp.o
-obj-$(CONFIG_RTC_DRV_GOLDFISH) += rtc-goldfish.o
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index 0fca4d74c76b..3b43787f154b 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -286,9 +286,10 @@ static void rtc_device_get_offset(struct rtc_device *rtc)
*
* Returns the pointer to the new struct class device.
*/
-struct rtc_device *rtc_device_register(const char *name, struct device *dev,
- const struct rtc_class_ops *ops,
- struct module *owner)
+static struct rtc_device *rtc_device_register(const char *name,
+ struct device *dev,
+ const struct rtc_class_ops *ops,
+ struct module *owner)
{
struct rtc_device *rtc;
struct rtc_wkalrm alrm;
@@ -351,15 +352,13 @@ exit:
name, err);
return ERR_PTR(err);
}
-EXPORT_SYMBOL_GPL(rtc_device_register);
-
/**
* rtc_device_unregister - removes the previously registered RTC class device
*
* @rtc: the RTC class device to destroy
*/
-void rtc_device_unregister(struct rtc_device *rtc)
+static void rtc_device_unregister(struct rtc_device *rtc)
{
mutex_lock(&rtc->ops_lock);
/*
@@ -372,7 +371,6 @@ void rtc_device_unregister(struct rtc_device *rtc)
mutex_unlock(&rtc->ops_lock);
put_device(&rtc->dev);
}
-EXPORT_SYMBOL_GPL(rtc_device_unregister);
static void devm_rtc_device_release(struct device *dev, void *res)
{
diff --git a/drivers/rtc/hctosys.c b/drivers/rtc/hctosys.c
index e79f2a181ad2..b9ec4a16db1f 100644
--- a/drivers/rtc/hctosys.c
+++ b/drivers/rtc/hctosys.c
@@ -50,8 +50,10 @@ static int __init rtc_hctosys(void)
tv64.tv_sec = rtc_tm_to_time64(&tm);
#if BITS_PER_LONG == 32
- if (tv64.tv_sec > INT_MAX)
+ if (tv64.tv_sec > INT_MAX) {
+ err = -ERANGE;
goto err_read;
+ }
#endif
err = do_settimeofday64(&tv64);
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index 3d577e259e91..612a83d3ddcc 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -596,7 +596,6 @@ EXPORT_SYMBOL_GPL(rtc_update_irq_enable);
* This function is called when an AIE, UIE or PIE mode interrupt
* has occurred (or been emulated).
*
- * Triggers the registered irq_task function callback.
*/
void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode)
{
@@ -741,7 +740,6 @@ static int rtc_update_hrtimer(struct rtc_device *rtc, int enabled)
/**
* rtc_irq_set_state - enable/disable 2^N Hz periodic IRQs
* @rtc: the rtc device
- * @task: currently registered with rtc_irq_register()
* @enabled: true to enable periodic IRQs
* Context: any
*
@@ -764,7 +762,6 @@ int rtc_irq_set_state(struct rtc_device *rtc, int enabled)
/**
* rtc_irq_set_freq - set 2^N Hz periodic IRQ frequency for IRQ
* @rtc: the rtc device
- * @task: currently registered with rtc_irq_register()
* @freq: positive frequency
* Context: any
*
diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c
index e28f4401fd35..1f0cbd51ba06 100644
--- a/drivers/rtc/rtc-ab8500.c
+++ b/drivers/rtc/rtc-ab8500.c
@@ -46,7 +46,6 @@
#define RTC_STATUS_DATA 0x01
#define COUNTS_PER_SEC (0xF000 / 60)
-#define AB8500_RTC_EPOCH 2000
static const u8 ab8500_rtc_time_regs[] = {
AB8500_RTC_WATCH_TMIN_HI_REG, AB8500_RTC_WATCH_TMIN_MID_REG,
@@ -59,23 +58,6 @@ static const u8 ab8500_rtc_alarm_regs[] = {
AB8500_RTC_ALRM_MIN_LOW_REG
};
-/* Calculate the seconds from 1970 to 01-01-2000 00:00:00 */
-static unsigned long get_elapsed_seconds(int year)
-{
- unsigned long secs;
- struct rtc_time tm = {
- .tm_year = year - 1900,
- .tm_mday = 1,
- };
-
- /*
- * This function calculates secs from 1970 and not from
- * 1900, even if we supply the offset from year 1900.
- */
- rtc_tm_to_time(&tm, &secs);
- return secs;
-}
-
static int ab8500_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
unsigned long timeout = jiffies + HZ;
@@ -118,9 +100,6 @@ static int ab8500_rtc_read_time(struct device *dev, struct rtc_time *tm)
secs = secs / COUNTS_PER_SEC;
secs = secs + (mins * 60);
- /* Add back the initially subtracted number of seconds */
- secs += get_elapsed_seconds(AB8500_RTC_EPOCH);
-
rtc_time_to_tm(secs, tm);
return 0;
}
@@ -131,21 +110,8 @@ static int ab8500_rtc_set_time(struct device *dev, struct rtc_time *tm)
unsigned char buf[ARRAY_SIZE(ab8500_rtc_time_regs)];
unsigned long no_secs, no_mins, secs = 0;
- if (tm->tm_year < (AB8500_RTC_EPOCH - 1900)) {
- dev_dbg(dev, "year should be equal to or greater than %d\n",
- AB8500_RTC_EPOCH);
- return -EINVAL;
- }
-
- /* Get the number of seconds since 1970 */
rtc_tm_to_time(tm, &secs);
- /*
- * Convert it to the number of seconds since 01-01-2000 00:00:00, since
- * we only have a small counter in the RTC.
- */
- secs -= get_elapsed_seconds(AB8500_RTC_EPOCH);
-
no_mins = secs / 60;
no_secs = secs % 60;
@@ -202,12 +168,9 @@ static int ab8500_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
mins = (buf[0] << 16) | (buf[1] << 8) | (buf[2]);
secs = mins * 60;
- /* Add back the initially subtracted number of seconds */
- secs += get_elapsed_seconds(AB8500_RTC_EPOCH);
-
rtc_time_to_tm(secs, &alarm->time);
- return rtc_valid_tm(&alarm->time);
+ return 0;
}
static int ab8500_rtc_irq_enable(struct device *dev, unsigned int enabled)
@@ -224,12 +187,6 @@ static int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
unsigned long mins, secs = 0, cursec = 0;
struct rtc_time curtm;
- if (alarm->time.tm_year < (AB8500_RTC_EPOCH - 1900)) {
- dev_dbg(dev, "year should be equal to or greater than %d\n",
- AB8500_RTC_EPOCH);
- return -EINVAL;
- }
-
/* Get the number of seconds since 1970 */
rtc_tm_to_time(&alarm->time, &secs);
@@ -245,12 +202,6 @@ static int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
return -EINVAL;
}
- /*
- * Convert it to the number of seconds since 01-01-2000 00:00:00, since
- * we only have a small counter in the RTC.
- */
- secs -= get_elapsed_seconds(AB8500_RTC_EPOCH);
-
mins = secs / 60;
buf[2] = mins & 0xFF;
@@ -360,15 +311,14 @@ static DEVICE_ATTR(rtc_calibration, S_IRUGO | S_IWUSR,
ab8500_sysfs_show_rtc_calibration,
ab8500_sysfs_store_rtc_calibration);
-static int ab8500_sysfs_rtc_register(struct device *dev)
-{
- return device_create_file(dev, &dev_attr_rtc_calibration);
-}
+static struct attribute *ab8500_rtc_attrs[] = {
+ &dev_attr_rtc_calibration.attr,
+ NULL
+};
-static void ab8500_sysfs_rtc_unregister(struct device *dev)
-{
- device_remove_file(dev, &dev_attr_rtc_calibration);
-}
+static const struct attribute_group ab8500_rtc_sysfs_files = {
+ .attrs = ab8500_rtc_attrs,
+};
static irqreturn_t rtc_alarm_handler(int irq, void *data)
{
@@ -429,14 +379,11 @@ static int ab8500_rtc_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, true);
- rtc = devm_rtc_device_register(&pdev->dev, "ab8500-rtc",
- (struct rtc_class_ops *)platid->driver_data,
- THIS_MODULE);
- if (IS_ERR(rtc)) {
- dev_err(&pdev->dev, "Registration failed\n");
- err = PTR_ERR(rtc);
- return err;
- }
+ rtc = devm_rtc_allocate_device(&pdev->dev);
+ if (IS_ERR(rtc))
+ return PTR_ERR(rtc);
+
+ rtc->ops = (struct rtc_class_ops *)platid->driver_data;
err = devm_request_threaded_irq(&pdev->dev, irq, NULL,
rtc_alarm_handler, IRQF_ONESHOT,
@@ -447,22 +394,23 @@ static int ab8500_rtc_probe(struct platform_device *pdev)
dev_pm_set_wake_irq(&pdev->dev, irq);
platform_set_drvdata(pdev, rtc);
- err = ab8500_sysfs_rtc_register(&pdev->dev);
- if (err) {
- dev_err(&pdev->dev, "sysfs RTC failed to register\n");
- return err;
- }
-
rtc->uie_unsupported = 1;
- return 0;
+ rtc->range_max = (1ULL << 24) * 60 - 1; // 24-bit minutes + 59 secs
+ rtc->start_secs = RTC_TIMESTAMP_BEGIN_2000;
+ rtc->set_start_time = true;
+
+ err = rtc_add_group(rtc, &ab8500_rtc_sysfs_files);
+ if (err)
+ return err;
+
+ return rtc_register_device(rtc);
}
static int ab8500_rtc_remove(struct platform_device *pdev)
{
dev_pm_clear_wake_irq(&pdev->dev);
device_init_wakeup(&pdev->dev, false);
- ab8500_sysfs_rtc_unregister(&pdev->dev);
return 0;
}
diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c
index 2cefa67a1132..d8e94edcb0ba 100644
--- a/drivers/rtc/rtc-abx80x.c
+++ b/drivers/rtc/rtc-abx80x.c
@@ -17,6 +17,7 @@
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/rtc.h>
+#include <linux/watchdog.h>
#define ABX8XX_REG_HTH 0x00
#define ABX8XX_REG_SC 0x01
@@ -37,6 +38,7 @@
#define ABX8XX_REG_STATUS 0x0f
#define ABX8XX_STATUS_AF BIT(2)
+#define ABX8XX_STATUS_WDT BIT(6)
#define ABX8XX_REG_CTRL1 0x10
#define ABX8XX_CTRL_WRITE BIT(0)
@@ -61,6 +63,14 @@
#define ABX8XX_OSS_OF BIT(1)
#define ABX8XX_OSS_OMODE BIT(4)
+#define ABX8XX_REG_WDT 0x1b
+#define ABX8XX_WDT_WDS BIT(7)
+#define ABX8XX_WDT_BMB_MASK 0x7c
+#define ABX8XX_WDT_BMB_SHIFT 2
+#define ABX8XX_WDT_MAX_TIME (ABX8XX_WDT_BMB_MASK >> ABX8XX_WDT_BMB_SHIFT)
+#define ABX8XX_WDT_WRB_MASK 0x03
+#define ABX8XX_WDT_WRB_1HZ 0x02
+
#define ABX8XX_REG_CFG_KEY 0x1f
#define ABX8XX_CFG_KEY_OSC 0xa1
#define ABX8XX_CFG_KEY_MISC 0x9d
@@ -80,20 +90,27 @@ enum abx80x_chip {AB0801, AB0803, AB0804, AB0805,
struct abx80x_cap {
u16 pn;
bool has_tc;
+ bool has_wdog;
};
static struct abx80x_cap abx80x_caps[] = {
[AB0801] = {.pn = 0x0801},
[AB0803] = {.pn = 0x0803},
- [AB0804] = {.pn = 0x0804, .has_tc = true},
- [AB0805] = {.pn = 0x0805, .has_tc = true},
+ [AB0804] = {.pn = 0x0804, .has_tc = true, .has_wdog = true},
+ [AB0805] = {.pn = 0x0805, .has_tc = true, .has_wdog = true},
[AB1801] = {.pn = 0x1801},
[AB1803] = {.pn = 0x1803},
- [AB1804] = {.pn = 0x1804, .has_tc = true},
- [AB1805] = {.pn = 0x1805, .has_tc = true},
+ [AB1804] = {.pn = 0x1804, .has_tc = true, .has_wdog = true},
+ [AB1805] = {.pn = 0x1805, .has_tc = true, .has_wdog = true},
[ABX80X] = {.pn = 0}
};
+struct abx80x_priv {
+ struct rtc_device *rtc;
+ struct i2c_client *client;
+ struct watchdog_device wdog;
+};
+
static int abx80x_is_rc_mode(struct i2c_client *client)
{
int flags = 0;
@@ -218,7 +235,8 @@ static int abx80x_rtc_set_time(struct device *dev, struct rtc_time *tm)
static irqreturn_t abx80x_handle_irq(int irq, void *dev_id)
{
struct i2c_client *client = dev_id;
- struct rtc_device *rtc = i2c_get_clientdata(client);
+ struct abx80x_priv *priv = i2c_get_clientdata(client);
+ struct rtc_device *rtc = priv->rtc;
int status;
status = i2c_smbus_read_byte_data(client, ABX8XX_REG_STATUS);
@@ -228,6 +246,13 @@ static irqreturn_t abx80x_handle_irq(int irq, void *dev_id)
if (status & ABX8XX_STATUS_AF)
rtc_update_irq(rtc, 1, RTC_AF | RTC_IRQF);
+ /*
+ * It is unclear if we'll get an interrupt before the external
+ * reset kicks in.
+ */
+ if (status & ABX8XX_STATUS_WDT)
+ dev_alert(&client->dev, "watchdog timeout interrupt.\n");
+
i2c_smbus_write_byte_data(client, ABX8XX_REG_STATUS, 0);
return IRQ_HANDLED;
@@ -529,11 +554,94 @@ static void rtc_calib_remove_sysfs_group(void *_dev)
sysfs_remove_group(&dev->kobj, &rtc_calib_attr_group);
}
+#ifdef CONFIG_WATCHDOG
+
+static inline u8 timeout_bits(unsigned int timeout)
+{
+ return ((timeout << ABX8XX_WDT_BMB_SHIFT) & ABX8XX_WDT_BMB_MASK) |
+ ABX8XX_WDT_WRB_1HZ;
+}
+
+static int __abx80x_wdog_set_timeout(struct watchdog_device *wdog,
+ unsigned int timeout)
+{
+ struct abx80x_priv *priv = watchdog_get_drvdata(wdog);
+ u8 val = ABX8XX_WDT_WDS | timeout_bits(timeout);
+
+ /*
+ * Writing any timeout to the WDT register resets the watchdog timer.
+ * Writing 0 disables it.
+ */
+ return i2c_smbus_write_byte_data(priv->client, ABX8XX_REG_WDT, val);
+}
+
+static int abx80x_wdog_set_timeout(struct watchdog_device *wdog,
+ unsigned int new_timeout)
+{
+ int err = 0;
+
+ if (watchdog_hw_running(wdog))
+ err = __abx80x_wdog_set_timeout(wdog, new_timeout);
+
+ if (err == 0)
+ wdog->timeout = new_timeout;
+
+ return err;
+}
+
+static int abx80x_wdog_ping(struct watchdog_device *wdog)
+{
+ return __abx80x_wdog_set_timeout(wdog, wdog->timeout);
+}
+
+static int abx80x_wdog_start(struct watchdog_device *wdog)
+{
+ return __abx80x_wdog_set_timeout(wdog, wdog->timeout);
+}
+
+static int abx80x_wdog_stop(struct watchdog_device *wdog)
+{
+ return __abx80x_wdog_set_timeout(wdog, 0);
+}
+
+static const struct watchdog_info abx80x_wdog_info = {
+ .identity = "abx80x watchdog",
+ .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
+};
+
+static const struct watchdog_ops abx80x_wdog_ops = {
+ .owner = THIS_MODULE,
+ .start = abx80x_wdog_start,
+ .stop = abx80x_wdog_stop,
+ .ping = abx80x_wdog_ping,
+ .set_timeout = abx80x_wdog_set_timeout,
+};
+
+static int abx80x_setup_watchdog(struct abx80x_priv *priv)
+{
+ priv->wdog.parent = &priv->client->dev;
+ priv->wdog.ops = &abx80x_wdog_ops;
+ priv->wdog.info = &abx80x_wdog_info;
+ priv->wdog.min_timeout = 1;
+ priv->wdog.max_timeout = ABX8XX_WDT_MAX_TIME;
+ priv->wdog.timeout = ABX8XX_WDT_MAX_TIME;
+
+ watchdog_set_drvdata(&priv->wdog, priv);
+
+ return devm_watchdog_register_device(&priv->client->dev, &priv->wdog);
+}
+#else
+static int abx80x_setup_watchdog(struct abx80x_priv *priv)
+{
+ return 0;
+}
+#endif
+
static int abx80x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device_node *np = client->dev.of_node;
- struct rtc_device *rtc;
+ struct abx80x_priv *priv;
int i, data, err, trickle_cfg = -EINVAL;
char buf[7];
unsigned int part = id->driver_data;
@@ -610,13 +718,24 @@ static int abx80x_probe(struct i2c_client *client,
if (err)
return err;
- rtc = devm_rtc_allocate_device(&client->dev);
- if (IS_ERR(rtc))
- return PTR_ERR(rtc);
+ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
+ if (priv == NULL)
+ return -ENOMEM;
+
+ priv->rtc = devm_rtc_allocate_device(&client->dev);
+ if (IS_ERR(priv->rtc))
+ return PTR_ERR(priv->rtc);
+
+ priv->rtc->ops = &abx80x_rtc_ops;
+ priv->client = client;
- rtc->ops = &abx80x_rtc_ops;
+ i2c_set_clientdata(client, priv);
- i2c_set_clientdata(client, rtc);
+ if (abx80x_caps[part].has_wdog) {
+ err = abx80x_setup_watchdog(priv);
+ if (err)
+ return err;
+ }
if (client->irq > 0) {
dev_info(&client->dev, "IRQ %d supplied\n", client->irq);
@@ -649,7 +768,7 @@ static int abx80x_probe(struct i2c_client *client,
return err;
}
- err = rtc_register_device(rtc);
+ err = rtc_register_device(priv->rtc);
return err;
}
diff --git a/drivers/rtc/rtc-armada38x.c b/drivers/rtc/rtc-armada38x.c
index bde53c8ccee2..9e78f004670b 100644
--- a/drivers/rtc/rtc-armada38x.c
+++ b/drivers/rtc/rtc-armada38x.c
@@ -224,7 +224,7 @@ static int armada38x_rtc_read_time(struct device *dev, struct rtc_time *tm)
time = rtc->data->read_rtc_reg(rtc, RTC_TIME);
spin_unlock_irqrestore(&rtc->lock, flags);
- rtc_time_to_tm(time, tm);
+ rtc_time64_to_tm(time, tm);
return 0;
}
@@ -249,13 +249,9 @@ static void armada38x_rtc_reset(struct armada38x_rtc *rtc)
static int armada38x_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct armada38x_rtc *rtc = dev_get_drvdata(dev);
- int ret = 0;
unsigned long time, flags;
- ret = rtc_tm_to_time(tm, &time);
-
- if (ret)
- goto out;
+ time = rtc_tm_to_time64(tm);
if (!rtc->initialized)
armada38x_rtc_reset(rtc);
@@ -264,8 +260,7 @@ static int armada38x_rtc_set_time(struct device *dev, struct rtc_time *tm)
rtc_delayed_write(time, rtc, RTC_TIME);
spin_unlock_irqrestore(&rtc->lock, flags);
-out:
- return ret;
+ return 0;
}
static int armada38x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
@@ -284,7 +279,7 @@ static int armada38x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
spin_unlock_irqrestore(&rtc->lock, flags);
alrm->enabled = val ? 1 : 0;
- rtc_time_to_tm(time, &alrm->time);
+ rtc_time64_to_tm(time, &alrm->time);
return 0;
}
@@ -295,12 +290,8 @@ static int armada38x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
u32 reg = ALARM_REG(RTC_ALARM1, rtc->data->alarm);
u32 reg_irq = ALARM_REG(RTC_IRQ1_CONF, rtc->data->alarm);
unsigned long time, flags;
- int ret = 0;
- ret = rtc_tm_to_time(&alrm->time, &time);
-
- if (ret)
- goto out;
+ time = rtc_tm_to_time64(&alrm->time);
spin_lock_irqsave(&rtc->lock, flags);
@@ -313,8 +304,7 @@ static int armada38x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
spin_unlock_irqrestore(&rtc->lock, flags);
-out:
- return ret;
+ return 0;
}
static int armada38x_rtc_alarm_irq_enable(struct device *dev,
@@ -514,7 +504,6 @@ MODULE_DEVICE_TABLE(of, armada38x_rtc_of_match_table);
static __init int armada38x_rtc_probe(struct platform_device *pdev)
{
- const struct rtc_class_ops *ops;
struct resource *res;
struct armada38x_rtc *rtc;
const struct of_device_id *match;
@@ -551,6 +540,11 @@ static __init int armada38x_rtc_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "no irq\n");
return rtc->irq;
}
+
+ rtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev);
+ if (IS_ERR(rtc->rtc_dev))
+ return PTR_ERR(rtc->rtc_dev);
+
if (devm_request_irq(&pdev->dev, rtc->irq, armada38x_rtc_alarm_irq,
0, pdev->name, rtc) < 0) {
dev_warn(&pdev->dev, "Interrupt not available.\n");
@@ -560,28 +554,26 @@ static __init int armada38x_rtc_probe(struct platform_device *pdev)
if (rtc->irq != -1) {
device_init_wakeup(&pdev->dev, 1);
- ops = &armada38x_rtc_ops;
+ rtc->rtc_dev->ops = &armada38x_rtc_ops;
} else {
/*
* If there is no interrupt available then we can't
* use the alarm
*/
- ops = &armada38x_rtc_ops_noirq;
+ rtc->rtc_dev->ops = &armada38x_rtc_ops_noirq;
}
rtc->data = (struct armada38x_rtc_data *)match->data;
-
/* Update RTC-MBUS bridge timing parameters */
rtc->data->update_mbus_timing(rtc);
- rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, pdev->name,
- ops, THIS_MODULE);
- if (IS_ERR(rtc->rtc_dev)) {
- ret = PTR_ERR(rtc->rtc_dev);
+ rtc->rtc_dev->range_max = U32_MAX;
+
+ ret = rtc_register_device(rtc->rtc_dev);
+ if (ret)
dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
- return ret;
- }
- return 0;
+
+ return ret;
}
#ifdef CONFIG_PM_SLEEP
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index cd3a2411bc2f..a5a19ff10535 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -50,6 +50,7 @@
/* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */
#include <linux/mc146818rtc.h>
+#ifdef CONFIG_ACPI
/*
* Use ACPI SCI to replace HPET interrupt for RTC Alarm event
*
@@ -61,6 +62,18 @@
static bool use_acpi_alarm;
module_param(use_acpi_alarm, bool, 0444);
+static inline int cmos_use_acpi_alarm(void)
+{
+ return use_acpi_alarm;
+}
+#else /* !CONFIG_ACPI */
+
+static inline int cmos_use_acpi_alarm(void)
+{
+ return 0;
+}
+#endif
+
struct cmos_rtc {
struct rtc_device *rtc;
struct device *dev;
@@ -167,9 +180,9 @@ static inline int hpet_unregister_irq_handler(irq_handler_t handler)
#endif
/* Don't use HPET for RTC Alarm event if ACPI Fixed event is used */
-static int use_hpet_alarm(void)
+static inline int use_hpet_alarm(void)
{
- return is_hpet_enabled() && !use_acpi_alarm;
+ return is_hpet_enabled() && !cmos_use_acpi_alarm();
}
/*----------------------------------------------------------------*/
@@ -244,6 +257,7 @@ static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t)
struct cmos_rtc *cmos = dev_get_drvdata(dev);
unsigned char rtc_control;
+ /* This not only a rtc_op, but also called directly */
if (!is_valid_irq(cmos->irq))
return -EIO;
@@ -340,7 +354,7 @@ static void cmos_irq_enable(struct cmos_rtc *cmos, unsigned char mask)
if (use_hpet_alarm())
hpet_set_rtc_irq_bit(mask);
- if ((mask & RTC_AIE) && use_acpi_alarm) {
+ if ((mask & RTC_AIE) && cmos_use_acpi_alarm()) {
if (cmos->wake_on)
cmos->wake_on(cmos->dev);
}
@@ -358,7 +372,7 @@ static void cmos_irq_disable(struct cmos_rtc *cmos, unsigned char mask)
if (use_hpet_alarm())
hpet_mask_rtc_irq_bit(mask);
- if ((mask & RTC_AIE) && use_acpi_alarm) {
+ if ((mask & RTC_AIE) && cmos_use_acpi_alarm()) {
if (cmos->wake_off)
cmos->wake_off(cmos->dev);
}
@@ -439,6 +453,7 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
unsigned char mon, mday, hrs, min, sec, rtc_control;
int ret;
+ /* This not only a rtc_op, but also called directly */
if (!is_valid_irq(cmos->irq))
return -EIO;
@@ -503,9 +518,6 @@ static int cmos_alarm_irq_enable(struct device *dev, unsigned int enabled)
struct cmos_rtc *cmos = dev_get_drvdata(dev);
unsigned long flags;
- if (!is_valid_irq(cmos->irq))
- return -EINVAL;
-
spin_lock_irqsave(&rtc_lock, flags);
if (enabled)
@@ -566,6 +578,12 @@ static const struct rtc_class_ops cmos_rtc_ops = {
.alarm_irq_enable = cmos_alarm_irq_enable,
};
+static const struct rtc_class_ops cmos_rtc_ops_no_alarm = {
+ .read_time = cmos_read_time,
+ .set_time = cmos_set_time,
+ .proc = cmos_procfs,
+};
+
/*----------------------------------------------------------------*/
/*
@@ -842,9 +860,12 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
dev_dbg(dev, "IRQ %d is already in use\n", rtc_irq);
goto cleanup1;
}
+
+ cmos_rtc.rtc->ops = &cmos_rtc_ops;
+ } else {
+ cmos_rtc.rtc->ops = &cmos_rtc_ops_no_alarm;
}
- cmos_rtc.rtc->ops = &cmos_rtc_ops;
cmos_rtc.rtc->nvram_old_abi = true;
retval = rtc_register_device(cmos_rtc.rtc);
if (retval)
@@ -980,7 +1001,7 @@ static int cmos_suspend(struct device *dev)
}
spin_unlock_irq(&rtc_lock);
- if ((tmp & RTC_AIE) && !use_acpi_alarm) {
+ if ((tmp & RTC_AIE) && !cmos_use_acpi_alarm()) {
cmos->enabled_wake = 1;
if (cmos->wake_on)
cmos->wake_on(dev);
@@ -1031,7 +1052,7 @@ static void cmos_check_wkalrm(struct device *dev)
* ACPI RTC wake event is cleared after resume from STR,
* ACK the rtc irq here
*/
- if (t_now >= cmos->alarm_expires && use_acpi_alarm) {
+ if (t_now >= cmos->alarm_expires && cmos_use_acpi_alarm()) {
cmos_interrupt(0, (void *)cmos->rtc);
return;
}
@@ -1053,7 +1074,7 @@ static int __maybe_unused cmos_resume(struct device *dev)
struct cmos_rtc *cmos = dev_get_drvdata(dev);
unsigned char tmp;
- if (cmos->enabled_wake && !use_acpi_alarm) {
+ if (cmos->enabled_wake && !cmos_use_acpi_alarm()) {
if (cmos->wake_off)
cmos->wake_off(dev);
else
@@ -1132,7 +1153,7 @@ static u32 rtc_handler(void *context)
* Or else, ACPI SCI is enabled during suspend/resume only,
* update rtc irq in that case.
*/
- if (use_acpi_alarm)
+ if (cmos_use_acpi_alarm())
cmos_interrupt(0, (void *)cmos->rtc);
else {
/* Fix me: can we use cmos_interrupt() here as well? */
diff --git a/drivers/rtc/rtc-core.h b/drivers/rtc/rtc-core.h
index ccc17a2e293d..0abf98983e13 100644
--- a/drivers/rtc/rtc-core.h
+++ b/drivers/rtc/rtc-core.h
@@ -40,23 +40,9 @@ static inline void rtc_proc_del_device(struct rtc_device *rtc)
#ifdef CONFIG_RTC_INTF_SYSFS
const struct attribute_group **rtc_get_dev_attribute_groups(void);
-int rtc_add_group(struct rtc_device *rtc, const struct attribute_group *grp);
-int rtc_add_groups(struct rtc_device *rtc, const struct attribute_group **grps);
#else
static inline const struct attribute_group **rtc_get_dev_attribute_groups(void)
{
return NULL;
}
-
-static inline
-int rtc_add_group(struct rtc_device *rtc, const struct attribute_group *grp)
-{
- return 0;
-}
-
-static inline
-int rtc_add_groups(struct rtc_device *rtc, const struct attribute_group **grps)
-{
- return 0;
-}
#endif
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index 4b2b4627daeb..74b31dce484f 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -114,6 +114,20 @@ enum ds_type {
# define RX8025_BIT_VDET 0x40
# define RX8025_BIT_XST 0x20
+#define M41TXX_REG_CONTROL 0x07
+# define M41TXX_BIT_OUT BIT(7)
+# define M41TXX_BIT_FT BIT(6)
+# define M41TXX_BIT_CALIB_SIGN BIT(5)
+# define M41TXX_M_CALIBRATION GENMASK(4, 0)
+
+/* negative offset step is -2.034ppm */
+#define M41TXX_NEG_OFFSET_STEP_PPB 2034
+/* positive offset step is +4.068ppm */
+#define M41TXX_POS_OFFSET_STEP_PPB 4068
+/* Min and max values supported with 'offset' interface by M41TXX */
+#define M41TXX_MIN_OFFSET ((-31) * M41TXX_NEG_OFFSET_STEP_PPB)
+#define M41TXX_MAX_OFFSET ((31) * M41TXX_POS_OFFSET_STEP_PPB)
+
struct ds1307 {
enum ds_type type;
unsigned long flags;
@@ -146,6 +160,9 @@ struct chip_desc {
static int ds1307_get_time(struct device *dev, struct rtc_time *t);
static int ds1307_set_time(struct device *dev, struct rtc_time *t);
+static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t);
+static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t);
+static int ds1307_alarm_irq_enable(struct device *dev, unsigned int enabled);
static u8 do_trickle_setup_ds1339(struct ds1307 *, u32 ohms, bool diode);
static irqreturn_t rx8130_irq(int irq, void *dev_id);
static int rx8130_read_alarm(struct device *dev, struct rtc_wkalrm *t);
@@ -155,6 +172,8 @@ static irqreturn_t mcp794xx_irq(int irq, void *dev_id);
static int mcp794xx_read_alarm(struct device *dev, struct rtc_wkalrm *t);
static int mcp794xx_set_alarm(struct device *dev, struct rtc_wkalrm *t);
static int mcp794xx_alarm_irq_enable(struct device *dev, unsigned int enabled);
+static int m41txx_rtc_read_offset(struct device *dev, long *offset);
+static int m41txx_rtc_set_offset(struct device *dev, long offset);
static const struct rtc_class_ops rx8130_rtc_ops = {
.read_time = ds1307_get_time,
@@ -172,6 +191,16 @@ static const struct rtc_class_ops mcp794xx_rtc_ops = {
.alarm_irq_enable = mcp794xx_alarm_irq_enable,
};
+static const struct rtc_class_ops m41txx_rtc_ops = {
+ .read_time = ds1307_get_time,
+ .set_time = ds1307_set_time,
+ .read_alarm = ds1337_read_alarm,
+ .set_alarm = ds1337_set_alarm,
+ .alarm_irq_enable = ds1307_alarm_irq_enable,
+ .read_offset = m41txx_rtc_read_offset,
+ .set_offset = m41txx_rtc_set_offset,
+};
+
static const struct chip_desc chips[last_ds_type] = {
[ds_1307] = {
.nvram_offset = 8,
@@ -228,10 +257,17 @@ static const struct chip_desc chips[last_ds_type] = {
.irq_handler = rx8130_irq,
.rtc_ops = &rx8130_rtc_ops,
},
+ [m41t0] = {
+ .rtc_ops = &m41txx_rtc_ops,
+ },
+ [m41t00] = {
+ .rtc_ops = &m41txx_rtc_ops,
+ },
[m41t11] = {
/* this is battery backed SRAM */
.nvram_offset = 8,
.nvram_size = 56,
+ .rtc_ops = &m41txx_rtc_ops,
},
[mcp794xx] = {
.alarm = 1,
@@ -973,6 +1009,110 @@ static int mcp794xx_alarm_irq_enable(struct device *dev, unsigned int enabled)
enabled ? MCP794XX_BIT_ALM0_EN : 0);
}
+static int m41txx_rtc_read_offset(struct device *dev, long *offset)
+{
+ struct ds1307 *ds1307 = dev_get_drvdata(dev);
+ unsigned int ctrl_reg;
+ u8 val;
+
+ regmap_read(ds1307->regmap, M41TXX_REG_CONTROL, &ctrl_reg);
+
+ val = ctrl_reg & M41TXX_M_CALIBRATION;
+
+ /* check if positive */
+ if (ctrl_reg & M41TXX_BIT_CALIB_SIGN)
+ *offset = (val * M41TXX_POS_OFFSET_STEP_PPB);
+ else
+ *offset = -(val * M41TXX_NEG_OFFSET_STEP_PPB);
+
+ return 0;
+}
+
+static int m41txx_rtc_set_offset(struct device *dev, long offset)
+{
+ struct ds1307 *ds1307 = dev_get_drvdata(dev);
+ unsigned int ctrl_reg;
+
+ if ((offset < M41TXX_MIN_OFFSET) || (offset > M41TXX_MAX_OFFSET))
+ return -ERANGE;
+
+ if (offset >= 0) {
+ ctrl_reg = DIV_ROUND_CLOSEST(offset,
+ M41TXX_POS_OFFSET_STEP_PPB);
+ ctrl_reg |= M41TXX_BIT_CALIB_SIGN;
+ } else {
+ ctrl_reg = DIV_ROUND_CLOSEST(abs(offset),
+ M41TXX_NEG_OFFSET_STEP_PPB);
+ }
+
+ return regmap_update_bits(ds1307->regmap, M41TXX_REG_CONTROL,
+ M41TXX_M_CALIBRATION | M41TXX_BIT_CALIB_SIGN,
+ ctrl_reg);
+}
+
+static ssize_t frequency_test_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ds1307 *ds1307 = dev_get_drvdata(dev->parent);
+ bool freq_test_en;
+ int ret;
+
+ ret = kstrtobool(buf, &freq_test_en);
+ if (ret) {
+ dev_err(dev, "Failed to store RTC Frequency Test attribute\n");
+ return ret;
+ }
+
+ regmap_update_bits(ds1307->regmap, M41TXX_REG_CONTROL, M41TXX_BIT_FT,
+ freq_test_en ? M41TXX_BIT_FT : 0);
+
+ return count;
+}
+
+static ssize_t frequency_test_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ds1307 *ds1307 = dev_get_drvdata(dev->parent);
+ unsigned int ctrl_reg;
+
+ regmap_read(ds1307->regmap, M41TXX_REG_CONTROL, &ctrl_reg);
+
+ return scnprintf(buf, PAGE_SIZE, (ctrl_reg & M41TXX_BIT_FT) ? "on\n" :
+ "off\n");
+}
+
+static DEVICE_ATTR_RW(frequency_test);
+
+static struct attribute *rtc_freq_test_attrs[] = {
+ &dev_attr_frequency_test.attr,
+ NULL,
+};
+
+static const struct attribute_group rtc_freq_test_attr_group = {
+ .attrs = rtc_freq_test_attrs,
+};
+
+static int ds1307_add_frequency_test(struct ds1307 *ds1307)
+{
+ int err;
+
+ switch (ds1307->type) {
+ case m41t0:
+ case m41t00:
+ case m41t11:
+ err = rtc_add_group(ds1307->rtc, &rtc_freq_test_attr_group);
+ if (err)
+ return err;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
/*----------------------------------------------------------------------*/
static int ds1307_nvram_read(void *priv, unsigned int offset, void *val,
@@ -1384,7 +1524,6 @@ static void ds1307_clks_register(struct ds1307 *ds1307)
static const struct regmap_config regmap_config = {
.reg_bits = 8,
.val_bits = 8,
- .max_register = 0x9,
};
static int ds1307_probe(struct i2c_client *client,
@@ -1711,6 +1850,10 @@ read_rtc:
}
ds1307->rtc->ops = chip->rtc_ops ?: &ds13xx_rtc_ops;
+ err = ds1307_add_frequency_test(ds1307);
+ if (err)
+ return err;
+
err = rtc_register_device(ds1307->rtc);
if (err)
return err;
diff --git a/drivers/rtc/rtc-ds1685.c b/drivers/rtc/rtc-ds1685.c
index 6f39f683a98c..2710f2594c42 100644
--- a/drivers/rtc/rtc-ds1685.c
+++ b/drivers/rtc/rtc-ds1685.c
@@ -770,33 +770,6 @@ static const char *ds1685_rtc_sqw_freq[16] = {
"512Hz", "256Hz", "128Hz", "64Hz", "32Hz", "16Hz", "8Hz", "4Hz", "2Hz"
};
-#ifdef CONFIG_RTC_DS1685_PROC_REGS
-/**
- * ds1685_rtc_print_regs - helper function to print register values.
- * @hex: hex byte to convert into binary bits.
- * @dest: destination char array.
- *
- * This is basically a hex->binary function, just with extra spacing between
- * the digits. It only works on 1-byte values (8 bits).
- */
-static char*
-ds1685_rtc_print_regs(u8 hex, char *dest)
-{
- u32 i, j;
- char *tmp = dest;
-
- for (i = 0; i < NUM_BITS; i++) {
- *tmp++ = ((hex & 0x80) != 0 ? '1' : '0');
- for (j = 0; j < NUM_SPACES; j++)
- *tmp++ = ' ';
- hex <<= 1;
- }
- *tmp++ = '\0';
-
- return dest;
-}
-#endif
-
/**
* ds1685_rtc_proc - procfs access function.
* @dev: pointer to device structure.
@@ -805,13 +778,9 @@ ds1685_rtc_print_regs(u8 hex, char *dest)
static int
ds1685_rtc_proc(struct device *dev, struct seq_file *seq)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct ds1685_priv *rtc = platform_get_drvdata(pdev);
+ struct ds1685_priv *rtc = dev_get_drvdata(dev);
u8 ctrla, ctrlb, ctrlc, ctrld, ctrl4a, ctrl4b, ssn[8];
char *model;
-#ifdef CONFIG_RTC_DS1685_PROC_REGS
- char bits[NUM_REGS][(NUM_BITS * NUM_SPACES) + NUM_BITS + 1];
-#endif
/* Read all the relevant data from the control registers. */
ds1685_rtc_switch_to_bank1(rtc);
@@ -859,28 +828,7 @@ ds1685_rtc_proc(struct device *dev, struct seq_file *seq)
"Periodic IRQ\t: %s\n"
"Periodic Rate\t: %s\n"
"SQW Freq\t: %s\n"
-#ifdef CONFIG_RTC_DS1685_PROC_REGS
- "Serial #\t: %8phC\n"
- "Register Status\t:\n"
- " Ctrl A\t: UIP DV2 DV1 DV0 RS3 RS2 RS1 RS0\n"
- "\t\t: %s\n"
- " Ctrl B\t: SET PIE AIE UIE SQWE DM 2412 DSE\n"
- "\t\t: %s\n"
- " Ctrl C\t: IRQF PF AF UF --- --- --- ---\n"
- "\t\t: %s\n"
- " Ctrl D\t: VRT --- --- --- --- --- --- ---\n"
- "\t\t: %s\n"
-#if !defined(CONFIG_RTC_DRV_DS1685) && !defined(CONFIG_RTC_DRV_DS1689)
- " Ctrl 4A\t: VRT2 INCR BME --- PAB RF WF KF\n"
-#else
- " Ctrl 4A\t: VRT2 INCR --- --- PAB RF WF KF\n"
-#endif
- "\t\t: %s\n"
- " Ctrl 4B\t: ABE E32k CS RCE PRS RIE WIE KSE\n"
- "\t\t: %s\n",
-#else
"Serial #\t: %8phC\n",
-#endif
model,
((ctrla & RTC_CTRL_A_DV1) ? "enabled" : "disabled"),
((ctrlb & RTC_CTRL_B_2412) ? "24-hour" : "12-hour"),
@@ -894,17 +842,7 @@ ds1685_rtc_proc(struct device *dev, struct seq_file *seq)
ds1685_rtc_pirq_rate[(ctrla & RTC_CTRL_A_RS_MASK)] : "none"),
(!((ctrl4b & RTC_CTRL_4B_E32K)) ?
ds1685_rtc_sqw_freq[(ctrla & RTC_CTRL_A_RS_MASK)] : "32768Hz"),
-#ifdef CONFIG_RTC_DS1685_PROC_REGS
- ssn,
- ds1685_rtc_print_regs(ctrla, bits[0]),
- ds1685_rtc_print_regs(ctrlb, bits[1]),
- ds1685_rtc_print_regs(ctrlc, bits[2]),
- ds1685_rtc_print_regs(ctrld, bits[3]),
- ds1685_rtc_print_regs(ctrl4a, bits[4]),
- ds1685_rtc_print_regs(ctrl4b, bits[5]));
-#else
ssn);
-#endif
return 0;
}
#else
@@ -927,30 +865,13 @@ ds1685_rtc_ops = {
};
/* ----------------------------------------------------------------------- */
-
-/* ----------------------------------------------------------------------- */
-/* SysFS interface */
-
-#ifdef CONFIG_SYSFS
-/**
- * ds1685_rtc_sysfs_nvram_read - reads rtc nvram via sysfs.
- * @file: pointer to file structure.
- * @kobj: pointer to kobject structure.
- * @bin_attr: pointer to bin_attribute structure.
- * @buf: pointer to char array to hold the output.
- * @pos: current file position pointer.
- * @size: size of the data to read.
- */
-static ssize_t
-ds1685_rtc_sysfs_nvram_read(struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr, char *buf,
- loff_t pos, size_t size)
+static int ds1685_nvram_read(void *priv, unsigned int pos, void *val,
+ size_t size)
{
- struct platform_device *pdev =
- to_platform_device(container_of(kobj, struct device, kobj));
- struct ds1685_priv *rtc = platform_get_drvdata(pdev);
+ struct ds1685_priv *rtc = priv;
ssize_t count;
unsigned long flags = 0;
+ u8 *buf = val;
spin_lock_irqsave(&rtc->lock, flags);
ds1685_rtc_switch_to_bank0(rtc);
@@ -1004,33 +925,16 @@ ds1685_rtc_sysfs_nvram_read(struct file *filp, struct kobject *kobj,
#endif /* !CONFIG_RTC_DRV_DS1689 */
spin_unlock_irqrestore(&rtc->lock, flags);
- /*
- * XXX: Bug? this appears to cause the function to get executed
- * several times in succession. But it's the only way to actually get
- * data written out to a file.
- */
- return count;
+ return 0;
}
-/**
- * ds1685_rtc_sysfs_nvram_write - writes rtc nvram via sysfs.
- * @file: pointer to file structure.
- * @kobj: pointer to kobject structure.
- * @bin_attr: pointer to bin_attribute structure.
- * @buf: pointer to char array to hold the input.
- * @pos: current file position pointer.
- * @size: size of the data to write.
- */
-static ssize_t
-ds1685_rtc_sysfs_nvram_write(struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr, char *buf,
- loff_t pos, size_t size)
+static int ds1685_nvram_write(void *priv, unsigned int pos, void *val,
+ size_t size)
{
- struct platform_device *pdev =
- to_platform_device(container_of(kobj, struct device, kobj));
- struct ds1685_priv *rtc = platform_get_drvdata(pdev);
+ struct ds1685_priv *rtc = priv;
ssize_t count;
unsigned long flags = 0;
+ u8 *buf = val;
spin_lock_irqsave(&rtc->lock, flags);
ds1685_rtc_switch_to_bank0(rtc);
@@ -1084,26 +988,11 @@ ds1685_rtc_sysfs_nvram_write(struct file *filp, struct kobject *kobj,
#endif /* !CONFIG_RTC_DRV_DS1689 */
spin_unlock_irqrestore(&rtc->lock, flags);
- return count;
+ return 0;
}
-/**
- * struct ds1685_rtc_sysfs_nvram_attr - sysfs attributes for rtc nvram.
- * @attr: nvram attributes.
- * @read: nvram read function.
- * @write: nvram write function.
- * @size: nvram total size (bank0 + extended).
- */
-static struct bin_attribute
-ds1685_rtc_sysfs_nvram_attr = {
- .attr = {
- .name = "nvram",
- .mode = S_IRUGO | S_IWUSR,
- },
- .read = ds1685_rtc_sysfs_nvram_read,
- .write = ds1685_rtc_sysfs_nvram_write,
- .size = NVRAM_TOTAL_SZ
-};
+/* ----------------------------------------------------------------------- */
+/* SysFS interface */
/**
* ds1685_rtc_sysfs_battery_show - sysfs file for main battery status.
@@ -1188,43 +1077,6 @@ ds1685_rtc_sysfs_misc_grp = {
.attrs = ds1685_rtc_sysfs_misc_attrs,
};
-/**
- * ds1685_rtc_sysfs_register - register sysfs files.
- * @dev: pointer to device structure.
- */
-static int
-ds1685_rtc_sysfs_register(struct device *dev)
-{
- int ret = 0;
-
- sysfs_bin_attr_init(&ds1685_rtc_sysfs_nvram_attr);
- ret = sysfs_create_bin_file(&dev->kobj, &ds1685_rtc_sysfs_nvram_attr);
- if (ret)
- return ret;
-
- ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_misc_grp);
- if (ret)
- return ret;
-
- return 0;
-}
-
-/**
- * ds1685_rtc_sysfs_unregister - unregister sysfs files.
- * @dev: pointer to device structure.
- */
-static int
-ds1685_rtc_sysfs_unregister(struct device *dev)
-{
- sysfs_remove_bin_file(&dev->kobj, &ds1685_rtc_sysfs_nvram_attr);
- sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_misc_grp);
-
- return 0;
-}
-#endif /* CONFIG_SYSFS */
-
-
-
/* ----------------------------------------------------------------------- */
/* Driver Probe/Removal */
@@ -1242,6 +1094,12 @@ ds1685_rtc_probe(struct platform_device *pdev)
u8 ctrla, ctrlb, hours;
unsigned char am_pm;
int ret = 0;
+ struct nvmem_config nvmem_cfg = {
+ .name = "ds1685_nvram",
+ .size = NVRAM_TOTAL_SZ,
+ .reg_read = ds1685_nvram_read,
+ .reg_write = ds1685_nvram_write,
+ };
/* Get the platform data. */
pdata = (struct ds1685_rtc_platform_data *) pdev->dev.platform_data;
@@ -1499,11 +1357,15 @@ ds1685_rtc_probe(struct platform_device *pdev)
/* Setup complete. */
ds1685_rtc_switch_to_bank0(rtc);
-#ifdef CONFIG_SYSFS
- ret = ds1685_rtc_sysfs_register(&pdev->dev);
+ ret = rtc_add_group(rtc_dev, &ds1685_rtc_sysfs_misc_grp);
+ if (ret)
+ return ret;
+
+ rtc_dev->nvram_old_abi = true;
+ nvmem_cfg.priv = rtc;
+ ret = rtc_nvmem_register(rtc_dev, &nvmem_cfg);
if (ret)
return ret;
-#endif
return rtc_register_device(rtc_dev);
}
@@ -1517,10 +1379,6 @@ ds1685_rtc_remove(struct platform_device *pdev)
{
struct ds1685_priv *rtc = platform_get_drvdata(pdev);
-#ifdef CONFIG_SYSFS
- ds1685_rtc_sysfs_unregister(&pdev->dev);
-#endif
-
/* Read Ctrl B and clear PIE/AIE/UIE. */
rtc->write(rtc, RTC_CTRL_B,
(rtc->read(rtc, RTC_CTRL_B) &
diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c
index ea18a8f4bce0..ec5ef518a09b 100644
--- a/drivers/rtc/rtc-isl1208.c
+++ b/drivers/rtc/rtc-isl1208.c
@@ -10,12 +10,11 @@
*
*/
-#include <linux/module.h>
-#include <linux/i2c.h>
#include <linux/bcd.h>
-#include <linux/rtc.h>
-#include "rtc-core.h"
+#include <linux/i2c.h>
+#include <linux/module.h>
#include <linux/of_irq.h>
+#include <linux/rtc.h>
/* Register map */
/* rtc section */
@@ -518,7 +517,7 @@ static ssize_t timestamp0_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = dev_get_drvdata(dev);
+ struct i2c_client *client = to_i2c_client(dev->parent);
int sr;
sr = isl1208_i2c_get_sr(client);
@@ -540,7 +539,7 @@ static ssize_t timestamp0_store(struct device *dev,
static ssize_t timestamp0_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct i2c_client *client = dev_get_drvdata(dev);
+ struct i2c_client *client = to_i2c_client(dev->parent);
u8 regs[ISL1219_EVT_SECTION_LEN] = { 0, };
struct rtc_time tm;
int sr;
@@ -650,7 +649,7 @@ static ssize_t
isl1208_sysfs_show_atrim(struct device *dev,
struct device_attribute *attr, char *buf)
{
- int atr = isl1208_i2c_get_atr(to_i2c_client(dev));
+ int atr = isl1208_i2c_get_atr(to_i2c_client(dev->parent));
if (atr < 0)
return atr;
@@ -663,7 +662,7 @@ static ssize_t
isl1208_sysfs_show_dtrim(struct device *dev,
struct device_attribute *attr, char *buf)
{
- int dtr = isl1208_i2c_get_dtr(to_i2c_client(dev));
+ int dtr = isl1208_i2c_get_dtr(to_i2c_client(dev->parent));
if (dtr < 0)
return dtr;
@@ -676,7 +675,7 @@ static ssize_t
isl1208_sysfs_show_usr(struct device *dev,
struct device_attribute *attr, char *buf)
{
- int usr = isl1208_i2c_get_usr(to_i2c_client(dev));
+ int usr = isl1208_i2c_get_usr(to_i2c_client(dev->parent));
if (usr < 0)
return usr;
@@ -701,7 +700,10 @@ isl1208_sysfs_store_usr(struct device *dev,
if (usr < 0 || usr > 0xffff)
return -EINVAL;
- return isl1208_i2c_set_usr(to_i2c_client(dev), usr) ? -EIO : count;
+ if (isl1208_i2c_set_usr(to_i2c_client(dev->parent), usr))
+ return -EIO;
+
+ return count;
}
static DEVICE_ATTR(usr, S_IRUGO | S_IWUSR, isl1208_sysfs_show_usr,
@@ -765,7 +767,6 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id)
rtc->ops = &isl1208_rtc_ops;
i2c_set_clientdata(client, rtc);
- dev_set_drvdata(&rtc->dev, client);
rc = isl1208_i2c_get_sr(client);
if (rc < 0) {
@@ -804,7 +805,7 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id)
evdet_irq = of_irq_get_byname(np, "evdet");
}
- rc = sysfs_create_group(&client->dev.kobj, &isl1208_rtc_sysfs_files);
+ rc = rtc_add_group(rtc, &isl1208_rtc_sysfs_files);
if (rc)
return rc;
@@ -821,14 +822,6 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id)
return rtc_register_device(rtc);
}
-static int
-isl1208_remove(struct i2c_client *client)
-{
- sysfs_remove_group(&client->dev.kobj, &isl1208_rtc_sysfs_files);
-
- return 0;
-}
-
static const struct i2c_device_id isl1208_id[] = {
{ "isl1208", TYPE_ISL1208 },
{ "isl1218", TYPE_ISL1218 },
@@ -851,7 +844,6 @@ static struct i2c_driver isl1208_driver = {
.of_match_table = of_match_ptr(isl1208_of_match),
},
.probe = isl1208_probe,
- .remove = isl1208_remove,
.id_table = isl1208_id,
};
diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c
index 4a3c0f3aab14..ef160da84220 100644
--- a/drivers/rtc/rtc-lib.c
+++ b/drivers/rtc/rtc-lib.c
@@ -47,7 +47,7 @@ EXPORT_SYMBOL(rtc_year_days);
/*
- * rtc_time_to_tm64 - Converts time64_t to rtc_time.
+ * rtc_time64_to_tm - Converts time64_t to rtc_time.
* Convert seconds since 01-01-1970 00:00:00 to Gregorian date.
*/
void rtc_time64_to_tm(time64_t time, struct rtc_time *tm)
diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c
index ad03e2f12f5d..a3fb235fea0d 100644
--- a/drivers/rtc/rtc-m41t80.c
+++ b/drivers/rtc/rtc-m41t80.c
@@ -745,7 +745,7 @@ static int wdt_ioctl(struct file *file, unsigned int cmd,
return -EINVAL;
wdt_margin = new_margin;
wdt_ping();
- /* Fall */
+ /* Fall through */
case WDIOC_GETTIMEOUT:
return put_user(wdt_margin, (int __user *)arg);
diff --git a/drivers/rtc/rtc-mrst.c b/drivers/rtc/rtc-mrst.c
index 1925aaf09093..daf354a6a853 100644
--- a/drivers/rtc/rtc-mrst.c
+++ b/drivers/rtc/rtc-mrst.c
@@ -90,7 +90,7 @@ static int mrst_read_time(struct device *dev, struct rtc_time *time)
unsigned long flags;
if (vrtc_is_updating())
- mdelay(20);
+ msleep(20);
spin_lock_irqsave(&rtc_lock, flags);
time->tm_sec = vrtc_cmos_read(RTC_SECONDS);
@@ -261,11 +261,10 @@ static int mrst_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
static int mrst_procfs(struct device *dev, struct seq_file *seq)
{
- unsigned char rtc_control, valid;
+ unsigned char rtc_control;
spin_lock_irq(&rtc_lock);
rtc_control = vrtc_cmos_read(RTC_CONTROL);
- valid = vrtc_cmos_read(RTC_VALID);
spin_unlock_irq(&rtc_lock);
seq_printf(seq,
diff --git a/drivers/rtc/rtc-mt6397.c b/drivers/rtc/rtc-mt6397.c
index 385f8303bb41..e9a25ec4d434 100644
--- a/drivers/rtc/rtc-mt6397.c
+++ b/drivers/rtc/rtc-mt6397.c
@@ -332,6 +332,10 @@ static int mtk_rtc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, rtc);
+ rtc->rtc_dev = devm_rtc_allocate_device(rtc->dev);
+ if (IS_ERR(rtc->rtc_dev))
+ return PTR_ERR(rtc->rtc_dev);
+
ret = request_threaded_irq(rtc->irq, NULL,
mtk_rtc_irq_handler_thread,
IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
@@ -344,11 +348,11 @@ static int mtk_rtc_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 1);
- rtc->rtc_dev = rtc_device_register("mt6397-rtc", &pdev->dev,
- &mtk_rtc_ops, THIS_MODULE);
- if (IS_ERR(rtc->rtc_dev)) {
+ rtc->rtc_dev->ops = &mtk_rtc_ops;
+
+ ret = rtc_register_device(rtc->rtc_dev);
+ if (ret) {
dev_err(&pdev->dev, "register rtc device failed\n");
- ret = PTR_ERR(rtc->rtc_dev);
goto out_free_irq;
}
@@ -365,7 +369,6 @@ static int mtk_rtc_remove(struct platform_device *pdev)
{
struct mt6397_rtc *rtc = platform_get_drvdata(pdev);
- rtc_device_unregister(rtc->rtc_dev);
free_irq(rtc->irq, rtc->rtc_dev);
irq_dispose_mapping(rtc->irq);
diff --git a/drivers/rtc/rtc-mv.c b/drivers/rtc/rtc-mv.c
index 4b198b3778d3..e7f14bd12fe3 100644
--- a/drivers/rtc/rtc-mv.c
+++ b/drivers/rtc/rtc-mv.c
@@ -125,13 +125,9 @@ static int mv_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
/* hw counts from year 2000, but tm_year is relative to 1900 */
alm->time.tm_year = bcd2bin(year) + 100;
- if (rtc_valid_tm(&alm->time) < 0) {
- dev_err(dev, "retrieved alarm date/time is not valid.\n");
- rtc_time_to_tm(0, &alm->time);
- }
-
alm->enabled = !!readl(ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS);
- return 0;
+
+ return rtc_valid_tm(&alm->time);
}
static int mv_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c
index 323ff55cc165..320b4a520eb3 100644
--- a/drivers/rtc/rtc-omap.c
+++ b/drivers/rtc/rtc-omap.c
@@ -421,12 +421,6 @@ static struct omap_rtc *omap_rtc_power_off_rtc;
* The RTC can be used to control an external PMIC via the pmic_power_en pin,
* which can be configured to transition to OFF on ALARM2 events.
*
- * Notes:
- * The two-second alarm offset is the shortest offset possible as the alarm
- * registers must be set before the next timer update and the offset
- * calculation is too heavy for everything to be done within a single access
- * period (~15 us).
- *
* Called with local interrupts disabled.
*/
static void omap_rtc_power_off(void)
@@ -434,6 +428,7 @@ static void omap_rtc_power_off(void)
struct omap_rtc *rtc = omap_rtc_power_off_rtc;
struct rtc_time tm;
unsigned long now;
+ int seconds;
u32 val;
rtc->type->unlock(rtc);
@@ -441,11 +436,13 @@ static void omap_rtc_power_off(void)
val = rtc_readl(rtc, OMAP_RTC_PMIC_REG);
rtc_writel(rtc, OMAP_RTC_PMIC_REG, val | OMAP_RTC_PMIC_POWER_EN_EN);
- /* set alarm two seconds from now */
+again:
+ /* set alarm one second from now */
omap_rtc_read_time_raw(rtc, &tm);
+ seconds = tm.tm_sec;
bcd2tm(&tm);
rtc_tm_to_time(&tm, &now);
- rtc_time_to_tm(now + 2, &tm);
+ rtc_time_to_tm(now + 1, &tm);
if (tm2bcd(&tm) < 0) {
dev_err(&rtc->rtc->dev, "power off failed\n");
@@ -470,14 +467,22 @@ static void omap_rtc_power_off(void)
val = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG);
rtc_writel(rtc, OMAP_RTC_INTERRUPTS_REG,
val | OMAP_RTC_INTERRUPTS_IT_ALARM2);
+
+ /* Retry in case roll over happened before alarm was armed. */
+ if (rtc_read(rtc, OMAP_RTC_SECONDS_REG) != seconds) {
+ val = rtc_read(rtc, OMAP_RTC_STATUS_REG);
+ if (!(val & OMAP_RTC_STATUS_ALARM2))
+ goto again;
+ }
+
rtc->type->lock(rtc);
/*
- * Wait for alarm to trigger (within two seconds) and external PMIC to
+ * Wait for alarm to trigger (within one second) and external PMIC to
* power off the system. Add a 500 ms margin for external latencies
* (e.g. debounce circuits).
*/
- mdelay(2500);
+ mdelay(1500);
}
static const struct rtc_class_ops omap_rtc_ops = {
@@ -721,8 +726,7 @@ static int omap_rtc_probe(struct platform_device *pdev)
if (of_id) {
rtc->type = of_id->data;
rtc->is_pmic_controller = rtc->type->has_pmic_mode &&
- of_property_read_bool(pdev->dev.of_node,
- "system-power-controller");
+ of_device_is_system_power_controller(pdev->dev.of_node);
} else {
id_entry = platform_get_device_id(pdev);
rtc->type = (void *)id_entry->driver_data;
diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c
index 9f99a0966550..7cb786d76e3c 100644
--- a/drivers/rtc/rtc-pcf2127.c
+++ b/drivers/rtc/rtc-pcf2127.c
@@ -303,6 +303,9 @@ static int pcf2127_i2c_gather_write(void *context,
memcpy(buf + 1, val, val_size);
ret = i2c_master_send(client, buf, val_size + 1);
+
+ kfree(buf);
+
if (ret != val_size + 1)
return ret < 0 ? ret : -EIO;
diff --git a/drivers/rtc/rtc-pl030.c b/drivers/rtc/rtc-pl030.c
index f85a1a93e669..343bb6ed1783 100644
--- a/drivers/rtc/rtc-pl030.c
+++ b/drivers/rtc/rtc-pl030.c
@@ -112,6 +112,13 @@ static int pl030_probe(struct amba_device *dev, const struct amba_id *id)
goto err_rtc;
}
+ rtc->rtc = devm_rtc_allocate_device(&dev->dev);
+ if (IS_ERR(rtc->rtc)) {
+ ret = PTR_ERR(rtc->rtc);
+ goto err_rtc;
+ }
+
+ rtc->rtc->ops = &pl030_ops;
rtc->base = ioremap(dev->res.start, resource_size(&dev->res));
if (!rtc->base) {
ret = -ENOMEM;
@@ -128,12 +135,9 @@ static int pl030_probe(struct amba_device *dev, const struct amba_id *id)
if (ret)
goto err_irq;
- rtc->rtc = rtc_device_register("pl030", &dev->dev, &pl030_ops,
- THIS_MODULE);
- if (IS_ERR(rtc->rtc)) {
- ret = PTR_ERR(rtc->rtc);
+ ret = rtc_register_device(rtc->rtc);
+ if (ret)
goto err_reg;
- }
return 0;
@@ -154,7 +158,6 @@ static int pl030_remove(struct amba_device *dev)
writel(0, rtc->base + RTC_CR);
free_irq(dev->irq[0], rtc);
- rtc_device_unregister(rtc->rtc);
iounmap(rtc->base);
amba_release_regions(dev);
diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c
index 82eb7da2c478..30943d200c5e 100644
--- a/drivers/rtc/rtc-pl031.c
+++ b/drivers/rtc/rtc-pl031.c
@@ -310,7 +310,6 @@ static int pl031_remove(struct amba_device *adev)
device_init_wakeup(&adev->dev, false);
if (adev->irq[0])
free_irq(adev->irq[0], ldata);
- rtc_device_unregister(ldata->rtc);
amba_release_regions(adev);
return 0;
@@ -383,24 +382,25 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)
}
device_init_wakeup(&adev->dev, true);
- ldata->rtc = rtc_device_register("pl031", &adev->dev, ops,
- THIS_MODULE);
- if (IS_ERR(ldata->rtc)) {
- ret = PTR_ERR(ldata->rtc);
+ ldata->rtc = devm_rtc_allocate_device(&adev->dev);
+ if (IS_ERR(ldata->rtc))
+ return PTR_ERR(ldata->rtc);
+
+ ldata->rtc->ops = ops;
+
+ ret = rtc_register_device(ldata->rtc);
+ if (ret)
goto out;
- }
if (adev->irq[0]) {
ret = request_irq(adev->irq[0], pl031_interrupt,
vendor->irqflags, "rtc-pl031", ldata);
if (ret)
- goto out_no_irq;
+ goto out;
dev_pm_set_wake_irq(&adev->dev, adev->irq[0]);
}
return 0;
-out_no_irq:
- rtc_device_unregister(ldata->rtc);
out:
amba_release_regions(adev);
err_req:
diff --git a/drivers/rtc/rtc-rs5c348.c b/drivers/rtc/rtc-rs5c348.c
index f2de8b17e7e3..6582be707bd0 100644
--- a/drivers/rtc/rtc-rs5c348.c
+++ b/drivers/rtc/rtc-rs5c348.c
@@ -66,6 +66,17 @@ rs5c348_rtc_set_time(struct device *dev, struct rtc_time *tm)
u8 txbuf[5+7], *txp;
int ret;
+ ret = spi_w8r8(spi, RS5C348_CMD_R(RS5C348_REG_CTL2));
+ if (ret < 0)
+ return ret;
+ if (ret & RS5C348_BIT_XSTP) {
+ txbuf[0] = RS5C348_CMD_W(RS5C348_REG_CTL2);
+ txbuf[1] = 0;
+ ret = spi_write_then_read(spi, txbuf, 2, NULL, 0);
+ if (ret < 0)
+ return ret;
+ }
+
/* Transfer 5 bytes before writing SEC. This gives 31us for carry. */
txp = txbuf;
txbuf[0] = RS5C348_CMD_R(RS5C348_REG_CTL2); /* cmd, ctl2 */
@@ -102,6 +113,16 @@ rs5c348_rtc_read_time(struct device *dev, struct rtc_time *tm)
u8 txbuf[5], rxbuf[7];
int ret;
+ ret = spi_w8r8(spi, RS5C348_CMD_R(RS5C348_REG_CTL2));
+ if (ret < 0)
+ return ret;
+ if (ret & RS5C348_BIT_VDET)
+ dev_warn(&spi->dev, "voltage-low detected.\n");
+ if (ret & RS5C348_BIT_XSTP) {
+ dev_warn(&spi->dev, "oscillator-stop detected.\n");
+ return -EINVAL;
+ }
+
/* Transfer 5 byte befores reading SEC. This gives 31us for carry. */
txbuf[0] = RS5C348_CMD_R(RS5C348_REG_CTL2); /* cmd, ctl2 */
txbuf[1] = 0; /* dummy */
@@ -143,8 +164,6 @@ static const struct rtc_class_ops rs5c348_rtc_ops = {
.set_time = rs5c348_rtc_set_time,
};
-static struct spi_driver rs5c348_driver;
-
static int rs5c348_probe(struct spi_device *spi)
{
int ret;
@@ -161,53 +180,27 @@ static int rs5c348_probe(struct spi_device *spi)
ret = spi_w8r8(spi, RS5C348_CMD_R(RS5C348_REG_SECS));
if (ret < 0 || (ret & 0x80)) {
dev_err(&spi->dev, "not found.\n");
- goto kfree_exit;
+ return ret;
}
dev_info(&spi->dev, "spiclk %u KHz.\n",
(spi->max_speed_hz + 500) / 1000);
- /* turn RTC on if it was not on */
- ret = spi_w8r8(spi, RS5C348_CMD_R(RS5C348_REG_CTL2));
- if (ret < 0)
- goto kfree_exit;
- if (ret & (RS5C348_BIT_XSTP | RS5C348_BIT_VDET)) {
- u8 buf[2];
- struct rtc_time tm;
- if (ret & RS5C348_BIT_VDET)
- dev_warn(&spi->dev, "voltage-low detected.\n");
- if (ret & RS5C348_BIT_XSTP)
- dev_warn(&spi->dev, "oscillator-stop detected.\n");
- rtc_time_to_tm(0, &tm); /* 1970/1/1 */
- ret = rs5c348_rtc_set_time(&spi->dev, &tm);
- if (ret < 0)
- goto kfree_exit;
- buf[0] = RS5C348_CMD_W(RS5C348_REG_CTL2);
- buf[1] = 0;
- ret = spi_write_then_read(spi, buf, sizeof(buf), NULL, 0);
- if (ret < 0)
- goto kfree_exit;
- }
-
ret = spi_w8r8(spi, RS5C348_CMD_R(RS5C348_REG_CTL1));
if (ret < 0)
- goto kfree_exit;
+ return ret;
if (ret & RS5C348_BIT_24H)
pdata->rtc_24h = 1;
- rtc = devm_rtc_device_register(&spi->dev, rs5c348_driver.driver.name,
- &rs5c348_rtc_ops, THIS_MODULE);
-
- if (IS_ERR(rtc)) {
- ret = PTR_ERR(rtc);
- goto kfree_exit;
- }
+ rtc = devm_rtc_allocate_device(&spi->dev);
+ if (IS_ERR(rtc))
+ return PTR_ERR(rtc);
pdata->rtc = rtc;
- return 0;
- kfree_exit:
- return ret;
+ rtc->ops = &rs5c348_rtc_ops;
+
+ return rtc_register_device(rtc);
}
static struct spi_driver rs5c348_driver = {
diff --git a/drivers/rtc/rtc-rv8803.c b/drivers/rtc/rtc-rv8803.c
index 29fc3d210392..450a0b831a2d 100644
--- a/drivers/rtc/rtc-rv8803.c
+++ b/drivers/rtc/rtc-rv8803.c
@@ -615,6 +615,7 @@ static int rv8803_probe(struct i2c_client *client,
static const struct i2c_device_id rv8803_id[] = {
{ "rv8803", rv_8803 },
+ { "rx8803", rv_8803 },
{ "rx8900", rx_8900 },
{ }
};
@@ -623,7 +624,11 @@ MODULE_DEVICE_TABLE(i2c, rv8803_id);
static const struct of_device_id rv8803_of_match[] = {
{
.compatible = "microcrystal,rv8803",
- .data = (void *)rx_8900
+ .data = (void *)rv_8803
+ },
+ {
+ .compatible = "epson,rx8803",
+ .data = (void *)rv_8803
},
{
.compatible = "epson,rx8900",
diff --git a/drivers/rtc/rtc-s35390a.c b/drivers/rtc/rtc-s35390a.c
index 77feb603cd4c..3c64dbb08109 100644
--- a/drivers/rtc/rtc-s35390a.c
+++ b/drivers/rtc/rtc-s35390a.c
@@ -108,7 +108,7 @@ static int s35390a_get_reg(struct s35390a *s35390a, int reg, char *buf, int len)
static int s35390a_init(struct s35390a *s35390a)
{
- char buf;
+ u8 buf;
int ret;
unsigned initcount = 0;
diff --git a/drivers/rtc/rtc-sc27xx.c b/drivers/rtc/rtc-sc27xx.c
index deea5c3726ad..b4eb3b3c6c2c 100644
--- a/drivers/rtc/rtc-sc27xx.c
+++ b/drivers/rtc/rtc-sc27xx.c
@@ -129,19 +129,6 @@ static int sprd_rtc_clear_alarm_ints(struct sprd_rtc *rtc)
SPRD_RTC_ALM_INT_MASK);
}
-static int sprd_rtc_disable_ints(struct sprd_rtc *rtc)
-{
- int ret;
-
- ret = regmap_update_bits(rtc->regmap, rtc->base + SPRD_RTC_INT_EN,
- SPRD_RTC_INT_MASK, 0);
- if (ret)
- return ret;
-
- return regmap_write(rtc->regmap, rtc->base + SPRD_RTC_INT_CLR,
- SPRD_RTC_INT_MASK);
-}
-
static int sprd_rtc_lock_alarm(struct sprd_rtc *rtc, bool lock)
{
int ret;
@@ -172,7 +159,8 @@ static int sprd_rtc_lock_alarm(struct sprd_rtc *rtc, bool lock)
return ret;
}
- return 0;
+ return regmap_write(rtc->regmap, rtc->base + SPRD_RTC_INT_CLR,
+ SPRD_RTC_SPG_UPD_EN);
}
static int sprd_rtc_get_secs(struct sprd_rtc *rtc, enum sprd_rtc_reg_types type,
@@ -427,10 +415,14 @@ static int sprd_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
u32 val;
/*
- * If aie_timer is enabled, we should get the normal alarm time.
+ * Before RTC device is registered, it will check to see if there is an
+ * alarm already set in RTC hardware, and we always read the normal
+ * alarm at this time.
+ *
+ * Or if aie_timer is enabled, we should get the normal alarm time.
* Otherwise we should get auxiliary alarm time.
*/
- if (rtc->rtc && rtc->rtc->aie_timer.enabled == 0)
+ if (rtc->rtc && rtc->rtc->registered && rtc->rtc->aie_timer.enabled == 0)
return sprd_rtc_read_aux_alarm(dev, alrm);
ret = sprd_rtc_get_secs(rtc, SPRD_RTC_ALARM, &secs);
@@ -575,6 +567,32 @@ static int sprd_rtc_check_power_down(struct sprd_rtc *rtc)
return 0;
}
+static int sprd_rtc_check_alarm_int(struct sprd_rtc *rtc)
+{
+ u32 val;
+ int ret;
+
+ ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_SPG_VALUE, &val);
+ if (ret)
+ return ret;
+
+ /*
+ * The SPRD_RTC_INT_EN register is not put in always-power-on region
+ * supplied by VDDRTC, so we should check if we need enable the alarm
+ * interrupt when system booting.
+ *
+ * If we have set SPRD_RTC_POWEROFF_ALM_FLAG which is saved in
+ * always-power-on region, that means we have set one alarm last time,
+ * so we should enable the alarm interrupt to help RTC core to see if
+ * there is an alarm already set in RTC hardware.
+ */
+ if (!(val & SPRD_RTC_POWEROFF_ALM_FLAG))
+ return 0;
+
+ return regmap_update_bits(rtc->regmap, rtc->base + SPRD_RTC_INT_EN,
+ SPRD_RTC_ALARM_EN, SPRD_RTC_ALARM_EN);
+}
+
static int sprd_rtc_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
@@ -608,10 +626,10 @@ static int sprd_rtc_probe(struct platform_device *pdev)
rtc->dev = &pdev->dev;
platform_set_drvdata(pdev, rtc);
- /* clear all RTC interrupts and disable all RTC interrupts */
- ret = sprd_rtc_disable_ints(rtc);
+ /* check if we need set the alarm interrupt */
+ ret = sprd_rtc_check_alarm_int(rtc);
if (ret) {
- dev_err(&pdev->dev, "failed to disable RTC interrupts\n");
+ dev_err(&pdev->dev, "failed to check RTC alarm interrupt\n");
return ret;
}
@@ -631,16 +649,18 @@ static int sprd_rtc_probe(struct platform_device *pdev)
return ret;
}
+ device_init_wakeup(&pdev->dev, 1);
+
rtc->rtc->ops = &sprd_rtc_ops;
rtc->rtc->range_min = 0;
rtc->rtc->range_max = 5662310399LL;
ret = rtc_register_device(rtc->rtc);
if (ret) {
dev_err(&pdev->dev, "failed to register rtc device\n");
+ device_init_wakeup(&pdev->dev, 0);
return ret;
}
- device_init_wakeup(&pdev->dev, 1);
return 0;
}
diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c
index 2cd5a7b1a2e3..fe07310952df 100644
--- a/drivers/rtc/rtc-sun6i.c
+++ b/drivers/rtc/rtc-sun6i.c
@@ -199,8 +199,7 @@ static void __init sun6i_rtc_clk_init(struct device_node *node)
if (!rtc)
return;
- clk_data = kzalloc(sizeof(*clk_data) + (sizeof(*clk_data->hws) * 2),
- GFP_KERNEL);
+ clk_data = kzalloc(struct_size(clk_data, hws, 2), GFP_KERNEL);
if (!clk_data) {
kfree(rtc);
return;
diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c
index f1ff30ade534..9746c32eee2e 100644
--- a/drivers/rtc/rtc-sysfs.c
+++ b/drivers/rtc/rtc-sysfs.c
@@ -338,8 +338,8 @@ int rtc_add_groups(struct rtc_device *rtc, const struct attribute_group **grps)
new_cnt = old_cnt + add_cnt + 1;
groups = devm_kcalloc(&rtc->dev, new_cnt, sizeof(*groups), GFP_KERNEL);
- if (IS_ERR_OR_NULL(groups))
- return PTR_ERR(groups);
+ if (!groups)
+ return -ENOMEM;
memcpy(groups, rtc->dev.groups, old_cnt * sizeof(*groups));
memcpy(groups + old_cnt, grps, add_cnt * sizeof(*groups));
groups[old_cnt + add_cnt] = NULL;
diff --git a/drivers/rtc/rtc-tegra.c b/drivers/rtc/rtc-tegra.c
index 8dc48fe7fc35..c9e77a83cd1b 100644
--- a/drivers/rtc/rtc-tegra.c
+++ b/drivers/rtc/rtc-tegra.c
@@ -322,9 +322,13 @@ static int __init tegra_rtc_probe(struct platform_device *pdev)
if (IS_ERR(info->rtc_base))
return PTR_ERR(info->rtc_base);
- info->tegra_rtc_irq = platform_get_irq(pdev, 0);
- if (info->tegra_rtc_irq <= 0)
- return -EBUSY;
+ ret = platform_get_irq(pdev, 0);
+ if (ret <= 0) {
+ dev_err(&pdev->dev, "failed to get platform IRQ: %d\n", ret);
+ return ret;
+ }
+
+ info->tegra_rtc_irq = ret;
info->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(info->clk))
diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c
index ade6a82709be..6c5f09c815e8 100644
--- a/drivers/rtc/rtc-test.c
+++ b/drivers/rtc/rtc-test.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* An RTC test device/driver
* Copyright (C) 2005 Tower Technologies
* Author: Alessandro Zummo <a.zummo@towertech.it>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/module.h>
@@ -197,7 +194,7 @@ static void __exit test_exit(void)
MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
MODULE_DESCRIPTION("RTC test driver/device");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
module_init(test_init);
module_exit(test_exit);
diff --git a/drivers/rtc/rtc-tx4939.c b/drivers/rtc/rtc-tx4939.c
index 08dbefc79520..61c110b2045f 100644
--- a/drivers/rtc/rtc-tx4939.c
+++ b/drivers/rtc/rtc-tx4939.c
@@ -253,9 +253,7 @@ static int __init tx4939_rtc_probe(struct platform_device *pdev)
struct resource *res;
int irq, ret;
struct nvmem_config nvmem_cfg = {
- .name = "rv8803_nvram",
- .word_size = 4,
- .stride = 4,
+ .name = "tx4939_nvram",
.size = TX4939_RTC_REG_RAMSIZE,
.reg_read = tx4939_nvram_read,
.reg_write = tx4939_nvram_write,
diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c
index 70f013e692b0..e66d0f63cee2 100644
--- a/drivers/rtc/rtc-vr41xx.c
+++ b/drivers/rtc/rtc-vr41xx.c
@@ -136,8 +136,7 @@ static int vr41xx_rtc_set_time(struct device *dev, struct rtc_time *time)
time64_t epoch_sec, current_sec;
epoch_sec = mktime64(epoch, 1, 1, 0, 0, 0);
- current_sec = mktime64(time->tm_year + 1900, time->tm_mon + 1, time->tm_mday,
- time->tm_hour, time->tm_min, time->tm_sec);
+ current_sec = rtc_tm_to_time64(time);
write_elapsed_second(current_sec - epoch_sec);
@@ -158,7 +157,7 @@ static int vr41xx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
spin_unlock_irq(&rtc_lock);
- rtc_time_to_tm((high << 17) | (mid << 1) | (low >> 15), time);
+ rtc_time64_to_tm((high << 17) | (mid << 1) | (low >> 15), time);
return 0;
}
@@ -166,10 +165,8 @@ static int vr41xx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
static int vr41xx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
{
time64_t alarm_sec;
- struct rtc_time *time = &wkalrm->time;
- alarm_sec = mktime64(time->tm_year + 1900, time->tm_mon + 1, time->tm_mday,
- time->tm_hour, time->tm_min, time->tm_sec);
+ alarm_sec = rtc_tm_to_time64(&wkalrm->time);
spin_lock_irq(&rtc_lock);
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index a23e7d394a0a..5e9ebdb0594c 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -3309,10 +3309,8 @@ dasd_exit(void)
dasd_proc_exit();
#endif
dasd_eer_exit();
- if (dasd_page_cache != NULL) {
- kmem_cache_destroy(dasd_page_cache);
- dasd_page_cache = NULL;
- }
+ kmem_cache_destroy(dasd_page_cache);
+ dasd_page_cache = NULL;
dasd_gendisk_exit();
dasd_devmap_exit();
if (dasd_debug_area != NULL) {
diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c
index 7036a6c6f86f..5542d9eadfe0 100644
--- a/drivers/s390/block/dasd_genhd.c
+++ b/drivers/s390/block/dasd_genhd.c
@@ -76,7 +76,7 @@ int dasd_gendisk_alloc(struct dasd_block *block)
gdp->queue = block->request_queue;
block->gdp = gdp;
set_capacity(block->gdp, 0);
- device_add_disk(&base->cdev->dev, block->gdp);
+ device_add_disk(&base->cdev->dev, block->gdp, NULL);
return 0;
}
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index 23e526cda5c1..4e8aedd50cb0 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -685,7 +685,7 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
}
get_device(&dev_info->dev);
- device_add_disk(&dev_info->dev, dev_info->gd);
+ device_add_disk(&dev_info->dev, dev_info->gd, NULL);
switch (dev_info->segment_type) {
case SEG_TYPE_SR:
diff --git a/drivers/s390/block/scm_blk.c b/drivers/s390/block/scm_blk.c
index 98f66b7b6794..e01889394c84 100644
--- a/drivers/s390/block/scm_blk.c
+++ b/drivers/s390/block/scm_blk.c
@@ -500,7 +500,7 @@ int scm_blk_dev_setup(struct scm_blk_dev *bdev, struct scm_device *scmdev)
/* 512 byte sectors */
set_capacity(bdev->gendisk, scmdev->size >> 9);
- device_add_disk(&scmdev->dev, bdev->gendisk);
+ device_add_disk(&scmdev->dev, bdev->gendisk, NULL);
return 0;
out_queue:
diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile
index c6ab34f94b1b..3072b89785dd 100644
--- a/drivers/s390/char/Makefile
+++ b/drivers/s390/char/Makefile
@@ -11,6 +11,7 @@ endif
GCOV_PROFILE_sclp_early_core.o := n
KCOV_INSTRUMENT_sclp_early_core.o := n
UBSAN_SANITIZE_sclp_early_core.o := n
+KASAN_SANITIZE_sclp_early_core.o := n
CFLAGS_sclp_early_core.o += -D__NO_FORTIFY
diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c
index 16a4e8528bbc..8f3a2eeb28dc 100644
--- a/drivers/s390/char/fs3270.c
+++ b/drivers/s390/char/fs3270.c
@@ -8,7 +8,7 @@
* Copyright IBM Corp. 2003, 2009
*/
-#include <linux/bootmem.h>
+#include <linux/memblock.h>
#include <linux/console.h>
#include <linux/init.h>
#include <linux/interrupt.h>
diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c
index 4f1a69c9d81d..fdc0c0b7a6f5 100644
--- a/drivers/s390/char/monwriter.c
+++ b/drivers/s390/char/monwriter.c
@@ -58,22 +58,31 @@ struct mon_private {
static int monwrite_diag(struct monwrite_hdr *myhdr, char *buffer, int fcn)
{
- struct appldata_product_id id;
+ struct appldata_parameter_list *parm_list;
+ struct appldata_product_id *id;
int rc;
- memcpy(id.prod_nr, "LNXAPPL", 7);
- id.prod_fn = myhdr->applid;
- id.record_nr = myhdr->record_num;
- id.version_nr = myhdr->version;
- id.release_nr = myhdr->release;
- id.mod_lvl = myhdr->mod_level;
- rc = appldata_asm(&id, fcn, (void *) buffer, myhdr->datalen);
+ id = kmalloc(sizeof(*id), GFP_KERNEL);
+ parm_list = kmalloc(sizeof(*parm_list), GFP_KERNEL);
+ rc = -ENOMEM;
+ if (!id || !parm_list)
+ goto out;
+ memcpy(id->prod_nr, "LNXAPPL", 7);
+ id->prod_fn = myhdr->applid;
+ id->record_nr = myhdr->record_num;
+ id->version_nr = myhdr->version;
+ id->release_nr = myhdr->release;
+ id->mod_lvl = myhdr->mod_level;
+ rc = appldata_asm(parm_list, id, fcn,
+ (void *) buffer, myhdr->datalen);
if (rc <= 0)
- return rc;
+ goto out;
pr_err("Writing monitor data failed with rc=%i\n", rc);
- if (rc == 5)
- return -EPERM;
- return -EINVAL;
+ rc = (rc == 5) ? -EPERM : -EINVAL;
+out:
+ kfree(id);
+ kfree(parm_list);
+ return rc;
}
static struct mon_buf *monwrite_find_hdr(struct mon_private *monpriv,
diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h
index 1fe4918088e7..b3fcc24b1182 100644
--- a/drivers/s390/char/sclp.h
+++ b/drivers/s390/char/sclp.h
@@ -63,6 +63,9 @@
typedef unsigned int sclp_cmdw_t;
#define SCLP_CMDW_READ_CPU_INFO 0x00010001
+#define SCLP_CMDW_READ_SCP_INFO 0x00020001
+#define SCLP_CMDW_READ_STORAGE_INFO 0x00040001
+#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001
#define SCLP_CMDW_READ_EVENT_DATA 0x00770005
#define SCLP_CMDW_WRITE_EVENT_DATA 0x00760005
#define SCLP_CMDW_WRITE_EVENT_MASK 0x00780005
@@ -156,6 +159,54 @@ struct read_cpu_info_sccb {
u8 reserved[4096 - 16];
} __attribute__((packed, aligned(PAGE_SIZE)));
+struct read_info_sccb {
+ struct sccb_header header; /* 0-7 */
+ u16 rnmax; /* 8-9 */
+ u8 rnsize; /* 10 */
+ u8 _pad_11[16 - 11]; /* 11-15 */
+ u16 ncpurl; /* 16-17 */
+ u16 cpuoff; /* 18-19 */
+ u8 _pad_20[24 - 20]; /* 20-23 */
+ u8 loadparm[8]; /* 24-31 */
+ u8 _pad_32[42 - 32]; /* 32-41 */
+ u8 fac42; /* 42 */
+ u8 fac43; /* 43 */
+ u8 _pad_44[48 - 44]; /* 44-47 */
+ u64 facilities; /* 48-55 */
+ u8 _pad_56[66 - 56]; /* 56-65 */
+ u8 fac66; /* 66 */
+ u8 _pad_67[76 - 67]; /* 67-83 */
+ u32 ibc; /* 76-79 */
+ u8 _pad80[84 - 80]; /* 80-83 */
+ u8 fac84; /* 84 */
+ u8 fac85; /* 85 */
+ u8 _pad_86[91 - 86]; /* 86-90 */
+ u8 fac91; /* 91 */
+ u8 _pad_92[98 - 92]; /* 92-97 */
+ u8 fac98; /* 98 */
+ u8 hamaxpow; /* 99 */
+ u32 rnsize2; /* 100-103 */
+ u64 rnmax2; /* 104-111 */
+ u32 hsa_size; /* 112-115 */
+ u8 fac116; /* 116 */
+ u8 fac117; /* 117 */
+ u8 fac118; /* 118 */
+ u8 fac119; /* 119 */
+ u16 hcpua; /* 120-121 */
+ u8 _pad_122[124 - 122]; /* 122-123 */
+ u32 hmfai; /* 124-127 */
+ u8 _pad_128[4096 - 128]; /* 128-4095 */
+} __packed __aligned(PAGE_SIZE);
+
+struct read_storage_sccb {
+ struct sccb_header header;
+ u16 max_id;
+ u16 assigned;
+ u16 standby;
+ u16 :16;
+ u32 entries[0];
+} __packed;
+
static inline void sclp_fill_core_info(struct sclp_core_info *info,
struct read_cpu_info_sccb *sccb)
{
@@ -275,6 +326,7 @@ unsigned int sclp_early_con_check_vt220(struct init_sccb *sccb);
int sclp_early_set_event_mask(struct init_sccb *sccb,
sccb_mask_t receive_mask,
sccb_mask_t send_mask);
+int sclp_early_get_info(struct read_info_sccb *info);
/* useful inlines */
diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c
index d7686a68c093..37d42de06079 100644
--- a/drivers/s390/char/sclp_cmd.c
+++ b/drivers/s390/char/sclp_cmd.c
@@ -460,15 +460,6 @@ static int sclp_mem_freeze(struct device *dev)
return -EPERM;
}
-struct read_storage_sccb {
- struct sccb_header header;
- u16 max_id;
- u16 assigned;
- u16 standby;
- u16 :16;
- u32 entries[0];
-} __packed;
-
static const struct dev_pm_ops sclp_mem_pm_ops = {
.freeze = sclp_mem_freeze,
};
@@ -498,7 +489,7 @@ static int __init sclp_detect_standby_memory(void)
for (id = 0; id <= sclp_max_storage_id; id++) {
memset(sccb, 0, PAGE_SIZE);
sccb->header.length = PAGE_SIZE;
- rc = sclp_sync_request(0x00040001 | id << 8, sccb);
+ rc = sclp_sync_request(SCLP_CMDW_READ_STORAGE_INFO | id << 8, sccb);
if (rc)
goto out;
switch (sccb->header.response_code) {
diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c
index 9a74abb9224d..e792cee3b51c 100644
--- a/drivers/s390/char/sclp_early.c
+++ b/drivers/s390/char/sclp_early.c
@@ -15,80 +15,17 @@
#include "sclp_sdias.h"
#include "sclp.h"
-#define SCLP_CMDW_READ_SCP_INFO 0x00020001
-#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001
-
-struct read_info_sccb {
- struct sccb_header header; /* 0-7 */
- u16 rnmax; /* 8-9 */
- u8 rnsize; /* 10 */
- u8 _pad_11[16 - 11]; /* 11-15 */
- u16 ncpurl; /* 16-17 */
- u16 cpuoff; /* 18-19 */
- u8 _pad_20[24 - 20]; /* 20-23 */
- u8 loadparm[8]; /* 24-31 */
- u8 _pad_32[42 - 32]; /* 32-41 */
- u8 fac42; /* 42 */
- u8 fac43; /* 43 */
- u8 _pad_44[48 - 44]; /* 44-47 */
- u64 facilities; /* 48-55 */
- u8 _pad_56[66 - 56]; /* 56-65 */
- u8 fac66; /* 66 */
- u8 _pad_67[76 - 67]; /* 67-83 */
- u32 ibc; /* 76-79 */
- u8 _pad80[84 - 80]; /* 80-83 */
- u8 fac84; /* 84 */
- u8 fac85; /* 85 */
- u8 _pad_86[91 - 86]; /* 86-90 */
- u8 fac91; /* 91 */
- u8 _pad_92[98 - 92]; /* 92-97 */
- u8 fac98; /* 98 */
- u8 hamaxpow; /* 99 */
- u32 rnsize2; /* 100-103 */
- u64 rnmax2; /* 104-111 */
- u8 _pad_112[116 - 112]; /* 112-115 */
- u8 fac116; /* 116 */
- u8 fac117; /* 117 */
- u8 fac118; /* 118 */
- u8 fac119; /* 119 */
- u16 hcpua; /* 120-121 */
- u8 _pad_122[124 - 122]; /* 122-123 */
- u32 hmfai; /* 124-127 */
- u8 _pad_128[4096 - 128]; /* 128-4095 */
-} __packed __aligned(PAGE_SIZE);
-
static struct sclp_ipl_info sclp_ipl_info;
struct sclp_info sclp;
EXPORT_SYMBOL(sclp);
-static int __init sclp_early_read_info(struct read_info_sccb *sccb)
-{
- int i;
- sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED,
- SCLP_CMDW_READ_SCP_INFO};
-
- for (i = 0; i < ARRAY_SIZE(commands); i++) {
- memset(sccb, 0, sizeof(*sccb));
- sccb->header.length = sizeof(*sccb);
- sccb->header.function_code = 0x80;
- sccb->header.control_mask[2] = 0x80;
- if (sclp_early_cmd(commands[i], sccb))
- break;
- if (sccb->header.response_code == 0x10)
- return 0;
- if (sccb->header.response_code != 0x1f0)
- break;
- }
- return -EIO;
-}
-
static void __init sclp_early_facilities_detect(struct read_info_sccb *sccb)
{
struct sclp_core_entry *cpue;
u16 boot_cpu_address, cpu;
- if (sclp_early_read_info(sccb))
+ if (sclp_early_get_info(sccb))
return;
sclp.facilities = sccb->facilities;
@@ -147,6 +84,8 @@ static void __init sclp_early_facilities_detect(struct read_info_sccb *sccb)
sclp_ipl_info.has_dump = 1;
memcpy(&sclp_ipl_info.loadparm, &sccb->loadparm, LOADPARM_LEN);
+ if (sccb->hsa_size)
+ sclp.hsa_size = (sccb->hsa_size - 1) * PAGE_SIZE;
sclp.mtid = (sccb->fac42 & 0x80) ? (sccb->fac42 & 31) : 0;
sclp.mtid_cp = (sccb->fac42 & 0x80) ? (sccb->fac43 & 31) : 0;
sclp.mtid_prev = (sccb->fac42 & 0x80) ? (sccb->fac66 & 31) : 0;
@@ -189,61 +128,6 @@ int __init sclp_early_get_core_info(struct sclp_core_info *info)
return 0;
}
-static long __init sclp_early_hsa_size_init(struct sdias_sccb *sccb)
-{
- memset(sccb, 0, sizeof(*sccb));
- sccb->hdr.length = sizeof(*sccb);
- sccb->evbuf.hdr.length = sizeof(struct sdias_evbuf);
- sccb->evbuf.hdr.type = EVTYP_SDIAS;
- sccb->evbuf.event_qual = SDIAS_EQ_SIZE;
- sccb->evbuf.data_id = SDIAS_DI_FCP_DUMP;
- sccb->evbuf.event_id = 4712;
- sccb->evbuf.dbs = 1;
- if (sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_DATA, sccb))
- return -EIO;
- if (sccb->hdr.response_code != 0x20)
- return -EIO;
- if (sccb->evbuf.blk_cnt == 0)
- return 0;
- return (sccb->evbuf.blk_cnt - 1) * PAGE_SIZE;
-}
-
-static long __init sclp_early_hsa_copy_wait(struct sdias_sccb *sccb)
-{
- memset(sccb, 0, PAGE_SIZE);
- sccb->hdr.length = PAGE_SIZE;
- if (sclp_early_cmd(SCLP_CMDW_READ_EVENT_DATA, sccb))
- return -EIO;
- if ((sccb->hdr.response_code != 0x20) && (sccb->hdr.response_code != 0x220))
- return -EIO;
- if (sccb->evbuf.blk_cnt == 0)
- return 0;
- return (sccb->evbuf.blk_cnt - 1) * PAGE_SIZE;
-}
-
-static void __init sclp_early_hsa_size_detect(void *sccb)
-{
- unsigned long flags;
- long size = -EIO;
-
- raw_local_irq_save(flags);
- if (sclp_early_set_event_mask(sccb, EVTYP_SDIAS_MASK, EVTYP_SDIAS_MASK))
- goto out;
- size = sclp_early_hsa_size_init(sccb);
- /* First check for synchronous response (LPAR) */
- if (size)
- goto out_mask;
- if (!(S390_lowcore.ext_params & 1))
- sclp_early_wait_irq();
- size = sclp_early_hsa_copy_wait(sccb);
-out_mask:
- sclp_early_set_event_mask(sccb, 0, 0);
-out:
- raw_local_irq_restore(flags);
- if (size > 0)
- sclp.hsa_size = size;
-}
-
static void __init sclp_early_console_detect(struct init_sccb *sccb)
{
if (sccb->header.response_code != 0x20)
@@ -262,7 +146,6 @@ void __init sclp_early_detect(void)
sclp_early_facilities_detect(sccb);
sclp_early_init_core_info(sccb);
- sclp_early_hsa_size_detect(sccb);
/*
* Turn off SCLP event notifications. Also save remote masks in the
diff --git a/drivers/s390/char/sclp_early_core.c b/drivers/s390/char/sclp_early_core.c
index eceba3858cef..387c114ded3f 100644
--- a/drivers/s390/char/sclp_early_core.c
+++ b/drivers/s390/char/sclp_early_core.c
@@ -9,9 +9,13 @@
#include <asm/lowcore.h>
#include <asm/ebcdic.h>
#include <asm/irq.h>
+#include <asm/sections.h>
+#include <asm/mem_detect.h>
#include "sclp.h"
#include "sclp_rw.h"
+static struct read_info_sccb __bootdata(sclp_info_sccb);
+static int __bootdata(sclp_info_sccb_valid);
char sclp_early_sccb[PAGE_SIZE] __aligned(PAGE_SIZE) __section(.data);
int sclp_init_state __section(.data) = sclp_init_state_uninitialized;
/*
@@ -210,11 +214,11 @@ static int sclp_early_setup(int disable, int *have_linemode, int *have_vt220)
* Output one or more lines of text on the SCLP console (VT220 and /
* or line-mode).
*/
-void __sclp_early_printk(const char *str, unsigned int len)
+void __sclp_early_printk(const char *str, unsigned int len, unsigned int force)
{
int have_linemode, have_vt220;
- if (sclp_init_state != sclp_init_state_uninitialized)
+ if (!force && sclp_init_state != sclp_init_state_uninitialized)
return;
if (sclp_early_setup(0, &have_linemode, &have_vt220) != 0)
return;
@@ -227,5 +231,122 @@ void __sclp_early_printk(const char *str, unsigned int len)
void sclp_early_printk(const char *str)
{
- __sclp_early_printk(str, strlen(str));
+ __sclp_early_printk(str, strlen(str), 0);
+}
+
+void sclp_early_printk_force(const char *str)
+{
+ __sclp_early_printk(str, strlen(str), 1);
+}
+
+int __init sclp_early_read_info(void)
+{
+ int i;
+ struct read_info_sccb *sccb = &sclp_info_sccb;
+ sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED,
+ SCLP_CMDW_READ_SCP_INFO};
+
+ for (i = 0; i < ARRAY_SIZE(commands); i++) {
+ memset(sccb, 0, sizeof(*sccb));
+ sccb->header.length = sizeof(*sccb);
+ sccb->header.function_code = 0x80;
+ sccb->header.control_mask[2] = 0x80;
+ if (sclp_early_cmd(commands[i], sccb))
+ break;
+ if (sccb->header.response_code == 0x10) {
+ sclp_info_sccb_valid = 1;
+ return 0;
+ }
+ if (sccb->header.response_code != 0x1f0)
+ break;
+ }
+ return -EIO;
+}
+
+int __init sclp_early_get_info(struct read_info_sccb *info)
+{
+ if (!sclp_info_sccb_valid)
+ return -EIO;
+
+ *info = sclp_info_sccb;
+ return 0;
+}
+
+int __init sclp_early_get_memsize(unsigned long *mem)
+{
+ unsigned long rnmax;
+ unsigned long rnsize;
+ struct read_info_sccb *sccb = &sclp_info_sccb;
+
+ if (!sclp_info_sccb_valid)
+ return -EIO;
+
+ rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2;
+ rnsize = sccb->rnsize ? sccb->rnsize : sccb->rnsize2;
+ rnsize <<= 20;
+ *mem = rnsize * rnmax;
+ return 0;
+}
+
+int __init sclp_early_get_hsa_size(unsigned long *hsa_size)
+{
+ if (!sclp_info_sccb_valid)
+ return -EIO;
+
+ *hsa_size = 0;
+ if (sclp_info_sccb.hsa_size)
+ *hsa_size = (sclp_info_sccb.hsa_size - 1) * PAGE_SIZE;
+ return 0;
+}
+
+#define SCLP_STORAGE_INFO_FACILITY 0x0000400000000000UL
+
+void __weak __init add_mem_detect_block(u64 start, u64 end) {}
+int __init sclp_early_read_storage_info(void)
+{
+ struct read_storage_sccb *sccb = (struct read_storage_sccb *)&sclp_early_sccb;
+ int rc, id, max_id = 0;
+ unsigned long rn, rzm;
+ sclp_cmdw_t command;
+ u16 sn;
+
+ if (!sclp_info_sccb_valid)
+ return -EIO;
+
+ if (!(sclp_info_sccb.facilities & SCLP_STORAGE_INFO_FACILITY))
+ return -EOPNOTSUPP;
+
+ rzm = sclp_info_sccb.rnsize ?: sclp_info_sccb.rnsize2;
+ rzm <<= 20;
+
+ for (id = 0; id <= max_id; id++) {
+ memset(sclp_early_sccb, 0, sizeof(sclp_early_sccb));
+ sccb->header.length = sizeof(sclp_early_sccb);
+ command = SCLP_CMDW_READ_STORAGE_INFO | (id << 8);
+ rc = sclp_early_cmd(command, sccb);
+ if (rc)
+ goto fail;
+
+ max_id = sccb->max_id;
+ switch (sccb->header.response_code) {
+ case 0x0010:
+ for (sn = 0; sn < sccb->assigned; sn++) {
+ if (!sccb->entries[sn])
+ continue;
+ rn = sccb->entries[sn] >> 16;
+ add_mem_detect_block((rn - 1) * rzm, rn * rzm);
+ }
+ break;
+ case 0x0310:
+ case 0x0410:
+ break;
+ default:
+ goto fail;
+ }
+ }
+
+ return 0;
+fail:
+ mem_detect.count = 0;
+ return -EIO;
}
diff --git a/drivers/s390/char/sclp_pci.c b/drivers/s390/char/sclp_pci.c
index e7c84a4e5eb5..995e9196852e 100644
--- a/drivers/s390/char/sclp_pci.c
+++ b/drivers/s390/char/sclp_pci.c
@@ -24,6 +24,7 @@
#define SCLP_ATYPE_PCI 2
+#define SCLP_ERRNOTIFY_AQ_RESET 0
#define SCLP_ERRNOTIFY_AQ_REPAIR 1
#define SCLP_ERRNOTIFY_AQ_INFO_LOG 2
@@ -111,9 +112,14 @@ static int sclp_pci_check_report(struct zpci_report_error_header *report)
if (report->version != 1)
return -EINVAL;
- if (report->action != SCLP_ERRNOTIFY_AQ_REPAIR &&
- report->action != SCLP_ERRNOTIFY_AQ_INFO_LOG)
+ switch (report->action) {
+ case SCLP_ERRNOTIFY_AQ_RESET:
+ case SCLP_ERRNOTIFY_AQ_REPAIR:
+ case SCLP_ERRNOTIFY_AQ_INFO_LOG:
+ break;
+ default:
return -EINVAL;
+ }
if (report->length > (PAGE_SIZE - sizeof(struct err_notify_sccb)))
return -EINVAL;
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c
index cdcde18e7220..4554cdf4d6bd 100644
--- a/drivers/s390/char/tape_3590.c
+++ b/drivers/s390/char/tape_3590.c
@@ -971,7 +971,7 @@ tape_3590_print_mim_msg_f0(struct tape_device *device, struct irb *irb)
snprintf(exception, BUFSIZE, "Data degraded");
break;
case 0x03:
- snprintf(exception, BUFSIZE, "Data degraded in partion %i",
+ snprintf(exception, BUFSIZE, "Data degraded in partition %i",
sense->fmt.f70.mp);
break;
case 0x04:
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index 5b8af2782282..2b0c36c2c568 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -19,7 +19,7 @@
#include <linux/workqueue.h>
#include <linux/slab.h>
-#include <linux/bootmem.h>
+#include <linux/memblock.h>
#include <linux/compat.h>
#include <asm/ccwdev.h>
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c
index 069b9ef08206..58333cb4503f 100644
--- a/drivers/s390/char/vmlogrdr.c
+++ b/drivers/s390/char/vmlogrdr.c
@@ -153,7 +153,7 @@ static struct vmlogrdr_priv_t sys_ser[] = {
}
};
-#define MAXMINOR (sizeof(sys_ser)/sizeof(struct vmlogrdr_priv_t))
+#define MAXMINOR ARRAY_SIZE(sys_ser)
static char FENCE[] = {"EOR"};
static int vmlogrdr_major = 0;
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index 93b2862bd3fa..4ebf6d4fc66c 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -608,6 +608,36 @@ void ccwgroup_driver_unregister(struct ccwgroup_driver *cdriver)
}
EXPORT_SYMBOL(ccwgroup_driver_unregister);
+static int __ccwgroupdev_check_busid(struct device *dev, void *id)
+{
+ char *bus_id = id;
+
+ return (strcmp(bus_id, dev_name(dev)) == 0);
+}
+
+/**
+ * get_ccwgroupdev_by_busid() - obtain device from a bus id
+ * @gdrv: driver the device is owned by
+ * @bus_id: bus id of the device to be searched
+ *
+ * This function searches all devices owned by @gdrv for a device with a bus
+ * id matching @bus_id.
+ * Returns:
+ * If a match is found, its reference count of the found device is increased
+ * and it is returned; else %NULL is returned.
+ */
+struct ccwgroup_device *get_ccwgroupdev_by_busid(struct ccwgroup_driver *gdrv,
+ char *bus_id)
+{
+ struct device *dev;
+
+ dev = driver_find_device(&gdrv->driver, NULL, bus_id,
+ __ccwgroupdev_check_busid);
+
+ return dev ? to_ccwgroupdev(dev) : NULL;
+}
+EXPORT_SYMBOL_GPL(get_ccwgroupdev_by_busid);
+
/**
* ccwgroup_probe_ccwdev() - probe function for slave devices
* @cdev: ccw device to be probed
diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c
index 8af4948dae80..72dd2471ec1e 100644
--- a/drivers/s390/cio/cmf.c
+++ b/drivers/s390/cio/cmf.c
@@ -13,7 +13,7 @@
#define KMSG_COMPONENT "cio"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
-#include <linux/bootmem.h>
+#include <linux/memblock.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/list.h>
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c
index 9c7d9da42ba0..9537e656e927 100644
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -595,19 +595,11 @@ static inline int qdio_inbound_q_done(struct qdio_q *q)
return 0;
}
-static inline int contains_aobs(struct qdio_q *q)
-{
- return !q->is_input_q && q->u.out.use_cq;
-}
-
static inline void qdio_handle_aobs(struct qdio_q *q, int start, int count)
{
unsigned char state = 0;
int j, b = start;
- if (!contains_aobs(q))
- return;
-
for (j = 0; j < count; ++j) {
get_buf_state(q, b, &state, 0);
if (state == SLSB_P_OUTPUT_PENDING) {
@@ -618,8 +610,6 @@ static inline void qdio_handle_aobs(struct qdio_q *q, int start, int count)
q->u.out.sbal_state[b].flags |=
QDIO_OUTBUF_STATE_FLAG_PENDING;
q->u.out.aobs[b] = NULL;
- } else if (state == SLSB_P_OUTPUT_EMPTY) {
- q->u.out.sbal_state[b].aob = NULL;
}
b = next_buf(b);
}
@@ -638,7 +628,6 @@ static inline unsigned long qdio_aob_for_buffer(struct qdio_output_q *q,
q->aobs[bufnr] = aob;
}
if (q->aobs[bufnr]) {
- q->sbal_state[bufnr].aob = q->aobs[bufnr];
q->aobs[bufnr]->user1 = (u64) q->sbal_state[bufnr].user;
phys_aob = virt_to_phys(q->aobs[bufnr]);
WARN_ON_ONCE(phys_aob & 0xFF);
@@ -666,10 +655,10 @@ static void qdio_kick_handler(struct qdio_q *q)
qperf_inc(q, outbound_handler);
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "koh: s:%02x c:%02x",
start, count);
+ if (q->u.out.use_cq)
+ qdio_handle_aobs(q, start, count);
}
- qdio_handle_aobs(q, start, count);
-
q->handler(q->irq_ptr->cdev, q->qdio_error, q->nr, start, count,
q->irq_ptr->int_parm);
diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c
index 78f1be41b05e..e324d890a4f6 100644
--- a/drivers/s390/cio/qdio_setup.c
+++ b/drivers/s390/cio/qdio_setup.c
@@ -27,7 +27,6 @@ struct qaob *qdio_allocate_aob(void)
{
return kmem_cache_zalloc(qdio_aob_cache, GFP_ATOMIC);
}
-EXPORT_SYMBOL_GPL(qdio_allocate_aob);
void qdio_release_aob(struct qaob *aob)
{
diff --git a/drivers/s390/cio/vfio_ccw_cp.c b/drivers/s390/cio/vfio_ccw_cp.c
index dbe7c7ac9ac8..fd77e46eb3b2 100644
--- a/drivers/s390/cio/vfio_ccw_cp.c
+++ b/drivers/s390/cio/vfio_ccw_cp.c
@@ -163,7 +163,7 @@ static bool pfn_array_table_iova_pinned(struct pfn_array_table *pat,
for (i = 0; i < pat->pat_nr; i++, pa++)
for (j = 0; j < pa->pa_nr; j++)
- if (pa->pa_iova_pfn[i] == iova_pfn)
+ if (pa->pa_iova_pfn[j] == iova_pfn)
return true;
return false;
diff --git a/drivers/s390/cio/vfio_ccw_drv.c b/drivers/s390/cio/vfio_ccw_drv.c
index 770fa9cfc310..f47d16b5810b 100644
--- a/drivers/s390/cio/vfio_ccw_drv.c
+++ b/drivers/s390/cio/vfio_ccw_drv.c
@@ -22,6 +22,7 @@
#include "vfio_ccw_private.h"
struct workqueue_struct *vfio_ccw_work_q;
+struct kmem_cache *vfio_ccw_io_region;
/*
* Helpers
@@ -79,7 +80,7 @@ static void vfio_ccw_sch_io_todo(struct work_struct *work)
cp_update_scsw(&private->cp, &irb->scsw);
cp_free(&private->cp);
}
- memcpy(private->io_region.irb_area, irb, sizeof(*irb));
+ memcpy(private->io_region->irb_area, irb, sizeof(*irb));
if (private->io_trigger)
eventfd_signal(private->io_trigger, 1);
@@ -114,6 +115,14 @@ static int vfio_ccw_sch_probe(struct subchannel *sch)
private = kzalloc(sizeof(*private), GFP_KERNEL | GFP_DMA);
if (!private)
return -ENOMEM;
+
+ private->io_region = kmem_cache_zalloc(vfio_ccw_io_region,
+ GFP_KERNEL | GFP_DMA);
+ if (!private->io_region) {
+ kfree(private);
+ return -ENOMEM;
+ }
+
private->sch = sch;
dev_set_drvdata(&sch->dev, private);
@@ -139,6 +148,7 @@ out_disable:
cio_disable_subchannel(sch);
out_free:
dev_set_drvdata(&sch->dev, NULL);
+ kmem_cache_free(vfio_ccw_io_region, private->io_region);
kfree(private);
return ret;
}
@@ -153,6 +163,7 @@ static int vfio_ccw_sch_remove(struct subchannel *sch)
dev_set_drvdata(&sch->dev, NULL);
+ kmem_cache_free(vfio_ccw_io_region, private->io_region);
kfree(private);
return 0;
@@ -232,10 +243,20 @@ static int __init vfio_ccw_sch_init(void)
if (!vfio_ccw_work_q)
return -ENOMEM;
+ vfio_ccw_io_region = kmem_cache_create_usercopy("vfio_ccw_io_region",
+ sizeof(struct ccw_io_region), 0,
+ SLAB_ACCOUNT, 0,
+ sizeof(struct ccw_io_region), NULL);
+ if (!vfio_ccw_io_region) {
+ destroy_workqueue(vfio_ccw_work_q);
+ return -ENOMEM;
+ }
+
isc_register(VFIO_CCW_ISC);
ret = css_driver_register(&vfio_ccw_sch_driver);
if (ret) {
isc_unregister(VFIO_CCW_ISC);
+ kmem_cache_destroy(vfio_ccw_io_region);
destroy_workqueue(vfio_ccw_work_q);
}
@@ -246,6 +267,7 @@ static void __exit vfio_ccw_sch_exit(void)
{
css_driver_unregister(&vfio_ccw_sch_driver);
isc_unregister(VFIO_CCW_ISC);
+ kmem_cache_destroy(vfio_ccw_io_region);
destroy_workqueue(vfio_ccw_work_q);
}
module_init(vfio_ccw_sch_init);
diff --git a/drivers/s390/cio/vfio_ccw_fsm.c b/drivers/s390/cio/vfio_ccw_fsm.c
index 797a82731159..f94aa01f9c36 100644
--- a/drivers/s390/cio/vfio_ccw_fsm.c
+++ b/drivers/s390/cio/vfio_ccw_fsm.c
@@ -93,13 +93,13 @@ static void fsm_io_error(struct vfio_ccw_private *private,
enum vfio_ccw_event event)
{
pr_err("vfio-ccw: FSM: I/O request from state:%d\n", private->state);
- private->io_region.ret_code = -EIO;
+ private->io_region->ret_code = -EIO;
}
static void fsm_io_busy(struct vfio_ccw_private *private,
enum vfio_ccw_event event)
{
- private->io_region.ret_code = -EBUSY;
+ private->io_region->ret_code = -EBUSY;
}
static void fsm_disabled_irq(struct vfio_ccw_private *private,
@@ -126,7 +126,7 @@ static void fsm_io_request(struct vfio_ccw_private *private,
{
union orb *orb;
union scsw *scsw = &private->scsw;
- struct ccw_io_region *io_region = &private->io_region;
+ struct ccw_io_region *io_region = private->io_region;
struct mdev_device *mdev = private->mdev;
char *errstr = "request";
diff --git a/drivers/s390/cio/vfio_ccw_ops.c b/drivers/s390/cio/vfio_ccw_ops.c
index 41eeb57d68a3..f673e106c041 100644
--- a/drivers/s390/cio/vfio_ccw_ops.c
+++ b/drivers/s390/cio/vfio_ccw_ops.c
@@ -174,7 +174,7 @@ static ssize_t vfio_ccw_mdev_read(struct mdev_device *mdev,
return -EINVAL;
private = dev_get_drvdata(mdev_parent_dev(mdev));
- region = &private->io_region;
+ region = private->io_region;
if (copy_to_user(buf, (void *)region + *ppos, count))
return -EFAULT;
@@ -196,7 +196,7 @@ static ssize_t vfio_ccw_mdev_write(struct mdev_device *mdev,
if (private->state != VFIO_CCW_STATE_IDLE)
return -EACCES;
- region = &private->io_region;
+ region = private->io_region;
if (copy_from_user((void *)region + *ppos, buf, count))
return -EFAULT;
diff --git a/drivers/s390/cio/vfio_ccw_private.h b/drivers/s390/cio/vfio_ccw_private.h
index 78a66d96756b..078e46f9623d 100644
--- a/drivers/s390/cio/vfio_ccw_private.h
+++ b/drivers/s390/cio/vfio_ccw_private.h
@@ -41,7 +41,7 @@ struct vfio_ccw_private {
atomic_t avail;
struct mdev_device *mdev;
struct notifier_block nb;
- struct ccw_io_region io_region;
+ struct ccw_io_region *io_region;
struct channel_program cp;
struct irb irb;
diff --git a/drivers/s390/crypto/Makefile b/drivers/s390/crypto/Makefile
index b59af548ed1c..6ccd93d0b1cb 100644
--- a/drivers/s390/crypto/Makefile
+++ b/drivers/s390/crypto/Makefile
@@ -10,8 +10,12 @@ zcrypt-objs := zcrypt_api.o zcrypt_card.o zcrypt_queue.o
zcrypt-objs += zcrypt_msgtype6.o zcrypt_msgtype50.o
obj-$(CONFIG_ZCRYPT) += zcrypt.o
# adapter drivers depend on ap.o and zcrypt.o
-obj-$(CONFIG_ZCRYPT) += zcrypt_pcixcc.o zcrypt_cex2a.o zcrypt_cex4.o
+obj-$(CONFIG_ZCRYPT) += zcrypt_cex2c.o zcrypt_cex2a.o zcrypt_cex4.o
# pkey kernel module
pkey-objs := pkey_api.o
obj-$(CONFIG_PKEY) += pkey.o
+
+# adjunct processor matrix
+vfio_ap-objs := vfio_ap_drv.o vfio_ap_ops.o
+obj-$(CONFIG_VFIO_AP) += vfio_ap.o
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index f039266b275d..048665e4f13d 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -65,12 +65,11 @@ static struct device *ap_root_device;
DEFINE_SPINLOCK(ap_list_lock);
LIST_HEAD(ap_card_list);
-/* Default permissions (card and domain masking) */
-static struct ap_perms {
- DECLARE_BITMAP(apm, AP_DEVICES);
- DECLARE_BITMAP(aqm, AP_DOMAINS);
-} ap_perms;
-static DEFINE_MUTEX(ap_perms_mutex);
+/* Default permissions (ioctl, card and domain masking) */
+struct ap_perms ap_perms;
+EXPORT_SYMBOL(ap_perms);
+DEFINE_MUTEX(ap_perms_mutex);
+EXPORT_SYMBOL(ap_perms_mutex);
static struct ap_config_info *ap_configuration;
static bool initialised;
@@ -944,21 +943,9 @@ static int modify_bitmap(const char *str, unsigned long *bitmap, int bits)
return 0;
}
-/*
- * process_mask_arg() - parse a bitmap string and clear/set the
- * bits in the bitmap accordingly. The string may be given as
- * absolute value, a hex string like 0x1F2E3D4C5B6A" simple over-
- * writing the current content of the bitmap. Or as relative string
- * like "+1-16,-32,-0x40,+128" where only single bits or ranges of
- * bits are cleared or set. Distinction is done based on the very
- * first character which may be '+' or '-' for the relative string
- * and othewise assume to be an absolute value string. If parsing fails
- * a negative errno value is returned. All arguments and bitmaps are
- * big endian order.
- */
-static int process_mask_arg(const char *str,
- unsigned long *bitmap, int bits,
- struct mutex *lock)
+int ap_parse_mask_str(const char *str,
+ unsigned long *bitmap, int bits,
+ struct mutex *lock)
{
unsigned long *newmap, size;
int rc;
@@ -989,6 +976,7 @@ static int process_mask_arg(const char *str,
kfree(newmap);
return rc;
}
+EXPORT_SYMBOL(ap_parse_mask_str);
/*
* AP bus attributes.
@@ -1049,6 +1037,21 @@ static ssize_t ap_usage_domain_mask_show(struct bus_type *bus, char *buf)
static BUS_ATTR_RO(ap_usage_domain_mask);
+static ssize_t ap_adapter_mask_show(struct bus_type *bus, char *buf)
+{
+ if (!ap_configuration) /* QCI not supported */
+ return snprintf(buf, PAGE_SIZE, "not supported\n");
+
+ return snprintf(buf, PAGE_SIZE,
+ "0x%08x%08x%08x%08x%08x%08x%08x%08x\n",
+ ap_configuration->apm[0], ap_configuration->apm[1],
+ ap_configuration->apm[2], ap_configuration->apm[3],
+ ap_configuration->apm[4], ap_configuration->apm[5],
+ ap_configuration->apm[6], ap_configuration->apm[7]);
+}
+
+static BUS_ATTR_RO(ap_adapter_mask);
+
static ssize_t ap_interrupts_show(struct bus_type *bus, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n",
@@ -1161,7 +1164,7 @@ static ssize_t apmask_store(struct bus_type *bus, const char *buf,
{
int rc;
- rc = process_mask_arg(buf, ap_perms.apm, AP_DEVICES, &ap_perms_mutex);
+ rc = ap_parse_mask_str(buf, ap_perms.apm, AP_DEVICES, &ap_perms_mutex);
if (rc)
return rc;
@@ -1192,7 +1195,7 @@ static ssize_t aqmask_store(struct bus_type *bus, const char *buf,
{
int rc;
- rc = process_mask_arg(buf, ap_perms.aqm, AP_DOMAINS, &ap_perms_mutex);
+ rc = ap_parse_mask_str(buf, ap_perms.aqm, AP_DOMAINS, &ap_perms_mutex);
if (rc)
return rc;
@@ -1207,6 +1210,7 @@ static struct bus_attribute *const ap_bus_attrs[] = {
&bus_attr_ap_domain,
&bus_attr_ap_control_domain_mask,
&bus_attr_ap_usage_domain_mask,
+ &bus_attr_ap_adapter_mask,
&bus_attr_config_time,
&bus_attr_poll_thread,
&bus_attr_ap_interrupts,
@@ -1218,11 +1222,10 @@ static struct bus_attribute *const ap_bus_attrs[] = {
};
/**
- * ap_select_domain(): Select an AP domain.
- *
- * Pick one of the 16 AP domains.
+ * ap_select_domain(): Select an AP domain if possible and we haven't
+ * already done so before.
*/
-static int ap_select_domain(void)
+static void ap_select_domain(void)
{
int count, max_count, best_domain;
struct ap_queue_status status;
@@ -1237,7 +1240,7 @@ static int ap_select_domain(void)
if (ap_domain_index >= 0) {
/* Domain has already been selected. */
spin_unlock_bh(&ap_domain_lock);
- return 0;
+ return;
}
best_domain = -1;
max_count = 0;
@@ -1264,11 +1267,8 @@ static int ap_select_domain(void)
if (best_domain >= 0) {
ap_domain_index = best_domain;
AP_DBF(DBF_DEBUG, "new ap_domain_index=%d\n", ap_domain_index);
- spin_unlock_bh(&ap_domain_lock);
- return 0;
}
spin_unlock_bh(&ap_domain_lock);
- return -ENODEV;
}
/*
@@ -1346,8 +1346,7 @@ static void ap_scan_bus(struct work_struct *unused)
AP_DBF(DBF_DEBUG, "%s running\n", __func__);
ap_query_configuration(ap_configuration);
- if (ap_select_domain() != 0)
- goto out;
+ ap_select_domain();
for (id = 0; id < AP_DEVICES; id++) {
/* check if device is registered */
@@ -1467,12 +1466,11 @@ static void ap_scan_bus(struct work_struct *unused)
}
} /* end device loop */
- if (defdomdevs < 1)
+ if (ap_domain_index >= 0 && defdomdevs < 1)
AP_DBF(DBF_INFO,
"no queue device with default domain %d available\n",
ap_domain_index);
-out:
mod_timer(&ap_config_timer, jiffies + ap_config_time * HZ);
}
@@ -1496,21 +1494,22 @@ static int __init ap_debug_init(void)
static void __init ap_perms_init(void)
{
/* all resources useable if no kernel parameter string given */
+ memset(&ap_perms.ioctlm, 0xFF, sizeof(ap_perms.ioctlm));
memset(&ap_perms.apm, 0xFF, sizeof(ap_perms.apm));
memset(&ap_perms.aqm, 0xFF, sizeof(ap_perms.aqm));
/* apm kernel parameter string */
if (apm_str) {
memset(&ap_perms.apm, 0, sizeof(ap_perms.apm));
- process_mask_arg(apm_str, ap_perms.apm, AP_DEVICES,
- &ap_perms_mutex);
+ ap_parse_mask_str(apm_str, ap_perms.apm, AP_DEVICES,
+ &ap_perms_mutex);
}
/* aqm kernel parameter string */
if (aqm_str) {
memset(&ap_perms.aqm, 0, sizeof(ap_perms.aqm));
- process_mask_arg(aqm_str, ap_perms.aqm, AP_DOMAINS,
- &ap_perms_mutex);
+ ap_parse_mask_str(aqm_str, ap_perms.aqm, AP_DOMAINS,
+ &ap_perms_mutex);
}
}
@@ -1533,7 +1532,7 @@ static int __init ap_module_init(void)
return -ENODEV;
}
- /* set up the AP permissions (ap and aq masks) */
+ /* set up the AP permissions (ioctls, ap and aq masks) */
ap_perms_init();
/* Get AP configuration data if available */
diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h
index 5246cd8c16a6..3eed1b36c876 100644
--- a/drivers/s390/crypto/ap_bus.h
+++ b/drivers/s390/crypto/ap_bus.h
@@ -20,6 +20,7 @@
#define AP_DEVICES 256 /* Number of AP devices. */
#define AP_DOMAINS 256 /* Number of AP domains. */
+#define AP_IOCTLS 256 /* Number of ioctls. */
#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. */
@@ -257,6 +258,14 @@ void ap_queue_resume(struct ap_device *ap_dev);
struct ap_card *ap_card_create(int id, int queue_depth, int raw_device_type,
int comp_device_type, unsigned int functions);
+struct ap_perms {
+ unsigned long ioctlm[BITS_TO_LONGS(AP_IOCTLS)];
+ unsigned long apm[BITS_TO_LONGS(AP_DEVICES)];
+ unsigned long aqm[BITS_TO_LONGS(AP_DOMAINS)];
+};
+extern struct ap_perms ap_perms;
+extern struct mutex ap_perms_mutex;
+
/*
* check APQN for owned/reserved by ap bus and default driver(s).
* Checks if this APQN is or will be in use by the ap bus
@@ -280,4 +289,20 @@ int ap_owned_by_def_drv(int card, int queue);
int ap_apqn_in_matrix_owned_by_def_drv(unsigned long *apm,
unsigned long *aqm);
+/*
+ * ap_parse_mask_str() - helper function to parse a bitmap string
+ * and clear/set the bits in the bitmap accordingly. The string may be
+ * given as absolute value, a hex string like 0x1F2E3D4C5B6A" simple
+ * overwriting the current content of the bitmap. Or as relative string
+ * like "+1-16,-32,-0x40,+128" where only single bits or ranges of
+ * bits are cleared or set. Distinction is done based on the very
+ * first character which may be '+' or '-' for the relative string
+ * and othewise assume to be an absolute value string. If parsing fails
+ * a negative errno value is returned. All arguments and bitmaps are
+ * big endian order.
+ */
+int ap_parse_mask_str(const char *str,
+ unsigned long *bitmap, int bits,
+ struct mutex *lock);
+
#endif /* _AP_BUS_H_ */
diff --git a/drivers/s390/crypto/pkey_api.c b/drivers/s390/crypto/pkey_api.c
index 1b4001e0285f..2f92bbed4bf6 100644
--- a/drivers/s390/crypto/pkey_api.c
+++ b/drivers/s390/crypto/pkey_api.c
@@ -16,9 +16,12 @@
#include <linux/slab.h>
#include <linux/kallsyms.h>
#include <linux/debugfs.h>
+#include <linux/random.h>
+#include <linux/cpufeature.h>
#include <asm/zcrypt.h>
#include <asm/cpacf.h>
#include <asm/pkey.h>
+#include <crypto/aes.h>
#include "zcrypt_api.h"
@@ -32,6 +35,9 @@ MODULE_DESCRIPTION("s390 protected key interface");
/* Size of vardata block used for some of the cca requests/replies */
#define VARDATASIZE 4096
+/* mask of available pckmo subfunctions, fetched once at module init */
+static cpacf_mask_t pckmo_functions;
+
/*
* debug feature data and functions
*/
@@ -55,6 +61,24 @@ static void __exit pkey_debug_exit(void)
debug_unregister(debug_info);
}
+/* Key token types */
+#define TOKTYPE_NON_CCA 0x00 /* Non-CCA key token */
+#define TOKTYPE_CCA_INTERNAL 0x01 /* CCA internal key token */
+
+/* For TOKTYPE_NON_CCA: */
+#define TOKVER_PROTECTED_KEY 0x01 /* Protected key token */
+
+/* For TOKTYPE_CCA_INTERNAL: */
+#define TOKVER_CCA_AES 0x04 /* CCA AES key token */
+
+/* header part of a key token */
+struct keytoken_header {
+ u8 type; /* one of the TOKTYPE values */
+ u8 res0[3];
+ u8 version; /* one of the TOKVER values */
+ u8 res1[3];
+} __packed;
+
/* inside view of a secure key token (only type 0x01 version 0x04) */
struct secaeskeytoken {
u8 type; /* 0x01 for internal key token */
@@ -71,6 +95,17 @@ struct secaeskeytoken {
u8 tvv[4]; /* token validation value */
} __packed;
+/* inside view of a protected key token (only type 0x00 version 0x01) */
+struct protaeskeytoken {
+ u8 type; /* 0x00 for PAES specific key tokens */
+ u8 res0[3];
+ u8 version; /* should be 0x01 for protected AES key token */
+ u8 res1[3];
+ u32 keytype; /* key type, one of the PKEY_KEYTYPE values */
+ u32 len; /* bytes actually stored in protkey[] */
+ u8 protkey[MAXPROTKEYSIZE]; /* the protected key blob */
+} __packed;
+
/*
* Simple check if the token is a valid CCA secure AES key
* token. If keybitsize is given, the bitsize of the key is
@@ -80,16 +115,16 @@ static int check_secaeskeytoken(const u8 *token, int keybitsize)
{
struct secaeskeytoken *t = (struct secaeskeytoken *) token;
- if (t->type != 0x01) {
+ if (t->type != TOKTYPE_CCA_INTERNAL) {
DEBUG_ERR(
- "%s secure token check failed, type mismatch 0x%02x != 0x01\n",
- __func__, (int) t->type);
+ "%s secure token check failed, type mismatch 0x%02x != 0x%02x\n",
+ __func__, (int) t->type, TOKTYPE_CCA_INTERNAL);
return -EINVAL;
}
- if (t->version != 0x04) {
+ if (t->version != TOKVER_CCA_AES) {
DEBUG_ERR(
- "%s secure token check failed, version mismatch 0x%02x != 0x04\n",
- __func__, (int) t->version);
+ "%s secure token check failed, version mismatch 0x%02x != 0x%02x\n",
+ __func__, (int) t->version, TOKVER_CCA_AES);
return -EINVAL;
}
if (keybitsize > 0 && t->bitsize != keybitsize) {
@@ -647,6 +682,16 @@ int pkey_clr2protkey(u32 keytype,
return -EINVAL;
}
+ /*
+ * Check if the needed pckmo subfunction is available.
+ * These subfunctions can be enabled/disabled by customers
+ * in the LPAR profile or may even change on the fly.
+ */
+ if (!cpacf_test_func(&pckmo_functions, fc)) {
+ DEBUG_ERR("%s pckmo functions not available\n", __func__);
+ return -EOPNOTSUPP;
+ }
+
/* prepare param block */
memset(paramblock, 0, sizeof(paramblock));
memcpy(paramblock, clrkey->clrkey, keysize);
@@ -1052,6 +1097,166 @@ out:
EXPORT_SYMBOL(pkey_verifykey);
/*
+ * Generate a random protected key
+ */
+int pkey_genprotkey(__u32 keytype, struct pkey_protkey *protkey)
+{
+ struct pkey_clrkey clrkey;
+ int keysize;
+ int rc;
+
+ switch (keytype) {
+ case PKEY_KEYTYPE_AES_128:
+ keysize = 16;
+ break;
+ case PKEY_KEYTYPE_AES_192:
+ keysize = 24;
+ break;
+ case PKEY_KEYTYPE_AES_256:
+ keysize = 32;
+ break;
+ default:
+ DEBUG_ERR("%s unknown/unsupported keytype %d\n", __func__,
+ keytype);
+ return -EINVAL;
+ }
+
+ /* generate a dummy random clear key */
+ get_random_bytes(clrkey.clrkey, keysize);
+
+ /* convert it to a dummy protected key */
+ rc = pkey_clr2protkey(keytype, &clrkey, protkey);
+ if (rc)
+ return rc;
+
+ /* replace the key part of the protected key with random bytes */
+ get_random_bytes(protkey->protkey, keysize);
+
+ return 0;
+}
+EXPORT_SYMBOL(pkey_genprotkey);
+
+/*
+ * Verify if a protected key is still valid
+ */
+int pkey_verifyprotkey(const struct pkey_protkey *protkey)
+{
+ unsigned long fc;
+ struct {
+ u8 iv[AES_BLOCK_SIZE];
+ u8 key[MAXPROTKEYSIZE];
+ } param;
+ u8 null_msg[AES_BLOCK_SIZE];
+ u8 dest_buf[AES_BLOCK_SIZE];
+ unsigned int k;
+
+ switch (protkey->type) {
+ case PKEY_KEYTYPE_AES_128:
+ fc = CPACF_KMC_PAES_128;
+ break;
+ case PKEY_KEYTYPE_AES_192:
+ fc = CPACF_KMC_PAES_192;
+ break;
+ case PKEY_KEYTYPE_AES_256:
+ fc = CPACF_KMC_PAES_256;
+ break;
+ default:
+ DEBUG_ERR("%s unknown/unsupported keytype %d\n", __func__,
+ protkey->type);
+ return -EINVAL;
+ }
+
+ memset(null_msg, 0, sizeof(null_msg));
+
+ memset(param.iv, 0, sizeof(param.iv));
+ memcpy(param.key, protkey->protkey, sizeof(param.key));
+
+ k = cpacf_kmc(fc | CPACF_ENCRYPT, &param, null_msg, dest_buf,
+ sizeof(null_msg));
+ if (k != sizeof(null_msg)) {
+ DEBUG_ERR("%s protected key is not valid\n", __func__);
+ return -EKEYREJECTED;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(pkey_verifyprotkey);
+
+/*
+ * Transform a non-CCA key token into a protected key
+ */
+static int pkey_nonccatok2pkey(const __u8 *key, __u32 keylen,
+ struct pkey_protkey *protkey)
+{
+ struct keytoken_header *hdr = (struct keytoken_header *)key;
+ struct protaeskeytoken *t;
+
+ switch (hdr->version) {
+ case TOKVER_PROTECTED_KEY:
+ if (keylen != sizeof(struct protaeskeytoken))
+ return -EINVAL;
+
+ t = (struct protaeskeytoken *)key;
+ protkey->len = t->len;
+ protkey->type = t->keytype;
+ memcpy(protkey->protkey, t->protkey,
+ sizeof(protkey->protkey));
+
+ return pkey_verifyprotkey(protkey);
+ default:
+ DEBUG_ERR("%s unknown/unsupported non-CCA token version %d\n",
+ __func__, hdr->version);
+ return -EINVAL;
+ }
+}
+
+/*
+ * Transform a CCA internal key token into a protected key
+ */
+static int pkey_ccainttok2pkey(const __u8 *key, __u32 keylen,
+ struct pkey_protkey *protkey)
+{
+ struct keytoken_header *hdr = (struct keytoken_header *)key;
+
+ switch (hdr->version) {
+ case TOKVER_CCA_AES:
+ if (keylen != sizeof(struct secaeskeytoken))
+ return -EINVAL;
+
+ return pkey_skey2pkey((struct pkey_seckey *)key,
+ protkey);
+ default:
+ DEBUG_ERR("%s unknown/unsupported CCA internal token version %d\n",
+ __func__, hdr->version);
+ return -EINVAL;
+ }
+}
+
+/*
+ * Transform a key blob (of any type) into a protected key
+ */
+int pkey_keyblob2pkey(const __u8 *key, __u32 keylen,
+ struct pkey_protkey *protkey)
+{
+ struct keytoken_header *hdr = (struct keytoken_header *)key;
+
+ if (keylen < sizeof(struct keytoken_header))
+ return -EINVAL;
+
+ switch (hdr->type) {
+ case TOKTYPE_NON_CCA:
+ return pkey_nonccatok2pkey(key, keylen, protkey);
+ case TOKTYPE_CCA_INTERNAL:
+ return pkey_ccainttok2pkey(key, keylen, protkey);
+ default:
+ DEBUG_ERR("%s unknown/unsupported blob type %d\n", __func__,
+ hdr->type);
+ return -EINVAL;
+ }
+}
+EXPORT_SYMBOL(pkey_keyblob2pkey);
+
+/*
* File io functions
*/
@@ -1167,6 +1372,58 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
return -EFAULT;
break;
}
+ case PKEY_GENPROTK: {
+ struct pkey_genprotk __user *ugp = (void __user *) arg;
+ struct pkey_genprotk kgp;
+
+ if (copy_from_user(&kgp, ugp, sizeof(kgp)))
+ return -EFAULT;
+ rc = pkey_genprotkey(kgp.keytype, &kgp.protkey);
+ DEBUG_DBG("%s pkey_genprotkey()=%d\n", __func__, rc);
+ if (rc)
+ break;
+ if (copy_to_user(ugp, &kgp, sizeof(kgp)))
+ return -EFAULT;
+ break;
+ }
+ case PKEY_VERIFYPROTK: {
+ struct pkey_verifyprotk __user *uvp = (void __user *) arg;
+ struct pkey_verifyprotk kvp;
+
+ if (copy_from_user(&kvp, uvp, sizeof(kvp)))
+ return -EFAULT;
+ rc = pkey_verifyprotkey(&kvp.protkey);
+ DEBUG_DBG("%s pkey_verifyprotkey()=%d\n", __func__, rc);
+ break;
+ }
+ case PKEY_KBLOB2PROTK: {
+ struct pkey_kblob2pkey __user *utp = (void __user *) arg;
+ struct pkey_kblob2pkey ktp;
+ __u8 __user *ukey;
+ __u8 *kkey;
+
+ if (copy_from_user(&ktp, utp, sizeof(ktp)))
+ return -EFAULT;
+ if (ktp.keylen < MINKEYBLOBSIZE ||
+ ktp.keylen > MAXKEYBLOBSIZE)
+ return -EINVAL;
+ ukey = ktp.key;
+ kkey = kmalloc(ktp.keylen, GFP_KERNEL);
+ if (kkey == NULL)
+ return -ENOMEM;
+ if (copy_from_user(kkey, ukey, ktp.keylen)) {
+ kfree(kkey);
+ return -EFAULT;
+ }
+ rc = pkey_keyblob2pkey(kkey, ktp.keylen, &ktp.protkey);
+ DEBUG_DBG("%s pkey_keyblob2pkey()=%d\n", __func__, rc);
+ kfree(kkey);
+ if (rc)
+ break;
+ if (copy_to_user(utp, &ktp, sizeof(ktp)))
+ return -EFAULT;
+ break;
+ }
default:
/* unknown/unsupported ioctl cmd */
return -ENOTTY;
@@ -1178,6 +1435,236 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
/*
* Sysfs and file io operations
*/
+
+/*
+ * Sysfs attribute read function for all protected key binary attributes.
+ * The implementation can not deal with partial reads, because a new random
+ * protected key blob is generated with each read. In case of partial reads
+ * (i.e. off != 0 or count < key blob size) -EINVAL is returned.
+ */
+static ssize_t pkey_protkey_aes_attr_read(u32 keytype, bool is_xts, char *buf,
+ loff_t off, size_t count)
+{
+ struct protaeskeytoken protkeytoken;
+ struct pkey_protkey protkey;
+ int rc;
+
+ if (off != 0 || count < sizeof(protkeytoken))
+ return -EINVAL;
+ if (is_xts)
+ if (count < 2 * sizeof(protkeytoken))
+ return -EINVAL;
+
+ memset(&protkeytoken, 0, sizeof(protkeytoken));
+ protkeytoken.type = TOKTYPE_NON_CCA;
+ protkeytoken.version = TOKVER_PROTECTED_KEY;
+ protkeytoken.keytype = keytype;
+
+ rc = pkey_genprotkey(protkeytoken.keytype, &protkey);
+ if (rc)
+ return rc;
+
+ protkeytoken.len = protkey.len;
+ memcpy(&protkeytoken.protkey, &protkey.protkey, protkey.len);
+
+ memcpy(buf, &protkeytoken, sizeof(protkeytoken));
+
+ if (is_xts) {
+ rc = pkey_genprotkey(protkeytoken.keytype, &protkey);
+ if (rc)
+ return rc;
+
+ protkeytoken.len = protkey.len;
+ memcpy(&protkeytoken.protkey, &protkey.protkey, protkey.len);
+
+ memcpy(buf + sizeof(protkeytoken), &protkeytoken,
+ sizeof(protkeytoken));
+
+ return 2 * sizeof(protkeytoken);
+ }
+
+ return sizeof(protkeytoken);
+}
+
+static ssize_t protkey_aes_128_read(struct file *filp,
+ struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t off,
+ size_t count)
+{
+ return pkey_protkey_aes_attr_read(PKEY_KEYTYPE_AES_128, false, buf,
+ off, count);
+}
+
+static ssize_t protkey_aes_192_read(struct file *filp,
+ struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t off,
+ size_t count)
+{
+ return pkey_protkey_aes_attr_read(PKEY_KEYTYPE_AES_192, false, buf,
+ off, count);
+}
+
+static ssize_t protkey_aes_256_read(struct file *filp,
+ struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t off,
+ size_t count)
+{
+ return pkey_protkey_aes_attr_read(PKEY_KEYTYPE_AES_256, false, buf,
+ off, count);
+}
+
+static ssize_t protkey_aes_128_xts_read(struct file *filp,
+ struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t off,
+ size_t count)
+{
+ return pkey_protkey_aes_attr_read(PKEY_KEYTYPE_AES_128, true, buf,
+ off, count);
+}
+
+static ssize_t protkey_aes_256_xts_read(struct file *filp,
+ struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t off,
+ size_t count)
+{
+ return pkey_protkey_aes_attr_read(PKEY_KEYTYPE_AES_256, true, buf,
+ off, count);
+}
+
+static BIN_ATTR_RO(protkey_aes_128, sizeof(struct protaeskeytoken));
+static BIN_ATTR_RO(protkey_aes_192, sizeof(struct protaeskeytoken));
+static BIN_ATTR_RO(protkey_aes_256, sizeof(struct protaeskeytoken));
+static BIN_ATTR_RO(protkey_aes_128_xts, 2 * sizeof(struct protaeskeytoken));
+static BIN_ATTR_RO(protkey_aes_256_xts, 2 * sizeof(struct protaeskeytoken));
+
+static struct bin_attribute *protkey_attrs[] = {
+ &bin_attr_protkey_aes_128,
+ &bin_attr_protkey_aes_192,
+ &bin_attr_protkey_aes_256,
+ &bin_attr_protkey_aes_128_xts,
+ &bin_attr_protkey_aes_256_xts,
+ NULL
+};
+
+static struct attribute_group protkey_attr_group = {
+ .name = "protkey",
+ .bin_attrs = protkey_attrs,
+};
+
+/*
+ * Sysfs attribute read function for all secure key ccadata binary attributes.
+ * The implementation can not deal with partial reads, because a new random
+ * protected key blob is generated with each read. In case of partial reads
+ * (i.e. off != 0 or count < key blob size) -EINVAL is returned.
+ */
+static ssize_t pkey_ccadata_aes_attr_read(u32 keytype, bool is_xts, char *buf,
+ loff_t off, size_t count)
+{
+ int rc;
+
+ if (off != 0 || count < sizeof(struct secaeskeytoken))
+ return -EINVAL;
+ if (is_xts)
+ if (count < 2 * sizeof(struct secaeskeytoken))
+ return -EINVAL;
+
+ rc = pkey_genseckey(-1, -1, keytype, (struct pkey_seckey *)buf);
+ if (rc)
+ return rc;
+
+ if (is_xts) {
+ buf += sizeof(struct pkey_seckey);
+ rc = pkey_genseckey(-1, -1, keytype, (struct pkey_seckey *)buf);
+ if (rc)
+ return rc;
+
+ return 2 * sizeof(struct secaeskeytoken);
+ }
+
+ return sizeof(struct secaeskeytoken);
+}
+
+static ssize_t ccadata_aes_128_read(struct file *filp,
+ struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t off,
+ size_t count)
+{
+ return pkey_ccadata_aes_attr_read(PKEY_KEYTYPE_AES_128, false, buf,
+ off, count);
+}
+
+static ssize_t ccadata_aes_192_read(struct file *filp,
+ struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t off,
+ size_t count)
+{
+ return pkey_ccadata_aes_attr_read(PKEY_KEYTYPE_AES_192, false, buf,
+ off, count);
+}
+
+static ssize_t ccadata_aes_256_read(struct file *filp,
+ struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t off,
+ size_t count)
+{
+ return pkey_ccadata_aes_attr_read(PKEY_KEYTYPE_AES_256, false, buf,
+ off, count);
+}
+
+static ssize_t ccadata_aes_128_xts_read(struct file *filp,
+ struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t off,
+ size_t count)
+{
+ return pkey_ccadata_aes_attr_read(PKEY_KEYTYPE_AES_128, true, buf,
+ off, count);
+}
+
+static ssize_t ccadata_aes_256_xts_read(struct file *filp,
+ struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t off,
+ size_t count)
+{
+ return pkey_ccadata_aes_attr_read(PKEY_KEYTYPE_AES_256, true, buf,
+ off, count);
+}
+
+static BIN_ATTR_RO(ccadata_aes_128, sizeof(struct secaeskeytoken));
+static BIN_ATTR_RO(ccadata_aes_192, sizeof(struct secaeskeytoken));
+static BIN_ATTR_RO(ccadata_aes_256, sizeof(struct secaeskeytoken));
+static BIN_ATTR_RO(ccadata_aes_128_xts, 2 * sizeof(struct secaeskeytoken));
+static BIN_ATTR_RO(ccadata_aes_256_xts, 2 * sizeof(struct secaeskeytoken));
+
+static struct bin_attribute *ccadata_attrs[] = {
+ &bin_attr_ccadata_aes_128,
+ &bin_attr_ccadata_aes_192,
+ &bin_attr_ccadata_aes_256,
+ &bin_attr_ccadata_aes_128_xts,
+ &bin_attr_ccadata_aes_256_xts,
+ NULL
+};
+
+static struct attribute_group ccadata_attr_group = {
+ .name = "ccadata",
+ .bin_attrs = ccadata_attrs,
+};
+
+static const struct attribute_group *pkey_attr_groups[] = {
+ &protkey_attr_group,
+ &ccadata_attr_group,
+ NULL,
+};
+
static const struct file_operations pkey_fops = {
.owner = THIS_MODULE,
.open = nonseekable_open,
@@ -1190,6 +1677,7 @@ static struct miscdevice pkey_dev = {
.minor = MISC_DYNAMIC_MINOR,
.mode = 0666,
.fops = &pkey_fops,
+ .groups = pkey_attr_groups,
};
/*
@@ -1197,14 +1685,23 @@ static struct miscdevice pkey_dev = {
*/
static int __init pkey_init(void)
{
- cpacf_mask_t pckmo_functions;
+ cpacf_mask_t kmc_functions;
- /* check for pckmo instructions available */
+ /*
+ * The pckmo instruction should be available - even if we don't
+ * actually invoke it. This instruction comes with MSA 3 which
+ * is also the minimum level for the kmc instructions which
+ * are able to work with protected keys.
+ */
if (!cpacf_query(CPACF_PCKMO, &pckmo_functions))
return -EOPNOTSUPP;
- if (!cpacf_test_func(&pckmo_functions, CPACF_PCKMO_ENC_AES_128_KEY) ||
- !cpacf_test_func(&pckmo_functions, CPACF_PCKMO_ENC_AES_192_KEY) ||
- !cpacf_test_func(&pckmo_functions, CPACF_PCKMO_ENC_AES_256_KEY))
+
+ /* check for kmc instructions available */
+ if (!cpacf_query(CPACF_KMC, &kmc_functions))
+ return -EOPNOTSUPP;
+ if (!cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_128) ||
+ !cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_192) ||
+ !cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_256))
return -EOPNOTSUPP;
pkey_debug_init();
@@ -1222,5 +1719,5 @@ static void __exit pkey_exit(void)
pkey_debug_exit();
}
-module_init(pkey_init);
+module_cpu_feature_match(MSA, pkey_init);
module_exit(pkey_exit);
diff --git a/drivers/s390/crypto/vfio_ap_drv.c b/drivers/s390/crypto/vfio_ap_drv.c
new file mode 100644
index 000000000000..7667b38728f0
--- /dev/null
+++ b/drivers/s390/crypto/vfio_ap_drv.c
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * VFIO based AP device driver
+ *
+ * Copyright IBM Corp. 2018
+ *
+ * Author(s): Tony Krowiak <akrowiak@linux.ibm.com>
+ */
+
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include "vfio_ap_private.h"
+
+#define VFIO_AP_ROOT_NAME "vfio_ap"
+#define VFIO_AP_DEV_TYPE_NAME "ap_matrix"
+#define VFIO_AP_DEV_NAME "matrix"
+
+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;
+
+static struct device_type vfio_ap_dev_type = {
+ .name = VFIO_AP_DEV_TYPE_NAME,
+};
+
+struct ap_matrix_dev *matrix_dev;
+
+/* Only type 10 adapters (CEX4 and later) are supported
+ * by the AP matrix device driver
+ */
+static struct ap_device_id ap_queue_ids[] = {
+ { .dev_type = AP_DEVICE_TYPE_CEX4,
+ .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
+ { .dev_type = AP_DEVICE_TYPE_CEX5,
+ .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
+ { .dev_type = AP_DEVICE_TYPE_CEX6,
+ .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
+ { /* end of sibling */ },
+};
+
+MODULE_DEVICE_TABLE(vfio_ap, ap_queue_ids);
+
+static int vfio_ap_queue_dev_probe(struct ap_device *apdev)
+{
+ return 0;
+}
+
+static void vfio_ap_queue_dev_remove(struct ap_device *apdev)
+{
+ /* Nothing to do yet */
+}
+
+static void vfio_ap_matrix_dev_release(struct device *dev)
+{
+ struct ap_matrix_dev *matrix_dev = dev_get_drvdata(dev);
+
+ kfree(matrix_dev);
+}
+
+static int vfio_ap_matrix_dev_create(void)
+{
+ int ret;
+ struct device *root_device;
+
+ root_device = root_device_register(VFIO_AP_ROOT_NAME);
+ if (IS_ERR(root_device))
+ return PTR_ERR(root_device);
+
+ matrix_dev = kzalloc(sizeof(*matrix_dev), GFP_KERNEL);
+ if (!matrix_dev) {
+ ret = -ENOMEM;
+ goto matrix_alloc_err;
+ }
+
+ /* Fill in config info via PQAP(QCI), if available */
+ if (test_facility(12)) {
+ ret = ap_qci(&matrix_dev->info);
+ if (ret)
+ goto matrix_alloc_err;
+ }
+
+ mutex_init(&matrix_dev->lock);
+ INIT_LIST_HEAD(&matrix_dev->mdev_list);
+
+ matrix_dev->device.type = &vfio_ap_dev_type;
+ dev_set_name(&matrix_dev->device, "%s", VFIO_AP_DEV_NAME);
+ matrix_dev->device.parent = root_device;
+ matrix_dev->device.release = vfio_ap_matrix_dev_release;
+ matrix_dev->device.driver = &vfio_ap_drv.driver;
+
+ ret = device_register(&matrix_dev->device);
+ if (ret)
+ goto matrix_reg_err;
+
+ return 0;
+
+matrix_reg_err:
+ put_device(&matrix_dev->device);
+matrix_alloc_err:
+ root_device_unregister(root_device);
+
+ return ret;
+}
+
+static void vfio_ap_matrix_dev_destroy(void)
+{
+ device_unregister(&matrix_dev->device);
+ root_device_unregister(matrix_dev->device.parent);
+}
+
+static int __init vfio_ap_init(void)
+{
+ int ret;
+
+ /* If there are no AP instructions, there is nothing to pass through. */
+ if (!ap_instructions_available())
+ return -ENODEV;
+
+ ret = vfio_ap_matrix_dev_create();
+ 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();
+ return ret;
+ }
+
+ ret = vfio_ap_mdev_register();
+ if (ret) {
+ ap_driver_unregister(&vfio_ap_drv);
+ vfio_ap_matrix_dev_destroy();
+
+ return ret;
+ }
+
+ return 0;
+}
+
+static void __exit vfio_ap_exit(void)
+{
+ vfio_ap_mdev_unregister();
+ ap_driver_unregister(&vfio_ap_drv);
+ vfio_ap_matrix_dev_destroy();
+}
+
+module_init(vfio_ap_init);
+module_exit(vfio_ap_exit);
diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c
new file mode 100644
index 000000000000..272ef427dcc0
--- /dev/null
+++ b/drivers/s390/crypto/vfio_ap_ops.c
@@ -0,0 +1,939 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Adjunct processor matrix VFIO device driver callbacks.
+ *
+ * Copyright IBM Corp. 2018
+ *
+ * Author(s): Tony Krowiak <akrowiak@linux.ibm.com>
+ * Halil Pasic <pasic@linux.ibm.com>
+ * Pierre Morel <pmorel@linux.ibm.com>
+ */
+#include <linux/string.h>
+#include <linux/vfio.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/ctype.h>
+#include <linux/bitops.h>
+#include <linux/kvm_host.h>
+#include <linux/module.h>
+#include <asm/kvm.h>
+#include <asm/zcrypt.h>
+
+#include "vfio_ap_private.h"
+
+#define VFIO_AP_MDEV_TYPE_HWVIRT "passthrough"
+#define VFIO_AP_MDEV_NAME_HWVIRT "VFIO AP Passthrough Device"
+
+static void vfio_ap_matrix_init(struct ap_config_info *info,
+ struct ap_matrix *matrix)
+{
+ matrix->apm_max = info->apxa ? info->Na : 63;
+ matrix->aqm_max = info->apxa ? info->Nd : 15;
+ matrix->adm_max = info->apxa ? info->Nd : 15;
+}
+
+static int vfio_ap_mdev_create(struct kobject *kobj, struct mdev_device *mdev)
+{
+ struct ap_matrix_mdev *matrix_mdev;
+
+ if ((atomic_dec_if_positive(&matrix_dev->available_instances) < 0))
+ return -EPERM;
+
+ matrix_mdev = kzalloc(sizeof(*matrix_mdev), GFP_KERNEL);
+ if (!matrix_mdev) {
+ atomic_inc(&matrix_dev->available_instances);
+ return -ENOMEM;
+ }
+
+ vfio_ap_matrix_init(&matrix_dev->info, &matrix_mdev->matrix);
+ mdev_set_drvdata(mdev, matrix_mdev);
+ mutex_lock(&matrix_dev->lock);
+ list_add(&matrix_mdev->node, &matrix_dev->mdev_list);
+ mutex_unlock(&matrix_dev->lock);
+
+ return 0;
+}
+
+static int vfio_ap_mdev_remove(struct mdev_device *mdev)
+{
+ struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev);
+
+ if (matrix_mdev->kvm)
+ return -EBUSY;
+
+ mutex_lock(&matrix_dev->lock);
+ list_del(&matrix_mdev->node);
+ mutex_unlock(&matrix_dev->lock);
+
+ kfree(matrix_mdev);
+ mdev_set_drvdata(mdev, NULL);
+ atomic_inc(&matrix_dev->available_instances);
+
+ return 0;
+}
+
+static ssize_t name_show(struct kobject *kobj, struct device *dev, char *buf)
+{
+ return sprintf(buf, "%s\n", VFIO_AP_MDEV_NAME_HWVIRT);
+}
+
+static MDEV_TYPE_ATTR_RO(name);
+
+static ssize_t available_instances_show(struct kobject *kobj,
+ struct device *dev, char *buf)
+{
+ return sprintf(buf, "%d\n",
+ atomic_read(&matrix_dev->available_instances));
+}
+
+static MDEV_TYPE_ATTR_RO(available_instances);
+
+static ssize_t device_api_show(struct kobject *kobj, struct device *dev,
+ char *buf)
+{
+ return sprintf(buf, "%s\n", VFIO_DEVICE_API_AP_STRING);
+}
+
+static MDEV_TYPE_ATTR_RO(device_api);
+
+static struct attribute *vfio_ap_mdev_type_attrs[] = {
+ &mdev_type_attr_name.attr,
+ &mdev_type_attr_device_api.attr,
+ &mdev_type_attr_available_instances.attr,
+ NULL,
+};
+
+static struct attribute_group vfio_ap_mdev_hwvirt_type_group = {
+ .name = VFIO_AP_MDEV_TYPE_HWVIRT,
+ .attrs = vfio_ap_mdev_type_attrs,
+};
+
+static struct attribute_group *vfio_ap_mdev_type_groups[] = {
+ &vfio_ap_mdev_hwvirt_type_group,
+ NULL,
+};
+
+struct vfio_ap_queue_reserved {
+ unsigned long *apid;
+ unsigned long *apqi;
+ bool reserved;
+};
+
+/**
+ * vfio_ap_has_queue
+ *
+ * @dev: an AP queue device
+ * @data: a struct vfio_ap_queue_reserved reference
+ *
+ * Flags whether the AP queue device (@dev) has a queue ID containing the APQN,
+ * apid or apqi specified in @data:
+ *
+ * - If @data contains both an apid and apqi value, then @data will be flagged
+ * as reserved if the APID and APQI fields for the AP queue device matches
+ *
+ * - If @data contains only an apid value, @data will be flagged as
+ * reserved if the APID field in the AP queue device matches
+ *
+ * - If @data contains only an apqi value, @data will be flagged as
+ * reserved if the APQI field in the AP queue device matches
+ *
+ * Returns 0 to indicate the input to function succeeded. Returns -EINVAL if
+ * @data does not contain either an apid or apqi.
+ */
+static int vfio_ap_has_queue(struct device *dev, void *data)
+{
+ struct vfio_ap_queue_reserved *qres = data;
+ struct ap_queue *ap_queue = to_ap_queue(dev);
+ ap_qid_t qid;
+ unsigned long id;
+
+ if (qres->apid && qres->apqi) {
+ qid = AP_MKQID(*qres->apid, *qres->apqi);
+ if (qid == ap_queue->qid)
+ qres->reserved = true;
+ } else if (qres->apid && !qres->apqi) {
+ id = AP_QID_CARD(ap_queue->qid);
+ if (id == *qres->apid)
+ qres->reserved = true;
+ } else if (!qres->apid && qres->apqi) {
+ id = AP_QID_QUEUE(ap_queue->qid);
+ if (id == *qres->apqi)
+ qres->reserved = true;
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * vfio_ap_verify_queue_reserved
+ *
+ * @matrix_dev: a mediated matrix device
+ * @apid: an AP adapter ID
+ * @apqi: an AP queue index
+ *
+ * Verifies that the AP queue with @apid/@apqi is reserved by the VFIO AP device
+ * driver according to the following rules:
+ *
+ * - If both @apid and @apqi are not NULL, then there must be an AP queue
+ * device bound to the vfio_ap driver with the APQN identified by @apid and
+ * @apqi
+ *
+ * - If only @apid is not NULL, then there must be an AP queue device bound
+ * to the vfio_ap driver with an APQN containing @apid
+ *
+ * - If only @apqi is not NULL, then there must be an AP queue device bound
+ * to the vfio_ap driver with an APQN containing @apqi
+ *
+ * Returns 0 if the AP queue is reserved; otherwise, returns -EADDRNOTAVAIL.
+ */
+static int vfio_ap_verify_queue_reserved(unsigned long *apid,
+ unsigned long *apqi)
+{
+ int ret;
+ struct vfio_ap_queue_reserved qres;
+
+ qres.apid = apid;
+ qres.apqi = apqi;
+ qres.reserved = false;
+
+ ret = driver_for_each_device(matrix_dev->device.driver, NULL, &qres,
+ vfio_ap_has_queue);
+ if (ret)
+ return ret;
+
+ if (qres.reserved)
+ return 0;
+
+ return -EADDRNOTAVAIL;
+}
+
+static int
+vfio_ap_mdev_verify_queues_reserved_for_apid(struct ap_matrix_mdev *matrix_mdev,
+ unsigned long apid)
+{
+ int ret;
+ unsigned long apqi;
+ unsigned long nbits = matrix_mdev->matrix.aqm_max + 1;
+
+ if (find_first_bit_inv(matrix_mdev->matrix.aqm, nbits) >= nbits)
+ return vfio_ap_verify_queue_reserved(&apid, NULL);
+
+ for_each_set_bit_inv(apqi, matrix_mdev->matrix.aqm, nbits) {
+ ret = vfio_ap_verify_queue_reserved(&apid, &apqi);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * vfio_ap_mdev_verify_no_sharing
+ *
+ * Verifies that the APQNs derived from the cross product of the AP adapter IDs
+ * and AP queue indexes comprising the AP matrix are not configured for another
+ * mediated device. AP queue sharing is not allowed.
+ *
+ * @matrix_mdev: the mediated matrix device
+ *
+ * Returns 0 if the APQNs are not shared, otherwise; returns -EADDRINUSE.
+ */
+static int vfio_ap_mdev_verify_no_sharing(struct ap_matrix_mdev *matrix_mdev)
+{
+ struct ap_matrix_mdev *lstdev;
+ DECLARE_BITMAP(apm, AP_DEVICES);
+ DECLARE_BITMAP(aqm, AP_DOMAINS);
+
+ list_for_each_entry(lstdev, &matrix_dev->mdev_list, node) {
+ if (matrix_mdev == lstdev)
+ continue;
+
+ memset(apm, 0, sizeof(apm));
+ memset(aqm, 0, sizeof(aqm));
+
+ /*
+ * We work on full longs, as we can only exclude the leftover
+ * bits in non-inverse order. The leftover is all zeros.
+ */
+ if (!bitmap_and(apm, matrix_mdev->matrix.apm,
+ lstdev->matrix.apm, AP_DEVICES))
+ continue;
+
+ if (!bitmap_and(aqm, matrix_mdev->matrix.aqm,
+ lstdev->matrix.aqm, AP_DOMAINS))
+ continue;
+
+ return -EADDRINUSE;
+ }
+
+ return 0;
+}
+
+/**
+ * assign_adapter_store
+ *
+ * @dev: the matrix device
+ * @attr: the mediated matrix device's assign_adapter attribute
+ * @buf: a buffer containing the AP adapter number (APID) to
+ * be assigned
+ * @count: the number of bytes in @buf
+ *
+ * Parses the APID from @buf and sets the corresponding bit in the mediated
+ * matrix device's APM.
+ *
+ * Returns the number of bytes processed if the APID is valid; otherwise,
+ * returns one of the following errors:
+ *
+ * 1. -EINVAL
+ * The APID is not a valid number
+ *
+ * 2. -ENODEV
+ * The APID exceeds the maximum value configured for the system
+ *
+ * 3. -EADDRNOTAVAIL
+ * An APQN derived from the cross product of the APID being assigned
+ * and the APQIs previously assigned is not bound to the vfio_ap device
+ * driver; or, if no APQIs have yet been assigned, the APID is not
+ * contained in an APQN bound to the vfio_ap device driver.
+ *
+ * 4. -EADDRINUSE
+ * An APQN derived from the cross product of the APID being assigned
+ * and the APQIs previously assigned is being used by another mediated
+ * matrix device
+ */
+static ssize_t assign_adapter_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+ unsigned long apid;
+ struct mdev_device *mdev = mdev_from_dev(dev);
+ struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev);
+
+ /* If the guest is running, disallow assignment of adapter */
+ if (matrix_mdev->kvm)
+ return -EBUSY;
+
+ ret = kstrtoul(buf, 0, &apid);
+ if (ret)
+ return ret;
+
+ if (apid > matrix_mdev->matrix.apm_max)
+ return -ENODEV;
+
+ /*
+ * Set the bit in the AP mask (APM) corresponding to the AP adapter
+ * number (APID). The bits in the mask, from most significant to least
+ * significant bit, correspond to APIDs 0-255.
+ */
+ mutex_lock(&matrix_dev->lock);
+
+ ret = vfio_ap_mdev_verify_queues_reserved_for_apid(matrix_mdev, apid);
+ if (ret)
+ goto done;
+
+ set_bit_inv(apid, matrix_mdev->matrix.apm);
+
+ ret = vfio_ap_mdev_verify_no_sharing(matrix_mdev);
+ if (ret)
+ goto share_err;
+
+ ret = count;
+ goto done;
+
+share_err:
+ clear_bit_inv(apid, matrix_mdev->matrix.apm);
+done:
+ mutex_unlock(&matrix_dev->lock);
+
+ return ret;
+}
+static DEVICE_ATTR_WO(assign_adapter);
+
+/**
+ * unassign_adapter_store
+ *
+ * @dev: the matrix device
+ * @attr: the mediated matrix device's unassign_adapter attribute
+ * @buf: a buffer containing the adapter number (APID) to be unassigned
+ * @count: the number of bytes in @buf
+ *
+ * Parses the APID from @buf and clears the corresponding bit in the mediated
+ * matrix device's APM.
+ *
+ * Returns the number of bytes processed if the APID is valid; otherwise,
+ * returns one of the following errors:
+ * -EINVAL if the APID is not a number
+ * -ENODEV if the APID it exceeds the maximum value configured for the
+ * system
+ */
+static ssize_t unassign_adapter_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+ unsigned long apid;
+ struct mdev_device *mdev = mdev_from_dev(dev);
+ struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev);
+
+ /* If the guest is running, disallow un-assignment of adapter */
+ if (matrix_mdev->kvm)
+ return -EBUSY;
+
+ ret = kstrtoul(buf, 0, &apid);
+ if (ret)
+ return ret;
+
+ if (apid > matrix_mdev->matrix.apm_max)
+ return -ENODEV;
+
+ mutex_lock(&matrix_dev->lock);
+ clear_bit_inv((unsigned long)apid, matrix_mdev->matrix.apm);
+ mutex_unlock(&matrix_dev->lock);
+
+ return count;
+}
+static DEVICE_ATTR_WO(unassign_adapter);
+
+static int
+vfio_ap_mdev_verify_queues_reserved_for_apqi(struct ap_matrix_mdev *matrix_mdev,
+ unsigned long apqi)
+{
+ int ret;
+ unsigned long apid;
+ unsigned long nbits = matrix_mdev->matrix.apm_max + 1;
+
+ if (find_first_bit_inv(matrix_mdev->matrix.apm, nbits) >= nbits)
+ return vfio_ap_verify_queue_reserved(NULL, &apqi);
+
+ for_each_set_bit_inv(apid, matrix_mdev->matrix.apm, nbits) {
+ ret = vfio_ap_verify_queue_reserved(&apid, &apqi);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * assign_domain_store
+ *
+ * @dev: the matrix device
+ * @attr: the mediated matrix device's assign_domain attribute
+ * @buf: a buffer containing the AP queue index (APQI) of the domain to
+ * be assigned
+ * @count: the number of bytes in @buf
+ *
+ * Parses the APQI from @buf and sets the corresponding bit in the mediated
+ * matrix device's AQM.
+ *
+ * Returns the number of bytes processed if the APQI is valid; otherwise returns
+ * one of the following errors:
+ *
+ * 1. -EINVAL
+ * The APQI is not a valid number
+ *
+ * 2. -ENODEV
+ * The APQI exceeds the maximum value configured for the system
+ *
+ * 3. -EADDRNOTAVAIL
+ * An APQN derived from the cross product of the APQI being assigned
+ * and the APIDs previously assigned is not bound to the vfio_ap device
+ * driver; or, if no APIDs have yet been assigned, the APQI is not
+ * contained in an APQN bound to the vfio_ap device driver.
+ *
+ * 4. -EADDRINUSE
+ * An APQN derived from the cross product of the APQI being assigned
+ * and the APIDs previously assigned is being used by another mediated
+ * matrix device
+ */
+static ssize_t assign_domain_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+ unsigned long apqi;
+ struct mdev_device *mdev = mdev_from_dev(dev);
+ struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev);
+ unsigned long max_apqi = matrix_mdev->matrix.aqm_max;
+
+ /* If the guest is running, disallow assignment of domain */
+ if (matrix_mdev->kvm)
+ return -EBUSY;
+
+ ret = kstrtoul(buf, 0, &apqi);
+ if (ret)
+ return ret;
+ if (apqi > max_apqi)
+ return -ENODEV;
+
+ mutex_lock(&matrix_dev->lock);
+
+ ret = vfio_ap_mdev_verify_queues_reserved_for_apqi(matrix_mdev, apqi);
+ if (ret)
+ goto done;
+
+ set_bit_inv(apqi, matrix_mdev->matrix.aqm);
+
+ ret = vfio_ap_mdev_verify_no_sharing(matrix_mdev);
+ if (ret)
+ goto share_err;
+
+ ret = count;
+ goto done;
+
+share_err:
+ clear_bit_inv(apqi, matrix_mdev->matrix.aqm);
+done:
+ mutex_unlock(&matrix_dev->lock);
+
+ return ret;
+}
+static DEVICE_ATTR_WO(assign_domain);
+
+
+/**
+ * unassign_domain_store
+ *
+ * @dev: the matrix device
+ * @attr: the mediated matrix device's unassign_domain attribute
+ * @buf: a buffer containing the AP queue index (APQI) of the domain to
+ * be unassigned
+ * @count: the number of bytes in @buf
+ *
+ * Parses the APQI from @buf and clears the corresponding bit in the
+ * mediated matrix device's AQM.
+ *
+ * Returns the number of bytes processed if the APQI is valid; otherwise,
+ * returns one of the following errors:
+ * -EINVAL if the APQI is not a number
+ * -ENODEV if the APQI exceeds the maximum value configured for the system
+ */
+static ssize_t unassign_domain_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+ unsigned long apqi;
+ struct mdev_device *mdev = mdev_from_dev(dev);
+ struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev);
+
+ /* If the guest is running, disallow un-assignment of domain */
+ if (matrix_mdev->kvm)
+ return -EBUSY;
+
+ ret = kstrtoul(buf, 0, &apqi);
+ if (ret)
+ return ret;
+
+ if (apqi > matrix_mdev->matrix.aqm_max)
+ return -ENODEV;
+
+ mutex_lock(&matrix_dev->lock);
+ clear_bit_inv((unsigned long)apqi, matrix_mdev->matrix.aqm);
+ mutex_unlock(&matrix_dev->lock);
+
+ return count;
+}
+static DEVICE_ATTR_WO(unassign_domain);
+
+/**
+ * assign_control_domain_store
+ *
+ * @dev: the matrix device
+ * @attr: the mediated matrix device's assign_control_domain attribute
+ * @buf: a buffer containing the domain ID to be assigned
+ * @count: the number of bytes in @buf
+ *
+ * Parses the domain ID from @buf and sets the corresponding bit in the mediated
+ * matrix device's ADM.
+ *
+ * Returns the number of bytes processed if the domain ID is valid; otherwise,
+ * returns one of the following errors:
+ * -EINVAL if the ID is not a number
+ * -ENODEV if the ID exceeds the maximum value configured for the system
+ */
+static ssize_t assign_control_domain_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+ unsigned long id;
+ struct mdev_device *mdev = mdev_from_dev(dev);
+ struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev);
+
+ /* If the guest is running, disallow assignment of control domain */
+ if (matrix_mdev->kvm)
+ return -EBUSY;
+
+ ret = kstrtoul(buf, 0, &id);
+ if (ret)
+ return ret;
+
+ if (id > matrix_mdev->matrix.adm_max)
+ return -ENODEV;
+
+ /* Set the bit in the ADM (bitmask) corresponding to the AP control
+ * domain number (id). The bits in the mask, from most significant to
+ * least significant, correspond to IDs 0 up to the one less than the
+ * number of control domains that can be assigned.
+ */
+ mutex_lock(&matrix_dev->lock);
+ set_bit_inv(id, matrix_mdev->matrix.adm);
+ mutex_unlock(&matrix_dev->lock);
+
+ return count;
+}
+static DEVICE_ATTR_WO(assign_control_domain);
+
+/**
+ * unassign_control_domain_store
+ *
+ * @dev: the matrix device
+ * @attr: the mediated matrix device's unassign_control_domain attribute
+ * @buf: a buffer containing the domain ID to be unassigned
+ * @count: the number of bytes in @buf
+ *
+ * Parses the domain ID from @buf and clears the corresponding bit in the
+ * mediated matrix device's ADM.
+ *
+ * Returns the number of bytes processed if the domain ID is valid; otherwise,
+ * returns one of the following errors:
+ * -EINVAL if the ID is not a number
+ * -ENODEV if the ID exceeds the maximum value configured for the system
+ */
+static ssize_t unassign_control_domain_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+ unsigned long domid;
+ struct mdev_device *mdev = mdev_from_dev(dev);
+ struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev);
+ unsigned long max_domid = matrix_mdev->matrix.adm_max;
+
+ /* If the guest is running, disallow un-assignment of control domain */
+ if (matrix_mdev->kvm)
+ return -EBUSY;
+
+ ret = kstrtoul(buf, 0, &domid);
+ if (ret)
+ return ret;
+ if (domid > max_domid)
+ return -ENODEV;
+
+ mutex_lock(&matrix_dev->lock);
+ clear_bit_inv(domid, matrix_mdev->matrix.adm);
+ mutex_unlock(&matrix_dev->lock);
+
+ return count;
+}
+static DEVICE_ATTR_WO(unassign_control_domain);
+
+static ssize_t control_domains_show(struct device *dev,
+ struct device_attribute *dev_attr,
+ char *buf)
+{
+ unsigned long id;
+ int nchars = 0;
+ int n;
+ char *bufpos = buf;
+ struct mdev_device *mdev = mdev_from_dev(dev);
+ struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev);
+ unsigned long max_domid = matrix_mdev->matrix.adm_max;
+
+ mutex_lock(&matrix_dev->lock);
+ for_each_set_bit_inv(id, matrix_mdev->matrix.adm, max_domid + 1) {
+ n = sprintf(bufpos, "%04lx\n", id);
+ bufpos += n;
+ nchars += n;
+ }
+ mutex_unlock(&matrix_dev->lock);
+
+ return nchars;
+}
+static DEVICE_ATTR_RO(control_domains);
+
+static ssize_t matrix_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct mdev_device *mdev = mdev_from_dev(dev);
+ struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev);
+ char *bufpos = buf;
+ unsigned long apid;
+ unsigned long apqi;
+ unsigned long apid1;
+ unsigned long apqi1;
+ unsigned long napm_bits = matrix_mdev->matrix.apm_max + 1;
+ unsigned long naqm_bits = matrix_mdev->matrix.aqm_max + 1;
+ int nchars = 0;
+ int n;
+
+ apid1 = find_first_bit_inv(matrix_mdev->matrix.apm, napm_bits);
+ apqi1 = find_first_bit_inv(matrix_mdev->matrix.aqm, naqm_bits);
+
+ mutex_lock(&matrix_dev->lock);
+
+ if ((apid1 < napm_bits) && (apqi1 < naqm_bits)) {
+ for_each_set_bit_inv(apid, matrix_mdev->matrix.apm, napm_bits) {
+ for_each_set_bit_inv(apqi, matrix_mdev->matrix.aqm,
+ naqm_bits) {
+ n = sprintf(bufpos, "%02lx.%04lx\n", apid,
+ apqi);
+ bufpos += n;
+ nchars += n;
+ }
+ }
+ } else if (apid1 < napm_bits) {
+ for_each_set_bit_inv(apid, matrix_mdev->matrix.apm, napm_bits) {
+ n = sprintf(bufpos, "%02lx.\n", apid);
+ bufpos += n;
+ nchars += n;
+ }
+ } else if (apqi1 < naqm_bits) {
+ for_each_set_bit_inv(apqi, matrix_mdev->matrix.aqm, naqm_bits) {
+ n = sprintf(bufpos, ".%04lx\n", apqi);
+ bufpos += n;
+ nchars += n;
+ }
+ }
+
+ mutex_unlock(&matrix_dev->lock);
+
+ return nchars;
+}
+static DEVICE_ATTR_RO(matrix);
+
+static struct attribute *vfio_ap_mdev_attrs[] = {
+ &dev_attr_assign_adapter.attr,
+ &dev_attr_unassign_adapter.attr,
+ &dev_attr_assign_domain.attr,
+ &dev_attr_unassign_domain.attr,
+ &dev_attr_assign_control_domain.attr,
+ &dev_attr_unassign_control_domain.attr,
+ &dev_attr_control_domains.attr,
+ &dev_attr_matrix.attr,
+ NULL,
+};
+
+static struct attribute_group vfio_ap_mdev_attr_group = {
+ .attrs = vfio_ap_mdev_attrs
+};
+
+static const struct attribute_group *vfio_ap_mdev_attr_groups[] = {
+ &vfio_ap_mdev_attr_group,
+ NULL
+};
+
+/**
+ * vfio_ap_mdev_set_kvm
+ *
+ * @matrix_mdev: a mediated matrix device
+ * @kvm: reference to KVM instance
+ *
+ * Verifies no other mediated matrix device has @kvm and sets a reference to
+ * it in @matrix_mdev->kvm.
+ *
+ * Return 0 if no other mediated matrix device has a reference to @kvm;
+ * otherwise, returns an -EPERM.
+ */
+static int vfio_ap_mdev_set_kvm(struct ap_matrix_mdev *matrix_mdev,
+ struct kvm *kvm)
+{
+ struct ap_matrix_mdev *m;
+
+ mutex_lock(&matrix_dev->lock);
+
+ list_for_each_entry(m, &matrix_dev->mdev_list, node) {
+ if ((m != matrix_mdev) && (m->kvm == kvm)) {
+ mutex_unlock(&matrix_dev->lock);
+ return -EPERM;
+ }
+ }
+
+ matrix_mdev->kvm = kvm;
+ mutex_unlock(&matrix_dev->lock);
+
+ return 0;
+}
+
+static int vfio_ap_mdev_group_notifier(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ int ret;
+ struct ap_matrix_mdev *matrix_mdev;
+
+ if (action != VFIO_GROUP_NOTIFY_SET_KVM)
+ return NOTIFY_OK;
+
+ matrix_mdev = container_of(nb, struct ap_matrix_mdev, group_notifier);
+
+ if (!data) {
+ matrix_mdev->kvm = NULL;
+ return NOTIFY_OK;
+ }
+
+ ret = vfio_ap_mdev_set_kvm(matrix_mdev, data);
+ if (ret)
+ return NOTIFY_DONE;
+
+ /* If there is no CRYCB pointer, then we can't copy the masks */
+ if (!matrix_mdev->kvm->arch.crypto.crycbd)
+ return NOTIFY_DONE;
+
+ kvm_arch_crypto_set_masks(matrix_mdev->kvm, matrix_mdev->matrix.apm,
+ matrix_mdev->matrix.aqm,
+ matrix_mdev->matrix.adm);
+
+ return NOTIFY_OK;
+}
+
+static int vfio_ap_mdev_reset_queue(unsigned int apid, unsigned int apqi,
+ unsigned int retry)
+{
+ struct ap_queue_status status;
+
+ do {
+ status = ap_zapq(AP_MKQID(apid, apqi));
+ switch (status.response_code) {
+ case AP_RESPONSE_NORMAL:
+ return 0;
+ case AP_RESPONSE_RESET_IN_PROGRESS:
+ case AP_RESPONSE_BUSY:
+ msleep(20);
+ break;
+ default:
+ /* things are really broken, give up */
+ return -EIO;
+ }
+ } while (retry--);
+
+ return -EBUSY;
+}
+
+static int vfio_ap_mdev_reset_queues(struct mdev_device *mdev)
+{
+ int ret;
+ int rc = 0;
+ unsigned long apid, apqi;
+ struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev);
+
+ for_each_set_bit_inv(apid, matrix_mdev->matrix.apm,
+ matrix_mdev->matrix.apm_max + 1) {
+ for_each_set_bit_inv(apqi, matrix_mdev->matrix.aqm,
+ matrix_mdev->matrix.aqm_max + 1) {
+ ret = vfio_ap_mdev_reset_queue(apid, apqi, 1);
+ /*
+ * Regardless whether a queue turns out to be busy, or
+ * is not operational, we need to continue resetting
+ * the remaining queues.
+ */
+ if (ret)
+ rc = ret;
+ }
+ }
+
+ return rc;
+}
+
+static int vfio_ap_mdev_open(struct mdev_device *mdev)
+{
+ struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev);
+ unsigned long events;
+ int ret;
+
+
+ if (!try_module_get(THIS_MODULE))
+ return -ENODEV;
+
+ matrix_mdev->group_notifier.notifier_call = vfio_ap_mdev_group_notifier;
+ events = VFIO_GROUP_NOTIFY_SET_KVM;
+
+ ret = vfio_register_notifier(mdev_dev(mdev), VFIO_GROUP_NOTIFY,
+ &events, &matrix_mdev->group_notifier);
+ if (ret) {
+ module_put(THIS_MODULE);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void vfio_ap_mdev_release(struct mdev_device *mdev)
+{
+ struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev);
+
+ if (matrix_mdev->kvm)
+ kvm_arch_crypto_clear_masks(matrix_mdev->kvm);
+
+ vfio_ap_mdev_reset_queues(mdev);
+ vfio_unregister_notifier(mdev_dev(mdev), VFIO_GROUP_NOTIFY,
+ &matrix_mdev->group_notifier);
+ matrix_mdev->kvm = NULL;
+ module_put(THIS_MODULE);
+}
+
+static int vfio_ap_mdev_get_device_info(unsigned long arg)
+{
+ unsigned long minsz;
+ struct vfio_device_info info;
+
+ minsz = offsetofend(struct vfio_device_info, num_irqs);
+
+ if (copy_from_user(&info, (void __user *)arg, minsz))
+ return -EFAULT;
+
+ if (info.argsz < minsz)
+ return -EINVAL;
+
+ info.flags = VFIO_DEVICE_FLAGS_AP | VFIO_DEVICE_FLAGS_RESET;
+ info.num_regions = 0;
+ info.num_irqs = 0;
+
+ return copy_to_user((void __user *)arg, &info, minsz);
+}
+
+static ssize_t vfio_ap_mdev_ioctl(struct mdev_device *mdev,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret;
+
+ switch (cmd) {
+ case VFIO_DEVICE_GET_INFO:
+ ret = vfio_ap_mdev_get_device_info(arg);
+ break;
+ case VFIO_DEVICE_RESET:
+ ret = vfio_ap_mdev_reset_queues(mdev);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ return ret;
+}
+
+static const struct mdev_parent_ops vfio_ap_matrix_ops = {
+ .owner = THIS_MODULE,
+ .supported_type_groups = vfio_ap_mdev_type_groups,
+ .mdev_attr_groups = vfio_ap_mdev_attr_groups,
+ .create = vfio_ap_mdev_create,
+ .remove = vfio_ap_mdev_remove,
+ .open = vfio_ap_mdev_open,
+ .release = vfio_ap_mdev_release,
+ .ioctl = vfio_ap_mdev_ioctl,
+};
+
+int vfio_ap_mdev_register(void)
+{
+ atomic_set(&matrix_dev->available_instances, MAX_ZDEV_ENTRIES_EXT);
+
+ return mdev_register_device(&matrix_dev->device, &vfio_ap_matrix_ops);
+}
+
+void vfio_ap_mdev_unregister(void)
+{
+ mdev_unregister_device(&matrix_dev->device);
+}
diff --git a/drivers/s390/crypto/vfio_ap_private.h b/drivers/s390/crypto/vfio_ap_private.h
new file mode 100644
index 000000000000..5675492233c7
--- /dev/null
+++ b/drivers/s390/crypto/vfio_ap_private.h
@@ -0,0 +1,88 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Private data and functions for adjunct processor VFIO matrix driver.
+ *
+ * Author(s): Tony Krowiak <akrowiak@linux.ibm.com>
+ * Halil Pasic <pasic@linux.ibm.com>
+ *
+ * Copyright IBM Corp. 2018
+ */
+
+#ifndef _VFIO_AP_PRIVATE_H_
+#define _VFIO_AP_PRIVATE_H_
+
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/mdev.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+
+#include "ap_bus.h"
+
+#define VFIO_AP_MODULE_NAME "vfio_ap"
+#define VFIO_AP_DRV_NAME "vfio_ap"
+
+/**
+ * ap_matrix_dev - the AP matrix device structure
+ * @device: generic device structure associated with the AP matrix device
+ * @available_instances: number of mediated matrix devices that can be created
+ * @info: the struct containing the output from the PQAP(QCI) instruction
+ * mdev_list: the list of mediated matrix devices created
+ * lock: mutex for locking the AP matrix device. This lock will be
+ * taken every time we fiddle with state managed by the vfio_ap
+ * driver, be it using @mdev_list or writing the state of a
+ * single ap_matrix_mdev device. It's quite coarse but we don't
+ * expect much contention.
+ */
+struct ap_matrix_dev {
+ struct device device;
+ atomic_t available_instances;
+ struct ap_config_info info;
+ struct list_head mdev_list;
+ struct mutex lock;
+};
+
+extern struct ap_matrix_dev *matrix_dev;
+
+/**
+ * The AP matrix is comprised of three bit masks identifying the adapters,
+ * queues (domains) and control domains that belong to an AP matrix. The bits i
+ * each mask, from least significant to most significant bit, correspond to IDs
+ * 0 to 255. When a bit is set, the corresponding ID belongs to the matrix.
+ *
+ * @apm_max: max adapter number in @apm
+ * @apm identifies the AP adapters in the matrix
+ * @aqm_max: max domain number in @aqm
+ * @aqm identifies the AP queues (domains) in the matrix
+ * @adm_max: max domain number in @adm
+ * @adm identifies the AP control domains in the matrix
+ */
+struct ap_matrix {
+ unsigned long apm_max;
+ DECLARE_BITMAP(apm, 256);
+ unsigned long aqm_max;
+ DECLARE_BITMAP(aqm, 256);
+ unsigned long adm_max;
+ DECLARE_BITMAP(adm, 256);
+};
+
+/**
+ * struct ap_matrix_mdev - the mediated matrix device structure
+ * @list: allows the ap_matrix_mdev struct to be added to a list
+ * @matrix: the adapters, usage domains and control domains assigned to the
+ * mediated matrix device.
+ * @group_notifier: notifier block used for specifying callback function for
+ * handling the VFIO_GROUP_NOTIFY_SET_KVM event
+ * @kvm: the struct holding guest's state
+ */
+struct ap_matrix_mdev {
+ struct list_head node;
+ struct ap_matrix matrix;
+ struct notifier_block group_notifier;
+ struct kvm *kvm;
+};
+
+extern int vfio_ap_mdev_register(void);
+extern void vfio_ap_mdev_unregister(void);
+
+#endif /* _VFIO_AP_PRIVATE_H_ */
diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c
index e6854127b434..eb93c2d27d0a 100644
--- a/drivers/s390/crypto/zcrypt_api.c
+++ b/drivers/s390/crypto/zcrypt_api.c
@@ -1,8 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * zcrypt 2.1.0
- *
- * Copyright IBM Corp. 2001, 2012
+ * Copyright IBM Corp. 2001, 2018
* Author(s): Robert Burroughs
* Eric Rossman (edrossma@us.ibm.com)
* Cornelia Huck <cornelia.huck@de.ibm.com>
@@ -11,6 +9,7 @@
* Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
* Ralph Wuerthner <rwuerthn@de.ibm.com>
* MSGTYPE restruct: Holger Dengler <hd@linux.vnet.ibm.com>
+ * Multiple device nodes: Harald Freudenberger <freude@linux.ibm.com>
*/
#include <linux/module.h>
@@ -24,6 +23,8 @@
#include <linux/uaccess.h>
#include <linux/hw_random.h>
#include <linux/debugfs.h>
+#include <linux/cdev.h>
+#include <linux/ctype.h>
#include <asm/debug.h>
#define CREATE_TRACE_POINTS
@@ -108,6 +109,375 @@ struct zcrypt_ops *zcrypt_msgtype(unsigned char *name, int variant)
}
EXPORT_SYMBOL(zcrypt_msgtype);
+/*
+ * Multi device nodes extension functions.
+ */
+
+#ifdef CONFIG_ZCRYPT_MULTIDEVNODES
+
+struct zcdn_device;
+
+static struct class *zcrypt_class;
+static dev_t zcrypt_devt;
+static struct cdev zcrypt_cdev;
+
+struct zcdn_device {
+ struct device device;
+ struct ap_perms perms;
+};
+
+#define to_zcdn_dev(x) container_of((x), struct zcdn_device, device)
+
+#define ZCDN_MAX_NAME 32
+
+static int zcdn_create(const char *name);
+static int zcdn_destroy(const char *name);
+
+/* helper function, matches the name for find_zcdndev_by_name() */
+static int __match_zcdn_name(struct device *dev, const void *data)
+{
+ return strcmp(dev_name(dev), (const char *)data) == 0;
+}
+
+/* helper function, matches the devt value for find_zcdndev_by_devt() */
+static int __match_zcdn_devt(struct device *dev, const void *data)
+{
+ return dev->devt == *((dev_t *) data);
+}
+
+/*
+ * Find zcdn device by name.
+ * Returns reference to the zcdn device which needs to be released
+ * with put_device() after use.
+ */
+static inline struct zcdn_device *find_zcdndev_by_name(const char *name)
+{
+ struct device *dev =
+ class_find_device(zcrypt_class, NULL,
+ (void *) name,
+ __match_zcdn_name);
+
+ return dev ? to_zcdn_dev(dev) : NULL;
+}
+
+/*
+ * Find zcdn device by devt value.
+ * Returns reference to the zcdn device which needs to be released
+ * with put_device() after use.
+ */
+static inline struct zcdn_device *find_zcdndev_by_devt(dev_t devt)
+{
+ struct device *dev =
+ class_find_device(zcrypt_class, NULL,
+ (void *) &devt,
+ __match_zcdn_devt);
+
+ return dev ? to_zcdn_dev(dev) : NULL;
+}
+
+static ssize_t ioctlmask_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int i, rc;
+ struct zcdn_device *zcdndev = to_zcdn_dev(dev);
+
+ if (mutex_lock_interruptible(&ap_perms_mutex))
+ return -ERESTARTSYS;
+
+ buf[0] = '0';
+ buf[1] = 'x';
+ for (i = 0; i < sizeof(zcdndev->perms.ioctlm) / sizeof(long); i++)
+ snprintf(buf + 2 + 2 * i * sizeof(long),
+ PAGE_SIZE - 2 - 2 * i * sizeof(long),
+ "%016lx", zcdndev->perms.ioctlm[i]);
+ buf[2 + 2 * i * sizeof(long)] = '\n';
+ buf[2 + 2 * i * sizeof(long) + 1] = '\0';
+ rc = 2 + 2 * i * sizeof(long) + 1;
+
+ mutex_unlock(&ap_perms_mutex);
+
+ return rc;
+}
+
+static ssize_t ioctlmask_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int rc;
+ struct zcdn_device *zcdndev = to_zcdn_dev(dev);
+
+ rc = ap_parse_mask_str(buf, zcdndev->perms.ioctlm,
+ AP_IOCTLS, &ap_perms_mutex);
+ if (rc)
+ return rc;
+
+ return count;
+}
+
+static DEVICE_ATTR_RW(ioctlmask);
+
+static ssize_t apmask_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int i, rc;
+ struct zcdn_device *zcdndev = to_zcdn_dev(dev);
+
+ if (mutex_lock_interruptible(&ap_perms_mutex))
+ return -ERESTARTSYS;
+
+ buf[0] = '0';
+ buf[1] = 'x';
+ for (i = 0; i < sizeof(zcdndev->perms.apm) / sizeof(long); i++)
+ snprintf(buf + 2 + 2 * i * sizeof(long),
+ PAGE_SIZE - 2 - 2 * i * sizeof(long),
+ "%016lx", zcdndev->perms.apm[i]);
+ buf[2 + 2 * i * sizeof(long)] = '\n';
+ buf[2 + 2 * i * sizeof(long) + 1] = '\0';
+ rc = 2 + 2 * i * sizeof(long) + 1;
+
+ mutex_unlock(&ap_perms_mutex);
+
+ return rc;
+}
+
+static ssize_t apmask_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int rc;
+ struct zcdn_device *zcdndev = to_zcdn_dev(dev);
+
+ rc = ap_parse_mask_str(buf, zcdndev->perms.apm,
+ AP_DEVICES, &ap_perms_mutex);
+ if (rc)
+ return rc;
+
+ return count;
+}
+
+static DEVICE_ATTR_RW(apmask);
+
+static ssize_t aqmask_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int i, rc;
+ struct zcdn_device *zcdndev = to_zcdn_dev(dev);
+
+ if (mutex_lock_interruptible(&ap_perms_mutex))
+ return -ERESTARTSYS;
+
+ buf[0] = '0';
+ buf[1] = 'x';
+ for (i = 0; i < sizeof(zcdndev->perms.aqm) / sizeof(long); i++)
+ snprintf(buf + 2 + 2 * i * sizeof(long),
+ PAGE_SIZE - 2 - 2 * i * sizeof(long),
+ "%016lx", zcdndev->perms.aqm[i]);
+ buf[2 + 2 * i * sizeof(long)] = '\n';
+ buf[2 + 2 * i * sizeof(long) + 1] = '\0';
+ rc = 2 + 2 * i * sizeof(long) + 1;
+
+ mutex_unlock(&ap_perms_mutex);
+
+ return rc;
+}
+
+static ssize_t aqmask_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int rc;
+ struct zcdn_device *zcdndev = to_zcdn_dev(dev);
+
+ rc = ap_parse_mask_str(buf, zcdndev->perms.aqm,
+ AP_DOMAINS, &ap_perms_mutex);
+ if (rc)
+ return rc;
+
+ return count;
+}
+
+static DEVICE_ATTR_RW(aqmask);
+
+static struct attribute *zcdn_dev_attrs[] = {
+ &dev_attr_ioctlmask.attr,
+ &dev_attr_apmask.attr,
+ &dev_attr_aqmask.attr,
+ NULL
+};
+
+static struct attribute_group zcdn_dev_attr_group = {
+ .attrs = zcdn_dev_attrs
+};
+
+static const struct attribute_group *zcdn_dev_attr_groups[] = {
+ &zcdn_dev_attr_group,
+ NULL
+};
+
+static ssize_t zcdn_create_store(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t count)
+{
+ int rc;
+ char name[ZCDN_MAX_NAME];
+
+ strncpy(name, skip_spaces(buf), sizeof(name));
+ name[sizeof(name) - 1] = '\0';
+
+ rc = zcdn_create(strim(name));
+
+ return rc ? rc : count;
+}
+
+static const struct class_attribute class_attr_zcdn_create =
+ __ATTR(create, 0600, NULL, zcdn_create_store);
+
+static ssize_t zcdn_destroy_store(struct class *class,
+ struct class_attribute *attr,
+ const char *buf, size_t count)
+{
+ int rc;
+ char name[ZCDN_MAX_NAME];
+
+ strncpy(name, skip_spaces(buf), sizeof(name));
+ name[sizeof(name) - 1] = '\0';
+
+ rc = zcdn_destroy(strim(name));
+
+ return rc ? rc : count;
+}
+
+static const struct class_attribute class_attr_zcdn_destroy =
+ __ATTR(destroy, 0600, NULL, zcdn_destroy_store);
+
+static void zcdn_device_release(struct device *dev)
+{
+ struct zcdn_device *zcdndev = to_zcdn_dev(dev);
+
+ ZCRYPT_DBF(DBF_INFO, "releasing zcdn device %d:%d\n",
+ MAJOR(dev->devt), MINOR(dev->devt));
+
+ kfree(zcdndev);
+}
+
+static int zcdn_create(const char *name)
+{
+ dev_t devt;
+ int i, rc = 0;
+ char nodename[ZCDN_MAX_NAME];
+ struct zcdn_device *zcdndev;
+
+ if (mutex_lock_interruptible(&ap_perms_mutex))
+ return -ERESTARTSYS;
+
+ /* check if device node with this name already exists */
+ if (name[0]) {
+ zcdndev = find_zcdndev_by_name(name);
+ if (zcdndev) {
+ put_device(&zcdndev->device);
+ rc = -EEXIST;
+ goto unlockout;
+ }
+ }
+
+ /* find an unused minor number */
+ for (i = 0; i < ZCRYPT_MAX_MINOR_NODES; i++) {
+ devt = MKDEV(MAJOR(zcrypt_devt), MINOR(zcrypt_devt) + i);
+ zcdndev = find_zcdndev_by_devt(devt);
+ if (zcdndev)
+ put_device(&zcdndev->device);
+ else
+ break;
+ }
+ if (i == ZCRYPT_MAX_MINOR_NODES) {
+ rc = -ENOSPC;
+ goto unlockout;
+ }
+
+ /* alloc and prepare a new zcdn device */
+ zcdndev = kzalloc(sizeof(*zcdndev), GFP_KERNEL);
+ if (!zcdndev) {
+ rc = -ENOMEM;
+ goto unlockout;
+ }
+ zcdndev->device.release = zcdn_device_release;
+ zcdndev->device.class = zcrypt_class;
+ zcdndev->device.devt = devt;
+ zcdndev->device.groups = zcdn_dev_attr_groups;
+ if (name[0])
+ strncpy(nodename, name, sizeof(nodename));
+ else
+ snprintf(nodename, sizeof(nodename),
+ ZCRYPT_NAME "_%d", (int) MINOR(devt));
+ nodename[sizeof(nodename)-1] = '\0';
+ if (dev_set_name(&zcdndev->device, nodename)) {
+ rc = -EINVAL;
+ goto unlockout;
+ }
+ rc = device_register(&zcdndev->device);
+ if (rc) {
+ put_device(&zcdndev->device);
+ goto unlockout;
+ }
+
+ ZCRYPT_DBF(DBF_INFO, "created zcdn device %d:%d\n",
+ MAJOR(devt), MINOR(devt));
+
+unlockout:
+ mutex_unlock(&ap_perms_mutex);
+ return rc;
+}
+
+static int zcdn_destroy(const char *name)
+{
+ int rc = 0;
+ struct zcdn_device *zcdndev;
+
+ if (mutex_lock_interruptible(&ap_perms_mutex))
+ return -ERESTARTSYS;
+
+ /* try to find this zcdn device */
+ zcdndev = find_zcdndev_by_name(name);
+ if (!zcdndev) {
+ rc = -ENOENT;
+ goto unlockout;
+ }
+
+ /*
+ * The zcdn device is not hard destroyed. It is subject to
+ * reference counting and thus just needs to be unregistered.
+ */
+ put_device(&zcdndev->device);
+ device_unregister(&zcdndev->device);
+
+unlockout:
+ mutex_unlock(&ap_perms_mutex);
+ return rc;
+}
+
+static void zcdn_destroy_all(void)
+{
+ int i;
+ dev_t devt;
+ struct zcdn_device *zcdndev;
+
+ mutex_lock(&ap_perms_mutex);
+ for (i = 0; i < ZCRYPT_MAX_MINOR_NODES; i++) {
+ devt = MKDEV(MAJOR(zcrypt_devt), MINOR(zcrypt_devt) + i);
+ zcdndev = find_zcdndev_by_devt(devt);
+ if (zcdndev) {
+ put_device(&zcdndev->device);
+ device_unregister(&zcdndev->device);
+ }
+ }
+ mutex_unlock(&ap_perms_mutex);
+}
+
+#endif
+
/**
* zcrypt_read (): Not supported beyond zcrypt 1.3.1.
*
@@ -137,6 +507,23 @@ static ssize_t zcrypt_write(struct file *filp, const char __user *buf,
*/
static int zcrypt_open(struct inode *inode, struct file *filp)
{
+ struct ap_perms *perms = &ap_perms;
+
+#ifdef CONFIG_ZCRYPT_MULTIDEVNODES
+ if (filp->f_inode->i_cdev == &zcrypt_cdev) {
+ struct zcdn_device *zcdndev;
+
+ if (mutex_lock_interruptible(&ap_perms_mutex))
+ return -ERESTARTSYS;
+ zcdndev = find_zcdndev_by_devt(filp->f_inode->i_rdev);
+ /* find returns a reference, no get_device() needed */
+ mutex_unlock(&ap_perms_mutex);
+ if (zcdndev)
+ perms = &zcdndev->perms;
+ }
+#endif
+ filp->private_data = (void *) perms;
+
atomic_inc(&zcrypt_open_count);
return nonseekable_open(inode, filp);
}
@@ -148,10 +535,55 @@ static int zcrypt_open(struct inode *inode, struct file *filp)
*/
static int zcrypt_release(struct inode *inode, struct file *filp)
{
+#ifdef CONFIG_ZCRYPT_MULTIDEVNODES
+ if (filp->f_inode->i_cdev == &zcrypt_cdev) {
+ struct zcdn_device *zcdndev;
+
+ if (mutex_lock_interruptible(&ap_perms_mutex))
+ return -ERESTARTSYS;
+ zcdndev = find_zcdndev_by_devt(filp->f_inode->i_rdev);
+ mutex_unlock(&ap_perms_mutex);
+ if (zcdndev) {
+ /* 2 puts here: one for find, one for open */
+ put_device(&zcdndev->device);
+ put_device(&zcdndev->device);
+ }
+ }
+#endif
+
atomic_dec(&zcrypt_open_count);
return 0;
}
+static inline int zcrypt_check_ioctl(struct ap_perms *perms,
+ unsigned int cmd)
+{
+ int rc = -EPERM;
+ int ioctlnr = (cmd & _IOC_NRMASK) >> _IOC_NRSHIFT;
+
+ if (ioctlnr > 0 && ioctlnr < AP_IOCTLS) {
+ if (test_bit_inv(ioctlnr, perms->ioctlm))
+ rc = 0;
+ }
+
+ if (rc)
+ ZCRYPT_DBF(DBF_WARN,
+ "ioctl check failed: ioctlnr=0x%04x rc=%d\n",
+ ioctlnr, rc);
+
+ return rc;
+}
+
+static inline bool zcrypt_check_card(struct ap_perms *perms, int card)
+{
+ return test_bit_inv(card, perms->apm) ? true : false;
+}
+
+static inline bool zcrypt_check_queue(struct ap_perms *perms, int queue)
+{
+ return test_bit_inv(queue, perms->aqm) ? true : false;
+}
+
static inline struct zcrypt_queue *zcrypt_pick_queue(struct zcrypt_card *zc,
struct zcrypt_queue *zq,
unsigned int weight)
@@ -213,7 +645,8 @@ static inline bool zcrypt_queue_compare(struct zcrypt_queue *zq,
/*
* zcrypt ioctls.
*/
-static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex)
+static long zcrypt_rsa_modexpo(struct ap_perms *perms,
+ struct ica_rsa_modexpo *mex)
{
struct zcrypt_card *zc, *pref_zc;
struct zcrypt_queue *zq, *pref_zq;
@@ -250,6 +683,9 @@ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex)
if (zc->min_mod_size > mex->inputdatalength ||
zc->max_mod_size < mex->inputdatalength)
continue;
+ /* check if device node has admission for this card */
+ if (!zcrypt_check_card(perms, zc->card->id))
+ continue;
/* get weight index of the card device */
weight = zc->speed_rating[func_code];
if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight))
@@ -258,6 +694,10 @@ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex)
/* check if device is online and eligible */
if (!zq->online || !zq->ops->rsa_modexpo)
continue;
+ /* check if device node has admission for this queue */
+ if (!zcrypt_check_queue(perms,
+ AP_QID_QUEUE(zq->queue->qid)))
+ continue;
if (zcrypt_queue_compare(zq, pref_zq,
weight, pref_weight))
continue;
@@ -287,7 +727,8 @@ out:
return rc;
}
-static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt)
+static long zcrypt_rsa_crt(struct ap_perms *perms,
+ struct ica_rsa_modexpo_crt *crt)
{
struct zcrypt_card *zc, *pref_zc;
struct zcrypt_queue *zq, *pref_zq;
@@ -324,6 +765,9 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt)
if (zc->min_mod_size > crt->inputdatalength ||
zc->max_mod_size < crt->inputdatalength)
continue;
+ /* check if device node has admission for this card */
+ if (!zcrypt_check_card(perms, zc->card->id))
+ continue;
/* get weight index of the card device */
weight = zc->speed_rating[func_code];
if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight))
@@ -332,6 +776,10 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt)
/* check if device is online and eligible */
if (!zq->online || !zq->ops->rsa_modexpo_crt)
continue;
+ /* check if device node has admission for this queue */
+ if (!zcrypt_check_queue(perms,
+ AP_QID_QUEUE(zq->queue->qid)))
+ continue;
if (zcrypt_queue_compare(zq, pref_zq,
weight, pref_weight))
continue;
@@ -361,7 +809,8 @@ out:
return rc;
}
-long zcrypt_send_cprb(struct ica_xcRB *xcRB)
+static long _zcrypt_send_cprb(struct ap_perms *perms,
+ struct ica_xcRB *xcRB)
{
struct zcrypt_card *zc, *pref_zc;
struct zcrypt_queue *zq, *pref_zq;
@@ -373,6 +822,7 @@ long zcrypt_send_cprb(struct ica_xcRB *xcRB)
trace_s390_zcrypt_req(xcRB, TB_ZSECSENDCPRB);
+ xcRB->status = 0;
ap_init_message(&ap_msg);
rc = get_cprb_fc(xcRB, &ap_msg, &func_code, &domain);
if (rc)
@@ -389,6 +839,9 @@ long zcrypt_send_cprb(struct ica_xcRB *xcRB)
if (xcRB->user_defined != AUTOSELECT &&
xcRB->user_defined != zc->card->id)
continue;
+ /* check if device node has admission for this card */
+ if (!zcrypt_check_card(perms, zc->card->id))
+ continue;
/* get weight index of the card device */
weight = speed_idx_cca(func_code) * zc->speed_rating[SECKEY];
if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight))
@@ -400,6 +853,10 @@ long zcrypt_send_cprb(struct ica_xcRB *xcRB)
((*domain != (unsigned short) AUTOSELECT) &&
(*domain != AP_QID_QUEUE(zq->queue->qid))))
continue;
+ /* check if device node has admission for this queue */
+ if (!zcrypt_check_queue(perms,
+ AP_QID_QUEUE(zq->queue->qid)))
+ continue;
if (zcrypt_queue_compare(zq, pref_zq,
weight, pref_weight))
continue;
@@ -433,6 +890,11 @@ out:
AP_QID_CARD(qid), AP_QID_QUEUE(qid));
return rc;
}
+
+long zcrypt_send_cprb(struct ica_xcRB *xcRB)
+{
+ return _zcrypt_send_cprb(&ap_perms, xcRB);
+}
EXPORT_SYMBOL(zcrypt_send_cprb);
static bool is_desired_ep11_card(unsigned int dev_id,
@@ -459,7 +921,8 @@ static bool is_desired_ep11_queue(unsigned int dev_qid,
return false;
}
-static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb)
+static long zcrypt_send_ep11_cprb(struct ap_perms *perms,
+ struct ep11_urb *xcrb)
{
struct zcrypt_card *zc, *pref_zc;
struct zcrypt_queue *zq, *pref_zq;
@@ -510,6 +973,9 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb)
if (targets &&
!is_desired_ep11_card(zc->card->id, target_num, targets))
continue;
+ /* check if device node has admission for this card */
+ if (!zcrypt_check_card(perms, zc->card->id))
+ continue;
/* get weight index of the card device */
weight = speed_idx_ep11(func_code) * zc->speed_rating[SECKEY];
if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight))
@@ -522,6 +988,10 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb)
!is_desired_ep11_queue(zq->queue->qid,
target_num, targets)))
continue;
+ /* check if device node has admission for this queue */
+ if (!zcrypt_check_queue(perms,
+ AP_QID_QUEUE(zq->queue->qid)))
+ continue;
if (zcrypt_queue_compare(zq, pref_zq,
weight, pref_weight))
continue;
@@ -788,7 +1258,13 @@ static int zcrypt_requestq_count(void)
static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
- int rc = 0;
+ int rc;
+ struct ap_perms *perms =
+ (struct ap_perms *) filp->private_data;
+
+ rc = zcrypt_check_ioctl(perms, cmd);
+ if (rc)
+ return rc;
switch (cmd) {
case ICARSAMODEXPO: {
@@ -798,12 +1274,12 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
if (copy_from_user(&mex, umex, sizeof(mex)))
return -EFAULT;
do {
- rc = zcrypt_rsa_modexpo(&mex);
+ rc = zcrypt_rsa_modexpo(perms, &mex);
} while (rc == -EAGAIN);
/* on failure: retry once again after a requested rescan */
if ((rc == -ENODEV) && (zcrypt_process_rescan()))
do {
- rc = zcrypt_rsa_modexpo(&mex);
+ rc = zcrypt_rsa_modexpo(perms, &mex);
} while (rc == -EAGAIN);
if (rc) {
ZCRYPT_DBF(DBF_DEBUG, "ioctl ICARSAMODEXPO rc=%d\n", rc);
@@ -818,12 +1294,12 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
if (copy_from_user(&crt, ucrt, sizeof(crt)))
return -EFAULT;
do {
- rc = zcrypt_rsa_crt(&crt);
+ rc = zcrypt_rsa_crt(perms, &crt);
} while (rc == -EAGAIN);
/* on failure: retry once again after a requested rescan */
if ((rc == -ENODEV) && (zcrypt_process_rescan()))
do {
- rc = zcrypt_rsa_crt(&crt);
+ rc = zcrypt_rsa_crt(perms, &crt);
} while (rc == -EAGAIN);
if (rc) {
ZCRYPT_DBF(DBF_DEBUG, "ioctl ICARSACRT rc=%d\n", rc);
@@ -838,15 +1314,16 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
if (copy_from_user(&xcRB, uxcRB, sizeof(xcRB)))
return -EFAULT;
do {
- rc = zcrypt_send_cprb(&xcRB);
+ rc = _zcrypt_send_cprb(perms, &xcRB);
} while (rc == -EAGAIN);
/* on failure: retry once again after a requested rescan */
if ((rc == -ENODEV) && (zcrypt_process_rescan()))
do {
- rc = zcrypt_send_cprb(&xcRB);
+ rc = _zcrypt_send_cprb(perms, &xcRB);
} while (rc == -EAGAIN);
if (rc)
- ZCRYPT_DBF(DBF_DEBUG, "ioctl ZSENDCPRB rc=%d\n", rc);
+ ZCRYPT_DBF(DBF_DEBUG, "ioctl ZSENDCPRB rc=%d status=0x%x\n",
+ rc, xcRB.status);
if (copy_to_user(uxcRB, &xcRB, sizeof(xcRB)))
return -EFAULT;
return rc;
@@ -858,12 +1335,12 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
if (copy_from_user(&xcrb, uxcrb, sizeof(xcrb)))
return -EFAULT;
do {
- rc = zcrypt_send_ep11_cprb(&xcrb);
+ rc = zcrypt_send_ep11_cprb(perms, &xcrb);
} while (rc == -EAGAIN);
/* on failure: retry once again after a requested rescan */
if ((rc == -ENODEV) && (zcrypt_process_rescan()))
do {
- rc = zcrypt_send_ep11_cprb(&xcrb);
+ rc = zcrypt_send_ep11_cprb(perms, &xcrb);
} while (rc == -EAGAIN);
if (rc)
ZCRYPT_DBF(DBF_DEBUG, "ioctl ZSENDEP11CPRB rc=%d\n", rc);
@@ -989,8 +1466,8 @@ struct compat_ica_rsa_modexpo {
compat_uptr_t n_modulus;
};
-static long trans_modexpo32(struct file *filp, unsigned int cmd,
- unsigned long arg)
+static long trans_modexpo32(struct ap_perms *perms, struct file *filp,
+ unsigned int cmd, unsigned long arg)
{
struct compat_ica_rsa_modexpo __user *umex32 = compat_ptr(arg);
struct compat_ica_rsa_modexpo mex32;
@@ -1006,12 +1483,12 @@ static long trans_modexpo32(struct file *filp, unsigned int cmd,
mex64.b_key = compat_ptr(mex32.b_key);
mex64.n_modulus = compat_ptr(mex32.n_modulus);
do {
- rc = zcrypt_rsa_modexpo(&mex64);
+ rc = zcrypt_rsa_modexpo(perms, &mex64);
} while (rc == -EAGAIN);
/* on failure: retry once again after a requested rescan */
if ((rc == -ENODEV) && (zcrypt_process_rescan()))
do {
- rc = zcrypt_rsa_modexpo(&mex64);
+ rc = zcrypt_rsa_modexpo(perms, &mex64);
} while (rc == -EAGAIN);
if (rc)
return rc;
@@ -1031,8 +1508,8 @@ struct compat_ica_rsa_modexpo_crt {
compat_uptr_t u_mult_inv;
};
-static long trans_modexpo_crt32(struct file *filp, unsigned int cmd,
- unsigned long arg)
+static long trans_modexpo_crt32(struct ap_perms *perms, struct file *filp,
+ unsigned int cmd, unsigned long arg)
{
struct compat_ica_rsa_modexpo_crt __user *ucrt32 = compat_ptr(arg);
struct compat_ica_rsa_modexpo_crt crt32;
@@ -1051,12 +1528,12 @@ static long trans_modexpo_crt32(struct file *filp, unsigned int cmd,
crt64.nq_prime = compat_ptr(crt32.nq_prime);
crt64.u_mult_inv = compat_ptr(crt32.u_mult_inv);
do {
- rc = zcrypt_rsa_crt(&crt64);
+ rc = zcrypt_rsa_crt(perms, &crt64);
} while (rc == -EAGAIN);
/* on failure: retry once again after a requested rescan */
if ((rc == -ENODEV) && (zcrypt_process_rescan()))
do {
- rc = zcrypt_rsa_crt(&crt64);
+ rc = zcrypt_rsa_crt(perms, &crt64);
} while (rc == -EAGAIN);
if (rc)
return rc;
@@ -1084,8 +1561,8 @@ struct compat_ica_xcRB {
unsigned int status;
} __packed;
-static long trans_xcRB32(struct file *filp, unsigned int cmd,
- unsigned long arg)
+static long trans_xcRB32(struct ap_perms *perms, struct file *filp,
+ unsigned int cmd, unsigned long arg)
{
struct compat_ica_xcRB __user *uxcRB32 = compat_ptr(arg);
struct compat_ica_xcRB xcRB32;
@@ -1115,12 +1592,12 @@ static long trans_xcRB32(struct file *filp, unsigned int cmd,
xcRB64.priority_window = xcRB32.priority_window;
xcRB64.status = xcRB32.status;
do {
- rc = zcrypt_send_cprb(&xcRB64);
+ rc = _zcrypt_send_cprb(perms, &xcRB64);
} while (rc == -EAGAIN);
/* on failure: retry once again after a requested rescan */
if ((rc == -ENODEV) && (zcrypt_process_rescan()))
do {
- rc = zcrypt_send_cprb(&xcRB64);
+ rc = _zcrypt_send_cprb(perms, &xcRB64);
} while (rc == -EAGAIN);
xcRB32.reply_control_blk_length = xcRB64.reply_control_blk_length;
xcRB32.reply_data_length = xcRB64.reply_data_length;
@@ -1133,12 +1610,20 @@ static long trans_xcRB32(struct file *filp, unsigned int cmd,
static long zcrypt_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
+ int rc;
+ struct ap_perms *perms =
+ (struct ap_perms *) filp->private_data;
+
+ rc = zcrypt_check_ioctl(perms, cmd);
+ if (rc)
+ return rc;
+
if (cmd == ICARSAMODEXPO)
- return trans_modexpo32(filp, cmd, arg);
+ return trans_modexpo32(perms, filp, cmd, arg);
if (cmd == ICARSACRT)
- return trans_modexpo_crt32(filp, cmd, arg);
+ return trans_modexpo_crt32(perms, filp, cmd, arg);
if (cmd == ZSECSENDCPRB)
- return trans_xcRB32(filp, cmd, arg);
+ return trans_xcRB32(perms, filp, cmd, arg);
return zcrypt_unlocked_ioctl(filp, cmd, arg);
}
#endif
@@ -1256,6 +1741,67 @@ void zcrypt_debug_exit(void)
debug_unregister(zcrypt_dbf_info);
}
+#ifdef CONFIG_ZCRYPT_MULTIDEVNODES
+
+static int __init zcdn_init(void)
+{
+ int rc;
+
+ /* create a new class 'zcrypt' */
+ zcrypt_class = class_create(THIS_MODULE, ZCRYPT_NAME);
+ if (IS_ERR(zcrypt_class)) {
+ rc = PTR_ERR(zcrypt_class);
+ goto out_class_create_failed;
+ }
+ zcrypt_class->dev_release = zcdn_device_release;
+
+ /* alloc device minor range */
+ rc = alloc_chrdev_region(&zcrypt_devt,
+ 0, ZCRYPT_MAX_MINOR_NODES,
+ ZCRYPT_NAME);
+ if (rc)
+ goto out_alloc_chrdev_failed;
+
+ cdev_init(&zcrypt_cdev, &zcrypt_fops);
+ zcrypt_cdev.owner = THIS_MODULE;
+ rc = cdev_add(&zcrypt_cdev, zcrypt_devt, ZCRYPT_MAX_MINOR_NODES);
+ if (rc)
+ goto out_cdev_add_failed;
+
+ /* need some class specific sysfs attributes */
+ rc = class_create_file(zcrypt_class, &class_attr_zcdn_create);
+ if (rc)
+ goto out_class_create_file_1_failed;
+ rc = class_create_file(zcrypt_class, &class_attr_zcdn_destroy);
+ if (rc)
+ goto out_class_create_file_2_failed;
+
+ return 0;
+
+out_class_create_file_2_failed:
+ class_remove_file(zcrypt_class, &class_attr_zcdn_create);
+out_class_create_file_1_failed:
+ cdev_del(&zcrypt_cdev);
+out_cdev_add_failed:
+ unregister_chrdev_region(zcrypt_devt, ZCRYPT_MAX_MINOR_NODES);
+out_alloc_chrdev_failed:
+ class_destroy(zcrypt_class);
+out_class_create_failed:
+ return rc;
+}
+
+static void zcdn_exit(void)
+{
+ class_remove_file(zcrypt_class, &class_attr_zcdn_create);
+ class_remove_file(zcrypt_class, &class_attr_zcdn_destroy);
+ zcdn_destroy_all();
+ cdev_del(&zcrypt_cdev);
+ unregister_chrdev_region(zcrypt_devt, ZCRYPT_MAX_MINOR_NODES);
+ class_destroy(zcrypt_class);
+}
+
+#endif
+
/**
* zcrypt_api_init(): Module initialization.
*
@@ -1269,15 +1815,27 @@ int __init zcrypt_api_init(void)
if (rc)
goto out;
+#ifdef CONFIG_ZCRYPT_MULTIDEVNODES
+ rc = zcdn_init();
+ if (rc)
+ goto out;
+#endif
+
/* Register the request sprayer. */
rc = misc_register(&zcrypt_misc_device);
if (rc < 0)
- goto out;
+ goto out_misc_register_failed;
zcrypt_msgtype6_init();
zcrypt_msgtype50_init();
+
return 0;
+out_misc_register_failed:
+#ifdef CONFIG_ZCRYPT_MULTIDEVNODES
+ zcdn_exit();
+#endif
+ zcrypt_debug_exit();
out:
return rc;
}
@@ -1289,6 +1847,9 @@ out:
*/
void __exit zcrypt_api_exit(void)
{
+#ifdef CONFIG_ZCRYPT_MULTIDEVNODES
+ zcdn_exit();
+#endif
misc_deregister(&zcrypt_misc_device);
zcrypt_msgtype6_exit();
zcrypt_msgtype50_exit();
diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h
index a848625c1a5a..af67a768a3fc 100644
--- a/drivers/s390/crypto/zcrypt_api.h
+++ b/drivers/s390/crypto/zcrypt_api.h
@@ -1,8 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
- * zcrypt 2.1.0
- *
- * Copyright IBM Corp. 2001, 2012
+ * Copyright IBM Corp. 2001, 2018
* Author(s): Robert Burroughs
* Eric Rossman (edrossma@us.ibm.com)
* Cornelia Huck <cornelia.huck@de.ibm.com>
@@ -22,17 +20,8 @@
#include "ap_bus.h"
/**
- * device type for an actual device is either PCICA, PCICC, PCIXCC_MCL2,
- * PCIXCC_MCL3, CEX2C, or CEX2A
- *
- * NOTE: PCIXCC_MCL3 refers to a PCIXCC with May 2004 version of Licensed
- * Internal Code (LIC) (EC J12220 level 29).
- * PCIXCC_MCL2 refers to any LIC before this level.
+ * Supported device types
*/
-#define ZCRYPT_PCICA 1
-#define ZCRYPT_PCICC 2
-#define ZCRYPT_PCIXCC_MCL2 3
-#define ZCRYPT_PCIXCC_MCL3 4
#define ZCRYPT_CEX2C 5
#define ZCRYPT_CEX2A 6
#define ZCRYPT_CEX3C 7
diff --git a/drivers/s390/crypto/zcrypt_card.c b/drivers/s390/crypto/zcrypt_card.c
index 40cd4c1c2de8..d4f35a183c15 100644
--- a/drivers/s390/crypto/zcrypt_card.c
+++ b/drivers/s390/crypto/zcrypt_card.c
@@ -1,7 +1,5 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * zcrypt 2.1.0
- *
* Copyright IBM Corp. 2001, 2012
* Author(s): Robert Burroughs
* Eric Rossman (edrossma@us.ibm.com)
diff --git a/drivers/s390/crypto/zcrypt_cca_key.h b/drivers/s390/crypto/zcrypt_cca_key.h
index e5b5c02c9d67..f09bb850763b 100644
--- a/drivers/s390/crypto/zcrypt_cca_key.h
+++ b/drivers/s390/crypto/zcrypt_cca_key.h
@@ -1,7 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
- * zcrypt 2.1.0
- *
* Copyright IBM Corp. 2001, 2006
* Author(s): Robert Burroughs
* Eric Rossman (edrossma@us.ibm.com)
diff --git a/drivers/s390/crypto/zcrypt_cex2a.c b/drivers/s390/crypto/zcrypt_cex2a.c
index f4ae5fa30ec9..146f54f5cbb8 100644
--- a/drivers/s390/crypto/zcrypt_cex2a.c
+++ b/drivers/s390/crypto/zcrypt_cex2a.c
@@ -1,7 +1,5 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * zcrypt 2.1.0
- *
* Copyright IBM Corp. 2001, 2012
* Author(s): Robert Burroughs
* Eric Rossman (edrossma@us.ibm.com)
@@ -43,8 +41,8 @@
#define CEX3A_CLEANUP_TIME CEX2A_CLEANUP_TIME
MODULE_AUTHOR("IBM Corporation");
-MODULE_DESCRIPTION("CEX2A Cryptographic Coprocessor device driver, " \
- "Copyright IBM Corp. 2001, 2012");
+MODULE_DESCRIPTION("CEX2A/CEX3A Cryptographic Coprocessor device driver, " \
+ "Copyright IBM Corp. 2001, 2018");
MODULE_LICENSE("GPL");
static struct ap_device_id zcrypt_cex2a_card_ids[] = {
diff --git a/drivers/s390/crypto/zcrypt_cex2a.h b/drivers/s390/crypto/zcrypt_cex2a.h
index 66d58bc87c66..7842214d9d09 100644
--- a/drivers/s390/crypto/zcrypt_cex2a.h
+++ b/drivers/s390/crypto/zcrypt_cex2a.h
@@ -1,7 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
- * zcrypt 2.1.0
- *
* Copyright IBM Corp. 2001, 2006
* Author(s): Robert Burroughs
* Eric Rossman (edrossma@us.ibm.com)
@@ -14,7 +12,7 @@
#define _ZCRYPT_CEX2A_H_
/**
- * The type 50 message family is associated with a CEX2A card.
+ * The type 50 message family is associated with CEXxA cards.
*
* The four members of the family are described below.
*
@@ -111,7 +109,7 @@ struct type50_crb3_msg {
} __packed;
/**
- * The type 80 response family is associated with a CEX2A card.
+ * The type 80 response family is associated with a CEXxA cards.
*
* Note that all unsigned char arrays are right-justified and left-padded
* with zeroes.
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_cex2c.c
index 94d9f7224aea..546f67676734 100644
--- a/drivers/s390/crypto/zcrypt_pcixcc.c
+++ b/drivers/s390/crypto/zcrypt_cex2c.c
@@ -1,8 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * zcrypt 2.1.0
- *
- * Copyright IBM Corp. 2001, 2012
+ * Copyright IBM Corp. 2001, 2018
* Author(s): Robert Burroughs
* Eric Rossman (edrossma@us.ibm.com)
*
@@ -25,39 +23,22 @@
#include "zcrypt_api.h"
#include "zcrypt_error.h"
#include "zcrypt_msgtype6.h"
-#include "zcrypt_pcixcc.h"
+#include "zcrypt_cex2c.h"
#include "zcrypt_cca_key.h"
-#define PCIXCC_MIN_MOD_SIZE 16 /* 128 bits */
-#define PCIXCC_MIN_MOD_SIZE_OLD 64 /* 512 bits */
-#define PCIXCC_MAX_MOD_SIZE 256 /* 2048 bits */
-#define CEX3C_MIN_MOD_SIZE PCIXCC_MIN_MOD_SIZE
+#define CEX2C_MIN_MOD_SIZE 16 /* 128 bits */
+#define CEX2C_MAX_MOD_SIZE 256 /* 2048 bits */
+#define CEX3C_MIN_MOD_SIZE 16 /* 128 bits */
#define CEX3C_MAX_MOD_SIZE 512 /* 4096 bits */
-
-#define PCIXCC_MAX_ICA_MESSAGE_SIZE 0x77c /* max size type6 v2 crt message */
-#define PCIXCC_MAX_ICA_RESPONSE_SIZE 0x77c /* max size type86 v2 reply */
-
-#define PCIXCC_MAX_XCRB_MESSAGE_SIZE (12*1024)
-
-#define PCIXCC_CLEANUP_TIME (15*HZ)
-
-#define CEIL4(x) ((((x)+3)/4)*4)
-
-struct response_type {
- struct completion work;
- int type;
-};
-#define PCIXCC_RESPONSE_TYPE_ICA 0
-#define PCIXCC_RESPONSE_TYPE_XCRB 1
+#define CEX2C_MAX_XCRB_MESSAGE_SIZE (12*1024)
+#define CEX2C_CLEANUP_TIME (15*HZ)
MODULE_AUTHOR("IBM Corporation");
-MODULE_DESCRIPTION("PCIXCC Cryptographic Coprocessor device driver, " \
- "Copyright IBM Corp. 2001, 2012");
+MODULE_DESCRIPTION("CEX2C/CEX3C Cryptographic Coprocessor device driver, " \
+ "Copyright IBM Corp. 2001, 2018");
MODULE_LICENSE("GPL");
-static struct ap_device_id zcrypt_pcixcc_card_ids[] = {
- { .dev_type = AP_DEVICE_TYPE_PCIXCC,
- .match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE },
+static struct ap_device_id zcrypt_cex2c_card_ids[] = {
{ .dev_type = AP_DEVICE_TYPE_CEX2C,
.match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE },
{ .dev_type = AP_DEVICE_TYPE_CEX3C,
@@ -65,11 +46,9 @@ static struct ap_device_id zcrypt_pcixcc_card_ids[] = {
{ /* end of list */ },
};
-MODULE_DEVICE_TABLE(ap, zcrypt_pcixcc_card_ids);
+MODULE_DEVICE_TABLE(ap, zcrypt_cex2c_card_ids);
-static struct ap_device_id zcrypt_pcixcc_queue_ids[] = {
- { .dev_type = AP_DEVICE_TYPE_PCIXCC,
- .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
+static struct ap_device_id zcrypt_cex2c_queue_ids[] = {
{ .dev_type = AP_DEVICE_TYPE_CEX2C,
.match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
{ .dev_type = AP_DEVICE_TYPE_CEX3C,
@@ -77,16 +56,16 @@ static struct ap_device_id zcrypt_pcixcc_queue_ids[] = {
{ /* end of list */ },
};
-MODULE_DEVICE_TABLE(ap, zcrypt_pcixcc_queue_ids);
+MODULE_DEVICE_TABLE(ap, zcrypt_cex2c_queue_ids);
/**
- * Large random number detection function. Its sends a message to a pcixcc
+ * Large random number detection function. Its sends a message to a CEX2C/CEX3C
* card to find out if large random numbers are supported.
* @ap_dev: pointer to the AP device.
*
* Returns 1 if large random numbers are supported, 0 if not and < 0 on error.
*/
-static int zcrypt_pcixcc_rng_supported(struct ap_queue *aq)
+static int zcrypt_cex2c_rng_supported(struct ap_queue *aq)
{
struct ap_message ap_msg;
unsigned long long psmid;
@@ -147,13 +126,11 @@ out_free:
}
/**
- * Probe function for PCIXCC/CEX2C card devices. It always accepts the
- * AP device since the bus_match already checked the hardware type. The
- * PCIXCC cards come in two flavours: micro code level 2 and micro code
- * level 3. This is checked by sending a test message to the device.
+ * Probe function for CEX2C/CEX3C card devices. It always accepts the
+ * AP device since the bus_match already checked the hardware type.
* @ap_dev: pointer to the AP card device.
*/
-static int zcrypt_pcixcc_card_probe(struct ap_device *ap_dev)
+static int zcrypt_cex2c_card_probe(struct ap_device *ap_dev)
{
/*
* Normalized speed ratings per crypto adapter
@@ -179,9 +156,9 @@ static int zcrypt_pcixcc_card_probe(struct ap_device *ap_dev)
zc->type_string = "CEX2C";
memcpy(zc->speed_rating, CEX2C_SPEED_IDX,
sizeof(CEX2C_SPEED_IDX));
- zc->min_mod_size = PCIXCC_MIN_MOD_SIZE;
- zc->max_mod_size = PCIXCC_MAX_MOD_SIZE;
- zc->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE;
+ zc->min_mod_size = CEX2C_MIN_MOD_SIZE;
+ zc->max_mod_size = CEX2C_MAX_MOD_SIZE;
+ zc->max_exp_bit_length = CEX2C_MAX_MOD_SIZE;
break;
case AP_DEVICE_TYPE_CEX3C:
zc->user_space_type = ZCRYPT_CEX3C;
@@ -208,10 +185,10 @@ static int zcrypt_pcixcc_card_probe(struct ap_device *ap_dev)
}
/**
- * This is called to remove the PCIXCC/CEX2C card driver information
+ * This is called to remove the CEX2C/CEX3C card driver information
* if an AP card device is removed.
*/
-static void zcrypt_pcixcc_card_remove(struct ap_device *ap_dev)
+static void zcrypt_cex2c_card_remove(struct ap_device *ap_dev)
{
struct zcrypt_card *zc = to_ap_card(&ap_dev->device)->private;
@@ -219,33 +196,31 @@ static void zcrypt_pcixcc_card_remove(struct ap_device *ap_dev)
zcrypt_card_unregister(zc);
}
-static struct ap_driver zcrypt_pcixcc_card_driver = {
- .probe = zcrypt_pcixcc_card_probe,
- .remove = zcrypt_pcixcc_card_remove,
- .ids = zcrypt_pcixcc_card_ids,
+static struct ap_driver zcrypt_cex2c_card_driver = {
+ .probe = zcrypt_cex2c_card_probe,
+ .remove = zcrypt_cex2c_card_remove,
+ .ids = zcrypt_cex2c_card_ids,
.flags = AP_DRIVER_FLAG_DEFAULT,
};
/**
- * Probe function for PCIXCC/CEX2C queue devices. It always accepts the
- * AP device since the bus_match already checked the hardware type. The
- * PCIXCC cards come in two flavours: micro code level 2 and micro code
- * level 3. This is checked by sending a test message to the device.
+ * Probe function for CEX2C/CEX3C queue devices. It always accepts the
+ * AP device since the bus_match already checked the hardware type.
* @ap_dev: pointer to the AP card device.
*/
-static int zcrypt_pcixcc_queue_probe(struct ap_device *ap_dev)
+static int zcrypt_cex2c_queue_probe(struct ap_device *ap_dev)
{
struct ap_queue *aq = to_ap_queue(&ap_dev->device);
struct zcrypt_queue *zq;
int rc;
- zq = zcrypt_queue_alloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE);
+ zq = zcrypt_queue_alloc(CEX2C_MAX_XCRB_MESSAGE_SIZE);
if (!zq)
return -ENOMEM;
zq->queue = aq;
zq->online = 1;
atomic_set(&zq->load, 0);
- rc = zcrypt_pcixcc_rng_supported(aq);
+ rc = zcrypt_cex2c_rng_supported(aq);
if (rc < 0) {
zcrypt_queue_free(zq);
return rc;
@@ -257,7 +232,7 @@ static int zcrypt_pcixcc_queue_probe(struct ap_device *ap_dev)
zq->ops = zcrypt_msgtype(MSGTYPE06_NAME,
MSGTYPE06_VARIANT_NORNG);
ap_queue_init_reply(aq, &zq->reply);
- aq->request_timeout = PCIXCC_CLEANUP_TIME,
+ aq->request_timeout = CEX2C_CLEANUP_TIME;
aq->private = zq;
rc = zcrypt_queue_register(zq);
if (rc) {
@@ -268,10 +243,10 @@ static int zcrypt_pcixcc_queue_probe(struct ap_device *ap_dev)
}
/**
- * This is called to remove the PCIXCC/CEX2C queue driver information
+ * This is called to remove the CEX2C/CEX3C queue driver information
* if an AP queue device is removed.
*/
-static void zcrypt_pcixcc_queue_remove(struct ap_device *ap_dev)
+static void zcrypt_cex2c_queue_remove(struct ap_device *ap_dev)
{
struct ap_queue *aq = to_ap_queue(&ap_dev->device);
struct zcrypt_queue *zq = aq->private;
@@ -281,37 +256,37 @@ static void zcrypt_pcixcc_queue_remove(struct ap_device *ap_dev)
zcrypt_queue_unregister(zq);
}
-static struct ap_driver zcrypt_pcixcc_queue_driver = {
- .probe = zcrypt_pcixcc_queue_probe,
- .remove = zcrypt_pcixcc_queue_remove,
+static struct ap_driver zcrypt_cex2c_queue_driver = {
+ .probe = zcrypt_cex2c_queue_probe,
+ .remove = zcrypt_cex2c_queue_remove,
.suspend = ap_queue_suspend,
.resume = ap_queue_resume,
- .ids = zcrypt_pcixcc_queue_ids,
+ .ids = zcrypt_cex2c_queue_ids,
.flags = AP_DRIVER_FLAG_DEFAULT,
};
-int __init zcrypt_pcixcc_init(void)
+int __init zcrypt_cex2c_init(void)
{
int rc;
- rc = ap_driver_register(&zcrypt_pcixcc_card_driver,
- THIS_MODULE, "pcixcccard");
+ rc = ap_driver_register(&zcrypt_cex2c_card_driver,
+ THIS_MODULE, "cex2card");
if (rc)
return rc;
- rc = ap_driver_register(&zcrypt_pcixcc_queue_driver,
- THIS_MODULE, "pcixccqueue");
+ rc = ap_driver_register(&zcrypt_cex2c_queue_driver,
+ THIS_MODULE, "cex2cqueue");
if (rc)
- ap_driver_unregister(&zcrypt_pcixcc_card_driver);
+ ap_driver_unregister(&zcrypt_cex2c_card_driver);
return rc;
}
-void zcrypt_pcixcc_exit(void)
+void zcrypt_cex2c_exit(void)
{
- ap_driver_unregister(&zcrypt_pcixcc_queue_driver);
- ap_driver_unregister(&zcrypt_pcixcc_card_driver);
+ ap_driver_unregister(&zcrypt_cex2c_queue_driver);
+ ap_driver_unregister(&zcrypt_cex2c_card_driver);
}
-module_init(zcrypt_pcixcc_init);
-module_exit(zcrypt_pcixcc_exit);
+module_init(zcrypt_cex2c_init);
+module_exit(zcrypt_cex2c_exit);
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.h b/drivers/s390/crypto/zcrypt_cex2c.h
index cf73a0f91e9c..6ec405c2bec2 100644
--- a/drivers/s390/crypto/zcrypt_pcixcc.h
+++ b/drivers/s390/crypto/zcrypt_cex2c.h
@@ -1,8 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
- * zcrypt 2.1.0
- *
- * Copyright IBM Corp. 2001, 2012
+ * Copyright IBM Corp. 2001, 2018
* Author(s): Robert Burroughs
* Eric Rossman (edrossma@us.ibm.com)
*
@@ -11,10 +9,10 @@
* MSGTYPE restruct: Holger Dengler <hd@linux.vnet.ibm.com>
*/
-#ifndef _ZCRYPT_PCIXCC_H_
-#define _ZCRYPT_PCIXCC_H_
+#ifndef _ZCRYPT_CEX2C_H_
+#define _ZCRYPT_CEX2C_H_
-int zcrypt_pcixcc_init(void);
-void zcrypt_pcixcc_exit(void);
+int zcrypt_cex2c_init(void);
+void zcrypt_cex2c_exit(void);
-#endif /* _ZCRYPT_PCIXCC_H_ */
+#endif /* _ZCRYPT_CEX2C_H_ */
diff --git a/drivers/s390/crypto/zcrypt_cex4.c b/drivers/s390/crypto/zcrypt_cex4.c
index 35d58dbbc4da..f9d4c6c7521d 100644
--- a/drivers/s390/crypto/zcrypt_cex4.c
+++ b/drivers/s390/crypto/zcrypt_cex4.c
@@ -37,8 +37,8 @@
#define CEX4_CLEANUP_TIME (900*HZ)
MODULE_AUTHOR("IBM Corporation");
-MODULE_DESCRIPTION("CEX4 Cryptographic Card device driver, " \
- "Copyright IBM Corp. 2012");
+MODULE_DESCRIPTION("CEX4/CEX5/CEX6 Cryptographic Card device driver, " \
+ "Copyright IBM Corp. 2018");
MODULE_LICENSE("GPL");
static struct ap_device_id zcrypt_cex4_card_ids[] = {
@@ -66,8 +66,9 @@ static struct ap_device_id zcrypt_cex4_queue_ids[] = {
MODULE_DEVICE_TABLE(ap, zcrypt_cex4_queue_ids);
/**
- * Probe function for CEX4 card device. It always accepts the AP device
- * since the bus_match already checked the hardware type.
+ * Probe function for CEX4/CEX5/CEX6 card device. It always
+ * accepts the AP device since the bus_match already checked
+ * the hardware type.
* @ap_dev: pointer to the AP device.
*/
static int zcrypt_cex4_card_probe(struct ap_device *ap_dev)
@@ -199,7 +200,7 @@ static int zcrypt_cex4_card_probe(struct ap_device *ap_dev)
}
/**
- * This is called to remove the CEX4 card driver information
+ * This is called to remove the CEX4/CEX5/CEX6 card driver information
* if an AP card device is removed.
*/
static void zcrypt_cex4_card_remove(struct ap_device *ap_dev)
@@ -218,8 +219,9 @@ static struct ap_driver zcrypt_cex4_card_driver = {
};
/**
- * Probe function for CEX4 queue device. It always accepts the AP device
- * since the bus_match already checked the hardware type.
+ * Probe function for CEX4/CEX5/CEX6 queue device. It always
+ * accepts the AP device since the bus_match already checked
+ * the hardware type.
* @ap_dev: pointer to the AP device.
*/
static int zcrypt_cex4_queue_probe(struct ap_device *ap_dev)
@@ -265,8 +267,8 @@ static int zcrypt_cex4_queue_probe(struct ap_device *ap_dev)
}
/**
- * This is called to remove the CEX4 queue driver information
- * if an AP queue device is removed.
+ * This is called to remove the CEX4/CEX5/CEX6 queue driver
+ * information if an AP queue device is removed.
*/
static void zcrypt_cex4_queue_remove(struct ap_device *ap_dev)
{
diff --git a/drivers/s390/crypto/zcrypt_error.h b/drivers/s390/crypto/zcrypt_error.h
index 6f7ebc1dbe10..240b27f3f5f6 100644
--- a/drivers/s390/crypto/zcrypt_error.h
+++ b/drivers/s390/crypto/zcrypt_error.h
@@ -1,7 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
- * zcrypt 2.1.0
- *
* Copyright IBM Corp. 2001, 2006
* Author(s): Robert Burroughs
* Eric Rossman (edrossma@us.ibm.com)
@@ -16,6 +14,7 @@
#include <linux/atomic.h>
#include "zcrypt_debug.h"
#include "zcrypt_api.h"
+#include "zcrypt_msgtype6.h"
/**
* Reply Messages
@@ -114,6 +113,27 @@ static inline int convert_error(struct zcrypt_queue *zq,
card, queue, ehdr->reply_code);
return -EAGAIN;
case REP82_ERROR_TRANSPORT_FAIL:
+ /* Card or infrastructure failure, disable card */
+ atomic_set(&zcrypt_rescan_req, 1);
+ zq->online = 0;
+ pr_err("Cryptographic device %02x.%04x failed and was set offline\n",
+ card, queue);
+ /* For type 86 response show the apfs value (failure reason) */
+ if (ehdr->type == TYPE86_RSP_CODE) {
+ struct {
+ struct type86_hdr hdr;
+ struct type86_fmt2_ext fmt2;
+ } __packed * head = reply->message;
+ unsigned int apfs = *((u32 *)head->fmt2.apfs);
+
+ ZCRYPT_DBF(DBF_ERR,
+ "device=%02x.%04x reply=0x%02x apfs=0x%x => online=0 rc=EAGAIN\n",
+ card, queue, apfs, ehdr->reply_code);
+ } else
+ ZCRYPT_DBF(DBF_ERR,
+ "device=%02x.%04x reply=0x%02x => online=0 rc=EAGAIN\n",
+ card, queue, ehdr->reply_code);
+ return -EAGAIN;
case REP82_ERROR_MACHINE_FAILURE:
// REP88_ERROR_MODULE_FAILURE // '10' CEX2A
/* If a card fails disable it and repeat the request. */
diff --git a/drivers/s390/crypto/zcrypt_msgtype50.c b/drivers/s390/crypto/zcrypt_msgtype50.c
index f159662c907b..fc4295b3d801 100644
--- a/drivers/s390/crypto/zcrypt_msgtype50.c
+++ b/drivers/s390/crypto/zcrypt_msgtype50.c
@@ -1,7 +1,5 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * zcrypt 2.1.0
- *
* Copyright IBM Corp. 2001, 2012
* Author(s): Robert Burroughs
* Eric Rossman (edrossma@us.ibm.com)
@@ -27,13 +25,13 @@
#include "zcrypt_error.h"
#include "zcrypt_msgtype50.h"
-/* 4096 bits */
+/* >= CEX3A: 4096 bits */
#define CEX3A_MAX_MOD_SIZE 512
-/* max outputdatalength + type80_hdr */
+/* CEX2A: max outputdatalength + type80_hdr */
#define CEX2A_MAX_RESPONSE_SIZE 0x110
-/* 512 bit modulus, (max outputdatalength) + type80_hdr */
+/* >= CEX3A: 512 bit modulus, (max outputdatalength) + type80_hdr */
#define CEX3A_MAX_RESPONSE_SIZE 0x210
MODULE_AUTHOR("IBM Corporation");
@@ -42,7 +40,7 @@ MODULE_DESCRIPTION("Cryptographic Accelerator (message type 50), " \
MODULE_LICENSE("GPL");
/**
- * The type 50 message family is associated with a CEX2A card.
+ * The type 50 message family is associated with a CEXxA cards.
*
* The four members of the family are described below.
*
@@ -139,7 +137,7 @@ struct type50_crb3_msg {
} __packed;
/**
- * The type 80 response family is associated with a CEX2A card.
+ * The type 80 response family is associated with a CEXxA cards.
*
* Note that all unsigned char arrays are right-justified and left-padded
* with zeroes.
@@ -273,7 +271,7 @@ static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_queue *zq,
/*
* CEX2A and CEX3A w/o FW update can handle requests up to
* 256 byte modulus (2k keys).
- * CEX3A with FW update and CEX4A cards are able to handle
+ * CEX3A with FW update and newer CEXxA cards are able to handle
* 512 byte modulus (4k keys).
*/
if (mod_len <= 128) { /* up to 1024 bit key size */
@@ -356,7 +354,7 @@ static int convert_type80(struct zcrypt_queue *zq,
unsigned char *data;
if (t80h->len < sizeof(*t80h) + outputdatalength) {
- /* The result is too short, the CEX2A card may not do that.. */
+ /* The result is too short, the CEXxA card may not do that.. */
zq->online = 0;
pr_err("Cryptographic device %02x.%04x failed and was set offline\n",
AP_QID_CARD(zq->queue->qid),
@@ -447,10 +445,10 @@ out:
static atomic_t zcrypt_step = ATOMIC_INIT(0);
/**
- * The request distributor calls this function if it picked the CEX2A
+ * The request distributor calls this function if it picked the CEXxA
* device to handle a modexpo request.
* @zq: pointer to zcrypt_queue structure that identifies the
- * CEX2A device to the request distributor
+ * CEXxA device to the request distributor
* @mex: pointer to the modexpo request buffer
*/
static long zcrypt_cex2a_modexpo(struct zcrypt_queue *zq,
@@ -493,10 +491,10 @@ out_free:
}
/**
- * The request distributor calls this function if it picked the CEX2A
+ * The request distributor calls this function if it picked the CEXxA
* device to handle a modexpo_crt request.
* @zq: pointer to zcrypt_queue structure that identifies the
- * CEX2A device to the request distributor
+ * CEXxA device to the request distributor
* @crt: pointer to the modexpoc_crt request buffer
*/
static long zcrypt_cex2a_modexpo_crt(struct zcrypt_queue *zq,
diff --git a/drivers/s390/crypto/zcrypt_msgtype50.h b/drivers/s390/crypto/zcrypt_msgtype50.h
index 8530f652ea4f..66bec4f45c56 100644
--- a/drivers/s390/crypto/zcrypt_msgtype50.h
+++ b/drivers/s390/crypto/zcrypt_msgtype50.h
@@ -1,7 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
- * zcrypt 2.1.0
- *
* Copyright IBM Corp. 2001, 2012
* Author(s): Robert Burroughs
* Eric Rossman (edrossma@us.ibm.com)
diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c
index 2101776a8148..0cbcc238ef98 100644
--- a/drivers/s390/crypto/zcrypt_msgtype6.c
+++ b/drivers/s390/crypto/zcrypt_msgtype6.c
@@ -1,7 +1,5 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * zcrypt 2.1.0
- *
* Copyright IBM Corp. 2001, 2012
* Author(s): Robert Burroughs
* Eric Rossman (edrossma@us.ibm.com)
@@ -29,8 +27,7 @@
#include "zcrypt_msgtype6.h"
#include "zcrypt_cca_key.h"
-#define PCIXCC_MIN_MOD_SIZE_OLD 64 /* 512 bits */
-#define PCIXCC_MAX_ICA_RESPONSE_SIZE 0x77c /* max size type86 v2 reply */
+#define CEXXC_MAX_ICA_RESPONSE_SIZE 0x77c /* max size type86 v2 reply */
#define CEIL4(x) ((((x)+3)/4)*4)
@@ -38,9 +35,9 @@ struct response_type {
struct completion work;
int type;
};
-#define PCIXCC_RESPONSE_TYPE_ICA 0
-#define PCIXCC_RESPONSE_TYPE_XCRB 1
-#define PCIXCC_RESPONSE_TYPE_EP11 2
+#define CEXXC_RESPONSE_TYPE_ICA 0
+#define CEXXC_RESPONSE_TYPE_XCRB 1
+#define CEXXC_RESPONSE_TYPE_EP11 2
MODULE_AUTHOR("IBM Corporation");
MODULE_DESCRIPTION("Cryptographic Coprocessor (message type 6), " \
@@ -111,7 +108,7 @@ struct function_and_rules_block {
} __packed;
/**
- * The following is used to initialize the CPRBX passed to the PCIXCC/CEX2C
+ * The following is used to initialize the CPRBX passed to the CEXxC/CEXxP
* card in a type6 message. The 3 fields that must be filled in at execution
* time are req_parml, rpl_parml and usage_domain.
* Everything about this interface is ascii/big-endian, since the
@@ -294,7 +291,7 @@ static int ICAMEX_msg_to_type6MEX_msgX(struct zcrypt_queue *zq,
/* message header, cprbx and f&r */
msg->hdr = static_type6_hdrX;
msg->hdr.ToCardLen1 = size - sizeof(msg->hdr);
- msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr);
+ msg->hdr.FromCardLen1 = CEXXC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr);
msg->cprbx = static_cprbx;
msg->cprbx.domain = AP_QID_QUEUE(zq->queue->qid);
@@ -364,7 +361,7 @@ static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_queue *zq,
/* message header, cprbx and f&r */
msg->hdr = static_type6_hdrX;
msg->hdr.ToCardLen1 = size - sizeof(msg->hdr);
- msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr);
+ msg->hdr.FromCardLen1 = CEXXC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr);
msg->cprbx = static_cprbx;
msg->cprbx.domain = AP_QID_QUEUE(zq->queue->qid);
@@ -658,16 +655,6 @@ static int convert_type86_ica(struct zcrypt_queue *zq,
(int) service_rc, (int) service_rs);
return -EINVAL;
}
- if (service_rc == 8 && service_rs == 783) {
- zq->zcard->min_mod_size =
- PCIXCC_MIN_MOD_SIZE_OLD;
- ZCRYPT_DBF(DBF_DEBUG,
- "device=%02x.%04x rc/rs=%d/%d => rc=EAGAIN\n",
- AP_QID_CARD(zq->queue->qid),
- AP_QID_QUEUE(zq->queue->qid),
- (int) service_rc, (int) service_rs);
- return -EAGAIN;
- }
zq->online = 0;
pr_err("Cryptographic device %02x.%04x failed and was set offline\n",
AP_QID_CARD(zq->queue->qid),
@@ -697,7 +684,7 @@ static int convert_type86_ica(struct zcrypt_queue *zq,
if (pad_len > 0) {
if (pad_len < 10)
return -EINVAL;
- /* 'restore' padding left in the PCICC/PCIXCC card. */
+ /* 'restore' padding left in the CEXXC card. */
if (copy_to_user(outputdata, static_pad, pad_len - 1))
return -EFAULT;
if (put_user(0, outputdata + pad_len - 1))
@@ -955,13 +942,13 @@ static void zcrypt_msgtype6_receive(struct ap_queue *aq,
if (t86r->hdr.type == TYPE86_RSP_CODE &&
t86r->cprbx.cprb_ver_id == 0x02) {
switch (resp_type->type) {
- case PCIXCC_RESPONSE_TYPE_ICA:
+ case CEXXC_RESPONSE_TYPE_ICA:
length = sizeof(struct type86x_reply)
+ t86r->length - 2;
- length = min(PCIXCC_MAX_ICA_RESPONSE_SIZE, length);
+ length = min(CEXXC_MAX_ICA_RESPONSE_SIZE, length);
memcpy(msg->message, reply->message, length);
break;
- case PCIXCC_RESPONSE_TYPE_XCRB:
+ case CEXXC_RESPONSE_TYPE_XCRB:
length = t86r->fmt2.offset2 + t86r->fmt2.count2;
length = min(MSGTYPE06_MAX_MSG_SIZE, length);
memcpy(msg->message, reply->message, length);
@@ -1004,7 +991,7 @@ static void zcrypt_msgtype6_receive_ep11(struct ap_queue *aq,
if (t86r->hdr.type == TYPE86_RSP_CODE &&
t86r->cprbx.cprb_ver_id == 0x04) {
switch (resp_type->type) {
- case PCIXCC_RESPONSE_TYPE_EP11:
+ case CEXXC_RESPONSE_TYPE_EP11:
length = t86r->fmt2.offset1 + t86r->fmt2.count1;
length = min(MSGTYPE06_MAX_MSG_SIZE, length);
memcpy(msg->message, reply->message, length);
@@ -1022,10 +1009,10 @@ out:
static atomic_t zcrypt_step = ATOMIC_INIT(0);
/**
- * The request distributor calls this function if it picked the PCIXCC/CEX2C
+ * The request distributor calls this function if it picked the CEXxC
* device to handle a modexpo request.
* @zq: pointer to zcrypt_queue structure that identifies the
- * PCIXCC/CEX2C device to the request distributor
+ * CEXxC device to the request distributor
* @mex: pointer to the modexpo request buffer
*/
static long zcrypt_msgtype6_modexpo(struct zcrypt_queue *zq,
@@ -1033,7 +1020,7 @@ static long zcrypt_msgtype6_modexpo(struct zcrypt_queue *zq,
{
struct ap_message ap_msg;
struct response_type resp_type = {
- .type = PCIXCC_RESPONSE_TYPE_ICA,
+ .type = CEXXC_RESPONSE_TYPE_ICA,
};
int rc;
@@ -1066,10 +1053,10 @@ out_free:
}
/**
- * The request distributor calls this function if it picked the PCIXCC/CEX2C
+ * The request distributor calls this function if it picked the CEXxC
* device to handle a modexpo_crt request.
* @zq: pointer to zcrypt_queue structure that identifies the
- * PCIXCC/CEX2C device to the request distributor
+ * CEXxC device to the request distributor
* @crt: pointer to the modexpoc_crt request buffer
*/
static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_queue *zq,
@@ -1077,7 +1064,7 @@ static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_queue *zq,
{
struct ap_message ap_msg;
struct response_type resp_type = {
- .type = PCIXCC_RESPONSE_TYPE_ICA,
+ .type = CEXXC_RESPONSE_TYPE_ICA,
};
int rc;
@@ -1122,7 +1109,7 @@ unsigned int get_cprb_fc(struct ica_xcRB *xcRB,
unsigned int *func_code, unsigned short **dom)
{
struct response_type resp_type = {
- .type = PCIXCC_RESPONSE_TYPE_XCRB,
+ .type = CEXXC_RESPONSE_TYPE_XCRB,
};
ap_msg->message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL);
@@ -1131,18 +1118,17 @@ unsigned int get_cprb_fc(struct ica_xcRB *xcRB,
ap_msg->receive = zcrypt_msgtype6_receive;
ap_msg->psmid = (((unsigned long long) current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
- ap_msg->private = kmalloc(sizeof(resp_type), GFP_KERNEL);
+ ap_msg->private = kmemdup(&resp_type, sizeof(resp_type), GFP_KERNEL);
if (!ap_msg->private)
return -ENOMEM;
- memcpy(ap_msg->private, &resp_type, sizeof(resp_type));
return XCRB_msg_to_type6CPRB_msgX(ap_msg, xcRB, func_code, dom);
}
/**
- * The request distributor calls this function if it picked the PCIXCC/CEX2C
+ * The request distributor calls this function if it picked the CEXxC
* device to handle a send_cprb request.
* @zq: pointer to zcrypt_queue structure that identifies the
- * PCIXCC/CEX2C device to the request distributor
+ * CEXxC device to the request distributor
* @xcRB: pointer to the send_cprb request buffer
*/
static long zcrypt_msgtype6_send_cprb(struct zcrypt_queue *zq,
@@ -1178,7 +1164,7 @@ unsigned int get_ep11cprb_fc(struct ep11_urb *xcrb,
unsigned int *func_code)
{
struct response_type resp_type = {
- .type = PCIXCC_RESPONSE_TYPE_EP11,
+ .type = CEXXC_RESPONSE_TYPE_EP11,
};
ap_msg->message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL);
@@ -1187,10 +1173,9 @@ unsigned int get_ep11cprb_fc(struct ep11_urb *xcrb,
ap_msg->receive = zcrypt_msgtype6_receive_ep11;
ap_msg->psmid = (((unsigned long long) current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
- ap_msg->private = kmalloc(sizeof(resp_type), GFP_KERNEL);
+ ap_msg->private = kmemdup(&resp_type, sizeof(resp_type), GFP_KERNEL);
if (!ap_msg->private)
return -ENOMEM;
- memcpy(ap_msg->private, &resp_type, sizeof(resp_type));
return xcrb_msg_to_type6_ep11cprb_msgx(ap_msg, xcrb, func_code);
}
@@ -1273,7 +1258,7 @@ unsigned int get_rng_fc(struct ap_message *ap_msg, int *func_code,
unsigned int *domain)
{
struct response_type resp_type = {
- .type = PCIXCC_RESPONSE_TYPE_XCRB,
+ .type = CEXXC_RESPONSE_TYPE_XCRB,
};
ap_msg->message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL);
@@ -1282,10 +1267,9 @@ unsigned int get_rng_fc(struct ap_message *ap_msg, int *func_code,
ap_msg->receive = zcrypt_msgtype6_receive;
ap_msg->psmid = (((unsigned long long) current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
- ap_msg->private = kmalloc(sizeof(resp_type), GFP_KERNEL);
+ ap_msg->private = kmemdup(&resp_type, sizeof(resp_type), GFP_KERNEL);
if (!ap_msg->private)
return -ENOMEM;
- memcpy(ap_msg->private, &resp_type, sizeof(resp_type));
rng_type6CPRB_msgX(ap_msg, ZCRYPT_RNG_BUFFER_SIZE, domain);
@@ -1294,10 +1278,10 @@ unsigned int get_rng_fc(struct ap_message *ap_msg, int *func_code,
}
/**
- * The request distributor calls this function if it picked the PCIXCC/CEX2C
+ * The request distributor calls this function if it picked the CEXxC
* device to generate random data.
* @zq: pointer to zcrypt_queue structure that identifies the
- * PCIXCC/CEX2C device to the request distributor
+ * CEXxC device to the request distributor
* @buffer: pointer to a memory page to return random data
*/
static long zcrypt_msgtype6_rng(struct zcrypt_queue *zq,
@@ -1332,7 +1316,7 @@ static long zcrypt_msgtype6_rng(struct zcrypt_queue *zq,
}
/**
- * The crypto operations for a PCIXCC/CEX2C card.
+ * The crypto operations for a CEXxC card.
*/
static struct zcrypt_ops zcrypt_msgtype6_norng_ops = {
.owner = THIS_MODULE,
diff --git a/drivers/s390/crypto/zcrypt_msgtype6.h b/drivers/s390/crypto/zcrypt_msgtype6.h
index e4c2f37d7ad9..41a0df5f070f 100644
--- a/drivers/s390/crypto/zcrypt_msgtype6.h
+++ b/drivers/s390/crypto/zcrypt_msgtype6.h
@@ -1,7 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
- * zcrypt 2.1.0
- *
* Copyright IBM Corp. 2001, 2012
* Author(s): Robert Burroughs
* Eric Rossman (edrossma@us.ibm.com)
@@ -24,7 +22,7 @@
#define MSGTYPE06_MAX_MSG_SIZE (12*1024)
/**
- * The type 6 message family is associated with PCICC or PCIXCC cards.
+ * The type 6 message family is associated with CEXxC/CEXxP cards.
*
* It contains a message header followed by a CPRB, both of which
* are described below.
@@ -43,13 +41,8 @@ struct type6_hdr {
unsigned int offset2; /* 0x00000000 */
unsigned int offset3; /* 0x00000000 */
unsigned int offset4; /* 0x00000000 */
- unsigned char agent_id[16]; /* PCICC: */
- /* 0x0100 */
- /* 0x4343412d4150504c202020 */
- /* 0x010101 */
- /* PCIXCC: */
- /* 0x4341000000000000 */
- /* 0x0000000000000000 */
+ unsigned char agent_id[16]; /* 0x4341000000000000 */
+ /* 0x0000000000000000 */
unsigned char rqid[2]; /* rqid. internal to 603 */
unsigned char reserved5[2]; /* 0x0000 */
unsigned char function_code[2]; /* for PKD, 0x5044 (ascii 'PD') */
@@ -65,7 +58,7 @@ struct type6_hdr {
} __packed;
/**
- * The type 86 message family is associated with PCICC and PCIXCC cards.
+ * The type 86 message family is associated with CEXxC/CEXxP cards.
*
* It contains a message header followed by a CPRB. The CPRB is
* the same as the request CPRB, which is described above.
diff --git a/drivers/s390/crypto/zcrypt_queue.c b/drivers/s390/crypto/zcrypt_queue.c
index 8df82c6ef66e..522c4bc69a08 100644
--- a/drivers/s390/crypto/zcrypt_queue.c
+++ b/drivers/s390/crypto/zcrypt_queue.c
@@ -1,7 +1,5 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * zcrypt 2.1.0
- *
* Copyright IBM Corp. 2001, 2012
* Author(s): Robert Burroughs
* Eric Rossman (edrossma@us.ibm.com)
diff --git a/drivers/s390/net/ism_drv.c b/drivers/s390/net/ism_drv.c
index c0631895154e..f96ec68af2e5 100644
--- a/drivers/s390/net/ism_drv.c
+++ b/drivers/s390/net/ism_drv.c
@@ -515,8 +515,8 @@ static int ism_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (ret)
goto err_unmap;
- pci_set_dma_seg_boundary(pdev, SZ_1M - 1);
- pci_set_dma_max_seg_size(pdev, SZ_1M);
+ dma_set_seg_boundary(&pdev->dev, SZ_1M - 1);
+ dma_set_max_seg_size(&pdev->dev, SZ_1M);
pci_set_master(pdev);
ism->smcd = smcd_alloc_dev(&pdev->dev, dev_name(&pdev->dev), &ism_ops,
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index 34e0d476c5c6..04e294d1d16d 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -26,6 +26,7 @@
#include <net/ipv6.h>
#include <net/if_inet6.h>
#include <net/addrconf.h>
+#include <net/tcp.h>
#include <asm/debug.h>
#include <asm/qdio.h>
@@ -86,6 +87,18 @@ struct qeth_dbf_info {
#define SENSE_RESETTING_EVENT_BYTE 1
#define SENSE_RESETTING_EVENT_FLAG 0x80
+static inline u32 qeth_get_device_id(struct ccw_device *cdev)
+{
+ struct ccw_dev_id dev_id;
+ u32 id;
+
+ ccw_device_get_id(cdev, &dev_id);
+ id = dev_id.devno;
+ id |= (u32) (dev_id.ssid << 16);
+
+ return id;
+}
+
/*
* Common IO related definitions
*/
@@ -96,7 +109,8 @@ struct qeth_dbf_info {
#define CARD_RDEV_ID(card) dev_name(&card->read.ccwdev->dev)
#define CARD_WDEV_ID(card) dev_name(&card->write.ccwdev->dev)
#define CARD_DDEV_ID(card) dev_name(&card->data.ccwdev->dev)
-#define CHANNEL_ID(channel) dev_name(&channel->ccwdev->dev)
+#define CCW_DEVID(cdev) (qeth_get_device_id(cdev))
+#define CARD_DEVID(card) (CCW_DEVID(CARD_RDEV(card)))
/**
* card stuff
@@ -389,8 +403,9 @@ enum qeth_layer2_frame_flags {
enum qeth_header_ids {
QETH_HEADER_TYPE_LAYER3 = 0x01,
QETH_HEADER_TYPE_LAYER2 = 0x02,
- QETH_HEADER_TYPE_TSO = 0x03,
+ QETH_HEADER_TYPE_L3_TSO = 0x03,
QETH_HEADER_TYPE_OSN = 0x04,
+ QETH_HEADER_TYPE_L2_TSO = 0x06,
};
/* flags for qeth_hdr.ext_flags */
#define QETH_HDR_EXT_VLAN_FRAME 0x01
@@ -581,7 +596,8 @@ struct qeth_cmd_buffer {
struct qeth_channel *channel;
unsigned char *data;
int rc;
- void (*callback) (struct qeth_channel *, struct qeth_cmd_buffer *);
+ void (*callback)(struct qeth_card *card, struct qeth_channel *channel,
+ struct qeth_cmd_buffer *iob);
};
static inline struct qeth_ipa_cmd *__ipa_cmd(struct qeth_cmd_buffer *iob)
@@ -638,7 +654,6 @@ struct qeth_reply {
atomic_t received;
int rc;
void *param;
- struct qeth_card *card;
refcount_t refcnt;
};
@@ -671,6 +686,12 @@ struct qeth_card_info {
__u32 hwtrap;
};
+enum qeth_discipline_id {
+ QETH_DISCIPLINE_UNDETERMINED = -1,
+ QETH_DISCIPLINE_LAYER3 = 0,
+ QETH_DISCIPLINE_LAYER2 = 1,
+};
+
struct qeth_card_options {
struct qeth_routing_info route4;
struct qeth_ipa_info ipa4;
@@ -680,7 +701,7 @@ struct qeth_card_options {
struct qeth_sbp_info sbp; /* SETBRIDGEPORT options */
struct qeth_vnicc_info vnicc; /* VNICC options */
int fake_broadcast;
- int layer2;
+ enum qeth_discipline_id layer;
int performance_stats;
int rx_sg_cb;
enum qeth_ipa_isolation_modes isolation;
@@ -690,6 +711,9 @@ struct qeth_card_options {
char hsuid[9];
};
+#define IS_LAYER2(card) ((card)->options.layer == QETH_DISCIPLINE_LAYER2)
+#define IS_LAYER3(card) ((card)->options.layer == QETH_DISCIPLINE_LAYER3)
+
/*
* thread bits for qeth_card thread masks
*/
@@ -702,12 +726,6 @@ struct qeth_osn_info {
int (*data_cb)(struct sk_buff *skb);
};
-enum qeth_discipline_id {
- QETH_DISCIPLINE_UNDETERMINED = -1,
- QETH_DISCIPLINE_LAYER3 = 0,
- QETH_DISCIPLINE_LAYER2 = 1,
-};
-
struct qeth_discipline {
const struct device_type *devtype;
int (*process_rx_buffer)(struct qeth_card *card, int budget, int *done);
@@ -759,7 +777,6 @@ struct qeth_switch_info {
struct qeth_card {
struct list_head list;
enum qeth_card_states state;
- int lan_online;
spinlock_t lock;
struct ccwgroup_device *gdev;
struct qeth_channel read;
@@ -826,6 +843,11 @@ struct qeth_trap_id {
/*some helper functions*/
#define QETH_CARD_IFNAME(card) (((card)->dev)? (card)->dev->name : "")
+static inline bool qeth_netdev_is_registered(struct net_device *dev)
+{
+ return dev->netdev_ops != NULL;
+}
+
static inline void qeth_scrub_qdio_buffer(struct qdio_buffer *buf,
unsigned int elements)
{
@@ -892,11 +914,6 @@ static inline void qeth_tx_csum(struct sk_buff *skb, u8 *flags, int ipv)
if ((ipv == 4 && ip_hdr(skb)->protocol == IPPROTO_UDP) ||
(ipv == 6 && ipv6_hdr(skb)->nexthdr == IPPROTO_UDP))
*flags |= QETH_HDR_EXT_UDP;
- if (ipv == 4) {
- /* some HW requires combined L3+L4 csum offload: */
- *flags |= QETH_HDR_EXT_CSUM_HDR_REQ;
- ip_hdr(skb)->check = 0;
- }
}
static inline void qeth_put_buffer_pool_entry(struct qeth_card *card,
@@ -974,7 +991,7 @@ int qeth_wait_for_threads(struct qeth_card *, unsigned long);
int qeth_do_run_thread(struct qeth_card *, unsigned long);
void qeth_clear_thread_start_bit(struct qeth_card *, unsigned long);
void qeth_clear_thread_running_bit(struct qeth_card *, unsigned long);
-int qeth_core_hardsetup_card(struct qeth_card *);
+int qeth_core_hardsetup_card(struct qeth_card *card, bool *carrier_ok);
void qeth_print_status_message(struct qeth_card *);
int qeth_init_qdio_queues(struct qeth_card *);
int qeth_send_ipa_cmd(struct qeth_card *, struct qeth_cmd_buffer *,
@@ -1007,9 +1024,7 @@ int qeth_query_switch_attributes(struct qeth_card *card,
int qeth_send_control_data(struct qeth_card *, int, struct qeth_cmd_buffer *,
int (*reply_cb)(struct qeth_card *, struct qeth_reply*, unsigned long),
void *reply_param);
-int qeth_get_elements_no(struct qeth_card *card, struct sk_buff *skb,
- int extra_elems, int data_offset);
-int qeth_get_elements_for_frags(struct sk_buff *);
+unsigned int qeth_count_elements(struct sk_buff *skb, unsigned int data_offset);
int qeth_do_send_packet_fast(struct qeth_qdio_out_q *queue, struct sk_buff *skb,
struct qeth_hdr *hdr, unsigned int offset,
unsigned int hd_len);
@@ -1027,16 +1042,10 @@ void qeth_dbf_longtext(debug_info_t *id, int level, char *text, ...);
int qeth_core_ethtool_get_link_ksettings(struct net_device *netdev,
struct ethtool_link_ksettings *cmd);
int qeth_set_access_ctrl_online(struct qeth_card *card, int fallback);
-int qeth_hdr_chk_and_bounce(struct sk_buff *, struct qeth_hdr **, int);
int qeth_configure_cq(struct qeth_card *, enum qeth_cq);
int qeth_hw_trap(struct qeth_card *, enum qeth_diags_trap_action);
void qeth_trace_features(struct qeth_card *);
void qeth_close_dev(struct qeth_card *);
-int qeth_send_setassparms(struct qeth_card *, struct qeth_cmd_buffer *, __u16,
- long,
- int (*reply_cb)(struct qeth_card *,
- struct qeth_reply *, unsigned long),
- void *);
int qeth_setassparms_cb(struct qeth_card *, struct qeth_reply *, unsigned long);
struct qeth_cmd_buffer *qeth_get_setassparms_cmd(struct qeth_card *,
enum qeth_ipa_funcs,
@@ -1052,6 +1061,13 @@ int qeth_vm_request_mac(struct qeth_card *card);
int qeth_add_hw_header(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr **hdr, unsigned int hdr_len,
unsigned int proto_len, unsigned int *elements);
+void qeth_fill_tso_ext(struct qeth_hdr_tso *hdr, unsigned int payload_len,
+ struct sk_buff *skb, unsigned int proto_len);
+int qeth_xmit(struct qeth_card *card, struct sk_buff *skb,
+ struct qeth_qdio_out_q *queue, int ipv, int cast_type,
+ void (*fill_header)(struct qeth_card *card, struct qeth_hdr *hdr,
+ struct sk_buff *skb, int ipv, int cast_type,
+ unsigned int data_len));
/* exports for OSN */
int qeth_osn_assist(struct net_device *, void *, int);
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index de8282420f96..4bce5ae65a55 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -16,6 +16,7 @@
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/kernel.h>
+#include <linux/log2.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/mii.h>
@@ -61,10 +62,10 @@ static struct kmem_cache *qeth_qdio_outbuf_cache;
static struct device *qeth_core_root_dev;
static struct lock_class_key qdio_out_skb_queue_key;
-static struct mutex qeth_mod_mutex;
-static void qeth_send_control_data_cb(struct qeth_channel *,
- struct qeth_cmd_buffer *);
+static void qeth_send_control_data_cb(struct qeth_card *card,
+ struct qeth_channel *channel,
+ struct qeth_cmd_buffer *iob);
static struct qeth_cmd_buffer *qeth_get_buffer(struct qeth_channel *);
static void qeth_free_buffer_pool(struct qeth_card *);
static int qeth_qdio_establish(struct qeth_card *);
@@ -166,6 +167,8 @@ const char *qeth_get_cardname_short(struct qeth_card *card)
return "OSD_1000";
case QETH_LINK_TYPE_10GBIT_ETH:
return "OSD_10GIG";
+ case QETH_LINK_TYPE_25GBIT_ETH:
+ return "OSD_25GIG";
case QETH_LINK_TYPE_LANE_ETH100:
return "OSD_FE_LANE";
case QETH_LINK_TYPE_LANE_TR:
@@ -553,8 +556,8 @@ static int __qeth_issue_next_read(struct qeth_card *card)
if (!iob) {
dev_warn(&card->gdev->dev, "The qeth device driver "
"failed to recover an error on the device\n");
- QETH_DBF_MESSAGE(2, "%s issue_next_read failed: no iob "
- "available\n", dev_name(&card->gdev->dev));
+ QETH_DBF_MESSAGE(2, "issue_next_read on device %x failed: no iob available\n",
+ CARD_DEVID(card));
return -ENOMEM;
}
qeth_setup_ccw(channel->ccw, CCW_CMD_READ, QETH_BUFSIZE, iob->data);
@@ -562,8 +565,8 @@ static int __qeth_issue_next_read(struct qeth_card *card)
rc = ccw_device_start(channel->ccwdev, channel->ccw,
(addr_t) iob, 0, 0);
if (rc) {
- QETH_DBF_MESSAGE(2, "%s error in starting next read ccw! "
- "rc=%i\n", dev_name(&card->gdev->dev), rc);
+ QETH_DBF_MESSAGE(2, "error %i on device %x when starting next read ccw!\n",
+ rc, CARD_DEVID(card));
atomic_set(&channel->irq_pending, 0);
card->read_or_write_problem = 1;
qeth_schedule_recovery(card);
@@ -591,7 +594,6 @@ static struct qeth_reply *qeth_alloc_reply(struct qeth_card *card)
if (reply) {
refcount_set(&reply->refcnt, 1);
atomic_set(&reply->received, 0);
- reply->card = card;
}
return reply;
}
@@ -610,96 +612,75 @@ static void qeth_put_reply(struct qeth_reply *reply)
static void qeth_issue_ipa_msg(struct qeth_ipa_cmd *cmd, int rc,
struct qeth_card *card)
{
- char *ipa_name;
+ const char *ipa_name;
int com = cmd->hdr.command;
ipa_name = qeth_get_ipa_cmd_name(com);
+
if (rc)
- QETH_DBF_MESSAGE(2, "IPA: %s(x%X) for %s/%s returned "
- "x%X \"%s\"\n",
- ipa_name, com, dev_name(&card->gdev->dev),
- QETH_CARD_IFNAME(card), rc,
- qeth_get_ipa_msg(rc));
+ QETH_DBF_MESSAGE(2, "IPA: %s(%#x) for device %x returned %#x \"%s\"\n",
+ ipa_name, com, CARD_DEVID(card), rc,
+ qeth_get_ipa_msg(rc));
else
- QETH_DBF_MESSAGE(5, "IPA: %s(x%X) for %s/%s succeeded\n",
- ipa_name, com, dev_name(&card->gdev->dev),
- QETH_CARD_IFNAME(card));
+ QETH_DBF_MESSAGE(5, "IPA: %s(%#x) for device %x succeeded\n",
+ ipa_name, com, CARD_DEVID(card));
}
static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card,
- struct qeth_cmd_buffer *iob)
+ struct qeth_ipa_cmd *cmd)
{
- struct qeth_ipa_cmd *cmd = NULL;
-
QETH_CARD_TEXT(card, 5, "chkipad");
- if (IS_IPA(iob->data)) {
- cmd = (struct qeth_ipa_cmd *) PDU_ENCAPSULATION(iob->data);
- if (IS_IPA_REPLY(cmd)) {
- if (cmd->hdr.command != IPA_CMD_SETCCID &&
- cmd->hdr.command != IPA_CMD_DELCCID &&
- cmd->hdr.command != IPA_CMD_MODCCID &&
- cmd->hdr.command != IPA_CMD_SET_DIAG_ASS)
- qeth_issue_ipa_msg(cmd,
- cmd->hdr.return_code, card);
- return cmd;
+
+ if (IS_IPA_REPLY(cmd)) {
+ if (cmd->hdr.command != IPA_CMD_SETCCID &&
+ cmd->hdr.command != IPA_CMD_DELCCID &&
+ cmd->hdr.command != IPA_CMD_MODCCID &&
+ cmd->hdr.command != IPA_CMD_SET_DIAG_ASS)
+ qeth_issue_ipa_msg(cmd, cmd->hdr.return_code, card);
+ return cmd;
+ }
+
+ /* handle unsolicited event: */
+ switch (cmd->hdr.command) {
+ case IPA_CMD_STOPLAN:
+ if (cmd->hdr.return_code == IPA_RC_VEPA_TO_VEB_TRANSITION) {
+ dev_err(&card->gdev->dev,
+ "Interface %s is down because the adjacent port is no longer in reflective relay mode\n",
+ QETH_CARD_IFNAME(card));
+ qeth_close_dev(card);
} else {
- switch (cmd->hdr.command) {
- case IPA_CMD_STOPLAN:
- if (cmd->hdr.return_code ==
- IPA_RC_VEPA_TO_VEB_TRANSITION) {
- dev_err(&card->gdev->dev,
- "Interface %s is down because the "
- "adjacent port is no longer in "
- "reflective relay mode\n",
- QETH_CARD_IFNAME(card));
- qeth_close_dev(card);
- } else {
- dev_warn(&card->gdev->dev,
- "The link for interface %s on CHPID"
- " 0x%X failed\n",
- QETH_CARD_IFNAME(card),
- card->info.chpid);
- qeth_issue_ipa_msg(cmd,
- cmd->hdr.return_code, card);
- }
- card->lan_online = 0;
- netif_carrier_off(card->dev);
- return NULL;
- case IPA_CMD_STARTLAN:
- dev_info(&card->gdev->dev,
- "The link for %s on CHPID 0x%X has"
- " been restored\n",
- QETH_CARD_IFNAME(card),
- card->info.chpid);
- netif_carrier_on(card->dev);
- card->lan_online = 1;
- if (card->info.hwtrap)
- card->info.hwtrap = 2;
- qeth_schedule_recovery(card);
- return NULL;
- case IPA_CMD_SETBRIDGEPORT_IQD:
- case IPA_CMD_SETBRIDGEPORT_OSA:
- case IPA_CMD_ADDRESS_CHANGE_NOTIF:
- if (card->discipline->control_event_handler
- (card, cmd))
- return cmd;
- else
- return NULL;
- case IPA_CMD_MODCCID:
- return cmd;
- case IPA_CMD_REGISTER_LOCAL_ADDR:
- QETH_CARD_TEXT(card, 3, "irla");
- break;
- case IPA_CMD_UNREGISTER_LOCAL_ADDR:
- QETH_CARD_TEXT(card, 3, "urla");
- break;
- default:
- QETH_DBF_MESSAGE(2, "Received data is IPA "
- "but not a reply!\n");
- break;
- }
+ dev_warn(&card->gdev->dev,
+ "The link for interface %s on CHPID 0x%X failed\n",
+ QETH_CARD_IFNAME(card), card->info.chpid);
+ qeth_issue_ipa_msg(cmd, cmd->hdr.return_code, card);
+ netif_carrier_off(card->dev);
}
+ return NULL;
+ case IPA_CMD_STARTLAN:
+ dev_info(&card->gdev->dev,
+ "The link for %s on CHPID 0x%X has been restored\n",
+ QETH_CARD_IFNAME(card), card->info.chpid);
+ if (card->info.hwtrap)
+ card->info.hwtrap = 2;
+ qeth_schedule_recovery(card);
+ return NULL;
+ case IPA_CMD_SETBRIDGEPORT_IQD:
+ case IPA_CMD_SETBRIDGEPORT_OSA:
+ case IPA_CMD_ADDRESS_CHANGE_NOTIF:
+ if (card->discipline->control_event_handler(card, cmd))
+ return cmd;
+ return NULL;
+ case IPA_CMD_MODCCID:
+ return cmd;
+ case IPA_CMD_REGISTER_LOCAL_ADDR:
+ QETH_CARD_TEXT(card, 3, "irla");
+ return NULL;
+ case IPA_CMD_UNREGISTER_LOCAL_ADDR:
+ QETH_CARD_TEXT(card, 3, "urla");
+ return NULL;
+ default:
+ QETH_DBF_MESSAGE(2, "Received data is IPA but not a reply!\n");
+ return cmd;
}
- return cmd;
}
void qeth_clear_ipacmd_list(struct qeth_card *card)
@@ -730,7 +711,7 @@ static int qeth_check_idx_response(struct qeth_card *card,
QETH_DBF_HEX(CTRL, 2, buffer, QETH_DBF_CTRL_LEN);
if ((buffer[2] & 0xc0) == 0xc0) {
- QETH_DBF_MESSAGE(2, "received an IDX TERMINATE with cause code %#02x\n",
+ QETH_DBF_MESSAGE(2, "received an IDX TERMINATE with cause code %#04x\n",
buffer[4]);
QETH_CARD_TEXT(card, 2, "ckidxres");
QETH_CARD_TEXT(card, 2, " idxterm");
@@ -746,18 +727,10 @@ static int qeth_check_idx_response(struct qeth_card *card,
return 0;
}
-static struct qeth_card *CARD_FROM_CDEV(struct ccw_device *cdev)
-{
- struct qeth_card *card = dev_get_drvdata(&((struct ccwgroup_device *)
- dev_get_drvdata(&cdev->dev))->dev);
- return card;
-}
-
static struct qeth_cmd_buffer *__qeth_get_buffer(struct qeth_channel *channel)
{
__u8 index;
- QETH_CARD_TEXT(CARD_FROM_CDEV(channel->ccwdev), 6, "getbuff");
index = channel->io_buf_no;
do {
if (channel->iob[index].state == BUF_STATE_FREE) {
@@ -778,9 +751,7 @@ void qeth_release_buffer(struct qeth_channel *channel,
{
unsigned long flags;
- QETH_CARD_TEXT(CARD_FROM_CDEV(channel->ccwdev), 6, "relbuff");
spin_lock_irqsave(&channel->iob_lock, flags);
- memset(iob->data, 0, QETH_BUFSIZE);
iob->state = BUF_STATE_FREE;
iob->callback = qeth_send_control_data_cb;
iob->rc = 0;
@@ -789,6 +760,13 @@ void qeth_release_buffer(struct qeth_channel *channel,
}
EXPORT_SYMBOL_GPL(qeth_release_buffer);
+static void qeth_release_buffer_cb(struct qeth_card *card,
+ struct qeth_channel *channel,
+ struct qeth_cmd_buffer *iob)
+{
+ qeth_release_buffer(channel, iob);
+}
+
static struct qeth_cmd_buffer *qeth_get_buffer(struct qeth_channel *channel)
{
struct qeth_cmd_buffer *buffer = NULL;
@@ -819,17 +797,16 @@ void qeth_clear_cmd_buffers(struct qeth_channel *channel)
}
EXPORT_SYMBOL_GPL(qeth_clear_cmd_buffers);
-static void qeth_send_control_data_cb(struct qeth_channel *channel,
- struct qeth_cmd_buffer *iob)
+static void qeth_send_control_data_cb(struct qeth_card *card,
+ struct qeth_channel *channel,
+ struct qeth_cmd_buffer *iob)
{
- struct qeth_card *card;
+ struct qeth_ipa_cmd *cmd = NULL;
struct qeth_reply *reply, *r;
- struct qeth_ipa_cmd *cmd;
unsigned long flags;
int keep_reply;
int rc = 0;
- card = CARD_FROM_CDEV(channel->ccwdev);
QETH_CARD_TEXT(card, 4, "sndctlcb");
rc = qeth_check_idx_response(card, iob->data);
switch (rc) {
@@ -843,16 +820,20 @@ static void qeth_send_control_data_cb(struct qeth_channel *channel,
goto out;
}
- cmd = qeth_check_ipa_data(card, iob);
- if ((cmd == NULL) && (card->state != CARD_STATE_DOWN))
- goto out;
- /*in case of OSN : check if cmd is set */
- if (card->info.type == QETH_CARD_TYPE_OSN &&
- cmd &&
- cmd->hdr.command != IPA_CMD_STARTLAN &&
- card->osn_info.assist_cb != NULL) {
- card->osn_info.assist_cb(card->dev, cmd);
- goto out;
+ if (IS_IPA(iob->data)) {
+ cmd = (struct qeth_ipa_cmd *) PDU_ENCAPSULATION(iob->data);
+ cmd = qeth_check_ipa_data(card, cmd);
+ if (!cmd)
+ goto out;
+ if (IS_OSN(card) && card->osn_info.assist_cb &&
+ cmd->hdr.command != IPA_CMD_STARTLAN) {
+ card->osn_info.assist_cb(card->dev, cmd);
+ goto out;
+ }
+ } else {
+ /* non-IPA commands should only flow during initialization */
+ if (card->state != CARD_STATE_DOWN)
+ goto out;
}
spin_lock_irqsave(&card->lock, flags);
@@ -900,44 +881,6 @@ out:
qeth_release_buffer(channel, iob);
}
-static int qeth_setup_channel(struct qeth_channel *channel, bool alloc_buffers)
-{
- int cnt;
-
- QETH_DBF_TEXT(SETUP, 2, "setupch");
-
- channel->ccw = kmalloc(sizeof(struct ccw1), GFP_KERNEL | GFP_DMA);
- if (!channel->ccw)
- return -ENOMEM;
- channel->state = CH_STATE_DOWN;
- atomic_set(&channel->irq_pending, 0);
- init_waitqueue_head(&channel->wait_q);
-
- if (!alloc_buffers)
- return 0;
-
- for (cnt = 0; cnt < QETH_CMD_BUFFER_NO; cnt++) {
- channel->iob[cnt].data =
- kzalloc(QETH_BUFSIZE, GFP_DMA|GFP_KERNEL);
- if (channel->iob[cnt].data == NULL)
- break;
- channel->iob[cnt].state = BUF_STATE_FREE;
- channel->iob[cnt].channel = channel;
- channel->iob[cnt].callback = qeth_send_control_data_cb;
- channel->iob[cnt].rc = 0;
- }
- if (cnt < QETH_CMD_BUFFER_NO) {
- kfree(channel->ccw);
- while (cnt-- > 0)
- kfree(channel->iob[cnt].data);
- return -ENOMEM;
- }
- channel->io_buf_no = 0;
- spin_lock_init(&channel->iob_lock);
-
- return 0;
-}
-
static int qeth_set_thread_start_bit(struct qeth_card *card,
unsigned long thread)
{
@@ -1013,16 +956,15 @@ void qeth_schedule_recovery(struct qeth_card *card)
}
EXPORT_SYMBOL_GPL(qeth_schedule_recovery);
-static int qeth_get_problem(struct ccw_device *cdev, struct irb *irb)
+static int qeth_get_problem(struct qeth_card *card, struct ccw_device *cdev,
+ struct irb *irb)
{
int dstat, cstat;
char *sense;
- struct qeth_card *card;
sense = (char *) irb->ecw;
cstat = irb->scsw.cmd.cstat;
dstat = irb->scsw.cmd.dstat;
- card = CARD_FROM_CDEV(cdev);
if (cstat & (SCHN_STAT_CHN_CTRL_CHK | SCHN_STAT_INTF_CTRL_CHK |
SCHN_STAT_CHN_DATA_CHK | SCHN_STAT_CHAIN_CHECK |
@@ -1030,8 +972,8 @@ static int qeth_get_problem(struct ccw_device *cdev, struct irb *irb)
QETH_CARD_TEXT(card, 2, "CGENCHK");
dev_warn(&cdev->dev, "The qeth device driver "
"failed to recover an error on the device\n");
- QETH_DBF_MESSAGE(2, "%s check on device dstat=x%x, cstat=x%x\n",
- dev_name(&cdev->dev), dstat, cstat);
+ QETH_DBF_MESSAGE(2, "check on channel %x with dstat=%#x, cstat=%#x\n",
+ CCW_DEVID(cdev), dstat, cstat);
print_hex_dump(KERN_WARNING, "qeth: irb ", DUMP_PREFIX_OFFSET,
16, 1, irb, 64, 1);
return 1;
@@ -1062,20 +1004,17 @@ static int qeth_get_problem(struct ccw_device *cdev, struct irb *irb)
return 0;
}
-static long __qeth_check_irb_error(struct ccw_device *cdev,
- unsigned long intparm, struct irb *irb)
+static long qeth_check_irb_error(struct qeth_card *card,
+ struct ccw_device *cdev, unsigned long intparm,
+ struct irb *irb)
{
- struct qeth_card *card;
-
- card = CARD_FROM_CDEV(cdev);
-
- if (!card || !IS_ERR(irb))
+ if (!IS_ERR(irb))
return 0;
switch (PTR_ERR(irb)) {
case -EIO:
- QETH_DBF_MESSAGE(2, "%s i/o-error on device\n",
- dev_name(&cdev->dev));
+ QETH_DBF_MESSAGE(2, "i/o-error on channel %x\n",
+ CCW_DEVID(cdev));
QETH_CARD_TEXT(card, 2, "ckirberr");
QETH_CARD_TEXT_(card, 2, " rc%d", -EIO);
break;
@@ -1092,8 +1031,8 @@ static long __qeth_check_irb_error(struct ccw_device *cdev,
}
break;
default:
- QETH_DBF_MESSAGE(2, "%s unknown error %ld on device\n",
- dev_name(&cdev->dev), PTR_ERR(irb));
+ QETH_DBF_MESSAGE(2, "unknown error %ld on channel %x\n",
+ PTR_ERR(irb), CCW_DEVID(cdev));
QETH_CARD_TEXT(card, 2, "ckirberr");
QETH_CARD_TEXT(card, 2, " rc???");
}
@@ -1106,10 +1045,13 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
int rc;
int cstat, dstat;
struct qeth_cmd_buffer *iob = NULL;
+ struct ccwgroup_device *gdev;
struct qeth_channel *channel;
struct qeth_card *card;
- card = CARD_FROM_CDEV(cdev);
+ /* while we hold the ccwdev lock, this stays valid: */
+ gdev = dev_get_drvdata(&cdev->dev);
+ card = dev_get_drvdata(&gdev->dev);
if (!card)
return;
@@ -1129,7 +1071,7 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
if (qeth_intparm_is_iob(intparm))
iob = (struct qeth_cmd_buffer *) __va((addr_t)intparm);
- if (__qeth_check_irb_error(cdev, intparm, irb)) {
+ if (qeth_check_irb_error(card, cdev, intparm, irb)) {
/* IO was terminated, free its resources. */
if (iob)
qeth_release_buffer(iob->channel, iob);
@@ -1172,9 +1114,9 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
dev_warn(&channel->ccwdev->dev,
"The qeth device driver failed to recover "
"an error on the device\n");
- QETH_DBF_MESSAGE(2, "%s sense data available. cstat "
- "0x%X dstat 0x%X\n",
- dev_name(&channel->ccwdev->dev), cstat, dstat);
+ QETH_DBF_MESSAGE(2, "sense data available on channel %x: cstat %#X dstat %#X\n",
+ CCW_DEVID(channel->ccwdev), cstat,
+ dstat);
print_hex_dump(KERN_WARNING, "qeth: irb ",
DUMP_PREFIX_OFFSET, 16, 1, irb, 32, 1);
print_hex_dump(KERN_WARNING, "qeth: sense data ",
@@ -1184,7 +1126,7 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
channel->state = CH_STATE_DOWN;
goto out;
}
- rc = qeth_get_problem(cdev, irb);
+ rc = qeth_get_problem(card, cdev, irb);
if (rc) {
card->read_or_write_problem = 1;
qeth_clear_ipacmd_list(card);
@@ -1204,7 +1146,7 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
__qeth_issue_next_read(card);
if (iob && iob->callback)
- iob->callback(iob->channel, iob);
+ iob->callback(card, iob->channel, iob);
out:
wake_up(&card->wait_q);
@@ -1217,54 +1159,23 @@ static void qeth_notify_skbs(struct qeth_qdio_out_q *q,
{
struct sk_buff *skb;
- if (skb_queue_empty(&buf->skb_list))
- goto out;
- skb = skb_peek(&buf->skb_list);
- while (skb) {
+ skb_queue_walk(&buf->skb_list, skb) {
QETH_CARD_TEXT_(q->card, 5, "skbn%d", notification);
QETH_CARD_TEXT_(q->card, 5, "%lx", (long) skb);
- if (be16_to_cpu(skb->protocol) == ETH_P_AF_IUCV) {
- if (skb->sk) {
- struct iucv_sock *iucv = iucv_sk(skb->sk);
- iucv->sk_txnotify(skb, notification);
- }
- }
- if (skb_queue_is_last(&buf->skb_list, skb))
- skb = NULL;
- else
- skb = skb_queue_next(&buf->skb_list, skb);
+ if (skb->protocol == htons(ETH_P_AF_IUCV) && skb->sk)
+ iucv_sk(skb->sk)->sk_txnotify(skb, notification);
}
-out:
- return;
}
static void qeth_release_skbs(struct qeth_qdio_out_buffer *buf)
{
- struct sk_buff *skb;
- struct iucv_sock *iucv;
- int notify_general_error = 0;
-
- if (atomic_read(&buf->state) == QETH_QDIO_BUF_PENDING)
- notify_general_error = 1;
-
/* release may never happen from within CQ tasklet scope */
WARN_ON_ONCE(atomic_read(&buf->state) == QETH_QDIO_BUF_IN_CQ);
- skb = skb_dequeue(&buf->skb_list);
- while (skb) {
- QETH_CARD_TEXT(buf->q->card, 5, "skbr");
- QETH_CARD_TEXT_(buf->q->card, 5, "%lx", (long) skb);
- if (notify_general_error &&
- be16_to_cpu(skb->protocol) == ETH_P_AF_IUCV) {
- if (skb->sk) {
- iucv = iucv_sk(skb->sk);
- iucv->sk_txnotify(skb, TX_NOTIFY_GENERALERROR);
- }
- }
- refcount_dec(&skb->users);
- dev_kfree_skb_any(skb);
- skb = skb_dequeue(&buf->skb_list);
- }
+ if (atomic_read(&buf->state) == QETH_QDIO_BUF_PENDING)
+ qeth_notify_skbs(buf->q, buf, TX_NOTIFY_GENERALERROR);
+
+ __skb_queue_purge(&buf->skb_list);
}
static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
@@ -1336,14 +1247,61 @@ static void qeth_free_buffer_pool(struct qeth_card *card)
static void qeth_clean_channel(struct qeth_channel *channel)
{
+ struct ccw_device *cdev = channel->ccwdev;
int cnt;
QETH_DBF_TEXT(SETUP, 2, "freech");
+
+ spin_lock_irq(get_ccwdev_lock(cdev));
+ cdev->handler = NULL;
+ spin_unlock_irq(get_ccwdev_lock(cdev));
+
for (cnt = 0; cnt < QETH_CMD_BUFFER_NO; cnt++)
kfree(channel->iob[cnt].data);
kfree(channel->ccw);
}
+static int qeth_setup_channel(struct qeth_channel *channel, bool alloc_buffers)
+{
+ struct ccw_device *cdev = channel->ccwdev;
+ int cnt;
+
+ QETH_DBF_TEXT(SETUP, 2, "setupch");
+
+ channel->ccw = kmalloc(sizeof(struct ccw1), GFP_KERNEL | GFP_DMA);
+ if (!channel->ccw)
+ return -ENOMEM;
+ channel->state = CH_STATE_DOWN;
+ atomic_set(&channel->irq_pending, 0);
+ init_waitqueue_head(&channel->wait_q);
+
+ spin_lock_irq(get_ccwdev_lock(cdev));
+ cdev->handler = qeth_irq;
+ spin_unlock_irq(get_ccwdev_lock(cdev));
+
+ if (!alloc_buffers)
+ return 0;
+
+ for (cnt = 0; cnt < QETH_CMD_BUFFER_NO; cnt++) {
+ channel->iob[cnt].data = kmalloc(QETH_BUFSIZE,
+ GFP_KERNEL | GFP_DMA);
+ if (channel->iob[cnt].data == NULL)
+ break;
+ channel->iob[cnt].state = BUF_STATE_FREE;
+ channel->iob[cnt].channel = channel;
+ channel->iob[cnt].callback = qeth_send_control_data_cb;
+ channel->iob[cnt].rc = 0;
+ }
+ if (cnt < QETH_CMD_BUFFER_NO) {
+ qeth_clean_channel(channel);
+ return -ENOMEM;
+ }
+ channel->io_buf_no = 0;
+ spin_lock_init(&channel->iob_lock);
+
+ return 0;
+}
+
static void qeth_set_single_write_queues(struct qeth_card *card)
{
if ((atomic_read(&card->qdio.state) != QETH_QDIO_UNINITIALIZED) &&
@@ -1421,6 +1379,7 @@ static void qeth_set_initial_options(struct qeth_card *card)
card->options.rx_sg_cb = QETH_RX_SG_CB;
card->options.isolation = ISOLATION_MODE_NONE;
card->options.cq = QETH_CQ_DISABLED;
+ card->options.layer = QETH_DISCIPLINE_UNDETERMINED;
}
static int qeth_do_start_thread(struct qeth_card *card, unsigned long thread)
@@ -1494,7 +1453,7 @@ static void qeth_core_sl_print(struct seq_file *m, struct service_level *slr)
CARD_BUS_ID(card), card->info.mcl_level);
}
-static struct qeth_card *qeth_alloc_card(void)
+static struct qeth_card *qeth_alloc_card(struct ccwgroup_device *gdev)
{
struct qeth_card *card;
@@ -1503,13 +1462,18 @@ static struct qeth_card *qeth_alloc_card(void)
if (!card)
goto out;
QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
+
+ card->gdev = gdev;
+ dev_set_drvdata(&gdev->dev, card);
+ CARD_RDEV(card) = gdev->cdev[0];
+ CARD_WDEV(card) = gdev->cdev[1];
+ CARD_DDEV(card) = gdev->cdev[2];
if (qeth_setup_channel(&card->read, true))
goto out_ip;
if (qeth_setup_channel(&card->write, true))
goto out_channel;
if (qeth_setup_channel(&card->data, false))
goto out_data;
- card->options.layer2 = -1;
card->qeth_service_level.seq_print = qeth_core_sl_print;
register_service_level(&card->qeth_service_level);
return card;
@@ -1519,22 +1483,21 @@ out_data:
out_channel:
qeth_clean_channel(&card->read);
out_ip:
+ dev_set_drvdata(&gdev->dev, NULL);
kfree(card);
out:
return NULL;
}
-static int qeth_clear_channel(struct qeth_channel *channel)
+static int qeth_clear_channel(struct qeth_card *card,
+ struct qeth_channel *channel)
{
- unsigned long flags;
- struct qeth_card *card;
int rc;
- card = CARD_FROM_CDEV(channel->ccwdev);
QETH_CARD_TEXT(card, 3, "clearch");
- spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
+ spin_lock_irq(get_ccwdev_lock(channel->ccwdev));
rc = ccw_device_clear(channel->ccwdev, QETH_CLEAR_CHANNEL_PARM);
- spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
+ spin_unlock_irq(get_ccwdev_lock(channel->ccwdev));
if (rc)
return rc;
@@ -1548,17 +1511,15 @@ static int qeth_clear_channel(struct qeth_channel *channel)
return 0;
}
-static int qeth_halt_channel(struct qeth_channel *channel)
+static int qeth_halt_channel(struct qeth_card *card,
+ struct qeth_channel *channel)
{
- unsigned long flags;
- struct qeth_card *card;
int rc;
- card = CARD_FROM_CDEV(channel->ccwdev);
QETH_CARD_TEXT(card, 3, "haltch");
- spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
+ spin_lock_irq(get_ccwdev_lock(channel->ccwdev));
rc = ccw_device_halt(channel->ccwdev, QETH_HALT_CHANNEL_PARM);
- spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
+ spin_unlock_irq(get_ccwdev_lock(channel->ccwdev));
if (rc)
return rc;
@@ -1576,9 +1537,9 @@ static int qeth_halt_channels(struct qeth_card *card)
int rc1 = 0, rc2 = 0, rc3 = 0;
QETH_CARD_TEXT(card, 3, "haltchs");
- rc1 = qeth_halt_channel(&card->read);
- rc2 = qeth_halt_channel(&card->write);
- rc3 = qeth_halt_channel(&card->data);
+ rc1 = qeth_halt_channel(card, &card->read);
+ rc2 = qeth_halt_channel(card, &card->write);
+ rc3 = qeth_halt_channel(card, &card->data);
if (rc1)
return rc1;
if (rc2)
@@ -1591,9 +1552,9 @@ static int qeth_clear_channels(struct qeth_card *card)
int rc1 = 0, rc2 = 0, rc3 = 0;
QETH_CARD_TEXT(card, 3, "clearchs");
- rc1 = qeth_clear_channel(&card->read);
- rc2 = qeth_clear_channel(&card->write);
- rc3 = qeth_clear_channel(&card->data);
+ rc1 = qeth_clear_channel(card, &card->read);
+ rc2 = qeth_clear_channel(card, &card->write);
+ rc3 = qeth_clear_channel(card, &card->data);
if (rc1)
return rc1;
if (rc2)
@@ -1652,7 +1613,6 @@ static int qeth_read_conf_data(struct qeth_card *card, void **buffer,
char *rcd_buf;
int ret;
struct qeth_channel *channel = &card->data;
- unsigned long flags;
/*
* scan for RCD command in extended SenseID data
@@ -1666,11 +1626,11 @@ static int qeth_read_conf_data(struct qeth_card *card, void **buffer,
qeth_setup_ccw(channel->ccw, ciw->cmd, ciw->count, rcd_buf);
channel->state = CH_STATE_RCD;
- spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
+ spin_lock_irq(get_ccwdev_lock(channel->ccwdev));
ret = ccw_device_start_timeout(channel->ccwdev, channel->ccw,
QETH_RCD_PARM, LPM_ANYPATH, 0,
QETH_RCD_TIMEOUT);
- spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
+ spin_unlock_irq(get_ccwdev_lock(channel->ccwdev));
if (!ret)
wait_event(card->wait_q,
(channel->state == CH_STATE_RCD_DONE ||
@@ -1823,30 +1783,29 @@ static void qeth_init_func_level(struct qeth_card *card)
}
}
-static int qeth_idx_activate_get_answer(struct qeth_channel *channel,
- void (*idx_reply_cb)(struct qeth_channel *,
- struct qeth_cmd_buffer *))
+static int qeth_idx_activate_get_answer(struct qeth_card *card,
+ struct qeth_channel *channel,
+ void (*reply_cb)(struct qeth_card *,
+ struct qeth_channel *,
+ struct qeth_cmd_buffer *))
{
struct qeth_cmd_buffer *iob;
- unsigned long flags;
int rc;
- struct qeth_card *card;
QETH_DBF_TEXT(SETUP, 2, "idxanswr");
- card = CARD_FROM_CDEV(channel->ccwdev);
iob = qeth_get_buffer(channel);
if (!iob)
return -ENOMEM;
- iob->callback = idx_reply_cb;
+ iob->callback = reply_cb;
qeth_setup_ccw(channel->ccw, CCW_CMD_READ, QETH_BUFSIZE, iob->data);
wait_event(card->wait_q,
atomic_cmpxchg(&channel->irq_pending, 0, 1) == 0);
QETH_DBF_TEXT(SETUP, 6, "noirqpnd");
- spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
+ spin_lock_irq(get_ccwdev_lock(channel->ccwdev));
rc = ccw_device_start_timeout(channel->ccwdev, channel->ccw,
(addr_t) iob, 0, 0, QETH_TIMEOUT);
- spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
+ spin_unlock_irq(get_ccwdev_lock(channel->ccwdev));
if (rc) {
QETH_DBF_MESSAGE(2, "Error2 in activating channel rc=%d\n", rc);
@@ -1867,26 +1826,24 @@ static int qeth_idx_activate_get_answer(struct qeth_channel *channel,
return rc;
}
-static int qeth_idx_activate_channel(struct qeth_channel *channel,
- void (*idx_reply_cb)(struct qeth_channel *,
- struct qeth_cmd_buffer *))
+static int qeth_idx_activate_channel(struct qeth_card *card,
+ struct qeth_channel *channel,
+ void (*reply_cb)(struct qeth_card *,
+ struct qeth_channel *,
+ struct qeth_cmd_buffer *))
{
- struct qeth_card *card;
struct qeth_cmd_buffer *iob;
- unsigned long flags;
__u16 temp;
__u8 tmp;
int rc;
struct ccw_dev_id temp_devid;
- card = CARD_FROM_CDEV(channel->ccwdev);
-
QETH_DBF_TEXT(SETUP, 2, "idxactch");
iob = qeth_get_buffer(channel);
if (!iob)
return -ENOMEM;
- iob->callback = idx_reply_cb;
+ iob->callback = reply_cb;
qeth_setup_ccw(channel->ccw, CCW_CMD_WRITE, IDX_ACTIVATE_SIZE,
iob->data);
if (channel == &card->write) {
@@ -1913,10 +1870,10 @@ static int qeth_idx_activate_channel(struct qeth_channel *channel,
wait_event(card->wait_q,
atomic_cmpxchg(&channel->irq_pending, 0, 1) == 0);
QETH_DBF_TEXT(SETUP, 6, "noirqpnd");
- spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
+ spin_lock_irq(get_ccwdev_lock(channel->ccwdev));
rc = ccw_device_start_timeout(channel->ccwdev, channel->ccw,
(addr_t) iob, 0, 0, QETH_TIMEOUT);
- spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
+ spin_unlock_irq(get_ccwdev_lock(channel->ccwdev));
if (rc) {
QETH_DBF_MESSAGE(2, "Error1 in activating channel. rc=%d\n",
@@ -1933,12 +1890,12 @@ static int qeth_idx_activate_channel(struct qeth_channel *channel,
if (channel->state != CH_STATE_ACTIVATING) {
dev_warn(&channel->ccwdev->dev, "The qeth device driver"
" failed to recover an error on the device\n");
- QETH_DBF_MESSAGE(2, "%s IDX activate timed out\n",
- dev_name(&channel->ccwdev->dev));
+ QETH_DBF_MESSAGE(2, "IDX activate timed out on channel %x\n",
+ CCW_DEVID(channel->ccwdev));
QETH_DBF_TEXT_(SETUP, 2, "2err%d", -ETIME);
return -ETIME;
}
- return qeth_idx_activate_get_answer(channel, idx_reply_cb);
+ return qeth_idx_activate_get_answer(card, channel, reply_cb);
}
static int qeth_peer_func_level(int level)
@@ -1950,10 +1907,10 @@ static int qeth_peer_func_level(int level)
return level;
}
-static void qeth_idx_write_cb(struct qeth_channel *channel,
- struct qeth_cmd_buffer *iob)
+static void qeth_idx_write_cb(struct qeth_card *card,
+ struct qeth_channel *channel,
+ struct qeth_cmd_buffer *iob)
{
- struct qeth_card *card;
__u16 temp;
QETH_DBF_TEXT(SETUP , 2, "idxwrcb");
@@ -1962,7 +1919,6 @@ static void qeth_idx_write_cb(struct qeth_channel *channel,
channel->state = CH_STATE_ACTIVATING;
goto out;
}
- card = CARD_FROM_CDEV(channel->ccwdev);
if (!(QETH_IS_IDX_ACT_POS_REPLY(iob->data))) {
if (QETH_IDX_ACT_CAUSE_CODE(iob->data) == QETH_IDX_ACT_ERR_EXCL)
@@ -1970,17 +1926,15 @@ static void qeth_idx_write_cb(struct qeth_channel *channel,
"The adapter is used exclusively by another "
"host\n");
else
- QETH_DBF_MESSAGE(2, "%s IDX_ACTIVATE on write channel:"
- " negative reply\n",
- dev_name(&channel->ccwdev->dev));
+ QETH_DBF_MESSAGE(2, "IDX_ACTIVATE on channel %x: negative reply\n",
+ CCW_DEVID(channel->ccwdev));
goto out;
}
memcpy(&temp, QETH_IDX_ACT_FUNC_LEVEL(iob->data), 2);
if ((temp & ~0x0100) != qeth_peer_func_level(card->info.func_level)) {
- QETH_DBF_MESSAGE(2, "%s IDX_ACTIVATE on write channel: "
- "function level mismatch (sent: 0x%x, received: "
- "0x%x)\n", dev_name(&channel->ccwdev->dev),
- card->info.func_level, temp);
+ QETH_DBF_MESSAGE(2, "IDX_ACTIVATE on channel %x: function level mismatch (sent: %#x, received: %#x)\n",
+ CCW_DEVID(channel->ccwdev),
+ card->info.func_level, temp);
goto out;
}
channel->state = CH_STATE_UP;
@@ -1988,10 +1942,10 @@ out:
qeth_release_buffer(channel, iob);
}
-static void qeth_idx_read_cb(struct qeth_channel *channel,
- struct qeth_cmd_buffer *iob)
+static void qeth_idx_read_cb(struct qeth_card *card,
+ struct qeth_channel *channel,
+ struct qeth_cmd_buffer *iob)
{
- struct qeth_card *card;
__u16 temp;
QETH_DBF_TEXT(SETUP , 2, "idxrdcb");
@@ -2000,7 +1954,6 @@ static void qeth_idx_read_cb(struct qeth_channel *channel,
goto out;
}
- card = CARD_FROM_CDEV(channel->ccwdev);
if (qeth_check_idx_response(card, iob->data))
goto out;
@@ -2018,9 +1971,8 @@ static void qeth_idx_read_cb(struct qeth_channel *channel,
"insufficient authorization\n");
break;
default:
- QETH_DBF_MESSAGE(2, "%s IDX_ACTIVATE on read channel:"
- " negative reply\n",
- dev_name(&channel->ccwdev->dev));
+ QETH_DBF_MESSAGE(2, "IDX_ACTIVATE on channel %x: negative reply\n",
+ CCW_DEVID(channel->ccwdev));
}
QETH_CARD_TEXT_(card, 2, "idxread%c",
QETH_IDX_ACT_CAUSE_CODE(iob->data));
@@ -2029,10 +1981,9 @@ static void qeth_idx_read_cb(struct qeth_channel *channel,
memcpy(&temp, QETH_IDX_ACT_FUNC_LEVEL(iob->data), 2);
if (temp != qeth_peer_func_level(card->info.func_level)) {
- QETH_DBF_MESSAGE(2, "%s IDX_ACTIVATE on read channel: function "
- "level mismatch (sent: 0x%x, received: 0x%x)\n",
- dev_name(&channel->ccwdev->dev),
- card->info.func_level, temp);
+ QETH_DBF_MESSAGE(2, "IDX_ACTIVATE on channel %x: function level mismatch (sent: %#x, received: %#x)\n",
+ CCW_DEVID(channel->ccwdev),
+ card->info.func_level, temp);
goto out;
}
memcpy(&card->token.issuer_rm_r,
@@ -2049,7 +2000,7 @@ void qeth_prepare_control_data(struct qeth_card *card, int len,
struct qeth_cmd_buffer *iob)
{
qeth_setup_ccw(iob->channel->ccw, CCW_CMD_WRITE, len, iob->data);
- iob->callback = qeth_release_buffer;
+ iob->callback = qeth_release_buffer_cb;
memcpy(QETH_TRANSPORT_HEADER_SEQ_NO(iob->data),
&card->seqno.trans_hdr, QETH_SEQ_NO_LENGTH);
@@ -2097,7 +2048,6 @@ int qeth_send_control_data(struct qeth_card *card, int len,
{
struct qeth_channel *channel = iob->channel;
int rc;
- unsigned long flags;
struct qeth_reply *reply = NULL;
unsigned long timeout, event_timeout;
struct qeth_ipa_cmd *cmd = NULL;
@@ -2130,26 +2080,25 @@ int qeth_send_control_data(struct qeth_card *card, int len,
}
qeth_prepare_control_data(card, len, iob);
- spin_lock_irqsave(&card->lock, flags);
+ spin_lock_irq(&card->lock);
list_add_tail(&reply->list, &card->cmd_waiter_list);
- spin_unlock_irqrestore(&card->lock, flags);
+ spin_unlock_irq(&card->lock);
timeout = jiffies + event_timeout;
QETH_CARD_TEXT(card, 6, "noirqpnd");
- spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
+ spin_lock_irq(get_ccwdev_lock(channel->ccwdev));
rc = ccw_device_start_timeout(channel->ccwdev, channel->ccw,
(addr_t) iob, 0, 0, event_timeout);
- spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
+ spin_unlock_irq(get_ccwdev_lock(channel->ccwdev));
if (rc) {
- QETH_DBF_MESSAGE(2, "%s qeth_send_control_data: "
- "ccw_device_start rc = %i\n",
- dev_name(&channel->ccwdev->dev), rc);
+ QETH_DBF_MESSAGE(2, "qeth_send_control_data on device %x: ccw_device_start rc = %i\n",
+ CARD_DEVID(card), rc);
QETH_CARD_TEXT_(card, 2, " err%d", rc);
- spin_lock_irqsave(&card->lock, flags);
+ spin_lock_irq(&card->lock);
list_del_init(&reply->list);
qeth_put_reply(reply);
- spin_unlock_irqrestore(&card->lock, flags);
+ spin_unlock_irq(&card->lock);
qeth_release_buffer(channel, iob);
atomic_set(&channel->irq_pending, 0);
wake_up(&card->wait_q);
@@ -2177,9 +2126,9 @@ int qeth_send_control_data(struct qeth_card *card, int len,
time_err:
reply->rc = -ETIME;
- spin_lock_irqsave(&reply->card->lock, flags);
+ spin_lock_irq(&card->lock);
list_del_init(&reply->list);
- spin_unlock_irqrestore(&reply->card->lock, flags);
+ spin_unlock_irq(&card->lock);
atomic_inc(&reply->received);
rc = reply->rc;
qeth_put_reply(reply);
@@ -2198,7 +2147,6 @@ static int qeth_cm_enable_cb(struct qeth_card *card, struct qeth_reply *reply,
memcpy(&card->token.cm_filter_r,
QETH_CM_ENABLE_RESP_FILTER_TOKEN(iob->data),
QETH_MPC_TOKEN_LENGTH);
- QETH_DBF_TEXT_(SETUP, 2, " rc%d", iob->rc);
return 0;
}
@@ -2224,7 +2172,6 @@ static int qeth_cm_enable(struct qeth_card *card)
static int qeth_cm_setup_cb(struct qeth_card *card, struct qeth_reply *reply,
unsigned long data)
{
-
struct qeth_cmd_buffer *iob;
QETH_DBF_TEXT(SETUP, 2, "cmsetpcb");
@@ -2233,7 +2180,6 @@ static int qeth_cm_setup_cb(struct qeth_card *card, struct qeth_reply *reply,
memcpy(&card->token.cm_connection_r,
QETH_CM_SETUP_RESP_DEST_ADDR(iob->data),
QETH_MPC_TOKEN_LENGTH);
- QETH_DBF_TEXT_(SETUP, 2, " rc%d", iob->rc);
return 0;
}
@@ -2255,7 +2201,6 @@ static int qeth_cm_setup(struct qeth_card *card)
rc = qeth_send_control_data(card, CM_SETUP_SIZE, iob,
qeth_cm_setup_cb, NULL);
return rc;
-
}
static int qeth_update_max_mtu(struct qeth_card *card, unsigned int max_mtu)
@@ -2284,7 +2229,7 @@ static int qeth_update_max_mtu(struct qeth_card *card, unsigned int max_mtu)
if (dev->mtu)
new_mtu = dev->mtu;
/* default MTUs for first setup: */
- else if (card->options.layer2)
+ else if (IS_LAYER2(card))
new_mtu = ETH_DATA_LEN;
else
new_mtu = ETH_DATA_LEN - 8; /* allow for LLC + SNAP */
@@ -2315,7 +2260,6 @@ static int qeth_get_mtu_outof_framesize(int framesize)
static int qeth_ulp_enable_cb(struct qeth_card *card, struct qeth_reply *reply,
unsigned long data)
{
-
__u16 mtu, framesize;
__u16 len;
__u8 link_type;
@@ -2343,7 +2287,6 @@ static int qeth_ulp_enable_cb(struct qeth_card *card, struct qeth_reply *reply,
} else
card->info.link_type = 0;
QETH_DBF_TEXT_(SETUP, 2, "link%d", card->info.link_type);
- QETH_DBF_TEXT_(SETUP, 2, " rc%d", iob->rc);
return 0;
}
@@ -2351,7 +2294,7 @@ static u8 qeth_mpc_select_prot_type(struct qeth_card *card)
{
if (IS_OSN(card))
return QETH_PROT_OSN2;
- return (card->options.layer2 == 1) ? QETH_PROT_LAYER2 : QETH_PROT_TCPIP;
+ return IS_LAYER2(card) ? QETH_PROT_LAYER2 : QETH_PROT_TCPIP;
}
static int qeth_ulp_enable(struct qeth_card *card)
@@ -2880,23 +2823,18 @@ static __u8 qeth_get_ipa_adp_type(enum qeth_link_types link_type)
}
static void qeth_fill_ipacmd_header(struct qeth_card *card,
- struct qeth_ipa_cmd *cmd, __u8 command,
- enum qeth_prot_versions prot)
+ struct qeth_ipa_cmd *cmd,
+ enum qeth_ipa_cmds command,
+ enum qeth_prot_versions prot)
{
- memset(cmd, 0, sizeof(struct qeth_ipa_cmd));
cmd->hdr.command = command;
cmd->hdr.initiator = IPA_CMD_INITIATOR_HOST;
/* cmd->hdr.seqno is set by qeth_send_control_data() */
cmd->hdr.adapter_type = qeth_get_ipa_adp_type(card->info.link_type);
cmd->hdr.rel_adapter_no = (u8) card->dev->dev_port;
- if (card->options.layer2)
- cmd->hdr.prim_version_no = 2;
- else
- cmd->hdr.prim_version_no = 1;
+ cmd->hdr.prim_version_no = IS_LAYER2(card) ? 2 : 1;
cmd->hdr.param_count = 1;
cmd->hdr.prot_version = prot;
- cmd->hdr.ipa_supported = 0;
- cmd->hdr.ipa_enabled = 0;
}
struct qeth_cmd_buffer *qeth_get_ipacmd_buffer(struct qeth_card *card,
@@ -2910,8 +2848,8 @@ struct qeth_cmd_buffer *qeth_get_ipacmd_buffer(struct qeth_card *card,
} else {
dev_warn(&card->gdev->dev,
"The qeth driver ran out of channel command buffers\n");
- QETH_DBF_MESSAGE(1, "%s The qeth driver ran out of channel command buffers",
- dev_name(&card->gdev->dev));
+ QETH_DBF_MESSAGE(1, "device %x ran out of channel command buffers",
+ CARD_DEVID(card));
}
return iob;
@@ -3043,13 +2981,12 @@ static int qeth_query_ipassists_cb(struct qeth_card *card,
QETH_DBF_TEXT(SETUP, 2, "ipaunsup");
card->options.ipa4.supported_funcs |= IPA_SETADAPTERPARMS;
card->options.ipa6.supported_funcs |= IPA_SETADAPTERPARMS;
- return -0;
+ return 0;
default:
if (cmd->hdr.return_code) {
- QETH_DBF_MESSAGE(1, "%s IPA_CMD_QIPASSIST: Unhandled "
- "rc=%d\n",
- dev_name(&card->gdev->dev),
- cmd->hdr.return_code);
+ QETH_DBF_MESSAGE(1, "IPA_CMD_QIPASSIST on device %x: Unhandled rc=%#x\n",
+ CARD_DEVID(card),
+ cmd->hdr.return_code);
return 0;
}
}
@@ -3061,8 +2998,8 @@ static int qeth_query_ipassists_cb(struct qeth_card *card,
card->options.ipa6.supported_funcs = cmd->hdr.ipa_supported;
card->options.ipa6.enabled_funcs = cmd->hdr.ipa_enabled;
} else
- QETH_DBF_MESSAGE(1, "%s IPA_CMD_QIPASSIST: Flawed LIC detected"
- "\n", dev_name(&card->gdev->dev));
+ QETH_DBF_MESSAGE(1, "IPA_CMD_QIPASSIST on device %x: Flawed LIC detected\n",
+ CARD_DEVID(card));
return 0;
}
@@ -3787,7 +3724,7 @@ EXPORT_SYMBOL_GPL(qeth_get_priority_queue);
* Returns the number of pages, and thus QDIO buffer elements, needed to cover
* fragmented part of the SKB. Returns zero for linear SKB.
*/
-int qeth_get_elements_for_frags(struct sk_buff *skb)
+static int qeth_get_elements_for_frags(struct sk_buff *skb)
{
int cnt, elements = 0;
@@ -3800,9 +3737,17 @@ int qeth_get_elements_for_frags(struct sk_buff *skb)
}
return elements;
}
-EXPORT_SYMBOL_GPL(qeth_get_elements_for_frags);
-static unsigned int qeth_count_elements(struct sk_buff *skb, int data_offset)
+/**
+ * qeth_count_elements() - Counts the number of QDIO buffer elements needed
+ * to transmit an skb.
+ * @skb: the skb to operate on.
+ * @data_offset: skip this part of the skb's linear data
+ *
+ * Returns the number of pages, and thus QDIO buffer elements, needed to map the
+ * skb's data (both its linear part and paged fragments).
+ */
+unsigned int qeth_count_elements(struct sk_buff *skb, unsigned int data_offset)
{
unsigned int elements = qeth_get_elements_for_frags(skb);
addr_t end = (addr_t)skb->data + skb_headlen(skb);
@@ -3812,54 +3757,10 @@ static unsigned int qeth_count_elements(struct sk_buff *skb, int data_offset)
elements += qeth_get_elements_for_range(start, end);
return elements;
}
+EXPORT_SYMBOL_GPL(qeth_count_elements);
-/**
- * qeth_get_elements_no() - find number of SBALEs for skb data, inc. frags.
- * @card: qeth card structure, to check max. elems.
- * @skb: SKB address
- * @extra_elems: extra elems needed, to check against max.
- * @data_offset: range starts at skb->data + data_offset
- *
- * Returns the number of pages, and thus QDIO buffer elements, needed to cover
- * skb data, including linear part and fragments. Checks if the result plus
- * extra_elems fits under the limit for the card. Returns 0 if it does not.
- * Note: extra_elems is not included in the returned result.
- */
-int qeth_get_elements_no(struct qeth_card *card,
- struct sk_buff *skb, int extra_elems, int data_offset)
-{
- int elements = qeth_count_elements(skb, data_offset);
-
- if ((elements + extra_elems) > QETH_MAX_BUFFER_ELEMENTS(card)) {
- QETH_DBF_MESSAGE(2, "Invalid size of IP packet "
- "(Number=%d / Length=%d). Discarded.\n",
- elements + extra_elems, skb->len);
- return 0;
- }
- return elements;
-}
-EXPORT_SYMBOL_GPL(qeth_get_elements_no);
-
-int qeth_hdr_chk_and_bounce(struct sk_buff *skb, struct qeth_hdr **hdr, int len)
-{
- int hroom, inpage, rest;
-
- if (((unsigned long)skb->data & PAGE_MASK) !=
- (((unsigned long)skb->data + len - 1) & PAGE_MASK)) {
- hroom = skb_headroom(skb);
- inpage = PAGE_SIZE - ((unsigned long) skb->data % PAGE_SIZE);
- rest = len - inpage;
- if (rest > hroom)
- return 1;
- memmove(skb->data - rest, skb->data, skb_headlen(skb));
- skb->data -= rest;
- skb->tail -= rest;
- *hdr = (struct qeth_hdr *)skb->data;
- QETH_DBF_MESSAGE(2, "skb bounce len: %d rest: %d\n", len, rest);
- }
- return 0;
-}
-EXPORT_SYMBOL_GPL(qeth_hdr_chk_and_bounce);
+#define QETH_HDR_CACHE_OBJ_SIZE (sizeof(struct qeth_hdr_tso) + \
+ MAX_TCP_HEADER)
/**
* qeth_add_hw_header() - add a HW header to an skb.
@@ -3894,7 +3795,11 @@ check_layout:
if (qeth_get_elements_for_range(start, end + contiguous) == 1) {
/* Push HW header into same page as first protocol header. */
push_ok = true;
- __elements = qeth_count_elements(skb, 0);
+ /* ... but TSO always needs a separate element for headers: */
+ if (skb_is_gso(skb))
+ __elements = 1 + qeth_count_elements(skb, proto_len);
+ else
+ __elements = qeth_count_elements(skb, 0);
} else if (!proto_len && qeth_get_elements_for_range(start, end) == 1) {
/* Push HW header into a new page. */
push_ok = true;
@@ -3935,6 +3840,8 @@ check_layout:
return hdr_len;
}
/* fall back */
+ if (hdr_len + proto_len > QETH_HDR_CACHE_OBJ_SIZE)
+ return -E2BIG;
*hdr = kmem_cache_alloc(qeth_core_header_cache, GFP_ATOMIC);
if (!*hdr)
return -ENOMEM;
@@ -4026,8 +3933,7 @@ static int qeth_fill_buffer(struct qeth_qdio_out_q *queue,
bool is_first_elem = true;
int flush_cnt = 0;
- refcount_inc(&skb->users);
- skb_queue_tail(&buf->skb_list, skb);
+ __skb_queue_tail(&buf->skb_list, skb);
/* build dedicated header element */
if (hd_len) {
@@ -4176,6 +4082,97 @@ out:
}
EXPORT_SYMBOL_GPL(qeth_do_send_packet);
+void qeth_fill_tso_ext(struct qeth_hdr_tso *hdr, unsigned int payload_len,
+ struct sk_buff *skb, unsigned int proto_len)
+{
+ struct qeth_hdr_ext_tso *ext = &hdr->ext;
+
+ ext->hdr_tot_len = sizeof(*ext);
+ ext->imb_hdr_no = 1;
+ ext->hdr_type = 1;
+ ext->hdr_version = 1;
+ ext->hdr_len = 28;
+ ext->payload_len = payload_len;
+ ext->mss = skb_shinfo(skb)->gso_size;
+ ext->dg_hdr_len = proto_len;
+}
+EXPORT_SYMBOL_GPL(qeth_fill_tso_ext);
+
+int qeth_xmit(struct qeth_card *card, struct sk_buff *skb,
+ struct qeth_qdio_out_q *queue, int ipv, int cast_type,
+ void (*fill_header)(struct qeth_card *card, struct qeth_hdr *hdr,
+ struct sk_buff *skb, int ipv, int cast_type,
+ unsigned int data_len))
+{
+ unsigned int proto_len, hw_hdr_len;
+ unsigned int frame_len = skb->len;
+ bool is_tso = skb_is_gso(skb);
+ unsigned int data_offset = 0;
+ struct qeth_hdr *hdr = NULL;
+ unsigned int hd_len = 0;
+ unsigned int elements;
+ int push_len, rc;
+ bool is_sg;
+
+ if (is_tso) {
+ hw_hdr_len = sizeof(struct qeth_hdr_tso);
+ proto_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+ } else {
+ hw_hdr_len = sizeof(struct qeth_hdr);
+ proto_len = IS_IQD(card) ? ETH_HLEN : 0;
+ }
+
+ rc = skb_cow_head(skb, hw_hdr_len);
+ if (rc)
+ return rc;
+
+ push_len = qeth_add_hw_header(card, skb, &hdr, hw_hdr_len, proto_len,
+ &elements);
+ if (push_len < 0)
+ return push_len;
+ if (is_tso || !push_len) {
+ /* HW header needs its own buffer element. */
+ hd_len = hw_hdr_len + proto_len;
+ data_offset = push_len + proto_len;
+ }
+ memset(hdr, 0, hw_hdr_len);
+ fill_header(card, hdr, skb, ipv, cast_type, frame_len);
+ if (is_tso)
+ qeth_fill_tso_ext((struct qeth_hdr_tso *) hdr,
+ frame_len - proto_len, skb, proto_len);
+
+ is_sg = skb_is_nonlinear(skb);
+ if (IS_IQD(card)) {
+ rc = qeth_do_send_packet_fast(queue, skb, hdr, data_offset,
+ hd_len);
+ } else {
+ /* TODO: drop skb_orphan() once TX completion is fast enough */
+ skb_orphan(skb);
+ rc = qeth_do_send_packet(card, queue, skb, hdr, data_offset,
+ hd_len, elements);
+ }
+
+ if (!rc) {
+ if (card->options.performance_stats) {
+ card->perf_stats.buf_elements_sent += elements;
+ if (is_sg)
+ card->perf_stats.sg_skbs_sent++;
+ if (is_tso) {
+ card->perf_stats.large_send_bytes += frame_len;
+ card->perf_stats.large_send_cnt++;
+ }
+ }
+ } else {
+ if (!push_len)
+ kmem_cache_free(qeth_core_header_cache, hdr);
+ if (rc == -EBUSY)
+ /* roll back to ETH header */
+ skb_pull(skb, push_len);
+ }
+ return rc;
+}
+EXPORT_SYMBOL_GPL(qeth_xmit);
+
static int qeth_setadp_promisc_mode_cb(struct qeth_card *card,
struct qeth_reply *reply, unsigned long data)
{
@@ -4243,8 +4240,7 @@ static int qeth_setadpparms_change_macaddr_cb(struct qeth_card *card,
if (qeth_setadpparms_inspect_rc(cmd))
return 0;
- if (!card->options.layer2 ||
- !(card->info.mac_bits & QETH_LAYER2_MAC_READ)) {
+ if (IS_LAYER3(card) || !(card->info.mac_bits & QETH_LAYER2_MAC_READ)) {
ether_addr_copy(card->dev->dev_addr,
cmd->data.setadapterparms.data.change_addr.addr);
card->info.mac_bits |= QETH_LAYER2_MAC_READ;
@@ -4295,10 +4291,9 @@ static int qeth_setadpparms_set_access_ctrl_cb(struct qeth_card *card,
cmd->data.setadapterparms.hdr.return_code);
if (cmd->data.setadapterparms.hdr.return_code !=
SET_ACCESS_CTRL_RC_SUCCESS)
- QETH_DBF_MESSAGE(3, "ERR:SET_ACCESS_CTRL(%s,%d)==%d\n",
- card->gdev->dev.kobj.name,
- access_ctrl_req->subcmd_code,
- cmd->data.setadapterparms.hdr.return_code);
+ QETH_DBF_MESSAGE(3, "ERR:SET_ACCESS_CTRL(%#x) on device %x: %#x\n",
+ access_ctrl_req->subcmd_code, CARD_DEVID(card),
+ cmd->data.setadapterparms.hdr.return_code);
switch (cmd->data.setadapterparms.hdr.return_code) {
case SET_ACCESS_CTRL_RC_SUCCESS:
if (card->options.isolation == ISOLATION_MODE_NONE) {
@@ -4310,14 +4305,14 @@ static int qeth_setadpparms_set_access_ctrl_cb(struct qeth_card *card,
}
break;
case SET_ACCESS_CTRL_RC_ALREADY_NOT_ISOLATED:
- QETH_DBF_MESSAGE(2, "%s QDIO data connection isolation already "
- "deactivated\n", dev_name(&card->gdev->dev));
+ QETH_DBF_MESSAGE(2, "QDIO data connection isolation on device %x already deactivated\n",
+ CARD_DEVID(card));
if (fallback)
card->options.isolation = card->options.prev_isolation;
break;
case SET_ACCESS_CTRL_RC_ALREADY_ISOLATED:
- QETH_DBF_MESSAGE(2, "%s QDIO data connection isolation already"
- " activated\n", dev_name(&card->gdev->dev));
+ QETH_DBF_MESSAGE(2, "QDIO data connection isolation on device %x already activated\n",
+ CARD_DEVID(card));
if (fallback)
card->options.isolation = card->options.prev_isolation;
break;
@@ -4403,10 +4398,8 @@ int qeth_set_access_ctrl_online(struct qeth_card *card, int fallback)
rc = qeth_setadpparms_set_access_ctrl(card,
card->options.isolation, fallback);
if (rc) {
- QETH_DBF_MESSAGE(3,
- "IPA(SET_ACCESS_CTRL,%s,%d) sent failed\n",
- card->gdev->dev.kobj.name,
- rc);
+ QETH_DBF_MESSAGE(3, "IPA(SET_ACCESS_CTRL(%d) on device %x: sent failed\n",
+ rc, CARD_DEVID(card));
rc = -EOPNOTSUPP;
}
} else if (card->options.isolation != ISOLATION_MODE_NONE) {
@@ -4441,7 +4434,8 @@ static int qeth_mdio_read(struct net_device *dev, int phy_id, int regnum)
rc = BMCR_FULLDPLX;
if ((card->info.link_type != QETH_LINK_TYPE_GBIT_ETH) &&
(card->info.link_type != QETH_LINK_TYPE_OSN) &&
- (card->info.link_type != QETH_LINK_TYPE_10GBIT_ETH))
+ (card->info.link_type != QETH_LINK_TYPE_10GBIT_ETH) &&
+ (card->info.link_type != QETH_LINK_TYPE_25GBIT_ETH))
rc |= BMCR_SPEED100;
break;
case MII_BMSR: /* Basic mode status register */
@@ -4598,9 +4592,9 @@ static int qeth_snmp_command(struct qeth_card *card, char __user *udata)
return -EOPNOTSUPP;
if ((!qeth_adp_supported(card, IPA_SETADP_SET_SNMP_CONTROL)) &&
- (!card->options.layer2)) {
+ IS_LAYER3(card))
return -EOPNOTSUPP;
- }
+
/* skip 4 bytes (data_len struct member) to get req_len */
if (copy_from_user(&req_len, udata + sizeof(int), sizeof(int)))
return -EFAULT;
@@ -4632,8 +4626,8 @@ static int qeth_snmp_command(struct qeth_card *card, char __user *udata)
rc = qeth_send_ipa_snmp_cmd(card, iob, QETH_SETADP_BASE_LEN + req_len,
qeth_snmp_command_cb, (void *)&qinfo);
if (rc)
- QETH_DBF_MESSAGE(2, "SNMP command failed on %s: (0x%x)\n",
- QETH_CARD_IFNAME(card), rc);
+ QETH_DBF_MESSAGE(2, "SNMP command failed on device %x: (%#x)\n",
+ CARD_DEVID(card), rc);
else {
if (copy_to_user(udata, qinfo.udata, qinfo.udata_len))
rc = -EFAULT;
@@ -4867,8 +4861,8 @@ static void qeth_determine_capabilities(struct qeth_card *card)
rc = qeth_read_conf_data(card, (void **) &prcd, &length);
if (rc) {
- QETH_DBF_MESSAGE(2, "%s qeth_read_conf_data returned %i\n",
- dev_name(&card->gdev->dev), rc);
+ QETH_DBF_MESSAGE(2, "qeth_read_conf_data on device %x returned %i\n",
+ CARD_DEVID(card), rc);
QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc);
goto out_offline;
}
@@ -5044,6 +5038,7 @@ static void qeth_core_free_card(struct qeth_card *card)
qeth_clean_channel(&card->data);
qeth_free_qdio_buffers(card);
unregister_service_level(&card->qeth_service_level);
+ dev_set_drvdata(&card->gdev->dev, NULL);
kfree(card);
}
@@ -5083,7 +5078,7 @@ static struct ccw_driver qeth_ccw_driver = {
.remove = ccwgroup_remove_ccwdev,
};
-int qeth_core_hardsetup_card(struct qeth_card *card)
+int qeth_core_hardsetup_card(struct qeth_card *card, bool *carrier_ok)
{
int retries = 3;
int rc;
@@ -5093,8 +5088,8 @@ int qeth_core_hardsetup_card(struct qeth_card *card)
qeth_update_from_chp_desc(card);
retry:
if (retries < 3)
- QETH_DBF_MESSAGE(2, "%s Retrying to do IDX activates.\n",
- dev_name(&card->gdev->dev));
+ QETH_DBF_MESSAGE(2, "Retrying to do IDX activates on device %x.\n",
+ CARD_DEVID(card));
rc = qeth_qdio_clear_card(card, card->info.type != QETH_CARD_TYPE_IQD);
ccw_device_set_offline(CARD_DDEV(card));
ccw_device_set_offline(CARD_WDEV(card));
@@ -5123,7 +5118,7 @@ retriable:
qeth_determine_capabilities(card);
qeth_init_tokens(card);
qeth_init_func_level(card);
- rc = qeth_idx_activate_channel(&card->read, qeth_idx_read_cb);
+ rc = qeth_idx_activate_channel(card, &card->read, qeth_idx_read_cb);
if (rc == -ERESTARTSYS) {
QETH_DBF_TEXT(SETUP, 2, "break2");
return rc;
@@ -5134,7 +5129,7 @@ retriable:
else
goto retry;
}
- rc = qeth_idx_activate_channel(&card->write, qeth_idx_write_cb);
+ rc = qeth_idx_activate_channel(card, &card->write, qeth_idx_write_cb);
if (rc == -ERESTARTSYS) {
QETH_DBF_TEXT(SETUP, 2, "break3");
return rc;
@@ -5158,13 +5153,21 @@ retriable:
if (rc == IPA_RC_LAN_OFFLINE) {
dev_warn(&card->gdev->dev,
"The LAN is offline\n");
- card->lan_online = 0;
+ *carrier_ok = false;
} else {
rc = -ENODEV;
goto out;
}
- } else
- card->lan_online = 1;
+ } else {
+ *carrier_ok = true;
+ }
+
+ if (qeth_netdev_is_registered(card->dev)) {
+ if (*carrier_ok)
+ netif_carrier_on(card->dev);
+ else
+ netif_carrier_off(card->dev);
+ }
card->options.ipa4.supported_funcs = 0;
card->options.ipa6.supported_funcs = 0;
@@ -5197,8 +5200,8 @@ retriable:
out:
dev_warn(&card->gdev->dev, "The qeth device driver failed to recover "
"an error on the device\n");
- QETH_DBF_MESSAGE(2, "%s Initialization in hardsetup failed! rc=%d\n",
- dev_name(&card->gdev->dev), rc);
+ QETH_DBF_MESSAGE(2, "Initialization for device %x failed in hardsetup! rc=%d\n",
+ CARD_DEVID(card), rc);
return rc;
}
EXPORT_SYMBOL_GPL(qeth_core_hardsetup_card);
@@ -5421,6 +5424,21 @@ static int qeth_setassparms_inspect_rc(struct qeth_ipa_cmd *cmd)
return cmd->hdr.return_code;
}
+static int qeth_setassparms_get_caps_cb(struct qeth_card *card,
+ struct qeth_reply *reply,
+ unsigned long data)
+{
+ struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
+ struct qeth_ipa_caps *caps = reply->param;
+
+ if (qeth_setassparms_inspect_rc(cmd))
+ return 0;
+
+ caps->supported = cmd->data.setassparms.data.caps.supported;
+ caps->enabled = cmd->data.setassparms.data.caps.enabled;
+ return 0;
+}
+
int qeth_setassparms_cb(struct qeth_card *card,
struct qeth_reply *reply, unsigned long data)
{
@@ -5456,19 +5474,18 @@ struct qeth_cmd_buffer *qeth_get_setassparms_cmd(struct qeth_card *card,
cmd->data.setassparms.hdr.assist_no = ipa_func;
cmd->data.setassparms.hdr.length = 8 + len;
cmd->data.setassparms.hdr.command_code = cmd_code;
- cmd->data.setassparms.hdr.return_code = 0;
- cmd->data.setassparms.hdr.seq_no = 0;
}
return iob;
}
EXPORT_SYMBOL_GPL(qeth_get_setassparms_cmd);
-int qeth_send_setassparms(struct qeth_card *card,
- struct qeth_cmd_buffer *iob, __u16 len, long data,
- int (*reply_cb)(struct qeth_card *,
- struct qeth_reply *, unsigned long),
- void *reply_param)
+static int qeth_send_setassparms(struct qeth_card *card,
+ struct qeth_cmd_buffer *iob, u16 len,
+ long data, int (*reply_cb)(struct qeth_card *,
+ struct qeth_reply *,
+ unsigned long),
+ void *reply_param)
{
int rc;
struct qeth_ipa_cmd *cmd;
@@ -5484,7 +5501,6 @@ int qeth_send_setassparms(struct qeth_card *card,
rc = qeth_send_ipa_cmd(card, iob, reply_cb, reply_param);
return rc;
}
-EXPORT_SYMBOL_GPL(qeth_send_setassparms);
int qeth_send_simple_setassparms_prot(struct qeth_card *card,
enum qeth_ipa_funcs ipa_func,
@@ -5560,11 +5576,11 @@ static int qeth_register_dbf_views(void)
return 0;
}
+static DEFINE_MUTEX(qeth_mod_mutex); /* for synchronized module loading */
+
int qeth_core_load_discipline(struct qeth_card *card,
enum qeth_discipline_id discipline)
{
- int rc = 0;
-
mutex_lock(&qeth_mod_mutex);
switch (discipline) {
case QETH_DISCIPLINE_LAYER3:
@@ -5578,22 +5594,25 @@ int qeth_core_load_discipline(struct qeth_card *card,
default:
break;
}
+ mutex_unlock(&qeth_mod_mutex);
if (!card->discipline) {
dev_err(&card->gdev->dev, "There is no kernel module to "
"support discipline %d\n", discipline);
- rc = -EINVAL;
+ return -EINVAL;
}
- mutex_unlock(&qeth_mod_mutex);
- return rc;
+
+ card->options.layer = discipline;
+ return 0;
}
void qeth_core_free_discipline(struct qeth_card *card)
{
- if (card->options.layer2)
+ if (IS_LAYER2(card))
symbol_put(qeth_l2_discipline);
else
symbol_put(qeth_l3_discipline);
+ card->options.layer = QETH_DISCIPLINE_UNDETERMINED;
card->discipline = NULL;
}
@@ -5731,7 +5750,6 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev)
struct device *dev;
int rc;
enum qeth_discipline_id enforced_disc;
- unsigned long flags;
char dbf_name[DBF_NAME_LEN];
QETH_DBF_TEXT(SETUP, 2, "probedev");
@@ -5742,7 +5760,7 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev)
QETH_DBF_TEXT_(SETUP, 2, "%s", dev_name(&gdev->dev));
- card = qeth_alloc_card();
+ card = qeth_alloc_card(gdev);
if (!card) {
QETH_DBF_TEXT_(SETUP, 2, "1err%d", -ENOMEM);
rc = -ENOMEM;
@@ -5758,15 +5776,6 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev)
goto err_card;
}
- card->read.ccwdev = gdev->cdev[0];
- card->write.ccwdev = gdev->cdev[1];
- card->data.ccwdev = gdev->cdev[2];
- dev_set_drvdata(&gdev->dev, card);
- card->gdev = gdev;
- gdev->cdev[0]->handler = qeth_irq;
- gdev->cdev[1]->handler = qeth_irq;
- gdev->cdev[2]->handler = qeth_irq;
-
qeth_setup_card(card);
qeth_update_from_chp_desc(card);
@@ -5797,9 +5806,9 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev)
break;
}
- write_lock_irqsave(&qeth_core_card_list.rwlock, flags);
+ write_lock_irq(&qeth_core_card_list.rwlock);
list_add_tail(&card->list, &qeth_core_card_list.list);
- write_unlock_irqrestore(&qeth_core_card_list.rwlock, flags);
+ write_unlock_irq(&qeth_core_card_list.rwlock);
return 0;
err_disc:
@@ -5815,7 +5824,6 @@ err_dev:
static void qeth_core_remove_device(struct ccwgroup_device *gdev)
{
- unsigned long flags;
struct qeth_card *card = dev_get_drvdata(&gdev->dev);
QETH_DBF_TEXT(SETUP, 2, "removedv");
@@ -5825,12 +5833,11 @@ static void qeth_core_remove_device(struct ccwgroup_device *gdev)
qeth_core_free_discipline(card);
}
- write_lock_irqsave(&qeth_core_card_list.rwlock, flags);
+ write_lock_irq(&qeth_core_card_list.rwlock);
list_del(&card->list);
- write_unlock_irqrestore(&qeth_core_card_list.rwlock, flags);
+ write_unlock_irq(&qeth_core_card_list.rwlock);
free_netdev(card->dev);
qeth_core_free_card(card);
- dev_set_drvdata(&gdev->dev, NULL);
put_device(&gdev->dev);
}
@@ -6123,7 +6130,7 @@ void qeth_core_get_drvinfo(struct net_device *dev,
{
struct qeth_card *card = dev->ml_priv;
- strlcpy(info->driver, card->options.layer2 ? "qeth_l2" : "qeth_l3",
+ strlcpy(info->driver, IS_LAYER2(card) ? "qeth_l2" : "qeth_l3",
sizeof(info->driver));
strlcpy(info->version, "1.0", sizeof(info->version));
strlcpy(info->fw_version, card->info.mcl_level,
@@ -6162,8 +6169,14 @@ static void qeth_set_cmd_adv_sup(struct ethtool_link_ksettings *cmd,
WARN_ON_ONCE(1);
}
- /* fallthrough from high to low, to select all legal speeds: */
+ /* partially does fall through, to also select lower speeds */
switch (maxspeed) {
+ case SPEED_25000:
+ ethtool_link_ksettings_add_link_mode(cmd, supported,
+ 25000baseSR_Full);
+ ethtool_link_ksettings_add_link_mode(cmd, advertising,
+ 25000baseSR_Full);
+ break;
case SPEED_10000:
ethtool_link_ksettings_add_link_mode(cmd, supported,
10000baseT_Full);
@@ -6246,6 +6259,10 @@ int qeth_core_ethtool_get_link_ksettings(struct net_device *netdev,
cmd->base.speed = SPEED_10000;
cmd->base.port = PORT_FIBRE;
break;
+ case QETH_LINK_TYPE_25GBIT_ETH:
+ cmd->base.speed = SPEED_25000;
+ cmd->base.port = PORT_FIBRE;
+ break;
default:
cmd->base.speed = SPEED_10;
cmd->base.port = PORT_TP;
@@ -6312,6 +6329,9 @@ int qeth_core_ethtool_get_link_ksettings(struct net_device *netdev,
case CARD_INFO_PORTS_10G:
cmd->base.speed = SPEED_10000;
break;
+ case CARD_INFO_PORTS_25G:
+ cmd->base.speed = SPEED_25000;
+ break;
}
return 0;
@@ -6434,27 +6454,85 @@ static int qeth_set_ipa_csum(struct qeth_card *card, bool on, int cstype,
return rc ? -EIO : 0;
}
-static int qeth_set_ipa_tso(struct qeth_card *card, int on)
+static int qeth_start_tso_cb(struct qeth_card *card, struct qeth_reply *reply,
+ unsigned long data)
+{
+ struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
+ struct qeth_tso_start_data *tso_data = reply->param;
+
+ if (qeth_setassparms_inspect_rc(cmd))
+ return 0;
+
+ tso_data->mss = cmd->data.setassparms.data.tso.mss;
+ tso_data->supported = cmd->data.setassparms.data.tso.supported;
+ return 0;
+}
+
+static int qeth_set_tso_off(struct qeth_card *card,
+ enum qeth_prot_versions prot)
{
+ return qeth_send_simple_setassparms_prot(card, IPA_OUTBOUND_TSO,
+ IPA_CMD_ASS_STOP, 0, prot);
+}
+
+static int qeth_set_tso_on(struct qeth_card *card,
+ enum qeth_prot_versions prot)
+{
+ struct qeth_tso_start_data tso_data;
+ struct qeth_cmd_buffer *iob;
+ struct qeth_ipa_caps caps;
int rc;
- QETH_CARD_TEXT(card, 3, "sttso");
+ iob = qeth_get_setassparms_cmd(card, IPA_OUTBOUND_TSO,
+ IPA_CMD_ASS_START, 0, prot);
+ if (!iob)
+ return -ENOMEM;
- if (on) {
- rc = qeth_send_simple_setassparms(card, IPA_OUTBOUND_TSO,
- IPA_CMD_ASS_START, 0);
- if (rc) {
- dev_warn(&card->gdev->dev,
- "Starting outbound TCP segmentation offload for %s failed\n",
- QETH_CARD_IFNAME(card));
- return -EIO;
- }
- dev_info(&card->gdev->dev, "Outbound TSO enabled\n");
- } else {
- rc = qeth_send_simple_setassparms(card, IPA_OUTBOUND_TSO,
- IPA_CMD_ASS_STOP, 0);
+ rc = qeth_send_setassparms(card, iob, 0, 0 /* unused */,
+ qeth_start_tso_cb, &tso_data);
+ if (rc)
+ return rc;
+
+ if (!tso_data.mss || !(tso_data.supported & QETH_IPA_LARGE_SEND_TCP)) {
+ qeth_set_tso_off(card, prot);
+ return -EOPNOTSUPP;
}
- return rc;
+
+ iob = qeth_get_setassparms_cmd(card, IPA_OUTBOUND_TSO,
+ IPA_CMD_ASS_ENABLE, sizeof(caps), prot);
+ if (!iob) {
+ qeth_set_tso_off(card, prot);
+ return -ENOMEM;
+ }
+
+ /* enable TSO capability */
+ caps.supported = 0;
+ caps.enabled = QETH_IPA_LARGE_SEND_TCP;
+ rc = qeth_send_setassparms(card, iob, sizeof(caps), (long) &caps,
+ qeth_setassparms_get_caps_cb, &caps);
+ if (rc) {
+ qeth_set_tso_off(card, prot);
+ return rc;
+ }
+
+ if (!qeth_ipa_caps_supported(&caps, QETH_IPA_LARGE_SEND_TCP) ||
+ !qeth_ipa_caps_enabled(&caps, QETH_IPA_LARGE_SEND_TCP)) {
+ qeth_set_tso_off(card, prot);
+ return -EOPNOTSUPP;
+ }
+
+ dev_info(&card->gdev->dev, "TSOv%u enabled (MSS: %u)\n", prot,
+ tso_data.mss);
+ return 0;
+}
+
+static int qeth_set_ipa_tso(struct qeth_card *card, bool on,
+ enum qeth_prot_versions prot)
+{
+ int rc = on ? qeth_set_tso_on(card, prot) :
+ qeth_set_tso_off(card, prot);
+
+ return rc ? -EIO : 0;
}
static int qeth_set_ipa_rx_csum(struct qeth_card *card, bool on)
@@ -6481,7 +6559,7 @@ static int qeth_set_ipa_rx_csum(struct qeth_card *card, bool on)
}
#define QETH_HW_FEATURES (NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_TSO | \
- NETIF_F_IPV6_CSUM)
+ NETIF_F_IPV6_CSUM | NETIF_F_TSO6)
/**
* qeth_enable_hw_features() - (Re-)Enable HW functions for device features
* @dev: a net_device
@@ -6531,11 +6609,18 @@ int qeth_set_features(struct net_device *dev, netdev_features_t features)
if (rc)
changed ^= NETIF_F_RXCSUM;
}
- if ((changed & NETIF_F_TSO)) {
- rc = qeth_set_ipa_tso(card, features & NETIF_F_TSO ? 1 : 0);
+ if (changed & NETIF_F_TSO) {
+ rc = qeth_set_ipa_tso(card, features & NETIF_F_TSO,
+ QETH_PROT_IPV4);
if (rc)
changed ^= NETIF_F_TSO;
}
+ if (changed & NETIF_F_TSO6) {
+ rc = qeth_set_ipa_tso(card, features & NETIF_F_TSO6,
+ QETH_PROT_IPV6);
+ if (rc)
+ changed ^= NETIF_F_TSO6;
+ }
/* everything changed successfully? */
if ((dev->features ^ features) == changed)
@@ -6561,6 +6646,8 @@ netdev_features_t qeth_fix_features(struct net_device *dev,
features &= ~NETIF_F_RXCSUM;
if (!qeth_is_supported(card, IPA_OUTBOUND_TSO))
features &= ~NETIF_F_TSO;
+ if (!qeth_is_supported6(card, IPA_OUTBOUND_TSO))
+ features &= ~NETIF_F_TSO6;
/* if the card isn't up, remove features that require hw changes */
if (card->state == CARD_STATE_DOWN ||
card->state == CARD_STATE_RECOVER)
@@ -6602,9 +6689,7 @@ static int __init qeth_core_init(void)
pr_info("loading core functions\n");
INIT_LIST_HEAD(&qeth_core_card_list.list);
- INIT_LIST_HEAD(&qeth_dbf_list);
rwlock_init(&qeth_core_card_list.rwlock);
- mutex_init(&qeth_mod_mutex);
qeth_wq = create_singlethread_workqueue("qeth_wq");
if (!qeth_wq) {
@@ -6619,8 +6704,10 @@ static int __init qeth_core_init(void)
rc = PTR_ERR_OR_ZERO(qeth_core_root_dev);
if (rc)
goto register_err;
- qeth_core_header_cache = kmem_cache_create("qeth_hdr",
- sizeof(struct qeth_hdr) + ETH_HLEN, 64, 0, NULL);
+ qeth_core_header_cache =
+ kmem_cache_create("qeth_hdr", QETH_HDR_CACHE_OBJ_SIZE,
+ roundup_pow_of_two(QETH_HDR_CACHE_OBJ_SIZE),
+ 0, NULL);
if (!qeth_core_header_cache) {
rc = -ENOMEM;
goto slab_err;
diff --git a/drivers/s390/net/qeth_core_mpc.c b/drivers/s390/net/qeth_core_mpc.c
index 5bcb8dafc3ee..e891c0b52f4c 100644
--- a/drivers/s390/net/qeth_core_mpc.c
+++ b/drivers/s390/net/qeth_core_mpc.c
@@ -148,10 +148,10 @@ EXPORT_SYMBOL_GPL(IPA_PDU_HEADER);
struct ipa_rc_msg {
enum qeth_ipa_return_codes rc;
- char *msg;
+ const char *msg;
};
-static struct ipa_rc_msg qeth_ipa_rc_msg[] = {
+static const struct ipa_rc_msg qeth_ipa_rc_msg[] = {
{IPA_RC_SUCCESS, "success"},
{IPA_RC_NOTSUPP, "Command not supported"},
{IPA_RC_IP_TABLE_FULL, "Add Addr IP Table Full - ipv6"},
@@ -219,23 +219,23 @@ static struct ipa_rc_msg qeth_ipa_rc_msg[] = {
-char *qeth_get_ipa_msg(enum qeth_ipa_return_codes rc)
+const char *qeth_get_ipa_msg(enum qeth_ipa_return_codes rc)
{
- int x = 0;
- qeth_ipa_rc_msg[sizeof(qeth_ipa_rc_msg) /
- sizeof(struct ipa_rc_msg) - 1].rc = rc;
- while (qeth_ipa_rc_msg[x].rc != rc)
- x++;
+ int x;
+
+ for (x = 0; x < ARRAY_SIZE(qeth_ipa_rc_msg) - 1; x++)
+ if (qeth_ipa_rc_msg[x].rc == rc)
+ return qeth_ipa_rc_msg[x].msg;
return qeth_ipa_rc_msg[x].msg;
}
struct ipa_cmd_names {
enum qeth_ipa_cmds cmd;
- char *name;
+ const char *name;
};
-static struct ipa_cmd_names qeth_ipa_cmd_names[] = {
+static const struct ipa_cmd_names qeth_ipa_cmd_names[] = {
{IPA_CMD_STARTLAN, "startlan"},
{IPA_CMD_STOPLAN, "stoplan"},
{IPA_CMD_SETVMAC, "setvmac"},
@@ -267,13 +267,12 @@ static struct ipa_cmd_names qeth_ipa_cmd_names[] = {
{IPA_CMD_UNKNOWN, "unknown"},
};
-char *qeth_get_ipa_cmd_name(enum qeth_ipa_cmds cmd)
+const char *qeth_get_ipa_cmd_name(enum qeth_ipa_cmds cmd)
{
- int x = 0;
- qeth_ipa_cmd_names[
- sizeof(qeth_ipa_cmd_names) /
- sizeof(struct ipa_cmd_names)-1].cmd = cmd;
- while (qeth_ipa_cmd_names[x].cmd != cmd)
- x++;
+ int x;
+
+ for (x = 0; x < ARRAY_SIZE(qeth_ipa_cmd_names) - 1; x++)
+ if (qeth_ipa_cmd_names[x].cmd == cmd)
+ return qeth_ipa_cmd_names[x].name;
return qeth_ipa_cmd_names[x].name;
}
diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h
index aa8b9196b089..3e54be201b27 100644
--- a/drivers/s390/net/qeth_core_mpc.h
+++ b/drivers/s390/net/qeth_core_mpc.h
@@ -56,6 +56,21 @@ static inline bool qeth_intparm_is_iob(unsigned long intparm)
#define IPA_CMD_INITIATOR_OSA_REPLY 0x81
#define IPA_CMD_PRIM_VERSION_NO 0x01
+struct qeth_ipa_caps {
+ u32 supported;
+ u32 enabled;
+};
+
+static inline bool qeth_ipa_caps_supported(struct qeth_ipa_caps *caps, u32 mask)
+{
+ return (caps->supported & mask) == mask;
+}
+
+static inline bool qeth_ipa_caps_enabled(struct qeth_ipa_caps *caps, u32 mask)
+{
+ return (caps->enabled & mask) == mask;
+}
+
enum qeth_card_types {
QETH_CARD_TYPE_OSD = 1,
QETH_CARD_TYPE_IQD = 5,
@@ -75,6 +90,7 @@ enum qeth_link_types {
QETH_LINK_TYPE_GBIT_ETH = 0x03,
QETH_LINK_TYPE_OSN = 0x04,
QETH_LINK_TYPE_10GBIT_ETH = 0x10,
+ QETH_LINK_TYPE_25GBIT_ETH = 0x12,
QETH_LINK_TYPE_LANE_ETH100 = 0x81,
QETH_LINK_TYPE_LANE_TR = 0x82,
QETH_LINK_TYPE_LANE_ETH1000 = 0x83,
@@ -332,6 +348,7 @@ enum qeth_card_info_port_speed {
CARD_INFO_PORTS_100M = 0x00000006,
CARD_INFO_PORTS_1G = 0x00000007,
CARD_INFO_PORTS_10G = 0x00000008,
+ CARD_INFO_PORTS_25G = 0x0000000A,
};
/* (SET)DELIP(M) IPA stuff ***************************************************/
@@ -405,14 +422,25 @@ struct qeth_checksum_cmd {
__u32 enabled;
} __packed;
+enum qeth_ipa_large_send_caps {
+ QETH_IPA_LARGE_SEND_TCP = 0x00000001,
+};
+
+struct qeth_tso_start_data {
+ u32 mss;
+ u32 supported;
+};
+
/* SETASSPARMS IPA Command: */
struct qeth_ipacmd_setassparms {
struct qeth_ipacmd_setassparms_hdr hdr;
union {
__u32 flags_32bit;
+ struct qeth_ipa_caps caps;
struct qeth_checksum_cmd chksum;
- struct qeth_arp_cache_entry add_arp_entry;
+ struct qeth_arp_cache_entry arp_entry;
struct qeth_arp_query_data query_arp;
+ struct qeth_tso_start_data tso;
__u8 ip[16];
} data;
} __attribute__ ((packed));
@@ -797,8 +825,8 @@ enum qeth_ipa_arp_return_codes {
QETH_IPA_ARP_RC_Q_NO_DATA = 0x0008,
};
-extern char *qeth_get_ipa_msg(enum qeth_ipa_return_codes rc);
-extern char *qeth_get_ipa_cmd_name(enum qeth_ipa_cmds cmd);
+extern const char *qeth_get_ipa_msg(enum qeth_ipa_return_codes rc);
+extern const char *qeth_get_ipa_cmd_name(enum qeth_ipa_cmds cmd);
#define QETH_SETASS_BASE_LEN (sizeof(struct qeth_ipacmd_hdr) + \
sizeof(struct qeth_ipacmd_setassparms_hdr))
diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c
index 25d0be25bcb3..30f61608fa22 100644
--- a/drivers/s390/net/qeth_core_sys.c
+++ b/drivers/s390/net/qeth_core_sys.c
@@ -31,10 +31,9 @@ static ssize_t qeth_dev_state_show(struct device *dev,
case CARD_STATE_SOFTSETUP:
return sprintf(buf, "SOFTSETUP\n");
case CARD_STATE_UP:
- if (card->lan_online)
- return sprintf(buf, "UP (LAN ONLINE)\n");
- else
- return sprintf(buf, "UP (LAN OFFLINE)\n");
+ return sprintf(buf, "UP (LAN %s)\n",
+ netif_carrier_ok(card->dev) ? "ONLINE" :
+ "OFFLINE");
case CARD_STATE_RECOVER:
return sprintf(buf, "RECOVER\n");
default:
@@ -228,7 +227,7 @@ static ssize_t qeth_dev_prioqing_store(struct device *dev,
card->qdio.do_prio_queueing = QETH_PRIO_Q_ING_TOS;
card->qdio.default_out_queue = QETH_DEFAULT_QUEUE;
} else if (sysfs_streq(buf, "prio_queueing_vlan")) {
- if (!card->options.layer2) {
+ if (IS_LAYER3(card)) {
rc = -ENOTSUPP;
goto out;
}
@@ -379,7 +378,7 @@ static ssize_t qeth_dev_layer2_show(struct device *dev,
if (!card)
return -EINVAL;
- return sprintf(buf, "%i\n", card->options.layer2);
+ return sprintf(buf, "%i\n", card->options.layer);
}
static ssize_t qeth_dev_layer2_store(struct device *dev,
@@ -413,7 +412,7 @@ static ssize_t qeth_dev_layer2_store(struct device *dev,
goto out;
}
- if (card->options.layer2 == newdis)
+ if (card->options.layer == newdis)
goto out;
if (card->info.layer_enforced) {
/* fixed layer, can't switch */
@@ -432,8 +431,6 @@ static ssize_t qeth_dev_layer2_store(struct device *dev,
card->discipline->remove(card->gdev);
qeth_core_free_discipline(card);
- card->options.layer2 = -1;
-
free_netdev(card->dev);
card->dev = ndev;
}
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index b5e38531733f..2914a1a69f83 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -146,11 +146,11 @@ static int qeth_l2_write_mac(struct qeth_card *card, u8 *mac)
QETH_CARD_TEXT(card, 2, "L2Wmac");
rc = qeth_l2_send_setdelmac(card, mac, cmd);
if (rc == -EEXIST)
- QETH_DBF_MESSAGE(2, "MAC %pM already registered on %s\n",
- mac, QETH_CARD_IFNAME(card));
+ QETH_DBF_MESSAGE(2, "MAC already registered on device %x\n",
+ CARD_DEVID(card));
else if (rc)
- QETH_DBF_MESSAGE(2, "Failed to register MAC %pM on %s: %d\n",
- mac, QETH_CARD_IFNAME(card), rc);
+ QETH_DBF_MESSAGE(2, "Failed to register MAC on device %x: %d\n",
+ CARD_DEVID(card), rc);
return rc;
}
@@ -163,8 +163,8 @@ static int qeth_l2_remove_mac(struct qeth_card *card, u8 *mac)
QETH_CARD_TEXT(card, 2, "L2Rmac");
rc = qeth_l2_send_setdelmac(card, mac, cmd);
if (rc)
- QETH_DBF_MESSAGE(2, "Failed to delete MAC %pM on %s: %d\n",
- mac, QETH_CARD_IFNAME(card), rc);
+ QETH_DBF_MESSAGE(2, "Failed to delete MAC on device %u: %d\n",
+ CARD_DEVID(card), rc);
return rc;
}
@@ -193,15 +193,25 @@ static int qeth_l2_get_cast_type(struct qeth_card *card, struct sk_buff *skb)
return RTN_UNICAST;
}
-static void qeth_l2_fill_header(struct qeth_hdr *hdr, struct sk_buff *skb,
- int cast_type, unsigned int data_len)
+static void qeth_l2_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
+ struct sk_buff *skb, int ipv, int cast_type,
+ unsigned int data_len)
{
- struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb_mac_header(skb);
+ struct vlan_ethhdr *veth = vlan_eth_hdr(skb);
- memset(hdr, 0, sizeof(struct qeth_hdr));
- hdr->hdr.l2.id = QETH_HEADER_TYPE_LAYER2;
hdr->hdr.l2.pkt_length = data_len;
+ if (skb_is_gso(skb)) {
+ hdr->hdr.l2.id = QETH_HEADER_TYPE_L2_TSO;
+ } else {
+ hdr->hdr.l2.id = QETH_HEADER_TYPE_LAYER2;
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ qeth_tx_csum(skb, &hdr->hdr.l2.flags[1], ipv);
+ if (card->options.performance_stats)
+ card->perf_stats.tx_csum++;
+ }
+ }
+
/* set byte byte 3 to casting flags */
if (cast_type == RTN_MULTICAST)
hdr->hdr.l2.flags[2] |= QETH_LAYER2_FLAG_MULTICAST;
@@ -250,9 +260,9 @@ static int qeth_l2_send_setdelvlan_cb(struct qeth_card *card,
QETH_CARD_TEXT(card, 2, "L2sdvcb");
if (cmd->hdr.return_code) {
- QETH_DBF_MESSAGE(2, "Error in processing VLAN %i on %s: 0x%x.\n",
+ QETH_DBF_MESSAGE(2, "Error in processing VLAN %u on device %x: %#x.\n",
cmd->data.setdelvlan.vlan_id,
- QETH_CARD_IFNAME(card), cmd->hdr.return_code);
+ CARD_DEVID(card), cmd->hdr.return_code);
QETH_CARD_TEXT_(card, 2, "L2VL%4x", cmd->hdr.command);
QETH_CARD_TEXT_(card, 2, "err%d", cmd->hdr.return_code);
}
@@ -445,8 +455,8 @@ static int qeth_l2_request_initial_mac(struct qeth_card *card)
rc = qeth_vm_request_mac(card);
if (!rc)
goto out;
- QETH_DBF_MESSAGE(2, "z/VM MAC Service failed on device %s: x%x\n",
- CARD_BUS_ID(card), rc);
+ QETH_DBF_MESSAGE(2, "z/VM MAC Service failed on device %x: %#x\n",
+ CARD_DEVID(card), rc);
QETH_DBF_TEXT_(SETUP, 2, "err%04x", rc);
/* fall back to alternative mechanism: */
}
@@ -458,8 +468,8 @@ static int qeth_l2_request_initial_mac(struct qeth_card *card)
rc = qeth_setadpparms_change_macaddr(card);
if (!rc)
goto out;
- QETH_DBF_MESSAGE(2, "READ_MAC Assist failed on device %s: x%x\n",
- CARD_BUS_ID(card), rc);
+ QETH_DBF_MESSAGE(2, "READ_MAC Assist failed on device %x: %#x\n",
+ CARD_DEVID(card), rc);
QETH_DBF_TEXT_(SETUP, 2, "1err%04x", rc);
/* fall back once more: */
}
@@ -641,84 +651,43 @@ static void qeth_l2_set_rx_mode(struct net_device *dev)
qeth_promisc_to_bridge(card);
}
-static int qeth_l2_xmit(struct qeth_card *card, struct sk_buff *skb,
- struct qeth_qdio_out_q *queue, int cast_type, int ipv)
+static int qeth_l2_xmit_osn(struct qeth_card *card, struct sk_buff *skb,
+ struct qeth_qdio_out_q *queue)
{
- const unsigned int proto_len = IS_IQD(card) ? ETH_HLEN : 0;
- const unsigned int hw_hdr_len = sizeof(struct qeth_hdr);
- unsigned int frame_len = skb->len;
- unsigned int data_offset = 0;
- struct qeth_hdr *hdr = NULL;
+ struct qeth_hdr *hdr = (struct qeth_hdr *)skb->data;
+ addr_t end = (addr_t)(skb->data + sizeof(*hdr));
+ addr_t start = (addr_t)skb->data;
+ unsigned int elements = 0;
unsigned int hd_len = 0;
- unsigned int elements;
- int push_len, rc;
- bool is_sg;
+ int rc;
- rc = skb_cow_head(skb, hw_hdr_len);
- if (rc)
- return rc;
+ if (skb->protocol == htons(ETH_P_IPV6))
+ return -EPROTONOSUPPORT;
- push_len = qeth_add_hw_header(card, skb, &hdr, hw_hdr_len, proto_len,
- &elements);
- if (push_len < 0)
- return push_len;
- if (!push_len) {
- /* HW header needs its own buffer element. */
- hd_len = hw_hdr_len + proto_len;
- data_offset = proto_len;
- }
- qeth_l2_fill_header(hdr, skb, cast_type, frame_len);
- if (skb->ip_summed == CHECKSUM_PARTIAL) {
- qeth_tx_csum(skb, &hdr->hdr.l2.flags[1], ipv);
- if (card->options.performance_stats)
- card->perf_stats.tx_csum++;
+ if (qeth_get_elements_for_range(start, end) > 1) {
+ /* Misaligned HW header, move it to its own buffer element. */
+ hdr = kmem_cache_alloc(qeth_core_header_cache, GFP_ATOMIC);
+ if (!hdr)
+ return -ENOMEM;
+ hd_len = sizeof(*hdr);
+ skb_copy_from_linear_data(skb, (char *)hdr, hd_len);
+ elements++;
}
- is_sg = skb_is_nonlinear(skb);
- if (IS_IQD(card)) {
- rc = qeth_do_send_packet_fast(queue, skb, hdr, data_offset,
- hd_len);
- } else {
- /* TODO: drop skb_orphan() once TX completion is fast enough */
- skb_orphan(skb);
- rc = qeth_do_send_packet(card, queue, skb, hdr, data_offset,
- hd_len, elements);
+ elements += qeth_count_elements(skb, hd_len);
+ if (elements > QETH_MAX_BUFFER_ELEMENTS(card)) {
+ rc = -E2BIG;
+ goto out;
}
- if (!rc) {
- if (card->options.performance_stats) {
- card->perf_stats.buf_elements_sent += elements;
- if (is_sg)
- card->perf_stats.sg_skbs_sent++;
- }
- } else {
- if (!push_len)
- kmem_cache_free(qeth_core_header_cache, hdr);
- if (rc == -EBUSY)
- /* roll back to ETH header */
- skb_pull(skb, push_len);
- }
+ rc = qeth_do_send_packet(card, queue, skb, hdr, hd_len, hd_len,
+ elements);
+out:
+ if (rc && hd_len)
+ kmem_cache_free(qeth_core_header_cache, hdr);
return rc;
}
-static int qeth_l2_xmit_osn(struct qeth_card *card, struct sk_buff *skb,
- struct qeth_qdio_out_q *queue)
-{
- unsigned int elements;
- struct qeth_hdr *hdr;
-
- if (skb->protocol == htons(ETH_P_IPV6))
- return -EPROTONOSUPPORT;
-
- hdr = (struct qeth_hdr *)skb->data;
- elements = qeth_get_elements_no(card, skb, 0, 0);
- if (!elements)
- return -E2BIG;
- if (qeth_hdr_chk_and_bounce(skb, &hdr, sizeof(*hdr)))
- return -EINVAL;
- return qeth_do_send_packet(card, queue, skb, hdr, 0, 0, elements);
-}
-
static netdev_tx_t qeth_l2_hard_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
@@ -729,7 +698,7 @@ static netdev_tx_t qeth_l2_hard_start_xmit(struct sk_buff *skb,
int tx_bytes = skb->len;
int rc;
- if ((card->state != CARD_STATE_UP) || !card->lan_online) {
+ if (card->state != CARD_STATE_UP) {
card->stats.tx_carrier_errors++;
goto tx_drop;
}
@@ -745,7 +714,8 @@ static netdev_tx_t qeth_l2_hard_start_xmit(struct sk_buff *skb,
if (IS_OSN(card))
rc = qeth_l2_xmit_osn(card, skb, queue);
else
- rc = qeth_l2_xmit(card, skb, queue, cast_type, ipv);
+ rc = qeth_xmit(card, skb, queue, ipv, cast_type,
+ qeth_l2_fill_header);
if (!rc) {
card->stats.tx_packets++;
@@ -789,7 +759,10 @@ static int __qeth_l2_open(struct net_device *dev)
if (qdio_stop_irq(card->data.ccwdev, 0) >= 0) {
napi_enable(&card->napi);
+ local_bh_disable();
napi_schedule(&card->napi);
+ /* kick-start the NAPI softirq: */
+ local_bh_enable();
} else
rc = -EIO;
return rc;
@@ -837,7 +810,6 @@ static int qeth_l2_probe_device(struct ccwgroup_device *gdev)
}
INIT_LIST_HEAD(&card->vid_list);
hash_init(card->mac_htable);
- card->options.layer2 = 1;
card->info.hwtrap = 0;
qeth_l2_vnicc_set_defaults(card);
return 0;
@@ -854,7 +826,8 @@ static void qeth_l2_remove_device(struct ccwgroup_device *cgdev)
if (cgdev->state == CCWGROUP_ONLINE)
qeth_l2_set_offline(cgdev);
- unregister_netdev(card->dev);
+ if (qeth_netdev_is_registered(card->dev))
+ unregister_netdev(card->dev);
}
static const struct ethtool_ops qeth_l2_ethtool_ops = {
@@ -890,11 +863,11 @@ static const struct net_device_ops qeth_l2_netdev_ops = {
.ndo_set_features = qeth_set_features
};
-static int qeth_l2_setup_netdev(struct qeth_card *card)
+static int qeth_l2_setup_netdev(struct qeth_card *card, bool carrier_ok)
{
int rc;
- if (card->dev->netdev_ops)
+ if (qeth_netdev_is_registered(card->dev))
return 0;
card->dev->priv_flags |= IFF_UNICAST_FLT;
@@ -929,10 +902,27 @@ static int qeth_l2_setup_netdev(struct qeth_card *card)
card->dev->hw_features |= NETIF_F_RXCSUM;
card->dev->vlan_features |= NETIF_F_RXCSUM;
}
+ if (qeth_is_supported(card, IPA_OUTBOUND_TSO)) {
+ card->dev->hw_features |= NETIF_F_TSO;
+ card->dev->vlan_features |= NETIF_F_TSO;
+ }
+ if (qeth_is_supported6(card, IPA_OUTBOUND_TSO)) {
+ card->dev->hw_features |= NETIF_F_TSO6;
+ card->dev->vlan_features |= NETIF_F_TSO6;
+ }
+
+ if (card->dev->hw_features & (NETIF_F_TSO | NETIF_F_TSO6)) {
+ card->dev->needed_headroom = sizeof(struct qeth_hdr_tso);
+ netif_set_gso_max_size(card->dev,
+ PAGE_SIZE * (QDIO_MAX_ELEMENTS_PER_BUFFER - 1));
+ }
qeth_l2_request_initial_mac(card);
netif_napi_add(card->dev, &card->napi, qeth_poll, QETH_NAPI_WEIGHT);
rc = register_netdev(card->dev);
+ if (!rc && carrier_ok)
+ netif_carrier_on(card->dev);
+
if (rc)
card->dev->netdev_ops = NULL;
return rc;
@@ -963,6 +953,7 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
struct qeth_card *card = dev_get_drvdata(&gdev->dev);
int rc = 0;
enum qeth_card_states recover_flag;
+ bool carrier_ok;
mutex_lock(&card->discipline_mutex);
mutex_lock(&card->conf_mutex);
@@ -970,7 +961,7 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
recover_flag = card->state;
- rc = qeth_core_hardsetup_card(card);
+ rc = qeth_core_hardsetup_card(card, &carrier_ok);
if (rc) {
QETH_DBF_TEXT_(SETUP, 2, "2err%04x", rc);
rc = -ENODEV;
@@ -981,7 +972,7 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
dev_info(&card->gdev->dev,
"The device represents a Bridge Capable Port\n");
- rc = qeth_l2_setup_netdev(card);
+ rc = qeth_l2_setup_netdev(card, carrier_ok);
if (rc)
goto out_remove;
@@ -1029,10 +1020,6 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
goto out_remove;
}
card->state = CARD_STATE_SOFTSETUP;
- if (card->lan_online)
- netif_carrier_on(card->dev);
- else
- netif_carrier_off(card->dev);
qeth_set_allowed_threads(card, 0xffffffff, 0);
@@ -1178,9 +1165,6 @@ static int qeth_l2_pm_resume(struct ccwgroup_device *gdev)
struct qeth_card *card = dev_get_drvdata(&gdev->dev);
int rc = 0;
- if (gdev->state == CCWGROUP_OFFLINE)
- goto out;
-
if (card->state == CARD_STATE_RECOVER) {
rc = __qeth_l2_set_online(card->gdev, 1);
if (rc) {
@@ -1190,7 +1174,7 @@ static int qeth_l2_pm_resume(struct ccwgroup_device *gdev)
}
} else
rc = __qeth_l2_set_online(card->gdev, 0);
-out:
+
qeth_set_allowed_threads(card, 0xffffffff, 0);
netif_device_attach(card->dev);
if (rc)
@@ -1240,7 +1224,6 @@ static int qeth_osn_send_control_data(struct qeth_card *card, int len,
struct qeth_cmd_buffer *iob)
{
struct qeth_channel *channel = iob->channel;
- unsigned long flags;
int rc = 0;
QETH_CARD_TEXT(card, 5, "osndctrd");
@@ -1249,10 +1232,10 @@ static int qeth_osn_send_control_data(struct qeth_card *card, int len,
atomic_cmpxchg(&channel->irq_pending, 0, 1) == 0);
qeth_prepare_control_data(card, len, iob);
QETH_CARD_TEXT(card, 6, "osnoirqp");
- spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
+ spin_lock_irq(get_ccwdev_lock(channel->ccwdev));
rc = ccw_device_start_timeout(channel->ccwdev, channel->ccw,
(addr_t) iob, 0, 0, QETH_IPA_TIMEOUT);
- spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
+ spin_unlock_irq(get_ccwdev_lock(channel->ccwdev));
if (rc) {
QETH_DBF_MESSAGE(2, "qeth_osn_send_control_data: "
"ccw_device_start rc = %i\n", rc);
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index ada258c01a08..f08b745c2007 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -33,7 +33,6 @@
#include <net/ipv6.h>
#include <net/ip6_route.h>
#include <net/ip6_fib.h>
-#include <net/ip6_checksum.h>
#include <net/iucv/af_iucv.h>
#include <linux/hashtable.h>
@@ -279,9 +278,6 @@ static void qeth_l3_clear_ip_htable(struct qeth_card *card, int recover)
QETH_CARD_TEXT(card, 4, "clearip");
- if (recover && card->options.sniffer)
- return;
-
spin_lock_bh(&card->ip_lock);
hash_for_each_safe(card->ip_htable, i, tmp, addr, hnode) {
@@ -495,9 +491,8 @@ int qeth_l3_setrouting_v4(struct qeth_card *card)
QETH_PROT_IPV4);
if (rc) {
card->options.route4.type = NO_ROUTER;
- QETH_DBF_MESSAGE(2, "Error (0x%04x) while setting routing type"
- " on %s. Type set to 'no router'.\n", rc,
- QETH_CARD_IFNAME(card));
+ QETH_DBF_MESSAGE(2, "Error (%#06x) while setting routing type on device %x. Type set to 'no router'.\n",
+ rc, CARD_DEVID(card));
}
return rc;
}
@@ -519,9 +514,8 @@ int qeth_l3_setrouting_v6(struct qeth_card *card)
QETH_PROT_IPV6);
if (rc) {
card->options.route6.type = NO_ROUTER;
- QETH_DBF_MESSAGE(2, "Error (0x%04x) while setting routing type"
- " on %s. Type set to 'no router'.\n", rc,
- QETH_CARD_IFNAME(card));
+ QETH_DBF_MESSAGE(2, "Error (%#06x) while setting routing type on device %x. Type set to 'no router'.\n",
+ rc, CARD_DEVID(card));
}
return rc;
}
@@ -664,6 +658,8 @@ static int qeth_l3_register_addr_entry(struct qeth_card *card,
int rc = 0;
int cnt = 3;
+ if (card->options.sniffer)
+ return 0;
if (addr->proto == QETH_PROT_IPV4) {
QETH_CARD_TEXT(card, 2, "setaddr4");
@@ -698,6 +694,9 @@ static int qeth_l3_deregister_addr_entry(struct qeth_card *card,
{
int rc = 0;
+ if (card->options.sniffer)
+ return 0;
+
if (addr->proto == QETH_PROT_IPV4) {
QETH_CARD_TEXT(card, 2, "deladdr4");
QETH_CARD_HEX(card, 3, &addr->u.a4.addr, sizeof(int));
@@ -1071,8 +1070,8 @@ qeth_diags_trace_cb(struct qeth_card *card, struct qeth_reply *reply,
}
break;
default:
- QETH_DBF_MESSAGE(2, "Unknown sniffer action (0x%04x) on %s\n",
- cmd->data.diagass.action, QETH_CARD_IFNAME(card));
+ QETH_DBF_MESSAGE(2, "Unknown sniffer action (%#06x) on device %x\n",
+ cmd->data.diagass.action, CARD_DEVID(card));
}
return 0;
@@ -1349,6 +1348,7 @@ static void qeth_l3_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
static int qeth_l3_process_inbound_buffer(struct qeth_card *card,
int budget, int *done)
{
+ struct net_device *dev = card->dev;
int work_done = 0;
struct sk_buff *skb;
struct qeth_hdr *hdr;
@@ -1370,11 +1370,10 @@ static int qeth_l3_process_inbound_buffer(struct qeth_card *card,
magic = *(__u16 *)skb->data;
if ((card->info.type == QETH_CARD_TYPE_IQD) &&
(magic == ETH_P_AF_IUCV)) {
- skb->protocol = cpu_to_be16(ETH_P_AF_IUCV);
len = skb->len;
- card->dev->header_ops->create(skb, card->dev, 0,
- card->dev->dev_addr, "FAKELL", len);
- skb_reset_mac_header(skb);
+ dev_hard_header(skb, dev, ETH_P_AF_IUCV,
+ dev->dev_addr, "FAKELL", len);
+ skb->protocol = eth_type_trans(skb, dev);
netif_receive_skb(skb);
} else {
qeth_l3_rebuild_skb(card, skb, hdr);
@@ -1518,32 +1517,25 @@ static void qeth_l3_set_rx_mode(struct net_device *dev)
qeth_l3_handle_promisc_mode(card);
}
-static const char *qeth_l3_arp_get_error_cause(int *rc)
+static int qeth_l3_arp_makerc(int rc)
{
- switch (*rc) {
- case QETH_IPA_ARP_RC_FAILED:
- *rc = -EIO;
- return "operation failed";
+ switch (rc) {
+ case IPA_RC_SUCCESS:
+ return 0;
case QETH_IPA_ARP_RC_NOTSUPP:
- *rc = -EOPNOTSUPP;
- return "operation not supported";
- case QETH_IPA_ARP_RC_OUT_OF_RANGE:
- *rc = -EINVAL;
- return "argument out of range";
case QETH_IPA_ARP_RC_Q_NOTSUPP:
- *rc = -EOPNOTSUPP;
- return "query operation not supported";
+ return -EOPNOTSUPP;
+ case QETH_IPA_ARP_RC_OUT_OF_RANGE:
+ return -EINVAL;
case QETH_IPA_ARP_RC_Q_NO_DATA:
- *rc = -ENOENT;
- return "no query data available";
+ return -ENOENT;
default:
- return "unknown error";
+ return -EIO;
}
}
static int qeth_l3_arp_set_no_entries(struct qeth_card *card, int no_entries)
{
- int tmp;
int rc;
QETH_CARD_TEXT(card, 3, "arpstnoe");
@@ -1561,13 +1553,10 @@ static int qeth_l3_arp_set_no_entries(struct qeth_card *card, int no_entries)
rc = qeth_send_simple_setassparms(card, IPA_ARP_PROCESSING,
IPA_CMD_ASS_ARP_SET_NO_ENTRIES,
no_entries);
- if (rc) {
- tmp = rc;
- QETH_DBF_MESSAGE(2, "Could not set number of ARP entries on "
- "%s: %s (0x%x/%d)\n", QETH_CARD_IFNAME(card),
- qeth_l3_arp_get_error_cause(&rc), tmp, tmp);
- }
- return rc;
+ if (rc)
+ QETH_DBF_MESSAGE(2, "Could not set number of ARP entries on device %x: %#x\n",
+ CARD_DEVID(card), rc);
+ return qeth_l3_arp_makerc(rc);
}
static __u32 get_arp_entry_size(struct qeth_card *card,
@@ -1717,7 +1706,6 @@ static int qeth_l3_query_arp_cache_info(struct qeth_card *card,
{
struct qeth_cmd_buffer *iob;
struct qeth_ipa_cmd *cmd;
- int tmp;
int rc;
QETH_CARD_TEXT_(card, 3, "qarpipv%i", prot);
@@ -1736,15 +1724,10 @@ static int qeth_l3_query_arp_cache_info(struct qeth_card *card,
rc = qeth_l3_send_ipa_arp_cmd(card, iob,
QETH_SETASS_BASE_LEN+QETH_ARP_CMD_LEN,
qeth_l3_arp_query_cb, (void *)qinfo);
- if (rc) {
- tmp = rc;
- QETH_DBF_MESSAGE(2,
- "Error while querying ARP cache on %s: %s "
- "(0x%x/%d)\n", QETH_CARD_IFNAME(card),
- qeth_l3_arp_get_error_cause(&rc), tmp, tmp);
- }
-
- return rc;
+ if (rc)
+ QETH_DBF_MESSAGE(2, "Error while querying ARP cache on device %x: %#x\n",
+ CARD_DEVID(card), rc);
+ return qeth_l3_arp_makerc(rc);
}
static int qeth_l3_arp_query(struct qeth_card *card, char __user *udata)
@@ -1794,15 +1777,18 @@ out:
return rc;
}
-static int qeth_l3_arp_add_entry(struct qeth_card *card,
- struct qeth_arp_cache_entry *entry)
+static int qeth_l3_arp_modify_entry(struct qeth_card *card,
+ struct qeth_arp_cache_entry *entry,
+ enum qeth_arp_process_subcmds arp_cmd)
{
+ struct qeth_arp_cache_entry *cmd_entry;
struct qeth_cmd_buffer *iob;
- char buf[16];
- int tmp;
int rc;
- QETH_CARD_TEXT(card, 3, "arpadent");
+ if (arp_cmd == IPA_CMD_ASS_ARP_ADD_ENTRY)
+ QETH_CARD_TEXT(card, 3, "arpadd");
+ else
+ QETH_CARD_TEXT(card, 3, "arpdel");
/*
* currently GuestLAN only supports the ARP assist function
@@ -1815,71 +1801,25 @@ static int qeth_l3_arp_add_entry(struct qeth_card *card,
return -EOPNOTSUPP;
}
- iob = qeth_get_setassparms_cmd(card, IPA_ARP_PROCESSING,
- IPA_CMD_ASS_ARP_ADD_ENTRY,
- sizeof(struct qeth_arp_cache_entry),
- QETH_PROT_IPV4);
+ iob = qeth_get_setassparms_cmd(card, IPA_ARP_PROCESSING, arp_cmd,
+ sizeof(*cmd_entry), QETH_PROT_IPV4);
if (!iob)
return -ENOMEM;
- rc = qeth_send_setassparms(card, iob,
- sizeof(struct qeth_arp_cache_entry),
- (unsigned long) entry,
- qeth_setassparms_cb, NULL);
- if (rc) {
- tmp = rc;
- qeth_l3_ipaddr4_to_string((u8 *)entry->ipaddr, buf);
- QETH_DBF_MESSAGE(2, "Could not add ARP entry for address %s "
- "on %s: %s (0x%x/%d)\n", buf, QETH_CARD_IFNAME(card),
- qeth_l3_arp_get_error_cause(&rc), tmp, tmp);
- }
- return rc;
-}
-
-static int qeth_l3_arp_remove_entry(struct qeth_card *card,
- struct qeth_arp_cache_entry *entry)
-{
- struct qeth_cmd_buffer *iob;
- char buf[16] = {0, };
- int tmp;
- int rc;
- QETH_CARD_TEXT(card, 3, "arprment");
+ cmd_entry = &__ipa_cmd(iob)->data.setassparms.data.arp_entry;
+ ether_addr_copy(cmd_entry->macaddr, entry->macaddr);
+ memcpy(cmd_entry->ipaddr, entry->ipaddr, 4);
+ rc = qeth_send_ipa_cmd(card, iob, qeth_setassparms_cb, NULL);
+ if (rc)
+ QETH_DBF_MESSAGE(2, "Could not modify (cmd: %#x) ARP entry on device %x: %#x\n",
+ arp_cmd, CARD_DEVID(card), rc);
- /*
- * currently GuestLAN only supports the ARP assist function
- * IPA_CMD_ASS_ARP_QUERY_INFO, but not IPA_CMD_ASS_ARP_REMOVE_ENTRY;
- * thus we say EOPNOTSUPP for this ARP function
- */
- if (card->info.guestlan)
- return -EOPNOTSUPP;
- if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) {
- return -EOPNOTSUPP;
- }
- memcpy(buf, entry, 12);
- iob = qeth_get_setassparms_cmd(card, IPA_ARP_PROCESSING,
- IPA_CMD_ASS_ARP_REMOVE_ENTRY,
- 12,
- QETH_PROT_IPV4);
- if (!iob)
- return -ENOMEM;
- rc = qeth_send_setassparms(card, iob,
- 12, (unsigned long)buf,
- qeth_setassparms_cb, NULL);
- if (rc) {
- tmp = rc;
- memset(buf, 0, 16);
- qeth_l3_ipaddr4_to_string((u8 *)entry->ipaddr, buf);
- QETH_DBF_MESSAGE(2, "Could not delete ARP entry for address %s"
- " on %s: %s (0x%x/%d)\n", buf, QETH_CARD_IFNAME(card),
- qeth_l3_arp_get_error_cause(&rc), tmp, tmp);
- }
- return rc;
+ return qeth_l3_arp_makerc(rc);
}
static int qeth_l3_arp_flush_cache(struct qeth_card *card)
{
int rc;
- int tmp;
QETH_CARD_TEXT(card, 3, "arpflush");
@@ -1895,19 +1835,17 @@ static int qeth_l3_arp_flush_cache(struct qeth_card *card)
}
rc = qeth_send_simple_setassparms(card, IPA_ARP_PROCESSING,
IPA_CMD_ASS_ARP_FLUSH_CACHE, 0);
- if (rc) {
- tmp = rc;
- QETH_DBF_MESSAGE(2, "Could not flush ARP cache on %s: %s "
- "(0x%x/%d)\n", QETH_CARD_IFNAME(card),
- qeth_l3_arp_get_error_cause(&rc), tmp, tmp);
- }
- return rc;
+ if (rc)
+ QETH_DBF_MESSAGE(2, "Could not flush ARP cache on device %x: %#x\n",
+ CARD_DEVID(card), rc);
+ return qeth_l3_arp_makerc(rc);
}
static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
struct qeth_card *card = dev->ml_priv;
struct qeth_arp_cache_entry arp_entry;
+ enum qeth_arp_process_subcmds arp_cmd;
int rc = 0;
switch (cmd) {
@@ -1926,27 +1864,16 @@ static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
rc = qeth_l3_arp_query(card, rq->ifr_ifru.ifru_data);
break;
case SIOC_QETH_ARP_ADD_ENTRY:
- if (!capable(CAP_NET_ADMIN)) {
- rc = -EPERM;
- break;
- }
- if (copy_from_user(&arp_entry, rq->ifr_ifru.ifru_data,
- sizeof(struct qeth_arp_cache_entry)))
- rc = -EFAULT;
- else
- rc = qeth_l3_arp_add_entry(card, &arp_entry);
- break;
case SIOC_QETH_ARP_REMOVE_ENTRY:
- if (!capable(CAP_NET_ADMIN)) {
- rc = -EPERM;
- break;
- }
- if (copy_from_user(&arp_entry, rq->ifr_ifru.ifru_data,
- sizeof(struct qeth_arp_cache_entry)))
- rc = -EFAULT;
- else
- rc = qeth_l3_arp_remove_entry(card, &arp_entry);
- break;
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (copy_from_user(&arp_entry, rq->ifr_data, sizeof(arp_entry)))
+ return -EFAULT;
+
+ arp_cmd = (cmd == SIOC_QETH_ARP_ADD_ENTRY) ?
+ IPA_CMD_ASS_ARP_ADD_ENTRY :
+ IPA_CMD_ASS_ARP_REMOVE_ENTRY;
+ return qeth_l3_arp_modify_entry(card, &arp_entry, arp_cmd);
case SIOC_QETH_ARP_FLUSH_CACHE:
if (!capable(CAP_NET_ADMIN)) {
rc = -EPERM;
@@ -1983,39 +1910,38 @@ static int qeth_l3_get_cast_type(struct sk_buff *skb)
rcu_read_unlock();
/* no neighbour (eg AF_PACKET), fall back to target's IP address ... */
- if (be16_to_cpu(skb->protocol) == ETH_P_IPV6)
- return ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) ?
- RTN_MULTICAST : RTN_UNICAST;
- else if (be16_to_cpu(skb->protocol) == ETH_P_IP)
+ switch (qeth_get_ip_version(skb)) {
+ case 4:
return ipv4_is_multicast(ip_hdr(skb)->daddr) ?
RTN_MULTICAST : RTN_UNICAST;
-
- /* ... and MAC address */
- if (ether_addr_equal_64bits(eth_hdr(skb)->h_dest, skb->dev->broadcast))
- return RTN_BROADCAST;
- if (is_multicast_ether_addr(eth_hdr(skb)->h_dest))
- return RTN_MULTICAST;
-
- /* default to unicast */
- return RTN_UNICAST;
+ case 6:
+ return ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) ?
+ RTN_MULTICAST : RTN_UNICAST;
+ default:
+ /* ... and MAC address */
+ if (ether_addr_equal_64bits(eth_hdr(skb)->h_dest,
+ skb->dev->broadcast))
+ return RTN_BROADCAST;
+ if (is_multicast_ether_addr(eth_hdr(skb)->h_dest))
+ return RTN_MULTICAST;
+ /* default to unicast */
+ return RTN_UNICAST;
+ }
}
static void qeth_l3_fill_af_iucv_hdr(struct qeth_hdr *hdr, struct sk_buff *skb,
unsigned int data_len)
{
char daddr[16];
- struct af_iucv_trans_hdr *iucv_hdr;
- memset(hdr, 0, sizeof(struct qeth_hdr));
hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3;
hdr->hdr.l3.length = data_len;
hdr->hdr.l3.flags = QETH_HDR_IPV6 | QETH_CAST_UNICAST;
- iucv_hdr = (struct af_iucv_trans_hdr *)(skb_mac_header(skb) + ETH_HLEN);
memset(daddr, 0, sizeof(daddr));
daddr[0] = 0xfe;
daddr[1] = 0x80;
- memcpy(&daddr[8], iucv_hdr->destUserID, 8);
+ memcpy(&daddr[8], iucv_trans_hdr(skb)->destUserID, 8);
memcpy(hdr->hdr.l3.next_hop.ipv6_addr, daddr, 16);
}
@@ -2034,26 +1960,33 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
struct sk_buff *skb, int ipv, int cast_type,
unsigned int data_len)
{
- memset(hdr, 0, sizeof(struct qeth_hdr));
- hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3;
+ struct vlan_ethhdr *veth = vlan_eth_hdr(skb);
+
hdr->hdr.l3.length = data_len;
- /*
- * before we're going to overwrite this location with next hop ip.
- * v6 uses passthrough, v4 sets the tag in the QDIO header.
- */
- if (skb_vlan_tag_present(skb)) {
- if ((ipv == 4) || (card->info.type == QETH_CARD_TYPE_IQD))
- hdr->hdr.l3.ext_flags = QETH_HDR_EXT_VLAN_FRAME;
- else
- hdr->hdr.l3.ext_flags = QETH_HDR_EXT_INCLUDE_VLAN_TAG;
- hdr->hdr.l3.vlan_id = skb_vlan_tag_get(skb);
+ if (skb_is_gso(skb)) {
+ hdr->hdr.l3.id = QETH_HEADER_TYPE_L3_TSO;
+ } else {
+ hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3;
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ qeth_tx_csum(skb, &hdr->hdr.l3.ext_flags, ipv);
+ /* some HW requires combined L3+L4 csum offload: */
+ if (ipv == 4)
+ hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_CSUM_HDR_REQ;
+ if (card->options.performance_stats)
+ card->perf_stats.tx_csum++;
+ }
}
- if (!skb_is_gso(skb) && skb->ip_summed == CHECKSUM_PARTIAL) {
- qeth_tx_csum(skb, &hdr->hdr.l3.ext_flags, ipv);
- if (card->options.performance_stats)
- card->perf_stats.tx_csum++;
+ if (ipv == 4 || IS_IQD(card)) {
+ /* NETIF_F_HW_VLAN_CTAG_TX */
+ if (skb_vlan_tag_present(skb)) {
+ hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_VLAN_FRAME;
+ hdr->hdr.l3.vlan_id = skb_vlan_tag_get(skb);
+ }
+ } else if (veth->h_vlan_proto == htons(ETH_P_8021Q)) {
+ hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_INCLUDE_VLAN_TAG;
+ hdr->hdr.l3.vlan_id = ntohs(veth->h_vlan_TCI);
}
/* OSA only: */
@@ -2094,85 +2027,41 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
rcu_read_unlock();
}
-static void qeth_tso_fill_header(struct qeth_card *card,
- struct qeth_hdr *qhdr, struct sk_buff *skb)
+static void qeth_l3_fixup_headers(struct sk_buff *skb)
{
- struct qeth_hdr_tso *hdr = (struct qeth_hdr_tso *)qhdr;
- struct tcphdr *tcph = tcp_hdr(skb);
struct iphdr *iph = ip_hdr(skb);
- struct ipv6hdr *ip6h = ipv6_hdr(skb);
-
- /*fix header to TSO values ...*/
- hdr->hdr.hdr.l3.id = QETH_HEADER_TYPE_TSO;
- /*set values which are fix for the first approach ...*/
- hdr->ext.hdr_tot_len = (__u16) sizeof(struct qeth_hdr_ext_tso);
- hdr->ext.imb_hdr_no = 1;
- hdr->ext.hdr_type = 1;
- hdr->ext.hdr_version = 1;
- hdr->ext.hdr_len = 28;
- /*insert non-fix values */
- hdr->ext.mss = skb_shinfo(skb)->gso_size;
- hdr->ext.dg_hdr_len = (__u16)(ip_hdrlen(skb) + tcp_hdrlen(skb));
- hdr->ext.payload_len = (__u16)(skb->len - hdr->ext.dg_hdr_len -
- sizeof(struct qeth_hdr_tso));
- tcph->check = 0;
- if (be16_to_cpu(skb->protocol) == ETH_P_IPV6) {
- ip6h->payload_len = 0;
- tcph->check = ~csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
- 0, IPPROTO_TCP, 0);
- } else {
- /*OSA want us to set these values ...*/
- tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
- 0, IPPROTO_TCP, 0);
- iph->tot_len = 0;
- iph->check = 0;
- }
-}
-
-/**
- * qeth_l3_get_elements_no_tso() - find number of SBALEs for skb data for tso
- * @card: qeth card structure, to check max. elems.
- * @skb: SKB address
- * @extra_elems: extra elems needed, to check against max.
- *
- * Returns the number of pages, and thus QDIO buffer elements, needed to cover
- * skb data, including linear part and fragments, but excluding TCP header.
- * (Exclusion of TCP header distinguishes it from qeth_get_elements_no().)
- * Checks if the result plus extra_elems fits under the limit for the card.
- * Returns 0 if it does not.
- * Note: extra_elems is not included in the returned result.
- */
-static int qeth_l3_get_elements_no_tso(struct qeth_card *card,
- struct sk_buff *skb, int extra_elems)
-{
- addr_t start = (addr_t)tcp_hdr(skb) + tcp_hdrlen(skb);
- addr_t end = (addr_t)skb->data + skb_headlen(skb);
- int elements = qeth_get_elements_for_frags(skb);
-
- if (start != end)
- elements += qeth_get_elements_for_range(start, end);
- if ((elements + extra_elems) > QETH_MAX_BUFFER_ELEMENTS(card)) {
- QETH_DBF_MESSAGE(2,
- "Invalid size of TSO IP packet (Number=%d / Length=%d). Discarded.\n",
- elements + extra_elems, skb->len);
- return 0;
+ /* this is safe, IPv6 traffic takes a different path */
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ iph->check = 0;
+ if (skb_is_gso(skb)) {
+ iph->tot_len = 0;
+ tcp_hdr(skb)->check = ~tcp_v4_check(0, iph->saddr,
+ iph->daddr, 0);
}
- return elements;
}
-static int qeth_l3_xmit_offload(struct qeth_card *card, struct sk_buff *skb,
- struct qeth_qdio_out_q *queue, int ipv,
- int cast_type)
+static int qeth_l3_xmit(struct qeth_card *card, struct sk_buff *skb,
+ struct qeth_qdio_out_q *queue, int ipv, int cast_type)
{
- const unsigned int hw_hdr_len = sizeof(struct qeth_hdr);
- unsigned int frame_len, elements;
+ unsigned int hw_hdr_len, proto_len, frame_len, elements;
unsigned char eth_hdr[ETH_HLEN];
+ bool is_tso = skb_is_gso(skb);
+ unsigned int data_offset = 0;
struct qeth_hdr *hdr = NULL;
unsigned int hd_len = 0;
int push_len, rc;
bool is_sg;
+ if (is_tso) {
+ hw_hdr_len = sizeof(struct qeth_hdr_tso);
+ proto_len = skb_transport_offset(skb) + tcp_hdrlen(skb) -
+ ETH_HLEN;
+ } else {
+ hw_hdr_len = sizeof(struct qeth_hdr);
+ proto_len = 0;
+ }
+
/* re-use the L2 header area for the HW header: */
rc = skb_cow_head(skb, hw_hdr_len - ETH_HLEN);
if (rc)
@@ -2181,28 +2070,37 @@ static int qeth_l3_xmit_offload(struct qeth_card *card, struct sk_buff *skb,
skb_pull(skb, ETH_HLEN);
frame_len = skb->len;
- push_len = qeth_add_hw_header(card, skb, &hdr, hw_hdr_len, 0,
+ qeth_l3_fixup_headers(skb);
+ push_len = qeth_add_hw_header(card, skb, &hdr, hw_hdr_len, proto_len,
&elements);
if (push_len < 0)
return push_len;
- if (!push_len) {
- /* hdr was added discontiguous from skb->data */
- hd_len = hw_hdr_len;
+ if (is_tso || !push_len) {
+ /* HW header needs its own buffer element. */
+ hd_len = hw_hdr_len + proto_len;
+ data_offset = push_len + proto_len;
}
+ memset(hdr, 0, hw_hdr_len);
- if (skb->protocol == htons(ETH_P_AF_IUCV))
+ if (skb->protocol == htons(ETH_P_AF_IUCV)) {
qeth_l3_fill_af_iucv_hdr(hdr, skb, frame_len);
- else
+ } else {
qeth_l3_fill_header(card, hdr, skb, ipv, cast_type, frame_len);
+ if (is_tso)
+ qeth_fill_tso_ext((struct qeth_hdr_tso *) hdr,
+ frame_len - proto_len, skb,
+ proto_len);
+ }
is_sg = skb_is_nonlinear(skb);
if (IS_IQD(card)) {
- rc = qeth_do_send_packet_fast(queue, skb, hdr, 0, hd_len);
+ rc = qeth_do_send_packet_fast(queue, skb, hdr, data_offset,
+ hd_len);
} else {
/* TODO: drop skb_orphan() once TX completion is fast enough */
skb_orphan(skb);
- rc = qeth_do_send_packet(card, queue, skb, hdr, 0, hd_len,
- elements);
+ rc = qeth_do_send_packet(card, queue, skb, hdr, data_offset,
+ hd_len, elements);
}
if (!rc) {
@@ -2210,6 +2108,10 @@ static int qeth_l3_xmit_offload(struct qeth_card *card, struct sk_buff *skb,
card->perf_stats.buf_elements_sent += elements;
if (is_sg)
card->perf_stats.sg_skbs_sent++;
+ if (is_tso) {
+ card->perf_stats.large_send_bytes += frame_len;
+ card->perf_stats.large_send_cnt++;
+ }
}
} else {
if (!push_len)
@@ -2224,118 +2126,6 @@ static int qeth_l3_xmit_offload(struct qeth_card *card, struct sk_buff *skb,
return rc;
}
-static int qeth_l3_xmit(struct qeth_card *card, struct sk_buff *skb,
- struct qeth_qdio_out_q *queue, int ipv, int cast_type)
-{
- int elements, len, rc;
- __be16 *tag;
- struct qeth_hdr *hdr = NULL;
- int hdr_elements = 0;
- struct sk_buff *new_skb = NULL;
- int tx_bytes = skb->len;
- unsigned int hd_len;
- bool use_tso, is_sg;
-
- /* Ignore segment size from skb_is_gso(), 1 page is always used. */
- use_tso = skb_is_gso(skb) &&
- (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4);
-
- /* create a clone with writeable headroom */
- new_skb = skb_realloc_headroom(skb, sizeof(struct qeth_hdr_tso) +
- VLAN_HLEN);
- if (!new_skb)
- return -ENOMEM;
-
- if (ipv == 4) {
- skb_pull(new_skb, ETH_HLEN);
- } else if (skb_vlan_tag_present(new_skb)) {
- skb_push(new_skb, VLAN_HLEN);
- skb_copy_to_linear_data(new_skb, new_skb->data + 4, 4);
- skb_copy_to_linear_data_offset(new_skb, 4,
- new_skb->data + 8, 4);
- skb_copy_to_linear_data_offset(new_skb, 8,
- new_skb->data + 12, 4);
- tag = (__be16 *)(new_skb->data + 12);
- *tag = cpu_to_be16(ETH_P_8021Q);
- *(tag + 1) = cpu_to_be16(skb_vlan_tag_get(new_skb));
- }
-
- /* fix hardware limitation: as long as we do not have sbal
- * chaining we can not send long frag lists
- */
- if ((use_tso && !qeth_l3_get_elements_no_tso(card, new_skb, 1)) ||
- (!use_tso && !qeth_get_elements_no(card, new_skb, 0, 0))) {
- rc = skb_linearize(new_skb);
-
- if (card->options.performance_stats) {
- if (rc)
- card->perf_stats.tx_linfail++;
- else
- card->perf_stats.tx_lin++;
- }
- if (rc)
- goto out;
- }
-
- if (use_tso) {
- hdr = skb_push(new_skb, sizeof(struct qeth_hdr_tso));
- memset(hdr, 0, sizeof(struct qeth_hdr_tso));
- qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type,
- new_skb->len - sizeof(struct qeth_hdr_tso));
- qeth_tso_fill_header(card, hdr, new_skb);
- hdr_elements++;
- } else {
- hdr = skb_push(new_skb, sizeof(struct qeth_hdr));
- qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type,
- new_skb->len - sizeof(struct qeth_hdr));
- }
-
- elements = use_tso ?
- qeth_l3_get_elements_no_tso(card, new_skb, hdr_elements) :
- qeth_get_elements_no(card, new_skb, hdr_elements, 0);
- if (!elements) {
- rc = -E2BIG;
- goto out;
- }
- elements += hdr_elements;
-
- if (use_tso) {
- hd_len = sizeof(struct qeth_hdr_tso) +
- ip_hdrlen(new_skb) + tcp_hdrlen(new_skb);
- len = hd_len;
- } else {
- hd_len = 0;
- len = sizeof(struct qeth_hdr_layer3);
- }
-
- if (qeth_hdr_chk_and_bounce(new_skb, &hdr, len)) {
- rc = -EINVAL;
- goto out;
- }
-
- is_sg = skb_is_nonlinear(new_skb);
- rc = qeth_do_send_packet(card, queue, new_skb, hdr, hd_len, hd_len,
- elements);
-out:
- if (!rc) {
- if (new_skb != skb)
- dev_kfree_skb_any(skb);
- if (card->options.performance_stats) {
- card->perf_stats.buf_elements_sent += elements;
- if (is_sg)
- card->perf_stats.sg_skbs_sent++;
- if (use_tso) {
- card->perf_stats.large_send_bytes += tx_bytes;
- card->perf_stats.large_send_cnt++;
- }
- }
- } else {
- if (new_skb != skb)
- dev_kfree_skb_any(new_skb);
- }
- return rc;
-}
-
static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
@@ -2355,7 +2145,7 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb,
goto tx_drop;
}
- if (card->state != CARD_STATE_UP || !card->lan_online) {
+ if (card->state != CARD_STATE_UP) {
card->stats.tx_carrier_errors++;
goto tx_drop;
}
@@ -2371,10 +2161,11 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb,
}
netif_stop_queue(dev);
- if (IS_IQD(card) || (!skb_is_gso(skb) && ipv == 4))
- rc = qeth_l3_xmit_offload(card, skb, queue, ipv, cast_type);
- else
+ if (ipv == 4 || IS_IQD(card))
rc = qeth_l3_xmit(card, skb, queue, ipv, cast_type);
+ else
+ rc = qeth_xmit(card, skb, queue, ipv, cast_type,
+ qeth_l3_fill_header);
if (!rc) {
card->stats.tx_packets++;
@@ -2412,7 +2203,10 @@ static int __qeth_l3_open(struct net_device *dev)
if (qdio_stop_irq(card->data.ccwdev, 0) >= 0) {
napi_enable(&card->napi);
+ local_bh_disable();
napi_schedule(&card->napi);
+ /* kick-start the NAPI softirq: */
+ local_bh_enable();
} else
rc = -EIO;
return rc;
@@ -2476,6 +2270,15 @@ qeth_l3_neigh_setup(struct net_device *dev, struct neigh_parms *np)
return 0;
}
+static netdev_features_t qeth_l3_osa_features_check(struct sk_buff *skb,
+ struct net_device *dev,
+ netdev_features_t features)
+{
+ if (qeth_get_ip_version(skb) != 4)
+ features &= ~NETIF_F_HW_VLAN_CTAG_TX;
+ return qeth_features_check(skb, dev, features);
+}
+
static const struct net_device_ops qeth_l3_netdev_ops = {
.ndo_open = qeth_l3_open,
.ndo_stop = qeth_l3_stop,
@@ -2496,7 +2299,7 @@ static const struct net_device_ops qeth_l3_osa_netdev_ops = {
.ndo_stop = qeth_l3_stop,
.ndo_get_stats = qeth_get_stats,
.ndo_start_xmit = qeth_l3_hard_start_xmit,
- .ndo_features_check = qeth_features_check,
+ .ndo_features_check = qeth_l3_osa_features_check,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_rx_mode = qeth_l3_set_rx_mode,
.ndo_do_ioctl = qeth_do_ioctl,
@@ -2508,11 +2311,12 @@ static const struct net_device_ops qeth_l3_osa_netdev_ops = {
.ndo_neigh_setup = qeth_l3_neigh_setup,
};
-static int qeth_l3_setup_netdev(struct qeth_card *card)
+static int qeth_l3_setup_netdev(struct qeth_card *card, bool carrier_ok)
{
+ unsigned int headroom;
int rc;
- if (card->dev->netdev_ops)
+ if (qeth_netdev_is_registered(card->dev))
return 0;
if (card->info.type == QETH_CARD_TYPE_OSD ||
@@ -2542,9 +2346,22 @@ static int qeth_l3_setup_netdev(struct qeth_card *card)
card->dev->hw_features |= NETIF_F_IPV6_CSUM;
card->dev->vlan_features |= NETIF_F_IPV6_CSUM;
}
+ if (qeth_is_supported6(card, IPA_OUTBOUND_TSO)) {
+ card->dev->hw_features |= NETIF_F_TSO6;
+ card->dev->vlan_features |= NETIF_F_TSO6;
+ }
+
+ /* allow for de-acceleration of NETIF_F_HW_VLAN_CTAG_TX: */
+ if (card->dev->hw_features & NETIF_F_TSO6)
+ headroom = sizeof(struct qeth_hdr_tso) + VLAN_HLEN;
+ else if (card->dev->hw_features & NETIF_F_TSO)
+ headroom = sizeof(struct qeth_hdr_tso);
+ else
+ headroom = sizeof(struct qeth_hdr) + VLAN_HLEN;
} else if (card->info.type == QETH_CARD_TYPE_IQD) {
card->dev->flags |= IFF_NOARP;
card->dev->netdev_ops = &qeth_l3_netdev_ops;
+ headroom = sizeof(struct qeth_hdr) - ETH_HLEN;
rc = qeth_l3_iqd_read_initial_mac(card);
if (rc)
@@ -2555,19 +2372,22 @@ static int qeth_l3_setup_netdev(struct qeth_card *card)
} else
return -ENODEV;
+ card->dev->needed_headroom = headroom;
card->dev->ethtool_ops = &qeth_l3_ethtool_ops;
- card->dev->needed_headroom = sizeof(struct qeth_hdr) - ETH_HLEN;
card->dev->features |= NETIF_F_HW_VLAN_CTAG_TX |
NETIF_F_HW_VLAN_CTAG_RX |
NETIF_F_HW_VLAN_CTAG_FILTER;
netif_keep_dst(card->dev);
- if (card->dev->hw_features & NETIF_F_TSO)
+ if (card->dev->hw_features & (NETIF_F_TSO | NETIF_F_TSO6))
netif_set_gso_max_size(card->dev,
PAGE_SIZE * (QETH_MAX_BUFFER_ELEMENTS(card) - 1));
netif_napi_add(card->dev, &card->napi, qeth_poll, QETH_NAPI_WEIGHT);
rc = register_netdev(card->dev);
+ if (!rc && carrier_ok)
+ netif_carrier_on(card->dev);
+
out:
if (rc)
card->dev->netdev_ops = NULL;
@@ -2591,7 +2411,6 @@ static int qeth_l3_probe_device(struct ccwgroup_device *gdev)
}
hash_init(card->ip_htable);
hash_init(card->ip_mc_htable);
- card->options.layer2 = 0;
card->info.hwtrap = 0;
return 0;
}
@@ -2609,7 +2428,8 @@ static void qeth_l3_remove_device(struct ccwgroup_device *cgdev)
if (cgdev->state == CCWGROUP_ONLINE)
qeth_l3_set_offline(cgdev);
- unregister_netdev(card->dev);
+ if (qeth_netdev_is_registered(card->dev))
+ unregister_netdev(card->dev);
qeth_l3_clear_ip_htable(card, 0);
qeth_l3_clear_ipato_list(card);
}
@@ -2619,6 +2439,7 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
struct qeth_card *card = dev_get_drvdata(&gdev->dev);
int rc = 0;
enum qeth_card_states recover_flag;
+ bool carrier_ok;
mutex_lock(&card->discipline_mutex);
mutex_lock(&card->conf_mutex);
@@ -2626,14 +2447,14 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
recover_flag = card->state;
- rc = qeth_core_hardsetup_card(card);
+ rc = qeth_core_hardsetup_card(card, &carrier_ok);
if (rc) {
QETH_DBF_TEXT_(SETUP, 2, "2err%04x", rc);
rc = -ENODEV;
goto out_remove;
}
- rc = qeth_l3_setup_netdev(card);
+ rc = qeth_l3_setup_netdev(card, carrier_ok);
if (rc)
goto out_remove;
@@ -2678,10 +2499,6 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
qeth_set_allowed_threads(card, 0xffffffff, 0);
qeth_l3_recover_ip(card);
- if (card->lan_online)
- netif_carrier_on(card->dev);
- else
- netif_carrier_off(card->dev);
qeth_enable_hw_features(card->dev);
if (recover_flag == CARD_STATE_RECOVER) {
@@ -2819,9 +2636,6 @@ static int qeth_l3_pm_resume(struct ccwgroup_device *gdev)
struct qeth_card *card = dev_get_drvdata(&gdev->dev);
int rc = 0;
- if (gdev->state == CCWGROUP_OFFLINE)
- goto out;
-
if (card->state == CARD_STATE_RECOVER) {
rc = __qeth_l3_set_online(card->gdev, 1);
if (rc) {
@@ -2831,7 +2645,7 @@ static int qeth_l3_pm_resume(struct ccwgroup_device *gdev)
}
} else
rc = __qeth_l3_set_online(card->gdev, 0);
-out:
+
qeth_set_allowed_threads(card, 0xffffffff, 0);
netif_device_attach(card->dev);
if (rc)
diff --git a/drivers/s390/virtio/virtio_ccw.c b/drivers/s390/virtio/virtio_ccw.c
index 8f5c1d7f751a..97b6f197f007 100644
--- a/drivers/s390/virtio/virtio_ccw.c
+++ b/drivers/s390/virtio/virtio_ccw.c
@@ -9,7 +9,7 @@
#include <linux/kernel_stat.h>
#include <linux/init.h>
-#include <linux/bootmem.h>
+#include <linux/memblock.h>
#include <linux/err.h>
#include <linux/virtio.h>
#include <linux/virtio_config.h>
diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c
index 7b31f19ade83..050879a2ddef 100644
--- a/drivers/sbus/char/openprom.c
+++ b/drivers/sbus/char/openprom.c
@@ -715,22 +715,13 @@ static struct miscdevice openprom_dev = {
static int __init openprom_init(void)
{
- struct device_node *dp;
int err;
err = misc_register(&openprom_dev);
if (err)
return err;
- dp = of_find_node_by_path("/");
- dp = dp->child;
- while (dp) {
- if (!strcmp(dp->name, "options"))
- break;
- dp = dp->sibling;
- }
- options_node = dp;
-
+ options_node = of_get_child_by_name(of_find_node_by_path("/"), "options");
if (!options_node) {
misc_deregister(&openprom_dev);
return -EIO;
diff --git a/drivers/sbus/char/oradax.c b/drivers/sbus/char/oradax.c
index 524f9ea62e52..6516bc3cb58b 100644
--- a/drivers/sbus/char/oradax.c
+++ b/drivers/sbus/char/oradax.c
@@ -689,8 +689,7 @@ static int dax_open(struct inode *inode, struct file *f)
alloc_error:
kfree(ctx->ccb_buf);
done:
- if (ctx != NULL)
- kfree(ctx);
+ kfree(ctx);
return -ENOMEM;
}
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c
index 27521fc3ef5a..2d655a97b959 100644
--- a/drivers/scsi/3w-9xxx.c
+++ b/drivers/scsi/3w-9xxx.c
@@ -143,7 +143,9 @@ static int twa_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int secon
static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id, char internal);
static int twa_reset_device_extension(TW_Device_Extension *tw_dev);
static int twa_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset);
-static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry *sglistarg);
+static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id,
+ unsigned char *cdb, int use_sg,
+ TW_SG_Entry *sglistarg);
static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id);
static char *twa_string_lookup(twa_message_type *table, unsigned int aen_code);
@@ -278,7 +280,7 @@ out:
static int twa_aen_drain_queue(TW_Device_Extension *tw_dev, int no_check_reset)
{
int request_id = 0;
- char cdb[TW_MAX_CDB_LEN];
+ unsigned char cdb[TW_MAX_CDB_LEN];
TW_SG_Entry sglist[1];
int finished = 0, count = 0;
TW_Command_Full *full_command_packet;
@@ -423,7 +425,7 @@ static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_H
/* This function will read the aen queue from the isr */
static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id)
{
- char cdb[TW_MAX_CDB_LEN];
+ unsigned char cdb[TW_MAX_CDB_LEN];
TW_SG_Entry sglist[1];
TW_Command_Full *full_command_packet;
int retval = 1;
@@ -518,7 +520,8 @@ static int twa_allocate_memory(TW_Device_Extension *tw_dev, int size, int which)
unsigned long *cpu_addr;
int retval = 1;
- cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, &dma_handle);
+ cpu_addr = dma_alloc_coherent(&tw_dev->tw_pci_dev->dev,
+ size * TW_Q_LENGTH, &dma_handle, GFP_KERNEL);
if (!cpu_addr) {
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x5, "Memory allocation failed");
goto out;
@@ -526,7 +529,8 @@ static int twa_allocate_memory(TW_Device_Extension *tw_dev, int size, int which)
if ((unsigned long)cpu_addr % (TW_ALIGNMENT_9000)) {
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x6, "Failed to allocate correctly aligned memory");
- pci_free_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, cpu_addr, dma_handle);
+ dma_free_coherent(&tw_dev->tw_pci_dev->dev, size * TW_Q_LENGTH,
+ cpu_addr, dma_handle);
goto out;
}
@@ -1027,16 +1031,16 @@ out:
static void twa_free_device_extension(TW_Device_Extension *tw_dev)
{
if (tw_dev->command_packet_virt[0])
- pci_free_consistent(tw_dev->tw_pci_dev,
- sizeof(TW_Command_Full)*TW_Q_LENGTH,
- tw_dev->command_packet_virt[0],
- tw_dev->command_packet_phys[0]);
+ dma_free_coherent(&tw_dev->tw_pci_dev->dev,
+ sizeof(TW_Command_Full) * TW_Q_LENGTH,
+ tw_dev->command_packet_virt[0],
+ tw_dev->command_packet_phys[0]);
if (tw_dev->generic_buffer_virt[0])
- pci_free_consistent(tw_dev->tw_pci_dev,
- TW_SECTOR_SIZE*TW_Q_LENGTH,
- tw_dev->generic_buffer_virt[0],
- tw_dev->generic_buffer_phys[0]);
+ dma_free_coherent(&tw_dev->tw_pci_dev->dev,
+ TW_SECTOR_SIZE * TW_Q_LENGTH,
+ tw_dev->generic_buffer_virt[0],
+ tw_dev->generic_buffer_phys[0]);
kfree(tw_dev->event_queue[0]);
} /* End twa_free_device_extension() */
@@ -1796,7 +1800,9 @@ out:
static DEF_SCSI_QCMD(twa_scsi_queue)
/* This function hands scsi cdb's to the firmware */
-static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry *sglistarg)
+static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id,
+ unsigned char *cdb, int use_sg,
+ TW_SG_Entry *sglistarg)
{
TW_Command_Full *full_command_packet;
TW_Command_Apache *command_packet;
@@ -2015,14 +2021,12 @@ static int twa_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
pci_set_master(pdev);
pci_try_set_mwi(pdev);
- if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
- || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)))
- if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
- || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
- TW_PRINTK(host, TW_DRIVER, 0x23, "Failed to set dma mask");
- retval = -ENODEV;
- goto out_disable_device;
- }
+ if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)) ||
+ dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32))) {
+ TW_PRINTK(host, TW_DRIVER, 0x23, "Failed to set dma mask");
+ retval = -ENODEV;
+ goto out_disable_device;
+ }
host = scsi_host_alloc(&driver_template, sizeof(TW_Device_Extension));
if (!host) {
@@ -2237,14 +2241,12 @@ static int twa_resume(struct pci_dev *pdev)
pci_set_master(pdev);
pci_try_set_mwi(pdev);
- if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
- || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)))
- if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
- || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
- TW_PRINTK(host, TW_DRIVER, 0x40, "Failed to set dma mask during resume");
- retval = -ENODEV;
- goto out_disable_device;
- }
+ if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)) ||
+ dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32))) {
+ TW_PRINTK(host, TW_DRIVER, 0x40, "Failed to set dma mask during resume");
+ retval = -ENODEV;
+ goto out_disable_device;
+ }
/* Initialize the card */
if (twa_reset_sequence(tw_dev, 0)) {
diff --git a/drivers/scsi/3w-sas.c b/drivers/scsi/3w-sas.c
index 40c1e6e64f58..480cf82700e9 100644
--- a/drivers/scsi/3w-sas.c
+++ b/drivers/scsi/3w-sas.c
@@ -287,7 +287,9 @@ static int twl_post_command_packet(TW_Device_Extension *tw_dev, int request_id)
} /* End twl_post_command_packet() */
/* This function hands scsi cdb's to the firmware */
-static int twl_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry_ISO *sglistarg)
+static int twl_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id,
+ unsigned char *cdb, int use_sg,
+ TW_SG_Entry_ISO *sglistarg)
{
TW_Command_Full *full_command_packet;
TW_Command_Apache *command_packet;
@@ -372,7 +374,7 @@ out:
/* This function will read the aen queue from the isr */
static int twl_aen_read_queue(TW_Device_Extension *tw_dev, int request_id)
{
- char cdb[TW_MAX_CDB_LEN];
+ unsigned char cdb[TW_MAX_CDB_LEN];
TW_SG_Entry_ISO sglist[1];
TW_Command_Full *full_command_packet;
int retval = 1;
@@ -554,7 +556,7 @@ out:
static int twl_aen_drain_queue(TW_Device_Extension *tw_dev, int no_check_reset)
{
int request_id = 0;
- char cdb[TW_MAX_CDB_LEN];
+ unsigned char cdb[TW_MAX_CDB_LEN];
TW_SG_Entry_ISO sglist[1];
int finished = 0, count = 0;
TW_Command_Full *full_command_packet;
@@ -644,8 +646,8 @@ static int twl_allocate_memory(TW_Device_Extension *tw_dev, int size, int which)
unsigned long *cpu_addr;
int retval = 1;
- cpu_addr = pci_zalloc_consistent(tw_dev->tw_pci_dev, size * TW_Q_LENGTH,
- &dma_handle);
+ cpu_addr = dma_zalloc_coherent(&tw_dev->tw_pci_dev->dev,
+ size * TW_Q_LENGTH, &dma_handle, GFP_KERNEL);
if (!cpu_addr) {
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x5, "Memory allocation failed");
goto out;
@@ -899,19 +901,19 @@ out:
static void twl_free_device_extension(TW_Device_Extension *tw_dev)
{
if (tw_dev->command_packet_virt[0])
- pci_free_consistent(tw_dev->tw_pci_dev,
+ dma_free_coherent(&tw_dev->tw_pci_dev->dev,
sizeof(TW_Command_Full)*TW_Q_LENGTH,
tw_dev->command_packet_virt[0],
tw_dev->command_packet_phys[0]);
if (tw_dev->generic_buffer_virt[0])
- pci_free_consistent(tw_dev->tw_pci_dev,
+ dma_free_coherent(&tw_dev->tw_pci_dev->dev,
TW_SECTOR_SIZE*TW_Q_LENGTH,
tw_dev->generic_buffer_virt[0],
tw_dev->generic_buffer_phys[0]);
if (tw_dev->sense_buffer_virt[0])
- pci_free_consistent(tw_dev->tw_pci_dev,
+ dma_free_coherent(&tw_dev->tw_pci_dev->dev,
sizeof(TW_Command_Apache_Header)*
TW_Q_LENGTH,
tw_dev->sense_buffer_virt[0],
@@ -1571,14 +1573,12 @@ static int twl_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
pci_set_master(pdev);
pci_try_set_mwi(pdev);
- if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
- || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)))
- if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
- || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
- TW_PRINTK(host, TW_DRIVER, 0x18, "Failed to set dma mask");
- retval = -ENODEV;
- goto out_disable_device;
- }
+ if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)) ||
+ dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32))) {
+ TW_PRINTK(host, TW_DRIVER, 0x18, "Failed to set dma mask");
+ retval = -ENODEV;
+ goto out_disable_device;
+ }
host = scsi_host_alloc(&driver_template, sizeof(TW_Device_Extension));
if (!host) {
@@ -1805,14 +1805,12 @@ static int twl_resume(struct pci_dev *pdev)
pci_set_master(pdev);
pci_try_set_mwi(pdev);
- if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
- || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)))
- if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
- || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
- TW_PRINTK(host, TW_DRIVER, 0x25, "Failed to set dma mask during resume");
- retval = -ENODEV;
- goto out_disable_device;
- }
+ if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)) ||
+ dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32))) {
+ TW_PRINTK(host, TW_DRIVER, 0x25, "Failed to set dma mask during resume");
+ retval = -ENODEV;
+ goto out_disable_device;
+ }
/* Initialize the card */
if (twl_reset_sequence(tw_dev, 0)) {
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
index 471366945bd4..a58257645e94 100644
--- a/drivers/scsi/3w-xxxx.c
+++ b/drivers/scsi/3w-xxxx.c
@@ -834,15 +834,17 @@ static int tw_allocate_memory(TW_Device_Extension *tw_dev, int size, int which)
dprintk(KERN_NOTICE "3w-xxxx: tw_allocate_memory()\n");
- cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, &dma_handle);
+ cpu_addr = dma_alloc_coherent(&tw_dev->tw_pci_dev->dev,
+ size * TW_Q_LENGTH, &dma_handle, GFP_KERNEL);
if (cpu_addr == NULL) {
- printk(KERN_WARNING "3w-xxxx: pci_alloc_consistent() failed.\n");
+ printk(KERN_WARNING "3w-xxxx: dma_alloc_coherent() failed.\n");
return 1;
}
if ((unsigned long)cpu_addr % (tw_dev->tw_pci_dev->device == TW_DEVICE_ID ? TW_ALIGNMENT_6000 : TW_ALIGNMENT_7000)) {
printk(KERN_WARNING "3w-xxxx: Couldn't allocate correctly aligned memory.\n");
- pci_free_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, cpu_addr, dma_handle);
+ dma_free_coherent(&tw_dev->tw_pci_dev->dev, size * TW_Q_LENGTH,
+ cpu_addr, dma_handle);
return 1;
}
@@ -1062,10 +1064,16 @@ static void tw_free_device_extension(TW_Device_Extension *tw_dev)
/* Free command packet and generic buffer memory */
if (tw_dev->command_packet_virtual_address[0])
- pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Command)*TW_Q_LENGTH, tw_dev->command_packet_virtual_address[0], tw_dev->command_packet_physical_address[0]);
+ dma_free_coherent(&tw_dev->tw_pci_dev->dev,
+ sizeof(TW_Command) * TW_Q_LENGTH,
+ tw_dev->command_packet_virtual_address[0],
+ tw_dev->command_packet_physical_address[0]);
if (tw_dev->alignment_virtual_address[0])
- pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Sector)*TW_Q_LENGTH, tw_dev->alignment_virtual_address[0], tw_dev->alignment_physical_address[0]);
+ dma_free_coherent(&tw_dev->tw_pci_dev->dev,
+ sizeof(TW_Sector) * TW_Q_LENGTH,
+ tw_dev->alignment_virtual_address[0],
+ tw_dev->alignment_physical_address[0]);
} /* End tw_free_device_extension() */
/* This function will send an initconnection command to controller */
@@ -2260,7 +2268,7 @@ static int tw_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
pci_set_master(pdev);
- retval = pci_set_dma_mask(pdev, TW_DMA_MASK);
+ retval = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
if (retval) {
printk(KERN_WARNING "3w-xxxx: Failed to set dma mask.");
goto out_disable_device;
diff --git a/drivers/scsi/3w-xxxx.h b/drivers/scsi/3w-xxxx.h
index 69e80c1ed1ca..bd87fbacfbc7 100644
--- a/drivers/scsi/3w-xxxx.h
+++ b/drivers/scsi/3w-xxxx.h
@@ -230,7 +230,6 @@ static unsigned char tw_sense_table[][4] =
#define TW_IOCTL_TIMEOUT 25 /* 25 seconds */
#define TW_IOCTL_CHRDEV_TIMEOUT 60 /* 60 seconds */
#define TW_IOCTL_CHRDEV_FREE -1
-#define TW_DMA_MASK DMA_BIT_MASK(32)
#define TW_MAX_CDB_LEN 16
/* Bitmask macros to eliminate bitfields */
diff --git a/drivers/scsi/53c700.h b/drivers/scsi/53c700.h
index 0c9a100af667..05fe439b66af 100644
--- a/drivers/scsi/53c700.h
+++ b/drivers/scsi/53c700.h
@@ -90,7 +90,7 @@ struct NCR_700_Device_Parameters {
/* The SYNC negotiation sequence looks like:
*
* If DEV_NEGOTIATED_SYNC not set, tack and SDTR message on to the
- * initial identify for the device and set DEV_BEGIN_SYNC_NEGOTATION
+ * initial identify for the device and set DEV_BEGIN_SYNC_NEGOTIATION
* If we get an SDTR reply, work out the SXFER parameters, squirrel
* them away here, clear DEV_BEGIN_SYNC_NEGOTIATION and set
* DEV_NEGOTIATED_SYNC. If we get a REJECT msg, squirrel
diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
index 0d4ffe0ae306..9cee941f97d6 100644
--- a/drivers/scsi/BusLogic.c
+++ b/drivers/scsi/BusLogic.c
@@ -201,8 +201,8 @@ static bool __init blogic_create_initccbs(struct blogic_adapter *adapter)
dma_addr_t blkp;
while (adapter->alloc_ccbs < adapter->initccbs) {
- blk_pointer = pci_alloc_consistent(adapter->pci_device,
- blk_size, &blkp);
+ blk_pointer = dma_alloc_coherent(&adapter->pci_device->dev,
+ blk_size, &blkp, GFP_KERNEL);
if (blk_pointer == NULL) {
blogic_err("UNABLE TO ALLOCATE CCB GROUP - DETACHING\n",
adapter);
@@ -227,15 +227,16 @@ static void blogic_destroy_ccbs(struct blogic_adapter *adapter)
next_ccb = ccb->next_all;
if (ccb->allocgrp_head) {
if (lastccb)
- pci_free_consistent(adapter->pci_device,
+ dma_free_coherent(&adapter->pci_device->dev,
lastccb->allocgrp_size, lastccb,
lastccb->allocgrp_head);
lastccb = ccb;
}
}
if (lastccb)
- pci_free_consistent(adapter->pci_device, lastccb->allocgrp_size,
- lastccb, lastccb->allocgrp_head);
+ dma_free_coherent(&adapter->pci_device->dev,
+ lastccb->allocgrp_size, lastccb,
+ lastccb->allocgrp_head);
}
@@ -256,8 +257,8 @@ static void blogic_create_addlccbs(struct blogic_adapter *adapter,
if (addl_ccbs <= 0)
return;
while (adapter->alloc_ccbs - prev_alloc < addl_ccbs) {
- blk_pointer = pci_alloc_consistent(adapter->pci_device,
- blk_size, &blkp);
+ blk_pointer = dma_alloc_coherent(&adapter->pci_device->dev,
+ blk_size, &blkp, GFP_KERNEL);
if (blk_pointer == NULL)
break;
blogic_init_ccbs(adapter, blk_pointer, blk_size, blkp);
@@ -318,8 +319,8 @@ static void blogic_dealloc_ccb(struct blogic_ccb *ccb, int dma_unmap)
if (ccb->command != NULL)
scsi_dma_unmap(ccb->command);
if (dma_unmap)
- pci_unmap_single(adapter->pci_device, ccb->sensedata,
- ccb->sense_datalen, PCI_DMA_FROMDEVICE);
+ dma_unmap_single(&adapter->pci_device->dev, ccb->sensedata,
+ ccb->sense_datalen, DMA_FROM_DEVICE);
ccb->command = NULL;
ccb->status = BLOGIC_CCB_FREE;
@@ -712,7 +713,7 @@ static int __init blogic_init_mm_probeinfo(struct blogic_adapter *adapter)
if (pci_enable_device(pci_device))
continue;
- if (pci_set_dma_mask(pci_device, DMA_BIT_MASK(32)))
+ if (dma_set_mask(&pci_device->dev, DMA_BIT_MASK(32)))
continue;
bus = pci_device->bus->number;
@@ -895,7 +896,7 @@ static int __init blogic_init_mm_probeinfo(struct blogic_adapter *adapter)
if (pci_enable_device(pci_device))
continue;
- if (pci_set_dma_mask(pci_device, DMA_BIT_MASK(32)))
+ if (dma_set_mask(&pci_device->dev, DMA_BIT_MASK(32)))
continue;
bus = pci_device->bus->number;
@@ -952,7 +953,7 @@ static int __init blogic_init_fp_probeinfo(struct blogic_adapter *adapter)
if (pci_enable_device(pci_device))
continue;
- if (pci_set_dma_mask(pci_device, DMA_BIT_MASK(32)))
+ if (dma_set_mask(&pci_device->dev, DMA_BIT_MASK(32)))
continue;
bus = pci_device->bus->number;
@@ -2040,7 +2041,7 @@ static void blogic_relres(struct blogic_adapter *adapter)
Release any allocated memory structs not released elsewhere
*/
if (adapter->mbox_space)
- pci_free_consistent(adapter->pci_device, adapter->mbox_sz,
+ dma_free_coherent(&adapter->pci_device->dev, adapter->mbox_sz,
adapter->mbox_space, adapter->mbox_space_handle);
pci_dev_put(adapter->pci_device);
adapter->mbox_space = NULL;
@@ -2092,8 +2093,9 @@ static bool blogic_initadapter(struct blogic_adapter *adapter)
Initialize the Outgoing and Incoming Mailbox pointers.
*/
adapter->mbox_sz = adapter->mbox_count * (sizeof(struct blogic_outbox) + sizeof(struct blogic_inbox));
- adapter->mbox_space = pci_alloc_consistent(adapter->pci_device,
- adapter->mbox_sz, &adapter->mbox_space_handle);
+ adapter->mbox_space = dma_alloc_coherent(&adapter->pci_device->dev,
+ adapter->mbox_sz, &adapter->mbox_space_handle,
+ GFP_KERNEL);
if (adapter->mbox_space == NULL)
return blogic_failure(adapter, "MAILBOX ALLOCATION");
adapter->first_outbox = (struct blogic_outbox *) adapter->mbox_space;
@@ -3183,9 +3185,9 @@ static int blogic_qcmd_lck(struct scsi_cmnd *command,
memcpy(ccb->cdb, cdb, cdblen);
ccb->sense_datalen = SCSI_SENSE_BUFFERSIZE;
ccb->command = command;
- sense_buf = pci_map_single(adapter->pci_device,
+ sense_buf = dma_map_single(&adapter->pci_device->dev,
command->sense_buffer, ccb->sense_datalen,
- PCI_DMA_FROMDEVICE);
+ DMA_FROM_DEVICE);
if (dma_mapping_error(&adapter->pci_device->dev, sense_buf)) {
blogic_err("DMA mapping for sense data buffer failed\n",
adapter);
diff --git a/drivers/scsi/FlashPoint.c b/drivers/scsi/FlashPoint.c
index 867b864f5047..0f17bd51088a 100644
--- a/drivers/scsi/FlashPoint.c
+++ b/drivers/scsi/FlashPoint.c
@@ -2944,7 +2944,7 @@ static void FPT_sdecm(unsigned char message, u32 port, unsigned char p_card)
}
if (currSCCB->Lun == 0x00) {
- if ((currSCCB->Sccb_scsistat == SELECT_SN_ST)) {
+ if (currSCCB->Sccb_scsistat == SELECT_SN_ST) {
currTar_Info->TarStatus |=
(unsigned char)SYNC_SUPPORTED;
@@ -2953,8 +2953,8 @@ static void FPT_sdecm(unsigned char message, u32 port, unsigned char p_card)
~EE_SYNC_MASK;
}
- else if ((currSCCB->Sccb_scsistat ==
- SELECT_WN_ST)) {
+ else if (currSCCB->Sccb_scsistat ==
+ SELECT_WN_ST) {
currTar_Info->TarStatus =
(currTar_Info->
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 7c097006c54d..640cd1b31a18 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -42,6 +42,9 @@ config SCSI_DMA
bool
default n
+config SCSI_ESP_PIO
+ bool
+
config SCSI_NETLINK
bool
default n
@@ -535,7 +538,7 @@ config SCSI_HPTIOP
config SCSI_BUSLOGIC
tristate "BusLogic SCSI support"
- depends on (PCI || ISA || MCA) && SCSI && ISA_DMA_API && VIRT_TO_BUS
+ depends on (PCI || ISA) && SCSI && ISA_DMA_API && VIRT_TO_BUS
---help---
This is support for BusLogic MultiMaster and FlashPoint SCSI Host
Adapters. Consult the SCSI-HOWTO, available from
@@ -557,6 +560,37 @@ config SCSI_FLASHPOINT
substantial, so users of MultiMaster Host Adapters may not
wish to include it.
+config SCSI_MYRB
+ tristate "Mylex DAC960/DAC1100 PCI RAID Controller (Block Interface)"
+ depends on PCI
+ select RAID_ATTRS
+ help
+ This driver adds support for the Mylex DAC960, AcceleRAID, and
+ eXtremeRAID PCI RAID controllers. This driver supports the
+ older, block based interface.
+ This driver is a reimplementation of the original DAC960
+ driver. If you have used the DAC960 driver you should enable
+ this module.
+
+ To compile this driver as a module, choose M here: the
+ module will be called myrb.
+
+config SCSI_MYRS
+ tristate "Mylex DAC960/DAC1100 PCI RAID Controller (SCSI Interface)"
+ depends on PCI
+ depends on !CPU_BIG_ENDIAN || COMPILE_TEST
+ select RAID_ATTRS
+ help
+ This driver adds support for the Mylex DAC960, AcceleRAID, and
+ eXtremeRAID PCI RAID controllers. This driver supports the
+ newer, SCSI-based interface only.
+ This driver is a reimplementation of the original DAC960
+ driver. If you have used the DAC960 driver you should enable
+ this module.
+
+ To compile this driver as a module, choose M here: the
+ module will be called myrs.
+
config VMWARE_PVSCSI
tristate "VMware PVSCSI driver support"
depends on PCI && SCSI && X86
@@ -1142,12 +1176,12 @@ config SCSI_LPFC_DEBUG_FS
config SCSI_SIM710
tristate "Simple 53c710 SCSI support (Compaq, NCR machines)"
- depends on (EISA || MCA) && SCSI
+ depends on EISA && SCSI
select SCSI_SPI_ATTRS
---help---
This driver is for NCR53c710 based SCSI host adapters.
- It currently supports Compaq EISA cards and NCR MCA cards
+ It currently supports Compaq EISA cards.
config SCSI_DC395x
tristate "Tekram DC395(U/UW/F) and DC315(U) SCSI support"
@@ -1332,6 +1366,7 @@ config SCSI_ZORRO_ESP
tristate "Zorro ESP SCSI support"
depends on ZORRO && SCSI
select SCSI_SPI_ATTRS
+ select SCSI_ESP_PIO
help
Support for various NCR53C9x (ESP) based SCSI controllers on Zorro
expansion boards for the Amiga.
@@ -1374,6 +1409,7 @@ config SCSI_MAC_ESP
tristate "Macintosh NCR53c9[46] SCSI"
depends on MAC && SCSI
select SCSI_SPI_ATTRS
+ select SCSI_ESP_PIO
help
This is the NCR 53c9x SCSI controller found on most of the 68040
based Macintoshes.
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 6d71b2a9592b..fcb41ae329c4 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -106,6 +106,8 @@ obj-$(CONFIG_SCSI_INIA100) += a100u2w.o
obj-$(CONFIG_SCSI_QLOGICPTI) += qlogicpti.o
obj-$(CONFIG_SCSI_MESH) += mesh.o
obj-$(CONFIG_SCSI_MAC53C94) += mac53c94.o
+obj-$(CONFIG_SCSI_MYRB) += myrb.o
+obj-$(CONFIG_SCSI_MYRS) += myrs.o
obj-$(CONFIG_BLK_DEV_3W_XXXX_RAID) += 3w-xxxx.o
obj-$(CONFIG_SCSI_3W_9XXX) += 3w-9xxx.o
obj-$(CONFIG_SCSI_3W_SAS) += 3w-sas.o
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
index 90ea0f5d9bdb..01c23d27f290 100644
--- a/drivers/scsi/NCR5380.c
+++ b/drivers/scsi/NCR5380.c
@@ -131,6 +131,7 @@
static int do_abort(struct Scsi_Host *);
static void do_reset(struct Scsi_Host *);
+static void bus_reset_cleanup(struct Scsi_Host *);
/**
* initialize_SCp - init the scsi pointer field
@@ -513,16 +514,15 @@ static void complete_cmd(struct Scsi_Host *instance,
if (hostdata->sensing == cmd) {
/* Autosense processing ends here */
- if ((cmd->result & 0xff) != SAM_STAT_GOOD) {
+ if (status_byte(cmd->result) != GOOD) {
scsi_eh_restore_cmnd(cmd, &hostdata->ses);
- set_host_byte(cmd, DID_ERROR);
- } else
+ } else {
scsi_eh_restore_cmnd(cmd, &hostdata->ses);
+ set_driver_byte(cmd, DRIVER_SENSE);
+ }
hostdata->sensing = NULL;
}
- hostdata->busy[scmd_id(cmd)] &= ~(1 << cmd->device->lun);
-
cmd->scsi_done(cmd);
}
@@ -884,7 +884,14 @@ static irqreturn_t __maybe_unused NCR5380_intr(int irq, void *dev_id)
/* Probably Bus Reset */
NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- dsprintk(NDEBUG_INTR, instance, "unknown interrupt\n");
+ if (sr & SR_RST) {
+ /* Certainly Bus Reset */
+ shost_printk(KERN_WARNING, instance,
+ "bus reset interrupt\n");
+ bus_reset_cleanup(instance);
+ } else {
+ dsprintk(NDEBUG_INTR, instance, "unknown interrupt\n");
+ }
#ifdef SUN3_SCSI_VME
dregs->csr |= CSR_DMA_ENABLE;
#endif
@@ -902,20 +909,16 @@ static irqreturn_t __maybe_unused NCR5380_intr(int irq, void *dev_id)
return IRQ_RETVAL(handled);
}
-/*
- * Function : int NCR5380_select(struct Scsi_Host *instance,
- * struct scsi_cmnd *cmd)
- *
- * Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command,
- * including ARBITRATION, SELECTION, and initial message out for
- * IDENTIFY and queue messages.
+/**
+ * NCR5380_select - attempt arbitration and selection for a given command
+ * @instance: the Scsi_Host instance
+ * @cmd: the scsi_cmnd to execute
*
- * Inputs : instance - instantiation of the 5380 driver on which this
- * target lives, cmd - SCSI command to execute.
+ * This routine establishes an I_T_L nexus for a SCSI command. This involves
+ * ARBITRATION, SELECTION and MESSAGE OUT phases and an IDENTIFY message.
*
- * Returns cmd if selection failed but should be retried,
- * NULL if selection failed and should not be retried, or
- * NULL if selection succeeded (hostdata->connected == cmd).
+ * Returns true if the operation should be retried.
+ * Returns false if it should not be retried.
*
* Side effects :
* If bus busy, arbitration failed, etc, NCR5380_select() will exit
@@ -923,16 +926,15 @@ static irqreturn_t __maybe_unused NCR5380_intr(int irq, void *dev_id)
* SELECT_ENABLE will be set appropriately, the NCR5380
* will cease to drive any SCSI bus signals.
*
- * If successful : I_T_L or I_T_L_Q nexus will be established,
- * instance->connected will be set to cmd.
+ * If successful : the I_T_L nexus will be established, and
+ * hostdata->connected will be set to cmd.
* SELECT interrupt will be disabled.
*
* If failed (no target) : cmd->scsi_done() will be called, and the
* cmd->result host byte set to DID_BAD_TARGET.
*/
-static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance,
- struct scsi_cmnd *cmd)
+static bool NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
__releases(&hostdata->lock) __acquires(&hostdata->lock)
{
struct NCR5380_hostdata *hostdata = shost_priv(instance);
@@ -940,6 +942,9 @@ static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance,
unsigned char *data;
int len;
int err;
+ bool ret = true;
+ bool can_disconnect = instance->irq != NO_IRQ &&
+ cmd->cmnd[0] != REQUEST_SENSE;
NCR5380_dprint(NDEBUG_ARBITRATION, instance);
dsprintk(NDEBUG_ARBITRATION, instance, "starting arbitration, id = %d\n",
@@ -948,7 +953,7 @@ static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance,
/*
* Arbitration and selection phases are slow and involve dropping the
* lock, so we have to watch out for EH. An exception handler may
- * change 'selecting' to NULL. This function will then return NULL
+ * change 'selecting' to NULL. This function will then return false
* so that the caller will forget about 'cmd'. (During information
* transfer phases, EH may change 'connected' to NULL.)
*/
@@ -984,7 +989,7 @@ static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance,
if (!hostdata->selecting) {
/* Command was aborted */
NCR5380_write(MODE_REG, MR_BASE);
- goto out;
+ return false;
}
if (err < 0) {
NCR5380_write(MODE_REG, MR_BASE);
@@ -1033,7 +1038,7 @@ static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance,
if (!hostdata->selecting) {
NCR5380_write(MODE_REG, MR_BASE);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- goto out;
+ return false;
}
dsprintk(NDEBUG_ARBITRATION, instance, "won arbitration\n");
@@ -1116,13 +1121,16 @@ static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance,
spin_lock_irq(&hostdata->lock);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+
/* Can't touch cmd if it has been reclaimed by the scsi ML */
- if (hostdata->selecting) {
- cmd->result = DID_BAD_TARGET << 16;
- complete_cmd(instance, cmd);
- dsprintk(NDEBUG_SELECTION, instance, "target did not respond within 250ms\n");
- cmd = NULL;
- }
+ if (!hostdata->selecting)
+ return false;
+
+ cmd->result = DID_BAD_TARGET << 16;
+ complete_cmd(instance, cmd);
+ dsprintk(NDEBUG_SELECTION, instance,
+ "target did not respond within 250ms\n");
+ ret = false;
goto out;
}
@@ -1155,12 +1163,12 @@ static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance,
}
if (!hostdata->selecting) {
do_abort(instance);
- goto out;
+ return false;
}
dsprintk(NDEBUG_SELECTION, instance, "target %d selected, going into MESSAGE OUT phase.\n",
scmd_id(cmd));
- tmp[0] = IDENTIFY(((instance->irq == NO_IRQ) ? 0 : 1), cmd->device->lun);
+ tmp[0] = IDENTIFY(can_disconnect, cmd->device->lun);
len = 1;
data = tmp;
@@ -1171,7 +1179,7 @@ static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance,
cmd->result = DID_ERROR << 16;
complete_cmd(instance, cmd);
dsprintk(NDEBUG_SELECTION, instance, "IDENTIFY message transfer failed\n");
- cmd = NULL;
+ ret = false;
goto out;
}
@@ -1186,13 +1194,13 @@ static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance,
initialize_SCp(cmd);
- cmd = NULL;
+ ret = false;
out:
if (!hostdata->selecting)
- return NULL;
+ return false;
hostdata->selecting = NULL;
- return cmd;
+ return ret;
}
/*
@@ -1711,6 +1719,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
cmd->result = DID_ERROR << 16;
complete_cmd(instance, cmd);
hostdata->connected = NULL;
+ hostdata->busy[scmd_id(cmd)] &= ~(1 << cmd->device->lun);
return;
#endif
case PHASE_DATAIN:
@@ -1793,6 +1802,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
cmd, scmd_id(cmd), cmd->device->lun);
hostdata->connected = NULL;
+ hostdata->busy[scmd_id(cmd)] &= ~(1 << cmd->device->lun);
cmd->result &= ~0xffff;
cmd->result |= cmd->SCp.Status;
@@ -1951,6 +1961,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
NCR5380_transfer_pio(instance, &phase, &len, &data);
if (msgout == ABORT) {
hostdata->connected = NULL;
+ hostdata->busy[scmd_id(cmd)] &= ~(1 << cmd->device->lun);
cmd->result = DID_ERROR << 16;
complete_cmd(instance, cmd);
maybe_release_dma_irq(instance);
@@ -2014,8 +2025,11 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
NCR5380_write(MODE_REG, MR_BASE);
target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask);
-
- dsprintk(NDEBUG_RESELECTION, instance, "reselect\n");
+ if (!target_mask || target_mask & (target_mask - 1)) {
+ shost_printk(KERN_WARNING, instance,
+ "reselect: bad target_mask 0x%02x\n", target_mask);
+ return;
+ }
/*
* At this point, we have detected that our SCSI ID is on the bus,
@@ -2029,6 +2043,7 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY);
if (NCR5380_poll_politely(hostdata,
STATUS_REG, SR_SEL, 0, 2 * HZ) < 0) {
+ shost_printk(KERN_ERR, instance, "reselect: !SEL timeout\n");
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
return;
}
@@ -2040,6 +2055,10 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
if (NCR5380_poll_politely(hostdata,
STATUS_REG, SR_REQ, SR_REQ, 2 * HZ) < 0) {
+ if ((NCR5380_read(STATUS_REG) & (SR_BSY | SR_SEL)) == 0)
+ /* BUS FREE phase */
+ return;
+ shost_printk(KERN_ERR, instance, "reselect: REQ timeout\n");
do_abort(instance);
return;
}
@@ -2101,13 +2120,16 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
dsprintk(NDEBUG_RESELECTION | NDEBUG_QUEUES, instance,
"reselect: removed %p from disconnected queue\n", tmp);
} else {
+ int target = ffs(target_mask) - 1;
+
shost_printk(KERN_ERR, instance, "target bitmask 0x%02x lun %d not in disconnected queue.\n",
target_mask, lun);
/*
* Since we have an established nexus that we can't do anything
* with, we must abort it.
*/
- do_abort(instance);
+ if (do_abort(instance) == 0)
+ hostdata->busy[target] &= ~(1 << lun);
return;
}
@@ -2272,15 +2294,16 @@ static int NCR5380_abort(struct scsi_cmnd *cmd)
if (list_del_cmd(&hostdata->autosense, cmd)) {
dsprintk(NDEBUG_ABORT, instance,
"abort: removed %p from sense queue\n", cmd);
- set_host_byte(cmd, DID_ERROR);
complete_cmd(instance, cmd);
}
out:
if (result == FAILED)
dsprintk(NDEBUG_ABORT, instance, "abort: failed to abort %p\n", cmd);
- else
+ else {
+ hostdata->busy[scmd_id(cmd)] &= ~(1 << cmd->device->lun);
dsprintk(NDEBUG_ABORT, instance, "abort: successfully aborted %p\n", cmd);
+ }
queue_work(hostdata->work_q, &hostdata->main_task);
maybe_release_dma_irq(instance);
@@ -2290,31 +2313,12 @@ out:
}
-/**
- * NCR5380_host_reset - reset the SCSI host
- * @cmd: SCSI command undergoing EH
- *
- * Returns SUCCESS
- */
-
-static int NCR5380_host_reset(struct scsi_cmnd *cmd)
+static void bus_reset_cleanup(struct Scsi_Host *instance)
{
- struct Scsi_Host *instance = cmd->device->host;
struct NCR5380_hostdata *hostdata = shost_priv(instance);
int i;
- unsigned long flags;
struct NCR5380_cmd *ncmd;
- spin_lock_irqsave(&hostdata->lock, flags);
-
-#if (NDEBUG & NDEBUG_ANY)
- scmd_printk(KERN_INFO, cmd, __func__);
-#endif
- NCR5380_dprint(NDEBUG_ANY, instance);
- NCR5380_dprint_phase(NDEBUG_ANY, instance);
-
- do_reset(instance);
-
/* reset NCR registers */
NCR5380_write(MODE_REG, MR_BASE);
NCR5380_write(TARGET_COMMAND_REG, 0);
@@ -2326,11 +2330,6 @@ static int NCR5380_host_reset(struct scsi_cmnd *cmd)
* commands!
*/
- if (list_del_cmd(&hostdata->unissued, cmd)) {
- cmd->result = DID_RESET << 16;
- cmd->scsi_done(cmd);
- }
-
if (hostdata->selecting) {
hostdata->selecting->result = DID_RESET << 16;
complete_cmd(instance, hostdata->selecting);
@@ -2348,7 +2347,6 @@ static int NCR5380_host_reset(struct scsi_cmnd *cmd)
list_for_each_entry(ncmd, &hostdata->autosense, list) {
struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd);
- set_host_byte(cmd, DID_RESET);
cmd->scsi_done(cmd);
}
INIT_LIST_HEAD(&hostdata->autosense);
@@ -2365,6 +2363,41 @@ static int NCR5380_host_reset(struct scsi_cmnd *cmd)
queue_work(hostdata->work_q, &hostdata->main_task);
maybe_release_dma_irq(instance);
+}
+
+/**
+ * NCR5380_host_reset - reset the SCSI host
+ * @cmd: SCSI command undergoing EH
+ *
+ * Returns SUCCESS
+ */
+
+static int NCR5380_host_reset(struct scsi_cmnd *cmd)
+{
+ struct Scsi_Host *instance = cmd->device->host;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ unsigned long flags;
+ struct NCR5380_cmd *ncmd;
+
+ spin_lock_irqsave(&hostdata->lock, flags);
+
+#if (NDEBUG & NDEBUG_ANY)
+ shost_printk(KERN_INFO, instance, __func__);
+#endif
+ NCR5380_dprint(NDEBUG_ANY, instance);
+ NCR5380_dprint_phase(NDEBUG_ANY, instance);
+
+ list_for_each_entry(ncmd, &hostdata->unissued, list) {
+ struct scsi_cmnd *scmd = NCR5380_to_scmd(ncmd);
+
+ scmd->result = DID_RESET << 16;
+ scmd->scsi_done(scmd);
+ }
+ INIT_LIST_HEAD(&hostdata->unissued);
+
+ do_reset(instance);
+ bus_reset_cleanup(instance);
+
spin_unlock_irqrestore(&hostdata->lock, flags);
return SUCCESS;
diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h
index 31096a0b0fdd..efca509b92b0 100644
--- a/drivers/scsi/NCR5380.h
+++ b/drivers/scsi/NCR5380.h
@@ -275,7 +275,7 @@ static irqreturn_t NCR5380_intr(int irq, void *dev_id);
static void NCR5380_main(struct work_struct *work);
static const char *NCR5380_info(struct Scsi_Host *instance);
static void NCR5380_reselect(struct Scsi_Host *instance);
-static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *, struct scsi_cmnd *);
+static bool NCR5380_select(struct Scsi_Host *, struct scsi_cmnd *);
static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data);
static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data);
static int NCR5380_poll_politely2(struct NCR5380_hostdata *,
diff --git a/drivers/scsi/a100u2w.c b/drivers/scsi/a100u2w.c
index 23b17621b6d2..00072ed9540b 100644
--- a/drivers/scsi/a100u2w.c
+++ b/drivers/scsi/a100u2w.c
@@ -1094,7 +1094,7 @@ static int inia100_probe_one(struct pci_dev *pdev,
if (pci_enable_device(pdev))
goto out;
- if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
+ if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) {
printk(KERN_WARNING "Unable to set 32bit DMA "
"on inia100 adapter, ignoring.\n");
goto out_disable_device;
@@ -1124,7 +1124,8 @@ static int inia100_probe_one(struct pci_dev *pdev,
/* Get total memory needed for SCB */
sz = ORC_MAXQUEUE * sizeof(struct orc_scb);
- host->scb_virt = pci_zalloc_consistent(pdev, sz, &host->scb_phys);
+ host->scb_virt = dma_zalloc_coherent(&pdev->dev, sz, &host->scb_phys,
+ GFP_KERNEL);
if (!host->scb_virt) {
printk("inia100: SCB memory allocation error\n");
goto out_host_put;
@@ -1132,7 +1133,8 @@ static int inia100_probe_one(struct pci_dev *pdev,
/* Get total memory needed for ESCB */
sz = ORC_MAXQUEUE * sizeof(struct orc_extended_scb);
- host->escb_virt = pci_zalloc_consistent(pdev, sz, &host->escb_phys);
+ host->escb_virt = dma_zalloc_coherent(&pdev->dev, sz, &host->escb_phys,
+ GFP_KERNEL);
if (!host->escb_virt) {
printk("inia100: ESCB memory allocation error\n");
goto out_free_scb_array;
@@ -1177,10 +1179,12 @@ static int inia100_probe_one(struct pci_dev *pdev,
out_free_irq:
free_irq(shost->irq, shost);
out_free_escb_array:
- pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(struct orc_extended_scb),
+ dma_free_coherent(&pdev->dev,
+ ORC_MAXQUEUE * sizeof(struct orc_extended_scb),
host->escb_virt, host->escb_phys);
out_free_scb_array:
- pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(struct orc_scb),
+ dma_free_coherent(&pdev->dev,
+ ORC_MAXQUEUE * sizeof(struct orc_scb),
host->scb_virt, host->scb_phys);
out_host_put:
scsi_host_put(shost);
@@ -1200,9 +1204,11 @@ static void inia100_remove_one(struct pci_dev *pdev)
scsi_remove_host(shost);
free_irq(shost->irq, shost);
- pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(struct orc_extended_scb),
+ dma_free_coherent(&pdev->dev,
+ ORC_MAXQUEUE * sizeof(struct orc_extended_scb),
host->escb_virt, host->escb_phys);
- pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(struct orc_scb),
+ dma_free_coherent(&pdev->dev,
+ ORC_MAXQUEUE * sizeof(struct orc_scb),
host->scb_virt, host->scb_phys);
release_region(shost->io_port, 256);
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index 6e356325d8d9..bd7f352c28f3 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -3480,7 +3480,6 @@ int aac_dev_ioctl(struct aac_dev *dev, int cmd, void __user *arg)
static void aac_srb_callback(void *context, struct fib * fibptr)
{
- struct aac_dev *dev;
struct aac_srb_reply *srbreply;
struct scsi_cmnd *scsicmd;
@@ -3491,8 +3490,6 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
BUG_ON(fibptr == NULL);
- dev = fibptr->dev;
-
srbreply = (struct aac_srb_reply *) fib_data(fibptr);
scsicmd->sense_buffer[0] = '\0'; /* Initialize sense valid flag to false */
@@ -3921,13 +3918,11 @@ static int aac_send_hba_fib(struct scsi_cmnd *scsicmd)
static long aac_build_sg(struct scsi_cmnd *scsicmd, struct sgmap *psg)
{
- struct aac_dev *dev;
unsigned long byte_count = 0;
int nseg;
struct scatterlist *sg;
int i;
- dev = (struct aac_dev *)scsicmd->device->host->hostdata;
// Get rid of old data
psg->count = 0;
psg->sg[0].addr = 0;
@@ -3963,14 +3958,12 @@ static long aac_build_sg(struct scsi_cmnd *scsicmd, struct sgmap *psg)
static long aac_build_sg64(struct scsi_cmnd *scsicmd, struct sgmap64 *psg)
{
- struct aac_dev *dev;
unsigned long byte_count = 0;
u64 addr;
int nseg;
struct scatterlist *sg;
int i;
- dev = (struct aac_dev *)scsicmd->device->host->hostdata;
// Get rid of old data
psg->count = 0;
psg->sg[0].addr[0] = 0;
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index 6e1b022a823d..1e77d96a18f2 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -2586,9 +2586,7 @@ int aac_acquire_irq(struct aac_dev *dev)
void aac_free_irq(struct aac_dev *dev)
{
int i;
- int cpu;
- cpu = cpumask_first(cpu_online_mask);
if (aac_is_src(dev)) {
if (dev->max_msix > 1) {
for (i = 0; i < dev->max_msix; i++)
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index 04443577d48b..2d4e4ddc5ace 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -1747,7 +1747,7 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
shost->max_sectors = (shost->sg_tablesize * 8) + 112;
}
- error = pci_set_dma_max_seg_size(pdev,
+ error = dma_set_max_seg_size(&pdev->dev,
(aac->adapter_info.options & AAC_OPT_NEW_COMM) ?
(shost->max_sectors << 9) : 65536);
if (error)
@@ -2055,8 +2055,6 @@ static void aac_pci_resume(struct pci_dev *pdev)
struct scsi_device *sdev = NULL;
struct aac_dev *aac = (struct aac_dev *)shost_priv(shost);
- pci_cleanup_aer_uncorrect_error_status(pdev);
-
if (aac_adapter_ioremap(aac, aac->base_size)) {
dev_err(&pdev->dev, "aacraid: ioremap failed\n");
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 713f69033f20..223ef6f4e258 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -5949,7 +5949,6 @@ static void adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code)
static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
{
struct asc_board *boardp = adv_dvc_varp->drv_ptr;
- u32 srb_tag;
adv_req_t *reqp;
adv_sgblk_t *sgblkp;
struct scsi_cmnd *scp;
@@ -5965,7 +5964,6 @@ static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
* completed. The adv_req_t structure actually contains the
* completed ADV_SCSI_REQ_Q structure.
*/
- srb_tag = le32_to_cpu(scsiqp->srb_tag);
scp = scsi_host_find_tag(boardp->shost, scsiqp->srb_tag);
ASC_DBG(1, "scp 0x%p\n", scp);
@@ -6448,7 +6446,7 @@ static void AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
sdtr_data =
AscCalSDTRData(asc_dvc, ext_msg.xfer_period,
ext_msg.req_ack_offset);
- if ((sdtr_data == 0xFF)) {
+ if (sdtr_data == 0xFF) {
q_cntl |= QC_MSG_OUT;
asc_dvc->init_sdtr &= ~target_id;
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index 4d7b0e0adbf7..301b3cad15f8 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -269,7 +269,7 @@ static LIST_HEAD(aha152x_host_list);
/* DEFINES */
/* For PCMCIA cards, always use AUTOCONF */
-#if defined(PCMCIA) || defined(MODULE)
+#if defined(AHA152X_PCMCIA) || defined(MODULE)
#if !defined(AUTOCONF)
#define AUTOCONF
#endif
@@ -297,7 +297,7 @@ CMD_INC_RESID(struct scsi_cmnd *cmd, int inc)
#define DELAY_DEFAULT 1000
-#if defined(PCMCIA)
+#if defined(AHA152X_PCMCIA)
#define IRQ_MIN 0
#define IRQ_MAX 16
#else
@@ -328,7 +328,7 @@ MODULE_AUTHOR("Jürgen Fischer");
MODULE_DESCRIPTION(AHA152X_REVID);
MODULE_LICENSE("GPL");
-#if !defined(PCMCIA)
+#if !defined(AHA152X_PCMCIA)
#if defined(MODULE)
static int io[] = {0, 0};
module_param_hw_array(io, int, ioport, NULL, 0);
@@ -391,7 +391,7 @@ static struct isapnp_device_id id_table[] = {
MODULE_DEVICE_TABLE(isapnp, id_table);
#endif /* ISAPNP */
-#endif /* !PCMCIA */
+#endif /* !AHA152X_PCMCIA */
static struct scsi_host_template aha152x_driver_template;
@@ -863,7 +863,7 @@ void aha152x_release(struct Scsi_Host *shpnt)
if (shpnt->irq)
free_irq(shpnt->irq, shpnt);
-#if !defined(PCMCIA)
+#if !defined(AHA152X_PCMCIA)
if (shpnt->io_port)
release_region(shpnt->io_port, IO_RANGE);
#endif
@@ -2924,7 +2924,7 @@ static struct scsi_host_template aha152x_driver_template = {
.slave_alloc = aha152x_adjust_queue,
};
-#if !defined(PCMCIA)
+#if !defined(AHA152X_PCMCIA)
static int setup_count;
static struct aha152x_setup setup[2];
@@ -3392,4 +3392,4 @@ static int __init aha152x_setup(char *str)
__setup("aha152x=", aha152x_setup);
#endif
-#endif /* !PCMCIA */
+#endif /* !AHA152X_PCMCIA */
diff --git a/drivers/scsi/aic7xxx/aic7770.c b/drivers/scsi/aic7xxx/aic7770.c
index 5000bd69c13f..176704b24e6a 100644
--- a/drivers/scsi/aic7xxx/aic7770.c
+++ b/drivers/scsi/aic7xxx/aic7770.c
@@ -42,15 +42,9 @@
* $FreeBSD$
*/
-#ifdef __linux__
#include "aic7xxx_osm.h"
#include "aic7xxx_inline.h"
#include "aic7xxx_93cx6.h"
-#else
-#include <dev/aic7xxx/aic7xxx_osm.h>
-#include <dev/aic7xxx/aic7xxx_inline.h>
-#include <dev/aic7xxx/aic7xxx_93cx6.h>
-#endif
#define ID_AIC7770 0x04907770
#define ID_AHA_274x 0x04907771
diff --git a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h
index 31f2bb9d7146..9a515551641c 100644
--- a/drivers/scsi/aic7xxx/aic79xx.h
+++ b/drivers/scsi/aic7xxx/aic79xx.h
@@ -607,9 +607,6 @@ struct scb {
ahd_io_ctx_t io_ctx;
struct ahd_softc *ahd_softc;
scb_flag flags;
-#ifndef __linux__
- bus_dmamap_t dmamap;
-#endif
struct scb_platform_data *platform_data;
struct map_node *hscb_map;
struct map_node *sg_map;
@@ -1056,9 +1053,6 @@ struct ahd_completion
struct ahd_softc {
bus_space_tag_t tags[2];
bus_space_handle_t bshs[2];
-#ifndef __linux__
- bus_dma_tag_t buffer_dmat; /* dmat for buffer I/O */
-#endif
struct scb_data scb_data;
struct hardware_scb *next_queued_hscb;
diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c
index 2d82ec85753e..9ee75c9a9aa1 100644
--- a/drivers/scsi/aic7xxx/aic79xx_core.c
+++ b/drivers/scsi/aic7xxx/aic79xx_core.c
@@ -40,16 +40,9 @@
* $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#250 $
*/
-#ifdef __linux__
#include "aic79xx_osm.h"
#include "aic79xx_inline.h"
#include "aicasm/aicasm_insformat.h"
-#else
-#include <dev/aic7xxx/aic79xx_osm.h>
-#include <dev/aic7xxx/aic79xx_inline.h>
-#include <dev/aic7xxx/aicasm/aicasm_insformat.h>
-#endif
-
/***************************** Lookup Tables **********************************/
static const char *const ahd_chip_names[] =
@@ -59,7 +52,6 @@ static const char *const ahd_chip_names[] =
"aic7902",
"aic7901A"
};
-static const u_int num_chip_names = ARRAY_SIZE(ahd_chip_names);
/*
* Hardware error codes.
@@ -6172,17 +6164,11 @@ ahd_free(struct ahd_softc *ahd)
case 2:
ahd_dma_tag_destroy(ahd, ahd->shared_data_dmat);
case 1:
-#ifndef __linux__
- ahd_dma_tag_destroy(ahd, ahd->buffer_dmat);
-#endif
break;
case 0:
break;
}
-#ifndef __linux__
- ahd_dma_tag_destroy(ahd, ahd->parent_dmat);
-#endif
ahd_platform_free(ahd);
ahd_fini_scbdata(ahd);
for (i = 0; i < AHD_NUM_TARGETS; i++) {
@@ -6934,9 +6920,6 @@ ahd_alloc_scbs(struct ahd_softc *ahd)
for (i = 0; i < newcount; i++) {
struct scb_platform_data *pdata;
u_int col_tag;
-#ifndef __linux__
- int error;
-#endif
next_scb = kmalloc(sizeof(*next_scb), GFP_ATOMIC);
if (next_scb == NULL)
@@ -6970,15 +6953,6 @@ ahd_alloc_scbs(struct ahd_softc *ahd)
next_scb->sg_list_busaddr += sizeof(struct ahd_dma_seg);
next_scb->ahd_softc = ahd;
next_scb->flags = SCB_FLAG_NONE;
-#ifndef __linux__
- error = ahd_dmamap_create(ahd, ahd->buffer_dmat, /*flags*/0,
- &next_scb->dmamap);
- if (error != 0) {
- kfree(next_scb);
- kfree(pdata);
- break;
- }
-#endif
next_scb->hscb->tag = ahd_htole16(scb_data->numscbs);
col_tag = scb_data->numscbs ^ 0x100;
next_scb->col_scb = ahd_find_scb_by_tag(ahd, col_tag);
@@ -7091,24 +7065,6 @@ ahd_init(struct ahd_softc *ahd)
if ((AHD_TMODE_ENABLE & (0x1 << ahd->unit)) == 0)
ahd->features &= ~AHD_TARGETMODE;
-#ifndef __linux__
- /* DMA tag for mapping buffers into device visible space. */
- if (ahd_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/1,
- /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1,
- /*lowaddr*/ahd->flags & AHD_39BIT_ADDRESSING
- ? (dma_addr_t)0x7FFFFFFFFFULL
- : BUS_SPACE_MAXADDR_32BIT,
- /*highaddr*/BUS_SPACE_MAXADDR,
- /*filter*/NULL, /*filterarg*/NULL,
- /*maxsize*/(AHD_NSEG - 1) * PAGE_SIZE,
- /*nsegments*/AHD_NSEG,
- /*maxsegsz*/AHD_MAXTRANSFER_SIZE,
- /*flags*/BUS_DMA_ALLOCNOW,
- &ahd->buffer_dmat) != 0) {
- return (ENOMEM);
- }
-#endif
-
ahd->init_level++;
/*
diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c
index cc9bd26f5d1a..8397ae93f7dd 100644
--- a/drivers/scsi/aic7xxx/aic79xx_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_pci.c
@@ -41,14 +41,8 @@
* $Id: //depot/aic7xxx/aic7xxx/aic79xx_pci.c#92 $
*/
-#ifdef __linux__
#include "aic79xx_osm.h"
#include "aic79xx_inline.h"
-#else
-#include <dev/aic7xxx/aic79xx_osm.h>
-#include <dev/aic7xxx/aic79xx_inline.h>
-#endif
-
#include "aic79xx_pci.h"
static inline uint64_t
@@ -294,13 +288,11 @@ ahd_find_pci_device(ahd_dev_softc_t pci)
int
ahd_pci_config(struct ahd_softc *ahd, const struct ahd_pci_identity *entry)
{
- struct scb_data *shared_scb_data;
u_int command;
uint32_t devconfig;
uint16_t subvendor;
int error;
- shared_scb_data = NULL;
ahd->description = entry->name;
/*
* Record if this is an HP board.
diff --git a/drivers/scsi/aic7xxx/aic7xxx.h b/drivers/scsi/aic7xxx/aic7xxx.h
index 4ce4e903a759..5614921b4041 100644
--- a/drivers/scsi/aic7xxx/aic7xxx.h
+++ b/drivers/scsi/aic7xxx/aic7xxx.h
@@ -568,9 +568,6 @@ struct scb {
ahc_io_ctx_t io_ctx;
struct ahc_softc *ahc_softc;
scb_flag flags;
-#ifndef __linux__
- bus_dmamap_t dmamap;
-#endif
struct scb_platform_data *platform_data;
struct sg_map_node *sg_map;
struct ahc_dma_seg *sg_list;
@@ -906,9 +903,6 @@ typedef void ahc_callback_t (void *);
struct ahc_softc {
bus_space_tag_t tag;
bus_space_handle_t bsh;
-#ifndef __linux__
- bus_dma_tag_t buffer_dmat; /* dmat for buffer I/O */
-#endif
struct scb_data *scb_data;
struct scb *next_queued_scb;
diff --git a/drivers/scsi/aic7xxx/aic7xxx_93cx6.c b/drivers/scsi/aic7xxx/aic7xxx_93cx6.c
index 9e85a7ef9c8e..cc9e41967ce4 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_93cx6.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_93cx6.c
@@ -64,15 +64,9 @@
* bit to be sent from the chip.
*/
-#ifdef __linux__
#include "aic7xxx_osm.h"
#include "aic7xxx_inline.h"
#include "aic7xxx_93cx6.h"
-#else
-#include <dev/aic7xxx/aic7xxx_osm.h>
-#include <dev/aic7xxx/aic7xxx_inline.h>
-#include <dev/aic7xxx/aic7xxx_93cx6.h>
-#endif
/*
* Right now, we only have to read the SEEPROM. But we make it easier to
diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c
index 915a34f141e4..f3362f4ab16e 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_core.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_core.c
@@ -40,15 +40,9 @@
* $Id: //depot/aic7xxx/aic7xxx/aic7xxx.c#155 $
*/
-#ifdef __linux__
#include "aic7xxx_osm.h"
#include "aic7xxx_inline.h"
#include "aicasm/aicasm_insformat.h"
-#else
-#include <dev/aic7xxx/aic7xxx_osm.h>
-#include <dev/aic7xxx/aic7xxx_inline.h>
-#include <dev/aic7xxx/aicasm/aicasm_insformat.h>
-#endif
/***************************** Lookup Tables **********************************/
static const char *const ahc_chip_names[] = {
@@ -67,7 +61,6 @@ static const char *const ahc_chip_names[] = {
"aic7892",
"aic7899"
};
-static const u_int num_chip_names = ARRAY_SIZE(ahc_chip_names);
/*
* Hardware error codes.
@@ -4509,17 +4502,11 @@ ahc_free(struct ahc_softc *ahc)
case 2:
ahc_dma_tag_destroy(ahc, ahc->shared_data_dmat);
case 1:
-#ifndef __linux__
- ahc_dma_tag_destroy(ahc, ahc->buffer_dmat);
-#endif
break;
case 0:
break;
}
-#ifndef __linux__
- ahc_dma_tag_destroy(ahc, ahc->parent_dmat);
-#endif
ahc_platform_free(ahc);
ahc_fini_scbdata(ahc);
for (i = 0; i < AHC_NUM_TARGETS; i++) {
@@ -5005,9 +4992,7 @@ ahc_alloc_scbs(struct ahc_softc *ahc)
newcount = min(newcount, (AHC_SCB_MAX_ALLOC - scb_data->numscbs));
for (i = 0; i < newcount; i++) {
struct scb_platform_data *pdata;
-#ifndef __linux__
- int error;
-#endif
+
pdata = kmalloc(sizeof(*pdata), GFP_ATOMIC);
if (pdata == NULL)
break;
@@ -5021,12 +5006,6 @@ ahc_alloc_scbs(struct ahc_softc *ahc)
next_scb->sg_list_phys = physaddr + sizeof(struct ahc_dma_seg);
next_scb->ahc_softc = ahc;
next_scb->flags = SCB_FREE;
-#ifndef __linux__
- error = ahc_dmamap_create(ahc, ahc->buffer_dmat, /*flags*/0,
- &next_scb->dmamap);
- if (error != 0)
- break;
-#endif
next_scb->hscb = &scb_data->hscbs[scb_data->numscbs];
next_scb->hscb->tag = ahc->scb_data->numscbs;
SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs,
@@ -5325,24 +5304,6 @@ ahc_init(struct ahc_softc *ahc)
if ((AHC_TMODE_ENABLE & (0x1 << ahc->unit)) == 0)
ahc->features &= ~AHC_TARGETMODE;
-#ifndef __linux__
- /* DMA tag for mapping buffers into device visible space. */
- if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1,
- /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1,
- /*lowaddr*/ahc->flags & AHC_39BIT_ADDRESSING
- ? (dma_addr_t)0x7FFFFFFFFFULL
- : BUS_SPACE_MAXADDR_32BIT,
- /*highaddr*/BUS_SPACE_MAXADDR,
- /*filter*/NULL, /*filterarg*/NULL,
- /*maxsize*/(AHC_NSEG - 1) * PAGE_SIZE,
- /*nsegments*/AHC_NSEG,
- /*maxsegsz*/AHC_MAXTRANSFER_SIZE,
- /*flags*/BUS_DMA_ALLOCNOW,
- &ahc->buffer_dmat) != 0) {
- return (ENOMEM);
- }
-#endif
-
ahc->init_level++;
/*
diff --git a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c
index 673e826d7adb..656f680c7802 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_pci.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c
@@ -42,16 +42,9 @@
* $Id: //depot/aic7xxx/aic7xxx/aic7xxx_pci.c#79 $
*/
-#ifdef __linux__
#include "aic7xxx_osm.h"
#include "aic7xxx_inline.h"
#include "aic7xxx_93cx6.h"
-#else
-#include <dev/aic7xxx/aic7xxx_osm.h>
-#include <dev/aic7xxx/aic7xxx_inline.h>
-#include <dev/aic7xxx/aic7xxx_93cx6.h>
-#endif
-
#include "aic7xxx_pci.h"
static inline uint64_t
diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm.h b/drivers/scsi/aic7xxx/aicasm/aicasm.h
index 51678dd46ff7..716a2aefc925 100644
--- a/drivers/scsi/aic7xxx/aicasm/aicasm.h
+++ b/drivers/scsi/aic7xxx/aicasm/aicasm.h
@@ -42,11 +42,7 @@
* $FreeBSD$
*/
-#ifdef __linux__
#include "../queue.h"
-#else
-#include <sys/queue.h>
-#endif
#ifndef TRUE
#define TRUE 1
diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y b/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y
index f1586a437906..924d55a8acbf 100644
--- a/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y
+++ b/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y
@@ -52,11 +52,7 @@
#include <string.h>
#include <sysexits.h>
-#ifdef __linux__
#include "../queue.h"
-#else
-#include <sys/queue.h>
-#endif
#include "aicasm.h"
#include "aicasm_symbol.h"
diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y b/drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y
index 708326df0766..8c0479865f04 100644
--- a/drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y
+++ b/drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y
@@ -52,11 +52,7 @@
#include <string.h>
#include <sysexits.h>
-#ifdef __linux__
#include "../queue.h"
-#else
-#include <sys/queue.h>
-#endif
#include "aicasm.h"
#include "aicasm_symbol.h"
diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l b/drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l
index c0457b8c3b77..98e9959c6907 100644
--- a/drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l
+++ b/drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l
@@ -51,11 +51,7 @@
#include <stdio.h>
#include <string.h>
#include <sysexits.h>
-#ifdef __linux__
#include "../queue.h"
-#else
-#include <sys/queue.h>
-#endif
#include "aicasm.h"
#include "aicasm_symbol.h"
diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l b/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l
index 93c8667cd704..c78d4f68eea5 100644
--- a/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l
+++ b/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l
@@ -51,11 +51,7 @@
#include <stdio.h>
#include <string.h>
#include <sysexits.h>
-#ifdef __linux__
#include "../queue.h"
-#else
-#include <sys/queue.h>
-#endif
#include "aicasm.h"
#include "aicasm_symbol.h"
diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c b/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c
index 232aff1fe784..975fcfcc0d8f 100644
--- a/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c
+++ b/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c
@@ -44,11 +44,7 @@
#include <sys/types.h>
-#ifdef __linux__
#include "aicdb.h"
-#else
-#include <db.h>
-#endif
#include <fcntl.h>
#include <inttypes.h>
#include <regex.h>
diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h b/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h
index 34bbcad7f83f..7bf7fd5953ac 100644
--- a/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h
+++ b/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h
@@ -42,11 +42,7 @@
* $FreeBSD$
*/
-#ifdef __linux__
#include "../queue.h"
-#else
-#include <sys/queue.h>
-#endif
typedef enum {
UNINITIALIZED,
diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c
index 1391e5f35918..41c4d8abdd4a 100644
--- a/drivers/scsi/aic94xx/aic94xx_init.c
+++ b/drivers/scsi/aic94xx/aic94xx_init.c
@@ -771,13 +771,8 @@ static int asd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
goto Err_remove;
err = -ENODEV;
- if (!pci_set_dma_mask(dev, DMA_BIT_MASK(64))
- && !pci_set_consistent_dma_mask(dev, DMA_BIT_MASK(64)))
- ;
- else if (!pci_set_dma_mask(dev, DMA_BIT_MASK(32))
- && !pci_set_consistent_dma_mask(dev, DMA_BIT_MASK(32)))
- ;
- else {
+ if (dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(64)) ||
+ dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32))) {
asd_printk("no suitable DMA mask for %s\n", pci_name(dev));
goto Err_remove;
}
diff --git a/drivers/scsi/aic94xx/aic94xx_scb.c b/drivers/scsi/aic94xx/aic94xx_scb.c
index 22873ce8bbfa..91ea87dfb700 100644
--- a/drivers/scsi/aic94xx/aic94xx_scb.c
+++ b/drivers/scsi/aic94xx/aic94xx_scb.c
@@ -724,9 +724,11 @@ static void set_speed_mask(u8 *speed_mask, struct asd_phy_desc *pd)
switch (pd->max_sas_lrate) {
case SAS_LINK_RATE_6_0_GBPS:
*speed_mask &= ~SAS_SPEED_60_DIS;
+ /* fall through*/
default:
case SAS_LINK_RATE_3_0_GBPS:
*speed_mask &= ~SAS_SPEED_30_DIS;
+ /* fall through*/
case SAS_LINK_RATE_1_5_GBPS:
*speed_mask &= ~SAS_SPEED_15_DIS;
}
@@ -734,6 +736,7 @@ static void set_speed_mask(u8 *speed_mask, struct asd_phy_desc *pd)
switch (pd->min_sas_lrate) {
case SAS_LINK_RATE_6_0_GBPS:
*speed_mask |= SAS_SPEED_30_DIS;
+ /* fall through*/
case SAS_LINK_RATE_3_0_GBPS:
*speed_mask |= SAS_SPEED_15_DIS;
default:
@@ -745,6 +748,7 @@ static void set_speed_mask(u8 *speed_mask, struct asd_phy_desc *pd)
switch (pd->max_sata_lrate) {
case SAS_LINK_RATE_3_0_GBPS:
*speed_mask &= ~SATA_SPEED_30_DIS;
+ /* fall through*/
default:
case SAS_LINK_RATE_1_5_GBPS:
*speed_mask &= ~SATA_SPEED_15_DIS;
@@ -803,6 +807,7 @@ void asd_build_control_phy(struct asd_ascb *ascb, int phy_id, u8 subfunc)
/* link reset retries, this should be nominal */
control_phy->link_reset_retries = 10;
+ /* fall through */
case RELEASE_SPINUP_HOLD: /* 0x02 */
/* decide the func_mask */
diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c
index cdd4ab683be9..7fea344531f6 100644
--- a/drivers/scsi/aic94xx/aic94xx_task.c
+++ b/drivers/scsi/aic94xx/aic94xx_task.c
@@ -42,13 +42,13 @@ static void asd_can_dequeue(struct asd_ha_struct *asd_ha, int num)
spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags);
}
-/* PCI_DMA_... to our direction translation.
+/* DMA_... to our direction translation.
*/
static const u8 data_dir_flags[] = {
- [PCI_DMA_BIDIRECTIONAL] = DATA_DIR_BYRECIPIENT, /* UNSPECIFIED */
- [PCI_DMA_TODEVICE] = DATA_DIR_OUT, /* OUTBOUND */
- [PCI_DMA_FROMDEVICE] = DATA_DIR_IN, /* INBOUND */
- [PCI_DMA_NONE] = DATA_DIR_NONE, /* NO TRANSFER */
+ [DMA_BIDIRECTIONAL] = DATA_DIR_BYRECIPIENT, /* UNSPECIFIED */
+ [DMA_TO_DEVICE] = DATA_DIR_OUT, /* OUTBOUND */
+ [DMA_FROM_DEVICE] = DATA_DIR_IN, /* INBOUND */
+ [DMA_NONE] = DATA_DIR_NONE, /* NO TRANSFER */
};
static int asd_map_scatterlist(struct sas_task *task,
@@ -60,12 +60,12 @@ static int asd_map_scatterlist(struct sas_task *task,
struct scatterlist *sc;
int num_sg, res;
- if (task->data_dir == PCI_DMA_NONE)
+ if (task->data_dir == DMA_NONE)
return 0;
if (task->num_scatter == 0) {
void *p = task->scatter;
- dma_addr_t dma = pci_map_single(asd_ha->pcidev, p,
+ dma_addr_t dma = dma_map_single(&asd_ha->pcidev->dev, p,
task->total_xfer_len,
task->data_dir);
sg_arr[0].bus_addr = cpu_to_le64((u64)dma);
@@ -79,7 +79,7 @@ static int asd_map_scatterlist(struct sas_task *task,
if (sas_protocol_ata(task->task_proto))
num_sg = task->num_scatter;
else
- num_sg = pci_map_sg(asd_ha->pcidev, task->scatter,
+ num_sg = dma_map_sg(&asd_ha->pcidev->dev, task->scatter,
task->num_scatter, task->data_dir);
if (num_sg == 0)
return -ENOMEM;
@@ -126,8 +126,8 @@ static int asd_map_scatterlist(struct sas_task *task,
return 0;
err_unmap:
if (sas_protocol_ata(task->task_proto))
- pci_unmap_sg(asd_ha->pcidev, task->scatter, task->num_scatter,
- task->data_dir);
+ dma_unmap_sg(&asd_ha->pcidev->dev, task->scatter,
+ task->num_scatter, task->data_dir);
return res;
}
@@ -136,21 +136,21 @@ static void asd_unmap_scatterlist(struct asd_ascb *ascb)
struct asd_ha_struct *asd_ha = ascb->ha;
struct sas_task *task = ascb->uldd_task;
- if (task->data_dir == PCI_DMA_NONE)
+ if (task->data_dir == DMA_NONE)
return;
if (task->num_scatter == 0) {
dma_addr_t dma = (dma_addr_t)
le64_to_cpu(ascb->scb->ssp_task.sg_element[0].bus_addr);
- pci_unmap_single(ascb->ha->pcidev, dma, task->total_xfer_len,
- task->data_dir);
+ dma_unmap_single(&ascb->ha->pcidev->dev, dma,
+ task->total_xfer_len, task->data_dir);
return;
}
asd_free_coherent(asd_ha, ascb->sg_arr);
if (task->task_proto != SAS_PROTOCOL_STP)
- pci_unmap_sg(asd_ha->pcidev, task->scatter, task->num_scatter,
- task->data_dir);
+ dma_unmap_sg(&asd_ha->pcidev->dev, task->scatter,
+ task->num_scatter, task->data_dir);
}
/* ---------- Task complete tasklet ---------- */
@@ -436,10 +436,10 @@ static int asd_build_smp_ascb(struct asd_ascb *ascb, struct sas_task *task,
struct domain_device *dev = task->dev;
struct scb *scb;
- pci_map_sg(asd_ha->pcidev, &task->smp_task.smp_req, 1,
- PCI_DMA_TODEVICE);
- pci_map_sg(asd_ha->pcidev, &task->smp_task.smp_resp, 1,
- PCI_DMA_FROMDEVICE);
+ dma_map_sg(&asd_ha->pcidev->dev, &task->smp_task.smp_req, 1,
+ DMA_TO_DEVICE);
+ dma_map_sg(&asd_ha->pcidev->dev, &task->smp_task.smp_resp, 1,
+ DMA_FROM_DEVICE);
scb = ascb->scb;
@@ -471,10 +471,10 @@ static void asd_unbuild_smp_ascb(struct asd_ascb *a)
struct sas_task *task = a->uldd_task;
BUG_ON(!task);
- pci_unmap_sg(a->ha->pcidev, &task->smp_task.smp_req, 1,
- PCI_DMA_TODEVICE);
- pci_unmap_sg(a->ha->pcidev, &task->smp_task.smp_resp, 1,
- PCI_DMA_FROMDEVICE);
+ dma_unmap_sg(&a->ha->pcidev->dev, &task->smp_task.smp_req, 1,
+ DMA_TO_DEVICE);
+ dma_unmap_sg(&a->ha->pcidev->dev, &task->smp_task.smp_resp, 1,
+ DMA_FROM_DEVICE);
}
/* ---------- SSP ---------- */
diff --git a/drivers/scsi/am53c974.c b/drivers/scsi/am53c974.c
index d81ca66e24d6..27c0a4a937d9 100644
--- a/drivers/scsi/am53c974.c
+++ b/drivers/scsi/am53c974.c
@@ -96,9 +96,7 @@ static void pci_esp_dma_drain(struct esp *esp);
static inline struct pci_esp_priv *pci_esp_get_priv(struct esp *esp)
{
- struct pci_dev *pdev = esp->dev;
-
- return pci_get_drvdata(pdev);
+ return dev_get_drvdata(esp->dev);
}
static void pci_esp_write8(struct esp *esp, u8 val, unsigned long reg)
@@ -116,30 +114,6 @@ static void pci_esp_write32(struct esp *esp, u32 val, unsigned long reg)
return iowrite32(val, esp->regs + (reg * 4UL));
}
-static dma_addr_t pci_esp_map_single(struct esp *esp, void *buf,
- size_t sz, int dir)
-{
- return pci_map_single(esp->dev, buf, sz, dir);
-}
-
-static int pci_esp_map_sg(struct esp *esp, struct scatterlist *sg,
- int num_sg, int dir)
-{
- return pci_map_sg(esp->dev, sg, num_sg, dir);
-}
-
-static void pci_esp_unmap_single(struct esp *esp, dma_addr_t addr,
- size_t sz, int dir)
-{
- pci_unmap_single(esp->dev, addr, sz, dir);
-}
-
-static void pci_esp_unmap_sg(struct esp *esp, struct scatterlist *sg,
- int num_sg, int dir)
-{
- pci_unmap_sg(esp->dev, sg, num_sg, dir);
-}
-
static int pci_esp_irq_pending(struct esp *esp)
{
struct pci_esp_priv *pep = pci_esp_get_priv(esp);
@@ -295,10 +269,6 @@ static u32 pci_esp_dma_length_limit(struct esp *esp, u32 dma_addr, u32 dma_len)
static const struct esp_driver_ops pci_esp_ops = {
.esp_write8 = pci_esp_write8,
.esp_read8 = pci_esp_read8,
- .map_single = pci_esp_map_single,
- .map_sg = pci_esp_map_sg,
- .unmap_single = pci_esp_unmap_single,
- .unmap_sg = pci_esp_unmap_sg,
.irq_pending = pci_esp_irq_pending,
.reset_dma = pci_esp_reset_dma,
.dma_drain = pci_esp_dma_drain,
@@ -375,18 +345,18 @@ static void dc390_read_eeprom(struct pci_dev *pdev, u16 *ptr)
static void dc390_check_eeprom(struct esp *esp)
{
+ struct pci_dev *pdev = to_pci_dev(esp->dev);
u8 EEbuf[128];
u16 *ptr = (u16 *)EEbuf, wval = 0;
int i;
- dc390_read_eeprom((struct pci_dev *)esp->dev, ptr);
+ dc390_read_eeprom(pdev, ptr);
for (i = 0; i < DC390_EEPROM_LEN; i++, ptr++)
wval += *ptr;
/* no Tekram EEprom found */
if (wval != 0x1234) {
- struct pci_dev *pdev = esp->dev;
dev_printk(KERN_INFO, &pdev->dev,
"No valid Tekram EEprom found\n");
return;
@@ -411,7 +381,7 @@ static int pci_esp_probe_one(struct pci_dev *pdev,
return -ENODEV;
}
- if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
+ if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) {
dev_printk(KERN_INFO, &pdev->dev,
"failed to set 32bit DMA mask\n");
goto fail_disable_device;
@@ -435,7 +405,7 @@ static int pci_esp_probe_one(struct pci_dev *pdev,
esp = shost_priv(shost);
esp->host = shost;
- esp->dev = pdev;
+ esp->dev = &pdev->dev;
esp->ops = &pci_esp_ops;
/*
* The am53c974 HBA has a design flaw of generating
@@ -467,8 +437,8 @@ static int pci_esp_probe_one(struct pci_dev *pdev,
pci_set_master(pdev);
- esp->command_block = pci_alloc_consistent(pdev, 16,
- &esp->command_block_dma);
+ esp->command_block = dma_alloc_coherent(&pdev->dev, 16,
+ &esp->command_block_dma, GFP_KERNEL);
if (!esp->command_block) {
dev_printk(KERN_ERR, &pdev->dev,
"failed to allocate command block\n");
@@ -498,7 +468,7 @@ static int pci_esp_probe_one(struct pci_dev *pdev,
/* Assume 40MHz clock */
esp->cfreq = 40000000;
- err = scsi_esp_register(esp, &pdev->dev);
+ err = scsi_esp_register(esp);
if (err)
goto fail_free_irq;
@@ -508,8 +478,8 @@ fail_free_irq:
free_irq(pdev->irq, esp);
fail_unmap_command_block:
pci_set_drvdata(pdev, NULL);
- pci_free_consistent(pdev, 16, esp->command_block,
- esp->command_block_dma);
+ dma_free_coherent(&pdev->dev, 16, esp->command_block,
+ esp->command_block_dma);
fail_unmap_regs:
pci_iounmap(pdev, esp->regs);
fail_release_regions:
@@ -532,8 +502,8 @@ static void pci_esp_remove_one(struct pci_dev *pdev)
scsi_esp_unregister(esp);
free_irq(pdev->irq, esp);
pci_set_drvdata(pdev, NULL);
- pci_free_consistent(pdev, 16, esp->command_block,
- esp->command_block_dma);
+ dma_free_coherent(&pdev->dev, 16, esp->command_block,
+ esp->command_block_dma);
pci_iounmap(pdev, esp->regs);
pci_release_regions(pdev);
pci_disable_device(pdev);
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index 12316ef4c893..d4404eea24fb 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -1317,13 +1317,10 @@ static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb,
static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, struct CommandControlBlock *pCCB, bool error)
{
- int id, lun;
if ((pCCB->acb != acb) || (pCCB->startdone != ARCMSR_CCB_START)) {
if (pCCB->startdone == ARCMSR_CCB_ABORTED) {
struct scsi_cmnd *abortcmd = pCCB->pcmd;
if (abortcmd) {
- id = abortcmd->device->id;
- lun = abortcmd->device->lun;
abortcmd->result |= DID_ABORT << 16;
arcmsr_ccb_complete(pCCB);
printk(KERN_NOTICE "arcmsr%d: pCCB ='0x%p' isr got aborted command \n",
@@ -1798,7 +1795,7 @@ static void arcmsr_hbaA_stop_bgrb(struct AdapterControlBlock *acb)
writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, &reg->inbound_msgaddr0);
if (!arcmsr_hbaA_wait_msgint_ready(acb)) {
printk(KERN_NOTICE
- "arcmsr%d: wait 'stop adapter background rebulid' timeout\n"
+ "arcmsr%d: wait 'stop adapter background rebuild' timeout\n"
, acb->host->host_no);
}
}
@@ -1811,7 +1808,7 @@ static void arcmsr_hbaB_stop_bgrb(struct AdapterControlBlock *acb)
if (!arcmsr_hbaB_wait_msgint_ready(acb)) {
printk(KERN_NOTICE
- "arcmsr%d: wait 'stop adapter background rebulid' timeout\n"
+ "arcmsr%d: wait 'stop adapter background rebuild' timeout\n"
, acb->host->host_no);
}
}
@@ -1824,7 +1821,7 @@ static void arcmsr_hbaC_stop_bgrb(struct AdapterControlBlock *pACB)
writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &reg->inbound_doorbell);
if (!arcmsr_hbaC_wait_msgint_ready(pACB)) {
printk(KERN_NOTICE
- "arcmsr%d: wait 'stop adapter background rebulid' timeout\n"
+ "arcmsr%d: wait 'stop adapter background rebuild' timeout\n"
, pACB->host->host_no);
}
return;
@@ -1837,7 +1834,7 @@ static void arcmsr_hbaD_stop_bgrb(struct AdapterControlBlock *pACB)
pACB->acb_flags &= ~ACB_F_MSG_START_BGRB;
writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, reg->inbound_msgaddr0);
if (!arcmsr_hbaD_wait_msgint_ready(pACB))
- pr_notice("arcmsr%d: wait 'stop adapter background rebulid' "
+ pr_notice("arcmsr%d: wait 'stop adapter background rebuild' "
"timeout\n", pACB->host->host_no);
}
@@ -1850,7 +1847,7 @@ static void arcmsr_hbaE_stop_bgrb(struct AdapterControlBlock *pACB)
pACB->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_MESSAGE_CMD_DONE;
writel(pACB->out_doorbell, &reg->iobound_doorbell);
if (!arcmsr_hbaE_wait_msgint_ready(pACB)) {
- pr_notice("arcmsr%d: wait 'stop adapter background rebulid' "
+ pr_notice("arcmsr%d: wait 'stop adapter background rebuild' "
"timeout\n", pACB->host->host_no);
}
}
@@ -3927,7 +3924,7 @@ static void arcmsr_hbaA_start_bgrb(struct AdapterControlBlock *acb)
writel(ARCMSR_INBOUND_MESG0_START_BGRB, &reg->inbound_msgaddr0);
if (!arcmsr_hbaA_wait_msgint_ready(acb)) {
printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \
- rebulid' timeout \n", acb->host->host_no);
+ rebuild' timeout \n", acb->host->host_no);
}
}
@@ -3938,7 +3935,7 @@ static void arcmsr_hbaB_start_bgrb(struct AdapterControlBlock *acb)
writel(ARCMSR_MESSAGE_START_BGRB, reg->drv2iop_doorbell);
if (!arcmsr_hbaB_wait_msgint_ready(acb)) {
printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \
- rebulid' timeout \n",acb->host->host_no);
+ rebuild' timeout \n",acb->host->host_no);
}
}
@@ -3950,7 +3947,7 @@ static void arcmsr_hbaC_start_bgrb(struct AdapterControlBlock *pACB)
writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &phbcmu->inbound_doorbell);
if (!arcmsr_hbaC_wait_msgint_ready(pACB)) {
printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \
- rebulid' timeout \n", pACB->host->host_no);
+ rebuild' timeout \n", pACB->host->host_no);
}
return;
}
@@ -3963,7 +3960,7 @@ static void arcmsr_hbaD_start_bgrb(struct AdapterControlBlock *pACB)
writel(ARCMSR_INBOUND_MESG0_START_BGRB, pmu->inbound_msgaddr0);
if (!arcmsr_hbaD_wait_msgint_ready(pACB)) {
pr_notice("arcmsr%d: wait 'start adapter "
- "background rebulid' timeout\n", pACB->host->host_no);
+ "background rebuild' timeout\n", pACB->host->host_no);
}
}
@@ -3977,7 +3974,7 @@ static void arcmsr_hbaE_start_bgrb(struct AdapterControlBlock *pACB)
writel(pACB->out_doorbell, &pmu->iobound_doorbell);
if (!arcmsr_hbaE_wait_msgint_ready(pACB)) {
pr_notice("arcmsr%d: wait 'start adapter "
- "background rebulid' timeout \n", pACB->host->host_no);
+ "background rebuild' timeout \n", pACB->host->host_no);
}
}
@@ -4135,9 +4132,9 @@ static void arcmsr_hardware_reset(struct AdapterControlBlock *acb)
pci_read_config_byte(acb->pdev, i, &value[i]);
}
/* hardware reset signal */
- if ((acb->dev_id == 0x1680)) {
+ if (acb->dev_id == 0x1680) {
writel(ARCMSR_ARC1680_BUS_RESET, &pmuA->reserved1[0]);
- } else if ((acb->dev_id == 0x1880)) {
+ } else if (acb->dev_id == 0x1880) {
do {
count++;
writel(0xF, &pmuC->write_sequence);
@@ -4161,7 +4158,7 @@ static void arcmsr_hardware_reset(struct AdapterControlBlock *acb)
} while (((readl(&pmuE->host_diagnostic_3xxx) &
ARCMSR_ARC1884_DiagWrite_ENABLE) == 0) && (count < 5));
writel(ARCMSR_ARC188X_RESET_ADAPTER, &pmuE->host_diagnostic_3xxx);
- } else if ((acb->dev_id == 0x1214)) {
+ } else if (acb->dev_id == 0x1214) {
writel(0x20, pmuD->reset_request);
} else {
pci_write_config_byte(acb->pdev, 0x84, 0x20);
diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c
index 8996d2329e11..802d15018ec0 100644
--- a/drivers/scsi/atp870u.c
+++ b/drivers/scsi/atp870u.c
@@ -1193,7 +1193,7 @@ static void atp870u_free_tables(struct Scsi_Host *host)
for (k = 0; k < 16; k++) {
if (!atp_dev->id[j][k].prd_table)
continue;
- pci_free_consistent(atp_dev->pdev, 1024, atp_dev->id[j][k].prd_table, atp_dev->id[j][k].prd_bus);
+ dma_free_coherent(&atp_dev->pdev->dev, 1024, atp_dev->id[j][k].prd_table, atp_dev->id[j][k].prd_bus);
atp_dev->id[j][k].prd_table = NULL;
}
}
@@ -1205,7 +1205,7 @@ static int atp870u_init_tables(struct Scsi_Host *host)
int c,k;
for(c=0;c < 2;c++) {
for(k=0;k<16;k++) {
- atp_dev->id[c][k].prd_table = pci_alloc_consistent(atp_dev->pdev, 1024, &(atp_dev->id[c][k].prd_bus));
+ atp_dev->id[c][k].prd_table = dma_alloc_coherent(&atp_dev->pdev->dev, 1024, &(atp_dev->id[c][k].prd_bus), GFP_KERNEL);
if (!atp_dev->id[c][k].prd_table) {
printk("atp870u_init_tables fail\n");
atp870u_free_tables(host);
@@ -1509,7 +1509,7 @@ static int atp870u_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (err)
goto fail;
- if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
+ if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) {
printk(KERN_ERR "atp870u: DMA mask required but not available.\n");
err = -EIO;
goto disable_device;
diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c
index c10aac4dbc5e..0a6972ee94d7 100644
--- a/drivers/scsi/be2iscsi/be_cmds.c
+++ b/drivers/scsi/be2iscsi/be_cmds.c
@@ -520,7 +520,7 @@ int beiscsi_process_mcc_compl(struct be_ctrl_info *ctrl,
**/
tag_mem = &ctrl->ptag_state[tag].tag_mem_state;
if (tag_mem->size) {
- pci_free_consistent(ctrl->pdev, tag_mem->size,
+ dma_free_coherent(&ctrl->pdev->dev, tag_mem->size,
tag_mem->va, tag_mem->dma);
tag_mem->size = 0;
}
@@ -1269,12 +1269,12 @@ int beiscsi_check_supported_fw(struct be_ctrl_info *ctrl,
struct be_sge *sge = nonembedded_sgl(wrb);
int status = 0;
- nonemb_cmd.va = pci_alloc_consistent(ctrl->pdev,
+ nonemb_cmd.va = dma_alloc_coherent(&ctrl->pdev->dev,
sizeof(struct be_mgmt_controller_attributes),
- &nonemb_cmd.dma);
+ &nonemb_cmd.dma, GFP_KERNEL);
if (nonemb_cmd.va == NULL) {
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
- "BG_%d : pci_alloc_consistent failed in %s\n",
+ "BG_%d : dma_alloc_coherent failed in %s\n",
__func__);
return -ENOMEM;
}
@@ -1314,7 +1314,7 @@ int beiscsi_check_supported_fw(struct be_ctrl_info *ctrl,
"BG_%d : Failed in beiscsi_check_supported_fw\n");
mutex_unlock(&ctrl->mbox_lock);
if (nonemb_cmd.va)
- pci_free_consistent(ctrl->pdev, nonemb_cmd.size,
+ dma_free_coherent(&ctrl->pdev->dev, nonemb_cmd.size,
nonemb_cmd.va, nonemb_cmd.dma);
return status;
diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c
index c8f0a2144b44..96b96e2ab91a 100644
--- a/drivers/scsi/be2iscsi/be_iscsi.c
+++ b/drivers/scsi/be2iscsi/be_iscsi.c
@@ -771,7 +771,7 @@ int beiscsi_get_host_param(struct Scsi_Host *shost,
status = beiscsi_get_initiator_name(phba, buf, false);
if (status < 0) {
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
- "BS_%d : Retreiving Initiator Name Failed\n");
+ "BS_%d : Retrieving Initiator Name Failed\n");
status = 0;
}
}
@@ -1071,9 +1071,9 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep,
else
req_memsize = sizeof(struct tcp_connect_and_offload_in_v1);
- nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev,
+ nonemb_cmd.va = dma_alloc_coherent(&phba->ctrl.pdev->dev,
req_memsize,
- &nonemb_cmd.dma);
+ &nonemb_cmd.dma, GFP_KERNEL);
if (nonemb_cmd.va == NULL) {
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
@@ -1091,7 +1091,7 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep,
"BS_%d : mgmt_open_connection Failed for cid=%d\n",
beiscsi_ep->ep_cid);
- pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+ dma_free_coherent(&phba->ctrl.pdev->dev, nonemb_cmd.size,
nonemb_cmd.va, nonemb_cmd.dma);
beiscsi_free_ep(beiscsi_ep);
return -EAGAIN;
@@ -1104,8 +1104,9 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep,
"BS_%d : mgmt_open_connection Failed");
if (ret != -EBUSY)
- pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
- nonemb_cmd.va, nonemb_cmd.dma);
+ dma_free_coherent(&phba->ctrl.pdev->dev,
+ nonemb_cmd.size, nonemb_cmd.va,
+ nonemb_cmd.dma);
beiscsi_free_ep(beiscsi_ep);
return ret;
@@ -1118,7 +1119,7 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep,
beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
"BS_%d : mgmt_open_connection Success\n");
- pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+ dma_free_coherent(&phba->ctrl.pdev->dev, nonemb_cmd.size,
nonemb_cmd.va, nonemb_cmd.dma);
return 0;
}
diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index 3660059784f7..effb6fc95af4 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -511,18 +511,9 @@ static int beiscsi_enable_pci(struct pci_dev *pcidev)
}
pci_set_master(pcidev);
- ret = pci_set_dma_mask(pcidev, DMA_BIT_MASK(64));
+ ret = dma_set_mask_and_coherent(&pcidev->dev, DMA_BIT_MASK(64));
if (ret) {
- ret = pci_set_dma_mask(pcidev, DMA_BIT_MASK(32));
- if (ret) {
- dev_err(&pcidev->dev, "Could not set PCI DMA Mask\n");
- goto pci_region_release;
- } else {
- ret = pci_set_consistent_dma_mask(pcidev,
- DMA_BIT_MASK(32));
- }
- } else {
- ret = pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(64));
+ ret = dma_set_mask_and_coherent(&pcidev->dev, DMA_BIT_MASK(32));
if (ret) {
dev_err(&pcidev->dev, "Could not set PCI DMA Mask\n");
goto pci_region_release;
@@ -550,9 +541,8 @@ static int be_ctrl_init(struct beiscsi_hba *phba, struct pci_dev *pdev)
if (status)
return status;
mbox_mem_alloc->size = sizeof(struct be_mcc_mailbox) + 16;
- mbox_mem_alloc->va = pci_alloc_consistent(pdev,
- mbox_mem_alloc->size,
- &mbox_mem_alloc->dma);
+ mbox_mem_alloc->va = dma_alloc_coherent(&pdev->dev,
+ mbox_mem_alloc->size, &mbox_mem_alloc->dma, GFP_KERNEL);
if (!mbox_mem_alloc->va) {
beiscsi_unmap_pci_function(phba);
return -ENOMEM;
@@ -1866,7 +1856,6 @@ unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq, int budget)
{
struct be_queue_info *cq;
struct sol_cqe *sol;
- struct dmsg_cqe *dmsg;
unsigned int total = 0;
unsigned int num_processed = 0;
unsigned short code = 0, cid = 0;
@@ -1939,7 +1928,6 @@ unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq, int budget)
"BM_%d : Received %s[%d] on CID : %d\n",
cqe_desc[code], code, cid);
- dmsg = (struct dmsg_cqe *)sol;
hwi_complete_drvr_msgs(beiscsi_conn, phba, sol);
break;
case UNSOL_HDR_NOTIFY:
@@ -2304,11 +2292,11 @@ static int hwi_write_buffer(struct iscsi_wrb *pwrb, struct iscsi_task *task)
/* Map addr only if there is data_count */
if (dsp_value) {
- io_task->mtask_addr = pci_map_single(phba->pcidev,
+ io_task->mtask_addr = dma_map_single(&phba->pcidev->dev,
task->data,
task->data_count,
- PCI_DMA_TODEVICE);
- if (pci_dma_mapping_error(phba->pcidev,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(&phba->pcidev->dev,
io_task->mtask_addr))
return -ENOMEM;
io_task->mtask_data_count = task->data_count;
@@ -2519,10 +2507,9 @@ static int beiscsi_alloc_mem(struct beiscsi_hba *phba)
BEISCSI_MAX_FRAGS_INIT);
curr_alloc_size = min(be_max_phys_size * 1024, alloc_size);
do {
- mem_arr->virtual_address = pci_alloc_consistent(
- phba->pcidev,
- curr_alloc_size,
- &bus_add);
+ mem_arr->virtual_address =
+ dma_alloc_coherent(&phba->pcidev->dev,
+ curr_alloc_size, &bus_add, GFP_KERNEL);
if (!mem_arr->virtual_address) {
if (curr_alloc_size <= BE_MIN_MEM_SIZE)
goto free_mem;
@@ -2560,7 +2547,7 @@ free_mem:
mem_descr->num_elements = j;
while ((i) || (j)) {
for (j = mem_descr->num_elements; j > 0; j--) {
- pci_free_consistent(phba->pcidev,
+ dma_free_coherent(&phba->pcidev->dev,
mem_descr->mem_array[j - 1].size,
mem_descr->mem_array[j - 1].
virtual_address,
@@ -3031,9 +3018,9 @@ static int beiscsi_create_eqs(struct beiscsi_hba *phba,
eq = &phwi_context->be_eq[i].q;
mem = &eq->dma_mem;
phwi_context->be_eq[i].phba = phba;
- eq_vaddress = pci_alloc_consistent(phba->pcidev,
+ eq_vaddress = dma_alloc_coherent(&phba->pcidev->dev,
num_eq_pages * PAGE_SIZE,
- &paddr);
+ &paddr, GFP_KERNEL);
if (!eq_vaddress) {
ret = -ENOMEM;
goto create_eq_error;
@@ -3069,7 +3056,7 @@ create_eq_error:
eq = &phwi_context->be_eq[i].q;
mem = &eq->dma_mem;
if (mem->va)
- pci_free_consistent(phba->pcidev, num_eq_pages
+ dma_free_coherent(&phba->pcidev->dev, num_eq_pages
* PAGE_SIZE,
mem->va, mem->dma);
}
@@ -3097,9 +3084,9 @@ static int beiscsi_create_cqs(struct beiscsi_hba *phba,
pbe_eq->cq = cq;
pbe_eq->phba = phba;
mem = &cq->dma_mem;
- cq_vaddress = pci_alloc_consistent(phba->pcidev,
+ cq_vaddress = dma_alloc_coherent(&phba->pcidev->dev,
num_cq_pages * PAGE_SIZE,
- &paddr);
+ &paddr, GFP_KERNEL);
if (!cq_vaddress) {
ret = -ENOMEM;
goto create_cq_error;
@@ -3134,7 +3121,7 @@ create_cq_error:
cq = &phwi_context->be_cq[i];
mem = &cq->dma_mem;
if (mem->va)
- pci_free_consistent(phba->pcidev, num_cq_pages
+ dma_free_coherent(&phba->pcidev->dev, num_cq_pages
* PAGE_SIZE,
mem->va, mem->dma);
}
@@ -3326,7 +3313,7 @@ static void be_queue_free(struct beiscsi_hba *phba, struct be_queue_info *q)
{
struct be_dma_mem *mem = &q->dma_mem;
if (mem->va) {
- pci_free_consistent(phba->pcidev, mem->size,
+ dma_free_coherent(&phba->pcidev->dev, mem->size,
mem->va, mem->dma);
mem->va = NULL;
}
@@ -3341,7 +3328,8 @@ static int be_queue_alloc(struct beiscsi_hba *phba, struct be_queue_info *q,
q->len = len;
q->entry_size = entry_size;
mem->size = len * entry_size;
- mem->va = pci_zalloc_consistent(phba->pcidev, mem->size, &mem->dma);
+ mem->va = dma_zalloc_coherent(&phba->pcidev->dev, mem->size, &mem->dma,
+ GFP_KERNEL);
if (!mem->va)
return -ENOMEM;
return 0;
@@ -3479,7 +3467,7 @@ static void be_mcc_queues_destroy(struct beiscsi_hba *phba)
&ctrl->ptag_state[tag].tag_state)) {
ptag_mem = &ctrl->ptag_state[tag].tag_mem_state;
if (ptag_mem->size) {
- pci_free_consistent(ctrl->pdev,
+ dma_free_coherent(&ctrl->pdev->dev,
ptag_mem->size,
ptag_mem->va,
ptag_mem->dma);
@@ -3880,7 +3868,7 @@ static void beiscsi_free_mem(struct beiscsi_hba *phba)
j = 0;
for (i = 0; i < SE_MEM_MAX; i++) {
for (j = mem_descr->num_elements; j > 0; j--) {
- pci_free_consistent(phba->pcidev,
+ dma_free_coherent(&phba->pcidev->dev,
mem_descr->mem_array[j - 1].size,
mem_descr->mem_array[j - 1].virtual_address,
(unsigned long)mem_descr->mem_array[j - 1].
@@ -4255,10 +4243,10 @@ beiscsi_free_mgmt_task_handles(struct beiscsi_conn *beiscsi_conn,
}
if (io_task->mtask_addr) {
- pci_unmap_single(phba->pcidev,
+ dma_unmap_single(&phba->pcidev->dev,
io_task->mtask_addr,
io_task->mtask_data_count,
- PCI_DMA_TODEVICE);
+ DMA_TO_DEVICE);
io_task->mtask_addr = 0;
}
}
@@ -4852,9 +4840,9 @@ static int beiscsi_bsg_request(struct bsg_job *job)
switch (bsg_req->msgcode) {
case ISCSI_BSG_HST_VENDOR:
- nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev,
+ nonemb_cmd.va = dma_alloc_coherent(&phba->ctrl.pdev->dev,
job->request_payload.payload_len,
- &nonemb_cmd.dma);
+ &nonemb_cmd.dma, GFP_KERNEL);
if (nonemb_cmd.va == NULL) {
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
"BM_%d : Failed to allocate memory for "
@@ -4867,7 +4855,7 @@ static int beiscsi_bsg_request(struct bsg_job *job)
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
"BM_%d : MBX Tag Allocation Failed\n");
- pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+ dma_free_coherent(&phba->ctrl.pdev->dev, nonemb_cmd.size,
nonemb_cmd.va, nonemb_cmd.dma);
return -EAGAIN;
}
@@ -4881,7 +4869,7 @@ static int beiscsi_bsg_request(struct bsg_job *job)
if (!test_bit(BEISCSI_HBA_ONLINE, &phba->state)) {
clear_bit(MCC_TAG_STATE_RUNNING,
&phba->ctrl.ptag_state[tag].tag_state);
- pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+ dma_free_coherent(&phba->ctrl.pdev->dev, nonemb_cmd.size,
nonemb_cmd.va, nonemb_cmd.dma);
return -EIO;
}
@@ -4898,7 +4886,7 @@ static int beiscsi_bsg_request(struct bsg_job *job)
bsg_reply->result = status;
bsg_job_done(job, bsg_reply->result,
bsg_reply->reply_payload_rcv_len);
- pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+ dma_free_coherent(&phba->ctrl.pdev->dev, nonemb_cmd.size,
nonemb_cmd.va, nonemb_cmd.dma);
if (status || extd_status) {
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
@@ -5529,7 +5517,6 @@ static pci_ers_result_t beiscsi_eeh_reset(struct pci_dev *pdev)
return PCI_ERS_RESULT_DISCONNECT;
}
- pci_cleanup_aer_uncorrect_error_status(pdev);
return PCI_ERS_RESULT_RECOVERED;
}
@@ -5755,7 +5742,7 @@ free_twq:
beiscsi_cleanup_port(phba);
beiscsi_free_mem(phba);
free_port:
- pci_free_consistent(phba->pcidev,
+ dma_free_coherent(&phba->pcidev->dev,
phba->ctrl.mbox_mem_alloced.size,
phba->ctrl.mbox_mem_alloced.va,
phba->ctrl.mbox_mem_alloced.dma);
@@ -5799,7 +5786,7 @@ static void beiscsi_remove(struct pci_dev *pcidev)
/* ctrl uninit */
beiscsi_unmap_pci_function(phba);
- pci_free_consistent(phba->pcidev,
+ dma_free_coherent(&phba->pcidev->dev,
phba->ctrl.mbox_mem_alloced.size,
phba->ctrl.mbox_mem_alloced.va,
phba->ctrl.mbox_mem_alloced.dma);
diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c
index 8fdc07b6c686..ca7b7bbc8371 100644
--- a/drivers/scsi/be2iscsi/be_mgmt.c
+++ b/drivers/scsi/be2iscsi/be_mgmt.c
@@ -284,7 +284,7 @@ static int beiscsi_exec_nemb_cmd(struct beiscsi_hba *phba,
return rc;
free_cmd:
- pci_free_consistent(ctrl->pdev, nonemb_cmd->size,
+ dma_free_coherent(&ctrl->pdev->dev, nonemb_cmd->size,
nonemb_cmd->va, nonemb_cmd->dma);
return rc;
}
@@ -293,7 +293,8 @@ static int beiscsi_prep_nemb_cmd(struct beiscsi_hba *phba,
struct be_dma_mem *cmd,
u8 subsystem, u8 opcode, u32 size)
{
- cmd->va = pci_zalloc_consistent(phba->ctrl.pdev, size, &cmd->dma);
+ cmd->va = dma_zalloc_coherent(&phba->ctrl.pdev->dev, size, &cmd->dma,
+ GFP_KERNEL);
if (!cmd->va) {
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
"BG_%d : Failed to allocate memory for if info\n");
@@ -315,7 +316,7 @@ static void __beiscsi_eq_delay_compl(struct beiscsi_hba *phba, unsigned int tag)
__beiscsi_mcc_compl_status(phba, tag, NULL, NULL);
tag_mem = &phba->ctrl.ptag_state[tag].tag_mem_state;
if (tag_mem->size) {
- pci_free_consistent(phba->pcidev, tag_mem->size,
+ dma_free_coherent(&phba->pcidev->dev, tag_mem->size,
tag_mem->va, tag_mem->dma);
tag_mem->size = 0;
}
@@ -761,7 +762,7 @@ int beiscsi_if_get_info(struct beiscsi_hba *phba, int ip_type,
"BG_%d : Memory Allocation Failure\n");
/* Free the DMA memory for the IOCTL issuing */
- pci_free_consistent(phba->ctrl.pdev,
+ dma_free_coherent(&phba->ctrl.pdev->dev,
nonemb_cmd.size,
nonemb_cmd.va,
nonemb_cmd.dma);
@@ -780,7 +781,7 @@ int beiscsi_if_get_info(struct beiscsi_hba *phba, int ip_type,
ioctl_size += sizeof(struct be_cmd_req_hdr);
/* Free the previous allocated DMA memory */
- pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+ dma_free_coherent(&phba->ctrl.pdev->dev, nonemb_cmd.size,
nonemb_cmd.va,
nonemb_cmd.dma);
@@ -869,7 +870,7 @@ static void beiscsi_boot_process_compl(struct beiscsi_hba *phba,
status);
boot_work = 0;
}
- pci_free_consistent(phba->ctrl.pdev, bs->nonemb_cmd.size,
+ dma_free_coherent(&phba->ctrl.pdev->dev, bs->nonemb_cmd.size,
bs->nonemb_cmd.va, bs->nonemb_cmd.dma);
bs->nonemb_cmd.va = NULL;
break;
@@ -1012,9 +1013,10 @@ unsigned int beiscsi_boot_get_sinfo(struct beiscsi_hba *phba)
nonemb_cmd = &phba->boot_struct.nonemb_cmd;
nonemb_cmd->size = sizeof(struct be_cmd_get_session_resp);
- nonemb_cmd->va = pci_alloc_consistent(phba->ctrl.pdev,
+ nonemb_cmd->va = dma_alloc_coherent(&phba->ctrl.pdev->dev,
nonemb_cmd->size,
- &nonemb_cmd->dma);
+ &nonemb_cmd->dma,
+ GFP_KERNEL);
if (!nonemb_cmd->va) {
mutex_unlock(&ctrl->mbox_lock);
return 0;
@@ -1508,9 +1510,10 @@ int beiscsi_mgmt_invalidate_icds(struct beiscsi_hba *phba,
return -EINVAL;
nonemb_cmd.size = sizeof(union be_invldt_cmds_params);
- nonemb_cmd.va = pci_zalloc_consistent(phba->ctrl.pdev,
+ nonemb_cmd.va = dma_zalloc_coherent(&phba->ctrl.pdev->dev,
nonemb_cmd.size,
- &nonemb_cmd.dma);
+ &nonemb_cmd.dma,
+ GFP_KERNEL);
if (!nonemb_cmd.va) {
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_EH,
"BM_%d : invldt_cmds_params alloc failed\n");
@@ -1521,7 +1524,7 @@ int beiscsi_mgmt_invalidate_icds(struct beiscsi_hba *phba,
wrb = alloc_mcc_wrb(phba, &tag);
if (!wrb) {
mutex_unlock(&ctrl->mbox_lock);
- pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+ dma_free_coherent(&phba->ctrl.pdev->dev, nonemb_cmd.size,
nonemb_cmd.va, nonemb_cmd.dma);
return -ENOMEM;
}
@@ -1548,7 +1551,7 @@ int beiscsi_mgmt_invalidate_icds(struct beiscsi_hba *phba,
rc = beiscsi_mccq_compl_wait(phba, tag, NULL, &nonemb_cmd);
if (rc != -EBUSY)
- pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+ dma_free_coherent(&phba->ctrl.pdev->dev, nonemb_cmd.size,
nonemb_cmd.va, nonemb_cmd.dma);
return rc;
}
diff --git a/drivers/scsi/bfa/bfa_defs_svc.h b/drivers/scsi/bfa/bfa_defs_svc.h
index 3d0c96a5c873..c19c26e0e405 100644
--- a/drivers/scsi/bfa/bfa_defs_svc.h
+++ b/drivers/scsi/bfa/bfa_defs_svc.h
@@ -1453,7 +1453,7 @@ union bfa_aen_data_u {
struct bfa_aen_entry_s {
struct list_head qe;
enum bfa_aen_category aen_category;
- u32 aen_type;
+ int aen_type;
union bfa_aen_data_u aen_data;
u64 aen_tv_sec;
u64 aen_tv_usec;
diff --git a/drivers/scsi/bfa/bfa_fcbuild.c b/drivers/scsi/bfa/bfa_fcbuild.c
index d3b00a475aeb..2de5d514e99c 100644
--- a/drivers/scsi/bfa/bfa_fcbuild.c
+++ b/drivers/scsi/bfa/bfa_fcbuild.c
@@ -190,27 +190,6 @@ fc_els_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id, __be16 ox_id)
fchs->ox_id = ox_id;
}
-enum fc_parse_status
-fc_els_rsp_parse(struct fchs_s *fchs, int len)
-{
- struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1);
- struct fc_ls_rjt_s *ls_rjt = (struct fc_ls_rjt_s *) els_cmd;
-
- len = len;
-
- switch (els_cmd->els_code) {
- case FC_ELS_LS_RJT:
- if (ls_rjt->reason_code == FC_LS_RJT_RSN_LOGICAL_BUSY)
- return FC_PARSE_BUSY;
- else
- return FC_PARSE_FAILURE;
-
- case FC_ELS_ACC:
- return FC_PARSE_OK;
- }
- return FC_PARSE_OK;
-}
-
static void
fc_bls_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id, __be16 ox_id)
{
@@ -831,18 +810,6 @@ fc_rpsc_acc_build(struct fchs_s *fchs, struct fc_rpsc_acc_s *rpsc_acc,
}
u16
-fc_logo_rsp_parse(struct fchs_s *fchs, int len)
-{
- struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1);
-
- len = len;
- if (els_cmd->els_code != FC_ELS_ACC)
- return FC_PARSE_FAILURE;
-
- return FC_PARSE_OK;
-}
-
-u16
fc_pdisc_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id,
wwn_t port_name, wwn_t node_name, u16 pdu_size)
{
@@ -908,40 +875,6 @@ fc_prlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id,
}
u16
-fc_prlo_rsp_parse(struct fchs_s *fchs, int len)
-{
- struct fc_prlo_acc_s *prlo = (struct fc_prlo_acc_s *) (fchs + 1);
- int num_pages = 0;
- int page = 0;
-
- len = len;
-
- if (prlo->command != FC_ELS_ACC)
- return FC_PARSE_FAILURE;
-
- num_pages = ((be16_to_cpu(prlo->payload_len)) - 4) / 16;
-
- for (page = 0; page < num_pages; page++) {
- if (prlo->prlo_acc_params[page].type != FC_TYPE_FCP)
- return FC_PARSE_FAILURE;
-
- if (prlo->prlo_acc_params[page].opa_valid != 0)
- return FC_PARSE_FAILURE;
-
- if (prlo->prlo_acc_params[page].rpa_valid != 0)
- return FC_PARSE_FAILURE;
-
- if (prlo->prlo_acc_params[page].orig_process_assc != 0)
- return FC_PARSE_FAILURE;
-
- if (prlo->prlo_acc_params[page].resp_process_assc != 0)
- return FC_PARSE_FAILURE;
- }
- return FC_PARSE_OK;
-
-}
-
-u16
fc_tprlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id,
int num_pages, enum fc_tprlo_type tprlo_type, u32 tpr_id)
{
@@ -972,47 +905,6 @@ fc_tprlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id,
}
u16
-fc_tprlo_rsp_parse(struct fchs_s *fchs, int len)
-{
- struct fc_tprlo_acc_s *tprlo = (struct fc_tprlo_acc_s *) (fchs + 1);
- int num_pages = 0;
- int page = 0;
-
- len = len;
-
- if (tprlo->command != FC_ELS_ACC)
- return FC_PARSE_ACC_INVAL;
-
- num_pages = (be16_to_cpu(tprlo->payload_len) - 4) / 16;
-
- for (page = 0; page < num_pages; page++) {
- if (tprlo->tprlo_acc_params[page].type != FC_TYPE_FCP)
- return FC_PARSE_NOT_FCP;
- if (tprlo->tprlo_acc_params[page].opa_valid != 0)
- return FC_PARSE_OPAFLAG_INVAL;
- if (tprlo->tprlo_acc_params[page].rpa_valid != 0)
- return FC_PARSE_RPAFLAG_INVAL;
- if (tprlo->tprlo_acc_params[page].orig_process_assc != 0)
- return FC_PARSE_OPA_INVAL;
- if (tprlo->tprlo_acc_params[page].resp_process_assc != 0)
- return FC_PARSE_RPA_INVAL;
- }
- return FC_PARSE_OK;
-}
-
-enum fc_parse_status
-fc_rrq_rsp_parse(struct fchs_s *fchs, int len)
-{
- struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1);
-
- len = len;
- if (els_cmd->els_code != FC_ELS_ACC)
- return FC_PARSE_FAILURE;
-
- return FC_PARSE_OK;
-}
-
-u16
fc_ba_rjt_build(struct fchs_s *fchs, u32 d_id, u32 s_id, __be16 ox_id,
u32 reason_code, u32 reason_expl)
{
diff --git a/drivers/scsi/bfa/bfa_fcbuild.h b/drivers/scsi/bfa/bfa_fcbuild.h
index b109a8813401..ac08d0b5b89a 100644
--- a/drivers/scsi/bfa/bfa_fcbuild.h
+++ b/drivers/scsi/bfa/bfa_fcbuild.h
@@ -163,7 +163,6 @@ enum fc_parse_status fc_abts_rsp_parse(struct fchs_s *buf, int len);
u16 fc_rrq_build(struct fchs_s *buf, struct fc_rrq_s *rrq, u32 d_id,
u32 s_id, u16 ox_id, u16 rrq_oxid);
-enum fc_parse_status fc_rrq_rsp_parse(struct fchs_s *buf, int len);
u16 fc_rspnid_build(struct fchs_s *fchs, void *pld, u32 s_id,
u16 ox_id, u8 *name);
@@ -276,8 +275,6 @@ void fc_get_fc4type_bitmask(u8 fc4_type, u8 *bit_mask);
void fc_els_req_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
__be16 ox_id);
-enum fc_parse_status fc_els_rsp_parse(struct fchs_s *fchs, int len);
-
enum fc_parse_status fc_plogi_rsp_parse(struct fchs_s *fchs, int len,
wwn_t port_name);
@@ -297,8 +294,6 @@ u16 fc_tprlo_acc_build(struct fchs_s *fchs, struct fc_tprlo_acc_s *tprlo_acc,
u16 fc_prlo_acc_build(struct fchs_s *fchs, struct fc_prlo_acc_s *prlo_acc,
u32 d_id, u32 s_id, __be16 ox_id, int num_pages);
-u16 fc_logo_rsp_parse(struct fchs_s *fchs, int len);
-
u16 fc_pdisc_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
u16 ox_id, wwn_t port_name, wwn_t node_name,
u16 pdu_size);
@@ -308,14 +303,10 @@ u16 fc_pdisc_rsp_parse(struct fchs_s *fchs, int len, wwn_t port_name);
u16 fc_prlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
u16 ox_id, int num_pages);
-u16 fc_prlo_rsp_parse(struct fchs_s *fchs, int len);
-
u16 fc_tprlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
u16 ox_id, int num_pages, enum fc_tprlo_type tprlo_type,
u32 tpr_id);
-u16 fc_tprlo_rsp_parse(struct fchs_s *fchs, int len);
-
u16 fc_ba_rjt_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
__be16 ox_id, u32 reason_code, u32 reason_expl);
diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c
index bd7e6a6fc1f1..911efc98d1fd 100644
--- a/drivers/scsi/bfa/bfad.c
+++ b/drivers/scsi/bfa/bfad.c
@@ -1569,8 +1569,6 @@ bfad_pci_slot_reset(struct pci_dev *pdev)
if (pci_set_dma_mask(bfad->pcidev, DMA_BIT_MASK(32)) != 0)
goto out_disable_device;
- pci_cleanup_aer_uncorrect_error_status(pdev);
-
if (restart_bfa(bfad) == -1)
goto out_disable_device;
diff --git a/drivers/scsi/bfa/bfad_im.h b/drivers/scsi/bfa/bfad_im.h
index e61ed8dad0b4..bd4ac187fd8e 100644
--- a/drivers/scsi/bfa/bfad_im.h
+++ b/drivers/scsi/bfa/bfad_im.h
@@ -143,7 +143,7 @@ struct bfad_im_s {
static inline void bfad_im_post_vendor_event(struct bfa_aen_entry_s *entry,
struct bfad_s *drv, int cnt,
enum bfa_aen_category cat,
- enum bfa_ioc_aen_event evt)
+ int evt)
{
struct timespec64 ts;
diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
index f00045813378..cd160f2ec75d 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
@@ -150,15 +150,11 @@ static void bnx2fc_clean_rx_queue(struct fc_lport *lp)
struct fcoe_rcv_info *fr;
struct sk_buff_head *list;
struct sk_buff *skb, *next;
- struct sk_buff *head;
bg = &bnx2fc_global;
spin_lock_bh(&bg->fcoe_rx_list.lock);
list = &bg->fcoe_rx_list;
- head = list->next;
- for (skb = head; skb != (struct sk_buff *)list;
- skb = next) {
- next = skb->next;
+ skb_queue_walk_safe(list, skb, next) {
fr = fcoe_dev_from_skb(skb);
if (fr->fr_dev == lp) {
__skb_unlink(skb, list);
@@ -436,7 +432,6 @@ static int bnx2fc_rcv(struct sk_buff *skb, struct net_device *dev,
struct fcoe_rcv_info *fr;
struct fcoe_percpu_s *bg;
struct sk_buff *tmp_skb;
- unsigned short oxid;
interface = container_of(ptype, struct bnx2fc_interface,
fcoe_packet_type);
@@ -470,8 +465,6 @@ static int bnx2fc_rcv(struct sk_buff *skb, struct net_device *dev,
skb_set_transport_header(skb, sizeof(struct fcoe_hdr));
fh = (struct fc_frame_header *) skb_transport_header(skb);
- oxid = ntohs(fh->fh_ox_id);
-
fr = fcoe_dev_from_skb(skb);
fr->fr_dev = lport;
diff --git a/drivers/scsi/csiostor/csio_init.c b/drivers/scsi/csiostor/csio_init.c
index ed2dae657964..1a458ce08210 100644
--- a/drivers/scsi/csiostor/csio_init.c
+++ b/drivers/scsi/csiostor/csio_init.c
@@ -210,11 +210,8 @@ csio_pci_init(struct pci_dev *pdev, int *bars)
pci_set_master(pdev);
pci_try_set_mwi(pdev);
- if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
- pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
- } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
- pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
- } else {
+ if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)) ||
+ dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32))) {
dev_err(&pdev->dev, "No suitable DMA available.\n");
goto err_release_regions;
}
@@ -1102,7 +1099,6 @@ csio_pci_slot_reset(struct pci_dev *pdev)
pci_set_master(pdev);
pci_restore_state(pdev);
pci_save_state(pdev);
- pci_cleanup_aer_uncorrect_error_status(pdev);
/* Bring HW s/m to ready state.
* but don't resume IOs.
diff --git a/drivers/scsi/csiostor/csio_lnode.c b/drivers/scsi/csiostor/csio_lnode.c
index cc5611efc7a9..66e58f0a75dc 100644
--- a/drivers/scsi/csiostor/csio_lnode.c
+++ b/drivers/scsi/csiostor/csio_lnode.c
@@ -1845,8 +1845,8 @@ csio_ln_fdmi_init(struct csio_lnode *ln)
/* Allocate Dma buffers for FDMI response Payload */
dma_buf = &ln->mgmt_req->dma_buf;
dma_buf->len = 2048;
- dma_buf->vaddr = pci_alloc_consistent(hw->pdev, dma_buf->len,
- &dma_buf->paddr);
+ dma_buf->vaddr = dma_alloc_coherent(&hw->pdev->dev, dma_buf->len,
+ &dma_buf->paddr, GFP_KERNEL);
if (!dma_buf->vaddr) {
csio_err(hw, "Failed to alloc DMA buffer for FDMI!\n");
kfree(ln->mgmt_req);
@@ -1873,7 +1873,7 @@ csio_ln_fdmi_exit(struct csio_lnode *ln)
dma_buf = &ln->mgmt_req->dma_buf;
if (dma_buf->vaddr)
- pci_free_consistent(hw->pdev, dma_buf->len, dma_buf->vaddr,
+ dma_free_coherent(&hw->pdev->dev, dma_buf->len, dma_buf->vaddr,
dma_buf->paddr);
kfree(ln->mgmt_req);
diff --git a/drivers/scsi/csiostor/csio_scsi.c b/drivers/scsi/csiostor/csio_scsi.c
index dab0d3f9bee1..8c15b7acb4b7 100644
--- a/drivers/scsi/csiostor/csio_scsi.c
+++ b/drivers/scsi/csiostor/csio_scsi.c
@@ -2349,8 +2349,8 @@ csio_scsi_alloc_ddp_bufs(struct csio_scsim *scm, struct csio_hw *hw,
}
/* Allocate Dma buffers for DDP */
- ddp_desc->vaddr = pci_alloc_consistent(hw->pdev, unit_size,
- &ddp_desc->paddr);
+ ddp_desc->vaddr = dma_alloc_coherent(&hw->pdev->dev, unit_size,
+ &ddp_desc->paddr, GFP_KERNEL);
if (!ddp_desc->vaddr) {
csio_err(hw,
"SCSI response DMA buffer (ddp) allocation"
@@ -2372,8 +2372,8 @@ no_mem:
list_for_each(tmp, &scm->ddp_freelist) {
ddp_desc = (struct csio_dma_buf *) tmp;
tmp = csio_list_prev(tmp);
- pci_free_consistent(hw->pdev, ddp_desc->len, ddp_desc->vaddr,
- ddp_desc->paddr);
+ dma_free_coherent(&hw->pdev->dev, ddp_desc->len,
+ ddp_desc->vaddr, ddp_desc->paddr);
list_del_init(&ddp_desc->list);
kfree(ddp_desc);
}
@@ -2399,8 +2399,8 @@ csio_scsi_free_ddp_bufs(struct csio_scsim *scm, struct csio_hw *hw)
list_for_each(tmp, &scm->ddp_freelist) {
ddp_desc = (struct csio_dma_buf *) tmp;
tmp = csio_list_prev(tmp);
- pci_free_consistent(hw->pdev, ddp_desc->len, ddp_desc->vaddr,
- ddp_desc->paddr);
+ dma_free_coherent(&hw->pdev->dev, ddp_desc->len,
+ ddp_desc->vaddr, ddp_desc->paddr);
list_del_init(&ddp_desc->list);
kfree(ddp_desc);
}
diff --git a/drivers/scsi/csiostor/csio_wr.c b/drivers/scsi/csiostor/csio_wr.c
index 5022e82ccc4f..dc12933533d5 100644
--- a/drivers/scsi/csiostor/csio_wr.c
+++ b/drivers/scsi/csiostor/csio_wr.c
@@ -124,8 +124,8 @@ csio_wr_fill_fl(struct csio_hw *hw, struct csio_q *flq)
while (n--) {
buf->len = sge->sge_fl_buf_size[sreg];
- buf->vaddr = pci_alloc_consistent(hw->pdev, buf->len,
- &buf->paddr);
+ buf->vaddr = dma_alloc_coherent(&hw->pdev->dev, buf->len,
+ &buf->paddr, GFP_KERNEL);
if (!buf->vaddr) {
csio_err(hw, "Could only fill %d buffers!\n", n + 1);
return -ENOMEM;
@@ -233,7 +233,8 @@ csio_wr_alloc_q(struct csio_hw *hw, uint32_t qsize, uint32_t wrsize,
q = wrm->q_arr[free_idx];
- q->vstart = pci_zalloc_consistent(hw->pdev, qsz, &q->pstart);
+ q->vstart = dma_zalloc_coherent(&hw->pdev->dev, qsz, &q->pstart,
+ GFP_KERNEL);
if (!q->vstart) {
csio_err(hw,
"Failed to allocate DMA memory for "
@@ -1703,14 +1704,14 @@ csio_wrm_exit(struct csio_wrm *wrm, struct csio_hw *hw)
buf = &q->un.fl.bufs[j];
if (!buf->vaddr)
continue;
- pci_free_consistent(hw->pdev, buf->len,
- buf->vaddr,
- buf->paddr);
+ dma_free_coherent(&hw->pdev->dev,
+ buf->len, buf->vaddr,
+ buf->paddr);
}
kfree(q->un.fl.bufs);
}
- pci_free_consistent(hw->pdev, q->size,
- q->vstart, q->pstart);
+ dma_free_coherent(&hw->pdev->dev, q->size,
+ q->vstart, q->pstart);
}
kfree(q);
}
diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
index 211da1d5a869..064ef5735182 100644
--- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
+++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
@@ -35,6 +35,11 @@ static unsigned int dbg_level;
#include "../libcxgbi.h"
+#ifdef CONFIG_CHELSIO_T4_DCB
+#include <net/dcbevent.h>
+#include "cxgb4_dcb.h"
+#endif
+
#define DRV_MODULE_NAME "cxgb4i"
#define DRV_MODULE_DESC "Chelsio T4-T6 iSCSI Driver"
#define DRV_MODULE_VERSION "0.9.5-ko"
@@ -155,6 +160,15 @@ static struct iscsi_transport cxgb4i_iscsi_transport = {
.session_recovery_timedout = iscsi_session_recovery_timedout,
};
+#ifdef CONFIG_CHELSIO_T4_DCB
+static int
+cxgb4_dcb_change_notify(struct notifier_block *, unsigned long, void *);
+
+static struct notifier_block cxgb4_dcb_change = {
+ .notifier_call = cxgb4_dcb_change_notify,
+};
+#endif
+
static struct scsi_transport_template *cxgb4i_stt;
/*
@@ -574,6 +588,9 @@ static inline int tx_flowc_wr_credits(int *nparamsp, int *flowclenp)
int nparams, flowclen16, flowclen;
nparams = FLOWC_WR_NPARAMS_MIN;
+#ifdef CONFIG_CHELSIO_T4_DCB
+ nparams++;
+#endif
flowclen = offsetof(struct fw_flowc_wr, mnemval[nparams]);
flowclen16 = DIV_ROUND_UP(flowclen, 16);
flowclen = flowclen16 * 16;
@@ -595,6 +612,9 @@ static inline int send_tx_flowc_wr(struct cxgbi_sock *csk)
struct fw_flowc_wr *flowc;
int nparams, flowclen16, flowclen;
+#ifdef CONFIG_CHELSIO_T4_DCB
+ u16 vlan = ((struct l2t_entry *)csk->l2t)->vlan;
+#endif
flowclen16 = tx_flowc_wr_credits(&nparams, &flowclen);
skb = alloc_wr(flowclen, 0, GFP_ATOMIC);
flowc = (struct fw_flowc_wr *)skb->head;
@@ -622,6 +642,17 @@ static inline int send_tx_flowc_wr(struct cxgbi_sock *csk)
flowc->mnemval[8].val = 0;
flowc->mnemval[8].mnemonic = FW_FLOWC_MNEM_TXDATAPLEN_MAX;
flowc->mnemval[8].val = 16384;
+#ifdef CONFIG_CHELSIO_T4_DCB
+ flowc->mnemval[9].mnemonic = FW_FLOWC_MNEM_DCBPRIO;
+ if (vlan == CPL_L2T_VLAN_NONE) {
+ pr_warn_ratelimited("csk %u without VLAN Tag on DCB Link\n",
+ csk->tid);
+ flowc->mnemval[9].val = cpu_to_be32(0);
+ } else {
+ flowc->mnemval[9].val = cpu_to_be32((vlan & VLAN_PRIO_MASK) >>
+ VLAN_PRIO_SHIFT);
+ }
+#endif
set_wr_txq(skb, CPL_PRIORITY_DATA, csk->port_id);
@@ -1600,6 +1631,46 @@ static void release_offload_resources(struct cxgbi_sock *csk)
csk->dst = NULL;
}
+#ifdef CONFIG_CHELSIO_T4_DCB
+static inline u8 get_iscsi_dcb_state(struct net_device *ndev)
+{
+ return ndev->dcbnl_ops->getstate(ndev);
+}
+
+static int select_priority(int pri_mask)
+{
+ if (!pri_mask)
+ return 0;
+ return (ffs(pri_mask) - 1);
+}
+
+static u8 get_iscsi_dcb_priority(struct net_device *ndev)
+{
+ int rv;
+ u8 caps;
+
+ struct dcb_app iscsi_dcb_app = {
+ .protocol = 3260
+ };
+
+ rv = (int)ndev->dcbnl_ops->getcap(ndev, DCB_CAP_ATTR_DCBX, &caps);
+ if (rv)
+ return 0;
+
+ if (caps & DCB_CAP_DCBX_VER_IEEE) {
+ iscsi_dcb_app.selector = IEEE_8021QAZ_APP_SEL_ANY;
+ rv = dcb_ieee_getapp_mask(ndev, &iscsi_dcb_app);
+ } else if (caps & DCB_CAP_DCBX_VER_CEE) {
+ iscsi_dcb_app.selector = DCB_APP_IDTYPE_PORTNUM;
+ rv = dcb_getapp(ndev, &iscsi_dcb_app);
+ }
+
+ log_debug(1 << CXGBI_DBG_ISCSI,
+ "iSCSI priority is set to %u\n", select_priority(rv));
+ return select_priority(rv);
+}
+#endif
+
static int init_act_open(struct cxgbi_sock *csk)
{
struct cxgbi_device *cdev = csk->cdev;
@@ -1613,7 +1684,9 @@ static int init_act_open(struct cxgbi_sock *csk)
unsigned int size, size6;
unsigned int linkspeed;
unsigned int rcv_winf, snd_winf;
-
+#ifdef CONFIG_CHELSIO_T4_DCB
+ u8 priority = 0;
+#endif
log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK,
"csk 0x%p,%u,0x%lx,%u.\n",
csk, csk->state, csk->flags, csk->tid);
@@ -1647,7 +1720,15 @@ static int init_act_open(struct cxgbi_sock *csk)
cxgbi_sock_set_flag(csk, CTPF_HAS_ATID);
cxgbi_sock_get(csk);
+#ifdef CONFIG_CHELSIO_T4_DCB
+ if (get_iscsi_dcb_state(ndev))
+ priority = get_iscsi_dcb_priority(ndev);
+
+ csk->dcb_priority = priority;
+ csk->l2t = cxgb4_l2t_get(lldi->l2t, n, ndev, priority);
+#else
csk->l2t = cxgb4_l2t_get(lldi->l2t, n, ndev, 0);
+#endif
if (!csk->l2t) {
pr_err("%s, cannot alloc l2t.\n", ndev->name);
goto rel_resource_without_clip;
@@ -2146,6 +2227,70 @@ static int t4_uld_state_change(void *handle, enum cxgb4_state state)
return 0;
}
+#ifdef CONFIG_CHELSIO_T4_DCB
+static int
+cxgb4_dcb_change_notify(struct notifier_block *self, unsigned long val,
+ void *data)
+{
+ int i, port = 0xFF;
+ struct net_device *ndev;
+ struct cxgbi_device *cdev = NULL;
+ struct dcb_app_type *iscsi_app = data;
+ struct cxgbi_ports_map *pmap;
+ u8 priority;
+
+ if (iscsi_app->dcbx & DCB_CAP_DCBX_VER_IEEE) {
+ if (iscsi_app->app.selector != IEEE_8021QAZ_APP_SEL_ANY)
+ return NOTIFY_DONE;
+
+ priority = iscsi_app->app.priority;
+ } else if (iscsi_app->dcbx & DCB_CAP_DCBX_VER_CEE) {
+ if (iscsi_app->app.selector != DCB_APP_IDTYPE_PORTNUM)
+ return NOTIFY_DONE;
+
+ if (!iscsi_app->app.priority)
+ return NOTIFY_DONE;
+
+ priority = ffs(iscsi_app->app.priority) - 1;
+ } else {
+ return NOTIFY_DONE;
+ }
+
+ if (iscsi_app->app.protocol != 3260)
+ return NOTIFY_DONE;
+
+ log_debug(1 << CXGBI_DBG_ISCSI, "iSCSI priority for ifid %d is %u\n",
+ iscsi_app->ifindex, priority);
+
+ ndev = dev_get_by_index(&init_net, iscsi_app->ifindex);
+ if (!ndev)
+ return NOTIFY_DONE;
+
+ cdev = cxgbi_device_find_by_netdev_rcu(ndev, &port);
+
+ dev_put(ndev);
+ if (!cdev)
+ return NOTIFY_DONE;
+
+ pmap = &cdev->pmap;
+
+ for (i = 0; i < pmap->used; i++) {
+ if (pmap->port_csk[i]) {
+ struct cxgbi_sock *csk = pmap->port_csk[i];
+
+ if (csk->dcb_priority != priority) {
+ iscsi_conn_failure(csk->user_data,
+ ISCSI_ERR_CONN_FAILED);
+ pr_info("Restarting iSCSI connection %p with "
+ "priority %u->%u.\n", csk,
+ csk->dcb_priority, priority);
+ }
+ }
+ }
+ return NOTIFY_OK;
+}
+#endif
+
static int __init cxgb4i_init_module(void)
{
int rc;
@@ -2157,11 +2302,18 @@ static int __init cxgb4i_init_module(void)
return rc;
cxgb4_register_uld(CXGB4_ULD_ISCSI, &cxgb4i_uld_info);
+#ifdef CONFIG_CHELSIO_T4_DCB
+ pr_info("%s dcb enabled.\n", DRV_MODULE_NAME);
+ register_dcbevent_notifier(&cxgb4_dcb_change);
+#endif
return 0;
}
static void __exit cxgb4i_exit_module(void)
{
+#ifdef CONFIG_CHELSIO_T4_DCB
+ unregister_dcbevent_notifier(&cxgb4_dcb_change);
+#endif
cxgb4_unregister_uld(CXGB4_ULD_ISCSI);
cxgbi_device_unregister_all(CXGBI_FLAG_DEV_T4);
cxgbi_iscsi_cleanup(&cxgb4i_iscsi_transport, &cxgb4i_stt);
diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c
index 3f3af5e74a07..75f876409fb9 100644
--- a/drivers/scsi/cxgbi/libcxgbi.c
+++ b/drivers/scsi/cxgbi/libcxgbi.c
@@ -784,7 +784,8 @@ cxgbi_check_route6(struct sockaddr *dst_addr, int ifindex)
csk->mtu = mtu;
csk->dst = dst;
- if (ipv6_addr_any(&rt->rt6i_prefsrc.addr)) {
+ rt6_get_prefsrc(rt, &pref_saddr);
+ if (ipv6_addr_any(&pref_saddr)) {
struct inet6_dev *idev = ip6_dst_idev((struct dst_entry *)rt);
err = ipv6_dev_get_saddr(&init_net, idev ? idev->dev : NULL,
@@ -794,8 +795,6 @@ cxgbi_check_route6(struct sockaddr *dst_addr, int ifindex)
&daddr6->sin6_addr);
goto rel_rt;
}
- } else {
- pref_saddr = rt->rt6i_prefsrc.addr;
}
csk->csk_family = AF_INET6;
diff --git a/drivers/scsi/cxgbi/libcxgbi.h b/drivers/scsi/cxgbi/libcxgbi.h
index dcb190e75343..5d5d8b50d842 100644
--- a/drivers/scsi/cxgbi/libcxgbi.h
+++ b/drivers/scsi/cxgbi/libcxgbi.h
@@ -120,6 +120,9 @@ struct cxgbi_sock {
int wr_max_cred;
int wr_cred;
int wr_una_cred;
+#ifdef CONFIG_CHELSIO_T4_DCB
+ u8 dcb_priority;
+#endif
unsigned char hcrc_len;
unsigned char dcrc_len;
diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c
index 1ed2cd82129d..8c55ec6e1827 100644
--- a/drivers/scsi/dc395x.c
+++ b/drivers/scsi/dc395x.c
@@ -753,105 +753,6 @@ static inline struct ScsiReqBlk *find_cmd(struct scsi_cmnd *cmd,
return NULL;
}
-
-static struct ScsiReqBlk *srb_get_free(struct AdapterCtlBlk *acb)
-{
- struct list_head *head = &acb->srb_free_list;
- struct ScsiReqBlk *srb = NULL;
-
- if (!list_empty(head)) {
- srb = list_entry(head->next, struct ScsiReqBlk, list);
- list_del(head->next);
- dprintkdbg(DBG_0, "srb_get_free: srb=%p\n", srb);
- }
- return srb;
-}
-
-
-static void srb_free_insert(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
-{
- dprintkdbg(DBG_0, "srb_free_insert: srb=%p\n", srb);
- list_add_tail(&srb->list, &acb->srb_free_list);
-}
-
-
-static void srb_waiting_insert(struct DeviceCtlBlk *dcb,
- struct ScsiReqBlk *srb)
-{
- dprintkdbg(DBG_0, "srb_waiting_insert: (0x%p) <%02i-%i> srb=%p\n",
- srb->cmd, dcb->target_id, dcb->target_lun, srb);
- list_add(&srb->list, &dcb->srb_waiting_list);
-}
-
-
-static void srb_waiting_append(struct DeviceCtlBlk *dcb,
- struct ScsiReqBlk *srb)
-{
- dprintkdbg(DBG_0, "srb_waiting_append: (0x%p) <%02i-%i> srb=%p\n",
- srb->cmd, dcb->target_id, dcb->target_lun, srb);
- list_add_tail(&srb->list, &dcb->srb_waiting_list);
-}
-
-
-static void srb_going_append(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb)
-{
- dprintkdbg(DBG_0, "srb_going_append: (0x%p) <%02i-%i> srb=%p\n",
- srb->cmd, dcb->target_id, dcb->target_lun, srb);
- list_add_tail(&srb->list, &dcb->srb_going_list);
-}
-
-
-static void srb_going_remove(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb)
-{
- struct ScsiReqBlk *i;
- struct ScsiReqBlk *tmp;
- dprintkdbg(DBG_0, "srb_going_remove: (0x%p) <%02i-%i> srb=%p\n",
- srb->cmd, dcb->target_id, dcb->target_lun, srb);
-
- list_for_each_entry_safe(i, tmp, &dcb->srb_going_list, list)
- if (i == srb) {
- list_del(&srb->list);
- break;
- }
-}
-
-
-static void srb_waiting_remove(struct DeviceCtlBlk *dcb,
- struct ScsiReqBlk *srb)
-{
- struct ScsiReqBlk *i;
- struct ScsiReqBlk *tmp;
- dprintkdbg(DBG_0, "srb_waiting_remove: (0x%p) <%02i-%i> srb=%p\n",
- srb->cmd, dcb->target_id, dcb->target_lun, srb);
-
- list_for_each_entry_safe(i, tmp, &dcb->srb_waiting_list, list)
- if (i == srb) {
- list_del(&srb->list);
- break;
- }
-}
-
-
-static void srb_going_to_waiting_move(struct DeviceCtlBlk *dcb,
- struct ScsiReqBlk *srb)
-{
- dprintkdbg(DBG_0,
- "srb_going_to_waiting_move: (0x%p) <%02i-%i> srb=%p\n",
- srb->cmd, dcb->target_id, dcb->target_lun, srb);
- list_move(&srb->list, &dcb->srb_waiting_list);
-}
-
-
-static void srb_waiting_to_going_move(struct DeviceCtlBlk *dcb,
- struct ScsiReqBlk *srb)
-{
- dprintkdbg(DBG_0,
- "srb_waiting_to_going_move: (0x%p) <%02i-%i> srb=%p\n",
- srb->cmd, dcb->target_id, dcb->target_lun, srb);
- list_move(&srb->list, &dcb->srb_going_list);
-}
-
-
/* Sets the timer to wake us up */
static void waiting_set_timer(struct AdapterCtlBlk *acb, unsigned long to)
{
@@ -923,7 +824,7 @@ static void waiting_process_next(struct AdapterCtlBlk *acb)
/* Try to send to the bus */
if (!start_scsi(acb, pos, srb))
- srb_waiting_to_going_move(pos, srb);
+ list_move(&srb->list, &pos->srb_going_list);
else
waiting_set_timer(acb, HZ/50);
break;
@@ -960,15 +861,15 @@ static void send_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
if (dcb->max_command <= list_size(&dcb->srb_going_list) ||
acb->active_dcb ||
(acb->acb_flag & (RESET_DETECT + RESET_DONE + RESET_DEV))) {
- srb_waiting_append(dcb, srb);
+ list_add_tail(&srb->list, &dcb->srb_waiting_list);
waiting_process_next(acb);
return;
}
- if (!start_scsi(acb, dcb, srb))
- srb_going_append(dcb, srb);
- else {
- srb_waiting_insert(dcb, srb);
+ if (!start_scsi(acb, dcb, srb)) {
+ list_add_tail(&srb->list, &dcb->srb_going_list);
+ } else {
+ list_add(&srb->list, &dcb->srb_waiting_list);
waiting_set_timer(acb, HZ / 50);
}
}
@@ -1045,10 +946,8 @@ static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb,
sgp->length++;
}
- srb->sg_bus_addr = pci_map_single(dcb->acb->dev,
- srb->segment_x,
- SEGMENTX_LEN,
- PCI_DMA_TODEVICE);
+ srb->sg_bus_addr = dma_map_single(&dcb->acb->dev->dev,
+ srb->segment_x, SEGMENTX_LEN, DMA_TO_DEVICE);
dprintkdbg(DBG_SG, "build_srb: [n] map sg %p->%08x(%05x)\n",
srb->segment_x, srb->sg_bus_addr, SEGMENTX_LEN);
@@ -1116,9 +1015,9 @@ static int dc395x_queue_command_lck(struct scsi_cmnd *cmd, void (*done)(struct s
cmd->scsi_done = done;
cmd->result = 0;
- srb = srb_get_free(acb);
- if (!srb)
- {
+ srb = list_first_entry_or_null(&acb->srb_free_list,
+ struct ScsiReqBlk, list);
+ if (!srb) {
/*
* Return 1 since we are unable to queue this command at this
* point in time.
@@ -1126,12 +1025,13 @@ static int dc395x_queue_command_lck(struct scsi_cmnd *cmd, void (*done)(struct s
dprintkdbg(DBG_0, "queue_command: No free srb's\n");
return 1;
}
+ list_del(&srb->list);
build_srb(cmd, dcb, srb);
if (!list_empty(&dcb->srb_waiting_list)) {
/* append to waiting queue */
- srb_waiting_append(dcb, srb);
+ list_add_tail(&srb->list, &dcb->srb_waiting_list);
waiting_process_next(acb);
} else {
/* process immediately */
@@ -1376,11 +1276,11 @@ static int dc395x_eh_abort(struct scsi_cmnd *cmd)
srb = find_cmd(cmd, &dcb->srb_waiting_list);
if (srb) {
- srb_waiting_remove(dcb, srb);
+ list_del(&srb->list);
pci_unmap_srb_sense(acb, srb);
pci_unmap_srb(acb, srb);
free_tag(dcb, srb);
- srb_free_insert(acb, srb);
+ list_add_tail(&srb->list, &acb->srb_free_list);
dprintkl(KERN_DEBUG, "eh_abort: Command was waiting\n");
cmd->result = DID_ABORT << 16;
return SUCCESS;
@@ -1969,14 +1869,15 @@ static void sg_update_list(struct ScsiReqBlk *srb, u32 left)
xferred -= psge->length;
} else {
/* Partial SG entry done */
+ dma_sync_single_for_cpu(&srb->dcb->acb->dev->dev,
+ srb->sg_bus_addr, SEGMENTX_LEN,
+ DMA_TO_DEVICE);
psge->length -= xferred;
psge->address += xferred;
srb->sg_index = idx;
- pci_dma_sync_single_for_device(srb->dcb->
- acb->dev,
- srb->sg_bus_addr,
- SEGMENTX_LEN,
- PCI_DMA_TODEVICE);
+ dma_sync_single_for_device(&srb->dcb->acb->dev->dev,
+ srb->sg_bus_addr, SEGMENTX_LEN,
+ DMA_TO_DEVICE);
break;
}
psge++;
@@ -3083,7 +2984,7 @@ static void disconnect(struct AdapterCtlBlk *acb)
goto disc1;
}
free_tag(dcb, srb);
- srb_going_to_waiting_move(dcb, srb);
+ list_move(&srb->list, &dcb->srb_waiting_list);
dprintkdbg(DBG_KG,
"disconnect: (0x%p) Retry\n",
srb->cmd);
@@ -3148,7 +3049,7 @@ static void reselect(struct AdapterCtlBlk *acb)
srb->state = SRB_READY;
free_tag(dcb, srb);
- srb_going_to_waiting_move(dcb, srb);
+ list_move(&srb->list, &dcb->srb_waiting_list);
waiting_set_timer(acb, HZ / 20);
/* return; */
@@ -3271,9 +3172,8 @@ static void pci_unmap_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
/* unmap DC395x SG list */
dprintkdbg(DBG_SG, "pci_unmap_srb: list=%08x(%05x)\n",
srb->sg_bus_addr, SEGMENTX_LEN);
- pci_unmap_single(acb->dev, srb->sg_bus_addr,
- SEGMENTX_LEN,
- PCI_DMA_TODEVICE);
+ dma_unmap_single(&acb->dev->dev, srb->sg_bus_addr, SEGMENTX_LEN,
+ DMA_TO_DEVICE);
dprintkdbg(DBG_SG, "pci_unmap_srb: segs=%i buffer=%p\n",
scsi_sg_count(cmd), scsi_bufflen(cmd));
/* unmap the sg segments */
@@ -3291,8 +3191,8 @@ static void pci_unmap_srb_sense(struct AdapterCtlBlk *acb,
/* Unmap sense buffer */
dprintkdbg(DBG_SG, "pci_unmap_srb_sense: buffer=%08x\n",
srb->segment_x[0].address);
- pci_unmap_single(acb->dev, srb->segment_x[0].address,
- srb->segment_x[0].length, PCI_DMA_FROMDEVICE);
+ dma_unmap_single(&acb->dev->dev, srb->segment_x[0].address,
+ srb->segment_x[0].length, DMA_FROM_DEVICE);
/* Restore SG stuff */
srb->total_xfer_length = srb->xferred;
srb->segment_x[0].address =
@@ -3411,7 +3311,7 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
tempcnt--;
dcb->max_command = tempcnt;
free_tag(dcb, srb);
- srb_going_to_waiting_move(dcb, srb);
+ list_move(&srb->list, &dcb->srb_waiting_list);
waiting_set_timer(acb, HZ / 20);
srb->adapter_status = 0;
srb->target_status = 0;
@@ -3447,14 +3347,12 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
}
}
- if (dir != PCI_DMA_NONE && scsi_sg_count(cmd))
- pci_dma_sync_sg_for_cpu(acb->dev, scsi_sglist(cmd),
- scsi_sg_count(cmd), dir);
-
ckc_only = 0;
/* Check Error Conditions */
ckc_e:
+ pci_unmap_srb(acb, srb);
+
if (cmd->cmnd[0] == INQUIRY) {
unsigned char *base = NULL;
struct ScsiInqData *ptr;
@@ -3498,16 +3396,14 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
cmd->cmnd[0], srb->total_xfer_length);
}
- srb_going_remove(dcb, srb);
- /* Add to free list */
- if (srb == acb->tmp_srb)
- dprintkl(KERN_ERR, "srb_done: ERROR! Completed cmd with tmp_srb\n");
- else {
+ if (srb != acb->tmp_srb) {
+ /* Add to free list */
dprintkdbg(DBG_0, "srb_done: (0x%p) done result=0x%08x\n",
cmd, cmd->result);
- srb_free_insert(acb, srb);
+ list_move_tail(&srb->list, &acb->srb_free_list);
+ } else {
+ dprintkl(KERN_ERR, "srb_done: ERROR! Completed cmd with tmp_srb\n");
}
- pci_unmap_srb(acb, srb);
cmd->scsi_done(cmd);
waiting_process_next(acb);
@@ -3535,9 +3431,9 @@ static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag,
result = MK_RES(0, did_flag, 0, 0);
printk("G:%p(%02i-%i) ", p,
p->device->id, (u8)p->device->lun);
- srb_going_remove(dcb, srb);
+ list_del(&srb->list);
free_tag(dcb, srb);
- srb_free_insert(acb, srb);
+ list_add_tail(&srb->list, &acb->srb_free_list);
p->result = result;
pci_unmap_srb_sense(acb, srb);
pci_unmap_srb(acb, srb);
@@ -3565,8 +3461,7 @@ static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag,
result = MK_RES(0, did_flag, 0, 0);
printk("W:%p<%02i-%i>", p, p->device->id,
(u8)p->device->lun);
- srb_waiting_remove(dcb, srb);
- srb_free_insert(acb, srb);
+ list_move_tail(&srb->list, &acb->srb_free_list);
p->result = result;
pci_unmap_srb_sense(acb, srb);
pci_unmap_srb(acb, srb);
@@ -3692,9 +3587,9 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
srb->total_xfer_length = SCSI_SENSE_BUFFERSIZE;
srb->segment_x[0].length = SCSI_SENSE_BUFFERSIZE;
/* Map sense buffer */
- srb->segment_x[0].address =
- pci_map_single(acb->dev, cmd->sense_buffer,
- SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE);
+ srb->segment_x[0].address = dma_map_single(&acb->dev->dev,
+ cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE,
+ DMA_FROM_DEVICE);
dprintkdbg(DBG_SG, "request_sense: map buffer %p->%08x(%05x)\n",
cmd->sense_buffer, srb->segment_x[0].address,
SCSI_SENSE_BUFFERSIZE);
@@ -3705,7 +3600,7 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
dprintkl(KERN_DEBUG,
"request_sense: (0x%p) failed <%02i-%i>\n",
srb->cmd, dcb->target_id, dcb->target_lun);
- srb_going_to_waiting_move(dcb, srb);
+ list_move(&srb->list, &dcb->srb_waiting_list);
waiting_set_timer(acb, HZ / 100);
}
}
@@ -4392,7 +4287,7 @@ static void adapter_init_params(struct AdapterCtlBlk *acb)
/* link static array of srbs into the srb free list */
for (i = 0; i < acb->srb_count - 1; i++)
- srb_free_insert(acb, &acb->srb_array[i]);
+ list_add_tail(&acb->srb_array[i].list, &acb->srb_free_list);
}
diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c
index c3fc34b9964d..ac7da9db7317 100644
--- a/drivers/scsi/esp_scsi.c
+++ b/drivers/scsi/esp_scsi.c
@@ -369,19 +369,28 @@ static void esp_map_dma(struct esp *esp, struct scsi_cmnd *cmd)
{
struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd);
struct scatterlist *sg = scsi_sglist(cmd);
- int dir = cmd->sc_data_direction;
- int total, i;
+ int total = 0, i;
- if (dir == DMA_NONE)
+ if (cmd->sc_data_direction == DMA_NONE)
return;
- spriv->u.num_sg = esp->ops->map_sg(esp, sg, scsi_sg_count(cmd), dir);
+ if (esp->flags & ESP_FLAG_NO_DMA_MAP) {
+ /*
+ * For pseudo DMA and PIO we need the virtual address instead of
+ * a dma address, so perform an identity mapping.
+ */
+ spriv->num_sg = scsi_sg_count(cmd);
+ for (i = 0; i < spriv->num_sg; i++) {
+ sg[i].dma_address = (uintptr_t)sg_virt(&sg[i]);
+ total += sg_dma_len(&sg[i]);
+ }
+ } else {
+ spriv->num_sg = scsi_dma_map(cmd);
+ for (i = 0; i < spriv->num_sg; i++)
+ total += sg_dma_len(&sg[i]);
+ }
spriv->cur_residue = sg_dma_len(sg);
spriv->cur_sg = sg;
-
- total = 0;
- for (i = 0; i < spriv->u.num_sg; i++)
- total += sg_dma_len(&sg[i]);
spriv->tot_residue = total;
}
@@ -441,13 +450,8 @@ static void esp_advance_dma(struct esp *esp, struct esp_cmd_entry *ent,
static void esp_unmap_dma(struct esp *esp, struct scsi_cmnd *cmd)
{
- struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd);
- int dir = cmd->sc_data_direction;
-
- if (dir == DMA_NONE)
- return;
-
- esp->ops->unmap_sg(esp, scsi_sglist(cmd), spriv->u.num_sg, dir);
+ if (!(esp->flags & ESP_FLAG_NO_DMA_MAP))
+ scsi_dma_unmap(cmd);
}
static void esp_save_pointers(struct esp *esp, struct esp_cmd_entry *ent)
@@ -478,17 +482,6 @@ static void esp_restore_pointers(struct esp *esp, struct esp_cmd_entry *ent)
spriv->tot_residue = ent->saved_tot_residue;
}
-static void esp_check_command_len(struct esp *esp, struct scsi_cmnd *cmd)
-{
- if (cmd->cmd_len == 6 ||
- cmd->cmd_len == 10 ||
- cmd->cmd_len == 12) {
- esp->flags &= ~ESP_FLAG_DOING_SLOWCMD;
- } else {
- esp->flags |= ESP_FLAG_DOING_SLOWCMD;
- }
-}
-
static void esp_write_tgt_config3(struct esp *esp, int tgt)
{
if (esp->rev > ESP100A) {
@@ -624,6 +617,26 @@ static void esp_free_lun_tag(struct esp_cmd_entry *ent,
}
}
+static void esp_map_sense(struct esp *esp, struct esp_cmd_entry *ent)
+{
+ ent->sense_ptr = ent->cmd->sense_buffer;
+ if (esp->flags & ESP_FLAG_NO_DMA_MAP) {
+ ent->sense_dma = (uintptr_t)ent->sense_ptr;
+ return;
+ }
+
+ ent->sense_dma = dma_map_single(esp->dev, ent->sense_ptr,
+ SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
+}
+
+static void esp_unmap_sense(struct esp *esp, struct esp_cmd_entry *ent)
+{
+ if (!(esp->flags & ESP_FLAG_NO_DMA_MAP))
+ dma_unmap_single(esp->dev, ent->sense_dma,
+ SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
+ ent->sense_ptr = NULL;
+}
+
/* When a contingent allegiance conditon is created, we force feed a
* REQUEST_SENSE command to the device to fetch the sense data. I
* tried many other schemes, relying on the scsi error handling layer
@@ -645,12 +658,7 @@ static void esp_autosense(struct esp *esp, struct esp_cmd_entry *ent)
if (!ent->sense_ptr) {
esp_log_autosense("Doing auto-sense for tgt[%d] lun[%d]\n",
tgt, lun);
-
- ent->sense_ptr = cmd->sense_buffer;
- ent->sense_dma = esp->ops->map_single(esp,
- ent->sense_ptr,
- SCSI_SENSE_BUFFERSIZE,
- DMA_FROM_DEVICE);
+ esp_map_sense(esp, ent);
}
ent->saved_sense_ptr = ent->sense_ptr;
@@ -717,10 +725,10 @@ static struct esp_cmd_entry *find_and_prep_issuable_command(struct esp *esp)
static void esp_maybe_execute_command(struct esp *esp)
{
struct esp_target_data *tp;
- struct esp_lun_data *lp;
struct scsi_device *dev;
struct scsi_cmnd *cmd;
struct esp_cmd_entry *ent;
+ bool select_and_stop = false;
int tgt, lun, i;
u32 val, start_cmd;
u8 *p;
@@ -743,7 +751,6 @@ static void esp_maybe_execute_command(struct esp *esp)
tgt = dev->id;
lun = dev->lun;
tp = &esp->target[tgt];
- lp = dev->hostdata;
list_move(&ent->list, &esp->active_cmds);
@@ -752,7 +759,8 @@ static void esp_maybe_execute_command(struct esp *esp)
esp_map_dma(esp, cmd);
esp_save_pointers(esp, ent);
- esp_check_command_len(esp, cmd);
+ if (!(cmd->cmd_len == 6 || cmd->cmd_len == 10 || cmd->cmd_len == 12))
+ select_and_stop = true;
p = esp->command_block;
@@ -793,42 +801,22 @@ static void esp_maybe_execute_command(struct esp *esp)
tp->flags &= ~ESP_TGT_CHECK_NEGO;
}
- /* Process it like a slow command. */
- if (tp->flags & (ESP_TGT_NEGO_WIDE | ESP_TGT_NEGO_SYNC))
- esp->flags |= ESP_FLAG_DOING_SLOWCMD;
+ /* If there are multiple message bytes, use Select and Stop */
+ if (esp->msg_out_len)
+ select_and_stop = true;
}
build_identify:
- /* If we don't have a lun-data struct yet, we're probing
- * so do not disconnect. Also, do not disconnect unless
- * we have a tag on this command.
- */
- if (lp && (tp->flags & ESP_TGT_DISCONNECT) && ent->tag[0])
- *p++ = IDENTIFY(1, lun);
- else
- *p++ = IDENTIFY(0, lun);
+ *p++ = IDENTIFY(tp->flags & ESP_TGT_DISCONNECT, lun);
if (ent->tag[0] && esp->rev == ESP100) {
/* ESP100 lacks select w/atn3 command, use select
* and stop instead.
*/
- esp->flags |= ESP_FLAG_DOING_SLOWCMD;
+ select_and_stop = true;
}
- if (!(esp->flags & ESP_FLAG_DOING_SLOWCMD)) {
- start_cmd = ESP_CMD_SELA;
- if (ent->tag[0]) {
- *p++ = ent->tag[0];
- *p++ = ent->tag[1];
-
- start_cmd = ESP_CMD_SA3;
- }
-
- for (i = 0; i < cmd->cmd_len; i++)
- *p++ = cmd->cmnd[i];
-
- esp->select_state = ESP_SELECT_BASIC;
- } else {
+ if (select_and_stop) {
esp->cmd_bytes_left = cmd->cmd_len;
esp->cmd_bytes_ptr = &cmd->cmnd[0];
@@ -843,6 +831,19 @@ build_identify:
start_cmd = ESP_CMD_SELAS;
esp->select_state = ESP_SELECT_MSGOUT;
+ } else {
+ start_cmd = ESP_CMD_SELA;
+ if (ent->tag[0]) {
+ *p++ = ent->tag[0];
+ *p++ = ent->tag[1];
+
+ start_cmd = ESP_CMD_SA3;
+ }
+
+ for (i = 0; i < cmd->cmd_len; i++)
+ *p++ = cmd->cmnd[i];
+
+ esp->select_state = ESP_SELECT_BASIC;
}
val = tgt;
if (esp->rev == FASHME)
@@ -902,9 +903,7 @@ static void esp_cmd_is_done(struct esp *esp, struct esp_cmd_entry *ent,
}
if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
- esp->ops->unmap_single(esp, ent->sense_dma,
- SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
- ent->sense_ptr = NULL;
+ esp_unmap_sense(esp, ent);
/* Restore the message/status bytes to what we actually
* saw originally. Also, report that we are providing
@@ -965,7 +964,7 @@ static int esp_queuecommand_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_
cmd->scsi_done = done;
spriv = ESP_CMD_PRIV(cmd);
- spriv->u.dma_addr = ~(dma_addr_t)0x0;
+ spriv->num_sg = 0;
list_add_tail(&ent->list, &esp->queued_cmds);
@@ -1252,14 +1251,10 @@ static int esp_finish_select(struct esp *esp)
esp_unmap_dma(esp, cmd);
esp_free_lun_tag(ent, cmd->device->hostdata);
tp->flags &= ~(ESP_TGT_NEGO_SYNC | ESP_TGT_NEGO_WIDE);
- esp->flags &= ~ESP_FLAG_DOING_SLOWCMD;
esp->cmd_bytes_ptr = NULL;
esp->cmd_bytes_left = 0;
} else {
- esp->ops->unmap_single(esp, ent->sense_dma,
- SCSI_SENSE_BUFFERSIZE,
- DMA_FROM_DEVICE);
- ent->sense_ptr = NULL;
+ esp_unmap_sense(esp, ent);
}
/* Now that the state is unwound properly, put back onto
@@ -1303,9 +1298,8 @@ static int esp_finish_select(struct esp *esp)
esp_flush_fifo(esp);
}
- /* If we are doing a slow command, negotiation, etc.
- * we'll do the right thing as we transition to the
- * next phase.
+ /* If we are doing a Select And Stop command, negotiation, etc.
+ * we'll do the right thing as we transition to the next phase.
*/
esp_event(esp, ESP_EVENT_CHECK_PHASE);
return 0;
@@ -1338,6 +1332,7 @@ static int esp_data_bytes_sent(struct esp *esp, struct esp_cmd_entry *ent,
bytes_sent = esp->data_dma_len;
bytes_sent -= ecount;
+ bytes_sent -= esp->send_cmd_residual;
/*
* The am53c974 has a DMA 'pecularity'. The doc states:
@@ -1358,7 +1353,7 @@ static int esp_data_bytes_sent(struct esp *esp, struct esp_cmd_entry *ent,
struct esp_cmd_priv *p = ESP_CMD_PRIV(cmd);
u8 *ptr;
- ptr = scsi_kmap_atomic_sg(p->cur_sg, p->u.num_sg,
+ ptr = scsi_kmap_atomic_sg(p->cur_sg, p->num_sg,
&offset, &count);
if (likely(ptr)) {
*(ptr + offset) = bval;
@@ -2039,11 +2034,8 @@ static void esp_reset_cleanup_one(struct esp *esp, struct esp_cmd_entry *ent)
esp_free_lun_tag(ent, cmd->device->hostdata);
cmd->result = DID_RESET << 16;
- if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
- esp->ops->unmap_single(esp, ent->sense_dma,
- SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
- ent->sense_ptr = NULL;
- }
+ if (ent->flags & ESP_CMD_FLAG_AUTOSENSE)
+ esp_unmap_sense(esp, ent);
cmd->scsi_done(cmd);
list_del(&ent->list);
@@ -2382,7 +2374,7 @@ static const char *esp_chip_names[] = {
static struct scsi_transport_template *esp_transport_template;
-int scsi_esp_register(struct esp *esp, struct device *dev)
+int scsi_esp_register(struct esp *esp)
{
static int instance;
int err;
@@ -2402,10 +2394,10 @@ int scsi_esp_register(struct esp *esp, struct device *dev)
esp_bootup_reset(esp);
- dev_printk(KERN_INFO, dev, "esp%u: regs[%1p:%1p] irq[%u]\n",
+ dev_printk(KERN_INFO, esp->dev, "esp%u: regs[%1p:%1p] irq[%u]\n",
esp->host->unique_id, esp->regs, esp->dma_regs,
esp->host->irq);
- dev_printk(KERN_INFO, dev,
+ dev_printk(KERN_INFO, esp->dev,
"esp%u: is a %s, %u MHz (ccf=%u), SCSI ID %u\n",
esp->host->unique_id, esp_chip_names[esp->rev],
esp->cfreq / 1000000, esp->cfact, esp->scsi_id);
@@ -2413,7 +2405,7 @@ int scsi_esp_register(struct esp *esp, struct device *dev)
/* Let the SCSI bus reset settle. */
ssleep(esp_bus_reset_settle);
- err = scsi_add_host(esp->host, dev);
+ err = scsi_add_host(esp->host, esp->dev);
if (err)
return err;
@@ -2790,3 +2782,131 @@ MODULE_PARM_DESC(esp_debug,
module_init(esp_init);
module_exit(esp_exit);
+
+#ifdef CONFIG_SCSI_ESP_PIO
+static inline unsigned int esp_wait_for_fifo(struct esp *esp)
+{
+ int i = 500000;
+
+ do {
+ unsigned int fbytes = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES;
+
+ if (fbytes)
+ return fbytes;
+
+ udelay(1);
+ } while (--i);
+
+ shost_printk(KERN_ERR, esp->host, "FIFO is empty. sreg [%02x]\n",
+ esp_read8(ESP_STATUS));
+ return 0;
+}
+
+static inline int esp_wait_for_intr(struct esp *esp)
+{
+ int i = 500000;
+
+ do {
+ esp->sreg = esp_read8(ESP_STATUS);
+ if (esp->sreg & ESP_STAT_INTR)
+ return 0;
+
+ udelay(1);
+ } while (--i);
+
+ shost_printk(KERN_ERR, esp->host, "IRQ timeout. sreg [%02x]\n",
+ esp->sreg);
+ return 1;
+}
+
+#define ESP_FIFO_SIZE 16
+
+void esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count,
+ u32 dma_count, int write, u8 cmd)
+{
+ u8 phase = esp->sreg & ESP_STAT_PMASK;
+
+ cmd &= ~ESP_CMD_DMA;
+ esp->send_cmd_error = 0;
+
+ if (write) {
+ u8 *dst = (u8 *)addr;
+ u8 mask = ~(phase == ESP_MIP ? ESP_INTR_FDONE : ESP_INTR_BSERV);
+
+ scsi_esp_cmd(esp, cmd);
+
+ while (1) {
+ if (!esp_wait_for_fifo(esp))
+ break;
+
+ *dst++ = readb(esp->fifo_reg);
+ --esp_count;
+
+ if (!esp_count)
+ break;
+
+ if (esp_wait_for_intr(esp)) {
+ esp->send_cmd_error = 1;
+ break;
+ }
+
+ if ((esp->sreg & ESP_STAT_PMASK) != phase)
+ break;
+
+ esp->ireg = esp_read8(ESP_INTRPT);
+ if (esp->ireg & mask) {
+ esp->send_cmd_error = 1;
+ break;
+ }
+
+ if (phase == ESP_MIP)
+ esp_write8(ESP_CMD_MOK, ESP_CMD);
+
+ esp_write8(ESP_CMD_TI, ESP_CMD);
+ }
+ } else {
+ unsigned int n = ESP_FIFO_SIZE;
+ u8 *src = (u8 *)addr;
+
+ scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+
+ if (n > esp_count)
+ n = esp_count;
+ writesb(esp->fifo_reg, src, n);
+ src += n;
+ esp_count -= n;
+
+ scsi_esp_cmd(esp, cmd);
+
+ while (esp_count) {
+ if (esp_wait_for_intr(esp)) {
+ esp->send_cmd_error = 1;
+ break;
+ }
+
+ if ((esp->sreg & ESP_STAT_PMASK) != phase)
+ break;
+
+ esp->ireg = esp_read8(ESP_INTRPT);
+ if (esp->ireg & ~ESP_INTR_BSERV) {
+ esp->send_cmd_error = 1;
+ break;
+ }
+
+ n = ESP_FIFO_SIZE -
+ (esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES);
+
+ if (n > esp_count)
+ n = esp_count;
+ writesb(esp->fifo_reg, src, n);
+ src += n;
+ esp_count -= n;
+
+ esp_write8(ESP_CMD_TI, ESP_CMD);
+ }
+ }
+
+ esp->send_cmd_residual = esp_count;
+}
+EXPORT_SYMBOL(esp_send_pio_cmd);
+#endif
diff --git a/drivers/scsi/esp_scsi.h b/drivers/scsi/esp_scsi.h
index 8163dca2071b..aa87a6b72dcc 100644
--- a/drivers/scsi/esp_scsi.h
+++ b/drivers/scsi/esp_scsi.h
@@ -249,11 +249,7 @@
#define SYNC_DEFP_FAST 0x19 /* 10mb/s */
struct esp_cmd_priv {
- union {
- dma_addr_t dma_addr;
- int num_sg;
- } u;
-
+ int num_sg;
int cur_residue;
struct scatterlist *cur_sg;
int tot_residue;
@@ -363,19 +359,6 @@ struct esp_driver_ops {
void (*esp_write8)(struct esp *esp, u8 val, unsigned long reg);
u8 (*esp_read8)(struct esp *esp, unsigned long reg);
- /* Map and unmap DMA memory. Eventually the driver will be
- * converted to the generic DMA API as soon as SBUS is able to
- * cope with that. At such time we can remove this.
- */
- dma_addr_t (*map_single)(struct esp *esp, void *buf,
- size_t sz, int dir);
- int (*map_sg)(struct esp *esp, struct scatterlist *sg,
- int num_sg, int dir);
- void (*unmap_single)(struct esp *esp, dma_addr_t addr,
- size_t sz, int dir);
- void (*unmap_sg)(struct esp *esp, struct scatterlist *sg,
- int num_sg, int dir);
-
/* Return non-zero if there is an IRQ pending. Usually this
* status bit lives in the DMA controller sitting in front of
* the ESP. This has to be accurate or else the ESP interrupt
@@ -435,7 +418,7 @@ struct esp {
const struct esp_driver_ops *ops;
struct Scsi_Host *host;
- void *dev;
+ struct device *dev;
struct esp_cmd_entry *active_cmd;
@@ -490,11 +473,11 @@ struct esp {
u32 flags;
#define ESP_FLAG_DIFFERENTIAL 0x00000001
#define ESP_FLAG_RESETTING 0x00000002
-#define ESP_FLAG_DOING_SLOWCMD 0x00000004
#define ESP_FLAG_WIDE_CAPABLE 0x00000008
#define ESP_FLAG_QUICKIRQ_CHECK 0x00000010
#define ESP_FLAG_DISABLE_SYNC 0x00000020
#define ESP_FLAG_USE_FIFO 0x00000040
+#define ESP_FLAG_NO_DMA_MAP 0x00000080
u8 select_state;
#define ESP_SELECT_NONE 0x00 /* Not selecting */
@@ -532,7 +515,7 @@ struct esp {
u32 min_period;
u32 radelay;
- /* Slow command state. */
+ /* ESP_CMD_SELAS command state */
u8 *cmd_bytes_ptr;
int cmd_bytes_left;
@@ -540,6 +523,11 @@ struct esp {
void *dma;
int dmarev;
+
+ /* These are used by esp_send_pio_cmd() */
+ u8 __iomem *fifo_reg;
+ int send_cmd_error;
+ u32 send_cmd_residual;
};
/* A front-end driver for the ESP chip should do the following in
@@ -568,16 +556,18 @@ struct esp {
* example, the DMA engine has to be reset before ESP can
* be programmed.
* 11) If necessary, call dev_set_drvdata() as needed.
- * 12) Call scsi_esp_register() with prepared 'esp' structure
- * and a device pointer if possible.
+ * 12) Call scsi_esp_register() with prepared 'esp' structure.
* 13) Check scsi_esp_register() return value, release all resources
* if an error was returned.
*/
extern struct scsi_host_template scsi_esp_template;
-extern int scsi_esp_register(struct esp *, struct device *);
+extern int scsi_esp_register(struct esp *);
extern void scsi_esp_unregister(struct esp *);
extern irqreturn_t scsi_esp_intr(int, void *);
extern void scsi_esp_cmd(struct esp *, u8);
+extern void esp_send_pio_cmd(struct esp *esp, u32 dma_addr, u32 esp_count,
+ u32 dma_count, int write, u8 cmd);
+
#endif /* !(_ESP_SCSI_H) */
diff --git a/drivers/scsi/fnic/fnic_fcs.c b/drivers/scsi/fnic/fnic_fcs.c
index c7bf316d8e83..844ef688fa91 100644
--- a/drivers/scsi/fnic/fnic_fcs.c
+++ b/drivers/scsi/fnic/fnic_fcs.c
@@ -836,8 +836,8 @@ static void fnic_rq_cmpl_frame_recv(struct vnic_rq *rq, struct cq_desc
u32 fcp_bytes_written = 0;
unsigned long flags;
- pci_unmap_single(fnic->pdev, buf->dma_addr, buf->len,
- PCI_DMA_FROMDEVICE);
+ dma_unmap_single(&fnic->pdev->dev, buf->dma_addr, buf->len,
+ DMA_FROM_DEVICE);
skb = buf->os_buf;
fp = (struct fc_frame *)skb;
buf->os_buf = NULL;
@@ -977,9 +977,8 @@ int fnic_alloc_rq_frame(struct vnic_rq *rq)
skb_reset_transport_header(skb);
skb_reset_network_header(skb);
skb_put(skb, len);
- pa = pci_map_single(fnic->pdev, skb->data, len, PCI_DMA_FROMDEVICE);
-
- if (pci_dma_mapping_error(fnic->pdev, pa)) {
+ pa = dma_map_single(&fnic->pdev->dev, skb->data, len, DMA_FROM_DEVICE);
+ if (dma_mapping_error(&fnic->pdev->dev, pa)) {
r = -ENOMEM;
printk(KERN_ERR "PCI mapping failed with error %d\n", r);
goto free_skb;
@@ -998,8 +997,8 @@ void fnic_free_rq_buf(struct vnic_rq *rq, struct vnic_rq_buf *buf)
struct fc_frame *fp = buf->os_buf;
struct fnic *fnic = vnic_dev_priv(rq->vdev);
- pci_unmap_single(fnic->pdev, buf->dma_addr, buf->len,
- PCI_DMA_FROMDEVICE);
+ dma_unmap_single(&fnic->pdev->dev, buf->dma_addr, buf->len,
+ DMA_FROM_DEVICE);
dev_kfree_skb(fp_skb(fp));
buf->os_buf = NULL;
@@ -1018,7 +1017,6 @@ void fnic_eth_send(struct fcoe_ctlr *fip, struct sk_buff *skb)
struct ethhdr *eth_hdr;
struct vlan_ethhdr *vlan_hdr;
unsigned long flags;
- int r;
if (!fnic->vlan_hw_insert) {
eth_hdr = (struct ethhdr *)skb_mac_header(skb);
@@ -1038,11 +1036,10 @@ void fnic_eth_send(struct fcoe_ctlr *fip, struct sk_buff *skb)
}
}
- pa = pci_map_single(fnic->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
-
- r = pci_dma_mapping_error(fnic->pdev, pa);
- if (r) {
- printk(KERN_ERR "PCI mapping failed with error %d\n", r);
+ pa = dma_map_single(&fnic->pdev->dev, skb->data, skb->len,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(&fnic->pdev->dev, pa)) {
+ printk(KERN_ERR "DMA mapping failed\n");
goto free_skb;
}
@@ -1058,7 +1055,7 @@ void fnic_eth_send(struct fcoe_ctlr *fip, struct sk_buff *skb)
irq_restore:
spin_unlock_irqrestore(&fnic->wq_lock[0], flags);
- pci_unmap_single(fnic->pdev, pa, skb->len, PCI_DMA_TODEVICE);
+ dma_unmap_single(&fnic->pdev->dev, pa, skb->len, DMA_TO_DEVICE);
free_skb:
kfree_skb(skb);
}
@@ -1115,9 +1112,8 @@ static int fnic_send_frame(struct fnic *fnic, struct fc_frame *fp)
if (FC_FCOE_VER)
FC_FCOE_ENCAPS_VER(fcoe_hdr, FC_FCOE_VER);
- pa = pci_map_single(fnic->pdev, eth_hdr, tot_len, PCI_DMA_TODEVICE);
-
- if (pci_dma_mapping_error(fnic->pdev, pa)) {
+ pa = dma_map_single(&fnic->pdev->dev, eth_hdr, tot_len, DMA_TO_DEVICE);
+ if (dma_mapping_error(&fnic->pdev->dev, pa)) {
ret = -ENOMEM;
printk(KERN_ERR "DMA map failed with error %d\n", ret);
goto free_skb_on_err;
@@ -1131,8 +1127,7 @@ static int fnic_send_frame(struct fnic *fnic, struct fc_frame *fp)
spin_lock_irqsave(&fnic->wq_lock[0], flags);
if (!vnic_wq_desc_avail(wq)) {
- pci_unmap_single(fnic->pdev, pa,
- tot_len, PCI_DMA_TODEVICE);
+ dma_unmap_single(&fnic->pdev->dev, pa, tot_len, DMA_TO_DEVICE);
ret = -1;
goto irq_restore;
}
@@ -1247,8 +1242,8 @@ static void fnic_wq_complete_frame_send(struct vnic_wq *wq,
struct fc_frame *fp = (struct fc_frame *)skb;
struct fnic *fnic = vnic_dev_priv(wq->vdev);
- pci_unmap_single(fnic->pdev, buf->dma_addr,
- buf->len, PCI_DMA_TODEVICE);
+ dma_unmap_single(&fnic->pdev->dev, buf->dma_addr, buf->len,
+ DMA_TO_DEVICE);
dev_kfree_skb_irq(fp_skb(fp));
buf->os_buf = NULL;
}
@@ -1290,8 +1285,8 @@ void fnic_free_wq_buf(struct vnic_wq *wq, struct vnic_wq_buf *buf)
struct fc_frame *fp = buf->os_buf;
struct fnic *fnic = vnic_dev_priv(wq->vdev);
- pci_unmap_single(fnic->pdev, buf->dma_addr,
- buf->len, PCI_DMA_TODEVICE);
+ dma_unmap_single(&fnic->pdev->dev, buf->dma_addr, buf->len,
+ DMA_TO_DEVICE);
dev_kfree_skb(fp_skb(fp));
buf->os_buf = NULL;
diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c
index e52599f44170..cc461fd7bef1 100644
--- a/drivers/scsi/fnic/fnic_main.c
+++ b/drivers/scsi/fnic/fnic_main.c
@@ -611,30 +611,15 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
* limitation for the device. Try 64-bit first, and
* fail to 32-bit.
*/
- err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+ err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
if (err) {
- err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
if (err) {
shost_printk(KERN_ERR, fnic->lport->host,
"No usable DMA configuration "
"aborting\n");
goto err_out_release_regions;
}
- err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
- if (err) {
- shost_printk(KERN_ERR, fnic->lport->host,
- "Unable to obtain 32-bit DMA "
- "for consistent allocations, aborting.\n");
- goto err_out_release_regions;
- }
- } else {
- err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
- if (err) {
- shost_printk(KERN_ERR, fnic->lport->host,
- "Unable to obtain 64-bit DMA "
- "for consistent allocations, aborting.\n");
- goto err_out_release_regions;
- }
}
/* Map vNIC resources from BAR0 */
diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c
index 8cbd3c9f0b4c..96acfcecd540 100644
--- a/drivers/scsi/fnic/fnic_scsi.c
+++ b/drivers/scsi/fnic/fnic_scsi.c
@@ -126,17 +126,17 @@ static void fnic_release_ioreq_buf(struct fnic *fnic,
struct scsi_cmnd *sc)
{
if (io_req->sgl_list_pa)
- pci_unmap_single(fnic->pdev, io_req->sgl_list_pa,
+ dma_unmap_single(&fnic->pdev->dev, io_req->sgl_list_pa,
sizeof(io_req->sgl_list[0]) * io_req->sgl_cnt,
- PCI_DMA_TODEVICE);
+ DMA_TO_DEVICE);
scsi_dma_unmap(sc);
if (io_req->sgl_cnt)
mempool_free(io_req->sgl_list_alloc,
fnic->io_sgl_pool[io_req->sgl_type]);
if (io_req->sense_buf_pa)
- pci_unmap_single(fnic->pdev, io_req->sense_buf_pa,
- SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE);
+ dma_unmap_single(&fnic->pdev->dev, io_req->sense_buf_pa,
+ SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
}
/* Free up Copy Wq descriptors. Called with copy_wq lock held */
@@ -330,7 +330,6 @@ static inline int fnic_queue_wq_copy_desc(struct fnic *fnic,
int flags;
u8 exch_flags;
struct scsi_lun fc_lun;
- int r;
if (sg_count) {
/* For each SGE, create a device desc entry */
@@ -342,30 +341,25 @@ static inline int fnic_queue_wq_copy_desc(struct fnic *fnic,
desc++;
}
- io_req->sgl_list_pa = pci_map_single
- (fnic->pdev,
- io_req->sgl_list,
- sizeof(io_req->sgl_list[0]) * sg_count,
- PCI_DMA_TODEVICE);
-
- r = pci_dma_mapping_error(fnic->pdev, io_req->sgl_list_pa);
- if (r) {
- printk(KERN_ERR "PCI mapping failed with error %d\n", r);
+ io_req->sgl_list_pa = dma_map_single(&fnic->pdev->dev,
+ io_req->sgl_list,
+ sizeof(io_req->sgl_list[0]) * sg_count,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(&fnic->pdev->dev, io_req->sgl_list_pa)) {
+ printk(KERN_ERR "DMA mapping failed\n");
return SCSI_MLQUEUE_HOST_BUSY;
}
}
- io_req->sense_buf_pa = pci_map_single(fnic->pdev,
+ io_req->sense_buf_pa = dma_map_single(&fnic->pdev->dev,
sc->sense_buffer,
SCSI_SENSE_BUFFERSIZE,
- PCI_DMA_FROMDEVICE);
-
- r = pci_dma_mapping_error(fnic->pdev, io_req->sense_buf_pa);
- if (r) {
- pci_unmap_single(fnic->pdev, io_req->sgl_list_pa,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(&fnic->pdev->dev, io_req->sense_buf_pa)) {
+ dma_unmap_single(&fnic->pdev->dev, io_req->sgl_list_pa,
sizeof(io_req->sgl_list[0]) * sg_count,
- PCI_DMA_TODEVICE);
- printk(KERN_ERR "PCI mapping failed with error %d\n", r);
+ DMA_TO_DEVICE);
+ printk(KERN_ERR "DMA mapping failed\n");
return SCSI_MLQUEUE_HOST_BUSY;
}
@@ -2272,33 +2266,17 @@ clean_pending_aborts_end:
static inline int
fnic_scsi_host_start_tag(struct fnic *fnic, struct scsi_cmnd *sc)
{
- struct blk_queue_tag *bqt = fnic->lport->host->bqt;
- int tag, ret = SCSI_NO_TAG;
-
- BUG_ON(!bqt);
- if (!bqt) {
- pr_err("Tags are not supported\n");
- goto end;
- }
-
- do {
- tag = find_next_zero_bit(bqt->tag_map, bqt->max_depth, 1);
- if (tag >= bqt->max_depth) {
- pr_err("Tag allocation failure\n");
- goto end;
- }
- } while (test_and_set_bit(tag, bqt->tag_map));
+ struct request_queue *q = sc->request->q;
+ struct request *dummy;
- bqt->tag_index[tag] = sc->request;
- sc->request->tag = tag;
- sc->tag = tag;
- if (!sc->request->special)
- sc->request->special = sc;
+ dummy = blk_mq_alloc_request(q, REQ_OP_WRITE, BLK_MQ_REQ_NOWAIT);
+ if (IS_ERR(dummy))
+ return SCSI_NO_TAG;
- ret = tag;
+ sc->tag = sc->request->tag = dummy->tag;
+ sc->request->special = sc;
-end:
- return ret;
+ return dummy->tag;
}
/**
@@ -2308,20 +2286,9 @@ end:
static inline void
fnic_scsi_host_end_tag(struct fnic *fnic, struct scsi_cmnd *sc)
{
- struct blk_queue_tag *bqt = fnic->lport->host->bqt;
- int tag = sc->request->tag;
+ struct request *dummy = sc->request->special;
- if (tag == SCSI_NO_TAG)
- return;
-
- BUG_ON(!bqt || !bqt->tag_index[tag]);
- if (!bqt)
- return;
-
- bqt->tag_index[tag] = NULL;
- clear_bit(tag, bqt->tag_map);
-
- return;
+ blk_mq_free_request(dummy);
}
/*
@@ -2380,19 +2347,9 @@ int fnic_device_reset(struct scsi_cmnd *sc)
tag = sc->request->tag;
if (unlikely(tag < 0)) {
/*
- * XXX(hch): current the midlayer fakes up a struct
- * request for the explicit reset ioctls, and those
- * don't have a tag allocated to them. The below
- * code pokes into midlayer structures to paper over
- * this design issue, but that won't work for blk-mq.
- *
- * Either someone who can actually test the hardware
- * will have to come up with a similar hack for the
- * blk-mq case, or we'll have to bite the bullet and
- * fix the way the EH ioctls work for real, but until
- * that happens we fail these explicit requests here.
+ * Really should fix the midlayer to pass in a proper
+ * request for ioctls...
*/
-
tag = fnic_scsi_host_start_tag(fnic, sc);
if (unlikely(tag == SCSI_NO_TAG))
goto fnic_device_reset_end;
diff --git a/drivers/scsi/fnic/vnic_dev.c b/drivers/scsi/fnic/vnic_dev.c
index ba69d6112fa1..434447ea24b8 100644
--- a/drivers/scsi/fnic/vnic_dev.c
+++ b/drivers/scsi/fnic/vnic_dev.c
@@ -195,9 +195,9 @@ int vnic_dev_alloc_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring,
{
vnic_dev_desc_ring_size(ring, desc_count, desc_size);
- ring->descs_unaligned = pci_alloc_consistent(vdev->pdev,
+ ring->descs_unaligned = dma_alloc_coherent(&vdev->pdev->dev,
ring->size_unaligned,
- &ring->base_addr_unaligned);
+ &ring->base_addr_unaligned, GFP_KERNEL);
if (!ring->descs_unaligned) {
printk(KERN_ERR
@@ -221,7 +221,7 @@ int vnic_dev_alloc_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring,
void vnic_dev_free_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring)
{
if (ring->descs) {
- pci_free_consistent(vdev->pdev,
+ dma_free_coherent(&vdev->pdev->dev,
ring->size_unaligned,
ring->descs_unaligned,
ring->base_addr_unaligned);
@@ -298,9 +298,9 @@ int vnic_dev_fw_info(struct vnic_dev *vdev,
int err = 0;
if (!vdev->fw_info) {
- vdev->fw_info = pci_alloc_consistent(vdev->pdev,
+ vdev->fw_info = dma_alloc_coherent(&vdev->pdev->dev,
sizeof(struct vnic_devcmd_fw_info),
- &vdev->fw_info_pa);
+ &vdev->fw_info_pa, GFP_KERNEL);
if (!vdev->fw_info)
return -ENOMEM;
@@ -361,8 +361,8 @@ int vnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats)
int wait = 1000;
if (!vdev->stats) {
- vdev->stats = pci_alloc_consistent(vdev->pdev,
- sizeof(struct vnic_stats), &vdev->stats_pa);
+ vdev->stats = dma_alloc_coherent(&vdev->pdev->dev,
+ sizeof(struct vnic_stats), &vdev->stats_pa, GFP_KERNEL);
if (!vdev->stats)
return -ENOMEM;
}
@@ -523,9 +523,9 @@ int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr)
int wait = 1000;
if (!vdev->notify) {
- vdev->notify = pci_alloc_consistent(vdev->pdev,
+ vdev->notify = dma_alloc_coherent(&vdev->pdev->dev,
sizeof(struct vnic_devcmd_notify),
- &vdev->notify_pa);
+ &vdev->notify_pa, GFP_KERNEL);
if (!vdev->notify)
return -ENOMEM;
}
@@ -647,21 +647,21 @@ void vnic_dev_unregister(struct vnic_dev *vdev)
{
if (vdev) {
if (vdev->notify)
- pci_free_consistent(vdev->pdev,
+ dma_free_coherent(&vdev->pdev->dev,
sizeof(struct vnic_devcmd_notify),
vdev->notify,
vdev->notify_pa);
if (vdev->linkstatus)
- pci_free_consistent(vdev->pdev,
+ dma_free_coherent(&vdev->pdev->dev,
sizeof(u32),
vdev->linkstatus,
vdev->linkstatus_pa);
if (vdev->stats)
- pci_free_consistent(vdev->pdev,
+ dma_free_coherent(&vdev->pdev->dev,
sizeof(struct vnic_stats),
vdev->stats, vdev->stats_pa);
if (vdev->fw_info)
- pci_free_consistent(vdev->pdev,
+ dma_free_coherent(&vdev->pdev->dev,
sizeof(struct vnic_devcmd_fw_info),
vdev->fw_info, vdev->fw_info_pa);
kfree(vdev);
diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
index 6c7d2e201abe..0ddb53c8a2e2 100644
--- a/drivers/scsi/hisi_sas/hisi_sas.h
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -34,6 +34,7 @@
#define HISI_SAS_MAX_DEVICES HISI_SAS_MAX_ITCT_ENTRIES
#define HISI_SAS_RESET_BIT 0
#define HISI_SAS_REJECT_CMD_BIT 1
+#define HISI_SAS_RESERVED_IPTT_CNT 96
#define HISI_SAS_STATUS_BUF_SZ (sizeof(struct hisi_sas_status_buffer))
#define HISI_SAS_COMMAND_TABLE_SZ (sizeof(union hisi_sas_command_table))
@@ -217,7 +218,7 @@ struct hisi_sas_hw {
int (*hw_init)(struct hisi_hba *hisi_hba);
void (*setup_itct)(struct hisi_hba *hisi_hba,
struct hisi_sas_device *device);
- int (*slot_index_alloc)(struct hisi_hba *hisi_hba, int *slot_idx,
+ int (*slot_index_alloc)(struct hisi_hba *hisi_hba,
struct domain_device *device);
struct hisi_sas_device *(*alloc_dev)(struct domain_device *device);
void (*sl_notify)(struct hisi_hba *hisi_hba, int phy_no);
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index a4e2e6aa9a6b..b3f01d5b821b 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -183,7 +183,14 @@ static void hisi_sas_slot_index_clear(struct hisi_hba *hisi_hba, int slot_idx)
static void hisi_sas_slot_index_free(struct hisi_hba *hisi_hba, int slot_idx)
{
- hisi_sas_slot_index_clear(hisi_hba, slot_idx);
+ unsigned long flags;
+
+ if (hisi_hba->hw->slot_index_alloc || (slot_idx >=
+ hisi_hba->hw->max_command_entries - HISI_SAS_RESERVED_IPTT_CNT)) {
+ spin_lock_irqsave(&hisi_hba->lock, flags);
+ hisi_sas_slot_index_clear(hisi_hba, slot_idx);
+ spin_unlock_irqrestore(&hisi_hba->lock, flags);
+ }
}
static void hisi_sas_slot_index_set(struct hisi_hba *hisi_hba, int slot_idx)
@@ -193,24 +200,34 @@ static void hisi_sas_slot_index_set(struct hisi_hba *hisi_hba, int slot_idx)
set_bit(slot_idx, bitmap);
}
-static int hisi_sas_slot_index_alloc(struct hisi_hba *hisi_hba, int *slot_idx)
+static int hisi_sas_slot_index_alloc(struct hisi_hba *hisi_hba,
+ struct scsi_cmnd *scsi_cmnd)
{
- unsigned int index;
+ int index;
void *bitmap = hisi_hba->slot_index_tags;
+ unsigned long flags;
+
+ if (scsi_cmnd)
+ return scsi_cmnd->request->tag;
+ spin_lock_irqsave(&hisi_hba->lock, flags);
index = find_next_zero_bit(bitmap, hisi_hba->slot_index_count,
- hisi_hba->last_slot_index + 1);
+ hisi_hba->last_slot_index + 1);
if (index >= hisi_hba->slot_index_count) {
- index = find_next_zero_bit(bitmap, hisi_hba->slot_index_count,
- 0);
- if (index >= hisi_hba->slot_index_count)
+ index = find_next_zero_bit(bitmap,
+ hisi_hba->slot_index_count,
+ hisi_hba->hw->max_command_entries -
+ HISI_SAS_RESERVED_IPTT_CNT);
+ if (index >= hisi_hba->slot_index_count) {
+ spin_unlock_irqrestore(&hisi_hba->lock, flags);
return -SAS_QUEUE_FULL;
+ }
}
hisi_sas_slot_index_set(hisi_hba, index);
- *slot_idx = index;
hisi_hba->last_slot_index = index;
+ spin_unlock_irqrestore(&hisi_hba->lock, flags);
- return 0;
+ return index;
}
static void hisi_sas_slot_index_init(struct hisi_hba *hisi_hba)
@@ -249,9 +266,7 @@ void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task,
memset(slot, 0, offsetof(struct hisi_sas_slot, buf));
- spin_lock_irqsave(&hisi_hba->lock, flags);
hisi_sas_slot_index_free(hisi_hba, slot->idx);
- spin_unlock_irqrestore(&hisi_hba->lock, flags);
}
EXPORT_SYMBOL_GPL(hisi_sas_slot_task_free);
@@ -287,13 +302,13 @@ static int hisi_sas_task_prep(struct sas_task *task,
int *pass)
{
struct domain_device *device = task->dev;
- struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
+ struct hisi_hba *hisi_hba;
struct hisi_sas_device *sas_dev = device->lldd_dev;
struct hisi_sas_port *port;
struct hisi_sas_slot *slot;
struct hisi_sas_cmd_hdr *cmd_hdr_base;
struct asd_sas_port *sas_port = device->port;
- struct device *dev = hisi_hba->dev;
+ struct device *dev;
int dlvry_queue_slot, dlvry_queue, rc, slot_idx;
int n_elem = 0, n_elem_req = 0, n_elem_resp = 0;
struct hisi_sas_dq *dq;
@@ -314,6 +329,9 @@ static int hisi_sas_task_prep(struct sas_task *task,
return -ECOMM;
}
+ hisi_hba = dev_to_hisi_hba(device);
+ dev = hisi_hba->dev;
+
if (DEV_IS_GONE(sas_dev)) {
if (sas_dev)
dev_info(dev, "task prep: device %d not ready\n",
@@ -381,16 +399,27 @@ static int hisi_sas_task_prep(struct sas_task *task,
goto err_out_dma_unmap;
}
- spin_lock_irqsave(&hisi_hba->lock, flags);
if (hisi_hba->hw->slot_index_alloc)
- rc = hisi_hba->hw->slot_index_alloc(hisi_hba, &slot_idx,
- device);
- else
- rc = hisi_sas_slot_index_alloc(hisi_hba, &slot_idx);
- spin_unlock_irqrestore(&hisi_hba->lock, flags);
- if (rc)
+ rc = hisi_hba->hw->slot_index_alloc(hisi_hba, device);
+ else {
+ struct scsi_cmnd *scsi_cmnd = NULL;
+
+ if (task->uldd_task) {
+ struct ata_queued_cmd *qc;
+
+ if (dev_is_sata(device)) {
+ qc = task->uldd_task;
+ scsi_cmnd = qc->scsicmd;
+ } else {
+ scsi_cmnd = task->uldd_task;
+ }
+ }
+ rc = hisi_sas_slot_index_alloc(hisi_hba, scsi_cmnd);
+ }
+ if (rc < 0)
goto err_out_dma_unmap;
+ slot_idx = rc;
slot = &hisi_hba->slot_info[slot_idx];
spin_lock_irqsave(&dq->lock, flags);
@@ -451,9 +480,7 @@ static int hisi_sas_task_prep(struct sas_task *task,
return 0;
err_out_tag:
- spin_lock_irqsave(&hisi_hba->lock, flags);
hisi_sas_slot_index_free(hisi_hba, slot_idx);
- spin_unlock_irqrestore(&hisi_hba->lock, flags);
err_out_dma_unmap:
if (!sas_protocol_ata(task->task_proto)) {
if (task->num_scatter) {
@@ -904,6 +931,9 @@ static void hisi_sas_phy_set_linkrate(struct hisi_hba *hisi_hba, int phy_no,
_r.maximum_linkrate = max;
_r.minimum_linkrate = min;
+ sas_phy->phy->maximum_linkrate = max;
+ sas_phy->phy->minimum_linkrate = min;
+
hisi_hba->hw->phy_disable(hisi_hba, phy_no);
msleep(100);
hisi_hba->hw->phy_set_linkrate(hisi_hba, phy_no, &_r);
@@ -950,8 +980,7 @@ static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func,
static void hisi_sas_task_done(struct sas_task *task)
{
- if (!del_timer(&task->slow_task->timer))
- return;
+ del_timer(&task->slow_task->timer);
complete(&task->slow_task->completion);
}
@@ -960,13 +989,17 @@ static void hisi_sas_tmf_timedout(struct timer_list *t)
struct sas_task_slow *slow = from_timer(slow, t, timer);
struct sas_task *task = slow->task;
unsigned long flags;
+ bool is_completed = true;
spin_lock_irqsave(&task->task_state_lock, flags);
- if (!(task->task_state_flags & SAS_TASK_STATE_DONE))
+ if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
task->task_state_flags |= SAS_TASK_STATE_ABORTED;
+ is_completed = false;
+ }
spin_unlock_irqrestore(&task->task_state_lock, flags);
- complete(&task->slow_task->completion);
+ if (!is_completed)
+ complete(&task->slow_task->completion);
}
#define TASK_TIMEOUT 20
@@ -1019,8 +1052,16 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device,
struct hisi_sas_slot *slot = task->lldd_task;
dev_err(dev, "abort tmf: TMF task timeout and not done\n");
- if (slot)
+ if (slot) {
+ struct hisi_sas_cq *cq =
+ &hisi_hba->cq[slot->dlvry_queue];
+ /*
+ * flush tasklet to avoid free'ing task
+ * before using task in IO completion
+ */
+ tasklet_kill(&cq->tasklet);
slot->task = NULL;
+ }
goto ex_err;
} else
@@ -1396,6 +1437,17 @@ static int hisi_sas_abort_task(struct sas_task *task)
spin_lock_irqsave(&task->task_state_lock, flags);
if (task->task_state_flags & SAS_TASK_STATE_DONE) {
+ struct hisi_sas_slot *slot = task->lldd_task;
+ struct hisi_sas_cq *cq;
+
+ if (slot) {
+ /*
+ * flush tasklet to avoid free'ing task
+ * before using task in IO completion
+ */
+ cq = &hisi_hba->cq[slot->dlvry_queue];
+ tasklet_kill(&cq->tasklet);
+ }
spin_unlock_irqrestore(&task->task_state_lock, flags);
rc = TMF_RESP_FUNC_COMPLETE;
goto out;
@@ -1451,12 +1503,19 @@ static int hisi_sas_abort_task(struct sas_task *task)
/* SMP */
struct hisi_sas_slot *slot = task->lldd_task;
u32 tag = slot->idx;
+ 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);
if (((rc < 0) || (rc == TMF_RESP_FUNC_FAILED)) &&
- task->lldd_task)
- hisi_sas_do_release_task(hisi_hba, task, slot);
+ task->lldd_task) {
+ /*
+ * flush tasklet to avoid free'ing task
+ * before using task in IO completion
+ */
+ tasklet_kill(&cq->tasklet);
+ slot->task = NULL;
+ }
}
out:
@@ -1705,14 +1764,11 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id,
port = to_hisi_sas_port(sas_port);
/* simply get a slot and send abort command */
- spin_lock_irqsave(&hisi_hba->lock, flags);
- rc = hisi_sas_slot_index_alloc(hisi_hba, &slot_idx);
- if (rc) {
- spin_unlock_irqrestore(&hisi_hba->lock, flags);
+ rc = hisi_sas_slot_index_alloc(hisi_hba, NULL);
+ if (rc < 0)
goto err_out;
- }
- spin_unlock_irqrestore(&hisi_hba->lock, flags);
+ slot_idx = rc;
slot = &hisi_hba->slot_info[slot_idx];
spin_lock_irqsave(&dq->lock, flags_dq);
@@ -1748,7 +1804,6 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id,
spin_lock_irqsave(&task->task_state_lock, flags);
task->task_state_flags |= SAS_TASK_AT_INITIATOR;
spin_unlock_irqrestore(&task->task_state_lock, flags);
-
WRITE_ONCE(slot->ready, 1);
/* send abort command to the chip */
spin_lock_irqsave(&dq->lock, flags);
@@ -1759,9 +1814,7 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id,
return 0;
err_out_tag:
- spin_lock_irqsave(&hisi_hba->lock, flags);
hisi_sas_slot_index_free(hisi_hba, slot_idx);
- spin_unlock_irqrestore(&hisi_hba->lock, flags);
err_out:
dev_err(dev, "internal abort task prep: failed[%d]!\n", rc);
@@ -1823,8 +1876,16 @@ 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;
- if (slot)
+ if (slot) {
+ struct hisi_sas_cq *cq =
+ &hisi_hba->cq[slot->dlvry_queue];
+ /*
+ * flush tasklet to avoid free'ing task
+ * before using task in IO completion
+ */
+ tasklet_kill(&cq->tasklet);
slot->task = NULL;
+ }
dev_err(dev, "internal task abort: timeout and not done.\n");
res = -EIO;
goto exit;
@@ -1861,10 +1922,6 @@ static void hisi_sas_port_formed(struct asd_sas_phy *sas_phy)
hisi_sas_port_notify_formed(sas_phy);
}
-static void hisi_sas_port_deformed(struct asd_sas_phy *sas_phy)
-{
-}
-
static int hisi_sas_write_gpio(struct sas_ha_struct *sha, u8 reg_type,
u8 reg_index, u8 reg_count, u8 *write_data)
{
@@ -1954,10 +2011,9 @@ static struct sas_domain_function_template hisi_sas_transport_ops = {
.lldd_I_T_nexus_reset = hisi_sas_I_T_nexus_reset,
.lldd_lu_reset = hisi_sas_lu_reset,
.lldd_query_task = hisi_sas_query_task,
- .lldd_clear_nexus_ha = hisi_sas_clear_nexus_ha,
+ .lldd_clear_nexus_ha = hisi_sas_clear_nexus_ha,
.lldd_port_formed = hisi_sas_port_formed,
- .lldd_port_deformed = hisi_sas_port_deformed,
- .lldd_write_gpio = hisi_sas_write_gpio,
+ .lldd_write_gpio = hisi_sas_write_gpio,
};
void hisi_sas_init_mem(struct hisi_hba *hisi_hba)
@@ -2120,6 +2176,8 @@ int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost)
hisi_sas_init_mem(hisi_hba);
hisi_sas_slot_index_init(hisi_hba);
+ hisi_hba->last_slot_index = hisi_hba->hw->max_command_entries -
+ HISI_SAS_RESERVED_IPTT_CNT;
hisi_hba->wq = create_singlethread_workqueue(dev_name(dev));
if (!hisi_hba->wq) {
@@ -2323,8 +2381,15 @@ int hisi_sas_probe(struct platform_device *pdev,
shost->max_channel = 1;
shost->max_cmd_len = 16;
shost->sg_tablesize = min_t(u16, SG_ALL, HISI_SAS_SGE_PAGE_CNT);
- shost->can_queue = hisi_hba->hw->max_command_entries;
- shost->cmd_per_lun = hisi_hba->hw->max_command_entries;
+ if (hisi_hba->hw->slot_index_alloc) {
+ shost->can_queue = hisi_hba->hw->max_command_entries;
+ shost->cmd_per_lun = hisi_hba->hw->max_command_entries;
+ } else {
+ shost->can_queue = hisi_hba->hw->max_command_entries -
+ HISI_SAS_RESERVED_IPTT_CNT;
+ shost->cmd_per_lun = hisi_hba->hw->max_command_entries -
+ HISI_SAS_RESERVED_IPTT_CNT;
+ }
sha->sas_ha_name = DRV_NAME;
sha->dev = hisi_hba->dev;
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
index 8f60f0e04599..8df822a4a1bd 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
@@ -904,11 +904,9 @@ static void start_delivery_v1_hw(struct hisi_sas_dq *dq)
{
struct hisi_hba *hisi_hba = dq->hisi_hba;
struct hisi_sas_slot *s, *s1, *s2 = NULL;
- struct list_head *dq_list;
int dlvry_queue = dq->id;
int wp;
- dq_list = &dq->list;
list_for_each_entry_safe(s, s1, &dq->list, delivery) {
if (!s->ready)
break;
@@ -1809,7 +1807,6 @@ static struct scsi_host_template sht_v1_hw = {
.scan_start = hisi_sas_scan_start,
.change_queue_depth = sas_change_queue_depth,
.bios_param = sas_bios_param,
- .can_queue = 1,
.this_id = -1,
.sg_tablesize = SG_ALL,
.max_sectors = SCSI_DEFAULT_MAX_SECTORS,
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
index 9c5c5a601332..77a85ead483e 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -770,7 +770,7 @@ static u32 hisi_sas_phy_read32(struct hisi_hba *hisi_hba,
/* This function needs to be protected from pre-emption. */
static int
-slot_index_alloc_quirk_v2_hw(struct hisi_hba *hisi_hba, int *slot_idx,
+slot_index_alloc_quirk_v2_hw(struct hisi_hba *hisi_hba,
struct domain_device *device)
{
int sata_dev = dev_is_sata(device);
@@ -778,6 +778,7 @@ slot_index_alloc_quirk_v2_hw(struct hisi_hba *hisi_hba, int *slot_idx,
struct hisi_sas_device *sas_dev = device->lldd_dev;
int sata_idx = sas_dev->sata_idx;
int start, end;
+ unsigned long flags;
if (!sata_dev) {
/*
@@ -801,11 +802,14 @@ slot_index_alloc_quirk_v2_hw(struct hisi_hba *hisi_hba, int *slot_idx,
end = 64 * (sata_idx + 2);
}
+ spin_lock_irqsave(&hisi_hba->lock, flags);
while (1) {
start = find_next_zero_bit(bitmap,
hisi_hba->slot_index_count, start);
- if (start >= end)
+ if (start >= end) {
+ spin_unlock_irqrestore(&hisi_hba->lock, flags);
return -SAS_QUEUE_FULL;
+ }
/*
* SAS IPTT bit0 should be 1, and SATA IPTT bit0 should be 0.
*/
@@ -815,8 +819,8 @@ slot_index_alloc_quirk_v2_hw(struct hisi_hba *hisi_hba, int *slot_idx,
}
set_bit(start, bitmap);
- *slot_idx = start;
- return 0;
+ spin_unlock_irqrestore(&hisi_hba->lock, flags);
+ return start;
}
static bool sata_index_alloc_v2_hw(struct hisi_hba *hisi_hba, int *idx)
@@ -1666,11 +1670,9 @@ static void start_delivery_v2_hw(struct hisi_sas_dq *dq)
{
struct hisi_hba *hisi_hba = dq->hisi_hba;
struct hisi_sas_slot *s, *s1, *s2 = NULL;
- struct list_head *dq_list;
int dlvry_queue = dq->id;
int wp;
- dq_list = &dq->list;
list_for_each_entry_safe(s, s1, &dq->list, delivery) {
if (!s->ready)
break;
@@ -2483,7 +2485,6 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot)
}
out:
- hisi_sas_slot_task_free(hisi_hba, task, slot);
sts = ts->stat;
spin_lock_irqsave(&task->task_state_lock, flags);
if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
@@ -2493,6 +2494,7 @@ out:
}
task->task_state_flags |= SAS_TASK_STATE_DONE;
spin_unlock_irqrestore(&task->task_state_lock, flags);
+ hisi_sas_slot_task_free(hisi_hba, task, slot);
if (!is_internal && (task->task_proto != SAS_PROTOCOL_SMP)) {
spin_lock_irqsave(&device->done_lock, flags);
@@ -3560,7 +3562,6 @@ static struct scsi_host_template sht_v2_hw = {
.scan_start = hisi_sas_scan_start,
.change_queue_depth = sas_change_queue_depth,
.bios_param = sas_bios_param,
- .can_queue = 1,
.this_id = -1,
.sg_tablesize = SG_ALL,
.max_sectors = SCSI_DEFAULT_MAX_SECTORS,
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index 08b503e274b8..a369450a1fa7 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -127,6 +127,7 @@
#define PHY_CTRL_RESET_OFF 0
#define PHY_CTRL_RESET_MSK (0x1 << PHY_CTRL_RESET_OFF)
#define SL_CFG (PORT_BASE + 0x84)
+#define AIP_LIMIT (PORT_BASE + 0x90)
#define SL_CONTROL (PORT_BASE + 0x94)
#define SL_CONTROL_NOTIFY_EN_OFF 0
#define SL_CONTROL_NOTIFY_EN_MSK (0x1 << SL_CONTROL_NOTIFY_EN_OFF)
@@ -431,6 +432,7 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
(u32)((1ULL << hisi_hba->queue_count) - 1));
hisi_sas_write32(hisi_hba, CFG_MAX_TAG, 0xfff0400);
hisi_sas_write32(hisi_hba, HGC_SAS_TXFAIL_RETRY_CTRL, 0x108);
+ hisi_sas_write32(hisi_hba, CFG_AGING_TIME, 0x1);
hisi_sas_write32(hisi_hba, INT_COAL_EN, 0x1);
hisi_sas_write32(hisi_hba, OQ_INT_COAL_TIME, 0x1);
hisi_sas_write32(hisi_hba, OQ_INT_COAL_CNT, 0x1);
@@ -441,7 +443,7 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1, 0xfefefefe);
hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK2, 0xfefefefe);
if (pdev->revision >= 0x21)
- hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, 0xffff7fff);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, 0xffff7aff);
else
hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, 0xfffe20ff);
hisi_sas_write32(hisi_hba, CHNL_PHYUPDOWN_INT_MSK, 0x0);
@@ -495,6 +497,7 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
/* used for 12G negotiate */
hisi_sas_phy_write32(hisi_hba, i, COARSETUNE_TIME, 0x1e);
+ hisi_sas_phy_write32(hisi_hba, i, AIP_LIMIT, 0x2ffff);
}
for (i = 0; i < hisi_hba->queue_count; i++) {
@@ -883,11 +886,9 @@ static void start_delivery_v3_hw(struct hisi_sas_dq *dq)
{
struct hisi_hba *hisi_hba = dq->hisi_hba;
struct hisi_sas_slot *s, *s1, *s2 = NULL;
- struct list_head *dq_list;
int dlvry_queue = dq->id;
int wp;
- dq_list = &dq->list;
list_for_each_entry_safe(s, s1, &dq->list, delivery) {
if (!s->ready)
break;
@@ -1751,7 +1752,6 @@ slot_complete_v3_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot)
}
out:
- hisi_sas_slot_task_free(hisi_hba, task, slot);
sts = ts->stat;
spin_lock_irqsave(&task->task_state_lock, flags);
if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
@@ -1761,6 +1761,7 @@ out:
}
task->task_state_flags |= SAS_TASK_STATE_DONE;
spin_unlock_irqrestore(&task->task_state_lock, flags);
+ hisi_sas_slot_task_free(hisi_hba, task, slot);
if (!is_internal && (task->task_proto != SAS_PROTOCOL_SMP)) {
spin_lock_irqsave(&device->done_lock, flags);
@@ -2098,7 +2099,6 @@ static struct scsi_host_template sht_v3_hw = {
.scan_start = hisi_sas_scan_start,
.change_queue_depth = sas_change_queue_depth,
.bios_param = sas_bios_param,
- .can_queue = 1,
.this_id = -1,
.sg_tablesize = SG_ALL,
.max_sectors = SCSI_DEFAULT_MAX_SECTORS,
@@ -2108,6 +2108,7 @@ static struct scsi_host_template sht_v3_hw = {
.target_destroy = sas_target_destroy,
.ioctl = sas_ioctl,
.shost_attrs = host_attrs,
+ .tag_alloc_policy = BLK_TAG_ALLOC_RR,
};
static const struct hisi_sas_hw hisi_sas_v3_hw = {
@@ -2245,8 +2246,10 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id)
shost->max_channel = 1;
shost->max_cmd_len = 16;
shost->sg_tablesize = min_t(u16, SG_ALL, HISI_SAS_SGE_PAGE_CNT);
- shost->can_queue = hisi_hba->hw->max_command_entries;
- shost->cmd_per_lun = hisi_hba->hw->max_command_entries;
+ shost->can_queue = hisi_hba->hw->max_command_entries -
+ HISI_SAS_RESERVED_IPTT_CNT;
+ shost->cmd_per_lun = hisi_hba->hw->max_command_entries -
+ HISI_SAS_RESERVED_IPTT_CNT;
sha->sas_ha_name = DRV_NAME;
sha->dev = dev;
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index c120929d4ffe..c9cccf35e9d7 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -2240,8 +2240,8 @@ static int hpsa_map_ioaccel2_sg_chain_block(struct ctlr_info *h,
chain_block = h->ioaccel2_cmd_sg_list[c->cmdindex];
chain_size = le32_to_cpu(cp->sg[0].length);
- temp64 = pci_map_single(h->pdev, chain_block, chain_size,
- PCI_DMA_TODEVICE);
+ temp64 = dma_map_single(&h->pdev->dev, chain_block, chain_size,
+ DMA_TO_DEVICE);
if (dma_mapping_error(&h->pdev->dev, temp64)) {
/* prevent subsequent unmapping */
cp->sg->address = 0;
@@ -2261,7 +2261,7 @@ static void hpsa_unmap_ioaccel2_sg_chain_block(struct ctlr_info *h,
chain_sg = cp->sg;
temp64 = le64_to_cpu(chain_sg->address);
chain_size = le32_to_cpu(cp->sg[0].length);
- pci_unmap_single(h->pdev, temp64, chain_size, PCI_DMA_TODEVICE);
+ dma_unmap_single(&h->pdev->dev, temp64, chain_size, DMA_TO_DEVICE);
}
static int hpsa_map_sg_chain_block(struct ctlr_info *h,
@@ -2277,8 +2277,8 @@ static int hpsa_map_sg_chain_block(struct ctlr_info *h,
chain_len = sizeof(*chain_sg) *
(le16_to_cpu(c->Header.SGTotal) - h->max_cmd_sg_entries);
chain_sg->Len = cpu_to_le32(chain_len);
- temp64 = pci_map_single(h->pdev, chain_block, chain_len,
- PCI_DMA_TODEVICE);
+ temp64 = dma_map_single(&h->pdev->dev, chain_block, chain_len,
+ DMA_TO_DEVICE);
if (dma_mapping_error(&h->pdev->dev, temp64)) {
/* prevent subsequent unmapping */
chain_sg->Addr = cpu_to_le64(0);
@@ -2297,8 +2297,8 @@ static void hpsa_unmap_sg_chain_block(struct ctlr_info *h,
return;
chain_sg = &c->SG[h->max_cmd_sg_entries - 1];
- pci_unmap_single(h->pdev, le64_to_cpu(chain_sg->Addr),
- le32_to_cpu(chain_sg->Len), PCI_DMA_TODEVICE);
+ dma_unmap_single(&h->pdev->dev, le64_to_cpu(chain_sg->Addr),
+ le32_to_cpu(chain_sg->Len), DMA_TO_DEVICE);
}
@@ -2759,13 +2759,13 @@ static void complete_scsi_command(struct CommandList *cp)
return hpsa_cmd_free_and_done(h, cp, cmd);
}
-static void hpsa_pci_unmap(struct pci_dev *pdev,
- struct CommandList *c, int sg_used, int data_direction)
+static void hpsa_pci_unmap(struct pci_dev *pdev, struct CommandList *c,
+ int sg_used, enum dma_data_direction data_direction)
{
int i;
for (i = 0; i < sg_used; i++)
- pci_unmap_single(pdev, (dma_addr_t) le64_to_cpu(c->SG[i].Addr),
+ dma_unmap_single(&pdev->dev, le64_to_cpu(c->SG[i].Addr),
le32_to_cpu(c->SG[i].Len),
data_direction);
}
@@ -2774,17 +2774,17 @@ static int hpsa_map_one(struct pci_dev *pdev,
struct CommandList *cp,
unsigned char *buf,
size_t buflen,
- int data_direction)
+ enum dma_data_direction data_direction)
{
u64 addr64;
- if (buflen == 0 || data_direction == PCI_DMA_NONE) {
+ if (buflen == 0 || data_direction == DMA_NONE) {
cp->Header.SGList = 0;
cp->Header.SGTotal = cpu_to_le16(0);
return 0;
}
- addr64 = pci_map_single(pdev, buf, buflen, data_direction);
+ addr64 = dma_map_single(&pdev->dev, buf, buflen, data_direction);
if (dma_mapping_error(&pdev->dev, addr64)) {
/* Prevent subsequent unmap of something never mapped */
cp->Header.SGList = 0;
@@ -2845,7 +2845,8 @@ static u32 lockup_detected(struct ctlr_info *h)
#define MAX_DRIVER_CMD_RETRIES 25
static int hpsa_scsi_do_simple_cmd_with_retry(struct ctlr_info *h,
- struct CommandList *c, int data_direction, unsigned long timeout_msecs)
+ struct CommandList *c, enum dma_data_direction data_direction,
+ unsigned long timeout_msecs)
{
int backoff_time = 10, retry_count = 0;
int rc;
@@ -2969,8 +2970,8 @@ static int hpsa_do_receive_diagnostic(struct ctlr_info *h, u8 *scsi3addr,
rc = -1;
goto out;
}
- rc = hpsa_scsi_do_simple_cmd_with_retry(h, c,
- PCI_DMA_FROMDEVICE, NO_TIMEOUT);
+ rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, DMA_FROM_DEVICE,
+ NO_TIMEOUT);
if (rc)
goto out;
ei = c->err_info;
@@ -3022,8 +3023,8 @@ static int hpsa_scsi_do_inquiry(struct ctlr_info *h, unsigned char *scsi3addr,
rc = -1;
goto out;
}
- rc = hpsa_scsi_do_simple_cmd_with_retry(h, c,
- PCI_DMA_FROMDEVICE, NO_TIMEOUT);
+ rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, DMA_FROM_DEVICE,
+ NO_TIMEOUT);
if (rc)
goto out;
ei = c->err_info;
@@ -3306,8 +3307,8 @@ static int hpsa_get_raid_map(struct ctlr_info *h,
cmd_free(h, c);
return -1;
}
- rc = hpsa_scsi_do_simple_cmd_with_retry(h, c,
- PCI_DMA_FROMDEVICE, NO_TIMEOUT);
+ rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, DMA_FROM_DEVICE,
+ NO_TIMEOUT);
if (rc)
goto out;
ei = c->err_info;
@@ -3349,8 +3350,8 @@ static int hpsa_bmic_sense_subsystem_information(struct ctlr_info *h,
c->Request.CDB[2] = bmic_device_index & 0xff;
c->Request.CDB[9] = (bmic_device_index >> 8) & 0xff;
- rc = hpsa_scsi_do_simple_cmd_with_retry(h, c,
- PCI_DMA_FROMDEVICE, NO_TIMEOUT);
+ rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, DMA_FROM_DEVICE,
+ NO_TIMEOUT);
if (rc)
goto out;
ei = c->err_info;
@@ -3377,8 +3378,8 @@ static int hpsa_bmic_id_controller(struct ctlr_info *h,
if (rc)
goto out;
- rc = hpsa_scsi_do_simple_cmd_with_retry(h, c,
- PCI_DMA_FROMDEVICE, NO_TIMEOUT);
+ rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, DMA_FROM_DEVICE,
+ NO_TIMEOUT);
if (rc)
goto out;
ei = c->err_info;
@@ -3408,7 +3409,7 @@ static int hpsa_bmic_id_physical_device(struct ctlr_info *h,
c->Request.CDB[2] = bmic_device_index & 0xff;
c->Request.CDB[9] = (bmic_device_index >> 8) & 0xff;
- hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE,
+ hpsa_scsi_do_simple_cmd_with_retry(h, c, DMA_FROM_DEVICE,
NO_TIMEOUT);
ei = c->err_info;
if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) {
@@ -3484,7 +3485,7 @@ static void hpsa_get_enclosure_info(struct ctlr_info *h,
else
c->Request.CDB[5] = 0;
- rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE,
+ rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, DMA_FROM_DEVICE,
NO_TIMEOUT);
if (rc)
goto out;
@@ -3731,8 +3732,8 @@ static int hpsa_scsi_do_report_luns(struct ctlr_info *h, int logical,
}
if (extended_response)
c->Request.CDB[1] = extended_response;
- rc = hpsa_scsi_do_simple_cmd_with_retry(h, c,
- PCI_DMA_FROMDEVICE, NO_TIMEOUT);
+ rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, DMA_FROM_DEVICE,
+ NO_TIMEOUT);
if (rc)
goto out;
ei = c->err_info;
@@ -6320,8 +6321,8 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp)
/* Fill in the scatter gather information */
if (iocommand.buf_size > 0) {
- temp64 = pci_map_single(h->pdev, buff,
- iocommand.buf_size, PCI_DMA_BIDIRECTIONAL);
+ temp64 = dma_map_single(&h->pdev->dev, buff,
+ iocommand.buf_size, DMA_BIDIRECTIONAL);
if (dma_mapping_error(&h->pdev->dev, (dma_addr_t) temp64)) {
c->SG[0].Addr = cpu_to_le64(0);
c->SG[0].Len = cpu_to_le32(0);
@@ -6335,7 +6336,7 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp)
rc = hpsa_scsi_do_simple_cmd(h, c, DEFAULT_REPLY_QUEUE,
NO_TIMEOUT);
if (iocommand.buf_size > 0)
- hpsa_pci_unmap(h->pdev, c, 1, PCI_DMA_BIDIRECTIONAL);
+ hpsa_pci_unmap(h->pdev, c, 1, DMA_BIDIRECTIONAL);
check_ioctl_unit_attention(h, c);
if (rc) {
rc = -EIO;
@@ -6381,13 +6382,9 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp)
return -EINVAL;
if (!capable(CAP_SYS_RAWIO))
return -EPERM;
- ioc = kmalloc(sizeof(*ioc), GFP_KERNEL);
- if (!ioc) {
- status = -ENOMEM;
- goto cleanup1;
- }
- if (copy_from_user(ioc, argp, sizeof(*ioc))) {
- status = -EFAULT;
+ ioc = vmemdup_user(argp, sizeof(*ioc));
+ if (IS_ERR(ioc)) {
+ status = PTR_ERR(ioc);
goto cleanup1;
}
if ((ioc->buf_size < 1) &&
@@ -6447,14 +6444,14 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp)
if (ioc->buf_size > 0) {
int i;
for (i = 0; i < sg_used; i++) {
- temp64 = pci_map_single(h->pdev, buff[i],
- buff_size[i], PCI_DMA_BIDIRECTIONAL);
+ temp64 = dma_map_single(&h->pdev->dev, buff[i],
+ buff_size[i], DMA_BIDIRECTIONAL);
if (dma_mapping_error(&h->pdev->dev,
(dma_addr_t) temp64)) {
c->SG[i].Addr = cpu_to_le64(0);
c->SG[i].Len = cpu_to_le32(0);
hpsa_pci_unmap(h->pdev, c, i,
- PCI_DMA_BIDIRECTIONAL);
+ DMA_BIDIRECTIONAL);
status = -ENOMEM;
goto cleanup0;
}
@@ -6467,7 +6464,7 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp)
status = hpsa_scsi_do_simple_cmd(h, c, DEFAULT_REPLY_QUEUE,
NO_TIMEOUT);
if (sg_used)
- hpsa_pci_unmap(h->pdev, c, sg_used, PCI_DMA_BIDIRECTIONAL);
+ hpsa_pci_unmap(h->pdev, c, sg_used, DMA_BIDIRECTIONAL);
check_ioctl_unit_attention(h, c);
if (status) {
status = -EIO;
@@ -6505,7 +6502,7 @@ cleanup1:
kfree(buff);
}
kfree(buff_size);
- kfree(ioc);
+ kvfree(ioc);
return status;
}
@@ -6579,7 +6576,7 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
void *buff, size_t size, u16 page_code, unsigned char *scsi3addr,
int cmd_type)
{
- int pci_dir = XFER_NONE;
+ enum dma_data_direction dir = DMA_NONE;
c->cmd_type = CMD_IOCTL_PEND;
c->scsi_cmd = SCSI_CMD_BUSY;
@@ -6785,18 +6782,18 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
switch (GET_DIR(c->Request.type_attr_dir)) {
case XFER_READ:
- pci_dir = PCI_DMA_FROMDEVICE;
+ dir = DMA_FROM_DEVICE;
break;
case XFER_WRITE:
- pci_dir = PCI_DMA_TODEVICE;
+ dir = DMA_TO_DEVICE;
break;
case XFER_NONE:
- pci_dir = PCI_DMA_NONE;
+ dir = DMA_NONE;
break;
default:
- pci_dir = PCI_DMA_BIDIRECTIONAL;
+ dir = DMA_BIDIRECTIONAL;
}
- if (hpsa_map_one(h->pdev, c, buff, size, pci_dir))
+ if (hpsa_map_one(h->pdev, c, buff, size, dir))
return -1;
return 0;
}
@@ -6992,13 +6989,13 @@ static int hpsa_message(struct pci_dev *pdev, unsigned char opcode,
* CCISS commands, so they must be allocated from the lower 4GiB of
* memory.
*/
- err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+ err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
if (err) {
iounmap(vaddr);
return err;
}
- cmd = pci_alloc_consistent(pdev, cmd_sz, &paddr64);
+ cmd = dma_alloc_coherent(&pdev->dev, cmd_sz, &paddr64, GFP_KERNEL);
if (cmd == NULL) {
iounmap(vaddr);
return -ENOMEM;
@@ -7047,7 +7044,7 @@ static int hpsa_message(struct pci_dev *pdev, unsigned char opcode,
return -ETIMEDOUT;
}
- pci_free_consistent(pdev, cmd_sz, cmd, paddr64);
+ dma_free_coherent(&pdev->dev, cmd_sz, cmd, paddr64);
if (tag & HPSA_ERROR_BIT) {
dev_err(&pdev->dev, "controller message %02x:%02x failed\n",
@@ -7914,7 +7911,7 @@ static void hpsa_free_cmd_pool(struct ctlr_info *h)
kfree(h->cmd_pool_bits);
h->cmd_pool_bits = NULL;
if (h->cmd_pool) {
- pci_free_consistent(h->pdev,
+ dma_free_coherent(&h->pdev->dev,
h->nr_cmds * sizeof(struct CommandList),
h->cmd_pool,
h->cmd_pool_dhandle);
@@ -7922,7 +7919,7 @@ static void hpsa_free_cmd_pool(struct ctlr_info *h)
h->cmd_pool_dhandle = 0;
}
if (h->errinfo_pool) {
- pci_free_consistent(h->pdev,
+ dma_free_coherent(&h->pdev->dev,
h->nr_cmds * sizeof(struct ErrorInfo),
h->errinfo_pool,
h->errinfo_pool_dhandle);
@@ -7936,12 +7933,12 @@ static int hpsa_alloc_cmd_pool(struct ctlr_info *h)
h->cmd_pool_bits = kcalloc(DIV_ROUND_UP(h->nr_cmds, BITS_PER_LONG),
sizeof(unsigned long),
GFP_KERNEL);
- h->cmd_pool = pci_alloc_consistent(h->pdev,
+ h->cmd_pool = dma_alloc_coherent(&h->pdev->dev,
h->nr_cmds * sizeof(*h->cmd_pool),
- &(h->cmd_pool_dhandle));
- h->errinfo_pool = pci_alloc_consistent(h->pdev,
+ &h->cmd_pool_dhandle, GFP_KERNEL);
+ h->errinfo_pool = dma_alloc_coherent(&h->pdev->dev,
h->nr_cmds * sizeof(*h->errinfo_pool),
- &(h->errinfo_pool_dhandle));
+ &h->errinfo_pool_dhandle, GFP_KERNEL);
if ((h->cmd_pool_bits == NULL)
|| (h->cmd_pool == NULL)
|| (h->errinfo_pool == NULL)) {
@@ -8068,7 +8065,7 @@ static void hpsa_free_reply_queues(struct ctlr_info *h)
for (i = 0; i < h->nreply_queues; i++) {
if (!h->reply_queue[i].head)
continue;
- pci_free_consistent(h->pdev,
+ dma_free_coherent(&h->pdev->dev,
h->reply_queue_size,
h->reply_queue[i].head,
h->reply_queue[i].busaddr);
@@ -8594,11 +8591,11 @@ reinit_after_soft_reset:
number_of_controllers++;
/* configure PCI DMA stuff */
- rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+ rc = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
if (rc == 0) {
dac = 1;
} else {
- rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ rc = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
if (rc == 0) {
dac = 0;
} else {
@@ -8797,8 +8794,8 @@ static void hpsa_flush_cache(struct ctlr_info *h)
RAID_CTLR_LUNID, TYPE_CMD)) {
goto out;
}
- rc = hpsa_scsi_do_simple_cmd_with_retry(h, c,
- PCI_DMA_TODEVICE, DEFAULT_TIMEOUT);
+ rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, DMA_TO_DEVICE,
+ DEFAULT_TIMEOUT);
if (rc)
goto out;
if (c->err_info->CommandStatus != 0)
@@ -8833,8 +8830,8 @@ static void hpsa_disable_rld_caching(struct ctlr_info *h)
RAID_CTLR_LUNID, TYPE_CMD))
goto errout;
- rc = hpsa_scsi_do_simple_cmd_with_retry(h, c,
- PCI_DMA_FROMDEVICE, NO_TIMEOUT);
+ rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, DMA_FROM_DEVICE,
+ NO_TIMEOUT);
if ((rc != 0) || (c->err_info->CommandStatus != 0))
goto errout;
@@ -8845,8 +8842,8 @@ static void hpsa_disable_rld_caching(struct ctlr_info *h)
RAID_CTLR_LUNID, TYPE_CMD))
goto errout;
- rc = hpsa_scsi_do_simple_cmd_with_retry(h, c,
- PCI_DMA_TODEVICE, NO_TIMEOUT);
+ rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, DMA_TO_DEVICE,
+ NO_TIMEOUT);
if ((rc != 0) || (c->err_info->CommandStatus != 0))
goto errout;
@@ -8855,8 +8852,8 @@ static void hpsa_disable_rld_caching(struct ctlr_info *h)
RAID_CTLR_LUNID, TYPE_CMD))
goto errout;
- rc = hpsa_scsi_do_simple_cmd_with_retry(h, c,
- PCI_DMA_FROMDEVICE, NO_TIMEOUT);
+ rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, DMA_FROM_DEVICE,
+ NO_TIMEOUT);
if ((rc != 0) || (c->err_info->CommandStatus != 0))
goto errout;
@@ -9228,9 +9225,9 @@ static int hpsa_alloc_ioaccel1_cmd_and_bft(struct ctlr_info *h)
BUILD_BUG_ON(sizeof(struct io_accel1_cmd) %
IOACCEL1_COMMANDLIST_ALIGNMENT);
h->ioaccel_cmd_pool =
- pci_alloc_consistent(h->pdev,
+ dma_alloc_coherent(&h->pdev->dev,
h->nr_cmds * sizeof(*h->ioaccel_cmd_pool),
- &(h->ioaccel_cmd_pool_dhandle));
+ &h->ioaccel_cmd_pool_dhandle, GFP_KERNEL);
h->ioaccel1_blockFetchTable =
kmalloc(((h->ioaccel_maxsg + 1) *
@@ -9281,9 +9278,9 @@ static int hpsa_alloc_ioaccel2_cmd_and_bft(struct ctlr_info *h)
BUILD_BUG_ON(sizeof(struct io_accel2_cmd) %
IOACCEL2_COMMANDLIST_ALIGNMENT);
h->ioaccel2_cmd_pool =
- pci_alloc_consistent(h->pdev,
+ dma_alloc_coherent(&h->pdev->dev,
h->nr_cmds * sizeof(*h->ioaccel2_cmd_pool),
- &(h->ioaccel2_cmd_pool_dhandle));
+ &h->ioaccel2_cmd_pool_dhandle, GFP_KERNEL);
h->ioaccel2_blockFetchTable =
kmalloc(((h->ioaccel_maxsg + 1) *
@@ -9356,9 +9353,10 @@ static int hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
h->reply_queue_size = h->max_commands * sizeof(u64);
for (i = 0; i < h->nreply_queues; i++) {
- h->reply_queue[i].head = pci_alloc_consistent(h->pdev,
+ h->reply_queue[i].head = dma_alloc_coherent(&h->pdev->dev,
h->reply_queue_size,
- &(h->reply_queue[i].busaddr));
+ &h->reply_queue[i].busaddr,
+ GFP_KERNEL);
if (!h->reply_queue[i].head) {
rc = -ENOMEM;
goto clean1; /* rq, ioaccel */
diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
index f42a619198c4..e63aadd10dfd 100644
--- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
+++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
@@ -2266,7 +2266,6 @@ static int ibmvscsis_drop_nexus(struct ibmvscsis_tport *tport)
/*
* Release the SCSI I_T Nexus to the emulated ibmvscsis Target Port
*/
- target_wait_for_sess_cmds(se_sess);
target_remove_session(se_sess);
tport->ibmv_nexus = NULL;
kfree(nexus);
diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
index bd6ac6b5980a..ee8a1ecd58fd 100644
--- a/drivers/scsi/ips.c
+++ b/drivers/scsi/ips.c
@@ -208,7 +208,7 @@ module_param(ips, charp, 0);
#define IPS_DMA_DIR(scb) ((!scb->scsi_cmd || ips_is_passthru(scb->scsi_cmd) || \
DMA_NONE == scb->scsi_cmd->sc_data_direction) ? \
- PCI_DMA_BIDIRECTIONAL : \
+ DMA_BIDIRECTIONAL : \
scb->scsi_cmd->sc_data_direction)
#ifdef IPS_DEBUG
@@ -1529,11 +1529,12 @@ ips_alloc_passthru_buffer(ips_ha_t * ha, int length)
if (ha->ioctl_data && length <= ha->ioctl_len)
return 0;
/* there is no buffer or it's not big enough, allocate a new one */
- bigger_buf = pci_alloc_consistent(ha->pcidev, length, &dma_busaddr);
+ bigger_buf = dma_alloc_coherent(&ha->pcidev->dev, length, &dma_busaddr,
+ GFP_KERNEL);
if (bigger_buf) {
/* free the old memory */
- pci_free_consistent(ha->pcidev, ha->ioctl_len, ha->ioctl_data,
- ha->ioctl_busaddr);
+ dma_free_coherent(&ha->pcidev->dev, ha->ioctl_len,
+ ha->ioctl_data, ha->ioctl_busaddr);
/* use the new memory */
ha->ioctl_data = (char *) bigger_buf;
ha->ioctl_len = length;
@@ -1678,9 +1679,8 @@ ips_flash_copperhead(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb)
} else if (!ha->flash_data) {
datasize = pt->CoppCP.cmd.flashfw.total_packets *
pt->CoppCP.cmd.flashfw.count;
- ha->flash_data = pci_alloc_consistent(ha->pcidev,
- datasize,
- &ha->flash_busaddr);
+ ha->flash_data = dma_alloc_coherent(&ha->pcidev->dev,
+ datasize, &ha->flash_busaddr, GFP_KERNEL);
if (!ha->flash_data){
printk(KERN_WARNING "Unable to allocate a flash buffer\n");
return IPS_FAILURE;
@@ -1858,7 +1858,7 @@ ips_flash_firmware(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb)
scb->data_len = ha->flash_datasize;
scb->data_busaddr =
- pci_map_single(ha->pcidev, ha->flash_data, scb->data_len,
+ dma_map_single(&ha->pcidev->dev, ha->flash_data, scb->data_len,
IPS_DMA_DIR(scb));
scb->flags |= IPS_SCB_MAP_SINGLE;
scb->cmd.flashfw.command_id = IPS_COMMAND_ID(ha, scb);
@@ -1880,8 +1880,8 @@ ips_free_flash_copperhead(ips_ha_t * ha)
if (ha->flash_data == ips_FlashData)
test_and_clear_bit(0, &ips_FlashDataInUse);
else if (ha->flash_data)
- pci_free_consistent(ha->pcidev, ha->flash_len, ha->flash_data,
- ha->flash_busaddr);
+ dma_free_coherent(&ha->pcidev->dev, ha->flash_len,
+ ha->flash_data, ha->flash_busaddr);
ha->flash_data = NULL;
}
@@ -3485,6 +3485,7 @@ ips_send_cmd(ips_ha_t * ha, ips_scb_t * scb)
case START_STOP:
scb->scsi_cmd->result = DID_OK << 16;
+ break;
case TEST_UNIT_READY:
case INQUIRY:
@@ -4212,7 +4213,7 @@ ips_free(ips_ha_t * ha)
if (ha) {
if (ha->enq) {
- pci_free_consistent(ha->pcidev, sizeof(IPS_ENQ),
+ dma_free_coherent(&ha->pcidev->dev, sizeof(IPS_ENQ),
ha->enq, ha->enq_busaddr);
ha->enq = NULL;
}
@@ -4221,7 +4222,7 @@ ips_free(ips_ha_t * ha)
ha->conf = NULL;
if (ha->adapt) {
- pci_free_consistent(ha->pcidev,
+ dma_free_coherent(&ha->pcidev->dev,
sizeof (IPS_ADAPTER) +
sizeof (IPS_IO_CMD), ha->adapt,
ha->adapt->hw_status_start);
@@ -4229,7 +4230,7 @@ ips_free(ips_ha_t * ha)
}
if (ha->logical_drive_info) {
- pci_free_consistent(ha->pcidev,
+ dma_free_coherent(&ha->pcidev->dev,
sizeof (IPS_LD_INFO),
ha->logical_drive_info,
ha->logical_drive_info_dma_addr);
@@ -4243,7 +4244,7 @@ ips_free(ips_ha_t * ha)
ha->subsys = NULL;
if (ha->ioctl_data) {
- pci_free_consistent(ha->pcidev, ha->ioctl_len,
+ dma_free_coherent(&ha->pcidev->dev, ha->ioctl_len,
ha->ioctl_data, ha->ioctl_busaddr);
ha->ioctl_data = NULL;
ha->ioctl_datasize = 0;
@@ -4276,11 +4277,11 @@ static int
ips_deallocatescbs(ips_ha_t * ha, int cmds)
{
if (ha->scbs) {
- pci_free_consistent(ha->pcidev,
+ dma_free_coherent(&ha->pcidev->dev,
IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * cmds,
ha->scbs->sg_list.list,
ha->scbs->sg_busaddr);
- pci_free_consistent(ha->pcidev, sizeof (ips_scb_t) * cmds,
+ dma_free_coherent(&ha->pcidev->dev, sizeof (ips_scb_t) * cmds,
ha->scbs, ha->scbs->scb_busaddr);
ha->scbs = NULL;
} /* end if */
@@ -4307,17 +4308,16 @@ ips_allocatescbs(ips_ha_t * ha)
METHOD_TRACE("ips_allocatescbs", 1);
/* Allocate memory for the SCBs */
- ha->scbs =
- pci_alloc_consistent(ha->pcidev, ha->max_cmds * sizeof (ips_scb_t),
- &command_dma);
+ ha->scbs = dma_alloc_coherent(&ha->pcidev->dev,
+ ha->max_cmds * sizeof (ips_scb_t),
+ &command_dma, GFP_KERNEL);
if (ha->scbs == NULL)
return 0;
- ips_sg.list =
- pci_alloc_consistent(ha->pcidev,
- IPS_SGLIST_SIZE(ha) * IPS_MAX_SG *
- ha->max_cmds, &sg_dma);
+ ips_sg.list = dma_alloc_coherent(&ha->pcidev->dev,
+ IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * ha->max_cmds,
+ &sg_dma, GFP_KERNEL);
if (ips_sg.list == NULL) {
- pci_free_consistent(ha->pcidev,
+ dma_free_coherent(&ha->pcidev->dev,
ha->max_cmds * sizeof (ips_scb_t), ha->scbs,
command_dma);
return 0;
@@ -4446,8 +4446,8 @@ ips_freescb(ips_ha_t * ha, ips_scb_t * scb)
if (scb->flags & IPS_SCB_MAP_SG)
scsi_dma_unmap(scb->scsi_cmd);
else if (scb->flags & IPS_SCB_MAP_SINGLE)
- pci_unmap_single(ha->pcidev, scb->data_busaddr, scb->data_len,
- IPS_DMA_DIR(scb));
+ dma_unmap_single(&ha->pcidev->dev, scb->data_busaddr,
+ scb->data_len, IPS_DMA_DIR(scb));
/* check to make sure this is not our "special" scb */
if (IPS_COMMAND_ID(ha, scb) < (ha->max_cmds - 1)) {
@@ -4559,7 +4559,8 @@ ips_flush_and_reset(ips_ha_t *ha)
dma_addr_t command_dma;
/* Create a usuable SCB */
- scb = pci_alloc_consistent(ha->pcidev, sizeof(ips_scb_t), &command_dma);
+ scb = dma_alloc_coherent(&ha->pcidev->dev, sizeof(ips_scb_t),
+ &command_dma, GFP_KERNEL);
if (scb) {
memset(scb, 0, sizeof(ips_scb_t));
ips_init_scb(ha, scb);
@@ -4594,7 +4595,7 @@ ips_flush_and_reset(ips_ha_t *ha)
/* Now RESET and INIT the adapter */
(*ha->func.reset) (ha);
- pci_free_consistent(ha->pcidev, sizeof(ips_scb_t), scb, command_dma);
+ dma_free_coherent(&ha->pcidev->dev, sizeof(ips_scb_t), scb, command_dma);
return;
}
@@ -6926,29 +6927,30 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
* are guaranteed to be < 4G.
*/
if (IPS_ENABLE_DMA64 && IPS_HAS_ENH_SGLIST(ha) &&
- !pci_set_dma_mask(ha->pcidev, DMA_BIT_MASK(64))) {
+ !dma_set_mask(&ha->pcidev->dev, DMA_BIT_MASK(64))) {
(ha)->flags |= IPS_HA_ENH_SG;
} else {
- if (pci_set_dma_mask(ha->pcidev, DMA_BIT_MASK(32)) != 0) {
+ if (dma_set_mask(&ha->pcidev->dev, DMA_BIT_MASK(32)) != 0) {
printk(KERN_WARNING "Unable to set DMA Mask\n");
return ips_abort_init(ha, index);
}
}
if(ips_cd_boot && !ips_FlashData){
- ips_FlashData = pci_alloc_consistent(pci_dev, PAGE_SIZE << 7,
- &ips_flashbusaddr);
+ ips_FlashData = dma_alloc_coherent(&pci_dev->dev,
+ PAGE_SIZE << 7, &ips_flashbusaddr, GFP_KERNEL);
}
- ha->enq = pci_alloc_consistent(pci_dev, sizeof (IPS_ENQ),
- &ha->enq_busaddr);
+ ha->enq = dma_alloc_coherent(&pci_dev->dev, sizeof (IPS_ENQ),
+ &ha->enq_busaddr, GFP_KERNEL);
if (!ha->enq) {
IPS_PRINTK(KERN_WARNING, pci_dev,
"Unable to allocate host inquiry structure\n");
return ips_abort_init(ha, index);
}
- ha->adapt = pci_alloc_consistent(pci_dev, sizeof (IPS_ADAPTER) +
- sizeof (IPS_IO_CMD), &dma_address);
+ ha->adapt = dma_alloc_coherent(&pci_dev->dev,
+ sizeof (IPS_ADAPTER) + sizeof (IPS_IO_CMD),
+ &dma_address, GFP_KERNEL);
if (!ha->adapt) {
IPS_PRINTK(KERN_WARNING, pci_dev,
"Unable to allocate host adapt & dummy structures\n");
@@ -6959,7 +6961,8 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
- ha->logical_drive_info = pci_alloc_consistent(pci_dev, sizeof (IPS_LD_INFO), &dma_address);
+ ha->logical_drive_info = dma_alloc_coherent(&pci_dev->dev,
+ sizeof (IPS_LD_INFO), &dma_address, GFP_KERNEL);
if (!ha->logical_drive_info) {
IPS_PRINTK(KERN_WARNING, pci_dev,
"Unable to allocate logical drive info structure\n");
@@ -6997,8 +7000,8 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
if (ips_ioctlsize < PAGE_SIZE)
ips_ioctlsize = PAGE_SIZE;
- ha->ioctl_data = pci_alloc_consistent(pci_dev, ips_ioctlsize,
- &ha->ioctl_busaddr);
+ ha->ioctl_data = dma_alloc_coherent(&pci_dev->dev, ips_ioctlsize,
+ &ha->ioctl_busaddr, GFP_KERNEL);
ha->ioctl_len = ips_ioctlsize;
if (!ha->ioctl_data) {
IPS_PRINTK(KERN_WARNING, pci_dev,
diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c
index 1ee3868ade07..7b5deae68d33 100644
--- a/drivers/scsi/isci/host.c
+++ b/drivers/scsi/isci/host.c
@@ -2717,9 +2717,9 @@ enum sci_status sci_controller_continue_io(struct isci_request *ireq)
* the task management request.
* @task_request: the handle to the task request object to start.
*/
-enum sci_task_status sci_controller_start_task(struct isci_host *ihost,
- struct isci_remote_device *idev,
- struct isci_request *ireq)
+enum sci_status sci_controller_start_task(struct isci_host *ihost,
+ struct isci_remote_device *idev,
+ struct isci_request *ireq)
{
enum sci_status status;
@@ -2728,7 +2728,7 @@ enum sci_task_status sci_controller_start_task(struct isci_host *ihost,
"%s: SCIC Controller starting task from invalid "
"state\n",
__func__);
- return SCI_TASK_FAILURE_INVALID_STATE;
+ return SCI_FAILURE_INVALID_STATE;
}
status = sci_remote_device_start_task(ihost, idev, ireq);
diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h
index b3539928073c..6bc3f022630a 100644
--- a/drivers/scsi/isci/host.h
+++ b/drivers/scsi/isci/host.h
@@ -489,7 +489,7 @@ enum sci_status sci_controller_start_io(
struct isci_remote_device *idev,
struct isci_request *ireq);
-enum sci_task_status sci_controller_start_task(
+enum sci_status sci_controller_start_task(
struct isci_host *ihost,
struct isci_remote_device *idev,
struct isci_request *ireq);
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index ed197bc8e801..2f151708b59a 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -1626,9 +1626,9 @@ static enum sci_status atapi_d2h_reg_frame_handler(struct isci_request *ireq,
if (status == SCI_SUCCESS) {
if (ireq->stp.rsp.status & ATA_ERR)
- status = SCI_IO_FAILURE_RESPONSE_VALID;
+ status = SCI_FAILURE_IO_RESPONSE_VALID;
} else {
- status = SCI_IO_FAILURE_RESPONSE_VALID;
+ status = SCI_FAILURE_IO_RESPONSE_VALID;
}
if (status != SCI_SUCCESS) {
diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c
index 6dcaed0c1fc8..fb6eba331ac6 100644
--- a/drivers/scsi/isci/task.c
+++ b/drivers/scsi/isci/task.c
@@ -258,7 +258,7 @@ static int isci_task_execute_tmf(struct isci_host *ihost,
struct isci_tmf *tmf, unsigned long timeout_ms)
{
DECLARE_COMPLETION_ONSTACK(completion);
- enum sci_task_status status = SCI_TASK_FAILURE;
+ enum sci_status status = SCI_FAILURE;
struct isci_request *ireq;
int ret = TMF_RESP_FUNC_FAILED;
unsigned long flags;
@@ -301,7 +301,7 @@ static int isci_task_execute_tmf(struct isci_host *ihost,
/* start the TMF io. */
status = sci_controller_start_task(ihost, idev, ireq);
- if (status != SCI_TASK_SUCCESS) {
+ if (status != SCI_SUCCESS) {
dev_dbg(&ihost->pdev->dev,
"%s: start_io failed - status = 0x%x, request = %p\n",
__func__,
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index b025a0b74341..23354f206533 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -800,7 +800,8 @@ static int iscsi_sw_tcp_host_get_param(struct Scsi_Host *shost,
return rc;
return iscsi_conn_get_addr_param((struct sockaddr_storage *)
- &addr, param, buf);
+ &addr,
+ (enum iscsi_param)param, buf);
default:
return iscsi_host_get_param(shost, param, buf);
}
diff --git a/drivers/scsi/jazz_esp.c b/drivers/scsi/jazz_esp.c
index 6eb5ff3e2e61..1ad28262b00a 100644
--- a/drivers/scsi/jazz_esp.c
+++ b/drivers/scsi/jazz_esp.c
@@ -38,30 +38,6 @@ static u8 jazz_esp_read8(struct esp *esp, unsigned long reg)
return *(volatile u8 *)(esp->regs + reg);
}
-static dma_addr_t jazz_esp_map_single(struct esp *esp, void *buf,
- size_t sz, int dir)
-{
- return dma_map_single(esp->dev, buf, sz, dir);
-}
-
-static int jazz_esp_map_sg(struct esp *esp, struct scatterlist *sg,
- int num_sg, int dir)
-{
- return dma_map_sg(esp->dev, sg, num_sg, dir);
-}
-
-static void jazz_esp_unmap_single(struct esp *esp, dma_addr_t addr,
- size_t sz, int dir)
-{
- dma_unmap_single(esp->dev, addr, sz, dir);
-}
-
-static void jazz_esp_unmap_sg(struct esp *esp, struct scatterlist *sg,
- int num_sg, int dir)
-{
- dma_unmap_sg(esp->dev, sg, num_sg, dir);
-}
-
static int jazz_esp_irq_pending(struct esp *esp)
{
if (jazz_esp_read8(esp, ESP_STATUS) & ESP_STAT_INTR)
@@ -117,10 +93,6 @@ static int jazz_esp_dma_error(struct esp *esp)
static const struct esp_driver_ops jazz_esp_ops = {
.esp_write8 = jazz_esp_write8,
.esp_read8 = jazz_esp_read8,
- .map_single = jazz_esp_map_single,
- .map_sg = jazz_esp_map_sg,
- .unmap_single = jazz_esp_unmap_single,
- .unmap_sg = jazz_esp_unmap_sg,
.irq_pending = jazz_esp_irq_pending,
.reset_dma = jazz_esp_reset_dma,
.dma_drain = jazz_esp_dma_drain,
@@ -182,7 +154,7 @@ static int esp_jazz_probe(struct platform_device *dev)
dev_set_drvdata(&dev->dev, esp);
- err = scsi_esp_register(esp, &dev->dev);
+ err = scsi_esp_register(esp);
if (err)
goto fail_free_irq;
diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c
index 4fae253d4f3d..b1bd283be51c 100644
--- a/drivers/scsi/libfc/fc_fcp.c
+++ b/drivers/scsi/libfc/fc_fcp.c
@@ -1872,7 +1872,6 @@ int fc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc_cmd)
struct fc_lport *lport = shost_priv(shost);
struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device));
struct fc_fcp_pkt *fsp;
- struct fc_rport_libfc_priv *rpriv;
int rval;
int rc = 0;
struct fc_stats *stats;
@@ -1894,8 +1893,6 @@ int fc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc_cmd)
goto out;
}
- rpriv = rport->dd_data;
-
if (!fc_fcp_lport_queue_ready(lport)) {
if (lport->qfull) {
if (fc_fcp_can_queue_ramp_down(lport))
@@ -2295,8 +2292,7 @@ int fc_setup_fcp(void)
void fc_destroy_fcp(void)
{
- if (scsi_pkt_cachep)
- kmem_cache_destroy(scsi_pkt_cachep);
+ kmem_cache_destroy(scsi_pkt_cachep);
}
/**
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c
index 372387a450df..1e1c0f1b9e69 100644
--- a/drivers/scsi/libfc/fc_rport.c
+++ b/drivers/scsi/libfc/fc_rport.c
@@ -1038,8 +1038,11 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp,
struct fc_els_ls_rjt *rjt;
rjt = fc_frame_payload_get(fp, sizeof(*rjt));
- FC_RPORT_DBG(rdata, "PLOGI ELS rejected, reason %x expl %x\n",
- rjt->er_reason, rjt->er_explan);
+ if (!rjt)
+ FC_RPORT_DBG(rdata, "PLOGI bad response\n");
+ else
+ FC_RPORT_DBG(rdata, "PLOGI ELS rejected, reason %x expl %x\n",
+ rjt->er_reason, rjt->er_explan);
fc_rport_error_retry(rdata, -FC_EX_ELS_RJT);
}
out:
@@ -1158,8 +1161,10 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,
op = fc_frame_payload_op(fp);
if (op == ELS_LS_ACC) {
pp = fc_frame_payload_get(fp, sizeof(*pp));
- if (!pp)
+ if (!pp) {
+ fc_rport_error_retry(rdata, -FC_EX_SEQ_ERR);
goto out;
+ }
resp_code = (pp->spp.spp_flags & FC_SPP_RESP_MASK);
FC_RPORT_DBG(rdata, "PRLI spp_flags = 0x%x spp_type 0x%x\n",
@@ -1172,8 +1177,10 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,
fc_rport_error_retry(rdata, -FC_EX_SEQ_ERR);
goto out;
}
- if (pp->prli.prli_spp_len < sizeof(pp->spp))
+ if (pp->prli.prli_spp_len < sizeof(pp->spp)) {
+ fc_rport_error_retry(rdata, -FC_EX_SEQ_ERR);
goto out;
+ }
fcp_parm = ntohl(pp->spp.spp_params);
if (fcp_parm & FCP_SPPF_RETRY)
@@ -1211,8 +1218,11 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,
} else {
rjt = fc_frame_payload_get(fp, sizeof(*rjt));
- FC_RPORT_DBG(rdata, "PRLI ELS rejected, reason %x expl %x\n",
- rjt->er_reason, rjt->er_explan);
+ if (!rjt)
+ FC_RPORT_DBG(rdata, "PRLI bad response\n");
+ else
+ FC_RPORT_DBG(rdata, "PRLI ELS rejected, reason %x expl %x\n",
+ rjt->er_reason, rjt->er_explan);
fc_rport_error_retry(rdata, FC_EX_ELS_RJT);
}
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index 64a958a99f6a..4f6cdf53e913 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -654,7 +654,7 @@ void sas_probe_sata(struct asd_sas_port *port)
/* if libata could not bring the link up, don't surface
* the device
*/
- if (ata_dev_disabled(sas_to_ata_dev(dev)))
+ if (!ata_dev_enabled(sas_to_ata_dev(dev)))
sas_fail_probe(dev, __func__, -ENODEV);
}
diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c
index 0148ae62a52a..dde433aa59c2 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -260,7 +260,7 @@ static void sas_suspend_devices(struct work_struct *work)
* phy_list is not being mutated
*/
list_for_each_entry(phy, &port->phy_list, port_phy_el) {
- if (si->dft->lldd_port_formed)
+ if (si->dft->lldd_port_deformed)
si->dft->lldd_port_deformed(phy);
phy->suspended = 1;
port->suspended = 1;
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index fadc99cb60df..0d1f72752ca2 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -48,17 +48,16 @@ static void smp_task_timedout(struct timer_list *t)
unsigned long flags;
spin_lock_irqsave(&task->task_state_lock, flags);
- if (!(task->task_state_flags & SAS_TASK_STATE_DONE))
+ if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
task->task_state_flags |= SAS_TASK_STATE_ABORTED;
+ complete(&task->slow_task->completion);
+ }
spin_unlock_irqrestore(&task->task_state_lock, flags);
-
- complete(&task->slow_task->completion);
}
static void smp_task_done(struct sas_task *task)
{
- if (!del_timer(&task->slow_task->timer))
- return;
+ del_timer(&task->slow_task->timer);
complete(&task->slow_task->completion);
}
@@ -2054,14 +2053,11 @@ static int sas_rediscover_dev(struct domain_device *dev, int phy_id, bool last)
return res;
}
- /* delete the old link */
- if (SAS_ADDR(phy->attached_sas_addr) &&
- SAS_ADDR(sas_addr) != SAS_ADDR(phy->attached_sas_addr)) {
- SAS_DPRINTK("ex %016llx phy 0x%x replace %016llx\n",
- SAS_ADDR(dev->sas_addr), phy_id,
- SAS_ADDR(phy->attached_sas_addr));
- sas_unregister_devs_sas_addr(dev, phy_id, last);
- }
+ /* we always have to delete the old device when we went here */
+ SAS_DPRINTK("ex %016llx phy 0x%x replace %016llx\n",
+ SAS_ADDR(dev->sas_addr), phy_id,
+ SAS_ADDR(phy->attached_sas_addr));
+ sas_unregister_devs_sas_addr(dev, phy_id, last);
return sas_discover_new(dev, phy_id);
}
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index 43732e8d1347..c1eb2b00ca7f 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -52,7 +52,7 @@ struct lpfc_sli2_slim;
downloads using bsg */
#define LPFC_MIN_SG_SLI4_BUF_SZ 0x800 /* based on LPFC_DEFAULT_SG_SEG_CNT */
-#define LPFC_MAX_SG_SLI4_SEG_CNT_DIF 128 /* sg element count per scsi cmnd */
+#define LPFC_MAX_BG_SLI4_SEG_CNT_DIF 128 /* sg element count for BlockGuard */
#define LPFC_MAX_SG_SEG_CNT_DIF 512 /* sg element count per scsi cmnd */
#define LPFC_MAX_SG_SEG_CNT 4096 /* sg element count per scsi cmnd */
#define LPFC_MIN_SG_SEG_CNT 32 /* sg element count per scsi cmnd */
@@ -583,6 +583,25 @@ struct lpfc_mbox_ext_buf_ctx {
struct list_head ext_dmabuf_list;
};
+struct lpfc_ras_fwlog {
+ uint8_t *fwlog_buff;
+ uint32_t fw_buffcount; /* Buffer size posted to FW */
+#define LPFC_RAS_BUFF_ENTERIES 16 /* Each entry can hold max of 64k */
+#define LPFC_RAS_MAX_ENTRY_SIZE (64 * 1024)
+#define LPFC_RAS_MIN_BUFF_POST_SIZE (256 * 1024)
+#define LPFC_RAS_MAX_BUFF_POST_SIZE (1024 * 1024)
+ uint32_t fw_loglevel; /* Log level set */
+ struct lpfc_dmabuf lwpd;
+ struct list_head fwlog_buff_list;
+
+ /* RAS support status on adapter */
+ bool ras_hwsupport; /* RAS Support available on HW or not */
+ bool ras_enabled; /* Ras Enabled for the function */
+#define LPFC_RAS_DISABLE_LOGGING 0x00
+#define LPFC_RAS_ENABLE_LOGGING 0x01
+ bool ras_active; /* RAS logging running state */
+};
+
struct lpfc_hba {
/* SCSI interface function jump table entries */
int (*lpfc_new_scsi_buf)
@@ -790,6 +809,7 @@ struct lpfc_hba {
uint32_t cfg_total_seg_cnt;
uint32_t cfg_sg_seg_cnt;
uint32_t cfg_nvme_seg_cnt;
+ uint32_t cfg_scsi_seg_cnt;
uint32_t cfg_sg_dma_buf_size;
uint64_t cfg_soft_wwnn;
uint64_t cfg_soft_wwpn;
@@ -833,6 +853,9 @@ struct lpfc_hba {
#define LPFC_FDMI_SUPPORT 1 /* FDMI supported? */
uint32_t cfg_enable_SmartSAN;
uint32_t cfg_enable_mds_diags;
+ uint32_t cfg_ras_fwlog_level;
+ uint32_t cfg_ras_fwlog_buffsize;
+ uint32_t cfg_ras_fwlog_func;
uint32_t cfg_enable_fc4_type;
uint32_t cfg_enable_bbcr; /* Enable BB Credit Recovery */
uint32_t cfg_enable_dpp; /* Enable Direct Packet Push */
@@ -963,6 +986,7 @@ struct lpfc_hba {
uint32_t intr_mode;
#define LPFC_INTR_ERROR 0xFFFFFFFF
struct list_head port_list;
+ spinlock_t port_list_lock; /* lock for port_list mutations */
struct lpfc_vport *pport; /* physical lpfc_vport pointer */
uint16_t max_vpi; /* Maximum virtual nports */
#define LPFC_MAX_VPI 0xFFFF /* Max number of VPI supported */
@@ -1092,6 +1116,9 @@ struct lpfc_hba {
struct unsol_rcv_ct_ctx ct_ctx[LPFC_CT_CTX_MAX];
uint32_t ctx_idx;
+ /* RAS Support */
+ struct lpfc_ras_fwlog ras_fwlog;
+
uint8_t menlo_flag; /* menlo generic flags */
#define HBA_MENLO_SUPPORT 0x1 /* HBA supports menlo commands */
uint32_t iocb_cnt;
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index 1a6ed9b0a249..dda7f450b96d 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -5358,15 +5358,74 @@ LPFC_ATTR(delay_discovery, 0, 0, 1,
/*
* lpfc_sg_seg_cnt - Initial Maximum DMA Segment Count
- * This value can be set to values between 64 and 4096. The default value is
- * 64, but may be increased to allow for larger Max I/O sizes. The scsi layer
- * will be allowed to request I/Os of sizes up to (MAX_SEG_COUNT * SEG_SIZE).
+ * This value can be set to values between 64 and 4096. The default value
+ * is 64, but may be increased to allow for larger Max I/O sizes. The scsi
+ * and nvme layers will allow I/O sizes up to (MAX_SEG_COUNT * SEG_SIZE).
* Because of the additional overhead involved in setting up T10-DIF,
* this parameter will be limited to 128 if BlockGuard is enabled under SLI4
* and will be limited to 512 if BlockGuard is enabled under SLI3.
*/
-LPFC_ATTR_R(sg_seg_cnt, LPFC_DEFAULT_SG_SEG_CNT, LPFC_MIN_SG_SEG_CNT,
- LPFC_MAX_SG_SEG_CNT, "Max Scatter Gather Segment Count");
+static uint lpfc_sg_seg_cnt = LPFC_DEFAULT_SG_SEG_CNT;
+module_param(lpfc_sg_seg_cnt, uint, 0444);
+MODULE_PARM_DESC(lpfc_sg_seg_cnt, "Max Scatter Gather Segment Count");
+
+/**
+ * lpfc_sg_seg_cnt_show - Display the scatter/gather list sizes
+ * configured for the adapter
+ * @dev: class converted to a Scsi_host structure.
+ * @attr: device attribute, not used.
+ * @buf: on return contains a string with the list sizes
+ *
+ * Returns: size of formatted string.
+ **/
+static ssize_t
+lpfc_sg_seg_cnt_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ int len;
+
+ len = snprintf(buf, PAGE_SIZE, "SGL sz: %d total SGEs: %d\n",
+ phba->cfg_sg_dma_buf_size, phba->cfg_total_seg_cnt);
+
+ len += snprintf(buf + len, PAGE_SIZE, "Cfg: %d SCSI: %d NVME: %d\n",
+ phba->cfg_sg_seg_cnt, phba->cfg_scsi_seg_cnt,
+ phba->cfg_nvme_seg_cnt);
+ return len;
+}
+
+static DEVICE_ATTR_RO(lpfc_sg_seg_cnt);
+
+/**
+ * lpfc_sg_seg_cnt_init - Set the hba sg_seg_cnt initial value
+ * @phba: lpfc_hba pointer.
+ * @val: contains the initial value
+ *
+ * Description:
+ * Validates the initial value is within range and assigns it to the
+ * adapter. If not in range, an error message is posted and the
+ * default value is assigned.
+ *
+ * Returns:
+ * zero if value is in range and is set
+ * -EINVAL if value was out of range
+ **/
+static int
+lpfc_sg_seg_cnt_init(struct lpfc_hba *phba, int val)
+{
+ if (val >= LPFC_MIN_SG_SEG_CNT && val <= LPFC_MAX_SG_SEG_CNT) {
+ phba->cfg_sg_seg_cnt = val;
+ return 0;
+ }
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "0409 "LPFC_DRIVER_NAME"_sg_seg_cnt attribute cannot "
+ "be set to %d, allowed range is [%d, %d]\n",
+ val, LPFC_MIN_SG_SEG_CNT, LPFC_MAX_SG_SEG_CNT);
+ phba->cfg_sg_seg_cnt = LPFC_DEFAULT_SG_SEG_CNT;
+ return -EINVAL;
+}
/*
* lpfc_enable_mds_diags: Enable MDS Diagnostics
@@ -5377,6 +5436,31 @@ LPFC_ATTR_R(sg_seg_cnt, LPFC_DEFAULT_SG_SEG_CNT, LPFC_MIN_SG_SEG_CNT,
LPFC_ATTR_R(enable_mds_diags, 0, 0, 1, "Enable MDS Diagnostics");
/*
+ * lpfc_ras_fwlog_buffsize: Firmware logging host buffer size
+ * 0 = Disable firmware logging (default)
+ * [1-4] = Multiple of 1/4th Mb of host memory for FW logging
+ * Value range [0..4]. Default value is 0
+ */
+LPFC_ATTR_RW(ras_fwlog_buffsize, 0, 0, 4, "Host memory for FW logging");
+
+/*
+ * lpfc_ras_fwlog_level: Firmware logging verbosity level
+ * Valid only if firmware logging is enabled
+ * 0(Least Verbosity) 4 (most verbosity)
+ * Value range is [0..4]. Default value is 0
+ */
+LPFC_ATTR_RW(ras_fwlog_level, 0, 0, 4, "Firmware Logging Level");
+
+/*
+ * lpfc_ras_fwlog_func: Firmware logging enabled on function number
+ * Default function which has RAS support : 0
+ * Value Range is [0..7].
+ * FW logging is a global action and enablement is via a specific
+ * port.
+ */
+LPFC_ATTR_RW(ras_fwlog_func, 0, 0, 7, "Firmware Logging Enabled on Function");
+
+/*
* lpfc_enable_bbcr: Enable BB Credit Recovery
* 0 = BB Credit Recovery disabled
* 1 = BB Credit Recovery enabled (default)
@@ -5501,6 +5585,9 @@ struct device_attribute *lpfc_hba_attrs[] = {
&dev_attr_protocol,
&dev_attr_lpfc_xlane_supported,
&dev_attr_lpfc_enable_mds_diags,
+ &dev_attr_lpfc_ras_fwlog_buffsize,
+ &dev_attr_lpfc_ras_fwlog_level,
+ &dev_attr_lpfc_ras_fwlog_func,
&dev_attr_lpfc_enable_bbcr,
&dev_attr_lpfc_enable_dpp,
NULL,
@@ -6587,6 +6674,20 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
lpfc_sli_mode_init(phba, lpfc_sli_mode);
phba->cfg_enable_dss = 1;
lpfc_enable_mds_diags_init(phba, lpfc_enable_mds_diags);
+ lpfc_ras_fwlog_buffsize_init(phba, lpfc_ras_fwlog_buffsize);
+ lpfc_ras_fwlog_level_init(phba, lpfc_ras_fwlog_level);
+ lpfc_ras_fwlog_func_init(phba, lpfc_ras_fwlog_func);
+
+
+ /* If the NVME FC4 type is enabled, scale the sg_seg_cnt to
+ * accommodate 512K and 1M IOs in a single nvme buf and supply
+ * enough NVME LS iocb buffers for larger connectivity counts.
+ */
+ if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) {
+ phba->cfg_sg_seg_cnt = LPFC_MAX_NVME_SEG_CNT;
+ phba->cfg_iocb_cnt = 5;
+ }
+
return;
}
diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c
index 90745feca808..7bd7ae86bed5 100644
--- a/drivers/scsi/lpfc/lpfc_bsg.c
+++ b/drivers/scsi/lpfc/lpfc_bsg.c
@@ -27,6 +27,7 @@
#include <linux/delay.h>
#include <linux/list.h>
#include <linux/bsg-lib.h>
+#include <linux/vmalloc.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
@@ -2843,9 +2844,6 @@ diag_cmd_data_alloc(struct lpfc_hba *phba,
if (nocopydata) {
bpl->tus.f.bdeFlags = 0;
- pci_dma_sync_single_for_device(phba->pcidev,
- dmp->dma.phys, LPFC_BPL_SIZE, PCI_DMA_TODEVICE);
-
} else {
memset((uint8_t *)dmp->dma.virt, 0, cnt);
bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I;
@@ -5309,6 +5307,330 @@ job_error:
}
/**
+ * lpfc_check_fwlog_support: Check FW log support on the adapter
+ * @phba: Pointer to HBA context object.
+ *
+ * Check if FW Logging support by the adapter
+ **/
+int
+lpfc_check_fwlog_support(struct lpfc_hba *phba)
+{
+ struct lpfc_ras_fwlog *ras_fwlog = NULL;
+
+ ras_fwlog = &phba->ras_fwlog;
+
+ if (ras_fwlog->ras_hwsupport == false)
+ return -EACCES;
+ else if (ras_fwlog->ras_enabled == false)
+ return -EPERM;
+ else
+ return 0;
+}
+
+/**
+ * lpfc_bsg_get_ras_config: Get RAS configuration settings
+ * @job: fc_bsg_job to handle
+ *
+ * Get RAS configuration values set.
+ **/
+static int
+lpfc_bsg_get_ras_config(struct bsg_job *job)
+{
+ struct Scsi_Host *shost = fc_bsg_to_shost(job);
+ struct lpfc_vport *vport = shost_priv(shost);
+ struct fc_bsg_reply *bsg_reply = job->reply;
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_bsg_get_ras_config_reply *ras_reply;
+ struct lpfc_ras_fwlog *ras_fwlog = &phba->ras_fwlog;
+ int rc = 0;
+
+ if (job->request_len <
+ sizeof(struct fc_bsg_request) +
+ sizeof(struct lpfc_bsg_ras_req)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
+ "6181 Received RAS_LOG request "
+ "below minimum size\n");
+ rc = -EINVAL;
+ goto ras_job_error;
+ }
+
+ /* Check FW log status */
+ rc = lpfc_check_fwlog_support(phba);
+ if (rc == -EACCES || rc == -EPERM)
+ goto ras_job_error;
+
+ ras_reply = (struct lpfc_bsg_get_ras_config_reply *)
+ bsg_reply->reply_data.vendor_reply.vendor_rsp;
+
+ /* Current logging state */
+ if (ras_fwlog->ras_active == true)
+ ras_reply->state = LPFC_RASLOG_STATE_RUNNING;
+ else
+ ras_reply->state = LPFC_RASLOG_STATE_STOPPED;
+
+ ras_reply->log_level = phba->ras_fwlog.fw_loglevel;
+ ras_reply->log_buff_sz = phba->cfg_ras_fwlog_buffsize;
+
+ras_job_error:
+ /* make error code available to userspace */
+ bsg_reply->result = rc;
+
+ /* complete the job back to userspace */
+ bsg_job_done(job, bsg_reply->result, bsg_reply->reply_payload_rcv_len);
+ return rc;
+}
+
+/**
+ * lpfc_ras_stop_fwlog: Disable FW logging by the adapter
+ * @phba: Pointer to HBA context object.
+ *
+ * Disable FW logging into host memory on the adapter. To
+ * be done before reading logs from the host memory.
+ **/
+static void
+lpfc_ras_stop_fwlog(struct lpfc_hba *phba)
+{
+ struct lpfc_ras_fwlog *ras_fwlog = &phba->ras_fwlog;
+
+ ras_fwlog->ras_active = false;
+
+ /* Disable FW logging to host memory */
+ writel(LPFC_CTL_PDEV_CTL_DDL_RAS,
+ phba->sli4_hba.conf_regs_memmap_p + LPFC_CTL_PDEV_CTL_OFFSET);
+}
+
+/**
+ * lpfc_bsg_set_ras_config: Set FW logging parameters
+ * @job: fc_bsg_job to handle
+ *
+ * Set log-level parameters for FW-logging in host memory
+ **/
+static int
+lpfc_bsg_set_ras_config(struct bsg_job *job)
+{
+ struct Scsi_Host *shost = fc_bsg_to_shost(job);
+ struct lpfc_vport *vport = shost_priv(shost);
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_bsg_set_ras_config_req *ras_req;
+ struct fc_bsg_request *bsg_request = job->request;
+ struct lpfc_ras_fwlog *ras_fwlog = &phba->ras_fwlog;
+ struct fc_bsg_reply *bsg_reply = job->reply;
+ uint8_t action = 0, log_level = 0;
+ int rc = 0;
+
+ if (job->request_len <
+ sizeof(struct fc_bsg_request) +
+ sizeof(struct lpfc_bsg_set_ras_config_req)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
+ "6182 Received RAS_LOG request "
+ "below minimum size\n");
+ rc = -EINVAL;
+ goto ras_job_error;
+ }
+
+ /* Check FW log status */
+ rc = lpfc_check_fwlog_support(phba);
+ if (rc == -EACCES || rc == -EPERM)
+ goto ras_job_error;
+
+ ras_req = (struct lpfc_bsg_set_ras_config_req *)
+ bsg_request->rqst_data.h_vendor.vendor_cmd;
+ action = ras_req->action;
+ log_level = ras_req->log_level;
+
+ if (action == LPFC_RASACTION_STOP_LOGGING) {
+ /* Check if already disabled */
+ if (ras_fwlog->ras_active == false) {
+ rc = -ESRCH;
+ goto ras_job_error;
+ }
+
+ /* Disable logging */
+ lpfc_ras_stop_fwlog(phba);
+ } else {
+ /*action = LPFC_RASACTION_START_LOGGING*/
+ if (ras_fwlog->ras_active == true) {
+ rc = -EINPROGRESS;
+ goto ras_job_error;
+ }
+
+ /* Enable logging */
+ rc = lpfc_sli4_ras_fwlog_init(phba, log_level,
+ LPFC_RAS_ENABLE_LOGGING);
+ if (rc)
+ rc = -EINVAL;
+ }
+ras_job_error:
+ /* make error code available to userspace */
+ bsg_reply->result = rc;
+
+ /* complete the job back to userspace */
+ bsg_job_done(job, bsg_reply->result,
+ bsg_reply->reply_payload_rcv_len);
+
+ return rc;
+}
+
+/**
+ * lpfc_bsg_get_ras_lwpd: Get log write position data
+ * @job: fc_bsg_job to handle
+ *
+ * Get Offset/Wrap count of the log message written
+ * in host memory
+ **/
+static int
+lpfc_bsg_get_ras_lwpd(struct bsg_job *job)
+{
+ struct Scsi_Host *shost = fc_bsg_to_shost(job);
+ struct lpfc_vport *vport = shost_priv(shost);
+ struct lpfc_bsg_get_ras_lwpd *ras_reply;
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_ras_fwlog *ras_fwlog = &phba->ras_fwlog;
+ struct fc_bsg_reply *bsg_reply = job->reply;
+ uint32_t lwpd_offset = 0;
+ uint64_t wrap_value = 0;
+ int rc = 0;
+
+ rc = lpfc_check_fwlog_support(phba);
+ if (rc == -EACCES || rc == -EPERM)
+ goto ras_job_error;
+
+ if (job->request_len <
+ sizeof(struct fc_bsg_request) +
+ sizeof(struct lpfc_bsg_ras_req)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
+ "6183 Received RAS_LOG request "
+ "below minimum size\n");
+ rc = -EINVAL;
+ goto ras_job_error;
+ }
+
+ ras_reply = (struct lpfc_bsg_get_ras_lwpd *)
+ bsg_reply->reply_data.vendor_reply.vendor_rsp;
+
+ lwpd_offset = *((uint32_t *)ras_fwlog->lwpd.virt) & 0xffffffff;
+ ras_reply->offset = be32_to_cpu(lwpd_offset);
+
+ wrap_value = *((uint64_t *)ras_fwlog->lwpd.virt);
+ ras_reply->wrap_count = be32_to_cpu((wrap_value >> 32) & 0xffffffff);
+
+ras_job_error:
+ /* make error code available to userspace */
+ bsg_reply->result = rc;
+
+ /* complete the job back to userspace */
+ bsg_job_done(job, bsg_reply->result, bsg_reply->reply_payload_rcv_len);
+
+ return rc;
+}
+
+/**
+ * lpfc_bsg_get_ras_fwlog: Read FW log
+ * @job: fc_bsg_job to handle
+ *
+ * Copy the FW log into the passed buffer.
+ **/
+static int
+lpfc_bsg_get_ras_fwlog(struct bsg_job *job)
+{
+ struct Scsi_Host *shost = fc_bsg_to_shost(job);
+ struct lpfc_vport *vport = shost_priv(shost);
+ struct lpfc_hba *phba = vport->phba;
+ struct fc_bsg_request *bsg_request = job->request;
+ struct fc_bsg_reply *bsg_reply = job->reply;
+ struct lpfc_bsg_get_fwlog_req *ras_req;
+ uint32_t rd_offset, rd_index, offset, pending_wlen;
+ uint32_t boundary = 0, align_len = 0, write_len = 0;
+ void *dest, *src, *fwlog_buff;
+ struct lpfc_ras_fwlog *ras_fwlog = NULL;
+ struct lpfc_dmabuf *dmabuf, *next;
+ int rc = 0;
+
+ ras_fwlog = &phba->ras_fwlog;
+
+ rc = lpfc_check_fwlog_support(phba);
+ if (rc == -EACCES || rc == -EPERM)
+ goto ras_job_error;
+
+ /* Logging to be stopped before reading */
+ if (ras_fwlog->ras_active == true) {
+ rc = -EINPROGRESS;
+ goto ras_job_error;
+ }
+
+ if (job->request_len <
+ sizeof(struct fc_bsg_request) +
+ sizeof(struct lpfc_bsg_get_fwlog_req)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
+ "6184 Received RAS_LOG request "
+ "below minimum size\n");
+ rc = -EINVAL;
+ goto ras_job_error;
+ }
+
+ ras_req = (struct lpfc_bsg_get_fwlog_req *)
+ bsg_request->rqst_data.h_vendor.vendor_cmd;
+ rd_offset = ras_req->read_offset;
+
+ /* Allocate memory to read fw log*/
+ fwlog_buff = vmalloc(ras_req->read_size);
+ if (!fwlog_buff) {
+ rc = -ENOMEM;
+ goto ras_job_error;
+ }
+
+ rd_index = (rd_offset / LPFC_RAS_MAX_ENTRY_SIZE);
+ offset = (rd_offset % LPFC_RAS_MAX_ENTRY_SIZE);
+ pending_wlen = ras_req->read_size;
+ dest = fwlog_buff;
+
+ list_for_each_entry_safe(dmabuf, next,
+ &ras_fwlog->fwlog_buff_list, list) {
+
+ if (dmabuf->buffer_tag < rd_index)
+ continue;
+
+ /* Align read to buffer size */
+ if (offset) {
+ boundary = ((dmabuf->buffer_tag + 1) *
+ LPFC_RAS_MAX_ENTRY_SIZE);
+
+ align_len = (boundary - offset);
+ write_len = min_t(u32, align_len,
+ LPFC_RAS_MAX_ENTRY_SIZE);
+ } else {
+ write_len = min_t(u32, pending_wlen,
+ LPFC_RAS_MAX_ENTRY_SIZE);
+ align_len = 0;
+ boundary = 0;
+ }
+ src = dmabuf->virt + offset;
+ memcpy(dest, src, write_len);
+
+ pending_wlen -= write_len;
+ if (!pending_wlen)
+ break;
+
+ dest += write_len;
+ offset = (offset + write_len) % LPFC_RAS_MAX_ENTRY_SIZE;
+ }
+
+ bsg_reply->reply_payload_rcv_len =
+ sg_copy_from_buffer(job->reply_payload.sg_list,
+ job->reply_payload.sg_cnt,
+ fwlog_buff, ras_req->read_size);
+
+ vfree(fwlog_buff);
+
+ras_job_error:
+ bsg_reply->result = rc;
+ bsg_job_done(job, bsg_reply->result, bsg_reply->reply_payload_rcv_len);
+
+ return rc;
+}
+
+
+/**
* lpfc_bsg_hst_vendor - process a vendor-specific fc_bsg_job
* @job: fc_bsg_job to handle
**/
@@ -5355,6 +5677,18 @@ lpfc_bsg_hst_vendor(struct bsg_job *job)
case LPFC_BSG_VENDOR_FORCED_LINK_SPEED:
rc = lpfc_forced_link_speed(job);
break;
+ case LPFC_BSG_VENDOR_RAS_GET_LWPD:
+ rc = lpfc_bsg_get_ras_lwpd(job);
+ break;
+ case LPFC_BSG_VENDOR_RAS_GET_FWLOG:
+ rc = lpfc_bsg_get_ras_fwlog(job);
+ break;
+ case LPFC_BSG_VENDOR_RAS_GET_CONFIG:
+ rc = lpfc_bsg_get_ras_config(job);
+ break;
+ case LPFC_BSG_VENDOR_RAS_SET_CONFIG:
+ rc = lpfc_bsg_set_ras_config(job);
+ break;
default:
rc = -EINVAL;
bsg_reply->reply_payload_rcv_len = 0;
@@ -5368,7 +5702,7 @@ lpfc_bsg_hst_vendor(struct bsg_job *job)
/**
* lpfc_bsg_request - handle a bsg request from the FC transport
- * @job: fc_bsg_job to handle
+ * @job: bsg_job to handle
**/
int
lpfc_bsg_request(struct bsg_job *job)
@@ -5402,7 +5736,7 @@ lpfc_bsg_request(struct bsg_job *job)
/**
* lpfc_bsg_timeout - handle timeout of a bsg request from the FC transport
- * @job: fc_bsg_job that has timed out
+ * @job: bsg_job that has timed out
*
* This function just aborts the job's IOCB. The aborted IOCB will return to
* the waiting function which will handle passing the error back to userspace
diff --git a/drivers/scsi/lpfc/lpfc_bsg.h b/drivers/scsi/lpfc/lpfc_bsg.h
index 32347c87e3b4..820323f1139b 100644
--- a/drivers/scsi/lpfc/lpfc_bsg.h
+++ b/drivers/scsi/lpfc/lpfc_bsg.h
@@ -38,6 +38,10 @@
#define LPFC_BSG_VENDOR_DIAG_MODE_END 10
#define LPFC_BSG_VENDOR_LINK_DIAG_TEST 11
#define LPFC_BSG_VENDOR_FORCED_LINK_SPEED 14
+#define LPFC_BSG_VENDOR_RAS_GET_LWPD 16
+#define LPFC_BSG_VENDOR_RAS_GET_FWLOG 17
+#define LPFC_BSG_VENDOR_RAS_GET_CONFIG 18
+#define LPFC_BSG_VENDOR_RAS_SET_CONFIG 19
struct set_ct_event {
uint32_t command;
@@ -296,6 +300,38 @@ struct forced_link_speed_support_reply {
uint8_t supported;
};
+struct lpfc_bsg_ras_req {
+ uint32_t command;
+};
+
+struct lpfc_bsg_get_fwlog_req {
+ uint32_t command;
+ uint32_t read_size;
+ uint32_t read_offset;
+};
+
+struct lpfc_bsg_get_ras_lwpd {
+ uint32_t offset;
+ uint32_t wrap_count;
+};
+
+struct lpfc_bsg_set_ras_config_req {
+ uint32_t command;
+ uint8_t action;
+#define LPFC_RASACTION_STOP_LOGGING 0x00
+#define LPFC_RASACTION_START_LOGGING 0x01
+ uint8_t log_level;
+};
+
+struct lpfc_bsg_get_ras_config_reply {
+ uint8_t state;
+#define LPFC_RASLOG_STATE_STOPPED 0x00
+#define LPFC_RASLOG_STATE_RUNNING 0x01
+ uint8_t log_level;
+ uint32_t log_buff_sz;
+};
+
+
/* driver only */
#define SLI_CONFIG_NOT_HANDLED 0
#define SLI_CONFIG_HANDLED 1
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index bea24bc4410a..e01136507780 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -545,6 +545,13 @@ bool lpfc_find_next_oas_lun(struct lpfc_hba *, struct lpfc_name *,
int lpfc_sli4_dump_page_a0(struct lpfc_hba *phba, struct lpfcMboxq *mbox);
void lpfc_mbx_cmpl_rdp_page_a0(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb);
+/* RAS Interface */
+void lpfc_sli4_ras_init(struct lpfc_hba *phba);
+void lpfc_sli4_ras_setup(struct lpfc_hba *phba);
+int lpfc_sli4_ras_fwlog_init(struct lpfc_hba *phba, uint32_t fwlog_level,
+ uint32_t fwlog_enable);
+int lpfc_check_fwlog_support(struct lpfc_hba *phba);
+
/* NVME interfaces. */
void lpfc_nvme_unregister_port(struct lpfc_vport *vport,
struct lpfc_nodelist *ndlp);
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index 1cbdc892ff95..789ad1502534 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -445,14 +445,14 @@ lpfc_find_vport_by_did(struct lpfc_hba *phba, uint32_t did) {
struct lpfc_vport *vport_curr;
unsigned long flags;
- spin_lock_irqsave(&phba->hbalock, flags);
+ spin_lock_irqsave(&phba->port_list_lock, flags);
list_for_each_entry(vport_curr, &phba->port_list, listentry) {
if ((vport_curr->fc_myDID) && (vport_curr->fc_myDID == did)) {
- spin_unlock_irqrestore(&phba->hbalock, flags);
+ spin_unlock_irqrestore(&phba->port_list_lock, flags);
return vport_curr;
}
}
- spin_unlock_irqrestore(&phba->hbalock, flags);
+ spin_unlock_irqrestore(&phba->port_list_lock, flags);
return NULL;
}
@@ -471,11 +471,6 @@ lpfc_prep_node_fc4type(struct lpfc_vport *vport, uint32_t Did, uint8_t fc4_type)
"Parse GID_FTrsp: did:x%x flg:x%x x%x",
Did, ndlp->nlp_flag, vport->fc_flag);
- /* Don't assume the rport is always the previous
- * FC4 type.
- */
- ndlp->nlp_fc4_type &= ~(NLP_FC4_FCP | NLP_FC4_NVME);
-
/* By default, the driver expects to support FCP FC4 */
if (fc4_type == FC_TYPE_FCP)
ndlp->nlp_fc4_type |= NLP_FC4_FCP;
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c
index aec5b10a8c85..34d311a7dbef 100644
--- a/drivers/scsi/lpfc/lpfc_debugfs.c
+++ b/drivers/scsi/lpfc/lpfc_debugfs.c
@@ -550,7 +550,6 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size)
struct lpfc_nodelist *ndlp;
unsigned char *statep;
struct nvme_fc_local_port *localport;
- struct lpfc_nvmet_tgtport *tgtp;
struct nvme_fc_remote_port *nrport = NULL;
struct lpfc_nvme_rport *rport;
@@ -654,7 +653,6 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size)
"\nOutstanding IO x%x\n", outio);
if (phba->nvmet_support && phba->targetport && (vport == phba->pport)) {
- tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private;
len += snprintf(buf + len, size - len,
"\nNVME Targetport Entry ...\n");
@@ -700,6 +698,8 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size)
rport = lpfc_ndlp_get_nrport(ndlp);
if (rport)
nrport = rport->remoteport;
+ else
+ nrport = NULL;
spin_unlock(&phba->hbalock);
if (!nrport)
continue;
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 4dda969e947c..f1c1faa74b46 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -7673,8 +7673,11 @@ void
lpfc_els_flush_all_cmd(struct lpfc_hba *phba)
{
struct lpfc_vport *vport;
+
+ spin_lock_irq(&phba->port_list_lock);
list_for_each_entry(vport, &phba->port_list, listentry)
lpfc_els_flush_cmd(vport);
+ spin_unlock_irq(&phba->port_list_lock);
return;
}
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index eb71877f12f8..f4deb862efc6 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -4193,7 +4193,7 @@ lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
if (new_state == NLP_STE_MAPPED_NODE ||
new_state == NLP_STE_UNMAPPED_NODE) {
- if (ndlp->nlp_fc4_type & NLP_FC4_FCP ||
+ if (ndlp->nlp_fc4_type ||
ndlp->nlp_DID == Fabric_DID ||
ndlp->nlp_DID == NameServer_DID ||
ndlp->nlp_DID == FDMI_DID) {
@@ -5428,12 +5428,10 @@ static void
lpfc_free_tx(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
{
LIST_HEAD(completions);
- struct lpfc_sli *psli;
IOCB_t *icmd;
struct lpfc_iocbq *iocb, *next_iocb;
struct lpfc_sli_ring *pring;
- psli = &phba->sli;
pring = lpfc_phba_elsring(phba);
if (unlikely(!pring))
return;
@@ -5938,14 +5936,14 @@ lpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi)
}
}
- spin_lock_irqsave(&phba->hbalock, flags);
+ spin_lock_irqsave(&phba->port_list_lock, flags);
list_for_each_entry(vport, &phba->port_list, listentry) {
if (vport->vpi == i) {
- spin_unlock_irqrestore(&phba->hbalock, flags);
+ spin_unlock_irqrestore(&phba->port_list_lock, flags);
return vport;
}
}
- spin_unlock_irqrestore(&phba->hbalock, flags);
+ spin_unlock_irqrestore(&phba->port_list_lock, flags);
return NULL;
}
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h
index 083f8c8706e5..bbd0a57e953f 100644
--- a/drivers/scsi/lpfc/lpfc_hw4.h
+++ b/drivers/scsi/lpfc/lpfc_hw4.h
@@ -186,6 +186,7 @@ struct lpfc_sli_intf {
#define LPFC_CTL_PDEV_CTL_FRL_ALL 0x00
#define LPFC_CTL_PDEV_CTL_FRL_FC_FCOE 0x10
#define LPFC_CTL_PDEV_CTL_FRL_NIC 0x20
+#define LPFC_CTL_PDEV_CTL_DDL_RAS 0x1000000
#define LPFC_FW_DUMP_REQUEST (LPFC_CTL_PDEV_CTL_DD | LPFC_CTL_PDEV_CTL_FRST)
@@ -964,6 +965,7 @@ struct mbox_header {
/* Subsystem Definitions */
#define LPFC_MBOX_SUBSYSTEM_NA 0x0
#define LPFC_MBOX_SUBSYSTEM_COMMON 0x1
+#define LPFC_MBOX_SUBSYSTEM_LOWLEVEL 0xB
#define LPFC_MBOX_SUBSYSTEM_FCOE 0xC
/* Device Specific Definitions */
@@ -1030,6 +1032,9 @@ struct mbox_header {
#define LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_STATE 0x22
#define LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_LOOPBACK 0x23
+/* Low level Opcodes */
+#define LPFC_MBOX_OPCODE_SET_DIAG_LOG_OPTION 0x37
+
/* Mailbox command structures */
struct eq_context {
uint32_t word0;
@@ -1162,6 +1167,45 @@ struct lpfc_mbx_nop {
uint32_t context[2];
};
+
+
+struct lpfc_mbx_set_ras_fwlog {
+ struct mbox_header header;
+ union {
+ struct {
+ uint32_t word4;
+#define lpfc_fwlog_enable_SHIFT 0
+#define lpfc_fwlog_enable_MASK 0x00000001
+#define lpfc_fwlog_enable_WORD word4
+#define lpfc_fwlog_loglvl_SHIFT 8
+#define lpfc_fwlog_loglvl_MASK 0x0000000F
+#define lpfc_fwlog_loglvl_WORD word4
+#define lpfc_fwlog_ra_SHIFT 15
+#define lpfc_fwlog_ra_WORD 0x00000008
+#define lpfc_fwlog_buffcnt_SHIFT 16
+#define lpfc_fwlog_buffcnt_MASK 0x000000FF
+#define lpfc_fwlog_buffcnt_WORD word4
+#define lpfc_fwlog_buffsz_SHIFT 24
+#define lpfc_fwlog_buffsz_MASK 0x000000FF
+#define lpfc_fwlog_buffsz_WORD word4
+ uint32_t word5;
+#define lpfc_fwlog_acqe_SHIFT 0
+#define lpfc_fwlog_acqe_MASK 0x0000FFFF
+#define lpfc_fwlog_acqe_WORD word5
+#define lpfc_fwlog_cqid_SHIFT 16
+#define lpfc_fwlog_cqid_MASK 0x0000FFFF
+#define lpfc_fwlog_cqid_WORD word5
+#define LPFC_MAX_FWLOG_PAGE 16
+ struct dma_address lwpd;
+ struct dma_address buff_fwlog[LPFC_MAX_FWLOG_PAGE];
+ } request;
+ struct {
+ uint32_t word0;
+ } response;
+ } u;
+};
+
+
struct cq_context {
uint32_t word0;
#define lpfc_cq_context_event_SHIFT 31
@@ -3868,6 +3912,7 @@ struct lpfc_mqe {
struct lpfc_mbx_memory_dump_type3 mem_dump_type3;
struct lpfc_mbx_set_host_data set_host_data;
struct lpfc_mbx_nop nop;
+ struct lpfc_mbx_set_ras_fwlog ras_fwlog;
} un;
};
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index f3cae733ae2d..20fa6785a0e2 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -3956,7 +3956,7 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
if (phba->sli_rev == LPFC_SLI_REV4) {
shost->dma_boundary =
phba->sli4_hba.pc_sli4_params.sge_supp_len-1;
- shost->sg_tablesize = phba->cfg_sg_seg_cnt;
+ shost->sg_tablesize = phba->cfg_scsi_seg_cnt;
}
/*
@@ -3988,9 +3988,9 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
if (error)
goto out_put_shost;
- spin_lock_irq(&phba->hbalock);
+ spin_lock_irq(&phba->port_list_lock);
list_add_tail(&vport->listentry, &phba->port_list);
- spin_unlock_irq(&phba->hbalock);
+ spin_unlock_irq(&phba->port_list_lock);
return vport;
out_put_shost:
@@ -4016,9 +4016,9 @@ destroy_port(struct lpfc_vport *vport)
fc_remove_host(shost);
scsi_remove_host(shost);
- spin_lock_irq(&phba->hbalock);
+ spin_lock_irq(&phba->port_list_lock);
list_del_init(&vport->listentry);
- spin_unlock_irq(&phba->hbalock);
+ spin_unlock_irq(&phba->port_list_lock);
lpfc_cleanup(vport);
return;
@@ -5621,7 +5621,10 @@ lpfc_setup_driver_resource_phase1(struct lpfc_hba *phba)
/* Initialize ndlp management spinlock */
spin_lock_init(&phba->ndlp_lock);
+ /* Initialize port_list spinlock */
+ spin_lock_init(&phba->port_list_lock);
INIT_LIST_HEAD(&phba->port_list);
+
INIT_LIST_HEAD(&phba->work_list);
init_waitqueue_head(&phba->wait_4_mlo_m_q);
@@ -5919,8 +5922,6 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
* There are going to be 2 reserved SGEs: 1 FCP cmnd + 1 FCP rsp
*/
max_buf_size = (2 * SLI4_PAGE_SIZE);
- if (phba->cfg_sg_seg_cnt > LPFC_MAX_SGL_SEG_CNT - extra)
- phba->cfg_sg_seg_cnt = LPFC_MAX_SGL_SEG_CNT - extra;
/*
* Since lpfc_sg_seg_cnt is module param, the sg_dma_buf_size
@@ -5942,9 +5943,16 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
/* Total SGEs for scsi_sg_list and scsi_sg_prot_list */
phba->cfg_total_seg_cnt = LPFC_MAX_SGL_SEG_CNT;
- if (phba->cfg_sg_seg_cnt > LPFC_MAX_SG_SLI4_SEG_CNT_DIF)
- phba->cfg_sg_seg_cnt =
- LPFC_MAX_SG_SLI4_SEG_CNT_DIF;
+ /*
+ * If supporting DIF, reduce the seg count for scsi to
+ * allow room for the DIF sges.
+ */
+ if (phba->cfg_enable_bg &&
+ phba->cfg_sg_seg_cnt > LPFC_MAX_BG_SLI4_SEG_CNT_DIF)
+ phba->cfg_scsi_seg_cnt = LPFC_MAX_BG_SLI4_SEG_CNT_DIF;
+ else
+ phba->cfg_scsi_seg_cnt = phba->cfg_sg_seg_cnt;
+
} else {
/*
* The scsi_buf for a regular I/O holds the FCP cmnd,
@@ -5958,6 +5966,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
/* Total SGEs for scsi_sg_list */
phba->cfg_total_seg_cnt = phba->cfg_sg_seg_cnt + extra;
+ phba->cfg_scsi_seg_cnt = phba->cfg_sg_seg_cnt;
/*
* NOTE: if (phba->cfg_sg_seg_cnt + extra) <= 256 we only
@@ -5965,10 +5974,22 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
*/
}
+ /* Limit to LPFC_MAX_NVME_SEG_CNT for NVME. */
+ if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) {
+ if (phba->cfg_sg_seg_cnt > LPFC_MAX_NVME_SEG_CNT) {
+ lpfc_printf_log(phba, KERN_INFO, LOG_NVME | LOG_INIT,
+ "6300 Reducing NVME sg segment "
+ "cnt to %d\n",
+ LPFC_MAX_NVME_SEG_CNT);
+ phba->cfg_nvme_seg_cnt = LPFC_MAX_NVME_SEG_CNT;
+ } else
+ phba->cfg_nvme_seg_cnt = phba->cfg_sg_seg_cnt;
+ }
+
/* Initialize the host templates with the updated values. */
- lpfc_vport_template.sg_tablesize = phba->cfg_sg_seg_cnt;
- lpfc_template.sg_tablesize = phba->cfg_sg_seg_cnt;
- lpfc_template_no_hr.sg_tablesize = phba->cfg_sg_seg_cnt;
+ lpfc_vport_template.sg_tablesize = phba->cfg_scsi_seg_cnt;
+ lpfc_template.sg_tablesize = phba->cfg_scsi_seg_cnt;
+ lpfc_template_no_hr.sg_tablesize = phba->cfg_scsi_seg_cnt;
if (phba->cfg_sg_dma_buf_size <= LPFC_MIN_SG_SLI4_BUF_SZ)
phba->cfg_sg_dma_buf_size = LPFC_MIN_SG_SLI4_BUF_SZ;
@@ -5977,9 +5998,11 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
SLI4_PAGE_ALIGN(phba->cfg_sg_dma_buf_size);
lpfc_printf_log(phba, KERN_INFO, LOG_INIT | LOG_FCP,
- "9087 sg_tablesize:%d dmabuf_size:%d total_sge:%d\n",
+ "9087 sg_seg_cnt:%d dmabuf_size:%d "
+ "total:%d scsi:%d nvme:%d\n",
phba->cfg_sg_seg_cnt, phba->cfg_sg_dma_buf_size,
- phba->cfg_total_seg_cnt);
+ phba->cfg_total_seg_cnt, phba->cfg_scsi_seg_cnt,
+ phba->cfg_nvme_seg_cnt);
/* Initialize buffer queue management fields */
INIT_LIST_HEAD(&phba->hbqs[LPFC_ELS_HBQ].hbq_buffer_list);
@@ -6205,6 +6228,9 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
if (phba->cfg_fof)
fof_vectors = 1;
+ /* Verify RAS support on adapter */
+ lpfc_sli4_ras_init(phba);
+
/* Verify all the SLI4 queues */
rc = lpfc_sli4_queue_verify(phba);
if (rc)
@@ -7967,7 +7993,7 @@ lpfc_sli4_read_config(struct lpfc_hba *phba)
else
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"3028 GET_FUNCTION_CONFIG: failed to find "
- "Resrouce Descriptor:x%x\n",
+ "Resource Descriptor:x%x\n",
LPFC_RSRC_DESC_TYPE_FCFCOE);
read_cfg_out:
@@ -10492,6 +10518,14 @@ lpfc_sli4_hba_unset(struct lpfc_hba *phba)
/* Stop kthread signal shall trigger work_done one more time */
kthread_stop(phba->worker_thread);
+ /* Disable FW logging to host memory */
+ writel(LPFC_CTL_PDEV_CTL_DDL_RAS,
+ phba->sli4_hba.conf_regs_memmap_p + LPFC_CTL_PDEV_CTL_OFFSET);
+
+ /* Free RAS DMA memory */
+ if (phba->ras_fwlog.ras_enabled == true)
+ lpfc_sli4_ras_dma_free(phba);
+
/* Unset the queues shared with the hardware then release all
* allocated resources.
*/
@@ -10737,6 +10771,7 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
phba->mds_diags_support = 1;
else
phba->mds_diags_support = 0;
+
return 0;
}
@@ -10965,9 +11000,9 @@ lpfc_pci_remove_one_s3(struct pci_dev *pdev)
kfree(phba->vpi_ids);
lpfc_stop_hba_timers(phba);
- spin_lock_irq(&phba->hbalock);
+ spin_lock_irq(&phba->port_list_lock);
list_del_init(&vport->listentry);
- spin_unlock_irq(&phba->hbalock);
+ spin_unlock_irq(&phba->port_list_lock);
lpfc_debugfs_terminate(vport);
@@ -11329,10 +11364,6 @@ lpfc_io_resume_s3(struct pci_dev *pdev)
/* Bring device online, it will be no-op for non-fatal error resume */
lpfc_online(phba);
-
- /* Clean up Advanced Error Reporting (AER) if needed */
- if (phba->hba_flag & HBA_AER_ENABLED)
- pci_cleanup_aer_uncorrect_error_status(pdev);
}
/**
@@ -11698,6 +11729,10 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
/* Check if there are static vports to be created. */
lpfc_create_static_vport(phba);
+
+ /* Enable RAS FW log support */
+ lpfc_sli4_ras_setup(phba);
+
return 0;
out_disable_intr:
@@ -11777,9 +11812,9 @@ lpfc_pci_remove_one_s4(struct pci_dev *pdev)
lpfc_sli4_hba_unset(phba);
lpfc_stop_hba_timers(phba);
- spin_lock_irq(&phba->hbalock);
+ spin_lock_irq(&phba->port_list_lock);
list_del_init(&vport->listentry);
- spin_unlock_irq(&phba->hbalock);
+ spin_unlock_irq(&phba->port_list_lock);
/* Perform scsi free before driver resource_unset since scsi
* buffers are released to their corresponding pools here.
@@ -12144,10 +12179,6 @@ lpfc_io_resume_s4(struct pci_dev *pdev)
/* Bring the device back online */
lpfc_online(phba);
}
-
- /* Clean up Advanced Error Reporting (AER) if needed */
- if (phba->hba_flag & HBA_AER_ENABLED)
- pci_cleanup_aer_uncorrect_error_status(pdev);
}
/**
@@ -12428,6 +12459,30 @@ lpfc_sli4_oas_verify(struct lpfc_hba *phba)
}
/**
+ * lpfc_sli4_ras_init - Verify RAS-FW log is supported by this adapter
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine checks to see if RAS is supported by the adapter. Check the
+ * function through which RAS support enablement is to be done.
+ **/
+void
+lpfc_sli4_ras_init(struct lpfc_hba *phba)
+{
+ switch (phba->pcidev->device) {
+ case PCI_DEVICE_ID_LANCER_G6_FC:
+ case PCI_DEVICE_ID_LANCER_G7_FC:
+ phba->ras_fwlog.ras_hwsupport = true;
+ if (phba->cfg_ras_fwlog_func == PCI_FUNC(phba->pcidev->devfn))
+ phba->ras_fwlog.ras_enabled = true;
+ else
+ phba->ras_fwlog.ras_enabled = false;
+ break;
+ default:
+ phba->ras_fwlog.ras_hwsupport = false;
+ }
+}
+
+/**
* lpfc_fof_queue_setup - Set up all the fof queues
* @phba: pointer to lpfc hba data structure.
*
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index bd9bce9d9974..269808e8480f 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -2318,6 +2318,7 @@ lpfc_device_recov_unmap_node(struct lpfc_vport *vport,
lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
+ ndlp->nlp_fc4_type &= ~(NLP_FC4_FCP | NLP_FC4_NVME);
spin_unlock_irq(shost->host_lock);
lpfc_disc_set_adisc(vport, ndlp);
@@ -2395,6 +2396,7 @@ lpfc_device_recov_mapped_node(struct lpfc_vport *vport,
lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
+ ndlp->nlp_fc4_type &= ~(NLP_FC4_FCP | NLP_FC4_NVME);
spin_unlock_irq(shost->host_lock);
lpfc_disc_set_adisc(vport, ndlp);
return ndlp->nlp_state;
@@ -2652,6 +2654,7 @@ lpfc_device_recov_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
lpfc_cancel_retry_delay_tmo(vport, ndlp);
spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
+ ndlp->nlp_fc4_type &= ~(NLP_FC4_FCP | NLP_FC4_NVME);
spin_unlock_irq(shost->host_lock);
return ndlp->nlp_state;
}
diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c
index 918ae18ef8a8..ba831def9301 100644
--- a/drivers/scsi/lpfc/lpfc_nvme.c
+++ b/drivers/scsi/lpfc/lpfc_nvme.c
@@ -282,7 +282,7 @@ lpfc_nvme_delete_queue(struct nvme_fc_local_port *pnvme_lport,
vport = lport->vport;
lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME,
- "6001 ENTER. lpfc_pnvme %p, qidx x%xi qhandle %p\n",
+ "6001 ENTER. lpfc_pnvme %p, qidx x%x qhandle %p\n",
lport, qidx, handle);
kfree(handle);
}
@@ -2235,13 +2235,11 @@ lpfc_new_nvme_buf(struct lpfc_vport *vport, int num_to_alloc)
struct sli4_sge *sgl;
dma_addr_t pdma_phys_sgl;
uint16_t iotag, lxri = 0;
- int bcnt, num_posted, sgl_size;
+ int bcnt, num_posted;
LIST_HEAD(prep_nblist);
LIST_HEAD(post_nblist);
LIST_HEAD(nvme_nblist);
- sgl_size = phba->cfg_sg_dma_buf_size;
-
for (bcnt = 0; bcnt < num_to_alloc; bcnt++) {
lpfc_ncmd = kzalloc(sizeof(struct lpfc_nvme_buf), GFP_KERNEL);
if (!lpfc_ncmd)
@@ -2462,17 +2460,10 @@ lpfc_nvme_create_localport(struct lpfc_vport *vport)
nfcp_info.node_name = wwn_to_u64(vport->fc_nodename.u.wwn);
nfcp_info.port_name = wwn_to_u64(vport->fc_portname.u.wwn);
- /* Limit to LPFC_MAX_NVME_SEG_CNT.
- * For now need + 1 to get around NVME transport logic.
+ /* We need to tell the transport layer + 1 because it takes page
+ * alignment into account. When space for the SGL is allocated we
+ * allocate + 3, one for cmd, one for rsp and one for this alignment
*/
- if (phba->cfg_sg_seg_cnt > LPFC_MAX_NVME_SEG_CNT) {
- lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME | LOG_INIT,
- "6300 Reducing sg segment cnt to %d\n",
- LPFC_MAX_NVME_SEG_CNT);
- phba->cfg_nvme_seg_cnt = LPFC_MAX_NVME_SEG_CNT;
- } else {
- phba->cfg_nvme_seg_cnt = phba->cfg_sg_seg_cnt;
- }
lpfc_nvme_template.max_sgl_segments = phba->cfg_nvme_seg_cnt + 1;
lpfc_nvme_template.max_hw_queues = phba->cfg_nvme_io_channel;
diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c
index b766afe10d3d..6245f442d784 100644
--- a/drivers/scsi/lpfc/lpfc_nvmet.c
+++ b/drivers/scsi/lpfc/lpfc_nvmet.c
@@ -1339,15 +1339,14 @@ lpfc_nvmet_setup_io_context(struct lpfc_hba *phba)
idx = 0;
}
- infop = phba->sli4_hba.nvmet_ctx_info;
- for (j = 0; j < phba->cfg_nvmet_mrq; j++) {
- for (i = 0; i < phba->sli4_hba.num_present_cpu; i++) {
+ for (i = 0; i < phba->sli4_hba.num_present_cpu; i++) {
+ for (j = 0; j < phba->cfg_nvmet_mrq; j++) {
+ infop = lpfc_get_ctx_list(phba, i, j);
lpfc_printf_log(phba, KERN_INFO, LOG_NVME | LOG_INIT,
"6408 TOTAL NVMET ctx for CPU %d "
"MRQ %d: cnt %d nextcpu %p\n",
i, j, infop->nvmet_ctx_list_cnt,
infop->nvmet_ctx_next_cpu);
- infop++;
}
}
return 0;
@@ -1373,17 +1372,10 @@ lpfc_nvmet_create_targetport(struct lpfc_hba *phba)
pinfo.port_name = wwn_to_u64(vport->fc_portname.u.wwn);
pinfo.port_id = vport->fc_myDID;
- /* Limit to LPFC_MAX_NVME_SEG_CNT.
- * For now need + 1 to get around NVME transport logic.
+ /* We need to tell the transport layer + 1 because it takes page
+ * alignment into account. When space for the SGL is allocated we
+ * allocate + 3, one for cmd, one for rsp and one for this alignment
*/
- if (phba->cfg_sg_seg_cnt > LPFC_MAX_NVME_SEG_CNT) {
- lpfc_printf_log(phba, KERN_INFO, LOG_NVME | LOG_INIT,
- "6400 Reducing sg segment cnt to %d\n",
- LPFC_MAX_NVME_SEG_CNT);
- phba->cfg_nvme_seg_cnt = LPFC_MAX_NVME_SEG_CNT;
- } else {
- phba->cfg_nvme_seg_cnt = phba->cfg_sg_seg_cnt;
- }
lpfc_tgttemplate.max_sgl_segments = phba->cfg_nvme_seg_cnt + 1;
lpfc_tgttemplate.max_hw_queues = phba->cfg_nvme_io_channel;
lpfc_tgttemplate.target_features = NVMET_FCTGTFEAT_READDATA_RSP;
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 5c7858e735c9..4fa6703a9ec9 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -202,8 +202,8 @@ lpfc_sli4_set_rsp_sgl_last(struct lpfc_hba *phba,
static void
lpfc_update_stats(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
{
- struct lpfc_rport_data *rdata = lpfc_cmd->rdata;
- struct lpfc_nodelist *pnode = rdata->pnode;
+ struct lpfc_rport_data *rdata;
+ struct lpfc_nodelist *pnode;
struct scsi_cmnd *cmd = lpfc_cmd->pCmd;
unsigned long flags;
struct Scsi_Host *shost = cmd->device->host;
@@ -211,17 +211,19 @@ lpfc_update_stats(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
unsigned long latency;
int i;
- if (cmd->result)
+ if (!vport->stat_data_enabled ||
+ vport->stat_data_blocked ||
+ (cmd->result))
return;
latency = jiffies_to_msecs((long)jiffies - (long)lpfc_cmd->start_time);
+ rdata = lpfc_cmd->rdata;
+ pnode = rdata->pnode;
spin_lock_irqsave(shost->host_lock, flags);
- if (!vport->stat_data_enabled ||
- vport->stat_data_blocked ||
- !pnode ||
- !pnode->lat_data ||
- (phba->bucket_type == LPFC_NO_BUCKET)) {
+ if (!pnode ||
+ !pnode->lat_data ||
+ (phba->bucket_type == LPFC_NO_BUCKET)) {
spin_unlock_irqrestore(shost->host_lock, flags);
return;
}
@@ -1050,7 +1052,7 @@ lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
if (!found)
return NULL;
- if (lpfc_ndlp_check_qdepth(phba, ndlp) && lpfc_cmd) {
+ if (lpfc_ndlp_check_qdepth(phba, ndlp)) {
atomic_inc(&ndlp->cmd_pending);
lpfc_cmd->flags |= LPFC_SBUF_BUMP_QDEPTH;
}
@@ -4158,9 +4160,17 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
}
lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd);
- spin_lock_irqsave(&phba->hbalock, flags);
- lpfc_cmd->pCmd = NULL;
- spin_unlock_irqrestore(&phba->hbalock, flags);
+ /* If pCmd was set to NULL from abort path, do not call scsi_done */
+ if (xchg(&lpfc_cmd->pCmd, NULL) == NULL) {
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
+ "0711 FCP cmd already NULL, sid: 0x%06x, "
+ "did: 0x%06x, oxid: 0x%04x\n",
+ vport->fc_myDID,
+ (pnode) ? pnode->nlp_DID : 0,
+ phba->sli_rev == LPFC_SLI_REV4 ?
+ lpfc_cmd->cur_iocbq.sli4_xritag : 0xffff);
+ return;
+ }
/* The sdev is not guaranteed to be valid post scsi_done upcall. */
cmd->scsi_done(cmd);
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 9830bdb6e072..783a1540cfbe 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -392,11 +392,7 @@ lpfc_sli4_if6_eq_clr_intr(struct lpfc_queue *q)
struct lpfc_register doorbell;
doorbell.word0 = 0;
- bf_set(lpfc_eqcq_doorbell_eqci, &doorbell, 1);
- bf_set(lpfc_eqcq_doorbell_qt, &doorbell, LPFC_QUEUE_TYPE_EVENT);
- bf_set(lpfc_eqcq_doorbell_eqid_hi, &doorbell,
- (q->queue_id >> LPFC_EQID_HI_FIELD_SHIFT));
- bf_set(lpfc_eqcq_doorbell_eqid_lo, &doorbell, q->queue_id);
+ bf_set(lpfc_if6_eq_doorbell_eqid, &doorbell, q->queue_id);
writel(doorbell.word0, q->phba->sli4_hba.EQDBregaddr);
}
@@ -3797,6 +3793,7 @@ lpfc_sli_handle_slow_ring_event_s4(struct lpfc_hba *phba,
struct hbq_dmabuf *dmabuf;
struct lpfc_cq_event *cq_event;
unsigned long iflag;
+ int count = 0;
spin_lock_irqsave(&phba->hbalock, iflag);
phba->hba_flag &= ~HBA_SP_QUEUE_EVT;
@@ -3818,16 +3815,22 @@ lpfc_sli_handle_slow_ring_event_s4(struct lpfc_hba *phba,
if (irspiocbq)
lpfc_sli_sp_handle_rspiocb(phba, pring,
irspiocbq);
+ count++;
break;
case CQE_CODE_RECEIVE:
case CQE_CODE_RECEIVE_V1:
dmabuf = container_of(cq_event, struct hbq_dmabuf,
cq_event);
lpfc_sli4_handle_received_buffer(phba, dmabuf);
+ count++;
break;
default:
break;
}
+
+ /* Limit the number of events to 64 to avoid soft lockups */
+ if (count == 64)
+ break;
}
}
@@ -6146,6 +6149,271 @@ lpfc_set_features(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox,
}
/**
+ * lpfc_sli4_ras_dma_free - Free memory allocated for FW logging.
+ * @phba: Pointer to HBA context object.
+ *
+ * This function is called to free memory allocated for RAS FW logging
+ * support in the driver.
+ **/
+void
+lpfc_sli4_ras_dma_free(struct lpfc_hba *phba)
+{
+ struct lpfc_ras_fwlog *ras_fwlog = &phba->ras_fwlog;
+ struct lpfc_dmabuf *dmabuf, *next;
+
+ if (!list_empty(&ras_fwlog->fwlog_buff_list)) {
+ list_for_each_entry_safe(dmabuf, next,
+ &ras_fwlog->fwlog_buff_list,
+ list) {
+ list_del(&dmabuf->list);
+ dma_free_coherent(&phba->pcidev->dev,
+ LPFC_RAS_MAX_ENTRY_SIZE,
+ dmabuf->virt, dmabuf->phys);
+ kfree(dmabuf);
+ }
+ }
+
+ if (ras_fwlog->lwpd.virt) {
+ dma_free_coherent(&phba->pcidev->dev,
+ sizeof(uint32_t) * 2,
+ ras_fwlog->lwpd.virt,
+ ras_fwlog->lwpd.phys);
+ ras_fwlog->lwpd.virt = NULL;
+ }
+
+ ras_fwlog->ras_active = false;
+}
+
+/**
+ * lpfc_sli4_ras_dma_alloc: Allocate memory for FW support
+ * @phba: Pointer to HBA context object.
+ * @fwlog_buff_count: Count of buffers to be created.
+ *
+ * This routine DMA memory for Log Write Position Data[LPWD] and buffer
+ * to update FW log is posted to the adapter.
+ * Buffer count is calculated based on module param ras_fwlog_buffsize
+ * Size of each buffer posted to FW is 64K.
+ **/
+
+static int
+lpfc_sli4_ras_dma_alloc(struct lpfc_hba *phba,
+ uint32_t fwlog_buff_count)
+{
+ struct lpfc_ras_fwlog *ras_fwlog = &phba->ras_fwlog;
+ struct lpfc_dmabuf *dmabuf;
+ int rc = 0, i = 0;
+
+ /* Initialize List */
+ INIT_LIST_HEAD(&ras_fwlog->fwlog_buff_list);
+
+ /* Allocate memory for the LWPD */
+ ras_fwlog->lwpd.virt = dma_alloc_coherent(&phba->pcidev->dev,
+ sizeof(uint32_t) * 2,
+ &ras_fwlog->lwpd.phys,
+ GFP_KERNEL);
+ if (!ras_fwlog->lwpd.virt) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+ "6185 LWPD Memory Alloc Failed\n");
+
+ return -ENOMEM;
+ }
+
+ ras_fwlog->fw_buffcount = fwlog_buff_count;
+ for (i = 0; i < ras_fwlog->fw_buffcount; i++) {
+ dmabuf = kzalloc(sizeof(struct lpfc_dmabuf),
+ GFP_KERNEL);
+ if (!dmabuf) {
+ rc = -ENOMEM;
+ lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+ "6186 Memory Alloc failed FW logging");
+ goto free_mem;
+ }
+
+ dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev,
+ LPFC_RAS_MAX_ENTRY_SIZE,
+ &dmabuf->phys,
+ GFP_KERNEL);
+ if (!dmabuf->virt) {
+ kfree(dmabuf);
+ rc = -ENOMEM;
+ lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+ "6187 DMA Alloc Failed FW logging");
+ goto free_mem;
+ }
+ memset(dmabuf->virt, 0, LPFC_RAS_MAX_ENTRY_SIZE);
+ dmabuf->buffer_tag = i;
+ list_add_tail(&dmabuf->list, &ras_fwlog->fwlog_buff_list);
+ }
+
+free_mem:
+ if (rc)
+ lpfc_sli4_ras_dma_free(phba);
+
+ return rc;
+}
+
+/**
+ * lpfc_sli4_ras_mbox_cmpl: Completion handler for RAS MBX command
+ * @phba: pointer to lpfc hba data structure.
+ * @pmboxq: pointer to the driver internal queue element for mailbox command.
+ *
+ * Completion handler for driver's RAS MBX command to the device.
+ **/
+static void
+lpfc_sli4_ras_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+{
+ MAILBOX_t *mb;
+ union lpfc_sli4_cfg_shdr *shdr;
+ uint32_t shdr_status, shdr_add_status;
+ struct lpfc_ras_fwlog *ras_fwlog = &phba->ras_fwlog;
+
+ mb = &pmb->u.mb;
+
+ shdr = (union lpfc_sli4_cfg_shdr *)
+ &pmb->u.mqe.un.ras_fwlog.header.cfg_shdr;
+ shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+ shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+
+ if (mb->mbxStatus != MBX_SUCCESS || shdr_status) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
+ "6188 FW LOG mailbox "
+ "completed with status x%x add_status x%x,"
+ " mbx status x%x\n",
+ shdr_status, shdr_add_status, mb->mbxStatus);
+ goto disable_ras;
+ }
+
+ ras_fwlog->ras_active = true;
+ mempool_free(pmb, phba->mbox_mem_pool);
+
+ return;
+
+disable_ras:
+ /* Free RAS DMA memory */
+ lpfc_sli4_ras_dma_free(phba);
+ mempool_free(pmb, phba->mbox_mem_pool);
+}
+
+/**
+ * lpfc_sli4_ras_fwlog_init: Initialize memory and post RAS MBX command
+ * @phba: pointer to lpfc hba data structure.
+ * @fwlog_level: Logging verbosity level.
+ * @fwlog_enable: Enable/Disable logging.
+ *
+ * Initialize memory and post mailbox command to enable FW logging in host
+ * memory.
+ **/
+int
+lpfc_sli4_ras_fwlog_init(struct lpfc_hba *phba,
+ uint32_t fwlog_level,
+ uint32_t fwlog_enable)
+{
+ struct lpfc_ras_fwlog *ras_fwlog = &phba->ras_fwlog;
+ struct lpfc_mbx_set_ras_fwlog *mbx_fwlog = NULL;
+ struct lpfc_dmabuf *dmabuf;
+ LPFC_MBOXQ_t *mbox;
+ uint32_t len = 0, fwlog_buffsize, fwlog_entry_count;
+ int rc = 0;
+
+ fwlog_buffsize = (LPFC_RAS_MIN_BUFF_POST_SIZE *
+ phba->cfg_ras_fwlog_buffsize);
+ fwlog_entry_count = (fwlog_buffsize/LPFC_RAS_MAX_ENTRY_SIZE);
+
+ /*
+ * If re-enabling FW logging support use earlier allocated
+ * DMA buffers while posting MBX command.
+ **/
+ if (!ras_fwlog->lwpd.virt) {
+ rc = lpfc_sli4_ras_dma_alloc(phba, fwlog_entry_count);
+ if (rc) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+ "6189 RAS FW Log Support Not Enabled");
+ return rc;
+ }
+ }
+
+ /* Setup Mailbox command */
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!mbox) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+ "6190 RAS MBX Alloc Failed");
+ rc = -ENOMEM;
+ goto mem_free;
+ }
+
+ ras_fwlog->fw_loglevel = fwlog_level;
+ len = (sizeof(struct lpfc_mbx_set_ras_fwlog) -
+ sizeof(struct lpfc_sli4_cfg_mhdr));
+
+ lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_LOWLEVEL,
+ LPFC_MBOX_OPCODE_SET_DIAG_LOG_OPTION,
+ len, LPFC_SLI4_MBX_EMBED);
+
+ mbx_fwlog = (struct lpfc_mbx_set_ras_fwlog *)&mbox->u.mqe.un.ras_fwlog;
+ bf_set(lpfc_fwlog_enable, &mbx_fwlog->u.request,
+ fwlog_enable);
+ bf_set(lpfc_fwlog_loglvl, &mbx_fwlog->u.request,
+ ras_fwlog->fw_loglevel);
+ bf_set(lpfc_fwlog_buffcnt, &mbx_fwlog->u.request,
+ ras_fwlog->fw_buffcount);
+ bf_set(lpfc_fwlog_buffsz, &mbx_fwlog->u.request,
+ LPFC_RAS_MAX_ENTRY_SIZE/SLI4_PAGE_SIZE);
+
+ /* Update DMA buffer address */
+ list_for_each_entry(dmabuf, &ras_fwlog->fwlog_buff_list, list) {
+ memset(dmabuf->virt, 0, LPFC_RAS_MAX_ENTRY_SIZE);
+
+ mbx_fwlog->u.request.buff_fwlog[dmabuf->buffer_tag].addr_lo =
+ putPaddrLow(dmabuf->phys);
+
+ mbx_fwlog->u.request.buff_fwlog[dmabuf->buffer_tag].addr_hi =
+ putPaddrHigh(dmabuf->phys);
+ }
+
+ /* Update LPWD address */
+ mbx_fwlog->u.request.lwpd.addr_lo = putPaddrLow(ras_fwlog->lwpd.phys);
+ mbx_fwlog->u.request.lwpd.addr_hi = putPaddrHigh(ras_fwlog->lwpd.phys);
+
+ mbox->vport = phba->pport;
+ mbox->mbox_cmpl = lpfc_sli4_ras_mbox_cmpl;
+
+ rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+
+ if (rc == MBX_NOT_FINISHED) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+ "6191 RAS Mailbox failed. "
+ "status %d mbxStatus : x%x", rc,
+ bf_get(lpfc_mqe_status, &mbox->u.mqe));
+ mempool_free(mbox, phba->mbox_mem_pool);
+ rc = -EIO;
+ goto mem_free;
+ } else
+ rc = 0;
+mem_free:
+ if (rc)
+ lpfc_sli4_ras_dma_free(phba);
+
+ return rc;
+}
+
+/**
+ * lpfc_sli4_ras_setup - Check if RAS supported on the adapter
+ * @phba: Pointer to HBA context object.
+ *
+ * Check if RAS is supported on the adapter and initialize it.
+ **/
+void
+lpfc_sli4_ras_setup(struct lpfc_hba *phba)
+{
+ /* Check RAS FW Log needs to be enabled or not */
+ if (lpfc_check_fwlog_support(phba))
+ return;
+
+ lpfc_sli4_ras_fwlog_init(phba, phba->cfg_ras_fwlog_level,
+ LPFC_RAS_ENABLE_LOGGING);
+}
+
+/**
* lpfc_sli4_alloc_resource_identifiers - Allocate all SLI4 resource extents.
* @phba: Pointer to HBA context object.
*
@@ -10266,8 +10534,12 @@ lpfc_sli_mbox_sys_flush(struct lpfc_hba *phba)
LPFC_MBOXQ_t *pmb;
unsigned long iflag;
+ /* Disable softirqs, including timers from obtaining phba->hbalock */
+ local_bh_disable();
+
/* Flush all the mailbox commands in the mbox system */
spin_lock_irqsave(&phba->hbalock, iflag);
+
/* The pending mailbox command queue */
list_splice_init(&phba->sli.mboxq, &completions);
/* The outstanding active mailbox command */
@@ -10280,6 +10552,9 @@ lpfc_sli_mbox_sys_flush(struct lpfc_hba *phba)
list_splice_init(&phba->sli.mboxq_cmpl, &completions);
spin_unlock_irqrestore(&phba->hbalock, iflag);
+ /* Enable softirqs again, done with phba->hbalock */
+ local_bh_enable();
+
/* Return all flushed mailbox commands with MBX_NOT_FINISHED status */
while (!list_empty(&completions)) {
list_remove_head(&completions, pmb, LPFC_MBOXQ_t, list);
@@ -10419,6 +10694,9 @@ lpfc_sli_hba_down(struct lpfc_hba *phba)
lpfc_hba_down_prep(phba);
+ /* Disable softirqs, including timers from obtaining phba->hbalock */
+ local_bh_disable();
+
lpfc_fabric_abort_hba(phba);
spin_lock_irqsave(&phba->hbalock, flags);
@@ -10472,6 +10750,9 @@ lpfc_sli_hba_down(struct lpfc_hba *phba)
kfree(buf_ptr);
}
+ /* Enable softirqs again, done with phba->hbalock */
+ local_bh_enable();
+
/* Return any active mbox cmds */
del_timer_sync(&psli->mbox_tmo);
@@ -11775,6 +12056,9 @@ lpfc_sli_mbox_sys_shutdown(struct lpfc_hba *phba, int mbx_action)
}
timeout = msecs_to_jiffies(LPFC_MBOX_TMO * 1000) + jiffies;
+ /* Disable softirqs, including timers from obtaining phba->hbalock */
+ local_bh_disable();
+
spin_lock_irq(&phba->hbalock);
psli->sli_flag |= LPFC_SLI_ASYNC_MBX_BLK;
@@ -11788,6 +12072,9 @@ lpfc_sli_mbox_sys_shutdown(struct lpfc_hba *phba, int mbx_action)
1000) + jiffies;
spin_unlock_irq(&phba->hbalock);
+ /* Enable softirqs again, done with phba->hbalock */
+ local_bh_enable();
+
while (phba->sli.mbox_active) {
/* Check active mailbox complete status every 2ms */
msleep(2);
@@ -11797,9 +12084,13 @@ lpfc_sli_mbox_sys_shutdown(struct lpfc_hba *phba, int mbx_action)
*/
break;
}
- } else
+ } else {
spin_unlock_irq(&phba->hbalock);
+ /* Enable softirqs again, done with phba->hbalock */
+ local_bh_enable();
+ }
+
lpfc_sli_mbox_sys_flush(phba);
}
@@ -13136,7 +13427,6 @@ static bool
lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_rcqe *rcqe)
{
bool workposted = false;
- struct fc_frame_header *fc_hdr;
struct lpfc_queue *hrq = phba->sli4_hba.hdr_rq;
struct lpfc_queue *drq = phba->sli4_hba.dat_rq;
struct lpfc_nvmet_tgtport *tgtp;
@@ -13173,9 +13463,6 @@ lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_rcqe *rcqe)
hrq->RQ_buf_posted--;
memcpy(&dma_buf->cq_event.cqe.rcqe_cmpl, rcqe, sizeof(*rcqe));
- /* If a NVME LS event (type 0x28), treat it as Fast path */
- fc_hdr = (struct fc_frame_header *)dma_buf->hbuf.virt;
-
/* save off the frame for the word thread to process */
list_add_tail(&dma_buf->cq_event.list,
&phba->sli4_hba.sp_queue_event);
@@ -14558,13 +14845,10 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq,
int rc, length, status = 0;
uint32_t shdr_status, shdr_add_status;
union lpfc_sli4_cfg_shdr *shdr;
- uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz;
/* sanity check on queue memory */
if (!cq || !eq)
return -ENODEV;
- if (!phba->sli4_hba.pc_sli4_params.supported)
- hw_page_size = cq->page_size;
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!mbox)
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h
index 399c0015c546..e76c380e1a84 100644
--- a/drivers/scsi/lpfc/lpfc_sli4.h
+++ b/drivers/scsi/lpfc/lpfc_sli4.h
@@ -886,3 +886,4 @@ int lpfc_sli4_unregister_fcf(struct lpfc_hba *);
int lpfc_sli4_post_status_check(struct lpfc_hba *);
uint8_t lpfc_sli_config_mbox_subsys_get(struct lpfc_hba *, LPFC_MBOXQ_t *);
uint8_t lpfc_sli_config_mbox_opcode_get(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_sli4_ras_dma_free(struct lpfc_hba *phba);
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index 501249509af4..5a0d512ff497 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.0.0.6"
+#define LPFC_DRIVER_VERSION "12.0.0.7"
#define LPFC_DRIVER_NAME "lpfc"
/* Used for SLI 2/3 */
diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c
index 1ff0f7de9105..c340e0e47473 100644
--- a/drivers/scsi/lpfc/lpfc_vport.c
+++ b/drivers/scsi/lpfc/lpfc_vport.c
@@ -207,7 +207,7 @@ lpfc_unique_wwpn(struct lpfc_hba *phba, struct lpfc_vport *new_vport)
struct lpfc_vport *vport;
unsigned long flags;
- spin_lock_irqsave(&phba->hbalock, flags);
+ spin_lock_irqsave(&phba->port_list_lock, flags);
list_for_each_entry(vport, &phba->port_list, listentry) {
if (vport == new_vport)
continue;
@@ -215,11 +215,11 @@ lpfc_unique_wwpn(struct lpfc_hba *phba, struct lpfc_vport *new_vport)
if (memcmp(&vport->fc_sparam.portName,
&new_vport->fc_sparam.portName,
sizeof(struct lpfc_name)) == 0) {
- spin_unlock_irqrestore(&phba->hbalock, flags);
+ spin_unlock_irqrestore(&phba->port_list_lock, flags);
return 0;
}
}
- spin_unlock_irqrestore(&phba->hbalock, flags);
+ spin_unlock_irqrestore(&phba->port_list_lock, flags);
return 1;
}
@@ -825,9 +825,9 @@ skip_logo:
lpfc_free_vpi(phba, vport->vpi);
vport->work_port_events = 0;
- spin_lock_irq(&phba->hbalock);
+ spin_lock_irq(&phba->port_list_lock);
list_del_init(&vport->listentry);
- spin_unlock_irq(&phba->hbalock);
+ spin_unlock_irq(&phba->port_list_lock);
lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT,
"1828 Vport Deleted.\n");
scsi_host_put(shost);
@@ -844,7 +844,7 @@ lpfc_create_vport_work_array(struct lpfc_hba *phba)
GFP_KERNEL);
if (vports == NULL)
return NULL;
- spin_lock_irq(&phba->hbalock);
+ spin_lock_irq(&phba->port_list_lock);
list_for_each_entry(port_iterator, &phba->port_list, listentry) {
if (port_iterator->load_flag & FC_UNLOADING)
continue;
@@ -856,7 +856,7 @@ lpfc_create_vport_work_array(struct lpfc_hba *phba)
}
vports[index++] = port_iterator;
}
- spin_unlock_irq(&phba->hbalock);
+ spin_unlock_irq(&phba->port_list_lock);
return vports;
}
diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c
index eb551f3cc471..764d320bb2ca 100644
--- a/drivers/scsi/mac_esp.c
+++ b/drivers/scsi/mac_esp.c
@@ -52,14 +52,12 @@ struct mac_esp_priv {
struct esp *esp;
void __iomem *pdma_regs;
void __iomem *pdma_io;
- int error;
};
static struct esp *esp_chips[2];
static DEFINE_SPINLOCK(esp_chips_lock);
#define MAC_ESP_GET_PRIV(esp) ((struct mac_esp_priv *) \
- platform_get_drvdata((struct platform_device *) \
- (esp->dev)))
+ dev_get_drvdata((esp)->dev))
static inline void mac_esp_write8(struct esp *esp, u8 val, unsigned long reg)
{
@@ -71,38 +69,6 @@ static inline u8 mac_esp_read8(struct esp *esp, unsigned long reg)
return nubus_readb(esp->regs + reg * 16);
}
-/* For pseudo DMA and PIO we need the virtual address
- * so this address mapping is the identity mapping.
- */
-
-static dma_addr_t mac_esp_map_single(struct esp *esp, void *buf,
- size_t sz, int dir)
-{
- return (dma_addr_t)buf;
-}
-
-static int mac_esp_map_sg(struct esp *esp, struct scatterlist *sg,
- int num_sg, int dir)
-{
- int i;
-
- for (i = 0; i < num_sg; i++)
- sg[i].dma_address = (u32)sg_virt(&sg[i]);
- return num_sg;
-}
-
-static void mac_esp_unmap_single(struct esp *esp, dma_addr_t addr,
- size_t sz, int dir)
-{
- /* Nothing to do. */
-}
-
-static void mac_esp_unmap_sg(struct esp *esp, struct scatterlist *sg,
- int num_sg, int dir)
-{
- /* Nothing to do. */
-}
-
static void mac_esp_reset_dma(struct esp *esp)
{
/* Nothing to do. */
@@ -120,12 +86,11 @@ static void mac_esp_dma_invalidate(struct esp *esp)
static int mac_esp_dma_error(struct esp *esp)
{
- return MAC_ESP_GET_PRIV(esp)->error;
+ return esp->send_cmd_error;
}
static inline int mac_esp_wait_for_empty_fifo(struct esp *esp)
{
- struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp);
int i = 500000;
do {
@@ -140,7 +105,7 @@ static inline int mac_esp_wait_for_empty_fifo(struct esp *esp)
printk(KERN_ERR PFX "FIFO is not empty (sreg %02x)\n",
esp_read8(ESP_STATUS));
- mep->error = 1;
+ esp->send_cmd_error = 1;
return 1;
}
@@ -166,7 +131,7 @@ static inline int mac_esp_wait_for_dreq(struct esp *esp)
printk(KERN_ERR PFX "PDMA timeout (sreg %02x)\n",
esp_read8(ESP_STATUS));
- mep->error = 1;
+ esp->send_cmd_error = 1;
return 1;
}
@@ -233,7 +198,7 @@ static void mac_esp_send_pdma_cmd(struct esp *esp, u32 addr, u32 esp_count,
{
struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp);
- mep->error = 0;
+ esp->send_cmd_error = 0;
if (!write)
scsi_esp_cmd(esp, ESP_CMD_FLUSH);
@@ -271,164 +236,6 @@ static void mac_esp_send_pdma_cmd(struct esp *esp, u32 addr, u32 esp_count,
} while (esp_count);
}
-/*
- * Programmed IO routines follow.
- */
-
-static inline unsigned int mac_esp_wait_for_fifo(struct esp *esp)
-{
- int i = 500000;
-
- do {
- unsigned int fbytes = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES;
-
- if (fbytes)
- return fbytes;
-
- udelay(2);
- } while (--i);
-
- printk(KERN_ERR PFX "FIFO is empty (sreg %02x)\n",
- esp_read8(ESP_STATUS));
- return 0;
-}
-
-static inline int mac_esp_wait_for_intr(struct esp *esp)
-{
- struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp);
- int i = 500000;
-
- do {
- esp->sreg = esp_read8(ESP_STATUS);
- if (esp->sreg & ESP_STAT_INTR)
- return 0;
-
- udelay(2);
- } while (--i);
-
- printk(KERN_ERR PFX "IRQ timeout (sreg %02x)\n", esp->sreg);
- mep->error = 1;
- return 1;
-}
-
-#define MAC_ESP_PIO_LOOP(operands, reg1) \
- asm volatile ( \
- "1: moveb " operands " \n" \
- " subqw #1,%1 \n" \
- " jbne 1b \n" \
- : "+a" (addr), "+r" (reg1) \
- : "a" (fifo))
-
-#define MAC_ESP_PIO_FILL(operands, reg1) \
- asm volatile ( \
- " moveb " operands " \n" \
- " moveb " operands " \n" \
- " moveb " operands " \n" \
- " moveb " operands " \n" \
- " moveb " operands " \n" \
- " moveb " operands " \n" \
- " moveb " operands " \n" \
- " moveb " operands " \n" \
- " moveb " operands " \n" \
- " moveb " operands " \n" \
- " moveb " operands " \n" \
- " moveb " operands " \n" \
- " moveb " operands " \n" \
- " moveb " operands " \n" \
- " moveb " operands " \n" \
- " moveb " operands " \n" \
- " subqw #8,%1 \n" \
- " subqw #8,%1 \n" \
- : "+a" (addr), "+r" (reg1) \
- : "a" (fifo))
-
-#define MAC_ESP_FIFO_SIZE 16
-
-static void mac_esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count,
- u32 dma_count, int write, u8 cmd)
-{
- struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp);
- u8 __iomem *fifo = esp->regs + ESP_FDATA * 16;
- u8 phase = esp->sreg & ESP_STAT_PMASK;
-
- cmd &= ~ESP_CMD_DMA;
- mep->error = 0;
-
- if (write) {
- u8 *dst = (u8 *)addr;
- u8 mask = ~(phase == ESP_MIP ? ESP_INTR_FDONE : ESP_INTR_BSERV);
-
- scsi_esp_cmd(esp, cmd);
-
- while (1) {
- if (!mac_esp_wait_for_fifo(esp))
- break;
-
- *dst++ = esp_read8(ESP_FDATA);
- --esp_count;
-
- if (!esp_count)
- break;
-
- if (mac_esp_wait_for_intr(esp))
- break;
-
- if ((esp->sreg & ESP_STAT_PMASK) != phase)
- break;
-
- esp->ireg = esp_read8(ESP_INTRPT);
- if (esp->ireg & mask) {
- mep->error = 1;
- break;
- }
-
- if (phase == ESP_MIP)
- scsi_esp_cmd(esp, ESP_CMD_MOK);
-
- scsi_esp_cmd(esp, ESP_CMD_TI);
- }
- } else {
- scsi_esp_cmd(esp, ESP_CMD_FLUSH);
-
- if (esp_count >= MAC_ESP_FIFO_SIZE)
- MAC_ESP_PIO_FILL("%0@+,%2@", esp_count);
- else
- MAC_ESP_PIO_LOOP("%0@+,%2@", esp_count);
-
- scsi_esp_cmd(esp, cmd);
-
- while (esp_count) {
- unsigned int n;
-
- if (mac_esp_wait_for_intr(esp))
- break;
-
- if ((esp->sreg & ESP_STAT_PMASK) != phase)
- break;
-
- esp->ireg = esp_read8(ESP_INTRPT);
- if (esp->ireg & ~ESP_INTR_BSERV) {
- mep->error = 1;
- break;
- }
-
- n = MAC_ESP_FIFO_SIZE -
- (esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES);
- if (n > esp_count)
- n = esp_count;
-
- if (n == MAC_ESP_FIFO_SIZE) {
- MAC_ESP_PIO_FILL("%0@+,%2@", esp_count);
- } else {
- esp_count -= n;
- MAC_ESP_PIO_LOOP("%0@+,%2@", n);
- }
-
- scsi_esp_cmd(esp, ESP_CMD_TI);
- }
- }
-}
-
static int mac_esp_irq_pending(struct esp *esp)
{
if (esp_read8(ESP_STATUS) & ESP_STAT_INTR)
@@ -470,10 +277,6 @@ static irqreturn_t mac_scsi_esp_intr(int irq, void *dev_id)
static struct esp_driver_ops mac_esp_ops = {
.esp_write8 = mac_esp_write8,
.esp_read8 = mac_esp_read8,
- .map_single = mac_esp_map_single,
- .map_sg = mac_esp_map_sg,
- .unmap_single = mac_esp_unmap_single,
- .unmap_sg = mac_esp_unmap_sg,
.irq_pending = mac_esp_irq_pending,
.dma_length_limit = mac_esp_dma_length_limit,
.reset_dma = mac_esp_reset_dma,
@@ -508,7 +311,7 @@ static int esp_mac_probe(struct platform_device *dev)
esp = shost_priv(host);
esp->host = host;
- esp->dev = dev;
+ esp->dev = &dev->dev;
esp->command_block = kzalloc(16, GFP_KERNEL);
if (!esp->command_block)
@@ -551,14 +354,16 @@ static int esp_mac_probe(struct platform_device *dev)
mep->pdma_regs = NULL;
break;
}
+ esp->fifo_reg = esp->regs + ESP_FDATA * 16;
esp->ops = &mac_esp_ops;
+ esp->flags = ESP_FLAG_NO_DMA_MAP;
if (mep->pdma_io == NULL) {
printk(KERN_INFO PFX "using PIO for controller %d\n", dev->id);
esp_write8(0, ESP_TCLOW);
esp_write8(0, ESP_TCMED);
- esp->flags = ESP_FLAG_DISABLE_SYNC;
- mac_esp_ops.send_dma_cmd = mac_esp_send_pio_cmd;
+ esp->flags |= ESP_FLAG_DISABLE_SYNC;
+ mac_esp_ops.send_dma_cmd = esp_send_pio_cmd;
} else {
printk(KERN_INFO PFX "using PDMA for controller %d\n", dev->id);
}
@@ -577,7 +382,7 @@ static int esp_mac_probe(struct platform_device *dev)
esp_chips[dev->id] = esp;
spin_unlock(&esp_chips_lock);
- err = scsi_esp_register(esp, &dev->dev);
+ err = scsi_esp_register(esp);
if (err)
goto fail_free_irq;
diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c
index 530358cdcb39..3b7abe5ca7f5 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.c
+++ b/drivers/scsi/megaraid/megaraid_mbox.c
@@ -202,13 +202,6 @@ module_param_named(debug_level, mraid_debug_level, int, 0);
MODULE_PARM_DESC(debug_level, "Debug level for driver (default=0)");
/*
- * ### global data ###
- */
-static uint8_t megaraid_mbox_version[8] =
- { 0x02, 0x20, 0x04, 0x06, 3, 7, 20, 5 };
-
-
-/*
* PCI table for all supported controllers.
*/
static struct pci_device_id pci_id_table_g[] = {
@@ -457,10 +450,9 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
// Setup the default DMA mask. This would be changed later on
// depending on hardware capabilities
- if (pci_set_dma_mask(adapter->pdev, DMA_BIT_MASK(32)) != 0) {
-
+ if (dma_set_mask(&adapter->pdev->dev, DMA_BIT_MASK(32))) {
con_log(CL_ANN, (KERN_WARNING
- "megaraid: pci_set_dma_mask failed:%d\n", __LINE__));
+ "megaraid: dma_set_mask failed:%d\n", __LINE__));
goto out_free_adapter;
}
@@ -484,7 +476,7 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
// Start the mailbox based controller
if (megaraid_init_mbox(adapter) != 0) {
con_log(CL_ANN, (KERN_WARNING
- "megaraid: maibox adapter did not initialize\n"));
+ "megaraid: mailbox adapter did not initialize\n"));
goto out_free_adapter;
}
@@ -878,11 +870,12 @@ megaraid_init_mbox(adapter_t *adapter)
adapter->pdev->device == PCI_DEVICE_ID_PERC4_DI_EVERGLADES) ||
(adapter->pdev->vendor == PCI_VENDOR_ID_DELL &&
adapter->pdev->device == PCI_DEVICE_ID_PERC4E_DI_KOBUK)) {
- if (pci_set_dma_mask(adapter->pdev, DMA_BIT_MASK(64))) {
+ if (dma_set_mask(&adapter->pdev->dev, DMA_BIT_MASK(64))) {
con_log(CL_ANN, (KERN_WARNING
"megaraid: DMA mask for 64-bit failed\n"));
- if (pci_set_dma_mask (adapter->pdev, DMA_BIT_MASK(32))) {
+ if (dma_set_mask(&adapter->pdev->dev,
+ DMA_BIT_MASK(32))) {
con_log(CL_ANN, (KERN_WARNING
"megaraid: 32-bit DMA mask failed\n"));
goto out_free_sysfs_res;
@@ -950,7 +943,7 @@ megaraid_fini_mbox(adapter_t *adapter)
* megaraid_alloc_cmd_packets - allocate shared mailbox
* @adapter : soft state of the raid controller
*
- * Allocate and align the shared mailbox. This maibox is used to issue
+ * Allocate and align the shared mailbox. This mailbox is used to issue
* all the commands. For IO based controllers, the mailbox is also registered
* with the FW. Allocate memory for all commands as well.
* This is our big allocator.
@@ -975,9 +968,9 @@ megaraid_alloc_cmd_packets(adapter_t *adapter)
* Allocate the common 16-byte aligned memory for the handshake
* mailbox.
*/
- raid_dev->una_mbox64 = pci_zalloc_consistent(adapter->pdev,
- sizeof(mbox64_t),
- &raid_dev->una_mbox64_dma);
+ raid_dev->una_mbox64 = dma_zalloc_coherent(&adapter->pdev->dev,
+ sizeof(mbox64_t), &raid_dev->una_mbox64_dma,
+ GFP_KERNEL);
if (!raid_dev->una_mbox64) {
con_log(CL_ANN, (KERN_WARNING
@@ -1003,8 +996,8 @@ megaraid_alloc_cmd_packets(adapter_t *adapter)
align;
// Allocate memory for commands issued internally
- adapter->ibuf = pci_zalloc_consistent(pdev, MBOX_IBUF_SIZE,
- &adapter->ibuf_dma_h);
+ adapter->ibuf = dma_zalloc_coherent(&pdev->dev, MBOX_IBUF_SIZE,
+ &adapter->ibuf_dma_h, GFP_KERNEL);
if (!adapter->ibuf) {
con_log(CL_ANN, (KERN_WARNING
@@ -1082,7 +1075,7 @@ megaraid_alloc_cmd_packets(adapter_t *adapter)
scb->scp = NULL;
scb->state = SCB_FREE;
- scb->dma_direction = PCI_DMA_NONE;
+ scb->dma_direction = DMA_NONE;
scb->dma_type = MRAID_DMA_NONE;
scb->dev_channel = -1;
scb->dev_target = -1;
@@ -1098,10 +1091,10 @@ out_teardown_dma_pools:
out_free_scb_list:
kfree(adapter->kscb_list);
out_free_ibuf:
- pci_free_consistent(pdev, MBOX_IBUF_SIZE, (void *)adapter->ibuf,
+ dma_free_coherent(&pdev->dev, MBOX_IBUF_SIZE, (void *)adapter->ibuf,
adapter->ibuf_dma_h);
out_free_common_mbox:
- pci_free_consistent(adapter->pdev, sizeof(mbox64_t),
+ dma_free_coherent(&adapter->pdev->dev, sizeof(mbox64_t),
(caddr_t)raid_dev->una_mbox64, raid_dev->una_mbox64_dma);
return -1;
@@ -1123,10 +1116,10 @@ megaraid_free_cmd_packets(adapter_t *adapter)
kfree(adapter->kscb_list);
- pci_free_consistent(adapter->pdev, MBOX_IBUF_SIZE,
+ dma_free_coherent(&adapter->pdev->dev, MBOX_IBUF_SIZE,
(void *)adapter->ibuf, adapter->ibuf_dma_h);
- pci_free_consistent(adapter->pdev, sizeof(mbox64_t),
+ dma_free_coherent(&adapter->pdev->dev, sizeof(mbox64_t),
(caddr_t)raid_dev->una_mbox64, raid_dev->una_mbox64_dma);
return;
}
@@ -1428,12 +1421,6 @@ mbox_post_cmd(adapter_t *adapter, scb_t *scb)
adapter->outstanding_cmds++;
- if (scb->dma_direction == PCI_DMA_TODEVICE)
- pci_dma_sync_sg_for_device(adapter->pdev,
- scsi_sglist(scb->scp),
- scsi_sg_count(scb->scp),
- PCI_DMA_TODEVICE);
-
mbox->busy = 1; // Set busy
mbox->poll = 0;
mbox->ack = 0;
@@ -2181,31 +2168,6 @@ megaraid_isr(int irq, void *devp)
/**
- * megaraid_mbox_sync_scb - sync kernel buffers
- * @adapter : controller's soft state
- * @scb : pointer to the resource packet
- *
- * DMA sync if required.
- */
-static void
-megaraid_mbox_sync_scb(adapter_t *adapter, scb_t *scb)
-{
- mbox_ccb_t *ccb;
-
- ccb = (mbox_ccb_t *)scb->ccb;
-
- if (scb->dma_direction == PCI_DMA_FROMDEVICE)
- pci_dma_sync_sg_for_cpu(adapter->pdev,
- scsi_sglist(scb->scp),
- scsi_sg_count(scb->scp),
- PCI_DMA_FROMDEVICE);
-
- scsi_dma_unmap(scb->scp);
- return;
-}
-
-
-/**
* megaraid_mbox_dpc - the tasklet to complete the commands from completed list
* @devp : pointer to HBA soft state
*
@@ -2403,9 +2365,7 @@ megaraid_mbox_dpc(unsigned long devp)
megaraid_mbox_display_scb(adapter, scb);
}
- // Free our internal resources and call the mid-layer callback
- // routine
- megaraid_mbox_sync_scb(adapter, scb);
+ scsi_dma_unmap(scp);
// remove from local clist
list_del_init(&scb->list);
@@ -2577,7 +2537,6 @@ megaraid_reset_handler(struct scsi_cmnd *scp)
uint8_t raw_mbox[sizeof(mbox_t)];
int rval;
int recovery_window;
- int recovering;
int i;
uioc_t *kioc;
@@ -2591,7 +2550,6 @@ megaraid_reset_handler(struct scsi_cmnd *scp)
return FAILED;
}
-
// Under exceptional conditions, FW can take up to 3 minutes to
// complete command processing. Wait for additional 2 minutes for the
// pending commands counter to go down to 0. If it doesn't, let the
@@ -2640,8 +2598,6 @@ megaraid_reset_handler(struct scsi_cmnd *scp)
recovery_window = MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT;
- recovering = adapter->outstanding_cmds;
-
for (i = 0; i < recovery_window; i++) {
megaraid_ack_sequence(adapter);
@@ -2725,13 +2681,10 @@ static int
mbox_post_sync_cmd(adapter_t *adapter, uint8_t raw_mbox[])
{
mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter);
- mbox64_t *mbox64;
mbox_t *mbox;
uint8_t status;
int i;
-
- mbox64 = raid_dev->mbox64;
mbox = raid_dev->mbox;
/*
@@ -2948,9 +2901,8 @@ megaraid_mbox_product_info(adapter_t *adapter)
* Issue an ENQUIRY3 command to find out certain adapter parameters,
* e.g., max channels, max commands etc.
*/
- pinfo = pci_zalloc_consistent(adapter->pdev, sizeof(mraid_pinfo_t),
- &pinfo_dma_h);
-
+ pinfo = dma_zalloc_coherent(&adapter->pdev->dev, sizeof(mraid_pinfo_t),
+ &pinfo_dma_h, GFP_KERNEL);
if (pinfo == NULL) {
con_log(CL_ANN, (KERN_WARNING
"megaraid: out of memory, %s %d\n", __func__,
@@ -2971,7 +2923,7 @@ megaraid_mbox_product_info(adapter_t *adapter)
con_log(CL_ANN, (KERN_WARNING "megaraid: Inquiry3 failed\n"));
- pci_free_consistent(adapter->pdev, sizeof(mraid_pinfo_t),
+ dma_free_coherent(&adapter->pdev->dev, sizeof(mraid_pinfo_t),
pinfo, pinfo_dma_h);
return -1;
@@ -3002,7 +2954,7 @@ megaraid_mbox_product_info(adapter_t *adapter)
con_log(CL_ANN, (KERN_WARNING
"megaraid: product info failed\n"));
- pci_free_consistent(adapter->pdev, sizeof(mraid_pinfo_t),
+ dma_free_coherent(&adapter->pdev->dev, sizeof(mraid_pinfo_t),
pinfo, pinfo_dma_h);
return -1;
@@ -3038,7 +2990,7 @@ megaraid_mbox_product_info(adapter_t *adapter)
"megaraid: fw version:[%s] bios version:[%s]\n",
adapter->fw_version, adapter->bios_version));
- pci_free_consistent(adapter->pdev, sizeof(mraid_pinfo_t), pinfo,
+ dma_free_coherent(&adapter->pdev->dev, sizeof(mraid_pinfo_t), pinfo,
pinfo_dma_h);
return 0;
@@ -3135,7 +3087,6 @@ megaraid_mbox_support_ha(adapter_t *adapter, uint16_t *init_id)
static int
megaraid_mbox_support_random_del(adapter_t *adapter)
{
- mbox_t *mbox;
uint8_t raw_mbox[sizeof(mbox_t)];
int rval;
@@ -3157,8 +3108,6 @@ megaraid_mbox_support_random_del(adapter_t *adapter)
return 0;
}
- mbox = (mbox_t *)raw_mbox;
-
memset((caddr_t)raw_mbox, 0, sizeof(mbox_t));
raw_mbox[0] = FC_DEL_LOGDRV;
@@ -3263,12 +3212,8 @@ megaraid_mbox_enum_raid_scsi(adapter_t *adapter)
static void
megaraid_mbox_flush_cache(adapter_t *adapter)
{
- mbox_t *mbox;
uint8_t raw_mbox[sizeof(mbox_t)];
-
- mbox = (mbox_t *)raw_mbox;
-
memset((caddr_t)raw_mbox, 0, sizeof(mbox_t));
raw_mbox[0] = FLUSH_ADAPTER;
@@ -3299,7 +3244,6 @@ megaraid_mbox_fire_sync_cmd(adapter_t *adapter)
mbox_t *mbox;
uint8_t raw_mbox[sizeof(mbox_t)];
mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter);
- mbox64_t *mbox64;
int status = 0;
int i;
uint32_t dword;
@@ -3310,7 +3254,6 @@ megaraid_mbox_fire_sync_cmd(adapter_t *adapter)
raw_mbox[0] = 0xFF;
- mbox64 = raid_dev->mbox64;
mbox = raid_dev->mbox;
/* Wait until mailbox is free */
@@ -3515,7 +3458,7 @@ megaraid_cmm_register(adapter_t *adapter)
scb->scp = NULL;
scb->state = SCB_FREE;
- scb->dma_direction = PCI_DMA_NONE;
+ scb->dma_direction = DMA_NONE;
scb->dma_type = MRAID_DMA_NONE;
scb->dev_channel = -1;
scb->dev_target = -1;
@@ -3653,7 +3596,7 @@ megaraid_mbox_mm_command(adapter_t *adapter, uioc_t *kioc)
scb->state = SCB_ACTIVE;
scb->dma_type = MRAID_DMA_NONE;
- scb->dma_direction = PCI_DMA_NONE;
+ scb->dma_direction = DMA_NONE;
ccb = (mbox_ccb_t *)scb->ccb;
mbox64 = (mbox64_t *)(unsigned long)kioc->cmdbuf;
@@ -3794,10 +3737,6 @@ megaraid_mbox_mm_done(adapter_t *adapter, scb_t *scb)
static int
gather_hbainfo(adapter_t *adapter, mraid_hba_info_t *hinfo)
{
- uint8_t dmajor;
-
- dmajor = megaraid_mbox_version[0];
-
hinfo->pci_vendor_id = adapter->pdev->vendor;
hinfo->pci_device_id = adapter->pdev->device;
hinfo->subsys_vendor_id = adapter->pdev->subsystem_vendor;
@@ -3843,8 +3782,8 @@ megaraid_sysfs_alloc_resources(adapter_t *adapter)
raid_dev->sysfs_mbox64 = kmalloc(sizeof(mbox64_t), GFP_KERNEL);
- raid_dev->sysfs_buffer = pci_alloc_consistent(adapter->pdev,
- PAGE_SIZE, &raid_dev->sysfs_buffer_dma);
+ raid_dev->sysfs_buffer = dma_alloc_coherent(&adapter->pdev->dev,
+ PAGE_SIZE, &raid_dev->sysfs_buffer_dma, GFP_KERNEL);
if (!raid_dev->sysfs_uioc || !raid_dev->sysfs_mbox64 ||
!raid_dev->sysfs_buffer) {
@@ -3881,7 +3820,7 @@ megaraid_sysfs_free_resources(adapter_t *adapter)
kfree(raid_dev->sysfs_mbox64);
if (raid_dev->sysfs_buffer) {
- pci_free_consistent(adapter->pdev, PAGE_SIZE,
+ dma_free_coherent(&adapter->pdev->dev, PAGE_SIZE,
raid_dev->sysfs_buffer, raid_dev->sysfs_buffer_dma);
}
}
diff --git a/drivers/scsi/megaraid/megaraid_mbox.h b/drivers/scsi/megaraid/megaraid_mbox.h
index c1d86d961a92..e075aeb4012f 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.h
+++ b/drivers/scsi/megaraid/megaraid_mbox.h
@@ -117,7 +117,7 @@
* @raw_mbox : raw mailbox pointer
* @mbox : mailbox
* @mbox64 : extended mailbox
- * @mbox_dma_h : maibox dma address
+ * @mbox_dma_h : mailbox dma address
* @sgl64 : 64-bit scatter-gather list
* @sgl32 : 32-bit scatter-gather list
* @sgl_dma_h : dma handle for the scatter-gather list
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index 9aa9590c5373..9b90c716f06d 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -1330,11 +1330,11 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
device_id = MEGASAS_DEV_INDEX(scp);
pthru = (struct megasas_pthru_frame *)cmd->frame;
- if (scp->sc_data_direction == PCI_DMA_TODEVICE)
+ if (scp->sc_data_direction == DMA_TO_DEVICE)
flags = MFI_FRAME_DIR_WRITE;
- else if (scp->sc_data_direction == PCI_DMA_FROMDEVICE)
+ else if (scp->sc_data_direction == DMA_FROM_DEVICE)
flags = MFI_FRAME_DIR_READ;
- else if (scp->sc_data_direction == PCI_DMA_NONE)
+ else if (scp->sc_data_direction == DMA_NONE)
flags = MFI_FRAME_DIR_NONE;
if (instance->flag_ieee == 1) {
@@ -1428,9 +1428,9 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
device_id = MEGASAS_DEV_INDEX(scp);
ldio = (struct megasas_io_frame *)cmd->frame;
- if (scp->sc_data_direction == PCI_DMA_TODEVICE)
+ if (scp->sc_data_direction == DMA_TO_DEVICE)
flags = MFI_FRAME_DIR_WRITE;
- else if (scp->sc_data_direction == PCI_DMA_FROMDEVICE)
+ else if (scp->sc_data_direction == DMA_FROM_DEVICE)
flags = MFI_FRAME_DIR_READ;
if (instance->flag_ieee == 1) {
@@ -2240,9 +2240,9 @@ static int megasas_get_ld_vf_affiliation_111(struct megasas_instance *instance,
sizeof(struct MR_LD_VF_AFFILIATION_111));
else {
new_affiliation_111 =
- pci_zalloc_consistent(instance->pdev,
+ dma_zalloc_coherent(&instance->pdev->dev,
sizeof(struct MR_LD_VF_AFFILIATION_111),
- &new_affiliation_111_h);
+ &new_affiliation_111_h, GFP_KERNEL);
if (!new_affiliation_111) {
dev_printk(KERN_DEBUG, &instance->pdev->dev, "SR-IOV: Couldn't allocate "
"memory for new affiliation for scsi%d\n",
@@ -2302,7 +2302,7 @@ static int megasas_get_ld_vf_affiliation_111(struct megasas_instance *instance,
}
out:
if (new_affiliation_111) {
- pci_free_consistent(instance->pdev,
+ dma_free_coherent(&instance->pdev->dev,
sizeof(struct MR_LD_VF_AFFILIATION_111),
new_affiliation_111,
new_affiliation_111_h);
@@ -2347,10 +2347,10 @@ static int megasas_get_ld_vf_affiliation_12(struct megasas_instance *instance,
sizeof(struct MR_LD_VF_AFFILIATION));
else {
new_affiliation =
- pci_zalloc_consistent(instance->pdev,
+ dma_zalloc_coherent(&instance->pdev->dev,
(MAX_LOGICAL_DRIVES + 1) *
sizeof(struct MR_LD_VF_AFFILIATION),
- &new_affiliation_h);
+ &new_affiliation_h, GFP_KERNEL);
if (!new_affiliation) {
dev_printk(KERN_DEBUG, &instance->pdev->dev, "SR-IOV: Couldn't allocate "
"memory for new affiliation for scsi%d\n",
@@ -2470,7 +2470,7 @@ out:
}
if (new_affiliation)
- pci_free_consistent(instance->pdev,
+ dma_free_coherent(&instance->pdev->dev,
(MAX_LOGICAL_DRIVES + 1) *
sizeof(struct MR_LD_VF_AFFILIATION),
new_affiliation, new_affiliation_h);
@@ -2513,9 +2513,9 @@ int megasas_sriov_start_heartbeat(struct megasas_instance *instance,
if (initial) {
instance->hb_host_mem =
- pci_zalloc_consistent(instance->pdev,
+ dma_zalloc_coherent(&instance->pdev->dev,
sizeof(struct MR_CTRL_HB_HOST_MEM),
- &instance->hb_host_mem_h);
+ &instance->hb_host_mem_h, GFP_KERNEL);
if (!instance->hb_host_mem) {
dev_printk(KERN_DEBUG, &instance->pdev->dev, "SR-IOV: Couldn't allocate"
" memory for heartbeat host memory for scsi%d\n",
@@ -4995,9 +4995,8 @@ megasas_init_adapter_mfi(struct megasas_instance *instance)
context_sz = sizeof(u32);
reply_q_sz = context_sz * (instance->max_fw_cmds + 1);
- instance->reply_queue = pci_alloc_consistent(instance->pdev,
- reply_q_sz,
- &instance->reply_queue_h);
+ instance->reply_queue = dma_alloc_coherent(&instance->pdev->dev,
+ reply_q_sz, &instance->reply_queue_h, GFP_KERNEL);
if (!instance->reply_queue) {
dev_printk(KERN_DEBUG, &instance->pdev->dev, "Out of DMA mem for reply queue\n");
@@ -5029,7 +5028,7 @@ megasas_init_adapter_mfi(struct megasas_instance *instance)
fail_fw_init:
- pci_free_consistent(instance->pdev, reply_q_sz,
+ dma_free_coherent(&instance->pdev->dev, reply_q_sz,
instance->reply_queue, instance->reply_queue_h);
fail_reply_queue:
megasas_free_cmds(instance);
@@ -5533,7 +5532,7 @@ static int megasas_init_fw(struct megasas_instance *instance)
else {
if (instance->crash_dump_buf)
- pci_free_consistent(instance->pdev,
+ dma_free_coherent(&instance->pdev->dev,
CRASH_DMA_BUF_SIZE,
instance->crash_dump_buf,
instance->crash_dump_h);
@@ -5616,7 +5615,7 @@ static void megasas_release_mfi(struct megasas_instance *instance)
u32 reply_q_sz = sizeof(u32) *(instance->max_mfi_cmds + 1);
if (instance->reply_queue)
- pci_free_consistent(instance->pdev, reply_q_sz,
+ dma_free_coherent(&instance->pdev->dev, reply_q_sz,
instance->reply_queue, instance->reply_queue_h);
megasas_free_cmds(instance);
@@ -5655,10 +5654,9 @@ megasas_get_seq_num(struct megasas_instance *instance,
}
dcmd = &cmd->frame->dcmd;
- el_info = pci_zalloc_consistent(instance->pdev,
- sizeof(struct megasas_evt_log_info),
- &el_info_h);
-
+ el_info = dma_zalloc_coherent(&instance->pdev->dev,
+ sizeof(struct megasas_evt_log_info), &el_info_h,
+ GFP_KERNEL);
if (!el_info) {
megasas_return_cmd(instance, cmd);
return -ENOMEM;
@@ -5695,8 +5693,9 @@ megasas_get_seq_num(struct megasas_instance *instance,
eli->boot_seq_num = el_info->boot_seq_num;
dcmd_failed:
- pci_free_consistent(instance->pdev, sizeof(struct megasas_evt_log_info),
- el_info, el_info_h);
+ dma_free_coherent(&instance->pdev->dev,
+ sizeof(struct megasas_evt_log_info),
+ el_info, el_info_h);
megasas_return_cmd(instance, cmd);
@@ -6134,10 +6133,10 @@ static inline void megasas_set_adapter_type(struct megasas_instance *instance)
static inline int megasas_alloc_mfi_ctrl_mem(struct megasas_instance *instance)
{
- instance->producer = pci_alloc_consistent(instance->pdev, sizeof(u32),
- &instance->producer_h);
- instance->consumer = pci_alloc_consistent(instance->pdev, sizeof(u32),
- &instance->consumer_h);
+ instance->producer = dma_alloc_coherent(&instance->pdev->dev,
+ sizeof(u32), &instance->producer_h, GFP_KERNEL);
+ instance->consumer = dma_alloc_coherent(&instance->pdev->dev,
+ sizeof(u32), &instance->consumer_h, GFP_KERNEL);
if (!instance->producer || !instance->consumer) {
dev_err(&instance->pdev->dev,
@@ -6199,11 +6198,11 @@ static inline void megasas_free_ctrl_mem(struct megasas_instance *instance)
kfree(instance->reply_map);
if (instance->adapter_type == MFI_SERIES) {
if (instance->producer)
- pci_free_consistent(instance->pdev, sizeof(u32),
+ dma_free_coherent(&instance->pdev->dev, sizeof(u32),
instance->producer,
instance->producer_h);
if (instance->consumer)
- pci_free_consistent(instance->pdev, sizeof(u32),
+ dma_free_coherent(&instance->pdev->dev, sizeof(u32),
instance->consumer,
instance->consumer_h);
} else {
@@ -6224,10 +6223,9 @@ int megasas_alloc_ctrl_dma_buffers(struct megasas_instance *instance)
struct pci_dev *pdev = instance->pdev;
struct fusion_context *fusion = instance->ctrl_context;
- instance->evt_detail =
- pci_alloc_consistent(pdev,
- sizeof(struct megasas_evt_detail),
- &instance->evt_detail_h);
+ instance->evt_detail = dma_alloc_coherent(&pdev->dev,
+ sizeof(struct megasas_evt_detail),
+ &instance->evt_detail_h, GFP_KERNEL);
if (!instance->evt_detail) {
dev_err(&instance->pdev->dev,
@@ -6250,9 +6248,9 @@ int megasas_alloc_ctrl_dma_buffers(struct megasas_instance *instance)
}
instance->pd_list_buf =
- pci_alloc_consistent(pdev,
+ dma_alloc_coherent(&pdev->dev,
MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST),
- &instance->pd_list_buf_h);
+ &instance->pd_list_buf_h, GFP_KERNEL);
if (!instance->pd_list_buf) {
dev_err(&pdev->dev, "Failed to allocate PD list buffer\n");
@@ -6260,9 +6258,9 @@ int megasas_alloc_ctrl_dma_buffers(struct megasas_instance *instance)
}
instance->ctrl_info_buf =
- pci_alloc_consistent(pdev,
+ dma_alloc_coherent(&pdev->dev,
sizeof(struct megasas_ctrl_info),
- &instance->ctrl_info_buf_h);
+ &instance->ctrl_info_buf_h, GFP_KERNEL);
if (!instance->ctrl_info_buf) {
dev_err(&pdev->dev,
@@ -6271,9 +6269,9 @@ int megasas_alloc_ctrl_dma_buffers(struct megasas_instance *instance)
}
instance->ld_list_buf =
- pci_alloc_consistent(pdev,
+ dma_alloc_coherent(&pdev->dev,
sizeof(struct MR_LD_LIST),
- &instance->ld_list_buf_h);
+ &instance->ld_list_buf_h, GFP_KERNEL);
if (!instance->ld_list_buf) {
dev_err(&pdev->dev, "Failed to allocate LD list buffer\n");
@@ -6281,9 +6279,9 @@ int megasas_alloc_ctrl_dma_buffers(struct megasas_instance *instance)
}
instance->ld_targetid_list_buf =
- pci_alloc_consistent(pdev,
- sizeof(struct MR_LD_TARGETID_LIST),
- &instance->ld_targetid_list_buf_h);
+ dma_alloc_coherent(&pdev->dev,
+ sizeof(struct MR_LD_TARGETID_LIST),
+ &instance->ld_targetid_list_buf_h, GFP_KERNEL);
if (!instance->ld_targetid_list_buf) {
dev_err(&pdev->dev,
@@ -6293,21 +6291,20 @@ int megasas_alloc_ctrl_dma_buffers(struct megasas_instance *instance)
if (!reset_devices) {
instance->system_info_buf =
- pci_alloc_consistent(pdev,
- sizeof(struct MR_DRV_SYSTEM_INFO),
- &instance->system_info_h);
+ dma_alloc_coherent(&pdev->dev,
+ sizeof(struct MR_DRV_SYSTEM_INFO),
+ &instance->system_info_h, GFP_KERNEL);
instance->pd_info =
- pci_alloc_consistent(pdev,
- sizeof(struct MR_PD_INFO),
- &instance->pd_info_h);
+ dma_alloc_coherent(&pdev->dev,
+ sizeof(struct MR_PD_INFO),
+ &instance->pd_info_h, GFP_KERNEL);
instance->tgt_prop =
- pci_alloc_consistent(pdev,
- sizeof(struct MR_TARGET_PROPERTIES),
- &instance->tgt_prop_h);
+ dma_alloc_coherent(&pdev->dev,
+ sizeof(struct MR_TARGET_PROPERTIES),
+ &instance->tgt_prop_h, GFP_KERNEL);
instance->crash_dump_buf =
- pci_alloc_consistent(pdev,
- CRASH_DMA_BUF_SIZE,
- &instance->crash_dump_h);
+ dma_alloc_coherent(&pdev->dev, CRASH_DMA_BUF_SIZE,
+ &instance->crash_dump_h, GFP_KERNEL);
if (!instance->system_info_buf)
dev_err(&instance->pdev->dev,
@@ -6343,7 +6340,7 @@ void megasas_free_ctrl_dma_buffers(struct megasas_instance *instance)
struct fusion_context *fusion = instance->ctrl_context;
if (instance->evt_detail)
- pci_free_consistent(pdev, sizeof(struct megasas_evt_detail),
+ dma_free_coherent(&pdev->dev, sizeof(struct megasas_evt_detail),
instance->evt_detail,
instance->evt_detail_h);
@@ -6354,41 +6351,41 @@ void megasas_free_ctrl_dma_buffers(struct megasas_instance *instance)
fusion->ioc_init_request_phys);
if (instance->pd_list_buf)
- pci_free_consistent(pdev,
+ dma_free_coherent(&pdev->dev,
MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST),
instance->pd_list_buf,
instance->pd_list_buf_h);
if (instance->ld_list_buf)
- pci_free_consistent(pdev, sizeof(struct MR_LD_LIST),
+ dma_free_coherent(&pdev->dev, sizeof(struct MR_LD_LIST),
instance->ld_list_buf,
instance->ld_list_buf_h);
if (instance->ld_targetid_list_buf)
- pci_free_consistent(pdev, sizeof(struct MR_LD_TARGETID_LIST),
+ dma_free_coherent(&pdev->dev, sizeof(struct MR_LD_TARGETID_LIST),
instance->ld_targetid_list_buf,
instance->ld_targetid_list_buf_h);
if (instance->ctrl_info_buf)
- pci_free_consistent(pdev, sizeof(struct megasas_ctrl_info),
+ dma_free_coherent(&pdev->dev, sizeof(struct megasas_ctrl_info),
instance->ctrl_info_buf,
instance->ctrl_info_buf_h);
if (instance->system_info_buf)
- pci_free_consistent(pdev, sizeof(struct MR_DRV_SYSTEM_INFO),
+ dma_free_coherent(&pdev->dev, sizeof(struct MR_DRV_SYSTEM_INFO),
instance->system_info_buf,
instance->system_info_h);
if (instance->pd_info)
- pci_free_consistent(pdev, sizeof(struct MR_PD_INFO),
+ dma_free_coherent(&pdev->dev, sizeof(struct MR_PD_INFO),
instance->pd_info, instance->pd_info_h);
if (instance->tgt_prop)
- pci_free_consistent(pdev, sizeof(struct MR_TARGET_PROPERTIES),
+ dma_free_coherent(&pdev->dev, sizeof(struct MR_TARGET_PROPERTIES),
instance->tgt_prop, instance->tgt_prop_h);
if (instance->crash_dump_buf)
- pci_free_consistent(pdev, CRASH_DMA_BUF_SIZE,
+ dma_free_coherent(&pdev->dev, CRASH_DMA_BUF_SIZE,
instance->crash_dump_buf,
instance->crash_dump_h);
}
@@ -6516,17 +6513,20 @@ static int megasas_probe_one(struct pci_dev *pdev,
if (instance->requestorId) {
if (instance->PlasmaFW111) {
instance->vf_affiliation_111 =
- pci_alloc_consistent(pdev, sizeof(struct MR_LD_VF_AFFILIATION_111),
- &instance->vf_affiliation_111_h);
+ dma_alloc_coherent(&pdev->dev,
+ sizeof(struct MR_LD_VF_AFFILIATION_111),
+ &instance->vf_affiliation_111_h,
+ GFP_KERNEL);
if (!instance->vf_affiliation_111)
dev_warn(&pdev->dev, "Can't allocate "
"memory for VF affiliation buffer\n");
} else {
instance->vf_affiliation =
- pci_alloc_consistent(pdev,
- (MAX_LOGICAL_DRIVES + 1) *
- sizeof(struct MR_LD_VF_AFFILIATION),
- &instance->vf_affiliation_h);
+ dma_alloc_coherent(&pdev->dev,
+ (MAX_LOGICAL_DRIVES + 1) *
+ sizeof(struct MR_LD_VF_AFFILIATION),
+ &instance->vf_affiliation_h,
+ GFP_KERNEL);
if (!instance->vf_affiliation)
dev_warn(&pdev->dev, "Can't allocate "
"memory for VF affiliation buffer\n");
@@ -6994,19 +6994,19 @@ skip_firing_dcmds:
}
if (instance->vf_affiliation)
- pci_free_consistent(pdev, (MAX_LOGICAL_DRIVES + 1) *
+ dma_free_coherent(&pdev->dev, (MAX_LOGICAL_DRIVES + 1) *
sizeof(struct MR_LD_VF_AFFILIATION),
instance->vf_affiliation,
instance->vf_affiliation_h);
if (instance->vf_affiliation_111)
- pci_free_consistent(pdev,
+ dma_free_coherent(&pdev->dev,
sizeof(struct MR_LD_VF_AFFILIATION_111),
instance->vf_affiliation_111,
instance->vf_affiliation_111_h);
if (instance->hb_host_mem)
- pci_free_consistent(pdev, sizeof(struct MR_CTRL_HB_HOST_MEM),
+ dma_free_coherent(&pdev->dev, sizeof(struct MR_CTRL_HB_HOST_MEM),
instance->hb_host_mem,
instance->hb_host_mem_h);
@@ -7254,7 +7254,7 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
/*
* We don't change the dma_coherent_mask, so
- * pci_alloc_consistent only returns 32bit addresses
+ * dma_alloc_coherent only returns 32bit addresses
*/
if (instance->consistent_mask_64bit) {
kern_sge64[i].phys_addr = cpu_to_le64(buf_handle);
@@ -7523,6 +7523,9 @@ static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg)
get_user(user_sense_off, &cioc->sense_off))
return -EFAULT;
+ if (local_sense_off != user_sense_off)
+ return -EINVAL;
+
if (local_sense_len) {
void __user **sense_ioc_ptr =
(void __user **)((u8 *)((unsigned long)&ioc->frame.raw) + local_sense_off);
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
index c7f95bace353..f74b5ea24f0f 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
@@ -684,8 +684,8 @@ megasas_alloc_rdpq_fusion(struct megasas_instance *instance)
array_size = sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) *
MAX_MSIX_QUEUES_FUSION;
- fusion->rdpq_virt = pci_zalloc_consistent(instance->pdev, array_size,
- &fusion->rdpq_phys);
+ fusion->rdpq_virt = dma_zalloc_coherent(&instance->pdev->dev,
+ array_size, &fusion->rdpq_phys, GFP_KERNEL);
if (!fusion->rdpq_virt) {
dev_err(&instance->pdev->dev,
"Failed from %s %d\n", __func__, __LINE__);
@@ -813,7 +813,7 @@ megasas_free_rdpq_fusion(struct megasas_instance *instance) {
dma_pool_destroy(fusion->reply_frames_desc_pool_align);
if (fusion->rdpq_virt)
- pci_free_consistent(instance->pdev,
+ dma_free_coherent(&instance->pdev->dev,
sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * MAX_MSIX_QUEUES_FUSION,
fusion->rdpq_virt, fusion->rdpq_phys);
}
@@ -2209,7 +2209,7 @@ megasas_set_pd_lba(struct MPI2_RAID_SCSI_IO_REQUEST *io_request, u8 cdb_len,
cdb[0] = MEGASAS_SCSI_VARIABLE_LENGTH_CMD;
cdb[7] = MEGASAS_SCSI_ADDL_CDB_LEN;
- if (scp->sc_data_direction == PCI_DMA_FROMDEVICE)
+ if (scp->sc_data_direction == DMA_FROM_DEVICE)
cdb[9] = MEGASAS_SCSI_SERVICE_ACTION_READ32;
else
cdb[9] = MEGASAS_SCSI_SERVICE_ACTION_WRITE32;
@@ -2238,7 +2238,7 @@ megasas_set_pd_lba(struct MPI2_RAID_SCSI_IO_REQUEST *io_request, u8 cdb_len,
cdb[31] = (u8)(num_blocks & 0xff);
/* set SCSI IO EEDPFlags */
- if (scp->sc_data_direction == PCI_DMA_FROMDEVICE) {
+ if (scp->sc_data_direction == DMA_FROM_DEVICE) {
io_request->EEDPFlags = cpu_to_le16(
MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
@@ -2621,7 +2621,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
scsi_buff_len = scsi_bufflen(scp);
io_request->DataLength = cpu_to_le32(scsi_buff_len);
- if (scp->sc_data_direction == PCI_DMA_FROMDEVICE)
+ if (scp->sc_data_direction == DMA_FROM_DEVICE)
io_info.isRead = 1;
local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)];
@@ -3088,9 +3088,9 @@ megasas_build_io_fusion(struct megasas_instance *instance,
io_request->SGLFlags = cpu_to_le16(MPI2_SGE_FLAGS_64_BIT_ADDRESSING);
- if (scp->sc_data_direction == PCI_DMA_TODEVICE)
+ if (scp->sc_data_direction == DMA_TO_DEVICE)
io_request->Control |= cpu_to_le32(MPI2_SCSIIO_CONTROL_WRITE);
- else if (scp->sc_data_direction == PCI_DMA_FROMDEVICE)
+ else if (scp->sc_data_direction == DMA_FROM_DEVICE)
io_request->Control |= cpu_to_le32(MPI2_SCSIIO_CONTROL_READ);
io_request->SGLOffset0 =
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c
index 82e01dbe90af..ec6940f2fcb3 100644
--- a/drivers/scsi/mesh.c
+++ b/drivers/scsi/mesh.c
@@ -1915,8 +1915,8 @@ static int mesh_probe(struct macio_dev *mdev, const struct of_device_id *match)
/* We use the PCI APIs for now until the generic one gets fixed
* enough or until we get some macio-specific versions
*/
- dma_cmd_space = pci_zalloc_consistent(macio_get_pci_dev(mdev),
- ms->dma_cmd_size, &dma_cmd_bus);
+ dma_cmd_space = dma_zalloc_coherent(&macio_get_pci_dev(mdev)->dev,
+ ms->dma_cmd_size, &dma_cmd_bus, GFP_KERNEL);
if (dma_cmd_space == NULL) {
printk(KERN_ERR "mesh: can't allocate DMA table\n");
goto out_unmap;
@@ -1974,7 +1974,7 @@ static int mesh_probe(struct macio_dev *mdev, const struct of_device_id *match)
*/
mesh_shutdown(mdev);
set_mesh_power(ms, 0);
- pci_free_consistent(macio_get_pci_dev(mdev), ms->dma_cmd_size,
+ dma_free_coherent(&macio_get_pci_dev(mdev)->dev, ms->dma_cmd_size,
ms->dma_cmd_space, ms->dma_cmd_bus);
out_unmap:
iounmap(ms->dma);
@@ -2007,7 +2007,7 @@ static int mesh_remove(struct macio_dev *mdev)
iounmap(ms->dma);
/* Free DMA commands memory */
- pci_free_consistent(macio_get_pci_dev(mdev), ms->dma_cmd_size,
+ dma_free_coherent(&macio_get_pci_dev(mdev)->dev, ms->dma_cmd_size,
ms->dma_cmd_space, ms->dma_cmd_bus);
/* Release memory resources */
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c
index 59d7844ee022..2500377d0723 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.c
@@ -122,8 +122,8 @@ mpt3sas_base_check_cmd_timeout(struct MPT3SAS_ADAPTER *ioc,
if (!(status & MPT3_CMD_RESET))
issue_reset = 1;
- pr_err(MPT3SAS_FMT "Command %s\n", ioc->name,
- ((issue_reset == 0) ? "terminated due to Host Reset" : "Timeout"));
+ ioc_err(ioc, "Command %s\n",
+ issue_reset == 0 ? "terminated due to Host Reset" : "Timeout");
_debug_dump_mf(mpi_request, sz);
return issue_reset;
@@ -336,9 +336,7 @@ _base_get_chain_buffer_dma_to_chain_buffer(struct MPT3SAS_ADAPTER *ioc,
return ct->chain_buffer;
}
}
- pr_info(MPT3SAS_FMT
- "Provided chain_buffer_dma address is not in the lookup list\n",
- ioc->name);
+ ioc_info(ioc, "Provided chain_buffer_dma address is not in the lookup list\n");
return NULL;
}
@@ -394,7 +392,7 @@ static void _clone_sg_entries(struct MPT3SAS_ADAPTER *ioc,
/* Get scsi_cmd using smid */
scmd = mpt3sas_scsih_scsi_lookup_get(ioc, smid);
if (scmd == NULL) {
- pr_err(MPT3SAS_FMT "scmd is NULL\n", ioc->name);
+ ioc_err(ioc, "scmd is NULL\n");
return;
}
@@ -532,11 +530,11 @@ static int mpt3sas_remove_dead_ioc_func(void *arg)
struct MPT3SAS_ADAPTER *ioc = (struct MPT3SAS_ADAPTER *)arg;
struct pci_dev *pdev;
- if ((ioc == NULL))
+ if (!ioc)
return -1;
pdev = ioc->pdev;
- if ((pdev == NULL))
+ if (!pdev)
return -1;
pci_stop_and_remove_bus_device_locked(pdev);
return 0;
@@ -566,8 +564,7 @@ _base_fault_reset_work(struct work_struct *work)
doorbell = mpt3sas_base_get_iocstate(ioc, 0);
if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_MASK) {
- pr_err(MPT3SAS_FMT "SAS host is non-operational !!!!\n",
- ioc->name);
+ ioc_err(ioc, "SAS host is non-operational !!!!\n");
/* It may be possible that EEH recovery can resolve some of
* pci bus failure issues rather removing the dead ioc function
@@ -600,13 +597,11 @@ _base_fault_reset_work(struct work_struct *work)
p = kthread_run(mpt3sas_remove_dead_ioc_func, ioc,
"%s_dead_ioc_%d", ioc->driver_name, ioc->id);
if (IS_ERR(p))
- pr_err(MPT3SAS_FMT
- "%s: Running mpt3sas_dead_ioc thread failed !!!!\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: Running mpt3sas_dead_ioc thread failed !!!!\n",
+ __func__);
else
- pr_err(MPT3SAS_FMT
- "%s: Running mpt3sas_dead_ioc thread success !!!!\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: Running mpt3sas_dead_ioc thread success !!!!\n",
+ __func__);
return; /* don't rearm timer */
}
@@ -614,8 +609,8 @@ _base_fault_reset_work(struct work_struct *work)
if ((doorbell & MPI2_IOC_STATE_MASK) != MPI2_IOC_STATE_OPERATIONAL) {
rc = mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
- pr_warn(MPT3SAS_FMT "%s: hard reset: %s\n", ioc->name,
- __func__, (rc == 0) ? "success" : "failed");
+ ioc_warn(ioc, "%s: hard reset: %s\n",
+ __func__, rc == 0 ? "success" : "failed");
doorbell = mpt3sas_base_get_iocstate(ioc, 0);
if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT)
mpt3sas_base_fault_info(ioc, doorbell &
@@ -657,8 +652,7 @@ mpt3sas_base_start_watchdog(struct MPT3SAS_ADAPTER *ioc)
ioc->fault_reset_work_q =
create_singlethread_workqueue(ioc->fault_reset_work_q_name);
if (!ioc->fault_reset_work_q) {
- pr_err(MPT3SAS_FMT "%s: failed (line=%d)\n",
- ioc->name, __func__, __LINE__);
+ ioc_err(ioc, "%s: failed (line=%d)\n", __func__, __LINE__);
return;
}
spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
@@ -700,8 +694,7 @@ mpt3sas_base_stop_watchdog(struct MPT3SAS_ADAPTER *ioc)
void
mpt3sas_base_fault_info(struct MPT3SAS_ADAPTER *ioc , u16 fault_code)
{
- pr_err(MPT3SAS_FMT "fault_state(0x%04x)!\n",
- ioc->name, fault_code);
+ ioc_err(ioc, "fault_state(0x%04x)!\n", fault_code);
}
/**
@@ -728,8 +721,7 @@ mpt3sas_halt_firmware(struct MPT3SAS_ADAPTER *ioc)
mpt3sas_base_fault_info(ioc , doorbell);
else {
writel(0xC0FFEE00, &ioc->chip->Doorbell);
- pr_err(MPT3SAS_FMT "Firmware is halted due to command timeout\n",
- ioc->name);
+ ioc_err(ioc, "Firmware is halted due to command timeout\n");
}
if (ioc->fwfault_debug == 2)
@@ -956,8 +948,8 @@ _base_sas_ioc_info(struct MPT3SAS_ADAPTER *ioc, MPI2DefaultReply_t *mpi_reply,
break;
}
- pr_warn(MPT3SAS_FMT "ioc_status: %s(0x%04x), request(0x%p),(%s)\n",
- ioc->name, desc, ioc_status, request_hdr, func_str);
+ ioc_warn(ioc, "ioc_status: %s(0x%04x), request(0x%p),(%s)\n",
+ desc, ioc_status, request_hdr, func_str);
_debug_dump_mf(request_hdr, frame_sz/4);
}
@@ -1003,9 +995,9 @@ _base_display_event_data(struct MPT3SAS_ADAPTER *ioc,
{
Mpi2EventDataSasDiscovery_t *event_data =
(Mpi2EventDataSasDiscovery_t *)mpi_reply->EventData;
- pr_info(MPT3SAS_FMT "Discovery: (%s)", ioc->name,
- (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ?
- "start" : "stop");
+ ioc_info(ioc, "Discovery: (%s)",
+ event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED ?
+ "start" : "stop");
if (event_data->DiscoveryStatus)
pr_cont(" discovery_status(0x%08x)",
le32_to_cpu(event_data->DiscoveryStatus));
@@ -1059,14 +1051,13 @@ _base_display_event_data(struct MPT3SAS_ADAPTER *ioc,
{
Mpi26EventDataPCIeEnumeration_t *event_data =
(Mpi26EventDataPCIeEnumeration_t *)mpi_reply->EventData;
- pr_info(MPT3SAS_FMT "PCIE Enumeration: (%s)", ioc->name,
- (event_data->ReasonCode ==
- MPI26_EVENT_PCIE_ENUM_RC_STARTED) ?
- "start" : "stop");
+ ioc_info(ioc, "PCIE Enumeration: (%s)",
+ event_data->ReasonCode == MPI26_EVENT_PCIE_ENUM_RC_STARTED ?
+ "start" : "stop");
if (event_data->EnumerationStatus)
- pr_info("enumeration_status(0x%08x)",
- le32_to_cpu(event_data->EnumerationStatus));
- pr_info("\n");
+ pr_cont("enumeration_status(0x%08x)",
+ le32_to_cpu(event_data->EnumerationStatus));
+ pr_cont("\n");
return;
}
case MPI2_EVENT_PCIE_TOPOLOGY_CHANGE_LIST:
@@ -1077,7 +1068,7 @@ _base_display_event_data(struct MPT3SAS_ADAPTER *ioc,
if (!desc)
return;
- pr_info(MPT3SAS_FMT "%s\n", ioc->name, desc);
+ ioc_info(ioc, "%s\n", desc);
}
/**
@@ -1128,11 +1119,9 @@ _base_sas_log_info(struct MPT3SAS_ADAPTER *ioc , u32 log_info)
break;
}
- pr_warn(MPT3SAS_FMT
- "log_info(0x%08x): originator(%s), code(0x%02x), sub_code(0x%04x)\n",
- ioc->name, log_info,
- originator_str, sas_loginfo.dw.code,
- sas_loginfo.dw.subcode);
+ ioc_warn(ioc, "log_info(0x%08x): originator(%s), code(0x%02x), sub_code(0x%04x)\n",
+ log_info,
+ originator_str, sas_loginfo.dw.code, sas_loginfo.dw.subcode);
}
/**
@@ -1152,8 +1141,8 @@ _base_display_reply_info(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply);
if (unlikely(!mpi_reply)) {
- pr_err(MPT3SAS_FMT "mpi_reply not valid at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "mpi_reply not valid at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
return;
}
ioc_status = le16_to_cpu(mpi_reply->IOCStatus);
@@ -1249,9 +1238,9 @@ _base_async_event(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, u32 reply)
delayed_event_ack->EventContext = mpi_reply->EventContext;
list_add_tail(&delayed_event_ack->list,
&ioc->delayed_event_ack_list);
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "DELAYED: EVENT ACK: event (0x%04x)\n",
- ioc->name, le16_to_cpu(mpi_reply->Event)));
+ dewtprintk(ioc,
+ ioc_info(ioc, "DELAYED: EVENT ACK: event (0x%04x)\n",
+ le16_to_cpu(mpi_reply->Event)));
goto out;
}
@@ -2270,7 +2259,7 @@ _base_build_sg_scmd(struct MPT3SAS_ADAPTER *ioc,
sges_left = scsi_dma_map(scmd);
if (sges_left < 0) {
sdev_printk(KERN_ERR, scmd->device,
- "pci_map_sg failed: request for %d bytes!\n",
+ "scsi_dma_map failed: request for %d bytes!\n",
scsi_bufflen(scmd));
return -ENOMEM;
}
@@ -2418,7 +2407,7 @@ _base_build_sg_scmd_ieee(struct MPT3SAS_ADAPTER *ioc,
sges_left = scsi_dma_map(scmd);
if (sges_left < 0) {
sdev_printk(KERN_ERR, scmd->device,
- "pci_map_sg failed: request for %d bytes!\n",
+ "scsi_dma_map failed: request for %d bytes!\n",
scsi_bufflen(scmd));
return -ENOMEM;
}
@@ -2563,44 +2552,41 @@ _base_build_sg_ieee(struct MPT3SAS_ADAPTER *ioc, void *psge,
static int
_base_config_dma_addressing(struct MPT3SAS_ADAPTER *ioc, struct pci_dev *pdev)
{
+ u64 required_mask, coherent_mask;
struct sysinfo s;
- u64 consistent_dma_mask;
if (ioc->is_mcpu_endpoint)
goto try_32bit;
+ required_mask = dma_get_required_mask(&pdev->dev);
+ if (sizeof(dma_addr_t) == 4 || required_mask == 32)
+ goto try_32bit;
+
if (ioc->dma_mask)
- consistent_dma_mask = DMA_BIT_MASK(64);
+ coherent_mask = DMA_BIT_MASK(64);
else
- consistent_dma_mask = DMA_BIT_MASK(32);
-
- if (sizeof(dma_addr_t) > 4) {
- const uint64_t required_mask =
- dma_get_required_mask(&pdev->dev);
- if ((required_mask > DMA_BIT_MASK(32)) &&
- !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) &&
- !pci_set_consistent_dma_mask(pdev, consistent_dma_mask)) {
- ioc->base_add_sg_single = &_base_add_sg_single_64;
- ioc->sge_size = sizeof(Mpi2SGESimple64_t);
- ioc->dma_mask = 64;
- goto out;
- }
- }
+ coherent_mask = DMA_BIT_MASK(32);
+
+ if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)) ||
+ dma_set_coherent_mask(&pdev->dev, coherent_mask))
+ goto try_32bit;
+
+ ioc->base_add_sg_single = &_base_add_sg_single_64;
+ ioc->sge_size = sizeof(Mpi2SGESimple64_t);
+ ioc->dma_mask = 64;
+ goto out;
try_32bit:
- if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
- && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
- ioc->base_add_sg_single = &_base_add_sg_single_32;
- ioc->sge_size = sizeof(Mpi2SGESimple32_t);
- ioc->dma_mask = 32;
- } else
+ if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)))
return -ENODEV;
+ ioc->base_add_sg_single = &_base_add_sg_single_32;
+ ioc->sge_size = sizeof(Mpi2SGESimple32_t);
+ ioc->dma_mask = 32;
out:
si_meminfo(&s);
- pr_info(MPT3SAS_FMT
- "%d BIT PCI BUS DMA ADDRESSING SUPPORTED, total mem (%ld kB)\n",
- ioc->name, ioc->dma_mask, convert_to_kb(s.totalram));
+ ioc_info(ioc, "%d BIT PCI BUS DMA ADDRESSING SUPPORTED, total mem (%ld kB)\n",
+ ioc->dma_mask, convert_to_kb(s.totalram));
return 0;
}
@@ -2639,8 +2625,7 @@ _base_check_enable_msix(struct MPT3SAS_ADAPTER *ioc)
base = pci_find_capability(ioc->pdev, PCI_CAP_ID_MSIX);
if (!base) {
- dfailprintk(ioc, pr_info(MPT3SAS_FMT "msix not supported\n",
- ioc->name));
+ dfailprintk(ioc, ioc_info(ioc, "msix not supported\n"));
return -EINVAL;
}
@@ -2658,9 +2643,8 @@ _base_check_enable_msix(struct MPT3SAS_ADAPTER *ioc)
pci_read_config_word(ioc->pdev, base + 2, &message_control);
ioc->msix_vector_count = (message_control & 0x3FF) + 1;
}
- dinitprintk(ioc, pr_info(MPT3SAS_FMT
- "msix is supported, vector_count(%d)\n",
- ioc->name, ioc->msix_vector_count));
+ dinitprintk(ioc, ioc_info(ioc, "msix is supported, vector_count(%d)\n",
+ ioc->msix_vector_count));
return 0;
}
@@ -2702,8 +2686,8 @@ _base_request_irq(struct MPT3SAS_ADAPTER *ioc, u8 index)
reply_q = kzalloc(sizeof(struct adapter_reply_queue), GFP_KERNEL);
if (!reply_q) {
- pr_err(MPT3SAS_FMT "unable to allocate memory %d!\n",
- ioc->name, (int)sizeof(struct adapter_reply_queue));
+ ioc_err(ioc, "unable to allocate memory %zu!\n",
+ sizeof(struct adapter_reply_queue));
return -ENOMEM;
}
reply_q->ioc = ioc;
@@ -2719,7 +2703,7 @@ _base_request_irq(struct MPT3SAS_ADAPTER *ioc, u8 index)
r = request_irq(pci_irq_vector(pdev, index), _base_interrupt,
IRQF_SHARED, reply_q->name, reply_q);
if (r) {
- pr_err(MPT3SAS_FMT "unable to allocate interrupt %d!\n",
+ pr_err("%s: unable to allocate interrupt %d!\n",
reply_q->name, pci_irq_vector(pdev, index));
kfree(reply_q);
return -EBUSY;
@@ -2761,8 +2745,8 @@ _base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc)
const cpumask_t *mask = pci_irq_get_affinity(ioc->pdev,
reply_q->msix_index);
if (!mask) {
- pr_warn(MPT3SAS_FMT "no affinity for msi %x\n",
- ioc->name, reply_q->msix_index);
+ ioc_warn(ioc, "no affinity for msi %x\n",
+ reply_q->msix_index);
continue;
}
@@ -2833,9 +2817,8 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc)
ioc->reply_queue_count = min_t(int, ioc->cpu_count,
ioc->msix_vector_count);
- printk(MPT3SAS_FMT "MSI-X vectors supported: %d, no of cores"
- ": %d, max_msix_vectors: %d\n", ioc->name, ioc->msix_vector_count,
- ioc->cpu_count, max_msix_vectors);
+ ioc_info(ioc, "MSI-X vectors supported: %d, no of cores: %d, max_msix_vectors: %d\n",
+ ioc->msix_vector_count, ioc->cpu_count, max_msix_vectors);
if (!ioc->rdpq_array_enable && max_msix_vectors == -1)
local_max_msix_vectors = (reset_devices) ? 1 : 8;
@@ -2857,9 +2840,9 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc)
r = pci_alloc_irq_vectors(ioc->pdev, 1, ioc->reply_queue_count,
irq_flags);
if (r < 0) {
- dfailprintk(ioc, pr_info(MPT3SAS_FMT
- "pci_alloc_irq_vectors failed (r=%d) !!!\n",
- ioc->name, r));
+ dfailprintk(ioc,
+ ioc_info(ioc, "pci_alloc_irq_vectors failed (r=%d) !!!\n",
+ r));
goto try_ioapic;
}
@@ -2882,9 +2865,9 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc)
ioc->reply_queue_count = 1;
r = pci_alloc_irq_vectors(ioc->pdev, 1, 1, PCI_IRQ_LEGACY);
if (r < 0) {
- dfailprintk(ioc, pr_info(MPT3SAS_FMT
- "pci_alloc_irq_vector(legacy) failed (r=%d) !!!\n",
- ioc->name, r));
+ dfailprintk(ioc,
+ ioc_info(ioc, "pci_alloc_irq_vector(legacy) failed (r=%d) !!!\n",
+ r));
} else
r = _base_request_irq(ioc, 0);
@@ -2900,8 +2883,7 @@ mpt3sas_base_unmap_resources(struct MPT3SAS_ADAPTER *ioc)
{
struct pci_dev *pdev = ioc->pdev;
- dexitprintk(ioc, printk(MPT3SAS_FMT "%s\n",
- ioc->name, __func__));
+ dexitprintk(ioc, ioc_info(ioc, "%s\n", __func__));
_base_free_irq(ioc);
_base_disable_msix(ioc);
@@ -2939,13 +2921,11 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc)
phys_addr_t chip_phys = 0;
struct adapter_reply_queue *reply_q;
- dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n",
- ioc->name, __func__));
+ dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__));
ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
if (pci_enable_device_mem(pdev)) {
- pr_warn(MPT3SAS_FMT "pci_enable_device_mem: failed\n",
- ioc->name);
+ ioc_warn(ioc, "pci_enable_device_mem: failed\n");
ioc->bars = 0;
return -ENODEV;
}
@@ -2953,8 +2933,7 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc)
if (pci_request_selected_regions(pdev, ioc->bars,
ioc->driver_name)) {
- pr_warn(MPT3SAS_FMT "pci_request_selected_regions: failed\n",
- ioc->name);
+ ioc_warn(ioc, "pci_request_selected_regions: failed\n");
ioc->bars = 0;
r = -ENODEV;
goto out_fail;
@@ -2967,8 +2946,7 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc)
if (_base_config_dma_addressing(ioc, pdev) != 0) {
- pr_warn(MPT3SAS_FMT "no suitable DMA mask for %s\n",
- ioc->name, pci_name(pdev));
+ ioc_warn(ioc, "no suitable DMA mask for %s\n", pci_name(pdev));
r = -ENODEV;
goto out_fail;
}
@@ -2991,8 +2969,7 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc)
}
if (ioc->chip == NULL) {
- pr_err(MPT3SAS_FMT "unable to map adapter memory! "
- " or resource not found\n", ioc->name);
+ ioc_err(ioc, "unable to map adapter memory! or resource not found\n");
r = -EINVAL;
goto out_fail;
}
@@ -3026,9 +3003,8 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc)
ioc->combined_reply_index_count,
sizeof(resource_size_t *), GFP_KERNEL);
if (!ioc->replyPostRegisterIndex) {
- dfailprintk(ioc, printk(MPT3SAS_FMT
- "allocation for reply Post Register Index failed!!!\n",
- ioc->name));
+ dfailprintk(ioc,
+ ioc_warn(ioc, "allocation for reply Post Register Index failed!!!\n"));
r = -ENOMEM;
goto out_fail;
}
@@ -3053,15 +3029,15 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc)
}
list_for_each_entry(reply_q, &ioc->reply_queue_list, list)
- pr_info(MPT3SAS_FMT "%s: IRQ %d\n",
- reply_q->name, ((ioc->msix_enable) ? "PCI-MSI-X enabled" :
- "IO-APIC enabled"),
- pci_irq_vector(ioc->pdev, reply_q->msix_index));
+ pr_info("%s: %s enabled: IRQ %d\n",
+ reply_q->name,
+ ioc->msix_enable ? "PCI-MSI-X" : "IO-APIC",
+ pci_irq_vector(ioc->pdev, reply_q->msix_index));
- pr_info(MPT3SAS_FMT "iomem(%pap), mapped(0x%p), size(%d)\n",
- ioc->name, &chip_phys, ioc->chip, memap_sz);
- pr_info(MPT3SAS_FMT "ioport(0x%016llx), size(%d)\n",
- ioc->name, (unsigned long long)pio_chip, pio_sz);
+ ioc_info(ioc, "iomem(%pap), mapped(0x%p), size(%d)\n",
+ &chip_phys, ioc->chip, memap_sz);
+ ioc_info(ioc, "ioport(0x%016llx), size(%d)\n",
+ (unsigned long long)pio_chip, pio_sz);
/* Save PCI configuration state for recovery from PCI AER/EEH errors */
pci_save_state(pdev);
@@ -3176,8 +3152,7 @@ mpt3sas_base_get_smid(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx)
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
if (list_empty(&ioc->internal_free_list)) {
spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
- pr_err(MPT3SAS_FMT "%s: smid not available\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: smid not available\n", __func__);
return 0;
}
@@ -3545,89 +3520,85 @@ _base_display_OEMs_branding(struct MPT3SAS_ADAPTER *ioc)
case MPI2_MFGPAGE_DEVID_SAS2008:
switch (ioc->pdev->subsystem_device) {
case MPT2SAS_INTEL_RMS2LL080_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT2SAS_INTEL_RMS2LL080_BRANDING);
+ ioc_info(ioc, "%s\n",
+ MPT2SAS_INTEL_RMS2LL080_BRANDING);
break;
case MPT2SAS_INTEL_RMS2LL040_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT2SAS_INTEL_RMS2LL040_BRANDING);
+ ioc_info(ioc, "%s\n",
+ MPT2SAS_INTEL_RMS2LL040_BRANDING);
break;
case MPT2SAS_INTEL_SSD910_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT2SAS_INTEL_SSD910_BRANDING);
+ ioc_info(ioc, "%s\n",
+ MPT2SAS_INTEL_SSD910_BRANDING);
break;
default:
- pr_info(MPT3SAS_FMT
- "Intel(R) Controller: Subsystem ID: 0x%X\n",
- ioc->name, ioc->pdev->subsystem_device);
+ ioc_info(ioc, "Intel(R) Controller: Subsystem ID: 0x%X\n",
+ ioc->pdev->subsystem_device);
break;
}
case MPI2_MFGPAGE_DEVID_SAS2308_2:
switch (ioc->pdev->subsystem_device) {
case MPT2SAS_INTEL_RS25GB008_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT2SAS_INTEL_RS25GB008_BRANDING);
+ ioc_info(ioc, "%s\n",
+ MPT2SAS_INTEL_RS25GB008_BRANDING);
break;
case MPT2SAS_INTEL_RMS25JB080_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT2SAS_INTEL_RMS25JB080_BRANDING);
+ ioc_info(ioc, "%s\n",
+ MPT2SAS_INTEL_RMS25JB080_BRANDING);
break;
case MPT2SAS_INTEL_RMS25JB040_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT2SAS_INTEL_RMS25JB040_BRANDING);
+ ioc_info(ioc, "%s\n",
+ MPT2SAS_INTEL_RMS25JB040_BRANDING);
break;
case MPT2SAS_INTEL_RMS25KB080_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT2SAS_INTEL_RMS25KB080_BRANDING);
+ ioc_info(ioc, "%s\n",
+ MPT2SAS_INTEL_RMS25KB080_BRANDING);
break;
case MPT2SAS_INTEL_RMS25KB040_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT2SAS_INTEL_RMS25KB040_BRANDING);
+ ioc_info(ioc, "%s\n",
+ MPT2SAS_INTEL_RMS25KB040_BRANDING);
break;
case MPT2SAS_INTEL_RMS25LB040_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT2SAS_INTEL_RMS25LB040_BRANDING);
+ ioc_info(ioc, "%s\n",
+ MPT2SAS_INTEL_RMS25LB040_BRANDING);
break;
case MPT2SAS_INTEL_RMS25LB080_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT2SAS_INTEL_RMS25LB080_BRANDING);
+ ioc_info(ioc, "%s\n",
+ MPT2SAS_INTEL_RMS25LB080_BRANDING);
break;
default:
- pr_info(MPT3SAS_FMT
- "Intel(R) Controller: Subsystem ID: 0x%X\n",
- ioc->name, ioc->pdev->subsystem_device);
+ ioc_info(ioc, "Intel(R) Controller: Subsystem ID: 0x%X\n",
+ ioc->pdev->subsystem_device);
break;
}
case MPI25_MFGPAGE_DEVID_SAS3008:
switch (ioc->pdev->subsystem_device) {
case MPT3SAS_INTEL_RMS3JC080_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT3SAS_INTEL_RMS3JC080_BRANDING);
+ ioc_info(ioc, "%s\n",
+ MPT3SAS_INTEL_RMS3JC080_BRANDING);
break;
case MPT3SAS_INTEL_RS3GC008_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT3SAS_INTEL_RS3GC008_BRANDING);
+ ioc_info(ioc, "%s\n",
+ MPT3SAS_INTEL_RS3GC008_BRANDING);
break;
case MPT3SAS_INTEL_RS3FC044_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT3SAS_INTEL_RS3FC044_BRANDING);
+ ioc_info(ioc, "%s\n",
+ MPT3SAS_INTEL_RS3FC044_BRANDING);
break;
case MPT3SAS_INTEL_RS3UC080_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT3SAS_INTEL_RS3UC080_BRANDING);
+ ioc_info(ioc, "%s\n",
+ MPT3SAS_INTEL_RS3UC080_BRANDING);
break;
default:
- pr_info(MPT3SAS_FMT
- "Intel(R) Controller: Subsystem ID: 0x%X\n",
- ioc->name, ioc->pdev->subsystem_device);
+ ioc_info(ioc, "Intel(R) Controller: Subsystem ID: 0x%X\n",
+ ioc->pdev->subsystem_device);
break;
}
break;
default:
- pr_info(MPT3SAS_FMT
- "Intel(R) Controller: Subsystem ID: 0x%X\n",
- ioc->name, ioc->pdev->subsystem_device);
+ ioc_info(ioc, "Intel(R) Controller: Subsystem ID: 0x%X\n",
+ ioc->pdev->subsystem_device);
break;
}
break;
@@ -3636,57 +3607,54 @@ _base_display_OEMs_branding(struct MPT3SAS_ADAPTER *ioc)
case MPI2_MFGPAGE_DEVID_SAS2008:
switch (ioc->pdev->subsystem_device) {
case MPT2SAS_DELL_6GBPS_SAS_HBA_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT2SAS_DELL_6GBPS_SAS_HBA_BRANDING);
+ ioc_info(ioc, "%s\n",
+ MPT2SAS_DELL_6GBPS_SAS_HBA_BRANDING);
break;
case MPT2SAS_DELL_PERC_H200_ADAPTER_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT2SAS_DELL_PERC_H200_ADAPTER_BRANDING);
+ ioc_info(ioc, "%s\n",
+ MPT2SAS_DELL_PERC_H200_ADAPTER_BRANDING);
break;
case MPT2SAS_DELL_PERC_H200_INTEGRATED_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT2SAS_DELL_PERC_H200_INTEGRATED_BRANDING);
+ ioc_info(ioc, "%s\n",
+ MPT2SAS_DELL_PERC_H200_INTEGRATED_BRANDING);
break;
case MPT2SAS_DELL_PERC_H200_MODULAR_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT2SAS_DELL_PERC_H200_MODULAR_BRANDING);
+ ioc_info(ioc, "%s\n",
+ MPT2SAS_DELL_PERC_H200_MODULAR_BRANDING);
break;
case MPT2SAS_DELL_PERC_H200_EMBEDDED_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT2SAS_DELL_PERC_H200_EMBEDDED_BRANDING);
+ ioc_info(ioc, "%s\n",
+ MPT2SAS_DELL_PERC_H200_EMBEDDED_BRANDING);
break;
case MPT2SAS_DELL_PERC_H200_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT2SAS_DELL_PERC_H200_BRANDING);
+ ioc_info(ioc, "%s\n",
+ MPT2SAS_DELL_PERC_H200_BRANDING);
break;
case MPT2SAS_DELL_6GBPS_SAS_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT2SAS_DELL_6GBPS_SAS_BRANDING);
+ ioc_info(ioc, "%s\n",
+ MPT2SAS_DELL_6GBPS_SAS_BRANDING);
break;
default:
- pr_info(MPT3SAS_FMT
- "Dell 6Gbps HBA: Subsystem ID: 0x%X\n",
- ioc->name, ioc->pdev->subsystem_device);
+ ioc_info(ioc, "Dell 6Gbps HBA: Subsystem ID: 0x%X\n",
+ ioc->pdev->subsystem_device);
break;
}
break;
case MPI25_MFGPAGE_DEVID_SAS3008:
switch (ioc->pdev->subsystem_device) {
case MPT3SAS_DELL_12G_HBA_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT3SAS_DELL_12G_HBA_BRANDING);
+ ioc_info(ioc, "%s\n",
+ MPT3SAS_DELL_12G_HBA_BRANDING);
break;
default:
- pr_info(MPT3SAS_FMT
- "Dell 12Gbps HBA: Subsystem ID: 0x%X\n",
- ioc->name, ioc->pdev->subsystem_device);
+ ioc_info(ioc, "Dell 12Gbps HBA: Subsystem ID: 0x%X\n",
+ ioc->pdev->subsystem_device);
break;
}
break;
default:
- pr_info(MPT3SAS_FMT
- "Dell HBA: Subsystem ID: 0x%X\n", ioc->name,
- ioc->pdev->subsystem_device);
+ ioc_info(ioc, "Dell HBA: Subsystem ID: 0x%X\n",
+ ioc->pdev->subsystem_device);
break;
}
break;
@@ -3695,46 +3663,42 @@ _base_display_OEMs_branding(struct MPT3SAS_ADAPTER *ioc)
case MPI25_MFGPAGE_DEVID_SAS3008:
switch (ioc->pdev->subsystem_device) {
case MPT3SAS_CISCO_12G_8E_HBA_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT3SAS_CISCO_12G_8E_HBA_BRANDING);
+ ioc_info(ioc, "%s\n",
+ MPT3SAS_CISCO_12G_8E_HBA_BRANDING);
break;
case MPT3SAS_CISCO_12G_8I_HBA_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT3SAS_CISCO_12G_8I_HBA_BRANDING);
+ ioc_info(ioc, "%s\n",
+ MPT3SAS_CISCO_12G_8I_HBA_BRANDING);
break;
case MPT3SAS_CISCO_12G_AVILA_HBA_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING);
+ ioc_info(ioc, "%s\n",
+ MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING);
break;
default:
- pr_info(MPT3SAS_FMT
- "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n",
- ioc->name, ioc->pdev->subsystem_device);
+ ioc_info(ioc, "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n",
+ ioc->pdev->subsystem_device);
break;
}
break;
case MPI25_MFGPAGE_DEVID_SAS3108_1:
switch (ioc->pdev->subsystem_device) {
case MPT3SAS_CISCO_12G_AVILA_HBA_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING);
+ ioc_info(ioc, "%s\n",
+ MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING);
break;
case MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_BRANDING
- );
+ ioc_info(ioc, "%s\n",
+ MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_BRANDING);
break;
default:
- pr_info(MPT3SAS_FMT
- "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n",
- ioc->name, ioc->pdev->subsystem_device);
+ ioc_info(ioc, "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n",
+ ioc->pdev->subsystem_device);
break;
}
break;
default:
- pr_info(MPT3SAS_FMT
- "Cisco SAS HBA: Subsystem ID: 0x%X\n",
- ioc->name, ioc->pdev->subsystem_device);
+ ioc_info(ioc, "Cisco SAS HBA: Subsystem ID: 0x%X\n",
+ ioc->pdev->subsystem_device);
break;
}
break;
@@ -3743,43 +3707,40 @@ _base_display_OEMs_branding(struct MPT3SAS_ADAPTER *ioc)
case MPI2_MFGPAGE_DEVID_SAS2004:
switch (ioc->pdev->subsystem_device) {
case MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_BRANDING);
+ ioc_info(ioc, "%s\n",
+ MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_BRANDING);
break;
default:
- pr_info(MPT3SAS_FMT
- "HP 6Gbps SAS HBA: Subsystem ID: 0x%X\n",
- ioc->name, ioc->pdev->subsystem_device);
+ ioc_info(ioc, "HP 6Gbps SAS HBA: Subsystem ID: 0x%X\n",
+ ioc->pdev->subsystem_device);
break;
}
case MPI2_MFGPAGE_DEVID_SAS2308_2:
switch (ioc->pdev->subsystem_device) {
case MPT2SAS_HP_2_4_INTERNAL_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT2SAS_HP_2_4_INTERNAL_BRANDING);
+ ioc_info(ioc, "%s\n",
+ MPT2SAS_HP_2_4_INTERNAL_BRANDING);
break;
case MPT2SAS_HP_2_4_EXTERNAL_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT2SAS_HP_2_4_EXTERNAL_BRANDING);
+ ioc_info(ioc, "%s\n",
+ MPT2SAS_HP_2_4_EXTERNAL_BRANDING);
break;
case MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_BRANDING);
+ ioc_info(ioc, "%s\n",
+ MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_BRANDING);
break;
case MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_BRANDING);
+ ioc_info(ioc, "%s\n",
+ MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_BRANDING);
break;
default:
- pr_info(MPT3SAS_FMT
- "HP 6Gbps SAS HBA: Subsystem ID: 0x%X\n",
- ioc->name, ioc->pdev->subsystem_device);
+ ioc_info(ioc, "HP 6Gbps SAS HBA: Subsystem ID: 0x%X\n",
+ ioc->pdev->subsystem_device);
break;
}
default:
- pr_info(MPT3SAS_FMT
- "HP SAS HBA: Subsystem ID: 0x%X\n",
- ioc->name, ioc->pdev->subsystem_device);
+ ioc_info(ioc, "HP SAS HBA: Subsystem ID: 0x%X\n",
+ ioc->pdev->subsystem_device);
break;
}
default:
@@ -3806,28 +3767,25 @@ _base_display_fwpkg_version(struct MPT3SAS_ADAPTER *ioc)
u16 smid, ioc_status;
size_t data_length;
- dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- __func__));
+ dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__));
if (ioc->base_cmds.status & MPT3_CMD_PENDING) {
- pr_err(MPT3SAS_FMT "%s: internal command already in use\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: internal command already in use\n", __func__);
return -EAGAIN;
}
data_length = sizeof(Mpi2FWImageHeader_t);
- fwpkg_data = pci_alloc_consistent(ioc->pdev, data_length,
- &fwpkg_data_dma);
+ fwpkg_data = dma_alloc_coherent(&ioc->pdev->dev, data_length,
+ &fwpkg_data_dma, GFP_KERNEL);
if (!fwpkg_data) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
return -ENOMEM;
}
smid = mpt3sas_base_get_smid(ioc, ioc->base_cb_idx);
if (!smid) {
- pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);
r = -EAGAIN;
goto out;
}
@@ -3846,11 +3804,9 @@ _base_display_fwpkg_version(struct MPT3SAS_ADAPTER *ioc)
/* Wait for 15 seconds */
wait_for_completion_timeout(&ioc->base_cmds.done,
FW_IMG_HDR_READ_TIMEOUT*HZ);
- pr_info(MPT3SAS_FMT "%s: complete\n",
- ioc->name, __func__);
+ ioc_info(ioc, "%s: complete\n", __func__);
if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) {
- pr_err(MPT3SAS_FMT "%s: timeout\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: timeout\n", __func__);
_debug_dump_mf(mpi_request,
sizeof(Mpi25FWUploadRequest_t)/4);
r = -ETIME;
@@ -3864,13 +3820,11 @@ _base_display_fwpkg_version(struct MPT3SAS_ADAPTER *ioc)
if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
FWImgHdr = (Mpi2FWImageHeader_t *)fwpkg_data;
if (FWImgHdr->PackageVersion.Word) {
- pr_info(MPT3SAS_FMT "FW Package Version"
- "(%02d.%02d.%02d.%02d)\n",
- ioc->name,
- FWImgHdr->PackageVersion.Struct.Major,
- FWImgHdr->PackageVersion.Struct.Minor,
- FWImgHdr->PackageVersion.Struct.Unit,
- FWImgHdr->PackageVersion.Struct.Dev);
+ ioc_info(ioc, "FW Package Version (%02d.%02d.%02d.%02d)\n",
+ FWImgHdr->PackageVersion.Struct.Major,
+ FWImgHdr->PackageVersion.Struct.Minor,
+ FWImgHdr->PackageVersion.Struct.Unit,
+ FWImgHdr->PackageVersion.Struct.Dev);
}
} else {
_debug_dump_mf(&mpi_reply,
@@ -3881,7 +3835,7 @@ _base_display_fwpkg_version(struct MPT3SAS_ADAPTER *ioc)
ioc->base_cmds.status = MPT3_CMD_NOT_USED;
out:
if (fwpkg_data)
- pci_free_consistent(ioc->pdev, data_length, fwpkg_data,
+ dma_free_coherent(&ioc->pdev->dev, data_length, fwpkg_data,
fwpkg_data_dma);
return r;
}
@@ -3900,18 +3854,17 @@ _base_display_ioc_capabilities(struct MPT3SAS_ADAPTER *ioc)
bios_version = le32_to_cpu(ioc->bios_pg3.BiosVersion);
strncpy(desc, ioc->manu_pg0.ChipName, 16);
- pr_info(MPT3SAS_FMT "%s: FWVersion(%02d.%02d.%02d.%02d), "\
- "ChipRevision(0x%02x), BiosVersion(%02d.%02d.%02d.%02d)\n",
- ioc->name, desc,
- (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
- (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
- (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
- ioc->facts.FWVersion.Word & 0x000000FF,
- ioc->pdev->revision,
- (bios_version & 0xFF000000) >> 24,
- (bios_version & 0x00FF0000) >> 16,
- (bios_version & 0x0000FF00) >> 8,
- bios_version & 0x000000FF);
+ ioc_info(ioc, "%s: FWVersion(%02d.%02d.%02d.%02d), ChipRevision(0x%02x), BiosVersion(%02d.%02d.%02d.%02d)\n",
+ desc,
+ (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
+ (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
+ (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
+ ioc->facts.FWVersion.Word & 0x000000FF,
+ ioc->pdev->revision,
+ (bios_version & 0xFF000000) >> 24,
+ (bios_version & 0x00FF0000) >> 16,
+ (bios_version & 0x0000FF00) >> 8,
+ bios_version & 0x000000FF);
_base_display_OEMs_branding(ioc);
@@ -3920,82 +3873,81 @@ _base_display_ioc_capabilities(struct MPT3SAS_ADAPTER *ioc)
i++;
}
- pr_info(MPT3SAS_FMT "Protocol=(", ioc->name);
+ ioc_info(ioc, "Protocol=(");
if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR) {
- pr_info("Initiator");
+ pr_cont("Initiator");
i++;
}
if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_TARGET) {
- pr_info("%sTarget", i ? "," : "");
+ pr_cont("%sTarget", i ? "," : "");
i++;
}
i = 0;
- pr_info("), ");
- pr_info("Capabilities=(");
+ pr_cont("), Capabilities=(");
if (!ioc->hide_ir_msg) {
if (ioc->facts.IOCCapabilities &
MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID) {
- pr_info("Raid");
+ pr_cont("Raid");
i++;
}
}
if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR) {
- pr_info("%sTLR", i ? "," : "");
+ pr_cont("%sTLR", i ? "," : "");
i++;
}
if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_MULTICAST) {
- pr_info("%sMulticast", i ? "," : "");
+ pr_cont("%sMulticast", i ? "," : "");
i++;
}
if (ioc->facts.IOCCapabilities &
MPI2_IOCFACTS_CAPABILITY_BIDIRECTIONAL_TARGET) {
- pr_info("%sBIDI Target", i ? "," : "");
+ pr_cont("%sBIDI Target", i ? "," : "");
i++;
}
if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_EEDP) {
- pr_info("%sEEDP", i ? "," : "");
+ pr_cont("%sEEDP", i ? "," : "");
i++;
}
if (ioc->facts.IOCCapabilities &
MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER) {
- pr_info("%sSnapshot Buffer", i ? "," : "");
+ pr_cont("%sSnapshot Buffer", i ? "," : "");
i++;
}
if (ioc->facts.IOCCapabilities &
MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER) {
- pr_info("%sDiag Trace Buffer", i ? "," : "");
+ pr_cont("%sDiag Trace Buffer", i ? "," : "");
i++;
}
if (ioc->facts.IOCCapabilities &
MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER) {
- pr_info("%sDiag Extended Buffer", i ? "," : "");
+ pr_cont("%sDiag Extended Buffer", i ? "," : "");
i++;
}
if (ioc->facts.IOCCapabilities &
MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING) {
- pr_info("%sTask Set Full", i ? "," : "");
+ pr_cont("%sTask Set Full", i ? "," : "");
i++;
}
iounit_pg1_flags = le32_to_cpu(ioc->iounit_pg1.Flags);
if (!(iounit_pg1_flags & MPI2_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE)) {
- pr_info("%sNCQ", i ? "," : "");
+ pr_cont("%sNCQ", i ? "," : "");
i++;
}
- pr_info(")\n");
+ pr_cont(")\n");
}
/**
@@ -4028,21 +3980,21 @@ mpt3sas_base_update_missing_delay(struct MPT3SAS_ADAPTER *ioc,
sizeof(Mpi2SasIOUnit1PhyData_t));
sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
if (!sas_iounit_pg1) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
goto out;
}
if ((mpt3sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
sas_iounit_pg1, sz))) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
goto out;
}
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
MPI2_IOCSTATUS_MASK;
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
goto out;
}
@@ -4074,11 +4026,11 @@ mpt3sas_base_update_missing_delay(struct MPT3SAS_ADAPTER *ioc,
else
dmd_new =
dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
- pr_info(MPT3SAS_FMT "device_missing_delay: old(%d), new(%d)\n",
- ioc->name, dmd_orignal, dmd_new);
- pr_info(MPT3SAS_FMT "ioc_missing_delay: old(%d), new(%d)\n",
- ioc->name, io_missing_delay_original,
- io_missing_delay);
+ ioc_info(ioc, "device_missing_delay: old(%d), new(%d)\n",
+ dmd_orignal, dmd_new);
+ ioc_info(ioc, "ioc_missing_delay: old(%d), new(%d)\n",
+ io_missing_delay_original,
+ io_missing_delay);
ioc->device_missing_delay = dmd_new;
ioc->io_missing_delay = io_missing_delay;
}
@@ -4189,33 +4141,32 @@ _base_release_memory_pools(struct MPT3SAS_ADAPTER *ioc)
struct chain_tracker *ct;
struct reply_post_struct *rps;
- dexitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- __func__));
+ dexitprintk(ioc, ioc_info(ioc, "%s\n", __func__));
if (ioc->request) {
- pci_free_consistent(ioc->pdev, ioc->request_dma_sz,
+ dma_free_coherent(&ioc->pdev->dev, ioc->request_dma_sz,
ioc->request, ioc->request_dma);
- dexitprintk(ioc, pr_info(MPT3SAS_FMT
- "request_pool(0x%p): free\n",
- ioc->name, ioc->request));
+ dexitprintk(ioc,
+ ioc_info(ioc, "request_pool(0x%p): free\n",
+ ioc->request));
ioc->request = NULL;
}
if (ioc->sense) {
dma_pool_free(ioc->sense_dma_pool, ioc->sense, ioc->sense_dma);
dma_pool_destroy(ioc->sense_dma_pool);
- dexitprintk(ioc, pr_info(MPT3SAS_FMT
- "sense_pool(0x%p): free\n",
- ioc->name, ioc->sense));
+ dexitprintk(ioc,
+ ioc_info(ioc, "sense_pool(0x%p): free\n",
+ ioc->sense));
ioc->sense = NULL;
}
if (ioc->reply) {
dma_pool_free(ioc->reply_dma_pool, ioc->reply, ioc->reply_dma);
dma_pool_destroy(ioc->reply_dma_pool);
- dexitprintk(ioc, pr_info(MPT3SAS_FMT
- "reply_pool(0x%p): free\n",
- ioc->name, ioc->reply));
+ dexitprintk(ioc,
+ ioc_info(ioc, "reply_pool(0x%p): free\n",
+ ioc->reply));
ioc->reply = NULL;
}
@@ -4223,9 +4174,9 @@ _base_release_memory_pools(struct MPT3SAS_ADAPTER *ioc)
dma_pool_free(ioc->reply_free_dma_pool, ioc->reply_free,
ioc->reply_free_dma);
dma_pool_destroy(ioc->reply_free_dma_pool);
- dexitprintk(ioc, pr_info(MPT3SAS_FMT
- "reply_free_pool(0x%p): free\n",
- ioc->name, ioc->reply_free));
+ dexitprintk(ioc,
+ ioc_info(ioc, "reply_free_pool(0x%p): free\n",
+ ioc->reply_free));
ioc->reply_free = NULL;
}
@@ -4237,9 +4188,9 @@ _base_release_memory_pools(struct MPT3SAS_ADAPTER *ioc)
ioc->reply_post_free_dma_pool,
rps->reply_post_free,
rps->reply_post_free_dma);
- dexitprintk(ioc, pr_info(MPT3SAS_FMT
- "reply_post_free_pool(0x%p): free\n",
- ioc->name, rps->reply_post_free));
+ dexitprintk(ioc,
+ ioc_info(ioc, "reply_post_free_pool(0x%p): free\n",
+ rps->reply_post_free));
rps->reply_post_free = NULL;
}
} while (ioc->rdpq_array_enable &&
@@ -4267,10 +4218,10 @@ _base_release_memory_pools(struct MPT3SAS_ADAPTER *ioc)
}
if (ioc->config_page) {
- dexitprintk(ioc, pr_info(MPT3SAS_FMT
- "config_page(0x%p): free\n", ioc->name,
- ioc->config_page));
- pci_free_consistent(ioc->pdev, ioc->config_page_sz,
+ dexitprintk(ioc,
+ ioc_info(ioc, "config_page(0x%p): free\n",
+ ioc->config_page));
+ dma_free_coherent(&ioc->pdev->dev, ioc->config_page_sz,
ioc->config_page, ioc->config_page_dma);
}
@@ -4338,8 +4289,7 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc)
int i, j;
struct chain_tracker *ct;
- dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- __func__));
+ dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__));
retry_sz = 0;
@@ -4368,10 +4318,8 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc)
else if (sg_tablesize > MPT_MAX_PHYS_SEGMENTS) {
sg_tablesize = min_t(unsigned short, sg_tablesize,
SG_MAX_SEGMENTS);
- pr_warn(MPT3SAS_FMT
- "sg_tablesize(%u) is bigger than kernel "
- "defined SG_CHUNK_SIZE(%u)\n", ioc->name,
- sg_tablesize, MPT_MAX_PHYS_SEGMENTS);
+ ioc_warn(ioc, "sg_tablesize(%u) is bigger than kernel defined SG_CHUNK_SIZE(%u)\n",
+ sg_tablesize, MPT_MAX_PHYS_SEGMENTS);
}
ioc->shost->sg_tablesize = sg_tablesize;
}
@@ -4381,9 +4329,8 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc)
if (ioc->internal_depth < INTERNAL_CMDS_COUNT) {
if (facts->RequestCredit <= (INTERNAL_CMDS_COUNT +
INTERNAL_SCSIIO_CMDS_COUNT)) {
- pr_err(MPT3SAS_FMT "IOC doesn't have enough Request \
- Credits, it has just %d number of credits\n",
- ioc->name, facts->RequestCredit);
+ ioc_err(ioc, "IOC doesn't have enough Request Credits, it has just %d number of credits\n",
+ facts->RequestCredit);
return -ENOMEM;
}
ioc->internal_depth = 10;
@@ -4482,11 +4429,12 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc)
ioc->reply_free_queue_depth = ioc->hba_queue_depth + 64;
}
- dinitprintk(ioc, pr_info(MPT3SAS_FMT "scatter gather: " \
- "sge_in_main_msg(%d), sge_per_chain(%d), sge_per_io(%d), "
- "chains_per_io(%d)\n", ioc->name, ioc->max_sges_in_main_message,
- ioc->max_sges_in_chain_message, ioc->shost->sg_tablesize,
- ioc->chains_needed_per_io));
+ dinitprintk(ioc,
+ ioc_info(ioc, "scatter gather: sge_in_main_msg(%d), sge_per_chain(%d), sge_per_io(%d), chains_per_io(%d)\n",
+ ioc->max_sges_in_main_message,
+ ioc->max_sges_in_chain_message,
+ ioc->shost->sg_tablesize,
+ ioc->chains_needed_per_io));
/* reply post queue, 16 byte align */
reply_post_free_sz = ioc->reply_post_queue_depth *
@@ -4501,48 +4449,40 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc)
sizeof(struct reply_post_struct), GFP_KERNEL);
if (!ioc->reply_post) {
- pr_err(MPT3SAS_FMT "reply_post_free pool: kcalloc failed\n",
- ioc->name);
+ ioc_err(ioc, "reply_post_free pool: kcalloc failed\n");
goto out;
}
ioc->reply_post_free_dma_pool = dma_pool_create("reply_post_free pool",
&ioc->pdev->dev, sz, 16, 0);
if (!ioc->reply_post_free_dma_pool) {
- pr_err(MPT3SAS_FMT
- "reply_post_free pool: dma_pool_create failed\n",
- ioc->name);
+ ioc_err(ioc, "reply_post_free pool: dma_pool_create failed\n");
goto out;
}
i = 0;
do {
ioc->reply_post[i].reply_post_free =
- dma_pool_alloc(ioc->reply_post_free_dma_pool,
+ dma_pool_zalloc(ioc->reply_post_free_dma_pool,
GFP_KERNEL,
&ioc->reply_post[i].reply_post_free_dma);
if (!ioc->reply_post[i].reply_post_free) {
- pr_err(MPT3SAS_FMT
- "reply_post_free pool: dma_pool_alloc failed\n",
- ioc->name);
+ ioc_err(ioc, "reply_post_free pool: dma_pool_alloc failed\n");
goto out;
}
- memset(ioc->reply_post[i].reply_post_free, 0, sz);
- dinitprintk(ioc, pr_info(MPT3SAS_FMT
- "reply post free pool (0x%p): depth(%d),"
- "element_size(%d), pool_size(%d kB)\n", ioc->name,
- ioc->reply_post[i].reply_post_free,
- ioc->reply_post_queue_depth, 8, sz/1024));
- dinitprintk(ioc, pr_info(MPT3SAS_FMT
- "reply_post_free_dma = (0x%llx)\n", ioc->name,
- (unsigned long long)
- ioc->reply_post[i].reply_post_free_dma));
+ dinitprintk(ioc,
+ ioc_info(ioc, "reply post free pool (0x%p): depth(%d), element_size(%d), pool_size(%d kB)\n",
+ ioc->reply_post[i].reply_post_free,
+ ioc->reply_post_queue_depth,
+ 8, sz / 1024));
+ dinitprintk(ioc,
+ ioc_info(ioc, "reply_post_free_dma = (0x%llx)\n",
+ (u64)ioc->reply_post[i].reply_post_free_dma));
total_sz += sz;
} while (ioc->rdpq_array_enable && (++i < ioc->reply_queue_count));
if (ioc->dma_mask == 64) {
if (_base_change_consistent_dma_mask(ioc, ioc->pdev) != 0) {
- pr_warn(MPT3SAS_FMT
- "no suitable consistent DMA mask for %s\n",
- ioc->name, pci_name(ioc->pdev));
+ ioc_warn(ioc, "no suitable consistent DMA mask for %s\n",
+ pci_name(ioc->pdev));
goto out;
}
}
@@ -4554,9 +4494,9 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc)
* with some internal commands that could be outstanding
*/
ioc->shost->can_queue = ioc->scsiio_depth - INTERNAL_SCSIIO_CMDS_COUNT;
- dinitprintk(ioc, pr_info(MPT3SAS_FMT
- "scsi host: can_queue depth (%d)\n",
- ioc->name, ioc->shost->can_queue));
+ dinitprintk(ioc,
+ ioc_info(ioc, "scsi host: can_queue depth (%d)\n",
+ ioc->shost->can_queue));
/* contiguous pool for request and chains, 16 byte align, one extra "
@@ -4572,12 +4512,12 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc)
sz += (ioc->internal_depth * ioc->request_sz);
ioc->request_dma_sz = sz;
- ioc->request = pci_alloc_consistent(ioc->pdev, sz, &ioc->request_dma);
+ ioc->request = dma_alloc_coherent(&ioc->pdev->dev, sz,
+ &ioc->request_dma, GFP_KERNEL);
if (!ioc->request) {
- pr_err(MPT3SAS_FMT "request pool: pci_alloc_consistent " \
- "failed: hba_depth(%d), chains_per_io(%d), frame_sz(%d), "
- "total(%d kB)\n", ioc->name, ioc->hba_queue_depth,
- ioc->chains_needed_per_io, ioc->request_sz, sz/1024);
+ ioc_err(ioc, "request pool: dma_alloc_coherent failed: hba_depth(%d), chains_per_io(%d), frame_sz(%d), total(%d kB)\n",
+ ioc->hba_queue_depth, ioc->chains_needed_per_io,
+ ioc->request_sz, sz / 1024);
if (ioc->scsiio_depth < MPT3SAS_SAS_QUEUE_DEPTH)
goto out;
retry_sz = 64;
@@ -4587,10 +4527,9 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc)
}
if (retry_sz)
- pr_err(MPT3SAS_FMT "request pool: pci_alloc_consistent " \
- "succeed: hba_depth(%d), chains_per_io(%d), frame_sz(%d), "
- "total(%d kb)\n", ioc->name, ioc->hba_queue_depth,
- ioc->chains_needed_per_io, ioc->request_sz, sz/1024);
+ ioc_err(ioc, "request pool: dma_alloc_coherent succeed: hba_depth(%d), chains_per_io(%d), frame_sz(%d), total(%d kb)\n",
+ ioc->hba_queue_depth, ioc->chains_needed_per_io,
+ ioc->request_sz, sz / 1024);
/* hi-priority queue */
ioc->hi_priority = ioc->request + ((ioc->scsiio_depth + 1) *
@@ -4604,24 +4543,26 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc)
ioc->internal_dma = ioc->hi_priority_dma + (ioc->hi_priority_depth *
ioc->request_sz);
- dinitprintk(ioc, pr_info(MPT3SAS_FMT
- "request pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB)\n",
- ioc->name, ioc->request, ioc->hba_queue_depth, ioc->request_sz,
- (ioc->hba_queue_depth * ioc->request_sz)/1024));
+ dinitprintk(ioc,
+ ioc_info(ioc, "request pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB)\n",
+ ioc->request, ioc->hba_queue_depth,
+ ioc->request_sz,
+ (ioc->hba_queue_depth * ioc->request_sz) / 1024));
- dinitprintk(ioc, pr_info(MPT3SAS_FMT "request pool: dma(0x%llx)\n",
- ioc->name, (unsigned long long) ioc->request_dma));
+ dinitprintk(ioc,
+ ioc_info(ioc, "request pool: dma(0x%llx)\n",
+ (unsigned long long)ioc->request_dma));
total_sz += sz;
- dinitprintk(ioc, pr_info(MPT3SAS_FMT "scsiio(0x%p): depth(%d)\n",
- ioc->name, ioc->request, ioc->scsiio_depth));
+ dinitprintk(ioc,
+ ioc_info(ioc, "scsiio(0x%p): depth(%d)\n",
+ ioc->request, ioc->scsiio_depth));
ioc->chain_depth = min_t(u32, ioc->chain_depth, MAX_CHAIN_DEPTH);
sz = ioc->scsiio_depth * sizeof(struct chain_lookup);
ioc->chain_lookup = kzalloc(sz, GFP_KERNEL);
if (!ioc->chain_lookup) {
- pr_err(MPT3SAS_FMT "chain_lookup: __get_free_pages "
- "failed\n", ioc->name);
+ ioc_err(ioc, "chain_lookup: __get_free_pages failed\n");
goto out;
}
@@ -4629,8 +4570,7 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc)
for (i = 0; i < ioc->scsiio_depth; i++) {
ioc->chain_lookup[i].chains_per_smid = kzalloc(sz, GFP_KERNEL);
if (!ioc->chain_lookup[i].chains_per_smid) {
- pr_err(MPT3SAS_FMT "chain_lookup: "
- " kzalloc failed\n", ioc->name);
+ ioc_err(ioc, "chain_lookup: kzalloc failed\n");
goto out;
}
}
@@ -4639,29 +4579,27 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc)
ioc->hpr_lookup = kcalloc(ioc->hi_priority_depth,
sizeof(struct request_tracker), GFP_KERNEL);
if (!ioc->hpr_lookup) {
- pr_err(MPT3SAS_FMT "hpr_lookup: kcalloc failed\n",
- ioc->name);
+ ioc_err(ioc, "hpr_lookup: kcalloc failed\n");
goto out;
}
ioc->hi_priority_smid = ioc->scsiio_depth + 1;
- dinitprintk(ioc, pr_info(MPT3SAS_FMT
- "hi_priority(0x%p): depth(%d), start smid(%d)\n",
- ioc->name, ioc->hi_priority,
- ioc->hi_priority_depth, ioc->hi_priority_smid));
+ dinitprintk(ioc,
+ ioc_info(ioc, "hi_priority(0x%p): depth(%d), start smid(%d)\n",
+ ioc->hi_priority,
+ ioc->hi_priority_depth, ioc->hi_priority_smid));
/* initialize internal queue smid's */
ioc->internal_lookup = kcalloc(ioc->internal_depth,
sizeof(struct request_tracker), GFP_KERNEL);
if (!ioc->internal_lookup) {
- pr_err(MPT3SAS_FMT "internal_lookup: kcalloc failed\n",
- ioc->name);
+ ioc_err(ioc, "internal_lookup: kcalloc failed\n");
goto out;
}
ioc->internal_smid = ioc->hi_priority_smid + ioc->hi_priority_depth;
- dinitprintk(ioc, pr_info(MPT3SAS_FMT
- "internal(0x%p): depth(%d), start smid(%d)\n",
- ioc->name, ioc->internal,
- ioc->internal_depth, ioc->internal_smid));
+ dinitprintk(ioc,
+ ioc_info(ioc, "internal(0x%p): depth(%d), start smid(%d)\n",
+ ioc->internal,
+ ioc->internal_depth, ioc->internal_smid));
/*
* The number of NVMe page sized blocks needed is:
* (((sg_tablesize * 8) - 1) / (page_size - 8)) + 1
@@ -4685,17 +4623,14 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc)
sz = sizeof(struct pcie_sg_list) * ioc->scsiio_depth;
ioc->pcie_sg_lookup = kzalloc(sz, GFP_KERNEL);
if (!ioc->pcie_sg_lookup) {
- pr_info(MPT3SAS_FMT
- "PCIe SGL lookup: kzalloc failed\n", ioc->name);
+ ioc_info(ioc, "PCIe SGL lookup: kzalloc failed\n");
goto out;
}
sz = nvme_blocks_needed * ioc->page_size;
ioc->pcie_sgl_dma_pool =
dma_pool_create("PCIe SGL pool", &ioc->pdev->dev, sz, 16, 0);
if (!ioc->pcie_sgl_dma_pool) {
- pr_info(MPT3SAS_FMT
- "PCIe SGL pool: dma_pool_create failed\n",
- ioc->name);
+ ioc_info(ioc, "PCIe SGL pool: dma_pool_create failed\n");
goto out;
}
@@ -4708,9 +4643,7 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc)
ioc->pcie_sgl_dma_pool, GFP_KERNEL,
&ioc->pcie_sg_lookup[i].pcie_sgl_dma);
if (!ioc->pcie_sg_lookup[i].pcie_sgl) {
- pr_info(MPT3SAS_FMT
- "PCIe SGL pool: dma_pool_alloc failed\n",
- ioc->name);
+ ioc_info(ioc, "PCIe SGL pool: dma_pool_alloc failed\n");
goto out;
}
for (j = 0; j < ioc->chains_per_prp_buffer; j++) {
@@ -4724,20 +4657,20 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc)
}
}
- dinitprintk(ioc, pr_info(MPT3SAS_FMT "PCIe sgl pool depth(%d), "
- "element_size(%d), pool_size(%d kB)\n", ioc->name,
- ioc->scsiio_depth, sz, (sz * ioc->scsiio_depth)/1024));
- dinitprintk(ioc, pr_info(MPT3SAS_FMT "Number of chains can "
- "fit in a PRP page(%d)\n", ioc->name,
- ioc->chains_per_prp_buffer));
+ dinitprintk(ioc,
+ ioc_info(ioc, "PCIe sgl pool depth(%d), element_size(%d), pool_size(%d kB)\n",
+ ioc->scsiio_depth, sz,
+ (sz * ioc->scsiio_depth) / 1024));
+ dinitprintk(ioc,
+ ioc_info(ioc, "Number of chains can fit in a PRP page(%d)\n",
+ ioc->chains_per_prp_buffer));
total_sz += sz * ioc->scsiio_depth;
}
ioc->chain_dma_pool = dma_pool_create("chain pool", &ioc->pdev->dev,
ioc->chain_segment_sz, 16, 0);
if (!ioc->chain_dma_pool) {
- pr_err(MPT3SAS_FMT "chain_dma_pool: dma_pool_create failed\n",
- ioc->name);
+ ioc_err(ioc, "chain_dma_pool: dma_pool_create failed\n");
goto out;
}
for (i = 0; i < ioc->scsiio_depth; i++) {
@@ -4748,8 +4681,7 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc)
ioc->chain_dma_pool, GFP_KERNEL,
&ct->chain_buffer_dma);
if (!ct->chain_buffer) {
- pr_err(MPT3SAS_FMT "chain_lookup: "
- " pci_pool_alloc failed\n", ioc->name);
+ ioc_err(ioc, "chain_lookup: pci_pool_alloc failed\n");
_base_release_memory_pools(ioc);
goto out;
}
@@ -4757,25 +4689,23 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc)
total_sz += ioc->chain_segment_sz;
}
- dinitprintk(ioc, pr_info(MPT3SAS_FMT
- "chain pool depth(%d), frame_size(%d), pool_size(%d kB)\n",
- ioc->name, ioc->chain_depth, ioc->chain_segment_sz,
- ((ioc->chain_depth * ioc->chain_segment_sz))/1024));
+ dinitprintk(ioc,
+ ioc_info(ioc, "chain pool depth(%d), frame_size(%d), pool_size(%d kB)\n",
+ ioc->chain_depth, ioc->chain_segment_sz,
+ (ioc->chain_depth * ioc->chain_segment_sz) / 1024));
/* sense buffers, 4 byte align */
sz = ioc->scsiio_depth * SCSI_SENSE_BUFFERSIZE;
ioc->sense_dma_pool = dma_pool_create("sense pool", &ioc->pdev->dev, sz,
4, 0);
if (!ioc->sense_dma_pool) {
- pr_err(MPT3SAS_FMT "sense pool: dma_pool_create failed\n",
- ioc->name);
+ ioc_err(ioc, "sense pool: dma_pool_create failed\n");
goto out;
}
ioc->sense = dma_pool_alloc(ioc->sense_dma_pool, GFP_KERNEL,
&ioc->sense_dma);
if (!ioc->sense) {
- pr_err(MPT3SAS_FMT "sense pool: dma_pool_alloc failed\n",
- ioc->name);
+ ioc_err(ioc, "sense pool: dma_pool_alloc failed\n");
goto out;
}
/* sense buffer requires to be in same 4 gb region.
@@ -4797,24 +4727,23 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc)
dma_pool_create("sense pool", &ioc->pdev->dev, sz,
roundup_pow_of_two(sz), 0);
if (!ioc->sense_dma_pool) {
- pr_err(MPT3SAS_FMT "sense pool: pci_pool_create failed\n",
- ioc->name);
+ ioc_err(ioc, "sense pool: pci_pool_create failed\n");
goto out;
}
ioc->sense = dma_pool_alloc(ioc->sense_dma_pool, GFP_KERNEL,
&ioc->sense_dma);
if (!ioc->sense) {
- pr_err(MPT3SAS_FMT "sense pool: pci_pool_alloc failed\n",
- ioc->name);
+ ioc_err(ioc, "sense pool: pci_pool_alloc failed\n");
goto out;
}
}
- dinitprintk(ioc, pr_info(MPT3SAS_FMT
- "sense pool(0x%p): depth(%d), element_size(%d), pool_size"
- "(%d kB)\n", ioc->name, ioc->sense, ioc->scsiio_depth,
- SCSI_SENSE_BUFFERSIZE, sz/1024));
- dinitprintk(ioc, pr_info(MPT3SAS_FMT "sense_dma(0x%llx)\n",
- ioc->name, (unsigned long long)ioc->sense_dma));
+ dinitprintk(ioc,
+ ioc_info(ioc, "sense pool(0x%p): depth(%d), element_size(%d), pool_size(%d kB)\n",
+ ioc->sense, ioc->scsiio_depth,
+ SCSI_SENSE_BUFFERSIZE, sz / 1024));
+ dinitprintk(ioc,
+ ioc_info(ioc, "sense_dma(0x%llx)\n",
+ (unsigned long long)ioc->sense_dma));
total_sz += sz;
/* reply pool, 4 byte align */
@@ -4822,25 +4751,24 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc)
ioc->reply_dma_pool = dma_pool_create("reply pool", &ioc->pdev->dev, sz,
4, 0);
if (!ioc->reply_dma_pool) {
- pr_err(MPT3SAS_FMT "reply pool: dma_pool_create failed\n",
- ioc->name);
+ ioc_err(ioc, "reply pool: dma_pool_create failed\n");
goto out;
}
ioc->reply = dma_pool_alloc(ioc->reply_dma_pool, GFP_KERNEL,
&ioc->reply_dma);
if (!ioc->reply) {
- pr_err(MPT3SAS_FMT "reply pool: dma_pool_alloc failed\n",
- ioc->name);
+ ioc_err(ioc, "reply pool: dma_pool_alloc failed\n");
goto out;
}
ioc->reply_dma_min_address = (u32)(ioc->reply_dma);
ioc->reply_dma_max_address = (u32)(ioc->reply_dma) + sz;
- dinitprintk(ioc, pr_info(MPT3SAS_FMT
- "reply pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB)\n",
- ioc->name, ioc->reply,
- ioc->reply_free_queue_depth, ioc->reply_sz, sz/1024));
- dinitprintk(ioc, pr_info(MPT3SAS_FMT "reply_dma(0x%llx)\n",
- ioc->name, (unsigned long long)ioc->reply_dma));
+ dinitprintk(ioc,
+ ioc_info(ioc, "reply pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB)\n",
+ ioc->reply, ioc->reply_free_queue_depth,
+ ioc->reply_sz, sz / 1024));
+ dinitprintk(ioc,
+ ioc_info(ioc, "reply_dma(0x%llx)\n",
+ (unsigned long long)ioc->reply_dma));
total_sz += sz;
/* reply free queue, 16 byte align */
@@ -4848,24 +4776,22 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc)
ioc->reply_free_dma_pool = dma_pool_create("reply_free pool",
&ioc->pdev->dev, sz, 16, 0);
if (!ioc->reply_free_dma_pool) {
- pr_err(MPT3SAS_FMT "reply_free pool: dma_pool_create failed\n",
- ioc->name);
+ ioc_err(ioc, "reply_free pool: dma_pool_create failed\n");
goto out;
}
- ioc->reply_free = dma_pool_alloc(ioc->reply_free_dma_pool, GFP_KERNEL,
+ ioc->reply_free = dma_pool_zalloc(ioc->reply_free_dma_pool, GFP_KERNEL,
&ioc->reply_free_dma);
if (!ioc->reply_free) {
- pr_err(MPT3SAS_FMT "reply_free pool: dma_pool_alloc failed\n",
- ioc->name);
+ ioc_err(ioc, "reply_free pool: dma_pool_alloc failed\n");
goto out;
}
- memset(ioc->reply_free, 0, sz);
- dinitprintk(ioc, pr_info(MPT3SAS_FMT "reply_free pool(0x%p): " \
- "depth(%d), element_size(%d), pool_size(%d kB)\n", ioc->name,
- ioc->reply_free, ioc->reply_free_queue_depth, 4, sz/1024));
- dinitprintk(ioc, pr_info(MPT3SAS_FMT
- "reply_free_dma (0x%llx)\n",
- ioc->name, (unsigned long long)ioc->reply_free_dma));
+ dinitprintk(ioc,
+ ioc_info(ioc, "reply_free pool(0x%p): depth(%d), element_size(%d), pool_size(%d kB)\n",
+ ioc->reply_free, ioc->reply_free_queue_depth,
+ 4, sz / 1024));
+ dinitprintk(ioc,
+ ioc_info(ioc, "reply_free_dma (0x%llx)\n",
+ (unsigned long long)ioc->reply_free_dma));
total_sz += sz;
if (ioc->rdpq_array_enable) {
@@ -4876,8 +4802,7 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc)
&ioc->pdev->dev, reply_post_free_array_sz, 16, 0);
if (!ioc->reply_post_free_array_dma_pool) {
dinitprintk(ioc,
- pr_info(MPT3SAS_FMT "reply_post_free_array pool: "
- "dma_pool_create failed\n", ioc->name));
+ ioc_info(ioc, "reply_post_free_array pool: dma_pool_create failed\n"));
goto out;
}
ioc->reply_post_free_array =
@@ -4885,34 +4810,31 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc)
GFP_KERNEL, &ioc->reply_post_free_array_dma);
if (!ioc->reply_post_free_array) {
dinitprintk(ioc,
- pr_info(MPT3SAS_FMT "reply_post_free_array pool: "
- "dma_pool_alloc failed\n", ioc->name));
+ ioc_info(ioc, "reply_post_free_array pool: dma_pool_alloc failed\n"));
goto out;
}
}
ioc->config_page_sz = 512;
- ioc->config_page = pci_alloc_consistent(ioc->pdev,
- ioc->config_page_sz, &ioc->config_page_dma);
+ ioc->config_page = dma_alloc_coherent(&ioc->pdev->dev,
+ ioc->config_page_sz, &ioc->config_page_dma, GFP_KERNEL);
if (!ioc->config_page) {
- pr_err(MPT3SAS_FMT
- "config page: dma_pool_alloc failed\n",
- ioc->name);
+ ioc_err(ioc, "config page: dma_pool_alloc failed\n");
goto out;
}
- dinitprintk(ioc, pr_info(MPT3SAS_FMT
- "config page(0x%p): size(%d)\n",
- ioc->name, ioc->config_page, ioc->config_page_sz));
- dinitprintk(ioc, pr_info(MPT3SAS_FMT "config_page_dma(0x%llx)\n",
- ioc->name, (unsigned long long)ioc->config_page_dma));
+ dinitprintk(ioc,
+ ioc_info(ioc, "config page(0x%p): size(%d)\n",
+ ioc->config_page, ioc->config_page_sz));
+ dinitprintk(ioc,
+ ioc_info(ioc, "config_page_dma(0x%llx)\n",
+ (unsigned long long)ioc->config_page_dma));
total_sz += ioc->config_page_sz;
- pr_info(MPT3SAS_FMT "Allocated physical memory: size(%d kB)\n",
- ioc->name, total_sz/1024);
- pr_info(MPT3SAS_FMT
- "Current Controller Queue Depth(%d),Max Controller Queue Depth(%d)\n",
- ioc->name, ioc->shost->can_queue, facts->RequestCredit);
- pr_info(MPT3SAS_FMT "Scatter Gather Elements per IO(%d)\n",
- ioc->name, ioc->shost->sg_tablesize);
+ ioc_info(ioc, "Allocated physical memory: size(%d kB)\n",
+ total_sz / 1024);
+ ioc_info(ioc, "Current Controller Queue Depth(%d),Max Controller Queue Depth(%d)\n",
+ ioc->shost->can_queue, facts->RequestCredit);
+ ioc_info(ioc, "Scatter Gather Elements per IO(%d)\n",
+ ioc->shost->sg_tablesize);
return 0;
out:
@@ -4990,9 +4912,9 @@ _base_wait_for_doorbell_int(struct MPT3SAS_ADAPTER *ioc, int timeout)
do {
int_status = readl(&ioc->chip->HostInterruptStatus);
if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) {
- dhsprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: successful count(%d), timeout(%d)\n",
- ioc->name, __func__, count, timeout));
+ dhsprintk(ioc,
+ ioc_info(ioc, "%s: successful count(%d), timeout(%d)\n",
+ __func__, count, timeout));
return 0;
}
@@ -5000,9 +4922,8 @@ _base_wait_for_doorbell_int(struct MPT3SAS_ADAPTER *ioc, int timeout)
count++;
} while (--cntdn);
- pr_err(MPT3SAS_FMT
- "%s: failed due to timeout count(%d), int_status(%x)!\n",
- ioc->name, __func__, count, int_status);
+ ioc_err(ioc, "%s: failed due to timeout count(%d), int_status(%x)!\n",
+ __func__, count, int_status);
return -EFAULT;
}
@@ -5017,9 +4938,9 @@ _base_spin_on_doorbell_int(struct MPT3SAS_ADAPTER *ioc, int timeout)
do {
int_status = readl(&ioc->chip->HostInterruptStatus);
if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) {
- dhsprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: successful count(%d), timeout(%d)\n",
- ioc->name, __func__, count, timeout));
+ dhsprintk(ioc,
+ ioc_info(ioc, "%s: successful count(%d), timeout(%d)\n",
+ __func__, count, timeout));
return 0;
}
@@ -5027,9 +4948,8 @@ _base_spin_on_doorbell_int(struct MPT3SAS_ADAPTER *ioc, int timeout)
count++;
} while (--cntdn);
- pr_err(MPT3SAS_FMT
- "%s: failed due to timeout count(%d), int_status(%x)!\n",
- ioc->name, __func__, count, int_status);
+ ioc_err(ioc, "%s: failed due to timeout count(%d), int_status(%x)!\n",
+ __func__, count, int_status);
return -EFAULT;
}
@@ -5056,9 +4976,9 @@ _base_wait_for_doorbell_ack(struct MPT3SAS_ADAPTER *ioc, int timeout)
do {
int_status = readl(&ioc->chip->HostInterruptStatus);
if (!(int_status & MPI2_HIS_SYS2IOC_DB_STATUS)) {
- dhsprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: successful count(%d), timeout(%d)\n",
- ioc->name, __func__, count, timeout));
+ dhsprintk(ioc,
+ ioc_info(ioc, "%s: successful count(%d), timeout(%d)\n",
+ __func__, count, timeout));
return 0;
} else if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) {
doorbell = readl(&ioc->chip->Doorbell);
@@ -5075,9 +4995,8 @@ _base_wait_for_doorbell_ack(struct MPT3SAS_ADAPTER *ioc, int timeout)
} while (--cntdn);
out:
- pr_err(MPT3SAS_FMT
- "%s: failed due to timeout count(%d), int_status(%x)!\n",
- ioc->name, __func__, count, int_status);
+ ioc_err(ioc, "%s: failed due to timeout count(%d), int_status(%x)!\n",
+ __func__, count, int_status);
return -EFAULT;
}
@@ -5099,9 +5018,9 @@ _base_wait_for_doorbell_not_used(struct MPT3SAS_ADAPTER *ioc, int timeout)
do {
doorbell_reg = readl(&ioc->chip->Doorbell);
if (!(doorbell_reg & MPI2_DOORBELL_USED)) {
- dhsprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: successful count(%d), timeout(%d)\n",
- ioc->name, __func__, count, timeout));
+ dhsprintk(ioc,
+ ioc_info(ioc, "%s: successful count(%d), timeout(%d)\n",
+ __func__, count, timeout));
return 0;
}
@@ -5109,9 +5028,8 @@ _base_wait_for_doorbell_not_used(struct MPT3SAS_ADAPTER *ioc, int timeout)
count++;
} while (--cntdn);
- pr_err(MPT3SAS_FMT
- "%s: failed due to timeout count(%d), doorbell_reg(%x)!\n",
- ioc->name, __func__, count, doorbell_reg);
+ ioc_err(ioc, "%s: failed due to timeout count(%d), doorbell_reg(%x)!\n",
+ __func__, count, doorbell_reg);
return -EFAULT;
}
@@ -5130,8 +5048,7 @@ _base_send_ioc_reset(struct MPT3SAS_ADAPTER *ioc, u8 reset_type, int timeout)
int r = 0;
if (reset_type != MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET) {
- pr_err(MPT3SAS_FMT "%s: unknown reset_type\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: unknown reset_type\n", __func__);
return -EFAULT;
}
@@ -5139,7 +5056,7 @@ _base_send_ioc_reset(struct MPT3SAS_ADAPTER *ioc, u8 reset_type, int timeout)
MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY))
return -EFAULT;
- pr_info(MPT3SAS_FMT "sending message unit reset !!\n", ioc->name);
+ ioc_info(ioc, "sending message unit reset !!\n");
writel(reset_type << MPI2_DOORBELL_FUNCTION_SHIFT,
&ioc->chip->Doorbell);
@@ -5149,15 +5066,14 @@ _base_send_ioc_reset(struct MPT3SAS_ADAPTER *ioc, u8 reset_type, int timeout)
}
ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, timeout);
if (ioc_state) {
- pr_err(MPT3SAS_FMT
- "%s: failed going to ready state (ioc_state=0x%x)\n",
- ioc->name, __func__, ioc_state);
+ ioc_err(ioc, "%s: failed going to ready state (ioc_state=0x%x)\n",
+ __func__, ioc_state);
r = -EFAULT;
goto out;
}
out:
- pr_info(MPT3SAS_FMT "message unit reset: %s\n",
- ioc->name, ((r == 0) ? "SUCCESS" : "FAILED"));
+ ioc_info(ioc, "message unit reset: %s\n",
+ r == 0 ? "SUCCESS" : "FAILED");
return r;
}
@@ -5183,9 +5099,7 @@ _base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int request_bytes,
/* make sure doorbell is not in use */
if ((readl(&ioc->chip->Doorbell) & MPI2_DOORBELL_USED)) {
- pr_err(MPT3SAS_FMT
- "doorbell is in use (line=%d)\n",
- ioc->name, __LINE__);
+ ioc_err(ioc, "doorbell is in use (line=%d)\n", __LINE__);
return -EFAULT;
}
@@ -5200,17 +5114,15 @@ _base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int request_bytes,
&ioc->chip->Doorbell);
if ((_base_spin_on_doorbell_int(ioc, 5))) {
- pr_err(MPT3SAS_FMT
- "doorbell handshake int failed (line=%d)\n",
- ioc->name, __LINE__);
+ ioc_err(ioc, "doorbell handshake int failed (line=%d)\n",
+ __LINE__);
return -EFAULT;
}
writel(0, &ioc->chip->HostInterruptStatus);
if ((_base_wait_for_doorbell_ack(ioc, 5))) {
- pr_err(MPT3SAS_FMT
- "doorbell handshake ack failed (line=%d)\n",
- ioc->name, __LINE__);
+ ioc_err(ioc, "doorbell handshake ack failed (line=%d)\n",
+ __LINE__);
return -EFAULT;
}
@@ -5222,17 +5134,15 @@ _base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int request_bytes,
}
if (failed) {
- pr_err(MPT3SAS_FMT
- "doorbell handshake sending request failed (line=%d)\n",
- ioc->name, __LINE__);
+ ioc_err(ioc, "doorbell handshake sending request failed (line=%d)\n",
+ __LINE__);
return -EFAULT;
}
/* now wait for the reply */
if ((_base_wait_for_doorbell_int(ioc, timeout))) {
- pr_err(MPT3SAS_FMT
- "doorbell handshake int failed (line=%d)\n",
- ioc->name, __LINE__);
+ ioc_err(ioc, "doorbell handshake int failed (line=%d)\n",
+ __LINE__);
return -EFAULT;
}
@@ -5241,9 +5151,8 @@ _base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int request_bytes,
& MPI2_DOORBELL_DATA_MASK);
writel(0, &ioc->chip->HostInterruptStatus);
if ((_base_wait_for_doorbell_int(ioc, 5))) {
- pr_err(MPT3SAS_FMT
- "doorbell handshake int failed (line=%d)\n",
- ioc->name, __LINE__);
+ ioc_err(ioc, "doorbell handshake int failed (line=%d)\n",
+ __LINE__);
return -EFAULT;
}
reply[1] = le16_to_cpu(readl(&ioc->chip->Doorbell)
@@ -5252,9 +5161,8 @@ _base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int request_bytes,
for (i = 2; i < default_reply->MsgLength * 2; i++) {
if ((_base_wait_for_doorbell_int(ioc, 5))) {
- pr_err(MPT3SAS_FMT
- "doorbell handshake int failed (line=%d)\n",
- ioc->name, __LINE__);
+ ioc_err(ioc, "doorbell handshake int failed (line=%d)\n",
+ __LINE__);
return -EFAULT;
}
if (i >= reply_bytes/2) /* overflow case */
@@ -5267,8 +5175,9 @@ _base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int request_bytes,
_base_wait_for_doorbell_int(ioc, 5);
if (_base_wait_for_doorbell_not_used(ioc, 5) != 0) {
- dhsprintk(ioc, pr_info(MPT3SAS_FMT
- "doorbell is in use (line=%d)\n", ioc->name, __LINE__));
+ dhsprintk(ioc,
+ ioc_info(ioc, "doorbell is in use (line=%d)\n",
+ __LINE__));
}
writel(0, &ioc->chip->HostInterruptStatus);
@@ -5308,14 +5217,12 @@ mpt3sas_base_sas_iounit_control(struct MPT3SAS_ADAPTER *ioc,
void *request;
u16 wait_state_count;
- dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- __func__));
+ dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__));
mutex_lock(&ioc->base_cmds.mutex);
if (ioc->base_cmds.status != MPT3_CMD_NOT_USED) {
- pr_err(MPT3SAS_FMT "%s: base_cmd in use\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: base_cmd in use\n", __func__);
rc = -EAGAIN;
goto out;
}
@@ -5324,23 +5231,20 @@ mpt3sas_base_sas_iounit_control(struct MPT3SAS_ADAPTER *ioc,
ioc_state = mpt3sas_base_get_iocstate(ioc, 1);
while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
if (wait_state_count++ == 10) {
- pr_err(MPT3SAS_FMT
- "%s: failed due to ioc not operational\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: failed due to ioc not operational\n",
+ __func__);
rc = -EFAULT;
goto out;
}
ssleep(1);
ioc_state = mpt3sas_base_get_iocstate(ioc, 1);
- pr_info(MPT3SAS_FMT
- "%s: waiting for operational state(count=%d)\n",
- ioc->name, __func__, wait_state_count);
+ ioc_info(ioc, "%s: waiting for operational state(count=%d)\n",
+ __func__, wait_state_count);
}
smid = mpt3sas_base_get_smid(ioc, ioc->base_cb_idx);
if (!smid) {
- pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);
rc = -EAGAIN;
goto out;
}
@@ -5408,14 +5312,12 @@ mpt3sas_base_scsi_enclosure_processor(struct MPT3SAS_ADAPTER *ioc,
void *request;
u16 wait_state_count;
- dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- __func__));
+ dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__));
mutex_lock(&ioc->base_cmds.mutex);
if (ioc->base_cmds.status != MPT3_CMD_NOT_USED) {
- pr_err(MPT3SAS_FMT "%s: base_cmd in use\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: base_cmd in use\n", __func__);
rc = -EAGAIN;
goto out;
}
@@ -5424,24 +5326,20 @@ mpt3sas_base_scsi_enclosure_processor(struct MPT3SAS_ADAPTER *ioc,
ioc_state = mpt3sas_base_get_iocstate(ioc, 1);
while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
if (wait_state_count++ == 10) {
- pr_err(MPT3SAS_FMT
- "%s: failed due to ioc not operational\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: failed due to ioc not operational\n",
+ __func__);
rc = -EFAULT;
goto out;
}
ssleep(1);
ioc_state = mpt3sas_base_get_iocstate(ioc, 1);
- pr_info(MPT3SAS_FMT
- "%s: waiting for operational state(count=%d)\n",
- ioc->name,
- __func__, wait_state_count);
+ ioc_info(ioc, "%s: waiting for operational state(count=%d)\n",
+ __func__, wait_state_count);
}
smid = mpt3sas_base_get_smid(ioc, ioc->base_cb_idx);
if (!smid) {
- pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);
rc = -EAGAIN;
goto out;
}
@@ -5495,8 +5393,7 @@ _base_get_port_facts(struct MPT3SAS_ADAPTER *ioc, int port)
struct mpt3sas_port_facts *pfacts;
int mpi_reply_sz, mpi_request_sz, r;
- dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- __func__));
+ dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__));
mpi_reply_sz = sizeof(Mpi2PortFactsReply_t);
mpi_request_sz = sizeof(Mpi2PortFactsRequest_t);
@@ -5507,8 +5404,7 @@ _base_get_port_facts(struct MPT3SAS_ADAPTER *ioc, int port)
(u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5);
if (r != 0) {
- pr_err(MPT3SAS_FMT "%s: handshake failed (r=%d)\n",
- ioc->name, __func__, r);
+ ioc_err(ioc, "%s: handshake failed (r=%d)\n", __func__, r);
return r;
}
@@ -5536,26 +5432,26 @@ _base_wait_for_iocstate(struct MPT3SAS_ADAPTER *ioc, int timeout)
u32 ioc_state;
int rc;
- dinitprintk(ioc, printk(MPT3SAS_FMT "%s\n", ioc->name,
- __func__));
+ dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__));
if (ioc->pci_error_recovery) {
- dfailprintk(ioc, printk(MPT3SAS_FMT
- "%s: host in pci error recovery\n", ioc->name, __func__));
+ dfailprintk(ioc,
+ ioc_info(ioc, "%s: host in pci error recovery\n",
+ __func__));
return -EFAULT;
}
ioc_state = mpt3sas_base_get_iocstate(ioc, 0);
- dhsprintk(ioc, printk(MPT3SAS_FMT "%s: ioc_state(0x%08x)\n",
- ioc->name, __func__, ioc_state));
+ dhsprintk(ioc,
+ ioc_info(ioc, "%s: ioc_state(0x%08x)\n",
+ __func__, ioc_state));
if (((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_READY) ||
(ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_OPERATIONAL)
return 0;
if (ioc_state & MPI2_DOORBELL_USED) {
- dhsprintk(ioc, printk(MPT3SAS_FMT
- "unexpected doorbell active!\n", ioc->name));
+ dhsprintk(ioc, ioc_info(ioc, "unexpected doorbell active!\n"));
goto issue_diag_reset;
}
@@ -5567,9 +5463,9 @@ _base_wait_for_iocstate(struct MPT3SAS_ADAPTER *ioc, int timeout)
ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, timeout);
if (ioc_state) {
- dfailprintk(ioc, printk(MPT3SAS_FMT
- "%s: failed going to ready state (ioc_state=0x%x)\n",
- ioc->name, __func__, ioc_state));
+ dfailprintk(ioc,
+ ioc_info(ioc, "%s: failed going to ready state (ioc_state=0x%x)\n",
+ __func__, ioc_state));
return -EFAULT;
}
@@ -5592,14 +5488,13 @@ _base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc)
struct mpt3sas_facts *facts;
int mpi_reply_sz, mpi_request_sz, r;
- dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- __func__));
+ dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__));
r = _base_wait_for_iocstate(ioc, 10);
if (r) {
- dfailprintk(ioc, printk(MPT3SAS_FMT
- "%s: failed getting to correct state\n",
- ioc->name, __func__));
+ dfailprintk(ioc,
+ ioc_info(ioc, "%s: failed getting to correct state\n",
+ __func__));
return r;
}
mpi_reply_sz = sizeof(Mpi2IOCFactsReply_t);
@@ -5610,8 +5505,7 @@ _base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc)
(u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5);
if (r != 0) {
- pr_err(MPT3SAS_FMT "%s: handshake failed (r=%d)\n",
- ioc->name, __func__, r);
+ ioc_err(ioc, "%s: handshake failed (r=%d)\n", __func__, r);
return r;
}
@@ -5663,20 +5557,20 @@ _base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc)
*/
ioc->page_size = 1 << facts->CurrentHostPageSize;
if (ioc->page_size == 1) {
- pr_info(MPT3SAS_FMT "CurrentHostPageSize is 0: Setting "
- "default host page size to 4k\n", ioc->name);
+ ioc_info(ioc, "CurrentHostPageSize is 0: Setting default host page size to 4k\n");
ioc->page_size = 1 << MPT3SAS_HOST_PAGE_SIZE_4K;
}
- dinitprintk(ioc, pr_info(MPT3SAS_FMT "CurrentHostPageSize(%d)\n",
- ioc->name, facts->CurrentHostPageSize));
-
- dinitprintk(ioc, pr_info(MPT3SAS_FMT
- "hba queue depth(%d), max chains per io(%d)\n",
- ioc->name, facts->RequestCredit,
- facts->MaxChainDepth));
- dinitprintk(ioc, pr_info(MPT3SAS_FMT
- "request frame size(%d), reply frame size(%d)\n", ioc->name,
- facts->IOCRequestFrameSize * 4, facts->ReplyFrameSize * 4));
+ dinitprintk(ioc,
+ ioc_info(ioc, "CurrentHostPageSize(%d)\n",
+ facts->CurrentHostPageSize));
+
+ dinitprintk(ioc,
+ ioc_info(ioc, "hba queue depth(%d), max chains per io(%d)\n",
+ facts->RequestCredit, facts->MaxChainDepth));
+ dinitprintk(ioc,
+ ioc_info(ioc, "request frame size(%d), reply frame size(%d)\n",
+ facts->IOCRequestFrameSize * 4,
+ facts->ReplyFrameSize * 4));
return 0;
}
@@ -5696,8 +5590,7 @@ _base_send_ioc_init(struct MPT3SAS_ADAPTER *ioc)
u16 ioc_status;
u32 reply_post_free_array_sz = 0;
- dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- __func__));
+ dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__));
memset(&mpi_request, 0, sizeof(Mpi2IOCInitRequest_t));
mpi_request.Function = MPI2_FUNCTION_IOC_INIT;
@@ -5763,15 +5656,14 @@ _base_send_ioc_init(struct MPT3SAS_ADAPTER *ioc)
sizeof(Mpi2IOCInitReply_t), (u16 *)&mpi_reply, 10);
if (r != 0) {
- pr_err(MPT3SAS_FMT "%s: handshake failed (r=%d)\n",
- ioc->name, __func__, r);
+ ioc_err(ioc, "%s: handshake failed (r=%d)\n", __func__, r);
return r;
}
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
if (ioc_status != MPI2_IOCSTATUS_SUCCESS ||
mpi_reply.IOCLogInfo) {
- pr_err(MPT3SAS_FMT "%s: failed\n", ioc->name, __func__);
+ ioc_err(ioc, "%s: failed\n", __func__);
r = -EIO;
}
@@ -5842,18 +5734,16 @@ _base_send_port_enable(struct MPT3SAS_ADAPTER *ioc)
u16 smid;
u16 ioc_status;
- pr_info(MPT3SAS_FMT "sending port enable !!\n", ioc->name);
+ ioc_info(ioc, "sending port enable !!\n");
if (ioc->port_enable_cmds.status & MPT3_CMD_PENDING) {
- pr_err(MPT3SAS_FMT "%s: internal command already in use\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: internal command already in use\n", __func__);
return -EAGAIN;
}
smid = mpt3sas_base_get_smid(ioc, ioc->port_enable_cb_idx);
if (!smid) {
- pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);
return -EAGAIN;
}
@@ -5867,8 +5757,7 @@ _base_send_port_enable(struct MPT3SAS_ADAPTER *ioc)
mpt3sas_base_put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->port_enable_cmds.done, 300*HZ);
if (!(ioc->port_enable_cmds.status & MPT3_CMD_COMPLETE)) {
- pr_err(MPT3SAS_FMT "%s: timeout\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: timeout\n", __func__);
_debug_dump_mf(mpi_request,
sizeof(Mpi2PortEnableRequest_t)/4);
if (ioc->port_enable_cmds.status & MPT3_CMD_RESET)
@@ -5881,16 +5770,15 @@ _base_send_port_enable(struct MPT3SAS_ADAPTER *ioc)
mpi_reply = ioc->port_enable_cmds.reply;
ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- pr_err(MPT3SAS_FMT "%s: failed with (ioc_status=0x%08x)\n",
- ioc->name, __func__, ioc_status);
+ ioc_err(ioc, "%s: failed with (ioc_status=0x%08x)\n",
+ __func__, ioc_status);
r = -EFAULT;
goto out;
}
out:
ioc->port_enable_cmds.status = MPT3_CMD_NOT_USED;
- pr_info(MPT3SAS_FMT "port enable: %s\n", ioc->name, ((r == 0) ?
- "SUCCESS" : "FAILED"));
+ ioc_info(ioc, "port enable: %s\n", r == 0 ? "SUCCESS" : "FAILED");
return r;
}
@@ -5906,18 +5794,16 @@ mpt3sas_port_enable(struct MPT3SAS_ADAPTER *ioc)
Mpi2PortEnableRequest_t *mpi_request;
u16 smid;
- pr_info(MPT3SAS_FMT "sending port enable !!\n", ioc->name);
+ ioc_info(ioc, "sending port enable !!\n");
if (ioc->port_enable_cmds.status & MPT3_CMD_PENDING) {
- pr_err(MPT3SAS_FMT "%s: internal command already in use\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: internal command already in use\n", __func__);
return -EAGAIN;
}
smid = mpt3sas_base_get_smid(ioc, ioc->port_enable_cb_idx);
if (!smid) {
- pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);
return -EAGAIN;
}
@@ -6020,19 +5906,16 @@ _base_event_notification(struct MPT3SAS_ADAPTER *ioc)
int r = 0;
int i;
- dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- __func__));
+ dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__));
if (ioc->base_cmds.status & MPT3_CMD_PENDING) {
- pr_err(MPT3SAS_FMT "%s: internal command already in use\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: internal command already in use\n", __func__);
return -EAGAIN;
}
smid = mpt3sas_base_get_smid(ioc, ioc->base_cb_idx);
if (!smid) {
- pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);
return -EAGAIN;
}
ioc->base_cmds.status = MPT3_CMD_PENDING;
@@ -6049,8 +5932,7 @@ _base_event_notification(struct MPT3SAS_ADAPTER *ioc)
mpt3sas_base_put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->base_cmds.done, 30*HZ);
if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) {
- pr_err(MPT3SAS_FMT "%s: timeout\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: timeout\n", __func__);
_debug_dump_mf(mpi_request,
sizeof(Mpi2EventNotificationRequest_t)/4);
if (ioc->base_cmds.status & MPT3_CMD_RESET)
@@ -6058,8 +5940,7 @@ _base_event_notification(struct MPT3SAS_ADAPTER *ioc)
else
r = -ETIME;
} else
- dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s: complete\n",
- ioc->name, __func__));
+ dinitprintk(ioc, ioc_info(ioc, "%s: complete\n", __func__));
ioc->base_cmds.status = MPT3_CMD_NOT_USED;
return r;
}
@@ -6115,18 +5996,16 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc)
u32 count;
u32 hcb_size;
- pr_info(MPT3SAS_FMT "sending diag reset !!\n", ioc->name);
+ ioc_info(ioc, "sending diag reset !!\n");
- drsprintk(ioc, pr_info(MPT3SAS_FMT "clear interrupts\n",
- ioc->name));
+ drsprintk(ioc, ioc_info(ioc, "clear interrupts\n"));
count = 0;
do {
/* Write magic sequence to WriteSequence register
* Loop until in diagnostic mode
*/
- drsprintk(ioc, pr_info(MPT3SAS_FMT
- "write magic sequence\n", ioc->name));
+ drsprintk(ioc, ioc_info(ioc, "write magic sequence\n"));
writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence);
writel(MPI2_WRSEQ_1ST_KEY_VALUE, &ioc->chip->WriteSequence);
writel(MPI2_WRSEQ_2ND_KEY_VALUE, &ioc->chip->WriteSequence);
@@ -6142,16 +6021,15 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc)
goto out;
host_diagnostic = readl(&ioc->chip->HostDiagnostic);
- drsprintk(ioc, pr_info(MPT3SAS_FMT
- "wrote magic sequence: count(%d), host_diagnostic(0x%08x)\n",
- ioc->name, count, host_diagnostic));
+ drsprintk(ioc,
+ ioc_info(ioc, "wrote magic sequence: count(%d), host_diagnostic(0x%08x)\n",
+ count, host_diagnostic));
} while ((host_diagnostic & MPI2_DIAG_DIAG_WRITE_ENABLE) == 0);
hcb_size = readl(&ioc->chip->HCBSize);
- drsprintk(ioc, pr_info(MPT3SAS_FMT "diag reset: issued\n",
- ioc->name));
+ drsprintk(ioc, ioc_info(ioc, "diag reset: issued\n"));
writel(host_diagnostic | MPI2_DIAG_RESET_ADAPTER,
&ioc->chip->HostDiagnostic);
@@ -6174,43 +6052,38 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc)
if (host_diagnostic & MPI2_DIAG_HCB_MODE) {
- drsprintk(ioc, pr_info(MPT3SAS_FMT
- "restart the adapter assuming the HCB Address points to good F/W\n",
- ioc->name));
+ drsprintk(ioc,
+ ioc_info(ioc, "restart the adapter assuming the HCB Address points to good F/W\n"));
host_diagnostic &= ~MPI2_DIAG_BOOT_DEVICE_SELECT_MASK;
host_diagnostic |= MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW;
writel(host_diagnostic, &ioc->chip->HostDiagnostic);
- drsprintk(ioc, pr_info(MPT3SAS_FMT
- "re-enable the HCDW\n", ioc->name));
+ drsprintk(ioc, ioc_info(ioc, "re-enable the HCDW\n"));
writel(hcb_size | MPI2_HCB_SIZE_HCB_ENABLE,
&ioc->chip->HCBSize);
}
- drsprintk(ioc, pr_info(MPT3SAS_FMT "restart the adapter\n",
- ioc->name));
+ drsprintk(ioc, ioc_info(ioc, "restart the adapter\n"));
writel(host_diagnostic & ~MPI2_DIAG_HOLD_IOC_RESET,
&ioc->chip->HostDiagnostic);
- drsprintk(ioc, pr_info(MPT3SAS_FMT
- "disable writes to the diagnostic register\n", ioc->name));
+ drsprintk(ioc,
+ ioc_info(ioc, "disable writes to the diagnostic register\n"));
writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence);
- drsprintk(ioc, pr_info(MPT3SAS_FMT
- "Wait for FW to go to the READY state\n", ioc->name));
+ drsprintk(ioc, ioc_info(ioc, "Wait for FW to go to the READY state\n"));
ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, 20);
if (ioc_state) {
- pr_err(MPT3SAS_FMT
- "%s: failed going to ready state (ioc_state=0x%x)\n",
- ioc->name, __func__, ioc_state);
+ ioc_err(ioc, "%s: failed going to ready state (ioc_state=0x%x)\n",
+ __func__, ioc_state);
goto out;
}
- pr_info(MPT3SAS_FMT "diag reset: SUCCESS\n", ioc->name);
+ ioc_info(ioc, "diag reset: SUCCESS\n");
return 0;
out:
- pr_err(MPT3SAS_FMT "diag reset: FAILED\n", ioc->name);
+ ioc_err(ioc, "diag reset: FAILED\n");
return -EFAULT;
}
@@ -6228,15 +6101,15 @@ _base_make_ioc_ready(struct MPT3SAS_ADAPTER *ioc, enum reset_type type)
int rc;
int count;
- dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- __func__));
+ dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__));
if (ioc->pci_error_recovery)
return 0;
ioc_state = mpt3sas_base_get_iocstate(ioc, 0);
- dhsprintk(ioc, pr_info(MPT3SAS_FMT "%s: ioc_state(0x%08x)\n",
- ioc->name, __func__, ioc_state));
+ dhsprintk(ioc,
+ ioc_info(ioc, "%s: ioc_state(0x%08x)\n",
+ __func__, ioc_state));
/* if in RESET state, it should move to READY state shortly */
count = 0;
@@ -6244,9 +6117,8 @@ _base_make_ioc_ready(struct MPT3SAS_ADAPTER *ioc, enum reset_type type)
while ((ioc_state & MPI2_IOC_STATE_MASK) !=
MPI2_IOC_STATE_READY) {
if (count++ == 10) {
- pr_err(MPT3SAS_FMT
- "%s: failed going to ready state (ioc_state=0x%x)\n",
- ioc->name, __func__, ioc_state);
+ ioc_err(ioc, "%s: failed going to ready state (ioc_state=0x%x)\n",
+ __func__, ioc_state);
return -EFAULT;
}
ssleep(1);
@@ -6258,9 +6130,7 @@ _base_make_ioc_ready(struct MPT3SAS_ADAPTER *ioc, enum reset_type type)
return 0;
if (ioc_state & MPI2_DOORBELL_USED) {
- dhsprintk(ioc, pr_info(MPT3SAS_FMT
- "unexpected doorbell active!\n",
- ioc->name));
+ dhsprintk(ioc, ioc_info(ioc, "unexpected doorbell active!\n"));
goto issue_diag_reset;
}
@@ -6304,8 +6174,7 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc)
struct adapter_reply_queue *reply_q;
Mpi2ReplyDescriptorsUnion_t *reply_post_free_contig;
- dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- __func__));
+ dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__));
/* clean the delayed target reset list */
list_for_each_entry_safe(delayed_tr, delayed_tr_next,
@@ -6465,8 +6334,7 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc)
void
mpt3sas_base_free_resources(struct MPT3SAS_ADAPTER *ioc)
{
- dexitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- __func__));
+ dexitprintk(ioc, ioc_info(ioc, "%s\n", __func__));
/* synchronizing freeing resource with pci_access_mutex lock */
mutex_lock(&ioc->pci_access_mutex);
@@ -6494,8 +6362,7 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
int r, i;
int cpu_id, last_cpu_id = 0;
- dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- __func__));
+ dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__));
/* setup cpu_msix_table */
ioc->cpu_count = num_online_cpus();
@@ -6505,9 +6372,8 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
ioc->cpu_msix_table = kzalloc(ioc->cpu_msix_table_sz, GFP_KERNEL);
ioc->reply_queue_count = 1;
if (!ioc->cpu_msix_table) {
- dfailprintk(ioc, pr_info(MPT3SAS_FMT
- "allocation for cpu_msix_table failed!!!\n",
- ioc->name));
+ dfailprintk(ioc,
+ ioc_info(ioc, "allocation for cpu_msix_table failed!!!\n"));
r = -ENOMEM;
goto out_free_resources;
}
@@ -6516,9 +6382,8 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
ioc->reply_post_host_index = kcalloc(ioc->cpu_msix_table_sz,
sizeof(resource_size_t *), GFP_KERNEL);
if (!ioc->reply_post_host_index) {
- dfailprintk(ioc, pr_info(MPT3SAS_FMT "allocation "
- "for reply_post_host_index failed!!!\n",
- ioc->name));
+ dfailprintk(ioc,
+ ioc_info(ioc, "allocation for reply_post_host_index failed!!!\n"));
r = -ENOMEM;
goto out_free_resources;
}
@@ -6747,8 +6612,7 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
void
mpt3sas_base_detach(struct MPT3SAS_ADAPTER *ioc)
{
- dexitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- __func__));
+ dexitprintk(ioc, ioc_info(ioc, "%s\n", __func__));
mpt3sas_base_stop_watchdog(ioc);
mpt3sas_base_free_resources(ioc);
@@ -6781,8 +6645,7 @@ static void _base_pre_reset_handler(struct MPT3SAS_ADAPTER *ioc)
{
mpt3sas_scsih_pre_reset_handler(ioc);
mpt3sas_ctl_pre_reset_handler(ioc);
- dtmprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: MPT3_IOC_PRE_RESET\n", ioc->name, __func__));
+ dtmprintk(ioc, ioc_info(ioc, "%s: MPT3_IOC_PRE_RESET\n", __func__));
}
/**
@@ -6793,8 +6656,7 @@ static void _base_after_reset_handler(struct MPT3SAS_ADAPTER *ioc)
{
mpt3sas_scsih_after_reset_handler(ioc);
mpt3sas_ctl_after_reset_handler(ioc);
- dtmprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: MPT3_IOC_AFTER_RESET\n", ioc->name, __func__));
+ dtmprintk(ioc, ioc_info(ioc, "%s: MPT3_IOC_AFTER_RESET\n", __func__));
if (ioc->transport_cmds.status & MPT3_CMD_PENDING) {
ioc->transport_cmds.status |= MPT3_CMD_RESET;
mpt3sas_base_free_smid(ioc, ioc->transport_cmds.smid);
@@ -6835,8 +6697,7 @@ static void _base_reset_done_handler(struct MPT3SAS_ADAPTER *ioc)
{
mpt3sas_scsih_reset_done_handler(ioc);
mpt3sas_ctl_reset_done_handler(ioc);
- dtmprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: MPT3_IOC_DONE_RESET\n", ioc->name, __func__));
+ dtmprintk(ioc, ioc_info(ioc, "%s: MPT3_IOC_DONE_RESET\n", __func__));
}
/**
@@ -6883,12 +6744,10 @@ mpt3sas_base_hard_reset_handler(struct MPT3SAS_ADAPTER *ioc,
u32 ioc_state;
u8 is_fault = 0, is_trigger = 0;
- dtmprintk(ioc, pr_info(MPT3SAS_FMT "%s: enter\n", ioc->name,
- __func__));
+ dtmprintk(ioc, ioc_info(ioc, "%s: enter\n", __func__));
if (ioc->pci_error_recovery) {
- pr_err(MPT3SAS_FMT "%s: pci error recovery reset\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: pci error recovery reset\n", __func__);
r = 0;
goto out_unlocked;
}
@@ -6942,8 +6801,9 @@ mpt3sas_base_hard_reset_handler(struct MPT3SAS_ADAPTER *ioc,
_base_reset_done_handler(ioc);
out:
- dtmprintk(ioc, pr_info(MPT3SAS_FMT "%s: %s\n",
- ioc->name, __func__, ((r == 0) ? "SUCCESS" : "FAILED")));
+ dtmprintk(ioc,
+ ioc_info(ioc, "%s: %s\n",
+ __func__, r == 0 ? "SUCCESS" : "FAILED"));
spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
ioc->shost_recovery = 0;
@@ -6959,7 +6819,6 @@ mpt3sas_base_hard_reset_handler(struct MPT3SAS_ADAPTER *ioc,
mpt3sas_trigger_master(ioc,
MASTER_TRIGGER_ADAPTER_RESET);
}
- dtmprintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name,
- __func__));
+ dtmprintk(ioc, ioc_info(ioc, "%s: exit\n", __func__));
return r;
}
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h
index 96dc15e90bd8..8f1d6b071b39 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.h
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.h
@@ -158,7 +158,14 @@ struct mpt3sas_nvme_cmd {
/*
* logging format
*/
-#define MPT3SAS_FMT "%s: "
+#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__)
/*
* WarpDrive Specific Log codes
diff --git a/drivers/scsi/mpt3sas/mpt3sas_config.c b/drivers/scsi/mpt3sas/mpt3sas_config.c
index d29a2dcc7d0e..02209447f4ef 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_config.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_config.c
@@ -175,20 +175,18 @@ _config_display_some_debug(struct MPT3SAS_ADAPTER *ioc, u16 smid,
if (!desc)
return;
- pr_info(MPT3SAS_FMT
- "%s: %s(%d), action(%d), form(0x%08x), smid(%d)\n",
- ioc->name, calling_function_name, desc,
- mpi_request->Header.PageNumber, mpi_request->Action,
- le32_to_cpu(mpi_request->PageAddress), smid);
+ ioc_info(ioc, "%s: %s(%d), action(%d), form(0x%08x), smid(%d)\n",
+ calling_function_name, desc,
+ mpi_request->Header.PageNumber, mpi_request->Action,
+ le32_to_cpu(mpi_request->PageAddress), smid);
if (!mpi_reply)
return;
if (mpi_reply->IOCStatus || mpi_reply->IOCLogInfo)
- pr_info(MPT3SAS_FMT
- "\tiocstatus(0x%04x), loginfo(0x%08x)\n",
- ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
- le32_to_cpu(mpi_reply->IOCLogInfo));
+ ioc_info(ioc, "\tiocstatus(0x%04x), loginfo(0x%08x)\n",
+ le16_to_cpu(mpi_reply->IOCStatus),
+ le32_to_cpu(mpi_reply->IOCLogInfo));
}
/**
@@ -210,9 +208,8 @@ _config_alloc_config_dma_memory(struct MPT3SAS_ADAPTER *ioc,
mem->page = dma_alloc_coherent(&ioc->pdev->dev, mem->sz,
&mem->page_dma, GFP_KERNEL);
if (!mem->page) {
- pr_err(MPT3SAS_FMT
- "%s: dma_alloc_coherent failed asking for (%d) bytes!!\n",
- ioc->name, __func__, mem->sz);
+ ioc_err(ioc, "%s: dma_alloc_coherent failed asking for (%d) bytes!!\n",
+ __func__, mem->sz);
r = -ENOMEM;
}
} else { /* use tmp buffer if less than 512 bytes */
@@ -313,8 +310,7 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
mutex_lock(&ioc->config_cmds.mutex);
if (ioc->config_cmds.status != MPT3_CMD_NOT_USED) {
- pr_err(MPT3SAS_FMT "%s: config_cmd in use\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: config_cmd in use\n", __func__);
mutex_unlock(&ioc->config_cmds.mutex);
return -EAGAIN;
}
@@ -362,34 +358,30 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
r = -EFAULT;
goto free_mem;
}
- pr_info(MPT3SAS_FMT "%s: attempting retry (%d)\n",
- ioc->name, __func__, retry_count);
+ ioc_info(ioc, "%s: attempting retry (%d)\n",
+ __func__, retry_count);
}
wait_state_count = 0;
ioc_state = mpt3sas_base_get_iocstate(ioc, 1);
while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
if (wait_state_count++ == MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT) {
- pr_err(MPT3SAS_FMT
- "%s: failed due to ioc not operational\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: failed due to ioc not operational\n",
+ __func__);
ioc->config_cmds.status = MPT3_CMD_NOT_USED;
r = -EFAULT;
goto free_mem;
}
ssleep(1);
ioc_state = mpt3sas_base_get_iocstate(ioc, 1);
- pr_info(MPT3SAS_FMT
- "%s: waiting for operational state(count=%d)\n",
- ioc->name, __func__, wait_state_count);
+ ioc_info(ioc, "%s: waiting for operational state(count=%d)\n",
+ __func__, wait_state_count);
}
if (wait_state_count)
- pr_info(MPT3SAS_FMT "%s: ioc is operational\n",
- ioc->name, __func__);
+ ioc_info(ioc, "%s: ioc is operational\n", __func__);
smid = mpt3sas_base_get_smid(ioc, ioc->config_cb_idx);
if (!smid) {
- pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);
ioc->config_cmds.status = MPT3_CMD_NOT_USED;
r = -EAGAIN;
goto free_mem;
@@ -429,12 +421,10 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
(mpi_reply->Header.PageType & 0xF)) {
_debug_dump_mf(mpi_request, ioc->request_sz/4);
_debug_dump_reply(mpi_reply, ioc->request_sz/4);
- panic(KERN_WARNING MPT3SAS_FMT "%s: Firmware BUG:" \
- " mpi_reply mismatch: Requested PageType(0x%02x)" \
- " Reply PageType(0x%02x)\n", \
- ioc->name, __func__,
- (mpi_request->Header.PageType & 0xF),
- (mpi_reply->Header.PageType & 0xF));
+ panic("%s: %s: Firmware BUG: mpi_reply mismatch: Requested PageType(0x%02x) Reply PageType(0x%02x)\n",
+ ioc->name, __func__,
+ mpi_request->Header.PageType & 0xF,
+ mpi_reply->Header.PageType & 0xF);
}
if (((mpi_request->Header.PageType & 0xF) ==
@@ -442,19 +432,18 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
mpi_request->ExtPageType != mpi_reply->ExtPageType) {
_debug_dump_mf(mpi_request, ioc->request_sz/4);
_debug_dump_reply(mpi_reply, ioc->request_sz/4);
- panic(KERN_WARNING MPT3SAS_FMT "%s: Firmware BUG:" \
- " mpi_reply mismatch: Requested ExtPageType(0x%02x)"
- " Reply ExtPageType(0x%02x)\n",
- ioc->name, __func__, mpi_request->ExtPageType,
- mpi_reply->ExtPageType);
+ panic("%s: %s: Firmware BUG: mpi_reply mismatch: Requested ExtPageType(0x%02x) Reply ExtPageType(0x%02x)\n",
+ ioc->name, __func__,
+ mpi_request->ExtPageType,
+ mpi_reply->ExtPageType);
}
ioc_status = le16_to_cpu(mpi_reply->IOCStatus)
& MPI2_IOCSTATUS_MASK;
}
if (retry_count)
- pr_info(MPT3SAS_FMT "%s: retry (%d) completed!!\n", \
- ioc->name, __func__, retry_count);
+ ioc_info(ioc, "%s: retry (%d) completed!!\n",
+ __func__, retry_count);
if ((ioc_status == MPI2_IOCSTATUS_SUCCESS) &&
config_page && mpi_request->Action ==
@@ -469,14 +458,10 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
_debug_dump_reply(mpi_reply, ioc->request_sz/4);
_debug_dump_config(p, min_t(u16, mem.sz,
config_page_sz)/4);
- panic(KERN_WARNING MPT3SAS_FMT
- "%s: Firmware BUG:" \
- " config page mismatch:"
- " Requested PageType(0x%02x)"
- " Reply PageType(0x%02x)\n",
- ioc->name, __func__,
- (mpi_request->Header.PageType & 0xF),
- (p[3] & 0xF));
+ panic("%s: %s: Firmware BUG: config page mismatch: Requested PageType(0x%02x) Reply PageType(0x%02x)\n",
+ ioc->name, __func__,
+ mpi_request->Header.PageType & 0xF,
+ p[3] & 0xF);
}
if (((mpi_request->Header.PageType & 0xF) ==
@@ -486,13 +471,9 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
_debug_dump_reply(mpi_reply, ioc->request_sz/4);
_debug_dump_config(p, min_t(u16, mem.sz,
config_page_sz)/4);
- panic(KERN_WARNING MPT3SAS_FMT
- "%s: Firmware BUG:" \
- " config page mismatch:"
- " Requested ExtPageType(0x%02x)"
- " Reply ExtPageType(0x%02x)\n",
- ioc->name, __func__,
- mpi_request->ExtPageType, p[6]);
+ panic("%s: %s: Firmware BUG: config page mismatch: Requested ExtPageType(0x%02x) Reply ExtPageType(0x%02x)\n",
+ ioc->name, __func__,
+ mpi_request->ExtPageType, p[6]);
}
}
memcpy(config_page, mem.page, min_t(u16, mem.sz,
diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c
index 5e8c059ce2c9..4afa597cbfba 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c
@@ -185,17 +185,15 @@ _ctl_display_some_debug(struct MPT3SAS_ADAPTER *ioc, u16 smid,
if (!desc)
return;
- pr_info(MPT3SAS_FMT "%s: %s, smid(%d)\n",
- ioc->name, calling_function_name, desc, smid);
+ ioc_info(ioc, "%s: %s, smid(%d)\n", calling_function_name, desc, smid);
if (!mpi_reply)
return;
if (mpi_reply->IOCStatus || mpi_reply->IOCLogInfo)
- pr_info(MPT3SAS_FMT
- "\tiocstatus(0x%04x), loginfo(0x%08x)\n",
- ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
- le32_to_cpu(mpi_reply->IOCLogInfo));
+ ioc_info(ioc, "\tiocstatus(0x%04x), loginfo(0x%08x)\n",
+ le16_to_cpu(mpi_reply->IOCStatus),
+ le32_to_cpu(mpi_reply->IOCLogInfo));
if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||
mpi_request->Function ==
@@ -208,38 +206,32 @@ _ctl_display_some_debug(struct MPT3SAS_ADAPTER *ioc, u16 smid,
sas_device = mpt3sas_get_sdev_by_handle(ioc,
le16_to_cpu(scsi_reply->DevHandle));
if (sas_device) {
- pr_warn(MPT3SAS_FMT "\tsas_address(0x%016llx), phy(%d)\n",
- ioc->name, (unsigned long long)
- sas_device->sas_address, sas_device->phy);
- pr_warn(MPT3SAS_FMT
- "\tenclosure_logical_id(0x%016llx), slot(%d)\n",
- ioc->name, (unsigned long long)
- sas_device->enclosure_logical_id, sas_device->slot);
+ ioc_warn(ioc, "\tsas_address(0x%016llx), phy(%d)\n",
+ (u64)sas_device->sas_address,
+ sas_device->phy);
+ ioc_warn(ioc, "\tenclosure_logical_id(0x%016llx), slot(%d)\n",
+ (u64)sas_device->enclosure_logical_id,
+ sas_device->slot);
sas_device_put(sas_device);
}
if (!sas_device) {
pcie_device = mpt3sas_get_pdev_by_handle(ioc,
le16_to_cpu(scsi_reply->DevHandle));
if (pcie_device) {
- pr_warn(MPT3SAS_FMT
- "\tWWID(0x%016llx), port(%d)\n", ioc->name,
- (unsigned long long)pcie_device->wwid,
- pcie_device->port_num);
+ ioc_warn(ioc, "\tWWID(0x%016llx), port(%d)\n",
+ (unsigned long long)pcie_device->wwid,
+ pcie_device->port_num);
if (pcie_device->enclosure_handle != 0)
- pr_warn(MPT3SAS_FMT
- "\tenclosure_logical_id(0x%016llx), slot(%d)\n",
- ioc->name, (unsigned long long)
- pcie_device->enclosure_logical_id,
- pcie_device->slot);
+ ioc_warn(ioc, "\tenclosure_logical_id(0x%016llx), slot(%d)\n",
+ (u64)pcie_device->enclosure_logical_id,
+ pcie_device->slot);
pcie_device_put(pcie_device);
}
}
if (scsi_reply->SCSIState || scsi_reply->SCSIStatus)
- pr_info(MPT3SAS_FMT
- "\tscsi_state(0x%02x), scsi_status"
- "(0x%02x)\n", ioc->name,
- scsi_reply->SCSIState,
- scsi_reply->SCSIStatus);
+ ioc_info(ioc, "\tscsi_state(0x%02x), scsi_status(0x%02x)\n",
+ scsi_reply->SCSIState,
+ scsi_reply->SCSIStatus);
}
}
@@ -466,8 +458,7 @@ void mpt3sas_ctl_pre_reset_handler(struct MPT3SAS_ADAPTER *ioc)
int i;
u8 issue_reset;
- dtmprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: MPT3_IOC_PRE_RESET\n", ioc->name, __func__));
+ dtmprintk(ioc, ioc_info(ioc, "%s: MPT3_IOC_PRE_RESET\n", __func__));
for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) {
if (!(ioc->diag_buffer_status[i] &
MPT3_DIAG_BUFFER_IS_REGISTERED))
@@ -487,8 +478,7 @@ void mpt3sas_ctl_pre_reset_handler(struct MPT3SAS_ADAPTER *ioc)
*/
void mpt3sas_ctl_after_reset_handler(struct MPT3SAS_ADAPTER *ioc)
{
- dtmprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: MPT3_IOC_AFTER_RESET\n", ioc->name, __func__));
+ dtmprintk(ioc, ioc_info(ioc, "%s: MPT3_IOC_AFTER_RESET\n", __func__));
if (ioc->ctl_cmds.status & MPT3_CMD_PENDING) {
ioc->ctl_cmds.status |= MPT3_CMD_RESET;
mpt3sas_base_free_smid(ioc, ioc->ctl_cmds.smid);
@@ -506,8 +496,7 @@ void mpt3sas_ctl_reset_done_handler(struct MPT3SAS_ADAPTER *ioc)
{
int i;
- dtmprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: MPT3_IOC_DONE_RESET\n", ioc->name, __func__));
+ dtmprintk(ioc, ioc_info(ioc, "%s: MPT3_IOC_DONE_RESET\n", __func__));
for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) {
if (!(ioc->diag_buffer_status[i] &
@@ -612,10 +601,10 @@ _ctl_set_task_mid(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command *karg,
}
if (!found) {
- dctlprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: handle(0x%04x), lun(%d), no active mid!!\n",
- ioc->name,
- desc, le16_to_cpu(tm_request->DevHandle), lun));
+ dctlprintk(ioc,
+ ioc_info(ioc, "%s: handle(0x%04x), lun(%d), no active mid!!\n",
+ desc, le16_to_cpu(tm_request->DevHandle),
+ lun));
tm_reply = ioc->ctl_cmds.reply;
tm_reply->DevHandle = tm_request->DevHandle;
tm_reply->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
@@ -631,10 +620,10 @@ _ctl_set_task_mid(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command *karg,
return 1;
}
- dctlprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: handle(0x%04x), lun(%d), task_mid(%d)\n", ioc->name,
- desc, le16_to_cpu(tm_request->DevHandle), lun,
- le16_to_cpu(tm_request->TaskMID)));
+ dctlprintk(ioc,
+ ioc_info(ioc, "%s: handle(0x%04x), lun(%d), task_mid(%d)\n",
+ desc, le16_to_cpu(tm_request->DevHandle), lun,
+ le16_to_cpu(tm_request->TaskMID)));
return 0;
}
@@ -672,8 +661,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
issue_reset = 0;
if (ioc->ctl_cmds.status != MPT3_CMD_NOT_USED) {
- pr_err(MPT3SAS_FMT "%s: ctl_cmd in use\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: ctl_cmd in use\n", __func__);
ret = -EAGAIN;
goto out;
}
@@ -682,28 +670,23 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
ioc_state = mpt3sas_base_get_iocstate(ioc, 1);
while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
if (wait_state_count++ == 10) {
- pr_err(MPT3SAS_FMT
- "%s: failed due to ioc not operational\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: failed due to ioc not operational\n",
+ __func__);
ret = -EFAULT;
goto out;
}
ssleep(1);
ioc_state = mpt3sas_base_get_iocstate(ioc, 1);
- pr_info(MPT3SAS_FMT
- "%s: waiting for operational state(count=%d)\n",
- ioc->name,
- __func__, wait_state_count);
+ ioc_info(ioc, "%s: waiting for operational state(count=%d)\n",
+ __func__, wait_state_count);
}
if (wait_state_count)
- pr_info(MPT3SAS_FMT "%s: ioc is operational\n",
- ioc->name, __func__);
+ ioc_info(ioc, "%s: ioc is operational\n", __func__);
mpi_request = kzalloc(ioc->request_sz, GFP_KERNEL);
if (!mpi_request) {
- pr_err(MPT3SAS_FMT
- "%s: failed obtaining a memory for mpi_request\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: failed obtaining a memory for mpi_request\n",
+ __func__);
ret = -ENOMEM;
goto out;
}
@@ -726,8 +709,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) {
smid = mpt3sas_base_get_smid_hpr(ioc, ioc->ctl_cb_idx);
if (!smid) {
- pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);
ret = -EAGAIN;
goto out;
}
@@ -762,8 +744,8 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
/* obtain dma-able memory for data transfer */
if (data_out_sz) /* WRITE */ {
- data_out = pci_alloc_consistent(ioc->pdev, data_out_sz,
- &data_out_dma);
+ data_out = dma_alloc_coherent(&ioc->pdev->dev, data_out_sz,
+ &data_out_dma, GFP_KERNEL);
if (!data_out) {
pr_err("failure at %s:%d/%s()!\n", __FILE__,
__LINE__, __func__);
@@ -782,8 +764,8 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
}
if (data_in_sz) /* READ */ {
- data_in = pci_alloc_consistent(ioc->pdev, data_in_sz,
- &data_in_dma);
+ data_in = dma_alloc_coherent(&ioc->pdev->dev, data_in_sz,
+ &data_in_dma, GFP_KERNEL);
if (!data_in) {
pr_err("failure at %s:%d/%s()!\n", __FILE__,
__LINE__, __func__);
@@ -823,9 +805,9 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
ioc->build_nvme_prp(ioc, smid, nvme_encap_request,
data_out_dma, data_out_sz, data_in_dma, data_in_sz);
if (test_bit(device_handle, ioc->device_remove_in_progress)) {
- dtmprintk(ioc, pr_info(MPT3SAS_FMT "handle(0x%04x) :"
- "ioctl failed due to device removal in progress\n",
- ioc->name, device_handle));
+ dtmprintk(ioc,
+ ioc_info(ioc, "handle(0x%04x): ioctl failed due to device removal in progress\n",
+ device_handle));
mpt3sas_base_free_smid(ioc, smid);
ret = -EINVAL;
goto out;
@@ -843,9 +825,9 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
mpt3sas_base_get_sense_buffer_dma(ioc, smid);
memset(ioc->ctl_cmds.sense, 0, SCSI_SENSE_BUFFERSIZE);
if (test_bit(device_handle, ioc->device_remove_in_progress)) {
- dtmprintk(ioc, pr_info(MPT3SAS_FMT
- "handle(0x%04x) :ioctl failed due to device removal in progress\n",
- ioc->name, device_handle));
+ dtmprintk(ioc,
+ ioc_info(ioc, "handle(0x%04x) :ioctl failed due to device removal in progress\n",
+ device_handle));
mpt3sas_base_free_smid(ioc, smid);
ret = -EINVAL;
goto out;
@@ -863,10 +845,10 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
Mpi2SCSITaskManagementRequest_t *tm_request =
(Mpi2SCSITaskManagementRequest_t *)request;
- dtmprintk(ioc, pr_info(MPT3SAS_FMT
- "TASK_MGMT: handle(0x%04x), task_type(0x%02x)\n",
- ioc->name,
- le16_to_cpu(tm_request->DevHandle), tm_request->TaskType));
+ dtmprintk(ioc,
+ ioc_info(ioc, "TASK_MGMT: handle(0x%04x), task_type(0x%02x)\n",
+ le16_to_cpu(tm_request->DevHandle),
+ tm_request->TaskType));
ioc->got_task_abort_from_ioctl = 1;
if (tm_request->TaskType ==
MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK ||
@@ -881,9 +863,9 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
ioc->got_task_abort_from_ioctl = 0;
if (test_bit(device_handle, ioc->device_remove_in_progress)) {
- dtmprintk(ioc, pr_info(MPT3SAS_FMT
- "handle(0x%04x) :ioctl failed due to device removal in progress\n",
- ioc->name, device_handle));
+ dtmprintk(ioc,
+ ioc_info(ioc, "handle(0x%04x) :ioctl failed due to device removal in progress\n",
+ device_handle));
mpt3sas_base_free_smid(ioc, smid);
ret = -EINVAL;
goto out;
@@ -929,9 +911,9 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
case MPI2_FUNCTION_SATA_PASSTHROUGH:
{
if (test_bit(device_handle, ioc->device_remove_in_progress)) {
- dtmprintk(ioc, pr_info(MPT3SAS_FMT
- "handle(0x%04x) :ioctl failed due to device removal in progress\n",
- ioc->name, device_handle));
+ dtmprintk(ioc,
+ ioc_info(ioc, "handle(0x%04x) :ioctl failed due to device removal in progress\n",
+ device_handle));
mpt3sas_base_free_smid(ioc, smid);
ret = -EINVAL;
goto out;
@@ -1017,12 +999,10 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
Mpi2SCSITaskManagementReply_t *tm_reply =
(Mpi2SCSITaskManagementReply_t *)mpi_reply;
- pr_info(MPT3SAS_FMT "TASK_MGMT: " \
- "IOCStatus(0x%04x), IOCLogInfo(0x%08x), "
- "TerminationCount(0x%08x)\n", ioc->name,
- le16_to_cpu(tm_reply->IOCStatus),
- le32_to_cpu(tm_reply->IOCLogInfo),
- le32_to_cpu(tm_reply->TerminationCount));
+ ioc_info(ioc, "TASK_MGMT: IOCStatus(0x%04x), IOCLogInfo(0x%08x), TerminationCount(0x%08x)\n",
+ le16_to_cpu(tm_reply->IOCStatus),
+ le32_to_cpu(tm_reply->IOCLogInfo),
+ le32_to_cpu(tm_reply->TerminationCount));
}
/* copy out xdata to user */
@@ -1054,9 +1034,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH || mpi_request->Function ==
MPI2_FUNCTION_NVME_ENCAPSULATED)) {
if (karg.sense_data_ptr == NULL) {
- pr_info(MPT3SAS_FMT "Response buffer provided"
- " by application is NULL; Response data will"
- " not be returned.\n", ioc->name);
+ ioc_info(ioc, "Response buffer provided by application is NULL; Response data will not be returned\n");
goto out;
}
sz_arg = (mpi_request->Function ==
@@ -1079,9 +1057,8 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
mpi_request->Function ==
MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH ||
mpi_request->Function == MPI2_FUNCTION_SATA_PASSTHROUGH)) {
- pr_info(MPT3SAS_FMT "issue target reset: handle = (0x%04x)\n",
- ioc->name,
- le16_to_cpu(mpi_request->FunctionDependent1));
+ ioc_info(ioc, "issue target reset: handle = (0x%04x)\n",
+ le16_to_cpu(mpi_request->FunctionDependent1));
mpt3sas_halt_firmware(ioc);
pcie_device = mpt3sas_get_pdev_by_handle(ioc,
le16_to_cpu(mpi_request->FunctionDependent1));
@@ -1106,11 +1083,11 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
/* free memory associated with sg buffers */
if (data_in)
- pci_free_consistent(ioc->pdev, data_in_sz, data_in,
+ dma_free_coherent(&ioc->pdev->dev, data_in_sz, data_in,
data_in_dma);
if (data_out)
- pci_free_consistent(ioc->pdev, data_out_sz, data_out,
+ dma_free_coherent(&ioc->pdev->dev, data_out_sz, data_out,
data_out_dma);
kfree(mpi_request);
@@ -1128,8 +1105,8 @@ _ctl_getiocinfo(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
{
struct mpt3_ioctl_iocinfo karg;
- dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s: enter\n", ioc->name,
- __func__));
+ dctlprintk(ioc, ioc_info(ioc, "%s: enter\n",
+ __func__));
memset(&karg, 0 , sizeof(karg));
if (ioc->pfacts)
@@ -1188,8 +1165,8 @@ _ctl_eventquery(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
return -EFAULT;
}
- dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s: enter\n", ioc->name,
- __func__));
+ dctlprintk(ioc, ioc_info(ioc, "%s: enter\n",
+ __func__));
karg.event_entries = MPT3SAS_CTL_EVENT_LOG_SIZE;
memcpy(karg.event_types, ioc->event_type,
@@ -1219,8 +1196,8 @@ _ctl_eventenable(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
return -EFAULT;
}
- dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s: enter\n", ioc->name,
- __func__));
+ dctlprintk(ioc, ioc_info(ioc, "%s: enter\n",
+ __func__));
memcpy(ioc->event_type, karg.event_types,
MPI2_EVENT_NOTIFY_EVENTMASK_WORDS * sizeof(u32));
@@ -1259,8 +1236,8 @@ _ctl_eventreport(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
return -EFAULT;
}
- dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s: enter\n", ioc->name,
- __func__));
+ dctlprintk(ioc, ioc_info(ioc, "%s: enter\n",
+ __func__));
number_bytes = karg.hdr.max_data_size -
sizeof(struct mpt3_ioctl_header);
@@ -1306,12 +1283,11 @@ _ctl_do_reset(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
ioc->is_driver_loading)
return -EAGAIN;
- dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s: enter\n", ioc->name,
- __func__));
+ dctlprintk(ioc, ioc_info(ioc, "%s: enter\n",
+ __func__));
retval = mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
- pr_info(MPT3SAS_FMT "host reset: %s\n",
- ioc->name, ((!retval) ? "SUCCESS" : "FAILED"));
+ ioc_info(ioc, "host reset: %s\n", ((!retval) ? "SUCCESS" : "FAILED"));
return 0;
}
@@ -1440,8 +1416,8 @@ _ctl_btdh_mapping(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
return -EFAULT;
}
- dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- __func__));
+ dctlprintk(ioc, ioc_info(ioc, "%s\n",
+ __func__));
rc = _ctl_btdh_search_sas_device(ioc, &karg);
if (!rc)
@@ -1512,53 +1488,46 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc,
u32 ioc_state;
u8 issue_reset = 0;
- dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- __func__));
+ dctlprintk(ioc, ioc_info(ioc, "%s\n",
+ __func__));
ioc_state = mpt3sas_base_get_iocstate(ioc, 1);
if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
- pr_err(MPT3SAS_FMT
- "%s: failed due to ioc not operational\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: failed due to ioc not operational\n",
+ __func__);
rc = -EAGAIN;
goto out;
}
if (ioc->ctl_cmds.status != MPT3_CMD_NOT_USED) {
- pr_err(MPT3SAS_FMT "%s: ctl_cmd in use\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: ctl_cmd in use\n", __func__);
rc = -EAGAIN;
goto out;
}
buffer_type = diag_register->buffer_type;
if (!_ctl_diag_capability(ioc, buffer_type)) {
- pr_err(MPT3SAS_FMT
- "%s: doesn't have capability for buffer_type(0x%02x)\n",
- ioc->name, __func__, buffer_type);
+ ioc_err(ioc, "%s: doesn't have capability for buffer_type(0x%02x)\n",
+ __func__, buffer_type);
return -EPERM;
}
if (ioc->diag_buffer_status[buffer_type] &
MPT3_DIAG_BUFFER_IS_REGISTERED) {
- pr_err(MPT3SAS_FMT
- "%s: already has a registered buffer for buffer_type(0x%02x)\n",
- ioc->name, __func__,
- buffer_type);
+ ioc_err(ioc, "%s: already has a registered buffer for buffer_type(0x%02x)\n",
+ __func__, buffer_type);
return -EINVAL;
}
if (diag_register->requested_buffer_size % 4) {
- pr_err(MPT3SAS_FMT
- "%s: the requested_buffer_size is not 4 byte aligned\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: the requested_buffer_size is not 4 byte aligned\n",
+ __func__);
return -EINVAL;
}
smid = mpt3sas_base_get_smid(ioc, ioc->ctl_cb_idx);
if (!smid) {
- pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);
rc = -EAGAIN;
goto out;
}
@@ -1580,9 +1549,9 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc,
if (request_data) {
request_data_dma = ioc->diag_buffer_dma[buffer_type];
if (request_data_sz != ioc->diag_buffer_sz[buffer_type]) {
- pci_free_consistent(ioc->pdev,
- ioc->diag_buffer_sz[buffer_type],
- request_data, request_data_dma);
+ dma_free_coherent(&ioc->pdev->dev,
+ ioc->diag_buffer_sz[buffer_type],
+ request_data, request_data_dma);
request_data = NULL;
}
}
@@ -1590,12 +1559,11 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc,
if (request_data == NULL) {
ioc->diag_buffer_sz[buffer_type] = 0;
ioc->diag_buffer_dma[buffer_type] = 0;
- request_data = pci_alloc_consistent(
- ioc->pdev, request_data_sz, &request_data_dma);
+ request_data = dma_alloc_coherent(&ioc->pdev->dev,
+ request_data_sz, &request_data_dma, GFP_KERNEL);
if (request_data == NULL) {
- pr_err(MPT3SAS_FMT "%s: failed allocating memory" \
- " for diag buffers, requested size(%d)\n",
- ioc->name, __func__, request_data_sz);
+ ioc_err(ioc, "%s: failed allocating memory for diag buffers, requested size(%d)\n",
+ __func__, request_data_sz);
mpt3sas_base_free_smid(ioc, smid);
return -ENOMEM;
}
@@ -1612,11 +1580,11 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc,
mpi_request->VF_ID = 0; /* TODO */
mpi_request->VP_ID = 0;
- dctlprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: diag_buffer(0x%p), dma(0x%llx), sz(%d)\n",
- ioc->name, __func__, request_data,
- (unsigned long long)request_data_dma,
- le32_to_cpu(mpi_request->BufferLength)));
+ dctlprintk(ioc,
+ ioc_info(ioc, "%s: diag_buffer(0x%p), dma(0x%llx), sz(%d)\n",
+ __func__, request_data,
+ (unsigned long long)request_data_dma,
+ le32_to_cpu(mpi_request->BufferLength)));
for (i = 0; i < MPT3_PRODUCT_SPECIFIC_DWORDS; i++)
mpi_request->ProductSpecific[i] =
@@ -1637,8 +1605,7 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc,
/* process the completed Reply Message Frame */
if ((ioc->ctl_cmds.status & MPT3_CMD_REPLY_VALID) == 0) {
- pr_err(MPT3SAS_FMT "%s: no reply message\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: no reply message\n", __func__);
rc = -EFAULT;
goto out;
}
@@ -1649,13 +1616,11 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc,
if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
ioc->diag_buffer_status[buffer_type] |=
MPT3_DIAG_BUFFER_IS_REGISTERED;
- dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s: success\n",
- ioc->name, __func__));
+ dctlprintk(ioc, ioc_info(ioc, "%s: success\n", __func__));
} else {
- pr_info(MPT3SAS_FMT
- "%s: ioc_status(0x%04x) log_info(0x%08x)\n",
- ioc->name, __func__,
- ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo));
+ ioc_info(ioc, "%s: ioc_status(0x%04x) log_info(0x%08x)\n",
+ __func__,
+ ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo));
rc = -EFAULT;
}
@@ -1666,7 +1631,7 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc,
out:
if (rc && request_data)
- pci_free_consistent(ioc->pdev, request_data_sz,
+ dma_free_coherent(&ioc->pdev->dev, request_data_sz,
request_data, request_data_dma);
ioc->ctl_cmds.status = MPT3_CMD_NOT_USED;
@@ -1689,8 +1654,7 @@ mpt3sas_enable_diag_buffer(struct MPT3SAS_ADAPTER *ioc, u8 bits_to_register)
memset(&diag_register, 0, sizeof(struct mpt3_diag_register));
if (bits_to_register & 1) {
- pr_info(MPT3SAS_FMT "registering trace buffer support\n",
- ioc->name);
+ ioc_info(ioc, "registering trace buffer support\n");
ioc->diag_trigger_master.MasterData =
(MASTER_TRIGGER_FW_FAULT + MASTER_TRIGGER_ADAPTER_RESET);
diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE;
@@ -1701,8 +1665,7 @@ mpt3sas_enable_diag_buffer(struct MPT3SAS_ADAPTER *ioc, u8 bits_to_register)
}
if (bits_to_register & 2) {
- pr_info(MPT3SAS_FMT "registering snapshot buffer support\n",
- ioc->name);
+ ioc_info(ioc, "registering snapshot buffer support\n");
diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_SNAPSHOT;
/* register for 2MB buffers */
diag_register.requested_buffer_size = 2 * (1024 * 1024);
@@ -1711,8 +1674,7 @@ mpt3sas_enable_diag_buffer(struct MPT3SAS_ADAPTER *ioc, u8 bits_to_register)
}
if (bits_to_register & 4) {
- pr_info(MPT3SAS_FMT "registering extended buffer support\n",
- ioc->name);
+ ioc_info(ioc, "registering extended buffer support\n");
diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_EXTENDED;
/* register for 2MB buffers */
diag_register.requested_buffer_size = 2 * (1024 * 1024);
@@ -1768,51 +1730,46 @@ _ctl_diag_unregister(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
return -EFAULT;
}
- dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- __func__));
+ dctlprintk(ioc, ioc_info(ioc, "%s\n",
+ __func__));
buffer_type = karg.unique_id & 0x000000ff;
if (!_ctl_diag_capability(ioc, buffer_type)) {
- pr_err(MPT3SAS_FMT
- "%s: doesn't have capability for buffer_type(0x%02x)\n",
- ioc->name, __func__, buffer_type);
+ ioc_err(ioc, "%s: doesn't have capability for buffer_type(0x%02x)\n",
+ __func__, buffer_type);
return -EPERM;
}
if ((ioc->diag_buffer_status[buffer_type] &
MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) {
- pr_err(MPT3SAS_FMT
- "%s: buffer_type(0x%02x) is not registered\n",
- ioc->name, __func__, buffer_type);
+ ioc_err(ioc, "%s: buffer_type(0x%02x) is not registered\n",
+ __func__, buffer_type);
return -EINVAL;
}
if ((ioc->diag_buffer_status[buffer_type] &
MPT3_DIAG_BUFFER_IS_RELEASED) == 0) {
- pr_err(MPT3SAS_FMT
- "%s: buffer_type(0x%02x) has not been released\n",
- ioc->name, __func__, buffer_type);
+ ioc_err(ioc, "%s: buffer_type(0x%02x) has not been released\n",
+ __func__, buffer_type);
return -EINVAL;
}
if (karg.unique_id != ioc->unique_id[buffer_type]) {
- pr_err(MPT3SAS_FMT
- "%s: unique_id(0x%08x) is not registered\n",
- ioc->name, __func__, karg.unique_id);
+ ioc_err(ioc, "%s: unique_id(0x%08x) is not registered\n",
+ __func__, karg.unique_id);
return -EINVAL;
}
request_data = ioc->diag_buffer[buffer_type];
if (!request_data) {
- pr_err(MPT3SAS_FMT
- "%s: doesn't have memory allocated for buffer_type(0x%02x)\n",
- ioc->name, __func__, buffer_type);
+ ioc_err(ioc, "%s: doesn't have memory allocated for buffer_type(0x%02x)\n",
+ __func__, buffer_type);
return -ENOMEM;
}
request_data_sz = ioc->diag_buffer_sz[buffer_type];
request_data_dma = ioc->diag_buffer_dma[buffer_type];
- pci_free_consistent(ioc->pdev, request_data_sz,
- request_data, request_data_dma);
+ dma_free_coherent(&ioc->pdev->dev, request_data_sz,
+ request_data, request_data_dma);
ioc->diag_buffer[buffer_type] = NULL;
ioc->diag_buffer_status[buffer_type] = 0;
return 0;
@@ -1841,41 +1798,37 @@ _ctl_diag_query(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
return -EFAULT;
}
- dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- __func__));
+ dctlprintk(ioc, ioc_info(ioc, "%s\n",
+ __func__));
karg.application_flags = 0;
buffer_type = karg.buffer_type;
if (!_ctl_diag_capability(ioc, buffer_type)) {
- pr_err(MPT3SAS_FMT
- "%s: doesn't have capability for buffer_type(0x%02x)\n",
- ioc->name, __func__, buffer_type);
+ ioc_err(ioc, "%s: doesn't have capability for buffer_type(0x%02x)\n",
+ __func__, buffer_type);
return -EPERM;
}
if ((ioc->diag_buffer_status[buffer_type] &
MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) {
- pr_err(MPT3SAS_FMT
- "%s: buffer_type(0x%02x) is not registered\n",
- ioc->name, __func__, buffer_type);
+ ioc_err(ioc, "%s: buffer_type(0x%02x) is not registered\n",
+ __func__, buffer_type);
return -EINVAL;
}
if (karg.unique_id & 0xffffff00) {
if (karg.unique_id != ioc->unique_id[buffer_type]) {
- pr_err(MPT3SAS_FMT
- "%s: unique_id(0x%08x) is not registered\n",
- ioc->name, __func__, karg.unique_id);
+ ioc_err(ioc, "%s: unique_id(0x%08x) is not registered\n",
+ __func__, karg.unique_id);
return -EINVAL;
}
}
request_data = ioc->diag_buffer[buffer_type];
if (!request_data) {
- pr_err(MPT3SAS_FMT
- "%s: doesn't have buffer for buffer_type(0x%02x)\n",
- ioc->name, __func__, buffer_type);
+ ioc_err(ioc, "%s: doesn't have buffer for buffer_type(0x%02x)\n",
+ __func__, buffer_type);
return -ENOMEM;
}
@@ -1897,9 +1850,8 @@ _ctl_diag_query(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
karg.diagnostic_flags = ioc->diagnostic_flags[buffer_type];
if (copy_to_user(arg, &karg, sizeof(struct mpt3_diag_query))) {
- pr_err(MPT3SAS_FMT
- "%s: unable to write mpt3_diag_query data @ %p\n",
- ioc->name, __func__, arg);
+ ioc_err(ioc, "%s: unable to write mpt3_diag_query data @ %p\n",
+ __func__, arg);
return -EFAULT;
}
return 0;
@@ -1923,8 +1875,8 @@ mpt3sas_send_diag_release(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type,
u32 ioc_state;
int rc;
- dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- __func__));
+ dctlprintk(ioc, ioc_info(ioc, "%s\n",
+ __func__));
rc = 0;
*issue_reset = 0;
@@ -1935,24 +1887,22 @@ mpt3sas_send_diag_release(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type,
MPT3_DIAG_BUFFER_IS_REGISTERED)
ioc->diag_buffer_status[buffer_type] |=
MPT3_DIAG_BUFFER_IS_RELEASED;
- dctlprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: skipping due to FAULT state\n", ioc->name,
- __func__));
+ dctlprintk(ioc,
+ ioc_info(ioc, "%s: skipping due to FAULT state\n",
+ __func__));
rc = -EAGAIN;
goto out;
}
if (ioc->ctl_cmds.status != MPT3_CMD_NOT_USED) {
- pr_err(MPT3SAS_FMT "%s: ctl_cmd in use\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: ctl_cmd in use\n", __func__);
rc = -EAGAIN;
goto out;
}
smid = mpt3sas_base_get_smid(ioc, ioc->ctl_cb_idx);
if (!smid) {
- pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);
rc = -EAGAIN;
goto out;
}
@@ -1982,8 +1932,7 @@ mpt3sas_send_diag_release(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type,
/* process the completed Reply Message Frame */
if ((ioc->ctl_cmds.status & MPT3_CMD_REPLY_VALID) == 0) {
- pr_err(MPT3SAS_FMT "%s: no reply message\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: no reply message\n", __func__);
rc = -EFAULT;
goto out;
}
@@ -1994,13 +1943,11 @@ mpt3sas_send_diag_release(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type,
if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
ioc->diag_buffer_status[buffer_type] |=
MPT3_DIAG_BUFFER_IS_RELEASED;
- dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s: success\n",
- ioc->name, __func__));
+ dctlprintk(ioc, ioc_info(ioc, "%s: success\n", __func__));
} else {
- pr_info(MPT3SAS_FMT
- "%s: ioc_status(0x%04x) log_info(0x%08x)\n",
- ioc->name, __func__,
- ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo));
+ ioc_info(ioc, "%s: ioc_status(0x%04x) log_info(0x%08x)\n",
+ __func__,
+ ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo));
rc = -EFAULT;
}
@@ -2033,47 +1980,41 @@ _ctl_diag_release(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
return -EFAULT;
}
- dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- __func__));
+ dctlprintk(ioc, ioc_info(ioc, "%s\n",
+ __func__));
buffer_type = karg.unique_id & 0x000000ff;
if (!_ctl_diag_capability(ioc, buffer_type)) {
- pr_err(MPT3SAS_FMT
- "%s: doesn't have capability for buffer_type(0x%02x)\n",
- ioc->name, __func__, buffer_type);
+ ioc_err(ioc, "%s: doesn't have capability for buffer_type(0x%02x)\n",
+ __func__, buffer_type);
return -EPERM;
}
if ((ioc->diag_buffer_status[buffer_type] &
MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) {
- pr_err(MPT3SAS_FMT
- "%s: buffer_type(0x%02x) is not registered\n",
- ioc->name, __func__, buffer_type);
+ ioc_err(ioc, "%s: buffer_type(0x%02x) is not registered\n",
+ __func__, buffer_type);
return -EINVAL;
}
if (karg.unique_id != ioc->unique_id[buffer_type]) {
- pr_err(MPT3SAS_FMT
- "%s: unique_id(0x%08x) is not registered\n",
- ioc->name, __func__, karg.unique_id);
+ ioc_err(ioc, "%s: unique_id(0x%08x) is not registered\n",
+ __func__, karg.unique_id);
return -EINVAL;
}
if (ioc->diag_buffer_status[buffer_type] &
MPT3_DIAG_BUFFER_IS_RELEASED) {
- pr_err(MPT3SAS_FMT
- "%s: buffer_type(0x%02x) is already released\n",
- ioc->name, __func__,
- buffer_type);
+ ioc_err(ioc, "%s: buffer_type(0x%02x) is already released\n",
+ __func__, buffer_type);
return 0;
}
request_data = ioc->diag_buffer[buffer_type];
if (!request_data) {
- pr_err(MPT3SAS_FMT
- "%s: doesn't have memory allocated for buffer_type(0x%02x)\n",
- ioc->name, __func__, buffer_type);
+ ioc_err(ioc, "%s: doesn't have memory allocated for buffer_type(0x%02x)\n",
+ __func__, buffer_type);
return -ENOMEM;
}
@@ -2084,9 +2025,8 @@ _ctl_diag_release(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
MPT3_DIAG_BUFFER_IS_RELEASED;
ioc->diag_buffer_status[buffer_type] &=
~MPT3_DIAG_BUFFER_IS_DIAG_RESET;
- pr_err(MPT3SAS_FMT
- "%s: buffer_type(0x%02x) was released due to host reset\n",
- ioc->name, __func__, buffer_type);
+ ioc_err(ioc, "%s: buffer_type(0x%02x) was released due to host reset\n",
+ __func__, buffer_type);
return 0;
}
@@ -2124,38 +2064,34 @@ _ctl_diag_read_buffer(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
return -EFAULT;
}
- dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- __func__));
+ dctlprintk(ioc, ioc_info(ioc, "%s\n",
+ __func__));
buffer_type = karg.unique_id & 0x000000ff;
if (!_ctl_diag_capability(ioc, buffer_type)) {
- pr_err(MPT3SAS_FMT
- "%s: doesn't have capability for buffer_type(0x%02x)\n",
- ioc->name, __func__, buffer_type);
+ ioc_err(ioc, "%s: doesn't have capability for buffer_type(0x%02x)\n",
+ __func__, buffer_type);
return -EPERM;
}
if (karg.unique_id != ioc->unique_id[buffer_type]) {
- pr_err(MPT3SAS_FMT
- "%s: unique_id(0x%08x) is not registered\n",
- ioc->name, __func__, karg.unique_id);
+ ioc_err(ioc, "%s: unique_id(0x%08x) is not registered\n",
+ __func__, karg.unique_id);
return -EINVAL;
}
request_data = ioc->diag_buffer[buffer_type];
if (!request_data) {
- pr_err(MPT3SAS_FMT
- "%s: doesn't have buffer for buffer_type(0x%02x)\n",
- ioc->name, __func__, buffer_type);
+ ioc_err(ioc, "%s: doesn't have buffer for buffer_type(0x%02x)\n",
+ __func__, buffer_type);
return -ENOMEM;
}
request_size = ioc->diag_buffer_sz[buffer_type];
if ((karg.starting_offset % 4) || (karg.bytes_to_read % 4)) {
- pr_err(MPT3SAS_FMT "%s: either the starting_offset " \
- "or bytes_to_read are not 4 byte aligned\n", ioc->name,
- __func__);
+ ioc_err(ioc, "%s: either the starting_offset or bytes_to_read are not 4 byte aligned\n",
+ __func__);
return -EINVAL;
}
@@ -2163,10 +2099,10 @@ _ctl_diag_read_buffer(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
return -EINVAL;
diag_data = (void *)(request_data + karg.starting_offset);
- dctlprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: diag_buffer(%p), offset(%d), sz(%d)\n",
- ioc->name, __func__,
- diag_data, karg.starting_offset, karg.bytes_to_read));
+ dctlprintk(ioc,
+ ioc_info(ioc, "%s: diag_buffer(%p), offset(%d), sz(%d)\n",
+ __func__, diag_data, karg.starting_offset,
+ karg.bytes_to_read));
/* Truncate data on requests that are too large */
if ((diag_data + karg.bytes_to_read < diag_data) ||
@@ -2177,39 +2113,36 @@ _ctl_diag_read_buffer(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
if (copy_to_user((void __user *)uarg->diagnostic_data,
diag_data, copy_size)) {
- pr_err(MPT3SAS_FMT
- "%s: Unable to write mpt_diag_read_buffer_t data @ %p\n",
- ioc->name, __func__, diag_data);
+ ioc_err(ioc, "%s: Unable to write mpt_diag_read_buffer_t data @ %p\n",
+ __func__, diag_data);
return -EFAULT;
}
if ((karg.flags & MPT3_FLAGS_REREGISTER) == 0)
return 0;
- dctlprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: Reregister buffer_type(0x%02x)\n",
- ioc->name, __func__, buffer_type));
+ dctlprintk(ioc,
+ ioc_info(ioc, "%s: Reregister buffer_type(0x%02x)\n",
+ __func__, buffer_type));
if ((ioc->diag_buffer_status[buffer_type] &
MPT3_DIAG_BUFFER_IS_RELEASED) == 0) {
- dctlprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: buffer_type(0x%02x) is still registered\n",
- ioc->name, __func__, buffer_type));
+ dctlprintk(ioc,
+ ioc_info(ioc, "%s: buffer_type(0x%02x) is still registered\n",
+ __func__, buffer_type));
return 0;
}
/* Get a free request frame and save the message context.
*/
if (ioc->ctl_cmds.status != MPT3_CMD_NOT_USED) {
- pr_err(MPT3SAS_FMT "%s: ctl_cmd in use\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: ctl_cmd in use\n", __func__);
rc = -EAGAIN;
goto out;
}
smid = mpt3sas_base_get_smid(ioc, ioc->ctl_cb_idx);
if (!smid) {
- pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);
rc = -EAGAIN;
goto out;
}
@@ -2247,8 +2180,7 @@ _ctl_diag_read_buffer(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
/* process the completed Reply Message Frame */
if ((ioc->ctl_cmds.status & MPT3_CMD_REPLY_VALID) == 0) {
- pr_err(MPT3SAS_FMT "%s: no reply message\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: no reply message\n", __func__);
rc = -EFAULT;
goto out;
}
@@ -2259,13 +2191,11 @@ _ctl_diag_read_buffer(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
ioc->diag_buffer_status[buffer_type] |=
MPT3_DIAG_BUFFER_IS_REGISTERED;
- dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s: success\n",
- ioc->name, __func__));
+ dctlprintk(ioc, ioc_info(ioc, "%s: success\n", __func__));
} else {
- pr_info(MPT3SAS_FMT
- "%s: ioc_status(0x%04x) log_info(0x%08x)\n",
- ioc->name, __func__,
- ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo));
+ ioc_info(ioc, "%s: ioc_status(0x%04x) log_info(0x%08x)\n",
+ __func__, ioc_status,
+ le32_to_cpu(mpi_reply->IOCLogInfo));
rc = -EFAULT;
}
@@ -2450,8 +2380,9 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg,
ret = _ctl_diag_read_buffer(ioc, arg);
break;
default:
- dctlprintk(ioc, pr_info(MPT3SAS_FMT
- "unsupported ioctl opcode(0x%08x)\n", ioc->name, cmd));
+ dctlprintk(ioc,
+ ioc_info(ioc, "unsupported ioctl opcode(0x%08x)\n",
+ cmd));
break;
}
@@ -2840,8 +2771,8 @@ _ctl_logging_level_store(struct device *cdev, struct device_attribute *attr,
return -EINVAL;
ioc->logging_level = val;
- pr_info(MPT3SAS_FMT "logging_level=%08xh\n", ioc->name,
- ioc->logging_level);
+ ioc_info(ioc, "logging_level=%08xh\n",
+ ioc->logging_level);
return strlen(buf);
}
static DEVICE_ATTR(logging_level, S_IRUGO | S_IWUSR, _ctl_logging_level_show,
@@ -2877,8 +2808,8 @@ _ctl_fwfault_debug_store(struct device *cdev, struct device_attribute *attr,
return -EINVAL;
ioc->fwfault_debug = val;
- pr_info(MPT3SAS_FMT "fwfault_debug=%d\n", ioc->name,
- ioc->fwfault_debug);
+ ioc_info(ioc, "fwfault_debug=%d\n",
+ ioc->fwfault_debug);
return strlen(buf);
}
static DEVICE_ATTR(fwfault_debug, S_IRUGO | S_IWUSR,
@@ -2958,8 +2889,8 @@ _ctl_BRM_status_show(struct device *cdev, struct device_attribute *attr,
ssize_t rc = 0;
if (!ioc->is_warpdrive) {
- pr_err(MPT3SAS_FMT "%s: BRM attribute is only for"
- " warpdrive\n", ioc->name, __func__);
+ ioc_err(ioc, "%s: BRM attribute is only for warpdrive\n",
+ __func__);
goto out;
}
/* pci_access_mutex lock acquired by sysfs show path */
@@ -2973,30 +2904,28 @@ _ctl_BRM_status_show(struct device *cdev, struct device_attribute *attr,
sz = offsetof(Mpi2IOUnitPage3_t, GPIOVal) + (sizeof(u16) * 36);
io_unit_pg3 = kzalloc(sz, GFP_KERNEL);
if (!io_unit_pg3) {
- pr_err(MPT3SAS_FMT "%s: failed allocating memory "
- "for iounit_pg3: (%d) bytes\n", ioc->name, __func__, sz);
+ ioc_err(ioc, "%s: failed allocating memory for iounit_pg3: (%d) bytes\n",
+ __func__, sz);
goto out;
}
if (mpt3sas_config_get_iounit_pg3(ioc, &mpi_reply, io_unit_pg3, sz) !=
0) {
- pr_err(MPT3SAS_FMT
- "%s: failed reading iounit_pg3\n", ioc->name,
- __func__);
+ ioc_err(ioc, "%s: failed reading iounit_pg3\n",
+ __func__);
goto out;
}
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- pr_err(MPT3SAS_FMT "%s: iounit_pg3 failed with "
- "ioc_status(0x%04x)\n", ioc->name, __func__, ioc_status);
+ ioc_err(ioc, "%s: iounit_pg3 failed with ioc_status(0x%04x)\n",
+ __func__, ioc_status);
goto out;
}
if (io_unit_pg3->GPIOCount < 25) {
- pr_err(MPT3SAS_FMT "%s: iounit_pg3->GPIOCount less than "
- "25 entries, detected (%d) entries\n", ioc->name, __func__,
- io_unit_pg3->GPIOCount);
+ ioc_err(ioc, "%s: iounit_pg3->GPIOCount less than 25 entries, detected (%d) entries\n",
+ __func__, io_unit_pg3->GPIOCount);
goto out;
}
@@ -3039,17 +2968,15 @@ _ctl_host_trace_buffer_size_show(struct device *cdev,
struct DIAG_BUFFER_START *request_data;
if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) {
- pr_err(MPT3SAS_FMT
- "%s: host_trace_buffer is not registered\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: host_trace_buffer is not registered\n",
+ __func__);
return 0;
}
if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) {
- pr_err(MPT3SAS_FMT
- "%s: host_trace_buffer is not registered\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: host_trace_buffer is not registered\n",
+ __func__);
return 0;
}
@@ -3089,17 +3016,15 @@ _ctl_host_trace_buffer_show(struct device *cdev, struct device_attribute *attr,
u32 size;
if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) {
- pr_err(MPT3SAS_FMT
- "%s: host_trace_buffer is not registered\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: host_trace_buffer is not registered\n",
+ __func__);
return 0;
}
if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) {
- pr_err(MPT3SAS_FMT
- "%s: host_trace_buffer is not registered\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: host_trace_buffer is not registered\n",
+ __func__);
return 0;
}
@@ -3188,8 +3113,7 @@ _ctl_host_trace_buffer_enable_store(struct device *cdev,
MPT3_DIAG_BUFFER_IS_RELEASED) == 0))
goto out;
memset(&diag_register, 0, sizeof(struct mpt3_diag_register));
- pr_info(MPT3SAS_FMT "posting host trace buffers\n",
- ioc->name);
+ ioc_info(ioc, "posting host trace buffers\n");
diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE;
diag_register.requested_buffer_size = (1024 * 1024);
diag_register.unique_id = 0x7075900;
@@ -3205,8 +3129,7 @@ _ctl_host_trace_buffer_enable_store(struct device *cdev,
if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
MPT3_DIAG_BUFFER_IS_RELEASED))
goto out;
- pr_info(MPT3SAS_FMT "releasing host trace buffer\n",
- ioc->name);
+ ioc_info(ioc, "releasing host trace buffer\n");
mpt3sas_send_diag_release(ioc, MPI2_DIAG_BUF_TYPE_TRACE,
&issue_reset);
}
@@ -3658,8 +3581,10 @@ mpt3sas_ctl_exit(ushort hbas_to_enumerate)
if ((ioc->diag_buffer_status[i] &
MPT3_DIAG_BUFFER_IS_RELEASED))
continue;
- pci_free_consistent(ioc->pdev, ioc->diag_buffer_sz[i],
- ioc->diag_buffer[i], ioc->diag_buffer_dma[i]);
+ dma_free_coherent(&ioc->pdev->dev,
+ ioc->diag_buffer_sz[i],
+ ioc->diag_buffer[i],
+ ioc->diag_buffer_dma[i]);
ioc->diag_buffer[i] = NULL;
ioc->diag_buffer_status[i] = 0;
}
diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
index 53133cfd420f..03c52847ed07 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
@@ -418,8 +418,8 @@ _scsih_get_sas_address(struct MPT3SAS_ADAPTER *ioc, u16 handle,
if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", ioc->name,
- __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
return -ENXIO;
}
@@ -442,10 +442,8 @@ _scsih_get_sas_address(struct MPT3SAS_ADAPTER *ioc, u16 handle,
return -ENXIO;
/* else error case */
- pr_err(MPT3SAS_FMT
- "handle(0x%04x), ioc_status(0x%04x), failure at %s:%d/%s()!\n",
- ioc->name, handle, ioc_status,
- __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "handle(0x%04x), ioc_status(0x%04x), failure at %s:%d/%s()!\n",
+ handle, ioc_status, __FILE__, __LINE__, __func__);
return -EIO;
}
@@ -508,10 +506,9 @@ _scsih_determine_boot_device(struct MPT3SAS_ADAPTER *ioc, void *device,
(ioc->bios_pg2.ReqBootDeviceForm &
MPI2_BIOSPAGE2_FORM_MASK),
&ioc->bios_pg2.RequestedBootDevice)) {
- dinitprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: req_boot_device(0x%016llx)\n",
- ioc->name, __func__,
- (unsigned long long)sas_address));
+ dinitprintk(ioc,
+ ioc_info(ioc, "%s: req_boot_device(0x%016llx)\n",
+ __func__, (u64)sas_address));
ioc->req_boot_device.device = device;
ioc->req_boot_device.channel = channel;
}
@@ -523,10 +520,9 @@ _scsih_determine_boot_device(struct MPT3SAS_ADAPTER *ioc, void *device,
(ioc->bios_pg2.ReqAltBootDeviceForm &
MPI2_BIOSPAGE2_FORM_MASK),
&ioc->bios_pg2.RequestedAltBootDevice)) {
- dinitprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: req_alt_boot_device(0x%016llx)\n",
- ioc->name, __func__,
- (unsigned long long)sas_address));
+ dinitprintk(ioc,
+ ioc_info(ioc, "%s: req_alt_boot_device(0x%016llx)\n",
+ __func__, (u64)sas_address));
ioc->req_alt_boot_device.device = device;
ioc->req_alt_boot_device.channel = channel;
}
@@ -538,10 +534,9 @@ _scsih_determine_boot_device(struct MPT3SAS_ADAPTER *ioc, void *device,
(ioc->bios_pg2.CurrentBootDeviceForm &
MPI2_BIOSPAGE2_FORM_MASK),
&ioc->bios_pg2.CurrentBootDevice)) {
- dinitprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: current_boot_device(0x%016llx)\n",
- ioc->name, __func__,
- (unsigned long long)sas_address));
+ dinitprintk(ioc,
+ ioc_info(ioc, "%s: current_boot_device(0x%016llx)\n",
+ __func__, (u64)sas_address));
ioc->current_boot_device.device = device;
ioc->current_boot_device.channel = channel;
}
@@ -752,19 +747,16 @@ _scsih_display_enclosure_chassis_info(struct MPT3SAS_ADAPTER *ioc,
sas_device->chassis_slot);
} else {
if (sas_device->enclosure_handle != 0)
- pr_info(MPT3SAS_FMT
- "enclosure logical id(0x%016llx), slot(%d) \n",
- ioc->name, (unsigned long long)
- sas_device->enclosure_logical_id,
- sas_device->slot);
+ ioc_info(ioc, "enclosure logical id(0x%016llx), slot(%d)\n",
+ (u64)sas_device->enclosure_logical_id,
+ sas_device->slot);
if (sas_device->connector_name[0] != '\0')
- pr_info(MPT3SAS_FMT
- "enclosure level(0x%04x), connector name( %s)\n",
- ioc->name, sas_device->enclosure_level,
- sas_device->connector_name);
+ ioc_info(ioc, "enclosure level(0x%04x), connector name( %s)\n",
+ sas_device->enclosure_level,
+ sas_device->connector_name);
if (sas_device->is_chassis_slot_valid)
- pr_info(MPT3SAS_FMT "chassis slot(0x%04x)\n",
- ioc->name, sas_device->chassis_slot);
+ ioc_info(ioc, "chassis slot(0x%04x)\n",
+ sas_device->chassis_slot);
}
}
@@ -784,10 +776,8 @@ _scsih_sas_device_remove(struct MPT3SAS_ADAPTER *ioc,
if (!sas_device)
return;
- pr_info(MPT3SAS_FMT
- "removing handle(0x%04x), sas_addr(0x%016llx)\n",
- ioc->name, sas_device->handle,
- (unsigned long long) sas_device->sas_address);
+ ioc_info(ioc, "removing handle(0x%04x), sas_addr(0x%016llx)\n",
+ sas_device->handle, (u64)sas_device->sas_address);
_scsih_display_enclosure_chassis_info(ioc, sas_device, NULL, NULL);
@@ -872,10 +862,10 @@ _scsih_sas_device_add(struct MPT3SAS_ADAPTER *ioc,
{
unsigned long flags;
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: handle(0x%04x), sas_addr(0x%016llx)\n",
- ioc->name, __func__, sas_device->handle,
- (unsigned long long)sas_device->sas_address));
+ dewtprintk(ioc,
+ ioc_info(ioc, "%s: handle(0x%04x), sas_addr(0x%016llx)\n",
+ __func__, sas_device->handle,
+ (u64)sas_device->sas_address));
dewtprintk(ioc, _scsih_display_enclosure_chassis_info(ioc, sas_device,
NULL, NULL));
@@ -923,10 +913,10 @@ _scsih_sas_device_init_add(struct MPT3SAS_ADAPTER *ioc,
{
unsigned long flags;
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name,
- __func__, sas_device->handle,
- (unsigned long long)sas_device->sas_address));
+ dewtprintk(ioc,
+ ioc_info(ioc, "%s: handle(0x%04x), sas_addr(0x%016llx)\n",
+ __func__, sas_device->handle,
+ (u64)sas_device->sas_address));
dewtprintk(ioc, _scsih_display_enclosure_chassis_info(ioc, sas_device,
NULL, NULL));
@@ -1073,21 +1063,16 @@ _scsih_pcie_device_remove(struct MPT3SAS_ADAPTER *ioc,
if (!pcie_device)
return;
- pr_info(MPT3SAS_FMT
- "removing handle(0x%04x), wwid(0x%016llx)\n",
- ioc->name, pcie_device->handle,
- (unsigned long long) pcie_device->wwid);
+ ioc_info(ioc, "removing handle(0x%04x), wwid(0x%016llx)\n",
+ pcie_device->handle, (u64)pcie_device->wwid);
if (pcie_device->enclosure_handle != 0)
- pr_info(MPT3SAS_FMT
- "removing enclosure logical id(0x%016llx), slot(%d)\n",
- ioc->name,
- (unsigned long long)pcie_device->enclosure_logical_id,
- pcie_device->slot);
+ ioc_info(ioc, "removing enclosure logical id(0x%016llx), slot(%d)\n",
+ (u64)pcie_device->enclosure_logical_id,
+ pcie_device->slot);
if (pcie_device->connector_name[0] != '\0')
- pr_info(MPT3SAS_FMT
- "removing enclosure level(0x%04x), connector name( %s)\n",
- ioc->name, pcie_device->enclosure_level,
- pcie_device->connector_name);
+ ioc_info(ioc, "removing enclosure level(0x%04x), connector name( %s)\n",
+ pcie_device->enclosure_level,
+ pcie_device->connector_name);
spin_lock_irqsave(&ioc->pcie_device_lock, flags);
if (!list_empty(&pcie_device->list)) {
@@ -1146,20 +1131,21 @@ _scsih_pcie_device_add(struct MPT3SAS_ADAPTER *ioc,
{
unsigned long flags;
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: handle (0x%04x), wwid(0x%016llx)\n", ioc->name, __func__,
- pcie_device->handle, (unsigned long long)pcie_device->wwid));
+ dewtprintk(ioc,
+ ioc_info(ioc, "%s: handle (0x%04x), wwid(0x%016llx)\n",
+ __func__,
+ pcie_device->handle, (u64)pcie_device->wwid));
if (pcie_device->enclosure_handle != 0)
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: enclosure logical id(0x%016llx), slot( %d)\n",
- ioc->name, __func__,
- (unsigned long long)pcie_device->enclosure_logical_id,
- pcie_device->slot));
+ dewtprintk(ioc,
+ ioc_info(ioc, "%s: enclosure logical id(0x%016llx), slot( %d)\n",
+ __func__,
+ (u64)pcie_device->enclosure_logical_id,
+ pcie_device->slot));
if (pcie_device->connector_name[0] != '\0')
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: enclosure level(0x%04x), connector name( %s)\n",
- ioc->name, __func__, pcie_device->enclosure_level,
- pcie_device->connector_name));
+ dewtprintk(ioc,
+ ioc_info(ioc, "%s: enclosure level(0x%04x), connector name( %s)\n",
+ __func__, pcie_device->enclosure_level,
+ pcie_device->connector_name));
spin_lock_irqsave(&ioc->pcie_device_lock, flags);
pcie_device_get(pcie_device);
@@ -1191,20 +1177,21 @@ _scsih_pcie_device_init_add(struct MPT3SAS_ADAPTER *ioc,
{
unsigned long flags;
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: handle (0x%04x), wwid(0x%016llx)\n", ioc->name, __func__,
- pcie_device->handle, (unsigned long long)pcie_device->wwid));
+ dewtprintk(ioc,
+ ioc_info(ioc, "%s: handle (0x%04x), wwid(0x%016llx)\n",
+ __func__,
+ pcie_device->handle, (u64)pcie_device->wwid));
if (pcie_device->enclosure_handle != 0)
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: enclosure logical id(0x%016llx), slot( %d)\n",
- ioc->name, __func__,
- (unsigned long long)pcie_device->enclosure_logical_id,
- pcie_device->slot));
+ dewtprintk(ioc,
+ ioc_info(ioc, "%s: enclosure logical id(0x%016llx), slot( %d)\n",
+ __func__,
+ (u64)pcie_device->enclosure_logical_id,
+ pcie_device->slot));
if (pcie_device->connector_name[0] != '\0')
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: enclosure level(0x%04x), connector name( %s)\n",
- ioc->name, __func__, pcie_device->enclosure_level,
- pcie_device->connector_name));
+ dewtprintk(ioc,
+ ioc_info(ioc, "%s: enclosure level(0x%04x), connector name( %s)\n",
+ __func__, pcie_device->enclosure_level,
+ pcie_device->connector_name));
spin_lock_irqsave(&ioc->pcie_device_lock, flags);
pcie_device_get(pcie_device);
@@ -1304,9 +1291,10 @@ _scsih_raid_device_add(struct MPT3SAS_ADAPTER *ioc,
{
unsigned long flags;
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: handle(0x%04x), wwid(0x%016llx)\n", ioc->name, __func__,
- raid_device->handle, (unsigned long long)raid_device->wwid));
+ dewtprintk(ioc,
+ ioc_info(ioc, "%s: handle(0x%04x), wwid(0x%016llx)\n",
+ __func__,
+ raid_device->handle, (u64)raid_device->wwid));
spin_lock_irqsave(&ioc->raid_device_lock, flags);
list_add_tail(&raid_device->list, &ioc->raid_device_list);
@@ -1857,16 +1845,16 @@ _scsih_display_sata_capabilities(struct MPT3SAS_ADAPTER *ioc,
if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
return;
}
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
MPI2_IOCSTATUS_MASK;
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
return;
}
@@ -1952,8 +1940,8 @@ scsih_get_resync(struct device *dev)
if (mpt3sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0,
MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle,
sizeof(Mpi2RaidVolPage0_t))) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
percent_complete = 0;
goto out;
}
@@ -2006,8 +1994,8 @@ scsih_get_state(struct device *dev)
if (mpt3sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0,
MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle,
sizeof(Mpi2RaidVolPage0_t))) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
goto out;
}
@@ -2103,9 +2091,9 @@ _scsih_get_volume_capabilities(struct MPT3SAS_ADAPTER *ioc,
if ((mpt3sas_config_get_number_pds(ioc, raid_device->handle,
&num_pds)) || !num_pds) {
- dfailprintk(ioc, pr_warn(MPT3SAS_FMT
- "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__,
- __func__));
+ dfailprintk(ioc,
+ ioc_warn(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__));
return 1;
}
@@ -2114,17 +2102,17 @@ _scsih_get_volume_capabilities(struct MPT3SAS_ADAPTER *ioc,
sizeof(Mpi2RaidVol0PhysDisk_t));
vol_pg0 = kzalloc(sz, GFP_KERNEL);
if (!vol_pg0) {
- dfailprintk(ioc, pr_warn(MPT3SAS_FMT
- "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__,
- __func__));
+ dfailprintk(ioc,
+ ioc_warn(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__));
return 1;
}
if ((mpt3sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0,
MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) {
- dfailprintk(ioc, pr_warn(MPT3SAS_FMT
- "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__,
- __func__));
+ dfailprintk(ioc,
+ ioc_warn(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__));
kfree(vol_pg0);
return 1;
}
@@ -2215,16 +2203,16 @@ scsih_slave_configure(struct scsi_device *sdev)
raid_device = mpt3sas_raid_device_find_by_handle(ioc, handle);
spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
if (!raid_device) {
- dfailprintk(ioc, pr_warn(MPT3SAS_FMT
- "failure at %s:%d/%s()!\n", ioc->name, __FILE__,
- __LINE__, __func__));
+ dfailprintk(ioc,
+ ioc_warn(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__));
return 1;
}
if (_scsih_get_volume_capabilities(ioc, raid_device)) {
- dfailprintk(ioc, pr_warn(MPT3SAS_FMT
- "failure at %s:%d/%s()!\n", ioc->name, __FILE__,
- __LINE__, __func__));
+ dfailprintk(ioc,
+ ioc_warn(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__));
return 1;
}
@@ -2308,16 +2296,16 @@ scsih_slave_configure(struct scsi_device *sdev)
if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
if (mpt3sas_config_get_volume_handle(ioc, handle,
&volume_handle)) {
- dfailprintk(ioc, pr_warn(MPT3SAS_FMT
- "failure at %s:%d/%s()!\n", ioc->name,
- __FILE__, __LINE__, __func__));
+ dfailprintk(ioc,
+ ioc_warn(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__));
return 1;
}
if (volume_handle && mpt3sas_config_get_volume_wwid(ioc,
volume_handle, &volume_wwid)) {
- dfailprintk(ioc, pr_warn(MPT3SAS_FMT
- "failure at %s:%d/%s()!\n", ioc->name,
- __FILE__, __LINE__, __func__));
+ dfailprintk(ioc,
+ ioc_warn(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__));
return 1;
}
}
@@ -2329,9 +2317,9 @@ scsih_slave_configure(struct scsi_device *sdev)
sas_device_priv_data->sas_target->sas_address);
if (!pcie_device) {
spin_unlock_irqrestore(&ioc->pcie_device_lock, flags);
- dfailprintk(ioc, pr_warn(MPT3SAS_FMT
- "failure at %s:%d/%s()!\n", ioc->name, __FILE__,
- __LINE__, __func__));
+ dfailprintk(ioc,
+ ioc_warn(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__));
return 1;
}
@@ -2377,9 +2365,9 @@ scsih_slave_configure(struct scsi_device *sdev)
sas_device_priv_data->sas_target->sas_address);
if (!sas_device) {
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- dfailprintk(ioc, pr_warn(MPT3SAS_FMT
- "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__,
- __func__));
+ dfailprintk(ioc,
+ ioc_warn(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__));
return 1;
}
@@ -2515,8 +2503,7 @@ _scsih_response_code(struct MPT3SAS_ADAPTER *ioc, u8 response_code)
desc = "unknown";
break;
}
- pr_warn(MPT3SAS_FMT "response_code(0x%01x): %s\n",
- ioc->name, response_code, desc);
+ ioc_warn(ioc, "response_code(0x%01x): %s\n", response_code, desc);
}
/**
@@ -2640,22 +2627,19 @@ mpt3sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle, u64 lun,
lockdep_assert_held(&ioc->tm_cmds.mutex);
if (ioc->tm_cmds.status != MPT3_CMD_NOT_USED) {
- pr_info(MPT3SAS_FMT "%s: tm_cmd busy!!!\n",
- __func__, ioc->name);
+ ioc_info(ioc, "%s: tm_cmd busy!!!\n", __func__);
return FAILED;
}
if (ioc->shost_recovery || ioc->remove_host ||
ioc->pci_error_recovery) {
- pr_info(MPT3SAS_FMT "%s: host reset in progress!\n",
- __func__, ioc->name);
+ ioc_info(ioc, "%s: host reset in progress!\n", __func__);
return FAILED;
}
ioc_state = mpt3sas_base_get_iocstate(ioc, 0);
if (ioc_state & MPI2_DOORBELL_USED) {
- dhsprintk(ioc, pr_info(MPT3SAS_FMT
- "unexpected doorbell active!\n", ioc->name));
+ dhsprintk(ioc, ioc_info(ioc, "unexpected doorbell active!\n"));
rc = mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
return (!rc) ? SUCCESS : FAILED;
}
@@ -2669,14 +2653,13 @@ mpt3sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle, u64 lun,
smid = mpt3sas_base_get_smid_hpr(ioc, ioc->tm_cb_idx);
if (!smid) {
- pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);
return FAILED;
}
- dtmprintk(ioc, pr_info(MPT3SAS_FMT
- "sending tm: handle(0x%04x), task_type(0x%02x), smid(%d), timeout(%d), tr_method(0x%x)\n",
- ioc->name, handle, type, smid_task, timeout, tr_method));
+ dtmprintk(ioc,
+ ioc_info(ioc, "sending tm: handle(0x%04x), task_type(0x%02x), smid(%d), timeout(%d), tr_method(0x%x)\n",
+ handle, type, smid_task, timeout, tr_method));
ioc->tm_cmds.status = MPT3_CMD_PENDING;
mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
ioc->tm_cmds.smid = smid;
@@ -2709,11 +2692,11 @@ mpt3sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle, u64 lun,
if (ioc->tm_cmds.status & MPT3_CMD_REPLY_VALID) {
mpt3sas_trigger_master(ioc, MASTER_TRIGGER_TASK_MANAGMENT);
mpi_reply = ioc->tm_cmds.reply;
- dtmprintk(ioc, pr_info(MPT3SAS_FMT "complete tm: " \
- "ioc_status(0x%04x), loginfo(0x%08x), term_count(0x%08x)\n",
- ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
- le32_to_cpu(mpi_reply->IOCLogInfo),
- le32_to_cpu(mpi_reply->TerminationCount)));
+ dtmprintk(ioc,
+ ioc_info(ioc, "complete tm: ioc_status(0x%04x), loginfo(0x%08x), term_count(0x%08x)\n",
+ le16_to_cpu(mpi_reply->IOCStatus),
+ le32_to_cpu(mpi_reply->IOCLogInfo),
+ le32_to_cpu(mpi_reply->TerminationCount)));
if (ioc->logging_level & MPT_DEBUG_TM) {
_scsih_response_code(ioc, mpi_reply->ResponseCode);
if (mpi_reply->IOCStatus)
@@ -3060,13 +3043,11 @@ scsih_host_reset(struct scsi_cmnd *scmd)
struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
int r, retval;
- pr_info(MPT3SAS_FMT "attempting host reset! scmd(%p)\n",
- ioc->name, scmd);
+ ioc_info(ioc, "attempting host reset! scmd(%p)\n", scmd);
scsi_print_command(scmd);
if (ioc->is_driver_loading || ioc->remove_host) {
- pr_info(MPT3SAS_FMT "Blocking the host reset\n",
- ioc->name);
+ ioc_info(ioc, "Blocking the host reset\n");
r = FAILED;
goto out;
}
@@ -3074,8 +3055,8 @@ scsih_host_reset(struct scsi_cmnd *scmd)
retval = mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
r = (retval < 0) ? FAILED : SUCCESS;
out:
- pr_info(MPT3SAS_FMT "host reset: %s scmd(%p)\n",
- ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
+ ioc_info(ioc, "host reset: %s scmd(%p)\n",
+ r == SUCCESS ? "SUCCESS" : "FAILED", scmd);
return r;
}
@@ -3567,18 +3548,16 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
u8 tr_method = 0;
if (ioc->pci_error_recovery) {
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: host in pci error recovery: handle(0x%04x)\n",
- __func__, ioc->name,
- handle));
+ dewtprintk(ioc,
+ ioc_info(ioc, "%s: host in pci error recovery: handle(0x%04x)\n",
+ __func__, handle));
return;
}
ioc_state = mpt3sas_base_get_iocstate(ioc, 1);
if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: host is not operational: handle(0x%04x)\n",
- __func__, ioc->name,
- handle));
+ dewtprintk(ioc,
+ ioc_info(ioc, "%s: host is not operational: handle(0x%04x)\n",
+ __func__, handle));
return;
}
@@ -3614,39 +3593,31 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
tr_method = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET;
}
if (sas_target_priv_data) {
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "setting delete flag: handle(0x%04x), sas_addr(0x%016llx)\n",
- ioc->name, handle,
- (unsigned long long)sas_address));
+ dewtprintk(ioc,
+ ioc_info(ioc, "setting delete flag: handle(0x%04x), sas_addr(0x%016llx)\n",
+ handle, (u64)sas_address));
if (sas_device) {
if (sas_device->enclosure_handle != 0)
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "setting delete flag:enclosure logical "
- "id(0x%016llx), slot(%d)\n", ioc->name,
- (unsigned long long)
- sas_device->enclosure_logical_id,
- sas_device->slot));
+ dewtprintk(ioc,
+ ioc_info(ioc, "setting delete flag:enclosure logical id(0x%016llx), slot(%d)\n",
+ (u64)sas_device->enclosure_logical_id,
+ sas_device->slot));
if (sas_device->connector_name[0] != '\0')
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "setting delete flag: enclosure "
- "level(0x%04x), connector name( %s)\n",
- ioc->name, sas_device->enclosure_level,
- sas_device->connector_name));
+ dewtprintk(ioc,
+ ioc_info(ioc, "setting delete flag: enclosure level(0x%04x), connector name( %s)\n",
+ sas_device->enclosure_level,
+ sas_device->connector_name));
} else if (pcie_device) {
if (pcie_device->enclosure_handle != 0)
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "setting delete flag: logical "
- "id(0x%016llx), slot(%d)\n", ioc->name,
- (unsigned long long)
- pcie_device->enclosure_logical_id,
- pcie_device->slot));
+ dewtprintk(ioc,
+ ioc_info(ioc, "setting delete flag: logical id(0x%016llx), slot(%d)\n",
+ (u64)pcie_device->enclosure_logical_id,
+ pcie_device->slot));
if (pcie_device->connector_name[0] != '\0')
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "setting delete flag:, enclosure "
- "level(0x%04x), "
- "connector name( %s)\n", ioc->name,
- pcie_device->enclosure_level,
- pcie_device->connector_name));
+ dewtprintk(ioc,
+ ioc_info(ioc, "setting delete flag:, enclosure level(0x%04x), connector name( %s)\n",
+ pcie_device->enclosure_level,
+ pcie_device->connector_name));
}
_scsih_ublock_io_device(ioc, sas_address);
sas_target_priv_data->handle = MPT3SAS_INVALID_DEVICE_HANDLE;
@@ -3660,16 +3631,15 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
INIT_LIST_HEAD(&delayed_tr->list);
delayed_tr->handle = handle;
list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list);
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "DELAYED:tr:handle(0x%04x), (open)\n",
- ioc->name, handle));
+ dewtprintk(ioc,
+ ioc_info(ioc, "DELAYED:tr:handle(0x%04x), (open)\n",
+ handle));
goto out;
}
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "tr_send:handle(0x%04x), (open), smid(%d), cb(%d)\n",
- ioc->name, handle, smid,
- ioc->tm_tr_cb_idx));
+ dewtprintk(ioc,
+ ioc_info(ioc, "tr_send:handle(0x%04x), (open), smid(%d), cb(%d)\n",
+ handle, smid, ioc->tm_tr_cb_idx));
mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));
mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
@@ -3717,39 +3687,39 @@ _scsih_tm_tr_complete(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
struct _sc_list *delayed_sc;
if (ioc->pci_error_recovery) {
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: host in pci error recovery\n", __func__,
- ioc->name));
+ dewtprintk(ioc,
+ ioc_info(ioc, "%s: host in pci error recovery\n",
+ __func__));
return 1;
}
ioc_state = mpt3sas_base_get_iocstate(ioc, 1);
if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: host is not operational\n", __func__, ioc->name));
+ dewtprintk(ioc,
+ ioc_info(ioc, "%s: host is not operational\n",
+ __func__));
return 1;
}
if (unlikely(!mpi_reply)) {
- pr_err(MPT3SAS_FMT "mpi_reply not valid at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "mpi_reply not valid at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
return 1;
}
mpi_request_tm = mpt3sas_base_get_msg_frame(ioc, smid);
handle = le16_to_cpu(mpi_request_tm->DevHandle);
if (handle != le16_to_cpu(mpi_reply->DevHandle)) {
- dewtprintk(ioc, pr_err(MPT3SAS_FMT
- "spurious interrupt: handle(0x%04x:0x%04x), smid(%d)!!!\n",
- ioc->name, handle,
- le16_to_cpu(mpi_reply->DevHandle), smid));
+ dewtprintk(ioc,
+ ioc_err(ioc, "spurious interrupt: handle(0x%04x:0x%04x), smid(%d)!!!\n",
+ handle,
+ le16_to_cpu(mpi_reply->DevHandle), smid));
return 0;
}
mpt3sas_trigger_master(ioc, MASTER_TRIGGER_TASK_MANAGMENT);
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), "
- "loginfo(0x%08x), completed(%d)\n", ioc->name,
- handle, smid, le16_to_cpu(mpi_reply->IOCStatus),
- le32_to_cpu(mpi_reply->IOCLogInfo),
- le32_to_cpu(mpi_reply->TerminationCount)));
+ dewtprintk(ioc,
+ ioc_info(ioc, "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), loginfo(0x%08x), completed(%d)\n",
+ handle, smid, le16_to_cpu(mpi_reply->IOCStatus),
+ le32_to_cpu(mpi_reply->IOCLogInfo),
+ le32_to_cpu(mpi_reply->TerminationCount)));
smid_sas_ctrl = mpt3sas_base_get_smid(ioc, ioc->tm_sas_control_cb_idx);
if (!smid_sas_ctrl) {
@@ -3759,16 +3729,15 @@ _scsih_tm_tr_complete(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
INIT_LIST_HEAD(&delayed_sc->list);
delayed_sc->handle = le16_to_cpu(mpi_request_tm->DevHandle);
list_add_tail(&delayed_sc->list, &ioc->delayed_sc_list);
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "DELAYED:sc:handle(0x%04x), (open)\n",
- ioc->name, handle));
+ dewtprintk(ioc,
+ ioc_info(ioc, "DELAYED:sc:handle(0x%04x), (open)\n",
+ handle));
return _scsih_check_for_pending_tm(ioc, smid);
}
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "sc_send:handle(0x%04x), (open), smid(%d), cb(%d)\n",
- ioc->name, handle, smid_sas_ctrl,
- ioc->tm_sas_control_cb_idx));
+ dewtprintk(ioc,
+ ioc_info(ioc, "sc_send:handle(0x%04x), (open), smid(%d), cb(%d)\n",
+ handle, smid_sas_ctrl, ioc->tm_sas_control_cb_idx));
mpi_request = mpt3sas_base_get_msg_frame(ioc, smid_sas_ctrl);
memset(mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));
mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
@@ -3803,20 +3772,19 @@ _scsih_sas_control_complete(struct MPT3SAS_ADAPTER *ioc, u16 smid,
mpt3sas_base_get_reply_virt_addr(ioc, reply);
if (likely(mpi_reply)) {
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "sc_complete:handle(0x%04x), (open) "
- "smid(%d), ioc_status(0x%04x), loginfo(0x%08x)\n",
- ioc->name, le16_to_cpu(mpi_reply->DevHandle), smid,
- le16_to_cpu(mpi_reply->IOCStatus),
- le32_to_cpu(mpi_reply->IOCLogInfo)));
+ dewtprintk(ioc,
+ ioc_info(ioc, "sc_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), loginfo(0x%08x)\n",
+ le16_to_cpu(mpi_reply->DevHandle), smid,
+ le16_to_cpu(mpi_reply->IOCStatus),
+ le32_to_cpu(mpi_reply->IOCLogInfo)));
if (le16_to_cpu(mpi_reply->IOCStatus) ==
MPI2_IOCSTATUS_SUCCESS) {
clear_bit(le16_to_cpu(mpi_reply->DevHandle),
ioc->device_remove_in_progress);
}
} else {
- pr_err(MPT3SAS_FMT "mpi_reply not valid at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "mpi_reply not valid at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
}
return mpt3sas_check_for_pending_internal_cmds(ioc, smid);
}
@@ -3839,9 +3807,9 @@ _scsih_tm_tr_volume_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
struct _tr_list *delayed_tr;
if (ioc->pci_error_recovery) {
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: host reset in progress!\n",
- __func__, ioc->name));
+ dewtprintk(ioc,
+ ioc_info(ioc, "%s: host reset in progress!\n",
+ __func__));
return;
}
@@ -3853,16 +3821,15 @@ _scsih_tm_tr_volume_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
INIT_LIST_HEAD(&delayed_tr->list);
delayed_tr->handle = handle;
list_add_tail(&delayed_tr->list, &ioc->delayed_tr_volume_list);
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "DELAYED:tr:handle(0x%04x), (open)\n",
- ioc->name, handle));
+ dewtprintk(ioc,
+ ioc_info(ioc, "DELAYED:tr:handle(0x%04x), (open)\n",
+ handle));
return;
}
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "tr_send:handle(0x%04x), (open), smid(%d), cb(%d)\n",
- ioc->name, handle, smid,
- ioc->tm_tr_volume_cb_idx));
+ dewtprintk(ioc,
+ ioc_info(ioc, "tr_send:handle(0x%04x), (open), smid(%d), cb(%d)\n",
+ handle, smid, ioc->tm_tr_volume_cb_idx));
mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));
mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
@@ -3892,33 +3859,32 @@ _scsih_tm_volume_tr_complete(struct MPT3SAS_ADAPTER *ioc, u16 smid,
mpt3sas_base_get_reply_virt_addr(ioc, reply);
if (ioc->shost_recovery || ioc->pci_error_recovery) {
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: host reset in progress!\n",
- __func__, ioc->name));
+ dewtprintk(ioc,
+ ioc_info(ioc, "%s: host reset in progress!\n",
+ __func__));
return 1;
}
if (unlikely(!mpi_reply)) {
- pr_err(MPT3SAS_FMT "mpi_reply not valid at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "mpi_reply not valid at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
return 1;
}
mpi_request_tm = mpt3sas_base_get_msg_frame(ioc, smid);
handle = le16_to_cpu(mpi_request_tm->DevHandle);
if (handle != le16_to_cpu(mpi_reply->DevHandle)) {
- dewtprintk(ioc, pr_err(MPT3SAS_FMT
- "spurious interrupt: handle(0x%04x:0x%04x), smid(%d)!!!\n",
- ioc->name, handle,
- le16_to_cpu(mpi_reply->DevHandle), smid));
+ dewtprintk(ioc,
+ ioc_err(ioc, "spurious interrupt: handle(0x%04x:0x%04x), smid(%d)!!!\n",
+ handle, le16_to_cpu(mpi_reply->DevHandle),
+ smid));
return 0;
}
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), "
- "loginfo(0x%08x), completed(%d)\n", ioc->name,
- handle, smid, le16_to_cpu(mpi_reply->IOCStatus),
- le32_to_cpu(mpi_reply->IOCLogInfo),
- le32_to_cpu(mpi_reply->TerminationCount)));
+ dewtprintk(ioc,
+ ioc_info(ioc, "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), loginfo(0x%08x), completed(%d)\n",
+ handle, smid, le16_to_cpu(mpi_reply->IOCStatus),
+ le32_to_cpu(mpi_reply->IOCLogInfo),
+ le32_to_cpu(mpi_reply->TerminationCount)));
return _scsih_check_for_pending_tm(ioc, smid);
}
@@ -3948,10 +3914,9 @@ _scsih_issue_delayed_event_ack(struct MPT3SAS_ADAPTER *ioc, u16 smid, U16 event,
ioc->internal_lookup[i].cb_idx = ioc->base_cb_idx;
spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "EVENT ACK: event(0x%04x), smid(%d), cb(%d)\n",
- ioc->name, le16_to_cpu(event), smid,
- ioc->base_cb_idx));
+ dewtprintk(ioc,
+ ioc_info(ioc, "EVENT ACK: event(0x%04x), smid(%d), cb(%d)\n",
+ le16_to_cpu(event), smid, ioc->base_cb_idx));
ack_request = mpt3sas_base_get_msg_frame(ioc, smid);
memset(ack_request, 0, sizeof(Mpi2EventAckRequest_t));
ack_request->Function = MPI2_FUNCTION_EVENT_ACK;
@@ -3981,21 +3946,21 @@ _scsih_issue_delayed_sas_io_unit_ctrl(struct MPT3SAS_ADAPTER *ioc,
unsigned long flags;
if (ioc->remove_host) {
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: host has been removed\n",
- __func__, ioc->name));
+ dewtprintk(ioc,
+ ioc_info(ioc, "%s: host has been removed\n",
+ __func__));
return;
} else if (ioc->pci_error_recovery) {
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: host in pci error recovery\n",
- __func__, ioc->name));
+ dewtprintk(ioc,
+ ioc_info(ioc, "%s: host in pci error recovery\n",
+ __func__));
return;
}
ioc_state = mpt3sas_base_get_iocstate(ioc, 1);
if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: host is not operational\n",
- __func__, ioc->name));
+ dewtprintk(ioc,
+ ioc_info(ioc, "%s: host is not operational\n",
+ __func__));
return;
}
@@ -4007,10 +3972,9 @@ _scsih_issue_delayed_sas_io_unit_ctrl(struct MPT3SAS_ADAPTER *ioc,
ioc->internal_lookup[i].cb_idx = ioc->tm_sas_control_cb_idx;
spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "sc_send:handle(0x%04x), (open), smid(%d), cb(%d)\n",
- ioc->name, handle, smid,
- ioc->tm_sas_control_cb_idx));
+ dewtprintk(ioc,
+ ioc_info(ioc, "sc_send:handle(0x%04x), (open), smid(%d), cb(%d)\n",
+ handle, smid, ioc->tm_sas_control_cb_idx));
mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
memset(mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));
mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
@@ -4171,8 +4135,8 @@ _scsih_check_topo_delete_events(struct MPT3SAS_ADAPTER *ioc,
MPI2_EVENT_SAS_TOPO_ES_RESPONDING) {
if (le16_to_cpu(local_event_data->ExpanderDevHandle) ==
expander_handle) {
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "setting ignoring flag\n", ioc->name));
+ dewtprintk(ioc,
+ ioc_info(ioc, "setting ignoring flag\n"));
fw_event->ignore = 1;
}
}
@@ -4243,9 +4207,8 @@ _scsih_check_pcie_topo_remove_events(struct MPT3SAS_ADAPTER *ioc,
MPI2_EVENT_SAS_TOPO_ES_RESPONDING) {
if (le16_to_cpu(local_event_data->SwitchDevHandle) ==
switch_handle) {
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "setting ignoring flag for switch event\n",
- ioc->name));
+ dewtprintk(ioc,
+ ioc_info(ioc, "setting ignoring flag for switch event\n"));
fw_event->ignore = 1;
}
}
@@ -4274,10 +4237,9 @@ _scsih_set_volume_delete_flag(struct MPT3SAS_ADAPTER *ioc, u16 handle)
sas_target_priv_data =
raid_device->starget->hostdata;
sas_target_priv_data->deleted = 1;
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "setting delete flag: handle(0x%04x), "
- "wwid(0x%016llx)\n", ioc->name, handle,
- (unsigned long long) raid_device->wwid));
+ dewtprintk(ioc,
+ ioc_info(ioc, "setting delete flag: handle(0x%04x), wwid(0x%016llx)\n",
+ handle, (u64)raid_device->wwid));
}
spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
}
@@ -4379,9 +4341,9 @@ _scsih_check_ir_config_unhide_events(struct MPT3SAS_ADAPTER *ioc,
INIT_LIST_HEAD(&delayed_tr->list);
delayed_tr->handle = handle;
list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list);
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "DELAYED:tr:handle(0x%04x), (open)\n", ioc->name,
- handle));
+ dewtprintk(ioc,
+ ioc_info(ioc, "DELAYED:tr:handle(0x%04x), (open)\n",
+ handle));
} else
_scsih_tm_tr_send(ioc, handle);
}
@@ -4424,15 +4386,14 @@ _scsih_temp_threshold_events(struct MPT3SAS_ADAPTER *ioc,
Mpi2EventDataTemperature_t *event_data)
{
if (ioc->temp_sensors_count >= event_data->SensorNum) {
- pr_err(MPT3SAS_FMT "Temperature Threshold flags %s%s%s%s"
- " exceeded for Sensor: %d !!!\n", ioc->name,
- ((le16_to_cpu(event_data->Status) & 0x1) == 1) ? "0 " : " ",
- ((le16_to_cpu(event_data->Status) & 0x2) == 2) ? "1 " : " ",
- ((le16_to_cpu(event_data->Status) & 0x4) == 4) ? "2 " : " ",
- ((le16_to_cpu(event_data->Status) & 0x8) == 8) ? "3 " : " ",
- event_data->SensorNum);
- pr_err(MPT3SAS_FMT "Current Temp In Celsius: %d\n",
- ioc->name, event_data->CurrentTemperature);
+ ioc_err(ioc, "Temperature Threshold flags %s%s%s%s exceeded for Sensor: %d !!!\n",
+ le16_to_cpu(event_data->Status) & 0x1 ? "0 " : " ",
+ le16_to_cpu(event_data->Status) & 0x2 ? "1 " : " ",
+ le16_to_cpu(event_data->Status) & 0x4 ? "2 " : " ",
+ le16_to_cpu(event_data->Status) & 0x8 ? "3 " : " ",
+ event_data->SensorNum);
+ ioc_err(ioc, "Current Temp In Celsius: %d\n",
+ event_data->CurrentTemperature);
}
}
@@ -4480,8 +4441,7 @@ _scsih_flush_running_cmds(struct MPT3SAS_ADAPTER *ioc)
scmd->result = DID_RESET << 16;
scmd->scsi_done(scmd);
}
- dtmprintk(ioc, pr_info(MPT3SAS_FMT "completing %d cmds\n",
- ioc->name, count));
+ dtmprintk(ioc, ioc_info(ioc, "completing %d cmds\n", count));
}
/**
@@ -4680,8 +4640,7 @@ scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
smid = mpt3sas_base_get_smid_scsiio(ioc, ioc->scsi_io_cb_idx, scmd);
if (!smid) {
- pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);
_scsih_set_satl_pending(scmd, false);
goto out;
}
@@ -4919,37 +4878,28 @@ _scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
scsi_print_command(scmd);
if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) {
- pr_warn(MPT3SAS_FMT "\t%s wwid(0x%016llx)\n", ioc->name,
- device_str, (unsigned long long)priv_target->sas_address);
+ ioc_warn(ioc, "\t%s wwid(0x%016llx)\n",
+ device_str, (u64)priv_target->sas_address);
} else if (priv_target->flags & MPT_TARGET_FLAGS_PCIE_DEVICE) {
pcie_device = mpt3sas_get_pdev_from_target(ioc, priv_target);
if (pcie_device) {
- pr_info(MPT3SAS_FMT "\twwid(0x%016llx), port(%d)\n",
- ioc->name,
- (unsigned long long)pcie_device->wwid,
- pcie_device->port_num);
+ ioc_info(ioc, "\twwid(0x%016llx), port(%d)\n",
+ (u64)pcie_device->wwid, pcie_device->port_num);
if (pcie_device->enclosure_handle != 0)
- pr_info(MPT3SAS_FMT
- "\tenclosure logical id(0x%016llx), "
- "slot(%d)\n", ioc->name,
- (unsigned long long)
- pcie_device->enclosure_logical_id,
- pcie_device->slot);
+ ioc_info(ioc, "\tenclosure logical id(0x%016llx), slot(%d)\n",
+ (u64)pcie_device->enclosure_logical_id,
+ pcie_device->slot);
if (pcie_device->connector_name[0])
- pr_info(MPT3SAS_FMT
- "\tenclosure level(0x%04x),"
- "connector name( %s)\n",
- ioc->name, pcie_device->enclosure_level,
- pcie_device->connector_name);
+ ioc_info(ioc, "\tenclosure level(0x%04x), connector name( %s)\n",
+ pcie_device->enclosure_level,
+ pcie_device->connector_name);
pcie_device_put(pcie_device);
}
} else {
sas_device = mpt3sas_get_sdev_from_target(ioc, priv_target);
if (sas_device) {
- pr_warn(MPT3SAS_FMT
- "\tsas_address(0x%016llx), phy(%d)\n",
- ioc->name, (unsigned long long)
- sas_device->sas_address, sas_device->phy);
+ ioc_warn(ioc, "\tsas_address(0x%016llx), phy(%d)\n",
+ (u64)sas_device->sas_address, sas_device->phy);
_scsih_display_enclosure_chassis_info(ioc, sas_device,
NULL, NULL);
@@ -4958,30 +4908,23 @@ _scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
}
}
- pr_warn(MPT3SAS_FMT
- "\thandle(0x%04x), ioc_status(%s)(0x%04x), smid(%d)\n",
- ioc->name, le16_to_cpu(mpi_reply->DevHandle),
- desc_ioc_state, ioc_status, smid);
- pr_warn(MPT3SAS_FMT
- "\trequest_len(%d), underflow(%d), resid(%d)\n",
- ioc->name, scsi_bufflen(scmd), scmd->underflow,
- scsi_get_resid(scmd));
- pr_warn(MPT3SAS_FMT
- "\ttag(%d), transfer_count(%d), sc->result(0x%08x)\n",
- ioc->name, le16_to_cpu(mpi_reply->TaskTag),
- le32_to_cpu(mpi_reply->TransferCount), scmd->result);
- pr_warn(MPT3SAS_FMT
- "\tscsi_status(%s)(0x%02x), scsi_state(%s)(0x%02x)\n",
- ioc->name, desc_scsi_status,
- scsi_status, desc_scsi_state, scsi_state);
+ ioc_warn(ioc, "\thandle(0x%04x), ioc_status(%s)(0x%04x), smid(%d)\n",
+ le16_to_cpu(mpi_reply->DevHandle),
+ desc_ioc_state, ioc_status, smid);
+ ioc_warn(ioc, "\trequest_len(%d), underflow(%d), resid(%d)\n",
+ scsi_bufflen(scmd), scmd->underflow, scsi_get_resid(scmd));
+ ioc_warn(ioc, "\ttag(%d), transfer_count(%d), sc->result(0x%08x)\n",
+ le16_to_cpu(mpi_reply->TaskTag),
+ le32_to_cpu(mpi_reply->TransferCount), scmd->result);
+ ioc_warn(ioc, "\tscsi_status(%s)(0x%02x), scsi_state(%s)(0x%02x)\n",
+ desc_scsi_status, scsi_status, desc_scsi_state, scsi_state);
if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
struct sense_info data;
_scsih_normalize_sense(scmd->sense_buffer, &data);
- pr_warn(MPT3SAS_FMT
- "\t[sense_key,asc,ascq]: [0x%02x,0x%02x,0x%02x], count(%d)\n",
- ioc->name, data.skey,
- data.asc, data.ascq, le32_to_cpu(mpi_reply->SenseCount));
+ ioc_warn(ioc, "\t[sense_key,asc,ascq]: [0x%02x,0x%02x,0x%02x], count(%d)\n",
+ data.skey, data.asc, data.ascq,
+ le32_to_cpu(mpi_reply->SenseCount));
}
if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) {
response_info = le32_to_cpu(mpi_reply->ResponseInfo);
@@ -5016,17 +4959,17 @@ _scsih_turn_on_pfa_led(struct MPT3SAS_ADAPTER *ioc, u16 handle)
mpi_request.Flags = MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS;
if ((mpt3sas_base_scsi_enclosure_processor(ioc, &mpi_reply,
&mpi_request)) != 0) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", ioc->name,
- __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
goto out;
}
sas_device->pfa_led_on = 1;
if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) {
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "enclosure_processor: ioc_status (0x%04x), loginfo(0x%08x)\n",
- ioc->name, le16_to_cpu(mpi_reply.IOCStatus),
- le32_to_cpu(mpi_reply.IOCLogInfo)));
+ dewtprintk(ioc,
+ ioc_info(ioc, "enclosure_processor: ioc_status (0x%04x), loginfo(0x%08x)\n",
+ le16_to_cpu(mpi_reply.IOCStatus),
+ le32_to_cpu(mpi_reply.IOCLogInfo)));
goto out;
}
out:
@@ -5056,16 +4999,16 @@ _scsih_turn_off_pfa_led(struct MPT3SAS_ADAPTER *ioc,
mpi_request.Flags = MPI2_SEP_REQ_FLAGS_ENCLOSURE_SLOT_ADDRESS;
if ((mpt3sas_base_scsi_enclosure_processor(ioc, &mpi_reply,
&mpi_request)) != 0) {
- printk(MPT3SAS_FMT "failure at %s:%d/%s()!\n", ioc->name,
- __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
return;
}
if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) {
- dewtprintk(ioc, printk(MPT3SAS_FMT
- "enclosure_processor: ioc_status (0x%04x), loginfo(0x%08x)\n",
- ioc->name, le16_to_cpu(mpi_reply.IOCStatus),
- le32_to_cpu(mpi_reply.IOCLogInfo)));
+ dewtprintk(ioc,
+ ioc_info(ioc, "enclosure_processor: ioc_status (0x%04x), loginfo(0x%08x)\n",
+ le16_to_cpu(mpi_reply.IOCStatus),
+ le32_to_cpu(mpi_reply.IOCLogInfo)));
return;
}
}
@@ -5133,8 +5076,8 @@ _scsih_smart_predicted_fault(struct MPT3SAS_ADAPTER *ioc, u16 handle)
sizeof(Mpi2EventDataSasDeviceStatusChange_t);
event_reply = kzalloc(sz, GFP_KERNEL);
if (!event_reply) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
goto out;
}
@@ -5424,16 +5367,16 @@ _scsih_sas_host_refresh(struct MPT3SAS_ADAPTER *ioc)
u16 attached_handle;
u8 link_rate;
- dtmprintk(ioc, pr_info(MPT3SAS_FMT
- "updating handles for sas_host(0x%016llx)\n",
- ioc->name, (unsigned long long)ioc->sas_hba.sas_address));
+ dtmprintk(ioc,
+ ioc_info(ioc, "updating handles for sas_host(0x%016llx)\n",
+ (u64)ioc->sas_hba.sas_address));
sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys
* sizeof(Mpi2SasIOUnit0PhyData_t));
sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
if (!sas_iounit_pg0) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
return;
}
@@ -5483,15 +5426,15 @@ _scsih_sas_host_add(struct MPT3SAS_ADAPTER *ioc)
mpt3sas_config_get_number_hba_phys(ioc, &num_phys);
if (!num_phys) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
return;
}
ioc->sas_hba.phy = kcalloc(num_phys,
sizeof(struct _sas_phy), GFP_KERNEL);
if (!ioc->sas_hba.phy) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
goto out;
}
ioc->sas_hba.num_phys = num_phys;
@@ -5501,21 +5444,21 @@ _scsih_sas_host_add(struct MPT3SAS_ADAPTER *ioc)
sizeof(Mpi2SasIOUnit0PhyData_t));
sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
if (!sas_iounit_pg0) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
return;
}
if ((mpt3sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
sas_iounit_pg0, sz))) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
goto out;
}
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
MPI2_IOCSTATUS_MASK;
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
goto out;
}
@@ -5524,21 +5467,21 @@ _scsih_sas_host_add(struct MPT3SAS_ADAPTER *ioc)
sizeof(Mpi2SasIOUnit1PhyData_t));
sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
if (!sas_iounit_pg1) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
goto out;
}
if ((mpt3sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
sas_iounit_pg1, sz))) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
goto out;
}
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
MPI2_IOCSTATUS_MASK;
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
goto out;
}
@@ -5557,15 +5500,15 @@ _scsih_sas_host_add(struct MPT3SAS_ADAPTER *ioc)
for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
if ((mpt3sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0,
i))) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
goto out;
}
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
MPI2_IOCSTATUS_MASK;
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
goto out;
}
@@ -5579,18 +5522,17 @@ _scsih_sas_host_add(struct MPT3SAS_ADAPTER *ioc)
}
if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, ioc->sas_hba.handle))) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
goto out;
}
ioc->sas_hba.enclosure_handle =
le16_to_cpu(sas_device_pg0.EnclosureHandle);
ioc->sas_hba.sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
- pr_info(MPT3SAS_FMT
- "host_add: handle(0x%04x), sas_addr(0x%016llx), phys(%d)\n",
- ioc->name, ioc->sas_hba.handle,
- (unsigned long long) ioc->sas_hba.sas_address,
- ioc->sas_hba.num_phys) ;
+ ioc_info(ioc, "host_add: handle(0x%04x), sas_addr(0x%016llx), phys(%d)\n",
+ ioc->sas_hba.handle,
+ (u64)ioc->sas_hba.sas_address,
+ ioc->sas_hba.num_phys);
if (ioc->sas_hba.enclosure_handle) {
if (!(mpt3sas_config_get_enclosure_pg0(ioc, &mpi_reply,
@@ -5639,16 +5581,16 @@ _scsih_expander_add(struct MPT3SAS_ADAPTER *ioc, u16 handle)
if ((mpt3sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
MPI2_SAS_EXPAND_PGAD_FORM_HNDL, handle))) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
return -1;
}
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
MPI2_IOCSTATUS_MASK;
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
return -1;
}
@@ -5656,8 +5598,8 @@ _scsih_expander_add(struct MPT3SAS_ADAPTER *ioc, u16 handle)
parent_handle = le16_to_cpu(expander_pg0.ParentDevHandle);
if (_scsih_get_sas_address(ioc, parent_handle, &sas_address_parent)
!= 0) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
return -1;
}
if (sas_address_parent != ioc->sas_hba.sas_address) {
@@ -5684,8 +5626,8 @@ _scsih_expander_add(struct MPT3SAS_ADAPTER *ioc, u16 handle)
sas_expander = kzalloc(sizeof(struct _sas_node),
GFP_KERNEL);
if (!sas_expander) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
return -1;
}
@@ -5694,18 +5636,17 @@ _scsih_expander_add(struct MPT3SAS_ADAPTER *ioc, u16 handle)
sas_expander->sas_address_parent = sas_address_parent;
sas_expander->sas_address = sas_address;
- pr_info(MPT3SAS_FMT "expander_add: handle(0x%04x)," \
- " parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n", ioc->name,
- handle, parent_handle, (unsigned long long)
- sas_expander->sas_address, sas_expander->num_phys);
+ ioc_info(ioc, "expander_add: handle(0x%04x), parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n",
+ handle, parent_handle,
+ (u64)sas_expander->sas_address, sas_expander->num_phys);
if (!sas_expander->num_phys)
goto out_fail;
sas_expander->phy = kcalloc(sas_expander->num_phys,
sizeof(struct _sas_phy), GFP_KERNEL);
if (!sas_expander->phy) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
rc = -1;
goto out_fail;
}
@@ -5714,8 +5655,8 @@ _scsih_expander_add(struct MPT3SAS_ADAPTER *ioc, u16 handle)
mpt3sas_port = mpt3sas_transport_port_add(ioc, handle,
sas_address_parent);
if (!mpt3sas_port) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
rc = -1;
goto out_fail;
}
@@ -5724,8 +5665,8 @@ _scsih_expander_add(struct MPT3SAS_ADAPTER *ioc, u16 handle)
for (i = 0 ; i < sas_expander->num_phys ; i++) {
if ((mpt3sas_config_get_expander_pg1(ioc, &mpi_reply,
&expander_pg1, i, handle))) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
rc = -1;
goto out_fail;
}
@@ -5735,8 +5676,8 @@ _scsih_expander_add(struct MPT3SAS_ADAPTER *ioc, u16 handle)
if ((mpt3sas_transport_add_expander_phy(ioc,
&sas_expander->phy[i], expander_pg1,
sas_expander->parent_dev))) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
rc = -1;
goto out_fail;
}
@@ -5883,9 +5824,8 @@ _scsih_check_access_status(struct MPT3SAS_ADAPTER *ioc, u64 sas_address,
if (!rc)
return 0;
- pr_err(MPT3SAS_FMT
- "discovery errors(%s): sas_address(0x%016llx), handle(0x%04x)\n",
- ioc->name, desc, (unsigned long long)sas_address, handle);
+ ioc_err(ioc, "discovery errors(%s): sas_address(0x%016llx), handle(0x%04x)\n",
+ desc, (u64)sas_address, handle);
return rc;
}
@@ -5979,9 +5919,8 @@ _scsih_check_device(struct MPT3SAS_ADAPTER *ioc,
/* check if device is present */
if (!(le16_to_cpu(sas_device_pg0.Flags) &
MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) {
- pr_err(MPT3SAS_FMT
- "device is not present handle(0x%04x), flags!!!\n",
- ioc->name, handle);
+ ioc_err(ioc, "device is not present handle(0x%04x), flags!!!\n",
+ handle);
goto out_unlock;
}
@@ -6028,16 +5967,16 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num,
if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
return -1;
}
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
MPI2_IOCSTATUS_MASK;
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
return -1;
}
@@ -6051,8 +5990,8 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num,
/* check if device is present */
if (!(le16_to_cpu(sas_device_pg0.Flags) &
MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) {
- pr_err(MPT3SAS_FMT "device is not present handle(0x04%x)!!!\n",
- ioc->name, handle);
+ ioc_err(ioc, "device is not present handle(0x04%x)!!!\n",
+ handle);
return -1;
}
@@ -6074,16 +6013,15 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num,
mpt3sas_scsih_enclosure_find_by_handle(ioc,
le16_to_cpu(sas_device_pg0.EnclosureHandle));
if (enclosure_dev == NULL)
- pr_info(MPT3SAS_FMT "Enclosure handle(0x%04x)"
- "doesn't match with enclosure device!\n",
- ioc->name, sas_device_pg0.EnclosureHandle);
+ ioc_info(ioc, "Enclosure handle(0x%04x) doesn't match with enclosure device!\n",
+ sas_device_pg0.EnclosureHandle);
}
sas_device = kzalloc(sizeof(struct _sas_device),
GFP_KERNEL);
if (!sas_device) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
return 0;
}
@@ -6092,8 +6030,8 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num,
if (_scsih_get_sas_address(ioc,
le16_to_cpu(sas_device_pg0.ParentDevHandle),
&sas_device->sas_address_parent) != 0)
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
sas_device->enclosure_handle =
le16_to_cpu(sas_device_pg0.EnclosureHandle);
if (sas_device->enclosure_handle != 0)
@@ -6158,11 +6096,10 @@ _scsih_remove_device(struct MPT3SAS_ADAPTER *ioc,
sas_device->pfa_led_on = 0;
}
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: enter: handle(0x%04x), sas_addr(0x%016llx)\n",
- ioc->name, __func__,
- sas_device->handle, (unsigned long long)
- sas_device->sas_address));
+ dewtprintk(ioc,
+ ioc_info(ioc, "%s: enter: handle(0x%04x), sas_addr(0x%016llx)\n",
+ __func__,
+ sas_device->handle, (u64)sas_device->sas_address));
dewtprintk(ioc, _scsih_display_enclosure_chassis_info(ioc, sas_device,
NULL, NULL));
@@ -6180,18 +6117,15 @@ _scsih_remove_device(struct MPT3SAS_ADAPTER *ioc,
sas_device->sas_address,
sas_device->sas_address_parent);
- pr_info(MPT3SAS_FMT
- "removing handle(0x%04x), sas_addr(0x%016llx)\n",
- ioc->name, sas_device->handle,
- (unsigned long long) sas_device->sas_address);
+ ioc_info(ioc, "removing handle(0x%04x), sas_addr(0x%016llx)\n",
+ sas_device->handle, (u64)sas_device->sas_address);
_scsih_display_enclosure_chassis_info(ioc, sas_device, NULL, NULL);
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: exit: handle(0x%04x), sas_addr(0x%016llx)\n",
- ioc->name, __func__,
- sas_device->handle, (unsigned long long)
- sas_device->sas_address));
+ dewtprintk(ioc,
+ ioc_info(ioc, "%s: exit: handle(0x%04x), sas_addr(0x%016llx)\n",
+ __func__,
+ sas_device->handle, (u64)sas_device->sas_address));
dewtprintk(ioc, _scsih_display_enclosure_chassis_info(ioc, sas_device,
NULL, NULL));
}
@@ -6231,8 +6165,7 @@ _scsih_sas_topology_change_event_debug(struct MPT3SAS_ADAPTER *ioc,
status_str = "unknown status";
break;
}
- pr_info(MPT3SAS_FMT "sas topology change: (%s)\n",
- ioc->name, status_str);
+ ioc_info(ioc, "sas topology change: (%s)\n", status_str);
pr_info("\thandle(0x%04x), enclosure_handle(0x%04x) " \
"start_phy(%02d), count(%d)\n",
le16_to_cpu(event_data->ExpanderDevHandle),
@@ -6309,8 +6242,7 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc,
_scsih_sas_host_refresh(ioc);
if (fw_event->ignore) {
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "ignoring expander event\n", ioc->name));
+ dewtprintk(ioc, ioc_info(ioc, "ignoring expander event\n"));
return 0;
}
@@ -6339,8 +6271,8 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc,
/* handle siblings events */
for (i = 0; i < event_data->NumEntries; i++) {
if (fw_event->ignore) {
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "ignoring expander event\n", ioc->name));
+ dewtprintk(ioc,
+ ioc_info(ioc, "ignoring expander event\n"));
return 0;
}
if (ioc->remove_host || ioc->pci_error_recovery)
@@ -6464,15 +6396,14 @@ _scsih_sas_device_status_change_event_debug(struct MPT3SAS_ADAPTER *ioc,
reason_str = "unknown reason";
break;
}
- pr_info(MPT3SAS_FMT "device status change: (%s)\n"
- "\thandle(0x%04x), sas address(0x%016llx), tag(%d)",
- ioc->name, reason_str, le16_to_cpu(event_data->DevHandle),
- (unsigned long long)le64_to_cpu(event_data->SASAddress),
- le16_to_cpu(event_data->TaskTag));
+ ioc_info(ioc, "device status change: (%s)\thandle(0x%04x), sas address(0x%016llx), tag(%d)",
+ reason_str, le16_to_cpu(event_data->DevHandle),
+ (u64)le64_to_cpu(event_data->SASAddress),
+ le16_to_cpu(event_data->TaskTag));
if (event_data->ReasonCode == MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA)
- pr_info(MPT3SAS_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name,
- event_data->ASC, event_data->ASCQ);
- pr_info("\n");
+ pr_cont(", ASC(0x%x), ASCQ(0x%x)\n",
+ event_data->ASC, event_data->ASCQ);
+ pr_cont("\n");
}
/**
@@ -6605,20 +6536,16 @@ _scsih_check_pcie_access_status(struct MPT3SAS_ADAPTER *ioc, u64 wwid,
desc = "nvme failure status";
break;
default:
- pr_err(MPT3SAS_FMT
- " NVMe discovery error(0x%02x): wwid(0x%016llx),"
- "handle(0x%04x)\n", ioc->name, access_status,
- (unsigned long long)wwid, handle);
+ ioc_err(ioc, "NVMe discovery error(0x%02x): wwid(0x%016llx), handle(0x%04x)\n",
+ access_status, (u64)wwid, handle);
return rc;
}
if (!rc)
return rc;
- pr_info(MPT3SAS_FMT
- "NVMe discovery error(%s): wwid(0x%016llx), handle(0x%04x)\n",
- ioc->name, desc,
- (unsigned long long)wwid, handle);
+ ioc_info(ioc, "NVMe discovery error(%s): wwid(0x%016llx), handle(0x%04x)\n",
+ desc, (u64)wwid, handle);
return rc;
}
@@ -6634,22 +6561,22 @@ _scsih_pcie_device_remove_from_sml(struct MPT3SAS_ADAPTER *ioc,
{
struct MPT3SAS_TARGET *sas_target_priv_data;
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: enter: handle(0x%04x), wwid(0x%016llx)\n", ioc->name, __func__,
- pcie_device->handle, (unsigned long long)
- pcie_device->wwid));
+ dewtprintk(ioc,
+ ioc_info(ioc, "%s: enter: handle(0x%04x), wwid(0x%016llx)\n",
+ __func__,
+ pcie_device->handle, (u64)pcie_device->wwid));
if (pcie_device->enclosure_handle != 0)
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: enter: enclosure logical id(0x%016llx), slot(%d)\n",
- ioc->name, __func__,
- (unsigned long long)pcie_device->enclosure_logical_id,
- pcie_device->slot));
+ dewtprintk(ioc,
+ ioc_info(ioc, "%s: enter: enclosure logical id(0x%016llx), slot(%d)\n",
+ __func__,
+ (u64)pcie_device->enclosure_logical_id,
+ pcie_device->slot));
if (pcie_device->connector_name[0] != '\0')
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: enter: enclosure level(0x%04x), connector name( %s)\n",
- ioc->name, __func__,
- pcie_device->enclosure_level,
- pcie_device->connector_name));
+ dewtprintk(ioc,
+ ioc_info(ioc, "%s: enter: enclosure level(0x%04x), connector name(%s)\n",
+ __func__,
+ pcie_device->enclosure_level,
+ pcie_device->connector_name));
if (pcie_device->starget && pcie_device->starget->hostdata) {
sas_target_priv_data = pcie_device->starget->hostdata;
@@ -6658,39 +6585,35 @@ _scsih_pcie_device_remove_from_sml(struct MPT3SAS_ADAPTER *ioc,
sas_target_priv_data->handle = MPT3SAS_INVALID_DEVICE_HANDLE;
}
- pr_info(MPT3SAS_FMT
- "removing handle(0x%04x), wwid (0x%016llx)\n",
- ioc->name, pcie_device->handle,
- (unsigned long long) pcie_device->wwid);
+ ioc_info(ioc, "removing handle(0x%04x), wwid(0x%016llx)\n",
+ pcie_device->handle, (u64)pcie_device->wwid);
if (pcie_device->enclosure_handle != 0)
- pr_info(MPT3SAS_FMT
- "removing : enclosure logical id(0x%016llx), slot(%d)\n",
- ioc->name,
- (unsigned long long)pcie_device->enclosure_logical_id,
- pcie_device->slot);
+ ioc_info(ioc, "removing : enclosure logical id(0x%016llx), slot(%d)\n",
+ (u64)pcie_device->enclosure_logical_id,
+ pcie_device->slot);
if (pcie_device->connector_name[0] != '\0')
- pr_info(MPT3SAS_FMT
- "removing: enclosure level(0x%04x), connector name( %s)\n",
- ioc->name, pcie_device->enclosure_level,
- pcie_device->connector_name);
+ ioc_info(ioc, "removing: enclosure level(0x%04x), connector name( %s)\n",
+ pcie_device->enclosure_level,
+ pcie_device->connector_name);
if (pcie_device->starget)
scsi_remove_target(&pcie_device->starget->dev);
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: exit: handle(0x%04x), wwid(0x%016llx)\n", ioc->name, __func__,
- pcie_device->handle, (unsigned long long)
- pcie_device->wwid));
+ dewtprintk(ioc,
+ ioc_info(ioc, "%s: exit: handle(0x%04x), wwid(0x%016llx)\n",
+ __func__,
+ pcie_device->handle, (u64)pcie_device->wwid));
if (pcie_device->enclosure_handle != 0)
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: exit: enclosure logical id(0x%016llx), slot(%d)\n",
- ioc->name, __func__,
- (unsigned long long)pcie_device->enclosure_logical_id,
- pcie_device->slot));
+ dewtprintk(ioc,
+ ioc_info(ioc, "%s: exit: enclosure logical id(0x%016llx), slot(%d)\n",
+ __func__,
+ (u64)pcie_device->enclosure_logical_id,
+ pcie_device->slot));
if (pcie_device->connector_name[0] != '\0')
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: exit: enclosure level(0x%04x), connector name( %s)\n",
- ioc->name, __func__, pcie_device->enclosure_level,
- pcie_device->connector_name));
+ dewtprintk(ioc,
+ ioc_info(ioc, "%s: exit: enclosure level(0x%04x), connector name( %s)\n",
+ __func__,
+ pcie_device->enclosure_level,
+ pcie_device->connector_name));
kfree(pcie_device->serial_number);
}
@@ -6760,9 +6683,8 @@ _scsih_pcie_check_device(struct MPT3SAS_ADAPTER *ioc, u16 handle)
/* check if device is present */
if (!(le32_to_cpu(pcie_device_pg0.Flags) &
MPI26_PCIEDEV0_FLAGS_DEVICE_PRESENT)) {
- pr_info(MPT3SAS_FMT
- "device is not present handle(0x%04x), flags!!!\n",
- ioc->name, handle);
+ ioc_info(ioc, "device is not present handle(0x%04x), flags!!!\n",
+ handle);
spin_unlock_irqrestore(&ioc->pcie_device_lock, flags);
pcie_device_put(pcie_device);
return;
@@ -6806,16 +6728,15 @@ _scsih_pcie_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle)
if ((mpt3sas_config_get_pcie_device_pg0(ioc, &mpi_reply,
&pcie_device_pg0, MPI26_PCIE_DEVICE_PGAD_FORM_HANDLE, handle))) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
return 0;
}
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
MPI2_IOCSTATUS_MASK;
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- pr_err(MPT3SAS_FMT
- "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
return 0;
}
@@ -6825,9 +6746,8 @@ _scsih_pcie_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle)
/* check if device is present */
if (!(le32_to_cpu(pcie_device_pg0.Flags) &
MPI26_PCIEDEV0_FLAGS_DEVICE_PRESENT)) {
- pr_err(MPT3SAS_FMT
- "device is not present handle(0x04%x)!!!\n",
- ioc->name, handle);
+ ioc_err(ioc, "device is not present handle(0x04%x)!!!\n",
+ handle);
return 0;
}
@@ -6848,8 +6768,8 @@ _scsih_pcie_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle)
pcie_device = kzalloc(sizeof(struct _pcie_device), GFP_KERNEL);
if (!pcie_device) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
return 0;
}
@@ -6890,16 +6810,16 @@ _scsih_pcie_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle)
/* TODO -- Add device name once FW supports it */
if (mpt3sas_config_get_pcie_device_pg2(ioc, &mpi_reply,
&pcie_device_pg2, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle)) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
kfree(pcie_device);
return 0;
}
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
kfree(pcie_device);
return 0;
}
@@ -6956,8 +6876,7 @@ _scsih_pcie_topology_change_event_debug(struct MPT3SAS_ADAPTER *ioc,
status_str = "unknown status";
break;
}
- pr_info(MPT3SAS_FMT "pcie topology change: (%s)\n",
- ioc->name, status_str);
+ ioc_info(ioc, "pcie topology change: (%s)\n", status_str);
pr_info("\tswitch_handle(0x%04x), enclosure_handle(0x%04x)"
"start_port(%02d), count(%d)\n",
le16_to_cpu(event_data->SwitchDevHandle),
@@ -7030,16 +6949,15 @@ _scsih_pcie_topology_change_event(struct MPT3SAS_ADAPTER *ioc,
return;
if (fw_event->ignore) {
- dewtprintk(ioc, pr_info(MPT3SAS_FMT "ignoring switch event\n",
- ioc->name));
+ dewtprintk(ioc, ioc_info(ioc, "ignoring switch event\n"));
return;
}
/* handle siblings events */
for (i = 0; i < event_data->NumEntries; i++) {
if (fw_event->ignore) {
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "ignoring switch event\n", ioc->name));
+ dewtprintk(ioc,
+ ioc_info(ioc, "ignoring switch event\n"));
return;
}
if (ioc->remove_host || ioc->pci_error_recovery)
@@ -7084,9 +7002,9 @@ _scsih_pcie_topology_change_event(struct MPT3SAS_ADAPTER *ioc,
if (!test_bit(handle, ioc->pend_os_device_add))
break;
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "handle(0x%04x) device not found: convert "
- "event to a device add\n", ioc->name, handle));
+ dewtprintk(ioc,
+ ioc_info(ioc, "handle(0x%04x) device not found: convert event to a device add\n",
+ handle));
event_data->PortEntry[i].PortStatus &= 0xF0;
event_data->PortEntry[i].PortStatus |=
MPI26_EVENT_PCIE_TOPO_PS_DEV_ADDED;
@@ -7169,15 +7087,15 @@ _scsih_pcie_device_status_change_event_debug(struct MPT3SAS_ADAPTER *ioc,
break;
}
- pr_info(MPT3SAS_FMT "PCIE device status change: (%s)\n"
- "\thandle(0x%04x), WWID(0x%016llx), tag(%d)",
- ioc->name, reason_str, le16_to_cpu(event_data->DevHandle),
- (unsigned long long)le64_to_cpu(event_data->WWID),
- le16_to_cpu(event_data->TaskTag));
+ ioc_info(ioc, "PCIE device status change: (%s)\n"
+ "\thandle(0x%04x), WWID(0x%016llx), tag(%d)",
+ reason_str, le16_to_cpu(event_data->DevHandle),
+ (u64)le64_to_cpu(event_data->WWID),
+ le16_to_cpu(event_data->TaskTag));
if (event_data->ReasonCode == MPI26_EVENT_PCIDEV_STAT_RC_SMART_DATA)
- pr_info(MPT3SAS_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name,
+ pr_cont(", ASC(0x%x), ASCQ(0x%x)\n",
event_data->ASC, event_data->ASCQ);
- pr_info("\n");
+ pr_cont("\n");
}
/**
@@ -7255,12 +7173,12 @@ _scsih_sas_enclosure_dev_status_change_event_debug(struct MPT3SAS_ADAPTER *ioc,
break;
}
- pr_info(MPT3SAS_FMT "enclosure status change: (%s)\n"
- "\thandle(0x%04x), enclosure logical id(0x%016llx)"
- " number slots(%d)\n", ioc->name, reason_str,
- le16_to_cpu(event_data->EnclosureHandle),
- (unsigned long long)le64_to_cpu(event_data->EnclosureLogicalID),
- le16_to_cpu(event_data->StartSlot));
+ ioc_info(ioc, "enclosure status change: (%s)\n"
+ "\thandle(0x%04x), enclosure logical id(0x%016llx) number slots(%d)\n",
+ reason_str,
+ le16_to_cpu(event_data->EnclosureHandle),
+ (u64)le64_to_cpu(event_data->EnclosureLogicalID),
+ le16_to_cpu(event_data->StartSlot));
}
/**
@@ -7298,9 +7216,8 @@ _scsih_sas_enclosure_dev_status_change_event(struct MPT3SAS_ADAPTER *ioc,
kzalloc(sizeof(struct _enclosure_node),
GFP_KERNEL);
if (!enclosure_dev) {
- pr_info(MPT3SAS_FMT
- "failure at %s:%d/%s()!\n", ioc->name,
- __FILE__, __LINE__, __func__);
+ ioc_info(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
return;
}
rc = mpt3sas_config_get_enclosure_pg0(ioc, &mpi_reply,
@@ -7358,10 +7275,8 @@ _scsih_sas_broadcast_primitive_event(struct MPT3SAS_ADAPTER *ioc,
u8 task_abort_retries;
mutex_lock(&ioc->tm_cmds.mutex);
- pr_info(MPT3SAS_FMT
- "%s: enter: phy number(%d), width(%d)\n",
- ioc->name, __func__, event_data->PhyNum,
- event_data->PortWidth);
+ ioc_info(ioc, "%s: enter: phy number(%d), width(%d)\n",
+ __func__, event_data->PhyNum, event_data->PortWidth);
_scsih_block_io_all_device(ioc);
@@ -7371,12 +7286,12 @@ _scsih_sas_broadcast_primitive_event(struct MPT3SAS_ADAPTER *ioc,
/* sanity checks for retrying this loop */
if (max_retries++ == 5) {
- dewtprintk(ioc, pr_info(MPT3SAS_FMT "%s: giving up\n",
- ioc->name, __func__));
+ dewtprintk(ioc, ioc_info(ioc, "%s: giving up\n", __func__));
goto out;
} else if (max_retries > 1)
- dewtprintk(ioc, pr_info(MPT3SAS_FMT "%s: %d retry\n",
- ioc->name, __func__, max_retries - 1));
+ dewtprintk(ioc,
+ ioc_info(ioc, "%s: %d retry\n",
+ __func__, max_retries - 1));
termination_count = 0;
query_count = 0;
@@ -7443,9 +7358,9 @@ _scsih_sas_broadcast_primitive_event(struct MPT3SAS_ADAPTER *ioc,
task_abort_retries = 0;
tm_retry:
if (task_abort_retries++ == 60) {
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: ABORT_TASK: giving up\n", ioc->name,
- __func__));
+ dewtprintk(ioc,
+ ioc_info(ioc, "%s: ABORT_TASK: giving up\n",
+ __func__));
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
goto broadcast_aen_retry;
}
@@ -7474,9 +7389,10 @@ _scsih_sas_broadcast_primitive_event(struct MPT3SAS_ADAPTER *ioc,
}
if (ioc->broadcast_aen_pending) {
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: loop back due to pending AEN\n",
- ioc->name, __func__));
+ dewtprintk(ioc,
+ ioc_info(ioc,
+ "%s: loop back due to pending AEN\n",
+ __func__));
ioc->broadcast_aen_pending = 0;
goto broadcast_aen_retry;
}
@@ -7485,9 +7401,9 @@ _scsih_sas_broadcast_primitive_event(struct MPT3SAS_ADAPTER *ioc,
spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
out_no_lock:
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "%s - exit, query_count = %d termination_count = %d\n",
- ioc->name, __func__, query_count, termination_count));
+ dewtprintk(ioc,
+ ioc_info(ioc, "%s - exit, query_count = %d termination_count = %d\n",
+ __func__, query_count, termination_count));
ioc->broadcast_aen_busy = 0;
if (!ioc->shost_recovery)
@@ -7509,13 +7425,13 @@ _scsih_sas_discovery_event(struct MPT3SAS_ADAPTER *ioc,
(Mpi2EventDataSasDiscovery_t *) fw_event->event_data;
if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) {
- pr_info(MPT3SAS_FMT "discovery event: (%s)", ioc->name,
- (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ?
- "start" : "stop");
+ ioc_info(ioc, "discovery event: (%s)",
+ event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED ?
+ "start" : "stop");
if (event_data->DiscoveryStatus)
- pr_info("discovery_status(0x%08x)",
- le32_to_cpu(event_data->DiscoveryStatus));
- pr_info("\n");
+ pr_cont("discovery_status(0x%08x)",
+ le32_to_cpu(event_data->DiscoveryStatus));
+ pr_cont("\n");
}
if (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED &&
@@ -7545,20 +7461,16 @@ _scsih_sas_device_discovery_error_event(struct MPT3SAS_ADAPTER *ioc,
switch (event_data->ReasonCode) {
case MPI25_EVENT_SAS_DISC_ERR_SMP_FAILED:
- pr_warn(MPT3SAS_FMT "SMP command sent to the expander"
- "(handle:0x%04x, sas_address:0x%016llx,"
- "physical_port:0x%02x) has failed",
- ioc->name, le16_to_cpu(event_data->DevHandle),
- (unsigned long long)le64_to_cpu(event_data->SASAddress),
- event_data->PhysicalPort);
+ ioc_warn(ioc, "SMP command sent to the expander (handle:0x%04x, sas_address:0x%016llx, physical_port:0x%02x) has failed\n",
+ le16_to_cpu(event_data->DevHandle),
+ (u64)le64_to_cpu(event_data->SASAddress),
+ event_data->PhysicalPort);
break;
case MPI25_EVENT_SAS_DISC_ERR_SMP_TIMEOUT:
- pr_warn(MPT3SAS_FMT "SMP command sent to the expander"
- "(handle:0x%04x, sas_address:0x%016llx,"
- "physical_port:0x%02x) has timed out",
- ioc->name, le16_to_cpu(event_data->DevHandle),
- (unsigned long long)le64_to_cpu(event_data->SASAddress),
- event_data->PhysicalPort);
+ ioc_warn(ioc, "SMP command sent to the expander (handle:0x%04x, sas_address:0x%016llx, physical_port:0x%02x) has timed out\n",
+ le16_to_cpu(event_data->DevHandle),
+ (u64)le64_to_cpu(event_data->SASAddress),
+ event_data->PhysicalPort);
break;
default:
break;
@@ -7581,11 +7493,10 @@ _scsih_pcie_enumeration_event(struct MPT3SAS_ADAPTER *ioc,
if (!(ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK))
return;
- pr_info(MPT3SAS_FMT "pcie enumeration event: (%s) Flag 0x%02x",
- ioc->name,
- (event_data->ReasonCode == MPI26_EVENT_PCIE_ENUM_RC_STARTED) ?
- "started" : "completed",
- event_data->Flags);
+ ioc_info(ioc, "pcie enumeration event: (%s) Flag 0x%02x",
+ (event_data->ReasonCode == MPI26_EVENT_PCIE_ENUM_RC_STARTED) ?
+ "started" : "completed",
+ event_data->Flags);
if (event_data->EnumerationStatus)
pr_cont("enumeration_status(0x%08x)",
le32_to_cpu(event_data->EnumerationStatus));
@@ -7617,8 +7528,7 @@ _scsih_ir_fastpath(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phys_disk_num)
mutex_lock(&ioc->scsih_cmds.mutex);
if (ioc->scsih_cmds.status != MPT3_CMD_NOT_USED) {
- pr_err(MPT3SAS_FMT "%s: scsih_cmd in use\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: scsih_cmd in use\n", __func__);
rc = -EAGAIN;
goto out;
}
@@ -7626,8 +7536,7 @@ _scsih_ir_fastpath(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phys_disk_num)
smid = mpt3sas_base_get_smid(ioc, ioc->scsih_cb_idx);
if (!smid) {
- pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);
ioc->scsih_cmds.status = MPT3_CMD_NOT_USED;
rc = -EAGAIN;
goto out;
@@ -7641,9 +7550,9 @@ _scsih_ir_fastpath(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phys_disk_num)
mpi_request->Action = MPI2_RAID_ACTION_PHYSDISK_HIDDEN;
mpi_request->PhysDiskNum = phys_disk_num;
- dewtprintk(ioc, pr_info(MPT3SAS_FMT "IR RAID_ACTION: turning fast "\
- "path on for handle(0x%04x), phys_disk_num (0x%02x)\n", ioc->name,
- handle, phys_disk_num));
+ dewtprintk(ioc,
+ ioc_info(ioc, "IR RAID_ACTION: turning fast path on for handle(0x%04x), phys_disk_num (0x%02x)\n",
+ handle, phys_disk_num));
init_completion(&ioc->scsih_cmds.done);
mpt3sas_base_put_smid_default(ioc, smid);
@@ -7668,15 +7577,13 @@ _scsih_ir_fastpath(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phys_disk_num)
log_info = 0;
ioc_status &= MPI2_IOCSTATUS_MASK;
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "IR RAID_ACTION: failed: ioc_status(0x%04x), "
- "loginfo(0x%08x)!!!\n", ioc->name, ioc_status,
- log_info));
+ dewtprintk(ioc,
+ ioc_info(ioc, "IR RAID_ACTION: failed: ioc_status(0x%04x), loginfo(0x%08x)!!!\n",
+ ioc_status, log_info));
rc = -EFAULT;
} else
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "IR RAID_ACTION: completed successfully\n",
- ioc->name));
+ dewtprintk(ioc,
+ ioc_info(ioc, "IR RAID_ACTION: completed successfully\n"));
}
out:
@@ -7721,9 +7628,8 @@ _scsih_sas_volume_add(struct MPT3SAS_ADAPTER *ioc,
mpt3sas_config_get_volume_wwid(ioc, handle, &wwid);
if (!wwid) {
- pr_err(MPT3SAS_FMT
- "failure at %s:%d/%s()!\n", ioc->name,
- __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
return;
}
@@ -7736,9 +7642,8 @@ _scsih_sas_volume_add(struct MPT3SAS_ADAPTER *ioc,
raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL);
if (!raid_device) {
- pr_err(MPT3SAS_FMT
- "failure at %s:%d/%s()!\n", ioc->name,
- __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
return;
}
@@ -7781,9 +7686,8 @@ _scsih_sas_volume_delete(struct MPT3SAS_ADAPTER *ioc, u16 handle)
sas_target_priv_data = starget->hostdata;
sas_target_priv_data->deleted = 1;
}
- pr_info(MPT3SAS_FMT "removing handle(0x%04x), wwid(0x%016llx)\n",
- ioc->name, raid_device->handle,
- (unsigned long long) raid_device->wwid);
+ ioc_info(ioc, "removing handle(0x%04x), wwid(0x%016llx)\n",
+ raid_device->handle, (u64)raid_device->wwid);
list_del(&raid_device->list);
kfree(raid_device);
}
@@ -7925,16 +7829,16 @@ _scsih_sas_pd_add(struct MPT3SAS_ADAPTER *ioc,
if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
return;
}
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
MPI2_IOCSTATUS_MASK;
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
return;
}
@@ -7964,10 +7868,10 @@ _scsih_sas_ir_config_change_event_debug(struct MPT3SAS_ADAPTER *ioc,
element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
- pr_info(MPT3SAS_FMT "raid config change: (%s), elements(%d)\n",
- ioc->name, (le32_to_cpu(event_data->Flags) &
- MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ?
- "foreign" : "native", event_data->NumElements);
+ ioc_info(ioc, "raid config change: (%s), elements(%d)\n",
+ le32_to_cpu(event_data->Flags) & MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG ?
+ "foreign" : "native",
+ event_data->NumElements);
for (i = 0; i < event_data->NumElements; i++, element++) {
switch (element->ReasonCode) {
case MPI2_EVENT_IR_CHANGE_RC_ADDED:
@@ -8123,10 +8027,11 @@ _scsih_sas_ir_volume_event(struct MPT3SAS_ADAPTER *ioc,
handle = le16_to_cpu(event_data->VolDevHandle);
state = le32_to_cpu(event_data->NewValue);
if (!ioc->hide_ir_msg)
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: handle(0x%04x), old(0x%08x), new(0x%08x)\n",
- ioc->name, __func__, handle,
- le32_to_cpu(event_data->PreviousValue), state));
+ dewtprintk(ioc,
+ ioc_info(ioc, "%s: handle(0x%04x), old(0x%08x), new(0x%08x)\n",
+ __func__, handle,
+ le32_to_cpu(event_data->PreviousValue),
+ state));
switch (state) {
case MPI2_RAID_VOL_STATE_MISSING:
case MPI2_RAID_VOL_STATE_FAILED:
@@ -8146,17 +8051,15 @@ _scsih_sas_ir_volume_event(struct MPT3SAS_ADAPTER *ioc,
mpt3sas_config_get_volume_wwid(ioc, handle, &wwid);
if (!wwid) {
- pr_err(MPT3SAS_FMT
- "failure at %s:%d/%s()!\n", ioc->name,
- __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
break;
}
raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL);
if (!raid_device) {
- pr_err(MPT3SAS_FMT
- "failure at %s:%d/%s()!\n", ioc->name,
- __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
break;
}
@@ -8207,10 +8110,11 @@ _scsih_sas_ir_physical_disk_event(struct MPT3SAS_ADAPTER *ioc,
state = le32_to_cpu(event_data->NewValue);
if (!ioc->hide_ir_msg)
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: handle(0x%04x), old(0x%08x), new(0x%08x)\n",
- ioc->name, __func__, handle,
- le32_to_cpu(event_data->PreviousValue), state));
+ dewtprintk(ioc,
+ ioc_info(ioc, "%s: handle(0x%04x), old(0x%08x), new(0x%08x)\n",
+ __func__, handle,
+ le32_to_cpu(event_data->PreviousValue),
+ state));
switch (state) {
case MPI2_RAID_PD_STATE_ONLINE:
@@ -8231,16 +8135,16 @@ _scsih_sas_ir_physical_disk_event(struct MPT3SAS_ADAPTER *ioc,
if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply,
&sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
handle))) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
return;
}
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
MPI2_IOCSTATUS_MASK;
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
return;
}
@@ -8294,11 +8198,10 @@ _scsih_sas_ir_operation_status_event_debug(struct MPT3SAS_ADAPTER *ioc,
if (!reason_str)
return;
- pr_info(MPT3SAS_FMT "raid operational status: (%s)" \
- "\thandle(0x%04x), percent complete(%d)\n",
- ioc->name, reason_str,
- le16_to_cpu(event_data->VolDevHandle),
- event_data->PercentComplete);
+ ioc_info(ioc, "raid operational status: (%s)\thandle(0x%04x), percent complete(%d)\n",
+ reason_str,
+ le16_to_cpu(event_data->VolDevHandle),
+ event_data->PercentComplete);
}
/**
@@ -8379,9 +8282,8 @@ Mpi2SasDevicePage0_t *sas_device_pg0)
mpt3sas_scsih_enclosure_find_by_handle(ioc,
le16_to_cpu(sas_device_pg0->EnclosureHandle));
if (enclosure_dev == NULL)
- pr_info(MPT3SAS_FMT "Enclosure handle(0x%04x)"
- "doesn't match with enclosure device!\n",
- ioc->name, sas_device_pg0->EnclosureHandle);
+ ioc_info(ioc, "Enclosure handle(0x%04x) doesn't match with enclosure device!\n",
+ sas_device_pg0->EnclosureHandle);
}
spin_lock_irqsave(&ioc->sas_device_lock, flags);
list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
@@ -8475,8 +8377,7 @@ _scsih_create_enclosure_list_after_reset(struct MPT3SAS_ADAPTER *ioc)
enclosure_dev =
kzalloc(sizeof(struct _enclosure_node), GFP_KERNEL);
if (!enclosure_dev) {
- pr_err(MPT3SAS_FMT
- "failure at %s:%d/%s()!\n", ioc->name,
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
return;
}
@@ -8513,7 +8414,7 @@ _scsih_search_responding_sas_devices(struct MPT3SAS_ADAPTER *ioc)
u16 handle;
u32 device_info;
- pr_info(MPT3SAS_FMT "search for end-devices: start\n", ioc->name);
+ ioc_info(ioc, "search for end-devices: start\n");
if (list_empty(&ioc->sas_device_list))
goto out;
@@ -8534,8 +8435,7 @@ _scsih_search_responding_sas_devices(struct MPT3SAS_ADAPTER *ioc)
}
out:
- pr_info(MPT3SAS_FMT "search for end-devices: complete\n",
- ioc->name);
+ ioc_info(ioc, "search for end-devices: complete\n");
}
/**
@@ -8628,7 +8528,7 @@ _scsih_search_responding_pcie_devices(struct MPT3SAS_ADAPTER *ioc)
u16 handle;
u32 device_info;
- pr_info(MPT3SAS_FMT "search for end-devices: start\n", ioc->name);
+ ioc_info(ioc, "search for end-devices: start\n");
if (list_empty(&ioc->pcie_device_list))
goto out;
@@ -8640,10 +8540,9 @@ _scsih_search_responding_pcie_devices(struct MPT3SAS_ADAPTER *ioc)
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
MPI2_IOCSTATUS_MASK;
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- pr_info(MPT3SAS_FMT "\tbreak from %s: "
- "ioc_status(0x%04x), loginfo(0x%08x)\n", ioc->name,
- __func__, ioc_status,
- le32_to_cpu(mpi_reply.IOCLogInfo));
+ ioc_info(ioc, "\tbreak from %s: ioc_status(0x%04x), loginfo(0x%08x)\n",
+ __func__, ioc_status,
+ le32_to_cpu(mpi_reply.IOCLogInfo));
break;
}
handle = le16_to_cpu(pcie_device_pg0.DevHandle);
@@ -8653,8 +8552,7 @@ _scsih_search_responding_pcie_devices(struct MPT3SAS_ADAPTER *ioc)
_scsih_mark_responding_pcie_device(ioc, &pcie_device_pg0);
}
out:
- pr_info(MPT3SAS_FMT "search for PCIe end-devices: complete\n",
- ioc->name);
+ ioc_info(ioc, "search for PCIe end-devices: complete\n");
}
/**
@@ -8735,8 +8633,7 @@ _scsih_search_responding_raid_devices(struct MPT3SAS_ADAPTER *ioc)
if (!ioc->ir_firmware)
return;
- pr_info(MPT3SAS_FMT "search for raid volumes: start\n",
- ioc->name);
+ ioc_info(ioc, "search for raid volumes: start\n");
if (list_empty(&ioc->raid_device_list))
goto out;
@@ -8779,8 +8676,7 @@ _scsih_search_responding_raid_devices(struct MPT3SAS_ADAPTER *ioc)
}
}
out:
- pr_info(MPT3SAS_FMT "search for responding raid volumes: complete\n",
- ioc->name);
+ ioc_info(ioc, "search for responding raid volumes: complete\n");
}
/**
@@ -8852,7 +8748,7 @@ _scsih_search_responding_expanders(struct MPT3SAS_ADAPTER *ioc)
u64 sas_address;
u16 handle;
- pr_info(MPT3SAS_FMT "search for expanders: start\n", ioc->name);
+ ioc_info(ioc, "search for expanders: start\n");
if (list_empty(&ioc->sas_expander_list))
goto out;
@@ -8875,7 +8771,7 @@ _scsih_search_responding_expanders(struct MPT3SAS_ADAPTER *ioc)
}
out:
- pr_info(MPT3SAS_FMT "search for expanders: complete\n", ioc->name);
+ ioc_info(ioc, "search for expanders: complete\n");
}
/**
@@ -8893,12 +8789,10 @@ _scsih_remove_unresponding_devices(struct MPT3SAS_ADAPTER *ioc)
unsigned long flags;
LIST_HEAD(head);
- pr_info(MPT3SAS_FMT "removing unresponding devices: start\n",
- ioc->name);
+ ioc_info(ioc, "removing unresponding devices: start\n");
/* removing unresponding end devices */
- pr_info(MPT3SAS_FMT "removing unresponding devices: end-devices\n",
- ioc->name);
+ ioc_info(ioc, "removing unresponding devices: end-devices\n");
/*
* Iterate, pulling off devices marked as non-responding. We become the
* owner for the reference the list had on any object we prune.
@@ -8922,9 +8816,7 @@ _scsih_remove_unresponding_devices(struct MPT3SAS_ADAPTER *ioc)
sas_device_put(sas_device);
}
- pr_info(MPT3SAS_FMT
- " Removing unresponding devices: pcie end-devices\n"
- , ioc->name);
+ ioc_info(ioc, "Removing unresponding devices: pcie end-devices\n");
INIT_LIST_HEAD(&head);
spin_lock_irqsave(&ioc->pcie_device_lock, flags);
list_for_each_entry_safe(pcie_device, pcie_device_next,
@@ -8944,8 +8836,7 @@ _scsih_remove_unresponding_devices(struct MPT3SAS_ADAPTER *ioc)
/* removing unresponding volumes */
if (ioc->ir_firmware) {
- pr_info(MPT3SAS_FMT "removing unresponding devices: volumes\n",
- ioc->name);
+ ioc_info(ioc, "removing unresponding devices: volumes\n");
list_for_each_entry_safe(raid_device, raid_device_next,
&ioc->raid_device_list, list) {
if (!raid_device->responding)
@@ -8957,8 +8848,7 @@ _scsih_remove_unresponding_devices(struct MPT3SAS_ADAPTER *ioc)
}
/* removing unresponding expanders */
- pr_info(MPT3SAS_FMT "removing unresponding devices: expanders\n",
- ioc->name);
+ ioc_info(ioc, "removing unresponding devices: expanders\n");
spin_lock_irqsave(&ioc->sas_node_lock, flags);
INIT_LIST_HEAD(&tmp_list);
list_for_each_entry_safe(sas_expander, sas_expander_next,
@@ -8974,8 +8864,7 @@ _scsih_remove_unresponding_devices(struct MPT3SAS_ADAPTER *ioc)
_scsih_expander_node_remove(ioc, sas_expander);
}
- pr_info(MPT3SAS_FMT "removing unresponding devices: complete\n",
- ioc->name);
+ ioc_info(ioc, "removing unresponding devices: complete\n");
/* unblock devices */
_scsih_ublock_io_all_device(ioc);
@@ -8992,8 +8881,8 @@ _scsih_refresh_expander_links(struct MPT3SAS_ADAPTER *ioc,
for (i = 0 ; i < sas_expander->num_phys ; i++) {
if ((mpt3sas_config_get_expander_pg1(ioc, &mpi_reply,
&expander_pg1, i, handle))) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
return;
}
@@ -9029,11 +8918,11 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc)
u8 retry_count;
unsigned long flags;
- pr_info(MPT3SAS_FMT "scan devices: start\n", ioc->name);
+ ioc_info(ioc, "scan devices: start\n");
_scsih_sas_host_refresh(ioc);
- pr_info(MPT3SAS_FMT "\tscan devices: expanders start\n", ioc->name);
+ ioc_info(ioc, "\tscan devices: expanders start\n");
/* expanders */
handle = 0xFFFF;
@@ -9042,10 +8931,8 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc)
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
MPI2_IOCSTATUS_MASK;
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- pr_info(MPT3SAS_FMT "\tbreak from expander scan: " \
- "ioc_status(0x%04x), loginfo(0x%08x)\n",
- ioc->name, ioc_status,
- le32_to_cpu(mpi_reply.IOCLogInfo));
+ ioc_info(ioc, "\tbreak from expander scan: ioc_status(0x%04x), loginfo(0x%08x)\n",
+ ioc_status, le32_to_cpu(mpi_reply.IOCLogInfo));
break;
}
handle = le16_to_cpu(expander_pg0.DevHandle);
@@ -9057,25 +8944,22 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc)
_scsih_refresh_expander_links(ioc, expander_device,
handle);
else {
- pr_info(MPT3SAS_FMT "\tBEFORE adding expander: " \
- "handle (0x%04x), sas_addr(0x%016llx)\n", ioc->name,
- handle, (unsigned long long)
- le64_to_cpu(expander_pg0.SASAddress));
+ ioc_info(ioc, "\tBEFORE adding expander: handle (0x%04x), sas_addr(0x%016llx)\n",
+ handle,
+ (u64)le64_to_cpu(expander_pg0.SASAddress));
_scsih_expander_add(ioc, handle);
- pr_info(MPT3SAS_FMT "\tAFTER adding expander: " \
- "handle (0x%04x), sas_addr(0x%016llx)\n", ioc->name,
- handle, (unsigned long long)
- le64_to_cpu(expander_pg0.SASAddress));
+ ioc_info(ioc, "\tAFTER adding expander: handle (0x%04x), sas_addr(0x%016llx)\n",
+ handle,
+ (u64)le64_to_cpu(expander_pg0.SASAddress));
}
}
- pr_info(MPT3SAS_FMT "\tscan devices: expanders complete\n",
- ioc->name);
+ ioc_info(ioc, "\tscan devices: expanders complete\n");
if (!ioc->ir_firmware)
goto skip_to_sas;
- pr_info(MPT3SAS_FMT "\tscan devices: phys disk start\n", ioc->name);
+ ioc_info(ioc, "\tscan devices: phys disk start\n");
/* phys disk */
phys_disk_num = 0xFF;
@@ -9085,10 +8969,8 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc)
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
MPI2_IOCSTATUS_MASK;
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- pr_info(MPT3SAS_FMT "\tbreak from phys disk scan: "\
- "ioc_status(0x%04x), loginfo(0x%08x)\n",
- ioc->name, ioc_status,
- le32_to_cpu(mpi_reply.IOCLogInfo));
+ ioc_info(ioc, "\tbreak from phys disk scan: ioc_status(0x%04x), loginfo(0x%08x)\n",
+ ioc_status, le32_to_cpu(mpi_reply.IOCLogInfo));
break;
}
phys_disk_num = pd_pg0.PhysDiskNum;
@@ -9105,19 +8987,16 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc)
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
MPI2_IOCSTATUS_MASK;
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- pr_info(MPT3SAS_FMT "\tbreak from phys disk scan " \
- "ioc_status(0x%04x), loginfo(0x%08x)\n",
- ioc->name, ioc_status,
- le32_to_cpu(mpi_reply.IOCLogInfo));
+ ioc_info(ioc, "\tbreak from phys disk scan ioc_status(0x%04x), loginfo(0x%08x)\n",
+ ioc_status, le32_to_cpu(mpi_reply.IOCLogInfo));
break;
}
parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
if (!_scsih_get_sas_address(ioc, parent_handle,
&sas_address)) {
- pr_info(MPT3SAS_FMT "\tBEFORE adding phys disk: " \
- " handle (0x%04x), sas_addr(0x%016llx)\n",
- ioc->name, handle, (unsigned long long)
- le64_to_cpu(sas_device_pg0.SASAddress));
+ ioc_info(ioc, "\tBEFORE adding phys disk: handle (0x%04x), sas_addr(0x%016llx)\n",
+ handle,
+ (u64)le64_to_cpu(sas_device_pg0.SASAddress));
mpt3sas_transport_update_links(ioc, sas_address,
handle, sas_device_pg0.PhyNum,
MPI2_SAS_NEG_LINK_RATE_1_5);
@@ -9131,17 +9010,15 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc)
1)) {
ssleep(1);
}
- pr_info(MPT3SAS_FMT "\tAFTER adding phys disk: " \
- " handle (0x%04x), sas_addr(0x%016llx)\n",
- ioc->name, handle, (unsigned long long)
- le64_to_cpu(sas_device_pg0.SASAddress));
+ ioc_info(ioc, "\tAFTER adding phys disk: handle (0x%04x), sas_addr(0x%016llx)\n",
+ handle,
+ (u64)le64_to_cpu(sas_device_pg0.SASAddress));
}
}
- pr_info(MPT3SAS_FMT "\tscan devices: phys disk complete\n",
- ioc->name);
+ ioc_info(ioc, "\tscan devices: phys disk complete\n");
- pr_info(MPT3SAS_FMT "\tscan devices: volumes start\n", ioc->name);
+ ioc_info(ioc, "\tscan devices: volumes start\n");
/* volumes */
handle = 0xFFFF;
@@ -9150,10 +9027,8 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc)
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
MPI2_IOCSTATUS_MASK;
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- pr_info(MPT3SAS_FMT "\tbreak from volume scan: " \
- "ioc_status(0x%04x), loginfo(0x%08x)\n",
- ioc->name, ioc_status,
- le32_to_cpu(mpi_reply.IOCLogInfo));
+ ioc_info(ioc, "\tbreak from volume scan: ioc_status(0x%04x), loginfo(0x%08x)\n",
+ ioc_status, le32_to_cpu(mpi_reply.IOCLogInfo));
break;
}
handle = le16_to_cpu(volume_pg1.DevHandle);
@@ -9170,10 +9045,8 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc)
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
MPI2_IOCSTATUS_MASK;
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- pr_info(MPT3SAS_FMT "\tbreak from volume scan: " \
- "ioc_status(0x%04x), loginfo(0x%08x)\n",
- ioc->name, ioc_status,
- le32_to_cpu(mpi_reply.IOCLogInfo));
+ ioc_info(ioc, "\tbreak from volume scan: ioc_status(0x%04x), loginfo(0x%08x)\n",
+ ioc_status, le32_to_cpu(mpi_reply.IOCLogInfo));
break;
}
if (volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_OPTIMAL ||
@@ -9182,23 +9055,19 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc)
memset(&element, 0, sizeof(Mpi2EventIrConfigElement_t));
element.ReasonCode = MPI2_EVENT_IR_CHANGE_RC_ADDED;
element.VolDevHandle = volume_pg1.DevHandle;
- pr_info(MPT3SAS_FMT
- "\tBEFORE adding volume: handle (0x%04x)\n",
- ioc->name, volume_pg1.DevHandle);
+ ioc_info(ioc, "\tBEFORE adding volume: handle (0x%04x)\n",
+ volume_pg1.DevHandle);
_scsih_sas_volume_add(ioc, &element);
- pr_info(MPT3SAS_FMT
- "\tAFTER adding volume: handle (0x%04x)\n",
- ioc->name, volume_pg1.DevHandle);
+ ioc_info(ioc, "\tAFTER adding volume: handle (0x%04x)\n",
+ volume_pg1.DevHandle);
}
}
- pr_info(MPT3SAS_FMT "\tscan devices: volumes complete\n",
- ioc->name);
+ ioc_info(ioc, "\tscan devices: volumes complete\n");
skip_to_sas:
- pr_info(MPT3SAS_FMT "\tscan devices: end devices start\n",
- ioc->name);
+ ioc_info(ioc, "\tscan devices: end devices start\n");
/* sas devices */
handle = 0xFFFF;
@@ -9208,10 +9077,8 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc)
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
MPI2_IOCSTATUS_MASK;
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- pr_info(MPT3SAS_FMT "\tbreak from end device scan:"\
- " ioc_status(0x%04x), loginfo(0x%08x)\n",
- ioc->name, ioc_status,
- le32_to_cpu(mpi_reply.IOCLogInfo));
+ ioc_info(ioc, "\tbreak from end device scan: ioc_status(0x%04x), loginfo(0x%08x)\n",
+ ioc_status, le32_to_cpu(mpi_reply.IOCLogInfo));
break;
}
handle = le16_to_cpu(sas_device_pg0.DevHandle);
@@ -9226,10 +9093,9 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc)
}
parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) {
- pr_info(MPT3SAS_FMT "\tBEFORE adding end device: " \
- "handle (0x%04x), sas_addr(0x%016llx)\n", ioc->name,
- handle, (unsigned long long)
- le64_to_cpu(sas_device_pg0.SASAddress));
+ ioc_info(ioc, "\tBEFORE adding end device: handle (0x%04x), sas_addr(0x%016llx)\n",
+ handle,
+ (u64)le64_to_cpu(sas_device_pg0.SASAddress));
mpt3sas_transport_update_links(ioc, sas_address, handle,
sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
retry_count = 0;
@@ -9241,16 +9107,13 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc)
0)) {
ssleep(1);
}
- pr_info(MPT3SAS_FMT "\tAFTER adding end device: " \
- "handle (0x%04x), sas_addr(0x%016llx)\n", ioc->name,
- handle, (unsigned long long)
- le64_to_cpu(sas_device_pg0.SASAddress));
+ ioc_info(ioc, "\tAFTER adding end device: handle (0x%04x), sas_addr(0x%016llx)\n",
+ handle,
+ (u64)le64_to_cpu(sas_device_pg0.SASAddress));
}
}
- pr_info(MPT3SAS_FMT "\tscan devices: end devices complete\n",
- ioc->name);
- pr_info(MPT3SAS_FMT "\tscan devices: pcie end devices start\n",
- ioc->name);
+ ioc_info(ioc, "\tscan devices: end devices complete\n");
+ ioc_info(ioc, "\tscan devices: pcie end devices start\n");
/* pcie devices */
handle = 0xFFFF;
@@ -9260,10 +9123,8 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc)
ioc_status = le16_to_cpu(mpi_reply.IOCStatus)
& MPI2_IOCSTATUS_MASK;
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- pr_info(MPT3SAS_FMT "\tbreak from pcie end device"
- " scan: ioc_status(0x%04x), loginfo(0x%08x)\n",
- ioc->name, ioc_status,
- le32_to_cpu(mpi_reply.IOCLogInfo));
+ ioc_info(ioc, "\tbreak from pcie end device scan: ioc_status(0x%04x), loginfo(0x%08x)\n",
+ ioc_status, le32_to_cpu(mpi_reply.IOCLogInfo));
break;
}
handle = le16_to_cpu(pcie_device_pg0.DevHandle);
@@ -9280,14 +9141,11 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc)
parent_handle = le16_to_cpu(pcie_device_pg0.ParentDevHandle);
_scsih_pcie_add_device(ioc, handle);
- pr_info(MPT3SAS_FMT "\tAFTER adding pcie end device: "
- "handle (0x%04x), wwid(0x%016llx)\n", ioc->name,
- handle,
- (unsigned long long) le64_to_cpu(pcie_device_pg0.WWID));
+ ioc_info(ioc, "\tAFTER adding pcie end device: handle (0x%04x), wwid(0x%016llx)\n",
+ handle, (u64)le64_to_cpu(pcie_device_pg0.WWID));
}
- pr_info(MPT3SAS_FMT "\tpcie devices: pcie end devices complete\n",
- ioc->name);
- pr_info(MPT3SAS_FMT "scan devices: complete\n", ioc->name);
+ ioc_info(ioc, "\tpcie devices: pcie end devices complete\n");
+ ioc_info(ioc, "scan devices: complete\n");
}
/**
@@ -9298,8 +9156,7 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc)
*/
void mpt3sas_scsih_pre_reset_handler(struct MPT3SAS_ADAPTER *ioc)
{
- dtmprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: MPT3_IOC_PRE_RESET\n", ioc->name, __func__));
+ dtmprintk(ioc, ioc_info(ioc, "%s: MPT3_IOC_PRE_RESET\n", __func__));
}
/**
@@ -9311,8 +9168,7 @@ void mpt3sas_scsih_pre_reset_handler(struct MPT3SAS_ADAPTER *ioc)
void
mpt3sas_scsih_after_reset_handler(struct MPT3SAS_ADAPTER *ioc)
{
- dtmprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: MPT3_IOC_AFTER_RESET\n", ioc->name, __func__));
+ dtmprintk(ioc, ioc_info(ioc, "%s: MPT3_IOC_AFTER_RESET\n", __func__));
if (ioc->scsih_cmds.status & MPT3_CMD_PENDING) {
ioc->scsih_cmds.status |= MPT3_CMD_RESET;
mpt3sas_base_free_smid(ioc, ioc->scsih_cmds.smid);
@@ -9340,8 +9196,7 @@ mpt3sas_scsih_after_reset_handler(struct MPT3SAS_ADAPTER *ioc)
void
mpt3sas_scsih_reset_done_handler(struct MPT3SAS_ADAPTER *ioc)
{
- dtmprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: MPT3_IOC_DONE_RESET\n", ioc->name, __func__));
+ 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)) {
_scsih_prep_device_scan(ioc);
@@ -9396,9 +9251,8 @@ _mpt3sas_fw_work(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event)
if (missing_delay[0] != -1 && missing_delay[1] != -1)
mpt3sas_base_update_missing_delay(ioc, missing_delay[0],
missing_delay[1]);
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "port enable: complete from worker thread\n",
- ioc->name));
+ dewtprintk(ioc,
+ ioc_info(ioc, "port enable: complete from worker thread\n"));
break;
case MPT3SAS_TURN_ON_PFA_LED:
_scsih_turn_on_pfa_led(ioc, fw_event->device_handle);
@@ -9496,8 +9350,8 @@ mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index,
mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply);
if (unlikely(!mpi_reply)) {
- pr_err(MPT3SAS_FMT "mpi_reply not valid at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "mpi_reply not valid at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
return 1;
}
@@ -9564,30 +9418,16 @@ mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index,
switch (le32_to_cpu(*log_code)) {
case MPT2_WARPDRIVE_LC_SSDT:
- pr_warn(MPT3SAS_FMT "WarpDrive Warning: "
- "IO Throttling has occurred in the WarpDrive "
- "subsystem. Check WarpDrive documentation for "
- "additional details.\n", ioc->name);
+ ioc_warn(ioc, "WarpDrive Warning: IO Throttling has occurred in the WarpDrive subsystem. Check WarpDrive documentation for additional details.\n");
break;
case MPT2_WARPDRIVE_LC_SSDLW:
- pr_warn(MPT3SAS_FMT "WarpDrive Warning: "
- "Program/Erase Cycles for the WarpDrive subsystem "
- "in degraded range. Check WarpDrive documentation "
- "for additional details.\n", ioc->name);
+ ioc_warn(ioc, "WarpDrive Warning: Program/Erase Cycles for the WarpDrive subsystem in degraded range. Check WarpDrive documentation for additional details.\n");
break;
case MPT2_WARPDRIVE_LC_SSDLF:
- pr_err(MPT3SAS_FMT "WarpDrive Fatal Error: "
- "There are no Program/Erase Cycles for the "
- "WarpDrive subsystem. The storage device will be "
- "in read-only mode. Check WarpDrive documentation "
- "for additional details.\n", ioc->name);
+ ioc_err(ioc, "WarpDrive Fatal Error: There are no Program/Erase Cycles for the WarpDrive subsystem. The storage device will be in read-only mode. Check WarpDrive documentation for additional details.\n");
break;
case MPT2_WARPDRIVE_LC_BRMF:
- pr_err(MPT3SAS_FMT "WarpDrive Fatal Error: "
- "The Backup Rail Monitor has failed on the "
- "WarpDrive subsystem. Check WarpDrive "
- "documentation for additional details.\n",
- ioc->name);
+ ioc_err(ioc, "WarpDrive Fatal Error: The Backup Rail Monitor has failed on the WarpDrive subsystem. Check WarpDrive documentation for additional details.\n");
break;
}
@@ -9613,9 +9453,8 @@ mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index,
(Mpi26EventDataActiveCableExcept_t *) mpi_reply->EventData;
switch (ActiveCableEventData->ReasonCode) {
case MPI26_EVENT_ACTIVE_CABLE_INSUFFICIENT_POWER:
- pr_notice(MPT3SAS_FMT
- "Currently an active cable with ReceptacleID %d\n",
- ioc->name, ActiveCableEventData->ReceptacleID);
+ ioc_notice(ioc, "Currently an active cable with ReceptacleID %d\n",
+ ActiveCableEventData->ReceptacleID);
pr_notice("cannot be powered and devices connected\n");
pr_notice("to this active cable will not be seen\n");
pr_notice("This active cable requires %d mW of power\n",
@@ -9623,9 +9462,8 @@ mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index,
break;
case MPI26_EVENT_ACTIVE_CABLE_DEGRADED:
- pr_notice(MPT3SAS_FMT
- "Currently a cable with ReceptacleID %d\n",
- ioc->name, ActiveCableEventData->ReceptacleID);
+ ioc_notice(ioc, "Currently a cable with ReceptacleID %d\n",
+ ActiveCableEventData->ReceptacleID);
pr_notice(
"is not running at optimal speed(12 Gb/s rate)\n");
break;
@@ -9640,8 +9478,8 @@ mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index,
sz = le16_to_cpu(mpi_reply->EventDataLength) * 4;
fw_event = alloc_fw_event_work(sz);
if (!fw_event) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
return 1;
}
@@ -9690,11 +9528,9 @@ _scsih_expander_node_remove(struct MPT3SAS_ADAPTER *ioc,
mpt3sas_transport_port_remove(ioc, sas_expander->sas_address,
sas_expander->sas_address_parent);
- pr_info(MPT3SAS_FMT
- "expander_remove: handle(0x%04x), sas_addr(0x%016llx)\n",
- ioc->name,
- sas_expander->handle, (unsigned long long)
- sas_expander->sas_address);
+ ioc_info(ioc, "expander_remove: handle(0x%04x), sas_addr(0x%016llx)\n",
+ sas_expander->handle, (unsigned long long)
+ sas_expander->sas_address);
spin_lock_irqsave(&ioc->sas_node_lock, flags);
list_del(&sas_expander->list);
@@ -9729,16 +9565,14 @@ _scsih_ir_shutdown(struct MPT3SAS_ADAPTER *ioc)
mutex_lock(&ioc->scsih_cmds.mutex);
if (ioc->scsih_cmds.status != MPT3_CMD_NOT_USED) {
- pr_err(MPT3SAS_FMT "%s: scsih_cmd in use\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: scsih_cmd in use\n", __func__);
goto out;
}
ioc->scsih_cmds.status = MPT3_CMD_PENDING;
smid = mpt3sas_base_get_smid(ioc, ioc->scsih_cb_idx);
if (!smid) {
- pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);
ioc->scsih_cmds.status = MPT3_CMD_NOT_USED;
goto out;
}
@@ -9751,24 +9585,22 @@ _scsih_ir_shutdown(struct MPT3SAS_ADAPTER *ioc)
mpi_request->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED;
if (!ioc->hide_ir_msg)
- pr_info(MPT3SAS_FMT "IR shutdown (sending)\n", ioc->name);
+ ioc_info(ioc, "IR shutdown (sending)\n");
init_completion(&ioc->scsih_cmds.done);
mpt3sas_base_put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ);
if (!(ioc->scsih_cmds.status & MPT3_CMD_COMPLETE)) {
- pr_err(MPT3SAS_FMT "%s: timeout\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: timeout\n", __func__);
goto out;
}
if (ioc->scsih_cmds.status & MPT3_CMD_REPLY_VALID) {
mpi_reply = ioc->scsih_cmds.reply;
if (!ioc->hide_ir_msg)
- pr_info(MPT3SAS_FMT "IR shutdown "
- "(complete): ioc_status(0x%04x), loginfo(0x%08x)\n",
- ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
- le32_to_cpu(mpi_reply->IOCLogInfo));
+ ioc_info(ioc, "IR shutdown (complete): ioc_status(0x%04x), loginfo(0x%08x)\n",
+ le16_to_cpu(mpi_reply->IOCStatus),
+ le32_to_cpu(mpi_reply->IOCLogInfo));
}
out:
@@ -9817,9 +9649,8 @@ static void scsih_remove(struct pci_dev *pdev)
sas_target_priv_data->deleted = 1;
scsi_remove_target(&raid_device->starget->dev);
}
- pr_info(MPT3SAS_FMT "removing handle(0x%04x), wwid(0x%016llx)\n",
- ioc->name, raid_device->handle,
- (unsigned long long) raid_device->wwid);
+ ioc_info(ioc, "removing handle(0x%04x), wwid(0x%016llx)\n",
+ raid_device->handle, (u64)raid_device->wwid);
_scsih_raid_device_remove(ioc, raid_device);
}
list_for_each_entry_safe(pcie_device, pcienext, &ioc->pcie_device_list,
@@ -10230,7 +10061,7 @@ scsih_scan_start(struct Scsi_Host *shost)
rc = mpt3sas_port_enable(ioc);
if (rc != 0)
- pr_info(MPT3SAS_FMT "port enable: FAILED\n", ioc->name);
+ ioc_info(ioc, "port enable: FAILED\n");
}
/**
@@ -10255,9 +10086,7 @@ scsih_scan_finished(struct Scsi_Host *shost, unsigned long time)
if (time >= (300 * HZ)) {
ioc->port_enable_cmds.status = MPT3_CMD_NOT_USED;
- pr_info(MPT3SAS_FMT
- "port enable: FAILED with timeout (timeout=300s)\n",
- ioc->name);
+ ioc_info(ioc, "port enable: FAILED with timeout (timeout=300s)\n");
ioc->is_driver_loading = 0;
return 1;
}
@@ -10266,16 +10095,15 @@ scsih_scan_finished(struct Scsi_Host *shost, unsigned long time)
return 0;
if (ioc->start_scan_failed) {
- pr_info(MPT3SAS_FMT
- "port enable: FAILED with (ioc_status=0x%08x)\n",
- ioc->name, ioc->start_scan_failed);
+ ioc_info(ioc, "port enable: FAILED with (ioc_status=0x%08x)\n",
+ ioc->start_scan_failed);
ioc->is_driver_loading = 0;
ioc->wait_for_discovery_to_complete = 0;
ioc->remove_host = 1;
return 1;
}
- pr_info(MPT3SAS_FMT "port enable: SUCCESS\n", ioc->name);
+ ioc_info(ioc, "port enable: SUCCESS\n");
ioc->port_enable_cmds.status = MPT3_CMD_NOT_USED;
if (ioc->wait_for_discovery_to_complete) {
@@ -10586,28 +10414,22 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (ioc->is_mcpu_endpoint) {
/* mCPU MPI support 64K max IO */
shost->max_sectors = 128;
- pr_info(MPT3SAS_FMT
- "The max_sectors value is set to %d\n",
- ioc->name, shost->max_sectors);
+ ioc_info(ioc, "The max_sectors value is set to %d\n",
+ shost->max_sectors);
} else {
if (max_sectors != 0xFFFF) {
if (max_sectors < 64) {
shost->max_sectors = 64;
- pr_warn(MPT3SAS_FMT "Invalid value %d passed " \
- "for max_sectors, range is 64 to 32767. " \
- "Assigning value of 64.\n", \
- ioc->name, max_sectors);
+ ioc_warn(ioc, "Invalid value %d passed for max_sectors, range is 64 to 32767. Assigning value of 64.\n",
+ max_sectors);
} else if (max_sectors > 32767) {
shost->max_sectors = 32767;
- pr_warn(MPT3SAS_FMT "Invalid value %d passed " \
- "for max_sectors, range is 64 to 32767." \
- "Assigning default value of 32767.\n", \
- ioc->name, max_sectors);
+ ioc_warn(ioc, "Invalid value %d passed for max_sectors, range is 64 to 32767.Assigning default value of 32767.\n",
+ max_sectors);
} else {
shost->max_sectors = max_sectors & 0xFFFE;
- pr_info(MPT3SAS_FMT
- "The max_sectors value is set to %d\n",
- ioc->name, shost->max_sectors);
+ ioc_info(ioc, "The max_sectors value is set to %d\n",
+ shost->max_sectors);
}
}
}
@@ -10627,16 +10449,16 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ioc->firmware_event_thread = alloc_ordered_workqueue(
ioc->firmware_event_name, 0);
if (!ioc->firmware_event_thread) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
rv = -ENODEV;
goto out_thread_fail;
}
ioc->is_driver_loading = 1;
if ((mpt3sas_base_attach(ioc))) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
rv = -ENODEV;
goto out_attach_fail;
}
@@ -10657,8 +10479,8 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
rv = scsi_add_host(shost, &pdev->dev);
if (rv) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
goto out_add_shost_fail;
}
@@ -10695,9 +10517,8 @@ scsih_suspend(struct pci_dev *pdev, pm_message_t state)
flush_scheduled_work();
scsi_block_requests(shost);
device_state = pci_choose_state(pdev, state);
- pr_info(MPT3SAS_FMT
- "pdev=0x%p, slot=%s, entering operating state [D%d]\n",
- ioc->name, pdev, pci_name(pdev), device_state);
+ ioc_info(ioc, "pdev=0x%p, slot=%s, entering operating state [D%d]\n",
+ pdev, pci_name(pdev), device_state);
pci_save_state(pdev);
mpt3sas_base_free_resources(ioc);
@@ -10719,9 +10540,8 @@ scsih_resume(struct pci_dev *pdev)
pci_power_t device_state = pdev->current_state;
int r;
- pr_info(MPT3SAS_FMT
- "pdev=0x%p, slot=%s, previous operating state [D%d]\n",
- ioc->name, pdev, pci_name(pdev), device_state);
+ ioc_info(ioc, "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);
@@ -10753,8 +10573,7 @@ scsih_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
struct Scsi_Host *shost = pci_get_drvdata(pdev);
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
- pr_info(MPT3SAS_FMT "PCI error: detected callback, state(%d)!!\n",
- ioc->name, state);
+ ioc_info(ioc, "PCI error: detected callback, state(%d)!!\n", state);
switch (state) {
case pci_channel_io_normal:
@@ -10791,8 +10610,7 @@ scsih_pci_slot_reset(struct pci_dev *pdev)
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
int rc;
- pr_info(MPT3SAS_FMT "PCI error: slot reset callback!!\n",
- ioc->name);
+ ioc_info(ioc, "PCI error: slot reset callback!!\n");
ioc->pci_error_recovery = 0;
ioc->pdev = pdev;
@@ -10803,8 +10621,8 @@ scsih_pci_slot_reset(struct pci_dev *pdev)
rc = mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
- pr_warn(MPT3SAS_FMT "hard reset: %s\n", ioc->name,
- (rc == 0) ? "success" : "failed");
+ ioc_warn(ioc, "hard reset: %s\n",
+ (rc == 0) ? "success" : "failed");
if (!rc)
return PCI_ERS_RESULT_RECOVERED;
@@ -10826,9 +10644,8 @@ scsih_pci_resume(struct pci_dev *pdev)
struct Scsi_Host *shost = pci_get_drvdata(pdev);
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
- pr_info(MPT3SAS_FMT "PCI error: resume callback!!\n", ioc->name);
+ ioc_info(ioc, "PCI error: resume callback!!\n");
- pci_cleanup_aer_uncorrect_error_status(pdev);
mpt3sas_base_start_watchdog(ioc);
scsi_unblock_requests(ioc->shost);
}
@@ -10843,8 +10660,7 @@ scsih_pci_mmio_enabled(struct pci_dev *pdev)
struct Scsi_Host *shost = pci_get_drvdata(pdev);
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
- pr_info(MPT3SAS_FMT "PCI error: mmio enabled callback!!\n",
- ioc->name);
+ ioc_info(ioc, "PCI error: mmio enabled callback!!\n");
/* TODO - dump whatever for debugging purposes */
diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c b/drivers/scsi/mpt3sas/mpt3sas_transport.c
index f8cc2677c1cd..6a8a3c09b4b1 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_transport.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c
@@ -146,25 +146,22 @@ _transport_set_identify(struct MPT3SAS_ADAPTER *ioc, u16 handle,
u32 ioc_status;
if (ioc->shost_recovery || ioc->pci_error_recovery) {
- pr_info(MPT3SAS_FMT "%s: host reset in progress!\n",
- __func__, ioc->name);
+ ioc_info(ioc, "%s: host reset in progress!\n", __func__);
return -EFAULT;
}
if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
return -ENXIO;
}
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
MPI2_IOCSTATUS_MASK;
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- pr_err(MPT3SAS_FMT
- "handle(0x%04x), ioc_status(0x%04x)\nfailure at %s:%d/%s()!\n",
- ioc->name, handle, ioc_status,
- __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "handle(0x%04x), ioc_status(0x%04x) failure at %s:%d/%s()!\n",
+ handle, ioc_status, __FILE__, __LINE__, __func__);
return -EIO;
}
@@ -310,16 +307,14 @@ _transport_expander_report_manufacture(struct MPT3SAS_ADAPTER *ioc,
u16 wait_state_count;
if (ioc->shost_recovery || ioc->pci_error_recovery) {
- pr_info(MPT3SAS_FMT "%s: host reset in progress!\n",
- __func__, ioc->name);
+ ioc_info(ioc, "%s: host reset in progress!\n", __func__);
return -EFAULT;
}
mutex_lock(&ioc->transport_cmds.mutex);
if (ioc->transport_cmds.status != MPT3_CMD_NOT_USED) {
- pr_err(MPT3SAS_FMT "%s: transport_cmds in use\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: transport_cmds in use\n", __func__);
rc = -EAGAIN;
goto out;
}
@@ -329,26 +324,22 @@ _transport_expander_report_manufacture(struct MPT3SAS_ADAPTER *ioc,
ioc_state = mpt3sas_base_get_iocstate(ioc, 1);
while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
if (wait_state_count++ == 10) {
- pr_err(MPT3SAS_FMT
- "%s: failed due to ioc not operational\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: failed due to ioc not operational\n",
+ __func__);
rc = -EFAULT;
goto out;
}
ssleep(1);
ioc_state = mpt3sas_base_get_iocstate(ioc, 1);
- pr_info(MPT3SAS_FMT
- "%s: waiting for operational state(count=%d)\n",
- ioc->name, __func__, wait_state_count);
+ ioc_info(ioc, "%s: waiting for operational state(count=%d)\n",
+ __func__, wait_state_count);
}
if (wait_state_count)
- pr_info(MPT3SAS_FMT "%s: ioc is operational\n",
- ioc->name, __func__);
+ ioc_info(ioc, "%s: ioc is operational\n", __func__);
smid = mpt3sas_base_get_smid(ioc, ioc->transport_cb_idx);
if (!smid) {
- pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);
rc = -EAGAIN;
goto out;
}
@@ -359,9 +350,8 @@ _transport_expander_report_manufacture(struct MPT3SAS_ADAPTER *ioc,
data_out_sz = sizeof(struct rep_manu_request);
data_in_sz = sizeof(struct rep_manu_reply);
- data_out = pci_alloc_consistent(ioc->pdev, data_out_sz + data_in_sz,
- &data_out_dma);
-
+ data_out = dma_alloc_coherent(&ioc->pdev->dev, data_out_sz + data_in_sz,
+ &data_out_dma, GFP_KERNEL);
if (!data_out) {
pr_err("failure at %s:%d/%s()!\n", __FILE__,
__LINE__, __func__);
@@ -388,16 +378,15 @@ _transport_expander_report_manufacture(struct MPT3SAS_ADAPTER *ioc,
ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma,
data_in_sz);
- dtransportprintk(ioc, pr_info(MPT3SAS_FMT
- "report_manufacture - send to sas_addr(0x%016llx)\n",
- ioc->name, (unsigned long long)sas_address));
+ dtransportprintk(ioc,
+ ioc_info(ioc, "report_manufacture - send to sas_addr(0x%016llx)\n",
+ (u64)sas_address));
init_completion(&ioc->transport_cmds.done);
mpt3sas_base_put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ);
if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) {
- pr_err(MPT3SAS_FMT "%s: timeout\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: timeout\n", __func__);
_debug_dump_mf(mpi_request,
sizeof(Mpi2SmpPassthroughRequest_t)/4);
if (!(ioc->transport_cmds.status & MPT3_CMD_RESET))
@@ -405,17 +394,16 @@ _transport_expander_report_manufacture(struct MPT3SAS_ADAPTER *ioc,
goto issue_host_reset;
}
- dtransportprintk(ioc, pr_info(MPT3SAS_FMT
- "report_manufacture - complete\n", ioc->name));
+ dtransportprintk(ioc, ioc_info(ioc, "report_manufacture - complete\n"));
if (ioc->transport_cmds.status & MPT3_CMD_REPLY_VALID) {
u8 *tmp;
mpi_reply = ioc->transport_cmds.reply;
- dtransportprintk(ioc, pr_info(MPT3SAS_FMT
- "report_manufacture - reply data transfer size(%d)\n",
- ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength)));
+ dtransportprintk(ioc,
+ ioc_info(ioc, "report_manufacture - reply data transfer size(%d)\n",
+ le16_to_cpu(mpi_reply->ResponseDataLength)));
if (le16_to_cpu(mpi_reply->ResponseDataLength) !=
sizeof(struct rep_manu_reply))
@@ -439,8 +427,8 @@ _transport_expander_report_manufacture(struct MPT3SAS_ADAPTER *ioc,
manufacture_reply->component_revision_id;
}
} else
- dtransportprintk(ioc, pr_info(MPT3SAS_FMT
- "report_manufacture - no reply\n", ioc->name));
+ dtransportprintk(ioc,
+ ioc_info(ioc, "report_manufacture - no reply\n"));
issue_host_reset:
if (issue_reset)
@@ -448,7 +436,7 @@ _transport_expander_report_manufacture(struct MPT3SAS_ADAPTER *ioc,
out:
ioc->transport_cmds.status = MPT3_CMD_NOT_USED;
if (data_out)
- pci_free_consistent(ioc->pdev, data_out_sz + data_in_sz,
+ dma_free_coherent(&ioc->pdev->dev, data_out_sz + data_in_sz,
data_out, data_out_dma);
mutex_unlock(&ioc->transport_cmds.mutex);
@@ -643,8 +631,8 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle,
mpt3sas_port = kzalloc(sizeof(struct _sas_port),
GFP_KERNEL);
if (!mpt3sas_port) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
return NULL;
}
@@ -655,22 +643,21 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle,
spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
if (!sas_node) {
- pr_err(MPT3SAS_FMT
- "%s: Could not find parent sas_address(0x%016llx)!\n",
- ioc->name, __func__, (unsigned long long)sas_address);
+ ioc_err(ioc, "%s: Could not find parent sas_address(0x%016llx)!\n",
+ __func__, (u64)sas_address);
goto out_fail;
}
if ((_transport_set_identify(ioc, handle,
&mpt3sas_port->remote_identify))) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
goto out_fail;
}
if (mpt3sas_port->remote_identify.device_type == SAS_PHY_UNUSED) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
goto out_fail;
}
@@ -687,20 +674,20 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle,
}
if (!mpt3sas_port->num_phys) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
goto out_fail;
}
if (!sas_node->parent_dev) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
goto out_fail;
}
port = sas_port_alloc_num(sas_node->parent_dev);
if ((sas_port_add(port))) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
goto out_fail;
}
@@ -729,17 +716,17 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle,
sas_device = mpt3sas_get_sdev_by_addr(ioc,
mpt3sas_port->remote_identify.sas_address);
if (!sas_device) {
- dfailprintk(ioc, printk(MPT3SAS_FMT
- "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__));
+ dfailprintk(ioc,
+ ioc_info(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__));
goto out_fail;
}
sas_device->pend_sas_rphy_add = 1;
}
if ((sas_rphy_add(rphy))) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
}
if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) {
@@ -861,14 +848,14 @@ mpt3sas_transport_add_host_phy(struct MPT3SAS_ADAPTER *ioc, struct _sas_phy
INIT_LIST_HEAD(&mpt3sas_phy->port_siblings);
phy = sas_phy_alloc(parent_dev, phy_index);
if (!phy) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
return -1;
}
if ((_transport_set_identify(ioc, mpt3sas_phy->handle,
&mpt3sas_phy->identify))) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
sas_phy_free(phy);
return -1;
}
@@ -890,8 +877,8 @@ mpt3sas_transport_add_host_phy(struct MPT3SAS_ADAPTER *ioc, struct _sas_phy
phy_pg0.ProgrammedLinkRate >> 4);
if ((sas_phy_add(phy))) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
sas_phy_free(phy);
return -1;
}
@@ -929,14 +916,14 @@ mpt3sas_transport_add_expander_phy(struct MPT3SAS_ADAPTER *ioc, struct _sas_phy
INIT_LIST_HEAD(&mpt3sas_phy->port_siblings);
phy = sas_phy_alloc(parent_dev, phy_index);
if (!phy) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
return -1;
}
if ((_transport_set_identify(ioc, mpt3sas_phy->handle,
&mpt3sas_phy->identify))) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
sas_phy_free(phy);
return -1;
}
@@ -960,8 +947,8 @@ mpt3sas_transport_add_expander_phy(struct MPT3SAS_ADAPTER *ioc, struct _sas_phy
expander_pg1.ProgrammedLinkRate >> 4);
if ((sas_phy_add(phy))) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
sas_phy_free(phy);
return -1;
}
@@ -1098,16 +1085,14 @@ _transport_get_expander_phy_error_log(struct MPT3SAS_ADAPTER *ioc,
u16 wait_state_count;
if (ioc->shost_recovery || ioc->pci_error_recovery) {
- pr_info(MPT3SAS_FMT "%s: host reset in progress!\n",
- __func__, ioc->name);
+ ioc_info(ioc, "%s: host reset in progress!\n", __func__);
return -EFAULT;
}
mutex_lock(&ioc->transport_cmds.mutex);
if (ioc->transport_cmds.status != MPT3_CMD_NOT_USED) {
- pr_err(MPT3SAS_FMT "%s: transport_cmds in use\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: transport_cmds in use\n", __func__);
rc = -EAGAIN;
goto out;
}
@@ -1117,26 +1102,22 @@ _transport_get_expander_phy_error_log(struct MPT3SAS_ADAPTER *ioc,
ioc_state = mpt3sas_base_get_iocstate(ioc, 1);
while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
if (wait_state_count++ == 10) {
- pr_err(MPT3SAS_FMT
- "%s: failed due to ioc not operational\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: failed due to ioc not operational\n",
+ __func__);
rc = -EFAULT;
goto out;
}
ssleep(1);
ioc_state = mpt3sas_base_get_iocstate(ioc, 1);
- pr_info(MPT3SAS_FMT
- "%s: waiting for operational state(count=%d)\n",
- ioc->name, __func__, wait_state_count);
+ ioc_info(ioc, "%s: waiting for operational state(count=%d)\n",
+ __func__, wait_state_count);
}
if (wait_state_count)
- pr_info(MPT3SAS_FMT "%s: ioc is operational\n",
- ioc->name, __func__);
+ ioc_info(ioc, "%s: ioc is operational\n", __func__);
smid = mpt3sas_base_get_smid(ioc, ioc->transport_cb_idx);
if (!smid) {
- pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);
rc = -EAGAIN;
goto out;
}
@@ -1146,7 +1127,8 @@ _transport_get_expander_phy_error_log(struct MPT3SAS_ADAPTER *ioc,
sz = sizeof(struct phy_error_log_request) +
sizeof(struct phy_error_log_reply);
- data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma);
+ data_out = dma_alloc_coherent(&ioc->pdev->dev, sz, &data_out_dma,
+ GFP_KERNEL);
if (!data_out) {
pr_err("failure at %s:%d/%s()!\n", __FILE__,
__LINE__, __func__);
@@ -1179,17 +1161,16 @@ _transport_get_expander_phy_error_log(struct MPT3SAS_ADAPTER *ioc,
data_out_dma + sizeof(struct phy_error_log_request),
sizeof(struct phy_error_log_reply));
- dtransportprintk(ioc, pr_info(MPT3SAS_FMT
- "phy_error_log - send to sas_addr(0x%016llx), phy(%d)\n",
- ioc->name, (unsigned long long)phy->identify.sas_address,
- phy->number));
+ dtransportprintk(ioc,
+ ioc_info(ioc, "phy_error_log - send to sas_addr(0x%016llx), phy(%d)\n",
+ (u64)phy->identify.sas_address,
+ phy->number));
init_completion(&ioc->transport_cmds.done);
mpt3sas_base_put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ);
if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) {
- pr_err(MPT3SAS_FMT "%s: timeout\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: timeout\n", __func__);
_debug_dump_mf(mpi_request,
sizeof(Mpi2SmpPassthroughRequest_t)/4);
if (!(ioc->transport_cmds.status & MPT3_CMD_RESET))
@@ -1197,16 +1178,15 @@ _transport_get_expander_phy_error_log(struct MPT3SAS_ADAPTER *ioc,
goto issue_host_reset;
}
- dtransportprintk(ioc, pr_info(MPT3SAS_FMT
- "phy_error_log - complete\n", ioc->name));
+ dtransportprintk(ioc, ioc_info(ioc, "phy_error_log - complete\n"));
if (ioc->transport_cmds.status & MPT3_CMD_REPLY_VALID) {
mpi_reply = ioc->transport_cmds.reply;
- dtransportprintk(ioc, pr_info(MPT3SAS_FMT
- "phy_error_log - reply data transfer size(%d)\n",
- ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength)));
+ dtransportprintk(ioc,
+ ioc_info(ioc, "phy_error_log - reply data transfer size(%d)\n",
+ le16_to_cpu(mpi_reply->ResponseDataLength)));
if (le16_to_cpu(mpi_reply->ResponseDataLength) !=
sizeof(struct phy_error_log_reply))
@@ -1215,9 +1195,9 @@ _transport_get_expander_phy_error_log(struct MPT3SAS_ADAPTER *ioc,
phy_error_log_reply = data_out +
sizeof(struct phy_error_log_request);
- dtransportprintk(ioc, pr_info(MPT3SAS_FMT
- "phy_error_log - function_result(%d)\n",
- ioc->name, phy_error_log_reply->function_result));
+ dtransportprintk(ioc,
+ ioc_info(ioc, "phy_error_log - function_result(%d)\n",
+ phy_error_log_reply->function_result));
phy->invalid_dword_count =
be32_to_cpu(phy_error_log_reply->invalid_dword);
@@ -1229,8 +1209,8 @@ _transport_get_expander_phy_error_log(struct MPT3SAS_ADAPTER *ioc,
be32_to_cpu(phy_error_log_reply->phy_reset_problem);
rc = 0;
} else
- dtransportprintk(ioc, pr_info(MPT3SAS_FMT
- "phy_error_log - no reply\n", ioc->name));
+ dtransportprintk(ioc,
+ ioc_info(ioc, "phy_error_log - no reply\n"));
issue_host_reset:
if (issue_reset)
@@ -1238,7 +1218,7 @@ _transport_get_expander_phy_error_log(struct MPT3SAS_ADAPTER *ioc,
out:
ioc->transport_cmds.status = MPT3_CMD_NOT_USED;
if (data_out)
- pci_free_consistent(ioc->pdev, sz, data_out, data_out_dma);
+ dma_free_coherent(&ioc->pdev->dev, sz, data_out, data_out_dma);
mutex_unlock(&ioc->transport_cmds.mutex);
return rc;
@@ -1273,17 +1253,16 @@ _transport_get_linkerrors(struct sas_phy *phy)
/* get hba phy error logs */
if ((mpt3sas_config_get_phy_pg1(ioc, &mpi_reply, &phy_pg1,
phy->number))) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
return -ENXIO;
}
if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo)
- pr_info(MPT3SAS_FMT
- "phy(%d), ioc_status (0x%04x), loginfo(0x%08x)\n",
- ioc->name, phy->number,
- le16_to_cpu(mpi_reply.IOCStatus),
- le32_to_cpu(mpi_reply.IOCLogInfo));
+ ioc_info(ioc, "phy(%d), ioc_status (0x%04x), loginfo(0x%08x)\n",
+ phy->number,
+ le16_to_cpu(mpi_reply.IOCStatus),
+ le32_to_cpu(mpi_reply.IOCLogInfo));
phy->invalid_dword_count = le32_to_cpu(phy_pg1.InvalidDwordCount);
phy->running_disparity_error_count =
@@ -1411,16 +1390,14 @@ _transport_expander_phy_control(struct MPT3SAS_ADAPTER *ioc,
u16 wait_state_count;
if (ioc->shost_recovery || ioc->pci_error_recovery) {
- pr_info(MPT3SAS_FMT "%s: host reset in progress!\n",
- __func__, ioc->name);
+ ioc_info(ioc, "%s: host reset in progress!\n", __func__);
return -EFAULT;
}
mutex_lock(&ioc->transport_cmds.mutex);
if (ioc->transport_cmds.status != MPT3_CMD_NOT_USED) {
- pr_err(MPT3SAS_FMT "%s: transport_cmds in use\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: transport_cmds in use\n", __func__);
rc = -EAGAIN;
goto out;
}
@@ -1430,26 +1407,22 @@ _transport_expander_phy_control(struct MPT3SAS_ADAPTER *ioc,
ioc_state = mpt3sas_base_get_iocstate(ioc, 1);
while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
if (wait_state_count++ == 10) {
- pr_err(MPT3SAS_FMT
- "%s: failed due to ioc not operational\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: failed due to ioc not operational\n",
+ __func__);
rc = -EFAULT;
goto out;
}
ssleep(1);
ioc_state = mpt3sas_base_get_iocstate(ioc, 1);
- pr_info(MPT3SAS_FMT
- "%s: waiting for operational state(count=%d)\n",
- ioc->name, __func__, wait_state_count);
+ ioc_info(ioc, "%s: waiting for operational state(count=%d)\n",
+ __func__, wait_state_count);
}
if (wait_state_count)
- pr_info(MPT3SAS_FMT "%s: ioc is operational\n",
- ioc->name, __func__);
+ ioc_info(ioc, "%s: ioc is operational\n", __func__);
smid = mpt3sas_base_get_smid(ioc, ioc->transport_cb_idx);
if (!smid) {
- pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);
rc = -EAGAIN;
goto out;
}
@@ -1459,7 +1432,8 @@ _transport_expander_phy_control(struct MPT3SAS_ADAPTER *ioc,
sz = sizeof(struct phy_control_request) +
sizeof(struct phy_control_reply);
- data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma);
+ data_out = dma_alloc_coherent(&ioc->pdev->dev, sz, &data_out_dma,
+ GFP_KERNEL);
if (!data_out) {
pr_err("failure at %s:%d/%s()!\n", __FILE__,
__LINE__, __func__);
@@ -1497,17 +1471,16 @@ _transport_expander_phy_control(struct MPT3SAS_ADAPTER *ioc,
data_out_dma + sizeof(struct phy_control_request),
sizeof(struct phy_control_reply));
- dtransportprintk(ioc, pr_info(MPT3SAS_FMT
- "phy_control - send to sas_addr(0x%016llx), phy(%d), opcode(%d)\n",
- ioc->name, (unsigned long long)phy->identify.sas_address,
- phy->number, phy_operation));
+ dtransportprintk(ioc,
+ ioc_info(ioc, "phy_control - send to sas_addr(0x%016llx), phy(%d), opcode(%d)\n",
+ (u64)phy->identify.sas_address,
+ phy->number, phy_operation));
init_completion(&ioc->transport_cmds.done);
mpt3sas_base_put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ);
if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) {
- pr_err(MPT3SAS_FMT "%s: timeout\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: timeout\n", __func__);
_debug_dump_mf(mpi_request,
sizeof(Mpi2SmpPassthroughRequest_t)/4);
if (!(ioc->transport_cmds.status & MPT3_CMD_RESET))
@@ -1515,16 +1488,15 @@ _transport_expander_phy_control(struct MPT3SAS_ADAPTER *ioc,
goto issue_host_reset;
}
- dtransportprintk(ioc, pr_info(MPT3SAS_FMT
- "phy_control - complete\n", ioc->name));
+ dtransportprintk(ioc, ioc_info(ioc, "phy_control - complete\n"));
if (ioc->transport_cmds.status & MPT3_CMD_REPLY_VALID) {
mpi_reply = ioc->transport_cmds.reply;
- dtransportprintk(ioc, pr_info(MPT3SAS_FMT
- "phy_control - reply data transfer size(%d)\n",
- ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength)));
+ dtransportprintk(ioc,
+ ioc_info(ioc, "phy_control - reply data transfer size(%d)\n",
+ le16_to_cpu(mpi_reply->ResponseDataLength)));
if (le16_to_cpu(mpi_reply->ResponseDataLength) !=
sizeof(struct phy_control_reply))
@@ -1533,14 +1505,14 @@ _transport_expander_phy_control(struct MPT3SAS_ADAPTER *ioc,
phy_control_reply = data_out +
sizeof(struct phy_control_request);
- dtransportprintk(ioc, pr_info(MPT3SAS_FMT
- "phy_control - function_result(%d)\n",
- ioc->name, phy_control_reply->function_result));
+ dtransportprintk(ioc,
+ ioc_info(ioc, "phy_control - function_result(%d)\n",
+ phy_control_reply->function_result));
rc = 0;
} else
- dtransportprintk(ioc, pr_info(MPT3SAS_FMT
- "phy_control - no reply\n", ioc->name));
+ dtransportprintk(ioc,
+ ioc_info(ioc, "phy_control - no reply\n"));
issue_host_reset:
if (issue_reset)
@@ -1548,7 +1520,8 @@ _transport_expander_phy_control(struct MPT3SAS_ADAPTER *ioc,
out:
ioc->transport_cmds.status = MPT3_CMD_NOT_USED;
if (data_out)
- pci_free_consistent(ioc->pdev, sz, data_out, data_out_dma);
+ dma_free_coherent(&ioc->pdev->dev, sz, data_out,
+ data_out_dma);
mutex_unlock(&ioc->transport_cmds.mutex);
return rc;
@@ -1591,16 +1564,15 @@ _transport_phy_reset(struct sas_phy *phy, int hard_reset)
mpi_request.PhyNum = phy->number;
if ((mpt3sas_base_sas_iounit_control(ioc, &mpi_reply, &mpi_request))) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
return -ENXIO;
}
if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo)
- pr_info(MPT3SAS_FMT
- "phy(%d), ioc_status(0x%04x), loginfo(0x%08x)\n",
- ioc->name, phy->number, le16_to_cpu(mpi_reply.IOCStatus),
- le32_to_cpu(mpi_reply.IOCLogInfo));
+ ioc_info(ioc, "phy(%d), ioc_status(0x%04x), loginfo(0x%08x)\n",
+ phy->number, le16_to_cpu(mpi_reply.IOCStatus),
+ le32_to_cpu(mpi_reply.IOCLogInfo));
return 0;
}
@@ -1647,23 +1619,23 @@ _transport_phy_enable(struct sas_phy *phy, int enable)
sizeof(Mpi2SasIOUnit0PhyData_t));
sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
if (!sas_iounit_pg0) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
rc = -ENOMEM;
goto out;
}
if ((mpt3sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
sas_iounit_pg0, sz))) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
rc = -ENXIO;
goto out;
}
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
MPI2_IOCSTATUS_MASK;
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
rc = -EIO;
goto out;
}
@@ -1672,10 +1644,8 @@ _transport_phy_enable(struct sas_phy *phy, int enable)
for (i = 0, discovery_active = 0; i < ioc->sas_hba.num_phys ; i++) {
if (sas_iounit_pg0->PhyData[i].PortFlags &
MPI2_SASIOUNIT0_PORTFLAGS_DISCOVERY_IN_PROGRESS) {
- pr_err(MPT3SAS_FMT "discovery is active on " \
- "port = %d, phy = %d: unable to enable/disable "
- "phys, try again later!\n", ioc->name,
- sas_iounit_pg0->PhyData[i].Port, i);
+ ioc_err(ioc, "discovery is active on port = %d, phy = %d: unable to enable/disable phys, try again later!\n",
+ sas_iounit_pg0->PhyData[i].Port, i);
discovery_active = 1;
}
}
@@ -1690,23 +1660,23 @@ _transport_phy_enable(struct sas_phy *phy, int enable)
sizeof(Mpi2SasIOUnit1PhyData_t));
sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
if (!sas_iounit_pg1) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
rc = -ENOMEM;
goto out;
}
if ((mpt3sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
sas_iounit_pg1, sz))) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
rc = -ENXIO;
goto out;
}
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
MPI2_IOCSTATUS_MASK;
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
rc = -EIO;
goto out;
}
@@ -1798,23 +1768,23 @@ _transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)
sizeof(Mpi2SasIOUnit1PhyData_t));
sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
if (!sas_iounit_pg1) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
rc = -ENOMEM;
goto out;
}
if ((mpt3sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
sas_iounit_pg1, sz))) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
rc = -ENXIO;
goto out;
}
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
MPI2_IOCSTATUS_MASK;
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
rc = -EIO;
goto out;
}
@@ -1833,8 +1803,8 @@ _transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)
if (mpt3sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1,
sz)) {
- pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
+ ioc_err(ioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
rc = -ENXIO;
goto out;
}
@@ -1922,8 +1892,7 @@ _transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
unsigned int reslen = 0;
if (ioc->shost_recovery || ioc->pci_error_recovery) {
- pr_info(MPT3SAS_FMT "%s: host reset in progress!\n",
- __func__, ioc->name);
+ ioc_info(ioc, "%s: host reset in progress!\n", __func__);
rc = -EFAULT;
goto job_done;
}
@@ -1933,8 +1902,8 @@ _transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
goto job_done;
if (ioc->transport_cmds.status != MPT3_CMD_NOT_USED) {
- pr_err(MPT3SAS_FMT "%s: transport_cmds in use\n", ioc->name,
- __func__);
+ ioc_err(ioc, "%s: transport_cmds in use\n",
+ __func__);
rc = -EAGAIN;
goto out;
}
@@ -1959,26 +1928,22 @@ _transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
ioc_state = mpt3sas_base_get_iocstate(ioc, 1);
while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
if (wait_state_count++ == 10) {
- pr_err(MPT3SAS_FMT
- "%s: failed due to ioc not operational\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: failed due to ioc not operational\n",
+ __func__);
rc = -EFAULT;
goto unmap_in;
}
ssleep(1);
ioc_state = mpt3sas_base_get_iocstate(ioc, 1);
- pr_info(MPT3SAS_FMT
- "%s: waiting for operational state(count=%d)\n",
- ioc->name, __func__, wait_state_count);
+ ioc_info(ioc, "%s: waiting for operational state(count=%d)\n",
+ __func__, wait_state_count);
}
if (wait_state_count)
- pr_info(MPT3SAS_FMT "%s: ioc is operational\n",
- ioc->name, __func__);
+ ioc_info(ioc, "%s: ioc is operational\n", __func__);
smid = mpt3sas_base_get_smid(ioc, ioc->transport_cb_idx);
if (!smid) {
- pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
+ ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);
rc = -EAGAIN;
goto unmap_in;
}
@@ -1999,16 +1964,15 @@ _transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
ioc->build_sg(ioc, psge, dma_addr_out, dma_len_out - 4, dma_addr_in,
dma_len_in - 4);
- dtransportprintk(ioc, pr_info(MPT3SAS_FMT
- "%s - sending smp request\n", ioc->name, __func__));
+ dtransportprintk(ioc,
+ ioc_info(ioc, "%s: sending smp request\n", __func__));
init_completion(&ioc->transport_cmds.done);
mpt3sas_base_put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ);
if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) {
- pr_err(MPT3SAS_FMT "%s : timeout\n",
- __func__, ioc->name);
+ ioc_err(ioc, "%s: timeout\n", __func__);
_debug_dump_mf(mpi_request,
sizeof(Mpi2SmpPassthroughRequest_t)/4);
if (!(ioc->transport_cmds.status & MPT3_CMD_RESET)) {
@@ -2018,12 +1982,11 @@ _transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
}
}
- dtransportprintk(ioc, pr_info(MPT3SAS_FMT
- "%s - complete\n", ioc->name, __func__));
+ dtransportprintk(ioc, ioc_info(ioc, "%s - complete\n", __func__));
if (!(ioc->transport_cmds.status & MPT3_CMD_REPLY_VALID)) {
- dtransportprintk(ioc, pr_info(MPT3SAS_FMT
- "%s - no reply\n", ioc->name, __func__));
+ dtransportprintk(ioc,
+ ioc_info(ioc, "%s: no reply\n", __func__));
rc = -ENXIO;
goto unmap_in;
}
@@ -2031,9 +1994,9 @@ _transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
mpi_reply = ioc->transport_cmds.reply;
dtransportprintk(ioc,
- pr_info(MPT3SAS_FMT "%s - reply data transfer size(%d)\n",
- ioc->name, __func__,
- le16_to_cpu(mpi_reply->ResponseDataLength)));
+ ioc_info(ioc, "%s: reply data transfer size(%d)\n",
+ __func__,
+ le16_to_cpu(mpi_reply->ResponseDataLength)));
memcpy(job->reply, mpi_reply, sizeof(*mpi_reply));
job->reply_len = sizeof(*mpi_reply);
diff --git a/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c b/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c
index cae7c1eaef34..6ac453fd5937 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c
@@ -72,8 +72,7 @@ _mpt3sas_raise_sigio(struct MPT3SAS_ADAPTER *ioc,
u16 sz, event_data_sz;
unsigned long flags;
- dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: enter\n",
- ioc->name, __func__));
+ dTriggerDiagPrintk(ioc, ioc_info(ioc, "%s: enter\n", __func__));
sz = offsetof(Mpi2EventNotificationReply_t, EventData) +
sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T) + 4;
@@ -85,23 +84,23 @@ _mpt3sas_raise_sigio(struct MPT3SAS_ADAPTER *ioc,
mpi_reply->EventDataLength = cpu_to_le16(event_data_sz);
memcpy(&mpi_reply->EventData, event_data,
sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T));
- dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT
- "%s: add to driver event log\n",
- ioc->name, __func__));
+ dTriggerDiagPrintk(ioc,
+ ioc_info(ioc, "%s: add to driver event log\n",
+ __func__));
mpt3sas_ctl_add_to_event_log(ioc, mpi_reply);
kfree(mpi_reply);
out:
/* clearing the diag_trigger_active flag */
spin_lock_irqsave(&ioc->diag_trigger_lock, flags);
- dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT
- "%s: clearing diag_trigger_active flag\n",
- ioc->name, __func__));
+ dTriggerDiagPrintk(ioc,
+ ioc_info(ioc, "%s: clearing diag_trigger_active flag\n",
+ __func__));
ioc->diag_trigger_active = 0;
spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
- dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name,
- __func__));
+ dTriggerDiagPrintk(ioc, ioc_info(ioc, "%s: exit\n",
+ __func__));
}
/**
@@ -115,22 +114,22 @@ mpt3sas_process_trigger_data(struct MPT3SAS_ADAPTER *ioc,
{
u8 issue_reset = 0;
- dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: enter\n",
- ioc->name, __func__));
+ dTriggerDiagPrintk(ioc, ioc_info(ioc, "%s: enter\n", __func__));
/* release the diag buffer trace */
if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
MPT3_DIAG_BUFFER_IS_RELEASED) == 0) {
- dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT
- "%s: release trace diag buffer\n", ioc->name, __func__));
+ dTriggerDiagPrintk(ioc,
+ ioc_info(ioc, "%s: release trace diag buffer\n",
+ __func__));
mpt3sas_send_diag_release(ioc, MPI2_DIAG_BUF_TYPE_TRACE,
&issue_reset);
}
_mpt3sas_raise_sigio(ioc, event_data);
- dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name,
- __func__));
+ dTriggerDiagPrintk(ioc, ioc_info(ioc, "%s: exit\n",
+ __func__));
}
/**
@@ -168,9 +167,9 @@ mpt3sas_trigger_master(struct MPT3SAS_ADAPTER *ioc, u32 trigger_bitmask)
by_pass_checks:
- dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT
- "%s: enter - trigger_bitmask = 0x%08x\n",
- ioc->name, __func__, trigger_bitmask));
+ dTriggerDiagPrintk(ioc,
+ ioc_info(ioc, "%s: enter - trigger_bitmask = 0x%08x\n",
+ __func__, trigger_bitmask));
/* don't send trigger if an trigger is currently active */
if (ioc->diag_trigger_active) {
@@ -182,9 +181,9 @@ mpt3sas_trigger_master(struct MPT3SAS_ADAPTER *ioc, u32 trigger_bitmask)
if (ioc->diag_trigger_master.MasterData & trigger_bitmask) {
found_match = 1;
ioc->diag_trigger_active = 1;
- dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT
- "%s: setting diag_trigger_active flag\n",
- ioc->name, __func__));
+ dTriggerDiagPrintk(ioc,
+ ioc_info(ioc, "%s: setting diag_trigger_active flag\n",
+ __func__));
}
spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
@@ -202,8 +201,8 @@ mpt3sas_trigger_master(struct MPT3SAS_ADAPTER *ioc, u32 trigger_bitmask)
mpt3sas_send_trigger_data_event(ioc, &event_data);
out:
- dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name,
- __func__));
+ dTriggerDiagPrintk(ioc, ioc_info(ioc, "%s: exit\n",
+ __func__));
}
/**
@@ -239,9 +238,9 @@ mpt3sas_trigger_event(struct MPT3SAS_ADAPTER *ioc, u16 event,
return;
}
- dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT
- "%s: enter - event = 0x%04x, log_entry_qualifier = 0x%04x\n",
- ioc->name, __func__, event, log_entry_qualifier));
+ dTriggerDiagPrintk(ioc,
+ ioc_info(ioc, "%s: enter - event = 0x%04x, log_entry_qualifier = 0x%04x\n",
+ __func__, event, log_entry_qualifier));
/* don't send trigger if an trigger is currently active */
if (ioc->diag_trigger_active) {
@@ -263,26 +262,26 @@ mpt3sas_trigger_event(struct MPT3SAS_ADAPTER *ioc, u16 event,
}
found_match = 1;
ioc->diag_trigger_active = 1;
- dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT
- "%s: setting diag_trigger_active flag\n",
- ioc->name, __func__));
+ dTriggerDiagPrintk(ioc,
+ ioc_info(ioc, "%s: setting diag_trigger_active flag\n",
+ __func__));
}
spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
if (!found_match)
goto out;
- dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT
- "%s: setting diag_trigger_active flag\n",
- ioc->name, __func__));
+ dTriggerDiagPrintk(ioc,
+ ioc_info(ioc, "%s: setting diag_trigger_active flag\n",
+ __func__));
memset(&event_data, 0, sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T));
event_data.trigger_type = MPT3SAS_TRIGGER_EVENT;
event_data.u.event.EventValue = event;
event_data.u.event.LogEntryQualifier = log_entry_qualifier;
mpt3sas_send_trigger_data_event(ioc, &event_data);
out:
- dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name,
- __func__));
+ dTriggerDiagPrintk(ioc, ioc_info(ioc, "%s: exit\n",
+ __func__));
}
/**
@@ -319,9 +318,9 @@ mpt3sas_trigger_scsi(struct MPT3SAS_ADAPTER *ioc, u8 sense_key, u8 asc,
return;
}
- dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT
- "%s: enter - sense_key = 0x%02x, asc = 0x%02x, ascq = 0x%02x\n",
- ioc->name, __func__, sense_key, asc, ascq));
+ dTriggerDiagPrintk(ioc,
+ ioc_info(ioc, "%s: enter - sense_key = 0x%02x, asc = 0x%02x, ascq = 0x%02x\n",
+ __func__, sense_key, asc, ascq));
/* don't send trigger if an trigger is currently active */
if (ioc->diag_trigger_active) {
@@ -347,9 +346,9 @@ mpt3sas_trigger_scsi(struct MPT3SAS_ADAPTER *ioc, u8 sense_key, u8 asc,
if (!found_match)
goto out;
- dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT
- "%s: setting diag_trigger_active flag\n",
- ioc->name, __func__));
+ dTriggerDiagPrintk(ioc,
+ ioc_info(ioc, "%s: setting diag_trigger_active flag\n",
+ __func__));
memset(&event_data, 0, sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T));
event_data.trigger_type = MPT3SAS_TRIGGER_SCSI;
event_data.u.scsi.SenseKey = sense_key;
@@ -357,8 +356,8 @@ mpt3sas_trigger_scsi(struct MPT3SAS_ADAPTER *ioc, u8 sense_key, u8 asc,
event_data.u.scsi.ASCQ = ascq;
mpt3sas_send_trigger_data_event(ioc, &event_data);
out:
- dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name,
- __func__));
+ dTriggerDiagPrintk(ioc, ioc_info(ioc, "%s: exit\n",
+ __func__));
}
/**
@@ -393,9 +392,9 @@ mpt3sas_trigger_mpi(struct MPT3SAS_ADAPTER *ioc, u16 ioc_status, u32 loginfo)
return;
}
- dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT
- "%s: enter - ioc_status = 0x%04x, loginfo = 0x%08x\n",
- ioc->name, __func__, ioc_status, loginfo));
+ dTriggerDiagPrintk(ioc,
+ ioc_info(ioc, "%s: enter - ioc_status = 0x%04x, loginfo = 0x%08x\n",
+ __func__, ioc_status, loginfo));
/* don't send trigger if an trigger is currently active */
if (ioc->diag_trigger_active) {
@@ -420,15 +419,15 @@ mpt3sas_trigger_mpi(struct MPT3SAS_ADAPTER *ioc, u16 ioc_status, u32 loginfo)
if (!found_match)
goto out;
- dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT
- "%s: setting diag_trigger_active flag\n",
- ioc->name, __func__));
+ dTriggerDiagPrintk(ioc,
+ ioc_info(ioc, "%s: setting diag_trigger_active flag\n",
+ __func__));
memset(&event_data, 0, sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T));
event_data.trigger_type = MPT3SAS_TRIGGER_MPI;
event_data.u.mpi.IOCStatus = ioc_status;
event_data.u.mpi.IocLogInfo = loginfo;
mpt3sas_send_trigger_data_event(ioc, &event_data);
out:
- dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name,
- __func__));
+ dTriggerDiagPrintk(ioc, ioc_info(ioc, "%s: exit\n",
+ __func__));
}
diff --git a/drivers/scsi/mpt3sas/mpt3sas_warpdrive.c b/drivers/scsi/mpt3sas/mpt3sas_warpdrive.c
index b4927f2b7677..cc07ba41f507 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_warpdrive.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_warpdrive.c
@@ -127,20 +127,17 @@ mpt3sas_init_warpdrive_properties(struct MPT3SAS_ADAPTER *ioc,
return;
if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_EXPOSE_ALL_DISKS) {
- pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
- "globally as drives are exposed\n", ioc->name);
+ ioc_info(ioc, "WarpDrive : Direct IO is disabled globally as drives are exposed\n");
return;
}
if (mpt3sas_get_num_volumes(ioc) > 1) {
_warpdrive_disable_ddio(ioc);
- pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
- "globally as number of drives > 1\n", ioc->name);
+ ioc_info(ioc, "WarpDrive : Direct IO is disabled globally as number of drives > 1\n");
return;
}
if ((mpt3sas_config_get_number_pds(ioc, raid_device->handle,
&num_pds)) || !num_pds) {
- pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
- "Failure in computing number of drives\n", ioc->name);
+ ioc_info(ioc, "WarpDrive : Direct IO is disabled Failure in computing number of drives\n");
return;
}
@@ -148,15 +145,13 @@ mpt3sas_init_warpdrive_properties(struct MPT3SAS_ADAPTER *ioc,
sizeof(Mpi2RaidVol0PhysDisk_t));
vol_pg0 = kzalloc(sz, GFP_KERNEL);
if (!vol_pg0) {
- pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
- "Memory allocation failure for RVPG0\n", ioc->name);
+ ioc_info(ioc, "WarpDrive : Direct IO is disabled Memory allocation failure for RVPG0\n");
return;
}
if ((mpt3sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0,
MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) {
- pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
- "Failure in retrieving RVPG0\n", ioc->name);
+ ioc_info(ioc, "WarpDrive : Direct IO is disabled Failure in retrieving RVPG0\n");
kfree(vol_pg0);
return;
}
@@ -166,10 +161,8 @@ mpt3sas_init_warpdrive_properties(struct MPT3SAS_ADAPTER *ioc,
* assumed for WARPDRIVE, disable direct I/O
*/
if (num_pds > MPT_MAX_WARPDRIVE_PDS) {
- pr_warn(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
- "for the drive with handle(0x%04x): num_mem=%d, "
- "max_mem_allowed=%d\n", ioc->name, raid_device->handle,
- num_pds, MPT_MAX_WARPDRIVE_PDS);
+ ioc_warn(ioc, "WarpDrive : Direct IO is disabled for the drive with handle(0x%04x): num_mem=%d, max_mem_allowed=%d\n",
+ raid_device->handle, num_pds, MPT_MAX_WARPDRIVE_PDS);
kfree(vol_pg0);
return;
}
@@ -179,22 +172,18 @@ mpt3sas_init_warpdrive_properties(struct MPT3SAS_ADAPTER *ioc,
vol_pg0->PhysDisk[count].PhysDiskNum) ||
le16_to_cpu(pd_pg0.DevHandle) ==
MPT3SAS_INVALID_DEVICE_HANDLE) {
- pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is "
- "disabled for the drive with handle(0x%04x) member"
- "handle retrieval failed for member number=%d\n",
- ioc->name, raid_device->handle,
- vol_pg0->PhysDisk[count].PhysDiskNum);
+ ioc_info(ioc, "WarpDrive : Direct IO is disabled for the drive with handle(0x%04x) member handle retrieval failed for member number=%d\n",
+ raid_device->handle,
+ vol_pg0->PhysDisk[count].PhysDiskNum);
goto out_error;
}
/* Disable direct I/O if member drive lba exceeds 4 bytes */
dev_max_lba = le64_to_cpu(pd_pg0.DeviceMaxLBA);
if (dev_max_lba >> 32) {
- pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is "
- "disabled for the drive with handle(0x%04x) member"
- " handle (0x%04x) unsupported max lba 0x%016llx\n",
- ioc->name, raid_device->handle,
- le16_to_cpu(pd_pg0.DevHandle),
- (unsigned long long)dev_max_lba);
+ ioc_info(ioc, "WarpDrive : Direct IO is disabled for the drive with handle(0x%04x) member handle (0x%04x) unsupported max lba 0x%016llx\n",
+ raid_device->handle,
+ le16_to_cpu(pd_pg0.DevHandle),
+ (u64)dev_max_lba);
goto out_error;
}
@@ -206,41 +195,36 @@ mpt3sas_init_warpdrive_properties(struct MPT3SAS_ADAPTER *ioc,
* not RAID0
*/
if (raid_device->volume_type != MPI2_RAID_VOL_TYPE_RAID0) {
- pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
- "for the drive with handle(0x%04x): type=%d, "
- "s_sz=%uK, blk_size=%u\n", ioc->name,
- raid_device->handle, raid_device->volume_type,
- (le32_to_cpu(vol_pg0->StripeSize) *
- le16_to_cpu(vol_pg0->BlockSize)) / 1024,
- le16_to_cpu(vol_pg0->BlockSize));
+ ioc_info(ioc, "WarpDrive : Direct IO is disabled for the drive with handle(0x%04x): type=%d, s_sz=%uK, blk_size=%u\n",
+ raid_device->handle, raid_device->volume_type,
+ (le32_to_cpu(vol_pg0->StripeSize) *
+ le16_to_cpu(vol_pg0->BlockSize)) / 1024,
+ le16_to_cpu(vol_pg0->BlockSize));
goto out_error;
}
stripe_sz = le32_to_cpu(vol_pg0->StripeSize);
stripe_exp = find_first_bit(&stripe_sz, 32);
if (stripe_exp == 32) {
- pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
- "for the drive with handle(0x%04x) invalid stripe sz %uK\n",
- ioc->name, raid_device->handle,
- (le32_to_cpu(vol_pg0->StripeSize) *
- le16_to_cpu(vol_pg0->BlockSize)) / 1024);
+ ioc_info(ioc, "WarpDrive : Direct IO is disabled for the drive with handle(0x%04x) invalid stripe sz %uK\n",
+ raid_device->handle,
+ (le32_to_cpu(vol_pg0->StripeSize) *
+ le16_to_cpu(vol_pg0->BlockSize)) / 1024);
goto out_error;
}
raid_device->stripe_exponent = stripe_exp;
block_sz = le16_to_cpu(vol_pg0->BlockSize);
block_exp = find_first_bit(&block_sz, 16);
if (block_exp == 16) {
- pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
- "for the drive with handle(0x%04x) invalid block sz %u\n",
- ioc->name, raid_device->handle,
- le16_to_cpu(vol_pg0->BlockSize));
+ ioc_info(ioc, "WarpDrive : Direct IO is disabled for the drive with handle(0x%04x) invalid block sz %u\n",
+ raid_device->handle, le16_to_cpu(vol_pg0->BlockSize));
goto out_error;
}
raid_device->block_exponent = block_exp;
raid_device->direct_io_enabled = 1;
- pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is Enabled for the drive"
- " with handle(0x%04x)\n", ioc->name, raid_device->handle);
+ ioc_info(ioc, "WarpDrive : Direct IO is Enabled for the drive with handle(0x%04x)\n",
+ raid_device->handle);
/*
* WARPDRIVE: Though the following fields are not used for direct IO,
* stored for future purpose:
diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c
index 8c91637cd598..3ac34373746c 100644
--- a/drivers/scsi/mvsas/mv_init.c
+++ b/drivers/scsi/mvsas/mv_init.c
@@ -403,29 +403,14 @@ static int pci_go_64(struct pci_dev *pdev)
{
int rc;
- if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
- rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
- if (rc) {
- rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
- if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "64-bit DMA enable failed\n");
- return rc;
- }
- }
- } else {
- rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+ if (rc) {
+ rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
if (rc) {
dev_printk(KERN_ERR, &pdev->dev,
"32-bit DMA enable failed\n");
return rc;
}
- rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
- if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "32-bit consistent DMA enable failed\n");
- return rc;
- }
}
return rc;
diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c
index cff43bd9f675..311d23c727ce 100644
--- a/drivers/scsi/mvsas/mv_sas.c
+++ b/drivers/scsi/mvsas/mv_sas.c
@@ -336,13 +336,13 @@ static int mvs_task_prep_smp(struct mvs_info *mvi,
* DMA-map SMP request, response buffers
*/
sg_req = &task->smp_task.smp_req;
- elem = dma_map_sg(mvi->dev, sg_req, 1, PCI_DMA_TODEVICE);
+ elem = dma_map_sg(mvi->dev, sg_req, 1, DMA_TO_DEVICE);
if (!elem)
return -ENOMEM;
req_len = sg_dma_len(sg_req);
sg_resp = &task->smp_task.smp_resp;
- elem = dma_map_sg(mvi->dev, sg_resp, 1, PCI_DMA_FROMDEVICE);
+ elem = dma_map_sg(mvi->dev, sg_resp, 1, DMA_FROM_DEVICE);
if (!elem) {
rc = -ENOMEM;
goto err_out;
@@ -416,10 +416,10 @@ static int mvs_task_prep_smp(struct mvs_info *mvi,
err_out_2:
dma_unmap_sg(mvi->dev, &tei->task->smp_task.smp_resp, 1,
- PCI_DMA_FROMDEVICE);
+ DMA_FROM_DEVICE);
err_out:
dma_unmap_sg(mvi->dev, &tei->task->smp_task.smp_req, 1,
- PCI_DMA_TODEVICE);
+ DMA_TO_DEVICE);
return rc;
}
@@ -790,12 +790,11 @@ static int mvs_task_prep(struct sas_task *task, struct mvs_info *mvi, int is_tmf
slot->n_elem = n_elem;
slot->slot_tag = tag;
- slot->buf = dma_pool_alloc(mvi->dma_pool, GFP_ATOMIC, &slot->buf_dma);
+ slot->buf = dma_pool_zalloc(mvi->dma_pool, GFP_ATOMIC, &slot->buf_dma);
if (!slot->buf) {
rc = -ENOMEM;
goto err_out_tag;
}
- memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
tei.task = task;
tei.hdr = &mvi->slot[tag];
@@ -904,9 +903,9 @@ static void mvs_slot_task_free(struct mvs_info *mvi, struct sas_task *task,
switch (task->task_proto) {
case SAS_PROTOCOL_SMP:
dma_unmap_sg(mvi->dev, &task->smp_task.smp_resp, 1,
- PCI_DMA_FROMDEVICE);
+ DMA_FROM_DEVICE);
dma_unmap_sg(mvi->dev, &task->smp_task.smp_req, 1,
- PCI_DMA_TODEVICE);
+ DMA_TO_DEVICE);
break;
case SAS_PROTOCOL_SATA:
@@ -1906,8 +1905,7 @@ static void mvs_work_queue(struct work_struct *work)
if (phy->phy_event & PHY_PLUG_OUT) {
u32 tmp;
- struct sas_identify_frame *id;
- id = (struct sas_identify_frame *)phy->frame_rcvd;
+
tmp = MVS_CHIP_DISP->read_phy_ctl(mvi, phy_no);
phy->phy_event &= ~PHY_PLUG_OUT;
if (!(tmp & PHY_READY_MASK)) {
diff --git a/drivers/scsi/mvumi.c b/drivers/scsi/mvumi.c
index b3cd9a6b1d30..2458974d1af6 100644
--- a/drivers/scsi/mvumi.c
+++ b/drivers/scsi/mvumi.c
@@ -143,8 +143,8 @@ static struct mvumi_res *mvumi_alloc_mem_resource(struct mvumi_hba *mhba,
case RESOURCE_UNCACHED_MEMORY:
size = round_up(size, 8);
- res->virt_addr = pci_zalloc_consistent(mhba->pdev, size,
- &res->bus_addr);
+ res->virt_addr = dma_zalloc_coherent(&mhba->pdev->dev, size,
+ &res->bus_addr, GFP_KERNEL);
if (!res->virt_addr) {
dev_err(&mhba->pdev->dev,
"unable to allocate consistent mem,"
@@ -175,7 +175,7 @@ static void mvumi_release_mem_resource(struct mvumi_hba *mhba)
list_for_each_entry_safe(res, tmp, &mhba->res_list, entry) {
switch (res->type) {
case RESOURCE_UNCACHED_MEMORY:
- pci_free_consistent(mhba->pdev, res->size,
+ dma_free_coherent(&mhba->pdev->dev, res->size,
res->virt_addr, res->bus_addr);
break;
case RESOURCE_CACHED_MEMORY:
@@ -211,14 +211,14 @@ static int mvumi_make_sgl(struct mvumi_hba *mhba, struct scsi_cmnd *scmd,
dma_addr_t busaddr;
sg = scsi_sglist(scmd);
- *sg_count = pci_map_sg(mhba->pdev, sg, sgnum,
- (int) scmd->sc_data_direction);
+ *sg_count = dma_map_sg(&mhba->pdev->dev, sg, sgnum,
+ scmd->sc_data_direction);
if (*sg_count > mhba->max_sge) {
dev_err(&mhba->pdev->dev,
"sg count[0x%x] is bigger than max sg[0x%x].\n",
*sg_count, mhba->max_sge);
- pci_unmap_sg(mhba->pdev, sg, sgnum,
- (int) scmd->sc_data_direction);
+ dma_unmap_sg(&mhba->pdev->dev, sg, sgnum,
+ scmd->sc_data_direction);
return -1;
}
for (i = 0; i < *sg_count; i++) {
@@ -246,7 +246,8 @@ static int mvumi_internal_cmd_sgl(struct mvumi_hba *mhba, struct mvumi_cmd *cmd,
if (size == 0)
return 0;
- virt_addr = pci_zalloc_consistent(mhba->pdev, size, &phy_addr);
+ virt_addr = dma_zalloc_coherent(&mhba->pdev->dev, size, &phy_addr,
+ GFP_KERNEL);
if (!virt_addr)
return -1;
@@ -274,8 +275,8 @@ static struct mvumi_cmd *mvumi_create_internal_cmd(struct mvumi_hba *mhba,
}
INIT_LIST_HEAD(&cmd->queue_pointer);
- cmd->frame = pci_alloc_consistent(mhba->pdev,
- mhba->ib_max_size, &cmd->frame_phys);
+ cmd->frame = dma_alloc_coherent(&mhba->pdev->dev, mhba->ib_max_size,
+ &cmd->frame_phys, GFP_KERNEL);
if (!cmd->frame) {
dev_err(&mhba->pdev->dev, "failed to allocate memory for FW"
" frame,size = %d.\n", mhba->ib_max_size);
@@ -287,7 +288,7 @@ static struct mvumi_cmd *mvumi_create_internal_cmd(struct mvumi_hba *mhba,
if (mvumi_internal_cmd_sgl(mhba, cmd, buf_size)) {
dev_err(&mhba->pdev->dev, "failed to allocate memory"
" for internal frame\n");
- pci_free_consistent(mhba->pdev, mhba->ib_max_size,
+ dma_free_coherent(&mhba->pdev->dev, mhba->ib_max_size,
cmd->frame, cmd->frame_phys);
kfree(cmd);
return NULL;
@@ -313,10 +314,10 @@ static void mvumi_delete_internal_cmd(struct mvumi_hba *mhba,
phy_addr = (dma_addr_t) m_sg->baseaddr_l |
(dma_addr_t) ((m_sg->baseaddr_h << 16) << 16);
- pci_free_consistent(mhba->pdev, size, cmd->data_buf,
+ dma_free_coherent(&mhba->pdev->dev, size, cmd->data_buf,
phy_addr);
}
- pci_free_consistent(mhba->pdev, mhba->ib_max_size,
+ dma_free_coherent(&mhba->pdev->dev, mhba->ib_max_size,
cmd->frame, cmd->frame_phys);
kfree(cmd);
}
@@ -663,16 +664,17 @@ static void mvumi_restore_bar_addr(struct mvumi_hba *mhba)
}
}
-static unsigned int mvumi_pci_set_master(struct pci_dev *pdev)
+static int mvumi_pci_set_master(struct pci_dev *pdev)
{
- unsigned int ret = 0;
+ int ret = 0;
+
pci_set_master(pdev);
if (IS_DMA64) {
- if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)))
- ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)))
+ ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
} else
- ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
return ret;
}
@@ -771,7 +773,7 @@ static void mvumi_release_fw(struct mvumi_hba *mhba)
mvumi_free_cmds(mhba);
mvumi_release_mem_resource(mhba);
mvumi_unmap_pci_addr(mhba->pdev, mhba->base_addr);
- pci_free_consistent(mhba->pdev, HSP_MAX_SIZE,
+ dma_free_coherent(&mhba->pdev->dev, HSP_MAX_SIZE,
mhba->handshake_page, mhba->handshake_page_phys);
kfree(mhba->regs);
pci_release_regions(mhba->pdev);
@@ -1339,9 +1341,9 @@ static void mvumi_complete_cmd(struct mvumi_hba *mhba, struct mvumi_cmd *cmd,
}
if (scsi_bufflen(scmd))
- pci_unmap_sg(mhba->pdev, scsi_sglist(scmd),
+ dma_unmap_sg(&mhba->pdev->dev, scsi_sglist(scmd),
scsi_sg_count(scmd),
- (int) scmd->sc_data_direction);
+ scmd->sc_data_direction);
cmd->scmd->scsi_done(scmd);
mvumi_return_cmd(mhba, cmd);
}
@@ -2148,9 +2150,9 @@ static enum blk_eh_timer_return mvumi_timed_out(struct scsi_cmnd *scmd)
scmd->result = (DRIVER_INVALID << 24) | (DID_ABORT << 16);
scmd->SCp.ptr = NULL;
if (scsi_bufflen(scmd)) {
- pci_unmap_sg(mhba->pdev, scsi_sglist(scmd),
+ dma_unmap_sg(&mhba->pdev->dev, scsi_sglist(scmd),
scsi_sg_count(scmd),
- (int)scmd->sc_data_direction);
+ scmd->sc_data_direction);
}
mvumi_return_cmd(mhba, cmd);
spin_unlock_irqrestore(mhba->shost->host_lock, flags);
@@ -2362,8 +2364,8 @@ static int mvumi_init_fw(struct mvumi_hba *mhba)
ret = -ENOMEM;
goto fail_alloc_mem;
}
- mhba->handshake_page = pci_alloc_consistent(mhba->pdev, HSP_MAX_SIZE,
- &mhba->handshake_page_phys);
+ mhba->handshake_page = dma_alloc_coherent(&mhba->pdev->dev,
+ HSP_MAX_SIZE, &mhba->handshake_page_phys, GFP_KERNEL);
if (!mhba->handshake_page) {
dev_err(&mhba->pdev->dev,
"failed to allocate memory for handshake\n");
@@ -2383,7 +2385,7 @@ static int mvumi_init_fw(struct mvumi_hba *mhba)
fail_ready_state:
mvumi_release_mem_resource(mhba);
- pci_free_consistent(mhba->pdev, HSP_MAX_SIZE,
+ dma_free_coherent(&mhba->pdev->dev, HSP_MAX_SIZE,
mhba->handshake_page, mhba->handshake_page_phys);
fail_alloc_page:
kfree(mhba->regs);
@@ -2480,20 +2482,9 @@ static int mvumi_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
if (ret)
return ret;
- pci_set_master(pdev);
-
- if (IS_DMA64) {
- ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
- if (ret) {
- ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
- if (ret)
- goto fail_set_dma_mask;
- }
- } else {
- ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
- if (ret)
- goto fail_set_dma_mask;
- }
+ ret = mvumi_pci_set_master(pdev);
+ if (ret)
+ goto fail_set_dma_mask;
host = scsi_host_alloc(&mvumi_template, sizeof(*mhba));
if (!host) {
@@ -2627,19 +2618,11 @@ static int __maybe_unused mvumi_resume(struct pci_dev *pdev)
dev_err(&pdev->dev, "enable device failed\n");
return ret;
}
- pci_set_master(pdev);
- if (IS_DMA64) {
- ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
- if (ret) {
- ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
- if (ret)
- goto fail;
- }
- } else {
- ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
- if (ret)
- goto fail;
- }
+
+ ret = mvumi_pci_set_master(pdev);
+ ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (ret)
+ goto fail;
ret = pci_request_regions(mhba->pdev, MV_DRIVER_NAME);
if (ret)
goto fail;
diff --git a/drivers/scsi/myrb.c b/drivers/scsi/myrb.c
new file mode 100644
index 000000000000..0642f2d0a3bb
--- /dev/null
+++ b/drivers/scsi/myrb.c
@@ -0,0 +1,3657 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers
+ *
+ * Copyright 2017 Hannes Reinecke, SUSE Linux GmbH <hare@suse.com>
+ *
+ * Based on the original DAC960 driver,
+ * Copyright 1998-2001 by Leonard N. Zubkoff <lnz@dandelion.com>
+ * Portions Copyright 2002 by Mylex (An IBM Business Unit)
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/raid_class.h>
+#include <asm/unaligned.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_tcq.h>
+#include "myrb.h"
+
+static struct raid_template *myrb_raid_template;
+
+static void myrb_monitor(struct work_struct *work);
+static inline void myrb_translate_devstate(void *DeviceState);
+
+static inline int myrb_logical_channel(struct Scsi_Host *shost)
+{
+ return shost->max_channel - 1;
+}
+
+static struct myrb_devstate_name_entry {
+ enum myrb_devstate state;
+ const char *name;
+} myrb_devstate_name_list[] = {
+ { MYRB_DEVICE_DEAD, "Dead" },
+ { MYRB_DEVICE_WO, "WriteOnly" },
+ { MYRB_DEVICE_ONLINE, "Online" },
+ { MYRB_DEVICE_CRITICAL, "Critical" },
+ { MYRB_DEVICE_STANDBY, "Standby" },
+ { MYRB_DEVICE_OFFLINE, "Offline" },
+};
+
+static const char *myrb_devstate_name(enum myrb_devstate state)
+{
+ struct myrb_devstate_name_entry *entry = myrb_devstate_name_list;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(myrb_devstate_name_list); i++) {
+ if (entry[i].state == state)
+ return entry[i].name;
+ }
+ return "Unknown";
+}
+
+static struct myrb_raidlevel_name_entry {
+ enum myrb_raidlevel level;
+ const char *name;
+} myrb_raidlevel_name_list[] = {
+ { MYRB_RAID_LEVEL0, "RAID0" },
+ { MYRB_RAID_LEVEL1, "RAID1" },
+ { MYRB_RAID_LEVEL3, "RAID3" },
+ { MYRB_RAID_LEVEL5, "RAID5" },
+ { MYRB_RAID_LEVEL6, "RAID6" },
+ { MYRB_RAID_JBOD, "JBOD" },
+};
+
+static const char *myrb_raidlevel_name(enum myrb_raidlevel level)
+{
+ struct myrb_raidlevel_name_entry *entry = myrb_raidlevel_name_list;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(myrb_raidlevel_name_list); i++) {
+ if (entry[i].level == level)
+ return entry[i].name;
+ }
+ return NULL;
+}
+
+/**
+ * myrb_create_mempools - allocates auxiliary data structures
+ *
+ * Return: true on success, false otherwise.
+ */
+static bool myrb_create_mempools(struct pci_dev *pdev, struct myrb_hba *cb)
+{
+ size_t elem_size, elem_align;
+
+ elem_align = sizeof(struct myrb_sge);
+ elem_size = cb->host->sg_tablesize * elem_align;
+ cb->sg_pool = dma_pool_create("myrb_sg", &pdev->dev,
+ elem_size, elem_align, 0);
+ if (cb->sg_pool == NULL) {
+ shost_printk(KERN_ERR, cb->host,
+ "Failed to allocate SG pool\n");
+ return false;
+ }
+
+ cb->dcdb_pool = dma_pool_create("myrb_dcdb", &pdev->dev,
+ sizeof(struct myrb_dcdb),
+ sizeof(unsigned int), 0);
+ if (!cb->dcdb_pool) {
+ dma_pool_destroy(cb->sg_pool);
+ cb->sg_pool = NULL;
+ shost_printk(KERN_ERR, cb->host,
+ "Failed to allocate DCDB pool\n");
+ return false;
+ }
+
+ snprintf(cb->work_q_name, sizeof(cb->work_q_name),
+ "myrb_wq_%d", cb->host->host_no);
+ cb->work_q = create_singlethread_workqueue(cb->work_q_name);
+ if (!cb->work_q) {
+ dma_pool_destroy(cb->dcdb_pool);
+ cb->dcdb_pool = NULL;
+ dma_pool_destroy(cb->sg_pool);
+ cb->sg_pool = NULL;
+ shost_printk(KERN_ERR, cb->host,
+ "Failed to create workqueue\n");
+ return false;
+ }
+
+ /*
+ * Initialize the Monitoring Timer.
+ */
+ INIT_DELAYED_WORK(&cb->monitor_work, myrb_monitor);
+ queue_delayed_work(cb->work_q, &cb->monitor_work, 1);
+
+ return true;
+}
+
+/**
+ * myrb_destroy_mempools - tears down the memory pools for the controller
+ */
+static void myrb_destroy_mempools(struct myrb_hba *cb)
+{
+ cancel_delayed_work_sync(&cb->monitor_work);
+ destroy_workqueue(cb->work_q);
+
+ dma_pool_destroy(cb->sg_pool);
+ dma_pool_destroy(cb->dcdb_pool);
+}
+
+/**
+ * myrb_reset_cmd - reset command block
+ */
+static inline void myrb_reset_cmd(struct myrb_cmdblk *cmd_blk)
+{
+ union myrb_cmd_mbox *mbox = &cmd_blk->mbox;
+
+ memset(mbox, 0, sizeof(union myrb_cmd_mbox));
+ cmd_blk->status = 0;
+}
+
+/**
+ * myrb_qcmd - queues command block for execution
+ */
+static void myrb_qcmd(struct myrb_hba *cb, struct myrb_cmdblk *cmd_blk)
+{
+ void __iomem *base = cb->io_base;
+ union myrb_cmd_mbox *mbox = &cmd_blk->mbox;
+ union myrb_cmd_mbox *next_mbox = cb->next_cmd_mbox;
+
+ cb->write_cmd_mbox(next_mbox, mbox);
+ if (cb->prev_cmd_mbox1->words[0] == 0 ||
+ cb->prev_cmd_mbox2->words[0] == 0)
+ cb->get_cmd_mbox(base);
+ cb->prev_cmd_mbox2 = cb->prev_cmd_mbox1;
+ cb->prev_cmd_mbox1 = next_mbox;
+ if (++next_mbox > cb->last_cmd_mbox)
+ next_mbox = cb->first_cmd_mbox;
+ cb->next_cmd_mbox = next_mbox;
+}
+
+/**
+ * myrb_exec_cmd - executes command block and waits for completion.
+ *
+ * Return: command status
+ */
+static unsigned short myrb_exec_cmd(struct myrb_hba *cb,
+ struct myrb_cmdblk *cmd_blk)
+{
+ DECLARE_COMPLETION_ONSTACK(cmpl);
+ unsigned long flags;
+
+ cmd_blk->completion = &cmpl;
+
+ spin_lock_irqsave(&cb->queue_lock, flags);
+ cb->qcmd(cb, cmd_blk);
+ spin_unlock_irqrestore(&cb->queue_lock, flags);
+
+ WARN_ON(in_interrupt());
+ wait_for_completion(&cmpl);
+ return cmd_blk->status;
+}
+
+/**
+ * myrb_exec_type3 - executes a type 3 command and waits for completion.
+ *
+ * Return: command status
+ */
+static unsigned short myrb_exec_type3(struct myrb_hba *cb,
+ enum myrb_cmd_opcode op, dma_addr_t addr)
+{
+ struct myrb_cmdblk *cmd_blk = &cb->dcmd_blk;
+ union myrb_cmd_mbox *mbox = &cmd_blk->mbox;
+ unsigned short status;
+
+ mutex_lock(&cb->dcmd_mutex);
+ myrb_reset_cmd(cmd_blk);
+ mbox->type3.id = MYRB_DCMD_TAG;
+ mbox->type3.opcode = op;
+ mbox->type3.addr = addr;
+ status = myrb_exec_cmd(cb, cmd_blk);
+ mutex_unlock(&cb->dcmd_mutex);
+ return status;
+}
+
+/**
+ * myrb_exec_type3D - executes a type 3D command and waits for completion.
+ *
+ * Return: command status
+ */
+static unsigned short myrb_exec_type3D(struct myrb_hba *cb,
+ enum myrb_cmd_opcode op, struct scsi_device *sdev,
+ struct myrb_pdev_state *pdev_info)
+{
+ struct myrb_cmdblk *cmd_blk = &cb->dcmd_blk;
+ union myrb_cmd_mbox *mbox = &cmd_blk->mbox;
+ unsigned short status;
+ dma_addr_t pdev_info_addr;
+
+ pdev_info_addr = dma_map_single(&cb->pdev->dev, pdev_info,
+ sizeof(struct myrb_pdev_state),
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(&cb->pdev->dev, pdev_info_addr))
+ return MYRB_STATUS_SUBSYS_FAILED;
+
+ mutex_lock(&cb->dcmd_mutex);
+ myrb_reset_cmd(cmd_blk);
+ mbox->type3D.id = MYRB_DCMD_TAG;
+ mbox->type3D.opcode = op;
+ mbox->type3D.channel = sdev->channel;
+ mbox->type3D.target = sdev->id;
+ mbox->type3D.addr = pdev_info_addr;
+ status = myrb_exec_cmd(cb, cmd_blk);
+ mutex_unlock(&cb->dcmd_mutex);
+ dma_unmap_single(&cb->pdev->dev, pdev_info_addr,
+ sizeof(struct myrb_pdev_state), DMA_FROM_DEVICE);
+ if (status == MYRB_STATUS_SUCCESS &&
+ mbox->type3D.opcode == MYRB_CMD_GET_DEVICE_STATE_OLD)
+ myrb_translate_devstate(pdev_info);
+
+ return status;
+}
+
+static char *myrb_event_msg[] = {
+ "killed because write recovery failed",
+ "killed because of SCSI bus reset failure",
+ "killed because of double check condition",
+ "killed because it was removed",
+ "killed because of gross error on SCSI chip",
+ "killed because of bad tag returned from drive",
+ "killed because of timeout on SCSI command",
+ "killed because of reset SCSI command issued from system",
+ "killed because busy or parity error count exceeded limit",
+ "killed because of 'kill drive' command from system",
+ "killed because of selection timeout",
+ "killed due to SCSI phase sequence error",
+ "killed due to unknown status",
+};
+
+/**
+ * myrb_get_event - get event log from HBA
+ * @cb: pointer to the hba structure
+ * @event: number of the event
+ *
+ * Execute a type 3E command and logs the event message
+ */
+static void myrb_get_event(struct myrb_hba *cb, unsigned int event)
+{
+ struct myrb_cmdblk *cmd_blk = &cb->mcmd_blk;
+ union myrb_cmd_mbox *mbox = &cmd_blk->mbox;
+ struct myrb_log_entry *ev_buf;
+ dma_addr_t ev_addr;
+ unsigned short status;
+
+ ev_buf = dma_alloc_coherent(&cb->pdev->dev,
+ sizeof(struct myrb_log_entry),
+ &ev_addr, GFP_KERNEL);
+ if (!ev_buf)
+ return;
+
+ myrb_reset_cmd(cmd_blk);
+ mbox->type3E.id = MYRB_MCMD_TAG;
+ mbox->type3E.opcode = MYRB_CMD_EVENT_LOG_OPERATION;
+ mbox->type3E.optype = DAC960_V1_GetEventLogEntry;
+ mbox->type3E.opqual = 1;
+ mbox->type3E.ev_seq = event;
+ mbox->type3E.addr = ev_addr;
+ status = myrb_exec_cmd(cb, cmd_blk);
+ if (status != MYRB_STATUS_SUCCESS)
+ shost_printk(KERN_INFO, cb->host,
+ "Failed to get event log %d, status %04x\n",
+ event, status);
+
+ else if (ev_buf->seq_num == event) {
+ struct scsi_sense_hdr sshdr;
+
+ memset(&sshdr, 0, sizeof(sshdr));
+ scsi_normalize_sense(ev_buf->sense, 32, &sshdr);
+
+ if (sshdr.sense_key == VENDOR_SPECIFIC &&
+ sshdr.asc == 0x80 &&
+ sshdr.ascq < ARRAY_SIZE(myrb_event_msg))
+ shost_printk(KERN_CRIT, cb->host,
+ "Physical drive %d:%d: %s\n",
+ ev_buf->channel, ev_buf->target,
+ myrb_event_msg[sshdr.ascq]);
+ else
+ shost_printk(KERN_CRIT, cb->host,
+ "Physical drive %d:%d: Sense: %X/%02X/%02X\n",
+ ev_buf->channel, ev_buf->target,
+ sshdr.sense_key, sshdr.asc, sshdr.ascq);
+ }
+
+ dma_free_coherent(&cb->pdev->dev, sizeof(struct myrb_log_entry),
+ ev_buf, ev_addr);
+}
+
+/**
+ * myrb_get_errtable - retrieves the error table from the controller
+ *
+ * Executes a type 3 command and logs the error table from the controller.
+ */
+static void myrb_get_errtable(struct myrb_hba *cb)
+{
+ struct myrb_cmdblk *cmd_blk = &cb->mcmd_blk;
+ union myrb_cmd_mbox *mbox = &cmd_blk->mbox;
+ unsigned short status;
+ struct myrb_error_entry old_table[MYRB_MAX_CHANNELS * MYRB_MAX_TARGETS];
+
+ memcpy(&old_table, cb->err_table, sizeof(old_table));
+
+ myrb_reset_cmd(cmd_blk);
+ mbox->type3.id = MYRB_MCMD_TAG;
+ mbox->type3.opcode = MYRB_CMD_GET_ERROR_TABLE;
+ mbox->type3.addr = cb->err_table_addr;
+ status = myrb_exec_cmd(cb, cmd_blk);
+ if (status == MYRB_STATUS_SUCCESS) {
+ struct myrb_error_entry *table = cb->err_table;
+ struct myrb_error_entry *new, *old;
+ size_t err_table_offset;
+ struct scsi_device *sdev;
+
+ shost_for_each_device(sdev, cb->host) {
+ if (sdev->channel >= myrb_logical_channel(cb->host))
+ continue;
+ err_table_offset = sdev->channel * MYRB_MAX_TARGETS
+ + sdev->id;
+ new = table + err_table_offset;
+ old = &old_table[err_table_offset];
+ if (new->parity_err == old->parity_err &&
+ new->soft_err == old->soft_err &&
+ new->hard_err == old->hard_err &&
+ new->misc_err == old->misc_err)
+ continue;
+ sdev_printk(KERN_CRIT, sdev,
+ "Errors: Parity = %d, Soft = %d, Hard = %d, Misc = %d\n",
+ new->parity_err, new->soft_err,
+ new->hard_err, new->misc_err);
+ }
+ }
+}
+
+/**
+ * myrb_get_ldev_info - retrieves the logical device table from the controller
+ *
+ * Executes a type 3 command and updates the logical device table.
+ *
+ * Return: command status
+ */
+static unsigned short myrb_get_ldev_info(struct myrb_hba *cb)
+{
+ unsigned short status;
+ int ldev_num, ldev_cnt = cb->enquiry->ldev_count;
+ struct Scsi_Host *shost = cb->host;
+
+ status = myrb_exec_type3(cb, MYRB_CMD_GET_LDEV_INFO,
+ cb->ldev_info_addr);
+ if (status != MYRB_STATUS_SUCCESS)
+ return status;
+
+ for (ldev_num = 0; ldev_num < ldev_cnt; ldev_num++) {
+ struct myrb_ldev_info *old = NULL;
+ struct myrb_ldev_info *new = cb->ldev_info_buf + ldev_num;
+ struct scsi_device *sdev;
+
+ sdev = scsi_device_lookup(shost, myrb_logical_channel(shost),
+ ldev_num, 0);
+ if (!sdev) {
+ if (new->state == MYRB_DEVICE_OFFLINE)
+ continue;
+ shost_printk(KERN_INFO, shost,
+ "Adding Logical Drive %d in state %s\n",
+ ldev_num, myrb_devstate_name(new->state));
+ scsi_add_device(shost, myrb_logical_channel(shost),
+ ldev_num, 0);
+ continue;
+ }
+ old = sdev->hostdata;
+ if (new->state != old->state)
+ shost_printk(KERN_INFO, shost,
+ "Logical Drive %d is now %s\n",
+ ldev_num, myrb_devstate_name(new->state));
+ if (new->wb_enabled != old->wb_enabled)
+ sdev_printk(KERN_INFO, sdev,
+ "Logical Drive is now WRITE %s\n",
+ (new->wb_enabled ? "BACK" : "THRU"));
+ memcpy(old, new, sizeof(*new));
+ scsi_device_put(sdev);
+ }
+ return status;
+}
+
+/**
+ * myrb_get_rbld_progress - get rebuild progress information
+ *
+ * Executes a type 3 command and returns the rebuild progress
+ * information.
+ *
+ * Return: command status
+ */
+static unsigned short myrb_get_rbld_progress(struct myrb_hba *cb,
+ struct myrb_rbld_progress *rbld)
+{
+ struct myrb_cmdblk *cmd_blk = &cb->mcmd_blk;
+ union myrb_cmd_mbox *mbox = &cmd_blk->mbox;
+ struct myrb_rbld_progress *rbld_buf;
+ dma_addr_t rbld_addr;
+ unsigned short status;
+
+ rbld_buf = dma_alloc_coherent(&cb->pdev->dev,
+ sizeof(struct myrb_rbld_progress),
+ &rbld_addr, GFP_KERNEL);
+ if (!rbld_buf)
+ return MYRB_STATUS_RBLD_NOT_CHECKED;
+
+ myrb_reset_cmd(cmd_blk);
+ mbox->type3.id = MYRB_MCMD_TAG;
+ mbox->type3.opcode = MYRB_CMD_GET_REBUILD_PROGRESS;
+ mbox->type3.addr = rbld_addr;
+ status = myrb_exec_cmd(cb, cmd_blk);
+ if (rbld)
+ memcpy(rbld, rbld_buf, sizeof(struct myrb_rbld_progress));
+ dma_free_coherent(&cb->pdev->dev, sizeof(struct myrb_rbld_progress),
+ rbld_buf, rbld_addr);
+ return status;
+}
+
+/**
+ * myrb_update_rbld_progress - updates the rebuild status
+ *
+ * Updates the rebuild status for the attached logical devices.
+ *
+ */
+static void myrb_update_rbld_progress(struct myrb_hba *cb)
+{
+ struct myrb_rbld_progress rbld_buf;
+ unsigned short status;
+
+ status = myrb_get_rbld_progress(cb, &rbld_buf);
+ if (status == MYRB_NO_STDBY_RBLD_OR_CHECK_IN_PROGRESS &&
+ cb->last_rbld_status == MYRB_STATUS_SUCCESS)
+ status = MYRB_STATUS_RBLD_SUCCESS;
+ if (status != MYRB_NO_STDBY_RBLD_OR_CHECK_IN_PROGRESS) {
+ unsigned int blocks_done =
+ rbld_buf.ldev_size - rbld_buf.blocks_left;
+ struct scsi_device *sdev;
+
+ sdev = scsi_device_lookup(cb->host,
+ myrb_logical_channel(cb->host),
+ rbld_buf.ldev_num, 0);
+ if (!sdev)
+ return;
+
+ switch (status) {
+ case MYRB_STATUS_SUCCESS:
+ sdev_printk(KERN_INFO, sdev,
+ "Rebuild in Progress, %d%% completed\n",
+ (100 * (blocks_done >> 7))
+ / (rbld_buf.ldev_size >> 7));
+ break;
+ case MYRB_STATUS_RBLD_FAILED_LDEV_FAILURE:
+ sdev_printk(KERN_INFO, sdev,
+ "Rebuild Failed due to Logical Drive Failure\n");
+ break;
+ case MYRB_STATUS_RBLD_FAILED_BADBLOCKS:
+ sdev_printk(KERN_INFO, sdev,
+ "Rebuild Failed due to Bad Blocks on Other Drives\n");
+ break;
+ case MYRB_STATUS_RBLD_FAILED_NEW_DRIVE_FAILED:
+ sdev_printk(KERN_INFO, sdev,
+ "Rebuild Failed due to Failure of Drive Being Rebuilt\n");
+ break;
+ case MYRB_STATUS_RBLD_SUCCESS:
+ sdev_printk(KERN_INFO, sdev,
+ "Rebuild Completed Successfully\n");
+ break;
+ case MYRB_STATUS_RBLD_SUCCESS_TERMINATED:
+ sdev_printk(KERN_INFO, sdev,
+ "Rebuild Successfully Terminated\n");
+ break;
+ default:
+ break;
+ }
+ scsi_device_put(sdev);
+ }
+ cb->last_rbld_status = status;
+}
+
+/**
+ * myrb_get_cc_progress - retrieve the rebuild status
+ *
+ * Execute a type 3 Command and fetch the rebuild / consistency check
+ * status.
+ */
+static void myrb_get_cc_progress(struct myrb_hba *cb)
+{
+ struct myrb_cmdblk *cmd_blk = &cb->mcmd_blk;
+ union myrb_cmd_mbox *mbox = &cmd_blk->mbox;
+ struct myrb_rbld_progress *rbld_buf;
+ dma_addr_t rbld_addr;
+ unsigned short status;
+
+ rbld_buf = dma_alloc_coherent(&cb->pdev->dev,
+ sizeof(struct myrb_rbld_progress),
+ &rbld_addr, GFP_KERNEL);
+ if (!rbld_buf) {
+ cb->need_cc_status = true;
+ return;
+ }
+ myrb_reset_cmd(cmd_blk);
+ mbox->type3.id = MYRB_MCMD_TAG;
+ mbox->type3.opcode = MYRB_CMD_REBUILD_STAT;
+ mbox->type3.addr = rbld_addr;
+ status = myrb_exec_cmd(cb, cmd_blk);
+ if (status == MYRB_STATUS_SUCCESS) {
+ unsigned int ldev_num = rbld_buf->ldev_num;
+ unsigned int ldev_size = rbld_buf->ldev_size;
+ unsigned int blocks_done =
+ ldev_size - rbld_buf->blocks_left;
+ struct scsi_device *sdev;
+
+ sdev = scsi_device_lookup(cb->host,
+ myrb_logical_channel(cb->host),
+ ldev_num, 0);
+ if (sdev) {
+ sdev_printk(KERN_INFO, sdev,
+ "Consistency Check in Progress: %d%% completed\n",
+ (100 * (blocks_done >> 7))
+ / (ldev_size >> 7));
+ scsi_device_put(sdev);
+ }
+ }
+ dma_free_coherent(&cb->pdev->dev, sizeof(struct myrb_rbld_progress),
+ rbld_buf, rbld_addr);
+}
+
+/**
+ * myrb_bgi_control - updates background initialisation status
+ *
+ * Executes a type 3B command and updates the background initialisation status
+ */
+static void myrb_bgi_control(struct myrb_hba *cb)
+{
+ struct myrb_cmdblk *cmd_blk = &cb->mcmd_blk;
+ union myrb_cmd_mbox *mbox = &cmd_blk->mbox;
+ struct myrb_bgi_status *bgi, *last_bgi;
+ dma_addr_t bgi_addr;
+ struct scsi_device *sdev = NULL;
+ unsigned short status;
+
+ bgi = dma_alloc_coherent(&cb->pdev->dev, sizeof(struct myrb_bgi_status),
+ &bgi_addr, GFP_KERNEL);
+ if (!bgi) {
+ shost_printk(KERN_ERR, cb->host,
+ "Failed to allocate bgi memory\n");
+ return;
+ }
+ myrb_reset_cmd(cmd_blk);
+ mbox->type3B.id = MYRB_DCMD_TAG;
+ mbox->type3B.opcode = MYRB_CMD_BGI_CONTROL;
+ mbox->type3B.optype = 0x20;
+ mbox->type3B.addr = bgi_addr;
+ status = myrb_exec_cmd(cb, cmd_blk);
+ last_bgi = &cb->bgi_status;
+ sdev = scsi_device_lookup(cb->host,
+ myrb_logical_channel(cb->host),
+ bgi->ldev_num, 0);
+ switch (status) {
+ case MYRB_STATUS_SUCCESS:
+ switch (bgi->status) {
+ case MYRB_BGI_INVALID:
+ break;
+ case MYRB_BGI_STARTED:
+ if (!sdev)
+ break;
+ sdev_printk(KERN_INFO, sdev,
+ "Background Initialization Started\n");
+ break;
+ case MYRB_BGI_INPROGRESS:
+ if (!sdev)
+ break;
+ if (bgi->blocks_done == last_bgi->blocks_done &&
+ bgi->ldev_num == last_bgi->ldev_num)
+ break;
+ sdev_printk(KERN_INFO, sdev,
+ "Background Initialization in Progress: %d%% completed\n",
+ (100 * (bgi->blocks_done >> 7))
+ / (bgi->ldev_size >> 7));
+ break;
+ case MYRB_BGI_SUSPENDED:
+ if (!sdev)
+ break;
+ sdev_printk(KERN_INFO, sdev,
+ "Background Initialization Suspended\n");
+ break;
+ case MYRB_BGI_CANCELLED:
+ if (!sdev)
+ break;
+ sdev_printk(KERN_INFO, sdev,
+ "Background Initialization Cancelled\n");
+ break;
+ }
+ memcpy(&cb->bgi_status, bgi, sizeof(struct myrb_bgi_status));
+ break;
+ case MYRB_STATUS_BGI_SUCCESS:
+ if (sdev && cb->bgi_status.status == MYRB_BGI_INPROGRESS)
+ sdev_printk(KERN_INFO, sdev,
+ "Background Initialization Completed Successfully\n");
+ cb->bgi_status.status = MYRB_BGI_INVALID;
+ break;
+ case MYRB_STATUS_BGI_ABORTED:
+ if (sdev && cb->bgi_status.status == MYRB_BGI_INPROGRESS)
+ sdev_printk(KERN_INFO, sdev,
+ "Background Initialization Aborted\n");
+ /* Fallthrough */
+ case MYRB_STATUS_NO_BGI_INPROGRESS:
+ cb->bgi_status.status = MYRB_BGI_INVALID;
+ break;
+ }
+ if (sdev)
+ scsi_device_put(sdev);
+ dma_free_coherent(&cb->pdev->dev, sizeof(struct myrb_bgi_status),
+ bgi, bgi_addr);
+}
+
+/**
+ * myrb_hba_enquiry - updates the controller status
+ *
+ * Executes a DAC_V1_Enquiry command and updates the controller status.
+ *
+ * Return: command status
+ */
+static unsigned short myrb_hba_enquiry(struct myrb_hba *cb)
+{
+ struct myrb_enquiry old, *new;
+ unsigned short status;
+
+ memcpy(&old, cb->enquiry, sizeof(struct myrb_enquiry));
+
+ status = myrb_exec_type3(cb, MYRB_CMD_ENQUIRY, cb->enquiry_addr);
+ if (status != MYRB_STATUS_SUCCESS)
+ return status;
+
+ new = cb->enquiry;
+ if (new->ldev_count > old.ldev_count) {
+ int ldev_num = old.ldev_count - 1;
+
+ while (++ldev_num < new->ldev_count)
+ shost_printk(KERN_CRIT, cb->host,
+ "Logical Drive %d Now Exists\n",
+ ldev_num);
+ }
+ if (new->ldev_count < old.ldev_count) {
+ int ldev_num = new->ldev_count - 1;
+
+ while (++ldev_num < old.ldev_count)
+ shost_printk(KERN_CRIT, cb->host,
+ "Logical Drive %d No Longer Exists\n",
+ ldev_num);
+ }
+ if (new->status.deferred != old.status.deferred)
+ shost_printk(KERN_CRIT, cb->host,
+ "Deferred Write Error Flag is now %s\n",
+ (new->status.deferred ? "TRUE" : "FALSE"));
+ if (new->ev_seq != old.ev_seq) {
+ cb->new_ev_seq = new->ev_seq;
+ cb->need_err_info = true;
+ shost_printk(KERN_INFO, cb->host,
+ "Event log %d/%d (%d/%d) available\n",
+ cb->old_ev_seq, cb->new_ev_seq,
+ old.ev_seq, new->ev_seq);
+ }
+ if ((new->ldev_critical > 0 &&
+ new->ldev_critical != old.ldev_critical) ||
+ (new->ldev_offline > 0 &&
+ new->ldev_offline != old.ldev_offline) ||
+ (new->ldev_count != old.ldev_count)) {
+ shost_printk(KERN_INFO, cb->host,
+ "Logical drive count changed (%d/%d/%d)\n",
+ new->ldev_critical,
+ new->ldev_offline,
+ new->ldev_count);
+ cb->need_ldev_info = true;
+ }
+ if (new->pdev_dead > 0 ||
+ new->pdev_dead != old.pdev_dead ||
+ time_after_eq(jiffies, cb->secondary_monitor_time
+ + MYRB_SECONDARY_MONITOR_INTERVAL)) {
+ cb->need_bgi_status = cb->bgi_status_supported;
+ cb->secondary_monitor_time = jiffies;
+ }
+ if (new->rbld == MYRB_STDBY_RBLD_IN_PROGRESS ||
+ new->rbld == MYRB_BG_RBLD_IN_PROGRESS ||
+ old.rbld == MYRB_STDBY_RBLD_IN_PROGRESS ||
+ old.rbld == MYRB_BG_RBLD_IN_PROGRESS) {
+ cb->need_rbld = true;
+ cb->rbld_first = (new->ldev_critical < old.ldev_critical);
+ }
+ if (old.rbld == MYRB_BG_CHECK_IN_PROGRESS)
+ switch (new->rbld) {
+ case MYRB_NO_STDBY_RBLD_OR_CHECK_IN_PROGRESS:
+ shost_printk(KERN_INFO, cb->host,
+ "Consistency Check Completed Successfully\n");
+ break;
+ case MYRB_STDBY_RBLD_IN_PROGRESS:
+ case MYRB_BG_RBLD_IN_PROGRESS:
+ break;
+ case MYRB_BG_CHECK_IN_PROGRESS:
+ cb->need_cc_status = true;
+ break;
+ case MYRB_STDBY_RBLD_COMPLETED_WITH_ERROR:
+ shost_printk(KERN_INFO, cb->host,
+ "Consistency Check Completed with Error\n");
+ break;
+ case MYRB_BG_RBLD_OR_CHECK_FAILED_DRIVE_FAILED:
+ shost_printk(KERN_INFO, cb->host,
+ "Consistency Check Failed - Physical Device Failed\n");
+ break;
+ case MYRB_BG_RBLD_OR_CHECK_FAILED_LDEV_FAILED:
+ shost_printk(KERN_INFO, cb->host,
+ "Consistency Check Failed - Logical Drive Failed\n");
+ break;
+ case MYRB_BG_RBLD_OR_CHECK_FAILED_OTHER:
+ shost_printk(KERN_INFO, cb->host,
+ "Consistency Check Failed - Other Causes\n");
+ break;
+ case MYRB_BG_RBLD_OR_CHECK_SUCCESS_TERMINATED:
+ shost_printk(KERN_INFO, cb->host,
+ "Consistency Check Successfully Terminated\n");
+ break;
+ }
+ else if (new->rbld == MYRB_BG_CHECK_IN_PROGRESS)
+ cb->need_cc_status = true;
+
+ return MYRB_STATUS_SUCCESS;
+}
+
+/**
+ * myrb_set_pdev_state - sets the device state for a physical device
+ *
+ * Return: command status
+ */
+static unsigned short myrb_set_pdev_state(struct myrb_hba *cb,
+ struct scsi_device *sdev, enum myrb_devstate state)
+{
+ struct myrb_cmdblk *cmd_blk = &cb->dcmd_blk;
+ union myrb_cmd_mbox *mbox = &cmd_blk->mbox;
+ unsigned short status;
+
+ mutex_lock(&cb->dcmd_mutex);
+ mbox->type3D.opcode = MYRB_CMD_START_DEVICE;
+ mbox->type3D.id = MYRB_DCMD_TAG;
+ mbox->type3D.channel = sdev->channel;
+ mbox->type3D.target = sdev->id;
+ mbox->type3D.state = state & 0x1F;
+ status = myrb_exec_cmd(cb, cmd_blk);
+ mutex_unlock(&cb->dcmd_mutex);
+
+ return status;
+}
+
+/**
+ * myrb_enable_mmio - enables the Memory Mailbox Interface
+ *
+ * PD and P controller types have no memory mailbox, but still need the
+ * other dma mapped memory.
+ *
+ * Return: true on success, false otherwise.
+ */
+static bool myrb_enable_mmio(struct myrb_hba *cb, mbox_mmio_init_t mmio_init_fn)
+{
+ void __iomem *base = cb->io_base;
+ struct pci_dev *pdev = cb->pdev;
+ size_t err_table_size;
+ size_t ldev_info_size;
+ union myrb_cmd_mbox *cmd_mbox_mem;
+ struct myrb_stat_mbox *stat_mbox_mem;
+ union myrb_cmd_mbox mbox;
+ unsigned short status;
+
+ memset(&mbox, 0, sizeof(union myrb_cmd_mbox));
+
+ if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) {
+ dev_err(&pdev->dev, "DMA mask out of range\n");
+ return false;
+ }
+
+ cb->enquiry = dma_alloc_coherent(&pdev->dev,
+ sizeof(struct myrb_enquiry),
+ &cb->enquiry_addr, GFP_KERNEL);
+ if (!cb->enquiry)
+ return false;
+
+ err_table_size = sizeof(struct myrb_error_entry) *
+ MYRB_MAX_CHANNELS * MYRB_MAX_TARGETS;
+ cb->err_table = dma_alloc_coherent(&pdev->dev, err_table_size,
+ &cb->err_table_addr, GFP_KERNEL);
+ if (!cb->err_table)
+ return false;
+
+ ldev_info_size = sizeof(struct myrb_ldev_info) * MYRB_MAX_LDEVS;
+ cb->ldev_info_buf = dma_alloc_coherent(&pdev->dev, ldev_info_size,
+ &cb->ldev_info_addr, GFP_KERNEL);
+ if (!cb->ldev_info_buf)
+ return false;
+
+ /*
+ * Skip mailbox initialisation for PD and P Controllers
+ */
+ if (!mmio_init_fn)
+ return true;
+
+ /* These are the base addresses for the command memory mailbox array */
+ cb->cmd_mbox_size = MYRB_CMD_MBOX_COUNT * sizeof(union myrb_cmd_mbox);
+ cb->first_cmd_mbox = dma_alloc_coherent(&pdev->dev,
+ cb->cmd_mbox_size,
+ &cb->cmd_mbox_addr,
+ GFP_KERNEL);
+ if (!cb->first_cmd_mbox)
+ return false;
+
+ cmd_mbox_mem = cb->first_cmd_mbox;
+ cmd_mbox_mem += MYRB_CMD_MBOX_COUNT - 1;
+ cb->last_cmd_mbox = cmd_mbox_mem;
+ cb->next_cmd_mbox = cb->first_cmd_mbox;
+ cb->prev_cmd_mbox1 = cb->last_cmd_mbox;
+ cb->prev_cmd_mbox2 = cb->last_cmd_mbox - 1;
+
+ /* These are the base addresses for the status memory mailbox array */
+ cb->stat_mbox_size = MYRB_STAT_MBOX_COUNT *
+ sizeof(struct myrb_stat_mbox);
+ cb->first_stat_mbox = dma_alloc_coherent(&pdev->dev,
+ cb->stat_mbox_size,
+ &cb->stat_mbox_addr,
+ GFP_KERNEL);
+ if (!cb->first_stat_mbox)
+ return false;
+
+ stat_mbox_mem = cb->first_stat_mbox;
+ stat_mbox_mem += MYRB_STAT_MBOX_COUNT - 1;
+ cb->last_stat_mbox = stat_mbox_mem;
+ cb->next_stat_mbox = cb->first_stat_mbox;
+
+ /* Enable the Memory Mailbox Interface. */
+ cb->dual_mode_interface = true;
+ mbox.typeX.opcode = 0x2B;
+ mbox.typeX.id = 0;
+ mbox.typeX.opcode2 = 0x14;
+ mbox.typeX.cmd_mbox_addr = cb->cmd_mbox_addr;
+ mbox.typeX.stat_mbox_addr = cb->stat_mbox_addr;
+
+ status = mmio_init_fn(pdev, base, &mbox);
+ if (status != MYRB_STATUS_SUCCESS) {
+ cb->dual_mode_interface = false;
+ mbox.typeX.opcode2 = 0x10;
+ status = mmio_init_fn(pdev, base, &mbox);
+ if (status != MYRB_STATUS_SUCCESS) {
+ dev_err(&pdev->dev,
+ "Failed to enable mailbox, statux %02X\n",
+ status);
+ return false;
+ }
+ }
+ return true;
+}
+
+/**
+ * myrb_get_hba_config - reads the configuration information
+ *
+ * Reads the configuration information from the controller and
+ * initializes the controller structure.
+ *
+ * Return: 0 on success, errno otherwise
+ */
+static int myrb_get_hba_config(struct myrb_hba *cb)
+{
+ struct myrb_enquiry2 *enquiry2;
+ dma_addr_t enquiry2_addr;
+ struct myrb_config2 *config2;
+ dma_addr_t config2_addr;
+ struct Scsi_Host *shost = cb->host;
+ struct pci_dev *pdev = cb->pdev;
+ int pchan_max = 0, pchan_cur = 0;
+ unsigned short status;
+ int ret = -ENODEV, memsize = 0;
+
+ enquiry2 = dma_alloc_coherent(&pdev->dev, sizeof(struct myrb_enquiry2),
+ &enquiry2_addr, GFP_KERNEL);
+ if (!enquiry2) {
+ shost_printk(KERN_ERR, cb->host,
+ "Failed to allocate V1 enquiry2 memory\n");
+ return -ENOMEM;
+ }
+ config2 = dma_alloc_coherent(&pdev->dev, sizeof(struct myrb_config2),
+ &config2_addr, GFP_KERNEL);
+ if (!config2) {
+ shost_printk(KERN_ERR, cb->host,
+ "Failed to allocate V1 config2 memory\n");
+ dma_free_coherent(&pdev->dev, sizeof(struct myrb_enquiry2),
+ enquiry2, enquiry2_addr);
+ return -ENOMEM;
+ }
+ mutex_lock(&cb->dma_mutex);
+ status = myrb_hba_enquiry(cb);
+ mutex_unlock(&cb->dma_mutex);
+ if (status != MYRB_STATUS_SUCCESS) {
+ shost_printk(KERN_WARNING, cb->host,
+ "Failed it issue V1 Enquiry\n");
+ goto out_free;
+ }
+
+ status = myrb_exec_type3(cb, MYRB_CMD_ENQUIRY2, enquiry2_addr);
+ if (status != MYRB_STATUS_SUCCESS) {
+ shost_printk(KERN_WARNING, cb->host,
+ "Failed to issue V1 Enquiry2\n");
+ goto out_free;
+ }
+
+ status = myrb_exec_type3(cb, MYRB_CMD_READ_CONFIG2, config2_addr);
+ if (status != MYRB_STATUS_SUCCESS) {
+ shost_printk(KERN_WARNING, cb->host,
+ "Failed to issue ReadConfig2\n");
+ goto out_free;
+ }
+
+ status = myrb_get_ldev_info(cb);
+ if (status != MYRB_STATUS_SUCCESS) {
+ shost_printk(KERN_WARNING, cb->host,
+ "Failed to get logical drive information\n");
+ goto out_free;
+ }
+
+ /*
+ * Initialize the Controller Model Name and Full Model Name fields.
+ */
+ switch (enquiry2->hw.sub_model) {
+ case DAC960_V1_P_PD_PU:
+ if (enquiry2->scsi_cap.bus_speed == MYRB_SCSI_SPEED_ULTRA)
+ strcpy(cb->model_name, "DAC960PU");
+ else
+ strcpy(cb->model_name, "DAC960PD");
+ break;
+ case DAC960_V1_PL:
+ strcpy(cb->model_name, "DAC960PL");
+ break;
+ case DAC960_V1_PG:
+ strcpy(cb->model_name, "DAC960PG");
+ break;
+ case DAC960_V1_PJ:
+ strcpy(cb->model_name, "DAC960PJ");
+ break;
+ case DAC960_V1_PR:
+ strcpy(cb->model_name, "DAC960PR");
+ break;
+ case DAC960_V1_PT:
+ strcpy(cb->model_name, "DAC960PT");
+ break;
+ case DAC960_V1_PTL0:
+ strcpy(cb->model_name, "DAC960PTL0");
+ break;
+ case DAC960_V1_PRL:
+ strcpy(cb->model_name, "DAC960PRL");
+ break;
+ case DAC960_V1_PTL1:
+ strcpy(cb->model_name, "DAC960PTL1");
+ break;
+ case DAC960_V1_1164P:
+ strcpy(cb->model_name, "eXtremeRAID 1100");
+ break;
+ default:
+ shost_printk(KERN_WARNING, cb->host,
+ "Unknown Model %X\n",
+ enquiry2->hw.sub_model);
+ goto out;
+ }
+ /*
+ * Initialize the Controller Firmware Version field and verify that it
+ * is a supported firmware version.
+ * The supported firmware versions are:
+ *
+ * DAC1164P 5.06 and above
+ * DAC960PTL/PRL/PJ/PG 4.06 and above
+ * DAC960PU/PD/PL 3.51 and above
+ * DAC960PU/PD/PL/P 2.73 and above
+ */
+#if defined(CONFIG_ALPHA)
+ /*
+ * DEC Alpha machines were often equipped with DAC960 cards that were
+ * OEMed from Mylex, and had their own custom firmware. Version 2.70,
+ * the last custom FW revision to be released by DEC for these older
+ * controllers, appears to work quite well with this driver.
+ *
+ * Cards tested successfully were several versions each of the PD and
+ * PU, called by DEC the KZPSC and KZPAC, respectively, and having
+ * the Manufacturer Numbers (from Mylex), usually on a sticker on the
+ * back of the board, of:
+ *
+ * KZPSC: D040347 (1-channel) or D040348 (2-channel)
+ * or D040349 (3-channel)
+ * KZPAC: D040395 (1-channel) or D040396 (2-channel)
+ * or D040397 (3-channel)
+ */
+# define FIRMWARE_27X "2.70"
+#else
+# define FIRMWARE_27X "2.73"
+#endif
+
+ if (enquiry2->fw.major_version == 0) {
+ enquiry2->fw.major_version = cb->enquiry->fw_major_version;
+ enquiry2->fw.minor_version = cb->enquiry->fw_minor_version;
+ enquiry2->fw.firmware_type = '0';
+ enquiry2->fw.turn_id = 0;
+ }
+ snprintf(cb->fw_version, sizeof(cb->fw_version),
+ "%d.%02d-%c-%02d",
+ enquiry2->fw.major_version,
+ enquiry2->fw.minor_version,
+ enquiry2->fw.firmware_type,
+ enquiry2->fw.turn_id);
+ if (!((enquiry2->fw.major_version == 5 &&
+ enquiry2->fw.minor_version >= 6) ||
+ (enquiry2->fw.major_version == 4 &&
+ enquiry2->fw.minor_version >= 6) ||
+ (enquiry2->fw.major_version == 3 &&
+ enquiry2->fw.minor_version >= 51) ||
+ (enquiry2->fw.major_version == 2 &&
+ strcmp(cb->fw_version, FIRMWARE_27X) >= 0))) {
+ shost_printk(KERN_WARNING, cb->host,
+ "Firmware Version '%s' unsupported\n",
+ cb->fw_version);
+ goto out;
+ }
+ /*
+ * Initialize the Channels, Targets, Memory Size, and SAF-TE
+ * Enclosure Management Enabled fields.
+ */
+ switch (enquiry2->hw.model) {
+ case MYRB_5_CHANNEL_BOARD:
+ pchan_max = 5;
+ break;
+ case MYRB_3_CHANNEL_BOARD:
+ case MYRB_3_CHANNEL_ASIC_DAC:
+ pchan_max = 3;
+ break;
+ case MYRB_2_CHANNEL_BOARD:
+ pchan_max = 2;
+ break;
+ default:
+ pchan_max = enquiry2->cfg_chan;
+ break;
+ }
+ pchan_cur = enquiry2->cur_chan;
+ if (enquiry2->scsi_cap.bus_width == MYRB_WIDTH_WIDE_32BIT)
+ cb->bus_width = 32;
+ else if (enquiry2->scsi_cap.bus_width == MYRB_WIDTH_WIDE_16BIT)
+ cb->bus_width = 16;
+ else
+ cb->bus_width = 8;
+ cb->ldev_block_size = enquiry2->ldev_block_size;
+ shost->max_channel = pchan_cur;
+ shost->max_id = enquiry2->max_targets;
+ memsize = enquiry2->mem_size >> 20;
+ cb->safte_enabled = (enquiry2->fault_mgmt == MYRB_FAULT_SAFTE);
+ /*
+ * Initialize the Controller Queue Depth, Driver Queue Depth,
+ * Logical Drive Count, Maximum Blocks per Command, Controller
+ * Scatter/Gather Limit, and Driver Scatter/Gather Limit.
+ * The Driver Queue Depth must be at most one less than the
+ * Controller Queue Depth to allow for an automatic drive
+ * rebuild operation.
+ */
+ shost->can_queue = cb->enquiry->max_tcq;
+ if (shost->can_queue < 3)
+ shost->can_queue = enquiry2->max_cmds;
+ if (shost->can_queue < 3)
+ /* Play safe and disable TCQ */
+ shost->can_queue = 1;
+
+ if (shost->can_queue > MYRB_CMD_MBOX_COUNT - 2)
+ shost->can_queue = MYRB_CMD_MBOX_COUNT - 2;
+ shost->max_sectors = enquiry2->max_sectors;
+ shost->sg_tablesize = enquiry2->max_sge;
+ if (shost->sg_tablesize > MYRB_SCATTER_GATHER_LIMIT)
+ shost->sg_tablesize = MYRB_SCATTER_GATHER_LIMIT;
+ /*
+ * Initialize the Stripe Size, Segment Size, and Geometry Translation.
+ */
+ cb->stripe_size = config2->blocks_per_stripe * config2->block_factor
+ >> (10 - MYRB_BLKSIZE_BITS);
+ cb->segment_size = config2->blocks_per_cacheline * config2->block_factor
+ >> (10 - MYRB_BLKSIZE_BITS);
+ /* Assume 255/63 translation */
+ cb->ldev_geom_heads = 255;
+ cb->ldev_geom_sectors = 63;
+ if (config2->drive_geometry) {
+ cb->ldev_geom_heads = 128;
+ cb->ldev_geom_sectors = 32;
+ }
+
+ /*
+ * Initialize the Background Initialization Status.
+ */
+ if ((cb->fw_version[0] == '4' &&
+ strcmp(cb->fw_version, "4.08") >= 0) ||
+ (cb->fw_version[0] == '5' &&
+ strcmp(cb->fw_version, "5.08") >= 0)) {
+ cb->bgi_status_supported = true;
+ myrb_bgi_control(cb);
+ }
+ cb->last_rbld_status = MYRB_NO_STDBY_RBLD_OR_CHECK_IN_PROGRESS;
+ ret = 0;
+
+out:
+ shost_printk(KERN_INFO, cb->host,
+ "Configuring %s PCI RAID Controller\n", cb->model_name);
+ shost_printk(KERN_INFO, cb->host,
+ " Firmware Version: %s, Memory Size: %dMB\n",
+ cb->fw_version, memsize);
+ if (cb->io_addr == 0)
+ shost_printk(KERN_INFO, cb->host,
+ " I/O Address: n/a, PCI Address: 0x%lX, IRQ Channel: %d\n",
+ (unsigned long)cb->pci_addr, cb->irq);
+ else
+ shost_printk(KERN_INFO, cb->host,
+ " I/O Address: 0x%lX, PCI Address: 0x%lX, IRQ Channel: %d\n",
+ (unsigned long)cb->io_addr, (unsigned long)cb->pci_addr,
+ cb->irq);
+ shost_printk(KERN_INFO, cb->host,
+ " Controller Queue Depth: %d, Maximum Blocks per Command: %d\n",
+ cb->host->can_queue, cb->host->max_sectors);
+ shost_printk(KERN_INFO, cb->host,
+ " Driver Queue Depth: %d, Scatter/Gather Limit: %d of %d Segments\n",
+ cb->host->can_queue, cb->host->sg_tablesize,
+ MYRB_SCATTER_GATHER_LIMIT);
+ shost_printk(KERN_INFO, cb->host,
+ " Stripe Size: %dKB, Segment Size: %dKB, BIOS Geometry: %d/%d%s\n",
+ cb->stripe_size, cb->segment_size,
+ cb->ldev_geom_heads, cb->ldev_geom_sectors,
+ cb->safte_enabled ?
+ " SAF-TE Enclosure Management Enabled" : "");
+ shost_printk(KERN_INFO, cb->host,
+ " Physical: %d/%d channels %d/%d/%d devices\n",
+ pchan_cur, pchan_max, 0, cb->enquiry->pdev_dead,
+ cb->host->max_id);
+
+ shost_printk(KERN_INFO, cb->host,
+ " Logical: 1/1 channels, %d/%d disks\n",
+ cb->enquiry->ldev_count, MYRB_MAX_LDEVS);
+
+out_free:
+ dma_free_coherent(&pdev->dev, sizeof(struct myrb_enquiry2),
+ enquiry2, enquiry2_addr);
+ dma_free_coherent(&pdev->dev, sizeof(struct myrb_config2),
+ config2, config2_addr);
+
+ return ret;
+}
+
+/**
+ * myrb_unmap - unmaps controller structures
+ */
+static void myrb_unmap(struct myrb_hba *cb)
+{
+ if (cb->ldev_info_buf) {
+ size_t ldev_info_size = sizeof(struct myrb_ldev_info) *
+ MYRB_MAX_LDEVS;
+ dma_free_coherent(&cb->pdev->dev, ldev_info_size,
+ cb->ldev_info_buf, cb->ldev_info_addr);
+ cb->ldev_info_buf = NULL;
+ }
+ if (cb->err_table) {
+ size_t err_table_size = sizeof(struct myrb_error_entry) *
+ MYRB_MAX_CHANNELS * MYRB_MAX_TARGETS;
+ dma_free_coherent(&cb->pdev->dev, err_table_size,
+ cb->err_table, cb->err_table_addr);
+ cb->err_table = NULL;
+ }
+ if (cb->enquiry) {
+ dma_free_coherent(&cb->pdev->dev, sizeof(struct myrb_enquiry),
+ cb->enquiry, cb->enquiry_addr);
+ cb->enquiry = NULL;
+ }
+ if (cb->first_stat_mbox) {
+ dma_free_coherent(&cb->pdev->dev, cb->stat_mbox_size,
+ cb->first_stat_mbox, cb->stat_mbox_addr);
+ cb->first_stat_mbox = NULL;
+ }
+ if (cb->first_cmd_mbox) {
+ dma_free_coherent(&cb->pdev->dev, cb->cmd_mbox_size,
+ cb->first_cmd_mbox, cb->cmd_mbox_addr);
+ cb->first_cmd_mbox = NULL;
+ }
+}
+
+/**
+ * myrb_cleanup - cleanup controller structures
+ */
+static void myrb_cleanup(struct myrb_hba *cb)
+{
+ struct pci_dev *pdev = cb->pdev;
+
+ /* Free the memory mailbox, status, and related structures */
+ myrb_unmap(cb);
+
+ if (cb->mmio_base) {
+ cb->disable_intr(cb->io_base);
+ iounmap(cb->mmio_base);
+ }
+ if (cb->irq)
+ free_irq(cb->irq, cb);
+ if (cb->io_addr)
+ release_region(cb->io_addr, 0x80);
+ pci_set_drvdata(pdev, NULL);
+ pci_disable_device(pdev);
+ scsi_host_put(cb->host);
+}
+
+static int myrb_host_reset(struct scsi_cmnd *scmd)
+{
+ struct Scsi_Host *shost = scmd->device->host;
+ struct myrb_hba *cb = shost_priv(shost);
+
+ cb->reset(cb->io_base);
+ return SUCCESS;
+}
+
+static int myrb_pthru_queuecommand(struct Scsi_Host *shost,
+ struct scsi_cmnd *scmd)
+{
+ struct myrb_hba *cb = shost_priv(shost);
+ struct myrb_cmdblk *cmd_blk = scsi_cmd_priv(scmd);
+ union myrb_cmd_mbox *mbox = &cmd_blk->mbox;
+ struct myrb_dcdb *dcdb;
+ dma_addr_t dcdb_addr;
+ struct scsi_device *sdev = scmd->device;
+ struct scatterlist *sgl;
+ unsigned long flags;
+ int nsge;
+
+ myrb_reset_cmd(cmd_blk);
+ dcdb = dma_pool_alloc(cb->dcdb_pool, GFP_ATOMIC, &dcdb_addr);
+ if (!dcdb)
+ return SCSI_MLQUEUE_HOST_BUSY;
+ nsge = scsi_dma_map(scmd);
+ if (nsge > 1) {
+ dma_pool_free(cb->dcdb_pool, dcdb, dcdb_addr);
+ scmd->result = (DID_ERROR << 16);
+ scmd->scsi_done(scmd);
+ return 0;
+ }
+
+ mbox->type3.opcode = MYRB_CMD_DCDB;
+ mbox->type3.id = scmd->request->tag + 3;
+ mbox->type3.addr = dcdb_addr;
+ dcdb->channel = sdev->channel;
+ dcdb->target = sdev->id;
+ switch (scmd->sc_data_direction) {
+ case DMA_NONE:
+ dcdb->data_xfer = MYRB_DCDB_XFER_NONE;
+ break;
+ case DMA_TO_DEVICE:
+ dcdb->data_xfer = MYRB_DCDB_XFER_SYSTEM_TO_DEVICE;
+ break;
+ case DMA_FROM_DEVICE:
+ dcdb->data_xfer = MYRB_DCDB_XFER_DEVICE_TO_SYSTEM;
+ break;
+ default:
+ dcdb->data_xfer = MYRB_DCDB_XFER_ILLEGAL;
+ break;
+ }
+ dcdb->early_status = false;
+ if (scmd->request->timeout <= 10)
+ dcdb->timeout = MYRB_DCDB_TMO_10_SECS;
+ else if (scmd->request->timeout <= 60)
+ dcdb->timeout = MYRB_DCDB_TMO_60_SECS;
+ else if (scmd->request->timeout <= 600)
+ dcdb->timeout = MYRB_DCDB_TMO_10_MINS;
+ else
+ dcdb->timeout = MYRB_DCDB_TMO_24_HRS;
+ dcdb->no_autosense = false;
+ dcdb->allow_disconnect = true;
+ sgl = scsi_sglist(scmd);
+ dcdb->dma_addr = sg_dma_address(sgl);
+ if (sg_dma_len(sgl) > USHRT_MAX) {
+ dcdb->xfer_len_lo = sg_dma_len(sgl) & 0xffff;
+ dcdb->xfer_len_hi4 = sg_dma_len(sgl) >> 16;
+ } else {
+ dcdb->xfer_len_lo = sg_dma_len(sgl);
+ dcdb->xfer_len_hi4 = 0;
+ }
+ dcdb->cdb_len = scmd->cmd_len;
+ dcdb->sense_len = sizeof(dcdb->sense);
+ memcpy(&dcdb->cdb, scmd->cmnd, scmd->cmd_len);
+
+ spin_lock_irqsave(&cb->queue_lock, flags);
+ cb->qcmd(cb, cmd_blk);
+ spin_unlock_irqrestore(&cb->queue_lock, flags);
+ return 0;
+}
+
+static void myrb_inquiry(struct myrb_hba *cb,
+ struct scsi_cmnd *scmd)
+{
+ unsigned char inq[36] = {
+ 0x00, 0x00, 0x03, 0x02, 0x20, 0x00, 0x01, 0x00,
+ 0x4d, 0x59, 0x4c, 0x45, 0x58, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20,
+ };
+
+ if (cb->bus_width > 16)
+ inq[7] |= 1 << 6;
+ if (cb->bus_width > 8)
+ inq[7] |= 1 << 5;
+ memcpy(&inq[16], cb->model_name, 16);
+ memcpy(&inq[32], cb->fw_version, 1);
+ memcpy(&inq[33], &cb->fw_version[2], 2);
+ memcpy(&inq[35], &cb->fw_version[7], 1);
+
+ scsi_sg_copy_from_buffer(scmd, (void *)inq, 36);
+}
+
+static void
+myrb_mode_sense(struct myrb_hba *cb, struct scsi_cmnd *scmd,
+ struct myrb_ldev_info *ldev_info)
+{
+ unsigned char modes[32], *mode_pg;
+ bool dbd;
+ size_t mode_len;
+
+ dbd = (scmd->cmnd[1] & 0x08) == 0x08;
+ if (dbd) {
+ mode_len = 24;
+ mode_pg = &modes[4];
+ } else {
+ mode_len = 32;
+ mode_pg = &modes[12];
+ }
+ memset(modes, 0, sizeof(modes));
+ modes[0] = mode_len - 1;
+ if (!dbd) {
+ unsigned char *block_desc = &modes[4];
+
+ modes[3] = 8;
+ put_unaligned_be32(ldev_info->size, &block_desc[0]);
+ put_unaligned_be32(cb->ldev_block_size, &block_desc[5]);
+ }
+ mode_pg[0] = 0x08;
+ mode_pg[1] = 0x12;
+ if (ldev_info->wb_enabled)
+ mode_pg[2] |= 0x04;
+ if (cb->segment_size) {
+ mode_pg[2] |= 0x08;
+ put_unaligned_be16(cb->segment_size, &mode_pg[14]);
+ }
+
+ scsi_sg_copy_from_buffer(scmd, modes, mode_len);
+}
+
+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_sg_copy_from_buffer(scmd, scmd->sense_buffer,
+ SCSI_SENSE_BUFFERSIZE);
+}
+
+static void myrb_read_capacity(struct myrb_hba *cb, struct scsi_cmnd *scmd,
+ struct myrb_ldev_info *ldev_info)
+{
+ unsigned char data[8];
+
+ dev_dbg(&scmd->device->sdev_gendev,
+ "Capacity %u, blocksize %u\n",
+ ldev_info->size, cb->ldev_block_size);
+ put_unaligned_be32(ldev_info->size - 1, &data[0]);
+ put_unaligned_be32(cb->ldev_block_size, &data[4]);
+ scsi_sg_copy_from_buffer(scmd, data, 8);
+}
+
+static int myrb_ldev_queuecommand(struct Scsi_Host *shost,
+ struct scsi_cmnd *scmd)
+{
+ struct myrb_hba *cb = shost_priv(shost);
+ struct myrb_cmdblk *cmd_blk = scsi_cmd_priv(scmd);
+ union myrb_cmd_mbox *mbox = &cmd_blk->mbox;
+ struct myrb_ldev_info *ldev_info;
+ struct scsi_device *sdev = scmd->device;
+ struct scatterlist *sgl;
+ unsigned long flags;
+ u64 lba;
+ u32 block_cnt;
+ int nsge;
+
+ ldev_info = sdev->hostdata;
+ if (ldev_info->state != MYRB_DEVICE_ONLINE &&
+ ldev_info->state != MYRB_DEVICE_WO) {
+ dev_dbg(&shost->shost_gendev, "ldev %u in state %x, skip\n",
+ sdev->id, ldev_info ? ldev_info->state : 0xff);
+ scmd->result = (DID_BAD_TARGET << 16);
+ scmd->scsi_done(scmd);
+ return 0;
+ }
+ switch (scmd->cmnd[0]) {
+ case TEST_UNIT_READY:
+ scmd->result = (DID_OK << 16);
+ scmd->scsi_done(scmd);
+ return 0;
+ 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;
+ } else {
+ myrb_inquiry(cb, scmd);
+ scmd->result = (DID_OK << 16);
+ }
+ scmd->scsi_done(scmd);
+ return 0;
+ case SYNCHRONIZE_CACHE:
+ scmd->result = (DID_OK << 16);
+ scmd->scsi_done(scmd);
+ return 0;
+ case MODE_SENSE:
+ 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;
+ } else {
+ myrb_mode_sense(cb, scmd, ldev_info);
+ scmd->result = (DID_OK << 16);
+ }
+ scmd->scsi_done(scmd);
+ return 0;
+ case READ_CAPACITY:
+ 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;
+ 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;
+ scmd->scsi_done(scmd);
+ return 0;
+ }
+ myrb_read_capacity(cb, scmd, ldev_info);
+ scmd->scsi_done(scmd);
+ return 0;
+ case REQUEST_SENSE:
+ myrb_request_sense(cb, scmd);
+ scmd->result = (DID_OK << 16);
+ return 0;
+ 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;
+ } else {
+ /* Assume good status */
+ scmd->result = (DID_OK << 16);
+ }
+ scmd->scsi_done(scmd);
+ return 0;
+ 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;
+ scmd->scsi_done(scmd);
+ return 0;
+ }
+ case WRITE_6:
+ lba = (((scmd->cmnd[1] & 0x1F) << 16) |
+ (scmd->cmnd[2] << 8) |
+ scmd->cmnd[3]);
+ block_cnt = scmd->cmnd[4];
+ break;
+ 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;
+ scmd->scsi_done(scmd);
+ return 0;
+ }
+ case WRITE_10:
+ case VERIFY: /* 0x2F */
+ case WRITE_VERIFY: /* 0x2E */
+ lba = get_unaligned_be32(&scmd->cmnd[2]);
+ block_cnt = get_unaligned_be16(&scmd->cmnd[7]);
+ break;
+ 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;
+ scmd->scsi_done(scmd);
+ return 0;
+ }
+ case WRITE_12:
+ case VERIFY_12: /* 0xAF */
+ case WRITE_VERIFY_12: /* 0xAE */
+ lba = get_unaligned_be32(&scmd->cmnd[2]);
+ block_cnt = get_unaligned_be32(&scmd->cmnd[6]);
+ 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;
+ scmd->scsi_done(scmd);
+ return 0;
+ }
+
+ myrb_reset_cmd(cmd_blk);
+ mbox->type5.id = scmd->request->tag + 3;
+ if (scmd->sc_data_direction == DMA_NONE)
+ goto submit;
+ nsge = scsi_dma_map(scmd);
+ if (nsge == 1) {
+ sgl = scsi_sglist(scmd);
+ if (scmd->sc_data_direction == DMA_FROM_DEVICE)
+ mbox->type5.opcode = MYRB_CMD_READ;
+ else
+ mbox->type5.opcode = MYRB_CMD_WRITE;
+
+ mbox->type5.ld.xfer_len = block_cnt;
+ mbox->type5.ld.ldev_num = sdev->id;
+ mbox->type5.lba = lba;
+ mbox->type5.addr = (u32)sg_dma_address(sgl);
+ } else {
+ struct myrb_sge *hw_sgl;
+ dma_addr_t hw_sgl_addr;
+ int i;
+
+ hw_sgl = dma_pool_alloc(cb->sg_pool, GFP_ATOMIC, &hw_sgl_addr);
+ if (!hw_sgl)
+ return SCSI_MLQUEUE_HOST_BUSY;
+
+ cmd_blk->sgl = hw_sgl;
+ cmd_blk->sgl_addr = hw_sgl_addr;
+
+ if (scmd->sc_data_direction == DMA_FROM_DEVICE)
+ mbox->type5.opcode = MYRB_CMD_READ_SG;
+ else
+ mbox->type5.opcode = MYRB_CMD_WRITE_SG;
+
+ mbox->type5.ld.xfer_len = block_cnt;
+ mbox->type5.ld.ldev_num = sdev->id;
+ mbox->type5.lba = lba;
+ mbox->type5.addr = hw_sgl_addr;
+ mbox->type5.sg_count = nsge;
+
+ scsi_for_each_sg(scmd, sgl, nsge, i) {
+ hw_sgl->sge_addr = (u32)sg_dma_address(sgl);
+ hw_sgl->sge_count = (u32)sg_dma_len(sgl);
+ hw_sgl++;
+ }
+ }
+submit:
+ spin_lock_irqsave(&cb->queue_lock, flags);
+ cb->qcmd(cb, cmd_blk);
+ spin_unlock_irqrestore(&cb->queue_lock, flags);
+
+ return 0;
+}
+
+static int myrb_queuecommand(struct Scsi_Host *shost,
+ struct scsi_cmnd *scmd)
+{
+ struct scsi_device *sdev = scmd->device;
+
+ if (sdev->channel > myrb_logical_channel(shost)) {
+ scmd->result = (DID_BAD_TARGET << 16);
+ scmd->scsi_done(scmd);
+ return 0;
+ }
+ if (sdev->channel == myrb_logical_channel(shost))
+ return myrb_ldev_queuecommand(shost, scmd);
+
+ return myrb_pthru_queuecommand(shost, scmd);
+}
+
+static int myrb_ldev_slave_alloc(struct scsi_device *sdev)
+{
+ struct myrb_hba *cb = shost_priv(sdev->host);
+ struct myrb_ldev_info *ldev_info;
+ unsigned short ldev_num = sdev->id;
+ enum raid_level level;
+
+ ldev_info = cb->ldev_info_buf + ldev_num;
+ if (!ldev_info)
+ return -ENXIO;
+
+ sdev->hostdata = kzalloc(sizeof(*ldev_info), GFP_KERNEL);
+ if (!sdev->hostdata)
+ return -ENOMEM;
+ dev_dbg(&sdev->sdev_gendev,
+ "slave alloc ldev %d state %x\n",
+ ldev_num, ldev_info->state);
+ memcpy(sdev->hostdata, ldev_info,
+ sizeof(*ldev_info));
+ switch (ldev_info->raid_level) {
+ case MYRB_RAID_LEVEL0:
+ level = RAID_LEVEL_LINEAR;
+ break;
+ case MYRB_RAID_LEVEL1:
+ level = RAID_LEVEL_1;
+ break;
+ case MYRB_RAID_LEVEL3:
+ level = RAID_LEVEL_3;
+ break;
+ case MYRB_RAID_LEVEL5:
+ level = RAID_LEVEL_5;
+ break;
+ case MYRB_RAID_LEVEL6:
+ level = RAID_LEVEL_6;
+ break;
+ case MYRB_RAID_JBOD:
+ level = RAID_LEVEL_JBOD;
+ break;
+ default:
+ level = RAID_LEVEL_UNKNOWN;
+ break;
+ }
+ raid_set_level(myrb_raid_template, &sdev->sdev_gendev, level);
+ return 0;
+}
+
+static int myrb_pdev_slave_alloc(struct scsi_device *sdev)
+{
+ struct myrb_hba *cb = shost_priv(sdev->host);
+ struct myrb_pdev_state *pdev_info;
+ unsigned short status;
+
+ if (sdev->id > MYRB_MAX_TARGETS)
+ return -ENXIO;
+
+ pdev_info = kzalloc(sizeof(*pdev_info), GFP_KERNEL|GFP_DMA);
+ if (!pdev_info)
+ return -ENOMEM;
+
+ status = myrb_exec_type3D(cb, MYRB_CMD_GET_DEVICE_STATE,
+ sdev, pdev_info);
+ if (status != MYRB_STATUS_SUCCESS) {
+ dev_dbg(&sdev->sdev_gendev,
+ "Failed to get device state, status %x\n",
+ status);
+ kfree(pdev_info);
+ return -ENXIO;
+ }
+ if (!pdev_info->present) {
+ dev_dbg(&sdev->sdev_gendev,
+ "device not present, skip\n");
+ kfree(pdev_info);
+ return -ENXIO;
+ }
+ dev_dbg(&sdev->sdev_gendev,
+ "slave alloc pdev %d:%d state %x\n",
+ sdev->channel, sdev->id, pdev_info->state);
+ sdev->hostdata = pdev_info;
+
+ return 0;
+}
+
+static int myrb_slave_alloc(struct scsi_device *sdev)
+{
+ if (sdev->channel > myrb_logical_channel(sdev->host))
+ return -ENXIO;
+
+ if (sdev->lun > 0)
+ return -ENXIO;
+
+ if (sdev->channel == myrb_logical_channel(sdev->host))
+ return myrb_ldev_slave_alloc(sdev);
+
+ return myrb_pdev_slave_alloc(sdev);
+}
+
+static int myrb_slave_configure(struct scsi_device *sdev)
+{
+ struct myrb_ldev_info *ldev_info;
+
+ if (sdev->channel > myrb_logical_channel(sdev->host))
+ return -ENXIO;
+
+ if (sdev->channel < myrb_logical_channel(sdev->host)) {
+ sdev->no_uld_attach = 1;
+ return 0;
+ }
+ if (sdev->lun != 0)
+ return -ENXIO;
+
+ ldev_info = sdev->hostdata;
+ if (!ldev_info)
+ return -ENXIO;
+ if (ldev_info->state != MYRB_DEVICE_ONLINE)
+ sdev_printk(KERN_INFO, sdev,
+ "Logical drive is %s\n",
+ myrb_devstate_name(ldev_info->state));
+
+ sdev->tagged_supported = 1;
+ return 0;
+}
+
+static void myrb_slave_destroy(struct scsi_device *sdev)
+{
+ kfree(sdev->hostdata);
+}
+
+static int myrb_biosparam(struct scsi_device *sdev, struct block_device *bdev,
+ sector_t capacity, int geom[])
+{
+ struct myrb_hba *cb = shost_priv(sdev->host);
+
+ geom[0] = cb->ldev_geom_heads;
+ geom[1] = cb->ldev_geom_sectors;
+ geom[2] = sector_div(capacity, geom[0] * geom[1]);
+
+ return 0;
+}
+
+static ssize_t raid_state_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct myrb_hba *cb = shost_priv(sdev->host);
+ int ret;
+
+ if (!sdev->hostdata)
+ return snprintf(buf, 16, "Unknown\n");
+
+ if (sdev->channel == myrb_logical_channel(sdev->host)) {
+ struct myrb_ldev_info *ldev_info = sdev->hostdata;
+ const char *name;
+
+ name = myrb_devstate_name(ldev_info->state);
+ if (name)
+ ret = snprintf(buf, 32, "%s\n", name);
+ else
+ ret = snprintf(buf, 32, "Invalid (%02X)\n",
+ ldev_info->state);
+ } else {
+ struct myrb_pdev_state *pdev_info = sdev->hostdata;
+ unsigned short status;
+ const char *name;
+
+ status = myrb_exec_type3D(cb, MYRB_CMD_GET_DEVICE_STATE,
+ sdev, pdev_info);
+ if (status != MYRB_STATUS_SUCCESS)
+ sdev_printk(KERN_INFO, sdev,
+ "Failed to get device state, status %x\n",
+ status);
+
+ if (!pdev_info->present)
+ name = "Removed";
+ else
+ name = myrb_devstate_name(pdev_info->state);
+ if (name)
+ ret = snprintf(buf, 32, "%s\n", name);
+ else
+ ret = snprintf(buf, 32, "Invalid (%02X)\n",
+ pdev_info->state);
+ }
+ return ret;
+}
+
+static ssize_t raid_state_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct myrb_hba *cb = shost_priv(sdev->host);
+ struct myrb_pdev_state *pdev_info;
+ enum myrb_devstate new_state;
+ unsigned short status;
+
+ if (!strncmp(buf, "kill", 4) ||
+ !strncmp(buf, "offline", 7))
+ new_state = MYRB_DEVICE_DEAD;
+ else if (!strncmp(buf, "online", 6))
+ new_state = MYRB_DEVICE_ONLINE;
+ else if (!strncmp(buf, "standby", 7))
+ new_state = MYRB_DEVICE_STANDBY;
+ else
+ return -EINVAL;
+
+ pdev_info = sdev->hostdata;
+ if (!pdev_info) {
+ sdev_printk(KERN_INFO, sdev,
+ "Failed - no physical device information\n");
+ return -ENXIO;
+ }
+ if (!pdev_info->present) {
+ sdev_printk(KERN_INFO, sdev,
+ "Failed - device not present\n");
+ return -ENXIO;
+ }
+
+ if (pdev_info->state == new_state)
+ return count;
+
+ status = myrb_set_pdev_state(cb, sdev, new_state);
+ switch (status) {
+ case MYRB_STATUS_SUCCESS:
+ break;
+ case MYRB_STATUS_START_DEVICE_FAILED:
+ sdev_printk(KERN_INFO, sdev,
+ "Failed - Unable to Start Device\n");
+ count = -EAGAIN;
+ break;
+ case MYRB_STATUS_NO_DEVICE:
+ sdev_printk(KERN_INFO, sdev,
+ "Failed - No Device at Address\n");
+ count = -ENODEV;
+ break;
+ case MYRB_STATUS_INVALID_CHANNEL_OR_TARGET:
+ sdev_printk(KERN_INFO, sdev,
+ "Failed - Invalid Channel or Target or Modifier\n");
+ count = -EINVAL;
+ break;
+ case MYRB_STATUS_CHANNEL_BUSY:
+ sdev_printk(KERN_INFO, sdev,
+ "Failed - Channel Busy\n");
+ count = -EBUSY;
+ break;
+ default:
+ sdev_printk(KERN_INFO, sdev,
+ "Failed - Unexpected Status %04X\n", status);
+ count = -EIO;
+ break;
+ }
+ return count;
+}
+static DEVICE_ATTR_RW(raid_state);
+
+static ssize_t raid_level_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+
+ if (sdev->channel == myrb_logical_channel(sdev->host)) {
+ struct myrb_ldev_info *ldev_info = sdev->hostdata;
+ const char *name;
+
+ if (!ldev_info)
+ return -ENXIO;
+
+ name = myrb_raidlevel_name(ldev_info->raid_level);
+ if (!name)
+ return snprintf(buf, 32, "Invalid (%02X)\n",
+ ldev_info->state);
+ return snprintf(buf, 32, "%s\n", name);
+ }
+ return snprintf(buf, 32, "Physical Drive\n");
+}
+static DEVICE_ATTR_RO(raid_level);
+
+static ssize_t rebuild_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct myrb_hba *cb = shost_priv(sdev->host);
+ struct myrb_rbld_progress rbld_buf;
+ unsigned char status;
+
+ if (sdev->channel < myrb_logical_channel(sdev->host))
+ return snprintf(buf, 32, "physical device - not rebuilding\n");
+
+ status = myrb_get_rbld_progress(cb, &rbld_buf);
+
+ if (rbld_buf.ldev_num != sdev->id ||
+ status != MYRB_STATUS_SUCCESS)
+ return snprintf(buf, 32, "not rebuilding\n");
+
+ return snprintf(buf, 32, "rebuilding block %u of %u\n",
+ rbld_buf.ldev_size - rbld_buf.blocks_left,
+ rbld_buf.ldev_size);
+}
+
+static ssize_t rebuild_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct myrb_hba *cb = shost_priv(sdev->host);
+ struct myrb_cmdblk *cmd_blk;
+ union myrb_cmd_mbox *mbox;
+ unsigned short status;
+ int rc, start;
+ const char *msg;
+
+ rc = kstrtoint(buf, 0, &start);
+ if (rc)
+ return rc;
+
+ if (sdev->channel >= myrb_logical_channel(sdev->host))
+ return -ENXIO;
+
+ status = myrb_get_rbld_progress(cb, NULL);
+ if (start) {
+ if (status == MYRB_STATUS_SUCCESS) {
+ sdev_printk(KERN_INFO, sdev,
+ "Rebuild Not Initiated; already in progress\n");
+ return -EALREADY;
+ }
+ mutex_lock(&cb->dcmd_mutex);
+ cmd_blk = &cb->dcmd_blk;
+ myrb_reset_cmd(cmd_blk);
+ mbox = &cmd_blk->mbox;
+ mbox->type3D.opcode = MYRB_CMD_REBUILD_ASYNC;
+ mbox->type3D.id = MYRB_DCMD_TAG;
+ mbox->type3D.channel = sdev->channel;
+ mbox->type3D.target = sdev->id;
+ status = myrb_exec_cmd(cb, cmd_blk);
+ mutex_unlock(&cb->dcmd_mutex);
+ } else {
+ struct pci_dev *pdev = cb->pdev;
+ unsigned char *rate;
+ dma_addr_t rate_addr;
+
+ if (status != MYRB_STATUS_SUCCESS) {
+ sdev_printk(KERN_INFO, sdev,
+ "Rebuild Not Cancelled; not in progress\n");
+ return 0;
+ }
+
+ rate = dma_alloc_coherent(&pdev->dev, sizeof(char),
+ &rate_addr, GFP_KERNEL);
+ if (rate == NULL) {
+ sdev_printk(KERN_INFO, sdev,
+ "Cancellation of Rebuild Failed - Out of Memory\n");
+ return -ENOMEM;
+ }
+ mutex_lock(&cb->dcmd_mutex);
+ cmd_blk = &cb->dcmd_blk;
+ myrb_reset_cmd(cmd_blk);
+ mbox = &cmd_blk->mbox;
+ mbox->type3R.opcode = MYRB_CMD_REBUILD_CONTROL;
+ mbox->type3R.id = MYRB_DCMD_TAG;
+ mbox->type3R.rbld_rate = 0xFF;
+ mbox->type3R.addr = rate_addr;
+ status = myrb_exec_cmd(cb, cmd_blk);
+ dma_free_coherent(&pdev->dev, sizeof(char), rate, rate_addr);
+ mutex_unlock(&cb->dcmd_mutex);
+ }
+ if (status == MYRB_STATUS_SUCCESS) {
+ sdev_printk(KERN_INFO, sdev, "Rebuild %s\n",
+ start ? "Initiated" : "Cancelled");
+ return count;
+ }
+ if (!start) {
+ sdev_printk(KERN_INFO, sdev,
+ "Rebuild Not Cancelled, status 0x%x\n",
+ status);
+ return -EIO;
+ }
+
+ switch (status) {
+ case MYRB_STATUS_ATTEMPT_TO_RBLD_ONLINE_DRIVE:
+ msg = "Attempt to Rebuild Online or Unresponsive Drive";
+ break;
+ case MYRB_STATUS_RBLD_NEW_DISK_FAILED:
+ msg = "New Disk Failed During Rebuild";
+ break;
+ case MYRB_STATUS_INVALID_ADDRESS:
+ msg = "Invalid Device Address";
+ break;
+ case MYRB_STATUS_RBLD_OR_CHECK_INPROGRESS:
+ msg = "Already in Progress";
+ break;
+ default:
+ msg = NULL;
+ break;
+ }
+ if (msg)
+ sdev_printk(KERN_INFO, sdev,
+ "Rebuild Failed - %s\n", msg);
+ else
+ sdev_printk(KERN_INFO, sdev,
+ "Rebuild Failed, status 0x%x\n", status);
+
+ return -EIO;
+}
+static DEVICE_ATTR_RW(rebuild);
+
+static ssize_t consistency_check_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct myrb_hba *cb = shost_priv(sdev->host);
+ struct myrb_rbld_progress rbld_buf;
+ struct myrb_cmdblk *cmd_blk;
+ union myrb_cmd_mbox *mbox;
+ unsigned short ldev_num = 0xFFFF;
+ unsigned short status;
+ int rc, start;
+ const char *msg;
+
+ rc = kstrtoint(buf, 0, &start);
+ if (rc)
+ return rc;
+
+ if (sdev->channel < myrb_logical_channel(sdev->host))
+ return -ENXIO;
+
+ status = myrb_get_rbld_progress(cb, &rbld_buf);
+ if (start) {
+ if (status == MYRB_STATUS_SUCCESS) {
+ sdev_printk(KERN_INFO, sdev,
+ "Check Consistency Not Initiated; already in progress\n");
+ return -EALREADY;
+ }
+ mutex_lock(&cb->dcmd_mutex);
+ cmd_blk = &cb->dcmd_blk;
+ myrb_reset_cmd(cmd_blk);
+ mbox = &cmd_blk->mbox;
+ mbox->type3C.opcode = MYRB_CMD_CHECK_CONSISTENCY_ASYNC;
+ mbox->type3C.id = MYRB_DCMD_TAG;
+ mbox->type3C.ldev_num = sdev->id;
+ mbox->type3C.auto_restore = true;
+
+ status = myrb_exec_cmd(cb, cmd_blk);
+ mutex_unlock(&cb->dcmd_mutex);
+ } else {
+ struct pci_dev *pdev = cb->pdev;
+ unsigned char *rate;
+ dma_addr_t rate_addr;
+
+ if (ldev_num != sdev->id) {
+ sdev_printk(KERN_INFO, sdev,
+ "Check Consistency Not Cancelled; not in progress\n");
+ return 0;
+ }
+ rate = dma_alloc_coherent(&pdev->dev, sizeof(char),
+ &rate_addr, GFP_KERNEL);
+ if (rate == NULL) {
+ sdev_printk(KERN_INFO, sdev,
+ "Cancellation of Check Consistency Failed - Out of Memory\n");
+ return -ENOMEM;
+ }
+ mutex_lock(&cb->dcmd_mutex);
+ cmd_blk = &cb->dcmd_blk;
+ myrb_reset_cmd(cmd_blk);
+ mbox = &cmd_blk->mbox;
+ mbox->type3R.opcode = MYRB_CMD_REBUILD_CONTROL;
+ mbox->type3R.id = MYRB_DCMD_TAG;
+ mbox->type3R.rbld_rate = 0xFF;
+ mbox->type3R.addr = rate_addr;
+ status = myrb_exec_cmd(cb, cmd_blk);
+ dma_free_coherent(&pdev->dev, sizeof(char), rate, rate_addr);
+ mutex_unlock(&cb->dcmd_mutex);
+ }
+ if (status == MYRB_STATUS_SUCCESS) {
+ sdev_printk(KERN_INFO, sdev, "Check Consistency %s\n",
+ start ? "Initiated" : "Cancelled");
+ return count;
+ }
+ if (!start) {
+ sdev_printk(KERN_INFO, sdev,
+ "Check Consistency Not Cancelled, status 0x%x\n",
+ status);
+ return -EIO;
+ }
+
+ switch (status) {
+ case MYRB_STATUS_ATTEMPT_TO_RBLD_ONLINE_DRIVE:
+ msg = "Dependent Physical Device is DEAD";
+ break;
+ case MYRB_STATUS_RBLD_NEW_DISK_FAILED:
+ msg = "New Disk Failed During Rebuild";
+ break;
+ case MYRB_STATUS_INVALID_ADDRESS:
+ msg = "Invalid or Nonredundant Logical Drive";
+ break;
+ case MYRB_STATUS_RBLD_OR_CHECK_INPROGRESS:
+ msg = "Already in Progress";
+ break;
+ default:
+ msg = NULL;
+ break;
+ }
+ if (msg)
+ sdev_printk(KERN_INFO, sdev,
+ "Check Consistency Failed - %s\n", msg);
+ else
+ sdev_printk(KERN_INFO, sdev,
+ "Check Consistency Failed, status 0x%x\n", status);
+
+ return -EIO;
+}
+
+static ssize_t consistency_check_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return rebuild_show(dev, attr, buf);
+}
+static DEVICE_ATTR_RW(consistency_check);
+
+static ssize_t ctlr_num_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct myrb_hba *cb = shost_priv(shost);
+
+ return snprintf(buf, 20, "%d\n", cb->ctlr_num);
+}
+static DEVICE_ATTR_RO(ctlr_num);
+
+static ssize_t firmware_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct myrb_hba *cb = shost_priv(shost);
+
+ return snprintf(buf, 16, "%s\n", cb->fw_version);
+}
+static DEVICE_ATTR_RO(firmware);
+
+static ssize_t model_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct myrb_hba *cb = shost_priv(shost);
+
+ return snprintf(buf, 16, "%s\n", cb->model_name);
+}
+static DEVICE_ATTR_RO(model);
+
+static ssize_t flush_cache_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct myrb_hba *cb = shost_priv(shost);
+ unsigned short status;
+
+ status = myrb_exec_type3(cb, MYRB_CMD_FLUSH, 0);
+ if (status == MYRB_STATUS_SUCCESS) {
+ shost_printk(KERN_INFO, shost,
+ "Cache Flush Completed\n");
+ return count;
+ }
+ shost_printk(KERN_INFO, shost,
+ "Cache Flush Failed, status %x\n", status);
+ return -EIO;
+}
+static DEVICE_ATTR_WO(flush_cache);
+
+static struct device_attribute *myrb_sdev_attrs[] = {
+ &dev_attr_rebuild,
+ &dev_attr_consistency_check,
+ &dev_attr_raid_state,
+ &dev_attr_raid_level,
+ NULL,
+};
+
+static struct device_attribute *myrb_shost_attrs[] = {
+ &dev_attr_ctlr_num,
+ &dev_attr_model,
+ &dev_attr_firmware,
+ &dev_attr_flush_cache,
+ NULL,
+};
+
+struct scsi_host_template myrb_template = {
+ .module = THIS_MODULE,
+ .name = "DAC960",
+ .proc_name = "myrb",
+ .queuecommand = myrb_queuecommand,
+ .eh_host_reset_handler = myrb_host_reset,
+ .slave_alloc = myrb_slave_alloc,
+ .slave_configure = myrb_slave_configure,
+ .slave_destroy = myrb_slave_destroy,
+ .bios_param = myrb_biosparam,
+ .cmd_size = sizeof(struct myrb_cmdblk),
+ .shost_attrs = myrb_shost_attrs,
+ .sdev_attrs = myrb_sdev_attrs,
+ .this_id = -1,
+};
+
+/**
+ * myrb_is_raid - return boolean indicating device is raid volume
+ * @dev the device struct object
+ */
+static int myrb_is_raid(struct device *dev)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+
+ return sdev->channel == myrb_logical_channel(sdev->host);
+}
+
+/**
+ * myrb_get_resync - get raid volume resync percent complete
+ * @dev the device struct object
+ */
+static void myrb_get_resync(struct device *dev)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct myrb_hba *cb = shost_priv(sdev->host);
+ struct myrb_rbld_progress rbld_buf;
+ unsigned int percent_complete = 0;
+ unsigned short status;
+ unsigned int ldev_size = 0, remaining = 0;
+
+ if (sdev->channel < myrb_logical_channel(sdev->host))
+ return;
+ status = myrb_get_rbld_progress(cb, &rbld_buf);
+ if (status == MYRB_STATUS_SUCCESS) {
+ if (rbld_buf.ldev_num == sdev->id) {
+ ldev_size = rbld_buf.ldev_size;
+ remaining = rbld_buf.blocks_left;
+ }
+ }
+ if (remaining && ldev_size)
+ percent_complete = (ldev_size - remaining) * 100 / ldev_size;
+ raid_set_resync(myrb_raid_template, dev, percent_complete);
+}
+
+/**
+ * myrb_get_state - get raid volume status
+ * @dev the device struct object
+ */
+static void myrb_get_state(struct device *dev)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct myrb_hba *cb = shost_priv(sdev->host);
+ struct myrb_ldev_info *ldev_info = sdev->hostdata;
+ enum raid_state state = RAID_STATE_UNKNOWN;
+ unsigned short status;
+
+ if (sdev->channel < myrb_logical_channel(sdev->host) || !ldev_info)
+ state = RAID_STATE_UNKNOWN;
+ else {
+ status = myrb_get_rbld_progress(cb, NULL);
+ if (status == MYRB_STATUS_SUCCESS)
+ state = RAID_STATE_RESYNCING;
+ else {
+ switch (ldev_info->state) {
+ case MYRB_DEVICE_ONLINE:
+ state = RAID_STATE_ACTIVE;
+ break;
+ case MYRB_DEVICE_WO:
+ case MYRB_DEVICE_CRITICAL:
+ state = RAID_STATE_DEGRADED;
+ break;
+ default:
+ state = RAID_STATE_OFFLINE;
+ }
+ }
+ }
+ raid_set_state(myrb_raid_template, dev, state);
+}
+
+struct raid_function_template myrb_raid_functions = {
+ .cookie = &myrb_template,
+ .is_raid = myrb_is_raid,
+ .get_resync = myrb_get_resync,
+ .get_state = myrb_get_state,
+};
+
+static void myrb_handle_scsi(struct myrb_hba *cb, struct myrb_cmdblk *cmd_blk,
+ struct scsi_cmnd *scmd)
+{
+ unsigned short status;
+
+ if (!cmd_blk)
+ return;
+
+ scsi_dma_unmap(scmd);
+
+ if (cmd_blk->dcdb) {
+ memcpy(scmd->sense_buffer, &cmd_blk->dcdb->sense, 64);
+ dma_pool_free(cb->dcdb_pool, cmd_blk->dcdb,
+ cmd_blk->dcdb_addr);
+ cmd_blk->dcdb = NULL;
+ }
+ if (cmd_blk->sgl) {
+ dma_pool_free(cb->sg_pool, cmd_blk->sgl, cmd_blk->sgl_addr);
+ cmd_blk->sgl = NULL;
+ cmd_blk->sgl_addr = 0;
+ }
+ status = cmd_blk->status;
+ switch (status) {
+ case MYRB_STATUS_SUCCESS:
+ case MYRB_STATUS_DEVICE_BUSY:
+ scmd->result = (DID_OK << 16) | status;
+ break;
+ case MYRB_STATUS_BAD_DATA:
+ dev_dbg(&scmd->device->sdev_gendev,
+ "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);
+ else
+ /* Write error */
+ scsi_build_sense_buffer(0, scmd->sense_buffer,
+ MEDIUM_ERROR, 0x0C, 0);
+ scmd->result = (DID_OK << 16) | SAM_STAT_CHECK_CONDITION;
+ 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);
+ 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;
+ break;
+ case MYRB_STATUS_LDRV_NONEXISTENT_OR_OFFLINE:
+ dev_dbg(&scmd->device->sdev_gendev,
+ "Logical Drive Nonexistent or Offline");
+ scmd->result = (DID_BAD_TARGET << 16);
+ break;
+ case MYRB_STATUS_ACCESS_BEYOND_END_OF_LDRV:
+ 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);
+ break;
+ case MYRB_STATUS_DEVICE_NONRESPONSIVE:
+ dev_dbg(&scmd->device->sdev_gendev, "Device nonresponsive\n");
+ scmd->result = (DID_BAD_TARGET << 16);
+ break;
+ default:
+ scmd_printk(KERN_ERR, scmd,
+ "Unexpected Error Status %04X", status);
+ scmd->result = (DID_ERROR << 16);
+ break;
+ }
+ scmd->scsi_done(scmd);
+}
+
+static void myrb_handle_cmdblk(struct myrb_hba *cb, struct myrb_cmdblk *cmd_blk)
+{
+ if (!cmd_blk)
+ return;
+
+ if (cmd_blk->completion) {
+ complete(cmd_blk->completion);
+ cmd_blk->completion = NULL;
+ }
+}
+
+static void myrb_monitor(struct work_struct *work)
+{
+ struct myrb_hba *cb = container_of(work,
+ struct myrb_hba, monitor_work.work);
+ struct Scsi_Host *shost = cb->host;
+ unsigned long interval = MYRB_PRIMARY_MONITOR_INTERVAL;
+
+ dev_dbg(&shost->shost_gendev, "monitor tick\n");
+
+ if (cb->new_ev_seq > cb->old_ev_seq) {
+ int event = cb->old_ev_seq;
+
+ dev_dbg(&shost->shost_gendev,
+ "get event log no %d/%d\n",
+ cb->new_ev_seq, event);
+ myrb_get_event(cb, event);
+ cb->old_ev_seq = event + 1;
+ interval = 10;
+ } else if (cb->need_err_info) {
+ cb->need_err_info = false;
+ dev_dbg(&shost->shost_gendev, "get error table\n");
+ myrb_get_errtable(cb);
+ interval = 10;
+ } else if (cb->need_rbld && cb->rbld_first) {
+ cb->need_rbld = false;
+ dev_dbg(&shost->shost_gendev,
+ "get rebuild progress\n");
+ myrb_update_rbld_progress(cb);
+ interval = 10;
+ } else if (cb->need_ldev_info) {
+ cb->need_ldev_info = false;
+ dev_dbg(&shost->shost_gendev,
+ "get logical drive info\n");
+ myrb_get_ldev_info(cb);
+ interval = 10;
+ } else if (cb->need_rbld) {
+ cb->need_rbld = false;
+ dev_dbg(&shost->shost_gendev,
+ "get rebuild progress\n");
+ myrb_update_rbld_progress(cb);
+ interval = 10;
+ } else if (cb->need_cc_status) {
+ cb->need_cc_status = false;
+ dev_dbg(&shost->shost_gendev,
+ "get consistency check progress\n");
+ myrb_get_cc_progress(cb);
+ interval = 10;
+ } else if (cb->need_bgi_status) {
+ cb->need_bgi_status = false;
+ dev_dbg(&shost->shost_gendev, "get background init status\n");
+ myrb_bgi_control(cb);
+ interval = 10;
+ } else {
+ dev_dbg(&shost->shost_gendev, "new enquiry\n");
+ mutex_lock(&cb->dma_mutex);
+ myrb_hba_enquiry(cb);
+ mutex_unlock(&cb->dma_mutex);
+ if ((cb->new_ev_seq - cb->old_ev_seq > 0) ||
+ cb->need_err_info || cb->need_rbld ||
+ cb->need_ldev_info || cb->need_cc_status ||
+ cb->need_bgi_status) {
+ dev_dbg(&shost->shost_gendev,
+ "reschedule monitor\n");
+ interval = 0;
+ }
+ }
+ if (interval > 1)
+ cb->primary_monitor_time = jiffies;
+ queue_delayed_work(cb->work_q, &cb->monitor_work, interval);
+}
+
+/**
+ * myrb_err_status - reports controller BIOS messages
+ *
+ * Controller BIOS messages are passed through the Error Status Register
+ * when the driver performs the BIOS handshaking.
+ *
+ * Return: true for fatal errors and false otherwise.
+ */
+bool myrb_err_status(struct myrb_hba *cb, unsigned char error,
+ unsigned char parm0, unsigned char parm1)
+{
+ struct pci_dev *pdev = cb->pdev;
+
+ switch (error) {
+ case 0x00:
+ dev_info(&pdev->dev,
+ "Physical Device %d:%d Not Responding\n",
+ parm1, parm0);
+ break;
+ case 0x08:
+ dev_notice(&pdev->dev, "Spinning Up Drives\n");
+ break;
+ case 0x30:
+ dev_notice(&pdev->dev, "Configuration Checksum Error\n");
+ break;
+ case 0x60:
+ dev_notice(&pdev->dev, "Mirror Race Recovery Failed\n");
+ break;
+ case 0x70:
+ dev_notice(&pdev->dev, "Mirror Race Recovery In Progress\n");
+ break;
+ case 0x90:
+ dev_notice(&pdev->dev, "Physical Device %d:%d COD Mismatch\n",
+ parm1, parm0);
+ break;
+ case 0xA0:
+ dev_notice(&pdev->dev, "Logical Drive Installation Aborted\n");
+ break;
+ case 0xB0:
+ dev_notice(&pdev->dev, "Mirror Race On A Critical Logical Drive\n");
+ break;
+ case 0xD0:
+ dev_notice(&pdev->dev, "New Controller Configuration Found\n");
+ break;
+ case 0xF0:
+ dev_err(&pdev->dev, "Fatal Memory Parity Error\n");
+ return true;
+ default:
+ dev_err(&pdev->dev, "Unknown Initialization Error %02X\n",
+ error);
+ return true;
+ }
+ return false;
+}
+
+/*
+ * Hardware-specific functions
+ */
+
+/*
+ * DAC960 LA Series Controllers
+ */
+
+static inline void DAC960_LA_hw_mbox_new_cmd(void __iomem *base)
+{
+ writeb(DAC960_LA_IDB_HWMBOX_NEW_CMD, base + DAC960_LA_IDB_OFFSET);
+}
+
+static inline void DAC960_LA_ack_hw_mbox_status(void __iomem *base)
+{
+ writeb(DAC960_LA_IDB_HWMBOX_ACK_STS, base + DAC960_LA_IDB_OFFSET);
+}
+
+static inline void DAC960_LA_gen_intr(void __iomem *base)
+{
+ writeb(DAC960_LA_IDB_GEN_IRQ, base + DAC960_LA_IDB_OFFSET);
+}
+
+static inline void DAC960_LA_reset_ctrl(void __iomem *base)
+{
+ writeb(DAC960_LA_IDB_CTRL_RESET, base + DAC960_LA_IDB_OFFSET);
+}
+
+static inline void DAC960_LA_mem_mbox_new_cmd(void __iomem *base)
+{
+ writeb(DAC960_LA_IDB_MMBOX_NEW_CMD, base + DAC960_LA_IDB_OFFSET);
+}
+
+static inline bool DAC960_LA_hw_mbox_is_full(void __iomem *base)
+{
+ unsigned char idb = readb(base + DAC960_LA_IDB_OFFSET);
+
+ return !(idb & DAC960_LA_IDB_HWMBOX_EMPTY);
+}
+
+static inline bool DAC960_LA_init_in_progress(void __iomem *base)
+{
+ unsigned char idb = readb(base + DAC960_LA_IDB_OFFSET);
+
+ return !(idb & DAC960_LA_IDB_INIT_DONE);
+}
+
+static inline void DAC960_LA_ack_hw_mbox_intr(void __iomem *base)
+{
+ writeb(DAC960_LA_ODB_HWMBOX_ACK_IRQ, base + DAC960_LA_ODB_OFFSET);
+}
+
+static inline void DAC960_LA_ack_mem_mbox_intr(void __iomem *base)
+{
+ writeb(DAC960_LA_ODB_MMBOX_ACK_IRQ, base + DAC960_LA_ODB_OFFSET);
+}
+
+static inline void DAC960_LA_ack_intr(void __iomem *base)
+{
+ writeb(DAC960_LA_ODB_HWMBOX_ACK_IRQ | DAC960_LA_ODB_MMBOX_ACK_IRQ,
+ base + DAC960_LA_ODB_OFFSET);
+}
+
+static inline bool DAC960_LA_hw_mbox_status_available(void __iomem *base)
+{
+ unsigned char odb = readb(base + DAC960_LA_ODB_OFFSET);
+
+ return odb & DAC960_LA_ODB_HWMBOX_STS_AVAIL;
+}
+
+static inline bool DAC960_LA_mem_mbox_status_available(void __iomem *base)
+{
+ unsigned char odb = readb(base + DAC960_LA_ODB_OFFSET);
+
+ return odb & DAC960_LA_ODB_MMBOX_STS_AVAIL;
+}
+
+static inline void DAC960_LA_enable_intr(void __iomem *base)
+{
+ unsigned char odb = 0xFF;
+
+ odb &= ~DAC960_LA_IRQMASK_DISABLE_IRQ;
+ writeb(odb, base + DAC960_LA_IRQMASK_OFFSET);
+}
+
+static inline void DAC960_LA_disable_intr(void __iomem *base)
+{
+ unsigned char odb = 0xFF;
+
+ odb |= DAC960_LA_IRQMASK_DISABLE_IRQ;
+ writeb(odb, base + DAC960_LA_IRQMASK_OFFSET);
+}
+
+static inline bool DAC960_LA_intr_enabled(void __iomem *base)
+{
+ unsigned char imask = readb(base + DAC960_LA_IRQMASK_OFFSET);
+
+ return !(imask & DAC960_LA_IRQMASK_DISABLE_IRQ);
+}
+
+static inline void DAC960_LA_write_cmd_mbox(union myrb_cmd_mbox *mem_mbox,
+ union myrb_cmd_mbox *mbox)
+{
+ mem_mbox->words[1] = mbox->words[1];
+ mem_mbox->words[2] = mbox->words[2];
+ mem_mbox->words[3] = mbox->words[3];
+ /* Memory barrier to prevent reordering */
+ wmb();
+ mem_mbox->words[0] = mbox->words[0];
+ /* Memory barrier to force PCI access */
+ mb();
+}
+
+static inline void DAC960_LA_write_hw_mbox(void __iomem *base,
+ union myrb_cmd_mbox *mbox)
+{
+ writel(mbox->words[0], base + DAC960_LA_CMDOP_OFFSET);
+ writel(mbox->words[1], base + DAC960_LA_MBOX4_OFFSET);
+ writel(mbox->words[2], base + DAC960_LA_MBOX8_OFFSET);
+ writeb(mbox->bytes[12], base + DAC960_LA_MBOX12_OFFSET);
+}
+
+static inline unsigned char DAC960_LA_read_status_cmd_ident(void __iomem *base)
+{
+ return readb(base + DAC960_LA_STSID_OFFSET);
+}
+
+static inline unsigned short DAC960_LA_read_status(void __iomem *base)
+{
+ return readw(base + DAC960_LA_STS_OFFSET);
+}
+
+static inline bool
+DAC960_LA_read_error_status(void __iomem *base, unsigned char *error,
+ unsigned char *param0, unsigned char *param1)
+{
+ unsigned char errsts = readb(base + DAC960_LA_ERRSTS_OFFSET);
+
+ if (!(errsts & DAC960_LA_ERRSTS_PENDING))
+ return false;
+ errsts &= ~DAC960_LA_ERRSTS_PENDING;
+
+ *error = errsts;
+ *param0 = readb(base + DAC960_LA_CMDOP_OFFSET);
+ *param1 = readb(base + DAC960_LA_CMDID_OFFSET);
+ writeb(0xFF, base + DAC960_LA_ERRSTS_OFFSET);
+ return true;
+}
+
+static inline unsigned short
+DAC960_LA_mbox_init(struct pci_dev *pdev, void __iomem *base,
+ union myrb_cmd_mbox *mbox)
+{
+ unsigned short status;
+ int timeout = 0;
+
+ while (timeout < MYRB_MAILBOX_TIMEOUT) {
+ if (!DAC960_LA_hw_mbox_is_full(base))
+ break;
+ udelay(10);
+ timeout++;
+ }
+ if (DAC960_LA_hw_mbox_is_full(base)) {
+ dev_err(&pdev->dev,
+ "Timeout waiting for empty mailbox\n");
+ return MYRB_STATUS_SUBSYS_TIMEOUT;
+ }
+ DAC960_LA_write_hw_mbox(base, mbox);
+ DAC960_LA_hw_mbox_new_cmd(base);
+ timeout = 0;
+ while (timeout < MYRB_MAILBOX_TIMEOUT) {
+ if (DAC960_LA_hw_mbox_status_available(base))
+ break;
+ udelay(10);
+ timeout++;
+ }
+ if (!DAC960_LA_hw_mbox_status_available(base)) {
+ dev_err(&pdev->dev, "Timeout waiting for mailbox status\n");
+ return MYRB_STATUS_SUBSYS_TIMEOUT;
+ }
+ status = DAC960_LA_read_status(base);
+ DAC960_LA_ack_hw_mbox_intr(base);
+ DAC960_LA_ack_hw_mbox_status(base);
+
+ return status;
+}
+
+static int DAC960_LA_hw_init(struct pci_dev *pdev,
+ struct myrb_hba *cb, void __iomem *base)
+{
+ int timeout = 0;
+ unsigned char error, parm0, parm1;
+
+ DAC960_LA_disable_intr(base);
+ DAC960_LA_ack_hw_mbox_status(base);
+ udelay(1000);
+ timeout = 0;
+ while (DAC960_LA_init_in_progress(base) &&
+ timeout < MYRB_MAILBOX_TIMEOUT) {
+ if (DAC960_LA_read_error_status(base, &error,
+ &parm0, &parm1) &&
+ myrb_err_status(cb, error, parm0, parm1))
+ return -ENODEV;
+ udelay(10);
+ timeout++;
+ }
+ if (timeout == MYRB_MAILBOX_TIMEOUT) {
+ dev_err(&pdev->dev,
+ "Timeout waiting for Controller Initialisation\n");
+ return -ETIMEDOUT;
+ }
+ if (!myrb_enable_mmio(cb, DAC960_LA_mbox_init)) {
+ dev_err(&pdev->dev,
+ "Unable to Enable Memory Mailbox Interface\n");
+ DAC960_LA_reset_ctrl(base);
+ return -ENODEV;
+ }
+ DAC960_LA_enable_intr(base);
+ cb->qcmd = myrb_qcmd;
+ cb->write_cmd_mbox = DAC960_LA_write_cmd_mbox;
+ if (cb->dual_mode_interface)
+ cb->get_cmd_mbox = DAC960_LA_mem_mbox_new_cmd;
+ else
+ cb->get_cmd_mbox = DAC960_LA_hw_mbox_new_cmd;
+ cb->disable_intr = DAC960_LA_disable_intr;
+ cb->reset = DAC960_LA_reset_ctrl;
+
+ return 0;
+}
+
+static irqreturn_t DAC960_LA_intr_handler(int irq, void *arg)
+{
+ struct myrb_hba *cb = arg;
+ void __iomem *base = cb->io_base;
+ struct myrb_stat_mbox *next_stat_mbox;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cb->queue_lock, flags);
+ DAC960_LA_ack_intr(base);
+ next_stat_mbox = cb->next_stat_mbox;
+ while (next_stat_mbox->valid) {
+ unsigned char id = next_stat_mbox->id;
+ struct scsi_cmnd *scmd = NULL;
+ struct myrb_cmdblk *cmd_blk = NULL;
+
+ if (id == MYRB_DCMD_TAG)
+ cmd_blk = &cb->dcmd_blk;
+ else if (id == MYRB_MCMD_TAG)
+ cmd_blk = &cb->mcmd_blk;
+ else {
+ scmd = scsi_host_find_tag(cb->host, id - 3);
+ if (scmd)
+ cmd_blk = scsi_cmd_priv(scmd);
+ }
+ if (cmd_blk)
+ cmd_blk->status = next_stat_mbox->status;
+ else
+ dev_err(&cb->pdev->dev,
+ "Unhandled command completion %d\n", id);
+
+ memset(next_stat_mbox, 0, sizeof(struct myrb_stat_mbox));
+ if (++next_stat_mbox > cb->last_stat_mbox)
+ next_stat_mbox = cb->first_stat_mbox;
+
+ if (cmd_blk) {
+ if (id < 3)
+ myrb_handle_cmdblk(cb, cmd_blk);
+ else
+ myrb_handle_scsi(cb, cmd_blk, scmd);
+ }
+ }
+ cb->next_stat_mbox = next_stat_mbox;
+ spin_unlock_irqrestore(&cb->queue_lock, flags);
+ return IRQ_HANDLED;
+}
+
+struct myrb_privdata DAC960_LA_privdata = {
+ .hw_init = DAC960_LA_hw_init,
+ .irq_handler = DAC960_LA_intr_handler,
+ .mmio_size = DAC960_LA_mmio_size,
+};
+
+/*
+ * DAC960 PG Series Controllers
+ */
+static inline void DAC960_PG_hw_mbox_new_cmd(void __iomem *base)
+{
+ writel(DAC960_PG_IDB_HWMBOX_NEW_CMD, base + DAC960_PG_IDB_OFFSET);
+}
+
+static inline void DAC960_PG_ack_hw_mbox_status(void __iomem *base)
+{
+ writel(DAC960_PG_IDB_HWMBOX_ACK_STS, base + DAC960_PG_IDB_OFFSET);
+}
+
+static inline void DAC960_PG_gen_intr(void __iomem *base)
+{
+ writel(DAC960_PG_IDB_GEN_IRQ, base + DAC960_PG_IDB_OFFSET);
+}
+
+static inline void DAC960_PG_reset_ctrl(void __iomem *base)
+{
+ writel(DAC960_PG_IDB_CTRL_RESET, base + DAC960_PG_IDB_OFFSET);
+}
+
+static inline void DAC960_PG_mem_mbox_new_cmd(void __iomem *base)
+{
+ writel(DAC960_PG_IDB_MMBOX_NEW_CMD, base + DAC960_PG_IDB_OFFSET);
+}
+
+static inline bool DAC960_PG_hw_mbox_is_full(void __iomem *base)
+{
+ unsigned char idb = readl(base + DAC960_PG_IDB_OFFSET);
+
+ return idb & DAC960_PG_IDB_HWMBOX_FULL;
+}
+
+static inline bool DAC960_PG_init_in_progress(void __iomem *base)
+{
+ unsigned char idb = readl(base + DAC960_PG_IDB_OFFSET);
+
+ return idb & DAC960_PG_IDB_INIT_IN_PROGRESS;
+}
+
+static inline void DAC960_PG_ack_hw_mbox_intr(void __iomem *base)
+{
+ writel(DAC960_PG_ODB_HWMBOX_ACK_IRQ, base + DAC960_PG_ODB_OFFSET);
+}
+
+static inline void DAC960_PG_ack_mem_mbox_intr(void __iomem *base)
+{
+ writel(DAC960_PG_ODB_MMBOX_ACK_IRQ, base + DAC960_PG_ODB_OFFSET);
+}
+
+static inline void DAC960_PG_ack_intr(void __iomem *base)
+{
+ writel(DAC960_PG_ODB_HWMBOX_ACK_IRQ | DAC960_PG_ODB_MMBOX_ACK_IRQ,
+ base + DAC960_PG_ODB_OFFSET);
+}
+
+static inline bool DAC960_PG_hw_mbox_status_available(void __iomem *base)
+{
+ unsigned char odb = readl(base + DAC960_PG_ODB_OFFSET);
+
+ return odb & DAC960_PG_ODB_HWMBOX_STS_AVAIL;
+}
+
+static inline bool DAC960_PG_mem_mbox_status_available(void __iomem *base)
+{
+ unsigned char odb = readl(base + DAC960_PG_ODB_OFFSET);
+
+ return odb & DAC960_PG_ODB_MMBOX_STS_AVAIL;
+}
+
+static inline void DAC960_PG_enable_intr(void __iomem *base)
+{
+ unsigned int imask = (unsigned int)-1;
+
+ imask &= ~DAC960_PG_IRQMASK_DISABLE_IRQ;
+ writel(imask, base + DAC960_PG_IRQMASK_OFFSET);
+}
+
+static inline void DAC960_PG_disable_intr(void __iomem *base)
+{
+ unsigned int imask = (unsigned int)-1;
+
+ writel(imask, base + DAC960_PG_IRQMASK_OFFSET);
+}
+
+static inline bool DAC960_PG_intr_enabled(void __iomem *base)
+{
+ unsigned int imask = readl(base + DAC960_PG_IRQMASK_OFFSET);
+
+ return !(imask & DAC960_PG_IRQMASK_DISABLE_IRQ);
+}
+
+static inline void DAC960_PG_write_cmd_mbox(union myrb_cmd_mbox *mem_mbox,
+ union myrb_cmd_mbox *mbox)
+{
+ mem_mbox->words[1] = mbox->words[1];
+ mem_mbox->words[2] = mbox->words[2];
+ mem_mbox->words[3] = mbox->words[3];
+ /* Memory barrier to prevent reordering */
+ wmb();
+ mem_mbox->words[0] = mbox->words[0];
+ /* Memory barrier to force PCI access */
+ mb();
+}
+
+static inline void DAC960_PG_write_hw_mbox(void __iomem *base,
+ union myrb_cmd_mbox *mbox)
+{
+ writel(mbox->words[0], base + DAC960_PG_CMDOP_OFFSET);
+ writel(mbox->words[1], base + DAC960_PG_MBOX4_OFFSET);
+ writel(mbox->words[2], base + DAC960_PG_MBOX8_OFFSET);
+ writeb(mbox->bytes[12], base + DAC960_PG_MBOX12_OFFSET);
+}
+
+static inline unsigned char
+DAC960_PG_read_status_cmd_ident(void __iomem *base)
+{
+ return readb(base + DAC960_PG_STSID_OFFSET);
+}
+
+static inline unsigned short
+DAC960_PG_read_status(void __iomem *base)
+{
+ return readw(base + DAC960_PG_STS_OFFSET);
+}
+
+static inline bool
+DAC960_PG_read_error_status(void __iomem *base, unsigned char *error,
+ unsigned char *param0, unsigned char *param1)
+{
+ unsigned char errsts = readb(base + DAC960_PG_ERRSTS_OFFSET);
+
+ if (!(errsts & DAC960_PG_ERRSTS_PENDING))
+ return false;
+ errsts &= ~DAC960_PG_ERRSTS_PENDING;
+ *error = errsts;
+ *param0 = readb(base + DAC960_PG_CMDOP_OFFSET);
+ *param1 = readb(base + DAC960_PG_CMDID_OFFSET);
+ writeb(0, base + DAC960_PG_ERRSTS_OFFSET);
+ return true;
+}
+
+static inline unsigned short
+DAC960_PG_mbox_init(struct pci_dev *pdev, void __iomem *base,
+ union myrb_cmd_mbox *mbox)
+{
+ unsigned short status;
+ int timeout = 0;
+
+ while (timeout < MYRB_MAILBOX_TIMEOUT) {
+ if (!DAC960_PG_hw_mbox_is_full(base))
+ break;
+ udelay(10);
+ timeout++;
+ }
+ if (DAC960_PG_hw_mbox_is_full(base)) {
+ dev_err(&pdev->dev,
+ "Timeout waiting for empty mailbox\n");
+ return MYRB_STATUS_SUBSYS_TIMEOUT;
+ }
+ DAC960_PG_write_hw_mbox(base, mbox);
+ DAC960_PG_hw_mbox_new_cmd(base);
+
+ timeout = 0;
+ while (timeout < MYRB_MAILBOX_TIMEOUT) {
+ if (DAC960_PG_hw_mbox_status_available(base))
+ break;
+ udelay(10);
+ timeout++;
+ }
+ if (!DAC960_PG_hw_mbox_status_available(base)) {
+ dev_err(&pdev->dev,
+ "Timeout waiting for mailbox status\n");
+ return MYRB_STATUS_SUBSYS_TIMEOUT;
+ }
+ status = DAC960_PG_read_status(base);
+ DAC960_PG_ack_hw_mbox_intr(base);
+ DAC960_PG_ack_hw_mbox_status(base);
+
+ return status;
+}
+
+static int DAC960_PG_hw_init(struct pci_dev *pdev,
+ struct myrb_hba *cb, void __iomem *base)
+{
+ int timeout = 0;
+ unsigned char error, parm0, parm1;
+
+ DAC960_PG_disable_intr(base);
+ DAC960_PG_ack_hw_mbox_status(base);
+ udelay(1000);
+ while (DAC960_PG_init_in_progress(base) &&
+ timeout < MYRB_MAILBOX_TIMEOUT) {
+ if (DAC960_PG_read_error_status(base, &error,
+ &parm0, &parm1) &&
+ myrb_err_status(cb, error, parm0, parm1))
+ return -EIO;
+ udelay(10);
+ timeout++;
+ }
+ if (timeout == MYRB_MAILBOX_TIMEOUT) {
+ dev_err(&pdev->dev,
+ "Timeout waiting for Controller Initialisation\n");
+ return -ETIMEDOUT;
+ }
+ if (!myrb_enable_mmio(cb, DAC960_PG_mbox_init)) {
+ dev_err(&pdev->dev,
+ "Unable to Enable Memory Mailbox Interface\n");
+ DAC960_PG_reset_ctrl(base);
+ return -ENODEV;
+ }
+ DAC960_PG_enable_intr(base);
+ cb->qcmd = myrb_qcmd;
+ cb->write_cmd_mbox = DAC960_PG_write_cmd_mbox;
+ if (cb->dual_mode_interface)
+ cb->get_cmd_mbox = DAC960_PG_mem_mbox_new_cmd;
+ else
+ cb->get_cmd_mbox = DAC960_PG_hw_mbox_new_cmd;
+ cb->disable_intr = DAC960_PG_disable_intr;
+ cb->reset = DAC960_PG_reset_ctrl;
+
+ return 0;
+}
+
+static irqreturn_t DAC960_PG_intr_handler(int irq, void *arg)
+{
+ struct myrb_hba *cb = arg;
+ void __iomem *base = cb->io_base;
+ struct myrb_stat_mbox *next_stat_mbox;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cb->queue_lock, flags);
+ DAC960_PG_ack_intr(base);
+ next_stat_mbox = cb->next_stat_mbox;
+ while (next_stat_mbox->valid) {
+ unsigned char id = next_stat_mbox->id;
+ struct scsi_cmnd *scmd = NULL;
+ struct myrb_cmdblk *cmd_blk = NULL;
+
+ if (id == MYRB_DCMD_TAG)
+ cmd_blk = &cb->dcmd_blk;
+ else if (id == MYRB_MCMD_TAG)
+ cmd_blk = &cb->mcmd_blk;
+ else {
+ scmd = scsi_host_find_tag(cb->host, id - 3);
+ if (scmd)
+ cmd_blk = scsi_cmd_priv(scmd);
+ }
+ if (cmd_blk)
+ cmd_blk->status = next_stat_mbox->status;
+ else
+ dev_err(&cb->pdev->dev,
+ "Unhandled command completion %d\n", id);
+
+ memset(next_stat_mbox, 0, sizeof(struct myrb_stat_mbox));
+ if (++next_stat_mbox > cb->last_stat_mbox)
+ next_stat_mbox = cb->first_stat_mbox;
+
+ if (id < 3)
+ myrb_handle_cmdblk(cb, cmd_blk);
+ else
+ myrb_handle_scsi(cb, cmd_blk, scmd);
+ }
+ cb->next_stat_mbox = next_stat_mbox;
+ spin_unlock_irqrestore(&cb->queue_lock, flags);
+ return IRQ_HANDLED;
+}
+
+struct myrb_privdata DAC960_PG_privdata = {
+ .hw_init = DAC960_PG_hw_init,
+ .irq_handler = DAC960_PG_intr_handler,
+ .mmio_size = DAC960_PG_mmio_size,
+};
+
+
+/*
+ * DAC960 PD Series Controllers
+ */
+
+static inline void DAC960_PD_hw_mbox_new_cmd(void __iomem *base)
+{
+ writeb(DAC960_PD_IDB_HWMBOX_NEW_CMD, base + DAC960_PD_IDB_OFFSET);
+}
+
+static inline void DAC960_PD_ack_hw_mbox_status(void __iomem *base)
+{
+ writeb(DAC960_PD_IDB_HWMBOX_ACK_STS, base + DAC960_PD_IDB_OFFSET);
+}
+
+static inline void DAC960_PD_gen_intr(void __iomem *base)
+{
+ writeb(DAC960_PD_IDB_GEN_IRQ, base + DAC960_PD_IDB_OFFSET);
+}
+
+static inline void DAC960_PD_reset_ctrl(void __iomem *base)
+{
+ writeb(DAC960_PD_IDB_CTRL_RESET, base + DAC960_PD_IDB_OFFSET);
+}
+
+static inline bool DAC960_PD_hw_mbox_is_full(void __iomem *base)
+{
+ unsigned char idb = readb(base + DAC960_PD_IDB_OFFSET);
+
+ return idb & DAC960_PD_IDB_HWMBOX_FULL;
+}
+
+static inline bool DAC960_PD_init_in_progress(void __iomem *base)
+{
+ unsigned char idb = readb(base + DAC960_PD_IDB_OFFSET);
+
+ return idb & DAC960_PD_IDB_INIT_IN_PROGRESS;
+}
+
+static inline void DAC960_PD_ack_intr(void __iomem *base)
+{
+ writeb(DAC960_PD_ODB_HWMBOX_ACK_IRQ, base + DAC960_PD_ODB_OFFSET);
+}
+
+static inline bool DAC960_PD_hw_mbox_status_available(void __iomem *base)
+{
+ unsigned char odb = readb(base + DAC960_PD_ODB_OFFSET);
+
+ return odb & DAC960_PD_ODB_HWMBOX_STS_AVAIL;
+}
+
+static inline void DAC960_PD_enable_intr(void __iomem *base)
+{
+ writeb(DAC960_PD_IRQMASK_ENABLE_IRQ, base + DAC960_PD_IRQEN_OFFSET);
+}
+
+static inline void DAC960_PD_disable_intr(void __iomem *base)
+{
+ writeb(0, base + DAC960_PD_IRQEN_OFFSET);
+}
+
+static inline bool DAC960_PD_intr_enabled(void __iomem *base)
+{
+ unsigned char imask = readb(base + DAC960_PD_IRQEN_OFFSET);
+
+ return imask & DAC960_PD_IRQMASK_ENABLE_IRQ;
+}
+
+static inline void DAC960_PD_write_cmd_mbox(void __iomem *base,
+ union myrb_cmd_mbox *mbox)
+{
+ writel(mbox->words[0], base + DAC960_PD_CMDOP_OFFSET);
+ writel(mbox->words[1], base + DAC960_PD_MBOX4_OFFSET);
+ writel(mbox->words[2], base + DAC960_PD_MBOX8_OFFSET);
+ writeb(mbox->bytes[12], base + DAC960_PD_MBOX12_OFFSET);
+}
+
+static inline unsigned char
+DAC960_PD_read_status_cmd_ident(void __iomem *base)
+{
+ return readb(base + DAC960_PD_STSID_OFFSET);
+}
+
+static inline unsigned short
+DAC960_PD_read_status(void __iomem *base)
+{
+ return readw(base + DAC960_PD_STS_OFFSET);
+}
+
+static inline bool
+DAC960_PD_read_error_status(void __iomem *base, unsigned char *error,
+ unsigned char *param0, unsigned char *param1)
+{
+ unsigned char errsts = readb(base + DAC960_PD_ERRSTS_OFFSET);
+
+ if (!(errsts & DAC960_PD_ERRSTS_PENDING))
+ return false;
+ errsts &= ~DAC960_PD_ERRSTS_PENDING;
+ *error = errsts;
+ *param0 = readb(base + DAC960_PD_CMDOP_OFFSET);
+ *param1 = readb(base + DAC960_PD_CMDID_OFFSET);
+ writeb(0, base + DAC960_PD_ERRSTS_OFFSET);
+ return true;
+}
+
+static void DAC960_PD_qcmd(struct myrb_hba *cb, struct myrb_cmdblk *cmd_blk)
+{
+ void __iomem *base = cb->io_base;
+ union myrb_cmd_mbox *mbox = &cmd_blk->mbox;
+
+ while (DAC960_PD_hw_mbox_is_full(base))
+ udelay(1);
+ DAC960_PD_write_cmd_mbox(base, mbox);
+ DAC960_PD_hw_mbox_new_cmd(base);
+}
+
+static int DAC960_PD_hw_init(struct pci_dev *pdev,
+ struct myrb_hba *cb, void __iomem *base)
+{
+ int timeout = 0;
+ unsigned char error, parm0, parm1;
+
+ if (!request_region(cb->io_addr, 0x80, "myrb")) {
+ dev_err(&pdev->dev, "IO port 0x%lx busy\n",
+ (unsigned long)cb->io_addr);
+ return -EBUSY;
+ }
+ DAC960_PD_disable_intr(base);
+ DAC960_PD_ack_hw_mbox_status(base);
+ udelay(1000);
+ while (DAC960_PD_init_in_progress(base) &&
+ timeout < MYRB_MAILBOX_TIMEOUT) {
+ if (DAC960_PD_read_error_status(base, &error,
+ &parm0, &parm1) &&
+ myrb_err_status(cb, error, parm0, parm1))
+ return -EIO;
+ udelay(10);
+ timeout++;
+ }
+ if (timeout == MYRB_MAILBOX_TIMEOUT) {
+ dev_err(&pdev->dev,
+ "Timeout waiting for Controller Initialisation\n");
+ return -ETIMEDOUT;
+ }
+ if (!myrb_enable_mmio(cb, NULL)) {
+ dev_err(&pdev->dev,
+ "Unable to Enable Memory Mailbox Interface\n");
+ DAC960_PD_reset_ctrl(base);
+ return -ENODEV;
+ }
+ DAC960_PD_enable_intr(base);
+ cb->qcmd = DAC960_PD_qcmd;
+ cb->disable_intr = DAC960_PD_disable_intr;
+ cb->reset = DAC960_PD_reset_ctrl;
+
+ return 0;
+}
+
+static irqreturn_t DAC960_PD_intr_handler(int irq, void *arg)
+{
+ struct myrb_hba *cb = arg;
+ void __iomem *base = cb->io_base;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cb->queue_lock, flags);
+ while (DAC960_PD_hw_mbox_status_available(base)) {
+ unsigned char id = DAC960_PD_read_status_cmd_ident(base);
+ struct scsi_cmnd *scmd = NULL;
+ struct myrb_cmdblk *cmd_blk = NULL;
+
+ if (id == MYRB_DCMD_TAG)
+ cmd_blk = &cb->dcmd_blk;
+ else if (id == MYRB_MCMD_TAG)
+ cmd_blk = &cb->mcmd_blk;
+ else {
+ scmd = scsi_host_find_tag(cb->host, id - 3);
+ if (scmd)
+ cmd_blk = scsi_cmd_priv(scmd);
+ }
+ if (cmd_blk)
+ cmd_blk->status = DAC960_PD_read_status(base);
+ else
+ dev_err(&cb->pdev->dev,
+ "Unhandled command completion %d\n", id);
+
+ DAC960_PD_ack_intr(base);
+ DAC960_PD_ack_hw_mbox_status(base);
+
+ if (id < 3)
+ myrb_handle_cmdblk(cb, cmd_blk);
+ else
+ myrb_handle_scsi(cb, cmd_blk, scmd);
+ }
+ spin_unlock_irqrestore(&cb->queue_lock, flags);
+ return IRQ_HANDLED;
+}
+
+struct myrb_privdata DAC960_PD_privdata = {
+ .hw_init = DAC960_PD_hw_init,
+ .irq_handler = DAC960_PD_intr_handler,
+ .mmio_size = DAC960_PD_mmio_size,
+};
+
+
+/*
+ * DAC960 P Series Controllers
+ *
+ * Similar to the DAC960 PD Series Controllers, but some commands have
+ * to be translated.
+ */
+
+static inline void myrb_translate_enquiry(void *enq)
+{
+ memcpy(enq + 132, enq + 36, 64);
+ memset(enq + 36, 0, 96);
+}
+
+static inline void myrb_translate_devstate(void *state)
+{
+ memcpy(state + 2, state + 3, 1);
+ memmove(state + 4, state + 5, 2);
+ memmove(state + 6, state + 8, 4);
+}
+
+static inline void myrb_translate_to_rw_command(struct myrb_cmdblk *cmd_blk)
+{
+ union myrb_cmd_mbox *mbox = &cmd_blk->mbox;
+ int ldev_num = mbox->type5.ld.ldev_num;
+
+ mbox->bytes[3] &= 0x7;
+ mbox->bytes[3] |= mbox->bytes[7] << 6;
+ mbox->bytes[7] = ldev_num;
+}
+
+static inline void myrb_translate_from_rw_command(struct myrb_cmdblk *cmd_blk)
+{
+ union myrb_cmd_mbox *mbox = &cmd_blk->mbox;
+ int ldev_num = mbox->bytes[7];
+
+ mbox->bytes[7] = mbox->bytes[3] >> 6;
+ mbox->bytes[3] &= 0x7;
+ mbox->bytes[3] |= ldev_num << 3;
+}
+
+static void DAC960_P_qcmd(struct myrb_hba *cb, struct myrb_cmdblk *cmd_blk)
+{
+ void __iomem *base = cb->io_base;
+ union myrb_cmd_mbox *mbox = &cmd_blk->mbox;
+
+ switch (mbox->common.opcode) {
+ case MYRB_CMD_ENQUIRY:
+ mbox->common.opcode = MYRB_CMD_ENQUIRY_OLD;
+ break;
+ case MYRB_CMD_GET_DEVICE_STATE:
+ mbox->common.opcode = MYRB_CMD_GET_DEVICE_STATE_OLD;
+ break;
+ case MYRB_CMD_READ:
+ mbox->common.opcode = MYRB_CMD_READ_OLD;
+ myrb_translate_to_rw_command(cmd_blk);
+ break;
+ case MYRB_CMD_WRITE:
+ mbox->common.opcode = MYRB_CMD_WRITE_OLD;
+ myrb_translate_to_rw_command(cmd_blk);
+ break;
+ case MYRB_CMD_READ_SG:
+ mbox->common.opcode = MYRB_CMD_READ_SG_OLD;
+ myrb_translate_to_rw_command(cmd_blk);
+ break;
+ case MYRB_CMD_WRITE_SG:
+ mbox->common.opcode = MYRB_CMD_WRITE_SG_OLD;
+ myrb_translate_to_rw_command(cmd_blk);
+ break;
+ default:
+ break;
+ }
+ while (DAC960_PD_hw_mbox_is_full(base))
+ udelay(1);
+ DAC960_PD_write_cmd_mbox(base, mbox);
+ DAC960_PD_hw_mbox_new_cmd(base);
+}
+
+
+static int DAC960_P_hw_init(struct pci_dev *pdev,
+ struct myrb_hba *cb, void __iomem *base)
+{
+ int timeout = 0;
+ unsigned char error, parm0, parm1;
+
+ if (!request_region(cb->io_addr, 0x80, "myrb")) {
+ dev_err(&pdev->dev, "IO port 0x%lx busy\n",
+ (unsigned long)cb->io_addr);
+ return -EBUSY;
+ }
+ DAC960_PD_disable_intr(base);
+ DAC960_PD_ack_hw_mbox_status(base);
+ udelay(1000);
+ while (DAC960_PD_init_in_progress(base) &&
+ timeout < MYRB_MAILBOX_TIMEOUT) {
+ if (DAC960_PD_read_error_status(base, &error,
+ &parm0, &parm1) &&
+ myrb_err_status(cb, error, parm0, parm1))
+ return -EAGAIN;
+ udelay(10);
+ timeout++;
+ }
+ if (timeout == MYRB_MAILBOX_TIMEOUT) {
+ dev_err(&pdev->dev,
+ "Timeout waiting for Controller Initialisation\n");
+ return -ETIMEDOUT;
+ }
+ if (!myrb_enable_mmio(cb, NULL)) {
+ dev_err(&pdev->dev,
+ "Unable to allocate DMA mapped memory\n");
+ DAC960_PD_reset_ctrl(base);
+ return -ETIMEDOUT;
+ }
+ DAC960_PD_enable_intr(base);
+ cb->qcmd = DAC960_P_qcmd;
+ cb->disable_intr = DAC960_PD_disable_intr;
+ cb->reset = DAC960_PD_reset_ctrl;
+
+ return 0;
+}
+
+static irqreturn_t DAC960_P_intr_handler(int irq, void *arg)
+{
+ struct myrb_hba *cb = arg;
+ void __iomem *base = cb->io_base;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cb->queue_lock, flags);
+ while (DAC960_PD_hw_mbox_status_available(base)) {
+ unsigned char id = DAC960_PD_read_status_cmd_ident(base);
+ struct scsi_cmnd *scmd = NULL;
+ struct myrb_cmdblk *cmd_blk = NULL;
+ union myrb_cmd_mbox *mbox;
+ enum myrb_cmd_opcode op;
+
+
+ if (id == MYRB_DCMD_TAG)
+ cmd_blk = &cb->dcmd_blk;
+ else if (id == MYRB_MCMD_TAG)
+ cmd_blk = &cb->mcmd_blk;
+ else {
+ scmd = scsi_host_find_tag(cb->host, id - 3);
+ if (scmd)
+ cmd_blk = scsi_cmd_priv(scmd);
+ }
+ if (cmd_blk)
+ cmd_blk->status = DAC960_PD_read_status(base);
+ else
+ dev_err(&cb->pdev->dev,
+ "Unhandled command completion %d\n", id);
+
+ DAC960_PD_ack_intr(base);
+ DAC960_PD_ack_hw_mbox_status(base);
+
+ if (!cmd_blk)
+ continue;
+
+ mbox = &cmd_blk->mbox;
+ op = mbox->common.opcode;
+ switch (op) {
+ case MYRB_CMD_ENQUIRY_OLD:
+ mbox->common.opcode = MYRB_CMD_ENQUIRY;
+ myrb_translate_enquiry(cb->enquiry);
+ break;
+ case MYRB_CMD_READ_OLD:
+ mbox->common.opcode = MYRB_CMD_READ;
+ myrb_translate_from_rw_command(cmd_blk);
+ break;
+ case MYRB_CMD_WRITE_OLD:
+ mbox->common.opcode = MYRB_CMD_WRITE;
+ myrb_translate_from_rw_command(cmd_blk);
+ break;
+ case MYRB_CMD_READ_SG_OLD:
+ mbox->common.opcode = MYRB_CMD_READ_SG;
+ myrb_translate_from_rw_command(cmd_blk);
+ break;
+ case MYRB_CMD_WRITE_SG_OLD:
+ mbox->common.opcode = MYRB_CMD_WRITE_SG;
+ myrb_translate_from_rw_command(cmd_blk);
+ break;
+ default:
+ break;
+ }
+ if (id < 3)
+ myrb_handle_cmdblk(cb, cmd_blk);
+ else
+ myrb_handle_scsi(cb, cmd_blk, scmd);
+ }
+ spin_unlock_irqrestore(&cb->queue_lock, flags);
+ return IRQ_HANDLED;
+}
+
+struct myrb_privdata DAC960_P_privdata = {
+ .hw_init = DAC960_P_hw_init,
+ .irq_handler = DAC960_P_intr_handler,
+ .mmio_size = DAC960_PD_mmio_size,
+};
+
+static struct myrb_hba *myrb_detect(struct pci_dev *pdev,
+ const struct pci_device_id *entry)
+{
+ struct myrb_privdata *privdata =
+ (struct myrb_privdata *)entry->driver_data;
+ irq_handler_t irq_handler = privdata->irq_handler;
+ unsigned int mmio_size = privdata->mmio_size;
+ struct Scsi_Host *shost;
+ struct myrb_hba *cb = NULL;
+
+ shost = scsi_host_alloc(&myrb_template, sizeof(struct myrb_hba));
+ if (!shost) {
+ dev_err(&pdev->dev, "Unable to allocate Controller\n");
+ return NULL;
+ }
+ shost->max_cmd_len = 12;
+ shost->max_lun = 256;
+ cb = shost_priv(shost);
+ mutex_init(&cb->dcmd_mutex);
+ mutex_init(&cb->dma_mutex);
+ cb->pdev = pdev;
+
+ if (pci_enable_device(pdev))
+ goto failure;
+
+ if (privdata->hw_init == DAC960_PD_hw_init ||
+ privdata->hw_init == DAC960_P_hw_init) {
+ cb->io_addr = pci_resource_start(pdev, 0);
+ cb->pci_addr = pci_resource_start(pdev, 1);
+ } else
+ cb->pci_addr = pci_resource_start(pdev, 0);
+
+ pci_set_drvdata(pdev, cb);
+ spin_lock_init(&cb->queue_lock);
+ if (mmio_size < PAGE_SIZE)
+ mmio_size = PAGE_SIZE;
+ cb->mmio_base = ioremap_nocache(cb->pci_addr & PAGE_MASK, mmio_size);
+ if (cb->mmio_base == NULL) {
+ dev_err(&pdev->dev,
+ "Unable to map Controller Register Window\n");
+ goto failure;
+ }
+
+ cb->io_base = cb->mmio_base + (cb->pci_addr & ~PAGE_MASK);
+ if (privdata->hw_init(pdev, cb, cb->io_base))
+ goto failure;
+
+ if (request_irq(pdev->irq, irq_handler, IRQF_SHARED, "myrb", cb) < 0) {
+ dev_err(&pdev->dev,
+ "Unable to acquire IRQ Channel %d\n", pdev->irq);
+ goto failure;
+ }
+ cb->irq = pdev->irq;
+ return cb;
+
+failure:
+ dev_err(&pdev->dev,
+ "Failed to initialize Controller\n");
+ myrb_cleanup(cb);
+ return NULL;
+}
+
+static int myrb_probe(struct pci_dev *dev, const struct pci_device_id *entry)
+{
+ struct myrb_hba *cb;
+ int ret;
+
+ cb = myrb_detect(dev, entry);
+ if (!cb)
+ return -ENODEV;
+
+ ret = myrb_get_hba_config(cb);
+ if (ret < 0) {
+ myrb_cleanup(cb);
+ return ret;
+ }
+
+ if (!myrb_create_mempools(dev, cb)) {
+ ret = -ENOMEM;
+ goto failed;
+ }
+
+ ret = scsi_add_host(cb->host, &dev->dev);
+ if (ret) {
+ dev_err(&dev->dev, "scsi_add_host failed with %d\n", ret);
+ myrb_destroy_mempools(cb);
+ goto failed;
+ }
+ scsi_scan_host(cb->host);
+ return 0;
+failed:
+ myrb_cleanup(cb);
+ return ret;
+}
+
+
+static void myrb_remove(struct pci_dev *pdev)
+{
+ struct myrb_hba *cb = pci_get_drvdata(pdev);
+
+ shost_printk(KERN_NOTICE, cb->host, "Flushing Cache...");
+ myrb_exec_type3(cb, MYRB_CMD_FLUSH, 0);
+ myrb_cleanup(cb);
+ myrb_destroy_mempools(cb);
+}
+
+
+static const struct pci_device_id myrb_id_table[] = {
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_DEC,
+ PCI_DEVICE_ID_DEC_21285,
+ PCI_VENDOR_ID_MYLEX,
+ PCI_DEVICE_ID_MYLEX_DAC960_LA),
+ .driver_data = (unsigned long) &DAC960_LA_privdata,
+ },
+ {
+ PCI_DEVICE_DATA(MYLEX, DAC960_PG, &DAC960_PG_privdata),
+ },
+ {
+ PCI_DEVICE_DATA(MYLEX, DAC960_PD, &DAC960_PD_privdata),
+ },
+ {
+ PCI_DEVICE_DATA(MYLEX, DAC960_P, &DAC960_P_privdata),
+ },
+ {0, },
+};
+
+MODULE_DEVICE_TABLE(pci, myrb_id_table);
+
+static struct pci_driver myrb_pci_driver = {
+ .name = "myrb",
+ .id_table = myrb_id_table,
+ .probe = myrb_probe,
+ .remove = myrb_remove,
+};
+
+static int __init myrb_init_module(void)
+{
+ int ret;
+
+ myrb_raid_template = raid_class_attach(&myrb_raid_functions);
+ if (!myrb_raid_template)
+ return -ENODEV;
+
+ ret = pci_register_driver(&myrb_pci_driver);
+ if (ret)
+ raid_class_release(myrb_raid_template);
+
+ return ret;
+}
+
+static void __exit myrb_cleanup_module(void)
+{
+ pci_unregister_driver(&myrb_pci_driver);
+ raid_class_release(myrb_raid_template);
+}
+
+module_init(myrb_init_module);
+module_exit(myrb_cleanup_module);
+
+MODULE_DESCRIPTION("Mylex DAC960/AcceleRAID/eXtremeRAID driver (Block interface)");
+MODULE_AUTHOR("Hannes Reinecke <hare@suse.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/myrb.h b/drivers/scsi/myrb.h
new file mode 100644
index 000000000000..9289c19fcb2f
--- /dev/null
+++ b/drivers/scsi/myrb.h
@@ -0,0 +1,958 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers
+ *
+ * Copyright 2017 Hannes Reinecke, SUSE Linux GmbH <hare@suse.com>
+ *
+ * Based on the original DAC960 driver,
+ * Copyright 1998-2001 by Leonard N. Zubkoff <lnz@dandelion.com>
+ * Portions Copyright 2002 by Mylex (An IBM Business Unit)
+ *
+ */
+
+#ifndef MYRB_H
+#define MYRB_H
+
+#define MYRB_MAX_LDEVS 32
+#define MYRB_MAX_CHANNELS 3
+#define MYRB_MAX_TARGETS 16
+#define MYRB_MAX_PHYSICAL_DEVICES 45
+#define MYRB_SCATTER_GATHER_LIMIT 32
+#define MYRB_CMD_MBOX_COUNT 256
+#define MYRB_STAT_MBOX_COUNT 1024
+
+#define MYRB_BLKSIZE_BITS 9
+#define MYRB_MAILBOX_TIMEOUT 1000000
+
+#define MYRB_DCMD_TAG 1
+#define MYRB_MCMD_TAG 2
+
+#define MYRB_PRIMARY_MONITOR_INTERVAL (10 * HZ)
+#define MYRB_SECONDARY_MONITOR_INTERVAL (60 * HZ)
+
+/*
+ * DAC960 V1 Firmware Command Opcodes.
+ */
+enum myrb_cmd_opcode {
+ /* I/O Commands */
+ MYRB_CMD_READ_EXTENDED = 0x33,
+ MYRB_CMD_WRITE_EXTENDED = 0x34,
+ MYRB_CMD_READAHEAD_EXTENDED = 0x35,
+ MYRB_CMD_READ_EXTENDED_SG = 0xB3,
+ MYRB_CMD_WRITE_EXTENDED_SG = 0xB4,
+ MYRB_CMD_READ = 0x36,
+ MYRB_CMD_READ_SG = 0xB6,
+ MYRB_CMD_WRITE = 0x37,
+ MYRB_CMD_WRITE_SG = 0xB7,
+ MYRB_CMD_DCDB = 0x04,
+ MYRB_CMD_DCDB_SG = 0x84,
+ MYRB_CMD_FLUSH = 0x0A,
+ /* Controller Status Related Commands */
+ MYRB_CMD_ENQUIRY = 0x53,
+ MYRB_CMD_ENQUIRY2 = 0x1C,
+ MYRB_CMD_GET_LDRV_ELEMENT = 0x55,
+ MYRB_CMD_GET_LDEV_INFO = 0x19,
+ MYRB_CMD_IOPORTREAD = 0x39,
+ MYRB_CMD_IOPORTWRITE = 0x3A,
+ MYRB_CMD_GET_SD_STATS = 0x3E,
+ MYRB_CMD_GET_PD_STATS = 0x3F,
+ MYRB_CMD_EVENT_LOG_OPERATION = 0x72,
+ /* Device Related Commands */
+ MYRB_CMD_START_DEVICE = 0x10,
+ MYRB_CMD_GET_DEVICE_STATE = 0x50,
+ MYRB_CMD_STOP_CHANNEL = 0x13,
+ MYRB_CMD_START_CHANNEL = 0x12,
+ MYRB_CMD_RESET_CHANNEL = 0x1A,
+ /* Commands Associated with Data Consistency and Errors */
+ MYRB_CMD_REBUILD = 0x09,
+ MYRB_CMD_REBUILD_ASYNC = 0x16,
+ MYRB_CMD_CHECK_CONSISTENCY = 0x0F,
+ MYRB_CMD_CHECK_CONSISTENCY_ASYNC = 0x1E,
+ MYRB_CMD_REBUILD_STAT = 0x0C,
+ MYRB_CMD_GET_REBUILD_PROGRESS = 0x27,
+ MYRB_CMD_REBUILD_CONTROL = 0x1F,
+ MYRB_CMD_READ_BADBLOCK_TABLE = 0x0B,
+ MYRB_CMD_READ_BADDATA_TABLE = 0x25,
+ MYRB_CMD_CLEAR_BADDATA_TABLE = 0x26,
+ MYRB_CMD_GET_ERROR_TABLE = 0x17,
+ MYRB_CMD_ADD_CAPACITY_ASYNC = 0x2A,
+ MYRB_CMD_BGI_CONTROL = 0x2B,
+ /* Configuration Related Commands */
+ MYRB_CMD_READ_CONFIG2 = 0x3D,
+ MYRB_CMD_WRITE_CONFIG2 = 0x3C,
+ MYRB_CMD_READ_CONFIG_ONDISK = 0x4A,
+ MYRB_CMD_WRITE_CONFIG_ONDISK = 0x4B,
+ MYRB_CMD_READ_CONFIG = 0x4E,
+ MYRB_CMD_READ_BACKUP_CONFIG = 0x4D,
+ MYRB_CMD_WRITE_CONFIG = 0x4F,
+ MYRB_CMD_ADD_CONFIG = 0x4C,
+ MYRB_CMD_READ_CONFIG_LABEL = 0x48,
+ MYRB_CMD_WRITE_CONFIG_LABEL = 0x49,
+ /* Firmware Upgrade Related Commands */
+ MYRB_CMD_LOAD_IMAGE = 0x20,
+ MYRB_CMD_STORE_IMAGE = 0x21,
+ MYRB_CMD_PROGRAM_IMAGE = 0x22,
+ /* Diagnostic Commands */
+ MYRB_CMD_SET_DIAGNOSTIC_MODE = 0x31,
+ MYRB_CMD_RUN_DIAGNOSTIC = 0x32,
+ /* Subsystem Service Commands */
+ MYRB_CMD_GET_SUBSYS_DATA = 0x70,
+ MYRB_CMD_SET_SUBSYS_PARAM = 0x71,
+ /* Version 2.xx Firmware Commands */
+ MYRB_CMD_ENQUIRY_OLD = 0x05,
+ MYRB_CMD_GET_DEVICE_STATE_OLD = 0x14,
+ MYRB_CMD_READ_OLD = 0x02,
+ MYRB_CMD_WRITE_OLD = 0x03,
+ MYRB_CMD_READ_SG_OLD = 0x82,
+ MYRB_CMD_WRITE_SG_OLD = 0x83
+} __packed;
+
+/*
+ * DAC960 V1 Firmware Command Status Codes.
+ */
+#define MYRB_STATUS_SUCCESS 0x0000 /* Common */
+#define MYRB_STATUS_CHECK_CONDITION 0x0002 /* Common */
+#define MYRB_STATUS_NO_DEVICE 0x0102 /* Common */
+#define MYRB_STATUS_INVALID_ADDRESS 0x0105 /* Common */
+#define MYRB_STATUS_INVALID_PARAM 0x0105 /* Common */
+#define MYRB_STATUS_IRRECOVERABLE_DATA_ERROR 0x0001 /* I/O */
+#define MYRB_STATUS_LDRV_NONEXISTENT_OR_OFFLINE 0x0002 /* I/O */
+#define MYRB_STATUS_ACCESS_BEYOND_END_OF_LDRV 0x0105 /* I/O */
+#define MYRB_STATUS_BAD_DATA 0x010C /* I/O */
+#define MYRB_STATUS_DEVICE_BUSY 0x0008 /* DCDB */
+#define MYRB_STATUS_DEVICE_NONRESPONSIVE 0x000E /* DCDB */
+#define MYRB_STATUS_COMMAND_TERMINATED 0x000F /* DCDB */
+#define MYRB_STATUS_START_DEVICE_FAILED 0x0002 /* Device */
+#define MYRB_STATUS_INVALID_CHANNEL_OR_TARGET 0x0105 /* Device */
+#define MYRB_STATUS_CHANNEL_BUSY 0x0106 /* Device */
+#define MYRB_STATUS_OUT_OF_MEMORY 0x0107 /* Device */
+#define MYRB_STATUS_CHANNEL_NOT_STOPPED 0x0002 /* Device */
+#define MYRB_STATUS_ATTEMPT_TO_RBLD_ONLINE_DRIVE 0x0002 /* Consistency */
+#define MYRB_STATUS_RBLD_BADBLOCKS 0x0003 /* Consistency */
+#define MYRB_STATUS_RBLD_NEW_DISK_FAILED 0x0004 /* Consistency */
+#define MYRB_STATUS_RBLD_OR_CHECK_INPROGRESS 0x0106 /* Consistency */
+#define MYRB_STATUS_DEPENDENT_DISK_DEAD 0x0002 /* Consistency */
+#define MYRB_STATUS_INCONSISTENT_BLOCKS 0x0003 /* Consistency */
+#define MYRB_STATUS_INVALID_OR_NONREDUNDANT_LDRV 0x0105 /* Consistency */
+#define MYRB_STATUS_NO_RBLD_OR_CHECK_INPROGRESS 0x0105 /* Consistency */
+#define MYRB_STATUS_RBLD_IN_PROGRESS_DATA_VALID 0x0000 /* Consistency */
+#define MYRB_STATUS_RBLD_FAILED_LDEV_FAILURE 0x0002 /* Consistency */
+#define MYRB_STATUS_RBLD_FAILED_BADBLOCKS 0x0003 /* Consistency */
+#define MYRB_STATUS_RBLD_FAILED_NEW_DRIVE_FAILED 0x0004 /* Consistency */
+#define MYRB_STATUS_RBLD_SUCCESS 0x0100 /* Consistency */
+#define MYRB_STATUS_RBLD_SUCCESS_TERMINATED 0x0107 /* Consistency */
+#define MYRB_STATUS_RBLD_NOT_CHECKED 0x0108 /* Consistency */
+#define MYRB_STATUS_BGI_SUCCESS 0x0100 /* Consistency */
+#define MYRB_STATUS_BGI_ABORTED 0x0005 /* Consistency */
+#define MYRB_STATUS_NO_BGI_INPROGRESS 0x0105 /* Consistency */
+#define MYRB_STATUS_ADD_CAPACITY_INPROGRESS 0x0004 /* Consistency */
+#define MYRB_STATUS_ADD_CAPACITY_FAILED_OR_SUSPENDED 0x00F4 /* Consistency */
+#define MYRB_STATUS_CONFIG2_CSUM_ERROR 0x0002 /* Configuration */
+#define MYRB_STATUS_CONFIGURATION_SUSPENDED 0x0106 /* Configuration */
+#define MYRB_STATUS_FAILED_TO_CONFIGURE_NVRAM 0x0105 /* Configuration */
+#define MYRB_STATUS_CONFIGURATION_NOT_SAVED 0x0106 /* Configuration */
+#define MYRB_STATUS_SUBSYS_NOTINSTALLED 0x0001 /* Subsystem */
+#define MYRB_STATUS_SUBSYS_FAILED 0x0002 /* Subsystem */
+#define MYRB_STATUS_SUBSYS_BUSY 0x0106 /* Subsystem */
+#define MYRB_STATUS_SUBSYS_TIMEOUT 0x0108 /* Subsystem */
+
+/*
+ * DAC960 V1 Firmware Enquiry Command reply structure.
+ */
+struct myrb_enquiry {
+ unsigned char ldev_count; /* Byte 0 */
+ unsigned int rsvd1:24; /* Bytes 1-3 */
+ unsigned int ldev_sizes[32]; /* Bytes 4-131 */
+ unsigned short flash_age; /* Bytes 132-133 */
+ struct {
+ unsigned char deferred:1; /* Byte 134 Bit 0 */
+ unsigned char low_bat:1; /* Byte 134 Bit 1 */
+ unsigned char rsvd2:6; /* Byte 134 Bits 2-7 */
+ } status;
+ unsigned char rsvd3:8; /* Byte 135 */
+ unsigned char fw_minor_version; /* Byte 136 */
+ unsigned char fw_major_version; /* Byte 137 */
+ enum {
+ MYRB_NO_STDBY_RBLD_OR_CHECK_IN_PROGRESS = 0x00,
+ MYRB_STDBY_RBLD_IN_PROGRESS = 0x01,
+ MYRB_BG_RBLD_IN_PROGRESS = 0x02,
+ MYRB_BG_CHECK_IN_PROGRESS = 0x03,
+ MYRB_STDBY_RBLD_COMPLETED_WITH_ERROR = 0xFF,
+ MYRB_BG_RBLD_OR_CHECK_FAILED_DRIVE_FAILED = 0xF0,
+ MYRB_BG_RBLD_OR_CHECK_FAILED_LDEV_FAILED = 0xF1,
+ MYRB_BG_RBLD_OR_CHECK_FAILED_OTHER = 0xF2,
+ MYRB_BG_RBLD_OR_CHECK_SUCCESS_TERMINATED = 0xF3
+ } __packed rbld; /* Byte 138 */
+ unsigned char max_tcq; /* Byte 139 */
+ unsigned char ldev_offline; /* Byte 140 */
+ unsigned char rsvd4:8; /* Byte 141 */
+ unsigned short ev_seq; /* Bytes 142-143 */
+ unsigned char ldev_critical; /* Byte 144 */
+ unsigned int rsvd5:24; /* Bytes 145-147 */
+ unsigned char pdev_dead; /* Byte 148 */
+ unsigned char rsvd6:8; /* Byte 149 */
+ unsigned char rbld_count; /* Byte 150 */
+ struct {
+ unsigned char rsvd7:3; /* Byte 151 Bits 0-2 */
+ unsigned char bbu_present:1; /* Byte 151 Bit 3 */
+ unsigned char rsvd8:4; /* Byte 151 Bits 4-7 */
+ } misc;
+ struct {
+ unsigned char target;
+ unsigned char channel;
+ } dead_drives[21]; /* Bytes 152-194 */
+ unsigned char rsvd9[62]; /* Bytes 195-255 */
+} __packed;
+
+/*
+ * DAC960 V1 Firmware Enquiry2 Command reply structure.
+ */
+struct myrb_enquiry2 {
+ struct {
+ enum {
+ DAC960_V1_P_PD_PU = 0x01,
+ DAC960_V1_PL = 0x02,
+ DAC960_V1_PG = 0x10,
+ DAC960_V1_PJ = 0x11,
+ DAC960_V1_PR = 0x12,
+ DAC960_V1_PT = 0x13,
+ DAC960_V1_PTL0 = 0x14,
+ DAC960_V1_PRL = 0x15,
+ DAC960_V1_PTL1 = 0x16,
+ DAC960_V1_1164P = 0x20
+ } __packed sub_model; /* Byte 0 */
+ unsigned char actual_channels; /* Byte 1 */
+ enum {
+ MYRB_5_CHANNEL_BOARD = 0x01,
+ MYRB_3_CHANNEL_BOARD = 0x02,
+ MYRB_2_CHANNEL_BOARD = 0x03,
+ MYRB_3_CHANNEL_ASIC_DAC = 0x04
+ } __packed model; /* Byte 2 */
+ enum {
+ MYRB_EISA_CONTROLLER = 0x01,
+ MYRB_MCA_CONTROLLER = 0x02,
+ MYRB_PCI_CONTROLLER = 0x03,
+ MYRB_SCSI_TO_SCSI = 0x08
+ } __packed controller; /* Byte 3 */
+ } hw; /* Bytes 0-3 */
+ /* MajorVersion.MinorVersion-FirmwareType-TurnID */
+ struct {
+ unsigned char major_version; /* Byte 4 */
+ unsigned char minor_version; /* Byte 5 */
+ unsigned char turn_id; /* Byte 6 */
+ char firmware_type; /* Byte 7 */
+ } fw; /* Bytes 4-7 */
+ unsigned int rsvd1; /* Byte 8-11 */
+ unsigned char cfg_chan; /* Byte 12 */
+ unsigned char cur_chan; /* Byte 13 */
+ unsigned char max_targets; /* Byte 14 */
+ unsigned char max_tcq; /* Byte 15 */
+ unsigned char max_ldev; /* Byte 16 */
+ unsigned char max_arms; /* Byte 17 */
+ unsigned char max_spans; /* Byte 18 */
+ unsigned char rsvd2; /* Byte 19 */
+ unsigned int rsvd3; /* Bytes 20-23 */
+ unsigned int mem_size; /* Bytes 24-27 */
+ unsigned int cache_size; /* Bytes 28-31 */
+ unsigned int flash_size; /* Bytes 32-35 */
+ unsigned int nvram_size; /* Bytes 36-39 */
+ struct {
+ enum {
+ MYRB_RAM_TYPE_DRAM = 0x0,
+ MYRB_RAM_TYPE_EDO = 0x1,
+ MYRB_RAM_TYPE_SDRAM = 0x2,
+ MYRB_RAM_TYPE_Last = 0x7
+ } __packed ram:3; /* Byte 40 Bits 0-2 */
+ enum {
+ MYRB_ERR_CORR_None = 0x0,
+ MYRB_ERR_CORR_Parity = 0x1,
+ MYRB_ERR_CORR_ECC = 0x2,
+ MYRB_ERR_CORR_Last = 0x7
+ } __packed ec:3; /* Byte 40 Bits 3-5 */
+ unsigned char fast_page:1; /* Byte 40 Bit 6 */
+ unsigned char low_power:1; /* Byte 40 Bit 7 */
+ unsigned char rsvd4; /* Bytes 41 */
+ } mem_type;
+ unsigned short clock_speed; /* Bytes 42-43 */
+ unsigned short mem_speed; /* Bytes 44-45 */
+ unsigned short hw_speed; /* Bytes 46-47 */
+ unsigned char rsvd5[12]; /* Bytes 48-59 */
+ unsigned short max_cmds; /* Bytes 60-61 */
+ unsigned short max_sge; /* Bytes 62-63 */
+ unsigned short max_drv_cmds; /* Bytes 64-65 */
+ unsigned short max_io_desc; /* Bytes 66-67 */
+ unsigned short max_sectors; /* Bytes 68-69 */
+ unsigned char latency; /* Byte 70 */
+ unsigned char rsvd6; /* Byte 71 */
+ unsigned char scsi_tmo; /* Byte 72 */
+ unsigned char rsvd7; /* Byte 73 */
+ unsigned short min_freelines; /* Bytes 74-75 */
+ unsigned char rsvd8[8]; /* Bytes 76-83 */
+ unsigned char rbld_rate_const; /* Byte 84 */
+ unsigned char rsvd9[11]; /* Byte 85-95 */
+ unsigned short pdrv_block_size; /* Bytes 96-97 */
+ unsigned short ldev_block_size; /* Bytes 98-99 */
+ unsigned short max_blocks_per_cmd; /* Bytes 100-101 */
+ unsigned short block_factor; /* Bytes 102-103 */
+ unsigned short cacheline_size; /* Bytes 104-105 */
+ struct {
+ enum {
+ MYRB_WIDTH_NARROW_8BIT = 0x0,
+ MYRB_WIDTH_WIDE_16BIT = 0x1,
+ MYRB_WIDTH_WIDE_32BIT = 0x2
+ } __packed bus_width:2; /* Byte 106 Bits 0-1 */
+ enum {
+ MYRB_SCSI_SPEED_FAST = 0x0,
+ MYRB_SCSI_SPEED_ULTRA = 0x1,
+ MYRB_SCSI_SPEED_ULTRA2 = 0x2
+ } __packed bus_speed:2; /* Byte 106 Bits 2-3 */
+ unsigned char differential:1; /* Byte 106 Bit 4 */
+ unsigned char rsvd10:3; /* Byte 106 Bits 5-7 */
+ } scsi_cap;
+ unsigned char rsvd11[5]; /* Byte 107-111 */
+ unsigned short fw_build; /* Bytes 112-113 */
+ enum {
+ MYRB_FAULT_AEMI = 0x01,
+ MYRB_FAULT_OEM1 = 0x02,
+ MYRB_FAULT_OEM2 = 0x04,
+ MYRB_FAULT_OEM3 = 0x08,
+ MYRB_FAULT_CONNER = 0x10,
+ MYRB_FAULT_SAFTE = 0x20
+ } __packed fault_mgmt; /* Byte 114 */
+ unsigned char rsvd12; /* Byte 115 */
+ struct {
+ unsigned int clustering:1; /* Byte 116 Bit 0 */
+ unsigned int online_RAID_expansion:1; /* Byte 116 Bit 1 */
+ unsigned int readahead:1; /* Byte 116 Bit 2 */
+ unsigned int bgi:1; /* Byte 116 Bit 3 */
+ unsigned int rsvd13:28; /* Bytes 116-119 */
+ } fw_features;
+ unsigned char rsvd14[8]; /* Bytes 120-127 */
+} __packed;
+
+/*
+ * DAC960 V1 Firmware Logical Drive State type.
+ */
+enum myrb_devstate {
+ MYRB_DEVICE_DEAD = 0x00,
+ MYRB_DEVICE_WO = 0x02,
+ MYRB_DEVICE_ONLINE = 0x03,
+ MYRB_DEVICE_CRITICAL = 0x04,
+ MYRB_DEVICE_STANDBY = 0x10,
+ MYRB_DEVICE_OFFLINE = 0xFF
+} __packed;
+
+/*
+ * DAC960 V1 RAID Levels
+ */
+enum myrb_raidlevel {
+ MYRB_RAID_LEVEL0 = 0x0, /* RAID 0 */
+ MYRB_RAID_LEVEL1 = 0x1, /* RAID 1 */
+ MYRB_RAID_LEVEL3 = 0x3, /* RAID 3 */
+ MYRB_RAID_LEVEL5 = 0x5, /* RAID 5 */
+ MYRB_RAID_LEVEL6 = 0x6, /* RAID 6 */
+ MYRB_RAID_JBOD = 0x7, /* RAID 7 (JBOD) */
+} __packed;
+
+/*
+ * DAC960 V1 Firmware Logical Drive Information structure.
+ */
+struct myrb_ldev_info {
+ unsigned int size; /* Bytes 0-3 */
+ enum myrb_devstate state; /* Byte 4 */
+ unsigned int raid_level:7; /* Byte 5 Bits 0-6 */
+ unsigned int wb_enabled:1; /* Byte 5 Bit 7 */
+ unsigned int rsvd:16; /* Bytes 6-7 */
+};
+
+/*
+ * DAC960 V1 Firmware Perform Event Log Operation Types.
+ */
+#define DAC960_V1_GetEventLogEntry 0x00
+
+/*
+ * DAC960 V1 Firmware Get Event Log Entry Command reply structure.
+ */
+struct myrb_log_entry {
+ unsigned char msg_type; /* Byte 0 */
+ unsigned char msg_len; /* Byte 1 */
+ unsigned char target:5; /* Byte 2 Bits 0-4 */
+ unsigned char channel:3; /* Byte 2 Bits 5-7 */
+ unsigned char lun:6; /* Byte 3 Bits 0-5 */
+ unsigned char rsvd1:2; /* Byte 3 Bits 6-7 */
+ unsigned short seq_num; /* Bytes 4-5 */
+ unsigned char sense[26]; /* Bytes 6-31 */
+};
+
+/*
+ * DAC960 V1 Firmware Get Device State Command reply structure.
+ * The structure is padded by 2 bytes for compatibility with Version 2.xx
+ * Firmware.
+ */
+struct myrb_pdev_state {
+ unsigned int present:1; /* Byte 0 Bit 0 */
+ unsigned int :7; /* Byte 0 Bits 1-7 */
+ enum {
+ MYRB_TYPE_OTHER = 0x0,
+ MYRB_TYPE_DISK = 0x1,
+ MYRB_TYPE_TAPE = 0x2,
+ MYRB_TYPE_CDROM_OR_WORM = 0x3
+ } __packed devtype:2; /* Byte 1 Bits 0-1 */
+ unsigned int rsvd1:1; /* Byte 1 Bit 2 */
+ unsigned int fast20:1; /* Byte 1 Bit 3 */
+ unsigned int sync:1; /* Byte 1 Bit 4 */
+ unsigned int fast:1; /* Byte 1 Bit 5 */
+ unsigned int wide:1; /* Byte 1 Bit 6 */
+ unsigned int tcq_supported:1; /* Byte 1 Bit 7 */
+ enum myrb_devstate state; /* Byte 2 */
+ unsigned int rsvd2:8; /* Byte 3 */
+ unsigned int sync_multiplier; /* Byte 4 */
+ unsigned int sync_offset:5; /* Byte 5 Bits 0-4 */
+ unsigned int rsvd3:3; /* Byte 5 Bits 5-7 */
+ unsigned int size; /* Bytes 6-9 */
+ unsigned int rsvd4:16; /* Bytes 10-11 */
+} __packed;
+
+/*
+ * DAC960 V1 Firmware Get Rebuild Progress Command reply structure.
+ */
+struct myrb_rbld_progress {
+ unsigned int ldev_num; /* Bytes 0-3 */
+ unsigned int ldev_size; /* Bytes 4-7 */
+ unsigned int blocks_left; /* Bytes 8-11 */
+};
+
+/*
+ * DAC960 V1 Firmware Background Initialization Status Command reply structure.
+ */
+struct myrb_bgi_status {
+ unsigned int ldev_size; /* Bytes 0-3 */
+ unsigned int blocks_done; /* Bytes 4-7 */
+ unsigned char rsvd1[12]; /* Bytes 8-19 */
+ unsigned int ldev_num; /* Bytes 20-23 */
+ unsigned char raid_level; /* Byte 24 */
+ enum {
+ MYRB_BGI_INVALID = 0x00,
+ MYRB_BGI_STARTED = 0x02,
+ MYRB_BGI_INPROGRESS = 0x04,
+ MYRB_BGI_SUSPENDED = 0x05,
+ MYRB_BGI_CANCELLED = 0x06
+ } __packed status; /* Byte 25 */
+ unsigned char rsvd2[6]; /* Bytes 26-31 */
+};
+
+/*
+ * DAC960 V1 Firmware Error Table Entry structure.
+ */
+struct myrb_error_entry {
+ unsigned char parity_err; /* Byte 0 */
+ unsigned char soft_err; /* Byte 1 */
+ unsigned char hard_err; /* Byte 2 */
+ unsigned char misc_err; /* Byte 3 */
+};
+
+/*
+ * DAC960 V1 Firmware Read Config2 Command reply structure.
+ */
+struct myrb_config2 {
+ unsigned rsvd1:1; /* Byte 0 Bit 0 */
+ unsigned active_negation:1; /* Byte 0 Bit 1 */
+ unsigned rsvd2:5; /* Byte 0 Bits 2-6 */
+ unsigned no_rescan_on_reset_during_scan:1; /* Byte 0 Bit 7 */
+ unsigned StorageWorks_support:1; /* Byte 1 Bit 0 */
+ unsigned HewlettPackard_support:1; /* Byte 1 Bit 1 */
+ unsigned no_disconnect_on_first_command:1; /* Byte 1 Bit 2 */
+ unsigned rsvd3:2; /* Byte 1 Bits 3-4 */
+ unsigned AEMI_ARM:1; /* Byte 1 Bit 5 */
+ unsigned AEMI_OFM:1; /* Byte 1 Bit 6 */
+ unsigned rsvd4:1; /* Byte 1 Bit 7 */
+ enum {
+ MYRB_OEMID_MYLEX = 0x00,
+ MYRB_OEMID_IBM = 0x08,
+ MYRB_OEMID_HP = 0x0A,
+ MYRB_OEMID_DEC = 0x0C,
+ MYRB_OEMID_SIEMENS = 0x10,
+ MYRB_OEMID_INTEL = 0x12
+ } __packed OEMID; /* Byte 2 */
+ unsigned char oem_model_number; /* Byte 3 */
+ unsigned char physical_sector; /* Byte 4 */
+ unsigned char logical_sector; /* Byte 5 */
+ unsigned char block_factor; /* Byte 6 */
+ unsigned readahead_enabled:1; /* Byte 7 Bit 0 */
+ unsigned low_BIOS_delay:1; /* Byte 7 Bit 1 */
+ unsigned rsvd5:2; /* Byte 7 Bits 2-3 */
+ unsigned restrict_reassign_to_one_sector:1; /* Byte 7 Bit 4 */
+ unsigned rsvd6:1; /* Byte 7 Bit 5 */
+ unsigned FUA_during_write_recovery:1; /* Byte 7 Bit 6 */
+ unsigned enable_LeftSymmetricRAID5Algorithm:1; /* Byte 7 Bit 7 */
+ unsigned char default_rebuild_rate; /* Byte 8 */
+ unsigned char rsvd7; /* Byte 9 */
+ unsigned char blocks_per_cacheline; /* Byte 10 */
+ unsigned char blocks_per_stripe; /* Byte 11 */
+ struct {
+ enum {
+ MYRB_SPEED_ASYNC = 0x0,
+ MYRB_SPEED_SYNC_8MHz = 0x1,
+ MYRB_SPEED_SYNC_5MHz = 0x2,
+ MYRB_SPEED_SYNC_10_OR_20MHz = 0x3
+ } __packed speed:2; /* Byte 11 Bits 0-1 */
+ unsigned force_8bit:1; /* Byte 11 Bit 2 */
+ unsigned disable_fast20:1; /* Byte 11 Bit 3 */
+ unsigned rsvd8:3; /* Byte 11 Bits 4-6 */
+ unsigned enable_tcq:1; /* Byte 11 Bit 7 */
+ } __packed channelparam[6]; /* Bytes 12-17 */
+ unsigned char SCSIInitiatorID; /* Byte 18 */
+ unsigned char rsvd9; /* Byte 19 */
+ enum {
+ MYRB_STARTUP_CONTROLLER_SPINUP = 0x00,
+ MYRB_STARTUP_POWERON_SPINUP = 0x01
+ } __packed startup; /* Byte 20 */
+ unsigned char simultaneous_device_spinup_count; /* Byte 21 */
+ unsigned char seconds_delay_between_spinups; /* Byte 22 */
+ unsigned char rsvd10[29]; /* Bytes 23-51 */
+ unsigned BIOS_disabled:1; /* Byte 52 Bit 0 */
+ unsigned CDROM_boot_enabled:1; /* Byte 52 Bit 1 */
+ unsigned rsvd11:3; /* Byte 52 Bits 2-4 */
+ enum {
+ MYRB_GEOM_128_32 = 0x0,
+ MYRB_GEOM_255_63 = 0x1,
+ MYRB_GEOM_RESERVED1 = 0x2,
+ MYRB_GEOM_RESERVED2 = 0x3
+ } __packed drive_geometry:2; /* Byte 52 Bits 5-6 */
+ unsigned rsvd12:1; /* Byte 52 Bit 7 */
+ unsigned char rsvd13[9]; /* Bytes 53-61 */
+ unsigned short csum; /* Bytes 62-63 */
+};
+
+/*
+ * DAC960 V1 Firmware DCDB request structure.
+ */
+struct myrb_dcdb {
+ unsigned target:4; /* Byte 0 Bits 0-3 */
+ unsigned channel:4; /* Byte 0 Bits 4-7 */
+ enum {
+ MYRB_DCDB_XFER_NONE = 0,
+ MYRB_DCDB_XFER_DEVICE_TO_SYSTEM = 1,
+ MYRB_DCDB_XFER_SYSTEM_TO_DEVICE = 2,
+ MYRB_DCDB_XFER_ILLEGAL = 3
+ } __packed data_xfer:2; /* Byte 1 Bits 0-1 */
+ unsigned early_status:1; /* Byte 1 Bit 2 */
+ unsigned rsvd1:1; /* Byte 1 Bit 3 */
+ enum {
+ MYRB_DCDB_TMO_24_HRS = 0,
+ MYRB_DCDB_TMO_10_SECS = 1,
+ MYRB_DCDB_TMO_60_SECS = 2,
+ MYRB_DCDB_TMO_10_MINS = 3
+ } __packed timeout:2; /* Byte 1 Bits 4-5 */
+ unsigned no_autosense:1; /* Byte 1 Bit 6 */
+ unsigned allow_disconnect:1; /* Byte 1 Bit 7 */
+ unsigned short xfer_len_lo; /* Bytes 2-3 */
+ u32 dma_addr; /* Bytes 4-7 */
+ unsigned char cdb_len:4; /* Byte 8 Bits 0-3 */
+ unsigned char xfer_len_hi4:4; /* Byte 8 Bits 4-7 */
+ unsigned char sense_len; /* Byte 9 */
+ unsigned char cdb[12]; /* Bytes 10-21 */
+ unsigned char sense[64]; /* Bytes 22-85 */
+ unsigned char status; /* Byte 86 */
+ unsigned char rsvd2; /* Byte 87 */
+};
+
+/*
+ * DAC960 V1 Firmware Scatter/Gather List Type 1 32 Bit Address
+ *32 Bit Byte Count structure.
+ */
+struct myrb_sge {
+ u32 sge_addr; /* Bytes 0-3 */
+ u32 sge_count; /* Bytes 4-7 */
+};
+
+/*
+ * 13 Byte DAC960 V1 Firmware Command Mailbox structure.
+ * Bytes 13-15 are not used. The structure is padded to 16 bytes for
+ * efficient access.
+ */
+union myrb_cmd_mbox {
+ unsigned int words[4]; /* Words 0-3 */
+ unsigned char bytes[16]; /* Bytes 0-15 */
+ struct {
+ enum myrb_cmd_opcode opcode; /* Byte 0 */
+ unsigned char id; /* Byte 1 */
+ unsigned char rsvd[14]; /* Bytes 2-15 */
+ } __packed common;
+ struct {
+ enum myrb_cmd_opcode opcode; /* Byte 0 */
+ unsigned char id; /* Byte 1 */
+ unsigned char rsvd1[6]; /* Bytes 2-7 */
+ u32 addr; /* Bytes 8-11 */
+ unsigned char rsvd2[4]; /* Bytes 12-15 */
+ } __packed type3;
+ struct {
+ enum myrb_cmd_opcode opcode; /* Byte 0 */
+ unsigned char id; /* Byte 1 */
+ unsigned char optype; /* Byte 2 */
+ unsigned char rsvd1[5]; /* Bytes 3-7 */
+ u32 addr; /* Bytes 8-11 */
+ unsigned char rsvd2[4]; /* Bytes 12-15 */
+ } __packed type3B;
+ struct {
+ enum myrb_cmd_opcode opcode; /* Byte 0 */
+ unsigned char id; /* Byte 1 */
+ unsigned char rsvd1[5]; /* Bytes 2-6 */
+ unsigned char ldev_num:6; /* Byte 7 Bits 0-6 */
+ unsigned char auto_restore:1; /* Byte 7 Bit 7 */
+ unsigned char rsvd2[8]; /* Bytes 8-15 */
+ } __packed type3C;
+ struct {
+ enum myrb_cmd_opcode opcode; /* Byte 0 */
+ unsigned char id; /* Byte 1 */
+ unsigned char channel; /* Byte 2 */
+ unsigned char target; /* Byte 3 */
+ enum myrb_devstate state; /* Byte 4 */
+ unsigned char rsvd1[3]; /* Bytes 5-7 */
+ u32 addr; /* Bytes 8-11 */
+ unsigned char rsvd2[4]; /* Bytes 12-15 */
+ } __packed type3D;
+ struct {
+ enum myrb_cmd_opcode opcode; /* Byte 0 */
+ unsigned char id; /* Byte 1 */
+ unsigned char optype; /* Byte 2 */
+ unsigned char opqual; /* Byte 3 */
+ unsigned short ev_seq; /* Bytes 4-5 */
+ unsigned char rsvd1[2]; /* Bytes 6-7 */
+ u32 addr; /* Bytes 8-11 */
+ unsigned char rsvd2[4]; /* Bytes 12-15 */
+ } __packed type3E;
+ struct {
+ enum myrb_cmd_opcode opcode; /* Byte 0 */
+ unsigned char id; /* Byte 1 */
+ unsigned char rsvd1[2]; /* Bytes 2-3 */
+ unsigned char rbld_rate; /* Byte 4 */
+ unsigned char rsvd2[3]; /* Bytes 5-7 */
+ u32 addr; /* Bytes 8-11 */
+ unsigned char rsvd3[4]; /* Bytes 12-15 */
+ } __packed type3R;
+ struct {
+ enum myrb_cmd_opcode opcode; /* Byte 0 */
+ unsigned char id; /* Byte 1 */
+ unsigned short xfer_len; /* Bytes 2-3 */
+ unsigned int lba; /* Bytes 4-7 */
+ u32 addr; /* Bytes 8-11 */
+ unsigned char ldev_num; /* Byte 12 */
+ unsigned char rsvd[3]; /* Bytes 13-15 */
+ } __packed type4;
+ struct {
+ enum myrb_cmd_opcode opcode; /* Byte 0 */
+ unsigned char id; /* Byte 1 */
+ struct {
+ unsigned short xfer_len:11; /* Bytes 2-3 */
+ unsigned char ldev_num:5; /* Byte 3 Bits 3-7 */
+ } __packed ld;
+ unsigned int lba; /* Bytes 4-7 */
+ u32 addr; /* Bytes 8-11 */
+ unsigned char sg_count:6; /* Byte 12 Bits 0-5 */
+ enum {
+ MYRB_SGL_ADDR32_COUNT32 = 0x0,
+ MYRB_SGL_ADDR32_COUNT16 = 0x1,
+ MYRB_SGL_COUNT32_ADDR32 = 0x2,
+ MYRB_SGL_COUNT16_ADDR32 = 0x3
+ } __packed sg_type:2; /* Byte 12 Bits 6-7 */
+ unsigned char rsvd[3]; /* Bytes 13-15 */
+ } __packed type5;
+ struct {
+ enum myrb_cmd_opcode opcode; /* Byte 0 */
+ unsigned char id; /* Byte 1 */
+ unsigned char opcode2; /* Byte 2 */
+ unsigned char rsvd1:8; /* Byte 3 */
+ u32 cmd_mbox_addr; /* Bytes 4-7 */
+ u32 stat_mbox_addr; /* Bytes 8-11 */
+ unsigned char rsvd2[4]; /* Bytes 12-15 */
+ } __packed typeX;
+};
+
+/*
+ * DAC960 V1 Firmware Controller Status Mailbox structure.
+ */
+struct myrb_stat_mbox {
+ unsigned char id; /* Byte 0 */
+ unsigned char rsvd:7; /* Byte 1 Bits 0-6 */
+ unsigned char valid:1; /* Byte 1 Bit 7 */
+ unsigned short status; /* Bytes 2-3 */
+};
+
+struct myrb_cmdblk {
+ union myrb_cmd_mbox mbox;
+ unsigned short status;
+ struct completion *completion;
+ struct myrb_dcdb *dcdb;
+ dma_addr_t dcdb_addr;
+ struct myrb_sge *sgl;
+ dma_addr_t sgl_addr;
+};
+
+struct myrb_hba {
+ unsigned int ldev_block_size;
+ unsigned char ldev_geom_heads;
+ unsigned char ldev_geom_sectors;
+ unsigned char bus_width;
+ unsigned short stripe_size;
+ unsigned short segment_size;
+ unsigned short new_ev_seq;
+ unsigned short old_ev_seq;
+ bool dual_mode_interface;
+ bool bgi_status_supported;
+ bool safte_enabled;
+ bool need_ldev_info;
+ bool need_err_info;
+ bool need_rbld;
+ bool need_cc_status;
+ bool need_bgi_status;
+ bool rbld_first;
+
+ struct pci_dev *pdev;
+ struct Scsi_Host *host;
+
+ struct workqueue_struct *work_q;
+ char work_q_name[20];
+ struct delayed_work monitor_work;
+ unsigned long primary_monitor_time;
+ unsigned long secondary_monitor_time;
+
+ struct dma_pool *sg_pool;
+ struct dma_pool *dcdb_pool;
+
+ spinlock_t queue_lock;
+
+ void (*qcmd)(struct myrb_hba *cs, struct myrb_cmdblk *cmd_blk);
+ void (*write_cmd_mbox)(union myrb_cmd_mbox *next_mbox,
+ union myrb_cmd_mbox *cmd_mbox);
+ void (*get_cmd_mbox)(void __iomem *base);
+ void (*disable_intr)(void __iomem *base);
+ void (*reset)(void __iomem *base);
+
+ unsigned int ctlr_num;
+ unsigned char model_name[20];
+ unsigned char fw_version[12];
+
+ unsigned int irq;
+ phys_addr_t io_addr;
+ phys_addr_t pci_addr;
+ void __iomem *io_base;
+ void __iomem *mmio_base;
+
+ size_t cmd_mbox_size;
+ dma_addr_t cmd_mbox_addr;
+ union myrb_cmd_mbox *first_cmd_mbox;
+ union myrb_cmd_mbox *last_cmd_mbox;
+ union myrb_cmd_mbox *next_cmd_mbox;
+ union myrb_cmd_mbox *prev_cmd_mbox1;
+ union myrb_cmd_mbox *prev_cmd_mbox2;
+
+ size_t stat_mbox_size;
+ dma_addr_t stat_mbox_addr;
+ struct myrb_stat_mbox *first_stat_mbox;
+ struct myrb_stat_mbox *last_stat_mbox;
+ struct myrb_stat_mbox *next_stat_mbox;
+
+ struct myrb_cmdblk dcmd_blk;
+ struct myrb_cmdblk mcmd_blk;
+ struct mutex dcmd_mutex;
+
+ struct myrb_enquiry *enquiry;
+ dma_addr_t enquiry_addr;
+
+ struct myrb_error_entry *err_table;
+ dma_addr_t err_table_addr;
+
+ unsigned short last_rbld_status;
+
+ struct myrb_ldev_info *ldev_info_buf;
+ dma_addr_t ldev_info_addr;
+
+ struct myrb_bgi_status bgi_status;
+
+ struct mutex dma_mutex;
+};
+
+/*
+ * DAC960 LA Series Controller Interface Register Offsets.
+ */
+#define DAC960_LA_mmio_size 0x80
+
+enum DAC960_LA_reg_offset {
+ DAC960_LA_IRQMASK_OFFSET = 0x34,
+ DAC960_LA_CMDOP_OFFSET = 0x50,
+ DAC960_LA_CMDID_OFFSET = 0x51,
+ DAC960_LA_MBOX2_OFFSET = 0x52,
+ DAC960_LA_MBOX3_OFFSET = 0x53,
+ DAC960_LA_MBOX4_OFFSET = 0x54,
+ DAC960_LA_MBOX5_OFFSET = 0x55,
+ DAC960_LA_MBOX6_OFFSET = 0x56,
+ DAC960_LA_MBOX7_OFFSET = 0x57,
+ DAC960_LA_MBOX8_OFFSET = 0x58,
+ DAC960_LA_MBOX9_OFFSET = 0x59,
+ DAC960_LA_MBOX10_OFFSET = 0x5A,
+ DAC960_LA_MBOX11_OFFSET = 0x5B,
+ DAC960_LA_MBOX12_OFFSET = 0x5C,
+ DAC960_LA_STSID_OFFSET = 0x5D,
+ DAC960_LA_STS_OFFSET = 0x5E,
+ DAC960_LA_IDB_OFFSET = 0x60,
+ DAC960_LA_ODB_OFFSET = 0x61,
+ DAC960_LA_ERRSTS_OFFSET = 0x63,
+};
+
+/*
+ * DAC960 LA Series Inbound Door Bell Register.
+ */
+#define DAC960_LA_IDB_HWMBOX_NEW_CMD 0x01
+#define DAC960_LA_IDB_HWMBOX_ACK_STS 0x02
+#define DAC960_LA_IDB_GEN_IRQ 0x04
+#define DAC960_LA_IDB_CTRL_RESET 0x08
+#define DAC960_LA_IDB_MMBOX_NEW_CMD 0x10
+
+#define DAC960_LA_IDB_HWMBOX_EMPTY 0x01
+#define DAC960_LA_IDB_INIT_DONE 0x02
+
+/*
+ * DAC960 LA Series Outbound Door Bell Register.
+ */
+#define DAC960_LA_ODB_HWMBOX_ACK_IRQ 0x01
+#define DAC960_LA_ODB_MMBOX_ACK_IRQ 0x02
+#define DAC960_LA_ODB_HWMBOX_STS_AVAIL 0x01
+#define DAC960_LA_ODB_MMBOX_STS_AVAIL 0x02
+
+/*
+ * DAC960 LA Series Interrupt Mask Register.
+ */
+#define DAC960_LA_IRQMASK_DISABLE_IRQ 0x04
+
+/*
+ * DAC960 LA Series Error Status Register.
+ */
+#define DAC960_LA_ERRSTS_PENDING 0x02
+
+/*
+ * DAC960 PG Series Controller Interface Register Offsets.
+ */
+#define DAC960_PG_mmio_size 0x2000
+
+enum DAC960_PG_reg_offset {
+ DAC960_PG_IDB_OFFSET = 0x0020,
+ DAC960_PG_ODB_OFFSET = 0x002C,
+ DAC960_PG_IRQMASK_OFFSET = 0x0034,
+ DAC960_PG_CMDOP_OFFSET = 0x1000,
+ DAC960_PG_CMDID_OFFSET = 0x1001,
+ DAC960_PG_MBOX2_OFFSET = 0x1002,
+ DAC960_PG_MBOX3_OFFSET = 0x1003,
+ DAC960_PG_MBOX4_OFFSET = 0x1004,
+ DAC960_PG_MBOX5_OFFSET = 0x1005,
+ DAC960_PG_MBOX6_OFFSET = 0x1006,
+ DAC960_PG_MBOX7_OFFSET = 0x1007,
+ DAC960_PG_MBOX8_OFFSET = 0x1008,
+ DAC960_PG_MBOX9_OFFSET = 0x1009,
+ DAC960_PG_MBOX10_OFFSET = 0x100A,
+ DAC960_PG_MBOX11_OFFSET = 0x100B,
+ DAC960_PG_MBOX12_OFFSET = 0x100C,
+ DAC960_PG_STSID_OFFSET = 0x1018,
+ DAC960_PG_STS_OFFSET = 0x101A,
+ DAC960_PG_ERRSTS_OFFSET = 0x103F,
+};
+
+/*
+ * DAC960 PG Series Inbound Door Bell Register.
+ */
+#define DAC960_PG_IDB_HWMBOX_NEW_CMD 0x01
+#define DAC960_PG_IDB_HWMBOX_ACK_STS 0x02
+#define DAC960_PG_IDB_GEN_IRQ 0x04
+#define DAC960_PG_IDB_CTRL_RESET 0x08
+#define DAC960_PG_IDB_MMBOX_NEW_CMD 0x10
+
+#define DAC960_PG_IDB_HWMBOX_FULL 0x01
+#define DAC960_PG_IDB_INIT_IN_PROGRESS 0x02
+
+/*
+ * DAC960 PG Series Outbound Door Bell Register.
+ */
+#define DAC960_PG_ODB_HWMBOX_ACK_IRQ 0x01
+#define DAC960_PG_ODB_MMBOX_ACK_IRQ 0x02
+#define DAC960_PG_ODB_HWMBOX_STS_AVAIL 0x01
+#define DAC960_PG_ODB_MMBOX_STS_AVAIL 0x02
+
+/*
+ * DAC960 PG Series Interrupt Mask Register.
+ */
+#define DAC960_PG_IRQMASK_MSI_MASK1 0x03
+#define DAC960_PG_IRQMASK_DISABLE_IRQ 0x04
+#define DAC960_PG_IRQMASK_MSI_MASK2 0xF8
+
+/*
+ * DAC960 PG Series Error Status Register.
+ */
+#define DAC960_PG_ERRSTS_PENDING 0x04
+
+/*
+ * DAC960 PD Series Controller Interface Register Offsets.
+ */
+#define DAC960_PD_mmio_size 0x80
+
+enum DAC960_PD_reg_offset {
+ DAC960_PD_CMDOP_OFFSET = 0x00,
+ DAC960_PD_CMDID_OFFSET = 0x01,
+ DAC960_PD_MBOX2_OFFSET = 0x02,
+ DAC960_PD_MBOX3_OFFSET = 0x03,
+ DAC960_PD_MBOX4_OFFSET = 0x04,
+ DAC960_PD_MBOX5_OFFSET = 0x05,
+ DAC960_PD_MBOX6_OFFSET = 0x06,
+ DAC960_PD_MBOX7_OFFSET = 0x07,
+ DAC960_PD_MBOX8_OFFSET = 0x08,
+ DAC960_PD_MBOX9_OFFSET = 0x09,
+ DAC960_PD_MBOX10_OFFSET = 0x0A,
+ DAC960_PD_MBOX11_OFFSET = 0x0B,
+ DAC960_PD_MBOX12_OFFSET = 0x0C,
+ DAC960_PD_STSID_OFFSET = 0x0D,
+ DAC960_PD_STS_OFFSET = 0x0E,
+ DAC960_PD_ERRSTS_OFFSET = 0x3F,
+ DAC960_PD_IDB_OFFSET = 0x40,
+ DAC960_PD_ODB_OFFSET = 0x41,
+ DAC960_PD_IRQEN_OFFSET = 0x43,
+};
+
+/*
+ * DAC960 PD Series Inbound Door Bell Register.
+ */
+#define DAC960_PD_IDB_HWMBOX_NEW_CMD 0x01
+#define DAC960_PD_IDB_HWMBOX_ACK_STS 0x02
+#define DAC960_PD_IDB_GEN_IRQ 0x04
+#define DAC960_PD_IDB_CTRL_RESET 0x08
+
+#define DAC960_PD_IDB_HWMBOX_FULL 0x01
+#define DAC960_PD_IDB_INIT_IN_PROGRESS 0x02
+
+/*
+ * DAC960 PD Series Outbound Door Bell Register.
+ */
+#define DAC960_PD_ODB_HWMBOX_ACK_IRQ 0x01
+#define DAC960_PD_ODB_HWMBOX_STS_AVAIL 0x01
+
+/*
+ * DAC960 PD Series Interrupt Enable Register.
+ */
+#define DAC960_PD_IRQMASK_ENABLE_IRQ 0x01
+
+/*
+ * DAC960 PD Series Error Status Register.
+ */
+#define DAC960_PD_ERRSTS_PENDING 0x04
+
+typedef int (*myrb_hw_init_t)(struct pci_dev *pdev,
+ struct myrb_hba *cb, void __iomem *base);
+typedef unsigned short (*mbox_mmio_init_t)(struct pci_dev *pdev,
+ void __iomem *base,
+ union myrb_cmd_mbox *mbox);
+
+struct myrb_privdata {
+ myrb_hw_init_t hw_init;
+ irq_handler_t irq_handler;
+ unsigned int mmio_size;
+};
+
+#endif /* MYRB_H */
diff --git a/drivers/scsi/myrs.c b/drivers/scsi/myrs.c
new file mode 100644
index 000000000000..b8d54ef8cf6d
--- /dev/null
+++ b/drivers/scsi/myrs.c
@@ -0,0 +1,3271 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers
+ *
+ * This driver supports the newer, SCSI-based firmware interface only.
+ *
+ * Copyright 2017 Hannes Reinecke, SUSE Linux GmbH <hare@suse.com>
+ *
+ * Based on the original DAC960 driver, which has
+ * Copyright 1998-2001 by Leonard N. Zubkoff <lnz@dandelion.com>
+ * Portions Copyright 2002 by Mylex (An IBM Business Unit)
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/raid_class.h>
+#include <asm/unaligned.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_tcq.h>
+#include "myrs.h"
+
+static struct raid_template *myrs_raid_template;
+
+static struct myrs_devstate_name_entry {
+ enum myrs_devstate state;
+ char *name;
+} myrs_devstate_name_list[] = {
+ { MYRS_DEVICE_UNCONFIGURED, "Unconfigured" },
+ { MYRS_DEVICE_ONLINE, "Online" },
+ { MYRS_DEVICE_REBUILD, "Rebuild" },
+ { MYRS_DEVICE_MISSING, "Missing" },
+ { MYRS_DEVICE_SUSPECTED_CRITICAL, "SuspectedCritical" },
+ { MYRS_DEVICE_OFFLINE, "Offline" },
+ { MYRS_DEVICE_CRITICAL, "Critical" },
+ { MYRS_DEVICE_SUSPECTED_DEAD, "SuspectedDead" },
+ { MYRS_DEVICE_COMMANDED_OFFLINE, "CommandedOffline" },
+ { MYRS_DEVICE_STANDBY, "Standby" },
+ { MYRS_DEVICE_INVALID_STATE, "Invalid" },
+};
+
+static char *myrs_devstate_name(enum myrs_devstate state)
+{
+ struct myrs_devstate_name_entry *entry = myrs_devstate_name_list;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(myrs_devstate_name_list); i++) {
+ if (entry[i].state == state)
+ return entry[i].name;
+ }
+ return NULL;
+}
+
+static struct myrs_raid_level_name_entry {
+ enum myrs_raid_level level;
+ char *name;
+} myrs_raid_level_name_list[] = {
+ { MYRS_RAID_LEVEL0, "RAID0" },
+ { MYRS_RAID_LEVEL1, "RAID1" },
+ { MYRS_RAID_LEVEL3, "RAID3 right asymmetric parity" },
+ { MYRS_RAID_LEVEL5, "RAID5 right asymmetric parity" },
+ { MYRS_RAID_LEVEL6, "RAID6" },
+ { MYRS_RAID_JBOD, "JBOD" },
+ { MYRS_RAID_NEWSPAN, "New Mylex SPAN" },
+ { MYRS_RAID_LEVEL3F, "RAID3 fixed parity" },
+ { MYRS_RAID_LEVEL3L, "RAID3 left symmetric parity" },
+ { MYRS_RAID_SPAN, "Mylex SPAN" },
+ { MYRS_RAID_LEVEL5L, "RAID5 left symmetric parity" },
+ { MYRS_RAID_LEVELE, "RAIDE (concatenation)" },
+ { MYRS_RAID_PHYSICAL, "Physical device" },
+};
+
+static char *myrs_raid_level_name(enum myrs_raid_level level)
+{
+ struct myrs_raid_level_name_entry *entry = myrs_raid_level_name_list;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(myrs_raid_level_name_list); i++) {
+ if (entry[i].level == level)
+ return entry[i].name;
+ }
+ return NULL;
+}
+
+/**
+ * myrs_reset_cmd - clears critical fields in struct myrs_cmdblk
+ */
+static inline void myrs_reset_cmd(struct myrs_cmdblk *cmd_blk)
+{
+ union myrs_cmd_mbox *mbox = &cmd_blk->mbox;
+
+ memset(mbox, 0, sizeof(union myrs_cmd_mbox));
+ cmd_blk->status = 0;
+}
+
+/**
+ * myrs_qcmd - queues Command for DAC960 V2 Series Controllers.
+ */
+static void myrs_qcmd(struct myrs_hba *cs, struct myrs_cmdblk *cmd_blk)
+{
+ void __iomem *base = cs->io_base;
+ union myrs_cmd_mbox *mbox = &cmd_blk->mbox;
+ union myrs_cmd_mbox *next_mbox = cs->next_cmd_mbox;
+
+ cs->write_cmd_mbox(next_mbox, mbox);
+
+ if (cs->prev_cmd_mbox1->words[0] == 0 ||
+ cs->prev_cmd_mbox2->words[0] == 0)
+ cs->get_cmd_mbox(base);
+
+ cs->prev_cmd_mbox2 = cs->prev_cmd_mbox1;
+ cs->prev_cmd_mbox1 = next_mbox;
+
+ if (++next_mbox > cs->last_cmd_mbox)
+ next_mbox = cs->first_cmd_mbox;
+
+ cs->next_cmd_mbox = next_mbox;
+}
+
+/**
+ * myrs_exec_cmd - executes V2 Command and waits for completion.
+ */
+static void myrs_exec_cmd(struct myrs_hba *cs,
+ struct myrs_cmdblk *cmd_blk)
+{
+ DECLARE_COMPLETION_ONSTACK(complete);
+ unsigned long flags;
+
+ cmd_blk->complete = &complete;
+ spin_lock_irqsave(&cs->queue_lock, flags);
+ myrs_qcmd(cs, cmd_blk);
+ spin_unlock_irqrestore(&cs->queue_lock, flags);
+
+ WARN_ON(in_interrupt());
+ wait_for_completion(&complete);
+}
+
+/**
+ * myrs_report_progress - prints progress message
+ */
+static void myrs_report_progress(struct myrs_hba *cs, unsigned short ldev_num,
+ unsigned char *msg, unsigned long blocks,
+ unsigned long size)
+{
+ shost_printk(KERN_INFO, cs->host,
+ "Logical Drive %d: %s in Progress: %d%% completed\n",
+ ldev_num, msg,
+ (100 * (int)(blocks >> 7)) / (int)(size >> 7));
+}
+
+/**
+ * myrs_get_ctlr_info - executes a Controller Information IOCTL Command
+ */
+static unsigned char myrs_get_ctlr_info(struct myrs_hba *cs)
+{
+ struct myrs_cmdblk *cmd_blk = &cs->dcmd_blk;
+ union myrs_cmd_mbox *mbox = &cmd_blk->mbox;
+ dma_addr_t ctlr_info_addr;
+ union myrs_sgl *sgl;
+ unsigned char status;
+ unsigned short ldev_present, ldev_critical, ldev_offline;
+
+ ldev_present = cs->ctlr_info->ldev_present;
+ ldev_critical = cs->ctlr_info->ldev_critical;
+ ldev_offline = cs->ctlr_info->ldev_offline;
+
+ ctlr_info_addr = dma_map_single(&cs->pdev->dev, cs->ctlr_info,
+ sizeof(struct myrs_ctlr_info),
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(&cs->pdev->dev, ctlr_info_addr))
+ return MYRS_STATUS_FAILED;
+
+ mutex_lock(&cs->dcmd_mutex);
+ myrs_reset_cmd(cmd_blk);
+ mbox->ctlr_info.id = MYRS_DCMD_TAG;
+ mbox->ctlr_info.opcode = MYRS_CMD_OP_IOCTL;
+ mbox->ctlr_info.control.dma_ctrl_to_host = true;
+ mbox->ctlr_info.control.no_autosense = true;
+ mbox->ctlr_info.dma_size = sizeof(struct myrs_ctlr_info);
+ mbox->ctlr_info.ctlr_num = 0;
+ mbox->ctlr_info.ioctl_opcode = MYRS_IOCTL_GET_CTLR_INFO;
+ sgl = &mbox->ctlr_info.dma_addr;
+ sgl->sge[0].sge_addr = ctlr_info_addr;
+ sgl->sge[0].sge_count = mbox->ctlr_info.dma_size;
+ dev_dbg(&cs->host->shost_gendev, "Sending GetControllerInfo\n");
+ myrs_exec_cmd(cs, cmd_blk);
+ status = cmd_blk->status;
+ mutex_unlock(&cs->dcmd_mutex);
+ dma_unmap_single(&cs->pdev->dev, ctlr_info_addr,
+ sizeof(struct myrs_ctlr_info), DMA_FROM_DEVICE);
+ if (status == MYRS_STATUS_SUCCESS) {
+ if (cs->ctlr_info->bg_init_active +
+ cs->ctlr_info->ldev_init_active +
+ cs->ctlr_info->pdev_init_active +
+ cs->ctlr_info->cc_active +
+ cs->ctlr_info->rbld_active +
+ cs->ctlr_info->exp_active != 0)
+ cs->needs_update = true;
+ if (cs->ctlr_info->ldev_present != ldev_present ||
+ cs->ctlr_info->ldev_critical != ldev_critical ||
+ cs->ctlr_info->ldev_offline != ldev_offline)
+ shost_printk(KERN_INFO, cs->host,
+ "Logical drive count changes (%d/%d/%d)\n",
+ cs->ctlr_info->ldev_critical,
+ cs->ctlr_info->ldev_offline,
+ cs->ctlr_info->ldev_present);
+ }
+
+ return status;
+}
+
+/**
+ * myrs_get_ldev_info - executes a Logical Device Information IOCTL Command
+ */
+static unsigned char myrs_get_ldev_info(struct myrs_hba *cs,
+ unsigned short ldev_num, struct myrs_ldev_info *ldev_info)
+{
+ struct myrs_cmdblk *cmd_blk = &cs->dcmd_blk;
+ union myrs_cmd_mbox *mbox = &cmd_blk->mbox;
+ dma_addr_t ldev_info_addr;
+ struct myrs_ldev_info ldev_info_orig;
+ union myrs_sgl *sgl;
+ unsigned char status;
+
+ memcpy(&ldev_info_orig, ldev_info, sizeof(struct myrs_ldev_info));
+ ldev_info_addr = dma_map_single(&cs->pdev->dev, ldev_info,
+ sizeof(struct myrs_ldev_info),
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(&cs->pdev->dev, ldev_info_addr))
+ return MYRS_STATUS_FAILED;
+
+ mutex_lock(&cs->dcmd_mutex);
+ myrs_reset_cmd(cmd_blk);
+ mbox->ldev_info.id = MYRS_DCMD_TAG;
+ mbox->ldev_info.opcode = MYRS_CMD_OP_IOCTL;
+ mbox->ldev_info.control.dma_ctrl_to_host = true;
+ mbox->ldev_info.control.no_autosense = true;
+ mbox->ldev_info.dma_size = sizeof(struct myrs_ldev_info);
+ mbox->ldev_info.ldev.ldev_num = ldev_num;
+ mbox->ldev_info.ioctl_opcode = MYRS_IOCTL_GET_LDEV_INFO_VALID;
+ sgl = &mbox->ldev_info.dma_addr;
+ sgl->sge[0].sge_addr = ldev_info_addr;
+ sgl->sge[0].sge_count = mbox->ldev_info.dma_size;
+ dev_dbg(&cs->host->shost_gendev,
+ "Sending GetLogicalDeviceInfoValid for ldev %d\n", ldev_num);
+ myrs_exec_cmd(cs, cmd_blk);
+ status = cmd_blk->status;
+ mutex_unlock(&cs->dcmd_mutex);
+ dma_unmap_single(&cs->pdev->dev, ldev_info_addr,
+ sizeof(struct myrs_ldev_info), DMA_FROM_DEVICE);
+ if (status == MYRS_STATUS_SUCCESS) {
+ unsigned short ldev_num = ldev_info->ldev_num;
+ struct myrs_ldev_info *new = ldev_info;
+ struct myrs_ldev_info *old = &ldev_info_orig;
+ unsigned long ldev_size = new->cfg_devsize;
+
+ if (new->dev_state != old->dev_state) {
+ const char *name;
+
+ name = myrs_devstate_name(new->dev_state);
+ shost_printk(KERN_INFO, cs->host,
+ "Logical Drive %d is now %s\n",
+ ldev_num, name ? name : "Invalid");
+ }
+ if ((new->soft_errs != old->soft_errs) ||
+ (new->cmds_failed != old->cmds_failed) ||
+ (new->deferred_write_errs != old->deferred_write_errs))
+ shost_printk(KERN_INFO, cs->host,
+ "Logical Drive %d Errors: Soft = %d, Failed = %d, Deferred Write = %d\n",
+ ldev_num, new->soft_errs,
+ new->cmds_failed,
+ new->deferred_write_errs);
+ if (new->bg_init_active)
+ myrs_report_progress(cs, ldev_num,
+ "Background Initialization",
+ new->bg_init_lba, ldev_size);
+ else if (new->fg_init_active)
+ myrs_report_progress(cs, ldev_num,
+ "Foreground Initialization",
+ new->fg_init_lba, ldev_size);
+ else if (new->migration_active)
+ myrs_report_progress(cs, ldev_num,
+ "Data Migration",
+ new->migration_lba, ldev_size);
+ else if (new->patrol_active)
+ myrs_report_progress(cs, ldev_num,
+ "Patrol Operation",
+ new->patrol_lba, ldev_size);
+ if (old->bg_init_active && !new->bg_init_active)
+ shost_printk(KERN_INFO, cs->host,
+ "Logical Drive %d: Background Initialization %s\n",
+ ldev_num,
+ (new->ldev_control.ldev_init_done ?
+ "Completed" : "Failed"));
+ }
+ return status;
+}
+
+/**
+ * myrs_get_pdev_info - executes a "Read Physical Device Information" Command
+ */
+static unsigned char myrs_get_pdev_info(struct myrs_hba *cs,
+ unsigned char channel, unsigned char target, unsigned char lun,
+ struct myrs_pdev_info *pdev_info)
+{
+ struct myrs_cmdblk *cmd_blk = &cs->dcmd_blk;
+ union myrs_cmd_mbox *mbox = &cmd_blk->mbox;
+ dma_addr_t pdev_info_addr;
+ union myrs_sgl *sgl;
+ unsigned char status;
+
+ pdev_info_addr = dma_map_single(&cs->pdev->dev, pdev_info,
+ sizeof(struct myrs_pdev_info),
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(&cs->pdev->dev, pdev_info_addr))
+ return MYRS_STATUS_FAILED;
+
+ mutex_lock(&cs->dcmd_mutex);
+ myrs_reset_cmd(cmd_blk);
+ mbox->pdev_info.opcode = MYRS_CMD_OP_IOCTL;
+ mbox->pdev_info.id = MYRS_DCMD_TAG;
+ mbox->pdev_info.control.dma_ctrl_to_host = true;
+ mbox->pdev_info.control.no_autosense = true;
+ mbox->pdev_info.dma_size = sizeof(struct myrs_pdev_info);
+ mbox->pdev_info.pdev.lun = lun;
+ mbox->pdev_info.pdev.target = target;
+ mbox->pdev_info.pdev.channel = channel;
+ mbox->pdev_info.ioctl_opcode = MYRS_IOCTL_GET_PDEV_INFO_VALID;
+ sgl = &mbox->pdev_info.dma_addr;
+ sgl->sge[0].sge_addr = pdev_info_addr;
+ sgl->sge[0].sge_count = mbox->pdev_info.dma_size;
+ dev_dbg(&cs->host->shost_gendev,
+ "Sending GetPhysicalDeviceInfoValid for pdev %d:%d:%d\n",
+ channel, target, lun);
+ myrs_exec_cmd(cs, cmd_blk);
+ status = cmd_blk->status;
+ mutex_unlock(&cs->dcmd_mutex);
+ dma_unmap_single(&cs->pdev->dev, pdev_info_addr,
+ sizeof(struct myrs_pdev_info), DMA_FROM_DEVICE);
+ return status;
+}
+
+/**
+ * myrs_dev_op - executes a "Device Operation" Command
+ */
+static unsigned char myrs_dev_op(struct myrs_hba *cs,
+ enum myrs_ioctl_opcode opcode, enum myrs_opdev opdev)
+{
+ struct myrs_cmdblk *cmd_blk = &cs->dcmd_blk;
+ union myrs_cmd_mbox *mbox = &cmd_blk->mbox;
+ unsigned char status;
+
+ mutex_lock(&cs->dcmd_mutex);
+ myrs_reset_cmd(cmd_blk);
+ mbox->dev_op.opcode = MYRS_CMD_OP_IOCTL;
+ mbox->dev_op.id = MYRS_DCMD_TAG;
+ mbox->dev_op.control.dma_ctrl_to_host = true;
+ mbox->dev_op.control.no_autosense = true;
+ mbox->dev_op.ioctl_opcode = opcode;
+ mbox->dev_op.opdev = opdev;
+ myrs_exec_cmd(cs, cmd_blk);
+ status = cmd_blk->status;
+ mutex_unlock(&cs->dcmd_mutex);
+ return status;
+}
+
+/**
+ * myrs_translate_pdev - translates a Physical Device Channel and
+ * TargetID into a Logical Device.
+ */
+static unsigned char myrs_translate_pdev(struct myrs_hba *cs,
+ unsigned char channel, unsigned char target, unsigned char lun,
+ struct myrs_devmap *devmap)
+{
+ struct pci_dev *pdev = cs->pdev;
+ dma_addr_t devmap_addr;
+ struct myrs_cmdblk *cmd_blk;
+ union myrs_cmd_mbox *mbox;
+ union myrs_sgl *sgl;
+ unsigned char status;
+
+ memset(devmap, 0x0, sizeof(struct myrs_devmap));
+ devmap_addr = dma_map_single(&pdev->dev, devmap,
+ sizeof(struct myrs_devmap),
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(&pdev->dev, devmap_addr))
+ return MYRS_STATUS_FAILED;
+
+ mutex_lock(&cs->dcmd_mutex);
+ cmd_blk = &cs->dcmd_blk;
+ mbox = &cmd_blk->mbox;
+ mbox->pdev_info.opcode = MYRS_CMD_OP_IOCTL;
+ mbox->pdev_info.control.dma_ctrl_to_host = true;
+ mbox->pdev_info.control.no_autosense = true;
+ mbox->pdev_info.dma_size = sizeof(struct myrs_devmap);
+ mbox->pdev_info.pdev.target = target;
+ mbox->pdev_info.pdev.channel = channel;
+ mbox->pdev_info.pdev.lun = lun;
+ mbox->pdev_info.ioctl_opcode = MYRS_IOCTL_XLATE_PDEV_TO_LDEV;
+ sgl = &mbox->pdev_info.dma_addr;
+ sgl->sge[0].sge_addr = devmap_addr;
+ sgl->sge[0].sge_count = mbox->pdev_info.dma_size;
+
+ myrs_exec_cmd(cs, cmd_blk);
+ status = cmd_blk->status;
+ mutex_unlock(&cs->dcmd_mutex);
+ dma_unmap_single(&pdev->dev, devmap_addr,
+ sizeof(struct myrs_devmap), DMA_FROM_DEVICE);
+ return status;
+}
+
+/**
+ * myrs_get_event - executes a Get Event Command
+ */
+static unsigned char myrs_get_event(struct myrs_hba *cs,
+ unsigned int event_num, struct myrs_event *event_buf)
+{
+ struct pci_dev *pdev = cs->pdev;
+ dma_addr_t event_addr;
+ struct myrs_cmdblk *cmd_blk = &cs->mcmd_blk;
+ union myrs_cmd_mbox *mbox = &cmd_blk->mbox;
+ union myrs_sgl *sgl;
+ unsigned char status;
+
+ event_addr = dma_map_single(&pdev->dev, event_buf,
+ sizeof(struct myrs_event), DMA_FROM_DEVICE);
+ if (dma_mapping_error(&pdev->dev, event_addr))
+ return MYRS_STATUS_FAILED;
+
+ mbox->get_event.opcode = MYRS_CMD_OP_IOCTL;
+ mbox->get_event.dma_size = sizeof(struct myrs_event);
+ mbox->get_event.evnum_upper = event_num >> 16;
+ mbox->get_event.ctlr_num = 0;
+ mbox->get_event.ioctl_opcode = MYRS_IOCTL_GET_EVENT;
+ mbox->get_event.evnum_lower = event_num & 0xFFFF;
+ sgl = &mbox->get_event.dma_addr;
+ sgl->sge[0].sge_addr = event_addr;
+ sgl->sge[0].sge_count = mbox->get_event.dma_size;
+ myrs_exec_cmd(cs, cmd_blk);
+ status = cmd_blk->status;
+ dma_unmap_single(&pdev->dev, event_addr,
+ sizeof(struct myrs_event), DMA_FROM_DEVICE);
+
+ return status;
+}
+
+/*
+ * myrs_get_fwstatus - executes a Get Health Status Command
+ */
+static unsigned char myrs_get_fwstatus(struct myrs_hba *cs)
+{
+ struct myrs_cmdblk *cmd_blk = &cs->mcmd_blk;
+ union myrs_cmd_mbox *mbox = &cmd_blk->mbox;
+ union myrs_sgl *sgl;
+ unsigned char status = cmd_blk->status;
+
+ myrs_reset_cmd(cmd_blk);
+ mbox->common.opcode = MYRS_CMD_OP_IOCTL;
+ mbox->common.id = MYRS_MCMD_TAG;
+ mbox->common.control.dma_ctrl_to_host = true;
+ mbox->common.control.no_autosense = true;
+ mbox->common.dma_size = sizeof(struct myrs_fwstat);
+ mbox->common.ioctl_opcode = MYRS_IOCTL_GET_HEALTH_STATUS;
+ sgl = &mbox->common.dma_addr;
+ sgl->sge[0].sge_addr = cs->fwstat_addr;
+ sgl->sge[0].sge_count = mbox->ctlr_info.dma_size;
+ dev_dbg(&cs->host->shost_gendev, "Sending GetHealthStatus\n");
+ myrs_exec_cmd(cs, cmd_blk);
+ status = cmd_blk->status;
+
+ return status;
+}
+
+/**
+ * myrs_enable_mmio_mbox - enables the Memory Mailbox Interface
+ */
+static bool myrs_enable_mmio_mbox(struct myrs_hba *cs,
+ enable_mbox_t enable_mbox_fn)
+{
+ void __iomem *base = cs->io_base;
+ struct pci_dev *pdev = cs->pdev;
+ union myrs_cmd_mbox *cmd_mbox;
+ struct myrs_stat_mbox *stat_mbox;
+ union myrs_cmd_mbox *mbox;
+ dma_addr_t mbox_addr;
+ unsigned char status = MYRS_STATUS_FAILED;
+
+ if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)))
+ if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) {
+ dev_err(&pdev->dev, "DMA mask out of range\n");
+ return false;
+ }
+
+ /* Temporary dma mapping, used only in the scope of this function */
+ mbox = dma_alloc_coherent(&pdev->dev, sizeof(union myrs_cmd_mbox),
+ &mbox_addr, GFP_KERNEL);
+ if (dma_mapping_error(&pdev->dev, mbox_addr))
+ return false;
+
+ /* These are the base addresses for the command memory mailbox array */
+ cs->cmd_mbox_size = MYRS_MAX_CMD_MBOX * sizeof(union myrs_cmd_mbox);
+ cmd_mbox = dma_alloc_coherent(&pdev->dev, cs->cmd_mbox_size,
+ &cs->cmd_mbox_addr, GFP_KERNEL);
+ if (dma_mapping_error(&pdev->dev, cs->cmd_mbox_addr)) {
+ dev_err(&pdev->dev, "Failed to map command mailbox\n");
+ goto out_free;
+ }
+ cs->first_cmd_mbox = cmd_mbox;
+ cmd_mbox += MYRS_MAX_CMD_MBOX - 1;
+ cs->last_cmd_mbox = cmd_mbox;
+ cs->next_cmd_mbox = cs->first_cmd_mbox;
+ cs->prev_cmd_mbox1 = cs->last_cmd_mbox;
+ cs->prev_cmd_mbox2 = cs->last_cmd_mbox - 1;
+
+ /* These are the base addresses for the status memory mailbox array */
+ cs->stat_mbox_size = MYRS_MAX_STAT_MBOX * sizeof(struct myrs_stat_mbox);
+ stat_mbox = dma_alloc_coherent(&pdev->dev, cs->stat_mbox_size,
+ &cs->stat_mbox_addr, GFP_KERNEL);
+ if (dma_mapping_error(&pdev->dev, cs->stat_mbox_addr)) {
+ dev_err(&pdev->dev, "Failed to map status mailbox\n");
+ goto out_free;
+ }
+
+ cs->first_stat_mbox = stat_mbox;
+ stat_mbox += MYRS_MAX_STAT_MBOX - 1;
+ cs->last_stat_mbox = stat_mbox;
+ cs->next_stat_mbox = cs->first_stat_mbox;
+
+ cs->fwstat_buf = dma_alloc_coherent(&pdev->dev,
+ sizeof(struct myrs_fwstat),
+ &cs->fwstat_addr, GFP_KERNEL);
+ if (dma_mapping_error(&pdev->dev, cs->fwstat_addr)) {
+ dev_err(&pdev->dev, "Failed to map firmware health buffer\n");
+ cs->fwstat_buf = NULL;
+ goto out_free;
+ }
+ cs->ctlr_info = kzalloc(sizeof(struct myrs_ctlr_info),
+ GFP_KERNEL | GFP_DMA);
+ if (!cs->ctlr_info)
+ goto out_free;
+
+ cs->event_buf = kzalloc(sizeof(struct myrs_event),
+ GFP_KERNEL | GFP_DMA);
+ if (!cs->event_buf)
+ goto out_free;
+
+ /* Enable the Memory Mailbox Interface. */
+ memset(mbox, 0, sizeof(union myrs_cmd_mbox));
+ mbox->set_mbox.id = 1;
+ mbox->set_mbox.opcode = MYRS_CMD_OP_IOCTL;
+ mbox->set_mbox.control.no_autosense = true;
+ mbox->set_mbox.first_cmd_mbox_size_kb =
+ (MYRS_MAX_CMD_MBOX * sizeof(union myrs_cmd_mbox)) >> 10;
+ mbox->set_mbox.first_stat_mbox_size_kb =
+ (MYRS_MAX_STAT_MBOX * sizeof(struct myrs_stat_mbox)) >> 10;
+ mbox->set_mbox.second_cmd_mbox_size_kb = 0;
+ mbox->set_mbox.second_stat_mbox_size_kb = 0;
+ mbox->set_mbox.sense_len = 0;
+ mbox->set_mbox.ioctl_opcode = MYRS_IOCTL_SET_MEM_MBOX;
+ mbox->set_mbox.fwstat_buf_size_kb = 1;
+ mbox->set_mbox.fwstat_buf_addr = cs->fwstat_addr;
+ mbox->set_mbox.first_cmd_mbox_addr = cs->cmd_mbox_addr;
+ mbox->set_mbox.first_stat_mbox_addr = cs->stat_mbox_addr;
+ status = enable_mbox_fn(base, mbox_addr);
+
+out_free:
+ dma_free_coherent(&pdev->dev, sizeof(union myrs_cmd_mbox),
+ mbox, mbox_addr);
+ if (status != MYRS_STATUS_SUCCESS)
+ dev_err(&pdev->dev, "Failed to enable mailbox, status %X\n",
+ status);
+ return (status == MYRS_STATUS_SUCCESS);
+}
+
+/**
+ * myrs_get_config - reads the Configuration Information
+ */
+static int myrs_get_config(struct myrs_hba *cs)
+{
+ struct myrs_ctlr_info *info = cs->ctlr_info;
+ struct Scsi_Host *shost = cs->host;
+ unsigned char status;
+ unsigned char model[20];
+ unsigned char fw_version[12];
+ int i, model_len;
+
+ /* Get data into dma-able area, then copy into permanent location */
+ mutex_lock(&cs->cinfo_mutex);
+ status = myrs_get_ctlr_info(cs);
+ mutex_unlock(&cs->cinfo_mutex);
+ if (status != MYRS_STATUS_SUCCESS) {
+ shost_printk(KERN_ERR, shost,
+ "Failed to get controller information\n");
+ return -ENODEV;
+ }
+
+ /* Initialize the Controller Model Name and Full Model Name fields. */
+ model_len = sizeof(info->ctlr_name);
+ if (model_len > sizeof(model)-1)
+ model_len = sizeof(model)-1;
+ memcpy(model, info->ctlr_name, model_len);
+ model_len--;
+ while (model[model_len] == ' ' || model[model_len] == '\0')
+ model_len--;
+ model[++model_len] = '\0';
+ strcpy(cs->model_name, "DAC960 ");
+ strcat(cs->model_name, model);
+ /* Initialize the Controller Firmware Version field. */
+ sprintf(fw_version, "%d.%02d-%02d",
+ info->fw_major_version, info->fw_minor_version,
+ info->fw_turn_number);
+ if (info->fw_major_version == 6 &&
+ info->fw_minor_version == 0 &&
+ info->fw_turn_number < 1) {
+ shost_printk(KERN_WARNING, shost,
+ "FIRMWARE VERSION %s DOES NOT PROVIDE THE CONTROLLER\n"
+ "STATUS MONITORING FUNCTIONALITY NEEDED BY THIS DRIVER.\n"
+ "PLEASE UPGRADE TO VERSION 6.00-01 OR ABOVE.\n",
+ fw_version);
+ return -ENODEV;
+ }
+ /* Initialize the Controller Channels and Targets. */
+ shost->max_channel = info->physchan_present + info->virtchan_present;
+ shost->max_id = info->max_targets[0];
+ for (i = 1; i < 16; i++) {
+ if (!info->max_targets[i])
+ continue;
+ if (shost->max_id < info->max_targets[i])
+ shost->max_id = info->max_targets[i];
+ }
+
+ /*
+ * Initialize the Controller Queue Depth, Driver Queue Depth,
+ * Logical Drive Count, Maximum Blocks per Command, Controller
+ * Scatter/Gather Limit, and Driver Scatter/Gather Limit.
+ * The Driver Queue Depth must be at most three less than
+ * the Controller Queue Depth; tag '1' is reserved for
+ * direct commands, and tag '2' for monitoring commands.
+ */
+ shost->can_queue = info->max_tcq - 3;
+ if (shost->can_queue > MYRS_MAX_CMD_MBOX - 3)
+ shost->can_queue = MYRS_MAX_CMD_MBOX - 3;
+ shost->max_sectors = info->max_transfer_size;
+ shost->sg_tablesize = info->max_sge;
+ if (shost->sg_tablesize > MYRS_SG_LIMIT)
+ shost->sg_tablesize = MYRS_SG_LIMIT;
+
+ shost_printk(KERN_INFO, shost,
+ "Configuring %s PCI RAID Controller\n", model);
+ shost_printk(KERN_INFO, shost,
+ " Firmware Version: %s, Channels: %d, Memory Size: %dMB\n",
+ fw_version, info->physchan_present, info->mem_size_mb);
+
+ shost_printk(KERN_INFO, shost,
+ " Controller Queue Depth: %d, Maximum Blocks per Command: %d\n",
+ shost->can_queue, shost->max_sectors);
+
+ shost_printk(KERN_INFO, shost,
+ " Driver Queue Depth: %d, Scatter/Gather Limit: %d of %d Segments\n",
+ shost->can_queue, shost->sg_tablesize, MYRS_SG_LIMIT);
+ for (i = 0; i < info->physchan_max; i++) {
+ if (!info->max_targets[i])
+ continue;
+ shost_printk(KERN_INFO, shost,
+ " Device Channel %d: max %d devices\n",
+ i, info->max_targets[i]);
+ }
+ shost_printk(KERN_INFO, shost,
+ " Physical: %d/%d channels, %d disks, %d devices\n",
+ info->physchan_present, info->physchan_max,
+ info->pdisk_present, info->pdev_present);
+
+ shost_printk(KERN_INFO, shost,
+ " Logical: %d/%d channels, %d disks\n",
+ info->virtchan_present, info->virtchan_max,
+ info->ldev_present);
+ return 0;
+}
+
+/**
+ * myrs_log_event - prints a Controller Event message
+ */
+static struct {
+ int ev_code;
+ unsigned char *ev_msg;
+} myrs_ev_list[] = {
+ /* Physical Device Events (0x0000 - 0x007F) */
+ { 0x0001, "P Online" },
+ { 0x0002, "P Standby" },
+ { 0x0005, "P Automatic Rebuild Started" },
+ { 0x0006, "P Manual Rebuild Started" },
+ { 0x0007, "P Rebuild Completed" },
+ { 0x0008, "P Rebuild Cancelled" },
+ { 0x0009, "P Rebuild Failed for Unknown Reasons" },
+ { 0x000A, "P Rebuild Failed due to New Physical Device" },
+ { 0x000B, "P Rebuild Failed due to Logical Drive Failure" },
+ { 0x000C, "S Offline" },
+ { 0x000D, "P Found" },
+ { 0x000E, "P Removed" },
+ { 0x000F, "P Unconfigured" },
+ { 0x0010, "P Expand Capacity Started" },
+ { 0x0011, "P Expand Capacity Completed" },
+ { 0x0012, "P Expand Capacity Failed" },
+ { 0x0013, "P Command Timed Out" },
+ { 0x0014, "P Command Aborted" },
+ { 0x0015, "P Command Retried" },
+ { 0x0016, "P Parity Error" },
+ { 0x0017, "P Soft Error" },
+ { 0x0018, "P Miscellaneous Error" },
+ { 0x0019, "P Reset" },
+ { 0x001A, "P Active Spare Found" },
+ { 0x001B, "P Warm Spare Found" },
+ { 0x001C, "S Sense Data Received" },
+ { 0x001D, "P Initialization Started" },
+ { 0x001E, "P Initialization Completed" },
+ { 0x001F, "P Initialization Failed" },
+ { 0x0020, "P Initialization Cancelled" },
+ { 0x0021, "P Failed because Write Recovery Failed" },
+ { 0x0022, "P Failed because SCSI Bus Reset Failed" },
+ { 0x0023, "P Failed because of Double Check Condition" },
+ { 0x0024, "P Failed because Device Cannot Be Accessed" },
+ { 0x0025, "P Failed because of Gross Error on SCSI Processor" },
+ { 0x0026, "P Failed because of Bad Tag from Device" },
+ { 0x0027, "P Failed because of Command Timeout" },
+ { 0x0028, "P Failed because of System Reset" },
+ { 0x0029, "P Failed because of Busy Status or Parity Error" },
+ { 0x002A, "P Failed because Host Set Device to Failed State" },
+ { 0x002B, "P Failed because of Selection Timeout" },
+ { 0x002C, "P Failed because of SCSI Bus Phase Error" },
+ { 0x002D, "P Failed because Device Returned Unknown Status" },
+ { 0x002E, "P Failed because Device Not Ready" },
+ { 0x002F, "P Failed because Device Not Found at Startup" },
+ { 0x0030, "P Failed because COD Write Operation Failed" },
+ { 0x0031, "P Failed because BDT Write Operation Failed" },
+ { 0x0039, "P Missing at Startup" },
+ { 0x003A, "P Start Rebuild Failed due to Physical Drive Too Small" },
+ { 0x003C, "P Temporarily Offline Device Automatically Made Online" },
+ { 0x003D, "P Standby Rebuild Started" },
+ /* Logical Device Events (0x0080 - 0x00FF) */
+ { 0x0080, "M Consistency Check Started" },
+ { 0x0081, "M Consistency Check Completed" },
+ { 0x0082, "M Consistency Check Cancelled" },
+ { 0x0083, "M Consistency Check Completed With Errors" },
+ { 0x0084, "M Consistency Check Failed due to Logical Drive Failure" },
+ { 0x0085, "M Consistency Check Failed due to Physical Device Failure" },
+ { 0x0086, "L Offline" },
+ { 0x0087, "L Critical" },
+ { 0x0088, "L Online" },
+ { 0x0089, "M Automatic Rebuild Started" },
+ { 0x008A, "M Manual Rebuild Started" },
+ { 0x008B, "M Rebuild Completed" },
+ { 0x008C, "M Rebuild Cancelled" },
+ { 0x008D, "M Rebuild Failed for Unknown Reasons" },
+ { 0x008E, "M Rebuild Failed due to New Physical Device" },
+ { 0x008F, "M Rebuild Failed due to Logical Drive Failure" },
+ { 0x0090, "M Initialization Started" },
+ { 0x0091, "M Initialization Completed" },
+ { 0x0092, "M Initialization Cancelled" },
+ { 0x0093, "M Initialization Failed" },
+ { 0x0094, "L Found" },
+ { 0x0095, "L Deleted" },
+ { 0x0096, "M Expand Capacity Started" },
+ { 0x0097, "M Expand Capacity Completed" },
+ { 0x0098, "M Expand Capacity Failed" },
+ { 0x0099, "L Bad Block Found" },
+ { 0x009A, "L Size Changed" },
+ { 0x009B, "L Type Changed" },
+ { 0x009C, "L Bad Data Block Found" },
+ { 0x009E, "L Read of Data Block in BDT" },
+ { 0x009F, "L Write Back Data for Disk Block Lost" },
+ { 0x00A0, "L Temporarily Offline RAID-5/3 Drive Made Online" },
+ { 0x00A1, "L Temporarily Offline RAID-6/1/0/7 Drive Made Online" },
+ { 0x00A2, "L Standby Rebuild Started" },
+ /* Fault Management Events (0x0100 - 0x017F) */
+ { 0x0140, "E Fan %d Failed" },
+ { 0x0141, "E Fan %d OK" },
+ { 0x0142, "E Fan %d Not Present" },
+ { 0x0143, "E Power Supply %d Failed" },
+ { 0x0144, "E Power Supply %d OK" },
+ { 0x0145, "E Power Supply %d Not Present" },
+ { 0x0146, "E Temperature Sensor %d Temperature Exceeds Safe Limit" },
+ { 0x0147, "E Temperature Sensor %d Temperature Exceeds Working Limit" },
+ { 0x0148, "E Temperature Sensor %d Temperature Normal" },
+ { 0x0149, "E Temperature Sensor %d Not Present" },
+ { 0x014A, "E Enclosure Management Unit %d Access Critical" },
+ { 0x014B, "E Enclosure Management Unit %d Access OK" },
+ { 0x014C, "E Enclosure Management Unit %d Access Offline" },
+ /* Controller Events (0x0180 - 0x01FF) */
+ { 0x0181, "C Cache Write Back Error" },
+ { 0x0188, "C Battery Backup Unit Found" },
+ { 0x0189, "C Battery Backup Unit Charge Level Low" },
+ { 0x018A, "C Battery Backup Unit Charge Level OK" },
+ { 0x0193, "C Installation Aborted" },
+ { 0x0195, "C Battery Backup Unit Physically Removed" },
+ { 0x0196, "C Memory Error During Warm Boot" },
+ { 0x019E, "C Memory Soft ECC Error Corrected" },
+ { 0x019F, "C Memory Hard ECC Error Corrected" },
+ { 0x01A2, "C Battery Backup Unit Failed" },
+ { 0x01AB, "C Mirror Race Recovery Failed" },
+ { 0x01AC, "C Mirror Race on Critical Drive" },
+ /* Controller Internal Processor Events */
+ { 0x0380, "C Internal Controller Hung" },
+ { 0x0381, "C Internal Controller Firmware Breakpoint" },
+ { 0x0390, "C Internal Controller i960 Processor Specific Error" },
+ { 0x03A0, "C Internal Controller StrongARM Processor Specific Error" },
+ { 0, "" }
+};
+
+static void myrs_log_event(struct myrs_hba *cs, struct myrs_event *ev)
+{
+ unsigned char msg_buf[MYRS_LINE_BUFFER_SIZE];
+ int ev_idx = 0, ev_code;
+ unsigned char ev_type, *ev_msg;
+ struct Scsi_Host *shost = cs->host;
+ struct scsi_device *sdev;
+ struct scsi_sense_hdr sshdr;
+ unsigned char sense_info[4];
+ unsigned char cmd_specific[4];
+
+ if (ev->ev_code == 0x1C) {
+ if (!scsi_normalize_sense(ev->sense_data, 40, &sshdr)) {
+ memset(&sshdr, 0x0, sizeof(sshdr));
+ memset(sense_info, 0x0, sizeof(sense_info));
+ memset(cmd_specific, 0x0, sizeof(cmd_specific));
+ } else {
+ memcpy(sense_info, &ev->sense_data[3], 4);
+ memcpy(cmd_specific, &ev->sense_data[7], 4);
+ }
+ }
+ if (sshdr.sense_key == VENDOR_SPECIFIC &&
+ (sshdr.asc == 0x80 || sshdr.asc == 0x81))
+ ev->ev_code = ((sshdr.asc - 0x80) << 8 | sshdr.ascq);
+ while (true) {
+ ev_code = myrs_ev_list[ev_idx].ev_code;
+ if (ev_code == ev->ev_code || ev_code == 0)
+ break;
+ ev_idx++;
+ }
+ ev_type = myrs_ev_list[ev_idx].ev_msg[0];
+ ev_msg = &myrs_ev_list[ev_idx].ev_msg[2];
+ if (ev_code == 0) {
+ shost_printk(KERN_WARNING, shost,
+ "Unknown Controller Event Code %04X\n",
+ ev->ev_code);
+ return;
+ }
+ switch (ev_type) {
+ case 'P':
+ sdev = scsi_device_lookup(shost, ev->channel,
+ ev->target, 0);
+ sdev_printk(KERN_INFO, sdev, "event %d: Physical Device %s\n",
+ ev->ev_seq, ev_msg);
+ if (sdev && sdev->hostdata &&
+ sdev->channel < cs->ctlr_info->physchan_present) {
+ struct myrs_pdev_info *pdev_info = sdev->hostdata;
+
+ switch (ev->ev_code) {
+ case 0x0001:
+ case 0x0007:
+ pdev_info->dev_state = MYRS_DEVICE_ONLINE;
+ break;
+ case 0x0002:
+ pdev_info->dev_state = MYRS_DEVICE_STANDBY;
+ break;
+ case 0x000C:
+ pdev_info->dev_state = MYRS_DEVICE_OFFLINE;
+ break;
+ case 0x000E:
+ pdev_info->dev_state = MYRS_DEVICE_MISSING;
+ break;
+ case 0x000F:
+ pdev_info->dev_state = MYRS_DEVICE_UNCONFIGURED;
+ break;
+ }
+ }
+ break;
+ case 'L':
+ shost_printk(KERN_INFO, shost,
+ "event %d: Logical Drive %d %s\n",
+ ev->ev_seq, ev->lun, ev_msg);
+ cs->needs_update = true;
+ break;
+ case 'M':
+ shost_printk(KERN_INFO, shost,
+ "event %d: Logical Drive %d %s\n",
+ ev->ev_seq, ev->lun, ev_msg);
+ cs->needs_update = true;
+ break;
+ case 'S':
+ if (sshdr.sense_key == NO_SENSE ||
+ (sshdr.sense_key == NOT_READY &&
+ sshdr.asc == 0x04 && (sshdr.ascq == 0x01 ||
+ sshdr.ascq == 0x02)))
+ break;
+ shost_printk(KERN_INFO, shost,
+ "event %d: Physical Device %d:%d %s\n",
+ ev->ev_seq, ev->channel, ev->target, ev_msg);
+ shost_printk(KERN_INFO, shost,
+ "Physical Device %d:%d Sense Key = %X, ASC = %02X, ASCQ = %02X\n",
+ ev->channel, ev->target,
+ sshdr.sense_key, sshdr.asc, sshdr.ascq);
+ shost_printk(KERN_INFO, shost,
+ "Physical Device %d:%d Sense Information = %02X%02X%02X%02X %02X%02X%02X%02X\n",
+ ev->channel, ev->target,
+ sense_info[0], sense_info[1],
+ sense_info[2], sense_info[3],
+ cmd_specific[0], cmd_specific[1],
+ cmd_specific[2], cmd_specific[3]);
+ break;
+ case 'E':
+ if (cs->disable_enc_msg)
+ break;
+ sprintf(msg_buf, ev_msg, ev->lun);
+ shost_printk(KERN_INFO, shost, "event %d: Enclosure %d %s\n",
+ ev->ev_seq, ev->target, msg_buf);
+ break;
+ case 'C':
+ shost_printk(KERN_INFO, shost, "event %d: Controller %s\n",
+ ev->ev_seq, ev_msg);
+ break;
+ default:
+ shost_printk(KERN_INFO, shost,
+ "event %d: Unknown Event Code %04X\n",
+ ev->ev_seq, ev->ev_code);
+ break;
+ }
+}
+
+/*
+ * SCSI sysfs interface functions
+ */
+static ssize_t raid_state_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct myrs_hba *cs = shost_priv(sdev->host);
+ int ret;
+
+ if (!sdev->hostdata)
+ return snprintf(buf, 16, "Unknown\n");
+
+ if (sdev->channel >= cs->ctlr_info->physchan_present) {
+ struct myrs_ldev_info *ldev_info = sdev->hostdata;
+ const char *name;
+
+ name = myrs_devstate_name(ldev_info->dev_state);
+ if (name)
+ ret = snprintf(buf, 32, "%s\n", name);
+ else
+ ret = snprintf(buf, 32, "Invalid (%02X)\n",
+ ldev_info->dev_state);
+ } else {
+ struct myrs_pdev_info *pdev_info;
+ const char *name;
+
+ pdev_info = sdev->hostdata;
+ name = myrs_devstate_name(pdev_info->dev_state);
+ if (name)
+ ret = snprintf(buf, 32, "%s\n", name);
+ else
+ ret = snprintf(buf, 32, "Invalid (%02X)\n",
+ pdev_info->dev_state);
+ }
+ return ret;
+}
+
+static ssize_t raid_state_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct myrs_hba *cs = shost_priv(sdev->host);
+ struct myrs_cmdblk *cmd_blk;
+ union myrs_cmd_mbox *mbox;
+ enum myrs_devstate new_state;
+ unsigned short ldev_num;
+ unsigned char status;
+
+ if (!strncmp(buf, "offline", 7) ||
+ !strncmp(buf, "kill", 4))
+ new_state = MYRS_DEVICE_OFFLINE;
+ else if (!strncmp(buf, "online", 6))
+ new_state = MYRS_DEVICE_ONLINE;
+ else if (!strncmp(buf, "standby", 7))
+ new_state = MYRS_DEVICE_STANDBY;
+ else
+ return -EINVAL;
+
+ if (sdev->channel < cs->ctlr_info->physchan_present) {
+ struct myrs_pdev_info *pdev_info = sdev->hostdata;
+ struct myrs_devmap *pdev_devmap =
+ (struct myrs_devmap *)&pdev_info->rsvd13;
+
+ if (pdev_info->dev_state == new_state) {
+ sdev_printk(KERN_INFO, sdev,
+ "Device already in %s\n",
+ myrs_devstate_name(new_state));
+ return count;
+ }
+ status = myrs_translate_pdev(cs, sdev->channel, sdev->id,
+ sdev->lun, pdev_devmap);
+ if (status != MYRS_STATUS_SUCCESS)
+ return -ENXIO;
+ ldev_num = pdev_devmap->ldev_num;
+ } else {
+ struct myrs_ldev_info *ldev_info = sdev->hostdata;
+
+ if (ldev_info->dev_state == new_state) {
+ sdev_printk(KERN_INFO, sdev,
+ "Device already in %s\n",
+ myrs_devstate_name(new_state));
+ return count;
+ }
+ ldev_num = ldev_info->ldev_num;
+ }
+ mutex_lock(&cs->dcmd_mutex);
+ cmd_blk = &cs->dcmd_blk;
+ myrs_reset_cmd(cmd_blk);
+ mbox = &cmd_blk->mbox;
+ mbox->common.opcode = MYRS_CMD_OP_IOCTL;
+ mbox->common.id = MYRS_DCMD_TAG;
+ mbox->common.control.dma_ctrl_to_host = true;
+ mbox->common.control.no_autosense = true;
+ mbox->set_devstate.ioctl_opcode = MYRS_IOCTL_SET_DEVICE_STATE;
+ mbox->set_devstate.state = new_state;
+ mbox->set_devstate.ldev.ldev_num = ldev_num;
+ myrs_exec_cmd(cs, cmd_blk);
+ status = cmd_blk->status;
+ mutex_unlock(&cs->dcmd_mutex);
+ if (status == MYRS_STATUS_SUCCESS) {
+ if (sdev->channel < cs->ctlr_info->physchan_present) {
+ struct myrs_pdev_info *pdev_info = sdev->hostdata;
+
+ pdev_info->dev_state = new_state;
+ } else {
+ struct myrs_ldev_info *ldev_info = sdev->hostdata;
+
+ ldev_info->dev_state = new_state;
+ }
+ sdev_printk(KERN_INFO, sdev,
+ "Set device state to %s\n",
+ myrs_devstate_name(new_state));
+ return count;
+ }
+ sdev_printk(KERN_INFO, sdev,
+ "Failed to set device state to %s, status 0x%02x\n",
+ myrs_devstate_name(new_state), status);
+ return -EINVAL;
+}
+static DEVICE_ATTR_RW(raid_state);
+
+static ssize_t raid_level_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct myrs_hba *cs = shost_priv(sdev->host);
+ const char *name = NULL;
+
+ if (!sdev->hostdata)
+ return snprintf(buf, 16, "Unknown\n");
+
+ if (sdev->channel >= cs->ctlr_info->physchan_present) {
+ struct myrs_ldev_info *ldev_info;
+
+ ldev_info = sdev->hostdata;
+ name = myrs_raid_level_name(ldev_info->raid_level);
+ if (!name)
+ return snprintf(buf, 32, "Invalid (%02X)\n",
+ ldev_info->dev_state);
+
+ } else
+ name = myrs_raid_level_name(MYRS_RAID_PHYSICAL);
+
+ return snprintf(buf, 32, "%s\n", name);
+}
+static DEVICE_ATTR_RO(raid_level);
+
+static ssize_t rebuild_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct myrs_hba *cs = shost_priv(sdev->host);
+ struct myrs_ldev_info *ldev_info;
+ unsigned short ldev_num;
+ unsigned char status;
+
+ if (sdev->channel < cs->ctlr_info->physchan_present)
+ return snprintf(buf, 32, "physical device - not rebuilding\n");
+
+ ldev_info = sdev->hostdata;
+ ldev_num = ldev_info->ldev_num;
+ status = myrs_get_ldev_info(cs, ldev_num, ldev_info);
+ if (status != MYRS_STATUS_SUCCESS) {
+ sdev_printk(KERN_INFO, sdev,
+ "Failed to get device information, status 0x%02x\n",
+ status);
+ return -EIO;
+ }
+ if (ldev_info->rbld_active) {
+ return snprintf(buf, 32, "rebuilding block %zu of %zu\n",
+ (size_t)ldev_info->rbld_lba,
+ (size_t)ldev_info->cfg_devsize);
+ } else
+ return snprintf(buf, 32, "not rebuilding\n");
+}
+
+static ssize_t rebuild_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct myrs_hba *cs = shost_priv(sdev->host);
+ struct myrs_ldev_info *ldev_info;
+ struct myrs_cmdblk *cmd_blk;
+ union myrs_cmd_mbox *mbox;
+ unsigned short ldev_num;
+ unsigned char status;
+ int rebuild, ret;
+
+ if (sdev->channel < cs->ctlr_info->physchan_present)
+ return -EINVAL;
+
+ ldev_info = sdev->hostdata;
+ if (!ldev_info)
+ return -ENXIO;
+ ldev_num = ldev_info->ldev_num;
+
+ ret = kstrtoint(buf, 0, &rebuild);
+ if (ret)
+ return ret;
+
+ status = myrs_get_ldev_info(cs, ldev_num, ldev_info);
+ if (status != MYRS_STATUS_SUCCESS) {
+ sdev_printk(KERN_INFO, sdev,
+ "Failed to get device information, status 0x%02x\n",
+ status);
+ return -EIO;
+ }
+
+ if (rebuild && ldev_info->rbld_active) {
+ sdev_printk(KERN_INFO, sdev,
+ "Rebuild Not Initiated; already in progress\n");
+ return -EALREADY;
+ }
+ if (!rebuild && !ldev_info->rbld_active) {
+ sdev_printk(KERN_INFO, sdev,
+ "Rebuild Not Cancelled; no rebuild in progress\n");
+ return count;
+ }
+
+ mutex_lock(&cs->dcmd_mutex);
+ cmd_blk = &cs->dcmd_blk;
+ myrs_reset_cmd(cmd_blk);
+ mbox = &cmd_blk->mbox;
+ mbox->common.opcode = MYRS_CMD_OP_IOCTL;
+ mbox->common.id = MYRS_DCMD_TAG;
+ mbox->common.control.dma_ctrl_to_host = true;
+ mbox->common.control.no_autosense = true;
+ if (rebuild) {
+ mbox->ldev_info.ldev.ldev_num = ldev_num;
+ mbox->ldev_info.ioctl_opcode = MYRS_IOCTL_RBLD_DEVICE_START;
+ } else {
+ mbox->ldev_info.ldev.ldev_num = ldev_num;
+ mbox->ldev_info.ioctl_opcode = MYRS_IOCTL_RBLD_DEVICE_STOP;
+ }
+ myrs_exec_cmd(cs, cmd_blk);
+ status = cmd_blk->status;
+ mutex_unlock(&cs->dcmd_mutex);
+ if (status) {
+ sdev_printk(KERN_INFO, sdev,
+ "Rebuild Not %s, status 0x%02x\n",
+ rebuild ? "Initiated" : "Cancelled", status);
+ ret = -EIO;
+ } else {
+ sdev_printk(KERN_INFO, sdev, "Rebuild %s\n",
+ rebuild ? "Initiated" : "Cancelled");
+ ret = count;
+ }
+
+ return ret;
+}
+static DEVICE_ATTR_RW(rebuild);
+
+static ssize_t consistency_check_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct myrs_hba *cs = shost_priv(sdev->host);
+ struct myrs_ldev_info *ldev_info;
+ unsigned short ldev_num;
+ unsigned char status;
+
+ if (sdev->channel < cs->ctlr_info->physchan_present)
+ return snprintf(buf, 32, "physical device - not checking\n");
+
+ ldev_info = sdev->hostdata;
+ if (!ldev_info)
+ return -ENXIO;
+ ldev_num = ldev_info->ldev_num;
+ status = myrs_get_ldev_info(cs, ldev_num, ldev_info);
+ if (ldev_info->cc_active)
+ return snprintf(buf, 32, "checking block %zu of %zu\n",
+ (size_t)ldev_info->cc_lba,
+ (size_t)ldev_info->cfg_devsize);
+ else
+ return snprintf(buf, 32, "not checking\n");
+}
+
+static ssize_t consistency_check_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct myrs_hba *cs = shost_priv(sdev->host);
+ struct myrs_ldev_info *ldev_info;
+ struct myrs_cmdblk *cmd_blk;
+ union myrs_cmd_mbox *mbox;
+ unsigned short ldev_num;
+ unsigned char status;
+ int check, ret;
+
+ if (sdev->channel < cs->ctlr_info->physchan_present)
+ return -EINVAL;
+
+ ldev_info = sdev->hostdata;
+ if (!ldev_info)
+ return -ENXIO;
+ ldev_num = ldev_info->ldev_num;
+
+ ret = kstrtoint(buf, 0, &check);
+ if (ret)
+ return ret;
+
+ status = myrs_get_ldev_info(cs, ldev_num, ldev_info);
+ if (status != MYRS_STATUS_SUCCESS) {
+ sdev_printk(KERN_INFO, sdev,
+ "Failed to get device information, status 0x%02x\n",
+ status);
+ return -EIO;
+ }
+ if (check && ldev_info->cc_active) {
+ sdev_printk(KERN_INFO, sdev,
+ "Consistency Check Not Initiated; "
+ "already in progress\n");
+ return -EALREADY;
+ }
+ if (!check && !ldev_info->cc_active) {
+ sdev_printk(KERN_INFO, sdev,
+ "Consistency Check Not Cancelled; "
+ "check not in progress\n");
+ return count;
+ }
+
+ mutex_lock(&cs->dcmd_mutex);
+ cmd_blk = &cs->dcmd_blk;
+ myrs_reset_cmd(cmd_blk);
+ mbox = &cmd_blk->mbox;
+ mbox->common.opcode = MYRS_CMD_OP_IOCTL;
+ mbox->common.id = MYRS_DCMD_TAG;
+ mbox->common.control.dma_ctrl_to_host = true;
+ mbox->common.control.no_autosense = true;
+ if (check) {
+ mbox->cc.ldev.ldev_num = ldev_num;
+ mbox->cc.ioctl_opcode = MYRS_IOCTL_CC_START;
+ mbox->cc.restore_consistency = true;
+ mbox->cc.initialized_area_only = false;
+ } else {
+ mbox->cc.ldev.ldev_num = ldev_num;
+ mbox->cc.ioctl_opcode = MYRS_IOCTL_CC_STOP;
+ }
+ myrs_exec_cmd(cs, cmd_blk);
+ status = cmd_blk->status;
+ mutex_unlock(&cs->dcmd_mutex);
+ if (status != MYRS_STATUS_SUCCESS) {
+ sdev_printk(KERN_INFO, sdev,
+ "Consistency Check Not %s, status 0x%02x\n",
+ check ? "Initiated" : "Cancelled", status);
+ ret = -EIO;
+ } else {
+ sdev_printk(KERN_INFO, sdev, "Consistency Check %s\n",
+ check ? "Initiated" : "Cancelled");
+ ret = count;
+ }
+
+ return ret;
+}
+static DEVICE_ATTR_RW(consistency_check);
+
+static struct device_attribute *myrs_sdev_attrs[] = {
+ &dev_attr_consistency_check,
+ &dev_attr_rebuild,
+ &dev_attr_raid_state,
+ &dev_attr_raid_level,
+ NULL,
+};
+
+static ssize_t serial_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct myrs_hba *cs = shost_priv(shost);
+ char serial[17];
+
+ memcpy(serial, cs->ctlr_info->serial_number, 16);
+ serial[16] = '\0';
+ return snprintf(buf, 16, "%s\n", serial);
+}
+static DEVICE_ATTR_RO(serial);
+
+static ssize_t ctlr_num_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct myrs_hba *cs = shost_priv(shost);
+
+ return snprintf(buf, 20, "%d\n", cs->host->host_no);
+}
+static DEVICE_ATTR_RO(ctlr_num);
+
+static struct myrs_cpu_type_tbl {
+ enum myrs_cpu_type type;
+ char *name;
+} myrs_cpu_type_names[] = {
+ { MYRS_CPUTYPE_i960CA, "i960CA" },
+ { MYRS_CPUTYPE_i960RD, "i960RD" },
+ { MYRS_CPUTYPE_i960RN, "i960RN" },
+ { MYRS_CPUTYPE_i960RP, "i960RP" },
+ { MYRS_CPUTYPE_NorthBay, "NorthBay" },
+ { MYRS_CPUTYPE_StrongArm, "StrongARM" },
+ { MYRS_CPUTYPE_i960RM, "i960RM" },
+};
+
+static ssize_t processor_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct myrs_hba *cs = shost_priv(shost);
+ struct myrs_cpu_type_tbl *tbl;
+ const char *first_processor = NULL;
+ const char *second_processor = NULL;
+ struct myrs_ctlr_info *info = cs->ctlr_info;
+ ssize_t ret;
+ int i;
+
+ if (info->cpu[0].cpu_count) {
+ tbl = myrs_cpu_type_names;
+ for (i = 0; i < ARRAY_SIZE(myrs_cpu_type_names); i++) {
+ if (tbl[i].type == info->cpu[0].cpu_type) {
+ first_processor = tbl[i].name;
+ break;
+ }
+ }
+ }
+ if (info->cpu[1].cpu_count) {
+ tbl = myrs_cpu_type_names;
+ for (i = 0; i < ARRAY_SIZE(myrs_cpu_type_names); i++) {
+ if (tbl[i].type == info->cpu[1].cpu_type) {
+ second_processor = tbl[i].name;
+ break;
+ }
+ }
+ }
+ if (first_processor && second_processor)
+ ret = snprintf(buf, 64, "1: %s (%s, %d cpus)\n"
+ "2: %s (%s, %d cpus)\n",
+ info->cpu[0].cpu_name,
+ first_processor, info->cpu[0].cpu_count,
+ info->cpu[1].cpu_name,
+ second_processor, info->cpu[1].cpu_count);
+ else if (first_processor && !second_processor)
+ ret = snprintf(buf, 64, "1: %s (%s, %d cpus)\n2: absent\n",
+ info->cpu[0].cpu_name,
+ first_processor, info->cpu[0].cpu_count);
+ else if (!first_processor && second_processor)
+ ret = snprintf(buf, 64, "1: absent\n2: %s (%s, %d cpus)\n",
+ info->cpu[1].cpu_name,
+ second_processor, info->cpu[1].cpu_count);
+ else
+ ret = snprintf(buf, 64, "1: absent\n2: absent\n");
+
+ return ret;
+}
+static DEVICE_ATTR_RO(processor);
+
+static ssize_t model_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct myrs_hba *cs = shost_priv(shost);
+
+ return snprintf(buf, 28, "%s\n", cs->model_name);
+}
+static DEVICE_ATTR_RO(model);
+
+static ssize_t ctlr_type_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct myrs_hba *cs = shost_priv(shost);
+
+ return snprintf(buf, 4, "%d\n", cs->ctlr_info->ctlr_type);
+}
+static DEVICE_ATTR_RO(ctlr_type);
+
+static ssize_t cache_size_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct myrs_hba *cs = shost_priv(shost);
+
+ return snprintf(buf, 8, "%d MB\n", cs->ctlr_info->cache_size_mb);
+}
+static DEVICE_ATTR_RO(cache_size);
+
+static ssize_t firmware_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct myrs_hba *cs = shost_priv(shost);
+
+ return snprintf(buf, 16, "%d.%02d-%02d\n",
+ cs->ctlr_info->fw_major_version,
+ cs->ctlr_info->fw_minor_version,
+ cs->ctlr_info->fw_turn_number);
+}
+static DEVICE_ATTR_RO(firmware);
+
+static ssize_t discovery_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct myrs_hba *cs = shost_priv(shost);
+ struct myrs_cmdblk *cmd_blk;
+ union myrs_cmd_mbox *mbox;
+ unsigned char status;
+
+ mutex_lock(&cs->dcmd_mutex);
+ cmd_blk = &cs->dcmd_blk;
+ myrs_reset_cmd(cmd_blk);
+ mbox = &cmd_blk->mbox;
+ mbox->common.opcode = MYRS_CMD_OP_IOCTL;
+ mbox->common.id = MYRS_DCMD_TAG;
+ mbox->common.control.dma_ctrl_to_host = true;
+ mbox->common.control.no_autosense = true;
+ mbox->common.ioctl_opcode = MYRS_IOCTL_START_DISCOVERY;
+ myrs_exec_cmd(cs, cmd_blk);
+ status = cmd_blk->status;
+ mutex_unlock(&cs->dcmd_mutex);
+ if (status != MYRS_STATUS_SUCCESS) {
+ shost_printk(KERN_INFO, shost,
+ "Discovery Not Initiated, status %02X\n",
+ status);
+ return -EINVAL;
+ }
+ shost_printk(KERN_INFO, shost, "Discovery Initiated\n");
+ cs->next_evseq = 0;
+ cs->needs_update = true;
+ queue_delayed_work(cs->work_q, &cs->monitor_work, 1);
+ flush_delayed_work(&cs->monitor_work);
+ shost_printk(KERN_INFO, shost, "Discovery Completed\n");
+
+ return count;
+}
+static DEVICE_ATTR_WO(discovery);
+
+static ssize_t flush_cache_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct myrs_hba *cs = shost_priv(shost);
+ unsigned char status;
+
+ status = myrs_dev_op(cs, MYRS_IOCTL_FLUSH_DEVICE_DATA,
+ MYRS_RAID_CONTROLLER);
+ if (status == MYRS_STATUS_SUCCESS) {
+ shost_printk(KERN_INFO, shost, "Cache Flush Completed\n");
+ return count;
+ }
+ shost_printk(KERN_INFO, shost,
+ "Cache Flush failed, status 0x%02x\n", status);
+ return -EIO;
+}
+static DEVICE_ATTR_WO(flush_cache);
+
+static ssize_t disable_enclosure_messages_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct myrs_hba *cs = shost_priv(shost);
+
+ return snprintf(buf, 3, "%d\n", cs->disable_enc_msg);
+}
+
+static ssize_t disable_enclosure_messages_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct myrs_hba *cs = shost_priv(sdev->host);
+ int value, ret;
+
+ ret = kstrtoint(buf, 0, &value);
+ if (ret)
+ return ret;
+
+ if (value > 2)
+ return -EINVAL;
+
+ cs->disable_enc_msg = value;
+ return count;
+}
+static DEVICE_ATTR_RW(disable_enclosure_messages);
+
+static struct device_attribute *myrs_shost_attrs[] = {
+ &dev_attr_serial,
+ &dev_attr_ctlr_num,
+ &dev_attr_processor,
+ &dev_attr_model,
+ &dev_attr_ctlr_type,
+ &dev_attr_cache_size,
+ &dev_attr_firmware,
+ &dev_attr_discovery,
+ &dev_attr_flush_cache,
+ &dev_attr_disable_enclosure_messages,
+ NULL,
+};
+
+/*
+ * SCSI midlayer interface
+ */
+int myrs_host_reset(struct scsi_cmnd *scmd)
+{
+ struct Scsi_Host *shost = scmd->device->host;
+ struct myrs_hba *cs = shost_priv(shost);
+
+ cs->reset(cs->io_base);
+ return SUCCESS;
+}
+
+static void myrs_mode_sense(struct myrs_hba *cs, struct scsi_cmnd *scmd,
+ struct myrs_ldev_info *ldev_info)
+{
+ unsigned char modes[32], *mode_pg;
+ bool dbd;
+ size_t mode_len;
+
+ dbd = (scmd->cmnd[1] & 0x08) == 0x08;
+ if (dbd) {
+ mode_len = 24;
+ mode_pg = &modes[4];
+ } else {
+ mode_len = 32;
+ mode_pg = &modes[12];
+ }
+ memset(modes, 0, sizeof(modes));
+ modes[0] = mode_len - 1;
+ modes[2] = 0x10; /* Enable FUA */
+ if (ldev_info->ldev_control.wce == MYRS_LOGICALDEVICE_RO)
+ modes[2] |= 0x80;
+ if (!dbd) {
+ unsigned char *block_desc = &modes[4];
+
+ modes[3] = 8;
+ put_unaligned_be32(ldev_info->cfg_devsize, &block_desc[0]);
+ put_unaligned_be32(ldev_info->devsize_bytes, &block_desc[5]);
+ }
+ mode_pg[0] = 0x08;
+ mode_pg[1] = 0x12;
+ if (ldev_info->ldev_control.rce == MYRS_READCACHE_DISABLED)
+ mode_pg[2] |= 0x01;
+ if (ldev_info->ldev_control.wce == MYRS_WRITECACHE_ENABLED ||
+ ldev_info->ldev_control.wce == MYRS_INTELLIGENT_WRITECACHE_ENABLED)
+ mode_pg[2] |= 0x04;
+ if (ldev_info->cacheline_size) {
+ mode_pg[2] |= 0x08;
+ put_unaligned_be16(1 << ldev_info->cacheline_size,
+ &mode_pg[14]);
+ }
+
+ scsi_sg_copy_from_buffer(scmd, modes, mode_len);
+}
+
+static int myrs_queuecommand(struct Scsi_Host *shost,
+ struct scsi_cmnd *scmd)
+{
+ struct myrs_hba *cs = shost_priv(shost);
+ struct myrs_cmdblk *cmd_blk = scsi_cmd_priv(scmd);
+ union myrs_cmd_mbox *mbox = &cmd_blk->mbox;
+ struct scsi_device *sdev = scmd->device;
+ union myrs_sgl *hw_sge;
+ dma_addr_t sense_addr;
+ struct scatterlist *sgl;
+ unsigned long flags, timeout;
+ int nsge;
+
+ if (!scmd->device->hostdata) {
+ scmd->result = (DID_NO_CONNECT << 16);
+ scmd->scsi_done(scmd);
+ return 0;
+ }
+
+ 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;
+ scmd->scsi_done(scmd);
+ return 0;
+ case MODE_SENSE:
+ if (scmd->device->channel >= cs->ctlr_info->physchan_present) {
+ struct myrs_ldev_info *ldev_info = sdev->hostdata;
+
+ 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;
+ } else {
+ myrs_mode_sense(cs, scmd, ldev_info);
+ scmd->result = (DID_OK << 16);
+ }
+ scmd->scsi_done(scmd);
+ return 0;
+ }
+ break;
+ }
+
+ myrs_reset_cmd(cmd_blk);
+ cmd_blk->sense = dma_pool_alloc(cs->sense_pool, GFP_ATOMIC,
+ &sense_addr);
+ if (!cmd_blk->sense)
+ return SCSI_MLQUEUE_HOST_BUSY;
+ cmd_blk->sense_addr = sense_addr;
+
+ timeout = scmd->request->timeout;
+ if (scmd->cmd_len <= 10) {
+ if (scmd->device->channel >= cs->ctlr_info->physchan_present) {
+ struct myrs_ldev_info *ldev_info = sdev->hostdata;
+
+ mbox->SCSI_10.opcode = MYRS_CMD_OP_SCSI_10;
+ mbox->SCSI_10.pdev.lun = ldev_info->lun;
+ mbox->SCSI_10.pdev.target = ldev_info->target;
+ mbox->SCSI_10.pdev.channel = ldev_info->channel;
+ mbox->SCSI_10.pdev.ctlr = 0;
+ } else {
+ mbox->SCSI_10.opcode = MYRS_CMD_OP_SCSI_10_PASSTHRU;
+ mbox->SCSI_10.pdev.lun = sdev->lun;
+ mbox->SCSI_10.pdev.target = sdev->id;
+ mbox->SCSI_10.pdev.channel = sdev->channel;
+ }
+ mbox->SCSI_10.id = scmd->request->tag + 3;
+ mbox->SCSI_10.control.dma_ctrl_to_host =
+ (scmd->sc_data_direction == DMA_FROM_DEVICE);
+ if (scmd->request->cmd_flags & REQ_FUA)
+ mbox->SCSI_10.control.fua = true;
+ mbox->SCSI_10.dma_size = scsi_bufflen(scmd);
+ mbox->SCSI_10.sense_addr = cmd_blk->sense_addr;
+ mbox->SCSI_10.sense_len = MYRS_SENSE_SIZE;
+ mbox->SCSI_10.cdb_len = scmd->cmd_len;
+ if (timeout > 60) {
+ mbox->SCSI_10.tmo.tmo_scale = MYRS_TMO_SCALE_MINUTES;
+ mbox->SCSI_10.tmo.tmo_val = timeout / 60;
+ } else {
+ mbox->SCSI_10.tmo.tmo_scale = MYRS_TMO_SCALE_SECONDS;
+ mbox->SCSI_10.tmo.tmo_val = timeout;
+ }
+ memcpy(&mbox->SCSI_10.cdb, scmd->cmnd, scmd->cmd_len);
+ hw_sge = &mbox->SCSI_10.dma_addr;
+ cmd_blk->dcdb = NULL;
+ } else {
+ dma_addr_t dcdb_dma;
+
+ cmd_blk->dcdb = dma_pool_alloc(cs->dcdb_pool, GFP_ATOMIC,
+ &dcdb_dma);
+ if (!cmd_blk->dcdb) {
+ dma_pool_free(cs->sense_pool, cmd_blk->sense,
+ cmd_blk->sense_addr);
+ cmd_blk->sense = NULL;
+ cmd_blk->sense_addr = 0;
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+ cmd_blk->dcdb_dma = dcdb_dma;
+ if (scmd->device->channel >= cs->ctlr_info->physchan_present) {
+ struct myrs_ldev_info *ldev_info = sdev->hostdata;
+
+ mbox->SCSI_255.opcode = MYRS_CMD_OP_SCSI_256;
+ mbox->SCSI_255.pdev.lun = ldev_info->lun;
+ mbox->SCSI_255.pdev.target = ldev_info->target;
+ mbox->SCSI_255.pdev.channel = ldev_info->channel;
+ mbox->SCSI_255.pdev.ctlr = 0;
+ } else {
+ mbox->SCSI_255.opcode = MYRS_CMD_OP_SCSI_255_PASSTHRU;
+ mbox->SCSI_255.pdev.lun = sdev->lun;
+ mbox->SCSI_255.pdev.target = sdev->id;
+ mbox->SCSI_255.pdev.channel = sdev->channel;
+ }
+ mbox->SCSI_255.id = scmd->request->tag + 3;
+ mbox->SCSI_255.control.dma_ctrl_to_host =
+ (scmd->sc_data_direction == DMA_FROM_DEVICE);
+ if (scmd->request->cmd_flags & REQ_FUA)
+ mbox->SCSI_255.control.fua = true;
+ mbox->SCSI_255.dma_size = scsi_bufflen(scmd);
+ mbox->SCSI_255.sense_addr = cmd_blk->sense_addr;
+ mbox->SCSI_255.sense_len = MYRS_SENSE_SIZE;
+ mbox->SCSI_255.cdb_len = scmd->cmd_len;
+ mbox->SCSI_255.cdb_addr = cmd_blk->dcdb_dma;
+ if (timeout > 60) {
+ mbox->SCSI_255.tmo.tmo_scale = MYRS_TMO_SCALE_MINUTES;
+ mbox->SCSI_255.tmo.tmo_val = timeout / 60;
+ } else {
+ mbox->SCSI_255.tmo.tmo_scale = MYRS_TMO_SCALE_SECONDS;
+ mbox->SCSI_255.tmo.tmo_val = timeout;
+ }
+ memcpy(cmd_blk->dcdb, scmd->cmnd, scmd->cmd_len);
+ hw_sge = &mbox->SCSI_255.dma_addr;
+ }
+ if (scmd->sc_data_direction == DMA_NONE)
+ goto submit;
+ nsge = scsi_dma_map(scmd);
+ if (nsge == 1) {
+ sgl = scsi_sglist(scmd);
+ hw_sge->sge[0].sge_addr = (u64)sg_dma_address(sgl);
+ hw_sge->sge[0].sge_count = (u64)sg_dma_len(sgl);
+ } else {
+ struct myrs_sge *hw_sgl;
+ dma_addr_t hw_sgl_addr;
+ int i;
+
+ if (nsge > 2) {
+ hw_sgl = dma_pool_alloc(cs->sg_pool, GFP_ATOMIC,
+ &hw_sgl_addr);
+ if (WARN_ON(!hw_sgl)) {
+ if (cmd_blk->dcdb) {
+ dma_pool_free(cs->dcdb_pool,
+ cmd_blk->dcdb,
+ cmd_blk->dcdb_dma);
+ cmd_blk->dcdb = NULL;
+ cmd_blk->dcdb_dma = 0;
+ }
+ dma_pool_free(cs->sense_pool,
+ cmd_blk->sense,
+ cmd_blk->sense_addr);
+ cmd_blk->sense = NULL;
+ cmd_blk->sense_addr = 0;
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+ cmd_blk->sgl = hw_sgl;
+ cmd_blk->sgl_addr = hw_sgl_addr;
+ if (scmd->cmd_len <= 10)
+ mbox->SCSI_10.control.add_sge_mem = true;
+ else
+ mbox->SCSI_255.control.add_sge_mem = true;
+ hw_sge->ext.sge0_len = nsge;
+ hw_sge->ext.sge0_addr = cmd_blk->sgl_addr;
+ } else
+ hw_sgl = hw_sge->sge;
+
+ scsi_for_each_sg(scmd, sgl, nsge, i) {
+ if (WARN_ON(!hw_sgl)) {
+ scsi_dma_unmap(scmd);
+ scmd->result = (DID_ERROR << 16);
+ scmd->scsi_done(scmd);
+ return 0;
+ }
+ hw_sgl->sge_addr = (u64)sg_dma_address(sgl);
+ hw_sgl->sge_count = (u64)sg_dma_len(sgl);
+ hw_sgl++;
+ }
+ }
+submit:
+ spin_lock_irqsave(&cs->queue_lock, flags);
+ myrs_qcmd(cs, cmd_blk);
+ spin_unlock_irqrestore(&cs->queue_lock, flags);
+
+ return 0;
+}
+
+static unsigned short myrs_translate_ldev(struct myrs_hba *cs,
+ struct scsi_device *sdev)
+{
+ unsigned short ldev_num;
+ unsigned int chan_offset =
+ sdev->channel - cs->ctlr_info->physchan_present;
+
+ ldev_num = sdev->id + chan_offset * sdev->host->max_id;
+
+ return ldev_num;
+}
+
+static int myrs_slave_alloc(struct scsi_device *sdev)
+{
+ struct myrs_hba *cs = shost_priv(sdev->host);
+ unsigned char status;
+
+ if (sdev->channel > sdev->host->max_channel)
+ return 0;
+
+ if (sdev->channel >= cs->ctlr_info->physchan_present) {
+ struct myrs_ldev_info *ldev_info;
+ unsigned short ldev_num;
+
+ if (sdev->lun > 0)
+ return -ENXIO;
+
+ ldev_num = myrs_translate_ldev(cs, sdev);
+
+ ldev_info = kzalloc(sizeof(*ldev_info), GFP_KERNEL|GFP_DMA);
+ if (!ldev_info)
+ return -ENOMEM;
+
+ status = myrs_get_ldev_info(cs, ldev_num, ldev_info);
+ if (status != MYRS_STATUS_SUCCESS) {
+ sdev->hostdata = NULL;
+ kfree(ldev_info);
+ } else {
+ enum raid_level level;
+
+ dev_dbg(&sdev->sdev_gendev,
+ "Logical device mapping %d:%d:%d -> %d\n",
+ ldev_info->channel, ldev_info->target,
+ ldev_info->lun, ldev_info->ldev_num);
+
+ sdev->hostdata = ldev_info;
+ switch (ldev_info->raid_level) {
+ case MYRS_RAID_LEVEL0:
+ level = RAID_LEVEL_LINEAR;
+ break;
+ case MYRS_RAID_LEVEL1:
+ level = RAID_LEVEL_1;
+ break;
+ case MYRS_RAID_LEVEL3:
+ case MYRS_RAID_LEVEL3F:
+ case MYRS_RAID_LEVEL3L:
+ level = RAID_LEVEL_3;
+ break;
+ case MYRS_RAID_LEVEL5:
+ case MYRS_RAID_LEVEL5L:
+ level = RAID_LEVEL_5;
+ break;
+ case MYRS_RAID_LEVEL6:
+ level = RAID_LEVEL_6;
+ break;
+ case MYRS_RAID_LEVELE:
+ case MYRS_RAID_NEWSPAN:
+ case MYRS_RAID_SPAN:
+ level = RAID_LEVEL_LINEAR;
+ break;
+ case MYRS_RAID_JBOD:
+ level = RAID_LEVEL_JBOD;
+ break;
+ default:
+ level = RAID_LEVEL_UNKNOWN;
+ break;
+ }
+ raid_set_level(myrs_raid_template,
+ &sdev->sdev_gendev, level);
+ if (ldev_info->dev_state != MYRS_DEVICE_ONLINE) {
+ const char *name;
+
+ name = myrs_devstate_name(ldev_info->dev_state);
+ sdev_printk(KERN_DEBUG, sdev,
+ "logical device in state %s\n",
+ name ? name : "Invalid");
+ }
+ }
+ } else {
+ struct myrs_pdev_info *pdev_info;
+
+ pdev_info = kzalloc(sizeof(*pdev_info), GFP_KERNEL|GFP_DMA);
+ if (!pdev_info)
+ return -ENOMEM;
+
+ status = myrs_get_pdev_info(cs, sdev->channel,
+ sdev->id, sdev->lun,
+ pdev_info);
+ if (status != MYRS_STATUS_SUCCESS) {
+ sdev->hostdata = NULL;
+ kfree(pdev_info);
+ return -ENXIO;
+ }
+ sdev->hostdata = pdev_info;
+ }
+ return 0;
+}
+
+static int myrs_slave_configure(struct scsi_device *sdev)
+{
+ struct myrs_hba *cs = shost_priv(sdev->host);
+ struct myrs_ldev_info *ldev_info;
+
+ if (sdev->channel > sdev->host->max_channel)
+ return -ENXIO;
+
+ if (sdev->channel < cs->ctlr_info->physchan_present) {
+ /* Skip HBA device */
+ if (sdev->type == TYPE_RAID)
+ return -ENXIO;
+ sdev->no_uld_attach = 1;
+ return 0;
+ }
+ if (sdev->lun != 0)
+ return -ENXIO;
+
+ ldev_info = sdev->hostdata;
+ if (!ldev_info)
+ return -ENXIO;
+ if (ldev_info->ldev_control.wce == MYRS_WRITECACHE_ENABLED ||
+ ldev_info->ldev_control.wce == MYRS_INTELLIGENT_WRITECACHE_ENABLED)
+ sdev->wce_default_on = 1;
+ sdev->tagged_supported = 1;
+ return 0;
+}
+
+static void myrs_slave_destroy(struct scsi_device *sdev)
+{
+ kfree(sdev->hostdata);
+}
+
+struct scsi_host_template myrs_template = {
+ .module = THIS_MODULE,
+ .name = "DAC960",
+ .proc_name = "myrs",
+ .queuecommand = myrs_queuecommand,
+ .eh_host_reset_handler = myrs_host_reset,
+ .slave_alloc = myrs_slave_alloc,
+ .slave_configure = myrs_slave_configure,
+ .slave_destroy = myrs_slave_destroy,
+ .cmd_size = sizeof(struct myrs_cmdblk),
+ .shost_attrs = myrs_shost_attrs,
+ .sdev_attrs = myrs_sdev_attrs,
+ .this_id = -1,
+};
+
+static struct myrs_hba *myrs_alloc_host(struct pci_dev *pdev,
+ const struct pci_device_id *entry)
+{
+ struct Scsi_Host *shost;
+ struct myrs_hba *cs;
+
+ shost = scsi_host_alloc(&myrs_template, sizeof(struct myrs_hba));
+ if (!shost)
+ return NULL;
+
+ shost->max_cmd_len = 16;
+ shost->max_lun = 256;
+ cs = shost_priv(shost);
+ mutex_init(&cs->dcmd_mutex);
+ mutex_init(&cs->cinfo_mutex);
+ cs->host = shost;
+
+ return cs;
+}
+
+/*
+ * RAID template functions
+ */
+
+/**
+ * myrs_is_raid - return boolean indicating device is raid volume
+ * @dev the device struct object
+ */
+static int
+myrs_is_raid(struct device *dev)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct myrs_hba *cs = shost_priv(sdev->host);
+
+ return (sdev->channel >= cs->ctlr_info->physchan_present) ? 1 : 0;
+}
+
+/**
+ * myrs_get_resync - get raid volume resync percent complete
+ * @dev the device struct object
+ */
+static void
+myrs_get_resync(struct device *dev)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct myrs_hba *cs = shost_priv(sdev->host);
+ struct myrs_ldev_info *ldev_info = sdev->hostdata;
+ u64 percent_complete = 0;
+ u8 status;
+
+ if (sdev->channel < cs->ctlr_info->physchan_present || !ldev_info)
+ return;
+ if (ldev_info->rbld_active) {
+ unsigned short ldev_num = ldev_info->ldev_num;
+
+ status = myrs_get_ldev_info(cs, ldev_num, ldev_info);
+ percent_complete = ldev_info->rbld_lba * 100;
+ do_div(percent_complete, ldev_info->cfg_devsize);
+ }
+ raid_set_resync(myrs_raid_template, dev, percent_complete);
+}
+
+/**
+ * myrs_get_state - get raid volume status
+ * @dev the device struct object
+ */
+static void
+myrs_get_state(struct device *dev)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct myrs_hba *cs = shost_priv(sdev->host);
+ struct myrs_ldev_info *ldev_info = sdev->hostdata;
+ enum raid_state state = RAID_STATE_UNKNOWN;
+
+ if (sdev->channel < cs->ctlr_info->physchan_present || !ldev_info)
+ state = RAID_STATE_UNKNOWN;
+ else {
+ switch (ldev_info->dev_state) {
+ case MYRS_DEVICE_ONLINE:
+ state = RAID_STATE_ACTIVE;
+ break;
+ case MYRS_DEVICE_SUSPECTED_CRITICAL:
+ case MYRS_DEVICE_CRITICAL:
+ state = RAID_STATE_DEGRADED;
+ break;
+ case MYRS_DEVICE_REBUILD:
+ state = RAID_STATE_RESYNCING;
+ break;
+ case MYRS_DEVICE_UNCONFIGURED:
+ case MYRS_DEVICE_INVALID_STATE:
+ state = RAID_STATE_UNKNOWN;
+ break;
+ default:
+ state = RAID_STATE_OFFLINE;
+ }
+ }
+ raid_set_state(myrs_raid_template, dev, state);
+}
+
+struct raid_function_template myrs_raid_functions = {
+ .cookie = &myrs_template,
+ .is_raid = myrs_is_raid,
+ .get_resync = myrs_get_resync,
+ .get_state = myrs_get_state,
+};
+
+/*
+ * PCI interface functions
+ */
+void myrs_flush_cache(struct myrs_hba *cs)
+{
+ myrs_dev_op(cs, MYRS_IOCTL_FLUSH_DEVICE_DATA, MYRS_RAID_CONTROLLER);
+}
+
+static void myrs_handle_scsi(struct myrs_hba *cs, struct myrs_cmdblk *cmd_blk,
+ struct scsi_cmnd *scmd)
+{
+ unsigned char status;
+
+ if (!cmd_blk)
+ return;
+
+ scsi_dma_unmap(scmd);
+ status = cmd_blk->status;
+ if (cmd_blk->sense) {
+ if (status == MYRS_STATUS_FAILED && cmd_blk->sense_len) {
+ unsigned int sense_len = SCSI_SENSE_BUFFERSIZE;
+
+ if (sense_len > cmd_blk->sense_len)
+ sense_len = cmd_blk->sense_len;
+ memcpy(scmd->sense_buffer, cmd_blk->sense, sense_len);
+ }
+ dma_pool_free(cs->sense_pool, cmd_blk->sense,
+ cmd_blk->sense_addr);
+ cmd_blk->sense = NULL;
+ cmd_blk->sense_addr = 0;
+ }
+ if (cmd_blk->dcdb) {
+ dma_pool_free(cs->dcdb_pool, cmd_blk->dcdb,
+ cmd_blk->dcdb_dma);
+ cmd_blk->dcdb = NULL;
+ cmd_blk->dcdb_dma = 0;
+ }
+ if (cmd_blk->sgl) {
+ dma_pool_free(cs->sg_pool, cmd_blk->sgl,
+ cmd_blk->sgl_addr);
+ cmd_blk->sgl = NULL;
+ cmd_blk->sgl_addr = 0;
+ }
+ if (cmd_blk->residual)
+ scsi_set_resid(scmd, cmd_blk->residual);
+ if (status == MYRS_STATUS_DEVICE_NON_RESPONSIVE ||
+ status == MYRS_STATUS_DEVICE_NON_RESPONSIVE2)
+ scmd->result = (DID_BAD_TARGET << 16);
+ else
+ scmd->result = (DID_OK << 16) | status;
+ scmd->scsi_done(scmd);
+}
+
+static void myrs_handle_cmdblk(struct myrs_hba *cs, struct myrs_cmdblk *cmd_blk)
+{
+ if (!cmd_blk)
+ return;
+
+ if (cmd_blk->complete) {
+ complete(cmd_blk->complete);
+ cmd_blk->complete = NULL;
+ }
+}
+
+static void myrs_monitor(struct work_struct *work)
+{
+ struct myrs_hba *cs = container_of(work, struct myrs_hba,
+ monitor_work.work);
+ struct Scsi_Host *shost = cs->host;
+ struct myrs_ctlr_info *info = cs->ctlr_info;
+ unsigned int epoch = cs->fwstat_buf->epoch;
+ unsigned long interval = MYRS_PRIMARY_MONITOR_INTERVAL;
+ unsigned char status;
+
+ dev_dbg(&shost->shost_gendev, "monitor tick\n");
+
+ status = myrs_get_fwstatus(cs);
+
+ if (cs->needs_update) {
+ cs->needs_update = false;
+ mutex_lock(&cs->cinfo_mutex);
+ status = myrs_get_ctlr_info(cs);
+ mutex_unlock(&cs->cinfo_mutex);
+ }
+ if (cs->fwstat_buf->next_evseq - cs->next_evseq > 0) {
+ status = myrs_get_event(cs, cs->next_evseq,
+ cs->event_buf);
+ if (status == MYRS_STATUS_SUCCESS) {
+ myrs_log_event(cs, cs->event_buf);
+ cs->next_evseq++;
+ interval = 1;
+ }
+ }
+
+ if (time_after(jiffies, cs->secondary_monitor_time
+ + MYRS_SECONDARY_MONITOR_INTERVAL))
+ cs->secondary_monitor_time = jiffies;
+
+ if (info->bg_init_active +
+ info->ldev_init_active +
+ info->pdev_init_active +
+ info->cc_active +
+ info->rbld_active +
+ info->exp_active != 0) {
+ struct scsi_device *sdev;
+
+ shost_for_each_device(sdev, shost) {
+ struct myrs_ldev_info *ldev_info;
+ int ldev_num;
+
+ if (sdev->channel < info->physchan_present)
+ continue;
+ ldev_info = sdev->hostdata;
+ if (!ldev_info)
+ continue;
+ ldev_num = ldev_info->ldev_num;
+ myrs_get_ldev_info(cs, ldev_num, ldev_info);
+ }
+ cs->needs_update = true;
+ }
+ if (epoch == cs->epoch &&
+ cs->fwstat_buf->next_evseq == cs->next_evseq &&
+ (cs->needs_update == false ||
+ time_before(jiffies, cs->primary_monitor_time
+ + MYRS_PRIMARY_MONITOR_INTERVAL))) {
+ interval = MYRS_SECONDARY_MONITOR_INTERVAL;
+ }
+
+ if (interval > 1)
+ cs->primary_monitor_time = jiffies;
+ queue_delayed_work(cs->work_q, &cs->monitor_work, interval);
+}
+
+static bool myrs_create_mempools(struct pci_dev *pdev, struct myrs_hba *cs)
+{
+ struct Scsi_Host *shost = cs->host;
+ size_t elem_size, elem_align;
+
+ elem_align = sizeof(struct myrs_sge);
+ elem_size = shost->sg_tablesize * elem_align;
+ cs->sg_pool = dma_pool_create("myrs_sg", &pdev->dev,
+ elem_size, elem_align, 0);
+ if (cs->sg_pool == NULL) {
+ shost_printk(KERN_ERR, shost,
+ "Failed to allocate SG pool\n");
+ return false;
+ }
+
+ cs->sense_pool = dma_pool_create("myrs_sense", &pdev->dev,
+ MYRS_SENSE_SIZE, sizeof(int), 0);
+ if (cs->sense_pool == NULL) {
+ dma_pool_destroy(cs->sg_pool);
+ cs->sg_pool = NULL;
+ shost_printk(KERN_ERR, shost,
+ "Failed to allocate sense data pool\n");
+ return false;
+ }
+
+ cs->dcdb_pool = dma_pool_create("myrs_dcdb", &pdev->dev,
+ MYRS_DCDB_SIZE,
+ sizeof(unsigned char), 0);
+ if (!cs->dcdb_pool) {
+ dma_pool_destroy(cs->sg_pool);
+ cs->sg_pool = NULL;
+ dma_pool_destroy(cs->sense_pool);
+ cs->sense_pool = NULL;
+ shost_printk(KERN_ERR, shost,
+ "Failed to allocate DCDB pool\n");
+ return false;
+ }
+
+ snprintf(cs->work_q_name, sizeof(cs->work_q_name),
+ "myrs_wq_%d", shost->host_no);
+ cs->work_q = create_singlethread_workqueue(cs->work_q_name);
+ if (!cs->work_q) {
+ dma_pool_destroy(cs->dcdb_pool);
+ cs->dcdb_pool = NULL;
+ dma_pool_destroy(cs->sg_pool);
+ cs->sg_pool = NULL;
+ dma_pool_destroy(cs->sense_pool);
+ cs->sense_pool = NULL;
+ shost_printk(KERN_ERR, shost,
+ "Failed to create workqueue\n");
+ return false;
+ }
+
+ /* Initialize the Monitoring Timer. */
+ INIT_DELAYED_WORK(&cs->monitor_work, myrs_monitor);
+ queue_delayed_work(cs->work_q, &cs->monitor_work, 1);
+
+ return true;
+}
+
+static void myrs_destroy_mempools(struct myrs_hba *cs)
+{
+ cancel_delayed_work_sync(&cs->monitor_work);
+ destroy_workqueue(cs->work_q);
+
+ dma_pool_destroy(cs->sg_pool);
+ dma_pool_destroy(cs->dcdb_pool);
+ dma_pool_destroy(cs->sense_pool);
+}
+
+static void myrs_unmap(struct myrs_hba *cs)
+{
+ kfree(cs->event_buf);
+ kfree(cs->ctlr_info);
+ if (cs->fwstat_buf) {
+ dma_free_coherent(&cs->pdev->dev, sizeof(struct myrs_fwstat),
+ cs->fwstat_buf, cs->fwstat_addr);
+ cs->fwstat_buf = NULL;
+ }
+ if (cs->first_stat_mbox) {
+ dma_free_coherent(&cs->pdev->dev, cs->stat_mbox_size,
+ cs->first_stat_mbox, cs->stat_mbox_addr);
+ cs->first_stat_mbox = NULL;
+ }
+ if (cs->first_cmd_mbox) {
+ dma_free_coherent(&cs->pdev->dev, cs->cmd_mbox_size,
+ cs->first_cmd_mbox, cs->cmd_mbox_addr);
+ cs->first_cmd_mbox = NULL;
+ }
+}
+
+static void myrs_cleanup(struct myrs_hba *cs)
+{
+ struct pci_dev *pdev = cs->pdev;
+
+ /* Free the memory mailbox, status, and related structures */
+ myrs_unmap(cs);
+
+ if (cs->mmio_base) {
+ cs->disable_intr(cs);
+ iounmap(cs->mmio_base);
+ }
+ if (cs->irq)
+ free_irq(cs->irq, cs);
+ if (cs->io_addr)
+ release_region(cs->io_addr, 0x80);
+ iounmap(cs->mmio_base);
+ pci_set_drvdata(pdev, NULL);
+ pci_disable_device(pdev);
+ scsi_host_put(cs->host);
+}
+
+static struct myrs_hba *myrs_detect(struct pci_dev *pdev,
+ const struct pci_device_id *entry)
+{
+ struct myrs_privdata *privdata =
+ (struct myrs_privdata *)entry->driver_data;
+ irq_handler_t irq_handler = privdata->irq_handler;
+ unsigned int mmio_size = privdata->mmio_size;
+ struct myrs_hba *cs = NULL;
+
+ cs = myrs_alloc_host(pdev, entry);
+ if (!cs) {
+ dev_err(&pdev->dev, "Unable to allocate Controller\n");
+ return NULL;
+ }
+ cs->pdev = pdev;
+
+ if (pci_enable_device(pdev))
+ goto Failure;
+
+ cs->pci_addr = pci_resource_start(pdev, 0);
+
+ pci_set_drvdata(pdev, cs);
+ spin_lock_init(&cs->queue_lock);
+ /* Map the Controller Register Window. */
+ if (mmio_size < PAGE_SIZE)
+ mmio_size = PAGE_SIZE;
+ cs->mmio_base = ioremap_nocache(cs->pci_addr & PAGE_MASK, mmio_size);
+ if (cs->mmio_base == NULL) {
+ dev_err(&pdev->dev,
+ "Unable to map Controller Register Window\n");
+ goto Failure;
+ }
+
+ cs->io_base = cs->mmio_base + (cs->pci_addr & ~PAGE_MASK);
+ if (privdata->hw_init(pdev, cs, cs->io_base))
+ goto Failure;
+
+ /* Acquire shared access to the IRQ Channel. */
+ if (request_irq(pdev->irq, irq_handler, IRQF_SHARED, "myrs", cs) < 0) {
+ dev_err(&pdev->dev,
+ "Unable to acquire IRQ Channel %d\n", pdev->irq);
+ goto Failure;
+ }
+ cs->irq = pdev->irq;
+ return cs;
+
+Failure:
+ dev_err(&pdev->dev,
+ "Failed to initialize Controller\n");
+ myrs_cleanup(cs);
+ return NULL;
+}
+
+/**
+ * myrs_err_status reports Controller BIOS Messages passed through
+ the Error Status Register when the driver performs the BIOS handshaking.
+ It returns true for fatal errors and false otherwise.
+*/
+
+static bool myrs_err_status(struct myrs_hba *cs, unsigned char status,
+ unsigned char parm0, unsigned char parm1)
+{
+ struct pci_dev *pdev = cs->pdev;
+
+ switch (status) {
+ case 0x00:
+ dev_info(&pdev->dev,
+ "Physical Device %d:%d Not Responding\n",
+ parm1, parm0);
+ break;
+ case 0x08:
+ dev_notice(&pdev->dev, "Spinning Up Drives\n");
+ break;
+ case 0x30:
+ dev_notice(&pdev->dev, "Configuration Checksum Error\n");
+ break;
+ case 0x60:
+ dev_notice(&pdev->dev, "Mirror Race Recovery Failed\n");
+ break;
+ case 0x70:
+ dev_notice(&pdev->dev, "Mirror Race Recovery In Progress\n");
+ break;
+ case 0x90:
+ dev_notice(&pdev->dev, "Physical Device %d:%d COD Mismatch\n",
+ parm1, parm0);
+ break;
+ case 0xA0:
+ dev_notice(&pdev->dev, "Logical Drive Installation Aborted\n");
+ break;
+ case 0xB0:
+ dev_notice(&pdev->dev, "Mirror Race On A Critical Logical Drive\n");
+ break;
+ case 0xD0:
+ dev_notice(&pdev->dev, "New Controller Configuration Found\n");
+ break;
+ case 0xF0:
+ dev_err(&pdev->dev, "Fatal Memory Parity Error\n");
+ return true;
+ default:
+ dev_err(&pdev->dev, "Unknown Initialization Error %02X\n",
+ status);
+ return true;
+ }
+ return false;
+}
+
+/*
+ * Hardware-specific functions
+ */
+
+/*
+ * DAC960 GEM Series Controllers.
+ */
+
+static inline void DAC960_GEM_hw_mbox_new_cmd(void __iomem *base)
+{
+ __le32 val = cpu_to_le32(DAC960_GEM_IDB_HWMBOX_NEW_CMD << 24);
+
+ writel(val, base + DAC960_GEM_IDB_READ_OFFSET);
+}
+
+static inline void DAC960_GEM_ack_hw_mbox_status(void __iomem *base)
+{
+ __le32 val = cpu_to_le32(DAC960_GEM_IDB_HWMBOX_ACK_STS << 24);
+
+ writel(val, base + DAC960_GEM_IDB_CLEAR_OFFSET);
+}
+
+static inline void DAC960_GEM_gen_intr(void __iomem *base)
+{
+ __le32 val = cpu_to_le32(DAC960_GEM_IDB_GEN_IRQ << 24);
+
+ writel(val, base + DAC960_GEM_IDB_READ_OFFSET);
+}
+
+static inline void DAC960_GEM_reset_ctrl(void __iomem *base)
+{
+ __le32 val = cpu_to_le32(DAC960_GEM_IDB_CTRL_RESET << 24);
+
+ writel(val, base + DAC960_GEM_IDB_READ_OFFSET);
+}
+
+static inline void DAC960_GEM_mem_mbox_new_cmd(void __iomem *base)
+{
+ __le32 val = cpu_to_le32(DAC960_GEM_IDB_HWMBOX_NEW_CMD << 24);
+
+ writel(val, base + DAC960_GEM_IDB_READ_OFFSET);
+}
+
+static inline bool DAC960_GEM_hw_mbox_is_full(void __iomem *base)
+{
+ __le32 val;
+
+ val = readl(base + DAC960_GEM_IDB_READ_OFFSET);
+ return (le32_to_cpu(val) >> 24) & DAC960_GEM_IDB_HWMBOX_FULL;
+}
+
+static inline bool DAC960_GEM_init_in_progress(void __iomem *base)
+{
+ __le32 val;
+
+ val = readl(base + DAC960_GEM_IDB_READ_OFFSET);
+ return (le32_to_cpu(val) >> 24) & DAC960_GEM_IDB_INIT_IN_PROGRESS;
+}
+
+static inline void DAC960_GEM_ack_hw_mbox_intr(void __iomem *base)
+{
+ __le32 val = cpu_to_le32(DAC960_GEM_ODB_HWMBOX_ACK_IRQ << 24);
+
+ writel(val, base + DAC960_GEM_ODB_CLEAR_OFFSET);
+}
+
+static inline void DAC960_GEM_ack_mem_mbox_intr(void __iomem *base)
+{
+ __le32 val = cpu_to_le32(DAC960_GEM_ODB_MMBOX_ACK_IRQ << 24);
+
+ writel(val, base + DAC960_GEM_ODB_CLEAR_OFFSET);
+}
+
+static inline void DAC960_GEM_ack_intr(void __iomem *base)
+{
+ __le32 val = cpu_to_le32((DAC960_GEM_ODB_HWMBOX_ACK_IRQ |
+ DAC960_GEM_ODB_MMBOX_ACK_IRQ) << 24);
+
+ writel(val, base + DAC960_GEM_ODB_CLEAR_OFFSET);
+}
+
+static inline bool DAC960_GEM_hw_mbox_status_available(void __iomem *base)
+{
+ __le32 val;
+
+ val = readl(base + DAC960_GEM_ODB_READ_OFFSET);
+ return (le32_to_cpu(val) >> 24) & DAC960_GEM_ODB_HWMBOX_STS_AVAIL;
+}
+
+static inline bool DAC960_GEM_mem_mbox_status_available(void __iomem *base)
+{
+ __le32 val;
+
+ val = readl(base + DAC960_GEM_ODB_READ_OFFSET);
+ return (le32_to_cpu(val) >> 24) & DAC960_GEM_ODB_MMBOX_STS_AVAIL;
+}
+
+static inline void DAC960_GEM_enable_intr(void __iomem *base)
+{
+ __le32 val = cpu_to_le32((DAC960_GEM_IRQMASK_HWMBOX_IRQ |
+ DAC960_GEM_IRQMASK_MMBOX_IRQ) << 24);
+ writel(val, base + DAC960_GEM_IRQMASK_CLEAR_OFFSET);
+}
+
+static inline void DAC960_GEM_disable_intr(void __iomem *base)
+{
+ __le32 val = 0;
+
+ writel(val, base + DAC960_GEM_IRQMASK_READ_OFFSET);
+}
+
+static inline bool DAC960_GEM_intr_enabled(void __iomem *base)
+{
+ __le32 val;
+
+ val = readl(base + DAC960_GEM_IRQMASK_READ_OFFSET);
+ return !((le32_to_cpu(val) >> 24) &
+ (DAC960_GEM_IRQMASK_HWMBOX_IRQ |
+ DAC960_GEM_IRQMASK_MMBOX_IRQ));
+}
+
+static inline void DAC960_GEM_write_cmd_mbox(union myrs_cmd_mbox *mem_mbox,
+ union myrs_cmd_mbox *mbox)
+{
+ memcpy(&mem_mbox->words[1], &mbox->words[1],
+ sizeof(union myrs_cmd_mbox) - sizeof(unsigned int));
+ /* Barrier to avoid reordering */
+ wmb();
+ mem_mbox->words[0] = mbox->words[0];
+ /* Barrier to force PCI access */
+ mb();
+}
+
+static inline void DAC960_GEM_write_hw_mbox(void __iomem *base,
+ dma_addr_t cmd_mbox_addr)
+{
+ dma_addr_writeql(cmd_mbox_addr, base + DAC960_GEM_CMDMBX_OFFSET);
+}
+
+static inline unsigned short DAC960_GEM_read_cmd_ident(void __iomem *base)
+{
+ return readw(base + DAC960_GEM_CMDSTS_OFFSET);
+}
+
+static inline unsigned char DAC960_GEM_read_cmd_status(void __iomem *base)
+{
+ return readw(base + DAC960_GEM_CMDSTS_OFFSET + 2);
+}
+
+static inline bool
+DAC960_GEM_read_error_status(void __iomem *base, unsigned char *error,
+ unsigned char *param0, unsigned char *param1)
+{
+ __le32 val;
+
+ val = readl(base + DAC960_GEM_ERRSTS_READ_OFFSET);
+ if (!((le32_to_cpu(val) >> 24) & DAC960_GEM_ERRSTS_PENDING))
+ return false;
+ *error = val & ~(DAC960_GEM_ERRSTS_PENDING << 24);
+ *param0 = readb(base + DAC960_GEM_CMDMBX_OFFSET + 0);
+ *param1 = readb(base + DAC960_GEM_CMDMBX_OFFSET + 1);
+ writel(0x03000000, base + DAC960_GEM_ERRSTS_CLEAR_OFFSET);
+ return true;
+}
+
+static inline unsigned char
+DAC960_GEM_mbox_init(void __iomem *base, dma_addr_t mbox_addr)
+{
+ unsigned char status;
+
+ while (DAC960_GEM_hw_mbox_is_full(base))
+ udelay(1);
+ DAC960_GEM_write_hw_mbox(base, mbox_addr);
+ DAC960_GEM_hw_mbox_new_cmd(base);
+ while (!DAC960_GEM_hw_mbox_status_available(base))
+ udelay(1);
+ status = DAC960_GEM_read_cmd_status(base);
+ DAC960_GEM_ack_hw_mbox_intr(base);
+ DAC960_GEM_ack_hw_mbox_status(base);
+
+ return status;
+}
+
+static int DAC960_GEM_hw_init(struct pci_dev *pdev,
+ struct myrs_hba *cs, void __iomem *base)
+{
+ int timeout = 0;
+ unsigned char status, parm0, parm1;
+
+ DAC960_GEM_disable_intr(base);
+ DAC960_GEM_ack_hw_mbox_status(base);
+ udelay(1000);
+ while (DAC960_GEM_init_in_progress(base) &&
+ timeout < MYRS_MAILBOX_TIMEOUT) {
+ if (DAC960_GEM_read_error_status(base, &status,
+ &parm0, &parm1) &&
+ myrs_err_status(cs, status, parm0, parm1))
+ return -EIO;
+ udelay(10);
+ timeout++;
+ }
+ if (timeout == MYRS_MAILBOX_TIMEOUT) {
+ dev_err(&pdev->dev,
+ "Timeout waiting for Controller Initialisation\n");
+ return -ETIMEDOUT;
+ }
+ if (!myrs_enable_mmio_mbox(cs, DAC960_GEM_mbox_init)) {
+ dev_err(&pdev->dev,
+ "Unable to Enable Memory Mailbox Interface\n");
+ DAC960_GEM_reset_ctrl(base);
+ return -EAGAIN;
+ }
+ DAC960_GEM_enable_intr(base);
+ cs->write_cmd_mbox = DAC960_GEM_write_cmd_mbox;
+ cs->get_cmd_mbox = DAC960_GEM_mem_mbox_new_cmd;
+ cs->disable_intr = DAC960_GEM_disable_intr;
+ cs->reset = DAC960_GEM_reset_ctrl;
+ return 0;
+}
+
+static irqreturn_t DAC960_GEM_intr_handler(int irq, void *arg)
+{
+ struct myrs_hba *cs = arg;
+ void __iomem *base = cs->io_base;
+ struct myrs_stat_mbox *next_stat_mbox;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cs->queue_lock, flags);
+ DAC960_GEM_ack_intr(base);
+ next_stat_mbox = cs->next_stat_mbox;
+ while (next_stat_mbox->id > 0) {
+ unsigned short id = next_stat_mbox->id;
+ struct scsi_cmnd *scmd = NULL;
+ struct myrs_cmdblk *cmd_blk = NULL;
+
+ if (id == MYRS_DCMD_TAG)
+ cmd_blk = &cs->dcmd_blk;
+ else if (id == MYRS_MCMD_TAG)
+ cmd_blk = &cs->mcmd_blk;
+ else {
+ scmd = scsi_host_find_tag(cs->host, id - 3);
+ if (scmd)
+ cmd_blk = scsi_cmd_priv(scmd);
+ }
+ if (cmd_blk) {
+ cmd_blk->status = next_stat_mbox->status;
+ cmd_blk->sense_len = next_stat_mbox->sense_len;
+ cmd_blk->residual = next_stat_mbox->residual;
+ } else
+ dev_err(&cs->pdev->dev,
+ "Unhandled command completion %d\n", id);
+
+ memset(next_stat_mbox, 0, sizeof(struct myrs_stat_mbox));
+ if (++next_stat_mbox > cs->last_stat_mbox)
+ next_stat_mbox = cs->first_stat_mbox;
+
+ if (cmd_blk) {
+ if (id < 3)
+ myrs_handle_cmdblk(cs, cmd_blk);
+ else
+ myrs_handle_scsi(cs, cmd_blk, scmd);
+ }
+ }
+ cs->next_stat_mbox = next_stat_mbox;
+ spin_unlock_irqrestore(&cs->queue_lock, flags);
+ return IRQ_HANDLED;
+}
+
+struct myrs_privdata DAC960_GEM_privdata = {
+ .hw_init = DAC960_GEM_hw_init,
+ .irq_handler = DAC960_GEM_intr_handler,
+ .mmio_size = DAC960_GEM_mmio_size,
+};
+
+/*
+ * DAC960 BA Series Controllers.
+ */
+
+static inline void DAC960_BA_hw_mbox_new_cmd(void __iomem *base)
+{
+ writeb(DAC960_BA_IDB_HWMBOX_NEW_CMD, base + DAC960_BA_IDB_OFFSET);
+}
+
+static inline void DAC960_BA_ack_hw_mbox_status(void __iomem *base)
+{
+ writeb(DAC960_BA_IDB_HWMBOX_ACK_STS, base + DAC960_BA_IDB_OFFSET);
+}
+
+static inline void DAC960_BA_gen_intr(void __iomem *base)
+{
+ writeb(DAC960_BA_IDB_GEN_IRQ, base + DAC960_BA_IDB_OFFSET);
+}
+
+static inline void DAC960_BA_reset_ctrl(void __iomem *base)
+{
+ writeb(DAC960_BA_IDB_CTRL_RESET, base + DAC960_BA_IDB_OFFSET);
+}
+
+static inline void DAC960_BA_mem_mbox_new_cmd(void __iomem *base)
+{
+ writeb(DAC960_BA_IDB_MMBOX_NEW_CMD, base + DAC960_BA_IDB_OFFSET);
+}
+
+static inline bool DAC960_BA_hw_mbox_is_full(void __iomem *base)
+{
+ u8 val;
+
+ val = readb(base + DAC960_BA_IDB_OFFSET);
+ return !(val & DAC960_BA_IDB_HWMBOX_EMPTY);
+}
+
+static inline bool DAC960_BA_init_in_progress(void __iomem *base)
+{
+ u8 val;
+
+ val = readb(base + DAC960_BA_IDB_OFFSET);
+ return !(val & DAC960_BA_IDB_INIT_DONE);
+}
+
+static inline void DAC960_BA_ack_hw_mbox_intr(void __iomem *base)
+{
+ writeb(DAC960_BA_ODB_HWMBOX_ACK_IRQ, base + DAC960_BA_ODB_OFFSET);
+}
+
+static inline void DAC960_BA_ack_mem_mbox_intr(void __iomem *base)
+{
+ writeb(DAC960_BA_ODB_MMBOX_ACK_IRQ, base + DAC960_BA_ODB_OFFSET);
+}
+
+static inline void DAC960_BA_ack_intr(void __iomem *base)
+{
+ writeb(DAC960_BA_ODB_HWMBOX_ACK_IRQ | DAC960_BA_ODB_MMBOX_ACK_IRQ,
+ base + DAC960_BA_ODB_OFFSET);
+}
+
+static inline bool DAC960_BA_hw_mbox_status_available(void __iomem *base)
+{
+ u8 val;
+
+ val = readb(base + DAC960_BA_ODB_OFFSET);
+ return val & DAC960_BA_ODB_HWMBOX_STS_AVAIL;
+}
+
+static inline bool DAC960_BA_mem_mbox_status_available(void __iomem *base)
+{
+ u8 val;
+
+ val = readb(base + DAC960_BA_ODB_OFFSET);
+ return val & DAC960_BA_ODB_MMBOX_STS_AVAIL;
+}
+
+static inline void DAC960_BA_enable_intr(void __iomem *base)
+{
+ writeb(~DAC960_BA_IRQMASK_DISABLE_IRQ, base + DAC960_BA_IRQMASK_OFFSET);
+}
+
+static inline void DAC960_BA_disable_intr(void __iomem *base)
+{
+ writeb(0xFF, base + DAC960_BA_IRQMASK_OFFSET);
+}
+
+static inline bool DAC960_BA_intr_enabled(void __iomem *base)
+{
+ u8 val;
+
+ val = readb(base + DAC960_BA_IRQMASK_OFFSET);
+ return !(val & DAC960_BA_IRQMASK_DISABLE_IRQ);
+}
+
+static inline void DAC960_BA_write_cmd_mbox(union myrs_cmd_mbox *mem_mbox,
+ union myrs_cmd_mbox *mbox)
+{
+ memcpy(&mem_mbox->words[1], &mbox->words[1],
+ sizeof(union myrs_cmd_mbox) - sizeof(unsigned int));
+ /* Barrier to avoid reordering */
+ wmb();
+ mem_mbox->words[0] = mbox->words[0];
+ /* Barrier to force PCI access */
+ mb();
+}
+
+
+static inline void DAC960_BA_write_hw_mbox(void __iomem *base,
+ dma_addr_t cmd_mbox_addr)
+{
+ dma_addr_writeql(cmd_mbox_addr, base + DAC960_BA_CMDMBX_OFFSET);
+}
+
+static inline unsigned short DAC960_BA_read_cmd_ident(void __iomem *base)
+{
+ return readw(base + DAC960_BA_CMDSTS_OFFSET);
+}
+
+static inline unsigned char DAC960_BA_read_cmd_status(void __iomem *base)
+{
+ return readw(base + DAC960_BA_CMDSTS_OFFSET + 2);
+}
+
+static inline bool
+DAC960_BA_read_error_status(void __iomem *base, unsigned char *error,
+ unsigned char *param0, unsigned char *param1)
+{
+ u8 val;
+
+ val = readb(base + DAC960_BA_ERRSTS_OFFSET);
+ if (!(val & DAC960_BA_ERRSTS_PENDING))
+ return false;
+ val &= ~DAC960_BA_ERRSTS_PENDING;
+ *error = val;
+ *param0 = readb(base + DAC960_BA_CMDMBX_OFFSET + 0);
+ *param1 = readb(base + DAC960_BA_CMDMBX_OFFSET + 1);
+ writeb(0xFF, base + DAC960_BA_ERRSTS_OFFSET);
+ return true;
+}
+
+static inline unsigned char
+DAC960_BA_mbox_init(void __iomem *base, dma_addr_t mbox_addr)
+{
+ unsigned char status;
+
+ while (DAC960_BA_hw_mbox_is_full(base))
+ udelay(1);
+ DAC960_BA_write_hw_mbox(base, mbox_addr);
+ DAC960_BA_hw_mbox_new_cmd(base);
+ while (!DAC960_BA_hw_mbox_status_available(base))
+ udelay(1);
+ status = DAC960_BA_read_cmd_status(base);
+ DAC960_BA_ack_hw_mbox_intr(base);
+ DAC960_BA_ack_hw_mbox_status(base);
+
+ return status;
+}
+
+static int DAC960_BA_hw_init(struct pci_dev *pdev,
+ struct myrs_hba *cs, void __iomem *base)
+{
+ int timeout = 0;
+ unsigned char status, parm0, parm1;
+
+ DAC960_BA_disable_intr(base);
+ DAC960_BA_ack_hw_mbox_status(base);
+ udelay(1000);
+ while (DAC960_BA_init_in_progress(base) &&
+ timeout < MYRS_MAILBOX_TIMEOUT) {
+ if (DAC960_BA_read_error_status(base, &status,
+ &parm0, &parm1) &&
+ myrs_err_status(cs, status, parm0, parm1))
+ return -EIO;
+ udelay(10);
+ timeout++;
+ }
+ if (timeout == MYRS_MAILBOX_TIMEOUT) {
+ dev_err(&pdev->dev,
+ "Timeout waiting for Controller Initialisation\n");
+ return -ETIMEDOUT;
+ }
+ if (!myrs_enable_mmio_mbox(cs, DAC960_BA_mbox_init)) {
+ dev_err(&pdev->dev,
+ "Unable to Enable Memory Mailbox Interface\n");
+ DAC960_BA_reset_ctrl(base);
+ return -EAGAIN;
+ }
+ DAC960_BA_enable_intr(base);
+ cs->write_cmd_mbox = DAC960_BA_write_cmd_mbox;
+ cs->get_cmd_mbox = DAC960_BA_mem_mbox_new_cmd;
+ cs->disable_intr = DAC960_BA_disable_intr;
+ cs->reset = DAC960_BA_reset_ctrl;
+ return 0;
+}
+
+static irqreturn_t DAC960_BA_intr_handler(int irq, void *arg)
+{
+ struct myrs_hba *cs = arg;
+ void __iomem *base = cs->io_base;
+ struct myrs_stat_mbox *next_stat_mbox;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cs->queue_lock, flags);
+ DAC960_BA_ack_intr(base);
+ next_stat_mbox = cs->next_stat_mbox;
+ while (next_stat_mbox->id > 0) {
+ unsigned short id = next_stat_mbox->id;
+ struct scsi_cmnd *scmd = NULL;
+ struct myrs_cmdblk *cmd_blk = NULL;
+
+ if (id == MYRS_DCMD_TAG)
+ cmd_blk = &cs->dcmd_blk;
+ else if (id == MYRS_MCMD_TAG)
+ cmd_blk = &cs->mcmd_blk;
+ else {
+ scmd = scsi_host_find_tag(cs->host, id - 3);
+ if (scmd)
+ cmd_blk = scsi_cmd_priv(scmd);
+ }
+ if (cmd_blk) {
+ cmd_blk->status = next_stat_mbox->status;
+ cmd_blk->sense_len = next_stat_mbox->sense_len;
+ cmd_blk->residual = next_stat_mbox->residual;
+ } else
+ dev_err(&cs->pdev->dev,
+ "Unhandled command completion %d\n", id);
+
+ memset(next_stat_mbox, 0, sizeof(struct myrs_stat_mbox));
+ if (++next_stat_mbox > cs->last_stat_mbox)
+ next_stat_mbox = cs->first_stat_mbox;
+
+ if (cmd_blk) {
+ if (id < 3)
+ myrs_handle_cmdblk(cs, cmd_blk);
+ else
+ myrs_handle_scsi(cs, cmd_blk, scmd);
+ }
+ }
+ cs->next_stat_mbox = next_stat_mbox;
+ spin_unlock_irqrestore(&cs->queue_lock, flags);
+ return IRQ_HANDLED;
+}
+
+struct myrs_privdata DAC960_BA_privdata = {
+ .hw_init = DAC960_BA_hw_init,
+ .irq_handler = DAC960_BA_intr_handler,
+ .mmio_size = DAC960_BA_mmio_size,
+};
+
+/*
+ * DAC960 LP Series Controllers.
+ */
+
+static inline void DAC960_LP_hw_mbox_new_cmd(void __iomem *base)
+{
+ writeb(DAC960_LP_IDB_HWMBOX_NEW_CMD, base + DAC960_LP_IDB_OFFSET);
+}
+
+static inline void DAC960_LP_ack_hw_mbox_status(void __iomem *base)
+{
+ writeb(DAC960_LP_IDB_HWMBOX_ACK_STS, base + DAC960_LP_IDB_OFFSET);
+}
+
+static inline void DAC960_LP_gen_intr(void __iomem *base)
+{
+ writeb(DAC960_LP_IDB_GEN_IRQ, base + DAC960_LP_IDB_OFFSET);
+}
+
+static inline void DAC960_LP_reset_ctrl(void __iomem *base)
+{
+ writeb(DAC960_LP_IDB_CTRL_RESET, base + DAC960_LP_IDB_OFFSET);
+}
+
+static inline void DAC960_LP_mem_mbox_new_cmd(void __iomem *base)
+{
+ writeb(DAC960_LP_IDB_MMBOX_NEW_CMD, base + DAC960_LP_IDB_OFFSET);
+}
+
+static inline bool DAC960_LP_hw_mbox_is_full(void __iomem *base)
+{
+ u8 val;
+
+ val = readb(base + DAC960_LP_IDB_OFFSET);
+ return val & DAC960_LP_IDB_HWMBOX_FULL;
+}
+
+static inline bool DAC960_LP_init_in_progress(void __iomem *base)
+{
+ u8 val;
+
+ val = readb(base + DAC960_LP_IDB_OFFSET);
+ return val & DAC960_LP_IDB_INIT_IN_PROGRESS;
+}
+
+static inline void DAC960_LP_ack_hw_mbox_intr(void __iomem *base)
+{
+ writeb(DAC960_LP_ODB_HWMBOX_ACK_IRQ, base + DAC960_LP_ODB_OFFSET);
+}
+
+static inline void DAC960_LP_ack_mem_mbox_intr(void __iomem *base)
+{
+ writeb(DAC960_LP_ODB_MMBOX_ACK_IRQ, base + DAC960_LP_ODB_OFFSET);
+}
+
+static inline void DAC960_LP_ack_intr(void __iomem *base)
+{
+ writeb(DAC960_LP_ODB_HWMBOX_ACK_IRQ | DAC960_LP_ODB_MMBOX_ACK_IRQ,
+ base + DAC960_LP_ODB_OFFSET);
+}
+
+static inline bool DAC960_LP_hw_mbox_status_available(void __iomem *base)
+{
+ u8 val;
+
+ val = readb(base + DAC960_LP_ODB_OFFSET);
+ return val & DAC960_LP_ODB_HWMBOX_STS_AVAIL;
+}
+
+static inline bool DAC960_LP_mem_mbox_status_available(void __iomem *base)
+{
+ u8 val;
+
+ val = readb(base + DAC960_LP_ODB_OFFSET);
+ return val & DAC960_LP_ODB_MMBOX_STS_AVAIL;
+}
+
+static inline void DAC960_LP_enable_intr(void __iomem *base)
+{
+ writeb(~DAC960_LP_IRQMASK_DISABLE_IRQ, base + DAC960_LP_IRQMASK_OFFSET);
+}
+
+static inline void DAC960_LP_disable_intr(void __iomem *base)
+{
+ writeb(0xFF, base + DAC960_LP_IRQMASK_OFFSET);
+}
+
+static inline bool DAC960_LP_intr_enabled(void __iomem *base)
+{
+ u8 val;
+
+ val = readb(base + DAC960_LP_IRQMASK_OFFSET);
+ return !(val & DAC960_LP_IRQMASK_DISABLE_IRQ);
+}
+
+static inline void DAC960_LP_write_cmd_mbox(union myrs_cmd_mbox *mem_mbox,
+ union myrs_cmd_mbox *mbox)
+{
+ memcpy(&mem_mbox->words[1], &mbox->words[1],
+ sizeof(union myrs_cmd_mbox) - sizeof(unsigned int));
+ /* Barrier to avoid reordering */
+ wmb();
+ mem_mbox->words[0] = mbox->words[0];
+ /* Barrier to force PCI access */
+ mb();
+}
+
+static inline void DAC960_LP_write_hw_mbox(void __iomem *base,
+ dma_addr_t cmd_mbox_addr)
+{
+ dma_addr_writeql(cmd_mbox_addr, base + DAC960_LP_CMDMBX_OFFSET);
+}
+
+static inline unsigned short DAC960_LP_read_cmd_ident(void __iomem *base)
+{
+ return readw(base + DAC960_LP_CMDSTS_OFFSET);
+}
+
+static inline unsigned char DAC960_LP_read_cmd_status(void __iomem *base)
+{
+ return readw(base + DAC960_LP_CMDSTS_OFFSET + 2);
+}
+
+static inline bool
+DAC960_LP_read_error_status(void __iomem *base, unsigned char *error,
+ unsigned char *param0, unsigned char *param1)
+{
+ u8 val;
+
+ val = readb(base + DAC960_LP_ERRSTS_OFFSET);
+ if (!(val & DAC960_LP_ERRSTS_PENDING))
+ return false;
+ val &= ~DAC960_LP_ERRSTS_PENDING;
+ *error = val;
+ *param0 = readb(base + DAC960_LP_CMDMBX_OFFSET + 0);
+ *param1 = readb(base + DAC960_LP_CMDMBX_OFFSET + 1);
+ writeb(0xFF, base + DAC960_LP_ERRSTS_OFFSET);
+ return true;
+}
+
+static inline unsigned char
+DAC960_LP_mbox_init(void __iomem *base, dma_addr_t mbox_addr)
+{
+ unsigned char status;
+
+ while (DAC960_LP_hw_mbox_is_full(base))
+ udelay(1);
+ DAC960_LP_write_hw_mbox(base, mbox_addr);
+ DAC960_LP_hw_mbox_new_cmd(base);
+ while (!DAC960_LP_hw_mbox_status_available(base))
+ udelay(1);
+ status = DAC960_LP_read_cmd_status(base);
+ DAC960_LP_ack_hw_mbox_intr(base);
+ DAC960_LP_ack_hw_mbox_status(base);
+
+ return status;
+}
+
+static int DAC960_LP_hw_init(struct pci_dev *pdev,
+ struct myrs_hba *cs, void __iomem *base)
+{
+ int timeout = 0;
+ unsigned char status, parm0, parm1;
+
+ DAC960_LP_disable_intr(base);
+ DAC960_LP_ack_hw_mbox_status(base);
+ udelay(1000);
+ while (DAC960_LP_init_in_progress(base) &&
+ timeout < MYRS_MAILBOX_TIMEOUT) {
+ if (DAC960_LP_read_error_status(base, &status,
+ &parm0, &parm1) &&
+ myrs_err_status(cs, status, parm0, parm1))
+ return -EIO;
+ udelay(10);
+ timeout++;
+ }
+ if (timeout == MYRS_MAILBOX_TIMEOUT) {
+ dev_err(&pdev->dev,
+ "Timeout waiting for Controller Initialisation\n");
+ return -ETIMEDOUT;
+ }
+ if (!myrs_enable_mmio_mbox(cs, DAC960_LP_mbox_init)) {
+ dev_err(&pdev->dev,
+ "Unable to Enable Memory Mailbox Interface\n");
+ DAC960_LP_reset_ctrl(base);
+ return -ENODEV;
+ }
+ DAC960_LP_enable_intr(base);
+ cs->write_cmd_mbox = DAC960_LP_write_cmd_mbox;
+ cs->get_cmd_mbox = DAC960_LP_mem_mbox_new_cmd;
+ cs->disable_intr = DAC960_LP_disable_intr;
+ cs->reset = DAC960_LP_reset_ctrl;
+
+ return 0;
+}
+
+static irqreturn_t DAC960_LP_intr_handler(int irq, void *arg)
+{
+ struct myrs_hba *cs = arg;
+ void __iomem *base = cs->io_base;
+ struct myrs_stat_mbox *next_stat_mbox;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cs->queue_lock, flags);
+ DAC960_LP_ack_intr(base);
+ next_stat_mbox = cs->next_stat_mbox;
+ while (next_stat_mbox->id > 0) {
+ unsigned short id = next_stat_mbox->id;
+ struct scsi_cmnd *scmd = NULL;
+ struct myrs_cmdblk *cmd_blk = NULL;
+
+ if (id == MYRS_DCMD_TAG)
+ cmd_blk = &cs->dcmd_blk;
+ else if (id == MYRS_MCMD_TAG)
+ cmd_blk = &cs->mcmd_blk;
+ else {
+ scmd = scsi_host_find_tag(cs->host, id - 3);
+ if (scmd)
+ cmd_blk = scsi_cmd_priv(scmd);
+ }
+ if (cmd_blk) {
+ cmd_blk->status = next_stat_mbox->status;
+ cmd_blk->sense_len = next_stat_mbox->sense_len;
+ cmd_blk->residual = next_stat_mbox->residual;
+ } else
+ dev_err(&cs->pdev->dev,
+ "Unhandled command completion %d\n", id);
+
+ memset(next_stat_mbox, 0, sizeof(struct myrs_stat_mbox));
+ if (++next_stat_mbox > cs->last_stat_mbox)
+ next_stat_mbox = cs->first_stat_mbox;
+
+ if (cmd_blk) {
+ if (id < 3)
+ myrs_handle_cmdblk(cs, cmd_blk);
+ else
+ myrs_handle_scsi(cs, cmd_blk, scmd);
+ }
+ }
+ cs->next_stat_mbox = next_stat_mbox;
+ spin_unlock_irqrestore(&cs->queue_lock, flags);
+ return IRQ_HANDLED;
+}
+
+struct myrs_privdata DAC960_LP_privdata = {
+ .hw_init = DAC960_LP_hw_init,
+ .irq_handler = DAC960_LP_intr_handler,
+ .mmio_size = DAC960_LP_mmio_size,
+};
+
+/*
+ * Module functions
+ */
+static int
+myrs_probe(struct pci_dev *dev, const struct pci_device_id *entry)
+{
+ struct myrs_hba *cs;
+ int ret;
+
+ cs = myrs_detect(dev, entry);
+ if (!cs)
+ return -ENODEV;
+
+ ret = myrs_get_config(cs);
+ if (ret < 0) {
+ myrs_cleanup(cs);
+ return ret;
+ }
+
+ if (!myrs_create_mempools(dev, cs)) {
+ ret = -ENOMEM;
+ goto failed;
+ }
+
+ ret = scsi_add_host(cs->host, &dev->dev);
+ if (ret) {
+ dev_err(&dev->dev, "scsi_add_host failed with %d\n", ret);
+ myrs_destroy_mempools(cs);
+ goto failed;
+ }
+ scsi_scan_host(cs->host);
+ return 0;
+failed:
+ myrs_cleanup(cs);
+ return ret;
+}
+
+
+static void myrs_remove(struct pci_dev *pdev)
+{
+ struct myrs_hba *cs = pci_get_drvdata(pdev);
+
+ if (cs == NULL)
+ return;
+
+ shost_printk(KERN_NOTICE, cs->host, "Flushing Cache...");
+ myrs_flush_cache(cs);
+ myrs_destroy_mempools(cs);
+ myrs_cleanup(cs);
+}
+
+
+static const struct pci_device_id myrs_id_table[] = {
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_MYLEX,
+ PCI_DEVICE_ID_MYLEX_DAC960_GEM,
+ PCI_VENDOR_ID_MYLEX, PCI_ANY_ID),
+ .driver_data = (unsigned long) &DAC960_GEM_privdata,
+ },
+ {
+ PCI_DEVICE_DATA(MYLEX, DAC960_BA, &DAC960_BA_privdata),
+ },
+ {
+ PCI_DEVICE_DATA(MYLEX, DAC960_LP, &DAC960_LP_privdata),
+ },
+ {0, },
+};
+
+MODULE_DEVICE_TABLE(pci, myrs_id_table);
+
+static struct pci_driver myrs_pci_driver = {
+ .name = "myrs",
+ .id_table = myrs_id_table,
+ .probe = myrs_probe,
+ .remove = myrs_remove,
+};
+
+static int __init myrs_init_module(void)
+{
+ int ret;
+
+ myrs_raid_template = raid_class_attach(&myrs_raid_functions);
+ if (!myrs_raid_template)
+ return -ENODEV;
+
+ ret = pci_register_driver(&myrs_pci_driver);
+ if (ret)
+ raid_class_release(myrs_raid_template);
+
+ return ret;
+}
+
+static void __exit myrs_cleanup_module(void)
+{
+ pci_unregister_driver(&myrs_pci_driver);
+ raid_class_release(myrs_raid_template);
+}
+
+module_init(myrs_init_module);
+module_exit(myrs_cleanup_module);
+
+MODULE_DESCRIPTION("Mylex DAC960/AcceleRAID/eXtremeRAID driver (SCSI Interface)");
+MODULE_AUTHOR("Hannes Reinecke <hare@suse.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/myrs.h b/drivers/scsi/myrs.h
new file mode 100644
index 000000000000..e6702ee85e9f
--- /dev/null
+++ b/drivers/scsi/myrs.h
@@ -0,0 +1,1134 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers
+ *
+ * This driver supports the newer, SCSI-based firmware interface only.
+ *
+ * Copyright 2018 Hannes Reinecke, SUSE Linux GmbH <hare@suse.com>
+ *
+ * Based on the original DAC960 driver, which has
+ * Copyright 1998-2001 by Leonard N. Zubkoff <lnz@dandelion.com>
+ * Portions Copyright 2002 by Mylex (An IBM Business Unit)
+ */
+
+#ifndef _MYRS_H
+#define _MYRS_H
+
+#define MYRS_MAILBOX_TIMEOUT 1000000
+
+#define MYRS_DCMD_TAG 1
+#define MYRS_MCMD_TAG 2
+
+#define MYRS_LINE_BUFFER_SIZE 128
+
+#define MYRS_PRIMARY_MONITOR_INTERVAL (10 * HZ)
+#define MYRS_SECONDARY_MONITOR_INTERVAL (60 * HZ)
+
+/* Maximum number of Scatter/Gather Segments supported */
+#define MYRS_SG_LIMIT 128
+
+/*
+ * Number of Command and Status Mailboxes used by the
+ * DAC960 V2 Firmware Memory Mailbox Interface.
+ */
+#define MYRS_MAX_CMD_MBOX 512
+#define MYRS_MAX_STAT_MBOX 512
+
+#define MYRS_DCDB_SIZE 16
+#define MYRS_SENSE_SIZE 14
+
+/*
+ * DAC960 V2 Firmware Command Opcodes.
+ */
+enum myrs_cmd_opcode {
+ MYRS_CMD_OP_MEMCOPY = 0x01,
+ MYRS_CMD_OP_SCSI_10_PASSTHRU = 0x02,
+ MYRS_CMD_OP_SCSI_255_PASSTHRU = 0x03,
+ MYRS_CMD_OP_SCSI_10 = 0x04,
+ MYRS_CMD_OP_SCSI_256 = 0x05,
+ MYRS_CMD_OP_IOCTL = 0x20,
+} __packed;
+
+/*
+ * DAC960 V2 Firmware IOCTL Opcodes.
+ */
+enum myrs_ioctl_opcode {
+ MYRS_IOCTL_GET_CTLR_INFO = 0x01,
+ MYRS_IOCTL_GET_LDEV_INFO_VALID = 0x03,
+ MYRS_IOCTL_GET_PDEV_INFO_VALID = 0x05,
+ MYRS_IOCTL_GET_HEALTH_STATUS = 0x11,
+ MYRS_IOCTL_GET_EVENT = 0x15,
+ MYRS_IOCTL_START_DISCOVERY = 0x81,
+ MYRS_IOCTL_SET_DEVICE_STATE = 0x82,
+ MYRS_IOCTL_INIT_PDEV_START = 0x84,
+ MYRS_IOCTL_INIT_PDEV_STOP = 0x85,
+ MYRS_IOCTL_INIT_LDEV_START = 0x86,
+ MYRS_IOCTL_INIT_LDEV_STOP = 0x87,
+ MYRS_IOCTL_RBLD_DEVICE_START = 0x88,
+ MYRS_IOCTL_RBLD_DEVICE_STOP = 0x89,
+ MYRS_IOCTL_MAKE_CONSISTENT_START = 0x8A,
+ MYRS_IOCTL_MAKE_CONSISTENT_STOP = 0x8B,
+ MYRS_IOCTL_CC_START = 0x8C,
+ MYRS_IOCTL_CC_STOP = 0x8D,
+ MYRS_IOCTL_SET_MEM_MBOX = 0x8E,
+ MYRS_IOCTL_RESET_DEVICE = 0x90,
+ MYRS_IOCTL_FLUSH_DEVICE_DATA = 0x91,
+ MYRS_IOCTL_PAUSE_DEVICE = 0x92,
+ MYRS_IOCTL_UNPAUS_EDEVICE = 0x93,
+ MYRS_IOCTL_LOCATE_DEVICE = 0x94,
+ MYRS_IOCTL_CREATE_CONFIGURATION = 0xC0,
+ MYRS_IOCTL_DELETE_LDEV = 0xC1,
+ MYRS_IOCTL_REPLACE_INTERNALDEVICE = 0xC2,
+ MYRS_IOCTL_RENAME_LDEV = 0xC3,
+ MYRS_IOCTL_ADD_CONFIGURATION = 0xC4,
+ MYRS_IOCTL_XLATE_PDEV_TO_LDEV = 0xC5,
+ MYRS_IOCTL_CLEAR_CONFIGURATION = 0xCA,
+} __packed;
+
+/*
+ * DAC960 V2 Firmware Command Status Codes.
+ */
+#define MYRS_STATUS_SUCCESS 0x00
+#define MYRS_STATUS_FAILED 0x02
+#define MYRS_STATUS_DEVICE_BUSY 0x08
+#define MYRS_STATUS_DEVICE_NON_RESPONSIVE 0x0E
+#define MYRS_STATUS_DEVICE_NON_RESPONSIVE2 0x0F
+#define MYRS_STATUS_RESERVATION_CONFLICT 0x18
+
+/*
+ * DAC960 V2 Firmware Memory Type structure.
+ */
+struct myrs_mem_type {
+ enum {
+ MYRS_MEMTYPE_RESERVED = 0x00,
+ MYRS_MEMTYPE_DRAM = 0x01,
+ MYRS_MEMTYPE_EDRAM = 0x02,
+ MYRS_MEMTYPE_EDO = 0x03,
+ MYRS_MEMTYPE_SDRAM = 0x04,
+ MYRS_MEMTYPE_LAST = 0x1F,
+ } __packed mem_type:5; /* Byte 0 Bits 0-4 */
+ unsigned rsvd:1; /* Byte 0 Bit 5 */
+ unsigned mem_parity:1; /* Byte 0 Bit 6 */
+ unsigned mem_ecc:1; /* Byte 0 Bit 7 */
+};
+
+/*
+ * DAC960 V2 Firmware Processor Type structure.
+ */
+enum myrs_cpu_type {
+ MYRS_CPUTYPE_i960CA = 0x01,
+ MYRS_CPUTYPE_i960RD = 0x02,
+ MYRS_CPUTYPE_i960RN = 0x03,
+ MYRS_CPUTYPE_i960RP = 0x04,
+ MYRS_CPUTYPE_NorthBay = 0x05,
+ MYRS_CPUTYPE_StrongArm = 0x06,
+ MYRS_CPUTYPE_i960RM = 0x07,
+} __packed;
+
+/*
+ * DAC960 V2 Firmware Get Controller Info reply structure.
+ */
+struct myrs_ctlr_info {
+ unsigned char rsvd1; /* Byte 0 */
+ enum {
+ MYRS_SCSI_BUS = 0x00,
+ MYRS_Fibre_BUS = 0x01,
+ MYRS_PCI_BUS = 0x03
+ } __packed bus; /* Byte 1 */
+ enum {
+ MYRS_CTLR_DAC960E = 0x01,
+ MYRS_CTLR_DAC960M = 0x08,
+ MYRS_CTLR_DAC960PD = 0x10,
+ MYRS_CTLR_DAC960PL = 0x11,
+ MYRS_CTLR_DAC960PU = 0x12,
+ MYRS_CTLR_DAC960PE = 0x13,
+ MYRS_CTLR_DAC960PG = 0x14,
+ MYRS_CTLR_DAC960PJ = 0x15,
+ MYRS_CTLR_DAC960PTL0 = 0x16,
+ MYRS_CTLR_DAC960PR = 0x17,
+ MYRS_CTLR_DAC960PRL = 0x18,
+ MYRS_CTLR_DAC960PT = 0x19,
+ MYRS_CTLR_DAC1164P = 0x1A,
+ MYRS_CTLR_DAC960PTL1 = 0x1B,
+ MYRS_CTLR_EXR2000P = 0x1C,
+ MYRS_CTLR_EXR3000P = 0x1D,
+ MYRS_CTLR_ACCELERAID352 = 0x1E,
+ MYRS_CTLR_ACCELERAID170 = 0x1F,
+ MYRS_CTLR_ACCELERAID160 = 0x20,
+ MYRS_CTLR_DAC960S = 0x60,
+ MYRS_CTLR_DAC960SU = 0x61,
+ MYRS_CTLR_DAC960SX = 0x62,
+ MYRS_CTLR_DAC960SF = 0x63,
+ MYRS_CTLR_DAC960SS = 0x64,
+ MYRS_CTLR_DAC960FL = 0x65,
+ MYRS_CTLR_DAC960LL = 0x66,
+ MYRS_CTLR_DAC960FF = 0x67,
+ MYRS_CTLR_DAC960HP = 0x68,
+ MYRS_CTLR_RAIDBRICK = 0x69,
+ MYRS_CTLR_METEOR_FL = 0x6A,
+ MYRS_CTLR_METEOR_FF = 0x6B
+ } __packed ctlr_type; /* Byte 2 */
+ unsigned char rsvd2; /* Byte 3 */
+ unsigned short bus_speed_mhz; /* Bytes 4-5 */
+ unsigned char bus_width; /* Byte 6 */
+ unsigned char flash_code; /* Byte 7 */
+ unsigned char ports_present; /* Byte 8 */
+ unsigned char rsvd3[7]; /* Bytes 9-15 */
+ unsigned char bus_name[16]; /* Bytes 16-31 */
+ unsigned char ctlr_name[16]; /* Bytes 32-47 */
+ unsigned char rsvd4[16]; /* Bytes 48-63 */
+ /* Firmware Release Information */
+ unsigned char fw_major_version; /* Byte 64 */
+ unsigned char fw_minor_version; /* Byte 65 */
+ unsigned char fw_turn_number; /* Byte 66 */
+ unsigned char fw_build_number; /* Byte 67 */
+ unsigned char fw_release_day; /* Byte 68 */
+ unsigned char fw_release_month; /* Byte 69 */
+ unsigned char fw_release_year_hi; /* Byte 70 */
+ unsigned char fw_release_year_lo; /* Byte 71 */
+ /* Hardware Release Information */
+ unsigned char hw_rev; /* Byte 72 */
+ unsigned char rsvd5[3]; /* Bytes 73-75 */
+ unsigned char hw_release_day; /* Byte 76 */
+ unsigned char hw_release_month; /* Byte 77 */
+ unsigned char hw_release_year_hi; /* Byte 78 */
+ unsigned char hw_release_year_lo; /* Byte 79 */
+ /* Hardware Manufacturing Information */
+ unsigned char manuf_batch_num; /* Byte 80 */
+ unsigned char rsvd6; /* Byte 81 */
+ unsigned char manuf_plant_num; /* Byte 82 */
+ unsigned char rsvd7; /* Byte 83 */
+ unsigned char hw_manuf_day; /* Byte 84 */
+ unsigned char hw_manuf_month; /* Byte 85 */
+ unsigned char hw_manuf_year_hi; /* Byte 86 */
+ unsigned char hw_manuf_year_lo; /* Byte 87 */
+ unsigned char max_pd_per_xld; /* Byte 88 */
+ unsigned char max_ild_per_xld; /* Byte 89 */
+ unsigned short nvram_size_kb; /* Bytes 90-91 */
+ unsigned char max_xld; /* Byte 92 */
+ unsigned char rsvd8[3]; /* Bytes 93-95 */
+ /* Unique Information per Controller */
+ unsigned char serial_number[16]; /* Bytes 96-111 */
+ unsigned char rsvd9[16]; /* Bytes 112-127 */
+ /* Vendor Information */
+ unsigned char rsvd10[3]; /* Bytes 128-130 */
+ unsigned char oem_code; /* Byte 131 */
+ unsigned char vendor[16]; /* Bytes 132-147 */
+ /* Other Physical/Controller/Operation Information */
+ unsigned char bbu_present:1; /* Byte 148 Bit 0 */
+ unsigned char cluster_mode:1; /* Byte 148 Bit 1 */
+ unsigned char rsvd11:6; /* Byte 148 Bits 2-7 */
+ unsigned char rsvd12[3]; /* Bytes 149-151 */
+ /* Physical Device Scan Information */
+ unsigned char pscan_active:1; /* Byte 152 Bit 0 */
+ unsigned char rsvd13:7; /* Byte 152 Bits 1-7 */
+ unsigned char pscan_chan; /* Byte 153 */
+ unsigned char pscan_target; /* Byte 154 */
+ unsigned char pscan_lun; /* Byte 155 */
+ /* Maximum Command Data Transfer Sizes */
+ unsigned short max_transfer_size; /* Bytes 156-157 */
+ unsigned short max_sge; /* Bytes 158-159 */
+ /* Logical/Physical Device Counts */
+ unsigned short ldev_present; /* Bytes 160-161 */
+ unsigned short ldev_critical; /* Bytes 162-163 */
+ unsigned short ldev_offline; /* Bytes 164-165 */
+ unsigned short pdev_present; /* Bytes 166-167 */
+ unsigned short pdisk_present; /* Bytes 168-169 */
+ unsigned short pdisk_critical; /* Bytes 170-171 */
+ unsigned short pdisk_offline; /* Bytes 172-173 */
+ unsigned short max_tcq; /* Bytes 174-175 */
+ /* Channel and Target ID Information */
+ unsigned char physchan_present; /* Byte 176 */
+ unsigned char virtchan_present; /* Byte 177 */
+ unsigned char physchan_max; /* Byte 178 */
+ unsigned char virtchan_max; /* Byte 179 */
+ unsigned char max_targets[16]; /* Bytes 180-195 */
+ unsigned char rsvd14[12]; /* Bytes 196-207 */
+ /* Memory/Cache Information */
+ unsigned short mem_size_mb; /* Bytes 208-209 */
+ unsigned short cache_size_mb; /* Bytes 210-211 */
+ unsigned int valid_cache_bytes; /* Bytes 212-215 */
+ unsigned int dirty_cache_bytes; /* Bytes 216-219 */
+ unsigned short mem_speed_mhz; /* Bytes 220-221 */
+ unsigned char mem_data_width; /* Byte 222 */
+ struct myrs_mem_type mem_type; /* Byte 223 */
+ unsigned char cache_mem_type_name[16]; /* Bytes 224-239 */
+ /* Execution Memory Information */
+ unsigned short exec_mem_size_mb; /* Bytes 240-241 */
+ unsigned short exec_l2_cache_size_mb; /* Bytes 242-243 */
+ unsigned char rsvd15[8]; /* Bytes 244-251 */
+ unsigned short exec_mem_speed_mhz; /* Bytes 252-253 */
+ unsigned char exec_mem_data_width; /* Byte 254 */
+ struct myrs_mem_type exec_mem_type; /* Byte 255 */
+ unsigned char exec_mem_type_name[16]; /* Bytes 256-271 */
+ /* CPU Type Information */
+ struct { /* Bytes 272-335 */
+ unsigned short cpu_speed_mhz;
+ enum myrs_cpu_type cpu_type;
+ unsigned char cpu_count;
+ unsigned char rsvd16[12];
+ unsigned char cpu_name[16];
+ } __packed cpu[2];
+ /* Debugging/Profiling/Command Time Tracing Information */
+ unsigned short cur_prof_page_num; /* Bytes 336-337 */
+ unsigned short num_prof_waiters; /* Bytes 338-339 */
+ unsigned short cur_trace_page_num; /* Bytes 340-341 */
+ unsigned short num_trace_waiters; /* Bytes 342-343 */
+ unsigned char rsvd18[8]; /* Bytes 344-351 */
+ /* Error Counters on Physical Devices */
+ unsigned short pdev_bus_resets; /* Bytes 352-353 */
+ unsigned short pdev_parity_errors; /* Bytes 355-355 */
+ unsigned short pdev_soft_errors; /* Bytes 356-357 */
+ unsigned short pdev_cmds_failed; /* Bytes 358-359 */
+ unsigned short pdev_misc_errors; /* Bytes 360-361 */
+ unsigned short pdev_cmd_timeouts; /* Bytes 362-363 */
+ unsigned short pdev_sel_timeouts; /* Bytes 364-365 */
+ unsigned short pdev_retries_done; /* Bytes 366-367 */
+ unsigned short pdev_aborts_done; /* Bytes 368-369 */
+ unsigned short pdev_host_aborts_done; /* Bytes 370-371 */
+ unsigned short pdev_predicted_failures; /* Bytes 372-373 */
+ unsigned short pdev_host_cmds_failed; /* Bytes 374-375 */
+ unsigned short pdev_hard_errors; /* Bytes 376-377 */
+ unsigned char rsvd19[6]; /* Bytes 378-383 */
+ /* Error Counters on Logical Devices */
+ unsigned short ldev_soft_errors; /* Bytes 384-385 */
+ unsigned short ldev_cmds_failed; /* Bytes 386-387 */
+ unsigned short ldev_host_aborts_done; /* Bytes 388-389 */
+ unsigned char rsvd20[2]; /* Bytes 390-391 */
+ /* Error Counters on Controller */
+ unsigned short ctlr_mem_errors; /* Bytes 392-393 */
+ unsigned short ctlr_host_aborts_done; /* Bytes 394-395 */
+ unsigned char rsvd21[4]; /* Bytes 396-399 */
+ /* Long Duration Activity Information */
+ unsigned short bg_init_active; /* Bytes 400-401 */
+ unsigned short ldev_init_active; /* Bytes 402-403 */
+ unsigned short pdev_init_active; /* Bytes 404-405 */
+ unsigned short cc_active; /* Bytes 406-407 */
+ unsigned short rbld_active; /* Bytes 408-409 */
+ unsigned short exp_active; /* Bytes 410-411 */
+ unsigned short patrol_active; /* Bytes 412-413 */
+ unsigned char rsvd22[2]; /* Bytes 414-415 */
+ /* Flash ROM Information */
+ unsigned char flash_type; /* Byte 416 */
+ unsigned char rsvd23; /* Byte 417 */
+ unsigned short flash_size_MB; /* Bytes 418-419 */
+ unsigned int flash_limit; /* Bytes 420-423 */
+ unsigned int flash_count; /* Bytes 424-427 */
+ unsigned char rsvd24[4]; /* Bytes 428-431 */
+ unsigned char flash_type_name[16]; /* Bytes 432-447 */
+ /* Firmware Run Time Information */
+ unsigned char rbld_rate; /* Byte 448 */
+ unsigned char bg_init_rate; /* Byte 449 */
+ unsigned char fg_init_rate; /* Byte 450 */
+ unsigned char cc_rate; /* Byte 451 */
+ unsigned char rsvd25[4]; /* Bytes 452-455 */
+ unsigned int max_dp; /* Bytes 456-459 */
+ unsigned int free_dp; /* Bytes 460-463 */
+ unsigned int max_iop; /* Bytes 464-467 */
+ unsigned int free_iop; /* Bytes 468-471 */
+ unsigned short max_combined_len; /* Bytes 472-473 */
+ unsigned short num_cfg_groups; /* Bytes 474-475 */
+ unsigned installation_abort_status:1; /* Byte 476 Bit 0 */
+ unsigned maint_mode_status:1; /* Byte 476 Bit 1 */
+ unsigned rsvd26:6; /* Byte 476 Bits 2-7 */
+ unsigned char rsvd27[6]; /* Bytes 477-511 */
+ unsigned char rsvd28[512]; /* Bytes 512-1023 */
+};
+
+/*
+ * DAC960 V2 Firmware Device State type.
+ */
+enum myrs_devstate {
+ MYRS_DEVICE_UNCONFIGURED = 0x00,
+ MYRS_DEVICE_ONLINE = 0x01,
+ MYRS_DEVICE_REBUILD = 0x03,
+ MYRS_DEVICE_MISSING = 0x04,
+ MYRS_DEVICE_SUSPECTED_CRITICAL = 0x05,
+ MYRS_DEVICE_OFFLINE = 0x08,
+ MYRS_DEVICE_CRITICAL = 0x09,
+ MYRS_DEVICE_SUSPECTED_DEAD = 0x0C,
+ MYRS_DEVICE_COMMANDED_OFFLINE = 0x10,
+ MYRS_DEVICE_STANDBY = 0x21,
+ MYRS_DEVICE_INVALID_STATE = 0xFF,
+} __packed;
+
+/*
+ * DAC960 V2 RAID Levels
+ */
+enum myrs_raid_level {
+ MYRS_RAID_LEVEL0 = 0x0, /* RAID 0 */
+ MYRS_RAID_LEVEL1 = 0x1, /* RAID 1 */
+ MYRS_RAID_LEVEL3 = 0x3, /* RAID 3 right asymmetric parity */
+ MYRS_RAID_LEVEL5 = 0x5, /* RAID 5 right asymmetric parity */
+ MYRS_RAID_LEVEL6 = 0x6, /* RAID 6 (Mylex RAID 6) */
+ MYRS_RAID_JBOD = 0x7, /* RAID 7 (JBOD) */
+ MYRS_RAID_NEWSPAN = 0x8, /* New Mylex SPAN */
+ MYRS_RAID_LEVEL3F = 0x9, /* RAID 3 fixed parity */
+ MYRS_RAID_LEVEL3L = 0xb, /* RAID 3 left symmetric parity */
+ MYRS_RAID_SPAN = 0xc, /* current spanning implementation */
+ MYRS_RAID_LEVEL5L = 0xd, /* RAID 5 left symmetric parity */
+ MYRS_RAID_LEVELE = 0xe, /* RAID E (concatenation) */
+ MYRS_RAID_PHYSICAL = 0xf, /* physical device */
+} __packed;
+
+enum myrs_stripe_size {
+ MYRS_STRIPE_SIZE_0 = 0x0, /* no stripe (RAID 1, RAID 7, etc) */
+ MYRS_STRIPE_SIZE_512B = 0x1,
+ MYRS_STRIPE_SIZE_1K = 0x2,
+ MYRS_STRIPE_SIZE_2K = 0x3,
+ MYRS_STRIPE_SIZE_4K = 0x4,
+ MYRS_STRIPE_SIZE_8K = 0x5,
+ MYRS_STRIPE_SIZE_16K = 0x6,
+ MYRS_STRIPE_SIZE_32K = 0x7,
+ MYRS_STRIPE_SIZE_64K = 0x8,
+ MYRS_STRIPE_SIZE_128K = 0x9,
+ MYRS_STRIPE_SIZE_256K = 0xa,
+ MYRS_STRIPE_SIZE_512K = 0xb,
+ MYRS_STRIPE_SIZE_1M = 0xc,
+} __packed;
+
+enum myrs_cacheline_size {
+ MYRS_CACHELINE_ZERO = 0x0, /* caching cannot be enabled */
+ MYRS_CACHELINE_512B = 0x1,
+ MYRS_CACHELINE_1K = 0x2,
+ MYRS_CACHELINE_2K = 0x3,
+ MYRS_CACHELINE_4K = 0x4,
+ MYRS_CACHELINE_8K = 0x5,
+ MYRS_CACHELINE_16K = 0x6,
+ MYRS_CACHELINE_32K = 0x7,
+ MYRS_CACHELINE_64K = 0x8,
+} __packed;
+
+/*
+ * DAC960 V2 Firmware Get Logical Device Info reply structure.
+ */
+struct myrs_ldev_info {
+ unsigned char ctlr; /* Byte 0 */
+ unsigned char channel; /* Byte 1 */
+ unsigned char target; /* Byte 2 */
+ unsigned char lun; /* Byte 3 */
+ enum myrs_devstate dev_state; /* Byte 4 */
+ unsigned char raid_level; /* Byte 5 */
+ enum myrs_stripe_size stripe_size; /* Byte 6 */
+ enum myrs_cacheline_size cacheline_size; /* Byte 7 */
+ struct {
+ enum {
+ MYRS_READCACHE_DISABLED = 0x0,
+ MYRS_READCACHE_ENABLED = 0x1,
+ MYRS_READAHEAD_ENABLED = 0x2,
+ MYRS_INTELLIGENT_READAHEAD_ENABLED = 0x3,
+ MYRS_READCACHE_LAST = 0x7,
+ } __packed rce:3; /* Byte 8 Bits 0-2 */
+ enum {
+ MYRS_WRITECACHE_DISABLED = 0x0,
+ MYRS_LOGICALDEVICE_RO = 0x1,
+ MYRS_WRITECACHE_ENABLED = 0x2,
+ MYRS_INTELLIGENT_WRITECACHE_ENABLED = 0x3,
+ MYRS_WRITECACHE_LAST = 0x7,
+ } __packed wce:3; /* Byte 8 Bits 3-5 */
+ unsigned rsvd1:1; /* Byte 8 Bit 6 */
+ unsigned ldev_init_done:1; /* Byte 8 Bit 7 */
+ } ldev_control; /* Byte 8 */
+ /* Logical Device Operations Status */
+ unsigned char cc_active:1; /* Byte 9 Bit 0 */
+ unsigned char rbld_active:1; /* Byte 9 Bit 1 */
+ unsigned char bg_init_active:1; /* Byte 9 Bit 2 */
+ unsigned char fg_init_active:1; /* Byte 9 Bit 3 */
+ unsigned char migration_active:1; /* Byte 9 Bit 4 */
+ unsigned char patrol_active:1; /* Byte 9 Bit 5 */
+ unsigned char rsvd2:2; /* Byte 9 Bits 6-7 */
+ unsigned char raid5_writeupdate; /* Byte 10 */
+ unsigned char raid5_algo; /* Byte 11 */
+ unsigned short ldev_num; /* Bytes 12-13 */
+ /* BIOS Info */
+ unsigned char bios_disabled:1; /* Byte 14 Bit 0 */
+ unsigned char cdrom_boot:1; /* Byte 14 Bit 1 */
+ unsigned char drv_coercion:1; /* Byte 14 Bit 2 */
+ unsigned char write_same_disabled:1; /* Byte 14 Bit 3 */
+ unsigned char hba_mode:1; /* Byte 14 Bit 4 */
+ enum {
+ MYRS_GEOMETRY_128_32 = 0x0,
+ MYRS_GEOMETRY_255_63 = 0x1,
+ MYRS_GEOMETRY_RSVD1 = 0x2,
+ MYRS_GEOMETRY_RSVD2 = 0x3
+ } __packed drv_geom:2; /* Byte 14 Bits 5-6 */
+ unsigned char super_ra_enabled:1; /* Byte 14 Bit 7 */
+ unsigned char rsvd3; /* Byte 15 */
+ /* Error Counters */
+ unsigned short soft_errs; /* Bytes 16-17 */
+ unsigned short cmds_failed; /* Bytes 18-19 */
+ unsigned short cmds_aborted; /* Bytes 20-21 */
+ unsigned short deferred_write_errs; /* Bytes 22-23 */
+ unsigned int rsvd4; /* Bytes 24-27 */
+ unsigned int rsvd5; /* Bytes 28-31 */
+ /* Device Size Information */
+ unsigned short rsvd6; /* Bytes 32-33 */
+ unsigned short devsize_bytes; /* Bytes 34-35 */
+ unsigned int orig_devsize; /* Bytes 36-39 */
+ unsigned int cfg_devsize; /* Bytes 40-43 */
+ unsigned int rsvd7; /* Bytes 44-47 */
+ unsigned char ldev_name[32]; /* Bytes 48-79 */
+ unsigned char inquiry[36]; /* Bytes 80-115 */
+ unsigned char rsvd8[12]; /* Bytes 116-127 */
+ u64 last_read_lba; /* Bytes 128-135 */
+ u64 last_write_lba; /* Bytes 136-143 */
+ u64 cc_lba; /* Bytes 144-151 */
+ u64 rbld_lba; /* Bytes 152-159 */
+ u64 bg_init_lba; /* Bytes 160-167 */
+ u64 fg_init_lba; /* Bytes 168-175 */
+ u64 migration_lba; /* Bytes 176-183 */
+ u64 patrol_lba; /* Bytes 184-191 */
+ unsigned char rsvd9[64]; /* Bytes 192-255 */
+};
+
+/*
+ * DAC960 V2 Firmware Get Physical Device Info reply structure.
+ */
+struct myrs_pdev_info {
+ unsigned char rsvd1; /* Byte 0 */
+ unsigned char channel; /* Byte 1 */
+ unsigned char target; /* Byte 2 */
+ unsigned char lun; /* Byte 3 */
+ /* Configuration Status Bits */
+ unsigned char pdev_fault_tolerant:1; /* Byte 4 Bit 0 */
+ unsigned char pdev_connected:1; /* Byte 4 Bit 1 */
+ unsigned char pdev_local_to_ctlr:1; /* Byte 4 Bit 2 */
+ unsigned char rsvd2:5; /* Byte 4 Bits 3-7 */
+ /* Multiple Host/Controller Status Bits */
+ unsigned char remote_host_dead:1; /* Byte 5 Bit 0 */
+ unsigned char remove_ctlr_dead:1; /* Byte 5 Bit 1 */
+ unsigned char rsvd3:6; /* Byte 5 Bits 2-7 */
+ enum myrs_devstate dev_state; /* Byte 6 */
+ unsigned char nego_data_width; /* Byte 7 */
+ unsigned short nego_sync_rate; /* Bytes 8-9 */
+ /* Multiported Physical Device Information */
+ unsigned char num_ports; /* Byte 10 */
+ unsigned char drv_access_bitmap; /* Byte 11 */
+ unsigned int rsvd4; /* Bytes 12-15 */
+ unsigned char ip_address[16]; /* Bytes 16-31 */
+ unsigned short max_tags; /* Bytes 32-33 */
+ /* Physical Device Operations Status */
+ unsigned char cc_in_progress:1; /* Byte 34 Bit 0 */
+ unsigned char rbld_in_progress:1; /* Byte 34 Bit 1 */
+ unsigned char makecc_in_progress:1; /* Byte 34 Bit 2 */
+ unsigned char pdevinit_in_progress:1; /* Byte 34 Bit 3 */
+ unsigned char migration_in_progress:1; /* Byte 34 Bit 4 */
+ unsigned char patrol_in_progress:1; /* Byte 34 Bit 5 */
+ unsigned char rsvd5:2; /* Byte 34 Bits 6-7 */
+ unsigned char long_op_status; /* Byte 35 */
+ unsigned char parity_errs; /* Byte 36 */
+ unsigned char soft_errs; /* Byte 37 */
+ unsigned char hard_errs; /* Byte 38 */
+ unsigned char misc_errs; /* Byte 39 */
+ unsigned char cmd_timeouts; /* Byte 40 */
+ unsigned char retries; /* Byte 41 */
+ unsigned char aborts; /* Byte 42 */
+ unsigned char pred_failures; /* Byte 43 */
+ unsigned int rsvd6; /* Bytes 44-47 */
+ unsigned short rsvd7; /* Bytes 48-49 */
+ unsigned short devsize_bytes; /* Bytes 50-51 */
+ unsigned int orig_devsize; /* Bytes 52-55 */
+ unsigned int cfg_devsize; /* Bytes 56-59 */
+ unsigned int rsvd8; /* Bytes 60-63 */
+ unsigned char pdev_name[16]; /* Bytes 64-79 */
+ unsigned char rsvd9[16]; /* Bytes 80-95 */
+ unsigned char rsvd10[32]; /* Bytes 96-127 */
+ unsigned char inquiry[36]; /* Bytes 128-163 */
+ unsigned char rsvd11[20]; /* Bytes 164-183 */
+ unsigned char rsvd12[8]; /* Bytes 184-191 */
+ u64 last_read_lba; /* Bytes 192-199 */
+ u64 last_write_lba; /* Bytes 200-207 */
+ u64 cc_lba; /* Bytes 208-215 */
+ u64 rbld_lba; /* Bytes 216-223 */
+ u64 makecc_lba; /* Bytes 224-231 */
+ u64 devinit_lba; /* Bytes 232-239 */
+ u64 migration_lba; /* Bytes 240-247 */
+ u64 patrol_lba; /* Bytes 248-255 */
+ unsigned char rsvd13[256]; /* Bytes 256-511 */
+};
+
+/*
+ * DAC960 V2 Firmware Health Status Buffer structure.
+ */
+struct myrs_fwstat {
+ unsigned int uptime_usecs; /* Bytes 0-3 */
+ unsigned int uptime_msecs; /* Bytes 4-7 */
+ unsigned int seconds; /* Bytes 8-11 */
+ unsigned char rsvd1[4]; /* Bytes 12-15 */
+ unsigned int epoch; /* Bytes 16-19 */
+ unsigned char rsvd2[4]; /* Bytes 20-23 */
+ unsigned int dbg_msgbuf_idx; /* Bytes 24-27 */
+ unsigned int coded_msgbuf_idx; /* Bytes 28-31 */
+ unsigned int cur_timetrace_page; /* Bytes 32-35 */
+ unsigned int cur_prof_page; /* Bytes 36-39 */
+ unsigned int next_evseq; /* Bytes 40-43 */
+ unsigned char rsvd3[4]; /* Bytes 44-47 */
+ unsigned char rsvd4[16]; /* Bytes 48-63 */
+ unsigned char rsvd5[64]; /* Bytes 64-127 */
+};
+
+/*
+ * DAC960 V2 Firmware Get Event reply structure.
+ */
+struct myrs_event {
+ unsigned int ev_seq; /* Bytes 0-3 */
+ unsigned int ev_time; /* Bytes 4-7 */
+ unsigned int ev_code; /* Bytes 8-11 */
+ unsigned char rsvd1; /* Byte 12 */
+ unsigned char channel; /* Byte 13 */
+ unsigned char target; /* Byte 14 */
+ unsigned char lun; /* Byte 15 */
+ unsigned int rsvd2; /* Bytes 16-19 */
+ unsigned int ev_parm; /* Bytes 20-23 */
+ unsigned char sense_data[40]; /* Bytes 24-63 */
+};
+
+/*
+ * DAC960 V2 Firmware Command Control Bits structure.
+ */
+struct myrs_cmd_ctrl {
+ unsigned char fua:1; /* Byte 0 Bit 0 */
+ unsigned char disable_pgout:1; /* Byte 0 Bit 1 */
+ unsigned char rsvd1:1; /* Byte 0 Bit 2 */
+ unsigned char add_sge_mem:1; /* Byte 0 Bit 3 */
+ unsigned char dma_ctrl_to_host:1; /* Byte 0 Bit 4 */
+ unsigned char rsvd2:1; /* Byte 0 Bit 5 */
+ unsigned char no_autosense:1; /* Byte 0 Bit 6 */
+ unsigned char disc_prohibited:1; /* Byte 0 Bit 7 */
+};
+
+/*
+ * DAC960 V2 Firmware Command Timeout structure.
+ */
+struct myrs_cmd_tmo {
+ unsigned char tmo_val:6; /* Byte 0 Bits 0-5 */
+ enum {
+ MYRS_TMO_SCALE_SECONDS = 0,
+ MYRS_TMO_SCALE_MINUTES = 1,
+ MYRS_TMO_SCALE_HOURS = 2,
+ MYRS_TMO_SCALE_RESERVED = 3
+ } __packed tmo_scale:2; /* Byte 0 Bits 6-7 */
+};
+
+/*
+ * DAC960 V2 Firmware Physical Device structure.
+ */
+struct myrs_pdev {
+ unsigned char lun; /* Byte 0 */
+ unsigned char target; /* Byte 1 */
+ unsigned char channel:3; /* Byte 2 Bits 0-2 */
+ unsigned char ctlr:5; /* Byte 2 Bits 3-7 */
+} __packed;
+
+/*
+ * DAC960 V2 Firmware Logical Device structure.
+ */
+struct myrs_ldev {
+ unsigned short ldev_num; /* Bytes 0-1 */
+ unsigned char rsvd:3; /* Byte 2 Bits 0-2 */
+ unsigned char ctlr:5; /* Byte 2 Bits 3-7 */
+} __packed;
+
+/*
+ * DAC960 V2 Firmware Operation Device type.
+ */
+enum myrs_opdev {
+ MYRS_PHYSICAL_DEVICE = 0x00,
+ MYRS_RAID_DEVICE = 0x01,
+ MYRS_PHYSICAL_CHANNEL = 0x02,
+ MYRS_RAID_CHANNEL = 0x03,
+ MYRS_PHYSICAL_CONTROLLER = 0x04,
+ MYRS_RAID_CONTROLLER = 0x05,
+ MYRS_CONFIGURATION_GROUP = 0x10,
+ MYRS_ENCLOSURE = 0x11,
+} __packed;
+
+/*
+ * DAC960 V2 Firmware Translate Physical To Logical Device structure.
+ */
+struct myrs_devmap {
+ unsigned short ldev_num; /* Bytes 0-1 */
+ unsigned short rsvd; /* Bytes 2-3 */
+ unsigned char prev_boot_ctlr; /* Byte 4 */
+ unsigned char prev_boot_channel; /* Byte 5 */
+ unsigned char prev_boot_target; /* Byte 6 */
+ unsigned char prev_boot_lun; /* Byte 7 */
+};
+
+/*
+ * DAC960 V2 Firmware Scatter/Gather List Entry structure.
+ */
+struct myrs_sge {
+ u64 sge_addr; /* Bytes 0-7 */
+ u64 sge_count; /* Bytes 8-15 */
+};
+
+/*
+ * DAC960 V2 Firmware Data Transfer Memory Address structure.
+ */
+union myrs_sgl {
+ struct myrs_sge sge[2]; /* Bytes 0-31 */
+ struct {
+ unsigned short sge0_len; /* Bytes 0-1 */
+ unsigned short sge1_len; /* Bytes 2-3 */
+ unsigned short sge2_len; /* Bytes 4-5 */
+ unsigned short rsvd; /* Bytes 6-7 */
+ u64 sge0_addr; /* Bytes 8-15 */
+ u64 sge1_addr; /* Bytes 16-23 */
+ u64 sge2_addr; /* Bytes 24-31 */
+ } ext;
+};
+
+/*
+ * 64 Byte DAC960 V2 Firmware Command Mailbox structure.
+ */
+union myrs_cmd_mbox {
+ unsigned int words[16]; /* Words 0-15 */
+ struct {
+ unsigned short id; /* Bytes 0-1 */
+ enum myrs_cmd_opcode opcode; /* Byte 2 */
+ struct myrs_cmd_ctrl control; /* Byte 3 */
+ u32 dma_size:24; /* Bytes 4-6 */
+ unsigned char dma_num; /* Byte 7 */
+ u64 sense_addr; /* Bytes 8-15 */
+ unsigned int rsvd1:24; /* Bytes 16-18 */
+ struct myrs_cmd_tmo tmo; /* Byte 19 */
+ unsigned char sense_len; /* Byte 20 */
+ enum myrs_ioctl_opcode ioctl_opcode; /* Byte 21 */
+ unsigned char rsvd2[10]; /* Bytes 22-31 */
+ union myrs_sgl dma_addr; /* Bytes 32-63 */
+ } common;
+ struct {
+ unsigned short id; /* Bytes 0-1 */
+ enum myrs_cmd_opcode opcode; /* Byte 2 */
+ struct myrs_cmd_ctrl control; /* Byte 3 */
+ u32 dma_size; /* Bytes 4-7 */
+ u64 sense_addr; /* Bytes 8-15 */
+ struct myrs_pdev pdev; /* Bytes 16-18 */
+ struct myrs_cmd_tmo tmo; /* Byte 19 */
+ unsigned char sense_len; /* Byte 20 */
+ unsigned char cdb_len; /* Byte 21 */
+ unsigned char cdb[10]; /* Bytes 22-31 */
+ union myrs_sgl dma_addr; /* Bytes 32-63 */
+ } SCSI_10;
+ struct {
+ unsigned short id; /* Bytes 0-1 */
+ enum myrs_cmd_opcode opcode; /* Byte 2 */
+ struct myrs_cmd_ctrl control; /* Byte 3 */
+ u32 dma_size; /* Bytes 4-7 */
+ u64 sense_addr; /* Bytes 8-15 */
+ struct myrs_pdev pdev; /* Bytes 16-18 */
+ struct myrs_cmd_tmo tmo; /* Byte 19 */
+ unsigned char sense_len; /* Byte 20 */
+ unsigned char cdb_len; /* Byte 21 */
+ unsigned short rsvd; /* Bytes 22-23 */
+ u64 cdb_addr; /* Bytes 24-31 */
+ union myrs_sgl dma_addr; /* Bytes 32-63 */
+ } SCSI_255;
+ struct {
+ unsigned short id; /* Bytes 0-1 */
+ enum myrs_cmd_opcode opcode; /* Byte 2 */
+ struct myrs_cmd_ctrl control; /* Byte 3 */
+ u32 dma_size:24; /* Bytes 4-6 */
+ unsigned char dma_num; /* Byte 7 */
+ u64 sense_addr; /* Bytes 8-15 */
+ unsigned short rsvd1; /* Bytes 16-17 */
+ unsigned char ctlr_num; /* Byte 18 */
+ struct myrs_cmd_tmo tmo; /* Byte 19 */
+ unsigned char sense_len; /* Byte 20 */
+ enum myrs_ioctl_opcode ioctl_opcode; /* Byte 21 */
+ unsigned char rsvd2[10]; /* Bytes 22-31 */
+ union myrs_sgl dma_addr; /* Bytes 32-63 */
+ } ctlr_info;
+ struct {
+ unsigned short id; /* Bytes 0-1 */
+ enum myrs_cmd_opcode opcode; /* Byte 2 */
+ struct myrs_cmd_ctrl control; /* Byte 3 */
+ u32 dma_size:24; /* Bytes 4-6 */
+ unsigned char dma_num; /* Byte 7 */
+ u64 sense_addr; /* Bytes 8-15 */
+ struct myrs_ldev ldev; /* Bytes 16-18 */
+ struct myrs_cmd_tmo tmo; /* Byte 19 */
+ unsigned char sense_len; /* Byte 20 */
+ enum myrs_ioctl_opcode ioctl_opcode; /* Byte 21 */
+ unsigned char rsvd[10]; /* Bytes 22-31 */
+ union myrs_sgl dma_addr; /* Bytes 32-63 */
+ } ldev_info;
+ struct {
+ unsigned short id; /* Bytes 0-1 */
+ enum myrs_cmd_opcode opcode; /* Byte 2 */
+ struct myrs_cmd_ctrl control; /* Byte 3 */
+ u32 dma_size:24; /* Bytes 4-6 */
+ unsigned char dma_num; /* Byte 7 */
+ u64 sense_addr; /* Bytes 8-15 */
+ struct myrs_pdev pdev; /* Bytes 16-18 */
+ struct myrs_cmd_tmo tmo; /* Byte 19 */
+ unsigned char sense_len; /* Byte 20 */
+ enum myrs_ioctl_opcode ioctl_opcode; /* Byte 21 */
+ unsigned char rsvd[10]; /* Bytes 22-31 */
+ union myrs_sgl dma_addr; /* Bytes 32-63 */
+ } pdev_info;
+ struct {
+ unsigned short id; /* Bytes 0-1 */
+ enum myrs_cmd_opcode opcode; /* Byte 2 */
+ struct myrs_cmd_ctrl control; /* Byte 3 */
+ u32 dma_size:24; /* Bytes 4-6 */
+ unsigned char dma_num; /* Byte 7 */
+ u64 sense_addr; /* Bytes 8-15 */
+ unsigned short evnum_upper; /* Bytes 16-17 */
+ unsigned char ctlr_num; /* Byte 18 */
+ struct myrs_cmd_tmo tmo; /* Byte 19 */
+ unsigned char sense_len; /* Byte 20 */
+ enum myrs_ioctl_opcode ioctl_opcode; /* Byte 21 */
+ unsigned short evnum_lower; /* Bytes 22-23 */
+ unsigned char rsvd[8]; /* Bytes 24-31 */
+ union myrs_sgl dma_addr; /* Bytes 32-63 */
+ } get_event;
+ struct {
+ unsigned short id; /* Bytes 0-1 */
+ enum myrs_cmd_opcode opcode; /* Byte 2 */
+ struct myrs_cmd_ctrl control; /* Byte 3 */
+ u32 dma_size:24; /* Bytes 4-6 */
+ unsigned char dma_num; /* Byte 7 */
+ u64 sense_addr; /* Bytes 8-15 */
+ union {
+ struct myrs_ldev ldev; /* Bytes 16-18 */
+ struct myrs_pdev pdev; /* Bytes 16-18 */
+ };
+ struct myrs_cmd_tmo tmo; /* Byte 19 */
+ unsigned char sense_len; /* Byte 20 */
+ enum myrs_ioctl_opcode ioctl_opcode; /* Byte 21 */
+ enum myrs_devstate state; /* Byte 22 */
+ unsigned char rsvd[9]; /* Bytes 23-31 */
+ union myrs_sgl dma_addr; /* Bytes 32-63 */
+ } set_devstate;
+ struct {
+ unsigned short id; /* Bytes 0-1 */
+ enum myrs_cmd_opcode opcode; /* Byte 2 */
+ struct myrs_cmd_ctrl control; /* Byte 3 */
+ u32 dma_size:24; /* Bytes 4-6 */
+ unsigned char dma_num; /* Byte 7 */
+ u64 sense_addr; /* Bytes 8-15 */
+ struct myrs_ldev ldev; /* Bytes 16-18 */
+ struct myrs_cmd_tmo tmo; /* Byte 19 */
+ unsigned char sense_len; /* Byte 20 */
+ enum myrs_ioctl_opcode ioctl_opcode; /* Byte 21 */
+ unsigned char restore_consistency:1; /* Byte 22 Bit 0 */
+ unsigned char initialized_area_only:1; /* Byte 22 Bit 1 */
+ unsigned char rsvd1:6; /* Byte 22 Bits 2-7 */
+ unsigned char rsvd2[9]; /* Bytes 23-31 */
+ union myrs_sgl dma_addr; /* Bytes 32-63 */
+ } cc;
+ struct {
+ unsigned short id; /* Bytes 0-1 */
+ enum myrs_cmd_opcode opcode; /* Byte 2 */
+ struct myrs_cmd_ctrl control; /* Byte 3 */
+ unsigned char first_cmd_mbox_size_kb; /* Byte 4 */
+ unsigned char first_stat_mbox_size_kb; /* Byte 5 */
+ unsigned char second_cmd_mbox_size_kb; /* Byte 6 */
+ unsigned char second_stat_mbox_size_kb; /* Byte 7 */
+ u64 sense_addr; /* Bytes 8-15 */
+ unsigned int rsvd1:24; /* Bytes 16-18 */
+ struct myrs_cmd_tmo tmo; /* Byte 19 */
+ unsigned char sense_len; /* Byte 20 */
+ enum myrs_ioctl_opcode ioctl_opcode; /* Byte 21 */
+ unsigned char fwstat_buf_size_kb; /* Byte 22 */
+ unsigned char rsvd2; /* Byte 23 */
+ u64 fwstat_buf_addr; /* Bytes 24-31 */
+ u64 first_cmd_mbox_addr; /* Bytes 32-39 */
+ u64 first_stat_mbox_addr; /* Bytes 40-47 */
+ u64 second_cmd_mbox_addr; /* Bytes 48-55 */
+ u64 second_stat_mbox_addr; /* Bytes 56-63 */
+ } set_mbox;
+ struct {
+ unsigned short id; /* Bytes 0-1 */
+ enum myrs_cmd_opcode opcode; /* Byte 2 */
+ struct myrs_cmd_ctrl control; /* Byte 3 */
+ u32 dma_size:24; /* Bytes 4-6 */
+ unsigned char dma_num; /* Byte 7 */
+ u64 sense_addr; /* Bytes 8-15 */
+ struct myrs_pdev pdev; /* Bytes 16-18 */
+ struct myrs_cmd_tmo tmo; /* Byte 19 */
+ unsigned char sense_len; /* Byte 20 */
+ enum myrs_ioctl_opcode ioctl_opcode; /* Byte 21 */
+ enum myrs_opdev opdev; /* Byte 22 */
+ unsigned char rsvd[9]; /* Bytes 23-31 */
+ union myrs_sgl dma_addr; /* Bytes 32-63 */
+ } dev_op;
+};
+
+/*
+ * DAC960 V2 Firmware Controller Status Mailbox structure.
+ */
+struct myrs_stat_mbox {
+ unsigned short id; /* Bytes 0-1 */
+ unsigned char status; /* Byte 2 */
+ unsigned char sense_len; /* Byte 3 */
+ int residual; /* Bytes 4-7 */
+};
+
+struct myrs_cmdblk {
+ union myrs_cmd_mbox mbox;
+ unsigned char status;
+ unsigned char sense_len;
+ int residual;
+ struct completion *complete;
+ struct myrs_sge *sgl;
+ dma_addr_t sgl_addr;
+ unsigned char *dcdb;
+ dma_addr_t dcdb_dma;
+ unsigned char *sense;
+ dma_addr_t sense_addr;
+};
+
+/*
+ * DAC960 Driver Controller structure.
+ */
+struct myrs_hba {
+ void __iomem *io_base;
+ void __iomem *mmio_base;
+ phys_addr_t io_addr;
+ phys_addr_t pci_addr;
+ unsigned int irq;
+
+ unsigned char model_name[28];
+ unsigned char fw_version[12];
+
+ struct Scsi_Host *host;
+ struct pci_dev *pdev;
+
+ unsigned int epoch;
+ unsigned int next_evseq;
+ /* Monitor flags */
+ bool needs_update;
+ bool disable_enc_msg;
+
+ struct workqueue_struct *work_q;
+ char work_q_name[20];
+ struct delayed_work monitor_work;
+ unsigned long primary_monitor_time;
+ unsigned long secondary_monitor_time;
+
+ spinlock_t queue_lock;
+
+ struct dma_pool *sg_pool;
+ struct dma_pool *sense_pool;
+ struct dma_pool *dcdb_pool;
+
+ void (*write_cmd_mbox)(union myrs_cmd_mbox *next_mbox,
+ union myrs_cmd_mbox *cmd_mbox);
+ void (*get_cmd_mbox)(void __iomem *base);
+ void (*disable_intr)(void __iomem *base);
+ void (*reset)(void __iomem *base);
+
+ dma_addr_t cmd_mbox_addr;
+ size_t cmd_mbox_size;
+ union myrs_cmd_mbox *first_cmd_mbox;
+ union myrs_cmd_mbox *last_cmd_mbox;
+ union myrs_cmd_mbox *next_cmd_mbox;
+ union myrs_cmd_mbox *prev_cmd_mbox1;
+ union myrs_cmd_mbox *prev_cmd_mbox2;
+
+ dma_addr_t stat_mbox_addr;
+ size_t stat_mbox_size;
+ struct myrs_stat_mbox *first_stat_mbox;
+ struct myrs_stat_mbox *last_stat_mbox;
+ struct myrs_stat_mbox *next_stat_mbox;
+
+ struct myrs_cmdblk dcmd_blk;
+ struct myrs_cmdblk mcmd_blk;
+ struct mutex dcmd_mutex;
+
+ struct myrs_fwstat *fwstat_buf;
+ dma_addr_t fwstat_addr;
+
+ struct myrs_ctlr_info *ctlr_info;
+ struct mutex cinfo_mutex;
+
+ struct myrs_event *event_buf;
+};
+
+typedef unsigned char (*enable_mbox_t)(void __iomem *base, dma_addr_t addr);
+typedef int (*myrs_hwinit_t)(struct pci_dev *pdev,
+ struct myrs_hba *c, void __iomem *base);
+
+struct myrs_privdata {
+ myrs_hwinit_t hw_init;
+ irq_handler_t irq_handler;
+ unsigned int mmio_size;
+};
+
+/*
+ * DAC960 GEM Series Controller Interface Register Offsets.
+ */
+
+#define DAC960_GEM_mmio_size 0x600
+
+enum DAC960_GEM_reg_offset {
+ DAC960_GEM_IDB_READ_OFFSET = 0x214,
+ DAC960_GEM_IDB_CLEAR_OFFSET = 0x218,
+ DAC960_GEM_ODB_READ_OFFSET = 0x224,
+ DAC960_GEM_ODB_CLEAR_OFFSET = 0x228,
+ DAC960_GEM_IRQSTS_OFFSET = 0x208,
+ DAC960_GEM_IRQMASK_READ_OFFSET = 0x22C,
+ DAC960_GEM_IRQMASK_CLEAR_OFFSET = 0x230,
+ DAC960_GEM_CMDMBX_OFFSET = 0x510,
+ DAC960_GEM_CMDSTS_OFFSET = 0x518,
+ DAC960_GEM_ERRSTS_READ_OFFSET = 0x224,
+ DAC960_GEM_ERRSTS_CLEAR_OFFSET = 0x228,
+};
+
+/*
+ * DAC960 GEM Series Inbound Door Bell Register.
+ */
+#define DAC960_GEM_IDB_HWMBOX_NEW_CMD 0x01
+#define DAC960_GEM_IDB_HWMBOX_ACK_STS 0x02
+#define DAC960_GEM_IDB_GEN_IRQ 0x04
+#define DAC960_GEM_IDB_CTRL_RESET 0x08
+#define DAC960_GEM_IDB_MMBOX_NEW_CMD 0x10
+
+#define DAC960_GEM_IDB_HWMBOX_FULL 0x01
+#define DAC960_GEM_IDB_INIT_IN_PROGRESS 0x02
+
+/*
+ * DAC960 GEM Series Outbound Door Bell Register.
+ */
+#define DAC960_GEM_ODB_HWMBOX_ACK_IRQ 0x01
+#define DAC960_GEM_ODB_MMBOX_ACK_IRQ 0x02
+#define DAC960_GEM_ODB_HWMBOX_STS_AVAIL 0x01
+#define DAC960_GEM_ODB_MMBOX_STS_AVAIL 0x02
+
+/*
+ * DAC960 GEM Series Interrupt Mask Register.
+ */
+#define DAC960_GEM_IRQMASK_HWMBOX_IRQ 0x01
+#define DAC960_GEM_IRQMASK_MMBOX_IRQ 0x02
+
+/*
+ * DAC960 GEM Series Error Status Register.
+ */
+#define DAC960_GEM_ERRSTS_PENDING 0x20
+
+/*
+ * dma_addr_writeql is provided to write dma_addr_t types
+ * to a 64-bit pci address space register. The controller
+ * will accept having the register written as two 32-bit
+ * values.
+ *
+ * In HIGHMEM kernels, dma_addr_t is a 64-bit value.
+ * without HIGHMEM, dma_addr_t is a 32-bit value.
+ *
+ * The compiler should always fix up the assignment
+ * to u.wq appropriately, depending upon the size of
+ * dma_addr_t.
+ */
+static inline
+void dma_addr_writeql(dma_addr_t addr, void __iomem *write_address)
+{
+ union {
+ u64 wq;
+ uint wl[2];
+ } u;
+
+ u.wq = addr;
+
+ writel(u.wl[0], write_address);
+ writel(u.wl[1], write_address + 4);
+}
+
+/*
+ * DAC960 BA Series Controller Interface Register Offsets.
+ */
+
+#define DAC960_BA_mmio_size 0x80
+
+enum DAC960_BA_reg_offset {
+ DAC960_BA_IRQSTS_OFFSET = 0x30,
+ DAC960_BA_IRQMASK_OFFSET = 0x34,
+ DAC960_BA_CMDMBX_OFFSET = 0x50,
+ DAC960_BA_CMDSTS_OFFSET = 0x58,
+ DAC960_BA_IDB_OFFSET = 0x60,
+ DAC960_BA_ODB_OFFSET = 0x61,
+ DAC960_BA_ERRSTS_OFFSET = 0x63,
+};
+
+/*
+ * DAC960 BA Series Inbound Door Bell Register.
+ */
+#define DAC960_BA_IDB_HWMBOX_NEW_CMD 0x01
+#define DAC960_BA_IDB_HWMBOX_ACK_STS 0x02
+#define DAC960_BA_IDB_GEN_IRQ 0x04
+#define DAC960_BA_IDB_CTRL_RESET 0x08
+#define DAC960_BA_IDB_MMBOX_NEW_CMD 0x10
+
+#define DAC960_BA_IDB_HWMBOX_EMPTY 0x01
+#define DAC960_BA_IDB_INIT_DONE 0x02
+
+/*
+ * DAC960 BA Series Outbound Door Bell Register.
+ */
+#define DAC960_BA_ODB_HWMBOX_ACK_IRQ 0x01
+#define DAC960_BA_ODB_MMBOX_ACK_IRQ 0x02
+
+#define DAC960_BA_ODB_HWMBOX_STS_AVAIL 0x01
+#define DAC960_BA_ODB_MMBOX_STS_AVAIL 0x02
+
+/*
+ * DAC960 BA Series Interrupt Mask Register.
+ */
+#define DAC960_BA_IRQMASK_DISABLE_IRQ 0x04
+#define DAC960_BA_IRQMASK_DISABLEW_I2O 0x08
+
+/*
+ * DAC960 BA Series Error Status Register.
+ */
+#define DAC960_BA_ERRSTS_PENDING 0x04
+
+/*
+ * DAC960 LP Series Controller Interface Register Offsets.
+ */
+
+#define DAC960_LP_mmio_size 0x80
+
+enum DAC960_LP_reg_offset {
+ DAC960_LP_CMDMBX_OFFSET = 0x10,
+ DAC960_LP_CMDSTS_OFFSET = 0x18,
+ DAC960_LP_IDB_OFFSET = 0x20,
+ DAC960_LP_ODB_OFFSET = 0x2C,
+ DAC960_LP_ERRSTS_OFFSET = 0x2E,
+ DAC960_LP_IRQSTS_OFFSET = 0x30,
+ DAC960_LP_IRQMASK_OFFSET = 0x34,
+};
+
+/*
+ * DAC960 LP Series Inbound Door Bell Register.
+ */
+#define DAC960_LP_IDB_HWMBOX_NEW_CMD 0x01
+#define DAC960_LP_IDB_HWMBOX_ACK_STS 0x02
+#define DAC960_LP_IDB_GEN_IRQ 0x04
+#define DAC960_LP_IDB_CTRL_RESET 0x08
+#define DAC960_LP_IDB_MMBOX_NEW_CMD 0x10
+
+#define DAC960_LP_IDB_HWMBOX_FULL 0x01
+#define DAC960_LP_IDB_INIT_IN_PROGRESS 0x02
+
+/*
+ * DAC960 LP Series Outbound Door Bell Register.
+ */
+#define DAC960_LP_ODB_HWMBOX_ACK_IRQ 0x01
+#define DAC960_LP_ODB_MMBOX_ACK_IRQ 0x02
+
+#define DAC960_LP_ODB_HWMBOX_STS_AVAIL 0x01
+#define DAC960_LP_ODB_MMBOX_STS_AVAIL 0x02
+
+/*
+ * DAC960 LP Series Interrupt Mask Register.
+ */
+#define DAC960_LP_IRQMASK_DISABLE_IRQ 0x04
+
+/*
+ * DAC960 LP Series Error Status Register.
+ */
+#define DAC960_LP_ERRSTS_PENDING 0x04
+
+#endif /* _MYRS_H */
diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c
index 8620ac5d6e41..5aac3e801903 100644
--- a/drivers/scsi/nsp32.c
+++ b/drivers/scsi/nsp32.c
@@ -2638,7 +2638,7 @@ static int nsp32_detect(struct pci_dev *pdev)
/*
* setup DMA
*/
- if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) {
+ if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)) != 0) {
nsp32_msg (KERN_ERR, "failed to set PCI DMA mask");
goto scsi_unregister;
}
@@ -2646,7 +2646,9 @@ static int nsp32_detect(struct pci_dev *pdev)
/*
* allocate autoparam DMA resource.
*/
- data->autoparam = pci_alloc_consistent(pdev, sizeof(nsp32_autoparam), &(data->auto_paddr));
+ data->autoparam = dma_alloc_coherent(&pdev->dev,
+ sizeof(nsp32_autoparam), &(data->auto_paddr),
+ GFP_KERNEL);
if (data->autoparam == NULL) {
nsp32_msg(KERN_ERR, "failed to allocate DMA memory");
goto scsi_unregister;
@@ -2655,8 +2657,8 @@ static int nsp32_detect(struct pci_dev *pdev)
/*
* allocate scatter-gather DMA resource.
*/
- data->sg_list = pci_alloc_consistent(pdev, NSP32_SG_TABLE_SIZE,
- &(data->sg_paddr));
+ data->sg_list = dma_alloc_coherent(&pdev->dev, NSP32_SG_TABLE_SIZE,
+ &data->sg_paddr, GFP_KERNEL);
if (data->sg_list == NULL) {
nsp32_msg(KERN_ERR, "failed to allocate DMA memory");
goto free_autoparam;
@@ -2761,11 +2763,11 @@ static int nsp32_detect(struct pci_dev *pdev)
free_irq(host->irq, data);
free_sg_list:
- pci_free_consistent(pdev, NSP32_SG_TABLE_SIZE,
+ dma_free_coherent(&pdev->dev, NSP32_SG_TABLE_SIZE,
data->sg_list, data->sg_paddr);
free_autoparam:
- pci_free_consistent(pdev, sizeof(nsp32_autoparam),
+ dma_free_coherent(&pdev->dev, sizeof(nsp32_autoparam),
data->autoparam, data->auto_paddr);
scsi_unregister:
@@ -2780,12 +2782,12 @@ static int nsp32_release(struct Scsi_Host *host)
nsp32_hw_data *data = (nsp32_hw_data *)host->hostdata;
if (data->autoparam) {
- pci_free_consistent(data->Pci, sizeof(nsp32_autoparam),
+ dma_free_coherent(&data->Pci->dev, sizeof(nsp32_autoparam),
data->autoparam, data->auto_paddr);
}
if (data->sg_list) {
- pci_free_consistent(data->Pci, NSP32_SG_TABLE_SIZE,
+ dma_free_coherent(&data->Pci->dev, NSP32_SG_TABLE_SIZE,
data->sg_list, data->sg_paddr);
}
diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
index 67b14576fff2..e19fa883376f 100644
--- a/drivers/scsi/osd/osd_initiator.c
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -445,7 +445,7 @@ static void _put_request(struct request *rq)
* code paths.
*/
if (unlikely(rq->bio))
- blk_end_request(rq, BLK_STS_IOERR, blk_rq_bytes(rq));
+ blk_mq_end_request(rq, BLK_STS_IOERR);
else
blk_put_request(rq);
}
diff --git a/drivers/scsi/pcmcia/aha152x_core.c b/drivers/scsi/pcmcia/aha152x_core.c
index dba3716511c5..24b89228b241 100644
--- a/drivers/scsi/pcmcia/aha152x_core.c
+++ b/drivers/scsi/pcmcia/aha152x_core.c
@@ -1,3 +1,3 @@
-#define PCMCIA 1
+#define AHA152X_PCMCIA 1
#define AHA152X_STAT 1
#include "aha152x.c"
diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c
index 7d1609fa233c..df82a349e969 100644
--- a/drivers/scsi/pcmcia/aha152x_stub.c
+++ b/drivers/scsi/pcmcia/aha152x_stub.c
@@ -220,16 +220,4 @@ static struct pcmcia_driver aha152x_cs_driver = {
.id_table = aha152x_ids,
.resume = aha152x_resume,
};
-
-static int __init init_aha152x_cs(void)
-{
- return pcmcia_register_driver(&aha152x_cs_driver);
-}
-
-static void __exit exit_aha152x_cs(void)
-{
- pcmcia_unregister_driver(&aha152x_cs_driver);
-}
-
-module_init(init_aha152x_cs);
-module_exit(exit_aha152x_cs);
+module_pcmcia_driver(aha152x_cs_driver);
diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c
index 5fb6eefc6541..f3230494a8c9 100644
--- a/drivers/scsi/pcmcia/nsp_cs.c
+++ b/drivers/scsi/pcmcia/nsp_cs.c
@@ -1742,19 +1742,6 @@ static struct pcmcia_driver nsp_driver = {
.suspend = nsp_cs_suspend,
.resume = nsp_cs_resume,
};
-
-static int __init nsp_cs_init(void)
-{
- return pcmcia_register_driver(&nsp_driver);
-}
-
-static void __exit nsp_cs_exit(void)
-{
- pcmcia_unregister_driver(&nsp_driver);
-}
-
-
-module_init(nsp_cs_init)
-module_exit(nsp_cs_exit)
+module_pcmcia_driver(nsp_driver);
/* end */
diff --git a/drivers/scsi/pcmcia/nsp_cs.h b/drivers/scsi/pcmcia/nsp_cs.h
index afd64f0adc4b..ea5122f3396d 100644
--- a/drivers/scsi/pcmcia/nsp_cs.h
+++ b/drivers/scsi/pcmcia/nsp_cs.h
@@ -326,10 +326,6 @@ static struct Scsi_Host *nsp_detect(struct scsi_host_template *sht);
/* Interrupt handler */
//static irqreturn_t nspintr(int irq, void *dev_id);
-/* Module entry point*/
-static int __init nsp_cs_init(void);
-static void __exit nsp_cs_exit(void);
-
/* Debug */
#ifdef NSP_DEBUG
static void show_command (struct scsi_cmnd *SCpnt);
diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c
index 0556054764dc..173351a8554b 100644
--- a/drivers/scsi/pcmcia/qlogic_stub.c
+++ b/drivers/scsi/pcmcia/qlogic_stub.c
@@ -254,8 +254,12 @@ static void qlogic_release(struct pcmcia_device *link)
static int qlogic_resume(struct pcmcia_device *link)
{
scsi_info_t *info = link->priv;
+ int ret;
+
+ ret = pcmcia_enable_device(link);
+ if (ret)
+ return ret;
- pcmcia_enable_device(link);
if ((info->manf_id == MANFID_MACNICA) ||
(info->manf_id == MANFID_PIONEER) ||
(info->manf_id == 0x0098)) {
@@ -300,18 +304,7 @@ static struct pcmcia_driver qlogic_cs_driver = {
.resume = qlogic_resume,
};
-static int __init init_qlogic_cs(void)
-{
- return pcmcia_register_driver(&qlogic_cs_driver);
-}
-
-static void __exit exit_qlogic_cs(void)
-{
- pcmcia_unregister_driver(&qlogic_cs_driver);
-}
-
MODULE_AUTHOR("Tom Zerucha, Michael Griffith");
MODULE_DESCRIPTION("Driver for the PCMCIA Qlogic FAS SCSI controllers");
MODULE_LICENSE("GPL");
-module_init(init_qlogic_cs);
-module_exit(exit_qlogic_cs);
+module_pcmcia_driver(qlogic_cs_driver);
diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c
index 20011c8afbb5..a3b63bea0e50 100644
--- a/drivers/scsi/pcmcia/sym53c500_cs.c
+++ b/drivers/scsi/pcmcia/sym53c500_cs.c
@@ -880,18 +880,4 @@ static struct pcmcia_driver sym53c500_cs_driver = {
.id_table = sym53c500_ids,
.resume = sym53c500_resume,
};
-
-static int __init
-init_sym53c500_cs(void)
-{
- return pcmcia_register_driver(&sym53c500_cs_driver);
-}
-
-static void __exit
-exit_sym53c500_cs(void)
-{
- pcmcia_unregister_driver(&sym53c500_cs_driver);
-}
-
-module_init(init_sym53c500_cs);
-module_exit(exit_sym53c500_cs);
+module_pcmcia_driver(sym53c500_cs_driver);
diff --git a/drivers/scsi/pm8001/pm8001_defs.h b/drivers/scsi/pm8001/pm8001_defs.h
index 199527dbaaa1..48e0624ecc68 100644
--- a/drivers/scsi/pm8001/pm8001_defs.h
+++ b/drivers/scsi/pm8001/pm8001_defs.h
@@ -132,4 +132,12 @@ enum pm8001_hba_info_flags {
PM8001F_RUN_TIME = (1U << 1),
};
+/**
+ * Phy Status
+ */
+#define PHY_LINK_DISABLE 0x00
+#define PHY_LINK_DOWN 0x01
+#define PHY_STATE_LINK_UP_SPCV 0x2
+#define PHY_STATE_LINK_UP_SPC 0x1
+
#endif
diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c
index 4dd6cad330e8..d0bb357034d8 100644
--- a/drivers/scsi/pm8001/pm8001_hwi.c
+++ b/drivers/scsi/pm8001/pm8001_hwi.c
@@ -1479,6 +1479,12 @@ u32 pm8001_mpi_msg_consume(struct pm8001_hba_info *pm8001_ha,
} else {
u32 producer_index;
void *pi_virt = circularQ->pi_virt;
+ /* spurious interrupt during setup if
+ * kexec-ing and driver doing a doorbell access
+ * with the pre-kexec oq interrupt setup
+ */
+ if (!pi_virt)
+ break;
/* Update the producer index from SPC */
producer_index = pm8001_read_32(pi_virt);
circularQ->producer_index = cpu_to_le32(producer_index);
@@ -2414,7 +2420,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
sata_resp = &psataPayload->sata_resp[0];
resp = (struct ata_task_resp *)ts->buf;
if (t->ata_task.dma_xfer == 0 &&
- t->data_dir == PCI_DMA_FROMDEVICE) {
+ t->data_dir == DMA_FROM_DEVICE) {
len = sizeof(struct pio_setup_fis);
PM8001_IO_DBG(pm8001_ha,
pm8001_printk("PIO read len = %d\n", len));
@@ -3810,7 +3816,8 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void* piomb)
" status = %x\n", status));
if (status == 0) {
phy->phy_state = 1;
- if (pm8001_ha->flags == PM8001F_RUN_TIME)
+ if (pm8001_ha->flags == PM8001F_RUN_TIME &&
+ phy->enable_completion != NULL)
complete(phy->enable_completion);
}
break;
@@ -4196,12 +4203,12 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
return ret;
}
-/* PCI_DMA_... to our direction translation. */
+/* DMA_... to our direction translation. */
static const u8 data_dir_flags[] = {
- [PCI_DMA_BIDIRECTIONAL] = DATA_DIR_BYRECIPIENT,/* UNSPECIFIED */
- [PCI_DMA_TODEVICE] = DATA_DIR_OUT,/* OUTBOUND */
- [PCI_DMA_FROMDEVICE] = DATA_DIR_IN,/* INBOUND */
- [PCI_DMA_NONE] = DATA_DIR_NONE,/* NO TRANSFER */
+ [DMA_BIDIRECTIONAL] = DATA_DIR_BYRECIPIENT, /* UNSPECIFIED */
+ [DMA_TO_DEVICE] = DATA_DIR_OUT, /* OUTBOUND */
+ [DMA_FROM_DEVICE] = DATA_DIR_IN, /* INBOUND */
+ [DMA_NONE] = DATA_DIR_NONE, /* NO TRANSFER */
};
void
pm8001_chip_make_sg(struct scatterlist *scatter, int nr, void *prd)
@@ -4248,13 +4255,13 @@ static int pm8001_chip_smp_req(struct pm8001_hba_info *pm8001_ha,
* DMA-map SMP request, response buffers
*/
sg_req = &task->smp_task.smp_req;
- elem = dma_map_sg(pm8001_ha->dev, sg_req, 1, PCI_DMA_TODEVICE);
+ elem = dma_map_sg(pm8001_ha->dev, sg_req, 1, DMA_TO_DEVICE);
if (!elem)
return -ENOMEM;
req_len = sg_dma_len(sg_req);
sg_resp = &task->smp_task.smp_resp;
- elem = dma_map_sg(pm8001_ha->dev, sg_resp, 1, PCI_DMA_FROMDEVICE);
+ elem = dma_map_sg(pm8001_ha->dev, sg_resp, 1, DMA_FROM_DEVICE);
if (!elem) {
rc = -ENOMEM;
goto err_out;
@@ -4287,10 +4294,10 @@ static int pm8001_chip_smp_req(struct pm8001_hba_info *pm8001_ha,
err_out_2:
dma_unmap_sg(pm8001_ha->dev, &ccb->task->smp_task.smp_resp, 1,
- PCI_DMA_FROMDEVICE);
+ DMA_FROM_DEVICE);
err_out:
dma_unmap_sg(pm8001_ha->dev, &ccb->task->smp_task.smp_req, 1,
- PCI_DMA_TODEVICE);
+ DMA_TO_DEVICE);
return rc;
}
@@ -4369,7 +4376,7 @@ static int pm8001_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
u32 opc = OPC_INB_SATA_HOST_OPSTART;
memset(&sata_cmd, 0, sizeof(sata_cmd));
circularQ = &pm8001_ha->inbnd_q_tbl[0];
- if (task->data_dir == PCI_DMA_NONE) {
+ if (task->data_dir == DMA_NONE) {
ATAP = 0x04; /* no data*/
PM8001_IO_DBG(pm8001_ha, pm8001_printk("no data\n"));
} else if (likely(!task->ata_task.device_control_reg_update)) {
diff --git a/drivers/scsi/pm8001/pm8001_hwi.h b/drivers/scsi/pm8001/pm8001_hwi.h
index e4867e690c84..6d91e2446542 100644
--- a/drivers/scsi/pm8001/pm8001_hwi.h
+++ b/drivers/scsi/pm8001/pm8001_hwi.h
@@ -131,10 +131,6 @@
#define LINKRATE_30 (0x02 << 8)
#define LINKRATE_60 (0x04 << 8)
-/* for phy state */
-
-#define PHY_STATE_LINK_UP_SPC 0x1
-
/* for new SPC controllers MEMBASE III is shared between BIOS and DATA */
#define GSM_SM_BASE 0x4F0000
struct mpi_msg_hdr{
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
index 7a697ca68501..d71e7e4ec29c 100644
--- a/drivers/scsi/pm8001/pm8001_init.c
+++ b/drivers/scsi/pm8001/pm8001_init.c
@@ -121,7 +121,7 @@ static void pm8001_phy_init(struct pm8001_hba_info *pm8001_ha, int phy_id)
{
struct pm8001_phy *phy = &pm8001_ha->phy[phy_id];
struct asd_sas_phy *sas_phy = &phy->sas_phy;
- phy->phy_state = 0;
+ phy->phy_state = PHY_LINK_DISABLE;
phy->pm8001_ha = pm8001_ha;
sas_phy->enabled = (phy_id < pm8001_ha->chip->n_phy) ? 1 : 0;
sas_phy->class = SAS;
@@ -152,7 +152,7 @@ static void pm8001_free(struct pm8001_hba_info *pm8001_ha)
for (i = 0; i < USI_MAX_MEMCNT; i++) {
if (pm8001_ha->memoryMap.region[i].virt_ptr != NULL) {
- pci_free_consistent(pm8001_ha->pdev,
+ dma_free_coherent(&pm8001_ha->pdev->dev,
(pm8001_ha->memoryMap.region[i].total_len +
pm8001_ha->memoryMap.region[i].alignment),
pm8001_ha->memoryMap.region[i].virt_ptr,
@@ -501,30 +501,12 @@ static int pci_go_44(struct pci_dev *pdev)
{
int rc;
- if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(44))) {
- rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(44));
- if (rc) {
- rc = pci_set_consistent_dma_mask(pdev,
- DMA_BIT_MASK(32));
- if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "44-bit DMA enable failed\n");
- return rc;
- }
- }
- } else {
- rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
- if (rc) {
+ rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(44));
+ if (rc) {
+ rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+ if (rc)
dev_printk(KERN_ERR, &pdev->dev,
"32-bit DMA enable failed\n");
- return rc;
- }
- rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
- if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "32-bit consistent DMA enable failed\n");
- return rc;
- }
}
return rc;
}
@@ -1067,6 +1049,7 @@ static int pm8001_pci_probe(struct pci_dev *pdev,
if (rc)
goto err_out_shost;
scsi_scan_host(pm8001_ha->shost);
+ pm8001_ha->flags = PM8001F_RUN_TIME;
return 0;
err_out_shost:
diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c
index 947d6017d004..b3be49d41375 100644
--- a/drivers/scsi/pm8001/pm8001_sas.c
+++ b/drivers/scsi/pm8001/pm8001_sas.c
@@ -116,8 +116,8 @@ int pm8001_mem_alloc(struct pci_dev *pdev, void **virt_addr,
u64 align_offset = 0;
if (align)
align_offset = (dma_addr_t)align - 1;
- mem_virt_alloc = pci_zalloc_consistent(pdev, mem_size + align,
- &mem_dma_handle);
+ mem_virt_alloc = dma_zalloc_coherent(&pdev->dev, mem_size + align,
+ &mem_dma_handle, GFP_KERNEL);
if (!mem_virt_alloc) {
pm8001_printk("memory allocation error\n");
return -1;
@@ -157,9 +157,12 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
int rc = 0, phy_id = sas_phy->id;
struct pm8001_hba_info *pm8001_ha = NULL;
struct sas_phy_linkrates *rates;
+ struct sas_ha_struct *sas_ha;
+ struct pm8001_phy *phy;
DECLARE_COMPLETION_ONSTACK(completion);
unsigned long flags;
pm8001_ha = sas_phy->ha->lldd_ha;
+ phy = &pm8001_ha->phy[phy_id];
pm8001_ha->phy[phy_id].enable_completion = &completion;
switch (func) {
case PHY_FUNC_SET_LINK_RATE:
@@ -172,7 +175,7 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
pm8001_ha->phy[phy_id].maximum_linkrate =
rates->maximum_linkrate;
}
- if (pm8001_ha->phy[phy_id].phy_state == 0) {
+ if (pm8001_ha->phy[phy_id].phy_state == PHY_LINK_DISABLE) {
PM8001_CHIP_DISP->phy_start_req(pm8001_ha, phy_id);
wait_for_completion(&completion);
}
@@ -180,7 +183,7 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
PHY_LINK_RESET);
break;
case PHY_FUNC_HARD_RESET:
- if (pm8001_ha->phy[phy_id].phy_state == 0) {
+ if (pm8001_ha->phy[phy_id].phy_state == PHY_LINK_DISABLE) {
PM8001_CHIP_DISP->phy_start_req(pm8001_ha, phy_id);
wait_for_completion(&completion);
}
@@ -188,7 +191,7 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
PHY_HARD_RESET);
break;
case PHY_FUNC_LINK_RESET:
- if (pm8001_ha->phy[phy_id].phy_state == 0) {
+ if (pm8001_ha->phy[phy_id].phy_state == PHY_LINK_DISABLE) {
PM8001_CHIP_DISP->phy_start_req(pm8001_ha, phy_id);
wait_for_completion(&completion);
}
@@ -200,6 +203,25 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
PHY_LINK_RESET);
break;
case PHY_FUNC_DISABLE:
+ if (pm8001_ha->chip_id != chip_8001) {
+ if (pm8001_ha->phy[phy_id].phy_state ==
+ PHY_STATE_LINK_UP_SPCV) {
+ sas_ha = pm8001_ha->sas;
+ sas_phy_disconnected(&phy->sas_phy);
+ sas_ha->notify_phy_event(&phy->sas_phy,
+ PHYE_LOSS_OF_SIGNAL);
+ phy->phy_attached = 0;
+ }
+ } else {
+ if (pm8001_ha->phy[phy_id].phy_state ==
+ PHY_STATE_LINK_UP_SPC) {
+ sas_ha = pm8001_ha->sas;
+ sas_phy_disconnected(&phy->sas_phy);
+ sas_ha->notify_phy_event(&phy->sas_phy,
+ PHYE_LOSS_OF_SIGNAL);
+ phy->phy_attached = 0;
+ }
+ }
PM8001_CHIP_DISP->phy_stop_req(pm8001_ha, phy_id);
break;
case PHY_FUNC_GET_EVENTS:
@@ -374,6 +396,13 @@ static int pm8001_task_exec(struct sas_task *task,
return 0;
}
pm8001_ha = pm8001_find_ha_by_dev(task->dev);
+ if (pm8001_ha->controller_fatal_error) {
+ struct task_status_struct *ts = &t->task_status;
+
+ ts->resp = SAS_TASK_UNDELIVERED;
+ t->task_done(t);
+ return 0;
+ }
PM8001_IO_DBG(pm8001_ha, pm8001_printk("pm8001_task_exec device \n "));
spin_lock_irqsave(&pm8001_ha->lock, flags);
do {
@@ -466,7 +495,7 @@ err_out:
dev_printk(KERN_ERR, pm8001_ha->dev, "pm8001 exec failed[%d]!\n", rc);
if (!sas_protocol_ata(t->task_proto))
if (n_elem)
- dma_unmap_sg(pm8001_ha->dev, t->scatter, n_elem,
+ dma_unmap_sg(pm8001_ha->dev, t->scatter, t->num_scatter,
t->data_dir);
out_done:
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
@@ -504,9 +533,9 @@ void pm8001_ccb_task_free(struct pm8001_hba_info *pm8001_ha,
switch (task->task_proto) {
case SAS_PROTOCOL_SMP:
dma_unmap_sg(pm8001_ha->dev, &task->smp_task.smp_resp, 1,
- PCI_DMA_FROMDEVICE);
+ DMA_FROM_DEVICE);
dma_unmap_sg(pm8001_ha->dev, &task->smp_task.smp_req, 1,
- PCI_DMA_TODEVICE);
+ DMA_TO_DEVICE);
break;
case SAS_PROTOCOL_SATA:
@@ -1020,13 +1049,11 @@ int pm8001_I_T_nexus_event_handler(struct domain_device *dev)
struct pm8001_device *pm8001_dev;
struct pm8001_hba_info *pm8001_ha;
struct sas_phy *phy;
- u32 device_id = 0;
if (!dev || !dev->lldd_dev)
return -1;
pm8001_dev = dev->lldd_dev;
- device_id = pm8001_dev->device_id;
pm8001_ha = pm8001_find_ha_by_dev(dev);
PM8001_EH_DBG(pm8001_ha,
@@ -1159,7 +1186,6 @@ int pm8001_abort_task(struct sas_task *task)
{
unsigned long flags;
u32 tag;
- u32 device_id;
struct domain_device *dev ;
struct pm8001_hba_info *pm8001_ha;
struct scsi_lun lun;
@@ -1173,7 +1199,6 @@ int pm8001_abort_task(struct sas_task *task)
dev = task->dev;
pm8001_dev = dev->lldd_dev;
pm8001_ha = pm8001_find_ha_by_dev(dev);
- device_id = pm8001_dev->device_id;
phy_id = pm8001_dev->attached_phy;
rc = pm8001_find_tag(task, &tag);
if (rc == 0) {
diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h
index 80b4dd6df0c2..f88b0d33c385 100644
--- a/drivers/scsi/pm8001/pm8001_sas.h
+++ b/drivers/scsi/pm8001/pm8001_sas.h
@@ -58,7 +58,7 @@
#include "pm8001_defs.h"
#define DRV_NAME "pm80xx"
-#define DRV_VERSION "0.1.38"
+#define DRV_VERSION "0.1.39"
#define PM8001_FAIL_LOGGING 0x01 /* Error message logging */
#define PM8001_INIT_LOGGING 0x02 /* driver init logging */
#define PM8001_DISC_LOGGING 0x04 /* discovery layer logging */
@@ -538,6 +538,7 @@ struct pm8001_hba_info {
u32 logging_level;
u32 fw_status;
u32 smp_exp_mode;
+ bool controller_fatal_error;
const struct firmware *fw_image;
struct isr_param irq_vector[PM8001_MAX_MSIX_VEC];
u32 reset_in_progress;
diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c
index 42f0405601ad..63e4f7d34d6c 100644
--- a/drivers/scsi/pm8001/pm80xx_hwi.c
+++ b/drivers/scsi/pm8001/pm80xx_hwi.c
@@ -577,6 +577,9 @@ static void update_main_config_table(struct pm8001_hba_info *pm8001_ha)
pm8001_ha->main_cfg_tbl.pm80xx_tbl.pcs_event_log_size);
pm8001_mw32(address, MAIN_PCS_EVENT_LOG_OPTION,
pm8001_ha->main_cfg_tbl.pm80xx_tbl.pcs_event_log_severity);
+ /* Update Fatal error interrupt vector */
+ pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_interrupt |=
+ ((pm8001_ha->number_of_intr - 1) << 8);
pm8001_mw32(address, MAIN_FATAL_ERROR_INTERRUPT,
pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_interrupt);
pm8001_mw32(address, MAIN_EVENT_CRC_CHECK,
@@ -1110,6 +1113,9 @@ static int pm80xx_chip_init(struct pm8001_hba_info *pm8001_ha)
return -EBUSY;
}
+ /* Initialize the controller fatal error flag */
+ pm8001_ha->controller_fatal_error = false;
+
/* Initialize pci space address eg: mpi offset */
init_pci_device_addresses(pm8001_ha);
init_default_table_values(pm8001_ha);
@@ -1218,13 +1224,17 @@ pm80xx_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
u32 bootloader_state;
u32 ibutton0, ibutton1;
- /* Check if MPI is in ready state to reset */
- if (mpi_uninit_check(pm8001_ha) != 0) {
- PM8001_FAIL_DBG(pm8001_ha,
- pm8001_printk("MPI state is not ready\n"));
- return -1;
+ /* Process MPI table uninitialization only if FW is ready */
+ if (!pm8001_ha->controller_fatal_error) {
+ /* Check if MPI is in ready state to reset */
+ if (mpi_uninit_check(pm8001_ha) != 0) {
+ regval = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1);
+ PM8001_FAIL_DBG(pm8001_ha, pm8001_printk(
+ "MPI state is not ready scratch1 :0x%x\n",
+ regval));
+ return -1;
+ }
}
-
/* checked for reset register normal state; 0x0 */
regval = pm8001_cr32(pm8001_ha, 0, SPC_REG_SOFT_RESET);
PM8001_INIT_DBG(pm8001_ha,
@@ -2123,7 +2133,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
sata_resp = &psataPayload->sata_resp[0];
resp = (struct ata_task_resp *)ts->buf;
if (t->ata_task.dma_xfer == 0 &&
- t->data_dir == PCI_DMA_FROMDEVICE) {
+ t->data_dir == DMA_FROM_DEVICE) {
len = sizeof(struct pio_setup_fis);
PM8001_IO_DBG(pm8001_ha,
pm8001_printk("PIO read len = %d\n", len));
@@ -3118,8 +3128,9 @@ static int mpi_phy_start_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
pm8001_printk("phy start resp status:0x%x, phyid:0x%x\n",
status, phy_id));
if (status == 0) {
- phy->phy_state = 1;
- if (pm8001_ha->flags == PM8001F_RUN_TIME)
+ phy->phy_state = PHY_LINK_DOWN;
+ if (pm8001_ha->flags == PM8001F_RUN_TIME &&
+ phy->enable_completion != NULL)
complete(phy->enable_completion);
}
return 0;
@@ -3211,7 +3222,7 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
return 0;
}
phy->phy_attached = 0;
- phy->phy_state = 0;
+ phy->phy_state = PHY_LINK_DISABLE;
break;
case HW_EVENT_PORT_INVALID:
PM8001_MSG_DBG(pm8001_ha,
@@ -3384,13 +3395,14 @@ static int mpi_phy_stop_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
u32 status =
le32_to_cpu(pPayload->status);
u32 phyid =
- le32_to_cpu(pPayload->phyid);
+ le32_to_cpu(pPayload->phyid) & 0xFF;
struct pm8001_phy *phy = &pm8001_ha->phy[phyid];
PM8001_MSG_DBG(pm8001_ha,
pm8001_printk("phy:0x%x status:0x%x\n",
phyid, status));
- if (status == 0)
- phy->phy_state = 0;
+ if (status == PHY_STOP_SUCCESS ||
+ status == PHY_STOP_ERR_DEVICE_ATTACHED)
+ phy->phy_state = PHY_LINK_DISABLE;
return 0;
}
@@ -3752,6 +3764,46 @@ static void process_one_iomb(struct pm8001_hba_info *pm8001_ha, void *piomb)
}
}
+static void print_scratchpad_registers(struct pm8001_hba_info *pm8001_ha)
+{
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("MSGU_SCRATCH_PAD_0: 0x%x\n",
+ pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0)));
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("MSGU_SCRATCH_PAD_1:0x%x\n",
+ pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1)));
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("MSGU_SCRATCH_PAD_2: 0x%x\n",
+ pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2)));
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("MSGU_SCRATCH_PAD_3: 0x%x\n",
+ pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3)));
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("MSGU_HOST_SCRATCH_PAD_0: 0x%x\n",
+ pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_0)));
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("MSGU_HOST_SCRATCH_PAD_1: 0x%x\n",
+ pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_1)));
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("MSGU_HOST_SCRATCH_PAD_2: 0x%x\n",
+ pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_2)));
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("MSGU_HOST_SCRATCH_PAD_3: 0x%x\n",
+ pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_3)));
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("MSGU_HOST_SCRATCH_PAD_4: 0x%x\n",
+ pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_4)));
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("MSGU_HOST_SCRATCH_PAD_5: 0x%x\n",
+ pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_5)));
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("MSGU_RSVD_SCRATCH_PAD_0: 0x%x\n",
+ pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_6)));
+ PM8001_FAIL_DBG(pm8001_ha,
+ pm8001_printk("MSGU_RSVD_SCRATCH_PAD_1: 0x%x\n",
+ pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_7)));
+}
+
static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
{
struct outbound_queue_table *circularQ;
@@ -3759,10 +3811,28 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
u8 uninitialized_var(bc);
u32 ret = MPI_IO_STATUS_FAIL;
unsigned long flags;
+ u32 regval;
+ if (vec == (pm8001_ha->number_of_intr - 1)) {
+ regval = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1);
+ if ((regval & SCRATCH_PAD_MIPSALL_READY) !=
+ SCRATCH_PAD_MIPSALL_READY) {
+ pm8001_ha->controller_fatal_error = true;
+ PM8001_FAIL_DBG(pm8001_ha, pm8001_printk(
+ "Firmware Fatal error! Regval:0x%x\n", regval));
+ print_scratchpad_registers(pm8001_ha);
+ return ret;
+ }
+ }
spin_lock_irqsave(&pm8001_ha->lock, flags);
circularQ = &pm8001_ha->outbnd_q_tbl[vec];
do {
+ /* spurious interrupt during setup if kexec-ing and
+ * driver doing a doorbell access w/ the pre-kexec oq
+ * interrupt setup.
+ */
+ if (!circularQ->pi_virt)
+ break;
ret = pm8001_mpi_msg_consume(pm8001_ha, circularQ, &pMsg1, &bc);
if (MPI_IO_STATUS_SUCCESS == ret) {
/* process the outbound message */
@@ -3785,12 +3855,12 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
return ret;
}
-/* PCI_DMA_... to our direction translation. */
+/* DMA_... to our direction translation. */
static const u8 data_dir_flags[] = {
- [PCI_DMA_BIDIRECTIONAL] = DATA_DIR_BYRECIPIENT,/* UNSPECIFIED */
- [PCI_DMA_TODEVICE] = DATA_DIR_OUT,/* OUTBOUND */
- [PCI_DMA_FROMDEVICE] = DATA_DIR_IN,/* INBOUND */
- [PCI_DMA_NONE] = DATA_DIR_NONE,/* NO TRANSFER */
+ [DMA_BIDIRECTIONAL] = DATA_DIR_BYRECIPIENT, /* UNSPECIFIED */
+ [DMA_TO_DEVICE] = DATA_DIR_OUT, /* OUTBOUND */
+ [DMA_FROM_DEVICE] = DATA_DIR_IN, /* INBOUND */
+ [DMA_NONE] = DATA_DIR_NONE, /* NO TRANSFER */
};
static void build_smp_cmd(u32 deviceID, __le32 hTag,
@@ -3832,13 +3902,13 @@ static int pm80xx_chip_smp_req(struct pm8001_hba_info *pm8001_ha,
* DMA-map SMP request, response buffers
*/
sg_req = &task->smp_task.smp_req;
- elem = dma_map_sg(pm8001_ha->dev, sg_req, 1, PCI_DMA_TODEVICE);
+ elem = dma_map_sg(pm8001_ha->dev, sg_req, 1, DMA_TO_DEVICE);
if (!elem)
return -ENOMEM;
req_len = sg_dma_len(sg_req);
sg_resp = &task->smp_task.smp_resp;
- elem = dma_map_sg(pm8001_ha->dev, sg_resp, 1, PCI_DMA_FROMDEVICE);
+ elem = dma_map_sg(pm8001_ha->dev, sg_resp, 1, DMA_FROM_DEVICE);
if (!elem) {
rc = -ENOMEM;
goto err_out;
@@ -3929,10 +3999,10 @@ static int pm80xx_chip_smp_req(struct pm8001_hba_info *pm8001_ha,
err_out_2:
dma_unmap_sg(pm8001_ha->dev, &ccb->task->smp_task.smp_resp, 1,
- PCI_DMA_FROMDEVICE);
+ DMA_FROM_DEVICE);
err_out:
dma_unmap_sg(pm8001_ha->dev, &ccb->task->smp_task.smp_req, 1,
- PCI_DMA_TODEVICE);
+ DMA_TO_DEVICE);
return rc;
}
@@ -4156,7 +4226,7 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
q_index = (u32) (pm8001_ha_dev->id & 0x00ffffff) % PM8001_MAX_INB_NUM;
circularQ = &pm8001_ha->inbnd_q_tbl[q_index];
- if (task->data_dir == PCI_DMA_NONE) {
+ if (task->data_dir == DMA_NONE) {
ATAP = 0x04; /* no data*/
PM8001_IO_DBG(pm8001_ha, pm8001_printk("no data\n"));
} else if (likely(!task->ata_task.device_control_reg_update)) {
@@ -4606,9 +4676,8 @@ void mpi_set_phy_profile_req(struct pm8001_hba_info *pm8001_ha,
void pm8001_set_phy_profile(struct pm8001_hba_info *pm8001_ha,
u32 length, u8 *buf)
{
- u32 page_code, i;
+ u32 i;
- page_code = SAS_PHY_ANALOG_SETTINGS_PAGE;
for (i = 0; i < pm8001_ha->chip->n_phy; i++) {
mpi_set_phy_profile_req(pm8001_ha,
SAS_PHY_ANALOG_SETTINGS_PAGE, i, length, (u32 *)buf);
diff --git a/drivers/scsi/pm8001/pm80xx_hwi.h b/drivers/scsi/pm8001/pm80xx_hwi.h
index 889e69ce3689..84d7426441bf 100644
--- a/drivers/scsi/pm8001/pm80xx_hwi.h
+++ b/drivers/scsi/pm8001/pm80xx_hwi.h
@@ -170,6 +170,10 @@
#define LINKRATE_60 (0x04 << 8)
#define LINKRATE_120 (0x08 << 8)
+/*phy_stop*/
+#define PHY_STOP_SUCCESS 0x00
+#define PHY_STOP_ERR_DEVICE_ATTACHED 0x1046
+
/* phy_profile */
#define SAS_PHY_ANALOG_SETTINGS_PAGE 0x04
#define PHY_DWORD_LENGTH 0xC
@@ -216,8 +220,6 @@
#define SAS_DOPNRJT_RTRY_TMO 128
#define SAS_COPNRJT_RTRY_TMO 128
-/* for phy state */
-#define PHY_STATE_LINK_UP_SPCV 0x2
/*
Making ORR bigger than IT NEXUS LOSS which is 2000000us = 2 second.
Assuming a bigger value 3 second, 3000000/128 = 23437.5 where 128
@@ -1384,6 +1386,9 @@ typedef struct SASProtocolTimerConfig SASProtocolTimerConfig_t;
#define SCRATCH_PAD_BOOT_LOAD_SUCCESS 0x0
#define SCRATCH_PAD_IOP0_READY 0xC00
#define SCRATCH_PAD_IOP1_READY 0x3000
+#define SCRATCH_PAD_MIPSALL_READY (SCRATCH_PAD_IOP1_READY | \
+ SCRATCH_PAD_IOP0_READY | \
+ SCRATCH_PAD_RAAE_READY)
/* boot loader state */
#define SCRATCH_PAD1_BOOTSTATE_MASK 0x70 /* Bit 4-6 */
diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c
index 0a5dd5595dd3..d5a4f17fce51 100644
--- a/drivers/scsi/qedf/qedf_main.c
+++ b/drivers/scsi/qedf/qedf_main.c
@@ -2855,12 +2855,12 @@ static int qedf_set_fcoe_pf_param(struct qedf_ctx *qedf)
QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC, "Number of CQs is %d.\n",
qedf->num_queues);
- qedf->p_cpuq = pci_alloc_consistent(qedf->pdev,
+ qedf->p_cpuq = dma_alloc_coherent(&qedf->pdev->dev,
qedf->num_queues * sizeof(struct qedf_glbl_q_params),
- &qedf->hw_p_cpuq);
+ &qedf->hw_p_cpuq, GFP_KERNEL);
if (!qedf->p_cpuq) {
- QEDF_ERR(&(qedf->dbg_ctx), "pci_alloc_consistent failed.\n");
+ QEDF_ERR(&(qedf->dbg_ctx), "dma_alloc_coherent failed.\n");
return 1;
}
@@ -2929,7 +2929,7 @@ static void qedf_free_fcoe_pf_param(struct qedf_ctx *qedf)
if (qedf->p_cpuq) {
size = qedf->num_queues * sizeof(struct qedf_glbl_q_params);
- pci_free_consistent(qedf->pdev, size, qedf->p_cpuq,
+ dma_free_coherent(&qedf->pdev->dev, size, qedf->p_cpuq,
qedf->hw_p_cpuq);
}
diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c
index cc8e64dc65ad..105b0e4d7818 100644
--- a/drivers/scsi/qedi/qedi_main.c
+++ b/drivers/scsi/qedi/qedi_main.c
@@ -806,11 +806,11 @@ static int qedi_set_iscsi_pf_param(struct qedi_ctx *qedi)
memset(&qedi->pf_params.iscsi_pf_params, 0,
sizeof(qedi->pf_params.iscsi_pf_params));
- qedi->p_cpuq = pci_alloc_consistent(qedi->pdev,
+ qedi->p_cpuq = dma_alloc_coherent(&qedi->pdev->dev,
qedi->num_queues * sizeof(struct qedi_glbl_q_params),
- &qedi->hw_p_cpuq);
+ &qedi->hw_p_cpuq, GFP_KERNEL);
if (!qedi->p_cpuq) {
- QEDI_ERR(&qedi->dbg_ctx, "pci_alloc_consistent fail\n");
+ QEDI_ERR(&qedi->dbg_ctx, "dma_alloc_coherent fail\n");
rval = -1;
goto err_alloc_mem;
}
@@ -871,7 +871,7 @@ static void qedi_free_iscsi_pf_param(struct qedi_ctx *qedi)
if (qedi->p_cpuq) {
size = qedi->num_queues * sizeof(struct qedi_glbl_q_params);
- pci_free_consistent(qedi->pdev, size, qedi->p_cpuq,
+ dma_free_coherent(&qedi->pdev->dev, size, qedi->p_cpuq,
qedi->hw_p_cpuq);
}
@@ -2472,6 +2472,7 @@ static int __qedi_probe(struct pci_dev *pdev, int mode)
/* start qedi context */
spin_lock_init(&qedi->hba_lock);
spin_lock_init(&qedi->task_idx_lock);
+ mutex_init(&qedi->stats_lock);
}
qedi_ops->ll2->register_cb_ops(qedi->cdev, &qedi_ll2_cb_ops, qedi);
qedi_ops->ll2->start(qedi->cdev, &params);
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index 390775d5c918..15a50cc7e4b3 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -1750,7 +1750,7 @@ qla1280_load_firmware_dma(struct scsi_qla_host *ha)
uint8_t *sp, *tbuf;
dma_addr_t p_tbuf;
- tbuf = pci_alloc_consistent(ha->pdev, 8000, &p_tbuf);
+ tbuf = dma_alloc_coherent(&ha->pdev->dev, 8000, &p_tbuf, GFP_KERNEL);
if (!tbuf)
return -ENOMEM;
#endif
@@ -1841,7 +1841,7 @@ qla1280_load_firmware_dma(struct scsi_qla_host *ha)
out:
#if DUMP_IT_BACK
- pci_free_consistent(ha->pdev, 8000, tbuf, p_tbuf);
+ dma_free_coherent(&ha->pdev->dev, 8000, tbuf, p_tbuf);
#endif
return err;
}
@@ -4259,8 +4259,8 @@ qla1280_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->devnum = devnum; /* specifies microcode load address */
#ifdef QLA_64BIT_PTR
- if (pci_set_dma_mask(ha->pdev, DMA_BIT_MASK(64))) {
- if (pci_set_dma_mask(ha->pdev, DMA_BIT_MASK(32))) {
+ if (dma_set_mask(&ha->pdev->dev, DMA_BIT_MASK(64))) {
+ if (dma_set_mask(&ha->pdev->dev, DMA_BIT_MASK(32))) {
printk(KERN_WARNING "scsi(%li): Unable to set a "
"suitable DMA mask - aborting\n", ha->host_no);
error = -ENODEV;
@@ -4270,7 +4270,7 @@ qla1280_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
dprintk(2, "scsi(%li): 64 Bit PCI Addressing Enabled\n",
ha->host_no);
#else
- if (pci_set_dma_mask(ha->pdev, DMA_BIT_MASK(32))) {
+ if (dma_set_mask(&ha->pdev->dev, DMA_BIT_MASK(32))) {
printk(KERN_WARNING "scsi(%li): Unable to set a "
"suitable DMA mask - aborting\n", ha->host_no);
error = -ENODEV;
@@ -4278,17 +4278,17 @@ qla1280_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
}
#endif
- ha->request_ring = pci_alloc_consistent(ha->pdev,
+ ha->request_ring = dma_alloc_coherent(&ha->pdev->dev,
((REQUEST_ENTRY_CNT + 1) * sizeof(request_t)),
- &ha->request_dma);
+ &ha->request_dma, GFP_KERNEL);
if (!ha->request_ring) {
printk(KERN_INFO "qla1280: Failed to get request memory\n");
goto error_put_host;
}
- ha->response_ring = pci_alloc_consistent(ha->pdev,
+ ha->response_ring = dma_alloc_coherent(&ha->pdev->dev,
((RESPONSE_ENTRY_CNT + 1) * sizeof(struct response)),
- &ha->response_dma);
+ &ha->response_dma, GFP_KERNEL);
if (!ha->response_ring) {
printk(KERN_INFO "qla1280: Failed to get response memory\n");
goto error_free_request_ring;
@@ -4370,11 +4370,11 @@ qla1280_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
release_region(host->io_port, 0xff);
#endif
error_free_response_ring:
- pci_free_consistent(ha->pdev,
+ dma_free_coherent(&ha->pdev->dev,
((RESPONSE_ENTRY_CNT + 1) * sizeof(struct response)),
ha->response_ring, ha->response_dma);
error_free_request_ring:
- pci_free_consistent(ha->pdev,
+ dma_free_coherent(&ha->pdev->dev,
((REQUEST_ENTRY_CNT + 1) * sizeof(request_t)),
ha->request_ring, ha->request_dma);
error_put_host:
@@ -4404,10 +4404,10 @@ qla1280_remove_one(struct pci_dev *pdev)
release_region(host->io_port, 0xff);
#endif
- pci_free_consistent(ha->pdev,
+ dma_free_coherent(&ha->pdev->dev,
((REQUEST_ENTRY_CNT + 1) * (sizeof(request_t))),
ha->request_ring, ha->request_dma);
- pci_free_consistent(ha->pdev,
+ dma_free_coherent(&ha->pdev->dev,
((RESPONSE_ENTRY_CNT + 1) * (sizeof(struct response))),
ha->response_ring, ha->response_dma);
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 4888b999e82f..0bb9ac6ece92 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -158,9 +158,17 @@ qla2x00_sysfs_read_nvram(struct file *filp, struct kobject *kobj,
if (!capable(CAP_SYS_ADMIN))
return 0;
+ mutex_lock(&ha->optrom_mutex);
+ if (qla2x00_chip_is_down(vha)) {
+ mutex_unlock(&ha->optrom_mutex);
+ return -EAGAIN;
+ }
+
if (IS_NOCACHE_VPD_TYPE(ha))
ha->isp_ops->read_optrom(vha, ha->nvram, ha->flt_region_nvram << 2,
ha->nvram_size);
+ mutex_unlock(&ha->optrom_mutex);
+
return memory_read_from_buffer(buf, count, &off, ha->nvram,
ha->nvram_size);
}
@@ -208,10 +216,17 @@ qla2x00_sysfs_write_nvram(struct file *filp, struct kobject *kobj,
return -EAGAIN;
}
+ mutex_lock(&ha->optrom_mutex);
+ if (qla2x00_chip_is_down(vha)) {
+ mutex_unlock(&ha->optrom_mutex);
+ return -EAGAIN;
+ }
+
/* Write NVRAM. */
ha->isp_ops->write_nvram(vha, (uint8_t *)buf, ha->nvram_base, count);
ha->isp_ops->read_nvram(vha, (uint8_t *)ha->nvram, ha->nvram_base,
- count);
+ count);
+ mutex_unlock(&ha->optrom_mutex);
ql_dbg(ql_dbg_user, vha, 0x7060,
"Setting ISP_ABORT_NEEDED\n");
@@ -322,6 +337,10 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
size = ha->optrom_size - start;
mutex_lock(&ha->optrom_mutex);
+ if (qla2x00_chip_is_down(vha)) {
+ mutex_unlock(&ha->optrom_mutex);
+ return -EAGAIN;
+ }
switch (val) {
case 0:
if (ha->optrom_state != QLA_SREADING &&
@@ -499,8 +518,14 @@ qla2x00_sysfs_read_vpd(struct file *filp, struct kobject *kobj,
qla27xx_find_valid_image(vha) == QLA27XX_SECONDARY_IMAGE)
faddr = ha->flt_region_vpd_sec << 2;
+ mutex_lock(&ha->optrom_mutex);
+ if (qla2x00_chip_is_down(vha)) {
+ mutex_unlock(&ha->optrom_mutex);
+ return -EAGAIN;
+ }
ha->isp_ops->read_optrom(vha, ha->vpd, faddr,
ha->vpd_size);
+ mutex_unlock(&ha->optrom_mutex);
}
return memory_read_from_buffer(buf, count, &off, ha->vpd, ha->vpd_size);
}
@@ -518,9 +543,6 @@ qla2x00_sysfs_write_vpd(struct file *filp, struct kobject *kobj,
if (unlikely(pci_channel_offline(ha->pdev)))
return 0;
- if (qla2x00_chip_is_down(vha))
- return 0;
-
if (!capable(CAP_SYS_ADMIN) || off != 0 || count != ha->vpd_size ||
!ha->isp_ops->write_nvram)
return 0;
@@ -531,16 +553,25 @@ qla2x00_sysfs_write_vpd(struct file *filp, struct kobject *kobj,
return -EAGAIN;
}
+ mutex_lock(&ha->optrom_mutex);
+ if (qla2x00_chip_is_down(vha)) {
+ mutex_unlock(&ha->optrom_mutex);
+ return -EAGAIN;
+ }
+
/* Write NVRAM. */
ha->isp_ops->write_nvram(vha, (uint8_t *)buf, ha->vpd_base, count);
ha->isp_ops->read_nvram(vha, (uint8_t *)ha->vpd, ha->vpd_base, count);
/* Update flash version information for 4Gb & above. */
- if (!IS_FWI2_CAPABLE(ha))
+ if (!IS_FWI2_CAPABLE(ha)) {
+ mutex_unlock(&ha->optrom_mutex);
return -EINVAL;
+ }
tmp_data = vmalloc(256);
if (!tmp_data) {
+ mutex_unlock(&ha->optrom_mutex);
ql_log(ql_log_warn, vha, 0x706b,
"Unable to allocate memory for VPD information update.\n");
return -ENOMEM;
@@ -548,6 +579,8 @@ qla2x00_sysfs_write_vpd(struct file *filp, struct kobject *kobj,
ha->isp_ops->get_flash_version(vha, tmp_data);
vfree(tmp_data);
+ mutex_unlock(&ha->optrom_mutex);
+
return count;
}
@@ -573,10 +606,15 @@ qla2x00_sysfs_read_sfp(struct file *filp, struct kobject *kobj,
if (!capable(CAP_SYS_ADMIN) || off != 0 || count < SFP_DEV_SIZE)
return 0;
- if (qla2x00_chip_is_down(vha))
+ mutex_lock(&vha->hw->optrom_mutex);
+ if (qla2x00_chip_is_down(vha)) {
+ mutex_unlock(&vha->hw->optrom_mutex);
return 0;
+ }
rval = qla2x00_read_sfp_dev(vha, buf, count);
+ mutex_unlock(&vha->hw->optrom_mutex);
+
if (rval)
return -EIO;
@@ -785,9 +823,11 @@ qla2x00_sysfs_read_xgmac_stats(struct file *filp, struct kobject *kobj,
if (unlikely(pci_channel_offline(ha->pdev)))
return 0;
-
- if (qla2x00_chip_is_down(vha))
+ mutex_lock(&vha->hw->optrom_mutex);
+ if (qla2x00_chip_is_down(vha)) {
+ mutex_unlock(&vha->hw->optrom_mutex);
return 0;
+ }
if (ha->xgmac_data)
goto do_read;
@@ -795,6 +835,7 @@ qla2x00_sysfs_read_xgmac_stats(struct file *filp, struct kobject *kobj,
ha->xgmac_data = dma_alloc_coherent(&ha->pdev->dev, XGMAC_DATA_SIZE,
&ha->xgmac_data_dma, GFP_KERNEL);
if (!ha->xgmac_data) {
+ mutex_unlock(&vha->hw->optrom_mutex);
ql_log(ql_log_warn, vha, 0x7076,
"Unable to allocate memory for XGMAC read-data.\n");
return 0;
@@ -806,6 +847,8 @@ do_read:
rval = qla2x00_get_xgmac_stats(vha, ha->xgmac_data_dma,
XGMAC_DATA_SIZE, &actual_size);
+
+ mutex_unlock(&vha->hw->optrom_mutex);
if (rval != QLA_SUCCESS) {
ql_log(ql_log_warn, vha, 0x7077,
"Unable to read XGMAC data (%x).\n", rval);
@@ -842,13 +885,16 @@ qla2x00_sysfs_read_dcbx_tlv(struct file *filp, struct kobject *kobj,
if (ha->dcbx_tlv)
goto do_read;
-
- if (qla2x00_chip_is_down(vha))
+ mutex_lock(&vha->hw->optrom_mutex);
+ if (qla2x00_chip_is_down(vha)) {
+ mutex_unlock(&vha->hw->optrom_mutex);
return 0;
+ }
ha->dcbx_tlv = dma_alloc_coherent(&ha->pdev->dev, DCBX_TLV_DATA_SIZE,
&ha->dcbx_tlv_dma, GFP_KERNEL);
if (!ha->dcbx_tlv) {
+ mutex_unlock(&vha->hw->optrom_mutex);
ql_log(ql_log_warn, vha, 0x7078,
"Unable to allocate memory for DCBX TLV read-data.\n");
return -ENOMEM;
@@ -859,6 +905,9 @@ do_read:
rval = qla2x00_get_dcbx_params(vha, ha->dcbx_tlv_dma,
DCBX_TLV_DATA_SIZE);
+
+ mutex_unlock(&vha->hw->optrom_mutex);
+
if (rval != QLA_SUCCESS) {
ql_log(ql_log_warn, vha, 0x7079,
"Unable to read DCBX TLV (%x).\n", rval);
@@ -1159,6 +1208,34 @@ qla2x00_zio_timer_store(struct device *dev, struct device_attribute *attr,
}
static ssize_t
+qla_zio_threshold_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+
+ return scnprintf(buf, PAGE_SIZE, "%d exchanges\n",
+ vha->hw->last_zio_threshold);
+}
+
+static ssize_t
+qla_zio_threshold_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+ int val = 0;
+
+ if (vha->hw->zio_mode != QLA_ZIO_MODE_6)
+ return -EINVAL;
+ if (sscanf(buf, "%d", &val) != 1)
+ return -EINVAL;
+ if (val < 0 || val > 256)
+ return -ERANGE;
+
+ atomic_set(&vha->hw->zio_threshold, val);
+ return strlen(buf);
+}
+
+static ssize_t
qla2x00_beacon_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -1184,15 +1261,17 @@ qla2x00_beacon_store(struct device *dev, struct device_attribute *attr,
if (IS_QLA2100(ha) || IS_QLA2200(ha))
return -EPERM;
+ if (sscanf(buf, "%d", &val) != 1)
+ return -EINVAL;
+
+ mutex_lock(&vha->hw->optrom_mutex);
if (qla2x00_chip_is_down(vha)) {
+ mutex_unlock(&vha->hw->optrom_mutex);
ql_log(ql_log_warn, vha, 0x707a,
"Abort ISP active -- ignoring beacon request.\n");
return -EBUSY;
}
- if (sscanf(buf, "%d", &val) != 1)
- return -EINVAL;
-
if (val)
rval = ha->isp_ops->beacon_on(vha);
else
@@ -1201,6 +1280,8 @@ qla2x00_beacon_store(struct device *dev, struct device_attribute *attr,
if (rval != QLA_SUCCESS)
count = 0;
+ mutex_unlock(&vha->hw->optrom_mutex);
+
return count;
}
@@ -1370,18 +1451,24 @@ qla2x00_thermal_temp_show(struct device *dev,
{
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
uint16_t temp = 0;
+ int rc;
+ mutex_lock(&vha->hw->optrom_mutex);
if (qla2x00_chip_is_down(vha)) {
+ mutex_unlock(&vha->hw->optrom_mutex);
ql_log(ql_log_warn, vha, 0x70dc, "ISP reset active.\n");
goto done;
}
if (vha->hw->flags.eeh_busy) {
+ mutex_unlock(&vha->hw->optrom_mutex);
ql_log(ql_log_warn, vha, 0x70dd, "PCI EEH busy.\n");
goto done;
}
- if (qla2x00_get_thermal_temp(vha, &temp) == QLA_SUCCESS)
+ rc = qla2x00_get_thermal_temp(vha, &temp);
+ mutex_unlock(&vha->hw->optrom_mutex);
+ if (rc == QLA_SUCCESS)
return scnprintf(buf, PAGE_SIZE, "%d\n", temp);
done:
@@ -1402,13 +1489,24 @@ qla2x00_fw_state_show(struct device *dev, struct device_attribute *attr,
return scnprintf(buf, PAGE_SIZE, "0x%x\n", pstate);
}
- if (qla2x00_chip_is_down(vha))
+ mutex_lock(&vha->hw->optrom_mutex);
+ if (qla2x00_chip_is_down(vha)) {
+ mutex_unlock(&vha->hw->optrom_mutex);
ql_log(ql_log_warn, vha, 0x707c,
"ISP reset active.\n");
- else if (!vha->hw->flags.eeh_busy)
- rval = qla2x00_get_firmware_state(vha, state);
- if (rval != QLA_SUCCESS)
+ goto out;
+ } else if (vha->hw->flags.eeh_busy) {
+ mutex_unlock(&vha->hw->optrom_mutex);
+ goto out;
+ }
+
+ rval = qla2x00_get_firmware_state(vha, state);
+ mutex_unlock(&vha->hw->optrom_mutex);
+out:
+ if (rval != QLA_SUCCESS) {
memset(state, -1, sizeof(state));
+ rval = qla2x00_get_firmware_state(vha, state);
+ }
return scnprintf(buf, PAGE_SIZE, "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
state[0], state[1], state[2], state[3], state[4], state[5]);
@@ -1534,6 +1632,433 @@ qla2x00_max_speed_sup_show(struct device *dev, struct device_attribute *attr,
ha->max_speed_sup ? "32Gps" : "16Gps");
}
+/* ----- */
+
+static ssize_t
+qlini_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+ int len = 0;
+
+ len += scnprintf(buf + len, PAGE_SIZE-len,
+ "Supported options: enabled | disabled | dual | exclusive\n");
+
+ /* --- */
+ len += scnprintf(buf + len, PAGE_SIZE-len, "Current selection: ");
+
+ switch (vha->qlini_mode) {
+ case QLA2XXX_INI_MODE_EXCLUSIVE:
+ len += scnprintf(buf + len, PAGE_SIZE-len,
+ QLA2XXX_INI_MODE_STR_EXCLUSIVE);
+ break;
+ case QLA2XXX_INI_MODE_DISABLED:
+ len += scnprintf(buf + len, PAGE_SIZE-len,
+ QLA2XXX_INI_MODE_STR_DISABLED);
+ break;
+ case QLA2XXX_INI_MODE_ENABLED:
+ len += scnprintf(buf + len, PAGE_SIZE-len,
+ QLA2XXX_INI_MODE_STR_ENABLED);
+ break;
+ case QLA2XXX_INI_MODE_DUAL:
+ len += scnprintf(buf + len, PAGE_SIZE-len,
+ QLA2XXX_INI_MODE_STR_DUAL);
+ break;
+ }
+ len += scnprintf(buf + len, PAGE_SIZE-len, "\n");
+
+ return len;
+}
+
+static char *mode_to_str[] = {
+ "exclusive",
+ "disabled",
+ "enabled",
+ "dual",
+};
+
+#define NEED_EXCH_OFFLOAD(_exchg) ((_exchg) > FW_DEF_EXCHANGES_CNT)
+static int qla_set_ini_mode(scsi_qla_host_t *vha, int op)
+{
+ int rc = 0;
+ enum {
+ NO_ACTION,
+ MODE_CHANGE_ACCEPT,
+ MODE_CHANGE_NO_ACTION,
+ TARGET_STILL_ACTIVE,
+ };
+ int action = NO_ACTION;
+ int set_mode = 0;
+ u8 eo_toggle = 0; /* exchange offload flipped */
+
+ switch (vha->qlini_mode) {
+ case QLA2XXX_INI_MODE_DISABLED:
+ switch (op) {
+ case QLA2XXX_INI_MODE_DISABLED:
+ if (qla_tgt_mode_enabled(vha)) {
+ if (NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld) !=
+ vha->hw->flags.exchoffld_enabled)
+ eo_toggle = 1;
+ if (((vha->ql2xexchoffld !=
+ vha->u_ql2xexchoffld) &&
+ NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld)) ||
+ eo_toggle) {
+ /*
+ * The number of exchange to be offload
+ * was tweaked or offload option was
+ * flipped
+ */
+ action = MODE_CHANGE_ACCEPT;
+ } else {
+ action = MODE_CHANGE_NO_ACTION;
+ }
+ } else {
+ action = MODE_CHANGE_NO_ACTION;
+ }
+ break;
+ case QLA2XXX_INI_MODE_EXCLUSIVE:
+ if (qla_tgt_mode_enabled(vha)) {
+ if (NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld) !=
+ vha->hw->flags.exchoffld_enabled)
+ eo_toggle = 1;
+ if (((vha->ql2xexchoffld !=
+ vha->u_ql2xexchoffld) &&
+ NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld)) ||
+ eo_toggle) {
+ /*
+ * The number of exchange to be offload
+ * was tweaked or offload option was
+ * flipped
+ */
+ action = MODE_CHANGE_ACCEPT;
+ } else {
+ action = MODE_CHANGE_NO_ACTION;
+ }
+ } else {
+ action = MODE_CHANGE_ACCEPT;
+ }
+ break;
+ case QLA2XXX_INI_MODE_DUAL:
+ action = MODE_CHANGE_ACCEPT;
+ /* active_mode is target only, reset it to dual */
+ if (qla_tgt_mode_enabled(vha)) {
+ set_mode = 1;
+ action = MODE_CHANGE_ACCEPT;
+ } else {
+ action = MODE_CHANGE_NO_ACTION;
+ }
+ break;
+
+ case QLA2XXX_INI_MODE_ENABLED:
+ if (qla_tgt_mode_enabled(vha))
+ action = TARGET_STILL_ACTIVE;
+ else {
+ action = MODE_CHANGE_ACCEPT;
+ set_mode = 1;
+ }
+ break;
+ }
+ break;
+
+ case QLA2XXX_INI_MODE_EXCLUSIVE:
+ switch (op) {
+ case QLA2XXX_INI_MODE_EXCLUSIVE:
+ if (qla_tgt_mode_enabled(vha)) {
+ if (NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld) !=
+ vha->hw->flags.exchoffld_enabled)
+ eo_toggle = 1;
+ if (((vha->ql2xexchoffld !=
+ vha->u_ql2xexchoffld) &&
+ NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld)) ||
+ eo_toggle)
+ /*
+ * The number of exchange to be offload
+ * was tweaked or offload option was
+ * flipped
+ */
+ action = MODE_CHANGE_ACCEPT;
+ else
+ action = NO_ACTION;
+ } else
+ action = NO_ACTION;
+
+ break;
+
+ case QLA2XXX_INI_MODE_DISABLED:
+ if (qla_tgt_mode_enabled(vha)) {
+ if (NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld) !=
+ vha->hw->flags.exchoffld_enabled)
+ eo_toggle = 1;
+ if (((vha->ql2xexchoffld !=
+ vha->u_ql2xexchoffld) &&
+ NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld)) ||
+ eo_toggle)
+ action = MODE_CHANGE_ACCEPT;
+ else
+ action = MODE_CHANGE_NO_ACTION;
+ } else
+ action = MODE_CHANGE_NO_ACTION;
+ break;
+
+ case QLA2XXX_INI_MODE_DUAL: /* exclusive -> dual */
+ if (qla_tgt_mode_enabled(vha)) {
+ action = MODE_CHANGE_ACCEPT;
+ set_mode = 1;
+ } else
+ action = MODE_CHANGE_ACCEPT;
+ break;
+
+ case QLA2XXX_INI_MODE_ENABLED:
+ if (qla_tgt_mode_enabled(vha))
+ action = TARGET_STILL_ACTIVE;
+ else {
+ if (vha->hw->flags.fw_started)
+ action = MODE_CHANGE_NO_ACTION;
+ else
+ action = MODE_CHANGE_ACCEPT;
+ }
+ break;
+ }
+ break;
+
+ case QLA2XXX_INI_MODE_ENABLED:
+ switch (op) {
+ case QLA2XXX_INI_MODE_ENABLED:
+ if (NEED_EXCH_OFFLOAD(vha->u_ql2xiniexchg) !=
+ vha->hw->flags.exchoffld_enabled)
+ eo_toggle = 1;
+ if (((vha->ql2xiniexchg != vha->u_ql2xiniexchg) &&
+ NEED_EXCH_OFFLOAD(vha->u_ql2xiniexchg)) ||
+ eo_toggle)
+ action = MODE_CHANGE_ACCEPT;
+ else
+ action = NO_ACTION;
+ break;
+ case QLA2XXX_INI_MODE_DUAL:
+ case QLA2XXX_INI_MODE_DISABLED:
+ action = MODE_CHANGE_ACCEPT;
+ break;
+ default:
+ action = MODE_CHANGE_NO_ACTION;
+ break;
+ }
+ break;
+
+ case QLA2XXX_INI_MODE_DUAL:
+ switch (op) {
+ case QLA2XXX_INI_MODE_DUAL:
+ if (qla_tgt_mode_enabled(vha) ||
+ qla_dual_mode_enabled(vha)) {
+ if (NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld +
+ vha->u_ql2xiniexchg) !=
+ vha->hw->flags.exchoffld_enabled)
+ eo_toggle = 1;
+
+ if ((((vha->ql2xexchoffld +
+ vha->ql2xiniexchg) !=
+ (vha->u_ql2xiniexchg +
+ vha->u_ql2xexchoffld)) &&
+ NEED_EXCH_OFFLOAD(vha->u_ql2xiniexchg +
+ vha->u_ql2xexchoffld)) || eo_toggle)
+ action = MODE_CHANGE_ACCEPT;
+ else
+ action = NO_ACTION;
+ } else {
+ if (NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld +
+ vha->u_ql2xiniexchg) !=
+ vha->hw->flags.exchoffld_enabled)
+ eo_toggle = 1;
+
+ if ((((vha->ql2xexchoffld + vha->ql2xiniexchg)
+ != (vha->u_ql2xiniexchg +
+ vha->u_ql2xexchoffld)) &&
+ NEED_EXCH_OFFLOAD(vha->u_ql2xiniexchg +
+ vha->u_ql2xexchoffld)) || eo_toggle)
+ action = MODE_CHANGE_NO_ACTION;
+ else
+ action = NO_ACTION;
+ }
+ break;
+
+ case QLA2XXX_INI_MODE_DISABLED:
+ if (qla_tgt_mode_enabled(vha) ||
+ qla_dual_mode_enabled(vha)) {
+ /* turning off initiator mode */
+ set_mode = 1;
+ action = MODE_CHANGE_ACCEPT;
+ } else {
+ action = MODE_CHANGE_NO_ACTION;
+ }
+ break;
+
+ case QLA2XXX_INI_MODE_EXCLUSIVE:
+ if (qla_tgt_mode_enabled(vha) ||
+ qla_dual_mode_enabled(vha)) {
+ set_mode = 1;
+ action = MODE_CHANGE_ACCEPT;
+ } else {
+ action = MODE_CHANGE_ACCEPT;
+ }
+ break;
+
+ case QLA2XXX_INI_MODE_ENABLED:
+ if (qla_tgt_mode_enabled(vha) ||
+ qla_dual_mode_enabled(vha)) {
+ action = TARGET_STILL_ACTIVE;
+ } else {
+ action = MODE_CHANGE_ACCEPT;
+ }
+ }
+ break;
+ }
+
+ switch (action) {
+ case MODE_CHANGE_ACCEPT:
+ ql_log(ql_log_warn, vha, 0xffff,
+ "Mode change accepted. From %s to %s, Tgt exchg %d|%d. ini exchg %d|%d\n",
+ mode_to_str[vha->qlini_mode], mode_to_str[op],
+ vha->ql2xexchoffld, vha->u_ql2xexchoffld,
+ vha->ql2xiniexchg, vha->u_ql2xiniexchg);
+
+ vha->qlini_mode = op;
+ vha->ql2xexchoffld = vha->u_ql2xexchoffld;
+ vha->ql2xiniexchg = vha->u_ql2xiniexchg;
+ if (set_mode)
+ qlt_set_mode(vha);
+ vha->flags.online = 1;
+ set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ break;
+
+ case MODE_CHANGE_NO_ACTION:
+ ql_log(ql_log_warn, vha, 0xffff,
+ "Mode is set. No action taken. From %s to %s, Tgt exchg %d|%d. ini exchg %d|%d\n",
+ mode_to_str[vha->qlini_mode], mode_to_str[op],
+ vha->ql2xexchoffld, vha->u_ql2xexchoffld,
+ vha->ql2xiniexchg, vha->u_ql2xiniexchg);
+ vha->qlini_mode = op;
+ vha->ql2xexchoffld = vha->u_ql2xexchoffld;
+ vha->ql2xiniexchg = vha->u_ql2xiniexchg;
+ break;
+
+ case TARGET_STILL_ACTIVE:
+ ql_log(ql_log_warn, vha, 0xffff,
+ "Target Mode is active. Unable to change Mode.\n");
+ break;
+
+ case NO_ACTION:
+ default:
+ ql_log(ql_log_warn, vha, 0xffff,
+ "Mode unchange. No action taken. %d|%d pct %d|%d.\n",
+ vha->qlini_mode, op,
+ vha->ql2xexchoffld, vha->u_ql2xexchoffld);
+ break;
+ }
+
+ return rc;
+}
+
+static ssize_t
+qlini_mode_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+ int ini;
+
+ if (!buf)
+ return -EINVAL;
+
+ if (strncasecmp(QLA2XXX_INI_MODE_STR_EXCLUSIVE, buf,
+ strlen(QLA2XXX_INI_MODE_STR_EXCLUSIVE)) == 0)
+ ini = QLA2XXX_INI_MODE_EXCLUSIVE;
+ else if (strncasecmp(QLA2XXX_INI_MODE_STR_DISABLED, buf,
+ strlen(QLA2XXX_INI_MODE_STR_DISABLED)) == 0)
+ ini = QLA2XXX_INI_MODE_DISABLED;
+ else if (strncasecmp(QLA2XXX_INI_MODE_STR_ENABLED, buf,
+ strlen(QLA2XXX_INI_MODE_STR_ENABLED)) == 0)
+ ini = QLA2XXX_INI_MODE_ENABLED;
+ else if (strncasecmp(QLA2XXX_INI_MODE_STR_DUAL, buf,
+ strlen(QLA2XXX_INI_MODE_STR_DUAL)) == 0)
+ ini = QLA2XXX_INI_MODE_DUAL;
+ else
+ return -EINVAL;
+
+ qla_set_ini_mode(vha, ini);
+ return strlen(buf);
+}
+
+static ssize_t
+ql2xexchoffld_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+ int len = 0;
+
+ len += scnprintf(buf + len, PAGE_SIZE-len,
+ "target exchange: new %d : current: %d\n\n",
+ vha->u_ql2xexchoffld, vha->ql2xexchoffld);
+
+ len += scnprintf(buf + len, PAGE_SIZE-len,
+ "Please (re)set operating mode via \"/sys/class/scsi_host/host%ld/qlini_mode\" to load new setting.\n",
+ vha->host_no);
+
+ return len;
+}
+
+static ssize_t
+ql2xexchoffld_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+ int val = 0;
+
+ if (sscanf(buf, "%d", &val) != 1)
+ return -EINVAL;
+
+ if (val > FW_MAX_EXCHANGES_CNT)
+ val = FW_MAX_EXCHANGES_CNT;
+ else if (val < 0)
+ val = 0;
+
+ vha->u_ql2xexchoffld = val;
+ return strlen(buf);
+}
+
+static ssize_t
+ql2xiniexchg_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+ int len = 0;
+
+ len += scnprintf(buf + len, PAGE_SIZE-len,
+ "target exchange: new %d : current: %d\n\n",
+ vha->u_ql2xiniexchg, vha->ql2xiniexchg);
+
+ len += scnprintf(buf + len, PAGE_SIZE-len,
+ "Please (re)set operating mode via \"/sys/class/scsi_host/host%ld/qlini_mode\" to load new setting.\n",
+ vha->host_no);
+
+ return len;
+}
+
+static ssize_t
+ql2xiniexchg_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+ int val = 0;
+
+ if (sscanf(buf, "%d", &val) != 1)
+ return -EINVAL;
+
+ if (val > FW_MAX_EXCHANGES_CNT)
+ val = FW_MAX_EXCHANGES_CNT;
+ else if (val < 0)
+ val = 0;
+
+ vha->u_ql2xiniexchg = val;
+ return strlen(buf);
+}
+
static DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show, NULL);
static DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL);
static DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL);
@@ -1581,6 +2106,13 @@ static DEVICE_ATTR(allow_cna_fw_dump, S_IRUGO | S_IWUSR,
static DEVICE_ATTR(pep_version, S_IRUGO, qla2x00_pep_version_show, NULL);
static DEVICE_ATTR(min_link_speed, S_IRUGO, qla2x00_min_link_speed_show, NULL);
static DEVICE_ATTR(max_speed_sup, S_IRUGO, qla2x00_max_speed_sup_show, NULL);
+static DEVICE_ATTR(zio_threshold, 0644,
+ qla_zio_threshold_show,
+ qla_zio_threshold_store);
+static DEVICE_ATTR_RW(qlini_mode);
+static DEVICE_ATTR_RW(ql2xexchoffld);
+static DEVICE_ATTR_RW(ql2xiniexchg);
+
struct device_attribute *qla2x00_host_attrs[] = {
&dev_attr_driver_version,
@@ -1617,9 +2149,28 @@ struct device_attribute *qla2x00_host_attrs[] = {
&dev_attr_pep_version,
&dev_attr_min_link_speed,
&dev_attr_max_speed_sup,
+ &dev_attr_zio_threshold,
+ NULL, /* reserve for qlini_mode */
+ NULL, /* reserve for ql2xiniexchg */
+ NULL, /* reserve for ql2xexchoffld */
NULL,
};
+void qla_insert_tgt_attrs(void)
+{
+ struct device_attribute **attr;
+
+ /* advance to empty slot */
+ for (attr = &qla2x00_host_attrs[0]; *attr; ++attr)
+ continue;
+
+ *attr = &dev_attr_qlini_mode;
+ attr++;
+ *attr = &dev_attr_ql2xiniexchg;
+ attr++;
+ *attr = &dev_attr_ql2xexchoffld;
+}
+
/* Host attributes. */
static void
diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
index c11a89be292c..4a9fd8d944d6 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.c
+++ b/drivers/scsi/qla2xxx/qla_bsg.c
@@ -2487,7 +2487,7 @@ qla24xx_bsg_request(struct bsg_job *bsg_job)
vha = shost_priv(host);
}
- if (qla2x00_reset_active(vha)) {
+ if (qla2x00_chip_is_down(vha)) {
ql_dbg(ql_dbg_user, vha, 0x709f,
"BSG: ISP abort active/needed -- cmd=%d.\n",
bsg_request->msgcode);
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index a9dc9c4a6382..26b93c563f92 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -262,8 +262,8 @@ struct name_list_extended {
struct get_name_list_extended *l;
dma_addr_t ldma;
struct list_head fcports;
- spinlock_t fcports_lock;
u32 size;
+ u8 sent;
};
/*
* Timeout timer counts in seconds
@@ -519,6 +519,7 @@ struct srb_iocb {
enum {
TYPE_SRB,
TYPE_TGT_CMD,
+ TYPE_TGT_TMCMD, /* task management */
};
typedef struct srb {
@@ -2280,7 +2281,6 @@ struct ct_sns_desc {
enum discovery_state {
DSC_DELETED,
DSC_GNN_ID,
- DSC_GID_PN,
DSC_GNL,
DSC_LOGIN_PEND,
DSC_LOGIN_FAILED,
@@ -2305,7 +2305,6 @@ enum login_state { /* FW control Target side */
enum fcport_mgt_event {
FCME_RELOGIN = 1,
FCME_RSCN,
- FCME_GIDPN_DONE,
FCME_PLOGI_DONE, /* Initiator side sent LLIOCB */
FCME_PRLI_DONE,
FCME_GNL_DONE,
@@ -2351,7 +2350,7 @@ typedef struct fc_port {
unsigned int login_succ:1;
unsigned int query:1;
unsigned int id_changed:1;
- unsigned int rscn_rcvd:1;
+ unsigned int scan_needed:1;
struct work_struct nvme_del_work;
struct completion nvme_del_done;
@@ -2375,11 +2374,13 @@ typedef struct fc_port {
unsigned long expires;
struct list_head del_list_entry;
struct work_struct free_work;
-
+ struct work_struct reg_work;
+ uint64_t jiffies_at_registration;
struct qlt_plogi_ack_t *plogi_link[QLT_PLOGI_LINK_MAX];
uint16_t tgt_id;
uint16_t old_tgt_id;
+ uint16_t sec_since_registration;
uint8_t fcp_prio;
@@ -2412,6 +2413,7 @@ typedef struct fc_port {
struct qla_tgt_sess *tgt_session;
struct ct_sns_desc ct_desc;
enum discovery_state disc_state;
+ enum discovery_state next_disc_state;
enum login_state fw_login_state;
unsigned long dm_login_expire;
unsigned long plogi_nack_done_deadline;
@@ -3212,17 +3214,14 @@ enum qla_work_type {
QLA_EVT_ASYNC_LOGOUT,
QLA_EVT_ASYNC_LOGOUT_DONE,
QLA_EVT_ASYNC_ADISC,
- QLA_EVT_ASYNC_ADISC_DONE,
QLA_EVT_UEVENT,
QLA_EVT_AENFX,
- QLA_EVT_GIDPN,
QLA_EVT_GPNID,
QLA_EVT_UNMAP,
QLA_EVT_NEW_SESS,
QLA_EVT_GPDB,
QLA_EVT_PRLI,
QLA_EVT_GPSC,
- QLA_EVT_UPD_FCPORT,
QLA_EVT_GNL,
QLA_EVT_NACK,
QLA_EVT_RELOGIN,
@@ -3483,6 +3482,9 @@ struct qla_qpair {
struct list_head qp_list_elem; /* vha->qp_list */
struct list_head hints_list;
uint16_t cpuid;
+ uint16_t retry_term_cnt;
+ uint32_t retry_term_exchg_addr;
+ uint64_t retry_term_jiff;
struct qla_tgt_counters tgt_counters;
};
@@ -4184,6 +4186,10 @@ struct qla_hw_data {
atomic_t nvme_active_aen_cnt;
uint16_t nvme_last_rptd_aen; /* Last recorded aen count */
+
+ atomic_t zio_threshold;
+ uint16_t last_zio_threshold;
+#define DEFAULT_ZIO_THRESHOLD 64
};
#define FW_ABILITY_MAX_SPEED_MASK 0xFUL
@@ -4263,10 +4269,11 @@ typedef struct scsi_qla_host {
#define FX00_CRITEMP_RECOVERY 25
#define FX00_HOST_INFO_RESEND 26
#define QPAIR_ONLINE_CHECK_NEEDED 27
-#define SET_ZIO_THRESHOLD_NEEDED 28
+#define SET_NVME_ZIO_THRESHOLD_NEEDED 28
#define DETECT_SFP_CHANGE 29
#define N2N_LOGIN_NEEDED 30
#define IOCB_WORK_ACTIVE 31
+#define SET_ZIO_THRESHOLD_NEEDED 32
unsigned long pci_flags;
#define PFLG_DISCONNECTED 0 /* PCI device removed */
@@ -4369,6 +4376,13 @@ typedef struct scsi_qla_host {
atomic_t vref_count;
struct qla8044_reset_template reset_tmplt;
uint16_t bbcr;
+
+ uint16_t u_ql2xexchoffld;
+ uint16_t u_ql2xiniexchg;
+ uint16_t qlini_mode;
+ uint16_t ql2xexchoffld;
+ uint16_t ql2xiniexchg;
+
struct name_list_extended gnl;
/* Count of active session/fcport */
int fcport_count;
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 178974896b5c..3673fcdb033a 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -54,7 +54,7 @@ extern void qla2x00_abort_isp_cleanup(scsi_qla_host_t *);
extern void qla2x00_quiesce_io(scsi_qla_host_t *);
extern void qla2x00_update_fcport(scsi_qla_host_t *, fc_port_t *);
-
+void qla_register_fcport_fn(struct work_struct *);
extern void qla2x00_alloc_fw_dump(scsi_qla_host_t *);
extern void qla2x00_try_to_stop_firmware(scsi_qla_host_t *);
@@ -73,8 +73,6 @@ extern void qla2x00_async_login_done(struct scsi_qla_host *, fc_port_t *,
uint16_t *);
extern void qla2x00_async_logout_done(struct scsi_qla_host *, fc_port_t *,
uint16_t *);
-extern void qla2x00_async_adisc_done(struct scsi_qla_host *, fc_port_t *,
- uint16_t *);
struct qla_work_evt *qla2x00_alloc_work(struct scsi_qla_host *,
enum qla_work_type);
extern int qla24xx_async_gnl(struct scsi_qla_host *, fc_port_t *);
@@ -109,6 +107,7 @@ int qla24xx_post_newsess_work(struct scsi_qla_host *, port_id_t *, u8 *, u8*,
int qla24xx_fcport_handle_login(struct scsi_qla_host *, fc_port_t *);
int qla24xx_detect_sfp(scsi_qla_host_t *vha);
int qla24xx_post_gpdb_work(struct scsi_qla_host *, fc_port_t *, u8);
+
void qla2x00_async_prlo_done(struct scsi_qla_host *, fc_port_t *,
uint16_t *);
extern int qla2x00_post_async_prlo_work(struct scsi_qla_host *, fc_port_t *,
@@ -118,6 +117,8 @@ extern int qla2x00_post_async_prlo_done_work(struct scsi_qla_host *,
int qla_post_iidma_work(struct scsi_qla_host *vha, fc_port_t *fcport);
void qla_do_iidma_work(struct scsi_qla_host *vha, fc_port_t *fcport);
int qla2x00_reserve_mgmt_server_loop_id(scsi_qla_host_t *);
+void qla_rscn_replay(fc_port_t *fcport);
+
/*
* Global Data in qla_os.c source file.
*/
@@ -158,6 +159,7 @@ extern int ql2xnvmeenable;
extern int ql2xautodetectsfp;
extern int ql2xenablemsix;
extern int qla2xuseresexchforels;
+extern int ql2xexlogins;
extern int qla2x00_loop_reset(scsi_qla_host_t *);
extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int);
@@ -208,7 +210,7 @@ extern void qla2x00_disable_board_on_pci_error(struct work_struct *);
extern void qla2x00_sp_compl(void *, int);
extern void qla2xxx_qpair_sp_free_dma(void *);
extern void qla2xxx_qpair_sp_compl(void *, int);
-extern int qla24xx_post_upd_fcport_work(struct scsi_qla_host *, fc_port_t *);
+extern void qla24xx_sched_upd_fcport(fc_port_t *);
void qla2x00_handle_login_done_event(struct scsi_qla_host *, fc_port_t *,
uint16_t *);
int qla24xx_post_gnl_work(struct scsi_qla_host *, fc_port_t *);
@@ -644,9 +646,6 @@ extern void qla2x00_get_sym_node_name(scsi_qla_host_t *, uint8_t *, size_t);
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 int qla24xx_async_gidpn(scsi_qla_host_t *, fc_port_t *);
-int qla24xx_post_gidpn_work(struct scsi_qla_host *, fc_port_t *);
-void qla24xx_handle_gidpn_event(scsi_qla_host_t *, struct event_arg *);
extern void qla2x00_free_fcport(fc_port_t *);
@@ -677,6 +676,7 @@ void qla_scan_work_fn(struct work_struct *);
*/
struct device_attribute;
extern struct device_attribute *qla2x00_host_attrs[];
+extern struct device_attribute *qla2x00_host_attrs_dm[];
struct fc_function_template;
extern struct fc_function_template qla2xxx_transport_functions;
extern struct fc_function_template qla2xxx_transport_vport_functions;
@@ -690,7 +690,7 @@ extern int qla2x00_echo_test(scsi_qla_host_t *,
extern int qla24xx_update_all_fcp_prio(scsi_qla_host_t *);
extern int qla24xx_fcp_prio_cfg_valid(scsi_qla_host_t *,
struct qla_fcp_prio_cfg *, uint8_t);
-
+void qla_insert_tgt_attrs(void);
/*
* Global Function Prototypes in qla_dfs.c source file.
*/
@@ -897,5 +897,6 @@ void qlt_unknown_atio_work_fn(struct work_struct *);
void qlt_update_host_map(struct scsi_qla_host *, port_id_t);
void qlt_remove_target_resources(struct qla_hw_data *);
void qlt_clr_qp_table(struct scsi_qla_host *vha);
+void qlt_set_mode(struct scsi_qla_host *);
#endif /* _QLA_GBL_H */
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index a0038d879b9d..90cfa394f942 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -2973,237 +2973,6 @@ qla2x00_gff_id(scsi_qla_host_t *vha, sw_info_t *list)
}
}
-/* GID_PN completion processing. */
-void qla24xx_handle_gidpn_event(scsi_qla_host_t *vha, struct event_arg *ea)
-{
- fc_port_t *fcport = ea->fcport;
-
- ql_dbg(ql_dbg_disc, vha, 0x201d,
- "%s %8phC DS %d LS %d rc %d login %d|%d rscn %d|%d lid %d\n",
- __func__, fcport->port_name, fcport->disc_state,
- fcport->fw_login_state, ea->rc, fcport->login_gen, ea->sp->gen2,
- fcport->rscn_gen, ea->sp->gen1, fcport->loop_id);
-
- if (fcport->disc_state == DSC_DELETE_PEND)
- return;
-
- if (ea->sp->gen2 != fcport->login_gen) {
- /* PLOGI/PRLI/LOGO came in while cmd was out.*/
- ql_dbg(ql_dbg_disc, vha, 0x201e,
- "%s %8phC generation changed rscn %d|%d n",
- __func__, fcport->port_name, fcport->last_rscn_gen,
- fcport->rscn_gen);
- return;
- }
-
- if (!ea->rc) {
- if (ea->sp->gen1 == fcport->rscn_gen) {
- fcport->scan_state = QLA_FCPORT_FOUND;
- fcport->flags |= FCF_FABRIC_DEVICE;
-
- if (fcport->d_id.b24 == ea->id.b24) {
- /* cable plugged into the same place */
- switch (vha->host->active_mode) {
- case MODE_TARGET:
- if (fcport->fw_login_state ==
- DSC_LS_PRLI_COMP) {
- u16 data[2];
- /*
- * Late RSCN was delivered.
- * Remote port already login'ed.
- */
- ql_dbg(ql_dbg_disc, vha, 0x201f,
- "%s %d %8phC post adisc\n",
- __func__, __LINE__,
- fcport->port_name);
- data[0] = data[1] = 0;
- qla2x00_post_async_adisc_work(
- vha, fcport, data);
- }
- break;
- case MODE_INITIATOR:
- case MODE_DUAL:
- default:
- ql_dbg(ql_dbg_disc, vha, 0x201f,
- "%s %d %8phC post %s\n", __func__,
- __LINE__, fcport->port_name,
- (atomic_read(&fcport->state) ==
- FCS_ONLINE) ? "adisc" : "gnl");
-
- if (atomic_read(&fcport->state) ==
- FCS_ONLINE) {
- u16 data[2];
-
- data[0] = data[1] = 0;
- qla2x00_post_async_adisc_work(
- vha, fcport, data);
- } else {
- qla24xx_post_gnl_work(vha,
- fcport);
- }
- break;
- }
- } else { /* fcport->d_id.b24 != ea->id.b24 */
- fcport->d_id.b24 = ea->id.b24;
- fcport->id_changed = 1;
- if (fcport->deleted != QLA_SESS_DELETED) {
- ql_dbg(ql_dbg_disc, vha, 0x2021,
- "%s %d %8phC post del sess\n",
- __func__, __LINE__, fcport->port_name);
- qlt_schedule_sess_for_deletion(fcport);
- }
- }
- } else { /* ea->sp->gen1 != fcport->rscn_gen */
- ql_dbg(ql_dbg_disc, vha, 0x2022,
- "%s %d %8phC post gidpn\n",
- __func__, __LINE__, fcport->port_name);
- /* rscn came in while cmd was out */
- qla24xx_post_gidpn_work(vha, fcport);
- }
- } else { /* ea->rc */
- /* cable pulled */
- if (ea->sp->gen1 == fcport->rscn_gen) {
- if (ea->sp->gen2 == fcport->login_gen) {
- ql_dbg(ql_dbg_disc, vha, 0x2042,
- "%s %d %8phC post del sess\n", __func__,
- __LINE__, fcport->port_name);
- qlt_schedule_sess_for_deletion(fcport);
- } else {
- ql_dbg(ql_dbg_disc, vha, 0x2045,
- "%s %d %8phC login\n", __func__, __LINE__,
- fcport->port_name);
- qla24xx_fcport_handle_login(vha, fcport);
- }
- } else {
- ql_dbg(ql_dbg_disc, vha, 0x2049,
- "%s %d %8phC post gidpn\n", __func__, __LINE__,
- fcport->port_name);
- qla24xx_post_gidpn_work(vha, fcport);
- }
- }
-} /* gidpn_event */
-
-static void qla2x00_async_gidpn_sp_done(void *s, int res)
-{
- struct srb *sp = s;
- struct scsi_qla_host *vha = sp->vha;
- fc_port_t *fcport = sp->fcport;
- u8 *id = fcport->ct_desc.ct_sns->p.rsp.rsp.gid_pn.port_id;
- struct event_arg ea;
-
- fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE);
-
- memset(&ea, 0, sizeof(ea));
- ea.fcport = fcport;
- ea.id.b.domain = id[0];
- ea.id.b.area = id[1];
- ea.id.b.al_pa = id[2];
- ea.sp = sp;
- ea.rc = res;
- ea.event = FCME_GIDPN_DONE;
-
- if (res == QLA_FUNCTION_TIMEOUT) {
- ql_dbg(ql_dbg_disc, sp->vha, 0xffff,
- "Async done-%s WWPN %8phC timed out.\n",
- sp->name, fcport->port_name);
- qla24xx_post_gidpn_work(sp->vha, fcport);
- sp->free(sp);
- return;
- } else if (res) {
- ql_dbg(ql_dbg_disc, sp->vha, 0xffff,
- "Async done-%s fail res %x, WWPN %8phC\n",
- sp->name, res, fcport->port_name);
- } else {
- ql_dbg(ql_dbg_disc, vha, 0x204f,
- "Async done-%s good WWPN %8phC ID %3phC\n",
- sp->name, fcport->port_name, id);
- }
-
- qla2x00_fcport_event_handler(vha, &ea);
-
- sp->free(sp);
-}
-
-int qla24xx_async_gidpn(scsi_qla_host_t *vha, fc_port_t *fcport)
-{
- int rval = QLA_FUNCTION_FAILED;
- struct ct_sns_req *ct_req;
- srb_t *sp;
-
- if (!vha->flags.online || (fcport->flags & FCF_ASYNC_SENT))
- return rval;
-
- fcport->disc_state = DSC_GID_PN;
- fcport->scan_state = QLA_FCPORT_SCAN;
- sp = qla2x00_get_sp(vha, fcport, GFP_ATOMIC);
- if (!sp)
- goto done;
-
- fcport->flags |= FCF_ASYNC_SENT;
- sp->type = SRB_CT_PTHRU_CMD;
- sp->name = "gidpn";
- sp->gen1 = fcport->rscn_gen;
- sp->gen2 = fcport->login_gen;
-
- qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2);
-
- /* CT_IU preamble */
- ct_req = qla2x00_prep_ct_req(fcport->ct_desc.ct_sns, GID_PN_CMD,
- GID_PN_RSP_SIZE);
-
- /* GIDPN req */
- memcpy(ct_req->req.gid_pn.port_name, fcport->port_name,
- WWN_SIZE);
-
- /* req & rsp use the same buffer */
- sp->u.iocb_cmd.u.ctarg.req = fcport->ct_desc.ct_sns;
- sp->u.iocb_cmd.u.ctarg.req_dma = fcport->ct_desc.ct_sns_dma;
- sp->u.iocb_cmd.u.ctarg.rsp = fcport->ct_desc.ct_sns;
- sp->u.iocb_cmd.u.ctarg.rsp_dma = fcport->ct_desc.ct_sns_dma;
- sp->u.iocb_cmd.u.ctarg.req_size = GID_PN_REQ_SIZE;
- sp->u.iocb_cmd.u.ctarg.rsp_size = GID_PN_RSP_SIZE;
- sp->u.iocb_cmd.u.ctarg.nport_handle = NPH_SNS;
-
- sp->u.iocb_cmd.timeout = qla2x00_async_iocb_timeout;
- sp->done = qla2x00_async_gidpn_sp_done;
-
- rval = qla2x00_start_sp(sp);
- if (rval != QLA_SUCCESS)
- goto done_free_sp;
-
- ql_dbg(ql_dbg_disc, vha, 0x20a4,
- "Async-%s - %8phC hdl=%x loopid=%x portid %02x%02x%02x.\n",
- sp->name, fcport->port_name,
- sp->handle, fcport->loop_id, fcport->d_id.b.domain,
- fcport->d_id.b.area, fcport->d_id.b.al_pa);
- return rval;
-
-done_free_sp:
- sp->free(sp);
-done:
- fcport->flags &= ~FCF_ASYNC_ACTIVE;
- return rval;
-}
-
-int qla24xx_post_gidpn_work(struct scsi_qla_host *vha, fc_port_t *fcport)
-{
- struct qla_work_evt *e;
- int ls;
-
- ls = atomic_read(&vha->loop_state);
- if (((ls != LOOP_READY) && (ls != LOOP_UP)) ||
- test_bit(UNLOADING, &vha->dpc_flags))
- return 0;
-
- e = qla2x00_alloc_work(vha, QLA_EVT_GIDPN);
- if (!e)
- return QLA_FUNCTION_FAILED;
-
- e->u.fcport.fcport = fcport;
- fcport->flags |= FCF_ASYNC_ACTIVE;
- return qla2x00_post_work(vha, e);
-}
-
int qla24xx_post_gpsc_work(struct scsi_qla_host *vha, fc_port_t *fcport)
{
struct qla_work_evt *e;
@@ -3237,9 +3006,6 @@ void qla24xx_handle_gpsc_event(scsi_qla_host_t *vha, struct event_arg *ea)
__func__, fcport->port_name);
return;
} else if (ea->sp->gen1 != fcport->rscn_gen) {
- ql_dbg(ql_dbg_disc, vha, 0x20d4, "%s %d %8phC post gidpn\n",
- __func__, __LINE__, fcport->port_name);
- qla24xx_post_gidpn_work(vha, fcport);
return;
}
@@ -3261,6 +3027,9 @@ static void qla24xx_async_gpsc_sp_done(void *s, int res)
"Async done-%s res %x, WWPN %8phC \n",
sp->name, res, fcport->port_name);
+ if (res == QLA_FUNCTION_TIMEOUT)
+ return;
+
if (res == (DID_ERROR << 16)) {
/* entry status error */
goto done;
@@ -3272,7 +3041,7 @@ static void qla24xx_async_gpsc_sp_done(void *s, int res)
ql_dbg(ql_dbg_disc, vha, 0x2019,
"GPSC command unsupported, disabling query.\n");
ha->flags.gpsc_supported = 0;
- res = QLA_SUCCESS;
+ goto done;
}
} else {
switch (be16_to_cpu(ct_rsp->rsp.gpsc.speed)) {
@@ -3305,7 +3074,6 @@ static void qla24xx_async_gpsc_sp_done(void *s, int res)
be16_to_cpu(ct_rsp->rsp.gpsc.speeds),
be16_to_cpu(ct_rsp->rsp.gpsc.speed));
}
-done:
memset(&ea, 0, sizeof(ea));
ea.event = FCME_GPSC_DONE;
ea.rc = res;
@@ -3313,6 +3081,7 @@ done:
ea.sp = sp;
qla2x00_fcport_event_handler(vha, &ea);
+done:
sp->free(sp);
}
@@ -3355,15 +3124,15 @@ int qla24xx_async_gpsc(scsi_qla_host_t *vha, fc_port_t *fcport)
sp->u.iocb_cmd.timeout = qla2x00_async_iocb_timeout;
sp->done = qla24xx_async_gpsc_sp_done;
- rval = qla2x00_start_sp(sp);
- if (rval != QLA_SUCCESS)
- goto done_free_sp;
-
ql_dbg(ql_dbg_disc, vha, 0x205e,
"Async-%s %8phC hdl=%x loopid=%x portid=%02x%02x%02x.\n",
sp->name, fcport->port_name, sp->handle,
fcport->loop_id, fcport->d_id.b.domain,
fcport->d_id.b.area, fcport->d_id.b.al_pa);
+
+ rval = qla2x00_start_sp(sp);
+ if (rval != QLA_SUCCESS)
+ goto done_free_sp;
return rval;
done_free_sp:
@@ -3442,26 +3211,10 @@ void qla24xx_handle_gpnid_event(scsi_qla_host_t *vha, struct event_arg *ea)
if (ea->rc) {
/* cable is disconnected */
list_for_each_entry_safe(fcport, t, &vha->vp_fcports, list) {
- if (fcport->d_id.b24 == ea->id.b24) {
- ql_dbg(ql_dbg_disc, vha, 0xffff,
- "%s %d %8phC DS %d\n",
- __func__, __LINE__,
- fcport->port_name,
- fcport->disc_state);
+ if (fcport->d_id.b24 == ea->id.b24)
fcport->scan_state = QLA_FCPORT_SCAN;
- switch (fcport->disc_state) {
- case DSC_DELETED:
- case DSC_DELETE_PEND:
- break;
- default:
- ql_dbg(ql_dbg_disc, vha, 0xffff,
- "%s %d %8phC post del sess\n",
- __func__, __LINE__,
- fcport->port_name);
- qlt_schedule_sess_for_deletion(fcport);
- break;
- }
- }
+
+ qlt_schedule_sess_for_deletion(fcport);
}
} else {
/* cable is connected */
@@ -3470,34 +3223,19 @@ void qla24xx_handle_gpnid_event(scsi_qla_host_t *vha, struct event_arg *ea)
list_for_each_entry_safe(conflict, t, &vha->vp_fcports,
list) {
if ((conflict->d_id.b24 == ea->id.b24) &&
- (fcport != conflict)) {
- /* 2 fcports with conflict Nport ID or
+ (fcport != conflict))
+ /*
+ * 2 fcports with conflict Nport ID or
* an existing fcport is having nport ID
* conflict with new fcport.
*/
- ql_dbg(ql_dbg_disc, vha, 0xffff,
- "%s %d %8phC DS %d\n",
- __func__, __LINE__,
- conflict->port_name,
- conflict->disc_state);
conflict->scan_state = QLA_FCPORT_SCAN;
- switch (conflict->disc_state) {
- case DSC_DELETED:
- case DSC_DELETE_PEND:
- break;
- default:
- ql_dbg(ql_dbg_disc, vha, 0xffff,
- "%s %d %8phC post del sess\n",
- __func__, __LINE__,
- conflict->port_name);
- qlt_schedule_sess_for_deletion
- (conflict);
- break;
- }
- }
+
+ qlt_schedule_sess_for_deletion(conflict);
}
+ fcport->scan_needed = 0;
fcport->rscn_gen++;
fcport->scan_state = QLA_FCPORT_FOUND;
fcport->flags |= FCF_FABRIC_DEVICE;
@@ -3548,19 +3286,7 @@ void qla24xx_handle_gpnid_event(scsi_qla_host_t *vha, struct event_arg *ea)
conflict->disc_state);
conflict->scan_state = QLA_FCPORT_SCAN;
- switch (conflict->disc_state) {
- case DSC_DELETED:
- case DSC_DELETE_PEND:
- break;
- default:
- ql_dbg(ql_dbg_disc, vha, 0xffff,
- "%s %d %8phC post del sess\n",
- __func__, __LINE__,
- conflict->port_name);
- qlt_schedule_sess_for_deletion
- (conflict);
- break;
- }
+ qlt_schedule_sess_for_deletion(conflict);
}
}
@@ -3724,13 +3450,14 @@ int qla24xx_async_gpnid(scsi_qla_host_t *vha, port_id_t *id)
sp->u.iocb_cmd.timeout = qla2x00_async_iocb_timeout;
sp->done = qla2x00_async_gpnid_sp_done;
+ ql_dbg(ql_dbg_disc, vha, 0x2067,
+ "Async-%s hdl=%x ID %3phC.\n", sp->name,
+ sp->handle, ct_req->req.port_id.port_id);
+
rval = qla2x00_start_sp(sp);
if (rval != QLA_SUCCESS)
goto done_free_sp;
- ql_dbg(ql_dbg_disc, vha, 0x2067,
- "Async-%s hdl=%x ID %3phC.\n", sp->name,
- sp->handle, ct_req->req.port_id.port_id);
return rval;
done_free_sp:
@@ -3896,9 +3623,10 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp)
fc_port_t *fcport;
u32 i, rc;
bool found;
- struct fab_scan_rp *rp;
+ struct fab_scan_rp *rp, *trp;
unsigned long flags;
u8 recheck = 0;
+ u16 dup = 0, dup_cnt = 0;
ql_dbg(ql_dbg_disc, vha, 0xffff,
"%s enter\n", __func__);
@@ -3929,6 +3657,7 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp)
for (i = 0; i < vha->hw->max_fibre_devices; i++) {
u64 wwn;
+ int k;
rp = &vha->scan.l[i];
found = false;
@@ -3937,6 +3666,20 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp)
if (wwn == 0)
continue;
+ /* Remove duplicate NPORT ID entries from switch data base */
+ for (k = i + 1; k < vha->hw->max_fibre_devices; k++) {
+ trp = &vha->scan.l[k];
+ if (rp->id.b24 == trp->id.b24) {
+ dup = 1;
+ dup_cnt++;
+ ql_dbg(ql_dbg_disc + ql_dbg_verbose,
+ vha, 0xffff,
+ "Detected duplicate NPORT ID from switch data base: ID %06x WWN %8phN WWN %8phN\n",
+ rp->id.b24, rp->port_name, trp->port_name);
+ memset(trp, 0, sizeof(*trp));
+ }
+ }
+
if (!memcmp(rp->port_name, vha->port_name, WWN_SIZE))
continue;
@@ -3951,7 +3694,7 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp)
list_for_each_entry(fcport, &vha->vp_fcports, list) {
if (memcmp(rp->port_name, fcport->port_name, WWN_SIZE))
continue;
- fcport->rscn_rcvd = 0;
+ fcport->scan_needed = 0;
fcport->scan_state = QLA_FCPORT_FOUND;
found = true;
/*
@@ -3976,25 +3719,30 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp)
}
}
+ if (dup) {
+ ql_log(ql_log_warn, vha, 0xffff,
+ "Detected %d duplicate NPORT ID(s) from switch data base\n",
+ dup_cnt);
+ }
+
/*
* Logout all previous fabric dev marked lost, except FCP2 devices.
*/
list_for_each_entry(fcport, &vha->vp_fcports, list) {
if ((fcport->flags & FCF_FABRIC_DEVICE) == 0) {
- fcport->rscn_rcvd = 0;
+ fcport->scan_needed = 0;
continue;
}
if (fcport->scan_state != QLA_FCPORT_FOUND) {
- fcport->rscn_rcvd = 0;
+ fcport->scan_needed = 0;
if ((qla_dual_mode_enabled(vha) ||
qla_ini_mode_enabled(vha)) &&
atomic_read(&fcport->state) == FCS_ONLINE) {
- qla2x00_mark_device_lost(vha, fcport,
- ql2xplogiabsentdevice, 0);
+ if (fcport->loop_id != FC_NO_LOOP_ID) {
+ if (fcport->flags & FCF_FCP2_DEVICE)
+ fcport->logout_on_delete = 0;
- if (fcport->loop_id != FC_NO_LOOP_ID &&
- (fcport->flags & FCF_FCP2_DEVICE) == 0) {
ql_dbg(ql_dbg_disc, vha, 0x20f0,
"%s %d %8phC post del sess\n",
__func__, __LINE__,
@@ -4005,7 +3753,7 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp)
}
}
} else {
- if (fcport->rscn_rcvd ||
+ if (fcport->scan_needed ||
fcport->disc_state != DSC_LOGIN_COMPLETE) {
if (fcport->login_retry == 0) {
fcport->login_retry =
@@ -4015,7 +3763,7 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp)
fcport->port_name, fcport->loop_id,
fcport->login_retry);
}
- fcport->rscn_rcvd = 0;
+ fcport->scan_needed = 0;
qla24xx_fcport_handle_login(vha, fcport);
}
}
@@ -4030,7 +3778,7 @@ out:
if (recheck) {
list_for_each_entry(fcport, &vha->vp_fcports, list) {
- if (fcport->rscn_rcvd) {
+ if (fcport->scan_needed) {
set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
break;
@@ -4039,6 +3787,41 @@ out:
}
}
+static int qla2x00_post_gnnft_gpnft_done_work(struct scsi_qla_host *vha,
+ srb_t *sp, int cmd)
+{
+ struct qla_work_evt *e;
+
+ if (cmd != QLA_EVT_GPNFT_DONE && cmd != QLA_EVT_GNNFT_DONE)
+ return QLA_PARAMETER_ERROR;
+
+ e = qla2x00_alloc_work(vha, cmd);
+ if (!e)
+ return QLA_FUNCTION_FAILED;
+
+ e->u.iosb.sp = sp;
+
+ return qla2x00_post_work(vha, e);
+}
+
+static int qla2x00_post_nvme_gpnft_work(struct scsi_qla_host *vha,
+ srb_t *sp, int cmd)
+{
+ struct qla_work_evt *e;
+
+ if (cmd != QLA_EVT_GPNFT)
+ return QLA_PARAMETER_ERROR;
+
+ e = qla2x00_alloc_work(vha, cmd);
+ if (!e)
+ return QLA_FUNCTION_FAILED;
+
+ e->u.gpnft.fc4_type = FC4_TYPE_NVME;
+ e->u.gpnft.sp = sp;
+
+ return qla2x00_post_work(vha, e);
+}
+
static void qla2x00_find_free_fcp_nvme_slot(struct scsi_qla_host *vha,
struct srb *sp)
{
@@ -4139,120 +3922,85 @@ static void qla2x00_async_gpnft_gnnft_sp_done(void *s, int res)
{
struct srb *sp = s;
struct scsi_qla_host *vha = sp->vha;
- struct qla_work_evt *e;
struct ct_sns_req *ct_req =
(struct ct_sns_req *)sp->u.iocb_cmd.u.ctarg.req;
u16 cmd = be16_to_cpu(ct_req->command);
u8 fc4_type = sp->gen2;
unsigned long flags;
+ int rc;
/* gen2 field is holding the fc4type */
ql_dbg(ql_dbg_disc, vha, 0xffff,
"Async done-%s res %x FC4Type %x\n",
sp->name, res, sp->gen2);
+ del_timer(&sp->u.iocb_cmd.timer);
+ sp->rc = res;
if (res) {
unsigned long flags;
+ const char *name = sp->name;
- sp->free(sp);
- spin_lock_irqsave(&vha->work_lock, flags);
- vha->scan.scan_flags &= ~SF_SCANNING;
- vha->scan.scan_retry++;
- spin_unlock_irqrestore(&vha->work_lock, flags);
+ /*
+ * We are in an Interrupt context, queue up this
+ * sp for GNNFT_DONE work. This will allow all
+ * the resource to get freed up.
+ */
+ rc = qla2x00_post_gnnft_gpnft_done_work(vha, sp,
+ QLA_EVT_GNNFT_DONE);
+ if (rc) {
+ /* Cleanup here to prevent memory leak */
+ qla24xx_sp_unmap(vha, sp);
- if (vha->scan.scan_retry < MAX_SCAN_RETRIES) {
- set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
- set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
- qla2xxx_wake_dpc(vha);
- } else {
- ql_dbg(ql_dbg_disc, sp->vha, 0xffff,
- "Async done-%s rescan failed on all retries\n",
- sp->name);
+ spin_lock_irqsave(&vha->work_lock, flags);
+ vha->scan.scan_flags &= ~SF_SCANNING;
+ vha->scan.scan_retry++;
+ spin_unlock_irqrestore(&vha->work_lock, flags);
+
+ if (vha->scan.scan_retry < MAX_SCAN_RETRIES) {
+ set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
+ set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
+ qla2xxx_wake_dpc(vha);
+ } else {
+ ql_dbg(ql_dbg_disc, vha, 0xffff,
+ "Async done-%s rescan failed on all retries.\n",
+ name);
+ }
}
return;
}
- if (!res)
- qla2x00_find_free_fcp_nvme_slot(vha, sp);
+ qla2x00_find_free_fcp_nvme_slot(vha, sp);
if ((fc4_type == FC4_TYPE_FCP_SCSI) && vha->flags.nvme_enabled &&
cmd == GNN_FT_CMD) {
- del_timer(&sp->u.iocb_cmd.timer);
spin_lock_irqsave(&vha->work_lock, flags);
vha->scan.scan_flags &= ~SF_SCANNING;
spin_unlock_irqrestore(&vha->work_lock, flags);
- e = qla2x00_alloc_work(vha, QLA_EVT_GPNFT);
- if (!e) {
- /*
- * please ignore kernel warning. Otherwise,
- * we have mem leak.
- */
- if (sp->u.iocb_cmd.u.ctarg.req) {
- dma_free_coherent(&vha->hw->pdev->dev,
- sp->u.iocb_cmd.u.ctarg.req_allocated_size,
- sp->u.iocb_cmd.u.ctarg.req,
- sp->u.iocb_cmd.u.ctarg.req_dma);
- sp->u.iocb_cmd.u.ctarg.req = NULL;
- }
- if (sp->u.iocb_cmd.u.ctarg.rsp) {
- dma_free_coherent(&vha->hw->pdev->dev,
- sp->u.iocb_cmd.u.ctarg.rsp_allocated_size,
- sp->u.iocb_cmd.u.ctarg.rsp,
- sp->u.iocb_cmd.u.ctarg.rsp_dma);
- sp->u.iocb_cmd.u.ctarg.rsp = NULL;
- }
-
- ql_dbg(ql_dbg_disc, vha, 0xffff,
- "Async done-%s unable to alloc work element\n",
- sp->name);
- sp->free(sp);
+ sp->rc = res;
+ rc = qla2x00_post_nvme_gpnft_work(vha, sp, QLA_EVT_GPNFT);
+ if (rc) {
+ qla24xx_sp_unmap(vha, sp);
set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
- return;
}
- e->u.gpnft.fc4_type = FC4_TYPE_NVME;
- sp->rc = res;
- e->u.gpnft.sp = sp;
-
- qla2x00_post_work(vha, e);
return;
}
- if (cmd == GPN_FT_CMD)
- e = qla2x00_alloc_work(vha, QLA_EVT_GPNFT_DONE);
- else
- e = qla2x00_alloc_work(vha, QLA_EVT_GNNFT_DONE);
- if (!e) {
- /* please ignore kernel warning. Otherwise, we have mem leak. */
- if (sp->u.iocb_cmd.u.ctarg.req) {
- dma_free_coherent(&vha->hw->pdev->dev,
- sp->u.iocb_cmd.u.ctarg.req_allocated_size,
- sp->u.iocb_cmd.u.ctarg.req,
- sp->u.iocb_cmd.u.ctarg.req_dma);
- sp->u.iocb_cmd.u.ctarg.req = NULL;
- }
- if (sp->u.iocb_cmd.u.ctarg.rsp) {
- dma_free_coherent(&vha->hw->pdev->dev,
- sp->u.iocb_cmd.u.ctarg.rsp_allocated_size,
- sp->u.iocb_cmd.u.ctarg.rsp,
- sp->u.iocb_cmd.u.ctarg.rsp_dma);
- sp->u.iocb_cmd.u.ctarg.rsp = NULL;
- }
+ if (cmd == GPN_FT_CMD) {
+ rc = qla2x00_post_gnnft_gpnft_done_work(vha, sp,
+ QLA_EVT_GPNFT_DONE);
+ } else {
+ rc = qla2x00_post_gnnft_gpnft_done_work(vha, sp,
+ QLA_EVT_GNNFT_DONE);
+ }
- ql_dbg(ql_dbg_disc, vha, 0xffff,
- "Async done-%s unable to alloc work element\n",
- sp->name);
- sp->free(sp);
+ if (rc) {
+ qla24xx_sp_unmap(vha, sp);
set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
return;
}
-
- sp->rc = res;
- e->u.iosb.sp = sp;
-
- qla2x00_post_work(vha, e);
}
/*
@@ -4285,11 +4033,13 @@ static int qla24xx_async_gnnft(scsi_qla_host_t *vha, struct srb *sp,
vha->scan.scan_flags &= ~SF_SCANNING;
spin_unlock_irqrestore(&vha->work_lock, flags);
WARN_ON(1);
+ set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
+ set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
goto done_free_sp;
}
ql_dbg(ql_dbg_disc, vha, 0xfffff,
- "%s: FC4Type %x, CT-PASSTRHU %s command ctarg rsp size %d, ctarg req size %d\n",
+ "%s: FC4Type %x, CT-PASSTHRU %s command ctarg rsp size %d, ctarg req size %d\n",
__func__, fc4_type, sp->name, sp->u.iocb_cmd.u.ctarg.rsp_size,
sp->u.iocb_cmd.u.ctarg.req_size);
@@ -4318,8 +4068,12 @@ static int qla24xx_async_gnnft(scsi_qla_host_t *vha, struct srb *sp,
sp->done = qla2x00_async_gpnft_gnnft_sp_done;
rval = qla2x00_start_sp(sp);
- if (rval != QLA_SUCCESS)
+ if (rval != QLA_SUCCESS) {
+ spin_lock_irqsave(&vha->work_lock, flags);
+ vha->scan.scan_flags &= ~SF_SCANNING;
+ spin_unlock_irqrestore(&vha->work_lock, flags);
goto done_free_sp;
+ }
ql_dbg(ql_dbg_disc, vha, 0xffff,
"Async-%s hdl=%x FC4Type %x.\n", sp->name,
@@ -4351,7 +4105,6 @@ void qla24xx_async_gpnft_done(scsi_qla_host_t *vha, srb_t *sp)
{
ql_dbg(ql_dbg_disc, vha, 0xffff,
"%s enter\n", __func__);
- del_timer(&sp->u.iocb_cmd.timer);
qla24xx_async_gnnft(vha, sp, sp->gen2);
}
@@ -4444,9 +4197,9 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type, srb_t *sp)
sp->u.iocb_cmd.timeout = qla2x00_async_iocb_timeout;
qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2);
- rspsz = sizeof(struct ct_sns_gpnft_rsp) +
- ((vha->hw->max_fibre_devices - 1) *
- sizeof(struct ct_sns_gpn_ft_data));
+ rspsz = sp->u.iocb_cmd.u.ctarg.rsp_size;
+ memset(sp->u.iocb_cmd.u.ctarg.rsp, 0, sp->u.iocb_cmd.u.ctarg.rsp_size);
+ memset(sp->u.iocb_cmd.u.ctarg.req, 0, sp->u.iocb_cmd.u.ctarg.req_size);
ct_sns = (struct ct_sns_pkt *)sp->u.iocb_cmd.u.ctarg.req;
/* CT_IU preamble */
@@ -4644,9 +4397,6 @@ void qla24xx_handle_gfpnid_event(scsi_qla_host_t *vha, struct event_arg *ea)
__func__, fcport->port_name);
return;
} else if (ea->sp->gen1 != fcport->rscn_gen) {
- ql_dbg(ql_dbg_disc, vha, 0x20d4, "%s %d %8phC post gidpn\n",
- __func__, __LINE__, fcport->port_name);
- qla24xx_post_gidpn_work(vha, fcport);
return;
}
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index b934977c5c26..eb59c796a795 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -52,12 +52,14 @@ qla2x00_sp_timeout(struct timer_list *t)
struct srb_iocb *iocb;
struct req_que *req;
unsigned long flags;
+ struct qla_hw_data *ha = sp->vha->hw;
- spin_lock_irqsave(sp->qpair->qp_lock_ptr, flags);
+ WARN_ON_ONCE(irqs_disabled());
+ spin_lock_irqsave(&ha->hardware_lock, flags);
req = sp->qpair->req;
req->outstanding_cmds[sp->handle] = NULL;
iocb = &sp->u.iocb_cmd;
- spin_unlock_irqrestore(sp->qpair->qp_lock_ptr, flags);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
iocb->timeout(sp);
}
@@ -245,6 +247,12 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,
}
+ ql_dbg(ql_dbg_disc, vha, 0x2072,
+ "Async-login - %8phC hdl=%x, loopid=%x portid=%02x%02x%02x "
+ "retries=%d.\n", fcport->port_name, sp->handle, fcport->loop_id,
+ fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa,
+ fcport->login_retry);
+
rval = qla2x00_start_sp(sp);
if (rval != QLA_SUCCESS) {
fcport->flags |= FCF_LOGIN_NEEDED;
@@ -252,11 +260,6 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,
goto done_free_sp;
}
- ql_dbg(ql_dbg_disc, vha, 0x2072,
- "Async-login - %8phC hdl=%x, loopid=%x portid=%02x%02x%02x "
- "retries=%d.\n", fcport->port_name, sp->handle, fcport->loop_id,
- fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa,
- fcport->login_retry);
return rval;
done_free_sp:
@@ -301,15 +304,16 @@ qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport)
qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2);
sp->done = qla2x00_async_logout_sp_done;
- rval = qla2x00_start_sp(sp);
- if (rval != QLA_SUCCESS)
- goto done_free_sp;
ql_dbg(ql_dbg_disc, vha, 0x2070,
"Async-logout - hdl=%x loop-id=%x portid=%02x%02x%02x %8phC.\n",
sp->handle, fcport->loop_id, fcport->d_id.b.domain,
fcport->d_id.b.area, fcport->d_id.b.al_pa,
fcport->port_name);
+
+ rval = qla2x00_start_sp(sp);
+ if (rval != QLA_SUCCESS)
+ goto done_free_sp;
return rval;
done_free_sp:
@@ -396,6 +400,9 @@ void qla24xx_handle_adisc_event(scsi_qla_host_t *vha, struct event_arg *ea)
ql_dbg(ql_dbg_disc, vha, 0x2066,
"%s %8phC: adisc fail: post delete\n",
__func__, ea->fcport->port_name);
+ /* deleted = 0 & logout_on_delete = force fw cleanup */
+ fcport->deleted = 0;
+ fcport->logout_on_delete = 1;
qlt_schedule_sess_for_deletion(ea->fcport);
return;
}
@@ -410,16 +417,15 @@ void qla24xx_handle_adisc_event(scsi_qla_host_t *vha, struct event_arg *ea)
__func__, ea->fcport->port_name);
return;
} else if (ea->sp->gen1 != ea->fcport->rscn_gen) {
- ql_dbg(ql_dbg_disc, vha, 0x20d4, "%s %d %8phC post gidpn\n",
- __func__, __LINE__, ea->fcport->port_name);
- qla24xx_post_gidpn_work(vha, ea->fcport);
+ qla_rscn_replay(fcport);
+ qlt_schedule_sess_for_deletion(fcport);
return;
}
__qla24xx_handle_gpdb_event(vha, ea);
}
-int qla_post_els_plogi_work(struct scsi_qla_host *vha, fc_port_t *fcport)
+static int qla_post_els_plogi_work(struct scsi_qla_host *vha, fc_port_t *fcport)
{
struct qla_work_evt *e;
@@ -487,13 +493,15 @@ qla2x00_async_adisc(struct scsi_qla_host *vha, fc_port_t *fcport,
sp->done = qla2x00_async_adisc_sp_done;
if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
lio->u.logio.flags |= SRB_LOGIN_RETRIED;
- rval = qla2x00_start_sp(sp);
- if (rval != QLA_SUCCESS)
- goto done_free_sp;
ql_dbg(ql_dbg_disc, vha, 0x206f,
"Async-adisc - hdl=%x loopid=%x portid=%06x %8phC.\n",
sp->handle, fcport->loop_id, fcport->d_id.b24, fcport->port_name);
+
+ rval = qla2x00_start_sp(sp);
+ if (rval != QLA_SUCCESS)
+ goto done_free_sp;
+
return rval;
done_free_sp:
@@ -536,11 +544,8 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha,
}
if (fcport->last_rscn_gen != fcport->rscn_gen) {
- ql_dbg(ql_dbg_disc, vha, 0x20df,
- "%s %8phC rscn gen changed rscn %d|%d \n",
- __func__, fcport->port_name,
- fcport->last_rscn_gen, fcport->rscn_gen);
- qla24xx_post_gidpn_work(vha, fcport);
+ qla_rscn_replay(fcport);
+ qlt_schedule_sess_for_deletion(fcport);
return;
} else if (fcport->last_login_gen != fcport->login_gen) {
ql_dbg(ql_dbg_disc, vha, 0x20e0,
@@ -675,7 +680,7 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha,
fcport);
break;
}
- /* drop through */
+ /* fall through */
default:
if (fcport_is_smaller(fcport)) {
/* local adapter is bigger */
@@ -787,6 +792,10 @@ qla24xx_async_gnl_sp_done(void *s, int res)
sp->name, res, sp->u.iocb_cmd.u.mbx.in_mb[1],
sp->u.iocb_cmd.u.mbx.in_mb[2]);
+ if (res == QLA_FUNCTION_TIMEOUT)
+ return;
+
+ sp->fcport->flags &= ~(FCF_ASYNC_SENT|FCF_ASYNC_ACTIVE);
memset(&ea, 0, sizeof(ea));
ea.sp = sp;
ea.rc = res;
@@ -814,25 +823,24 @@ qla24xx_async_gnl_sp_done(void *s, int res)
(loop_id & 0x7fff));
}
- spin_lock_irqsave(&vha->gnl.fcports_lock, flags);
+ spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
INIT_LIST_HEAD(&h);
fcport = tf = NULL;
if (!list_empty(&vha->gnl.fcports))
list_splice_init(&vha->gnl.fcports, &h);
+ spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
list_for_each_entry_safe(fcport, tf, &h, gnl_entry) {
list_del_init(&fcport->gnl_entry);
- spin_lock(&vha->hw->tgt.sess_lock);
+ spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE);
- spin_unlock(&vha->hw->tgt.sess_lock);
+ spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
ea.fcport = fcport;
qla2x00_fcport_event_handler(vha, &ea);
}
- spin_unlock_irqrestore(&vha->gnl.fcports_lock, flags);
- spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
/* create new fcport if fw has knowledge of new sessions */
for (i = 0; i < n; i++) {
port_id_t id;
@@ -865,6 +873,8 @@ qla24xx_async_gnl_sp_done(void *s, int res)
}
}
+ spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
+ vha->gnl.sent = 0;
spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
sp->free(sp);
@@ -884,27 +894,24 @@ int qla24xx_async_gnl(struct scsi_qla_host *vha, fc_port_t *fcport)
ql_dbg(ql_dbg_disc, vha, 0x20d9,
"Async-gnlist WWPN %8phC \n", fcport->port_name);
- spin_lock_irqsave(&vha->gnl.fcports_lock, flags);
- if (!list_empty(&fcport->gnl_entry)) {
- spin_unlock_irqrestore(&vha->gnl.fcports_lock, flags);
- rval = QLA_SUCCESS;
- goto done;
- }
-
- spin_lock(&vha->hw->tgt.sess_lock);
+ spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
+ fcport->flags |= FCF_ASYNC_SENT;
fcport->disc_state = DSC_GNL;
fcport->last_rscn_gen = fcport->rscn_gen;
fcport->last_login_gen = fcport->login_gen;
- spin_unlock(&vha->hw->tgt.sess_lock);
list_add_tail(&fcport->gnl_entry, &vha->gnl.fcports);
- spin_unlock_irqrestore(&vha->gnl.fcports_lock, flags);
+ if (vha->gnl.sent) {
+ spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
+ return QLA_SUCCESS;
+ }
+ vha->gnl.sent = 1;
+ spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
if (!sp)
goto done;
- fcport->flags |= FCF_ASYNC_SENT;
sp->type = SRB_MB_IOCB;
sp->name = "gnlist";
sp->gen1 = fcport->rscn_gen;
@@ -970,8 +977,13 @@ void qla24xx_async_gpdb_sp_done(void *s, int res)
"Async done-%s res %x, WWPN %8phC mb[1]=%x mb[2]=%x \n",
sp->name, res, fcport->port_name, mb[1], mb[2]);
- fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE);
+ if (res == QLA_FUNCTION_TIMEOUT) {
+ dma_pool_free(sp->vha->hw->s_dma_pool, sp->u.iocb_cmd.u.mbx.in,
+ sp->u.iocb_cmd.u.mbx.in_dma);
+ return;
+ }
+ fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE);
memset(&ea, 0, sizeof(ea));
ea.event = FCME_GPDB_DONE;
ea.fcport = fcport;
@@ -1147,14 +1159,13 @@ int qla24xx_async_gpdb(struct scsi_qla_host *vha, fc_port_t *fcport, u8 opt)
sp->done = qla24xx_async_gpdb_sp_done;
- rval = qla2x00_start_sp(sp);
- if (rval != QLA_SUCCESS)
- goto done_free_sp;
-
ql_dbg(ql_dbg_disc, vha, 0x20dc,
"Async-%s %8phC hndl %x opt %x\n",
sp->name, fcport->port_name, sp->handle, opt);
+ rval = qla2x00_start_sp(sp);
+ if (rval != QLA_SUCCESS)
+ goto done_free_sp;
return rval;
done_free_sp:
@@ -1182,11 +1193,9 @@ void __qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea)
vha->fcport_count++;
ea->fcport->login_succ = 1;
- ql_dbg(ql_dbg_disc, vha, 0x20d6,
- "%s %d %8phC post upd_fcport fcp_cnt %d\n",
- __func__, __LINE__, ea->fcport->port_name,
- vha->fcport_count);
- qla24xx_post_upd_fcport_work(vha, ea->fcport);
+ spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
+ qla24xx_sched_upd_fcport(ea->fcport);
+ spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
} else if (ea->fcport->login_succ) {
/*
* We have an existing session. A late RSCN delivery
@@ -1226,6 +1235,19 @@ void qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea)
else
ls = pd->current_login_state & 0xf;
+ if (ea->sp->gen2 != fcport->login_gen) {
+ /* target side must have changed it. */
+
+ ql_dbg(ql_dbg_disc, vha, 0x20d3,
+ "%s %8phC generation changed\n",
+ __func__, fcport->port_name);
+ return;
+ } else if (ea->sp->gen1 != fcport->rscn_gen) {
+ qla_rscn_replay(fcport);
+ qlt_schedule_sess_for_deletion(fcport);
+ return;
+ }
+
switch (ls) {
case PDS_PRLI_COMPLETE:
__qla24xx_parse_gpdb(vha, fcport, pd);
@@ -1280,7 +1302,8 @@ static void qla_chk_n2n_b4_login(struct scsi_qla_host *vha, fc_port_t *fcport)
login = 1;
}
- if (login) {
+ if (login && fcport->login_retry) {
+ fcport->login_retry--;
if (fcport->loop_id == FC_NO_LOOP_ID) {
fcport->fw_login_state = DSC_LS_PORT_UNAVAIL;
rc = qla2x00_find_new_loop_id(vha, fcport);
@@ -1304,14 +1327,14 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport)
{
u16 data[2];
u64 wwn;
+ u16 sec;
- ql_dbg(ql_dbg_disc, vha, 0x20d8,
- "%s %8phC DS %d LS %d P %d fl %x confl %p rscn %d|%d login %d retry %d lid %d scan %d\n",
+ ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0x20d8,
+ "%s %8phC DS %d LS %d P %d fl %x confl %p rscn %d|%d login %d lid %d scan %d\n",
__func__, fcport->port_name, fcport->disc_state,
fcport->fw_login_state, fcport->login_pause, fcport->flags,
fcport->conflict, fcport->last_rscn_gen, fcport->rscn_gen,
- fcport->login_gen, fcport->login_retry,
- fcport->loop_id, fcport->scan_state);
+ fcport->login_gen, fcport->loop_id, fcport->scan_state);
if (fcport->scan_state != QLA_FCPORT_FOUND)
return 0;
@@ -1410,22 +1433,14 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport)
break;
case DSC_LOGIN_FAILED:
- fcport->login_retry--;
- ql_dbg(ql_dbg_disc, vha, 0x20d0,
- "%s %d %8phC post gidpn\n",
- __func__, __LINE__, fcport->port_name);
if (N2N_TOPO(vha->hw))
qla_chk_n2n_b4_login(vha, fcport);
else
- qla24xx_post_gidpn_work(vha, fcport);
+ qlt_schedule_sess_for_deletion(fcport);
break;
case DSC_LOGIN_COMPLETE:
/* recheck login state */
- ql_dbg(ql_dbg_disc, vha, 0x20d1,
- "%s %d %8phC post adisc\n",
- __func__, __LINE__, fcport->port_name);
- fcport->login_retry--;
data[0] = data[1] = 0;
qla2x00_post_async_adisc_work(vha, fcport, data);
break;
@@ -1435,6 +1450,22 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport)
qla24xx_post_prli_work(vha, fcport);
break;
+ case DSC_UPD_FCPORT:
+ sec = jiffies_to_msecs(jiffies -
+ fcport->jiffies_at_registration)/1000;
+ if (fcport->sec_since_registration < sec && sec &&
+ !(sec % 60)) {
+ fcport->sec_since_registration = sec;
+ ql_dbg(ql_dbg_disc, fcport->vha, 0xffff,
+ "%s %8phC - Slow Rport registration(%d Sec)\n",
+ __func__, fcport->port_name, sec);
+ }
+
+ if (fcport->next_disc_state != DSC_DELETE_PEND)
+ fcport->next_disc_state = DSC_ADISC;
+ set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
+ break;
+
default:
break;
}
@@ -1513,7 +1544,6 @@ void qla24xx_handle_relogin_event(scsi_qla_host_t *vha,
ql_dbg(ql_dbg_disc, vha, 0x20e9, "%s %d %8phC post gidpn\n",
__func__, __LINE__, fcport->port_name);
- qla24xx_post_gidpn_work(vha, fcport);
return;
}
@@ -1521,7 +1551,8 @@ void qla24xx_handle_relogin_event(scsi_qla_host_t *vha,
}
-void qla_handle_els_plogi_done(scsi_qla_host_t *vha, struct event_arg *ea)
+static void qla_handle_els_plogi_done(scsi_qla_host_t *vha,
+ struct event_arg *ea)
{
ql_dbg(ql_dbg_disc, vha, 0x2118,
"%s %d %8phC post PRLI\n",
@@ -1533,7 +1564,6 @@ void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, struct event_arg *ea)
{
fc_port_t *f, *tf;
uint32_t id = 0, mask, rid;
- unsigned long flags;
fc_port_t *fcport;
switch (ea->event) {
@@ -1548,10 +1578,16 @@ void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, struct event_arg *ea)
return;
switch (ea->id.b.rsvd_1) {
case RSCN_PORT_ADDR:
+#define BIGSCAN 1
+#if defined BIGSCAN & BIGSCAN > 0
+ {
+ unsigned long flags;
fcport = qla2x00_find_fcport_by_nportid
(vha, &ea->id, 1);
- if (fcport)
- fcport->rscn_rcvd = 1;
+ if (fcport) {
+ fcport->scan_needed = 1;
+ fcport->rscn_gen++;
+ }
spin_lock_irqsave(&vha->work_lock, flags);
if (vha->scan.scan_flags == 0) {
@@ -1561,7 +1597,26 @@ void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, struct event_arg *ea)
schedule_delayed_work(&vha->scan.scan_work, 5);
}
spin_unlock_irqrestore(&vha->work_lock, flags);
-
+ }
+#else
+ {
+ int rc;
+ fcport = qla2x00_find_fcport_by_nportid(vha, &ea->id, 1);
+ if (!fcport) {
+ /* cable moved */
+ rc = qla24xx_post_gpnid_work(vha, &ea->id);
+ if (rc) {
+ ql_log(ql_log_warn, vha, 0xd044,
+ "RSCN GPNID work failed %06x\n",
+ ea->id.b24);
+ }
+ } else {
+ ea->fcport = fcport;
+ fcport->scan_needed = 1;
+ qla24xx_handle_rscn_event(fcport, ea);
+ }
+ }
+#endif
break;
case RSCN_AREA_ADDR:
case RSCN_DOM_ADDR:
@@ -1597,9 +1652,6 @@ void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, struct event_arg *ea)
set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
}
break;
- case FCME_GIDPN_DONE:
- qla24xx_handle_gidpn_event(vha, ea);
- break;
case FCME_GNL_DONE:
qla24xx_handle_gnl_done_event(vha, ea);
break;
@@ -1639,6 +1691,34 @@ void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, struct event_arg *ea)
}
}
+/*
+ * RSCN(s) came in for this fcport, but the RSCN(s) was not able
+ * to be consumed by the fcport
+ */
+void qla_rscn_replay(fc_port_t *fcport)
+{
+ struct event_arg ea;
+
+ switch (fcport->disc_state) {
+ case DSC_DELETE_PEND:
+ return;
+ default:
+ break;
+ }
+
+ if (fcport->scan_needed) {
+ memset(&ea, 0, sizeof(ea));
+ ea.event = FCME_RSCN;
+ ea.id = fcport->d_id;
+ ea.id.b.rsvd_1 = RSCN_PORT_ADDR;
+#if defined BIGSCAN & BIGSCAN > 0
+ qla2x00_fcport_event_handler(fcport->vha, &ea);
+#else
+ qla24xx_post_gpnid_work(fcport->vha, &ea.id);
+#endif
+ }
+}
+
static void
qla2x00_tmf_iocb_timeout(void *data)
{
@@ -1684,15 +1764,14 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun,
tm_iocb->u.tmf.data = tag;
sp->done = qla2x00_tmf_sp_done;
- rval = qla2x00_start_sp(sp);
- if (rval != QLA_SUCCESS)
- goto done_free_sp;
-
ql_dbg(ql_dbg_taskm, vha, 0x802f,
"Async-tmf hdl=%x loop-id=%x portid=%02x%02x%02x.\n",
sp->handle, fcport->loop_id, fcport->d_id.b.domain,
fcport->d_id.b.area, fcport->d_id.b.al_pa);
+ rval = qla2x00_start_sp(sp);
+ if (rval != QLA_SUCCESS)
+ goto done_free_sp;
wait_for_completion(&tm_iocb->u.tmf.comp);
rval = tm_iocb->u.tmf.data;
@@ -1747,47 +1826,46 @@ int
qla24xx_async_abort_cmd(srb_t *cmd_sp, bool wait)
{
scsi_qla_host_t *vha = cmd_sp->vha;
- fc_port_t *fcport = cmd_sp->fcport;
struct srb_iocb *abt_iocb;
srb_t *sp;
int rval = QLA_FUNCTION_FAILED;
- sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
+ sp = qla2xxx_get_qpair_sp(cmd_sp->vha, cmd_sp->qpair, cmd_sp->fcport,
+ GFP_KERNEL);
if (!sp)
goto done;
abt_iocb = &sp->u.iocb_cmd;
sp->type = SRB_ABT_CMD;
sp->name = "abort";
+ sp->qpair = cmd_sp->qpair;
if (wait)
sp->flags = SRB_WAKEUP_ON_COMP;
abt_iocb->timeout = qla24xx_abort_iocb_timeout;
init_completion(&abt_iocb->u.abt.comp);
- qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha));
+ /* FW can send 2 x ABTS's timeout/20s */
+ qla2x00_init_timer(sp, 42);
abt_iocb->u.abt.cmd_hndl = cmd_sp->handle;
-
- if (vha->flags.qpairs_available && cmd_sp->qpair)
- abt_iocb->u.abt.req_que_no =
- cpu_to_le16(cmd_sp->qpair->req->id);
- else
- abt_iocb->u.abt.req_que_no = cpu_to_le16(vha->req->id);
+ abt_iocb->u.abt.req_que_no = cpu_to_le16(cmd_sp->qpair->req->id);
sp->done = qla24xx_abort_sp_done;
+ ql_dbg(ql_dbg_async, vha, 0x507c,
+ "Abort command issued - hdl=%x, type=%x\n",
+ cmd_sp->handle, cmd_sp->type);
+
rval = qla2x00_start_sp(sp);
if (rval != QLA_SUCCESS)
goto done_free_sp;
- ql_dbg(ql_dbg_async, vha, 0x507c,
- "Abort command issued - hdl=%x, target_id=%x\n",
- cmd_sp->handle, fcport->tgt_id);
-
if (wait) {
wait_for_completion(&abt_iocb->u.abt.comp);
rval = abt_iocb->u.abt.comp_status == CS_COMPLETE ?
QLA_SUCCESS : QLA_FUNCTION_FAILED;
+ } else {
+ goto done;
}
done_free_sp:
@@ -1803,19 +1881,17 @@ qla24xx_async_abort_command(srb_t *sp)
uint32_t handle;
fc_port_t *fcport = sp->fcport;
+ struct qla_qpair *qpair = sp->qpair;
struct scsi_qla_host *vha = fcport->vha;
- struct qla_hw_data *ha = vha->hw;
- struct req_que *req = vha->req;
-
- if (vha->flags.qpairs_available && sp->qpair)
- req = sp->qpair->req;
+ struct req_que *req = qpair->req;
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(qpair->qp_lock_ptr, flags);
for (handle = 1; handle < req->num_outstanding_cmds; handle++) {
if (req->outstanding_cmds[handle] == sp)
break;
}
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
+
if (handle == req->num_outstanding_cmds) {
/* Command not found. */
return QLA_FUNCTION_FAILED;
@@ -1876,7 +1952,7 @@ qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea)
"%s %8phC DS %d LS %d rc %d login %d|%d rscn %d|%d data %x|%x iop %x|%x\n",
__func__, fcport->port_name, fcport->disc_state,
fcport->fw_login_state, ea->rc, ea->sp->gen2, fcport->login_gen,
- ea->sp->gen2, fcport->rscn_gen|ea->sp->gen1,
+ ea->sp->gen1, fcport->rscn_gen,
ea->data[0], ea->data[1], ea->iop[0], ea->iop[1]);
if ((fcport->fw_login_state == DSC_LS_PLOGI_PEND) ||
@@ -1898,9 +1974,11 @@ qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea)
set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
return;
} else if (ea->sp->gen1 != fcport->rscn_gen) {
- ql_dbg(ql_dbg_disc, vha, 0x20d4, "%s %d %8phC post gidpn\n",
- __func__, __LINE__, fcport->port_name);
- qla24xx_post_gidpn_work(vha, fcport);
+ ql_dbg(ql_dbg_disc, vha, 0x20d3,
+ "%s %8phC RSCN generation changed\n",
+ __func__, fcport->port_name);
+ qla_rscn_replay(fcport);
+ qlt_schedule_sess_for_deletion(fcport);
return;
}
@@ -1952,25 +2030,15 @@ qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea)
cid.b.rsvd_1 = 0;
ql_dbg(ql_dbg_disc, vha, 0x20ec,
- "%s %d %8phC LoopID 0x%x in use post gnl\n",
+ "%s %d %8phC lid %#x in use with pid %06x post gnl\n",
__func__, __LINE__, ea->fcport->port_name,
- ea->fcport->loop_id);
+ ea->fcport->loop_id, cid.b24);
- if (IS_SW_RESV_ADDR(cid)) {
- set_bit(ea->fcport->loop_id, vha->hw->loop_id_map);
- ea->fcport->loop_id = FC_NO_LOOP_ID;
- } else {
- qla2x00_clear_loop_id(ea->fcport);
- }
+ set_bit(ea->fcport->loop_id, vha->hw->loop_id_map);
+ ea->fcport->loop_id = FC_NO_LOOP_ID;
qla24xx_post_gnl_work(vha, ea->fcport);
break;
case MBS_PORT_ID_USED:
- ql_dbg(ql_dbg_disc, vha, 0x20ed,
- "%s %d %8phC NPortId %02x%02x%02x inuse post gidpn\n",
- __func__, __LINE__, ea->fcport->port_name,
- ea->fcport->d_id.b.domain, ea->fcport->d_id.b.area,
- ea->fcport->d_id.b.al_pa);
-
lid = ea->iop[1] & 0xffff;
qlt_find_sess_invalidate_other(vha,
wwn_to_u64(ea->fcport->port_name),
@@ -1989,8 +2057,6 @@ qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea)
"%s %d %8phC NPortId %06x inuse with loopid 0x%x. post gidpn\n",
__func__, __LINE__, ea->fcport->port_name,
ea->fcport->d_id.b24, lid);
- qla2x00_clear_loop_id(ea->fcport);
- qla24xx_post_gidpn_work(vha, ea->fcport);
} else {
ql_dbg(ql_dbg_disc, vha, 0x20ed,
"%s %d %8phC NPortId %06x inuse with loopid 0x%x. sched delete\n",
@@ -2018,26 +2084,6 @@ qla2x00_async_logout_done(struct scsi_qla_host *vha, fc_port_t *fcport,
return;
}
-void
-qla2x00_async_adisc_done(struct scsi_qla_host *vha, fc_port_t *fcport,
- uint16_t *data)
-{
- fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE);
- if (data[0] == MBS_COMMAND_COMPLETE) {
- qla2x00_update_fcport(vha, fcport);
-
- return;
- }
-
- /* Retry login. */
- if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
- set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
- else
- qla2x00_mark_device_lost(vha, fcport, 1, 0);
-
- return;
-}
-
/****************************************************************************/
/* QLogic ISP2x00 Hardware Support Functions. */
/****************************************************************************/
@@ -3527,6 +3573,11 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
if (rval == QLA_SUCCESS) {
qla24xx_detect_sfp(vha);
+ if ((IS_QLA83XX(ha) || IS_QLA27XX(ha)) &&
+ (ha->zio_mode == QLA_ZIO_MODE_6))
+ qla27xx_set_zio_threshold(vha,
+ ha->last_zio_threshold);
+
rval = qla2x00_set_exlogins_buffer(vha);
if (rval != QLA_SUCCESS)
goto failed;
@@ -4015,6 +4066,7 @@ next_check:
ql_dbg(ql_dbg_init, vha, 0x00d3,
"Init Firmware -- success.\n");
QLA_FW_STARTED(ha);
+ vha->u_ql2xexchoffld = vha->u_ql2xiniexchg = 0;
}
return (rval);
@@ -4711,6 +4763,7 @@ qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags)
fcport->loop_id = FC_NO_LOOP_ID;
qla2x00_set_fcport_state(fcport, FCS_UNCONFIGURED);
fcport->supported_classes = FC_COS_UNSPECIFIED;
+ fcport->fp_speed = PORT_SPEED_UNKNOWN;
fcport->ct_desc.ct_sns = dma_alloc_coherent(&vha->hw->pdev->dev,
sizeof(struct ct_sns_pkt), &fcport->ct_desc.ct_sns_dma,
@@ -4728,6 +4781,7 @@ qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags)
fcport = NULL;
}
INIT_WORK(&fcport->del_work, qla24xx_delete_sess_fn);
+ INIT_WORK(&fcport->reg_work, qla_register_fcport_fn);
INIT_LIST_HEAD(&fcport->gnl_entry);
INIT_LIST_HEAD(&fcport->list);
@@ -4853,19 +4907,10 @@ qla2x00_configure_loop(scsi_qla_host_t *vha)
*/
if (qla_tgt_mode_enabled(vha) ||
qla_dual_mode_enabled(vha)) {
- if (IS_QLA27XX(ha) || IS_QLA83XX(ha)) {
- spin_lock_irqsave(&ha->tgt.atio_lock,
- flags);
- qlt_24xx_process_atio_queue(vha, 0);
- spin_unlock_irqrestore(
- &ha->tgt.atio_lock, flags);
- } else {
- spin_lock_irqsave(&ha->hardware_lock,
- flags);
- qlt_24xx_process_atio_queue(vha, 1);
- spin_unlock_irqrestore(
- &ha->hardware_lock, flags);
- }
+ spin_lock_irqsave(&ha->tgt.atio_lock, flags);
+ qlt_24xx_process_atio_queue(vha, 0);
+ spin_unlock_irqrestore(&ha->tgt.atio_lock,
+ flags);
}
}
}
@@ -4958,6 +5003,19 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha)
(uint8_t *)ha->gid_list,
entries * sizeof(struct gid_list_info));
+ if (entries == 0) {
+ spin_lock_irqsave(&vha->work_lock, flags);
+ vha->scan.scan_retry++;
+ spin_unlock_irqrestore(&vha->work_lock, flags);
+
+ if (vha->scan.scan_retry < MAX_SCAN_RETRIES) {
+ set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
+ set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
+ }
+ } else {
+ vha->scan.scan_retry = 0;
+ }
+
list_for_each_entry(fcport, &vha->vp_fcports, list) {
fcport->scan_state = QLA_FCPORT_SCAN;
}
@@ -5223,20 +5281,20 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport)
void
qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
{
- fcport->vha = vha;
-
if (IS_SW_RESV_ADDR(fcport->d_id))
return;
+ ql_dbg(ql_dbg_disc, vha, 0x20ef, "%s %8phC\n",
+ __func__, fcport->port_name);
+
+ fcport->disc_state = DSC_UPD_FCPORT;
+ fcport->login_retry = vha->hw->login_retry_count;
fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT);
- fcport->disc_state = DSC_LOGIN_COMPLETE;
fcport->deleted = 0;
fcport->logout_on_delete = 1;
fcport->login_retry = vha->hw->login_retry_count;
fcport->n2n_chip_reset = fcport->n2n_link_reset_cnt = 0;
- qla2x00_iidma_fcport(vha, fcport);
-
switch (vha->hw->current_topology) {
case ISP_CFG_N:
case ISP_CFG_NL:
@@ -5246,6 +5304,8 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
break;
}
+ qla2x00_iidma_fcport(vha, fcport);
+
if (fcport->fc4f_nvme) {
qla_nvme_register_remote(vha, fcport);
fcport->disc_state = DSC_LOGIN_COMPLETE;
@@ -5274,6 +5334,8 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
break;
}
+ qla2x00_set_fcport_state(fcport, FCS_ONLINE);
+
if (IS_IIDMA_CAPABLE(vha->hw) && vha->hw->flags.gpsc_supported) {
if (fcport->id_changed) {
fcport->id_changed = 0;
@@ -5290,7 +5352,36 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
qla24xx_post_gpsc_work(vha, fcport);
}
}
- qla2x00_set_fcport_state(fcport, FCS_ONLINE);
+
+ fcport->disc_state = DSC_LOGIN_COMPLETE;
+}
+
+void qla_register_fcport_fn(struct work_struct *work)
+{
+ fc_port_t *fcport = container_of(work, struct fc_port, reg_work);
+ u32 rscn_gen = fcport->rscn_gen;
+ u16 data[2];
+
+ if (IS_SW_RESV_ADDR(fcport->d_id))
+ return;
+
+ qla2x00_update_fcport(fcport->vha, fcport);
+
+ if (rscn_gen != fcport->rscn_gen) {
+ /* RSCN(s) came in while registration */
+ switch (fcport->next_disc_state) {
+ case DSC_DELETE_PEND:
+ qlt_schedule_sess_for_deletion(fcport);
+ break;
+ case DSC_ADISC:
+ data[0] = data[1] = 0;
+ qla2x00_post_async_adisc_work(fcport->vha, fcport,
+ data);
+ break;
+ default:
+ break;
+ }
+ }
}
/*
@@ -6494,6 +6585,7 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha)
if (!(IS_P3P_TYPE(ha)))
ha->isp_ops->reset_chip(vha);
+ ha->link_data_rate = PORT_SPEED_UNKNOWN;
SAVE_TOPO(ha);
ha->flags.rida_fmt2 = 0;
ha->flags.n2n_ae = 0;
@@ -6622,6 +6714,20 @@ qla2x00_abort_isp(scsi_qla_host_t *vha)
return status;
}
+ switch (vha->qlini_mode) {
+ case QLA2XXX_INI_MODE_DISABLED:
+ if (!qla_tgt_mode_enabled(vha))
+ return 0;
+ break;
+ case QLA2XXX_INI_MODE_DUAL:
+ if (!qla_dual_mode_enabled(vha))
+ return 0;
+ break;
+ case QLA2XXX_INI_MODE_ENABLED:
+ default:
+ break;
+ }
+
ha->isp_ops->get_flash_version(vha, req->ring);
ha->isp_ops->nvram_config(vha);
@@ -6682,7 +6788,7 @@ qla2x00_abort_isp(scsi_qla_host_t *vha)
* The next call disables the board
* completely.
*/
- ha->isp_ops->reset_adapter(vha);
+ qla2x00_abort_isp_cleanup(vha);
vha->flags.online = 0;
clear_bit(ISP_ABORT_RETRY,
&vha->dpc_flags);
@@ -7142,7 +7248,6 @@ qla24xx_nvram_config(scsi_qla_host_t *vha)
}
icb->firmware_options_2 &= cpu_to_le32(
~(BIT_3 | BIT_2 | BIT_1 | BIT_0));
- vha->flags.process_response_queue = 0;
if (ha->zio_mode != QLA_ZIO_DISABLED) {
ha->zio_mode = QLA_ZIO_MODE_6;
@@ -7153,7 +7258,6 @@ qla24xx_nvram_config(scsi_qla_host_t *vha)
icb->firmware_options_2 |= cpu_to_le32(
(uint32_t)ha->zio_mode);
icb->interrupt_delay_timer = cpu_to_le16(ha->zio_timer);
- vha->flags.process_response_queue = 1;
}
if (rval) {
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index 4351736b2426..512c3c37b447 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -209,7 +209,8 @@ qla2x00_chip_is_down(scsi_qla_host_t *vha)
}
static inline srb_t *
-qla2xxx_get_qpair_sp(struct qla_qpair *qpair, fc_port_t *fcport, gfp_t flag)
+qla2xxx_get_qpair_sp(scsi_qla_host_t *vha, struct qla_qpair *qpair,
+ fc_port_t *fcport, gfp_t flag)
{
srb_t *sp = NULL;
uint8_t bail;
@@ -225,7 +226,9 @@ qla2xxx_get_qpair_sp(struct qla_qpair *qpair, fc_port_t *fcport, gfp_t flag)
memset(sp, 0, sizeof(*sp));
sp->fcport = fcport;
sp->iocbs = 1;
- sp->vha = qpair->vha;
+ sp->vha = vha;
+ sp->qpair = qpair;
+ sp->cmd_type = TYPE_SRB;
INIT_LIST_HEAD(&sp->elem);
done:
@@ -246,19 +249,17 @@ qla2x00_get_sp(scsi_qla_host_t *vha, fc_port_t *fcport, gfp_t flag)
{
srb_t *sp = NULL;
uint8_t bail;
+ struct qla_qpair *qpair;
QLA_VHA_MARK_BUSY(vha, bail);
if (unlikely(bail))
return NULL;
- sp = mempool_alloc(vha->hw->srb_mempool, flag);
+ qpair = vha->hw->base_qpair;
+ sp = qla2xxx_get_qpair_sp(vha, qpair, fcport, flag);
if (!sp)
goto done;
- memset(sp, 0, sizeof(*sp));
- sp->fcport = fcport;
- sp->cmd_type = TYPE_SRB;
- sp->iocbs = 1;
sp->vha = vha;
done:
if (!sp)
@@ -270,7 +271,7 @@ static inline void
qla2x00_rel_sp(srb_t *sp)
{
QLA_VHA_MARK_NOT_BUSY(sp->vha);
- mempool_free(sp, sp->vha->hw->srb_mempool);
+ qla2xxx_rel_qpair_sp(sp->qpair, sp);
}
static inline void
@@ -317,13 +318,13 @@ static inline bool
qla_is_exch_offld_enabled(struct scsi_qla_host *vha)
{
if (qla_ini_mode_enabled(vha) &&
- (ql2xiniexchg > FW_DEF_EXCHANGES_CNT))
+ (vha->ql2xiniexchg > FW_DEF_EXCHANGES_CNT))
return true;
else if (qla_tgt_mode_enabled(vha) &&
- (ql2xexchoffld > FW_DEF_EXCHANGES_CNT))
+ (vha->ql2xexchoffld > FW_DEF_EXCHANGES_CNT))
return true;
else if (qla_dual_mode_enabled(vha) &&
- ((ql2xiniexchg + ql2xexchoffld) > FW_DEF_EXCHANGES_CNT))
+ ((vha->ql2xiniexchg + vha->ql2xexchoffld) > FW_DEF_EXCHANGES_CNT))
return true;
else
return false;
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index 42ac8e097419..032635321ad6 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -1195,8 +1195,8 @@ qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp,
* @sp: SRB command to process
* @cmd_pkt: Command type 3 IOCB
* @tot_dsds: Total number of segments to transfer
- * @tot_prot_dsds:
- * @fw_prot_opts:
+ * @tot_prot_dsds: Total number of segments with protection information
+ * @fw_prot_opts: Protection options to be passed to firmware
*/
inline int
qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
@@ -1526,12 +1526,6 @@ qla24xx_start_scsi(srb_t *sp)
/* Set chip new ring index. */
WRT_REG_DWORD(req->req_q_in, req->ring_index);
- RD_REG_DWORD_RELAXED(&ha->iobase->isp24.hccr);
-
- /* Manage unprocessed RIO/ZIO commands in response queue. */
- if (vha->flags.process_response_queue &&
- rsp->ring_ptr->signature != RESPONSE_PROCESSED)
- qla24xx_process_response_queue(vha, rsp);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return QLA_SUCCESS;
@@ -1725,12 +1719,6 @@ qla24xx_dif_start_scsi(srb_t *sp)
/* Set chip new ring index. */
WRT_REG_DWORD(req->req_q_in, req->ring_index);
- RD_REG_DWORD_RELAXED(&ha->iobase->isp24.hccr);
-
- /* Manage unprocessed RIO/ZIO commands in response queue. */
- if (vha->flags.process_response_queue &&
- rsp->ring_ptr->signature != RESPONSE_PROCESSED)
- qla24xx_process_response_queue(vha, rsp);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
@@ -1880,11 +1868,6 @@ qla2xxx_start_scsi_mq(srb_t *sp)
/* Set chip new ring index. */
WRT_REG_DWORD(req->req_q_in, req->ring_index);
- /* Manage unprocessed RIO/ZIO commands in response queue. */
- if (vha->flags.process_response_queue &&
- rsp->ring_ptr->signature != RESPONSE_PROCESSED)
- qla24xx_process_response_queue(vha, rsp);
-
spin_unlock_irqrestore(&qpair->qp_lock, flags);
return QLA_SUCCESS;
@@ -2287,8 +2270,7 @@ qla24xx_logout_iocb(srb_t *sp, struct logio_entry_24xx *logio)
logio->entry_type = LOGINOUT_PORT_IOCB_TYPE;
logio->control_flags =
cpu_to_le16(LCF_COMMAND_LOGO|LCF_IMPL_LOGO);
- if (!sp->fcport->se_sess ||
- !sp->fcport->keep_nport_handle)
+ if (!sp->fcport->keep_nport_handle)
logio->control_flags |= cpu_to_le16(LCF_FREE_NPORT);
logio->nport_handle = cpu_to_le16(sp->fcport->loop_id);
logio->port_id[0] = sp->fcport->d_id.b.al_pa;
@@ -2659,7 +2641,6 @@ qla24xx_els_dcmd2_iocb(scsi_qla_host_t *vha, int els_opcode,
struct qla_hw_data *ha = vha->hw;
int rval = QLA_SUCCESS;
void *ptr, *resp_ptr;
- dma_addr_t ptr_dma;
/* Alloc SRB structure */
sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
@@ -2691,7 +2672,6 @@ qla24xx_els_dcmd2_iocb(scsi_qla_host_t *vha, int els_opcode,
ptr = elsio->u.els_plogi.els_plogi_pyld =
dma_alloc_coherent(&ha->pdev->dev, DMA_POOL_SIZE,
&elsio->u.els_plogi.els_plogi_pyld_dma, GFP_KERNEL);
- ptr_dma = elsio->u.els_plogi.els_plogi_pyld_dma;
if (!elsio->u.els_plogi.els_plogi_pyld) {
rval = QLA_FUNCTION_FAILED;
@@ -3314,19 +3294,21 @@ qla24xx_abort_iocb(srb_t *sp, struct abort_entry_24xx *abt_iocb)
{
struct srb_iocb *aio = &sp->u.iocb_cmd;
scsi_qla_host_t *vha = sp->vha;
- struct req_que *req = vha->req;
+ struct req_que *req = sp->qpair->req;
memset(abt_iocb, 0, sizeof(struct abort_entry_24xx));
abt_iocb->entry_type = ABORT_IOCB_TYPE;
abt_iocb->entry_count = 1;
abt_iocb->handle = cpu_to_le32(MAKE_HANDLE(req->id, sp->handle));
- abt_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id);
+ if (sp->fcport) {
+ abt_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id);
+ abt_iocb->port_id[0] = sp->fcport->d_id.b.al_pa;
+ abt_iocb->port_id[1] = sp->fcport->d_id.b.area;
+ abt_iocb->port_id[2] = sp->fcport->d_id.b.domain;
+ }
abt_iocb->handle_to_abort =
cpu_to_le32(MAKE_HANDLE(aio->u.abt.req_que_no,
aio->u.abt.cmd_hndl));
- abt_iocb->port_id[0] = sp->fcport->d_id.b.al_pa;
- abt_iocb->port_id[1] = sp->fcport->d_id.b.area;
- abt_iocb->port_id[2] = sp->fcport->d_id.b.domain;
abt_iocb->vp_index = vha->vp_idx;
abt_iocb->req_que_no = cpu_to_le16(aio->u.abt.req_que_no);
/* Send the command to the firmware */
@@ -3455,12 +3437,13 @@ qla2x00_start_sp(srb_t *sp)
int rval;
scsi_qla_host_t *vha = sp->vha;
struct qla_hw_data *ha = vha->hw;
+ struct qla_qpair *qp = sp->qpair;
void *pkt;
unsigned long flags;
rval = QLA_FUNCTION_FAILED;
- spin_lock_irqsave(&ha->hardware_lock, flags);
- pkt = qla2x00_alloc_iocbs(vha, sp);
+ spin_lock_irqsave(qp->qp_lock_ptr, flags);
+ pkt = __qla2x00_alloc_iocbs(sp->qpair, sp);
if (!pkt) {
ql_log(ql_log_warn, vha, 0x700c,
"qla2x00_alloc_iocbs failed.\n");
@@ -3538,9 +3521,9 @@ qla2x00_start_sp(srb_t *sp)
}
wmb();
- qla2x00_start_iocbs(vha, ha->req_q_map[0]);
+ qla2x00_start_iocbs(vha, qp->req);
done:
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(qp->qp_lock_ptr, flags);
return rval;
}
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 36cbb29c84f6..30d3090842f8 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -25,7 +25,7 @@ static int qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *,
/**
* qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200.
- * @irq:
+ * @irq: interrupt number
* @dev_id: SCSI driver HA context
*
* Called by system whenever the host adapter generates an interrupt.
@@ -144,7 +144,7 @@ qla2x00_check_reg16_for_disconnect(scsi_qla_host_t *vha, uint16_t reg)
/**
* qla2300_intr_handler() - Process interrupts for the ISP23xx and ISP63xx.
- * @irq:
+ * @irq: interrupt number
* @dev_id: SCSI driver HA context
*
* Called by system whenever the host adapter generates an interrupt.
@@ -1850,11 +1850,12 @@ static void qla24xx_nvme_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
struct sts_entry_24xx *sts = (struct sts_entry_24xx *)tsk;
uint16_t state_flags;
struct nvmefc_fcp_req *fd;
- uint16_t ret = 0;
+ uint16_t ret = QLA_SUCCESS;
+ uint16_t comp_status = le16_to_cpu(sts->comp_status);
iocb = &sp->u.iocb_cmd;
fcport = sp->fcport;
- iocb->u.nvme.comp_status = le16_to_cpu(sts->comp_status);
+ iocb->u.nvme.comp_status = comp_status;
state_flags = le16_to_cpu(sts->state_flags);
fd = iocb->u.nvme.desc;
@@ -1892,28 +1893,35 @@ static void qla24xx_nvme_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
fd->transferred_length = fd->payload_length -
le32_to_cpu(sts->residual_len);
- switch (le16_to_cpu(sts->comp_status)) {
+ if (unlikely(comp_status != CS_COMPLETE))
+ ql_log(ql_log_warn, fcport->vha, 0x5060,
+ "NVME-%s ERR Handling - hdl=%x status(%x) tr_len:%x resid=%x ox_id=%x\n",
+ sp->name, sp->handle, comp_status,
+ fd->transferred_length, le32_to_cpu(sts->residual_len),
+ sts->ox_id);
+
+ /*
+ * If transport error then Failure (HBA rejects request)
+ * otherwise transport will handle.
+ */
+ switch (comp_status) {
case CS_COMPLETE:
- ret = QLA_SUCCESS;
break;
- case CS_ABORTED:
+
case CS_RESET:
case CS_PORT_UNAVAILABLE:
case CS_PORT_LOGGED_OUT:
+ fcport->nvme_flag |= NVME_FLAG_RESETTING;
+ /* fall through */
+ case CS_ABORTED:
case CS_PORT_BUSY:
- ql_log(ql_log_warn, fcport->vha, 0x5060,
- "NVME-%s ERR Handling - hdl=%x completion status(%x) resid=%x ox_id=%x\n",
- sp->name, sp->handle, sts->comp_status,
- le32_to_cpu(sts->residual_len), sts->ox_id);
fd->transferred_length = 0;
iocb->u.nvme.rsp_pyld_len = 0;
ret = QLA_ABORTED;
break;
+ case CS_DATA_UNDERRUN:
+ break;
default:
- ql_log(ql_log_warn, fcport->vha, 0x5060,
- "NVME-%s error - hdl=%x completion status(%x) resid=%x ox_id=%x\n",
- sp->name, sp->handle, sts->comp_status,
- le32_to_cpu(sts->residual_len), sts->ox_id);
ret = QLA_FUNCTION_FAILED;
break;
}
@@ -2837,6 +2845,7 @@ qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt)
case ELS_IOCB_TYPE:
case ABORT_IOCB_TYPE:
case MBX_IOCB_TYPE:
+ default:
sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
if (sp) {
sp->done(sp, res);
@@ -2847,7 +2856,6 @@ qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt)
case ABTS_RESP_24XX:
case CTIO_TYPE7:
case CTIO_CRC2:
- default:
return 1;
}
fatal:
@@ -3101,7 +3109,7 @@ done:
/**
* qla24xx_intr_handler() - Process interrupts for the ISP23xx and ISP24xx.
- * @irq:
+ * @irq: interrupt number
* @dev_id: SCSI driver HA context
*
* Called by system whenever the host adapter generates an interrupt.
@@ -3121,6 +3129,7 @@ qla24xx_intr_handler(int irq, void *dev_id)
uint16_t mb[8];
struct rsp_que *rsp;
unsigned long flags;
+ bool process_atio = false;
rsp = (struct rsp_que *) dev_id;
if (!rsp) {
@@ -3181,22 +3190,13 @@ qla24xx_intr_handler(int irq, void *dev_id)
qla24xx_process_response_queue(vha, rsp);
break;
case INTR_ATIO_QUE_UPDATE_27XX:
- case INTR_ATIO_QUE_UPDATE:{
- unsigned long flags2;
- spin_lock_irqsave(&ha->tgt.atio_lock, flags2);
- qlt_24xx_process_atio_queue(vha, 1);
- spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2);
+ case INTR_ATIO_QUE_UPDATE:
+ process_atio = true;
break;
- }
- case INTR_ATIO_RSP_QUE_UPDATE: {
- unsigned long flags2;
- spin_lock_irqsave(&ha->tgt.atio_lock, flags2);
- qlt_24xx_process_atio_queue(vha, 1);
- spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2);
-
+ case INTR_ATIO_RSP_QUE_UPDATE:
+ process_atio = true;
qla24xx_process_response_queue(vha, rsp);
break;
- }
default:
ql_dbg(ql_dbg_async, vha, 0x504f,
"Unrecognized interrupt type (%d).\n", stat * 0xff);
@@ -3210,6 +3210,12 @@ qla24xx_intr_handler(int irq, void *dev_id)
qla2x00_handle_mbx_completion(ha, status);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ if (process_atio) {
+ spin_lock_irqsave(&ha->tgt.atio_lock, flags);
+ qlt_24xx_process_atio_queue(vha, 0);
+ spin_unlock_irqrestore(&ha->tgt.atio_lock, flags);
+ }
+
return IRQ_HANDLED;
}
@@ -3256,6 +3262,7 @@ qla24xx_msix_default(int irq, void *dev_id)
uint32_t hccr;
uint16_t mb[8];
unsigned long flags;
+ bool process_atio = false;
rsp = (struct rsp_que *) dev_id;
if (!rsp) {
@@ -3312,22 +3319,13 @@ qla24xx_msix_default(int irq, void *dev_id)
qla24xx_process_response_queue(vha, rsp);
break;
case INTR_ATIO_QUE_UPDATE_27XX:
- case INTR_ATIO_QUE_UPDATE:{
- unsigned long flags2;
- spin_lock_irqsave(&ha->tgt.atio_lock, flags2);
- qlt_24xx_process_atio_queue(vha, 1);
- spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2);
+ case INTR_ATIO_QUE_UPDATE:
+ process_atio = true;
break;
- }
- case INTR_ATIO_RSP_QUE_UPDATE: {
- unsigned long flags2;
- spin_lock_irqsave(&ha->tgt.atio_lock, flags2);
- qlt_24xx_process_atio_queue(vha, 1);
- spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2);
-
+ case INTR_ATIO_RSP_QUE_UPDATE:
+ process_atio = true;
qla24xx_process_response_queue(vha, rsp);
break;
- }
default:
ql_dbg(ql_dbg_async, vha, 0x5051,
"Unrecognized interrupt type (%d).\n", stat & 0xff);
@@ -3338,6 +3336,12 @@ qla24xx_msix_default(int irq, void *dev_id)
qla2x00_handle_mbx_completion(ha, status);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ if (process_atio) {
+ spin_lock_irqsave(&ha->tgt.atio_lock, flags);
+ qlt_24xx_process_atio_queue(vha, 0);
+ spin_unlock_irqrestore(&ha->tgt.atio_lock, flags);
+ }
+
return IRQ_HANDLED;
}
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 2c6c2cd5a0d0..191b6b7c8747 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -60,6 +60,7 @@ static struct rom_cmd {
{ MBC_GET_ADAPTER_LOOP_ID },
{ MBC_READ_SFP },
{ MBC_GET_RNID_PARAMS },
+ { MBC_GET_SET_ZIO_THRESHOLD },
};
static int is_rom_cmd(uint16_t cmd)
@@ -189,7 +190,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
goto premature_exit;
}
- ha->flags.mbox_busy = 1;
+
/* Save mailbox command for debug */
ha->mcp = mcp;
@@ -198,12 +199,13 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
spin_lock_irqsave(&ha->hardware_lock, flags);
- if (ha->flags.purge_mbox || chip_reset != ha->chip_reset) {
+ if (ha->flags.purge_mbox || chip_reset != ha->chip_reset ||
+ ha->flags.mbox_busy) {
rval = QLA_ABORTED;
- ha->flags.mbox_busy = 0;
spin_unlock_irqrestore(&ha->hardware_lock, flags);
goto premature_exit;
}
+ ha->flags.mbox_busy = 1;
/* Load mailbox registers. */
if (IS_P3P_TYPE(ha))
@@ -254,9 +256,10 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
if (IS_P3P_TYPE(ha)) {
if (RD_REG_DWORD(&reg->isp82.hint) &
HINT_MBX_INT_PENDING) {
+ ha->flags.mbox_busy = 0;
spin_unlock_irqrestore(&ha->hardware_lock,
flags);
- ha->flags.mbox_busy = 0;
+
atomic_dec(&ha->num_pend_mbx_stage2);
ql_dbg(ql_dbg_mbx, vha, 0x1010,
"Pending mailbox timeout, exiting.\n");
@@ -274,6 +277,16 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
atomic_inc(&ha->num_pend_mbx_stage3);
if (!wait_for_completion_timeout(&ha->mbx_intr_comp,
mcp->tov * HZ)) {
+ if (chip_reset != ha->chip_reset) {
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ ha->flags.mbox_busy = 0;
+ spin_unlock_irqrestore(&ha->hardware_lock,
+ flags);
+ atomic_dec(&ha->num_pend_mbx_stage2);
+ atomic_dec(&ha->num_pend_mbx_stage3);
+ rval = QLA_ABORTED;
+ goto premature_exit;
+ }
ql_dbg(ql_dbg_mbx, vha, 0x117a,
"cmd=%x Timeout.\n", command);
spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -282,7 +295,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
} else if (ha->flags.purge_mbox ||
chip_reset != ha->chip_reset) {
+ spin_lock_irqsave(&ha->hardware_lock, flags);
ha->flags.mbox_busy = 0;
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
atomic_dec(&ha->num_pend_mbx_stage2);
atomic_dec(&ha->num_pend_mbx_stage3);
rval = QLA_ABORTED;
@@ -300,9 +315,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
if (IS_P3P_TYPE(ha)) {
if (RD_REG_DWORD(&reg->isp82.hint) &
HINT_MBX_INT_PENDING) {
+ ha->flags.mbox_busy = 0;
spin_unlock_irqrestore(&ha->hardware_lock,
flags);
- ha->flags.mbox_busy = 0;
atomic_dec(&ha->num_pend_mbx_stage2);
ql_dbg(ql_dbg_mbx, vha, 0x1012,
"Pending mailbox timeout, exiting.\n");
@@ -320,7 +335,10 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
while (!ha->flags.mbox_int) {
if (ha->flags.purge_mbox ||
chip_reset != ha->chip_reset) {
+ spin_lock_irqsave(&ha->hardware_lock, flags);
ha->flags.mbox_busy = 0;
+ spin_unlock_irqrestore(&ha->hardware_lock,
+ flags);
atomic_dec(&ha->num_pend_mbx_stage2);
rval = QLA_ABORTED;
goto premature_exit;
@@ -363,7 +381,10 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
if (IS_P3P_TYPE(ha) && ha->flags.isp82xx_fw_hung) {
+ spin_lock_irqsave(&ha->hardware_lock, flags);
ha->flags.mbox_busy = 0;
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
/* Setting Link-Down error */
mcp->mb[0] = MBS_LINK_DOWN_ERROR;
ha->mcp = NULL;
@@ -436,7 +457,10 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
* then only PCI ERR flag would be set.
* we will do premature exit for above case.
*/
+ spin_lock_irqsave(&ha->hardware_lock, flags);
ha->flags.mbox_busy = 0;
+ spin_unlock_irqrestore(&ha->hardware_lock,
+ flags);
rval = QLA_FUNCTION_TIMEOUT;
goto premature_exit;
}
@@ -451,8 +475,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
rval = QLA_FUNCTION_TIMEOUT;
}
}
-
+ spin_lock_irqsave(&ha->hardware_lock, flags);
ha->flags.mbox_busy = 0;
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
/* Clean up */
ha->mcp = NULL;
@@ -493,7 +518,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
qla2xxx_wake_dpc(vha);
}
- } else if (!abort_active) {
+ } else if (current == ha->dpc_thread) {
/* call abort directly since we are in the DPC thread */
ql_dbg(ql_dbg_mbx, vha, 0x101d,
"Timeout, calling abort_isp.\n");
@@ -1486,7 +1511,6 @@ qla2x00_abort_target(struct fc_port *fcport, uint64_t l, int tag)
struct req_que *req;
struct rsp_que *rsp;
- l = l;
vha = fcport->vha;
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x103e,
@@ -3072,22 +3096,25 @@ qla24xx_abort_command(srb_t *sp)
struct scsi_qla_host *vha = fcport->vha;
struct qla_hw_data *ha = vha->hw;
struct req_que *req = vha->req;
+ struct qla_qpair *qpair = sp->qpair;
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x108c,
"Entered %s.\n", __func__);
if (vha->flags.qpairs_available && sp->qpair)
req = sp->qpair->req;
+ else
+ return QLA_FUNCTION_FAILED;
if (ql2xasynctmfenable)
return qla24xx_async_abort_command(sp);
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(qpair->qp_lock_ptr, flags);
for (handle = 1; handle < req->num_outstanding_cmds; handle++) {
if (req->outstanding_cmds[handle] == sp)
break;
}
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
if (handle == req->num_outstanding_cmds) {
/* Command not found. */
return QLA_FUNCTION_FAILED;
@@ -3451,9 +3478,9 @@ qla8044_read_serdes_word(scsi_qla_host_t *vha, uint32_t addr, uint32_t *data)
/**
* qla2x00_set_serdes_params() -
* @vha: HA context
- * @sw_em_1g:
- * @sw_em_2g:
- * @sw_em_4g:
+ * @sw_em_1g: serial link options
+ * @sw_em_2g: serial link options
+ * @sw_em_4g: serial link options
*
* Returns
*/
@@ -3762,10 +3789,7 @@ qla2x00_set_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id,
mcp->mb[0] = MBC_PORT_PARAMS;
mcp->mb[1] = loop_id;
mcp->mb[2] = BIT_0;
- if (IS_CNA_CAPABLE(vha->hw))
- mcp->mb[3] = port_speed & (BIT_5|BIT_4|BIT_3|BIT_2|BIT_1|BIT_0);
- else
- mcp->mb[3] = port_speed & (BIT_2|BIT_1|BIT_0);
+ mcp->mb[3] = port_speed & (BIT_5|BIT_4|BIT_3|BIT_2|BIT_1|BIT_0);
mcp->mb[9] = vha->vp_idx;
mcp->out_mb = MBX_9|MBX_3|MBX_2|MBX_1|MBX_0;
mcp->in_mb = MBX_3|MBX_1|MBX_0;
diff --git a/drivers/scsi/qla2xxx/qla_mr.c b/drivers/scsi/qla2xxx/qla_mr.c
index 521a51370554..60f964c53c01 100644
--- a/drivers/scsi/qla2xxx/qla_mr.c
+++ b/drivers/scsi/qla2xxx/qla_mr.c
@@ -2212,7 +2212,7 @@ qlafx00_ioctl_iosb_entry(scsi_qla_host_t *vha, struct req_que *req,
struct bsg_job *bsg_job;
struct fc_bsg_reply *bsg_reply;
struct srb_iocb *iocb_job;
- int res;
+ int res = 0;
struct qla_mt_iocb_rsp_fx00 fstatus;
uint8_t *fw_sts_ptr;
@@ -2624,7 +2624,7 @@ qlafx00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt)
* qlafx00_multistatus_entry() - Process Multi response queue entries.
* @vha: SCSI driver HA context
* @rsp: response queue
- * @pkt:
+ * @pkt: received packet
*/
static void
qlafx00_multistatus_entry(struct scsi_qla_host *vha,
@@ -2681,12 +2681,10 @@ qlafx00_multistatus_entry(struct scsi_qla_host *vha,
* @vha: SCSI driver HA context
* @rsp: response queue
* @pkt: Entry pointer
- * @estatus:
- * @etype:
*/
static void
qlafx00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp,
- struct sts_entry_fx00 *pkt, uint8_t estatus, uint8_t etype)
+ struct sts_entry_fx00 *pkt)
{
srb_t *sp;
struct qla_hw_data *ha = vha->hw;
@@ -2695,9 +2693,6 @@ qlafx00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp,
struct req_que *req = NULL;
int res = DID_ERROR << 16;
- ql_dbg(ql_dbg_async, vha, 0x507f,
- "type of error status in response: 0x%x\n", estatus);
-
req = ha->req_q_map[que];
sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
@@ -2745,9 +2740,11 @@ qlafx00_process_response_queue(struct scsi_qla_host *vha,
if (pkt->entry_status != 0 &&
pkt->entry_type != IOCTL_IOSB_TYPE_FX00) {
+ ql_dbg(ql_dbg_async, vha, 0x507f,
+ "type of error status in response: 0x%x\n",
+ pkt->entry_status);
qlafx00_error_entry(vha, rsp,
- (struct sts_entry_fx00 *)pkt, pkt->entry_status,
- pkt->entry_type);
+ (struct sts_entry_fx00 *)pkt);
continue;
}
@@ -2867,7 +2864,7 @@ qlafx00_async_event(scsi_qla_host_t *vha)
/**
* qlafx00x_mbx_completion() - Process mailbox command completions.
* @vha: SCSI driver HA context
- * @mb0:
+ * @mb0: value to be written into mailbox register 0
*/
static void
qlafx00_mbx_completion(scsi_qla_host_t *vha, uint32_t mb0)
@@ -2893,7 +2890,7 @@ qlafx00_mbx_completion(scsi_qla_host_t *vha, uint32_t mb0)
/**
* qlafx00_intr_handler() - Process interrupts for the ISPFX00.
- * @irq:
+ * @irq: interrupt number
* @dev_id: SCSI driver HA context
*
* Called by system whenever the host adapter generates an interrupt.
diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c
index 20d9dc39f0fb..7e78e7eff783 100644
--- a/drivers/scsi/qla2xxx/qla_nvme.c
+++ b/drivers/scsi/qla2xxx/qla_nvme.c
@@ -506,7 +506,7 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport,
return -EBUSY;
/* Alloc SRB structure */
- sp = qla2xxx_get_qpair_sp(qpair, fcport, GFP_ATOMIC);
+ sp = qla2xxx_get_qpair_sp(vha, qpair, fcport, GFP_ATOMIC);
if (!sp)
return -EBUSY;
@@ -607,7 +607,7 @@ void qla_nvme_abort(struct qla_hw_data *ha, struct srb *sp, int res)
{
int rval;
- if (!test_bit(ABORT_ISP_ACTIVE, &sp->vha->dpc_flags)) {
+ if (ha->flags.fw_started) {
rval = ha->isp_ops->abort_command(sp);
if (!rval && !qla_nvme_wait_on_command(sp))
ql_log(ql_log_warn, NULL, 0x2112,
@@ -660,9 +660,6 @@ void qla_nvme_delete(struct scsi_qla_host *vha)
__func__, fcport);
nvme_fc_set_remoteport_devloss(fcport->nvme_remote_port, 0);
- init_completion(&fcport->nvme_del_done);
- nvme_fc_unregister_remoteport(fcport->nvme_remote_port);
- wait_for_completion(&fcport->nvme_del_done);
}
if (vha->nvme_local_port) {
diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c
index de2bc78449e7..f2f54806f4da 100644
--- a/drivers/scsi/qla2xxx/qla_nx.c
+++ b/drivers/scsi/qla2xxx/qla_nx.c
@@ -2010,7 +2010,7 @@ qla82xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
/**
* qla82xx_intr_handler() - Process interrupts for the ISP23xx and ISP63xx.
- * @irq:
+ * @irq: interrupt number
* @dev_id: SCSI driver HA context
*
* Called by system whenever the host adapter generates an interrupt.
@@ -3699,8 +3699,8 @@ qla82xx_chip_reset_cleanup(scsi_qla_host_t *vha)
spin_unlock_irqrestore(&ha->hardware_lock, flags);
/* Wait for pending cmds (physical and virtual) to complete */
- if (!qla2x00_eh_wait_for_pending_commands(vha, 0, 0,
- WAIT_HOST) == QLA_SUCCESS) {
+ if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0,
+ WAIT_HOST)) {
ql_dbg(ql_dbg_init, vha, 0x00b3,
"Done wait for "
"pending commands.\n");
diff --git a/drivers/scsi/qla2xxx/qla_nx2.c b/drivers/scsi/qla2xxx/qla_nx2.c
index 3a2b0282df14..fe856b602e03 100644
--- a/drivers/scsi/qla2xxx/qla_nx2.c
+++ b/drivers/scsi/qla2xxx/qla_nx2.c
@@ -3878,7 +3878,7 @@ out:
#define PF_BITS_MASK (0xF << 16)
/**
* qla8044_intr_handler() - Process interrupts for the ISP8044
- * @irq:
+ * @irq: interrupt number
* @dev_id: SCSI driver HA context
*
* Called by system whenever the host adapter generates an interrupt.
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 42b8f0d3e580..20c85eed1a75 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -14,6 +14,8 @@
#include <linux/kobject.h>
#include <linux/slab.h>
#include <linux/blk-mq-pci.h>
+#include <linux/refcount.h>
+
#include <scsi/scsi_tcq.h>
#include <scsi/scsicam.h>
#include <scsi/scsi_transport.h>
@@ -65,7 +67,7 @@ module_param(ql2xplogiabsentdevice, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(ql2xplogiabsentdevice,
"Option to enable PLOGI to devices that are not present after "
"a Fabric scan. This is needed for several broken switches. "
- "Default is 0 - no PLOGI. 1 - perfom PLOGI.");
+ "Default is 0 - no PLOGI. 1 - perform PLOGI.");
int ql2xloginretrycount = 0;
module_param(ql2xloginretrycount, int, S_IRUGO);
@@ -204,7 +206,7 @@ int ql2xasynctmfenable = 1;
module_param(ql2xasynctmfenable, int, S_IRUGO);
MODULE_PARM_DESC(ql2xasynctmfenable,
"Enables issue of TM IOCBs asynchronously via IOCB mechanism"
- "Default is 0 - Issue TM IOCBs via mailbox mechanism.");
+ "Default is 1 - Issue TM IOCBs via mailbox mechanism.");
int ql2xdontresethba;
module_param(ql2xdontresethba, int, S_IRUGO|S_IWUSR);
@@ -391,12 +393,14 @@ static void qla_init_base_qpair(struct scsi_qla_host *vha, struct req_que *req,
struct qla_hw_data *ha = vha->hw;
rsp->qpair = ha->base_qpair;
rsp->req = req;
+ ha->base_qpair->hw = ha;
ha->base_qpair->req = req;
ha->base_qpair->rsp = rsp;
ha->base_qpair->vha = vha;
ha->base_qpair->qp_lock_ptr = &ha->hardware_lock;
ha->base_qpair->use_shadow_reg = IS_SHADOW_REG_CAPABLE(ha) ? 1 : 0;
ha->base_qpair->msix = &ha->msix_entries[QLA_MSIX_RSP_Q];
+ ha->base_qpair->srb_mempool = ha->srb_mempool;
INIT_LIST_HEAD(&ha->base_qpair->hints_list);
ha->base_qpair->enable_class_2 = ql2xenableclass2;
/* init qpair to this cpu. Will adjust at run time. */
@@ -1012,7 +1016,7 @@ qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd,
else
goto qc24_target_busy;
- sp = qla2xxx_get_qpair_sp(qpair, fcport, GFP_ATOMIC);
+ sp = qla2xxx_get_qpair_sp(vha, qpair, fcport, GFP_ATOMIC);
if (!sp)
goto qc24_host_busy;
@@ -1212,10 +1216,14 @@ qla2x00_wait_for_chip_reset(scsi_qla_host_t *vha)
return return_status;
}
-static void
+static int
sp_get(struct srb *sp)
{
- atomic_inc(&sp->ref_count);
+ if (!refcount_inc_not_zero((refcount_t*)&sp->ref_count))
+ /* kref get fail */
+ return ENXIO;
+ else
+ return 0;
}
#define ISP_REG_DISCONNECT 0xffffffffU
@@ -1273,38 +1281,51 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
unsigned long flags;
int rval, wait = 0;
struct qla_hw_data *ha = vha->hw;
+ struct qla_qpair *qpair;
if (qla2x00_isp_reg_stat(ha)) {
ql_log(ql_log_info, vha, 0x8042,
"PCI/Register disconnect, exiting.\n");
return FAILED;
}
- if (!CMD_SP(cmd))
- return SUCCESS;
ret = fc_block_scsi_eh(cmd);
if (ret != 0)
return ret;
ret = SUCCESS;
- id = cmd->device->id;
- lun = cmd->device->lun;
-
- spin_lock_irqsave(&ha->hardware_lock, flags);
sp = (srb_t *) CMD_SP(cmd);
- if (!sp) {
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ if (!sp)
+ return SUCCESS;
+
+ qpair = sp->qpair;
+ if (!qpair)
+ return SUCCESS;
+
+ spin_lock_irqsave(qpair->qp_lock_ptr, flags);
+ if (!CMD_SP(cmd)) {
+ /* there's a chance an interrupt could clear
+ the ptr as part of done & free */
+ spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
return SUCCESS;
}
+ if (sp_get(sp)){
+ /* ref_count is already 0 */
+ spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
+ return SUCCESS;
+ }
+ spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
+
+ id = cmd->device->id;
+ lun = cmd->device->lun;
+
ql_dbg(ql_dbg_taskm, vha, 0x8002,
"Aborting from RISC nexus=%ld:%d:%llu sp=%p cmd=%p handle=%x\n",
vha->host_no, id, lun, sp, cmd, sp->handle);
/* Get a reference to the sp and drop the lock.*/
- sp_get(sp);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
rval = ha->isp_ops->abort_command(sp);
if (rval) {
if (rval == QLA_FUNCTION_PARAMETER_ERROR)
@@ -1320,14 +1341,29 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
wait = 1;
}
- spin_lock_irqsave(&ha->hardware_lock, flags);
- sp->done(sp, 0);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_lock_irqsave(qpair->qp_lock_ptr, flags);
+ /*
+ * Clear the slot in the oustanding_cmds array if we can't find the
+ * command to reclaim the resources.
+ */
+ if (rval == QLA_FUNCTION_PARAMETER_ERROR)
+ vha->req->outstanding_cmds[sp->handle] = NULL;
+
+ /*
+ * sp->done will do ref_count--
+ * sp_get() took an extra count above
+ */
+ sp->done(sp, DID_RESET << 16);
/* Did the command return during mailbox execution? */
if (ret == FAILED && !CMD_SP(cmd))
ret = SUCCESS;
+ if (!CMD_SP(cmd))
+ wait = 0;
+
+ spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
+
/* Wait for the command to be returned. */
if (wait) {
if (qla2x00_eh_wait_on_command(cmd) != QLA_SUCCESS) {
@@ -1713,7 +1749,7 @@ qla2x00_loop_reset(scsi_qla_host_t *vha)
static void
__qla2x00_abort_all_cmds(struct qla_qpair *qp, int res)
{
- int cnt, status;
+ int cnt;
unsigned long flags;
srb_t *sp;
scsi_qla_host_t *vha = qp->vha;
@@ -1721,7 +1757,6 @@ __qla2x00_abort_all_cmds(struct qla_qpair *qp, int res)
struct req_que *req;
struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
struct qla_tgt_cmd *cmd;
- uint8_t trace = 0;
if (!ha->req_q_map)
return;
@@ -1731,64 +1766,68 @@ __qla2x00_abort_all_cmds(struct qla_qpair *qp, int res)
sp = req->outstanding_cmds[cnt];
if (sp) {
req->outstanding_cmds[cnt] = NULL;
- if (sp->cmd_type == TYPE_SRB) {
+ switch (sp->cmd_type) {
+ case TYPE_SRB:
if (sp->type == SRB_NVME_CMD ||
sp->type == SRB_NVME_LS) {
- sp_get(sp);
- spin_unlock_irqrestore(qp->qp_lock_ptr,
- flags);
- qla_nvme_abort(ha, sp, res);
- spin_lock_irqsave(qp->qp_lock_ptr,
- flags);
+ if (!sp_get(sp)) {
+ /* got sp */
+ spin_unlock_irqrestore
+ (qp->qp_lock_ptr,
+ flags);
+ qla_nvme_abort(ha, sp, res);
+ spin_lock_irqsave
+ (qp->qp_lock_ptr, flags);
+ }
} else if (GET_CMD_SP(sp) &&
!ha->flags.eeh_busy &&
(!test_bit(ABORT_ISP_ACTIVE,
&vha->dpc_flags)) &&
+ !qla2x00_isp_reg_stat(ha) &&
(sp->type == SRB_SCSI_CMD)) {
/*
- * Don't abort commands in
- * adapter during EEH
- * recovery as it's not
+ * Don't abort commands in adapter
+ * during EEH recovery as it's not
* accessible/responding.
*
- * Get a reference to the sp
- * and drop the lock. The
- * reference ensures this
- * sp->done() call and not the
- * call in qla2xxx_eh_abort()
- * ends the SCSI command (with
- * result 'res').
+ * Get a reference to the sp and drop
+ * the lock. The reference ensures this
+ * sp->done() call and not the call in
+ * qla2xxx_eh_abort() ends the SCSI cmd
+ * (with result 'res').
*/
- sp_get(sp);
- spin_unlock_irqrestore(qp->qp_lock_ptr,
- flags);
- status = qla2xxx_eh_abort(
- GET_CMD_SP(sp));
- spin_lock_irqsave(qp->qp_lock_ptr,
- flags);
- /*
- * Get rid of extra reference
- * if immediate exit from
- * ql2xxx_eh_abort
- */
- if (status == FAILED &&
- (qla2x00_isp_reg_stat(ha)))
- atomic_dec(
- &sp->ref_count);
+ if (!sp_get(sp)) {
+ spin_unlock_irqrestore
+ (qp->qp_lock_ptr, flags);
+ qla2xxx_eh_abort(
+ GET_CMD_SP(sp));
+ spin_lock_irqsave
+ (qp->qp_lock_ptr, flags);
+ }
}
sp->done(sp, res);
- } else {
+ break;
+ case TYPE_TGT_CMD:
if (!vha->hw->tgt.tgt_ops || !tgt ||
qla_ini_mode_enabled(vha)) {
- if (!trace)
- ql_dbg(ql_dbg_tgt_mgt,
- vha, 0xf003,
- "HOST-ABORT-HNDLR: dpc_flags=%lx. Target mode disabled\n",
- vha->dpc_flags);
+ ql_dbg(ql_dbg_tgt_mgt, vha, 0xf003,
+ "HOST-ABORT-HNDLR: dpc_flags=%lx. Target mode disabled\n",
+ vha->dpc_flags);
continue;
}
cmd = (struct qla_tgt_cmd *)sp;
qlt_abort_cmd_on_host_reset(cmd->vha, cmd);
+ break;
+ case TYPE_TGT_TMCMD:
+ /*
+ * Currently, only ABTS response gets on the
+ * outstanding_cmds[]
+ */
+ ha->tgt.tgt_ops->free_mcmd(
+ (struct qla_tgt_mgmt_cmd *)sp);
+ break;
+ default:
+ break;
}
}
}
@@ -2708,7 +2747,7 @@ static void qla2x00_iocb_work_fn(struct work_struct *work)
struct scsi_qla_host, iocb_work);
struct qla_hw_data *ha = vha->hw;
struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
- int i = 20;
+ int i = 2;
unsigned long flags;
if (test_bit(UNLOADING, &base_vha->dpc_flags))
@@ -2819,6 +2858,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
atomic_set(&ha->num_pend_mbx_stage1, 0);
atomic_set(&ha->num_pend_mbx_stage2, 0);
atomic_set(&ha->num_pend_mbx_stage3, 0);
+ atomic_set(&ha->zio_threshold, DEFAULT_ZIO_THRESHOLD);
+ ha->last_zio_threshold = DEFAULT_ZIO_THRESHOLD;
/* Assign ISP specific operations. */
if (IS_QLA2100(ha)) {
@@ -4249,29 +4290,34 @@ static void
qla2x00_number_of_exch(scsi_qla_host_t *vha, u32 *ret_cnt, u16 max_cnt)
{
u32 temp;
+ struct init_cb_81xx *icb = (struct init_cb_81xx *)&vha->hw->init_cb;
*ret_cnt = FW_DEF_EXCHANGES_CNT;
if (max_cnt > vha->hw->max_exchg)
max_cnt = vha->hw->max_exchg;
if (qla_ini_mode_enabled(vha)) {
- if (ql2xiniexchg > max_cnt)
- ql2xiniexchg = max_cnt;
+ if (vha->ql2xiniexchg > max_cnt)
+ vha->ql2xiniexchg = max_cnt;
+
+ if (vha->ql2xiniexchg > FW_DEF_EXCHANGES_CNT)
+ *ret_cnt = vha->ql2xiniexchg;
- if (ql2xiniexchg > FW_DEF_EXCHANGES_CNT)
- *ret_cnt = ql2xiniexchg;
} else if (qla_tgt_mode_enabled(vha)) {
- if (ql2xexchoffld > max_cnt)
- ql2xexchoffld = max_cnt;
+ if (vha->ql2xexchoffld > max_cnt) {
+ vha->ql2xexchoffld = max_cnt;
+ icb->exchange_count = cpu_to_le16(vha->ql2xexchoffld);
+ }
- if (ql2xexchoffld > FW_DEF_EXCHANGES_CNT)
- *ret_cnt = ql2xexchoffld;
+ if (vha->ql2xexchoffld > FW_DEF_EXCHANGES_CNT)
+ *ret_cnt = vha->ql2xexchoffld;
} else if (qla_dual_mode_enabled(vha)) {
- temp = ql2xiniexchg + ql2xexchoffld;
+ temp = vha->ql2xiniexchg + vha->ql2xexchoffld;
if (temp > max_cnt) {
- ql2xiniexchg -= (temp - max_cnt)/2;
- ql2xexchoffld -= (((temp - max_cnt)/2) + 1);
+ vha->ql2xiniexchg -= (temp - max_cnt)/2;
+ vha->ql2xexchoffld -= (((temp - max_cnt)/2) + 1);
temp = max_cnt;
+ icb->exchange_count = cpu_to_le16(vha->ql2xexchoffld);
}
if (temp > FW_DEF_EXCHANGES_CNT)
@@ -4309,6 +4355,12 @@ qla2x00_set_exchoffld_buffer(scsi_qla_host_t *vha)
if (totsz != ha->exchoffld_size) {
qla2x00_free_exchoffld_buffer(ha);
+ if (actual_cnt <= FW_DEF_EXCHANGES_CNT) {
+ ha->exchoffld_size = 0;
+ ha->flags.exchoffld_enabled = 0;
+ return QLA_SUCCESS;
+ }
+
ha->exchoffld_size = totsz;
ql_log(ql_log_info, vha, 0xd016,
@@ -4341,6 +4393,15 @@ qla2x00_set_exchoffld_buffer(scsi_qla_host_t *vha)
return -ENOMEM;
}
+ } else if (!ha->exchoffld_buf || (actual_cnt <= FW_DEF_EXCHANGES_CNT)) {
+ /* pathological case */
+ qla2x00_free_exchoffld_buffer(ha);
+ ha->exchoffld_size = 0;
+ ha->flags.exchoffld_enabled = 0;
+ ql_log(ql_log_info, vha, 0xd016,
+ "Exchange offload not enable: offld size=%d, actual count=%d entry sz=0x%x, total sz=0x%x.\n",
+ ha->exchoffld_size, actual_cnt, size, totsz);
+ return 0;
}
/* Now configure the dma buffer */
@@ -4356,7 +4417,7 @@ qla2x00_set_exchoffld_buffer(scsi_qla_host_t *vha)
if (qla_ini_mode_enabled(vha))
icb->exchange_count = 0;
else
- icb->exchange_count = cpu_to_le16(ql2xexchoffld);
+ icb->exchange_count = cpu_to_le16(vha->ql2xexchoffld);
}
return rval;
@@ -4564,6 +4625,10 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht,
vha->host_no = host->host_no;
vha->hw = ha;
+ vha->qlini_mode = ql2x_ini_mode;
+ vha->ql2xexchoffld = ql2xexchoffld;
+ vha->ql2xiniexchg = ql2xiniexchg;
+
INIT_LIST_HEAD(&vha->vp_fcports);
INIT_LIST_HEAD(&vha->work_list);
INIT_LIST_HEAD(&vha->list);
@@ -4579,7 +4644,6 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht,
spin_lock_init(&vha->work_lock);
spin_lock_init(&vha->cmd_list_lock);
- spin_lock_init(&vha->gnl.fcports_lock);
init_waitqueue_head(&vha->fcport_waitQ);
init_waitqueue_head(&vha->vref_waitq);
@@ -4710,7 +4774,6 @@ qla2x00_post_async_work(login, QLA_EVT_ASYNC_LOGIN);
qla2x00_post_async_work(logout, QLA_EVT_ASYNC_LOGOUT);
qla2x00_post_async_work(logout_done, QLA_EVT_ASYNC_LOGOUT_DONE);
qla2x00_post_async_work(adisc, QLA_EVT_ASYNC_ADISC);
-qla2x00_post_async_work(adisc_done, QLA_EVT_ASYNC_ADISC_DONE);
qla2x00_post_async_work(prlo, QLA_EVT_ASYNC_PRLO);
qla2x00_post_async_work(prlo_done, QLA_EVT_ASYNC_PRLO_DONE);
@@ -4761,16 +4824,25 @@ qlafx00_post_aenfx_work(struct scsi_qla_host *vha, uint32_t evtcode,
return qla2x00_post_work(vha, e);
}
-int qla24xx_post_upd_fcport_work(struct scsi_qla_host *vha, fc_port_t *fcport)
+void qla24xx_sched_upd_fcport(fc_port_t *fcport)
{
- struct qla_work_evt *e;
+ unsigned long flags;
- e = qla2x00_alloc_work(vha, QLA_EVT_UPD_FCPORT);
- if (!e)
- return QLA_FUNCTION_FAILED;
+ if (IS_SW_RESV_ADDR(fcport->d_id))
+ return;
- e->u.fcport.fcport = fcport;
- return qla2x00_post_work(vha, e);
+ spin_lock_irqsave(&fcport->vha->work_lock, flags);
+ if (fcport->disc_state == DSC_UPD_FCPORT) {
+ spin_unlock_irqrestore(&fcport->vha->work_lock, flags);
+ return;
+ }
+ fcport->jiffies_at_registration = jiffies;
+ fcport->sec_since_registration = 0;
+ fcport->next_disc_state = DSC_DELETED;
+ fcport->disc_state = DSC_UPD_FCPORT;
+ spin_unlock_irqrestore(&fcport->vha->work_lock, flags);
+
+ queue_work(system_unbound_wq, &fcport->reg_work);
}
static
@@ -4808,10 +4880,10 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e)
fcport->d_id = e->u.new_sess.id;
fcport->flags |= FCF_FABRIC_DEVICE;
fcport->fw_login_state = DSC_LS_PLOGI_PEND;
- if (e->u.new_sess.fc4_type == FS_FC4TYPE_FCP)
+ if (e->u.new_sess.fc4_type & FS_FC4TYPE_FCP)
fcport->fc4_type = FC4_TYPE_FCP_SCSI;
- if (e->u.new_sess.fc4_type == FS_FC4TYPE_NVME) {
+ if (e->u.new_sess.fc4_type & FS_FC4TYPE_NVME) {
fcport->fc4_type = FC4_TYPE_OTHER;
fcport->fc4f_nvme = FC4_TYPE_NVME;
}
@@ -4990,19 +5062,12 @@ qla2x00_do_work(struct scsi_qla_host *vha)
qla2x00_async_adisc(vha, e->u.logio.fcport,
e->u.logio.data);
break;
- case QLA_EVT_ASYNC_ADISC_DONE:
- qla2x00_async_adisc_done(vha, e->u.logio.fcport,
- e->u.logio.data);
- break;
case QLA_EVT_UEVENT:
qla2x00_uevent_emit(vha, e->u.uevent.code);
break;
case QLA_EVT_AENFX:
qlafx00_process_aen(vha, e);
break;
- case QLA_EVT_GIDPN:
- qla24xx_async_gidpn(vha, e->u.fcport.fcport);
- break;
case QLA_EVT_GPNID:
qla24xx_async_gpnid(vha, &e->u.gpnid.id);
break;
@@ -5025,9 +5090,6 @@ qla2x00_do_work(struct scsi_qla_host *vha)
case QLA_EVT_GPSC:
qla24xx_async_gpsc(vha, e->u.fcport.fcport);
break;
- case QLA_EVT_UPD_FCPORT:
- qla2x00_update_fcport(vha, e->u.fcport.fcport);
- break;
case QLA_EVT_GNL:
qla24xx_async_gnl(vha, e->u.fcport.fcport);
break;
@@ -6041,12 +6103,29 @@ qla2x00_do_dpc(void *data)
if (test_and_clear_bit
(ISP_ABORT_NEEDED, &base_vha->dpc_flags) &&
!test_bit(UNLOADING, &base_vha->dpc_flags)) {
+ bool do_reset = true;
+
+ switch (base_vha->qlini_mode) {
+ case QLA2XXX_INI_MODE_ENABLED:
+ break;
+ case QLA2XXX_INI_MODE_DISABLED:
+ if (!qla_tgt_mode_enabled(base_vha) &&
+ !ha->flags.fw_started)
+ do_reset = false;
+ break;
+ case QLA2XXX_INI_MODE_DUAL:
+ if (!qla_dual_mode_enabled(base_vha) &&
+ !ha->flags.fw_started)
+ do_reset = false;
+ break;
+ default:
+ break;
+ }
- ql_dbg(ql_dbg_dpc, base_vha, 0x4007,
- "ISP abort scheduled.\n");
- if (!(test_and_set_bit(ABORT_ISP_ACTIVE,
+ if (do_reset && !(test_and_set_bit(ABORT_ISP_ACTIVE,
&base_vha->dpc_flags))) {
-
+ ql_dbg(ql_dbg_dpc, base_vha, 0x4007,
+ "ISP abort scheduled.\n");
if (ha->isp_ops->abort_isp(base_vha)) {
/* failed. retry later */
set_bit(ISP_ABORT_NEEDED,
@@ -6054,10 +6133,9 @@ qla2x00_do_dpc(void *data)
}
clear_bit(ABORT_ISP_ACTIVE,
&base_vha->dpc_flags);
+ ql_dbg(ql_dbg_dpc, base_vha, 0x4008,
+ "ISP abort end.\n");
}
-
- ql_dbg(ql_dbg_dpc, base_vha, 0x4008,
- "ISP abort end.\n");
}
if (test_and_clear_bit(FCPORT_UPDATE_NEEDED,
@@ -6183,17 +6261,28 @@ intr_on_check:
mutex_unlock(&ha->mq_lock);
}
- if (test_and_clear_bit(SET_ZIO_THRESHOLD_NEEDED, &base_vha->dpc_flags)) {
+ if (test_and_clear_bit(SET_NVME_ZIO_THRESHOLD_NEEDED,
+ &base_vha->dpc_flags)) {
ql_log(ql_log_info, base_vha, 0xffffff,
"nvme: SET ZIO Activity exchange threshold to %d.\n",
ha->nvme_last_rptd_aen);
- if (qla27xx_set_zio_threshold(base_vha, ha->nvme_last_rptd_aen)) {
+ if (qla27xx_set_zio_threshold(base_vha,
+ ha->nvme_last_rptd_aen)) {
ql_log(ql_log_info, base_vha, 0xffffff,
- "nvme: Unable to SET ZIO Activity exchange threshold to %d.\n",
- ha->nvme_last_rptd_aen);
+ "nvme: Unable to SET ZIO Activity exchange threshold to %d.\n",
+ ha->nvme_last_rptd_aen);
}
}
+ if (test_and_clear_bit(SET_ZIO_THRESHOLD_NEEDED,
+ &base_vha->dpc_flags)) {
+ ql_log(ql_log_info, base_vha, 0xffffff,
+ "SET ZIO Activity exchange threshold to %d.\n",
+ ha->last_zio_threshold);
+ qla27xx_set_zio_threshold(base_vha,
+ ha->last_zio_threshold);
+ }
+
if (!IS_QLAFX00(ha))
qla2x00_do_dpc_all_vps(base_vha);
@@ -6406,13 +6495,24 @@ qla2x00_timer(struct timer_list *t)
* FC-NVME
* see if the active AEN count has changed from what was last reported.
*/
- if (!vha->vp_idx &&
- atomic_read(&ha->nvme_active_aen_cnt) != ha->nvme_last_rptd_aen &&
- ha->zio_mode == QLA_ZIO_MODE_6) {
+ if (!vha->vp_idx && (atomic_read(&ha->nvme_active_aen_cnt) !=
+ ha->nvme_last_rptd_aen) && ha->zio_mode == QLA_ZIO_MODE_6) {
ql_log(ql_log_info, vha, 0x3002,
- "nvme: Sched: Set ZIO exchange threshold to %d.\n",
- ha->nvme_last_rptd_aen);
+ "nvme: Sched: Set ZIO exchange threshold to %d.\n",
+ ha->nvme_last_rptd_aen);
ha->nvme_last_rptd_aen = atomic_read(&ha->nvme_active_aen_cnt);
+ set_bit(SET_NVME_ZIO_THRESHOLD_NEEDED, &vha->dpc_flags);
+ start_dpc++;
+ }
+
+ if (!vha->vp_idx &&
+ (atomic_read(&ha->zio_threshold) != ha->last_zio_threshold) &&
+ (ha->zio_mode == QLA_ZIO_MODE_6) &&
+ (IS_QLA83XX(ha) || IS_QLA27XX(ha))) {
+ ql_log(ql_log_info, vha, 0x3002,
+ "Sched: Set ZIO exchange threshold to %d.\n",
+ ha->last_zio_threshold);
+ ha->last_zio_threshold = atomic_read(&ha->zio_threshold);
set_bit(SET_ZIO_THRESHOLD_NEEDED, &vha->dpc_flags);
start_dpc++;
}
@@ -6839,8 +6939,6 @@ qla2xxx_pci_resume(struct pci_dev *pdev)
"The device failed to resume I/O from slot/link_reset.\n");
}
- pci_cleanup_aer_uncorrect_error_status(pdev);
-
ha->flags.eeh_busy = 0;
}
@@ -6946,6 +7044,9 @@ qla2x00_module_init(void)
if (ql2xextended_error_logging == 1)
ql2xextended_error_logging = QL_DBG_DEFAULT1_MASK;
+ if (ql2x_ini_mode == QLA2XXX_INI_MODE_DUAL)
+ qla_insert_tgt_attrs();
+
qla2xxx_transport_template =
fc_attach_transport(&qla2xxx_transport_functions);
if (!qla2xxx_transport_template) {
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index 4499c787165f..2a3055c799fb 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -2229,7 +2229,7 @@ qla2x00_erase_flash_sector(struct qla_hw_data *ha, uint32_t addr,
/**
* qla2x00_get_flash_manufacturer() - Read manufacturer ID from flash chip.
- * @ha:
+ * @ha: host adapter
* @man_id: Flash manufacturer ID
* @flash_id: Flash ID
*/
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index 8c811b251d42..c4504740f0e2 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -141,6 +141,8 @@ static void qlt_24xx_handle_abts(struct scsi_qla_host *,
struct abts_recv_from_24xx *);
static void qlt_send_busy(struct qla_qpair *, struct atio_from_isp *,
uint16_t);
+static int qlt_check_reserve_free_req(struct qla_qpair *qpair, uint32_t);
+static inline uint32_t qlt_make_handle(struct qla_qpair *);
/*
* Global Variables
@@ -541,7 +543,6 @@ void qlt_response_pkt_all_vps(struct scsi_qla_host *vha,
qlt_response_pkt(host, rsp, pkt);
break;
}
-
default:
qlt_response_pkt(vha, rsp, pkt);
break;
@@ -600,14 +601,9 @@ void qla2x00_async_nack_sp_done(void *s, int res)
sp->fcport->login_succ = 1;
vha->fcport_count++;
-
- ql_dbg(ql_dbg_disc, vha, 0x20f3,
- "%s %d %8phC post upd_fcport fcp_cnt %d\n",
- __func__, __LINE__,
- sp->fcport->port_name,
- vha->fcport_count);
- sp->fcport->disc_state = DSC_UPD_FCPORT;
- qla24xx_post_upd_fcport_work(vha, sp->fcport);
+ spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
+ qla24xx_sched_upd_fcport(sp->fcport);
+ spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
} else {
sp->fcport->login_retry = 0;
sp->fcport->disc_state = DSC_LOGIN_COMPLETE;
@@ -1230,11 +1226,12 @@ void qlt_schedule_sess_for_deletion(struct fc_port *sess)
{
struct qla_tgt *tgt = sess->tgt;
unsigned long flags;
+ u16 sec;
- if (sess->disc_state == DSC_DELETE_PEND)
+ switch (sess->disc_state) {
+ case DSC_DELETE_PEND:
return;
-
- if (sess->disc_state == DSC_DELETED) {
+ case DSC_DELETED:
if (tgt && tgt->tgt_stop && (tgt->sess_count == 0))
wake_up_all(&tgt->waitQ);
if (sess->vha->fcport_count == 0)
@@ -1243,11 +1240,26 @@ void qlt_schedule_sess_for_deletion(struct fc_port *sess)
if (!sess->plogi_link[QLT_PLOGI_LINK_SAME_WWN] &&
!sess->plogi_link[QLT_PLOGI_LINK_CONFLICT])
return;
+ break;
+ case DSC_UPD_FCPORT:
+ /*
+ * This port is not done reporting to upper layer.
+ * let it finish
+ */
+ sess->next_disc_state = DSC_DELETE_PEND;
+ sec = jiffies_to_msecs(jiffies -
+ sess->jiffies_at_registration)/1000;
+ if (sess->sec_since_registration < sec && sec && !(sec % 5)) {
+ sess->sec_since_registration = sec;
+ ql_dbg(ql_dbg_disc, sess->vha, 0xffff,
+ "%s %8phC : Slow Rport registration(%d Sec)\n",
+ __func__, sess->port_name, sec);
+ }
+ return;
+ default:
+ break;
}
- if (sess->deleted == QLA_SESS_DELETED)
- sess->logout_on_delete = 0;
-
spin_lock_irqsave(&sess->vha->work_lock, flags);
if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
spin_unlock_irqrestore(&sess->vha->work_lock, flags);
@@ -1261,7 +1273,8 @@ void qlt_schedule_sess_for_deletion(struct fc_port *sess)
qla24xx_chk_fcp_state(sess);
ql_dbg(ql_dbg_tgt, sess->vha, 0xe001,
- "Scheduling sess %p for deletion\n", sess);
+ "Scheduling sess %p for deletion %8phC\n",
+ sess, sess->port_name);
INIT_WORK(&sess->del_work, qla24xx_delete_sess_fn);
WARN_ON(!queue_work(sess->vha->hw->wq, &sess->del_work));
@@ -1479,27 +1492,14 @@ int qlt_stop_phase1(struct qla_tgt *tgt)
struct qla_hw_data *ha = tgt->ha;
unsigned long flags;
+ mutex_lock(&ha->optrom_mutex);
mutex_lock(&qla_tgt_mutex);
- if (!vha->fc_vport) {
- struct Scsi_Host *sh = vha->host;
- struct fc_host_attrs *fc_host = shost_to_fc_host(sh);
- bool npiv_vports;
-
- spin_lock_irqsave(sh->host_lock, flags);
- npiv_vports = (fc_host->npiv_vports_inuse);
- spin_unlock_irqrestore(sh->host_lock, flags);
-
- if (npiv_vports) {
- mutex_unlock(&qla_tgt_mutex);
- ql_dbg(ql_dbg_tgt_mgt, vha, 0xf021,
- "NPIV is in use. Can not stop target\n");
- return -EPERM;
- }
- }
+
if (tgt->tgt_stop || tgt->tgt_stopped) {
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04e,
"Already in tgt->tgt_stop or tgt_stopped state\n");
mutex_unlock(&qla_tgt_mutex);
+ mutex_unlock(&ha->optrom_mutex);
return -EPERM;
}
@@ -1537,6 +1537,8 @@ int qlt_stop_phase1(struct qla_tgt *tgt)
/* Wait for sessions to clear out (just in case) */
wait_event_timeout(tgt->waitQ, test_tgt_sess_count(tgt), 10*HZ);
+ mutex_unlock(&ha->optrom_mutex);
+
return 0;
}
EXPORT_SYMBOL(qlt_stop_phase1);
@@ -1566,6 +1568,15 @@ void qlt_stop_phase2(struct qla_tgt *tgt)
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf00c, "Stop of tgt %p finished\n",
tgt);
+
+ switch (vha->qlini_mode) {
+ case QLA2XXX_INI_MODE_EXCLUSIVE:
+ vha->flags.online = 1;
+ set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ break;
+ default:
+ break;
+ }
}
EXPORT_SYMBOL(qlt_stop_phase2);
@@ -1715,6 +1726,94 @@ static void qlt_send_notify_ack(struct qla_qpair *qpair,
qla2x00_start_iocbs(vha, qpair->req);
}
+static int qlt_build_abts_resp_iocb(struct qla_tgt_mgmt_cmd *mcmd)
+{
+ struct scsi_qla_host *vha = mcmd->vha;
+ struct qla_hw_data *ha = vha->hw;
+ struct abts_resp_to_24xx *resp;
+ uint32_t f_ctl, h;
+ uint8_t *p;
+ int rc;
+ struct abts_recv_from_24xx *abts = &mcmd->orig_iocb.abts;
+ struct qla_qpair *qpair = mcmd->qpair;
+
+ ql_dbg(ql_dbg_tgt, vha, 0xe006,
+ "Sending task mgmt ABTS response (ha=%p, status=%x)\n",
+ ha, mcmd->fc_tm_rsp);
+
+ rc = qlt_check_reserve_free_req(qpair, 1);
+ if (rc) {
+ ql_dbg(ql_dbg_tgt, vha, 0xe04a,
+ "qla_target(%d): %s failed: unable to allocate request packet\n",
+ vha->vp_idx, __func__);
+ return -EAGAIN;
+ }
+
+ resp = (struct abts_resp_to_24xx *)qpair->req->ring_ptr;
+ memset(resp, 0, sizeof(*resp));
+
+ h = qlt_make_handle(qpair);
+ if (unlikely(h == QLA_TGT_NULL_HANDLE)) {
+ /*
+ * CTIO type 7 from the firmware doesn't provide a way to
+ * know the initiator's LOOP ID, hence we can't find
+ * the session and, so, the command.
+ */
+ return -EAGAIN;
+ } else {
+ qpair->req->outstanding_cmds[h] = (srb_t *)mcmd;
+ }
+
+ resp->handle = MAKE_HANDLE(qpair->req->id, h);
+ resp->entry_type = ABTS_RESP_24XX;
+ resp->entry_count = 1;
+ resp->nport_handle = abts->nport_handle;
+ resp->vp_index = vha->vp_idx;
+ resp->sof_type = abts->sof_type;
+ resp->exchange_address = abts->exchange_address;
+ resp->fcp_hdr_le = abts->fcp_hdr_le;
+ f_ctl = cpu_to_le32(F_CTL_EXCH_CONTEXT_RESP |
+ F_CTL_LAST_SEQ | F_CTL_END_SEQ |
+ F_CTL_SEQ_INITIATIVE);
+ p = (uint8_t *)&f_ctl;
+ resp->fcp_hdr_le.f_ctl[0] = *p++;
+ resp->fcp_hdr_le.f_ctl[1] = *p++;
+ resp->fcp_hdr_le.f_ctl[2] = *p;
+
+ resp->fcp_hdr_le.d_id[0] = abts->fcp_hdr_le.s_id[0];
+ resp->fcp_hdr_le.d_id[1] = abts->fcp_hdr_le.s_id[1];
+ resp->fcp_hdr_le.d_id[2] = abts->fcp_hdr_le.s_id[2];
+ resp->fcp_hdr_le.s_id[0] = abts->fcp_hdr_le.d_id[0];
+ resp->fcp_hdr_le.s_id[1] = abts->fcp_hdr_le.d_id[1];
+ resp->fcp_hdr_le.s_id[2] = abts->fcp_hdr_le.d_id[2];
+
+ resp->exchange_addr_to_abort = abts->exchange_addr_to_abort;
+ if (mcmd->fc_tm_rsp == FCP_TMF_CMPL) {
+ resp->fcp_hdr_le.r_ctl = R_CTL_BASIC_LINK_SERV | R_CTL_B_ACC;
+ resp->payload.ba_acct.seq_id_valid = SEQ_ID_INVALID;
+ resp->payload.ba_acct.low_seq_cnt = 0x0000;
+ resp->payload.ba_acct.high_seq_cnt = 0xFFFF;
+ resp->payload.ba_acct.ox_id = abts->fcp_hdr_le.ox_id;
+ resp->payload.ba_acct.rx_id = abts->fcp_hdr_le.rx_id;
+ } else {
+ resp->fcp_hdr_le.r_ctl = R_CTL_BASIC_LINK_SERV | R_CTL_B_RJT;
+ resp->payload.ba_rjt.reason_code =
+ BA_RJT_REASON_CODE_UNABLE_TO_PERFORM;
+ /* Other bytes are zero */
+ }
+
+ vha->vha_tgt.qla_tgt->abts_resp_expected++;
+
+ /* Memory Barrier */
+ wmb();
+ if (qpair->reqq_start_iocbs)
+ qpair->reqq_start_iocbs(qpair);
+ else
+ qla2x00_start_iocbs(vha, qpair->req);
+
+ return rc;
+}
+
/*
* ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire
*/
@@ -1742,6 +1841,7 @@ static void qlt_24xx_send_abts_resp(struct qla_qpair *qpair,
}
resp->entry_type = ABTS_RESP_24XX;
+ resp->handle = QLA_TGT_SKIP_HANDLE;
resp->entry_count = 1;
resp->nport_handle = abts->nport_handle;
resp->vp_index = vha->vp_idx;
@@ -1799,15 +1899,13 @@ static void qlt_24xx_send_abts_resp(struct qla_qpair *qpair,
* ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire
*/
static void qlt_24xx_retry_term_exchange(struct scsi_qla_host *vha,
- struct abts_resp_from_24xx_fw *entry)
+ struct qla_qpair *qpair, response_t *pkt, struct qla_tgt_mgmt_cmd *mcmd)
{
struct ctio7_to_24xx *ctio;
+ u16 tmp;
+ struct abts_recv_from_24xx *entry;
- ql_dbg(ql_dbg_tgt, vha, 0xe007,
- "Sending retry TERM EXCH CTIO7 (ha=%p)\n", vha->hw);
-
- ctio = (struct ctio7_to_24xx *)qla2x00_alloc_iocbs_ready(
- vha->hw->base_qpair, NULL);
+ ctio = (struct ctio7_to_24xx *)qla2x00_alloc_iocbs_ready(qpair, NULL);
if (ctio == NULL) {
ql_dbg(ql_dbg_tgt, vha, 0xe04b,
"qla_target(%d): %s failed: unable to allocate "
@@ -1815,6 +1913,13 @@ static void qlt_24xx_retry_term_exchange(struct scsi_qla_host *vha,
return;
}
+ if (mcmd)
+ /* abts from remote port */
+ entry = &mcmd->orig_iocb.abts;
+ else
+ /* abts from this driver. */
+ entry = (struct abts_recv_from_24xx *)pkt;
+
/*
* We've got on entrance firmware's response on by us generated
* ABTS response. So, in it ID fields are reversed.
@@ -1826,56 +1931,48 @@ static void qlt_24xx_retry_term_exchange(struct scsi_qla_host *vha,
ctio->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK;
ctio->timeout = cpu_to_le16(QLA_TGT_TIMEOUT);
ctio->vp_index = vha->vp_idx;
- ctio->initiator_id[0] = entry->fcp_hdr_le.d_id[0];
- ctio->initiator_id[1] = entry->fcp_hdr_le.d_id[1];
- ctio->initiator_id[2] = entry->fcp_hdr_le.d_id[2];
ctio->exchange_addr = entry->exchange_addr_to_abort;
- ctio->u.status1.flags = cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_1 |
- CTIO7_FLAGS_TERMINATE);
- ctio->u.status1.ox_id = cpu_to_le16(entry->fcp_hdr_le.ox_id);
-
- /* Memory Barrier */
- wmb();
- qla2x00_start_iocbs(vha, vha->req);
+ tmp = (CTIO7_FLAGS_STATUS_MODE_1 | CTIO7_FLAGS_TERMINATE);
- qlt_24xx_send_abts_resp(vha->hw->base_qpair,
- (struct abts_recv_from_24xx *)entry,
- FCP_TMF_CMPL, true);
-}
+ if (mcmd) {
+ ctio->initiator_id[0] = entry->fcp_hdr_le.s_id[0];
+ ctio->initiator_id[1] = entry->fcp_hdr_le.s_id[1];
+ ctio->initiator_id[2] = entry->fcp_hdr_le.s_id[2];
-static int abort_cmd_for_tag(struct scsi_qla_host *vha, uint32_t tag)
-{
- struct qla_tgt_sess_op *op;
- struct qla_tgt_cmd *cmd;
- unsigned long flags;
+ if (mcmd->flags & QLA24XX_MGMT_ABORT_IO_ATTR_VALID)
+ tmp |= (mcmd->abort_io_attr << 9);
+ else if (qpair->retry_term_cnt & 1)
+ tmp |= (0x4 << 9);
+ } else {
+ ctio->initiator_id[0] = entry->fcp_hdr_le.d_id[0];
+ ctio->initiator_id[1] = entry->fcp_hdr_le.d_id[1];
+ ctio->initiator_id[2] = entry->fcp_hdr_le.d_id[2];
- spin_lock_irqsave(&vha->cmd_list_lock, flags);
- list_for_each_entry(op, &vha->qla_sess_op_cmd_list, cmd_list) {
- if (tag == op->atio.u.isp24.exchange_addr) {
- op->aborted = true;
- spin_unlock_irqrestore(&vha->cmd_list_lock, flags);
- return 1;
- }
+ if (qpair->retry_term_cnt & 1)
+ tmp |= (0x4 << 9);
}
+ ctio->u.status1.flags = cpu_to_le16(tmp);
+ ctio->u.status1.ox_id = entry->fcp_hdr_le.ox_id;
- list_for_each_entry(op, &vha->unknown_atio_list, cmd_list) {
- if (tag == op->atio.u.isp24.exchange_addr) {
- op->aborted = true;
- spin_unlock_irqrestore(&vha->cmd_list_lock, flags);
- return 1;
- }
- }
+ ql_dbg(ql_dbg_tgt, vha, 0xe007,
+ "Sending retry TERM EXCH CTIO7 flags %04xh oxid %04xh attr valid %x\n",
+ le16_to_cpu(ctio->u.status1.flags),
+ le16_to_cpu(ctio->u.status1.ox_id),
+ (mcmd && mcmd->flags & QLA24XX_MGMT_ABORT_IO_ATTR_VALID) ? 1 : 0);
- list_for_each_entry(cmd, &vha->qla_cmd_list, cmd_list) {
- if (tag == cmd->atio.u.isp24.exchange_addr) {
- cmd->aborted = 1;
- spin_unlock_irqrestore(&vha->cmd_list_lock, flags);
- return 1;
- }
- }
- spin_unlock_irqrestore(&vha->cmd_list_lock, flags);
+ /* Memory Barrier */
+ wmb();
+ if (qpair->reqq_start_iocbs)
+ qpair->reqq_start_iocbs(qpair);
+ else
+ qla2x00_start_iocbs(vha, qpair->req);
+
+ if (mcmd)
+ qlt_build_abts_resp_iocb(mcmd);
+ else
+ qlt_24xx_send_abts_resp(qpair,
+ (struct abts_recv_from_24xx *)entry, FCP_TMF_CMPL, true);
- return 0;
}
/* drop cmds for the given lun
@@ -1970,9 +2067,8 @@ static void qlt_do_tmr_work(struct work_struct *work)
spin_lock_irqsave(mcmd->qpair->qp_lock_ptr, flags);
switch (mcmd->tmr_func) {
case QLA_TGT_ABTS:
- qlt_24xx_send_abts_resp(mcmd->qpair,
- &mcmd->orig_iocb.abts,
- FCP_TMF_REJECTED, false);
+ mcmd->fc_tm_rsp = FCP_TMF_REJECTED;
+ qlt_build_abts_resp_iocb(mcmd);
break;
case QLA_TGT_LUN_RESET:
case QLA_TGT_CLEAR_TS:
@@ -2007,12 +2103,6 @@ static int __qlt_24xx_handle_abts(struct scsi_qla_host *vha,
struct qla_tgt_mgmt_cmd *mcmd;
struct qla_qpair_hint *h = &vha->vha_tgt.qla_tgt->qphints[0];
- if (abort_cmd_for_tag(vha, abts->exchange_addr_to_abort)) {
- /* send TASK_ABORT response immediately */
- qlt_24xx_send_abts_resp(ha->base_qpair, abts, FCP_TMF_CMPL, false);
- return 0;
- }
-
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf00f,
"qla_target(%d): task abort (tag=%d)\n",
vha->vp_idx, abts->exchange_addr_to_abort);
@@ -2025,7 +2115,7 @@ static int __qlt_24xx_handle_abts(struct scsi_qla_host *vha,
return -ENOMEM;
}
memset(mcmd, 0, sizeof(*mcmd));
-
+ mcmd->cmd_type = TYPE_TGT_TMCMD;
mcmd->sess = sess;
memcpy(&mcmd->orig_iocb.abts, abts, sizeof(mcmd->orig_iocb.abts));
mcmd->reset_count = ha->base_qpair->chip_reset;
@@ -2047,6 +2137,8 @@ static int __qlt_24xx_handle_abts(struct scsi_qla_host *vha,
if (abort_cmd && abort_cmd->qpair) {
mcmd->qpair = abort_cmd->qpair;
mcmd->se_cmd.cpuid = abort_cmd->se_cmd.cpuid;
+ mcmd->abort_io_attr = abort_cmd->atio.u.isp24.attr;
+ mcmd->flags = QLA24XX_MGMT_ABORT_IO_ATTR_VALID;
}
}
@@ -2264,6 +2356,7 @@ void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *mcmd)
struct qla_hw_data *ha = vha->hw;
unsigned long flags;
struct qla_qpair *qpair = mcmd->qpair;
+ bool free_mcmd = true;
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf013,
"TM response mcmd (%p) status %#x state %#x",
@@ -2302,10 +2395,10 @@ void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *mcmd)
&mcmd->orig_iocb.imm_ntfy, 0, 0, 0, 0, 0, 0);
}
} else {
- if (mcmd->orig_iocb.atio.u.raw.entry_type == ABTS_RECV_24XX)
- qlt_24xx_send_abts_resp(qpair, &mcmd->orig_iocb.abts,
- mcmd->fc_tm_rsp, false);
- else
+ if (mcmd->orig_iocb.atio.u.raw.entry_type == ABTS_RECV_24XX) {
+ qlt_build_abts_resp_iocb(mcmd);
+ free_mcmd = false;
+ } else
qlt_24xx_send_task_mgmt_ctio(qpair, mcmd,
mcmd->fc_tm_rsp);
}
@@ -2317,7 +2410,9 @@ void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *mcmd)
* descriptor after TFO->queue_tm_rsp() -> tcm_qla2xxx_queue_tm_rsp() ->
* qlt_xmit_tm_rsp() returns here..
*/
- ha->tgt.tgt_ops->free_mcmd(mcmd);
+ if (free_mcmd)
+ ha->tgt.tgt_ops->free_mcmd(mcmd);
+
spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
}
EXPORT_SYMBOL(qlt_xmit_tm_rsp);
@@ -2330,7 +2425,7 @@ static int qlt_pci_map_calc_cnt(struct qla_tgt_prm *prm)
BUG_ON(cmd->sg_cnt == 0);
prm->sg = (struct scatterlist *)cmd->sg;
- prm->seg_cnt = pci_map_sg(cmd->qpair->pdev, cmd->sg,
+ prm->seg_cnt = dma_map_sg(&cmd->qpair->pdev->dev, cmd->sg,
cmd->sg_cnt, cmd->dma_data_direction);
if (unlikely(prm->seg_cnt == 0))
goto out_err;
@@ -2357,7 +2452,7 @@ static int qlt_pci_map_calc_cnt(struct qla_tgt_prm *prm)
if (cmd->prot_sg_cnt) {
prm->prot_sg = cmd->prot_sg;
- prm->prot_seg_cnt = pci_map_sg(cmd->qpair->pdev,
+ prm->prot_seg_cnt = dma_map_sg(&cmd->qpair->pdev->dev,
cmd->prot_sg, cmd->prot_sg_cnt,
cmd->dma_data_direction);
if (unlikely(prm->prot_seg_cnt == 0))
@@ -2392,12 +2487,12 @@ static void qlt_unmap_sg(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd)
qpair = cmd->qpair;
- pci_unmap_sg(qpair->pdev, cmd->sg, cmd->sg_cnt,
+ dma_unmap_sg(&qpair->pdev->dev, cmd->sg, cmd->sg_cnt,
cmd->dma_data_direction);
cmd->sg_mapped = 0;
if (cmd->prot_sg_cnt)
- pci_unmap_sg(qpair->pdev, cmd->prot_sg, cmd->prot_sg_cnt,
+ dma_unmap_sg(&qpair->pdev->dev, cmd->prot_sg, cmd->prot_sg_cnt,
cmd->dma_data_direction);
if (!cmd->ctx)
@@ -3289,7 +3384,10 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,
cmd->state = QLA_TGT_STATE_PROCESSED; /* Mid-level is done processing */
+ spin_lock(&cmd->cmd_lock);
cmd->cmd_sent_to_fw = 1;
+ spin_unlock(&cmd->cmd_lock);
+ cmd->ctio_flags = le16_to_cpu(pkt->u.status0.flags);
/* Memory Barrier */
wmb();
@@ -3367,7 +3465,10 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd)
qlt_load_data_segments(&prm);
cmd->state = QLA_TGT_STATE_NEED_DATA;
+ spin_lock(&cmd->cmd_lock);
cmd->cmd_sent_to_fw = 1;
+ spin_unlock(&cmd->cmd_lock);
+ cmd->ctio_flags = le16_to_cpu(pkt->u.status0.flags);
/* Memory Barrier */
wmb();
@@ -3825,10 +3926,10 @@ static int qlt_term_ctio_exchange(struct qla_qpair *qpair, void *ctio,
/* ha->hardware_lock supposed to be held on entry */
-static struct qla_tgt_cmd *qlt_ctio_to_cmd(struct scsi_qla_host *vha,
+static void *qlt_ctio_to_cmd(struct scsi_qla_host *vha,
struct rsp_que *rsp, uint32_t handle, void *ctio)
{
- struct qla_tgt_cmd *cmd = NULL;
+ void *cmd = NULL;
struct req_que *req;
int qid = GET_QID(handle);
uint32_t h = handle & ~QLA_TGT_HANDLE_MASK;
@@ -3857,7 +3958,7 @@ static struct qla_tgt_cmd *qlt_ctio_to_cmd(struct scsi_qla_host *vha,
return NULL;
}
- cmd = (struct qla_tgt_cmd *)req->outstanding_cmds[h];
+ cmd = (void *) req->outstanding_cmds[h];
if (unlikely(cmd == NULL)) {
ql_dbg(ql_dbg_async, vha, 0xe053,
"qla_target(%d): Suspicious: unable to find the command with handle %x req->id %d rsp->id %d\n",
@@ -3930,7 +4031,7 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha,
return;
}
- cmd = qlt_ctio_to_cmd(vha, rsp, handle, ctio);
+ cmd = (struct qla_tgt_cmd *)qlt_ctio_to_cmd(vha, rsp, handle, ctio);
if (cmd == NULL)
return;
@@ -3941,12 +4042,20 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha,
if (unlikely(status != CTIO_SUCCESS)) {
switch (status & 0xFFFF) {
+ case CTIO_INVALID_RX_ID:
+ if (printk_ratelimit())
+ dev_info(&vha->hw->pdev->dev,
+ "qla_target(%d): CTIO with INVALID_RX_ID ATIO attr %x CTIO Flags %x|%x\n",
+ vha->vp_idx, cmd->atio.u.isp24.attr,
+ ((cmd->ctio_flags >> 9) & 0xf),
+ cmd->ctio_flags);
+
+ break;
case CTIO_LIP_RESET:
case CTIO_TARGET_RESET:
case CTIO_ABORTED:
/* driver request abort via Terminate exchange */
case CTIO_TIMEOUT:
- case CTIO_INVALID_RX_ID:
/* They are OK */
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf058,
"qla_target(%d): CTIO with "
@@ -3973,7 +4082,6 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha,
* Session is already logged out, but we need
* to notify initiator, who's not aware of this
*/
- cmd->sess->logout_on_delete = 0;
cmd->sess->send_els_logo = 1;
ql_dbg(ql_dbg_disc, vha, 0x20f8,
"%s %d %8phC post del sess\n",
@@ -4432,7 +4540,7 @@ static int qlt_issue_task_mgmt(struct fc_port *sess, u64 lun,
case QLA_TGT_CLEAR_TS:
case QLA_TGT_ABORT_TS:
abort_cmds_for_lun(vha, lun, a->u.isp24.fcp_hdr.s_id);
- /* drop through */
+ /* fall through */
case QLA_TGT_CLEAR_ACA:
h = qlt_find_qphint(vha, mcmd->unpacked_lun);
mcmd->qpair = h->qpair;
@@ -4711,6 +4819,12 @@ static int qlt_handle_login(struct scsi_qla_host *vha,
sess = qlt_find_sess_invalidate_other(vha, wwn,
port_id, loop_id, &conflict_sess);
spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
+ } else {
+ ql_dbg(ql_dbg_disc, vha, 0xffff,
+ "%s %d Term INOT due to WWN=0 lid=%d, NportID %06X ",
+ __func__, __LINE__, loop_id, port_id.b24);
+ qlt_send_term_imm_notif(vha, iocb, 1);
+ goto out;
}
if (IS_SW_RESV_ADDR(port_id)) {
@@ -4752,6 +4866,32 @@ static int qlt_handle_login(struct scsi_qla_host *vha,
goto out;
}
+ if (sess->disc_state == DSC_UPD_FCPORT) {
+ u16 sec;
+
+ /*
+ * Remote port registration is still going on from
+ * previous login. Allow it to finish before we
+ * accept the new login.
+ */
+ sess->next_disc_state = DSC_DELETE_PEND;
+ sec = jiffies_to_msecs(jiffies -
+ sess->jiffies_at_registration) / 1000;
+ if (sess->sec_since_registration < sec && sec &&
+ !(sec % 5)) {
+ sess->sec_since_registration = sec;
+ ql_dbg(ql_dbg_disc, vha, 0xffff,
+ "%s %8phC - Slow Rport registration (%d Sec)\n",
+ __func__, sess->port_name, sec);
+ }
+
+ if (!conflict_sess)
+ kmem_cache_free(qla_tgt_plogi_cachep, pla);
+
+ qlt_send_term_imm_notif(vha, iocb, 1);
+ goto out;
+ }
+
qlt_plogi_ack_link(vha, pla, sess, QLT_PLOGI_LINK_SAME_WWN);
sess->d_id = port_id;
sess->login_gen++;
@@ -4910,6 +5050,7 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha,
if (sess != NULL) {
bool delete = false;
+ int sec;
spin_lock_irqsave(&tgt->ha->tgt.sess_lock, flags);
switch (sess->fw_login_state) {
case DSC_LS_PLOGI_PEND:
@@ -4922,9 +5063,24 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha,
}
switch (sess->disc_state) {
+ case DSC_UPD_FCPORT:
+ spin_unlock_irqrestore(&tgt->ha->tgt.sess_lock,
+ flags);
+
+ sec = jiffies_to_msecs(jiffies -
+ sess->jiffies_at_registration)/1000;
+ if (sess->sec_since_registration < sec && sec &&
+ !(sec % 5)) {
+ sess->sec_since_registration = sec;
+ ql_dbg(ql_dbg_disc, sess->vha, 0xffff,
+ "%s %8phC : Slow Rport registration(%d Sec)\n",
+ __func__, sess->port_name, sec);
+ }
+ qlt_send_term_imm_notif(vha, iocb, 1);
+ return 0;
+
case DSC_LOGIN_PEND:
case DSC_GPDB:
- case DSC_UPD_FCPORT:
case DSC_LOGIN_COMPLETE:
case DSC_ADISC:
delete = false;
@@ -5608,6 +5764,101 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
tgt->atio_irq_cmd_count--;
}
+/*
+ * qpair lock is assume to be held
+ * rc = 0 : send terminate & abts respond
+ * rc != 0: do not send term & abts respond
+ */
+static int qlt_chk_unresolv_exchg(struct scsi_qla_host *vha,
+ struct qla_qpair *qpair, struct abts_resp_from_24xx_fw *entry)
+{
+ struct qla_hw_data *ha = vha->hw;
+ int rc = 0;
+
+ /*
+ * Detect unresolved exchange. If the same ABTS is unable
+ * to terminate an existing command and the same ABTS loops
+ * between FW & Driver, then force FW dump. Under 1 jiff,
+ * we should see multiple loops.
+ */
+ if (qpair->retry_term_exchg_addr == entry->exchange_addr_to_abort &&
+ qpair->retry_term_jiff == jiffies) {
+ /* found existing exchange */
+ qpair->retry_term_cnt++;
+ if (qpair->retry_term_cnt >= 5) {
+ rc = EIO;
+ qpair->retry_term_cnt = 0;
+ ql_log(ql_log_warn, vha, 0xffff,
+ "Unable to send ABTS Respond. Dumping firmware.\n");
+ ql_dump_buffer(ql_dbg_tgt_mgt + ql_dbg_buffer,
+ vha, 0xffff, (uint8_t *)entry, sizeof(*entry));
+
+ if (qpair == ha->base_qpair)
+ ha->isp_ops->fw_dump(vha, 1);
+ else
+ ha->isp_ops->fw_dump(vha, 0);
+
+ set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ qla2xxx_wake_dpc(vha);
+ }
+ } else if (qpair->retry_term_jiff != jiffies) {
+ qpair->retry_term_exchg_addr = entry->exchange_addr_to_abort;
+ qpair->retry_term_cnt = 0;
+ qpair->retry_term_jiff = jiffies;
+ }
+
+ return rc;
+}
+
+
+static void qlt_handle_abts_completion(struct scsi_qla_host *vha,
+ struct rsp_que *rsp, response_t *pkt)
+{
+ struct abts_resp_from_24xx_fw *entry =
+ (struct abts_resp_from_24xx_fw *)pkt;
+ u32 h = pkt->handle & ~QLA_TGT_HANDLE_MASK;
+ struct qla_tgt_mgmt_cmd *mcmd;
+ struct qla_hw_data *ha = vha->hw;
+
+ mcmd = (struct qla_tgt_mgmt_cmd *)qlt_ctio_to_cmd(vha, rsp,
+ pkt->handle, pkt);
+ if (mcmd == NULL && h != QLA_TGT_SKIP_HANDLE) {
+ ql_dbg(ql_dbg_async, vha, 0xe064,
+ "qla_target(%d): ABTS Comp without mcmd\n",
+ vha->vp_idx);
+ return;
+ }
+
+ if (mcmd)
+ vha = mcmd->vha;
+ vha->vha_tgt.qla_tgt->abts_resp_expected--;
+
+ ql_dbg(ql_dbg_tgt, vha, 0xe038,
+ "ABTS_RESP_24XX: compl_status %x\n",
+ entry->compl_status);
+
+ if (le16_to_cpu(entry->compl_status) != ABTS_RESP_COMPL_SUCCESS) {
+ if ((entry->error_subcode1 == 0x1E) &&
+ (entry->error_subcode2 == 0)) {
+ if (qlt_chk_unresolv_exchg(vha, rsp->qpair, entry)) {
+ ha->tgt.tgt_ops->free_mcmd(mcmd);
+ return;
+ }
+ qlt_24xx_retry_term_exchange(vha, rsp->qpair,
+ pkt, mcmd);
+ } else {
+ ql_dbg(ql_dbg_tgt, vha, 0xe063,
+ "qla_target(%d): ABTS_RESP_24XX failed %x (subcode %x:%x)",
+ vha->vp_idx, entry->compl_status,
+ entry->error_subcode1,
+ entry->error_subcode2);
+ ha->tgt.tgt_ops->free_mcmd(mcmd);
+ }
+ } else {
+ ha->tgt.tgt_ops->free_mcmd(mcmd);
+ }
+}
+
/* ha->hardware_lock supposed to be held on entry */
/* called via callback from qla2xxx */
static void qlt_response_pkt(struct scsi_qla_host *vha,
@@ -5740,41 +5991,7 @@ static void qlt_response_pkt(struct scsi_qla_host *vha,
case ABTS_RESP_24XX:
if (tgt->abts_resp_expected > 0) {
- struct abts_resp_from_24xx_fw *entry =
- (struct abts_resp_from_24xx_fw *)pkt;
- ql_dbg(ql_dbg_tgt, vha, 0xe038,
- "ABTS_RESP_24XX: compl_status %x\n",
- entry->compl_status);
- tgt->abts_resp_expected--;
- if (le16_to_cpu(entry->compl_status) !=
- ABTS_RESP_COMPL_SUCCESS) {
- if ((entry->error_subcode1 == 0x1E) &&
- (entry->error_subcode2 == 0)) {
- /*
- * We've got a race here: aborted
- * exchange not terminated, i.e.
- * response for the aborted command was
- * sent between the abort request was
- * received and processed.
- * Unfortunately, the firmware has a
- * silly requirement that all aborted
- * exchanges must be explicitely
- * terminated, otherwise it refuses to
- * send responses for the abort
- * requests. So, we have to
- * (re)terminate the exchange and retry
- * the abort response.
- */
- qlt_24xx_retry_term_exchange(vha,
- entry);
- } else
- ql_dbg(ql_dbg_tgt, vha, 0xe063,
- "qla_target(%d): ABTS_RESP_24XX "
- "failed %x (subcode %x:%x)",
- vha->vp_idx, entry->compl_status,
- entry->error_subcode1,
- entry->error_subcode2);
- }
+ qlt_handle_abts_completion(vha, rsp, pkt);
} else {
ql_dbg(ql_dbg_tgt, vha, 0xe064,
"qla_target(%d): Unexpected ABTS_RESP_24XX "
@@ -5964,10 +6181,7 @@ static fc_port_t *qlt_get_port_database(struct scsi_qla_host *vha,
case MODE_DUAL:
if (newfcport) {
if (!IS_IIDMA_CAPABLE(vha->hw) || !vha->hw->flags.gpsc_supported) {
- ql_dbg(ql_dbg_disc, vha, 0x20fe,
- "%s %d %8phC post upd_fcport fcp_cnt %d\n",
- __func__, __LINE__, fcport->port_name, vha->fcport_count);
- qla24xx_post_upd_fcport_work(vha, fcport);
+ qla24xx_sched_upd_fcport(fcport);
} else {
ql_dbg(ql_dbg_disc, vha, 0x20ff,
"%s %d %8phC post gpsc fcp_cnt %d\n",
@@ -6384,9 +6598,9 @@ static void qlt_lport_dump(struct scsi_qla_host *vha, u64 wwpn,
* qla_tgt_lport_register - register lport with external module
*
* @target_lport_ptr: pointer for tcm_qla2xxx specific lport data
- * @phys_wwpn:
- * @npiv_wwpn:
- * @npiv_wwnn:
+ * @phys_wwpn: physical port WWPN
+ * @npiv_wwpn: NPIV WWPN
+ * @npiv_wwnn: NPIV WWNN
* @callback: lport initialization callback for tcm_qla2xxx code
*/
int qlt_lport_register(void *target_lport_ptr, u64 phys_wwpn,
@@ -6413,6 +6627,9 @@ int qlt_lport_register(void *target_lport_ptr, u64 phys_wwpn,
if (!(host->hostt->supported_mode & MODE_TARGET))
continue;
+ if (vha->qlini_mode == QLA2XXX_INI_MODE_ENABLED)
+ continue;
+
spin_lock_irqsave(&ha->hardware_lock, flags);
if ((!npiv_wwpn || !npiv_wwnn) && host->active_mode & MODE_TARGET) {
pr_debug("MODE_TARGET already active on qla2xxx(%d)\n",
@@ -6475,15 +6692,15 @@ void qlt_lport_deregister(struct scsi_qla_host *vha)
EXPORT_SYMBOL(qlt_lport_deregister);
/* Must be called under HW lock */
-static void qlt_set_mode(struct scsi_qla_host *vha)
+void qlt_set_mode(struct scsi_qla_host *vha)
{
- switch (ql2x_ini_mode) {
+ switch (vha->qlini_mode) {
case QLA2XXX_INI_MODE_DISABLED:
case QLA2XXX_INI_MODE_EXCLUSIVE:
vha->host->active_mode = MODE_TARGET;
break;
case QLA2XXX_INI_MODE_ENABLED:
- vha->host->active_mode = MODE_UNKNOWN;
+ vha->host->active_mode = MODE_INITIATOR;
break;
case QLA2XXX_INI_MODE_DUAL:
vha->host->active_mode = MODE_DUAL;
@@ -6496,7 +6713,7 @@ static void qlt_set_mode(struct scsi_qla_host *vha)
/* Must be called under HW lock */
static void qlt_clear_mode(struct scsi_qla_host *vha)
{
- switch (ql2x_ini_mode) {
+ switch (vha->qlini_mode) {
case QLA2XXX_INI_MODE_DISABLED:
vha->host->active_mode = MODE_UNKNOWN;
break;
@@ -6532,12 +6749,17 @@ qlt_enable_vha(struct scsi_qla_host *vha)
dump_stack();
return;
}
+ if (vha->qlini_mode == QLA2XXX_INI_MODE_ENABLED)
+ return;
spin_lock_irqsave(&ha->hardware_lock, flags);
tgt->tgt_stopped = 0;
qlt_set_mode(vha);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ mutex_lock(&ha->optrom_mutex);
+ ql_dbg(ql_dbg_tgt_mgt, vha, 0xf021,
+ "%s.\n", __func__);
if (vha->vp_idx) {
qla24xx_disable_vp(vha);
qla24xx_enable_vp(vha);
@@ -6546,6 +6768,7 @@ qlt_enable_vha(struct scsi_qla_host *vha)
qla2xxx_wake_dpc(base_vha);
qla2x00_wait_for_hba_online(base_vha);
}
+ mutex_unlock(&ha->optrom_mutex);
}
EXPORT_SYMBOL(qlt_enable_vha);
@@ -6767,7 +6990,7 @@ qlt_24xx_config_nvram_stage1(struct scsi_qla_host *vha, struct nvram_24xx *nv)
if (qla_tgt_mode_enabled(vha))
nv->exchange_count = cpu_to_le16(0xFFFF);
else /* dual */
- nv->exchange_count = cpu_to_le16(ql2xexchoffld);
+ nv->exchange_count = cpu_to_le16(vha->ql2xexchoffld);
/* Enable target mode */
nv->firmware_options_1 |= cpu_to_le32(BIT_4);
@@ -6846,14 +7069,6 @@ qlt_24xx_config_nvram_stage2(struct scsi_qla_host *vha,
memcpy(icb->node_name, ha->tgt.tgt_node_name, WWN_SIZE);
icb->firmware_options_1 |= cpu_to_le32(BIT_14);
}
-
- /* disable ZIO at start time. */
- if (!vha->flags.init_done) {
- uint32_t tmp;
- tmp = le32_to_cpu(icb->firmware_options_2);
- tmp &= ~(BIT_3 | BIT_2 | BIT_1 | BIT_0);
- icb->firmware_options_2 = cpu_to_le32(tmp);
- }
}
void
@@ -6881,7 +7096,7 @@ qlt_81xx_config_nvram_stage1(struct scsi_qla_host *vha, struct nvram_81xx *nv)
if (qla_tgt_mode_enabled(vha))
nv->exchange_count = cpu_to_le16(0xFFFF);
else /* dual */
- nv->exchange_count = cpu_to_le16(ql2xexchoffld);
+ nv->exchange_count = cpu_to_le16(vha->ql2xexchoffld);
/* Enable target mode */
nv->firmware_options_1 |= cpu_to_le32(BIT_4);
@@ -6957,15 +7172,6 @@ qlt_81xx_config_nvram_stage2(struct scsi_qla_host *vha,
memcpy(icb->node_name, ha->tgt.tgt_node_name, WWN_SIZE);
icb->firmware_options_1 |= cpu_to_le32(BIT_14);
}
-
- /* disable ZIO at start time. */
- if (!vha->flags.init_done) {
- uint32_t tmp;
- tmp = le32_to_cpu(icb->firmware_options_2);
- tmp &= ~(BIT_3 | BIT_2 | BIT_1 | BIT_0);
- icb->firmware_options_2 = cpu_to_le32(tmp);
- }
-
}
void
diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h
index 199d3ba1916d..721da593b1bc 100644
--- a/drivers/scsi/qla2xxx/qla_target.h
+++ b/drivers/scsi/qla2xxx/qla_target.h
@@ -900,6 +900,7 @@ struct qla_tgt_cmd {
unsigned int aborted:1;
unsigned int data_work:1;
unsigned int data_work_free:1;
+ unsigned int released:1;
struct scatterlist *sg; /* cmd data buffer SG vector */
int sg_cnt; /* SG segments count */
@@ -908,6 +909,7 @@ struct qla_tgt_cmd {
u64 unpacked_lun;
enum dma_data_direction dma_data_direction;
+ uint16_t ctio_flags;
uint16_t vp_idx;
uint16_t loop_id; /* to save extra sess dereferences */
struct qla_tgt *tgt; /* to save extra sess dereferences */
@@ -956,16 +958,20 @@ struct qla_tgt_sess_work_param {
};
struct qla_tgt_mgmt_cmd {
+ uint8_t cmd_type;
+ uint8_t pad[3];
uint16_t tmr_func;
uint8_t fc_tm_rsp;
+ uint8_t abort_io_attr;
struct fc_port *sess;
struct qla_qpair *qpair;
struct scsi_qla_host *vha;
struct se_cmd se_cmd;
struct work_struct free_work;
unsigned int flags;
+#define QLA24XX_MGMT_SEND_NACK BIT_0
+#define QLA24XX_MGMT_ABORT_IO_ATTR_VALID BIT_1
uint32_t reset_count;
-#define QLA24XX_MGMT_SEND_NACK 1
struct work_struct work;
uint64_t unpacked_lun;
union {
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index 3850b28518e5..12bafff71a1a 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,7 +7,7 @@
/*
* Driver version
*/
-#define QLA2XXX_VERSION "10.00.00.08-k"
+#define QLA2XXX_VERSION "10.00.00.11-k"
#define QLA_DRIVER_MAJOR_VER 10
#define QLA_DRIVER_MINOR_VER 0
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
index e03d12a5f986..65053c066680 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -277,14 +277,25 @@ static void tcm_qla2xxx_free_mcmd(struct qla_tgt_mgmt_cmd *mcmd)
static void tcm_qla2xxx_complete_free(struct work_struct *work)
{
struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work);
+ bool released = false;
+ unsigned long flags;
cmd->cmd_in_wq = 0;
WARN_ON(cmd->trc_flags & TRC_CMD_FREE);
+ spin_lock_irqsave(&cmd->cmd_lock, flags);
cmd->qpair->tgt_counters.qla_core_ret_sta_ctio++;
cmd->trc_flags |= TRC_CMD_FREE;
- transport_generic_free_cmd(&cmd->se_cmd, 0);
+ cmd->cmd_sent_to_fw = 0;
+ if (cmd->released)
+ released = true;
+ spin_unlock_irqrestore(&cmd->cmd_lock, flags);
+
+ if (released)
+ qlt_free_cmd(cmd);
+ else
+ transport_generic_free_cmd(&cmd->se_cmd, 0);
}
/*
@@ -325,6 +336,7 @@ static int tcm_qla2xxx_check_stop_free(struct se_cmd *se_cmd)
static void tcm_qla2xxx_release_cmd(struct se_cmd *se_cmd)
{
struct qla_tgt_cmd *cmd;
+ unsigned long flags;
if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB) {
struct qla_tgt_mgmt_cmd *mcmd = container_of(se_cmd,
@@ -332,9 +344,16 @@ static void tcm_qla2xxx_release_cmd(struct se_cmd *se_cmd)
qlt_free_mcmd(mcmd);
return;
}
-
cmd = container_of(se_cmd, struct qla_tgt_cmd, se_cmd);
- qlt_free_cmd(cmd);
+
+ spin_lock_irqsave(&cmd->cmd_lock, flags);
+ if (cmd->cmd_sent_to_fw) {
+ cmd->released = 1;
+ spin_unlock_irqrestore(&cmd->cmd_lock, flags);
+ } else {
+ spin_unlock_irqrestore(&cmd->cmd_lock, flags);
+ qlt_free_cmd(cmd);
+ }
}
static void tcm_qla2xxx_release_session(struct kref *kref)
@@ -405,7 +424,7 @@ static int tcm_qla2xxx_write_pending(struct se_cmd *se_cmd)
se_cmd->pi_err = 0;
/*
- * qla_target.c:qlt_rdy_to_xfer() will call pci_map_sg() to setup
+ * qla_target.c:qlt_rdy_to_xfer() will call dma_map_sg() to setup
* the SGL mappings into PCIe memory for incoming FCP WRITE data.
*/
return qlt_rdy_to_xfer(cmd);
@@ -499,6 +518,7 @@ static int tcm_qla2xxx_handle_cmd(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd,
static void tcm_qla2xxx_handle_data_work(struct work_struct *work)
{
struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work);
+ unsigned long flags;
/*
* Ensure that the complete FCP WRITE payload has been received.
@@ -506,6 +526,25 @@ static void tcm_qla2xxx_handle_data_work(struct work_struct *work)
*/
cmd->cmd_in_wq = 0;
+ spin_lock_irqsave(&cmd->cmd_lock, flags);
+ cmd->cmd_sent_to_fw = 0;
+
+ if (cmd->released) {
+ spin_unlock_irqrestore(&cmd->cmd_lock, flags);
+ qlt_free_cmd(cmd);
+ return;
+ }
+
+ cmd->data_work = 1;
+ if (cmd->aborted) {
+ cmd->data_work_free = 1;
+ spin_unlock_irqrestore(&cmd->cmd_lock, flags);
+
+ tcm_qla2xxx_free_cmd(cmd);
+ return;
+ }
+ spin_unlock_irqrestore(&cmd->cmd_lock, flags);
+
cmd->qpair->tgt_counters.qla_core_ret_ctio++;
if (!cmd->write_data_transferred) {
/*
@@ -718,10 +757,6 @@ static int tcm_qla2xxx_queue_status(struct se_cmd *se_cmd)
cmd->sg_cnt = 0;
cmd->offset = 0;
cmd->dma_data_direction = target_reverse_dma_direction(se_cmd);
- if (cmd->trc_flags & TRC_XMIT_STATUS) {
- pr_crit("Multiple calls for status = %p.\n", cmd);
- dump_stack();
- }
cmd->trc_flags |= TRC_XMIT_STATUS;
if (se_cmd->data_direction == DMA_FROM_DEVICE) {
diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c
index 52b1a0bc93c9..1ef74aa2d00a 100644
--- a/drivers/scsi/qla4xxx/ql4_init.c
+++ b/drivers/scsi/qla4xxx/ql4_init.c
@@ -766,12 +766,10 @@ int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a)
while (drvr_wait) {
if (ql4xxx_lock_drvr(a) == 0) {
ssleep(QL4_LOCK_DRVR_SLEEP);
- if (drvr_wait) {
- DEBUG2(printk("scsi%ld: %s: Waiting for "
- "Global Init Semaphore(%d)...\n",
- a->host_no,
- __func__, drvr_wait));
- }
+ DEBUG2(printk("scsi%ld: %s: Waiting for "
+ "Global Init Semaphore(%d)...\n",
+ a->host_no,
+ __func__, drvr_wait));
drvr_wait -= QL4_LOCK_DRVR_SLEEP;
} else {
DEBUG2(printk("scsi%ld: %s: Global Init Semaphore "
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index 0e13349dce57..051164f755a4 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -3382,7 +3382,7 @@ static int qla4xxx_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
if (task->data_count) {
task_data->data_dma = dma_map_single(&ha->pdev->dev, task->data,
task->data_count,
- PCI_DMA_TODEVICE);
+ DMA_TO_DEVICE);
}
DEBUG2(ql4_printk(KERN_INFO, ha, "%s: MaxRecvLen %u, iscsi hrd %d\n",
@@ -3437,7 +3437,7 @@ static void qla4xxx_task_cleanup(struct iscsi_task *task)
if (task->data_count) {
dma_unmap_single(&ha->pdev->dev, task_data->data_dma,
- task->data_count, PCI_DMA_TODEVICE);
+ task->data_count, DMA_TO_DEVICE);
}
DEBUG2(ql4_printk(KERN_INFO, ha, "%s: MaxRecvLen %u, iscsi hrd %d\n",
@@ -9020,25 +9020,16 @@ static void qla4xxx_remove_adapter(struct pci_dev *pdev)
/**
* qla4xxx_config_dma_addressing() - Configure OS DMA addressing method.
* @ha: HA context
- *
- * At exit, the @ha's flags.enable_64bit_addressing set to indicated
- * supported addressing method.
*/
static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha)
{
- int retval;
-
/* Update our PCI device dma_mask for full 64 bit mask */
- if (pci_set_dma_mask(ha->pdev, DMA_BIT_MASK(64)) == 0) {
- if (pci_set_consistent_dma_mask(ha->pdev, DMA_BIT_MASK(64))) {
- dev_dbg(&ha->pdev->dev,
- "Failed to set 64 bit PCI consistent mask; "
- "using 32 bit.\n");
- retval = pci_set_consistent_dma_mask(ha->pdev,
- DMA_BIT_MASK(32));
- }
- } else
- retval = pci_set_dma_mask(ha->pdev, DMA_BIT_MASK(32));
+ if (dma_set_mask_and_coherent(&ha->pdev->dev, DMA_BIT_MASK(64))) {
+ dev_dbg(&ha->pdev->dev,
+ "Failed to set 64 bit PCI consistent mask; "
+ "using 32 bit.\n");
+ dma_set_mask_and_coherent(&ha->pdev->dev, DMA_BIT_MASK(32));
+ }
}
static int qla4xxx_slave_alloc(struct scsi_device *sdev)
@@ -9824,7 +9815,6 @@ qla4xxx_pci_resume(struct pci_dev *pdev)
__func__);
}
- pci_cleanup_aer_uncorrect_error_status(pdev);
clear_bit(AF_EEH_BUSY, &ha->flags);
}
diff --git a/drivers/scsi/raid_class.c b/drivers/scsi/raid_class.c
index ea88906d2cc5..5c3d6e1e0145 100644
--- a/drivers/scsi/raid_class.c
+++ b/drivers/scsi/raid_class.c
@@ -63,8 +63,7 @@ static int raid_match(struct attribute_container *cont, struct device *dev)
* emulated RAID devices, so start with SCSI */
struct raid_internal *i = ac_to_raid_internal(cont);
-#if defined(CONFIG_SCSI) || defined(CONFIG_SCSI_MODULE)
- if (scsi_is_sdev_device(dev)) {
+ if (IS_ENABLED(CONFIG_SCSI) && scsi_is_sdev_device(dev)) {
struct scsi_device *sdev = to_scsi_device(dev);
if (i->f->cookie != sdev->host->hostt)
@@ -72,7 +71,6 @@ static int raid_match(struct attribute_container *cont, struct device *dev)
return i->f->is_raid(dev);
}
-#endif
/* FIXME: look at other subsystems too */
return 0;
}
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index b7a8fdfeb2f4..c736d61b1648 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -338,9 +338,6 @@ int scsi_block_when_processing_errors(struct scsi_device *sdev)
online = scsi_device_online(sdev);
- SCSI_LOG_ERROR_RECOVERY(5, sdev_printk(KERN_INFO, sdev,
- "%s: rtn: %d\n", __func__, online));
-
return online;
}
EXPORT_SYMBOL(scsi_block_when_processing_errors);
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index eb97d2dd3651..fa6e0c3b3aa6 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -697,6 +697,12 @@ static bool scsi_end_request(struct request *req, blk_status_t error,
*/
scsi_mq_uninit_cmd(cmd);
+ /*
+ * queue is still alive, so grab the ref for preventing it
+ * from being cleaned up during running queue.
+ */
+ percpu_ref_get(&q->q_usage_counter);
+
__blk_mq_end_request(req, error);
if (scsi_target(sdev)->single_lun ||
@@ -704,6 +710,8 @@ static bool scsi_end_request(struct request *req, blk_status_t error,
kblockd_schedule_work(&sdev->requeue_work);
else
blk_mq_run_hw_queues(q, true);
+
+ percpu_ref_put(&q->q_usage_counter);
} else {
unsigned long flags;
@@ -1201,8 +1209,8 @@ int scsi_init_io(struct scsi_cmnd *cmd)
count = blk_rq_map_integrity_sg(rq->q, rq->bio,
prot_sdb->table.sgl);
- BUG_ON(unlikely(count > ivecs));
- BUG_ON(unlikely(count > queue_max_integrity_segments(rq->q)));
+ BUG_ON(count > ivecs);
+ BUG_ON(count > queue_max_integrity_segments(rq->q));
cmd->prot_sdb = prot_sdb;
cmd->prot_sdb->table.nents = count;
@@ -2753,6 +2761,7 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state)
switch (oldstate) {
case SDEV_RUNNING:
case SDEV_CREATED_BLOCK:
+ case SDEV_OFFLINE:
break;
default:
goto illegal;
@@ -3046,11 +3055,14 @@ scsi_device_quiesce(struct scsi_device *sdev)
*/
WARN_ON_ONCE(sdev->quiesced_by && sdev->quiesced_by != current);
- blk_set_preempt_only(q);
+ if (sdev->quiesced_by == current)
+ return 0;
+
+ blk_set_pm_only(q);
blk_mq_freeze_queue(q);
/*
- * Ensure that the effect of blk_set_preempt_only() will be visible
+ * Ensure that the effect of blk_set_pm_only() will be visible
* for percpu_ref_tryget() callers that occur after the queue
* unfreeze even if the queue was already frozen before this function
* was called. See also https://lwn.net/Articles/573497/.
@@ -3063,7 +3075,7 @@ scsi_device_quiesce(struct scsi_device *sdev)
if (err == 0)
sdev->quiesced_by = current;
else
- blk_clear_preempt_only(q);
+ blk_clear_pm_only(q);
mutex_unlock(&sdev->state_mutex);
return err;
@@ -3088,7 +3100,7 @@ void scsi_device_resume(struct scsi_device *sdev)
mutex_lock(&sdev->state_mutex);
WARN_ON_ONCE(!sdev->quiesced_by);
sdev->quiesced_by = NULL;
- blk_clear_preempt_only(sdev->request_queue);
+ blk_clear_pm_only(sdev->request_queue);
if (sdev->sdev_state == SDEV_QUIESCE)
scsi_device_set_state(sdev, SDEV_RUNNING);
mutex_unlock(&sdev->state_mutex);
diff --git a/drivers/scsi/scsi_pm.c b/drivers/scsi/scsi_pm.c
index b44c1bb687a2..a2b4179bfdf7 100644
--- a/drivers/scsi/scsi_pm.c
+++ b/drivers/scsi/scsi_pm.c
@@ -8,6 +8,7 @@
#include <linux/pm_runtime.h>
#include <linux/export.h>
#include <linux/async.h>
+#include <linux/blk-pm.h>
#include <scsi/scsi.h>
#include <scsi/scsi_device.h>
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index 0cd16e80b019..0a165b2b3e81 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -612,7 +612,6 @@ sas_phy_protocol_attr(identify.target_port_protocols,
sas_phy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n",
unsigned long long);
sas_phy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8);
-//sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", int);
sas_phy_linkspeed_attr(negotiated_linkrate);
sas_phy_linkspeed_attr(minimum_linkrate_hw);
sas_phy_linkspeed_rw_attr(minimum_linkrate);
@@ -1802,7 +1801,6 @@ sas_attach_transport(struct sas_function_template *ft)
SETUP_PHY_ATTRIBUTE(device_type);
SETUP_PHY_ATTRIBUTE(sas_address);
SETUP_PHY_ATTRIBUTE(phy_identifier);
- //SETUP_PHY_ATTRIBUTE(port_identifier);
SETUP_PHY_ATTRIBUTE(negotiated_linkrate);
SETUP_PHY_ATTRIBUTE(minimum_linkrate_hw);
SETUP_PHY_ATTRIBUTE_RW(minimum_linkrate);
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 4a57ffecc7e6..3bb2b3351e35 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -45,6 +45,7 @@
#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/blkpg.h>
+#include <linux/blk-pm.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/string_helpers.h>
@@ -1271,8 +1272,6 @@ static int sd_init_command(struct scsi_cmnd *cmd)
case REQ_OP_READ:
case REQ_OP_WRITE:
return sd_setup_read_write_cmnd(cmd);
- case REQ_OP_ZONE_REPORT:
- return sd_zbc_setup_report_cmnd(cmd);
case REQ_OP_ZONE_RESET:
return sd_zbc_setup_reset_cmnd(cmd);
default:
@@ -1801,6 +1800,7 @@ static const struct block_device_operations sd_fops = {
.check_events = sd_check_events,
.revalidate_disk = sd_revalidate_disk,
.unlock_native_capacity = sd_unlock_native_capacity,
+ .report_zones = sd_zbc_report_zones,
.pr_ops = &sd_pr_ops,
};
@@ -1952,16 +1952,6 @@ static int sd_done(struct scsi_cmnd *SCpnt)
scsi_set_resid(SCpnt, blk_rq_bytes(req));
}
break;
- case REQ_OP_ZONE_REPORT:
- if (!result) {
- good_bytes = scsi_bufflen(SCpnt)
- - scsi_get_resid(SCpnt);
- scsi_set_resid(SCpnt, 0);
- } else {
- good_bytes = 0;
- scsi_set_resid(SCpnt, blk_rq_bytes(req));
- }
- break;
default:
/*
* In case of bogus fw or device, we could end up having
@@ -3275,7 +3265,7 @@ static void sd_probe_async(void *data, async_cookie_t cookie)
}
blk_pm_runtime_init(sdp->request_queue, dev);
- device_add_disk(dev, gd);
+ device_add_disk(dev, gd, NULL);
if (sdkp->capacity)
sd_dif_config_host(sdkp);
@@ -3424,8 +3414,6 @@ static int sd_remove(struct device *dev)
del_gendisk(sdkp->disk);
sd_shutdown(dev);
- sd_zbc_remove(sdkp);
-
free_opal_dev(sdkp->opal_dev);
blk_register_region(devt, SD_MINORS, NULL,
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h
index a7d4f50b67d4..1d63f3a23ffb 100644
--- a/drivers/scsi/sd.h
+++ b/drivers/scsi/sd.h
@@ -76,7 +76,6 @@ struct scsi_disk {
#ifdef CONFIG_BLK_DEV_ZONED
u32 nr_zones;
u32 zone_blocks;
- u32 zone_shift;
u32 zones_optimal_open;
u32 zones_optimal_nonseq;
u32 zones_max_open;
@@ -271,12 +270,13 @@ static inline int sd_is_zoned(struct scsi_disk *sdkp)
#ifdef CONFIG_BLK_DEV_ZONED
extern int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buffer);
-extern void sd_zbc_remove(struct scsi_disk *sdkp);
extern void sd_zbc_print_zones(struct scsi_disk *sdkp);
-extern int sd_zbc_setup_report_cmnd(struct scsi_cmnd *cmd);
extern int sd_zbc_setup_reset_cmnd(struct scsi_cmnd *cmd);
extern void sd_zbc_complete(struct scsi_cmnd *cmd, unsigned int good_bytes,
struct scsi_sense_hdr *sshdr);
+extern int sd_zbc_report_zones(struct gendisk *disk, sector_t sector,
+ struct blk_zone *zones, unsigned int *nr_zones,
+ gfp_t gfp_mask);
#else /* CONFIG_BLK_DEV_ZONED */
@@ -286,15 +286,8 @@ static inline int sd_zbc_read_zones(struct scsi_disk *sdkp,
return 0;
}
-static inline void sd_zbc_remove(struct scsi_disk *sdkp) {}
-
static inline void sd_zbc_print_zones(struct scsi_disk *sdkp) {}
-static inline int sd_zbc_setup_report_cmnd(struct scsi_cmnd *cmd)
-{
- return BLKPREP_INVALID;
-}
-
static inline int sd_zbc_setup_reset_cmnd(struct scsi_cmnd *cmd)
{
return BLKPREP_INVALID;
@@ -304,6 +297,8 @@ static inline void sd_zbc_complete(struct scsi_cmnd *cmd,
unsigned int good_bytes,
struct scsi_sense_hdr *sshdr) {}
+#define sd_zbc_report_zones NULL
+
#endif /* CONFIG_BLK_DEV_ZONED */
#endif /* _SCSI_DISK_H */
diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c
index 412c1787dcd9..e06c48c866e4 100644
--- a/drivers/scsi/sd_zbc.c
+++ b/drivers/scsi/sd_zbc.c
@@ -62,16 +62,22 @@ static void sd_zbc_parse_report(struct scsi_disk *sdkp, u8 *buf,
}
/**
- * sd_zbc_report_zones - Issue a REPORT ZONES scsi command.
+ * sd_zbc_do_report_zones - Issue a REPORT ZONES scsi command.
* @sdkp: The target disk
* @buf: Buffer to use for the reply
* @buflen: the buffer size
* @lba: Start LBA of the report
+ * @partial: Do partial report
*
* For internal use during device validation.
+ * Using partial=true can significantly speed up execution of a report zones
+ * command because the disk does not have to count all possible report matching
+ * zones and will only report the count of zones fitting in the command reply
+ * buffer.
*/
-static int sd_zbc_report_zones(struct scsi_disk *sdkp, unsigned char *buf,
- unsigned int buflen, sector_t lba)
+static int sd_zbc_do_report_zones(struct scsi_disk *sdkp, unsigned char *buf,
+ unsigned int buflen, sector_t lba,
+ bool partial)
{
struct scsi_device *sdp = sdkp->device;
const int timeout = sdp->request_queue->rq_timeout;
@@ -85,6 +91,8 @@ static int sd_zbc_report_zones(struct scsi_disk *sdkp, unsigned char *buf,
cmd[1] = ZI_REPORT_ZONES;
put_unaligned_be64(lba, &cmd[2]);
put_unaligned_be32(buflen, &cmd[10]);
+ if (partial)
+ cmd[14] = ZBC_REPORT_ZONE_PARTIAL;
memset(buf, 0, buflen);
result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE,
@@ -110,108 +118,56 @@ static int sd_zbc_report_zones(struct scsi_disk *sdkp, unsigned char *buf,
}
/**
- * sd_zbc_setup_report_cmnd - Prepare a REPORT ZONES scsi command
- * @cmd: The command to setup
+ * sd_zbc_report_zones - Disk report zones operation.
+ * @disk: The target disk
+ * @sector: Start 512B sector of the report
+ * @zones: Array of zone descriptors
+ * @nr_zones: Number of descriptors in the array
+ * @gfp_mask: Memory allocation mask
*
- * Call in sd_init_command() for a REQ_OP_ZONE_REPORT request.
+ * Execute a report zones command on the target disk.
*/
-int sd_zbc_setup_report_cmnd(struct scsi_cmnd *cmd)
+int sd_zbc_report_zones(struct gendisk *disk, sector_t sector,
+ struct blk_zone *zones, unsigned int *nr_zones,
+ gfp_t gfp_mask)
{
- struct request *rq = cmd->request;
- struct scsi_disk *sdkp = scsi_disk(rq->rq_disk);
- sector_t lba, sector = blk_rq_pos(rq);
- unsigned int nr_bytes = blk_rq_bytes(rq);
- int ret;
-
- WARN_ON(nr_bytes == 0);
+ struct scsi_disk *sdkp = scsi_disk(disk);
+ unsigned int i, buflen, nrz = *nr_zones;
+ unsigned char *buf;
+ size_t offset = 0;
+ int ret = 0;
if (!sd_is_zoned(sdkp))
/* Not a zoned device */
- return BLKPREP_KILL;
-
- ret = scsi_init_io(cmd);
- if (ret != BLKPREP_OK)
- return ret;
-
- cmd->cmd_len = 16;
- memset(cmd->cmnd, 0, cmd->cmd_len);
- cmd->cmnd[0] = ZBC_IN;
- cmd->cmnd[1] = ZI_REPORT_ZONES;
- lba = sectors_to_logical(sdkp->device, sector);
- put_unaligned_be64(lba, &cmd->cmnd[2]);
- put_unaligned_be32(nr_bytes, &cmd->cmnd[10]);
- /* Do partial report for speeding things up */
- cmd->cmnd[14] = ZBC_REPORT_ZONE_PARTIAL;
-
- cmd->sc_data_direction = DMA_FROM_DEVICE;
- cmd->sdb.length = nr_bytes;
- cmd->transfersize = sdkp->device->sector_size;
- cmd->allowed = 0;
-
- return BLKPREP_OK;
-}
-
-/**
- * sd_zbc_report_zones_complete - Process a REPORT ZONES scsi command reply.
- * @scmd: The completed report zones command
- * @good_bytes: reply size in bytes
- *
- * Convert all reported zone descriptors to struct blk_zone. The conversion
- * is done in-place, directly in the request specified sg buffer.
- */
-static void sd_zbc_report_zones_complete(struct scsi_cmnd *scmd,
- unsigned int good_bytes)
-{
- struct request *rq = scmd->request;
- struct scsi_disk *sdkp = scsi_disk(rq->rq_disk);
- struct sg_mapping_iter miter;
- struct blk_zone_report_hdr hdr;
- struct blk_zone zone;
- unsigned int offset, bytes = 0;
- unsigned long flags;
- u8 *buf;
-
- if (good_bytes < 64)
- return;
+ return -EOPNOTSUPP;
- memset(&hdr, 0, sizeof(struct blk_zone_report_hdr));
-
- sg_miter_start(&miter, scsi_sglist(scmd), scsi_sg_count(scmd),
- SG_MITER_TO_SG | SG_MITER_ATOMIC);
-
- local_irq_save(flags);
- while (sg_miter_next(&miter) && bytes < good_bytes) {
+ /*
+ * Get a reply buffer for the number of requested zones plus a header.
+ * For ATA, buffers must be aligned to 512B.
+ */
+ buflen = roundup((nrz + 1) * 64, 512);
+ buf = kmalloc(buflen, gfp_mask);
+ if (!buf)
+ return -ENOMEM;
- buf = miter.addr;
- offset = 0;
+ ret = sd_zbc_do_report_zones(sdkp, buf, buflen,
+ sectors_to_logical(sdkp->device, sector), true);
+ if (ret)
+ goto out_free_buf;
- if (bytes == 0) {
- /* Set the report header */
- hdr.nr_zones = min_t(unsigned int,
- (good_bytes - 64) / 64,
- get_unaligned_be32(&buf[0]) / 64);
- memcpy(buf, &hdr, sizeof(struct blk_zone_report_hdr));
- offset += 64;
- bytes += 64;
- }
+ nrz = min(nrz, get_unaligned_be32(&buf[0]) / 64);
+ for (i = 0; i < nrz; i++) {
+ offset += 64;
+ sd_zbc_parse_report(sdkp, buf + offset, zones);
+ zones++;
+ }
- /* Parse zone descriptors */
- while (offset < miter.length && hdr.nr_zones) {
- WARN_ON(offset > miter.length);
- buf = miter.addr + offset;
- sd_zbc_parse_report(sdkp, buf, &zone);
- memcpy(buf, &zone, sizeof(struct blk_zone));
- offset += 64;
- bytes += 64;
- hdr.nr_zones--;
- }
+ *nr_zones = nrz;
- if (!hdr.nr_zones)
- break;
+out_free_buf:
+ kfree(buf);
- }
- sg_miter_stop(&miter);
- local_irq_restore(flags);
+ return ret;
}
/**
@@ -294,30 +250,23 @@ void sd_zbc_complete(struct scsi_cmnd *cmd, unsigned int good_bytes,
case REQ_OP_WRITE_ZEROES:
case REQ_OP_WRITE_SAME:
break;
-
- case REQ_OP_ZONE_REPORT:
-
- if (!result)
- sd_zbc_report_zones_complete(cmd, good_bytes);
- break;
-
}
}
/**
- * sd_zbc_read_zoned_characteristics - Read zoned block device characteristics
+ * sd_zbc_check_zoned_characteristics - Check zoned block device characteristics
* @sdkp: Target disk
* @buf: Buffer where to store the VPD page data
*
- * Read VPD page B6.
+ * Read VPD page B6, get information and check that reads are unconstrained.
*/
-static int sd_zbc_read_zoned_characteristics(struct scsi_disk *sdkp,
- unsigned char *buf)
+static int sd_zbc_check_zoned_characteristics(struct scsi_disk *sdkp,
+ unsigned char *buf)
{
if (scsi_get_vpd_page(sdkp->device, 0xb6, buf, 64)) {
sd_printk(KERN_NOTICE, sdkp,
- "Unconstrained-read check failed\n");
+ "Read zoned characteristics VPD page failed\n");
return -ENODEV;
}
@@ -335,43 +284,17 @@ static int sd_zbc_read_zoned_characteristics(struct scsi_disk *sdkp,
sdkp->zones_max_open = get_unaligned_be32(&buf[16]);
}
- return 0;
-}
-
-/**
- * sd_zbc_check_capacity - Check reported capacity.
- * @sdkp: Target disk
- * @buf: Buffer to use for commands
- *
- * ZBC drive may report only the capacity of the first conventional zones at
- * LBA 0. This is indicated by the RC_BASIS field of the read capacity reply.
- * Check this here. If the disk reported only its conventional zones capacity,
- * get the total capacity by doing a report zones.
- */
-static int sd_zbc_check_capacity(struct scsi_disk *sdkp, unsigned char *buf)
-{
- sector_t lba;
- int ret;
-
- if (sdkp->rc_basis != 0)
- return 0;
-
- /* Do a report zone to get the maximum LBA to check capacity */
- ret = sd_zbc_report_zones(sdkp, buf, SD_BUF_SIZE, 0);
- if (ret)
- return ret;
-
- /* The max_lba field is the capacity of this device */
- lba = get_unaligned_be64(&buf[8]);
- if (lba + 1 == sdkp->capacity)
- return 0;
-
- if (sdkp->first_scan)
- sd_printk(KERN_WARNING, sdkp,
- "Changing capacity from %llu to max LBA+1 %llu\n",
- (unsigned long long)sdkp->capacity,
- (unsigned long long)lba + 1);
- sdkp->capacity = lba + 1;
+ /*
+ * Check for unconstrained reads: host-managed devices with
+ * constrained reads (drives failing read after write pointer)
+ * are not supported.
+ */
+ if (!sdkp->urswrz) {
+ if (sdkp->first_scan)
+ sd_printk(KERN_NOTICE, sdkp,
+ "constrained reads devices are not supported\n");
+ return -ENODEV;
+ }
return 0;
}
@@ -379,24 +302,27 @@ static int sd_zbc_check_capacity(struct scsi_disk *sdkp, unsigned char *buf)
#define SD_ZBC_BUF_SIZE 131072U
/**
- * sd_zbc_check_zone_size - Check the device zone sizes
+ * sd_zbc_check_zones - Check the device capacity and zone sizes
* @sdkp: Target disk
*
- * Check that all zones of the device are equal. The last zone can however
- * be smaller. The zone size must also be a power of two number of LBAs.
+ * Check that the device capacity as reported by READ CAPACITY matches the
+ * max_lba value (plus one)of the report zones command reply. Also check that
+ * all zones of the device have an equal size, only allowing the last zone of
+ * the disk to have a smaller size (runt zone). The zone size must also be a
+ * power of two.
*
* Returns the zone size in number of blocks upon success or an error code
* upon failure.
*/
-static s64 sd_zbc_check_zone_size(struct scsi_disk *sdkp)
+static int sd_zbc_check_zones(struct scsi_disk *sdkp, u32 *zblocks)
{
u64 zone_blocks = 0;
- sector_t block = 0;
+ sector_t max_lba, block = 0;
unsigned char *buf;
unsigned char *rec;
unsigned int buf_len;
unsigned int list_length;
- s64 ret;
+ int ret;
u8 same;
/* Get a buffer */
@@ -404,11 +330,28 @@ static s64 sd_zbc_check_zone_size(struct scsi_disk *sdkp)
if (!buf)
return -ENOMEM;
- /* Do a report zone to get the same field */
- ret = sd_zbc_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE, 0);
+ /* Do a report zone to get max_lba and the same field */
+ ret = sd_zbc_do_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE, 0, false);
if (ret)
goto out_free;
+ if (sdkp->rc_basis == 0) {
+ /* The max_lba field is the capacity of this device */
+ max_lba = get_unaligned_be64(&buf[8]);
+ if (sdkp->capacity != max_lba + 1) {
+ if (sdkp->first_scan)
+ sd_printk(KERN_WARNING, sdkp,
+ "Changing capacity from %llu to max LBA+1 %llu\n",
+ (unsigned long long)sdkp->capacity,
+ (unsigned long long)max_lba + 1);
+ sdkp->capacity = max_lba + 1;
+ }
+ }
+
+ /*
+ * Check same field: for any value other than 0, we know that all zones
+ * have the same size.
+ */
same = buf[4] & 0x0f;
if (same > 0) {
rec = &buf[64];
@@ -445,8 +388,8 @@ static s64 sd_zbc_check_zone_size(struct scsi_disk *sdkp)
}
if (block < sdkp->capacity) {
- ret = sd_zbc_report_zones(sdkp, buf,
- SD_ZBC_BUF_SIZE, block);
+ ret = sd_zbc_do_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE,
+ block, true);
if (ret)
goto out_free;
}
@@ -470,9 +413,10 @@ out:
if (sdkp->first_scan)
sd_printk(KERN_NOTICE, sdkp,
"Zone size too large\n");
- ret = -ENODEV;
+ ret = -EFBIG;
} else {
- ret = zone_blocks;
+ *zblocks = zone_blocks;
+ ret = 0;
}
out_free:
@@ -481,191 +425,11 @@ out_free:
return ret;
}
-/**
- * sd_zbc_alloc_zone_bitmap - Allocate a zone bitmap (one bit per zone).
- * @nr_zones: Number of zones to allocate space for.
- * @numa_node: NUMA node to allocate the memory from.
- */
-static inline unsigned long *
-sd_zbc_alloc_zone_bitmap(u32 nr_zones, int numa_node)
-{
- return kcalloc_node(BITS_TO_LONGS(nr_zones), sizeof(unsigned long),
- GFP_KERNEL, numa_node);
-}
-
-/**
- * sd_zbc_get_seq_zones - Parse report zones reply to identify sequential zones
- * @sdkp: disk used
- * @buf: report reply buffer
- * @buflen: length of @buf
- * @zone_shift: logarithm base 2 of the number of blocks in a zone
- * @seq_zones_bitmap: bitmap of sequential zones to set
- *
- * Parse reported zone descriptors in @buf to identify sequential zones and
- * set the reported zone bit in @seq_zones_bitmap accordingly.
- * Since read-only and offline zones cannot be written, do not
- * mark them as sequential in the bitmap.
- * Return the LBA after the last zone reported.
- */
-static sector_t sd_zbc_get_seq_zones(struct scsi_disk *sdkp, unsigned char *buf,
- unsigned int buflen, u32 zone_shift,
- unsigned long *seq_zones_bitmap)
-{
- sector_t lba, next_lba = sdkp->capacity;
- unsigned int buf_len, list_length;
- unsigned char *rec;
- u8 type, cond;
-
- list_length = get_unaligned_be32(&buf[0]) + 64;
- buf_len = min(list_length, buflen);
- rec = buf + 64;
-
- while (rec < buf + buf_len) {
- type = rec[0] & 0x0f;
- cond = (rec[1] >> 4) & 0xf;
- lba = get_unaligned_be64(&rec[16]);
- if (type != ZBC_ZONE_TYPE_CONV &&
- cond != ZBC_ZONE_COND_READONLY &&
- cond != ZBC_ZONE_COND_OFFLINE)
- set_bit(lba >> zone_shift, seq_zones_bitmap);
- next_lba = lba + get_unaligned_be64(&rec[8]);
- rec += 64;
- }
-
- return next_lba;
-}
-
-/**
- * sd_zbc_setup_seq_zones_bitmap - Initialize a seq zone bitmap.
- * @sdkp: target disk
- * @zone_shift: logarithm base 2 of the number of blocks in a zone
- * @nr_zones: number of zones to set up a seq zone bitmap for
- *
- * Allocate a zone bitmap and initialize it by identifying sequential zones.
- */
-static unsigned long *
-sd_zbc_setup_seq_zones_bitmap(struct scsi_disk *sdkp, u32 zone_shift,
- u32 nr_zones)
-{
- struct request_queue *q = sdkp->disk->queue;
- unsigned long *seq_zones_bitmap;
- sector_t lba = 0;
- unsigned char *buf;
- int ret = -ENOMEM;
-
- seq_zones_bitmap = sd_zbc_alloc_zone_bitmap(nr_zones, q->node);
- if (!seq_zones_bitmap)
- return ERR_PTR(-ENOMEM);
-
- buf = kmalloc(SD_ZBC_BUF_SIZE, GFP_KERNEL);
- if (!buf)
- goto out;
-
- while (lba < sdkp->capacity) {
- ret = sd_zbc_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE, lba);
- if (ret)
- goto out;
- lba = sd_zbc_get_seq_zones(sdkp, buf, SD_ZBC_BUF_SIZE,
- zone_shift, seq_zones_bitmap);
- }
-
- if (lba != sdkp->capacity) {
- /* Something went wrong */
- ret = -EIO;
- }
-
-out:
- kfree(buf);
- if (ret) {
- kfree(seq_zones_bitmap);
- return ERR_PTR(ret);
- }
- return seq_zones_bitmap;
-}
-
-static void sd_zbc_cleanup(struct scsi_disk *sdkp)
-{
- struct request_queue *q = sdkp->disk->queue;
-
- kfree(q->seq_zones_bitmap);
- q->seq_zones_bitmap = NULL;
-
- kfree(q->seq_zones_wlock);
- q->seq_zones_wlock = NULL;
-
- q->nr_zones = 0;
-}
-
-static int sd_zbc_setup(struct scsi_disk *sdkp, u32 zone_blocks)
-{
- struct request_queue *q = sdkp->disk->queue;
- u32 zone_shift = ilog2(zone_blocks);
- u32 nr_zones;
- int ret;
-
- /* chunk_sectors indicates the zone size */
- blk_queue_chunk_sectors(q,
- logical_to_sectors(sdkp->device, zone_blocks));
- nr_zones = round_up(sdkp->capacity, zone_blocks) >> zone_shift;
-
- /*
- * Initialize the device request queue information if the number
- * of zones changed.
- */
- if (nr_zones != sdkp->nr_zones || nr_zones != q->nr_zones) {
- unsigned long *seq_zones_wlock = NULL, *seq_zones_bitmap = NULL;
- size_t zone_bitmap_size;
-
- if (nr_zones) {
- seq_zones_wlock = sd_zbc_alloc_zone_bitmap(nr_zones,
- q->node);
- if (!seq_zones_wlock) {
- ret = -ENOMEM;
- goto err;
- }
-
- seq_zones_bitmap = sd_zbc_setup_seq_zones_bitmap(sdkp,
- zone_shift, nr_zones);
- if (IS_ERR(seq_zones_bitmap)) {
- ret = PTR_ERR(seq_zones_bitmap);
- kfree(seq_zones_wlock);
- goto err;
- }
- }
- zone_bitmap_size = BITS_TO_LONGS(nr_zones) *
- sizeof(unsigned long);
- blk_mq_freeze_queue(q);
- if (q->nr_zones != nr_zones) {
- /* READ16/WRITE16 is mandatory for ZBC disks */
- sdkp->device->use_16_for_rw = 1;
- sdkp->device->use_10_for_rw = 0;
-
- sdkp->zone_blocks = zone_blocks;
- sdkp->zone_shift = zone_shift;
- sdkp->nr_zones = nr_zones;
- q->nr_zones = nr_zones;
- swap(q->seq_zones_wlock, seq_zones_wlock);
- swap(q->seq_zones_bitmap, seq_zones_bitmap);
- } else if (memcmp(q->seq_zones_bitmap, seq_zones_bitmap,
- zone_bitmap_size) != 0) {
- memcpy(q->seq_zones_bitmap, seq_zones_bitmap,
- zone_bitmap_size);
- }
- blk_mq_unfreeze_queue(q);
- kfree(seq_zones_wlock);
- kfree(seq_zones_bitmap);
- }
-
- return 0;
-
-err:
- sd_zbc_cleanup(sdkp);
- return ret;
-}
-
int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf)
{
- int64_t zone_blocks;
+ struct gendisk *disk = sdkp->disk;
+ unsigned int nr_zones;
+ u32 zone_blocks;
int ret;
if (!sd_is_zoned(sdkp))
@@ -675,26 +439,8 @@ int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf)
*/
return 0;
- /* Get zoned block device characteristics */
- ret = sd_zbc_read_zoned_characteristics(sdkp, buf);
- if (ret)
- goto err;
-
- /*
- * Check for unconstrained reads: host-managed devices with
- * constrained reads (drives failing read after write pointer)
- * are not supported.
- */
- if (!sdkp->urswrz) {
- if (sdkp->first_scan)
- sd_printk(KERN_NOTICE, sdkp,
- "constrained reads devices are not supported\n");
- ret = -ENODEV;
- goto err;
- }
-
- /* Check capacity */
- ret = sd_zbc_check_capacity(sdkp, buf);
+ /* Check zoned block device characteristics (unconstrained reads) */
+ ret = sd_zbc_check_zoned_characteristics(sdkp, buf);
if (ret)
goto err;
@@ -702,33 +448,44 @@ int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf)
* Check zone size: only devices with a constant zone size (except
* an eventual last runt zone) that is a power of 2 are supported.
*/
- zone_blocks = sd_zbc_check_zone_size(sdkp);
- ret = -EFBIG;
- if (zone_blocks != (u32)zone_blocks)
- goto err;
- ret = zone_blocks;
- if (ret < 0)
+ ret = sd_zbc_check_zones(sdkp, &zone_blocks);
+ if (ret != 0)
goto err;
/* The drive satisfies the kernel restrictions: set it up */
- ret = sd_zbc_setup(sdkp, zone_blocks);
- if (ret)
- goto err;
+ blk_queue_chunk_sectors(sdkp->disk->queue,
+ logical_to_sectors(sdkp->device, zone_blocks));
+ nr_zones = round_up(sdkp->capacity, zone_blocks) >> ilog2(zone_blocks);
+
+ /* READ16/WRITE16 is mandatory for ZBC disks */
+ sdkp->device->use_16_for_rw = 1;
+ sdkp->device->use_10_for_rw = 0;
+
+ /*
+ * If something changed, revalidate the disk zone bitmaps once we have
+ * the capacity, that is on the second revalidate execution during disk
+ * scan and always during normal revalidate.
+ */
+ if (sdkp->first_scan)
+ return 0;
+ if (sdkp->zone_blocks != zone_blocks ||
+ sdkp->nr_zones != nr_zones ||
+ disk->queue->nr_zones != nr_zones) {
+ ret = blk_revalidate_disk_zones(disk);
+ if (ret != 0)
+ goto err;
+ sdkp->zone_blocks = zone_blocks;
+ sdkp->nr_zones = nr_zones;
+ }
return 0;
err:
sdkp->capacity = 0;
- sd_zbc_cleanup(sdkp);
return ret;
}
-void sd_zbc_remove(struct scsi_disk *sdkp)
-{
- sd_zbc_cleanup(sdkp);
-}
-
void sd_zbc_print_zones(struct scsi_disk *sdkp)
{
if (!sd_is_zoned(sdkp) || !sdkp->capacity)
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 8a254bb46a9b..c6ad00703c5b 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -822,7 +822,7 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp,
if (atomic_read(&sdp->detaching)) {
if (srp->bio) {
scsi_req_free_cmd(scsi_req(srp->rq));
- blk_end_request_all(srp->rq, BLK_STS_IOERR);
+ blk_put_request(srp->rq);
srp->rq = NULL;
}
diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c
index 2112ea6723c6..a25a07a0b7f0 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -349,16 +349,16 @@ static inline u32 pqi_read_heartbeat_counter(struct pqi_ctrl_info *ctrl_info)
static int pqi_map_single(struct pci_dev *pci_dev,
struct pqi_sg_descriptor *sg_descriptor, void *buffer,
- size_t buffer_length, int data_direction)
+ size_t buffer_length, enum dma_data_direction data_direction)
{
dma_addr_t bus_address;
- if (!buffer || buffer_length == 0 || data_direction == PCI_DMA_NONE)
+ if (!buffer || buffer_length == 0 || data_direction == DMA_NONE)
return 0;
- bus_address = pci_map_single(pci_dev, buffer, buffer_length,
+ bus_address = dma_map_single(&pci_dev->dev, buffer, buffer_length,
data_direction);
- if (pci_dma_mapping_error(pci_dev, bus_address))
+ if (dma_mapping_error(&pci_dev->dev, bus_address))
return -ENOMEM;
put_unaligned_le64((u64)bus_address, &sg_descriptor->address);
@@ -370,15 +370,15 @@ static int pqi_map_single(struct pci_dev *pci_dev,
static void pqi_pci_unmap(struct pci_dev *pci_dev,
struct pqi_sg_descriptor *descriptors, int num_descriptors,
- int data_direction)
+ enum dma_data_direction data_direction)
{
int i;
- if (data_direction == PCI_DMA_NONE)
+ if (data_direction == DMA_NONE)
return;
for (i = 0; i < num_descriptors; i++)
- pci_unmap_single(pci_dev,
+ dma_unmap_single(&pci_dev->dev,
(dma_addr_t)get_unaligned_le64(&descriptors[i].address),
get_unaligned_le32(&descriptors[i].length),
data_direction);
@@ -387,10 +387,9 @@ static void pqi_pci_unmap(struct pci_dev *pci_dev,
static int pqi_build_raid_path_request(struct pqi_ctrl_info *ctrl_info,
struct pqi_raid_path_request *request, u8 cmd,
u8 *scsi3addr, void *buffer, size_t buffer_length,
- u16 vpd_page, int *pci_direction)
+ u16 vpd_page, enum dma_data_direction *dir)
{
u8 *cdb;
- int pci_dir;
memset(request, 0, sizeof(*request));
@@ -458,23 +457,21 @@ static int pqi_build_raid_path_request(struct pqi_ctrl_info *ctrl_info,
switch (request->data_direction) {
case SOP_READ_FLAG:
- pci_dir = PCI_DMA_FROMDEVICE;
+ *dir = DMA_FROM_DEVICE;
break;
case SOP_WRITE_FLAG:
- pci_dir = PCI_DMA_TODEVICE;
+ *dir = DMA_TO_DEVICE;
break;
case SOP_NO_DIRECTION_FLAG:
- pci_dir = PCI_DMA_NONE;
+ *dir = DMA_NONE;
break;
default:
- pci_dir = PCI_DMA_BIDIRECTIONAL;
+ *dir = DMA_BIDIRECTIONAL;
break;
}
- *pci_direction = pci_dir;
-
return pqi_map_single(ctrl_info->pci_dev, &request->sg_descriptors[0],
- buffer, buffer_length, pci_dir);
+ buffer, buffer_length, *dir);
}
static inline void pqi_reinit_io_request(struct pqi_io_request *io_request)
@@ -516,21 +513,19 @@ static int pqi_identify_controller(struct pqi_ctrl_info *ctrl_info,
struct bmic_identify_controller *buffer)
{
int rc;
- int pci_direction;
+ enum dma_data_direction dir;
struct pqi_raid_path_request request;
rc = pqi_build_raid_path_request(ctrl_info, &request,
BMIC_IDENTIFY_CONTROLLER, RAID_CTLR_LUNID, buffer,
- sizeof(*buffer), 0, &pci_direction);
+ sizeof(*buffer), 0, &dir);
if (rc)
return rc;
rc = pqi_submit_raid_request_synchronous(ctrl_info, &request.header, 0,
NULL, NO_TIMEOUT);
- pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1,
- pci_direction);
-
+ pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1, dir);
return rc;
}
@@ -538,21 +533,19 @@ static int pqi_scsi_inquiry(struct pqi_ctrl_info *ctrl_info,
u8 *scsi3addr, u16 vpd_page, void *buffer, size_t buffer_length)
{
int rc;
- int pci_direction;
+ enum dma_data_direction dir;
struct pqi_raid_path_request request;
rc = pqi_build_raid_path_request(ctrl_info, &request,
INQUIRY, scsi3addr, buffer, buffer_length, vpd_page,
- &pci_direction);
+ &dir);
if (rc)
return rc;
rc = pqi_submit_raid_request_synchronous(ctrl_info, &request.header, 0,
NULL, NO_TIMEOUT);
- pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1,
- pci_direction);
-
+ pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1, dir);
return rc;
}
@@ -562,13 +555,13 @@ static int pqi_identify_physical_device(struct pqi_ctrl_info *ctrl_info,
size_t buffer_length)
{
int rc;
- int pci_direction;
+ enum dma_data_direction dir;
u16 bmic_device_index;
struct pqi_raid_path_request request;
rc = pqi_build_raid_path_request(ctrl_info, &request,
BMIC_IDENTIFY_PHYSICAL_DEVICE, RAID_CTLR_LUNID, buffer,
- buffer_length, 0, &pci_direction);
+ buffer_length, 0, &dir);
if (rc)
return rc;
@@ -579,9 +572,7 @@ static int pqi_identify_physical_device(struct pqi_ctrl_info *ctrl_info,
rc = pqi_submit_raid_request_synchronous(ctrl_info, &request.header,
0, NULL, NO_TIMEOUT);
- pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1,
- pci_direction);
-
+ pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1, dir);
return rc;
}
@@ -590,8 +581,8 @@ static int pqi_flush_cache(struct pqi_ctrl_info *ctrl_info,
{
int rc;
struct pqi_raid_path_request request;
- int pci_direction;
struct bmic_flush_cache *flush_cache;
+ enum dma_data_direction dir;
/*
* Don't bother trying to flush the cache if the controller is
@@ -608,16 +599,14 @@ static int pqi_flush_cache(struct pqi_ctrl_info *ctrl_info,
rc = pqi_build_raid_path_request(ctrl_info, &request,
SA_FLUSH_CACHE, RAID_CTLR_LUNID, flush_cache,
- sizeof(*flush_cache), 0, &pci_direction);
+ sizeof(*flush_cache), 0, &dir);
if (rc)
goto out;
rc = pqi_submit_raid_request_synchronous(ctrl_info, &request.header,
0, NULL, NO_TIMEOUT);
- pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1,
- pci_direction);
-
+ pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1, dir);
out:
kfree(flush_cache);
@@ -629,20 +618,18 @@ static int pqi_write_host_wellness(struct pqi_ctrl_info *ctrl_info,
{
int rc;
struct pqi_raid_path_request request;
- int pci_direction;
+ enum dma_data_direction dir;
rc = pqi_build_raid_path_request(ctrl_info, &request,
BMIC_WRITE_HOST_WELLNESS, RAID_CTLR_LUNID, buffer,
- buffer_length, 0, &pci_direction);
+ buffer_length, 0, &dir);
if (rc)
return rc;
rc = pqi_submit_raid_request_synchronous(ctrl_info, &request.header,
0, NULL, NO_TIMEOUT);
- pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1,
- pci_direction);
-
+ pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1, dir);
return rc;
}
@@ -793,20 +780,18 @@ static int pqi_report_luns(struct pqi_ctrl_info *ctrl_info, u8 cmd,
void *buffer, size_t buffer_length)
{
int rc;
- int pci_direction;
+ enum dma_data_direction dir;
struct pqi_raid_path_request request;
rc = pqi_build_raid_path_request(ctrl_info, &request,
- cmd, RAID_CTLR_LUNID, buffer, buffer_length, 0, &pci_direction);
+ cmd, RAID_CTLR_LUNID, buffer, buffer_length, 0, &dir);
if (rc)
return rc;
rc = pqi_submit_raid_request_synchronous(ctrl_info, &request.header, 0,
NULL, NO_TIMEOUT);
- pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1,
- pci_direction);
-
+ pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1, dir);
return rc;
}
@@ -1089,7 +1074,7 @@ static int pqi_get_raid_map(struct pqi_ctrl_info *ctrl_info,
struct pqi_scsi_dev *device)
{
int rc;
- int pci_direction;
+ enum dma_data_direction dir;
struct pqi_raid_path_request request;
struct raid_map *raid_map;
@@ -1099,15 +1084,14 @@ static int pqi_get_raid_map(struct pqi_ctrl_info *ctrl_info,
rc = pqi_build_raid_path_request(ctrl_info, &request,
CISS_GET_RAID_MAP, device->scsi3addr, raid_map,
- sizeof(*raid_map), 0, &pci_direction);
+ sizeof(*raid_map), 0, &dir);
if (rc)
goto error;
rc = pqi_submit_raid_request_synchronous(ctrl_info, &request.header, 0,
NULL, NO_TIMEOUT);
- pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1,
- pci_direction);
+ pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1, dir);
if (rc)
goto error;
@@ -3822,7 +3806,7 @@ static int pqi_report_device_capability(struct pqi_ctrl_info *ctrl_info)
rc = pqi_map_single(ctrl_info->pci_dev,
&request.data.report_device_capability.sg_descriptor,
capability, sizeof(*capability),
- PCI_DMA_FROMDEVICE);
+ DMA_FROM_DEVICE);
if (rc)
goto out;
@@ -3831,7 +3815,7 @@ static int pqi_report_device_capability(struct pqi_ctrl_info *ctrl_info)
pqi_pci_unmap(ctrl_info->pci_dev,
&request.data.report_device_capability.sg_descriptor, 1,
- PCI_DMA_FROMDEVICE);
+ DMA_FROM_DEVICE);
if (rc)
goto out;
@@ -4158,7 +4142,7 @@ static int pqi_configure_events(struct pqi_ctrl_info *ctrl_info,
rc = pqi_map_single(ctrl_info->pci_dev,
request.data.report_event_configuration.sg_descriptors,
event_config, PQI_REPORT_EVENT_CONFIG_BUFFER_LENGTH,
- PCI_DMA_FROMDEVICE);
+ DMA_FROM_DEVICE);
if (rc)
goto out;
@@ -4167,7 +4151,7 @@ static int pqi_configure_events(struct pqi_ctrl_info *ctrl_info,
pqi_pci_unmap(ctrl_info->pci_dev,
request.data.report_event_configuration.sg_descriptors, 1,
- PCI_DMA_FROMDEVICE);
+ DMA_FROM_DEVICE);
if (rc)
goto out;
@@ -4194,7 +4178,7 @@ static int pqi_configure_events(struct pqi_ctrl_info *ctrl_info,
rc = pqi_map_single(ctrl_info->pci_dev,
request.data.report_event_configuration.sg_descriptors,
event_config, PQI_REPORT_EVENT_CONFIG_BUFFER_LENGTH,
- PCI_DMA_TODEVICE);
+ DMA_TO_DEVICE);
if (rc)
goto out;
@@ -4203,7 +4187,7 @@ static int pqi_configure_events(struct pqi_ctrl_info *ctrl_info,
pqi_pci_unmap(ctrl_info->pci_dev,
request.data.report_event_configuration.sg_descriptors, 1,
- PCI_DMA_TODEVICE);
+ DMA_TO_DEVICE);
out:
kfree(event_config);
@@ -5534,7 +5518,7 @@ static int pqi_passthru_ioctl(struct pqi_ctrl_info *ctrl_info, void __user *arg)
rc = pqi_map_single(ctrl_info->pci_dev,
&request.sg_descriptors[0], kernel_buffer,
- iocommand.buf_size, PCI_DMA_BIDIRECTIONAL);
+ iocommand.buf_size, DMA_BIDIRECTIONAL);
if (rc)
goto out;
@@ -5548,7 +5532,7 @@ static int pqi_passthru_ioctl(struct pqi_ctrl_info *ctrl_info, void __user *arg)
if (iocommand.buf_size > 0)
pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1,
- PCI_DMA_BIDIRECTIONAL);
+ DMA_BIDIRECTIONAL);
memset(&iocommand.error_info, 0, sizeof(iocommand.error_info));
diff --git a/drivers/scsi/smartpqi/smartpqi_sis.c b/drivers/scsi/smartpqi/smartpqi_sis.c
index 5141bd4c9f06..ea91658c7060 100644
--- a/drivers/scsi/smartpqi/smartpqi_sis.c
+++ b/drivers/scsi/smartpqi/smartpqi_sis.c
@@ -316,9 +316,9 @@ int sis_init_base_struct_addr(struct pqi_ctrl_info *ctrl_info)
put_unaligned_le32(ctrl_info->max_io_slots,
&base_struct->error_buffer_num_elements);
- bus_address = pci_map_single(ctrl_info->pci_dev, base_struct,
- sizeof(*base_struct), PCI_DMA_TODEVICE);
- if (pci_dma_mapping_error(ctrl_info->pci_dev, bus_address)) {
+ bus_address = dma_map_single(&ctrl_info->pci_dev->dev, base_struct,
+ sizeof(*base_struct), DMA_TO_DEVICE);
+ if (dma_mapping_error(&ctrl_info->pci_dev->dev, bus_address)) {
rc = -ENOMEM;
goto out;
}
@@ -331,9 +331,8 @@ int sis_init_base_struct_addr(struct pqi_ctrl_info *ctrl_info)
rc = sis_send_sync_cmd(ctrl_info, SIS_CMD_INIT_BASE_STRUCT_ADDRESS,
&params);
- pci_unmap_single(ctrl_info->pci_dev, bus_address, sizeof(*base_struct),
- PCI_DMA_TODEVICE);
-
+ dma_unmap_single(&ctrl_info->pci_dev->dev, bus_address,
+ sizeof(*base_struct), DMA_TO_DEVICE);
out:
kfree(base_struct_unaligned);
diff --git a/drivers/scsi/snic/snic_disc.c b/drivers/scsi/snic/snic_disc.c
index b106596cc0cf..e9ccfb97773f 100644
--- a/drivers/scsi/snic/snic_disc.c
+++ b/drivers/scsi/snic/snic_disc.c
@@ -111,8 +111,8 @@ snic_queue_report_tgt_req(struct snic *snic)
SNIC_BUG_ON((((unsigned long)buf) % SNIC_SG_DESC_ALIGN) != 0);
- pa = pci_map_single(snic->pdev, buf, buf_len, PCI_DMA_FROMDEVICE);
- if (pci_dma_mapping_error(snic->pdev, pa)) {
+ pa = dma_map_single(&snic->pdev->dev, buf, buf_len, DMA_FROM_DEVICE);
+ if (dma_mapping_error(&snic->pdev->dev, pa)) {
SNIC_HOST_ERR(snic->shost,
"Rpt-tgt rspbuf %p: PCI DMA Mapping Failed\n",
buf);
@@ -138,7 +138,8 @@ snic_queue_report_tgt_req(struct snic *snic)
ret = snic_queue_wq_desc(snic, rqi->req, rqi->req_len);
if (ret) {
- pci_unmap_single(snic->pdev, pa, buf_len, PCI_DMA_FROMDEVICE);
+ dma_unmap_single(&snic->pdev->dev, pa, buf_len,
+ DMA_FROM_DEVICE);
kfree(buf);
rqi->sge_va = 0;
snic_release_untagged_req(snic, rqi);
diff --git a/drivers/scsi/snic/snic_io.c b/drivers/scsi/snic/snic_io.c
index 8e69548395b9..159ee94d2a55 100644
--- a/drivers/scsi/snic/snic_io.c
+++ b/drivers/scsi/snic/snic_io.c
@@ -102,7 +102,8 @@ snic_free_wq_buf(struct vnic_wq *wq, struct vnic_wq_buf *buf)
struct snic_req_info *rqi = NULL;
unsigned long flags;
- pci_unmap_single(snic->pdev, buf->dma_addr, buf->len, PCI_DMA_TODEVICE);
+ dma_unmap_single(&snic->pdev->dev, buf->dma_addr, buf->len,
+ DMA_TO_DEVICE);
rqi = req_to_rqi(req);
spin_lock_irqsave(&snic->spl_cmd_lock, flags);
@@ -172,8 +173,8 @@ snic_queue_wq_desc(struct snic *snic, void *os_buf, u16 len)
snic_print_desc(__func__, os_buf, len);
/* Map request buffer */
- pa = pci_map_single(snic->pdev, os_buf, len, PCI_DMA_TODEVICE);
- if (pci_dma_mapping_error(snic->pdev, pa)) {
+ pa = dma_map_single(&snic->pdev->dev, os_buf, len, DMA_TO_DEVICE);
+ if (dma_mapping_error(&snic->pdev->dev, pa)) {
SNIC_HOST_ERR(snic->shost, "qdesc: PCI DMA Mapping Fail.\n");
return -ENOMEM;
@@ -186,7 +187,7 @@ snic_queue_wq_desc(struct snic *snic, void *os_buf, u16 len)
spin_lock_irqsave(&snic->wq_lock[q_num], flags);
desc_avail = snic_wqdesc_avail(snic, q_num, req->hdr.type);
if (desc_avail <= 0) {
- pci_unmap_single(snic->pdev, pa, len, PCI_DMA_TODEVICE);
+ dma_unmap_single(&snic->pdev->dev, pa, len, DMA_TO_DEVICE);
req->req_pa = 0;
spin_unlock_irqrestore(&snic->wq_lock[q_num], flags);
atomic64_inc(&snic->s_stats.misc.wq_alloc_fail);
@@ -350,29 +351,29 @@ snic_req_free(struct snic *snic, struct snic_req_info *rqi)
if (rqi->abort_req) {
if (rqi->abort_req->req_pa)
- pci_unmap_single(snic->pdev,
+ dma_unmap_single(&snic->pdev->dev,
rqi->abort_req->req_pa,
sizeof(struct snic_host_req),
- PCI_DMA_TODEVICE);
+ DMA_TO_DEVICE);
mempool_free(rqi->abort_req, snic->req_pool[SNIC_REQ_TM_CACHE]);
}
if (rqi->dr_req) {
if (rqi->dr_req->req_pa)
- pci_unmap_single(snic->pdev,
+ dma_unmap_single(&snic->pdev->dev,
rqi->dr_req->req_pa,
sizeof(struct snic_host_req),
- PCI_DMA_TODEVICE);
+ DMA_TO_DEVICE);
mempool_free(rqi->dr_req, snic->req_pool[SNIC_REQ_TM_CACHE]);
}
if (rqi->req->req_pa)
- pci_unmap_single(snic->pdev,
+ dma_unmap_single(&snic->pdev->dev,
rqi->req->req_pa,
rqi->req_len,
- PCI_DMA_TODEVICE);
+ DMA_TO_DEVICE);
mempool_free(rqi, snic->req_pool[rqi->rq_pool_type]);
}
@@ -384,10 +385,10 @@ snic_pci_unmap_rsp_buf(struct snic *snic, struct snic_req_info *rqi)
sgd = req_to_sgl(rqi_to_req(rqi));
SNIC_BUG_ON(sgd[0].addr == 0);
- pci_unmap_single(snic->pdev,
+ dma_unmap_single(&snic->pdev->dev,
le64_to_cpu(sgd[0].addr),
le32_to_cpu(sgd[0].len),
- PCI_DMA_FROMDEVICE);
+ DMA_FROM_DEVICE);
}
/*
diff --git a/drivers/scsi/snic/snic_main.c b/drivers/scsi/snic/snic_main.c
index 7cf70aaec0ba..5295277d6325 100644
--- a/drivers/scsi/snic/snic_main.c
+++ b/drivers/scsi/snic/snic_main.c
@@ -435,37 +435,17 @@ snic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
* limitation for the device. Try 43-bit first, and
* fail to 32-bit.
*/
- ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(43));
+ ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(43));
if (ret) {
- ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
if (ret) {
SNIC_HOST_ERR(shost,
"No Usable DMA Configuration, aborting %d\n",
ret);
-
- goto err_rel_regions;
- }
-
- ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
- if (ret) {
- SNIC_HOST_ERR(shost,
- "Unable to obtain 32-bit DMA for consistent allocations, aborting: %d\n",
- ret);
-
- goto err_rel_regions;
- }
- } else {
- ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(43));
- if (ret) {
- SNIC_HOST_ERR(shost,
- "Unable to obtain 43-bit DMA for consistent allocations. aborting: %d\n",
- ret);
-
goto err_rel_regions;
}
}
-
/* Map vNIC resources from BAR0 */
if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
SNIC_HOST_ERR(shost, "BAR0 not memory mappable aborting.\n");
diff --git a/drivers/scsi/snic/snic_scsi.c b/drivers/scsi/snic/snic_scsi.c
index d9b2e46424aa..b3650c989ed4 100644
--- a/drivers/scsi/snic/snic_scsi.c
+++ b/drivers/scsi/snic/snic_scsi.c
@@ -146,10 +146,10 @@ snic_release_req_buf(struct snic *snic,
CMD_FLAGS(sc));
if (req->u.icmnd.sense_addr)
- pci_unmap_single(snic->pdev,
+ dma_unmap_single(&snic->pdev->dev,
le64_to_cpu(req->u.icmnd.sense_addr),
SCSI_SENSE_BUFFERSIZE,
- PCI_DMA_FROMDEVICE);
+ DMA_FROM_DEVICE);
scsi_dma_unmap(sc);
@@ -185,12 +185,11 @@ snic_queue_icmnd_req(struct snic *snic,
}
}
- pa = pci_map_single(snic->pdev,
+ pa = dma_map_single(&snic->pdev->dev,
sc->sense_buffer,
SCSI_SENSE_BUFFERSIZE,
- PCI_DMA_FROMDEVICE);
-
- if (pci_dma_mapping_error(snic->pdev, pa)) {
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(&snic->pdev->dev, pa)) {
SNIC_HOST_ERR(snic->shost,
"QIcmnd:PCI Map Failed for sns buf %p tag %x\n",
sc->sense_buffer, snic_cmd_tag(sc));
@@ -2001,7 +2000,7 @@ snic_dr_finish(struct snic *snic, struct scsi_cmnd *sc)
}
dr_failed:
- SNIC_BUG_ON(!spin_is_locked(io_lock));
+ lockdep_assert_held(io_lock);
if (rqi)
CMD_SP(sc) = NULL;
spin_unlock_irqrestore(io_lock, flags);
@@ -2604,7 +2603,7 @@ snic_internal_abort_io(struct snic *snic, struct scsi_cmnd *sc, int tmf)
ret = SUCCESS;
skip_internal_abts:
- SNIC_BUG_ON(!spin_is_locked(io_lock));
+ lockdep_assert_held(io_lock);
spin_unlock_irqrestore(io_lock, flags);
return ret;
diff --git a/drivers/scsi/snic/vnic_dev.c b/drivers/scsi/snic/vnic_dev.c
index dad5fc66effb..05e374f80946 100644
--- a/drivers/scsi/snic/vnic_dev.c
+++ b/drivers/scsi/snic/vnic_dev.c
@@ -225,10 +225,9 @@ int svnic_dev_alloc_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring,
{
svnic_dev_desc_ring_size(ring, desc_count, desc_size);
- ring->descs_unaligned = pci_alloc_consistent(vdev->pdev,
- ring->size_unaligned,
- &ring->base_addr_unaligned);
-
+ ring->descs_unaligned = dma_alloc_coherent(&vdev->pdev->dev,
+ ring->size_unaligned, &ring->base_addr_unaligned,
+ GFP_KERNEL);
if (!ring->descs_unaligned) {
pr_err("Failed to allocate ring (size=%d), aborting\n",
(int)ring->size);
@@ -251,7 +250,7 @@ int svnic_dev_alloc_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring,
void svnic_dev_free_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring)
{
if (ring->descs) {
- pci_free_consistent(vdev->pdev,
+ dma_free_coherent(&vdev->pdev->dev,
ring->size_unaligned,
ring->descs_unaligned,
ring->base_addr_unaligned);
@@ -470,9 +469,9 @@ int svnic_dev_fw_info(struct vnic_dev *vdev,
int err = 0;
if (!vdev->fw_info) {
- vdev->fw_info = pci_alloc_consistent(vdev->pdev,
+ vdev->fw_info = dma_alloc_coherent(&vdev->pdev->dev,
sizeof(struct vnic_devcmd_fw_info),
- &vdev->fw_info_pa);
+ &vdev->fw_info_pa, GFP_KERNEL);
if (!vdev->fw_info)
return -ENOMEM;
@@ -534,8 +533,8 @@ int svnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats)
int wait = VNIC_DVCMD_TMO;
if (!vdev->stats) {
- vdev->stats = pci_alloc_consistent(vdev->pdev,
- sizeof(struct vnic_stats), &vdev->stats_pa);
+ vdev->stats = dma_alloc_coherent(&vdev->pdev->dev,
+ sizeof(struct vnic_stats), &vdev->stats_pa, GFP_KERNEL);
if (!vdev->stats)
return -ENOMEM;
}
@@ -607,9 +606,9 @@ int svnic_dev_notify_set(struct vnic_dev *vdev, u16 intr)
int wait = VNIC_DVCMD_TMO;
if (!vdev->notify) {
- vdev->notify = pci_alloc_consistent(vdev->pdev,
+ vdev->notify = dma_alloc_coherent(&vdev->pdev->dev,
sizeof(struct vnic_devcmd_notify),
- &vdev->notify_pa);
+ &vdev->notify_pa, GFP_KERNEL);
if (!vdev->notify)
return -ENOMEM;
}
@@ -697,21 +696,21 @@ void svnic_dev_unregister(struct vnic_dev *vdev)
{
if (vdev) {
if (vdev->notify)
- pci_free_consistent(vdev->pdev,
+ dma_free_coherent(&vdev->pdev->dev,
sizeof(struct vnic_devcmd_notify),
vdev->notify,
vdev->notify_pa);
if (vdev->linkstatus)
- pci_free_consistent(vdev->pdev,
+ dma_free_coherent(&vdev->pdev->dev,
sizeof(u32),
vdev->linkstatus,
vdev->linkstatus_pa);
if (vdev->stats)
- pci_free_consistent(vdev->pdev,
+ dma_free_coherent(&vdev->pdev->dev,
sizeof(struct vnic_stats),
vdev->stats, vdev->stats_pa);
if (vdev->fw_info)
- pci_free_consistent(vdev->pdev,
+ dma_free_coherent(&vdev->pdev->dev,
sizeof(struct vnic_devcmd_fw_info),
vdev->fw_info, vdev->fw_info_pa);
if (vdev->devcmd2)
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index d0389b20574d..54dd70ae9731 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -43,6 +43,7 @@
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/blkdev.h>
+#include <linux/blk-pm.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
@@ -758,7 +759,7 @@ static int sr_probe(struct device *dev)
dev_set_drvdata(dev, cd);
disk->flags |= GENHD_FL_REMOVABLE;
- device_add_disk(&sdev->sdev_gendev, disk);
+ device_add_disk(&sdev->sdev_gendev, disk, NULL);
sdev_printk(KERN_DEBUG, sdev,
"Attached scsi CD-ROM %s\n", cd->cdi.name);
diff --git a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c
index 0b1421cdf8a0..c9a55d0f076d 100644
--- a/drivers/scsi/sun3x_esp.c
+++ b/drivers/scsi/sun3x_esp.c
@@ -60,30 +60,6 @@ static u8 sun3x_esp_read8(struct esp *esp, unsigned long reg)
return readb(esp->regs + (reg * 4UL));
}
-static dma_addr_t sun3x_esp_map_single(struct esp *esp, void *buf,
- size_t sz, int dir)
-{
- return dma_map_single(esp->dev, buf, sz, dir);
-}
-
-static int sun3x_esp_map_sg(struct esp *esp, struct scatterlist *sg,
- int num_sg, int dir)
-{
- return dma_map_sg(esp->dev, sg, num_sg, dir);
-}
-
-static void sun3x_esp_unmap_single(struct esp *esp, dma_addr_t addr,
- size_t sz, int dir)
-{
- dma_unmap_single(esp->dev, addr, sz, dir);
-}
-
-static void sun3x_esp_unmap_sg(struct esp *esp, struct scatterlist *sg,
- int num_sg, int dir)
-{
- dma_unmap_sg(esp->dev, sg, num_sg, dir);
-}
-
static int sun3x_esp_irq_pending(struct esp *esp)
{
if (dma_read32(DMA_CSR) & (DMA_HNDL_INTR | DMA_HNDL_ERROR))
@@ -182,10 +158,6 @@ static int sun3x_esp_dma_error(struct esp *esp)
static const struct esp_driver_ops sun3x_esp_ops = {
.esp_write8 = sun3x_esp_write8,
.esp_read8 = sun3x_esp_read8,
- .map_single = sun3x_esp_map_single,
- .map_sg = sun3x_esp_map_sg,
- .unmap_single = sun3x_esp_unmap_single,
- .unmap_sg = sun3x_esp_unmap_sg,
.irq_pending = sun3x_esp_irq_pending,
.reset_dma = sun3x_esp_reset_dma,
.dma_drain = sun3x_esp_dma_drain,
@@ -246,7 +218,7 @@ static int esp_sun3x_probe(struct platform_device *dev)
dev_set_drvdata(&dev->dev, esp);
- err = scsi_esp_register(esp, &dev->dev);
+ err = scsi_esp_register(esp);
if (err)
goto fail_free_irq;
diff --git a/drivers/scsi/sun_esp.c b/drivers/scsi/sun_esp.c
index 747ee64a78e1..a11efbcb7f8b 100644
--- a/drivers/scsi/sun_esp.c
+++ b/drivers/scsi/sun_esp.c
@@ -80,7 +80,7 @@ static int esp_sbus_setup_dma(struct esp *esp, struct platform_device *dma_of)
static int esp_sbus_map_regs(struct esp *esp, int hme)
{
- struct platform_device *op = esp->dev;
+ struct platform_device *op = to_platform_device(esp->dev);
struct resource *res;
/* On HME, two reg sets exist, first is DVMA,
@@ -100,11 +100,9 @@ static int esp_sbus_map_regs(struct esp *esp, int hme)
static int esp_sbus_map_command_block(struct esp *esp)
{
- struct platform_device *op = esp->dev;
-
- esp->command_block = dma_alloc_coherent(&op->dev, 16,
+ esp->command_block = dma_alloc_coherent(esp->dev, 16,
&esp->command_block_dma,
- GFP_ATOMIC);
+ GFP_KERNEL);
if (!esp->command_block)
return -ENOMEM;
return 0;
@@ -113,7 +111,7 @@ static int esp_sbus_map_command_block(struct esp *esp)
static int esp_sbus_register_irq(struct esp *esp)
{
struct Scsi_Host *host = esp->host;
- struct platform_device *op = esp->dev;
+ struct platform_device *op = to_platform_device(esp->dev);
host->irq = op->archdata.irqs[0];
return request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, "ESP", esp);
@@ -121,7 +119,7 @@ static int esp_sbus_register_irq(struct esp *esp)
static void esp_get_scsi_id(struct esp *esp, struct platform_device *espdma)
{
- struct platform_device *op = esp->dev;
+ struct platform_device *op = to_platform_device(esp->dev);
struct device_node *dp;
dp = op->dev.of_node;
@@ -143,7 +141,7 @@ done:
static void esp_get_differential(struct esp *esp)
{
- struct platform_device *op = esp->dev;
+ struct platform_device *op = to_platform_device(esp->dev);
struct device_node *dp;
dp = op->dev.of_node;
@@ -155,7 +153,7 @@ static void esp_get_differential(struct esp *esp)
static void esp_get_clock_params(struct esp *esp)
{
- struct platform_device *op = esp->dev;
+ struct platform_device *op = to_platform_device(esp->dev);
struct device_node *bus_dp, *dp;
int fmhz;
@@ -172,7 +170,7 @@ static void esp_get_clock_params(struct esp *esp)
static void esp_get_bursts(struct esp *esp, struct platform_device *dma_of)
{
struct device_node *dma_dp = dma_of->dev.of_node;
- struct platform_device *op = esp->dev;
+ struct platform_device *op = to_platform_device(esp->dev);
struct device_node *dp;
u8 bursts, val;
@@ -212,38 +210,6 @@ static u8 sbus_esp_read8(struct esp *esp, unsigned long reg)
return sbus_readb(esp->regs + (reg * 4UL));
}
-static dma_addr_t sbus_esp_map_single(struct esp *esp, void *buf,
- size_t sz, int dir)
-{
- struct platform_device *op = esp->dev;
-
- return dma_map_single(&op->dev, buf, sz, dir);
-}
-
-static int sbus_esp_map_sg(struct esp *esp, struct scatterlist *sg,
- int num_sg, int dir)
-{
- struct platform_device *op = esp->dev;
-
- return dma_map_sg(&op->dev, sg, num_sg, dir);
-}
-
-static void sbus_esp_unmap_single(struct esp *esp, dma_addr_t addr,
- size_t sz, int dir)
-{
- struct platform_device *op = esp->dev;
-
- dma_unmap_single(&op->dev, addr, sz, dir);
-}
-
-static void sbus_esp_unmap_sg(struct esp *esp, struct scatterlist *sg,
- int num_sg, int dir)
-{
- struct platform_device *op = esp->dev;
-
- dma_unmap_sg(&op->dev, sg, num_sg, dir);
-}
-
static int sbus_esp_irq_pending(struct esp *esp)
{
if (dma_read32(DMA_CSR) & (DMA_HNDL_INTR | DMA_HNDL_ERROR))
@@ -255,14 +221,13 @@ static void sbus_esp_reset_dma(struct esp *esp)
{
int can_do_burst16, can_do_burst32, can_do_burst64;
int can_do_sbus64, lim;
- struct platform_device *op;
+ struct platform_device *op = to_platform_device(esp->dev);
u32 val;
can_do_burst16 = (esp->bursts & DMA_BURST16) != 0;
can_do_burst32 = (esp->bursts & DMA_BURST32) != 0;
can_do_burst64 = 0;
can_do_sbus64 = 0;
- op = esp->dev;
if (sbus_can_dma_64bit())
can_do_sbus64 = 1;
if (sbus_can_burst64())
@@ -474,10 +439,6 @@ static int sbus_esp_dma_error(struct esp *esp)
static const struct esp_driver_ops sbus_esp_ops = {
.esp_write8 = sbus_esp_write8,
.esp_read8 = sbus_esp_read8,
- .map_single = sbus_esp_map_single,
- .map_sg = sbus_esp_map_sg,
- .unmap_single = sbus_esp_unmap_single,
- .unmap_sg = sbus_esp_unmap_sg,
.irq_pending = sbus_esp_irq_pending,
.reset_dma = sbus_esp_reset_dma,
.dma_drain = sbus_esp_dma_drain,
@@ -504,7 +465,7 @@ static int esp_sbus_probe_one(struct platform_device *op,
esp = shost_priv(host);
esp->host = host;
- esp->dev = op;
+ esp->dev = &op->dev;
esp->ops = &sbus_esp_ops;
if (hme)
@@ -540,7 +501,7 @@ static int esp_sbus_probe_one(struct platform_device *op,
dev_set_drvdata(&op->dev, esp);
- err = scsi_esp_register(esp, &op->dev);
+ err = scsi_esp_register(esp);
if (err)
goto fail_free_irq;
diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c
index bd3f6e2d6834..0a2a54517b15 100644
--- a/drivers/scsi/sym53c8xx_2/sym_hipd.c
+++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c
@@ -4370,6 +4370,13 @@ static void sym_nego_rejected(struct sym_hcb *np, struct sym_tcb *tp, struct sym
OUTB(np, HS_PRT, HS_BUSY);
}
+#define sym_printk(lvl, tp, cp, fmt, v...) do { \
+ if (cp) \
+ scmd_printk(lvl, cp->cmd, fmt, ##v); \
+ else \
+ starget_printk(lvl, tp->starget, fmt, ##v); \
+} while (0)
+
/*
* chip exception handler for programmed interrupts.
*/
@@ -4415,7 +4422,7 @@ static void sym_int_sir(struct sym_hcb *np)
* been selected with ATN. We do not want to handle that.
*/
case SIR_SEL_ATN_NO_MSG_OUT:
- scmd_printk(KERN_WARNING, cp->cmd,
+ sym_printk(KERN_WARNING, tp, cp,
"No MSG OUT phase after selection with ATN\n");
goto out_stuck;
/*
@@ -4423,7 +4430,7 @@ static void sym_int_sir(struct sym_hcb *np)
* having reselected the initiator.
*/
case SIR_RESEL_NO_MSG_IN:
- scmd_printk(KERN_WARNING, cp->cmd,
+ sym_printk(KERN_WARNING, tp, cp,
"No MSG IN phase after reselection\n");
goto out_stuck;
/*
@@ -4431,7 +4438,7 @@ static void sym_int_sir(struct sym_hcb *np)
* an IDENTIFY.
*/
case SIR_RESEL_NO_IDENTIFY:
- scmd_printk(KERN_WARNING, cp->cmd,
+ sym_printk(KERN_WARNING, tp, cp,
"No IDENTIFY after reselection\n");
goto out_stuck;
/*
@@ -4460,7 +4467,7 @@ static void sym_int_sir(struct sym_hcb *np)
case SIR_RESEL_ABORTED:
np->lastmsg = np->msgout[0];
np->msgout[0] = M_NOOP;
- scmd_printk(KERN_WARNING, cp->cmd,
+ sym_printk(KERN_WARNING, tp, cp,
"message %x sent on bad reselection\n", np->lastmsg);
goto out;
/*
diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig
index e09fe6ab3572..2ddd426323e9 100644
--- a/drivers/scsi/ufs/Kconfig
+++ b/drivers/scsi/ufs/Kconfig
@@ -109,3 +109,22 @@ config SCSI_UFS_HISI
Select this if you have UFS controller on Hisilicon chipset.
If unsure, say N.
+
+config SCSI_UFS_BSG
+ bool "Universal Flash Storage BSG device node"
+ depends on SCSI_UFSHCD
+ select BLK_DEV_BSGLIB
+ help
+ Universal Flash Storage (UFS) is SCSI transport specification for
+ accessing flash storage on digital cameras, mobile phones and
+ consumer electronic devices.
+ A UFS controller communicates with a UFS device by exchanging
+ UFS Protocol Information Units (UPIUs).
+ UPIUs can not only be used as a transport layer for the SCSI protocol
+ but are also used by the UFS native command set.
+ This transport driver supports exchanging UFS protocol information units
+ with a UFS device. See also the ufshcd driver, which is a SCSI driver
+ that supports UFS devices.
+
+ Select this if you need a bsg device node for your UFS controller.
+ If unsure, say N.
diff --git a/drivers/scsi/ufs/Makefile b/drivers/scsi/ufs/Makefile
index 2c50f03d8c4a..aca481329828 100644
--- a/drivers/scsi/ufs/Makefile
+++ b/drivers/scsi/ufs/Makefile
@@ -4,7 +4,8 @@ obj-$(CONFIG_SCSI_UFS_DWC_TC_PCI) += tc-dwc-g210-pci.o ufshcd-dwc.o tc-dwc-g210.
obj-$(CONFIG_SCSI_UFS_DWC_TC_PLATFORM) += tc-dwc-g210-pltfrm.o ufshcd-dwc.o tc-dwc-g210.o
obj-$(CONFIG_SCSI_UFS_QCOM) += ufs-qcom.o
obj-$(CONFIG_SCSI_UFSHCD) += ufshcd-core.o
-ufshcd-core-objs := ufshcd.o ufs-sysfs.o
+ufshcd-core-y += ufshcd.o ufs-sysfs.o
+ufshcd-core-$(CONFIG_SCSI_UFS_BSG) += ufs_bsg.o
obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o
obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.o
obj-$(CONFIG_SCSI_UFS_HISI) += ufs-hisi.o
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 75ee5906b966..3aeadb14aae1 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -16,7 +16,6 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/phy/phy.h>
-#include <linux/phy/phy-qcom-ufs.h>
#include "ufshcd.h"
#include "ufshcd-pltfrm.h"
@@ -70,20 +69,27 @@ static int ufs_qcom_get_connected_tx_lanes(struct ufs_hba *hba, u32 *tx_lanes)
}
static int ufs_qcom_host_clk_get(struct device *dev,
- const char *name, struct clk **clk_out)
+ const char *name, struct clk **clk_out, bool optional)
{
struct clk *clk;
int err = 0;
clk = devm_clk_get(dev, name);
- if (IS_ERR(clk)) {
- err = PTR_ERR(clk);
- dev_err(dev, "%s: failed to get %s err %d",
- __func__, name, err);
- } else {
+ if (!IS_ERR(clk)) {
*clk_out = clk;
+ return 0;
}
+ err = PTR_ERR(clk);
+
+ if (optional && err == -ENOENT) {
+ *clk_out = NULL;
+ return 0;
+ }
+
+ if (err != -EPROBE_DEFER)
+ dev_err(dev, "failed to get %s err %d\n", name, err);
+
return err;
}
@@ -104,11 +110,9 @@ static void ufs_qcom_disable_lane_clks(struct ufs_qcom_host *host)
if (!host->is_lane_clks_enabled)
return;
- if (host->hba->lanes_per_direction > 1)
- clk_disable_unprepare(host->tx_l1_sync_clk);
+ clk_disable_unprepare(host->tx_l1_sync_clk);
clk_disable_unprepare(host->tx_l0_sync_clk);
- if (host->hba->lanes_per_direction > 1)
- clk_disable_unprepare(host->rx_l1_sync_clk);
+ clk_disable_unprepare(host->rx_l1_sync_clk);
clk_disable_unprepare(host->rx_l0_sync_clk);
host->is_lane_clks_enabled = false;
@@ -132,24 +136,21 @@ static int ufs_qcom_enable_lane_clks(struct ufs_qcom_host *host)
if (err)
goto disable_rx_l0;
- if (host->hba->lanes_per_direction > 1) {
- err = ufs_qcom_host_clk_enable(dev, "rx_lane1_sync_clk",
+ err = ufs_qcom_host_clk_enable(dev, "rx_lane1_sync_clk",
host->rx_l1_sync_clk);
- if (err)
- goto disable_tx_l0;
+ if (err)
+ goto disable_tx_l0;
- err = ufs_qcom_host_clk_enable(dev, "tx_lane1_sync_clk",
+ err = ufs_qcom_host_clk_enable(dev, "tx_lane1_sync_clk",
host->tx_l1_sync_clk);
- if (err)
- goto disable_rx_l1;
- }
+ if (err)
+ goto disable_rx_l1;
host->is_lane_clks_enabled = true;
goto out;
disable_rx_l1:
- if (host->hba->lanes_per_direction > 1)
- clk_disable_unprepare(host->rx_l1_sync_clk);
+ clk_disable_unprepare(host->rx_l1_sync_clk);
disable_tx_l0:
clk_disable_unprepare(host->tx_l0_sync_clk);
disable_rx_l0:
@@ -163,25 +164,25 @@ static int ufs_qcom_init_lane_clks(struct ufs_qcom_host *host)
int err = 0;
struct device *dev = host->hba->dev;
- err = ufs_qcom_host_clk_get(dev,
- "rx_lane0_sync_clk", &host->rx_l0_sync_clk);
+ err = ufs_qcom_host_clk_get(dev, "rx_lane0_sync_clk",
+ &host->rx_l0_sync_clk, false);
if (err)
goto out;
- err = ufs_qcom_host_clk_get(dev,
- "tx_lane0_sync_clk", &host->tx_l0_sync_clk);
+ err = ufs_qcom_host_clk_get(dev, "tx_lane0_sync_clk",
+ &host->tx_l0_sync_clk, false);
if (err)
goto out;
/* In case of single lane per direction, don't read lane1 clocks */
if (host->hba->lanes_per_direction > 1) {
err = ufs_qcom_host_clk_get(dev, "rx_lane1_sync_clk",
- &host->rx_l1_sync_clk);
+ &host->rx_l1_sync_clk, false);
if (err)
goto out;
err = ufs_qcom_host_clk_get(dev, "tx_lane1_sync_clk",
- &host->tx_l1_sync_clk);
+ &host->tx_l1_sync_clk, true);
}
out:
return err;
@@ -189,22 +190,9 @@ out:
static int ufs_qcom_link_startup_post_change(struct ufs_hba *hba)
{
- struct ufs_qcom_host *host = ufshcd_get_variant(hba);
- struct phy *phy = host->generic_phy;
u32 tx_lanes;
- int err = 0;
-
- err = ufs_qcom_get_connected_tx_lanes(hba, &tx_lanes);
- if (err)
- goto out;
-
- err = ufs_qcom_phy_set_tx_lane_enable(phy, tx_lanes);
- if (err)
- dev_err(hba->dev, "%s: ufs_qcom_phy_set_tx_lane_enable failed\n",
- __func__);
-out:
- return err;
+ return ufs_qcom_get_connected_tx_lanes(hba, &tx_lanes);
}
static int ufs_qcom_check_hibern8(struct ufs_hba *hba)
@@ -932,10 +920,8 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
{
u32 val;
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
- struct phy *phy = host->generic_phy;
struct ufs_qcom_dev_params ufs_qcom_cap;
int ret = 0;
- int res = 0;
if (!dev_req_params) {
pr_err("%s: incoming dev_req_params is NULL\n", __func__);
@@ -1002,12 +988,6 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
}
val = ~(MAX_U32 << dev_req_params->lane_tx);
- res = ufs_qcom_phy_set_tx_lane_enable(phy, val);
- if (res) {
- dev_err(hba->dev, "%s: ufs_qcom_phy_set_tx_lane_enable() failed res = %d\n",
- __func__, res);
- ret = res;
- }
/* cache the power mode parameters to use internally */
memcpy(&host->dev_req_params,
@@ -1264,10 +1244,6 @@ static int ufs_qcom_init(struct ufs_hba *hba)
}
}
- /* update phy revision information before calling phy_init() */
- ufs_qcom_phy_save_controller_version(host->generic_phy,
- host->hw_ver.major, host->hw_ver.minor, host->hw_ver.step);
-
err = ufs_qcom_init_lane_clks(host);
if (err)
goto out_variant_clear;
diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h
index 295f4bef6a0e..c114826316eb 100644
--- a/drivers/scsi/ufs/ufs-qcom.h
+++ b/drivers/scsi/ufs/ufs-qcom.h
@@ -129,11 +129,6 @@ enum {
MASK_CLK_NS_REG = 0xFFFC00,
};
-enum ufs_qcom_phy_init_type {
- UFS_PHY_INIT_FULL,
- UFS_PHY_INIT_CFG_RESTORE,
-};
-
/* QCOM UFS debug print bit mask */
#define UFS_QCOM_DBG_PRINT_REGS_EN BIT(0)
#define UFS_QCOM_DBG_PRINT_ICE_REGS_EN BIT(1)
diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 14e5bf7af0bb..58087d3916d0 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -38,9 +38,9 @@
#include <linux/mutex.h>
#include <linux/types.h>
+#include <uapi/scsi/scsi_bsg_ufs.h>
-#define MAX_CDB_SIZE 16
-#define GENERAL_UPIU_REQUEST_SIZE 32
+#define GENERAL_UPIU_REQUEST_SIZE (sizeof(struct utp_upiu_req))
#define QUERY_DESC_MAX_SIZE 255
#define QUERY_DESC_MIN_SIZE 2
#define QUERY_DESC_HDR_SIZE 2
@@ -414,6 +414,7 @@ enum {
MASK_RSP_UPIU_DATA_SEG_LEN = 0xFFFF,
MASK_RSP_EXCEPTION_EVENT = 0x10000,
MASK_TM_SERVICE_RESP = 0xFF,
+ MASK_TM_FUNC = 0xFF,
};
/* Task management service response */
@@ -433,65 +434,6 @@ enum ufs_dev_pwr_mode {
};
/**
- * struct utp_upiu_header - UPIU header structure
- * @dword_0: UPIU header DW-0
- * @dword_1: UPIU header DW-1
- * @dword_2: UPIU header DW-2
- */
-struct utp_upiu_header {
- __be32 dword_0;
- __be32 dword_1;
- __be32 dword_2;
-};
-
-/**
- * struct utp_upiu_cmd - Command UPIU structure
- * @data_transfer_len: Data Transfer Length DW-3
- * @cdb: Command Descriptor Block CDB DW-4 to DW-7
- */
-struct utp_upiu_cmd {
- __be32 exp_data_transfer_len;
- u8 cdb[MAX_CDB_SIZE];
-};
-
-/**
- * struct utp_upiu_query - upiu request buffer structure for
- * query request.
- * @opcode: command to perform B-0
- * @idn: a value that indicates the particular type of data B-1
- * @index: Index to further identify data B-2
- * @selector: Index to further identify data B-3
- * @reserved_osf: spec reserved field B-4,5
- * @length: number of descriptor bytes to read/write B-6,7
- * @value: Attribute value to be written DW-5
- * @reserved: spec reserved DW-6,7
- */
-struct utp_upiu_query {
- u8 opcode;
- u8 idn;
- u8 index;
- u8 selector;
- __be16 reserved_osf;
- __be16 length;
- __be32 value;
- __be32 reserved[2];
-};
-
-/**
- * struct utp_upiu_req - general upiu request structure
- * @header:UPIU header structure DW-0 to DW-2
- * @sc: fields structure for scsi command DW-3 to DW-7
- * @qr: fields structure for query request DW-3 to DW-7
- */
-struct utp_upiu_req {
- struct utp_upiu_header header;
- union {
- struct utp_upiu_cmd sc;
- struct utp_upiu_query qr;
- };
-};
-
-/**
* struct utp_cmd_rsp - Response UPIU structure
* @residual_transfer_count: Residual transfer count DW-3
* @reserved: Reserved double words DW-4 to DW-7
@@ -520,36 +462,6 @@ struct utp_upiu_rsp {
};
/**
- * struct utp_upiu_task_req - Task request UPIU structure
- * @header - UPIU header structure DW0 to DW-2
- * @input_param1: Input parameter 1 DW-3
- * @input_param2: Input parameter 2 DW-4
- * @input_param3: Input parameter 3 DW-5
- * @reserved: Reserved double words DW-6 to DW-7
- */
-struct utp_upiu_task_req {
- struct utp_upiu_header header;
- __be32 input_param1;
- __be32 input_param2;
- __be32 input_param3;
- __be32 reserved[2];
-};
-
-/**
- * struct utp_upiu_task_rsp - Task Management Response UPIU structure
- * @header: UPIU header structure DW0-DW-2
- * @output_param1: Ouput parameter 1 DW3
- * @output_param2: Output parameter 2 DW4
- * @reserved: Reserved double words DW-5 to DW-7
- */
-struct utp_upiu_task_rsp {
- struct utp_upiu_header header;
- __be32 output_param1;
- __be32 output_param2;
- __be32 reserved[3];
-};
-
-/**
* struct ufs_query_req - parameters for building a query request
* @query_func: UPIU header query function
* @upiu_req: the query request data
diff --git a/drivers/scsi/ufs/ufs_bsg.c b/drivers/scsi/ufs/ufs_bsg.c
new file mode 100644
index 000000000000..e5f8e54bf644
--- /dev/null
+++ b/drivers/scsi/ufs/ufs_bsg.c
@@ -0,0 +1,210 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * bsg endpoint that supports UPIUs
+ *
+ * Copyright (C) 2018 Western Digital Corporation
+ */
+#include "ufs_bsg.h"
+
+static int ufs_bsg_get_query_desc_size(struct ufs_hba *hba, int *desc_len,
+ struct utp_upiu_query *qr)
+{
+ int desc_size = be16_to_cpu(qr->length);
+ int desc_id = qr->idn;
+ int ret;
+
+ if (desc_size <= 0)
+ return -EINVAL;
+
+ ret = ufshcd_map_desc_id_to_length(hba, desc_id, desc_len);
+ if (ret || !*desc_len)
+ return -EINVAL;
+
+ *desc_len = min_t(int, *desc_len, desc_size);
+
+ return 0;
+}
+
+static int ufs_bsg_verify_query_size(struct ufs_hba *hba,
+ unsigned int request_len,
+ unsigned int reply_len,
+ int desc_len, enum query_opcode desc_op)
+{
+ int min_req_len = sizeof(struct ufs_bsg_request);
+ int min_rsp_len = sizeof(struct ufs_bsg_reply);
+
+ if (desc_op == UPIU_QUERY_OPCODE_WRITE_DESC)
+ min_req_len += desc_len;
+
+ if (min_req_len > request_len || min_rsp_len > reply_len) {
+ dev_err(hba->dev, "not enough space assigned\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ufs_bsg_verify_query_params(struct ufs_hba *hba,
+ struct ufs_bsg_request *bsg_request,
+ unsigned int request_len,
+ unsigned int reply_len,
+ uint8_t *desc_buff, int *desc_len,
+ enum query_opcode desc_op)
+{
+ struct utp_upiu_query *qr;
+
+ if (desc_op == UPIU_QUERY_OPCODE_READ_DESC) {
+ dev_err(hba->dev, "unsupported opcode %d\n", desc_op);
+ return -ENOTSUPP;
+ }
+
+ if (desc_op != UPIU_QUERY_OPCODE_WRITE_DESC)
+ goto out;
+
+ qr = &bsg_request->upiu_req.qr;
+ if (ufs_bsg_get_query_desc_size(hba, desc_len, qr)) {
+ dev_err(hba->dev, "Illegal desc size\n");
+ return -EINVAL;
+ }
+
+ if (ufs_bsg_verify_query_size(hba, request_len, reply_len, *desc_len,
+ desc_op))
+ return -EINVAL;
+
+ desc_buff = (uint8_t *)(bsg_request + 1);
+
+out:
+ return 0;
+}
+
+static int ufs_bsg_request(struct bsg_job *job)
+{
+ struct ufs_bsg_request *bsg_request = job->request;
+ struct ufs_bsg_reply *bsg_reply = job->reply;
+ struct ufs_hba *hba = shost_priv(dev_to_shost(job->dev->parent));
+ unsigned int req_len = job->request_len;
+ unsigned int reply_len = job->reply_len;
+ struct uic_command uc = {};
+ int msgcode;
+ uint8_t *desc_buff = NULL;
+ int desc_len = 0;
+ enum query_opcode desc_op = UPIU_QUERY_OPCODE_NOP;
+ int ret;
+
+ ret = ufs_bsg_verify_query_size(hba, req_len, reply_len, 0, desc_op);
+ if (ret)
+ goto out;
+
+ bsg_reply->reply_payload_rcv_len = 0;
+
+ msgcode = bsg_request->msgcode;
+ switch (msgcode) {
+ case UPIU_TRANSACTION_QUERY_REQ:
+ desc_op = bsg_request->upiu_req.qr.opcode;
+ ret = ufs_bsg_verify_query_params(hba, bsg_request, req_len,
+ reply_len, desc_buff,
+ &desc_len, desc_op);
+ if (ret)
+ goto out;
+
+ /* fall through */
+ case UPIU_TRANSACTION_NOP_OUT:
+ case UPIU_TRANSACTION_TASK_REQ:
+ ret = ufshcd_exec_raw_upiu_cmd(hba, &bsg_request->upiu_req,
+ &bsg_reply->upiu_rsp, msgcode,
+ desc_buff, &desc_len, desc_op);
+ if (ret)
+ dev_err(hba->dev,
+ "exe raw upiu: error code %d\n", ret);
+
+ break;
+ case UPIU_TRANSACTION_UIC_CMD:
+ memcpy(&uc, &bsg_request->upiu_req.uc, UIC_CMD_SIZE);
+ ret = ufshcd_send_uic_cmd(hba, &uc);
+ if (ret)
+ dev_dbg(hba->dev,
+ "send uic cmd: error code %d\n", ret);
+
+ memcpy(&bsg_reply->upiu_rsp.uc, &uc, UIC_CMD_SIZE);
+
+ break;
+ default:
+ ret = -ENOTSUPP;
+ dev_err(hba->dev, "unsupported msgcode 0x%x\n", msgcode);
+
+ break;
+ }
+
+out:
+ bsg_reply->result = ret;
+ job->reply_len = sizeof(struct ufs_bsg_reply) +
+ bsg_reply->reply_payload_rcv_len;
+
+ bsg_job_done(job, ret, bsg_reply->reply_payload_rcv_len);
+
+ return ret;
+}
+
+/**
+ * ufs_bsg_remove - detach and remove the added ufs-bsg node
+ *
+ * Should be called when unloading the driver.
+ */
+void ufs_bsg_remove(struct ufs_hba *hba)
+{
+ struct device *bsg_dev = &hba->bsg_dev;
+
+ if (!hba->bsg_queue)
+ return;
+
+ bsg_unregister_queue(hba->bsg_queue);
+
+ device_del(bsg_dev);
+ put_device(bsg_dev);
+}
+
+static inline void ufs_bsg_node_release(struct device *dev)
+{
+ put_device(dev->parent);
+}
+
+/**
+ * ufs_bsg_probe - Add ufs bsg device node
+ * @hba: per adapter object
+ *
+ * Called during initial loading of the driver, and before scsi_scan_host.
+ */
+int ufs_bsg_probe(struct ufs_hba *hba)
+{
+ struct device *bsg_dev = &hba->bsg_dev;
+ struct Scsi_Host *shost = hba->host;
+ struct device *parent = &shost->shost_gendev;
+ struct request_queue *q;
+ int ret;
+
+ device_initialize(bsg_dev);
+
+ bsg_dev->parent = get_device(parent);
+ bsg_dev->release = ufs_bsg_node_release;
+
+ dev_set_name(bsg_dev, "ufs-bsg");
+
+ ret = device_add(bsg_dev);
+ if (ret)
+ goto out;
+
+ q = bsg_setup_queue(bsg_dev, dev_name(bsg_dev), ufs_bsg_request, 0);
+ if (IS_ERR(q)) {
+ ret = PTR_ERR(q);
+ goto out;
+ }
+
+ hba->bsg_queue = q;
+
+ return 0;
+
+out:
+ dev_err(bsg_dev, "fail to initialize a bsg dev %d\n", shost->host_no);
+ put_device(bsg_dev);
+ return ret;
+}
diff --git a/drivers/scsi/ufs/ufs_bsg.h b/drivers/scsi/ufs/ufs_bsg.h
new file mode 100644
index 000000000000..d09918758631
--- /dev/null
+++ b/drivers/scsi/ufs/ufs_bsg.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 Western Digital Corporation
+ */
+#ifndef UFS_BSG_H
+#define UFS_BSG_H
+
+#include <linux/bsg-lib.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+
+#include "ufshcd.h"
+#include "ufs.h"
+
+#ifdef CONFIG_SCSI_UFS_BSG
+void ufs_bsg_remove(struct ufs_hba *hba);
+int ufs_bsg_probe(struct ufs_hba *hba);
+#else
+static inline void ufs_bsg_remove(struct ufs_hba *hba) {}
+static inline int ufs_bsg_probe(struct ufs_hba *hba) {return 0; }
+#endif
+
+#endif /* UFS_BSG_H */
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index c55f38ec391c..27db55b0ca7f 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -46,6 +46,7 @@
#include "ufs_quirks.h"
#include "unipro.h"
#include "ufs-sysfs.h"
+#include "ufs_bsg.h"
#define CREATE_TRACE_POINTS
#include <trace/events/ufs.h>
@@ -326,14 +327,11 @@ static void ufshcd_add_query_upiu_trace(struct ufs_hba *hba, unsigned int tag,
static void ufshcd_add_tm_upiu_trace(struct ufs_hba *hba, unsigned int tag,
const char *str)
{
- struct utp_task_req_desc *descp;
- struct utp_upiu_task_req *task_req;
int off = (int)tag - hba->nutrs;
+ struct utp_task_req_desc *descp = &hba->utmrdl_base_addr[off];
- descp = &hba->utmrdl_base_addr[off];
- task_req = (struct utp_upiu_task_req *)descp->task_req_upiu;
- trace_ufshcd_upiu(dev_name(hba->dev), str, &task_req->header,
- &task_req->input_param1);
+ trace_ufshcd_upiu(dev_name(hba->dev), str, &descp->req_header,
+ &descp->input_param1);
}
static void ufshcd_add_command_trace(struct ufs_hba *hba,
@@ -475,22 +473,13 @@ void ufshcd_print_trs(struct ufs_hba *hba, unsigned long bitmap, bool pr_prdt)
static void ufshcd_print_tmrs(struct ufs_hba *hba, unsigned long bitmap)
{
- struct utp_task_req_desc *tmrdp;
int tag;
for_each_set_bit(tag, &bitmap, hba->nutmrs) {
- tmrdp = &hba->utmrdl_base_addr[tag];
+ struct utp_task_req_desc *tmrdp = &hba->utmrdl_base_addr[tag];
+
dev_err(hba->dev, "TM[%d] - Task Management Header\n", tag);
- ufshcd_hex_dump("TM TRD: ", &tmrdp->header,
- sizeof(struct request_desc_header));
- dev_err(hba->dev, "TM[%d] - Task Management Request UPIU\n",
- tag);
- ufshcd_hex_dump("TM REQ: ", tmrdp->task_req_upiu,
- sizeof(struct utp_upiu_req));
- dev_err(hba->dev, "TM[%d] - Task Management Response UPIU\n",
- tag);
- ufshcd_hex_dump("TM RSP: ", tmrdp->task_rsp_upiu,
- sizeof(struct utp_task_req_desc));
+ ufshcd_hex_dump("", tmrdp, sizeof(*tmrdp));
}
}
@@ -646,19 +635,6 @@ static inline int ufshcd_get_tr_ocs(struct ufshcd_lrb *lrbp)
}
/**
- * ufshcd_get_tmr_ocs - Get the UTMRD Overall Command Status
- * @task_req_descp: pointer to utp_task_req_desc structure
- *
- * This function is used to get the OCS field from UTMRD
- * Returns the OCS field in the UTMRD
- */
-static inline int
-ufshcd_get_tmr_ocs(struct utp_task_req_desc *task_req_descp)
-{
- return le32_to_cpu(task_req_descp->header.dword_2) & MASK_OCS;
-}
-
-/**
* ufshcd_get_tm_free_slot - get a free slot for task management request
* @hba: per adapter instance
* @free_slot: pointer to variable with available slot value
@@ -1691,8 +1667,9 @@ static void __ufshcd_release(struct ufs_hba *hba)
hba->clk_gating.state = REQ_CLKS_OFF;
trace_ufshcd_clk_gating(dev_name(hba->dev), hba->clk_gating.state);
- schedule_delayed_work(&hba->clk_gating.gate_work,
- msecs_to_jiffies(hba->clk_gating.delay_ms));
+ queue_delayed_work(hba->clk_gating.clk_gating_workq,
+ &hba->clk_gating.gate_work,
+ msecs_to_jiffies(hba->clk_gating.delay_ms));
}
void ufshcd_release(struct ufs_hba *hba)
@@ -1763,6 +1740,34 @@ out:
return count;
}
+static void ufshcd_init_clk_scaling(struct ufs_hba *hba)
+{
+ char wq_name[sizeof("ufs_clkscaling_00")];
+
+ if (!ufshcd_is_clkscaling_supported(hba))
+ return;
+
+ INIT_WORK(&hba->clk_scaling.suspend_work,
+ ufshcd_clk_scaling_suspend_work);
+ INIT_WORK(&hba->clk_scaling.resume_work,
+ ufshcd_clk_scaling_resume_work);
+
+ snprintf(wq_name, sizeof(wq_name), "ufs_clkscaling_%d",
+ hba->host->host_no);
+ hba->clk_scaling.workq = create_singlethread_workqueue(wq_name);
+
+ ufshcd_clkscaling_init_sysfs(hba);
+}
+
+static void ufshcd_exit_clk_scaling(struct ufs_hba *hba)
+{
+ if (!ufshcd_is_clkscaling_supported(hba))
+ return;
+
+ destroy_workqueue(hba->clk_scaling.workq);
+ ufshcd_devfreq_remove(hba);
+}
+
static void ufshcd_init_clk_gating(struct ufs_hba *hba)
{
char wq_name[sizeof("ufs_clk_gating_00")];
@@ -2055,8 +2060,7 @@ __ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd,
*
* Returns 0 only if success.
*/
-static int
-ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
+int ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
{
int ret;
unsigned long flags;
@@ -2238,8 +2242,8 @@ void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufshcd_lrb *lrbp, u32 upiu_flags)
ucd_req_ptr->sc.exp_data_transfer_len =
cpu_to_be32(lrbp->cmd->sdb.length);
- cdb_len = min_t(unsigned short, lrbp->cmd->cmd_len, MAX_CDB_SIZE);
- memset(ucd_req_ptr->sc.cdb, 0, MAX_CDB_SIZE);
+ cdb_len = min_t(unsigned short, lrbp->cmd->cmd_len, UFS_CDB_SIZE);
+ memset(ucd_req_ptr->sc.cdb, 0, UFS_CDB_SIZE);
memcpy(ucd_req_ptr->sc.cdb, lrbp->cmd->cmnd, cdb_len);
memset(lrbp->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp));
@@ -2258,7 +2262,6 @@ static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba,
struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr;
struct ufs_query *query = &hba->dev_cmd.query;
u16 len = be16_to_cpu(query->request.upiu_req.length);
- u8 *descp = (u8 *)lrbp->ucd_req_ptr + GENERAL_UPIU_REQUEST_SIZE;
/* Query request header */
ucd_req_ptr->header.dword_0 = UPIU_HEADER_DWORD(
@@ -2280,7 +2283,7 @@ static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba,
/* Copy the Descriptor */
if (query->request.upiu_req.opcode == UPIU_QUERY_OPCODE_WRITE_DESC)
- memcpy(descp, query->descriptor, len);
+ memcpy(ucd_req_ptr + 1, query->descriptor, len);
memset(lrbp->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp));
}
@@ -4601,46 +4604,6 @@ static void ufshcd_slave_destroy(struct scsi_device *sdev)
}
/**
- * ufshcd_task_req_compl - handle task management request completion
- * @hba: per adapter instance
- * @index: index of the completed request
- * @resp: task management service response
- *
- * Returns non-zero value on error, zero on success
- */
-static int ufshcd_task_req_compl(struct ufs_hba *hba, u32 index, u8 *resp)
-{
- struct utp_task_req_desc *task_req_descp;
- struct utp_upiu_task_rsp *task_rsp_upiup;
- unsigned long flags;
- int ocs_value;
- int task_result;
-
- spin_lock_irqsave(hba->host->host_lock, flags);
-
- /* Clear completed tasks from outstanding_tasks */
- __clear_bit(index, &hba->outstanding_tasks);
-
- task_req_descp = hba->utmrdl_base_addr;
- ocs_value = ufshcd_get_tmr_ocs(&task_req_descp[index]);
-
- if (ocs_value == OCS_SUCCESS) {
- task_rsp_upiup = (struct utp_upiu_task_rsp *)
- task_req_descp[index].task_rsp_upiu;
- task_result = be32_to_cpu(task_rsp_upiup->output_param1);
- task_result = task_result & MASK_TM_SERVICE_RESP;
- if (resp)
- *resp = (u8)task_result;
- } else {
- dev_err(hba->dev, "%s: failed, ocs = 0x%x\n",
- __func__, ocs_value);
- }
- spin_unlock_irqrestore(hba->host->host_lock, flags);
-
- return ocs_value;
-}
-
-/**
* ufshcd_scsi_cmd_status - Update SCSI command result based on SCSI status
* @lrbp: pointer to local reference block of completed command
* @scsi_status: SCSI command status
@@ -5597,28 +5560,12 @@ out:
return err;
}
-/**
- * ufshcd_issue_tm_cmd - issues task management commands to controller
- * @hba: per adapter instance
- * @lun_id: LUN ID to which TM command is sent
- * @task_id: task ID to which the TM command is applicable
- * @tm_function: task management function opcode
- * @tm_response: task management service response return value
- *
- * Returns non-zero value on error, zero on success.
- */
-static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id,
- u8 tm_function, u8 *tm_response)
+static int __ufshcd_issue_tm_cmd(struct ufs_hba *hba,
+ struct utp_task_req_desc *treq, u8 tm_function)
{
- struct utp_task_req_desc *task_req_descp;
- struct utp_upiu_task_req *task_req_upiup;
- struct Scsi_Host *host;
+ struct Scsi_Host *host = hba->host;
unsigned long flags;
- int free_slot;
- int err;
- int task_tag;
-
- host = hba->host;
+ int free_slot, task_tag, err;
/*
* Get free slot, sleep if slots are unavailable.
@@ -5629,30 +5576,11 @@ static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id,
ufshcd_hold(hba, false);
spin_lock_irqsave(host->host_lock, flags);
- task_req_descp = hba->utmrdl_base_addr;
- task_req_descp += free_slot;
-
- /* Configure task request descriptor */
- task_req_descp->header.dword_0 = cpu_to_le32(UTP_REQ_DESC_INT_CMD);
- task_req_descp->header.dword_2 =
- cpu_to_le32(OCS_INVALID_COMMAND_STATUS);
-
- /* Configure task request UPIU */
- task_req_upiup =
- (struct utp_upiu_task_req *) task_req_descp->task_req_upiu;
task_tag = hba->nutrs + free_slot;
- task_req_upiup->header.dword_0 =
- UPIU_HEADER_DWORD(UPIU_TRANSACTION_TASK_REQ, 0,
- lun_id, task_tag);
- task_req_upiup->header.dword_1 =
- UPIU_HEADER_DWORD(0, tm_function, 0, 0);
- /*
- * The host shall provide the same value for LUN field in the basic
- * header and for Input Parameter.
- */
- task_req_upiup->input_param1 = cpu_to_be32(lun_id);
- task_req_upiup->input_param2 = cpu_to_be32(task_id);
+ treq->req_header.dword_0 |= cpu_to_be32(task_tag);
+
+ memcpy(hba->utmrdl_base_addr + free_slot, treq, sizeof(*treq));
ufshcd_vops_setup_task_mgmt(hba, free_slot, tm_function);
/* send command to the controller */
@@ -5682,8 +5610,15 @@ static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id,
__func__, free_slot);
err = -ETIMEDOUT;
} else {
- err = ufshcd_task_req_compl(hba, free_slot, tm_response);
+ err = 0;
+ memcpy(treq, hba->utmrdl_base_addr + free_slot, sizeof(*treq));
+
ufshcd_add_tm_upiu_trace(hba, task_tag, "tm_complete");
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ __clear_bit(free_slot, &hba->outstanding_tasks);
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+
}
clear_bit(free_slot, &hba->tm_condition);
@@ -5695,6 +5630,228 @@ static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id,
}
/**
+ * ufshcd_issue_tm_cmd - issues task management commands to controller
+ * @hba: per adapter instance
+ * @lun_id: LUN ID to which TM command is sent
+ * @task_id: task ID to which the TM command is applicable
+ * @tm_function: task management function opcode
+ * @tm_response: task management service response return value
+ *
+ * Returns non-zero value on error, zero on success.
+ */
+static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id,
+ u8 tm_function, u8 *tm_response)
+{
+ struct utp_task_req_desc treq = { { 0 }, };
+ int ocs_value, err;
+
+ /* Configure task request descriptor */
+ treq.header.dword_0 = cpu_to_le32(UTP_REQ_DESC_INT_CMD);
+ treq.header.dword_2 = cpu_to_le32(OCS_INVALID_COMMAND_STATUS);
+
+ /* Configure task request UPIU */
+ treq.req_header.dword_0 = cpu_to_be32(lun_id << 8) |
+ cpu_to_be32(UPIU_TRANSACTION_TASK_REQ << 24);
+ treq.req_header.dword_1 = cpu_to_be32(tm_function << 16);
+
+ /*
+ * The host shall provide the same value for LUN field in the basic
+ * header and for Input Parameter.
+ */
+ treq.input_param1 = cpu_to_be32(lun_id);
+ treq.input_param2 = cpu_to_be32(task_id);
+
+ err = __ufshcd_issue_tm_cmd(hba, &treq, tm_function);
+ if (err == -ETIMEDOUT)
+ return err;
+
+ ocs_value = le32_to_cpu(treq.header.dword_2) & MASK_OCS;
+ if (ocs_value != OCS_SUCCESS)
+ dev_err(hba->dev, "%s: failed, ocs = 0x%x\n",
+ __func__, ocs_value);
+ else if (tm_response)
+ *tm_response = be32_to_cpu(treq.output_param1) &
+ MASK_TM_SERVICE_RESP;
+ return err;
+}
+
+/**
+ * ufshcd_issue_devman_upiu_cmd - API for sending "utrd" type requests
+ * @hba: per-adapter instance
+ * @req_upiu: upiu request
+ * @rsp_upiu: upiu reply
+ * @msgcode: message code, one of UPIU Transaction Codes Initiator to Target
+ * @desc_buff: pointer to descriptor buffer, NULL if NA
+ * @buff_len: descriptor size, 0 if NA
+ * @desc_op: descriptor operation
+ *
+ * Those type of requests uses UTP Transfer Request Descriptor - utrd.
+ * Therefore, it "rides" the device management infrastructure: uses its tag and
+ * tasks work queues.
+ *
+ * Since there is only one available tag for device management commands,
+ * the caller is expected to hold the hba->dev_cmd.lock mutex.
+ */
+static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba,
+ struct utp_upiu_req *req_upiu,
+ struct utp_upiu_req *rsp_upiu,
+ u8 *desc_buff, int *buff_len,
+ int cmd_type,
+ enum query_opcode desc_op)
+{
+ struct ufshcd_lrb *lrbp;
+ int err = 0;
+ int tag;
+ struct completion wait;
+ unsigned long flags;
+ u32 upiu_flags;
+
+ down_read(&hba->clk_scaling_lock);
+
+ wait_event(hba->dev_cmd.tag_wq, ufshcd_get_dev_cmd_tag(hba, &tag));
+
+ init_completion(&wait);
+ lrbp = &hba->lrb[tag];
+ WARN_ON(lrbp->cmd);
+
+ lrbp->cmd = NULL;
+ lrbp->sense_bufflen = 0;
+ lrbp->sense_buffer = NULL;
+ lrbp->task_tag = tag;
+ lrbp->lun = 0;
+ lrbp->intr_cmd = true;
+ hba->dev_cmd.type = cmd_type;
+
+ switch (hba->ufs_version) {
+ case UFSHCI_VERSION_10:
+ case UFSHCI_VERSION_11:
+ lrbp->command_type = UTP_CMD_TYPE_DEV_MANAGE;
+ break;
+ default:
+ lrbp->command_type = UTP_CMD_TYPE_UFS_STORAGE;
+ break;
+ }
+
+ /* update the task tag in the request upiu */
+ req_upiu->header.dword_0 |= cpu_to_be32(tag);
+
+ ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags, DMA_NONE);
+
+ /* just copy the upiu request as it is */
+ memcpy(lrbp->ucd_req_ptr, req_upiu, sizeof(*lrbp->ucd_req_ptr));
+ if (desc_buff && desc_op == UPIU_QUERY_OPCODE_WRITE_DESC) {
+ /* The Data Segment Area is optional depending upon the query
+ * function value. for WRITE DESCRIPTOR, the data segment
+ * follows right after the tsf.
+ */
+ memcpy(lrbp->ucd_req_ptr + 1, desc_buff, *buff_len);
+ *buff_len = 0;
+ }
+
+ memset(lrbp->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp));
+
+ hba->dev_cmd.complete = &wait;
+
+ /* 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);
+
+ /*
+ * ignore the returning value here - ufshcd_check_query_response is
+ * bound to fail since dev_cmd.query and dev_cmd.type were left empty.
+ * read the response directly ignoring all errors.
+ */
+ ufshcd_wait_for_dev_cmd(hba, lrbp, QUERY_REQ_TIMEOUT);
+
+ /* just copy the upiu response as it is */
+ memcpy(rsp_upiu, lrbp->ucd_rsp_ptr, sizeof(*rsp_upiu));
+
+ ufshcd_put_dev_cmd_tag(hba, tag);
+ wake_up(&hba->dev_cmd.tag_wq);
+ up_read(&hba->clk_scaling_lock);
+ return err;
+}
+
+/**
+ * ufshcd_exec_raw_upiu_cmd - API function for sending raw upiu commands
+ * @hba: per-adapter instance
+ * @req_upiu: upiu request
+ * @rsp_upiu: upiu reply - only 8 DW as we do not support scsi commands
+ * @msgcode: message code, one of UPIU Transaction Codes Initiator to Target
+ * @desc_buff: pointer to descriptor buffer, NULL if NA
+ * @buff_len: descriptor size, 0 if NA
+ * @desc_op: descriptor operation
+ *
+ * Supports UTP Transfer requests (nop and query), and UTP Task
+ * Management requests.
+ * It is up to the caller to fill the upiu conent properly, as it will
+ * be copied without any further input validations.
+ */
+int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba,
+ struct utp_upiu_req *req_upiu,
+ struct utp_upiu_req *rsp_upiu,
+ int msgcode,
+ u8 *desc_buff, int *buff_len,
+ enum query_opcode desc_op)
+{
+ int err;
+ int cmd_type = DEV_CMD_TYPE_QUERY;
+ struct utp_task_req_desc treq = { { 0 }, };
+ int ocs_value;
+ u8 tm_f = be32_to_cpu(req_upiu->header.dword_1) >> 16 & MASK_TM_FUNC;
+
+ if (desc_buff && desc_op != UPIU_QUERY_OPCODE_WRITE_DESC) {
+ err = -ENOTSUPP;
+ goto out;
+ }
+
+ switch (msgcode) {
+ case UPIU_TRANSACTION_NOP_OUT:
+ cmd_type = DEV_CMD_TYPE_NOP;
+ /* fall through */
+ case UPIU_TRANSACTION_QUERY_REQ:
+ ufshcd_hold(hba, false);
+ mutex_lock(&hba->dev_cmd.lock);
+ err = ufshcd_issue_devman_upiu_cmd(hba, req_upiu, rsp_upiu,
+ desc_buff, buff_len,
+ cmd_type, desc_op);
+ mutex_unlock(&hba->dev_cmd.lock);
+ ufshcd_release(hba);
+
+ break;
+ case UPIU_TRANSACTION_TASK_REQ:
+ treq.header.dword_0 = cpu_to_le32(UTP_REQ_DESC_INT_CMD);
+ treq.header.dword_2 = cpu_to_le32(OCS_INVALID_COMMAND_STATUS);
+
+ memcpy(&treq.req_header, req_upiu, sizeof(*req_upiu));
+
+ err = __ufshcd_issue_tm_cmd(hba, &treq, tm_f);
+ if (err == -ETIMEDOUT)
+ break;
+
+ ocs_value = le32_to_cpu(treq.header.dword_2) & MASK_OCS;
+ if (ocs_value != OCS_SUCCESS) {
+ dev_err(hba->dev, "%s: failed, ocs = 0x%x\n", __func__,
+ ocs_value);
+ break;
+ }
+
+ memcpy(rsp_upiu, &treq.rsp_header, sizeof(*rsp_upiu));
+
+ break;
+ default:
+ err = -EINVAL;
+
+ break;
+ }
+
+out:
+ return err;
+}
+
+/**
* ufshcd_eh_device_reset_handler - device reset handler registered to
* scsi layer.
* @cmd: SCSI command pointer
@@ -6652,6 +6809,8 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
hba->clk_scaling.is_allowed = true;
}
+ ufs_bsg_probe(hba);
+
scsi_scan_host(hba->host);
pm_runtime_put_sync(hba->dev);
}
@@ -6666,6 +6825,7 @@ out:
*/
if (ret && !ufshcd_eh_in_progress(hba) && !hba->pm_op_in_progress) {
pm_runtime_put_sync(hba->dev);
+ ufshcd_exit_clk_scaling(hba);
ufshcd_hba_exit(hba);
}
@@ -7201,12 +7361,9 @@ static void ufshcd_hba_exit(struct ufs_hba *hba)
ufshcd_variant_hba_exit(hba);
ufshcd_setup_vreg(hba, false);
ufshcd_suspend_clkscaling(hba);
- if (ufshcd_is_clkscaling_supported(hba)) {
+ if (ufshcd_is_clkscaling_supported(hba))
if (hba->devfreq)
ufshcd_suspend_clkscaling(hba);
- destroy_workqueue(hba->clk_scaling.workq);
- ufshcd_devfreq_remove(hba);
- }
ufshcd_setup_clocks(hba, false);
ufshcd_setup_hba_vreg(hba, false);
hba->is_powered = false;
@@ -7875,12 +8032,14 @@ EXPORT_SYMBOL(ufshcd_shutdown);
*/
void ufshcd_remove(struct ufs_hba *hba)
{
+ ufs_bsg_remove(hba);
ufs_sysfs_remove_nodes(hba->dev);
scsi_remove_host(hba->host);
/* disable interrupts */
ufshcd_disable_intr(hba, hba->intr_mask);
ufshcd_hba_stop(hba, true);
+ ufshcd_exit_clk_scaling(hba);
ufshcd_exit_clk_gating(hba);
if (ufshcd_is_clkscaling_supported(hba))
device_remove_file(hba->dev, &hba->clk_scaling.enable_attr);
@@ -7940,13 +8099,6 @@ int ufshcd_alloc_host(struct device *dev, struct ufs_hba **hba_handle)
err = -ENOMEM;
goto out_error;
}
-
- /*
- * Do not use blk-mq at this time because blk-mq does not support
- * runtime pm.
- */
- host->use_blk_mq = false;
-
hba = shost_priv(host);
hba->host = host;
hba->dev = dev;
@@ -8027,7 +8179,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
host->max_lun = UFS_MAX_LUNS;
host->max_channel = UFSHCD_MAX_CHANNEL;
host->unique_id = host->host_no;
- host->max_cmd_len = MAX_CDB_SIZE;
+ host->max_cmd_len = UFS_CDB_SIZE;
hba->max_pwr_info.is_valid = false;
@@ -8052,6 +8204,8 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
ufshcd_init_clk_gating(hba);
+ ufshcd_init_clk_scaling(hba);
+
/*
* In order to avoid any spurious interrupt immediately after
* registering UFS controller interrupt handler, clear any pending UFS
@@ -8090,21 +8244,6 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
goto out_remove_scsi_host;
}
- if (ufshcd_is_clkscaling_supported(hba)) {
- char wq_name[sizeof("ufs_clkscaling_00")];
-
- INIT_WORK(&hba->clk_scaling.suspend_work,
- ufshcd_clk_scaling_suspend_work);
- INIT_WORK(&hba->clk_scaling.resume_work,
- ufshcd_clk_scaling_resume_work);
-
- snprintf(wq_name, sizeof(wq_name), "ufs_clkscaling_%d",
- host->host_no);
- hba->clk_scaling.workq = create_singlethread_workqueue(wq_name);
-
- ufshcd_clkscaling_init_sysfs(hba);
- }
-
/*
* Set the default power management level for runtime and system PM.
* Default power saving mode is to keep UFS link in Hibern8 state
@@ -8142,6 +8281,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
out_remove_scsi_host:
scsi_remove_host(hba->host);
exit_gating:
+ ufshcd_exit_clk_scaling(hba);
ufshcd_exit_clk_gating(hba);
out_disable:
hba->is_irq_enabled = false;
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 33fdd3f281ae..1a1c2b487a4e 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -702,6 +702,9 @@ struct ufs_hba {
struct rw_semaphore clk_scaling_lock;
struct ufs_desc_size desc_size;
atomic_t scsi_block_reqs_cnt;
+
+ struct device bsg_dev;
+ struct request_queue *bsg_queue;
};
/* Returns true if clocks can be gated. Otherwise false */
@@ -892,6 +895,15 @@ int ufshcd_map_desc_id_to_length(struct ufs_hba *hba, enum desc_idn desc_id,
u32 ufshcd_get_local_unipro_ver(struct ufs_hba *hba);
+int ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd);
+
+int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba,
+ struct utp_upiu_req *req_upiu,
+ struct utp_upiu_req *rsp_upiu,
+ int msgcode,
+ u8 *desc_buff, int *buff_len,
+ enum query_opcode desc_op);
+
/* Wrapper functions for safely calling variant operations */
static inline const char *ufshcd_get_var_name(struct ufs_hba *hba)
{
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index bb5d9c7f3353..6fa889de5ee5 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -433,22 +433,25 @@ struct utp_transfer_req_desc {
__le16 prd_table_offset;
};
-/**
- * struct utp_task_req_desc - UTMRD structure
- * @header: UTMRD header DW-0 to DW-3
- * @task_req_upiu: Pointer to task request UPIU DW-4 to DW-11
- * @task_rsp_upiu: Pointer to task response UPIU DW12 to DW-19
+/*
+ * UTMRD structure.
*/
struct utp_task_req_desc {
-
/* DW 0-3 */
struct request_desc_header header;
- /* DW 4-11 */
- __le32 task_req_upiu[TASK_REQ_UPIU_SIZE_DWORDS];
-
- /* DW 12-19 */
- __le32 task_rsp_upiu[TASK_RSP_UPIU_SIZE_DWORDS];
+ /* DW 4-11 - Task request UPIU structure */
+ struct utp_upiu_header req_header;
+ __be32 input_param1;
+ __be32 input_param2;
+ __be32 input_param3;
+ __be32 __reserved1[2];
+
+ /* DW 12-19 - Task Management Response UPIU structure */
+ struct utp_upiu_header rsp_header;
+ __be32 output_param1;
+ __be32 output_param2;
+ __be32 __reserved2[3];
};
#endif /* End of Header */
diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c
index 0cd947f78b5b..6e491023fdd8 100644
--- a/drivers/scsi/vmw_pvscsi.c
+++ b/drivers/scsi/vmw_pvscsi.c
@@ -372,9 +372,9 @@ static int pvscsi_map_buffers(struct pvscsi_adapter *adapter,
pvscsi_create_sg(ctx, sg, segs);
e->flags |= PVSCSI_FLAG_CMD_WITH_SG_LIST;
- ctx->sglPA = pci_map_single(adapter->dev, ctx->sgl,
- SGL_SIZE, PCI_DMA_TODEVICE);
- if (pci_dma_mapping_error(adapter->dev, ctx->sglPA)) {
+ ctx->sglPA = dma_map_single(&adapter->dev->dev,
+ ctx->sgl, SGL_SIZE, DMA_TO_DEVICE);
+ if (dma_mapping_error(&adapter->dev->dev, ctx->sglPA)) {
scmd_printk(KERN_ERR, cmd,
"vmw_pvscsi: Failed to map ctx sglist for DMA.\n");
scsi_dma_unmap(cmd);
@@ -389,9 +389,9 @@ static int pvscsi_map_buffers(struct pvscsi_adapter *adapter,
* In case there is no S/G list, scsi_sglist points
* directly to the buffer.
*/
- ctx->dataPA = pci_map_single(adapter->dev, sg, bufflen,
+ ctx->dataPA = dma_map_single(&adapter->dev->dev, sg, bufflen,
cmd->sc_data_direction);
- if (pci_dma_mapping_error(adapter->dev, ctx->dataPA)) {
+ if (dma_mapping_error(&adapter->dev->dev, ctx->dataPA)) {
scmd_printk(KERN_ERR, cmd,
"vmw_pvscsi: Failed to map direct data buffer for DMA.\n");
return -ENOMEM;
@@ -417,23 +417,23 @@ static void pvscsi_unmap_buffers(const struct pvscsi_adapter *adapter,
if (count != 0) {
scsi_dma_unmap(cmd);
if (ctx->sglPA) {
- pci_unmap_single(adapter->dev, ctx->sglPA,
- SGL_SIZE, PCI_DMA_TODEVICE);
+ dma_unmap_single(&adapter->dev->dev, ctx->sglPA,
+ SGL_SIZE, DMA_TO_DEVICE);
ctx->sglPA = 0;
}
} else
- pci_unmap_single(adapter->dev, ctx->dataPA, bufflen,
- cmd->sc_data_direction);
+ dma_unmap_single(&adapter->dev->dev, ctx->dataPA,
+ bufflen, cmd->sc_data_direction);
}
if (cmd->sense_buffer)
- pci_unmap_single(adapter->dev, ctx->sensePA,
- SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE);
+ dma_unmap_single(&adapter->dev->dev, ctx->sensePA,
+ SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
}
static int pvscsi_allocate_rings(struct pvscsi_adapter *adapter)
{
- adapter->rings_state = pci_alloc_consistent(adapter->dev, PAGE_SIZE,
- &adapter->ringStatePA);
+ adapter->rings_state = dma_alloc_coherent(&adapter->dev->dev, PAGE_SIZE,
+ &adapter->ringStatePA, GFP_KERNEL);
if (!adapter->rings_state)
return -ENOMEM;
@@ -441,17 +441,17 @@ static int pvscsi_allocate_rings(struct pvscsi_adapter *adapter)
pvscsi_ring_pages);
adapter->req_depth = adapter->req_pages
* PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE;
- adapter->req_ring = pci_alloc_consistent(adapter->dev,
- adapter->req_pages * PAGE_SIZE,
- &adapter->reqRingPA);
+ adapter->req_ring = dma_alloc_coherent(&adapter->dev->dev,
+ adapter->req_pages * PAGE_SIZE, &adapter->reqRingPA,
+ GFP_KERNEL);
if (!adapter->req_ring)
return -ENOMEM;
adapter->cmp_pages = min(PVSCSI_MAX_NUM_PAGES_CMP_RING,
pvscsi_ring_pages);
- adapter->cmp_ring = pci_alloc_consistent(adapter->dev,
- adapter->cmp_pages * PAGE_SIZE,
- &adapter->cmpRingPA);
+ adapter->cmp_ring = dma_alloc_coherent(&adapter->dev->dev,
+ adapter->cmp_pages * PAGE_SIZE, &adapter->cmpRingPA,
+ GFP_KERNEL);
if (!adapter->cmp_ring)
return -ENOMEM;
@@ -464,9 +464,9 @@ static int pvscsi_allocate_rings(struct pvscsi_adapter *adapter)
adapter->msg_pages = min(PVSCSI_MAX_NUM_PAGES_MSG_RING,
pvscsi_msg_ring_pages);
- adapter->msg_ring = pci_alloc_consistent(adapter->dev,
- adapter->msg_pages * PAGE_SIZE,
- &adapter->msgRingPA);
+ adapter->msg_ring = dma_alloc_coherent(&adapter->dev->dev,
+ adapter->msg_pages * PAGE_SIZE, &adapter->msgRingPA,
+ GFP_KERNEL);
if (!adapter->msg_ring)
return -ENOMEM;
BUG_ON(!IS_ALIGNED(adapter->msgRingPA, PAGE_SIZE));
@@ -708,10 +708,10 @@ static int pvscsi_queue_ring(struct pvscsi_adapter *adapter,
e->lun[1] = sdev->lun;
if (cmd->sense_buffer) {
- ctx->sensePA = pci_map_single(adapter->dev, cmd->sense_buffer,
- SCSI_SENSE_BUFFERSIZE,
- PCI_DMA_FROMDEVICE);
- if (pci_dma_mapping_error(adapter->dev, ctx->sensePA)) {
+ ctx->sensePA = dma_map_single(&adapter->dev->dev,
+ cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(&adapter->dev->dev, ctx->sensePA)) {
scmd_printk(KERN_ERR, cmd,
"vmw_pvscsi: Failed to map sense buffer for DMA.\n");
ctx->sensePA = 0;
@@ -740,9 +740,9 @@ static int pvscsi_queue_ring(struct pvscsi_adapter *adapter,
if (pvscsi_map_buffers(adapter, ctx, cmd, e) != 0) {
if (cmd->sense_buffer) {
- pci_unmap_single(adapter->dev, ctx->sensePA,
+ dma_unmap_single(&adapter->dev->dev, ctx->sensePA,
SCSI_SENSE_BUFFERSIZE,
- PCI_DMA_FROMDEVICE);
+ DMA_FROM_DEVICE);
ctx->sensePA = 0;
}
return -ENOMEM;
@@ -1218,21 +1218,21 @@ static void pvscsi_release_resources(struct pvscsi_adapter *adapter)
}
if (adapter->rings_state)
- pci_free_consistent(adapter->dev, PAGE_SIZE,
+ dma_free_coherent(&adapter->dev->dev, PAGE_SIZE,
adapter->rings_state, adapter->ringStatePA);
if (adapter->req_ring)
- pci_free_consistent(adapter->dev,
+ dma_free_coherent(&adapter->dev->dev,
adapter->req_pages * PAGE_SIZE,
adapter->req_ring, adapter->reqRingPA);
if (adapter->cmp_ring)
- pci_free_consistent(adapter->dev,
+ dma_free_coherent(&adapter->dev->dev,
adapter->cmp_pages * PAGE_SIZE,
adapter->cmp_ring, adapter->cmpRingPA);
if (adapter->msg_ring)
- pci_free_consistent(adapter->dev,
+ dma_free_coherent(&adapter->dev->dev,
adapter->msg_pages * PAGE_SIZE,
adapter->msg_ring, adapter->msgRingPA);
}
@@ -1291,8 +1291,8 @@ static u32 pvscsi_get_max_targets(struct pvscsi_adapter *adapter)
u32 numPhys = 16;
dev = pvscsi_dev(adapter);
- config_page = pci_alloc_consistent(adapter->dev, PAGE_SIZE,
- &configPagePA);
+ config_page = dma_alloc_coherent(&adapter->dev->dev, PAGE_SIZE,
+ &configPagePA, GFP_KERNEL);
if (!config_page) {
dev_warn(dev, "vmw_pvscsi: failed to allocate memory for config page\n");
goto exit;
@@ -1326,7 +1326,8 @@ static u32 pvscsi_get_max_targets(struct pvscsi_adapter *adapter)
} else
dev_warn(dev, "vmw_pvscsi: PVSCSI_CMD_CONFIG failed. hostStatus = 0x%x, scsiStatus = 0x%x\n",
header->hostStatus, header->scsiStatus);
- pci_free_consistent(adapter->dev, PAGE_SIZE, config_page, configPagePA);
+ dma_free_coherent(&adapter->dev->dev, PAGE_SIZE, config_page,
+ configPagePA);
exit:
return numPhys;
}
@@ -1346,11 +1347,9 @@ static int pvscsi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (pci_enable_device(pdev))
return error;
- if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) == 0 &&
- pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) == 0) {
+ if (!dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64))) {
printk(KERN_INFO "vmw_pvscsi: using 64bit dma\n");
- } else if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) == 0 &&
- pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)) == 0) {
+ } else if (!dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32))) {
printk(KERN_INFO "vmw_pvscsi: using 32bit dma\n");
} else {
printk(KERN_ERR "vmw_pvscsi: failed to set DMA mask\n");
diff --git a/drivers/scsi/zorro_esp.c b/drivers/scsi/zorro_esp.c
index bb70882e6b56..ca8e3abeb2c7 100644
--- a/drivers/scsi/zorro_esp.c
+++ b/drivers/scsi/zorro_esp.c
@@ -9,8 +9,6 @@
*
* Copyright (C) 2013 Tuomas Vainikka (tuomas.vainikka@aalto.fi) for
* Blizzard 1230 DMA and probe function fixes
- *
- * Copyright (C) 2017 Finn Thain for PIO code from Mac ESP driver adapted here
*/
/*
* ZORRO bus code from:
@@ -159,7 +157,6 @@ struct fastlane_dma_registers {
struct zorro_esp_priv {
struct esp *esp; /* our ESP instance - for Scsi_host* */
void __iomem *board_base; /* virtual address (Zorro III board) */
- int error; /* PIO error flag */
int zorro3; /* board is Zorro III */
unsigned char ctrl_data; /* shadow copy of ctrl_reg */
};
@@ -182,30 +179,6 @@ static u8 zorro_esp_read8(struct esp *esp, unsigned long reg)
return readb(esp->regs + (reg * 4UL));
}
-static dma_addr_t zorro_esp_map_single(struct esp *esp, void *buf,
- size_t sz, int dir)
-{
- return dma_map_single(esp->dev, buf, sz, dir);
-}
-
-static int zorro_esp_map_sg(struct esp *esp, struct scatterlist *sg,
- int num_sg, int dir)
-{
- return dma_map_sg(esp->dev, sg, num_sg, dir);
-}
-
-static void zorro_esp_unmap_single(struct esp *esp, dma_addr_t addr,
- size_t sz, int dir)
-{
- dma_unmap_single(esp->dev, addr, sz, dir);
-}
-
-static void zorro_esp_unmap_sg(struct esp *esp, struct scatterlist *sg,
- int num_sg, int dir)
-{
- dma_unmap_sg(esp->dev, sg, num_sg, dir);
-}
-
static int zorro_esp_irq_pending(struct esp *esp)
{
/* check ESP status register; DMA has no status reg. */
@@ -245,7 +218,7 @@ static int fastlane_esp_irq_pending(struct esp *esp)
static u32 zorro_esp_dma_length_limit(struct esp *esp, u32 dma_addr,
u32 dma_len)
{
- return dma_len > 0xFFFFFF ? 0xFFFFFF : dma_len;
+ return dma_len > 0xFFFF ? 0xFFFF : dma_len;
}
static void zorro_esp_reset_dma(struct esp *esp)
@@ -274,192 +247,29 @@ static void fastlane_esp_dma_invalidate(struct esp *esp)
z_writel(0, zep->board_base);
}
-/*
- * Programmed IO routines follow.
- */
-
-static inline unsigned int zorro_esp_wait_for_fifo(struct esp *esp)
-{
- int i = 500000;
-
- do {
- unsigned int fbytes = zorro_esp_read8(esp, ESP_FFLAGS)
- & ESP_FF_FBYTES;
-
- if (fbytes)
- return fbytes;
-
- udelay(2);
- } while (--i);
-
- pr_err("FIFO is empty (sreg %02x)\n",
- zorro_esp_read8(esp, ESP_STATUS));
- return 0;
-}
-
-static inline int zorro_esp_wait_for_intr(struct esp *esp)
-{
- struct zorro_esp_priv *zep = dev_get_drvdata(esp->dev);
- int i = 500000;
-
- do {
- esp->sreg = zorro_esp_read8(esp, ESP_STATUS);
- if (esp->sreg & ESP_STAT_INTR)
- return 0;
-
- udelay(2);
- } while (--i);
-
- pr_err("IRQ timeout (sreg %02x)\n", esp->sreg);
- zep->error = 1;
- return 1;
-}
-
-/*
- * PIO macros as used in mac_esp.c.
- * Note that addr and fifo arguments are local-scope variables declared
- * in zorro_esp_send_pio_cmd(), the macros are only used in that function,
- * and addr and fifo are referenced in each use of the macros so there
- * is no need to pass them as macro parameters.
- */
-#define ZORRO_ESP_PIO_LOOP(operands, reg1) \
- asm volatile ( \
- "1: moveb " operands "\n" \
- " subqw #1,%1 \n" \
- " jbne 1b \n" \
- : "+a" (addr), "+r" (reg1) \
- : "a" (fifo));
-
-#define ZORRO_ESP_PIO_FILL(operands, reg1) \
- asm volatile ( \
- " moveb " operands "\n" \
- " moveb " operands "\n" \
- " moveb " operands "\n" \
- " moveb " operands "\n" \
- " moveb " operands "\n" \
- " moveb " operands "\n" \
- " moveb " operands "\n" \
- " moveb " operands "\n" \
- " moveb " operands "\n" \
- " moveb " operands "\n" \
- " moveb " operands "\n" \
- " moveb " operands "\n" \
- " moveb " operands "\n" \
- " moveb " operands "\n" \
- " moveb " operands "\n" \
- " moveb " operands "\n" \
- " subqw #8,%1 \n" \
- " subqw #8,%1 \n" \
- : "+a" (addr), "+r" (reg1) \
- : "a" (fifo));
-
-#define ZORRO_ESP_FIFO_SIZE 16
-
-static void zorro_esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count,
- u32 dma_count, int write, u8 cmd)
-{
- struct zorro_esp_priv *zep = dev_get_drvdata(esp->dev);
- u8 __iomem *fifo = esp->regs + ESP_FDATA * 16;
- u8 phase = esp->sreg & ESP_STAT_PMASK;
-
- cmd &= ~ESP_CMD_DMA;
-
- if (write) {
- u8 *dst = (u8 *)addr;
- u8 mask = ~(phase == ESP_MIP ? ESP_INTR_FDONE : ESP_INTR_BSERV);
-
- scsi_esp_cmd(esp, cmd);
-
- while (1) {
- if (!zorro_esp_wait_for_fifo(esp))
- break;
-
- *dst++ = zorro_esp_read8(esp, ESP_FDATA);
- --esp_count;
-
- if (!esp_count)
- break;
-
- if (zorro_esp_wait_for_intr(esp))
- break;
-
- if ((esp->sreg & ESP_STAT_PMASK) != phase)
- break;
-
- esp->ireg = zorro_esp_read8(esp, ESP_INTRPT);
- if (esp->ireg & mask) {
- zep->error = 1;
- break;
- }
-
- if (phase == ESP_MIP)
- scsi_esp_cmd(esp, ESP_CMD_MOK);
-
- scsi_esp_cmd(esp, ESP_CMD_TI);
- }
- } else { /* unused, as long as we only handle MIP here */
- scsi_esp_cmd(esp, ESP_CMD_FLUSH);
-
- if (esp_count >= ZORRO_ESP_FIFO_SIZE)
- ZORRO_ESP_PIO_FILL("%0@+,%2@", esp_count)
- else
- ZORRO_ESP_PIO_LOOP("%0@+,%2@", esp_count)
-
- scsi_esp_cmd(esp, cmd);
-
- while (esp_count) {
- unsigned int n;
-
- if (zorro_esp_wait_for_intr(esp))
- break;
-
- if ((esp->sreg & ESP_STAT_PMASK) != phase)
- break;
-
- esp->ireg = zorro_esp_read8(esp, ESP_INTRPT);
- if (esp->ireg & ~ESP_INTR_BSERV) {
- zep->error = 1;
- break;
- }
-
- n = ZORRO_ESP_FIFO_SIZE -
- (zorro_esp_read8(esp, ESP_FFLAGS) & ESP_FF_FBYTES);
- if (n > esp_count)
- n = esp_count;
-
- if (n == ZORRO_ESP_FIFO_SIZE)
- ZORRO_ESP_PIO_FILL("%0@+,%2@", esp_count)
- else {
- esp_count -= n;
- ZORRO_ESP_PIO_LOOP("%0@+,%2@", n)
- }
-
- scsi_esp_cmd(esp, ESP_CMD_TI);
- }
- }
-}
-
/* Blizzard 1230/60 SCSI-IV DMA */
static void zorro_esp_send_blz1230_dma_cmd(struct esp *esp, u32 addr,
u32 esp_count, u32 dma_count, int write, u8 cmd)
{
- struct zorro_esp_priv *zep = dev_get_drvdata(esp->dev);
struct blz1230_dma_registers __iomem *dregs = esp->dma_regs;
u8 phase = esp->sreg & ESP_STAT_PMASK;
- zep->error = 0;
/*
* Use PIO if transferring message bytes to esp->command_block_dma.
* PIO requires a virtual address, so substitute esp->command_block
* for addr.
*/
if (phase == ESP_MIP && addr == esp->command_block_dma) {
- zorro_esp_send_pio_cmd(esp, (u32) esp->command_block,
- esp_count, dma_count, write, cmd);
+ esp_send_pio_cmd(esp, (u32)esp->command_block, esp_count,
+ dma_count, write, cmd);
return;
}
+ /* Clear the results of a possible prior esp->ops->send_dma_cmd() */
+ esp->send_cmd_error = 0;
+ esp->send_cmd_residual = 0;
+
if (write)
/* DMA receive */
dma_sync_single_for_device(esp->dev, addr, esp_count,
@@ -484,7 +294,6 @@ static void zorro_esp_send_blz1230_dma_cmd(struct esp *esp, u32 addr,
scsi_esp_cmd(esp, ESP_CMD_DMA);
zorro_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW);
zorro_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED);
- zorro_esp_write8(esp, (esp_count >> 16) & 0xff, ESP_TCHI);
scsi_esp_cmd(esp, cmd);
}
@@ -494,18 +303,19 @@ static void zorro_esp_send_blz1230_dma_cmd(struct esp *esp, u32 addr,
static void zorro_esp_send_blz1230II_dma_cmd(struct esp *esp, u32 addr,
u32 esp_count, u32 dma_count, int write, u8 cmd)
{
- struct zorro_esp_priv *zep = dev_get_drvdata(esp->dev);
struct blz1230II_dma_registers __iomem *dregs = esp->dma_regs;
u8 phase = esp->sreg & ESP_STAT_PMASK;
- zep->error = 0;
/* Use PIO if transferring message bytes to esp->command_block_dma */
if (phase == ESP_MIP && addr == esp->command_block_dma) {
- zorro_esp_send_pio_cmd(esp, (u32) esp->command_block,
- esp_count, dma_count, write, cmd);
+ esp_send_pio_cmd(esp, (u32)esp->command_block, esp_count,
+ dma_count, write, cmd);
return;
}
+ esp->send_cmd_error = 0;
+ esp->send_cmd_residual = 0;
+
if (write)
/* DMA receive */
dma_sync_single_for_device(esp->dev, addr, esp_count,
@@ -529,7 +339,6 @@ static void zorro_esp_send_blz1230II_dma_cmd(struct esp *esp, u32 addr,
scsi_esp_cmd(esp, ESP_CMD_DMA);
zorro_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW);
zorro_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED);
- zorro_esp_write8(esp, (esp_count >> 16) & 0xff, ESP_TCHI);
scsi_esp_cmd(esp, cmd);
}
@@ -539,18 +348,19 @@ static void zorro_esp_send_blz1230II_dma_cmd(struct esp *esp, u32 addr,
static void zorro_esp_send_blz2060_dma_cmd(struct esp *esp, u32 addr,
u32 esp_count, u32 dma_count, int write, u8 cmd)
{
- struct zorro_esp_priv *zep = dev_get_drvdata(esp->dev);
struct blz2060_dma_registers __iomem *dregs = esp->dma_regs;
u8 phase = esp->sreg & ESP_STAT_PMASK;
- zep->error = 0;
/* Use PIO if transferring message bytes to esp->command_block_dma */
if (phase == ESP_MIP && addr == esp->command_block_dma) {
- zorro_esp_send_pio_cmd(esp, (u32) esp->command_block,
- esp_count, dma_count, write, cmd);
+ esp_send_pio_cmd(esp, (u32)esp->command_block, esp_count,
+ dma_count, write, cmd);
return;
}
+ esp->send_cmd_error = 0;
+ esp->send_cmd_residual = 0;
+
if (write)
/* DMA receive */
dma_sync_single_for_device(esp->dev, addr, esp_count,
@@ -574,7 +384,6 @@ static void zorro_esp_send_blz2060_dma_cmd(struct esp *esp, u32 addr,
scsi_esp_cmd(esp, ESP_CMD_DMA);
zorro_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW);
zorro_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED);
- zorro_esp_write8(esp, (esp_count >> 16) & 0xff, ESP_TCHI);
scsi_esp_cmd(esp, cmd);
}
@@ -589,17 +398,18 @@ static void zorro_esp_send_cyber_dma_cmd(struct esp *esp, u32 addr,
u8 phase = esp->sreg & ESP_STAT_PMASK;
unsigned char *ctrl_data = &zep->ctrl_data;
- zep->error = 0;
/* Use PIO if transferring message bytes to esp->command_block_dma */
if (phase == ESP_MIP && addr == esp->command_block_dma) {
- zorro_esp_send_pio_cmd(esp, (u32) esp->command_block,
- esp_count, dma_count, write, cmd);
+ esp_send_pio_cmd(esp, (u32)esp->command_block, esp_count,
+ dma_count, write, cmd);
return;
}
+ esp->send_cmd_error = 0;
+ esp->send_cmd_residual = 0;
+
zorro_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW);
zorro_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED);
- zorro_esp_write8(esp, (esp_count >> 16) & 0xff, ESP_TCHI);
if (write) {
/* DMA receive */
@@ -635,21 +445,21 @@ static void zorro_esp_send_cyber_dma_cmd(struct esp *esp, u32 addr,
static void zorro_esp_send_cyberII_dma_cmd(struct esp *esp, u32 addr,
u32 esp_count, u32 dma_count, int write, u8 cmd)
{
- struct zorro_esp_priv *zep = dev_get_drvdata(esp->dev);
struct cyberII_dma_registers __iomem *dregs = esp->dma_regs;
u8 phase = esp->sreg & ESP_STAT_PMASK;
- zep->error = 0;
/* Use PIO if transferring message bytes to esp->command_block_dma */
if (phase == ESP_MIP && addr == esp->command_block_dma) {
- zorro_esp_send_pio_cmd(esp, (u32) esp->command_block,
- esp_count, dma_count, write, cmd);
+ esp_send_pio_cmd(esp, (u32)esp->command_block, esp_count,
+ dma_count, write, cmd);
return;
}
+ esp->send_cmd_error = 0;
+ esp->send_cmd_residual = 0;
+
zorro_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW);
zorro_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED);
- zorro_esp_write8(esp, (esp_count >> 16) & 0xff, ESP_TCHI);
if (write) {
/* DMA receive */
@@ -681,17 +491,18 @@ static void zorro_esp_send_fastlane_dma_cmd(struct esp *esp, u32 addr,
u8 phase = esp->sreg & ESP_STAT_PMASK;
unsigned char *ctrl_data = &zep->ctrl_data;
- zep->error = 0;
/* Use PIO if transferring message bytes to esp->command_block_dma */
if (phase == ESP_MIP && addr == esp->command_block_dma) {
- zorro_esp_send_pio_cmd(esp, (u32) esp->command_block,
- esp_count, dma_count, write, cmd);
+ esp_send_pio_cmd(esp, (u32)esp->command_block, esp_count,
+ dma_count, write, cmd);
return;
}
+ esp->send_cmd_error = 0;
+ esp->send_cmd_residual = 0;
+
zorro_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW);
zorro_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED);
- zorro_esp_write8(esp, (esp_count >> 16) & 0xff, ESP_TCHI);
if (write) {
/* DMA receive */
@@ -724,14 +535,7 @@ static void zorro_esp_send_fastlane_dma_cmd(struct esp *esp, u32 addr,
static int zorro_esp_dma_error(struct esp *esp)
{
- struct zorro_esp_priv *zep = dev_get_drvdata(esp->dev);
-
- /* check for error in case we've been doing PIO */
- if (zep->error == 1)
- return 1;
-
- /* do nothing - there seems to be no way to check for DMA errors */
- return 0;
+ return esp->send_cmd_error;
}
/* per-board ESP driver ops */
@@ -739,10 +543,6 @@ static int zorro_esp_dma_error(struct esp *esp)
static const struct esp_driver_ops blz1230_esp_ops = {
.esp_write8 = zorro_esp_write8,
.esp_read8 = zorro_esp_read8,
- .map_single = zorro_esp_map_single,
- .map_sg = zorro_esp_map_sg,
- .unmap_single = zorro_esp_unmap_single,
- .unmap_sg = zorro_esp_unmap_sg,
.irq_pending = zorro_esp_irq_pending,
.dma_length_limit = zorro_esp_dma_length_limit,
.reset_dma = zorro_esp_reset_dma,
@@ -755,10 +555,6 @@ static const struct esp_driver_ops blz1230_esp_ops = {
static const struct esp_driver_ops blz1230II_esp_ops = {
.esp_write8 = zorro_esp_write8,
.esp_read8 = zorro_esp_read8,
- .map_single = zorro_esp_map_single,
- .map_sg = zorro_esp_map_sg,
- .unmap_single = zorro_esp_unmap_single,
- .unmap_sg = zorro_esp_unmap_sg,
.irq_pending = zorro_esp_irq_pending,
.dma_length_limit = zorro_esp_dma_length_limit,
.reset_dma = zorro_esp_reset_dma,
@@ -771,10 +567,6 @@ static const struct esp_driver_ops blz1230II_esp_ops = {
static const struct esp_driver_ops blz2060_esp_ops = {
.esp_write8 = zorro_esp_write8,
.esp_read8 = zorro_esp_read8,
- .map_single = zorro_esp_map_single,
- .map_sg = zorro_esp_map_sg,
- .unmap_single = zorro_esp_unmap_single,
- .unmap_sg = zorro_esp_unmap_sg,
.irq_pending = zorro_esp_irq_pending,
.dma_length_limit = zorro_esp_dma_length_limit,
.reset_dma = zorro_esp_reset_dma,
@@ -787,10 +579,6 @@ static const struct esp_driver_ops blz2060_esp_ops = {
static const struct esp_driver_ops cyber_esp_ops = {
.esp_write8 = zorro_esp_write8,
.esp_read8 = zorro_esp_read8,
- .map_single = zorro_esp_map_single,
- .map_sg = zorro_esp_map_sg,
- .unmap_single = zorro_esp_unmap_single,
- .unmap_sg = zorro_esp_unmap_sg,
.irq_pending = cyber_esp_irq_pending,
.dma_length_limit = zorro_esp_dma_length_limit,
.reset_dma = zorro_esp_reset_dma,
@@ -803,10 +591,6 @@ static const struct esp_driver_ops cyber_esp_ops = {
static const struct esp_driver_ops cyberII_esp_ops = {
.esp_write8 = zorro_esp_write8,
.esp_read8 = zorro_esp_read8,
- .map_single = zorro_esp_map_single,
- .map_sg = zorro_esp_map_sg,
- .unmap_single = zorro_esp_unmap_single,
- .unmap_sg = zorro_esp_unmap_sg,
.irq_pending = zorro_esp_irq_pending,
.dma_length_limit = zorro_esp_dma_length_limit,
.reset_dma = zorro_esp_reset_dma,
@@ -819,10 +603,6 @@ static const struct esp_driver_ops cyberII_esp_ops = {
static const struct esp_driver_ops fastlane_esp_ops = {
.esp_write8 = zorro_esp_write8,
.esp_read8 = zorro_esp_read8,
- .map_single = zorro_esp_map_single,
- .map_sg = zorro_esp_map_sg,
- .unmap_single = zorro_esp_unmap_single,
- .unmap_sg = zorro_esp_unmap_sg,
.irq_pending = fastlane_esp_irq_pending,
.dma_length_limit = zorro_esp_dma_length_limit,
.reset_dma = zorro_esp_reset_dma,
@@ -1039,6 +819,8 @@ static int zorro_esp_probe(struct zorro_dev *z,
goto fail_unmap_fastlane;
}
+ esp->fifo_reg = esp->regs + ESP_FDATA * 4;
+
/* Check whether a Blizzard 12x0 or CyberstormII really has SCSI */
if (zdd->scsi_option) {
zorro_esp_write8(esp, (ESP_CONFIG1_PENABLE | 7), ESP_CFG1);
@@ -1082,7 +864,7 @@ static int zorro_esp_probe(struct zorro_dev *z,
}
/* register the chip */
- err = scsi_esp_register(esp, &z->dev);
+ err = scsi_esp_register(esp);
if (err) {
err = -ENOMEM;
diff --git a/drivers/sfi/sfi_core.c b/drivers/sfi/sfi_core.c
index 153b3f3cc795..a5136901dd8a 100644
--- a/drivers/sfi/sfi_core.c
+++ b/drivers/sfi/sfi_core.c
@@ -59,7 +59,7 @@
#define KMSG_COMPONENT "SFI"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
-#include <linux/bootmem.h>
+#include <linux/memblock.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
diff --git a/drivers/slimbus/core.c b/drivers/slimbus/core.c
index 95b00d28ad6e..55eda5863a6b 100644
--- a/drivers/slimbus/core.c
+++ b/drivers/slimbus/core.c
@@ -9,6 +9,7 @@
#include <linux/init.h>
#include <linux/idr.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include <linux/slimbus.h>
#include "slimbus.h"
@@ -32,6 +33,10 @@ static int slim_device_match(struct device *dev, struct device_driver *drv)
struct slim_device *sbdev = to_slim_device(dev);
struct slim_driver *sbdrv = to_slim_driver(drv);
+ /* Attempt an OF style match first */
+ if (of_driver_match_device(dev, drv))
+ return 1;
+
return !!slim_match(sbdrv->id_table, sbdev);
}
@@ -39,8 +44,23 @@ static int slim_device_probe(struct device *dev)
{
struct slim_device *sbdev = to_slim_device(dev);
struct slim_driver *sbdrv = to_slim_driver(dev->driver);
+ int ret;
- return sbdrv->probe(sbdev);
+ ret = sbdrv->probe(sbdev);
+ if (ret)
+ return ret;
+
+ /* try getting the logical address after probe */
+ ret = slim_get_logical_addr(sbdev);
+ if (!ret) {
+ if (sbdrv->device_status)
+ sbdrv->device_status(sbdev, sbdev->status);
+ } else {
+ dev_err(&sbdev->dev, "Failed to get logical address\n");
+ ret = -EPROBE_DEFER;
+ }
+
+ return ret;
}
static int slim_device_remove(struct device *dev)
@@ -57,11 +77,24 @@ static int slim_device_remove(struct device *dev)
return 0;
}
+static int slim_device_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ struct slim_device *sbdev = to_slim_device(dev);
+ int ret;
+
+ ret = of_device_uevent_modalias(dev, env);
+ if (ret != -ENODEV)
+ return ret;
+
+ return add_uevent_var(env, "MODALIAS=slim:%s", dev_name(&sbdev->dev));
+}
+
struct bus_type slimbus_bus = {
.name = "slimbus",
.match = slim_device_match,
.probe = slim_device_probe,
.remove = slim_device_remove,
+ .uevent = slim_device_uevent,
};
EXPORT_SYMBOL_GPL(slimbus_bus);
@@ -77,7 +110,7 @@ EXPORT_SYMBOL_GPL(slimbus_bus);
int __slim_driver_register(struct slim_driver *drv, struct module *owner)
{
/* ID table and probe are mandatory */
- if (!drv->id_table || !drv->probe)
+ if (!(drv->driver.of_match_table || drv->id_table) || !drv->probe)
return -EINVAL;
drv->driver.bus = &slimbus_bus;
diff --git a/drivers/slimbus/qcom-ngd-ctrl.c b/drivers/slimbus/qcom-ngd-ctrl.c
index 8be4d6786c61..7218fb963d0a 100644
--- a/drivers/slimbus/qcom-ngd-ctrl.c
+++ b/drivers/slimbus/qcom-ngd-ctrl.c
@@ -1004,6 +1004,7 @@ static int qcom_slim_ngd_get_laddr(struct slim_controller *ctrl,
struct slim_eaddr *ea, u8 *laddr)
{
struct slim_val_inf msg = {0};
+ u8 failed_ea[6] = {0, 0, 0, 0, 0, 0};
struct slim_msg_txn txn;
u8 wbuf[10] = {0};
u8 rbuf[10] = {0};
@@ -1034,6 +1035,9 @@ static int qcom_slim_ngd_get_laddr(struct slim_controller *ctrl,
return ret;
}
+ if (!memcmp(rbuf, failed_ea, 6))
+ return -ENXIO;
+
*laddr = rbuf[6];
return ret;
@@ -1234,8 +1238,17 @@ static int qcom_slim_ngd_enable(struct qcom_slim_ngd_ctrl *ctrl, bool enable)
pm_runtime_resume(ctrl->dev);
pm_runtime_mark_last_busy(ctrl->dev);
pm_runtime_put(ctrl->dev);
+
+ ret = slim_register_controller(&ctrl->ctrl);
+ if (ret) {
+ dev_err(ctrl->dev, "error adding slim controller\n");
+ return ret;
+ }
+
+ dev_info(ctrl->dev, "SLIM controller Registered\n");
} else {
qcom_slim_qmi_exit(ctrl);
+ slim_unregister_controller(&ctrl->ctrl);
}
return 0;
@@ -1342,7 +1355,6 @@ static int of_qcom_slim_ngd_register(struct device *parent,
ngd->base = ctrl->base + ngd->id * data->offset +
(ngd->id - 1) * data->size;
ctrl->ngd = ngd;
- platform_driver_register(&qcom_slim_ngd_driver);
return 0;
}
@@ -1357,11 +1369,6 @@ static int qcom_slim_ngd_probe(struct platform_device *pdev)
int ret;
ctrl->ctrl.dev = dev;
- ret = slim_register_controller(&ctrl->ctrl);
- if (ret) {
- dev_err(dev, "error adding slim controller\n");
- return ret;
- }
pm_runtime_use_autosuspend(dev);
pm_runtime_set_autosuspend_delay(dev, QCOM_SLIM_NGD_AUTOSUSPEND);
@@ -1371,7 +1378,7 @@ static int qcom_slim_ngd_probe(struct platform_device *pdev)
ret = qcom_slim_ngd_qmi_svc_event_init(ctrl);
if (ret) {
dev_err(&pdev->dev, "QMI service registration failed:%d", ret);
- goto err;
+ return ret;
}
INIT_WORK(&ctrl->m_work, qcom_slim_ngd_master_worker);
@@ -1383,14 +1390,12 @@ static int qcom_slim_ngd_probe(struct platform_device *pdev)
}
return 0;
-err:
- slim_unregister_controller(&ctrl->ctrl);
wq_err:
qcom_slim_ngd_qmi_svc_event_deinit(&ctrl->qmi);
if (ctrl->mwq)
destroy_workqueue(ctrl->mwq);
- return 0;
+ return ret;
}
static int qcom_slim_ngd_ctrl_probe(struct platform_device *pdev)
@@ -1441,6 +1446,7 @@ static int qcom_slim_ngd_ctrl_probe(struct platform_device *pdev)
init_completion(&ctrl->reconf);
init_completion(&ctrl->qmi.qmi_comp);
+ platform_driver_register(&qcom_slim_ngd_driver);
return of_qcom_slim_ngd_register(dev, ctrl);
}
@@ -1456,7 +1462,7 @@ static int qcom_slim_ngd_remove(struct platform_device *pdev)
struct qcom_slim_ngd_ctrl *ctrl = platform_get_drvdata(pdev);
pm_runtime_disable(&pdev->dev);
- slim_unregister_controller(&ctrl->ctrl);
+ qcom_slim_ngd_enable(ctrl, false);
qcom_slim_ngd_exit_dma(ctrl);
qcom_slim_ngd_qmi_svc_event_deinit(&ctrl->qmi);
if (ctrl->mwq)
@@ -1467,7 +1473,7 @@ static int qcom_slim_ngd_remove(struct platform_device *pdev)
return 0;
}
-static int qcom_slim_ngd_runtime_idle(struct device *dev)
+static int __maybe_unused qcom_slim_ngd_runtime_idle(struct device *dev)
{
struct qcom_slim_ngd_ctrl *ctrl = dev_get_drvdata(dev);
@@ -1477,8 +1483,7 @@ static int qcom_slim_ngd_runtime_idle(struct device *dev)
return -EAGAIN;
}
-#ifdef CONFIG_PM
-static int qcom_slim_ngd_runtime_suspend(struct device *dev)
+static int __maybe_unused qcom_slim_ngd_runtime_suspend(struct device *dev)
{
struct qcom_slim_ngd_ctrl *ctrl = dev_get_drvdata(dev);
int ret = 0;
@@ -1491,7 +1496,6 @@ static int qcom_slim_ngd_runtime_suspend(struct device *dev)
return ret;
}
-#endif
static const struct dev_pm_ops qcom_slim_ngd_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
index 113e884697fd..446166ba0bec 100644
--- a/drivers/soc/Makefile
+++ b/drivers/soc/Makefile
@@ -18,7 +18,7 @@ obj-y += qcom/
obj-y += renesas/
obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
obj-$(CONFIG_SOC_SAMSUNG) += samsung/
-obj-$(CONFIG_ARCH_SUNXI) += sunxi/
+obj-y += sunxi/
obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-$(CONFIG_SOC_TI) += ti/
obj-$(CONFIG_ARCH_U8500) += ux500/
diff --git a/drivers/soc/actions/Kconfig b/drivers/soc/actions/Kconfig
index 9d68b5a771c3..1a0b9649efb4 100644
--- a/drivers/soc/actions/Kconfig
+++ b/drivers/soc/actions/Kconfig
@@ -10,7 +10,7 @@ config OWL_PM_DOMAINS
select PM_GENERIC_DOMAINS
help
Say 'y' here to enable support for Smart Power System (SPS)
- power-gating on Actions Semiconductor S500 SoC.
+ power-gating on Actions Semiconductor S500, S700 and S900 SoCs.
If unsure, say 'n'.
endif
diff --git a/drivers/soc/actions/Makefile b/drivers/soc/actions/Makefile
index 1e101b06bab1..4db9e7b050e5 100644
--- a/drivers/soc/actions/Makefile
+++ b/drivers/soc/actions/Makefile
@@ -1,2 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0+
+
obj-$(CONFIG_OWL_PM_DOMAINS_HELPER) += owl-sps-helper.o
obj-$(CONFIG_OWL_PM_DOMAINS) += owl-sps.o
diff --git a/drivers/soc/actions/owl-sps-helper.c b/drivers/soc/actions/owl-sps-helper.c
index 9d7a2c2b44ec..291a206d6f04 100644
--- a/drivers/soc/actions/owl-sps-helper.c
+++ b/drivers/soc/actions/owl-sps-helper.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Actions Semi Owl Smart Power System (SPS) shared helpers
*
@@ -5,11 +6,6 @@
* Author: Actions Semi, Inc.
*
* Copyright (c) 2017 Andreas Färber
- *
- * 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.
*/
#include <linux/delay.h>
diff --git a/drivers/soc/actions/owl-sps.c b/drivers/soc/actions/owl-sps.c
index 032921d8d41f..73a9e0bb7e8e 100644
--- a/drivers/soc/actions/owl-sps.c
+++ b/drivers/soc/actions/owl-sps.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Actions Semi Owl Smart Power System (SPS)
*
@@ -5,11 +6,6 @@
* Author: Actions Semi, Inc.
*
* Copyright (c) 2017 Andreas Färber
- *
- * 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.
*/
#include <linux/of_address.h>
@@ -18,6 +14,7 @@
#include <linux/soc/actions/owl-sps.h>
#include <dt-bindings/power/owl-s500-powergate.h>
#include <dt-bindings/power/owl-s700-powergate.h>
+#include <dt-bindings/power/owl-s900-powergate.h>
struct owl_sps_domain_info {
const char *name;
@@ -244,9 +241,66 @@ static const struct owl_sps_info s700_sps_info = {
.domains = s700_sps_domains,
};
+static const struct owl_sps_domain_info s900_sps_domains[] = {
+ [S900_PD_GPU_B] = {
+ .name = "GPU_B",
+ .pwr_bit = 3,
+ },
+ [S900_PD_VCE] = {
+ .name = "VCE",
+ .pwr_bit = 4,
+ },
+ [S900_PD_SENSOR] = {
+ .name = "SENSOR",
+ .pwr_bit = 5,
+ },
+ [S900_PD_VDE] = {
+ .name = "VDE",
+ .pwr_bit = 6,
+ },
+ [S900_PD_HDE] = {
+ .name = "HDE",
+ .pwr_bit = 7,
+ },
+ [S900_PD_USB3] = {
+ .name = "USB3",
+ .pwr_bit = 8,
+ },
+ [S900_PD_DDR0] = {
+ .name = "DDR0",
+ .pwr_bit = 9,
+ },
+ [S900_PD_DDR1] = {
+ .name = "DDR1",
+ .pwr_bit = 10,
+ },
+ [S900_PD_DE] = {
+ .name = "DE",
+ .pwr_bit = 13,
+ },
+ [S900_PD_NAND] = {
+ .name = "NAND",
+ .pwr_bit = 14,
+ },
+ [S900_PD_USB2_H0] = {
+ .name = "USB2_H0",
+ .pwr_bit = 15,
+ },
+ [S900_PD_USB2_H1] = {
+ .name = "USB2_H1",
+ .pwr_bit = 16,
+ },
+};
+
+static const struct owl_sps_info s900_sps_info = {
+ .num_domains = ARRAY_SIZE(s900_sps_domains),
+ .domains = s900_sps_domains,
+};
+
static const struct of_device_id owl_sps_of_matches[] = {
{ .compatible = "actions,s500-sps", .data = &s500_sps_info },
{ .compatible = "actions,s700-sps", .data = &s700_sps_info },
+ { .compatible = "actions,s900-sps", .data = &s900_sps_info },
{ }
};
diff --git a/drivers/soc/amlogic/Kconfig b/drivers/soc/amlogic/Kconfig
index b04f6e4aedbc..2f282b472912 100644
--- a/drivers/soc/amlogic/Kconfig
+++ b/drivers/soc/amlogic/Kconfig
@@ -1,5 +1,12 @@
menu "Amlogic SoC drivers"
+config MESON_CANVAS
+ tristate "Amlogic Meson Canvas driver"
+ depends on ARCH_MESON || COMPILE_TEST
+ default n
+ help
+ Say yes to support the canvas IP for Amlogic SoCs.
+
config MESON_GX_SOCINFO
bool "Amlogic Meson GX SoC Information driver"
depends on ARCH_MESON || COMPILE_TEST
diff --git a/drivers/soc/amlogic/Makefile b/drivers/soc/amlogic/Makefile
index 8fa321893928..0ab16d35ac36 100644
--- a/drivers/soc/amlogic/Makefile
+++ b/drivers/soc/amlogic/Makefile
@@ -1,3 +1,4 @@
+obj-$(CONFIG_MESON_CANVAS) += meson-canvas.o
obj-$(CONFIG_MESON_GX_SOCINFO) += meson-gx-socinfo.o
obj-$(CONFIG_MESON_GX_PM_DOMAINS) += meson-gx-pwrc-vpu.o
obj-$(CONFIG_MESON_MX_SOCINFO) += meson-mx-socinfo.o
diff --git a/drivers/soc/amlogic/meson-canvas.c b/drivers/soc/amlogic/meson-canvas.c
new file mode 100644
index 000000000000..fce33ca76bb6
--- /dev/null
+++ b/drivers/soc/amlogic/meson-canvas.c
@@ -0,0 +1,185 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 BayLibre, SAS
+ * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
+ * Copyright (C) 2014 Endless Mobile
+ */
+
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/soc/amlogic/meson-canvas.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+
+#define NUM_CANVAS 256
+
+/* DMC Registers */
+#define DMC_CAV_LUT_DATAL 0x00
+ #define CANVAS_WIDTH_LBIT 29
+ #define CANVAS_WIDTH_LWID 3
+#define DMC_CAV_LUT_DATAH 0x04
+ #define CANVAS_WIDTH_HBIT 0
+ #define CANVAS_HEIGHT_BIT 9
+ #define CANVAS_WRAP_BIT 22
+ #define CANVAS_BLKMODE_BIT 24
+ #define CANVAS_ENDIAN_BIT 26
+#define DMC_CAV_LUT_ADDR 0x08
+ #define CANVAS_LUT_WR_EN BIT(9)
+ #define CANVAS_LUT_RD_EN BIT(8)
+
+struct meson_canvas {
+ struct device *dev;
+ void __iomem *reg_base;
+ spinlock_t lock; /* canvas device lock */
+ u8 used[NUM_CANVAS];
+};
+
+static void canvas_write(struct meson_canvas *canvas, u32 reg, u32 val)
+{
+ writel_relaxed(val, canvas->reg_base + reg);
+}
+
+static u32 canvas_read(struct meson_canvas *canvas, u32 reg)
+{
+ return readl_relaxed(canvas->reg_base + reg);
+}
+
+struct meson_canvas *meson_canvas_get(struct device *dev)
+{
+ struct device_node *canvas_node;
+ struct platform_device *canvas_pdev;
+
+ canvas_node = of_parse_phandle(dev->of_node, "amlogic,canvas", 0);
+ if (!canvas_node)
+ return ERR_PTR(-ENODEV);
+
+ canvas_pdev = of_find_device_by_node(canvas_node);
+ if (!canvas_pdev)
+ return ERR_PTR(-EPROBE_DEFER);
+
+ return dev_get_drvdata(&canvas_pdev->dev);
+}
+EXPORT_SYMBOL_GPL(meson_canvas_get);
+
+int meson_canvas_config(struct meson_canvas *canvas, u8 canvas_index,
+ u32 addr, u32 stride, u32 height,
+ unsigned int wrap,
+ unsigned int blkmode,
+ unsigned int endian)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&canvas->lock, flags);
+ if (!canvas->used[canvas_index]) {
+ dev_err(canvas->dev,
+ "Trying to setup non allocated canvas %u\n",
+ canvas_index);
+ spin_unlock_irqrestore(&canvas->lock, flags);
+ return -EINVAL;
+ }
+
+ canvas_write(canvas, DMC_CAV_LUT_DATAL,
+ ((addr + 7) >> 3) |
+ (((stride + 7) >> 3) << CANVAS_WIDTH_LBIT));
+
+ canvas_write(canvas, DMC_CAV_LUT_DATAH,
+ ((((stride + 7) >> 3) >> CANVAS_WIDTH_LWID) <<
+ CANVAS_WIDTH_HBIT) |
+ (height << CANVAS_HEIGHT_BIT) |
+ (wrap << CANVAS_WRAP_BIT) |
+ (blkmode << CANVAS_BLKMODE_BIT) |
+ (endian << CANVAS_ENDIAN_BIT));
+
+ canvas_write(canvas, DMC_CAV_LUT_ADDR,
+ CANVAS_LUT_WR_EN | canvas_index);
+
+ /* Force a read-back to make sure everything is flushed. */
+ canvas_read(canvas, DMC_CAV_LUT_DATAH);
+ spin_unlock_irqrestore(&canvas->lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(meson_canvas_config);
+
+int meson_canvas_alloc(struct meson_canvas *canvas, u8 *canvas_index)
+{
+ int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&canvas->lock, flags);
+ for (i = 0; i < NUM_CANVAS; ++i) {
+ if (!canvas->used[i]) {
+ canvas->used[i] = 1;
+ spin_unlock_irqrestore(&canvas->lock, flags);
+ *canvas_index = i;
+ return 0;
+ }
+ }
+ spin_unlock_irqrestore(&canvas->lock, flags);
+
+ dev_err(canvas->dev, "No more canvas available\n");
+ return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(meson_canvas_alloc);
+
+int meson_canvas_free(struct meson_canvas *canvas, u8 canvas_index)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&canvas->lock, flags);
+ if (!canvas->used[canvas_index]) {
+ dev_err(canvas->dev,
+ "Trying to free unused canvas %u\n", canvas_index);
+ spin_unlock_irqrestore(&canvas->lock, flags);
+ return -EINVAL;
+ }
+ canvas->used[canvas_index] = 0;
+ spin_unlock_irqrestore(&canvas->lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(meson_canvas_free);
+
+static int meson_canvas_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct meson_canvas *canvas;
+ struct device *dev = &pdev->dev;
+
+ canvas = devm_kzalloc(dev, sizeof(*canvas), GFP_KERNEL);
+ if (!canvas)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ canvas->reg_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(canvas->reg_base))
+ return PTR_ERR(canvas->reg_base);
+
+ canvas->dev = dev;
+ spin_lock_init(&canvas->lock);
+ dev_set_drvdata(dev, canvas);
+
+ return 0;
+}
+
+static const struct of_device_id canvas_dt_match[] = {
+ { .compatible = "amlogic,canvas" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, canvas_dt_match);
+
+static struct platform_driver meson_canvas_driver = {
+ .probe = meson_canvas_probe,
+ .driver = {
+ .name = "amlogic-canvas",
+ .of_match_table = canvas_dt_match,
+ },
+};
+module_platform_driver(meson_canvas_driver);
+
+MODULE_DESCRIPTION("Amlogic Canvas driver");
+MODULE_AUTHOR("Maxime Jourdan <mjourdan@baylibre.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/dove/pmu.c b/drivers/soc/dove/pmu.c
index 5abb08ffb74d..ffc5311c0ed8 100644
--- a/drivers/soc/dove/pmu.c
+++ b/drivers/soc/dove/pmu.c
@@ -383,7 +383,7 @@ int __init dove_init_pmu(void)
domains_node = of_get_child_by_name(np_pmu, "domains");
if (!domains_node) {
- pr_err("%s: failed to find domains sub-node\n", np_pmu->name);
+ pr_err("%pOFn: failed to find domains sub-node\n", np_pmu);
return 0;
}
@@ -396,7 +396,7 @@ int __init dove_init_pmu(void)
pmu->pmc_base = of_iomap(pmu->of_node, 0);
pmu->pmu_base = of_iomap(pmu->of_node, 1);
if (!pmu->pmc_base || !pmu->pmu_base) {
- pr_err("%s: failed to map PMU\n", np_pmu->name);
+ pr_err("%pOFn: failed to map PMU\n", np_pmu);
iounmap(pmu->pmu_base);
iounmap(pmu->pmc_base);
kfree(pmu);
@@ -414,7 +414,7 @@ int __init dove_init_pmu(void)
break;
domain->pmu = pmu;
- domain->base.name = kstrdup(np->name, GFP_KERNEL);
+ domain->base.name = kasprintf(GFP_KERNEL, "%pOFn", np);
if (!domain->base.name) {
kfree(domain);
break;
@@ -444,7 +444,7 @@ int __init dove_init_pmu(void)
/* Loss of the interrupt controller is not a fatal error. */
parent_irq = irq_of_parse_and_map(pmu->of_node, 0);
if (!parent_irq) {
- pr_err("%s: no interrupt specified\n", np_pmu->name);
+ pr_err("%pOFn: no interrupt specified\n", np_pmu);
} else {
ret = dove_init_pmu_irq(pmu, parent_irq);
if (ret)
diff --git a/drivers/soc/fsl/dpio/dpio-driver.c b/drivers/soc/fsl/dpio/dpio-driver.c
index b60b77bfaffa..e58fcc9096e8 100644
--- a/drivers/soc/fsl/dpio/dpio-driver.c
+++ b/drivers/soc/fsl/dpio/dpio-driver.c
@@ -50,13 +50,10 @@ static void unregister_dpio_irq_handlers(struct fsl_mc_device *dpio_dev)
static int register_dpio_irq_handlers(struct fsl_mc_device *dpio_dev, int cpu)
{
- struct dpio_priv *priv;
int error;
struct fsl_mc_device_irq *irq;
cpumask_t mask;
- priv = dev_get_drvdata(&dpio_dev->dev);
-
irq = dpio_dev->irqs[0];
error = devm_request_irq(&dpio_dev->dev,
irq->msi_desc->irq,
diff --git a/drivers/soc/fsl/dpio/dpio-service.c b/drivers/soc/fsl/dpio/dpio-service.c
index 9b17f72349ed..321a92613a7e 100644
--- a/drivers/soc/fsl/dpio/dpio-service.c
+++ b/drivers/soc/fsl/dpio/dpio-service.c
@@ -310,6 +310,37 @@ int dpaa2_io_service_rearm(struct dpaa2_io *d,
EXPORT_SYMBOL_GPL(dpaa2_io_service_rearm);
/**
+ * dpaa2_io_service_pull_fq() - pull dequeue functions from a fq.
+ * @d: the given DPIO service.
+ * @fqid: the given frame queue id.
+ * @s: the dpaa2_io_store object for the result.
+ *
+ * Return 0 for success, or error code for failure.
+ */
+int dpaa2_io_service_pull_fq(struct dpaa2_io *d, u32 fqid,
+ struct dpaa2_io_store *s)
+{
+ struct qbman_pull_desc pd;
+ int err;
+
+ qbman_pull_desc_clear(&pd);
+ qbman_pull_desc_set_storage(&pd, s->vaddr, s->paddr, 1);
+ qbman_pull_desc_set_numframes(&pd, (u8)s->max);
+ qbman_pull_desc_set_fq(&pd, fqid);
+
+ d = service_select(d);
+ if (!d)
+ return -ENODEV;
+ s->swp = d->swp;
+ err = qbman_swp_pull(d->swp, &pd);
+ if (err)
+ s->swp = NULL;
+
+ return err;
+}
+EXPORT_SYMBOL(dpaa2_io_service_pull_fq);
+
+/**
* dpaa2_io_service_pull_channel() - pull dequeue functions from a channel.
* @d: the given DPIO service.
* @channelid: the given channel id.
@@ -342,6 +373,33 @@ int dpaa2_io_service_pull_channel(struct dpaa2_io *d, u32 channelid,
EXPORT_SYMBOL_GPL(dpaa2_io_service_pull_channel);
/**
+ * dpaa2_io_service_enqueue_fq() - Enqueue a frame to a frame queue.
+ * @d: the given DPIO service.
+ * @fqid: the given frame queue id.
+ * @fd: the frame descriptor which is enqueued.
+ *
+ * Return 0 for successful enqueue, -EBUSY if the enqueue ring is not ready,
+ * or -ENODEV if there is no dpio service.
+ */
+int dpaa2_io_service_enqueue_fq(struct dpaa2_io *d,
+ u32 fqid,
+ const struct dpaa2_fd *fd)
+{
+ struct qbman_eq_desc ed;
+
+ d = service_select(d);
+ if (!d)
+ return -ENODEV;
+
+ qbman_eq_desc_clear(&ed);
+ qbman_eq_desc_set_no_orp(&ed, 0);
+ qbman_eq_desc_set_fq(&ed, fqid);
+
+ return qbman_swp_enqueue(d->swp, &ed, fd);
+}
+EXPORT_SYMBOL(dpaa2_io_service_enqueue_fq);
+
+/**
* dpaa2_io_service_enqueue_qd() - Enqueue a frame to a QD.
* @d: the given DPIO service.
* @qdid: the given queuing destination id.
diff --git a/drivers/soc/fsl/qbman/Kconfig b/drivers/soc/fsl/qbman/Kconfig
index d570cb5fd381..b0943e541796 100644
--- a/drivers/soc/fsl/qbman/Kconfig
+++ b/drivers/soc/fsl/qbman/Kconfig
@@ -1,6 +1,6 @@
menuconfig FSL_DPAA
bool "QorIQ DPAA1 framework support"
- depends on (FSL_SOC_BOOKE || ARCH_LAYERSCAPE)
+ depends on ((FSL_SOC_BOOKE || ARCH_LAYERSCAPE) && ARCH_DMA_ADDR_T_64BIT)
select GENERIC_ALLOCATOR
help
The Freescale Data Path Acceleration Architecture (DPAA) is a set of
diff --git a/drivers/soc/fsl/qbman/bman.c b/drivers/soc/fsl/qbman/bman.c
index f9485cedc648..f84ab596bde8 100644
--- a/drivers/soc/fsl/qbman/bman.c
+++ b/drivers/soc/fsl/qbman/bman.c
@@ -562,11 +562,9 @@ static int bman_create_portal(struct bman_portal *portal,
dev_err(c->dev, "request_irq() failed\n");
goto fail_irq;
}
- if (c->cpu != -1 && irq_can_set_affinity(c->irq) &&
- irq_set_affinity(c->irq, cpumask_of(c->cpu))) {
- dev_err(c->dev, "irq_set_affinity() failed\n");
+
+ if (dpaa_set_portal_irq_affinity(c->dev, c->irq, c->cpu))
goto fail_affinity;
- }
/* Need RCR to be empty before continuing */
ret = bm_rcr_get_fill(p);
diff --git a/drivers/soc/fsl/qbman/bman_ccsr.c b/drivers/soc/fsl/qbman/bman_ccsr.c
index 05c42235dd41..7c3cc968053c 100644
--- a/drivers/soc/fsl/qbman/bman_ccsr.c
+++ b/drivers/soc/fsl/qbman/bman_ccsr.c
@@ -120,6 +120,7 @@ static void bm_set_memory(u64 ba, u32 size)
*/
static dma_addr_t fbpr_a;
static size_t fbpr_sz;
+static int __bman_probed;
static int bman_fbpr(struct reserved_mem *rmem)
{
@@ -166,6 +167,12 @@ static irqreturn_t bman_isr(int irq, void *ptr)
return IRQ_HANDLED;
}
+int bman_is_probed(void)
+{
+ return __bman_probed;
+}
+EXPORT_SYMBOL_GPL(bman_is_probed);
+
static int fsl_bman_probe(struct platform_device *pdev)
{
int ret, err_irq;
@@ -175,6 +182,8 @@ static int fsl_bman_probe(struct platform_device *pdev)
u16 id, bm_pool_cnt;
u8 major, minor;
+ __bman_probed = -1;
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "Can't get %pOF property 'IORESOURCE_MEM'\n",
@@ -255,6 +264,8 @@ static int fsl_bman_probe(struct platform_device *pdev)
return ret;
}
+ __bman_probed = 1;
+
return 0;
};
diff --git a/drivers/soc/fsl/qbman/bman_portal.c b/drivers/soc/fsl/qbman/bman_portal.c
index 2f71f7df3465..2c95cf59f3e7 100644
--- a/drivers/soc/fsl/qbman/bman_portal.c
+++ b/drivers/soc/fsl/qbman/bman_portal.c
@@ -65,7 +65,9 @@ static int bman_offline_cpu(unsigned int cpu)
if (!pcfg)
return 0;
- irq_set_affinity(pcfg->irq, cpumask_of(0));
+ /* use any other online CPU */
+ cpu = cpumask_any_but(cpu_online_mask, cpu);
+ irq_set_affinity(pcfg->irq, cpumask_of(cpu));
return 0;
}
@@ -91,7 +93,15 @@ static int bman_portal_probe(struct platform_device *pdev)
struct device_node *node = dev->of_node;
struct bm_portal_config *pcfg;
struct resource *addr_phys[2];
- int irq, cpu;
+ int irq, cpu, err;
+
+ err = bman_is_probed();
+ if (!err)
+ return -EPROBE_DEFER;
+ if (err < 0) {
+ dev_err(&pdev->dev, "failing probe due to bman probe error\n");
+ return -ENODEV;
+ }
pcfg = devm_kmalloc(dev, sizeof(*pcfg), GFP_KERNEL);
if (!pcfg)
diff --git a/drivers/soc/fsl/qbman/dpaa_sys.h b/drivers/soc/fsl/qbman/dpaa_sys.h
index 9f379000da85..ae8afa552b1e 100644
--- a/drivers/soc/fsl/qbman/dpaa_sys.h
+++ b/drivers/soc/fsl/qbman/dpaa_sys.h
@@ -111,4 +111,24 @@ int qbman_init_private_mem(struct device *dev, int idx, dma_addr_t *addr,
#define QBMAN_MEMREMAP_ATTR MEMREMAP_WC
#endif
+static inline int dpaa_set_portal_irq_affinity(struct device *dev,
+ int irq, int cpu)
+{
+ int ret = 0;
+
+ if (!irq_can_set_affinity(irq)) {
+ dev_err(dev, "unable to set IRQ affinity\n");
+ return -EINVAL;
+ }
+
+ if (cpu == -1 || !cpu_online(cpu))
+ cpu = cpumask_any(cpu_online_mask);
+
+ ret = irq_set_affinity(irq, cpumask_of(cpu));
+ if (ret)
+ dev_err(dev, "irq_set_affinity() on CPU %d failed\n", cpu);
+
+ return ret;
+}
+
#endif /* __DPAA_SYS_H */
diff --git a/drivers/soc/fsl/qbman/qman.c b/drivers/soc/fsl/qbman/qman.c
index ecb22749df0b..5ce24718c2fd 100644
--- a/drivers/soc/fsl/qbman/qman.c
+++ b/drivers/soc/fsl/qbman/qman.c
@@ -850,12 +850,24 @@ static inline void qm_mr_set_ithresh(struct qm_portal *portal, u8 ithresh)
static inline int qm_mc_init(struct qm_portal *portal)
{
+ u8 rr0, rr1;
struct qm_mc *mc = &portal->mc;
mc->cr = portal->addr.ce + QM_CL_CR;
mc->rr = portal->addr.ce + QM_CL_RR0;
- mc->rridx = (mc->cr->_ncw_verb & QM_MCC_VERB_VBIT)
- ? 0 : 1;
+ /*
+ * The expected valid bit polarity for the next CR command is 0
+ * if RR1 contains a valid response, and is 1 if RR0 contains a
+ * valid response. If both RR contain all 0, this indicates either
+ * that no command has been executed since reset (in which case the
+ * expected valid bit polarity is 1)
+ */
+ rr0 = mc->rr->verb;
+ rr1 = (mc->rr+1)->verb;
+ if ((rr0 == 0 && rr1 == 0) || rr0 != 0)
+ mc->rridx = 1;
+ else
+ mc->rridx = 0;
mc->vbit = mc->rridx ? QM_MCC_VERB_VBIT : 0;
#ifdef CONFIG_FSL_DPAA_CHECKING
mc->state = qman_mc_idle;
@@ -1000,6 +1012,37 @@ static inline void put_affine_portal(void)
static struct workqueue_struct *qm_portal_wq;
+void qman_dqrr_set_ithresh(struct qman_portal *portal, u8 ithresh)
+{
+ if (!portal)
+ return;
+
+ qm_dqrr_set_ithresh(&portal->p, ithresh);
+ portal->p.dqrr.ithresh = ithresh;
+}
+EXPORT_SYMBOL(qman_dqrr_set_ithresh);
+
+void qman_dqrr_get_ithresh(struct qman_portal *portal, u8 *ithresh)
+{
+ if (portal && ithresh)
+ *ithresh = portal->p.dqrr.ithresh;
+}
+EXPORT_SYMBOL(qman_dqrr_get_ithresh);
+
+void qman_portal_get_iperiod(struct qman_portal *portal, u32 *iperiod)
+{
+ if (portal && iperiod)
+ *iperiod = qm_in(&portal->p, QM_REG_ITPR);
+}
+EXPORT_SYMBOL(qman_portal_get_iperiod);
+
+void qman_portal_set_iperiod(struct qman_portal *portal, u32 iperiod)
+{
+ if (portal)
+ qm_out(&portal->p, QM_REG_ITPR, iperiod);
+}
+EXPORT_SYMBOL(qman_portal_set_iperiod);
+
int qman_wq_alloc(void)
{
qm_portal_wq = alloc_workqueue("qman_portal_wq", 0, 1);
@@ -1210,11 +1253,9 @@ static int qman_create_portal(struct qman_portal *portal,
dev_err(c->dev, "request_irq() failed\n");
goto fail_irq;
}
- if (c->cpu != -1 && irq_can_set_affinity(c->irq) &&
- irq_set_affinity(c->irq, cpumask_of(c->cpu))) {
- dev_err(c->dev, "irq_set_affinity() failed\n");
+
+ if (dpaa_set_portal_irq_affinity(c->dev, c->irq, c->cpu))
goto fail_affinity;
- }
/* Need EQCR to be empty before continuing */
isdr &= ~QM_PIRQ_EQCI;
@@ -2729,6 +2770,9 @@ static int qman_alloc_range(struct gen_pool *p, u32 *result, u32 cnt)
{
unsigned long addr;
+ if (!p)
+ return -ENODEV;
+
addr = gen_pool_alloc(p, cnt);
if (!addr)
return -ENOMEM;
diff --git a/drivers/soc/fsl/qbman/qman_ccsr.c b/drivers/soc/fsl/qbman/qman_ccsr.c
index 79cba58387a5..109b38de3176 100644
--- a/drivers/soc/fsl/qbman/qman_ccsr.c
+++ b/drivers/soc/fsl/qbman/qman_ccsr.c
@@ -273,6 +273,7 @@ static const struct qman_error_info_mdata error_mdata[] = {
static u32 __iomem *qm_ccsr_start;
/* A SDQCR mask comprising all the available/visible pool channels */
static u32 qm_pools_sdqcr;
+static int __qman_probed;
static inline u32 qm_ccsr_in(u32 offset)
{
@@ -418,7 +419,7 @@ static size_t fqd_sz, pfdr_sz;
static int zero_priv_mem(phys_addr_t addr, size_t sz)
{
/* map as cacheable, non-guarded */
- void __iomem *tmpp = ioremap_prot(addr, sz, 0);
+ void __iomem *tmpp = ioremap_cache(addr, sz);
if (!tmpp)
return -ENOMEM;
@@ -686,6 +687,12 @@ static int qman_resource_init(struct device *dev)
return 0;
}
+int qman_is_probed(void)
+{
+ return __qman_probed;
+}
+EXPORT_SYMBOL_GPL(qman_is_probed);
+
static int fsl_qman_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -695,6 +702,8 @@ static int fsl_qman_probe(struct platform_device *pdev)
u16 id;
u8 major, minor;
+ __qman_probed = -1;
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "Can't get %pOF property 'IORESOURCE_MEM'\n",
@@ -828,6 +837,8 @@ static int fsl_qman_probe(struct platform_device *pdev)
if (ret)
return ret;
+ __qman_probed = 1;
+
return 0;
}
diff --git a/drivers/soc/fsl/qbman/qman_portal.c b/drivers/soc/fsl/qbman/qman_portal.c
index a120002b630e..661c9b234d32 100644
--- a/drivers/soc/fsl/qbman/qman_portal.c
+++ b/drivers/soc/fsl/qbman/qman_portal.c
@@ -195,8 +195,10 @@ static int qman_offline_cpu(unsigned int cpu)
if (p) {
pcfg = qman_get_qm_portal_config(p);
if (pcfg) {
- irq_set_affinity(pcfg->irq, cpumask_of(0));
- qman_portal_update_sdest(pcfg, 0);
+ /* select any other online CPU */
+ cpu = cpumask_any_but(cpu_online_mask, cpu);
+ irq_set_affinity(pcfg->irq, cpumask_of(cpu));
+ qman_portal_update_sdest(pcfg, cpu);
}
}
return 0;
@@ -227,6 +229,14 @@ static int qman_portal_probe(struct platform_device *pdev)
int irq, cpu, err;
u32 val;
+ err = qman_is_probed();
+ if (!err)
+ return -EPROBE_DEFER;
+ if (err < 0) {
+ dev_err(&pdev->dev, "failing probe due to qman probe error\n");
+ return -ENODEV;
+ }
+
pcfg = devm_kmalloc(dev, sizeof(*pcfg), GFP_KERNEL);
if (!pcfg)
return -ENOMEM;
diff --git a/drivers/soc/fsl/qe/qe.c b/drivers/soc/fsl/qe/qe.c
index 2ef6fc6487c1..612d9c551be5 100644
--- a/drivers/soc/fsl/qe/qe.c
+++ b/drivers/soc/fsl/qe/qe.c
@@ -588,11 +588,7 @@ struct qe_firmware_info *qe_get_firmware_info(void)
}
/* Find the 'firmware' child node */
- for_each_child_of_node(qe, fw) {
- if (strcmp(fw->name, "firmware") == 0)
- break;
- }
-
+ fw = of_get_child_by_name(qe, "firmware");
of_node_put(qe);
/* Did we find the 'firmware' node? */
diff --git a/drivers/soc/fsl/qe/qe_tdm.c b/drivers/soc/fsl/qe/qe_tdm.c
index f744c214f680..f78c34647ca2 100644
--- a/drivers/soc/fsl/qe/qe_tdm.c
+++ b/drivers/soc/fsl/qe/qe_tdm.c
@@ -131,7 +131,7 @@ int ucc_of_parse_tdm(struct device_node *np, struct ucc_tdm *utdm,
pdev = of_find_device_by_node(np2);
if (!pdev) {
- pr_err("%s: failed to lookup pdev\n", np2->name);
+ pr_err("%pOFn: failed to lookup pdev\n", np2);
of_node_put(np2);
return -EINVAL;
}
@@ -153,7 +153,7 @@ int ucc_of_parse_tdm(struct device_node *np, struct ucc_tdm *utdm,
pdev = of_find_device_by_node(np2);
if (!pdev) {
ret = -EINVAL;
- pr_err("%s: failed to lookup pdev\n", np2->name);
+ pr_err("%pOFn: failed to lookup pdev\n", np2);
of_node_put(np2);
goto err_miss_siram_property;
}
diff --git a/drivers/soc/fsl/qe/ucc.c b/drivers/soc/fsl/qe/ucc.c
index c646d8713861..681f7d4b7724 100644
--- a/drivers/soc/fsl/qe/ucc.c
+++ b/drivers/soc/fsl/qe/ucc.c
@@ -626,7 +626,7 @@ static u32 ucc_get_tdm_sync_shift(enum comm_dir mode, u32 tdm_num)
{
u32 shift;
- shift = (mode == COMM_DIR_RX) ? RX_SYNC_SHIFT_BASE : RX_SYNC_SHIFT_BASE;
+ shift = (mode == COMM_DIR_RX) ? RX_SYNC_SHIFT_BASE : TX_SYNC_SHIFT_BASE;
shift -= tdm_num * 2;
return shift;
diff --git a/drivers/soc/imx/gpc.c b/drivers/soc/imx/gpc.c
index b3da635970ea..aa3729ecaa9e 100644
--- a/drivers/soc/imx/gpc.c
+++ b/drivers/soc/imx/gpc.c
@@ -1,13 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2015-2017 Pengutronix, Lucas Stach <kernel@pengutronix.de>
* Copyright 2011-2013 Freescale Semiconductor, Inc.
- *
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
*/
#include <linux/clk.h>
@@ -69,7 +63,7 @@ static int imx6_pm_domain_power_off(struct generic_pm_domain *genpd)
u32 val;
/* Read ISO and ISO2SW power down delays */
- regmap_read(pd->regmap, pd->reg_offs + GPC_PGC_PUPSCR_OFFS, &val);
+ regmap_read(pd->regmap, pd->reg_offs + GPC_PGC_PDNSCR_OFFS, &val);
iso = val & 0x3f;
iso2sw = (val >> 8) & 0x3f;
@@ -247,6 +241,7 @@ builtin_platform_driver(imx_pgc_power_domain_driver)
#define GPC_PGC_DOMAIN_ARM 0
#define GPC_PGC_DOMAIN_PU 1
#define GPC_PGC_DOMAIN_DISPLAY 2
+#define GPC_PGC_DOMAIN_PCI 3
static struct genpd_power_state imx6_pm_domain_pu_state = {
.power_off_latency_ns = 25000,
@@ -254,12 +249,13 @@ static struct genpd_power_state imx6_pm_domain_pu_state = {
};
static struct imx_pm_domain imx_gpc_domains[] = {
- {
+ [GPC_PGC_DOMAIN_ARM] {
.base = {
.name = "ARM",
.flags = GENPD_FLAG_ALWAYS_ON,
},
- }, {
+ },
+ [GPC_PGC_DOMAIN_PU] {
.base = {
.name = "PU",
.power_off = imx6_pm_domain_power_off,
@@ -269,7 +265,8 @@ static struct imx_pm_domain imx_gpc_domains[] = {
},
.reg_offs = 0x260,
.cntr_pdn_bit = 0,
- }, {
+ },
+ [GPC_PGC_DOMAIN_DISPLAY] {
.base = {
.name = "DISPLAY",
.power_off = imx6_pm_domain_power_off,
@@ -277,7 +274,8 @@ static struct imx_pm_domain imx_gpc_domains[] = {
},
.reg_offs = 0x240,
.cntr_pdn_bit = 4,
- }, {
+ },
+ [GPC_PGC_DOMAIN_PCI] {
.base = {
.name = "PCI",
.power_off = imx6_pm_domain_power_off,
@@ -348,8 +346,8 @@ static const struct regmap_config imx_gpc_regmap_config = {
};
static struct generic_pm_domain *imx_gpc_onecell_domains[] = {
- &imx_gpc_domains[0].base,
- &imx_gpc_domains[1].base,
+ &imx_gpc_domains[GPC_PGC_DOMAIN_ARM].base,
+ &imx_gpc_domains[GPC_PGC_DOMAIN_PU].base,
};
static struct genpd_onecell_data imx_gpc_onecell_data = {
diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c
index 6ef18cf8f243..e7b5994fee9d 100644
--- a/drivers/soc/imx/gpcv2.c
+++ b/drivers/soc/imx/gpcv2.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2017 Impinj, Inc
* Author: Andrey Smirnov <andrew.smirnov@gmail.com>
@@ -5,29 +6,23 @@
* Based on the code of analogus driver:
*
* Copyright 2015-2017 Pengutronix, Lucas Stach <kernel@pengutronix.de>
- *
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
*/
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <dt-bindings/power/imx7-power.h>
-#define GPC_LPCR_A7_BSC 0x000
+#define GPC_LPCR_A_CORE_BSC 0x000
#define GPC_PGC_CPU_MAPPING 0x0ec
-#define USB_HSIC_PHY_A7_DOMAIN BIT(6)
-#define USB_OTG2_PHY_A7_DOMAIN BIT(5)
-#define USB_OTG1_PHY_A7_DOMAIN BIT(4)
-#define PCIE_PHY_A7_DOMAIN BIT(3)
-#define MIPI_PHY_A7_DOMAIN BIT(2)
+#define USB_HSIC_PHY_A_CORE_DOMAIN BIT(6)
+#define USB_OTG2_PHY_A_CORE_DOMAIN BIT(5)
+#define USB_OTG1_PHY_A_CORE_DOMAIN BIT(4)
+#define PCIE_PHY_A_CORE_DOMAIN BIT(3)
+#define MIPI_PHY_A_CORE_DOMAIN BIT(2)
#define GPC_PU_PGC_SW_PUP_REQ 0x0f8
#define GPC_PU_PGC_SW_PDN_REQ 0x104
@@ -53,7 +48,7 @@
#define GPC_PGC_CTRL_PCR BIT(0)
-struct imx7_pgc_domain {
+struct imx_pgc_domain {
struct generic_pm_domain genpd;
struct regmap *regmap;
struct regulator *regulator;
@@ -69,11 +64,16 @@ struct imx7_pgc_domain {
struct device *dev;
};
-static int imx7_gpc_pu_pgc_sw_pxx_req(struct generic_pm_domain *genpd,
+struct imx_pgc_domain_data {
+ const struct imx_pgc_domain *domains;
+ size_t domains_num;
+};
+
+static int imx_gpc_pu_pgc_sw_pxx_req(struct generic_pm_domain *genpd,
bool on)
{
- struct imx7_pgc_domain *domain = container_of(genpd,
- struct imx7_pgc_domain,
+ 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;
@@ -150,24 +150,24 @@ unmap:
return ret;
}
-static int imx7_gpc_pu_pgc_sw_pup_req(struct generic_pm_domain *genpd)
+static int imx_gpc_pu_pgc_sw_pup_req(struct generic_pm_domain *genpd)
{
- return imx7_gpc_pu_pgc_sw_pxx_req(genpd, true);
+ return imx_gpc_pu_pgc_sw_pxx_req(genpd, true);
}
-static int imx7_gpc_pu_pgc_sw_pdn_req(struct generic_pm_domain *genpd)
+static int imx_gpc_pu_pgc_sw_pdn_req(struct generic_pm_domain *genpd)
{
- return imx7_gpc_pu_pgc_sw_pxx_req(genpd, false);
+ return imx_gpc_pu_pgc_sw_pxx_req(genpd, false);
}
-static const struct imx7_pgc_domain imx7_pgc_domains[] = {
+static const struct imx_pgc_domain imx7_pgc_domains[] = {
[IMX7_POWER_DOMAIN_MIPI_PHY] = {
.genpd = {
.name = "mipi-phy",
},
.bits = {
.pxx = MIPI_PHY_SW_Pxx_REQ,
- .map = MIPI_PHY_A7_DOMAIN,
+ .map = MIPI_PHY_A_CORE_DOMAIN,
},
.voltage = 1000000,
.pgc = PGC_MIPI,
@@ -179,7 +179,7 @@ static const struct imx7_pgc_domain imx7_pgc_domains[] = {
},
.bits = {
.pxx = PCIE_PHY_SW_Pxx_REQ,
- .map = PCIE_PHY_A7_DOMAIN,
+ .map = PCIE_PHY_A_CORE_DOMAIN,
},
.voltage = 1000000,
.pgc = PGC_PCIE,
@@ -191,16 +191,21 @@ static const struct imx7_pgc_domain imx7_pgc_domains[] = {
},
.bits = {
.pxx = USB_HSIC_PHY_SW_Pxx_REQ,
- .map = USB_HSIC_PHY_A7_DOMAIN,
+ .map = USB_HSIC_PHY_A_CORE_DOMAIN,
},
.voltage = 1200000,
.pgc = PGC_USB_HSIC,
},
};
-static int imx7_pgc_domain_probe(struct platform_device *pdev)
+static const struct imx_pgc_domain_data imx7_pgc_domain_data = {
+ .domains = imx7_pgc_domains,
+ .domains_num = ARRAY_SIZE(imx7_pgc_domains),
+};
+
+static int imx_pgc_domain_probe(struct platform_device *pdev)
{
- struct imx7_pgc_domain *domain = pdev->dev.platform_data;
+ struct imx_pgc_domain *domain = pdev->dev.platform_data;
int ret;
domain->dev = &pdev->dev;
@@ -233,9 +238,9 @@ static int imx7_pgc_domain_probe(struct platform_device *pdev)
return ret;
}
-static int imx7_pgc_domain_remove(struct platform_device *pdev)
+static int imx_pgc_domain_remove(struct platform_device *pdev)
{
- struct imx7_pgc_domain *domain = pdev->dev.platform_data;
+ struct imx_pgc_domain *domain = pdev->dev.platform_data;
of_genpd_del_provider(domain->dev->of_node);
pm_genpd_remove(&domain->genpd);
@@ -243,25 +248,26 @@ static int imx7_pgc_domain_remove(struct platform_device *pdev)
return 0;
}
-static const struct platform_device_id imx7_pgc_domain_id[] = {
- { "imx7-pgc-domain", },
+static const struct platform_device_id imx_pgc_domain_id[] = {
+ { "imx-pgc-domain", },
{ },
};
-static struct platform_driver imx7_pgc_domain_driver = {
+static struct platform_driver imx_pgc_domain_driver = {
.driver = {
- .name = "imx7-pgc",
+ .name = "imx-pgc",
},
- .probe = imx7_pgc_domain_probe,
- .remove = imx7_pgc_domain_remove,
- .id_table = imx7_pgc_domain_id,
+ .probe = imx_pgc_domain_probe,
+ .remove = imx_pgc_domain_remove,
+ .id_table = imx_pgc_domain_id,
};
-builtin_platform_driver(imx7_pgc_domain_driver)
+builtin_platform_driver(imx_pgc_domain_driver)
static int imx_gpcv2_probe(struct platform_device *pdev)
{
+ static const struct imx_pgc_domain_data *domain_data;
static const struct regmap_range yes_ranges[] = {
- regmap_reg_range(GPC_LPCR_A7_BSC,
+ regmap_reg_range(GPC_LPCR_A_CORE_BSC,
GPC_M4_PU_PDN_FLG),
regmap_reg_range(GPC_PGC_CTRL(PGC_MIPI),
GPC_PGC_SR(PGC_MIPI)),
@@ -307,9 +313,11 @@ static int imx_gpcv2_probe(struct platform_device *pdev)
return ret;
}
+ domain_data = of_device_get_match_data(&pdev->dev);
+
for_each_child_of_node(pgc_np, np) {
struct platform_device *pd_pdev;
- struct imx7_pgc_domain *domain;
+ struct imx_pgc_domain *domain;
u32 domain_index;
ret = of_property_read_u32(np, "reg", &domain_index);
@@ -319,14 +327,14 @@ static int imx_gpcv2_probe(struct platform_device *pdev)
return ret;
}
- if (domain_index >= ARRAY_SIZE(imx7_pgc_domains)) {
+ if (domain_index >= domain_data->domains_num) {
dev_warn(dev,
"Domain index %d is out of bounds\n",
domain_index);
continue;
}
- pd_pdev = platform_device_alloc("imx7-pgc-domain",
+ pd_pdev = platform_device_alloc("imx-pgc-domain",
domain_index);
if (!pd_pdev) {
dev_err(dev, "Failed to allocate platform device\n");
@@ -335,8 +343,8 @@ static int imx_gpcv2_probe(struct platform_device *pdev)
}
ret = platform_device_add_data(pd_pdev,
- &imx7_pgc_domains[domain_index],
- sizeof(imx7_pgc_domains[domain_index]));
+ &domain_data->domains[domain_index],
+ sizeof(domain_data->domains[domain_index]));
if (ret) {
platform_device_put(pd_pdev);
of_node_put(np);
@@ -345,8 +353,8 @@ static int imx_gpcv2_probe(struct platform_device *pdev)
domain = pd_pdev->dev.platform_data;
domain->regmap = regmap;
- domain->genpd.power_on = imx7_gpc_pu_pgc_sw_pup_req;
- domain->genpd.power_off = imx7_gpc_pu_pgc_sw_pdn_req;
+ domain->genpd.power_on = imx_gpc_pu_pgc_sw_pup_req;
+ domain->genpd.power_off = imx_gpc_pu_pgc_sw_pdn_req;
pd_pdev->dev.parent = dev;
pd_pdev->dev.of_node = np;
@@ -363,7 +371,7 @@ static int imx_gpcv2_probe(struct platform_device *pdev)
}
static const struct of_device_id imx_gpcv2_dt_ids[] = {
- { .compatible = "fsl,imx7d-gpc" },
+ { .compatible = "fsl,imx7d-gpc", .data = &imx7_pgc_domain_data, },
{ }
};
diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
index 4e931fdf4d09..8236a6c87e19 100644
--- a/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -76,6 +76,13 @@
#define PWRAP_SLV_CAP_SECURITY BIT(2)
#define HAS_CAP(_c, _x) (((_c) & (_x)) == (_x))
+/* Group of bits used for shown pwrap capability */
+#define PWRAP_CAP_BRIDGE BIT(0)
+#define PWRAP_CAP_RESET BIT(1)
+#define PWRAP_CAP_DCM BIT(2)
+#define PWRAP_CAP_INT1_EN BIT(3)
+#define PWRAP_CAP_WDT_SRC1 BIT(4)
+
/* defines for slave device wrapper registers */
enum dew_regs {
PWRAP_DEW_BASE,
@@ -91,6 +98,27 @@ enum dew_regs {
PWRAP_DEW_CIPHER_MODE,
PWRAP_DEW_CIPHER_SWRST,
+ /* MT6323 only regs */
+ PWRAP_DEW_CIPHER_EN,
+ PWRAP_DEW_RDDMY_NO,
+
+ /* MT6358 only regs */
+ PWRAP_SMT_CON1,
+ PWRAP_DRV_CON1,
+ PWRAP_FILTER_CON0,
+ PWRAP_GPIO_PULLEN0_CLR,
+ PWRAP_RG_SPI_CON0,
+ PWRAP_RG_SPI_RECORD0,
+ PWRAP_RG_SPI_CON2,
+ PWRAP_RG_SPI_CON3,
+ PWRAP_RG_SPI_CON4,
+ PWRAP_RG_SPI_CON5,
+ PWRAP_RG_SPI_CON6,
+ PWRAP_RG_SPI_CON7,
+ PWRAP_RG_SPI_CON8,
+ PWRAP_RG_SPI_CON13,
+ PWRAP_SPISLV_KEY,
+
/* MT6397 only regs */
PWRAP_DEW_EVENT_OUT_EN,
PWRAP_DEW_EVENT_SRC_EN,
@@ -100,10 +128,6 @@ enum dew_regs {
PWRAP_DEW_EVENT_TEST,
PWRAP_DEW_CIPHER_LOAD,
PWRAP_DEW_CIPHER_START,
-
- /* MT6323 only regs */
- PWRAP_DEW_CIPHER_EN,
- PWRAP_DEW_RDDMY_NO,
};
static const u32 mt6323_regs[] = {
@@ -123,6 +147,64 @@ static const u32 mt6323_regs[] = {
[PWRAP_DEW_RDDMY_NO] = 0x01a4,
};
+static const u32 mt6351_regs[] = {
+ [PWRAP_DEW_DIO_EN] = 0x02F2,
+ [PWRAP_DEW_READ_TEST] = 0x02F4,
+ [PWRAP_DEW_WRITE_TEST] = 0x02F6,
+ [PWRAP_DEW_CRC_EN] = 0x02FA,
+ [PWRAP_DEW_CRC_VAL] = 0x02FC,
+ [PWRAP_DEW_CIPHER_KEY_SEL] = 0x0300,
+ [PWRAP_DEW_CIPHER_IV_SEL] = 0x0302,
+ [PWRAP_DEW_CIPHER_EN] = 0x0304,
+ [PWRAP_DEW_CIPHER_RDY] = 0x0306,
+ [PWRAP_DEW_CIPHER_MODE] = 0x0308,
+ [PWRAP_DEW_CIPHER_SWRST] = 0x030A,
+ [PWRAP_DEW_RDDMY_NO] = 0x030C,
+};
+
+static const u32 mt6357_regs[] = {
+ [PWRAP_DEW_DIO_EN] = 0x040A,
+ [PWRAP_DEW_READ_TEST] = 0x040C,
+ [PWRAP_DEW_WRITE_TEST] = 0x040E,
+ [PWRAP_DEW_CRC_EN] = 0x0412,
+ [PWRAP_DEW_CRC_VAL] = 0x0414,
+ [PWRAP_DEW_CIPHER_KEY_SEL] = 0x0418,
+ [PWRAP_DEW_CIPHER_IV_SEL] = 0x041A,
+ [PWRAP_DEW_CIPHER_EN] = 0x041C,
+ [PWRAP_DEW_CIPHER_RDY] = 0x041E,
+ [PWRAP_DEW_CIPHER_MODE] = 0x0420,
+ [PWRAP_DEW_CIPHER_SWRST] = 0x0422,
+ [PWRAP_DEW_RDDMY_NO] = 0x0424,
+};
+
+static const u32 mt6358_regs[] = {
+ [PWRAP_SMT_CON1] = 0x0030,
+ [PWRAP_DRV_CON1] = 0x0038,
+ [PWRAP_FILTER_CON0] = 0x0040,
+ [PWRAP_GPIO_PULLEN0_CLR] = 0x0098,
+ [PWRAP_RG_SPI_CON0] = 0x0408,
+ [PWRAP_RG_SPI_RECORD0] = 0x040a,
+ [PWRAP_DEW_DIO_EN] = 0x040c,
+ [PWRAP_DEW_READ_TEST] = 0x040e,
+ [PWRAP_DEW_WRITE_TEST] = 0x0410,
+ [PWRAP_DEW_CRC_EN] = 0x0414,
+ [PWRAP_DEW_CIPHER_KEY_SEL] = 0x041a,
+ [PWRAP_DEW_CIPHER_IV_SEL] = 0x041c,
+ [PWRAP_DEW_CIPHER_EN] = 0x041e,
+ [PWRAP_DEW_CIPHER_RDY] = 0x0420,
+ [PWRAP_DEW_CIPHER_MODE] = 0x0422,
+ [PWRAP_DEW_CIPHER_SWRST] = 0x0424,
+ [PWRAP_RG_SPI_CON2] = 0x0432,
+ [PWRAP_RG_SPI_CON3] = 0x0434,
+ [PWRAP_RG_SPI_CON4] = 0x0436,
+ [PWRAP_RG_SPI_CON5] = 0x0438,
+ [PWRAP_RG_SPI_CON6] = 0x043a,
+ [PWRAP_RG_SPI_CON7] = 0x043c,
+ [PWRAP_RG_SPI_CON8] = 0x043e,
+ [PWRAP_RG_SPI_CON13] = 0x0448,
+ [PWRAP_SPISLV_KEY] = 0x044a,
+};
+
static const u32 mt6397_regs[] = {
[PWRAP_DEW_BASE] = 0xbc00,
[PWRAP_DEW_EVENT_OUT_EN] = 0xbc00,
@@ -146,21 +228,6 @@ static const u32 mt6397_regs[] = {
[PWRAP_DEW_CIPHER_SWRST] = 0xbc24,
};
-static const u32 mt6351_regs[] = {
- [PWRAP_DEW_DIO_EN] = 0x02F2,
- [PWRAP_DEW_READ_TEST] = 0x02F4,
- [PWRAP_DEW_WRITE_TEST] = 0x02F6,
- [PWRAP_DEW_CRC_EN] = 0x02FA,
- [PWRAP_DEW_CRC_VAL] = 0x02FC,
- [PWRAP_DEW_CIPHER_KEY_SEL] = 0x0300,
- [PWRAP_DEW_CIPHER_IV_SEL] = 0x0302,
- [PWRAP_DEW_CIPHER_EN] = 0x0304,
- [PWRAP_DEW_CIPHER_RDY] = 0x0306,
- [PWRAP_DEW_CIPHER_MODE] = 0x0308,
- [PWRAP_DEW_CIPHER_SWRST] = 0x030A,
- [PWRAP_DEW_RDDMY_NO] = 0x030C,
-};
-
enum pwrap_regs {
PWRAP_MUX_SEL,
PWRAP_WRAP_EN,
@@ -221,6 +288,8 @@ enum pwrap_regs {
PWRAP_CIPHER_SWRST,
PWRAP_DCM_EN,
PWRAP_DCM_DBC_PRD,
+ PWRAP_EINT_STA0_ADR,
+ PWRAP_EINT_STA1_ADR,
/* MT2701 only regs */
PWRAP_ADC_CMD_ADDR,
@@ -230,8 +299,6 @@ enum pwrap_regs {
PWRAP_ADC_RDATA_ADDR2,
/* MT7622 only regs */
- PWRAP_EINT_STA0_ADR,
- PWRAP_EINT_STA1_ADR,
PWRAP_STA,
PWRAP_CLR,
PWRAP_DVFS_ADR8,
@@ -293,6 +360,27 @@ enum pwrap_regs {
PWRAP_DVFS_WDATA7,
PWRAP_SPMINF_STA,
PWRAP_CIPHER_EN,
+
+ /* MT8183 only regs */
+ PWRAP_SI_SAMPLE_CTRL,
+ PWRAP_CSLEXT_WRITE,
+ PWRAP_CSLEXT_READ,
+ PWRAP_EXT_CK_WRITE,
+ PWRAP_STAUPD_CTRL,
+ PWRAP_WACS_P2P_EN,
+ PWRAP_INIT_DONE_P2P,
+ PWRAP_WACS_MD32_EN,
+ PWRAP_INIT_DONE_MD32,
+ PWRAP_INT1_EN,
+ PWRAP_INT1_FLG,
+ PWRAP_INT1_CLR,
+ PWRAP_WDT_SRC_EN_1,
+ PWRAP_INT_GPS_AUXADC_CMD_ADDR,
+ PWRAP_INT_GPS_AUXADC_CMD,
+ PWRAP_INT_GPS_AUXADC_RDATA_ADDR,
+ PWRAP_EXT_GPS_AUXADC_RDATA_ADDR,
+ PWRAP_GPSINF_0_STA,
+ PWRAP_GPSINF_1_STA,
};
static int mt2701_regs[] = {
@@ -381,6 +469,38 @@ static int mt2701_regs[] = {
[PWRAP_ADC_RDATA_ADDR2] = 0x154,
};
+static int mt6765_regs[] = {
+ [PWRAP_MUX_SEL] = 0x0,
+ [PWRAP_WRAP_EN] = 0x4,
+ [PWRAP_DIO_EN] = 0x8,
+ [PWRAP_RDDMY] = 0x20,
+ [PWRAP_CSHEXT_WRITE] = 0x24,
+ [PWRAP_CSHEXT_READ] = 0x28,
+ [PWRAP_CSLEXT_START] = 0x2C,
+ [PWRAP_CSLEXT_END] = 0x30,
+ [PWRAP_STAUPD_PRD] = 0x3C,
+ [PWRAP_HARB_HPRIO] = 0x68,
+ [PWRAP_HIPRIO_ARB_EN] = 0x6C,
+ [PWRAP_MAN_EN] = 0x7C,
+ [PWRAP_MAN_CMD] = 0x80,
+ [PWRAP_WACS0_EN] = 0x8C,
+ [PWRAP_WACS1_EN] = 0x94,
+ [PWRAP_WACS2_EN] = 0x9C,
+ [PWRAP_INIT_DONE2] = 0xA0,
+ [PWRAP_WACS2_CMD] = 0xC20,
+ [PWRAP_WACS2_RDATA] = 0xC24,
+ [PWRAP_WACS2_VLDCLR] = 0xC28,
+ [PWRAP_INT_EN] = 0xB4,
+ [PWRAP_INT_FLG_RAW] = 0xB8,
+ [PWRAP_INT_FLG] = 0xBC,
+ [PWRAP_INT_CLR] = 0xC0,
+ [PWRAP_TIMER_EN] = 0xE8,
+ [PWRAP_WDT_UNIT] = 0xF0,
+ [PWRAP_WDT_SRC_EN] = 0xF4,
+ [PWRAP_DCM_EN] = 0x1DC,
+ [PWRAP_DCM_DBC_PRD] = 0x1E0,
+};
+
static int mt6797_regs[] = {
[PWRAP_MUX_SEL] = 0x0,
[PWRAP_WRAP_EN] = 0x4,
@@ -526,6 +646,79 @@ static int mt7622_regs[] = {
[PWRAP_SPI2_CTRL] = 0x244,
};
+static int mt8135_regs[] = {
+ [PWRAP_MUX_SEL] = 0x0,
+ [PWRAP_WRAP_EN] = 0x4,
+ [PWRAP_DIO_EN] = 0x8,
+ [PWRAP_SIDLY] = 0xc,
+ [PWRAP_CSHEXT] = 0x10,
+ [PWRAP_CSHEXT_WRITE] = 0x14,
+ [PWRAP_CSHEXT_READ] = 0x18,
+ [PWRAP_CSLEXT_START] = 0x1c,
+ [PWRAP_CSLEXT_END] = 0x20,
+ [PWRAP_STAUPD_PRD] = 0x24,
+ [PWRAP_STAUPD_GRPEN] = 0x28,
+ [PWRAP_STAUPD_MAN_TRIG] = 0x2c,
+ [PWRAP_STAUPD_STA] = 0x30,
+ [PWRAP_EVENT_IN_EN] = 0x34,
+ [PWRAP_EVENT_DST_EN] = 0x38,
+ [PWRAP_WRAP_STA] = 0x3c,
+ [PWRAP_RRARB_INIT] = 0x40,
+ [PWRAP_RRARB_EN] = 0x44,
+ [PWRAP_RRARB_STA0] = 0x48,
+ [PWRAP_RRARB_STA1] = 0x4c,
+ [PWRAP_HARB_INIT] = 0x50,
+ [PWRAP_HARB_HPRIO] = 0x54,
+ [PWRAP_HIPRIO_ARB_EN] = 0x58,
+ [PWRAP_HARB_STA0] = 0x5c,
+ [PWRAP_HARB_STA1] = 0x60,
+ [PWRAP_MAN_EN] = 0x64,
+ [PWRAP_MAN_CMD] = 0x68,
+ [PWRAP_MAN_RDATA] = 0x6c,
+ [PWRAP_MAN_VLDCLR] = 0x70,
+ [PWRAP_WACS0_EN] = 0x74,
+ [PWRAP_INIT_DONE0] = 0x78,
+ [PWRAP_WACS0_CMD] = 0x7c,
+ [PWRAP_WACS0_RDATA] = 0x80,
+ [PWRAP_WACS0_VLDCLR] = 0x84,
+ [PWRAP_WACS1_EN] = 0x88,
+ [PWRAP_INIT_DONE1] = 0x8c,
+ [PWRAP_WACS1_CMD] = 0x90,
+ [PWRAP_WACS1_RDATA] = 0x94,
+ [PWRAP_WACS1_VLDCLR] = 0x98,
+ [PWRAP_WACS2_EN] = 0x9c,
+ [PWRAP_INIT_DONE2] = 0xa0,
+ [PWRAP_WACS2_CMD] = 0xa4,
+ [PWRAP_WACS2_RDATA] = 0xa8,
+ [PWRAP_WACS2_VLDCLR] = 0xac,
+ [PWRAP_INT_EN] = 0xb0,
+ [PWRAP_INT_FLG_RAW] = 0xb4,
+ [PWRAP_INT_FLG] = 0xb8,
+ [PWRAP_INT_CLR] = 0xbc,
+ [PWRAP_SIG_ADR] = 0xc0,
+ [PWRAP_SIG_MODE] = 0xc4,
+ [PWRAP_SIG_VALUE] = 0xc8,
+ [PWRAP_SIG_ERRVAL] = 0xcc,
+ [PWRAP_CRC_EN] = 0xd0,
+ [PWRAP_EVENT_STA] = 0xd4,
+ [PWRAP_EVENT_STACLR] = 0xd8,
+ [PWRAP_TIMER_EN] = 0xdc,
+ [PWRAP_TIMER_STA] = 0xe0,
+ [PWRAP_WDT_UNIT] = 0xe4,
+ [PWRAP_WDT_SRC_EN] = 0xe8,
+ [PWRAP_WDT_FLG] = 0xec,
+ [PWRAP_DEBUG_INT_SEL] = 0xf0,
+ [PWRAP_CIPHER_KEY_SEL] = 0x134,
+ [PWRAP_CIPHER_IV_SEL] = 0x138,
+ [PWRAP_CIPHER_LOAD] = 0x13c,
+ [PWRAP_CIPHER_START] = 0x140,
+ [PWRAP_CIPHER_RDY] = 0x144,
+ [PWRAP_CIPHER_MODE] = 0x148,
+ [PWRAP_CIPHER_SWRST] = 0x14c,
+ [PWRAP_DCM_EN] = 0x15c,
+ [PWRAP_DCM_DBC_PRD] = 0x160,
+};
+
static int mt8173_regs[] = {
[PWRAP_MUX_SEL] = 0x0,
[PWRAP_WRAP_EN] = 0x4,
@@ -608,92 +801,74 @@ static int mt8173_regs[] = {
[PWRAP_DCM_DBC_PRD] = 0x148,
};
-static int mt8135_regs[] = {
- [PWRAP_MUX_SEL] = 0x0,
- [PWRAP_WRAP_EN] = 0x4,
- [PWRAP_DIO_EN] = 0x8,
- [PWRAP_SIDLY] = 0xc,
- [PWRAP_CSHEXT] = 0x10,
- [PWRAP_CSHEXT_WRITE] = 0x14,
- [PWRAP_CSHEXT_READ] = 0x18,
- [PWRAP_CSLEXT_START] = 0x1c,
- [PWRAP_CSLEXT_END] = 0x20,
- [PWRAP_STAUPD_PRD] = 0x24,
- [PWRAP_STAUPD_GRPEN] = 0x28,
- [PWRAP_STAUPD_MAN_TRIG] = 0x2c,
- [PWRAP_STAUPD_STA] = 0x30,
- [PWRAP_EVENT_IN_EN] = 0x34,
- [PWRAP_EVENT_DST_EN] = 0x38,
- [PWRAP_WRAP_STA] = 0x3c,
- [PWRAP_RRARB_INIT] = 0x40,
- [PWRAP_RRARB_EN] = 0x44,
- [PWRAP_RRARB_STA0] = 0x48,
- [PWRAP_RRARB_STA1] = 0x4c,
- [PWRAP_HARB_INIT] = 0x50,
- [PWRAP_HARB_HPRIO] = 0x54,
- [PWRAP_HIPRIO_ARB_EN] = 0x58,
- [PWRAP_HARB_STA0] = 0x5c,
- [PWRAP_HARB_STA1] = 0x60,
- [PWRAP_MAN_EN] = 0x64,
- [PWRAP_MAN_CMD] = 0x68,
- [PWRAP_MAN_RDATA] = 0x6c,
- [PWRAP_MAN_VLDCLR] = 0x70,
- [PWRAP_WACS0_EN] = 0x74,
- [PWRAP_INIT_DONE0] = 0x78,
- [PWRAP_WACS0_CMD] = 0x7c,
- [PWRAP_WACS0_RDATA] = 0x80,
- [PWRAP_WACS0_VLDCLR] = 0x84,
- [PWRAP_WACS1_EN] = 0x88,
- [PWRAP_INIT_DONE1] = 0x8c,
- [PWRAP_WACS1_CMD] = 0x90,
- [PWRAP_WACS1_RDATA] = 0x94,
- [PWRAP_WACS1_VLDCLR] = 0x98,
- [PWRAP_WACS2_EN] = 0x9c,
- [PWRAP_INIT_DONE2] = 0xa0,
- [PWRAP_WACS2_CMD] = 0xa4,
- [PWRAP_WACS2_RDATA] = 0xa8,
- [PWRAP_WACS2_VLDCLR] = 0xac,
- [PWRAP_INT_EN] = 0xb0,
- [PWRAP_INT_FLG_RAW] = 0xb4,
- [PWRAP_INT_FLG] = 0xb8,
- [PWRAP_INT_CLR] = 0xbc,
- [PWRAP_SIG_ADR] = 0xc0,
- [PWRAP_SIG_MODE] = 0xc4,
- [PWRAP_SIG_VALUE] = 0xc8,
- [PWRAP_SIG_ERRVAL] = 0xcc,
- [PWRAP_CRC_EN] = 0xd0,
- [PWRAP_EVENT_STA] = 0xd4,
- [PWRAP_EVENT_STACLR] = 0xd8,
- [PWRAP_TIMER_EN] = 0xdc,
- [PWRAP_TIMER_STA] = 0xe0,
- [PWRAP_WDT_UNIT] = 0xe4,
- [PWRAP_WDT_SRC_EN] = 0xe8,
- [PWRAP_WDT_FLG] = 0xec,
- [PWRAP_DEBUG_INT_SEL] = 0xf0,
- [PWRAP_CIPHER_KEY_SEL] = 0x134,
- [PWRAP_CIPHER_IV_SEL] = 0x138,
- [PWRAP_CIPHER_LOAD] = 0x13c,
- [PWRAP_CIPHER_START] = 0x140,
- [PWRAP_CIPHER_RDY] = 0x144,
- [PWRAP_CIPHER_MODE] = 0x148,
- [PWRAP_CIPHER_SWRST] = 0x14c,
- [PWRAP_DCM_EN] = 0x15c,
- [PWRAP_DCM_DBC_PRD] = 0x160,
+static int mt8183_regs[] = {
+ [PWRAP_MUX_SEL] = 0x0,
+ [PWRAP_WRAP_EN] = 0x4,
+ [PWRAP_DIO_EN] = 0x8,
+ [PWRAP_SI_SAMPLE_CTRL] = 0xC,
+ [PWRAP_RDDMY] = 0x14,
+ [PWRAP_CSHEXT_WRITE] = 0x18,
+ [PWRAP_CSHEXT_READ] = 0x1C,
+ [PWRAP_CSLEXT_WRITE] = 0x20,
+ [PWRAP_CSLEXT_READ] = 0x24,
+ [PWRAP_EXT_CK_WRITE] = 0x28,
+ [PWRAP_STAUPD_CTRL] = 0x30,
+ [PWRAP_STAUPD_GRPEN] = 0x34,
+ [PWRAP_EINT_STA0_ADR] = 0x38,
+ [PWRAP_HARB_HPRIO] = 0x5C,
+ [PWRAP_HIPRIO_ARB_EN] = 0x60,
+ [PWRAP_MAN_EN] = 0x70,
+ [PWRAP_MAN_CMD] = 0x74,
+ [PWRAP_WACS0_EN] = 0x80,
+ [PWRAP_INIT_DONE0] = 0x84,
+ [PWRAP_WACS1_EN] = 0x88,
+ [PWRAP_INIT_DONE1] = 0x8C,
+ [PWRAP_WACS2_EN] = 0x90,
+ [PWRAP_INIT_DONE2] = 0x94,
+ [PWRAP_WACS_P2P_EN] = 0xA0,
+ [PWRAP_INIT_DONE_P2P] = 0xA4,
+ [PWRAP_WACS_MD32_EN] = 0xA8,
+ [PWRAP_INIT_DONE_MD32] = 0xAC,
+ [PWRAP_INT_EN] = 0xB0,
+ [PWRAP_INT_FLG] = 0xB8,
+ [PWRAP_INT_CLR] = 0xBC,
+ [PWRAP_INT1_EN] = 0xC0,
+ [PWRAP_INT1_FLG] = 0xC8,
+ [PWRAP_INT1_CLR] = 0xCC,
+ [PWRAP_SIG_ADR] = 0xD0,
+ [PWRAP_CRC_EN] = 0xE0,
+ [PWRAP_TIMER_EN] = 0xE4,
+ [PWRAP_WDT_UNIT] = 0xEC,
+ [PWRAP_WDT_SRC_EN] = 0xF0,
+ [PWRAP_WDT_SRC_EN_1] = 0xF4,
+ [PWRAP_INT_GPS_AUXADC_CMD_ADDR] = 0x1DC,
+ [PWRAP_INT_GPS_AUXADC_CMD] = 0x1E0,
+ [PWRAP_INT_GPS_AUXADC_RDATA_ADDR] = 0x1E4,
+ [PWRAP_EXT_GPS_AUXADC_RDATA_ADDR] = 0x1E8,
+ [PWRAP_GPSINF_0_STA] = 0x1EC,
+ [PWRAP_GPSINF_1_STA] = 0x1F0,
+ [PWRAP_WACS2_CMD] = 0xC20,
+ [PWRAP_WACS2_RDATA] = 0xC24,
+ [PWRAP_WACS2_VLDCLR] = 0xC28,
};
enum pmic_type {
PMIC_MT6323,
PMIC_MT6351,
+ PMIC_MT6357,
+ PMIC_MT6358,
PMIC_MT6380,
PMIC_MT6397,
};
enum pwrap_type {
PWRAP_MT2701,
+ PWRAP_MT6765,
PWRAP_MT6797,
PWRAP_MT7622,
PWRAP_MT8135,
PWRAP_MT8173,
+ PWRAP_MT8183,
};
struct pmic_wrapper;
@@ -731,9 +906,11 @@ struct pmic_wrapper_type {
enum pwrap_type type;
u32 arb_en_all;
u32 int_en_all;
+ u32 int1_en_all;
u32 spi_w;
u32 wdt_src;
- unsigned int has_bridge:1;
+ /* Flags indicating the capability for the target pwrap */
+ u32 caps;
int (*init_reg_clock)(struct pmic_wrapper *wrp);
int (*init_soc_specific)(struct pmic_wrapper *wrp);
};
@@ -1096,7 +1273,7 @@ static bool pwrap_is_pmic_cipher_ready(struct pmic_wrapper *wrp)
ret = pwrap_read(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_RDY],
&rdata);
if (ret)
- return 0;
+ return false;
return rdata == 1;
}
@@ -1117,6 +1294,7 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
pwrap_writel(wrp, 1, PWRAP_CIPHER_START);
break;
case PWRAP_MT2701:
+ case PWRAP_MT6765:
case PWRAP_MT6797:
case PWRAP_MT8173:
pwrap_writel(wrp, 1, PWRAP_CIPHER_EN);
@@ -1124,6 +1302,8 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
case PWRAP_MT7622:
pwrap_writel(wrp, 0, PWRAP_CIPHER_EN);
break;
+ case PWRAP_MT8183:
+ break;
}
/* Config cipher mode @PMIC */
@@ -1141,6 +1321,7 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
break;
case PMIC_MT6323:
case PMIC_MT6351:
+ case PMIC_MT6357:
pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_EN],
0x1);
break;
@@ -1276,6 +1457,23 @@ static int pwrap_mt7622_init_soc_specific(struct pmic_wrapper *wrp)
return 0;
}
+static int pwrap_mt8183_init_soc_specific(struct pmic_wrapper *wrp)
+{
+ pwrap_writel(wrp, 0xf5, PWRAP_STAUPD_GRPEN);
+
+ pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CRC_EN], 0x1);
+ pwrap_writel(wrp, 1, PWRAP_CRC_EN);
+ pwrap_writel(wrp, 0x416, PWRAP_SIG_ADR);
+ pwrap_writel(wrp, 0x42e, PWRAP_EINT_STA0_ADR);
+
+ pwrap_writel(wrp, 1, PWRAP_WACS_P2P_EN);
+ pwrap_writel(wrp, 1, PWRAP_WACS_MD32_EN);
+ pwrap_writel(wrp, 1, PWRAP_INIT_DONE_P2P);
+ pwrap_writel(wrp, 1, PWRAP_INIT_DONE_MD32);
+
+ return 0;
+}
+
static int pwrap_init(struct pmic_wrapper *wrp)
{
int ret;
@@ -1348,7 +1546,7 @@ static int pwrap_init(struct pmic_wrapper *wrp)
pwrap_writel(wrp, 1, PWRAP_INIT_DONE0);
pwrap_writel(wrp, 1, PWRAP_INIT_DONE1);
- if (wrp->master->has_bridge) {
+ if (HAS_CAP(wrp->master->caps, PWRAP_CAP_BRIDGE)) {
writel(1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_INIT_DONE3);
writel(1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_INIT_DONE4);
}
@@ -1362,11 +1560,15 @@ static irqreturn_t pwrap_interrupt(int irqno, void *dev_id)
struct pmic_wrapper *wrp = dev_id;
rdata = pwrap_readl(wrp, PWRAP_INT_FLG);
-
dev_err(wrp->dev, "unexpected interrupt int=0x%x\n", rdata);
-
pwrap_writel(wrp, 0xffffffff, PWRAP_INT_CLR);
+ if (HAS_CAP(wrp->master->caps, PWRAP_CAP_INT1_EN)) {
+ rdata = pwrap_readl(wrp, PWRAP_INT1_FLG);
+ dev_err(wrp->dev, "unexpected interrupt int1=0x%x\n", rdata);
+ pwrap_writel(wrp, 0xffffffff, PWRAP_INT1_CLR);
+ }
+
return IRQ_HANDLED;
}
@@ -1398,6 +1600,33 @@ static const struct pwrap_slv_type pmic_mt6323 = {
.pwrap_write = pwrap_write16,
};
+static const struct pwrap_slv_type pmic_mt6351 = {
+ .dew_regs = mt6351_regs,
+ .type = PMIC_MT6351,
+ .regmap = &pwrap_regmap_config16,
+ .caps = 0,
+ .pwrap_read = pwrap_read16,
+ .pwrap_write = pwrap_write16,
+};
+
+static const struct pwrap_slv_type pmic_mt6357 = {
+ .dew_regs = mt6357_regs,
+ .type = PMIC_MT6357,
+ .regmap = &pwrap_regmap_config16,
+ .caps = 0,
+ .pwrap_read = pwrap_read16,
+ .pwrap_write = pwrap_write16,
+};
+
+static const struct pwrap_slv_type pmic_mt6358 = {
+ .dew_regs = mt6358_regs,
+ .type = PMIC_MT6358,
+ .regmap = &pwrap_regmap_config16,
+ .caps = PWRAP_SLV_CAP_SPI | PWRAP_SLV_CAP_DUALIO,
+ .pwrap_read = pwrap_read16,
+ .pwrap_write = pwrap_write16,
+};
+
static const struct pwrap_slv_type pmic_mt6380 = {
.dew_regs = NULL,
.type = PMIC_MT6380,
@@ -1417,20 +1646,20 @@ static const struct pwrap_slv_type pmic_mt6397 = {
.pwrap_write = pwrap_write16,
};
-static const struct pwrap_slv_type pmic_mt6351 = {
- .dew_regs = mt6351_regs,
- .type = PMIC_MT6351,
- .regmap = &pwrap_regmap_config16,
- .caps = 0,
- .pwrap_read = pwrap_read16,
- .pwrap_write = pwrap_write16,
-};
-
static const struct of_device_id of_slave_match_tbl[] = {
{
.compatible = "mediatek,mt6323",
.data = &pmic_mt6323,
}, {
+ .compatible = "mediatek,mt6351",
+ .data = &pmic_mt6351,
+ }, {
+ .compatible = "mediatek,mt6357",
+ .data = &pmic_mt6357,
+ }, {
+ .compatible = "mediatek,mt6358",
+ .data = &pmic_mt6358,
+ }, {
/* The MT6380 PMIC only implements a regulator, so we bind it
* directly instead of using a MFD.
*/
@@ -1440,9 +1669,6 @@ static const struct of_device_id of_slave_match_tbl[] = {
.compatible = "mediatek,mt6397",
.data = &pmic_mt6397,
}, {
- .compatible = "mediatek,mt6351",
- .data = &pmic_mt6351,
- }, {
/* sentinel */
}
};
@@ -1453,21 +1679,35 @@ static const struct pmic_wrapper_type pwrap_mt2701 = {
.type = PWRAP_MT2701,
.arb_en_all = 0x3f,
.int_en_all = ~(u32)(BIT(31) | BIT(2)),
+ .int1_en_all = 0,
.spi_w = PWRAP_MAN_CMD_SPI_WRITE_NEW,
.wdt_src = PWRAP_WDT_SRC_MASK_ALL,
- .has_bridge = 0,
+ .caps = PWRAP_CAP_RESET | PWRAP_CAP_DCM,
.init_reg_clock = pwrap_mt2701_init_reg_clock,
.init_soc_specific = pwrap_mt2701_init_soc_specific,
};
+static const struct pmic_wrapper_type pwrap_mt6765 = {
+ .regs = mt6765_regs,
+ .type = PWRAP_MT6765,
+ .arb_en_all = 0x3fd35,
+ .int_en_all = 0xffffffff,
+ .spi_w = PWRAP_MAN_CMD_SPI_WRITE,
+ .wdt_src = PWRAP_WDT_SRC_MASK_ALL,
+ .caps = PWRAP_CAP_RESET | PWRAP_CAP_DCM,
+ .init_reg_clock = pwrap_common_init_reg_clock,
+ .init_soc_specific = NULL,
+};
+
static const struct pmic_wrapper_type pwrap_mt6797 = {
.regs = mt6797_regs,
.type = PWRAP_MT6797,
.arb_en_all = 0x01fff,
.int_en_all = 0xffffffc6,
+ .int1_en_all = 0,
.spi_w = PWRAP_MAN_CMD_SPI_WRITE,
.wdt_src = PWRAP_WDT_SRC_MASK_ALL,
- .has_bridge = 0,
+ .caps = PWRAP_CAP_RESET | PWRAP_CAP_DCM,
.init_reg_clock = pwrap_common_init_reg_clock,
.init_soc_specific = NULL,
};
@@ -1477,9 +1717,10 @@ static const struct pmic_wrapper_type pwrap_mt7622 = {
.type = PWRAP_MT7622,
.arb_en_all = 0xff,
.int_en_all = ~(u32)BIT(31),
+ .int1_en_all = 0,
.spi_w = PWRAP_MAN_CMD_SPI_WRITE,
.wdt_src = PWRAP_WDT_SRC_MASK_ALL,
- .has_bridge = 0,
+ .caps = PWRAP_CAP_RESET | PWRAP_CAP_DCM,
.init_reg_clock = pwrap_common_init_reg_clock,
.init_soc_specific = pwrap_mt7622_init_soc_specific,
};
@@ -1489,9 +1730,10 @@ static const struct pmic_wrapper_type pwrap_mt8135 = {
.type = PWRAP_MT8135,
.arb_en_all = 0x1ff,
.int_en_all = ~(u32)(BIT(31) | BIT(1)),
+ .int1_en_all = 0,
.spi_w = PWRAP_MAN_CMD_SPI_WRITE,
.wdt_src = PWRAP_WDT_SRC_MASK_ALL,
- .has_bridge = 1,
+ .caps = PWRAP_CAP_BRIDGE | PWRAP_CAP_RESET | PWRAP_CAP_DCM,
.init_reg_clock = pwrap_common_init_reg_clock,
.init_soc_specific = pwrap_mt8135_init_soc_specific,
};
@@ -1501,18 +1743,35 @@ static const struct pmic_wrapper_type pwrap_mt8173 = {
.type = PWRAP_MT8173,
.arb_en_all = 0x3f,
.int_en_all = ~(u32)(BIT(31) | BIT(1)),
+ .int1_en_all = 0,
.spi_w = PWRAP_MAN_CMD_SPI_WRITE,
.wdt_src = PWRAP_WDT_SRC_MASK_NO_STAUPD,
- .has_bridge = 0,
+ .caps = PWRAP_CAP_RESET | PWRAP_CAP_DCM,
.init_reg_clock = pwrap_common_init_reg_clock,
.init_soc_specific = pwrap_mt8173_init_soc_specific,
};
+static const struct pmic_wrapper_type pwrap_mt8183 = {
+ .regs = mt8183_regs,
+ .type = PWRAP_MT8183,
+ .arb_en_all = 0x3fa75,
+ .int_en_all = 0xffffffff,
+ .int1_en_all = 0xeef7ffff,
+ .spi_w = PWRAP_MAN_CMD_SPI_WRITE,
+ .wdt_src = PWRAP_WDT_SRC_MASK_ALL,
+ .caps = PWRAP_CAP_INT1_EN | PWRAP_CAP_WDT_SRC1,
+ .init_reg_clock = pwrap_common_init_reg_clock,
+ .init_soc_specific = pwrap_mt8183_init_soc_specific,
+};
+
static const struct of_device_id of_pwrap_match_tbl[] = {
{
.compatible = "mediatek,mt2701-pwrap",
.data = &pwrap_mt2701,
}, {
+ .compatible = "mediatek,mt6765-pwrap",
+ .data = &pwrap_mt6765,
+ }, {
.compatible = "mediatek,mt6797-pwrap",
.data = &pwrap_mt6797,
}, {
@@ -1525,6 +1784,9 @@ static const struct of_device_id of_pwrap_match_tbl[] = {
.compatible = "mediatek,mt8173-pwrap",
.data = &pwrap_mt8173,
}, {
+ .compatible = "mediatek,mt8183-pwrap",
+ .data = &pwrap_mt8183,
+ }, {
/* sentinel */
}
};
@@ -1561,14 +1823,16 @@ static int pwrap_probe(struct platform_device *pdev)
if (IS_ERR(wrp->base))
return PTR_ERR(wrp->base);
- wrp->rstc = devm_reset_control_get(wrp->dev, "pwrap");
- if (IS_ERR(wrp->rstc)) {
- ret = PTR_ERR(wrp->rstc);
- dev_dbg(wrp->dev, "cannot get pwrap reset: %d\n", ret);
- return ret;
+ if (HAS_CAP(wrp->master->caps, PWRAP_CAP_RESET)) {
+ wrp->rstc = devm_reset_control_get(wrp->dev, "pwrap");
+ if (IS_ERR(wrp->rstc)) {
+ ret = PTR_ERR(wrp->rstc);
+ dev_dbg(wrp->dev, "cannot get pwrap reset: %d\n", ret);
+ return ret;
+ }
}
- if (wrp->master->has_bridge) {
+ if (HAS_CAP(wrp->master->caps, PWRAP_CAP_BRIDGE)) {
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"pwrap-bridge");
wrp->bridge_base = devm_ioremap_resource(wrp->dev, res);
@@ -1608,8 +1872,10 @@ static int pwrap_probe(struct platform_device *pdev)
goto err_out1;
/* Enable internal dynamic clock */
- pwrap_writel(wrp, 1, PWRAP_DCM_EN);
- pwrap_writel(wrp, 0, PWRAP_DCM_DBC_PRD);
+ if (HAS_CAP(wrp->master->caps, PWRAP_CAP_DCM)) {
+ pwrap_writel(wrp, 1, PWRAP_DCM_EN);
+ pwrap_writel(wrp, 0, PWRAP_DCM_DBC_PRD);
+ }
/*
* The PMIC could already be initialized by the bootloader.
@@ -1636,8 +1902,17 @@ static int pwrap_probe(struct platform_device *pdev)
* so STAUPD of WDT_SRC which should be turned off
*/
pwrap_writel(wrp, wrp->master->wdt_src, PWRAP_WDT_SRC_EN);
+ if (HAS_CAP(wrp->master->caps, PWRAP_CAP_WDT_SRC1))
+ pwrap_writel(wrp, wrp->master->wdt_src, PWRAP_WDT_SRC_EN_1);
+
pwrap_writel(wrp, 0x1, PWRAP_TIMER_EN);
pwrap_writel(wrp, wrp->master->int_en_all, PWRAP_INT_EN);
+ /*
+ * We add INT1 interrupt to handle starvation and request exception
+ * If we support it, we should enable it here.
+ */
+ if (HAS_CAP(wrp->master->caps, PWRAP_CAP_INT1_EN))
+ pwrap_writel(wrp, wrp->master->int1_en_all, PWRAP_INT1_EN);
irq = platform_get_irq(pdev, 0);
ret = devm_request_irq(wrp->dev, irq, pwrap_interrupt,
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index ba79b609aca2..684cb51694d1 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -33,7 +33,7 @@ config QCOM_GLINK_SSR
config QCOM_GSBI
tristate "QCOM General Serial Bus Interface"
- depends on ARCH_QCOM
+ depends on ARCH_QCOM || COMPILE_TEST
select MFD_SYSCON
help
Say y here to enable GSBI support. The GSBI provides control
@@ -42,7 +42,7 @@ config QCOM_GSBI
config QCOM_LLCC
tristate "Qualcomm Technologies, Inc. LLCC driver"
- depends on ARCH_QCOM
+ depends on ARCH_QCOM || COMPILE_TEST
help
Qualcomm Technologies, Inc. platform specific
Last Level Cache Controller(LLCC) driver. This provides interfaces
@@ -73,7 +73,8 @@ config QCOM_PM
config QCOM_QMI_HELPERS
tristate
- depends on ARCH_QCOM && NET
+ depends on ARCH_QCOM || COMPILE_TEST
+ depends on NET
help
Helper library for handling QMI encoded messages. QMI encoded
messages are used in communication between the majority of QRTR
@@ -94,7 +95,7 @@ config QCOM_RMTFS_MEM
config QCOM_RPMH
bool "Qualcomm RPM-Hardened (RPMH) Communication"
- depends on ARCH_QCOM && ARM64 && OF || COMPILE_TEST
+ depends on ARCH_QCOM && ARM64 || COMPILE_TEST
help
Support for communication with the hardened-RPM blocks in
Qualcomm Technologies Inc (QTI) SoCs. RPMH communication uses an
@@ -104,7 +105,7 @@ config QCOM_RPMH
config QCOM_SMEM
tristate "Qualcomm Shared Memory Manager (SMEM)"
- depends on ARCH_QCOM
+ depends on ARCH_QCOM || COMPILE_TEST
depends on HWSPINLOCK
help
Say y here to enable support for the Qualcomm Shared Memory Manager.
@@ -113,8 +114,8 @@ config QCOM_SMEM
config QCOM_SMD_RPM
tristate "Qualcomm Resource Power Manager (RPM) over SMD"
- depends on ARCH_QCOM
- depends on RPMSG && OF
+ depends on ARCH_QCOM || COMPILE_TEST
+ depends on RPMSG
help
If you say yes to this option, support will be included for the
Resource Power Manager system found in the Qualcomm 8974 based
@@ -134,6 +135,7 @@ config QCOM_SMP2P
depends on MAILBOX
depends on QCOM_SMEM
select QCOM_SMEM_STATE
+ select IRQ_DOMAIN
help
Say yes here to support the Qualcomm Shared Memory Point to Point
protocol.
@@ -142,13 +144,14 @@ config QCOM_SMSM
tristate "Qualcomm Shared Memory State Machine"
depends on QCOM_SMEM
select QCOM_SMEM_STATE
+ select IRQ_DOMAIN
help
Say yes here to support the Qualcomm Shared Memory State Machine.
The state machine is represented by bits in shared memory.
config QCOM_WCNSS_CTRL
tristate "Qualcomm WCNSS control driver"
- depends on ARCH_QCOM
+ depends on ARCH_QCOM || COMPILE_TEST
depends on RPMSG
help
Client driver for the WCNSS_CTRL SMD channel, used to download nv
@@ -156,7 +159,7 @@ config QCOM_WCNSS_CTRL
config QCOM_APR
tristate "Qualcomm APR Bus (Asynchronous Packet Router)"
- depends on ARCH_QCOM
+ depends on ARCH_QCOM || COMPILE_TEST
depends on RPMSG
help
Enable APR IPC protocol support between
diff --git a/drivers/soc/qcom/apr.c b/drivers/soc/qcom/apr.c
index 57af8a537332..74f8b9607daa 100644
--- a/drivers/soc/qcom/apr.c
+++ b/drivers/soc/qcom/apr.c
@@ -87,7 +87,7 @@ static int apr_callback(struct rpmsg_device *rpdev, void *buf,
}
if (hdr->pkt_size < APR_HDR_SIZE || hdr->pkt_size != len) {
- dev_err(apr->dev, "APR: Wrong paket size\n");
+ dev_err(apr->dev, "APR: Wrong packet size\n");
return -EINVAL;
}
@@ -219,9 +219,9 @@ static int apr_add_device(struct device *dev, struct device_node *np,
adev->domain_id = id->domain_id;
adev->version = id->svc_version;
if (np)
- strncpy(adev->name, np->name, APR_NAME_SIZE);
+ snprintf(adev->name, APR_NAME_SIZE, "%pOFn", np);
else
- strncpy(adev->name, id->name, APR_NAME_SIZE);
+ strscpy(adev->name, id->name, APR_NAME_SIZE);
dev_set_name(&adev->dev, "aprsvc:%s:%x:%x", adev->name,
id->domain_id, id->svc_id);
diff --git a/drivers/soc/qcom/llcc-slice.c b/drivers/soc/qcom/llcc-slice.c
index 54063a31132f..192ca761b2cb 100644
--- a/drivers/soc/qcom/llcc-slice.c
+++ b/drivers/soc/qcom/llcc-slice.c
@@ -13,6 +13,7 @@
#include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
+#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/soc/qcom/llcc-qcom.h>
@@ -106,22 +107,24 @@ static int llcc_update_act_ctrl(u32 sid,
u32 slice_status;
int ret;
- act_ctrl_reg = drv_data->bcast_off + LLCC_TRP_ACT_CTRLn(sid);
- status_reg = drv_data->bcast_off + LLCC_TRP_STATUSn(sid);
+ act_ctrl_reg = LLCC_TRP_ACT_CTRLn(sid);
+ status_reg = LLCC_TRP_STATUSn(sid);
/* Set the ACTIVE trigger */
act_ctrl_reg_val |= ACT_CTRL_ACT_TRIG;
- ret = regmap_write(drv_data->regmap, act_ctrl_reg, act_ctrl_reg_val);
+ ret = regmap_write(drv_data->bcast_regmap, act_ctrl_reg,
+ act_ctrl_reg_val);
if (ret)
return ret;
/* Clear the ACTIVE trigger */
act_ctrl_reg_val &= ~ACT_CTRL_ACT_TRIG;
- ret = regmap_write(drv_data->regmap, act_ctrl_reg, act_ctrl_reg_val);
+ ret = regmap_write(drv_data->bcast_regmap, act_ctrl_reg,
+ act_ctrl_reg_val);
if (ret)
return ret;
- ret = regmap_read_poll_timeout(drv_data->regmap, status_reg,
+ ret = regmap_read_poll_timeout(drv_data->bcast_regmap, status_reg,
slice_status, !(slice_status & status),
0, LLCC_STATUS_READ_DELAY);
return ret;
@@ -223,19 +226,16 @@ static int qcom_llcc_cfg_program(struct platform_device *pdev)
u32 attr0_val;
u32 max_cap_cacheline;
u32 sz;
- int ret;
+ int ret = 0;
const struct llcc_slice_config *llcc_table;
struct llcc_slice_desc desc;
- u32 bcast_off = drv_data->bcast_off;
sz = drv_data->cfg_size;
llcc_table = drv_data->cfg;
for (i = 0; i < sz; i++) {
- attr1_cfg = bcast_off +
- LLCC_TRP_ATTR1_CFGn(llcc_table[i].slice_id);
- attr0_cfg = bcast_off +
- LLCC_TRP_ATTR0_CFGn(llcc_table[i].slice_id);
+ attr1_cfg = LLCC_TRP_ATTR1_CFGn(llcc_table[i].slice_id);
+ attr0_cfg = LLCC_TRP_ATTR0_CFGn(llcc_table[i].slice_id);
attr1_val = llcc_table[i].cache_mode;
attr1_val |= llcc_table[i].probe_target_ways <<
@@ -260,10 +260,12 @@ static int qcom_llcc_cfg_program(struct platform_device *pdev)
attr0_val = llcc_table[i].res_ways & ATTR0_RES_WAYS_MASK;
attr0_val |= llcc_table[i].bonus_ways << ATTR0_BONUS_WAYS_SHIFT;
- ret = regmap_write(drv_data->regmap, attr1_cfg, attr1_val);
+ ret = regmap_write(drv_data->bcast_regmap, attr1_cfg,
+ attr1_val);
if (ret)
return ret;
- ret = regmap_write(drv_data->regmap, attr0_cfg, attr0_val);
+ ret = regmap_write(drv_data->bcast_regmap, attr0_cfg,
+ attr0_val);
if (ret)
return ret;
if (llcc_table[i].activate_on_init) {
@@ -279,24 +281,37 @@ int qcom_llcc_probe(struct platform_device *pdev,
{
u32 num_banks;
struct device *dev = &pdev->dev;
- struct resource *res;
- void __iomem *base;
+ struct resource *llcc_banks_res, *llcc_bcast_res;
+ void __iomem *llcc_banks_base, *llcc_bcast_base;
int ret, i;
+ struct platform_device *llcc_edac;
drv_data = devm_kzalloc(dev, sizeof(*drv_data), GFP_KERNEL);
if (!drv_data)
return -ENOMEM;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(base))
- return PTR_ERR(base);
+ llcc_banks_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "llcc_base");
+ llcc_banks_base = devm_ioremap_resource(&pdev->dev, llcc_banks_res);
+ if (IS_ERR(llcc_banks_base))
+ return PTR_ERR(llcc_banks_base);
- drv_data->regmap = devm_regmap_init_mmio(dev, base,
- &llcc_regmap_config);
+ drv_data->regmap = devm_regmap_init_mmio(dev, llcc_banks_base,
+ &llcc_regmap_config);
if (IS_ERR(drv_data->regmap))
return PTR_ERR(drv_data->regmap);
+ llcc_bcast_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "llcc_broadcast_base");
+ llcc_bcast_base = devm_ioremap_resource(&pdev->dev, llcc_bcast_res);
+ if (IS_ERR(llcc_bcast_base))
+ return PTR_ERR(llcc_bcast_base);
+
+ drv_data->bcast_regmap = devm_regmap_init_mmio(dev, llcc_bcast_base,
+ &llcc_regmap_config);
+ if (IS_ERR(drv_data->bcast_regmap))
+ return PTR_ERR(drv_data->bcast_regmap);
+
ret = regmap_read(drv_data->regmap, LLCC_COMMON_STATUS0,
&num_banks);
if (ret)
@@ -318,8 +333,6 @@ int qcom_llcc_probe(struct platform_device *pdev,
for (i = 0; i < num_banks; i++)
drv_data->offsets[i] = i * BANK_OFFSET_STRIDE;
- drv_data->bcast_off = num_banks * BANK_OFFSET_STRIDE;
-
drv_data->bitmap = devm_kcalloc(dev,
BITS_TO_LONGS(drv_data->max_slices), sizeof(unsigned long),
GFP_KERNEL);
@@ -331,7 +344,20 @@ int qcom_llcc_probe(struct platform_device *pdev,
mutex_init(&drv_data->lock);
platform_set_drvdata(pdev, drv_data);
- return qcom_llcc_cfg_program(pdev);
+ ret = qcom_llcc_cfg_program(pdev);
+ if (ret)
+ return ret;
+
+ drv_data->ecc_irq = platform_get_irq(pdev, 0);
+ if (drv_data->ecc_irq >= 0) {
+ llcc_edac = platform_device_register_data(&pdev->dev,
+ "qcom_llcc_edac", -1, drv_data,
+ sizeof(*drv_data));
+ if (IS_ERR(llcc_edac))
+ dev_err(dev, "Failed to register llcc edac driver\n");
+ }
+
+ return ret;
}
EXPORT_SYMBOL_GPL(qcom_llcc_probe);
diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c
index feed3db21c10..ee89ffb6dde8 100644
--- a/drivers/soc/qcom/qcom-geni-se.c
+++ b/drivers/soc/qcom/qcom-geni-se.c
@@ -513,7 +513,7 @@ EXPORT_SYMBOL(geni_se_resources_on);
*/
int geni_se_clk_tbl_get(struct geni_se *se, unsigned long **tbl)
{
- unsigned long freq = 0;
+ long freq = 0;
int i;
if (se->clk_perf_tbl) {
@@ -529,7 +529,7 @@ int geni_se_clk_tbl_get(struct geni_se *se, unsigned long **tbl)
for (i = 0; i < MAX_CLK_PERF_LEVEL; i++) {
freq = clk_round_rate(se->clk, freq + 1);
- if (!freq || freq == se->clk_perf_tbl[i - 1])
+ if (freq <= 0 || freq == se->clk_perf_tbl[i - 1])
break;
se->clk_perf_tbl[i] = freq;
}
@@ -544,16 +544,17 @@ EXPORT_SYMBOL(geni_se_clk_tbl_get);
* @se: Pointer to the concerned serial engine.
* @req_freq: Requested clock frequency.
* @index: Index of the resultant frequency in the table.
- * @res_freq: Resultant frequency which matches or is closer to the
- * requested frequency.
+ * @res_freq: Resultant frequency of the source clock.
* @exact: Flag to indicate exact multiple requirement of the requested
* frequency.
*
- * This function is called by the protocol drivers to determine the matching
- * or exact multiple of the requested frequency, as provided by the serial
- * engine clock in order to meet the performance requirements. If there is
- * no matching or exact multiple of the requested frequency found, then it
- * selects the closest floor frequency, if exact flag is not set.
+ * This function is called by the protocol drivers to determine the best match
+ * of the requested frequency as provided by the serial engine clock in order
+ * to meet the performance requirements.
+ *
+ * If we return success:
+ * - if @exact is true then @res_freq / <an_integer> == @req_freq
+ * - if @exact is false then @res_freq / <an_integer> <= @req_freq
*
* Return: 0 on success, standard Linux error codes on failure.
*/
@@ -564,6 +565,9 @@ int geni_se_clk_freq_match(struct geni_se *se, unsigned long req_freq,
unsigned long *tbl;
int num_clk_levels;
int i;
+ unsigned long best_delta;
+ unsigned long new_delta;
+ unsigned int divider;
num_clk_levels = geni_se_clk_tbl_get(se, &tbl);
if (num_clk_levels < 0)
@@ -572,18 +576,21 @@ int geni_se_clk_freq_match(struct geni_se *se, unsigned long req_freq,
if (num_clk_levels == 0)
return -EINVAL;
- *res_freq = 0;
+ best_delta = ULONG_MAX;
for (i = 0; i < num_clk_levels; i++) {
- if (!(tbl[i] % req_freq)) {
+ divider = DIV_ROUND_UP(tbl[i], req_freq);
+ new_delta = req_freq - tbl[i] / divider;
+ if (new_delta < best_delta) {
+ /* We have a new best! */
*index = i;
*res_freq = tbl[i];
- return 0;
- }
- if (!(*res_freq) || ((tbl[i] > *res_freq) &&
- (tbl[i] < req_freq))) {
- *index = i;
- *res_freq = tbl[i];
+ /* If the new best is exact then we're done */
+ if (new_delta == 0)
+ return 0;
+
+ /* Record how close we got */
+ best_delta = new_delta;
}
}
diff --git a/drivers/soc/qcom/rmtfs_mem.c b/drivers/soc/qcom/rmtfs_mem.c
index 8a3678c2e83c..97bb5989aa21 100644
--- a/drivers/soc/qcom/rmtfs_mem.c
+++ b/drivers/soc/qcom/rmtfs_mem.c
@@ -212,6 +212,11 @@ static int qcom_rmtfs_mem_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "failed to parse qcom,vmid\n");
goto remove_cdev;
} else if (!ret) {
+ if (!qcom_scm_is_available()) {
+ ret = -EPROBE_DEFER;
+ goto remove_cdev;
+ }
+
perms[0].vmid = QCOM_SCM_VMID_HLOS;
perms[0].perm = QCOM_SCM_PERM_RW;
perms[1].vmid = vmid;
diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
index ee75da66d64b..75bd9a83aef0 100644
--- a/drivers/soc/qcom/rpmh-rsc.c
+++ b/drivers/soc/qcom/rpmh-rsc.c
@@ -121,6 +121,7 @@ static int tcs_invalidate(struct rsc_drv *drv, int type)
return -EAGAIN;
}
write_tcs_reg_sync(drv, RSC_DRV_CMD_ENABLE, m, 0);
+ write_tcs_reg_sync(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, m, 0);
}
bitmap_zero(tcs->slots, MAX_TCS_SLOTS);
spin_unlock(&tcs->lock);
@@ -239,6 +240,7 @@ static irqreturn_t tcs_tx_done(int irq, void *p)
skip:
/* Reclaim the TCS */
write_tcs_reg(drv, RSC_DRV_CMD_ENABLE, i, 0);
+ write_tcs_reg(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, i, 0);
write_tcs_reg(drv, RSC_DRV_IRQ_CLEAR, 0, BIT(i));
spin_lock(&drv->lock);
clear_bit(i, drv->tcs_in_use);
diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c
index bf4bd71ab53f..f80d040601fd 100644
--- a/drivers/soc/qcom/smem.c
+++ b/drivers/soc/qcom/smem.c
@@ -18,6 +18,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
+#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/soc/qcom/smem.h>
@@ -277,7 +278,7 @@ struct qcom_smem {
u32 item_count;
unsigned num_regions;
- struct smem_region regions[0];
+ struct smem_region regions[];
};
static void *
@@ -489,7 +490,7 @@ static void *qcom_smem_get_global(struct qcom_smem *smem,
size_t *size)
{
struct smem_header *header;
- struct smem_region *area;
+ struct smem_region *region;
struct smem_global_entry *entry;
u32 aux_base;
unsigned i;
@@ -502,12 +503,12 @@ static void *qcom_smem_get_global(struct qcom_smem *smem,
aux_base = le32_to_cpu(entry->aux_base) & AUX_BASE_MASK;
for (i = 0; i < smem->num_regions; i++) {
- area = &smem->regions[i];
+ region = &smem->regions[i];
- if (area->aux_base == aux_base || !aux_base) {
+ if (region->aux_base == aux_base || !aux_base) {
if (size != NULL)
*size = le32_to_cpu(entry->size);
- return area->virt_base + le32_to_cpu(entry->offset);
+ return region->virt_base + le32_to_cpu(entry->offset);
}
}
@@ -722,12 +723,59 @@ static u32 qcom_smem_get_item_count(struct qcom_smem *smem)
return le16_to_cpu(info->num_items);
}
+/*
+ * Validate the partition header for a partition whose partition
+ * table entry is supplied. Returns a pointer to its header if
+ * valid, or a null pointer otherwise.
+ */
+static struct smem_partition_header *
+qcom_smem_partition_header(struct qcom_smem *smem,
+ struct smem_ptable_entry *entry, u16 host0, u16 host1)
+{
+ struct smem_partition_header *header;
+ u32 size;
+
+ header = smem->regions[0].virt_base + le32_to_cpu(entry->offset);
+
+ if (memcmp(header->magic, SMEM_PART_MAGIC, sizeof(header->magic))) {
+ dev_err(smem->dev, "bad partition magic %02x %02x %02x %02x\n",
+ header->magic[0], header->magic[1],
+ header->magic[2], header->magic[3]);
+ return NULL;
+ }
+
+ if (host0 != le16_to_cpu(header->host0)) {
+ dev_err(smem->dev, "bad host0 (%hu != %hu)\n",
+ host0, le16_to_cpu(header->host0));
+ return NULL;
+ }
+ if (host1 != le16_to_cpu(header->host1)) {
+ dev_err(smem->dev, "bad host1 (%hu != %hu)\n",
+ host1, le16_to_cpu(header->host1));
+ return NULL;
+ }
+
+ size = le32_to_cpu(header->size);
+ if (size != le32_to_cpu(entry->size)) {
+ dev_err(smem->dev, "bad partition size (%u != %u)\n",
+ size, le32_to_cpu(entry->size));
+ return NULL;
+ }
+
+ if (le32_to_cpu(header->offset_free_uncached) > size) {
+ dev_err(smem->dev, "bad partition free uncached (%u > %u)\n",
+ le32_to_cpu(header->offset_free_uncached), size);
+ return NULL;
+ }
+
+ return header;
+}
+
static int qcom_smem_set_global_partition(struct qcom_smem *smem)
{
struct smem_partition_header *header;
struct smem_ptable_entry *entry;
struct smem_ptable *ptable;
- u32 host0, host1, size;
bool found = false;
int i;
@@ -742,10 +790,15 @@ static int qcom_smem_set_global_partition(struct qcom_smem *smem)
for (i = 0; i < le32_to_cpu(ptable->num_entries); i++) {
entry = &ptable->entry[i];
- host0 = le16_to_cpu(entry->host0);
- host1 = le16_to_cpu(entry->host1);
+ if (!le32_to_cpu(entry->offset))
+ continue;
+ if (!le32_to_cpu(entry->size))
+ continue;
+
+ if (le16_to_cpu(entry->host0) != SMEM_GLOBAL_HOST)
+ continue;
- if (host0 == SMEM_GLOBAL_HOST && host0 == host1) {
+ if (le16_to_cpu(entry->host1) == SMEM_GLOBAL_HOST) {
found = true;
break;
}
@@ -756,36 +809,10 @@ static int qcom_smem_set_global_partition(struct qcom_smem *smem)
return -EINVAL;
}
- if (!le32_to_cpu(entry->offset) || !le32_to_cpu(entry->size)) {
- dev_err(smem->dev, "Invalid entry for global partition\n");
+ header = qcom_smem_partition_header(smem, entry,
+ SMEM_GLOBAL_HOST, SMEM_GLOBAL_HOST);
+ if (!header)
return -EINVAL;
- }
-
- header = smem->regions[0].virt_base + le32_to_cpu(entry->offset);
- host0 = le16_to_cpu(header->host0);
- host1 = le16_to_cpu(header->host1);
-
- if (memcmp(header->magic, SMEM_PART_MAGIC, sizeof(header->magic))) {
- dev_err(smem->dev, "Global partition has invalid magic\n");
- return -EINVAL;
- }
-
- if (host0 != SMEM_GLOBAL_HOST && host1 != SMEM_GLOBAL_HOST) {
- dev_err(smem->dev, "Global partition hosts are invalid\n");
- return -EINVAL;
- }
-
- if (le32_to_cpu(header->size) != le32_to_cpu(entry->size)) {
- dev_err(smem->dev, "Global partition has invalid size\n");
- return -EINVAL;
- }
-
- size = le32_to_cpu(header->offset_free_uncached);
- if (size > le32_to_cpu(header->size)) {
- dev_err(smem->dev,
- "Global partition has invalid free pointer\n");
- return -EINVAL;
- }
smem->global_partition = header;
smem->global_cacheline = le32_to_cpu(entry->cacheline);
@@ -793,14 +820,14 @@ static int qcom_smem_set_global_partition(struct qcom_smem *smem)
return 0;
}
-static int qcom_smem_enumerate_partitions(struct qcom_smem *smem,
- unsigned int local_host)
+static int
+qcom_smem_enumerate_partitions(struct qcom_smem *smem, u16 local_host)
{
struct smem_partition_header *header;
struct smem_ptable_entry *entry;
struct smem_ptable *ptable;
unsigned int remote_host;
- u32 host0, host1;
+ u16 host0, host1;
int i;
ptable = qcom_smem_get_ptable(smem);
@@ -809,71 +836,33 @@ static int qcom_smem_enumerate_partitions(struct qcom_smem *smem,
for (i = 0; i < le32_to_cpu(ptable->num_entries); i++) {
entry = &ptable->entry[i];
- host0 = le16_to_cpu(entry->host0);
- host1 = le16_to_cpu(entry->host1);
-
- if (host0 != local_host && host1 != local_host)
- continue;
-
if (!le32_to_cpu(entry->offset))
continue;
-
if (!le32_to_cpu(entry->size))
continue;
+ host0 = le16_to_cpu(entry->host0);
+ host1 = le16_to_cpu(entry->host1);
if (host0 == local_host)
remote_host = host1;
- else
+ else if (host1 == local_host)
remote_host = host0;
+ else
+ continue;
if (remote_host >= SMEM_HOST_COUNT) {
- dev_err(smem->dev,
- "Invalid remote host %d\n",
- remote_host);
+ dev_err(smem->dev, "bad host %hu\n", remote_host);
return -EINVAL;
}
if (smem->partitions[remote_host]) {
- dev_err(smem->dev,
- "Already found a partition for host %d\n",
- remote_host);
- return -EINVAL;
- }
-
- header = smem->regions[0].virt_base + le32_to_cpu(entry->offset);
- host0 = le16_to_cpu(header->host0);
- host1 = le16_to_cpu(header->host1);
-
- if (memcmp(header->magic, SMEM_PART_MAGIC,
- sizeof(header->magic))) {
- dev_err(smem->dev,
- "Partition %d has invalid magic\n", i);
+ dev_err(smem->dev, "duplicate host %hu\n", remote_host);
return -EINVAL;
}
- if (host0 != local_host && host1 != local_host) {
- dev_err(smem->dev,
- "Partition %d hosts are invalid\n", i);
+ header = qcom_smem_partition_header(smem, entry, host0, host1);
+ if (!header)
return -EINVAL;
- }
-
- if (host0 != remote_host && host1 != remote_host) {
- dev_err(smem->dev,
- "Partition %d hosts are invalid\n", i);
- return -EINVAL;
- }
-
- if (le32_to_cpu(header->size) != le32_to_cpu(entry->size)) {
- dev_err(smem->dev,
- "Partition %d has invalid size\n", i);
- return -EINVAL;
- }
-
- if (le32_to_cpu(header->offset_free_uncached) > le32_to_cpu(header->size)) {
- dev_err(smem->dev,
- "Partition %d has invalid free pointer\n", i);
- return -EINVAL;
- }
smem->partitions[remote_host] = header;
smem->cacheline[remote_host] = le32_to_cpu(entry->cacheline);
@@ -887,6 +876,7 @@ static int qcom_smem_map_memory(struct qcom_smem *smem, struct device *dev,
{
struct device_node *np;
struct resource r;
+ resource_size_t size;
int ret;
np = of_parse_phandle(dev->of_node, name, 0);
@@ -899,12 +889,13 @@ static int qcom_smem_map_memory(struct qcom_smem *smem, struct device *dev,
of_node_put(np);
if (ret)
return ret;
+ size = resource_size(&r);
- smem->regions[i].aux_base = (u32)r.start;
- smem->regions[i].size = resource_size(&r);
- smem->regions[i].virt_base = devm_ioremap_wc(dev, r.start, resource_size(&r));
+ smem->regions[i].virt_base = devm_ioremap_wc(dev, r.start, size);
if (!smem->regions[i].virt_base)
return -ENOMEM;
+ smem->regions[i].aux_base = (u32)r.start;
+ smem->regions[i].size = size;
return 0;
}
@@ -962,6 +953,7 @@ static int qcom_smem_probe(struct platform_device *pdev)
return -EINVAL;
}
+ BUILD_BUG_ON(SMEM_HOST_APPS >= SMEM_HOST_COUNT);
ret = qcom_smem_enumerate_partitions(smem, SMEM_HOST_APPS);
if (ret < 0 && ret != -ENOENT)
return ret;
diff --git a/drivers/soc/qcom/spm.c b/drivers/soc/qcom/spm.c
index f9d7a85b2822..53807e839664 100644
--- a/drivers/soc/qcom/spm.c
+++ b/drivers/soc/qcom/spm.c
@@ -219,6 +219,9 @@ static int __init qcom_cpuidle_init(struct device_node *cpu_node, int cpu)
cpumask_t mask;
bool use_scm_power_down = false;
+ if (!qcom_scm_is_available())
+ return -EPROBE_DEFER;
+
for (i = 0; ; i++) {
state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i);
if (!state_node)
diff --git a/drivers/soc/qcom/wcnss_ctrl.c b/drivers/soc/qcom/wcnss_ctrl.c
index df3ccb30bc2d..373400dd816d 100644
--- a/drivers/soc/qcom/wcnss_ctrl.c
+++ b/drivers/soc/qcom/wcnss_ctrl.c
@@ -281,7 +281,7 @@ struct rpmsg_endpoint *qcom_wcnss_open_channel(void *wcnss, const char *name, rp
struct rpmsg_channel_info chinfo;
struct wcnss_ctrl *_wcnss = wcnss;
- strncpy(chinfo.name, name, sizeof(chinfo.name));
+ strscpy(chinfo.name, name, sizeof(chinfo.name));
chinfo.src = RPMSG_ADDR_ANY;
chinfo.dst = RPMSG_ADDR_ANY;
diff --git a/drivers/soc/renesas/Kconfig b/drivers/soc/renesas/Kconfig
index 1d824cbd462d..407f02c80e8b 100644
--- a/drivers/soc/renesas/Kconfig
+++ b/drivers/soc/renesas/Kconfig
@@ -1,14 +1,17 @@
+# SPDX-License-Identifier: GPL-2.0
config SOC_RENESAS
bool "Renesas SoC driver support" if COMPILE_TEST && !ARCH_RENESAS
default y if ARCH_RENESAS
select SOC_BUS
select RST_RCAR if ARCH_RCAR_GEN1 || ARCH_RCAR_GEN2 || \
- ARCH_R8A7795 || ARCH_R8A7796 || ARCH_R8A77965 || \
- ARCH_R8A77970 || ARCH_R8A77980 || ARCH_R8A77990 || \
- ARCH_R8A77995
- select SYSC_R8A7743 if ARCH_R8A7743
+ ARCH_R8A774A1 || ARCH_R8A774C0 || ARCH_R8A7795 || \
+ ARCH_R8A7796 || ARCH_R8A77965 || ARCH_R8A77970 || \
+ ARCH_R8A77980 || ARCH_R8A77990 || ARCH_R8A77995
+ select SYSC_R8A7743 if ARCH_R8A7743 || ARCH_R8A7744
select SYSC_R8A7745 if ARCH_R8A7745
select SYSC_R8A77470 if ARCH_R8A77470
+ select SYSC_R8A774A1 if ARCH_R8A774A1
+ select SYSC_R8A774C0 if ARCH_R8A774C0
select SYSC_R8A7779 if ARCH_R8A7779
select SYSC_R8A7790 if ARCH_R8A7790
select SYSC_R8A7791 if ARCH_R8A7791 || ARCH_R8A7793
@@ -37,6 +40,14 @@ config SYSC_R8A77470
bool "RZ/G1C System Controller support" if COMPILE_TEST
select SYSC_RCAR
+config SYSC_R8A774A1
+ bool "RZ/G2M System Controller support" if COMPILE_TEST
+ select SYSC_RCAR
+
+config SYSC_R8A774C0
+ bool "RZ/G2E System Controller support" if COMPILE_TEST
+ select SYSC_RCAR
+
config SYSC_R8A7779
bool "R-Car H1 System Controller support" if COMPILE_TEST
select SYSC_RCAR
diff --git a/drivers/soc/renesas/Makefile b/drivers/soc/renesas/Makefile
index c37b0803c1b6..3bdd7dbc38a9 100644
--- a/drivers/soc/renesas/Makefile
+++ b/drivers/soc/renesas/Makefile
@@ -6,6 +6,8 @@ obj-$(CONFIG_SOC_RENESAS) += renesas-soc.o
obj-$(CONFIG_SYSC_R8A7743) += r8a7743-sysc.o
obj-$(CONFIG_SYSC_R8A7745) += r8a7745-sysc.o
obj-$(CONFIG_SYSC_R8A77470) += r8a77470-sysc.o
+obj-$(CONFIG_SYSC_R8A774A1) += r8a774a1-sysc.o
+obj-$(CONFIG_SYSC_R8A774C0) += r8a774c0-sysc.o
obj-$(CONFIG_SYSC_R8A7779) += r8a7779-sysc.o
obj-$(CONFIG_SYSC_R8A7790) += r8a7790-sysc.o
obj-$(CONFIG_SYSC_R8A7791) += r8a7791-sysc.o
diff --git a/drivers/soc/renesas/r8a7743-sysc.c b/drivers/soc/renesas/r8a7743-sysc.c
index 9583a327d90c..edf6436e879f 100644
--- a/drivers/soc/renesas/r8a7743-sysc.c
+++ b/drivers/soc/renesas/r8a7743-sysc.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Renesas RZ/G1M System Controller
*
* Copyright (C) 2016 Cogent Embedded Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation; of the License.
*/
#include <linux/bug.h>
diff --git a/drivers/soc/renesas/r8a7745-sysc.c b/drivers/soc/renesas/r8a7745-sysc.c
index d17887c08aa1..65dc6b09cc85 100644
--- a/drivers/soc/renesas/r8a7745-sysc.c
+++ b/drivers/soc/renesas/r8a7745-sysc.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Renesas RZ/G1E System Controller
*
* Copyright (C) 2016 Cogent Embedded Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation; of the License.
*/
#include <linux/bug.h>
diff --git a/drivers/soc/renesas/r8a774a1-sysc.c b/drivers/soc/renesas/r8a774a1-sysc.c
new file mode 100644
index 000000000000..9db51ff6f5ed
--- /dev/null
+++ b/drivers/soc/renesas/r8a774a1-sysc.c
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas RZ/G2M System Controller
+ * Copyright (C) 2018 Renesas Electronics Corp.
+ *
+ * Based on Renesas R-Car M3-W System Controller
+ * Copyright (C) 2016 Glider bvba
+ */
+
+#include <linux/bug.h>
+#include <linux/kernel.h>
+
+#include <dt-bindings/power/r8a774a1-sysc.h>
+
+#include "rcar-sysc.h"
+
+static const struct rcar_sysc_area r8a774a1_areas[] __initconst = {
+ { "always-on", 0, 0, R8A774A1_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
+ { "ca57-scu", 0x1c0, 0, R8A774A1_PD_CA57_SCU, R8A774A1_PD_ALWAYS_ON,
+ PD_SCU },
+ { "ca57-cpu0", 0x80, 0, R8A774A1_PD_CA57_CPU0, R8A774A1_PD_CA57_SCU,
+ PD_CPU_NOCR },
+ { "ca57-cpu1", 0x80, 1, R8A774A1_PD_CA57_CPU1, R8A774A1_PD_CA57_SCU,
+ PD_CPU_NOCR },
+ { "ca53-scu", 0x140, 0, R8A774A1_PD_CA53_SCU, R8A774A1_PD_ALWAYS_ON,
+ PD_SCU },
+ { "ca53-cpu0", 0x200, 0, R8A774A1_PD_CA53_CPU0, R8A774A1_PD_CA53_SCU,
+ PD_CPU_NOCR },
+ { "ca53-cpu1", 0x200, 1, R8A774A1_PD_CA53_CPU1, R8A774A1_PD_CA53_SCU,
+ PD_CPU_NOCR },
+ { "ca53-cpu2", 0x200, 2, R8A774A1_PD_CA53_CPU2, R8A774A1_PD_CA53_SCU,
+ PD_CPU_NOCR },
+ { "ca53-cpu3", 0x200, 3, R8A774A1_PD_CA53_CPU3, R8A774A1_PD_CA53_SCU,
+ PD_CPU_NOCR },
+ { "a3vc", 0x380, 0, R8A774A1_PD_A3VC, R8A774A1_PD_ALWAYS_ON },
+ { "a2vc0", 0x3c0, 0, R8A774A1_PD_A2VC0, R8A774A1_PD_A3VC },
+ { "a2vc1", 0x3c0, 1, R8A774A1_PD_A2VC1, R8A774A1_PD_A3VC },
+ { "3dg-a", 0x100, 0, R8A774A1_PD_3DG_A, R8A774A1_PD_ALWAYS_ON },
+ { "3dg-b", 0x100, 1, R8A774A1_PD_3DG_B, R8A774A1_PD_3DG_A },
+};
+
+const struct rcar_sysc_info r8a774a1_sysc_info __initconst = {
+ .areas = r8a774a1_areas,
+ .num_areas = ARRAY_SIZE(r8a774a1_areas),
+};
diff --git a/drivers/soc/renesas/r8a774c0-sysc.c b/drivers/soc/renesas/r8a774c0-sysc.c
new file mode 100644
index 000000000000..e1ac4c0f6640
--- /dev/null
+++ b/drivers/soc/renesas/r8a774c0-sysc.c
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas RZ/G2E System Controller
+ * Copyright (C) 2018 Renesas Electronics Corp.
+ *
+ * Based on Renesas R-Car E3 System Controller
+ */
+
+#include <linux/bug.h>
+#include <linux/kernel.h>
+#include <linux/sys_soc.h>
+
+#include <dt-bindings/power/r8a774c0-sysc.h>
+
+#include "rcar-sysc.h"
+
+static struct rcar_sysc_area r8a774c0_areas[] __initdata = {
+ { "always-on", 0, 0, R8A774C0_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
+ { "ca53-scu", 0x140, 0, R8A774C0_PD_CA53_SCU, R8A774C0_PD_ALWAYS_ON,
+ PD_SCU },
+ { "ca53-cpu0", 0x200, 0, R8A774C0_PD_CA53_CPU0, R8A774C0_PD_CA53_SCU,
+ PD_CPU_NOCR },
+ { "ca53-cpu1", 0x200, 1, R8A774C0_PD_CA53_CPU1, R8A774C0_PD_CA53_SCU,
+ PD_CPU_NOCR },
+ { "a3vc", 0x380, 0, R8A774C0_PD_A3VC, R8A774C0_PD_ALWAYS_ON },
+ { "a2vc1", 0x3c0, 1, R8A774C0_PD_A2VC1, R8A774C0_PD_A3VC },
+ { "3dg-a", 0x100, 0, R8A774C0_PD_3DG_A, R8A774C0_PD_ALWAYS_ON },
+ { "3dg-b", 0x100, 1, R8A774C0_PD_3DG_B, R8A774C0_PD_3DG_A },
+};
+
+static void __init rcar_sysc_fix_parent(struct rcar_sysc_area *areas,
+ unsigned int num_areas, u8 id,
+ int new_parent)
+{
+ unsigned int i;
+
+ for (i = 0; i < num_areas; i++)
+ if (areas[i].isr_bit == id) {
+ areas[i].parent = new_parent;
+ return;
+ }
+}
+
+/* Fixups for RZ/G2E ES1.0 revision */
+static const struct soc_device_attribute r8a774c0[] __initconst = {
+ { .soc_id = "r8a774c0", .revision = "ES1.0" },
+ { /* sentinel */ }
+};
+
+static int __init r8a774c0_sysc_init(void)
+{
+ if (soc_device_match(r8a774c0)) {
+ rcar_sysc_fix_parent(r8a774c0_areas,
+ ARRAY_SIZE(r8a774c0_areas),
+ R8A774C0_PD_3DG_A, R8A774C0_PD_3DG_B);
+ rcar_sysc_fix_parent(r8a774c0_areas,
+ ARRAY_SIZE(r8a774c0_areas),
+ R8A774C0_PD_3DG_B, R8A774C0_PD_ALWAYS_ON);
+ }
+
+ return 0;
+}
+
+const struct rcar_sysc_info r8a774c0_sysc_info __initconst = {
+ .init = r8a774c0_sysc_init,
+ .areas = r8a774c0_areas,
+ .num_areas = ARRAY_SIZE(r8a774c0_areas),
+};
diff --git a/drivers/soc/renesas/r8a7779-sysc.c b/drivers/soc/renesas/r8a7779-sysc.c
index 9e8e6b7faa04..517aa40fa6e6 100644
--- a/drivers/soc/renesas/r8a7779-sysc.c
+++ b/drivers/soc/renesas/r8a7779-sysc.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Renesas R-Car H1 System Controller
*
* Copyright (C) 2016 Glider bvba
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
*/
#include <linux/bug.h>
diff --git a/drivers/soc/renesas/r8a7790-sysc.c b/drivers/soc/renesas/r8a7790-sysc.c
index 7a567ad0ff73..9b5a6bb62152 100644
--- a/drivers/soc/renesas/r8a7790-sysc.c
+++ b/drivers/soc/renesas/r8a7790-sysc.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Renesas R-Car H2 System Controller
*
* Copyright (C) 2016 Glider bvba
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
*/
#include <linux/bug.h>
diff --git a/drivers/soc/renesas/r8a7791-sysc.c b/drivers/soc/renesas/r8a7791-sysc.c
index 03b9f41a34e6..acf545cdebfb 100644
--- a/drivers/soc/renesas/r8a7791-sysc.c
+++ b/drivers/soc/renesas/r8a7791-sysc.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Renesas R-Car M2-W/N System Controller
*
* Copyright (C) 2016 Glider bvba
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
*/
#include <linux/bug.h>
diff --git a/drivers/soc/renesas/r8a7792-sysc.c b/drivers/soc/renesas/r8a7792-sysc.c
index ca7467d7b7ec..05b78525cc43 100644
--- a/drivers/soc/renesas/r8a7792-sysc.c
+++ b/drivers/soc/renesas/r8a7792-sysc.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Renesas R-Car V2H (R8A7792) System Controller
*
* Copyright (C) 2016 Cogent Embedded 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; version 2 of the License.
*/
#include <linux/bug.h>
diff --git a/drivers/soc/renesas/r8a7794-sysc.c b/drivers/soc/renesas/r8a7794-sysc.c
index c4da2941e06c..0d42637fa662 100644
--- a/drivers/soc/renesas/r8a7794-sysc.c
+++ b/drivers/soc/renesas/r8a7794-sysc.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Renesas R-Car E2 System Controller
*
* Copyright (C) 2016 Glider bvba
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
*/
#include <linux/bug.h>
diff --git a/drivers/soc/renesas/r8a7795-sysc.c b/drivers/soc/renesas/r8a7795-sysc.c
index 7412666187b3..cda27a67de98 100644
--- a/drivers/soc/renesas/r8a7795-sysc.c
+++ b/drivers/soc/renesas/r8a7795-sysc.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Renesas R-Car H3 System Controller
*
* Copyright (C) 2016-2017 Glider bvba
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
*/
#include <linux/bug.h>
diff --git a/drivers/soc/renesas/r8a7796-sysc.c b/drivers/soc/renesas/r8a7796-sysc.c
index f700c842b9e1..1b06f868b6e8 100644
--- a/drivers/soc/renesas/r8a7796-sysc.c
+++ b/drivers/soc/renesas/r8a7796-sysc.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Renesas R-Car M3-W System Controller
*
* Copyright (C) 2016 Glider bvba
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
*/
#include <linux/bug.h>
diff --git a/drivers/soc/renesas/r8a77970-sysc.c b/drivers/soc/renesas/r8a77970-sysc.c
index caf894f193ed..35b30d6a8958 100644
--- a/drivers/soc/renesas/r8a77970-sysc.c
+++ b/drivers/soc/renesas/r8a77970-sysc.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Renesas R-Car V3M System Controller
*
* Copyright (C) 2017 Cogent Embedded Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/bug.h>
diff --git a/drivers/soc/renesas/r8a77995-sysc.c b/drivers/soc/renesas/r8a77995-sysc.c
index 1b2ef415bbe1..6243aaaf60fb 100644
--- a/drivers/soc/renesas/r8a77995-sysc.c
+++ b/drivers/soc/renesas/r8a77995-sysc.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Renesas R-Car D3 System Controller
*
* Copyright (C) 2017 Glider bvba
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
*/
#include <linux/bug.h>
diff --git a/drivers/soc/renesas/rcar-rst.c b/drivers/soc/renesas/rcar-rst.c
index d9c1034e70e9..d183c381e8db 100644
--- a/drivers/soc/renesas/rcar-rst.c
+++ b/drivers/soc/renesas/rcar-rst.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* R-Car Gen1 RESET/WDT, R-Car Gen2, Gen3, and RZ/G RST Driver
*
* Copyright (C) 2016 Glider bvba
- *
- * 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/err.h>
@@ -41,10 +38,14 @@ static const struct rst_config rcar_rst_gen3 __initconst = {
};
static const struct of_device_id rcar_rst_matches[] __initconst = {
- /* RZ/G is handled like R-Car Gen2 */
+ /* RZ/G1 is handled like R-Car Gen2 */
{ .compatible = "renesas,r8a7743-rst", .data = &rcar_rst_gen2 },
+ { .compatible = "renesas,r8a7744-rst", .data = &rcar_rst_gen2 },
{ .compatible = "renesas,r8a7745-rst", .data = &rcar_rst_gen2 },
{ .compatible = "renesas,r8a77470-rst", .data = &rcar_rst_gen2 },
+ /* RZ/G2 is handled like R-Car Gen3 */
+ { .compatible = "renesas,r8a774a1-rst", .data = &rcar_rst_gen3 },
+ { .compatible = "renesas,r8a774c0-rst", .data = &rcar_rst_gen3 },
/* R-Car Gen1 */
{ .compatible = "renesas,r8a7778-reset-wdt", .data = &rcar_rst_gen1 },
{ .compatible = "renesas,r8a7779-reset-wdt", .data = &rcar_rst_gen1 },
diff --git a/drivers/soc/renesas/rcar-sysc.c b/drivers/soc/renesas/rcar-sysc.c
index 029188e8be6e..af53363eda03 100644
--- a/drivers/soc/renesas/rcar-sysc.c
+++ b/drivers/soc/renesas/rcar-sysc.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* R-Car SYSC Power management support
*
* Copyright (C) 2014 Magnus Damm
* Copyright (C) 2015-2017 Glider bvba
- *
- * 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/clk/renesas.h>
@@ -268,6 +265,8 @@ finalize:
static const struct of_device_id rcar_sysc_matches[] __initconst = {
#ifdef CONFIG_SYSC_R8A7743
{ .compatible = "renesas,r8a7743-sysc", .data = &r8a7743_sysc_info },
+ /* RZ/G1N is identical to RZ/G2M w.r.t. power domains. */
+ { .compatible = "renesas,r8a7744-sysc", .data = &r8a7743_sysc_info },
#endif
#ifdef CONFIG_SYSC_R8A7745
{ .compatible = "renesas,r8a7745-sysc", .data = &r8a7745_sysc_info },
@@ -275,6 +274,12 @@ static const struct of_device_id rcar_sysc_matches[] __initconst = {
#ifdef CONFIG_SYSC_R8A77470
{ .compatible = "renesas,r8a77470-sysc", .data = &r8a77470_sysc_info },
#endif
+#ifdef CONFIG_SYSC_R8A774A1
+ { .compatible = "renesas,r8a774a1-sysc", .data = &r8a774a1_sysc_info },
+#endif
+#ifdef CONFIG_SYSC_R8A774C0
+ { .compatible = "renesas,r8a774c0-sysc", .data = &r8a774c0_sysc_info },
+#endif
#ifdef CONFIG_SYSC_R8A7779
{ .compatible = "renesas,r8a7779-sysc", .data = &r8a7779_sysc_info },
#endif
diff --git a/drivers/soc/renesas/rcar-sysc.h b/drivers/soc/renesas/rcar-sysc.h
index a22e7cf25e30..485520a5b295 100644
--- a/drivers/soc/renesas/rcar-sysc.h
+++ b/drivers/soc/renesas/rcar-sysc.h
@@ -1,11 +1,8 @@
-/*
+/* SPDX-License-Identifier: GPL-2.0
+ *
* Renesas R-Car System Controller
*
* Copyright (C) 2016 Glider bvba
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
*/
#ifndef __SOC_RENESAS_RCAR_SYSC_H__
#define __SOC_RENESAS_RCAR_SYSC_H__
@@ -52,6 +49,8 @@ struct rcar_sysc_info {
extern const struct rcar_sysc_info r8a7743_sysc_info;
extern const struct rcar_sysc_info r8a7745_sysc_info;
extern const struct rcar_sysc_info r8a77470_sysc_info;
+extern const struct rcar_sysc_info r8a774a1_sysc_info;
+extern const struct rcar_sysc_info r8a774c0_sysc_info;
extern const struct rcar_sysc_info r8a7779_sysc_info;
extern const struct rcar_sysc_info r8a7790_sysc_info;
extern const struct rcar_sysc_info r8a7791_sysc_info;
diff --git a/drivers/soc/renesas/renesas-soc.c b/drivers/soc/renesas/renesas-soc.c
index d44d0e687ab8..4af96e668a2f 100644
--- a/drivers/soc/renesas/renesas-soc.c
+++ b/drivers/soc/renesas/renesas-soc.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Renesas SoC Identification
*
* Copyright (C) 2014-2016 Glider bvba
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/io.h>
@@ -46,15 +38,24 @@ static const struct renesas_family fam_rmobile __initconst __maybe_unused = {
.reg = 0xe600101c, /* CCCR (Common Chip Code Register) */
};
-static const struct renesas_family fam_rza __initconst __maybe_unused = {
- .name = "RZ/A",
+static const struct renesas_family fam_rza1 __initconst __maybe_unused = {
+ .name = "RZ/A1",
+};
+
+static const struct renesas_family fam_rza2 __initconst __maybe_unused = {
+ .name = "RZ/A2",
};
-static const struct renesas_family fam_rzg __initconst __maybe_unused = {
- .name = "RZ/G",
+static const struct renesas_family fam_rzg1 __initconst __maybe_unused = {
+ .name = "RZ/G1",
.reg = 0xff000044, /* PRR (Product Register) */
};
+static const struct renesas_family fam_rzg2 __initconst __maybe_unused = {
+ .name = "RZ/G2",
+ .reg = 0xfff00044, /* PRR (Product Register) */
+};
+
static const struct renesas_family fam_shmobile __initconst __maybe_unused = {
.name = "SH-Mobile",
.reg = 0xe600101c, /* CCCR (Common Chip Code Register) */
@@ -67,7 +68,12 @@ struct renesas_soc {
};
static const struct renesas_soc soc_rz_a1h __initconst __maybe_unused = {
- .family = &fam_rza,
+ .family = &fam_rza1,
+};
+
+static const struct renesas_soc soc_rz_a2m __initconst __maybe_unused = {
+ .family = &fam_rza2,
+ .id = 0x3b,
};
static const struct renesas_soc soc_rmobile_ape6 __initconst __maybe_unused = {
@@ -81,30 +87,40 @@ static const struct renesas_soc soc_rmobile_a1 __initconst __maybe_unused = {
};
static const struct renesas_soc soc_rz_g1h __initconst __maybe_unused = {
- .family = &fam_rzg,
+ .family = &fam_rzg1,
.id = 0x45,
};
static const struct renesas_soc soc_rz_g1m __initconst __maybe_unused = {
- .family = &fam_rzg,
+ .family = &fam_rzg1,
.id = 0x47,
};
static const struct renesas_soc soc_rz_g1n __initconst __maybe_unused = {
- .family = &fam_rzg,
+ .family = &fam_rzg1,
.id = 0x4b,
};
static const struct renesas_soc soc_rz_g1e __initconst __maybe_unused = {
- .family = &fam_rzg,
+ .family = &fam_rzg1,
.id = 0x4c,
};
static const struct renesas_soc soc_rz_g1c __initconst __maybe_unused = {
- .family = &fam_rzg,
+ .family = &fam_rzg1,
.id = 0x53,
};
+static const struct renesas_soc soc_rz_g2m __initconst __maybe_unused = {
+ .family = &fam_rzg2,
+ .id = 0x52,
+};
+
+static const struct renesas_soc soc_rz_g2e __initconst __maybe_unused = {
+ .family = &fam_rzg2,
+ .id = 0x57,
+};
+
static const struct renesas_soc soc_rcar_m1a __initconst __maybe_unused = {
.family = &fam_rcar_gen1,
};
@@ -184,6 +200,9 @@ static const struct of_device_id renesas_socs[] __initconst = {
#ifdef CONFIG_ARCH_R7S72100
{ .compatible = "renesas,r7s72100", .data = &soc_rz_a1h },
#endif
+#ifdef CONFIG_ARCH_R7S9210
+ { .compatible = "renesas,r7s9210", .data = &soc_rz_a2m },
+#endif
#ifdef CONFIG_ARCH_R8A73A4
{ .compatible = "renesas,r8a73a4", .data = &soc_rmobile_ape6 },
#endif
@@ -205,6 +224,12 @@ static const struct of_device_id renesas_socs[] __initconst = {
#ifdef CONFIG_ARCH_R8A77470
{ .compatible = "renesas,r8a77470", .data = &soc_rz_g1c },
#endif
+#ifdef CONFIG_ARCH_R8A774A1
+ { .compatible = "renesas,r8a774a1", .data = &soc_rz_g2m },
+#endif
+#ifdef CONFIG_ARCH_R8A774C0
+ { .compatible = "renesas,r8a774c0", .data = &soc_rz_g2e },
+#endif
#ifdef CONFIG_ARCH_R8A7778
{ .compatible = "renesas,r8a7778", .data = &soc_rcar_m1a },
#endif
@@ -262,7 +287,7 @@ static int __init renesas_soc_init(void)
void __iomem *chipid = NULL;
struct soc_device *soc_dev;
struct device_node *np;
- unsigned int product;
+ unsigned int product, eshi = 0, eslo;
match = of_match_node(renesas_socs, of_root);
if (!match)
@@ -271,6 +296,31 @@ static int __init renesas_soc_init(void)
soc = match->data;
family = soc->family;
+ np = of_find_compatible_node(NULL, NULL, "renesas,bsid");
+ if (np) {
+ chipid = of_iomap(np, 0);
+ of_node_put(np);
+
+ if (chipid) {
+ product = readl(chipid);
+ iounmap(chipid);
+
+ if (soc->id && ((product >> 16) & 0xff) != soc->id) {
+ pr_warn("SoC mismatch (product = 0x%x)\n",
+ product);
+ return -ENODEV;
+ }
+ }
+
+ /*
+ * TODO: Upper 4 bits of BSID are for chip version, but the
+ * format is not known at this time so we don't know how to
+ * specify eshi and eslo
+ */
+
+ goto done;
+ }
+
/* Try PRR first, then hardcoded fallback */
np = of_find_compatible_node(NULL, NULL, "renesas,prr");
if (np) {
@@ -289,8 +339,11 @@ static int __init renesas_soc_init(void)
pr_warn("SoC mismatch (product = 0x%x)\n", product);
return -ENODEV;
}
+ eshi = ((product >> 4) & 0x0f) + 1;
+ eslo = product & 0xf;
}
+done:
soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
if (!soc_dev_attr)
return -ENOMEM;
@@ -302,10 +355,9 @@ static int __init renesas_soc_init(void)
soc_dev_attr->family = kstrdup_const(family->name, GFP_KERNEL);
soc_dev_attr->soc_id = kstrdup_const(strchr(match->compatible, ',') + 1,
GFP_KERNEL);
- if (chipid)
- soc_dev_attr->revision = kasprintf(GFP_KERNEL, "ES%u.%u",
- ((product >> 4) & 0x0f) + 1,
- product & 0xf);
+ if (eshi)
+ soc_dev_attr->revision = kasprintf(GFP_KERNEL, "ES%u.%u", eshi,
+ eslo);
pr_info("Detected Renesas %s %s %s\n", soc_dev_attr->family,
soc_dev_attr->soc_id, soc_dev_attr->revision ?: "");
diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c
index 6dff8682155f..6f86a726bb45 100644
--- a/drivers/soc/rockchip/pm_domains.c
+++ b/drivers/soc/rockchip/pm_domains.c
@@ -392,21 +392,21 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
error = of_property_read_u32(node, "reg", &id);
if (error) {
dev_err(pmu->dev,
- "%s: failed to retrieve domain id (reg): %d\n",
- node->name, error);
+ "%pOFn: failed to retrieve domain id (reg): %d\n",
+ node, error);
return -EINVAL;
}
if (id >= pmu->info->num_domains) {
- dev_err(pmu->dev, "%s: invalid domain id %d\n",
- node->name, id);
+ dev_err(pmu->dev, "%pOFn: invalid domain id %d\n",
+ node, id);
return -EINVAL;
}
pd_info = &pmu->info->domain_info[id];
if (!pd_info) {
- dev_err(pmu->dev, "%s: undefined domain id %d\n",
- node->name, id);
+ dev_err(pmu->dev, "%pOFn: undefined domain id %d\n",
+ node, id);
return -EINVAL;
}
@@ -424,8 +424,8 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
if (!pd->clks)
return -ENOMEM;
} else {
- dev_dbg(pmu->dev, "%s: doesn't have clocks: %d\n",
- node->name, pd->num_clks);
+ dev_dbg(pmu->dev, "%pOFn: doesn't have clocks: %d\n",
+ node, pd->num_clks);
pd->num_clks = 0;
}
@@ -434,8 +434,8 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
if (IS_ERR(pd->clks[i].clk)) {
error = PTR_ERR(pd->clks[i].clk);
dev_err(pmu->dev,
- "%s: failed to get clk at index %d: %d\n",
- node->name, i, error);
+ "%pOFn: failed to get clk at index %d: %d\n",
+ node, i, error);
return error;
}
}
@@ -486,8 +486,8 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
error = rockchip_pd_power(pd, true);
if (error) {
dev_err(pmu->dev,
- "failed to power on domain '%s': %d\n",
- node->name, error);
+ "failed to power on domain '%pOFn': %d\n",
+ node, error);
goto err_unprepare_clocks;
}
@@ -575,24 +575,24 @@ static int rockchip_pm_add_subdomain(struct rockchip_pmu *pmu,
error = of_property_read_u32(parent, "reg", &idx);
if (error) {
dev_err(pmu->dev,
- "%s: failed to retrieve domain id (reg): %d\n",
- parent->name, error);
+ "%pOFn: failed to retrieve domain id (reg): %d\n",
+ parent, error);
goto err_out;
}
parent_domain = pmu->genpd_data.domains[idx];
error = rockchip_pm_add_one_domain(pmu, np);
if (error) {
- dev_err(pmu->dev, "failed to handle node %s: %d\n",
- np->name, error);
+ dev_err(pmu->dev, "failed to handle node %pOFn: %d\n",
+ np, error);
goto err_out;
}
error = of_property_read_u32(np, "reg", &idx);
if (error) {
dev_err(pmu->dev,
- "%s: failed to retrieve domain id (reg): %d\n",
- np->name, error);
+ "%pOFn: failed to retrieve domain id (reg): %d\n",
+ np, error);
goto err_out;
}
child_domain = pmu->genpd_data.domains[idx];
@@ -683,16 +683,16 @@ static int rockchip_pm_domain_probe(struct platform_device *pdev)
for_each_available_child_of_node(np, node) {
error = rockchip_pm_add_one_domain(pmu, node);
if (error) {
- dev_err(dev, "failed to handle node %s: %d\n",
- node->name, error);
+ dev_err(dev, "failed to handle node %pOFn: %d\n",
+ node, error);
of_node_put(node);
goto err_out;
}
error = rockchip_pm_add_subdomain(pmu, node);
if (error < 0) {
- dev_err(dev, "failed to handle subdomain node %s: %d\n",
- node->name, error);
+ dev_err(dev, "failed to handle subdomain node %pOFn: %d\n",
+ node, error);
of_node_put(node);
goto err_out;
}
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index 2d6f3fcf3211..1fa840e3d930 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -33,6 +33,9 @@
#include <linux/of_address.h>
#include <linux/of_clk.h>
#include <linux/of_platform.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/reboot.h>
@@ -45,6 +48,8 @@
#include <soc/tegra/fuse.h>
#include <soc/tegra/pmc.h>
+#include <dt-bindings/pinctrl/pinctrl-tegra-io-pad.h>
+
#define PMC_CNTRL 0x0
#define PMC_CNTRL_INTR_POLARITY BIT(17) /* inverts INTR polarity */
#define PMC_CNTRL_CPU_PWRREQ_OE BIT(16) /* CPU pwr req enable */
@@ -65,6 +70,8 @@
#define PWRGATE_STATUS 0x38
+#define PMC_IMPL_E_33V_PWR 0x40
+
#define PMC_PWR_DET 0x48
#define PMC_SCRATCH0_MODE_RECOVERY BIT(31)
@@ -135,6 +142,7 @@ struct tegra_io_pad_soc {
enum tegra_io_pad id;
unsigned int dpd;
unsigned int voltage;
+ const char *name;
};
struct tegra_pmc_regs {
@@ -154,10 +162,14 @@ struct tegra_pmc_soc {
bool has_tsense_reset;
bool has_gpu_clamps;
bool needs_mbist_war;
+ bool has_impl_33v_pwr;
const struct tegra_io_pad_soc *io_pads;
unsigned int num_io_pads;
+ const struct pinctrl_pin_desc *pin_descs;
+ unsigned int num_pin_descs;
+
const struct tegra_pmc_regs *regs;
void (*init)(struct tegra_pmc *pmc);
void (*setup_irq_polarity)(struct tegra_pmc *pmc,
@@ -216,6 +228,8 @@ struct tegra_pmc {
DECLARE_BITMAP(powergates_available, TEGRA_POWERGATE_MAX);
struct mutex powergates_lock;
+
+ struct pinctrl_dev *pctl_dev;
};
static struct tegra_pmc *pmc = &(struct tegra_pmc) {
@@ -796,7 +810,7 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
id = tegra_powergate_lookup(pmc, np->name);
if (id < 0) {
- pr_err("powergate lookup failed for %s: %d\n", np->name, id);
+ pr_err("powergate lookup failed for %pOFn: %d\n", np, id);
goto free_mem;
}
@@ -816,13 +830,13 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
err = tegra_powergate_of_get_clks(pg, np);
if (err < 0) {
- pr_err("failed to get clocks for %s: %d\n", np->name, err);
+ pr_err("failed to get clocks for %pOFn: %d\n", np, err);
goto set_available;
}
err = tegra_powergate_of_get_resets(pg, np, off);
if (err < 0) {
- pr_err("failed to get resets for %s: %d\n", np->name, err);
+ pr_err("failed to get resets for %pOFn: %d\n", np, err);
goto remove_clks;
}
@@ -851,15 +865,15 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
err = pm_genpd_init(&pg->genpd, NULL, off);
if (err < 0) {
- pr_err("failed to initialise PM domain %s: %d\n", np->name,
+ pr_err("failed to initialise PM domain %pOFn: %d\n", np,
err);
goto remove_resets;
}
err = of_genpd_add_provider_simple(np, &pg->genpd);
if (err < 0) {
- pr_err("failed to add PM domain provider for %s: %d\n",
- np->name, err);
+ pr_err("failed to add PM domain provider for %pOFn: %d\n",
+ np, err);
goto remove_genpd;
}
@@ -919,11 +933,12 @@ tegra_io_pad_find(struct tegra_pmc *pmc, enum tegra_io_pad id)
return NULL;
}
-static int tegra_io_pad_prepare(enum tegra_io_pad id, unsigned long *request,
- unsigned long *status, u32 *mask)
+static int tegra_io_pad_get_dpd_register_bit(enum tegra_io_pad id,
+ unsigned long *request,
+ unsigned long *status,
+ u32 *mask)
{
const struct tegra_io_pad_soc *pad;
- unsigned long rate, value;
pad = tegra_io_pad_find(pmc, id);
if (!pad) {
@@ -944,6 +959,19 @@ static int tegra_io_pad_prepare(enum tegra_io_pad id, unsigned long *request,
*request = pmc->soc->regs->dpd2_req;
}
+ return 0;
+}
+
+static int tegra_io_pad_prepare(enum tegra_io_pad id, unsigned long *request,
+ unsigned long *status, u32 *mask)
+{
+ unsigned long rate, value;
+ int err;
+
+ err = tegra_io_pad_get_dpd_register_bit(id, request, status, mask);
+ if (err)
+ return err;
+
if (pmc->clk) {
rate = clk_get_rate(pmc->clk);
if (!rate) {
@@ -1058,8 +1086,22 @@ unlock:
}
EXPORT_SYMBOL(tegra_io_pad_power_disable);
-int tegra_io_pad_set_voltage(enum tegra_io_pad id,
- enum tegra_io_pad_voltage voltage)
+static int tegra_io_pad_is_powered(enum tegra_io_pad id)
+{
+ unsigned long request, status;
+ u32 mask, value;
+ int err;
+
+ err = tegra_io_pad_get_dpd_register_bit(id, &request, &status, &mask);
+ if (err)
+ return err;
+
+ value = tegra_pmc_readl(status);
+
+ return !(value & mask);
+}
+
+static int tegra_io_pad_set_voltage(enum tegra_io_pad id, int voltage)
{
const struct tegra_io_pad_soc *pad;
u32 value;
@@ -1073,20 +1115,31 @@ int tegra_io_pad_set_voltage(enum tegra_io_pad id,
mutex_lock(&pmc->powergates_lock);
- /* write-enable PMC_PWR_DET_VALUE[pad->voltage] */
- value = tegra_pmc_readl(PMC_PWR_DET);
- value |= BIT(pad->voltage);
- tegra_pmc_writel(value, PMC_PWR_DET);
+ if (pmc->soc->has_impl_33v_pwr) {
+ value = tegra_pmc_readl(PMC_IMPL_E_33V_PWR);
- /* update I/O voltage */
- value = tegra_pmc_readl(PMC_PWR_DET_VALUE);
+ if (voltage == TEGRA_IO_PAD_VOLTAGE_1V8)
+ value &= ~BIT(pad->voltage);
+ else
+ value |= BIT(pad->voltage);
- if (voltage == TEGRA_IO_PAD_1800000UV)
- value &= ~BIT(pad->voltage);
- else
+ tegra_pmc_writel(value, PMC_IMPL_E_33V_PWR);
+ } else {
+ /* write-enable PMC_PWR_DET_VALUE[pad->voltage] */
+ value = tegra_pmc_readl(PMC_PWR_DET);
value |= BIT(pad->voltage);
+ tegra_pmc_writel(value, PMC_PWR_DET);
- tegra_pmc_writel(value, PMC_PWR_DET_VALUE);
+ /* update I/O voltage */
+ value = tegra_pmc_readl(PMC_PWR_DET_VALUE);
+
+ if (voltage == TEGRA_IO_PAD_VOLTAGE_1V8)
+ value &= ~BIT(pad->voltage);
+ else
+ value |= BIT(pad->voltage);
+
+ tegra_pmc_writel(value, PMC_PWR_DET_VALUE);
+ }
mutex_unlock(&pmc->powergates_lock);
@@ -1094,9 +1147,8 @@ int tegra_io_pad_set_voltage(enum tegra_io_pad id,
return 0;
}
-EXPORT_SYMBOL(tegra_io_pad_set_voltage);
-int tegra_io_pad_get_voltage(enum tegra_io_pad id)
+static int tegra_io_pad_get_voltage(enum tegra_io_pad id)
{
const struct tegra_io_pad_soc *pad;
u32 value;
@@ -1108,14 +1160,16 @@ int tegra_io_pad_get_voltage(enum tegra_io_pad id)
if (pad->voltage == UINT_MAX)
return -ENOTSUPP;
- value = tegra_pmc_readl(PMC_PWR_DET_VALUE);
+ if (pmc->soc->has_impl_33v_pwr)
+ value = tegra_pmc_readl(PMC_IMPL_E_33V_PWR);
+ else
+ value = tegra_pmc_readl(PMC_PWR_DET_VALUE);
if ((value & BIT(pad->voltage)) == 0)
- return TEGRA_IO_PAD_1800000UV;
+ return TEGRA_IO_PAD_VOLTAGE_1V8;
- return TEGRA_IO_PAD_3300000UV;
+ return TEGRA_IO_PAD_VOLTAGE_3V3;
}
-EXPORT_SYMBOL(tegra_io_pad_get_voltage);
/**
* tegra_io_rail_power_on() - enable power to I/O rail
@@ -1288,7 +1342,7 @@ static void tegra_pmc_init_tsense_reset(struct tegra_pmc *pmc)
if (!pmc->soc->has_tsense_reset)
return;
- np = of_find_node_by_name(pmc->dev->of_node, "i2c-thermtrip");
+ np = of_get_child_by_name(pmc->dev->of_node, "i2c-thermtrip");
if (!np) {
dev_warn(dev, "i2c-thermtrip node not found, %s.\n", disabled);
return;
@@ -1353,6 +1407,142 @@ out:
of_node_put(np);
}
+static int tegra_io_pad_pinctrl_get_groups_count(struct pinctrl_dev *pctl_dev)
+{
+ return pmc->soc->num_io_pads;
+}
+
+static const char *tegra_io_pad_pinctrl_get_group_name(
+ struct pinctrl_dev *pctl, unsigned int group)
+{
+ return pmc->soc->io_pads[group].name;
+}
+
+static int tegra_io_pad_pinctrl_get_group_pins(struct pinctrl_dev *pctl_dev,
+ unsigned int group,
+ const unsigned int **pins,
+ unsigned int *num_pins)
+{
+ *pins = &pmc->soc->io_pads[group].id;
+ *num_pins = 1;
+ return 0;
+}
+
+static const struct pinctrl_ops tegra_io_pad_pinctrl_ops = {
+ .get_groups_count = tegra_io_pad_pinctrl_get_groups_count,
+ .get_group_name = tegra_io_pad_pinctrl_get_group_name,
+ .get_group_pins = tegra_io_pad_pinctrl_get_group_pins,
+ .dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
+ .dt_free_map = pinconf_generic_dt_free_map,
+};
+
+static int tegra_io_pad_pinconf_get(struct pinctrl_dev *pctl_dev,
+ unsigned int pin, unsigned long *config)
+{
+ const struct tegra_io_pad_soc *pad = tegra_io_pad_find(pmc, pin);
+ enum pin_config_param param = pinconf_to_config_param(*config);
+ int ret;
+ u32 arg;
+
+ if (!pad)
+ return -EINVAL;
+
+ switch (param) {
+ case PIN_CONFIG_POWER_SOURCE:
+ ret = tegra_io_pad_get_voltage(pad->id);
+ if (ret < 0)
+ return ret;
+ arg = ret;
+ break;
+ case PIN_CONFIG_LOW_POWER_MODE:
+ ret = tegra_io_pad_is_powered(pad->id);
+ if (ret < 0)
+ return ret;
+ arg = !ret;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ *config = pinconf_to_config_packed(param, arg);
+
+ return 0;
+}
+
+static int tegra_io_pad_pinconf_set(struct pinctrl_dev *pctl_dev,
+ unsigned int pin, unsigned long *configs,
+ unsigned int num_configs)
+{
+ const struct tegra_io_pad_soc *pad = tegra_io_pad_find(pmc, pin);
+ enum pin_config_param param;
+ unsigned int i;
+ int err;
+ u32 arg;
+
+ if (!pad)
+ return -EINVAL;
+
+ for (i = 0; i < num_configs; ++i) {
+ param = pinconf_to_config_param(configs[i]);
+ arg = pinconf_to_config_argument(configs[i]);
+
+ switch (param) {
+ case PIN_CONFIG_LOW_POWER_MODE:
+ if (arg)
+ err = tegra_io_pad_power_disable(pad->id);
+ else
+ err = tegra_io_pad_power_enable(pad->id);
+ if (err)
+ return err;
+ break;
+ case PIN_CONFIG_POWER_SOURCE:
+ if (arg != TEGRA_IO_PAD_VOLTAGE_1V8 &&
+ arg != TEGRA_IO_PAD_VOLTAGE_3V3)
+ return -EINVAL;
+ err = tegra_io_pad_set_voltage(pad->id, arg);
+ if (err)
+ return err;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static const struct pinconf_ops tegra_io_pad_pinconf_ops = {
+ .pin_config_get = tegra_io_pad_pinconf_get,
+ .pin_config_set = tegra_io_pad_pinconf_set,
+ .is_generic = true,
+};
+
+static struct pinctrl_desc tegra_pmc_pctl_desc = {
+ .pctlops = &tegra_io_pad_pinctrl_ops,
+ .confops = &tegra_io_pad_pinconf_ops,
+};
+
+static int tegra_pmc_pinctrl_init(struct tegra_pmc *pmc)
+{
+ int err = 0;
+
+ if (!pmc->soc->num_pin_descs)
+ return 0;
+
+ tegra_pmc_pctl_desc.name = dev_name(pmc->dev);
+ tegra_pmc_pctl_desc.pins = pmc->soc->pin_descs;
+ tegra_pmc_pctl_desc.npins = pmc->soc->num_pin_descs;
+
+ pmc->pctl_dev = devm_pinctrl_register(pmc->dev, &tegra_pmc_pctl_desc,
+ pmc);
+ if (IS_ERR(pmc->pctl_dev)) {
+ err = PTR_ERR(pmc->pctl_dev);
+ dev_err(pmc->dev, "unable to register pinctrl, %d\n", err);
+ }
+
+ return err;
+}
+
static int tegra_pmc_probe(struct platform_device *pdev)
{
void __iomem *base;
@@ -1430,18 +1620,27 @@ static int tegra_pmc_probe(struct platform_device *pdev)
err = register_restart_handler(&tegra_pmc_restart_handler);
if (err) {
- debugfs_remove(pmc->debugfs);
dev_err(&pdev->dev, "unable to register restart handler, %d\n",
err);
- return err;
+ goto cleanup_debugfs;
}
+ err = tegra_pmc_pinctrl_init(pmc);
+ if (err)
+ goto cleanup_restart_handler;
+
mutex_lock(&pmc->powergates_lock);
iounmap(pmc->base);
pmc->base = base;
mutex_unlock(&pmc->powergates_lock);
return 0;
+
+cleanup_restart_handler:
+ unregister_restart_handler(&tegra_pmc_restart_handler);
+cleanup_debugfs:
+ debugfs_remove(pmc->debugfs);
+ return err;
}
#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM)
@@ -1531,6 +1730,8 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = {
.has_gpu_clamps = false,
.num_io_pads = 0,
.io_pads = NULL,
+ .num_pin_descs = 0,
+ .pin_descs = NULL,
.regs = &tegra20_pmc_regs,
.init = tegra20_pmc_init,
.setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
@@ -1567,8 +1768,11 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = {
.cpu_powergates = tegra30_cpu_powergates,
.has_tsense_reset = true,
.has_gpu_clamps = false,
+ .has_impl_33v_pwr = false,
.num_io_pads = 0,
.io_pads = NULL,
+ .num_pin_descs = 0,
+ .pin_descs = NULL,
.regs = &tegra20_pmc_regs,
.init = tegra20_pmc_init,
.setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
@@ -1609,8 +1813,11 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = {
.cpu_powergates = tegra114_cpu_powergates,
.has_tsense_reset = true,
.has_gpu_clamps = false,
+ .has_impl_33v_pwr = false,
.num_io_pads = 0,
.io_pads = NULL,
+ .num_pin_descs = 0,
+ .pin_descs = NULL,
.regs = &tegra20_pmc_regs,
.init = tegra20_pmc_init,
.setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
@@ -1649,37 +1856,59 @@ static const u8 tegra124_cpu_powergates[] = {
TEGRA_POWERGATE_CPU3,
};
+#define TEGRA_IO_PAD(_id, _dpd, _voltage, _name) \
+ ((struct tegra_io_pad_soc) { \
+ .id = (_id), \
+ .dpd = (_dpd), \
+ .voltage = (_voltage), \
+ .name = (_name), \
+ })
+
+#define TEGRA_IO_PIN_DESC(_id, _dpd, _voltage, _name) \
+ ((struct pinctrl_pin_desc) { \
+ .number = (_id), \
+ .name = (_name) \
+ })
+
+#define TEGRA124_IO_PAD_TABLE(_pad) \
+ /* .id .dpd .voltage .name */ \
+ _pad(TEGRA_IO_PAD_AUDIO, 17, UINT_MAX, "audio"), \
+ _pad(TEGRA_IO_PAD_BB, 15, UINT_MAX, "bb"), \
+ _pad(TEGRA_IO_PAD_CAM, 36, UINT_MAX, "cam"), \
+ _pad(TEGRA_IO_PAD_COMP, 22, UINT_MAX, "comp"), \
+ _pad(TEGRA_IO_PAD_CSIA, 0, UINT_MAX, "csia"), \
+ _pad(TEGRA_IO_PAD_CSIB, 1, UINT_MAX, "csb"), \
+ _pad(TEGRA_IO_PAD_CSIE, 44, UINT_MAX, "cse"), \
+ _pad(TEGRA_IO_PAD_DSI, 2, UINT_MAX, "dsi"), \
+ _pad(TEGRA_IO_PAD_DSIB, 39, UINT_MAX, "dsib"), \
+ _pad(TEGRA_IO_PAD_DSIC, 40, UINT_MAX, "dsic"), \
+ _pad(TEGRA_IO_PAD_DSID, 41, UINT_MAX, "dsid"), \
+ _pad(TEGRA_IO_PAD_HDMI, 28, UINT_MAX, "hdmi"), \
+ _pad(TEGRA_IO_PAD_HSIC, 19, UINT_MAX, "hsic"), \
+ _pad(TEGRA_IO_PAD_HV, 38, UINT_MAX, "hv"), \
+ _pad(TEGRA_IO_PAD_LVDS, 57, UINT_MAX, "lvds"), \
+ _pad(TEGRA_IO_PAD_MIPI_BIAS, 3, UINT_MAX, "mipi-bias"), \
+ _pad(TEGRA_IO_PAD_NAND, 13, UINT_MAX, "nand"), \
+ _pad(TEGRA_IO_PAD_PEX_BIAS, 4, UINT_MAX, "pex-bias"), \
+ _pad(TEGRA_IO_PAD_PEX_CLK1, 5, UINT_MAX, "pex-clk1"), \
+ _pad(TEGRA_IO_PAD_PEX_CLK2, 6, UINT_MAX, "pex-clk2"), \
+ _pad(TEGRA_IO_PAD_PEX_CNTRL, 32, UINT_MAX, "pex-cntrl"), \
+ _pad(TEGRA_IO_PAD_SDMMC1, 33, UINT_MAX, "sdmmc1"), \
+ _pad(TEGRA_IO_PAD_SDMMC3, 34, UINT_MAX, "sdmmc3"), \
+ _pad(TEGRA_IO_PAD_SDMMC4, 35, UINT_MAX, "sdmmc4"), \
+ _pad(TEGRA_IO_PAD_SYS_DDC, 58, UINT_MAX, "sys_ddc"), \
+ _pad(TEGRA_IO_PAD_UART, 14, UINT_MAX, "uart"), \
+ _pad(TEGRA_IO_PAD_USB0, 9, UINT_MAX, "usb0"), \
+ _pad(TEGRA_IO_PAD_USB1, 10, UINT_MAX, "usb1"), \
+ _pad(TEGRA_IO_PAD_USB2, 11, UINT_MAX, "usb2"), \
+ _pad(TEGRA_IO_PAD_USB_BIAS, 12, UINT_MAX, "usb_bias")
+
static const struct tegra_io_pad_soc tegra124_io_pads[] = {
- { .id = TEGRA_IO_PAD_AUDIO, .dpd = 17, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_BB, .dpd = 15, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_CAM, .dpd = 36, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_COMP, .dpd = 22, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_CSIA, .dpd = 0, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_CSIB, .dpd = 1, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_CSIE, .dpd = 44, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_DSI, .dpd = 2, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_DSIB, .dpd = 39, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_DSIC, .dpd = 40, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_DSID, .dpd = 41, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_HDMI, .dpd = 28, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_HSIC, .dpd = 19, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_HV, .dpd = 38, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_LVDS, .dpd = 57, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_MIPI_BIAS, .dpd = 3, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_NAND, .dpd = 13, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_PEX_BIAS, .dpd = 4, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_PEX_CLK1, .dpd = 5, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_PEX_CLK2, .dpd = 6, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_PEX_CNTRL, .dpd = 32, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_SDMMC1, .dpd = 33, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_SDMMC3, .dpd = 34, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_SDMMC4, .dpd = 35, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_SYS_DDC, .dpd = 58, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_UART, .dpd = 14, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_USB0, .dpd = 9, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_USB1, .dpd = 10, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_USB2, .dpd = 11, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_USB_BIAS, .dpd = 12, .voltage = UINT_MAX },
+ TEGRA124_IO_PAD_TABLE(TEGRA_IO_PAD)
+};
+
+static const struct pinctrl_pin_desc tegra124_pin_descs[] = {
+ TEGRA124_IO_PAD_TABLE(TEGRA_IO_PIN_DESC)
};
static const struct tegra_pmc_soc tegra124_pmc_soc = {
@@ -1689,8 +1918,11 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = {
.cpu_powergates = tegra124_cpu_powergates,
.has_tsense_reset = true,
.has_gpu_clamps = true,
+ .has_impl_33v_pwr = false,
.num_io_pads = ARRAY_SIZE(tegra124_io_pads),
.io_pads = tegra124_io_pads,
+ .num_pin_descs = ARRAY_SIZE(tegra124_pin_descs),
+ .pin_descs = tegra124_pin_descs,
.regs = &tegra20_pmc_regs,
.init = tegra20_pmc_init,
.setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
@@ -1730,45 +1962,53 @@ static const u8 tegra210_cpu_powergates[] = {
TEGRA_POWERGATE_CPU3,
};
+#define TEGRA210_IO_PAD_TABLE(_pad) \
+ /* .id .dpd .voltage .name */ \
+ _pad(TEGRA_IO_PAD_AUDIO, 17, 5, "audio"), \
+ _pad(TEGRA_IO_PAD_AUDIO_HV, 61, 18, "audio-hv"), \
+ _pad(TEGRA_IO_PAD_CAM, 36, 10, "cam"), \
+ _pad(TEGRA_IO_PAD_CSIA, 0, UINT_MAX, "csia"), \
+ _pad(TEGRA_IO_PAD_CSIB, 1, UINT_MAX, "csib"), \
+ _pad(TEGRA_IO_PAD_CSIC, 42, UINT_MAX, "csic"), \
+ _pad(TEGRA_IO_PAD_CSID, 43, UINT_MAX, "csid"), \
+ _pad(TEGRA_IO_PAD_CSIE, 44, UINT_MAX, "csie"), \
+ _pad(TEGRA_IO_PAD_CSIF, 45, UINT_MAX, "csif"), \
+ _pad(TEGRA_IO_PAD_DBG, 25, 19, "dbg"), \
+ _pad(TEGRA_IO_PAD_DEBUG_NONAO, 26, UINT_MAX, "debug-nonao"), \
+ _pad(TEGRA_IO_PAD_DMIC, 50, 20, "dmic"), \
+ _pad(TEGRA_IO_PAD_DP, 51, UINT_MAX, "dp"), \
+ _pad(TEGRA_IO_PAD_DSI, 2, UINT_MAX, "dsi"), \
+ _pad(TEGRA_IO_PAD_DSIB, 39, UINT_MAX, "dsib"), \
+ _pad(TEGRA_IO_PAD_DSIC, 40, UINT_MAX, "dsic"), \
+ _pad(TEGRA_IO_PAD_DSID, 41, UINT_MAX, "dsid"), \
+ _pad(TEGRA_IO_PAD_EMMC, 35, UINT_MAX, "emmc"), \
+ _pad(TEGRA_IO_PAD_EMMC2, 37, UINT_MAX, "emmc2"), \
+ _pad(TEGRA_IO_PAD_GPIO, 27, 21, "gpio"), \
+ _pad(TEGRA_IO_PAD_HDMI, 28, UINT_MAX, "hdmi"), \
+ _pad(TEGRA_IO_PAD_HSIC, 19, UINT_MAX, "hsic"), \
+ _pad(TEGRA_IO_PAD_LVDS, 57, UINT_MAX, "lvds"), \
+ _pad(TEGRA_IO_PAD_MIPI_BIAS, 3, UINT_MAX, "mipi-bias"), \
+ _pad(TEGRA_IO_PAD_PEX_BIAS, 4, UINT_MAX, "pex-bias"), \
+ _pad(TEGRA_IO_PAD_PEX_CLK1, 5, UINT_MAX, "pex-clk1"), \
+ _pad(TEGRA_IO_PAD_PEX_CLK2, 6, UINT_MAX, "pex-clk2"), \
+ _pad(TEGRA_IO_PAD_PEX_CNTRL, UINT_MAX, 11, "pex-cntrl"), \
+ _pad(TEGRA_IO_PAD_SDMMC1, 33, 12, "sdmmc1"), \
+ _pad(TEGRA_IO_PAD_SDMMC3, 34, 13, "sdmmc3"), \
+ _pad(TEGRA_IO_PAD_SPI, 46, 22, "spi"), \
+ _pad(TEGRA_IO_PAD_SPI_HV, 47, 23, "spi-hv"), \
+ _pad(TEGRA_IO_PAD_UART, 14, 2, "uart"), \
+ _pad(TEGRA_IO_PAD_USB0, 9, UINT_MAX, "usb0"), \
+ _pad(TEGRA_IO_PAD_USB1, 10, UINT_MAX, "usb1"), \
+ _pad(TEGRA_IO_PAD_USB2, 11, UINT_MAX, "usb2"), \
+ _pad(TEGRA_IO_PAD_USB3, 18, UINT_MAX, "usb3"), \
+ _pad(TEGRA_IO_PAD_USB_BIAS, 12, UINT_MAX, "usb-bias")
+
static const struct tegra_io_pad_soc tegra210_io_pads[] = {
- { .id = TEGRA_IO_PAD_AUDIO, .dpd = 17, .voltage = 5 },
- { .id = TEGRA_IO_PAD_AUDIO_HV, .dpd = 61, .voltage = 18 },
- { .id = TEGRA_IO_PAD_CAM, .dpd = 36, .voltage = 10 },
- { .id = TEGRA_IO_PAD_CSIA, .dpd = 0, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_CSIB, .dpd = 1, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_CSIC, .dpd = 42, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_CSID, .dpd = 43, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_CSIE, .dpd = 44, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_CSIF, .dpd = 45, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_DBG, .dpd = 25, .voltage = 19 },
- { .id = TEGRA_IO_PAD_DEBUG_NONAO, .dpd = 26, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_DMIC, .dpd = 50, .voltage = 20 },
- { .id = TEGRA_IO_PAD_DP, .dpd = 51, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_DSI, .dpd = 2, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_DSIB, .dpd = 39, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_DSIC, .dpd = 40, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_DSID, .dpd = 41, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_EMMC, .dpd = 35, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_EMMC2, .dpd = 37, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_GPIO, .dpd = 27, .voltage = 21 },
- { .id = TEGRA_IO_PAD_HDMI, .dpd = 28, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_HSIC, .dpd = 19, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_LVDS, .dpd = 57, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_MIPI_BIAS, .dpd = 3, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_PEX_BIAS, .dpd = 4, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_PEX_CLK1, .dpd = 5, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_PEX_CLK2, .dpd = 6, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_PEX_CNTRL, .dpd = UINT_MAX, .voltage = 11 },
- { .id = TEGRA_IO_PAD_SDMMC1, .dpd = 33, .voltage = 12 },
- { .id = TEGRA_IO_PAD_SDMMC3, .dpd = 34, .voltage = 13 },
- { .id = TEGRA_IO_PAD_SPI, .dpd = 46, .voltage = 22 },
- { .id = TEGRA_IO_PAD_SPI_HV, .dpd = 47, .voltage = 23 },
- { .id = TEGRA_IO_PAD_UART, .dpd = 14, .voltage = 2 },
- { .id = TEGRA_IO_PAD_USB0, .dpd = 9, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_USB1, .dpd = 10, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_USB2, .dpd = 11, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_USB3, .dpd = 18, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_USB_BIAS, .dpd = 12, .voltage = UINT_MAX },
+ TEGRA210_IO_PAD_TABLE(TEGRA_IO_PAD)
+};
+
+static const struct pinctrl_pin_desc tegra210_pin_descs[] = {
+ TEGRA210_IO_PAD_TABLE(TEGRA_IO_PIN_DESC)
};
static const struct tegra_pmc_soc tegra210_pmc_soc = {
@@ -1778,52 +2018,64 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = {
.cpu_powergates = tegra210_cpu_powergates,
.has_tsense_reset = true,
.has_gpu_clamps = true,
+ .has_impl_33v_pwr = false,
.needs_mbist_war = true,
.num_io_pads = ARRAY_SIZE(tegra210_io_pads),
.io_pads = tegra210_io_pads,
+ .num_pin_descs = ARRAY_SIZE(tegra210_pin_descs),
+ .pin_descs = tegra210_pin_descs,
.regs = &tegra20_pmc_regs,
.init = tegra20_pmc_init,
.setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
};
+#define TEGRA186_IO_PAD_TABLE(_pad) \
+ /* .id .dpd .voltage .name */ \
+ _pad(TEGRA_IO_PAD_CSIA, 0, UINT_MAX, "csia"), \
+ _pad(TEGRA_IO_PAD_CSIB, 1, UINT_MAX, "csib"), \
+ _pad(TEGRA_IO_PAD_DSI, 2, UINT_MAX, "dsi"), \
+ _pad(TEGRA_IO_PAD_MIPI_BIAS, 3, UINT_MAX, "mipi-bias"), \
+ _pad(TEGRA_IO_PAD_PEX_CLK_BIAS, 4, UINT_MAX, "pex-clk-bias"), \
+ _pad(TEGRA_IO_PAD_PEX_CLK3, 5, UINT_MAX, "pex-clk3"), \
+ _pad(TEGRA_IO_PAD_PEX_CLK2, 6, UINT_MAX, "pex-clk2"), \
+ _pad(TEGRA_IO_PAD_PEX_CLK1, 7, UINT_MAX, "pex-clk1"), \
+ _pad(TEGRA_IO_PAD_USB0, 9, UINT_MAX, "usb0"), \
+ _pad(TEGRA_IO_PAD_USB1, 10, UINT_MAX, "usb1"), \
+ _pad(TEGRA_IO_PAD_USB2, 11, UINT_MAX, "usb2"), \
+ _pad(TEGRA_IO_PAD_USB_BIAS, 12, UINT_MAX, "usb-bias"), \
+ _pad(TEGRA_IO_PAD_UART, 14, UINT_MAX, "uart"), \
+ _pad(TEGRA_IO_PAD_AUDIO, 17, UINT_MAX, "audio"), \
+ _pad(TEGRA_IO_PAD_HSIC, 19, UINT_MAX, "hsic"), \
+ _pad(TEGRA_IO_PAD_DBG, 25, UINT_MAX, "dbg"), \
+ _pad(TEGRA_IO_PAD_HDMI_DP0, 28, UINT_MAX, "hdmi-dp0"), \
+ _pad(TEGRA_IO_PAD_HDMI_DP1, 29, UINT_MAX, "hdmi-dp1"), \
+ _pad(TEGRA_IO_PAD_PEX_CNTRL, 32, UINT_MAX, "pex-cntrl"), \
+ _pad(TEGRA_IO_PAD_SDMMC2_HV, 34, 5, "sdmmc2-hv"), \
+ _pad(TEGRA_IO_PAD_SDMMC4, 36, UINT_MAX, "sdmmc4"), \
+ _pad(TEGRA_IO_PAD_CAM, 38, UINT_MAX, "cam"), \
+ _pad(TEGRA_IO_PAD_DSIB, 40, UINT_MAX, "dsib"), \
+ _pad(TEGRA_IO_PAD_DSIC, 41, UINT_MAX, "dsic"), \
+ _pad(TEGRA_IO_PAD_DSID, 42, UINT_MAX, "dsid"), \
+ _pad(TEGRA_IO_PAD_CSIC, 43, UINT_MAX, "csic"), \
+ _pad(TEGRA_IO_PAD_CSID, 44, UINT_MAX, "csid"), \
+ _pad(TEGRA_IO_PAD_CSIE, 45, UINT_MAX, "csie"), \
+ _pad(TEGRA_IO_PAD_CSIF, 46, UINT_MAX, "csif"), \
+ _pad(TEGRA_IO_PAD_SPI, 47, UINT_MAX, "spi"), \
+ _pad(TEGRA_IO_PAD_UFS, 49, UINT_MAX, "ufs"), \
+ _pad(TEGRA_IO_PAD_DMIC_HV, 52, 2, "dmic-hv"), \
+ _pad(TEGRA_IO_PAD_EDP, 53, UINT_MAX, "edp"), \
+ _pad(TEGRA_IO_PAD_SDMMC1_HV, 55, 4, "sdmmc1-hv"), \
+ _pad(TEGRA_IO_PAD_SDMMC3_HV, 56, 6, "sdmmc3-hv"), \
+ _pad(TEGRA_IO_PAD_CONN, 60, UINT_MAX, "conn"), \
+ _pad(TEGRA_IO_PAD_AUDIO_HV, 61, 1, "audio-hv"), \
+ _pad(TEGRA_IO_PAD_AO_HV, UINT_MAX, 0, "ao-hv")
+
static const struct tegra_io_pad_soc tegra186_io_pads[] = {
- { .id = TEGRA_IO_PAD_CSIA, .dpd = 0, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_CSIB, .dpd = 1, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_DSI, .dpd = 2, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_MIPI_BIAS, .dpd = 3, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_PEX_CLK_BIAS, .dpd = 4, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_PEX_CLK3, .dpd = 5, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_PEX_CLK2, .dpd = 6, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_PEX_CLK1, .dpd = 7, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_USB0, .dpd = 9, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_USB1, .dpd = 10, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_USB2, .dpd = 11, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_USB_BIAS, .dpd = 12, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_UART, .dpd = 14, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_AUDIO, .dpd = 17, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_HSIC, .dpd = 19, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_DBG, .dpd = 25, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_HDMI_DP0, .dpd = 28, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_HDMI_DP1, .dpd = 29, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_PEX_CNTRL, .dpd = 32, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_SDMMC2_HV, .dpd = 34, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_SDMMC4, .dpd = 36, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_CAM, .dpd = 38, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_DSIB, .dpd = 40, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_DSIC, .dpd = 41, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_DSID, .dpd = 42, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_CSIC, .dpd = 43, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_CSID, .dpd = 44, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_CSIE, .dpd = 45, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_CSIF, .dpd = 46, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_SPI, .dpd = 47, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_UFS, .dpd = 49, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_DMIC_HV, .dpd = 52, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_EDP, .dpd = 53, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_SDMMC1_HV, .dpd = 55, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_SDMMC3_HV, .dpd = 56, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_CONN, .dpd = 60, .voltage = UINT_MAX },
- { .id = TEGRA_IO_PAD_AUDIO_HV, .dpd = 61, .voltage = UINT_MAX },
+ TEGRA186_IO_PAD_TABLE(TEGRA_IO_PAD)
+};
+
+static const struct pinctrl_pin_desc tegra186_pin_descs[] = {
+ TEGRA186_IO_PAD_TABLE(TEGRA_IO_PIN_DESC)
};
static const struct tegra_pmc_regs tegra186_pmc_regs = {
@@ -1876,8 +2128,11 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = {
.cpu_powergates = NULL,
.has_tsense_reset = false,
.has_gpu_clamps = false,
+ .has_impl_33v_pwr = true,
.num_io_pads = ARRAY_SIZE(tegra186_io_pads),
.io_pads = tegra186_io_pads,
+ .num_pin_descs = ARRAY_SIZE(tegra186_pin_descs),
+ .pin_descs = tegra186_pin_descs,
.regs = &tegra186_pmc_regs,
.init = NULL,
.setup_irq_polarity = tegra186_pmc_setup_irq_polarity,
diff --git a/drivers/soc/ti/knav_dma.c b/drivers/soc/ti/knav_dma.c
index 224d7ddeeb76..e05ab16d9a9e 100644
--- a/drivers/soc/ti/knav_dma.c
+++ b/drivers/soc/ti/knav_dma.c
@@ -438,7 +438,7 @@ void *knav_dma_open_channel(struct device *dev, const char *name,
chan_num = of_channel_match_helper(dev->of_node, name, &instance);
if (chan_num < 0) {
- dev_err(kdev->dev, "No DMA instace with name %s\n", name);
+ dev_err(kdev->dev, "No DMA instance with name %s\n", name);
return (void *)-EINVAL;
}
@@ -461,7 +461,7 @@ void *knav_dma_open_channel(struct device *dev, const char *name,
}
}
if (!found) {
- dev_err(kdev->dev, "No DMA instace with name %s\n", instance);
+ dev_err(kdev->dev, "No DMA instance with name %s\n", instance);
return (void *)-EINVAL;
}
@@ -544,15 +544,15 @@ static void __iomem *pktdma_get_regs(struct knav_dma_device *dma,
ret = of_address_to_resource(node, index, &res);
if (ret) {
- dev_err(dev, "Can't translate of node(%s) address for index(%d)\n",
- node->name, index);
+ dev_err(dev, "Can't translate of node(%pOFn) address for index(%d)\n",
+ node, index);
return ERR_PTR(ret);
}
regs = devm_ioremap_resource(kdev->dev, &res);
if (IS_ERR(regs))
- dev_err(dev, "Failed to map register base for index(%d) node(%s)\n",
- index, node->name);
+ dev_err(dev, "Failed to map register base for index(%d) node(%pOFn)\n",
+ index, node);
if (_size)
*_size = resource_size(&res);
diff --git a/drivers/soc/ti/knav_qmss.h b/drivers/soc/ti/knav_qmss.h
index 3efc47e82973..4c28fa938ac7 100644
--- a/drivers/soc/ti/knav_qmss.h
+++ b/drivers/soc/ti/knav_qmss.h
@@ -240,14 +240,14 @@ struct knav_pool {
};
/**
- * struct knav_queue_inst: qmss queue instace properties
+ * struct knav_queue_inst: qmss queue instance properties
* @descs: descriptor pointer
* @desc_head, desc_tail, desc_count: descriptor counters
* @acc: accumulator channel pointer
* @kdev: qmss device pointer
* @range: range info
* @qmgr: queue manager info
- * @id: queue instace id
+ * @id: queue instance id
* @irq_num: irq line number
* @notify_needed: notifier needed based on queue type
* @num_notifiers: total notifiers
@@ -274,7 +274,7 @@ struct knav_queue_inst {
/**
* struct knav_queue: qmss queue properties
* @reg_push, reg_pop, reg_peek: push, pop queue registers
- * @inst: qmss queue instace properties
+ * @inst: qmss queue instance properties
* @notifier_fn: notifier function
* @notifier_fn_arg: notifier function argument
* @notifier_enabled: notier enabled for a give queue
@@ -329,8 +329,8 @@ struct knav_range_ops {
};
struct knav_irq_info {
- int irq;
- u32 cpu_map;
+ int irq;
+ struct cpumask *cpu_mask;
};
struct knav_range_info {
diff --git a/drivers/soc/ti/knav_qmss_acc.c b/drivers/soc/ti/knav_qmss_acc.c
index 316e82e46f6c..2f7fb2dcc1d6 100644
--- a/drivers/soc/ti/knav_qmss_acc.c
+++ b/drivers/soc/ti/knav_qmss_acc.c
@@ -205,18 +205,18 @@ static int knav_range_setup_acc_irq(struct knav_range_info *range,
{
struct knav_device *kdev = range->kdev;
struct knav_acc_channel *acc;
- unsigned long cpu_map;
+ struct cpumask *cpu_mask;
int ret = 0, irq;
u32 old, new;
if (range->flags & RANGE_MULTI_QUEUE) {
acc = range->acc;
irq = range->irqs[0].irq;
- cpu_map = range->irqs[0].cpu_map;
+ cpu_mask = range->irqs[0].cpu_mask;
} else {
acc = range->acc + queue;
irq = range->irqs[queue].irq;
- cpu_map = range->irqs[queue].cpu_map;
+ cpu_mask = range->irqs[queue].cpu_mask;
}
old = acc->open_mask;
@@ -239,8 +239,8 @@ static int knav_range_setup_acc_irq(struct knav_range_info *range,
acc->name, acc->name);
ret = request_irq(irq, knav_acc_int_handler, 0, acc->name,
range);
- if (!ret && cpu_map) {
- ret = irq_set_affinity_hint(irq, to_cpumask(&cpu_map));
+ if (!ret && cpu_mask) {
+ ret = irq_set_affinity_hint(irq, cpu_mask);
if (ret) {
dev_warn(range->kdev->dev,
"Failed to set IRQ affinity\n");
diff --git a/drivers/soc/ti/knav_qmss_queue.c b/drivers/soc/ti/knav_qmss_queue.c
index 6755f2af5619..8b418379272d 100644
--- a/drivers/soc/ti/knav_qmss_queue.c
+++ b/drivers/soc/ti/knav_qmss_queue.c
@@ -118,19 +118,17 @@ static int knav_queue_setup_irq(struct knav_range_info *range,
struct knav_queue_inst *inst)
{
unsigned queue = inst->id - range->queue_base;
- unsigned long cpu_map;
int ret = 0, irq;
if (range->flags & RANGE_HAS_IRQ) {
irq = range->irqs[queue].irq;
- cpu_map = range->irqs[queue].cpu_map;
ret = request_irq(irq, knav_queue_int_handler, 0,
inst->irq_name, inst);
if (ret)
return ret;
disable_irq(irq);
- if (cpu_map) {
- ret = irq_set_affinity_hint(irq, to_cpumask(&cpu_map));
+ if (range->irqs[queue].cpu_mask) {
+ ret = irq_set_affinity_hint(irq, range->irqs[queue].cpu_mask);
if (ret) {
dev_warn(range->kdev->dev,
"Failed to set IRQ affinity\n");
@@ -1262,9 +1260,19 @@ static int knav_setup_queue_range(struct knav_device *kdev,
range->num_irqs++;
- if (IS_ENABLED(CONFIG_SMP) && oirq.args_count == 3)
- range->irqs[i].cpu_map =
- (oirq.args[2] & 0x0000ff00) >> 8;
+ if (IS_ENABLED(CONFIG_SMP) && oirq.args_count == 3) {
+ unsigned long mask;
+ int bit;
+
+ range->irqs[i].cpu_mask = devm_kzalloc(dev,
+ cpumask_size(), GFP_KERNEL);
+ if (!range->irqs[i].cpu_mask)
+ return -ENOMEM;
+
+ mask = (oirq.args[2] & 0x0000ff00) >> 8;
+ for_each_set_bit(bit, &mask, BITS_PER_LONG)
+ cpumask_set_cpu(bit, range->irqs[i].cpu_mask);
+ }
}
range->num_irqs = min(range->num_irqs, range->num_queues);
@@ -1382,15 +1390,15 @@ static void __iomem *knav_queue_map_reg(struct knav_device *kdev,
ret = of_address_to_resource(node, index, &res);
if (ret) {
- dev_err(kdev->dev, "Can't translate of node(%s) address for index(%d)\n",
- node->name, index);
+ dev_err(kdev->dev, "Can't translate of node(%pOFn) address for index(%d)\n",
+ node, index);
return ERR_PTR(ret);
}
regs = devm_ioremap_resource(kdev->dev, &res);
if (IS_ERR(regs))
- dev_err(kdev->dev, "Failed to map register base for index(%d) node(%s)\n",
- index, node->name);
+ dev_err(kdev->dev, "Failed to map register base for index(%d) node(%pOFn)\n",
+ index, node);
return regs;
}
diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
index dcc0ff9f0c22..1cbfedfc20ef 100644
--- a/drivers/soundwire/bus.c
+++ b/drivers/soundwire/bus.c
@@ -35,6 +35,11 @@ int sdw_add_bus_master(struct sdw_bus *bus)
INIT_LIST_HEAD(&bus->slaves);
INIT_LIST_HEAD(&bus->m_rt_list);
+ /*
+ * Initialize multi_link flag
+ * TODO: populate this flag by reading property from FW node
+ */
+ bus->multi_link = false;
if (bus->ops->read_prop) {
ret = bus->ops->read_prop(bus);
if (ret < 0) {
@@ -175,6 +180,7 @@ static inline int do_transfer_defer(struct sdw_bus *bus,
defer->msg = msg;
defer->length = msg->len;
+ init_completion(&defer->complete);
for (i = 0; i <= retry; i++) {
resp = bus->ops->xfer_msg_defer(bus, msg, defer);
diff --git a/drivers/soundwire/bus.h b/drivers/soundwire/bus.h
index 3b15c4e25a3a..c77de05b8100 100644
--- a/drivers/soundwire/bus.h
+++ b/drivers/soundwire/bus.h
@@ -4,6 +4,8 @@
#ifndef __SDW_BUS_H
#define __SDW_BUS_H
+#define DEFAULT_BANK_SWITCH_TIMEOUT 3000
+
#if IS_ENABLED(CONFIG_ACPI)
int sdw_acpi_find_slaves(struct sdw_bus *bus);
#else
@@ -99,6 +101,7 @@ struct sdw_slave_runtime {
* this stream, can be zero.
* @slave_rt_list: Slave runtime list
* @port_list: List of Master Ports configured for this stream, can be zero.
+ * @stream_node: sdw_stream_runtime master_list node
* @bus_node: sdw_bus m_rt_list node
*/
struct sdw_master_runtime {
@@ -108,6 +111,7 @@ struct sdw_master_runtime {
unsigned int ch_count;
struct list_head slave_rt_list;
struct list_head port_list;
+ struct list_head stream_node;
struct list_head bus_node;
};
diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
index 0a8990e758f9..c5ee97ee7886 100644
--- a/drivers/soundwire/intel.c
+++ b/drivers/soundwire/intel.c
@@ -398,6 +398,69 @@ static int intel_config_stream(struct sdw_intel *sdw,
}
/*
+ * bank switch routines
+ */
+
+static int intel_pre_bank_switch(struct sdw_bus *bus)
+{
+ struct sdw_cdns *cdns = bus_to_cdns(bus);
+ struct sdw_intel *sdw = cdns_to_intel(cdns);
+ void __iomem *shim = sdw->res->shim;
+ int sync_reg;
+
+ /* Write to register only for multi-link */
+ if (!bus->multi_link)
+ return 0;
+
+ /* Read SYNC register */
+ sync_reg = intel_readl(shim, SDW_SHIM_SYNC);
+ sync_reg |= SDW_SHIM_SYNC_CMDSYNC << sdw->instance;
+ intel_writel(shim, SDW_SHIM_SYNC, sync_reg);
+
+ return 0;
+}
+
+static int intel_post_bank_switch(struct sdw_bus *bus)
+{
+ struct sdw_cdns *cdns = bus_to_cdns(bus);
+ struct sdw_intel *sdw = cdns_to_intel(cdns);
+ void __iomem *shim = sdw->res->shim;
+ int sync_reg, ret;
+
+ /* Write to register only for multi-link */
+ if (!bus->multi_link)
+ return 0;
+
+ /* Read SYNC register */
+ sync_reg = intel_readl(shim, SDW_SHIM_SYNC);
+
+ /*
+ * post_bank_switch() ops is called from the bus in loop for
+ * all the Masters in the steam with the expectation that
+ * we trigger the bankswitch for the only first Master in the list
+ * and do nothing for the other Masters
+ *
+ * So, set the SYNCGO bit only if CMDSYNC bit is set for any Master.
+ */
+ if (!(sync_reg & SDW_SHIM_SYNC_CMDSYNC_MASK))
+ return 0;
+
+ /*
+ * Set SyncGO bit to synchronously trigger a bank switch for
+ * all the masters. A write to SYNCGO bit clears CMDSYNC bit for all
+ * the Masters.
+ */
+ sync_reg |= SDW_SHIM_SYNC_SYNCGO;
+
+ ret = intel_clear_bit(shim, SDW_SHIM_SYNC, sync_reg,
+ SDW_SHIM_SYNC_SYNCGO);
+ if (ret < 0)
+ dev_err(sdw->cdns.dev, "Post bank switch failed: %d", ret);
+
+ return ret;
+}
+
+/*
* DAI routines
*/
@@ -750,6 +813,8 @@ static struct sdw_master_ops sdw_intel_ops = {
.xfer_msg_defer = cdns_xfer_msg_defer,
.reset_page_addr = cdns_reset_page_addr,
.set_bus_conf = cdns_bus_conf,
+ .pre_bank_switch = intel_pre_bank_switch,
+ .post_bank_switch = intel_post_bank_switch,
};
/*
@@ -780,9 +845,6 @@ static int intel_probe(struct platform_device *pdev)
sdw_intel_ops.read_prop = intel_prop_read;
sdw->cdns.bus.ops = &sdw_intel_ops;
- sdw_intel_ops.read_prop = intel_prop_read;
- sdw->cdns.bus.ops = &sdw_intel_ops;
-
platform_set_drvdata(pdev, sdw);
ret = sdw_add_bus_master(&sdw->cdns.bus);
diff --git a/drivers/soundwire/intel_init.c b/drivers/soundwire/intel_init.c
index d1ea6b4d0ad3..5c8a20d99878 100644
--- a/drivers/soundwire/intel_init.c
+++ b/drivers/soundwire/intel_init.c
@@ -151,7 +151,7 @@ static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level,
struct acpi_device *adev;
if (acpi_bus_get_device(handle, &adev)) {
- dev_err(&adev->dev, "Couldn't find ACPI handle\n");
+ pr_err("%s: Couldn't find ACPI handle\n", __func__);
return AE_NOT_FOUND;
}
diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c
index e5c7e1ef6318..bd879b1a76c8 100644
--- a/drivers/soundwire/stream.c
+++ b/drivers/soundwire/stream.c
@@ -626,9 +626,10 @@ static int sdw_program_params(struct sdw_bus *bus)
return ret;
}
-static int sdw_bank_switch(struct sdw_bus *bus)
+static int sdw_bank_switch(struct sdw_bus *bus, int m_rt_count)
{
int col_index, row_index;
+ bool multi_link;
struct sdw_msg *wr_msg;
u8 *wbuf = NULL;
int ret = 0;
@@ -638,6 +639,8 @@ static int sdw_bank_switch(struct sdw_bus *bus)
if (!wr_msg)
return -ENOMEM;
+ bus->defer_msg.msg = wr_msg;
+
wbuf = kzalloc(sizeof(*wbuf), GFP_KERNEL);
if (!wbuf) {
ret = -ENOMEM;
@@ -658,17 +661,29 @@ static int sdw_bank_switch(struct sdw_bus *bus)
SDW_MSG_FLAG_WRITE, wbuf);
wr_msg->ssp_sync = true;
- ret = sdw_transfer(bus, wr_msg);
+ /*
+ * Set the multi_link flag only when both the hardware supports
+ * and there is a stream handled by multiple masters
+ */
+ multi_link = bus->multi_link && (m_rt_count > 1);
+
+ if (multi_link)
+ ret = sdw_transfer_defer(bus, wr_msg, &bus->defer_msg);
+ else
+ ret = sdw_transfer(bus, wr_msg);
+
if (ret < 0) {
dev_err(bus->dev, "Slave frame_ctrl reg write failed");
goto error;
}
- kfree(wr_msg);
- kfree(wbuf);
- bus->defer_msg.msg = NULL;
- bus->params.curr_bank = !bus->params.curr_bank;
- bus->params.next_bank = !bus->params.next_bank;
+ if (!multi_link) {
+ kfree(wr_msg);
+ kfree(wbuf);
+ bus->defer_msg.msg = NULL;
+ bus->params.curr_bank = !bus->params.curr_bank;
+ bus->params.next_bank = !bus->params.next_bank;
+ }
return 0;
@@ -679,37 +694,138 @@ error_1:
return ret;
}
+/**
+ * sdw_ml_sync_bank_switch: Multilink register bank switch
+ *
+ * @bus: SDW bus instance
+ *
+ * Caller function should free the buffers on error
+ */
+static int sdw_ml_sync_bank_switch(struct sdw_bus *bus)
+{
+ unsigned long time_left;
+
+ if (!bus->multi_link)
+ return 0;
+
+ /* Wait for completion of transfer */
+ time_left = wait_for_completion_timeout(&bus->defer_msg.complete,
+ bus->bank_switch_timeout);
+
+ if (!time_left) {
+ dev_err(bus->dev, "Controller Timed out on bank switch");
+ return -ETIMEDOUT;
+ }
+
+ bus->params.curr_bank = !bus->params.curr_bank;
+ bus->params.next_bank = !bus->params.next_bank;
+
+ if (bus->defer_msg.msg) {
+ kfree(bus->defer_msg.msg->buf);
+ kfree(bus->defer_msg.msg);
+ }
+
+ return 0;
+}
+
static int do_bank_switch(struct sdw_stream_runtime *stream)
{
- struct sdw_master_runtime *m_rt = stream->m_rt;
+ struct sdw_master_runtime *m_rt = NULL;
const struct sdw_master_ops *ops;
- struct sdw_bus *bus = m_rt->bus;
+ struct sdw_bus *bus = NULL;
+ bool multi_link = false;
int ret = 0;
- ops = bus->ops;
+ list_for_each_entry(m_rt, &stream->master_list, stream_node) {
+ bus = m_rt->bus;
+ ops = bus->ops;
+
+ if (bus->multi_link) {
+ multi_link = true;
+ mutex_lock(&bus->msg_lock);
+ }
+
+ /* Pre-bank switch */
+ if (ops->pre_bank_switch) {
+ ret = ops->pre_bank_switch(bus);
+ if (ret < 0) {
+ dev_err(bus->dev,
+ "Pre bank switch op failed: %d", ret);
+ goto msg_unlock;
+ }
+ }
- /* Pre-bank switch */
- if (ops->pre_bank_switch) {
- ret = ops->pre_bank_switch(bus);
+ /*
+ * Perform Bank switch operation.
+ * For multi link cases, the actual bank switch is
+ * synchronized across all Masters and happens later as a
+ * part of post_bank_switch ops.
+ */
+ ret = sdw_bank_switch(bus, stream->m_rt_count);
if (ret < 0) {
- dev_err(bus->dev, "Pre bank switch op failed: %d", ret);
- return ret;
+ dev_err(bus->dev, "Bank switch failed: %d", ret);
+ goto error;
+
}
}
- /* Bank switch */
- ret = sdw_bank_switch(bus);
- if (ret < 0) {
- dev_err(bus->dev, "Bank switch failed: %d", ret);
- return ret;
- }
+ /*
+ * For multi link cases, it is expected that the bank switch is
+ * triggered by the post_bank_switch for the first Master in the list
+ * and for the other Masters the post_bank_switch() should return doing
+ * nothing.
+ */
+ list_for_each_entry(m_rt, &stream->master_list, stream_node) {
+ bus = m_rt->bus;
+ ops = bus->ops;
+
+ /* Post-bank switch */
+ if (ops->post_bank_switch) {
+ ret = ops->post_bank_switch(bus);
+ if (ret < 0) {
+ dev_err(bus->dev,
+ "Post bank switch op failed: %d", ret);
+ goto error;
+ }
+ } else if (bus->multi_link && stream->m_rt_count > 1) {
+ dev_err(bus->dev,
+ "Post bank switch ops not implemented");
+ goto error;
+ }
+
+ /* Set the bank switch timeout to default, if not set */
+ if (!bus->bank_switch_timeout)
+ bus->bank_switch_timeout = DEFAULT_BANK_SWITCH_TIMEOUT;
- /* Post-bank switch */
- if (ops->post_bank_switch) {
- ret = ops->post_bank_switch(bus);
+ /* Check if bank switch was successful */
+ ret = sdw_ml_sync_bank_switch(bus);
if (ret < 0) {
dev_err(bus->dev,
- "Post bank switch op failed: %d", ret);
+ "multi link bank switch failed: %d", ret);
+ goto error;
+ }
+
+ mutex_unlock(&bus->msg_lock);
+ }
+
+ return ret;
+
+error:
+ list_for_each_entry(m_rt, &stream->master_list, stream_node) {
+
+ bus = m_rt->bus;
+
+ kfree(bus->defer_msg.msg->buf);
+ kfree(bus->defer_msg.msg);
+ }
+
+msg_unlock:
+
+ if (multi_link) {
+ list_for_each_entry(m_rt, &stream->master_list, stream_node) {
+ bus = m_rt->bus;
+ if (mutex_is_locked(&bus->msg_lock))
+ mutex_unlock(&bus->msg_lock);
}
}
@@ -747,12 +863,29 @@ struct sdw_stream_runtime *sdw_alloc_stream(char *stream_name)
return NULL;
stream->name = stream_name;
+ INIT_LIST_HEAD(&stream->master_list);
stream->state = SDW_STREAM_ALLOCATED;
+ stream->m_rt_count = 0;
return stream;
}
EXPORT_SYMBOL(sdw_alloc_stream);
+static struct sdw_master_runtime
+*sdw_find_master_rt(struct sdw_bus *bus,
+ struct sdw_stream_runtime *stream)
+{
+ struct sdw_master_runtime *m_rt = NULL;
+
+ /* Retrieve Bus handle if already available */
+ list_for_each_entry(m_rt, &stream->master_list, stream_node) {
+ if (m_rt->bus == bus)
+ return m_rt;
+ }
+
+ return NULL;
+}
+
/**
* sdw_alloc_master_rt() - Allocates and initialize Master runtime handle
*
@@ -769,12 +902,11 @@ static struct sdw_master_runtime
{
struct sdw_master_runtime *m_rt;
- m_rt = stream->m_rt;
-
/*
* check if Master is already allocated (as a result of Slave adding
* it first), if so skip allocation and go to configure
*/
+ m_rt = sdw_find_master_rt(bus, stream);
if (m_rt)
goto stream_config;
@@ -785,7 +917,7 @@ static struct sdw_master_runtime
/* Initialization of Master runtime handle */
INIT_LIST_HEAD(&m_rt->port_list);
INIT_LIST_HEAD(&m_rt->slave_rt_list);
- stream->m_rt = m_rt;
+ list_add_tail(&m_rt->stream_node, &stream->master_list);
list_add_tail(&m_rt->bus_node, &bus->m_rt_list);
@@ -843,17 +975,21 @@ static void sdw_slave_port_release(struct sdw_bus *bus,
struct sdw_stream_runtime *stream)
{
struct sdw_port_runtime *p_rt, *_p_rt;
- struct sdw_master_runtime *m_rt = stream->m_rt;
+ struct sdw_master_runtime *m_rt;
struct sdw_slave_runtime *s_rt;
- list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
- if (s_rt->slave != slave)
- continue;
+ list_for_each_entry(m_rt, &stream->master_list, stream_node) {
+ list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
- list_for_each_entry_safe(p_rt, _p_rt,
- &s_rt->port_list, port_node) {
- list_del(&p_rt->port_node);
- kfree(p_rt);
+ if (s_rt->slave != slave)
+ continue;
+
+ list_for_each_entry_safe(p_rt, _p_rt,
+ &s_rt->port_list, port_node) {
+
+ list_del(&p_rt->port_node);
+ kfree(p_rt);
+ }
}
}
}
@@ -870,16 +1006,18 @@ static void sdw_release_slave_stream(struct sdw_slave *slave,
struct sdw_stream_runtime *stream)
{
struct sdw_slave_runtime *s_rt, *_s_rt;
- struct sdw_master_runtime *m_rt = stream->m_rt;
+ struct sdw_master_runtime *m_rt;
- /* Retrieve Slave runtime handle */
- list_for_each_entry_safe(s_rt, _s_rt,
- &m_rt->slave_rt_list, m_rt_node) {
+ list_for_each_entry(m_rt, &stream->master_list, stream_node) {
+ /* Retrieve Slave runtime handle */
+ list_for_each_entry_safe(s_rt, _s_rt,
+ &m_rt->slave_rt_list, m_rt_node) {
- if (s_rt->slave == slave) {
- list_del(&s_rt->m_rt_node);
- kfree(s_rt);
- return;
+ if (s_rt->slave == slave) {
+ list_del(&s_rt->m_rt_node);
+ kfree(s_rt);
+ return;
+ }
}
}
}
@@ -887,6 +1025,7 @@ static void sdw_release_slave_stream(struct sdw_slave *slave,
/**
* sdw_release_master_stream() - Free Master runtime handle
*
+ * @m_rt: Master runtime node
* @stream: Stream runtime handle.
*
* This function is to be called with bus_lock held
@@ -894,9 +1033,9 @@ static void sdw_release_slave_stream(struct sdw_slave *slave,
* handle. If this is called first then sdw_release_slave_stream() will have
* no effect as Slave(s) runtime handle would already be freed up.
*/
-static void sdw_release_master_stream(struct sdw_stream_runtime *stream)
+static void sdw_release_master_stream(struct sdw_master_runtime *m_rt,
+ struct sdw_stream_runtime *stream)
{
- struct sdw_master_runtime *m_rt = stream->m_rt;
struct sdw_slave_runtime *s_rt, *_s_rt;
list_for_each_entry_safe(s_rt, _s_rt, &m_rt->slave_rt_list, m_rt_node) {
@@ -904,7 +1043,9 @@ static void sdw_release_master_stream(struct sdw_stream_runtime *stream)
sdw_release_slave_stream(s_rt->slave, stream);
}
+ list_del(&m_rt->stream_node);
list_del(&m_rt->bus_node);
+ kfree(m_rt);
}
/**
@@ -918,13 +1059,23 @@ static void sdw_release_master_stream(struct sdw_stream_runtime *stream)
int sdw_stream_remove_master(struct sdw_bus *bus,
struct sdw_stream_runtime *stream)
{
+ struct sdw_master_runtime *m_rt, *_m_rt;
+
mutex_lock(&bus->bus_lock);
- sdw_release_master_stream(stream);
- sdw_master_port_release(bus, stream->m_rt);
- stream->state = SDW_STREAM_RELEASED;
- kfree(stream->m_rt);
- stream->m_rt = NULL;
+ list_for_each_entry_safe(m_rt, _m_rt,
+ &stream->master_list, stream_node) {
+
+ if (m_rt->bus != bus)
+ continue;
+
+ sdw_master_port_release(bus, m_rt);
+ sdw_release_master_stream(m_rt, stream);
+ stream->m_rt_count--;
+ }
+
+ if (list_empty(&stream->master_list))
+ stream->state = SDW_STREAM_RELEASED;
mutex_unlock(&bus->bus_lock);
@@ -1107,6 +1258,18 @@ int sdw_stream_add_master(struct sdw_bus *bus,
mutex_lock(&bus->bus_lock);
+ /*
+ * For multi link streams, add the second master only if
+ * the bus supports it.
+ * Check if bus->multi_link is set
+ */
+ if (!bus->multi_link && stream->m_rt_count > 0) {
+ dev_err(bus->dev,
+ "Multilink not supported, link %d", bus->link_id);
+ ret = -EINVAL;
+ goto unlock;
+ }
+
m_rt = sdw_alloc_master_rt(bus, stream_config, stream);
if (!m_rt) {
dev_err(bus->dev,
@@ -1124,10 +1287,12 @@ int sdw_stream_add_master(struct sdw_bus *bus,
if (ret)
goto stream_error;
+ stream->m_rt_count++;
+
goto unlock;
stream_error:
- sdw_release_master_stream(stream);
+ sdw_release_master_stream(m_rt, stream);
unlock:
mutex_unlock(&bus->bus_lock);
return ret;
@@ -1205,7 +1370,7 @@ stream_error:
* we hit error so cleanup the stream, release all Slave(s) and
* Master runtime
*/
- sdw_release_master_stream(stream);
+ sdw_release_master_stream(m_rt, stream);
error:
mutex_unlock(&slave->bus->bus_lock);
return ret;
@@ -1245,33 +1410,82 @@ struct sdw_dpn_prop *sdw_get_slave_dpn_prop(struct sdw_slave *slave,
return NULL;
}
+/**
+ * sdw_acquire_bus_lock: Acquire bus lock for all Master runtime(s)
+ *
+ * @stream: SoundWire stream
+ *
+ * Acquire bus_lock for each of the master runtime(m_rt) part of this
+ * stream to reconfigure the bus.
+ * NOTE: This function is called from SoundWire stream ops and is
+ * expected that a global lock is held before acquiring bus_lock.
+ */
+static void sdw_acquire_bus_lock(struct sdw_stream_runtime *stream)
+{
+ struct sdw_master_runtime *m_rt = NULL;
+ struct sdw_bus *bus = NULL;
+
+ /* Iterate for all Master(s) in Master list */
+ list_for_each_entry(m_rt, &stream->master_list, stream_node) {
+ bus = m_rt->bus;
+
+ mutex_lock(&bus->bus_lock);
+ }
+}
+
+/**
+ * sdw_release_bus_lock: Release bus lock for all Master runtime(s)
+ *
+ * @stream: SoundWire stream
+ *
+ * Release the previously held bus_lock after reconfiguring the bus.
+ * NOTE: This function is called from SoundWire stream ops and is
+ * expected that a global lock is held before releasing bus_lock.
+ */
+static void sdw_release_bus_lock(struct sdw_stream_runtime *stream)
+{
+ struct sdw_master_runtime *m_rt = NULL;
+ struct sdw_bus *bus = NULL;
+
+ /* Iterate for all Master(s) in Master list */
+ list_for_each_entry_reverse(m_rt, &stream->master_list, stream_node) {
+ bus = m_rt->bus;
+ mutex_unlock(&bus->bus_lock);
+ }
+}
+
static int _sdw_prepare_stream(struct sdw_stream_runtime *stream)
{
- struct sdw_master_runtime *m_rt = stream->m_rt;
- struct sdw_bus *bus = m_rt->bus;
+ struct sdw_master_runtime *m_rt = NULL;
+ struct sdw_bus *bus = NULL;
struct sdw_master_prop *prop = NULL;
struct sdw_bus_params params;
int ret;
- prop = &bus->prop;
- memcpy(&params, &bus->params, sizeof(params));
+ /* Prepare Master(s) and Slave(s) port(s) associated with stream */
+ list_for_each_entry(m_rt, &stream->master_list, stream_node) {
+ bus = m_rt->bus;
+ prop = &bus->prop;
+ memcpy(&params, &bus->params, sizeof(params));
- /* TODO: Support Asynchronous mode */
- if ((prop->max_freq % stream->params.rate) != 0) {
- dev_err(bus->dev, "Async mode not supported");
- return -EINVAL;
- }
+ /* TODO: Support Asynchronous mode */
+ if ((prop->max_freq % stream->params.rate) != 0) {
+ dev_err(bus->dev, "Async mode not supported");
+ return -EINVAL;
+ }
- /* Increment cumulative bus bandwidth */
- /* TODO: Update this during Device-Device support */
- bus->params.bandwidth += m_rt->stream->params.rate *
- m_rt->ch_count * m_rt->stream->params.bps;
+ /* Increment cumulative bus bandwidth */
+ /* TODO: Update this during Device-Device support */
+ bus->params.bandwidth += m_rt->stream->params.rate *
+ m_rt->ch_count * m_rt->stream->params.bps;
+
+ /* Program params */
+ ret = sdw_program_params(bus);
+ if (ret < 0) {
+ dev_err(bus->dev, "Program params failed: %d", ret);
+ goto restore_params;
+ }
- /* Program params */
- ret = sdw_program_params(bus);
- if (ret < 0) {
- dev_err(bus->dev, "Program params failed: %d", ret);
- goto restore_params;
}
ret = do_bank_switch(stream);
@@ -1280,12 +1494,16 @@ static int _sdw_prepare_stream(struct sdw_stream_runtime *stream)
goto restore_params;
}
- /* Prepare port(s) on the new clock configuration */
- ret = sdw_prep_deprep_ports(m_rt, true);
- if (ret < 0) {
- dev_err(bus->dev, "Prepare port(s) failed ret = %d",
- ret);
- return ret;
+ list_for_each_entry(m_rt, &stream->master_list, stream_node) {
+ bus = m_rt->bus;
+
+ /* Prepare port(s) on the new clock configuration */
+ ret = sdw_prep_deprep_ports(m_rt, true);
+ if (ret < 0) {
+ dev_err(bus->dev, "Prepare port(s) failed ret = %d",
+ ret);
+ return ret;
+ }
}
stream->state = SDW_STREAM_PREPARED;
@@ -1313,35 +1531,40 @@ int sdw_prepare_stream(struct sdw_stream_runtime *stream)
return -EINVAL;
}
- mutex_lock(&stream->m_rt->bus->bus_lock);
+ sdw_acquire_bus_lock(stream);
ret = _sdw_prepare_stream(stream);
if (ret < 0)
pr_err("Prepare for stream:%s failed: %d", stream->name, ret);
- mutex_unlock(&stream->m_rt->bus->bus_lock);
+ sdw_release_bus_lock(stream);
return ret;
}
EXPORT_SYMBOL(sdw_prepare_stream);
static int _sdw_enable_stream(struct sdw_stream_runtime *stream)
{
- struct sdw_master_runtime *m_rt = stream->m_rt;
- struct sdw_bus *bus = m_rt->bus;
+ struct sdw_master_runtime *m_rt = NULL;
+ struct sdw_bus *bus = NULL;
int ret;
- /* Program params */
- ret = sdw_program_params(bus);
- if (ret < 0) {
- dev_err(bus->dev, "Program params failed: %d", ret);
- return ret;
- }
+ /* Enable Master(s) and Slave(s) port(s) associated with stream */
+ list_for_each_entry(m_rt, &stream->master_list, stream_node) {
+ bus = m_rt->bus;
- /* Enable port(s) */
- ret = sdw_enable_disable_ports(m_rt, true);
- if (ret < 0) {
- dev_err(bus->dev, "Enable port(s) failed ret: %d", ret);
- return ret;
+ /* Program params */
+ ret = sdw_program_params(bus);
+ if (ret < 0) {
+ dev_err(bus->dev, "Program params failed: %d", ret);
+ return ret;
+ }
+
+ /* Enable port(s) */
+ ret = sdw_enable_disable_ports(m_rt, true);
+ if (ret < 0) {
+ dev_err(bus->dev, "Enable port(s) failed ret: %d", ret);
+ return ret;
+ }
}
ret = do_bank_switch(stream);
@@ -1370,37 +1593,42 @@ int sdw_enable_stream(struct sdw_stream_runtime *stream)
return -EINVAL;
}
- mutex_lock(&stream->m_rt->bus->bus_lock);
+ sdw_acquire_bus_lock(stream);
ret = _sdw_enable_stream(stream);
if (ret < 0)
pr_err("Enable for stream:%s failed: %d", stream->name, ret);
- mutex_unlock(&stream->m_rt->bus->bus_lock);
+ sdw_release_bus_lock(stream);
return ret;
}
EXPORT_SYMBOL(sdw_enable_stream);
static int _sdw_disable_stream(struct sdw_stream_runtime *stream)
{
- struct sdw_master_runtime *m_rt = stream->m_rt;
- struct sdw_bus *bus = m_rt->bus;
+ struct sdw_master_runtime *m_rt = NULL;
+ struct sdw_bus *bus = NULL;
int ret;
- /* Disable port(s) */
- ret = sdw_enable_disable_ports(m_rt, false);
- if (ret < 0) {
- dev_err(bus->dev, "Disable port(s) failed: %d", ret);
- return ret;
+ list_for_each_entry(m_rt, &stream->master_list, stream_node) {
+ bus = m_rt->bus;
+ /* Disable port(s) */
+ ret = sdw_enable_disable_ports(m_rt, false);
+ if (ret < 0) {
+ dev_err(bus->dev, "Disable port(s) failed: %d", ret);
+ return ret;
+ }
}
-
stream->state = SDW_STREAM_DISABLED;
- /* Program params */
- ret = sdw_program_params(bus);
- if (ret < 0) {
- dev_err(bus->dev, "Program params failed: %d", ret);
- return ret;
+ list_for_each_entry(m_rt, &stream->master_list, stream_node) {
+ bus = m_rt->bus;
+ /* Program params */
+ ret = sdw_program_params(bus);
+ if (ret < 0) {
+ dev_err(bus->dev, "Program params failed: %d", ret);
+ return ret;
+ }
}
return do_bank_switch(stream);
@@ -1422,43 +1650,46 @@ int sdw_disable_stream(struct sdw_stream_runtime *stream)
return -EINVAL;
}
- mutex_lock(&stream->m_rt->bus->bus_lock);
+ sdw_acquire_bus_lock(stream);
ret = _sdw_disable_stream(stream);
if (ret < 0)
pr_err("Disable for stream:%s failed: %d", stream->name, ret);
- mutex_unlock(&stream->m_rt->bus->bus_lock);
+ sdw_release_bus_lock(stream);
return ret;
}
EXPORT_SYMBOL(sdw_disable_stream);
static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream)
{
- struct sdw_master_runtime *m_rt = stream->m_rt;
- struct sdw_bus *bus = m_rt->bus;
+ struct sdw_master_runtime *m_rt = NULL;
+ struct sdw_bus *bus = NULL;
int ret = 0;
- /* De-prepare port(s) */
- ret = sdw_prep_deprep_ports(m_rt, false);
- if (ret < 0) {
- dev_err(bus->dev, "De-prepare port(s) failed: %d", ret);
- return ret;
- }
+ list_for_each_entry(m_rt, &stream->master_list, stream_node) {
+ bus = m_rt->bus;
+ /* De-prepare port(s) */
+ ret = sdw_prep_deprep_ports(m_rt, false);
+ if (ret < 0) {
+ dev_err(bus->dev, "De-prepare port(s) failed: %d", ret);
+ return ret;
+ }
- stream->state = SDW_STREAM_DEPREPARED;
+ /* TODO: Update this during Device-Device support */
+ bus->params.bandwidth -= m_rt->stream->params.rate *
+ m_rt->ch_count * m_rt->stream->params.bps;
- /* TODO: Update this during Device-Device support */
- bus->params.bandwidth -= m_rt->stream->params.rate *
- m_rt->ch_count * m_rt->stream->params.bps;
+ /* Program params */
+ ret = sdw_program_params(bus);
+ if (ret < 0) {
+ dev_err(bus->dev, "Program params failed: %d", ret);
+ return ret;
+ }
- /* Program params */
- ret = sdw_program_params(bus);
- if (ret < 0) {
- dev_err(bus->dev, "Program params failed: %d", ret);
- return ret;
}
+ stream->state = SDW_STREAM_DEPREPARED;
return do_bank_switch(stream);
}
@@ -1478,13 +1709,12 @@ int sdw_deprepare_stream(struct sdw_stream_runtime *stream)
return -EINVAL;
}
- mutex_lock(&stream->m_rt->bus->bus_lock);
-
+ sdw_acquire_bus_lock(stream);
ret = _sdw_deprepare_stream(stream);
if (ret < 0)
pr_err("De-prepare for stream:%d failed: %d", ret, ret);
- mutex_unlock(&stream->m_rt->bus->bus_lock);
+ sdw_release_bus_lock(stream);
return ret;
}
EXPORT_SYMBOL(sdw_deprepare_stream);
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 671d078349cc..7d3a5c94727e 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -83,6 +83,14 @@ config SPI_ATMEL
This selects a driver for the Atmel SPI Controller, present on
many AT91 ARM chips.
+config SPI_AT91_USART
+ tristate "Atmel USART Controller SPI driver"
+ depends on (ARCH_AT91 || COMPILE_TEST)
+ depends on MFD_AT91_USART
+ help
+ This selects a driver for the AT91 USART Controller as SPI Master,
+ present on AT91 and SAMA5 SoC series.
+
config SPI_AU1550
tristate "Au1550/Au1200/Au1300 SPI Controller"
depends on MIPS_ALCHEMY
@@ -129,7 +137,7 @@ config SPI_BCM63XX
config SPI_BCM63XX_HSSPI
tristate "Broadcom BCM63XX HS SPI controller driver"
- depends on BCM63XX || COMPILE_TEST
+ depends on BCM63XX || ARCH_BCM_63XX || COMPILE_TEST
help
This enables support for the High Speed SPI controller present on
newer Broadcom BCM63XX SoCs.
@@ -520,6 +528,12 @@ config SPI_RSPI
help
SPI driver for Renesas RSPI and QSPI blocks.
+config SPI_QCOM_QSPI
+ tristate "QTI QSPI controller"
+ depends on ARCH_QCOM
+ help
+ QSPI(Quad SPI) driver for Qualcomm QSPI controller.
+
config SPI_QUP
tristate "Qualcomm SPI controller with QUP interface"
depends on ARCH_QCOM || (ARM && COMPILE_TEST)
@@ -533,6 +547,18 @@ config SPI_QUP
This driver can also be built as a module. If so, the module
will be called spi_qup.
+config SPI_QCOM_GENI
+ tristate "Qualcomm GENI based SPI controller"
+ depends on QCOM_GENI_SE
+ help
+ This driver supports GENI serial engine based SPI controller in
+ master mode on the Qualcomm Technologies Inc.'s SoCs. If you say
+ yes to this option, support will be included for the built-in SPI
+ interface on the Qualcomm Technologies Inc.'s SoCs.
+
+ This driver can also be built as a module. If so, the module
+ will be called spi-geni-qcom.
+
config SPI_S3C24XX
tristate "Samsung S3C24XX series SPI"
depends on ARCH_S3C24XX
@@ -596,6 +622,22 @@ config SPI_SIRF
help
SPI driver for CSR SiRFprimaII SoCs
+config SPI_SLAVE_MT27XX
+ tristate "MediaTek SPI slave device"
+ depends on ARCH_MEDIATEK || COMPILE_TEST
+ depends on SPI_SLAVE
+ help
+ This selects the MediaTek(R) SPI slave device driver.
+ If you want to use MediaTek(R) SPI slave interface,
+ say Y or M here.If you are not sure, say N.
+ SPI slave drivers for Mediatek MT27XX series ARM SoCs.
+
+config SPI_SPRD
+ tristate "Spreadtrum SPI controller"
+ depends on ARCH_SPRD || COMPILE_TEST
+ help
+ SPI driver for Spreadtrum SoCs.
+
config SPI_SPRD_ADI
tristate "Spreadtrum ADI controller"
depends on ARCH_SPRD || COMPILE_TEST
@@ -613,6 +655,15 @@ config SPI_STM32
is not available, the driver automatically falls back to
PIO mode.
+config SPI_STM32_QSPI
+ tristate "STMicroelectronics STM32 QUAD SPI controller"
+ depends on ARCH_STM32 || COMPILE_TEST
+ depends on OF
+ help
+ This enables support for the Quad SPI controller in master mode.
+ This driver does not support generic SPI. The implementation only
+ supports spi-mem interface.
+
config SPI_ST_SSC4
tristate "STMicroelectronics SPI SSC-based driver"
depends on ARCH_STI || COMPILE_TEST
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index a90d55970036..3575205c5c27 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_SPI_LOOPBACK_TEST) += spi-loopback-test.o
obj-$(CONFIG_SPI_ALTERA) += spi-altera.o
obj-$(CONFIG_SPI_ARMADA_3700) += spi-armada-3700.o
obj-$(CONFIG_SPI_ATMEL) += spi-atmel.o
+obj-$(CONFIG_SPI_AT91_USART) += spi-at91-usart.o
obj-$(CONFIG_SPI_ATH79) += spi-ath79.o
obj-$(CONFIG_SPI_AU1550) += spi-au1550.o
obj-$(CONFIG_SPI_AXI_SPI_ENGINE) += spi-axi-spi-engine.o
@@ -74,6 +75,8 @@ obj-$(CONFIG_SPI_PPC4xx) += spi-ppc4xx.o
spi-pxa2xx-platform-objs := spi-pxa2xx.o spi-pxa2xx-dma.o
obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx-platform.o
obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o
+obj-$(CONFIG_SPI_QCOM_GENI) += spi-geni-qcom.o
+obj-$(CONFIG_SPI_QCOM_QSPI) += spi-qcom-qspi.o
obj-$(CONFIG_SPI_QUP) += spi-qup.o
obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o
obj-$(CONFIG_SPI_RB4XX) += spi-rb4xx.o
@@ -88,8 +91,11 @@ obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o
obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o
obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o
obj-$(CONFIG_SPI_SIRF) += spi-sirf.o
+obj-$(CONFIG_SPI_SLAVE_MT27XX) += spi-slave-mt27xx.o
+obj-$(CONFIG_SPI_SPRD) += spi-sprd.o
obj-$(CONFIG_SPI_SPRD_ADI) += spi-sprd-adi.o
obj-$(CONFIG_SPI_STM32) += spi-stm32.o
+obj-$(CONFIG_SPI_STM32_QSPI) += spi-stm32-qspi.o
obj-$(CONFIG_SPI_ST_SSC4) += spi-st-ssc4.o
obj-$(CONFIG_SPI_SUN4I) += spi-sun4i.o
obj-$(CONFIG_SPI_SUN6I) += spi-sun6i.o
diff --git a/drivers/spi/spi-at91-usart.c b/drivers/spi/spi-at91-usart.c
new file mode 100644
index 000000000000..a924657642fa
--- /dev/null
+++ b/drivers/spi/spi-at91-usart.c
@@ -0,0 +1,432 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Driver for AT91 USART Controllers as SPI
+//
+// Copyright (C) 2018 Microchip Technology Inc.
+//
+// Author: Radu Pirea <radu.pirea@microchip.com>
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+
+#include <linux/spi/spi.h>
+
+#define US_CR 0x00
+#define US_MR 0x04
+#define US_IER 0x08
+#define US_IDR 0x0C
+#define US_CSR 0x14
+#define US_RHR 0x18
+#define US_THR 0x1C
+#define US_BRGR 0x20
+#define US_VERSION 0xFC
+
+#define US_CR_RSTRX BIT(2)
+#define US_CR_RSTTX BIT(3)
+#define US_CR_RXEN BIT(4)
+#define US_CR_RXDIS BIT(5)
+#define US_CR_TXEN BIT(6)
+#define US_CR_TXDIS BIT(7)
+
+#define US_MR_SPI_MASTER 0x0E
+#define US_MR_CHRL GENMASK(7, 6)
+#define US_MR_CPHA BIT(8)
+#define US_MR_CPOL BIT(16)
+#define US_MR_CLKO BIT(18)
+#define US_MR_WRDBT BIT(20)
+#define US_MR_LOOP BIT(15)
+
+#define US_IR_RXRDY BIT(0)
+#define US_IR_TXRDY BIT(1)
+#define US_IR_OVRE BIT(5)
+
+#define US_BRGR_SIZE BIT(16)
+
+#define US_MIN_CLK_DIV 0x06
+#define US_MAX_CLK_DIV BIT(16)
+
+#define US_RESET (US_CR_RSTRX | US_CR_RSTTX)
+#define US_DISABLE (US_CR_RXDIS | US_CR_TXDIS)
+#define US_ENABLE (US_CR_RXEN | US_CR_TXEN)
+#define US_OVRE_RXRDY_IRQS (US_IR_OVRE | US_IR_RXRDY)
+
+#define US_INIT \
+ (US_MR_SPI_MASTER | US_MR_CHRL | US_MR_CLKO | US_MR_WRDBT)
+
+/* Register access macros */
+#define at91_usart_spi_readl(port, reg) \
+ readl_relaxed((port)->regs + US_##reg)
+#define at91_usart_spi_writel(port, reg, value) \
+ writel_relaxed((value), (port)->regs + US_##reg)
+
+#define at91_usart_spi_readb(port, reg) \
+ readb_relaxed((port)->regs + US_##reg)
+#define at91_usart_spi_writeb(port, reg, value) \
+ writeb_relaxed((value), (port)->regs + US_##reg)
+
+struct at91_usart_spi {
+ struct spi_transfer *current_transfer;
+ void __iomem *regs;
+ struct device *dev;
+ struct clk *clk;
+
+ /*used in interrupt to protect data reading*/
+ spinlock_t lock;
+
+ int irq;
+ unsigned int current_tx_remaining_bytes;
+ unsigned int current_rx_remaining_bytes;
+
+ u32 spi_clk;
+ u32 status;
+
+ bool xfer_failed;
+};
+
+static inline u32 at91_usart_spi_tx_ready(struct at91_usart_spi *aus)
+{
+ return aus->status & US_IR_TXRDY;
+}
+
+static inline u32 at91_usart_spi_rx_ready(struct at91_usart_spi *aus)
+{
+ return aus->status & US_IR_RXRDY;
+}
+
+static inline u32 at91_usart_spi_check_overrun(struct at91_usart_spi *aus)
+{
+ return aus->status & US_IR_OVRE;
+}
+
+static inline u32 at91_usart_spi_read_status(struct at91_usart_spi *aus)
+{
+ aus->status = at91_usart_spi_readl(aus, CSR);
+ return aus->status;
+}
+
+static inline void at91_usart_spi_tx(struct at91_usart_spi *aus)
+{
+ unsigned int len = aus->current_transfer->len;
+ unsigned int remaining = aus->current_tx_remaining_bytes;
+ const u8 *tx_buf = aus->current_transfer->tx_buf;
+
+ if (!remaining)
+ return;
+
+ if (at91_usart_spi_tx_ready(aus)) {
+ at91_usart_spi_writeb(aus, THR, tx_buf[len - remaining]);
+ aus->current_tx_remaining_bytes--;
+ }
+}
+
+static inline void at91_usart_spi_rx(struct at91_usart_spi *aus)
+{
+ int len = aus->current_transfer->len;
+ int remaining = aus->current_rx_remaining_bytes;
+ u8 *rx_buf = aus->current_transfer->rx_buf;
+
+ if (!remaining)
+ return;
+
+ rx_buf[len - remaining] = at91_usart_spi_readb(aus, RHR);
+ aus->current_rx_remaining_bytes--;
+}
+
+static inline void
+at91_usart_spi_set_xfer_speed(struct at91_usart_spi *aus,
+ struct spi_transfer *xfer)
+{
+ at91_usart_spi_writel(aus, BRGR,
+ DIV_ROUND_UP(aus->spi_clk, xfer->speed_hz));
+}
+
+static irqreturn_t at91_usart_spi_interrupt(int irq, void *dev_id)
+{
+ struct spi_controller *controller = dev_id;
+ struct at91_usart_spi *aus = spi_master_get_devdata(controller);
+
+ spin_lock(&aus->lock);
+ at91_usart_spi_read_status(aus);
+
+ if (at91_usart_spi_check_overrun(aus)) {
+ aus->xfer_failed = true;
+ at91_usart_spi_writel(aus, IDR, US_IR_OVRE | US_IR_RXRDY);
+ spin_unlock(&aus->lock);
+ return IRQ_HANDLED;
+ }
+
+ if (at91_usart_spi_rx_ready(aus)) {
+ at91_usart_spi_rx(aus);
+ spin_unlock(&aus->lock);
+ return IRQ_HANDLED;
+ }
+
+ spin_unlock(&aus->lock);
+
+ return IRQ_NONE;
+}
+
+static int at91_usart_spi_setup(struct spi_device *spi)
+{
+ struct at91_usart_spi *aus = spi_master_get_devdata(spi->controller);
+ u32 *ausd = spi->controller_state;
+ unsigned int mr = at91_usart_spi_readl(aus, MR);
+ u8 bits = spi->bits_per_word;
+
+ if (bits != 8) {
+ dev_dbg(&spi->dev, "Only 8 bits per word are supported\n");
+ return -EINVAL;
+ }
+
+ if (spi->mode & SPI_CPOL)
+ mr |= US_MR_CPOL;
+ else
+ mr &= ~US_MR_CPOL;
+
+ if (spi->mode & SPI_CPHA)
+ mr |= US_MR_CPHA;
+ else
+ mr &= ~US_MR_CPHA;
+
+ if (spi->mode & SPI_LOOP)
+ mr |= US_MR_LOOP;
+ else
+ mr &= ~US_MR_LOOP;
+
+ if (!ausd) {
+ ausd = kzalloc(sizeof(*ausd), GFP_KERNEL);
+ if (!ausd)
+ return -ENOMEM;
+
+ spi->controller_state = ausd;
+ }
+
+ *ausd = mr;
+
+ dev_dbg(&spi->dev,
+ "setup: bpw %u mode 0x%x -> mr %d %08x\n",
+ bits, spi->mode, spi->chip_select, mr);
+
+ return 0;
+}
+
+static int at91_usart_spi_transfer_one(struct spi_controller *ctlr,
+ struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct at91_usart_spi *aus = spi_master_get_devdata(ctlr);
+
+ at91_usart_spi_set_xfer_speed(aus, xfer);
+ aus->xfer_failed = false;
+ aus->current_transfer = xfer;
+ aus->current_tx_remaining_bytes = xfer->len;
+ aus->current_rx_remaining_bytes = xfer->len;
+
+ while ((aus->current_tx_remaining_bytes ||
+ aus->current_rx_remaining_bytes) && !aus->xfer_failed) {
+ at91_usart_spi_read_status(aus);
+ at91_usart_spi_tx(aus);
+ cpu_relax();
+ }
+
+ if (aus->xfer_failed) {
+ dev_err(aus->dev, "Overrun!\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int at91_usart_spi_prepare_message(struct spi_controller *ctlr,
+ struct spi_message *message)
+{
+ struct at91_usart_spi *aus = spi_master_get_devdata(ctlr);
+ struct spi_device *spi = message->spi;
+ u32 *ausd = spi->controller_state;
+
+ at91_usart_spi_writel(aus, CR, US_ENABLE);
+ at91_usart_spi_writel(aus, IER, US_OVRE_RXRDY_IRQS);
+ at91_usart_spi_writel(aus, MR, *ausd);
+
+ return 0;
+}
+
+static int at91_usart_spi_unprepare_message(struct spi_controller *ctlr,
+ struct spi_message *message)
+{
+ struct at91_usart_spi *aus = spi_master_get_devdata(ctlr);
+
+ at91_usart_spi_writel(aus, CR, US_RESET | US_DISABLE);
+ at91_usart_spi_writel(aus, IDR, US_OVRE_RXRDY_IRQS);
+
+ return 0;
+}
+
+static void at91_usart_spi_cleanup(struct spi_device *spi)
+{
+ struct at91_usart_spi_device *ausd = spi->controller_state;
+
+ spi->controller_state = NULL;
+ kfree(ausd);
+}
+
+static void at91_usart_spi_init(struct at91_usart_spi *aus)
+{
+ at91_usart_spi_writel(aus, MR, US_INIT);
+ at91_usart_spi_writel(aus, CR, US_RESET | US_DISABLE);
+}
+
+static int at91_usart_gpio_setup(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.parent->of_node;
+ int i;
+ int ret;
+ int nb;
+
+ if (!np)
+ return -EINVAL;
+
+ nb = of_gpio_named_count(np, "cs-gpios");
+ for (i = 0; i < nb; i++) {
+ int cs_gpio = of_get_named_gpio(np, "cs-gpios", i);
+
+ if (cs_gpio < 0)
+ return cs_gpio;
+
+ if (gpio_is_valid(cs_gpio)) {
+ ret = devm_gpio_request_one(&pdev->dev, cs_gpio,
+ GPIOF_DIR_OUT,
+ dev_name(&pdev->dev));
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int at91_usart_spi_probe(struct platform_device *pdev)
+{
+ struct resource *regs;
+ struct spi_controller *controller;
+ struct at91_usart_spi *aus;
+ struct clk *clk;
+ int irq;
+ int ret;
+
+ regs = platform_get_resource(to_platform_device(pdev->dev.parent),
+ IORESOURCE_MEM, 0);
+ if (!regs)
+ return -EINVAL;
+
+ irq = platform_get_irq(to_platform_device(pdev->dev.parent), 0);
+ if (irq < 0)
+ return irq;
+
+ clk = devm_clk_get(pdev->dev.parent, "usart");
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ ret = -ENOMEM;
+ controller = spi_alloc_master(&pdev->dev, sizeof(*aus));
+ if (!controller)
+ goto at91_usart_spi_probe_fail;
+
+ ret = at91_usart_gpio_setup(pdev);
+ if (ret)
+ goto at91_usart_spi_probe_fail;
+
+ controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP | SPI_CS_HIGH;
+ controller->dev.of_node = pdev->dev.parent->of_node;
+ controller->bits_per_word_mask = SPI_BPW_MASK(8);
+ controller->setup = at91_usart_spi_setup;
+ controller->flags = SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX;
+ controller->transfer_one = at91_usart_spi_transfer_one;
+ controller->prepare_message = at91_usart_spi_prepare_message;
+ controller->unprepare_message = at91_usart_spi_unprepare_message;
+ controller->cleanup = at91_usart_spi_cleanup;
+ controller->max_speed_hz = DIV_ROUND_UP(clk_get_rate(clk),
+ US_MIN_CLK_DIV);
+ controller->min_speed_hz = DIV_ROUND_UP(clk_get_rate(clk),
+ US_MAX_CLK_DIV);
+ platform_set_drvdata(pdev, controller);
+
+ aus = spi_master_get_devdata(controller);
+
+ aus->dev = &pdev->dev;
+ aus->regs = devm_ioremap_resource(&pdev->dev, regs);
+ if (IS_ERR(aus->regs)) {
+ ret = PTR_ERR(aus->regs);
+ goto at91_usart_spi_probe_fail;
+ }
+
+ aus->irq = irq;
+ aus->clk = clk;
+
+ ret = devm_request_irq(&pdev->dev, irq, at91_usart_spi_interrupt, 0,
+ dev_name(&pdev->dev), controller);
+ if (ret)
+ goto at91_usart_spi_probe_fail;
+
+ ret = clk_prepare_enable(clk);
+ if (ret)
+ goto at91_usart_spi_probe_fail;
+
+ aus->spi_clk = clk_get_rate(clk);
+ at91_usart_spi_init(aus);
+
+ spin_lock_init(&aus->lock);
+ ret = devm_spi_register_master(&pdev->dev, controller);
+ if (ret)
+ goto at91_usart_fail_register_master;
+
+ dev_info(&pdev->dev,
+ "AT91 USART SPI Controller version 0x%x at %pa (irq %d)\n",
+ at91_usart_spi_readl(aus, VERSION),
+ &regs->start, irq);
+
+ return 0;
+
+at91_usart_fail_register_master:
+ clk_disable_unprepare(clk);
+at91_usart_spi_probe_fail:
+ spi_master_put(controller);
+ return ret;
+}
+
+static int at91_usart_spi_remove(struct platform_device *pdev)
+{
+ struct spi_controller *ctlr = platform_get_drvdata(pdev);
+ struct at91_usart_spi *aus = spi_master_get_devdata(ctlr);
+
+ clk_disable_unprepare(aus->clk);
+
+ return 0;
+}
+
+static const struct of_device_id at91_usart_spi_dt_ids[] = {
+ { .compatible = "microchip,at91sam9g45-usart-spi"},
+ { /* sentinel */}
+};
+
+MODULE_DEVICE_TABLE(of, at91_usart_spi_dt_ids);
+
+static struct platform_driver at91_usart_spi_driver = {
+ .driver = {
+ .name = "at91_usart_spi",
+ },
+ .probe = at91_usart_spi_probe,
+ .remove = at91_usart_spi_remove,
+};
+
+module_platform_driver(at91_usart_spi_driver);
+
+MODULE_DESCRIPTION("Microchip AT91 USART SPI Controller driver");
+MODULE_AUTHOR("Radu Pirea <radu.pirea@microchip.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:at91_usart_spi");
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index 3f890d162934..74fddcd3282b 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -1767,10 +1767,8 @@ static int atmel_spi_suspend(struct device *dev)
/* Stop the queue running */
ret = spi_master_suspend(master);
- if (ret) {
- dev_warn(dev, "cannot suspend master\n");
+ if (ret)
return ret;
- }
if (!pm_runtime_suspended(dev))
atmel_spi_runtime_suspend(dev);
@@ -1799,11 +1797,7 @@ static int atmel_spi_resume(struct device *dev)
}
/* Start the queue running */
- ret = spi_master_resume(master);
- if (ret)
- dev_err(dev, "problem starting queue (%d)\n", ret);
-
- return ret;
+ return spi_master_resume(master);
}
#endif
diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c
index 8612525fa4e3..584bcb018a62 100644
--- a/drivers/spi/spi-bcm-qspi.c
+++ b/drivers/spi/spi-bcm-qspi.c
@@ -89,7 +89,7 @@
#define BSPI_BPP_MODE_SELECT_MASK BIT(8)
#define BSPI_BPP_ADDR_SELECT_MASK BIT(16)
-#define BSPI_READ_LENGTH 512
+#define BSPI_READ_LENGTH 256
/* MSPI register offsets */
#define MSPI_SPCR0_LSB 0x000
@@ -355,7 +355,7 @@ static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi,
int bpc = 0, bpp = 0;
u8 command = op->cmd.opcode;
int width = op->cmd.buswidth ? op->cmd.buswidth : SPI_NBITS_SINGLE;
- int addrlen = op->addr.nbytes * 8;
+ int addrlen = op->addr.nbytes;
int flex_mode = 1;
dev_dbg(&qspi->pdev->dev, "set flex mode w %x addrlen %x hp %d\n",
diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c
index c23849f7aa7b..9a06ffdb73b8 100644
--- a/drivers/spi/spi-bcm63xx-hsspi.c
+++ b/drivers/spi/spi-bcm63xx-hsspi.c
@@ -101,6 +101,7 @@ struct bcm63xx_hsspi {
struct platform_device *pdev;
struct clk *clk;
+ struct clk *pll_clk;
void __iomem *regs;
u8 __iomem *fifo;
@@ -332,7 +333,7 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
struct resource *res_mem;
void __iomem *regs;
struct device *dev = &pdev->dev;
- struct clk *clk;
+ struct clk *clk, *pll_clk = NULL;
int irq, ret;
u32 reg, rate, num_cs = HSSPI_SPI_MAX_CS;
@@ -358,7 +359,7 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
rate = clk_get_rate(clk);
if (!rate) {
- struct clk *pll_clk = devm_clk_get(dev, "pll");
+ pll_clk = devm_clk_get(dev, "pll");
if (IS_ERR(pll_clk)) {
ret = PTR_ERR(pll_clk);
@@ -373,19 +374,20 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
clk_disable_unprepare(pll_clk);
if (!rate) {
ret = -EINVAL;
- goto out_disable_clk;
+ goto out_disable_pll_clk;
}
}
master = spi_alloc_master(&pdev->dev, sizeof(*bs));
if (!master) {
ret = -ENOMEM;
- goto out_disable_clk;
+ goto out_disable_pll_clk;
}
bs = spi_master_get_devdata(master);
bs->pdev = pdev;
bs->clk = clk;
+ bs->pll_clk = pll_clk;
bs->regs = regs;
bs->speed_hz = rate;
bs->fifo = (u8 __iomem *)(bs->regs + HSSPI_FIFO_REG(0));
@@ -440,6 +442,8 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
out_put_master:
spi_master_put(master);
+out_disable_pll_clk:
+ clk_disable_unprepare(pll_clk);
out_disable_clk:
clk_disable_unprepare(clk);
return ret;
@@ -453,6 +457,7 @@ static int bcm63xx_hsspi_remove(struct platform_device *pdev)
/* reset the hardware and block queue progress */
__raw_writel(0, bs->regs + HSSPI_INT_MASK_REG);
+ clk_disable_unprepare(bs->pll_clk);
clk_disable_unprepare(bs->clk);
return 0;
@@ -465,6 +470,7 @@ static int bcm63xx_hsspi_suspend(struct device *dev)
struct bcm63xx_hsspi *bs = spi_master_get_devdata(master);
spi_master_suspend(master);
+ clk_disable_unprepare(bs->pll_clk);
clk_disable_unprepare(bs->clk);
return 0;
@@ -480,6 +486,12 @@ static int bcm63xx_hsspi_resume(struct device *dev)
if (ret)
return ret;
+ if (bs->pll_clk) {
+ ret = clk_prepare_enable(bs->pll_clk);
+ if (ret)
+ return ret;
+ }
+
spi_master_resume(master);
return 0;
diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c
index a02099c90c5c..56adec83f8fc 100644
--- a/drivers/spi/spi-davinci.c
+++ b/drivers/spi/spi-davinci.c
@@ -208,13 +208,11 @@ static inline void clear_io_bits(void __iomem *addr, u32 bits)
static void davinci_spi_chipselect(struct spi_device *spi, int value)
{
struct davinci_spi *dspi;
- struct davinci_spi_platform_data *pdata;
struct davinci_spi_config *spicfg = spi->controller_data;
u8 chip_sel = spi->chip_select;
u16 spidat1 = CS_DEFAULT;
dspi = spi_master_get_devdata(spi->master);
- pdata = &dspi->pdata;
/* program delay transfers if tx_delay is non zero */
if (spicfg && spicfg->wdelay)
@@ -232,7 +230,8 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value)
!(spi->mode & SPI_CS_HIGH));
} else {
if (value == BITBANG_CS_ACTIVE) {
- spidat1 |= SPIDAT1_CSHOLD_MASK;
+ if (!(spi->mode & SPI_CS_WORD))
+ spidat1 |= SPIDAT1_CSHOLD_MASK;
spidat1 &= ~(0x1 << chip_sel);
}
}
@@ -421,26 +420,17 @@ static int davinci_spi_setup(struct spi_device *spi)
{
int retval = 0;
struct davinci_spi *dspi;
- struct davinci_spi_platform_data *pdata;
struct spi_master *master = spi->master;
struct device_node *np = spi->dev.of_node;
bool internal_cs = true;
dspi = spi_master_get_devdata(spi->master);
- pdata = &dspi->pdata;
if (!(spi->mode & SPI_NO_CS)) {
if (np && (master->cs_gpios != NULL) && (spi->cs_gpio >= 0)) {
retval = gpio_direction_output(
spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
internal_cs = false;
- } else if (pdata->chip_sel &&
- spi->chip_select < pdata->num_chipselect &&
- pdata->chip_sel[spi->chip_select] != SPI_INTERN_CS) {
- spi->cs_gpio = pdata->chip_sel[spi->chip_select];
- retval = gpio_direction_output(
- spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
- internal_cs = false;
}
if (retval) {
@@ -449,8 +439,9 @@ static int davinci_spi_setup(struct spi_device *spi)
return retval;
}
- if (internal_cs)
+ if (internal_cs) {
set_io_bits(dspi->base + SPIPC0, 1 << spi->chip_select);
+ }
}
if (spi->mode & SPI_READY)
@@ -985,7 +976,7 @@ static int davinci_spi_probe(struct platform_device *pdev)
dspi->prescaler_limit = pdata->prescaler_limit;
dspi->version = pdata->version;
- dspi->bitbang.flags = SPI_NO_CS | SPI_LSB_FIRST | SPI_LOOP;
+ dspi->bitbang.flags = SPI_NO_CS | SPI_LSB_FIRST | SPI_LOOP | SPI_CS_WORD;
if (dspi->version == SPI_VERSION_2)
dspi->bitbang.flags |= SPI_READY;
diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c
index e80f60ed6fdf..3ffb6a40fe0c 100644
--- a/drivers/spi/spi-dw-mmio.c
+++ b/drivers/spi/spi-dw-mmio.c
@@ -34,8 +34,9 @@ struct dw_spi_mmio {
};
#define MSCC_CPU_SYSTEM_CTRL_GENERAL_CTRL 0x24
-#define OCELOT_IF_SI_OWNER_MASK GENMASK(5, 4)
#define OCELOT_IF_SI_OWNER_OFFSET 4
+#define JAGUAR2_IF_SI_OWNER_OFFSET 6
+#define MSCC_IF_SI_OWNER_MASK GENMASK(1, 0)
#define MSCC_IF_SI_OWNER_SISL 0
#define MSCC_IF_SI_OWNER_SIBM 1
#define MSCC_IF_SI_OWNER_SIMC 2
@@ -76,7 +77,8 @@ static void dw_spi_mscc_set_cs(struct spi_device *spi, bool enable)
}
static int dw_spi_mscc_init(struct platform_device *pdev,
- struct dw_spi_mmio *dwsmmio)
+ struct dw_spi_mmio *dwsmmio,
+ const char *cpu_syscon, u32 if_si_owner_offset)
{
struct dw_spi_mscc *dwsmscc;
struct resource *res;
@@ -92,7 +94,7 @@ static int dw_spi_mscc_init(struct platform_device *pdev,
return PTR_ERR(dwsmscc->spi_mst);
}
- dwsmscc->syscon = syscon_regmap_lookup_by_compatible("mscc,ocelot-cpu-syscon");
+ dwsmscc->syscon = syscon_regmap_lookup_by_compatible(cpu_syscon);
if (IS_ERR(dwsmscc->syscon))
return PTR_ERR(dwsmscc->syscon);
@@ -101,8 +103,8 @@ static int dw_spi_mscc_init(struct platform_device *pdev,
/* Select the owner of the SI interface */
regmap_update_bits(dwsmscc->syscon, MSCC_CPU_SYSTEM_CTRL_GENERAL_CTRL,
- OCELOT_IF_SI_OWNER_MASK,
- MSCC_IF_SI_OWNER_SIMC << OCELOT_IF_SI_OWNER_OFFSET);
+ MSCC_IF_SI_OWNER_MASK << if_si_owner_offset,
+ MSCC_IF_SI_OWNER_SIMC << if_si_owner_offset);
dwsmmio->dws.set_cs = dw_spi_mscc_set_cs;
dwsmmio->priv = dwsmscc;
@@ -110,6 +112,28 @@ static int dw_spi_mscc_init(struct platform_device *pdev,
return 0;
}
+static int dw_spi_mscc_ocelot_init(struct platform_device *pdev,
+ struct dw_spi_mmio *dwsmmio)
+{
+ return dw_spi_mscc_init(pdev, dwsmmio, "mscc,ocelot-cpu-syscon",
+ OCELOT_IF_SI_OWNER_OFFSET);
+}
+
+static int dw_spi_mscc_jaguar2_init(struct platform_device *pdev,
+ struct dw_spi_mmio *dwsmmio)
+{
+ return dw_spi_mscc_init(pdev, dwsmmio, "mscc,jaguar2-cpu-syscon",
+ JAGUAR2_IF_SI_OWNER_OFFSET);
+}
+
+static int dw_spi_alpine_init(struct platform_device *pdev,
+ struct dw_spi_mmio *dwsmmio)
+{
+ dwsmmio->dws.cs_override = 1;
+
+ return 0;
+}
+
static int dw_spi_mmio_probe(struct platform_device *pdev)
{
int (*init_func)(struct platform_device *pdev,
@@ -212,7 +236,9 @@ static int dw_spi_mmio_remove(struct platform_device *pdev)
static const struct of_device_id dw_spi_mmio_of_match[] = {
{ .compatible = "snps,dw-apb-ssi", },
- { .compatible = "mscc,ocelot-spi", .data = dw_spi_mscc_init},
+ { .compatible = "mscc,ocelot-spi", .data = dw_spi_mscc_ocelot_init},
+ { .compatible = "mscc,jaguar2-spi", .data = dw_spi_mscc_jaguar2_init},
+ { .compatible = "amazon,alpine-dw-apb-ssi", .data = dw_spi_alpine_init},
{ /* end of table */}
};
MODULE_DEVICE_TABLE(of, dw_spi_mmio_of_match);
diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c
index ac2eb89ef7a5..b705f2bdb8b9 100644
--- a/drivers/spi/spi-dw.c
+++ b/drivers/spi/spi-dw.c
@@ -144,6 +144,8 @@ void dw_spi_set_cs(struct spi_device *spi, bool enable)
if (!enable)
dw_writel(dws, DW_SPI_SER, BIT(spi->chip_select));
+ else if (dws->cs_override)
+ dw_writel(dws, DW_SPI_SER, 0);
}
EXPORT_SYMBOL_GPL(dw_spi_set_cs);
@@ -308,15 +310,10 @@ static int dw_spi_transfer_one(struct spi_controller *master,
dws->current_freq = transfer->speed_hz;
spi_set_clk(dws, chip->clk_div);
}
- if (transfer->bits_per_word == 8) {
- dws->n_bytes = 1;
- dws->dma_width = 1;
- } else if (transfer->bits_per_word == 16) {
- dws->n_bytes = 2;
- dws->dma_width = 2;
- } else {
- return -EINVAL;
- }
+
+ dws->n_bytes = DIV_ROUND_UP(transfer->bits_per_word, BITS_PER_BYTE);
+ dws->dma_width = DIV_ROUND_UP(transfer->bits_per_word, BITS_PER_BYTE);
+
/* Default SPI mode is SCPOL = 0, SCPH = 0 */
cr0 = (transfer->bits_per_word - 1)
| (chip->type << SPI_FRF_OFFSET)
@@ -468,6 +465,10 @@ static void spi_hw_init(struct device *dev, struct dw_spi *dws)
dws->fifo_len = (fifo == 1) ? 0 : fifo;
dev_dbg(dev, "Detected FIFO size: %u bytes\n", dws->fifo_len);
}
+
+ /* enable HW fixup for explicit CS deselect for Amazon's alpine chip */
+ if (dws->cs_override)
+ dw_writel(dws, DW_SPI_CS_OVERRIDE, 0xF);
}
int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
@@ -496,7 +497,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
}
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP;
- master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
+ master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
master->bus_num = dws->bus_num;
master->num_chipselect = dws->num_cs;
master->setup = dw_spi_setup;
@@ -572,13 +573,8 @@ EXPORT_SYMBOL_GPL(dw_spi_suspend_host);
int dw_spi_resume_host(struct dw_spi *dws)
{
- int ret;
-
spi_hw_init(&dws->master->dev, dws);
- ret = spi_controller_resume(dws->master);
- if (ret)
- dev_err(&dws->master->dev, "fail to start queue (%d)\n", ret);
- return ret;
+ return spi_controller_resume(dws->master);
}
EXPORT_SYMBOL_GPL(dw_spi_resume_host);
diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
index 0168b08364d5..c9c15881e982 100644
--- a/drivers/spi/spi-dw.h
+++ b/drivers/spi/spi-dw.h
@@ -32,6 +32,7 @@
#define DW_SPI_IDR 0x58
#define DW_SPI_VERSION 0x5c
#define DW_SPI_DR 0x60
+#define DW_SPI_CS_OVERRIDE 0xf4
/* Bit fields in CTRLR0 */
#define SPI_DFS_OFFSET 0
@@ -109,6 +110,7 @@ struct dw_spi {
u32 fifo_len; /* depth of the FIFO buffer */
u32 max_freq; /* max bus freq supported */
+ int cs_override;
u32 reg_io_width; /* DR I/O width in bytes */
u16 bus_num;
u16 num_cs; /* supported slave numbers */
diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c
index f1526757aaf6..79fc3940245a 100644
--- a/drivers/spi/spi-ep93xx.c
+++ b/drivers/spi/spi-ep93xx.c
@@ -246,6 +246,19 @@ static int ep93xx_spi_read_write(struct spi_master *master)
return -EINPROGRESS;
}
+static enum dma_transfer_direction
+ep93xx_dma_data_to_trans_dir(enum dma_data_direction dir)
+{
+ switch (dir) {
+ case DMA_TO_DEVICE:
+ return DMA_MEM_TO_DEV;
+ case DMA_FROM_DEVICE:
+ return DMA_DEV_TO_MEM;
+ default:
+ return DMA_TRANS_NONE;
+ }
+}
+
/**
* ep93xx_spi_dma_prepare() - prepares a DMA transfer
* @master: SPI master
@@ -257,7 +270,7 @@ static int ep93xx_spi_read_write(struct spi_master *master)
*/
static struct dma_async_tx_descriptor *
ep93xx_spi_dma_prepare(struct spi_master *master,
- enum dma_transfer_direction dir)
+ enum dma_data_direction dir)
{
struct ep93xx_spi *espi = spi_master_get_devdata(master);
struct spi_transfer *xfer = master->cur_msg->state;
@@ -277,9 +290,9 @@ ep93xx_spi_dma_prepare(struct spi_master *master,
buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE;
memset(&conf, 0, sizeof(conf));
- conf.direction = dir;
+ conf.direction = ep93xx_dma_data_to_trans_dir(dir);
- if (dir == DMA_DEV_TO_MEM) {
+ if (dir == DMA_FROM_DEVICE) {
chan = espi->dma_rx;
buf = xfer->rx_buf;
sgt = &espi->rx_sgt;
@@ -343,7 +356,8 @@ ep93xx_spi_dma_prepare(struct spi_master *master,
if (!nents)
return ERR_PTR(-ENOMEM);
- txd = dmaengine_prep_slave_sg(chan, sgt->sgl, nents, dir, DMA_CTRL_ACK);
+ txd = dmaengine_prep_slave_sg(chan, sgt->sgl, nents, conf.direction,
+ DMA_CTRL_ACK);
if (!txd) {
dma_unmap_sg(chan->device->dev, sgt->sgl, sgt->nents, dir);
return ERR_PTR(-ENOMEM);
@@ -360,13 +374,13 @@ ep93xx_spi_dma_prepare(struct spi_master *master,
* unmapped.
*/
static void ep93xx_spi_dma_finish(struct spi_master *master,
- enum dma_transfer_direction dir)
+ enum dma_data_direction dir)
{
struct ep93xx_spi *espi = spi_master_get_devdata(master);
struct dma_chan *chan;
struct sg_table *sgt;
- if (dir == DMA_DEV_TO_MEM) {
+ if (dir == DMA_FROM_DEVICE) {
chan = espi->dma_rx;
sgt = &espi->rx_sgt;
} else {
@@ -381,8 +395,8 @@ static void ep93xx_spi_dma_callback(void *callback_param)
{
struct spi_master *master = callback_param;
- ep93xx_spi_dma_finish(master, DMA_MEM_TO_DEV);
- ep93xx_spi_dma_finish(master, DMA_DEV_TO_MEM);
+ ep93xx_spi_dma_finish(master, DMA_TO_DEVICE);
+ ep93xx_spi_dma_finish(master, DMA_FROM_DEVICE);
spi_finalize_current_transfer(master);
}
@@ -392,15 +406,15 @@ static int ep93xx_spi_dma_transfer(struct spi_master *master)
struct ep93xx_spi *espi = spi_master_get_devdata(master);
struct dma_async_tx_descriptor *rxd, *txd;
- rxd = ep93xx_spi_dma_prepare(master, DMA_DEV_TO_MEM);
+ rxd = ep93xx_spi_dma_prepare(master, DMA_FROM_DEVICE);
if (IS_ERR(rxd)) {
dev_err(&master->dev, "DMA RX failed: %ld\n", PTR_ERR(rxd));
return PTR_ERR(rxd);
}
- txd = ep93xx_spi_dma_prepare(master, DMA_MEM_TO_DEV);
+ txd = ep93xx_spi_dma_prepare(master, DMA_TO_DEVICE);
if (IS_ERR(txd)) {
- ep93xx_spi_dma_finish(master, DMA_DEV_TO_MEM);
+ ep93xx_spi_dma_finish(master, DMA_FROM_DEVICE);
dev_err(&master->dev, "DMA TX failed: %ld\n", PTR_ERR(txd));
return PTR_ERR(txd);
}
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c
index 1e8ff6256079..cf2118dc91f4 100644
--- a/drivers/spi/spi-fsl-espi.c
+++ b/drivers/spi/spi-fsl-espi.c
@@ -798,10 +798,8 @@ static int of_fsl_espi_suspend(struct device *dev)
int ret;
ret = spi_master_suspend(master);
- if (ret) {
- dev_warn(dev, "cannot suspend master\n");
+ if (ret)
return ret;
- }
return pm_runtime_force_suspend(dev);
}
diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c
index e6d5cc6ab108..51670976faa3 100644
--- a/drivers/spi/spi-fsl-lpspi.c
+++ b/drivers/spi/spi-fsl-lpspi.c
@@ -276,7 +276,7 @@ static int fsl_lpspi_config(struct fsl_lpspi_data *fsl_lpspi)
fsl_lpspi_set_watermark(fsl_lpspi);
- temp = CFGR1_PCSCFG | CFGR1_MASTER | CFGR1_NOSTALL;
+ temp = CFGR1_PCSCFG | CFGR1_MASTER;
if (fsl_lpspi->config.mode & SPI_CS_HIGH)
temp |= CFGR1_PCSPOL;
writel(temp, fsl_lpspi->base + IMX7ULP_CFGR1);
diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
new file mode 100644
index 000000000000..6432ecc4e2ca
--- /dev/null
+++ b/drivers/spi/spi-geni-qcom.c
@@ -0,0 +1,703 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2017-2018, The Linux foundation. All rights reserved.
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/log2.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/qcom-geni-se.h>
+#include <linux/spi/spi.h>
+#include <linux/spinlock.h>
+
+/* SPI SE specific registers and respective register fields */
+#define SE_SPI_CPHA 0x224
+#define CPHA BIT(0)
+
+#define SE_SPI_LOOPBACK 0x22c
+#define LOOPBACK_ENABLE 0x1
+#define NORMAL_MODE 0x0
+#define LOOPBACK_MSK GENMASK(1, 0)
+
+#define SE_SPI_CPOL 0x230
+#define CPOL BIT(2)
+
+#define SE_SPI_DEMUX_OUTPUT_INV 0x24c
+#define CS_DEMUX_OUTPUT_INV_MSK GENMASK(3, 0)
+
+#define SE_SPI_DEMUX_SEL 0x250
+#define CS_DEMUX_OUTPUT_SEL GENMASK(3, 0)
+
+#define SE_SPI_TRANS_CFG 0x25c
+#define CS_TOGGLE BIT(0)
+
+#define SE_SPI_WORD_LEN 0x268
+#define WORD_LEN_MSK GENMASK(9, 0)
+#define MIN_WORD_LEN 4
+
+#define SE_SPI_TX_TRANS_LEN 0x26c
+#define SE_SPI_RX_TRANS_LEN 0x270
+#define TRANS_LEN_MSK GENMASK(23, 0)
+
+#define SE_SPI_PRE_POST_CMD_DLY 0x274
+
+#define SE_SPI_DELAY_COUNTERS 0x278
+#define SPI_INTER_WORDS_DELAY_MSK GENMASK(9, 0)
+#define SPI_CS_CLK_DELAY_MSK GENMASK(19, 10)
+#define SPI_CS_CLK_DELAY_SHFT 10
+
+/* M_CMD OP codes for SPI */
+#define SPI_TX_ONLY 1
+#define SPI_RX_ONLY 2
+#define SPI_FULL_DUPLEX 3
+#define SPI_TX_RX 7
+#define SPI_CS_ASSERT 8
+#define SPI_CS_DEASSERT 9
+#define SPI_SCK_ONLY 10
+/* M_CMD params for SPI */
+#define SPI_PRE_CMD_DELAY BIT(0)
+#define TIMESTAMP_BEFORE BIT(1)
+#define FRAGMENTATION BIT(2)
+#define TIMESTAMP_AFTER BIT(3)
+#define POST_CMD_DELAY BIT(4)
+
+/* SPI M_COMMAND OPCODE */
+enum spi_mcmd_code {
+ CMD_NONE,
+ CMD_XFER,
+ CMD_CS,
+ CMD_CANCEL,
+};
+
+
+struct spi_geni_master {
+ struct geni_se se;
+ struct device *dev;
+ u32 tx_fifo_depth;
+ u32 fifo_width_bits;
+ u32 tx_wm;
+ unsigned long cur_speed_hz;
+ unsigned int cur_bits_per_word;
+ unsigned int tx_rem_bytes;
+ unsigned int rx_rem_bytes;
+ const struct spi_transfer *cur_xfer;
+ struct completion xfer_done;
+ unsigned int oversampling;
+ spinlock_t lock;
+ unsigned int cur_mcmd;
+ int irq;
+};
+
+static void handle_fifo_timeout(struct spi_master *spi,
+ struct spi_message *msg);
+
+static int get_spi_clk_cfg(unsigned int speed_hz,
+ struct spi_geni_master *mas,
+ unsigned int *clk_idx,
+ unsigned int *clk_div)
+{
+ unsigned long sclk_freq;
+ unsigned int actual_hz;
+ struct geni_se *se = &mas->se;
+ int ret;
+
+ ret = geni_se_clk_freq_match(&mas->se,
+ speed_hz * mas->oversampling,
+ clk_idx, &sclk_freq, false);
+ if (ret) {
+ dev_err(mas->dev, "Failed(%d) to find src clk for %dHz\n",
+ ret, speed_hz);
+ return ret;
+ }
+
+ *clk_div = DIV_ROUND_UP(sclk_freq, mas->oversampling * speed_hz);
+ actual_hz = sclk_freq / (mas->oversampling * *clk_div);
+
+ dev_dbg(mas->dev, "req %u=>%u sclk %lu, idx %d, div %d\n", speed_hz,
+ actual_hz, sclk_freq, *clk_idx, *clk_div);
+ ret = clk_set_rate(se->clk, sclk_freq);
+ if (ret)
+ dev_err(mas->dev, "clk_set_rate failed %d\n", ret);
+ return ret;
+}
+
+static void spi_geni_set_cs(struct spi_device *slv, bool set_flag)
+{
+ struct spi_geni_master *mas = spi_master_get_devdata(slv->master);
+ struct spi_master *spi = dev_get_drvdata(mas->dev);
+ struct geni_se *se = &mas->se;
+ unsigned long timeout;
+
+ reinit_completion(&mas->xfer_done);
+ pm_runtime_get_sync(mas->dev);
+ if (!(slv->mode & SPI_CS_HIGH))
+ set_flag = !set_flag;
+
+ mas->cur_mcmd = CMD_CS;
+ if (set_flag)
+ geni_se_setup_m_cmd(se, SPI_CS_ASSERT, 0);
+ else
+ geni_se_setup_m_cmd(se, SPI_CS_DEASSERT, 0);
+
+ timeout = wait_for_completion_timeout(&mas->xfer_done, HZ);
+ if (!timeout)
+ handle_fifo_timeout(spi, NULL);
+
+ pm_runtime_put(mas->dev);
+}
+
+static void spi_setup_word_len(struct spi_geni_master *mas, u16 mode,
+ unsigned int bits_per_word)
+{
+ unsigned int pack_words;
+ bool msb_first = (mode & SPI_LSB_FIRST) ? false : true;
+ struct geni_se *se = &mas->se;
+ u32 word_len;
+
+ word_len = readl(se->base + SE_SPI_WORD_LEN);
+
+ /*
+ * If bits_per_word isn't a byte aligned value, set the packing to be
+ * 1 SPI word per FIFO word.
+ */
+ if (!(mas->fifo_width_bits % bits_per_word))
+ pack_words = mas->fifo_width_bits / bits_per_word;
+ else
+ pack_words = 1;
+ word_len &= ~WORD_LEN_MSK;
+ word_len |= ((bits_per_word - MIN_WORD_LEN) & WORD_LEN_MSK);
+ geni_se_config_packing(&mas->se, bits_per_word, pack_words, msb_first,
+ true, true);
+ writel(word_len, se->base + SE_SPI_WORD_LEN);
+}
+
+static int setup_fifo_params(struct spi_device *spi_slv,
+ struct spi_master *spi)
+{
+ struct spi_geni_master *mas = spi_master_get_devdata(spi);
+ struct geni_se *se = &mas->se;
+ u32 loopback_cfg, cpol, cpha, demux_output_inv;
+ u32 demux_sel, clk_sel, m_clk_cfg, idx, div;
+ int ret;
+
+ loopback_cfg = readl(se->base + SE_SPI_LOOPBACK);
+ cpol = readl(se->base + SE_SPI_CPOL);
+ cpha = readl(se->base + SE_SPI_CPHA);
+ demux_output_inv = 0;
+ loopback_cfg &= ~LOOPBACK_MSK;
+ cpol &= ~CPOL;
+ cpha &= ~CPHA;
+
+ if (spi_slv->mode & SPI_LOOP)
+ loopback_cfg |= LOOPBACK_ENABLE;
+
+ if (spi_slv->mode & SPI_CPOL)
+ cpol |= CPOL;
+
+ if (spi_slv->mode & SPI_CPHA)
+ cpha |= CPHA;
+
+ if (spi_slv->mode & SPI_CS_HIGH)
+ demux_output_inv = BIT(spi_slv->chip_select);
+
+ demux_sel = spi_slv->chip_select;
+ mas->cur_speed_hz = spi_slv->max_speed_hz;
+ mas->cur_bits_per_word = spi_slv->bits_per_word;
+
+ ret = get_spi_clk_cfg(mas->cur_speed_hz, mas, &idx, &div);
+ if (ret) {
+ dev_err(mas->dev, "Err setting clks ret(%d) for %ld\n",
+ ret, mas->cur_speed_hz);
+ return ret;
+ }
+
+ clk_sel = idx & CLK_SEL_MSK;
+ m_clk_cfg = (div << CLK_DIV_SHFT) | SER_CLK_EN;
+ spi_setup_word_len(mas, spi_slv->mode, spi_slv->bits_per_word);
+ writel(loopback_cfg, se->base + SE_SPI_LOOPBACK);
+ writel(demux_sel, se->base + SE_SPI_DEMUX_SEL);
+ writel(cpha, se->base + SE_SPI_CPHA);
+ writel(cpol, se->base + SE_SPI_CPOL);
+ writel(demux_output_inv, se->base + SE_SPI_DEMUX_OUTPUT_INV);
+ writel(clk_sel, se->base + SE_GENI_CLK_SEL);
+ writel(m_clk_cfg, se->base + GENI_SER_M_CLK_CFG);
+ return 0;
+}
+
+static int spi_geni_prepare_message(struct spi_master *spi,
+ struct spi_message *spi_msg)
+{
+ int ret;
+ struct spi_geni_master *mas = spi_master_get_devdata(spi);
+ struct geni_se *se = &mas->se;
+
+ geni_se_select_mode(se, GENI_SE_FIFO);
+ reinit_completion(&mas->xfer_done);
+ ret = setup_fifo_params(spi_msg->spi, spi);
+ if (ret)
+ dev_err(mas->dev, "Couldn't select mode %d\n", ret);
+ return ret;
+}
+
+static int spi_geni_init(struct spi_geni_master *mas)
+{
+ struct geni_se *se = &mas->se;
+ unsigned int proto, major, minor, ver;
+
+ pm_runtime_get_sync(mas->dev);
+
+ proto = geni_se_read_proto(se);
+ if (proto != GENI_SE_SPI) {
+ dev_err(mas->dev, "Invalid proto %d\n", proto);
+ pm_runtime_put(mas->dev);
+ return -ENXIO;
+ }
+ mas->tx_fifo_depth = geni_se_get_tx_fifo_depth(se);
+
+ /* Width of Tx and Rx FIFO is same */
+ mas->fifo_width_bits = geni_se_get_tx_fifo_width(se);
+
+ /*
+ * Hardware programming guide suggests to configure
+ * RX FIFO RFR level to fifo_depth-2.
+ */
+ geni_se_init(se, 0x0, mas->tx_fifo_depth - 2);
+ /* Transmit an entire FIFO worth of data per IRQ */
+ mas->tx_wm = 1;
+ ver = geni_se_get_qup_hw_version(se);
+ major = GENI_SE_VERSION_MAJOR(ver);
+ minor = GENI_SE_VERSION_MINOR(ver);
+
+ if (major == 1 && minor == 0)
+ mas->oversampling = 2;
+ else
+ mas->oversampling = 1;
+
+ pm_runtime_put(mas->dev);
+ return 0;
+}
+
+static void setup_fifo_xfer(struct spi_transfer *xfer,
+ struct spi_geni_master *mas,
+ u16 mode, struct spi_master *spi)
+{
+ u32 m_cmd = 0;
+ u32 spi_tx_cfg, len;
+ struct geni_se *se = &mas->se;
+
+ spi_tx_cfg = readl(se->base + SE_SPI_TRANS_CFG);
+ if (xfer->bits_per_word != mas->cur_bits_per_word) {
+ spi_setup_word_len(mas, mode, xfer->bits_per_word);
+ mas->cur_bits_per_word = xfer->bits_per_word;
+ }
+
+ /* Speed and bits per word can be overridden per transfer */
+ if (xfer->speed_hz != mas->cur_speed_hz) {
+ int ret;
+ u32 clk_sel, m_clk_cfg;
+ unsigned int idx, div;
+
+ ret = get_spi_clk_cfg(xfer->speed_hz, mas, &idx, &div);
+ if (ret) {
+ dev_err(mas->dev, "Err setting clks:%d\n", ret);
+ return;
+ }
+ /*
+ * SPI core clock gets configured with the requested frequency
+ * or the frequency closer to the requested frequency.
+ * For that reason requested frequency is stored in the
+ * cur_speed_hz and referred in the consecutive transfer instead
+ * of calling clk_get_rate() API.
+ */
+ mas->cur_speed_hz = xfer->speed_hz;
+ clk_sel = idx & CLK_SEL_MSK;
+ m_clk_cfg = (div << CLK_DIV_SHFT) | SER_CLK_EN;
+ writel(clk_sel, se->base + SE_GENI_CLK_SEL);
+ writel(m_clk_cfg, se->base + GENI_SER_M_CLK_CFG);
+ }
+
+ mas->tx_rem_bytes = 0;
+ mas->rx_rem_bytes = 0;
+ if (xfer->tx_buf && xfer->rx_buf)
+ m_cmd = SPI_FULL_DUPLEX;
+ else if (xfer->tx_buf)
+ m_cmd = SPI_TX_ONLY;
+ else if (xfer->rx_buf)
+ m_cmd = SPI_RX_ONLY;
+
+ spi_tx_cfg &= ~CS_TOGGLE;
+
+ if (!(mas->cur_bits_per_word % MIN_WORD_LEN))
+ len = xfer->len * BITS_PER_BYTE / mas->cur_bits_per_word;
+ else
+ len = xfer->len / (mas->cur_bits_per_word / BITS_PER_BYTE + 1);
+ len &= TRANS_LEN_MSK;
+
+ mas->cur_xfer = xfer;
+ if (m_cmd & SPI_TX_ONLY) {
+ mas->tx_rem_bytes = xfer->len;
+ writel(len, se->base + SE_SPI_TX_TRANS_LEN);
+ }
+
+ if (m_cmd & SPI_RX_ONLY) {
+ writel(len, se->base + SE_SPI_RX_TRANS_LEN);
+ mas->rx_rem_bytes = xfer->len;
+ }
+ writel(spi_tx_cfg, se->base + SE_SPI_TRANS_CFG);
+ mas->cur_mcmd = CMD_XFER;
+ geni_se_setup_m_cmd(se, m_cmd, FRAGMENTATION);
+
+ /*
+ * TX_WATERMARK_REG should be set after SPI configuration and
+ * setting up GENI SE engine, as driver starts data transfer
+ * for the watermark interrupt.
+ */
+ if (m_cmd & SPI_TX_ONLY)
+ writel(mas->tx_wm, se->base + SE_GENI_TX_WATERMARK_REG);
+}
+
+static void handle_fifo_timeout(struct spi_master *spi,
+ struct spi_message *msg)
+{
+ struct spi_geni_master *mas = spi_master_get_devdata(spi);
+ unsigned long time_left, flags;
+ struct geni_se *se = &mas->se;
+
+ spin_lock_irqsave(&mas->lock, flags);
+ reinit_completion(&mas->xfer_done);
+ mas->cur_mcmd = CMD_CANCEL;
+ geni_se_cancel_m_cmd(se);
+ writel(0, se->base + SE_GENI_TX_WATERMARK_REG);
+ spin_unlock_irqrestore(&mas->lock, flags);
+ time_left = wait_for_completion_timeout(&mas->xfer_done, HZ);
+ if (time_left)
+ return;
+
+ spin_lock_irqsave(&mas->lock, flags);
+ reinit_completion(&mas->xfer_done);
+ geni_se_abort_m_cmd(se);
+ spin_unlock_irqrestore(&mas->lock, flags);
+ time_left = wait_for_completion_timeout(&mas->xfer_done, HZ);
+ if (!time_left)
+ dev_err(mas->dev, "Failed to cancel/abort m_cmd\n");
+}
+
+static int spi_geni_transfer_one(struct spi_master *spi,
+ struct spi_device *slv,
+ struct spi_transfer *xfer)
+{
+ struct spi_geni_master *mas = spi_master_get_devdata(spi);
+
+ /* Terminate and return success for 0 byte length transfer */
+ if (!xfer->len)
+ return 0;
+
+ setup_fifo_xfer(xfer, mas, slv->mode, spi);
+ return 1;
+}
+
+static unsigned int geni_byte_per_fifo_word(struct spi_geni_master *mas)
+{
+ /*
+ * Calculate how many bytes we'll put in each FIFO word. If the
+ * transfer words don't pack cleanly into a FIFO word we'll just put
+ * one transfer word in each FIFO word. If they do pack we'll pack 'em.
+ */
+ if (mas->fifo_width_bits % mas->cur_bits_per_word)
+ return roundup_pow_of_two(DIV_ROUND_UP(mas->cur_bits_per_word,
+ BITS_PER_BYTE));
+
+ return mas->fifo_width_bits / BITS_PER_BYTE;
+}
+
+static void geni_spi_handle_tx(struct spi_geni_master *mas)
+{
+ struct geni_se *se = &mas->se;
+ unsigned int max_bytes;
+ const u8 *tx_buf;
+ unsigned int bytes_per_fifo_word = geni_byte_per_fifo_word(mas);
+ unsigned int i = 0;
+
+ max_bytes = (mas->tx_fifo_depth - mas->tx_wm) * bytes_per_fifo_word;
+ if (mas->tx_rem_bytes < max_bytes)
+ max_bytes = mas->tx_rem_bytes;
+
+ tx_buf = mas->cur_xfer->tx_buf + mas->cur_xfer->len - mas->tx_rem_bytes;
+ while (i < max_bytes) {
+ unsigned int j;
+ unsigned int bytes_to_write;
+ u32 fifo_word = 0;
+ u8 *fifo_byte = (u8 *)&fifo_word;
+
+ bytes_to_write = min(bytes_per_fifo_word, max_bytes - i);
+ for (j = 0; j < bytes_to_write; j++)
+ fifo_byte[j] = tx_buf[i++];
+ iowrite32_rep(se->base + SE_GENI_TX_FIFOn, &fifo_word, 1);
+ }
+ mas->tx_rem_bytes -= max_bytes;
+ if (!mas->tx_rem_bytes)
+ writel(0, se->base + SE_GENI_TX_WATERMARK_REG);
+}
+
+static void geni_spi_handle_rx(struct spi_geni_master *mas)
+{
+ struct geni_se *se = &mas->se;
+ u32 rx_fifo_status;
+ unsigned int rx_bytes;
+ unsigned int rx_last_byte_valid;
+ u8 *rx_buf;
+ unsigned int bytes_per_fifo_word = geni_byte_per_fifo_word(mas);
+ unsigned int i = 0;
+
+ rx_fifo_status = readl(se->base + SE_GENI_RX_FIFO_STATUS);
+ rx_bytes = (rx_fifo_status & RX_FIFO_WC_MSK) * bytes_per_fifo_word;
+ if (rx_fifo_status & RX_LAST) {
+ rx_last_byte_valid = rx_fifo_status & RX_LAST_BYTE_VALID_MSK;
+ rx_last_byte_valid >>= RX_LAST_BYTE_VALID_SHFT;
+ if (rx_last_byte_valid && rx_last_byte_valid < 4)
+ rx_bytes -= bytes_per_fifo_word - rx_last_byte_valid;
+ }
+ if (mas->rx_rem_bytes < rx_bytes)
+ rx_bytes = mas->rx_rem_bytes;
+
+ rx_buf = mas->cur_xfer->rx_buf + mas->cur_xfer->len - mas->rx_rem_bytes;
+ while (i < rx_bytes) {
+ u32 fifo_word = 0;
+ u8 *fifo_byte = (u8 *)&fifo_word;
+ unsigned int bytes_to_read;
+ unsigned int j;
+
+ bytes_to_read = min(bytes_per_fifo_word, rx_bytes - i);
+ ioread32_rep(se->base + SE_GENI_RX_FIFOn, &fifo_word, 1);
+ for (j = 0; j < bytes_to_read; j++)
+ rx_buf[i++] = fifo_byte[j];
+ }
+ mas->rx_rem_bytes -= rx_bytes;
+}
+
+static irqreturn_t geni_spi_isr(int irq, void *data)
+{
+ struct spi_master *spi = data;
+ struct spi_geni_master *mas = spi_master_get_devdata(spi);
+ struct geni_se *se = &mas->se;
+ u32 m_irq;
+ unsigned long flags;
+ irqreturn_t ret = IRQ_HANDLED;
+
+ if (mas->cur_mcmd == CMD_NONE)
+ return IRQ_NONE;
+
+ spin_lock_irqsave(&mas->lock, flags);
+ m_irq = readl(se->base + SE_GENI_M_IRQ_STATUS);
+
+ if ((m_irq & M_RX_FIFO_WATERMARK_EN) || (m_irq & M_RX_FIFO_LAST_EN))
+ geni_spi_handle_rx(mas);
+
+ if (m_irq & M_TX_FIFO_WATERMARK_EN)
+ geni_spi_handle_tx(mas);
+
+ if (m_irq & M_CMD_DONE_EN) {
+ if (mas->cur_mcmd == CMD_XFER)
+ spi_finalize_current_transfer(spi);
+ else if (mas->cur_mcmd == CMD_CS)
+ complete(&mas->xfer_done);
+ mas->cur_mcmd = CMD_NONE;
+ /*
+ * If this happens, then a CMD_DONE came before all the Tx
+ * buffer bytes were sent out. This is unusual, log this
+ * condition and disable the WM interrupt to prevent the
+ * system from stalling due an interrupt storm.
+ * If this happens when all Rx bytes haven't been received, log
+ * the condition.
+ * The only known time this can happen is if bits_per_word != 8
+ * and some registers that expect xfer lengths in num spi_words
+ * weren't written correctly.
+ */
+ if (mas->tx_rem_bytes) {
+ writel(0, se->base + SE_GENI_TX_WATERMARK_REG);
+ dev_err(mas->dev, "Premature done. tx_rem = %d bpw%d\n",
+ mas->tx_rem_bytes, mas->cur_bits_per_word);
+ }
+ if (mas->rx_rem_bytes)
+ dev_err(mas->dev, "Premature done. rx_rem = %d bpw%d\n",
+ mas->rx_rem_bytes, mas->cur_bits_per_word);
+ }
+
+ if ((m_irq & M_CMD_CANCEL_EN) || (m_irq & M_CMD_ABORT_EN)) {
+ mas->cur_mcmd = CMD_NONE;
+ complete(&mas->xfer_done);
+ }
+
+ writel(m_irq, se->base + SE_GENI_M_IRQ_CLEAR);
+ spin_unlock_irqrestore(&mas->lock, flags);
+ return ret;
+}
+
+static int spi_geni_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct spi_master *spi;
+ struct spi_geni_master *mas;
+ struct resource *res;
+ struct geni_se *se;
+
+ spi = spi_alloc_master(&pdev->dev, sizeof(*mas));
+ if (!spi)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, spi);
+ mas = spi_master_get_devdata(spi);
+ mas->dev = &pdev->dev;
+ mas->se.dev = &pdev->dev;
+ mas->se.wrapper = dev_get_drvdata(pdev->dev.parent);
+ se = &mas->se;
+
+ spi->bus_num = -1;
+ spi->dev.of_node = pdev->dev.of_node;
+ mas->se.clk = devm_clk_get(&pdev->dev, "se");
+ if (IS_ERR(mas->se.clk)) {
+ ret = PTR_ERR(mas->se.clk);
+ dev_err(&pdev->dev, "Err getting SE Core clk %d\n", ret);
+ goto spi_geni_probe_err;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ se->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(se->base)) {
+ ret = PTR_ERR(se->base);
+ goto spi_geni_probe_err;
+ }
+
+ spi->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP | SPI_CS_HIGH;
+ spi->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
+ spi->num_chipselect = 4;
+ spi->max_speed_hz = 50000000;
+ spi->prepare_message = spi_geni_prepare_message;
+ spi->transfer_one = spi_geni_transfer_one;
+ spi->auto_runtime_pm = true;
+ spi->handle_err = handle_fifo_timeout;
+ spi->set_cs = spi_geni_set_cs;
+
+ init_completion(&mas->xfer_done);
+ spin_lock_init(&mas->lock);
+ pm_runtime_enable(&pdev->dev);
+
+ ret = spi_geni_init(mas);
+ if (ret)
+ goto spi_geni_probe_runtime_disable;
+
+ mas->irq = platform_get_irq(pdev, 0);
+ if (mas->irq < 0) {
+ ret = mas->irq;
+ dev_err(&pdev->dev, "Err getting IRQ %d\n", ret);
+ goto spi_geni_probe_runtime_disable;
+ }
+
+ ret = request_irq(mas->irq, geni_spi_isr,
+ IRQF_TRIGGER_HIGH, "spi_geni", spi);
+ if (ret)
+ goto spi_geni_probe_runtime_disable;
+
+ ret = spi_register_master(spi);
+ if (ret)
+ goto spi_geni_probe_free_irq;
+
+ return 0;
+spi_geni_probe_free_irq:
+ free_irq(mas->irq, spi);
+spi_geni_probe_runtime_disable:
+ pm_runtime_disable(&pdev->dev);
+spi_geni_probe_err:
+ spi_master_put(spi);
+ return ret;
+}
+
+static int spi_geni_remove(struct platform_device *pdev)
+{
+ struct spi_master *spi = platform_get_drvdata(pdev);
+ struct spi_geni_master *mas = spi_master_get_devdata(spi);
+
+ /* Unregister _before_ disabling pm_runtime() so we stop transfers */
+ spi_unregister_master(spi);
+
+ free_irq(mas->irq, spi);
+ pm_runtime_disable(&pdev->dev);
+ return 0;
+}
+
+static int __maybe_unused spi_geni_runtime_suspend(struct device *dev)
+{
+ struct spi_master *spi = dev_get_drvdata(dev);
+ struct spi_geni_master *mas = spi_master_get_devdata(spi);
+
+ return geni_se_resources_off(&mas->se);
+}
+
+static int __maybe_unused spi_geni_runtime_resume(struct device *dev)
+{
+ struct spi_master *spi = dev_get_drvdata(dev);
+ struct spi_geni_master *mas = spi_master_get_devdata(spi);
+
+ return geni_se_resources_on(&mas->se);
+}
+
+static int __maybe_unused spi_geni_suspend(struct device *dev)
+{
+ struct spi_master *spi = dev_get_drvdata(dev);
+ int ret;
+
+ ret = spi_master_suspend(spi);
+ if (ret)
+ return ret;
+
+ ret = pm_runtime_force_suspend(dev);
+ if (ret)
+ spi_master_resume(spi);
+
+ return ret;
+}
+
+static int __maybe_unused spi_geni_resume(struct device *dev)
+{
+ struct spi_master *spi = dev_get_drvdata(dev);
+ int ret;
+
+ ret = pm_runtime_force_resume(dev);
+ if (ret)
+ return ret;
+
+ ret = spi_master_resume(spi);
+ if (ret)
+ pm_runtime_force_suspend(dev);
+
+ return ret;
+}
+
+static const struct dev_pm_ops spi_geni_pm_ops = {
+ SET_RUNTIME_PM_OPS(spi_geni_runtime_suspend,
+ spi_geni_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(spi_geni_suspend, spi_geni_resume)
+};
+
+static const struct of_device_id spi_geni_dt_match[] = {
+ { .compatible = "qcom,geni-spi" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, spi_geni_dt_match);
+
+static struct platform_driver spi_geni_driver = {
+ .probe = spi_geni_probe,
+ .remove = spi_geni_remove,
+ .driver = {
+ .name = "geni_spi",
+ .pm = &spi_geni_pm_ops,
+ .of_match_table = spi_geni_dt_match,
+ },
+};
+module_platform_driver(spi_geni_driver);
+
+MODULE_DESCRIPTION("SPI driver for GENI based QUP cores");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c
index 421bfc7dda67..45973ee3ae11 100644
--- a/drivers/spi/spi-gpio.c
+++ b/drivers/spi/spi-gpio.c
@@ -295,9 +295,11 @@ static int spi_gpio_request(struct device *dev,
spi_gpio->miso = devm_gpiod_get_optional(dev, "miso", GPIOD_IN);
if (IS_ERR(spi_gpio->miso))
return PTR_ERR(spi_gpio->miso);
- if (!spi_gpio->miso)
- /* HW configuration without MISO pin */
- *mflags |= SPI_MASTER_NO_RX;
+ /*
+ * No setting SPI_MASTER_NO_RX here - if there is only a MOSI
+ * pin connected the host can still do RX by changing the
+ * direction of the line.
+ */
spi_gpio->sck = devm_gpiod_get(dev, "sck", GPIOD_OUT_LOW);
if (IS_ERR(spi_gpio->sck))
@@ -423,7 +425,7 @@ static int spi_gpio_probe(struct platform_device *pdev)
spi_gpio->bitbang.chipselect = spi_gpio_chipselect;
spi_gpio->bitbang.set_line_direction = spi_gpio_set_direction;
- if ((master_flags & (SPI_MASTER_NO_TX | SPI_MASTER_NO_RX)) == 0) {
+ if ((master_flags & SPI_MASTER_NO_TX) == 0) {
spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_word_mode0;
spi_gpio->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_txrx_word_mode1;
spi_gpio->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_txrx_word_mode2;
@@ -447,10 +449,8 @@ static int spi_gpio_probe(struct platform_device *pdev)
static int spi_gpio_remove(struct platform_device *pdev)
{
struct spi_gpio *spi_gpio;
- struct spi_gpio_platform_data *pdata;
spi_gpio = platform_get_drvdata(pdev);
- pdata = dev_get_platdata(&pdev->dev);
/* stop() unregisters child devices too */
spi_bitbang_stop(&spi_gpio->bitbang);
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index 08dd3a31a3e5..dd1ce12aa386 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -63,6 +63,7 @@ struct spi_imx_devtype_data {
void (*trigger)(struct spi_imx_data *);
int (*rx_available)(struct spi_imx_data *);
void (*reset)(struct spi_imx_data *);
+ void (*setup_wml)(struct spi_imx_data *);
void (*disable)(struct spi_imx_data *);
bool has_dmamode;
bool has_slavemode;
@@ -216,7 +217,6 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
struct spi_transfer *transfer)
{
struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
- unsigned int bytes_per_word, i;
if (!master->dma_rx)
return false;
@@ -224,14 +224,9 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
if (spi_imx->slave_mode)
return false;
- bytes_per_word = spi_imx_bytes_per_word(transfer->bits_per_word);
-
- for (i = spi_imx->devtype_data->fifo_size / 2; i > 0; i--) {
- if (!(transfer->len % (i * bytes_per_word)))
- break;
- }
+ if (transfer->len < spi_imx->devtype_data->fifo_size)
+ return false;
- spi_imx->wml = i;
spi_imx->dynamic_burst = 0;
return true;
@@ -583,18 +578,21 @@ static int mx51_ecspi_config(struct spi_device *spi)
else /* SCLK is _very_ slow */
usleep_range(delay, delay + 10);
+ return 0;
+}
+
+static void mx51_setup_wml(struct spi_imx_data *spi_imx)
+{
/*
* Configure the DMA register: setup the watermark
* and enable DMA request.
*/
- writel(MX51_ECSPI_DMA_RX_WML(spi_imx->wml) |
+ writel(MX51_ECSPI_DMA_RX_WML(spi_imx->wml - 1) |
MX51_ECSPI_DMA_TX_WML(spi_imx->wml) |
MX51_ECSPI_DMA_RXT_WML(spi_imx->wml) |
MX51_ECSPI_DMA_TEDEN | MX51_ECSPI_DMA_RXDEN |
MX51_ECSPI_DMA_RXTDEN, spi_imx->base + MX51_ECSPI_DMA);
-
- return 0;
}
static int mx51_ecspi_rx_available(struct spi_imx_data *spi_imx)
@@ -931,6 +929,7 @@ static struct spi_imx_devtype_data imx51_ecspi_devtype_data = {
.trigger = mx51_ecspi_trigger,
.rx_available = mx51_ecspi_rx_available,
.reset = mx51_ecspi_reset,
+ .setup_wml = mx51_setup_wml,
.fifo_size = 64,
.has_dmamode = true,
.dynamic_burst = true,
@@ -1138,7 +1137,6 @@ static int spi_imx_setupxfer(struct spi_device *spi,
struct spi_transfer *t)
{
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
- int ret;
if (!t)
return 0;
@@ -1179,12 +1177,6 @@ static int spi_imx_setupxfer(struct spi_device *spi,
else
spi_imx->usedma = 0;
- if (spi_imx->usedma) {
- ret = spi_imx_dma_configure(spi->master);
- if (ret)
- return ret;
- }
-
if (is_imx53_ecspi(spi_imx) && spi_imx->slave_mode) {
spi_imx->rx = mx53_ecspi_rx_slave;
spi_imx->tx = mx53_ecspi_tx_slave;
@@ -1289,6 +1281,31 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
unsigned long timeout;
struct spi_master *master = spi_imx->bitbang.master;
struct sg_table *tx = &transfer->tx_sg, *rx = &transfer->rx_sg;
+ struct scatterlist *last_sg = sg_last(rx->sgl, rx->nents);
+ unsigned int bytes_per_word, i;
+ int ret;
+
+ /* Get the right burst length from the last sg to ensure no tail data */
+ bytes_per_word = spi_imx_bytes_per_word(transfer->bits_per_word);
+ for (i = spi_imx->devtype_data->fifo_size / 2; i > 0; i--) {
+ if (!(sg_dma_len(last_sg) % (i * bytes_per_word)))
+ break;
+ }
+ /* Use 1 as wml in case no available burst length got */
+ if (i == 0)
+ i = 1;
+
+ spi_imx->wml = i;
+
+ ret = spi_imx_dma_configure(master);
+ if (ret)
+ return ret;
+
+ if (!spi_imx->devtype_data->setup_wml) {
+ dev_err(spi_imx->dev, "No setup_wml()?\n");
+ return -EINVAL;
+ }
+ spi_imx->devtype_data->setup_wml(spi_imx);
/*
* The TX DMA setup starts the transfer, so make sure RX is configured
diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
index e43842c7a31a..62a7b80801d2 100644
--- a/drivers/spi/spi-mem.c
+++ b/drivers/spi/spi-mem.c
@@ -12,6 +12,8 @@
#include "internals.h"
+#define SPI_MEM_MAX_BUSWIDTH 4
+
/**
* spi_controller_dma_map_mem_op_data() - DMA-map the buffer attached to a
* memory operation
@@ -149,6 +151,44 @@ static bool spi_mem_default_supports_op(struct spi_mem *mem,
}
EXPORT_SYMBOL_GPL(spi_mem_default_supports_op);
+static bool spi_mem_buswidth_is_valid(u8 buswidth)
+{
+ if (hweight8(buswidth) > 1 || buswidth > SPI_MEM_MAX_BUSWIDTH)
+ return false;
+
+ return true;
+}
+
+static int spi_mem_check_op(const struct spi_mem_op *op)
+{
+ if (!op->cmd.buswidth)
+ return -EINVAL;
+
+ if ((op->addr.nbytes && !op->addr.buswidth) ||
+ (op->dummy.nbytes && !op->dummy.buswidth) ||
+ (op->data.nbytes && !op->data.buswidth))
+ return -EINVAL;
+
+ if (!spi_mem_buswidth_is_valid(op->cmd.buswidth) ||
+ !spi_mem_buswidth_is_valid(op->addr.buswidth) ||
+ !spi_mem_buswidth_is_valid(op->dummy.buswidth) ||
+ !spi_mem_buswidth_is_valid(op->data.buswidth))
+ return -EINVAL;
+
+ return 0;
+}
+
+static bool spi_mem_internal_supports_op(struct spi_mem *mem,
+ const struct spi_mem_op *op)
+{
+ struct spi_controller *ctlr = mem->spi->controller;
+
+ if (ctlr->mem_ops && ctlr->mem_ops->supports_op)
+ return ctlr->mem_ops->supports_op(mem, op);
+
+ return spi_mem_default_supports_op(mem, op);
+}
+
/**
* spi_mem_supports_op() - Check if a memory device and the controller it is
* connected to support a specific memory operation
@@ -166,12 +206,10 @@ EXPORT_SYMBOL_GPL(spi_mem_default_supports_op);
*/
bool spi_mem_supports_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
- struct spi_controller *ctlr = mem->spi->controller;
-
- if (ctlr->mem_ops && ctlr->mem_ops->supports_op)
- return ctlr->mem_ops->supports_op(mem, op);
+ if (spi_mem_check_op(op))
+ return false;
- return spi_mem_default_supports_op(mem, op);
+ return spi_mem_internal_supports_op(mem, op);
}
EXPORT_SYMBOL_GPL(spi_mem_supports_op);
@@ -196,7 +234,11 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
u8 *tmpbuf;
int ret;
- if (!spi_mem_supports_op(mem, op))
+ ret = spi_mem_check_op(op);
+ if (ret)
+ return ret;
+
+ if (!spi_mem_internal_supports_op(mem, op))
return -ENOTSUPP;
if (ctlr->mem_ops) {
@@ -346,10 +388,25 @@ EXPORT_SYMBOL_GPL(spi_mem_get_name);
int spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
{
struct spi_controller *ctlr = mem->spi->controller;
+ size_t len;
+
+ len = sizeof(op->cmd.opcode) + op->addr.nbytes + op->dummy.nbytes;
if (ctlr->mem_ops && ctlr->mem_ops->adjust_op_size)
return ctlr->mem_ops->adjust_op_size(mem, op);
+ if (!ctlr->mem_ops || !ctlr->mem_ops->exec_op) {
+ if (len > spi_max_transfer_size(mem->spi))
+ return -EINVAL;
+
+ op->data.nbytes = min3((size_t)op->data.nbytes,
+ spi_max_transfer_size(mem->spi),
+ spi_max_message_size(mem->spi) -
+ len);
+ if (!op->data.nbytes)
+ return -EINVAL;
+ }
+
return 0;
}
EXPORT_SYMBOL_GPL(spi_mem_adjust_op_size);
diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c
index 86bf45667a04..3dc31627c655 100644
--- a/drivers/spi/spi-mt65xx.c
+++ b/drivers/spi/spi-mt65xx.c
@@ -98,6 +98,7 @@ struct mtk_spi {
struct clk *parent_clk, *sel_clk, *spi_clk;
struct spi_transfer *cur_transfer;
u32 xfer_len;
+ u32 num_xfered;
struct scatterlist *tx_sgl, *rx_sgl;
u32 tx_sgl_len, rx_sgl_len;
const struct mtk_spi_compatible *dev_comp;
@@ -385,6 +386,7 @@ static int mtk_spi_fifo_transfer(struct spi_master *master,
mdata->cur_transfer = xfer;
mdata->xfer_len = min(MTK_SPI_MAX_FIFO_SIZE, xfer->len);
+ mdata->num_xfered = 0;
mtk_spi_prepare_transfer(master, xfer);
mtk_spi_setup_packet(master);
@@ -415,6 +417,7 @@ static int mtk_spi_dma_transfer(struct spi_master *master,
mdata->tx_sgl_len = 0;
mdata->rx_sgl_len = 0;
mdata->cur_transfer = xfer;
+ mdata->num_xfered = 0;
mtk_spi_prepare_transfer(master, xfer);
@@ -482,7 +485,7 @@ static int mtk_spi_setup(struct spi_device *spi)
static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id)
{
- u32 cmd, reg_val, cnt, remainder;
+ u32 cmd, reg_val, cnt, remainder, len;
struct spi_master *master = dev_id;
struct mtk_spi *mdata = spi_master_get_devdata(master);
struct spi_transfer *trans = mdata->cur_transfer;
@@ -497,36 +500,38 @@ static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id)
if (trans->rx_buf) {
cnt = mdata->xfer_len / 4;
ioread32_rep(mdata->base + SPI_RX_DATA_REG,
- trans->rx_buf, cnt);
+ trans->rx_buf + mdata->num_xfered, cnt);
remainder = mdata->xfer_len % 4;
if (remainder > 0) {
reg_val = readl(mdata->base + SPI_RX_DATA_REG);
- memcpy(trans->rx_buf + (cnt * 4),
- &reg_val, remainder);
+ memcpy(trans->rx_buf +
+ mdata->num_xfered +
+ (cnt * 4),
+ &reg_val,
+ remainder);
}
}
- trans->len -= mdata->xfer_len;
- if (!trans->len) {
+ mdata->num_xfered += mdata->xfer_len;
+ if (mdata->num_xfered == trans->len) {
spi_finalize_current_transfer(master);
return IRQ_HANDLED;
}
- if (trans->tx_buf)
- trans->tx_buf += mdata->xfer_len;
- if (trans->rx_buf)
- trans->rx_buf += mdata->xfer_len;
-
- mdata->xfer_len = min(MTK_SPI_MAX_FIFO_SIZE, trans->len);
+ len = trans->len - mdata->num_xfered;
+ mdata->xfer_len = min(MTK_SPI_MAX_FIFO_SIZE, len);
mtk_spi_setup_packet(master);
- cnt = trans->len / 4;
- iowrite32_rep(mdata->base + SPI_TX_DATA_REG, trans->tx_buf, cnt);
+ cnt = len / 4;
+ iowrite32_rep(mdata->base + SPI_TX_DATA_REG,
+ trans->tx_buf + mdata->num_xfered, cnt);
- remainder = trans->len % 4;
+ remainder = len % 4;
if (remainder > 0) {
reg_val = 0;
- memcpy(&reg_val, trans->tx_buf + (cnt * 4), remainder);
+ memcpy(&reg_val,
+ trans->tx_buf + (cnt * 4) + mdata->num_xfered,
+ remainder);
writel(reg_val, mdata->base + SPI_TX_DATA_REG);
}
diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index 508c61c669e7..f024c3fc3679 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -33,6 +33,7 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/gcd.h>
+#include <linux/iopoll.h>
#include <linux/spi/spi.h>
#include <linux/gpio.h>
@@ -126,6 +127,7 @@ struct omap2_mcspi_regs {
};
struct omap2_mcspi {
+ struct completion txdone;
struct spi_master *master;
/* Virtual base address of the controller */
void __iomem *base;
@@ -135,6 +137,7 @@ struct omap2_mcspi {
struct device *dev;
struct omap2_mcspi_regs ctx;
int fifo_depth;
+ bool slave_aborted;
unsigned int pin_dir:1;
};
@@ -274,19 +277,23 @@ static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable)
}
}
-static void omap2_mcspi_set_master_mode(struct spi_master *master)
+static void omap2_mcspi_set_mode(struct spi_master *master)
{
struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
struct omap2_mcspi_regs *ctx = &mcspi->ctx;
u32 l;
/*
- * Setup when switching from (reset default) slave mode
- * to single-channel master mode
+ * Choose master or slave mode
*/
l = mcspi_read_reg(master, OMAP2_MCSPI_MODULCTRL);
- l &= ~(OMAP2_MCSPI_MODULCTRL_STEST | OMAP2_MCSPI_MODULCTRL_MS);
- l |= OMAP2_MCSPI_MODULCTRL_SINGLE;
+ l &= ~(OMAP2_MCSPI_MODULCTRL_STEST);
+ if (spi_controller_is_slave(master)) {
+ l |= (OMAP2_MCSPI_MODULCTRL_MS);
+ } else {
+ l &= ~(OMAP2_MCSPI_MODULCTRL_MS);
+ l |= OMAP2_MCSPI_MODULCTRL_SINGLE;
+ }
mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, l);
ctx->modulctrl = l;
@@ -299,7 +306,7 @@ static void omap2_mcspi_set_fifo(const struct spi_device *spi,
struct omap2_mcspi_cs *cs = spi->controller_state;
struct omap2_mcspi *mcspi;
unsigned int wcnt;
- int max_fifo_depth, fifo_depth, bytes_per_word;
+ int max_fifo_depth, bytes_per_word;
u32 chconf, xferlevel;
mcspi = spi_master_get_devdata(master);
@@ -315,10 +322,6 @@ static void omap2_mcspi_set_fifo(const struct spi_device *spi,
else
max_fifo_depth = OMAP2_MCSPI_MAX_FIFODEPTH;
- fifo_depth = gcd(t->len, max_fifo_depth);
- if (fifo_depth < 2 || fifo_depth % bytes_per_word != 0)
- goto disable_fifo;
-
wcnt = t->len / bytes_per_word;
if (wcnt > OMAP2_MCSPI_MAX_FIFOWCNT)
goto disable_fifo;
@@ -326,16 +329,17 @@ static void omap2_mcspi_set_fifo(const struct spi_device *spi,
xferlevel = wcnt << 16;
if (t->rx_buf != NULL) {
chconf |= OMAP2_MCSPI_CHCONF_FFER;
- xferlevel |= (fifo_depth - 1) << 8;
+ xferlevel |= (bytes_per_word - 1) << 8;
}
+
if (t->tx_buf != NULL) {
chconf |= OMAP2_MCSPI_CHCONF_FFET;
- xferlevel |= fifo_depth - 1;
+ xferlevel |= bytes_per_word - 1;
}
mcspi_write_reg(master, OMAP2_MCSPI_XFERLEVEL, xferlevel);
mcspi_write_chconf0(spi, chconf);
- mcspi->fifo_depth = fifo_depth;
+ mcspi->fifo_depth = max_fifo_depth;
return;
}
@@ -353,18 +357,22 @@ disable_fifo:
static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit)
{
- unsigned long timeout;
-
- timeout = jiffies + msecs_to_jiffies(1000);
- while (!(readl_relaxed(reg) & bit)) {
- if (time_after(jiffies, timeout)) {
- if (!(readl_relaxed(reg) & bit))
- return -ETIMEDOUT;
- else
- return 0;
- }
- cpu_relax();
+ u32 val;
+
+ return readl_poll_timeout(reg, val, val & bit, 1, MSEC_PER_SEC);
+}
+
+static int mcspi_wait_for_completion(struct omap2_mcspi *mcspi,
+ struct completion *x)
+{
+ if (spi_controller_is_slave(mcspi->master)) {
+ if (wait_for_completion_interruptible(x) ||
+ mcspi->slave_aborted)
+ return -EINTR;
+ } else {
+ wait_for_completion(x);
}
+
return 0;
}
@@ -517,7 +525,12 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
dma_async_issue_pending(mcspi_dma->dma_rx);
omap2_mcspi_set_dma_req(spi, 1, 1);
- wait_for_completion(&mcspi_dma->dma_rx_completion);
+ ret = mcspi_wait_for_completion(mcspi, &mcspi_dma->dma_rx_completion);
+ if (ret || mcspi->slave_aborted) {
+ dmaengine_terminate_sync(mcspi_dma->dma_rx);
+ omap2_mcspi_set_dma_req(spi, 1, 0);
+ return 0;
+ }
for (x = 0; x < nb_sizes; x++)
kfree(sg_out[x]);
@@ -585,7 +598,6 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
struct dma_slave_config cfg;
enum dma_slave_buswidth width;
unsigned es;
- u32 burst;
void __iomem *chstat_reg;
void __iomem *irqstat_reg;
int wait_res;
@@ -605,34 +617,49 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
}
count = xfer->len;
- burst = 1;
-
- if (mcspi->fifo_depth > 0) {
- if (count > mcspi->fifo_depth)
- burst = mcspi->fifo_depth / es;
- else
- burst = count / es;
- }
memset(&cfg, 0, sizeof(cfg));
cfg.src_addr = cs->phys + OMAP2_MCSPI_RX0;
cfg.dst_addr = cs->phys + OMAP2_MCSPI_TX0;
cfg.src_addr_width = width;
cfg.dst_addr_width = width;
- cfg.src_maxburst = burst;
- cfg.dst_maxburst = burst;
+ cfg.src_maxburst = es;
+ cfg.dst_maxburst = es;
rx = xfer->rx_buf;
tx = xfer->tx_buf;
- if (tx != NULL)
+ mcspi->slave_aborted = false;
+ reinit_completion(&mcspi_dma->dma_tx_completion);
+ reinit_completion(&mcspi_dma->dma_rx_completion);
+ reinit_completion(&mcspi->txdone);
+ if (tx) {
+ /* Enable EOW IRQ to know end of tx in slave mode */
+ if (spi_controller_is_slave(spi->master))
+ mcspi_write_reg(spi->master,
+ OMAP2_MCSPI_IRQENABLE,
+ OMAP2_MCSPI_IRQSTATUS_EOW);
omap2_mcspi_tx_dma(spi, xfer, cfg);
+ }
if (rx != NULL)
count = omap2_mcspi_rx_dma(spi, xfer, cfg, es);
if (tx != NULL) {
- wait_for_completion(&mcspi_dma->dma_tx_completion);
+ int ret;
+
+ ret = mcspi_wait_for_completion(mcspi, &mcspi_dma->dma_tx_completion);
+ if (ret || mcspi->slave_aborted) {
+ dmaengine_terminate_sync(mcspi_dma->dma_tx);
+ omap2_mcspi_set_dma_req(spi, 0, 0);
+ return 0;
+ }
+
+ if (spi_controller_is_slave(mcspi->master)) {
+ ret = mcspi_wait_for_completion(mcspi, &mcspi->txdone);
+ if (ret || mcspi->slave_aborted)
+ return 0;
+ }
if (mcspi->fifo_depth > 0) {
irqstat_reg = mcspi->base + OMAP2_MCSPI_IRQSTATUS;
@@ -1089,6 +1116,36 @@ static void omap2_mcspi_cleanup(struct spi_device *spi)
gpio_free(spi->cs_gpio);
}
+static irqreturn_t omap2_mcspi_irq_handler(int irq, void *data)
+{
+ struct omap2_mcspi *mcspi = data;
+ u32 irqstat;
+
+ irqstat = mcspi_read_reg(mcspi->master, OMAP2_MCSPI_IRQSTATUS);
+ if (!irqstat)
+ return IRQ_NONE;
+
+ /* Disable IRQ and wakeup slave xfer task */
+ mcspi_write_reg(mcspi->master, OMAP2_MCSPI_IRQENABLE, 0);
+ if (irqstat & OMAP2_MCSPI_IRQSTATUS_EOW)
+ complete(&mcspi->txdone);
+
+ return IRQ_HANDLED;
+}
+
+static int omap2_mcspi_slave_abort(struct spi_master *master)
+{
+ struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
+ struct omap2_mcspi_dma *mcspi_dma = mcspi->dma_channels;
+
+ mcspi->slave_aborted = true;
+ complete(&mcspi_dma->dma_rx_completion);
+ complete(&mcspi_dma->dma_tx_completion);
+ complete(&mcspi->txdone);
+
+ return 0;
+}
+
static int omap2_mcspi_transfer_one(struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *t)
@@ -1255,10 +1312,20 @@ static bool omap2_mcspi_can_dma(struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *xfer)
{
+ struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
+ struct omap2_mcspi_dma *mcspi_dma =
+ &mcspi->dma_channels[spi->chip_select];
+
+ if (!mcspi_dma->dma_rx || !mcspi_dma->dma_tx)
+ return false;
+
+ if (spi_controller_is_slave(master))
+ return true;
+
return (xfer->len >= DMA_MIN_BYTES);
}
-static int omap2_mcspi_master_setup(struct omap2_mcspi *mcspi)
+static int omap2_mcspi_controller_setup(struct omap2_mcspi *mcspi)
{
struct spi_master *master = mcspi->master;
struct omap2_mcspi_regs *ctx = &mcspi->ctx;
@@ -1275,7 +1342,7 @@ static int omap2_mcspi_master_setup(struct omap2_mcspi *mcspi)
OMAP2_MCSPI_WAKEUPENABLE_WKEN);
ctx->wakeupenable = OMAP2_MCSPI_WAKEUPENABLE_WKEN;
- omap2_mcspi_set_master_mode(master);
+ omap2_mcspi_set_mode(master);
pm_runtime_mark_last_busy(mcspi->dev);
pm_runtime_put_autosuspend(mcspi->dev);
return 0;
@@ -1350,11 +1417,12 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
struct device_node *node = pdev->dev.of_node;
const struct of_device_id *match;
- master = spi_alloc_master(&pdev->dev, sizeof *mcspi);
- if (master == NULL) {
- dev_dbg(&pdev->dev, "master allocation failed\n");
+ if (of_property_read_bool(node, "spi-slave"))
+ master = spi_alloc_slave(&pdev->dev, sizeof(*mcspi));
+ else
+ master = spi_alloc_master(&pdev->dev, sizeof(*mcspi));
+ if (!master)
return -ENOMEM;
- }
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
@@ -1366,6 +1434,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
master->transfer_one = omap2_mcspi_transfer_one;
master->set_cs = omap2_mcspi_set_cs;
master->cleanup = omap2_mcspi_cleanup;
+ master->slave_abort = omap2_mcspi_slave_abort;
master->dev.of_node = node;
master->max_speed_hz = OMAP2_MCSPI_MAX_FREQ;
master->min_speed_hz = OMAP2_MCSPI_MAX_FREQ >> 15;
@@ -1417,15 +1486,31 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
sprintf(mcspi->dma_channels[i].dma_tx_ch_name, "tx%d", i);
}
+ status = platform_get_irq(pdev, 0);
+ if (status == -EPROBE_DEFER)
+ goto free_master;
+ if (status < 0) {
+ dev_err(&pdev->dev, "no irq resource found\n");
+ goto free_master;
+ }
+ init_completion(&mcspi->txdone);
+ status = devm_request_irq(&pdev->dev, status,
+ omap2_mcspi_irq_handler, 0, pdev->name,
+ mcspi);
+ if (status) {
+ dev_err(&pdev->dev, "Cannot request IRQ");
+ goto free_master;
+ }
+
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT);
pm_runtime_enable(&pdev->dev);
- status = omap2_mcspi_master_setup(mcspi);
+ status = omap2_mcspi_controller_setup(mcspi);
if (status < 0)
goto disable_pm;
- status = devm_spi_register_master(&pdev->dev, master);
+ status = devm_spi_register_controller(&pdev->dev, master);
if (status < 0)
goto disable_pm;
diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c
index 47ef6b1a2e76..7f280567093e 100644
--- a/drivers/spi/spi-orion.c
+++ b/drivers/spi/spi-orion.c
@@ -431,6 +431,7 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
int word_len;
struct orion_spi *orion_spi;
int cs = spi->chip_select;
+ void __iomem *vaddr;
word_len = spi->bits_per_word;
count = xfer->len;
@@ -441,8 +442,9 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
* Use SPI direct write mode if base address is available. Otherwise
* fall back to PIO mode for this transfer.
*/
- if ((orion_spi->child[cs].direct_access.vaddr) && (xfer->tx_buf) &&
- (word_len == 8)) {
+ vaddr = orion_spi->child[cs].direct_access.vaddr;
+
+ if (vaddr && xfer->tx_buf && word_len == 8) {
unsigned int cnt = count / 4;
unsigned int rem = count % 4;
@@ -450,13 +452,11 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
* Send the TX-data to the SPI device via the direct
* mapped address window
*/
- iowrite32_rep(orion_spi->child[cs].direct_access.vaddr,
- xfer->tx_buf, cnt);
+ iowrite32_rep(vaddr, xfer->tx_buf, cnt);
if (rem) {
u32 *buf = (u32 *)xfer->tx_buf;
- iowrite8_rep(orion_spi->child[cs].direct_access.vaddr,
- &buf[cnt], rem);
+ iowrite8_rep(vaddr, &buf[cnt], rem);
}
return count;
@@ -683,6 +683,7 @@ static int orion_spi_probe(struct platform_device *pdev)
}
for_each_available_child_of_node(pdev->dev.of_node, np) {
+ struct orion_direct_acc *dir_acc;
u32 cs;
int cs_gpio;
@@ -750,14 +751,13 @@ static int orion_spi_probe(struct platform_device *pdev)
* This needs to get extended for the direct SPI-NOR / SPI-NAND
* support, once this gets implemented.
*/
- spi->child[cs].direct_access.vaddr = devm_ioremap(&pdev->dev,
- r->start,
- PAGE_SIZE);
- if (!spi->child[cs].direct_access.vaddr) {
+ dir_acc = &spi->child[cs].direct_access;
+ dir_acc->vaddr = devm_ioremap(&pdev->dev, r->start, PAGE_SIZE);
+ if (!dir_acc->vaddr) {
status = -ENOMEM;
goto out_rel_axi_clk;
}
- spi->child[cs].direct_access.size = PAGE_SIZE;
+ dir_acc->size = PAGE_SIZE;
dev_info(&pdev->dev, "CS%d configured for direct access\n", cs);
}
diff --git a/drivers/spi/spi-pic32-sqi.c b/drivers/spi/spi-pic32-sqi.c
index bd1c6b53283f..d7e4e18ec3df 100644
--- a/drivers/spi/spi-pic32-sqi.c
+++ b/drivers/spi/spi-pic32-sqi.c
@@ -468,7 +468,7 @@ static int ring_desc_ring_alloc(struct pic32_sqi *sqi)
/* allocate coherent DMAable memory for hardware buffer descriptors. */
sqi->bd = dma_zalloc_coherent(&sqi->master->dev,
sizeof(*bd) * PESQI_BD_COUNT,
- &sqi->bd_dma, GFP_DMA32);
+ &sqi->bd_dma, GFP_KERNEL);
if (!sqi->bd) {
dev_err(&sqi->master->dev, "failed allocating dma buffer\n");
return -ENOMEM;
@@ -656,7 +656,7 @@ static int pic32_sqi_probe(struct platform_device *pdev)
master->max_speed_hz = clk_get_rate(sqi->base_clk);
master->dma_alignment = 32;
master->max_dma_len = PESQI_BD_BUF_LEN_MAX;
- master->dev.of_node = of_node_get(pdev->dev.of_node);
+ master->dev.of_node = pdev->dev.of_node;
master->mode_bits = SPI_MODE_3 | SPI_MODE_0 | SPI_TX_DUAL |
SPI_RX_DUAL | SPI_TX_QUAD | SPI_RX_QUAD;
master->flags = SPI_MASTER_HALF_DUPLEX;
diff --git a/drivers/spi/spi-pic32.c b/drivers/spi/spi-pic32.c
index f8a45af1fa9f..131849adc570 100644
--- a/drivers/spi/spi-pic32.c
+++ b/drivers/spi/spi-pic32.c
@@ -320,7 +320,7 @@ static int pic32_spi_dma_transfer(struct pic32_spi *pic32s,
desc_rx = dmaengine_prep_slave_sg(master->dma_rx,
xfer->rx_sg.sgl,
xfer->rx_sg.nents,
- DMA_FROM_DEVICE,
+ DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc_rx) {
ret = -EINVAL;
@@ -330,7 +330,7 @@ static int pic32_spi_dma_transfer(struct pic32_spi *pic32s,
desc_tx = dmaengine_prep_slave_sg(master->dma_tx,
xfer->tx_sg.sgl,
xfer->tx_sg.nents,
- DMA_TO_DEVICE,
+ DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc_tx) {
ret = -EINVAL;
@@ -774,7 +774,7 @@ static int pic32_spi_probe(struct platform_device *pdev)
if (ret)
goto err_master;
- master->dev.of_node = of_node_get(pdev->dev.of_node);
+ master->dev.of_node = pdev->dev.of_node;
master->mode_bits = SPI_MODE_3 | SPI_MODE_0 | SPI_CS_HIGH;
master->num_chipselect = 1; /* single chip-select */
master->max_speed_hz = clk_get_rate(pic32s->clk);
diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c
index 1af8c96b940e..6120e6abcd96 100644
--- a/drivers/spi/spi-pl022.c
+++ b/drivers/spi/spi-pl022.c
@@ -1490,10 +1490,8 @@ static void do_polling_transfer(struct pl022 *pl022)
struct spi_message *message = NULL;
struct spi_transfer *transfer = NULL;
struct spi_transfer *previous = NULL;
- struct chip_data *chip;
unsigned long time, timeout;
- chip = pl022->cur_chip;
message = pl022->cur_msg;
while (message->state != STATE_DONE) {
@@ -2325,10 +2323,8 @@ static int pl022_suspend(struct device *dev)
int ret;
ret = spi_master_suspend(pl022->master);
- if (ret) {
- dev_warn(dev, "cannot suspend master\n");
+ if (ret)
return ret;
- }
ret = pm_runtime_force_suspend(dev);
if (ret) {
@@ -2353,9 +2349,7 @@ static int pl022_resume(struct device *dev)
/* Start the queue running */
ret = spi_master_resume(pl022->master);
- if (ret)
- dev_err(dev, "problem starting queue (%d)\n", ret);
- else
+ if (!ret)
dev_dbg(dev, "resumed\n");
return ret;
diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c
index 14f4ea59caff..612cc49db28f 100644
--- a/drivers/spi/spi-pxa2xx.c
+++ b/drivers/spi/spi-pxa2xx.c
@@ -33,6 +33,7 @@
#include <linux/clk.h>
#include <linux/pm_runtime.h>
#include <linux/acpi.h>
+#include <linux/of_device.h>
#include "spi-pxa2xx.h"
@@ -665,9 +666,11 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
bytes_left = drv_data->rx_end - drv_data->rx;
switch (drv_data->n_bytes) {
case 4:
- bytes_left >>= 1;
+ bytes_left >>= 2;
+ break;
case 2:
bytes_left >>= 1;
+ break;
}
rx_thre = pxa2xx_spi_get_rx_default_thre(drv_data);
@@ -1333,9 +1336,6 @@ static void cleanup(struct spi_device *spi)
kfree(chip);
}
-#ifdef CONFIG_PCI
-#ifdef CONFIG_ACPI
-
static const struct acpi_device_id pxa2xx_spi_acpi_match[] = {
{ "INT33C0", LPSS_LPT_SSP },
{ "INT33C1", LPSS_LPT_SSP },
@@ -1347,23 +1347,6 @@ static const struct acpi_device_id pxa2xx_spi_acpi_match[] = {
};
MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match);
-static int pxa2xx_spi_get_port_id(struct acpi_device *adev)
-{
- unsigned int devid;
- int port_id = -1;
-
- if (adev && adev->pnp.unique_id &&
- !kstrtouint(adev->pnp.unique_id, 0, &devid))
- port_id = devid;
- return port_id;
-}
-#else /* !CONFIG_ACPI */
-static int pxa2xx_spi_get_port_id(struct acpi_device *adev)
-{
- return -1;
-}
-#endif
-
/*
* PCI IDs of compound devices that integrate both host controller and private
* integrated DMA engine. Please note these are not used in module
@@ -1410,6 +1393,37 @@ static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = {
{ },
};
+static const struct of_device_id pxa2xx_spi_of_match[] = {
+ { .compatible = "marvell,mmp2-ssp", .data = (void *)MMP2_SSP },
+ {},
+};
+MODULE_DEVICE_TABLE(of, pxa2xx_spi_of_match);
+
+#ifdef CONFIG_ACPI
+
+static int pxa2xx_spi_get_port_id(struct acpi_device *adev)
+{
+ unsigned int devid;
+ int port_id = -1;
+
+ if (adev && adev->pnp.unique_id &&
+ !kstrtouint(adev->pnp.unique_id, 0, &devid))
+ port_id = devid;
+ return port_id;
+}
+
+#else /* !CONFIG_ACPI */
+
+static int pxa2xx_spi_get_port_id(struct acpi_device *adev)
+{
+ return -1;
+}
+
+#endif /* CONFIG_ACPI */
+
+
+#ifdef CONFIG_PCI
+
static bool pxa2xx_spi_idma_filter(struct dma_chan *chan, void *param)
{
struct device *dev = param;
@@ -1420,6 +1434,8 @@ static bool pxa2xx_spi_idma_filter(struct dma_chan *chan, void *param)
return true;
}
+#endif /* CONFIG_PCI */
+
static struct pxa2xx_spi_master *
pxa2xx_spi_init_pdata(struct platform_device *pdev)
{
@@ -1429,11 +1445,15 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev)
struct resource *res;
const struct acpi_device_id *adev_id = NULL;
const struct pci_device_id *pcidev_id = NULL;
- int type;
+ const struct of_device_id *of_id = NULL;
+ enum pxa_ssp_type type;
adev = ACPI_COMPANION(&pdev->dev);
- if (dev_is_pci(pdev->dev.parent))
+ if (pdev->dev.of_node)
+ of_id = of_match_device(pdev->dev.driver->of_match_table,
+ &pdev->dev);
+ else if (dev_is_pci(pdev->dev.parent))
pcidev_id = pci_match_id(pxa2xx_spi_pci_compound_match,
to_pci_dev(pdev->dev.parent));
else if (adev)
@@ -1443,9 +1463,11 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev)
return NULL;
if (adev_id)
- type = (int)adev_id->driver_data;
+ type = (enum pxa_ssp_type)adev_id->driver_data;
else if (pcidev_id)
- type = (int)pcidev_id->driver_data;
+ type = (enum pxa_ssp_type)pcidev_id->driver_data;
+ else if (of_id)
+ type = (enum pxa_ssp_type)of_id->data;
else
return NULL;
@@ -1464,11 +1486,13 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev)
if (IS_ERR(ssp->mmio_base))
return NULL;
+#ifdef CONFIG_PCI
if (pcidev_id) {
pdata->tx_param = pdev->dev.parent;
pdata->rx_param = pdev->dev.parent;
pdata->dma_filter = pxa2xx_spi_idma_filter;
}
+#endif
ssp->clk = devm_clk_get(&pdev->dev, NULL);
ssp->irq = platform_get_irq(pdev, 0);
@@ -1482,14 +1506,6 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev)
return pdata;
}
-#else /* !CONFIG_PCI */
-static inline struct pxa2xx_spi_master *
-pxa2xx_spi_init_pdata(struct platform_device *pdev)
-{
- return NULL;
-}
-#endif
-
static int pxa2xx_spi_fw_translate_cs(struct spi_controller *master,
unsigned int cs)
{
@@ -1764,14 +1780,6 @@ static int pxa2xx_spi_remove(struct platform_device *pdev)
return 0;
}
-static void pxa2xx_spi_shutdown(struct platform_device *pdev)
-{
- int status = 0;
-
- if ((status = pxa2xx_spi_remove(pdev)) != 0)
- dev_err(&pdev->dev, "shutdown failed with %d\n", status);
-}
-
#ifdef CONFIG_PM_SLEEP
static int pxa2xx_spi_suspend(struct device *dev)
{
@@ -1808,13 +1816,7 @@ static int pxa2xx_spi_resume(struct device *dev)
lpss_ssp_setup(drv_data);
/* Start the queue running */
- status = spi_controller_resume(drv_data->master);
- if (status != 0) {
- dev_err(dev, "problem starting queue (%d)\n", status);
- return status;
- }
-
- return 0;
+ return spi_controller_resume(drv_data->master);
}
#endif
@@ -1848,10 +1850,10 @@ static struct platform_driver driver = {
.name = "pxa2xx-spi",
.pm = &pxa2xx_spi_pm_ops,
.acpi_match_table = ACPI_PTR(pxa2xx_spi_acpi_match),
+ .of_match_table = of_match_ptr(pxa2xx_spi_of_match),
},
.probe = pxa2xx_spi_probe,
.remove = pxa2xx_spi_remove,
- .shutdown = pxa2xx_spi_shutdown,
};
static int __init pxa2xx_spi_init(void)
diff --git a/drivers/spi/spi-qcom-qspi.c b/drivers/spi/spi-qcom-qspi.c
new file mode 100644
index 000000000000..b8163b40bb92
--- /dev/null
+++ b/drivers/spi/spi-qcom-qspi.c
@@ -0,0 +1,581 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2017-2018, The Linux foundation. All rights reserved.
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/pm_runtime.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi-mem.h>
+
+
+#define QSPI_NUM_CS 2
+#define QSPI_BYTES_PER_WORD 4
+
+#define MSTR_CONFIG 0x0000
+#define FULL_CYCLE_MODE BIT(3)
+#define FB_CLK_EN BIT(4)
+#define PIN_HOLDN BIT(6)
+#define PIN_WPN BIT(7)
+#define DMA_ENABLE BIT(8)
+#define BIG_ENDIAN_MODE BIT(9)
+#define SPI_MODE_MSK 0xc00
+#define SPI_MODE_SHFT 10
+#define CHIP_SELECT_NUM BIT(12)
+#define SBL_EN BIT(13)
+#define LPA_BASE_MSK 0x3c000
+#define LPA_BASE_SHFT 14
+#define TX_DATA_DELAY_MSK 0xc0000
+#define TX_DATA_DELAY_SHFT 18
+#define TX_CLK_DELAY_MSK 0x300000
+#define TX_CLK_DELAY_SHFT 20
+#define TX_CS_N_DELAY_MSK 0xc00000
+#define TX_CS_N_DELAY_SHFT 22
+#define TX_DATA_OE_DELAY_MSK 0x3000000
+#define TX_DATA_OE_DELAY_SHFT 24
+
+#define AHB_MASTER_CFG 0x0004
+#define HMEM_TYPE_START_MID_TRANS_MSK 0x7
+#define HMEM_TYPE_START_MID_TRANS_SHFT 0
+#define HMEM_TYPE_LAST_TRANS_MSK 0x38
+#define HMEM_TYPE_LAST_TRANS_SHFT 3
+#define USE_HMEMTYPE_LAST_ON_DESC_OR_CHAIN_MSK 0xc0
+#define USE_HMEMTYPE_LAST_ON_DESC_OR_CHAIN_SHFT 6
+#define HMEMTYPE_READ_TRANS_MSK 0x700
+#define HMEMTYPE_READ_TRANS_SHFT 8
+#define HSHARED BIT(11)
+#define HINNERSHARED BIT(12)
+
+#define MSTR_INT_EN 0x000C
+#define MSTR_INT_STATUS 0x0010
+#define RESP_FIFO_UNDERRUN BIT(0)
+#define RESP_FIFO_NOT_EMPTY BIT(1)
+#define RESP_FIFO_RDY BIT(2)
+#define HRESP_FROM_NOC_ERR BIT(3)
+#define WR_FIFO_EMPTY BIT(9)
+#define WR_FIFO_FULL BIT(10)
+#define WR_FIFO_OVERRUN BIT(11)
+#define TRANSACTION_DONE BIT(16)
+#define QSPI_ERR_IRQS (RESP_FIFO_UNDERRUN | HRESP_FROM_NOC_ERR | \
+ WR_FIFO_OVERRUN)
+#define QSPI_ALL_IRQS (QSPI_ERR_IRQS | RESP_FIFO_RDY | \
+ WR_FIFO_EMPTY | WR_FIFO_FULL | \
+ TRANSACTION_DONE)
+
+#define PIO_XFER_CTRL 0x0014
+#define REQUEST_COUNT_MSK 0xffff
+
+#define PIO_XFER_CFG 0x0018
+#define TRANSFER_DIRECTION BIT(0)
+#define MULTI_IO_MODE_MSK 0xe
+#define MULTI_IO_MODE_SHFT 1
+#define TRANSFER_FRAGMENT BIT(8)
+#define SDR_1BIT 1
+#define SDR_2BIT 2
+#define SDR_4BIT 3
+#define DDR_1BIT 5
+#define DDR_2BIT 6
+#define DDR_4BIT 7
+#define DMA_DESC_SINGLE_SPI 1
+#define DMA_DESC_DUAL_SPI 2
+#define DMA_DESC_QUAD_SPI 3
+
+#define PIO_XFER_STATUS 0x001c
+#define WR_FIFO_BYTES_MSK 0xffff0000
+#define WR_FIFO_BYTES_SHFT 16
+
+#define PIO_DATAOUT_1B 0x0020
+#define PIO_DATAOUT_4B 0x0024
+
+#define RD_FIFO_STATUS 0x002c
+#define FIFO_EMPTY BIT(11)
+#define WR_CNTS_MSK 0x7f0
+#define WR_CNTS_SHFT 4
+#define RDY_64BYTE BIT(3)
+#define RDY_32BYTE BIT(2)
+#define RDY_16BYTE BIT(1)
+#define FIFO_RDY BIT(0)
+
+#define RD_FIFO_CFG 0x0028
+#define CONTINUOUS_MODE BIT(0)
+
+#define RD_FIFO_RESET 0x0030
+#define RESET_FIFO BIT(0)
+
+#define CUR_MEM_ADDR 0x0048
+#define HW_VERSION 0x004c
+#define RD_FIFO 0x0050
+#define SAMPLING_CLK_CFG 0x0090
+#define SAMPLING_CLK_STATUS 0x0094
+
+
+enum qspi_dir {
+ QSPI_READ,
+ QSPI_WRITE,
+};
+
+struct qspi_xfer {
+ union {
+ const void *tx_buf;
+ void *rx_buf;
+ };
+ unsigned int rem_bytes;
+ unsigned int buswidth;
+ enum qspi_dir dir;
+ bool is_last;
+};
+
+enum qspi_clocks {
+ QSPI_CLK_CORE,
+ QSPI_CLK_IFACE,
+ QSPI_NUM_CLKS
+};
+
+struct qcom_qspi {
+ void __iomem *base;
+ struct device *dev;
+ struct clk_bulk_data clks[QSPI_NUM_CLKS];
+ struct qspi_xfer xfer;
+ /* Lock to protect data accessed by IRQs */
+ spinlock_t lock;
+};
+
+static u32 qspi_buswidth_to_iomode(struct qcom_qspi *ctrl,
+ unsigned int buswidth)
+{
+ switch (buswidth) {
+ case 1:
+ return SDR_1BIT << MULTI_IO_MODE_SHFT;
+ case 2:
+ return SDR_2BIT << MULTI_IO_MODE_SHFT;
+ case 4:
+ return SDR_4BIT << MULTI_IO_MODE_SHFT;
+ default:
+ dev_warn_once(ctrl->dev,
+ "Unexpected bus width: %u\n", buswidth);
+ return SDR_1BIT << MULTI_IO_MODE_SHFT;
+ }
+}
+
+static void qcom_qspi_pio_xfer_cfg(struct qcom_qspi *ctrl)
+{
+ u32 pio_xfer_cfg;
+ const struct qspi_xfer *xfer;
+
+ xfer = &ctrl->xfer;
+ pio_xfer_cfg = readl(ctrl->base + PIO_XFER_CFG);
+ pio_xfer_cfg &= ~TRANSFER_DIRECTION;
+ pio_xfer_cfg |= xfer->dir;
+ if (xfer->is_last)
+ pio_xfer_cfg &= ~TRANSFER_FRAGMENT;
+ else
+ pio_xfer_cfg |= TRANSFER_FRAGMENT;
+ pio_xfer_cfg &= ~MULTI_IO_MODE_MSK;
+ pio_xfer_cfg |= qspi_buswidth_to_iomode(ctrl, xfer->buswidth);
+
+ writel(pio_xfer_cfg, ctrl->base + PIO_XFER_CFG);
+}
+
+static void qcom_qspi_pio_xfer_ctrl(struct qcom_qspi *ctrl)
+{
+ u32 pio_xfer_ctrl;
+
+ pio_xfer_ctrl = readl(ctrl->base + PIO_XFER_CTRL);
+ pio_xfer_ctrl &= ~REQUEST_COUNT_MSK;
+ pio_xfer_ctrl |= ctrl->xfer.rem_bytes;
+ writel(pio_xfer_ctrl, ctrl->base + PIO_XFER_CTRL);
+}
+
+static void qcom_qspi_pio_xfer(struct qcom_qspi *ctrl)
+{
+ u32 ints;
+
+ qcom_qspi_pio_xfer_cfg(ctrl);
+
+ /* Ack any previous interrupts that might be hanging around */
+ writel(QSPI_ALL_IRQS, ctrl->base + MSTR_INT_STATUS);
+
+ /* Setup new interrupts */
+ if (ctrl->xfer.dir == QSPI_WRITE)
+ ints = QSPI_ERR_IRQS | WR_FIFO_EMPTY;
+ else
+ ints = QSPI_ERR_IRQS | RESP_FIFO_RDY;
+ writel(ints, ctrl->base + MSTR_INT_EN);
+
+ /* Kick off the transfer */
+ qcom_qspi_pio_xfer_ctrl(ctrl);
+}
+
+static void qcom_qspi_handle_err(struct spi_master *master,
+ struct spi_message *msg)
+{
+ struct qcom_qspi *ctrl = spi_master_get_devdata(master);
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctrl->lock, flags);
+ writel(0, ctrl->base + MSTR_INT_EN);
+ ctrl->xfer.rem_bytes = 0;
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+}
+
+static int qcom_qspi_transfer_one(struct spi_master *master,
+ struct spi_device *slv,
+ struct spi_transfer *xfer)
+{
+ struct qcom_qspi *ctrl = spi_master_get_devdata(master);
+ int ret;
+ unsigned long speed_hz;
+ unsigned long flags;
+
+ speed_hz = slv->max_speed_hz;
+ if (xfer->speed_hz)
+ speed_hz = xfer->speed_hz;
+
+ /* In regular operation (SBL_EN=1) core must be 4x transfer clock */
+ ret = clk_set_rate(ctrl->clks[QSPI_CLK_CORE].clk, speed_hz * 4);
+ if (ret) {
+ dev_err(ctrl->dev, "Failed to set core clk %d\n", ret);
+ return ret;
+ }
+
+ spin_lock_irqsave(&ctrl->lock, flags);
+
+ /* We are half duplex, so either rx or tx will be set */
+ if (xfer->rx_buf) {
+ ctrl->xfer.dir = QSPI_READ;
+ ctrl->xfer.buswidth = xfer->rx_nbits;
+ ctrl->xfer.rx_buf = xfer->rx_buf;
+ } else {
+ ctrl->xfer.dir = QSPI_WRITE;
+ ctrl->xfer.buswidth = xfer->tx_nbits;
+ ctrl->xfer.tx_buf = xfer->tx_buf;
+ }
+ ctrl->xfer.is_last = list_is_last(&xfer->transfer_list,
+ &master->cur_msg->transfers);
+ ctrl->xfer.rem_bytes = xfer->len;
+ qcom_qspi_pio_xfer(ctrl);
+
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+
+ /* We'll call spi_finalize_current_transfer() when done */
+ return 1;
+}
+
+static int qcom_qspi_prepare_message(struct spi_master *master,
+ struct spi_message *message)
+{
+ u32 mstr_cfg;
+ struct qcom_qspi *ctrl;
+ int tx_data_oe_delay = 1;
+ int tx_data_delay = 1;
+ unsigned long flags;
+
+ ctrl = spi_master_get_devdata(master);
+ spin_lock_irqsave(&ctrl->lock, flags);
+
+ mstr_cfg = readl(ctrl->base + MSTR_CONFIG);
+ mstr_cfg &= ~CHIP_SELECT_NUM;
+ if (message->spi->chip_select)
+ mstr_cfg |= CHIP_SELECT_NUM;
+
+ mstr_cfg |= FB_CLK_EN | PIN_WPN | PIN_HOLDN | SBL_EN | FULL_CYCLE_MODE;
+ mstr_cfg &= ~(SPI_MODE_MSK | TX_DATA_OE_DELAY_MSK | TX_DATA_DELAY_MSK);
+ mstr_cfg |= message->spi->mode << SPI_MODE_SHFT;
+ mstr_cfg |= tx_data_oe_delay << TX_DATA_OE_DELAY_SHFT;
+ mstr_cfg |= tx_data_delay << TX_DATA_DELAY_SHFT;
+ mstr_cfg &= ~DMA_ENABLE;
+
+ writel(mstr_cfg, ctrl->base + MSTR_CONFIG);
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+
+ return 0;
+}
+
+static irqreturn_t pio_read(struct qcom_qspi *ctrl)
+{
+ u32 rd_fifo_status;
+ u32 rd_fifo;
+ unsigned int wr_cnts;
+ unsigned int bytes_to_read;
+ unsigned int words_to_read;
+ u32 *word_buf;
+ u8 *byte_buf;
+ int i;
+
+ rd_fifo_status = readl(ctrl->base + RD_FIFO_STATUS);
+
+ if (!(rd_fifo_status & FIFO_RDY)) {
+ dev_dbg(ctrl->dev, "Spurious IRQ %#x\n", rd_fifo_status);
+ return IRQ_NONE;
+ }
+
+ wr_cnts = (rd_fifo_status & WR_CNTS_MSK) >> WR_CNTS_SHFT;
+ wr_cnts = min(wr_cnts, ctrl->xfer.rem_bytes);
+
+ words_to_read = wr_cnts / QSPI_BYTES_PER_WORD;
+ bytes_to_read = wr_cnts % QSPI_BYTES_PER_WORD;
+
+ if (words_to_read) {
+ word_buf = ctrl->xfer.rx_buf;
+ ctrl->xfer.rem_bytes -= words_to_read * QSPI_BYTES_PER_WORD;
+ ioread32_rep(ctrl->base + RD_FIFO, word_buf, words_to_read);
+ ctrl->xfer.rx_buf = word_buf + words_to_read;
+ }
+
+ if (bytes_to_read) {
+ byte_buf = ctrl->xfer.rx_buf;
+ rd_fifo = readl(ctrl->base + RD_FIFO);
+ ctrl->xfer.rem_bytes -= bytes_to_read;
+ for (i = 0; i < bytes_to_read; i++)
+ *byte_buf++ = rd_fifo >> (i * BITS_PER_BYTE);
+ ctrl->xfer.rx_buf = byte_buf;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t pio_write(struct qcom_qspi *ctrl)
+{
+ const void *xfer_buf = ctrl->xfer.tx_buf;
+ const int *word_buf;
+ const char *byte_buf;
+ unsigned int wr_fifo_bytes;
+ unsigned int wr_fifo_words;
+ unsigned int wr_size;
+ unsigned int rem_words;
+
+ wr_fifo_bytes = readl(ctrl->base + PIO_XFER_STATUS);
+ wr_fifo_bytes >>= WR_FIFO_BYTES_SHFT;
+
+ if (ctrl->xfer.rem_bytes < QSPI_BYTES_PER_WORD) {
+ /* Process the last 1-3 bytes */
+ wr_size = min(wr_fifo_bytes, ctrl->xfer.rem_bytes);
+ ctrl->xfer.rem_bytes -= wr_size;
+
+ byte_buf = xfer_buf;
+ while (wr_size--)
+ writel(*byte_buf++,
+ ctrl->base + PIO_DATAOUT_1B);
+ ctrl->xfer.tx_buf = byte_buf;
+ } else {
+ /*
+ * Process all the whole words; to keep things simple we'll
+ * just wait for the next interrupt to handle the last 1-3
+ * bytes if we don't have an even number of words.
+ */
+ rem_words = ctrl->xfer.rem_bytes / QSPI_BYTES_PER_WORD;
+ wr_fifo_words = wr_fifo_bytes / QSPI_BYTES_PER_WORD;
+
+ wr_size = min(rem_words, wr_fifo_words);
+ ctrl->xfer.rem_bytes -= wr_size * QSPI_BYTES_PER_WORD;
+
+ word_buf = xfer_buf;
+ iowrite32_rep(ctrl->base + PIO_DATAOUT_4B, word_buf, wr_size);
+ ctrl->xfer.tx_buf = word_buf + wr_size;
+
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t qcom_qspi_irq(int irq, void *dev_id)
+{
+ u32 int_status;
+ struct qcom_qspi *ctrl = dev_id;
+ irqreturn_t ret = IRQ_NONE;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctrl->lock, flags);
+
+ int_status = readl(ctrl->base + MSTR_INT_STATUS);
+ writel(int_status, ctrl->base + MSTR_INT_STATUS);
+
+ if (ctrl->xfer.dir == QSPI_WRITE) {
+ if (int_status & WR_FIFO_EMPTY)
+ ret = pio_write(ctrl);
+ } else {
+ if (int_status & RESP_FIFO_RDY)
+ ret = pio_read(ctrl);
+ }
+
+ if (int_status & QSPI_ERR_IRQS) {
+ if (int_status & RESP_FIFO_UNDERRUN)
+ dev_err(ctrl->dev, "IRQ error: FIFO underrun\n");
+ if (int_status & WR_FIFO_OVERRUN)
+ dev_err(ctrl->dev, "IRQ error: FIFO overrun\n");
+ if (int_status & HRESP_FROM_NOC_ERR)
+ dev_err(ctrl->dev, "IRQ error: NOC response error\n");
+ ret = IRQ_HANDLED;
+ }
+
+ if (!ctrl->xfer.rem_bytes) {
+ writel(0, ctrl->base + MSTR_INT_EN);
+ spi_finalize_current_transfer(dev_get_drvdata(ctrl->dev));
+ }
+
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+ return ret;
+}
+
+static int qcom_qspi_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct device *dev;
+ struct resource *res;
+ struct spi_master *master;
+ struct qcom_qspi *ctrl;
+
+ dev = &pdev->dev;
+
+ master = spi_alloc_master(dev, sizeof(*ctrl));
+ if (!master)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, master);
+
+ ctrl = spi_master_get_devdata(master);
+
+ spin_lock_init(&ctrl->lock);
+ ctrl->dev = dev;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ ctrl->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(ctrl->base)) {
+ ret = PTR_ERR(ctrl->base);
+ goto exit_probe_master_put;
+ }
+
+ ctrl->clks[QSPI_CLK_CORE].id = "core";
+ ctrl->clks[QSPI_CLK_IFACE].id = "iface";
+ ret = devm_clk_bulk_get(dev, QSPI_NUM_CLKS, ctrl->clks);
+ if (ret)
+ goto exit_probe_master_put;
+
+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0) {
+ dev_err(dev, "Failed to get irq %d\n", ret);
+ goto exit_probe_master_put;
+ }
+ ret = devm_request_irq(dev, ret, qcom_qspi_irq,
+ IRQF_TRIGGER_HIGH, dev_name(dev), ctrl);
+ if (ret) {
+ dev_err(dev, "Failed to request irq %d\n", ret);
+ goto exit_probe_master_put;
+ }
+
+ master->max_speed_hz = 300000000;
+ master->num_chipselect = QSPI_NUM_CS;
+ master->bus_num = -1;
+ master->dev.of_node = pdev->dev.of_node;
+ master->mode_bits = SPI_MODE_0 |
+ SPI_TX_DUAL | SPI_RX_DUAL |
+ SPI_TX_QUAD | SPI_RX_QUAD;
+ master->flags = SPI_MASTER_HALF_DUPLEX;
+ master->prepare_message = qcom_qspi_prepare_message;
+ master->transfer_one = qcom_qspi_transfer_one;
+ master->handle_err = qcom_qspi_handle_err;
+ master->auto_runtime_pm = true;
+
+ pm_runtime_enable(dev);
+
+ ret = spi_register_master(master);
+ if (!ret)
+ return 0;
+
+ pm_runtime_disable(dev);
+
+exit_probe_master_put:
+ spi_master_put(master);
+
+ return ret;
+}
+
+static int qcom_qspi_remove(struct platform_device *pdev)
+{
+ struct spi_master *master = platform_get_drvdata(pdev);
+
+ /* Unregister _before_ disabling pm_runtime() so we stop transfers */
+ spi_unregister_master(master);
+
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+static int __maybe_unused qcom_qspi_runtime_suspend(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct qcom_qspi *ctrl = spi_master_get_devdata(master);
+
+ clk_bulk_disable_unprepare(QSPI_NUM_CLKS, ctrl->clks);
+
+ return 0;
+}
+
+static int __maybe_unused qcom_qspi_runtime_resume(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct qcom_qspi *ctrl = spi_master_get_devdata(master);
+
+ return clk_bulk_prepare_enable(QSPI_NUM_CLKS, ctrl->clks);
+}
+
+static int __maybe_unused qcom_qspi_suspend(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ int ret;
+
+ ret = spi_master_suspend(master);
+ if (ret)
+ return ret;
+
+ ret = pm_runtime_force_suspend(dev);
+ if (ret)
+ spi_master_resume(master);
+
+ return ret;
+}
+
+static int __maybe_unused qcom_qspi_resume(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ int ret;
+
+ ret = pm_runtime_force_resume(dev);
+ if (ret)
+ return ret;
+
+ ret = spi_master_resume(master);
+ if (ret)
+ pm_runtime_force_suspend(dev);
+
+ return ret;
+}
+
+static const struct dev_pm_ops qcom_qspi_dev_pm_ops = {
+ SET_RUNTIME_PM_OPS(qcom_qspi_runtime_suspend,
+ qcom_qspi_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(qcom_qspi_suspend, qcom_qspi_resume)
+};
+
+static const struct of_device_id qcom_qspi_dt_match[] = {
+ { .compatible = "qcom,qspi-v1", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, qcom_qspi_dt_match);
+
+static struct platform_driver qcom_qspi_driver = {
+ .driver = {
+ .name = "qcom_qspi",
+ .pm = &qcom_qspi_dev_pm_ops,
+ .of_match_table = qcom_qspi_dt_match,
+ },
+ .probe = qcom_qspi_probe,
+ .remove = qcom_qspi_remove,
+};
+module_platform_driver(qcom_qspi_driver);
+
+MODULE_DESCRIPTION("SPI driver for QSPI cores");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/spi/spi-rb4xx.c b/drivers/spi/spi-rb4xx.c
index 3641d0e20135..fbbf9a188247 100644
--- a/drivers/spi/spi-rb4xx.c
+++ b/drivers/spi/spi-rb4xx.c
@@ -159,7 +159,7 @@ static int rb4xx_spi_probe(struct platform_device *pdev)
master->bus_num = 0;
master->num_chipselect = 3;
master->mode_bits = SPI_TX_DUAL;
- master->bits_per_word_mask = BIT(7);
+ master->bits_per_word_mask = SPI_BPW_MASK(8);
master->flags = SPI_MASTER_MUST_TX;
master->transfer_one = rb4xx_transfer_one;
master->set_cs = rb4xx_set_cs;
diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index fdcf3076681b..51ef632bca52 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -164,7 +164,6 @@ enum rockchip_ssi_type {
struct rockchip_spi_dma_data {
struct dma_chan *ch;
- enum dma_transfer_direction direction;
dma_addr_t addr;
};
@@ -202,12 +201,11 @@ struct rockchip_spi {
bool cs_asserted[ROCKCHIP_SPI_MAX_CS_NUM];
- u32 use_dma;
+ bool use_dma;
struct sg_table tx_sg;
struct sg_table rx_sg;
struct rockchip_spi_dma_data dma_rx;
struct rockchip_spi_dma_data dma_tx;
- struct dma_slave_caps dma_caps;
};
static inline void spi_enable_chip(struct rockchip_spi *rs, int enable)
@@ -381,6 +379,8 @@ static int rockchip_spi_pio_transfer(struct rockchip_spi *rs)
{
int remain = 0;
+ spi_enable_chip(rs, 1);
+
do {
if (rs->tx) {
remain = rs->tx_end - rs->tx;
@@ -445,6 +445,9 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)
struct dma_slave_config rxconf, txconf;
struct dma_async_tx_descriptor *rxdesc, *txdesc;
+ memset(&rxconf, 0, sizeof(rxconf));
+ memset(&txconf, 0, sizeof(txconf));
+
spin_lock_irqsave(&rs->lock, flags);
rs->state &= ~RXBUSY;
rs->state &= ~TXBUSY;
@@ -452,19 +455,16 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)
rxdesc = NULL;
if (rs->rx) {
- rxconf.direction = rs->dma_rx.direction;
+ rxconf.direction = DMA_DEV_TO_MEM;
rxconf.src_addr = rs->dma_rx.addr;
rxconf.src_addr_width = rs->n_bytes;
- if (rs->dma_caps.max_burst > 4)
- rxconf.src_maxburst = 4;
- else
- rxconf.src_maxburst = 1;
+ rxconf.src_maxburst = 1;
dmaengine_slave_config(rs->dma_rx.ch, &rxconf);
rxdesc = dmaengine_prep_slave_sg(
rs->dma_rx.ch,
rs->rx_sg.sgl, rs->rx_sg.nents,
- rs->dma_rx.direction, DMA_PREP_INTERRUPT);
+ DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
if (!rxdesc)
return -EINVAL;
@@ -474,19 +474,16 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)
txdesc = NULL;
if (rs->tx) {
- txconf.direction = rs->dma_tx.direction;
+ txconf.direction = DMA_MEM_TO_DEV;
txconf.dst_addr = rs->dma_tx.addr;
txconf.dst_addr_width = rs->n_bytes;
- if (rs->dma_caps.max_burst > 4)
- txconf.dst_maxburst = 4;
- else
- txconf.dst_maxburst = 1;
+ txconf.dst_maxburst = rs->fifo_len / 2;
dmaengine_slave_config(rs->dma_tx.ch, &txconf);
txdesc = dmaengine_prep_slave_sg(
rs->dma_tx.ch,
rs->tx_sg.sgl, rs->tx_sg.nents,
- rs->dma_tx.direction, DMA_PREP_INTERRUPT);
+ DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
if (!txdesc) {
if (rxdesc)
dmaengine_terminate_sync(rs->dma_rx.ch);
@@ -506,6 +503,8 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)
dma_async_issue_pending(rs->dma_rx.ch);
}
+ spi_enable_chip(rs, 1);
+
if (txdesc) {
spin_lock_irqsave(&rs->lock, flags);
rs->state |= TXBUSY;
@@ -514,7 +513,8 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)
dma_async_issue_pending(rs->dma_tx.ch);
}
- return 0;
+ /* 1 means the transfer is in progress */
+ return 1;
}
static void rockchip_spi_config(struct rockchip_spi *rs)
@@ -578,7 +578,7 @@ static void rockchip_spi_config(struct rockchip_spi *rs)
writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_TXFTLR);
writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_RXFTLR);
- writel_relaxed(0, rs->regs + ROCKCHIP_SPI_DMATDLR);
+ writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_DMATDLR);
writel_relaxed(0, rs->regs + ROCKCHIP_SPI_DMARDLR);
writel_relaxed(dmacr, rs->regs + ROCKCHIP_SPI_DMACR);
@@ -597,7 +597,6 @@ static int rockchip_spi_transfer_one(
struct spi_device *spi,
struct spi_transfer *xfer)
{
- int ret = 0;
struct rockchip_spi *rs = spi_master_get_devdata(master);
WARN_ON(readl_relaxed(rs->regs + ROCKCHIP_SPI_SSIENR) &&
@@ -635,30 +634,16 @@ static int rockchip_spi_transfer_one(
/* we need prepare dma before spi was enabled */
if (master->can_dma && master->can_dma(master, spi, xfer))
- rs->use_dma = 1;
+ rs->use_dma = true;
else
- rs->use_dma = 0;
+ rs->use_dma = false;
rockchip_spi_config(rs);
- if (rs->use_dma) {
- if (rs->tmode == CR0_XFM_RO) {
- /* rx: dma must be prepared first */
- ret = rockchip_spi_prepare_dma(rs);
- spi_enable_chip(rs, 1);
- } else {
- /* tx or tr: spi must be enabled first */
- spi_enable_chip(rs, 1);
- ret = rockchip_spi_prepare_dma(rs);
- }
- /* successful DMA prepare means the transfer is in progress */
- ret = ret ? ret : 1;
- } else {
- spi_enable_chip(rs, 1);
- ret = rockchip_spi_pio_transfer(rs);
- }
+ if (rs->use_dma)
+ return rockchip_spi_prepare_dma(rs);
- return ret;
+ return rockchip_spi_pio_transfer(rs);
}
static bool rockchip_spi_can_dma(struct spi_master *master,
@@ -780,11 +765,8 @@ static int rockchip_spi_probe(struct platform_device *pdev)
}
if (rs->dma_tx.ch && rs->dma_rx.ch) {
- dma_get_slave_caps(rs->dma_rx.ch, &(rs->dma_caps));
rs->dma_tx.addr = (dma_addr_t)(mem->start + ROCKCHIP_SPI_TXDR);
rs->dma_rx.addr = (dma_addr_t)(mem->start + ROCKCHIP_SPI_RXDR);
- rs->dma_tx.direction = DMA_MEM_TO_DEV;
- rs->dma_rx.direction = DMA_DEV_TO_MEM;
master->can_dma = rockchip_spi_can_dma;
master->dma_tx = rs->dma_tx.ch;
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c
index b37de1d991d6..55f8e55327b3 100644
--- a/drivers/spi/spi-rspi.c
+++ b/drivers/spi/spi-rspi.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* SH RSPI driver
*
@@ -6,15 +7,6 @@
*
* Based on spi-sh.c:
* Copyright (C) 2011 Renesas Solutions Corp.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/module.h>
diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c
index 20e800e70442..dc0926e43665 100644
--- a/drivers/spi/spi-sh-hspi.c
+++ b/drivers/spi/spi-sh-hspi.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* SuperH HSPI bus driver
*
@@ -7,15 +8,6 @@
* Based on pxa2xx_spi.c:
* Copyright (C) 2011 Renesas Solutions Corp.
* Copyright (C) 2005 Stephen Street / StreetFire Sound Labs
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/clk.h>
@@ -316,6 +308,6 @@ static struct platform_driver hspi_driver = {
module_platform_driver(hspi_driver);
MODULE_DESCRIPTION("SuperH HSPI bus driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
MODULE_ALIAS("platform:sh-hspi");
diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c
index 101cd6aae2ea..adf384323934 100644
--- a/drivers/spi/spi-sh-msiof.c
+++ b/drivers/spi/spi-sh-msiof.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* SuperH MSIOF SPI Master Interface
*
* Copyright (c) 2009 Magnus Damm
* Copyright (C) 2014 Renesas Electronics Corporation
* Copyright (C) 2014-2017 Glider bvba
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
*/
#include <linux/bitmap.h>
@@ -1343,8 +1339,8 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
i = platform_get_irq(pdev, 0);
if (i < 0) {
- dev_err(&pdev->dev, "cannot get platform IRQ\n");
- ret = -ENOENT;
+ dev_err(&pdev->dev, "cannot get IRQ\n");
+ ret = i;
goto err1;
}
diff --git a/drivers/spi/spi-sh.c b/drivers/spi/spi-sh.c
index 50e0ea9acf8b..f1ee58208216 100644
--- a/drivers/spi/spi-sh.c
+++ b/drivers/spi/spi-sh.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* SH SPI bus driver
*
@@ -5,15 +6,6 @@
*
* Based on pxa2xx_spi.c:
* Copyright (C) 2005 Stephen Street / StreetFire Sound Labs
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/module.h>
@@ -522,6 +514,6 @@ static struct platform_driver spi_sh_driver = {
module_platform_driver(spi_sh_driver);
MODULE_DESCRIPTION("SH SPI bus driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Yoshihiro Shimoda");
MODULE_ALIAS("platform:sh_spi");
diff --git a/drivers/spi/spi-slave-mt27xx.c b/drivers/spi/spi-slave-mt27xx.c
new file mode 100644
index 000000000000..d1075433f6a6
--- /dev/null
+++ b/drivers/spi/spi-slave-mt27xx.c
@@ -0,0 +1,554 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Copyright (c) 2018 MediaTek Inc.
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/spi/spi.h>
+
+#define SPIS_IRQ_EN_REG 0x0
+#define SPIS_IRQ_CLR_REG 0x4
+#define SPIS_IRQ_ST_REG 0x8
+#define SPIS_IRQ_MASK_REG 0xc
+#define SPIS_CFG_REG 0x10
+#define SPIS_RX_DATA_REG 0x14
+#define SPIS_TX_DATA_REG 0x18
+#define SPIS_RX_DST_REG 0x1c
+#define SPIS_TX_SRC_REG 0x20
+#define SPIS_DMA_CFG_REG 0x30
+#define SPIS_SOFT_RST_REG 0x40
+
+/* SPIS_IRQ_EN_REG */
+#define DMA_DONE_EN BIT(7)
+#define DATA_DONE_EN BIT(2)
+#define RSTA_DONE_EN BIT(1)
+#define CMD_INVALID_EN BIT(0)
+
+/* SPIS_IRQ_ST_REG */
+#define DMA_DONE_ST BIT(7)
+#define DATA_DONE_ST BIT(2)
+#define RSTA_DONE_ST BIT(1)
+#define CMD_INVALID_ST BIT(0)
+
+/* SPIS_IRQ_MASK_REG */
+#define DMA_DONE_MASK BIT(7)
+#define DATA_DONE_MASK BIT(2)
+#define RSTA_DONE_MASK BIT(1)
+#define CMD_INVALID_MASK BIT(0)
+
+/* SPIS_CFG_REG */
+#define SPIS_TX_ENDIAN BIT(7)
+#define SPIS_RX_ENDIAN BIT(6)
+#define SPIS_TXMSBF BIT(5)
+#define SPIS_RXMSBF BIT(4)
+#define SPIS_CPHA BIT(3)
+#define SPIS_CPOL BIT(2)
+#define SPIS_TX_EN BIT(1)
+#define SPIS_RX_EN BIT(0)
+
+/* SPIS_DMA_CFG_REG */
+#define TX_DMA_TRIG_EN BIT(31)
+#define TX_DMA_EN BIT(30)
+#define RX_DMA_EN BIT(29)
+#define TX_DMA_LEN 0xfffff
+
+/* SPIS_SOFT_RST_REG */
+#define SPIS_DMA_ADDR_EN BIT(1)
+#define SPIS_SOFT_RST BIT(0)
+
+#define MTK_SPI_SLAVE_MAX_FIFO_SIZE 512U
+
+struct mtk_spi_slave {
+ struct device *dev;
+ void __iomem *base;
+ struct clk *spi_clk;
+ struct completion xfer_done;
+ struct spi_transfer *cur_transfer;
+ bool slave_aborted;
+};
+
+static const struct of_device_id mtk_spi_slave_of_match[] = {
+ { .compatible = "mediatek,mt2712-spi-slave", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, mtk_spi_slave_of_match);
+
+static void mtk_spi_slave_disable_dma(struct mtk_spi_slave *mdata)
+{
+ u32 reg_val;
+
+ reg_val = readl(mdata->base + SPIS_DMA_CFG_REG);
+ reg_val &= ~RX_DMA_EN;
+ reg_val &= ~TX_DMA_EN;
+ writel(reg_val, mdata->base + SPIS_DMA_CFG_REG);
+}
+
+static void mtk_spi_slave_disable_xfer(struct mtk_spi_slave *mdata)
+{
+ u32 reg_val;
+
+ reg_val = readl(mdata->base + SPIS_CFG_REG);
+ reg_val &= ~SPIS_TX_EN;
+ reg_val &= ~SPIS_RX_EN;
+ writel(reg_val, mdata->base + SPIS_CFG_REG);
+}
+
+static int mtk_spi_slave_wait_for_completion(struct mtk_spi_slave *mdata)
+{
+ if (wait_for_completion_interruptible(&mdata->xfer_done) ||
+ mdata->slave_aborted) {
+ dev_err(mdata->dev, "interrupted\n");
+ return -EINTR;
+ }
+
+ return 0;
+}
+
+static int mtk_spi_slave_prepare_message(struct spi_controller *ctlr,
+ struct spi_message *msg)
+{
+ struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr);
+ struct spi_device *spi = msg->spi;
+ bool cpha, cpol;
+ u32 reg_val;
+
+ cpha = spi->mode & SPI_CPHA ? 1 : 0;
+ cpol = spi->mode & SPI_CPOL ? 1 : 0;
+
+ reg_val = readl(mdata->base + SPIS_CFG_REG);
+ if (cpha)
+ reg_val |= SPIS_CPHA;
+ else
+ reg_val &= ~SPIS_CPHA;
+ if (cpol)
+ reg_val |= SPIS_CPOL;
+ else
+ reg_val &= ~SPIS_CPOL;
+
+ if (spi->mode & SPI_LSB_FIRST)
+ reg_val &= ~(SPIS_TXMSBF | SPIS_RXMSBF);
+ else
+ reg_val |= SPIS_TXMSBF | SPIS_RXMSBF;
+
+ reg_val &= ~SPIS_TX_ENDIAN;
+ reg_val &= ~SPIS_RX_ENDIAN;
+ writel(reg_val, mdata->base + SPIS_CFG_REG);
+
+ return 0;
+}
+
+static int mtk_spi_slave_fifo_transfer(struct spi_controller *ctlr,
+ struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr);
+ int reg_val, cnt, remainder, ret;
+
+ writel(SPIS_SOFT_RST, mdata->base + SPIS_SOFT_RST_REG);
+
+ reg_val = readl(mdata->base + SPIS_CFG_REG);
+ if (xfer->rx_buf)
+ reg_val |= SPIS_RX_EN;
+ if (xfer->tx_buf)
+ reg_val |= SPIS_TX_EN;
+ writel(reg_val, mdata->base + SPIS_CFG_REG);
+
+ cnt = xfer->len / 4;
+ if (xfer->tx_buf)
+ iowrite32_rep(mdata->base + SPIS_TX_DATA_REG,
+ xfer->tx_buf, cnt);
+
+ remainder = xfer->len % 4;
+ if (xfer->tx_buf && remainder > 0) {
+ reg_val = 0;
+ memcpy(&reg_val, xfer->tx_buf + cnt * 4, remainder);
+ writel(reg_val, mdata->base + SPIS_TX_DATA_REG);
+ }
+
+ ret = mtk_spi_slave_wait_for_completion(mdata);
+ if (ret) {
+ mtk_spi_slave_disable_xfer(mdata);
+ writel(SPIS_SOFT_RST, mdata->base + SPIS_SOFT_RST_REG);
+ }
+
+ return ret;
+}
+
+static int mtk_spi_slave_dma_transfer(struct spi_controller *ctlr,
+ struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr);
+ struct device *dev = mdata->dev;
+ int reg_val, ret;
+
+ writel(SPIS_SOFT_RST, mdata->base + SPIS_SOFT_RST_REG);
+
+ if (xfer->tx_buf) {
+ /* tx_buf is a const void* where we need a void * for
+ * the dma mapping
+ */
+ void *nonconst_tx = (void *)xfer->tx_buf;
+
+ xfer->tx_dma = dma_map_single(dev, nonconst_tx,
+ xfer->len, DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, xfer->tx_dma)) {
+ ret = -ENOMEM;
+ goto disable_transfer;
+ }
+ }
+
+ if (xfer->rx_buf) {
+ xfer->rx_dma = dma_map_single(dev, xfer->rx_buf,
+ xfer->len, DMA_FROM_DEVICE);
+ if (dma_mapping_error(dev, xfer->rx_dma)) {
+ ret = -ENOMEM;
+ goto unmap_txdma;
+ }
+ }
+
+ writel(xfer->tx_dma, mdata->base + SPIS_TX_SRC_REG);
+ writel(xfer->rx_dma, mdata->base + SPIS_RX_DST_REG);
+
+ writel(SPIS_DMA_ADDR_EN, mdata->base + SPIS_SOFT_RST_REG);
+
+ /* enable config reg tx rx_enable */
+ reg_val = readl(mdata->base + SPIS_CFG_REG);
+ if (xfer->tx_buf)
+ reg_val |= SPIS_TX_EN;
+ if (xfer->rx_buf)
+ reg_val |= SPIS_RX_EN;
+ writel(reg_val, mdata->base + SPIS_CFG_REG);
+
+ /* config dma */
+ reg_val = 0;
+ reg_val |= (xfer->len - 1) & TX_DMA_LEN;
+ writel(reg_val, mdata->base + SPIS_DMA_CFG_REG);
+
+ reg_val = readl(mdata->base + SPIS_DMA_CFG_REG);
+ if (xfer->tx_buf)
+ reg_val |= TX_DMA_EN;
+ if (xfer->rx_buf)
+ reg_val |= RX_DMA_EN;
+ reg_val |= TX_DMA_TRIG_EN;
+ writel(reg_val, mdata->base + SPIS_DMA_CFG_REG);
+
+ ret = mtk_spi_slave_wait_for_completion(mdata);
+ if (ret)
+ goto unmap_rxdma;
+
+ return 0;
+
+unmap_rxdma:
+ if (xfer->rx_buf)
+ dma_unmap_single(dev, xfer->rx_dma,
+ xfer->len, DMA_FROM_DEVICE);
+
+unmap_txdma:
+ if (xfer->tx_buf)
+ dma_unmap_single(dev, xfer->tx_dma,
+ xfer->len, DMA_TO_DEVICE);
+
+disable_transfer:
+ mtk_spi_slave_disable_dma(mdata);
+ mtk_spi_slave_disable_xfer(mdata);
+ writel(SPIS_SOFT_RST, mdata->base + SPIS_SOFT_RST_REG);
+
+ return ret;
+}
+
+static int mtk_spi_slave_transfer_one(struct spi_controller *ctlr,
+ struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr);
+
+ reinit_completion(&mdata->xfer_done);
+ mdata->slave_aborted = false;
+ mdata->cur_transfer = xfer;
+
+ if (xfer->len > MTK_SPI_SLAVE_MAX_FIFO_SIZE)
+ return mtk_spi_slave_dma_transfer(ctlr, spi, xfer);
+ else
+ return mtk_spi_slave_fifo_transfer(ctlr, spi, xfer);
+}
+
+static int mtk_spi_slave_setup(struct spi_device *spi)
+{
+ struct mtk_spi_slave *mdata = spi_controller_get_devdata(spi->master);
+ u32 reg_val;
+
+ reg_val = DMA_DONE_EN | DATA_DONE_EN |
+ RSTA_DONE_EN | CMD_INVALID_EN;
+ writel(reg_val, mdata->base + SPIS_IRQ_EN_REG);
+
+ reg_val = DMA_DONE_MASK | DATA_DONE_MASK |
+ RSTA_DONE_MASK | CMD_INVALID_MASK;
+ writel(reg_val, mdata->base + SPIS_IRQ_MASK_REG);
+
+ mtk_spi_slave_disable_dma(mdata);
+ mtk_spi_slave_disable_xfer(mdata);
+
+ return 0;
+}
+
+static int mtk_slave_abort(struct spi_controller *ctlr)
+{
+ struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr);
+
+ mdata->slave_aborted = true;
+ complete(&mdata->xfer_done);
+
+ return 0;
+}
+
+static irqreturn_t mtk_spi_slave_interrupt(int irq, void *dev_id)
+{
+ struct spi_controller *ctlr = dev_id;
+ struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr);
+ struct spi_transfer *trans = mdata->cur_transfer;
+ u32 int_status, reg_val, cnt, remainder;
+
+ int_status = readl(mdata->base + SPIS_IRQ_ST_REG);
+ writel(int_status, mdata->base + SPIS_IRQ_CLR_REG);
+
+ if (!trans)
+ return IRQ_NONE;
+
+ if ((int_status & DMA_DONE_ST) &&
+ ((int_status & DATA_DONE_ST) ||
+ (int_status & RSTA_DONE_ST))) {
+ writel(SPIS_SOFT_RST, mdata->base + SPIS_SOFT_RST_REG);
+
+ if (trans->tx_buf)
+ dma_unmap_single(mdata->dev, trans->tx_dma,
+ trans->len, DMA_TO_DEVICE);
+ if (trans->rx_buf)
+ dma_unmap_single(mdata->dev, trans->rx_dma,
+ trans->len, DMA_FROM_DEVICE);
+
+ mtk_spi_slave_disable_dma(mdata);
+ mtk_spi_slave_disable_xfer(mdata);
+ }
+
+ if ((!(int_status & DMA_DONE_ST)) &&
+ ((int_status & DATA_DONE_ST) ||
+ (int_status & RSTA_DONE_ST))) {
+ cnt = trans->len / 4;
+ if (trans->rx_buf)
+ ioread32_rep(mdata->base + SPIS_RX_DATA_REG,
+ trans->rx_buf, cnt);
+ remainder = trans->len % 4;
+ if (trans->rx_buf && remainder > 0) {
+ reg_val = readl(mdata->base + SPIS_RX_DATA_REG);
+ memcpy(trans->rx_buf + (cnt * 4),
+ &reg_val, remainder);
+ }
+
+ mtk_spi_slave_disable_xfer(mdata);
+ }
+
+ if (int_status & CMD_INVALID_ST) {
+ dev_warn(&ctlr->dev, "cmd invalid\n");
+ return IRQ_NONE;
+ }
+
+ mdata->cur_transfer = NULL;
+ complete(&mdata->xfer_done);
+
+ return IRQ_HANDLED;
+}
+
+static int mtk_spi_slave_probe(struct platform_device *pdev)
+{
+ struct spi_controller *ctlr;
+ struct mtk_spi_slave *mdata;
+ struct resource *res;
+ int irq, ret;
+
+ ctlr = spi_alloc_slave(&pdev->dev, sizeof(*mdata));
+ if (!ctlr) {
+ dev_err(&pdev->dev, "failed to alloc spi slave\n");
+ return -ENOMEM;
+ }
+
+ ctlr->auto_runtime_pm = true;
+ ctlr->dev.of_node = pdev->dev.of_node;
+ ctlr->mode_bits = SPI_CPOL | SPI_CPHA;
+ ctlr->mode_bits |= SPI_LSB_FIRST;
+
+ ctlr->prepare_message = mtk_spi_slave_prepare_message;
+ ctlr->transfer_one = mtk_spi_slave_transfer_one;
+ ctlr->setup = mtk_spi_slave_setup;
+ ctlr->slave_abort = mtk_slave_abort;
+
+ mdata = spi_controller_get_devdata(ctlr);
+
+ platform_set_drvdata(pdev, ctlr);
+
+ init_completion(&mdata->xfer_done);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ ret = -ENODEV;
+ dev_err(&pdev->dev, "failed to determine base address\n");
+ goto err_put_ctlr;
+ }
+
+ mdata->dev = &pdev->dev;
+
+ mdata->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mdata->base)) {
+ ret = PTR_ERR(mdata->base);
+ goto err_put_ctlr;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "failed to get irq (%d)\n", irq);
+ ret = irq;
+ goto err_put_ctlr;
+ }
+
+ ret = devm_request_irq(&pdev->dev, irq, mtk_spi_slave_interrupt,
+ IRQF_TRIGGER_NONE, dev_name(&pdev->dev), ctlr);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register irq (%d)\n", ret);
+ goto err_put_ctlr;
+ }
+
+ mdata->spi_clk = devm_clk_get(&pdev->dev, "spi");
+ if (IS_ERR(mdata->spi_clk)) {
+ ret = PTR_ERR(mdata->spi_clk);
+ dev_err(&pdev->dev, "failed to get spi-clk: %d\n", ret);
+ goto err_put_ctlr;
+ }
+
+ ret = clk_prepare_enable(mdata->spi_clk);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to enable spi_clk (%d)\n", ret);
+ goto err_put_ctlr;
+ }
+
+ pm_runtime_enable(&pdev->dev);
+
+ ret = devm_spi_register_controller(&pdev->dev, ctlr);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "failed to register slave controller(%d)\n", ret);
+ clk_disable_unprepare(mdata->spi_clk);
+ goto err_disable_runtime_pm;
+ }
+
+ clk_disable_unprepare(mdata->spi_clk);
+
+ return 0;
+
+err_disable_runtime_pm:
+ pm_runtime_disable(&pdev->dev);
+err_put_ctlr:
+ spi_controller_put(ctlr);
+
+ return ret;
+}
+
+static int mtk_spi_slave_remove(struct platform_device *pdev)
+{
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int mtk_spi_slave_suspend(struct device *dev)
+{
+ struct spi_controller *ctlr = dev_get_drvdata(dev);
+ struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr);
+ int ret;
+
+ ret = spi_controller_suspend(ctlr);
+ if (ret)
+ return ret;
+
+ if (!pm_runtime_suspended(dev))
+ clk_disable_unprepare(mdata->spi_clk);
+
+ return ret;
+}
+
+static int mtk_spi_slave_resume(struct device *dev)
+{
+ struct spi_controller *ctlr = dev_get_drvdata(dev);
+ struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr);
+ int ret;
+
+ if (!pm_runtime_suspended(dev)) {
+ ret = clk_prepare_enable(mdata->spi_clk);
+ if (ret < 0) {
+ dev_err(dev, "failed to enable spi_clk (%d)\n", ret);
+ return ret;
+ }
+ }
+
+ ret = spi_controller_resume(ctlr);
+ if (ret < 0)
+ clk_disable_unprepare(mdata->spi_clk);
+
+ return ret;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+#ifdef CONFIG_PM
+static int mtk_spi_slave_runtime_suspend(struct device *dev)
+{
+ struct spi_controller *ctlr = dev_get_drvdata(dev);
+ struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr);
+
+ clk_disable_unprepare(mdata->spi_clk);
+
+ return 0;
+}
+
+static int mtk_spi_slave_runtime_resume(struct device *dev)
+{
+ struct spi_controller *ctlr = dev_get_drvdata(dev);
+ struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr);
+ int ret;
+
+ ret = clk_prepare_enable(mdata->spi_clk);
+ if (ret < 0) {
+ dev_err(dev, "failed to enable spi_clk (%d)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+#endif /* CONFIG_PM */
+
+static const struct dev_pm_ops mtk_spi_slave_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(mtk_spi_slave_suspend, mtk_spi_slave_resume)
+ SET_RUNTIME_PM_OPS(mtk_spi_slave_runtime_suspend,
+ mtk_spi_slave_runtime_resume, NULL)
+};
+
+static struct platform_driver mtk_spi_slave_driver = {
+ .driver = {
+ .name = "mtk-spi-slave",
+ .pm = &mtk_spi_slave_pm,
+ .of_match_table = mtk_spi_slave_of_match,
+ },
+ .probe = mtk_spi_slave_probe,
+ .remove = mtk_spi_slave_remove,
+};
+
+module_platform_driver(mtk_spi_slave_driver);
+
+MODULE_DESCRIPTION("MTK SPI Slave Controller driver");
+MODULE_AUTHOR("Leilk Liu <leilk.liu@mediatek.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:mtk-spi-slave");
diff --git a/drivers/spi/spi-slave-system-control.c b/drivers/spi/spi-slave-system-control.c
index c0257e937995..169f3d595f60 100644
--- a/drivers/spi/spi-slave-system-control.c
+++ b/drivers/spi/spi-slave-system-control.c
@@ -60,6 +60,7 @@ static void spi_slave_system_control_complete(void *arg)
case CMD_REBOOT:
dev_info(&priv->spi->dev, "Rebooting system...\n");
kernel_restart(NULL);
+ break;
case CMD_POWEROFF:
dev_info(&priv->spi->dev, "Powering off system...\n");
diff --git a/drivers/spi/spi-sprd.c b/drivers/spi/spi-sprd.c
new file mode 100644
index 000000000000..8daa24eec624
--- /dev/null
+++ b/drivers/spi/spi-sprd.c
@@ -0,0 +1,745 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2018 Spreadtrum Communications Inc.
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/spi/spi.h>
+
+#define SPRD_SPI_TXD 0x0
+#define SPRD_SPI_CLKD 0x4
+#define SPRD_SPI_CTL0 0x8
+#define SPRD_SPI_CTL1 0xc
+#define SPRD_SPI_CTL2 0x10
+#define SPRD_SPI_CTL3 0x14
+#define SPRD_SPI_CTL4 0x18
+#define SPRD_SPI_CTL5 0x1c
+#define SPRD_SPI_INT_EN 0x20
+#define SPRD_SPI_INT_CLR 0x24
+#define SPRD_SPI_INT_RAW_STS 0x28
+#define SPRD_SPI_INT_MASK_STS 0x2c
+#define SPRD_SPI_STS1 0x30
+#define SPRD_SPI_STS2 0x34
+#define SPRD_SPI_DSP_WAIT 0x38
+#define SPRD_SPI_STS3 0x3c
+#define SPRD_SPI_CTL6 0x40
+#define SPRD_SPI_STS4 0x44
+#define SPRD_SPI_FIFO_RST 0x48
+#define SPRD_SPI_CTL7 0x4c
+#define SPRD_SPI_STS5 0x50
+#define SPRD_SPI_CTL8 0x54
+#define SPRD_SPI_CTL9 0x58
+#define SPRD_SPI_CTL10 0x5c
+#define SPRD_SPI_CTL11 0x60
+#define SPRD_SPI_CTL12 0x64
+#define SPRD_SPI_STS6 0x68
+#define SPRD_SPI_STS7 0x6c
+#define SPRD_SPI_STS8 0x70
+#define SPRD_SPI_STS9 0x74
+
+/* Bits & mask definition for register CTL0 */
+#define SPRD_SPI_SCK_REV BIT(13)
+#define SPRD_SPI_NG_TX BIT(1)
+#define SPRD_SPI_NG_RX BIT(0)
+#define SPRD_SPI_CHNL_LEN_MASK GENMASK(4, 0)
+#define SPRD_SPI_CSN_MASK GENMASK(11, 8)
+#define SPRD_SPI_CS0_VALID BIT(8)
+
+/* Bits & mask definition for register SPI_INT_EN */
+#define SPRD_SPI_TX_END_INT_EN BIT(8)
+#define SPRD_SPI_RX_END_INT_EN BIT(9)
+
+/* Bits & mask definition for register SPI_INT_RAW_STS */
+#define SPRD_SPI_TX_END_RAW BIT(8)
+#define SPRD_SPI_RX_END_RAW BIT(9)
+
+/* Bits & mask definition for register SPI_INT_CLR */
+#define SPRD_SPI_TX_END_CLR BIT(8)
+#define SPRD_SPI_RX_END_CLR BIT(9)
+
+/* Bits & mask definition for register INT_MASK_STS */
+#define SPRD_SPI_MASK_RX_END BIT(9)
+#define SPRD_SPI_MASK_TX_END BIT(8)
+
+/* Bits & mask definition for register STS2 */
+#define SPRD_SPI_TX_BUSY BIT(8)
+
+/* Bits & mask definition for register CTL1 */
+#define SPRD_SPI_RX_MODE BIT(12)
+#define SPRD_SPI_TX_MODE BIT(13)
+#define SPRD_SPI_RTX_MD_MASK GENMASK(13, 12)
+
+/* Bits & mask definition for register CTL2 */
+#define SPRD_SPI_DMA_EN BIT(6)
+
+/* Bits & mask definition for register CTL4 */
+#define SPRD_SPI_START_RX BIT(9)
+#define SPRD_SPI_ONLY_RECV_MASK GENMASK(8, 0)
+
+/* Bits & mask definition for register SPI_INT_CLR */
+#define SPRD_SPI_RX_END_INT_CLR BIT(9)
+#define SPRD_SPI_TX_END_INT_CLR BIT(8)
+
+/* Bits & mask definition for register SPI_INT_RAW */
+#define SPRD_SPI_RX_END_IRQ BIT(9)
+#define SPRD_SPI_TX_END_IRQ BIT(8)
+
+/* Bits & mask definition for register CTL12 */
+#define SPRD_SPI_SW_RX_REQ BIT(0)
+#define SPRD_SPI_SW_TX_REQ BIT(1)
+
+/* Bits & mask definition for register CTL7 */
+#define SPRD_SPI_DATA_LINE2_EN BIT(15)
+#define SPRD_SPI_MODE_MASK GENMASK(5, 3)
+#define SPRD_SPI_MODE_OFFSET 3
+#define SPRD_SPI_3WIRE_MODE 4
+#define SPRD_SPI_4WIRE_MODE 0
+
+/* Bits & mask definition for register CTL8 */
+#define SPRD_SPI_TX_MAX_LEN_MASK GENMASK(19, 0)
+#define SPRD_SPI_TX_LEN_H_MASK GENMASK(3, 0)
+#define SPRD_SPI_TX_LEN_H_OFFSET 16
+
+/* Bits & mask definition for register CTL9 */
+#define SPRD_SPI_TX_LEN_L_MASK GENMASK(15, 0)
+
+/* Bits & mask definition for register CTL10 */
+#define SPRD_SPI_RX_MAX_LEN_MASK GENMASK(19, 0)
+#define SPRD_SPI_RX_LEN_H_MASK GENMASK(3, 0)
+#define SPRD_SPI_RX_LEN_H_OFFSET 16
+
+/* Bits & mask definition for register CTL11 */
+#define SPRD_SPI_RX_LEN_L_MASK GENMASK(15, 0)
+
+/* Default & maximum word delay cycles */
+#define SPRD_SPI_MIN_DELAY_CYCLE 14
+#define SPRD_SPI_MAX_DELAY_CYCLE 130
+
+#define SPRD_SPI_FIFO_SIZE 32
+#define SPRD_SPI_CHIP_CS_NUM 0x4
+#define SPRD_SPI_CHNL_LEN 2
+#define SPRD_SPI_DEFAULT_SOURCE 26000000
+#define SPRD_SPI_MAX_SPEED_HZ 48000000
+#define SPRD_SPI_AUTOSUSPEND_DELAY 100
+
+struct sprd_spi {
+ void __iomem *base;
+ struct device *dev;
+ struct clk *clk;
+ u32 src_clk;
+ u32 hw_mode;
+ u32 trans_len;
+ u32 trans_mode;
+ u32 word_delay;
+ u32 hw_speed_hz;
+ u32 len;
+ int status;
+ const void *tx_buf;
+ void *rx_buf;
+ int (*read_bufs)(struct sprd_spi *ss, u32 len);
+ int (*write_bufs)(struct sprd_spi *ss, u32 len);
+};
+
+static u32 sprd_spi_transfer_max_timeout(struct sprd_spi *ss,
+ struct spi_transfer *t)
+{
+ /*
+ * The time spent on transmission of the full FIFO data is the maximum
+ * SPI transmission time.
+ */
+ u32 size = t->bits_per_word * SPRD_SPI_FIFO_SIZE;
+ u32 bit_time_us = DIV_ROUND_UP(USEC_PER_SEC, ss->hw_speed_hz);
+ u32 total_time_us = size * bit_time_us;
+ /*
+ * There is an interval between data and the data in our SPI hardware,
+ * so the total transmission time need add the interval time.
+ */
+ u32 interval_cycle = SPRD_SPI_FIFO_SIZE * ss->word_delay;
+ u32 interval_time_us = DIV_ROUND_UP(interval_cycle * USEC_PER_SEC,
+ ss->src_clk);
+
+ return total_time_us + interval_time_us;
+}
+
+static int sprd_spi_wait_for_tx_end(struct sprd_spi *ss, struct spi_transfer *t)
+{
+ u32 val, us;
+ int ret;
+
+ us = sprd_spi_transfer_max_timeout(ss, t);
+ ret = readl_relaxed_poll_timeout(ss->base + SPRD_SPI_INT_RAW_STS, val,
+ val & SPRD_SPI_TX_END_IRQ, 0, us);
+ if (ret) {
+ dev_err(ss->dev, "SPI error, spi send timeout!\n");
+ return ret;
+ }
+
+ ret = readl_relaxed_poll_timeout(ss->base + SPRD_SPI_STS2, val,
+ !(val & SPRD_SPI_TX_BUSY), 0, us);
+ if (ret) {
+ dev_err(ss->dev, "SPI error, spi busy timeout!\n");
+ return ret;
+ }
+
+ writel_relaxed(SPRD_SPI_TX_END_INT_CLR, ss->base + SPRD_SPI_INT_CLR);
+
+ return 0;
+}
+
+static int sprd_spi_wait_for_rx_end(struct sprd_spi *ss, struct spi_transfer *t)
+{
+ u32 val, us;
+ int ret;
+
+ us = sprd_spi_transfer_max_timeout(ss, t);
+ ret = readl_relaxed_poll_timeout(ss->base + SPRD_SPI_INT_RAW_STS, val,
+ val & SPRD_SPI_RX_END_IRQ, 0, us);
+ if (ret) {
+ dev_err(ss->dev, "SPI error, spi rx timeout!\n");
+ return ret;
+ }
+
+ writel_relaxed(SPRD_SPI_RX_END_INT_CLR, ss->base + SPRD_SPI_INT_CLR);
+
+ return 0;
+}
+
+static void sprd_spi_tx_req(struct sprd_spi *ss)
+{
+ writel_relaxed(SPRD_SPI_SW_TX_REQ, ss->base + SPRD_SPI_CTL12);
+}
+
+static void sprd_spi_rx_req(struct sprd_spi *ss)
+{
+ writel_relaxed(SPRD_SPI_SW_RX_REQ, ss->base + SPRD_SPI_CTL12);
+}
+
+static void sprd_spi_enter_idle(struct sprd_spi *ss)
+{
+ u32 val = readl_relaxed(ss->base + SPRD_SPI_CTL1);
+
+ val &= ~SPRD_SPI_RTX_MD_MASK;
+ writel_relaxed(val, ss->base + SPRD_SPI_CTL1);
+}
+
+static void sprd_spi_set_transfer_bits(struct sprd_spi *ss, u32 bits)
+{
+ u32 val = readl_relaxed(ss->base + SPRD_SPI_CTL0);
+
+ /* Set the valid bits for every transaction */
+ val &= ~(SPRD_SPI_CHNL_LEN_MASK << SPRD_SPI_CHNL_LEN);
+ val |= bits << SPRD_SPI_CHNL_LEN;
+ writel_relaxed(val, ss->base + SPRD_SPI_CTL0);
+}
+
+static void sprd_spi_set_tx_length(struct sprd_spi *ss, u32 length)
+{
+ u32 val = readl_relaxed(ss->base + SPRD_SPI_CTL8);
+
+ length &= SPRD_SPI_TX_MAX_LEN_MASK;
+ val &= ~SPRD_SPI_TX_LEN_H_MASK;
+ val |= length >> SPRD_SPI_TX_LEN_H_OFFSET;
+ writel_relaxed(val, ss->base + SPRD_SPI_CTL8);
+
+ val = length & SPRD_SPI_TX_LEN_L_MASK;
+ writel_relaxed(val, ss->base + SPRD_SPI_CTL9);
+}
+
+static void sprd_spi_set_rx_length(struct sprd_spi *ss, u32 length)
+{
+ u32 val = readl_relaxed(ss->base + SPRD_SPI_CTL10);
+
+ length &= SPRD_SPI_RX_MAX_LEN_MASK;
+ val &= ~SPRD_SPI_RX_LEN_H_MASK;
+ val |= length >> SPRD_SPI_RX_LEN_H_OFFSET;
+ writel_relaxed(val, ss->base + SPRD_SPI_CTL10);
+
+ val = length & SPRD_SPI_RX_LEN_L_MASK;
+ writel_relaxed(val, ss->base + SPRD_SPI_CTL11);
+}
+
+static void sprd_spi_chipselect(struct spi_device *sdev, bool cs)
+{
+ struct spi_controller *sctlr = sdev->controller;
+ struct sprd_spi *ss = spi_controller_get_devdata(sctlr);
+ u32 val;
+
+ val = readl_relaxed(ss->base + SPRD_SPI_CTL0);
+ /* The SPI controller will pull down CS pin if cs is 0 */
+ if (!cs) {
+ val &= ~SPRD_SPI_CS0_VALID;
+ writel_relaxed(val, ss->base + SPRD_SPI_CTL0);
+ } else {
+ val |= SPRD_SPI_CSN_MASK;
+ writel_relaxed(val, ss->base + SPRD_SPI_CTL0);
+ }
+}
+
+static int sprd_spi_write_only_receive(struct sprd_spi *ss, u32 len)
+{
+ u32 val;
+
+ /* Clear the start receive bit and reset receive data number */
+ val = readl_relaxed(ss->base + SPRD_SPI_CTL4);
+ val &= ~(SPRD_SPI_START_RX | SPRD_SPI_ONLY_RECV_MASK);
+ writel_relaxed(val, ss->base + SPRD_SPI_CTL4);
+
+ /* Set the receive data length */
+ val = readl_relaxed(ss->base + SPRD_SPI_CTL4);
+ val |= len & SPRD_SPI_ONLY_RECV_MASK;
+ writel_relaxed(val, ss->base + SPRD_SPI_CTL4);
+
+ /* Trigger to receive data */
+ val = readl_relaxed(ss->base + SPRD_SPI_CTL4);
+ val |= SPRD_SPI_START_RX;
+ writel_relaxed(val, ss->base + SPRD_SPI_CTL4);
+
+ return len;
+}
+
+static int sprd_spi_write_bufs_u8(struct sprd_spi *ss, u32 len)
+{
+ u8 *tx_p = (u8 *)ss->tx_buf;
+ int i;
+
+ for (i = 0; i < len; i++)
+ writeb_relaxed(tx_p[i], ss->base + SPRD_SPI_TXD);
+
+ ss->tx_buf += i;
+ return i;
+}
+
+static int sprd_spi_write_bufs_u16(struct sprd_spi *ss, u32 len)
+{
+ u16 *tx_p = (u16 *)ss->tx_buf;
+ int i;
+
+ for (i = 0; i < len; i++)
+ writew_relaxed(tx_p[i], ss->base + SPRD_SPI_TXD);
+
+ ss->tx_buf += i << 1;
+ return i << 1;
+}
+
+static int sprd_spi_write_bufs_u32(struct sprd_spi *ss, u32 len)
+{
+ u32 *tx_p = (u32 *)ss->tx_buf;
+ int i;
+
+ for (i = 0; i < len; i++)
+ writel_relaxed(tx_p[i], ss->base + SPRD_SPI_TXD);
+
+ ss->tx_buf += i << 2;
+ return i << 2;
+}
+
+static int sprd_spi_read_bufs_u8(struct sprd_spi *ss, u32 len)
+{
+ u8 *rx_p = (u8 *)ss->rx_buf;
+ int i;
+
+ for (i = 0; i < len; i++)
+ rx_p[i] = readb_relaxed(ss->base + SPRD_SPI_TXD);
+
+ ss->rx_buf += i;
+ return i;
+}
+
+static int sprd_spi_read_bufs_u16(struct sprd_spi *ss, u32 len)
+{
+ u16 *rx_p = (u16 *)ss->rx_buf;
+ int i;
+
+ for (i = 0; i < len; i++)
+ rx_p[i] = readw_relaxed(ss->base + SPRD_SPI_TXD);
+
+ ss->rx_buf += i << 1;
+ return i << 1;
+}
+
+static int sprd_spi_read_bufs_u32(struct sprd_spi *ss, u32 len)
+{
+ u32 *rx_p = (u32 *)ss->rx_buf;
+ int i;
+
+ for (i = 0; i < len; i++)
+ rx_p[i] = readl_relaxed(ss->base + SPRD_SPI_TXD);
+
+ ss->rx_buf += i << 2;
+ return i << 2;
+}
+
+static int sprd_spi_txrx_bufs(struct spi_device *sdev, struct spi_transfer *t)
+{
+ struct sprd_spi *ss = spi_controller_get_devdata(sdev->controller);
+ u32 trans_len = ss->trans_len, len;
+ int ret, write_size = 0;
+
+ while (trans_len) {
+ len = trans_len > SPRD_SPI_FIFO_SIZE ? SPRD_SPI_FIFO_SIZE :
+ trans_len;
+ if (ss->trans_mode & SPRD_SPI_TX_MODE) {
+ sprd_spi_set_tx_length(ss, len);
+ write_size += ss->write_bufs(ss, len);
+
+ /*
+ * For our 3 wires mode or dual TX line mode, we need
+ * to request the controller to transfer.
+ */
+ if (ss->hw_mode & SPI_3WIRE || ss->hw_mode & SPI_TX_DUAL)
+ sprd_spi_tx_req(ss);
+
+ ret = sprd_spi_wait_for_tx_end(ss, t);
+ } else {
+ sprd_spi_set_rx_length(ss, len);
+
+ /*
+ * For our 3 wires mode or dual TX line mode, we need
+ * to request the controller to read.
+ */
+ if (ss->hw_mode & SPI_3WIRE || ss->hw_mode & SPI_TX_DUAL)
+ sprd_spi_rx_req(ss);
+ else
+ write_size += ss->write_bufs(ss, len);
+
+ ret = sprd_spi_wait_for_rx_end(ss, t);
+ }
+
+ if (ret)
+ goto complete;
+
+ if (ss->trans_mode & SPRD_SPI_RX_MODE)
+ ss->read_bufs(ss, len);
+
+ trans_len -= len;
+ }
+
+ ret = write_size;
+
+complete:
+ sprd_spi_enter_idle(ss);
+
+ return ret;
+}
+
+static void sprd_spi_set_speed(struct sprd_spi *ss, u32 speed_hz)
+{
+ /*
+ * From SPI datasheet, the prescale calculation formula:
+ * prescale = SPI source clock / (2 * SPI_freq) - 1;
+ */
+ u32 clk_div = DIV_ROUND_UP(ss->src_clk, speed_hz << 1) - 1;
+
+ /* Save the real hardware speed */
+ ss->hw_speed_hz = (ss->src_clk >> 1) / (clk_div + 1);
+ writel_relaxed(clk_div, ss->base + SPRD_SPI_CLKD);
+}
+
+static void sprd_spi_init_hw(struct sprd_spi *ss, struct spi_transfer *t)
+{
+ u16 word_delay, interval;
+ u32 val;
+
+ val = readl_relaxed(ss->base + SPRD_SPI_CTL7);
+ val &= ~(SPRD_SPI_SCK_REV | SPRD_SPI_NG_TX | SPRD_SPI_NG_RX);
+ /* Set default chip selection, clock phase and clock polarity */
+ val |= ss->hw_mode & SPI_CPHA ? SPRD_SPI_NG_RX : SPRD_SPI_NG_TX;
+ val |= ss->hw_mode & SPI_CPOL ? SPRD_SPI_SCK_REV : 0;
+ writel_relaxed(val, ss->base + SPRD_SPI_CTL0);
+
+ /*
+ * Set the intervals of two SPI frames, and the inteval calculation
+ * formula as below per datasheet:
+ * interval time (source clock cycles) = interval * 4 + 10.
+ */
+ word_delay = clamp_t(u16, t->word_delay, SPRD_SPI_MIN_DELAY_CYCLE,
+ SPRD_SPI_MAX_DELAY_CYCLE);
+ interval = DIV_ROUND_UP(word_delay - 10, 4);
+ ss->word_delay = interval * 4 + 10;
+ writel_relaxed(interval, ss->base + SPRD_SPI_CTL5);
+
+ /* Reset SPI fifo */
+ writel_relaxed(1, ss->base + SPRD_SPI_FIFO_RST);
+ writel_relaxed(0, ss->base + SPRD_SPI_FIFO_RST);
+
+ /* Set SPI work mode */
+ val = readl_relaxed(ss->base + SPRD_SPI_CTL7);
+ val &= ~SPRD_SPI_MODE_MASK;
+
+ if (ss->hw_mode & SPI_3WIRE)
+ val |= SPRD_SPI_3WIRE_MODE << SPRD_SPI_MODE_OFFSET;
+ else
+ val |= SPRD_SPI_4WIRE_MODE << SPRD_SPI_MODE_OFFSET;
+
+ if (ss->hw_mode & SPI_TX_DUAL)
+ val |= SPRD_SPI_DATA_LINE2_EN;
+ else
+ val &= ~SPRD_SPI_DATA_LINE2_EN;
+
+ writel_relaxed(val, ss->base + SPRD_SPI_CTL7);
+}
+
+static int sprd_spi_setup_transfer(struct spi_device *sdev,
+ struct spi_transfer *t)
+{
+ struct sprd_spi *ss = spi_controller_get_devdata(sdev->controller);
+ u8 bits_per_word = t->bits_per_word;
+ u32 val, mode = 0;
+
+ ss->len = t->len;
+ ss->tx_buf = t->tx_buf;
+ ss->rx_buf = t->rx_buf;
+
+ ss->hw_mode = sdev->mode;
+ sprd_spi_init_hw(ss, t);
+
+ /* Set tansfer speed and valid bits */
+ sprd_spi_set_speed(ss, t->speed_hz);
+ sprd_spi_set_transfer_bits(ss, bits_per_word);
+
+ if (bits_per_word > 16)
+ bits_per_word = round_up(bits_per_word, 16);
+ else
+ bits_per_word = round_up(bits_per_word, 8);
+
+ switch (bits_per_word) {
+ case 8:
+ ss->trans_len = t->len;
+ ss->read_bufs = sprd_spi_read_bufs_u8;
+ ss->write_bufs = sprd_spi_write_bufs_u8;
+ break;
+ case 16:
+ ss->trans_len = t->len >> 1;
+ ss->read_bufs = sprd_spi_read_bufs_u16;
+ ss->write_bufs = sprd_spi_write_bufs_u16;
+ break;
+ case 32:
+ ss->trans_len = t->len >> 2;
+ ss->read_bufs = sprd_spi_read_bufs_u32;
+ ss->write_bufs = sprd_spi_write_bufs_u32;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Set transfer read or write mode */
+ val = readl_relaxed(ss->base + SPRD_SPI_CTL1);
+ val &= ~SPRD_SPI_RTX_MD_MASK;
+ if (t->tx_buf)
+ mode |= SPRD_SPI_TX_MODE;
+ if (t->rx_buf)
+ mode |= SPRD_SPI_RX_MODE;
+
+ writel_relaxed(val | mode, ss->base + SPRD_SPI_CTL1);
+
+ ss->trans_mode = mode;
+
+ /*
+ * If in only receive mode, we need to trigger the SPI controller to
+ * receive data automatically.
+ */
+ if (ss->trans_mode == SPRD_SPI_RX_MODE)
+ ss->write_bufs = sprd_spi_write_only_receive;
+
+ return 0;
+}
+
+static int sprd_spi_transfer_one(struct spi_controller *sctlr,
+ struct spi_device *sdev,
+ struct spi_transfer *t)
+{
+ int ret;
+
+ ret = sprd_spi_setup_transfer(sdev, t);
+ if (ret)
+ goto setup_err;
+
+ ret = sprd_spi_txrx_bufs(sdev, t);
+ if (ret == t->len)
+ ret = 0;
+ else if (ret >= 0)
+ ret = -EREMOTEIO;
+
+setup_err:
+ spi_finalize_current_transfer(sctlr);
+
+ return ret;
+}
+
+static int sprd_spi_clk_init(struct platform_device *pdev, struct sprd_spi *ss)
+{
+ struct clk *clk_spi, *clk_parent;
+
+ clk_spi = devm_clk_get(&pdev->dev, "spi");
+ if (IS_ERR(clk_spi)) {
+ dev_warn(&pdev->dev, "can't get the spi clock\n");
+ clk_spi = NULL;
+ }
+
+ clk_parent = devm_clk_get(&pdev->dev, "source");
+ if (IS_ERR(clk_parent)) {
+ dev_warn(&pdev->dev, "can't get the source clock\n");
+ clk_parent = NULL;
+ }
+
+ ss->clk = devm_clk_get(&pdev->dev, "enable");
+ if (IS_ERR(ss->clk)) {
+ dev_err(&pdev->dev, "can't get the enable clock\n");
+ return PTR_ERR(ss->clk);
+ }
+
+ if (!clk_set_parent(clk_spi, clk_parent))
+ ss->src_clk = clk_get_rate(clk_spi);
+ else
+ ss->src_clk = SPRD_SPI_DEFAULT_SOURCE;
+
+ return 0;
+}
+
+static int sprd_spi_probe(struct platform_device *pdev)
+{
+ struct spi_controller *sctlr;
+ struct resource *res;
+ struct sprd_spi *ss;
+ int ret;
+
+ pdev->id = of_alias_get_id(pdev->dev.of_node, "spi");
+ sctlr = spi_alloc_master(&pdev->dev, sizeof(*ss));
+ if (!sctlr)
+ return -ENOMEM;
+
+ ss = spi_controller_get_devdata(sctlr);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ ss->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(ss->base)) {
+ ret = PTR_ERR(ss->base);
+ goto free_controller;
+ }
+
+ ss->dev = &pdev->dev;
+ sctlr->dev.of_node = pdev->dev.of_node;
+ sctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_3WIRE | SPI_TX_DUAL;
+ sctlr->bus_num = pdev->id;
+ sctlr->set_cs = sprd_spi_chipselect;
+ sctlr->transfer_one = sprd_spi_transfer_one;
+ sctlr->auto_runtime_pm = true;
+ sctlr->max_speed_hz = min_t(u32, ss->src_clk >> 1,
+ SPRD_SPI_MAX_SPEED_HZ);
+
+ platform_set_drvdata(pdev, sctlr);
+ ret = sprd_spi_clk_init(pdev, ss);
+ if (ret)
+ goto free_controller;
+
+ ret = clk_prepare_enable(ss->clk);
+ if (ret)
+ goto free_controller;
+
+ ret = pm_runtime_set_active(&pdev->dev);
+ if (ret < 0)
+ goto disable_clk;
+
+ pm_runtime_set_autosuspend_delay(&pdev->dev,
+ SPRD_SPI_AUTOSUSPEND_DELAY);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+ ret = pm_runtime_get_sync(&pdev->dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to resume SPI controller\n");
+ goto err_rpm_put;
+ }
+
+ ret = devm_spi_register_controller(&pdev->dev, sctlr);
+ if (ret)
+ goto err_rpm_put;
+
+ pm_runtime_mark_last_busy(&pdev->dev);
+ pm_runtime_put_autosuspend(&pdev->dev);
+
+ return 0;
+
+err_rpm_put:
+ pm_runtime_put_noidle(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+disable_clk:
+ clk_disable_unprepare(ss->clk);
+free_controller:
+ spi_controller_put(sctlr);
+
+ return ret;
+}
+
+static int sprd_spi_remove(struct platform_device *pdev)
+{
+ struct spi_controller *sctlr = platform_get_drvdata(pdev);
+ struct sprd_spi *ss = spi_controller_get_devdata(sctlr);
+ int ret;
+
+ ret = pm_runtime_get_sync(ss->dev);
+ if (ret < 0) {
+ dev_err(ss->dev, "failed to resume SPI controller\n");
+ return ret;
+ }
+
+ clk_disable_unprepare(ss->clk);
+ pm_runtime_put_noidle(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+static int __maybe_unused sprd_spi_runtime_suspend(struct device *dev)
+{
+ struct spi_controller *sctlr = dev_get_drvdata(dev);
+ struct sprd_spi *ss = spi_controller_get_devdata(sctlr);
+
+ clk_disable_unprepare(ss->clk);
+
+ return 0;
+}
+
+static int __maybe_unused sprd_spi_runtime_resume(struct device *dev)
+{
+ struct spi_controller *sctlr = dev_get_drvdata(dev);
+ struct sprd_spi *ss = spi_controller_get_devdata(sctlr);
+ int ret;
+
+ ret = clk_prepare_enable(ss->clk);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static const struct dev_pm_ops sprd_spi_pm_ops = {
+ SET_RUNTIME_PM_OPS(sprd_spi_runtime_suspend,
+ sprd_spi_runtime_resume, NULL)
+};
+
+static const struct of_device_id sprd_spi_of_match[] = {
+ { .compatible = "sprd,sc9860-spi", },
+ { /* sentinel */ }
+};
+
+static struct platform_driver sprd_spi_driver = {
+ .driver = {
+ .name = "sprd-spi",
+ .of_match_table = sprd_spi_of_match,
+ .pm = &sprd_spi_pm_ops,
+ },
+ .probe = sprd_spi_probe,
+ .remove = sprd_spi_remove,
+};
+
+module_platform_driver(sprd_spi_driver);
+
+MODULE_DESCRIPTION("Spreadtrum SPI Controller driver");
+MODULE_AUTHOR("Lanqing Liu <lanqing.liu@spreadtrum.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c
new file mode 100644
index 000000000000..3b2a9a6b990d
--- /dev/null
+++ b/drivers/spi/spi-stm32-qspi.c
@@ -0,0 +1,512 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Author: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics.
+ */
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/sizes.h>
+#include <linux/spi/spi-mem.h>
+
+#define QSPI_CR 0x00
+#define CR_EN BIT(0)
+#define CR_ABORT BIT(1)
+#define CR_DMAEN BIT(2)
+#define CR_TCEN BIT(3)
+#define CR_SSHIFT BIT(4)
+#define CR_DFM BIT(6)
+#define CR_FSEL BIT(7)
+#define CR_FTHRES_MASK GENMASK(12, 8)
+#define CR_TEIE BIT(16)
+#define CR_TCIE BIT(17)
+#define CR_FTIE BIT(18)
+#define CR_SMIE BIT(19)
+#define CR_TOIE BIT(20)
+#define CR_PRESC_MASK GENMASK(31, 24)
+
+#define QSPI_DCR 0x04
+#define DCR_FSIZE_MASK GENMASK(20, 16)
+
+#define QSPI_SR 0x08
+#define SR_TEF BIT(0)
+#define SR_TCF BIT(1)
+#define SR_FTF BIT(2)
+#define SR_SMF BIT(3)
+#define SR_TOF BIT(4)
+#define SR_BUSY BIT(5)
+#define SR_FLEVEL_MASK GENMASK(13, 8)
+
+#define QSPI_FCR 0x0c
+#define FCR_CTEF BIT(0)
+#define FCR_CTCF BIT(1)
+
+#define QSPI_DLR 0x10
+
+#define QSPI_CCR 0x14
+#define CCR_INST_MASK GENMASK(7, 0)
+#define CCR_IMODE_MASK GENMASK(9, 8)
+#define CCR_ADMODE_MASK GENMASK(11, 10)
+#define CCR_ADSIZE_MASK GENMASK(13, 12)
+#define CCR_DCYC_MASK GENMASK(22, 18)
+#define CCR_DMODE_MASK GENMASK(25, 24)
+#define CCR_FMODE_MASK GENMASK(27, 26)
+#define CCR_FMODE_INDW (0U << 26)
+#define CCR_FMODE_INDR (1U << 26)
+#define CCR_FMODE_APM (2U << 26)
+#define CCR_FMODE_MM (3U << 26)
+#define CCR_BUSWIDTH_0 0x0
+#define CCR_BUSWIDTH_1 0x1
+#define CCR_BUSWIDTH_2 0x2
+#define CCR_BUSWIDTH_4 0x3
+
+#define QSPI_AR 0x18
+#define QSPI_ABR 0x1c
+#define QSPI_DR 0x20
+#define QSPI_PSMKR 0x24
+#define QSPI_PSMAR 0x28
+#define QSPI_PIR 0x2c
+#define QSPI_LPTR 0x30
+#define LPTR_DFT_TIMEOUT 0x10
+
+#define STM32_QSPI_MAX_MMAP_SZ SZ_256M
+#define STM32_QSPI_MAX_NORCHIP 2
+
+#define STM32_FIFO_TIMEOUT_US 30000
+#define STM32_BUSY_TIMEOUT_US 100000
+#define STM32_ABT_TIMEOUT_US 100000
+
+struct stm32_qspi_flash {
+ struct stm32_qspi *qspi;
+ u32 cs;
+ u32 presc;
+};
+
+struct stm32_qspi {
+ struct device *dev;
+ void __iomem *io_base;
+ void __iomem *mm_base;
+ resource_size_t mm_size;
+ struct clk *clk;
+ u32 clk_rate;
+ struct stm32_qspi_flash flash[STM32_QSPI_MAX_NORCHIP];
+ struct completion data_completion;
+ u32 fmode;
+
+ /*
+ * to protect device configuration, could be different between
+ * 2 flash access (bk1, bk2)
+ */
+ struct mutex lock;
+};
+
+static irqreturn_t stm32_qspi_irq(int irq, void *dev_id)
+{
+ struct stm32_qspi *qspi = (struct stm32_qspi *)dev_id;
+ u32 cr, sr;
+
+ sr = readl_relaxed(qspi->io_base + QSPI_SR);
+
+ 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);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void stm32_qspi_read_fifo(u8 *val, void __iomem *addr)
+{
+ *val = readb_relaxed(addr);
+}
+
+static void stm32_qspi_write_fifo(u8 *val, void __iomem *addr)
+{
+ writeb_relaxed(*val, addr);
+}
+
+static int stm32_qspi_tx_poll(struct stm32_qspi *qspi,
+ const struct spi_mem_op *op)
+{
+ void (*tx_fifo)(u8 *val, void __iomem *addr);
+ u32 len = op->data.nbytes, sr;
+ u8 *buf;
+ int ret;
+
+ if (op->data.dir == SPI_MEM_DATA_IN) {
+ tx_fifo = stm32_qspi_read_fifo;
+ buf = op->data.buf.in;
+
+ } else {
+ tx_fifo = stm32_qspi_write_fifo;
+ buf = (u8 *)op->data.buf.out;
+ }
+
+ while (len--) {
+ ret = readl_relaxed_poll_timeout_atomic(qspi->io_base + QSPI_SR,
+ sr, (sr & SR_FTF), 1,
+ STM32_FIFO_TIMEOUT_US);
+ if (ret) {
+ dev_err(qspi->dev, "fifo timeout (len:%d stat:%#x)\n",
+ len, sr);
+ return ret;
+ }
+ tx_fifo(buf++, qspi->io_base + QSPI_DR);
+ }
+
+ return 0;
+}
+
+static int stm32_qspi_tx_mm(struct stm32_qspi *qspi,
+ const struct spi_mem_op *op)
+{
+ memcpy_fromio(op->data.buf.in, qspi->mm_base + op->addr.val,
+ op->data.nbytes);
+ return 0;
+}
+
+static int stm32_qspi_tx(struct stm32_qspi *qspi, const struct spi_mem_op *op)
+{
+ if (!op->data.nbytes)
+ return 0;
+
+ if (qspi->fmode == CCR_FMODE_MM)
+ return stm32_qspi_tx_mm(qspi, op);
+
+ return stm32_qspi_tx_poll(qspi, op);
+}
+
+static int stm32_qspi_wait_nobusy(struct stm32_qspi *qspi)
+{
+ u32 sr;
+
+ return readl_relaxed_poll_timeout_atomic(qspi->io_base + QSPI_SR, sr,
+ !(sr & SR_BUSY), 1,
+ STM32_BUSY_TIMEOUT_US);
+}
+
+static int stm32_qspi_wait_cmd(struct stm32_qspi *qspi,
+ const struct spi_mem_op *op)
+{
+ u32 cr, sr;
+ int err = 0;
+
+ if (!op->data.nbytes)
+ return stm32_qspi_wait_nobusy(qspi);
+
+ if (readl_relaxed(qspi->io_base + QSPI_SR) & SR_TCF)
+ goto out;
+
+ reinit_completion(&qspi->data_completion);
+ cr = readl_relaxed(qspi->io_base + QSPI_CR);
+ writel_relaxed(cr | CR_TCIE | CR_TEIE, qspi->io_base + QSPI_CR);
+
+ if (!wait_for_completion_interruptible_timeout(&qspi->data_completion,
+ msecs_to_jiffies(1000))) {
+ err = -ETIMEDOUT;
+ } else {
+ sr = readl_relaxed(qspi->io_base + QSPI_SR);
+ if (sr & SR_TEF)
+ err = -EIO;
+ }
+
+out:
+ /* clear flags */
+ writel_relaxed(FCR_CTCF | FCR_CTEF, qspi->io_base + QSPI_FCR);
+
+ return err;
+}
+
+static int stm32_qspi_get_mode(struct stm32_qspi *qspi, u8 buswidth)
+{
+ if (buswidth == 4)
+ return CCR_BUSWIDTH_4;
+
+ return buswidth;
+}
+
+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, addr_max;
+ int timeout, err = 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,
+ op->dummy.buswidth, op->data.buswidth,
+ op->addr.val, op->data.nbytes);
+
+ err = stm32_qspi_wait_nobusy(qspi);
+ if (err)
+ goto abort;
+
+ addr_max = op->addr.val + op->data.nbytes + 1;
+
+ if (op->data.dir == SPI_MEM_DATA_IN) {
+ if (addr_max < qspi->mm_size &&
+ op->addr.buswidth)
+ qspi->fmode = CCR_FMODE_MM;
+ else
+ qspi->fmode = CCR_FMODE_INDR;
+ } else {
+ qspi->fmode = CCR_FMODE_INDW;
+ }
+
+ cr = readl_relaxed(qspi->io_base + QSPI_CR);
+ cr &= ~CR_PRESC_MASK & ~CR_FSEL;
+ cr |= FIELD_PREP(CR_PRESC_MASK, flash->presc);
+ cr |= FIELD_PREP(CR_FSEL, flash->cs);
+ writel_relaxed(cr, qspi->io_base + QSPI_CR);
+
+ if (op->data.nbytes)
+ writel_relaxed(op->data.nbytes - 1,
+ qspi->io_base + QSPI_DLR);
+ else
+ qspi->fmode = CCR_FMODE_INDW;
+
+ ccr = qspi->fmode;
+ ccr |= FIELD_PREP(CCR_INST_MASK, op->cmd.opcode);
+ ccr |= FIELD_PREP(CCR_IMODE_MASK,
+ stm32_qspi_get_mode(qspi, op->cmd.buswidth));
+
+ if (op->addr.nbytes) {
+ ccr |= FIELD_PREP(CCR_ADMODE_MASK,
+ stm32_qspi_get_mode(qspi, op->addr.buswidth));
+ ccr |= FIELD_PREP(CCR_ADSIZE_MASK, op->addr.nbytes - 1);
+ }
+
+ if (op->dummy.buswidth && op->dummy.nbytes)
+ ccr |= FIELD_PREP(CCR_DCYC_MASK,
+ op->dummy.nbytes * 8 / op->dummy.buswidth);
+
+ if (op->data.nbytes) {
+ ccr |= FIELD_PREP(CCR_DMODE_MASK,
+ stm32_qspi_get_mode(qspi, op->data.buswidth));
+ }
+
+ writel_relaxed(ccr, qspi->io_base + QSPI_CCR);
+
+ if (op->addr.nbytes && qspi->fmode != CCR_FMODE_MM)
+ writel_relaxed(op->addr.val, qspi->io_base + QSPI_AR);
+
+ err = stm32_qspi_tx(qspi, op);
+
+ /*
+ * Abort in:
+ * -error case
+ * -read memory map: prefetching must be stopped if we read the last
+ * 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)
+ goto abort;
+
+ /* wait end of tx in indirect mode */
+ err = stm32_qspi_wait_cmd(qspi, op);
+ if (err)
+ goto abort;
+
+ return 0;
+
+abort:
+ cr = readl_relaxed(qspi->io_base + QSPI_CR) | CR_ABORT;
+ writel_relaxed(cr, qspi->io_base + QSPI_CR);
+
+ /* wait clear of abort bit by hw */
+ timeout = readl_relaxed_poll_timeout_atomic(qspi->io_base + QSPI_CR,
+ cr, !(cr & CR_ABORT), 1,
+ STM32_ABT_TIMEOUT_US);
+
+ writel_relaxed(FCR_CTCF, qspi->io_base + QSPI_FCR);
+
+ if (err || timeout)
+ dev_err(qspi->dev, "%s err:%d abort timeout:%d\n",
+ __func__, err, timeout);
+
+ return err;
+}
+
+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);
+ int ret;
+
+ mutex_lock(&qspi->lock);
+ ret = stm32_qspi_send(mem, op);
+ mutex_unlock(&qspi->lock);
+
+ return ret;
+}
+
+static int stm32_qspi_setup(struct spi_device *spi)
+{
+ struct spi_controller *ctrl = spi->master;
+ struct stm32_qspi *qspi = spi_controller_get_devdata(ctrl);
+ struct stm32_qspi_flash *flash;
+ u32 cr, presc;
+
+ if (ctrl->busy)
+ return -EBUSY;
+
+ if (!spi->max_speed_hz)
+ return -EINVAL;
+
+ 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);
+ writel_relaxed(LPTR_DFT_TIMEOUT, qspi->io_base + QSPI_LPTR);
+ cr = FIELD_PREP(CR_FTHRES_MASK, 3) | CR_TCEN | CR_SSHIFT | CR_EN;
+ writel_relaxed(cr, qspi->io_base + QSPI_CR);
+
+ /* set dcr fsize to max address */
+ writel_relaxed(DCR_FSIZE_MASK, qspi->io_base + QSPI_DCR);
+ mutex_unlock(&qspi->lock);
+
+ return 0;
+}
+
+/*
+ * no special host constraint, so use default spi_mem_default_supports_op
+ * to check supported mode.
+ */
+static const struct spi_controller_mem_ops stm32_qspi_mem_ops = {
+ .exec_op = stm32_qspi_exec_op,
+};
+
+static void stm32_qspi_release(struct stm32_qspi *qspi)
+{
+ /* disable qspi */
+ writel_relaxed(0, qspi->io_base + QSPI_CR);
+ mutex_destroy(&qspi->lock);
+ clk_disable_unprepare(qspi->clk);
+}
+
+static int stm32_qspi_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct spi_controller *ctrl;
+ struct reset_control *rstc;
+ struct stm32_qspi *qspi;
+ struct resource *res;
+ int ret, irq;
+
+ ctrl = spi_alloc_master(dev, sizeof(*qspi));
+ if (!ctrl)
+ return -ENOMEM;
+
+ qspi = spi_controller_get_devdata(ctrl);
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi");
+ qspi->io_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(qspi->io_base))
+ return PTR_ERR(qspi->io_base);
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_mm");
+ qspi->mm_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(qspi->mm_base))
+ return PTR_ERR(qspi->mm_base);
+
+ qspi->mm_size = resource_size(res);
+ if (qspi->mm_size > STM32_QSPI_MAX_MMAP_SZ)
+ return -EINVAL;
+
+ irq = platform_get_irq(pdev, 0);
+ ret = devm_request_irq(dev, irq, stm32_qspi_irq, 0,
+ dev_name(dev), qspi);
+ if (ret) {
+ dev_err(dev, "failed to request irq\n");
+ return ret;
+ }
+
+ init_completion(&qspi->data_completion);
+
+ qspi->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(qspi->clk))
+ return PTR_ERR(qspi->clk);
+
+ qspi->clk_rate = clk_get_rate(qspi->clk);
+ if (!qspi->clk_rate)
+ return -EINVAL;
+
+ ret = clk_prepare_enable(qspi->clk);
+ if (ret) {
+ dev_err(dev, "can not enable the clock\n");
+ return ret;
+ }
+
+ rstc = devm_reset_control_get_exclusive(dev, NULL);
+ if (!IS_ERR(rstc)) {
+ reset_control_assert(rstc);
+ udelay(2);
+ reset_control_deassert(rstc);
+ }
+
+ qspi->dev = dev;
+ platform_set_drvdata(pdev, qspi);
+ mutex_init(&qspi->lock);
+
+ ctrl->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD
+ | SPI_TX_DUAL | SPI_TX_QUAD;
+ ctrl->setup = stm32_qspi_setup;
+ ctrl->bus_num = -1;
+ ctrl->mem_ops = &stm32_qspi_mem_ops;
+ ctrl->num_chipselect = STM32_QSPI_MAX_NORCHIP;
+ ctrl->dev.of_node = dev->of_node;
+
+ ret = devm_spi_register_master(dev, ctrl);
+ if (ret)
+ goto err_spi_register;
+
+ return 0;
+
+err_spi_register:
+ stm32_qspi_release(qspi);
+
+ return ret;
+}
+
+static int stm32_qspi_remove(struct platform_device *pdev)
+{
+ struct stm32_qspi *qspi = platform_get_drvdata(pdev);
+
+ stm32_qspi_release(qspi);
+ return 0;
+}
+
+static const struct of_device_id stm32_qspi_match[] = {
+ {.compatible = "st,stm32f469-qspi"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, stm32_qspi_match);
+
+static struct platform_driver stm32_qspi_driver = {
+ .probe = stm32_qspi_probe,
+ .remove = stm32_qspi_remove,
+ .driver = {
+ .name = "stm32-qspi",
+ .of_match_table = stm32_qspi_match,
+ },
+};
+module_platform_driver(stm32_qspi_driver);
+
+MODULE_AUTHOR("Ludovic Barre <ludovic.barre@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics STM32 quad spi driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 9da0bc5a036c..6ca59406b0b7 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -1,18 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* SPI init/core code
*
* Copyright (C) 2005 David Brownell
* Copyright (C) 2008 Secret Lab Technologies Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/kernel.h>
@@ -60,6 +51,7 @@ static void spidev_release(struct device *dev)
spi->controller->cleanup(spi);
spi_controller_put(spi->controller);
+ kfree(spi->driver_override);
kfree(spi);
}
@@ -77,6 +69,51 @@ modalias_show(struct device *dev, struct device_attribute *a, char *buf)
}
static DEVICE_ATTR_RO(modalias);
+static ssize_t driver_override_store(struct device *dev,
+ struct device_attribute *a,
+ const char *buf, size_t count)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ const char *end = memchr(buf, '\n', count);
+ const size_t len = end ? end - buf : count;
+ const char *driver_override, *old;
+
+ /* We need to keep extra room for a newline when displaying value */
+ if (len >= (PAGE_SIZE - 1))
+ return -EINVAL;
+
+ driver_override = kstrndup(buf, len, GFP_KERNEL);
+ if (!driver_override)
+ return -ENOMEM;
+
+ device_lock(dev);
+ old = spi->driver_override;
+ if (len) {
+ spi->driver_override = driver_override;
+ } else {
+ /* Emptry string, disable driver override */
+ spi->driver_override = NULL;
+ kfree(driver_override);
+ }
+ device_unlock(dev);
+ kfree(old);
+
+ return count;
+}
+
+static ssize_t driver_override_show(struct device *dev,
+ struct device_attribute *a, char *buf)
+{
+ const struct spi_device *spi = to_spi_device(dev);
+ ssize_t len;
+
+ device_lock(dev);
+ len = snprintf(buf, PAGE_SIZE, "%s\n", spi->driver_override ? : "");
+ device_unlock(dev);
+ return len;
+}
+static DEVICE_ATTR_RW(driver_override);
+
#define SPI_STATISTICS_ATTRS(field, file) \
static ssize_t spi_controller_##field##_show(struct device *dev, \
struct device_attribute *attr, \
@@ -158,6 +195,7 @@ SPI_STATISTICS_SHOW(transfers_split_maxsize, "%lu");
static struct attribute *spi_dev_attrs[] = {
&dev_attr_modalias.attr,
+ &dev_attr_driver_override.attr,
NULL,
};
@@ -305,6 +343,10 @@ static int spi_match_device(struct device *dev, struct device_driver *drv)
const struct spi_device *spi = to_spi_device(dev);
const struct spi_driver *sdrv = to_spi_driver(drv);
+ /* Check override first, and if set, only use the named driver */
+ if (spi->driver_override)
+ return strcmp(spi->driver_override, drv->name) == 0;
+
/* Attempt an OF style match */
if (of_driver_match_device(dev, drv))
return 1;
@@ -733,7 +775,9 @@ static void spi_set_cs(struct spi_device *spi, bool enable)
enable = !enable;
if (gpio_is_valid(spi->cs_gpio)) {
- gpio_set_value(spi->cs_gpio, !enable);
+ /* Honour the SPI_NO_CS flag */
+ if (!(spi->mode & SPI_NO_CS))
+ gpio_set_value(spi->cs_gpio, !enable);
/* Some SPI masters need both GPIO CS & slave_select */
if ((spi->controller->flags & SPI_MASTER_GPIO_SS) &&
spi->controller->set_cs)
@@ -2783,8 +2827,10 @@ int spi_setup(struct spi_device *spi)
return -EINVAL;
/* help drivers fail *cleanly* when they need options
* that aren't supported with their current controller
+ * SPI_CS_WORD has a fallback software implementation,
+ * so it is ignored here.
*/
- bad_bits = spi->mode & ~spi->controller->mode_bits;
+ bad_bits = spi->mode & ~(spi->controller->mode_bits | SPI_CS_WORD);
ugly_bits = bad_bits &
(SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD);
if (ugly_bits) {
@@ -2838,6 +2884,35 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
if (list_empty(&message->transfers))
return -EINVAL;
+ /* If an SPI controller does not support toggling the CS line on each
+ * transfer (indicated by the SPI_CS_WORD flag) or we are using a GPIO
+ * for the CS line, we can emulate the CS-per-word hardware function by
+ * splitting transfers into one-word transfers and ensuring that
+ * cs_change is set for each transfer.
+ */
+ if ((spi->mode & SPI_CS_WORD) && (!(ctlr->mode_bits & SPI_CS_WORD) ||
+ gpio_is_valid(spi->cs_gpio))) {
+ size_t maxsize;
+ int ret;
+
+ maxsize = (spi->bits_per_word + 7) / 8;
+
+ /* spi_split_transfers_maxsize() requires message->spi */
+ message->spi = spi;
+
+ ret = spi_split_transfers_maxsize(ctlr, message, maxsize,
+ GFP_KERNEL);
+ if (ret)
+ return ret;
+
+ list_for_each_entry(xfer, &message->transfers, transfer_list) {
+ /* don't change cs_change on the last entry in the list */
+ if (list_is_last(&xfer->transfer_list, &message->transfers))
+ break;
+ xfer->cs_change = 1;
+ }
+ }
+
/* Half-duplex links include original MicroWire, and ones with
* only one data pin like SPI_3WIRE (switches direction) or where
* either MOSI or MISO is missing. They can also be caused by
@@ -3323,20 +3398,23 @@ EXPORT_SYMBOL_GPL(spi_write_then_read);
/*-------------------------------------------------------------------------*/
-#if IS_ENABLED(CONFIG_OF_DYNAMIC)
+#if IS_ENABLED(CONFIG_OF)
static int __spi_of_device_match(struct device *dev, void *data)
{
return dev->of_node == data;
}
/* must call put_device() when done with returned spi_device device */
-static struct spi_device *of_find_spi_device_by_node(struct device_node *node)
+struct spi_device *of_find_spi_device_by_node(struct device_node *node)
{
struct device *dev = bus_find_device(&spi_bus_type, NULL, node,
__spi_of_device_match);
return dev ? to_spi_device(dev) : NULL;
}
+EXPORT_SYMBOL_GPL(of_find_spi_device_by_node);
+#endif /* IS_ENABLED(CONFIG_OF) */
+#if IS_ENABLED(CONFIG_OF_DYNAMIC)
static int __spi_of_controller_match(struct device *dev, const void *data)
{
return dev->of_node == data;
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index cda10719d1d1..b0c76e2626ce 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -669,6 +669,7 @@ static const struct of_device_id spidev_dt_ids[] = {
{ .compatible = "lineartechnology,ltc2488" },
{ .compatible = "ge,achc" },
{ .compatible = "semtech,sx1301" },
+ { .compatible = "lwn,bk4" },
{},
};
MODULE_DEVICE_TABLE(of, spidev_dt_ids);
@@ -724,11 +725,9 @@ static int spidev_probe(struct spi_device *spi)
* compatible string, it is a Linux implementation thing
* rather than a description of the hardware.
*/
- if (spi->dev.of_node && !of_match_device(spidev_dt_ids, &spi->dev)) {
- dev_err(&spi->dev, "buggy DT: spidev listed directly in DT\n");
- WARN_ON(spi->dev.of_node &&
- !of_match_device(spidev_dt_ids, &spi->dev));
- }
+ WARN(spi->dev.of_node &&
+ of_device_is_compatible(spi->dev.of_node, "spidev"),
+ "%pOF: buggy DT: spidev listed directly in DT\n", spi->dev.of_node);
spidev_probe_acpi(spi);
diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c
index 99a4656d113d..3861cb659cb9 100644
--- a/drivers/ssb/driver_chipcommon.c
+++ b/drivers/ssb/driver_chipcommon.c
@@ -425,7 +425,7 @@ void ssb_chipco_get_clockcontrol(struct ssb_chipcommon *cc,
*m = chipco_read32(cc, SSB_CHIPCO_CLOCK_M2);
break;
}
- /* Fallthough */
+ /* Fall through */
default:
*m = chipco_read32(cc, SSB_CHIPCO_CLOCK_SB);
}
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 1abf76be2aa8..7c015536360d 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -80,8 +80,6 @@ source "drivers/staging/netlogic/Kconfig"
source "drivers/staging/mt29f_spinand/Kconfig"
-source "drivers/staging/dgnc/Kconfig"
-
source "drivers/staging/gs_fpgaboot/Kconfig"
source "drivers/staging/unisys/Kconfig"
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index ab0cbe8815b1..a79b3fe20cf0 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -29,7 +29,6 @@ obj-$(CONFIG_STAGING_BOARD) += board/
obj-$(CONFIG_LTE_GDM724X) += gdm724x/
obj-$(CONFIG_FIREWIRE_SERIAL) += fwserial/
obj-$(CONFIG_GOLDFISH) += goldfish/
-obj-$(CONFIG_DGNC) += dgnc/
obj-$(CONFIG_MTD_SPINAND_MT29F) += mt29f_spinand/
obj-$(CONFIG_GS_FPGABOOT) += gs_fpgaboot/
obj-$(CONFIG_UNISYSSPAR) += unisys/
diff --git a/drivers/staging/android/ion/Kconfig b/drivers/staging/android/ion/Kconfig
index c16dd16afe6a..0fdda6f62953 100644
--- a/drivers/staging/android/ion/Kconfig
+++ b/drivers/staging/android/ion/Kconfig
@@ -1,6 +1,6 @@
menuconfig ION
bool "Ion Memory Manager"
- depends on HAVE_MEMBLOCK && HAS_DMA && MMU
+ depends on HAS_DMA && MMU
select GENERIC_ALLOCATOR
select DMA_SHARED_BUFFER
help
diff --git a/drivers/staging/android/ion/ion.h b/drivers/staging/android/ion/ion.h
index 16cbd38a7160..c006fc1e5a16 100644
--- a/drivers/staging/android/ion/ion.h
+++ b/drivers/staging/android/ion/ion.h
@@ -157,8 +157,6 @@ struct ion_heap_ops {
* @lock: protects the free list
* @waitqueue: queue to wait on from deferred free thread
* @task: task struct of deferred free thread
- * @debug_show: called when heap debug file is read to add any
- * heap specific debug info to output
*
* Represents a pool of memory from which buffers can be made. In some
* systems the only heap is regular system memory allocated via vmalloc.
@@ -179,9 +177,6 @@ struct ion_heap {
spinlock_t free_lock;
wait_queue_head_t waitqueue;
struct task_struct *task;
-
- int (*debug_show)(struct ion_heap *heap, struct seq_file *s,
- void *unused);
};
/**
diff --git a/drivers/staging/android/ion/ion_page_pool.c b/drivers/staging/android/ion/ion_page_pool.c
index 9bc56eb48d2a..0d2a95957ee8 100644
--- a/drivers/staging/android/ion/ion_page_pool.c
+++ b/drivers/staging/android/ion/ion_page_pool.c
@@ -33,8 +33,8 @@ static void ion_page_pool_add(struct ion_page_pool *pool, struct page *page)
pool->low_count++;
}
- mod_node_page_state(page_pgdat(page), NR_INDIRECTLY_RECLAIMABLE_BYTES,
- (1 << (PAGE_SHIFT + pool->order)));
+ mod_node_page_state(page_pgdat(page), NR_KERNEL_MISC_RECLAIMABLE,
+ 1 << pool->order);
mutex_unlock(&pool->mutex);
}
@@ -53,8 +53,8 @@ static struct page *ion_page_pool_remove(struct ion_page_pool *pool, bool high)
}
list_del(&page->lru);
- mod_node_page_state(page_pgdat(page), NR_INDIRECTLY_RECLAIMABLE_BYTES,
- -(1 << (PAGE_SHIFT + pool->order)));
+ mod_node_page_state(page_pgdat(page), NR_KERNEL_MISC_RECLAIMABLE,
+ -(1 << pool->order));
return page;
}
diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c
index 701eb9f3b0f1..548bb02c0ca6 100644
--- a/drivers/staging/android/ion/ion_system_heap.c
+++ b/drivers/staging/android/ion/ion_system_heap.c
@@ -212,29 +212,6 @@ static struct ion_heap_ops system_heap_ops = {
.shrink = ion_system_heap_shrink,
};
-static int ion_system_heap_debug_show(struct ion_heap *heap, struct seq_file *s,
- void *unused)
-{
- struct ion_system_heap *sys_heap = container_of(heap,
- struct ion_system_heap,
- heap);
- int i;
- struct ion_page_pool *pool;
-
- for (i = 0; i < NUM_ORDERS; i++) {
- pool = sys_heap->pools[i];
-
- seq_printf(s, "%d order %u highmem pages %lu total\n",
- pool->high_count, pool->order,
- (PAGE_SIZE << pool->order) * pool->high_count);
- seq_printf(s, "%d order %u lowmem pages %lu total\n",
- pool->low_count, pool->order,
- (PAGE_SIZE << pool->order) * pool->low_count);
- }
-
- return 0;
-}
-
static void ion_system_heap_destroy_pools(struct ion_page_pool **pools)
{
int i;
@@ -281,7 +258,6 @@ static struct ion_heap *__ion_system_heap_create(void)
if (ion_system_heap_create_pools(heap->pools))
goto free_heap;
- heap->heap.debug_show = ion_system_heap_debug_show;
return &heap->heap;
free_heap:
diff --git a/drivers/staging/axis-fifo/axis-fifo.c b/drivers/staging/axis-fifo/axis-fifo.c
index abeee0ecc122..c18bf31f55b6 100644
--- a/drivers/staging/axis-fifo/axis-fifo.c
+++ b/drivers/staging/axis-fifo/axis-fifo.c
@@ -27,8 +27,6 @@
#include <linux/interrupt.h>
#include <linux/param.h>
#include <linux/fs.h>
-#include <linux/device.h>
-#include <linux/cdev.h>
#include <linux/types.h>
#include <linux/uaccess.h>
#include <linux/jiffies.h>
@@ -364,11 +362,11 @@ static ssize_t axis_fifo_read(struct file *f, char __user *buf,
* if nothing is currently available
*/
spin_lock_irq(&fifo->read_queue_lock);
- ret = wait_event_interruptible_lock_irq_timeout(
- fifo->read_queue,
- ioread32(fifo->base_addr + XLLF_RDFO_OFFSET),
- fifo->read_queue_lock,
- (read_timeout >= 0) ? msecs_to_jiffies(read_timeout) :
+ ret = wait_event_interruptible_lock_irq_timeout
+ (fifo->read_queue,
+ ioread32(fifo->base_addr + XLLF_RDFO_OFFSET),
+ fifo->read_queue_lock,
+ (read_timeout >= 0) ? msecs_to_jiffies(read_timeout) :
MAX_SCHEDULE_TIMEOUT);
spin_unlock_irq(&fifo->read_queue_lock);
@@ -482,12 +480,12 @@ static ssize_t axis_fifo_write(struct file *f, const char __user *buf,
* currently enough room in the fifo
*/
spin_lock_irq(&fifo->write_queue_lock);
- ret = wait_event_interruptible_lock_irq_timeout(
- fifo->write_queue,
- ioread32(fifo->base_addr + XLLF_TDFV_OFFSET)
+ ret = wait_event_interruptible_lock_irq_timeout
+ (fifo->write_queue,
+ ioread32(fifo->base_addr + XLLF_TDFV_OFFSET)
>= words_to_write,
- fifo->write_queue_lock,
- (write_timeout >= 0) ? msecs_to_jiffies(write_timeout) :
+ fifo->write_queue_lock,
+ (write_timeout >= 0) ? msecs_to_jiffies(write_timeout) :
MAX_SCHEDULE_TIMEOUT);
spin_unlock_irq(&fifo->write_queue_lock);
@@ -1089,6 +1087,8 @@ static int __init axis_fifo_init(void)
pr_info("axis-fifo driver loaded with parameters read_timeout = %i, write_timeout = %i\n",
read_timeout, write_timeout);
axis_fifo_driver_class = class_create(THIS_MODULE, DRIVER_NAME);
+ if (IS_ERR(axis_fifo_driver_class))
+ return PTR_ERR(axis_fifo_driver_class);
return platform_driver_register(&axis_fifo_driver);
}
diff --git a/drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c b/drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c
index cae7e6e695b0..15b7a82f4b1e 100644
--- a/drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c
+++ b/drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c
@@ -199,10 +199,10 @@ static int clk_wzrd_probe(struct platform_device *pdev)
ret = -ENOMEM;
goto err_disable_clk;
}
- clk_wzrd->clks_internal[wzrd_clk_mul] = clk_register_fixed_factor(
- &pdev->dev, clk_name,
- __clk_get_name(clk_wzrd->clk_in1),
- 0, reg, 1);
+ clk_wzrd->clks_internal[wzrd_clk_mul] = clk_register_fixed_factor
+ (&pdev->dev, clk_name,
+ __clk_get_name(clk_wzrd->clk_in1),
+ 0, reg, 1);
kfree(clk_name);
if (IS_ERR(clk_wzrd->clks_internal[wzrd_clk_mul])) {
dev_err(&pdev->dev, "unable to register fixed-factor clock\n");
@@ -219,10 +219,10 @@ static int clk_wzrd_probe(struct platform_device *pdev)
goto err_rm_int_clk;
}
- clk_wzrd->clks_internal[wzrd_clk_mul_div] = clk_register_fixed_factor(
- &pdev->dev, clk_name,
- __clk_get_name(clk_wzrd->clks_internal[wzrd_clk_mul]),
- 0, 1, reg);
+ clk_wzrd->clks_internal[wzrd_clk_mul_div] = clk_register_fixed_factor
+ (&pdev->dev, clk_name,
+ __clk_get_name(clk_wzrd->clks_internal[wzrd_clk_mul]),
+ 0, 1, reg);
if (IS_ERR(clk_wzrd->clks_internal[wzrd_clk_mul_div])) {
dev_err(&pdev->dev, "unable to register divider clock\n");
ret = PTR_ERR(clk_wzrd->clks_internal[wzrd_clk_mul_div]);
@@ -243,8 +243,8 @@ static int clk_wzrd_probe(struct platform_device *pdev)
reg = readl(clk_wzrd->base + WZRD_CLK_CFG_REG(2) + i * 12);
reg &= WZRD_CLKOUT_DIVIDE_MASK;
reg >>= WZRD_CLKOUT_DIVIDE_SHIFT;
- clk_wzrd->clkout[i] = clk_register_fixed_factor(&pdev->dev,
- clkout_name, clk_name, 0, 1, reg);
+ clk_wzrd->clkout[i] = clk_register_fixed_factor
+ (&pdev->dev, clkout_name, clk_name, 0, 1, reg);
if (IS_ERR(clk_wzrd->clkout[i])) {
int j;
diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig
index 583bce9bb18e..9ab1ee7d36bf 100644
--- a/drivers/staging/comedi/Kconfig
+++ b/drivers/staging/comedi/Kconfig
@@ -1313,5 +1313,9 @@ config COMEDI_NI_LABPC_ISADMA
config COMEDI_NI_TIO
tristate
+ select COMEDI_NI_ROUTING
+
+config COMEDI_NI_ROUTING
+ tristate
endif # COMEDI
diff --git a/drivers/staging/comedi/comedi.h b/drivers/staging/comedi/comedi.h
index bb961ac79b7e..e90b17775284 100644
--- a/drivers/staging/comedi/comedi.h
+++ b/drivers/staging/comedi/comedi.h
@@ -107,6 +107,7 @@
#define INSN_WRITE (1 | INSN_MASK_WRITE)
#define INSN_BITS (2 | INSN_MASK_READ | INSN_MASK_WRITE)
#define INSN_CONFIG (3 | INSN_MASK_READ | INSN_MASK_WRITE)
+#define INSN_DEVICE_CONFIG (INSN_CONFIG | INSN_MASK_SPECIAL)
#define INSN_GTOD (4 | INSN_MASK_READ | INSN_MASK_SPECIAL)
#define INSN_WAIT (5 | INSN_MASK_WRITE | INSN_MASK_SPECIAL)
#define INSN_INTTRIG (6 | INSN_MASK_WRITE | INSN_MASK_SPECIAL)
@@ -301,6 +302,8 @@ enum comedi_io_direction {
* @INSN_CONFIG_PWM_SET_H_BRIDGE: Set PWM H bridge duty cycle and polarity for
* a relay simultaneously.
* @INSN_CONFIG_PWM_GET_H_BRIDGE: Get PWM H bridge duty cycle and polarity.
+ * @INSN_CONFIG_GET_CMD_TIMING_CONSTRAINTS: Get the hardware timing restraints,
+ * regardless of trigger sources.
*/
enum configuration_ids {
INSN_CONFIG_DIO_INPUT = COMEDI_INPUT,
@@ -344,7 +347,25 @@ enum configuration_ids {
INSN_CONFIG_PWM_GET_PERIOD = 5001,
INSN_CONFIG_GET_PWM_STATUS = 5002,
INSN_CONFIG_PWM_SET_H_BRIDGE = 5003,
- INSN_CONFIG_PWM_GET_H_BRIDGE = 5004
+ INSN_CONFIG_PWM_GET_H_BRIDGE = 5004,
+ INSN_CONFIG_GET_CMD_TIMING_CONSTRAINTS = 5005,
+};
+
+/**
+ * enum device_configuration_ids - COMEDI configuration instruction codes global
+ * to an entire device.
+ * @INSN_DEVICE_CONFIG_TEST_ROUTE: Validate the possibility of a
+ * globally-named route
+ * @INSN_DEVICE_CONFIG_CONNECT_ROUTE: Connect a globally-named route
+ * @INSN_DEVICE_CONFIG_DISCONNECT_ROUTE:Disconnect a globally-named route
+ * @INSN_DEVICE_CONFIG_GET_ROUTES: Get a list of all globally-named routes
+ * that are valid for a particular device.
+ */
+enum device_config_route_ids {
+ INSN_DEVICE_CONFIG_TEST_ROUTE = 0,
+ INSN_DEVICE_CONFIG_CONNECT_ROUTE = 1,
+ INSN_DEVICE_CONFIG_DISCONNECT_ROUTE = 2,
+ INSN_DEVICE_CONFIG_GET_ROUTES = 3,
};
/**
@@ -928,6 +949,157 @@ enum i8254_mode {
I8254_BINARY = 0
};
+/* *** BEGIN GLOBALLY-NAMED NI TERMINALS/SIGNALS *** */
+
+/*
+ * Common National Instruments Terminal/Signal names.
+ * Some of these have no NI_ prefix as they are useful for non-NI hardware, such
+ * as those that utilize the PXI/RTSI trigger lines.
+ *
+ * NOTE ABOUT THE CHOICE OF NAMES HERE AND THE CAMELSCRIPT:
+ * The choice to use CamelScript and the exact names below is for
+ * maintainability, clarity, similarity to manufacturer's documentation,
+ * _and_ a mitigation for confusion that has plagued the use of these drivers
+ * for years!
+ *
+ * More detail:
+ * There have been significant confusions over the past many years for users
+ * when trying to understand how to connect to/from signals and terminals on
+ * NI hardware using comedi. The major reason for this is that the actual
+ * register values were exposed and required to be used by users. Several
+ * major reasons exist why this caused major confusion for users:
+ * 1) The register values are _NOT_ in user documentation, but rather in
+ * arcane locations, such as a few register programming manuals that are
+ * increasingly hard to find and the NI MHDDK (comments in in example code).
+ * There is no one place to find the various valid values of the registers.
+ * 2) The register values are _NOT_ completely consistent. There is no way to
+ * gain any sense of intuition of which values, or even enums one should use
+ * for various registers. There was some attempt in prior use of comedi to
+ * name enums such that a user might know which enums should be used for
+ * varying purposes, but the end-user had to gain a knowledge of register
+ * values to correctly wield this approach.
+ * 3) The names for signals and registers found in the various register level
+ * programming manuals and vendor-provided documentation are _not_ even
+ * close to the same names that are in the end-user documentation.
+ *
+ * Similar, albeit less, confusion plagued NI's previous version of their own
+ * drivers. Earlier than 2003, NI greatly simplified the situation for users
+ * by releasing a new API that abstracted the names of signals/terminals to a
+ * common and intuitive set of names.
+ *
+ * The names below mirror the names chosen and well documented by NI. These
+ * names are exposed to the user via the comedilib user library. By keeping
+ * the names below, in spite of the use of CamelScript, maintenance will be
+ * greatly eased and confusion for users _and_ comedi developers will be
+ * greatly reduced.
+ */
+
+/*
+ * Base of abstracted NI names.
+ * The first 16 bits of *_arg are reserved for channel selection.
+ * Since we only actually need the first 4 or 5 bits for all register values on
+ * NI select registers anyways, we'll identify all values >= (1<<15) as being an
+ * abstracted NI signal/terminal name.
+ * These values are also used/returned by INSN_DEVICE_CONFIG_TEST_ROUTE,
+ * INSN_DEVICE_CONFIG_CONNECT_ROUTE, INSN_DEVICE_CONFIG_DISCONNECT_ROUTE,
+ * and INSN_DEVICE_CONFIG_GET_ROUTES.
+ */
+#define NI_NAMES_BASE 0x8000u
+/*
+ * not necessarily all allowed 64 PFIs are valid--certainly not for all devices
+ */
+#define NI_PFI(x) (NI_NAMES_BASE + ((x) & 0x3f))
+/* 8 trigger lines by standard, Some devices cannot talk to all eight. */
+#define TRIGGER_LINE(x) (NI_PFI(-1) + 1 + ((x) & 0x7))
+/* 4 RTSI shared MUXes to route signals to/from TRIGGER_LINES on NI hardware */
+#define NI_RTSI_BRD(x) (TRIGGER_LINE(-1) + 1 + ((x) & 0x3))
+
+/* *** Counter/timer names : 8 counters max *** */
+#define NI_COUNTER_NAMES_BASE (NI_RTSI_BRD(-1) + 1)
+#define NI_MAX_COUNTERS 7
+#define NI_CtrSource(x) (NI_COUNTER_NAMES_BASE + ((x) & NI_MAX_COUNTERS))
+/* Gate, Aux, A,B,Z are all treated, at times as gates */
+#define NI_GATES_NAMES_BASE (NI_CtrSource(-1) + 1)
+#define NI_CtrGate(x) (NI_GATES_NAMES_BASE + ((x) & NI_MAX_COUNTERS))
+#define NI_CtrAux(x) (NI_CtrGate(-1) + 1 + ((x) & NI_MAX_COUNTERS))
+#define NI_CtrA(x) (NI_CtrAux(-1) + 1 + ((x) & NI_MAX_COUNTERS))
+#define NI_CtrB(x) (NI_CtrA(-1) + 1 + ((x) & NI_MAX_COUNTERS))
+#define NI_CtrZ(x) (NI_CtrB(-1) + 1 + ((x) & NI_MAX_COUNTERS))
+#define NI_GATES_NAMES_MAX NI_CtrZ(-1)
+#define NI_CtrArmStartTrigger(x) (NI_CtrZ(-1) + 1 + ((x) & NI_MAX_COUNTERS))
+#define NI_CtrInternalOutput(x) \
+ (NI_CtrArmStartTrigger(-1) + 1 + ((x) & NI_MAX_COUNTERS))
+/** external pin(s) labeled conveniently as Ctr<i>Out. */
+#define NI_CtrOut(x) (NI_CtrInternalOutput(-1) + 1 + ((x) & NI_MAX_COUNTERS))
+/** For Buffered sampling of ctr -- x series capability. */
+#define NI_CtrSampleClock(x) (NI_CtrOut(-1) + 1 + ((x) & NI_MAX_COUNTERS))
+#define NI_COUNTER_NAMES_MAX NI_CtrSampleClock(-1)
+
+enum ni_common_signal_names {
+ /* PXI_Star: this is a non-NI-specific signal */
+ PXI_Star = NI_COUNTER_NAMES_MAX + 1,
+ PXI_Clk10,
+ PXIe_Clk100,
+ NI_AI_SampleClock,
+ NI_AI_SampleClockTimebase,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_ConvertClockTimebase,
+ NI_AI_PauseTrigger,
+ NI_AI_HoldCompleteEvent,
+ NI_AI_HoldComplete,
+ NI_AI_ExternalMUXClock,
+ NI_AI_STOP, /* pulse signal that occurs when a update is finished(?) */
+ NI_AO_SampleClock,
+ NI_AO_SampleClockTimebase,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_SampleClockTimebase,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DI_InputBufferFull,
+ NI_DI_ReadyForStartEvent,
+ NI_DI_ReadyForTransferEventBurst,
+ NI_DI_ReadyForTransferEventPipelined,
+ NI_DO_SampleClock,
+ NI_DO_SampleClockTimebase,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_DO_OutputBufferFull,
+ NI_DO_DataActiveEvent,
+ NI_DO_ReadyForStartEvent,
+ NI_DO_ReadyForTransferEvent,
+ NI_MasterTimebase,
+ NI_20MHzTimebase,
+ NI_80MHzTimebase,
+ NI_100MHzTimebase,
+ NI_200MHzTimebase,
+ NI_100kHzTimebase,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ NI_WatchdogExpiredEvent,
+ NI_WatchdogExpirationTrigger,
+ NI_SCXI_Trig1,
+ NI_LogicLow,
+ NI_LogicHigh,
+ NI_ExternalStrobe,
+ NI_PFI_DO,
+ NI_CaseGround,
+ /* special internal signal used as variable source for RTSI bus: */
+ NI_RGOUT0,
+
+ /* just a name to make the next more convenient, regardless of above */
+ _NI_NAMES_MAX_PLUS_1,
+ NI_NUM_NAMES = _NI_NAMES_MAX_PLUS_1 - NI_NAMES_BASE,
+};
+
+/* *** END GLOBALLY-NAMED NI TERMINALS/SIGNALS *** */
+
#define NI_USUAL_PFI_SELECT(x) (((x) < 10) ? (0x1 + (x)) : (0xb + (x)))
#define NI_USUAL_RTSI_SELECT(x) (((x) < 7) ? (0xb + (x)) : 0x1b)
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index e18b61cdbdeb..c1c6b2b4ab91 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -1216,6 +1216,10 @@ static int check_insn_config_length(struct comedi_insn *insn,
if (insn->n == 6)
return 0;
break;
+ case INSN_CONFIG_GET_CMD_TIMING_CONSTRAINTS:
+ if (insn->n >= 4)
+ return 0;
+ break;
/*
* by default we allow the insn since we don't have checks for
* all possible cases yet
@@ -1230,6 +1234,57 @@ static int check_insn_config_length(struct comedi_insn *insn,
return -EINVAL;
}
+static int check_insn_device_config_length(struct comedi_insn *insn,
+ unsigned int *data)
+{
+ if (insn->n < 1)
+ return -EINVAL;
+
+ switch (data[0]) {
+ case INSN_DEVICE_CONFIG_TEST_ROUTE:
+ case INSN_DEVICE_CONFIG_CONNECT_ROUTE:
+ case INSN_DEVICE_CONFIG_DISCONNECT_ROUTE:
+ if (insn->n == 3)
+ return 0;
+ break;
+ case INSN_DEVICE_CONFIG_GET_ROUTES:
+ /*
+ * Big enough for config_id and the length of the userland
+ * memory buffer. Additional length should be in factors of 2
+ * to communicate any returned route pairs (source,destination).
+ */
+ if (insn->n >= 2)
+ return 0;
+ break;
+ }
+ return -EINVAL;
+}
+
+/**
+ * get_valid_routes() - Calls low-level driver get_valid_routes function to
+ * either return a count of valid routes to user, or copy
+ * of list of all valid device routes to buffer in
+ * userspace.
+ * @dev: comedi device pointer
+ * @data: data from user insn call. The length of the data must be >= 2.
+ * data[0] must contain the INSN_DEVICE_CONFIG config_id.
+ * data[1](input) contains the number of _pairs_ for which memory is
+ * allotted from the user. If the user specifies '0', then only
+ * the number of pairs available is returned.
+ * data[1](output) returns either the number of pairs available (if none
+ * where requested) or the number of _pairs_ that are copied back
+ * to the user.
+ * data[2::2] returns each (source, destination) pair.
+ *
+ * Return: -EINVAL if low-level driver does not allocate and return routes as
+ * expected. Returns 0 otherwise.
+ */
+static int get_valid_routes(struct comedi_device *dev, unsigned int *data)
+{
+ data[1] = dev->get_valid_routes(dev, data[1], data + 2);
+ return 0;
+}
+
static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
unsigned int *data, void *file)
{
@@ -1293,6 +1348,24 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
if (ret >= 0)
ret = 1;
break;
+ case INSN_DEVICE_CONFIG:
+ ret = check_insn_device_config_length(insn, data);
+ if (ret)
+ break;
+
+ if (data[0] == INSN_DEVICE_CONFIG_GET_ROUTES) {
+ /*
+ * data[1] should be the number of _pairs_ that
+ * the memory can hold.
+ */
+ data[1] = (insn->n - 2) / 2;
+ ret = get_valid_routes(dev, data);
+ break;
+ }
+
+ /* other global device config instructions. */
+ ret = dev->insn_device_config(dev, insn, data);
+ break;
default:
dev_dbg(dev->class_dev, "invalid insn\n");
ret = -EINVAL;
diff --git a/drivers/staging/comedi/comedidev.h b/drivers/staging/comedi/comedidev.h
index 5775a93917f4..a7d569cfca5d 100644
--- a/drivers/staging/comedi/comedidev.h
+++ b/drivers/staging/comedi/comedidev.h
@@ -516,6 +516,15 @@ struct comedi_driver {
* called when @use_count changes from 0 to 1.
* @close: Optional pointer to a function set by the low-level driver to be
* called when @use_count changed from 1 to 0.
+ * @insn_device_config: Optional pointer to a handler for all sub-instructions
+ * except %INSN_DEVICE_CONFIG_GET_ROUTES of the %INSN_DEVICE_CONFIG
+ * instruction. If this is not initialized by the low-level driver, a
+ * default handler will be set during post-configuration.
+ * @get_valid_routes: Optional pointer to a handler for the
+ * %INSN_DEVICE_CONFIG_GET_ROUTES sub-instruction of the
+ * %INSN_DEVICE_CONFIG instruction set. If this is not initialized by the
+ * low-level driver, a default handler that copies zero routes back to the
+ * user will be used.
*
* This is the main control data structure for a COMEDI device (as far as the
* COMEDI core is concerned). There are two groups of COMEDI devices -
@@ -565,6 +574,11 @@ struct comedi_device {
int (*open)(struct comedi_device *dev);
void (*close)(struct comedi_device *dev);
+ int (*insn_device_config)(struct comedi_device *dev,
+ struct comedi_insn *insn, unsigned int *data);
+ unsigned int (*get_valid_routes)(struct comedi_device *dev,
+ unsigned int n_pairs,
+ unsigned int *pair_data);
};
/*
diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c
index 57dd63d548b7..eefa62f42c0f 100644
--- a/drivers/staging/comedi/drivers.c
+++ b/drivers/staging/comedi/drivers.c
@@ -211,6 +211,19 @@ static int poll_invalid(struct comedi_device *dev, struct comedi_subdevice *s)
return -EINVAL;
}
+static int insn_device_inval(struct comedi_device *dev,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ return -EINVAL;
+}
+
+static unsigned int get_zero_valid_routes(struct comedi_device *dev,
+ unsigned int n_pairs,
+ unsigned int *pair_data)
+{
+ return 0;
+}
+
int insn_inval(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
@@ -652,6 +665,12 @@ static int __comedi_device_postconfig(struct comedi_device *dev)
int ret;
int i;
+ if (!dev->insn_device_config)
+ dev->insn_device_config = insn_device_inval;
+
+ if (!dev->get_valid_routes)
+ dev->get_valid_routes = get_zero_valid_routes;
+
for (i = 0; i < dev->n_subdevices; i++) {
s = &dev->subdevices[i];
diff --git a/drivers/staging/comedi/drivers/Makefile b/drivers/staging/comedi/drivers/Makefile
index 98b42b47dfe1..b24ac00cab73 100644
--- a/drivers/staging/comedi/drivers/Makefile
+++ b/drivers/staging/comedi/drivers/Makefile
@@ -137,6 +137,33 @@ obj-$(CONFIG_COMEDI_VMK80XX) += vmk80xx.o
obj-$(CONFIG_COMEDI_MITE) += mite.o
obj-$(CONFIG_COMEDI_NI_TIO) += ni_tio.o
obj-$(CONFIG_COMEDI_NI_TIOCMD) += ni_tiocmd.o
+obj-$(CONFIG_COMEDI_NI_ROUTING) += ni_routing.o
+ni_routing-objs += ni_routes.o \
+ ni_routing/ni_route_values.o \
+ ni_routing/ni_route_values/ni_660x.o \
+ ni_routing/ni_route_values/ni_eseries.o \
+ ni_routing/ni_route_values/ni_mseries.o \
+ ni_routing/ni_device_routes.o \
+ ni_routing/ni_device_routes/pxi-6030e.o \
+ ni_routing/ni_device_routes/pci-6070e.o \
+ ni_routing/ni_device_routes/pci-6220.o \
+ ni_routing/ni_device_routes/pci-6221.o \
+ ni_routing/ni_device_routes/pxi-6224.o \
+ ni_routing/ni_device_routes/pxi-6225.o \
+ ni_routing/ni_device_routes/pci-6229.o \
+ ni_routing/ni_device_routes/pci-6251.o \
+ ni_routing/ni_device_routes/pxi-6251.o \
+ ni_routing/ni_device_routes/pxie-6251.o \
+ ni_routing/ni_device_routes/pci-6254.o \
+ ni_routing/ni_device_routes/pci-6259.o \
+ ni_routing/ni_device_routes/pci-6534.o \
+ ni_routing/ni_device_routes/pxie-6535.o \
+ ni_routing/ni_device_routes/pci-6602.o \
+ ni_routing/ni_device_routes/pci-6713.o \
+ ni_routing/ni_device_routes/pci-6723.o \
+ ni_routing/ni_device_routes/pci-6733.o \
+ ni_routing/ni_device_routes/pxi-6733.o \
+ ni_routing/ni_device_routes/pxie-6738.o
obj-$(CONFIG_COMEDI_NI_LABPC) += ni_labpc_common.o
obj-$(CONFIG_COMEDI_NI_LABPC_ISADMA) += ni_labpc_isadma.o
@@ -145,3 +172,4 @@ obj-$(CONFIG_COMEDI_8255_SA) += 8255.o
obj-$(CONFIG_COMEDI_AMPLC_DIO200) += amplc_dio200_common.o
obj-$(CONFIG_COMEDI_AMPLC_PC236) += amplc_pc236_common.o
obj-$(CONFIG_COMEDI_DAS08) += das08.o
+obj-$(CONFIG_COMEDI_TESTS) += tests/
diff --git a/drivers/staging/comedi/drivers/comedi_test.c b/drivers/staging/comedi/drivers/comedi_test.c
index d437af721bd8..ef4c7c8a2b71 100644
--- a/drivers/staging/comedi/drivers/comedi_test.c
+++ b/drivers/staging/comedi/drivers/comedi_test.c
@@ -626,6 +626,48 @@ static int waveform_ao_insn_write(struct comedi_device *dev,
return insn->n;
}
+static int waveform_ai_insn_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ if (data[0] == INSN_CONFIG_GET_CMD_TIMING_CONSTRAINTS) {
+ /*
+ * input: data[1], data[2] : scan_begin_src, convert_src
+ * output: data[1], data[2] : scan_begin_min, convert_min
+ */
+ if (data[1] == TRIG_FOLLOW) {
+ /* exactly TRIG_FOLLOW case */
+ data[1] = 0;
+ data[2] = NSEC_PER_USEC;
+ } else {
+ data[1] = NSEC_PER_USEC;
+ if (data[2] & TRIG_TIMER)
+ data[2] = NSEC_PER_USEC;
+ else
+ data[2] = 0;
+ }
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int waveform_ao_insn_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ if (data[0] == INSN_CONFIG_GET_CMD_TIMING_CONSTRAINTS) {
+ /* we don't care about actual channels */
+ data[1] = NSEC_PER_USEC; /* scan_begin_min */
+ data[2] = 0; /* convert_min */
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
static int waveform_common_attach(struct comedi_device *dev,
int amplitude, int period)
{
@@ -658,6 +700,7 @@ static int waveform_common_attach(struct comedi_device *dev,
s->do_cmd = waveform_ai_cmd;
s->do_cmdtest = waveform_ai_cmdtest;
s->cancel = waveform_ai_cancel;
+ s->insn_config = waveform_ai_insn_config;
s = &dev->subdevices[1];
dev->write_subdev = s;
@@ -673,6 +716,7 @@ static int waveform_common_attach(struct comedi_device *dev,
s->do_cmd = waveform_ao_cmd;
s->do_cmdtest = waveform_ao_cmdtest;
s->cancel = waveform_ao_cancel;
+ s->insn_config = waveform_ao_insn_config;
/* Our default loopback value is just a 0V flatline */
for (i = 0; i < s->n_chan; i++)
diff --git a/drivers/staging/comedi/drivers/ni_660x.c b/drivers/staging/comedi/drivers/ni_660x.c
index e521ed9d0887..e70a461e723f 100644
--- a/drivers/staging/comedi/drivers/ni_660x.c
+++ b/drivers/staging/comedi/drivers/ni_660x.c
@@ -7,7 +7,7 @@
* Driver: ni_660x
* Description: National Instruments 660x counter/timer boards
* Devices: [National Instruments] PCI-6601 (ni_660x), PCI-6602, PXI-6602,
- * PXI-6608, PCI-6624, PXI-6624
+ * PCI-6608, PXI-6608, PCI-6624, PXI-6624
* Author: J.P. Mellor <jpmellor@rose-hulman.edu>,
* Herman.Bruyninckx@mech.kuleuven.ac.be,
* Wim.Meeussen@mech.kuleuven.ac.be,
@@ -31,6 +31,7 @@
#include "mite.h"
#include "ni_tio.h"
+#include "ni_routes.h"
/* See Register-Level Programmer Manual page 3.1 */
enum ni_660x_register {
@@ -201,6 +202,7 @@ enum ni_660x_boardid {
BOARD_PCI6601,
BOARD_PCI6602,
BOARD_PXI6602,
+ BOARD_PCI6608,
BOARD_PXI6608,
BOARD_PCI6624,
BOARD_PXI6624
@@ -224,6 +226,10 @@ static const struct ni_660x_board ni_660x_boards[] = {
.name = "PXI-6602",
.n_chips = 2,
},
+ [BOARD_PCI6608] = {
+ .name = "PCI-6608",
+ .n_chips = 2,
+ },
[BOARD_PXI6608] = {
.name = "PXI-6608",
.n_chips = 2,
@@ -259,6 +265,7 @@ struct ni_660x_private {
unsigned int dma_cfg[NI660X_MAX_CHIPS];
unsigned int io_cfg[NI660X_NUM_PFI_CHANNELS];
u64 io_dir;
+ struct ni_route_tables routing_tables;
};
static void ni_660x_write(struct comedi_device *dev, unsigned int chip,
@@ -561,6 +568,10 @@ static void ni_660x_select_pfi_output(struct comedi_device *dev,
unsigned int idle_chip = 0;
unsigned int bits;
+ if (chan >= NI_PFI(0))
+ /* allow new and old names of pfi channels to work. */
+ chan -= NI_PFI(0);
+
if (board->n_chips > 1) {
if (out_sel == NI_660X_PFI_OUTPUT_COUNTER &&
chan >= 8 && chan <= 23) {
@@ -589,11 +600,54 @@ static void ni_660x_select_pfi_output(struct comedi_device *dev,
ni_660x_write(dev, active_chip, bits, NI660X_IO_CFG(chan));
}
+static void ni_660x_set_pfi_direction(struct comedi_device *dev,
+ unsigned int chan,
+ unsigned int direction)
+{
+ struct ni_660x_private *devpriv = dev->private;
+ u64 bit;
+
+ if (chan >= NI_PFI(0))
+ /* allow new and old names of pfi channels to work. */
+ chan -= NI_PFI(0);
+
+ bit = 1ULL << chan;
+
+ if (direction == COMEDI_OUTPUT) {
+ devpriv->io_dir |= bit;
+ /* reset the output to currently assigned output value */
+ ni_660x_select_pfi_output(dev, chan, devpriv->io_cfg[chan]);
+ } else {
+ devpriv->io_dir &= ~bit;
+ /* set pin to high-z; do not change currently assigned route */
+ ni_660x_select_pfi_output(dev, chan, 0);
+ }
+}
+
+static unsigned int ni_660x_get_pfi_direction(struct comedi_device *dev,
+ unsigned int chan)
+{
+ struct ni_660x_private *devpriv = dev->private;
+ u64 bit;
+
+ if (chan >= NI_PFI(0))
+ /* allow new and old names of pfi channels to work. */
+ chan -= NI_PFI(0);
+
+ bit = 1ULL << chan;
+
+ return (devpriv->io_dir & bit) ? COMEDI_OUTPUT : COMEDI_INPUT;
+}
+
static int ni_660x_set_pfi_routing(struct comedi_device *dev,
unsigned int chan, unsigned int source)
{
struct ni_660x_private *devpriv = dev->private;
+ if (chan >= NI_PFI(0))
+ /* allow new and old names of pfi channels to work. */
+ chan -= NI_PFI(0);
+
switch (source) {
case NI_660X_PFI_OUTPUT_COUNTER:
if (chan < 8)
@@ -607,36 +661,56 @@ static int ni_660x_set_pfi_routing(struct comedi_device *dev,
}
devpriv->io_cfg[chan] = source;
- if (devpriv->io_dir & (1ULL << chan))
+ if (ni_660x_get_pfi_direction(dev, chan) == COMEDI_OUTPUT)
ni_660x_select_pfi_output(dev, chan, devpriv->io_cfg[chan]);
return 0;
}
+static int ni_660x_get_pfi_routing(struct comedi_device *dev, unsigned int chan)
+{
+ struct ni_660x_private *devpriv = dev->private;
+
+ if (chan >= NI_PFI(0))
+ /* allow new and old names of pfi channels to work. */
+ chan -= NI_PFI(0);
+
+ return devpriv->io_cfg[chan];
+}
+
+static void ni_660x_set_pfi_filter(struct comedi_device *dev,
+ unsigned int chan, unsigned int value)
+{
+ unsigned int val;
+
+ if (chan >= NI_PFI(0))
+ /* allow new and old names of pfi channels to work. */
+ chan -= NI_PFI(0);
+
+ val = ni_660x_read(dev, 0, NI660X_IO_CFG(chan));
+ val &= ~NI660X_IO_CFG_IN_SEL_MASK(chan);
+ val |= NI660X_IO_CFG_IN_SEL(chan, value);
+ ni_660x_write(dev, 0, val, NI660X_IO_CFG(chan));
+}
+
static int ni_660x_dio_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
unsigned int *data)
{
- struct ni_660x_private *devpriv = dev->private;
unsigned int chan = CR_CHAN(insn->chanspec);
- u64 bit = 1ULL << chan;
- unsigned int val;
int ret;
switch (data[0]) {
case INSN_CONFIG_DIO_OUTPUT:
- devpriv->io_dir |= bit;
- ni_660x_select_pfi_output(dev, chan, devpriv->io_cfg[chan]);
+ ni_660x_set_pfi_direction(dev, chan, COMEDI_OUTPUT);
break;
case INSN_CONFIG_DIO_INPUT:
- devpriv->io_dir &= ~bit;
- ni_660x_select_pfi_output(dev, chan, 0); /* high-z */
+ ni_660x_set_pfi_direction(dev, chan, COMEDI_INPUT);
break;
case INSN_CONFIG_DIO_QUERY:
- data[1] = (devpriv->io_dir & bit) ? COMEDI_OUTPUT
- : COMEDI_INPUT;
+ data[1] = ni_660x_get_pfi_direction(dev, chan);
break;
case INSN_CONFIG_SET_ROUTING:
@@ -646,14 +720,11 @@ static int ni_660x_dio_insn_config(struct comedi_device *dev,
break;
case INSN_CONFIG_GET_ROUTING:
- data[1] = devpriv->io_cfg[chan];
+ data[1] = ni_660x_get_pfi_routing(dev, chan);
break;
case INSN_CONFIG_FILTER:
- val = ni_660x_read(dev, 0, NI660X_IO_CFG(chan));
- val &= ~NI660X_IO_CFG_IN_SEL_MASK(chan);
- val |= NI660X_IO_CFG_IN_SEL(chan, data[1]);
- ni_660x_write(dev, 0, val, NI660X_IO_CFG(chan));
+ ni_660x_set_pfi_filter(dev, chan, data[1]);
break;
default:
@@ -663,6 +734,240 @@ static int ni_660x_dio_insn_config(struct comedi_device *dev,
return insn->n;
}
+static unsigned int _ni_get_valid_routes(struct comedi_device *dev,
+ unsigned int n_pairs,
+ unsigned int *pair_data)
+{
+ struct ni_660x_private *devpriv = dev->private;
+
+ return ni_get_valid_routes(&devpriv->routing_tables, n_pairs,
+ pair_data);
+}
+
+/*
+ * Retrieves the current source of the output selector for the given
+ * destination. If the terminal for the destination is not already configured
+ * as an output, this function returns -EINVAL as error.
+ *
+ * Return: The register value of the destination output selector;
+ * -EINVAL if terminal is not configured for output.
+ */
+static inline int get_output_select_source(int dest, struct comedi_device *dev)
+{
+ struct ni_660x_private *devpriv = dev->private;
+ int reg = -1;
+
+ if (channel_is_pfi(dest)) {
+ if (ni_660x_get_pfi_direction(dev, dest) == COMEDI_OUTPUT)
+ reg = ni_660x_get_pfi_routing(dev, dest);
+ } else if (channel_is_rtsi(dest)) {
+ dev_dbg(dev->class_dev,
+ "%s: unhandled rtsi destination (%d) queried\n",
+ __func__, dest);
+ /*
+ * The following can be enabled when RTSI routing info is
+ * determined (not currently documented):
+ * if (ni_get_rtsi_direction(dev, dest) == COMEDI_OUTPUT) {
+ * reg = ni_get_rtsi_routing(dev, dest);
+
+ * if (reg == NI_RTSI_OUTPUT_RGOUT0) {
+ * dest = NI_RGOUT0; ** prepare for lookup below **
+ * reg = get_rgout0_reg(dev);
+ * } else if (reg >= NI_RTSI_OUTPUT_RTSI_BRD(0) &&
+ * reg <= NI_RTSI_OUTPUT_RTSI_BRD(3)) {
+ * const int i = reg - NI_RTSI_OUTPUT_RTSI_BRD(0);
+
+ * dest = NI_RTSI_BRD(i); ** prepare for lookup **
+ * reg = get_ith_rtsi_brd_reg(i, dev);
+ * }
+ * }
+ */
+ } else if (channel_is_ctr(dest)) {
+ reg = ni_tio_get_routing(devpriv->counter_dev, dest);
+ } else {
+ dev_dbg(dev->class_dev,
+ "%s: unhandled destination (%d) queried\n",
+ __func__, dest);
+ }
+
+ if (reg >= 0)
+ return ni_find_route_source(CR_CHAN(reg), dest,
+ &devpriv->routing_tables);
+ return -EINVAL;
+}
+
+/*
+ * Test a route:
+ *
+ * Return: -1 if not connectible;
+ * 0 if connectible and not connected;
+ * 1 if connectible and connected.
+ */
+static inline int test_route(unsigned int src, unsigned int dest,
+ struct comedi_device *dev)
+{
+ struct ni_660x_private *devpriv = dev->private;
+ s8 reg = ni_route_to_register(CR_CHAN(src), dest,
+ &devpriv->routing_tables);
+
+ if (reg < 0)
+ return -1;
+ if (get_output_select_source(dest, dev) != CR_CHAN(src))
+ return 0;
+ return 1;
+}
+
+/* Connect the actual route. */
+static inline int connect_route(unsigned int src, unsigned int dest,
+ struct comedi_device *dev)
+{
+ struct ni_660x_private *devpriv = dev->private;
+ s8 reg = ni_route_to_register(CR_CHAN(src), dest,
+ &devpriv->routing_tables);
+ s8 current_src;
+
+ if (reg < 0)
+ /* route is not valid */
+ return -EINVAL;
+
+ current_src = get_output_select_source(dest, dev);
+ if (current_src == CR_CHAN(src))
+ return -EALREADY;
+ if (current_src >= 0)
+ /* destination mux is already busy. complain, don't overwrite */
+ return -EBUSY;
+
+ /* The route is valid and available. Now connect... */
+ if (channel_is_pfi(CR_CHAN(dest))) {
+ /*
+ * set routing and then direction so that the output does not
+ * first get generated with the wrong pin
+ */
+ ni_660x_set_pfi_routing(dev, dest, reg);
+ ni_660x_set_pfi_direction(dev, dest, COMEDI_OUTPUT);
+ } else if (channel_is_rtsi(CR_CHAN(dest))) {
+ dev_dbg(dev->class_dev, "%s: unhandled rtsi destination (%d)\n",
+ __func__, dest);
+ return -EINVAL;
+ /*
+ * The following can be enabled when RTSI routing info is
+ * determined (not currently documented):
+ * if (reg == NI_RTSI_OUTPUT_RGOUT0) {
+ * int ret = incr_rgout0_src_use(src, dev);
+
+ * if (ret < 0)
+ * return ret;
+ * } else if (ni_rtsi_route_requires_mux(reg)) {
+ * ** Attempt to allocate and route (src->brd) **
+ * int brd = incr_rtsi_brd_src_use(src, dev);
+
+ * if (brd < 0)
+ * return brd;
+
+ * ** Now lookup the register value for (brd->dest) **
+ * reg = ni_lookup_route_register(brd, CR_CHAN(dest),
+ * &devpriv->routing_tables);
+ * }
+
+ * ni_set_rtsi_direction(dev, dest, COMEDI_OUTPUT);
+ * ni_set_rtsi_routing(dev, dest, reg);
+ */
+ } else if (channel_is_ctr(CR_CHAN(dest))) {
+ /*
+ * we are adding back the channel modifier info to set
+ * invert/edge info passed by the user
+ */
+ ni_tio_set_routing(devpriv->counter_dev, dest,
+ reg | (src & ~CR_CHAN(-1)));
+ } else {
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static inline int disconnect_route(unsigned int src, unsigned int dest,
+ struct comedi_device *dev)
+{
+ struct ni_660x_private *devpriv = dev->private;
+ s8 reg = ni_route_to_register(CR_CHAN(src), CR_CHAN(dest),
+ &devpriv->routing_tables);
+
+ if (reg < 0)
+ /* route is not valid */
+ return -EINVAL;
+ if (get_output_select_source(dest, dev) != CR_CHAN(src))
+ /* cannot disconnect something not connected */
+ return -EINVAL;
+
+ /* The route is valid and is connected. Now disconnect... */
+ if (channel_is_pfi(CR_CHAN(dest))) {
+ unsigned int source = ((CR_CHAN(dest) - NI_PFI(0)) < 8)
+ ? NI_660X_PFI_OUTPUT_DIO
+ : NI_660X_PFI_OUTPUT_COUNTER;
+
+ /* set the pfi to high impedance, and disconnect */
+ ni_660x_set_pfi_direction(dev, dest, COMEDI_INPUT);
+ ni_660x_set_pfi_routing(dev, dest, source);
+ } else if (channel_is_rtsi(CR_CHAN(dest))) {
+ dev_dbg(dev->class_dev, "%s: unhandled rtsi destination (%d)\n",
+ __func__, dest);
+ return -EINVAL;
+ /*
+ * The following can be enabled when RTSI routing info is
+ * determined (not currently documented):
+ * if (reg == NI_RTSI_OUTPUT_RGOUT0) {
+ * int ret = decr_rgout0_src_use(src, dev);
+
+ * if (ret < 0)
+ * return ret;
+ * } else if (ni_rtsi_route_requires_mux(reg)) {
+ * ** find which RTSI_BRD line is source for rtsi pin **
+ * int brd = ni_find_route_source(
+ * ni_get_rtsi_routing(dev, dest), CR_CHAN(dest),
+ * &devpriv->routing_tables);
+
+ * if (brd < 0)
+ * return brd;
+
+ * ** decrement/disconnect RTSI_BRD line from source **
+ * decr_rtsi_brd_src_use(src, brd, dev);
+ * }
+
+ * ** set rtsi output selector to default state **
+ * reg = default_rtsi_routing[CR_CHAN(dest) - TRIGGER_LINE(0)];
+ * ni_set_rtsi_direction(dev, dest, COMEDI_INPUT);
+ * ni_set_rtsi_routing(dev, dest, reg);
+ */
+ } else if (channel_is_ctr(CR_CHAN(dest))) {
+ ni_tio_unset_routing(devpriv->counter_dev, dest);
+ } else {
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int ni_global_insn_config(struct comedi_device *dev,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ switch (data[0]) {
+ case INSN_DEVICE_CONFIG_TEST_ROUTE:
+ data[0] = test_route(data[1], data[2], dev);
+ return 2;
+ case INSN_DEVICE_CONFIG_CONNECT_ROUTE:
+ return connect_route(data[1], data[2], dev);
+ case INSN_DEVICE_CONFIG_DISCONNECT_ROUTE:
+ return disconnect_route(data[1], data[2], dev);
+ /*
+ * This case is already handled one level up.
+ * case INSN_DEVICE_CONFIG_GET_ROUTES:
+ */
+ default:
+ return -EINVAL;
+ }
+ return 1;
+}
+
static void ni_660x_init_tio_chips(struct comedi_device *dev,
unsigned int n_chips)
{
@@ -730,12 +1035,30 @@ static int ni_660x_auto_attach(struct comedi_device *dev,
ni_660x_init_tio_chips(dev, board->n_chips);
+ /* prepare the device for globally-named routes. */
+ if (ni_assign_device_routes("ni_660x", board->name,
+ &devpriv->routing_tables) < 0) {
+ dev_warn(dev->class_dev, "%s: %s device has no signal routing table.\n",
+ __func__, board->name);
+ dev_warn(dev->class_dev, "%s: High level NI signal names will not be available for this %s board.\n",
+ __func__, board->name);
+ } else {
+ /*
+ * only(?) assign insn_device_config if we have global names for
+ * this device.
+ */
+ dev->insn_device_config = ni_global_insn_config;
+ dev->get_valid_routes = _ni_get_valid_routes;
+ }
+
n_counters = board->n_chips * NI660X_COUNTERS_PER_CHIP;
gpct_dev = ni_gpct_device_construct(dev,
ni_660x_gpct_write,
ni_660x_gpct_read,
ni_gpct_variant_660x,
- n_counters);
+ n_counters,
+ NI660X_COUNTERS_PER_CHIP,
+ &devpriv->routing_tables);
if (!gpct_dev)
return -ENOMEM;
devpriv->counter_dev = gpct_dev;
@@ -822,7 +1145,7 @@ static int ni_660x_auto_attach(struct comedi_device *dev,
: NI_660X_PFI_OUTPUT_COUNTER;
ni_660x_set_pfi_routing(dev, i, source);
- ni_660x_select_pfi_output(dev, i, 0); /* high-z */
+ ni_660x_set_pfi_direction(dev, i, COMEDI_INPUT);/* high-z */
}
/* Counter subdevices (4 NI TIO General Purpose Counters per chip) */
@@ -831,9 +1154,6 @@ static int ni_660x_auto_attach(struct comedi_device *dev,
if (i < n_counters) {
struct ni_gpct *counter = &gpct_dev->counters[i];
- counter->chip_index = i / NI660X_COUNTERS_PER_CHIP;
- counter->counter_index = i % NI660X_COUNTERS_PER_CHIP;
-
s->type = COMEDI_SUBD_COUNTER;
s->subdev_flags = SDF_READABLE | SDF_WRITABLE |
SDF_LSAMPL | SDF_CMD_READ;
@@ -915,6 +1235,7 @@ static const struct pci_device_id ni_660x_pci_table[] = {
{ PCI_VDEVICE(NI, 0x1310), BOARD_PCI6602 },
{ PCI_VDEVICE(NI, 0x1360), BOARD_PXI6602 },
{ PCI_VDEVICE(NI, 0x2c60), BOARD_PCI6601 },
+ { PCI_VDEVICE(NI, 0x2db0), BOARD_PCI6608 },
{ PCI_VDEVICE(NI, 0x2cc0), BOARD_PXI6608 },
{ PCI_VDEVICE(NI, 0x1e30), BOARD_PCI6624 },
{ PCI_VDEVICE(NI, 0x1e40), BOARD_PXI6624 },
diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c
index 4dee2fc37aed..2d1e0325d04d 100644
--- a/drivers/staging/comedi/drivers/ni_mio_common.c
+++ b/drivers/staging/comedi/drivers/ni_mio_common.c
@@ -351,7 +351,8 @@ static const struct mio_regmap m_series_stc_write_regmap[] = {
[NISTC_AO_PERSONAL_REG] = { 0x19c, 2 },
[NISTC_RTSI_TRIGA_OUT_REG] = { 0x19e, 2 },
[NISTC_RTSI_TRIGB_OUT_REG] = { 0x1a0, 2 },
- [NISTC_RTSI_BOARD_REG] = { 0, 0 }, /* Unknown */
+ /* doc for following line: mhddk/nimseries/ChipObjects/tMSeries.h */
+ [NISTC_RTSI_BOARD_REG] = { 0x1a2, 2 },
[NISTC_CFG_MEM_CLR_REG] = { 0x1a4, 2 },
[NISTC_ADC_FIFO_CLR_REG] = { 0x1a6, 2 },
[NISTC_DAC_FIFO_CLR_REG] = { 0x1a8, 2 },
@@ -2006,7 +2007,6 @@ static int ni_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
const struct ni_board_struct *board = dev->board_ptr;
struct ni_private *devpriv = dev->private;
int err = 0;
- unsigned int tmp;
unsigned int sources;
/* Step 1 : check if triggers are trivially valid */
@@ -2047,12 +2047,9 @@ static int ni_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
break;
case TRIG_EXT:
- tmp = CR_CHAN(cmd->start_arg);
-
- if (tmp > 16)
- tmp = 16;
- tmp |= (cmd->start_arg & (CR_INVERT | CR_EDGE));
- err |= comedi_check_trigger_arg_is(&cmd->start_arg, tmp);
+ err |= ni_check_trigger_arg_roffs(CR_CHAN(cmd->start_arg),
+ NI_AI_StartTrigger,
+ &devpriv->routing_tables, 1);
break;
}
@@ -2064,12 +2061,9 @@ static int ni_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
0xffffff);
} else if (cmd->scan_begin_src == TRIG_EXT) {
/* external trigger */
- unsigned int tmp = CR_CHAN(cmd->scan_begin_arg);
-
- if (tmp > 16)
- tmp = 16;
- tmp |= (cmd->scan_begin_arg & (CR_INVERT | CR_EDGE));
- err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, tmp);
+ err |= ni_check_trigger_arg_roffs(CR_CHAN(cmd->scan_begin_arg),
+ NI_AI_SampleClock,
+ &devpriv->routing_tables, 1);
} else { /* TRIG_OTHER */
err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
}
@@ -2087,12 +2081,9 @@ static int ni_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
}
} else if (cmd->convert_src == TRIG_EXT) {
/* external trigger */
- unsigned int tmp = CR_CHAN(cmd->convert_arg);
-
- if (tmp > 16)
- tmp = 16;
- tmp |= (cmd->convert_arg & (CR_ALT_FILTER | CR_INVERT));
- err |= comedi_check_trigger_arg_is(&cmd->convert_arg, tmp);
+ err |= ni_check_trigger_arg_roffs(CR_CHAN(cmd->convert_arg),
+ NI_AI_ConvertClock,
+ &devpriv->routing_tables, 1);
} else if (cmd->convert_src == TRIG_NOW) {
err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0);
}
@@ -2118,7 +2109,7 @@ static int ni_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
/* step 4: fix up any arguments */
if (cmd->scan_begin_src == TRIG_TIMER) {
- tmp = cmd->scan_begin_arg;
+ unsigned int tmp = cmd->scan_begin_arg;
cmd->scan_begin_arg =
ni_timer_to_ns(dev, ni_ns_to_timer(dev,
cmd->scan_begin_arg,
@@ -2128,7 +2119,7 @@ static int ni_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
}
if (cmd->convert_src == TRIG_TIMER) {
if (!devpriv->is_611x && !devpriv->is_6143) {
- tmp = cmd->convert_arg;
+ unsigned int tmp = cmd->convert_arg;
cmd->convert_arg =
ni_timer_to_ns(dev, ni_ns_to_timer(dev,
cmd->convert_arg,
@@ -2206,8 +2197,10 @@ static int ni_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
NISTC_AI_TRIG_START1_SEL(0);
break;
case TRIG_EXT:
- ai_trig |= NISTC_AI_TRIG_START1_SEL(CR_CHAN(cmd->start_arg) +
- 1);
+ ai_trig |= NISTC_AI_TRIG_START1_SEL(
+ ni_get_reg_value_roffs(CR_CHAN(cmd->start_arg),
+ NI_AI_StartTrigger,
+ &devpriv->routing_tables, 1));
if (cmd->start_arg & CR_INVERT)
ai_trig |= NISTC_AI_TRIG_START1_POLARITY;
@@ -2317,8 +2310,10 @@ static int ni_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
(cmd->scan_begin_arg & ~CR_EDGE) !=
(cmd->convert_arg & ~CR_EDGE))
start_stop_select |= NISTC_AI_START_SYNC;
- start_stop_select |=
- NISTC_AI_START_SEL(1 + CR_CHAN(cmd->scan_begin_arg));
+ start_stop_select |= NISTC_AI_START_SEL(
+ ni_get_reg_value_roffs(CR_CHAN(cmd->scan_begin_arg),
+ NI_AI_SampleClock,
+ &devpriv->routing_tables, 1));
ni_stc_writew(dev, start_stop_select, NISTC_AI_START_STOP_REG);
break;
}
@@ -2346,8 +2341,10 @@ static int ni_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
ni_stc_writew(dev, mode2, NISTC_AI_MODE2_REG);
break;
case TRIG_EXT:
- mode1 |= NISTC_AI_MODE1_CONVERT_SRC(1 +
- CR_CHAN(cmd->convert_arg));
+ mode1 |= NISTC_AI_MODE1_CONVERT_SRC(
+ ni_get_reg_value_roffs(CR_CHAN(cmd->convert_arg),
+ NI_AI_ConvertClock,
+ &devpriv->routing_tables, 1));
if ((cmd->convert_arg & CR_INVERT) == 0)
mode1 |= NISTC_AI_MODE1_CONVERT_POLARITY;
ni_stc_writew(dev, mode1, NISTC_AI_MODE1_REG);
@@ -2464,6 +2461,7 @@ static int ni_ai_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
+ const struct ni_board_struct *board = dev->board_ptr;
struct ni_private *devpriv = dev->private;
if (insn->n < 1)
@@ -2498,6 +2496,15 @@ static int ni_ai_insn_config(struct comedi_device *dev,
}
}
return 2;
+ case INSN_CONFIG_GET_CMD_TIMING_CONSTRAINTS:
+ /* we don't care about actual channels */
+ /* data[3] : chanlist_len */
+ data[1] = ni_min_ai_scan_period_ns(dev, data[3]);
+ if (devpriv->is_611x || devpriv->is_6143)
+ data[2] = 0; /* simultaneous output */
+ else
+ data[2] = board->ai_speed;
+ return 0;
default:
break;
}
@@ -2834,6 +2841,11 @@ static int ni_ao_insn_config(struct comedi_device *dev,
return 0;
case INSN_CONFIG_ARM:
return ni_ao_arm(dev, s);
+ case INSN_CONFIG_GET_CMD_TIMING_CONSTRAINTS:
+ /* we don't care about actual channels */
+ data[1] = board->ao_speed;
+ data[2] = 0;
+ return 0;
default:
break;
}
@@ -2955,7 +2967,10 @@ static void ni_ao_cmd_set_trigger(struct comedi_device *dev,
trigsel = NISTC_AO_TRIG_START1_EDGE |
NISTC_AO_TRIG_START1_SYNC;
} else { /* TRIG_EXT */
- trigsel = NISTC_AO_TRIG_START1_SEL(CR_CHAN(cmd->start_arg) + 1);
+ trigsel = NISTC_AO_TRIG_START1_SEL(
+ ni_get_reg_value_roffs(CR_CHAN(cmd->start_arg),
+ NI_AO_StartTrigger,
+ &devpriv->routing_tables, 1));
/* 0=active high, 1=active low. see daq-stc 3-24 (p186) */
if (cmd->start_arg & CR_INVERT)
trigsel |= NISTC_AO_TRIG_START1_POLARITY;
@@ -3117,7 +3132,9 @@ static void ni_ao_cmd_set_update(struct comedi_device *dev,
/* FIXME: assert scan_begin_arg != 0, ret failure otherwise */
devpriv->ao_cmd2 |= NISTC_AO_CMD2_BC_GATE_ENA;
devpriv->ao_mode1 |= NISTC_AO_MODE1_UPDATE_SRC(
- CR_CHAN(cmd->scan_begin_arg));
+ ni_get_reg_value(CR_CHAN(cmd->scan_begin_arg),
+ NI_AO_SampleClock,
+ &devpriv->routing_tables));
if (cmd->scan_begin_arg & CR_INVERT)
devpriv->ao_mode1 |= NISTC_AO_MODE1_UPDATE_SRC_POLARITY;
}
@@ -3313,12 +3330,9 @@ static int ni_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
break;
case TRIG_EXT:
- tmp = CR_CHAN(cmd->start_arg);
-
- if (tmp > 18)
- tmp = 18;
- tmp |= (cmd->start_arg & (CR_INVERT | CR_EDGE));
- err |= comedi_check_trigger_arg_is(&cmd->start_arg, tmp);
+ err |= ni_check_trigger_arg_roffs(CR_CHAN(cmd->start_arg),
+ NI_AO_StartTrigger,
+ &devpriv->routing_tables, 1);
break;
}
@@ -3328,6 +3342,10 @@ static int ni_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
err |= comedi_check_trigger_arg_max(&cmd->scan_begin_arg,
devpriv->clock_ns *
0xffffff);
+ } else { /* TRIG_EXT */
+ err |= ni_check_trigger_arg(CR_CHAN(cmd->scan_begin_arg),
+ NI_AO_SampleClock,
+ &devpriv->routing_tables);
}
err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0);
@@ -3475,6 +3493,15 @@ static int ni_m_series_dio_insn_config(struct comedi_device *dev,
{
int ret;
+ if (data[0] == INSN_CONFIG_GET_CMD_TIMING_CONSTRAINTS) {
+ const struct ni_board_struct *board = dev->board_ptr;
+
+ /* we don't care about actual channels */
+ data[1] = board->dio_speed;
+ data[2] = 0;
+ return 0;
+ }
+
ret = comedi_dio_insn_config(dev, s, insn, data, 0);
if (ret)
return ret;
@@ -3516,8 +3543,8 @@ static int ni_cdio_check_chanlist(struct comedi_device *dev,
static int ni_cdio_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_cmd *cmd)
{
+ struct ni_private *devpriv = dev->private;
int err = 0;
- int tmp;
/* Step 1 : check if triggers are trivially valid */
@@ -3537,9 +3564,15 @@ static int ni_cdio_cmdtest(struct comedi_device *dev,
err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
- tmp = cmd->scan_begin_arg;
- tmp &= CR_PACK_FLAGS(NI_M_CDO_MODE_SAMPLE_SRC_MASK, 0, 0, CR_INVERT);
- if (tmp != cmd->scan_begin_arg)
+ /*
+ * Although NI_D[IO]_SampleClock are the same, perhaps we should still,
+ * for completeness, test whether the cmd is output or input?
+ */
+ err |= ni_check_trigger_arg(CR_CHAN(cmd->scan_begin_arg),
+ NI_DO_SampleClock,
+ &devpriv->routing_tables);
+ if (CR_RANGE(cmd->scan_begin_arg) != 0 ||
+ CR_AREF(cmd->scan_begin_arg) != 0)
err |= -EINVAL;
err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0);
@@ -3627,9 +3660,16 @@ static int ni_cdio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
int retval;
ni_writel(dev, NI_M_CDO_CMD_RESET, NI_M_CDIO_CMD_REG);
+ /*
+ * Although NI_D[IO]_SampleClock are the same, perhaps we should still,
+ * for completeness, test whether the cmd is output or input(?)
+ */
cdo_mode_bits = NI_M_CDO_MODE_FIFO_MODE |
NI_M_CDO_MODE_HALT_ON_ERROR |
- NI_M_CDO_MODE_SAMPLE_SRC(CR_CHAN(cmd->scan_begin_arg));
+ NI_M_CDO_MODE_SAMPLE_SRC(
+ ni_get_reg_value(CR_CHAN(cmd->scan_begin_arg),
+ NI_DO_SampleClock,
+ &devpriv->routing_tables));
if (cmd->scan_begin_arg & CR_INVERT)
cdo_mode_bits |= NI_M_CDO_MODE_POLARITY;
ni_writel(dev, cdo_mode_bits, NI_M_CDO_MODE_REG);
@@ -4551,24 +4591,33 @@ static unsigned int ni_get_pfi_routing(struct comedi_device *dev,
{
struct ni_private *devpriv = dev->private;
+ if (chan >= NI_PFI(0)) {
+ /* allow new and old names of pfi channels to work. */
+ chan -= NI_PFI(0);
+ }
return (devpriv->is_m_series)
? ni_m_series_get_pfi_routing(dev, chan)
: ni_old_get_pfi_routing(dev, chan);
}
+/* Sets the output mux for the specified PFI channel. */
static int ni_set_pfi_routing(struct comedi_device *dev,
unsigned int chan, unsigned int source)
{
struct ni_private *devpriv = dev->private;
+ if (chan >= NI_PFI(0)) {
+ /* allow new and old names of pfi channels to work. */
+ chan -= NI_PFI(0);
+ }
return (devpriv->is_m_series)
? ni_m_series_set_pfi_routing(dev, chan, source)
: ni_old_set_pfi_routing(dev, chan, source);
}
-static int ni_config_filter(struct comedi_device *dev,
- unsigned int pfi_channel,
- enum ni_pfi_filter_select filter)
+static int ni_config_pfi_filter(struct comedi_device *dev,
+ unsigned int chan,
+ enum ni_pfi_filter_select filter)
{
struct ni_private *devpriv = dev->private;
unsigned int bits;
@@ -4576,19 +4625,46 @@ static int ni_config_filter(struct comedi_device *dev,
if (!devpriv->is_m_series)
return -ENOTSUPP;
+ if (chan >= NI_PFI(0)) {
+ /* allow new and old names of pfi channels to work. */
+ chan -= NI_PFI(0);
+ }
+
bits = ni_readl(dev, NI_M_PFI_FILTER_REG);
- bits &= ~NI_M_PFI_FILTER_SEL_MASK(pfi_channel);
- bits |= NI_M_PFI_FILTER_SEL(pfi_channel, filter);
+ bits &= ~NI_M_PFI_FILTER_SEL_MASK(chan);
+ bits |= NI_M_PFI_FILTER_SEL(chan, filter);
ni_writel(dev, bits, NI_M_PFI_FILTER_REG);
return 0;
}
+static void ni_set_pfi_direction(struct comedi_device *dev, int chan,
+ unsigned int direction)
+{
+ if (chan >= NI_PFI(0)) {
+ /* allow new and old names of pfi channels to work. */
+ chan -= NI_PFI(0);
+ }
+ direction = (direction == COMEDI_OUTPUT) ? 1u : 0u;
+ ni_set_bits(dev, NISTC_IO_BIDIR_PIN_REG, 1 << chan, direction);
+}
+
+static int ni_get_pfi_direction(struct comedi_device *dev, int chan)
+{
+ struct ni_private *devpriv = dev->private;
+
+ if (chan >= NI_PFI(0)) {
+ /* allow new and old names of pfi channels to work. */
+ chan -= NI_PFI(0);
+ }
+ return devpriv->io_bidirection_pin_reg & (1 << chan) ?
+ COMEDI_OUTPUT : COMEDI_INPUT;
+}
+
static int ni_pfi_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
unsigned int *data)
{
- struct ni_private *devpriv = dev->private;
unsigned int chan;
if (insn->n < 1)
@@ -4598,23 +4674,19 @@ static int ni_pfi_insn_config(struct comedi_device *dev,
switch (data[0]) {
case COMEDI_OUTPUT:
- ni_set_bits(dev, NISTC_IO_BIDIR_PIN_REG, 1 << chan, 1);
- break;
case COMEDI_INPUT:
- ni_set_bits(dev, NISTC_IO_BIDIR_PIN_REG, 1 << chan, 0);
+ ni_set_pfi_direction(dev, chan, data[0]);
break;
case INSN_CONFIG_DIO_QUERY:
- data[1] =
- (devpriv->io_bidirection_pin_reg & (1 << chan)) ?
- COMEDI_OUTPUT : COMEDI_INPUT;
- return 0;
+ data[1] = ni_get_pfi_direction(dev, chan);
+ break;
case INSN_CONFIG_SET_ROUTING:
return ni_set_pfi_routing(dev, chan, data[1]);
case INSN_CONFIG_GET_ROUTING:
data[1] = ni_get_pfi_routing(dev, chan);
break;
case INSN_CONFIG_FILTER:
- return ni_config_filter(dev, chan, data[1]);
+ return ni_config_pfi_filter(dev, chan, data[1]);
default:
return -EINVAL;
}
@@ -4980,7 +5052,10 @@ static int ni_valid_rtsi_output_source(struct comedi_device *dev,
case NI_RTSI_OUTPUT_G_SRC0:
case NI_RTSI_OUTPUT_G_GATE0:
case NI_RTSI_OUTPUT_RGOUT0:
- case NI_RTSI_OUTPUT_RTSI_BRD_0:
+ case NI_RTSI_OUTPUT_RTSI_BRD(0):
+ case NI_RTSI_OUTPUT_RTSI_BRD(1):
+ case NI_RTSI_OUTPUT_RTSI_BRD(2):
+ case NI_RTSI_OUTPUT_RTSI_BRD(3):
return 1;
case NI_RTSI_OUTPUT_RTSI_OSC:
return (devpriv->is_m_series) ? 1 : 0;
@@ -4994,6 +5069,10 @@ static int ni_set_rtsi_routing(struct comedi_device *dev,
{
struct ni_private *devpriv = dev->private;
+ if (chan >= TRIGGER_LINE(0))
+ /* allow new and old names of rtsi channels to work. */
+ chan -= TRIGGER_LINE(0);
+
if (ni_valid_rtsi_output_source(dev, chan, src) == 0)
return -EINVAL;
if (chan < 4) {
@@ -5001,11 +5080,18 @@ static int ni_set_rtsi_routing(struct comedi_device *dev,
devpriv->rtsi_trig_a_output_reg |= NISTC_RTSI_TRIG(chan, src);
ni_stc_writew(dev, devpriv->rtsi_trig_a_output_reg,
NISTC_RTSI_TRIGA_OUT_REG);
- } else if (chan < 8) {
+ } else if (chan < NISTC_RTSI_TRIG_NUM_CHAN(devpriv->is_m_series)) {
devpriv->rtsi_trig_b_output_reg &= ~NISTC_RTSI_TRIG_MASK(chan);
devpriv->rtsi_trig_b_output_reg |= NISTC_RTSI_TRIG(chan, src);
ni_stc_writew(dev, devpriv->rtsi_trig_b_output_reg,
NISTC_RTSI_TRIGB_OUT_REG);
+ } else if (chan != NISTC_RTSI_TRIG_OLD_CLK_CHAN) {
+ /* probably should never reach this, since the
+ * ni_valid_rtsi_output_source above errors out if chan is too
+ * high
+ */
+ dev_err(dev->class_dev, "%s: unknown rtsi channel\n", __func__);
+ return -EINVAL;
}
return 2;
}
@@ -5015,31 +5101,35 @@ static unsigned int ni_get_rtsi_routing(struct comedi_device *dev,
{
struct ni_private *devpriv = dev->private;
+ if (chan >= TRIGGER_LINE(0))
+ /* allow new and old names of rtsi channels to work. */
+ chan -= TRIGGER_LINE(0);
+
if (chan < 4) {
return NISTC_RTSI_TRIG_TO_SRC(chan,
devpriv->rtsi_trig_a_output_reg);
} else if (chan < NISTC_RTSI_TRIG_NUM_CHAN(devpriv->is_m_series)) {
return NISTC_RTSI_TRIG_TO_SRC(chan,
devpriv->rtsi_trig_b_output_reg);
- } else {
- if (chan == NISTC_RTSI_TRIG_OLD_CLK_CHAN)
- return NI_RTSI_OUTPUT_RTSI_OSC;
- dev_err(dev->class_dev, "bug! should never get here?\n");
- return 0;
+ } else if (chan == NISTC_RTSI_TRIG_OLD_CLK_CHAN) {
+ return NI_RTSI_OUTPUT_RTSI_OSC;
}
+
+ dev_err(dev->class_dev, "%s: unknown rtsi channel\n", __func__);
+ return -EINVAL;
}
-static int ni_rtsi_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+static void ni_set_rtsi_direction(struct comedi_device *dev, int chan,
+ unsigned int direction)
{
struct ni_private *devpriv = dev->private;
- unsigned int chan = CR_CHAN(insn->chanspec);
unsigned int max_chan = NISTC_RTSI_TRIG_NUM_CHAN(devpriv->is_m_series);
- switch (data[0]) {
- case INSN_CONFIG_DIO_OUTPUT:
+ if (chan >= TRIGGER_LINE(0))
+ /* allow new and old names of rtsi channels to work. */
+ chan -= TRIGGER_LINE(0);
+
+ if (direction == COMEDI_OUTPUT) {
if (chan < max_chan) {
devpriv->rtsi_trig_direction_reg |=
NISTC_RTSI_TRIG_DIR(chan, devpriv->is_m_series);
@@ -5047,10 +5137,7 @@ static int ni_rtsi_insn_config(struct comedi_device *dev,
devpriv->rtsi_trig_direction_reg |=
NISTC_RTSI_TRIG_DRV_CLK;
}
- ni_stc_writew(dev, devpriv->rtsi_trig_direction_reg,
- NISTC_RTSI_TRIG_DIR_REG);
- break;
- case INSN_CONFIG_DIO_INPUT:
+ } else {
if (chan < max_chan) {
devpriv->rtsi_trig_direction_reg &=
~NISTC_RTSI_TRIG_DIR(chan, devpriv->is_m_series);
@@ -5058,23 +5145,53 @@ static int ni_rtsi_insn_config(struct comedi_device *dev,
devpriv->rtsi_trig_direction_reg &=
~NISTC_RTSI_TRIG_DRV_CLK;
}
- ni_stc_writew(dev, devpriv->rtsi_trig_direction_reg,
- NISTC_RTSI_TRIG_DIR_REG);
+ }
+ ni_stc_writew(dev, devpriv->rtsi_trig_direction_reg,
+ NISTC_RTSI_TRIG_DIR_REG);
+}
+
+static int ni_get_rtsi_direction(struct comedi_device *dev, int chan)
+{
+ struct ni_private *devpriv = dev->private;
+ unsigned int max_chan = NISTC_RTSI_TRIG_NUM_CHAN(devpriv->is_m_series);
+
+ if (chan >= TRIGGER_LINE(0))
+ /* allow new and old names of rtsi channels to work. */
+ chan -= TRIGGER_LINE(0);
+
+ if (chan < max_chan) {
+ return (devpriv->rtsi_trig_direction_reg &
+ NISTC_RTSI_TRIG_DIR(chan, devpriv->is_m_series))
+ ? COMEDI_OUTPUT : COMEDI_INPUT;
+ } else if (chan == NISTC_RTSI_TRIG_OLD_CLK_CHAN) {
+ return (devpriv->rtsi_trig_direction_reg &
+ NISTC_RTSI_TRIG_DRV_CLK)
+ ? COMEDI_OUTPUT : COMEDI_INPUT;
+ }
+ return -EINVAL;
+}
+
+static int ni_rtsi_insn_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ struct ni_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+
+ switch (data[0]) {
+ case COMEDI_OUTPUT:
+ case COMEDI_INPUT:
+ ni_set_rtsi_direction(dev, chan, data[0]);
break;
- case INSN_CONFIG_DIO_QUERY:
- if (chan < max_chan) {
- data[1] =
- (devpriv->rtsi_trig_direction_reg &
- NISTC_RTSI_TRIG_DIR(chan, devpriv->is_m_series))
- ? INSN_CONFIG_DIO_OUTPUT
- : INSN_CONFIG_DIO_INPUT;
- } else if (chan == NISTC_RTSI_TRIG_OLD_CLK_CHAN) {
- data[1] = (devpriv->rtsi_trig_direction_reg &
- NISTC_RTSI_TRIG_DRV_CLK)
- ? INSN_CONFIG_DIO_OUTPUT
- : INSN_CONFIG_DIO_INPUT;
- }
+ case INSN_CONFIG_DIO_QUERY: {
+ int ret = ni_get_rtsi_direction(dev, chan);
+
+ if (ret < 0)
+ return ret;
+ data[1] = ret;
return 2;
+ }
case INSN_CONFIG_SET_CLOCK_SRC:
return ni_set_master_clock(dev, data[1], data[2]);
case INSN_CONFIG_GET_CLOCK_SRC:
@@ -5083,9 +5200,14 @@ static int ni_rtsi_insn_config(struct comedi_device *dev,
return 3;
case INSN_CONFIG_SET_ROUTING:
return ni_set_rtsi_routing(dev, chan, data[1]);
- case INSN_CONFIG_GET_ROUTING:
- data[1] = ni_get_rtsi_routing(dev, chan);
+ case INSN_CONFIG_GET_ROUTING: {
+ int ret = ni_get_rtsi_routing(dev, chan);
+
+ if (ret < 0)
+ return ret;
+ data[1] = ret;
return 2;
+ }
default:
return -EINVAL;
}
@@ -5102,9 +5224,275 @@ static int ni_rtsi_insn_bits(struct comedi_device *dev,
return insn->n;
}
+/*
+ * Default routing for RTSI trigger lines.
+ *
+ * These values are used here in the init function, as well as in the
+ * disconnect_route function, after a RTSI route has been disconnected.
+ */
+static const int default_rtsi_routing[] = {
+ [0] = NI_RTSI_OUTPUT_ADR_START1,
+ [1] = NI_RTSI_OUTPUT_ADR_START2,
+ [2] = NI_RTSI_OUTPUT_SCLKG,
+ [3] = NI_RTSI_OUTPUT_DACUPDN,
+ [4] = NI_RTSI_OUTPUT_DA_START1,
+ [5] = NI_RTSI_OUTPUT_G_SRC0,
+ [6] = NI_RTSI_OUTPUT_G_GATE0,
+ [7] = NI_RTSI_OUTPUT_RTSI_OSC,
+};
+
+/*
+ * Route signals through RGOUT0 terminal.
+ * @reg: raw register value of RGOUT0 bits (only bit0 is important).
+ * @dev: comedi device handle.
+ */
+static void set_rgout0_reg(int reg, struct comedi_device *dev)
+{
+ struct ni_private *devpriv = dev->private;
+
+ if (devpriv->is_m_series) {
+ devpriv->rtsi_trig_direction_reg &=
+ ~NISTC_RTSI_TRIG_DIR_SUB_SEL1;
+ devpriv->rtsi_trig_direction_reg |=
+ (reg << NISTC_RTSI_TRIG_DIR_SUB_SEL1_SHIFT) &
+ NISTC_RTSI_TRIG_DIR_SUB_SEL1;
+ ni_stc_writew(dev, devpriv->rtsi_trig_direction_reg,
+ NISTC_RTSI_TRIG_DIR_REG);
+ } else {
+ devpriv->rtsi_trig_b_output_reg &= ~NISTC_RTSI_TRIGB_SUB_SEL1;
+ devpriv->rtsi_trig_b_output_reg |=
+ (reg << NISTC_RTSI_TRIGB_SUB_SEL1_SHIFT) &
+ NISTC_RTSI_TRIGB_SUB_SEL1;
+ ni_stc_writew(dev, devpriv->rtsi_trig_b_output_reg,
+ NISTC_RTSI_TRIGB_OUT_REG);
+ }
+}
+
+static int get_rgout0_reg(struct comedi_device *dev)
+{
+ struct ni_private *devpriv = dev->private;
+ int reg;
+
+ if (devpriv->is_m_series)
+ reg = (devpriv->rtsi_trig_direction_reg &
+ NISTC_RTSI_TRIG_DIR_SUB_SEL1)
+ >> NISTC_RTSI_TRIG_DIR_SUB_SEL1_SHIFT;
+ else
+ reg = (devpriv->rtsi_trig_b_output_reg &
+ NISTC_RTSI_TRIGB_SUB_SEL1)
+ >> NISTC_RTSI_TRIGB_SUB_SEL1_SHIFT;
+ return reg;
+}
+
+static inline int get_rgout0_src(struct comedi_device *dev)
+{
+ struct ni_private *devpriv = dev->private;
+ int reg = get_rgout0_reg(dev);
+
+ return ni_find_route_source(reg, NI_RGOUT0, &devpriv->routing_tables);
+}
+
+/*
+ * Route signals through RGOUT0 terminal and increment the RGOUT0 use for this
+ * particular route.
+ * @src: device-global signal name
+ * @dev: comedi device handle
+ *
+ * Return: -EINVAL if the source is not valid to route to RGOUT0;
+ * -EBUSY if the RGOUT0 is already used;
+ * 0 if successful.
+ */
+static int incr_rgout0_src_use(int src, struct comedi_device *dev)
+{
+ struct ni_private *devpriv = dev->private;
+ s8 reg = ni_lookup_route_register(CR_CHAN(src), NI_RGOUT0,
+ &devpriv->routing_tables);
+
+ if (reg < 0)
+ return -EINVAL;
+
+ if (devpriv->rgout0_usage > 0 && get_rgout0_reg(dev) != reg)
+ return -EBUSY;
+
+ ++devpriv->rgout0_usage;
+ set_rgout0_reg(reg, dev);
+ return 0;
+}
+
+/*
+ * Unroute signals through RGOUT0 terminal and deccrement the RGOUT0 use for
+ * this particular source. This function does not actually unroute anything
+ * with respect to RGOUT0. It does, on the other hand, decrement the usage
+ * counter for the current src->RGOUT0 mapping.
+ *
+ * Return: -EINVAL if the source is not already routed to RGOUT0 (or usage is
+ * already at zero); 0 if successful.
+ */
+static int decr_rgout0_src_use(int src, struct comedi_device *dev)
+{
+ struct ni_private *devpriv = dev->private;
+ s8 reg = ni_lookup_route_register(CR_CHAN(src), NI_RGOUT0,
+ &devpriv->routing_tables);
+
+ if (devpriv->rgout0_usage > 0 && get_rgout0_reg(dev) == reg) {
+ --devpriv->rgout0_usage;
+ if (!devpriv->rgout0_usage)
+ set_rgout0_reg(0, dev); /* ok default? */
+ return 0;
+ }
+ return -EINVAL;
+}
+
+/*
+ * Route signals through given NI_RTSI_BRD mux.
+ * @i: index of mux to route
+ * @reg: raw register value of RTSI_BRD bits
+ * @dev: comedi device handle
+ */
+static void set_ith_rtsi_brd_reg(int i, int reg, struct comedi_device *dev)
+{
+ struct ni_private *devpriv = dev->private;
+ int reg_i_sz = 3; /* value for e-series */
+ int reg_i_mask;
+ int reg_i_shift;
+
+ if (devpriv->is_m_series)
+ reg_i_sz = 4;
+ reg_i_mask = ~((~0) << reg_i_sz);
+ reg_i_shift = i * reg_i_sz;
+
+ /* clear out the current reg_i for ith brd */
+ devpriv->rtsi_shared_mux_reg &= ~(reg_i_mask << reg_i_shift);
+ /* (softcopy) write the new reg_i for ith brd */
+ devpriv->rtsi_shared_mux_reg |= (reg & reg_i_mask) << reg_i_shift;
+ /* (hardcopy) write the new reg_i for ith brd */
+ ni_stc_writew(dev, devpriv->rtsi_shared_mux_reg, NISTC_RTSI_BOARD_REG);
+}
+
+static int get_ith_rtsi_brd_reg(int i, struct comedi_device *dev)
+{
+ struct ni_private *devpriv = dev->private;
+ int reg_i_sz = 3; /* value for e-series */
+ int reg_i_mask;
+ int reg_i_shift;
+
+ if (devpriv->is_m_series)
+ reg_i_sz = 4;
+ reg_i_mask = ~((~0) << reg_i_sz);
+ reg_i_shift = i * reg_i_sz;
+
+ return (devpriv->rtsi_shared_mux_reg >> reg_i_shift) & reg_i_mask;
+}
+
+static inline int get_rtsi_brd_src(int brd, struct comedi_device *dev)
+{
+ struct ni_private *devpriv = dev->private;
+ int brd_index = brd;
+ int reg;
+
+ if (brd >= NI_RTSI_BRD(0))
+ brd_index = brd - NI_RTSI_BRD(0);
+ else
+ brd = NI_RTSI_BRD(brd);
+ /*
+ * And now:
+ * brd : device-global name
+ * brd_index : index number of RTSI_BRD mux
+ */
+
+ reg = get_ith_rtsi_brd_reg(brd_index, dev);
+
+ return ni_find_route_source(reg, brd, &devpriv->routing_tables);
+}
+
+/*
+ * Route signals through NI_RTSI_BRD mux and increment the use counter for this
+ * particular route.
+ *
+ * Return: -EINVAL if the source is not valid to route to NI_RTSI_BRD(i);
+ * -EBUSY if all NI_RTSI_BRD muxes are already used;
+ * NI_RTSI_BRD(i) of allocated ith mux if successful.
+ */
+static int incr_rtsi_brd_src_use(int src, struct comedi_device *dev)
+{
+ struct ni_private *devpriv = dev->private;
+ int first_available = -1;
+ int err = -EINVAL;
+ s8 reg;
+ int i;
+
+ /* first look for a mux that is already configured to provide src */
+ for (i = 0; i < NUM_RTSI_SHARED_MUXS; ++i) {
+ reg = ni_lookup_route_register(CR_CHAN(src), NI_RTSI_BRD(i),
+ &devpriv->routing_tables);
+
+ if (reg < 0)
+ continue; /* invalid route */
+
+ if (!devpriv->rtsi_shared_mux_usage[i]) {
+ if (first_available < 0)
+ /* found the first unused, but usable mux */
+ first_available = i;
+ } else {
+ /*
+ * we've seen at least one possible route, so change the
+ * final error to -EBUSY in case there are no muxes
+ * available.
+ */
+ err = -EBUSY;
+
+ if (get_ith_rtsi_brd_reg(i, dev) == reg) {
+ /*
+ * we've found a mux that is already being used
+ * to provide the requested signal. Reuse it.
+ */
+ goto success;
+ }
+ }
+ }
+
+ if (first_available < 0)
+ return err;
+
+ /* we did not find a mux to reuse, but there is at least one usable */
+ i = first_available;
+
+success:
+ ++devpriv->rtsi_shared_mux_usage[i];
+ set_ith_rtsi_brd_reg(i, reg, dev);
+ return NI_RTSI_BRD(i);
+}
+
+/*
+ * Unroute signals through NI_RTSI_BRD mux and decrement the user counter for
+ * this particular route.
+ *
+ * Return: -EINVAL if the source is not already routed to rtsi_brd(i) (or usage
+ * is already at zero); 0 if successful.
+ */
+static int decr_rtsi_brd_src_use(int src, int rtsi_brd,
+ struct comedi_device *dev)
+{
+ struct ni_private *devpriv = dev->private;
+ s8 reg = ni_lookup_route_register(CR_CHAN(src), rtsi_brd,
+ &devpriv->routing_tables);
+ const int i = rtsi_brd - NI_RTSI_BRD(0);
+
+ if (devpriv->rtsi_shared_mux_usage[i] > 0 &&
+ get_ith_rtsi_brd_reg(i, dev) == reg) {
+ --devpriv->rtsi_shared_mux_usage[i];
+ if (!devpriv->rtsi_shared_mux_usage[i])
+ set_ith_rtsi_brd_reg(i, 0, dev); /* ok default? */
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
static void ni_rtsi_init(struct comedi_device *dev)
{
struct ni_private *devpriv = dev->private;
+ int i;
/* Initialises the RTSI bus signal switch to a default state */
@@ -5117,28 +5505,328 @@ static void ni_rtsi_init(struct comedi_device *dev)
/* Set clock mode to internal */
if (ni_set_master_clock(dev, NI_MIO_INTERNAL_CLOCK, 0) < 0)
dev_err(dev->class_dev, "ni_set_master_clock failed, bug?\n");
- /* default internal lines routing to RTSI bus lines */
- devpriv->rtsi_trig_a_output_reg =
- NISTC_RTSI_TRIG(0, NI_RTSI_OUTPUT_ADR_START1) |
- NISTC_RTSI_TRIG(1, NI_RTSI_OUTPUT_ADR_START2) |
- NISTC_RTSI_TRIG(2, NI_RTSI_OUTPUT_SCLKG) |
- NISTC_RTSI_TRIG(3, NI_RTSI_OUTPUT_DACUPDN);
- ni_stc_writew(dev, devpriv->rtsi_trig_a_output_reg,
- NISTC_RTSI_TRIGA_OUT_REG);
- devpriv->rtsi_trig_b_output_reg =
- NISTC_RTSI_TRIG(4, NI_RTSI_OUTPUT_DA_START1) |
- NISTC_RTSI_TRIG(5, NI_RTSI_OUTPUT_G_SRC0) |
- NISTC_RTSI_TRIG(6, NI_RTSI_OUTPUT_G_GATE0);
- if (devpriv->is_m_series)
- devpriv->rtsi_trig_b_output_reg |=
- NISTC_RTSI_TRIG(7, NI_RTSI_OUTPUT_RTSI_OSC);
- ni_stc_writew(dev, devpriv->rtsi_trig_b_output_reg,
- NISTC_RTSI_TRIGB_OUT_REG);
+ /* default internal lines routing to RTSI bus lines */
+ for (i = 0; i < 8; ++i) {
+ ni_set_rtsi_direction(dev, i, COMEDI_INPUT);
+ ni_set_rtsi_routing(dev, i, default_rtsi_routing[i]);
+ }
+
+ /*
+ * Sets the source and direction of the 4 on board lines.
+ * This configures all board lines to be:
+ * for e-series:
+ * 1) inputs (not sure what "output" would mean)
+ * 2) copying TRIGGER_LINE(0) (or RTSI0) output
+ * for m-series:
+ * copying NI_PFI(0) output
+ */
+ devpriv->rtsi_shared_mux_reg = 0;
+ for (i = 0; i < 4; ++i)
+ set_ith_rtsi_brd_reg(i, 0, dev);
+ memset(devpriv->rtsi_shared_mux_usage, 0,
+ sizeof(devpriv->rtsi_shared_mux_usage));
+
+ /* initialize rgout0 pin as unused. */
+ devpriv->rgout0_usage = 0;
+ set_rgout0_reg(0, dev);
+}
+
+/* Get route of GPFO_i/CtrOut pins */
+static inline int ni_get_gout_routing(unsigned int dest,
+ struct comedi_device *dev)
+{
+ struct ni_private *devpriv = dev->private;
+ unsigned int reg = devpriv->an_trig_etc_reg;
+
+ switch (dest) {
+ case 0:
+ if (reg & NISTC_ATRIG_ETC_GPFO_0_ENA)
+ return NISTC_ATRIG_ETC_GPFO_0_SEL_TO_SRC(reg);
+ break;
+ case 1:
+ if (reg & NISTC_ATRIG_ETC_GPFO_1_ENA)
+ return NISTC_ATRIG_ETC_GPFO_1_SEL_TO_SRC(reg);
+ break;
+ }
+
+ return -EINVAL;
+}
+
+/* Set route of GPFO_i/CtrOut pins */
+static inline int ni_disable_gout_routing(unsigned int dest,
+ struct comedi_device *dev)
+{
+ struct ni_private *devpriv = dev->private;
+
+ switch (dest) {
+ case 0:
+ devpriv->an_trig_etc_reg &= ~NISTC_ATRIG_ETC_GPFO_0_ENA;
+ break;
+ case 1:
+ devpriv->an_trig_etc_reg &= ~NISTC_ATRIG_ETC_GPFO_1_ENA;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ni_stc_writew(dev, devpriv->an_trig_etc_reg, NISTC_ATRIG_ETC_REG);
+ return 0;
+}
+
+/* Set route of GPFO_i/CtrOut pins */
+static inline int ni_set_gout_routing(unsigned int src, unsigned int dest,
+ struct comedi_device *dev)
+{
+ struct ni_private *devpriv = dev->private;
+
+ switch (dest) {
+ case 0:
+ /* clear reg */
+ devpriv->an_trig_etc_reg &= ~NISTC_ATRIG_ETC_GPFO_0_SEL(-1);
+ /* set reg */
+ devpriv->an_trig_etc_reg |= NISTC_ATRIG_ETC_GPFO_0_ENA
+ | NISTC_ATRIG_ETC_GPFO_0_SEL(src);
+ break;
+ case 1:
+ /* clear reg */
+ devpriv->an_trig_etc_reg &= ~NISTC_ATRIG_ETC_GPFO_1_SEL;
+ src = src ? NISTC_ATRIG_ETC_GPFO_1_SEL : 0;
+ /* set reg */
+ devpriv->an_trig_etc_reg |= NISTC_ATRIG_ETC_GPFO_1_ENA | src;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ni_stc_writew(dev, devpriv->an_trig_etc_reg, NISTC_ATRIG_ETC_REG);
+ return 0;
+}
+
+/*
+ * Retrieves the current source of the output selector for the given
+ * destination. If the terminal for the destination is not already configured
+ * as an output, this function returns -EINVAL as error.
+ *
+ * Return: the register value of the destination output selector;
+ * -EINVAL if terminal is not configured for output.
+ */
+static int get_output_select_source(int dest, struct comedi_device *dev)
+{
+ struct ni_private *devpriv = dev->private;
+ int reg = -1;
+
+ if (channel_is_pfi(dest)) {
+ if (ni_get_pfi_direction(dev, dest) == COMEDI_OUTPUT)
+ reg = ni_get_pfi_routing(dev, dest);
+ } else if (channel_is_rtsi(dest)) {
+ if (ni_get_rtsi_direction(dev, dest) == COMEDI_OUTPUT) {
+ reg = ni_get_rtsi_routing(dev, dest);
+
+ if (reg == NI_RTSI_OUTPUT_RGOUT0) {
+ dest = NI_RGOUT0; /* prepare for lookup below */
+ reg = get_rgout0_reg(dev);
+ } else if (reg >= NI_RTSI_OUTPUT_RTSI_BRD(0) &&
+ reg <= NI_RTSI_OUTPUT_RTSI_BRD(3)) {
+ const int i = reg - NI_RTSI_OUTPUT_RTSI_BRD(0);
+
+ dest = NI_RTSI_BRD(i); /* prepare for lookup */
+ reg = get_ith_rtsi_brd_reg(i, dev);
+ }
+ }
+ } else if (dest >= NI_CtrOut(0) && dest <= NI_CtrOut(-1)) {
+ /*
+ * not handled by ni_tio. Only available for GPFO registers in
+ * e/m series.
+ */
+ dest -= NI_CtrOut(0);
+ if (dest > 1)
+ /* there are only two g_out outputs. */
+ return -EINVAL;
+ reg = ni_get_gout_routing(dest, dev);
+ } else if (channel_is_ctr(dest)) {
+ reg = ni_tio_get_routing(devpriv->counter_dev, dest);
+ } else {
+ dev_dbg(dev->class_dev, "%s: unhandled destination (%d) queried\n",
+ __func__, dest);
+ }
+
+ if (reg >= 0)
+ return ni_find_route_source(CR_CHAN(reg), dest,
+ &devpriv->routing_tables);
+ return -EINVAL;
+}
+
+/*
+ * Test a route:
+ *
+ * Return: -1 if not connectible;
+ * 0 if connectible and not connected;
+ * 1 if connectible and connected.
+ */
+static int test_route(unsigned int src, unsigned int dest,
+ struct comedi_device *dev)
+{
+ struct ni_private *devpriv = dev->private;
+ s8 reg = ni_route_to_register(CR_CHAN(src), dest,
+ &devpriv->routing_tables);
+
+ if (reg < 0)
+ return -1;
+ if (get_output_select_source(dest, dev) != CR_CHAN(src))
+ return 0;
+ return 1;
+}
+
+/* Connect the actual route. */
+static int connect_route(unsigned int src, unsigned int dest,
+ struct comedi_device *dev)
+{
+ struct ni_private *devpriv = dev->private;
+ s8 reg = ni_route_to_register(CR_CHAN(src), dest,
+ &devpriv->routing_tables);
+ s8 current_src;
+
+ if (reg < 0)
+ /* route is not valid */
+ return -EINVAL;
+
+ current_src = get_output_select_source(dest, dev);
+ if (current_src == CR_CHAN(src))
+ return -EALREADY;
+ if (current_src >= 0)
+ /* destination mux is already busy. complain, don't overwrite */
+ return -EBUSY;
+
+ /* The route is valid and available. Now connect... */
+ if (channel_is_pfi(dest)) {
+ /* set routing source, then open output */
+ ni_set_pfi_routing(dev, dest, reg);
+ ni_set_pfi_direction(dev, dest, COMEDI_OUTPUT);
+ } else if (channel_is_rtsi(dest)) {
+ if (reg == NI_RTSI_OUTPUT_RGOUT0) {
+ int ret = incr_rgout0_src_use(src, dev);
+
+ if (ret < 0)
+ return ret;
+ } else if (ni_rtsi_route_requires_mux(reg)) {
+ /* Attempt to allocate and route (src->brd) */
+ int brd = incr_rtsi_brd_src_use(src, dev);
+
+ if (brd < 0)
+ return brd;
+
+ /* Now lookup the register value for (brd->dest) */
+ reg = ni_lookup_route_register(
+ brd, dest, &devpriv->routing_tables);
+ }
+
+ ni_set_rtsi_direction(dev, dest, COMEDI_OUTPUT);
+ ni_set_rtsi_routing(dev, dest, reg);
+ } else if (dest >= NI_CtrOut(0) && dest <= NI_CtrOut(-1)) {
+ /*
+ * not handled by ni_tio. Only available for GPFO registers in
+ * e/m series.
+ */
+ dest -= NI_CtrOut(0);
+ if (dest > 1)
+ /* there are only two g_out outputs. */
+ return -EINVAL;
+ if (ni_set_gout_routing(src, dest, dev))
+ return -EINVAL;
+ } else if (channel_is_ctr(dest)) {
+ /*
+ * we are adding back the channel modifier info to set
+ * invert/edge info passed by the user
+ */
+ ni_tio_set_routing(devpriv->counter_dev, dest,
+ reg | (src & ~CR_CHAN(-1)));
+ } else {
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int disconnect_route(unsigned int src, unsigned int dest,
+ struct comedi_device *dev)
+{
+ struct ni_private *devpriv = dev->private;
+ s8 reg = ni_route_to_register(CR_CHAN(src), dest,
+ &devpriv->routing_tables);
+
+ if (reg < 0)
+ /* route is not valid */
+ return -EINVAL;
+ if (get_output_select_source(dest, dev) != src)
+ /* cannot disconnect something not connected */
+ return -EINVAL;
+
+ /* The route is valid and is connected. Now disconnect... */
+ if (channel_is_pfi(dest)) {
+ /* set the pfi to high impedance, and disconnect */
+ ni_set_pfi_direction(dev, dest, COMEDI_INPUT);
+ ni_set_pfi_routing(dev, dest, NI_PFI_OUTPUT_PFI_DEFAULT);
+ } else if (channel_is_rtsi(dest)) {
+ if (reg == NI_RTSI_OUTPUT_RGOUT0) {
+ int ret = decr_rgout0_src_use(src, dev);
+
+ if (ret < 0)
+ return ret;
+ } else if (ni_rtsi_route_requires_mux(reg)) {
+ /* find which RTSI_BRD line is source for rtsi pin */
+ int brd = ni_find_route_source(
+ ni_get_rtsi_routing(dev, dest), dest,
+ &devpriv->routing_tables);
+
+ if (brd < 0)
+ return brd;
+
+ /* decrement/disconnect RTSI_BRD line from source */
+ decr_rtsi_brd_src_use(src, brd, dev);
+ }
+
+ /* set rtsi output selector to default state */
+ reg = default_rtsi_routing[dest - TRIGGER_LINE(0)];
+ ni_set_rtsi_direction(dev, dest, COMEDI_INPUT);
+ ni_set_rtsi_routing(dev, dest, reg);
+ } else if (dest >= NI_CtrOut(0) && dest <= NI_CtrOut(-1)) {
+ /*
+ * not handled by ni_tio. Only available for GPFO registers in
+ * e/m series.
+ */
+ dest -= NI_CtrOut(0);
+ if (dest > 1)
+ /* there are only two g_out outputs. */
+ return -EINVAL;
+ reg = ni_disable_gout_routing(dest, dev);
+ } else if (channel_is_ctr(dest)) {
+ ni_tio_unset_routing(devpriv->counter_dev, dest);
+ } else {
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int ni_global_insn_config(struct comedi_device *dev,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ switch (data[0]) {
+ case INSN_DEVICE_CONFIG_TEST_ROUTE:
+ data[0] = test_route(data[1], data[2], dev);
+ return 2;
+ case INSN_DEVICE_CONFIG_CONNECT_ROUTE:
+ return connect_route(data[1], data[2], dev);
+ case INSN_DEVICE_CONFIG_DISCONNECT_ROUTE:
+ return disconnect_route(data[1], data[2], dev);
/*
- * Sets the source and direction of the 4 on board lines
- * ni_stc_writew(dev, 0, NISTC_RTSI_BOARD_REG);
+ * This case is already handled one level up.
+ * case INSN_DEVICE_CONFIG_GET_ROUTES:
*/
+ default:
+ return -EINVAL;
+ }
+ return 1;
}
#ifdef PCIDMA
@@ -5244,6 +5932,16 @@ static int ni_alloc_private(struct comedi_device *dev)
return 0;
}
+static unsigned int _ni_get_valid_routes(struct comedi_device *dev,
+ unsigned int n_pairs,
+ unsigned int *pair_data)
+{
+ struct ni_private *devpriv = dev->private;
+
+ return ni_get_valid_routes(&devpriv->routing_tables, n_pairs,
+ pair_data);
+}
+
static int ni_E_init(struct comedi_device *dev,
unsigned int interrupt_pin, unsigned int irq_polarity)
{
@@ -5252,6 +5950,24 @@ static int ni_E_init(struct comedi_device *dev,
struct comedi_subdevice *s;
int ret;
int i;
+ const char *dev_family = devpriv->is_m_series ? "ni_mseries"
+ : "ni_eseries";
+
+ /* prepare the device for globally-named routes. */
+ if (ni_assign_device_routes(dev_family, board->name,
+ &devpriv->routing_tables) < 0) {
+ dev_warn(dev->class_dev, "%s: %s device has no signal routing table.\n",
+ __func__, board->name);
+ dev_warn(dev->class_dev, "%s: High level NI signal names will not be available for this %s board.\n",
+ __func__, board->name);
+ } else {
+ /*
+ * only(?) assign insn_device_config if we have global names for
+ * this device.
+ */
+ dev->insn_device_config = ni_global_insn_config;
+ dev->get_valid_routes = _ni_get_valid_routes;
+ }
if (board->n_aochan > MAX_N_AO_CHAN) {
dev_err(dev->class_dev, "bug! n_aochan > MAX_N_AO_CHAN\n");
@@ -5508,7 +6224,9 @@ static int ni_E_init(struct comedi_device *dev,
(devpriv->is_m_series)
? ni_gpct_variant_m_series
: ni_gpct_variant_e_series,
- NUM_GPCT);
+ NUM_GPCT,
+ NUM_GPCT,
+ &devpriv->routing_tables);
if (!devpriv->counter_dev)
return -ENOMEM;
@@ -5517,8 +6235,6 @@ static int ni_E_init(struct comedi_device *dev,
struct ni_gpct *gpct = &devpriv->counter_dev->counters[i];
/* setup and initialize the counter */
- gpct->chip_index = 0;
- gpct->counter_index = i;
ni_tio_init_counter(gpct);
s = &dev->subdevices[NI_GPCT_SUBDEV(i)];
@@ -5544,6 +6260,10 @@ static int ni_E_init(struct comedi_device *dev,
s->private = gpct;
}
+ /* Initialize GPFO_{0,1} to produce output of counters */
+ ni_set_gout_routing(0, 0, dev); /* output of counter 0; DAQ STC, p338 */
+ ni_set_gout_routing(0, 1, dev); /* output of counter 1; DAQ STC, p338 */
+
/* Frequency output subdevice */
s = &dev->subdevices[NI_FREQ_OUT_SUBDEV];
s->type = COMEDI_SUBD_COUNTER;
diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c
index 6692af5ff79b..b9a0dc6eac44 100644
--- a/drivers/staging/comedi/drivers/ni_pcidio.c
+++ b/drivers/staging/comedi/drivers/ni_pcidio.c
@@ -260,18 +260,22 @@ enum nidio_boardid {
struct nidio_board {
const char *name;
unsigned int uses_firmware:1;
+ unsigned int dio_speed;
};
static const struct nidio_board nidio_boards[] = {
[BOARD_PCIDIO_32HS] = {
.name = "pci-dio-32hs",
+ .dio_speed = 50,
},
[BOARD_PXI6533] = {
.name = "pxi-6533",
+ .dio_speed = 50,
},
[BOARD_PCI6534] = {
.name = "pci-6534",
.uses_firmware = 1,
+ .dio_speed = 50,
},
};
@@ -467,6 +471,15 @@ static int ni_pcidio_insn_config(struct comedi_device *dev,
{
int ret;
+ if (data[0] == INSN_CONFIG_GET_CMD_TIMING_CONSTRAINTS) {
+ const struct nidio_board *board = dev->board_ptr;
+
+ /* we don't care about actual channels */
+ data[1] = board->dio_speed;
+ data[2] = 0;
+ return 0;
+ }
+
ret = comedi_dio_insn_config(dev, s, insn, data, 0);
if (ret)
return ret;
diff --git a/drivers/staging/comedi/drivers/ni_pcimio.c b/drivers/staging/comedi/drivers/ni_pcimio.c
index f9e466d18b3f..14b26fffe049 100644
--- a/drivers/staging/comedi/drivers/ni_pcimio.c
+++ b/drivers/staging/comedi/drivers/ni_pcimio.c
@@ -693,6 +693,7 @@ static const struct ni_board_struct ni_boards[] = {
.ai_speed = 4000,
.reg_type = ni_reg_622x,
.caldac = { caldac_none },
+ .dio_speed = 1000,
},
[BOARD_PCI6221] = {
.name = "pci-6221",
@@ -708,6 +709,7 @@ static const struct ni_board_struct ni_boards[] = {
.reg_type = ni_reg_622x,
.ao_speed = 1200,
.caldac = { caldac_none },
+ .dio_speed = 1000,
},
[BOARD_PCI6221_37PIN] = {
.name = "pci-6221_37pin",
@@ -738,6 +740,7 @@ static const struct ni_board_struct ni_boards[] = {
.reg_type = ni_reg_622x,
.ao_speed = 1200,
.caldac = { caldac_none },
+ .dio_speed = 1000,
},
[BOARD_PCI6224] = {
.name = "pci-6224",
@@ -749,6 +752,7 @@ static const struct ni_board_struct ni_boards[] = {
.reg_type = ni_reg_622x,
.has_32dio_chan = 1,
.caldac = { caldac_none },
+ .dio_speed = 1000,
},
[BOARD_PXI6224] = {
.name = "pxi-6224",
@@ -760,6 +764,7 @@ static const struct ni_board_struct ni_boards[] = {
.reg_type = ni_reg_622x,
.has_32dio_chan = 1,
.caldac = { caldac_none },
+ .dio_speed = 1000,
},
[BOARD_PCI6225] = {
.name = "pci-6225",
@@ -776,6 +781,7 @@ static const struct ni_board_struct ni_boards[] = {
.ao_speed = 1200,
.has_32dio_chan = 1,
.caldac = { caldac_none },
+ .dio_speed = 1000,
},
[BOARD_PXI6225] = {
.name = "pxi-6225",
@@ -792,6 +798,7 @@ static const struct ni_board_struct ni_boards[] = {
.ao_speed = 1200,
.has_32dio_chan = 1,
.caldac = { caldac_none },
+ .dio_speed = 1000,
},
[BOARD_PCI6229] = {
.name = "pci-6229",
@@ -824,6 +831,7 @@ static const struct ni_board_struct ni_boards[] = {
.ao_speed = 1200,
.has_32dio_chan = 1,
.caldac = { caldac_none },
+ .dio_speed = 1000,
},
[BOARD_PCI6250] = {
.name = "pci-6250",
@@ -844,6 +852,7 @@ static const struct ni_board_struct ni_boards[] = {
.ai_speed = 800,
.reg_type = ni_reg_625x,
.caldac = { caldac_none },
+ .dio_speed = 100,
},
[BOARD_PCI6251] = {
.name = "pci-6251",
@@ -859,6 +868,7 @@ static const struct ni_board_struct ni_boards[] = {
.reg_type = ni_reg_625x,
.ao_speed = 350,
.caldac = { caldac_none },
+ .dio_speed = 100,
},
[BOARD_PXI6251] = {
.name = "pxi-6251",
@@ -874,6 +884,7 @@ static const struct ni_board_struct ni_boards[] = {
.reg_type = ni_reg_625x,
.ao_speed = 350,
.caldac = { caldac_none },
+ .dio_speed = 100,
},
[BOARD_PCIE6251] = {
.name = "pcie-6251",
@@ -889,6 +900,7 @@ static const struct ni_board_struct ni_boards[] = {
.reg_type = ni_reg_625x,
.ao_speed = 350,
.caldac = { caldac_none },
+ .dio_speed = 100,
},
[BOARD_PXIE6251] = {
.name = "pxie-6251",
@@ -904,6 +916,7 @@ static const struct ni_board_struct ni_boards[] = {
.reg_type = ni_reg_625x,
.ao_speed = 350,
.caldac = { caldac_none },
+ .dio_speed = 100,
},
[BOARD_PCI6254] = {
.name = "pci-6254",
@@ -926,6 +939,7 @@ static const struct ni_board_struct ni_boards[] = {
.reg_type = ni_reg_625x,
.has_32dio_chan = 1,
.caldac = { caldac_none },
+ .dio_speed = 100,
},
[BOARD_PCI6259] = {
.name = "pci-6259",
@@ -958,6 +972,7 @@ static const struct ni_board_struct ni_boards[] = {
.ao_speed = 350,
.has_32dio_chan = 1,
.caldac = { caldac_none },
+ .dio_speed = 100,
},
[BOARD_PCIE6259] = {
.name = "pcie-6259",
@@ -990,6 +1005,7 @@ static const struct ni_board_struct ni_boards[] = {
.ao_speed = 350,
.has_32dio_chan = 1,
.caldac = { caldac_none },
+ .dio_speed = 100,
},
[BOARD_PCI6280] = {
.name = "pci-6280",
@@ -1012,6 +1028,7 @@ static const struct ni_board_struct ni_boards[] = {
.ao_fifo_depth = 8191,
.reg_type = ni_reg_628x,
.caldac = { caldac_none },
+ .dio_speed = 100,
},
[BOARD_PCI6281] = {
.name = "pci-6281",
@@ -1027,6 +1044,7 @@ static const struct ni_board_struct ni_boards[] = {
.reg_type = ni_reg_628x,
.ao_speed = 350,
.caldac = { caldac_none },
+ .dio_speed = 100,
},
[BOARD_PXI6281] = {
.name = "pxi-6281",
@@ -1042,6 +1060,7 @@ static const struct ni_board_struct ni_boards[] = {
.reg_type = ni_reg_628x,
.ao_speed = 350,
.caldac = { caldac_none },
+ .dio_speed = 100,
},
[BOARD_PCI6284] = {
.name = "pci-6284",
@@ -1064,6 +1083,7 @@ static const struct ni_board_struct ni_boards[] = {
.reg_type = ni_reg_628x,
.has_32dio_chan = 1,
.caldac = { caldac_none },
+ .dio_speed = 100,
},
[BOARD_PCI6289] = {
.name = "pci-6289",
@@ -1096,6 +1116,7 @@ static const struct ni_board_struct ni_boards[] = {
.ao_speed = 350,
.has_32dio_chan = 1,
.caldac = { caldac_none },
+ .dio_speed = 100,
},
[BOARD_PCI6143] = {
.name = "pci-6143",
diff --git a/drivers/staging/comedi/drivers/ni_routes.c b/drivers/staging/comedi/drivers/ni_routes.c
new file mode 100644
index 000000000000..eb61494dc2bd
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routes.c
@@ -0,0 +1,523 @@
+// 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/bsearch.h>
+#include <linux/sort.h>
+
+#include "../comedi.h"
+
+#include "ni_routes.h"
+#include "ni_routing/ni_route_values.h"
+#include "ni_routing/ni_device_routes.h"
+
+/*
+ * This is defined in ni_routing/ni_route_values.h:
+ * #define B(x) ((x) - NI_NAMES_BASE)
+ */
+
+/*
+ * These are defined in ni_routing/ni_route_values.h to identify clearly
+ * elements of the table that were set. In other words, entries that are zero
+ * are invalid. To get the value to use for the register, one must mask out the
+ * high bit.
+ *
+ * #define V(x) ((x) | 0x80)
+ *
+ * #define UNMARK(x) ((x) & (~(0x80)))
+ *
+ */
+
+/* Helper for accessing data. */
+#define RVi(table, src, dest) ((table)[(dest) * NI_NUM_NAMES + (src)])
+
+static const size_t route_table_size = NI_NUM_NAMES * NI_NUM_NAMES;
+
+/*
+ * Find the proper route_values and ni_device_routes tables for this particular
+ * device.
+ *
+ * Return: -ENODATA if either was not found; 0 if both were found.
+ */
+static int ni_find_device_routes(const char *device_family,
+ const char *board_name,
+ struct ni_route_tables *tables)
+{
+ const struct ni_device_routes *dr = NULL;
+ const u8 *rv = NULL;
+ int i;
+
+ /* First, find the register_values table for this device family */
+ for (i = 0; ni_all_route_values[i]; ++i) {
+ if (memcmp(ni_all_route_values[i]->family, device_family,
+ strnlen(device_family, 30)) == 0) {
+ rv = &ni_all_route_values[i]->register_values[0][0];
+ break;
+ }
+ }
+
+ if (!rv)
+ return -ENODATA;
+
+ /* Second, find the set of routes valid for this device. */
+ for (i = 0; ni_device_routes_list[i]; ++i) {
+ if (memcmp(ni_device_routes_list[i]->device, board_name,
+ strnlen(board_name, 30)) == 0) {
+ dr = ni_device_routes_list[i];
+ break;
+ }
+ }
+
+ if (!dr)
+ return -ENODATA;
+
+ tables->route_values = rv;
+ tables->valid_routes = dr;
+
+ return 0;
+}
+
+/**
+ * ni_assign_device_routes() - Assign the proper lookup table for NI signal
+ * routing to the specified NI device.
+ *
+ * Return: -ENODATA if assignment was not successful; 0 if successful.
+ */
+int ni_assign_device_routes(const char *device_family,
+ const char *board_name,
+ struct ni_route_tables *tables)
+{
+ memset(tables, 0, sizeof(struct ni_route_tables));
+ return ni_find_device_routes(device_family, board_name, tables);
+}
+EXPORT_SYMBOL_GPL(ni_assign_device_routes);
+
+/**
+ * ni_count_valid_routes() - Count the number of valid routes.
+ * @tables: Routing tables for which to count all valid routes.
+ */
+unsigned int ni_count_valid_routes(const struct ni_route_tables *tables)
+{
+ int total = 0;
+ int i;
+
+ for (i = 0; i < tables->valid_routes->n_route_sets; ++i) {
+ const struct ni_route_set *R = &tables->valid_routes->routes[i];
+ int j;
+
+ for (j = 0; j < R->n_src; ++j) {
+ const int src = R->src[j];
+ const int dest = R->dest;
+ const u8 *rv = tables->route_values;
+
+ if (RVi(rv, B(src), B(dest)))
+ /* direct routing is valid */
+ ++total;
+ else if (channel_is_rtsi(dest) &&
+ (RVi(rv, B(src), B(NI_RGOUT0)) ||
+ RVi(rv, B(src), B(NI_RTSI_BRD(0))) ||
+ RVi(rv, B(src), B(NI_RTSI_BRD(1))) ||
+ RVi(rv, B(src), B(NI_RTSI_BRD(2))) ||
+ RVi(rv, B(src), B(NI_RTSI_BRD(3))))) {
+ ++total;
+ }
+ }
+ }
+ return total;
+}
+EXPORT_SYMBOL_GPL(ni_count_valid_routes);
+
+/**
+ * ni_get_valid_routes() - Implements INSN_DEVICE_CONFIG_GET_ROUTES.
+ * @tables: pointer to relevant set of routing tables.
+ * @n_pairs: Number of pairs for which memory is allocated by the user. If
+ * the user specifies '0', only the number of available pairs is
+ * returned.
+ * @pair_data: Pointer to memory allocated to return pairs back to user. Each
+ * even, odd indexed member of this array will hold source,
+ * destination of a route pair respectively.
+ *
+ * Return: the number of valid routes if n_pairs == 0; otherwise, the number of
+ * valid routes copied.
+ */
+unsigned int ni_get_valid_routes(const struct ni_route_tables *tables,
+ unsigned int n_pairs,
+ unsigned int *pair_data)
+{
+ unsigned int n_valid = ni_count_valid_routes(tables);
+ int i;
+
+ if (n_pairs == 0 || n_valid == 0)
+ return n_valid;
+
+ if (!pair_data)
+ return 0;
+
+ n_valid = 0;
+
+ for (i = 0; i < tables->valid_routes->n_route_sets; ++i) {
+ const struct ni_route_set *R = &tables->valid_routes->routes[i];
+ int j;
+
+ for (j = 0; j < R->n_src; ++j) {
+ const int src = R->src[j];
+ const int dest = R->dest;
+ bool valid = false;
+ const u8 *rv = tables->route_values;
+
+ if (RVi(rv, B(src), B(dest)))
+ /* direct routing is valid */
+ valid = true;
+ else if (channel_is_rtsi(dest) &&
+ (RVi(rv, B(src), B(NI_RGOUT0)) ||
+ RVi(rv, B(src), B(NI_RTSI_BRD(0))) ||
+ RVi(rv, B(src), B(NI_RTSI_BRD(1))) ||
+ RVi(rv, B(src), B(NI_RTSI_BRD(2))) ||
+ RVi(rv, B(src), B(NI_RTSI_BRD(3))))) {
+ /* indirect routing also valid */
+ valid = true;
+ }
+
+ if (valid) {
+ pair_data[2 * n_valid] = src;
+ pair_data[2 * n_valid + 1] = dest;
+ ++n_valid;
+ }
+
+ if (n_valid >= n_pairs)
+ return n_valid;
+ }
+ }
+ return n_valid;
+}
+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.
+ */
+static const int NI_CMD_DESTS[] = {
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+};
+
+/**
+ * ni_is_cmd_dest() - Determine whether the given destination is only
+ * configurable via a comedi_cmd struct.
+ * @dest: Destination to test.
+ */
+bool ni_is_cmd_dest(int dest)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(NI_CMD_DESTS); ++i)
+ if (NI_CMD_DESTS[i] == dest)
+ return true;
+ return false;
+}
+EXPORT_SYMBOL_GPL(ni_is_cmd_dest);
+
+/* **** BEGIN Routes sort routines **** */
+static int _ni_sort_destcmp(const void *va, const void *vb)
+{
+ const struct ni_route_set *a = va;
+ const struct ni_route_set *b = vb;
+
+ if (a->dest < b->dest)
+ return -1;
+ else if (a->dest > b->dest)
+ return 1;
+ return 0;
+}
+
+static int _ni_sort_srccmp(const void *vsrc0, const void *vsrc1)
+{
+ const int *src0 = vsrc0;
+ const int *src1 = vsrc1;
+
+ if (*src0 < *src1)
+ return -1;
+ else if (*src0 > *src1)
+ return 1;
+ return 0;
+}
+
+/**
+ * ni_sort_device_routes() - Sort the list of valid device signal routes in
+ * preparation for use.
+ * @valid_routes: pointer to ni_device_routes struct to sort.
+ */
+void ni_sort_device_routes(struct ni_device_routes *valid_routes)
+{
+ unsigned int n;
+
+ /* 1. Count and set the number of ni_route_set objects. */
+ valid_routes->n_route_sets = 0;
+ while (valid_routes->routes[valid_routes->n_route_sets].dest != 0)
+ ++valid_routes->n_route_sets;
+
+ /* 2. sort all ni_route_set objects by destination. */
+ sort(valid_routes->routes, valid_routes->n_route_sets,
+ sizeof(struct ni_route_set), _ni_sort_destcmp, NULL);
+
+ /* 3. Loop through each route_set for sorting. */
+ for (n = 0; n < valid_routes->n_route_sets; ++n) {
+ struct ni_route_set *rs = &valid_routes->routes[n];
+
+ /* 3a. Count and set the number of sources. */
+ rs->n_src = 0;
+ while (rs->src[rs->n_src])
+ ++rs->n_src;
+
+ /* 3a. Sort sources. */
+ sort(valid_routes->routes[n].src, valid_routes->routes[n].n_src,
+ sizeof(int), _ni_sort_srccmp, NULL);
+ }
+}
+EXPORT_SYMBOL_GPL(ni_sort_device_routes);
+
+/* sort all valid device signal routes in prep for use */
+static void ni_sort_all_device_routes(void)
+{
+ unsigned int i;
+
+ for (i = 0; ni_device_routes_list[i]; ++i)
+ ni_sort_device_routes(ni_device_routes_list[i]);
+}
+
+/* **** BEGIN Routes search routines **** */
+static int _ni_bsearch_destcmp(const void *vkey, const void *velt)
+{
+ const int *key = vkey;
+ const struct ni_route_set *elt = velt;
+
+ if (*key < elt->dest)
+ return -1;
+ else if (*key > elt->dest)
+ return 1;
+ return 0;
+}
+
+static int _ni_bsearch_srccmp(const void *vkey, const void *velt)
+{
+ const int *key = vkey;
+ const int *elt = velt;
+
+ if (*key < *elt)
+ return -1;
+ else if (*key > *elt)
+ return 1;
+ return 0;
+}
+
+/**
+ * ni_find_route_set() - Finds the proper route set with the specified
+ * destination.
+ * @destination: Destination of which to search for the route set.
+ * @valid_routes: Pointer to device routes within which to search.
+ *
+ * Return: NULL if no route_set is found with the specified @destination;
+ * otherwise, a pointer to the route_set if found.
+ */
+const struct ni_route_set *
+ni_find_route_set(const int destination,
+ const struct ni_device_routes *valid_routes)
+{
+ return bsearch(&destination, valid_routes->routes,
+ valid_routes->n_route_sets, sizeof(struct ni_route_set),
+ _ni_bsearch_destcmp);
+}
+EXPORT_SYMBOL_GPL(ni_find_route_set);
+
+/**
+ * ni_route_set_has_source() - Determines whether the given source is in
+ * included given route_set.
+ *
+ * Return: true if found; false otherwise.
+ */
+bool ni_route_set_has_source(const struct ni_route_set *routes,
+ const int source)
+{
+ if (!bsearch(&source, routes->src, routes->n_src, sizeof(int),
+ _ni_bsearch_srccmp))
+ return false;
+ return true;
+}
+EXPORT_SYMBOL_GPL(ni_route_set_has_source);
+
+/**
+ * ni_lookup_route_register() - Look up a register value for a particular route
+ * without checking whether the route is valid for
+ * the particular device.
+ * @src: global-identifier for route source
+ * @dest: global-identifier for route destination
+ * @tables: pointer to relevant set of routing tables.
+ *
+ * Return: -EINVAL if the specified route is not valid for this device family.
+ */
+s8 ni_lookup_route_register(int src, int dest,
+ const struct ni_route_tables *tables)
+{
+ s8 regval;
+
+ /*
+ * Be sure to use the B() macro to subtract off the NI_NAMES_BASE before
+ * indexing into the route_values array.
+ */
+ src = B(src);
+ dest = B(dest);
+ if (src < 0 || src >= NI_NUM_NAMES || dest < 0 || dest >= NI_NUM_NAMES)
+ return -EINVAL;
+ regval = RVi(tables->route_values, src, dest);
+ if (!regval)
+ return -EINVAL;
+ /* mask out the valid-value marking bit */
+ return UNMARK(regval);
+}
+EXPORT_SYMBOL_GPL(ni_lookup_route_register);
+
+/**
+ * ni_route_to_register() - Validates and converts the specified signal route
+ * (src-->dest) to the value used at the appropriate
+ * register.
+ * @src: global-identifier for route source
+ * @dest: global-identifier for route destination
+ * @tables: pointer to relevant set of routing tables.
+ *
+ * Generally speaking, most routes require the first six bits and a few require
+ * 7 bits. Special handling is given for the return value when the route is to
+ * be handled by the RTSI sub-device. In this case, the returned register may
+ * not be sufficient to define the entire route path, but rather may only
+ * indicate the intermediate route. For example, if the route must go through
+ * the RGOUT0 pin, the (src->RGOUT0) register value will be returned.
+ * Similarly, if the route must go through the NI_RTSI_BRD lines, the BIT(6)
+ * will be set:
+ *
+ * if route does not need RTSI_BRD lines:
+ * bits 0:7 : register value
+ * for a route that must go through RGOUT0 pin, this will be equal
+ * to the (src->RGOUT0) register value.
+ * else: * route is (src->RTSI_BRD(x), RTSI_BRD(x)->TRIGGER_LINE(i)) *
+ * bits 0:5 : zero
+ * bits 6 : set to 1
+ * bits 7:7 : zero
+ *
+ * Return: register value to be used for source at destination with special
+ * cases given above; Otherwise, -1 if the specified route is not valid for
+ * this particular device.
+ */
+s8 ni_route_to_register(const int src, const int dest,
+ const struct ni_route_tables *tables)
+{
+ const struct ni_route_set *routes =
+ ni_find_route_set(dest, tables->valid_routes);
+ const u8 *rv;
+ s8 regval;
+
+ /* first check to see if source is listed with bunch of destinations. */
+ if (!routes)
+ return -1;
+ /* 2nd, check to see if destination is in list of source's targets. */
+ if (!ni_route_set_has_source(routes, src))
+ return -1;
+ /*
+ * finally, check to see if we know how to route...
+ * Be sure to use the B() macro to subtract off the NI_NAMES_BASE before
+ * indexing into the route_values array.
+ */
+ rv = tables->route_values;
+ regval = RVi(rv, B(src), B(dest));
+
+ /*
+ * if we did not validate the route, we'll see if we can route through
+ * one of the muxes
+ */
+ if (!regval && channel_is_rtsi(dest)) {
+ regval = RVi(rv, B(src), B(NI_RGOUT0));
+ if (!regval && (RVi(rv, B(src), B(NI_RTSI_BRD(0))) ||
+ RVi(rv, B(src), B(NI_RTSI_BRD(1))) ||
+ RVi(rv, B(src), B(NI_RTSI_BRD(2))) ||
+ RVi(rv, B(src), B(NI_RTSI_BRD(3)))))
+ regval = BIT(6);
+ }
+
+ if (!regval)
+ return -1;
+ /* mask out the valid-value marking bit */
+ return UNMARK(regval);
+}
+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
+ * specified device.
+ *
+ * Note that this function does _not_ validate the source based on device
+ * routes.
+ *
+ * Return: The NI signal value (e.g. NI_PFI(0) or PXI_Clk10) if found.
+ * If the source was not found (i.e. the register value is not
+ * valid for any routes to the destination), -EINVAL is returned.
+ */
+int ni_find_route_source(const u8 src_sel_reg_value, int dest,
+ const struct ni_route_tables *tables)
+{
+ int src;
+
+ dest = B(dest); /* subtract NI names offset */
+ /* ensure we are not going to under/over run the route value table */
+ if (dest < 0 || dest >= NI_NUM_NAMES)
+ return -EINVAL;
+ for (src = 0; src < NI_NUM_NAMES; ++src)
+ if (RVi(tables->route_values, src, dest) ==
+ V(src_sel_reg_value))
+ return src + NI_NAMES_BASE;
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(ni_find_route_source);
+
+/* **** END Routes search routines **** */
+
+/* **** BEGIN simple module entry/exit functions **** */
+static int __init ni_routes_module_init(void)
+{
+ ni_sort_all_device_routes();
+ return 0;
+}
+
+static void __exit ni_routes_module_exit(void)
+{
+}
+
+module_init(ni_routes_module_init);
+module_exit(ni_routes_module_exit);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi helper for routing signals-->terminals for NI");
+MODULE_LICENSE("GPL");
+/* **** END simple module entry/exit functions **** */
diff --git a/drivers/staging/comedi/drivers/ni_routes.h b/drivers/staging/comedi/drivers/ni_routes.h
new file mode 100644
index 000000000000..3211a16adc6f
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routes.h
@@ -0,0 +1,329 @@
+/* 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _COMEDI_DRIVERS_NI_ROUTES_H
+#define _COMEDI_DRIVERS_NI_ROUTES_H
+
+#include <linux/types.h>
+#include <linux/errno.h>
+
+#ifndef NI_ROUTE_VALUE_EXTERNAL_CONVERSION
+#include <linux/bitops.h>
+#endif
+
+#include "../comedi.h"
+
+/**
+ * struct ni_route_set - Set of destinations with a common source.
+ * @dest: Destination of all sources in this route set.
+ * @n_src: Number of sources for this route set.
+ * @src: List of sources that all map to the same destination.
+ */
+struct ni_route_set {
+ int dest;
+ int n_src;
+ int *src;
+};
+
+/**
+ * struct ni_device_routes - List of all src->dest sets for a particular device.
+ * @device: Name of board/device (e.g. pxi-6733).
+ * @n_route_sets: Number of route sets that are valid for this device.
+ * @routes: List of route sets that are valid for this device.
+ */
+struct ni_device_routes {
+ const char *device;
+ int n_route_sets;
+ struct ni_route_set *routes;
+};
+
+/**
+ * struct ni_route_tables - Register values and valid routes for a device.
+ * @valid_routes: Pointer to a all valid route sets for a single device.
+ * @route_values: Pointer to register values for all routes for the family to
+ * which the device belongs.
+ *
+ * Link to the valid src->dest routes and the register values used to assign
+ * such routes for that particular device.
+ */
+struct ni_route_tables {
+ const struct ni_device_routes *valid_routes;
+ const u8 *route_values;
+};
+
+/*
+ * ni_assign_device_routes() - Assign the proper lookup table for NI signal
+ * routing to the specified NI device.
+ *
+ * Return: -ENODATA if assignment was not successful; 0 if successful.
+ */
+int ni_assign_device_routes(const char *device_family,
+ const char *board_name,
+ struct ni_route_tables *tables);
+
+/*
+ * ni_find_route_set() - Finds the proper route set with the specified
+ * destination.
+ * @destination: Destination of which to search for the route set.
+ * @valid_routes: Pointer to device routes within which to search.
+ *
+ * Return: NULL if no route_set is found with the specified @destination;
+ * otherwise, a pointer to the route_set if found.
+ */
+const struct ni_route_set *
+ni_find_route_set(const int destination,
+ const struct ni_device_routes *valid_routes);
+
+/*
+ * ni_route_set_has_source() - Determines whether the given source is in
+ * included given route_set.
+ *
+ * Return: true if found; false otherwise.
+ */
+bool ni_route_set_has_source(const struct ni_route_set *routes, const int src);
+
+/*
+ * ni_route_to_register() - Validates and converts the specified signal route
+ * (src-->dest) to the value used at the appropriate
+ * register.
+ * @src: global-identifier for route source
+ * @dest: global-identifier for route destination
+ * @tables: pointer to relevant set of routing tables.
+ *
+ * Generally speaking, most routes require the first six bits and a few require
+ * 7 bits. Special handling is given for the return value when the route is to
+ * be handled by the RTSI sub-device. In this case, the returned register may
+ * not be sufficient to define the entire route path, but rather may only
+ * indicate the intermediate route. For example, if the route must go through
+ * the RGOUT0 pin, the (src->RGOUT0) register value will be returned.
+ * Similarly, if the route must go through the NI_RTSI_BRD lines, the BIT(6)
+ * will be set:
+ *
+ * if route does not need RTSI_BRD lines:
+ * bits 0:7 : register value
+ * for a route that must go through RGOUT0 pin, this will be equal
+ * to the (src->RGOUT0) register value.
+ * else: * route is (src->RTSI_BRD(x), RTSI_BRD(x)->TRIGGER_LINE(i)) *
+ * bits 0:5 : zero
+ * bits 6 : set to 1
+ * bits 7:7 : zero
+ *
+ * Return: register value to be used for source at destination with special
+ * cases given above; Otherwise, -1 if the specified route is not valid for
+ * this particular device.
+ */
+s8 ni_route_to_register(const int src, const int dest,
+ const struct ni_route_tables *tables);
+
+static inline bool ni_rtsi_route_requires_mux(s8 value)
+{
+ return value & BIT(6);
+}
+
+/*
+ * ni_lookup_route_register() - Look up a register value for a particular route
+ * without checking whether the route is valid for
+ * the particular device.
+ * @src: global-identifier for route source
+ * @dest: global-identifier for route destination
+ * @tables: pointer to relevant set of routing tables.
+ *
+ * Return: -EINVAL if the specified route is not valid for this device family.
+ */
+s8 ni_lookup_route_register(int src, int dest,
+ const struct ni_route_tables *tables);
+
+/**
+ * route_is_valid() - Determines whether the specified signal route (src-->dest)
+ * is valid for the given NI comedi_device.
+ * @src: global-identifier for route source
+ * @dest: global-identifier for route destination
+ * @tables: pointer to relevant set of routing tables.
+ *
+ * Return: True if the route is valid, otherwise false.
+ */
+static inline bool route_is_valid(const int src, const int dest,
+ const struct ni_route_tables *tables)
+{
+ return ni_route_to_register(src, dest, tables) >= 0;
+}
+
+/*
+ * ni_is_cmd_dest() - Determine whether the given destination is only
+ * configurable via a comedi_cmd struct.
+ * @dest: Destination to test.
+ */
+bool ni_is_cmd_dest(int dest);
+
+static inline bool channel_is_pfi(int channel)
+{
+ return NI_PFI(0) <= channel && channel <= NI_PFI(-1);
+}
+
+static inline bool channel_is_rtsi(int channel)
+{
+ return TRIGGER_LINE(0) <= channel && channel <= TRIGGER_LINE(-1);
+}
+
+static inline bool channel_is_ctr(int channel)
+{
+ return channel >= NI_COUNTER_NAMES_BASE &&
+ channel <= NI_COUNTER_NAMES_MAX;
+}
+
+/*
+ * ni_count_valid_routes() - Count the number of valid routes.
+ * @tables: Routing tables for which to count all valid routes.
+ */
+unsigned int ni_count_valid_routes(const struct ni_route_tables *tables);
+
+/*
+ * ni_get_valid_routes() - Implements INSN_DEVICE_CONFIG_GET_ROUTES.
+ * @tables: pointer to relevant set of routing tables.
+ * @n_pairs: Number of pairs for which memory is allocated by the user. If
+ * the user specifies '0', only the number of available pairs is
+ * returned.
+ * @pair_data: Pointer to memory allocated to return pairs back to user. Each
+ * even, odd indexed member of this array will hold source,
+ * destination of a route pair respectively.
+ *
+ * Return: the number of valid routes if n_pairs == 0; otherwise, the number of
+ * valid routes copied.
+ */
+unsigned int ni_get_valid_routes(const struct ni_route_tables *tables,
+ unsigned int n_pairs,
+ unsigned int *pair_data);
+
+/*
+ * ni_sort_device_routes() - Sort the list of valid device signal routes in
+ * preparation for use.
+ * @valid_routes: pointer to ni_device_routes struct to sort.
+ */
+void ni_sort_device_routes(struct ni_device_routes *valid_routes);
+
+/*
+ * 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
+ * specified device.
+ *
+ * Note that this function does _not_ validate the source based on device
+ * routes.
+ *
+ * Return: The NI signal value (e.g. NI_PFI(0) or PXI_Clk10) if found.
+ * If the source was not found (i.e. the register value is not
+ * valid for any routes to the destination), -EINVAL is returned.
+ */
+int ni_find_route_source(const u8 src_sel_reg_value, const int dest,
+ const struct ni_route_tables *tables);
+
+/**
+ * route_register_is_valid() - Determines whether the register value for the
+ * specified route destination on the specified
+ * device is valid.
+ */
+static inline bool route_register_is_valid(const u8 src_sel_reg_value,
+ const int dest,
+ const struct ni_route_tables *tables)
+{
+ return ni_find_route_source(src_sel_reg_value, dest, tables) >= 0;
+}
+
+/**
+ * ni_get_reg_value_roffs() - Determines the proper register value for a
+ * particular valid NI signal/terminal route.
+ * @src: Either a direct register value or one of NI_* signal names.
+ * @dest: global-identifier for route destination
+ * @tables: pointer to relevant set of routing tables.
+ * @direct_reg_offset:
+ * Compatibility compensation argument. This argument allows us to
+ * arbitrarily apply an offset to src if src is a direct register
+ * value reference. This is necessary to be compatible with
+ * definitions of register values as previously exported directly
+ * to user space.
+ *
+ * Return: the register value (>0) to be used at the destination if the src is
+ * valid for the given destination; -1 otherwise.
+ */
+static inline s8 ni_get_reg_value_roffs(int src, const int dest,
+ const struct ni_route_tables *tables,
+ const int direct_reg_offset)
+{
+ if (src < NI_NAMES_BASE) {
+ src += direct_reg_offset;
+ /*
+ * In this case, the src is expected to actually be a register
+ * value.
+ */
+ if (route_register_is_valid(src, dest, tables))
+ return src;
+ return -1;
+ }
+
+ /*
+ * Otherwise, the src is expected to be one of the abstracted NI
+ * signal/terminal names.
+ */
+ return ni_route_to_register(src, dest, tables);
+}
+
+static inline int ni_get_reg_value(const int src, const int dest,
+ const struct ni_route_tables *tables)
+{
+ return ni_get_reg_value_roffs(src, dest, tables, 0);
+}
+
+/**
+ * ni_check_trigger_arg_roffs() - Checks the trigger argument (*_arg) of an NI
+ * device to ensure that the *_arg value
+ * corresponds to _either_ a valid register value
+ * to define a trigger source, _or_ a valid NI
+ * signal/terminal name that has a valid route to
+ * the destination on the particular device.
+ * @src: Either a direct register value or one of NI_* signal names.
+ * @dest: global-identifier for route destination
+ * @tables: pointer to relevant set of routing tables.
+ * @direct_reg_offset:
+ * Compatibility compensation argument. This argument allows us to
+ * arbitrarily apply an offset to src if src is a direct register
+ * value reference. This is necessary to be compatible with
+ * definitions of register values as previously exported directly
+ * to user space.
+ *
+ * Return: 0 if the src (either register value or NI signal/terminal name) is
+ * valid for the destination; -EINVAL otherwise.
+ */
+static inline
+int ni_check_trigger_arg_roffs(int src, const int dest,
+ const struct ni_route_tables *tables,
+ const int direct_reg_offset)
+{
+ if (ni_get_reg_value_roffs(src, dest, tables, direct_reg_offset) < 0)
+ return -EINVAL;
+ return 0;
+}
+
+static inline int ni_check_trigger_arg(const int src, const int dest,
+ const struct ni_route_tables *tables)
+{
+ return ni_check_trigger_arg_roffs(src, dest, tables, 0);
+}
+
+#endif /* _COMEDI_DRIVERS_NI_ROUTES_H */
diff --git a/drivers/staging/comedi/drivers/ni_routing/README b/drivers/staging/comedi/drivers/ni_routing/README
new file mode 100644
index 000000000000..b65c4ebedbc4
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/README
@@ -0,0 +1,240 @@
+Framework for Maintaining Common National Instruments Terminal/Signal names
+
+The contents of this directory are primarily for maintaining and formatting all
+known valid signal routes for various National Instruments devices.
+
+Some background:
+ There have been significant confusions over the past many years for users
+ when trying to understand how to connect to/from signals and terminals on
+ NI hardware using comedi. The major reason for this is that the actual
+ register values were exposed and required to be used by users. Several
+ major reasons exist why this caused major confusion for users:
+
+ 1) The register values are _NOT_ in user documentation, but rather in
+ arcane locations, such as a few register programming manuals that are
+ increasingly hard to find and the NI-MHDDK (comments in in example code).
+ There is no one place to find the various valid values of the registers.
+
+ 2) The register values are _NOT_ completely consistent. There is no way to
+ gain any sense of intuition of which values, or even enums one should use
+ for various registers. There was some attempt in prior use of comedi to
+ name enums such that a user might know which enums should be used for
+ varying purposes, but the end-user had to gain a knowledge of register
+ values to correctly wield this approach.
+
+ 3) The names for signals and registers found in the various register level
+ programming manuals and vendor-provided documentation are _not_ even
+ close to the same names that are in the end-user documentation.
+
+ 4) The sets of routes that are valid are not consistent from device to device.
+ One additional major challenge is that this information does not seem to be
+ obtainable in any programmatic fashion, neither through the proprietary
+ NIDAQmx(-base) c-libraries, nor with register level programming, _nor_
+ through any documentation. In fact, the only consistent source of this
+ information is through the proprietary NI-MAX software, which currently only
+ runs on Windows platforms. A further challenge is that this information
+ cannot be exported from NI-MAX, except by screenshot.
+
+
+
+The content of this directory is part of an effort to greatly simplify the use
+of signal routing capabilities of National Instruments data-acquisition and
+control hardware. In order to facilitate the transfer of register-level
+information _and_ the knowledge of valid routes per device, a few specific
+choices were made:
+
+
+1) The names of the National Instruments signals/terminals that are used in this
+ directory are chosen to be consistent with (a) the NI's user level
+ documentation, (b) NI's user-level code, (c) the information as provided by
+ the proprietary NI-MAX software, and (d) the user interface code provided by
+ the user-land comedilib library.
+
+ The impact of this choice implies that one allows the use of CamelScript names
+ in the kernel. In short, the choice to use CamelScript and the exact names
+ below is for maintainability, clarity, similarity to manufacturer's
+ documentation, _and_ a mitigation for confusion that has plagued the use of
+ these drivers for years!
+
+2) The bulk of the real content for this directory is stored in two separate
+ collections (i.e. sub-directories) of tables stored in c source files:
+
+ (a) ni_route_values/ni_[series-label]series.c
+
+ This data represents all the various register values to use for the
+ multiple different signal MUXes for the specific device families.
+
+ The values are all wrapped in one of three macros to help document and
+ track which values have been implemented and tested.
+ These macros are:
+ V(<value>) : register value is valid, tested, and implemented
+ I(<value>) : register value is implemented but needs testing
+ U(<value>) : register value is not implemented
+
+ The actual function of these macros will depend on whether the code is
+ compiled in the kernel or whether it is compiled into the conversion
+ tools. For the conversion tools, it can be used to indicate the status
+ of the register value. For the kernel, V() and I() both perform the
+ same function and prepare data to be used; U() zeroes out the value to
+ ensure that it cannot be used.
+
+ *** It would be a great help for users to test these values such that
+ these files can be correctly marked/documented ***
+
+ (b) ni_device_routes/[board-name].c
+
+ This data represents the known set of valid signal routes that are
+ possible for each specific board. Although the family defines the
+ register values to use for a particular signal MUX, not all possible
+ signals are actually available on each board.
+
+ In order for a particular board to take advantage of the effort to
+ simplify/clarify signal routing on NI devices, a corresponding
+ [board-name].c file must be created. This file should reflect the known
+ valid _direct_ routing capabilities of the board.
+
+ As noted above, the only known consistent source of information for
+ valid device routes comes from the proprietary National Instruments
+ Windows software, NI-MAX. Also, as noted above, this information can
+ only be visually conveyed from NI-MAX to other media. To make this
+ easier, the naming conventions used in the [board-name].c file are
+ similar to the naming conventions as presented by NI-MAX.
+
+
+3) Two other files aggregate the above data to integrate it into comedi:
+ ni_route_values.c
+ ni_device_routes.c
+
+ When adding a new [board-name].c file, be sure to also add in the line in
+ ni_device_routes.c to include this information into comedi.
+
+
+4) Several tools have been included to convert from/to the c file formats.
+ These tools are best used/demonstrated via the included Makefile targets:
+ (a) `make csv-files`
+ Creates new csv-files using content of c-files of existing
+ ni_routing/* content. New csv files are placed in csv
+ sub-directory.
+
+ As noted above, the only consistent source of information of valid
+ device routes comes from the proprietary National Instruments Windows
+ software, NI-MAX. Also, as noted above, this information can only be
+ visually conveyed from NI-MAX to other media. This make target creates
+ spreadsheet representations of the routing data. The choice of using a
+ spreadsheet (ala CSV) to copy this information allows for easy direct
+ visual comparison to the NI-MAX "Valid Routes" tables.
+
+ Furthermore, the register-level information is much easier to identify and
+ correct when entire families of NI devices are shown side by side in table
+ format. This is made easy by using a file-storage format that can be
+ loaded into a spreadsheet application.
+
+ Finally, .csv content is very easy to edit and read using a variety of
+ tools, including spreadsheets or various other scripting languages. In
+ fact, the tools provided here enable quick conversion of the
+ spreadsheet-like .csv format to c-files that follow the kernel coding
+ conventions.
+
+
+ (b) `make c-files`
+ Creates new c-files using content of csv sub-directory. These
+ new c-files can be compared to the active content in the
+ ni_routing directory.
+ (c) `make csv-blank`
+ Create a new blank csv file. This is useful for establishing a
+ new data table for either a device family (less likely) or a
+ specific board of an existing device family (more likely).
+ (d) `make clean`
+ Remove all generated files/directories.
+ (e) `make everything`
+ Build all csv-files, then all new c-files.
+
+
+
+
+In summary, similar confusion about signal routing configuration, albeit less,
+plagued NI's previous version of their own proprietary drivers. Earlier than
+2003, NI greatly simplified the situation for users by releasing a new API that
+abstracted the names of signals/terminals to a common and intuitive set of
+names. In addition, this new API provided a much more common interface to use
+for most of NI hardware.
+
+Comedi already provides such a common interface for data-acquisition and control
+hardware. This effort complements comedi's abstraction layers by further
+abstracting much more of the use cases for NI hardware, but allowing users _and_
+developers to directly refer to NI documentation (user-level, register-level,
+and the register-level examples of the NI-MHDDK).
+
+
+
+--------------------------------------------------------------------------------
+Various naming conventions and relations:
+--------------------------------------------------------------------------------
+These are various notes that help to relate the naming conventions used in the
+NI-STC with those naming conventions used here.
+--------------------------------------------------------------------------------
+
+ Signal sources for most signals-destinations are given a specific naming
+ convention, although the register values are not consistent. This next table
+ shows the mapping between the names used in comedi for NI and those names
+ typically used within the NI-STC documentation.
+
+ (comedi) (NI-STC input or output) (NOTE)
+ ------------------------------------------------------------------------------
+ TRIGGER_LINE(i) RTSI_Trig_i_Output_Select i in range [0..7]
+ NI_AI_STOP AI_STOP
+ NI_AI_SampleClock AI_START_Select
+ NI_AI_SampleClockTimebase AI_SI If internal sample
+ clock signal is used
+ NI_AI_StartTrigger AI_START1_Select
+ NI_AI_ReferenceTrigger AI_START2_Select for pre-triggered
+ acquisition---not
+ currently supported
+ in comedi
+ NI_AI_ConvertClock AI_CONVERT_Source_Select
+ NI_AI_ConvertClockTimebase AI_SI2 If internal convert
+ signal is used
+ NI_AI_HoldCompleteEvent
+ NI_AI_PauseTrigger AI_External_Gate
+ NI_AO_SampleClock AO_UPDATE
+ NI_AO_SampleClockTimebase AO_UI
+ NI_AO_StartTrigger AO_START1
+ NI_AO_PauseTrigger AO_External_Gate
+ NI_DI_SampleClock
+ NI_DO_SampleClock
+ NI_MasterTimebase
+ NI_20MHzTimebase TIMEBASE 1 && TIMEBASE 3 if no higher clock exists
+ NI_80MHzTimebase TIMEBASE 3
+ NI_100kHzTimebase TIMEBASE 2
+ NI_10MHzRefClock
+ PXI_Clk10
+ NI_CtrOut(0) GPFO_0 external ctr0out pin
+ NI_CtrOut(1) GPFO_1 external ctr1out pin
+ NI_CtrSource(0)
+ NI_CtrSource(1)
+ NI_CtrGate(0)
+ NI_CtrGate(1)
+ NI_CtrInternalOutput(0) G_OUT0, G0_TC for Ctr1Source, Ctr1Gate
+ NI_CtrInternalOutput(1) G_OUT1, G1_TC for Ctr0Source, Ctr0Gate
+ NI_RGOUT0 RGOUT0 internal signal
+ NI_FrequencyOutput
+ #NI_FrequencyOutputTimebase
+ NI_ChangeDetectionEvent
+ NI_RTSI_BRD(0)
+ NI_RTSI_BRD(1)
+ NI_RTSI_BRD(2)
+ NI_RTSI_BRD(3)
+ #NI_SoftwareStrobe
+ NI_LogicLow
+ NI_CtrA(0) G0_A_Select see M-Series user
+ manual (371022K-01)
+ NI_CtrA(1) G1_A_Select see M-Series user
+ manual (371022K-01)
+ NI_CtrB(0) G0_B_Select, up/down see M-Series user
+ manual (371022K-01)
+ NI_CtrB(1) G1_B_Select, up/down see M-Series user
+ manual (371022K-01)
+ NI_CtrZ(0) see M-Series user
+ manual (371022K-01)
+ NI_CtrZ(1) see M-Series user
+ manual (371022K-01)
diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes.c b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes.c
new file mode 100644
index 000000000000..7b6a74dfe48b
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes.c
@@ -0,0 +1,51 @@
+// 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * The contents of this file are generated using the tools in
+ * comedi/drivers/ni_routing/tools
+ *
+ * Please use those tools to help maintain the contents of this file.
+ */
+
+#include "ni_device_routes.h"
+#include "ni_device_routes/all.h"
+
+struct ni_device_routes *const ni_device_routes_list[] = {
+ &ni_pxi_6030e_device_routes,
+ &ni_pci_6070e_device_routes,
+ &ni_pci_6220_device_routes,
+ &ni_pci_6221_device_routes,
+ &ni_pxi_6224_device_routes,
+ &ni_pxi_6225_device_routes,
+ &ni_pci_6229_device_routes,
+ &ni_pci_6251_device_routes,
+ &ni_pxi_6251_device_routes,
+ &ni_pxie_6251_device_routes,
+ &ni_pci_6254_device_routes,
+ &ni_pci_6259_device_routes,
+ &ni_pci_6534_device_routes,
+ &ni_pci_6602_device_routes,
+ &ni_pci_6713_device_routes,
+ &ni_pci_6723_device_routes,
+ &ni_pci_6733_device_routes,
+ &ni_pxi_6733_device_routes,
+ NULL,
+};
diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes.h b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes.h
new file mode 100644
index 000000000000..b9f1c47d19e1
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes.h
@@ -0,0 +1,32 @@
+/* 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * This file is meant to be included by comedi/drivers/ni_routes.c
+ */
+
+#ifndef _COMEDI_DRIVERS_NI_ROUTINT_NI_DEVICE_ROUTES_H
+#define _COMEDI_DRIVERS_NI_ROUTINT_NI_DEVICE_ROUTES_H
+
+#include "../ni_routes.h"
+
+extern struct ni_device_routes *const ni_device_routes_list[];
+
+#endif /* _COMEDI_DRIVERS_NI_ROUTINT_NI_DEVICE_ROUTES_H */
diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/all.h b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/all.h
new file mode 100644
index 000000000000..78b24138acb7
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/all.h
@@ -0,0 +1,54 @@
+/* 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * The contents of this file are generated using the tools in
+ * comedi/drivers/ni_routing/tools
+ *
+ * Please use those tools to help maintain the contents of this file.
+ */
+
+#ifndef _COMEDI_DRIVERS_NI_ROUTING_NI_DEVICE_ROUTES_EXTERN_H
+#define _COMEDI_DRIVERS_NI_ROUTING_NI_DEVICE_ROUTES_EXTERN_H
+
+#include "../ni_device_routes.h"
+
+extern struct ni_device_routes ni_pxi_6030e_device_routes;
+extern struct ni_device_routes ni_pci_6070e_device_routes;
+extern struct ni_device_routes ni_pci_6220_device_routes;
+extern struct ni_device_routes ni_pci_6221_device_routes;
+extern struct ni_device_routes ni_pxi_6224_device_routes;
+extern struct ni_device_routes ni_pxi_6225_device_routes;
+extern struct ni_device_routes ni_pci_6229_device_routes;
+extern struct ni_device_routes ni_pci_6251_device_routes;
+extern struct ni_device_routes ni_pxi_6251_device_routes;
+extern struct ni_device_routes ni_pxie_6251_device_routes;
+extern struct ni_device_routes ni_pci_6254_device_routes;
+extern struct ni_device_routes ni_pci_6259_device_routes;
+extern struct ni_device_routes ni_pci_6534_device_routes;
+extern struct ni_device_routes ni_pxie_6535_device_routes;
+extern struct ni_device_routes ni_pci_6602_device_routes;
+extern struct ni_device_routes ni_pci_6713_device_routes;
+extern struct ni_device_routes ni_pci_6723_device_routes;
+extern struct ni_device_routes ni_pci_6733_device_routes;
+extern struct ni_device_routes ni_pxi_6733_device_routes;
+extern struct ni_device_routes ni_pxie_6738_device_routes;
+
+#endif //_COMEDI_DRIVERS_NI_ROUTING_NI_DEVICE_ROUTES_EXTERN_H
diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6070e.c b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6070e.c
new file mode 100644
index 000000000000..f1126a0cb285
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6070e.c
@@ -0,0 +1,639 @@
+// 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * The contents of this file are generated using the tools in
+ * comedi/drivers/ni_routing/tools
+ *
+ * Please use those tools to help maintain the contents of this file.
+ */
+
+#include "../ni_device_routes.h"
+#include "all.h"
+
+struct ni_device_routes ni_pci_6070e_device_routes = {
+ .device = "pci-6070e",
+ .routes = (struct ni_route_set[]){
+ {
+ .dest = NI_PFI(0),
+ .src = (int[]){
+ NI_AI_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(1),
+ .src = (int[]){
+ NI_AI_ReferenceTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(2),
+ .src = (int[]){
+ NI_AI_ConvertClock,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(3),
+ .src = (int[]){
+ NI_CtrSource(1),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(4),
+ .src = (int[]){
+ NI_CtrGate(1),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(5),
+ .src = (int[]){
+ NI_AO_SampleClock,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(6),
+ .src = (int[]){
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(7),
+ .src = (int[]){
+ NI_AI_SampleClock,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(8),
+ .src = (int[]){
+ NI_CtrSource(0),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(9),
+ .src = (int[]){
+ NI_CtrGate(0),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(0),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(1),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(2),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(3),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(4),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(5),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(6),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(7),
+ .src = (int[]){
+ NI_20MHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_MasterTimebase,
+ NI_20MHzTimebase,
+ NI_100kHzTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_MasterTimebase,
+ NI_20MHzTimebase,
+ NI_100kHzTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ NI_CtrInternalOutput(1),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ NI_CtrInternalOutput(0),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrOut(0),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ NI_CtrInternalOutput(0),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrOut(1),
+ .src = (int[]){
+ NI_CtrInternalOutput(1),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ NI_CtrInternalOutput(0),
+ NI_AI_SampleClockTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_SampleClockTimebase,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_MasterTimebase,
+ NI_20MHzTimebase,
+ NI_100kHzTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_StartTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ NI_CtrInternalOutput(0),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_ReferenceTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_ConvertClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ NI_CtrInternalOutput(0),
+ NI_AI_ConvertClockTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_ConvertClockTimebase,
+ .src = (int[]){
+ TRIGGER_LINE(7),
+ NI_AI_SampleClockTimebase,
+ NI_MasterTimebase,
+ NI_20MHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_PauseTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_HoldComplete,
+ .src = (int[]){
+ NI_AI_HoldCompleteEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ NI_CtrInternalOutput(1),
+ NI_AO_SampleClockTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_SampleClockTimebase,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_MasterTimebase,
+ NI_20MHzTimebase,
+ NI_100kHzTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_StartTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ NI_AI_StartTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_PauseTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_MasterTimebase,
+ .src = (int[]){
+ TRIGGER_LINE(7),
+ NI_20MHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ { /* Termination of list */
+ .dest = 0,
+ },
+ },
+};
diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6220.c b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6220.c
new file mode 100644
index 000000000000..74a59222963f
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6220.c
@@ -0,0 +1,1418 @@
+// 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * The contents of this file are generated using the tools in
+ * comedi/drivers/ni_routing/tools
+ *
+ * Please use those tools to help maintain the contents of this file.
+ */
+
+#include "../ni_device_routes.h"
+#include "all.h"
+
+struct ni_device_routes ni_pci_6220_device_routes = {
+ .device = "pci-6220",
+ .routes = (struct ni_route_set[]){
+ {
+ .dest = NI_PFI(0),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(1),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(2),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(3),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(4),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(5),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(6),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(7),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(8),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(9),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(10),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(11),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(12),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(13),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(14),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(15),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(2),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(3),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(4),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(5),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(6),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(7),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrGate(1),
+ NI_20MHzTimebase,
+ NI_80MHzTimebase,
+ NI_100kHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrGate(0),
+ NI_20MHzTimebase,
+ NI_80MHzTimebase,
+ NI_100kHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(1),
+ NI_CtrInternalOutput(1),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrInternalOutput(0),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrAux(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(1),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrAux(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrA(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrA(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrB(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrB(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrZ(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrZ(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrArmStartTrigger(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(1),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrArmStartTrigger(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClockTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_SampleClockTimebase,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_20MHzTimebase,
+ NI_100kHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_StartTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_ReferenceTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_ConvertClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_ConvertClockTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_ConvertClockTimebase,
+ .src = (int[]){
+ NI_AI_SampleClockTimebase,
+ NI_20MHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_PauseTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DI_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_ConvertClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DO_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_ConvertClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ { /* Termination of list */
+ .dest = 0,
+ },
+ },
+};
diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6221.c b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6221.c
new file mode 100644
index 000000000000..44dcbabf2a99
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6221.c
@@ -0,0 +1,1602 @@
+// 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * The contents of this file are generated using the tools in
+ * comedi/drivers/ni_routing/tools
+ *
+ * Please use those tools to help maintain the contents of this file.
+ */
+
+#include "../ni_device_routes.h"
+#include "all.h"
+
+struct ni_device_routes ni_pci_6221_device_routes = {
+ .device = "pci-6221",
+ .routes = (struct ni_route_set[]){
+ {
+ .dest = NI_PFI(0),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(1),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(2),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(3),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(4),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(5),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(6),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(7),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(8),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(9),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(10),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(11),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(12),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(13),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(14),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(15),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(2),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(3),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(4),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(5),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(6),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(7),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrGate(1),
+ NI_20MHzTimebase,
+ NI_80MHzTimebase,
+ NI_100kHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrGate(0),
+ NI_20MHzTimebase,
+ NI_80MHzTimebase,
+ NI_100kHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(1),
+ NI_CtrInternalOutput(1),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrInternalOutput(0),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrAux(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(1),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrAux(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrA(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrA(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrB(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrB(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrZ(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrZ(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrArmStartTrigger(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(1),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrArmStartTrigger(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClockTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_SampleClockTimebase,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_20MHzTimebase,
+ NI_100kHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_StartTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_ReferenceTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_ConvertClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_ConvertClockTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_ConvertClockTimebase,
+ .src = (int[]){
+ NI_AI_SampleClockTimebase,
+ NI_20MHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_PauseTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AO_SampleClockTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_SampleClockTimebase,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_20MHzTimebase,
+ NI_100kHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_StartTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AI_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_PauseTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DI_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DO_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ { /* Termination of list */
+ .dest = 0,
+ },
+ },
+};
diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6229.c b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6229.c
new file mode 100644
index 000000000000..fa5794e4e2b3
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6229.c
@@ -0,0 +1,1602 @@
+// 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * The contents of this file are generated using the tools in
+ * comedi/drivers/ni_routing/tools
+ *
+ * Please use those tools to help maintain the contents of this file.
+ */
+
+#include "../ni_device_routes.h"
+#include "all.h"
+
+struct ni_device_routes ni_pci_6229_device_routes = {
+ .device = "pci-6229",
+ .routes = (struct ni_route_set[]){
+ {
+ .dest = NI_PFI(0),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(1),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(2),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(3),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(4),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(5),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(6),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(7),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(8),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(9),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(10),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(11),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(12),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(13),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(14),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(15),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(2),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(3),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(4),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(5),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(6),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(7),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrGate(1),
+ NI_20MHzTimebase,
+ NI_80MHzTimebase,
+ NI_100kHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrGate(0),
+ NI_20MHzTimebase,
+ NI_80MHzTimebase,
+ NI_100kHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(1),
+ NI_CtrInternalOutput(1),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrInternalOutput(0),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrAux(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(1),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrAux(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrA(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrA(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrB(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrB(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrZ(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrZ(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrArmStartTrigger(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(1),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrArmStartTrigger(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClockTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_SampleClockTimebase,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_20MHzTimebase,
+ NI_100kHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_StartTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_ReferenceTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_ConvertClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_ConvertClockTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_ConvertClockTimebase,
+ .src = (int[]){
+ NI_AI_SampleClockTimebase,
+ NI_20MHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_PauseTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AO_SampleClockTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_SampleClockTimebase,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_20MHzTimebase,
+ NI_100kHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_StartTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AI_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_PauseTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DI_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DO_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ { /* Termination of list */
+ .dest = 0,
+ },
+ },
+};
diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6251.c b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6251.c
new file mode 100644
index 000000000000..645fd1cd2de4
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6251.c
@@ -0,0 +1,1652 @@
+// 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * The contents of this file are generated using the tools in
+ * comedi/drivers/ni_routing/tools
+ *
+ * Please use those tools to help maintain the contents of this file.
+ */
+
+#include "../ni_device_routes.h"
+#include "all.h"
+
+struct ni_device_routes ni_pci_6251_device_routes = {
+ .device = "pci-6251",
+ .routes = (struct ni_route_set[]){
+ {
+ .dest = NI_PFI(0),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(1),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(2),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(3),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(4),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(5),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(6),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(7),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(8),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(9),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(10),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(11),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(12),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(13),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(14),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(15),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(2),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(3),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(4),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(5),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(6),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(7),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrGate(1),
+ NI_20MHzTimebase,
+ NI_80MHzTimebase,
+ NI_100kHzTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrGate(0),
+ NI_20MHzTimebase,
+ NI_80MHzTimebase,
+ NI_100kHzTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(1),
+ NI_CtrInternalOutput(1),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrInternalOutput(0),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrAux(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(1),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrAux(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrA(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrA(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrB(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrB(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrZ(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrZ(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrArmStartTrigger(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(1),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrArmStartTrigger(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClockTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_SampleClockTimebase,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_20MHzTimebase,
+ NI_100kHzTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_StartTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_ReferenceTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_ConvertClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_ConvertClockTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_ConvertClockTimebase,
+ .src = (int[]){
+ NI_AI_SampleClockTimebase,
+ NI_20MHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_PauseTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AO_SampleClockTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_SampleClockTimebase,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_20MHzTimebase,
+ NI_100kHzTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_StartTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AI_StartTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_PauseTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DI_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DO_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ { /* Termination of list */
+ .dest = 0,
+ },
+ },
+};
diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6254.c b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6254.c
new file mode 100644
index 000000000000..056a240cd3a2
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6254.c
@@ -0,0 +1,1464 @@
+// 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * The contents of this file are generated using the tools in
+ * comedi/drivers/ni_routing/tools
+ *
+ * Please use those tools to help maintain the contents of this file.
+ */
+
+#include "../ni_device_routes.h"
+#include "all.h"
+
+struct ni_device_routes ni_pci_6254_device_routes = {
+ .device = "pci-6254",
+ .routes = (struct ni_route_set[]){
+ {
+ .dest = NI_PFI(0),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(1),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(2),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(3),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(4),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(5),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(6),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(7),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(8),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(9),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(10),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(11),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(12),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(13),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(14),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(15),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(2),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(3),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(4),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(5),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(6),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(7),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrGate(1),
+ NI_20MHzTimebase,
+ NI_80MHzTimebase,
+ NI_100kHzTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrGate(0),
+ NI_20MHzTimebase,
+ NI_80MHzTimebase,
+ NI_100kHzTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(1),
+ NI_CtrInternalOutput(1),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrInternalOutput(0),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrAux(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(1),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrAux(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrA(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrA(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrB(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrB(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrZ(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrZ(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrArmStartTrigger(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(1),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrArmStartTrigger(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClockTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_SampleClockTimebase,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_20MHzTimebase,
+ NI_100kHzTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_StartTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_ReferenceTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_ConvertClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_ConvertClockTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_ConvertClockTimebase,
+ .src = (int[]){
+ NI_AI_SampleClockTimebase,
+ NI_20MHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_PauseTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DI_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_ConvertClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DO_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_ConvertClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ { /* Termination of list */
+ .dest = 0,
+ },
+ },
+};
diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6259.c b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6259.c
new file mode 100644
index 000000000000..e0b5fa78c3bc
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6259.c
@@ -0,0 +1,1652 @@
+// 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * The contents of this file are generated using the tools in
+ * comedi/drivers/ni_routing/tools
+ *
+ * Please use those tools to help maintain the contents of this file.
+ */
+
+#include "../ni_device_routes.h"
+#include "all.h"
+
+struct ni_device_routes ni_pci_6259_device_routes = {
+ .device = "pci-6259",
+ .routes = (struct ni_route_set[]){
+ {
+ .dest = NI_PFI(0),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(1),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(2),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(3),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(4),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(5),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(6),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(7),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(8),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(9),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(10),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(11),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(12),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(13),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(14),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(15),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(2),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(3),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(4),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(5),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(6),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(7),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrGate(1),
+ NI_20MHzTimebase,
+ NI_80MHzTimebase,
+ NI_100kHzTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrGate(0),
+ NI_20MHzTimebase,
+ NI_80MHzTimebase,
+ NI_100kHzTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(1),
+ NI_CtrInternalOutput(1),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrInternalOutput(0),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrAux(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(1),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrAux(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrA(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrA(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrB(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrB(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrZ(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrZ(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrArmStartTrigger(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(1),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrArmStartTrigger(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClockTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_SampleClockTimebase,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_20MHzTimebase,
+ NI_100kHzTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_StartTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_ReferenceTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_ConvertClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_ConvertClockTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_ConvertClockTimebase,
+ .src = (int[]){
+ NI_AI_SampleClockTimebase,
+ NI_20MHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_PauseTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AO_SampleClockTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_SampleClockTimebase,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_20MHzTimebase,
+ NI_100kHzTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_StartTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AI_StartTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_PauseTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DI_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DO_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ { /* Termination of list */
+ .dest = 0,
+ },
+ },
+};
diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6534.c b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6534.c
new file mode 100644
index 000000000000..a2472ed288cf
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6534.c
@@ -0,0 +1,290 @@
+// 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * The contents of this file are generated using the tools in
+ * comedi/drivers/ni_routing/tools
+ *
+ * Please use those tools to help maintain the contents of this file.
+ */
+
+#include "../ni_device_routes.h"
+#include "all.h"
+
+struct ni_device_routes ni_pci_6534_device_routes = {
+ .device = "pci-6534",
+ .routes = (struct ni_route_set[]){
+ {
+ .dest = NI_PFI(0),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(1),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(2),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(3),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(4),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(5),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(6),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(7),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(2),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(3),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(4),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(5),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(6),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(6),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(7),
+ .src = (int[]){
+ NI_20MHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_MasterTimebase,
+ .src = (int[]){
+ TRIGGER_LINE(7),
+ NI_20MHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ { /* Termination of list */
+ .dest = 0,
+ },
+ },
+};
diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6602.c b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6602.c
new file mode 100644
index 000000000000..91de9dac2d6a
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6602.c
@@ -0,0 +1,3378 @@
+// 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * The contents of this file are generated using the tools in
+ * comedi/drivers/ni_routing/tools
+ *
+ * Please use those tools to help maintain the contents of this file.
+ */
+
+#include "../ni_device_routes.h"
+#include "all.h"
+
+struct ni_device_routes ni_pci_6602_device_routes = {
+ .device = "pci-6602",
+ .routes = (struct ni_route_set[]){
+ {
+ .dest = NI_PFI(2),
+ .src = (int[]){
+ NI_80MHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(3),
+ .src = (int[]){
+ NI_100kHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(4),
+ .src = (int[]){
+ NI_20MHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(6),
+ .src = (int[]){
+ NI_80MHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(7),
+ .src = (int[]){
+ TRIGGER_LINE(7),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(8),
+ .src = (int[]){
+ NI_PFI(7),
+ NI_PFI(15),
+ NI_PFI(23),
+ NI_PFI(31),
+ NI_PFI(39),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrInternalOutput(4),
+ NI_CtrInternalOutput(5),
+ NI_CtrInternalOutput(6),
+ NI_CtrInternalOutput(7),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(9),
+ .src = (int[]){
+ NI_PFI(7),
+ NI_PFI(15),
+ NI_PFI(23),
+ NI_PFI(31),
+ NI_PFI(39),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrInternalOutput(4),
+ NI_CtrInternalOutput(5),
+ NI_CtrInternalOutput(6),
+ NI_CtrInternalOutput(7),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(10),
+ .src = (int[]){
+ NI_CtrGate(7),
+ NI_LogicLow,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(11),
+ .src = (int[]){
+ NI_CtrSource(7),
+ NI_LogicLow,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(12),
+ .src = (int[]){
+ NI_PFI(6),
+ NI_PFI(14),
+ NI_PFI(22),
+ NI_PFI(30),
+ NI_PFI(38),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrInternalOutput(4),
+ NI_CtrInternalOutput(5),
+ NI_CtrInternalOutput(6),
+ NI_CtrInternalOutput(7),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(13),
+ .src = (int[]){
+ NI_PFI(6),
+ NI_PFI(14),
+ NI_PFI(22),
+ NI_PFI(30),
+ NI_PFI(38),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrInternalOutput(4),
+ NI_CtrInternalOutput(5),
+ NI_CtrInternalOutput(6),
+ NI_CtrInternalOutput(7),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(14),
+ .src = (int[]){
+ NI_CtrGate(6),
+ NI_LogicLow,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(15),
+ .src = (int[]){
+ NI_CtrSource(6),
+ NI_LogicLow,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(16),
+ .src = (int[]){
+ NI_PFI(5),
+ NI_PFI(13),
+ NI_PFI(21),
+ NI_PFI(29),
+ NI_PFI(37),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrInternalOutput(4),
+ NI_CtrInternalOutput(5),
+ NI_CtrInternalOutput(6),
+ NI_CtrInternalOutput(7),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(17),
+ .src = (int[]){
+ NI_PFI(5),
+ NI_PFI(13),
+ NI_PFI(21),
+ NI_PFI(29),
+ NI_PFI(37),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrInternalOutput(4),
+ NI_CtrInternalOutput(5),
+ NI_CtrInternalOutput(6),
+ NI_CtrInternalOutput(7),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(18),
+ .src = (int[]){
+ NI_CtrGate(5),
+ NI_LogicLow,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(19),
+ .src = (int[]){
+ NI_CtrSource(5),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(20),
+ .src = (int[]){
+ NI_PFI(4),
+ NI_PFI(12),
+ NI_PFI(28),
+ NI_PFI(36),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrInternalOutput(4),
+ NI_CtrInternalOutput(5),
+ NI_CtrInternalOutput(6),
+ NI_CtrInternalOutput(7),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(21),
+ .src = (int[]){
+ NI_PFI(4),
+ NI_PFI(12),
+ NI_PFI(20),
+ NI_PFI(28),
+ NI_PFI(36),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrInternalOutput(4),
+ NI_CtrInternalOutput(5),
+ NI_CtrInternalOutput(6),
+ NI_CtrInternalOutput(7),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(22),
+ .src = (int[]){
+ NI_CtrGate(4),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(23),
+ .src = (int[]){
+ NI_CtrSource(4),
+ NI_LogicLow,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(24),
+ .src = (int[]){
+ NI_PFI(3),
+ NI_PFI(11),
+ NI_PFI(19),
+ NI_PFI(27),
+ NI_PFI(35),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(3),
+ NI_CtrSource(7),
+ NI_CtrGate(3),
+ NI_CtrGate(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrInternalOutput(4),
+ NI_CtrInternalOutput(5),
+ NI_CtrInternalOutput(6),
+ NI_CtrInternalOutput(7),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(25),
+ .src = (int[]){
+ NI_PFI(3),
+ NI_PFI(11),
+ NI_PFI(19),
+ NI_PFI(27),
+ NI_PFI(35),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(3),
+ NI_CtrSource(7),
+ NI_CtrGate(3),
+ NI_CtrGate(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrInternalOutput(4),
+ NI_CtrInternalOutput(5),
+ NI_CtrInternalOutput(6),
+ NI_CtrInternalOutput(7),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(26),
+ .src = (int[]){
+ NI_CtrGate(3),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(27),
+ .src = (int[]){
+ NI_CtrSource(3),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(28),
+ .src = (int[]){
+ NI_PFI(2),
+ NI_PFI(10),
+ NI_PFI(18),
+ NI_PFI(26),
+ NI_PFI(34),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(2),
+ NI_CtrSource(6),
+ NI_CtrGate(2),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrInternalOutput(4),
+ NI_CtrInternalOutput(5),
+ NI_CtrInternalOutput(6),
+ NI_CtrInternalOutput(7),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(29),
+ .src = (int[]){
+ NI_PFI(2),
+ NI_PFI(10),
+ NI_PFI(18),
+ NI_PFI(26),
+ NI_PFI(34),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(2),
+ NI_CtrSource(6),
+ NI_CtrGate(2),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrInternalOutput(4),
+ NI_CtrInternalOutput(5),
+ NI_CtrInternalOutput(6),
+ NI_CtrInternalOutput(7),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(30),
+ .src = (int[]){
+ NI_CtrGate(2),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(31),
+ .src = (int[]){
+ NI_CtrSource(2),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(32),
+ .src = (int[]){
+ NI_PFI(1),
+ NI_PFI(9),
+ NI_PFI(17),
+ NI_PFI(25),
+ NI_PFI(33),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(1),
+ NI_CtrSource(5),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrInternalOutput(4),
+ NI_CtrInternalOutput(5),
+ NI_CtrInternalOutput(6),
+ NI_CtrInternalOutput(7),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(33),
+ .src = (int[]){
+ NI_PFI(1),
+ NI_PFI(9),
+ NI_PFI(17),
+ NI_PFI(25),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(1),
+ NI_CtrSource(5),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrInternalOutput(4),
+ NI_CtrInternalOutput(5),
+ NI_CtrInternalOutput(6),
+ NI_CtrInternalOutput(7),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(34),
+ .src = (int[]){
+ NI_CtrGate(1),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(35),
+ .src = (int[]){
+ NI_CtrSource(1),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(36),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(5),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrInternalOutput(4),
+ NI_CtrInternalOutput(5),
+ NI_CtrInternalOutput(6),
+ NI_CtrInternalOutput(7),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(37),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(38),
+ NI_PFI(39),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(5),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrInternalOutput(4),
+ NI_CtrInternalOutput(5),
+ NI_CtrInternalOutput(6),
+ NI_CtrInternalOutput(7),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(38),
+ .src = (int[]){
+ NI_CtrGate(0),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(39),
+ .src = (int[]){
+ NI_CtrSource(0),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrSource(4),
+ NI_CtrSource(5),
+ NI_CtrSource(6),
+ NI_CtrSource(7),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrGate(4),
+ NI_CtrGate(5),
+ NI_CtrGate(6),
+ NI_CtrGate(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrInternalOutput(4),
+ NI_CtrInternalOutput(5),
+ NI_CtrInternalOutput(6),
+ NI_CtrInternalOutput(7),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrSource(4),
+ NI_CtrSource(5),
+ NI_CtrSource(6),
+ NI_CtrSource(7),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrGate(4),
+ NI_CtrGate(5),
+ NI_CtrGate(6),
+ NI_CtrGate(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrInternalOutput(4),
+ NI_CtrInternalOutput(5),
+ NI_CtrInternalOutput(6),
+ NI_CtrInternalOutput(7),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(2),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrSource(4),
+ NI_CtrSource(5),
+ NI_CtrSource(6),
+ NI_CtrSource(7),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrGate(4),
+ NI_CtrGate(5),
+ NI_CtrGate(6),
+ NI_CtrGate(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrInternalOutput(4),
+ NI_CtrInternalOutput(5),
+ NI_CtrInternalOutput(6),
+ NI_CtrInternalOutput(7),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(3),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrSource(4),
+ NI_CtrSource(5),
+ NI_CtrSource(6),
+ NI_CtrSource(7),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrGate(4),
+ NI_CtrGate(5),
+ NI_CtrGate(6),
+ NI_CtrGate(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrInternalOutput(4),
+ NI_CtrInternalOutput(5),
+ NI_CtrInternalOutput(6),
+ NI_CtrInternalOutput(7),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(4),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrSource(4),
+ NI_CtrSource(5),
+ NI_CtrSource(6),
+ NI_CtrSource(7),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrGate(4),
+ NI_CtrGate(5),
+ NI_CtrGate(6),
+ NI_CtrGate(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrInternalOutput(4),
+ NI_CtrInternalOutput(5),
+ NI_CtrInternalOutput(6),
+ NI_CtrInternalOutput(7),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(5),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrSource(4),
+ NI_CtrSource(5),
+ NI_CtrSource(6),
+ NI_CtrSource(7),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrGate(4),
+ NI_CtrGate(5),
+ NI_CtrGate(6),
+ NI_CtrGate(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrInternalOutput(4),
+ NI_CtrInternalOutput(5),
+ NI_CtrInternalOutput(6),
+ NI_CtrInternalOutput(7),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(6),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrSource(4),
+ NI_CtrSource(5),
+ NI_CtrSource(6),
+ NI_CtrSource(7),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrGate(4),
+ NI_CtrGate(5),
+ NI_CtrGate(6),
+ NI_CtrGate(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrInternalOutput(4),
+ NI_CtrInternalOutput(5),
+ NI_CtrInternalOutput(6),
+ NI_CtrInternalOutput(7),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(7),
+ .src = (int[]){
+ NI_20MHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_20MHzTimebase,
+ NI_80MHzTimebase,
+ NI_100kHzTimebase,
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_20MHzTimebase,
+ NI_80MHzTimebase,
+ NI_100kHzTimebase,
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(2),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(3),
+ NI_20MHzTimebase,
+ NI_80MHzTimebase,
+ NI_100kHzTimebase,
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(3),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_20MHzTimebase,
+ NI_80MHzTimebase,
+ NI_100kHzTimebase,
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(4),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(5),
+ NI_CtrSource(6),
+ NI_CtrSource(7),
+ NI_CtrGate(5),
+ NI_CtrGate(6),
+ NI_CtrGate(7),
+ NI_CtrInternalOutput(5),
+ NI_CtrInternalOutput(6),
+ NI_CtrInternalOutput(7),
+ NI_20MHzTimebase,
+ NI_80MHzTimebase,
+ NI_100kHzTimebase,
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(5),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(4),
+ NI_CtrSource(6),
+ NI_CtrSource(7),
+ NI_CtrGate(4),
+ NI_CtrGate(6),
+ NI_CtrGate(7),
+ NI_CtrInternalOutput(4),
+ NI_CtrInternalOutput(6),
+ NI_CtrInternalOutput(7),
+ NI_20MHzTimebase,
+ NI_80MHzTimebase,
+ NI_100kHzTimebase,
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(6),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(4),
+ NI_CtrSource(5),
+ NI_CtrSource(7),
+ NI_CtrGate(4),
+ NI_CtrGate(5),
+ NI_CtrGate(7),
+ NI_CtrInternalOutput(4),
+ NI_CtrInternalOutput(5),
+ NI_CtrInternalOutput(7),
+ NI_20MHzTimebase,
+ NI_80MHzTimebase,
+ NI_100kHzTimebase,
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(7),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(4),
+ NI_CtrSource(5),
+ NI_CtrSource(6),
+ NI_CtrGate(4),
+ NI_CtrGate(5),
+ NI_CtrGate(6),
+ NI_CtrInternalOutput(4),
+ NI_CtrInternalOutput(5),
+ NI_CtrInternalOutput(6),
+ NI_20MHzTimebase,
+ NI_80MHzTimebase,
+ NI_100kHzTimebase,
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(2),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(3),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(3),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(4),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(5),
+ NI_CtrSource(6),
+ NI_CtrSource(7),
+ NI_CtrGate(5),
+ NI_CtrGate(6),
+ NI_CtrGate(7),
+ NI_CtrInternalOutput(5),
+ NI_CtrInternalOutput(6),
+ NI_CtrInternalOutput(7),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(5),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(4),
+ NI_CtrSource(6),
+ NI_CtrSource(7),
+ NI_CtrGate(4),
+ NI_CtrGate(6),
+ NI_CtrGate(7),
+ NI_CtrInternalOutput(4),
+ NI_CtrInternalOutput(6),
+ NI_CtrInternalOutput(7),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(6),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(4),
+ NI_CtrSource(5),
+ NI_CtrSource(7),
+ NI_CtrGate(4),
+ NI_CtrGate(5),
+ NI_CtrGate(7),
+ NI_CtrInternalOutput(4),
+ NI_CtrInternalOutput(5),
+ NI_CtrInternalOutput(7),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(7),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(4),
+ NI_CtrSource(5),
+ NI_CtrSource(6),
+ NI_CtrGate(4),
+ NI_CtrGate(5),
+ NI_CtrGate(6),
+ NI_CtrInternalOutput(4),
+ NI_CtrInternalOutput(5),
+ NI_CtrInternalOutput(6),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrAux(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrAux(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrAux(2),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(3),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrAux(3),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrAux(4),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(5),
+ NI_CtrSource(6),
+ NI_CtrSource(7),
+ NI_CtrGate(4),
+ NI_CtrGate(5),
+ NI_CtrGate(6),
+ NI_CtrGate(7),
+ NI_CtrInternalOutput(5),
+ NI_CtrInternalOutput(6),
+ NI_CtrInternalOutput(7),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrAux(5),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(4),
+ NI_CtrSource(6),
+ NI_CtrSource(7),
+ NI_CtrGate(4),
+ NI_CtrGate(5),
+ NI_CtrGate(6),
+ NI_CtrGate(7),
+ NI_CtrInternalOutput(4),
+ NI_CtrInternalOutput(6),
+ NI_CtrInternalOutput(7),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrAux(6),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(4),
+ NI_CtrSource(5),
+ NI_CtrSource(7),
+ NI_CtrGate(4),
+ NI_CtrGate(5),
+ NI_CtrGate(6),
+ NI_CtrGate(7),
+ NI_CtrInternalOutput(4),
+ NI_CtrInternalOutput(5),
+ NI_CtrInternalOutput(7),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrAux(7),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(4),
+ NI_CtrSource(5),
+ NI_CtrSource(6),
+ NI_CtrGate(4),
+ NI_CtrGate(5),
+ NI_CtrGate(6),
+ NI_CtrGate(7),
+ NI_CtrInternalOutput(4),
+ NI_CtrInternalOutput(5),
+ NI_CtrInternalOutput(6),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrArmStartTrigger(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrArmStartTrigger(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrArmStartTrigger(2),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(3),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrArmStartTrigger(3),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrArmStartTrigger(4),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(5),
+ NI_CtrSource(6),
+ NI_CtrSource(7),
+ NI_CtrGate(5),
+ NI_CtrGate(6),
+ NI_CtrGate(7),
+ NI_CtrInternalOutput(5),
+ NI_CtrInternalOutput(6),
+ NI_CtrInternalOutput(7),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrArmStartTrigger(5),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(4),
+ NI_CtrSource(6),
+ NI_CtrSource(7),
+ NI_CtrGate(4),
+ NI_CtrGate(6),
+ NI_CtrGate(7),
+ NI_CtrInternalOutput(4),
+ NI_CtrInternalOutput(6),
+ NI_CtrInternalOutput(7),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrArmStartTrigger(6),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(4),
+ NI_CtrSource(5),
+ NI_CtrSource(7),
+ NI_CtrGate(4),
+ NI_CtrGate(5),
+ NI_CtrGate(7),
+ NI_CtrInternalOutput(4),
+ NI_CtrInternalOutput(5),
+ NI_CtrInternalOutput(7),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrArmStartTrigger(7),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ NI_PFI(16),
+ NI_PFI(17),
+ NI_PFI(18),
+ NI_PFI(19),
+ NI_PFI(20),
+ NI_PFI(21),
+ NI_PFI(22),
+ NI_PFI(23),
+ NI_PFI(24),
+ NI_PFI(25),
+ NI_PFI(26),
+ NI_PFI(27),
+ NI_PFI(28),
+ NI_PFI(29),
+ NI_PFI(30),
+ NI_PFI(31),
+ NI_PFI(32),
+ NI_PFI(33),
+ NI_PFI(34),
+ NI_PFI(35),
+ NI_PFI(36),
+ NI_PFI(37),
+ NI_PFI(38),
+ NI_PFI(39),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(4),
+ NI_CtrSource(5),
+ NI_CtrSource(6),
+ NI_CtrGate(4),
+ NI_CtrGate(5),
+ NI_CtrGate(6),
+ NI_CtrInternalOutput(4),
+ NI_CtrInternalOutput(5),
+ NI_CtrInternalOutput(6),
+ NI_LogicLow,
+ NI_LogicHigh,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_MasterTimebase,
+ .src = (int[]){
+ TRIGGER_LINE(7),
+ NI_20MHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ { /* Termination of list */
+ .dest = 0,
+ },
+ },
+};
diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6713.c b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6713.c
new file mode 100644
index 000000000000..d378b36d2084
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6713.c
@@ -0,0 +1,400 @@
+// 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * The contents of this file are generated using the tools in
+ * comedi/drivers/ni_routing/tools
+ *
+ * Please use those tools to help maintain the contents of this file.
+ */
+
+#include "../ni_device_routes.h"
+#include "all.h"
+
+struct ni_device_routes ni_pci_6713_device_routes = {
+ .device = "pci-6713",
+ .routes = (struct ni_route_set[]){
+ {
+ .dest = NI_PFI(3),
+ .src = (int[]){
+ NI_CtrSource(1),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(4),
+ .src = (int[]){
+ NI_CtrGate(1),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(5),
+ .src = (int[]){
+ NI_AO_SampleClock,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(6),
+ .src = (int[]){
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(8),
+ .src = (int[]){
+ NI_CtrSource(0),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(9),
+ .src = (int[]){
+ NI_CtrGate(0),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(0),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(1),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(2),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(3),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(4),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(5),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(6),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(7),
+ .src = (int[]){
+ NI_20MHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_MasterTimebase,
+ NI_20MHzTimebase,
+ NI_100kHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_MasterTimebase,
+ NI_20MHzTimebase,
+ NI_100kHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ NI_CtrInternalOutput(1),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ NI_CtrInternalOutput(0),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrOut(0),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ NI_CtrInternalOutput(0),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrOut(1),
+ .src = (int[]){
+ NI_CtrInternalOutput(1),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ NI_CtrInternalOutput(1),
+ NI_AO_SampleClockTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_SampleClockTimebase,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_MasterTimebase,
+ NI_20MHzTimebase,
+ NI_100kHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_StartTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_PauseTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_MasterTimebase,
+ .src = (int[]){
+ TRIGGER_LINE(7),
+ NI_20MHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ { /* Termination of list */
+ .dest = 0,
+ },
+ },
+};
diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6723.c b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6723.c
new file mode 100644
index 000000000000..e0cc57ab06e7
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6723.c
@@ -0,0 +1,400 @@
+// 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * The contents of this file are generated using the tools in
+ * comedi/drivers/ni_routing/tools
+ *
+ * Please use those tools to help maintain the contents of this file.
+ */
+
+#include "../ni_device_routes.h"
+#include "all.h"
+
+struct ni_device_routes ni_pci_6723_device_routes = {
+ .device = "pci-6723",
+ .routes = (struct ni_route_set[]){
+ {
+ .dest = NI_PFI(3),
+ .src = (int[]){
+ NI_CtrSource(1),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(4),
+ .src = (int[]){
+ NI_CtrGate(1),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(5),
+ .src = (int[]){
+ NI_AO_SampleClock,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(6),
+ .src = (int[]){
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(8),
+ .src = (int[]){
+ NI_CtrSource(0),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(9),
+ .src = (int[]){
+ NI_CtrGate(0),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(0),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(1),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(2),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(3),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(4),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(5),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(6),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(7),
+ .src = (int[]){
+ NI_20MHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_MasterTimebase,
+ NI_20MHzTimebase,
+ NI_100kHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_MasterTimebase,
+ NI_20MHzTimebase,
+ NI_100kHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ NI_CtrInternalOutput(1),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ NI_CtrInternalOutput(0),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrOut(0),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ NI_CtrInternalOutput(0),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrOut(1),
+ .src = (int[]){
+ NI_CtrInternalOutput(1),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ NI_CtrInternalOutput(1),
+ NI_AO_SampleClockTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_SampleClockTimebase,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_MasterTimebase,
+ NI_20MHzTimebase,
+ NI_100kHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_StartTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_PauseTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_MasterTimebase,
+ .src = (int[]){
+ TRIGGER_LINE(7),
+ NI_20MHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ { /* Termination of list */
+ .dest = 0,
+ },
+ },
+};
diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6733.c b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6733.c
new file mode 100644
index 000000000000..f6e1e17ab854
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pci-6733.c
@@ -0,0 +1,428 @@
+// 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * The contents of this file are generated using the tools in
+ * comedi/drivers/ni_routing/tools
+ *
+ * Please use those tools to help maintain the contents of this file.
+ */
+
+#include "../ni_device_routes.h"
+#include "all.h"
+
+struct ni_device_routes ni_pci_6733_device_routes = {
+ .device = "pci-6733",
+ .routes = (struct ni_route_set[]){
+ {
+ .dest = NI_PFI(3),
+ .src = (int[]){
+ NI_CtrSource(1),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(4),
+ .src = (int[]){
+ NI_CtrGate(1),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(5),
+ .src = (int[]){
+ NI_AO_SampleClock,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(6),
+ .src = (int[]){
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(8),
+ .src = (int[]){
+ NI_CtrSource(0),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(9),
+ .src = (int[]){
+ NI_CtrGate(0),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(0),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(1),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(2),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(3),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(4),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(5),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(6),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(7),
+ .src = (int[]){
+ NI_20MHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_MasterTimebase,
+ NI_20MHzTimebase,
+ NI_100kHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_MasterTimebase,
+ NI_20MHzTimebase,
+ NI_100kHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ NI_CtrInternalOutput(1),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ NI_CtrInternalOutput(0),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrOut(0),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ NI_CtrInternalOutput(0),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrOut(1),
+ .src = (int[]){
+ NI_CtrInternalOutput(1),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ NI_CtrInternalOutput(1),
+ NI_AO_SampleClockTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_SampleClockTimebase,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_MasterTimebase,
+ NI_20MHzTimebase,
+ NI_100kHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_StartTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_PauseTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DI_SampleClock,
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ NI_AO_SampleClock,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DO_SampleClock,
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ NI_AO_SampleClock,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_MasterTimebase,
+ .src = (int[]){
+ TRIGGER_LINE(7),
+ NI_20MHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ { /* Termination of list */
+ .dest = 0,
+ },
+ },
+};
diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxi-6030e.c b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxi-6030e.c
new file mode 100644
index 000000000000..9978d632117f
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxi-6030e.c
@@ -0,0 +1,608 @@
+// 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * The contents of this file are generated using the tools in
+ * comedi/drivers/ni_routing/tools
+ *
+ * Please use those tools to help maintain the contents of this file.
+ */
+
+#include "../ni_device_routes.h"
+#include "all.h"
+
+struct ni_device_routes ni_pxi_6030e_device_routes = {
+ .device = "pxi-6030e",
+ .routes = (struct ni_route_set[]){
+ {
+ .dest = NI_PFI(0),
+ .src = (int[]){
+ NI_AI_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(1),
+ .src = (int[]){
+ NI_AI_ReferenceTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(2),
+ .src = (int[]){
+ NI_AI_ConvertClock,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(3),
+ .src = (int[]){
+ NI_CtrSource(1),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(4),
+ .src = (int[]){
+ NI_CtrGate(1),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(5),
+ .src = (int[]){
+ NI_AO_SampleClock,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(6),
+ .src = (int[]){
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(7),
+ .src = (int[]){
+ NI_AI_SampleClock,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(8),
+ .src = (int[]){
+ NI_CtrSource(0),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(9),
+ .src = (int[]){
+ NI_CtrGate(0),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(0),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(1),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(2),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(3),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(4),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(5),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(7),
+ .src = (int[]){
+ NI_20MHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(7),
+ NI_MasterTimebase,
+ NI_20MHzTimebase,
+ NI_100kHzTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(7),
+ NI_MasterTimebase,
+ NI_20MHzTimebase,
+ NI_100kHzTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ NI_CtrInternalOutput(1),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ NI_CtrInternalOutput(0),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrOut(0),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ NI_CtrInternalOutput(0),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrOut(1),
+ .src = (int[]){
+ NI_CtrInternalOutput(1),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ NI_CtrInternalOutput(0),
+ NI_AI_SampleClockTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_SampleClockTimebase,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(7),
+ NI_MasterTimebase,
+ NI_20MHzTimebase,
+ NI_100kHzTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_StartTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ NI_CtrInternalOutput(0),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_ReferenceTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_ConvertClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ NI_CtrInternalOutput(0),
+ NI_AI_ConvertClockTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_ConvertClockTimebase,
+ .src = (int[]){
+ TRIGGER_LINE(7),
+ NI_AI_SampleClockTimebase,
+ NI_MasterTimebase,
+ NI_20MHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_PauseTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_HoldComplete,
+ .src = (int[]){
+ NI_AI_HoldCompleteEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ NI_CtrInternalOutput(1),
+ NI_AO_SampleClockTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_SampleClockTimebase,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(7),
+ NI_MasterTimebase,
+ NI_20MHzTimebase,
+ NI_100kHzTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_StartTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ NI_AI_StartTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_PauseTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_MasterTimebase,
+ .src = (int[]){
+ TRIGGER_LINE(7),
+ NI_20MHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ { /* Termination of list */
+ .dest = 0,
+ },
+ },
+};
diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxi-6224.c b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxi-6224.c
new file mode 100644
index 000000000000..1b89e27d7aa5
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxi-6224.c
@@ -0,0 +1,1432 @@
+// 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * The contents of this file are generated using the tools in
+ * comedi/drivers/ni_routing/tools
+ *
+ * Please use those tools to help maintain the contents of this file.
+ */
+
+#include "../ni_device_routes.h"
+#include "all.h"
+
+struct ni_device_routes ni_pxi_6224_device_routes = {
+ .device = "pxi-6224",
+ .routes = (struct ni_route_set[]){
+ {
+ .dest = NI_PFI(0),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(1),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(2),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(3),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(4),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(5),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(6),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(7),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(8),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(9),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(10),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(11),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(12),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(13),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(14),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(15),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(2),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(3),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(4),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(5),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(6),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(7),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ PXI_Clk10,
+ NI_20MHzTimebase,
+ NI_80MHzTimebase,
+ NI_100kHzTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrGate(0),
+ PXI_Clk10,
+ NI_20MHzTimebase,
+ NI_80MHzTimebase,
+ NI_100kHzTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(1),
+ NI_CtrInternalOutput(1),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrInternalOutput(0),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrAux(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrAux(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrA(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrA(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrB(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrB(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrZ(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrZ(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrArmStartTrigger(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(1),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrArmStartTrigger(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClockTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_SampleClockTimebase,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ PXI_Clk10,
+ NI_20MHzTimebase,
+ NI_100kHzTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_StartTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_ReferenceTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_ConvertClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_ConvertClockTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_ConvertClockTimebase,
+ .src = (int[]){
+ NI_AI_SampleClockTimebase,
+ NI_20MHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_PauseTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DI_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_ConvertClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DO_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_ConvertClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ { /* Termination of list */
+ .dest = 0,
+ },
+ },
+};
diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxi-6225.c b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxi-6225.c
new file mode 100644
index 000000000000..10dfc34bc87c
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxi-6225.c
@@ -0,0 +1,1613 @@
+// 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * The contents of this file are generated using the tools in
+ * comedi/drivers/ni_routing/tools
+ *
+ * Please use those tools to help maintain the contents of this file.
+ */
+
+#include "../ni_device_routes.h"
+#include "all.h"
+
+struct ni_device_routes ni_pxi_6225_device_routes = {
+ .device = "pxi-6225",
+ .routes = (struct ni_route_set[]){
+ {
+ .dest = NI_PFI(0),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(1),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(2),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(3),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(4),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(5),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(6),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(7),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(8),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(9),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(10),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(11),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(12),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(13),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(14),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(15),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(2),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(3),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(4),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(5),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(6),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(7),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ PXI_Clk10,
+ NI_20MHzTimebase,
+ NI_80MHzTimebase,
+ NI_100kHzTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrGate(0),
+ PXI_Clk10,
+ NI_20MHzTimebase,
+ NI_80MHzTimebase,
+ NI_100kHzTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(1),
+ NI_CtrInternalOutput(1),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrInternalOutput(0),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrAux(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrAux(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrA(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrA(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrB(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrB(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrZ(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrZ(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrArmStartTrigger(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(1),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrArmStartTrigger(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClockTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_SampleClockTimebase,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ PXI_Clk10,
+ NI_20MHzTimebase,
+ NI_100kHzTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_StartTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_ReferenceTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_ConvertClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_ConvertClockTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_ConvertClockTimebase,
+ .src = (int[]){
+ NI_AI_SampleClockTimebase,
+ NI_20MHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_PauseTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AO_SampleClockTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_SampleClockTimebase,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ PXI_Clk10,
+ NI_20MHzTimebase,
+ NI_100kHzTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_StartTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AI_StartTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_PauseTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DI_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DO_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ { /* Termination of list */
+ .dest = 0,
+ },
+ },
+};
diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxi-6251.c b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxi-6251.c
new file mode 100644
index 000000000000..25db4b7363de
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxi-6251.c
@@ -0,0 +1,1655 @@
+// 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * The contents of this file are generated using the tools in
+ * comedi/drivers/ni_routing/tools
+ *
+ * Please use those tools to help maintain the contents of this file.
+ */
+
+#include "../ni_device_routes.h"
+#include "all.h"
+
+struct ni_device_routes ni_pxi_6251_device_routes = {
+ .device = "pxi-6251",
+ .routes = (struct ni_route_set[]){
+ {
+ .dest = NI_PFI(0),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ PXI_Star,
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(1),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ PXI_Star,
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(2),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ PXI_Star,
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(3),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ PXI_Star,
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(4),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ PXI_Star,
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(5),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ PXI_Star,
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(6),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ PXI_Star,
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(7),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ PXI_Star,
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(8),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ PXI_Star,
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(9),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ PXI_Star,
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(10),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ PXI_Star,
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(11),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ PXI_Star,
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(12),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ PXI_Star,
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(13),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ PXI_Star,
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(14),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ PXI_Star,
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(15),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ PXI_Star,
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(2),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(3),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(4),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(5),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(6),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(7),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ PXI_Star,
+ PXI_Clk10,
+ NI_20MHzTimebase,
+ NI_80MHzTimebase,
+ NI_100kHzTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrGate(0),
+ PXI_Star,
+ PXI_Clk10,
+ NI_20MHzTimebase,
+ NI_80MHzTimebase,
+ NI_100kHzTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(1),
+ NI_CtrInternalOutput(1),
+ PXI_Star,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrInternalOutput(0),
+ PXI_Star,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrAux(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(1),
+ PXI_Star,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrAux(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ PXI_Star,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrA(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ PXI_Star,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrA(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ PXI_Star,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrB(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ PXI_Star,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrB(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ PXI_Star,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrZ(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ PXI_Star,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrZ(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ PXI_Star,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrArmStartTrigger(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(1),
+ PXI_Star,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrArmStartTrigger(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ PXI_Star,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ PXI_Star,
+ NI_AI_SampleClockTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_SampleClockTimebase,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ PXI_Star,
+ PXI_Clk10,
+ NI_20MHzTimebase,
+ NI_100kHzTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_StartTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ PXI_Star,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_ReferenceTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ PXI_Star,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_ConvertClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ PXI_Star,
+ NI_AI_ConvertClockTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_ConvertClockTimebase,
+ .src = (int[]){
+ NI_AI_SampleClockTimebase,
+ NI_20MHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_PauseTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ PXI_Star,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ PXI_Star,
+ NI_AO_SampleClockTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_SampleClockTimebase,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ PXI_Star,
+ PXI_Clk10,
+ NI_20MHzTimebase,
+ NI_100kHzTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_StartTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ PXI_Star,
+ NI_AI_StartTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_PauseTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ PXI_Star,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DI_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ PXI_Star,
+ NI_AI_SampleClock,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DO_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ PXI_Star,
+ NI_AI_SampleClock,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ { /* Termination of list */
+ .dest = 0,
+ },
+ },
+};
diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxi-6733.c b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxi-6733.c
new file mode 100644
index 000000000000..27da4433fc4a
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxi-6733.c
@@ -0,0 +1,428 @@
+// 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * The contents of this file are generated using the tools in
+ * comedi/drivers/ni_routing/tools
+ *
+ * Please use those tools to help maintain the contents of this file.
+ */
+
+#include "../ni_device_routes.h"
+#include "all.h"
+
+struct ni_device_routes ni_pxi_6733_device_routes = {
+ .device = "pxi-6733",
+ .routes = (struct ni_route_set[]){
+ {
+ .dest = NI_PFI(3),
+ .src = (int[]){
+ NI_CtrSource(1),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(4),
+ .src = (int[]){
+ NI_CtrGate(1),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(5),
+ .src = (int[]){
+ NI_AO_SampleClock,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(6),
+ .src = (int[]){
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(8),
+ .src = (int[]){
+ NI_CtrSource(0),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(9),
+ .src = (int[]){
+ NI_CtrGate(0),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(0),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(1),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(2),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(3),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(4),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(5),
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(7),
+ .src = (int[]){
+ NI_20MHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(7),
+ PXI_Star,
+ NI_MasterTimebase,
+ NI_20MHzTimebase,
+ NI_100kHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(7),
+ PXI_Star,
+ NI_MasterTimebase,
+ NI_20MHzTimebase,
+ NI_100kHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ NI_CtrInternalOutput(1),
+ PXI_Star,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ NI_CtrInternalOutput(0),
+ PXI_Star,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrOut(0),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ NI_CtrInternalOutput(0),
+ PXI_Star,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrOut(1),
+ .src = (int[]){
+ NI_CtrInternalOutput(1),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = PXI_Star,
+ .src = (int[]){
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrInternalOutput(0),
+ NI_CtrOut(0),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ NI_CtrInternalOutput(1),
+ PXI_Star,
+ NI_AO_SampleClockTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_SampleClockTimebase,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(7),
+ PXI_Star,
+ NI_MasterTimebase,
+ NI_20MHzTimebase,
+ NI_100kHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_StartTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ PXI_Star,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_PauseTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ PXI_Star,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DI_SampleClock,
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ PXI_Star,
+ NI_AO_SampleClock,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DO_SampleClock,
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ PXI_Star,
+ NI_AO_SampleClock,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_MasterTimebase,
+ .src = (int[]){
+ TRIGGER_LINE(7),
+ NI_20MHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ { /* Termination of list */
+ .dest = 0,
+ },
+ },
+};
diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxie-6251.c b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxie-6251.c
new file mode 100644
index 000000000000..8354fe971d59
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxie-6251.c
@@ -0,0 +1,1656 @@
+// 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * The contents of this file are generated using the tools in
+ * comedi/drivers/ni_routing/tools
+ *
+ * Please use those tools to help maintain the contents of this file.
+ */
+
+#include "../ni_device_routes.h"
+#include "all.h"
+
+struct ni_device_routes ni_pxie_6251_device_routes = {
+ .device = "pxie-6251",
+ .routes = (struct ni_route_set[]){
+ {
+ .dest = NI_PFI(0),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(1),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(2),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(3),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(4),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(5),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(6),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(7),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(8),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(9),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(10),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(11),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(12),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(13),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(14),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(15),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_DI_SampleClock,
+ NI_DO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(2),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(3),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(4),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(5),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(6),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(7),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AI_ConvertClock,
+ NI_AI_PauseTrigger,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrGate(1),
+ PXI_Clk10,
+ NI_20MHzTimebase,
+ NI_80MHzTimebase,
+ NI_100kHzTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrGate(0),
+ PXI_Clk10,
+ NI_20MHzTimebase,
+ NI_80MHzTimebase,
+ NI_100kHzTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(1),
+ NI_CtrInternalOutput(1),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrInternalOutput(0),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrAux(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(1),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(1),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrAux(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrInternalOutput(0),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrA(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrA(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrB(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrB(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrZ(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrZ(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrArmStartTrigger(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(1),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrArmStartTrigger(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_AI_StartTrigger,
+ NI_AI_ReferenceTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClockTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_SampleClockTimebase,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ PXI_Clk10,
+ NI_20MHzTimebase,
+ NI_100kHzTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_StartTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_ReferenceTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_ConvertClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_ConvertClockTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_ConvertClockTimebase,
+ .src = (int[]){
+ NI_AI_SampleClockTimebase,
+ NI_20MHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AI_PauseTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AO_SampleClockTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_SampleClockTimebase,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ PXI_Clk10,
+ NI_20MHzTimebase,
+ NI_100kHzTimebase,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_StartTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AI_StartTrigger,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_PauseTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DI_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DO_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_PFI(8),
+ NI_PFI(9),
+ NI_PFI(10),
+ NI_PFI(11),
+ NI_PFI(12),
+ NI_PFI(13),
+ NI_PFI(14),
+ NI_PFI(15),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_AI_SampleClock,
+ NI_AI_ConvertClock,
+ NI_AO_SampleClock,
+ NI_FrequencyOutput,
+ NI_ChangeDetectionEvent,
+ NI_AnalogComparisonEvent,
+ 0, /* Termination */
+ }
+ },
+ { /* Termination of list */
+ .dest = 0,
+ },
+ },
+};
diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxie-6535.c b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxie-6535.c
new file mode 100644
index 000000000000..2ebb679e0129
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxie-6535.c
@@ -0,0 +1,575 @@
+// 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * The contents of this file are generated using the tools in
+ * comedi/drivers/ni_routing/tools
+ *
+ * Please use those tools to help maintain the contents of this file.
+ */
+
+#include "../ni_device_routes.h"
+#include "all.h"
+
+struct ni_device_routes ni_pxie_6535_device_routes = {
+ .device = "pxie-6535",
+ .routes = (struct ni_route_set[]){
+ {
+ .dest = NI_PFI(0),
+ .src = (int[]){
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_InputBufferFull,
+ NI_DI_ReadyForStartEvent,
+ NI_DI_ReadyForTransferEventBurst,
+ NI_DI_ReadyForTransferEventPipelined,
+ NI_DO_StartTrigger,
+ NI_DO_OutputBufferFull,
+ NI_DO_DataActiveEvent,
+ NI_DO_ReadyForStartEvent,
+ NI_DO_ReadyForTransferEvent,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_InputBufferFull,
+ NI_DI_ReadyForStartEvent,
+ NI_DI_ReadyForTransferEventBurst,
+ NI_DI_ReadyForTransferEventPipelined,
+ NI_DO_StartTrigger,
+ NI_DO_OutputBufferFull,
+ NI_DO_DataActiveEvent,
+ NI_DO_ReadyForStartEvent,
+ NI_DO_ReadyForTransferEvent,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(2),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_InputBufferFull,
+ NI_DI_ReadyForStartEvent,
+ NI_DI_ReadyForTransferEventBurst,
+ NI_DI_ReadyForTransferEventPipelined,
+ NI_DO_StartTrigger,
+ NI_DO_OutputBufferFull,
+ NI_DO_DataActiveEvent,
+ NI_DO_ReadyForStartEvent,
+ NI_DO_ReadyForTransferEvent,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(3),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(4),
+ NI_PFI(5),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_InputBufferFull,
+ NI_DI_ReadyForStartEvent,
+ NI_DI_ReadyForTransferEventBurst,
+ NI_DI_ReadyForTransferEventPipelined,
+ NI_DO_StartTrigger,
+ NI_DO_OutputBufferFull,
+ NI_DO_DataActiveEvent,
+ NI_DO_ReadyForStartEvent,
+ NI_DO_ReadyForTransferEvent,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(4),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(5),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_InputBufferFull,
+ NI_DI_ReadyForStartEvent,
+ NI_DI_ReadyForTransferEventBurst,
+ NI_DI_ReadyForTransferEventPipelined,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_OutputBufferFull,
+ NI_DO_DataActiveEvent,
+ NI_DO_ReadyForStartEvent,
+ NI_DO_ReadyForTransferEvent,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(5),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_InputBufferFull,
+ NI_DI_ReadyForStartEvent,
+ NI_DI_ReadyForTransferEventBurst,
+ NI_DI_ReadyForTransferEventPipelined,
+ NI_DO_StartTrigger,
+ NI_DO_OutputBufferFull,
+ NI_DO_DataActiveEvent,
+ NI_DO_ReadyForStartEvent,
+ NI_DO_ReadyForTransferEvent,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_InputBufferFull,
+ NI_DI_ReadyForStartEvent,
+ NI_DI_ReadyForTransferEventBurst,
+ NI_DI_ReadyForTransferEventPipelined,
+ NI_DO_StartTrigger,
+ NI_DO_OutputBufferFull,
+ NI_DO_DataActiveEvent,
+ NI_DO_ReadyForStartEvent,
+ NI_DO_ReadyForTransferEvent,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_InputBufferFull,
+ NI_DI_ReadyForStartEvent,
+ NI_DI_ReadyForTransferEventBurst,
+ NI_DI_ReadyForTransferEventPipelined,
+ NI_DO_StartTrigger,
+ NI_DO_OutputBufferFull,
+ NI_DO_DataActiveEvent,
+ NI_DO_ReadyForStartEvent,
+ NI_DO_ReadyForTransferEvent,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(2),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_InputBufferFull,
+ NI_DI_ReadyForStartEvent,
+ NI_DI_ReadyForTransferEventBurst,
+ NI_DI_ReadyForTransferEventPipelined,
+ NI_DO_StartTrigger,
+ NI_DO_OutputBufferFull,
+ NI_DO_DataActiveEvent,
+ NI_DO_ReadyForStartEvent,
+ NI_DO_ReadyForTransferEvent,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(3),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_InputBufferFull,
+ NI_DI_ReadyForStartEvent,
+ NI_DI_ReadyForTransferEventBurst,
+ NI_DI_ReadyForTransferEventPipelined,
+ NI_DO_StartTrigger,
+ NI_DO_OutputBufferFull,
+ NI_DO_DataActiveEvent,
+ NI_DO_ReadyForStartEvent,
+ NI_DO_ReadyForTransferEvent,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(4),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_InputBufferFull,
+ NI_DI_ReadyForStartEvent,
+ NI_DI_ReadyForTransferEventBurst,
+ NI_DI_ReadyForTransferEventPipelined,
+ NI_DO_StartTrigger,
+ NI_DO_OutputBufferFull,
+ NI_DO_DataActiveEvent,
+ NI_DO_ReadyForStartEvent,
+ NI_DO_ReadyForTransferEvent,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(5),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(6),
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_InputBufferFull,
+ NI_DI_ReadyForStartEvent,
+ NI_DI_ReadyForTransferEventBurst,
+ NI_DI_ReadyForTransferEventPipelined,
+ NI_DO_StartTrigger,
+ NI_DO_OutputBufferFull,
+ NI_DO_DataActiveEvent,
+ NI_DO_ReadyForStartEvent,
+ NI_DO_ReadyForTransferEvent,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(6),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_InputBufferFull,
+ NI_DI_ReadyForStartEvent,
+ NI_DI_ReadyForTransferEventBurst,
+ NI_DI_ReadyForTransferEventPipelined,
+ NI_DO_StartTrigger,
+ NI_DO_OutputBufferFull,
+ NI_DO_DataActiveEvent,
+ NI_DO_ReadyForStartEvent,
+ NI_DO_ReadyForTransferEvent,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(7),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_InputBufferFull,
+ NI_DI_ReadyForStartEvent,
+ NI_DI_ReadyForTransferEventBurst,
+ NI_DI_ReadyForTransferEventPipelined,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_OutputBufferFull,
+ NI_DO_DataActiveEvent,
+ NI_DO_ReadyForStartEvent,
+ NI_DO_ReadyForTransferEvent,
+ NI_ChangeDetectionEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DI_SampleClock,
+ .src = (int[]){
+ NI_PFI(5),
+ TRIGGER_LINE(7),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DI_StartTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DI_ReferenceTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DI_PauseTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DO_SampleClock,
+ .src = (int[]){
+ NI_PFI(4),
+ TRIGGER_LINE(7),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DO_StartTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DO_PauseTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ 0, /* Termination */
+ }
+ },
+ { /* Termination of list */
+ .dest = 0,
+ },
+ },
+};
diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxie-6738.c b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxie-6738.c
new file mode 100644
index 000000000000..d88504314d7f
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/ni_device_routes/pxie-6738.c
@@ -0,0 +1,3083 @@
+// 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * The contents of this file are generated using the tools in
+ * comedi/drivers/ni_routing/tools
+ *
+ * Please use those tools to help maintain the contents of this file.
+ */
+
+#include "../ni_device_routes.h"
+#include "all.h"
+
+struct ni_device_routes ni_pxie_6738_device_routes = {
+ .device = "pxie-6738",
+ .routes = (struct ni_route_set[]){
+ {
+ .dest = NI_PFI(0),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(1),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(2),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(3),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(4),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(5),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(6),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_PFI(7),
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrZ(0),
+ NI_CtrZ(1),
+ NI_CtrZ(2),
+ NI_CtrZ(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrZ(0),
+ NI_CtrZ(1),
+ NI_CtrZ(2),
+ NI_CtrZ(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(2),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrZ(0),
+ NI_CtrZ(1),
+ NI_CtrZ(2),
+ NI_CtrZ(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(3),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrZ(0),
+ NI_CtrZ(1),
+ NI_CtrZ(2),
+ NI_CtrZ(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(4),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrZ(0),
+ NI_CtrZ(1),
+ NI_CtrZ(2),
+ NI_CtrZ(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(5),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrZ(0),
+ NI_CtrZ(1),
+ NI_CtrZ(2),
+ NI_CtrZ(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(6),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrZ(0),
+ NI_CtrZ(1),
+ NI_CtrZ(2),
+ NI_CtrZ(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = TRIGGER_LINE(7),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrZ(0),
+ NI_CtrZ(1),
+ NI_CtrZ(2),
+ NI_CtrZ(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ PXI_Clk10,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_20MHzTimebase,
+ NI_100MHzTimebase,
+ NI_100kHzTimebase,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ PXI_Clk10,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_20MHzTimebase,
+ NI_100MHzTimebase,
+ NI_100kHzTimebase,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(2),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(3),
+ PXI_Clk10,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_20MHzTimebase,
+ NI_100MHzTimebase,
+ NI_100kHzTimebase,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSource(3),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ PXI_Clk10,
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_20MHzTimebase,
+ NI_100MHzTimebase,
+ NI_100kHzTimebase,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(2),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrGate(3),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrAux(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrAux(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrAux(2),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrAux(3),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrA(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrA(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrA(2),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrA(3),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrB(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrB(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrB(2),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrB(3),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrZ(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrZ(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrZ(2),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrZ(3),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrArmStartTrigger(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrArmStartTrigger(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrArmStartTrigger(2),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrArmStartTrigger(3),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSampleClock(0),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSampleClock(1),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSampleClock(2),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_CtrSampleClock(3),
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClockTimebase,
+ NI_DI_SampleClock,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_SampleClockTimebase,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ PXI_Clk10,
+ NI_20MHzTimebase,
+ NI_100MHzTimebase,
+ NI_100kHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_StartTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_AO_PauseTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DI_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DI_SampleClockTimebase,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ PXI_Clk10,
+ NI_DI_SampleClockTimebase,
+ NI_20MHzTimebase,
+ NI_100MHzTimebase,
+ NI_100kHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DI_StartTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DI_ReferenceTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DI_PauseTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DO_SampleClock,
+ NI_DO_StartTrigger,
+ NI_DO_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DO_SampleClock,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_DO_SampleClockTimebase,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DO_SampleClockTimebase,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ PXI_Clk10,
+ NI_20MHzTimebase,
+ NI_100MHzTimebase,
+ NI_100kHzTimebase,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DO_StartTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_DO_PauseTrigger,
+ .src = (int[]){
+ NI_PFI(0),
+ NI_PFI(1),
+ NI_PFI(2),
+ NI_PFI(3),
+ NI_PFI(4),
+ NI_PFI(5),
+ NI_PFI(6),
+ NI_PFI(7),
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ NI_CtrSource(0),
+ NI_CtrSource(1),
+ NI_CtrSource(2),
+ NI_CtrSource(3),
+ NI_CtrGate(0),
+ NI_CtrGate(1),
+ NI_CtrGate(2),
+ NI_CtrGate(3),
+ NI_CtrArmStartTrigger(0),
+ NI_CtrArmStartTrigger(1),
+ NI_CtrArmStartTrigger(2),
+ NI_CtrArmStartTrigger(3),
+ NI_CtrInternalOutput(0),
+ NI_CtrInternalOutput(1),
+ NI_CtrInternalOutput(2),
+ NI_CtrInternalOutput(3),
+ NI_CtrSampleClock(0),
+ NI_CtrSampleClock(1),
+ NI_CtrSampleClock(2),
+ NI_CtrSampleClock(3),
+ NI_AO_SampleClock,
+ NI_AO_StartTrigger,
+ NI_AO_PauseTrigger,
+ NI_DI_SampleClock,
+ NI_DI_StartTrigger,
+ NI_DI_ReferenceTrigger,
+ NI_DI_PauseTrigger,
+ NI_10MHzRefClock,
+ NI_ChangeDetectionEvent,
+ NI_WatchdogExpiredEvent,
+ 0, /* Termination */
+ }
+ },
+ {
+ .dest = NI_WatchdogExpirationTrigger,
+ .src = (int[]){
+ TRIGGER_LINE(0),
+ TRIGGER_LINE(1),
+ TRIGGER_LINE(2),
+ TRIGGER_LINE(3),
+ TRIGGER_LINE(4),
+ TRIGGER_LINE(5),
+ TRIGGER_LINE(6),
+ TRIGGER_LINE(7),
+ 0, /* Termination */
+ }
+ },
+ { /* Termination of list */
+ .dest = 0,
+ },
+ },
+};
diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_route_values.c b/drivers/staging/comedi/drivers/ni_routing/ni_route_values.c
new file mode 100644
index 000000000000..5901762734ed
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/ni_route_values.c
@@ -0,0 +1,42 @@
+// 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * This file includes the tables that are a list of all the values of various
+ * signals routes available on NI hardware. In many cases, one does not
+ * explicitly make these routes, rather one might indicate that something is
+ * used as the source of one particular trigger or another (using
+ * *_src=TRIG_EXT).
+ *
+ * The contents of this file are generated using the tools in
+ * comedi/drivers/ni_routing/tools
+ *
+ * Please use those tools to help maintain the contents of this file.
+ */
+
+#include "ni_route_values.h"
+#include "ni_route_values/all.h"
+
+const struct family_route_values *const ni_all_route_values[] = {
+ &ni_660x_route_values,
+ &ni_eseries_route_values,
+ &ni_mseries_route_values,
+ NULL,
+};
diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_route_values.h b/drivers/staging/comedi/drivers/ni_routing/ni_route_values.h
new file mode 100644
index 000000000000..80e0145fb82b
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/ni_route_values.h
@@ -0,0 +1,98 @@
+/* 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _COMEDI_DRIVERS_NI_ROUTINT_NI_ROUTE_VALUES_H
+#define _COMEDI_DRIVERS_NI_ROUTINT_NI_ROUTE_VALUES_H
+
+#include "../../comedi.h"
+#include <linux/types.h>
+
+/*
+ * This file includes the tables that are a list of all the values of various
+ * signals routes available on NI hardware. In many cases, one does not
+ * explicitly make these routes, rather one might indicate that something is
+ * used as the source of one particular trigger or another (using
+ * *_src=TRIG_EXT).
+ *
+ * This file is meant to be included by comedi/drivers/ni_routes.c
+ */
+
+#define B(x) ((x) - NI_NAMES_BASE)
+
+/** Marks a register value as valid, implemented, and tested. */
+#define V(x) (((x) & 0x7f) | 0x80)
+
+#ifndef NI_ROUTE_VALUE_EXTERNAL_CONVERSION
+ /** Marks a register value as implemented but needing testing. */
+ #define I(x) V(x)
+ /** Marks a register value as not implemented. */
+ #define U(x) 0x0
+
+ typedef u8 register_type;
+#else
+ /** Marks a register value as implemented but needing testing. */
+ #define I(x) (((x) & 0x7f) | 0x100)
+ /** Marks a register value as not implemented. */
+ #define U(x) (((x) & 0x7f) | 0x200)
+
+ /** Tests whether a register is marked as valid/implemented/tested */
+ #define MARKED_V(x) (((x) & 0x80) != 0)
+ /** Tests whether a register is implemented but not tested */
+ #define MARKED_I(x) (((x) & 0x100) != 0)
+ /** Tests whether a register is not implemented */
+ #define MARKED_U(x) (((x) & 0x200) != 0)
+
+ /* need more space to store extra marks */
+ typedef u16 register_type;
+#endif
+
+/* Mask out the marking bit(s). */
+#define UNMARK(x) ((x) & 0x7f)
+
+/*
+ * Gi_SRC(x,1) implements Gi_Src_SubSelect = 1
+ *
+ * This appears to only really be a valid MUX for m-series devices.
+ */
+#define Gi_SRC(val, subsel) ((val) | ((subsel) << 6))
+
+/**
+ * struct family_route_values - Register values for all routes for a particular
+ * family.
+ * @family: lower-case string representation of a specific series or family of
+ * devices from National Instruments where each member of this family
+ * shares the same register values for the various signal MUXes. It
+ * should be noted that not all devices of any family have access to
+ * all routes defined.
+ * @register_values: Table of all register values for various signal MUXes on
+ * National Instruments devices. The first index of this table is the
+ * signal destination (i.e. identification of the signal MUX). The
+ * second index of this table is the signal source (i.e. input of the
+ * signal MUX).
+ */
+struct family_route_values {
+ const char *family;
+ const register_type register_values[NI_NUM_NAMES][NI_NUM_NAMES];
+
+};
+
+extern const struct family_route_values *const ni_all_route_values[];
+
+#endif /* _COMEDI_DRIVERS_NI_ROUTINT_NI_ROUTE_VALUES_H */
diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_route_values/all.h b/drivers/staging/comedi/drivers/ni_routing/ni_route_values/all.h
new file mode 100644
index 000000000000..7227461500b5
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/ni_route_values/all.h
@@ -0,0 +1,37 @@
+/* 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * The contents of this file are generated using the tools in
+ * comedi/drivers/ni_routing/tools
+ *
+ * Please use those tools to help maintain the contents of this file.
+ */
+
+#ifndef _COMEDI_DRIVERS_NI_ROUTING_NI_ROUTE_VALUES_EXTERN_H
+#define _COMEDI_DRIVERS_NI_ROUTING_NI_ROUTE_VALUES_EXTERN_H
+
+#include "../ni_route_values.h"
+
+extern const struct family_route_values ni_660x_route_values;
+extern const struct family_route_values ni_eseries_route_values;
+extern const struct family_route_values ni_mseries_route_values;
+
+#endif //_COMEDI_DRIVERS_NI_ROUTING_NI_ROUTE_VALUES_EXTERN_H
diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_route_values/ni_660x.c b/drivers/staging/comedi/drivers/ni_routing/ni_route_values/ni_660x.c
new file mode 100644
index 000000000000..f1c7e6646261
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/ni_route_values/ni_660x.c
@@ -0,0 +1,650 @@
+// 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * This file includes a list of all the values of various signals routes
+ * available on NI 660x hardware. In many cases, one does not explicitly make
+ * these routes, rather one might indicate that something is used as the source
+ * of one particular trigger or another (using *_src=TRIG_EXT).
+ *
+ * The contents of this file can be generated using the tools in
+ * comedi/drivers/ni_routing/tools. This file also contains specific notes to
+ * this family of devices.
+ *
+ * Please use those tools to help maintain the contents of this file, but be
+ * mindful to not lose the notes already made in this file, since these notes
+ * are critical to a complete undertsanding of the register values of this
+ * family.
+ */
+
+#include "../ni_route_values.h"
+#include "all.h"
+
+const struct family_route_values ni_660x_route_values = {
+ .family = "ni_660x",
+ .register_values = {
+ /*
+ * destination = {
+ * source = register value,
+ * ...
+ * }
+ */
+ [B(NI_PFI(8))] = {
+ [B(NI_CtrInternalOutput(7))] = I(1),
+ },
+ [B(NI_PFI(10))] = {
+ [B(NI_CtrGate(7))] = I(1),
+ },
+ [B(NI_PFI(11))] = {
+ [B(NI_CtrSource(7))] = I(1),
+ },
+ [B(NI_PFI(12))] = {
+ [B(NI_CtrInternalOutput(6))] = I(1),
+ },
+ [B(NI_PFI(14))] = {
+ [B(NI_CtrGate(6))] = I(1),
+ },
+ [B(NI_PFI(15))] = {
+ [B(NI_CtrSource(6))] = I(1),
+ },
+ [B(NI_PFI(16))] = {
+ [B(NI_CtrInternalOutput(5))] = I(1),
+ },
+ [B(NI_PFI(18))] = {
+ [B(NI_CtrGate(5))] = I(1),
+ },
+ [B(NI_PFI(19))] = {
+ [B(NI_CtrSource(5))] = I(1),
+ },
+ [B(NI_PFI(20))] = {
+ [B(NI_CtrInternalOutput(4))] = I(1),
+ },
+ [B(NI_PFI(22))] = {
+ [B(NI_CtrGate(4))] = I(1),
+ },
+ [B(NI_PFI(23))] = {
+ [B(NI_CtrSource(4))] = I(1),
+ },
+ [B(NI_PFI(24))] = {
+ [B(NI_CtrInternalOutput(3))] = I(1),
+ },
+ [B(NI_PFI(26))] = {
+ [B(NI_CtrGate(3))] = I(1),
+ },
+ [B(NI_PFI(27))] = {
+ [B(NI_CtrSource(3))] = I(1),
+ },
+ [B(NI_PFI(28))] = {
+ [B(NI_CtrInternalOutput(2))] = I(1),
+ },
+ [B(NI_PFI(30))] = {
+ [B(NI_CtrGate(2))] = I(1),
+ },
+ [B(NI_PFI(31))] = {
+ [B(NI_CtrSource(2))] = I(1),
+ },
+ [B(NI_PFI(32))] = {
+ [B(NI_CtrInternalOutput(1))] = I(1),
+ },
+ [B(NI_PFI(34))] = {
+ [B(NI_CtrGate(1))] = I(1),
+ },
+ [B(NI_PFI(35))] = {
+ [B(NI_CtrSource(1))] = I(1),
+ },
+ [B(NI_PFI(36))] = {
+ [B(NI_CtrInternalOutput(0))] = I(1),
+ },
+ [B(NI_PFI(38))] = {
+ [B(NI_CtrGate(0))] = I(1),
+ },
+ [B(NI_PFI(39))] = {
+ [B(NI_CtrSource(0))] = I(1),
+ },
+ [B(NI_CtrSource(0))] = {
+ /* These are not currently implemented in ni modules */
+ [B(NI_PFI(11))] = U(9),
+ [B(NI_PFI(15))] = U(8),
+ [B(NI_PFI(19))] = U(7),
+ [B(NI_PFI(23))] = U(6),
+ [B(NI_PFI(27))] = U(5),
+ [B(NI_PFI(31))] = U(4),
+ [B(NI_PFI(35))] = U(3),
+ [B(NI_PFI(39))] = U(2 /* or 1 */),
+ [B(TRIGGER_LINE(0))] = U(11),
+ [B(TRIGGER_LINE(1))] = U(12),
+ [B(TRIGGER_LINE(2))] = U(13),
+ [B(TRIGGER_LINE(3))] = U(14),
+ [B(TRIGGER_LINE(4))] = U(15),
+ [B(TRIGGER_LINE(5))] = U(16),
+ [B(TRIGGER_LINE(6))] = U(17),
+ [B(NI_CtrGate(1))] = U(10),
+ [B(NI_20MHzTimebase)] = U(0),
+ [B(NI_80MHzTimebase)] = U(30),
+ [B(NI_100kHzTimebase)] = U(18),
+ [B(NI_LogicLow)] = U(31),
+ },
+ [B(NI_CtrSource(1))] = {
+ /* These are not currently implemented in ni modules */
+ [B(NI_PFI(11))] = U(9),
+ [B(NI_PFI(15))] = U(8),
+ [B(NI_PFI(19))] = U(7),
+ [B(NI_PFI(23))] = U(6),
+ [B(NI_PFI(27))] = U(5),
+ [B(NI_PFI(31))] = U(4),
+ [B(NI_PFI(35))] = U(3 /* or 1 */),
+ [B(NI_PFI(39))] = U(2),
+ [B(TRIGGER_LINE(0))] = U(11),
+ [B(TRIGGER_LINE(1))] = U(12),
+ [B(TRIGGER_LINE(2))] = U(13),
+ [B(TRIGGER_LINE(3))] = U(14),
+ [B(TRIGGER_LINE(4))] = U(15),
+ [B(TRIGGER_LINE(5))] = U(16),
+ [B(TRIGGER_LINE(6))] = U(17),
+ [B(NI_CtrGate(2))] = U(10),
+ [B(NI_20MHzTimebase)] = U(0),
+ [B(NI_80MHzTimebase)] = U(30),
+ [B(NI_100kHzTimebase)] = U(18),
+ [B(NI_LogicLow)] = U(31),
+ },
+ [B(NI_CtrSource(2))] = {
+ /* These are not currently implemented in ni modules */
+ [B(NI_PFI(11))] = U(9),
+ [B(NI_PFI(15))] = U(8),
+ [B(NI_PFI(19))] = U(7),
+ [B(NI_PFI(23))] = U(6),
+ [B(NI_PFI(27))] = U(5),
+ [B(NI_PFI(31))] = U(4 /* or 1 */),
+ [B(NI_PFI(35))] = U(3),
+ [B(NI_PFI(39))] = U(2),
+ [B(TRIGGER_LINE(0))] = U(11),
+ [B(TRIGGER_LINE(1))] = U(12),
+ [B(TRIGGER_LINE(2))] = U(13),
+ [B(TRIGGER_LINE(3))] = U(14),
+ [B(TRIGGER_LINE(4))] = U(15),
+ [B(TRIGGER_LINE(5))] = U(16),
+ [B(TRIGGER_LINE(6))] = U(17),
+ [B(NI_CtrGate(3))] = U(10),
+ [B(NI_20MHzTimebase)] = U(0),
+ [B(NI_80MHzTimebase)] = U(30),
+ [B(NI_100kHzTimebase)] = U(18),
+ [B(NI_LogicLow)] = U(31),
+ },
+ [B(NI_CtrSource(3))] = {
+ /* These are not currently implemented in ni modules */
+ [B(NI_PFI(11))] = U(9),
+ [B(NI_PFI(15))] = U(8),
+ [B(NI_PFI(19))] = U(7),
+ [B(NI_PFI(23))] = U(6),
+ [B(NI_PFI(27))] = U(5 /* or 1 */),
+ [B(NI_PFI(31))] = U(4),
+ [B(NI_PFI(35))] = U(3),
+ [B(NI_PFI(39))] = U(2),
+ [B(TRIGGER_LINE(0))] = U(11),
+ [B(TRIGGER_LINE(1))] = U(12),
+ [B(TRIGGER_LINE(2))] = U(13),
+ [B(TRIGGER_LINE(3))] = U(14),
+ [B(TRIGGER_LINE(4))] = U(15),
+ [B(TRIGGER_LINE(5))] = U(16),
+ [B(TRIGGER_LINE(6))] = U(17),
+ [B(NI_CtrGate(4))] = U(10),
+ [B(NI_20MHzTimebase)] = U(0),
+ [B(NI_80MHzTimebase)] = U(30),
+ [B(NI_100kHzTimebase)] = U(18),
+ [B(NI_LogicLow)] = U(31),
+ },
+ [B(NI_CtrSource(4))] = {
+ /* These are not currently implemented in ni modules */
+ [B(NI_PFI(11))] = U(9),
+ [B(NI_PFI(15))] = U(8),
+ [B(NI_PFI(19))] = U(7),
+ [B(NI_PFI(23))] = U(6 /* or 1 */),
+ [B(NI_PFI(27))] = U(5),
+ [B(NI_PFI(31))] = U(4),
+ [B(NI_PFI(35))] = U(3),
+ [B(NI_PFI(39))] = U(2),
+ [B(TRIGGER_LINE(0))] = U(11),
+ [B(TRIGGER_LINE(1))] = U(12),
+ [B(TRIGGER_LINE(2))] = U(13),
+ [B(TRIGGER_LINE(3))] = U(14),
+ [B(TRIGGER_LINE(4))] = U(15),
+ [B(TRIGGER_LINE(5))] = U(16),
+ [B(TRIGGER_LINE(6))] = U(17),
+ [B(NI_CtrGate(5))] = U(10),
+ [B(NI_20MHzTimebase)] = U(0),
+ [B(NI_80MHzTimebase)] = U(30),
+ [B(NI_100kHzTimebase)] = U(18),
+ [B(NI_LogicLow)] = U(31),
+ },
+ [B(NI_CtrSource(5))] = {
+ /* These are not currently implemented in ni modules */
+ [B(NI_PFI(11))] = U(9),
+ [B(NI_PFI(15))] = U(8),
+ [B(NI_PFI(19))] = U(7 /* or 1 */),
+ [B(NI_PFI(23))] = U(6),
+ [B(NI_PFI(27))] = U(5),
+ [B(NI_PFI(31))] = U(4),
+ [B(NI_PFI(35))] = U(3),
+ [B(NI_PFI(39))] = U(2),
+ [B(TRIGGER_LINE(0))] = U(11),
+ [B(TRIGGER_LINE(1))] = U(12),
+ [B(TRIGGER_LINE(2))] = U(13),
+ [B(TRIGGER_LINE(3))] = U(14),
+ [B(TRIGGER_LINE(4))] = U(15),
+ [B(TRIGGER_LINE(5))] = U(16),
+ [B(TRIGGER_LINE(6))] = U(17),
+ [B(NI_CtrGate(6))] = U(10),
+ [B(NI_20MHzTimebase)] = U(0),
+ [B(NI_80MHzTimebase)] = U(30),
+ [B(NI_100kHzTimebase)] = U(18),
+ [B(NI_LogicLow)] = U(31),
+ },
+ [B(NI_CtrSource(6))] = {
+ /* These are not currently implemented in ni modules */
+ [B(NI_PFI(11))] = U(9),
+ [B(NI_PFI(15))] = U(8 /* or 1 */),
+ [B(NI_PFI(19))] = U(7),
+ [B(NI_PFI(23))] = U(6),
+ [B(NI_PFI(27))] = U(5),
+ [B(NI_PFI(31))] = U(4),
+ [B(NI_PFI(35))] = U(3),
+ [B(NI_PFI(39))] = U(2),
+ [B(TRIGGER_LINE(0))] = U(11),
+ [B(TRIGGER_LINE(1))] = U(12),
+ [B(TRIGGER_LINE(2))] = U(13),
+ [B(TRIGGER_LINE(3))] = U(14),
+ [B(TRIGGER_LINE(4))] = U(15),
+ [B(TRIGGER_LINE(5))] = U(16),
+ [B(TRIGGER_LINE(6))] = U(17),
+ [B(NI_CtrGate(7))] = U(10),
+ [B(NI_20MHzTimebase)] = U(0),
+ [B(NI_80MHzTimebase)] = U(30),
+ [B(NI_100kHzTimebase)] = U(18),
+ [B(NI_LogicLow)] = U(31),
+ },
+ [B(NI_CtrSource(7))] = {
+ /* These are not currently implemented in ni modules */
+ [B(NI_PFI(11))] = U(9 /* or 1 */),
+ [B(NI_PFI(15))] = U(8),
+ [B(NI_PFI(19))] = U(7),
+ [B(NI_PFI(23))] = U(6),
+ [B(NI_PFI(27))] = U(5),
+ [B(NI_PFI(31))] = U(4),
+ [B(NI_PFI(35))] = U(3),
+ [B(NI_PFI(39))] = U(2),
+ [B(TRIGGER_LINE(0))] = U(11),
+ [B(TRIGGER_LINE(1))] = U(12),
+ [B(TRIGGER_LINE(2))] = U(13),
+ [B(TRIGGER_LINE(3))] = U(14),
+ [B(TRIGGER_LINE(4))] = U(15),
+ [B(TRIGGER_LINE(5))] = U(16),
+ [B(TRIGGER_LINE(6))] = U(17),
+ [B(NI_CtrGate(0))] = U(10),
+ [B(NI_20MHzTimebase)] = U(0),
+ [B(NI_80MHzTimebase)] = U(30),
+ [B(NI_100kHzTimebase)] = U(18),
+ [B(NI_LogicLow)] = U(31),
+ },
+ [B(NI_CtrGate(0))] = {
+ [B(NI_PFI(10))] = I(9),
+ [B(NI_PFI(14))] = I(8),
+ [B(NI_PFI(18))] = I(7),
+ [B(NI_PFI(22))] = I(6),
+ [B(NI_PFI(26))] = I(5),
+ [B(NI_PFI(30))] = I(4),
+ [B(NI_PFI(34))] = I(3),
+ [B(NI_PFI(38))] = I(2 /* or 1 */),
+ [B(NI_PFI(39))] = I(0),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(NI_CtrSource(1))] = I(10),
+ [B(NI_CtrInternalOutput(1))] = I(20),
+ [B(NI_LogicLow)] = I(31 /* or 30 */),
+ },
+ [B(NI_CtrGate(1))] = {
+ [B(NI_PFI(10))] = I(9),
+ [B(NI_PFI(14))] = I(8),
+ [B(NI_PFI(18))] = I(7),
+ [B(NI_PFI(22))] = I(6),
+ [B(NI_PFI(26))] = I(5),
+ [B(NI_PFI(30))] = I(4),
+ [B(NI_PFI(34))] = I(3 /* or 1 */),
+ [B(NI_PFI(35))] = I(0),
+ [B(NI_PFI(38))] = I(2),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(NI_CtrSource(2))] = I(10),
+ [B(NI_CtrInternalOutput(2))] = I(20),
+ [B(NI_LogicLow)] = I(31 /* or 30 */),
+ },
+ [B(NI_CtrGate(2))] = {
+ [B(NI_PFI(10))] = I(9),
+ [B(NI_PFI(14))] = I(8),
+ [B(NI_PFI(18))] = I(7),
+ [B(NI_PFI(22))] = I(6),
+ [B(NI_PFI(26))] = I(5),
+ [B(NI_PFI(30))] = I(4 /* or 1 */),
+ [B(NI_PFI(31))] = I(0),
+ [B(NI_PFI(34))] = I(3),
+ [B(NI_PFI(38))] = I(2),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(NI_CtrSource(3))] = I(10),
+ [B(NI_CtrInternalOutput(3))] = I(20),
+ [B(NI_LogicLow)] = I(31 /* or 30 */),
+ },
+ [B(NI_CtrGate(3))] = {
+ [B(NI_PFI(10))] = I(9),
+ [B(NI_PFI(14))] = I(8),
+ [B(NI_PFI(18))] = I(7),
+ [B(NI_PFI(22))] = I(6),
+ [B(NI_PFI(26))] = I(5 /* or 1 */),
+ [B(NI_PFI(27))] = I(0),
+ [B(NI_PFI(30))] = I(4),
+ [B(NI_PFI(34))] = I(3),
+ [B(NI_PFI(38))] = I(2),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(NI_CtrSource(4))] = I(10),
+ [B(NI_CtrInternalOutput(4))] = I(20),
+ [B(NI_LogicLow)] = I(31 /* or 30 */),
+ },
+ [B(NI_CtrGate(4))] = {
+ [B(NI_PFI(10))] = I(9),
+ [B(NI_PFI(14))] = I(8),
+ [B(NI_PFI(18))] = I(7),
+ [B(NI_PFI(22))] = I(6 /* or 1 */),
+ [B(NI_PFI(23))] = I(0),
+ [B(NI_PFI(26))] = I(5),
+ [B(NI_PFI(30))] = I(4),
+ [B(NI_PFI(34))] = I(3),
+ [B(NI_PFI(38))] = I(2),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(NI_CtrSource(5))] = I(10),
+ [B(NI_CtrInternalOutput(5))] = I(20),
+ [B(NI_LogicLow)] = I(31 /* or 30 */),
+ },
+ [B(NI_CtrGate(5))] = {
+ [B(NI_PFI(10))] = I(9),
+ [B(NI_PFI(14))] = I(8),
+ [B(NI_PFI(18))] = I(7 /* or 1 */),
+ [B(NI_PFI(19))] = I(0),
+ [B(NI_PFI(22))] = I(6),
+ [B(NI_PFI(26))] = I(5),
+ [B(NI_PFI(30))] = I(4),
+ [B(NI_PFI(34))] = I(3),
+ [B(NI_PFI(38))] = I(2),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(NI_CtrSource(6))] = I(10),
+ [B(NI_CtrInternalOutput(6))] = I(20),
+ [B(NI_LogicLow)] = I(31 /* or 30 */),
+ },
+ [B(NI_CtrGate(6))] = {
+ [B(NI_PFI(10))] = I(9),
+ [B(NI_PFI(14))] = I(8 /* or 1 */),
+ [B(NI_PFI(15))] = I(0),
+ [B(NI_PFI(18))] = I(7),
+ [B(NI_PFI(22))] = I(6),
+ [B(NI_PFI(26))] = I(5),
+ [B(NI_PFI(30))] = I(4),
+ [B(NI_PFI(34))] = I(3),
+ [B(NI_PFI(38))] = I(2),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(NI_CtrSource(7))] = I(10),
+ [B(NI_CtrInternalOutput(7))] = I(20),
+ [B(NI_LogicLow)] = I(31 /* or 30 */),
+ },
+ [B(NI_CtrGate(7))] = {
+ [B(NI_PFI(10))] = I(9 /* or 1 */),
+ [B(NI_PFI(11))] = I(0),
+ [B(NI_PFI(14))] = I(8),
+ [B(NI_PFI(18))] = I(7),
+ [B(NI_PFI(22))] = I(6),
+ [B(NI_PFI(26))] = I(5),
+ [B(NI_PFI(30))] = I(4),
+ [B(NI_PFI(34))] = I(3),
+ [B(NI_PFI(38))] = I(2),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(NI_CtrSource(0))] = I(10),
+ [B(NI_CtrInternalOutput(0))] = I(20),
+ [B(NI_LogicLow)] = I(31 /* or 30 */),
+ },
+ [B(NI_CtrAux(0))] = {
+ [B(NI_PFI(9))] = I(9),
+ [B(NI_PFI(13))] = I(8),
+ [B(NI_PFI(17))] = I(7),
+ [B(NI_PFI(21))] = I(6),
+ [B(NI_PFI(25))] = I(5),
+ [B(NI_PFI(29))] = I(4),
+ [B(NI_PFI(33))] = I(3),
+ [B(NI_PFI(37))] = I(2 /* or 1 */),
+ [B(NI_PFI(39))] = I(0),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(NI_CtrSource(1))] = I(10),
+ [B(NI_CtrGate(1))] = I(30),
+ [B(NI_CtrInternalOutput(1))] = I(20),
+ [B(NI_LogicLow)] = I(31),
+ },
+ [B(NI_CtrAux(1))] = {
+ [B(NI_PFI(9))] = I(9),
+ [B(NI_PFI(13))] = I(8),
+ [B(NI_PFI(17))] = I(7),
+ [B(NI_PFI(21))] = I(6),
+ [B(NI_PFI(25))] = I(5),
+ [B(NI_PFI(29))] = I(4),
+ [B(NI_PFI(33))] = I(3 /* or 1 */),
+ [B(NI_PFI(35))] = I(0),
+ [B(NI_PFI(37))] = I(2),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(NI_CtrSource(2))] = I(10),
+ [B(NI_CtrGate(2))] = I(30),
+ [B(NI_CtrInternalOutput(2))] = I(20),
+ [B(NI_LogicLow)] = I(31),
+ },
+ [B(NI_CtrAux(2))] = {
+ [B(NI_PFI(9))] = I(9),
+ [B(NI_PFI(13))] = I(8),
+ [B(NI_PFI(17))] = I(7),
+ [B(NI_PFI(21))] = I(6),
+ [B(NI_PFI(25))] = I(5),
+ [B(NI_PFI(29))] = I(4 /* or 1 */),
+ [B(NI_PFI(31))] = I(0),
+ [B(NI_PFI(33))] = I(3),
+ [B(NI_PFI(37))] = I(2),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(NI_CtrSource(3))] = I(10),
+ [B(NI_CtrGate(3))] = I(30),
+ [B(NI_CtrInternalOutput(3))] = I(20),
+ [B(NI_LogicLow)] = I(31),
+ },
+ [B(NI_CtrAux(3))] = {
+ [B(NI_PFI(9))] = I(9),
+ [B(NI_PFI(13))] = I(8),
+ [B(NI_PFI(17))] = I(7),
+ [B(NI_PFI(21))] = I(6),
+ [B(NI_PFI(25))] = I(5 /* or 1 */),
+ [B(NI_PFI(27))] = I(0),
+ [B(NI_PFI(29))] = I(4),
+ [B(NI_PFI(33))] = I(3),
+ [B(NI_PFI(37))] = I(2),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(NI_CtrSource(4))] = I(10),
+ [B(NI_CtrGate(4))] = I(30),
+ [B(NI_CtrInternalOutput(4))] = I(20),
+ [B(NI_LogicLow)] = I(31),
+ },
+ [B(NI_CtrAux(4))] = {
+ [B(NI_PFI(9))] = I(9),
+ [B(NI_PFI(13))] = I(8),
+ [B(NI_PFI(17))] = I(7),
+ [B(NI_PFI(21))] = I(6 /* or 1 */),
+ [B(NI_PFI(23))] = I(0),
+ [B(NI_PFI(25))] = I(5),
+ [B(NI_PFI(29))] = I(4),
+ [B(NI_PFI(33))] = I(3),
+ [B(NI_PFI(37))] = I(2),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(NI_CtrSource(5))] = I(10),
+ [B(NI_CtrGate(5))] = I(30),
+ [B(NI_CtrInternalOutput(5))] = I(20),
+ [B(NI_LogicLow)] = I(31),
+ },
+ [B(NI_CtrAux(5))] = {
+ [B(NI_PFI(9))] = I(9),
+ [B(NI_PFI(13))] = I(8),
+ [B(NI_PFI(17))] = I(7 /* or 1 */),
+ [B(NI_PFI(19))] = I(0),
+ [B(NI_PFI(21))] = I(6),
+ [B(NI_PFI(25))] = I(5),
+ [B(NI_PFI(29))] = I(4),
+ [B(NI_PFI(33))] = I(3),
+ [B(NI_PFI(37))] = I(2),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(NI_CtrSource(6))] = I(10),
+ [B(NI_CtrGate(6))] = I(30),
+ [B(NI_CtrInternalOutput(6))] = I(20),
+ [B(NI_LogicLow)] = I(31),
+ },
+ [B(NI_CtrAux(6))] = {
+ [B(NI_PFI(9))] = I(9),
+ [B(NI_PFI(13))] = I(8 /* or 1 */),
+ [B(NI_PFI(15))] = I(0),
+ [B(NI_PFI(17))] = I(7),
+ [B(NI_PFI(21))] = I(6),
+ [B(NI_PFI(25))] = I(5),
+ [B(NI_PFI(29))] = I(4),
+ [B(NI_PFI(33))] = I(3),
+ [B(NI_PFI(37))] = I(2),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(NI_CtrSource(7))] = I(10),
+ [B(NI_CtrGate(7))] = I(30),
+ [B(NI_CtrInternalOutput(7))] = I(20),
+ [B(NI_LogicLow)] = I(31),
+ },
+ [B(NI_CtrAux(7))] = {
+ [B(NI_PFI(9))] = I(9 /* or 1 */),
+ [B(NI_PFI(11))] = I(0),
+ [B(NI_PFI(13))] = I(8),
+ [B(NI_PFI(17))] = I(7),
+ [B(NI_PFI(21))] = I(6),
+ [B(NI_PFI(25))] = I(5),
+ [B(NI_PFI(29))] = I(4),
+ [B(NI_PFI(33))] = I(3),
+ [B(NI_PFI(37))] = I(2),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(NI_CtrSource(0))] = I(10),
+ [B(NI_CtrGate(0))] = I(30),
+ [B(NI_CtrInternalOutput(0))] = I(20),
+ [B(NI_LogicLow)] = I(31),
+ },
+ },
+};
diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_route_values/ni_eseries.c b/drivers/staging/comedi/drivers/ni_routing/ni_route_values/ni_eseries.c
new file mode 100644
index 000000000000..d1ab3c9ce585
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/ni_route_values/ni_eseries.c
@@ -0,0 +1,602 @@
+// 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * This file includes a list of all the values of various signals routes
+ * available on NI 660x hardware. In many cases, one does not explicitly make
+ * these routes, rather one might indicate that something is used as the source
+ * of one particular trigger or another (using *_src=TRIG_EXT).
+ *
+ * The contents of this file can be generated using the tools in
+ * comedi/drivers/ni_routing/tools. This file also contains specific notes to
+ * this family of devices.
+ *
+ * Please use those tools to help maintain the contents of this file, but be
+ * mindful to not lose the notes already made in this file, since these notes
+ * are critical to a complete undertsanding of the register values of this
+ * family.
+ */
+
+#include "../ni_route_values.h"
+#include "all.h"
+
+/*
+ * Note that for e-series devices, the backplane TRIGGER_LINE(6) is generally
+ * not connected to RTSI(6).
+ */
+
+const struct family_route_values ni_eseries_route_values = {
+ .family = "ni_eseries",
+ .register_values = {
+ /*
+ * destination = {
+ * source = register value,
+ * ...
+ * }
+ */
+ [B(NI_PFI(0))] = {
+ [B(NI_AI_StartTrigger)] = I(NI_PFI_OUTPUT_AI_START1),
+ },
+ [B(NI_PFI(1))] = {
+ [B(NI_AI_ReferenceTrigger)] = I(NI_PFI_OUTPUT_AI_START2),
+ },
+ [B(NI_PFI(2))] = {
+ [B(NI_AI_ConvertClock)] = I(NI_PFI_OUTPUT_AI_CONVERT),
+ },
+ [B(NI_PFI(3))] = {
+ [B(NI_CtrSource(1))] = I(NI_PFI_OUTPUT_G_SRC1),
+ },
+ [B(NI_PFI(4))] = {
+ [B(NI_CtrGate(1))] = I(NI_PFI_OUTPUT_G_GATE1),
+ },
+ [B(NI_PFI(5))] = {
+ [B(NI_AO_SampleClock)] = I(NI_PFI_OUTPUT_AO_UPDATE_N),
+ },
+ [B(NI_PFI(6))] = {
+ [B(NI_AO_StartTrigger)] = I(NI_PFI_OUTPUT_AO_START1),
+ },
+ [B(NI_PFI(7))] = {
+ [B(NI_AI_SampleClock)] = I(NI_PFI_OUTPUT_AI_START_PULSE),
+ },
+ [B(NI_PFI(8))] = {
+ [B(NI_CtrSource(0))] = I(NI_PFI_OUTPUT_G_SRC0),
+ },
+ [B(NI_PFI(9))] = {
+ [B(NI_CtrGate(0))] = I(NI_PFI_OUTPUT_G_GATE0),
+ },
+ [B(TRIGGER_LINE(0))] = {
+ [B(NI_RTSI_BRD(0))] = I(8),
+ [B(NI_RTSI_BRD(1))] = I(9),
+ [B(NI_RTSI_BRD(2))] = I(10),
+ [B(NI_RTSI_BRD(3))] = I(11),
+ [B(NI_CtrSource(0))] = I(5),
+ [B(NI_CtrGate(0))] = I(6),
+ [B(NI_AI_StartTrigger)] = I(0),
+ [B(NI_AI_ReferenceTrigger)] = I(1),
+ [B(NI_AI_ConvertClock)] = I(2),
+ [B(NI_AO_SampleClock)] = I(3),
+ [B(NI_AO_StartTrigger)] = I(4),
+ [B(NI_RGOUT0)] = I(7),
+ },
+ [B(TRIGGER_LINE(1))] = {
+ [B(NI_RTSI_BRD(0))] = I(8),
+ [B(NI_RTSI_BRD(1))] = I(9),
+ [B(NI_RTSI_BRD(2))] = I(10),
+ [B(NI_RTSI_BRD(3))] = I(11),
+ [B(NI_CtrSource(0))] = I(5),
+ [B(NI_CtrGate(0))] = I(6),
+ [B(NI_AI_StartTrigger)] = I(0),
+ [B(NI_AI_ReferenceTrigger)] = I(1),
+ [B(NI_AI_ConvertClock)] = I(2),
+ [B(NI_AO_SampleClock)] = I(3),
+ [B(NI_AO_StartTrigger)] = I(4),
+ [B(NI_RGOUT0)] = I(7),
+ },
+ [B(TRIGGER_LINE(2))] = {
+ [B(NI_RTSI_BRD(0))] = I(8),
+ [B(NI_RTSI_BRD(1))] = I(9),
+ [B(NI_RTSI_BRD(2))] = I(10),
+ [B(NI_RTSI_BRD(3))] = I(11),
+ [B(NI_CtrSource(0))] = I(5),
+ [B(NI_CtrGate(0))] = I(6),
+ [B(NI_AI_StartTrigger)] = I(0),
+ [B(NI_AI_ReferenceTrigger)] = I(1),
+ [B(NI_AI_ConvertClock)] = I(2),
+ [B(NI_AO_SampleClock)] = I(3),
+ [B(NI_AO_StartTrigger)] = I(4),
+ [B(NI_RGOUT0)] = I(7),
+ },
+ [B(TRIGGER_LINE(3))] = {
+ [B(NI_RTSI_BRD(0))] = I(8),
+ [B(NI_RTSI_BRD(1))] = I(9),
+ [B(NI_RTSI_BRD(2))] = I(10),
+ [B(NI_RTSI_BRD(3))] = I(11),
+ [B(NI_CtrSource(0))] = I(5),
+ [B(NI_CtrGate(0))] = I(6),
+ [B(NI_AI_StartTrigger)] = I(0),
+ [B(NI_AI_ReferenceTrigger)] = I(1),
+ [B(NI_AI_ConvertClock)] = I(2),
+ [B(NI_AO_SampleClock)] = I(3),
+ [B(NI_AO_StartTrigger)] = I(4),
+ [B(NI_RGOUT0)] = I(7),
+ },
+ [B(TRIGGER_LINE(4))] = {
+ [B(NI_RTSI_BRD(0))] = I(8),
+ [B(NI_RTSI_BRD(1))] = I(9),
+ [B(NI_RTSI_BRD(2))] = I(10),
+ [B(NI_RTSI_BRD(3))] = I(11),
+ [B(NI_CtrSource(0))] = I(5),
+ [B(NI_CtrGate(0))] = I(6),
+ [B(NI_AI_StartTrigger)] = I(0),
+ [B(NI_AI_ReferenceTrigger)] = I(1),
+ [B(NI_AI_ConvertClock)] = I(2),
+ [B(NI_AO_SampleClock)] = I(3),
+ [B(NI_AO_StartTrigger)] = I(4),
+ [B(NI_RGOUT0)] = I(7),
+ },
+ [B(TRIGGER_LINE(5))] = {
+ [B(NI_RTSI_BRD(0))] = I(8),
+ [B(NI_RTSI_BRD(1))] = I(9),
+ [B(NI_RTSI_BRD(2))] = I(10),
+ [B(NI_RTSI_BRD(3))] = I(11),
+ [B(NI_CtrSource(0))] = I(5),
+ [B(NI_CtrGate(0))] = I(6),
+ [B(NI_AI_StartTrigger)] = I(0),
+ [B(NI_AI_ReferenceTrigger)] = I(1),
+ [B(NI_AI_ConvertClock)] = I(2),
+ [B(NI_AO_SampleClock)] = I(3),
+ [B(NI_AO_StartTrigger)] = I(4),
+ [B(NI_RGOUT0)] = I(7),
+ },
+ [B(TRIGGER_LINE(6))] = {
+ [B(NI_RTSI_BRD(0))] = I(8),
+ [B(NI_RTSI_BRD(1))] = I(9),
+ [B(NI_RTSI_BRD(2))] = I(10),
+ [B(NI_RTSI_BRD(3))] = I(11),
+ [B(NI_CtrSource(0))] = I(5),
+ [B(NI_CtrGate(0))] = I(6),
+ [B(NI_AI_StartTrigger)] = I(0),
+ [B(NI_AI_ReferenceTrigger)] = I(1),
+ [B(NI_AI_ConvertClock)] = I(2),
+ [B(NI_AO_SampleClock)] = I(3),
+ [B(NI_AO_StartTrigger)] = I(4),
+ [B(NI_RGOUT0)] = I(7),
+ },
+ [B(TRIGGER_LINE(7))] = {
+ [B(NI_20MHzTimebase)] = I(NI_RTSI_OUTPUT_RTSI_OSC),
+ },
+ [B(NI_RTSI_BRD(0))] = {
+ [B(TRIGGER_LINE(0))] = I(0),
+ [B(TRIGGER_LINE(1))] = I(1),
+ [B(TRIGGER_LINE(2))] = I(2),
+ [B(TRIGGER_LINE(3))] = I(3),
+ [B(TRIGGER_LINE(4))] = I(4),
+ [B(TRIGGER_LINE(5))] = I(5),
+ [B(TRIGGER_LINE(6))] = I(6),
+ [B(PXI_Star)] = I(6),
+ [B(NI_AI_STOP)] = I(7),
+ },
+ [B(NI_RTSI_BRD(1))] = {
+ [B(TRIGGER_LINE(0))] = I(0),
+ [B(TRIGGER_LINE(1))] = I(1),
+ [B(TRIGGER_LINE(2))] = I(2),
+ [B(TRIGGER_LINE(3))] = I(3),
+ [B(TRIGGER_LINE(4))] = I(4),
+ [B(TRIGGER_LINE(5))] = I(5),
+ [B(TRIGGER_LINE(6))] = I(6),
+ [B(PXI_Star)] = I(6),
+ [B(NI_AI_STOP)] = I(7),
+ },
+ [B(NI_RTSI_BRD(2))] = {
+ [B(TRIGGER_LINE(0))] = I(0),
+ [B(TRIGGER_LINE(1))] = I(1),
+ [B(TRIGGER_LINE(2))] = I(2),
+ [B(TRIGGER_LINE(3))] = I(3),
+ [B(TRIGGER_LINE(4))] = I(4),
+ [B(TRIGGER_LINE(5))] = I(5),
+ [B(TRIGGER_LINE(6))] = I(6),
+ [B(PXI_Star)] = I(6),
+ [B(NI_AI_SampleClock)] = I(7),
+ },
+ [B(NI_RTSI_BRD(3))] = {
+ [B(TRIGGER_LINE(0))] = I(0),
+ [B(TRIGGER_LINE(1))] = I(1),
+ [B(TRIGGER_LINE(2))] = I(2),
+ [B(TRIGGER_LINE(3))] = I(3),
+ [B(TRIGGER_LINE(4))] = I(4),
+ [B(TRIGGER_LINE(5))] = I(5),
+ [B(TRIGGER_LINE(6))] = I(6),
+ [B(PXI_Star)] = I(6),
+ [B(NI_AI_SampleClock)] = I(7),
+ },
+ [B(NI_CtrSource(0))] = {
+ /* These are not currently implemented in ni modules */
+ [B(NI_PFI(0))] = U(1),
+ [B(NI_PFI(1))] = U(2),
+ [B(NI_PFI(2))] = U(3),
+ [B(NI_PFI(3))] = U(4),
+ [B(NI_PFI(4))] = U(5),
+ [B(NI_PFI(5))] = U(6),
+ [B(NI_PFI(6))] = U(7),
+ [B(NI_PFI(7))] = U(8),
+ [B(NI_PFI(8))] = U(9),
+ [B(NI_PFI(9))] = U(10),
+ [B(TRIGGER_LINE(0))] = U(11),
+ [B(TRIGGER_LINE(1))] = U(12),
+ [B(TRIGGER_LINE(2))] = U(13),
+ [B(TRIGGER_LINE(3))] = U(14),
+ [B(TRIGGER_LINE(4))] = U(15),
+ [B(TRIGGER_LINE(5))] = U(16),
+ [B(TRIGGER_LINE(6))] = U(17),
+ [B(NI_CtrInternalOutput(1))] = U(19),
+ [B(PXI_Star)] = U(17),
+ [B(NI_20MHzTimebase)] = U(0),
+ [B(NI_100kHzTimebase)] = U(18),
+ [B(NI_LogicLow)] = U(31),
+ },
+ [B(NI_CtrSource(1))] = {
+ /* These are not currently implemented in ni modules */
+ [B(NI_PFI(0))] = U(1),
+ [B(NI_PFI(1))] = U(2),
+ [B(NI_PFI(2))] = U(3),
+ [B(NI_PFI(3))] = U(4),
+ [B(NI_PFI(4))] = U(5),
+ [B(NI_PFI(5))] = U(6),
+ [B(NI_PFI(6))] = U(7),
+ [B(NI_PFI(7))] = U(8),
+ [B(NI_PFI(8))] = U(9),
+ [B(NI_PFI(9))] = U(10),
+ [B(TRIGGER_LINE(0))] = U(11),
+ [B(TRIGGER_LINE(1))] = U(12),
+ [B(TRIGGER_LINE(2))] = U(13),
+ [B(TRIGGER_LINE(3))] = U(14),
+ [B(TRIGGER_LINE(4))] = U(15),
+ [B(TRIGGER_LINE(5))] = U(16),
+ [B(TRIGGER_LINE(6))] = U(17),
+ [B(NI_CtrInternalOutput(0))] = U(19),
+ [B(PXI_Star)] = U(17),
+ [B(NI_20MHzTimebase)] = U(0),
+ [B(NI_100kHzTimebase)] = U(18),
+ [B(NI_LogicLow)] = U(31),
+ },
+ [B(NI_CtrGate(0))] = {
+ [B(NI_PFI(0))] = I(1),
+ [B(NI_PFI(1))] = I(2),
+ [B(NI_PFI(2))] = I(3),
+ [B(NI_PFI(3))] = I(4),
+ [B(NI_PFI(4))] = I(5),
+ [B(NI_PFI(5))] = I(6),
+ [B(NI_PFI(6))] = I(7),
+ [B(NI_PFI(7))] = I(8),
+ [B(NI_PFI(8))] = I(9),
+ [B(NI_PFI(9))] = I(10),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(NI_CtrInternalOutput(1))] = I(20),
+ [B(PXI_Star)] = I(17),
+ [B(NI_AI_StartTrigger)] = I(21),
+ [B(NI_AI_ReferenceTrigger)] = I(18),
+ [B(NI_LogicLow)] = I(31),
+ },
+ [B(NI_CtrGate(1))] = {
+ [B(NI_PFI(0))] = I(1),
+ [B(NI_PFI(1))] = I(2),
+ [B(NI_PFI(2))] = I(3),
+ [B(NI_PFI(3))] = I(4),
+ [B(NI_PFI(4))] = I(5),
+ [B(NI_PFI(5))] = I(6),
+ [B(NI_PFI(6))] = I(7),
+ [B(NI_PFI(7))] = I(8),
+ [B(NI_PFI(8))] = I(9),
+ [B(NI_PFI(9))] = I(10),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(NI_CtrInternalOutput(0))] = I(20),
+ [B(PXI_Star)] = I(17),
+ [B(NI_AI_StartTrigger)] = I(21),
+ [B(NI_AI_ReferenceTrigger)] = I(18),
+ [B(NI_LogicLow)] = I(31),
+ },
+ [B(NI_CtrOut(0))] = {
+ [B(TRIGGER_LINE(0))] = I(1),
+ [B(TRIGGER_LINE(1))] = I(2),
+ [B(TRIGGER_LINE(2))] = I(3),
+ [B(TRIGGER_LINE(3))] = I(4),
+ [B(TRIGGER_LINE(4))] = I(5),
+ [B(TRIGGER_LINE(5))] = I(6),
+ [B(TRIGGER_LINE(6))] = I(7),
+ [B(NI_CtrInternalOutput(0))] = I(0),
+ [B(PXI_Star)] = I(7),
+ },
+ [B(NI_CtrOut(1))] = {
+ [B(NI_CtrInternalOutput(1))] = I(0),
+ },
+ [B(NI_AI_SampleClock)] = {
+ [B(NI_PFI(0))] = I(1),
+ [B(NI_PFI(1))] = I(2),
+ [B(NI_PFI(2))] = I(3),
+ [B(NI_PFI(3))] = I(4),
+ [B(NI_PFI(4))] = I(5),
+ [B(NI_PFI(5))] = I(6),
+ [B(NI_PFI(6))] = I(7),
+ [B(NI_PFI(7))] = I(8),
+ [B(NI_PFI(8))] = I(9),
+ [B(NI_PFI(9))] = I(10),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(NI_CtrInternalOutput(0))] = I(19),
+ [B(PXI_Star)] = I(17),
+ [B(NI_AI_SampleClockTimebase)] = I(0),
+ [B(NI_LogicLow)] = I(31),
+ },
+ [B(NI_AI_SampleClockTimebase)] = {
+ /* These are not currently implemented in ni modules */
+ [B(NI_PFI(0))] = U(1),
+ [B(NI_PFI(1))] = U(2),
+ [B(NI_PFI(2))] = U(3),
+ [B(NI_PFI(3))] = U(4),
+ [B(NI_PFI(4))] = U(5),
+ [B(NI_PFI(5))] = U(6),
+ [B(NI_PFI(6))] = U(7),
+ [B(NI_PFI(7))] = U(8),
+ [B(NI_PFI(8))] = U(9),
+ [B(NI_PFI(9))] = U(10),
+ [B(TRIGGER_LINE(0))] = U(11),
+ [B(TRIGGER_LINE(1))] = U(12),
+ [B(TRIGGER_LINE(2))] = U(13),
+ [B(TRIGGER_LINE(3))] = U(14),
+ [B(TRIGGER_LINE(4))] = U(15),
+ [B(TRIGGER_LINE(5))] = U(16),
+ [B(TRIGGER_LINE(6))] = U(17),
+ [B(PXI_Star)] = U(17),
+ [B(NI_20MHzTimebase)] = U(0),
+ [B(NI_100kHzTimebase)] = U(19),
+ [B(NI_LogicLow)] = U(31),
+ },
+ [B(NI_AI_StartTrigger)] = {
+ [B(NI_PFI(0))] = I(1),
+ [B(NI_PFI(1))] = I(2),
+ [B(NI_PFI(2))] = I(3),
+ [B(NI_PFI(3))] = I(4),
+ [B(NI_PFI(4))] = I(5),
+ [B(NI_PFI(5))] = I(6),
+ [B(NI_PFI(6))] = I(7),
+ [B(NI_PFI(7))] = I(8),
+ [B(NI_PFI(8))] = I(9),
+ [B(NI_PFI(9))] = I(10),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(NI_CtrInternalOutput(0))] = I(18),
+ [B(PXI_Star)] = I(17),
+ [B(NI_LogicLow)] = I(31),
+ },
+ [B(NI_AI_ReferenceTrigger)] = {
+ /* These are not currently implemented in ni modules */
+ [B(NI_PFI(0))] = U(1),
+ [B(NI_PFI(1))] = U(2),
+ [B(NI_PFI(2))] = U(3),
+ [B(NI_PFI(3))] = U(4),
+ [B(NI_PFI(4))] = U(5),
+ [B(NI_PFI(5))] = U(6),
+ [B(NI_PFI(6))] = U(7),
+ [B(NI_PFI(7))] = U(8),
+ [B(NI_PFI(8))] = U(9),
+ [B(NI_PFI(9))] = U(10),
+ [B(TRIGGER_LINE(0))] = U(11),
+ [B(TRIGGER_LINE(1))] = U(12),
+ [B(TRIGGER_LINE(2))] = U(13),
+ [B(TRIGGER_LINE(3))] = U(14),
+ [B(TRIGGER_LINE(4))] = U(15),
+ [B(TRIGGER_LINE(5))] = U(16),
+ [B(TRIGGER_LINE(6))] = U(17),
+ [B(PXI_Star)] = U(17),
+ [B(NI_LogicLow)] = U(31),
+ },
+ [B(NI_AI_ConvertClock)] = {
+ [B(NI_PFI(0))] = I(1),
+ [B(NI_PFI(1))] = I(2),
+ [B(NI_PFI(2))] = I(3),
+ [B(NI_PFI(3))] = I(4),
+ [B(NI_PFI(4))] = I(5),
+ [B(NI_PFI(5))] = I(6),
+ [B(NI_PFI(6))] = I(7),
+ [B(NI_PFI(7))] = I(8),
+ [B(NI_PFI(8))] = I(9),
+ [B(NI_PFI(9))] = I(10),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(NI_CtrInternalOutput(0))] = I(19),
+ [B(PXI_Star)] = I(17),
+ [B(NI_AI_ConvertClockTimebase)] = I(0),
+ [B(NI_LogicLow)] = I(31),
+ },
+ [B(NI_AI_ConvertClockTimebase)] = {
+ /* These are not currently implemented in ni modules */
+ [B(NI_AI_SampleClockTimebase)] = U(0),
+ [B(NI_20MHzTimebase)] = U(1),
+ },
+ [B(NI_AI_PauseTrigger)] = {
+ /* These are not currently implemented in ni modules */
+ [B(NI_PFI(0))] = U(1),
+ [B(NI_PFI(1))] = U(2),
+ [B(NI_PFI(2))] = U(3),
+ [B(NI_PFI(3))] = U(4),
+ [B(NI_PFI(4))] = U(5),
+ [B(NI_PFI(5))] = U(6),
+ [B(NI_PFI(6))] = U(7),
+ [B(NI_PFI(7))] = U(8),
+ [B(NI_PFI(8))] = U(9),
+ [B(NI_PFI(9))] = U(10),
+ [B(TRIGGER_LINE(0))] = U(11),
+ [B(TRIGGER_LINE(1))] = U(12),
+ [B(TRIGGER_LINE(2))] = U(13),
+ [B(TRIGGER_LINE(3))] = U(14),
+ [B(TRIGGER_LINE(4))] = U(15),
+ [B(TRIGGER_LINE(5))] = U(16),
+ [B(TRIGGER_LINE(6))] = U(17),
+ [B(PXI_Star)] = U(17),
+ [B(NI_LogicLow)] = U(31),
+ },
+ [B(NI_AO_SampleClock)] = {
+ [B(NI_PFI(0))] = I(1),
+ [B(NI_PFI(1))] = I(2),
+ [B(NI_PFI(2))] = I(3),
+ [B(NI_PFI(3))] = I(4),
+ [B(NI_PFI(4))] = I(5),
+ [B(NI_PFI(5))] = I(6),
+ [B(NI_PFI(6))] = I(7),
+ [B(NI_PFI(7))] = I(8),
+ [B(NI_PFI(8))] = I(9),
+ [B(NI_PFI(9))] = I(10),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(NI_CtrInternalOutput(1))] = I(19),
+ [B(PXI_Star)] = I(17),
+ [B(NI_AO_SampleClockTimebase)] = I(0),
+ [B(NI_LogicLow)] = I(31),
+ },
+ [B(NI_AO_SampleClockTimebase)] = {
+ /* These are not currently implemented in ni modules */
+ [B(NI_PFI(0))] = U(1),
+ [B(NI_PFI(1))] = U(2),
+ [B(NI_PFI(2))] = U(3),
+ [B(NI_PFI(3))] = U(4),
+ [B(NI_PFI(4))] = U(5),
+ [B(NI_PFI(5))] = U(6),
+ [B(NI_PFI(6))] = U(7),
+ [B(NI_PFI(7))] = U(8),
+ [B(NI_PFI(8))] = U(9),
+ [B(NI_PFI(9))] = U(10),
+ [B(TRIGGER_LINE(0))] = U(11),
+ [B(TRIGGER_LINE(1))] = U(12),
+ [B(TRIGGER_LINE(2))] = U(13),
+ [B(TRIGGER_LINE(3))] = U(14),
+ [B(TRIGGER_LINE(4))] = U(15),
+ [B(TRIGGER_LINE(5))] = U(16),
+ [B(TRIGGER_LINE(6))] = U(17),
+ [B(PXI_Star)] = U(17),
+ [B(NI_20MHzTimebase)] = U(0),
+ [B(NI_100kHzTimebase)] = U(19),
+ [B(NI_LogicLow)] = U(31),
+ },
+ [B(NI_AO_StartTrigger)] = {
+ [B(NI_PFI(0))] = I(1),
+ [B(NI_PFI(1))] = I(2),
+ [B(NI_PFI(2))] = I(3),
+ [B(NI_PFI(3))] = I(4),
+ [B(NI_PFI(4))] = I(5),
+ [B(NI_PFI(5))] = I(6),
+ [B(NI_PFI(6))] = I(7),
+ [B(NI_PFI(7))] = I(8),
+ [B(NI_PFI(8))] = I(9),
+ [B(NI_PFI(9))] = I(10),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(PXI_Star)] = I(17),
+ /*
+ * for the signal route
+ * (NI_AI_StartTrigger->NI_AO_StartTrigger), MHDDK says
+ * used register value 18 and DAQ-STC says 19.
+ * Hoping that the MHDDK is correct--being a "working"
+ * example.
+ */
+ [B(NI_AI_StartTrigger)] = I(18),
+ [B(NI_LogicLow)] = I(31),
+ },
+ [B(NI_AO_PauseTrigger)] = {
+ /* These are not currently implemented in ni modules */
+ [B(NI_PFI(0))] = U(1),
+ [B(NI_PFI(1))] = U(2),
+ [B(NI_PFI(2))] = U(3),
+ [B(NI_PFI(3))] = U(4),
+ [B(NI_PFI(4))] = U(5),
+ [B(NI_PFI(5))] = U(6),
+ [B(NI_PFI(6))] = U(7),
+ [B(NI_PFI(7))] = U(8),
+ [B(NI_PFI(8))] = U(9),
+ [B(NI_PFI(9))] = U(10),
+ [B(TRIGGER_LINE(0))] = U(11),
+ [B(TRIGGER_LINE(1))] = U(12),
+ [B(TRIGGER_LINE(2))] = U(13),
+ [B(TRIGGER_LINE(3))] = U(14),
+ [B(TRIGGER_LINE(4))] = U(15),
+ [B(TRIGGER_LINE(5))] = U(16),
+ [B(TRIGGER_LINE(6))] = U(17),
+ [B(PXI_Star)] = U(17),
+ [B(NI_LogicLow)] = U(31),
+ },
+ [B(NI_MasterTimebase)] = {
+ /* These are not currently implemented in ni modules */
+ [B(TRIGGER_LINE(7))] = U(1),
+ [B(PXI_Star)] = U(2),
+ [B(PXI_Clk10)] = U(3),
+ [B(NI_10MHzRefClock)] = U(0),
+ },
+ /*
+ * This symbol is not defined and nothing for this is
+ * implemented--just including this because data was found in
+ * the NI-STC for it--can't remember where.
+ * [B(NI_FrequencyOutTimebase)] = {
+ * ** These are not currently implemented in ni modules **
+ * [B(NI_20MHzTimebase)] = U(0),
+ * [B(NI_100kHzTimebase)] = U(1),
+ * },
+ */
+ [B(NI_RGOUT0)] = {
+ [B(NI_CtrInternalOutput(0))] = I(0),
+ [B(NI_CtrOut(0))] = I(1),
+ },
+ },
+};
diff --git a/drivers/staging/comedi/drivers/ni_routing/ni_route_values/ni_mseries.c b/drivers/staging/comedi/drivers/ni_routing/ni_route_values/ni_mseries.c
new file mode 100644
index 000000000000..c59d8afe0ae9
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/ni_route_values/ni_mseries.c
@@ -0,0 +1,1752 @@
+// 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * This file includes a list of all the values of various signals routes
+ * available on NI 660x hardware. In many cases, one does not explicitly make
+ * these routes, rather one might indicate that something is used as the source
+ * of one particular trigger or another (using *_src=TRIG_EXT).
+ *
+ * The contents of this file can be generated using the tools in
+ * comedi/drivers/ni_routing/tools. This file also contains specific notes to
+ * this family of devices.
+ *
+ * Please use those tools to help maintain the contents of this file, but be
+ * mindful to not lose the notes already made in this file, since these notes
+ * are critical to a complete undertsanding of the register values of this
+ * family.
+ */
+
+#include "../ni_route_values.h"
+#include "all.h"
+
+/*
+ * GATE SELECT NOTE:
+ * CtrAux and CtrArmStartrigger register values are not documented in the
+ * DAQ-STC. There is some evidence that using CtrGate values is valid (see
+ * comedi.h). Some information and hints exist in the M-Series user manual
+ * (ni-62xx user-manual 371022K-01).
+ */
+
+const struct family_route_values ni_mseries_route_values = {
+ .family = "ni_mseries",
+ .register_values = {
+ /*
+ * destination = {
+ * source = register value,
+ * ...
+ * }
+ */
+ [B(NI_PFI(0))] = {
+ [B(TRIGGER_LINE(0))] = I(18),
+ [B(TRIGGER_LINE(1))] = I(19),
+ [B(TRIGGER_LINE(2))] = I(20),
+ [B(TRIGGER_LINE(3))] = I(21),
+ [B(TRIGGER_LINE(4))] = I(22),
+ [B(TRIGGER_LINE(5))] = I(23),
+ [B(TRIGGER_LINE(6))] = I(24),
+ [B(TRIGGER_LINE(7))] = I(25),
+ [B(NI_CtrSource(0))] = I(9),
+ [B(NI_CtrSource(1))] = I(4),
+ [B(NI_CtrGate(0))] = I(10),
+ [B(NI_CtrGate(1))] = I(5),
+ [B(NI_CtrInternalOutput(0))] = I(13),
+ [B(NI_CtrInternalOutput(1))] = I(14),
+ [B(PXI_Star)] = I(26),
+ [B(NI_AI_SampleClock)] = I(8),
+ [B(NI_AI_StartTrigger)] = I(1),
+ [B(NI_AI_ReferenceTrigger)] = I(2),
+ [B(NI_AI_ConvertClock)] = I(3),
+ [B(NI_AI_ExternalMUXClock)] = I(12),
+ [B(NI_AO_SampleClock)] = I(6),
+ [B(NI_AO_StartTrigger)] = I(7),
+ [B(NI_DI_SampleClock)] = I(29),
+ [B(NI_DO_SampleClock)] = I(30),
+ [B(NI_FrequencyOutput)] = I(15),
+ [B(NI_ChangeDetectionEvent)] = I(28),
+ [B(NI_AnalogComparisonEvent)] = I(17),
+ [B(NI_SCXI_Trig1)] = I(27),
+ [B(NI_ExternalStrobe)] = I(11),
+ [B(NI_PFI_DO)] = I(16),
+ },
+ [B(NI_PFI(1))] = {
+ [B(TRIGGER_LINE(0))] = I(18),
+ [B(TRIGGER_LINE(1))] = I(19),
+ [B(TRIGGER_LINE(2))] = I(20),
+ [B(TRIGGER_LINE(3))] = I(21),
+ [B(TRIGGER_LINE(4))] = I(22),
+ [B(TRIGGER_LINE(5))] = I(23),
+ [B(TRIGGER_LINE(6))] = I(24),
+ [B(TRIGGER_LINE(7))] = I(25),
+ [B(NI_CtrSource(0))] = I(9),
+ [B(NI_CtrSource(1))] = I(4),
+ [B(NI_CtrGate(0))] = I(10),
+ [B(NI_CtrGate(1))] = I(5),
+ [B(NI_CtrInternalOutput(0))] = I(13),
+ [B(NI_CtrInternalOutput(1))] = I(14),
+ [B(PXI_Star)] = I(26),
+ [B(NI_AI_SampleClock)] = I(8),
+ [B(NI_AI_StartTrigger)] = I(1),
+ [B(NI_AI_ReferenceTrigger)] = I(2),
+ [B(NI_AI_ConvertClock)] = I(3),
+ [B(NI_AI_ExternalMUXClock)] = I(12),
+ [B(NI_AO_SampleClock)] = I(6),
+ [B(NI_AO_StartTrigger)] = I(7),
+ [B(NI_DI_SampleClock)] = I(29),
+ [B(NI_DO_SampleClock)] = I(30),
+ [B(NI_FrequencyOutput)] = I(15),
+ [B(NI_ChangeDetectionEvent)] = I(28),
+ [B(NI_AnalogComparisonEvent)] = I(17),
+ [B(NI_SCXI_Trig1)] = I(27),
+ [B(NI_ExternalStrobe)] = I(11),
+ [B(NI_PFI_DO)] = I(16),
+ },
+ [B(NI_PFI(2))] = {
+ [B(TRIGGER_LINE(0))] = I(18),
+ [B(TRIGGER_LINE(1))] = I(19),
+ [B(TRIGGER_LINE(2))] = I(20),
+ [B(TRIGGER_LINE(3))] = I(21),
+ [B(TRIGGER_LINE(4))] = I(22),
+ [B(TRIGGER_LINE(5))] = I(23),
+ [B(TRIGGER_LINE(6))] = I(24),
+ [B(TRIGGER_LINE(7))] = I(25),
+ [B(NI_CtrSource(0))] = I(9),
+ [B(NI_CtrSource(1))] = I(4),
+ [B(NI_CtrGate(0))] = I(10),
+ [B(NI_CtrGate(1))] = I(5),
+ [B(NI_CtrInternalOutput(0))] = I(13),
+ [B(NI_CtrInternalOutput(1))] = I(14),
+ [B(PXI_Star)] = I(26),
+ [B(NI_AI_SampleClock)] = I(8),
+ [B(NI_AI_StartTrigger)] = I(1),
+ [B(NI_AI_ReferenceTrigger)] = I(2),
+ [B(NI_AI_ConvertClock)] = I(3),
+ [B(NI_AI_ExternalMUXClock)] = I(12),
+ [B(NI_AO_SampleClock)] = I(6),
+ [B(NI_AO_StartTrigger)] = I(7),
+ [B(NI_DI_SampleClock)] = I(29),
+ [B(NI_DO_SampleClock)] = I(30),
+ [B(NI_FrequencyOutput)] = I(15),
+ [B(NI_ChangeDetectionEvent)] = I(28),
+ [B(NI_AnalogComparisonEvent)] = I(17),
+ [B(NI_SCXI_Trig1)] = I(27),
+ [B(NI_ExternalStrobe)] = I(11),
+ [B(NI_PFI_DO)] = I(16),
+ },
+ [B(NI_PFI(3))] = {
+ [B(TRIGGER_LINE(0))] = I(18),
+ [B(TRIGGER_LINE(1))] = I(19),
+ [B(TRIGGER_LINE(2))] = I(20),
+ [B(TRIGGER_LINE(3))] = I(21),
+ [B(TRIGGER_LINE(4))] = I(22),
+ [B(TRIGGER_LINE(5))] = I(23),
+ [B(TRIGGER_LINE(6))] = I(24),
+ [B(TRIGGER_LINE(7))] = I(25),
+ [B(NI_CtrSource(0))] = I(9),
+ [B(NI_CtrSource(1))] = I(4),
+ [B(NI_CtrGate(0))] = I(10),
+ [B(NI_CtrGate(1))] = I(5),
+ [B(NI_CtrInternalOutput(0))] = I(13),
+ [B(NI_CtrInternalOutput(1))] = I(14),
+ [B(PXI_Star)] = I(26),
+ [B(NI_AI_SampleClock)] = I(8),
+ [B(NI_AI_StartTrigger)] = I(1),
+ [B(NI_AI_ReferenceTrigger)] = I(2),
+ [B(NI_AI_ConvertClock)] = I(3),
+ [B(NI_AI_ExternalMUXClock)] = I(12),
+ [B(NI_AO_SampleClock)] = I(6),
+ [B(NI_AO_StartTrigger)] = I(7),
+ [B(NI_DI_SampleClock)] = I(29),
+ [B(NI_DO_SampleClock)] = I(30),
+ [B(NI_FrequencyOutput)] = I(15),
+ [B(NI_ChangeDetectionEvent)] = I(28),
+ [B(NI_AnalogComparisonEvent)] = I(17),
+ [B(NI_SCXI_Trig1)] = I(27),
+ [B(NI_ExternalStrobe)] = I(11),
+ [B(NI_PFI_DO)] = I(16),
+ },
+ [B(NI_PFI(4))] = {
+ [B(TRIGGER_LINE(0))] = I(18),
+ [B(TRIGGER_LINE(1))] = I(19),
+ [B(TRIGGER_LINE(2))] = I(20),
+ [B(TRIGGER_LINE(3))] = I(21),
+ [B(TRIGGER_LINE(4))] = I(22),
+ [B(TRIGGER_LINE(5))] = I(23),
+ [B(TRIGGER_LINE(6))] = I(24),
+ [B(TRIGGER_LINE(7))] = I(25),
+ [B(NI_CtrSource(0))] = I(9),
+ [B(NI_CtrSource(1))] = I(4),
+ [B(NI_CtrGate(0))] = I(10),
+ [B(NI_CtrGate(1))] = I(5),
+ [B(NI_CtrInternalOutput(0))] = I(13),
+ [B(NI_CtrInternalOutput(1))] = I(14),
+ [B(PXI_Star)] = I(26),
+ [B(NI_AI_SampleClock)] = I(8),
+ [B(NI_AI_StartTrigger)] = I(1),
+ [B(NI_AI_ReferenceTrigger)] = I(2),
+ [B(NI_AI_ConvertClock)] = I(3),
+ [B(NI_AI_ExternalMUXClock)] = I(12),
+ [B(NI_AO_SampleClock)] = I(6),
+ [B(NI_AO_StartTrigger)] = I(7),
+ [B(NI_DI_SampleClock)] = I(29),
+ [B(NI_DO_SampleClock)] = I(30),
+ [B(NI_FrequencyOutput)] = I(15),
+ [B(NI_ChangeDetectionEvent)] = I(28),
+ [B(NI_AnalogComparisonEvent)] = I(17),
+ [B(NI_SCXI_Trig1)] = I(27),
+ [B(NI_ExternalStrobe)] = I(11),
+ [B(NI_PFI_DO)] = I(16),
+ },
+ [B(NI_PFI(5))] = {
+ [B(TRIGGER_LINE(0))] = I(18),
+ [B(TRIGGER_LINE(1))] = I(19),
+ [B(TRIGGER_LINE(2))] = I(20),
+ [B(TRIGGER_LINE(3))] = I(21),
+ [B(TRIGGER_LINE(4))] = I(22),
+ [B(TRIGGER_LINE(5))] = I(23),
+ [B(TRIGGER_LINE(6))] = I(24),
+ [B(TRIGGER_LINE(7))] = I(25),
+ [B(NI_CtrSource(0))] = I(9),
+ [B(NI_CtrSource(1))] = I(4),
+ [B(NI_CtrGate(0))] = I(10),
+ [B(NI_CtrGate(1))] = I(5),
+ [B(NI_CtrInternalOutput(0))] = I(13),
+ [B(NI_CtrInternalOutput(1))] = I(14),
+ [B(PXI_Star)] = I(26),
+ [B(NI_AI_SampleClock)] = I(8),
+ [B(NI_AI_StartTrigger)] = I(1),
+ [B(NI_AI_ReferenceTrigger)] = I(2),
+ [B(NI_AI_ConvertClock)] = I(3),
+ [B(NI_AI_ExternalMUXClock)] = I(12),
+ [B(NI_AO_SampleClock)] = I(6),
+ [B(NI_AO_StartTrigger)] = I(7),
+ [B(NI_DI_SampleClock)] = I(29),
+ [B(NI_DO_SampleClock)] = I(30),
+ [B(NI_FrequencyOutput)] = I(15),
+ [B(NI_ChangeDetectionEvent)] = I(28),
+ [B(NI_AnalogComparisonEvent)] = I(17),
+ [B(NI_SCXI_Trig1)] = I(27),
+ [B(NI_ExternalStrobe)] = I(11),
+ [B(NI_PFI_DO)] = I(16),
+ },
+ [B(NI_PFI(6))] = {
+ [B(TRIGGER_LINE(0))] = I(18),
+ [B(TRIGGER_LINE(1))] = I(19),
+ [B(TRIGGER_LINE(2))] = I(20),
+ [B(TRIGGER_LINE(3))] = I(21),
+ [B(TRIGGER_LINE(4))] = I(22),
+ [B(TRIGGER_LINE(5))] = I(23),
+ [B(TRIGGER_LINE(6))] = I(24),
+ [B(TRIGGER_LINE(7))] = I(25),
+ [B(NI_CtrSource(0))] = I(9),
+ [B(NI_CtrSource(1))] = I(4),
+ [B(NI_CtrGate(0))] = I(10),
+ [B(NI_CtrGate(1))] = I(5),
+ [B(NI_CtrInternalOutput(0))] = I(13),
+ [B(NI_CtrInternalOutput(1))] = I(14),
+ [B(PXI_Star)] = I(26),
+ [B(NI_AI_SampleClock)] = I(8),
+ [B(NI_AI_StartTrigger)] = I(1),
+ [B(NI_AI_ReferenceTrigger)] = I(2),
+ [B(NI_AI_ConvertClock)] = I(3),
+ [B(NI_AI_ExternalMUXClock)] = I(12),
+ [B(NI_AO_SampleClock)] = I(6),
+ [B(NI_AO_StartTrigger)] = I(7),
+ [B(NI_DI_SampleClock)] = I(29),
+ [B(NI_DO_SampleClock)] = I(30),
+ [B(NI_FrequencyOutput)] = I(15),
+ [B(NI_ChangeDetectionEvent)] = I(28),
+ [B(NI_AnalogComparisonEvent)] = I(17),
+ [B(NI_SCXI_Trig1)] = I(27),
+ [B(NI_ExternalStrobe)] = I(11),
+ [B(NI_PFI_DO)] = I(16),
+ },
+ [B(NI_PFI(7))] = {
+ [B(TRIGGER_LINE(0))] = I(18),
+ [B(TRIGGER_LINE(1))] = I(19),
+ [B(TRIGGER_LINE(2))] = I(20),
+ [B(TRIGGER_LINE(3))] = I(21),
+ [B(TRIGGER_LINE(4))] = I(22),
+ [B(TRIGGER_LINE(5))] = I(23),
+ [B(TRIGGER_LINE(6))] = I(24),
+ [B(TRIGGER_LINE(7))] = I(25),
+ [B(NI_CtrSource(0))] = I(9),
+ [B(NI_CtrSource(1))] = I(4),
+ [B(NI_CtrGate(0))] = I(10),
+ [B(NI_CtrGate(1))] = I(5),
+ [B(NI_CtrInternalOutput(0))] = I(13),
+ [B(NI_CtrInternalOutput(1))] = I(14),
+ [B(PXI_Star)] = I(26),
+ [B(NI_AI_SampleClock)] = I(8),
+ [B(NI_AI_StartTrigger)] = I(1),
+ [B(NI_AI_ReferenceTrigger)] = I(2),
+ [B(NI_AI_ConvertClock)] = I(3),
+ [B(NI_AI_ExternalMUXClock)] = I(12),
+ [B(NI_AO_SampleClock)] = I(6),
+ [B(NI_AO_StartTrigger)] = I(7),
+ [B(NI_DI_SampleClock)] = I(29),
+ [B(NI_DO_SampleClock)] = I(30),
+ [B(NI_FrequencyOutput)] = I(15),
+ [B(NI_ChangeDetectionEvent)] = I(28),
+ [B(NI_AnalogComparisonEvent)] = I(17),
+ [B(NI_SCXI_Trig1)] = I(27),
+ [B(NI_ExternalStrobe)] = I(11),
+ [B(NI_PFI_DO)] = I(16),
+ },
+ [B(NI_PFI(8))] = {
+ [B(TRIGGER_LINE(0))] = I(18),
+ [B(TRIGGER_LINE(1))] = I(19),
+ [B(TRIGGER_LINE(2))] = I(20),
+ [B(TRIGGER_LINE(3))] = I(21),
+ [B(TRIGGER_LINE(4))] = I(22),
+ [B(TRIGGER_LINE(5))] = I(23),
+ [B(TRIGGER_LINE(6))] = I(24),
+ [B(TRIGGER_LINE(7))] = I(25),
+ [B(NI_CtrSource(0))] = I(9),
+ [B(NI_CtrSource(1))] = I(4),
+ [B(NI_CtrGate(0))] = I(10),
+ [B(NI_CtrGate(1))] = I(5),
+ [B(NI_CtrInternalOutput(0))] = I(13),
+ [B(NI_CtrInternalOutput(1))] = I(14),
+ [B(PXI_Star)] = I(26),
+ [B(NI_AI_SampleClock)] = I(8),
+ [B(NI_AI_StartTrigger)] = I(1),
+ [B(NI_AI_ReferenceTrigger)] = I(2),
+ [B(NI_AI_ConvertClock)] = I(3),
+ [B(NI_AI_ExternalMUXClock)] = I(12),
+ [B(NI_AO_SampleClock)] = I(6),
+ [B(NI_AO_StartTrigger)] = I(7),
+ [B(NI_DI_SampleClock)] = I(29),
+ [B(NI_DO_SampleClock)] = I(30),
+ [B(NI_FrequencyOutput)] = I(15),
+ [B(NI_ChangeDetectionEvent)] = I(28),
+ [B(NI_AnalogComparisonEvent)] = I(17),
+ [B(NI_SCXI_Trig1)] = I(27),
+ [B(NI_ExternalStrobe)] = I(11),
+ [B(NI_PFI_DO)] = I(16),
+ },
+ [B(NI_PFI(9))] = {
+ [B(TRIGGER_LINE(0))] = I(18),
+ [B(TRIGGER_LINE(1))] = I(19),
+ [B(TRIGGER_LINE(2))] = I(20),
+ [B(TRIGGER_LINE(3))] = I(21),
+ [B(TRIGGER_LINE(4))] = I(22),
+ [B(TRIGGER_LINE(5))] = I(23),
+ [B(TRIGGER_LINE(6))] = I(24),
+ [B(TRIGGER_LINE(7))] = I(25),
+ [B(NI_CtrSource(0))] = I(9),
+ [B(NI_CtrSource(1))] = I(4),
+ [B(NI_CtrGate(0))] = I(10),
+ [B(NI_CtrGate(1))] = I(5),
+ [B(NI_CtrInternalOutput(0))] = I(13),
+ [B(NI_CtrInternalOutput(1))] = I(14),
+ [B(PXI_Star)] = I(26),
+ [B(NI_AI_SampleClock)] = I(8),
+ [B(NI_AI_StartTrigger)] = I(1),
+ [B(NI_AI_ReferenceTrigger)] = I(2),
+ [B(NI_AI_ConvertClock)] = I(3),
+ [B(NI_AI_ExternalMUXClock)] = I(12),
+ [B(NI_AO_SampleClock)] = I(6),
+ [B(NI_AO_StartTrigger)] = I(7),
+ [B(NI_DI_SampleClock)] = I(29),
+ [B(NI_DO_SampleClock)] = I(30),
+ [B(NI_FrequencyOutput)] = I(15),
+ [B(NI_ChangeDetectionEvent)] = I(28),
+ [B(NI_AnalogComparisonEvent)] = I(17),
+ [B(NI_SCXI_Trig1)] = I(27),
+ [B(NI_ExternalStrobe)] = I(11),
+ [B(NI_PFI_DO)] = I(16),
+ },
+ [B(NI_PFI(10))] = {
+ [B(TRIGGER_LINE(0))] = I(18),
+ [B(TRIGGER_LINE(1))] = I(19),
+ [B(TRIGGER_LINE(2))] = I(20),
+ [B(TRIGGER_LINE(3))] = I(21),
+ [B(TRIGGER_LINE(4))] = I(22),
+ [B(TRIGGER_LINE(5))] = I(23),
+ [B(TRIGGER_LINE(6))] = I(24),
+ [B(TRIGGER_LINE(7))] = I(25),
+ [B(NI_CtrSource(0))] = I(9),
+ [B(NI_CtrSource(1))] = I(4),
+ [B(NI_CtrGate(0))] = I(10),
+ [B(NI_CtrGate(1))] = I(5),
+ [B(NI_CtrInternalOutput(0))] = I(13),
+ [B(NI_CtrInternalOutput(1))] = I(14),
+ [B(PXI_Star)] = I(26),
+ [B(NI_AI_SampleClock)] = I(8),
+ [B(NI_AI_StartTrigger)] = I(1),
+ [B(NI_AI_ReferenceTrigger)] = I(2),
+ [B(NI_AI_ConvertClock)] = I(3),
+ [B(NI_AI_ExternalMUXClock)] = I(12),
+ [B(NI_AO_SampleClock)] = I(6),
+ [B(NI_AO_StartTrigger)] = I(7),
+ [B(NI_DI_SampleClock)] = I(29),
+ [B(NI_DO_SampleClock)] = I(30),
+ [B(NI_FrequencyOutput)] = I(15),
+ [B(NI_ChangeDetectionEvent)] = I(28),
+ [B(NI_AnalogComparisonEvent)] = I(17),
+ [B(NI_SCXI_Trig1)] = I(27),
+ [B(NI_ExternalStrobe)] = I(11),
+ [B(NI_PFI_DO)] = I(16),
+ },
+ [B(NI_PFI(11))] = {
+ [B(TRIGGER_LINE(0))] = I(18),
+ [B(TRIGGER_LINE(1))] = I(19),
+ [B(TRIGGER_LINE(2))] = I(20),
+ [B(TRIGGER_LINE(3))] = I(21),
+ [B(TRIGGER_LINE(4))] = I(22),
+ [B(TRIGGER_LINE(5))] = I(23),
+ [B(TRIGGER_LINE(6))] = I(24),
+ [B(TRIGGER_LINE(7))] = I(25),
+ [B(NI_CtrSource(0))] = I(9),
+ [B(NI_CtrSource(1))] = I(4),
+ [B(NI_CtrGate(0))] = I(10),
+ [B(NI_CtrGate(1))] = I(5),
+ [B(NI_CtrInternalOutput(0))] = I(13),
+ [B(NI_CtrInternalOutput(1))] = I(14),
+ [B(PXI_Star)] = I(26),
+ [B(NI_AI_SampleClock)] = I(8),
+ [B(NI_AI_StartTrigger)] = I(1),
+ [B(NI_AI_ReferenceTrigger)] = I(2),
+ [B(NI_AI_ConvertClock)] = I(3),
+ [B(NI_AI_ExternalMUXClock)] = I(12),
+ [B(NI_AO_SampleClock)] = I(6),
+ [B(NI_AO_StartTrigger)] = I(7),
+ [B(NI_DI_SampleClock)] = I(29),
+ [B(NI_DO_SampleClock)] = I(30),
+ [B(NI_FrequencyOutput)] = I(15),
+ [B(NI_ChangeDetectionEvent)] = I(28),
+ [B(NI_AnalogComparisonEvent)] = I(17),
+ [B(NI_SCXI_Trig1)] = I(27),
+ [B(NI_ExternalStrobe)] = I(11),
+ [B(NI_PFI_DO)] = I(16),
+ },
+ [B(NI_PFI(12))] = {
+ [B(TRIGGER_LINE(0))] = I(18),
+ [B(TRIGGER_LINE(1))] = I(19),
+ [B(TRIGGER_LINE(2))] = I(20),
+ [B(TRIGGER_LINE(3))] = I(21),
+ [B(TRIGGER_LINE(4))] = I(22),
+ [B(TRIGGER_LINE(5))] = I(23),
+ [B(TRIGGER_LINE(6))] = I(24),
+ [B(TRIGGER_LINE(7))] = I(25),
+ [B(NI_CtrSource(0))] = I(9),
+ [B(NI_CtrSource(1))] = I(4),
+ [B(NI_CtrGate(0))] = I(10),
+ [B(NI_CtrGate(1))] = I(5),
+ [B(NI_CtrInternalOutput(0))] = I(13),
+ [B(NI_CtrInternalOutput(1))] = I(14),
+ [B(PXI_Star)] = I(26),
+ [B(NI_AI_SampleClock)] = I(8),
+ [B(NI_AI_StartTrigger)] = I(1),
+ [B(NI_AI_ReferenceTrigger)] = I(2),
+ [B(NI_AI_ConvertClock)] = I(3),
+ [B(NI_AI_ExternalMUXClock)] = I(12),
+ [B(NI_AO_SampleClock)] = I(6),
+ [B(NI_AO_StartTrigger)] = I(7),
+ [B(NI_DI_SampleClock)] = I(29),
+ [B(NI_DO_SampleClock)] = I(30),
+ [B(NI_FrequencyOutput)] = I(15),
+ [B(NI_ChangeDetectionEvent)] = I(28),
+ [B(NI_AnalogComparisonEvent)] = I(17),
+ [B(NI_SCXI_Trig1)] = I(27),
+ [B(NI_ExternalStrobe)] = I(11),
+ [B(NI_PFI_DO)] = I(16),
+ },
+ [B(NI_PFI(13))] = {
+ [B(TRIGGER_LINE(0))] = I(18),
+ [B(TRIGGER_LINE(1))] = I(19),
+ [B(TRIGGER_LINE(2))] = I(20),
+ [B(TRIGGER_LINE(3))] = I(21),
+ [B(TRIGGER_LINE(4))] = I(22),
+ [B(TRIGGER_LINE(5))] = I(23),
+ [B(TRIGGER_LINE(6))] = I(24),
+ [B(TRIGGER_LINE(7))] = I(25),
+ [B(NI_CtrSource(0))] = I(9),
+ [B(NI_CtrSource(1))] = I(4),
+ [B(NI_CtrGate(0))] = I(10),
+ [B(NI_CtrGate(1))] = I(5),
+ [B(NI_CtrInternalOutput(0))] = I(13),
+ [B(NI_CtrInternalOutput(1))] = I(14),
+ [B(PXI_Star)] = I(26),
+ [B(NI_AI_SampleClock)] = I(8),
+ [B(NI_AI_StartTrigger)] = I(1),
+ [B(NI_AI_ReferenceTrigger)] = I(2),
+ [B(NI_AI_ConvertClock)] = I(3),
+ [B(NI_AI_ExternalMUXClock)] = I(12),
+ [B(NI_AO_SampleClock)] = I(6),
+ [B(NI_AO_StartTrigger)] = I(7),
+ [B(NI_DI_SampleClock)] = I(29),
+ [B(NI_DO_SampleClock)] = I(30),
+ [B(NI_FrequencyOutput)] = I(15),
+ [B(NI_ChangeDetectionEvent)] = I(28),
+ [B(NI_AnalogComparisonEvent)] = I(17),
+ [B(NI_SCXI_Trig1)] = I(27),
+ [B(NI_ExternalStrobe)] = I(11),
+ [B(NI_PFI_DO)] = I(16),
+ },
+ [B(NI_PFI(14))] = {
+ [B(TRIGGER_LINE(0))] = I(18),
+ [B(TRIGGER_LINE(1))] = I(19),
+ [B(TRIGGER_LINE(2))] = I(20),
+ [B(TRIGGER_LINE(3))] = I(21),
+ [B(TRIGGER_LINE(4))] = I(22),
+ [B(TRIGGER_LINE(5))] = I(23),
+ [B(TRIGGER_LINE(6))] = I(24),
+ [B(TRIGGER_LINE(7))] = I(25),
+ [B(NI_CtrSource(0))] = I(9),
+ [B(NI_CtrSource(1))] = I(4),
+ [B(NI_CtrGate(0))] = I(10),
+ [B(NI_CtrGate(1))] = I(5),
+ [B(NI_CtrInternalOutput(0))] = I(13),
+ [B(NI_CtrInternalOutput(1))] = I(14),
+ [B(PXI_Star)] = I(26),
+ [B(NI_AI_SampleClock)] = I(8),
+ [B(NI_AI_StartTrigger)] = I(1),
+ [B(NI_AI_ReferenceTrigger)] = I(2),
+ [B(NI_AI_ConvertClock)] = I(3),
+ [B(NI_AI_ExternalMUXClock)] = I(12),
+ [B(NI_AO_SampleClock)] = I(6),
+ [B(NI_AO_StartTrigger)] = I(7),
+ [B(NI_DI_SampleClock)] = I(29),
+ [B(NI_DO_SampleClock)] = I(30),
+ [B(NI_FrequencyOutput)] = I(15),
+ [B(NI_ChangeDetectionEvent)] = I(28),
+ [B(NI_AnalogComparisonEvent)] = I(17),
+ [B(NI_SCXI_Trig1)] = I(27),
+ [B(NI_ExternalStrobe)] = I(11),
+ [B(NI_PFI_DO)] = I(16),
+ },
+ [B(NI_PFI(15))] = {
+ [B(TRIGGER_LINE(0))] = I(18),
+ [B(TRIGGER_LINE(1))] = I(19),
+ [B(TRIGGER_LINE(2))] = I(20),
+ [B(TRIGGER_LINE(3))] = I(21),
+ [B(TRIGGER_LINE(4))] = I(22),
+ [B(TRIGGER_LINE(5))] = I(23),
+ [B(TRIGGER_LINE(6))] = I(24),
+ [B(TRIGGER_LINE(7))] = I(25),
+ [B(NI_CtrSource(0))] = I(9),
+ [B(NI_CtrSource(1))] = I(4),
+ [B(NI_CtrGate(0))] = I(10),
+ [B(NI_CtrGate(1))] = I(5),
+ [B(NI_CtrInternalOutput(0))] = I(13),
+ [B(NI_CtrInternalOutput(1))] = I(14),
+ [B(PXI_Star)] = I(26),
+ [B(NI_AI_SampleClock)] = I(8),
+ [B(NI_AI_StartTrigger)] = I(1),
+ [B(NI_AI_ReferenceTrigger)] = I(2),
+ [B(NI_AI_ConvertClock)] = I(3),
+ [B(NI_AI_ExternalMUXClock)] = I(12),
+ [B(NI_AO_SampleClock)] = I(6),
+ [B(NI_AO_StartTrigger)] = I(7),
+ [B(NI_DI_SampleClock)] = I(29),
+ [B(NI_DO_SampleClock)] = I(30),
+ [B(NI_FrequencyOutput)] = I(15),
+ [B(NI_ChangeDetectionEvent)] = I(28),
+ [B(NI_AnalogComparisonEvent)] = I(17),
+ [B(NI_SCXI_Trig1)] = I(27),
+ [B(NI_ExternalStrobe)] = I(11),
+ [B(NI_PFI_DO)] = I(16),
+ },
+ [B(TRIGGER_LINE(0))] = {
+ [B(NI_RTSI_BRD(0))] = I(8),
+ [B(NI_RTSI_BRD(1))] = I(9),
+ [B(NI_RTSI_BRD(2))] = I(10),
+ [B(NI_RTSI_BRD(3))] = I(11),
+ [B(NI_CtrSource(0))] = I(5),
+ [B(NI_CtrGate(0))] = I(6),
+ [B(NI_AI_StartTrigger)] = I(0),
+ [B(NI_AI_ReferenceTrigger)] = I(1),
+ [B(NI_AI_ConvertClock)] = I(2),
+ [B(NI_AO_SampleClock)] = I(3),
+ [B(NI_AO_StartTrigger)] = I(4),
+ /*
+ * for (*->TRIGGER_LINE(*)) MUX, a value of 12 should be
+ * RTSI_OSC according to MHDDK mseries source. There
+ * are hints in comedi that show that this is actually a
+ * 20MHz source for 628x cards(?)
+ */
+ [B(NI_10MHzRefClock)] = I(12),
+ [B(NI_RGOUT0)] = I(7),
+ },
+ [B(TRIGGER_LINE(1))] = {
+ [B(NI_RTSI_BRD(0))] = I(8),
+ [B(NI_RTSI_BRD(1))] = I(9),
+ [B(NI_RTSI_BRD(2))] = I(10),
+ [B(NI_RTSI_BRD(3))] = I(11),
+ [B(NI_CtrSource(0))] = I(5),
+ [B(NI_CtrGate(0))] = I(6),
+ [B(NI_AI_StartTrigger)] = I(0),
+ [B(NI_AI_ReferenceTrigger)] = I(1),
+ [B(NI_AI_ConvertClock)] = I(2),
+ [B(NI_AO_SampleClock)] = I(3),
+ [B(NI_AO_StartTrigger)] = I(4),
+ /*
+ * for (*->TRIGGER_LINE(*)) MUX, a value of 12 should be
+ * RTSI_OSC according to MHDDK mseries source. There
+ * are hints in comedi that show that this is actually a
+ * 20MHz source for 628x cards(?)
+ */
+ [B(NI_10MHzRefClock)] = I(12),
+ [B(NI_RGOUT0)] = I(7),
+ },
+ [B(TRIGGER_LINE(2))] = {
+ [B(NI_RTSI_BRD(0))] = I(8),
+ [B(NI_RTSI_BRD(1))] = I(9),
+ [B(NI_RTSI_BRD(2))] = I(10),
+ [B(NI_RTSI_BRD(3))] = I(11),
+ [B(NI_CtrSource(0))] = I(5),
+ [B(NI_CtrGate(0))] = I(6),
+ [B(NI_AI_StartTrigger)] = I(0),
+ [B(NI_AI_ReferenceTrigger)] = I(1),
+ [B(NI_AI_ConvertClock)] = I(2),
+ [B(NI_AO_SampleClock)] = I(3),
+ [B(NI_AO_StartTrigger)] = I(4),
+ /*
+ * for (*->TRIGGER_LINE(*)) MUX, a value of 12 should be
+ * RTSI_OSC according to MHDDK mseries source. There
+ * are hints in comedi that show that this is actually a
+ * 20MHz source for 628x cards(?)
+ */
+ [B(NI_10MHzRefClock)] = I(12),
+ [B(NI_RGOUT0)] = I(7),
+ },
+ [B(TRIGGER_LINE(3))] = {
+ [B(NI_RTSI_BRD(0))] = I(8),
+ [B(NI_RTSI_BRD(1))] = I(9),
+ [B(NI_RTSI_BRD(2))] = I(10),
+ [B(NI_RTSI_BRD(3))] = I(11),
+ [B(NI_CtrSource(0))] = I(5),
+ [B(NI_CtrGate(0))] = I(6),
+ [B(NI_AI_StartTrigger)] = I(0),
+ [B(NI_AI_ReferenceTrigger)] = I(1),
+ [B(NI_AI_ConvertClock)] = I(2),
+ [B(NI_AO_SampleClock)] = I(3),
+ [B(NI_AO_StartTrigger)] = I(4),
+ /*
+ * for (*->TRIGGER_LINE(*)) MUX, a value of 12 should be
+ * RTSI_OSC according to MHDDK mseries source. There
+ * are hints in comedi that show that this is actually a
+ * 20MHz source for 628x cards(?)
+ */
+ [B(NI_10MHzRefClock)] = I(12),
+ [B(NI_RGOUT0)] = I(7),
+ },
+ [B(TRIGGER_LINE(4))] = {
+ [B(NI_RTSI_BRD(0))] = I(8),
+ [B(NI_RTSI_BRD(1))] = I(9),
+ [B(NI_RTSI_BRD(2))] = I(10),
+ [B(NI_RTSI_BRD(3))] = I(11),
+ [B(NI_CtrSource(0))] = I(5),
+ [B(NI_CtrGate(0))] = I(6),
+ [B(NI_AI_StartTrigger)] = I(0),
+ [B(NI_AI_ReferenceTrigger)] = I(1),
+ [B(NI_AI_ConvertClock)] = I(2),
+ [B(NI_AO_SampleClock)] = I(3),
+ [B(NI_AO_StartTrigger)] = I(4),
+ /*
+ * for (*->TRIGGER_LINE(*)) MUX, a value of 12 should be
+ * RTSI_OSC according to MHDDK mseries source. There
+ * are hints in comedi that show that this is actually a
+ * 20MHz source for 628x cards(?)
+ */
+ [B(NI_10MHzRefClock)] = I(12),
+ [B(NI_RGOUT0)] = I(7),
+ },
+ [B(TRIGGER_LINE(5))] = {
+ [B(NI_RTSI_BRD(0))] = I(8),
+ [B(NI_RTSI_BRD(1))] = I(9),
+ [B(NI_RTSI_BRD(2))] = I(10),
+ [B(NI_RTSI_BRD(3))] = I(11),
+ [B(NI_CtrSource(0))] = I(5),
+ [B(NI_CtrGate(0))] = I(6),
+ [B(NI_AI_StartTrigger)] = I(0),
+ [B(NI_AI_ReferenceTrigger)] = I(1),
+ [B(NI_AI_ConvertClock)] = I(2),
+ [B(NI_AO_SampleClock)] = I(3),
+ [B(NI_AO_StartTrigger)] = I(4),
+ /*
+ * for (*->TRIGGER_LINE(*)) MUX, a value of 12 should be
+ * RTSI_OSC according to MHDDK mseries source. There
+ * are hints in comedi that show that this is actually a
+ * 20MHz source for 628x cards(?)
+ */
+ [B(NI_10MHzRefClock)] = I(12),
+ [B(NI_RGOUT0)] = I(7),
+ },
+ [B(TRIGGER_LINE(6))] = {
+ [B(NI_RTSI_BRD(0))] = I(8),
+ [B(NI_RTSI_BRD(1))] = I(9),
+ [B(NI_RTSI_BRD(2))] = I(10),
+ [B(NI_RTSI_BRD(3))] = I(11),
+ [B(NI_CtrSource(0))] = I(5),
+ [B(NI_CtrGate(0))] = I(6),
+ [B(NI_AI_StartTrigger)] = I(0),
+ [B(NI_AI_ReferenceTrigger)] = I(1),
+ [B(NI_AI_ConvertClock)] = I(2),
+ [B(NI_AO_SampleClock)] = I(3),
+ [B(NI_AO_StartTrigger)] = I(4),
+ /*
+ * for (*->TRIGGER_LINE(*)) MUX, a value of 12 should be
+ * RTSI_OSC according to MHDDK mseries source. There
+ * are hints in comedi that show that this is actually a
+ * 20MHz source for 628x cards(?)
+ */
+ [B(NI_10MHzRefClock)] = I(12),
+ [B(NI_RGOUT0)] = I(7),
+ },
+ [B(TRIGGER_LINE(7))] = {
+ [B(NI_RTSI_BRD(0))] = I(8),
+ [B(NI_RTSI_BRD(1))] = I(9),
+ [B(NI_RTSI_BRD(2))] = I(10),
+ [B(NI_RTSI_BRD(3))] = I(11),
+ [B(NI_CtrSource(0))] = I(5),
+ [B(NI_CtrGate(0))] = I(6),
+ [B(NI_AI_StartTrigger)] = I(0),
+ [B(NI_AI_ReferenceTrigger)] = I(1),
+ [B(NI_AI_ConvertClock)] = I(2),
+ [B(NI_AO_SampleClock)] = I(3),
+ [B(NI_AO_StartTrigger)] = I(4),
+ /*
+ * for (*->TRIGGER_LINE(*)) MUX, a value of 12 should be
+ * RTSI_OSC according to MHDDK mseries source. There
+ * are hints in comedi that show that this is actually a
+ * 20MHz source for 628x cards(?)
+ */
+ [B(NI_10MHzRefClock)] = I(12),
+ [B(NI_RGOUT0)] = I(7),
+ },
+ [B(NI_RTSI_BRD(0))] = {
+ [B(NI_PFI(0))] = I(0),
+ [B(NI_PFI(1))] = I(1),
+ [B(NI_PFI(2))] = I(2),
+ [B(NI_PFI(3))] = I(3),
+ [B(NI_PFI(4))] = I(4),
+ [B(NI_PFI(5))] = I(5),
+ [B(NI_CtrSource(1))] = I(11),
+ [B(NI_CtrGate(1))] = I(10),
+ [B(NI_CtrZ(0))] = I(13),
+ [B(NI_CtrZ(1))] = I(12),
+ [B(NI_CtrOut(1))] = I(9),
+ [B(NI_AI_SampleClock)] = I(15),
+ [B(NI_AI_PauseTrigger)] = I(7),
+ [B(NI_AO_PauseTrigger)] = I(6),
+ [B(NI_FrequencyOutput)] = I(8),
+ [B(NI_AnalogComparisonEvent)] = I(14),
+ },
+ [B(NI_RTSI_BRD(1))] = {
+ [B(NI_PFI(0))] = I(0),
+ [B(NI_PFI(1))] = I(1),
+ [B(NI_PFI(2))] = I(2),
+ [B(NI_PFI(3))] = I(3),
+ [B(NI_PFI(4))] = I(4),
+ [B(NI_PFI(5))] = I(5),
+ [B(NI_CtrSource(1))] = I(11),
+ [B(NI_CtrGate(1))] = I(10),
+ [B(NI_CtrZ(0))] = I(13),
+ [B(NI_CtrZ(1))] = I(12),
+ [B(NI_CtrOut(1))] = I(9),
+ [B(NI_AI_SampleClock)] = I(15),
+ [B(NI_AI_PauseTrigger)] = I(7),
+ [B(NI_AO_PauseTrigger)] = I(6),
+ [B(NI_FrequencyOutput)] = I(8),
+ [B(NI_AnalogComparisonEvent)] = I(14),
+ },
+ [B(NI_RTSI_BRD(2))] = {
+ [B(NI_PFI(0))] = I(0),
+ [B(NI_PFI(1))] = I(1),
+ [B(NI_PFI(2))] = I(2),
+ [B(NI_PFI(3))] = I(3),
+ [B(NI_PFI(4))] = I(4),
+ [B(NI_PFI(5))] = I(5),
+ [B(NI_CtrSource(1))] = I(11),
+ [B(NI_CtrGate(1))] = I(10),
+ [B(NI_CtrZ(0))] = I(13),
+ [B(NI_CtrZ(1))] = I(12),
+ [B(NI_CtrOut(1))] = I(9),
+ [B(NI_AI_SampleClock)] = I(15),
+ [B(NI_AI_PauseTrigger)] = I(7),
+ [B(NI_AO_PauseTrigger)] = I(6),
+ [B(NI_FrequencyOutput)] = I(8),
+ [B(NI_AnalogComparisonEvent)] = I(14),
+ },
+ [B(NI_RTSI_BRD(3))] = {
+ [B(NI_PFI(0))] = I(0),
+ [B(NI_PFI(1))] = I(1),
+ [B(NI_PFI(2))] = I(2),
+ [B(NI_PFI(3))] = I(3),
+ [B(NI_PFI(4))] = I(4),
+ [B(NI_PFI(5))] = I(5),
+ [B(NI_CtrSource(1))] = I(11),
+ [B(NI_CtrGate(1))] = I(10),
+ [B(NI_CtrZ(0))] = I(13),
+ [B(NI_CtrZ(1))] = I(12),
+ [B(NI_CtrOut(1))] = I(9),
+ [B(NI_AI_SampleClock)] = I(15),
+ [B(NI_AI_PauseTrigger)] = I(7),
+ [B(NI_AO_PauseTrigger)] = I(6),
+ [B(NI_FrequencyOutput)] = I(8),
+ [B(NI_AnalogComparisonEvent)] = I(14),
+ },
+ [B(NI_CtrSource(0))] = {
+ /* These are not currently implemented in ni modules */
+ [B(NI_PFI(0))] = U(1),
+ [B(NI_PFI(1))] = U(2),
+ [B(NI_PFI(2))] = U(3),
+ [B(NI_PFI(3))] = U(4),
+ [B(NI_PFI(4))] = U(5),
+ [B(NI_PFI(5))] = U(6),
+ [B(NI_PFI(6))] = U(7),
+ [B(NI_PFI(7))] = U(8),
+ [B(NI_PFI(8))] = U(9),
+ [B(NI_PFI(9))] = U(10),
+ [B(NI_PFI(10))] = U(21),
+ [B(NI_PFI(11))] = U(22),
+ [B(NI_PFI(12))] = U(23),
+ [B(NI_PFI(13))] = U(24),
+ [B(NI_PFI(14))] = U(25),
+ [B(NI_PFI(15))] = U(26),
+ [B(TRIGGER_LINE(0))] = U(11),
+ [B(TRIGGER_LINE(1))] = U(12),
+ [B(TRIGGER_LINE(2))] = U(13),
+ [B(TRIGGER_LINE(3))] = U(14),
+ [B(TRIGGER_LINE(4))] = U(15),
+ [B(TRIGGER_LINE(5))] = U(16),
+ [B(TRIGGER_LINE(6))] = U(17),
+ [B(TRIGGER_LINE(7))] = U(27),
+ [B(NI_CtrGate(1))] = U(Gi_SRC(20, 0)),
+ [B(NI_CtrInternalOutput(1))] = U(19),
+ [B(PXI_Star)] = U(Gi_SRC(20, 1)),
+ [B(PXI_Clk10)] = U(29),
+ [B(NI_20MHzTimebase)] = U(0),
+ [B(NI_80MHzTimebase)] = U(Gi_SRC(30, 0)),
+ [B(NI_100kHzTimebase)] = U(18),
+ [B(NI_AnalogComparisonEvent)] = U(Gi_SRC(30, 1)),
+ [B(NI_LogicLow)] = U(31),
+ },
+ [B(NI_CtrSource(1))] = {
+ /* These are not currently implemented in ni modules */
+ [B(NI_PFI(0))] = U(1),
+ [B(NI_PFI(1))] = U(2),
+ [B(NI_PFI(2))] = U(3),
+ [B(NI_PFI(3))] = U(4),
+ [B(NI_PFI(4))] = U(5),
+ [B(NI_PFI(5))] = U(6),
+ [B(NI_PFI(6))] = U(7),
+ [B(NI_PFI(7))] = U(8),
+ [B(NI_PFI(8))] = U(9),
+ [B(NI_PFI(9))] = U(10),
+ [B(NI_PFI(10))] = U(21),
+ [B(NI_PFI(11))] = U(22),
+ [B(NI_PFI(12))] = U(23),
+ [B(NI_PFI(13))] = U(24),
+ [B(NI_PFI(14))] = U(25),
+ [B(NI_PFI(15))] = U(26),
+ [B(TRIGGER_LINE(0))] = U(11),
+ [B(TRIGGER_LINE(1))] = U(12),
+ [B(TRIGGER_LINE(2))] = U(13),
+ [B(TRIGGER_LINE(3))] = U(14),
+ [B(TRIGGER_LINE(4))] = U(15),
+ [B(TRIGGER_LINE(5))] = U(16),
+ [B(TRIGGER_LINE(6))] = U(17),
+ [B(TRIGGER_LINE(7))] = U(27),
+ [B(NI_CtrGate(0))] = U(Gi_SRC(20, 0)),
+ [B(NI_CtrInternalOutput(0))] = U(19),
+ [B(PXI_Star)] = U(Gi_SRC(20, 1)),
+ [B(PXI_Clk10)] = U(29),
+ [B(NI_20MHzTimebase)] = U(0),
+ [B(NI_80MHzTimebase)] = U(Gi_SRC(30, 0)),
+ [B(NI_100kHzTimebase)] = U(18),
+ [B(NI_AnalogComparisonEvent)] = U(Gi_SRC(30, 1)),
+ [B(NI_LogicLow)] = U(31),
+ },
+ [B(NI_CtrGate(0))] = {
+ [B(NI_PFI(0))] = I(1 /* source: mhddk examples */),
+ [B(NI_PFI(1))] = I(2),
+ [B(NI_PFI(2))] = I(3),
+ [B(NI_PFI(3))] = I(4),
+ [B(NI_PFI(4))] = I(5),
+ [B(NI_PFI(5))] = I(6),
+ [B(NI_PFI(6))] = I(7),
+ [B(NI_PFI(7))] = I(8),
+ [B(NI_PFI(8))] = I(9),
+ [B(NI_PFI(9))] = I(10),
+ [B(NI_PFI(10))] = I(21),
+ [B(NI_PFI(11))] = I(22),
+ [B(NI_PFI(12))] = I(23),
+ [B(NI_PFI(13))] = I(24),
+ [B(NI_PFI(14))] = I(25),
+ [B(NI_PFI(15))] = I(26),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(TRIGGER_LINE(7))] = I(27),
+ [B(NI_CtrSource(1))] = I(29),
+ /* source for following line: mhddk GP examples */
+ [B(NI_CtrInternalOutput(1))] = I(20),
+ [B(PXI_Star)] = I(19),
+ [B(NI_AI_StartTrigger)] = I(28),
+ [B(NI_AI_ReferenceTrigger)] = I(18),
+ [B(NI_AnalogComparisonEvent)] = I(30),
+ [B(NI_LogicLow)] = I(31),
+ },
+ [B(NI_CtrGate(1))] = {
+ /* source for following line: mhddk examples */
+ [B(NI_PFI(0))] = I(1),
+ [B(NI_PFI(1))] = I(2),
+ [B(NI_PFI(2))] = I(3),
+ [B(NI_PFI(3))] = I(4),
+ [B(NI_PFI(4))] = I(5),
+ [B(NI_PFI(5))] = I(6),
+ [B(NI_PFI(6))] = I(7),
+ [B(NI_PFI(7))] = I(8),
+ [B(NI_PFI(8))] = I(9),
+ [B(NI_PFI(9))] = I(10),
+ [B(NI_PFI(10))] = I(21),
+ [B(NI_PFI(11))] = I(22),
+ [B(NI_PFI(12))] = I(23),
+ [B(NI_PFI(13))] = I(24),
+ [B(NI_PFI(14))] = I(25),
+ [B(NI_PFI(15))] = I(26),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(TRIGGER_LINE(7))] = I(27),
+ [B(NI_CtrSource(0))] = I(29),
+ /* source for following line: mhddk GP examples */
+ [B(NI_CtrInternalOutput(0))] = I(20),
+ [B(PXI_Star)] = I(19),
+ [B(NI_AI_StartTrigger)] = I(28),
+ [B(NI_AI_ReferenceTrigger)] = I(18),
+ [B(NI_AnalogComparisonEvent)] = I(30),
+ [B(NI_LogicLow)] = I(31),
+ },
+ [B(NI_CtrAux(0))] = {
+ /* these are just a guess; see GATE SELECT NOTE */
+ [B(NI_PFI(0))] = I(1),
+ [B(NI_PFI(1))] = I(2),
+ [B(NI_PFI(2))] = I(3),
+ [B(NI_PFI(3))] = I(4),
+ [B(NI_PFI(4))] = I(5),
+ [B(NI_PFI(5))] = I(6),
+ [B(NI_PFI(6))] = I(7),
+ [B(NI_PFI(7))] = I(8),
+ [B(NI_PFI(8))] = I(9),
+ [B(NI_PFI(9))] = I(10),
+ [B(NI_PFI(10))] = I(21),
+ [B(NI_PFI(11))] = I(22),
+ [B(NI_PFI(12))] = I(23),
+ [B(NI_PFI(13))] = I(24),
+ [B(NI_PFI(14))] = I(25),
+ [B(NI_PFI(15))] = I(26),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(TRIGGER_LINE(7))] = I(27),
+ [B(NI_CtrSource(1))] = I(29),
+ /* source for following line: mhddk GP examples */
+ [B(NI_CtrInternalOutput(1))] = I(20),
+ [B(PXI_Star)] = I(19),
+ [B(NI_AI_StartTrigger)] = I(28),
+ [B(NI_AI_ReferenceTrigger)] = I(18),
+ [B(NI_AnalogComparisonEvent)] = I(30),
+ [B(NI_LogicLow)] = I(31),
+ },
+ [B(NI_CtrAux(1))] = {
+ /* these are just a guess; see GATE SELECT NOTE */
+ [B(NI_PFI(0))] = I(1),
+ [B(NI_PFI(1))] = I(2),
+ [B(NI_PFI(2))] = I(3),
+ [B(NI_PFI(3))] = I(4),
+ [B(NI_PFI(4))] = I(5),
+ [B(NI_PFI(5))] = I(6),
+ [B(NI_PFI(6))] = I(7),
+ [B(NI_PFI(7))] = I(8),
+ [B(NI_PFI(8))] = I(9),
+ [B(NI_PFI(9))] = I(10),
+ [B(NI_PFI(10))] = I(21),
+ [B(NI_PFI(11))] = I(22),
+ [B(NI_PFI(12))] = I(23),
+ [B(NI_PFI(13))] = I(24),
+ [B(NI_PFI(14))] = I(25),
+ [B(NI_PFI(15))] = I(26),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(TRIGGER_LINE(7))] = I(27),
+ [B(NI_CtrSource(0))] = I(29),
+ /* source for following line: mhddk GP examples */
+ [B(NI_CtrInternalOutput(0))] = I(20),
+ [B(PXI_Star)] = I(19),
+ [B(NI_AI_StartTrigger)] = I(28),
+ [B(NI_AI_ReferenceTrigger)] = I(18),
+ [B(NI_AnalogComparisonEvent)] = I(30),
+ [B(NI_LogicLow)] = I(31),
+ },
+ [B(NI_CtrA(0))] = {
+ /*
+ * See nimseries/Examples for outputs; inputs a guess
+ * from device routes shown on NI-MAX.
+ * see M-Series user manual (371022K-01)
+ */
+ [B(NI_PFI(0))] = I(1),
+ [B(NI_PFI(1))] = I(2),
+ [B(NI_PFI(2))] = I(3),
+ [B(NI_PFI(3))] = I(4),
+ [B(NI_PFI(4))] = I(5),
+ [B(NI_PFI(5))] = I(6),
+ [B(NI_PFI(6))] = I(7),
+ [B(NI_PFI(7))] = I(8),
+ [B(NI_PFI(8))] = I(9),
+ [B(NI_PFI(9))] = I(10),
+ [B(NI_PFI(10))] = I(21),
+ [B(NI_PFI(11))] = I(22),
+ [B(NI_PFI(12))] = I(23),
+ [B(NI_PFI(13))] = I(24),
+ [B(NI_PFI(14))] = I(25),
+ [B(NI_PFI(15))] = I(26),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(TRIGGER_LINE(7))] = I(27),
+ [B(PXI_Star)] = I(20),
+ [B(NI_AnalogComparisonEvent)] = I(30),
+ [B(NI_LogicLow)] = I(31),
+ },
+ [B(NI_CtrA(1))] = {
+ /*
+ * See nimseries/Examples for outputs; inputs a guess
+ * from device routes shown on NI-MAX.
+ * see M-Series user manual (371022K-01)
+ */
+ [B(NI_PFI(0))] = I(1),
+ [B(NI_PFI(1))] = I(2),
+ [B(NI_PFI(2))] = I(3),
+ [B(NI_PFI(3))] = I(4),
+ [B(NI_PFI(4))] = I(5),
+ [B(NI_PFI(5))] = I(6),
+ [B(NI_PFI(6))] = I(7),
+ [B(NI_PFI(7))] = I(8),
+ [B(NI_PFI(8))] = I(9),
+ [B(NI_PFI(9))] = I(10),
+ [B(NI_PFI(10))] = I(21),
+ [B(NI_PFI(11))] = I(22),
+ [B(NI_PFI(12))] = I(23),
+ [B(NI_PFI(13))] = I(24),
+ [B(NI_PFI(14))] = I(25),
+ [B(NI_PFI(15))] = I(26),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(TRIGGER_LINE(7))] = I(27),
+ [B(PXI_Star)] = I(20),
+ [B(NI_AnalogComparisonEvent)] = I(30),
+ [B(NI_LogicLow)] = I(31),
+ },
+ [B(NI_CtrB(0))] = {
+ /*
+ * See nimseries/Examples for outputs; inputs a guess
+ * from device routes shown on NI-MAX.
+ * see M-Series user manual (371022K-01)
+ */
+ [B(NI_PFI(0))] = I(1),
+ [B(NI_PFI(1))] = I(2),
+ [B(NI_PFI(2))] = I(3),
+ [B(NI_PFI(3))] = I(4),
+ [B(NI_PFI(4))] = I(5),
+ [B(NI_PFI(5))] = I(6),
+ [B(NI_PFI(6))] = I(7),
+ [B(NI_PFI(7))] = I(8),
+ [B(NI_PFI(8))] = I(9),
+ [B(NI_PFI(9))] = I(10),
+ [B(NI_PFI(10))] = I(21),
+ [B(NI_PFI(11))] = I(22),
+ [B(NI_PFI(12))] = I(23),
+ [B(NI_PFI(13))] = I(24),
+ [B(NI_PFI(14))] = I(25),
+ [B(NI_PFI(15))] = I(26),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(TRIGGER_LINE(7))] = I(27),
+ [B(PXI_Star)] = I(20),
+ [B(NI_AnalogComparisonEvent)] = I(30),
+ [B(NI_LogicLow)] = I(31),
+ },
+ [B(NI_CtrB(1))] = {
+ /*
+ * See nimseries/Examples for outputs; inputs a guess
+ * from device routes shown on NI-MAX.
+ * see M-Series user manual (371022K-01)
+ */
+ [B(NI_PFI(0))] = I(1),
+ [B(NI_PFI(1))] = I(2),
+ [B(NI_PFI(2))] = I(3),
+ [B(NI_PFI(3))] = I(4),
+ [B(NI_PFI(4))] = I(5),
+ [B(NI_PFI(5))] = I(6),
+ [B(NI_PFI(6))] = I(7),
+ [B(NI_PFI(7))] = I(8),
+ [B(NI_PFI(8))] = I(9),
+ [B(NI_PFI(9))] = I(10),
+ [B(NI_PFI(10))] = I(21),
+ [B(NI_PFI(11))] = I(22),
+ [B(NI_PFI(12))] = I(23),
+ [B(NI_PFI(13))] = I(24),
+ [B(NI_PFI(14))] = I(25),
+ [B(NI_PFI(15))] = I(26),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(TRIGGER_LINE(7))] = I(27),
+ [B(PXI_Star)] = I(20),
+ [B(NI_AnalogComparisonEvent)] = I(30),
+ [B(NI_LogicLow)] = I(31),
+ },
+ [B(NI_CtrZ(0))] = {
+ /*
+ * See nimseries/Examples for outputs; inputs a guess
+ * from device routes shown on NI-MAX.
+ * see M-Series user manual (371022K-01)
+ */
+ [B(NI_PFI(0))] = I(1),
+ [B(NI_PFI(1))] = I(2),
+ [B(NI_PFI(2))] = I(3),
+ [B(NI_PFI(3))] = I(4),
+ [B(NI_PFI(4))] = I(5),
+ [B(NI_PFI(5))] = I(6),
+ [B(NI_PFI(6))] = I(7),
+ [B(NI_PFI(7))] = I(8),
+ [B(NI_PFI(8))] = I(9),
+ [B(NI_PFI(9))] = I(10),
+ [B(NI_PFI(10))] = I(21),
+ [B(NI_PFI(11))] = I(22),
+ [B(NI_PFI(12))] = I(23),
+ [B(NI_PFI(13))] = I(24),
+ [B(NI_PFI(14))] = I(25),
+ [B(NI_PFI(15))] = I(26),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(TRIGGER_LINE(7))] = I(27),
+ [B(PXI_Star)] = I(20),
+ [B(NI_AnalogComparisonEvent)] = I(30),
+ [B(NI_LogicLow)] = I(31),
+ },
+ [B(NI_CtrZ(1))] = {
+ /*
+ * See nimseries/Examples for outputs; inputs a guess
+ * from device routes shown on NI-MAX.
+ * see M-Series user manual (371022K-01)
+ */
+ [B(NI_PFI(0))] = I(1),
+ [B(NI_PFI(1))] = I(2),
+ [B(NI_PFI(2))] = I(3),
+ [B(NI_PFI(3))] = I(4),
+ [B(NI_PFI(4))] = I(5),
+ [B(NI_PFI(5))] = I(6),
+ [B(NI_PFI(6))] = I(7),
+ [B(NI_PFI(7))] = I(8),
+ [B(NI_PFI(8))] = I(9),
+ [B(NI_PFI(9))] = I(10),
+ [B(NI_PFI(10))] = I(21),
+ [B(NI_PFI(11))] = I(22),
+ [B(NI_PFI(12))] = I(23),
+ [B(NI_PFI(13))] = I(24),
+ [B(NI_PFI(14))] = I(25),
+ [B(NI_PFI(15))] = I(26),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(TRIGGER_LINE(7))] = I(27),
+ [B(PXI_Star)] = I(20),
+ [B(NI_AnalogComparisonEvent)] = I(30),
+ [B(NI_LogicLow)] = I(31),
+ },
+ [B(NI_CtrArmStartTrigger(0))] = {
+ /* these are just a guess; see GATE SELECT NOTE */
+ [B(NI_PFI(0))] = I(1),
+ [B(NI_PFI(1))] = I(2),
+ [B(NI_PFI(2))] = I(3),
+ [B(NI_PFI(3))] = I(4),
+ [B(NI_PFI(4))] = I(5),
+ [B(NI_PFI(5))] = I(6),
+ [B(NI_PFI(6))] = I(7),
+ [B(NI_PFI(7))] = I(8),
+ [B(NI_PFI(8))] = I(9),
+ [B(NI_PFI(9))] = I(10),
+ [B(NI_PFI(10))] = I(21),
+ [B(NI_PFI(11))] = I(22),
+ [B(NI_PFI(12))] = I(23),
+ [B(NI_PFI(13))] = I(24),
+ [B(NI_PFI(14))] = I(25),
+ [B(NI_PFI(15))] = I(26),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(TRIGGER_LINE(7))] = I(27),
+ [B(NI_CtrSource(1))] = I(29),
+ /* source for following line: mhddk GP examples */
+ [B(NI_CtrInternalOutput(1))] = I(20),
+ [B(PXI_Star)] = I(19),
+ [B(NI_AI_StartTrigger)] = I(28),
+ [B(NI_AI_ReferenceTrigger)] = I(18),
+ [B(NI_AnalogComparisonEvent)] = I(30),
+ [B(NI_LogicLow)] = I(31),
+ },
+ [B(NI_CtrArmStartTrigger(1))] = {
+ /* these are just a guess; see GATE SELECT NOTE */
+ [B(NI_PFI(0))] = I(1),
+ [B(NI_PFI(1))] = I(2),
+ [B(NI_PFI(2))] = I(3),
+ [B(NI_PFI(3))] = I(4),
+ [B(NI_PFI(4))] = I(5),
+ [B(NI_PFI(5))] = I(6),
+ [B(NI_PFI(6))] = I(7),
+ [B(NI_PFI(7))] = I(8),
+ [B(NI_PFI(8))] = I(9),
+ [B(NI_PFI(9))] = I(10),
+ [B(NI_PFI(10))] = I(21),
+ [B(NI_PFI(11))] = I(22),
+ [B(NI_PFI(12))] = I(23),
+ [B(NI_PFI(13))] = I(24),
+ [B(NI_PFI(14))] = I(25),
+ [B(NI_PFI(15))] = I(26),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(TRIGGER_LINE(7))] = I(27),
+ [B(NI_CtrSource(0))] = I(29),
+ /* source for following line: mhddk GP examples */
+ [B(NI_CtrInternalOutput(0))] = I(20),
+ [B(PXI_Star)] = I(19),
+ [B(NI_AI_StartTrigger)] = I(28),
+ [B(NI_AI_ReferenceTrigger)] = I(18),
+ [B(NI_AnalogComparisonEvent)] = I(30),
+ [B(NI_LogicLow)] = I(31),
+ },
+ [B(NI_CtrOut(0))] = {
+ [B(TRIGGER_LINE(0))] = I(1),
+ [B(TRIGGER_LINE(1))] = I(2),
+ [B(TRIGGER_LINE(2))] = I(3),
+ [B(TRIGGER_LINE(3))] = I(4),
+ [B(TRIGGER_LINE(4))] = I(5),
+ [B(TRIGGER_LINE(5))] = I(6),
+ [B(TRIGGER_LINE(6))] = I(7),
+ [B(NI_CtrInternalOutput(0))] = I(0),
+ },
+ [B(NI_CtrOut(1))] = {
+ [B(NI_CtrInternalOutput(1))] = I(0),
+ },
+ [B(NI_AI_SampleClock)] = {
+ [B(NI_PFI(0))] = I(1),
+ [B(NI_PFI(1))] = I(2),
+ [B(NI_PFI(2))] = I(3),
+ [B(NI_PFI(3))] = I(4),
+ [B(NI_PFI(4))] = I(5),
+ [B(NI_PFI(5))] = I(6),
+ [B(NI_PFI(6))] = I(7),
+ [B(NI_PFI(7))] = I(8),
+ [B(NI_PFI(8))] = I(9),
+ [B(NI_PFI(9))] = I(10),
+ [B(NI_PFI(10))] = I(21),
+ [B(NI_PFI(11))] = I(22),
+ [B(NI_PFI(12))] = I(23),
+ [B(NI_PFI(13))] = I(24),
+ [B(NI_PFI(14))] = I(25),
+ [B(NI_PFI(15))] = I(26),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(TRIGGER_LINE(7))] = I(27),
+ [B(NI_CtrInternalOutput(0))] = I(19),
+ [B(NI_CtrInternalOutput(1))] = I(28),
+ [B(PXI_Star)] = I(20),
+ [B(NI_AI_SampleClockTimebase)] = I(0),
+ [B(NI_AnalogComparisonEvent)] = I(30),
+ [B(NI_SCXI_Trig1)] = I(29),
+ [B(NI_LogicLow)] = I(31),
+ },
+ [B(NI_AI_SampleClockTimebase)] = {
+ /* These are not currently implemented in ni modules */
+ [B(NI_PFI(0))] = U(1),
+ [B(NI_PFI(1))] = U(2),
+ [B(NI_PFI(2))] = U(3),
+ [B(NI_PFI(3))] = U(4),
+ [B(NI_PFI(4))] = U(5),
+ [B(NI_PFI(5))] = U(6),
+ [B(NI_PFI(6))] = U(7),
+ [B(NI_PFI(7))] = U(8),
+ [B(NI_PFI(8))] = U(9),
+ [B(NI_PFI(9))] = U(10),
+ [B(NI_PFI(10))] = U(21),
+ [B(NI_PFI(11))] = U(22),
+ [B(NI_PFI(12))] = U(23),
+ [B(NI_PFI(13))] = U(24),
+ [B(NI_PFI(14))] = U(25),
+ [B(NI_PFI(15))] = U(26),
+ [B(TRIGGER_LINE(0))] = U(11),
+ [B(TRIGGER_LINE(1))] = U(12),
+ [B(TRIGGER_LINE(2))] = U(13),
+ [B(TRIGGER_LINE(3))] = U(14),
+ [B(TRIGGER_LINE(4))] = U(15),
+ [B(TRIGGER_LINE(5))] = U(16),
+ [B(TRIGGER_LINE(6))] = U(17),
+ [B(TRIGGER_LINE(7))] = U(27),
+ [B(PXI_Star)] = U(20),
+ [B(PXI_Clk10)] = U(29),
+ /*
+ * For routes (*->NI_AI_SampleClockTimebase) and
+ * (*->NI_AO_SampleClockTimebase), tMSeries.h of MHDDK
+ * shows 0 value as selecting ground (case ground?) and
+ * 28 value selecting TIMEBASE 1.
+ */
+ [B(NI_20MHzTimebase)] = U(28),
+ [B(NI_100kHzTimebase)] = U(19),
+ [B(NI_AnalogComparisonEvent)] = U(30),
+ [B(NI_LogicLow)] = U(31),
+ [B(NI_CaseGround)] = U(0),
+ },
+ [B(NI_AI_StartTrigger)] = {
+ [B(NI_PFI(0))] = I(1),
+ [B(NI_PFI(1))] = I(2),
+ [B(NI_PFI(2))] = I(3),
+ [B(NI_PFI(3))] = I(4),
+ [B(NI_PFI(4))] = I(5),
+ [B(NI_PFI(5))] = I(6),
+ [B(NI_PFI(6))] = I(7),
+ [B(NI_PFI(7))] = I(8),
+ [B(NI_PFI(8))] = I(9),
+ [B(NI_PFI(9))] = I(10),
+ [B(NI_PFI(10))] = I(21),
+ [B(NI_PFI(11))] = I(22),
+ [B(NI_PFI(12))] = I(23),
+ [B(NI_PFI(13))] = I(24),
+ [B(NI_PFI(14))] = I(25),
+ [B(NI_PFI(15))] = I(26),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(TRIGGER_LINE(7))] = I(27),
+ [B(NI_CtrInternalOutput(0))] = I(18),
+ [B(NI_CtrInternalOutput(1))] = I(19),
+ [B(PXI_Star)] = I(20),
+ [B(NI_AnalogComparisonEvent)] = I(30),
+ [B(NI_LogicLow)] = I(31),
+ },
+ [B(NI_AI_ReferenceTrigger)] = {
+ /* These are not currently implemented in ni modules */
+ [B(NI_PFI(0))] = U(1),
+ [B(NI_PFI(1))] = U(2),
+ [B(NI_PFI(2))] = U(3),
+ [B(NI_PFI(3))] = U(4),
+ [B(NI_PFI(4))] = U(5),
+ [B(NI_PFI(5))] = U(6),
+ [B(NI_PFI(6))] = U(7),
+ [B(NI_PFI(7))] = U(8),
+ [B(NI_PFI(8))] = U(9),
+ [B(NI_PFI(9))] = U(10),
+ [B(NI_PFI(10))] = U(21),
+ [B(NI_PFI(11))] = U(22),
+ [B(NI_PFI(12))] = U(23),
+ [B(NI_PFI(13))] = U(24),
+ [B(NI_PFI(14))] = U(25),
+ [B(NI_PFI(15))] = U(26),
+ [B(TRIGGER_LINE(0))] = U(11),
+ [B(TRIGGER_LINE(1))] = U(12),
+ [B(TRIGGER_LINE(2))] = U(13),
+ [B(TRIGGER_LINE(3))] = U(14),
+ [B(TRIGGER_LINE(4))] = U(15),
+ [B(TRIGGER_LINE(5))] = U(16),
+ [B(TRIGGER_LINE(6))] = U(17),
+ [B(TRIGGER_LINE(7))] = U(27),
+ [B(PXI_Star)] = U(20),
+ [B(NI_AnalogComparisonEvent)] = U(30),
+ [B(NI_LogicLow)] = U(31),
+ },
+ [B(NI_AI_ConvertClock)] = {
+ [B(NI_PFI(0))] = I(1),
+ [B(NI_PFI(1))] = I(2),
+ [B(NI_PFI(2))] = I(3),
+ [B(NI_PFI(3))] = I(4),
+ [B(NI_PFI(4))] = I(5),
+ [B(NI_PFI(5))] = I(6),
+ [B(NI_PFI(6))] = I(7),
+ [B(NI_PFI(7))] = I(8),
+ [B(NI_PFI(8))] = I(9),
+ [B(NI_PFI(9))] = I(10),
+ [B(NI_PFI(10))] = I(21),
+ [B(NI_PFI(11))] = I(22),
+ [B(NI_PFI(12))] = I(23),
+ [B(NI_PFI(13))] = I(24),
+ [B(NI_PFI(14))] = I(25),
+ [B(NI_PFI(15))] = I(26),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(TRIGGER_LINE(7))] = I(27),
+ /* source for following line: mhddk example headers */
+ [B(NI_CtrInternalOutput(0))] = I(19),
+ /* source for following line: mhddk example headers */
+ [B(NI_CtrInternalOutput(1))] = I(18),
+ [B(PXI_Star)] = I(20),
+ [B(NI_AI_ConvertClockTimebase)] = I(0),
+ [B(NI_AnalogComparisonEvent)] = I(30),
+ [B(NI_LogicLow)] = I(31),
+ },
+ [B(NI_AI_ConvertClockTimebase)] = {
+ /* These are not currently implemented in ni modules */
+ [B(NI_AI_SampleClockTimebase)] = U(0),
+ [B(NI_20MHzTimebase)] = U(1),
+ },
+ [B(NI_AI_PauseTrigger)] = {
+ /* These are not currently implemented in ni modules */
+ [B(NI_PFI(0))] = U(1),
+ [B(NI_PFI(1))] = U(2),
+ [B(NI_PFI(2))] = U(3),
+ [B(NI_PFI(3))] = U(4),
+ [B(NI_PFI(4))] = U(5),
+ [B(NI_PFI(5))] = U(6),
+ [B(NI_PFI(6))] = U(7),
+ [B(NI_PFI(7))] = U(8),
+ [B(NI_PFI(8))] = U(9),
+ [B(NI_PFI(9))] = U(10),
+ [B(NI_PFI(10))] = U(21),
+ [B(NI_PFI(11))] = U(22),
+ [B(NI_PFI(12))] = U(23),
+ [B(NI_PFI(13))] = U(24),
+ [B(NI_PFI(14))] = U(25),
+ [B(NI_PFI(15))] = U(26),
+ [B(TRIGGER_LINE(0))] = U(11),
+ [B(TRIGGER_LINE(1))] = U(12),
+ [B(TRIGGER_LINE(2))] = U(13),
+ [B(TRIGGER_LINE(3))] = U(14),
+ [B(TRIGGER_LINE(4))] = U(15),
+ [B(TRIGGER_LINE(5))] = U(16),
+ [B(TRIGGER_LINE(6))] = U(17),
+ [B(TRIGGER_LINE(7))] = U(27),
+ [B(PXI_Star)] = U(20),
+ [B(NI_AnalogComparisonEvent)] = U(30),
+ [B(NI_LogicLow)] = U(31),
+ },
+ [B(NI_AO_SampleClock)] = {
+ [B(NI_PFI(0))] = I(1),
+ [B(NI_PFI(1))] = I(2),
+ [B(NI_PFI(2))] = I(3),
+ [B(NI_PFI(3))] = I(4),
+ [B(NI_PFI(4))] = I(5),
+ [B(NI_PFI(5))] = I(6),
+ [B(NI_PFI(6))] = I(7),
+ [B(NI_PFI(7))] = I(8),
+ [B(NI_PFI(8))] = I(9),
+ [B(NI_PFI(9))] = I(10),
+ [B(NI_PFI(10))] = I(21),
+ [B(NI_PFI(11))] = I(22),
+ [B(NI_PFI(12))] = I(23),
+ [B(NI_PFI(13))] = I(24),
+ [B(NI_PFI(14))] = I(25),
+ [B(NI_PFI(15))] = I(26),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(TRIGGER_LINE(7))] = I(27),
+ [B(NI_CtrInternalOutput(0))] = I(18),
+ [B(NI_CtrInternalOutput(1))] = I(19),
+ [B(PXI_Star)] = I(20),
+ [B(NI_AO_SampleClockTimebase)] = I(0),
+ [B(NI_AnalogComparisonEvent)] = I(30),
+ [B(NI_LogicLow)] = I(31),
+ },
+ [B(NI_AO_SampleClockTimebase)] = {
+ /* These are not currently implemented in ni modules */
+ [B(NI_PFI(0))] = U(1),
+ [B(NI_PFI(1))] = U(2),
+ [B(NI_PFI(2))] = U(3),
+ [B(NI_PFI(3))] = U(4),
+ [B(NI_PFI(4))] = U(5),
+ [B(NI_PFI(5))] = U(6),
+ [B(NI_PFI(6))] = U(7),
+ [B(NI_PFI(7))] = U(8),
+ [B(NI_PFI(8))] = U(9),
+ [B(NI_PFI(9))] = U(10),
+ [B(NI_PFI(10))] = U(21),
+ [B(NI_PFI(11))] = U(22),
+ [B(NI_PFI(12))] = U(23),
+ [B(NI_PFI(13))] = U(24),
+ [B(NI_PFI(14))] = U(25),
+ [B(NI_PFI(15))] = U(26),
+ [B(TRIGGER_LINE(0))] = U(11),
+ [B(TRIGGER_LINE(1))] = U(12),
+ [B(TRIGGER_LINE(2))] = U(13),
+ [B(TRIGGER_LINE(3))] = U(14),
+ [B(TRIGGER_LINE(4))] = U(15),
+ [B(TRIGGER_LINE(5))] = U(16),
+ [B(TRIGGER_LINE(6))] = U(17),
+ [B(TRIGGER_LINE(7))] = U(27),
+ [B(PXI_Star)] = U(20),
+ [B(PXI_Clk10)] = U(29),
+ /*
+ * For routes (*->NI_AI_SampleClockTimebase) and
+ * (*->NI_AO_SampleClockTimebase), tMSeries.h of MHDDK
+ * shows 0 value as selecting ground (case ground?) and
+ * 28 value selecting TIMEBASE 1.
+ */
+ [B(NI_20MHzTimebase)] = U(28),
+ [B(NI_100kHzTimebase)] = U(19),
+ [B(NI_AnalogComparisonEvent)] = U(30),
+ [B(NI_LogicLow)] = U(31),
+ [B(NI_CaseGround)] = U(0),
+ },
+ [B(NI_AO_StartTrigger)] = {
+ [B(NI_PFI(0))] = I(1),
+ [B(NI_PFI(1))] = I(2),
+ [B(NI_PFI(2))] = I(3),
+ [B(NI_PFI(3))] = I(4),
+ [B(NI_PFI(4))] = I(5),
+ [B(NI_PFI(5))] = I(6),
+ [B(NI_PFI(6))] = I(7),
+ [B(NI_PFI(7))] = I(8),
+ [B(NI_PFI(8))] = I(9),
+ [B(NI_PFI(9))] = I(10),
+ [B(NI_PFI(10))] = I(21),
+ [B(NI_PFI(11))] = I(22),
+ [B(NI_PFI(12))] = I(23),
+ [B(NI_PFI(13))] = I(24),
+ [B(NI_PFI(14))] = I(25),
+ [B(NI_PFI(15))] = I(26),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(TRIGGER_LINE(7))] = I(27),
+ [B(PXI_Star)] = I(20),
+ /*
+ * for the signal route
+ * (NI_AI_StartTrigger->NI_AO_StartTrigger), DAQ-STC &
+ * MHDDK disagreed for e-series. MHDDK for m-series
+ * agrees with DAQ-STC description and uses the value 18
+ * for the route
+ * (NI_AI_ReferenceTrigger->NI_AO_StartTrigger). The
+ * m-series devices are supposed to have DAQ-STC2.
+ * There are no DAQ-STC2 docs to compare with.
+ */
+ [B(NI_AI_StartTrigger)] = I(19),
+ [B(NI_AI_ReferenceTrigger)] = I(18),
+ [B(NI_AnalogComparisonEvent)] = I(30),
+ [B(NI_LogicLow)] = I(31),
+ },
+ [B(NI_AO_PauseTrigger)] = {
+ /* These are not currently implemented in ni modules */
+ [B(NI_PFI(0))] = U(1),
+ [B(NI_PFI(1))] = U(2),
+ [B(NI_PFI(2))] = U(3),
+ [B(NI_PFI(3))] = U(4),
+ [B(NI_PFI(4))] = U(5),
+ [B(NI_PFI(5))] = U(6),
+ [B(NI_PFI(6))] = U(7),
+ [B(NI_PFI(7))] = U(8),
+ [B(NI_PFI(8))] = U(9),
+ [B(NI_PFI(9))] = U(10),
+ [B(NI_PFI(10))] = U(21),
+ [B(NI_PFI(11))] = U(22),
+ [B(NI_PFI(12))] = U(23),
+ [B(NI_PFI(13))] = U(24),
+ [B(NI_PFI(14))] = U(25),
+ [B(NI_PFI(15))] = U(26),
+ [B(TRIGGER_LINE(0))] = U(11),
+ [B(TRIGGER_LINE(1))] = U(12),
+ [B(TRIGGER_LINE(2))] = U(13),
+ [B(TRIGGER_LINE(3))] = U(14),
+ [B(TRIGGER_LINE(4))] = U(15),
+ [B(TRIGGER_LINE(5))] = U(16),
+ [B(TRIGGER_LINE(6))] = U(17),
+ [B(TRIGGER_LINE(7))] = U(27),
+ [B(PXI_Star)] = U(20),
+ [B(NI_AnalogComparisonEvent)] = U(30),
+ [B(NI_LogicLow)] = U(31),
+ },
+ [B(NI_DI_SampleClock)] = {
+ [B(NI_PFI(0))] = I(1),
+ [B(NI_PFI(1))] = I(2),
+ [B(NI_PFI(2))] = I(3),
+ [B(NI_PFI(3))] = I(4),
+ [B(NI_PFI(4))] = I(5),
+ [B(NI_PFI(5))] = I(6),
+ [B(NI_PFI(6))] = I(7),
+ [B(NI_PFI(7))] = I(8),
+ [B(NI_PFI(8))] = I(9),
+ [B(NI_PFI(9))] = I(10),
+ [B(NI_PFI(10))] = I(21),
+ [B(NI_PFI(11))] = I(22),
+ [B(NI_PFI(12))] = I(23),
+ [B(NI_PFI(13))] = I(24),
+ [B(NI_PFI(14))] = I(25),
+ [B(NI_PFI(15))] = I(26),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(TRIGGER_LINE(7))] = I(27),
+ [B(NI_CtrInternalOutput(0))] = I(28),
+ [B(NI_CtrInternalOutput(1))] = I(29),
+ [B(PXI_Star)] = I(20),
+ [B(NI_AI_SampleClock)] = I(18),
+ [B(NI_AI_ConvertClock)] = I(19),
+ [B(NI_AO_SampleClock)] = I(31),
+ [B(NI_FrequencyOutput)] = I(32),
+ [B(NI_ChangeDetectionEvent)] = I(33),
+ [B(NI_CaseGround)] = I(0),
+ },
+ [B(NI_DO_SampleClock)] = {
+ [B(NI_PFI(0))] = I(1),
+ [B(NI_PFI(1))] = I(2),
+ [B(NI_PFI(2))] = I(3),
+ [B(NI_PFI(3))] = I(4),
+ [B(NI_PFI(4))] = I(5),
+ [B(NI_PFI(5))] = I(6),
+ [B(NI_PFI(6))] = I(7),
+ [B(NI_PFI(7))] = I(8),
+ [B(NI_PFI(8))] = I(9),
+ [B(NI_PFI(9))] = I(10),
+ [B(NI_PFI(10))] = I(21),
+ [B(NI_PFI(11))] = I(22),
+ [B(NI_PFI(12))] = I(23),
+ [B(NI_PFI(13))] = I(24),
+ [B(NI_PFI(14))] = I(25),
+ [B(NI_PFI(15))] = I(26),
+ [B(TRIGGER_LINE(0))] = I(11),
+ [B(TRIGGER_LINE(1))] = I(12),
+ [B(TRIGGER_LINE(2))] = I(13),
+ [B(TRIGGER_LINE(3))] = I(14),
+ [B(TRIGGER_LINE(4))] = I(15),
+ [B(TRIGGER_LINE(5))] = I(16),
+ [B(TRIGGER_LINE(6))] = I(17),
+ [B(TRIGGER_LINE(7))] = I(27),
+ [B(NI_CtrInternalOutput(0))] = I(28),
+ [B(NI_CtrInternalOutput(1))] = I(29),
+ [B(PXI_Star)] = I(20),
+ [B(NI_AI_SampleClock)] = I(18),
+ [B(NI_AI_ConvertClock)] = I(19),
+ [B(NI_AO_SampleClock)] = I(31),
+ [B(NI_FrequencyOutput)] = I(32),
+ [B(NI_ChangeDetectionEvent)] = I(33),
+ [B(NI_CaseGround)] = I(0),
+ },
+ [B(NI_MasterTimebase)] = {
+ /* These are not currently implemented in ni modules */
+ [B(TRIGGER_LINE(0))] = U(11),
+ [B(TRIGGER_LINE(1))] = U(12),
+ [B(TRIGGER_LINE(2))] = U(13),
+ [B(TRIGGER_LINE(3))] = U(14),
+ [B(TRIGGER_LINE(4))] = U(15),
+ [B(TRIGGER_LINE(5))] = U(16),
+ [B(TRIGGER_LINE(6))] = U(17),
+ [B(TRIGGER_LINE(7))] = U(27),
+ [B(PXI_Star)] = U(20),
+ [B(PXI_Clk10)] = U(29),
+ [B(NI_10MHzRefClock)] = U(0),
+ },
+ /*
+ * This symbol is not defined and nothing for this is
+ * implemented--just including this because data was found in
+ * the NI-STC for it--can't remember where.
+ * [B(NI_FrequencyOutTimebase)] = {
+ * ** These are not currently implemented in ni modules **
+ * [B(NI_20MHzTimebase)] = U(0),
+ * [B(NI_100kHzTimebase)] = U(1),
+ * },
+ */
+ [B(NI_RGOUT0)] = {
+ [B(NI_CtrInternalOutput(0))] = I(0),
+ [B(NI_CtrOut(0))] = I(1),
+ },
+ },
+};
diff --git a/drivers/staging/comedi/drivers/ni_routing/tools/.gitignore b/drivers/staging/comedi/drivers/ni_routing/tools/.gitignore
new file mode 100644
index 000000000000..ef38008280a9
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/tools/.gitignore
@@ -0,0 +1,7 @@
+comedi_h.py
+*.pyc
+ni_values.py
+convert_c_to_py
+c/
+csv/
+all_cfiles.c
diff --git a/drivers/staging/comedi/drivers/ni_routing/tools/Makefile b/drivers/staging/comedi/drivers/ni_routing/tools/Makefile
new file mode 100644
index 000000000000..1966850584d2
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/tools/Makefile
@@ -0,0 +1,79 @@
+# this make file is simply to help autogenerate these files:
+# ni_route_values.h
+# ni_device_routes.h
+# in order to do this, we are also generating a python representation (using
+# ctypesgen) of ../../comedi.h.
+# This allows us to sort NI signal/terminal names numerically to use a binary
+# search through the device_routes tables to find valid routes.
+
+ALL:
+ @echo Typical targets:
+ @echo "\`make csv-files\`"
+ @echo " Creates new csv-files using content of c-files of existing"
+ @echo " ni_routing/* content. New csv files are placed in csv"
+ @echo " sub-directory."
+ @echo "\`make c-files\`"
+ @echo " Creates new c-files using content of csv sub-directory. These"
+ @echo " new c-files can be compared to the active content in the"
+ @echo " ni_routing directory."
+ @echo "\`make csv-blank\`"
+ @echo " Create a new blank csv file. This is useful for establishing a"
+ @echo " new data table for either a device family \(less likely\) or a"
+ @echo " specific board of an existing device family \(more likely\)."
+ @echo "\`make clean-partial\`"
+ @echo " Remove all generated files/directories EXCEPT for csv/c files."
+ @echo "\`make clean\`"
+ @echo " Remove all generated files/directories."
+ @echo "\`make everything\`"
+ @echo " Build all csv-files, then all new c-files."
+
+everything : csv-files c-files csv-blank
+
+CPPFLAGS=-D"BIT(x)=(1UL<<(x))" -D__user=
+
+comedi_h.py : ../../../comedi.h
+ ctypesgen $< --include "sys/ioctl.h" --cpp 'gcc -E $(CPPFLAGS)' -o $@
+
+convert_c_to_py: all_cfiles.c
+ gcc -g convert_c_to_py.c -o convert_c_to_py -std=c99
+
+ni_values.py: convert_c_to_py
+ ./convert_c_to_py
+
+csv-files : ni_values.py comedi_h.py
+ ./convert_py_to_csv.py
+
+csv-blank :
+ ./make_blank_csv.py
+ @echo New blank csv signal table in csv/blank_route_table.csv
+
+c-files : comedi_h.py
+ ./convert_csv_to_c.py --route_values --device_routes
+
+ROUTE_VALUES_SRC=$(wildcard ../ni_route_values/*.c)
+DEVICE_ROUTES_SRC=$(wildcard ../ni_device_routes/*.c)
+all_cfiles.c : $(DEVICE_ROUTES_SRC) $(ROUTE_VALUES_SRC)
+ @for i in $(DEVICE_ROUTES_SRC) $(ROUTE_VALUES_SRC); do \
+ echo "#include \"$$i\"" >> all_cfiles.c; \
+ done
+
+clean-partial :
+ $(RM) -rf comedi_h.py ni_values.py convert_c_to_py all_cfiles.c *.pyc \
+ __pycache__/
+
+clean : partial_clean
+ $(RM) -rf c/ csv/
+
+# Note: One could also use ctypeslib in order to generate these files. The
+# caveat is that ctypeslib does not do a great job at handling macro functions.
+# The make rules are as follows:
+# comedi.h.xml : ../../comedi.h
+# # note that we have to use PWD here to avoid h2xml finding a system
+# # installed version of the comedilib/comedi.h file
+# h2xml ${PWD}/../../comedi.h -c -D__user="" -D"BIT(x)=(1<<(x))" \
+# -o comedi.h.xml
+#
+# comedi_h.py : comedi.h.xml
+# xml2py ./comedi.h.xml -o comedi_h.py
+# clean :
+# rm -f comedi.h.xml comedi_h.py comedi_h.pyc
diff --git a/drivers/staging/comedi/drivers/ni_routing/tools/convert_c_to_py.c b/drivers/staging/comedi/drivers/ni_routing/tools/convert_c_to_py.c
new file mode 100644
index 000000000000..dedb6f2fc678
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/tools/convert_c_to_py.c
@@ -0,0 +1,159 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <errno.h>
+#include <stdlib.h>
+
+typedef uint8_t u8;
+typedef uint16_t u16;
+typedef int8_t s8;
+#define __user
+#define BIT(x) (1UL << (x))
+
+#define NI_ROUTE_VALUE_EXTERNAL_CONVERSION 1
+
+#include "../ni_route_values.c"
+#include "../ni_device_routes.c"
+#include "all_cfiles.c"
+
+#include <stdio.h>
+
+#define RVij(rv, src, dest) ((rv)->register_values[(dest)][(src)])
+
+/*
+ * write out
+ * {
+ * "family" : "<family-name>",
+ * "register_values": {
+ * <destination0>:[src0, src1, ...],
+ * <destination0>:[src0, src1, ...],
+ * ...
+ * }
+ * }
+ */
+void family_write(const struct family_route_values *rv, FILE *fp)
+{
+ fprintf(fp,
+ " \"%s\" : {\n"
+ " # dest -> {src0:val0, src1:val1, ...}\n"
+ , rv->family);
+ for (unsigned int dest = NI_NAMES_BASE;
+ dest < (NI_NAMES_BASE + NI_NUM_NAMES);
+ ++dest) {
+ unsigned int src = NI_NAMES_BASE;
+
+ for (; src < (NI_NAMES_BASE + NI_NUM_NAMES) &&
+ RVij(rv, B(src), B(dest)) == 0; ++src)
+ ;
+
+ if (src >= (NI_NAMES_BASE + NI_NUM_NAMES))
+ continue; /* no data here */
+
+ fprintf(fp, " %u : {\n", dest);
+ for (src = NI_NAMES_BASE; src < (NI_NAMES_BASE + NI_NUM_NAMES);
+ ++src) {
+ register_type r = RVij(rv, B(src), B(dest));
+ const char *M;
+
+ if (r == 0) {
+ continue;
+ } else if (MARKED_V(r)) {
+ M = "V";
+ } else if (MARKED_I(r)) {
+ M = "I";
+ } else if (MARKED_U(r)) {
+ M = "U";
+ } else {
+ fprintf(stderr,
+ "Invalid register marking %s[%u][%u] = %u\n",
+ rv->family, dest, src, r);
+ exit(1);
+ }
+
+ fprintf(fp, " %u : \"%s(%u)\",\n",
+ src, M, UNMARK(r));
+ }
+ fprintf(fp, " },\n");
+ }
+ fprintf(fp, " },\n\n");
+}
+
+bool is_valid_ni_sig(unsigned int sig)
+{
+ return (sig >= NI_NAMES_BASE) && (sig < (NI_NAMES_BASE + NI_NUM_NAMES));
+}
+
+/*
+ * write out
+ * {
+ * "family" : "<family-name>",
+ * "register_values": {
+ * <destination0>:[src0, src1, ...],
+ * <destination0>:[src0, src1, ...],
+ * ...
+ * }
+ * }
+ */
+void device_write(const struct ni_device_routes *dR, FILE *fp)
+{
+ fprintf(fp,
+ " \"%s\" : {\n"
+ " # dest -> [src0, src1, ...]\n"
+ , dR->device);
+
+ unsigned int i = 0;
+
+ while (dR->routes[i].dest != 0) {
+ if (!is_valid_ni_sig(dR->routes[i].dest)) {
+ fprintf(stderr,
+ "Invalid NI signal value [%u] for destination %s.[%u]\n",
+ dR->routes[i].dest, dR->device, i);
+ exit(1);
+ }
+
+ fprintf(fp, " %u : [", dR->routes[i].dest);
+
+ unsigned int j = 0;
+
+ while (dR->routes[i].src[j] != 0) {
+ if (!is_valid_ni_sig(dR->routes[i].src[j])) {
+ fprintf(stderr,
+ "Invalid NI signal value [%u] for source %s.[%u].[%u]\n",
+ dR->routes[i].src[j], dR->device, i, j);
+ exit(1);
+ }
+
+ fprintf(fp, "%u,", dR->routes[i].src[j]);
+
+ ++j;
+ }
+ fprintf(fp, "],\n");
+
+ ++i;
+ }
+ fprintf(fp, " },\n\n");
+}
+
+int main(void)
+{
+ FILE *fp = fopen("ni_values.py", "w");
+
+ /* write route register values */
+ fprintf(fp, "ni_route_values = {\n");
+ for (int i = 0; ni_all_route_values[i]; ++i)
+ family_write(ni_all_route_values[i], fp);
+ fprintf(fp, "}\n\n");
+
+ /* write valid device routes */
+ fprintf(fp, "ni_device_routes = {\n");
+ for (int i = 0; ni_device_routes_list[i]; ++i)
+ device_write(ni_device_routes_list[i], fp);
+ fprintf(fp, "}\n");
+
+ /* finish; close file */
+ fclose(fp);
+ return 0;
+}
diff --git a/drivers/staging/comedi/drivers/ni_routing/tools/convert_csv_to_c.py b/drivers/staging/comedi/drivers/ni_routing/tools/convert_csv_to_c.py
new file mode 100755
index 000000000000..532eb6372a5a
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/tools/convert_csv_to_c.py
@@ -0,0 +1,503 @@
+#!/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
+import comedi_h
+import os, sys, re
+from csv_collection import CSVCollection
+
+
+def c_to_o(filename, prefix='\t\t\t\t\t ni_routing/', suffix=' \\'):
+ if not filename.endswith('.c'):
+ return ''
+ return prefix + filename.rpartition('.c')[0] + '.o' + suffix
+
+
+def routedict_to_structinit_single(name, D, return_name=False):
+ Locals = dict()
+ lines = [
+ '\t.family = "{}",'.format(name),
+ '\t.register_values = {',
+ '\t\t/*',
+ '\t\t * destination = {',
+ '\t\t * source = register value,',
+ '\t\t * ...',
+ '\t\t * }',
+ '\t\t */',
+ ]
+ if (False):
+ # print table with index0:src, index1:dest
+ D0 = D # (src-> dest->reg_value)
+ #D1 : destD
+ else:
+ D0 = dict()
+ for src, destD in D.items():
+ for dest, val in destD.items():
+ D0.setdefault(dest, {})[src] = val
+
+
+ D0 = sorted(D0.items(), key=lambda i: eval(i[0], comedi_h.__dict__, Locals))
+
+ for D0_sig, D1_D in D0:
+ D1 = sorted(D1_D.items(), key=lambda i: eval(i[0], comedi_h.__dict__, Locals))
+
+ lines.append('\t\t[B({})] = {{'.format(D0_sig))
+ for D1_sig, value in D1:
+ if not re.match('[VIU]\([^)]*\)', value):
+ sys.stderr.write('Invalid register format: {}\n'.format(repr(value)))
+ sys.stderr.write(
+ 'Register values should be formatted with V(),I(),or U()\n')
+ raise RuntimeError('Invalid register values format')
+ lines.append('\t\t\t[B({})]\t= {},'.format(D1_sig, value))
+ lines.append('\t\t},')
+ lines.append('\t},')
+
+ lines = '\n'.join(lines)
+ if return_name:
+ return N, lines
+ else:
+ return lines
+
+
+def routedict_to_routelist_single(name, D, indent=1):
+ Locals = dict()
+
+ indents = dict(
+ I0 = '\t'*(indent),
+ I1 = '\t'*(indent+1),
+ I2 = '\t'*(indent+2),
+ I3 = '\t'*(indent+3),
+ I4 = '\t'*(indent+4),
+ )
+
+ if (False):
+ # data is src -> dest-list
+ D0 = D
+ keyname = 'src'
+ valname = 'dest'
+ else:
+ # data is dest -> src-list
+ keyname = 'dest'
+ valname = 'src'
+ D0 = dict()
+ for src, destD in D.items():
+ for dest, val in destD.items():
+ D0.setdefault(dest, {})[src] = val
+
+ # Sort by order of device-global names (numerically)
+ D0 = sorted(D0.items(), key=lambda i: eval(i[0], comedi_h.__dict__, Locals))
+
+ lines = [ '{I0}.device = "{name}",\n'
+ '{I0}.routes = (struct ni_route_set[]){{'
+ .format(name=name, **indents) ]
+ for D0_sig, D1_D in D0:
+ D1 = [ k for k,v in D1_D.items() if v ]
+ D1.sort(key=lambda i: eval(i, comedi_h.__dict__, Locals))
+
+ lines.append('{I1}{{\n{I2}.{keyname} = {D0_sig},\n'
+ '{I2}.{valname} = (int[]){{'
+ .format(keyname=keyname, valname=valname, D0_sig=D0_sig, **indents)
+ )
+ for D1_sig in D1:
+ lines.append( '{I3}{D1_sig},'.format(D1_sig=D1_sig, **indents) )
+ lines.append( '{I3}0, /* Termination */'.format(**indents) )
+
+ lines.append('{I2}}}\n{I1}}},'.format(**indents))
+
+ lines.append('{I1}{{ /* Termination of list */\n{I2}.{keyname} = 0,\n{I1}}},'
+ .format(keyname=keyname, **indents))
+
+ lines.append('{I0}}},'.format(**indents))
+
+ return '\n'.join(lines)
+
+
+class DeviceRoutes(CSVCollection):
+ MKFILE_SEGMENTS = 'device-route.mk'
+ SET_C = 'ni_device_routes.c'
+ ITEMS_DIR = 'ni_device_routes'
+ EXTERN_H = 'all.h'
+ OUTPUT_DIR = 'c'
+
+ 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * The contents of this file are generated using the tools in
+ * comedi/drivers/ni_routing/tools
+ *
+ * Please use those tools to help maintain the contents of this file.
+ */
+
+#include "ni_device_routes.h"
+#include "{extern_h}"\
+""".format(filename=SET_C, extern_h=os.path.join(ITEMS_DIR, EXTERN_H))
+
+ 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * The contents of this file are generated using the tools in
+ * comedi/drivers/ni_routing/tools
+ *
+ * Please use those tools to help maintain the contents of this file.
+ */
+
+#ifndef _COMEDI_DRIVERS_NI_ROUTING_NI_DEVICE_ROUTES_EXTERN_H
+#define _COMEDI_DRIVERS_NI_ROUTING_NI_DEVICE_ROUTES_EXTERN_H
+
+#include "../ni_device_routes.h"
+
+{externs}
+
+#endif //_COMEDI_DRIVERS_NI_ROUTING_NI_DEVICE_ROUTES_EXTERN_H
+"""
+
+ 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * The contents of this file are generated using the tools in
+ * comedi/drivers/ni_routing/tools
+ *
+ * Please use those tools to help maintain the contents of this file.
+ */
+
+#include "../ni_device_routes.h"
+#include "{extern_h}"
+
+struct ni_device_routes {table_name} = {{\
+"""
+
+ def __init__(self, pattern='csv/device_routes/*.csv'):
+ super(DeviceRoutes,self).__init__(pattern)
+
+ def to_listinit(self):
+ chunks = [ self.output_file_top,
+ '',
+ 'struct ni_device_routes *const ni_device_routes_list[] = {'
+ ]
+ # put the sheets in lexical order of device numbers then bus
+ sheets = sorted(self.items(), key=lambda i : tuple(i[0].split('-')[::-1]) )
+
+ externs = []
+ objs = [c_to_o(self.SET_C)]
+
+ for sheet,D in sheets:
+ S = sheet.lower()
+ dev_table_name = 'ni_{}_device_routes'.format(S.replace('-','_'))
+ sheet_filename = os.path.join(self.ITEMS_DIR,'{}.c'.format(S))
+ externs.append('extern struct ni_device_routes {};'.format(dev_table_name))
+
+ chunks.append('\t&{},'.format(dev_table_name))
+
+ s_chunks = [
+ self.single_output_file_top.format(
+ filename = sheet_filename,
+ table_name = dev_table_name,
+ extern_h = self.EXTERN_H,
+ ),
+ routedict_to_routelist_single(S, D),
+ '};',
+ ]
+
+ objs.append(c_to_o(sheet_filename))
+
+ with open(os.path.join(self.OUTPUT_DIR, sheet_filename), 'w') as f:
+ f.write('\n'.join(s_chunks))
+ f.write('\n')
+
+ with open(os.path.join(self.OUTPUT_DIR, self.MKFILE_SEGMENTS), 'w') as f:
+ f.write('# This is the segment that should be included in comedi/drivers/Makefile\n')
+ f.write('ni_routing-objs\t\t\t\t+= \\\n')
+ f.write('\n'.join(objs))
+ f.write('\n')
+
+ EXTERN_H = os.path.join(self.ITEMS_DIR, self.EXTERN_H)
+ with open(os.path.join(self.OUTPUT_DIR, EXTERN_H), 'w') as f:
+ f.write(self.extern_header.format(
+ filename=EXTERN_H, externs='\n'.join(externs)))
+
+ chunks.append('\tNULL,') # terminate list
+ chunks.append('};')
+ return '\n'.join(chunks)
+
+ def save(self):
+ filename=os.path.join(self.OUTPUT_DIR, self.SET_C)
+
+ try:
+ os.makedirs(os.path.join(self.OUTPUT_DIR, self.ITEMS_DIR))
+ except:
+ pass
+ with open(filename,'w') as f:
+ f.write( self.to_listinit() )
+ f.write( '\n' )
+
+
+class RouteValues(CSVCollection):
+ MKFILE_SEGMENTS = 'route-values.mk'
+ SET_C = 'ni_route_values.c'
+ ITEMS_DIR = 'ni_route_values'
+ EXTERN_H = 'all.h'
+ OUTPUT_DIR = 'c'
+
+ 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * This file includes the tables that are a list of all the values of various
+ * signals routes available on NI hardware. In many cases, one does not
+ * explicitly make these routes, rather one might indicate that something is
+ * used as the source of one particular trigger or another (using
+ * *_src=TRIG_EXT).
+ *
+ * The contents of this file are generated using the tools in
+ * comedi/drivers/ni_routing/tools
+ *
+ * Please use those tools to help maintain the contents of this file.
+ */
+
+#include "ni_route_values.h"
+#include "{extern_h}"\
+""".format(filename=SET_C, extern_h=os.path.join(ITEMS_DIR, EXTERN_H))
+
+ 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * The contents of this file are generated using the tools in
+ * comedi/drivers/ni_routing/tools
+ *
+ * Please use those tools to help maintain the contents of this file.
+ */
+
+#ifndef _COMEDI_DRIVERS_NI_ROUTING_NI_ROUTE_VALUES_EXTERN_H
+#define _COMEDI_DRIVERS_NI_ROUTING_NI_ROUTE_VALUES_EXTERN_H
+
+#include "../ni_route_values.h"
+
+{externs}
+
+#endif //_COMEDI_DRIVERS_NI_ROUTING_NI_ROUTE_VALUES_EXTERN_H
+"""
+
+ 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * This file includes a list of all the values of various signals routes
+ * available on NI 660x hardware. In many cases, one does not explicitly make
+ * these routes, rather one might indicate that something is used as the source
+ * of one particular trigger or another (using *_src=TRIG_EXT).
+ *
+ * The contents of this file can be generated using the tools in
+ * comedi/drivers/ni_routing/tools. This file also contains specific notes to
+ * this family of devices.
+ *
+ * Please use those tools to help maintain the contents of this file, but be
+ * mindful to not lose the notes already made in this file, since these notes
+ * are critical to a complete undertsanding of the register values of this
+ * family.
+ */
+
+#include "../ni_route_values.h"
+#include "{extern_h}"
+
+const struct family_route_values {table_name} = {{\
+"""
+
+ def __init__(self, pattern='csv/route_values/*.csv'):
+ super(RouteValues,self).__init__(pattern)
+
+ def to_structinit(self):
+ chunks = [ self.output_file_top,
+ '',
+ 'const struct family_route_values *const ni_all_route_values[] = {'
+ ]
+ # put the sheets in lexical order for consistency
+ sheets = sorted(self.items(), key=lambda i : i[0] )
+
+ externs = []
+ objs = [c_to_o(self.SET_C)]
+
+ for sheet,D in sheets:
+ S = sheet.lower()
+ fam_table_name = '{}_route_values'.format(S.replace('-','_'))
+ sheet_filename = os.path.join(self.ITEMS_DIR,'{}.c'.format(S))
+ externs.append('extern const struct family_route_values {};'.format(fam_table_name))
+
+ chunks.append('\t&{},'.format(fam_table_name))
+
+ s_chunks = [
+ self.single_output_file_top.format(
+ filename = sheet_filename,
+ sheet = sheet.upper(),
+ table_name = fam_table_name,
+ extern_h = self.EXTERN_H,
+ ),
+ routedict_to_structinit_single(S, D),
+ '};',
+ ]
+
+ objs.append(c_to_o(sheet_filename))
+
+ with open(os.path.join(self.OUTPUT_DIR, sheet_filename), 'w') as f:
+ f.write('\n'.join(s_chunks))
+ f.write( '\n' )
+
+ with open(os.path.join(self.OUTPUT_DIR, self.MKFILE_SEGMENTS), 'w') as f:
+ f.write('# This is the segment that should be included in comedi/drivers/Makefile\n')
+ f.write('ni_routing-objs\t\t\t\t+= \\\n')
+ f.write('\n'.join(objs))
+ f.write('\n')
+
+ EXTERN_H = os.path.join(self.ITEMS_DIR, self.EXTERN_H)
+ with open(os.path.join(self.OUTPUT_DIR, EXTERN_H), 'w') as f:
+ f.write(self.extern_header.format(
+ filename=EXTERN_H, externs='\n'.join(externs)))
+
+ chunks.append('\tNULL,') # terminate list
+ chunks.append('};')
+ return '\n'.join(chunks)
+
+ def save(self):
+ filename=os.path.join(self.OUTPUT_DIR, self.SET_C)
+
+ try:
+ os.makedirs(os.path.join(self.OUTPUT_DIR, self.ITEMS_DIR))
+ except:
+ pass
+ with open(filename,'w') as f:
+ f.write( self.to_structinit() )
+ f.write( '\n' )
+
+
+
+if __name__ == '__main__':
+ import argparse
+ parser = argparse.ArgumentParser()
+ parser.add_argument( '--route_values', action='store_true',
+ help='Extract route values from csv/route_values/*.csv' )
+ parser.add_argument( '--device_routes', action='store_true',
+ help='Extract route values from csv/device_routes/*.csv' )
+ args = parser.parse_args()
+ KL = list()
+ if args.route_values:
+ KL.append( RouteValues )
+ if args.device_routes:
+ KL.append( DeviceRoutes )
+ if not KL:
+ parser.error('nothing to do...')
+ for K in KL:
+ doc = K()
+ doc.save()
diff --git a/drivers/staging/comedi/drivers/ni_routing/tools/convert_py_to_csv.py b/drivers/staging/comedi/drivers/ni_routing/tools/convert_py_to_csv.py
new file mode 100755
index 000000000000..b3e6472bac22
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/tools/convert_py_to_csv.py
@@ -0,0 +1,67 @@
+#!/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
+from itertools import chain
+
+from csv_collection import CSVCollection
+from ni_names import value_to_name
+import ni_values
+
+CSV_DIR = 'csv'
+
+def iter_src_values(D):
+ return D.items()
+
+def iter_src(D):
+ for dest in D:
+ yield dest, 1
+
+def create_csv(name, D, src_iter):
+ # have to change dest->{src:val} to src->{dest:val}
+ fieldnames = [value_to_name[i] for i in sorted(D.keys())]
+ fieldnames.insert(0, CSVCollection.source_column_name)
+
+ S = dict()
+ for dest, srcD in D.items():
+ for src,val in src_iter(srcD):
+ S.setdefault(src,{})[dest] = val
+
+ S = sorted(S.items(), key = lambda src_destD : src_destD[0])
+
+
+ csv_fname = path.join(CSV_DIR, name + '.csv')
+ with open(csv_fname, 'w') as F_csv:
+ dR = csv.DictWriter(F_csv, fieldnames, delimiter=';', quotechar='"')
+ dR.writeheader()
+
+ # now change the json back into the csv dictionaries
+ rows = [
+ dict(chain(
+ ((CSVCollection.source_column_name,value_to_name[src]),),
+ *(((value_to_name[dest],v),) for dest,v in destD.items())
+ ))
+ for src, destD in S
+ ]
+
+ dR.writerows(rows)
+
+
+def to_csv():
+ for d in ['route_values', 'device_routes']:
+ try:
+ os.makedirs(path.join(CSV_DIR,d))
+ except:
+ pass
+
+ for family, dst_src_map in ni_values.ni_route_values.items():
+ create_csv(path.join('route_values',family), dst_src_map, iter_src_values)
+
+ for device, dst_src_map in ni_values.ni_device_routes.items():
+ create_csv(path.join('device_routes',device), dst_src_map, iter_src)
+
+
+if __name__ == '__main__':
+ to_csv()
diff --git a/drivers/staging/comedi/drivers/ni_routing/tools/csv_collection.py b/drivers/staging/comedi/drivers/ni_routing/tools/csv_collection.py
new file mode 100644
index 000000000000..12617329a928
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/tools/csv_collection.py
@@ -0,0 +1,40 @@
+# SPDX-License-Identifier: GPL-2.0+
+# vim: ts=2:sw=2:et:tw=80:nowrap
+
+import os, csv, glob
+
+class CSVCollection(dict):
+ delimiter=';'
+ quotechar='"'
+ source_column_name = 'Sources / Destinations'
+
+ """
+ This class is a dictionary representation of the collection of sheets that
+ exist in a given .ODS file.
+ """
+ def __init__(self, pattern, skip_commented_lines=True, strip_lines=True):
+ super(CSVCollection, self).__init__()
+ self.pattern = pattern
+ C = '#' if skip_commented_lines else 'blahblahblah'
+
+ if strip_lines:
+ strip = lambda s:s.strip()
+ else:
+ strip = lambda s:s
+
+ # load all CSV files
+ key = self.source_column_name
+ for fname in glob.glob(pattern):
+ with open(fname) as F:
+ dR = csv.DictReader(F, delimiter=self.delimiter,
+ quotechar=self.quotechar)
+ name = os.path.basename(fname).partition('.')[0]
+ D = {
+ r[key]:{f:strip(c) for f,c in r.items()
+ if f != key and f[:1] not in ['', C] and
+ strip(c)[:1] not in ['', C]}
+ for r in dR if r[key][:1] not in ['', C]
+ }
+ # now, go back through and eliminate all empty dictionaries
+ D = {k:v for k,v in D.items() if v}
+ self[name] = D
diff --git a/drivers/staging/comedi/drivers/ni_routing/tools/make_blank_csv.py b/drivers/staging/comedi/drivers/ni_routing/tools/make_blank_csv.py
new file mode 100755
index 000000000000..89c90a0ba24d
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/tools/make_blank_csv.py
@@ -0,0 +1,32 @@
+#!/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
+
+from csv_collection import CSVCollection
+from ni_names import value_to_name
+
+CSV_DIR = 'csv'
+
+def to_csv():
+ try:
+ os.makedirs(CSV_DIR)
+ except:
+ pass
+
+ csv_fname = path.join(CSV_DIR, 'blank_route_table.csv')
+
+ fieldnames = [sig for sig_val, sig in sorted(value_to_name.items())]
+ fieldnames.insert(0, CSVCollection.source_column_name)
+
+ with open(csv_fname, 'w') as F_csv:
+ dR = csv.DictWriter(F_csv, fieldnames, delimiter=';', quotechar='"')
+ dR.writeheader()
+
+ for sig in fieldnames[1:]:
+ dR.writerow({CSVCollection.source_column_name: sig})
+
+if __name__ == '__main__':
+ to_csv()
diff --git a/drivers/staging/comedi/drivers/ni_routing/tools/ni_names.py b/drivers/staging/comedi/drivers/ni_routing/tools/ni_names.py
new file mode 100644
index 000000000000..5f9b825968b1
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_routing/tools/ni_names.py
@@ -0,0 +1,56 @@
+# 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.
+"""
+
+# 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
+import comedi_h
+
+
+ni_macros = (
+ 'NI_PFI',
+ 'TRIGGER_LINE',
+ 'NI_RTSI_BRD',
+ 'NI_CtrSource',
+ 'NI_CtrGate',
+ 'NI_CtrAux',
+ 'NI_CtrA',
+ 'NI_CtrB',
+ 'NI_CtrZ',
+ 'NI_CtrArmStartTrigger',
+ 'NI_CtrInternalOutput',
+ 'NI_CtrOut',
+ 'NI_CtrSampleClock',
+)
+
+def get_ni_names():
+ name_dict = dict()
+
+ # load all the static names; start with those that do not begin with NI_
+ name_dict['PXI_Star'] = comedi_h.PXI_Star
+ name_dict['PXI_Clk10'] = comedi_h.PXI_Clk10
+
+ #load all macro values
+ for fun in ni_macros:
+ f = getattr(comedi_h, fun)
+ name_dict.update({
+ '{}({})'.format(fun,i):f(i) for i in range(1 + f(-1) - f(0))
+ })
+
+ #load everything else in ni_common_signal_names enum
+ name_dict.update({
+ k:v for k,v in comedi_h.__dict__.items()
+ if k.startswith('NI_') and (not callable(v)) and
+ comedi_h.NI_COUNTER_NAMES_MAX < v < (comedi_h.NI_NAMES_BASE + comedi_h.NI_NUM_NAMES)
+ })
+
+ # now create reverse lookup (value -> name)
+
+ val_dict = {v:k for k,v in name_dict.items()}
+
+ return name_dict, val_dict
+
+name_to_value, value_to_name = get_ni_names()
diff --git a/drivers/staging/comedi/drivers/ni_stc.h b/drivers/staging/comedi/drivers/ni_stc.h
index 831088c5cabb..6c023b40fb53 100644
--- a/drivers/staging/comedi/drivers/ni_stc.h
+++ b/drivers/staging/comedi/drivers/ni_stc.h
@@ -15,6 +15,7 @@
#define _COMEDI_NI_STC_H
#include "ni_tio.h"
+#include "ni_routes.h"
/*
* Registers in the National Instruments DAQ-STC chip
@@ -253,6 +254,8 @@
#define NISTC_RTSI_TRIG_OLD_CLK_CHAN 7
#define NISTC_RTSI_TRIG_NUM_CHAN(_m) ((_m) ? 8 : 7)
#define NISTC_RTSI_TRIG_DIR(_c, _m) ((_m) ? BIT(8 + (_c)) : BIT(7 + (_c)))
+#define NISTC_RTSI_TRIG_DIR_SUB_SEL1 BIT(2) /* only for M-Series */
+#define NISTC_RTSI_TRIG_DIR_SUB_SEL1_SHIFT 2 /* only for M-Series */
#define NISTC_RTSI_TRIG_USE_CLK BIT(1)
#define NISTC_RTSI_TRIG_DRV_CLK BIT(0)
@@ -281,11 +284,15 @@
#define NISTC_ATRIG_ETC_REG 61
#define NISTC_ATRIG_ETC_GPFO_1_ENA BIT(15)
#define NISTC_ATRIG_ETC_GPFO_0_ENA BIT(14)
-#define NISTC_ATRIG_ETC_GPFO_0_SEL(x) (((x) & 0x3) << 11)
+#define NISTC_ATRIG_ETC_GPFO_0_SEL(x) (((x) & 0x7) << 11)
+#define NISTC_ATRIG_ETC_GPFO_0_SEL_TO_SRC(x) (((x) >> 11) & 0x7)
#define NISTC_ATRIG_ETC_GPFO_1_SEL BIT(7)
+#define NISTC_ATRIG_ETC_GPFO_1_SEL_TO_SRC(x) (((x) >> 7) & 0x1)
#define NISTC_ATRIG_ETC_DRV BIT(4)
#define NISTC_ATRIG_ETC_ENA BIT(3)
#define NISTC_ATRIG_ETC_MODE(x) (((x) & 0x7) << 0)
+#define NISTC_GPFO_0_G_OUT 0 /* input to GPFO_0_SEL for Ctr0Out */
+#define NISTC_GPFO_1_G_OUT 0 /* input to GPFO_1_SEL for Ctr1Out */
#define NISTC_AI_START_STOP_REG 62
#define NISTC_AI_START_POLARITY BIT(15)
@@ -422,6 +429,7 @@
#define NISTC_RTSI_TRIGA_OUT_REG 79
#define NISTC_RTSI_TRIGB_OUT_REG 80
#define NISTC_RTSI_TRIGB_SUB_SEL1 BIT(15) /* not for M-Series */
+#define NISTC_RTSI_TRIGB_SUB_SEL1_SHIFT 15 /* not for M-Series */
#define NISTC_RTSI_TRIG(_c, _s) (((_s) & 0xf) << (((_c) % 4) * 4))
#define NISTC_RTSI_TRIG_MASK(_c) NISTC_RTSI_TRIG((_c), 0xf)
#define NISTC_RTSI_TRIG_TO_SRC(_c, _b) (((_b) >> (((_c) % 4) * 4)) & 0xf)
@@ -953,6 +961,7 @@ struct ni_board_struct {
int reg_type;
unsigned int has_8255:1;
unsigned int has_32dio_chan:1;
+ unsigned int dio_speed; /* not for e-series */
enum caldac_enum caldac[3];
};
@@ -962,6 +971,7 @@ struct ni_board_struct {
#define NUM_GPCT 2
#define NUM_PFI_OUTPUT_SELECT_REGS 6
+#define NUM_RTSI_SHARED_MUXS (NI_RTSI_BRD(-1) - NI_RTSI_BRD(0) + 1)
#define M_SERIES_EEPROM_SIZE 1024
@@ -1057,6 +1067,73 @@ struct ni_private {
* possible.
*/
unsigned int ao_needs_arming:1;
+
+ /* device signal route tables */
+ struct ni_route_tables routing_tables;
+
+ /*
+ * Number of clients (RTSI lines) for current RTSI MUX source.
+ *
+ * This allows resource management of RTSI board/shared mux lines by
+ * marking the RTSI line that is using a particular MUX. Currently,
+ * these lines are only automatically allocated based on source of the
+ * route requested. Furthermore, the only way that this auto-allocation
+ * and configuration works is via the globally-named ni signal/terminal
+ * names.
+ */
+ u8 rtsi_shared_mux_usage[NUM_RTSI_SHARED_MUXS];
+
+ /*
+ * softcopy register for rtsi shared mux/board lines.
+ * For e-series, the bit layout of this register is
+ * (docs: mhddk/nieseries/ChipObjects/tSTC.{h,ipp},
+ * DAQ-STC, Jan 1999, 340934B-01):
+ * bits 0:2 -- NI_RTSI_BRD(0) source selection
+ * bits 3:5 -- NI_RTSI_BRD(1) source selection
+ * bits 6:8 -- NI_RTSI_BRD(2) source selection
+ * bits 9:11 -- NI_RTSI_BRD(3) source selection
+ * bit 12 -- NI_RTSI_BRD(0) direction, 0:input, 1:output
+ * bit 13 -- NI_RTSI_BRD(1) direction, 0:input, 1:output
+ * bit 14 -- NI_RTSI_BRD(2) direction, 0:input, 1:output
+ * bit 15 -- NI_RTSI_BRD(3) direction, 0:input, 1:output
+ * According to DAQ-STC:
+ * RTSI Board Interface--Configured as an input, each bidirectional
+ * RTSI_BRD pin can drive any of the seven RTSI_TRIGGER pins.
+ * RTSI_BRD<0..1> can also be driven by AI STOP and RTSI_BRD<2..3>
+ * can also be driven by the AI START and SCAN_IN_PROG signals.
+ * These pins provide a mechanism for additional board-level signals
+ * to be sent on or received from the RTSI bus.
+ * Couple of comments:
+ * - Neither the DAQ-STC nor the MHDDK is clear on what the direction
+ * of the RTSI_BRD pins actually means. There does not appear to be
+ * any clear indication on what "output" would mean, since the point
+ * of the RTSI_BRD lines is to always drive one of the
+ * RTSI_TRIGGER<0..6> lines.
+ * - The DAQ-STC also indicates that the NI_RTSI_BRD lines can be
+ * driven by any of the RTSI_TRIGGER<0..6> lines.
+ * But, looking at valid device routes, as visually imported from
+ * NI-MAX, there appears to be only one family (so far) that has the
+ * ability to route a signal from one TRIGGER_LINE to another
+ * TRIGGER_LINE: the 653x family of DIO devices.
+ *
+ * For m-series, the bit layout of this register is
+ * (docs: mhddk/nimseries/ChipObjects/tMSeries.{h,ipp}):
+ * bits 0:3 -- NI_RTSI_BRD(0) source selection
+ * bits 4:7 -- NI_RTSI_BRD(1) source selection
+ * bits 8:11 -- NI_RTSI_BRD(2) source selection
+ * bits 12:15 -- NI_RTSI_BRD(3) source selection
+ * Note: The m-series does not have any option to change direction of
+ * NI_RTSI_BRD muxes. Furthermore, there are no register values that
+ * indicate the ability to have TRIGGER_LINES driving the output of
+ * the NI_RTSI_BRD muxes.
+ */
+ u16 rtsi_shared_mux_reg;
+
+ /*
+ * Number of clients (RTSI lines) for current RGOUT0 path.
+ * Stored in part of in RTSI_TRIG_DIR or RTSI_TRIGB registers
+ */
+ u8 rgout0_usage;
};
static const struct comedi_lrange range_ni_E_ao_ext;
diff --git a/drivers/staging/comedi/drivers/ni_tio.c b/drivers/staging/comedi/drivers/ni_tio.c
index ef919b21b7d9..0eb388c0e1f0 100644
--- a/drivers/staging/comedi/drivers/ni_tio.c
+++ b/drivers/staging/comedi/drivers/ni_tio.c
@@ -818,10 +818,79 @@ static int ni_tio_get_clock_src(struct ni_gpct *counter,
return 0;
}
+static inline void ni_tio_set_gate_raw(struct ni_gpct *counter,
+ unsigned int gate_source)
+{
+ ni_tio_set_bits(counter, NITIO_INPUT_SEL_REG(counter->counter_index),
+ GI_GATE_SEL_MASK, GI_GATE_SEL(gate_source));
+}
+
+static inline void ni_tio_set_gate2_raw(struct ni_gpct *counter,
+ unsigned int gate_source)
+{
+ ni_tio_set_bits(counter, NITIO_GATE2_REG(counter->counter_index),
+ GI_GATE2_SEL_MASK, GI_GATE2_SEL(gate_source));
+}
+
+/* Set the mode bits for gate. */
+static inline void ni_tio_set_gate_mode(struct ni_gpct *counter,
+ unsigned int src)
+{
+ unsigned int mode_bits = 0;
+
+ if (CR_CHAN(src) & NI_GPCT_DISABLED_GATE_SELECT) {
+ /*
+ * Allowing bitwise comparison here to allow non-zero raw
+ * register value to be used for channel when disabling.
+ */
+ mode_bits = GI_GATING_DISABLED;
+ } else {
+ if (src & CR_INVERT)
+ mode_bits |= GI_GATE_POL_INVERT;
+ if (src & CR_EDGE)
+ mode_bits |= GI_RISING_EDGE_GATING;
+ else
+ mode_bits |= GI_LEVEL_GATING;
+ }
+ ni_tio_set_bits(counter, NITIO_MODE_REG(counter->counter_index),
+ GI_GATE_POL_INVERT | GI_GATING_MODE_MASK,
+ mode_bits);
+}
+
+/*
+ * Set the mode bits for gate2.
+ *
+ * Previously, the code this function represents did not actually write anything
+ * to the register. Rather, writing to this register was reserved for the code
+ * ni ni_tio_set_gate2_raw.
+ */
+static inline void ni_tio_set_gate2_mode(struct ni_gpct *counter,
+ unsigned int src)
+{
+ /*
+ * The GI_GATE2_MODE bit was previously set in the code that also sets
+ * the gate2 source.
+ * We'll set mode bits _after_ source bits now, and thus, this function
+ * will effectively enable the second gate after all bits are set.
+ */
+ unsigned int mode_bits = GI_GATE2_MODE;
+
+ if (CR_CHAN(src) & NI_GPCT_DISABLED_GATE_SELECT)
+ /*
+ * Allowing bitwise comparison here to allow non-zero raw
+ * register value to be used for channel when disabling.
+ */
+ mode_bits = GI_GATING_DISABLED;
+ if (src & CR_INVERT)
+ mode_bits |= GI_GATE2_POL_INVERT;
+
+ ni_tio_set_bits(counter, NITIO_GATE2_REG(counter->counter_index),
+ GI_GATE2_POL_INVERT | GI_GATE2_MODE, mode_bits);
+}
+
static int ni_660x_set_gate(struct ni_gpct *counter, unsigned int gate_source)
{
unsigned int chan = CR_CHAN(gate_source);
- unsigned int cidx = counter->counter_index;
unsigned int gate_sel;
unsigned int i;
@@ -854,15 +923,13 @@ static int ni_660x_set_gate(struct ni_gpct *counter, unsigned int gate_source)
break;
return -EINVAL;
}
- ni_tio_set_bits(counter, NITIO_INPUT_SEL_REG(cidx),
- GI_GATE_SEL_MASK, GI_GATE_SEL(gate_sel));
+ ni_tio_set_gate_raw(counter, gate_sel);
return 0;
}
static int ni_m_set_gate(struct ni_gpct *counter, unsigned int gate_source)
{
unsigned int chan = CR_CHAN(gate_source);
- unsigned int cidx = counter->counter_index;
unsigned int gate_sel;
unsigned int i;
@@ -896,17 +963,13 @@ static int ni_m_set_gate(struct ni_gpct *counter, unsigned int gate_source)
break;
return -EINVAL;
}
- ni_tio_set_bits(counter, NITIO_INPUT_SEL_REG(cidx),
- GI_GATE_SEL_MASK, GI_GATE_SEL(gate_sel));
+ ni_tio_set_gate_raw(counter, gate_sel);
return 0;
}
static int ni_660x_set_gate2(struct ni_gpct *counter, unsigned int gate_source)
{
- struct ni_gpct_device *counter_dev = counter->counter_dev;
- unsigned int cidx = counter->counter_index;
unsigned int chan = CR_CHAN(gate_source);
- unsigned int gate2_reg = NITIO_GATE2_REG(cidx);
unsigned int gate2_sel;
unsigned int i;
@@ -940,94 +1003,106 @@ static int ni_660x_set_gate2(struct ni_gpct *counter, unsigned int gate_source)
break;
return -EINVAL;
}
- counter_dev->regs[gate2_reg] |= GI_GATE2_MODE;
- counter_dev->regs[gate2_reg] &= ~GI_GATE2_SEL_MASK;
- counter_dev->regs[gate2_reg] |= GI_GATE2_SEL(gate2_sel);
- ni_tio_write(counter, counter_dev->regs[gate2_reg], gate2_reg);
+ ni_tio_set_gate2_raw(counter, gate2_sel);
return 0;
}
static int ni_m_set_gate2(struct ni_gpct *counter, unsigned int gate_source)
{
- struct ni_gpct_device *counter_dev = counter->counter_dev;
- unsigned int cidx = counter->counter_index;
- unsigned int chan = CR_CHAN(gate_source);
- unsigned int gate2_reg = NITIO_GATE2_REG(cidx);
- unsigned int gate2_sel;
-
/*
* FIXME: We don't know what the m-series second gate codes are,
* so we'll just pass the bits through for now.
*/
- switch (chan) {
- default:
- gate2_sel = chan & 0x1f;
+ ni_tio_set_gate2_raw(counter, gate_source);
+ return 0;
+}
+
+int ni_tio_set_gate_src_raw(struct ni_gpct *counter,
+ unsigned int gate, unsigned int src)
+{
+ struct ni_gpct_device *counter_dev = counter->counter_dev;
+
+ switch (gate) {
+ case 0:
+ /* 1. start by disabling gate */
+ ni_tio_set_gate_mode(counter, NI_GPCT_DISABLED_GATE_SELECT);
+ /* 2. set the requested gate source */
+ ni_tio_set_gate_raw(counter, src);
+ /* 3. reenable & set mode to starts things back up */
+ ni_tio_set_gate_mode(counter, src);
+ break;
+ case 1:
+ if (!ni_tio_has_gate2_registers(counter_dev))
+ return -EINVAL;
+
+ /* 1. start by disabling gate */
+ ni_tio_set_gate2_mode(counter, NI_GPCT_DISABLED_GATE_SELECT);
+ /* 2. set the requested gate source */
+ ni_tio_set_gate2_raw(counter, src);
+ /* 3. reenable & set mode to starts things back up */
+ ni_tio_set_gate2_mode(counter, src);
break;
+ default:
+ return -EINVAL;
}
- counter_dev->regs[gate2_reg] |= GI_GATE2_MODE;
- counter_dev->regs[gate2_reg] &= ~GI_GATE2_SEL_MASK;
- counter_dev->regs[gate2_reg] |= GI_GATE2_SEL(gate2_sel);
- ni_tio_write(counter, counter_dev->regs[gate2_reg], gate2_reg);
return 0;
}
+EXPORT_SYMBOL_GPL(ni_tio_set_gate_src_raw);
int ni_tio_set_gate_src(struct ni_gpct *counter,
unsigned int gate, unsigned int src)
{
struct ni_gpct_device *counter_dev = counter->counter_dev;
- unsigned int cidx = counter->counter_index;
- unsigned int chan = CR_CHAN(src);
- unsigned int gate2_reg = NITIO_GATE2_REG(cidx);
- unsigned int mode = 0;
+ /*
+ * mask off disable flag. This high bit still passes CR_CHAN.
+ * Doing this allows one to both set the gate as disabled, but also
+ * change the route value of the gate.
+ */
+ int chan = CR_CHAN(src) & (~NI_GPCT_DISABLED_GATE_SELECT);
+ int ret;
switch (gate) {
case 0:
- if (chan == NI_GPCT_DISABLED_GATE_SELECT) {
- ni_tio_set_bits(counter, NITIO_MODE_REG(cidx),
- GI_GATING_MODE_MASK,
- GI_GATING_DISABLED);
- return 0;
- }
- if (src & CR_INVERT)
- mode |= GI_GATE_POL_INVERT;
- if (src & CR_EDGE)
- mode |= GI_RISING_EDGE_GATING;
- else
- mode |= GI_LEVEL_GATING;
- ni_tio_set_bits(counter, NITIO_MODE_REG(cidx),
- GI_GATE_POL_INVERT | GI_GATING_MODE_MASK,
- mode);
+ /* 1. start by disabling gate */
+ ni_tio_set_gate_mode(counter, NI_GPCT_DISABLED_GATE_SELECT);
+ /* 2. set the requested gate source */
switch (counter_dev->variant) {
case ni_gpct_variant_e_series:
case ni_gpct_variant_m_series:
- default:
- return ni_m_set_gate(counter, src);
+ ret = ni_m_set_gate(counter, chan);
+ break;
case ni_gpct_variant_660x:
- return ni_660x_set_gate(counter, src);
+ ret = ni_660x_set_gate(counter, chan);
+ break;
+ default:
+ return -EINVAL;
}
+ if (ret)
+ return ret;
+ /* 3. reenable & set mode to starts things back up */
+ ni_tio_set_gate_mode(counter, src);
break;
case 1:
if (!ni_tio_has_gate2_registers(counter_dev))
return -EINVAL;
- if (chan == NI_GPCT_DISABLED_GATE_SELECT) {
- counter_dev->regs[gate2_reg] &= ~GI_GATE2_MODE;
- ni_tio_write(counter, counter_dev->regs[gate2_reg],
- gate2_reg);
- return 0;
- }
- if (src & CR_INVERT)
- counter_dev->regs[gate2_reg] |= GI_GATE2_POL_INVERT;
- else
- counter_dev->regs[gate2_reg] &= ~GI_GATE2_POL_INVERT;
+ /* 1. start by disabling gate */
+ ni_tio_set_gate2_mode(counter, NI_GPCT_DISABLED_GATE_SELECT);
+ /* 2. set the requested gate source */
switch (counter_dev->variant) {
case ni_gpct_variant_m_series:
- return ni_m_set_gate2(counter, src);
+ ret = ni_m_set_gate2(counter, chan);
+ break;
case ni_gpct_variant_660x:
- return ni_660x_set_gate2(counter, src);
+ ret = ni_660x_set_gate2(counter, chan);
+ break;
default:
return -EINVAL;
}
+ if (ret)
+ return ret;
+ /* 3. reenable & set mode to starts things back up */
+ ni_tio_set_gate2_mode(counter, src);
break;
default:
return -EINVAL;
@@ -1047,19 +1122,21 @@ static int ni_tio_set_other_src(struct ni_gpct *counter, unsigned int index,
return -EINVAL;
abz_reg = NITIO_ABZ_REG(cidx);
- switch (index) {
- case NI_GPCT_SOURCE_ENCODER_A:
+
+ /* allow for new device-global names */
+ if (index == NI_GPCT_SOURCE_ENCODER_A ||
+ (index >= NI_CtrA(0) && index <= NI_CtrA(-1))) {
shift = 10;
- break;
- case NI_GPCT_SOURCE_ENCODER_B:
+ } else if (index == NI_GPCT_SOURCE_ENCODER_B ||
+ (index >= NI_CtrB(0) && index <= NI_CtrB(-1))) {
shift = 5;
- break;
- case NI_GPCT_SOURCE_ENCODER_Z:
+ } else if (index == NI_GPCT_SOURCE_ENCODER_Z ||
+ (index >= NI_CtrZ(0) && index <= NI_CtrZ(-1))) {
shift = 0;
- break;
- default:
+ } else {
return -EINVAL;
}
+
mask = 0x1f << shift;
if (source > 0x1f)
source = 0x1f; /* Disable gate */
@@ -1070,6 +1147,39 @@ static int ni_tio_set_other_src(struct ni_gpct *counter, unsigned int index,
return 0;
}
+static int ni_tio_get_other_src(struct ni_gpct *counter, unsigned int index,
+ unsigned int *source)
+{
+ struct ni_gpct_device *counter_dev = counter->counter_dev;
+ unsigned int cidx = counter->counter_index;
+ unsigned int abz_reg, shift, mask;
+
+ if (counter_dev->variant != ni_gpct_variant_m_series)
+ /* A,B,Z only valid for m-series */
+ return -EINVAL;
+
+ abz_reg = NITIO_ABZ_REG(cidx);
+
+ /* allow for new device-global names */
+ if (index == NI_GPCT_SOURCE_ENCODER_A ||
+ (index >= NI_CtrA(0) && index <= NI_CtrA(-1))) {
+ shift = 10;
+ } else if (index == NI_GPCT_SOURCE_ENCODER_B ||
+ (index >= NI_CtrB(0) && index <= NI_CtrB(-1))) {
+ shift = 5;
+ } else if (index == NI_GPCT_SOURCE_ENCODER_Z ||
+ (index >= NI_CtrZ(0) && index <= NI_CtrZ(-1))) {
+ shift = 0;
+ } else {
+ return -EINVAL;
+ }
+
+ mask = 0x1f;
+
+ *source = (ni_tio_get_soft_copy(counter, abz_reg) >> shift) & mask;
+ return 0;
+}
+
static int ni_660x_gate_to_generic_gate(unsigned int gate, unsigned int *src)
{
unsigned int source;
@@ -1112,7 +1222,7 @@ static int ni_660x_gate_to_generic_gate(unsigned int gate, unsigned int *src)
}
*src = source;
return 0;
-};
+}
static int ni_m_gate_to_generic_gate(unsigned int gate, unsigned int *src)
{
@@ -1165,7 +1275,7 @@ static int ni_m_gate_to_generic_gate(unsigned int gate, unsigned int *src)
}
*src = source;
return 0;
-};
+}
static int ni_660x_gate2_to_generic_gate(unsigned int gate, unsigned int *src)
{
@@ -1212,7 +1322,7 @@ static int ni_660x_gate2_to_generic_gate(unsigned int gate, unsigned int *src)
}
*src = source;
return 0;
-};
+}
static int ni_m_gate2_to_generic_gate(unsigned int gate, unsigned int *src)
{
@@ -1222,32 +1332,60 @@ static int ni_m_gate2_to_generic_gate(unsigned int gate, unsigned int *src)
*/
*src = gate;
return 0;
-};
+}
+
+static inline unsigned int ni_tio_get_gate_mode(struct ni_gpct *counter)
+{
+ unsigned int mode = ni_tio_get_soft_copy(
+ counter, NITIO_MODE_REG(counter->counter_index));
+ unsigned int ret = 0;
+
+ if ((mode & GI_GATING_MODE_MASK) == GI_GATING_DISABLED)
+ ret |= NI_GPCT_DISABLED_GATE_SELECT;
+ if (mode & GI_GATE_POL_INVERT)
+ ret |= CR_INVERT;
+ if ((mode & GI_GATING_MODE_MASK) != GI_LEVEL_GATING)
+ ret |= CR_EDGE;
+
+ return ret;
+}
+
+static inline unsigned int ni_tio_get_gate2_mode(struct ni_gpct *counter)
+{
+ unsigned int mode = ni_tio_get_soft_copy(
+ counter, NITIO_GATE2_REG(counter->counter_index));
+ unsigned int ret = 0;
+
+ if (!(mode & GI_GATE2_MODE))
+ ret |= NI_GPCT_DISABLED_GATE_SELECT;
+ if (mode & GI_GATE2_POL_INVERT)
+ ret |= CR_INVERT;
+
+ return ret;
+}
+
+static inline unsigned int ni_tio_get_gate_val(struct ni_gpct *counter)
+{
+ return GI_BITS_TO_GATE(ni_tio_get_soft_copy(counter,
+ NITIO_INPUT_SEL_REG(counter->counter_index)));
+}
+
+static inline unsigned int ni_tio_get_gate2_val(struct ni_gpct *counter)
+{
+ return GI_BITS_TO_GATE2(ni_tio_get_soft_copy(counter,
+ NITIO_GATE2_REG(counter->counter_index)));
+}
static int ni_tio_get_gate_src(struct ni_gpct *counter, unsigned int gate_index,
unsigned int *gate_source)
{
- struct ni_gpct_device *counter_dev = counter->counter_dev;
- unsigned int cidx = counter->counter_index;
- unsigned int mode;
- unsigned int reg;
unsigned int gate;
int ret;
- mode = ni_tio_get_soft_copy(counter, NITIO_MODE_REG(cidx));
- if (((mode & GI_GATING_MODE_MASK) == GI_GATING_DISABLED) ||
- (gate_index == 1 &&
- !(counter_dev->regs[NITIO_GATE2_REG(cidx)] & GI_GATE2_MODE))) {
- *gate_source = NI_GPCT_DISABLED_GATE_SELECT;
- return 0;
- }
-
switch (gate_index) {
case 0:
- reg = NITIO_INPUT_SEL_REG(cidx);
- gate = GI_BITS_TO_GATE(ni_tio_get_soft_copy(counter, reg));
-
- switch (counter_dev->variant) {
+ gate = ni_tio_get_gate_val(counter);
+ switch (counter->counter_dev->variant) {
case ni_gpct_variant_e_series:
case ni_gpct_variant_m_series:
default:
@@ -1259,16 +1397,11 @@ static int ni_tio_get_gate_src(struct ni_gpct *counter, unsigned int gate_index,
}
if (ret)
return ret;
- if (mode & GI_GATE_POL_INVERT)
- *gate_source |= CR_INVERT;
- if ((mode & GI_GATING_MODE_MASK) != GI_LEVEL_GATING)
- *gate_source |= CR_EDGE;
+ *gate_source |= ni_tio_get_gate_mode(counter);
break;
case 1:
- reg = NITIO_GATE2_REG(cidx);
- gate = GI_BITS_TO_GATE2(counter_dev->regs[reg]);
-
- switch (counter_dev->variant) {
+ gate = ni_tio_get_gate2_val(counter);
+ switch (counter->counter_dev->variant) {
case ni_gpct_variant_e_series:
case ni_gpct_variant_m_series:
default:
@@ -1280,11 +1413,26 @@ static int ni_tio_get_gate_src(struct ni_gpct *counter, unsigned int gate_index,
}
if (ret)
return ret;
- if (counter_dev->regs[reg] & GI_GATE2_POL_INVERT)
- *gate_source |= CR_INVERT;
- /* second gate can't have edge/level mode set independently */
- if ((mode & GI_GATING_MODE_MASK) != GI_LEVEL_GATING)
- *gate_source |= CR_EDGE;
+ *gate_source |= ni_tio_get_gate2_mode(counter);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int ni_tio_get_gate_src_raw(struct ni_gpct *counter,
+ unsigned int gate_index,
+ unsigned int *gate_source)
+{
+ switch (gate_index) {
+ case 0:
+ *gate_source = ni_tio_get_gate_mode(counter)
+ | ni_tio_get_gate_val(counter);
+ break;
+ case 1:
+ *gate_source = ni_tio_get_gate2_mode(counter)
+ | ni_tio_get_gate2_val(counter);
break;
default:
return -EINVAL;
@@ -1347,6 +1495,107 @@ 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.
+ *
+ * If the terminal for the destination is not already configured as an output,
+ * this function returns -EINVAL as error.
+ *
+ * Return: the register value of the destination output selector;
+ * -EINVAL if terminal is not configured for output.
+ */
+int ni_tio_get_routing(struct ni_gpct_device *counter_dev, unsigned int dest)
+{
+ /* we need to know the actual counter below... */
+ int ctr_index = (dest - NI_COUNTER_NAMES_BASE) % NI_MAX_COUNTERS;
+ struct ni_gpct *counter = &counter_dev->counters[ctr_index];
+ int ret = 1;
+ unsigned int reg;
+
+ if (dest >= NI_CtrA(0) && dest <= NI_CtrZ(-1)) {
+ ret = ni_tio_get_other_src(counter, dest, &reg);
+ } else if (dest >= NI_CtrGate(0) && dest <= NI_CtrGate(-1)) {
+ ret = ni_tio_get_gate_src_raw(counter, 0, &reg);
+ } else if (dest >= NI_CtrAux(0) && dest <= NI_CtrAux(-1)) {
+ ret = ni_tio_get_gate_src_raw(counter, 1, &reg);
+ /*
+ * This case is not possible through this interface. A user must use
+ * INSN_CONFIG_SET_CLOCK_SRC instead.
+ * } else if (dest >= NI_CtrSource(0) && dest <= NI_CtrSource(-1)) {
+ * ret = ni_tio_set_clock_src(counter, &reg, &period_ns);
+ */
+ }
+
+ if (ret)
+ return -EINVAL;
+
+ return reg;
+}
+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:
+ * 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
+ * destination/gate. These mode bits might include a bitwise or of
+ * CR_INVERT and CR_EDGE. Note that the calling function should
+ * have already validated the correctness of this value.
+ */
+int ni_tio_set_routing(struct ni_gpct_device *counter_dev, unsigned int dest,
+ unsigned int reg)
+{
+ /* we need to know the actual counter below... */
+ int ctr_index = (dest - NI_COUNTER_NAMES_BASE) % NI_MAX_COUNTERS;
+ struct ni_gpct *counter = &counter_dev->counters[ctr_index];
+ int ret;
+
+ if (dest >= NI_CtrA(0) && dest <= NI_CtrZ(-1)) {
+ ret = ni_tio_set_other_src(counter, dest, reg);
+ } else if (dest >= NI_CtrGate(0) && dest <= NI_CtrGate(-1)) {
+ ret = ni_tio_set_gate_src_raw(counter, 0, reg);
+ } else if (dest >= NI_CtrAux(0) && dest <= NI_CtrAux(-1)) {
+ ret = ni_tio_set_gate_src_raw(counter, 1, reg);
+ /*
+ * This case is not possible through this interface. A user must use
+ * INSN_CONFIG_SET_CLOCK_SRC instead.
+ * } else if (dest >= NI_CtrSource(0) && dest <= NI_CtrSource(-1)) {
+ * ret = ni_tio_set_clock_src(counter, reg, period_ns);
+ */
+ } else {
+ return -EINVAL;
+ }
+
+ return ret;
+}
+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.
+ */
+int ni_tio_unset_routing(struct ni_gpct_device *counter_dev, unsigned int dest)
+{
+ if (dest >= NI_GATES_NAMES_BASE && dest <= NI_GATES_NAMES_MAX)
+ /* Disable gate (via mode bits) and set to default 0-value */
+ return ni_tio_set_routing(counter_dev, dest,
+ NI_GPCT_DISABLED_GATE_SELECT);
+ /*
+ * This case is not possible through this interface. A user must use
+ * INSN_CONFIG_SET_CLOCK_SRC instead.
+ * if (dest >= NI_CtrSource(0) && dest <= NI_CtrSource(-1))
+ * return ni_tio_set_clock_src(counter, reg, period_ns);
+ */
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(ni_tio_unset_routing);
+
static unsigned int ni_tio_read_sw_save_reg(struct comedi_device *dev,
struct comedi_subdevice *s)
{
@@ -1504,13 +1753,15 @@ ni_gpct_device_construct(struct comedi_device *dev,
unsigned int (*read)(struct ni_gpct *counter,
enum ni_gpct_register reg),
enum ni_gpct_variant variant,
- unsigned int num_counters)
+ unsigned int num_counters,
+ unsigned int counters_per_chip,
+ const struct ni_route_tables *routing_tables)
{
struct ni_gpct_device *counter_dev;
struct ni_gpct *counter;
unsigned int i;
- if (num_counters == 0)
+ if (num_counters == 0 || counters_per_chip == 0)
return NULL;
counter_dev = kzalloc(sizeof(*counter_dev), GFP_KERNEL);
@@ -1521,6 +1772,7 @@ ni_gpct_device_construct(struct comedi_device *dev,
counter_dev->write = write;
counter_dev->read = read;
counter_dev->variant = variant;
+ counter_dev->routing_tables = routing_tables;
spin_lock_init(&counter_dev->regs_lock);
@@ -1534,9 +1786,12 @@ ni_gpct_device_construct(struct comedi_device *dev,
for (i = 0; i < num_counters; ++i) {
counter = &counter_dev->counters[i];
counter->counter_dev = counter_dev;
+ counter->chip_index = i / counters_per_chip;
+ counter->counter_index = i % counters_per_chip;
spin_lock_init(&counter->lock);
}
counter_dev->num_counters = num_counters;
+ counter_dev->counters_per_chip = counters_per_chip;
return counter_dev;
}
diff --git a/drivers/staging/comedi/drivers/ni_tio.h b/drivers/staging/comedi/drivers/ni_tio.h
index 23221cead8ca..340d63c74467 100644
--- a/drivers/staging/comedi/drivers/ni_tio.h
+++ b/drivers/staging/comedi/drivers/ni_tio.h
@@ -107,8 +107,10 @@ struct ni_gpct_device {
enum ni_gpct_variant variant;
struct ni_gpct *counters;
unsigned int num_counters;
+ unsigned int counters_per_chip;
unsigned int regs[NITIO_NUM_REGS];
spinlock_t regs_lock; /* protects 'regs' */
+ const struct ni_route_tables *routing_tables; /* link to routes */
};
struct ni_gpct_device *
@@ -119,7 +121,9 @@ ni_gpct_device_construct(struct comedi_device *dev,
unsigned int (*read)(struct ni_gpct *counter,
enum ni_gpct_register),
enum ni_gpct_variant,
- unsigned int num_counters);
+ unsigned int num_counters,
+ unsigned int counters_per_chip,
+ const struct ni_route_tables *routing_tables);
void ni_gpct_device_destroy(struct ni_gpct_device *counter_dev);
void ni_tio_init_counter(struct ni_gpct *counter);
int ni_tio_insn_read(struct comedi_device *dev, struct comedi_subdevice *s,
@@ -138,4 +142,40 @@ void ni_tio_set_mite_channel(struct ni_gpct *counter,
struct mite_channel *mite_chan);
void ni_tio_acknowledge(struct ni_gpct *counter);
+/*
+ * Retrieves the register value of the current source of the output selector for
+ * the given destination.
+ *
+ * If the terminal for the destination is not already configured as an output,
+ * this function returns -EINVAL as error.
+ *
+ * Return: the register value of the destination output selector;
+ * -EINVAL if terminal is not configured for output.
+ */
+int ni_tio_get_routing(struct ni_gpct_device *counter_dev,
+ unsigned int destination);
+
+/*
+ * 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:
+ * 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
+ * destination/gate. These mode bits might include a bitwise or of
+ * CR_INVERT and CR_EDGE. Note that the calling function should
+ * have already validated the correctness of this value.
+ */
+int ni_tio_set_routing(struct ni_gpct_device *counter_dev,
+ unsigned int destination, unsigned int register_value);
+
+/*
+ * Sets the given destination MUX to its default value or disable it.
+ *
+ * Return: 0 if successful; -EINVAL if terminal is unknown.
+ */
+int ni_tio_unset_routing(struct ni_gpct_device *counter_dev,
+ unsigned int destination);
+
#endif /* _COMEDI_NI_TIO_H */
diff --git a/drivers/staging/comedi/drivers/ni_tio_internal.h b/drivers/staging/comedi/drivers/ni_tio_internal.h
index f4d99d78208a..652a28990132 100644
--- a/drivers/staging/comedi/drivers/ni_tio_internal.h
+++ b/drivers/staging/comedi/drivers/ni_tio_internal.h
@@ -170,5 +170,7 @@ unsigned int ni_tio_get_soft_copy(const struct ni_gpct *counter,
int ni_tio_arm(struct ni_gpct *counter, bool arm, unsigned int start_trigger);
int ni_tio_set_gate_src(struct ni_gpct *counter, unsigned int gate,
unsigned int src);
+int ni_tio_set_gate_src_raw(struct ni_gpct *counter, unsigned int gate,
+ unsigned int src);
#endif /* _COMEDI_NI_TIO_INTERNAL_H */
diff --git a/drivers/staging/comedi/drivers/ni_tiocmd.c b/drivers/staging/comedi/drivers/ni_tiocmd.c
index 050bee0b9515..2a9f7e9821a7 100644
--- a/drivers/staging/comedi/drivers/ni_tiocmd.c
+++ b/drivers/staging/comedi/drivers/ni_tiocmd.c
@@ -33,6 +33,7 @@
#include <linux/module.h>
#include "ni_tio_internal.h"
#include "mite.h"
+#include "ni_routes.h"
static void ni_tio_configure_dma(struct ni_gpct *counter,
bool enable, bool read)
@@ -100,6 +101,8 @@ static int ni_tio_input_cmd(struct comedi_subdevice *s)
{
struct ni_gpct *counter = s->private;
struct ni_gpct_device *counter_dev = counter->counter_dev;
+ const struct ni_route_tables *routing_tables =
+ counter_dev->routing_tables;
unsigned int cidx = counter->counter_index;
struct comedi_async *async = s->async;
struct comedi_cmd *cmd = &async->cmd;
@@ -128,8 +131,19 @@ static int ni_tio_input_cmd(struct comedi_subdevice *s)
if (cmd->start_src == TRIG_NOW)
ret = ni_tio_arm(counter, true, NI_GPCT_ARM_IMMEDIATE);
- else if (cmd->start_src == TRIG_EXT)
- ret = ni_tio_arm(counter, true, cmd->start_arg);
+ else if (cmd->start_src == TRIG_EXT) {
+ int reg = CR_CHAN(cmd->start_arg);
+
+ if (reg >= NI_NAMES_BASE) {
+ /* using a device-global name. lookup reg */
+ reg = ni_get_reg_value(reg,
+ NI_CtrArmStartTrigger(cidx),
+ routing_tables);
+ /* mark this as a raw register value */
+ reg |= NI_GPCT_HW_ARM;
+ }
+ ret = ni_tio_arm(counter, true, reg);
+ }
}
return ret;
}
@@ -148,6 +162,8 @@ static int ni_tio_cmd_setup(struct comedi_subdevice *s)
struct comedi_cmd *cmd = &s->async->cmd;
struct ni_gpct *counter = s->private;
unsigned int cidx = counter->counter_index;
+ const struct ni_route_tables *routing_tables =
+ counter->counter_dev->routing_tables;
int set_gate_source = 0;
unsigned int gate_source;
int retval = 0;
@@ -159,8 +175,24 @@ static int ni_tio_cmd_setup(struct comedi_subdevice *s)
set_gate_source = 1;
gate_source = cmd->convert_arg;
}
- if (set_gate_source)
- retval = ni_tio_set_gate_src(counter, 0, gate_source);
+ if (set_gate_source) {
+ if (CR_CHAN(gate_source) >= NI_NAMES_BASE) {
+ /* Lookup and use the real register values */
+ int reg = ni_get_reg_value(CR_CHAN(gate_source),
+ NI_CtrGate(cidx),
+ routing_tables);
+ if (reg < 0)
+ return -EINVAL;
+ retval = ni_tio_set_gate_src_raw(counter, 0, reg);
+ } else {
+ /*
+ * This function must be used separately since it does
+ * not expect real register values and attempts to
+ * convert these to real register values.
+ */
+ retval = ni_tio_set_gate_src(counter, 0, gate_source);
+ }
+ }
if (cmd->flags & CMDF_WAKE_EOS) {
ni_tio_set_bits(counter, NITIO_INT_ENA_REG(cidx),
GI_GATE_INTERRUPT_ENABLE(cidx),
@@ -203,6 +235,9 @@ int ni_tio_cmdtest(struct comedi_device *dev,
struct comedi_cmd *cmd)
{
struct ni_gpct *counter = s->private;
+ unsigned int cidx = counter->counter_index;
+ const struct ni_route_tables *routing_tables =
+ counter->counter_dev->routing_tables;
int err = 0;
unsigned int sources;
@@ -247,14 +282,37 @@ int ni_tio_cmdtest(struct comedi_device *dev,
break;
case TRIG_EXT:
/* start_arg is the start_trigger passed to ni_tio_arm() */
+ /*
+ * This should be done, but we don't yet know the actual
+ * register values. These should be tested and then documented
+ * in the ni_route_values/ni_*.csv files, with indication of
+ * who/when/which/how these these were tested.
+ * When at least a e/m/660x series have been tested, this code
+ * should be uncommented:
+ *
+ * err |= ni_check_trigger_arg(CR_CHAN(cmd->start_arg),
+ * NI_CtrArmStartTrigger(cidx),
+ * routing_tables);
+ */
break;
}
+ /*
+ * It seems that convention is to allow either scan_begin_arg or
+ * convert_arg to specify the Gate source, with scan_begin_arg taking
+ * precedence.
+ */
if (cmd->scan_begin_src != TRIG_EXT)
err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
+ else
+ err |= ni_check_trigger_arg(CR_CHAN(cmd->scan_begin_arg),
+ NI_CtrGate(cidx), routing_tables);
if (cmd->convert_src != TRIG_EXT)
err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0);
+ else
+ err |= ni_check_trigger_arg(CR_CHAN(cmd->convert_arg),
+ NI_CtrGate(cidx), routing_tables);
err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
cmd->chanlist_len);
diff --git a/drivers/staging/comedi/drivers/tests/Makefile b/drivers/staging/comedi/drivers/tests/Makefile
new file mode 100644
index 000000000000..b5d8e13d4162
--- /dev/null
+++ b/drivers/staging/comedi/drivers/tests/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+# Makefile for comedi drivers unit tests
+#
+ccflags-$(CONFIG_COMEDI_DEBUG) := -DDEBUG
+
+obj-$(CONFIG_COMEDI_TESTS) += example_test.o ni_routes_test.o
+CFLAGS_ni_routes_test.o := -DDEBUG
diff --git a/drivers/staging/comedi/drivers/tests/example_test.c b/drivers/staging/comedi/drivers/tests/example_test.c
new file mode 100644
index 000000000000..fc65158b8e8e
--- /dev/null
+++ b/drivers/staging/comedi/drivers/tests/example_test.c
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
+/*
+ * comedi/drivers/tests/example_test.c
+ * Example set of unit tests.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+
+#include "unittest.h"
+
+/* *** BEGIN fake board data *** */
+struct comedi_device {
+ const char *board_name;
+ int item;
+};
+
+static struct comedi_device dev = {
+ .board_name = "fake_device",
+};
+
+/* *** END fake board data *** */
+
+/* *** BEGIN fake data init *** */
+void init_fake(void)
+{
+ dev.item = 10;
+}
+
+/* *** END fake data init *** */
+
+void test0(void)
+{
+ init_fake();
+ unittest(dev.item != 11, "negative result\n");
+ unittest(dev.item == 10, "positive result\n");
+}
+
+/* **** BEGIN simple module entry/exit functions **** */
+static int __init unittest_enter(void)
+{
+ const unittest_fptr unit_tests[] = {
+ (unittest_fptr)test0,
+ NULL,
+ };
+
+ exec_unittests("example", unit_tests);
+ return 0;
+}
+
+static void __exit unittest_exit(void) { }
+
+module_init(unittest_enter);
+module_exit(unittest_exit);
+
+MODULE_AUTHOR("Spencer Olson <olsonse@umich.edu>");
+MODULE_DESCRIPTION("Comedi unit-tests example");
+MODULE_LICENSE("GPL");
+/* **** END simple module entry/exit functions **** */
diff --git a/drivers/staging/comedi/drivers/tests/ni_routes_test.c b/drivers/staging/comedi/drivers/tests/ni_routes_test.c
new file mode 100644
index 000000000000..a1eda035f270
--- /dev/null
+++ b/drivers/staging/comedi/drivers/tests/ni_routes_test.c
@@ -0,0 +1,613 @@
+// 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).
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+
+#include "../ni_stc.h"
+#include "../ni_routes.h"
+#include "unittest.h"
+
+#define RVi(table, src, dest) ((table)[(dest) * NI_NUM_NAMES + (src)])
+#define O(x) ((x) + NI_NAMES_BASE)
+#define B(x) ((x) - NI_NAMES_BASE)
+#define V(x) ((x) | 0x80)
+
+/* *** BEGIN fake board data *** */
+static const char *pci_6070e = "pci-6070e";
+static const char *pci_6220 = "pci-6220";
+static const char *pci_fake = "pci-fake";
+
+static const char *ni_eseries = "ni_eseries";
+static const char *ni_mseries = "ni_mseries";
+
+static struct ni_board_struct board = {
+ .name = NULL,
+};
+
+static struct ni_private private = {
+ .is_m_series = 0,
+};
+
+static const int bad_dest = O(8), dest0 = O(0), desti = O(5);
+static const int ith_dest_index = 2;
+static const int no_val_dest = O(7), no_val_index = 4;
+
+/* These have to be defs to be used in init code below */
+#define rgout0_src0 (O(100))
+#define rgout0_src1 (O(101))
+#define brd0_src0 (O(110))
+#define brd0_src1 (O(111))
+#define brd1_src0 (O(120))
+#define brd1_src1 (O(121))
+#define brd2_src0 (O(130))
+#define brd2_src1 (O(131))
+#define brd3_src0 (O(140))
+#define brd3_src1 (O(141))
+
+/* I1 and I2 should not call O(...). Mostly here to shut checkpatch.pl up */
+#define I1(x1) \
+ (int[]){ \
+ x1, 0 \
+ }
+#define I2(x1, x2) \
+ (int[]){ \
+ (x1), (x2), 0 \
+ }
+#define I3(x1, x2, x3) \
+ (int[]){ \
+ (x1), (x2), (x3), 0 \
+ }
+
+/* O9 is build to call O(...) for each arg */
+#define O9(x1, x2, x3, x4, x5, x6, x7, x8, x9) \
+ (int[]){ \
+ O(x1), O(x2), O(x3), O(x4), O(x5), O(x6), O(x7), O(x8), O(x9), \
+ 0 \
+ }
+
+static struct ni_device_routes DR = {
+ .device = "testdev",
+ .routes = (struct ni_route_set[]){
+ {.dest = O(0), .src = O9(/**/1, 2, 3, 4, 5, 6, 7, 8, 9)},
+ {.dest = O(1), .src = O9(0, /**/2, 3, 4, 5, 6, 7, 8, 9)},
+ /* ith route_set */
+ {.dest = O(5), .src = O9(0, 1, 2, 3, 4,/**/ 6, 7, 8, 9)},
+ {.dest = O(6), .src = O9(0, 1, 2, 3, 4, 5,/**/ 7, 8, 9)},
+ /* next one will not have valid reg values */
+ {.dest = O(7), .src = O9(0, 1, 2, 3, 4, 5, 6,/**/ 8, 9)},
+ {.dest = O(9), .src = O9(0, 1, 2, 3, 4, 5, 6, 7, 8/**/)},
+
+ /* indirect routes done through muxes */
+ {.dest = TRIGGER_LINE(0), .src = I1(rgout0_src0)},
+ {.dest = TRIGGER_LINE(1), .src = I3(rgout0_src0,
+ brd3_src0,
+ brd3_src1)},
+ {.dest = TRIGGER_LINE(2), .src = I3(rgout0_src1,
+ brd2_src0,
+ brd2_src1)},
+ {.dest = TRIGGER_LINE(3), .src = I3(rgout0_src1,
+ brd1_src0,
+ brd1_src1)},
+ {.dest = TRIGGER_LINE(4), .src = I2(brd0_src0,
+ brd0_src1)},
+ {.dest = 0},
+ },
+};
+
+#undef I1
+#undef I2
+#undef O9
+
+#define RV9(x1, x2, x3, x4, x5, x6, x7, x8, x9) \
+ [x1] = V(x1), [x2] = V(x2), [x3] = V(x3), [x4] = V(x4), \
+ [x5] = V(x5), [x6] = V(x6), [x7] = V(x7), [x8] = V(x8), \
+ [x9] = V(x9),
+
+/* This table is indexed as RV[destination][source] */
+static const u8 RV[NI_NUM_NAMES][NI_NUM_NAMES] = {
+ [0] = {RV9(/**/1, 2, 3, 4, 5, 6, 7, 8, 9)},
+ [1] = {RV9(0,/**/ 2, 3, 4, 5, 6, 7, 8, 9)},
+ [2] = {RV9(0, 1,/**/3, 4, 5, 6, 7, 8, 9)},
+ [3] = {RV9(0, 1, 2,/**/4, 5, 6, 7, 8, 9)},
+ [4] = {RV9(0, 1, 2, 3,/**/5, 6, 7, 8, 9)},
+ [5] = {RV9(0, 1, 2, 3, 4,/**/6, 7, 8, 9)},
+ [6] = {RV9(0, 1, 2, 3, 4, 5,/**/7, 8, 9)},
+ /* [7] is intentionaly left absent to test invalid routes */
+ [8] = {RV9(0, 1, 2, 3, 4, 5, 6, 7,/**/9)},
+ [9] = {RV9(0, 1, 2, 3, 4, 5, 6, 7, 8/**/)},
+ /* some tests for needing extra muxes */
+ [B(NI_RGOUT0)] = {[B(rgout0_src0)] = V(0),
+ [B(rgout0_src1)] = V(1)},
+ [B(NI_RTSI_BRD(0))] = {[B(brd0_src0)] = V(0),
+ [B(brd0_src1)] = V(1)},
+ [B(NI_RTSI_BRD(1))] = {[B(brd1_src0)] = V(0),
+ [B(brd1_src1)] = V(1)},
+ [B(NI_RTSI_BRD(2))] = {[B(brd2_src0)] = V(0),
+ [B(brd2_src1)] = V(1)},
+ [B(NI_RTSI_BRD(3))] = {[B(brd3_src0)] = V(0),
+ [B(brd3_src1)] = V(1)},
+};
+
+#undef RV9
+
+/* *** END fake board data *** */
+
+/* *** BEGIN board data initializers *** */
+static void init_private(void)
+{
+ memset(&private, 0, sizeof(struct ni_private));
+}
+
+static void init_pci_6070e(void)
+{
+ board.name = pci_6070e;
+ init_private();
+ private.is_m_series = 0;
+}
+
+static void init_pci_6220(void)
+{
+ board.name = pci_6220;
+ init_private();
+ private.is_m_series = 1;
+}
+
+static void init_pci_fake(void)
+{
+ board.name = pci_fake;
+ init_private();
+ private.routing_tables.route_values = &RV[0][0];
+ private.routing_tables.valid_routes = &DR;
+}
+
+/* *** END board data initializers *** */
+
+/* Tests that route_sets are in order of the signal destination. */
+static bool route_set_dests_in_order(const struct ni_device_routes *devroutes)
+{
+ int i;
+ int last = NI_NAMES_BASE - 1;
+
+ for (i = 0; i < devroutes->n_route_sets; ++i) {
+ if (last >= devroutes->routes[i].dest)
+ return false;
+ last = devroutes->routes[i].dest;
+ }
+ return true;
+}
+
+/* Tests that all route_set->src are in order of the signal source. */
+bool route_set_sources_in_order(const struct ni_device_routes *devroutes)
+{
+ int i;
+
+ for (i = 0; i < devroutes->n_route_sets; ++i) {
+ int j;
+ int last = NI_NAMES_BASE - 1;
+
+ for (j = 0; j < devroutes->routes[i].n_src; ++j) {
+ if (last >= devroutes->routes[i].src[j])
+ return false;
+ last = devroutes->routes[i].src[j];
+ }
+ }
+ return true;
+}
+
+void test_ni_assign_device_routes(void)
+{
+ const struct ni_device_routes *devroutes, *olddevroutes;
+ const u8 *table, *oldtable;
+
+ init_pci_6070e();
+ ni_assign_device_routes(ni_eseries, pci_6070e, &private.routing_tables);
+ devroutes = private.routing_tables.valid_routes;
+ table = private.routing_tables.route_values;
+
+ unittest(strncmp(devroutes->device, pci_6070e, 10) == 0,
+ "find device pci-6070e\n");
+ unittest(devroutes->n_route_sets == 37,
+ "number of pci-6070e route_sets == 37\n");
+ unittest(devroutes->routes->dest == NI_PFI(0),
+ "first pci-6070e route_set is for NI_PFI(0)\n");
+ unittest(devroutes->routes->n_src == 1,
+ "first pci-6070e route_set length == 1\n");
+ unittest(devroutes->routes->src[0] == NI_AI_StartTrigger,
+ "first pci-6070e route_set src. == NI_AI_StartTrigger\n");
+ unittest(devroutes->routes[10].dest == TRIGGER_LINE(0),
+ "10th pci-6070e route_set is for TRIGGER_LINE(0)\n");
+ unittest(devroutes->routes[10].n_src == 10,
+ "10th pci-6070e route_set length == 10\n");
+ unittest(devroutes->routes[10].src[0] == NI_CtrSource(0),
+ "10th pci-6070e route_set src. == NI_CtrSource(0)\n");
+ unittest(route_set_dests_in_order(devroutes),
+ "all pci-6070e route_sets in order of signal destination\n");
+ unittest(route_set_sources_in_order(devroutes),
+ "all pci-6070e route_set->src's in order of signal source\n");
+
+ unittest(
+ RVi(table, B(PXI_Star), B(NI_AI_SampleClock)) == V(17) &&
+ RVi(table, B(NI_10MHzRefClock), B(TRIGGER_LINE(0))) == 0 &&
+ RVi(table, B(NI_AI_ConvertClock), B(NI_PFI(0))) == 0 &&
+ RVi(table, B(NI_AI_ConvertClock), B(NI_PFI(2))) ==
+ V(NI_PFI_OUTPUT_AI_CONVERT),
+ "pci-6070e finds e-series route_values table\n");
+
+ olddevroutes = devroutes;
+ oldtable = table;
+ init_pci_6220();
+ ni_assign_device_routes(ni_mseries, pci_6220, &private.routing_tables);
+ devroutes = private.routing_tables.valid_routes;
+ table = private.routing_tables.route_values;
+
+ unittest(strncmp(devroutes->device, pci_6220, 10) == 0,
+ "find device pci-6220\n");
+ unittest(oldtable != table, "pci-6220 find other route_values table\n");
+
+ unittest(
+ RVi(table, B(PXI_Star), B(NI_AI_SampleClock)) == V(20) &&
+ RVi(table, B(NI_10MHzRefClock), B(TRIGGER_LINE(0))) == V(12) &&
+ RVi(table, B(NI_AI_ConvertClock), B(NI_PFI(0))) == V(3) &&
+ RVi(table, B(NI_AI_ConvertClock), B(NI_PFI(2))) == V(3),
+ "pci-6220 finds m-series route_values table\n");
+}
+
+void test_ni_sort_device_routes(void)
+{
+ /* We begin by sorting the device routes for use in later tests */
+ ni_sort_device_routes(&DR);
+ /* now we test that sorting. */
+ unittest(route_set_dests_in_order(&DR),
+ "all route_sets of fake data in order of sig. destination\n");
+ unittest(route_set_sources_in_order(&DR),
+ "all route_set->src's of fake data in order of sig. source\n");
+}
+
+void test_ni_find_route_set(void)
+{
+ unittest(ni_find_route_set(bad_dest, &DR) == NULL,
+ "check for nonexistent route_set\n");
+ unittest(ni_find_route_set(dest0, &DR) == &DR.routes[0],
+ "find first route_set\n");
+ unittest(ni_find_route_set(desti, &DR) == &DR.routes[ith_dest_index],
+ "find ith route_set\n");
+ unittest(ni_find_route_set(no_val_dest, &DR) ==
+ &DR.routes[no_val_index],
+ "find no_val route_set in spite of missing values\n");
+ unittest(ni_find_route_set(DR.routes[DR.n_route_sets - 1].dest, &DR) ==
+ &DR.routes[DR.n_route_sets - 1],
+ "find last route_set\n");
+}
+
+void test_ni_route_set_has_source(void)
+{
+ unittest(!ni_route_set_has_source(&DR.routes[0], O(0)),
+ "check for bad source\n");
+ unittest(ni_route_set_has_source(&DR.routes[0], O(1)),
+ "find first source\n");
+ unittest(ni_route_set_has_source(&DR.routes[0], O(5)),
+ "find fifth source\n");
+ unittest(ni_route_set_has_source(&DR.routes[0], O(9)),
+ "find last source\n");
+}
+
+void test_ni_route_to_register(void)
+{
+ const struct ni_route_tables *T = &private.routing_tables;
+
+ init_pci_fake();
+ unittest(ni_route_to_register(O(0), O(0), T) < 0,
+ "check for bad route 0-->0\n");
+ unittest(ni_route_to_register(O(1), O(0), T) == 1,
+ "validate first destination\n");
+ unittest(ni_route_to_register(O(6), O(5), T) == 6,
+ "validate middle destination\n");
+ unittest(ni_route_to_register(O(8), O(9), T) == 8,
+ "validate last destination\n");
+
+ /* choice of trigger line in the following is somewhat random */
+ unittest(ni_route_to_register(rgout0_src0, TRIGGER_LINE(0), T) == 0,
+ "validate indirect route through rgout0 to TRIGGER_LINE(0)\n");
+ unittest(ni_route_to_register(rgout0_src0, TRIGGER_LINE(1), T) == 0,
+ "validate indirect route through rgout0 to TRIGGER_LINE(1)\n");
+ unittest(ni_route_to_register(rgout0_src1, TRIGGER_LINE(2), T) == 1,
+ "validate indirect route through rgout0 to TRIGGER_LINE(2)\n");
+ unittest(ni_route_to_register(rgout0_src1, TRIGGER_LINE(3), T) == 1,
+ "validate indirect route through rgout0 to TRIGGER_LINE(3)\n");
+
+ unittest(ni_route_to_register(brd0_src0, TRIGGER_LINE(4), T) ==
+ BIT(6),
+ "validate indirect route through brd0 to TRIGGER_LINE(4)\n");
+ unittest(ni_route_to_register(brd0_src1, TRIGGER_LINE(4), T) ==
+ BIT(6),
+ "validate indirect route through brd0 to TRIGGER_LINE(4)\n");
+ unittest(ni_route_to_register(brd1_src0, TRIGGER_LINE(3), T) ==
+ BIT(6),
+ "validate indirect route through brd1 to TRIGGER_LINE(3)\n");
+ unittest(ni_route_to_register(brd1_src1, TRIGGER_LINE(3), T) ==
+ BIT(6),
+ "validate indirect route through brd1 to TRIGGER_LINE(3)\n");
+ unittest(ni_route_to_register(brd2_src0, TRIGGER_LINE(2), T) ==
+ BIT(6),
+ "validate indirect route through brd2 to TRIGGER_LINE(2)\n");
+ unittest(ni_route_to_register(brd2_src1, TRIGGER_LINE(2), T) ==
+ BIT(6),
+ "validate indirect route through brd2 to TRIGGER_LINE(2)\n");
+ unittest(ni_route_to_register(brd3_src0, TRIGGER_LINE(1), T) ==
+ BIT(6),
+ "validate indirect route through brd3 to TRIGGER_LINE(1)\n");
+ unittest(ni_route_to_register(brd3_src1, TRIGGER_LINE(1), T) ==
+ BIT(6),
+ "validate indirect route through brd3 to TRIGGER_LINE(1)\n");
+}
+
+void test_ni_lookup_route_register(void)
+{
+ const struct ni_route_tables *T = &private.routing_tables;
+
+ init_pci_fake();
+ unittest(ni_lookup_route_register(O(0), O(0), T) == -EINVAL,
+ "check for bad route 0-->0\n");
+ unittest(ni_lookup_route_register(O(1), O(0), T) == 1,
+ "validate first destination\n");
+ unittest(ni_lookup_route_register(O(6), O(5), T) == 6,
+ "validate middle destination\n");
+ unittest(ni_lookup_route_register(O(8), O(9), T) == 8,
+ "validate last destination\n");
+ unittest(ni_lookup_route_register(O(10), O(9), T) == -EINVAL,
+ "lookup invalid desination\n");
+
+ unittest(ni_lookup_route_register(rgout0_src0, TRIGGER_LINE(0), T) ==
+ -EINVAL,
+ "rgout0_src0: no direct lookup of indirect route\n");
+ unittest(ni_lookup_route_register(rgout0_src0, NI_RGOUT0, T) == 0,
+ "rgout0_src0: lookup indirect route register\n");
+ unittest(ni_lookup_route_register(rgout0_src1, TRIGGER_LINE(2), T) ==
+ -EINVAL,
+ "rgout0_src1: no direct lookup of indirect route\n");
+ unittest(ni_lookup_route_register(rgout0_src1, NI_RGOUT0, T) == 1,
+ "rgout0_src1: lookup indirect route register\n");
+
+ unittest(ni_lookup_route_register(brd0_src0, TRIGGER_LINE(4), T) ==
+ -EINVAL,
+ "brd0_src0: no direct lookup of indirect route\n");
+ unittest(ni_lookup_route_register(brd0_src0, NI_RTSI_BRD(0), T) == 0,
+ "brd0_src0: lookup indirect route register\n");
+ unittest(ni_lookup_route_register(brd0_src1, TRIGGER_LINE(4), T) ==
+ -EINVAL,
+ "brd0_src1: no direct lookup of indirect route\n");
+ unittest(ni_lookup_route_register(brd0_src1, NI_RTSI_BRD(0), T) == 1,
+ "brd0_src1: lookup indirect route register\n");
+}
+
+void test_route_is_valid(void)
+{
+ const struct ni_route_tables *T = &private.routing_tables;
+
+ init_pci_fake();
+ unittest(!route_is_valid(O(0), O(0), T),
+ "check for bad route 0-->0\n");
+ unittest(route_is_valid(O(0), O(1), T),
+ "validate first destination\n");
+ unittest(route_is_valid(O(5), O(6), T),
+ "validate middle destination\n");
+ unittest(route_is_valid(O(8), O(9), T),
+ "validate last destination\n");
+}
+
+void test_ni_is_cmd_dest(void)
+{
+ init_pci_fake();
+ unittest(ni_is_cmd_dest(NI_AI_SampleClock),
+ "check that AI/SampleClock is cmd destination\n");
+ unittest(ni_is_cmd_dest(NI_AI_StartTrigger),
+ "check that AI/StartTrigger is cmd destination\n");
+ unittest(ni_is_cmd_dest(NI_AI_ConvertClock),
+ "check that AI/ConvertClock is cmd destination\n");
+ unittest(ni_is_cmd_dest(NI_AO_SampleClock),
+ "check that AO/SampleClock is cmd destination\n");
+ unittest(ni_is_cmd_dest(NI_DO_SampleClock),
+ "check that DO/SampleClock is cmd destination\n");
+ unittest(!ni_is_cmd_dest(NI_AO_SampleClockTimebase),
+ "check that AO/SampleClockTimebase _not_ cmd destination\n");
+}
+
+void test_channel_is_pfi(void)
+{
+ init_pci_fake();
+ unittest(channel_is_pfi(NI_PFI(0)), "check First pfi channel\n");
+ unittest(channel_is_pfi(NI_PFI(10)), "check 10th pfi channel\n");
+ unittest(channel_is_pfi(NI_PFI(-1)), "check last pfi channel\n");
+ unittest(!channel_is_pfi(NI_PFI(-1) + 1),
+ "check first non pfi channel\n");
+}
+
+void test_channel_is_rtsi(void)
+{
+ init_pci_fake();
+ unittest(channel_is_rtsi(TRIGGER_LINE(0)),
+ "check First rtsi channel\n");
+ unittest(channel_is_rtsi(TRIGGER_LINE(3)),
+ "check 3rd rtsi channel\n");
+ unittest(channel_is_rtsi(TRIGGER_LINE(-1)),
+ "check last rtsi channel\n");
+ unittest(!channel_is_rtsi(TRIGGER_LINE(-1) + 1),
+ "check first non rtsi channel\n");
+}
+
+void test_ni_count_valid_routes(void)
+{
+ const struct ni_route_tables *T = &private.routing_tables;
+
+ init_pci_fake();
+ unittest(ni_count_valid_routes(T) == 57, "count all valid routes\n");
+}
+
+void test_ni_get_valid_routes(void)
+{
+ const struct ni_route_tables *T = &private.routing_tables;
+ unsigned int pair_data[2];
+
+ init_pci_fake();
+ unittest(ni_get_valid_routes(T, 0, NULL) == 57,
+ "count all valid routes through ni_get_valid_routes\n");
+
+ unittest(ni_get_valid_routes(T, 1, pair_data) == 1,
+ "copied first valid route from ni_get_valid_routes\n");
+ unittest(pair_data[0] == O(1),
+ "source of first valid pair from ni_get_valid_routes\n");
+ unittest(pair_data[1] == O(0),
+ "destination of first valid pair from ni_get_valid_routes\n");
+}
+
+void test_ni_find_route_source(void)
+{
+ const struct ni_route_tables *T = &private.routing_tables;
+
+ init_pci_fake();
+ unittest(ni_find_route_source(4, O(4), T) == -EINVAL,
+ "check for bad source 4-->4\n");
+ unittest(ni_find_route_source(0, O(1), T) == O(0),
+ "find first source\n");
+ unittest(ni_find_route_source(4, O(6), T) == O(4),
+ "find middle source\n");
+ unittest(ni_find_route_source(9, O(8), T) == O(9),
+ "find last source");
+ unittest(ni_find_route_source(8, O(9), T) == O(8),
+ "find invalid source (without checking device routes)\n");
+}
+
+void test_route_register_is_valid(void)
+{
+ const struct ni_route_tables *T = &private.routing_tables;
+
+ init_pci_fake();
+ unittest(route_register_is_valid(4, O(4), T) == false,
+ "check for bad source 4-->4\n");
+ unittest(route_register_is_valid(0, O(1), T) == true,
+ "find first source\n");
+ unittest(route_register_is_valid(4, O(6), T) == true,
+ "find middle source\n");
+ unittest(route_register_is_valid(9, O(8), T) == true,
+ "find last source");
+}
+
+void test_ni_check_trigger_arg(void)
+{
+ const struct ni_route_tables *T = &private.routing_tables;
+
+ init_pci_fake();
+ unittest(ni_check_trigger_arg(0, O(0), T) == -EINVAL,
+ "check bad direct trigger arg for first reg->dest\n");
+ unittest(ni_check_trigger_arg(0, O(1), T) == 0,
+ "check direct trigger arg for first reg->dest\n");
+ unittest(ni_check_trigger_arg(4, O(6), T) == 0,
+ "check direct trigger arg for middle reg->dest\n");
+ unittest(ni_check_trigger_arg(9, O(8), T) == 0,
+ "check direct trigger arg for last reg->dest\n");
+
+ unittest(ni_check_trigger_arg_roffs(-1, O(0), T, 1) == -EINVAL,
+ "check bad direct trigger arg for first reg->dest w/offs\n");
+ unittest(ni_check_trigger_arg_roffs(0, O(1), T, 0) == 0,
+ "check direct trigger arg for first reg->dest w/offs\n");
+ unittest(ni_check_trigger_arg_roffs(3, O(6), T, 1) == 0,
+ "check direct trigger arg for middle reg->dest w/offs\n");
+ unittest(ni_check_trigger_arg_roffs(7, O(8), T, 2) == 0,
+ "check direct trigger arg for last reg->dest w/offs\n");
+
+ unittest(ni_check_trigger_arg(O(0), O(0), T) == -EINVAL,
+ "check bad trigger arg for first src->dest\n");
+ unittest(ni_check_trigger_arg(O(0), O(1), T) == 0,
+ "check trigger arg for first src->dest\n");
+ unittest(ni_check_trigger_arg(O(5), O(6), T) == 0,
+ "check trigger arg for middle src->dest\n");
+ unittest(ni_check_trigger_arg(O(8), O(9), T) == 0,
+ "check trigger arg for last src->dest\n");
+}
+
+void test_ni_get_reg_value(void)
+{
+ const struct ni_route_tables *T = &private.routing_tables;
+
+ init_pci_fake();
+ unittest(ni_get_reg_value(0, O(0), T) == -1,
+ "check bad direct trigger arg for first reg->dest\n");
+ unittest(ni_get_reg_value(0, O(1), T) == 0,
+ "check direct trigger arg for first reg->dest\n");
+ unittest(ni_get_reg_value(4, O(6), T) == 4,
+ "check direct trigger arg for middle reg->dest\n");
+ unittest(ni_get_reg_value(9, O(8), T) == 9,
+ "check direct trigger arg for last reg->dest\n");
+
+ unittest(ni_get_reg_value_roffs(-1, O(0), T, 1) == -1,
+ "check bad direct trigger arg for first reg->dest w/offs\n");
+ unittest(ni_get_reg_value_roffs(0, O(1), T, 0) == 0,
+ "check direct trigger arg for first reg->dest w/offs\n");
+ unittest(ni_get_reg_value_roffs(3, O(6), T, 1) == 4,
+ "check direct trigger arg for middle reg->dest w/offs\n");
+ unittest(ni_get_reg_value_roffs(7, O(8), T, 2) == 9,
+ "check direct trigger arg for last reg->dest w/offs\n");
+
+ unittest(ni_get_reg_value(O(0), O(0), T) == -1,
+ "check bad trigger arg for first src->dest\n");
+ unittest(ni_get_reg_value(O(0), O(1), T) == 0,
+ "check trigger arg for first src->dest\n");
+ unittest(ni_get_reg_value(O(5), O(6), T) == 5,
+ "check trigger arg for middle src->dest\n");
+ unittest(ni_get_reg_value(O(8), O(9), T) == 8,
+ "check trigger arg for last src->dest\n");
+}
+
+/* **** BEGIN simple module entry/exit functions **** */
+static int __init ni_routes_unittest(void)
+{
+ const unittest_fptr unit_tests[] = {
+ (unittest_fptr)test_ni_assign_device_routes,
+ (unittest_fptr)test_ni_sort_device_routes,
+ (unittest_fptr)test_ni_find_route_set,
+ (unittest_fptr)test_ni_route_set_has_source,
+ (unittest_fptr)test_ni_route_to_register,
+ (unittest_fptr)test_ni_lookup_route_register,
+ (unittest_fptr)test_route_is_valid,
+ (unittest_fptr)test_ni_is_cmd_dest,
+ (unittest_fptr)test_channel_is_pfi,
+ (unittest_fptr)test_channel_is_rtsi,
+ (unittest_fptr)test_ni_count_valid_routes,
+ (unittest_fptr)test_ni_get_valid_routes,
+ (unittest_fptr)test_ni_find_route_source,
+ (unittest_fptr)test_route_register_is_valid,
+ (unittest_fptr)test_ni_check_trigger_arg,
+ (unittest_fptr)test_ni_get_reg_value,
+ NULL,
+ };
+
+ exec_unittests("ni_routes", unit_tests);
+ return 0;
+}
+
+static void __exit ni_routes_unittest_exit(void) { }
+
+module_init(ni_routes_unittest);
+module_exit(ni_routes_unittest_exit);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi unit-tests for ni_routes module");
+MODULE_LICENSE("GPL");
+/* **** END simple module entry/exit functions **** */
diff --git a/drivers/staging/comedi/drivers/tests/unittest.h b/drivers/staging/comedi/drivers/tests/unittest.h
new file mode 100644
index 000000000000..b8e622ea1de1
--- /dev/null
+++ b/drivers/staging/comedi/drivers/tests/unittest.h
@@ -0,0 +1,63 @@
+/* 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.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu>
+ * based of parts of drivers/of/unittest.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _COMEDI_DRIVERS_TESTS_UNITTEST_H
+#define _COMEDI_DRIVERS_TESTS_UNITTEST_H
+
+static struct unittest_results {
+ int passed;
+ int failed;
+} unittest_results;
+
+typedef void *(*unittest_fptr)(void);
+
+#define unittest(result, fmt, ...) ({ \
+ bool failed = !(result); \
+ if (failed) { \
+ ++unittest_results.failed; \
+ pr_err("FAIL %s():%i " fmt, __func__, __LINE__, \
+ ##__VA_ARGS__); \
+ } else { \
+ ++unittest_results.passed; \
+ pr_debug("pass %s():%i " fmt, __func__, __LINE__, \
+ ##__VA_ARGS__); \
+ } \
+ failed; \
+})
+
+/**
+ * Execute an array of unit tests.
+ * @name: Name of set of unit tests--will be shown at INFO log level.
+ * @unit_tests: A null-terminated list of unit tests to execute.
+ */
+static inline void exec_unittests(const char *name,
+ const unittest_fptr *unit_tests)
+{
+ pr_info("begin comedi:\"%s\" unittests\n", name);
+
+ for (; (*unit_tests) != NULL; ++unit_tests)
+ (*unit_tests)();
+
+ pr_info("end of comedi:\"%s\" unittests - %i passed, %i failed\n", name,
+ unittest_results.passed, unittest_results.failed);
+}
+
+#endif /* _COMEDI_DRIVERS_TESTS_UNITTEST_H */
diff --git a/drivers/staging/dgnc/Kconfig b/drivers/staging/dgnc/Kconfig
deleted file mode 100644
index 032c2a795238..000000000000
--- a/drivers/staging/dgnc/Kconfig
+++ /dev/null
@@ -1,6 +0,0 @@
-config DGNC
- tristate "Digi Neo and Classic PCI Products"
- default n
- depends on TTY && PCI
- ---help---
- Driver for the Digi International Neo and Classic PCI based product line.
diff --git a/drivers/staging/dgnc/Makefile b/drivers/staging/dgnc/Makefile
deleted file mode 100644
index 49633042fcc9..000000000000
--- a/drivers/staging/dgnc/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-obj-$(CONFIG_DGNC) += dgnc.o
-
-dgnc-objs := dgnc_cls.o dgnc_driver.o\
- dgnc_tty.o
diff --git a/drivers/staging/dgnc/TODO b/drivers/staging/dgnc/TODO
deleted file mode 100644
index d4cc65770513..000000000000
--- a/drivers/staging/dgnc/TODO
+++ /dev/null
@@ -1,6 +0,0 @@
-* remove unnecessary comments
-* there is a lot of unnecessary code in the driver. It was
- originally a standalone driver. Remove unneeded code.
-
-Please send patches to Greg Kroah-Hartman <greg@kroah.com> and
-Cc: Lidza Louina <lidza.louina@gmail.com>
diff --git a/drivers/staging/dgnc/dgnc_cls.c b/drivers/staging/dgnc/dgnc_cls.c
deleted file mode 100644
index 7e6cbfe4e4ee..000000000000
--- a/drivers/staging/dgnc/dgnc_cls.c
+++ /dev/null
@@ -1,1135 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright 2003 Digi International (www.digi.com)
- * Scott H Kilau <Scott_Kilau at digi dot com>
- */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/serial.h>
-#include <linux/serial_reg.h>
-#include <linux/pci.h>
-
-#include "dgnc_driver.h"
-#include "dgnc_cls.h"
-#include "dgnc_tty.h"
-
-static inline void cls_set_cts_flow_control(struct channel_t *ch)
-{
- unsigned char lcrb = readb(&ch->ch_cls_uart->lcr);
- unsigned char ier = readb(&ch->ch_cls_uart->ier);
- unsigned char isr_fcr = 0;
-
- /*
- * The Enhanced Register Set may only be accessed when
- * the Line Control Register is set to 0xBFh.
- */
- writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
-
- isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
-
- /* Turn on CTS flow control, turn off IXON flow control */
- isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_CTSDSR);
- isr_fcr &= ~(UART_EXAR654_EFR_IXON);
-
- writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
-
- /* Write old LCR value back out, which turns enhanced access off */
- writeb(lcrb, &ch->ch_cls_uart->lcr);
-
- /*
- * Enable interrupts for CTS flow, turn off interrupts for
- * received XOFF chars
- */
- ier |= (UART_EXAR654_IER_CTSDSR);
- ier &= ~(UART_EXAR654_IER_XOFF);
- writeb(ier, &ch->ch_cls_uart->ier);
-
- /* Set the usual FIFO values */
- writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
-
- writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_56 |
- UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
- &ch->ch_cls_uart->isr_fcr);
-
- ch->ch_t_tlevel = 16;
-}
-
-static inline void cls_set_ixon_flow_control(struct channel_t *ch)
-{
- unsigned char lcrb = readb(&ch->ch_cls_uart->lcr);
- unsigned char ier = readb(&ch->ch_cls_uart->ier);
- unsigned char isr_fcr = 0;
-
- /*
- * The Enhanced Register Set may only be accessed when
- * the Line Control Register is set to 0xBFh.
- */
- writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
-
- isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
-
- /* Turn on IXON flow control, turn off CTS flow control */
- isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_IXON);
- isr_fcr &= ~(UART_EXAR654_EFR_CTSDSR);
-
- writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
-
- /* Now set our current start/stop chars while in enhanced mode */
- writeb(ch->ch_startc, &ch->ch_cls_uart->mcr);
- writeb(0, &ch->ch_cls_uart->lsr);
- writeb(ch->ch_stopc, &ch->ch_cls_uart->msr);
- writeb(0, &ch->ch_cls_uart->spr);
-
- /* Write old LCR value back out, which turns enhanced access off */
- writeb(lcrb, &ch->ch_cls_uart->lcr);
-
- /*
- * Disable interrupts for CTS flow, turn on interrupts for
- * received XOFF chars
- */
- ier &= ~(UART_EXAR654_IER_CTSDSR);
- ier |= (UART_EXAR654_IER_XOFF);
- writeb(ier, &ch->ch_cls_uart->ier);
-
- /* Set the usual FIFO values */
- writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
-
- writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 |
- UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
- &ch->ch_cls_uart->isr_fcr);
-}
-
-static inline void cls_set_no_output_flow_control(struct channel_t *ch)
-{
- unsigned char lcrb = readb(&ch->ch_cls_uart->lcr);
- unsigned char ier = readb(&ch->ch_cls_uart->ier);
- unsigned char isr_fcr = 0;
-
- /*
- * The Enhanced Register Set may only be accessed when
- * the Line Control Register is set to 0xBFh.
- */
- writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
-
- isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
-
- /* Turn off IXON flow control, turn off CTS flow control */
- isr_fcr |= (UART_EXAR654_EFR_ECB);
- isr_fcr &= ~(UART_EXAR654_EFR_CTSDSR | UART_EXAR654_EFR_IXON);
-
- writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
-
- /* Write old LCR value back out, which turns enhanced access off */
- writeb(lcrb, &ch->ch_cls_uart->lcr);
-
- /*
- * Disable interrupts for CTS flow, turn off interrupts for
- * received XOFF chars
- */
- ier &= ~(UART_EXAR654_IER_CTSDSR);
- ier &= ~(UART_EXAR654_IER_XOFF);
- writeb(ier, &ch->ch_cls_uart->ier);
-
- /* Set the usual FIFO values */
- writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
-
- writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 |
- UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
- &ch->ch_cls_uart->isr_fcr);
-
- ch->ch_r_watermark = 0;
- ch->ch_t_tlevel = 16;
- ch->ch_r_tlevel = 16;
-}
-
-static inline void cls_set_rts_flow_control(struct channel_t *ch)
-{
- unsigned char lcrb = readb(&ch->ch_cls_uart->lcr);
- unsigned char ier = readb(&ch->ch_cls_uart->ier);
- unsigned char isr_fcr = 0;
-
- /*
- * The Enhanced Register Set may only be accessed when
- * the Line Control Register is set to 0xBFh.
- */
- writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
-
- isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
-
- /* Turn on RTS flow control, turn off IXOFF flow control */
- isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_RTSDTR);
- isr_fcr &= ~(UART_EXAR654_EFR_IXOFF);
-
- writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
-
- /* Write old LCR value back out, which turns enhanced access off */
- writeb(lcrb, &ch->ch_cls_uart->lcr);
-
- /* Enable interrupts for RTS flow */
- ier |= (UART_EXAR654_IER_RTSDTR);
- writeb(ier, &ch->ch_cls_uart->ier);
-
- /* Set the usual FIFO values */
- writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
-
- writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_56 |
- UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
- &ch->ch_cls_uart->isr_fcr);
-
- ch->ch_r_watermark = 4;
- ch->ch_r_tlevel = 8;
-}
-
-static inline void cls_set_ixoff_flow_control(struct channel_t *ch)
-{
- unsigned char lcrb = readb(&ch->ch_cls_uart->lcr);
- unsigned char ier = readb(&ch->ch_cls_uart->ier);
- unsigned char isr_fcr = 0;
-
- /*
- * The Enhanced Register Set may only be accessed when
- * the Line Control Register is set to 0xBFh.
- */
- writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
-
- isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
-
- /* Turn on IXOFF flow control, turn off RTS flow control */
- isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_IXOFF);
- isr_fcr &= ~(UART_EXAR654_EFR_RTSDTR);
-
- writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
-
- /* Now set our current start/stop chars while in enhanced mode */
- writeb(ch->ch_startc, &ch->ch_cls_uart->mcr);
- writeb(0, &ch->ch_cls_uart->lsr);
- writeb(ch->ch_stopc, &ch->ch_cls_uart->msr);
- writeb(0, &ch->ch_cls_uart->spr);
-
- /* Write old LCR value back out, which turns enhanced access off */
- writeb(lcrb, &ch->ch_cls_uart->lcr);
-
- /* Disable interrupts for RTS flow */
- ier &= ~(UART_EXAR654_IER_RTSDTR);
- writeb(ier, &ch->ch_cls_uart->ier);
-
- /* Set the usual FIFO values */
- writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
-
- writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 |
- UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
- &ch->ch_cls_uart->isr_fcr);
-}
-
-static inline void cls_set_no_input_flow_control(struct channel_t *ch)
-{
- unsigned char lcrb = readb(&ch->ch_cls_uart->lcr);
- unsigned char ier = readb(&ch->ch_cls_uart->ier);
- unsigned char isr_fcr = 0;
-
- /*
- * The Enhanced Register Set may only be accessed when
- * the Line Control Register is set to 0xBFh.
- */
- writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
-
- isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
-
- /* Turn off IXOFF flow control, turn off RTS flow control */
- isr_fcr |= (UART_EXAR654_EFR_ECB);
- isr_fcr &= ~(UART_EXAR654_EFR_RTSDTR | UART_EXAR654_EFR_IXOFF);
-
- writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
-
- /* Write old LCR value back out, which turns enhanced access off */
- writeb(lcrb, &ch->ch_cls_uart->lcr);
-
- /* Disable interrupts for RTS flow */
- ier &= ~(UART_EXAR654_IER_RTSDTR);
- writeb(ier, &ch->ch_cls_uart->ier);
-
- /* Set the usual FIFO values */
- writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
-
- writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 |
- UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
- &ch->ch_cls_uart->isr_fcr);
-
- ch->ch_t_tlevel = 16;
- ch->ch_r_tlevel = 16;
-}
-
-/*
- * Determines whether its time to shut off break condition.
- *
- * No locks are assumed to be held when calling this function.
- * channel lock is held and released in this function.
- */
-static inline void cls_clear_break(struct channel_t *ch, int force)
-{
- unsigned long flags;
-
- if (!ch)
- return;
-
- spin_lock_irqsave(&ch->ch_lock, flags);
-
- if (!ch->ch_stop_sending_break) {
- spin_unlock_irqrestore(&ch->ch_lock, flags);
- return;
- }
-
- /* Turn break off, and unset some variables */
- if (ch->ch_flags & CH_BREAK_SENDING) {
- if (time_after(jiffies, ch->ch_stop_sending_break) || force) {
- unsigned char temp = readb(&ch->ch_cls_uart->lcr);
-
- writeb((temp & ~UART_LCR_SBC), &ch->ch_cls_uart->lcr);
- ch->ch_flags &= ~(CH_BREAK_SENDING);
- ch->ch_stop_sending_break = 0;
- }
- }
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-}
-
-static void cls_copy_data_from_uart_to_queue(struct channel_t *ch)
-{
- int qleft = 0;
- unsigned char linestatus = 0;
- unsigned char error_mask = 0;
- ushort head;
- ushort tail;
- unsigned long flags;
-
- if (!ch)
- return;
-
- spin_lock_irqsave(&ch->ch_lock, flags);
-
- head = ch->ch_r_head;
- tail = ch->ch_r_tail;
-
- qleft = tail - head - 1;
- if (qleft < 0)
- qleft += RQUEUEMASK + 1;
-
- /*
- * Create a mask to determine whether we should
- * insert the character (if any) into our queue.
- */
- if (ch->ch_c_iflag & IGNBRK)
- error_mask |= UART_LSR_BI;
-
- while (1) {
- linestatus = readb(&ch->ch_cls_uart->lsr);
-
- if (!(linestatus & (UART_LSR_DR)))
- break;
-
- /* Discard character if we are ignoring the error mask. */
- if (linestatus & error_mask) {
- linestatus = 0;
- readb(&ch->ch_cls_uart->txrx);
- continue;
- }
-
- /*
- * If our queue is full, we have no choice but to drop some
- * data. The assumption is that HWFLOW or SWFLOW should have
- * stopped things way way before we got to this point.
- */
- while (qleft < 1) {
- tail = (tail + 1) & RQUEUEMASK;
- ch->ch_r_tail = tail;
- ch->ch_err_overrun++;
- qleft++;
- }
-
- ch->ch_equeue[head] = linestatus & (UART_LSR_BI | UART_LSR_PE
- | UART_LSR_FE);
- ch->ch_rqueue[head] = readb(&ch->ch_cls_uart->txrx);
-
- qleft--;
-
- if (ch->ch_equeue[head] & UART_LSR_PE)
- ch->ch_err_parity++;
- if (ch->ch_equeue[head] & UART_LSR_BI)
- ch->ch_err_break++;
- if (ch->ch_equeue[head] & UART_LSR_FE)
- ch->ch_err_frame++;
-
- head = (head + 1) & RQUEUEMASK;
- ch->ch_rxcount++;
- }
-
- ch->ch_r_head = head & RQUEUEMASK;
- ch->ch_e_head = head & EQUEUEMASK;
-
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-}
-
-/* Make the UART raise any of the output signals we want up */
-static void cls_assert_modem_signals(struct channel_t *ch)
-{
- unsigned char out;
-
- if (!ch)
- return;
-
- out = ch->ch_mostat;
-
- if (ch->ch_flags & CH_LOOPBACK)
- out |= UART_MCR_LOOP;
-
- writeb(out, &ch->ch_cls_uart->mcr);
-
- /* Give time for the UART to actually drop the signals */
- usleep_range(10, 20);
-}
-
-static void cls_copy_data_from_queue_to_uart(struct channel_t *ch)
-{
- ushort head;
- ushort tail;
- int n;
- int qlen;
- uint len_written = 0;
- unsigned long flags;
-
- if (!ch)
- return;
-
- spin_lock_irqsave(&ch->ch_lock, flags);
-
- if (ch->ch_w_tail == ch->ch_w_head)
- goto exit_unlock;
-
- /* If port is "stopped", don't send any data to the UART */
- if ((ch->ch_flags & CH_FORCED_STOP) ||
- (ch->ch_flags & CH_BREAK_SENDING))
- goto exit_unlock;
-
- if (!(ch->ch_flags & (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM)))
- goto exit_unlock;
-
- n = 32;
-
- head = ch->ch_w_head & WQUEUEMASK;
- tail = ch->ch_w_tail & WQUEUEMASK;
- qlen = (head - tail) & WQUEUEMASK;
-
- n = min(n, qlen);
-
- while (n > 0) {
- /*
- * If RTS Toggle mode is on, turn on RTS now if not already set,
- * and make sure we get an event when the data transfer has
- * completed.
- */
- if (ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE) {
- if (!(ch->ch_mostat & UART_MCR_RTS)) {
- ch->ch_mostat |= (UART_MCR_RTS);
- cls_assert_modem_signals(ch);
- }
- ch->ch_tun.un_flags |= (UN_EMPTY);
- }
-
- /*
- * If DTR Toggle mode is on, turn on DTR now if not already set,
- * and make sure we get an event when the data transfer has
- * completed.
- */
- if (ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE) {
- if (!(ch->ch_mostat & UART_MCR_DTR)) {
- ch->ch_mostat |= (UART_MCR_DTR);
- cls_assert_modem_signals(ch);
- }
- ch->ch_tun.un_flags |= (UN_EMPTY);
- }
- writeb(ch->ch_wqueue[ch->ch_w_tail], &ch->ch_cls_uart->txrx);
- ch->ch_w_tail++;
- ch->ch_w_tail &= WQUEUEMASK;
- ch->ch_txcount++;
- len_written++;
- n--;
- }
-
- if (len_written > 0)
- ch->ch_flags &= ~(CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
-
-exit_unlock:
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-}
-
-static void cls_parse_modem(struct channel_t *ch, unsigned char signals)
-{
- unsigned char msignals = signals;
- unsigned long flags;
-
- if (!ch)
- return;
-
- /*
- * Do altpin switching. Altpin switches DCD and DSR.
- * This prolly breaks DSRPACE, so we should be more clever here.
- */
- spin_lock_irqsave(&ch->ch_lock, flags);
- if (ch->ch_digi.digi_flags & DIGI_ALTPIN) {
- unsigned char mswap = signals;
-
- if (mswap & UART_MSR_DDCD) {
- msignals &= ~UART_MSR_DDCD;
- msignals |= UART_MSR_DDSR;
- }
- if (mswap & UART_MSR_DDSR) {
- msignals &= ~UART_MSR_DDSR;
- msignals |= UART_MSR_DDCD;
- }
- if (mswap & UART_MSR_DCD) {
- msignals &= ~UART_MSR_DCD;
- msignals |= UART_MSR_DSR;
- }
- if (mswap & UART_MSR_DSR) {
- msignals &= ~UART_MSR_DSR;
- msignals |= UART_MSR_DCD;
- }
- }
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-
- /* Scrub off lower bits. They signify delta's */
- signals &= 0xf0;
-
- spin_lock_irqsave(&ch->ch_lock, flags);
- if (msignals & UART_MSR_DCD)
- ch->ch_mistat |= UART_MSR_DCD;
- else
- ch->ch_mistat &= ~UART_MSR_DCD;
-
- if (msignals & UART_MSR_DSR)
- ch->ch_mistat |= UART_MSR_DSR;
- else
- ch->ch_mistat &= ~UART_MSR_DSR;
-
- if (msignals & UART_MSR_RI)
- ch->ch_mistat |= UART_MSR_RI;
- else
- ch->ch_mistat &= ~UART_MSR_RI;
-
- if (msignals & UART_MSR_CTS)
- ch->ch_mistat |= UART_MSR_CTS;
- else
- ch->ch_mistat &= ~UART_MSR_CTS;
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-}
-
-/* Parse the ISR register for the specific port */
-static inline void cls_parse_isr(struct dgnc_board *brd, uint port)
-{
- struct channel_t *ch;
- unsigned char isr = 0;
- unsigned long flags;
-
- /*
- * No need to verify board pointer, it was already
- * verified in the interrupt routine.
- */
-
- if (port >= brd->nasync)
- return;
-
- ch = brd->channels[port];
-
- /* Here we try to figure out what caused the interrupt to happen */
- while (1) {
- isr = readb(&ch->ch_cls_uart->isr_fcr);
-
- if (isr & UART_IIR_NO_INT)
- break;
-
- /* Receive Interrupt pending */
- if (isr & (UART_IIR_RDI | UART_IIR_RDI_TIMEOUT)) {
- cls_copy_data_from_uart_to_queue(ch);
- dgnc_check_queue_flow_control(ch);
- }
-
- /* Transmit Hold register empty pending */
- if (isr & UART_IIR_THRI) {
- spin_lock_irqsave(&ch->ch_lock, flags);
- ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
- spin_unlock_irqrestore(&ch->ch_lock, flags);
- cls_copy_data_from_queue_to_uart(ch);
- }
-
- cls_parse_modem(ch, readb(&ch->ch_cls_uart->msr));
- }
-}
-
-/* Channel lock MUST be held before calling this function! */
-static void cls_flush_uart_write(struct channel_t *ch)
-{
- if (!ch)
- return;
-
- writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_XMIT),
- &ch->ch_cls_uart->isr_fcr);
-
- /* Must use *delay family functions in atomic context */
- udelay(10);
-
- ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
-}
-
-/* Channel lock MUST be held before calling this function! */
-static void cls_flush_uart_read(struct channel_t *ch)
-{
- if (!ch)
- return;
-
- /*
- * For complete POSIX compatibility, we should be purging the
- * read FIFO in the UART here.
- *
- * However, clearing the read FIFO (UART_FCR_CLEAR_RCVR) also
- * incorrectly flushes write data as well as just basically trashing the
- * FIFO.
- *
- * Presumably, this is a bug in this UART.
- */
-
- udelay(10);
-}
-
-/* Send any/all changes to the line to the UART. */
-static void cls_param(struct tty_struct *tty)
-{
- unsigned char lcr = 0;
- unsigned char uart_lcr = 0;
- unsigned char ier = 0;
- unsigned char uart_ier = 0;
- uint baud = 9600;
- int quot = 0;
- struct dgnc_board *bd;
- struct channel_t *ch;
- struct un_t *un;
-
- if (!tty)
- return;
-
- un = (struct un_t *)tty->driver_data;
- if (!un)
- return;
-
- ch = un->un_ch;
- if (!ch)
- return;
-
- bd = ch->ch_bd;
- if (!bd)
- return;
-
- /* If baud rate is zero, flush queues, and set mval to drop DTR. */
- if ((ch->ch_c_cflag & (CBAUD)) == 0) {
- ch->ch_r_head = 0;
- ch->ch_r_tail = 0;
- ch->ch_e_head = 0;
- ch->ch_e_tail = 0;
- ch->ch_w_head = 0;
- ch->ch_w_tail = 0;
-
- cls_flush_uart_write(ch);
- cls_flush_uart_read(ch);
-
- /* The baudrate is B0 so all modem lines are to be dropped. */
- ch->ch_flags |= (CH_BAUD0);
- ch->ch_mostat &= ~(UART_MCR_RTS | UART_MCR_DTR);
- cls_assert_modem_signals(ch);
- ch->ch_old_baud = 0;
- return;
- } else if (ch->ch_custom_speed) {
- baud = ch->ch_custom_speed;
- /* Handle transition from B0 */
- if (ch->ch_flags & CH_BAUD0) {
- ch->ch_flags &= ~(CH_BAUD0);
-
- /*
- * Bring back up RTS and DTR...
- * Also handle RTS or DTR toggle if set.
- */
- if (!(ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE))
- ch->ch_mostat |= (UART_MCR_RTS);
- if (!(ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE))
- ch->ch_mostat |= (UART_MCR_DTR);
- }
-
- } else {
- int iindex = 0;
- int jindex = 0;
-
- ulong bauds[4][16] = {
- { /* slowbaud */
- 0, 50, 75, 110,
- 134, 150, 200, 300,
- 600, 1200, 1800, 2400,
- 4800, 9600, 19200, 38400 },
- { /* slowbaud & CBAUDEX */
- 0, 57600, 115200, 230400,
- 460800, 150, 200, 921600,
- 600, 1200, 1800, 2400,
- 4800, 9600, 19200, 38400 },
- { /* fastbaud */
- 0, 57600, 76800, 115200,
- 131657, 153600, 230400, 460800,
- 921600, 1200, 1800, 2400,
- 4800, 9600, 19200, 38400 },
- { /* fastbaud & CBAUDEX */
- 0, 57600, 115200, 230400,
- 460800, 150, 200, 921600,
- 600, 1200, 1800, 2400,
- 4800, 9600, 19200, 38400 }
- };
-
- /*
- * Only use the TXPrint baud rate if the terminal
- * unit is NOT open
- */
- if (!(ch->ch_tun.un_flags & UN_ISOPEN) &&
- (un->un_type == DGNC_PRINT))
- baud = C_BAUD(ch->ch_pun.un_tty) & 0xff;
- else
- baud = C_BAUD(ch->ch_tun.un_tty) & 0xff;
-
- if (ch->ch_c_cflag & CBAUDEX)
- iindex = 1;
-
- if (ch->ch_digi.digi_flags & DIGI_FAST)
- iindex += 2;
-
- jindex = baud;
-
- if ((iindex >= 0) && (iindex < 4) && (jindex >= 0) &&
- (jindex < 16)) {
- baud = bauds[iindex][jindex];
- } else {
- baud = 0;
- }
-
- if (baud == 0)
- baud = 9600;
-
- /* Handle transition from B0 */
- if (ch->ch_flags & CH_BAUD0) {
- ch->ch_flags &= ~(CH_BAUD0);
-
- /*
- * Bring back up RTS and DTR...
- * Also handle RTS or DTR toggle if set.
- */
- if (!(ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE))
- ch->ch_mostat |= (UART_MCR_RTS);
- if (!(ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE))
- ch->ch_mostat |= (UART_MCR_DTR);
- }
- }
-
- if (ch->ch_c_cflag & PARENB)
- lcr |= UART_LCR_PARITY;
-
- if (!(ch->ch_c_cflag & PARODD))
- lcr |= UART_LCR_EPAR;
-
-#ifdef CMSPAR
- if (ch->ch_c_cflag & CMSPAR)
- lcr |= UART_LCR_SPAR;
-#endif
-
- if (ch->ch_c_cflag & CSTOPB)
- lcr |= UART_LCR_STOP;
-
- switch (ch->ch_c_cflag & CSIZE) {
- case CS5:
- lcr |= UART_LCR_WLEN5;
- break;
- case CS6:
- lcr |= UART_LCR_WLEN6;
- break;
- case CS7:
- lcr |= UART_LCR_WLEN7;
- break;
- case CS8:
- default:
- lcr |= UART_LCR_WLEN8;
- break;
- }
-
- uart_ier = readb(&ch->ch_cls_uart->ier);
- ier = uart_ier;
- uart_lcr = readb(&ch->ch_cls_uart->lcr);
-
- if (baud == 0)
- baud = 9600;
-
- quot = ch->ch_bd->bd_dividend / baud;
-
- if (quot != 0 && ch->ch_old_baud != baud) {
- ch->ch_old_baud = baud;
- writeb(UART_LCR_DLAB, &ch->ch_cls_uart->lcr);
- writeb((quot & 0xff), &ch->ch_cls_uart->txrx);
- writeb((quot >> 8), &ch->ch_cls_uart->ier);
- writeb(lcr, &ch->ch_cls_uart->lcr);
- }
-
- if (uart_lcr != lcr)
- writeb(lcr, &ch->ch_cls_uart->lcr);
-
- if (ch->ch_c_cflag & CREAD)
- ier |= (UART_IER_RDI | UART_IER_RLSI);
- else
- ier &= ~(UART_IER_RDI | UART_IER_RLSI);
-
- /*
- * Have the UART interrupt on modem signal changes ONLY when
- * we are in hardware flow control mode, or CLOCAL/FORCEDCD is not set.
- */
- if ((ch->ch_digi.digi_flags & CTSPACE) ||
- (ch->ch_digi.digi_flags & RTSPACE) ||
- (ch->ch_c_cflag & CRTSCTS) ||
- !(ch->ch_digi.digi_flags & DIGI_FORCEDCD) ||
- !(ch->ch_c_cflag & CLOCAL))
- ier |= UART_IER_MSI;
- else
- ier &= ~UART_IER_MSI;
-
- ier |= UART_IER_THRI;
-
- if (ier != uart_ier)
- writeb(ier, &ch->ch_cls_uart->ier);
-
- if (ch->ch_digi.digi_flags & CTSPACE || ch->ch_c_cflag & CRTSCTS) {
- cls_set_cts_flow_control(ch);
- } else if (ch->ch_c_iflag & IXON) {
- if ((ch->ch_startc == _POSIX_VDISABLE) ||
- (ch->ch_stopc == _POSIX_VDISABLE))
- cls_set_no_output_flow_control(ch);
- else
- cls_set_ixon_flow_control(ch);
- } else {
- cls_set_no_output_flow_control(ch);
- }
-
- if (ch->ch_digi.digi_flags & RTSPACE || ch->ch_c_cflag & CRTSCTS) {
- cls_set_rts_flow_control(ch);
- } else if (ch->ch_c_iflag & IXOFF) {
- if ((ch->ch_startc == _POSIX_VDISABLE) ||
- (ch->ch_stopc == _POSIX_VDISABLE))
- cls_set_no_input_flow_control(ch);
- else
- cls_set_ixoff_flow_control(ch);
- } else {
- cls_set_no_input_flow_control(ch);
- }
-
- cls_assert_modem_signals(ch);
-
- cls_parse_modem(ch, readb(&ch->ch_cls_uart->msr));
-}
-
-/* Board poller function. */
-static void cls_tasklet(unsigned long data)
-{
- struct dgnc_board *bd = (struct dgnc_board *)data;
- struct channel_t *ch;
- unsigned long flags;
- int i;
- int state = 0;
- int ports = 0;
-
- if (!bd)
- return;
-
- spin_lock_irqsave(&bd->bd_lock, flags);
- state = bd->state;
- ports = bd->nasync;
- spin_unlock_irqrestore(&bd->bd_lock, flags);
-
- /*
- * Do NOT allow the interrupt routine to read the intr registers
- * Until we release this lock.
- */
- spin_lock_irqsave(&bd->bd_intr_lock, flags);
-
- if ((state == BOARD_READY) && (ports > 0)) {
- for (i = 0; i < ports; i++) {
- ch = bd->channels[i];
-
- /*
- * NOTE: Remember you CANNOT hold any channel
- * locks when calling input.
- * During input processing, its possible we
- * will call ld, which might do callbacks back
- * into us.
- */
- dgnc_input(ch);
-
- /*
- * Channel lock is grabbed and then released
- * inside this routine.
- */
- cls_copy_data_from_queue_to_uart(ch);
- dgnc_wakeup_writes(ch);
-
- dgnc_carrier(ch);
-
- /*
- * The timing check of turning off the break is done
- * inside clear_break()
- */
- if (ch->ch_stop_sending_break)
- cls_clear_break(ch, 0);
- }
- }
-
- spin_unlock_irqrestore(&bd->bd_intr_lock, flags);
-}
-
-/* Classic specific interrupt handler. */
-static irqreturn_t cls_intr(int irq, void *voidbrd)
-{
- struct dgnc_board *brd = voidbrd;
- uint i = 0;
- unsigned char poll_reg;
- unsigned long flags;
-
- if (!brd)
- return IRQ_NONE;
-
- spin_lock_irqsave(&brd->bd_intr_lock, flags);
-
- poll_reg = readb(brd->re_map_membase + UART_CLASSIC_POLL_ADDR_OFFSET);
- if (!poll_reg) {
- spin_unlock_irqrestore(&brd->bd_intr_lock, flags);
- return IRQ_NONE;
- }
-
- for (i = 0; i < brd->nasync; i++)
- cls_parse_isr(brd, i);
-
- tasklet_schedule(&brd->helper_tasklet);
-
- spin_unlock_irqrestore(&brd->bd_intr_lock, flags);
-
- return IRQ_HANDLED;
-}
-
-static void cls_disable_receiver(struct channel_t *ch)
-{
- unsigned char tmp = readb(&ch->ch_cls_uart->ier);
-
- tmp &= ~(UART_IER_RDI);
- writeb(tmp, &ch->ch_cls_uart->ier);
-}
-
-static void cls_enable_receiver(struct channel_t *ch)
-{
- unsigned char tmp = readb(&ch->ch_cls_uart->ier);
-
- tmp |= (UART_IER_RDI);
- writeb(tmp, &ch->ch_cls_uart->ier);
-}
-
-/*
- * This function basically goes to sleep for seconds, or until
- * it gets signalled that the port has fully drained.
- */
-static int cls_drain(struct tty_struct *tty, uint seconds)
-{
- unsigned long flags;
- struct channel_t *ch;
- struct un_t *un;
-
- if (!tty)
- return -ENXIO;
-
- un = (struct un_t *)tty->driver_data;
- if (!un)
- return -ENXIO;
-
- ch = un->un_ch;
- if (!ch)
- return -ENXIO;
-
- spin_lock_irqsave(&ch->ch_lock, flags);
- un->un_flags |= UN_EMPTY;
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-
- /* NOTE: Do something with time passed in. */
-
- /* If ret is non-zero, user ctrl-c'ed us */
-
- return wait_event_interruptible(un->un_flags_wait,
- ((un->un_flags & UN_EMPTY) == 0));
-}
-
-static void cls_send_start_character(struct channel_t *ch)
-{
- if (!ch)
- return;
-
- if (ch->ch_startc != _POSIX_VDISABLE) {
- ch->ch_xon_sends++;
- writeb(ch->ch_startc, &ch->ch_cls_uart->txrx);
- }
-}
-
-static void cls_send_stop_character(struct channel_t *ch)
-{
- if (!ch)
- return;
-
- if (ch->ch_stopc != _POSIX_VDISABLE) {
- ch->ch_xoff_sends++;
- writeb(ch->ch_stopc, &ch->ch_cls_uart->txrx);
- }
-}
-
-static void cls_uart_init(struct channel_t *ch)
-{
- unsigned char lcrb = readb(&ch->ch_cls_uart->lcr);
- unsigned char isr_fcr = 0;
-
- writeb(0, &ch->ch_cls_uart->ier);
-
- /*
- * The Enhanced Register Set may only be accessed when
- * the Line Control Register is set to 0xBFh.
- */
- writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
-
- isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
-
- /* Turn on Enhanced/Extended controls */
- isr_fcr |= (UART_EXAR654_EFR_ECB);
-
- writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
-
- /* Write old LCR value back out, which turns enhanced access off */
- writeb(lcrb, &ch->ch_cls_uart->lcr);
-
- /* Clear out UART and FIFO */
- readb(&ch->ch_cls_uart->txrx);
-
- writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
- &ch->ch_cls_uart->isr_fcr);
- usleep_range(10, 20);
-
- ch->ch_flags |= (CH_FIFO_ENABLED | CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
-
- readb(&ch->ch_cls_uart->lsr);
- readb(&ch->ch_cls_uart->msr);
-}
-
-static void cls_uart_off(struct channel_t *ch)
-{
- writeb(0, &ch->ch_cls_uart->ier);
-}
-
-/*
- * The channel lock MUST be held by the calling function.
- * Returns 0 is nothing left in the FIFO, returns 1 otherwise.
- */
-static uint cls_get_uart_bytes_left(struct channel_t *ch)
-{
- unsigned char left = 0;
- unsigned char lsr = 0;
-
- if (!ch)
- return 0;
-
- lsr = readb(&ch->ch_cls_uart->lsr);
-
- /* Determine whether the Transmitter is empty or not */
- if (!(lsr & UART_LSR_TEMT)) {
- if (ch->ch_flags & CH_TX_FIFO_EMPTY)
- tasklet_schedule(&ch->ch_bd->helper_tasklet);
- left = 1;
- } else {
- ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
- left = 0;
- }
-
- return left;
-}
-
-/*
- * Starts sending a break thru the UART.
- * The channel lock MUST be held by the calling function.
- */
-static void cls_send_break(struct channel_t *ch, int msecs)
-{
- if (!ch)
- return;
-
- /* If we receive a time of 0, this means turn off the break. */
- if (msecs == 0) {
- if (ch->ch_flags & CH_BREAK_SENDING) {
- unsigned char temp = readb(&ch->ch_cls_uart->lcr);
-
- writeb((temp & ~UART_LCR_SBC), &ch->ch_cls_uart->lcr);
- ch->ch_flags &= ~(CH_BREAK_SENDING);
- ch->ch_stop_sending_break = 0;
- }
- return;
- }
-
- /*
- * Set the time we should stop sending the break.
- * If we are already sending a break, toss away the existing
- * time to stop, and use this new value instead.
- */
- ch->ch_stop_sending_break = jiffies + dgnc_jiffies_from_ms(msecs);
-
- /* Tell the UART to start sending the break */
- if (!(ch->ch_flags & CH_BREAK_SENDING)) {
- unsigned char temp = readb(&ch->ch_cls_uart->lcr);
-
- writeb((temp | UART_LCR_SBC), &ch->ch_cls_uart->lcr);
- ch->ch_flags |= (CH_BREAK_SENDING);
- }
-}
-
-/*
- * Sends a specific character as soon as possible to the UART,
- * jumping over any bytes that might be in the write queue.
- *
- * The channel lock MUST be held by the calling function.
- */
-static void cls_send_immediate_char(struct channel_t *ch, unsigned char c)
-{
- if (!ch)
- return;
-
- writeb(c, &ch->ch_cls_uart->txrx);
-}
-
-struct board_ops dgnc_cls_ops = {
- .tasklet = cls_tasklet,
- .intr = cls_intr,
- .uart_init = cls_uart_init,
- .uart_off = cls_uart_off,
- .drain = cls_drain,
- .param = cls_param,
- .assert_modem_signals = cls_assert_modem_signals,
- .flush_uart_write = cls_flush_uart_write,
- .flush_uart_read = cls_flush_uart_read,
- .disable_receiver = cls_disable_receiver,
- .enable_receiver = cls_enable_receiver,
- .send_break = cls_send_break,
- .send_start_character = cls_send_start_character,
- .send_stop_character = cls_send_stop_character,
- .copy_data_from_queue_to_uart = cls_copy_data_from_queue_to_uart,
- .get_uart_bytes_left = cls_get_uart_bytes_left,
- .send_immediate_char = cls_send_immediate_char
-};
diff --git a/drivers/staging/dgnc/dgnc_cls.h b/drivers/staging/dgnc/dgnc_cls.h
deleted file mode 100644
index d31508542261..000000000000
--- a/drivers/staging/dgnc/dgnc_cls.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * Copyright 2003 Digi International (www.digi.com)
- * Scott H Kilau <Scott_Kilau at digi dot com>
- */
-
-#ifndef _DGNC_CLS_H
-#define _DGNC_CLS_H
-
-/**
- * struct cls_uart_struct - Per channel/port Classic UART.
- *
- * key - W = read write
- * - R = read only
- * - U = unused
- *
- * @txrx: (WR) Holding Register.
- * @ier: (WR) Interrupt Enable Register.
- * @isr_fcr: (WR) Interrupt Status Register/Fifo Control Register.
- * @lcr: (WR) Line Control Register.
- * @mcr: (WR) Modem Control Register.
- * @lsr: (WR) Line Status Register.
- * @msr: (WR) Modem Status Register.
- * @spr: (WR) Scratch Pad Register.
- */
-struct cls_uart_struct {
- u8 txrx;
- u8 ier;
- u8 isr_fcr;
- u8 lcr;
- u8 mcr;
- u8 lsr;
- u8 msr;
- u8 spr;
-};
-
-/* Where to read the interrupt register (8bits) */
-#define UART_CLASSIC_POLL_ADDR_OFFSET 0x40
-
-#define UART_EXAR654_ENHANCED_REGISTER_SET 0xBF
-
-#define UART_16654_FCR_TXTRIGGER_16 0x10
-#define UART_16654_FCR_RXTRIGGER_16 0x40
-#define UART_16654_FCR_RXTRIGGER_56 0x80
-
-/* Received CTS/RTS change of state */
-#define UART_IIR_CTSRTS 0x20
-
-/* Receiver data TIMEOUT */
-#define UART_IIR_RDI_TIMEOUT 0x0C
-
-/*
- * These are the EXTENDED definitions for the Exar 654's Interrupt
- * Enable Register.
- */
-#define UART_EXAR654_EFR_ECB 0x10 /* Enhanced control bit */
-#define UART_EXAR654_EFR_IXON 0x2 /* Receiver compares Xon1/Xoff1 */
-#define UART_EXAR654_EFR_IXOFF 0x8 /* Transmit Xon1/Xoff1 */
-#define UART_EXAR654_EFR_RTSDTR 0x40 /* Auto RTS/DTR Flow Control Enable */
-#define UART_EXAR654_EFR_CTSDSR 0x80 /* Auto CTS/DSR Flow Control Enable */
-#define UART_EXAR654_IER_XOFF 0x20 /* Xoff Interrupt Enable */
-#define UART_EXAR654_IER_RTSDTR 0x40 /* Output Interrupt Enable */
-#define UART_EXAR654_IER_CTSDSR 0x80 /* Input Interrupt Enable */
-
-extern struct board_ops dgnc_cls_ops;
-
-#endif /* _DGNC_CLS_H */
diff --git a/drivers/staging/dgnc/dgnc_driver.c b/drivers/staging/dgnc/dgnc_driver.c
deleted file mode 100644
index 5d8c2d995dcc..000000000000
--- a/drivers/staging/dgnc/dgnc_driver.c
+++ /dev/null
@@ -1,404 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright 2003 Digi International (www.digi.com)
- * Scott H Kilau <Scott_Kilau at digi dot com>
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include "dgnc_driver.h"
-#include "dgnc_tty.h"
-#include "dgnc_cls.h"
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Digi International, http://www.digi.com");
-MODULE_DESCRIPTION("Driver for the Digi International Neo and Classic PCI based product line");
-MODULE_SUPPORTED_DEVICE("dgnc");
-
-static unsigned int dgnc_num_boards;
-struct dgnc_board *dgnc_board[MAXBOARDS];
-static DEFINE_SPINLOCK(dgnc_poll_lock); /* Poll scheduling lock */
-
-static int dgnc_poll_tick = 20; /* Poll interval - 20 ms */
-static ulong dgnc_poll_time; /* Time of next poll */
-static uint dgnc_poll_stop; /* Used to tell poller to stop */
-static struct timer_list dgnc_poll_timer;
-
-#define DIGI_VID 0x114F
-#define PCI_DEVICE_CLASSIC_4_DID 0x0028
-#define PCI_DEVICE_CLASSIC_8_DID 0x0029
-#define PCI_DEVICE_CLASSIC_4_422_DID 0x00D0
-#define PCI_DEVICE_CLASSIC_8_422_DID 0x00D1
-
-#define PCI_DEVICE_CLASSIC_4_PCI_NAME "ClassicBoard 4 PCI"
-#define PCI_DEVICE_CLASSIC_8_PCI_NAME "ClassicBoard 8 PCI"
-#define PCI_DEVICE_CLASSIC_4_422_PCI_NAME "ClassicBoard 4 422 PCI"
-#define PCI_DEVICE_CLASSIC_8_422_PCI_NAME "ClassicBoard 8 422 PCI"
-
-static const struct pci_device_id dgnc_pci_tbl[] = {
- {PCI_DEVICE(DIGI_VID, PCI_DEVICE_CLASSIC_4_DID), .driver_data = 0},
- {PCI_DEVICE(DIGI_VID, PCI_DEVICE_CLASSIC_4_422_DID), .driver_data = 1},
- {PCI_DEVICE(DIGI_VID, PCI_DEVICE_CLASSIC_8_DID), .driver_data = 2},
- {PCI_DEVICE(DIGI_VID, PCI_DEVICE_CLASSIC_8_422_DID), .driver_data = 3},
- {0,}
-};
-MODULE_DEVICE_TABLE(pci, dgnc_pci_tbl);
-
-struct board_id {
- unsigned char *name;
- uint maxports;
- unsigned int is_pci_express;
-};
-
-static const struct board_id dgnc_ids[] = {
- { PCI_DEVICE_CLASSIC_4_PCI_NAME, 4, 0 },
- { PCI_DEVICE_CLASSIC_4_422_PCI_NAME, 4, 0 },
- { PCI_DEVICE_CLASSIC_8_PCI_NAME, 8, 0 },
- { PCI_DEVICE_CLASSIC_8_422_PCI_NAME, 8, 0 },
- { NULL, 0, 0 }
-};
-
-/* Remap PCI memory. */
-static int dgnc_do_remap(struct dgnc_board *brd)
-{
- brd->re_map_membase = ioremap(brd->membase, 0x1000);
- if (!brd->re_map_membase)
- return -ENOMEM;
-
- return 0;
-}
-
-/* A board has been found, initialize it. */
-static struct dgnc_board *dgnc_found_board(struct pci_dev *pdev, int id)
-{
- struct dgnc_board *brd;
- unsigned int pci_irq;
- int rc = 0;
-
- brd = kzalloc(sizeof(*brd), GFP_KERNEL);
- if (!brd)
- return ERR_PTR(-ENOMEM);
-
- /* store the info for the board we've found */
- brd->boardnum = dgnc_num_boards;
- brd->device = dgnc_pci_tbl[id].device;
- brd->pdev = pdev;
- brd->name = dgnc_ids[id].name;
- brd->maxports = dgnc_ids[id].maxports;
- init_waitqueue_head(&brd->state_wait);
-
- spin_lock_init(&brd->bd_lock);
- spin_lock_init(&brd->bd_intr_lock);
-
- brd->state = BOARD_FOUND;
-
- pci_irq = pdev->irq;
- brd->irq = pci_irq;
-
- switch (brd->device) {
- case PCI_DEVICE_CLASSIC_4_DID:
- case PCI_DEVICE_CLASSIC_8_DID:
- case PCI_DEVICE_CLASSIC_4_422_DID:
- case PCI_DEVICE_CLASSIC_8_422_DID:
- /*
- * For PCI ClassicBoards
- * PCI Local Address (i.e. "resource" number) space
- * 0 PLX Memory Mapped Config
- * 1 PLX I/O Mapped Config
- * 2 I/O Mapped UARTs and Status
- * 3 Memory Mapped VPD
- * 4 Memory Mapped UARTs and Status
- */
-
- brd->membase = pci_resource_start(pdev, 4);
-
- if (!brd->membase) {
- dev_err(&brd->pdev->dev,
- "Card has no PCI IO resources, failing.\n");
- rc = -ENODEV;
- goto failed;
- }
-
- brd->membase_end = pci_resource_end(pdev, 4);
-
- if (brd->membase & 1)
- brd->membase &= ~3;
- else
- brd->membase &= ~15;
-
- brd->iobase = pci_resource_start(pdev, 1);
- brd->iobase_end = pci_resource_end(pdev, 1);
- brd->iobase = ((unsigned int)(brd->iobase)) & 0xFFFE;
-
- brd->bd_ops = &dgnc_cls_ops;
-
- brd->bd_uart_offset = 0x8;
- brd->bd_dividend = 921600;
-
- rc = dgnc_do_remap(brd);
- if (rc < 0)
- goto failed;
-
- /*
- * Enable Local Interrupt 1 (0x1),
- * Local Interrupt 1 Polarity Active high (0x2),
- * Enable PCI interrupt (0x40)
- */
- outb(0x43, brd->iobase + 0x4c);
-
- break;
-
- default:
- dev_err(&brd->pdev->dev,
- "Didn't find any compatible Neo/Classic PCI boards.\n");
- rc = -ENXIO;
- goto failed;
- }
-
- tasklet_init(&brd->helper_tasklet,
- brd->bd_ops->tasklet,
- (unsigned long)brd);
-
- wake_up_interruptible(&brd->state_wait);
-
- return brd;
-
-failed:
- kfree(brd);
-
- return ERR_PTR(rc);
-}
-
-static int dgnc_request_irq(struct dgnc_board *brd)
-{
- if (brd->irq) {
- int rc = request_irq(brd->irq, brd->bd_ops->intr,
- IRQF_SHARED, "DGNC", brd);
- if (rc) {
- dev_err(&brd->pdev->dev,
- "Failed to hook IRQ %d\n", brd->irq);
- brd->state = BOARD_FAILED;
- return -ENODEV;
- }
- }
- return 0;
-}
-
-static void dgnc_free_irq(struct dgnc_board *brd)
-{
- if (brd->irq)
- free_irq(brd->irq, brd);
-}
-
- /*
- * As each timer expires, it determines (a) whether the "transmit"
- * waiter needs to be woken up, and (b) whether the poller needs to
- * be rescheduled.
- */
-static void dgnc_poll_handler(struct timer_list *unused)
-{
- struct dgnc_board *brd;
- unsigned long flags;
- int i;
- unsigned long new_time;
-
- for (i = 0; i < dgnc_num_boards; i++) {
- brd = dgnc_board[i];
-
- spin_lock_irqsave(&brd->bd_lock, flags);
-
- if (brd->state == BOARD_FAILED) {
- spin_unlock_irqrestore(&brd->bd_lock, flags);
- continue;
- }
-
- tasklet_schedule(&brd->helper_tasklet);
-
- spin_unlock_irqrestore(&brd->bd_lock, flags);
- }
-
- /* Schedule ourself back at the nominal wakeup interval. */
-
- spin_lock_irqsave(&dgnc_poll_lock, flags);
- dgnc_poll_time += dgnc_jiffies_from_ms(dgnc_poll_tick);
-
- new_time = dgnc_poll_time - jiffies;
-
- if ((ulong)new_time >= 2 * dgnc_poll_tick)
- dgnc_poll_time = jiffies + dgnc_jiffies_from_ms(dgnc_poll_tick);
-
- timer_setup(&dgnc_poll_timer, dgnc_poll_handler, 0);
- dgnc_poll_timer.expires = dgnc_poll_time;
- spin_unlock_irqrestore(&dgnc_poll_lock, flags);
-
- if (!dgnc_poll_stop)
- add_timer(&dgnc_poll_timer);
-}
-
-/* returns count (>= 0), or negative on error */
-static int dgnc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- int rc;
- struct dgnc_board *brd;
-
- rc = pci_enable_device(pdev);
- if (rc)
- return -EIO;
-
- brd = dgnc_found_board(pdev, ent->driver_data);
- if (IS_ERR(brd))
- return PTR_ERR(brd);
-
- rc = dgnc_tty_register(brd);
- if (rc < 0) {
- pr_err(DRVSTR ": Can't register tty devices (%d)\n", rc);
- goto failed;
- }
-
- rc = dgnc_request_irq(brd);
- if (rc < 0) {
- pr_err(DRVSTR ": Can't finalize board init (%d)\n", rc);
- goto unregister_tty;
- }
-
- rc = dgnc_tty_init(brd);
- if (rc < 0) {
- pr_err(DRVSTR ": Can't init tty devices (%d)\n", rc);
- goto free_irq;
- }
-
- brd->state = BOARD_READY;
-
- dgnc_board[dgnc_num_boards++] = brd;
-
- return 0;
-
-free_irq:
- dgnc_free_irq(brd);
-unregister_tty:
- dgnc_tty_unregister(brd);
-failed:
- kfree(brd);
-
- return rc;
-}
-
-static struct pci_driver dgnc_driver = {
- .name = "dgnc",
- .probe = dgnc_init_one,
- .id_table = dgnc_pci_tbl,
-};
-
-static int dgnc_start(void)
-{
- unsigned long flags;
-
- /* Start the poller */
- spin_lock_irqsave(&dgnc_poll_lock, flags);
- timer_setup(&dgnc_poll_timer, dgnc_poll_handler, 0);
- dgnc_poll_time = jiffies + dgnc_jiffies_from_ms(dgnc_poll_tick);
- dgnc_poll_timer.expires = dgnc_poll_time;
- spin_unlock_irqrestore(&dgnc_poll_lock, flags);
-
- add_timer(&dgnc_poll_timer);
-
- return 0;
-}
-
-/* Free all the memory associated with a board */
-static void dgnc_cleanup_board(struct dgnc_board *brd)
-{
- int i = 0;
-
- if (!brd)
- return;
-
- switch (brd->device) {
- case PCI_DEVICE_CLASSIC_4_DID:
- case PCI_DEVICE_CLASSIC_8_DID:
- case PCI_DEVICE_CLASSIC_4_422_DID:
- case PCI_DEVICE_CLASSIC_8_422_DID:
-
- /* Tell card not to interrupt anymore. */
- outb(0, brd->iobase + 0x4c);
- break;
-
- default:
- break;
- }
-
- if (brd->irq)
- free_irq(brd->irq, brd);
-
- tasklet_kill(&brd->helper_tasklet);
-
- if (brd->re_map_membase) {
- iounmap(brd->re_map_membase);
- brd->re_map_membase = NULL;
- }
-
- for (i = 0; i < MAXPORTS ; i++) {
- if (brd->channels[i]) {
- kfree(brd->channels[i]->ch_rqueue);
- kfree(brd->channels[i]->ch_equeue);
- kfree(brd->channels[i]->ch_wqueue);
- kfree(brd->channels[i]);
- brd->channels[i] = NULL;
- }
- }
-
- dgnc_board[brd->boardnum] = NULL;
-
- kfree(brd);
-}
-
-/* Driver load/unload functions */
-
-static void cleanup(void)
-{
- int i;
- unsigned long flags;
-
- spin_lock_irqsave(&dgnc_poll_lock, flags);
- dgnc_poll_stop = 1;
- spin_unlock_irqrestore(&dgnc_poll_lock, flags);
-
- /* Turn off poller right away. */
- del_timer_sync(&dgnc_poll_timer);
-
- for (i = 0; i < dgnc_num_boards; ++i) {
- dgnc_cleanup_tty(dgnc_board[i]);
- dgnc_cleanup_board(dgnc_board[i]);
- }
-}
-
-static void __exit dgnc_cleanup_module(void)
-{
- cleanup();
- pci_unregister_driver(&dgnc_driver);
-}
-
-static int __init dgnc_init_module(void)
-{
- int rc;
-
- /* Initialize global stuff */
- rc = dgnc_start();
- if (rc < 0)
- return rc;
-
- /* Find and configure all the cards */
- rc = pci_register_driver(&dgnc_driver);
- if (rc) {
- pr_warn("WARNING: dgnc driver load failed. No Digi Neo or Classic boards found.\n");
- cleanup();
- return rc;
- }
- return 0;
-}
-
-module_init(dgnc_init_module);
-module_exit(dgnc_cleanup_module);
diff --git a/drivers/staging/dgnc/dgnc_driver.h b/drivers/staging/dgnc/dgnc_driver.h
deleted file mode 100644
index b4d9f714c60a..000000000000
--- a/drivers/staging/dgnc/dgnc_driver.h
+++ /dev/null
@@ -1,345 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * Copyright 2003 Digi International (www.digi.com)
- * Scott H Kilau <Scott_Kilau at digi dot com>
- */
-
-#ifndef _DGNC_DRIVER_H
-#define _DGNC_DRIVER_H
-
-#include <linux/types.h>
-#include <linux/tty.h>
-#include <linux/interrupt.h>
-
-#include "digi.h" /* Digi specific ioctl header */
-
-/* Driver identification and error statements */
-#define PROCSTR "dgnc" /* /proc entries */
-#define DEVSTR "/dev/dg/dgnc" /* /dev entries */
-#define DRVSTR "dgnc" /* Driver name string */
-#define DG_PART "40002369_F" /* RPM part number */
-
-#define TRC_TO_CONSOLE 1
-
-/* Number of boards we support at once. */
-#define MAXBOARDS 20
-#define MAXPORTS 8
-#define MAXTTYNAMELEN 200
-
-/* Serial port types */
-#define DGNC_SERIAL 0
-#define DGNC_PRINT 1
-
-#define SERIAL_TYPE_NORMAL 1
-
-#define PORT_NUM(dev) ((dev) & 0x7f)
-#define IS_PRINT(dev) (((dev) & 0xff) >= 0x80)
-
-/* MAX number of stop characters sent when our read queue is getting full */
-#define MAX_STOPS_SENT 5
-
-/* 4 extra for alignment play space */
-#define WRITEBUFLEN ((4096) + 4)
-
-#define dgnc_jiffies_from_ms(a) (((a) * HZ) / 1000)
-
-#ifndef _POSIX_VDISABLE
-#define _POSIX_VDISABLE '\0'
-#endif
-
-/* All the possible states the driver can be while being loaded. */
-enum {
- DRIVER_INITIALIZED = 0,
- DRIVER_READY
-};
-
-/* All the possible states the board can be while booting up. */
-enum {
- BOARD_FAILED = 0,
- BOARD_FOUND,
- BOARD_READY
-};
-
-struct dgnc_board;
-struct channel_t;
-
-/**
- * struct board_ops - Per board operations.
- */
-struct board_ops {
- void (*tasklet)(unsigned long data);
- irqreturn_t (*intr)(int irq, void *voidbrd);
- void (*uart_init)(struct channel_t *ch);
- void (*uart_off)(struct channel_t *ch);
- int (*drain)(struct tty_struct *tty, uint seconds);
- void (*param)(struct tty_struct *tty);
- void (*assert_modem_signals)(struct channel_t *ch);
- void (*flush_uart_write)(struct channel_t *ch);
- void (*flush_uart_read)(struct channel_t *ch);
- void (*disable_receiver)(struct channel_t *ch);
- void (*enable_receiver)(struct channel_t *ch);
- void (*send_break)(struct channel_t *ch, int msec);
- void (*send_start_character)(struct channel_t *ch);
- void (*send_stop_character)(struct channel_t *ch);
- void (*copy_data_from_queue_to_uart)(struct channel_t *ch);
- uint (*get_uart_bytes_left)(struct channel_t *ch);
- void (*send_immediate_char)(struct channel_t *ch, unsigned char c);
-};
-
-/**
- * struct dgnc_board - Per board information.
- * @boardnum: Board number (0 - 32).
- *
- * @name: Product name.
- * @pdev: Pointer to the pci_dev structure.
- * @device: PCI device ID.
- * @maxports: Maximum ports this board can handle.
- * @bd_lock: Used to protect board.
- * @bd_intr_lock: Protect poller tasklet and interrupt routine from each other.
- * @state: State of the card.
- * @state_wait: Queue to sleep on for state change.
- * @helper_tasklet: Poll helper tasklet.
- * @nasync: Number of ports on card.
- * @irq: Interrupt request number.
- * @membase: Start of base memory of the card.
- * @membase_end: End of base memory of the card.
- * @iobase: Start of IO base of the card.
- * @iobase_end: End of IO base of the card.
- * @bd_uart_offset: Space between each UART.
- * @channels: array of pointers to our channels.
- * @serial_driver: Pointer to the serial driver.
- * @serial_name: Serial driver name.
- * @print_dirver: Pointer to the print driver.
- * @print_name: Print driver name.
- * @bd_dividend: Board/UART's specific dividend.
- * @bd_ops: Pointer to board operations structure.
- */
-struct dgnc_board {
- int boardnum;
- char *name;
- struct pci_dev *pdev;
- u16 device;
- uint maxports;
-
- /* used to protect the board */
- spinlock_t bd_lock;
-
- /* Protect poller tasklet and interrupt routine from each other. */
- spinlock_t bd_intr_lock;
-
- uint state;
- wait_queue_head_t state_wait;
-
- struct tasklet_struct helper_tasklet;
-
- uint nasync;
-
- uint irq;
-
- ulong membase;
- ulong membase_end;
-
- u8 __iomem *re_map_membase;
-
- ulong iobase;
- ulong iobase_end;
-
- uint bd_uart_offset;
-
- struct channel_t *channels[MAXPORTS];
-
- struct tty_driver *serial_driver;
- char serial_name[200];
- struct tty_driver *print_driver;
- char print_name[200];
-
- uint bd_dividend;
-
- struct board_ops *bd_ops;
-};
-
-/* Unit flag definitions for un_flags. */
-#define UN_ISOPEN 0x0001 /* Device is open */
-#define UN_CLOSING 0x0002 /* Line is being closed */
-#define UN_IMM 0x0004 /* Service immediately */
-#define UN_BUSY 0x0008 /* Some work this channel */
-#define UN_BREAKI 0x0010 /* Input break received */
-#define UN_PWAIT 0x0020 /* Printer waiting for terminal */
-#define UN_TIME 0x0040 /* Waiting on time */
-#define UN_EMPTY 0x0080 /* Waiting output queue empty */
-#define UN_LOW 0x0100 /* Waiting output low water mark*/
-#define UN_EXCL_OPEN 0x0200 /* Open for exclusive use */
-#define UN_WOPEN 0x0400 /* Device waiting for open */
-#define UN_WIOCTL 0x0800 /* Device waiting for open */
-#define UN_HANGUP 0x8000 /* Carrier lost */
-
-struct device;
-
-/**
- * struct un_t - terminal or printer unit
- * @un_open_count: Counter of opens to port.
- * @un_tty: Pointer to unit tty structure.
- * @un_flags: Unit flags.
- * @un_flags_wait: Place to sleep to wait on unit.
- * @un_dev: Minor device number.
- */
-struct un_t {
- struct channel_t *un_ch;
- uint un_type;
- uint un_open_count;
- struct tty_struct *un_tty;
- uint un_flags;
- wait_queue_head_t un_flags_wait;
- uint un_dev;
- struct device *un_sysfs;
-};
-
-/* Device flag definitions for ch_flags. */
-#define CH_PRON 0x0001 /* Printer on string */
-#define CH_STOP 0x0002 /* Output is stopped */
-#define CH_STOPI 0x0004 /* Input is stopped */
-#define CH_CD 0x0008 /* Carrier is present */
-#define CH_FCAR 0x0010 /* Carrier forced on */
-#define CH_HANGUP 0x0020 /* Hangup received */
-
-#define CH_RECEIVER_OFF 0x0040 /* Receiver is off */
-#define CH_OPENING 0x0080 /* Port in fragile open state */
-#define CH_CLOSING 0x0100 /* Port in fragile close state */
-#define CH_FIFO_ENABLED 0x0200 /* Port has FIFOs enabled */
-#define CH_TX_FIFO_EMPTY 0x0400 /* TX Fifo is completely empty */
-#define CH_TX_FIFO_LWM 0x0800 /* TX Fifo is below Low Water */
-#define CH_BREAK_SENDING 0x1000 /* Break is being sent */
-#define CH_LOOPBACK 0x2000 /* Channel is in lookback mode */
-#define CH_BAUD0 0x08000 /* Used for checking B0 transitions */
-#define CH_FORCED_STOP 0x20000 /* Output is forcibly stopped */
-#define CH_FORCED_STOPI 0x40000 /* Input is forcibly stopped */
-
-/* Our Read/Error/Write queue sizes */
-#define RQUEUEMASK 0x1FFF /* 8 K - 1 */
-#define EQUEUEMASK 0x1FFF /* 8 K - 1 */
-#define WQUEUEMASK 0x0FFF /* 4 K - 1 */
-#define RQUEUESIZE (RQUEUEMASK + 1)
-#define EQUEUESIZE RQUEUESIZE
-#define WQUEUESIZE (WQUEUEMASK + 1)
-
-/**
- * struct channel_t - Channel information.
- * @dgnc_board: Pointer to board structure.
- * @ch_bd: Transparent print structure.
- * @ch_tun: Terminal unit information.
- * @ch_pun: Printer unit information.
- * @ch_lock: Provide for serialization.
- * @ch_flags_wait: Channel flags wait queue.
- * @ch_portnum: Port number, 0 offset.
- * @ch_open_count: Open count.
- * @ch_flags: Channel flags.
- * @ch_close_delay: How long we should drop RTS/DTR for.
- * @ch_cpstime: Time for CPS calculations.
- * @ch_c_iflag: Channel iflags.
- * @ch_c_cflag: Channel cflags.
- * @ch_c_oflag: Channel oflags.
- * @ch_c_lflag: Channel lflags.
- * @ch_stopc: Stop character.
- * @ch_startc: Start character.
- * @ch_old_baud: Cache of the current baud rate.
- * @ch_custom_speed: Custom baud rate, if set.
- * @ch_wopen: Waiting for open process count.
- * @ch_mostat: FEP output modem status.
- * @ch_mistat: FEP input modem status.
- * @ch_cls_uart: Pointer to the mapped cls UART struct
- * @ch_cached_lsr: Cached value of the LSR register.
- * @ch_rqueue: Read queue buffer, malloc'ed.
- * @ch_r_head: Head location of the read queue.
- * @ch_r_tail: Tail location of the read queue.
- * @ch_equeue: Error queue buffer, malloc'ed.
- * @ch_e_head: Head location of the error queue.
- * @ch_e_tail: Tail location of the error queue.
- * @ch_wqueue: Write queue buffer, malloc'ed.
- * @ch_w_head: Head location of the write queue.
- * @ch_w_tail: Tail location of the write queue.
- * @ch_rxcount: Total of data received so far.
- * @ch_txcount: Total of data transmitted so far.
- * @ch_r_tlevel: Receive trigger level.
- * @ch_t_tlevel: Transmit trigger level.
- * @ch_r_watermark: Receive water mark.
- * @ch_stop_sending_break: Time we should STOP sending a break.
- * @ch_stops_sent: How many times I have send a stop character to try
- * to stop the other guy sending.
- * @ch_err_parity: Count of parity
- * @ch_err_frame: Count of framing errors on channel.
- * @ch_err_break: Count of breaks on channel.
- * @ch_err_overrun: Count of overruns on channel.
- * @ch_xon_sends: Count of xons transmitted.
- * @ch_xoff_sends: Count of xoffs transmitted.
- */
-struct channel_t {
- struct dgnc_board *ch_bd;
- struct digi_t ch_digi;
- struct un_t ch_tun;
- struct un_t ch_pun;
-
- spinlock_t ch_lock; /* provide for serialization */
- wait_queue_head_t ch_flags_wait;
-
- uint ch_portnum;
- uint ch_open_count;
- uint ch_flags;
-
- ulong ch_close_delay;
-
- ulong ch_cpstime;
-
- tcflag_t ch_c_iflag;
- tcflag_t ch_c_cflag;
- tcflag_t ch_c_oflag;
- tcflag_t ch_c_lflag;
- unsigned char ch_stopc;
- unsigned char ch_startc;
-
- uint ch_old_baud;
- uint ch_custom_speed;
-
- uint ch_wopen;
-
- unsigned char ch_mostat;
- unsigned char ch_mistat;
-
- struct cls_uart_struct __iomem *ch_cls_uart;
-
- unsigned char ch_cached_lsr;
-
- unsigned char *ch_rqueue;
- ushort ch_r_head;
- ushort ch_r_tail;
-
- unsigned char *ch_equeue;
- ushort ch_e_head;
- ushort ch_e_tail;
-
- unsigned char *ch_wqueue;
- ushort ch_w_head;
- ushort ch_w_tail;
-
- ulong ch_rxcount;
- ulong ch_txcount;
-
- unsigned char ch_r_tlevel;
- unsigned char ch_t_tlevel;
-
- unsigned char ch_r_watermark;
-
- ulong ch_stop_sending_break;
- uint ch_stops_sent;
-
- ulong ch_err_parity;
- ulong ch_err_frame;
- ulong ch_err_break;
- ulong ch_err_overrun;
-
- ulong ch_xon_sends;
- ulong ch_xoff_sends;
-};
-
-extern struct dgnc_board *dgnc_board[MAXBOARDS];/* Array of boards */
-
-#endif /* _DGNC_DRIVER_H */
diff --git a/drivers/staging/dgnc/dgnc_tty.c b/drivers/staging/dgnc/dgnc_tty.c
deleted file mode 100644
index f91eaa1c3b67..000000000000
--- a/drivers/staging/dgnc/dgnc_tty.c
+++ /dev/null
@@ -1,2590 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright 2003 Digi International (www.digi.com)
- * Scott H Kilau <Scott_Kilau at digi dot com>
- */
-
-/*
- * This file implements the tty driver functionality for the
- * Neo and ClassicBoard PCI based product lines.
- */
-
-#include <linux/kernel.h>
-#include <linux/sched/signal.h> /* For jiffies, task states, etc. */
-#include <linux/interrupt.h> /* For tasklet and interrupt structs/defines */
-#include <linux/module.h>
-#include <linux/ctype.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/types.h>
-#include <linux/serial_reg.h>
-#include <linux/slab.h>
-#include <linux/delay.h> /* For udelay */
-#include <linux/uaccess.h> /* For copy_from_user/copy_to_user */
-#include <linux/pci.h>
-#include "dgnc_driver.h"
-#include "dgnc_tty.h"
-#include "dgnc_cls.h"
-
-/* Default transparent print information. */
-
-static const struct digi_t dgnc_digi_init = {
- .digi_flags = DIGI_COOK, /* Flags */
- .digi_maxcps = 100, /* Max CPS */
- .digi_maxchar = 50, /* Max chars in print queue */
- .digi_bufsize = 100, /* Printer buffer size */
- .digi_onlen = 4, /* size of printer on string */
- .digi_offlen = 4, /* size of printer off string */
- .digi_onstr = "\033[5i", /* ANSI printer on string ] */
- .digi_offstr = "\033[4i", /* ANSI printer off string ] */
- .digi_term = "ansi" /* default terminal type */
-};
-
-static int dgnc_tty_open(struct tty_struct *tty, struct file *file);
-static void dgnc_tty_close(struct tty_struct *tty, struct file *file);
-static int dgnc_block_til_ready(struct tty_struct *tty, struct file *file,
- struct channel_t *ch);
-static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
- unsigned long arg);
-static int dgnc_tty_digigeta(struct tty_struct *tty,
- struct digi_t __user *retinfo);
-static int dgnc_tty_digiseta(struct tty_struct *tty,
- struct digi_t __user *new_info);
-static int dgnc_tty_write_room(struct tty_struct *tty);
-static int dgnc_tty_put_char(struct tty_struct *tty, unsigned char c);
-static int dgnc_tty_chars_in_buffer(struct tty_struct *tty);
-static void dgnc_tty_start(struct tty_struct *tty);
-static void dgnc_tty_stop(struct tty_struct *tty);
-static void dgnc_tty_throttle(struct tty_struct *tty);
-static void dgnc_tty_unthrottle(struct tty_struct *tty);
-static void dgnc_tty_flush_chars(struct tty_struct *tty);
-static void dgnc_tty_flush_buffer(struct tty_struct *tty);
-static void dgnc_tty_hangup(struct tty_struct *tty);
-static int dgnc_set_modem_info(struct channel_t *ch, unsigned int command,
- unsigned int __user *value);
-static int dgnc_get_modem_info(struct channel_t *ch,
- unsigned int __user *value);
-static int dgnc_tty_tiocmget(struct tty_struct *tty);
-static int dgnc_tty_tiocmset(struct tty_struct *tty, unsigned int set,
- unsigned int clear);
-static int dgnc_tty_send_break(struct tty_struct *tty, int msec);
-static void dgnc_tty_wait_until_sent(struct tty_struct *tty, int timeout);
-static int dgnc_tty_write(struct tty_struct *tty, const unsigned char *buf,
- int count);
-static void dgnc_tty_set_termios(struct tty_struct *tty,
- struct ktermios *old_termios);
-static void dgnc_tty_send_xchar(struct tty_struct *tty, char ch);
-static void dgnc_set_signal_low(struct channel_t *ch, const unsigned char line);
-static void dgnc_wake_up_unit(struct un_t *unit);
-
-static const struct tty_operations dgnc_tty_ops = {
- .open = dgnc_tty_open,
- .close = dgnc_tty_close,
- .write = dgnc_tty_write,
- .write_room = dgnc_tty_write_room,
- .flush_buffer = dgnc_tty_flush_buffer,
- .chars_in_buffer = dgnc_tty_chars_in_buffer,
- .flush_chars = dgnc_tty_flush_chars,
- .ioctl = dgnc_tty_ioctl,
- .set_termios = dgnc_tty_set_termios,
- .stop = dgnc_tty_stop,
- .start = dgnc_tty_start,
- .throttle = dgnc_tty_throttle,
- .unthrottle = dgnc_tty_unthrottle,
- .hangup = dgnc_tty_hangup,
- .put_char = dgnc_tty_put_char,
- .tiocmget = dgnc_tty_tiocmget,
- .tiocmset = dgnc_tty_tiocmset,
- .break_ctl = dgnc_tty_send_break,
- .wait_until_sent = dgnc_tty_wait_until_sent,
- .send_xchar = dgnc_tty_send_xchar
-};
-
-/* TTY Initialization/Cleanup Functions */
-
-static struct tty_driver *dgnc_tty_create(char *serial_name, uint maxports,
- int major, int minor)
-{
- int rc;
- struct tty_driver *drv;
-
- drv = tty_alloc_driver(maxports,
- TTY_DRIVER_REAL_RAW |
- TTY_DRIVER_DYNAMIC_DEV |
- TTY_DRIVER_HARDWARE_BREAK);
- if (IS_ERR(drv))
- return drv;
-
- drv->name = serial_name;
- drv->name_base = 0;
- drv->major = major;
- drv->minor_start = minor;
- drv->type = TTY_DRIVER_TYPE_SERIAL;
- drv->subtype = SERIAL_TYPE_NORMAL;
- drv->init_termios = tty_std_termios;
- drv->init_termios.c_cflag = (B9600 | CS8 | CREAD | HUPCL | CLOCAL);
- drv->init_termios.c_ispeed = 9600;
- drv->init_termios.c_ospeed = 9600;
- drv->driver_name = DRVSTR;
- /*
- * Entry points for driver. Called by the kernel from
- * tty_io.c and n_tty.c.
- */
- tty_set_operations(drv, &dgnc_tty_ops);
- rc = tty_register_driver(drv);
- if (rc < 0) {
- put_tty_driver(drv);
- return ERR_PTR(rc);
- }
- return drv;
-}
-
-static void dgnc_tty_free(struct tty_driver *drv)
-{
- tty_unregister_driver(drv);
- put_tty_driver(drv);
-}
-
-/**
- * dgnc_tty_register() - Init the tty subsystem for this board.
- */
-int dgnc_tty_register(struct dgnc_board *brd)
-{
- int rc;
-
- snprintf(brd->serial_name, MAXTTYNAMELEN, "tty_dgnc_%d_",
- brd->boardnum);
-
- brd->serial_driver = dgnc_tty_create(brd->serial_name,
- brd->maxports, 0, 0);
- if (IS_ERR(brd->serial_driver)) {
- rc = PTR_ERR(brd->serial_driver);
- dev_dbg(&brd->pdev->dev, "Can't register tty device (%d)\n",
- rc);
- return rc;
- }
-
- snprintf(brd->print_name, MAXTTYNAMELEN, "pr_dgnc_%d_", brd->boardnum);
- brd->print_driver = dgnc_tty_create(brd->print_name, brd->maxports,
- 0x80,
- brd->serial_driver->major);
- if (IS_ERR(brd->print_driver)) {
- rc = PTR_ERR(brd->print_driver);
- dev_dbg(&brd->pdev->dev,
- "Can't register Transparent Print device(%d)\n", rc);
- dgnc_tty_free(brd->serial_driver);
- return rc;
- }
- return 0;
-}
-
-void dgnc_tty_unregister(struct dgnc_board *brd)
-{
- dgnc_tty_free(brd->print_driver);
- dgnc_tty_free(brd->serial_driver);
-}
-
-/**
- * dgnc_tty_init() - Initialize the tty subsystem.
- *
- * Called once per board after board has been downloaded and initialized.
- */
-int dgnc_tty_init(struct dgnc_board *brd)
-{
- int i;
- int rc;
- void __iomem *vaddr;
- struct channel_t *ch;
-
- if (!brd)
- return -ENXIO;
-
- /* Initialize board structure elements. */
-
- vaddr = brd->re_map_membase;
-
- brd->nasync = brd->maxports;
-
- for (i = 0; i < brd->nasync; i++) {
- brd->channels[i] = kzalloc(sizeof(*brd->channels[i]),
- GFP_KERNEL);
- if (!brd->channels[i]) {
- rc = -ENOMEM;
- goto err_free_channels;
- }
- }
-
- ch = brd->channels[0];
- vaddr = brd->re_map_membase;
-
- /* Set up channel variables */
- for (i = 0; i < brd->nasync; i++, ch = brd->channels[i]) {
- spin_lock_init(&ch->ch_lock);
-
- ch->ch_tun.un_ch = ch;
- ch->ch_tun.un_type = DGNC_SERIAL;
- ch->ch_tun.un_dev = i;
-
- ch->ch_pun.un_ch = ch;
- ch->ch_pun.un_type = DGNC_PRINT;
- ch->ch_pun.un_dev = i + 128;
-
- ch->ch_cls_uart = vaddr + (brd->bd_uart_offset * i);
-
- ch->ch_bd = brd;
- ch->ch_portnum = i;
- ch->ch_digi = dgnc_digi_init;
-
- /* .25 second delay */
- ch->ch_close_delay = 250;
-
- init_waitqueue_head(&ch->ch_flags_wait);
- init_waitqueue_head(&ch->ch_tun.un_flags_wait);
- init_waitqueue_head(&ch->ch_pun.un_flags_wait);
-
- {
- struct device *classp;
-
- classp = tty_register_device(brd->serial_driver, i,
- &ch->ch_bd->pdev->dev);
- ch->ch_tun.un_sysfs = classp;
-
- classp = tty_register_device(brd->print_driver, i,
- &ch->ch_bd->pdev->dev);
- ch->ch_pun.un_sysfs = classp;
- }
- }
-
- return 0;
-
-err_free_channels:
- for (i = i - 1; i >= 0; --i) {
- kfree(brd->channels[i]);
- brd->channels[i] = NULL;
- }
-
- return rc;
-}
-
-/**
- * dgnc_cleanup_tty() - Cleanup driver.
- *
- * Uninitialize the TTY portion of this driver. Free all memory and
- * resources.
- */
-void dgnc_cleanup_tty(struct dgnc_board *brd)
-{
- int i = 0;
-
- for (i = 0; i < brd->nasync; i++)
- tty_unregister_device(brd->serial_driver, i);
-
- tty_unregister_driver(brd->serial_driver);
-
- for (i = 0; i < brd->nasync; i++)
- tty_unregister_device(brd->print_driver, i);
-
- tty_unregister_driver(brd->print_driver);
-
- put_tty_driver(brd->serial_driver);
- put_tty_driver(brd->print_driver);
-}
-
-/**
- * dgnc_wmove() - Write data to transmit queue.
- * @ch: Pointer to channel structure.
- * @buf: Pointer to characters to be moved.
- * @n: Number of characters to move.
- */
-static void dgnc_wmove(struct channel_t *ch, char *buf, uint n)
-{
- int remain;
- uint head;
-
- if (!ch)
- return;
-
- head = ch->ch_w_head & WQUEUEMASK;
-
- /*
- * If the write wraps over the top of the circular buffer,
- * move the portion up to the wrap point, and reset the
- * pointers to the bottom.
- */
- remain = WQUEUESIZE - head;
-
- if (n >= remain) {
- n -= remain;
- memcpy(ch->ch_wqueue + head, buf, remain);
- head = 0;
- buf += remain;
- }
-
- if (n > 0) {
- /* Move rest of data. */
- remain = n;
- memcpy(ch->ch_wqueue + head, buf, remain);
- head += remain;
- }
-
- head &= WQUEUEMASK;
- ch->ch_w_head = head;
-}
-
-/**
- * dgnc_input() - Process received data.
- * @ch: Pointer to channel structure.
- */
-void dgnc_input(struct channel_t *ch)
-{
- struct dgnc_board *bd;
- struct tty_struct *tp;
- struct tty_ldisc *ld = NULL;
- uint rmask;
- ushort head;
- ushort tail;
- int data_len;
- unsigned long flags;
- int flip_len;
- int len = 0;
- int n = 0;
- int s = 0;
- int i = 0;
-
- if (!ch)
- return;
-
- tp = ch->ch_tun.un_tty;
-
- bd = ch->ch_bd;
- if (!bd)
- return;
-
- spin_lock_irqsave(&ch->ch_lock, flags);
-
- rmask = RQUEUEMASK;
- head = ch->ch_r_head & rmask;
- tail = ch->ch_r_tail & rmask;
- data_len = (head - tail) & rmask;
-
- if (data_len == 0)
- goto exit_unlock;
-
- /*
- * If the device is not open, or CREAD is off,
- * flush input data and return immediately.
- */
- if (!tp ||
- !(ch->ch_tun.un_flags & UN_ISOPEN) ||
- !C_CREAD(tp) ||
- (ch->ch_tun.un_flags & UN_CLOSING)) {
- ch->ch_r_head = tail;
-
- /* Force queue flow control to be released, if needed */
- dgnc_check_queue_flow_control(ch);
-
- goto exit_unlock;
- }
-
- if (ch->ch_flags & CH_FORCED_STOPI)
- goto exit_unlock;
-
- flip_len = TTY_FLIPBUF_SIZE;
-
- len = min(data_len, flip_len);
- len = min(len, (N_TTY_BUF_SIZE - 1));
-
- ld = tty_ldisc_ref(tp);
- if (!ld) {
- len = 0;
- } else {
- if (!ld->ops->receive_buf) {
- ch->ch_r_head = ch->ch_r_tail;
- len = 0;
- }
- }
-
- if (len <= 0)
- goto exit_unlock;
-
- /*
- * The tty layer in the kernel has changed in 2.6.16+.
- *
- * The flip buffers in the tty structure are no longer exposed,
- * and probably will be going away eventually.
- *
- * If we are completely raw, we don't need to go through a lot
- * of the tty layers that exist.
- * In this case, we take the shortest and fastest route we
- * can to relay the data to the user.
- *
- * On the other hand, if we are not raw, we need to go through
- * the new 2.6.16+ tty layer, which has its API more well defined.
- */
- len = tty_buffer_request_room(tp->port, len);
- n = len;
-
- /*
- * n now contains the most amount of data we can copy,
- * bounded either by how much the Linux tty layer can handle,
- * or the amount of data the card actually has pending...
- */
- while (n) {
- unsigned char *ch_pos = ch->ch_equeue + tail;
-
- s = ((head >= tail) ? head : RQUEUESIZE) - tail;
- s = min(s, n);
-
- if (s <= 0)
- break;
-
- /*
- * If conditions are such that ld needs to see all
- * UART errors, we will have to walk each character
- * and error byte and send them to the buffer one at
- * a time.
- */
- if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) {
- for (i = 0; i < s; i++) {
- unsigned char ch = *(ch_pos + i);
- char flag = TTY_NORMAL;
-
- if (ch & UART_LSR_BI)
- flag = TTY_BREAK;
- else if (ch & UART_LSR_PE)
- flag = TTY_PARITY;
- else if (ch & UART_LSR_FE)
- flag = TTY_FRAME;
-
- tty_insert_flip_char(tp->port, ch, flag);
- }
- } else {
- tty_insert_flip_string(tp->port, ch_pos, s);
- }
-
- tail += s;
- n -= s;
- /* Flip queue if needed */
- tail &= rmask;
- }
-
- ch->ch_r_tail = tail & rmask;
- ch->ch_e_tail = tail & rmask;
- dgnc_check_queue_flow_control(ch);
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-
- /* Tell the tty layer its okay to "eat" the data now */
- tty_flip_buffer_push(tp->port);
-
- if (ld)
- tty_ldisc_deref(ld);
- return;
-
-exit_unlock:
- spin_unlock_irqrestore(&ch->ch_lock, flags);
- if (ld)
- tty_ldisc_deref(ld);
-}
-
-/**
- * dgnc_carrier()
- *
- * Determines when CARRIER changes state and takes appropriate
- * action.
- */
-void dgnc_carrier(struct channel_t *ch)
-{
- int virt_carrier = 0;
- int phys_carrier = 0;
-
- if (!ch)
- return;
-
- if (ch->ch_mistat & UART_MSR_DCD)
- phys_carrier = 1;
-
- if (ch->ch_digi.digi_flags & DIGI_FORCEDCD)
- virt_carrier = 1;
-
- if (ch->ch_c_cflag & CLOCAL)
- virt_carrier = 1;
-
- /* Test for a VIRTUAL carrier transition to HIGH. */
-
- if (((ch->ch_flags & CH_FCAR) == 0) && (virt_carrier == 1)) {
- /*
- * When carrier rises, wake any threads waiting
- * for carrier in the open routine.
- */
- if (waitqueue_active(&ch->ch_flags_wait))
- wake_up_interruptible(&ch->ch_flags_wait);
- }
-
- /* Test for a PHYSICAL carrier transition to HIGH. */
-
- if (((ch->ch_flags & CH_CD) == 0) && (phys_carrier == 1)) {
- /*
- * When carrier rises, wake any threads waiting
- * for carrier in the open routine.
- */
- if (waitqueue_active(&ch->ch_flags_wait))
- wake_up_interruptible(&ch->ch_flags_wait);
- }
-
- /*
- * Test for a PHYSICAL transition to low, so long as we aren't
- * currently ignoring physical transitions (which is what "virtual
- * carrier" indicates).
- *
- * The transition of the virtual carrier to low really doesn't
- * matter... it really only means "ignore carrier state", not
- * "make pretend that carrier is there".
- */
- if ((virt_carrier == 0) && ((ch->ch_flags & CH_CD) != 0) &&
- (phys_carrier == 0)) {
- /*
- * When carrier drops:
- *
- * Drop carrier on all open units.
- *
- * Flush queues, waking up any task waiting in the
- * line discipline.
- *
- * Send a hangup to the control terminal.
- *
- * Enable all select calls.
- */
- if (waitqueue_active(&ch->ch_flags_wait))
- wake_up_interruptible(&ch->ch_flags_wait);
-
- if (ch->ch_tun.un_open_count > 0)
- tty_hangup(ch->ch_tun.un_tty);
-
- if (ch->ch_pun.un_open_count > 0)
- tty_hangup(ch->ch_pun.un_tty);
- }
-
- /* Make sure that our cached values reflect the current reality. */
-
- if (virt_carrier == 1)
- ch->ch_flags |= CH_FCAR;
- else
- ch->ch_flags &= ~CH_FCAR;
-
- if (phys_carrier == 1)
- ch->ch_flags |= CH_CD;
- else
- ch->ch_flags &= ~CH_CD;
-}
-
-/* Assign the custom baud rate to the channel structure */
-static void dgnc_set_custom_speed(struct channel_t *ch, uint newrate)
-{
- int testdiv;
- int testrate_high;
- int testrate_low;
- int deltahigh;
- int deltalow;
-
- if (newrate <= 0) {
- ch->ch_custom_speed = 0;
- return;
- }
-
- /*
- * Since the divisor is stored in a 16-bit integer, we make sure
- * we don't allow any rates smaller than a 16-bit integer would allow.
- * And of course, rates above the dividend won't fly.
- */
- if (newrate && newrate < ((ch->ch_bd->bd_dividend / 0xFFFF) + 1))
- newrate = (ch->ch_bd->bd_dividend / 0xFFFF) + 1;
-
- if (newrate && newrate > ch->ch_bd->bd_dividend)
- newrate = ch->ch_bd->bd_dividend;
-
- if (newrate > 0) {
- testdiv = ch->ch_bd->bd_dividend / newrate;
-
- /*
- * If we try to figure out what rate the board would use
- * with the test divisor, it will be either equal or higher
- * than the requested baud rate. If we then determine the
- * rate with a divisor one higher, we will get the next lower
- * supported rate below the requested.
- */
- testrate_high = ch->ch_bd->bd_dividend / testdiv;
- testrate_low = ch->ch_bd->bd_dividend / (testdiv + 1);
-
- /*
- * If the rate for the requested divisor is correct, just
- * use it and be done.
- */
- if (testrate_high != newrate) {
- /*
- * Otherwise, pick the rate that is closer
- * (i.e. whichever rate has a smaller delta).
- */
- deltahigh = testrate_high - newrate;
- deltalow = newrate - testrate_low;
-
- if (deltahigh < deltalow)
- newrate = testrate_high;
- else
- newrate = testrate_low;
- }
- }
-
- ch->ch_custom_speed = newrate;
-}
-
-void dgnc_check_queue_flow_control(struct channel_t *ch)
-{
- int qleft;
-
- qleft = ch->ch_r_tail - ch->ch_r_head - 1;
- if (qleft < 0)
- qleft += RQUEUEMASK + 1;
-
- /*
- * Check to see if we should enforce flow control on our queue because
- * the ld (or user) isn't reading data out of our queue fast enuf.
- *
- * NOTE: This is done based on what the current flow control of the
- * port is set for.
- *
- * 1) HWFLOW (RTS) - Turn off the UART's Receive interrupt.
- * This will cause the UART's FIFO to back up, and force
- * the RTS signal to be dropped.
- * 2) SWFLOW (IXOFF) - Keep trying to send a stop character to
- * the other side, in hopes it will stop sending data to us.
- * 3) NONE - Nothing we can do. We will simply drop any extra data
- * that gets sent into us when the queue fills up.
- */
- if (qleft < 256) {
- /* HWFLOW */
- if (ch->ch_digi.digi_flags & CTSPACE ||
- ch->ch_c_cflag & CRTSCTS) {
- if (!(ch->ch_flags & CH_RECEIVER_OFF)) {
- ch->ch_bd->bd_ops->disable_receiver(ch);
- ch->ch_flags |= (CH_RECEIVER_OFF);
- }
- }
- /* SWFLOW */
- else if (ch->ch_c_iflag & IXOFF) {
- if (ch->ch_stops_sent <= MAX_STOPS_SENT) {
- ch->ch_bd->bd_ops->send_stop_character(ch);
- ch->ch_stops_sent++;
- }
- }
- }
-
- /*
- * Check to see if we should unenforce flow control because
- * ld (or user) finally read enuf data out of our queue.
- *
- * NOTE: This is done based on what the current flow control of the
- * port is set for.
- *
- * 1) HWFLOW (RTS) - Turn back on the UART's Receive interrupt.
- * This will cause the UART's FIFO to raise RTS back up,
- * which will allow the other side to start sending data again.
- * 2) SWFLOW (IXOFF) - Send a start character to
- * the other side, so it will start sending data to us again.
- * 3) NONE - Do nothing. Since we didn't do anything to turn off the
- * other side, we don't need to do anything now.
- */
- if (qleft > (RQUEUESIZE / 2)) {
- /* HWFLOW */
- if (ch->ch_digi.digi_flags & RTSPACE ||
- ch->ch_c_cflag & CRTSCTS) {
- if (ch->ch_flags & CH_RECEIVER_OFF) {
- ch->ch_bd->bd_ops->enable_receiver(ch);
- ch->ch_flags &= ~(CH_RECEIVER_OFF);
- }
- }
- /* SWFLOW */
- else if (ch->ch_c_iflag & IXOFF && ch->ch_stops_sent) {
- ch->ch_stops_sent = 0;
- ch->ch_bd->bd_ops->send_start_character(ch);
- }
- }
-}
-
-static void dgnc_set_signal_low(struct channel_t *ch, const unsigned char sig)
-{
- ch->ch_mostat &= ~(sig);
- ch->ch_bd->bd_ops->assert_modem_signals(ch);
-}
-
-void dgnc_wakeup_writes(struct channel_t *ch)
-{
- int qlen = 0;
- unsigned long flags;
-
- if (!ch)
- return;
-
- spin_lock_irqsave(&ch->ch_lock, flags);
-
- /* If channel now has space, wake up anyone waiting on the condition. */
-
- qlen = ch->ch_w_head - ch->ch_w_tail;
- if (qlen < 0)
- qlen += WQUEUESIZE;
-
- if (qlen >= (WQUEUESIZE - 256)) {
- spin_unlock_irqrestore(&ch->ch_lock, flags);
- return;
- }
-
- if (ch->ch_tun.un_flags & UN_ISOPEN) {
- tty_wakeup(ch->ch_tun.un_tty);
-
- /*
- * If unit is set to wait until empty, check to make sure
- * the queue AND FIFO are both empty.
- */
- if (ch->ch_tun.un_flags & UN_EMPTY) {
- if ((qlen == 0) &&
- (ch->ch_bd->bd_ops->get_uart_bytes_left(ch) == 0)) {
- ch->ch_tun.un_flags &= ~(UN_EMPTY);
-
- /*
- * If RTS Toggle mode is on, whenever
- * the queue and UART is empty, keep RTS low.
- */
- if (ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE)
- dgnc_set_signal_low(ch, UART_MCR_RTS);
-
- /*
- * If DTR Toggle mode is on, whenever
- * the queue and UART is empty, keep DTR low.
- */
- if (ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE)
- dgnc_set_signal_low(ch, UART_MCR_DTR);
- }
- }
-
- wake_up_interruptible(&ch->ch_tun.un_flags_wait);
- }
-
- if (ch->ch_pun.un_flags & UN_ISOPEN) {
- tty_wakeup(ch->ch_pun.un_tty);
-
- /*
- * If unit is set to wait until empty, check to make sure
- * the queue AND FIFO are both empty.
- */
- if (ch->ch_pun.un_flags & UN_EMPTY) {
- if ((qlen == 0) &&
- (ch->ch_bd->bd_ops->get_uart_bytes_left(ch) == 0))
- ch->ch_pun.un_flags &= ~(UN_EMPTY);
- }
-
- wake_up_interruptible(&ch->ch_pun.un_flags_wait);
- }
-
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-}
-
-static struct dgnc_board *find_board_by_major(unsigned int major)
-{
- int i;
-
- for (i = 0; i < MAXBOARDS; i++) {
- struct dgnc_board *brd = dgnc_board[i];
-
- if (!brd)
- return NULL;
-
- if (major == brd->serial_driver->major ||
- major == brd->print_driver->major)
- return brd;
- }
-
- return NULL;
-}
-
-/* TTY Entry points and helper functions */
-
-static int dgnc_tty_open(struct tty_struct *tty, struct file *file)
-{
- struct dgnc_board *brd;
- struct channel_t *ch;
- struct un_t *un;
- uint major = 0;
- uint minor = 0;
- int rc = 0;
- unsigned long flags;
-
- rc = 0;
-
- major = MAJOR(tty_devnum(tty));
- minor = MINOR(tty_devnum(tty));
-
- if (major > 255)
- return -ENXIO;
-
- brd = find_board_by_major(major);
- if (!brd)
- return -ENXIO;
-
- rc = wait_event_interruptible(brd->state_wait,
- (brd->state & BOARD_READY));
- if (rc)
- return rc;
-
- spin_lock_irqsave(&brd->bd_lock, flags);
-
- if (PORT_NUM(minor) >= brd->nasync) {
- rc = -ENXIO;
- goto err_brd_unlock;
- }
-
- ch = brd->channels[PORT_NUM(minor)];
- if (!ch) {
- rc = -ENXIO;
- goto err_brd_unlock;
- }
-
- spin_unlock_irqrestore(&brd->bd_lock, flags);
-
- spin_lock_irqsave(&ch->ch_lock, flags);
-
- /* Figure out our type */
- if (!IS_PRINT(minor)) {
- un = &brd->channels[PORT_NUM(minor)]->ch_tun;
- un->un_type = DGNC_SERIAL;
- } else if (IS_PRINT(minor)) {
- un = &brd->channels[PORT_NUM(minor)]->ch_pun;
- un->un_type = DGNC_PRINT;
- } else {
- rc = -ENXIO;
- goto err_ch_unlock;
- }
-
- /*
- * If the port is still in a previous open, and in a state
- * where we simply cannot safely keep going, wait until the
- * state clears.
- */
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-
- rc = wait_event_interruptible(ch->ch_flags_wait,
- ((ch->ch_flags & CH_OPENING) == 0));
- /* If ret is non-zero, user ctrl-c'ed us */
- if (rc)
- return -EINTR;
-
- /*
- * If either unit is in the middle of the fragile part of close,
- * we just cannot touch the channel safely.
- * Go to sleep, knowing that when the channel can be
- * touched safely, the close routine will signal the
- * ch_flags_wait to wake us back up.
- */
- rc = wait_event_interruptible(ch->ch_flags_wait,
- !((ch->ch_tun.un_flags |
- ch->ch_pun.un_flags) & UN_CLOSING));
- /* If ret is non-zero, user ctrl-c'ed us */
- if (rc)
- return -EINTR;
-
- spin_lock_irqsave(&ch->ch_lock, flags);
-
- tty->driver_data = un;
-
- /* Initialize tty's */
-
- if (!(un->un_flags & UN_ISOPEN)) {
- un->un_tty = tty;
-
- /* Maybe do something here to the TTY struct as well? */
- }
-
- /*
- * Allocate channel buffers for read/write/error.
- * Set flag, so we don't get trounced on.
- */
- ch->ch_flags |= (CH_OPENING);
-
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-
- if (!ch->ch_rqueue)
- ch->ch_rqueue = kzalloc(RQUEUESIZE, GFP_KERNEL);
- if (!ch->ch_equeue)
- ch->ch_equeue = kzalloc(EQUEUESIZE, GFP_KERNEL);
- if (!ch->ch_wqueue)
- ch->ch_wqueue = kzalloc(WQUEUESIZE, GFP_KERNEL);
-
- if (!ch->ch_rqueue || !ch->ch_equeue || !ch->ch_wqueue) {
- kfree(ch->ch_rqueue);
- kfree(ch->ch_equeue);
- kfree(ch->ch_wqueue);
- return -ENOMEM;
- }
-
- spin_lock_irqsave(&ch->ch_lock, flags);
-
- ch->ch_flags &= ~(CH_OPENING);
- wake_up_interruptible(&ch->ch_flags_wait);
-
- /* Initialize if neither terminal or printer is open. */
-
- if (!((ch->ch_tun.un_flags | ch->ch_pun.un_flags) & UN_ISOPEN)) {
- /* Flush input queues. */
- ch->ch_r_head = 0;
- ch->ch_r_tail = 0;
- ch->ch_e_head = 0;
- ch->ch_e_tail = 0;
- ch->ch_w_head = 0;
- ch->ch_w_tail = 0;
-
- brd->bd_ops->flush_uart_write(ch);
- brd->bd_ops->flush_uart_read(ch);
-
- ch->ch_flags = 0;
- ch->ch_cached_lsr = 0;
- ch->ch_stop_sending_break = 0;
- ch->ch_stops_sent = 0;
-
- ch->ch_c_cflag = tty->termios.c_cflag;
- ch->ch_c_iflag = tty->termios.c_iflag;
- ch->ch_c_oflag = tty->termios.c_oflag;
- ch->ch_c_lflag = tty->termios.c_lflag;
- ch->ch_startc = tty->termios.c_cc[VSTART];
- ch->ch_stopc = tty->termios.c_cc[VSTOP];
-
- /*
- * Bring up RTS and DTR...
- * Also handle RTS or DTR toggle if set.
- */
- if (!(ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE))
- ch->ch_mostat |= (UART_MCR_RTS);
- if (!(ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE))
- ch->ch_mostat |= (UART_MCR_DTR);
-
- /* Tell UART to init itself */
- brd->bd_ops->uart_init(ch);
- }
-
- brd->bd_ops->param(tty);
-
- dgnc_carrier(ch);
-
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-
- rc = dgnc_block_til_ready(tty, file, ch);
-
- spin_lock_irqsave(&ch->ch_lock, flags);
- ch->ch_open_count++;
- un->un_open_count++;
- un->un_flags |= (UN_ISOPEN);
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-
- return rc;
-
-err_brd_unlock:
- spin_unlock_irqrestore(&brd->bd_lock, flags);
-
- return rc;
-err_ch_unlock:
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-
- return rc;
-}
-
-/* Wait for DCD, if needed. */
-static int dgnc_block_til_ready(struct tty_struct *tty,
- struct file *file,
- struct channel_t *ch)
-{
- int rc = 0;
- struct un_t *un = tty->driver_data;
- unsigned long flags;
- uint old_flags = 0;
- int sleep_on_un_flags = 0;
-
- if (!file)
- return -ENXIO;
-
- spin_lock_irqsave(&ch->ch_lock, flags);
-
- ch->ch_wopen++;
-
- while (1) {
- sleep_on_un_flags = 0;
-
- if (ch->ch_bd->state == BOARD_FAILED) {
- rc = -ENXIO;
- break;
- }
-
- if (tty_hung_up_p(file)) {
- rc = -EAGAIN;
- break;
- }
-
- /*
- * If either unit is in the middle of the fragile part of close,
- * we just cannot touch the channel safely.
- * Go back to sleep, knowing that when the channel can be
- * touched safely, the close routine will signal the
- * ch_wait_flags to wake us back up.
- */
- if (!((ch->ch_tun.un_flags |
- ch->ch_pun.un_flags) &
- UN_CLOSING)) {
- /*
- * Our conditions to leave cleanly and happily:
- * 1) NONBLOCKING on the tty is set.
- * 2) CLOCAL is set.
- * 3) DCD (fake or real) is active.
- */
-
- if (file->f_flags & O_NONBLOCK)
- break;
-
- if (tty_io_error(tty)) {
- rc = -EIO;
- break;
- }
-
- if (ch->ch_flags & CH_CD)
- break;
-
- if (ch->ch_flags & CH_FCAR)
- break;
- } else {
- sleep_on_un_flags = 1;
- }
-
- /*
- * If there is a signal pending, the user probably
- * interrupted (ctrl-c) us.
- */
- if (signal_pending(current)) {
- rc = -ERESTARTSYS;
- break;
- }
-
- if (sleep_on_un_flags)
- old_flags = ch->ch_tun.un_flags | ch->ch_pun.un_flags;
- else
- old_flags = ch->ch_flags;
-
- /*
- * Let go of channel lock before calling schedule.
- * Our poller will get any FEP events and wake us up when DCD
- * eventually goes active.
- */
-
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-
- /*
- * Wait for something in the flags to change
- * from the current value.
- */
- if (sleep_on_un_flags)
- rc = wait_event_interruptible
- (un->un_flags_wait,
- (old_flags != (ch->ch_tun.un_flags |
- ch->ch_pun.un_flags)));
- else
- rc = wait_event_interruptible(
- ch->ch_flags_wait,
- (old_flags != ch->ch_flags));
-
- /*
- * We got woken up for some reason.
- * Before looping around, grab our channel lock.
- */
- spin_lock_irqsave(&ch->ch_lock, flags);
- }
-
- ch->ch_wopen--;
-
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-
- return rc;
-}
-
-/* Hangup the port. Like a close, but don't wait for output to drain. */
-static void dgnc_tty_hangup(struct tty_struct *tty)
-{
- if (!tty)
- return;
-
- /* flush the transmit queues */
- dgnc_tty_flush_buffer(tty);
-}
-
-static void dgnc_tty_close(struct tty_struct *tty, struct file *file)
-{
- struct dgnc_board *bd;
- struct channel_t *ch;
- struct un_t *un;
- unsigned long flags;
-
- if (!tty)
- return;
-
- un = tty->driver_data;
- if (!un)
- return;
-
- ch = un->un_ch;
- if (!ch)
- return;
-
- bd = ch->ch_bd;
- if (!bd)
- return;
-
- spin_lock_irqsave(&ch->ch_lock, flags);
-
- /*
- * Determine if this is the last close or not - and if we agree about
- * which type of close it is with the Line Discipline
- */
- if ((tty->count == 1) && (un->un_open_count != 1)) {
- /*
- * Uh, oh. tty->count is 1, which means that the tty
- * structure will be freed. un_open_count should always
- * be one in these conditions. If it's greater than
- * one, we've got real problems, since it means the
- * serial port won't be shutdown.
- */
- dev_dbg(tty->dev,
- "tty->count is 1, un open count is %d\n",
- un->un_open_count);
- un->un_open_count = 1;
- }
-
- if (un->un_open_count)
- un->un_open_count--;
- else
- dev_dbg(tty->dev,
- "bad serial port open count of %d\n",
- un->un_open_count);
-
- ch->ch_open_count--;
-
- if (ch->ch_open_count && un->un_open_count) {
- spin_unlock_irqrestore(&ch->ch_lock, flags);
- return;
- }
-
- /* OK, its the last close on the unit */
- un->un_flags |= UN_CLOSING;
-
- tty->closing = 1;
-
- /*
- * Only officially close channel if count is 0 and
- * DIGI_PRINTER bit is not set.
- */
- if ((ch->ch_open_count == 0) &&
- !(ch->ch_digi.digi_flags & DIGI_PRINTER)) {
- ch->ch_flags &= ~(CH_STOPI | CH_FORCED_STOPI);
-
- /* turn off print device when closing print device. */
-
- if ((un->un_type == DGNC_PRINT) && (ch->ch_flags & CH_PRON)) {
- dgnc_wmove(ch, ch->ch_digi.digi_offstr,
- (int)ch->ch_digi.digi_offlen);
- ch->ch_flags &= ~CH_PRON;
- }
-
- spin_unlock_irqrestore(&ch->ch_lock, flags);
- /* wait for output to drain */
- /* This will also return if we take an interrupt */
-
- bd->bd_ops->drain(tty, 0);
-
- dgnc_tty_flush_buffer(tty);
- tty_ldisc_flush(tty);
-
- spin_lock_irqsave(&ch->ch_lock, flags);
-
- tty->closing = 0;
-
- /* If we have HUPCL set, lower DTR and RTS */
-
- if (ch->ch_c_cflag & HUPCL) {
- /* Drop RTS/DTR */
- ch->ch_mostat &= ~(UART_MCR_DTR | UART_MCR_RTS);
- bd->bd_ops->assert_modem_signals(ch);
-
- /*
- * Go to sleep to ensure RTS/DTR
- * have been dropped for modems to see it.
- */
- if (ch->ch_close_delay) {
- spin_unlock_irqrestore(&ch->ch_lock,
- flags);
- msleep_interruptible(ch->ch_close_delay);
- spin_lock_irqsave(&ch->ch_lock, flags);
- }
- }
-
- ch->ch_old_baud = 0;
-
- /* Turn off UART interrupts for this port */
- ch->ch_bd->bd_ops->uart_off(ch);
- } else {
- /* turn off print device when closing print device. */
-
- if ((un->un_type == DGNC_PRINT) && (ch->ch_flags & CH_PRON)) {
- dgnc_wmove(ch, ch->ch_digi.digi_offstr,
- (int)ch->ch_digi.digi_offlen);
- ch->ch_flags &= ~CH_PRON;
- }
- }
-
- un->un_tty = NULL;
- un->un_flags &= ~(UN_ISOPEN | UN_CLOSING);
-
- wake_up_interruptible(&ch->ch_flags_wait);
- wake_up_interruptible(&un->un_flags_wait);
-
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-}
-
-/*
- * Return number of characters that have not been transmitted yet.
- *
- * This routine is used by the line discipline to determine if there
- * is data waiting to be transmitted/drained/flushed or not.
- */
-static int dgnc_tty_chars_in_buffer(struct tty_struct *tty)
-{
- struct channel_t *ch = NULL;
- struct un_t *un = NULL;
- ushort thead;
- ushort ttail;
- uint tmask;
- uint chars;
- unsigned long flags;
-
- if (!tty)
- return 0;
-
- un = tty->driver_data;
- if (!un)
- return 0;
-
- ch = un->un_ch;
- if (!ch)
- return 0;
-
- spin_lock_irqsave(&ch->ch_lock, flags);
-
- tmask = WQUEUEMASK;
- thead = ch->ch_w_head & tmask;
- ttail = ch->ch_w_tail & tmask;
-
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-
- if (ttail == thead)
- chars = 0;
- else if (thead > ttail)
- chars = thead - ttail;
- else
- chars = thead - ttail + WQUEUESIZE;
-
- return chars;
-}
-
-/*
- * Reduces bytes_available to the max number of characters
- * that can be sent currently given the maxcps value, and
- * returns the new bytes_available. This only affects printer
- * output.
- */
-static int dgnc_maxcps_room(struct channel_t *ch, int bytes_available)
-{
- int rc = bytes_available;
-
- if (ch->ch_digi.digi_maxcps > 0 && ch->ch_digi.digi_bufsize > 0) {
- int cps_limit = 0;
- unsigned long current_time = jiffies;
- unsigned long buffer_time = current_time +
- (HZ * ch->ch_digi.digi_bufsize) /
- ch->ch_digi.digi_maxcps;
-
- if (ch->ch_cpstime < current_time) {
- /* buffer is empty */
- ch->ch_cpstime = current_time; /* reset ch_cpstime */
- cps_limit = ch->ch_digi.digi_bufsize;
- } else if (ch->ch_cpstime < buffer_time) {
- /* still room in the buffer */
- cps_limit = ((buffer_time - ch->ch_cpstime) *
- ch->ch_digi.digi_maxcps) / HZ;
- } else {
- /* no room in the buffer */
- cps_limit = 0;
- }
-
- rc = min(cps_limit, bytes_available);
- }
-
- return rc;
-}
-
-/* Return room available in Tx buffer */
-static int dgnc_tty_write_room(struct tty_struct *tty)
-{
- struct channel_t *ch = NULL;
- struct un_t *un = NULL;
- ushort head;
- ushort tail;
- ushort tmask;
- int room = 0;
- unsigned long flags;
-
- if (!tty)
- return 0;
-
- un = tty->driver_data;
- if (!un)
- return 0;
-
- ch = un->un_ch;
- if (!ch)
- return 0;
-
- spin_lock_irqsave(&ch->ch_lock, flags);
-
- tmask = WQUEUEMASK;
- head = (ch->ch_w_head) & tmask;
- tail = (ch->ch_w_tail) & tmask;
-
- room = tail - head - 1;
- if (room < 0)
- room += WQUEUESIZE;
-
- /* Limit printer to maxcps */
- if (un->un_type != DGNC_PRINT)
- room = dgnc_maxcps_room(ch, room);
-
- /*
- * If we are printer device, leave room for
- * possibly both the on and off strings.
- */
- if (un->un_type == DGNC_PRINT) {
- if (!(ch->ch_flags & CH_PRON))
- room -= ch->ch_digi.digi_onlen;
- room -= ch->ch_digi.digi_offlen;
- } else {
- if (ch->ch_flags & CH_PRON)
- room -= ch->ch_digi.digi_offlen;
- }
-
- if (room < 0)
- room = 0;
-
- spin_unlock_irqrestore(&ch->ch_lock, flags);
- return room;
-}
-
-/*
- * Put a character into ch->ch_buf
- * Used by the line discipline for OPOST processing
- */
-static int dgnc_tty_put_char(struct tty_struct *tty, unsigned char c)
-{
- dgnc_tty_write(tty, &c, 1);
- return 1;
-}
-
-/*
- * Take data from the user or kernel and send it out to the FEP.
- * In here exists all the Transparent Print magic as well.
- */
-static int dgnc_tty_write(struct tty_struct *tty,
- const unsigned char *buf, int count)
-{
- struct channel_t *ch = NULL;
- struct un_t *un = NULL;
- int bufcount = 0, n = 0;
- unsigned long flags;
- ushort head;
- ushort tail;
- ushort tmask;
- uint remain;
-
- if (!tty)
- return 0;
-
- un = tty->driver_data;
- if (!un)
- return 0;
-
- ch = un->un_ch;
- if (!ch)
- return 0;
-
- if (!count)
- return 0;
-
- /*
- * Store original amount of characters passed in.
- * This helps to figure out if we should ask the FEP
- * to send us an event when it has more space available.
- */
-
- spin_lock_irqsave(&ch->ch_lock, flags);
-
- tmask = WQUEUEMASK;
- head = (ch->ch_w_head) & tmask;
- tail = (ch->ch_w_tail) & tmask;
-
- bufcount = tail - head - 1;
- if (bufcount < 0)
- bufcount += WQUEUESIZE;
-
- /*
- * Limit printer output to maxcps overall, with bursts allowed
- * up to bufsize characters.
- */
- if (un->un_type != DGNC_PRINT)
- bufcount = dgnc_maxcps_room(ch, bufcount);
-
- count = min(count, bufcount);
- if (count <= 0)
- goto exit_retry;
-
- /*
- * Output the printer ON string, if we are in terminal mode, but
- * need to be in printer mode.
- */
- if ((un->un_type == DGNC_PRINT) && !(ch->ch_flags & CH_PRON)) {
- dgnc_wmove(ch, ch->ch_digi.digi_onstr,
- (int)ch->ch_digi.digi_onlen);
- head = (ch->ch_w_head) & tmask;
- ch->ch_flags |= CH_PRON;
- }
-
- /*
- * On the other hand, output the printer OFF string, if we are
- * currently in printer mode, but need to output to the terminal.
- */
- if ((un->un_type != DGNC_PRINT) && (ch->ch_flags & CH_PRON)) {
- dgnc_wmove(ch, ch->ch_digi.digi_offstr,
- (int)ch->ch_digi.digi_offlen);
- head = (ch->ch_w_head) & tmask;
- ch->ch_flags &= ~CH_PRON;
- }
-
- n = count;
-
- /*
- * If the write wraps over the top of the circular buffer,
- * move the portion up to the wrap point, and reset the
- * pointers to the bottom.
- */
- remain = WQUEUESIZE - head;
-
- if (n >= remain) {
- n -= remain;
- memcpy(ch->ch_wqueue + head, buf, remain);
- head = 0;
- buf += remain;
- }
-
- if (n > 0) {
- /* Move rest of data. */
- remain = n;
- memcpy(ch->ch_wqueue + head, buf, remain);
- head += remain;
- }
-
- if (count) {
- head &= tmask;
- ch->ch_w_head = head;
- }
-
- /* Update printer buffer empty time. */
- if ((un->un_type == DGNC_PRINT) && (ch->ch_digi.digi_maxcps > 0) &&
- (ch->ch_digi.digi_bufsize > 0)) {
- ch->ch_cpstime += (HZ * count) / ch->ch_digi.digi_maxcps;
- }
-
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-
- if (count)
- ch->ch_bd->bd_ops->copy_data_from_queue_to_uart(ch);
-
- return count;
-
-exit_retry:
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-
- return 0;
-}
-
-/* Return modem signals to ld. */
-static int dgnc_tty_tiocmget(struct tty_struct *tty)
-{
- struct channel_t *ch;
- struct un_t *un;
- int rc;
- unsigned char mstat = 0;
- unsigned long flags;
-
- if (!tty)
- return -EIO;
-
- un = tty->driver_data;
- if (!un)
- return -EIO;
-
- ch = un->un_ch;
- if (!ch)
- return -EIO;
-
- spin_lock_irqsave(&ch->ch_lock, flags);
-
- mstat = ch->ch_mostat | ch->ch_mistat;
-
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-
- rc = 0;
-
- if (mstat & UART_MCR_DTR)
- rc |= TIOCM_DTR;
- if (mstat & UART_MCR_RTS)
- rc |= TIOCM_RTS;
- if (mstat & UART_MSR_CTS)
- rc |= TIOCM_CTS;
- if (mstat & UART_MSR_DSR)
- rc |= TIOCM_DSR;
- if (mstat & UART_MSR_RI)
- rc |= TIOCM_RI;
- if (mstat & UART_MSR_DCD)
- rc |= TIOCM_CD;
-
- return rc;
-}
-
-/* Set modem signals, called by ld. */
-static int dgnc_tty_tiocmset(struct tty_struct *tty,
- unsigned int set, unsigned int clear)
-{
- struct dgnc_board *bd;
- struct channel_t *ch;
- struct un_t *un;
- unsigned long flags;
-
- if (!tty)
- return -EIO;
-
- un = tty->driver_data;
- if (!un)
- return -EIO;
-
- ch = un->un_ch;
- if (!ch)
- return -EIO;
-
- bd = ch->ch_bd;
- if (!bd)
- return -EIO;
-
- spin_lock_irqsave(&ch->ch_lock, flags);
-
- if (set & TIOCM_RTS)
- ch->ch_mostat |= UART_MCR_RTS;
-
- if (set & TIOCM_DTR)
- ch->ch_mostat |= UART_MCR_DTR;
-
- if (clear & TIOCM_RTS)
- ch->ch_mostat &= ~(UART_MCR_RTS);
-
- if (clear & TIOCM_DTR)
- ch->ch_mostat &= ~(UART_MCR_DTR);
-
- bd->bd_ops->assert_modem_signals(ch);
-
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-
- return 0;
-}
-
-/* Send a Break, called by ld. */
-static int dgnc_tty_send_break(struct tty_struct *tty, int msec)
-{
- struct dgnc_board *bd;
- struct channel_t *ch;
- struct un_t *un;
- unsigned long flags;
-
- if (!tty)
- return -EIO;
-
- un = tty->driver_data;
- if (!un)
- return -EIO;
-
- ch = un->un_ch;
- if (!ch)
- return -EIO;
-
- bd = ch->ch_bd;
- if (!bd)
- return -EIO;
-
- if (msec < 0)
- msec = 0xFFFF;
-
- spin_lock_irqsave(&ch->ch_lock, flags);
-
- bd->bd_ops->send_break(ch, msec);
-
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-
- return 0;
-}
-
-/* wait until data has been transmitted, called by ld. */
-static void dgnc_tty_wait_until_sent(struct tty_struct *tty, int timeout)
-{
- struct dgnc_board *bd;
- struct channel_t *ch;
- struct un_t *un;
-
- if (!tty)
- return;
-
- un = tty->driver_data;
- if (!un)
- return;
-
- ch = un->un_ch;
- if (!ch)
- return;
-
- bd = ch->ch_bd;
- if (!bd)
- return;
-
- bd->bd_ops->drain(tty, 0);
-}
-
-/* send a high priority character, called by ld. */
-static void dgnc_tty_send_xchar(struct tty_struct *tty, char c)
-{
- struct dgnc_board *bd;
- struct channel_t *ch;
- struct un_t *un;
- unsigned long flags;
-
- if (!tty)
- return;
-
- un = tty->driver_data;
- if (!un)
- return;
-
- ch = un->un_ch;
- if (!ch)
- return;
-
- bd = ch->ch_bd;
- if (!bd)
- return;
-
- spin_lock_irqsave(&ch->ch_lock, flags);
- bd->bd_ops->send_immediate_char(ch, c);
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-}
-
-/* Return modem signals to ld. */
-static inline int dgnc_get_mstat(struct channel_t *ch)
-{
- unsigned char mstat;
- unsigned long flags;
- int rc;
-
- if (!ch)
- return -ENXIO;
-
- spin_lock_irqsave(&ch->ch_lock, flags);
-
- mstat = ch->ch_mostat | ch->ch_mistat;
-
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-
- rc = 0;
-
- if (mstat & UART_MCR_DTR)
- rc |= TIOCM_DTR;
- if (mstat & UART_MCR_RTS)
- rc |= TIOCM_RTS;
- if (mstat & UART_MSR_CTS)
- rc |= TIOCM_CTS;
- if (mstat & UART_MSR_DSR)
- rc |= TIOCM_DSR;
- if (mstat & UART_MSR_RI)
- rc |= TIOCM_RI;
- if (mstat & UART_MSR_DCD)
- rc |= TIOCM_CD;
-
- return rc;
-}
-
-/* Return modem signals to ld. */
-static int dgnc_get_modem_info(struct channel_t *ch,
- unsigned int __user *value)
-{
- return put_user(dgnc_get_mstat(ch), value);
-}
-
-/* Set modem signals, called by ld. */
-static int dgnc_set_modem_info(struct channel_t *ch,
- unsigned int command,
- unsigned int __user *value)
-{
- int rc;
- unsigned int arg = 0;
- unsigned long flags;
-
- rc = get_user(arg, value);
- if (rc)
- return rc;
-
- switch (command) {
- case TIOCMBIS:
- if (arg & TIOCM_RTS)
- ch->ch_mostat |= UART_MCR_RTS;
-
- if (arg & TIOCM_DTR)
- ch->ch_mostat |= UART_MCR_DTR;
-
- break;
-
- case TIOCMBIC:
- if (arg & TIOCM_RTS)
- ch->ch_mostat &= ~(UART_MCR_RTS);
-
- if (arg & TIOCM_DTR)
- ch->ch_mostat &= ~(UART_MCR_DTR);
-
- break;
-
- case TIOCMSET:
-
- if (arg & TIOCM_RTS)
- ch->ch_mostat |= UART_MCR_RTS;
- else
- ch->ch_mostat &= ~(UART_MCR_RTS);
-
- if (arg & TIOCM_DTR)
- ch->ch_mostat |= UART_MCR_DTR;
- else
- ch->ch_mostat &= ~(UART_MCR_DTR);
-
- break;
-
- default:
- return -EINVAL;
- }
-
- spin_lock_irqsave(&ch->ch_lock, flags);
-
- ch->ch_bd->bd_ops->assert_modem_signals(ch);
-
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-
- return 0;
-}
-
-/* Ioctl to get the information for ditty. */
-static int dgnc_tty_digigeta(struct tty_struct *tty,
- struct digi_t __user *retinfo)
-{
- struct channel_t *ch;
- struct un_t *un;
- struct digi_t tmp;
- unsigned long flags;
-
- if (!retinfo)
- return -EFAULT;
-
- if (!tty)
- return -EFAULT;
-
- un = tty->driver_data;
- if (!un)
- return -EFAULT;
-
- ch = un->un_ch;
- if (!ch)
- return -EFAULT;
-
- memset(&tmp, 0, sizeof(tmp));
-
- spin_lock_irqsave(&ch->ch_lock, flags);
- memcpy(&tmp, &ch->ch_digi, sizeof(tmp));
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-
- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return -EFAULT;
-
- return 0;
-}
-
-/* Ioctl to set the information for ditty. */
-static int dgnc_tty_digiseta(struct tty_struct *tty,
- struct digi_t __user *new_info)
-{
- struct dgnc_board *bd;
- struct channel_t *ch;
- struct un_t *un;
- struct digi_t new_digi;
- unsigned long flags;
-
- if (!tty)
- return -EFAULT;
-
- un = tty->driver_data;
- if (!un)
- return -EFAULT;
-
- ch = un->un_ch;
- if (!ch)
- return -EFAULT;
-
- bd = ch->ch_bd;
- if (!bd)
- return -EFAULT;
-
- if (copy_from_user(&new_digi, new_info, sizeof(new_digi)))
- return -EFAULT;
-
- spin_lock_irqsave(&ch->ch_lock, flags);
-
- /* Handle transitions to and from RTS Toggle. */
-
- if (!(ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE) &&
- (new_digi.digi_flags & DIGI_RTS_TOGGLE))
- ch->ch_mostat &= ~(UART_MCR_RTS);
- if ((ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE) &&
- !(new_digi.digi_flags & DIGI_RTS_TOGGLE))
- ch->ch_mostat |= (UART_MCR_RTS);
-
- /* Handle transitions to and from DTR Toggle. */
-
- if (!(ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE) &&
- (new_digi.digi_flags & DIGI_DTR_TOGGLE))
- ch->ch_mostat &= ~(UART_MCR_DTR);
- if ((ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE) &&
- !(new_digi.digi_flags & DIGI_DTR_TOGGLE))
- ch->ch_mostat |= (UART_MCR_DTR);
-
- memcpy(&ch->ch_digi, &new_digi, sizeof(new_digi));
-
- if (ch->ch_digi.digi_maxcps < 1)
- ch->ch_digi.digi_maxcps = 1;
-
- if (ch->ch_digi.digi_maxcps > 10000)
- ch->ch_digi.digi_maxcps = 10000;
-
- if (ch->ch_digi.digi_bufsize < 10)
- ch->ch_digi.digi_bufsize = 10;
-
- if (ch->ch_digi.digi_maxchar < 1)
- ch->ch_digi.digi_maxchar = 1;
-
- if (ch->ch_digi.digi_maxchar > ch->ch_digi.digi_bufsize)
- ch->ch_digi.digi_maxchar = ch->ch_digi.digi_bufsize;
-
- if (ch->ch_digi.digi_onlen > DIGI_PLEN)
- ch->ch_digi.digi_onlen = DIGI_PLEN;
-
- if (ch->ch_digi.digi_offlen > DIGI_PLEN)
- ch->ch_digi.digi_offlen = DIGI_PLEN;
-
- bd->bd_ops->param(tty);
-
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-
- return 0;
-}
-
-static void dgnc_tty_set_termios(struct tty_struct *tty,
- struct ktermios *old_termios)
-{
- struct dgnc_board *bd;
- struct channel_t *ch;
- struct un_t *un;
- unsigned long flags;
-
- if (!tty)
- return;
-
- un = tty->driver_data;
- if (!un)
- return;
-
- ch = un->un_ch;
- if (!ch)
- return;
-
- bd = ch->ch_bd;
- if (!bd)
- return;
-
- spin_lock_irqsave(&ch->ch_lock, flags);
-
- ch->ch_c_cflag = tty->termios.c_cflag;
- ch->ch_c_iflag = tty->termios.c_iflag;
- ch->ch_c_oflag = tty->termios.c_oflag;
- ch->ch_c_lflag = tty->termios.c_lflag;
- ch->ch_startc = tty->termios.c_cc[VSTART];
- ch->ch_stopc = tty->termios.c_cc[VSTOP];
-
- bd->bd_ops->param(tty);
- dgnc_carrier(ch);
-
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-}
-
-static void dgnc_tty_throttle(struct tty_struct *tty)
-{
- struct channel_t *ch;
- struct un_t *un;
- unsigned long flags;
-
- if (!tty)
- return;
-
- un = tty->driver_data;
- if (!un)
- return;
-
- ch = un->un_ch;
- if (!ch)
- return;
-
- spin_lock_irqsave(&ch->ch_lock, flags);
-
- ch->ch_flags |= (CH_FORCED_STOPI);
-
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-}
-
-static void dgnc_tty_unthrottle(struct tty_struct *tty)
-{
- struct channel_t *ch;
- struct un_t *un;
- unsigned long flags;
-
- if (!tty)
- return;
-
- un = tty->driver_data;
- if (!un)
- return;
-
- ch = un->un_ch;
- if (!ch)
- return;
-
- spin_lock_irqsave(&ch->ch_lock, flags);
-
- ch->ch_flags &= ~(CH_FORCED_STOPI);
-
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-}
-
-static void dgnc_tty_start(struct tty_struct *tty)
-{
- struct dgnc_board *bd;
- struct channel_t *ch;
- struct un_t *un;
- unsigned long flags;
-
- if (!tty)
- return;
-
- un = tty->driver_data;
- if (!un)
- return;
-
- ch = un->un_ch;
- if (!ch)
- return;
-
- bd = ch->ch_bd;
- if (!bd)
- return;
-
- spin_lock_irqsave(&ch->ch_lock, flags);
-
- ch->ch_flags &= ~(CH_FORCED_STOP);
-
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-}
-
-static void dgnc_tty_stop(struct tty_struct *tty)
-{
- struct dgnc_board *bd;
- struct channel_t *ch;
- struct un_t *un;
- unsigned long flags;
-
- if (!tty)
- return;
-
- un = tty->driver_data;
- if (!un)
- return;
-
- ch = un->un_ch;
- if (!ch)
- return;
-
- bd = ch->ch_bd;
- if (!bd)
- return;
-
- spin_lock_irqsave(&ch->ch_lock, flags);
-
- ch->ch_flags |= (CH_FORCED_STOP);
-
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-}
-
-/*
- * Flush the cook buffer
- *
- * Note to self, and any other poor souls who venture here:
- *
- * flush in this case DOES NOT mean dispose of the data.
- * instead, it means "stop buffering and send it if you
- * haven't already." Just guess how I figured that out... SRW 2-Jun-98
- *
- * It is also always called in interrupt context - JAR 8-Sept-99
- */
-static void dgnc_tty_flush_chars(struct tty_struct *tty)
-{
- struct dgnc_board *bd;
- struct channel_t *ch;
- struct un_t *un;
- unsigned long flags;
-
- if (!tty)
- return;
-
- un = tty->driver_data;
- if (!un)
- return;
-
- ch = un->un_ch;
- if (!ch)
- return;
-
- bd = ch->ch_bd;
- if (!bd)
- return;
-
- spin_lock_irqsave(&ch->ch_lock, flags);
-
- /* Do something maybe here */
-
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-}
-
-/* Flush Tx buffer (make in == out) */
-static void dgnc_tty_flush_buffer(struct tty_struct *tty)
-{
- struct channel_t *ch;
- struct un_t *un;
- unsigned long flags;
-
- if (!tty)
- return;
-
- un = tty->driver_data;
- if (!un)
- return;
-
- ch = un->un_ch;
- if (!ch)
- return;
-
- spin_lock_irqsave(&ch->ch_lock, flags);
-
- ch->ch_flags &= ~CH_STOP;
-
- /* Flush our write queue */
- ch->ch_w_head = ch->ch_w_tail;
-
- /* Flush UARTs transmit FIFO */
- ch->ch_bd->bd_ops->flush_uart_write(ch);
-
- if (ch->ch_tun.un_flags & (UN_LOW | UN_EMPTY)) {
- ch->ch_tun.un_flags &= ~(UN_LOW | UN_EMPTY);
- wake_up_interruptible(&ch->ch_tun.un_flags_wait);
- }
- if (ch->ch_pun.un_flags & (UN_LOW | UN_EMPTY)) {
- ch->ch_pun.un_flags &= ~(UN_LOW | UN_EMPTY);
- wake_up_interruptible(&ch->ch_pun.un_flags_wait);
- }
-
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-}
-
-/* Wakes up processes waiting in the unit's (teminal/printer) wait queue */
-static void dgnc_wake_up_unit(struct un_t *unit)
-{
- unit->un_flags &= ~(UN_LOW | UN_EMPTY);
- wake_up_interruptible(&unit->un_flags_wait);
-}
-
-/* The IOCTL function and all of its helpers */
-
-/* The usual assortment of ioctl's */
-static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
- unsigned long arg)
-{
- struct dgnc_board *bd;
- struct board_ops *ch_bd_ops;
- struct channel_t *ch;
- struct un_t *un;
- int rc;
- unsigned long flags;
- void __user *uarg = (void __user *)arg;
-
- if (!tty)
- return -ENODEV;
-
- un = tty->driver_data;
- if (!un)
- return -ENODEV;
-
- ch = un->un_ch;
- if (!ch)
- return -ENODEV;
-
- bd = ch->ch_bd;
- if (!bd)
- return -ENODEV;
-
- ch_bd_ops = bd->bd_ops;
-
- spin_lock_irqsave(&ch->ch_lock, flags);
-
- if (un->un_open_count <= 0) {
- rc = -EIO;
- goto err_unlock;
- }
-
- switch (cmd) {
- /* Here are all the standard ioctl's that we MUST implement */
-
- case TCSBRK:
- /*
- * TCSBRK is SVID version: non-zero arg --> no break
- * this behaviour is exploited by tcdrain().
- *
- * According to POSIX.1 spec (7.2.2.1.2) breaks should be
- * between 0.25 and 0.5 seconds so we'll ask for something
- * in the middle: 0.375 seconds.
- */
- rc = tty_check_change(tty);
- spin_unlock_irqrestore(&ch->ch_lock, flags);
- if (rc)
- return rc;
-
- rc = ch_bd_ops->drain(tty, 0);
- if (rc)
- return -EINTR;
-
- spin_lock_irqsave(&ch->ch_lock, flags);
-
- if (((cmd == TCSBRK) && (!arg)) || (cmd == TCSBRKP))
- ch_bd_ops->send_break(ch, 250);
-
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-
- return 0;
-
- case TCSBRKP:
- /*
- * support for POSIX tcsendbreak()
- * According to POSIX.1 spec (7.2.2.1.2) breaks should be
- * between 0.25 and 0.5 seconds so we'll ask for something
- * in the middle: 0.375 seconds.
- */
- rc = tty_check_change(tty);
- spin_unlock_irqrestore(&ch->ch_lock, flags);
- if (rc)
- return rc;
-
- rc = ch_bd_ops->drain(tty, 0);
- if (rc)
- return -EINTR;
-
- spin_lock_irqsave(&ch->ch_lock, flags);
-
- ch_bd_ops->send_break(ch, 250);
-
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-
- return 0;
-
- case TIOCSBRK:
- rc = tty_check_change(tty);
- spin_unlock_irqrestore(&ch->ch_lock, flags);
- if (rc)
- return rc;
-
- rc = ch_bd_ops->drain(tty, 0);
- if (rc)
- return -EINTR;
-
- spin_lock_irqsave(&ch->ch_lock, flags);
-
- ch_bd_ops->send_break(ch, 250);
-
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-
- return 0;
-
- case TIOCCBRK:
- /* Do Nothing */
- spin_unlock_irqrestore(&ch->ch_lock, flags);
- return 0;
-
- case TIOCGSOFTCAR:
-
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-
- return put_user(C_CLOCAL(tty) ? 1 : 0,
- (unsigned long __user *)arg);
-
- case TIOCSSOFTCAR:
-
- spin_unlock_irqrestore(&ch->ch_lock, flags);
- rc = get_user(arg, (unsigned long __user *)arg);
- if (rc)
- return rc;
-
- spin_lock_irqsave(&ch->ch_lock, flags);
- tty->termios.c_cflag = ((tty->termios.c_cflag & ~CLOCAL) |
- (arg ? CLOCAL : 0));
- ch_bd_ops->param(tty);
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-
- return 0;
-
- case TIOCMGET:
- spin_unlock_irqrestore(&ch->ch_lock, flags);
- return dgnc_get_modem_info(ch, uarg);
-
- case TIOCMBIS:
- case TIOCMBIC:
- case TIOCMSET:
- spin_unlock_irqrestore(&ch->ch_lock, flags);
- return dgnc_set_modem_info(ch, cmd, uarg);
-
- /* Here are any additional ioctl's that we want to implement */
-
- case TCFLSH:
- /*
- * The linux tty driver doesn't have a flush
- * input routine for the driver, assuming all backed
- * up data is in the line disc. buffers. However,
- * we all know that's not the case. Here, we
- * act on the ioctl, but then lie and say we didn't
- * so the line discipline will process the flush
- * also.
- */
- rc = tty_check_change(tty);
- if (rc)
- goto err_unlock;
-
- if ((arg == TCIFLUSH) || (arg == TCIOFLUSH)) {
- ch->ch_r_head = ch->ch_r_tail;
- ch_bd_ops->flush_uart_read(ch);
- /* Force queue flow control to be released, if needed */
- dgnc_check_queue_flow_control(ch);
- }
-
- if ((arg == TCOFLUSH) || (arg == TCIOFLUSH)) {
- if (!(un->un_type == DGNC_PRINT)) {
- ch->ch_w_head = ch->ch_w_tail;
- ch_bd_ops->flush_uart_write(ch);
-
- if (ch->ch_tun.un_flags & (UN_LOW | UN_EMPTY))
- dgnc_wake_up_unit(&ch->ch_tun);
-
- if (ch->ch_pun.un_flags & (UN_LOW | UN_EMPTY))
- dgnc_wake_up_unit(&ch->ch_pun);
- }
- }
-
- /* pretend we didn't recognize this IOCTL */
- spin_unlock_irqrestore(&ch->ch_lock, flags);
- return -ENOIOCTLCMD;
- case TCSETSF:
- case TCSETSW:
- /*
- * The linux tty driver doesn't have a flush
- * input routine for the driver, assuming all backed
- * up data is in the line disc. buffers. However,
- * we all know that's not the case. Here, we
- * act on the ioctl, but then lie and say we didn't
- * so the line discipline will process the flush
- * also.
- */
- if (cmd == TCSETSF) {
- /* flush rx */
- ch->ch_flags &= ~CH_STOP;
- ch->ch_r_head = ch->ch_r_tail;
- ch_bd_ops->flush_uart_read(ch);
- /* Force queue flow control to be released, if needed */
- dgnc_check_queue_flow_control(ch);
- }
-
- /* now wait for all the output to drain */
- spin_unlock_irqrestore(&ch->ch_lock, flags);
- rc = ch_bd_ops->drain(tty, 0);
- if (rc)
- return -EINTR;
-
- /* pretend we didn't recognize this */
- return -ENOIOCTLCMD;
-
- case TCSETAW:
-
- spin_unlock_irqrestore(&ch->ch_lock, flags);
- rc = ch_bd_ops->drain(tty, 0);
- if (rc)
- return -EINTR;
-
- /* pretend we didn't recognize this */
- return -ENOIOCTLCMD;
-
- case TCXONC:
- spin_unlock_irqrestore(&ch->ch_lock, flags);
- /* Make the ld do it */
- return -ENOIOCTLCMD;
-
- case DIGI_GETA:
- /* get information for ditty */
- spin_unlock_irqrestore(&ch->ch_lock, flags);
- return dgnc_tty_digigeta(tty, uarg);
-
- case DIGI_SETAW:
- case DIGI_SETAF:
-
- /* set information for ditty */
- if (cmd == (DIGI_SETAW)) {
- spin_unlock_irqrestore(&ch->ch_lock, flags);
- rc = ch_bd_ops->drain(tty, 0);
- if (rc)
- return -EINTR;
-
- spin_lock_irqsave(&ch->ch_lock, flags);
- } else {
- tty_ldisc_flush(tty);
- }
- /* fall thru */
-
- case DIGI_SETA:
- spin_unlock_irqrestore(&ch->ch_lock, flags);
- return dgnc_tty_digiseta(tty, uarg);
-
- case DIGI_LOOPBACK:
- {
- uint loopback = 0;
- /*
- * Let go of locks when accessing user space,
- * could sleep
- */
- spin_unlock_irqrestore(&ch->ch_lock, flags);
- rc = get_user(loopback, (unsigned int __user *)arg);
- if (rc)
- return rc;
- spin_lock_irqsave(&ch->ch_lock, flags);
-
- /* Enable/disable internal loopback for this port */
- if (loopback)
- ch->ch_flags |= CH_LOOPBACK;
- else
- ch->ch_flags &= ~(CH_LOOPBACK);
-
- ch_bd_ops->param(tty);
- spin_unlock_irqrestore(&ch->ch_lock, flags);
- return 0;
- }
-
- case DIGI_GETCUSTOMBAUD:
- spin_unlock_irqrestore(&ch->ch_lock, flags);
- return put_user(ch->ch_custom_speed,
- (unsigned int __user *)arg);
-
- case DIGI_SETCUSTOMBAUD:
- {
- int new_rate;
-
- spin_unlock_irqrestore(&ch->ch_lock, flags);
- rc = get_user(new_rate, (int __user *)arg);
- if (rc)
- return rc;
- spin_lock_irqsave(&ch->ch_lock, flags);
- dgnc_set_custom_speed(ch, new_rate);
- ch_bd_ops->param(tty);
- spin_unlock_irqrestore(&ch->ch_lock, flags);
- return 0;
- }
-
- /*
- * This ioctl allows insertion of a character into the front
- * of any pending data to be transmitted.
- *
- * This ioctl is to satisfy the "Send Character Immediate"
- * call that the RealPort protocol spec requires.
- */
- case DIGI_REALPORT_SENDIMMEDIATE:
- {
- unsigned char c;
-
- spin_unlock_irqrestore(&ch->ch_lock, flags);
- rc = get_user(c, (unsigned char __user *)arg);
- if (rc)
- return rc;
- spin_lock_irqsave(&ch->ch_lock, flags);
- ch_bd_ops->send_immediate_char(ch, c);
- spin_unlock_irqrestore(&ch->ch_lock, flags);
- return 0;
- }
-
- /*
- * This ioctl returns all the current counts for the port.
- *
- * This ioctl is to satisfy the "Line Error Counters"
- * call that the RealPort protocol spec requires.
- */
- case DIGI_REALPORT_GETCOUNTERS:
- {
- struct digi_getcounter buf;
-
- buf.norun = ch->ch_err_overrun;
- buf.noflow = 0; /* The driver doesn't keep this stat */
- buf.nframe = ch->ch_err_frame;
- buf.nparity = ch->ch_err_parity;
- buf.nbreak = ch->ch_err_break;
- buf.rbytes = ch->ch_rxcount;
- buf.tbytes = ch->ch_txcount;
-
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-
- if (copy_to_user(uarg, &buf, sizeof(buf)))
- return -EFAULT;
-
- return 0;
- }
-
- /*
- * This ioctl returns all current events.
- *
- * This ioctl is to satisfy the "Event Reporting"
- * call that the RealPort protocol spec requires.
- */
- case DIGI_REALPORT_GETEVENTS:
- {
- unsigned int events = 0;
-
- /* NOTE: MORE EVENTS NEEDS TO BE ADDED HERE */
- if (ch->ch_flags & CH_BREAK_SENDING)
- events |= EV_TXB;
- if ((ch->ch_flags & CH_STOP) ||
- (ch->ch_flags & CH_FORCED_STOP))
- events |= (EV_OPU | EV_OPS);
-
- if ((ch->ch_flags & CH_STOPI) ||
- (ch->ch_flags & CH_FORCED_STOPI))
- events |= (EV_IPU | EV_IPS);
-
- spin_unlock_irqrestore(&ch->ch_lock, flags);
- return put_user(events, (unsigned int __user *)arg);
- }
-
- /*
- * This ioctl returns TOUT and TIN counters based
- * upon the values passed in by the RealPort Server.
- * It also passes back whether the UART Transmitter is
- * empty as well.
- */
- case DIGI_REALPORT_GETBUFFERS:
- {
- struct digi_getbuffer buf;
- int tdist;
- int count;
-
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-
- if (copy_from_user(&buf, uarg, sizeof(buf)))
- return -EFAULT;
-
- spin_lock_irqsave(&ch->ch_lock, flags);
-
- /* Figure out how much data is in our RX and TX queues. */
-
- buf.rxbuf = (ch->ch_r_head - ch->ch_r_tail) & RQUEUEMASK;
- buf.txbuf = (ch->ch_w_head - ch->ch_w_tail) & WQUEUEMASK;
-
- /*
- * Is the UART empty?
- * Add that value to whats in our TX queue.
- */
-
- count = buf.txbuf + ch_bd_ops->get_uart_bytes_left(ch);
-
- /*
- * Figure out how much data the RealPort Server believes should
- * be in our TX queue.
- */
- tdist = (buf.tx_in - buf.tx_out) & 0xffff;
-
- /*
- * If we have more data than the RealPort Server believes we
- * should have, reduce our count to its amount.
- *
- * This count difference CAN happen because the Linux LD can
- * insert more characters into our queue for OPOST processing
- * that the RealPort Server doesn't know about.
- */
- if (buf.txbuf > tdist)
- buf.txbuf = tdist;
-
- /* Report whether our queue and UART TX are completely empty. */
-
- if (count)
- buf.txdone = 0;
- else
- buf.txdone = 1;
-
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-
- if (copy_to_user(uarg, &buf, sizeof(buf)))
- return -EFAULT;
-
- return 0;
- }
- default:
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-
- return -ENOIOCTLCMD;
- }
-err_unlock:
- spin_unlock_irqrestore(&ch->ch_lock, flags);
-
- return rc;
-}
diff --git a/drivers/staging/dgnc/dgnc_tty.h b/drivers/staging/dgnc/dgnc_tty.h
deleted file mode 100644
index 00e31035b83d..000000000000
--- a/drivers/staging/dgnc/dgnc_tty.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * Copyright 2003 Digi International (www.digi.com)
- * Scott H Kilau <Scott_Kilau at digi dot com>
- */
-
-#ifndef _DGNC_TTY_H
-#define _DGNC_TTY_H
-
-#include "dgnc_driver.h"
-
-int dgnc_tty_register(struct dgnc_board *brd);
-void dgnc_tty_unregister(struct dgnc_board *brd);
-
-int dgnc_tty_init(struct dgnc_board *brd);
-
-void dgnc_cleanup_tty(struct dgnc_board *brd);
-
-void dgnc_input(struct channel_t *ch);
-void dgnc_carrier(struct channel_t *ch);
-void dgnc_wakeup_writes(struct channel_t *ch);
-void dgnc_check_queue_flow_control(struct channel_t *ch);
-
-#endif /* _DGNC_TTY_H */
diff --git a/drivers/staging/dgnc/digi.h b/drivers/staging/dgnc/digi.h
deleted file mode 100644
index b414ee80db88..000000000000
--- a/drivers/staging/dgnc/digi.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * Copyright 2003 Digi International (www.digi.com)
- * Scott H Kilau <Scott_Kilau at digi dot com>
- */
-
-#ifndef _DIGI_H
-#define _DIGI_H
-
-#define DIGI_GETA (('e' << 8) | 94) /* Read params */
-#define DIGI_SETA (('e' << 8) | 95) /* Set params */
-#define DIGI_SETAW (('e' << 8) | 96) /* Drain & set params */
-#define DIGI_SETAF (('e' << 8) | 97) /* Drain, flush & set params */
-#define DIGI_LOOPBACK (('d' << 8) | 252) /* Enable/disable UART
- * internal loopback
- */
-#define DIGI_FAST 0x0002 /* Fast baud rates */
-#define RTSPACE 0x0004 /* RTS input flow control */
-#define CTSPACE 0x0008 /* CTS output flow control */
-#define DIGI_COOK 0x0080 /* Cooked processing done in FEP */
-#define DIGI_FORCEDCD 0x0100 /* Force carrier */
-#define DIGI_ALTPIN 0x0200 /* Alternate RJ-45 pin config */
-#define DIGI_PRINTER 0x0800 /* Hold port open for flow cntrl*/
-#define DIGI_DTR_TOGGLE 0x2000 /* Support DTR Toggle */
-#define DIGI_RTS_TOGGLE 0x8000 /* Support RTS Toggle */
-#define DIGI_PLEN 28 /* String length */
-#define DIGI_TSIZ 10 /* Terminal string len */
-
-/*
- * Structure used with ioctl commands for DIGI parameters.
- */
-/**
- * struct digi_t - Ioctl commands for DIGI parameters.
- * @digi_flags: Flags.
- * @digi_maxcps: Maximum printer CPS.
- * @digi_maxchar: Maximum characters in the print queue.
- * @digi_bufsize: Buffer size.
- * @digi_onlen: Length of ON string.
- * @digi_offlen: Length of OFF string.
- * @digi_onstr: Printer ON string.
- * @digi_offstr: Printer OFF string.
- * @digi_term: Terminal string.
- */
-struct digi_t {
- unsigned short digi_flags;
- unsigned short digi_maxcps;
- unsigned short digi_maxchar;
- unsigned short digi_bufsize;
- unsigned char digi_onlen;
- unsigned char digi_offlen;
- char digi_onstr[DIGI_PLEN];
- char digi_offstr[DIGI_PLEN];
- char digi_term[DIGI_TSIZ];
-};
-
-/**
- * struct digi_getbuffer - Holds buffer use counts.
- */
-struct digi_getbuffer {
- unsigned long tx_in;
- unsigned long tx_out;
- unsigned long rxbuf;
- unsigned long txbuf;
- unsigned long txdone;
-};
-
-/**
- * struct digi_getcounter
- * @norun: Number of UART overrun errors.
- * @noflow: Number of buffer overflow errors.
- * @nframe: Number of framing errors.
- * @nparity: Number of parity errors.
- * @nbreak: Number of breaks received.
- * @rbytes: Number of received bytes.
- * @tbytes: Number of transmitted bytes.
- */
-struct digi_getcounter {
- unsigned long norun;
- unsigned long noflow;
- unsigned long nframe;
- unsigned long nparity;
- unsigned long nbreak;
- unsigned long rbytes;
- unsigned long tbytes;
-};
-
-#define DIGI_SETCUSTOMBAUD _IOW('e', 106, int) /* Set integer baud rate */
-#define DIGI_GETCUSTOMBAUD _IOR('e', 107, int) /* Get integer baud rate */
-
-#define DIGI_REALPORT_GETBUFFERS (('e' << 8) | 108)
-#define DIGI_REALPORT_SENDIMMEDIATE (('e' << 8) | 109)
-#define DIGI_REALPORT_GETCOUNTERS (('e' << 8) | 110)
-#define DIGI_REALPORT_GETEVENTS (('e' << 8) | 111)
-
-#define EV_OPU 0x0001 /* Output paused by client */
-#define EV_OPS 0x0002 /* Output paused by regular sw flowctrl */
-#define EV_IPU 0x0010 /* Input paused unconditionally by user */
-#define EV_IPS 0x0020 /* Input paused by high/low water marks */
-#define EV_TXB 0x0040 /* Transmit break pending */
-
-/**
- * struct ni_info - intelligent <--> non-intelligent DPA translation.
- */
-struct ni_info {
- int board;
- int channel;
- int dtr;
- int rts;
- int cts;
- int dsr;
- int ri;
- int dcd;
- int curtx;
- int currx;
- unsigned short iflag;
- unsigned short oflag;
- unsigned short cflag;
- unsigned short lflag;
- unsigned int mstat;
- unsigned char hflow;
- unsigned char xmit_stopped;
- unsigned char recv_stopped;
- unsigned int baud;
-};
-
-#define TTY_FLIPBUF_SIZE 512
-
-#endif /* _DIGI_H */
diff --git a/drivers/staging/emxx_udc/emxx_udc.c b/drivers/staging/emxx_udc/emxx_udc.c
index 3e51476a7045..65cc3d9af972 100644
--- a/drivers/staging/emxx_udc/emxx_udc.c
+++ b/drivers/staging/emxx_udc/emxx_udc.c
@@ -1369,25 +1369,6 @@ static void _nbu2ss_set_endpoint_stall(
}
/*-------------------------------------------------------------------------*/
-/* Device Descriptor */
-static struct usb_device_descriptor device_desc = {
- .bLength = sizeof(device_desc),
- .bDescriptorType = USB_DT_DEVICE,
- .bcdUSB = cpu_to_le16(0x0200),
- .bDeviceClass = USB_CLASS_VENDOR_SPEC,
- .bDeviceSubClass = 0x00,
- .bDeviceProtocol = 0x00,
- .bMaxPacketSize0 = 64,
- .idVendor = cpu_to_le16(0x0409),
- .idProduct = cpu_to_le16(0xfff0),
- .bcdDevice = 0xffff,
- .iManufacturer = 0x00,
- .iProduct = 0x00,
- .iSerialNumber = 0x00,
- .bNumConfigurations = 0x01,
-};
-
-/*-------------------------------------------------------------------------*/
static void _nbu2ss_set_test_mode(struct nbu2ss_udc *udc, u32 mode)
{
u32 data;
@@ -2513,7 +2494,7 @@ static int nbu2ss_ep_enable(
}
ep = container_of(_ep, struct nbu2ss_ep, ep);
- if ((!ep) || (!ep->udc)) {
+ if ((!ep->udc)) {
pr_err(" *** %s, ep == NULL !!\n", __func__);
return -EINVAL;
}
@@ -2570,7 +2551,7 @@ static int nbu2ss_ep_disable(struct usb_ep *_ep)
}
ep = container_of(_ep, struct nbu2ss_ep, ep);
- if ((!ep) || (!ep->udc)) {
+ if (!ep->udc) {
pr_err("udc: *** %s, ep == NULL !!\n", __func__);
return -EINVAL;
}
@@ -2743,10 +2724,6 @@ static int nbu2ss_ep_dequeue(
}
ep = container_of(_ep, struct nbu2ss_ep, ep);
- if (!ep) {
- pr_err("%s, ep == NULL !!\n", __func__);
- return -EINVAL;
- }
udc = ep->udc;
if (!udc)
@@ -2787,10 +2764,6 @@ static int nbu2ss_ep_set_halt(struct usb_ep *_ep, int value)
}
ep = container_of(_ep, struct nbu2ss_ep, ep);
- if (!ep) {
- pr_err("%s, bad ep\n", __func__);
- return -EINVAL;
- }
udc = ep->udc;
if (!udc) {
@@ -2839,10 +2812,6 @@ static int nbu2ss_ep_fifo_status(struct usb_ep *_ep)
}
ep = container_of(_ep, struct nbu2ss_ep, ep);
- if (!ep) {
- pr_err("%s, bad ep\n", __func__);
- return -EINVAL;
- }
udc = ep->udc;
if (!udc) {
@@ -2885,10 +2854,6 @@ static void nbu2ss_ep_fifo_flush(struct usb_ep *_ep)
}
ep = container_of(_ep, struct nbu2ss_ep, ep);
- if (!ep) {
- pr_err("udc: %s, bad ep\n", __func__);
- return;
- }
udc = ep->udc;
if (!udc) {
@@ -2959,10 +2924,6 @@ static int nbu2ss_gad_wakeup(struct usb_gadget *pgadget)
}
udc = container_of(pgadget, struct nbu2ss_udc, gadget);
- if (!udc) {
- dev_err(&pgadget->dev, "%s, udc == NULL\n", __func__);
- return -EINVAL;
- }
data = gpio_get_value(VBUS_VALUE);
if (data == 0) {
diff --git a/drivers/staging/erofs/Kconfig b/drivers/staging/erofs/Kconfig
index 663b755bf2fb..c8521d71039b 100644
--- a/drivers/staging/erofs/Kconfig
+++ b/drivers/staging/erofs/Kconfig
@@ -78,6 +78,15 @@ config EROFS_FAULT_INJECTION
Test EROFS to inject faults such as ENOMEM, EIO, and so on.
If unsure, say N.
+config EROFS_FS_IO_MAX_RETRIES
+ int "EROFS IO Maximum Retries"
+ depends on EROFS_FS
+ default "5"
+ help
+ Maximum retry count of IO Errors.
+
+ If unsure, leave the default value (5 retries, 6 IOs at most).
+
config EROFS_FS_ZIP
bool "EROFS Data Compresssion Support"
depends on EROFS_FS
diff --git a/drivers/staging/erofs/data.c b/drivers/staging/erofs/data.c
index ac263a180253..6384f73e5418 100644
--- a/drivers/staging/erofs/data.c
+++ b/drivers/staging/erofs/data.c
@@ -25,7 +25,7 @@ static inline void read_endio(struct bio *bio)
struct page *page = bvec->bv_page;
/* page is already locked */
- BUG_ON(PageUptodate(page));
+ DBG_BUGON(PageUptodate(page));
if (unlikely(err))
SetPageError(page);
@@ -39,38 +39,50 @@ static inline void read_endio(struct bio *bio)
}
/* prio -- true is used for dir */
-struct page *erofs_get_meta_page(struct super_block *sb,
- erofs_blk_t blkaddr, bool prio)
+struct page *__erofs_get_meta_page(struct super_block *sb,
+ erofs_blk_t blkaddr, bool prio, bool nofail)
{
- struct inode *bd_inode = sb->s_bdev->bd_inode;
- struct address_space *mapping = bd_inode->i_mapping;
+ struct inode *const bd_inode = sb->s_bdev->bd_inode;
+ struct address_space *const mapping = bd_inode->i_mapping;
+ /* prefer retrying in the allocator to blindly looping below */
+ const gfp_t gfp = mapping_gfp_constraint(mapping, ~__GFP_FS) |
+ (nofail ? __GFP_NOFAIL : 0);
+ unsigned int io_retries = nofail ? EROFS_IO_MAX_RETRIES_NOFAIL : 0;
struct page *page;
+ int err;
repeat:
- page = find_or_create_page(mapping, blkaddr,
- /*
- * Prefer looping in the allocator rather than here,
- * at least that code knows what it's doing.
- */
- mapping_gfp_constraint(mapping, ~__GFP_FS) | __GFP_NOFAIL);
-
- BUG_ON(!page || !PageLocked(page));
+ page = find_or_create_page(mapping, blkaddr, gfp);
+ if (unlikely(page == NULL)) {
+ DBG_BUGON(nofail);
+ return ERR_PTR(-ENOMEM);
+ }
+ DBG_BUGON(!PageLocked(page));
if (!PageUptodate(page)) {
struct bio *bio;
- int err;
- bio = prepare_bio(sb, blkaddr, 1, read_endio);
+ bio = erofs_grab_bio(sb, blkaddr, 1, read_endio, nofail);
+ if (IS_ERR(bio)) {
+ DBG_BUGON(nofail);
+ err = PTR_ERR(bio);
+ goto err_out;
+ }
+
err = bio_add_page(bio, page, PAGE_SIZE, 0);
- BUG_ON(err != PAGE_SIZE);
+ if (unlikely(err != PAGE_SIZE)) {
+ err = -EFAULT;
+ goto err_out;
+ }
__submit_bio(bio, REQ_OP_READ,
REQ_META | (prio ? REQ_PRIO : 0));
lock_page(page);
- /* the page has been truncated by others? */
+ /* this page has been truncated by others */
if (unlikely(page->mapping != mapping)) {
+unlock_repeat:
unlock_page(page);
put_page(page);
goto repeat;
@@ -78,25 +90,32 @@ repeat:
/* more likely a read error */
if (unlikely(!PageUptodate(page))) {
- unlock_page(page);
- put_page(page);
-
- page = ERR_PTR(-EIO);
+ if (io_retries) {
+ --io_retries;
+ goto unlock_repeat;
+ }
+ err = -EIO;
+ goto err_out;
}
}
return page;
+
+err_out:
+ unlock_page(page);
+ put_page(page);
+ return ERR_PTR(err);
}
static int erofs_map_blocks_flatmode(struct inode *inode,
struct erofs_map_blocks *map,
int flags)
{
+ int err = 0;
erofs_blk_t nblocks, lastblk;
u64 offset = map->m_la;
struct erofs_vnode *vi = EROFS_V(inode);
trace_erofs_map_blocks_flatmode_enter(inode, map, flags);
- BUG_ON(is_inode_layout_compression(inode));
nblocks = DIV_ROUND_UP(inode->i_size, PAGE_SIZE);
lastblk = nblocks - is_inode_layout_inline(inode);
@@ -123,18 +142,27 @@ static int erofs_map_blocks_flatmode(struct inode *inode,
map->m_plen = inode->i_size - offset;
/* inline data should locate in one meta block */
- BUG_ON(erofs_blkoff(map->m_pa) + map->m_plen > PAGE_SIZE);
+ if (erofs_blkoff(map->m_pa) + map->m_plen > PAGE_SIZE) {
+ DBG_BUGON(1);
+ err = -EIO;
+ goto err_out;
+ }
+
map->m_flags |= EROFS_MAP_META;
} else {
errln("internal error @ nid: %llu (size %llu), m_la 0x%llx",
vi->nid, inode->i_size, map->m_la);
- BUG();
+ DBG_BUGON(1);
+ err = -EIO;
+ goto err_out;
}
out:
map->m_llen = map->m_plen;
+
+err_out:
trace_erofs_map_blocks_flatmode_exit(inode, map, flags, 0);
- return 0;
+ return err;
}
#ifdef CONFIG_EROFS_FS_ZIP
@@ -183,14 +211,14 @@ static inline struct bio *erofs_read_raw_page(
struct address_space *mapping,
struct page *page,
erofs_off_t *last_block,
- unsigned nblocks,
+ unsigned int nblocks,
bool ra)
{
struct inode *inode = mapping->host;
erofs_off_t current_block = (erofs_off_t)page->index;
int err;
- BUG_ON(!nblocks);
+ DBG_BUGON(!nblocks);
if (PageUptodate(page)) {
err = 0;
@@ -217,7 +245,7 @@ submit_bio_retry:
.m_la = blknr_to_addr(current_block),
};
erofs_blk_t blknr;
- unsigned blkoff;
+ unsigned int blkoff;
err = erofs_map_blocks(inode, &map, EROFS_GET_BLOCKS_RAW);
if (unlikely(err))
@@ -233,7 +261,7 @@ submit_bio_retry:
}
/* for RAW access mode, m_plen must be equal to m_llen */
- BUG_ON(map.m_plen != map.m_llen);
+ DBG_BUGON(map.m_plen != map.m_llen);
blknr = erofs_blknr(map.m_pa);
blkoff = erofs_blkoff(map.m_pa);
@@ -243,7 +271,7 @@ submit_bio_retry:
void *vsrc, *vto;
struct page *ipage;
- BUG_ON(map.m_plen > PAGE_SIZE);
+ DBG_BUGON(map.m_plen > PAGE_SIZE);
ipage = erofs_get_meta_page(inode->i_sb, blknr, 0);
@@ -270,7 +298,7 @@ submit_bio_retry:
}
/* pa must be block-aligned for raw reading */
- BUG_ON(erofs_blkoff(map.m_pa) != 0);
+ DBG_BUGON(erofs_blkoff(map.m_pa));
/* max # of continuous pages */
if (nblocks > DIV_ROUND_UP(map.m_plen, PAGE_SIZE))
@@ -278,7 +306,14 @@ submit_bio_retry:
if (nblocks > BIO_MAX_PAGES)
nblocks = BIO_MAX_PAGES;
- bio = prepare_bio(inode->i_sb, blknr, nblocks, read_endio);
+ bio = erofs_grab_bio(inode->i_sb,
+ blknr, nblocks, read_endio, false);
+
+ if (IS_ERR(bio)) {
+ err = PTR_ERR(bio);
+ bio = NULL;
+ goto err_out;
+ }
}
err = bio_add_page(bio, page, PAGE_SIZE, 0);
@@ -331,13 +366,13 @@ static int erofs_raw_access_readpage(struct file *file, struct page *page)
if (IS_ERR(bio))
return PTR_ERR(bio);
- BUG_ON(bio != NULL); /* since we have only one bio -- must be NULL */
+ DBG_BUGON(bio); /* since we have only one bio -- must be NULL */
return 0;
}
static int erofs_raw_access_readpages(struct file *filp,
struct address_space *mapping,
- struct list_head *pages, unsigned nr_pages)
+ struct list_head *pages, unsigned int nr_pages)
{
erofs_off_t last_block;
struct bio *bio = NULL;
@@ -369,7 +404,7 @@ static int erofs_raw_access_readpages(struct file *filp,
/* pages could still be locked */
put_page(page);
}
- BUG_ON(!list_empty(pages));
+ DBG_BUGON(!list_empty(pages));
/* the rare case (end in gaps) */
if (unlikely(bio != NULL))
diff --git a/drivers/staging/erofs/dir.c b/drivers/staging/erofs/dir.c
index be6ae3b1bdbe..d1cb0d78ab84 100644
--- a/drivers/staging/erofs/dir.c
+++ b/drivers/staging/erofs/dir.c
@@ -24,8 +24,8 @@ static const unsigned char erofs_filetype_table[EROFS_FT_MAX] = {
};
static int erofs_fill_dentries(struct dir_context *ctx,
- void *dentry_blk, unsigned *ofs,
- unsigned nameoff, unsigned maxsize)
+ void *dentry_blk, unsigned int *ofs,
+ unsigned int nameoff, unsigned int maxsize)
{
struct erofs_dirent *de = dentry_blk;
const struct erofs_dirent *end = dentry_blk + nameoff;
@@ -36,7 +36,7 @@ static int erofs_fill_dentries(struct dir_context *ctx,
int de_namelen;
unsigned char d_type;
#ifdef CONFIG_EROFS_FS_DEBUG
- unsigned dbg_namelen;
+ unsigned int dbg_namelen;
unsigned char dbg_namebuf[EROFS_NAME_LEN];
#endif
@@ -81,15 +81,15 @@ static int erofs_readdir(struct file *f, struct dir_context *ctx)
struct inode *dir = file_inode(f);
struct address_space *mapping = dir->i_mapping;
const size_t dirsize = i_size_read(dir);
- unsigned i = ctx->pos / EROFS_BLKSIZ;
- unsigned ofs = ctx->pos % EROFS_BLKSIZ;
+ unsigned int i = ctx->pos / EROFS_BLKSIZ;
+ unsigned int ofs = ctx->pos % EROFS_BLKSIZ;
int err = 0;
bool initial = true;
while (ctx->pos < dirsize) {
struct page *dentry_page;
struct erofs_dirent *de;
- unsigned nameoff, maxsize;
+ unsigned int nameoff, maxsize;
dentry_page = read_mapping_page(mapping, i, NULL);
if (IS_ERR(dentry_page))
@@ -109,7 +109,8 @@ static int erofs_readdir(struct file *f, struct dir_context *ctx)
goto skip_this;
}
- maxsize = min_t(unsigned, dirsize - ctx->pos + ofs, PAGE_SIZE);
+ maxsize = min_t(unsigned int,
+ dirsize - ctx->pos + ofs, PAGE_SIZE);
/* search dirents at the arbitrary position */
if (unlikely(initial)) {
diff --git a/drivers/staging/erofs/erofs_fs.h b/drivers/staging/erofs/erofs_fs.h
index 2f8e2bf70941..d4bffa2852b3 100644
--- a/drivers/staging/erofs/erofs_fs.h
+++ b/drivers/staging/erofs/erofs_fs.h
@@ -202,6 +202,14 @@ struct erofs_extent_header {
* di_u.delta[1] = distance to its corresponding tail cluster
* (di_advise could be 0, 1 or 2)
*/
+enum {
+ Z_EROFS_VLE_CLUSTER_TYPE_PLAIN,
+ Z_EROFS_VLE_CLUSTER_TYPE_HEAD,
+ Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD,
+ Z_EROFS_VLE_CLUSTER_TYPE_RESERVED,
+ Z_EROFS_VLE_CLUSTER_TYPE_MAX
+};
+
#define Z_EROFS_VLE_DI_CLUSTER_TYPE_BITS 2
#define Z_EROFS_VLE_DI_CLUSTER_TYPE_BIT 0
@@ -260,6 +268,9 @@ static inline void erofs_check_ondisk_layout_definitions(void)
BUILD_BUG_ON(sizeof(struct erofs_extent_header) != 16);
BUILD_BUG_ON(sizeof(struct z_erofs_vle_decompressed_index) != 8);
BUILD_BUG_ON(sizeof(struct erofs_dirent) != 12);
+
+ BUILD_BUG_ON(BIT(Z_EROFS_VLE_DI_CLUSTER_TYPE_BITS) <
+ Z_EROFS_VLE_CLUSTER_TYPE_MAX - 1);
}
#endif
diff --git a/drivers/staging/erofs/include/trace/events/erofs.h b/drivers/staging/erofs/include/trace/events/erofs.h
index 5aead93a762f..660c92fc1803 100644
--- a/drivers/staging/erofs/include/trace/events/erofs.h
+++ b/drivers/staging/erofs/include/trace/events/erofs.h
@@ -162,7 +162,8 @@ DECLARE_EVENT_CLASS(erofs__map_blocks_enter,
TP_printk("dev = (%d,%d), nid = %llu, la %llu llen %llu flags %s",
show_dev_nid(__entry),
- __entry->la, __entry->llen, show_map_flags(__entry->flags))
+ __entry->la, __entry->llen,
+ __entry->flags ? show_map_flags(__entry->flags) : "NULL")
);
DEFINE_EVENT(erofs__map_blocks_enter, erofs_map_blocks_flatmode_enter,
@@ -172,6 +173,13 @@ DEFINE_EVENT(erofs__map_blocks_enter, erofs_map_blocks_flatmode_enter,
TP_ARGS(inode, map, flags)
);
+DEFINE_EVENT(erofs__map_blocks_enter, z_erofs_map_blocks_iter_enter,
+ TP_PROTO(struct inode *inode, struct erofs_map_blocks *map,
+ unsigned int flags),
+
+ TP_ARGS(inode, map, flags)
+);
+
DECLARE_EVENT_CLASS(erofs__map_blocks_exit,
TP_PROTO(struct inode *inode, struct erofs_map_blocks *map,
unsigned int flags, int ret),
@@ -204,7 +212,8 @@ DECLARE_EVENT_CLASS(erofs__map_blocks_exit,
TP_printk("dev = (%d,%d), nid = %llu, flags %s "
"la %llu pa %llu llen %llu plen %llu mflags %s ret %d",
- show_dev_nid(__entry), show_map_flags(__entry->flags),
+ show_dev_nid(__entry),
+ __entry->flags ? show_map_flags(__entry->flags) : "NULL",
__entry->la, __entry->pa, __entry->llen, __entry->plen,
show_mflags(__entry->mflags), __entry->ret)
);
@@ -216,6 +225,13 @@ DEFINE_EVENT(erofs__map_blocks_exit, erofs_map_blocks_flatmode_exit,
TP_ARGS(inode, map, flags, ret)
);
+DEFINE_EVENT(erofs__map_blocks_exit, z_erofs_map_blocks_iter_exit,
+ TP_PROTO(struct inode *inode, struct erofs_map_blocks *map,
+ unsigned int flags, int ret),
+
+ TP_ARGS(inode, map, flags, ret)
+);
+
TRACE_EVENT(erofs_destroy_inode,
TP_PROTO(struct inode *inode),
diff --git a/drivers/staging/erofs/inode.c b/drivers/staging/erofs/inode.c
index fbf6ff25cd1b..04c61a9d7b76 100644
--- a/drivers/staging/erofs/inode.c
+++ b/drivers/staging/erofs/inode.c
@@ -19,7 +19,7 @@ static int read_inode(struct inode *inode, void *data)
{
struct erofs_vnode *vi = EROFS_V(inode);
struct erofs_inode_v1 *v1 = data;
- const unsigned advise = le16_to_cpu(v1->i_advise);
+ const unsigned int advise = le16_to_cpu(v1->i_advise);
vi->data_mapping_mode = __inode_data_mapping(advise);
@@ -112,7 +112,8 @@ static int read_inode(struct inode *inode, void *data)
* try_lock since it takes no much overhead and
* will success immediately.
*/
-static int fill_inline_data(struct inode *inode, void *data, unsigned m_pofs)
+static int fill_inline_data(struct inode *inode, void *data,
+ unsigned int m_pofs)
{
struct erofs_vnode *vi = EROFS_V(inode);
struct erofs_sb_info *sbi = EROFS_I_SB(inode);
@@ -152,7 +153,7 @@ static int fill_inode(struct inode *inode, int isdir)
void *data;
int err;
erofs_blk_t blkaddr;
- unsigned ofs;
+ unsigned int ofs;
trace_erofs_fill_inode(inode, isdir);
@@ -231,10 +232,45 @@ out_unlock:
return err;
}
+/*
+ * erofs nid is 64bits, but i_ino is 'unsigned long', therefore
+ * we should do more for 32-bit platform to find the right inode.
+ */
+#if BITS_PER_LONG == 32
+static int erofs_ilookup_test_actor(struct inode *inode, void *opaque)
+{
+ const erofs_nid_t nid = *(erofs_nid_t *)opaque;
+
+ return EROFS_V(inode)->nid == nid;
+}
+
+static int erofs_iget_set_actor(struct inode *inode, void *opaque)
+{
+ const erofs_nid_t nid = *(erofs_nid_t *)opaque;
+
+ inode->i_ino = erofs_inode_hash(nid);
+ return 0;
+}
+#endif
+
+static inline struct inode *erofs_iget_locked(struct super_block *sb,
+ erofs_nid_t nid)
+{
+ const unsigned long hashval = erofs_inode_hash(nid);
+
+#if BITS_PER_LONG >= 64
+ /* it is safe to use iget_locked for >= 64-bit platform */
+ return iget_locked(sb, hashval);
+#else
+ return iget5_locked(sb, hashval, erofs_ilookup_test_actor,
+ erofs_iget_set_actor, &nid);
+#endif
+}
+
struct inode *erofs_iget(struct super_block *sb,
erofs_nid_t nid, bool isdir)
{
- struct inode *inode = iget_locked(sb, nid);
+ struct inode *inode = erofs_iget_locked(sb, nid);
if (unlikely(inode == NULL))
return ERR_PTR(-ENOMEM);
@@ -259,22 +295,16 @@ struct inode *erofs_iget(struct super_block *sb,
const struct inode_operations erofs_generic_xattr_iops = {
.listxattr = erofs_listxattr,
};
-#endif
-#ifdef CONFIG_EROFS_FS_XATTR
const struct inode_operations erofs_symlink_xattr_iops = {
.get_link = page_get_link,
.listxattr = erofs_listxattr,
};
-#endif
const struct inode_operations erofs_special_inode_operations = {
-#ifdef CONFIG_EROFS_FS_XATTR
.listxattr = erofs_listxattr,
-#endif
};
-#ifdef CONFIG_EROFS_FS_XATTR
const struct inode_operations erofs_fast_symlink_xattr_iops = {
.get_link = simple_get_link,
.listxattr = erofs_listxattr,
diff --git a/drivers/staging/erofs/internal.h b/drivers/staging/erofs/internal.h
index 367b39fe46e5..57575c7f5635 100644
--- a/drivers/staging/erofs/internal.h
+++ b/drivers/staging/erofs/internal.h
@@ -42,12 +42,12 @@
#define DBG_BUGON(...) ((void)0)
#endif
-#ifdef CONFIG_EROFS_FAULT_INJECTION
enum {
FAULT_KMALLOC,
FAULT_MAX,
};
+#ifdef CONFIG_EROFS_FAULT_INJECTION
extern char *erofs_fault_name[FAULT_MAX];
#define IS_FAULT_SET(fi, type) ((fi)->inject_type & (1 << (type)))
@@ -95,6 +95,9 @@ struct erofs_sb_info {
/* the dedicated workstation for compression */
struct radix_tree_root workstn_tree;
+ /* threshold for decompression synchronously */
+ unsigned int max_sync_decompress_pages;
+
#ifdef EROFS_FS_HAS_MANAGED_CACHE
struct inode *managed_cache;
#endif
@@ -143,17 +146,24 @@ static inline bool time_to_inject(struct erofs_sb_info *sbi, int type)
}
return false;
}
+#else
+static inline bool time_to_inject(struct erofs_sb_info *sbi, int type)
+{
+ return false;
+}
+
+static inline void erofs_show_injection_info(int type)
+{
+}
#endif
static inline void *erofs_kmalloc(struct erofs_sb_info *sbi,
size_t size, gfp_t flags)
{
-#ifdef CONFIG_EROFS_FAULT_INJECTION
if (time_to_inject(sbi, FAULT_KMALLOC)) {
erofs_show_injection_info(FAULT_KMALLOC);
return NULL;
}
-#endif
return kmalloc(size, flags);
}
@@ -266,6 +276,20 @@ extern int erofs_try_to_free_cached_page(struct address_space *mapping,
struct page *page);
#endif
+#define DEFAULT_MAX_SYNC_DECOMPRESS_PAGES 3
+
+static inline bool __should_decompress_synchronously(struct erofs_sb_info *sbi,
+ unsigned int nr)
+{
+ return nr <= sbi->max_sync_decompress_pages;
+}
+
+int __init z_erofs_init_zip_subsystem(void);
+void z_erofs_exit_zip_subsystem(void);
+#else
+/* dummy initializer/finalizer for the decompression subsystem */
+static inline int z_erofs_init_zip_subsystem(void) { return 0; }
+static inline void z_erofs_exit_zip_subsystem(void) {}
#endif
/* we strictly follow PAGE_SIZE and no buffer head yet */
@@ -420,30 +444,30 @@ struct erofs_map_blocks {
#define EROFS_GET_BLOCKS_RAW 0x0001
/* data.c */
-static inline struct bio *prepare_bio(
- struct super_block *sb,
- erofs_blk_t blkaddr, unsigned nr_pages,
- bio_end_io_t endio)
+static inline struct bio *
+erofs_grab_bio(struct super_block *sb,
+ erofs_blk_t blkaddr, unsigned int nr_pages,
+ bio_end_io_t endio, bool nofail)
{
- gfp_t gfp = GFP_NOIO;
- struct bio *bio = bio_alloc(gfp, nr_pages);
-
- if (unlikely(bio == NULL) &&
- (current->flags & PF_MEMALLOC)) {
- do {
- nr_pages /= 2;
- if (unlikely(!nr_pages)) {
- bio = bio_alloc(gfp | __GFP_NOFAIL, 1);
- BUG_ON(bio == NULL);
- break;
+ const gfp_t gfp = GFP_NOIO;
+ struct bio *bio;
+
+ do {
+ if (nr_pages == 1) {
+ bio = bio_alloc(gfp | (nofail ? __GFP_NOFAIL : 0), 1);
+ if (unlikely(bio == NULL)) {
+ DBG_BUGON(nofail);
+ return ERR_PTR(-ENOMEM);
}
- bio = bio_alloc(gfp, nr_pages);
- } while (bio == NULL);
- }
+ break;
+ }
+ bio = bio_alloc(gfp, nr_pages);
+ nr_pages /= 2;
+ } while (unlikely(bio == NULL));
bio->bi_end_io = endio;
bio_set_dev(bio, sb->s_bdev);
- bio->bi_iter.bi_sector = blkaddr << LOG_SECTORS_PER_BLOCK;
+ bio->bi_iter.bi_sector = (sector_t)blkaddr << LOG_SECTORS_PER_BLOCK;
return bio;
}
@@ -453,8 +477,27 @@ static inline void __submit_bio(struct bio *bio, unsigned op, unsigned op_flags)
submit_bio(bio);
}
-extern struct page *erofs_get_meta_page(struct super_block *sb,
- erofs_blk_t blkaddr, bool prio);
+#ifndef CONFIG_EROFS_FS_IO_MAX_RETRIES
+#define EROFS_IO_MAX_RETRIES_NOFAIL 0
+#else
+#define EROFS_IO_MAX_RETRIES_NOFAIL CONFIG_EROFS_FS_IO_MAX_RETRIES
+#endif
+
+extern struct page *__erofs_get_meta_page(struct super_block *sb,
+ erofs_blk_t blkaddr, bool prio, bool nofail);
+
+static inline struct page *erofs_get_meta_page(struct super_block *sb,
+ erofs_blk_t blkaddr, bool prio)
+{
+ return __erofs_get_meta_page(sb, blkaddr, prio, false);
+}
+
+static inline struct page *erofs_get_meta_page_nofail(struct super_block *sb,
+ erofs_blk_t blkaddr, bool prio)
+{
+ return __erofs_get_meta_page(sb, blkaddr, prio, true);
+}
+
extern int erofs_map_blocks(struct inode *, struct erofs_map_blocks *, int);
extern int erofs_map_blocks_iter(struct inode *, struct erofs_map_blocks *,
struct page **, int);
@@ -465,14 +508,24 @@ struct erofs_map_blocks_iter {
};
-static inline struct page *erofs_get_inline_page(struct inode *inode,
- erofs_blk_t blkaddr)
+static inline struct page *
+erofs_get_inline_page(struct inode *inode,
+ erofs_blk_t blkaddr)
{
return erofs_get_meta_page(inode->i_sb,
blkaddr, S_ISDIR(inode->i_mode));
}
/* inode.c */
+static inline unsigned long erofs_inode_hash(erofs_nid_t nid)
+{
+#if BITS_PER_LONG == 32
+ return (nid >> 32) ^ (nid & 0xffffffff);
+#else
+ return nid;
+#endif
+}
+
extern struct inode *erofs_iget(struct super_block *sb,
erofs_nid_t nid, bool dir);
@@ -480,13 +533,11 @@ extern struct inode *erofs_iget(struct super_block *sb,
int erofs_namei(struct inode *dir, struct qstr *name,
erofs_nid_t *nid, unsigned *d_type);
-/* xattr.c */
#ifdef CONFIG_EROFS_FS_XATTR
+/* xattr.c */
extern const struct xattr_handler *erofs_xattr_handlers[];
-#endif
-/* symlink */
-#ifdef CONFIG_EROFS_FS_XATTR
+/* symlink and special inode */
extern const struct inode_operations erofs_symlink_xattr_iops;
extern const struct inode_operations erofs_fast_symlink_xattr_iops;
extern const struct inode_operations erofs_special_inode_operations;
diff --git a/drivers/staging/erofs/namei.c b/drivers/staging/erofs/namei.c
index 546a47156101..5596c52e246d 100644
--- a/drivers/staging/erofs/namei.c
+++ b/drivers/staging/erofs/namei.c
@@ -17,9 +17,9 @@
/* based on the value of qn->len is accurate */
static inline int dirnamecmp(struct qstr *qn,
- struct qstr *qd, unsigned *matched)
+ struct qstr *qd, unsigned int *matched)
{
- unsigned i = *matched, len = min(qn->len, qd->len);
+ unsigned int i = *matched, len = min(qn->len, qd->len);
loop:
if (unlikely(i >= len)) {
*matched = i;
@@ -46,8 +46,8 @@ static struct erofs_dirent *find_target_dirent(
struct qstr *name,
u8 *data, int maxsize)
{
- unsigned ndirents, head, back;
- unsigned startprfx, endprfx;
+ unsigned int ndirents, head, back;
+ unsigned int startprfx, endprfx;
struct erofs_dirent *const de = (struct erofs_dirent *)data;
/* make sure that maxsize is valid */
@@ -63,9 +63,9 @@ static struct erofs_dirent *find_target_dirent(
startprfx = endprfx = 0;
while (head <= back) {
- unsigned mid = head + (back - head) / 2;
- unsigned nameoff = le16_to_cpu(de[mid].nameoff);
- unsigned matched = min(startprfx, endprfx);
+ unsigned int mid = head + (back - head) / 2;
+ unsigned int nameoff = le16_to_cpu(de[mid].nameoff);
+ unsigned int matched = min(startprfx, endprfx);
struct qstr dname = QSTR_INIT(data + nameoff,
unlikely(mid >= ndirents - 1) ?
@@ -95,8 +95,8 @@ static struct page *find_target_block_classic(
struct inode *dir,
struct qstr *name, int *_diff)
{
- unsigned startprfx, endprfx;
- unsigned head, back;
+ unsigned int startprfx, endprfx;
+ unsigned int head, back;
struct address_space *const mapping = dir->i_mapping;
struct page *candidate = ERR_PTR(-ENOENT);
@@ -105,7 +105,7 @@ static struct page *find_target_block_classic(
back = inode_datablocks(dir) - 1;
while (head <= back) {
- unsigned mid = head + (back - head) / 2;
+ unsigned int mid = head + (back - head) / 2;
struct page *page = read_mapping_page(mapping, mid, NULL);
if (IS_ERR(page)) {
@@ -115,10 +115,10 @@ exact_out:
return page;
} else {
int diff;
- unsigned ndirents, matched;
+ unsigned int ndirents, matched;
struct qstr dname;
struct erofs_dirent *de = kmap_atomic(page);
- unsigned nameoff = le16_to_cpu(de->nameoff);
+ unsigned int nameoff = le16_to_cpu(de->nameoff);
ndirents = nameoff / sizeof(*de);
@@ -164,7 +164,7 @@ exact_out:
int erofs_namei(struct inode *dir,
struct qstr *name,
- erofs_nid_t *nid, unsigned *d_type)
+ erofs_nid_t *nid, unsigned int *d_type)
{
int diff;
struct page *page;
@@ -204,7 +204,7 @@ static struct dentry *erofs_lookup(struct inode *dir,
{
int err;
erofs_nid_t nid;
- unsigned d_type;
+ unsigned int d_type;
struct inode *inode;
DBG_BUGON(!d_really_is_negative(dentry));
@@ -223,18 +223,13 @@ static struct dentry *erofs_lookup(struct inode *dir,
if (err == -ENOENT) {
/* negative dentry */
inode = NULL;
- goto negative_out;
- } else if (unlikely(err))
- return ERR_PTR(err);
-
- debugln("%s, %s (nid %llu) found, d_type %u", __func__,
- dentry->d_name.name, nid, d_type);
-
- inode = erofs_iget(dir->i_sb, nid, d_type == EROFS_FT_DIR);
- if (IS_ERR(inode))
- return ERR_CAST(inode);
-
-negative_out:
+ } else if (unlikely(err)) {
+ inode = ERR_PTR(err);
+ } else {
+ debugln("%s, %s (nid %llu) found, d_type %u", __func__,
+ dentry->d_name.name, nid, d_type);
+ inode = erofs_iget(dir->i_sb, nid, d_type == EROFS_FT_DIR);
+ }
return d_splice_alias(inode, dentry);
}
diff --git a/drivers/staging/erofs/super.c b/drivers/staging/erofs/super.c
index 2df9768edac9..f69e619807a1 100644
--- a/drivers/staging/erofs/super.c
+++ b/drivers/staging/erofs/super.c
@@ -29,7 +29,7 @@ static void init_once(void *ptr)
inode_init_once(&vi->vfs_inode);
}
-static int erofs_init_inode_cache(void)
+static int __init erofs_init_inode_cache(void)
{
erofs_inode_cachep = kmem_cache_create("erofs_inode",
sizeof(struct erofs_vnode), 0,
@@ -81,7 +81,7 @@ static int superblock_read(struct super_block *sb)
struct erofs_sb_info *sbi;
struct buffer_head *bh;
struct erofs_super_block *layout;
- unsigned blkszbits;
+ unsigned int blkszbits;
int ret;
bh = sb_bread(sb, 0);
@@ -116,9 +116,10 @@ static int superblock_read(struct super_block *sb)
#endif
sbi->islotbits = ffs(sizeof(struct erofs_inode_v1)) - 1;
#ifdef CONFIG_EROFS_FS_ZIP
- sbi->clusterbits = 12;
+ /* TODO: clusterbits should be related to inode */
+ sbi->clusterbits = blkszbits;
- if (1 << (sbi->clusterbits - 12) > Z_EROFS_CLUSTER_MAX_PAGES)
+ if (1 << (sbi->clusterbits - PAGE_SHIFT) > Z_EROFS_CLUSTER_MAX_PAGES)
errln("clusterbits %u is not supported on this kernel",
sbi->clusterbits);
#endif
@@ -144,8 +145,8 @@ char *erofs_fault_name[FAULT_MAX] = {
[FAULT_KMALLOC] = "kmalloc",
};
-static void erofs_build_fault_attr(struct erofs_sb_info *sbi,
- unsigned int rate)
+static void __erofs_build_fault_attr(struct erofs_sb_info *sbi,
+ unsigned int rate)
{
struct erofs_fault_info *ffi = &sbi->fault_info;
@@ -156,11 +157,52 @@ static void erofs_build_fault_attr(struct erofs_sb_info *sbi,
} else {
memset(ffi, 0, sizeof(struct erofs_fault_info));
}
+
+ set_opt(sbi, FAULT_INJECTION);
+}
+
+static int erofs_build_fault_attr(struct erofs_sb_info *sbi,
+ substring_t *args)
+{
+ int rate = 0;
+
+ if (args->from && match_int(args, &rate))
+ return -EINVAL;
+
+ __erofs_build_fault_attr(sbi, rate);
+ return 0;
+}
+
+static unsigned int erofs_get_fault_rate(struct erofs_sb_info *sbi)
+{
+ return sbi->fault_info.inject_rate;
+}
+#else
+static void __erofs_build_fault_attr(struct erofs_sb_info *sbi,
+ unsigned int rate)
+{
+}
+
+static int erofs_build_fault_attr(struct erofs_sb_info *sbi,
+ substring_t *args)
+{
+ infoln("fault_injection options not supported");
+ return 0;
+}
+
+static unsigned int erofs_get_fault_rate(struct erofs_sb_info *sbi)
+{
+ return 0;
}
#endif
static void default_options(struct erofs_sb_info *sbi)
{
+ /* set up some FS parameters */
+#ifdef CONFIG_EROFS_FS_ZIP
+ sbi->max_sync_decompress_pages = DEFAULT_MAX_SYNC_DECOMPRESS_PAGES;
+#endif
+
#ifdef CONFIG_EROFS_FS_XATTR
set_opt(sbi, XATTR_USER);
#endif
@@ -192,7 +234,7 @@ static int parse_options(struct super_block *sb, char *options)
{
substring_t args[MAX_OPT_ARGS];
char *p;
- int arg = 0;
+ int err;
if (!options)
return 0;
@@ -238,15 +280,11 @@ static int parse_options(struct super_block *sb, char *options)
break;
#endif
case Opt_fault_injection:
- if (args->from && match_int(args, &arg))
- return -EINVAL;
-#ifdef CONFIG_EROFS_FAULT_INJECTION
- erofs_build_fault_attr(EROFS_SB(sb), arg);
- set_opt(EROFS_SB(sb), FAULT_INJECTION);
-#else
- infoln("FAULT_INJECTION was not selected");
-#endif
+ err = erofs_build_fault_attr(EROFS_SB(sb), args);
+ if (err)
+ return err;
break;
+
default:
errln("Unrecognized mount option \"%s\" "
"or missing value", p);
@@ -521,11 +559,6 @@ static struct file_system_type erofs_fs_type = {
};
MODULE_ALIAS_FS("erofs");
-#ifdef CONFIG_EROFS_FS_ZIP
-extern int z_erofs_init_zip_subsystem(void);
-extern void z_erofs_exit_zip_subsystem(void);
-#endif
-
static int __init erofs_module_init(void)
{
int err;
@@ -541,11 +574,9 @@ static int __init erofs_module_init(void)
if (err)
goto shrinker_err;
-#ifdef CONFIG_EROFS_FS_ZIP
err = z_erofs_init_zip_subsystem();
if (err)
goto zip_err;
-#endif
err = register_filesystem(&erofs_fs_type);
if (err)
@@ -555,10 +586,8 @@ static int __init erofs_module_init(void)
return 0;
fs_err:
-#ifdef CONFIG_EROFS_FS_ZIP
z_erofs_exit_zip_subsystem();
zip_err:
-#endif
unregister_shrinker(&erofs_shrinker_info);
shrinker_err:
erofs_exit_inode_cache();
@@ -569,9 +598,7 @@ icache_err:
static void __exit erofs_module_exit(void)
{
unregister_filesystem(&erofs_fs_type);
-#ifdef CONFIG_EROFS_FS_ZIP
z_erofs_exit_zip_subsystem();
-#endif
unregister_shrinker(&erofs_shrinker_info);
erofs_exit_inode_cache();
infoln("successfully finalize erofs");
@@ -615,20 +642,31 @@ static int erofs_show_options(struct seq_file *seq, struct dentry *root)
else
seq_puts(seq, ",noacl");
#endif
-#ifdef CONFIG_EROFS_FAULT_INJECTION
if (test_opt(sbi, FAULT_INJECTION))
seq_printf(seq, ",fault_injection=%u",
- sbi->fault_info.inject_rate);
-#endif
+ erofs_get_fault_rate(sbi));
return 0;
}
static int erofs_remount(struct super_block *sb, int *flags, char *data)
{
+ struct erofs_sb_info *sbi = EROFS_SB(sb);
+ unsigned int org_mnt_opt = sbi->mount_opt;
+ unsigned int org_inject_rate = erofs_get_fault_rate(sbi);
+ int err;
+
BUG_ON(!sb_rdonly(sb));
+ err = parse_options(sb, data);
+ if (err)
+ goto out;
*flags |= SB_RDONLY;
return 0;
+out:
+ __erofs_build_fault_attr(sbi, org_inject_rate);
+ sbi->mount_opt = org_mnt_opt;
+
+ return err;
}
const struct super_operations erofs_sops = {
diff --git a/drivers/staging/erofs/unzip_vle.c b/drivers/staging/erofs/unzip_vle.c
index 8721f0a41d15..79d3ba62b298 100644
--- a/drivers/staging/erofs/unzip_vle.c
+++ b/drivers/staging/erofs/unzip_vle.c
@@ -13,6 +13,8 @@
#include "unzip_vle.h"
#include <linux/prefetch.h>
+#include <trace/events/erofs.h>
+
static struct workqueue_struct *z_erofs_workqueue __read_mostly;
static struct kmem_cache *z_erofs_workgroup_cachep __read_mostly;
@@ -27,7 +29,7 @@ void z_erofs_exit_zip_subsystem(void)
static inline int init_unzip_workqueue(void)
{
- const unsigned onlinecpus = num_possible_cpus();
+ const unsigned int onlinecpus = num_possible_cpus();
/*
* we don't need too many threads, limiting threads
@@ -40,7 +42,7 @@ static inline int init_unzip_workqueue(void)
return z_erofs_workqueue != NULL ? 0 : -ENOMEM;
}
-int z_erofs_init_zip_subsystem(void)
+int __init z_erofs_init_zip_subsystem(void)
{
z_erofs_workgroup_cachep =
kmem_cache_create("erofs_compress",
@@ -89,7 +91,7 @@ struct z_erofs_vle_work_builder {
/* pages used for reading the compressed data */
struct page **compressed_pages;
- unsigned compressed_deficit;
+ unsigned int compressed_deficit;
};
#define VLE_WORK_BUILDER_INIT() \
@@ -232,7 +234,7 @@ static int z_erofs_vle_work_add_page(
ret = z_erofs_pagevec_ctor_enqueue(&builder->vector,
page, type, &occupied);
- builder->work->vcnt += (unsigned)ret;
+ builder->work->vcnt += (unsigned int)ret;
return ret ? 0 : -EAGAIN;
}
@@ -271,36 +273,39 @@ retry:
return true; /* lucky, I am the followee :) */
}
+struct z_erofs_vle_work_finder {
+ struct super_block *sb;
+ pgoff_t idx;
+ unsigned int pageofs;
+
+ struct z_erofs_vle_workgroup **grp_ret;
+ enum z_erofs_vle_work_role *role;
+ z_erofs_vle_owned_workgrp_t *owned_head;
+ bool *hosted;
+};
+
static struct z_erofs_vle_work *
-z_erofs_vle_work_lookup(struct super_block *sb,
- pgoff_t idx, unsigned pageofs,
- struct z_erofs_vle_workgroup **grp_ret,
- enum z_erofs_vle_work_role *role,
- z_erofs_vle_owned_workgrp_t *owned_head,
- bool *hosted)
+z_erofs_vle_work_lookup(const struct z_erofs_vle_work_finder *f)
{
bool tag, primary;
struct erofs_workgroup *egrp;
struct z_erofs_vle_workgroup *grp;
struct z_erofs_vle_work *work;
- egrp = erofs_find_workgroup(sb, idx, &tag);
+ egrp = erofs_find_workgroup(f->sb, f->idx, &tag);
if (egrp == NULL) {
- *grp_ret = NULL;
+ *f->grp_ret = NULL;
return NULL;
}
- *grp_ret = grp = container_of(egrp,
- struct z_erofs_vle_workgroup, obj);
+ grp = container_of(egrp, struct z_erofs_vle_workgroup, obj);
+ *f->grp_ret = grp;
-#ifndef CONFIG_EROFS_FS_ZIP_MULTIREF
- work = z_erofs_vle_grab_work(grp, pageofs);
+ work = z_erofs_vle_grab_work(grp, f->pageofs);
+ /* if multiref is disabled, `primary' is always true */
primary = true;
-#else
- BUG();
-#endif
- DBG_BUGON(work->pageofs != pageofs);
+ DBG_BUGON(work->pageofs != f->pageofs);
/*
* lock must be taken first to avoid grp->next == NIL between
@@ -340,43 +345,35 @@ z_erofs_vle_work_lookup(struct super_block *sb,
*/
mutex_lock(&work->lock);
- *hosted = false;
+ *f->hosted = false;
if (!primary)
- *role = Z_EROFS_VLE_WORK_SECONDARY;
+ *f->role = Z_EROFS_VLE_WORK_SECONDARY;
/* claim the workgroup if possible */
- else if (try_to_claim_workgroup(grp, owned_head, hosted))
- *role = Z_EROFS_VLE_WORK_PRIMARY_FOLLOWED;
+ else if (try_to_claim_workgroup(grp, f->owned_head, f->hosted))
+ *f->role = Z_EROFS_VLE_WORK_PRIMARY_FOLLOWED;
else
- *role = Z_EROFS_VLE_WORK_PRIMARY;
+ *f->role = Z_EROFS_VLE_WORK_PRIMARY;
return work;
}
static struct z_erofs_vle_work *
-z_erofs_vle_work_register(struct super_block *sb,
- struct z_erofs_vle_workgroup **grp_ret,
- struct erofs_map_blocks *map,
- pgoff_t index, unsigned pageofs,
- enum z_erofs_vle_work_role *role,
- z_erofs_vle_owned_workgrp_t *owned_head,
- bool *hosted)
+z_erofs_vle_work_register(const struct z_erofs_vle_work_finder *f,
+ struct erofs_map_blocks *map)
{
- bool newgrp = false;
- struct z_erofs_vle_workgroup *grp = *grp_ret;
+ bool gnew = false;
+ struct z_erofs_vle_workgroup *grp = *f->grp_ret;
struct z_erofs_vle_work *work;
-#ifndef CONFIG_EROFS_FS_ZIP_MULTIREF
+ /* if multiref is disabled, grp should never be nullptr */
BUG_ON(grp != NULL);
-#else
- if (grp != NULL)
- goto skip;
-#endif
+
/* no available workgroup, let's allocate one */
grp = kmem_cache_zalloc(z_erofs_workgroup_cachep, GFP_NOFS);
if (unlikely(grp == NULL))
return ERR_PTR(-ENOMEM);
- grp->obj.index = index;
+ grp->obj.index = f->idx;
grp->llen = map->m_llen;
z_erofs_vle_set_workgrp_fmt(grp,
@@ -386,26 +383,20 @@ z_erofs_vle_work_register(struct super_block *sb,
atomic_set(&grp->obj.refcount, 1);
/* new workgrps have been claimed as type 1 */
- WRITE_ONCE(grp->next, *owned_head);
+ WRITE_ONCE(grp->next, *f->owned_head);
/* primary and followed work for all new workgrps */
- *role = Z_EROFS_VLE_WORK_PRIMARY_FOLLOWED;
+ *f->role = Z_EROFS_VLE_WORK_PRIMARY_FOLLOWED;
/* it should be submitted by ourselves */
- *hosted = true;
+ *f->hosted = true;
- newgrp = true;
-#ifdef CONFIG_EROFS_FS_ZIP_MULTIREF
-skip:
- /* currently unimplemented */
- BUG();
-#else
+ gnew = true;
work = z_erofs_vle_grab_primary_work(grp);
-#endif
- work->pageofs = pageofs;
+ work->pageofs = f->pageofs;
mutex_init(&work->lock);
- if (newgrp) {
- int err = erofs_register_workgroup(sb, &grp->obj, 0);
+ if (gnew) {
+ int err = erofs_register_workgroup(f->sb, &grp->obj, 0);
if (err) {
kmem_cache_free(z_erofs_workgroup_cachep, grp);
@@ -413,24 +404,12 @@ skip:
}
}
- *owned_head = *grp_ret = grp;
+ *f->owned_head = *f->grp_ret = grp;
mutex_lock(&work->lock);
return work;
}
-static inline void __update_workgrp_llen(struct z_erofs_vle_workgroup *grp,
- unsigned int llen)
-{
- while (1) {
- unsigned int orig_llen = grp->llen;
-
- if (orig_llen >= llen || orig_llen ==
- cmpxchg(&grp->llen, orig_llen, llen))
- break;
- }
-}
-
#define builder_is_followed(builder) \
((builder)->role >= Z_EROFS_VLE_WORK_PRIMARY_FOLLOWED)
@@ -439,10 +418,17 @@ static int z_erofs_vle_work_iter_begin(struct z_erofs_vle_work_builder *builder,
struct erofs_map_blocks *map,
z_erofs_vle_owned_workgrp_t *owned_head)
{
- const unsigned clusterpages = erofs_clusterpages(EROFS_SB(sb));
- const erofs_blk_t index = erofs_blknr(map->m_pa);
- const unsigned pageofs = map->m_la & ~PAGE_MASK;
+ const unsigned int clusterpages = erofs_clusterpages(EROFS_SB(sb));
struct z_erofs_vle_workgroup *grp;
+ const struct z_erofs_vle_work_finder finder = {
+ .sb = sb,
+ .idx = erofs_blknr(map->m_pa),
+ .pageofs = map->m_la & ~PAGE_MASK,
+ .grp_ret = &grp,
+ .role = &builder->role,
+ .owned_head = owned_head,
+ .hosted = &builder->hosted
+ };
struct z_erofs_vle_work *work;
DBG_BUGON(builder->work != NULL);
@@ -454,16 +440,19 @@ static int z_erofs_vle_work_iter_begin(struct z_erofs_vle_work_builder *builder,
DBG_BUGON(erofs_blkoff(map->m_pa));
repeat:
- work = z_erofs_vle_work_lookup(sb, index,
- pageofs, &grp, &builder->role, owned_head, &builder->hosted);
+ work = z_erofs_vle_work_lookup(&finder);
if (work != NULL) {
- __update_workgrp_llen(grp, map->m_llen);
+ unsigned int orig_llen;
+
+ /* increase workgroup `llen' if needed */
+ while ((orig_llen = READ_ONCE(grp->llen)) < map->m_llen &&
+ orig_llen != cmpxchg_relaxed(&grp->llen,
+ orig_llen, map->m_llen))
+ cpu_relax();
goto got_it;
}
- work = z_erofs_vle_work_register(sb, &grp, map, index, pageofs,
- &builder->role, owned_head, &builder->hosted);
-
+ work = z_erofs_vle_work_register(&finder, map);
if (unlikely(work == ERR_PTR(-EAGAIN)))
goto repeat;
@@ -605,8 +594,10 @@ static int z_erofs_do_read_page(struct z_erofs_vle_frontend *fe,
#endif
enum z_erofs_page_type page_type;
- unsigned cur, end, spiltted, index;
- int err;
+ unsigned int cur, end, spiltted, index;
+ int err = 0;
+
+ trace_erofs_readpage(page, false);
/* register locked file pages as online pages in pack */
z_erofs_onlinepage_init(page);
@@ -624,7 +615,7 @@ repeat:
/* go ahead the next map_blocks */
debugln("%s: [out-of-range] pos %llu", __func__, offset + cur);
- if (!z_erofs_vle_work_iter_end(builder))
+ if (z_erofs_vle_work_iter_end(builder))
fe->initial = false;
map->m_la = offset + cur;
@@ -633,12 +624,11 @@ repeat:
if (unlikely(err))
goto err_out;
- /* deal with hole (FIXME! broken now) */
if (unlikely(!(map->m_flags & EROFS_MAP_MAPPED)))
goto hitted;
DBG_BUGON(map->m_plen != 1 << sbi->clusterbits);
- BUG_ON(erofs_blkoff(map->m_pa));
+ DBG_BUGON(erofs_blkoff(map->m_pa));
err = z_erofs_vle_work_iter_begin(builder, sb, map, &fe->owned_head);
if (unlikely(err))
@@ -662,7 +652,7 @@ repeat:
tight &= builder_is_followed(builder);
work = builder->work;
hitted:
- cur = end - min_t(unsigned, offset + end - map->m_la, end);
+ cur = end - min_t(unsigned int, offset + end - map->m_la, end);
if (unlikely(!(map->m_flags & EROFS_MAP_MAPPED))) {
zero_user_segment(page, cur, end);
goto next_part;
@@ -683,7 +673,7 @@ retry:
err = z_erofs_vle_work_add_page(builder,
newpage, Z_EROFS_PAGE_TYPE_EXCLUSIVE);
- if (!err)
+ if (likely(!err))
goto retry;
}
@@ -694,9 +684,10 @@ retry:
/* FIXME! avoid the last relundant fixup & endio */
z_erofs_onlinepage_fixup(page, index, true);
- ++spiltted;
- /* also update nr_pages and increase queued_pages */
+ /* bump up the number of spiltted parts of a page */
+ ++spiltted;
+ /* also update nr_pages */
work->nr_pages = max_t(pgoff_t, work->nr_pages, index + 1);
next_part:
/* can be used for verification */
@@ -706,16 +697,18 @@ next_part:
if (end > 0)
goto repeat;
+out:
/* FIXME! avoid the last relundant fixup & endio */
z_erofs_onlinepage_endio(page);
debugln("%s, finish page: %pK spiltted: %u map->m_llen %llu",
__func__, page, spiltted, map->m_llen);
- return 0;
+ return err;
+ /* if some error occurred while processing this page */
err_out:
- /* TODO: the missing error handing cases */
- return err;
+ SetPageError(page);
+ goto out;
}
static void z_erofs_vle_unzip_kickoff(void *ptr, int bios)
@@ -736,7 +729,7 @@ static void z_erofs_vle_unzip_kickoff(void *ptr, int bios)
static inline void z_erofs_vle_read_endio(struct bio *bio)
{
const blk_status_t err = bio->bi_status;
- unsigned i;
+ unsigned int i;
struct bio_vec *bvec;
#ifdef EROFS_FS_HAS_MANAGED_CACHE
struct address_space *mngda = NULL;
@@ -788,16 +781,14 @@ static int z_erofs_vle_unzip(struct super_block *sb,
#ifdef EROFS_FS_HAS_MANAGED_CACHE
struct address_space *const mngda = sbi->managed_cache->i_mapping;
#endif
- const unsigned clusterpages = erofs_clusterpages(sbi);
+ const unsigned int clusterpages = erofs_clusterpages(sbi);
struct z_erofs_pagevec_ctor ctor;
- unsigned nr_pages;
-#ifndef CONFIG_EROFS_FS_ZIP_MULTIREF
- unsigned sparsemem_pages = 0;
-#endif
+ unsigned int nr_pages;
+ unsigned int sparsemem_pages = 0;
struct page *pages_onstack[Z_EROFS_VLE_VMAP_ONSTACK_PAGES];
struct page **pages, **compressed_pages, *page;
- unsigned i, llen;
+ unsigned int i, llen;
enum z_erofs_page_type page_type;
bool overlapped;
@@ -806,11 +797,7 @@ static int z_erofs_vle_unzip(struct super_block *sb,
int err;
might_sleep();
-#ifndef CONFIG_EROFS_FS_ZIP_MULTIREF
work = z_erofs_vle_grab_primary_work(grp);
-#else
- BUG();
-#endif
BUG_ON(!READ_ONCE(work->nr_pages));
mutex_lock(&work->lock);
@@ -844,7 +831,7 @@ repeat:
Z_EROFS_VLE_INLINE_PAGEVECS, work->pagevec, 0);
for (i = 0; i < work->vcnt; ++i) {
- unsigned pagenr;
+ unsigned int pagenr;
page = z_erofs_pagevec_ctor_dequeue(&ctor, &page_type);
@@ -861,13 +848,11 @@ repeat:
pagenr = z_erofs_onlinepage_index(page);
BUG_ON(pagenr >= nr_pages);
-
-#ifndef CONFIG_EROFS_FS_ZIP_MULTIREF
BUG_ON(pages[pagenr] != NULL);
- ++sparsemem_pages;
-#endif
+
pages[pagenr] = page;
}
+ sparsemem_pages = i;
z_erofs_pagevec_ctor_exit(&ctor, true);
@@ -875,7 +860,7 @@ repeat:
compressed_pages = grp->compressed_pages;
for (i = 0; i < clusterpages; ++i) {
- unsigned pagenr;
+ unsigned int pagenr;
page = compressed_pages[i];
@@ -897,10 +882,8 @@ repeat:
pagenr = z_erofs_onlinepage_index(page);
BUG_ON(pagenr >= nr_pages);
-#ifndef CONFIG_EROFS_FS_ZIP_MULTIREF
BUG_ON(pages[pagenr] != NULL);
++sparsemem_pages;
-#endif
pages[pagenr] = page;
overlapped = true;
@@ -926,12 +909,10 @@ repeat:
if (err != -ENOTSUPP)
goto out_percpu;
-#ifndef CONFIG_EROFS_FS_ZIP_MULTIREF
if (sparsemem_pages >= nr_pages) {
BUG_ON(sparsemem_pages > nr_pages);
goto skip_allocpage;
}
-#endif
for (i = 0; i < nr_pages; ++i) {
if (pages[i] != NULL)
@@ -940,9 +921,7 @@ repeat:
pages[i] = __stagingpage_alloc(page_pool, GFP_NOFS);
}
-#ifndef CONFIG_EROFS_FS_ZIP_MULTIREF
skip_allocpage:
-#endif
vout = erofs_vmap(pages, nr_pages);
err = z_erofs_vle_unzip_vmap(compressed_pages,
@@ -1100,7 +1079,7 @@ static bool z_erofs_vle_submit_all(struct super_block *sb,
bool force_fg)
{
struct erofs_sb_info *const sbi = EROFS_SB(sb);
- const unsigned clusterpages = erofs_clusterpages(sbi);
+ const unsigned int clusterpages = erofs_clusterpages(sbi);
const gfp_t gfp = GFP_NOFS;
#ifdef EROFS_FS_HAS_MANAGED_CACHE
struct address_space *const mngda = sbi->managed_cache->i_mapping;
@@ -1112,7 +1091,7 @@ static bool z_erofs_vle_submit_all(struct super_block *sb,
/* since bio will be NULL, no need to initialize last_index */
pgoff_t uninitialized_var(last_index);
bool force_submit = false;
- unsigned nr_bios;
+ unsigned int nr_bios;
if (unlikely(owned_head == Z_EROFS_VLE_WORKGRP_TAIL))
return false;
@@ -1144,7 +1123,7 @@ static bool z_erofs_vle_submit_all(struct super_block *sb,
struct z_erofs_vle_workgroup *grp;
struct page **compressed_pages, *oldpage, *page;
pgoff_t first_index;
- unsigned i = 0;
+ unsigned int i = 0;
#ifdef EROFS_FS_HAS_MANAGED_CACHE
unsigned int noio = 0;
bool cachemngd;
@@ -1213,8 +1192,8 @@ submit_bio_retry:
}
if (bio == NULL) {
- bio = prepare_bio(sb, first_index + i,
- BIO_MAX_PAGES, z_erofs_vle_read_endio);
+ bio = erofs_grab_bio(sb, first_index + i,
+ BIO_MAX_PAGES, z_erofs_vle_read_endio, true);
bio->bi_private = tagptr_cast_ptr(bi_private);
++nr_bios;
@@ -1309,7 +1288,7 @@ static int z_erofs_vle_normalaccess_readpage(struct file *file,
LIST_HEAD(pagepool);
#if (EROFS_FS_ZIP_CACHE_LVL >= 2)
- f.cachedzone_la = page->index << PAGE_SHIFT;
+ f.cachedzone_la = (erofs_off_t)page->index << PAGE_SHIFT;
#endif
err = z_erofs_do_read_page(&f, page, &pagepool);
(void)z_erofs_vle_work_iter_end(&f.builder);
@@ -1329,20 +1308,25 @@ out:
return 0;
}
-static inline int __z_erofs_vle_normalaccess_readpages(
- struct file *filp,
- struct address_space *mapping,
- struct list_head *pages, unsigned nr_pages, bool sync)
+static int z_erofs_vle_normalaccess_readpages(struct file *filp,
+ struct address_space *mapping,
+ struct list_head *pages,
+ unsigned int nr_pages)
{
struct inode *const inode = mapping->host;
+ struct erofs_sb_info *const sbi = EROFS_I_SB(inode);
+ const bool sync = __should_decompress_synchronously(sbi, nr_pages);
struct z_erofs_vle_frontend f = VLE_FRONTEND_INIT(inode);
gfp_t gfp = mapping_gfp_constraint(mapping, GFP_KERNEL);
struct page *head = NULL;
LIST_HEAD(pagepool);
+ trace_erofs_readpages(mapping->host, lru_to_page(pages),
+ nr_pages, false);
+
#if (EROFS_FS_ZIP_CACHE_LVL >= 2)
- f.cachedzone_la = lru_to_page(pages)->index << PAGE_SHIFT;
+ f.cachedzone_la = (erofs_off_t)lru_to_page(pages)->index << PAGE_SHIFT;
#endif
for (; nr_pages; --nr_pages) {
struct page *page = lru_to_page(pages);
@@ -1390,56 +1374,45 @@ static inline int __z_erofs_vle_normalaccess_readpages(
return 0;
}
-static int z_erofs_vle_normalaccess_readpages(
- struct file *filp,
- struct address_space *mapping,
- struct list_head *pages, unsigned nr_pages)
-{
- return __z_erofs_vle_normalaccess_readpages(filp,
- mapping, pages, nr_pages,
- nr_pages < 4 /* sync */);
-}
-
const struct address_space_operations z_erofs_vle_normalaccess_aops = {
.readpage = z_erofs_vle_normalaccess_readpage,
.readpages = z_erofs_vle_normalaccess_readpages,
};
+/*
+ * Variable-sized Logical Extent (Fixed Physical Cluster) Compression Mode
+ * ---
+ * VLE compression mode attempts to compress a number of logical data into
+ * a physical cluster with a fixed size.
+ * VLE compression mode uses "struct z_erofs_vle_decompressed_index".
+ */
#define __vle_cluster_advise(x, bit, bits) \
((le16_to_cpu(x) >> (bit)) & ((1 << (bits)) - 1))
#define __vle_cluster_type(advise) __vle_cluster_advise(advise, \
Z_EROFS_VLE_DI_CLUSTER_TYPE_BIT, Z_EROFS_VLE_DI_CLUSTER_TYPE_BITS)
-enum {
- Z_EROFS_VLE_CLUSTER_TYPE_PLAIN,
- Z_EROFS_VLE_CLUSTER_TYPE_HEAD,
- Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD,
- Z_EROFS_VLE_CLUSTER_TYPE_RESERVED,
- Z_EROFS_VLE_CLUSTER_TYPE_MAX
-};
-
#define vle_cluster_type(di) \
__vle_cluster_type((di)->di_advise)
-static inline unsigned
-vle_compressed_index_clusterofs(unsigned clustersize,
- struct z_erofs_vle_decompressed_index *di)
+static int
+vle_decompressed_index_clusterofs(unsigned int *clusterofs,
+ unsigned int clustersize,
+ struct z_erofs_vle_decompressed_index *di)
{
- debugln("%s, vle=%pK, advise=%x (type %u), clusterofs=%x blkaddr=%x",
- __func__, di, di->di_advise, vle_cluster_type(di),
- di->di_clusterofs, di->di_u.blkaddr);
-
switch (vle_cluster_type(di)) {
case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD:
+ *clusterofs = clustersize;
break;
case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN:
case Z_EROFS_VLE_CLUSTER_TYPE_HEAD:
- return di->di_clusterofs;
+ *clusterofs = le16_to_cpu(di->di_clusterofs);
+ break;
default:
- BUG_ON(1);
+ DBG_BUGON(1);
+ return -EIO;
}
- return clustersize;
+ return 0;
}
static inline erofs_blk_t
@@ -1448,7 +1421,7 @@ vle_extent_blkaddr(struct inode *inode, pgoff_t index)
struct erofs_sb_info *sbi = EROFS_I_SB(inode);
struct erofs_vnode *vi = EROFS_V(inode);
- unsigned ofs = Z_EROFS_VLE_EXTENT_ALIGN(vi->inode_isize +
+ unsigned int ofs = Z_EROFS_VLE_EXTENT_ALIGN(vi->inode_isize +
vi->xattr_isize) + sizeof(struct erofs_extent_header) +
index * sizeof(struct z_erofs_vle_decompressed_index);
@@ -1461,95 +1434,117 @@ vle_extent_blkoff(struct inode *inode, pgoff_t index)
struct erofs_sb_info *sbi = EROFS_I_SB(inode);
struct erofs_vnode *vi = EROFS_V(inode);
- unsigned ofs = Z_EROFS_VLE_EXTENT_ALIGN(vi->inode_isize +
+ unsigned int ofs = Z_EROFS_VLE_EXTENT_ALIGN(vi->inode_isize +
vi->xattr_isize) + sizeof(struct erofs_extent_header) +
index * sizeof(struct z_erofs_vle_decompressed_index);
return erofs_blkoff(iloc(sbi, vi->nid) + ofs);
}
-/*
- * Variable-sized Logical Extent (Fixed Physical Cluster) Compression Mode
- * ---
- * VLE compression mode attempts to compress a number of logical data into
- * a physical cluster with a fixed size.
- * VLE compression mode uses "struct z_erofs_vle_decompressed_index".
- */
-static erofs_off_t vle_get_logical_extent_head(
- struct inode *inode,
- struct page **page_iter,
- void **kaddr_iter,
- unsigned lcn, /* logical cluster number */
- erofs_blk_t *pcn,
- unsigned *flags)
+struct vle_map_blocks_iter_ctx {
+ struct inode *inode;
+ struct super_block *sb;
+ unsigned int clusterbits;
+
+ struct page **mpage_ret;
+ void **kaddr_ret;
+};
+
+static int
+vle_get_logical_extent_head(const struct vle_map_blocks_iter_ctx *ctx,
+ unsigned int lcn, /* logical cluster number */
+ unsigned long long *ofs,
+ erofs_blk_t *pblk,
+ unsigned int *flags)
{
- /* for extent meta */
- struct page *page = *page_iter;
- erofs_blk_t blkaddr = vle_extent_blkaddr(inode, lcn);
+ const unsigned int clustersize = 1 << ctx->clusterbits;
+ const erofs_blk_t mblk = vle_extent_blkaddr(ctx->inode, lcn);
+ struct page *mpage = *ctx->mpage_ret; /* extent metapage */
+
struct z_erofs_vle_decompressed_index *di;
- unsigned long long ofs;
- const unsigned int clusterbits = EROFS_SB(inode->i_sb)->clusterbits;
- const unsigned int clustersize = 1 << clusterbits;
+ unsigned int cluster_type, delta0;
- if (page->index != blkaddr) {
- kunmap_atomic(*kaddr_iter);
- unlock_page(page);
- put_page(page);
+ if (mpage->index != mblk) {
+ kunmap_atomic(*ctx->kaddr_ret);
+ unlock_page(mpage);
+ put_page(mpage);
- *page_iter = page = erofs_get_meta_page(inode->i_sb,
- blkaddr, false);
- *kaddr_iter = kmap_atomic(page);
+ mpage = erofs_get_meta_page(ctx->sb, mblk, false);
+ if (IS_ERR(mpage)) {
+ *ctx->mpage_ret = NULL;
+ return PTR_ERR(mpage);
+ }
+ *ctx->mpage_ret = mpage;
+ *ctx->kaddr_ret = kmap_atomic(mpage);
}
- di = *kaddr_iter + vle_extent_blkoff(inode, lcn);
- switch (vle_cluster_type(di)) {
- case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD:
- BUG_ON(!di->di_u.delta[0]);
- BUG_ON(lcn < di->di_u.delta[0]);
+ di = *ctx->kaddr_ret + vle_extent_blkoff(ctx->inode, lcn);
- ofs = vle_get_logical_extent_head(inode,
- page_iter, kaddr_iter,
- lcn - di->di_u.delta[0], pcn, flags);
- break;
+ cluster_type = vle_cluster_type(di);
+ switch (cluster_type) {
+ case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD:
+ delta0 = le16_to_cpu(di->di_u.delta[0]);
+ if (unlikely(!delta0 || delta0 > lcn)) {
+ errln("invalid NONHEAD dl0 %u at lcn %u of nid %llu",
+ delta0, lcn, EROFS_V(ctx->inode)->nid);
+ DBG_BUGON(1);
+ return -EIO;
+ }
+ return vle_get_logical_extent_head(ctx,
+ lcn - delta0, ofs, pblk, flags);
case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN:
*flags ^= EROFS_MAP_ZIPPED;
+ /* fallthrough */
case Z_EROFS_VLE_CLUSTER_TYPE_HEAD:
/* clustersize should be a power of two */
- ofs = ((unsigned long long)lcn << clusterbits) +
+ *ofs = ((u64)lcn << ctx->clusterbits) +
(le16_to_cpu(di->di_clusterofs) & (clustersize - 1));
- *pcn = le32_to_cpu(di->di_u.blkaddr);
+ *pblk = le32_to_cpu(di->di_u.blkaddr);
break;
default:
- BUG_ON(1);
+ errln("unknown cluster type %u at lcn %u of nid %llu",
+ cluster_type, lcn, EROFS_V(ctx->inode)->nid);
+ DBG_BUGON(1);
+ return -EIO;
}
- return ofs;
+ return 0;
}
int z_erofs_map_blocks_iter(struct inode *inode,
struct erofs_map_blocks *map,
struct page **mpage_ret, int flags)
{
+ void *kaddr;
+ const struct vle_map_blocks_iter_ctx ctx = {
+ .inode = inode,
+ .sb = inode->i_sb,
+ .clusterbits = EROFS_I_SB(inode)->clusterbits,
+ .mpage_ret = mpage_ret,
+ .kaddr_ret = &kaddr
+ };
+ const unsigned int clustersize = 1 << ctx.clusterbits;
+ /* if both m_(l,p)len are 0, regularize l_lblk, l_lofs, etc... */
+ const bool initial = !map->m_llen;
+
/* logicial extent (start, end) offset */
unsigned long long ofs, end;
- struct z_erofs_vle_decompressed_index *di;
- erofs_blk_t e_blkaddr, pcn;
- unsigned lcn, logical_cluster_ofs, cluster_type;
+ unsigned int lcn;
u32 ofs_rem;
+
+ /* initialize `pblk' to keep gcc from printing foolish warnings */
+ erofs_blk_t mblk, pblk = 0;
struct page *mpage = *mpage_ret;
- void *kaddr;
- bool initial;
- const unsigned int clusterbits = EROFS_SB(inode->i_sb)->clusterbits;
- const unsigned int clustersize = 1 << clusterbits;
+ struct z_erofs_vle_decompressed_index *di;
+ unsigned int cluster_type, logical_cluster_ofs;
int err = 0;
- /* if both m_(l,p)len are 0, regularize l_lblk, l_lofs, etc... */
- initial = !map->m_llen;
+ trace_z_erofs_map_blocks_iter_enter(inode, map, flags);
/* when trying to read beyond EOF, leave it unmapped */
if (unlikely(map->m_la >= inode->i_size)) {
- BUG_ON(!initial);
+ DBG_BUGON(!initial);
map->m_llen = map->m_la + 1 - inode->i_size;
- map->m_la = inode->i_size - 1;
+ map->m_la = inode->i_size;
map->m_flags = 0;
goto out;
}
@@ -1560,16 +1555,20 @@ int z_erofs_map_blocks_iter(struct inode *inode,
ofs = map->m_la + map->m_llen;
/* clustersize should be power of two */
- lcn = ofs >> clusterbits;
+ lcn = ofs >> ctx.clusterbits;
ofs_rem = ofs & (clustersize - 1);
- e_blkaddr = vle_extent_blkaddr(inode, lcn);
+ mblk = vle_extent_blkaddr(inode, lcn);
- if (mpage == NULL || mpage->index != e_blkaddr) {
+ if (!mpage || mpage->index != mblk) {
if (mpage != NULL)
put_page(mpage);
- mpage = erofs_get_meta_page(inode->i_sb, e_blkaddr, false);
+ mpage = erofs_get_meta_page(ctx.sb, mblk, false);
+ if (IS_ERR(mpage)) {
+ err = PTR_ERR(mpage);
+ goto out;
+ }
*mpage_ret = mpage;
} else {
lock_page(mpage);
@@ -1579,10 +1578,14 @@ int z_erofs_map_blocks_iter(struct inode *inode,
kaddr = kmap_atomic(mpage);
di = kaddr + vle_extent_blkoff(inode, lcn);
- debugln("%s, lcn %u e_blkaddr %u e_blkoff %u", __func__, lcn,
- e_blkaddr, vle_extent_blkoff(inode, lcn));
+ debugln("%s, lcn %u mblk %u e_blkoff %u", __func__, lcn,
+ mblk, vle_extent_blkoff(inode, lcn));
+
+ err = vle_decompressed_index_clusterofs(&logical_cluster_ofs,
+ clustersize, di);
+ if (unlikely(err))
+ goto unmap_out;
- logical_cluster_ofs = vle_compressed_index_clusterofs(clustersize, di);
if (!initial) {
/* [walking mode] 'map' has been already initialized */
map->m_llen += logical_cluster_ofs;
@@ -1592,7 +1595,7 @@ int z_erofs_map_blocks_iter(struct inode *inode,
/* by default, compressed */
map->m_flags |= EROFS_MAP_ZIPPED;
- end = (u64)(lcn + 1) * clustersize;
+ end = ((u64)lcn + 1) * clustersize;
cluster_type = vle_cluster_type(di);
@@ -1603,13 +1606,13 @@ int z_erofs_map_blocks_iter(struct inode *inode,
/* fallthrough */
case Z_EROFS_VLE_CLUSTER_TYPE_HEAD:
if (ofs_rem == logical_cluster_ofs) {
- pcn = le32_to_cpu(di->di_u.blkaddr);
+ pblk = le32_to_cpu(di->di_u.blkaddr);
goto exact_hitted;
}
if (ofs_rem > logical_cluster_ofs) {
- ofs = lcn * clustersize | logical_cluster_ofs;
- pcn = le32_to_cpu(di->di_u.blkaddr);
+ ofs = (u64)lcn * clustersize | logical_cluster_ofs;
+ pblk = le32_to_cpu(di->di_u.blkaddr);
break;
}
@@ -1620,13 +1623,19 @@ int z_erofs_map_blocks_iter(struct inode *inode,
err = -EIO;
goto unmap_out;
}
- end = (lcn-- * clustersize) | logical_cluster_ofs;
+ end = ((u64)lcn-- * clustersize) | logical_cluster_ofs;
/* fallthrough */
case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD:
/* get the correspoinding first chunk */
- ofs = vle_get_logical_extent_head(inode, mpage_ret,
- &kaddr, lcn, &pcn, &map->m_flags);
+ err = vle_get_logical_extent_head(&ctx, lcn, &ofs,
+ &pblk, &map->m_flags);
mpage = *mpage_ret;
+
+ if (unlikely(err)) {
+ if (mpage)
+ goto unmap_out;
+ goto out;
+ }
break;
default:
errln("unknown cluster type %u at offset %llu of nid %llu",
@@ -1639,7 +1648,7 @@ int z_erofs_map_blocks_iter(struct inode *inode,
exact_hitted:
map->m_llen = end - ofs;
map->m_plen = clustersize;
- map->m_pa = blknr_to_addr(pcn);
+ map->m_pa = blknr_to_addr(pblk);
map->m_flags |= EROFS_MAP_MAPPED;
unmap_out:
kunmap_atomic(kaddr);
@@ -1649,8 +1658,10 @@ out:
__func__, map->m_la, map->m_pa,
map->m_llen, map->m_plen, map->m_flags);
+ trace_z_erofs_map_blocks_iter_exit(inode, map, flags, err);
+
/* aggressively BUG_ON iff CONFIG_EROFS_FS_DEBUG is on */
- DBG_BUGON(err < 0);
+ DBG_BUGON(err < 0 && err != -ENOMEM);
return err;
}
diff --git a/drivers/staging/erofs/unzip_vle.h b/drivers/staging/erofs/unzip_vle.h
index 393998500865..3316bc36965d 100644
--- a/drivers/staging/erofs/unzip_vle.h
+++ b/drivers/staging/erofs/unzip_vle.h
@@ -47,13 +47,6 @@ static inline bool z_erofs_gather_if_stagingpage(struct list_head *page_pool,
#define Z_EROFS_VLE_INLINE_PAGEVECS 3
struct z_erofs_vle_work {
- /* struct z_erofs_vle_work *left, *right; */
-
-#ifdef CONFIG_EROFS_FS_ZIP_MULTIREF
- struct list_head list;
-
- atomic_t refcount;
-#endif
struct mutex lock;
/* I: decompression offset in page */
@@ -107,10 +100,8 @@ static inline void z_erofs_vle_set_workgrp_fmt(
grp->flags = fmt | (grp->flags & ~Z_EROFS_VLE_WORKGRP_FMT_MASK);
}
-#ifdef CONFIG_EROFS_FS_ZIP_MULTIREF
-#error multiref decompression is unimplemented yet
-#else
+/* definitions if multiref is disabled */
#define z_erofs_vle_grab_primary_work(grp) (&(grp)->work)
#define z_erofs_vle_grab_work(grp, pageofs) (&(grp)->work)
#define z_erofs_vle_work_workgroup(wrk, primary) \
@@ -118,7 +109,6 @@ static inline void z_erofs_vle_set_workgrp_fmt(
struct z_erofs_vle_workgroup, work) : \
({ BUG(); (void *)NULL; }))
-#endif
#define Z_EROFS_WORKGROUP_SIZE sizeof(struct z_erofs_vle_workgroup)
diff --git a/drivers/staging/erofs/unzip_vle_lz4.c b/drivers/staging/erofs/unzip_vle_lz4.c
index f5b665f15be5..1a428658cbea 100644
--- a/drivers/staging/erofs/unzip_vle_lz4.c
+++ b/drivers/staging/erofs/unzip_vle_lz4.c
@@ -23,14 +23,14 @@ static struct {
} erofs_pcpubuf[NR_CPUS];
int z_erofs_vle_plain_copy(struct page **compressed_pages,
- unsigned clusterpages,
+ unsigned int clusterpages,
struct page **pages,
- unsigned nr_pages,
+ unsigned int nr_pages,
unsigned short pageofs)
{
- unsigned i, j;
+ unsigned int i, j;
void *src = NULL;
- const unsigned righthalf = PAGE_SIZE - pageofs;
+ const unsigned int righthalf = PAGE_SIZE - pageofs;
char *percpu_data;
bool mirrored[Z_EROFS_CLUSTER_MAX_PAGES] = { 0 };
@@ -42,8 +42,8 @@ int z_erofs_vle_plain_copy(struct page **compressed_pages,
struct page *page = pages[i];
void *dst;
- if (page == NULL) {
- if (src != NULL) {
+ if (!page) {
+ if (src) {
if (!mirrored[j])
kunmap_atomic(src);
src = NULL;
@@ -64,14 +64,14 @@ int z_erofs_vle_plain_copy(struct page **compressed_pages,
}
if (i) {
- if (src == NULL)
- src = mirrored[i-1] ?
- percpu_data + (i-1) * PAGE_SIZE :
- kmap_atomic(compressed_pages[i-1]);
+ if (!src)
+ src = mirrored[i - 1] ?
+ percpu_data + (i - 1) * PAGE_SIZE :
+ kmap_atomic(compressed_pages[i - 1]);
memcpy(dst, src + righthalf, pageofs);
- if (!mirrored[i-1])
+ if (!mirrored[i - 1])
kunmap_atomic(src);
if (unlikely(i >= clusterpages)) {
@@ -80,9 +80,9 @@ int z_erofs_vle_plain_copy(struct page **compressed_pages,
}
}
- if (!righthalf)
+ if (!righthalf) {
src = NULL;
- else {
+ } else {
src = mirrored[i] ? percpu_data + i * PAGE_SIZE :
kmap_atomic(compressed_pages[i]);
@@ -92,7 +92,7 @@ int z_erofs_vle_plain_copy(struct page **compressed_pages,
kunmap_atomic(dst);
}
- if (src != NULL && !mirrored[j])
+ if (src && !mirrored[j])
kunmap_atomic(src);
preempt_enable();
@@ -102,14 +102,14 @@ int z_erofs_vle_plain_copy(struct page **compressed_pages,
extern int z_erofs_unzip_lz4(void *in, void *out, size_t inlen, size_t outlen);
int z_erofs_vle_unzip_fast_percpu(struct page **compressed_pages,
- unsigned clusterpages,
+ unsigned int clusterpages,
struct page **pages,
- unsigned outlen,
+ unsigned int outlen,
unsigned short pageofs,
void (*endio)(struct page *))
{
void *vin, *vout;
- unsigned nr_pages, i, j;
+ unsigned int nr_pages, i, j;
int ret;
if (outlen + pageofs > EROFS_PERCPU_NR_PAGES * PAGE_SIZE)
@@ -126,7 +126,7 @@ int z_erofs_vle_unzip_fast_percpu(struct page **compressed_pages,
vout = erofs_pcpubuf[smp_processor_id()].data;
ret = z_erofs_unzip_lz4(vin, vout + pageofs,
- clusterpages * PAGE_SIZE, outlen);
+ clusterpages * PAGE_SIZE, outlen);
if (ret >= 0) {
outlen = ret;
@@ -134,14 +134,15 @@ int z_erofs_vle_unzip_fast_percpu(struct page **compressed_pages,
}
for (i = 0; i < nr_pages; ++i) {
- j = min((unsigned)PAGE_SIZE - pageofs, outlen);
+ j = min((unsigned int)PAGE_SIZE - pageofs, outlen);
- if (pages[i] != NULL) {
- if (ret < 0)
+ if (pages[i]) {
+ if (ret < 0) {
SetPageError(pages[i]);
- else if (clusterpages == 1 && pages[i] == compressed_pages[0])
+ } else if (clusterpages == 1 &&
+ pages[i] == compressed_pages[0]) {
memcpy(vin + pageofs, vout + pageofs, j);
- else {
+ } else {
void *dst = kmap_atomic(pages[i]);
memcpy(dst + pageofs, vout + pageofs, j);
@@ -164,14 +165,14 @@ int z_erofs_vle_unzip_fast_percpu(struct page **compressed_pages,
}
int z_erofs_vle_unzip_vmap(struct page **compressed_pages,
- unsigned clusterpages,
+ unsigned int clusterpages,
void *vout,
- unsigned llen,
+ unsigned int llen,
unsigned short pageofs,
bool overlapped)
{
void *vin;
- unsigned i;
+ unsigned int i;
int ret;
if (overlapped) {
@@ -181,29 +182,27 @@ int z_erofs_vle_unzip_vmap(struct page **compressed_pages,
for (i = 0; i < clusterpages; ++i) {
void *t = kmap_atomic(compressed_pages[i]);
- memcpy(vin + PAGE_SIZE *i, t, PAGE_SIZE);
+ memcpy(vin + PAGE_SIZE * i, t, PAGE_SIZE);
kunmap_atomic(t);
}
- } else if (clusterpages == 1)
+ } else if (clusterpages == 1) {
vin = kmap_atomic(compressed_pages[0]);
- else {
+ } else {
vin = erofs_vmap(compressed_pages, clusterpages);
}
ret = z_erofs_unzip_lz4(vin, vout + pageofs,
- clusterpages * PAGE_SIZE, llen);
+ clusterpages * PAGE_SIZE, llen);
if (ret > 0)
ret = 0;
if (!overlapped) {
if (clusterpages == 1)
kunmap_atomic(vin);
- else {
+ else
erofs_vunmap(vin, clusterpages);
- }
- } else
+ } else {
preempt_enable();
-
+ }
return ret;
}
-
diff --git a/drivers/staging/erofs/utils.c b/drivers/staging/erofs/utils.c
index 595cf90af9bb..ea8a962e5c95 100644
--- a/drivers/staging/erofs/utils.c
+++ b/drivers/staging/erofs/utils.c
@@ -35,7 +35,6 @@ static atomic_long_t erofs_global_shrink_cnt;
#ifdef CONFIG_EROFS_FS_ZIP
-/* radix_tree and the future XArray both don't use tagptr_t yet */
struct erofs_workgroup *erofs_find_workgroup(
struct super_block *sb, pgoff_t index, bool *tag)
{
@@ -47,9 +46,8 @@ repeat:
rcu_read_lock();
grp = radix_tree_lookup(&sbi->workstn_tree, index);
if (grp != NULL) {
- *tag = radix_tree_exceptional_entry(grp);
- grp = (void *)((unsigned long)grp &
- ~RADIX_TREE_EXCEPTIONAL_ENTRY);
+ *tag = xa_pointer_tag(grp);
+ grp = xa_untag_pointer(grp);
if (erofs_workgroup_get(grp, &oldcount)) {
/* prefer to relax rcu read side */
@@ -83,9 +81,7 @@ int erofs_register_workgroup(struct super_block *sb,
sbi = EROFS_SB(sb);
erofs_workstn_lock(sbi);
- if (tag)
- grp = (void *)((unsigned long)grp |
- 1UL << RADIX_TREE_EXCEPTIONAL_SHIFT);
+ grp = xa_tag_pointer(grp, tag);
err = radix_tree_insert(&sbi->workstn_tree,
grp->index, grp);
@@ -120,7 +116,7 @@ unsigned long erofs_shrink_workstation(struct erofs_sb_info *sbi,
{
pgoff_t first_index = 0;
void *batch[PAGEVEC_SIZE];
- unsigned freed = 0;
+ unsigned int freed = 0;
int i, found;
repeat:
@@ -131,9 +127,7 @@ repeat:
for (i = 0; i < found; ++i) {
int cnt;
- struct erofs_workgroup *grp = (void *)
- ((unsigned long)batch[i] &
- ~RADIX_TREE_EXCEPTIONAL_ENTRY);
+ struct erofs_workgroup *grp = xa_untag_pointer(batch[i]);
first_index = grp->index + 1;
@@ -150,8 +144,8 @@ repeat:
#endif
continue;
- if (radix_tree_delete(&sbi->workstn_tree,
- grp->index) != grp) {
+ if (xa_untag_pointer(radix_tree_delete(&sbi->workstn_tree,
+ grp->index)) != grp) {
#ifdef EROFS_FS_HAS_MANAGED_CACHE
skip:
erofs_workgroup_unfreeze(grp, 1);
diff --git a/drivers/staging/erofs/xattr.c b/drivers/staging/erofs/xattr.c
index 0e9cfeccdf99..80dca6a4adbe 100644
--- a/drivers/staging/erofs/xattr.c
+++ b/drivers/staging/erofs/xattr.c
@@ -19,41 +19,53 @@ struct xattr_iter {
void *kaddr;
erofs_blk_t blkaddr;
- unsigned ofs;
+ unsigned int ofs;
};
static inline void xattr_iter_end(struct xattr_iter *it, bool atomic)
{
- /* only init_inode_xattrs use non-atomic once */
+ /* the only user of kunmap() is 'init_inode_xattrs' */
if (unlikely(!atomic))
kunmap(it->page);
else
kunmap_atomic(it->kaddr);
+
unlock_page(it->page);
put_page(it->page);
}
-static void init_inode_xattrs(struct inode *inode)
+static inline void xattr_iter_end_final(struct xattr_iter *it)
+{
+ if (it->page == NULL)
+ return;
+
+ xattr_iter_end(it, true);
+}
+
+static int init_inode_xattrs(struct inode *inode)
{
struct xattr_iter it;
- unsigned i;
+ unsigned int i;
struct erofs_xattr_ibody_header *ih;
+ struct super_block *sb;
struct erofs_sb_info *sbi;
struct erofs_vnode *vi;
bool atomic_map;
if (likely(inode_has_inited_xattr(inode)))
- return;
+ return 0;
vi = EROFS_V(inode);
BUG_ON(!vi->xattr_isize);
- sbi = EROFS_I_SB(inode);
+ sb = inode->i_sb;
+ sbi = EROFS_SB(sb);
it.blkaddr = erofs_blknr(iloc(sbi, vi->nid) + vi->inode_isize);
it.ofs = erofs_blkoff(iloc(sbi, vi->nid) + vi->inode_isize);
it.page = erofs_get_inline_page(inode, it.blkaddr);
- BUG_ON(IS_ERR(it.page));
+ if (IS_ERR(it.page))
+ return PTR_ERR(it.page);
/* read in shared xattr array (non-atomic, see kmalloc below) */
it.kaddr = kmap(it.page);
@@ -62,9 +74,12 @@ static void init_inode_xattrs(struct inode *inode)
ih = (struct erofs_xattr_ibody_header *)(it.kaddr + it.ofs);
vi->xattr_shared_count = ih->h_shared_count;
- vi->xattr_shared_xattrs = (unsigned *)kmalloc_array(
- vi->xattr_shared_count, sizeof(unsigned),
- GFP_KERNEL | __GFP_NOFAIL);
+ vi->xattr_shared_xattrs = kmalloc_array(vi->xattr_shared_count,
+ sizeof(uint), GFP_KERNEL);
+ if (vi->xattr_shared_xattrs == NULL) {
+ xattr_iter_end(&it, atomic_map);
+ return -ENOMEM;
+ }
/* let's skip ibody header */
it.ofs += sizeof(struct erofs_xattr_ibody_header);
@@ -75,9 +90,10 @@ static void init_inode_xattrs(struct inode *inode)
BUG_ON(it.ofs != EROFS_BLKSIZ);
xattr_iter_end(&it, atomic_map);
- it.page = erofs_get_meta_page(inode->i_sb,
+ it.page = erofs_get_meta_page(sb,
++it.blkaddr, S_ISDIR(inode->i_mode));
- BUG_ON(IS_ERR(it.page));
+ if (IS_ERR(it.page))
+ return PTR_ERR(it.page);
it.kaddr = kmap_atomic(it.page);
atomic_map = true;
@@ -90,27 +106,43 @@ static void init_inode_xattrs(struct inode *inode)
xattr_iter_end(&it, atomic_map);
inode_set_inited_xattr(inode);
+ return 0;
}
+/*
+ * the general idea for these return values is
+ * if 0 is returned, go on processing the current xattr;
+ * 1 (> 0) is returned, skip this round to process the next xattr;
+ * -err (< 0) is returned, an error (maybe ENOXATTR) occurred
+ * and need to be handled
+ */
struct xattr_iter_handlers {
int (*entry)(struct xattr_iter *, struct erofs_xattr_entry *);
- int (*name)(struct xattr_iter *, unsigned, char *, unsigned);
- int (*alloc_buffer)(struct xattr_iter *, unsigned);
- void (*value)(struct xattr_iter *, unsigned, char *, unsigned);
+ int (*name)(struct xattr_iter *, unsigned int, char *, unsigned int);
+ int (*alloc_buffer)(struct xattr_iter *, unsigned int);
+ void (*value)(struct xattr_iter *, unsigned int, char *, unsigned int);
};
-static void xattr_iter_fixup(struct xattr_iter *it)
+static inline int xattr_iter_fixup(struct xattr_iter *it)
{
- if (unlikely(it->ofs >= EROFS_BLKSIZ)) {
- xattr_iter_end(it, true);
+ if (it->ofs < EROFS_BLKSIZ)
+ return 0;
+
+ xattr_iter_end(it, true);
+
+ it->blkaddr += erofs_blknr(it->ofs);
- it->blkaddr += erofs_blknr(it->ofs);
- it->page = erofs_get_meta_page(it->sb, it->blkaddr, false);
- BUG_ON(IS_ERR(it->page));
+ it->page = erofs_get_meta_page(it->sb, it->blkaddr, false);
+ if (IS_ERR(it->page)) {
+ int err = PTR_ERR(it->page);
- it->kaddr = kmap_atomic(it->page);
- it->ofs = erofs_blkoff(it->ofs);
+ it->page = NULL;
+ return err;
}
+
+ it->kaddr = kmap_atomic(it->page);
+ it->ofs = erofs_blkoff(it->ofs);
+ return 0;
}
static int inline_xattr_iter_begin(struct xattr_iter *it,
@@ -118,7 +150,7 @@ static int inline_xattr_iter_begin(struct xattr_iter *it,
{
struct erofs_vnode *const vi = EROFS_V(inode);
struct erofs_sb_info *const sbi = EROFS_SB(inode->i_sb);
- unsigned xattr_header_sz, inline_xattr_ofs;
+ unsigned int xattr_header_sz, inline_xattr_ofs;
xattr_header_sz = inlinexattr_header_size(inode);
if (unlikely(xattr_header_sz >= vi->xattr_isize)) {
@@ -132,21 +164,28 @@ static int inline_xattr_iter_begin(struct xattr_iter *it,
it->ofs = erofs_blkoff(iloc(sbi, vi->nid) + inline_xattr_ofs);
it->page = erofs_get_inline_page(inode, it->blkaddr);
- BUG_ON(IS_ERR(it->page));
- it->kaddr = kmap_atomic(it->page);
+ if (IS_ERR(it->page))
+ return PTR_ERR(it->page);
+ it->kaddr = kmap_atomic(it->page);
return vi->xattr_isize - xattr_header_sz;
}
+/*
+ * Regardless of success or failure, `xattr_foreach' will end up with
+ * `ofs' pointing to the next xattr item rather than an arbitrary position.
+ */
static int xattr_foreach(struct xattr_iter *it,
- struct xattr_iter_handlers *op, unsigned *tlimit)
+ const struct xattr_iter_handlers *op, unsigned int *tlimit)
{
struct erofs_xattr_entry entry;
- unsigned value_sz, processed, slice;
+ unsigned int value_sz, processed, slice;
int err;
/* 0. fixup blkaddr, ofs, ipage */
- xattr_iter_fixup(it);
+ err = xattr_iter_fixup(it);
+ if (err)
+ return err;
/*
* 1. read xattr entry to the memory,
@@ -155,7 +194,7 @@ static int xattr_foreach(struct xattr_iter *it,
*/
entry = *(struct erofs_xattr_entry *)(it->kaddr + it->ofs);
if (tlimit != NULL) {
- unsigned entry_sz = EROFS_XATTR_ENTRY_SIZE(&entry);
+ unsigned int entry_sz = EROFS_XATTR_ENTRY_SIZE(&entry);
BUG_ON(*tlimit < entry_sz);
*tlimit -= entry_sz;
@@ -178,12 +217,14 @@ static int xattr_foreach(struct xattr_iter *it,
if (it->ofs >= EROFS_BLKSIZ) {
BUG_ON(it->ofs > EROFS_BLKSIZ);
- xattr_iter_fixup(it);
+ err = xattr_iter_fixup(it);
+ if (err)
+ goto out;
it->ofs = 0;
}
- slice = min_t(unsigned, PAGE_SIZE - it->ofs,
- entry.e_name_len - processed);
+ slice = min_t(unsigned int, PAGE_SIZE - it->ofs,
+ entry.e_name_len - processed);
/* handle name */
err = op->name(it, processed, it->kaddr + it->ofs, slice);
@@ -210,21 +251,24 @@ static int xattr_foreach(struct xattr_iter *it,
while (processed < value_sz) {
if (it->ofs >= EROFS_BLKSIZ) {
BUG_ON(it->ofs > EROFS_BLKSIZ);
- xattr_iter_fixup(it);
+
+ err = xattr_iter_fixup(it);
+ if (err)
+ goto out;
it->ofs = 0;
}
- slice = min_t(unsigned, PAGE_SIZE - it->ofs,
- value_sz - processed);
+ slice = min_t(unsigned int, PAGE_SIZE - it->ofs,
+ value_sz - processed);
op->value(it, processed, it->kaddr + it->ofs, slice);
it->ofs += slice;
processed += slice;
}
out:
- /* we assume that ofs is aligned with 4 bytes */
+ /* xattrs should be 4-byte aligned (on-disk constraint) */
it->ofs = EROFS_XATTR_ALIGN(it->ofs);
- return err;
+ return err < 0 ? err : 0;
}
struct getxattr_iter {
@@ -245,7 +289,7 @@ static int xattr_entrymatch(struct xattr_iter *_it,
}
static int xattr_namematch(struct xattr_iter *_it,
- unsigned processed, char *buf, unsigned len)
+ unsigned int processed, char *buf, unsigned int len)
{
struct getxattr_iter *it = container_of(_it, struct getxattr_iter, it);
@@ -253,7 +297,7 @@ static int xattr_namematch(struct xattr_iter *_it,
}
static int xattr_checkbuffer(struct xattr_iter *_it,
- unsigned value_sz)
+ unsigned int value_sz)
{
struct getxattr_iter *it = container_of(_it, struct getxattr_iter, it);
int err = it->buffer_size < value_sz ? -ERANGE : 0;
@@ -263,14 +307,14 @@ static int xattr_checkbuffer(struct xattr_iter *_it,
}
static void xattr_copyvalue(struct xattr_iter *_it,
- unsigned processed, char *buf, unsigned len)
+ unsigned int processed, char *buf, unsigned int len)
{
struct getxattr_iter *it = container_of(_it, struct getxattr_iter, it);
memcpy(it->buffer + processed, buf, len);
}
-static struct xattr_iter_handlers find_xattr_handlers = {
+static const struct xattr_iter_handlers find_xattr_handlers = {
.entry = xattr_entrymatch,
.name = xattr_namematch,
.alloc_buffer = xattr_checkbuffer,
@@ -280,7 +324,7 @@ static struct xattr_iter_handlers find_xattr_handlers = {
static int inline_getxattr(struct inode *inode, struct getxattr_iter *it)
{
int ret;
- unsigned remaining;
+ unsigned int remaining;
ret = inline_xattr_iter_begin(&it->it, inode);
if (ret < 0)
@@ -289,19 +333,20 @@ static int inline_getxattr(struct inode *inode, struct getxattr_iter *it)
remaining = ret;
while (remaining) {
ret = xattr_foreach(&it->it, &find_xattr_handlers, &remaining);
- if (ret >= 0)
+ if (ret != -ENOATTR)
break;
}
- xattr_iter_end(&it->it, true);
+ xattr_iter_end_final(&it->it);
- return ret < 0 ? ret : it->buffer_size;
+ return ret ? ret : it->buffer_size;
}
static int shared_getxattr(struct inode *inode, struct getxattr_iter *it)
{
struct erofs_vnode *const vi = EROFS_V(inode);
- struct erofs_sb_info *const sbi = EROFS_SB(inode->i_sb);
- unsigned i;
+ struct super_block *const sb = inode->i_sb;
+ struct erofs_sb_info *const sbi = EROFS_SB(sb);
+ unsigned int i;
int ret = -ENOATTR;
for (i = 0; i < vi->xattr_shared_count; ++i) {
@@ -314,21 +359,22 @@ static int shared_getxattr(struct inode *inode, struct getxattr_iter *it)
if (i)
xattr_iter_end(&it->it, true);
- it->it.page = erofs_get_meta_page(inode->i_sb,
- blkaddr, false);
- BUG_ON(IS_ERR(it->it.page));
+ it->it.page = erofs_get_meta_page(sb, blkaddr, false);
+ if (IS_ERR(it->it.page))
+ return PTR_ERR(it->it.page);
+
it->it.kaddr = kmap_atomic(it->it.page);
it->it.blkaddr = blkaddr;
}
ret = xattr_foreach(&it->it, &find_xattr_handlers, NULL);
- if (ret >= 0)
+ if (ret != -ENOATTR)
break;
}
if (vi->xattr_shared_count)
- xattr_iter_end(&it->it, true);
+ xattr_iter_end_final(&it->it);
- return ret < 0 ? ret : it->buffer_size;
+ return ret ? ret : it->buffer_size;
}
static bool erofs_xattr_user_list(struct dentry *dentry)
@@ -351,7 +397,9 @@ int erofs_getxattr(struct inode *inode, int index,
if (unlikely(name == NULL))
return -EINVAL;
- init_inode_xattrs(inode);
+ ret = init_inode_xattrs(inode);
+ if (ret)
+ return ret;
it.index = index;
@@ -446,7 +494,7 @@ static int xattr_entrylist(struct xattr_iter *_it,
{
struct listxattr_iter *it =
container_of(_it, struct listxattr_iter, it);
- unsigned prefix_len;
+ unsigned int prefix_len;
const char *prefix;
const struct xattr_handler *h =
@@ -474,7 +522,7 @@ static int xattr_entrylist(struct xattr_iter *_it,
}
static int xattr_namelist(struct xattr_iter *_it,
- unsigned processed, char *buf, unsigned len)
+ unsigned int processed, char *buf, unsigned int len)
{
struct listxattr_iter *it =
container_of(_it, struct listxattr_iter, it);
@@ -485,7 +533,7 @@ static int xattr_namelist(struct xattr_iter *_it,
}
static int xattr_skipvalue(struct xattr_iter *_it,
- unsigned value_sz)
+ unsigned int value_sz)
{
struct listxattr_iter *it =
container_of(_it, struct listxattr_iter, it);
@@ -494,7 +542,7 @@ static int xattr_skipvalue(struct xattr_iter *_it,
return 1;
}
-static struct xattr_iter_handlers list_xattr_handlers = {
+static const struct xattr_iter_handlers list_xattr_handlers = {
.entry = xattr_entrylist,
.name = xattr_namelist,
.alloc_buffer = xattr_skipvalue,
@@ -504,7 +552,7 @@ static struct xattr_iter_handlers list_xattr_handlers = {
static int inline_listxattr(struct listxattr_iter *it)
{
int ret;
- unsigned remaining;
+ unsigned int remaining;
ret = inline_xattr_iter_begin(&it->it, d_inode(it->dentry));
if (ret < 0)
@@ -513,19 +561,20 @@ static int inline_listxattr(struct listxattr_iter *it)
remaining = ret;
while (remaining) {
ret = xattr_foreach(&it->it, &list_xattr_handlers, &remaining);
- if (ret < 0)
+ if (ret)
break;
}
- xattr_iter_end(&it->it, true);
- return ret < 0 ? ret : it->buffer_ofs;
+ xattr_iter_end_final(&it->it);
+ return ret ? ret : it->buffer_ofs;
}
static int shared_listxattr(struct listxattr_iter *it)
{
struct inode *const inode = d_inode(it->dentry);
struct erofs_vnode *const vi = EROFS_V(inode);
- struct erofs_sb_info *const sbi = EROFS_I_SB(inode);
- unsigned i;
+ struct super_block *const sb = inode->i_sb;
+ struct erofs_sb_info *const sbi = EROFS_SB(sb);
+ unsigned int i;
int ret = 0;
for (i = 0; i < vi->xattr_shared_count; ++i) {
@@ -537,21 +586,22 @@ static int shared_listxattr(struct listxattr_iter *it)
if (i)
xattr_iter_end(&it->it, true);
- it->it.page = erofs_get_meta_page(inode->i_sb,
- blkaddr, false);
- BUG_ON(IS_ERR(it->it.page));
+ it->it.page = erofs_get_meta_page(sb, blkaddr, false);
+ if (IS_ERR(it->it.page))
+ return PTR_ERR(it->it.page);
+
it->it.kaddr = kmap_atomic(it->it.page);
it->it.blkaddr = blkaddr;
}
ret = xattr_foreach(&it->it, &list_xattr_handlers, NULL);
- if (ret < 0)
+ if (ret)
break;
}
if (vi->xattr_shared_count)
- xattr_iter_end(&it->it, true);
+ xattr_iter_end_final(&it->it);
- return ret < 0 ? ret : it->buffer_ofs;
+ return ret ? ret : it->buffer_ofs;
}
ssize_t erofs_listxattr(struct dentry *dentry,
@@ -560,7 +610,9 @@ ssize_t erofs_listxattr(struct dentry *dentry,
int ret;
struct listxattr_iter it;
- init_inode_xattrs(d_inode(dentry));
+ ret = init_inode_xattrs(d_inode(dentry));
+ if (ret)
+ return ret;
it.dentry = dentry;
it.buffer = buffer;
diff --git a/drivers/staging/fbtft/fbtft.h b/drivers/staging/fbtft/fbtft.h
index 798a8fe98e95..ac427baa464a 100644
--- a/drivers/staging/fbtft/fbtft.h
+++ b/drivers/staging/fbtft/fbtft.h
@@ -232,7 +232,7 @@ struct fbtft_par {
bool polarity;
};
-#define NUMARGS(...) (sizeof((int[]){__VA_ARGS__})/sizeof(int))
+#define NUMARGS(...) (sizeof((int[]){__VA_ARGS__}) / sizeof(int))
#define write_reg(par, ...) \
((par)->fbtftops.write_register(par, NUMARGS(__VA_ARGS__), __VA_ARGS__))
@@ -355,39 +355,39 @@ module_exit(fbtft_driver_module_exit);
#define DEBUG_LEVEL_6 (DEBUG_LEVEL_4 | DEBUG_LEVEL_5)
#define DEBUG_LEVEL_7 0xFFFFFFFF
-#define DEBUG_DRIVER_INIT_FUNCTIONS (1<<3)
-#define DEBUG_TIME_FIRST_UPDATE (1<<4)
-#define DEBUG_TIME_EACH_UPDATE (1<<5)
-#define DEBUG_DEFERRED_IO (1<<6)
-#define DEBUG_FBTFT_INIT_FUNCTIONS (1<<7)
+#define DEBUG_DRIVER_INIT_FUNCTIONS BIT(3)
+#define DEBUG_TIME_FIRST_UPDATE BIT(4)
+#define DEBUG_TIME_EACH_UPDATE BIT(5)
+#define DEBUG_DEFERRED_IO BIT(6)
+#define DEBUG_FBTFT_INIT_FUNCTIONS BIT(7)
/* fbops */
-#define DEBUG_FB_READ (1<<8)
-#define DEBUG_FB_WRITE (1<<9)
-#define DEBUG_FB_FILLRECT (1<<10)
-#define DEBUG_FB_COPYAREA (1<<11)
-#define DEBUG_FB_IMAGEBLIT (1<<12)
-#define DEBUG_FB_SETCOLREG (1<<13)
-#define DEBUG_FB_BLANK (1<<14)
+#define DEBUG_FB_READ BIT(8)
+#define DEBUG_FB_WRITE BIT(9)
+#define DEBUG_FB_FILLRECT BIT(10)
+#define DEBUG_FB_COPYAREA BIT(11)
+#define DEBUG_FB_IMAGEBLIT BIT(12)
+#define DEBUG_FB_SETCOLREG BIT(13)
+#define DEBUG_FB_BLANK BIT(14)
-#define DEBUG_SYSFS (1<<16)
+#define DEBUG_SYSFS BIT(16)
/* fbtftops */
-#define DEBUG_BACKLIGHT (1<<17)
-#define DEBUG_READ (1<<18)
-#define DEBUG_WRITE (1<<19)
-#define DEBUG_WRITE_VMEM (1<<20)
-#define DEBUG_WRITE_REGISTER (1<<21)
-#define DEBUG_SET_ADDR_WIN (1<<22)
-#define DEBUG_RESET (1<<23)
-#define DEBUG_MKDIRTY (1<<24)
-#define DEBUG_UPDATE_DISPLAY (1<<25)
-#define DEBUG_INIT_DISPLAY (1<<26)
-#define DEBUG_BLANK (1<<27)
-#define DEBUG_REQUEST_GPIOS (1<<28)
-#define DEBUG_FREE_GPIOS (1<<29)
-#define DEBUG_REQUEST_GPIOS_MATCH (1<<30)
-#define DEBUG_VERIFY_GPIOS (1<<31)
+#define DEBUG_BACKLIGHT BIT(17)
+#define DEBUG_READ BIT(18)
+#define DEBUG_WRITE BIT(19)
+#define DEBUG_WRITE_VMEM BIT(20)
+#define DEBUG_WRITE_REGISTER BIT(21)
+#define DEBUG_SET_ADDR_WIN BIT(22)
+#define DEBUG_RESET BIT(23)
+#define DEBUG_MKDIRTY BIT(24)
+#define DEBUG_UPDATE_DISPLAY BIT(25)
+#define DEBUG_INIT_DISPLAY BIT(26)
+#define DEBUG_BLANK BIT(27)
+#define DEBUG_REQUEST_GPIOS BIT(28)
+#define DEBUG_FREE_GPIOS BIT(29)
+#define DEBUG_REQUEST_GPIOS_MATCH BIT(30)
+#define DEBUG_VERIFY_GPIOS BIT(31)
#define fbtft_init_dbg(dev, format, arg...) \
do { \
diff --git a/drivers/staging/fsl-dpaa2/Kconfig b/drivers/staging/fsl-dpaa2/Kconfig
index a4c4b83ddc9c..991e154c0eca 100644
--- a/drivers/staging/fsl-dpaa2/Kconfig
+++ b/drivers/staging/fsl-dpaa2/Kconfig
@@ -9,14 +9,6 @@ config FSL_DPAA2
Build drivers for Freescale DataPath Acceleration
Architecture (DPAA2) family of SoCs.
-config FSL_DPAA2_ETH
- tristate "Freescale DPAA2 Ethernet"
- depends on FSL_DPAA2 && FSL_MC_DPIO
- depends on NETDEVICES && ETHERNET
- ---help---
- Ethernet driver for Freescale DPAA2 SoCs, using the
- Freescale MC bus driver
-
config FSL_DPAA2_ETHSW
tristate "Freescale DPAA2 Ethernet Switch"
depends on FSL_DPAA2
@@ -24,11 +16,3 @@ config FSL_DPAA2_ETHSW
---help---
Driver for Freescale DPAA2 Ethernet Switch. Select
BRIDGE to have support for bridge tools.
-
-config FSL_DPAA2_PTP_CLOCK
- tristate "Freescale DPAA2 PTP Clock"
- depends on FSL_DPAA2_ETH && POSIX_TIMERS
- select PTP_1588_CLOCK
- help
- This driver adds support for using the DPAA2 1588 timer module
- as a PTP clock.
diff --git a/drivers/staging/fsl-dpaa2/Makefile b/drivers/staging/fsl-dpaa2/Makefile
index 9c7062945758..c92ab98c27d9 100644
--- a/drivers/staging/fsl-dpaa2/Makefile
+++ b/drivers/staging/fsl-dpaa2/Makefile
@@ -2,6 +2,4 @@
# Freescale DataPath Acceleration Architecture Gen2 (DPAA2) drivers
#
-obj-$(CONFIG_FSL_DPAA2_ETH) += ethernet/
obj-$(CONFIG_FSL_DPAA2_ETHSW) += ethsw/
-obj-$(CONFIG_FSL_DPAA2_PTP_CLOCK) += rtc/
diff --git a/drivers/staging/fsl-dpaa2/ethernet/Makefile b/drivers/staging/fsl-dpaa2/ethernet/Makefile
deleted file mode 100644
index 9315ecdba612..000000000000
--- a/drivers/staging/fsl-dpaa2/ethernet/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-#
-# Makefile for the Freescale DPAA2 Ethernet controller
-#
-
-obj-$(CONFIG_FSL_DPAA2_ETH) += fsl-dpaa2-eth.o
-
-fsl-dpaa2-eth-objs := dpaa2-eth.o dpaa2-ethtool.o dpni.o
-
-# Needed by the tracing framework
-CFLAGS_dpaa2-eth.o := -I$(src)
diff --git a/drivers/staging/fsl-dpaa2/ethernet/TODO b/drivers/staging/fsl-dpaa2/ethernet/TODO
deleted file mode 100644
index e400a5e427a5..000000000000
--- a/drivers/staging/fsl-dpaa2/ethernet/TODO
+++ /dev/null
@@ -1,18 +0,0 @@
-* Add a DPAA2 MAC kernel driver in order to allow PHY management; currently
- the DPMAC objects and their link to DPNIs are handled by MC internally
- and all PHYs are seen as fixed-link
-* add more debug support: decide how to expose detailed debug statistics,
- add ingress error queue support
-* MC firmware uprev; the DPAA2 objects used by the Ethernet driver need to
- be kept in sync with binary interface changes in MC
-* refine README file
-* cleanup
-
-NOTE: None of the above is must-have before getting the DPAA2 Ethernet driver
-out of staging. The main requirement for that is to have the drivers it
-depends on, fsl-mc bus and DPIO driver, moved to drivers/bus and drivers/soc
-respectively.
-
- Please send any patches to Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
- ruxandra.radulescu@nxp.com, devel@driverdev.osuosl.org,
- linux-kernel@vger.kernel.org
diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c
deleted file mode 100644
index 8056a95e1265..000000000000
--- a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c
+++ /dev/null
@@ -1,280 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
-/* Copyright 2014-2016 Freescale Semiconductor Inc.
- * Copyright 2016 NXP
- */
-
-#include <linux/net_tstamp.h>
-
-#include "dpni.h" /* DPNI_LINK_OPT_* */
-#include "dpaa2-eth.h"
-
-/* To be kept in sync with DPNI statistics */
-static char dpaa2_ethtool_stats[][ETH_GSTRING_LEN] = {
- "[hw] rx frames",
- "[hw] rx bytes",
- "[hw] rx mcast frames",
- "[hw] rx mcast bytes",
- "[hw] rx bcast frames",
- "[hw] rx bcast bytes",
- "[hw] tx frames",
- "[hw] tx bytes",
- "[hw] tx mcast frames",
- "[hw] tx mcast bytes",
- "[hw] tx bcast frames",
- "[hw] tx bcast bytes",
- "[hw] rx filtered frames",
- "[hw] rx discarded frames",
- "[hw] rx nobuffer discards",
- "[hw] tx discarded frames",
- "[hw] tx confirmed frames",
-};
-
-#define DPAA2_ETH_NUM_STATS ARRAY_SIZE(dpaa2_ethtool_stats)
-
-static char dpaa2_ethtool_extras[][ETH_GSTRING_LEN] = {
- /* per-cpu stats */
- "[drv] tx conf frames",
- "[drv] tx conf bytes",
- "[drv] tx sg frames",
- "[drv] tx sg bytes",
- "[drv] tx realloc frames",
- "[drv] rx sg frames",
- "[drv] rx sg bytes",
- "[drv] enqueue portal busy",
- /* Channel stats */
- "[drv] dequeue portal busy",
- "[drv] channel pull errors",
- "[drv] cdan",
-};
-
-#define DPAA2_ETH_NUM_EXTRA_STATS ARRAY_SIZE(dpaa2_ethtool_extras)
-
-static void dpaa2_eth_get_drvinfo(struct net_device *net_dev,
- struct ethtool_drvinfo *drvinfo)
-{
- struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
-
- strlcpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver));
-
- snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
- "%u.%u", priv->dpni_ver_major, priv->dpni_ver_minor);
-
- strlcpy(drvinfo->bus_info, dev_name(net_dev->dev.parent->parent),
- sizeof(drvinfo->bus_info));
-}
-
-static int
-dpaa2_eth_get_link_ksettings(struct net_device *net_dev,
- struct ethtool_link_ksettings *link_settings)
-{
- struct dpni_link_state state = {0};
- int err = 0;
- struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
-
- err = dpni_get_link_state(priv->mc_io, 0, priv->mc_token, &state);
- if (err) {
- netdev_err(net_dev, "ERROR %d getting link state\n", err);
- goto out;
- }
-
- /* At the moment, we have no way of interrogating the DPMAC
- * from the DPNI side - and for that matter there may exist
- * no DPMAC at all. So for now we just don't report anything
- * beyond the DPNI attributes.
- */
- if (state.options & DPNI_LINK_OPT_AUTONEG)
- link_settings->base.autoneg = AUTONEG_ENABLE;
- if (!(state.options & DPNI_LINK_OPT_HALF_DUPLEX))
- link_settings->base.duplex = DUPLEX_FULL;
- link_settings->base.speed = state.rate;
-
-out:
- return err;
-}
-
-#define DPNI_DYNAMIC_LINK_SET_VER_MAJOR 7
-#define DPNI_DYNAMIC_LINK_SET_VER_MINOR 1
-static int
-dpaa2_eth_set_link_ksettings(struct net_device *net_dev,
- const struct ethtool_link_ksettings *link_settings)
-{
- struct dpni_link_cfg cfg = {0};
- struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
- int err = 0;
-
- /* If using an older MC version, the DPNI must be down
- * in order to be able to change link settings. Taking steps to let
- * the user know that.
- */
- if (dpaa2_eth_cmp_dpni_ver(priv, DPNI_DYNAMIC_LINK_SET_VER_MAJOR,
- DPNI_DYNAMIC_LINK_SET_VER_MINOR) < 0) {
- if (netif_running(net_dev)) {
- netdev_info(net_dev, "Interface must be brought down first.\n");
- return -EACCES;
- }
- }
-
- cfg.rate = link_settings->base.speed;
- if (link_settings->base.autoneg == AUTONEG_ENABLE)
- cfg.options |= DPNI_LINK_OPT_AUTONEG;
- else
- cfg.options &= ~DPNI_LINK_OPT_AUTONEG;
- if (link_settings->base.duplex == DUPLEX_HALF)
- cfg.options |= DPNI_LINK_OPT_HALF_DUPLEX;
- else
- cfg.options &= ~DPNI_LINK_OPT_HALF_DUPLEX;
-
- err = dpni_set_link_cfg(priv->mc_io, 0, priv->mc_token, &cfg);
- if (err)
- /* ethtool will be loud enough if we return an error; no point
- * in putting our own error message on the console by default
- */
- netdev_dbg(net_dev, "ERROR %d setting link cfg\n", err);
-
- return err;
-}
-
-static void dpaa2_eth_get_strings(struct net_device *netdev, u32 stringset,
- u8 *data)
-{
- u8 *p = data;
- int i;
-
- switch (stringset) {
- case ETH_SS_STATS:
- for (i = 0; i < DPAA2_ETH_NUM_STATS; i++) {
- strlcpy(p, dpaa2_ethtool_stats[i], ETH_GSTRING_LEN);
- p += ETH_GSTRING_LEN;
- }
- for (i = 0; i < DPAA2_ETH_NUM_EXTRA_STATS; i++) {
- strlcpy(p, dpaa2_ethtool_extras[i], ETH_GSTRING_LEN);
- p += ETH_GSTRING_LEN;
- }
- break;
- }
-}
-
-static int dpaa2_eth_get_sset_count(struct net_device *net_dev, int sset)
-{
- switch (sset) {
- case ETH_SS_STATS: /* ethtool_get_stats(), ethtool_get_drvinfo() */
- return DPAA2_ETH_NUM_STATS + DPAA2_ETH_NUM_EXTRA_STATS;
- default:
- return -EOPNOTSUPP;
- }
-}
-
-/** Fill in hardware counters, as returned by MC.
- */
-static void dpaa2_eth_get_ethtool_stats(struct net_device *net_dev,
- struct ethtool_stats *stats,
- u64 *data)
-{
- int i = 0;
- int j, k, err;
- int num_cnt;
- union dpni_statistics dpni_stats;
- u64 cdan = 0;
- u64 portal_busy = 0, pull_err = 0;
- struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
- struct dpaa2_eth_drv_stats *extras;
- struct dpaa2_eth_ch_stats *ch_stats;
-
- memset(data, 0,
- sizeof(u64) * (DPAA2_ETH_NUM_STATS + DPAA2_ETH_NUM_EXTRA_STATS));
-
- /* Print standard counters, from DPNI statistics */
- for (j = 0; j <= 2; j++) {
- err = dpni_get_statistics(priv->mc_io, 0, priv->mc_token,
- j, &dpni_stats);
- if (err != 0)
- netdev_warn(net_dev, "dpni_get_stats(%d) failed\n", j);
- switch (j) {
- case 0:
- num_cnt = sizeof(dpni_stats.page_0) / sizeof(u64);
- break;
- case 1:
- num_cnt = sizeof(dpni_stats.page_1) / sizeof(u64);
- break;
- case 2:
- num_cnt = sizeof(dpni_stats.page_2) / sizeof(u64);
- break;
- }
- for (k = 0; k < num_cnt; k++)
- *(data + i++) = dpni_stats.raw.counter[k];
- }
-
- /* Print per-cpu extra stats */
- for_each_online_cpu(k) {
- extras = per_cpu_ptr(priv->percpu_extras, k);
- for (j = 0; j < sizeof(*extras) / sizeof(__u64); j++)
- *((__u64 *)data + i + j) += *((__u64 *)extras + j);
- }
- i += j;
-
- for (j = 0; j < priv->num_channels; j++) {
- ch_stats = &priv->channel[j]->stats;
- cdan += ch_stats->cdan;
- portal_busy += ch_stats->dequeue_portal_busy;
- pull_err += ch_stats->pull_err;
- }
-
- *(data + i++) = portal_busy;
- *(data + i++) = pull_err;
- *(data + i++) = cdan;
-}
-
-static int dpaa2_eth_get_rxnfc(struct net_device *net_dev,
- struct ethtool_rxnfc *rxnfc, u32 *rule_locs)
-{
- struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
-
- switch (rxnfc->cmd) {
- case ETHTOOL_GRXFH:
- /* we purposely ignore cmd->flow_type for now, because the
- * classifier only supports a single set of fields for all
- * protocols
- */
- rxnfc->data = priv->rx_hash_fields;
- break;
- case ETHTOOL_GRXRINGS:
- rxnfc->data = dpaa2_eth_queue_count(priv);
- break;
- default:
- return -EOPNOTSUPP;
- }
-
- return 0;
-}
-
-int dpaa2_phc_index = -1;
-EXPORT_SYMBOL(dpaa2_phc_index);
-
-static int dpaa2_eth_get_ts_info(struct net_device *dev,
- struct ethtool_ts_info *info)
-{
- info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
- SOF_TIMESTAMPING_RX_HARDWARE |
- SOF_TIMESTAMPING_RAW_HARDWARE;
-
- info->phc_index = dpaa2_phc_index;
-
- info->tx_types = (1 << HWTSTAMP_TX_OFF) |
- (1 << HWTSTAMP_TX_ON);
-
- info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
- (1 << HWTSTAMP_FILTER_ALL);
- return 0;
-}
-
-const struct ethtool_ops dpaa2_ethtool_ops = {
- .get_drvinfo = dpaa2_eth_get_drvinfo,
- .get_link = ethtool_op_get_link,
- .get_link_ksettings = dpaa2_eth_get_link_ksettings,
- .set_link_ksettings = dpaa2_eth_set_link_ksettings,
- .get_sset_count = dpaa2_eth_get_sset_count,
- .get_ethtool_stats = dpaa2_eth_get_ethtool_stats,
- .get_strings = dpaa2_eth_get_strings,
- .get_rxnfc = dpaa2_eth_get_rxnfc,
- .get_ts_info = dpaa2_eth_get_ts_info,
-};
diff --git a/drivers/staging/fsl-dpaa2/ethernet/ethernet-driver.rst b/drivers/staging/fsl-dpaa2/ethernet/ethernet-driver.rst
deleted file mode 100644
index 90ec940749e8..000000000000
--- a/drivers/staging/fsl-dpaa2/ethernet/ethernet-driver.rst
+++ /dev/null
@@ -1,185 +0,0 @@
-.. SPDX-License-Identifier: GPL-2.0
-.. include:: <isonum.txt>
-
-===============================
-DPAA2 Ethernet driver
-===============================
-
-:Copyright: |copy| 2017-2018 NXP
-
-This file provides documentation for the Freescale DPAA2 Ethernet driver.
-
-Supported Platforms
-===================
-This driver provides networking support for Freescale DPAA2 SoCs, e.g.
-LS2080A, LS2088A, LS1088A.
-
-
-Architecture Overview
-=====================
-Unlike regular NICs, in the DPAA2 architecture there is no single hardware block
-representing network interfaces; instead, several separate hardware resources
-concur to provide the networking functionality:
-
-- network interfaces
-- queues, channels
-- buffer pools
-- MAC/PHY
-
-All hardware resources are allocated and configured through the Management
-Complex (MC) portals. MC abstracts most of these resources as DPAA2 objects
-and exposes ABIs through which they can be configured and controlled. A few
-hardware resources, like queues, do not have a corresponding MC object and
-are treated as internal resources of other objects.
-
-For a more detailed description of the DPAA2 architecture and its object
-abstractions see *Documentation/networking/dpaa2/overview.rst*.
-
-Each Linux net device is built on top of a Datapath Network Interface (DPNI)
-object and uses Buffer Pools (DPBPs), I/O Portals (DPIOs) and Concentrators
-(DPCONs).
-
-Configuration interface::
-
- -----------------------
- | DPAA2 Ethernet Driver |
- -----------------------
- . . .
- . . .
- . . . . . . . . . . . .
- . . .
- . . .
- ---------- ---------- -----------
- | DPBP API | | DPNI API | | DPCON API |
- ---------- ---------- -----------
- . . . software
- ======= . ========== . ============ . ===================
- . . . hardware
- ------------------------------------------
- | MC hardware portals |
- ------------------------------------------
- . . .
- . . .
- ------ ------ -------
- | DPBP | | DPNI | | DPCON |
- ------ ------ -------
-
-The DPNIs are network interfaces without a direct one-on-one mapping to PHYs.
-DPBPs represent hardware buffer pools. Packet I/O is performed in the context
-of DPCON objects, using DPIO portals for managing and communicating with the
-hardware resources.
-
-Datapath (I/O) interface::
-
- -----------------------------------------------
- | DPAA2 Ethernet Driver |
- -----------------------------------------------
- | ^ ^ | |
- | | | | |
- enqueue| dequeue| data | dequeue| seed |
- (Tx) | (Rx, TxC)| avail.| request| buffers|
- | | notify| | |
- | | | | |
- V | | V V
- -----------------------------------------------
- | DPIO Driver |
- -----------------------------------------------
- | | | | | software
- | | | | | ================
- | | | | | hardware
- -----------------------------------------------
- | I/O hardware portals |
- -----------------------------------------------
- | ^ ^ | |
- | | | | |
- | | | V |
- V | ================ V
- ---------------------- | -------------
- queues ---------------------- | | Buffer pool |
- ---------------------- | -------------
- =======================
- Channel
-
-Datapath I/O (DPIO) portals provide enqueue and dequeue services, data
-availability notifications and buffer pool management. DPIOs are shared between
-all DPAA2 objects (and implicitly all DPAA2 kernel drivers) that work with data
-frames, but must be affine to the CPUs for the purpose of traffic distribution.
-
-Frames are transmitted and received through hardware frame queues, which can be
-grouped in channels for the purpose of hardware scheduling. The Ethernet driver
-enqueues TX frames on egress queues and after transmission is complete a TX
-confirmation frame is sent back to the CPU.
-
-When frames are available on ingress queues, a data availability notification
-is sent to the CPU; notifications are raised per channel, so even if multiple
-queues in the same channel have available frames, only one notification is sent.
-After a channel fires a notification, is must be explicitly rearmed.
-
-Each network interface can have multiple Rx, Tx and confirmation queues affined
-to CPUs, and one channel (DPCON) for each CPU that services at least one queue.
-DPCONs are used to distribute ingress traffic to different CPUs via the cores'
-affine DPIOs.
-
-The role of hardware buffer pools is storage of ingress frame data. Each network
-interface has a privately owned buffer pool which it seeds with kernel allocated
-buffers.
-
-
-DPNIs are decoupled from PHYs; a DPNI can be connected to a PHY through a DPMAC
-object or to another DPNI through an internal link, but the connection is
-managed by MC and completely transparent to the Ethernet driver.
-
-::
-
- --------- --------- ---------
- | eth if1 | | eth if2 | | eth ifn |
- --------- --------- ---------
- . . .
- . . .
- . . .
- ---------------------------
- | DPAA2 Ethernet Driver |
- ---------------------------
- . . .
- . . .
- . . .
- ------ ------ ------ -------
- | DPNI | | DPNI | | DPNI | | DPMAC |----+
- ------ ------ ------ ------- |
- | | | | |
- | | | | -----
- =========== ================== | PHY |
- -----
-
-Creating a Network Interface
-============================
-A net device is created for each DPNI object probed on the MC bus. Each DPNI has
-a number of properties which determine the network interface configuration
-options and associated hardware resources.
-
-DPNI objects (and the other DPAA2 objects needed for a network interface) can be
-added to a container on the MC bus in one of two ways: statically, through a
-Datapath Layout Binary file (DPL) that is parsed by MC at boot time; or created
-dynamically at runtime, via the DPAA2 objects APIs.
-
-
-Features & Offloads
-===================
-Hardware checksum offloading is supported for TCP and UDP over IPv4/6 frames.
-The checksum offloads can be independently configured on RX and TX through
-ethtool.
-
-Hardware offload of unicast and multicast MAC filtering is supported on the
-ingress path and permanently enabled.
-
-Scatter-gather frames are supported on both RX and TX paths. On TX, SG support
-is configurable via ethtool; on RX it is always enabled.
-
-The DPAA2 hardware can process jumbo Ethernet frames of up to 10K bytes.
-
-The Ethernet driver defines a static flow hashing scheme that distributes
-traffic based on a 5-tuple key: src IP, dst IP, IP proto, L4 src port,
-L4 dst port. No user configuration is supported for now.
-
-Hardware specific statistics for the network interface as well as some
-non-standard driver stats can be consulted through ethtool -S option.
diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
index ecdd3d84f956..7a7ca67822c5 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
+++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
@@ -717,7 +717,7 @@ static int port_vlans_add(struct net_device *netdev,
struct switchdev_trans *trans)
{
struct ethsw_port_priv *port_priv = netdev_priv(netdev);
- int vid, err;
+ int vid, err = 0;
if (netif_is_bridge_master(vlan->obj.orig_dev))
return -EOPNOTSUPP;
@@ -872,7 +872,7 @@ static int port_vlans_del(struct net_device *netdev,
const struct switchdev_obj_port_vlan *vlan)
{
struct ethsw_port_priv *port_priv = netdev_priv(netdev);
- int vid, err;
+ int vid, err = 0;
if (netif_is_bridge_master(vlan->obj.orig_dev))
return -EOPNOTSUPP;
@@ -1014,10 +1014,8 @@ static void ethsw_switchdev_event_work(struct work_struct *work)
container_of(work, struct ethsw_switchdev_event_work, work);
struct net_device *dev = switchdev_work->dev;
struct switchdev_notifier_fdb_info *fdb_info;
- struct ethsw_port_priv *port_priv;
rtnl_lock();
- port_priv = netdev_priv(dev);
fdb_info = &switchdev_work->fdb_info;
switch (switchdev_work->event) {
diff --git a/drivers/staging/fsl-dpaa2/rtc/Makefile b/drivers/staging/fsl-dpaa2/rtc/Makefile
deleted file mode 100644
index 5468da071163..000000000000
--- a/drivers/staging/fsl-dpaa2/rtc/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# Makefile for the Freescale DPAA2 PTP clock
-#
-
-obj-$(CONFIG_FSL_DPAA2_PTP_CLOCK) += dpaa2-rtc.o
-
-dpaa2-rtc-objs := rtc.o dprtc.o
diff --git a/drivers/staging/fsl-dpaa2/rtc/dprtc-cmd.h b/drivers/staging/fsl-dpaa2/rtc/dprtc-cmd.h
deleted file mode 100644
index db6a473430cc..000000000000
--- a/drivers/staging/fsl-dpaa2/rtc/dprtc-cmd.h
+++ /dev/null
@@ -1,137 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright 2013-2016 Freescale Semiconductor Inc.
- * Copyright 2016-2018 NXP
- */
-
-#ifndef _FSL_DPRTC_CMD_H
-#define _FSL_DPRTC_CMD_H
-
-/* DPRTC Version */
-#define DPRTC_VER_MAJOR 2
-#define DPRTC_VER_MINOR 0
-
-/* Command versioning */
-#define DPRTC_CMD_BASE_VERSION 1
-#define DPRTC_CMD_ID_OFFSET 4
-
-#define DPRTC_CMD(id) (((id) << DPRTC_CMD_ID_OFFSET) | DPRTC_CMD_BASE_VERSION)
-
-/* Command IDs */
-#define DPRTC_CMDID_CLOSE DPRTC_CMD(0x800)
-#define DPRTC_CMDID_OPEN DPRTC_CMD(0x810)
-#define DPRTC_CMDID_CREATE DPRTC_CMD(0x910)
-#define DPRTC_CMDID_DESTROY DPRTC_CMD(0x990)
-#define DPRTC_CMDID_GET_API_VERSION DPRTC_CMD(0xa10)
-
-#define DPRTC_CMDID_ENABLE DPRTC_CMD(0x002)
-#define DPRTC_CMDID_DISABLE DPRTC_CMD(0x003)
-#define DPRTC_CMDID_GET_ATTR DPRTC_CMD(0x004)
-#define DPRTC_CMDID_RESET DPRTC_CMD(0x005)
-#define DPRTC_CMDID_IS_ENABLED DPRTC_CMD(0x006)
-
-#define DPRTC_CMDID_SET_IRQ_ENABLE DPRTC_CMD(0x012)
-#define DPRTC_CMDID_GET_IRQ_ENABLE DPRTC_CMD(0x013)
-#define DPRTC_CMDID_SET_IRQ_MASK DPRTC_CMD(0x014)
-#define DPRTC_CMDID_GET_IRQ_MASK DPRTC_CMD(0x015)
-#define DPRTC_CMDID_GET_IRQ_STATUS DPRTC_CMD(0x016)
-#define DPRTC_CMDID_CLEAR_IRQ_STATUS DPRTC_CMD(0x017)
-
-#define DPRTC_CMDID_SET_CLOCK_OFFSET DPRTC_CMD(0x1d0)
-#define DPRTC_CMDID_SET_FREQ_COMPENSATION DPRTC_CMD(0x1d1)
-#define DPRTC_CMDID_GET_FREQ_COMPENSATION DPRTC_CMD(0x1d2)
-#define DPRTC_CMDID_GET_TIME DPRTC_CMD(0x1d3)
-#define DPRTC_CMDID_SET_TIME DPRTC_CMD(0x1d4)
-#define DPRTC_CMDID_SET_ALARM DPRTC_CMD(0x1d5)
-#define DPRTC_CMDID_SET_PERIODIC_PULSE DPRTC_CMD(0x1d6)
-#define DPRTC_CMDID_CLEAR_PERIODIC_PULSE DPRTC_CMD(0x1d7)
-#define DPRTC_CMDID_SET_EXT_TRIGGER DPRTC_CMD(0x1d8)
-#define DPRTC_CMDID_CLEAR_EXT_TRIGGER DPRTC_CMD(0x1d9)
-#define DPRTC_CMDID_GET_EXT_TRIGGER_TIMESTAMP DPRTC_CMD(0x1dA)
-
-/* Macros for accessing command fields smaller than 1byte */
-#define DPRTC_MASK(field) \
- GENMASK(DPRTC_##field##_SHIFT + DPRTC_##field##_SIZE - 1, \
- DPRTC_##field##_SHIFT)
-#define dprtc_get_field(var, field) \
- (((var) & DPRTC_MASK(field)) >> DPRTC_##field##_SHIFT)
-
-#pragma pack(push, 1)
-struct dprtc_cmd_open {
- __le32 dprtc_id;
-};
-
-struct dprtc_cmd_destroy {
- __le32 object_id;
-};
-
-#define DPRTC_ENABLE_SHIFT 0
-#define DPRTC_ENABLE_SIZE 1
-
-struct dprtc_rsp_is_enabled {
- u8 en;
-};
-
-struct dprtc_cmd_get_irq {
- __le32 pad;
- u8 irq_index;
-};
-
-struct dprtc_cmd_set_irq_enable {
- u8 en;
- u8 pad[3];
- u8 irq_index;
-};
-
-struct dprtc_rsp_get_irq_enable {
- u8 en;
-};
-
-struct dprtc_cmd_set_irq_mask {
- __le32 mask;
- u8 irq_index;
-};
-
-struct dprtc_rsp_get_irq_mask {
- __le32 mask;
-};
-
-struct dprtc_cmd_get_irq_status {
- __le32 status;
- u8 irq_index;
-};
-
-struct dprtc_rsp_get_irq_status {
- __le32 status;
-};
-
-struct dprtc_cmd_clear_irq_status {
- __le32 status;
- u8 irq_index;
-};
-
-struct dprtc_rsp_get_attributes {
- __le32 pad;
- __le32 id;
-};
-
-struct dprtc_cmd_set_clock_offset {
- __le64 offset;
-};
-
-struct dprtc_get_freq_compensation {
- __le32 freq_compensation;
-};
-
-struct dprtc_time {
- __le64 time;
-};
-
-struct dprtc_rsp_get_api_version {
- __le16 major;
- __le16 minor;
-};
-
-#pragma pack(pop)
-
-#endif /* _FSL_DPRTC_CMD_H */
diff --git a/drivers/staging/fsl-dpaa2/rtc/dprtc.c b/drivers/staging/fsl-dpaa2/rtc/dprtc.c
deleted file mode 100644
index 68ae6ffefbf5..000000000000
--- a/drivers/staging/fsl-dpaa2/rtc/dprtc.c
+++ /dev/null
@@ -1,701 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright 2013-2016 Freescale Semiconductor Inc.
- * Copyright 2016-2018 NXP
- */
-
-#include <linux/fsl/mc.h>
-
-#include "dprtc.h"
-#include "dprtc-cmd.h"
-
-/**
- * dprtc_open() - Open a control session for the specified object.
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @dprtc_id: DPRTC unique ID
- * @token: Returned token; use in subsequent API calls
- *
- * This function can be used to open a control session for an
- * already created object; an object may have been declared in
- * the DPL or by calling the dprtc_create function.
- * This function returns a unique authentication token,
- * associated with the specific object ID and the specific MC
- * portal; this token must be used in all subsequent commands for
- * this specific object
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dprtc_open(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- int dprtc_id,
- u16 *token)
-{
- struct dprtc_cmd_open *cmd_params;
- struct fsl_mc_command cmd = { 0 };
- int err;
-
- cmd.header = mc_encode_cmd_header(DPRTC_CMDID_OPEN,
- cmd_flags,
- 0);
- cmd_params = (struct dprtc_cmd_open *)cmd.params;
- cmd_params->dprtc_id = cpu_to_le32(dprtc_id);
-
- err = mc_send_command(mc_io, &cmd);
- if (err)
- return err;
-
- *token = mc_cmd_hdr_read_token(&cmd);
-
- return 0;
-}
-
-/**
- * dprtc_close() - Close the control session of the object
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPRTC object
- *
- * After this function is called, no further operations are
- * allowed on the object without opening a new control session.
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dprtc_close(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token)
-{
- struct fsl_mc_command cmd = { 0 };
-
- cmd.header = mc_encode_cmd_header(DPRTC_CMDID_CLOSE, cmd_flags,
- token);
-
- return mc_send_command(mc_io, &cmd);
-}
-
-/**
- * dprtc_create() - Create the DPRTC object.
- * @mc_io: Pointer to MC portal's I/O object
- * @dprc_token: Parent container token; '0' for default container
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @cfg: Configuration structure
- * @obj_id: Returned object id
- *
- * Create the DPRTC object, allocate required resources and
- * perform required initialization.
- *
- * The function accepts an authentication token of a parent
- * container that this object should be assigned to. The token
- * can be '0' so the object will be assigned to the default container.
- * The newly created object can be opened with the returned
- * object id and using the container's associated tokens and MC portals.
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dprtc_create(struct fsl_mc_io *mc_io,
- u16 dprc_token,
- u32 cmd_flags,
- const struct dprtc_cfg *cfg,
- u32 *obj_id)
-{
- struct fsl_mc_command cmd = { 0 };
- int err;
-
- cmd.header = mc_encode_cmd_header(DPRTC_CMDID_CREATE,
- cmd_flags,
- dprc_token);
-
- err = mc_send_command(mc_io, &cmd);
- if (err)
- return err;
-
- *obj_id = mc_cmd_read_object_id(&cmd);
-
- return 0;
-}
-
-/**
- * dprtc_destroy() - Destroy the DPRTC object and release all its resources.
- * @mc_io: Pointer to MC portal's I/O object
- * @dprc_token: Parent container token; '0' for default container
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @object_id: The object id; it must be a valid id within the container that
- * created this object;
- *
- * The function accepts the authentication token of the parent container that
- * created the object (not the one that currently owns the object). The object
- * is searched within parent using the provided 'object_id'.
- * All tokens to the object must be closed before calling destroy.
- *
- * Return: '0' on Success; error code otherwise.
- */
-int dprtc_destroy(struct fsl_mc_io *mc_io,
- u16 dprc_token,
- u32 cmd_flags,
- u32 object_id)
-{
- struct dprtc_cmd_destroy *cmd_params;
- struct fsl_mc_command cmd = { 0 };
-
- cmd.header = mc_encode_cmd_header(DPRTC_CMDID_DESTROY,
- cmd_flags,
- dprc_token);
- cmd_params = (struct dprtc_cmd_destroy *)cmd.params;
- cmd_params->object_id = cpu_to_le32(object_id);
-
- return mc_send_command(mc_io, &cmd);
-}
-
-/**
- * dprtc_enable() - Enable the DPRTC.
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPRTC object
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dprtc_enable(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token)
-{
- struct fsl_mc_command cmd = { 0 };
-
- cmd.header = mc_encode_cmd_header(DPRTC_CMDID_ENABLE, cmd_flags,
- token);
-
- return mc_send_command(mc_io, &cmd);
-}
-
-/**
- * dprtc_disable() - Disable the DPRTC.
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPRTC object
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dprtc_disable(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token)
-{
- struct fsl_mc_command cmd = { 0 };
-
- cmd.header = mc_encode_cmd_header(DPRTC_CMDID_DISABLE,
- cmd_flags,
- token);
-
- return mc_send_command(mc_io, &cmd);
-}
-
-/**
- * dprtc_is_enabled() - Check if the DPRTC is enabled.
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPRTC object
- * @en: Returns '1' if object is enabled; '0' otherwise
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dprtc_is_enabled(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- int *en)
-{
- struct dprtc_rsp_is_enabled *rsp_params;
- struct fsl_mc_command cmd = { 0 };
- int err;
-
- cmd.header = mc_encode_cmd_header(DPRTC_CMDID_IS_ENABLED, cmd_flags,
- token);
-
- err = mc_send_command(mc_io, &cmd);
- if (err)
- return err;
-
- rsp_params = (struct dprtc_rsp_is_enabled *)cmd.params;
- *en = dprtc_get_field(rsp_params->en, ENABLE);
-
- return 0;
-}
-
-/**
- * dprtc_reset() - Reset the DPRTC, returns the object to initial state.
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPRTC object
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dprtc_reset(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token)
-{
- struct fsl_mc_command cmd = { 0 };
-
- cmd.header = mc_encode_cmd_header(DPRTC_CMDID_RESET,
- cmd_flags,
- token);
-
- return mc_send_command(mc_io, &cmd);
-}
-
-/**
- * dprtc_set_irq_enable() - Set overall interrupt state.
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPRTC object
- * @irq_index: The interrupt index to configure
- * @en: Interrupt state - enable = 1, disable = 0
- *
- * Allows GPP software to control when interrupts are generated.
- * Each interrupt can have up to 32 causes. The enable/disable control's the
- * overall interrupt state. if the interrupt is disabled no causes will cause
- * an interrupt.
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dprtc_set_irq_enable(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- u8 en)
-{
- struct dprtc_cmd_set_irq_enable *cmd_params;
- struct fsl_mc_command cmd = { 0 };
-
- cmd.header = mc_encode_cmd_header(DPRTC_CMDID_SET_IRQ_ENABLE,
- cmd_flags,
- token);
- cmd_params = (struct dprtc_cmd_set_irq_enable *)cmd.params;
- cmd_params->irq_index = irq_index;
- cmd_params->en = en;
-
- return mc_send_command(mc_io, &cmd);
-}
-
-/**
- * dprtc_get_irq_enable() - Get overall interrupt state
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPRTC object
- * @irq_index: The interrupt index to configure
- * @en: Returned interrupt state - enable = 1, disable = 0
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dprtc_get_irq_enable(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- u8 *en)
-{
- struct dprtc_rsp_get_irq_enable *rsp_params;
- struct dprtc_cmd_get_irq *cmd_params;
- struct fsl_mc_command cmd = { 0 };
- int err;
-
- cmd.header = mc_encode_cmd_header(DPRTC_CMDID_GET_IRQ_ENABLE,
- cmd_flags,
- token);
- cmd_params = (struct dprtc_cmd_get_irq *)cmd.params;
- cmd_params->irq_index = irq_index;
-
- err = mc_send_command(mc_io, &cmd);
- if (err)
- return err;
-
- rsp_params = (struct dprtc_rsp_get_irq_enable *)cmd.params;
- *en = rsp_params->en;
-
- return 0;
-}
-
-/**
- * dprtc_set_irq_mask() - Set interrupt mask.
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPRTC object
- * @irq_index: The interrupt index to configure
- * @mask: Event mask to trigger interrupt;
- * each bit:
- * 0 = ignore event
- * 1 = consider event for asserting IRQ
- *
- * Every interrupt can have up to 32 causes and the interrupt model supports
- * masking/unmasking each cause independently
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dprtc_set_irq_mask(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- u32 mask)
-{
- struct dprtc_cmd_set_irq_mask *cmd_params;
- struct fsl_mc_command cmd = { 0 };
-
- cmd.header = mc_encode_cmd_header(DPRTC_CMDID_SET_IRQ_MASK,
- cmd_flags,
- token);
- cmd_params = (struct dprtc_cmd_set_irq_mask *)cmd.params;
- cmd_params->mask = cpu_to_le32(mask);
- cmd_params->irq_index = irq_index;
-
- return mc_send_command(mc_io, &cmd);
-}
-
-/**
- * dprtc_get_irq_mask() - Get interrupt mask.
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPRTC object
- * @irq_index: The interrupt index to configure
- * @mask: Returned event mask to trigger interrupt
- *
- * Every interrupt can have up to 32 causes and the interrupt model supports
- * masking/unmasking each cause independently
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dprtc_get_irq_mask(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- u32 *mask)
-{
- struct dprtc_rsp_get_irq_mask *rsp_params;
- struct dprtc_cmd_get_irq *cmd_params;
- struct fsl_mc_command cmd = { 0 };
- int err;
-
- cmd.header = mc_encode_cmd_header(DPRTC_CMDID_GET_IRQ_MASK,
- cmd_flags,
- token);
- cmd_params = (struct dprtc_cmd_get_irq *)cmd.params;
- cmd_params->irq_index = irq_index;
-
- err = mc_send_command(mc_io, &cmd);
- if (err)
- return err;
-
- rsp_params = (struct dprtc_rsp_get_irq_mask *)cmd.params;
- *mask = le32_to_cpu(rsp_params->mask);
-
- return 0;
-}
-
-/**
- * dprtc_get_irq_status() - Get the current status of any pending interrupts.
- *
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPRTC object
- * @irq_index: The interrupt index to configure
- * @status: Returned interrupts status - one bit per cause:
- * 0 = no interrupt pending
- * 1 = interrupt pending
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dprtc_get_irq_status(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- u32 *status)
-{
- struct dprtc_cmd_get_irq_status *cmd_params;
- struct dprtc_rsp_get_irq_status *rsp_params;
- struct fsl_mc_command cmd = { 0 };
- int err;
-
- cmd.header = mc_encode_cmd_header(DPRTC_CMDID_GET_IRQ_STATUS,
- cmd_flags,
- token);
- cmd_params = (struct dprtc_cmd_get_irq_status *)cmd.params;
- cmd_params->status = cpu_to_le32(*status);
- cmd_params->irq_index = irq_index;
-
- err = mc_send_command(mc_io, &cmd);
- if (err)
- return err;
-
- rsp_params = (struct dprtc_rsp_get_irq_status *)cmd.params;
- *status = le32_to_cpu(rsp_params->status);
-
- return 0;
-}
-
-/**
- * dprtc_clear_irq_status() - Clear a pending interrupt's status
- *
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPRTC object
- * @irq_index: The interrupt index to configure
- * @status: Bits to clear (W1C) - one bit per cause:
- * 0 = don't change
- * 1 = clear status bit
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dprtc_clear_irq_status(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- u32 status)
-{
- struct dprtc_cmd_clear_irq_status *cmd_params;
- struct fsl_mc_command cmd = { 0 };
-
- cmd.header = mc_encode_cmd_header(DPRTC_CMDID_CLEAR_IRQ_STATUS,
- cmd_flags,
- token);
- cmd_params = (struct dprtc_cmd_clear_irq_status *)cmd.params;
- cmd_params->irq_index = irq_index;
- cmd_params->status = cpu_to_le32(status);
-
- return mc_send_command(mc_io, &cmd);
-}
-
-/**
- * dprtc_get_attributes - Retrieve DPRTC attributes.
- *
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPRTC object
- * @attr: Returned object's attributes
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dprtc_get_attributes(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- struct dprtc_attr *attr)
-{
- struct dprtc_rsp_get_attributes *rsp_params;
- struct fsl_mc_command cmd = { 0 };
- int err;
-
- cmd.header = mc_encode_cmd_header(DPRTC_CMDID_GET_ATTR,
- cmd_flags,
- token);
-
- err = mc_send_command(mc_io, &cmd);
- if (err)
- return err;
-
- rsp_params = (struct dprtc_rsp_get_attributes *)cmd.params;
- attr->id = le32_to_cpu(rsp_params->id);
-
- return 0;
-}
-
-/**
- * dprtc_set_clock_offset() - Sets the clock's offset
- * (usually relative to another clock).
- *
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPRTC object
- * @offset: New clock offset (in nanoseconds).
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dprtc_set_clock_offset(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- int64_t offset)
-{
- struct dprtc_cmd_set_clock_offset *cmd_params;
- struct fsl_mc_command cmd = { 0 };
-
- cmd.header = mc_encode_cmd_header(DPRTC_CMDID_SET_CLOCK_OFFSET,
- cmd_flags,
- token);
- cmd_params = (struct dprtc_cmd_set_clock_offset *)cmd.params;
- cmd_params->offset = cpu_to_le64(offset);
-
- return mc_send_command(mc_io, &cmd);
-}
-
-/**
- * dprtc_set_freq_compensation() - Sets a new frequency compensation value.
- *
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPRTC object
- * @freq_compensation: The new frequency compensation value to set.
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dprtc_set_freq_compensation(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u32 freq_compensation)
-{
- struct dprtc_get_freq_compensation *cmd_params;
- struct fsl_mc_command cmd = { 0 };
-
- cmd.header = mc_encode_cmd_header(DPRTC_CMDID_SET_FREQ_COMPENSATION,
- cmd_flags,
- token);
- cmd_params = (struct dprtc_get_freq_compensation *)cmd.params;
- cmd_params->freq_compensation = cpu_to_le32(freq_compensation);
-
- return mc_send_command(mc_io, &cmd);
-}
-
-/**
- * dprtc_get_freq_compensation() - Retrieves the frequency compensation value
- *
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPRTC object
- * @freq_compensation: Frequency compensation value
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dprtc_get_freq_compensation(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u32 *freq_compensation)
-{
- struct dprtc_get_freq_compensation *rsp_params;
- struct fsl_mc_command cmd = { 0 };
- int err;
-
- cmd.header = mc_encode_cmd_header(DPRTC_CMDID_GET_FREQ_COMPENSATION,
- cmd_flags,
- token);
-
- err = mc_send_command(mc_io, &cmd);
- if (err)
- return err;
-
- rsp_params = (struct dprtc_get_freq_compensation *)cmd.params;
- *freq_compensation = le32_to_cpu(rsp_params->freq_compensation);
-
- return 0;
-}
-
-/**
- * dprtc_get_time() - Returns the current RTC time.
- *
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPRTC object
- * @time: Current RTC time.
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dprtc_get_time(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- uint64_t *time)
-{
- struct dprtc_time *rsp_params;
- struct fsl_mc_command cmd = { 0 };
- int err;
-
- cmd.header = mc_encode_cmd_header(DPRTC_CMDID_GET_TIME,
- cmd_flags,
- token);
-
- err = mc_send_command(mc_io, &cmd);
- if (err)
- return err;
-
- rsp_params = (struct dprtc_time *)cmd.params;
- *time = le64_to_cpu(rsp_params->time);
-
- return 0;
-}
-
-/**
- * dprtc_set_time() - Updates current RTC time.
- *
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPRTC object
- * @time: New RTC time.
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dprtc_set_time(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- uint64_t time)
-{
- struct dprtc_time *cmd_params;
- struct fsl_mc_command cmd = { 0 };
-
- cmd.header = mc_encode_cmd_header(DPRTC_CMDID_SET_TIME,
- cmd_flags,
- token);
- cmd_params = (struct dprtc_time *)cmd.params;
- cmd_params->time = cpu_to_le64(time);
-
- return mc_send_command(mc_io, &cmd);
-}
-
-/**
- * dprtc_set_alarm() - Defines and sets alarm.
- *
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPRTC object
- * @time: In nanoseconds, the time when the alarm
- * should go off - must be a multiple of
- * 1 microsecond
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dprtc_set_alarm(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token, uint64_t time)
-{
- struct dprtc_time *cmd_params;
- struct fsl_mc_command cmd = { 0 };
-
- cmd.header = mc_encode_cmd_header(DPRTC_CMDID_SET_ALARM,
- cmd_flags,
- token);
- cmd_params = (struct dprtc_time *)cmd.params;
- cmd_params->time = cpu_to_le64(time);
-
- return mc_send_command(mc_io, &cmd);
-}
-
-/**
- * dprtc_get_api_version() - Get Data Path Real Time Counter API version
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @major_ver: Major version of data path real time counter API
- * @minor_ver: Minor version of data path real time counter API
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dprtc_get_api_version(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 *major_ver,
- u16 *minor_ver)
-{
- struct dprtc_rsp_get_api_version *rsp_params;
- struct fsl_mc_command cmd = { 0 };
- int err;
-
- cmd.header = mc_encode_cmd_header(DPRTC_CMDID_GET_API_VERSION,
- cmd_flags,
- 0);
-
- err = mc_send_command(mc_io, &cmd);
- if (err)
- return err;
-
- rsp_params = (struct dprtc_rsp_get_api_version *)cmd.params;
- *major_ver = le16_to_cpu(rsp_params->major);
- *minor_ver = le16_to_cpu(rsp_params->minor);
-
- return 0;
-}
diff --git a/drivers/staging/fsl-dpaa2/rtc/dprtc.h b/drivers/staging/fsl-dpaa2/rtc/dprtc.h
deleted file mode 100644
index 08f7c7bebbca..000000000000
--- a/drivers/staging/fsl-dpaa2/rtc/dprtc.h
+++ /dev/null
@@ -1,164 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright 2013-2016 Freescale Semiconductor Inc.
- * Copyright 2016-2018 NXP
- */
-
-#ifndef __FSL_DPRTC_H
-#define __FSL_DPRTC_H
-
-/* Data Path Real Time Counter API
- * Contains initialization APIs and runtime control APIs for RTC
- */
-
-struct fsl_mc_io;
-
-/**
- * Number of irq's
- */
-#define DPRTC_MAX_IRQ_NUM 1
-#define DPRTC_IRQ_INDEX 0
-
-/**
- * Interrupt event masks:
- */
-
-/**
- * Interrupt event mask indicating alarm event had occurred
- */
-#define DPRTC_EVENT_ALARM 0x40000000
-/**
- * Interrupt event mask indicating periodic pulse event had occurred
- */
-#define DPRTC_EVENT_PPS 0x08000000
-
-int dprtc_open(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- int dprtc_id,
- u16 *token);
-
-int dprtc_close(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token);
-
-/**
- * struct dprtc_cfg - Structure representing DPRTC configuration
- * @options: place holder
- */
-struct dprtc_cfg {
- u32 options;
-};
-
-int dprtc_create(struct fsl_mc_io *mc_io,
- u16 dprc_token,
- u32 cmd_flags,
- const struct dprtc_cfg *cfg,
- u32 *obj_id);
-
-int dprtc_destroy(struct fsl_mc_io *mc_io,
- u16 dprc_token,
- u32 cmd_flags,
- u32 object_id);
-
-int dprtc_enable(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token);
-
-int dprtc_disable(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token);
-
-int dprtc_is_enabled(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- int *en);
-
-int dprtc_reset(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token);
-
-int dprtc_set_clock_offset(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- int64_t offset);
-
-int dprtc_set_freq_compensation(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u32 freq_compensation);
-
-int dprtc_get_freq_compensation(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u32 *freq_compensation);
-
-int dprtc_get_time(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- uint64_t *time);
-
-int dprtc_set_time(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- uint64_t time);
-
-int dprtc_set_alarm(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- uint64_t time);
-
-int dprtc_set_irq_enable(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- u8 en);
-
-int dprtc_get_irq_enable(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- u8 *en);
-
-int dprtc_set_irq_mask(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- u32 mask);
-
-int dprtc_get_irq_mask(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- u32 *mask);
-
-int dprtc_get_irq_status(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- u32 *status);
-
-int dprtc_clear_irq_status(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- u32 status);
-
-/**
- * struct dprtc_attr - Structure representing DPRTC attributes
- * @id: DPRTC object ID
- */
-struct dprtc_attr {
- int id;
-};
-
-int dprtc_get_attributes(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- struct dprtc_attr *attr);
-
-int dprtc_get_api_version(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 *major_ver,
- u16 *minor_ver);
-
-#endif /* __FSL_DPRTC_H */
diff --git a/drivers/staging/fwserial/fwserial.c b/drivers/staging/fwserial/fwserial.c
index fa0dd425b454..173f451b86b7 100644
--- a/drivers/staging/fwserial/fwserial.c
+++ b/drivers/staging/fwserial/fwserial.c
@@ -1209,42 +1209,40 @@ static int wait_msr_change(struct fwtty_port *port, unsigned long mask)
check_msr_delta(port, mask, &prev));
}
-static int get_serial_info(struct fwtty_port *port,
- struct serial_struct __user *info)
+static int get_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
- struct serial_struct tmp;
-
- memset(&tmp, 0, sizeof(tmp));
-
- tmp.type = PORT_UNKNOWN;
- tmp.line = port->port.tty->index;
- tmp.flags = port->port.flags;
- tmp.xmit_fifo_size = FWTTY_PORT_TXFIFO_LEN;
- tmp.baud_base = 400000000;
- tmp.close_delay = port->port.close_delay;
-
- return (copy_to_user(info, &tmp, sizeof(*info))) ? -EFAULT : 0;
+ struct fwtty_port *port = tty->driver_data;
+ mutex_lock(&port->port.mutex);
+ ss->type = PORT_UNKNOWN;
+ ss->line = port->port.tty->index;
+ ss->flags = port->port.flags;
+ ss->xmit_fifo_size = FWTTY_PORT_TXFIFO_LEN;
+ ss->baud_base = 400000000;
+ ss->close_delay = port->port.close_delay;
+ mutex_unlock(&port->port.mutex);
+ return 0;
}
-static int set_serial_info(struct fwtty_port *port,
- struct serial_struct __user *info)
+static int set_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
- struct serial_struct tmp;
-
- if (copy_from_user(&tmp, info, sizeof(tmp)))
- return -EFAULT;
+ struct fwtty_port *port = tty->driver_data;
- if (tmp.irq != 0 || tmp.port != 0 || tmp.custom_divisor != 0 ||
- tmp.baud_base != 400000000)
+ if (ss->irq != 0 || ss->port != 0 || ss->custom_divisor != 0 ||
+ ss->baud_base != 400000000)
return -EPERM;
+ mutex_lock(&port->port.mutex);
if (!capable(CAP_SYS_ADMIN)) {
- if (((tmp.flags & ~ASYNC_USR_MASK) !=
- (port->port.flags & ~ASYNC_USR_MASK)))
+ if (((ss->flags & ~ASYNC_USR_MASK) !=
+ (port->port.flags & ~ASYNC_USR_MASK))) {
+ mutex_unlock(&port->port.mutex);
return -EPERM;
- } else {
- port->port.close_delay = tmp.close_delay * HZ / 100;
+ }
}
+ port->port.close_delay = ss->close_delay * HZ / 100;
+ mutex_unlock(&port->port.mutex);
return 0;
}
@@ -1256,18 +1254,6 @@ static int fwtty_ioctl(struct tty_struct *tty, unsigned int cmd,
int err;
switch (cmd) {
- case TIOCGSERIAL:
- mutex_lock(&port->port.mutex);
- err = get_serial_info(port, (void __user *)arg);
- mutex_unlock(&port->port.mutex);
- break;
-
- case TIOCSSERIAL:
- mutex_lock(&port->port.mutex);
- err = set_serial_info(port, (void __user *)arg);
- mutex_unlock(&port->port.mutex);
- break;
-
case TIOCMIWAIT:
err = wait_msr_change(port, arg);
break;
@@ -1557,6 +1543,8 @@ static const struct tty_operations fwtty_ops = {
.tiocmget = fwtty_tiocmget,
.tiocmset = fwtty_tiocmset,
.get_icount = fwtty_get_icount,
+ .set_serial = set_serial_info,
+ .get_serial = get_serial_info,
.proc_show = fwtty_proc_show,
};
@@ -1578,6 +1566,8 @@ static const struct tty_operations fwloop_ops = {
.tiocmget = fwtty_tiocmget,
.tiocmset = fwtty_tiocmset,
.get_icount = fwtty_get_icount,
+ .set_serial = set_serial_info,
+ .get_serial = get_serial_info,
};
static inline int mgmt_pkt_expected_len(__be16 code)
diff --git a/drivers/staging/gasket/Kconfig b/drivers/staging/gasket/Kconfig
index 970e299046c3..e82b85541f7e 100644
--- a/drivers/staging/gasket/Kconfig
+++ b/drivers/staging/gasket/Kconfig
@@ -14,8 +14,9 @@ config STAGING_APEX_DRIVER
tristate "Apex Driver"
depends on STAGING_GASKET_FRAMEWORK
help
- This driver supports the Apex device. Say Y if you want to
- include this driver in the kernel.
+ This driver supports the Apex Edge TPU device. See
+ https://cloud.google.com/edge-tpu/ for more information.
+ Say Y if you want to include this driver in the kernel.
To compile this driver as a module, choose M here. The module
will be called "apex".
diff --git a/drivers/staging/gasket/apex_driver.c b/drivers/staging/gasket/apex_driver.c
index c747e9ca4518..0578bf1ba1e9 100644
--- a/drivers/staging/gasket/apex_driver.c
+++ b/drivers/staging/gasket/apex_driver.c
@@ -138,9 +138,6 @@ static const struct gasket_mappable_region mappable_regions[NUM_REGIONS] = {
{ 0x48000, 0x1000 },
};
-static const struct gasket_mappable_region cm_mappable_regions[1] = { { 0x0,
- APEX_CH_MEM_BYTES } };
-
/* Gasket device interrupts enums must be dense (i.e., no empty slots). */
enum apex_interrupt {
APEX_INTERRUPT_INSTR_QUEUE = 0,
@@ -228,7 +225,6 @@ static struct gasket_interrupt_desc apex_interrupts[] = {
},
};
-
/* Allows device to enter power save upon driver close(). */
static int allow_power_save = 1;
@@ -529,7 +525,7 @@ static ssize_t sysfs_show(struct device *device, struct device_attribute *attr,
return -ENODEV;
}
- type = (enum sysfs_attribute_type)gasket_sysfs_get_attr(device, attr);
+ type = (enum sysfs_attribute_type)gasket_attr->data.attr_type;
switch (type) {
case ATTR_KERNEL_HIB_PAGE_TABLE_SIZE:
ret = scnprintf(buf, PAGE_SIZE, "%u\n",
diff --git a/drivers/staging/gasket/gasket_core.c b/drivers/staging/gasket/gasket_core.c
index d12ab560411f..a445d58fb399 100644
--- a/drivers/staging/gasket/gasket_core.c
+++ b/drivers/staging/gasket/gasket_core.c
@@ -109,8 +109,6 @@ check_and_invoke_callback(struct gasket_dev *gasket_dev,
{
int ret = 0;
- dev_dbg(gasket_dev->dev, "check_and_invoke_callback %p\n",
- cb_function);
if (cb_function) {
mutex_lock(&gasket_dev->mutex);
ret = cb_function(gasket_dev);
@@ -126,11 +124,8 @@ gasket_check_and_invoke_callback_nolock(struct gasket_dev *gasket_dev,
{
int ret = 0;
- if (cb_function) {
- dev_dbg(gasket_dev->dev,
- "Invoking device-specific callback.\n");
+ if (cb_function)
ret = cb_function(gasket_dev);
- }
return ret;
}
@@ -189,26 +184,26 @@ static int gasket_find_dev_slot(struct gasket_internal_desc *internal_desc,
* Returns 0 if successful, a negative error code otherwise.
*/
static int gasket_alloc_dev(struct gasket_internal_desc *internal_desc,
- struct device *parent, struct gasket_dev **pdev,
- const char *kobj_name)
+ struct device *parent, struct gasket_dev **pdev)
{
int dev_idx;
const struct gasket_driver_desc *driver_desc =
internal_desc->driver_desc;
struct gasket_dev *gasket_dev;
struct gasket_cdev_info *dev_info;
+ const char *parent_name = dev_name(parent);
- pr_debug("Allocating a Gasket device %s.\n", kobj_name);
+ pr_debug("Allocating a Gasket device, parent %s.\n", parent_name);
*pdev = NULL;
- dev_idx = gasket_find_dev_slot(internal_desc, kobj_name);
+ dev_idx = gasket_find_dev_slot(internal_desc, parent_name);
if (dev_idx < 0)
return dev_idx;
gasket_dev = *pdev = kzalloc(sizeof(*gasket_dev), GFP_KERNEL);
if (!gasket_dev) {
- pr_err("no memory for device %s\n", kobj_name);
+ pr_err("no memory for device, parent %s\n", parent_name);
return -ENOMEM;
}
internal_desc->devs[dev_idx] = gasket_dev;
@@ -217,7 +212,7 @@ static int gasket_alloc_dev(struct gasket_internal_desc *internal_desc,
gasket_dev->internal_desc = internal_desc;
gasket_dev->dev_idx = dev_idx;
- snprintf(gasket_dev->kobj_name, GASKET_NAME_MAX, "%s", kobj_name);
+ snprintf(gasket_dev->kobj_name, GASKET_NAME_MAX, "%s", parent_name);
gasket_dev->dev = get_device(parent);
/* gasket_bar_data is uninitialized. */
gasket_dev->num_page_tables = driver_desc->num_page_tables;
@@ -231,10 +226,9 @@ static int gasket_alloc_dev(struct gasket_internal_desc *internal_desc,
dev_info->devt =
MKDEV(driver_desc->major, driver_desc->minor +
gasket_dev->dev_idx);
- dev_info->device = device_create(internal_desc->class, parent,
- dev_info->devt, gasket_dev, dev_info->name);
-
- dev_dbg(dev_info->device, "Gasket device allocated.\n");
+ dev_info->device =
+ device_create(internal_desc->class, parent, dev_info->devt,
+ gasket_dev, dev_info->name);
/* cdev has not yet been added; cdev_added is 0 */
dev_info->gasket_dev_ptr = gasket_dev;
@@ -652,13 +646,13 @@ void gasket_disable_device(struct gasket_dev *gasket_dev)
EXPORT_SYMBOL(gasket_disable_device);
/*
- * Registered descriptor lookup.
+ * Registered driver descriptor lookup for PCI devices.
*
* Precondition: Called with g_mutex held (to avoid a race on return).
* Returns NULL if no matching device was found.
*/
static struct gasket_internal_desc *
-lookup_internal_desc(struct pci_dev *pci_dev)
+lookup_pci_internal_desc(struct pci_dev *pci_dev)
{
int i;
@@ -1358,13 +1352,7 @@ int gasket_enable_device(struct gasket_dev *gasket_dev)
const struct gasket_driver_desc *driver_desc =
gasket_dev->internal_desc->driver_desc;
- ret = gasket_interrupt_init(gasket_dev, driver_desc->name,
- driver_desc->interrupt_type,
- driver_desc->interrupts,
- driver_desc->num_interrupts,
- driver_desc->interrupt_pack_width,
- driver_desc->interrupt_bar_index,
- driver_desc->wire_interrupt_offsets);
+ ret = gasket_interrupt_init(gasket_dev);
if (ret) {
dev_err(gasket_dev->dev,
"Critical failure to allocate interrupts: %d\n", ret);
@@ -1420,6 +1408,56 @@ int gasket_enable_device(struct gasket_dev *gasket_dev)
}
EXPORT_SYMBOL(gasket_enable_device);
+static int __gasket_add_device(struct device *parent_dev,
+ struct gasket_internal_desc *internal_desc,
+ struct gasket_dev **gasket_devp)
+{
+ int ret;
+ struct gasket_dev *gasket_dev;
+ const struct gasket_driver_desc *driver_desc =
+ internal_desc->driver_desc;
+
+ ret = gasket_alloc_dev(internal_desc, parent_dev, &gasket_dev);
+ if (ret)
+ return ret;
+ if (IS_ERR(gasket_dev->dev_info.device)) {
+ dev_err(parent_dev, "Cannot create %s device %s [ret = %ld]\n",
+ driver_desc->name, gasket_dev->dev_info.name,
+ PTR_ERR(gasket_dev->dev_info.device));
+ ret = -ENODEV;
+ goto free_gasket_dev;
+ }
+
+ ret = gasket_sysfs_create_mapping(gasket_dev->dev_info.device,
+ gasket_dev);
+ if (ret)
+ goto remove_device;
+
+ ret = gasket_sysfs_create_entries(gasket_dev->dev_info.device,
+ gasket_sysfs_generic_attrs);
+ if (ret)
+ goto remove_sysfs_mapping;
+
+ *gasket_devp = gasket_dev;
+ return 0;
+
+remove_sysfs_mapping:
+ gasket_sysfs_remove_mapping(gasket_dev->dev_info.device);
+remove_device:
+ device_destroy(internal_desc->class, gasket_dev->dev_info.devt);
+free_gasket_dev:
+ gasket_free_dev(gasket_dev);
+ return ret;
+}
+
+static void __gasket_remove_device(struct gasket_internal_desc *internal_desc,
+ struct gasket_dev *gasket_dev)
+{
+ gasket_sysfs_remove_mapping(gasket_dev->dev_info.device);
+ device_destroy(internal_desc->class, gasket_dev->dev_info.devt);
+ gasket_free_dev(gasket_dev);
+}
+
/*
* Add PCI gasket device.
*
@@ -1432,16 +1470,14 @@ int gasket_pci_add_device(struct pci_dev *pci_dev,
struct gasket_dev **gasket_devp)
{
int ret;
- const char *kobj_name = dev_name(&pci_dev->dev);
struct gasket_internal_desc *internal_desc;
struct gasket_dev *gasket_dev;
- const struct gasket_driver_desc *driver_desc;
struct device *parent;
- pr_debug("add PCI device %s\n", kobj_name);
+ dev_dbg(&pci_dev->dev, "add PCI gasket device\n");
mutex_lock(&g_mutex);
- internal_desc = lookup_internal_desc(pci_dev);
+ internal_desc = lookup_pci_internal_desc(pci_dev);
mutex_unlock(&g_mutex);
if (!internal_desc) {
dev_err(&pci_dev->dev,
@@ -1449,29 +1485,15 @@ int gasket_pci_add_device(struct pci_dev *pci_dev,
return -ENODEV;
}
- driver_desc = internal_desc->driver_desc;
-
parent = &pci_dev->dev;
- ret = gasket_alloc_dev(internal_desc, parent, &gasket_dev, kobj_name);
+ ret = __gasket_add_device(parent, internal_desc, &gasket_dev);
if (ret)
return ret;
- gasket_dev->pci_dev = pci_dev;
- if (IS_ERR_OR_NULL(gasket_dev->dev_info.device)) {
- pr_err("Cannot create %s device %s [ret = %ld]\n",
- driver_desc->name, gasket_dev->dev_info.name,
- PTR_ERR(gasket_dev->dev_info.device));
- ret = -ENODEV;
- goto fail1;
- }
+ gasket_dev->pci_dev = pci_dev;
ret = gasket_setup_pci(pci_dev, gasket_dev);
if (ret)
- goto fail2;
-
- ret = gasket_sysfs_create_mapping(gasket_dev->dev_info.device,
- gasket_dev);
- if (ret)
- goto fail3;
+ goto cleanup_pci;
/*
* Once we've created the mapping structures successfully, attempt to
@@ -1482,24 +1504,15 @@ int gasket_pci_add_device(struct pci_dev *pci_dev,
if (ret) {
dev_err(gasket_dev->dev,
"Cannot create sysfs pci link: %d\n", ret);
- goto fail3;
+ goto cleanup_pci;
}
- ret = gasket_sysfs_create_entries(gasket_dev->dev_info.device,
- gasket_sysfs_generic_attrs);
- if (ret)
- goto fail4;
*gasket_devp = gasket_dev;
return 0;
-fail4:
-fail3:
- gasket_sysfs_remove_mapping(gasket_dev->dev_info.device);
-fail2:
+cleanup_pci:
gasket_cleanup_pci(gasket_dev);
- device_destroy(internal_desc->class, gasket_dev->dev_info.devt);
-fail1:
- gasket_free_dev(gasket_dev);
+ __gasket_remove_device(internal_desc, gasket_dev);
return ret;
}
EXPORT_SYMBOL(gasket_pci_add_device);
@@ -1510,18 +1523,15 @@ void gasket_pci_remove_device(struct pci_dev *pci_dev)
int i;
struct gasket_internal_desc *internal_desc;
struct gasket_dev *gasket_dev = NULL;
- const struct gasket_driver_desc *driver_desc;
/* Find the device desc. */
mutex_lock(&g_mutex);
- internal_desc = lookup_internal_desc(pci_dev);
+ internal_desc = lookup_pci_internal_desc(pci_dev);
if (!internal_desc) {
mutex_unlock(&g_mutex);
return;
}
mutex_unlock(&g_mutex);
- driver_desc = internal_desc->driver_desc;
-
/* Now find the specific device */
mutex_lock(&internal_desc->mutex);
for (i = 0; i < GASKET_DEV_MAX; i++) {
@@ -1540,10 +1550,7 @@ void gasket_pci_remove_device(struct pci_dev *pci_dev)
internal_desc->driver_desc->name);
gasket_cleanup_pci(gasket_dev);
-
- gasket_sysfs_remove_mapping(gasket_dev->dev_info.device);
- device_destroy(internal_desc->class, gasket_dev->dev_info.devt);
- gasket_free_dev(gasket_dev);
+ __gasket_remove_device(internal_desc, gasket_dev);
}
EXPORT_SYMBOL(gasket_pci_remove_device);
@@ -1791,7 +1798,6 @@ static int __init gasket_init(void)
{
int i;
- pr_debug("%s\n", __func__);
mutex_lock(&g_mutex);
for (i = 0; i < GASKET_FRAMEWORK_DESC_MAX; i++) {
g_descs[i].driver_desc = NULL;
@@ -1804,13 +1810,8 @@ static int __init gasket_init(void)
return 0;
}
-static void __exit gasket_exit(void)
-{
- pr_debug("%s\n", __func__);
-}
MODULE_DESCRIPTION("Google Gasket driver framework");
MODULE_VERSION(GASKET_FRAMEWORK_VERSION);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Rob Springer <rspringer@google.com>");
module_init(gasket_init);
-module_exit(gasket_exit);
diff --git a/drivers/staging/gasket/gasket_core.h b/drivers/staging/gasket/gasket_core.h
index 275fd0b345b6..be44ac1e3118 100644
--- a/drivers/staging/gasket/gasket_core.h
+++ b/drivers/staging/gasket/gasket_core.h
@@ -50,8 +50,6 @@ enum gasket_interrupt_packing {
/* Type of the interrupt supported by the device. */
enum gasket_interrupt_type {
PCI_MSIX = 0,
- PCI_MSI = 1,
- PLATFORM_WIRE = 2,
};
/*
@@ -69,12 +67,6 @@ struct gasket_interrupt_desc {
int packing;
};
-/* Offsets to the wire interrupt handling registers */
-struct gasket_wire_interrupt_offsets {
- u64 pending_bit_array;
- u64 mask_array;
-};
-
/*
* This enum is used to identify memory regions being part of the physical
* memory that belongs to a device.
@@ -231,7 +223,7 @@ struct gasket_coherent_buffer_desc {
/* Coherent buffer structure. */
struct gasket_coherent_buffer {
/* Virtual base address. */
- u8 __iomem *virt_base;
+ u8 *virt_base;
/* Physical base address. */
ulong phys_base;
@@ -384,9 +376,6 @@ struct gasket_driver_desc {
*/
struct gasket_coherent_buffer_desc coherent_buffer_description;
- /* Offset of wire interrupt registers. */
- const struct gasket_wire_interrupt_offsets *wire_interrupt_offsets;
-
/* Interrupt type. (One of gasket_interrupt_type). */
int interrupt_type;
@@ -590,25 +579,25 @@ const char *gasket_num_name_lookup(uint num,
static inline ulong gasket_dev_read_64(struct gasket_dev *gasket_dev, int bar,
ulong location)
{
- return readq(&gasket_dev->bar_data[bar].virt_base[location]);
+ return readq_relaxed(&gasket_dev->bar_data[bar].virt_base[location]);
}
static inline void gasket_dev_write_64(struct gasket_dev *dev, u64 value,
int bar, ulong location)
{
- writeq(value, &dev->bar_data[bar].virt_base[location]);
+ writeq_relaxed(value, &dev->bar_data[bar].virt_base[location]);
}
static inline void gasket_dev_write_32(struct gasket_dev *dev, u32 value,
int bar, ulong location)
{
- writel(value, &dev->bar_data[bar].virt_base[location]);
+ writel_relaxed(value, &dev->bar_data[bar].virt_base[location]);
}
static inline u32 gasket_dev_read_32(struct gasket_dev *dev, int bar,
ulong location)
{
- return readl(&dev->bar_data[bar].virt_base[location]);
+ return readl_relaxed(&dev->bar_data[bar].virt_base[location]);
}
static inline void gasket_read_modify_write_64(struct gasket_dev *dev, int bar,
diff --git a/drivers/staging/gasket/gasket_interrupt.c b/drivers/staging/gasket/gasket_interrupt.c
index 1cfbc120f228..49d47afad64f 100644
--- a/drivers/staging/gasket/gasket_interrupt.c
+++ b/drivers/staging/gasket/gasket_interrupt.c
@@ -45,9 +45,6 @@ struct gasket_interrupt_data {
/* The width of a single interrupt in a packed interrupt register. */
int pack_width;
- /* offset of wire interrupt registers */
- const struct gasket_wire_interrupt_offsets *wire_interrupt_offsets;
-
/*
* Design-wise, these elements should be bundled together, but
* pci_enable_msix's interface requires that they be managed
@@ -92,19 +89,6 @@ static void gasket_interrupt_setup(struct gasket_dev *gasket_dev)
dev_dbg(gasket_dev->dev, "Running interrupt setup\n");
- if (interrupt_data->type == PLATFORM_WIRE ||
- interrupt_data->type == PCI_MSI) {
- /* Nothing needs to be done for platform or PCI devices. */
- return;
- }
-
- if (interrupt_data->type != PCI_MSIX) {
- dev_dbg(gasket_dev->dev,
- "Cannot handle unsupported interrupt type %d\n",
- interrupt_data->type);
- return;
- }
-
/* Setup the MSIX table. */
for (i = 0; i < interrupt_data->num_interrupts; i++) {
@@ -157,9 +141,22 @@ static void gasket_interrupt_setup(struct gasket_dev *gasket_dev)
}
}
-static irqreturn_t gasket_msix_interrupt_handler(int irq, void *dev_id)
+static void
+gasket_handle_interrupt(struct gasket_interrupt_data *interrupt_data,
+ int interrupt_index)
{
struct eventfd_ctx *ctx;
+
+ trace_gasket_interrupt_event(interrupt_data->name, interrupt_index);
+ ctx = interrupt_data->eventfd_ctxs[interrupt_index];
+ if (ctx)
+ eventfd_signal(ctx, 1);
+
+ ++(interrupt_data->interrupt_counts[interrupt_index]);
+}
+
+static irqreturn_t gasket_msix_interrupt_handler(int irq, void *dev_id)
+{
struct gasket_interrupt_data *interrupt_data = dev_id;
int interrupt = -1;
int i;
@@ -175,14 +172,7 @@ static irqreturn_t gasket_msix_interrupt_handler(int irq, void *dev_id)
pr_err("Received unknown irq %d\n", irq);
return IRQ_HANDLED;
}
- trace_gasket_interrupt_event(interrupt_data->name, interrupt);
-
- ctx = interrupt_data->eventfd_ctxs[interrupt];
- if (ctx)
- eventfd_signal(ctx, 1);
-
- ++(interrupt_data->interrupt_counts[interrupt]);
-
+ gasket_handle_interrupt(interrupt_data, interrupt);
return IRQ_HANDLED;
}
@@ -192,6 +182,12 @@ gasket_interrupt_msix_init(struct gasket_interrupt_data *interrupt_data)
int ret = 1;
int i;
+ interrupt_data->msix_entries =
+ kcalloc(interrupt_data->num_interrupts,
+ sizeof(struct msix_entry), GFP_KERNEL);
+ if (!interrupt_data->msix_entries)
+ return -ENOMEM;
+
for (i = 0; i < interrupt_data->num_interrupts; i++) {
interrupt_data->msix_entries[i].entry = i;
interrupt_data->msix_entries[i].vector = 0;
@@ -319,54 +315,40 @@ static struct gasket_sysfs_attribute interrupt_sysfs_attrs[] = {
GASKET_END_OF_ATTR_ARRAY,
};
-int gasket_interrupt_init(struct gasket_dev *gasket_dev, const char *name,
- int type,
- const struct gasket_interrupt_desc *interrupts,
- int num_interrupts, int pack_width, int bar_index,
- const struct gasket_wire_interrupt_offsets *wire_int_offsets)
+int gasket_interrupt_init(struct gasket_dev *gasket_dev)
{
int ret;
struct gasket_interrupt_data *interrupt_data;
+ const struct gasket_driver_desc *driver_desc =
+ gasket_get_driver_desc(gasket_dev);
interrupt_data = kzalloc(sizeof(struct gasket_interrupt_data),
GFP_KERNEL);
if (!interrupt_data)
return -ENOMEM;
gasket_dev->interrupt_data = interrupt_data;
- interrupt_data->name = name;
- interrupt_data->type = type;
+ interrupt_data->name = driver_desc->name;
+ interrupt_data->type = driver_desc->interrupt_type;
interrupt_data->pci_dev = gasket_dev->pci_dev;
- interrupt_data->num_interrupts = num_interrupts;
- interrupt_data->interrupts = interrupts;
- interrupt_data->interrupt_bar_index = bar_index;
- interrupt_data->pack_width = pack_width;
+ interrupt_data->num_interrupts = driver_desc->num_interrupts;
+ interrupt_data->interrupts = driver_desc->interrupts;
+ interrupt_data->interrupt_bar_index = driver_desc->interrupt_bar_index;
+ interrupt_data->pack_width = driver_desc->interrupt_pack_width;
interrupt_data->num_configured = 0;
- interrupt_data->wire_interrupt_offsets = wire_int_offsets;
- /* Allocate all dynamic structures. */
- interrupt_data->msix_entries = kcalloc(num_interrupts,
- sizeof(struct msix_entry),
- GFP_KERNEL);
- if (!interrupt_data->msix_entries) {
- kfree(interrupt_data);
- return -ENOMEM;
- }
-
- interrupt_data->eventfd_ctxs = kcalloc(num_interrupts,
+ interrupt_data->eventfd_ctxs = kcalloc(driver_desc->num_interrupts,
sizeof(struct eventfd_ctx *),
GFP_KERNEL);
if (!interrupt_data->eventfd_ctxs) {
- kfree(interrupt_data->msix_entries);
kfree(interrupt_data);
return -ENOMEM;
}
- interrupt_data->interrupt_counts = kcalloc(num_interrupts,
+ interrupt_data->interrupt_counts = kcalloc(driver_desc->num_interrupts,
sizeof(ulong),
GFP_KERNEL);
if (!interrupt_data->interrupt_counts) {
kfree(interrupt_data->eventfd_ctxs);
- kfree(interrupt_data->msix_entries);
kfree(interrupt_data);
return -ENOMEM;
}
@@ -379,12 +361,7 @@ int gasket_interrupt_init(struct gasket_dev *gasket_dev, const char *name,
force_msix_interrupt_unmasking(gasket_dev);
break;
- case PCI_MSI:
- case PLATFORM_WIRE:
default:
- dev_err(gasket_dev->dev,
- "Cannot handle unsupported interrupt type %d\n",
- interrupt_data->type);
ret = -EINVAL;
}
@@ -417,6 +394,7 @@ gasket_interrupt_msix_cleanup(struct gasket_interrupt_data *interrupt_data)
if (interrupt_data->msix_configured)
pci_disable_msix(interrupt_data->pci_dev);
interrupt_data->msix_configured = 0;
+ kfree(interrupt_data->msix_entries);
}
int gasket_interrupt_reinit(struct gasket_dev *gasket_dev)
@@ -438,20 +416,16 @@ int gasket_interrupt_reinit(struct gasket_dev *gasket_dev)
force_msix_interrupt_unmasking(gasket_dev);
break;
- case PCI_MSI:
- case PLATFORM_WIRE:
default:
- dev_dbg(gasket_dev->dev,
- "Cannot handle unsupported interrupt type %d\n",
- gasket_dev->interrupt_data->type);
ret = -EINVAL;
}
if (ret) {
- /* Failing to setup MSIx will cause the device
+ /* Failing to setup interrupts will cause the device
* to report GASKET_STATUS_LAMED, but is not fatal.
*/
- dev_warn(gasket_dev->dev, "Couldn't init msix: %d\n", ret);
+ dev_warn(gasket_dev->dev, "Couldn't reinit interrupts: %d\n",
+ ret);
return 0;
}
@@ -487,17 +461,12 @@ void gasket_interrupt_cleanup(struct gasket_dev *gasket_dev)
gasket_interrupt_msix_cleanup(interrupt_data);
break;
- case PCI_MSI:
- case PLATFORM_WIRE:
default:
- dev_dbg(gasket_dev->dev,
- "Cannot handle unsupported interrupt type %d\n",
- interrupt_data->type);
+ break;
}
kfree(interrupt_data->interrupt_counts);
kfree(interrupt_data->eventfd_ctxs);
- kfree(interrupt_data->msix_entries);
kfree(interrupt_data);
gasket_dev->interrupt_data = NULL;
}
@@ -509,11 +478,6 @@ int gasket_interrupt_system_status(struct gasket_dev *gasket_dev)
return GASKET_STATUS_DEAD;
}
- if (!gasket_dev->interrupt_data->msix_configured) {
- dev_dbg(gasket_dev->dev, "Interrupt not initialized\n");
- return GASKET_STATUS_LAMED;
- }
-
if (gasket_dev->interrupt_data->num_configured !=
gasket_dev->interrupt_data->num_interrupts) {
dev_dbg(gasket_dev->dev,
diff --git a/drivers/staging/gasket/gasket_interrupt.h b/drivers/staging/gasket/gasket_interrupt.h
index 835af439e96a..85526a1374a1 100644
--- a/drivers/staging/gasket/gasket_interrupt.h
+++ b/drivers/staging/gasket/gasket_interrupt.h
@@ -24,30 +24,8 @@ struct gasket_interrupt_data;
/*
* Initialize the interrupt module.
* @gasket_dev: The Gasket device structure for the device to be initted.
- * @type: Type of the interrupt. (See gasket_interrupt_type).
- * @name: The name to associate with these interrupts.
- * @interrupts: An array of all interrupt descriptions for this device.
- * @num_interrupts: The length of the @interrupts array.
- * @pack_width: The width, in bits, of a single field in a packed interrupt reg.
- * @bar_index: The bar containing all interrupt registers.
- *
- * Allocates and initializes data to track interrupt state for a device.
- * After this call, no interrupts will be configured/delivered; call
- * gasket_interrupt_set_vector[_packed] to associate each interrupt with an
- * __iomem location, then gasket_interrupt_set_eventfd to associate an eventfd
- * with an interrupt.
- *
- * If num_interrupts interrupts are not available, this call will return a
- * negative error code. In that case, gasket_interrupt_cleanup should still be
- * called. Returns 0 on success (which can include a device where interrupts
- * are not possible to set up, but is otherwise OK; that device will report
- * status LAMED.)
*/
-int gasket_interrupt_init(struct gasket_dev *gasket_dev, const char *name,
- int type,
- const struct gasket_interrupt_desc *interrupts,
- int num_interrupts, int pack_width, int bar_index,
- const struct gasket_wire_interrupt_offsets *wire_int_offsets);
+int gasket_interrupt_init(struct gasket_dev *gasket_dev);
/*
* Clean up a device's interrupt structure.
diff --git a/drivers/staging/gasket/gasket_page_table.c b/drivers/staging/gasket/gasket_page_table.c
index d4c5f8aa7dd3..b7d460cf15fb 100644
--- a/drivers/staging/gasket/gasket_page_table.c
+++ b/drivers/staging/gasket/gasket_page_table.c
@@ -10,10 +10,18 @@
*
* This file assumes 4kB pages throughout; can be factored out when necessary.
*
- * Address format is as follows:
+ * There is a configurable number of page table entries, as well as a
+ * configurable bit index for the extended address flag. Both of these are
+ * specified in gasket_page_table_init through the page_table_config parameter.
+ *
+ * The following example assumes:
+ * page_table_config->total_entries = 8192
+ * page_table_config->extended_bit = 63
+ *
+ * Address format:
* Simple addresses - those whose containing pages are directly placed in the
* device's address translation registers - are laid out as:
- * [ 63 - 40: Unused | 39 - 28: 0 | 27 - 12: page index | 11 - 0: page offset ]
+ * [ 63 - 25: 0 | 24 - 12: page index | 11 - 0: page offset ]
* page index: The index of the containing page in the device's address
* translation registers.
* page offset: The index of the address into the containing page.
@@ -21,7 +29,7 @@
* Extended address - those whose containing pages are contained in a second-
* level page table whose address is present in the device's address translation
* registers - are laid out as:
- * [ 63 - 40: Unused | 39: flag | 38 - 37: 0 | 36 - 21: dev/level 0 index |
+ * [ 63: flag | 62 - 34: 0 | 33 - 21: dev/level 0 index |
* 20 - 12: host/level 1 index | 11 - 0: page offset ]
* flag: Marker indicating that this is an extended address. Always 1.
* dev index: The index of the first-level page in the device's extended
@@ -103,12 +111,6 @@ struct gasket_page_table_entry {
/* The status of this entry/slot: free or in use. */
enum pte_status status;
- /* Address of the page in DMA space. */
- dma_addr_t dma_addr;
-
- /* Linux page descriptor for the page described by this structure. */
- struct page *page;
-
/*
* Index for alignment into host vaddrs.
* When a user specifies a host address for a mapping, that address may
@@ -119,6 +121,12 @@ struct gasket_page_table_entry {
*/
int offset;
+ /* Address of the page in DMA space. */
+ dma_addr_t dma_addr;
+
+ /* Linux page descriptor for the page described by this structure. */
+ struct page *page;
+
/*
* If this is an extended and first-level entry, sublevel points
* to the second-level entries underneath this entry.
@@ -317,12 +325,10 @@ static void gasket_free_extended_subtable(struct gasket_page_table *pg_tbl,
/* Release the page table from the device */
writeq(0, slot);
- /* Force sync around the address release. */
- mb();
if (pte->dma_addr)
dma_unmap_page(pg_tbl->device, pte->dma_addr, PAGE_SIZE,
- DMA_BIDIRECTIONAL);
+ DMA_TO_DEVICE);
vfree(pte->sublevel);
@@ -435,6 +441,19 @@ static int is_coherent(struct gasket_page_table *pg_tbl, ulong host_addr)
return min <= host_addr && host_addr < max;
}
+/* Safely return a page to the OS. */
+static bool gasket_release_page(struct page *page)
+{
+ if (!page)
+ return false;
+
+ if (!PageReserved(page))
+ SetPageDirty(page);
+ put_page(page);
+
+ return true;
+}
+
/*
* Get and map last level page table buffers.
*
@@ -458,7 +477,6 @@ static int gasket_perform_mapping(struct gasket_page_table *pg_tbl,
for (i = 0; i < num_pages; i++) {
page_addr = host_addr + i * PAGE_SIZE;
offset = page_addr & (PAGE_SIZE - 1);
- dev_dbg(pg_tbl->device, "%s i %d\n", __func__, i);
if (is_coherent(pg_tbl, host_addr)) {
u64 off =
(u64)host_addr -
@@ -487,24 +505,16 @@ static int gasket_perform_mapping(struct gasket_page_table *pg_tbl,
ptes[i].dma_addr =
dma_map_page(pg_tbl->device, page, 0, PAGE_SIZE,
DMA_BIDIRECTIONAL);
- dev_dbg(pg_tbl->device,
- "%s i %d pte %p pfn %p -> mapped %llx\n",
- __func__, i, &ptes[i],
- (void *)page_to_pfn(page),
- (unsigned long long)ptes[i].dma_addr);
-
- if (ptes[i].dma_addr == -1) {
- dev_dbg(pg_tbl->device,
- "%s i %d -> fail to map page %llx "
- "[pfn %p ohys %p]\n",
- __func__, i,
- (unsigned long long)ptes[i].dma_addr,
- (void *)page_to_pfn(page),
- (void *)page_to_phys(page));
- return -1;
+
+ if (dma_mapping_error(pg_tbl->device,
+ ptes[i].dma_addr)) {
+ if (gasket_release_page(ptes[i].page))
+ --pg_tbl->num_active_pages;
+
+ memset(&ptes[i], 0,
+ sizeof(struct gasket_page_table_entry));
+ return -EINVAL;
}
- /* Wait until the page is mapped. */
- mb();
}
/* Make the DMA-space address available to the device. */
@@ -545,7 +555,7 @@ static ulong gasket_extended_lvl0_page_idx(struct gasket_page_table *pg_tbl,
ulong dev_addr)
{
return (dev_addr >> GASKET_EXTENDED_LVL0_SHIFT) &
- ((1 << GASKET_EXTENDED_LVL0_WIDTH) - 1);
+ (pg_tbl->config.total_entries - 1);
}
/*
@@ -574,19 +584,6 @@ static int gasket_alloc_simple_entries(struct gasket_page_table *pg_tbl,
return 0;
}
-/* Safely return a page to the OS. */
-static bool gasket_release_page(struct page *page)
-{
- if (!page)
- return false;
-
- if (!PageReserved(page))
- SetPageDirty(page);
- put_page(page);
-
- return true;
-}
-
/*
* Unmap and release mapped pages.
* The page table mutex must be held by the caller.
@@ -603,23 +600,23 @@ static void gasket_perform_unmapping(struct gasket_page_table *pg_tbl,
*/
for (i = 0; i < num_pages; i++) {
/* release the address from the device, */
- if (is_simple_mapping || ptes[i].status == PTE_INUSE)
+ if (is_simple_mapping || ptes[i].status == PTE_INUSE) {
writeq(0, &slots[i]);
- else
+ } else {
((u64 __force *)slots)[i] = 0;
- /* Force sync around the address release. */
- mb();
+ /* sync above PTE update before updating mappings */
+ wmb();
+ }
/* release the address from the driver, */
if (ptes[i].status == PTE_INUSE) {
- if (ptes[i].dma_addr) {
+ if (ptes[i].page && ptes[i].dma_addr) {
dma_unmap_page(pg_tbl->device, ptes[i].dma_addr,
- PAGE_SIZE, DMA_FROM_DEVICE);
+ PAGE_SIZE, DMA_BIDIRECTIONAL);
}
if (gasket_release_page(ptes[i].page))
--pg_tbl->num_active_pages;
}
- ptes[i].status = PTE_FREE;
/* and clear the PTE. */
memset(&ptes[i], 0, sizeof(struct gasket_page_table_entry));
@@ -684,38 +681,21 @@ static inline bool gasket_addr_is_simple(struct gasket_page_table *pg_tbl,
* Convert (simple, page, offset) into a device address.
* Examples:
* Simple page 0, offset 32:
- * Input (0, 0, 32), Output 0x20
+ * Input (1, 0, 32), Output 0x20
* Simple page 1000, offset 511:
- * Input (0, 1000, 512), Output 0x3E81FF
+ * Input (1, 1000, 511), Output 0x3E81FF
* Extended page 0, offset 32:
* Input (0, 0, 32), Output 0x8000000020
* Extended page 1000, offset 511:
- * Input (1, 1000, 512), Output 0x8003E81FF
+ * Input (0, 1000, 511), Output 0x8003E81FF
*/
static ulong gasket_components_to_dev_address(struct gasket_page_table *pg_tbl,
int is_simple, uint page_index,
uint offset)
{
- ulong lvl0_index, lvl1_index;
-
- if (is_simple) {
- /* Return simple addresses directly. */
- lvl0_index = page_index & (pg_tbl->config.total_entries - 1);
- return (lvl0_index << GASKET_SIMPLE_PAGE_SHIFT) | offset;
- }
+ ulong dev_addr = (page_index << GASKET_SIMPLE_PAGE_SHIFT) | offset;
- /*
- * This could be compressed into fewer statements, but
- * A) the compiler should optimize it
- * B) this is not slow
- * C) this is an uncommon operation
- * D) this is actually readable this way.
- */
- lvl0_index = page_index / GASKET_PAGES_PER_SUBTABLE;
- lvl1_index = page_index & (GASKET_PAGES_PER_SUBTABLE - 1);
- return (pg_tbl)->extended_flag |
- (lvl0_index << GASKET_EXTENDED_LVL0_SHIFT) |
- (lvl1_index << GASKET_EXTENDED_LVL1_SHIFT) | offset;
+ return is_simple ? dev_addr : (pg_tbl->extended_flag | dev_addr);
}
/*
@@ -896,9 +876,13 @@ static int gasket_alloc_extended_subtable(struct gasket_page_table *pg_tbl,
/* Map the page into DMA space. */
pte->dma_addr = dma_map_page(pg_tbl->device, pte->page, 0, PAGE_SIZE,
- DMA_BIDIRECTIONAL);
- /* Wait until the page is mapped. */
- mb();
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(pg_tbl->device, pte->dma_addr)) {
+ free_page(page_addr);
+ vfree(pte->sublevel);
+ memset(pte, 0, sizeof(struct gasket_page_table_entry));
+ return -ENOMEM;
+ }
/* make the addresses available to the device */
dma_addr = (pte->dma_addr + pte->offset) | GASKET_VALID_SLOT_FLAG;
@@ -1047,11 +1031,6 @@ int gasket_page_table_map(struct gasket_page_table *pg_tbl, ulong host_addr,
}
mutex_unlock(&pg_tbl->mutex);
-
- dev_dbg(pg_tbl->device,
- "%s done: ha %llx daddr %llx num %d, ret %d\n",
- __func__, (unsigned long long)host_addr,
- (unsigned long long)dev_addr, num_pages, ret);
return ret;
}
EXPORT_SYMBOL(gasket_page_table_map);
@@ -1151,7 +1130,7 @@ fail:
*ppage = NULL;
*poffset = 0;
mutex_unlock(&pg_tbl->mutex);
- return -1;
+ return -EINVAL;
}
/* See gasket_page_table.h for description. */
@@ -1291,7 +1270,7 @@ int gasket_alloc_coherent_memory(struct gasket_dev *gasket_dev, u64 size,
return -EINVAL;
mem = dma_alloc_coherent(gasket_get_device(gasket_dev),
- num_pages * PAGE_SIZE, &handle, 0);
+ num_pages * PAGE_SIZE, &handle, GFP_KERNEL);
if (!mem)
goto nomem;
@@ -1303,7 +1282,6 @@ int gasket_alloc_coherent_memory(struct gasket_dev *gasket_dev, u64 size,
GFP_KERNEL);
if (!gasket_dev->page_table[index]->coherent_pages)
goto nomem;
- *dma_address = 0;
gasket_dev->coherent_buffer.length_bytes =
PAGE_SIZE * (num_pages);
@@ -1318,20 +1296,19 @@ int gasket_alloc_coherent_memory(struct gasket_dev *gasket_dev, u64 size,
(u64)mem + j * PAGE_SIZE;
}
- if (*dma_address == 0)
- goto nomem;
return 0;
nomem:
if (mem) {
dma_free_coherent(gasket_get_device(gasket_dev),
num_pages * PAGE_SIZE, mem, handle);
+ gasket_dev->coherent_buffer.length_bytes = 0;
+ gasket_dev->coherent_buffer.virt_base = NULL;
+ gasket_dev->coherent_buffer.phys_base = 0;
}
- if (gasket_dev->page_table[index]->coherent_pages) {
- kfree(gasket_dev->page_table[index]->coherent_pages);
- gasket_dev->page_table[index]->coherent_pages = NULL;
- }
+ kfree(gasket_dev->page_table[index]->coherent_pages);
+ gasket_dev->page_table[index]->coherent_pages = NULL;
gasket_dev->page_table[index]->num_coherent_pages = 0;
return -ENOMEM;
}
@@ -1359,6 +1336,11 @@ int gasket_free_coherent_memory(struct gasket_dev *gasket_dev, u64 size,
gasket_dev->coherent_buffer.virt_base = NULL;
gasket_dev->coherent_buffer.phys_base = 0;
}
+
+ kfree(gasket_dev->page_table[index]->coherent_pages);
+ gasket_dev->page_table[index]->coherent_pages = NULL;
+ gasket_dev->page_table[index]->num_coherent_pages = 0;
+
return 0;
}
diff --git a/drivers/staging/gasket/gasket_sysfs.h b/drivers/staging/gasket/gasket_sysfs.h
index f32eaf89e056..151e8edd28ea 100644
--- a/drivers/staging/gasket/gasket_sysfs.h
+++ b/drivers/staging/gasket/gasket_sysfs.h
@@ -152,8 +152,8 @@ void gasket_sysfs_put_device_data(struct device *device,
* Returns the Gasket sysfs attribute associated with the kernel device
* attribute and device structure itself. Upon success, this call will take a
* reference to internal sysfs data that must be released with a call to
- * gasket_sysfs_get_device_data. While this reference is held, the underlying
- * device sysfs information/structure will remain valid/will not be deleted.
+ * gasket_sysfs_put_attr. While this reference is held, the underlying device
+ * sysfs information/structure will remain valid/will not be deleted.
*/
struct gasket_sysfs_attribute *
gasket_sysfs_get_attr(struct device *device, struct device_attribute *attr);
diff --git a/drivers/staging/greybus/audio_codec.c b/drivers/staging/greybus/audio_codec.c
index 35acd55ca5ab..08746c85dea6 100644
--- a/drivers/staging/greybus/audio_codec.c
+++ b/drivers/staging/greybus/audio_codec.c
@@ -1087,7 +1087,6 @@ static const struct of_device_id greybus_asoc_machine_of_match[] = {
static struct platform_driver gbaudio_codec_driver = {
.driver = {
.name = "apb-dummy-codec",
- .owner = THIS_MODULE,
#ifdef CONFIG_PM
.pm = &gbaudio_codec_pm_ops,
#endif
diff --git a/drivers/staging/greybus/loopback.c b/drivers/staging/greybus/loopback.c
index 42f6f3de967c..7080294f705c 100644
--- a/drivers/staging/greybus/loopback.c
+++ b/drivers/staging/greybus/loopback.c
@@ -97,7 +97,6 @@ struct gb_loopback {
u32 timeout_min;
u32 timeout_max;
u32 outstanding_operations_max;
- u32 lbid;
u64 elapsed_nsecs;
u32 apbridge_latency_ts;
u32 gbphy_latency_ts;
@@ -1014,16 +1013,9 @@ static int gb_loopback_bus_id_compare(void *priv, struct list_head *lha,
static void gb_loopback_insert_id(struct gb_loopback *gb)
{
- struct gb_loopback *gb_list;
- u32 new_lbid = 0;
-
/* perform an insertion sort */
list_add_tail(&gb->entry, &gb_dev.list);
list_sort(NULL, &gb_dev.list, gb_loopback_bus_id_compare);
- list_for_each_entry(gb_list, &gb_dev.list, entry) {
- gb_list->lbid = 1 << new_lbid;
- new_lbid++;
- }
}
#define DEBUGFS_NAMELEN 32
diff --git a/drivers/staging/greybus/tools/README.loopback b/drivers/staging/greybus/tools/README.loopback
index 845b08dc4696..070a510cbe7c 100644
--- a/drivers/staging/greybus/tools/README.loopback
+++ b/drivers/staging/greybus/tools/README.loopback
@@ -79,7 +79,7 @@ Here is the summary of the available options:
-t must be one of the test names - sink, transfer or ping
-i iteration count - the number of iterations to run the test over
Optional arguments
- -S sysfs location - location for greybus 'endo' entires default /sys/bus/greybus/devices/
+ -S sysfs location - location for greybus 'endo' entries default /sys/bus/greybus/devices/
-D debugfs location - location for loopback debugfs entries default /sys/kernel/debug/gb_loopback/
-s size of data packet to send during test - defaults to zero
-m mask - a bit mask of connections to include example: -m 8 = 4th connection -m 9 = 1st and 4th connection etc
diff --git a/drivers/staging/greybus/tools/loopback_test.c b/drivers/staging/greybus/tools/loopback_test.c
index b82e2befe935..2fa88092514d 100644
--- a/drivers/staging/greybus/tools/loopback_test.c
+++ b/drivers/staging/greybus/tools/loopback_test.c
@@ -192,7 +192,7 @@ void usage(void)
" -t must be one of the test names - sink, transfer or ping\n"
" -i iteration count - the number of iterations to run the test over\n"
" Optional arguments\n"
- " -S sysfs location - location for greybus 'endo' entires default /sys/bus/greybus/devices/\n"
+ " -S sysfs location - location for greybus 'endo' entries default /sys/bus/greybus/devices/\n"
" -D debugfs location - location for loopback debugfs entries default /sys/kernel/debug/gb_loopback/\n"
" -s size of data packet to send during test - defaults to zero\n"
" -m mask - a bit mask of connections to include example: -m 8 = 4th connection -m 9 = 1st and 4th connection etc\n"
diff --git a/drivers/staging/greybus/uart.c b/drivers/staging/greybus/uart.c
index 8a006323c3c1..3313cb0b60af 100644
--- a/drivers/staging/greybus/uart.c
+++ b/drivers/staging/greybus/uart.c
@@ -616,40 +616,33 @@ static void gb_tty_unthrottle(struct tty_struct *tty)
}
}
-static int get_serial_info(struct gb_tty *gb_tty,
- struct serial_struct __user *info)
+static int get_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
- struct serial_struct tmp;
-
- memset(&tmp, 0, sizeof(tmp));
- tmp.type = PORT_16550A;
- tmp.line = gb_tty->minor;
- tmp.xmit_fifo_size = 16;
- tmp.baud_base = 9600;
- tmp.close_delay = gb_tty->port.close_delay / 10;
- tmp.closing_wait =
+ struct gb_tty *gb_tty = tty->driver_data;
+
+ ss->type = PORT_16550A;
+ ss->line = gb_tty->minor;
+ ss->xmit_fifo_size = 16;
+ ss->baud_base = 9600;
+ ss->close_delay = gb_tty->port.close_delay / 10;
+ ss->closing_wait =
gb_tty->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
ASYNC_CLOSING_WAIT_NONE : gb_tty->port.closing_wait / 10;
-
- if (copy_to_user(info, &tmp, sizeof(tmp)))
- return -EFAULT;
return 0;
}
-static int set_serial_info(struct gb_tty *gb_tty,
- struct serial_struct __user *newinfo)
+static int set_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
- struct serial_struct new_serial;
+ struct gb_tty *gb_tty = tty->driver_data;
unsigned int closing_wait;
unsigned int close_delay;
int retval = 0;
- if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
- return -EFAULT;
-
- close_delay = new_serial.close_delay * 10;
- closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
- ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10;
+ close_delay = ss->close_delay * 10;
+ closing_wait = ss->closing_wait == ASYNC_CLOSING_WAIT_NONE ?
+ ASYNC_CLOSING_WAIT_NONE : ss->closing_wait * 10;
mutex_lock(&gb_tty->port.mutex);
if (!capable(CAP_SYS_ADMIN)) {
@@ -728,12 +721,6 @@ static int gb_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
struct gb_tty *gb_tty = tty->driver_data;
switch (cmd) {
- case TIOCGSERIAL:
- return get_serial_info(gb_tty,
- (struct serial_struct __user *)arg);
- case TIOCSSERIAL:
- return set_serial_info(gb_tty,
- (struct serial_struct __user *)arg);
case TIOCMIWAIT:
return wait_serial_change(gb_tty, arg);
}
@@ -818,6 +805,8 @@ static const struct tty_operations gb_ops = {
.tiocmget = gb_tty_tiocmget,
.tiocmset = gb_tty_tiocmset,
.get_icount = gb_tty_get_icount,
+ .set_serial = set_serial_info,
+ .get_serial = get_serial_info,
};
static const struct tty_port_operations gb_port_ops = {
diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig
index e17efb03bac0..9d3062a07460 100644
--- a/drivers/staging/iio/adc/Kconfig
+++ b/drivers/staging/iio/adc/Kconfig
@@ -11,7 +11,7 @@ config AD7606
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for Analog Devices:
- ad7606, ad7606-6, ad7606-4 analog to digital converters (ADC).
+ ad7605-4, ad7606, ad7606-6, ad7606-4 analog to digital converters (ADC).
To compile this driver as a module, choose M here: the
module will be called ad7606.
diff --git a/drivers/staging/iio/adc/ad7192.c b/drivers/staging/iio/adc/ad7192.c
index df0499fc4802..acdbc07fd259 100644
--- a/drivers/staging/iio/adc/ad7192.c
+++ b/drivers/staging/iio/adc/ad7192.c
@@ -761,6 +761,6 @@ static struct spi_driver ad7192_driver = {
};
module_spi_driver(ad7192_driver);
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7190, AD7192, AD7193, AD7195 ADC");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c
index b736275c10f5..58420dcb406d 100644
--- a/drivers/staging/iio/adc/ad7280a.c
+++ b/drivers/staging/iio/adc/ad7280a.c
@@ -987,6 +987,6 @@ static struct spi_driver ad7280_driver = {
};
module_spi_driver(ad7280_driver);
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7280A");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/adc/ad7606.c b/drivers/staging/iio/adc/ad7606.c
index 25b9fcd5e3a4..048c205b979e 100644
--- a/drivers/staging/iio/adc/ad7606.c
+++ b/drivers/staging/iio/adc/ad7606.c
@@ -26,9 +26,12 @@
#include "ad7606.h"
-/* Scales are computed as 2.5/2**16 and 5/2**16 respectively */
+/*
+ * Scales are computed as 5000/32768 and 10000/32768 respectively,
+ * so that when applied to the raw values they provide mV values
+ */
static const unsigned int scale_avail[2][2] = {
- {0, 38147}, {0, 76294}
+ {0, 152588}, {0, 305176}
};
static int ad7606_reset(struct ad7606_state *st)
@@ -202,7 +205,7 @@ static int ad7606_write_raw(struct iio_dev *indio_dev,
long mask)
{
struct ad7606_state *st = iio_priv(indio_dev);
- int values[3];
+ DECLARE_BITMAP(values, 3);
int ret, i;
switch (mask) {
@@ -227,12 +230,10 @@ static int ad7606_write_raw(struct iio_dev *indio_dev,
if (ret < 0)
return ret;
- values[0] = (ret >> 0) & 1;
- values[1] = (ret >> 1) & 1;
- values[2] = (ret >> 2) & 1;
+ values[0] = ret;
mutex_lock(&st->lock);
- gpiod_set_array_value(ARRAY_SIZE(values), st->gpio_os->desc,
+ gpiod_set_array_value(3, st->gpio_os->desc, st->gpio_os->info,
values);
st->oversampling = val;
mutex_unlock(&st->lock);
@@ -273,7 +274,7 @@ static const struct attribute_group ad7606_attribute_group_range = {
.attrs = ad7606_attributes_range,
};
-#define AD7606_CHANNEL(num) \
+#define AD760X_CHANNEL(num, mask) \
{ \
.type = IIO_VOLTAGE, \
.indexed = 1, \
@@ -281,8 +282,7 @@ static const struct attribute_group ad7606_attribute_group_range = {
.address = num, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),\
- .info_mask_shared_by_all = \
- BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
+ .info_mask_shared_by_all = mask, \
.scan_index = num, \
.scan_type = { \
.sign = 's', \
@@ -292,6 +292,20 @@ static const struct attribute_group ad7606_attribute_group_range = {
}, \
}
+#define AD7605_CHANNEL(num) \
+ AD760X_CHANNEL(num, 0)
+
+#define AD7606_CHANNEL(num) \
+ AD760X_CHANNEL(num, BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO))
+
+static const struct iio_chan_spec ad7605_channels[] = {
+ IIO_CHAN_SOFT_TIMESTAMP(4),
+ AD7605_CHANNEL(0),
+ AD7605_CHANNEL(1),
+ AD7605_CHANNEL(2),
+ AD7605_CHANNEL(3),
+};
+
static const struct iio_chan_spec ad7606_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(8),
AD7606_CHANNEL(0),
@@ -308,17 +322,24 @@ static const struct ad7606_chip_info ad7606_chip_info_tbl[] = {
/*
* More devices added in future
*/
+ [ID_AD7605_4] = {
+ .channels = ad7605_channels,
+ .num_channels = 5,
+ },
[ID_AD7606_8] = {
.channels = ad7606_channels,
.num_channels = 9,
+ .has_oversampling = true,
},
[ID_AD7606_6] = {
.channels = ad7606_channels,
.num_channels = 7,
+ .has_oversampling = true,
},
[ID_AD7606_4] = {
.channels = ad7606_channels,
.num_channels = 5,
+ .has_oversampling = true,
},
};
@@ -349,6 +370,9 @@ static int ad7606_request_gpios(struct ad7606_state *st)
if (IS_ERR(st->gpio_frstdata))
return PTR_ERR(st->gpio_frstdata);
+ if (!st->chip_info->has_oversampling)
+ return 0;
+
st->gpio_os = devm_gpiod_get_array_optional(dev, "oversampling-ratio",
GPIOD_OUT_LOW);
return PTR_ERR_OR_ZERO(st->gpio_os);
@@ -427,12 +451,12 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
return ret;
}
+ st->chip_info = &ad7606_chip_info_tbl[id];
+
ret = ad7606_request_gpios(st);
if (ret)
goto error_disable_reg;
- st->chip_info = &ad7606_chip_info_tbl[id];
-
indio_dev->dev.parent = dev;
if (st->gpio_os) {
if (st->gpio_range)
@@ -534,6 +558,6 @@ EXPORT_SYMBOL_GPL(ad7606_pm_ops);
#endif
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7606 ADC");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/adc/ad7606.h b/drivers/staging/iio/adc/ad7606.h
index 9716ee9d94a7..86188054b60b 100644
--- a/drivers/staging/iio/adc/ad7606.h
+++ b/drivers/staging/iio/adc/ad7606.h
@@ -11,20 +11,40 @@
/**
* struct ad7606_chip_info - chip specific information
- * @name: identification string for chip
* @channels: channel specification
* @num_channels: number of channels
- * @lock protect sensor state
+ * @has_oversampling: whether the device has oversampling support
*/
struct ad7606_chip_info {
const struct iio_chan_spec *channels;
unsigned int num_channels;
+ bool has_oversampling;
};
/**
* struct ad7606_state - driver instance specific data
- * @lock protect sensor state
+ * @dev pointer to kernel device
+ * @chip_info entry in the table of chips that describes this device
+ * @reg regulator info for the the power supply of the device
+ * @poll_work work struct for continuously reading data from the device
+ * into an IIO triggered buffer
+ * @wq_data_avail wait queue struct for buffer mode
+ * @bops bus operations (SPI or parallel)
+ * @range voltage range selection, selects which scale to apply
+ * @oversampling oversampling selection
+ * @done marks whether reading data is done
+ * @base_address address from where to read data in parallel operation
+ * @lock protect sensor state from concurrent accesses to GPIOs
+ * @gpio_convst GPIO descriptor for conversion start signal (CONVST)
+ * @gpio_reset GPIO descriptor for device hard-reset
+ * @gpio_range GPIO descriptor for range selection
+ * @gpio_standby GPIO descriptor for stand-by signal (STBY),
+ * controls power-down mode of device
+ * @gpio_frstdata GPIO descriptor for reading from device when data
+ * is being read on the first channel
+ * @gpio_os GPIO descriptors to control oversampling on the device
+ * @data buffer for reading data from the device
*/
struct ad7606_state {
@@ -55,6 +75,10 @@ struct ad7606_state {
unsigned short data[12] ____cacheline_aligned;
};
+/**
+ * struct ad7606_bus_ops - driver bus operations
+ * @read_block function pointer for reading blocks of data
+ */
struct ad7606_bus_ops {
/* more methods added in future? */
int (*read_block)(struct device *dev, int num, void *data);
@@ -66,6 +90,7 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
int ad7606_remove(struct device *dev, int irq);
enum ad7606_supported_device_ids {
+ ID_AD7605_4,
ID_AD7606_8,
ID_AD7606_6,
ID_AD7606_4
diff --git a/drivers/staging/iio/adc/ad7606_par.c b/drivers/staging/iio/adc/ad7606_par.c
index a34c2a1d5373..8bd86e727b02 100644
--- a/drivers/staging/iio/adc/ad7606_par.c
+++ b/drivers/staging/iio/adc/ad7606_par.c
@@ -79,6 +79,9 @@ static int ad7606_par_remove(struct platform_device *pdev)
static const struct platform_device_id ad7606_driver_ids[] = {
{
+ .name = "ad7605-4",
+ .driver_data = ID_AD7605_4,
+ }, {
.name = "ad7606-8",
.driver_data = ID_AD7606_8,
}, {
@@ -105,6 +108,6 @@ static struct platform_driver ad7606_driver = {
module_platform_driver(ad7606_driver);
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7606 ADC");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/adc/ad7606_spi.c b/drivers/staging/iio/adc/ad7606_spi.c
index c9b1f26685f4..b76ca5a8c059 100644
--- a/drivers/staging/iio/adc/ad7606_spi.c
+++ b/drivers/staging/iio/adc/ad7606_spi.c
@@ -55,6 +55,7 @@ static int ad7606_spi_remove(struct spi_device *spi)
}
static const struct spi_device_id ad7606_id[] = {
+ {"ad7605-4", ID_AD7605_4},
{"ad7606-8", ID_AD7606_8},
{"ad7606-6", ID_AD7606_6},
{"ad7606-4", ID_AD7606_4},
@@ -73,6 +74,6 @@ static struct spi_driver ad7606_driver = {
};
module_spi_driver(ad7606_driver);
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7606 ADC");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/adc/ad7780.c b/drivers/staging/iio/adc/ad7780.c
index 16d72072c076..b67412db0318 100644
--- a/drivers/staging/iio/adc/ad7780.c
+++ b/drivers/staging/iio/adc/ad7780.c
@@ -260,6 +260,6 @@ static struct spi_driver ad7780_driver = {
};
module_spi_driver(ad7780_driver);
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7780 and similar ADCs");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/cdc/ad7746.c b/drivers/staging/iio/cdc/ad7746.c
index f53612a6461d..0eb28fea876e 100644
--- a/drivers/staging/iio/cdc/ad7746.c
+++ b/drivers/staging/iio/cdc/ad7746.c
@@ -758,6 +758,6 @@ static struct i2c_driver ad7746_driver = {
};
module_i2c_driver(ad7746_driver);
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7746/5/7 capacitive sensor driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/frequency/ad9832.c b/drivers/staging/iio/frequency/ad9832.c
index c73eff1f8d73..a3ce50427724 100644
--- a/drivers/staging/iio/frequency/ad9832.c
+++ b/drivers/staging/iio/frequency/ad9832.c
@@ -454,6 +454,6 @@ static struct spi_driver ad9832_driver = {
};
module_spi_driver(ad9832_driver);
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD9832/AD9835 DDS");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/frequency/ad9834.c b/drivers/staging/iio/frequency/ad9834.c
index 4c6d4043903e..1e977014fe5f 100644
--- a/drivers/staging/iio/frequency/ad9834.c
+++ b/drivers/staging/iio/frequency/ad9834.c
@@ -526,6 +526,6 @@ static struct spi_driver ad9834_driver = {
};
module_spi_driver(ad9834_driver);
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD9833/AD9834/AD9837/AD9838 DDS");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c
index 14df89510396..a2370dd1e1a8 100644
--- a/drivers/staging/iio/impedance-analyzer/ad5933.c
+++ b/drivers/staging/iio/impedance-analyzer/ad5933.c
@@ -797,6 +797,6 @@ static struct i2c_driver ad5933_driver = {
};
module_i2c_driver(ad5933_driver);
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD5933 Impedance Conv. Network Analyzer");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/ks7010/ks_hostif.c b/drivers/staging/ks7010/ks_hostif.c
index 0e554e3359b5..065bce193fac 100644
--- a/drivers/staging/ks7010/ks_hostif.c
+++ b/drivers/staging/ks7010/ks_hostif.c
@@ -191,7 +191,6 @@ static u8 read_ie(unsigned char *bp, u8 max, u8 *body)
return size;
}
-
static
int get_ap_information(struct ks_wlan_private *priv, struct ap_info *ap_info,
struct local_ap *ap)
@@ -1023,8 +1022,8 @@ int hostif_data_request(struct ks_wlan_private *priv, struct sk_buff *skb)
priv->wpa.mic_failure.stop) {
if (netif_queue_stopped(priv->net_dev))
netif_wake_queue(priv->net_dev);
- if (skb)
- dev_kfree_skb(skb);
+
+ dev_kfree_skb(skb);
return 0;
}
diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig
index db5cf67047ad..b3620a8f2d9f 100644
--- a/drivers/staging/media/Kconfig
+++ b/drivers/staging/media/Kconfig
@@ -31,6 +31,8 @@ source "drivers/staging/media/mt9t031/Kconfig"
source "drivers/staging/media/omap4iss/Kconfig"
+source "drivers/staging/media/sunxi/Kconfig"
+
source "drivers/staging/media/tegra-vde/Kconfig"
source "drivers/staging/media/zoran/Kconfig"
diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile
index 503fbe47fa58..42948f805548 100644
--- a/drivers/staging/media/Makefile
+++ b/drivers/staging/media/Makefile
@@ -5,5 +5,6 @@ obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074/
obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031/
obj-$(CONFIG_VIDEO_DM365_VPFE) += davinci_vpfe/
obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/
+obj-$(CONFIG_VIDEO_SUNXI) += sunxi/
obj-$(CONFIG_TEGRA_VDE) += tegra-vde/
obj-$(CONFIG_VIDEO_ZORAN) += zoran/
diff --git a/drivers/staging/media/bcm2048/radio-bcm2048.c b/drivers/staging/media/bcm2048/radio-bcm2048.c
index a90b2eb112f9..874d290f9622 100644
--- a/drivers/staging/media/bcm2048/radio-bcm2048.c
+++ b/drivers/staging/media/bcm2048/radio-bcm2048.c
@@ -2304,9 +2304,9 @@ static int bcm2048_vidioc_querycap(struct file *file, void *priv,
{
struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file));
- strlcpy(capability->driver, BCM2048_DRIVER_NAME,
+ strscpy(capability->driver, BCM2048_DRIVER_NAME,
sizeof(capability->driver));
- strlcpy(capability->card, BCM2048_DRIVER_CARD,
+ strscpy(capability->card, BCM2048_DRIVER_CARD,
sizeof(capability->card));
snprintf(capability->bus_info, 32, "I2C: 0x%X", bdev->client->addr);
capability->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO |
diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipe.c b/drivers/staging/media/davinci_vpfe/dm365_ipipe.c
index 95942768639c..dcfeac818451 100644
--- a/drivers/staging/media/davinci_vpfe/dm365_ipipe.c
+++ b/drivers/staging/media/davinci_vpfe/dm365_ipipe.c
@@ -695,21 +695,21 @@ static int ipipe_get_gamma_params(struct vpfe_ipipe_device *ipipe, void *param)
if (!gamma->bypass_r) {
dev_err(dev,
- "ipipe_get_gamma_params: table ptr empty for R\n");
+ "%s: table ptr empty for R\n", __func__);
return -EINVAL;
}
memcpy(gamma_param->table_r, gamma->table_r,
(table_size * sizeof(struct vpfe_ipipe_gamma_entry)));
if (!gamma->bypass_g) {
- dev_err(dev, "ipipe_get_gamma_params: table ptr empty for G\n");
+ dev_err(dev, "%s: table ptr empty for G\n", __func__);
return -EINVAL;
}
memcpy(gamma_param->table_g, gamma->table_g,
(table_size * sizeof(struct vpfe_ipipe_gamma_entry)));
if (!gamma->bypass_b) {
- dev_err(dev, "ipipe_get_gamma_params: table ptr empty for B\n");
+ dev_err(dev, "%s: table ptr empty for B\n", __func__);
return -EINVAL;
}
memcpy(gamma_param->table_b, gamma->table_b,
@@ -1801,7 +1801,7 @@ vpfe_ipipe_init(struct vpfe_ipipe_device *ipipe, struct platform_device *pdev)
v4l2_subdev_init(sd, &ipipe_v4l2_ops);
sd->internal_ops = &ipipe_v4l2_internal_ops;
- strlcpy(sd->name, "DAVINCI IPIPE", sizeof(sd->name));
+ strscpy(sd->name, "DAVINCI IPIPE", sizeof(sd->name));
sd->grp_id = 1 << 16; /* group ID for davinci subdevs */
v4l2_set_subdevdata(sd, ipipe);
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c b/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c
index 11c9edfbdbe3..a53231b08d30 100644
--- a/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c
+++ b/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c
@@ -1020,7 +1020,7 @@ int vpfe_ipipeif_init(struct vpfe_ipipeif_device *ipipeif,
v4l2_subdev_init(sd, &ipipeif_v4l2_ops);
sd->internal_ops = &ipipeif_v4l2_internal_ops;
- strlcpy(sd->name, "DAVINCI IPIPEIF", sizeof(sd->name));
+ strscpy(sd->name, "DAVINCI IPIPEIF", sizeof(sd->name));
sd->grp_id = 1 << 16; /* group ID for davinci subdevs */
v4l2_set_subdevdata(sd, ipipeif);
diff --git a/drivers/staging/media/davinci_vpfe/dm365_isif.c b/drivers/staging/media/davinci_vpfe/dm365_isif.c
index 745e33fa6bea..39eb0819ab4e 100644
--- a/drivers/staging/media/davinci_vpfe/dm365_isif.c
+++ b/drivers/staging/media/davinci_vpfe/dm365_isif.c
@@ -2038,7 +2038,7 @@ int vpfe_isif_init(struct vpfe_isif_device *isif, struct platform_device *pdev)
isif->video_out.ops = &isif_video_ops;
v4l2_subdev_init(sd, &isif_v4l2_ops);
sd->internal_ops = &isif_v4l2_internal_ops;
- strlcpy(sd->name, "DAVINCI ISIF", sizeof(sd->name));
+ strscpy(sd->name, "DAVINCI ISIF", sizeof(sd->name));
sd->grp_id = 1 << 16; /* group ID for davinci subdevs */
v4l2_set_subdevdata(sd, isif);
sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
diff --git a/drivers/staging/media/davinci_vpfe/dm365_resizer.c b/drivers/staging/media/davinci_vpfe/dm365_resizer.c
index 2b797474a344..72bbbc34d18c 100644
--- a/drivers/staging/media/davinci_vpfe/dm365_resizer.c
+++ b/drivers/staging/media/davinci_vpfe/dm365_resizer.c
@@ -499,7 +499,7 @@ resizer_configure_in_continuous_mode(struct vpfe_resizer_device *resizer)
configure_resizer_out_params(resizer, RSZ_A,
&cont_config->output1, 1, 0);
param->rsz_en[RSZ_B] = DISABLE;
- param->oper_mode = RESIZER_MODE_CONTINIOUS;
+ param->oper_mode = RESIZER_MODE_CONTINUOUS;
if (resizer->resizer_b.output == RESIZER_OUTPUT_MEMORY) {
struct v4l2_mbus_framefmt *outformat2;
@@ -1903,7 +1903,7 @@ int vpfe_resizer_init(struct vpfe_resizer_device *vpfe_rsz,
v4l2_subdev_init(sd, &resizer_v4l2_ops);
sd->internal_ops = &resizer_v4l2_internal_ops;
- strlcpy(sd->name, "DAVINCI RESIZER CROP", sizeof(sd->name));
+ strscpy(sd->name, "DAVINCI RESIZER CROP", sizeof(sd->name));
sd->grp_id = 1 << 16; /* group ID for davinci subdevs */
v4l2_set_subdevdata(sd, vpfe_rsz);
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
@@ -1927,7 +1927,7 @@ int vpfe_resizer_init(struct vpfe_resizer_device *vpfe_rsz,
v4l2_subdev_init(sd, &resizer_v4l2_ops);
sd->internal_ops = &resizer_v4l2_internal_ops;
- strlcpy(sd->name, "DAVINCI RESIZER A", sizeof(sd->name));
+ strscpy(sd->name, "DAVINCI RESIZER A", sizeof(sd->name));
sd->grp_id = 1 << 16; /* group ID for davinci subdevs */
v4l2_set_subdevdata(sd, vpfe_rsz);
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
@@ -1949,7 +1949,7 @@ int vpfe_resizer_init(struct vpfe_resizer_device *vpfe_rsz,
v4l2_subdev_init(sd, &resizer_v4l2_ops);
sd->internal_ops = &resizer_v4l2_internal_ops;
- strlcpy(sd->name, "DAVINCI RESIZER B", sizeof(sd->name));
+ strscpy(sd->name, "DAVINCI RESIZER B", sizeof(sd->name));
sd->grp_id = 1 << 16; /* group ID for davinci subdevs */
v4l2_set_subdevdata(sd, vpfe_rsz);
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
diff --git a/drivers/staging/media/davinci_vpfe/dm365_resizer.h b/drivers/staging/media/davinci_vpfe/dm365_resizer.h
index 00e64b0d0295..cf560a33d862 100644
--- a/drivers/staging/media/davinci_vpfe/dm365_resizer.h
+++ b/drivers/staging/media/davinci_vpfe/dm365_resizer.h
@@ -23,7 +23,7 @@
#define _DAVINCI_VPFE_DM365_RESIZER_H
enum resizer_oper_mode {
- RESIZER_MODE_CONTINIOUS = 0,
+ RESIZER_MODE_CONTINUOUS = 0,
RESIZER_MODE_ONE_SHOT = 1,
};
diff --git a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c b/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c
index e55c815b9b65..bdf6ee5ad96c 100644
--- a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c
+++ b/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c
@@ -639,7 +639,8 @@ static int vpfe_probe(struct platform_device *pdev)
goto probe_disable_clock;
vpfe_dev->media_dev.dev = vpfe_dev->pdev;
- strcpy((char *)&vpfe_dev->media_dev.model, "davinci-media");
+ strscpy((char *)&vpfe_dev->media_dev.model, "davinci-media",
+ sizeof(vpfe_dev->media_dev.model));
ret = media_device_register(&vpfe_dev->media_dev);
if (ret) {
diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.c b/drivers/staging/media/davinci_vpfe/vpfe_video.c
index 1269a983455e..5e9769ea8a50 100644
--- a/drivers/staging/media/davinci_vpfe/vpfe_video.c
+++ b/drivers/staging/media/davinci_vpfe/vpfe_video.c
@@ -618,9 +618,9 @@ static int vpfe_querycap(struct file *file, void *priv,
cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT |
V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS;
- strlcpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver));
- strlcpy(cap->bus_info, "VPFE", sizeof(cap->bus_info));
- strlcpy(cap->card, vpfe_dev->cfg->card_name, sizeof(cap->card));
+ strscpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver));
+ strscpy(cap->bus_info, "VPFE", sizeof(cap->bus_info));
+ strscpy(cap->card, vpfe_dev->cfg->card_name, sizeof(cap->card));
return 0;
}
@@ -1135,10 +1135,6 @@ static int vpfe_buffer_prepare(struct vb2_buffer *vb)
v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_prepare\n");
- if (vb->state != VB2_BUF_STATE_ACTIVE &&
- vb->state != VB2_BUF_STATE_PREPARED)
- return 0;
-
/* Initialize buffer */
vb2_set_plane_payload(vb, 0, video->fmt.fmt.pix.sizeimage);
if (vb2_plane_vaddr(vb, 0) &&
@@ -1429,7 +1425,8 @@ static int vpfe_qbuf(struct file *file, void *priv,
return -EACCES;
}
- return vb2_qbuf(&video->buffer_queue, p);
+ return vb2_qbuf(&video->buffer_queue,
+ video->video_dev.v4l2_dev->mdev, p);
}
/*
diff --git a/drivers/staging/media/imx/TODO b/drivers/staging/media/imx/TODO
index 9eb7326f3fc6..aeeb15494a49 100644
--- a/drivers/staging/media/imx/TODO
+++ b/drivers/staging/media/imx/TODO
@@ -17,29 +17,15 @@
decided whether this feature is useful enough to make it generally
available by exporting to v4l2-core.
-- The OF graph is walked at probe time to form the list of fwnodes to
- be passed to v4l2_async_notifier_register(), starting from the IPU
- CSI ports. And after all async subdevices have been bound,
- v4l2_fwnode_parse_link() is used to form the media links between
- the entities discovered by walking the OF graph.
+- After all async subdevices have been bound, v4l2_fwnode_parse_link()
+ is used to form the media links between the devices discovered in
+ the OF graph.
While this approach allows support for arbitrary OF graphs, there
are some assumptions for this to work:
- 1. All port parent nodes reachable in the graph from the IPU CSI
- ports bind to V4L2 async subdevice drivers.
-
- If a device has mixed-use ports such as video plus audio, the
- endpoints from the audio ports are followed to devices that must
- bind to V4L2 subdevice drivers, and not for example, to an ALSA
- driver or a non-V4L2 media driver. If the device were bound to
- such a driver, imx-media would never get an async completion
- notification because the device fwnode was added to the async
- list, but the driver does not interface with the V4L2 async
- framework.
-
- 2. Every port reachable in the graph is treated as a media pad,
- owned by the V4L2 subdevice that is bound to the port's parent.
+ 1. If a port owned by a device in the graph has endpoint nodes, the
+ port is treated as a media pad.
This presents problems for devices that don't make this port = pad
assumption. Examples are SMIAPP compatible cameras which define only
@@ -54,9 +40,8 @@
possible long-term solution is to implement a subdev API that
maps a port id to a media pad index.
- 3. Every endpoint of a port reachable in the graph is treated as
- a media link, between V4L2 subdevices that are bound to the
- port parents of the local and remote endpoints.
+ 2. Every endpoint of a port owned by a device in the graph is treated
+ as a media link.
Which means a port must not contain mixed-use endpoints, they
must all refer to media links between V4L2 subdevices.
diff --git a/drivers/staging/media/imx/imx-media-capture.c b/drivers/staging/media/imx/imx-media-capture.c
index 256039ce561e..b37e1186eb2f 100644
--- a/drivers/staging/media/imx/imx-media-capture.c
+++ b/drivers/staging/media/imx/imx-media-capture.c
@@ -73,8 +73,8 @@ static int vidioc_querycap(struct file *file, void *fh,
{
struct capture_priv *priv = video_drvdata(file);
- strlcpy(cap->driver, "imx-media-capture", sizeof(cap->driver));
- strlcpy(cap->card, "imx-media-capture", sizeof(cap->card));
+ strscpy(cap->driver, "imx-media-capture", sizeof(cap->driver));
+ strscpy(cap->card, "imx-media-capture", sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info),
"platform:%s", priv->src_sd->name);
diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c
index cd2c291e1e94..4223f8d418ae 100644
--- a/drivers/staging/media/imx/imx-media-csi.c
+++ b/drivers/staging/media/imx/imx-media-csi.c
@@ -124,7 +124,7 @@ static inline struct csi_priv *sd_to_dev(struct v4l2_subdev *sdev)
static inline bool is_parallel_bus(struct v4l2_fwnode_endpoint *ep)
{
- return ep->bus_type != V4L2_MBUS_CSI2;
+ return ep->bus_type != V4L2_MBUS_CSI2_DPHY;
}
static inline bool is_parallel_16bit_bus(struct v4l2_fwnode_endpoint *ep)
@@ -165,6 +165,9 @@ static int csi_get_upstream_endpoint(struct csi_priv *priv,
struct v4l2_subdev *sd;
struct media_pad *pad;
+ if (!IS_ENABLED(CONFIG_OF))
+ return -ENXIO;
+
if (!priv->src_sd)
return -EPIPE;
@@ -1050,7 +1053,7 @@ static int csi_link_validate(struct v4l2_subdev *sd,
struct v4l2_subdev_format *sink_fmt)
{
struct csi_priv *priv = v4l2_get_subdevdata(sd);
- struct v4l2_fwnode_endpoint upstream_ep = {};
+ struct v4l2_fwnode_endpoint upstream_ep = { .bus_type = 0 };
bool is_csi2;
int ret;
@@ -1164,7 +1167,7 @@ static int csi_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_mbus_code_enum *code)
{
struct csi_priv *priv = v4l2_get_subdevdata(sd);
- struct v4l2_fwnode_endpoint upstream_ep;
+ struct v4l2_fwnode_endpoint upstream_ep = { .bus_type = 0 };
const struct imx_media_pixfmt *incc;
struct v4l2_mbus_framefmt *infmt;
int ret = 0;
@@ -1403,7 +1406,7 @@ static int csi_set_fmt(struct v4l2_subdev *sd,
{
struct csi_priv *priv = v4l2_get_subdevdata(sd);
struct imx_media_video_dev *vdev = priv->vdev;
- struct v4l2_fwnode_endpoint upstream_ep;
+ struct v4l2_fwnode_endpoint upstream_ep = { .bus_type = 0 };
const struct imx_media_pixfmt *cc;
struct v4l2_pix_format vdev_fmt;
struct v4l2_mbus_framefmt *fmt;
@@ -1542,7 +1545,7 @@ static int csi_set_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_selection *sel)
{
struct csi_priv *priv = v4l2_get_subdevdata(sd);
- struct v4l2_fwnode_endpoint upstream_ep;
+ struct v4l2_fwnode_endpoint upstream_ep = { .bus_type = 0 };
struct v4l2_mbus_framefmt *infmt;
struct v4l2_rect *crop, *compose;
int pad, ret;
@@ -1780,6 +1783,61 @@ static const struct v4l2_subdev_internal_ops csi_internal_ops = {
.unregistered = csi_unregistered,
};
+static int imx_csi_parse_endpoint(struct device *dev,
+ struct v4l2_fwnode_endpoint *vep,
+ struct v4l2_async_subdev *asd)
+{
+ return fwnode_device_is_available(asd->match.fwnode) ? 0 : -EINVAL;
+}
+
+static int imx_csi_async_register(struct csi_priv *priv)
+{
+ struct v4l2_async_notifier *notifier;
+ struct fwnode_handle *fwnode;
+ unsigned int port;
+ int ret;
+
+ notifier = kzalloc(sizeof(*notifier), GFP_KERNEL);
+ if (!notifier)
+ return -ENOMEM;
+
+ v4l2_async_notifier_init(notifier);
+
+ fwnode = dev_fwnode(priv->dev);
+
+ /* get this CSI's port id */
+ ret = fwnode_property_read_u32(fwnode, "reg", &port);
+ if (ret < 0)
+ goto out_free;
+
+ ret = v4l2_async_notifier_parse_fwnode_endpoints_by_port(
+ priv->dev->parent, notifier, sizeof(struct v4l2_async_subdev),
+ port, imx_csi_parse_endpoint);
+ if (ret < 0)
+ goto out_cleanup;
+
+ ret = v4l2_async_subdev_notifier_register(&priv->sd, notifier);
+ if (ret < 0)
+ goto out_cleanup;
+
+ ret = v4l2_async_register_subdev(&priv->sd);
+ if (ret < 0)
+ goto out_unregister;
+
+ priv->sd.subdev_notifier = notifier;
+
+ return 0;
+
+out_unregister:
+ v4l2_async_notifier_unregister(notifier);
+out_cleanup:
+ v4l2_async_notifier_cleanup(notifier);
+out_free:
+ kfree(notifier);
+
+ return ret;
+}
+
static int imx_csi_probe(struct platform_device *pdev)
{
struct ipu_client_platformdata *pdata;
@@ -1849,7 +1907,7 @@ static int imx_csi_probe(struct platform_device *pdev)
goto free;
}
- ret = v4l2_async_register_subdev(&priv->sd);
+ ret = imx_csi_async_register(priv);
if (ret)
goto free;
diff --git a/drivers/staging/media/imx/imx-media-dev.c b/drivers/staging/media/imx/imx-media-dev.c
index b0be80f05767..4b344a4a3706 100644
--- a/drivers/staging/media/imx/imx-media-dev.c
+++ b/drivers/staging/media/imx/imx-media-dev.c
@@ -29,47 +29,14 @@
static inline struct imx_media_dev *notifier2dev(struct v4l2_async_notifier *n)
{
- return container_of(n, struct imx_media_dev, subdev_notifier);
+ return container_of(n, struct imx_media_dev, notifier);
}
/*
- * Find an asd by fwnode or device name. This is called during
- * driver load to form the async subdev list and bind them.
- */
-static struct v4l2_async_subdev *
-find_async_subdev(struct imx_media_dev *imxmd,
- struct fwnode_handle *fwnode,
- const char *devname)
-{
- struct imx_media_async_subdev *imxasd;
- struct v4l2_async_subdev *asd;
-
- list_for_each_entry(imxasd, &imxmd->asd_list, list) {
- asd = &imxasd->asd;
- switch (asd->match_type) {
- case V4L2_ASYNC_MATCH_FWNODE:
- if (fwnode && asd->match.fwnode == fwnode)
- return asd;
- break;
- case V4L2_ASYNC_MATCH_DEVNAME:
- if (devname && !strcmp(asd->match.device_name,
- devname))
- return asd;
- break;
- default:
- break;
- }
- }
-
- return NULL;
-}
-
-
-/*
- * Adds a subdev to the async subdev list. If fwnode is non-NULL, adds
- * the async as a V4L2_ASYNC_MATCH_FWNODE match type, otherwise as
- * a V4L2_ASYNC_MATCH_DEVNAME match type using the dev_name of the
- * given platform_device. This is called during driver load when
+ * Adds a subdev to the root notifier's async subdev list. If fwnode is
+ * non-NULL, adds the async as a V4L2_ASYNC_MATCH_FWNODE match type,
+ * otherwise as a V4L2_ASYNC_MATCH_DEVNAME match type using the dev_name
+ * of the given platform_device. This is called during driver load when
* forming the async subdev list.
*/
int imx_media_add_async_subdev(struct imx_media_dev *imxmd,
@@ -80,47 +47,43 @@ int imx_media_add_async_subdev(struct imx_media_dev *imxmd,
struct imx_media_async_subdev *imxasd;
struct v4l2_async_subdev *asd;
const char *devname = NULL;
- int ret = 0;
-
- mutex_lock(&imxmd->mutex);
+ int ret;
- if (pdev)
+ if (fwnode) {
+ asd = v4l2_async_notifier_add_fwnode_subdev(
+ &imxmd->notifier, fwnode, sizeof(*imxasd));
+ } else {
devname = dev_name(&pdev->dev);
-
- /* return -EEXIST if this asd already added */
- if (find_async_subdev(imxmd, fwnode, devname)) {
- dev_dbg(imxmd->md.dev, "%s: already added %s\n",
- __func__, np ? np->name : devname);
- ret = -EEXIST;
- goto out;
+ asd = v4l2_async_notifier_add_devname_subdev(
+ &imxmd->notifier, devname, sizeof(*imxasd));
}
- imxasd = devm_kzalloc(imxmd->md.dev, sizeof(*imxasd), GFP_KERNEL);
- if (!imxasd) {
- ret = -ENOMEM;
- goto out;
- }
- asd = &imxasd->asd;
-
- if (fwnode) {
- asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
- asd->match.fwnode = fwnode;
- } else {
- asd->match_type = V4L2_ASYNC_MATCH_DEVNAME;
- asd->match.device_name = devname;
- imxasd->pdev = pdev;
+ if (IS_ERR(asd)) {
+ ret = PTR_ERR(asd);
+ if (ret == -EEXIST) {
+ if (np)
+ dev_dbg(imxmd->md.dev, "%s: already added %pOFn\n",
+ __func__, np);
+ else
+ dev_dbg(imxmd->md.dev, "%s: already added %s\n",
+ __func__, devname);
+ }
+ return ret;
}
- list_add_tail(&imxasd->list, &imxmd->asd_list);
+ imxasd = to_imx_media_asd(asd);
- imxmd->subdev_notifier.num_subdevs++;
+ if (devname)
+ imxasd->pdev = pdev;
- dev_dbg(imxmd->md.dev, "%s: added %s, match type %s\n",
- __func__, np ? np->name : devname, np ? "FWNODE" : "DEVNAME");
+ if (np)
+ dev_dbg(imxmd->md.dev, "%s: added %pOFn, match type FWNODE\n",
+ __func__, np);
+ else
+ dev_dbg(imxmd->md.dev, "%s: added %s, match type DEVNAME\n",
+ __func__, devname);
-out:
- mutex_unlock(&imxmd->mutex);
- return ret;
+ return 0;
}
/*
@@ -175,7 +138,7 @@ out:
}
/*
- * create the media links for all subdevs that registered async.
+ * Create the media links for all subdevs that registered.
* Called after all async subdevs have bound.
*/
static int imx_media_create_links(struct v4l2_async_notifier *notifier)
@@ -184,14 +147,7 @@ static int imx_media_create_links(struct v4l2_async_notifier *notifier)
struct v4l2_subdev *sd;
int ret;
- /*
- * Only links are created between subdevices that are known
- * to the async notifier. If there are other non-async subdevices,
- * they were created internally by some subdevice (smiapp is one
- * example). In those cases it is expected the subdevice is
- * responsible for creating those internal links.
- */
- list_for_each_entry(sd, &notifier->done, async_list) {
+ list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) {
switch (sd->grp_id) {
case IMX_MEDIA_GRP_ID_VDIC:
case IMX_MEDIA_GRP_ID_IC_PRP:
@@ -211,7 +167,10 @@ static int imx_media_create_links(struct v4l2_async_notifier *notifier)
imx_media_create_csi_of_links(imxmd, sd);
break;
default:
- /* this is an external fwnode subdev */
+ /*
+ * if this subdev has fwnode links, create media
+ * links for them.
+ */
imx_media_create_of_links(imxmd, sd);
break;
}
@@ -391,7 +350,7 @@ static int imx_media_inherit_controls(struct imx_media_dev *imxmd,
ret = v4l2_ctrl_add_handler(vfd->ctrl_handler,
sd->ctrl_handler,
- NULL);
+ NULL, true);
if (ret)
return ret;
}
@@ -487,10 +446,8 @@ static int imx_media_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *node = dev->of_node;
- struct imx_media_async_subdev *imxasd;
- struct v4l2_async_subdev **subdevs;
struct imx_media_dev *imxmd;
- int num_subdevs, i, ret;
+ int ret;
imxmd = devm_kzalloc(dev, sizeof(*imxmd), GFP_KERNEL);
if (!imxmd)
@@ -498,14 +455,14 @@ static int imx_media_probe(struct platform_device *pdev)
dev_set_drvdata(dev, imxmd);
- strlcpy(imxmd->md.model, "imx-media", sizeof(imxmd->md.model));
+ strscpy(imxmd->md.model, "imx-media", sizeof(imxmd->md.model));
imxmd->md.ops = &imx_media_md_ops;
imxmd->md.dev = dev;
mutex_init(&imxmd->mutex);
imxmd->v4l2_dev.mdev = &imxmd->md;
- strlcpy(imxmd->v4l2_dev.name, "imx-media",
+ strscpy(imxmd->v4l2_dev.name, "imx-media",
sizeof(imxmd->v4l2_dev.name));
media_device_init(&imxmd->md);
@@ -519,47 +476,34 @@ static int imx_media_probe(struct platform_device *pdev)
dev_set_drvdata(imxmd->v4l2_dev.dev, imxmd);
- INIT_LIST_HEAD(&imxmd->asd_list);
INIT_LIST_HEAD(&imxmd->vdev_list);
+ v4l2_async_notifier_init(&imxmd->notifier);
+
ret = imx_media_add_of_subdevs(imxmd, node);
if (ret) {
v4l2_err(&imxmd->v4l2_dev,
"add_of_subdevs failed with %d\n", ret);
- goto unreg_dev;
+ goto notifier_cleanup;
}
ret = imx_media_add_internal_subdevs(imxmd);
if (ret) {
v4l2_err(&imxmd->v4l2_dev,
"add_internal_subdevs failed with %d\n", ret);
- goto unreg_dev;
+ goto notifier_cleanup;
}
- num_subdevs = imxmd->subdev_notifier.num_subdevs;
-
/* no subdevs? just bail */
- if (num_subdevs == 0) {
+ if (list_empty(&imxmd->notifier.asd_list)) {
ret = -ENODEV;
- goto unreg_dev;
+ goto notifier_cleanup;
}
- subdevs = devm_kcalloc(imxmd->md.dev, num_subdevs, sizeof(*subdevs),
- GFP_KERNEL);
- if (!subdevs) {
- ret = -ENOMEM;
- goto unreg_dev;
- }
-
- i = 0;
- list_for_each_entry(imxasd, &imxmd->asd_list, list)
- subdevs[i++] = &imxasd->asd;
-
/* prepare the async subdev notifier and register it */
- imxmd->subdev_notifier.subdevs = subdevs;
- imxmd->subdev_notifier.ops = &imx_media_subdev_ops;
+ imxmd->notifier.ops = &imx_media_subdev_ops;
ret = v4l2_async_notifier_register(&imxmd->v4l2_dev,
- &imxmd->subdev_notifier);
+ &imxmd->notifier);
if (ret) {
v4l2_err(&imxmd->v4l2_dev,
"v4l2_async_notifier_register failed with %d\n", ret);
@@ -570,7 +514,8 @@ static int imx_media_probe(struct platform_device *pdev)
del_int:
imx_media_remove_internal_subdevs(imxmd);
-unreg_dev:
+notifier_cleanup:
+ v4l2_async_notifier_cleanup(&imxmd->notifier);
v4l2_device_unregister(&imxmd->v4l2_dev);
cleanup:
media_device_cleanup(&imxmd->md);
@@ -584,8 +529,9 @@ static int imx_media_remove(struct platform_device *pdev)
v4l2_info(&imxmd->v4l2_dev, "Removing imx-media\n");
- v4l2_async_notifier_unregister(&imxmd->subdev_notifier);
+ v4l2_async_notifier_unregister(&imxmd->notifier);
imx_media_remove_internal_subdevs(imxmd);
+ v4l2_async_notifier_cleanup(&imxmd->notifier);
v4l2_device_unregister(&imxmd->v4l2_dev);
media_device_unregister(&imxmd->md);
media_device_cleanup(&imxmd->md);
diff --git a/drivers/staging/media/imx/imx-media-fim.c b/drivers/staging/media/imx/imx-media-fim.c
index 6df189135db8..8cf773eef9da 100644
--- a/drivers/staging/media/imx/imx-media-fim.c
+++ b/drivers/staging/media/imx/imx-media-fim.c
@@ -463,7 +463,7 @@ int imx_media_fim_add_controls(struct imx_media_fim *fim)
{
/* add the FIM controls to the calling subdev ctrl handler */
return v4l2_ctrl_add_handler(fim->sd->ctrl_handler,
- &fim->ctrl_handler, NULL);
+ &fim->ctrl_handler, NULL, false);
}
EXPORT_SYMBOL_GPL(imx_media_fim_add_controls);
diff --git a/drivers/staging/media/imx/imx-media-internal-sd.c b/drivers/staging/media/imx/imx-media-internal-sd.c
index daf66c2d69ab..0fdc45dbfb76 100644
--- a/drivers/staging/media/imx/imx-media-internal-sd.c
+++ b/drivers/staging/media/imx/imx-media-internal-sd.c
@@ -350,8 +350,11 @@ remove:
void imx_media_remove_internal_subdevs(struct imx_media_dev *imxmd)
{
struct imx_media_async_subdev *imxasd;
+ struct v4l2_async_subdev *asd;
+
+ list_for_each_entry(asd, &imxmd->notifier.asd_list, asd_list) {
+ imxasd = to_imx_media_asd(asd);
- list_for_each_entry(imxasd, &imxmd->asd_list, list) {
if (!imxasd->pdev)
continue;
diff --git a/drivers/staging/media/imx/imx-media-of.c b/drivers/staging/media/imx/imx-media-of.c
index acde372c6795..b2e840f96c50 100644
--- a/drivers/staging/media/imx/imx-media-of.c
+++ b/drivers/staging/media/imx/imx-media-of.c
@@ -20,74 +20,19 @@
#include <video/imx-ipu-v3.h>
#include "imx-media.h"
-static int of_get_port_count(const struct device_node *np)
+static int of_add_csi(struct imx_media_dev *imxmd, struct device_node *csi_np)
{
- struct device_node *ports, *child;
- int num = 0;
-
- /* check if this node has a ports subnode */
- ports = of_get_child_by_name(np, "ports");
- if (ports)
- np = ports;
-
- for_each_child_of_node(np, child)
- if (of_node_cmp(child->name, "port") == 0)
- num++;
-
- of_node_put(ports);
- return num;
-}
-
-/*
- * find the remote device node given local endpoint node
- */
-static bool of_get_remote(struct device_node *epnode,
- struct device_node **remote_node)
-{
- struct device_node *rp, *rpp;
- struct device_node *remote;
- bool is_csi_port;
-
- rp = of_graph_get_remote_port(epnode);
- rpp = of_graph_get_remote_port_parent(epnode);
-
- if (of_device_is_compatible(rpp, "fsl,imx6q-ipu")) {
- /* the remote is one of the CSI ports */
- remote = rp;
- of_node_put(rpp);
- is_csi_port = true;
- } else {
- remote = rpp;
- of_node_put(rp);
- is_csi_port = false;
- }
-
- if (!of_device_is_available(remote)) {
- of_node_put(remote);
- *remote_node = NULL;
- } else {
- *remote_node = remote;
- }
-
- return is_csi_port;
-}
-
-static int
-of_parse_subdev(struct imx_media_dev *imxmd, struct device_node *sd_np,
- bool is_csi_port)
-{
- int i, num_ports, ret;
+ int ret;
- if (!of_device_is_available(sd_np)) {
- dev_dbg(imxmd->md.dev, "%s: %s not enabled\n", __func__,
- sd_np->name);
+ if (!of_device_is_available(csi_np)) {
+ dev_dbg(imxmd->md.dev, "%s: %pOFn not enabled\n", __func__,
+ csi_np);
/* unavailable is not an error */
return 0;
}
- /* register this subdev with async notifier */
- ret = imx_media_add_async_subdev(imxmd, of_fwnode_handle(sd_np),
- NULL);
+ /* add CSI fwnode to async notifier */
+ ret = imx_media_add_async_subdev(imxmd, of_fwnode_handle(csi_np), NULL);
if (ret) {
if (ret == -EEXIST) {
/* already added, everything is fine */
@@ -98,42 +43,7 @@ of_parse_subdev(struct imx_media_dev *imxmd, struct device_node *sd_np,
return ret;
}
- /*
- * the ipu-csi has one sink port. The source pads are not
- * represented in the device tree by port nodes, but are
- * described by the internal pads and links later.
- */
- num_ports = is_csi_port ? 1 : of_get_port_count(sd_np);
-
- for (i = 0; i < num_ports; i++) {
- struct device_node *epnode = NULL, *port, *remote_np;
-
- port = is_csi_port ? sd_np : of_graph_get_port_by_id(sd_np, i);
- if (!port)
- continue;
-
- for_each_child_of_node(port, epnode) {
- bool remote_is_csi;
-
- remote_is_csi = of_get_remote(epnode, &remote_np);
- if (!remote_np)
- continue;
-
- ret = of_parse_subdev(imxmd, remote_np, remote_is_csi);
- of_node_put(remote_np);
- if (ret)
- break;
- }
-
- if (port != sd_np)
- of_node_put(port);
- if (ret) {
- of_node_put(epnode);
- break;
- }
- }
-
- return ret;
+ return 0;
}
int imx_media_add_of_subdevs(struct imx_media_dev *imxmd,
@@ -147,7 +57,7 @@ int imx_media_add_of_subdevs(struct imx_media_dev *imxmd,
if (!csi_np)
break;
- ret = of_parse_subdev(imxmd, csi_np, true);
+ ret = of_add_csi(imxmd, csi_np);
of_node_put(csi_np);
if (ret)
return ret;
diff --git a/drivers/staging/media/imx/imx-media-utils.c b/drivers/staging/media/imx/imx-media-utils.c
index 8aa13403b09d..0eaa353d5cb3 100644
--- a/drivers/staging/media/imx/imx-media-utils.c
+++ b/drivers/staging/media/imx/imx-media-utils.c
@@ -88,7 +88,7 @@ static const struct imx_media_pixfmt rgb_formats[] = {
.cs = IPUV3_COLORSPACE_RGB,
.bpp = 24,
}, {
- .fourcc = V4L2_PIX_FMT_RGB32,
+ .fourcc = V4L2_PIX_FMT_XRGB32,
.codes = {MEDIA_BUS_FMT_ARGB8888_1X32},
.cs = IPUV3_COLORSPACE_RGB,
.bpp = 32,
@@ -212,7 +212,7 @@ static const struct imx_media_pixfmt ipu_yuv_formats[] = {
static const struct imx_media_pixfmt ipu_rgb_formats[] = {
{
- .fourcc = V4L2_PIX_FMT_RGB32,
+ .fourcc = V4L2_PIX_FMT_XRGB32,
.codes = {MEDIA_BUS_FMT_ARGB8888_1X32},
.cs = IPUV3_COLORSPACE_RGB,
.bpp = 32,
diff --git a/drivers/staging/media/imx/imx-media.h b/drivers/staging/media/imx/imx-media.h
index 57bd094cf765..bc7feb81937c 100644
--- a/drivers/staging/media/imx/imx-media.h
+++ b/drivers/staging/media/imx/imx-media.h
@@ -119,12 +119,11 @@ struct imx_media_internal_sd_platformdata {
int ipu_id;
};
-
struct imx_media_async_subdev {
+ /* the base asd - must be first in this struct */
struct v4l2_async_subdev asd;
/* the platform device of IPU-internal subdevs */
struct platform_device *pdev;
- struct list_head list;
};
static inline struct imx_media_async_subdev *
@@ -149,8 +148,7 @@ struct imx_media_dev {
struct ipu_soc *ipu[2];
/* for async subdev registration */
- struct list_head asd_list;
- struct v4l2_async_notifier subdev_notifier;
+ struct v4l2_async_notifier notifier;
};
enum codespace_sel {
diff --git a/drivers/staging/media/imx/imx6-mipi-csi2.c b/drivers/staging/media/imx/imx6-mipi-csi2.c
index ceeeb3069a02..6a1cee55a49b 100644
--- a/drivers/staging/media/imx/imx6-mipi-csi2.c
+++ b/drivers/staging/media/imx/imx6-mipi-csi2.c
@@ -551,35 +551,34 @@ static const struct v4l2_subdev_internal_ops csi2_internal_ops = {
.registered = csi2_registered,
};
-static int csi2_parse_endpoints(struct csi2_dev *csi2)
+static int csi2_parse_endpoint(struct device *dev,
+ struct v4l2_fwnode_endpoint *vep,
+ struct v4l2_async_subdev *asd)
{
- struct device_node *node = csi2->dev->of_node;
- struct device_node *epnode;
- struct v4l2_fwnode_endpoint ep;
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct csi2_dev *csi2 = sd_to_dev(sd);
- epnode = of_graph_get_endpoint_by_regs(node, 0, -1);
- if (!epnode) {
- v4l2_err(&csi2->sd, "failed to get sink endpoint node\n");
+ if (!fwnode_device_is_available(asd->match.fwnode)) {
+ v4l2_err(&csi2->sd, "remote is not available\n");
return -EINVAL;
}
- v4l2_fwnode_endpoint_parse(of_fwnode_handle(epnode), &ep);
- of_node_put(epnode);
-
- if (ep.bus_type != V4L2_MBUS_CSI2) {
+ if (vep->bus_type != V4L2_MBUS_CSI2_DPHY) {
v4l2_err(&csi2->sd, "invalid bus type, must be MIPI CSI2\n");
return -EINVAL;
}
- csi2->bus = ep.bus.mipi_csi2;
+ csi2->bus = vep->bus.mipi_csi2;
dev_dbg(csi2->dev, "data lanes: %d\n", csi2->bus.num_data_lanes);
dev_dbg(csi2->dev, "flags: 0x%08x\n", csi2->bus.flags);
+
return 0;
}
static int csi2_probe(struct platform_device *pdev)
{
+ unsigned int sink_port = 0;
struct csi2_dev *csi2;
struct resource *res;
int ret;
@@ -597,14 +596,10 @@ static int csi2_probe(struct platform_device *pdev)
csi2->sd.dev = &pdev->dev;
csi2->sd.owner = THIS_MODULE;
csi2->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
- strcpy(csi2->sd.name, DEVICE_NAME);
+ strscpy(csi2->sd.name, DEVICE_NAME, sizeof(csi2->sd.name));
csi2->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
csi2->sd.grp_id = IMX_MEDIA_GRP_ID_CSI2;
- ret = csi2_parse_endpoints(csi2);
- if (ret)
- return ret;
-
csi2->pllref_clk = devm_clk_get(&pdev->dev, "ref");
if (IS_ERR(csi2->pllref_clk)) {
v4l2_err(&csi2->sd, "failed to get pll reference clock\n");
@@ -654,7 +649,9 @@ static int csi2_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, &csi2->sd);
- ret = v4l2_async_register_subdev(&csi2->sd);
+ ret = v4l2_async_register_fwnode_subdev(
+ &csi2->sd, sizeof(struct v4l2_async_subdev),
+ &sink_port, 1, csi2_parse_endpoint);
if (ret)
goto dphy_off;
diff --git a/drivers/staging/media/imx074/imx074.c b/drivers/staging/media/imx074/imx074.c
index 77f1e0243d6e..1676c166dc83 100644
--- a/drivers/staging/media/imx074/imx074.c
+++ b/drivers/staging/media/imx074/imx074.c
@@ -223,7 +223,6 @@ static int imx074_get_selection(struct v4l2_subdev *sd,
switch (sel->target) {
case V4L2_SEL_TGT_CROP_BOUNDS:
- case V4L2_SEL_TGT_CROP_DEFAULT:
case V4L2_SEL_TGT_CROP:
return 0;
default:
@@ -263,7 +262,7 @@ static int imx074_s_power(struct v4l2_subdev *sd, int on)
static int imx074_g_mbus_config(struct v4l2_subdev *sd,
struct v4l2_mbus_config *cfg)
{
- cfg->type = V4L2_MBUS_CSI2;
+ cfg->type = V4L2_MBUS_CSI2_DPHY;
cfg->flags = V4L2_MBUS_CSI2_2_LANE |
V4L2_MBUS_CSI2_CHANNEL_0 |
V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
diff --git a/drivers/staging/media/mt9t031/mt9t031.c b/drivers/staging/media/mt9t031/mt9t031.c
index 4802d30e47de..4ff179302b4f 100644
--- a/drivers/staging/media/mt9t031/mt9t031.c
+++ b/drivers/staging/media/mt9t031/mt9t031.c
@@ -330,7 +330,6 @@ static int mt9t031_get_selection(struct v4l2_subdev *sd,
switch (sel->target) {
case V4L2_SEL_TGT_CROP_BOUNDS:
- case V4L2_SEL_TGT_CROP_DEFAULT:
sel->r.left = MT9T031_COLUMN_SKIP;
sel->r.top = MT9T031_ROW_SKIP;
sel->r.width = MT9T031_MAX_WIDTH;
diff --git a/drivers/staging/media/omap4iss/Kconfig b/drivers/staging/media/omap4iss/Kconfig
index dddd27335cb4..841cc0b3ce13 100644
--- a/drivers/staging/media/omap4iss/Kconfig
+++ b/drivers/staging/media/omap4iss/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
config VIDEO_OMAP4
tristate "OMAP 4 Camera support"
depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && I2C
diff --git a/drivers/staging/media/omap4iss/Makefile b/drivers/staging/media/omap4iss/Makefile
index a716ce936cf6..e64d489a4a76 100644
--- a/drivers/staging/media/omap4iss/Makefile
+++ b/drivers/staging/media/omap4iss/Makefile
@@ -1,4 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+#
# Makefile for OMAP4 ISS driver
+#
omap4-iss-objs += \
iss.o iss_csi2.o iss_csiphy.o iss_ipipeif.o iss_ipipe.o iss_resizer.o iss_video.o
diff --git a/drivers/staging/media/omap4iss/iss.c b/drivers/staging/media/omap4iss/iss.c
index b1036baebb03..c8be1db532ab 100644
--- a/drivers/staging/media/omap4iss/iss.c
+++ b/drivers/staging/media/omap4iss/iss.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* TI OMAP4 ISS V4L2 Driver
*
* Copyright (C) 2012, Texas Instruments
*
* Author: Sergio Aguirre <sergio.a.aguirre@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include <linux/clk.h>
@@ -989,7 +985,7 @@ static int iss_register_entities(struct iss_device *iss)
int ret;
iss->media_dev.dev = iss->dev;
- strlcpy(iss->media_dev.model, "TI OMAP4 ISS",
+ strscpy(iss->media_dev.model, "TI OMAP4 ISS",
sizeof(iss->media_dev.model));
iss->media_dev.hw_revision = iss->revision;
iss->media_dev.ops = &iss_media_ops;
diff --git a/drivers/staging/media/omap4iss/iss.h b/drivers/staging/media/omap4iss/iss.h
index 760ee27da704..b88f9529683c 100644
--- a/drivers/staging/media/omap4iss/iss.h
+++ b/drivers/staging/media/omap4iss/iss.h
@@ -1,14 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
/*
* TI OMAP4 ISS V4L2 Driver
*
* Copyright (C) 2012 Texas Instruments.
*
* Author: Sergio Aguirre <sergio.a.aguirre@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#ifndef _OMAP4_ISS_H_
diff --git a/drivers/staging/media/omap4iss/iss_csi2.c b/drivers/staging/media/omap4iss/iss_csi2.c
index f6acc541e8a2..059cf5bd3c36 100644
--- a/drivers/staging/media/omap4iss/iss_csi2.c
+++ b/drivers/staging/media/omap4iss/iss_csi2.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* TI OMAP4 ISS V4L2 Driver - CSI PHY module
*
* Copyright (C) 2012 Texas Instruments, Inc.
*
* Author: Sergio Aguirre <sergio.a.aguirre@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include <linux/delay.h>
diff --git a/drivers/staging/media/omap4iss/iss_csi2.h b/drivers/staging/media/omap4iss/iss_csi2.h
index 24ab378d469f..3f7fd9cff41d 100644
--- a/drivers/staging/media/omap4iss/iss_csi2.h
+++ b/drivers/staging/media/omap4iss/iss_csi2.h
@@ -1,14 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
/*
* TI OMAP4 ISS V4L2 Driver - CSI2 module
*
* Copyright (C) 2012 Texas Instruments, Inc.
*
* Author: Sergio Aguirre <sergio.a.aguirre@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#ifndef OMAP4_ISS_CSI2_H
diff --git a/drivers/staging/media/omap4iss/iss_csiphy.c b/drivers/staging/media/omap4iss/iss_csiphy.c
index 748607f8918f..96f2ce045138 100644
--- a/drivers/staging/media/omap4iss/iss_csiphy.c
+++ b/drivers/staging/media/omap4iss/iss_csiphy.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* TI OMAP4 ISS V4L2 Driver - CSI PHY module
*
* Copyright (C) 2012 Texas Instruments, Inc.
*
* Author: Sergio Aguirre <sergio.a.aguirre@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include <linux/delay.h>
diff --git a/drivers/staging/media/omap4iss/iss_csiphy.h b/drivers/staging/media/omap4iss/iss_csiphy.h
index a0f2d974daeb..44408e4fcf3b 100644
--- a/drivers/staging/media/omap4iss/iss_csiphy.h
+++ b/drivers/staging/media/omap4iss/iss_csiphy.h
@@ -1,14 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
/*
* TI OMAP4 ISS V4L2 Driver - CSI PHY module
*
* Copyright (C) 2012 Texas Instruments, Inc.
*
* Author: Sergio Aguirre <sergio.a.aguirre@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#ifndef OMAP4_ISS_CSI_PHY_H
diff --git a/drivers/staging/media/omap4iss/iss_ipipe.c b/drivers/staging/media/omap4iss/iss_ipipe.c
index d86ef8a031f2..26be078b69f3 100644
--- a/drivers/staging/media/omap4iss/iss_ipipe.c
+++ b/drivers/staging/media/omap4iss/iss_ipipe.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* TI OMAP4 ISS V4L2 Driver - ISP IPIPE module
*
* Copyright (C) 2012 Texas Instruments, Inc.
*
* Author: Sergio Aguirre <sergio.a.aguirre@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include <linux/module.h>
@@ -507,7 +503,7 @@ static int ipipe_init_entities(struct iss_ipipe_device *ipipe)
v4l2_subdev_init(sd, &ipipe_v4l2_ops);
sd->internal_ops = &ipipe_v4l2_internal_ops;
- strlcpy(sd->name, "OMAP4 ISS ISP IPIPE", sizeof(sd->name));
+ strscpy(sd->name, "OMAP4 ISS ISP IPIPE", sizeof(sd->name));
sd->grp_id = BIT(16); /* group ID for iss subdevs */
v4l2_set_subdevdata(sd, ipipe);
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
diff --git a/drivers/staging/media/omap4iss/iss_ipipe.h b/drivers/staging/media/omap4iss/iss_ipipe.h
index d5b441d9cb31..53b42aac1696 100644
--- a/drivers/staging/media/omap4iss/iss_ipipe.h
+++ b/drivers/staging/media/omap4iss/iss_ipipe.h
@@ -1,14 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
/*
* TI OMAP4 ISS V4L2 Driver - ISP IPIPE module
*
* Copyright (C) 2012 Texas Instruments, Inc.
*
* Author: Sergio Aguirre <sergio.a.aguirre@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#ifndef OMAP4_ISS_IPIPE_H
diff --git a/drivers/staging/media/omap4iss/iss_ipipeif.c b/drivers/staging/media/omap4iss/iss_ipipeif.c
index cb88b2bd0d82..c2978d02e797 100644
--- a/drivers/staging/media/omap4iss/iss_ipipeif.c
+++ b/drivers/staging/media/omap4iss/iss_ipipeif.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* TI OMAP4 ISS V4L2 Driver - ISP IPIPEIF module
*
* Copyright (C) 2012 Texas Instruments, Inc.
*
* Author: Sergio Aguirre <sergio.a.aguirre@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include <linux/module.h>
@@ -738,7 +734,7 @@ static int ipipeif_init_entities(struct iss_ipipeif_device *ipipeif)
v4l2_subdev_init(sd, &ipipeif_v4l2_ops);
sd->internal_ops = &ipipeif_v4l2_internal_ops;
- strlcpy(sd->name, "OMAP4 ISS ISP IPIPEIF", sizeof(sd->name));
+ strscpy(sd->name, "OMAP4 ISS ISP IPIPEIF", sizeof(sd->name));
sd->grp_id = BIT(16); /* group ID for iss subdevs */
v4l2_set_subdevdata(sd, ipipeif);
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
diff --git a/drivers/staging/media/omap4iss/iss_ipipeif.h b/drivers/staging/media/omap4iss/iss_ipipeif.h
index bad32b1d6ad8..69792333a62e 100644
--- a/drivers/staging/media/omap4iss/iss_ipipeif.h
+++ b/drivers/staging/media/omap4iss/iss_ipipeif.h
@@ -1,14 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
/*
* TI OMAP4 ISS V4L2 Driver - ISP IPIPEIF module
*
* Copyright (C) 2012 Texas Instruments, Inc.
*
* Author: Sergio Aguirre <sergio.a.aguirre@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#ifndef OMAP4_ISS_IPIPEIF_H
diff --git a/drivers/staging/media/omap4iss/iss_regs.h b/drivers/staging/media/omap4iss/iss_regs.h
index cb415e898aca..09a7375c89ac 100644
--- a/drivers/staging/media/omap4iss/iss_regs.h
+++ b/drivers/staging/media/omap4iss/iss_regs.h
@@ -1,14 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
/*
* TI OMAP4 ISS V4L2 Driver - Register defines
*
* Copyright (C) 2012 Texas Instruments.
*
* Author: Sergio Aguirre <sergio.a.aguirre@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#ifndef _OMAP4_ISS_REGS_H_
diff --git a/drivers/staging/media/omap4iss/iss_resizer.c b/drivers/staging/media/omap4iss/iss_resizer.c
index 4bbfa20b3c38..3b6875cbca9b 100644
--- a/drivers/staging/media/omap4iss/iss_resizer.c
+++ b/drivers/staging/media/omap4iss/iss_resizer.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* TI OMAP4 ISS V4L2 Driver - ISP RESIZER module
*
* Copyright (C) 2012 Texas Instruments, Inc.
*
* Author: Sergio Aguirre <sergio.a.aguirre@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include <linux/module.h>
@@ -781,7 +777,7 @@ static int resizer_init_entities(struct iss_resizer_device *resizer)
v4l2_subdev_init(sd, &resizer_v4l2_ops);
sd->internal_ops = &resizer_v4l2_internal_ops;
- strlcpy(sd->name, "OMAP4 ISS ISP resizer", sizeof(sd->name));
+ strscpy(sd->name, "OMAP4 ISS ISP resizer", sizeof(sd->name));
sd->grp_id = BIT(16); /* group ID for iss subdevs */
v4l2_set_subdevdata(sd, resizer);
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
diff --git a/drivers/staging/media/omap4iss/iss_resizer.h b/drivers/staging/media/omap4iss/iss_resizer.h
index 8b7c5fe9ffed..cb937fccc21f 100644
--- a/drivers/staging/media/omap4iss/iss_resizer.h
+++ b/drivers/staging/media/omap4iss/iss_resizer.h
@@ -1,14 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
/*
* TI OMAP4 ISS V4L2 Driver - ISP RESIZER module
*
* Copyright (C) 2012 Texas Instruments, Inc.
*
* Author: Sergio Aguirre <sergio.a.aguirre@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#ifndef OMAP4_ISS_RESIZER_H
diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c
index 16478fe9e3f8..c2c5a9cd8642 100644
--- a/drivers/staging/media/omap4iss/iss_video.c
+++ b/drivers/staging/media/omap4iss/iss_video.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* TI OMAP4 ISS V4L2 Driver - Generic video node
*
* Copyright (C) 2012 Texas Instruments, Inc.
*
* Author: Sergio Aguirre <sergio.a.aguirre@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include <linux/clk.h>
@@ -534,9 +530,9 @@ iss_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
{
struct iss_video *video = video_drvdata(file);
- strlcpy(cap->driver, ISS_VIDEO_DRIVER_NAME, sizeof(cap->driver));
- strlcpy(cap->card, video->video.name, sizeof(cap->card));
- strlcpy(cap->bus_info, "media", sizeof(cap->bus_info));
+ strscpy(cap->driver, ISS_VIDEO_DRIVER_NAME, sizeof(cap->driver));
+ strscpy(cap->card, video->video.name, sizeof(cap->card));
+ strscpy(cap->bus_info, "media", sizeof(cap->bus_info));
if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
@@ -573,7 +569,7 @@ iss_video_enum_format(struct file *file, void *fh, struct v4l2_fmtdesc *f)
if (index == 0) {
f->pixelformat = info->pixelformat;
- strlcpy(f->description, info->description,
+ strscpy(f->description, info->description,
sizeof(f->description));
return 0;
}
@@ -806,9 +802,10 @@ iss_video_querybuf(struct file *file, void *fh, struct v4l2_buffer *b)
static int
iss_video_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
{
+ struct iss_video *video = video_drvdata(file);
struct iss_video_fh *vfh = to_iss_video_fh(fh);
- return vb2_qbuf(&vfh->queue, b);
+ return vb2_qbuf(&vfh->queue, video->video.v4l2_dev->mdev, b);
}
static int
@@ -1053,7 +1050,7 @@ iss_video_enum_input(struct file *file, void *fh, struct v4l2_input *input)
if (input->index > 0)
return -EINVAL;
- strlcpy(input->name, "camera", sizeof(input->name));
+ strscpy(input->name, "camera", sizeof(input->name));
input->type = V4L2_INPUT_TYPE_CAMERA;
return 0;
diff --git a/drivers/staging/media/omap4iss/iss_video.h b/drivers/staging/media/omap4iss/iss_video.h
index d7e05d04512c..f22489edb562 100644
--- a/drivers/staging/media/omap4iss/iss_video.h
+++ b/drivers/staging/media/omap4iss/iss_video.h
@@ -1,14 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
/*
* TI OMAP4 ISS V4L2 Driver - Generic video node
*
* Copyright (C) 2012 Texas Instruments, Inc.
*
* Author: Sergio Aguirre <sergio.a.aguirre@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#ifndef OMAP4_ISS_VIDEO_H
diff --git a/drivers/staging/media/sunxi/Kconfig b/drivers/staging/media/sunxi/Kconfig
new file mode 100644
index 000000000000..c78d92240ceb
--- /dev/null
+++ b/drivers/staging/media/sunxi/Kconfig
@@ -0,0 +1,15 @@
+config VIDEO_SUNXI
+ bool "Allwinner sunXi family Video Devices"
+ depends on ARCH_SUNXI || COMPILE_TEST
+ help
+ If you have an Allwinner SoC based on the sunXi family, say Y.
+
+ Note that this option doesn't include new drivers in the
+ kernel: saying N will just cause Kconfig to skip all the
+ questions about Allwinner media devices.
+
+if VIDEO_SUNXI
+
+source "drivers/staging/media/sunxi/cedrus/Kconfig"
+
+endif
diff --git a/drivers/staging/media/sunxi/Makefile b/drivers/staging/media/sunxi/Makefile
new file mode 100644
index 000000000000..cee2846c3ecf
--- /dev/null
+++ b/drivers/staging/media/sunxi/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_VIDEO_SUNXI_CEDRUS) += cedrus/
diff --git a/drivers/staging/media/sunxi/cedrus/Kconfig b/drivers/staging/media/sunxi/cedrus/Kconfig
new file mode 100644
index 000000000000..a7a34e89c42d
--- /dev/null
+++ b/drivers/staging/media/sunxi/cedrus/Kconfig
@@ -0,0 +1,14 @@
+config VIDEO_SUNXI_CEDRUS
+ tristate "Allwinner Cedrus VPU driver"
+ depends on VIDEO_DEV && VIDEO_V4L2 && MEDIA_CONTROLLER
+ depends on HAS_DMA
+ depends on OF
+ select SUNXI_SRAM
+ select VIDEOBUF2_DMA_CONTIG
+ select V4L2_MEM2MEM_DEV
+ help
+ Support for the VPU found in Allwinner SoCs, also known as the Cedar
+ video engine.
+
+ To compile this driver as a module, choose M here: the module
+ will be called sunxi-cedrus.
diff --git a/drivers/staging/media/sunxi/cedrus/Makefile b/drivers/staging/media/sunxi/cedrus/Makefile
new file mode 100644
index 000000000000..e9dc68b7bcb6
--- /dev/null
+++ b/drivers/staging/media/sunxi/cedrus/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_VIDEO_SUNXI_CEDRUS) += sunxi-cedrus.o
+
+sunxi-cedrus-y = cedrus.o cedrus_video.o cedrus_hw.o cedrus_dec.o cedrus_mpeg2.o
diff --git a/drivers/staging/media/sunxi/cedrus/TODO b/drivers/staging/media/sunxi/cedrus/TODO
new file mode 100644
index 000000000000..ec277ece47af
--- /dev/null
+++ b/drivers/staging/media/sunxi/cedrus/TODO
@@ -0,0 +1,7 @@
+Before this stateless decoder driver can leave the staging area:
+* The Request API needs to be stabilized;
+* The codec-specific controls need to be thoroughly reviewed to ensure they
+ cover all intended uses cases;
+* Userspace support for the Request API needs to be reviewed;
+* Another stateless decoder driver should be submitted;
+* At least one stateless encoder driver should be submitted.
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c
new file mode 100644
index 000000000000..82558455384a
--- /dev/null
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.c
@@ -0,0 +1,431 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Cedrus VPU driver
+ *
+ * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
+ * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ * Copyright (C) 2018 Bootlin
+ *
+ * Based on the vim2m driver, that is:
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Pawel Osciak, <pawel@osciak.com>
+ * Marek Szyprowski, <m.szyprowski@samsung.com>
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "cedrus.h"
+#include "cedrus_video.h"
+#include "cedrus_dec.h"
+#include "cedrus_hw.h"
+
+static const struct cedrus_control cedrus_controls[] = {
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS,
+ .elem_size = sizeof(struct v4l2_ctrl_mpeg2_slice_params),
+ .codec = CEDRUS_CODEC_MPEG2,
+ .required = true,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION,
+ .elem_size = sizeof(struct v4l2_ctrl_mpeg2_quantization),
+ .codec = CEDRUS_CODEC_MPEG2,
+ .required = false,
+ },
+};
+
+#define CEDRUS_CONTROLS_COUNT ARRAY_SIZE(cedrus_controls)
+
+void *cedrus_find_control_data(struct cedrus_ctx *ctx, u32 id)
+{
+ unsigned int i;
+
+ for (i = 0; ctx->ctrls[i]; i++)
+ if (ctx->ctrls[i]->id == id)
+ return ctx->ctrls[i]->p_cur.p;
+
+ return NULL;
+}
+
+static int cedrus_init_ctrls(struct cedrus_dev *dev, struct cedrus_ctx *ctx)
+{
+ struct v4l2_ctrl_handler *hdl = &ctx->hdl;
+ struct v4l2_ctrl *ctrl;
+ unsigned int ctrl_size;
+ unsigned int i;
+
+ v4l2_ctrl_handler_init(hdl, CEDRUS_CONTROLS_COUNT);
+ if (hdl->error) {
+ v4l2_err(&dev->v4l2_dev,
+ "Failed to initialize control handler\n");
+ return hdl->error;
+ }
+
+ ctrl_size = sizeof(ctrl) * CEDRUS_CONTROLS_COUNT + 1;
+
+ ctx->ctrls = kzalloc(ctrl_size, GFP_KERNEL);
+ memset(ctx->ctrls, 0, ctrl_size);
+
+ for (i = 0; i < CEDRUS_CONTROLS_COUNT; i++) {
+ struct v4l2_ctrl_config cfg = { 0 };
+
+ cfg.elem_size = cedrus_controls[i].elem_size;
+ cfg.id = cedrus_controls[i].id;
+
+ ctrl = v4l2_ctrl_new_custom(hdl, &cfg, NULL);
+ if (hdl->error) {
+ v4l2_err(&dev->v4l2_dev,
+ "Failed to create new custom control\n");
+
+ v4l2_ctrl_handler_free(hdl);
+ kfree(ctx->ctrls);
+ return hdl->error;
+ }
+
+ ctx->ctrls[i] = ctrl;
+ }
+
+ ctx->fh.ctrl_handler = hdl;
+ v4l2_ctrl_handler_setup(hdl);
+
+ return 0;
+}
+
+static int cedrus_request_validate(struct media_request *req)
+{
+ struct media_request_object *obj;
+ struct v4l2_ctrl_handler *parent_hdl, *hdl;
+ struct cedrus_ctx *ctx = NULL;
+ struct v4l2_ctrl *ctrl_test;
+ unsigned int count;
+ unsigned int i;
+
+ count = vb2_request_buffer_cnt(req);
+ if (!count) {
+ v4l2_info(&ctx->dev->v4l2_dev,
+ "No buffer was provided with the request\n");
+ return -ENOENT;
+ } else if (count > 1) {
+ v4l2_info(&ctx->dev->v4l2_dev,
+ "More than one buffer was provided with the request\n");
+ return -EINVAL;
+ }
+
+ list_for_each_entry(obj, &req->objects, list) {
+ struct vb2_buffer *vb;
+
+ if (vb2_request_object_is_buffer(obj)) {
+ vb = container_of(obj, struct vb2_buffer, req_obj);
+ ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+ break;
+ }
+ }
+
+ if (!ctx)
+ return -ENOENT;
+
+ parent_hdl = &ctx->hdl;
+
+ hdl = v4l2_ctrl_request_hdl_find(req, parent_hdl);
+ if (!hdl) {
+ v4l2_info(&ctx->dev->v4l2_dev, "Missing codec control(s)\n");
+ return -ENOENT;
+ }
+
+ for (i = 0; i < CEDRUS_CONTROLS_COUNT; i++) {
+ if (cedrus_controls[i].codec != ctx->current_codec ||
+ !cedrus_controls[i].required)
+ continue;
+
+ ctrl_test = v4l2_ctrl_request_hdl_ctrl_find(hdl,
+ cedrus_controls[i].id);
+ if (!ctrl_test) {
+ v4l2_info(&ctx->dev->v4l2_dev,
+ "Missing required codec control\n");
+ return -ENOENT;
+ }
+ }
+
+ v4l2_ctrl_request_hdl_put(hdl);
+
+ return vb2_request_validate(req);
+}
+
+static int cedrus_open(struct file *file)
+{
+ struct cedrus_dev *dev = video_drvdata(file);
+ struct cedrus_ctx *ctx = NULL;
+ int ret;
+
+ if (mutex_lock_interruptible(&dev->dev_mutex))
+ return -ERESTARTSYS;
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx) {
+ mutex_unlock(&dev->dev_mutex);
+ return -ENOMEM;
+ }
+
+ v4l2_fh_init(&ctx->fh, video_devdata(file));
+ file->private_data = &ctx->fh;
+ ctx->dev = dev;
+
+ ret = cedrus_init_ctrls(dev, ctx);
+ if (ret)
+ goto err_free;
+
+ ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx,
+ &cedrus_queue_init);
+ if (IS_ERR(ctx->fh.m2m_ctx)) {
+ ret = PTR_ERR(ctx->fh.m2m_ctx);
+ goto err_ctrls;
+ }
+
+ v4l2_fh_add(&ctx->fh);
+
+ mutex_unlock(&dev->dev_mutex);
+
+ return 0;
+
+err_ctrls:
+ v4l2_ctrl_handler_free(&ctx->hdl);
+err_free:
+ kfree(ctx);
+ mutex_unlock(&dev->dev_mutex);
+
+ return ret;
+}
+
+static int cedrus_release(struct file *file)
+{
+ struct cedrus_dev *dev = video_drvdata(file);
+ struct cedrus_ctx *ctx = container_of(file->private_data,
+ struct cedrus_ctx, fh);
+
+ mutex_lock(&dev->dev_mutex);
+
+ v4l2_fh_del(&ctx->fh);
+ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+
+ v4l2_ctrl_handler_free(&ctx->hdl);
+ kfree(ctx->ctrls);
+
+ v4l2_fh_exit(&ctx->fh);
+
+ kfree(ctx);
+
+ mutex_unlock(&dev->dev_mutex);
+
+ return 0;
+}
+
+static const struct v4l2_file_operations cedrus_fops = {
+ .owner = THIS_MODULE,
+ .open = cedrus_open,
+ .release = cedrus_release,
+ .poll = v4l2_m2m_fop_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = v4l2_m2m_fop_mmap,
+};
+
+static const struct video_device cedrus_video_device = {
+ .name = CEDRUS_NAME,
+ .vfl_dir = VFL_DIR_M2M,
+ .fops = &cedrus_fops,
+ .ioctl_ops = &cedrus_ioctl_ops,
+ .minor = -1,
+ .release = video_device_release_empty,
+ .device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING,
+};
+
+static const struct v4l2_m2m_ops cedrus_m2m_ops = {
+ .device_run = cedrus_device_run,
+};
+
+static const struct media_device_ops cedrus_m2m_media_ops = {
+ .req_validate = cedrus_request_validate,
+ .req_queue = vb2_m2m_request_queue,
+};
+
+static int cedrus_probe(struct platform_device *pdev)
+{
+ struct cedrus_dev *dev;
+ struct video_device *vfd;
+ int ret;
+
+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ dev->vfd = cedrus_video_device;
+ dev->dev = &pdev->dev;
+ dev->pdev = pdev;
+
+ ret = cedrus_hw_probe(dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to probe hardware\n");
+ return ret;
+ }
+
+ dev->dec_ops[CEDRUS_CODEC_MPEG2] = &cedrus_dec_ops_mpeg2;
+
+ mutex_init(&dev->dev_mutex);
+ spin_lock_init(&dev->irq_lock);
+
+ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register V4L2 device\n");
+ return ret;
+ }
+
+ vfd = &dev->vfd;
+ vfd->lock = &dev->dev_mutex;
+ vfd->v4l2_dev = &dev->v4l2_dev;
+
+ snprintf(vfd->name, sizeof(vfd->name), "%s", cedrus_video_device.name);
+ video_set_drvdata(vfd, dev);
+
+ dev->m2m_dev = v4l2_m2m_init(&cedrus_m2m_ops);
+ if (IS_ERR(dev->m2m_dev)) {
+ v4l2_err(&dev->v4l2_dev,
+ "Failed to initialize V4L2 M2M device\n");
+ ret = PTR_ERR(dev->m2m_dev);
+
+ goto err_video;
+ }
+
+ dev->mdev.dev = &pdev->dev;
+ strscpy(dev->mdev.model, CEDRUS_NAME, sizeof(dev->mdev.model));
+
+ media_device_init(&dev->mdev);
+ dev->mdev.ops = &cedrus_m2m_media_ops;
+ dev->v4l2_dev.mdev = &dev->mdev;
+
+ ret = v4l2_m2m_register_media_controller(dev->m2m_dev, vfd,
+ MEDIA_ENT_F_PROC_VIDEO_DECODER);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev,
+ "Failed to initialize V4L2 M2M media controller\n");
+ goto err_m2m;
+ }
+
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
+ goto err_v4l2;
+ }
+
+ v4l2_info(&dev->v4l2_dev,
+ "Device registered as /dev/video%d\n", vfd->num);
+
+ ret = media_device_register(&dev->mdev);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev, "Failed to register media device\n");
+ goto err_m2m_mc;
+ }
+
+ platform_set_drvdata(pdev, dev);
+
+ return 0;
+
+err_m2m_mc:
+ v4l2_m2m_unregister_media_controller(dev->m2m_dev);
+err_m2m:
+ v4l2_m2m_release(dev->m2m_dev);
+err_video:
+ video_unregister_device(&dev->vfd);
+err_v4l2:
+ v4l2_device_unregister(&dev->v4l2_dev);
+
+ return ret;
+}
+
+static int cedrus_remove(struct platform_device *pdev)
+{
+ struct cedrus_dev *dev = platform_get_drvdata(pdev);
+
+ if (media_devnode_is_registered(dev->mdev.devnode)) {
+ media_device_unregister(&dev->mdev);
+ v4l2_m2m_unregister_media_controller(dev->m2m_dev);
+ media_device_cleanup(&dev->mdev);
+ }
+
+ v4l2_m2m_release(dev->m2m_dev);
+ video_unregister_device(&dev->vfd);
+ v4l2_device_unregister(&dev->v4l2_dev);
+
+ cedrus_hw_remove(dev);
+
+ return 0;
+}
+
+static const struct cedrus_variant sun4i_a10_cedrus_variant = {
+ /* No particular capability. */
+};
+
+static const struct cedrus_variant sun5i_a13_cedrus_variant = {
+ /* No particular capability. */
+};
+
+static const struct cedrus_variant sun7i_a20_cedrus_variant = {
+ /* No particular capability. */
+};
+
+static const struct cedrus_variant sun8i_a33_cedrus_variant = {
+ .capabilities = CEDRUS_CAPABILITY_UNTILED,
+};
+
+static const struct cedrus_variant sun8i_h3_cedrus_variant = {
+ .capabilities = CEDRUS_CAPABILITY_UNTILED,
+};
+
+static const struct of_device_id cedrus_dt_match[] = {
+ {
+ .compatible = "allwinner,sun4i-a10-video-engine",
+ .data = &sun4i_a10_cedrus_variant,
+ },
+ {
+ .compatible = "allwinner,sun5i-a13-video-engine",
+ .data = &sun5i_a13_cedrus_variant,
+ },
+ {
+ .compatible = "allwinner,sun7i-a20-video-engine",
+ .data = &sun7i_a20_cedrus_variant,
+ },
+ {
+ .compatible = "allwinner,sun8i-a33-video-engine",
+ .data = &sun8i_a33_cedrus_variant,
+ },
+ {
+ .compatible = "allwinner,sun8i-h3-video-engine",
+ .data = &sun8i_h3_cedrus_variant,
+ },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, cedrus_dt_match);
+
+static struct platform_driver cedrus_driver = {
+ .probe = cedrus_probe,
+ .remove = cedrus_remove,
+ .driver = {
+ .name = CEDRUS_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(cedrus_dt_match),
+ },
+};
+module_platform_driver(cedrus_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Florent Revest <florent.revest@free-electrons.com>");
+MODULE_AUTHOR("Paul Kocialkowski <paul.kocialkowski@bootlin.com>");
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@bootlin.com>");
+MODULE_DESCRIPTION("Cedrus VPU driver");
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h
new file mode 100644
index 000000000000..3f61248c57ac
--- /dev/null
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.h
@@ -0,0 +1,167 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Cedrus VPU driver
+ *
+ * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
+ * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ * Copyright (C) 2018 Bootlin
+ *
+ * Based on the vim2m driver, that is:
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Pawel Osciak, <pawel@osciak.com>
+ * Marek Szyprowski, <m.szyprowski@samsung.com>
+ */
+
+#ifndef _CEDRUS_H_
+#define _CEDRUS_H_
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-v4l2.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include <linux/platform_device.h>
+
+#define CEDRUS_NAME "cedrus"
+
+#define CEDRUS_CAPABILITY_UNTILED BIT(0)
+
+enum cedrus_codec {
+ CEDRUS_CODEC_MPEG2,
+
+ CEDRUS_CODEC_LAST,
+};
+
+enum cedrus_irq_status {
+ CEDRUS_IRQ_NONE,
+ CEDRUS_IRQ_ERROR,
+ CEDRUS_IRQ_OK,
+};
+
+struct cedrus_control {
+ u32 id;
+ u32 elem_size;
+ enum cedrus_codec codec;
+ unsigned char required:1;
+};
+
+struct cedrus_mpeg2_run {
+ const struct v4l2_ctrl_mpeg2_slice_params *slice_params;
+ const struct v4l2_ctrl_mpeg2_quantization *quantization;
+};
+
+struct cedrus_run {
+ struct vb2_v4l2_buffer *src;
+ struct vb2_v4l2_buffer *dst;
+
+ union {
+ struct cedrus_mpeg2_run mpeg2;
+ };
+};
+
+struct cedrus_buffer {
+ struct v4l2_m2m_buffer m2m_buf;
+};
+
+struct cedrus_ctx {
+ struct v4l2_fh fh;
+ struct cedrus_dev *dev;
+
+ struct v4l2_pix_format src_fmt;
+ struct v4l2_pix_format dst_fmt;
+ enum cedrus_codec current_codec;
+
+ struct v4l2_ctrl_handler hdl;
+ struct v4l2_ctrl **ctrls;
+
+ struct vb2_buffer *dst_bufs[VIDEO_MAX_FRAME];
+};
+
+struct cedrus_dec_ops {
+ void (*irq_clear)(struct cedrus_ctx *ctx);
+ void (*irq_disable)(struct cedrus_ctx *ctx);
+ enum cedrus_irq_status (*irq_status)(struct cedrus_ctx *ctx);
+ void (*setup)(struct cedrus_ctx *ctx, struct cedrus_run *run);
+ int (*start)(struct cedrus_ctx *ctx);
+ void (*stop)(struct cedrus_ctx *ctx);
+ void (*trigger)(struct cedrus_ctx *ctx);
+};
+
+struct cedrus_variant {
+ unsigned int capabilities;
+};
+
+struct cedrus_dev {
+ struct v4l2_device v4l2_dev;
+ struct video_device vfd;
+ struct media_device mdev;
+ struct media_pad pad[2];
+ struct platform_device *pdev;
+ struct device *dev;
+ struct v4l2_m2m_dev *m2m_dev;
+ struct cedrus_dec_ops *dec_ops[CEDRUS_CODEC_LAST];
+
+ /* Device file mutex */
+ struct mutex dev_mutex;
+ /* Interrupt spinlock */
+ spinlock_t irq_lock;
+
+ void __iomem *base;
+
+ struct clk *mod_clk;
+ struct clk *ahb_clk;
+ struct clk *ram_clk;
+
+ struct reset_control *rstc;
+
+ unsigned int capabilities;
+};
+
+extern struct cedrus_dec_ops cedrus_dec_ops_mpeg2;
+
+static inline void cedrus_write(struct cedrus_dev *dev, u32 reg, u32 val)
+{
+ writel(val, dev->base + reg);
+}
+
+static inline u32 cedrus_read(struct cedrus_dev *dev, u32 reg)
+{
+ return readl(dev->base + reg);
+}
+
+static inline dma_addr_t cedrus_buf_addr(struct vb2_buffer *buf,
+ struct v4l2_pix_format *pix_fmt,
+ unsigned int plane)
+{
+ dma_addr_t addr = vb2_dma_contig_plane_dma_addr(buf, 0);
+
+ return addr + (pix_fmt ? (dma_addr_t)pix_fmt->bytesperline *
+ pix_fmt->height * plane : 0);
+}
+
+static inline dma_addr_t cedrus_dst_buf_addr(struct cedrus_ctx *ctx,
+ unsigned int index,
+ unsigned int plane)
+{
+ struct vb2_buffer *buf = ctx->dst_bufs[index];
+
+ return buf ? cedrus_buf_addr(buf, &ctx->dst_fmt, plane) : 0;
+}
+
+static inline struct cedrus_buffer *
+vb2_v4l2_to_cedrus_buffer(const struct vb2_v4l2_buffer *p)
+{
+ return container_of(p, struct cedrus_buffer, m2m_buf.vb);
+}
+
+static inline struct cedrus_buffer *
+vb2_to_cedrus_buffer(const struct vb2_buffer *p)
+{
+ return vb2_v4l2_to_cedrus_buffer(to_vb2_v4l2_buffer(p));
+}
+
+void *cedrus_find_control_data(struct cedrus_ctx *ctx, u32 id);
+
+#endif
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c
new file mode 100644
index 000000000000..e40180a33951
--- /dev/null
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Cedrus VPU driver
+ *
+ * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
+ * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ * Copyright (C) 2018 Bootlin
+ *
+ * Based on the vim2m driver, that is:
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Pawel Osciak, <pawel@osciak.com>
+ * Marek Szyprowski, <m.szyprowski@samsung.com>
+ */
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "cedrus.h"
+#include "cedrus_dec.h"
+#include "cedrus_hw.h"
+
+void cedrus_device_run(void *priv)
+{
+ struct cedrus_ctx *ctx = priv;
+ struct cedrus_dev *dev = ctx->dev;
+ struct cedrus_run run = { 0 };
+ struct media_request *src_req;
+ unsigned long flags;
+
+ run.src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+ run.dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+
+ /* Apply request(s) controls if needed. */
+ src_req = run.src->vb2_buf.req_obj.req;
+
+ if (src_req)
+ v4l2_ctrl_request_setup(src_req, &ctx->hdl);
+
+ spin_lock_irqsave(&ctx->dev->irq_lock, flags);
+
+ 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);
+ break;
+
+ default:
+ break;
+ }
+
+ dev->dec_ops[ctx->current_codec]->setup(ctx, &run);
+
+ spin_unlock_irqrestore(&ctx->dev->irq_lock, flags);
+
+ /* Complete request(s) controls if needed. */
+
+ if (src_req)
+ v4l2_ctrl_request_complete(src_req, &ctx->hdl);
+
+ spin_lock_irqsave(&ctx->dev->irq_lock, flags);
+
+ dev->dec_ops[ctx->current_codec]->trigger(ctx);
+
+ spin_unlock_irqrestore(&ctx->dev->irq_lock, flags);
+}
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_dec.h b/drivers/staging/media/sunxi/cedrus/cedrus_dec.h
new file mode 100644
index 000000000000..4f423d3a1cad
--- /dev/null
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_dec.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Cedrus VPU driver
+ *
+ * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
+ * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ * Copyright (C) 2018 Bootlin
+ *
+ * Based on the vim2m driver, that is:
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Pawel Osciak, <pawel@osciak.com>
+ * Marek Szyprowski, <m.szyprowski@samsung.com>
+ */
+
+#ifndef _CEDRUS_DEC_H_
+#define _CEDRUS_DEC_H_
+
+extern const struct v4l2_ioctl_ops cedrus_ioctl_ops;
+
+void cedrus_device_work(struct work_struct *work);
+void cedrus_device_run(void *priv);
+
+int cedrus_queue_init(void *priv, struct vb2_queue *src_vq,
+ struct vb2_queue *dst_vq);
+
+#endif
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c
new file mode 100644
index 000000000000..32adbcbe6175
--- /dev/null
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c
@@ -0,0 +1,327 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Cedrus VPU driver
+ *
+ * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
+ * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ * Copyright (C) 2018 Bootlin
+ *
+ * Based on the vim2m driver, that is:
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Pawel Osciak, <pawel@osciak.com>
+ * Marek Szyprowski, <m.szyprowski@samsung.com>
+ */
+
+#include <linux/platform_device.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/of_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <linux/soc/sunxi/sunxi_sram.h>
+
+#include <media/videobuf2-core.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "cedrus.h"
+#include "cedrus_hw.h"
+#include "cedrus_regs.h"
+
+int cedrus_engine_enable(struct cedrus_dev *dev, enum cedrus_codec codec)
+{
+ u32 reg = 0;
+
+ /*
+ * FIXME: This is only valid on 32-bits DDR's, we should test
+ * it on the A13/A33.
+ */
+ reg |= VE_MODE_REC_WR_MODE_2MB;
+ reg |= VE_MODE_DDR_MODE_BW_128;
+
+ switch (codec) {
+ case CEDRUS_CODEC_MPEG2:
+ reg |= VE_MODE_DEC_MPEG;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ cedrus_write(dev, VE_MODE, reg);
+
+ return 0;
+}
+
+void cedrus_engine_disable(struct cedrus_dev *dev)
+{
+ cedrus_write(dev, VE_MODE, VE_MODE_DISABLED);
+}
+
+void cedrus_dst_format_set(struct cedrus_dev *dev,
+ struct v4l2_pix_format *fmt)
+{
+ unsigned int width = fmt->width;
+ unsigned int height = fmt->height;
+ u32 chroma_size;
+ u32 reg;
+
+ switch (fmt->pixelformat) {
+ case V4L2_PIX_FMT_NV12:
+ chroma_size = ALIGN(width, 16) * ALIGN(height, 16) / 2;
+
+ reg = VE_PRIMARY_OUT_FMT_NV12;
+ cedrus_write(dev, VE_PRIMARY_OUT_FMT, reg);
+
+ reg = VE_CHROMA_BUF_LEN_SDRT(chroma_size / 2);
+ cedrus_write(dev, VE_CHROMA_BUF_LEN, reg);
+
+ reg = chroma_size / 2;
+ cedrus_write(dev, VE_PRIMARY_CHROMA_BUF_LEN, reg);
+
+ reg = VE_PRIMARY_FB_LINE_STRIDE_LUMA(ALIGN(width, 16)) |
+ VE_PRIMARY_FB_LINE_STRIDE_CHROMA(ALIGN(width, 16) / 2);
+ cedrus_write(dev, VE_PRIMARY_FB_LINE_STRIDE, reg);
+
+ break;
+ case V4L2_PIX_FMT_SUNXI_TILED_NV12:
+ default:
+ reg = VE_PRIMARY_OUT_FMT_TILED_32_NV12;
+ cedrus_write(dev, VE_PRIMARY_OUT_FMT, reg);
+
+ reg = VE_SECONDARY_OUT_FMT_TILED_32_NV12;
+ cedrus_write(dev, VE_CHROMA_BUF_LEN, reg);
+
+ break;
+ }
+}
+
+static irqreturn_t cedrus_bh(int irq, void *data)
+{
+ struct cedrus_dev *dev = data;
+ struct cedrus_ctx *ctx;
+
+ ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);
+ if (!ctx) {
+ v4l2_err(&dev->v4l2_dev,
+ "Instance released before the end of transaction\n");
+ return IRQ_HANDLED;
+ }
+
+ v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t cedrus_irq(int irq, void *data)
+{
+ struct cedrus_dev *dev = data;
+ struct cedrus_ctx *ctx;
+ struct vb2_v4l2_buffer *src_buf, *dst_buf;
+ enum vb2_buffer_state state;
+ enum cedrus_irq_status status;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->irq_lock, flags);
+
+ ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);
+ if (!ctx) {
+ v4l2_err(&dev->v4l2_dev,
+ "Instance released before the end of transaction\n");
+ spin_unlock_irqrestore(&dev->irq_lock, flags);
+
+ return IRQ_NONE;
+ }
+
+ status = dev->dec_ops[ctx->current_codec]->irq_status(ctx);
+ if (status == CEDRUS_IRQ_NONE) {
+ spin_unlock_irqrestore(&dev->irq_lock, flags);
+ return IRQ_NONE;
+ }
+
+ dev->dec_ops[ctx->current_codec]->irq_disable(ctx);
+ dev->dec_ops[ctx->current_codec]->irq_clear(ctx);
+
+ src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+ dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+
+ if (!src_buf || !dst_buf) {
+ v4l2_err(&dev->v4l2_dev,
+ "Missing source and/or destination buffers\n");
+ spin_unlock_irqrestore(&dev->irq_lock, flags);
+
+ return IRQ_HANDLED;
+ }
+
+ if (status == CEDRUS_IRQ_ERROR)
+ state = VB2_BUF_STATE_ERROR;
+ else
+ state = VB2_BUF_STATE_DONE;
+
+ v4l2_m2m_buf_done(src_buf, state);
+ v4l2_m2m_buf_done(dst_buf, state);
+
+ spin_unlock_irqrestore(&dev->irq_lock, flags);
+
+ return IRQ_WAKE_THREAD;
+}
+
+int cedrus_hw_probe(struct cedrus_dev *dev)
+{
+ const struct cedrus_variant *variant;
+ struct resource *res;
+ int irq_dec;
+ int ret;
+
+ variant = of_device_get_match_data(dev->dev);
+ if (!variant)
+ return -EINVAL;
+
+ dev->capabilities = variant->capabilities;
+
+ irq_dec = platform_get_irq(dev->pdev, 0);
+ if (irq_dec <= 0) {
+ v4l2_err(&dev->v4l2_dev, "Failed to get IRQ\n");
+
+ return irq_dec;
+ }
+ ret = devm_request_threaded_irq(dev->dev, irq_dec, cedrus_irq,
+ cedrus_bh, 0, dev_name(dev->dev),
+ dev);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev, "Failed to request IRQ\n");
+
+ return ret;
+ }
+
+ /*
+ * The VPU is only able to handle bus addresses so we have to subtract
+ * the RAM offset to the physcal addresses.
+ *
+ * This information will eventually be obtained from device-tree.
+ */
+
+#ifdef PHYS_PFN_OFFSET
+ dev->dev->dma_pfn_offset = PHYS_PFN_OFFSET;
+#endif
+
+ ret = of_reserved_mem_device_init(dev->dev);
+ if (ret && ret != -ENODEV) {
+ v4l2_err(&dev->v4l2_dev, "Failed to reserve memory\n");
+
+ return ret;
+ }
+
+ ret = sunxi_sram_claim(dev->dev);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev, "Failed to claim SRAM\n");
+
+ goto err_mem;
+ }
+
+ dev->ahb_clk = devm_clk_get(dev->dev, "ahb");
+ if (IS_ERR(dev->ahb_clk)) {
+ v4l2_err(&dev->v4l2_dev, "Failed to get AHB clock\n");
+
+ ret = PTR_ERR(dev->ahb_clk);
+ goto err_sram;
+ }
+
+ dev->mod_clk = devm_clk_get(dev->dev, "mod");
+ if (IS_ERR(dev->mod_clk)) {
+ v4l2_err(&dev->v4l2_dev, "Failed to get MOD clock\n");
+
+ ret = PTR_ERR(dev->mod_clk);
+ goto err_sram;
+ }
+
+ dev->ram_clk = devm_clk_get(dev->dev, "ram");
+ if (IS_ERR(dev->ram_clk)) {
+ v4l2_err(&dev->v4l2_dev, "Failed to get RAM clock\n");
+
+ ret = PTR_ERR(dev->ram_clk);
+ goto err_sram;
+ }
+
+ dev->rstc = devm_reset_control_get(dev->dev, NULL);
+ if (IS_ERR(dev->rstc)) {
+ v4l2_err(&dev->v4l2_dev, "Failed to get reset control\n");
+
+ ret = PTR_ERR(dev->rstc);
+ goto err_sram;
+ }
+
+ res = platform_get_resource(dev->pdev, IORESOURCE_MEM, 0);
+ dev->base = devm_ioremap_resource(dev->dev, res);
+ if (!dev->base) {
+ v4l2_err(&dev->v4l2_dev, "Failed to map registers\n");
+
+ ret = -ENOMEM;
+ goto err_sram;
+ }
+
+ ret = clk_set_rate(dev->mod_clk, CEDRUS_CLOCK_RATE_DEFAULT);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev, "Failed to set clock rate\n");
+
+ goto err_sram;
+ }
+
+ ret = clk_prepare_enable(dev->ahb_clk);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev, "Failed to enable AHB clock\n");
+
+ goto err_sram;
+ }
+
+ ret = clk_prepare_enable(dev->mod_clk);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev, "Failed to enable MOD clock\n");
+
+ goto err_ahb_clk;
+ }
+
+ ret = clk_prepare_enable(dev->ram_clk);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev, "Failed to enable RAM clock\n");
+
+ goto err_mod_clk;
+ }
+
+ ret = reset_control_reset(dev->rstc);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev, "Failed to apply reset\n");
+
+ goto err_ram_clk;
+ }
+
+ return 0;
+
+err_ram_clk:
+ clk_disable_unprepare(dev->ram_clk);
+err_mod_clk:
+ clk_disable_unprepare(dev->mod_clk);
+err_ahb_clk:
+ clk_disable_unprepare(dev->ahb_clk);
+err_sram:
+ sunxi_sram_release(dev->dev);
+err_mem:
+ of_reserved_mem_device_release(dev->dev);
+
+ return ret;
+}
+
+void cedrus_hw_remove(struct cedrus_dev *dev)
+{
+ reset_control_assert(dev->rstc);
+
+ clk_disable_unprepare(dev->ram_clk);
+ clk_disable_unprepare(dev->mod_clk);
+ clk_disable_unprepare(dev->ahb_clk);
+
+ sunxi_sram_release(dev->dev);
+
+ of_reserved_mem_device_release(dev->dev);
+}
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_hw.h b/drivers/staging/media/sunxi/cedrus/cedrus_hw.h
new file mode 100644
index 000000000000..b43c77d54b95
--- /dev/null
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_hw.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Cedrus VPU driver
+ *
+ * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
+ * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ * Copyright (C) 2018 Bootlin
+ *
+ * Based on the vim2m driver, that is:
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Pawel Osciak, <pawel@osciak.com>
+ * Marek Szyprowski, <m.szyprowski@samsung.com>
+ */
+
+#ifndef _CEDRUS_HW_H_
+#define _CEDRUS_HW_H_
+
+#define CEDRUS_CLOCK_RATE_DEFAULT 320000000
+
+int cedrus_engine_enable(struct cedrus_dev *dev, enum cedrus_codec codec);
+void cedrus_engine_disable(struct cedrus_dev *dev);
+
+void cedrus_dst_format_set(struct cedrus_dev *dev,
+ struct v4l2_pix_format *fmt);
+
+int cedrus_hw_probe(struct cedrus_dev *dev);
+void cedrus_hw_remove(struct cedrus_dev *dev);
+
+#endif
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c b/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c
new file mode 100644
index 000000000000..9abd39cae38c
--- /dev/null
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c
@@ -0,0 +1,246 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Cedrus VPU driver
+ *
+ * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
+ * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ * Copyright (C) 2018 Bootlin
+ */
+
+#include <media/videobuf2-dma-contig.h>
+
+#include "cedrus.h"
+#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;
+ u32 reg;
+
+ reg = cedrus_read(dev, VE_DEC_MPEG_STATUS);
+ reg &= VE_DEC_MPEG_STATUS_CHECK_MASK;
+
+ if (!reg)
+ return CEDRUS_IRQ_NONE;
+
+ if (reg & VE_DEC_MPEG_STATUS_CHECK_ERROR ||
+ !(reg & VE_DEC_MPEG_STATUS_SUCCESS))
+ return CEDRUS_IRQ_ERROR;
+
+ return CEDRUS_IRQ_OK;
+}
+
+static void cedrus_mpeg2_irq_clear(struct cedrus_ctx *ctx)
+{
+ struct cedrus_dev *dev = ctx->dev;
+
+ cedrus_write(dev, VE_DEC_MPEG_STATUS, VE_DEC_MPEG_STATUS_CHECK_MASK);
+}
+
+static void cedrus_mpeg2_irq_disable(struct cedrus_ctx *ctx)
+{
+ struct cedrus_dev *dev = ctx->dev;
+ u32 reg = cedrus_read(dev, VE_DEC_MPEG_CTRL);
+
+ reg &= ~VE_DEC_MPEG_CTRL_IRQ_MASK;
+
+ cedrus_write(dev, VE_DEC_MPEG_CTRL, reg);
+}
+
+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;
+ 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;
+ struct cedrus_dev *dev = ctx->dev;
+ const u8 *matrix;
+ unsigned int i;
+ u32 reg;
+
+ slice_params = run->mpeg2.slice_params;
+ sequence = &slice_params->sequence;
+ picture = &slice_params->picture;
+
+ quantization = run->mpeg2.quantization;
+
+ /* Activate MPEG engine. */
+ cedrus_engine_enable(dev, 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;
+
+ for (i = 0; i < 64; i++) {
+ reg = VE_DEC_MPEG_IQMINPUT_WEIGHT(i, matrix[i]);
+ reg |= VE_DEC_MPEG_IQMINPUT_FLAG_INTRA;
+
+ 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;
+
+ for (i = 0; i < 64; i++) {
+ reg = VE_DEC_MPEG_IQMINPUT_WEIGHT(i, matrix[i]);
+ reg |= VE_DEC_MPEG_IQMINPUT_FLAG_NON_INTRA;
+
+ cedrus_write(dev, VE_DEC_MPEG_IQMINPUT, reg);
+ }
+
+ /* 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_FULL_PEL_FORWARD_VECTOR(0);
+ reg |= VE_DEC_MPEG_MP12HDR_FULL_PEL_BACKWARD_VECTOR(0);
+
+ cedrus_write(dev, VE_DEC_MPEG_MP12HDR, reg);
+
+ /* Set frame dimensions. */
+
+ reg = VE_DEC_MPEG_PICCODEDSIZE_WIDTH(sequence->horizontal_size);
+ reg |= VE_DEC_MPEG_PICCODEDSIZE_HEIGHT(sequence->vertical_size);
+
+ cedrus_write(dev, VE_DEC_MPEG_PICCODEDSIZE, reg);
+
+ reg = VE_DEC_MPEG_PICBOUNDSIZE_WIDTH(ctx->src_fmt.width);
+ reg |= VE_DEC_MPEG_PICBOUNDSIZE_HEIGHT(ctx->src_fmt.height);
+
+ cedrus_write(dev, VE_DEC_MPEG_PICBOUNDSIZE, reg);
+
+ /* Forward and backward prediction reference buffers. */
+
+ fwd_luma_addr = cedrus_dst_buf_addr(ctx,
+ slice_params->forward_ref_index,
+ 0);
+ fwd_chroma_addr = cedrus_dst_buf_addr(ctx,
+ slice_params->forward_ref_index,
+ 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);
+
+ bwd_luma_addr = cedrus_dst_buf_addr(ctx,
+ slice_params->backward_ref_index,
+ 0);
+ bwd_chroma_addr = cedrus_dst_buf_addr(ctx,
+ slice_params->backward_ref_index,
+ 1);
+
+ cedrus_write(dev, VE_DEC_MPEG_BWD_REF_LUMA_ADDR, bwd_luma_addr);
+ cedrus_write(dev, VE_DEC_MPEG_BWD_REF_CHROMA_ADDR, bwd_chroma_addr);
+
+ /* Destination luma and chroma buffers. */
+
+ dst_luma_addr = cedrus_dst_buf_addr(ctx, run->dst->vb2_buf.index, 0);
+ dst_chroma_addr = cedrus_dst_buf_addr(ctx, run->dst->vb2_buf.index, 1);
+
+ cedrus_write(dev, VE_DEC_MPEG_REC_LUMA, dst_luma_addr);
+ cedrus_write(dev, VE_DEC_MPEG_REC_CHROMA, dst_chroma_addr);
+
+ /* Source offset and length in bits. */
+
+ cedrus_write(dev, VE_DEC_MPEG_VLD_OFFSET,
+ slice_params->data_bit_offset);
+
+ reg = slice_params->bit_size - slice_params->data_bit_offset;
+ cedrus_write(dev, VE_DEC_MPEG_VLD_LEN, reg);
+
+ /* Source beginning and end addresses. */
+
+ src_buf_addr = vb2_dma_contig_plane_dma_addr(&run->src->vb2_buf, 0);
+
+ reg = VE_DEC_MPEG_VLD_ADDR_BASE(src_buf_addr);
+ reg |= VE_DEC_MPEG_VLD_ADDR_VALID_PIC_DATA;
+ reg |= VE_DEC_MPEG_VLD_ADDR_LAST_PIC_DATA;
+ reg |= VE_DEC_MPEG_VLD_ADDR_FIRST_PIC_DATA;
+
+ cedrus_write(dev, VE_DEC_MPEG_VLD_ADDR, reg);
+
+ reg = src_buf_addr + DIV_ROUND_UP(slice_params->bit_size, 8);
+ cedrus_write(dev, VE_DEC_MPEG_VLD_END_ADDR, reg);
+
+ /* Macroblock address: start at the beginning. */
+ reg = VE_DEC_MPEG_MBADDR_Y(0) | VE_DEC_MPEG_MBADDR_X(0);
+ cedrus_write(dev, VE_DEC_MPEG_MBADDR, reg);
+
+ /* Clear previous errors. */
+ cedrus_write(dev, VE_DEC_MPEG_ERROR, 0);
+
+ /* Clear correct macroblocks register. */
+ cedrus_write(dev, VE_DEC_MPEG_CRTMBADDR, 0);
+
+ /* Enable appropriate interruptions and components. */
+
+ reg = VE_DEC_MPEG_CTRL_IRQ_MASK | VE_DEC_MPEG_CTRL_MC_NO_WRITEBACK |
+ VE_DEC_MPEG_CTRL_MC_CACHE_EN;
+
+ cedrus_write(dev, VE_DEC_MPEG_CTRL, reg);
+}
+
+static void cedrus_mpeg2_trigger(struct cedrus_ctx *ctx)
+{
+ struct cedrus_dev *dev = ctx->dev;
+ u32 reg;
+
+ /* Trigger MPEG engine. */
+ reg = VE_DEC_MPEG_TRIGGER_HW_MPEG_VLD | VE_DEC_MPEG_TRIGGER_MPEG2 |
+ VE_DEC_MPEG_TRIGGER_MB_BOUNDARY;
+
+ cedrus_write(dev, VE_DEC_MPEG_TRIGGER, reg);
+}
+
+struct cedrus_dec_ops cedrus_dec_ops_mpeg2 = {
+ .irq_clear = cedrus_mpeg2_irq_clear,
+ .irq_disable = cedrus_mpeg2_irq_disable,
+ .irq_status = cedrus_mpeg2_irq_status,
+ .setup = cedrus_mpeg2_setup,
+ .trigger = cedrus_mpeg2_trigger,
+};
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
new file mode 100644
index 000000000000..de2d6b6f64bf
--- /dev/null
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
@@ -0,0 +1,235 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Cedrus VPU driver
+ *
+ * Copyright (c) 2013-2016 Jens Kuske <jenskuske@gmail.com>
+ * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
+ * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ */
+
+#ifndef _CEDRUS_REGS_H_
+#define _CEDRUS_REGS_H_
+
+/*
+ * Common acronyms and contractions used in register descriptions:
+ * * VLD : Variable-Length Decoder
+ * * IQ: Inverse Quantization
+ * * IDCT: Inverse Discrete Cosine Transform
+ * * MC: Motion Compensation
+ * * STCD: Start Code Detect
+ * * SDRT: Scale Down and Rotate
+ */
+
+#define VE_ENGINE_DEC_MPEG 0x100
+#define VE_ENGINE_DEC_H264 0x200
+
+#define VE_MODE 0x00
+
+#define VE_MODE_REC_WR_MODE_2MB (0x01 << 20)
+#define VE_MODE_REC_WR_MODE_1MB (0x00 << 20)
+#define VE_MODE_DDR_MODE_BW_128 (0x03 << 16)
+#define VE_MODE_DDR_MODE_BW_256 (0x02 << 16)
+#define VE_MODE_DISABLED (0x07 << 0)
+#define VE_MODE_DEC_H265 (0x04 << 0)
+#define VE_MODE_DEC_H264 (0x01 << 0)
+#define VE_MODE_DEC_MPEG (0x00 << 0)
+
+#define VE_PRIMARY_CHROMA_BUF_LEN 0xc4
+#define VE_PRIMARY_FB_LINE_STRIDE 0xc8
+
+#define VE_PRIMARY_FB_LINE_STRIDE_CHROMA(s) (((s) << 16) & GENMASK(31, 16))
+#define VE_PRIMARY_FB_LINE_STRIDE_LUMA(s) (((s) << 0) & GENMASK(15, 0))
+
+#define VE_CHROMA_BUF_LEN 0xe8
+
+#define VE_SECONDARY_OUT_FMT_TILED_32_NV12 (0x00 << 30)
+#define VE_SECONDARY_OUT_FMT_EXT (0x01 << 30)
+#define VE_SECONDARY_OUT_FMT_YU12 (0x02 << 30)
+#define VE_SECONDARY_OUT_FMT_YV12 (0x03 << 30)
+#define VE_CHROMA_BUF_LEN_SDRT(l) ((l) & GENMASK(27, 0))
+
+#define VE_PRIMARY_OUT_FMT 0xec
+
+#define VE_PRIMARY_OUT_FMT_TILED_32_NV12 (0x00 << 4)
+#define VE_PRIMARY_OUT_FMT_TILED_128_NV12 (0x01 << 4)
+#define VE_PRIMARY_OUT_FMT_YU12 (0x02 << 4)
+#define VE_PRIMARY_OUT_FMT_YV12 (0x03 << 4)
+#define VE_PRIMARY_OUT_FMT_NV12 (0x04 << 4)
+#define VE_PRIMARY_OUT_FMT_NV21 (0x05 << 4)
+#define VE_SECONDARY_OUT_FMT_EXT_TILED_32_NV12 (0x00 << 0)
+#define VE_SECONDARY_OUT_FMT_EXT_TILED_128_NV12 (0x01 << 0)
+#define VE_SECONDARY_OUT_FMT_EXT_YU12 (0x02 << 0)
+#define VE_SECONDARY_OUT_FMT_EXT_YV12 (0x03 << 0)
+#define VE_SECONDARY_OUT_FMT_EXT_NV12 (0x04 << 0)
+#define VE_SECONDARY_OUT_FMT_EXT_NV21 (0x05 << 0)
+
+#define VE_VERSION 0xf0
+
+#define VE_VERSION_SHIFT 16
+
+#define VE_DEC_MPEG_MP12HDR (VE_ENGINE_DEC_MPEG + 0x00)
+
+#define VE_DEC_MPEG_MP12HDR_SLICE_TYPE(t) (((t) << 28) & GENMASK(30, 28))
+#define VE_DEC_MPEG_MP12HDR_F_CODE_SHIFT(x, y) (24 - 4 * (y) - 8 * (x))
+#define VE_DEC_MPEG_MP12HDR_F_CODE(__x, __y, __v) \
+ (((__v) & GENMASK(3, 0)) << VE_DEC_MPEG_MP12HDR_F_CODE_SHIFT(__x, __y))
+
+#define VE_DEC_MPEG_MP12HDR_INTRA_DC_PRECISION(p) \
+ (((p) << 10) & GENMASK(11, 10))
+#define VE_DEC_MPEG_MP12HDR_INTRA_PICTURE_STRUCTURE(s) \
+ (((s) << 8) & GENMASK(9, 8))
+#define VE_DEC_MPEG_MP12HDR_TOP_FIELD_FIRST(v) \
+ ((v) ? BIT(7) : 0)
+#define VE_DEC_MPEG_MP12HDR_FRAME_PRED_FRAME_DCT(v) \
+ ((v) ? BIT(6) : 0)
+#define VE_DEC_MPEG_MP12HDR_CONCEALMENT_MOTION_VECTORS(v) \
+ ((v) ? BIT(5) : 0)
+#define VE_DEC_MPEG_MP12HDR_Q_SCALE_TYPE(v) \
+ ((v) ? BIT(4) : 0)
+#define VE_DEC_MPEG_MP12HDR_INTRA_VLC_FORMAT(v) \
+ ((v) ? BIT(3) : 0)
+#define VE_DEC_MPEG_MP12HDR_ALTERNATE_SCAN(v) \
+ ((v) ? BIT(2) : 0)
+#define VE_DEC_MPEG_MP12HDR_FULL_PEL_FORWARD_VECTOR(v) \
+ ((v) ? BIT(1) : 0)
+#define VE_DEC_MPEG_MP12HDR_FULL_PEL_BACKWARD_VECTOR(v) \
+ ((v) ? BIT(0) : 0)
+
+#define VE_DEC_MPEG_PICCODEDSIZE (VE_ENGINE_DEC_MPEG + 0x08)
+
+#define VE_DEC_MPEG_PICCODEDSIZE_WIDTH(w) \
+ ((DIV_ROUND_UP((w), 16) << 8) & GENMASK(15, 8))
+#define VE_DEC_MPEG_PICCODEDSIZE_HEIGHT(h) \
+ ((DIV_ROUND_UP((h), 16) << 0) & GENMASK(7, 0))
+
+#define VE_DEC_MPEG_PICBOUNDSIZE (VE_ENGINE_DEC_MPEG + 0x0c)
+
+#define VE_DEC_MPEG_PICBOUNDSIZE_WIDTH(w) (((w) << 16) & GENMASK(27, 16))
+#define VE_DEC_MPEG_PICBOUNDSIZE_HEIGHT(h) (((h) << 0) & GENMASK(11, 0))
+
+#define VE_DEC_MPEG_MBADDR (VE_ENGINE_DEC_MPEG + 0x10)
+
+#define VE_DEC_MPEG_MBADDR_X(w) (((w) << 8) & GENMASK(15, 8))
+#define VE_DEC_MPEG_MBADDR_Y(h) (((h) << 0) & GENMASK(0, 7))
+
+#define VE_DEC_MPEG_CTRL (VE_ENGINE_DEC_MPEG + 0x14)
+
+#define VE_DEC_MPEG_CTRL_MC_CACHE_EN BIT(31)
+#define VE_DEC_MPEG_CTRL_SW_VLD BIT(27)
+#define VE_DEC_MPEG_CTRL_SW_IQ_IS BIT(17)
+#define VE_DEC_MPEG_CTRL_QP_AC_DC_OUT_EN BIT(14)
+#define VE_DEC_MPEG_CTRL_ROTATE_SCALE_OUT_EN BIT(8)
+#define VE_DEC_MPEG_CTRL_MC_NO_WRITEBACK BIT(7)
+#define VE_DEC_MPEG_CTRL_ROTATE_IRQ_EN BIT(6)
+#define VE_DEC_MPEG_CTRL_VLD_DATA_REQ_IRQ_EN BIT(5)
+#define VE_DEC_MPEG_CTRL_ERROR_IRQ_EN BIT(4)
+#define VE_DEC_MPEG_CTRL_FINISH_IRQ_EN BIT(3)
+#define VE_DEC_MPEG_CTRL_IRQ_MASK \
+ (VE_DEC_MPEG_CTRL_FINISH_IRQ_EN | VE_DEC_MPEG_CTRL_ERROR_IRQ_EN | \
+ VE_DEC_MPEG_CTRL_VLD_DATA_REQ_IRQ_EN)
+
+#define VE_DEC_MPEG_TRIGGER (VE_ENGINE_DEC_MPEG + 0x18)
+
+#define VE_DEC_MPEG_TRIGGER_MB_BOUNDARY BIT(31)
+
+#define VE_DEC_MPEG_TRIGGER_CHROMA_FMT_420 (0x00 << 27)
+#define VE_DEC_MPEG_TRIGGER_CHROMA_FMT_411 (0x01 << 27)
+#define VE_DEC_MPEG_TRIGGER_CHROMA_FMT_422 (0x02 << 27)
+#define VE_DEC_MPEG_TRIGGER_CHROMA_FMT_444 (0x03 << 27)
+#define VE_DEC_MPEG_TRIGGER_CHROMA_FMT_422T (0x04 << 27)
+
+#define VE_DEC_MPEG_TRIGGER_MPEG1 (0x01 << 24)
+#define VE_DEC_MPEG_TRIGGER_MPEG2 (0x02 << 24)
+#define VE_DEC_MPEG_TRIGGER_JPEG (0x03 << 24)
+#define VE_DEC_MPEG_TRIGGER_MPEG4 (0x04 << 24)
+#define VE_DEC_MPEG_TRIGGER_VP62 (0x05 << 24)
+
+#define VE_DEC_MPEG_TRIGGER_VP62_AC_GET_BITS BIT(7)
+
+#define VE_DEC_MPEG_TRIGGER_STCD_VC1 (0x02 << 4)
+#define VE_DEC_MPEG_TRIGGER_STCD_MPEG2 (0x01 << 4)
+#define VE_DEC_MPEG_TRIGGER_STCD_AVC (0x00 << 4)
+
+#define VE_DEC_MPEG_TRIGGER_HW_MPEG_VLD (0x0f << 0)
+#define VE_DEC_MPEG_TRIGGER_HW_JPEG_VLD (0x0e << 0)
+#define VE_DEC_MPEG_TRIGGER_HW_MB (0x0d << 0)
+#define VE_DEC_MPEG_TRIGGER_HW_ROTATE (0x0c << 0)
+#define VE_DEC_MPEG_TRIGGER_HW_VP6_VLD (0x0b << 0)
+#define VE_DEC_MPEG_TRIGGER_HW_MAF (0x0a << 0)
+#define VE_DEC_MPEG_TRIGGER_HW_STCD_END (0x09 << 0)
+#define VE_DEC_MPEG_TRIGGER_HW_STCD_BEGIN (0x08 << 0)
+#define VE_DEC_MPEG_TRIGGER_SW_MC (0x07 << 0)
+#define VE_DEC_MPEG_TRIGGER_SW_IQ (0x06 << 0)
+#define VE_DEC_MPEG_TRIGGER_SW_IDCT (0x05 << 0)
+#define VE_DEC_MPEG_TRIGGER_SW_SCALE (0x04 << 0)
+#define VE_DEC_MPEG_TRIGGER_SW_VP6 (0x03 << 0)
+#define VE_DEC_MPEG_TRIGGER_SW_VP62_AC_GET_BITS (0x02 << 0)
+
+#define VE_DEC_MPEG_STATUS (VE_ENGINE_DEC_MPEG + 0x1c)
+
+#define VE_DEC_MPEG_STATUS_START_DETECT_BUSY BIT(27)
+#define VE_DEC_MPEG_STATUS_VP6_BIT BIT(26)
+#define VE_DEC_MPEG_STATUS_VP6_BIT_BUSY BIT(25)
+#define VE_DEC_MPEG_STATUS_MAF_BUSY BIT(23)
+#define VE_DEC_MPEG_STATUS_VP6_MVP_BUSY BIT(22)
+#define VE_DEC_MPEG_STATUS_JPEG_BIT_END BIT(21)
+#define VE_DEC_MPEG_STATUS_JPEG_RESTART_ERROR BIT(20)
+#define VE_DEC_MPEG_STATUS_JPEG_MARKER BIT(19)
+#define VE_DEC_MPEG_STATUS_ROTATE_BUSY BIT(18)
+#define VE_DEC_MPEG_STATUS_DEBLOCKING_BUSY BIT(17)
+#define VE_DEC_MPEG_STATUS_SCALE_DOWN_BUSY BIT(16)
+#define VE_DEC_MPEG_STATUS_IQIS_BUF_EMPTY BIT(15)
+#define VE_DEC_MPEG_STATUS_IDCT_BUF_EMPTY BIT(14)
+#define VE_DEC_MPEG_STATUS_VE_BUSY BIT(13)
+#define VE_DEC_MPEG_STATUS_MC_BUSY BIT(12)
+#define VE_DEC_MPEG_STATUS_IDCT_BUSY BIT(11)
+#define VE_DEC_MPEG_STATUS_IQIS_BUSY BIT(10)
+#define VE_DEC_MPEG_STATUS_DCAC_BUSY BIT(9)
+#define VE_DEC_MPEG_STATUS_VLD_BUSY BIT(8)
+#define VE_DEC_MPEG_STATUS_ROTATE_SUCCESS BIT(3)
+#define VE_DEC_MPEG_STATUS_VLD_DATA_REQ BIT(2)
+#define VE_DEC_MPEG_STATUS_ERROR BIT(1)
+#define VE_DEC_MPEG_STATUS_SUCCESS BIT(0)
+#define VE_DEC_MPEG_STATUS_CHECK_MASK \
+ (VE_DEC_MPEG_STATUS_SUCCESS | VE_DEC_MPEG_STATUS_ERROR | \
+ VE_DEC_MPEG_STATUS_VLD_DATA_REQ)
+#define VE_DEC_MPEG_STATUS_CHECK_ERROR \
+ (VE_DEC_MPEG_STATUS_ERROR | VE_DEC_MPEG_STATUS_VLD_DATA_REQ)
+
+#define VE_DEC_MPEG_VLD_ADDR (VE_ENGINE_DEC_MPEG + 0x28)
+
+#define VE_DEC_MPEG_VLD_ADDR_FIRST_PIC_DATA BIT(30)
+#define VE_DEC_MPEG_VLD_ADDR_LAST_PIC_DATA BIT(29)
+#define VE_DEC_MPEG_VLD_ADDR_VALID_PIC_DATA BIT(28)
+#define VE_DEC_MPEG_VLD_ADDR_BASE(a) \
+ ({ \
+ u32 _tmp = (a); \
+ u32 _lo = _tmp & GENMASK(27, 4); \
+ u32 _hi = (_tmp >> 28) & GENMASK(3, 0); \
+ (_lo | _hi); \
+ })
+
+#define VE_DEC_MPEG_VLD_OFFSET (VE_ENGINE_DEC_MPEG + 0x2c)
+#define VE_DEC_MPEG_VLD_LEN (VE_ENGINE_DEC_MPEG + 0x30)
+#define VE_DEC_MPEG_VLD_END_ADDR (VE_ENGINE_DEC_MPEG + 0x34)
+
+#define VE_DEC_MPEG_REC_LUMA (VE_ENGINE_DEC_MPEG + 0x48)
+#define VE_DEC_MPEG_REC_CHROMA (VE_ENGINE_DEC_MPEG + 0x4c)
+#define VE_DEC_MPEG_FWD_REF_LUMA_ADDR (VE_ENGINE_DEC_MPEG + 0x50)
+#define VE_DEC_MPEG_FWD_REF_CHROMA_ADDR (VE_ENGINE_DEC_MPEG + 0x54)
+#define VE_DEC_MPEG_BWD_REF_LUMA_ADDR (VE_ENGINE_DEC_MPEG + 0x58)
+#define VE_DEC_MPEG_BWD_REF_CHROMA_ADDR (VE_ENGINE_DEC_MPEG + 0x5c)
+
+#define VE_DEC_MPEG_IQMINPUT (VE_ENGINE_DEC_MPEG + 0x80)
+
+#define VE_DEC_MPEG_IQMINPUT_FLAG_INTRA (0x01 << 14)
+#define VE_DEC_MPEG_IQMINPUT_FLAG_NON_INTRA (0x00 << 14)
+#define VE_DEC_MPEG_IQMINPUT_WEIGHT(i, v) \
+ (((v) & GENMASK(7, 0)) | (((i) << 8) & GENMASK(13, 8)))
+
+#define VE_DEC_MPEG_ERROR (VE_ENGINE_DEC_MPEG + 0xc4)
+#define VE_DEC_MPEG_CRTMBADDR (VE_ENGINE_DEC_MPEG + 0xc8)
+#define VE_DEC_MPEG_ROT_LUMA (VE_ENGINE_DEC_MPEG + 0xcc)
+#define VE_DEC_MPEG_ROT_CHROMA (VE_ENGINE_DEC_MPEG + 0xd0)
+
+#endif
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c
new file mode 100644
index 000000000000..5c5fce678b93
--- /dev/null
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c
@@ -0,0 +1,542 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Cedrus VPU driver
+ *
+ * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
+ * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ * Copyright (C) 2018 Bootlin
+ *
+ * Based on the vim2m driver, that is:
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Pawel Osciak, <pawel@osciak.com>
+ * Marek Szyprowski, <m.szyprowski@samsung.com>
+ */
+
+#include <media/videobuf2-dma-contig.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "cedrus.h"
+#include "cedrus_video.h"
+#include "cedrus_dec.h"
+#include "cedrus_hw.h"
+
+#define CEDRUS_DECODE_SRC BIT(0)
+#define CEDRUS_DECODE_DST BIT(1)
+
+#define CEDRUS_MIN_WIDTH 16U
+#define CEDRUS_MIN_HEIGHT 16U
+#define CEDRUS_MAX_WIDTH 3840U
+#define CEDRUS_MAX_HEIGHT 2160U
+
+static struct cedrus_format cedrus_formats[] = {
+ {
+ .pixelformat = V4L2_PIX_FMT_MPEG2_SLICE,
+ .directions = CEDRUS_DECODE_SRC,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_SUNXI_TILED_NV12,
+ .directions = CEDRUS_DECODE_DST,
+ },
+ {
+ .pixelformat = V4L2_PIX_FMT_NV12,
+ .directions = CEDRUS_DECODE_DST,
+ .capabilities = CEDRUS_CAPABILITY_UNTILED,
+ },
+};
+
+#define CEDRUS_FORMATS_COUNT ARRAY_SIZE(cedrus_formats)
+
+static inline struct cedrus_ctx *cedrus_file2ctx(struct file *file)
+{
+ return container_of(file->private_data, struct cedrus_ctx, fh);
+}
+
+static struct cedrus_format *cedrus_find_format(u32 pixelformat, u32 directions,
+ unsigned int capabilities)
+{
+ struct cedrus_format *fmt;
+ unsigned int i;
+
+ for (i = 0; i < CEDRUS_FORMATS_COUNT; i++) {
+ fmt = &cedrus_formats[i];
+
+ if (fmt->capabilities && (fmt->capabilities & capabilities) !=
+ fmt->capabilities)
+ continue;
+
+ if (fmt->pixelformat == pixelformat &&
+ (fmt->directions & directions) != 0)
+ break;
+ }
+
+ if (i == CEDRUS_FORMATS_COUNT)
+ return NULL;
+
+ return &cedrus_formats[i];
+}
+
+static bool cedrus_check_format(u32 pixelformat, u32 directions,
+ unsigned int capabilities)
+{
+ return cedrus_find_format(pixelformat, directions, capabilities);
+}
+
+static void cedrus_prepare_format(struct v4l2_pix_format *pix_fmt)
+{
+ unsigned int width = pix_fmt->width;
+ unsigned int height = pix_fmt->height;
+ unsigned int sizeimage = pix_fmt->sizeimage;
+ unsigned int bytesperline = pix_fmt->bytesperline;
+
+ pix_fmt->field = V4L2_FIELD_NONE;
+
+ /* Limit to hardware min/max. */
+ width = clamp(width, CEDRUS_MIN_WIDTH, CEDRUS_MAX_WIDTH);
+ height = clamp(height, CEDRUS_MIN_HEIGHT, CEDRUS_MAX_HEIGHT);
+
+ switch (pix_fmt->pixelformat) {
+ case V4L2_PIX_FMT_MPEG2_SLICE:
+ /* Zero bytes per line for encoded source. */
+ bytesperline = 0;
+
+ break;
+
+ case V4L2_PIX_FMT_SUNXI_TILED_NV12:
+ /* 32-aligned stride. */
+ bytesperline = ALIGN(width, 32);
+
+ /* 32-aligned height. */
+ height = ALIGN(height, 32);
+
+ /* Luma plane size. */
+ sizeimage = bytesperline * height;
+
+ /* Chroma plane size. */
+ sizeimage += bytesperline * height / 2;
+
+ break;
+
+ case V4L2_PIX_FMT_NV12:
+ /* 16-aligned stride. */
+ bytesperline = ALIGN(width, 16);
+
+ /* 16-aligned height. */
+ height = ALIGN(height, 16);
+
+ /* Luma plane size. */
+ sizeimage = bytesperline * height;
+
+ /* Chroma plane size. */
+ sizeimage += bytesperline * height / 2;
+
+ break;
+ }
+
+ pix_fmt->width = width;
+ pix_fmt->height = height;
+
+ pix_fmt->bytesperline = bytesperline;
+ pix_fmt->sizeimage = sizeimage;
+}
+
+static int cedrus_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ strscpy(cap->driver, CEDRUS_NAME, sizeof(cap->driver));
+ strscpy(cap->card, CEDRUS_NAME, sizeof(cap->card));
+ snprintf(cap->bus_info, sizeof(cap->bus_info),
+ "platform:%s", CEDRUS_NAME);
+
+ return 0;
+}
+
+static int cedrus_enum_fmt(struct file *file, struct v4l2_fmtdesc *f,
+ u32 direction)
+{
+ struct cedrus_ctx *ctx = cedrus_file2ctx(file);
+ struct cedrus_dev *dev = ctx->dev;
+ unsigned int capabilities = dev->capabilities;
+ struct cedrus_format *fmt;
+ unsigned int i, index;
+
+ /* Index among formats that match the requested direction. */
+ index = 0;
+
+ for (i = 0; i < CEDRUS_FORMATS_COUNT; i++) {
+ fmt = &cedrus_formats[i];
+
+ if (fmt->capabilities && (fmt->capabilities & capabilities) !=
+ fmt->capabilities)
+ continue;
+
+ if (!(cedrus_formats[i].directions & direction))
+ continue;
+
+ if (index == f->index)
+ break;
+
+ index++;
+ }
+
+ /* Matched format. */
+ if (i < CEDRUS_FORMATS_COUNT) {
+ f->pixelformat = cedrus_formats[i].pixelformat;
+
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int cedrus_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ return cedrus_enum_fmt(file, f, CEDRUS_DECODE_DST);
+}
+
+static int cedrus_enum_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ return cedrus_enum_fmt(file, f, CEDRUS_DECODE_SRC);
+}
+
+static int cedrus_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cedrus_ctx *ctx = cedrus_file2ctx(file);
+
+ /* Fall back to dummy default by lack of hardware configuration. */
+ if (!ctx->dst_fmt.width || !ctx->dst_fmt.height) {
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_SUNXI_TILED_NV12;
+ cedrus_prepare_format(&f->fmt.pix);
+
+ return 0;
+ }
+
+ f->fmt.pix = ctx->dst_fmt;
+
+ return 0;
+}
+
+static int cedrus_g_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cedrus_ctx *ctx = cedrus_file2ctx(file);
+
+ /* Fall back to dummy default by lack of hardware configuration. */
+ if (!ctx->dst_fmt.width || !ctx->dst_fmt.height) {
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG2_SLICE;
+ f->fmt.pix.sizeimage = SZ_1K;
+ cedrus_prepare_format(&f->fmt.pix);
+
+ return 0;
+ }
+
+ f->fmt.pix = ctx->src_fmt;
+
+ return 0;
+}
+
+static int cedrus_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cedrus_ctx *ctx = cedrus_file2ctx(file);
+ struct cedrus_dev *dev = ctx->dev;
+ struct v4l2_pix_format *pix_fmt = &f->fmt.pix;
+
+ if (!cedrus_check_format(pix_fmt->pixelformat, CEDRUS_DECODE_DST,
+ dev->capabilities))
+ return -EINVAL;
+
+ cedrus_prepare_format(pix_fmt);
+
+ return 0;
+}
+
+static int cedrus_try_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cedrus_ctx *ctx = cedrus_file2ctx(file);
+ struct cedrus_dev *dev = ctx->dev;
+ struct v4l2_pix_format *pix_fmt = &f->fmt.pix;
+
+ if (!cedrus_check_format(pix_fmt->pixelformat, CEDRUS_DECODE_SRC,
+ dev->capabilities))
+ return -EINVAL;
+
+ /* Source image size has to be provided by userspace. */
+ if (pix_fmt->sizeimage == 0)
+ return -EINVAL;
+
+ cedrus_prepare_format(pix_fmt);
+
+ return 0;
+}
+
+static int cedrus_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cedrus_ctx *ctx = cedrus_file2ctx(file);
+ struct cedrus_dev *dev = ctx->dev;
+ int ret;
+
+ ret = cedrus_try_fmt_vid_cap(file, priv, f);
+ if (ret)
+ return ret;
+
+ ctx->dst_fmt = f->fmt.pix;
+
+ cedrus_dst_format_set(dev, &ctx->dst_fmt);
+
+ return 0;
+}
+
+static int cedrus_s_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cedrus_ctx *ctx = cedrus_file2ctx(file);
+ int ret;
+
+ ret = cedrus_try_fmt_vid_out(file, priv, f);
+ if (ret)
+ return ret;
+
+ ctx->src_fmt = f->fmt.pix;
+
+ /* Propagate colorspace information to capture. */
+ ctx->dst_fmt.colorspace = f->fmt.pix.colorspace;
+ ctx->dst_fmt.xfer_func = f->fmt.pix.xfer_func;
+ ctx->dst_fmt.ycbcr_enc = f->fmt.pix.ycbcr_enc;
+ ctx->dst_fmt.quantization = f->fmt.pix.quantization;
+
+ return 0;
+}
+
+const struct v4l2_ioctl_ops cedrus_ioctl_ops = {
+ .vidioc_querycap = cedrus_querycap,
+
+ .vidioc_enum_fmt_vid_cap = cedrus_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = cedrus_g_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = cedrus_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = cedrus_s_fmt_vid_cap,
+
+ .vidioc_enum_fmt_vid_out = cedrus_enum_fmt_vid_out,
+ .vidioc_g_fmt_vid_out = cedrus_g_fmt_vid_out,
+ .vidioc_try_fmt_vid_out = cedrus_try_fmt_vid_out,
+ .vidioc_s_fmt_vid_out = cedrus_s_fmt_vid_out,
+
+ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
+ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
+ .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
+ .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
+ .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
+ .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
+ .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
+
+ .vidioc_streamon = v4l2_m2m_ioctl_streamon,
+ .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
+
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static int cedrus_queue_setup(struct vb2_queue *vq, unsigned int *nbufs,
+ unsigned int *nplanes, unsigned int sizes[],
+ struct device *alloc_devs[])
+{
+ struct cedrus_ctx *ctx = vb2_get_drv_priv(vq);
+ struct cedrus_dev *dev = ctx->dev;
+ struct v4l2_pix_format *pix_fmt;
+ u32 directions;
+
+ if (V4L2_TYPE_IS_OUTPUT(vq->type)) {
+ directions = CEDRUS_DECODE_SRC;
+ pix_fmt = &ctx->src_fmt;
+ } else {
+ directions = CEDRUS_DECODE_DST;
+ pix_fmt = &ctx->dst_fmt;
+ }
+
+ if (!cedrus_check_format(pix_fmt->pixelformat, directions,
+ dev->capabilities))
+ return -EINVAL;
+
+ if (*nplanes) {
+ if (sizes[0] < pix_fmt->sizeimage)
+ return -EINVAL;
+ } else {
+ sizes[0] = pix_fmt->sizeimage;
+ *nplanes = 1;
+ }
+
+ return 0;
+}
+
+static void cedrus_queue_cleanup(struct vb2_queue *vq, u32 state)
+{
+ struct cedrus_ctx *ctx = vb2_get_drv_priv(vq);
+ struct vb2_v4l2_buffer *vbuf;
+ unsigned long flags;
+
+ for (;;) {
+ spin_lock_irqsave(&ctx->dev->irq_lock, flags);
+
+ if (V4L2_TYPE_IS_OUTPUT(vq->type))
+ vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+ else
+ vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+
+ spin_unlock_irqrestore(&ctx->dev->irq_lock, flags);
+
+ if (!vbuf)
+ return;
+
+ v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req,
+ &ctx->hdl);
+ v4l2_m2m_buf_done(vbuf, state);
+ }
+}
+
+static int cedrus_buf_init(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct cedrus_ctx *ctx = vb2_get_drv_priv(vq);
+
+ if (!V4L2_TYPE_IS_OUTPUT(vq->type))
+ ctx->dst_bufs[vb->index] = vb;
+
+ return 0;
+}
+
+static void cedrus_buf_cleanup(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct cedrus_ctx *ctx = vb2_get_drv_priv(vq);
+
+ if (!V4L2_TYPE_IS_OUTPUT(vq->type))
+ ctx->dst_bufs[vb->index] = NULL;
+}
+
+static int cedrus_buf_prepare(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct cedrus_ctx *ctx = vb2_get_drv_priv(vq);
+ struct v4l2_pix_format *pix_fmt;
+
+ if (V4L2_TYPE_IS_OUTPUT(vq->type))
+ pix_fmt = &ctx->src_fmt;
+ else
+ pix_fmt = &ctx->dst_fmt;
+
+ if (vb2_plane_size(vb, 0) < pix_fmt->sizeimage)
+ return -EINVAL;
+
+ vb2_set_plane_payload(vb, 0, pix_fmt->sizeimage);
+
+ return 0;
+}
+
+static int cedrus_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+ struct cedrus_ctx *ctx = vb2_get_drv_priv(vq);
+ struct cedrus_dev *dev = ctx->dev;
+ int ret = 0;
+
+ switch (ctx->src_fmt.pixelformat) {
+ case V4L2_PIX_FMT_MPEG2_SLICE:
+ ctx->current_codec = CEDRUS_CODEC_MPEG2;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (V4L2_TYPE_IS_OUTPUT(vq->type) &&
+ dev->dec_ops[ctx->current_codec]->start)
+ ret = dev->dec_ops[ctx->current_codec]->start(ctx);
+
+ if (ret)
+ cedrus_queue_cleanup(vq, VB2_BUF_STATE_QUEUED);
+
+ return ret;
+}
+
+static void cedrus_stop_streaming(struct vb2_queue *vq)
+{
+ struct cedrus_ctx *ctx = vb2_get_drv_priv(vq);
+ struct cedrus_dev *dev = ctx->dev;
+
+ if (V4L2_TYPE_IS_OUTPUT(vq->type) &&
+ dev->dec_ops[ctx->current_codec]->stop)
+ dev->dec_ops[ctx->current_codec]->stop(ctx);
+
+ cedrus_queue_cleanup(vq, VB2_BUF_STATE_ERROR);
+}
+
+static void cedrus_buf_queue(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct cedrus_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+ v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
+}
+
+static void cedrus_buf_request_complete(struct vb2_buffer *vb)
+{
+ struct cedrus_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+ v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl);
+}
+
+static struct vb2_ops cedrus_qops = {
+ .queue_setup = cedrus_queue_setup,
+ .buf_prepare = cedrus_buf_prepare,
+ .buf_init = cedrus_buf_init,
+ .buf_cleanup = cedrus_buf_cleanup,
+ .buf_queue = cedrus_buf_queue,
+ .buf_request_complete = cedrus_buf_request_complete,
+ .start_streaming = cedrus_start_streaming,
+ .stop_streaming = cedrus_stop_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+};
+
+int cedrus_queue_init(void *priv, struct vb2_queue *src_vq,
+ struct vb2_queue *dst_vq)
+{
+ struct cedrus_ctx *ctx = priv;
+ int ret;
+
+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+ src_vq->drv_priv = ctx;
+ src_vq->buf_struct_size = sizeof(struct cedrus_buffer);
+ src_vq->min_buffers_needed = 1;
+ src_vq->ops = &cedrus_qops;
+ src_vq->mem_ops = &vb2_dma_contig_memops;
+ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ src_vq->lock = &ctx->dev->dev_mutex;
+ src_vq->dev = ctx->dev->dev;
+ src_vq->supports_requests = true;
+
+ ret = vb2_queue_init(src_vq);
+ if (ret)
+ return ret;
+
+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+ dst_vq->drv_priv = ctx;
+ dst_vq->buf_struct_size = sizeof(struct cedrus_buffer);
+ dst_vq->min_buffers_needed = 1;
+ dst_vq->ops = &cedrus_qops;
+ dst_vq->mem_ops = &vb2_dma_contig_memops;
+ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ dst_vq->lock = &ctx->dev->dev_mutex;
+ dst_vq->dev = ctx->dev->dev;
+
+ return vb2_queue_init(dst_vq);
+}
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.h b/drivers/staging/media/sunxi/cedrus/cedrus_video.h
new file mode 100644
index 000000000000..0e4f7a8cccf2
--- /dev/null
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Cedrus VPU driver
+ *
+ * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
+ * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ * Copyright (C) 2018 Bootlin
+ *
+ * Based on the vim2m driver, that is:
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Pawel Osciak, <pawel@osciak.com>
+ * Marek Szyprowski, <m.szyprowski@samsung.com>
+ */
+
+#ifndef _CEDRUS_VIDEO_H_
+#define _CEDRUS_VIDEO_H_
+
+struct cedrus_format {
+ u32 pixelformat;
+ u32 directions;
+ unsigned int capabilities;
+};
+
+extern const struct v4l2_ioctl_ops cedrus_ioctl_ops;
+
+int cedrus_queue_init(void *priv, struct vb2_queue *src_vq,
+ struct vb2_queue *dst_vq);
+
+#endif
diff --git a/drivers/staging/media/zoran/zoran_card.c b/drivers/staging/media/zoran/zoran_card.c
index a6b9ebd20263..94dadbba7cd5 100644
--- a/drivers/staging/media/zoran/zoran_card.c
+++ b/drivers/staging/media/zoran/zoran_card.c
@@ -706,7 +706,7 @@ zoran_register_i2c (struct zoran *zr)
{
zr->i2c_algo = zoran_i2c_bit_data_template;
zr->i2c_algo.data = zr;
- strlcpy(zr->i2c_adapter.name, ZR_DEVNAME(zr),
+ strscpy(zr->i2c_adapter.name, ZR_DEVNAME(zr),
sizeof(zr->i2c_adapter.name));
i2c_set_adapdata(&zr->i2c_adapter, &zr->v4l2_dev);
zr->i2c_adapter.algo_data = &zr->i2c_algo;
@@ -1048,7 +1048,7 @@ static int zr36057_init (struct zoran *zr)
*zr->video_dev = zoran_template;
zr->video_dev->v4l2_dev = &zr->v4l2_dev;
zr->video_dev->lock = &zr->lock;
- strcpy(zr->video_dev->name, ZR_DEVNAME(zr));
+ strscpy(zr->video_dev->name, ZR_DEVNAME(zr), sizeof(zr->video_dev->name));
/* It's not a mem2mem device, but you can both capture and output from
one and the same device. This should really be split up into two
device nodes, but that's a job for another day. */
@@ -1145,7 +1145,7 @@ static struct videocodec_master *zoran_setup_videocodec(struct zoran *zr,
m->type = 0;
m->flags = CODEC_FLAG_ENCODER | CODEC_FLAG_DECODER;
- strlcpy(m->name, ZR_DEVNAME(zr), sizeof(m->name));
+ strscpy(m->name, ZR_DEVNAME(zr), sizeof(m->name));
m->data = zr;
switch (type)
diff --git a/drivers/staging/media/zoran/zoran_driver.c b/drivers/staging/media/zoran/zoran_driver.c
index d7842224fff6..27c76e2eeb41 100644
--- a/drivers/staging/media/zoran/zoran_driver.c
+++ b/drivers/staging/media/zoran/zoran_driver.c
@@ -692,7 +692,7 @@ static int zoran_jpg_queue_frame(struct zoran_fh *fh, int num,
case BUZ_STATE_DONE:
dprintk(2,
KERN_WARNING
- "%s: %s - queing frame in BUZ_STATE_DONE state!?\n",
+ "%s: %s - queuing frame in BUZ_STATE_DONE state!?\n",
ZR_DEVNAME(zr), __func__);
/* fall through */
case BUZ_STATE_USER:
@@ -1510,8 +1510,8 @@ static int zoran_querycap(struct file *file, void *__fh, struct v4l2_capability
struct zoran_fh *fh = __fh;
struct zoran *zr = fh->zr;
- strlcpy(cap->card, ZR_DEVNAME(zr), sizeof(cap->card));
- strlcpy(cap->driver, "zoran", sizeof(cap->driver));
+ strscpy(cap->card, ZR_DEVNAME(zr), sizeof(cap->card));
+ strscpy(cap->driver, "zoran", sizeof(cap->driver));
snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
pci_name(zr->pci_dev));
cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE |
diff --git a/drivers/staging/most/cdev/cdev.c b/drivers/staging/most/cdev/cdev.c
index 4569838f27a0..ea64aabda94e 100644
--- a/drivers/staging/most/cdev/cdev.c
+++ b/drivers/staging/most/cdev/cdev.c
@@ -447,7 +447,7 @@ static int comp_probe(struct most_interface *iface, int channel_id,
c = kzalloc(sizeof(*c), GFP_KERNEL);
if (!c) {
retval = -ENOMEM;
- goto error_alloc_channel;
+ goto err_remove_ida;
}
c->devno = MKDEV(comp.major, current_minor);
@@ -463,7 +463,7 @@ static int comp_probe(struct most_interface *iface, int channel_id,
retval = kfifo_alloc(&c->fifo, cfg->num_buffers, GFP_KERNEL);
if (retval) {
pr_info("failed to alloc channel kfifo");
- goto error_alloc_kfifo;
+ goto err_del_cdev_and_free_channel;
}
init_waitqueue_head(&c->wq);
mutex_init(&c->io_mutex);
@@ -475,18 +475,18 @@ static int comp_probe(struct most_interface *iface, int channel_id,
if (IS_ERR(c->dev)) {
retval = PTR_ERR(c->dev);
pr_info("failed to create new device node %s\n", name);
- goto error_create_device;
+ goto err_free_kfifo_and_del_list;
}
kobject_uevent(&c->dev->kobj, KOBJ_ADD);
return 0;
-error_create_device:
+err_free_kfifo_and_del_list:
kfifo_free(&c->fifo);
list_del(&c->list);
-error_alloc_kfifo:
+err_del_cdev_and_free_channel:
cdev_del(&c->cdev);
kfree(c);
-error_alloc_channel:
+err_remove_ida:
ida_simple_remove(&comp.minor_id, current_minor);
return retval;
}
diff --git a/drivers/staging/most/core.c b/drivers/staging/most/core.c
index f4c464625a67..6a18cf73c85e 100644
--- a/drivers/staging/most/core.c
+++ b/drivers/staging/most/core.c
@@ -442,6 +442,24 @@ static ssize_t set_dbr_size_store(struct device *dev,
return count;
}
+#define to_dev_attr(a) container_of(a, struct device_attribute, attr)
+static umode_t channel_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int index)
+{
+ struct device_attribute *dev_attr = to_dev_attr(attr);
+ struct device *dev = kobj_to_dev(kobj);
+ struct most_channel *c = to_channel(dev);
+
+ if (!strcmp(dev_attr->attr.name, "set_dbr_size") &&
+ (c->iface->interface != ITYPE_MEDIALB_DIM2))
+ return 0;
+ if (!strcmp(dev_attr->attr.name, "set_packets_per_xact") &&
+ (c->iface->interface != ITYPE_USB))
+ return 0;
+
+ return attr->mode;
+}
+
#define DEV_ATTR(_name) (&dev_attr_##_name.attr)
static DEVICE_ATTR_RO(available_directions);
@@ -479,6 +497,7 @@ static struct attribute *channel_attrs[] = {
static struct attribute_group channel_attr_group = {
.attrs = channel_attrs,
+ .is_visible = channel_attr_is_visible,
};
static const struct attribute_group *channel_attr_groups[] = {
@@ -1216,7 +1235,7 @@ int most_start_channel(struct most_interface *iface, int id,
if (c->iface->configure(c->iface, c->channel_id, &c->cfg)) {
pr_info("channel configuration failed. Go check settings...\n");
ret = -EINVAL;
- goto error;
+ goto err_put_module;
}
init_waitqueue_head(&c->hdm_fifo_wq);
@@ -1229,12 +1248,12 @@ int most_start_channel(struct most_interface *iface, int id,
most_write_completion);
if (unlikely(!num_buffer)) {
ret = -ENOMEM;
- goto error;
+ goto err_put_module;
}
ret = run_enqueue_thread(c, id);
if (ret)
- goto error;
+ goto err_put_module;
c->is_starving = 0;
c->pipe0.num_buffers = c->cfg.num_buffers / 2;
@@ -1249,7 +1268,7 @@ out:
mutex_unlock(&c->start_mutex);
return 0;
-error:
+err_put_module:
module_put(iface->mod);
mutex_unlock(&c->start_mutex);
return ret;
@@ -1430,7 +1449,7 @@ int most_register_interface(struct most_interface *iface)
c = kzalloc(sizeof(*c), GFP_KERNEL);
if (!c)
- goto free_instance;
+ goto err_free_resources;
if (!name_suffix)
snprintf(c->name, STRING_SIZE, "ch%d", i);
else
@@ -1439,10 +1458,6 @@ int most_register_interface(struct most_interface *iface)
c->dev.parent = &iface->dev;
c->dev.groups = channel_attr_groups;
c->dev.release = release_channel;
- if (device_register(&c->dev)) {
- pr_err("registering c->dev failed\n");
- goto free_instance_nodev;
- }
iface->p->channel[i] = c;
c->is_starving = 0;
c->iface = iface;
@@ -1465,15 +1480,19 @@ int most_register_interface(struct most_interface *iface)
mutex_init(&c->start_mutex);
mutex_init(&c->nq_mutex);
list_add_tail(&c->list, &iface->p->channel_list);
+ if (device_register(&c->dev)) {
+ pr_err("registering c->dev failed\n");
+ goto err_free_most_channel;
+ }
}
pr_info("registered new device mdev%d (%s)\n",
id, iface->description);
return 0;
-free_instance_nodev:
+err_free_most_channel:
kfree(c);
-free_instance:
+err_free_resources:
while (i > 0) {
c = iface->p->channel[--i];
device_unregister(&c->dev);
@@ -1594,20 +1613,20 @@ static int __init most_init(void)
err = driver_register(&mc.drv);
if (err) {
pr_info("Cannot register core driver\n");
- goto exit_bus;
+ goto err_unregister_bus;
}
mc.dev.init_name = "most_bus";
mc.dev.release = release_most_sub;
if (device_register(&mc.dev)) {
err = -ENOMEM;
- goto exit_driver;
+ goto err_unregister_driver;
}
return 0;
-exit_driver:
+err_unregister_driver:
driver_unregister(&mc.drv);
-exit_bus:
+err_unregister_bus:
bus_unregister(&mc.bus);
return err;
}
diff --git a/drivers/staging/most/net/net.c b/drivers/staging/most/net/net.c
index 30d816b7e165..e20584b1b112 100644
--- a/drivers/staging/most/net/net.c
+++ b/drivers/staging/most/net/net.c
@@ -75,7 +75,7 @@ static struct core_component comp;
static int skb_to_mamac(const struct sk_buff *skb, struct mbo *mbo)
{
u8 *buff = mbo->virt_address;
- const u8 broadcast[] = { 0x03, 0xFF };
+ static const u8 broadcast[] = { 0x03, 0xFF };
const u8 *dest_addr = skb->data + 4;
const u8 *eth_type = skb->data + 12;
unsigned int payload_len = skb->len - ETH_HLEN;
diff --git a/drivers/staging/most/usb/usb.c b/drivers/staging/most/usb/usb.c
index bc820f90bcb1..c0293d8d5934 100644
--- a/drivers/staging/most/usb/usb.c
+++ b/drivers/staging/most/usb/usb.c
@@ -568,19 +568,19 @@ static int hdm_enqueue(struct most_interface *iface, int channel,
mutex_lock(&mdev->io_mutex);
if (!mdev->usb_device) {
retval = -ENODEV;
- goto _exit;
+ goto unlock_io_mutex;
}
urb = usb_alloc_urb(NO_ISOCHRONOUS_URB, GFP_ATOMIC);
if (!urb) {
retval = -ENOMEM;
- goto _exit;
+ goto unlock_io_mutex;
}
if ((conf->direction & MOST_CH_TX) && mdev->padding_active[channel] &&
hdm_add_padding(mdev, channel, mbo)) {
retval = -EIO;
- goto _error;
+ goto err_free_urb;
}
urb->transfer_dma = mbo->bus_address;
@@ -615,15 +615,15 @@ static int hdm_enqueue(struct most_interface *iface, int channel,
if (retval) {
dev_err(&mdev->usb_device->dev,
"URB submit failed with error %d.\n", retval);
- goto _error_1;
+ goto err_unanchor_urb;
}
- goto _exit;
+ goto unlock_io_mutex;
-_error_1:
+err_unanchor_urb:
usb_unanchor_urb(urb);
-_error:
+err_free_urb:
usb_free_urb(urb);
-_exit:
+unlock_io_mutex:
mutex_unlock(&mdev->io_mutex);
return retval;
}
@@ -1015,6 +1015,13 @@ static const struct attribute_group *dci_attr_groups[] = {
NULL,
};
+static void release_dci(struct device *dev)
+{
+ struct most_dci_obj *dci = to_dci_obj(dev);
+
+ kfree(dci);
+}
+
/**
* hdm_probe - probe function of USB device driver
* @interface: Interface of the attached USB device
@@ -1041,7 +1048,7 @@ hdm_probe(struct usb_interface *interface, const struct usb_device_id *id)
int ret = 0;
if (!mdev)
- goto exit_ENOMEM;
+ goto err_out_of_memory;
usb_set_intfdata(interface, mdev);
num_endpoints = usb_iface_desc->desc.bNumEndpoints;
@@ -1073,22 +1080,22 @@ hdm_probe(struct usb_interface *interface, const struct usb_device_id *id)
mdev->conf = kcalloc(num_endpoints, sizeof(*mdev->conf), GFP_KERNEL);
if (!mdev->conf)
- goto exit_free;
+ goto err_free_mdev;
mdev->cap = kcalloc(num_endpoints, sizeof(*mdev->cap), GFP_KERNEL);
if (!mdev->cap)
- goto exit_free1;
+ goto err_free_conf;
mdev->iface.channel_vector = mdev->cap;
mdev->ep_address =
kcalloc(num_endpoints, sizeof(*mdev->ep_address), GFP_KERNEL);
if (!mdev->ep_address)
- goto exit_free2;
+ goto err_free_cap;
mdev->busy_urbs =
kcalloc(num_endpoints, sizeof(*mdev->busy_urbs), GFP_KERNEL);
if (!mdev->busy_urbs)
- goto exit_free3;
+ goto err_free_ep_address;
tmp_cap = mdev->cap;
for (i = 0; i < num_endpoints; i++) {
@@ -1129,7 +1136,7 @@ hdm_probe(struct usb_interface *interface, const struct usb_device_id *id)
ret = most_register_interface(&mdev->iface);
if (ret)
- goto exit_free4;
+ goto err_free_busy_urbs;
mutex_lock(&mdev->io_mutex);
if (le16_to_cpu(usb_dev->descriptor.idProduct) == USB_DEV_ID_OS81118 ||
@@ -1140,35 +1147,36 @@ hdm_probe(struct usb_interface *interface, const struct usb_device_id *id)
mutex_unlock(&mdev->io_mutex);
most_deregister_interface(&mdev->iface);
ret = -ENOMEM;
- goto exit_free4;
+ goto err_free_busy_urbs;
}
mdev->dci->dev.init_name = "dci";
mdev->dci->dev.parent = &mdev->iface.dev;
mdev->dci->dev.groups = dci_attr_groups;
+ mdev->dci->dev.release = release_dci;
if (device_register(&mdev->dci->dev)) {
mutex_unlock(&mdev->io_mutex);
most_deregister_interface(&mdev->iface);
ret = -ENOMEM;
- goto exit_free5;
+ goto err_free_dci;
}
mdev->dci->usb_device = mdev->usb_device;
}
mutex_unlock(&mdev->io_mutex);
return 0;
-exit_free5:
+err_free_dci:
kfree(mdev->dci);
-exit_free4:
+err_free_busy_urbs:
kfree(mdev->busy_urbs);
-exit_free3:
+err_free_ep_address:
kfree(mdev->ep_address);
-exit_free2:
+err_free_cap:
kfree(mdev->cap);
-exit_free1:
+err_free_conf:
kfree(mdev->conf);
-exit_free:
+err_free_mdev:
kfree(mdev);
-exit_ENOMEM:
+err_out_of_memory:
if (ret == 0 || ret == -ENOMEM) {
ret = -ENOMEM;
dev_err(dev, "out of memory\n");
@@ -1198,7 +1206,6 @@ static void hdm_disconnect(struct usb_interface *interface)
cancel_work_sync(&mdev->poll_work_obj);
device_unregister(&mdev->dci->dev);
- kfree(mdev->dci);
most_deregister_interface(&mdev->iface);
kfree(mdev->busy_urbs);
diff --git a/drivers/staging/most/video/video.c b/drivers/staging/most/video/video.c
index cf342eb58e10..ad7e28ab9a4f 100644
--- a/drivers/staging/most/video/video.c
+++ b/drivers/staging/most/video/video.c
@@ -530,7 +530,7 @@ static int comp_disconnect_channel(struct most_interface *iface,
return 0;
}
-static struct core_component comp_info = {
+static struct core_component comp = {
.name = "video",
.probe_channel = comp_probe_channel,
.disconnect_channel = comp_disconnect_channel,
@@ -565,7 +565,7 @@ static void __exit comp_exit(void)
}
spin_unlock_irq(&list_lock);
- most_deregister_component(&comp_info);
+ most_deregister_component(&comp);
BUG_ON(!list_empty(&video_devices));
}
diff --git a/drivers/staging/mt29f_spinand/mt29f_spinand.c b/drivers/staging/mt29f_spinand/mt29f_spinand.c
index 448478451c4c..def8a1f57d1c 100644
--- a/drivers/staging/mt29f_spinand/mt29f_spinand.c
+++ b/drivers/staging/mt29f_spinand/mt29f_spinand.c
@@ -630,8 +630,7 @@ static int spinand_erase_block(struct spi_device *spi_nand, u16 block_id)
}
#ifdef CONFIG_MTD_SPINAND_ONDIEECC
-static int spinand_write_page_hwecc(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int spinand_write_page_hwecc(struct nand_chip *chip,
const u8 *buf, int oob_required,
int page)
{
@@ -643,21 +642,22 @@ static int spinand_write_page_hwecc(struct mtd_info *mtd,
return nand_prog_page_op(chip, page, 0, p, eccsize * eccsteps);
}
-static int spinand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
- u8 *buf, int oob_required, int page)
+static int spinand_read_page_hwecc(struct nand_chip *chip, u8 *buf,
+ int oob_required, int page)
{
int retval;
u8 status;
u8 *p = buf;
int eccsize = chip->ecc.size;
int eccsteps = chip->ecc.steps;
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct spinand_info *info = nand_get_controller_data(chip);
enable_read_hw_ecc = 1;
nand_read_page_op(chip, page, 0, p, eccsize * eccsteps);
if (oob_required)
- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize);
while (1) {
retval = spinand_read_status(info->spi, &status);
@@ -681,13 +681,13 @@ static int spinand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
}
#endif
-static void spinand_select_chip(struct mtd_info *mtd, int dev)
+static void spinand_select_chip(struct nand_chip *chip, int dev)
{
}
-static u8 spinand_read_byte(struct mtd_info *mtd)
+static u8 spinand_read_byte(struct nand_chip *chip)
{
- struct spinand_state *state = mtd_to_state(mtd);
+ struct spinand_state *state = mtd_to_state(nand_to_mtd(chip));
u8 data;
data = state->buf[state->buf_ptr];
@@ -695,8 +695,9 @@ static u8 spinand_read_byte(struct mtd_info *mtd)
return data;
}
-static int spinand_wait(struct mtd_info *mtd, struct nand_chip *chip)
+static int spinand_wait(struct nand_chip *chip)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct spinand_info *info = nand_get_controller_data(chip);
unsigned long timeo = jiffies;
@@ -724,17 +725,17 @@ static int spinand_wait(struct mtd_info *mtd, struct nand_chip *chip)
return 0;
}
-static void spinand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+static void spinand_write_buf(struct nand_chip *chip, const u8 *buf, int len)
{
- struct spinand_state *state = mtd_to_state(mtd);
+ struct spinand_state *state = mtd_to_state(nand_to_mtd(chip));
memcpy(state->buf + state->buf_ptr, buf, len);
state->buf_ptr += len;
}
-static void spinand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+static void spinand_read_buf(struct nand_chip *chip, u8 *buf, int len)
{
- struct spinand_state *state = mtd_to_state(mtd);
+ struct spinand_state *state = mtd_to_state(nand_to_mtd(chip));
memcpy(buf, state->buf + state->buf_ptr, len);
state->buf_ptr += len;
@@ -759,10 +760,10 @@ static void spinand_reset(struct spi_device *spi_nand)
dev_err(&spi_nand->dev, "wait timedout!\n");
}
-static void spinand_cmdfunc(struct mtd_info *mtd, unsigned int command,
+static void spinand_cmdfunc(struct nand_chip *chip, unsigned int command,
int column, int page)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct spinand_info *info = nand_get_controller_data(chip);
struct spinand_state *state = info->priv;
@@ -914,15 +915,15 @@ static int spinand_probe(struct spi_device *spi_nand)
nand_set_flash_node(chip, spi_nand->dev.of_node);
nand_set_controller_data(chip, info);
- chip->read_buf = spinand_read_buf;
- chip->write_buf = spinand_write_buf;
- chip->read_byte = spinand_read_byte;
- chip->cmdfunc = spinand_cmdfunc;
- chip->waitfunc = spinand_wait;
+ chip->legacy.read_buf = spinand_read_buf;
+ chip->legacy.write_buf = spinand_write_buf;
+ chip->legacy.read_byte = spinand_read_byte;
+ chip->legacy.cmdfunc = spinand_cmdfunc;
+ chip->legacy.waitfunc = spinand_wait;
chip->options |= NAND_CACHEPRG;
chip->select_chip = spinand_select_chip;
- chip->set_features = nand_get_set_features_notsupp;
- chip->get_features = nand_get_set_features_notsupp;
+ chip->legacy.set_features = nand_get_set_features_notsupp;
+ chip->legacy.get_features = nand_get_set_features_notsupp;
mtd = nand_to_mtd(chip);
@@ -934,7 +935,7 @@ static int spinand_probe(struct spi_device *spi_nand)
mtd_set_ooblayout(mtd, &spinand_oob_64_ops);
#endif
- if (nand_scan(mtd, 1))
+ if (nand_scan(chip, 1))
return -ENXIO;
return mtd_device_register(mtd, NULL, 0);
diff --git a/drivers/staging/mt7621-dma/ralink-gdma.c b/drivers/staging/mt7621-dma/ralink-gdma.c
index 6d9fe175ea52..73dbc7fe38a2 100644
--- a/drivers/staging/mt7621-dma/ralink-gdma.c
+++ b/drivers/staging/mt7621-dma/ralink-gdma.c
@@ -47,7 +47,6 @@
#define GDMA_REG_CTRL1_REQ_MASK 0x3f
#define GDMA_REG_CTRL1_SRC_REQ_SHIFT 16
#define GDMA_REG_CTRL1_DST_REQ_SHIFT 8
-#define GDMA_REG_CTRL1_CONTINOUS BIT(14)
#define GDMA_REG_CTRL1_NEXT_MASK 0x1f
#define GDMA_REG_CTRL1_NEXT_SHIFT 3
#define GDMA_REG_CTRL1_COHERENT BIT(2)
diff --git a/drivers/staging/mt7621-eth/gsw_mt7621.c b/drivers/staging/mt7621-eth/gsw_mt7621.c
index 2c07b559bed7..53767b17bad9 100644
--- a/drivers/staging/mt7621-eth/gsw_mt7621.c
+++ b/drivers/staging/mt7621-eth/gsw_mt7621.c
@@ -286,7 +286,6 @@ static struct platform_driver gsw_driver = {
.remove = mt7621_gsw_remove,
.driver = {
.name = "mt7621-gsw",
- .owner = THIS_MODULE,
.of_match_table = mediatek_gsw_match,
},
};
diff --git a/drivers/staging/mt7621-eth/mdio.c b/drivers/staging/mt7621-eth/mdio.c
index 7ad0c4141205..ee851281b657 100644
--- a/drivers/staging/mt7621-eth/mdio.c
+++ b/drivers/staging/mt7621-eth/mdio.c
@@ -70,7 +70,7 @@ int mtk_connect_phy_node(struct mtk_eth *eth, struct mtk_mac *mac,
_port = of_get_property(phy_node, "reg", NULL);
if (!_port || (be32_to_cpu(*_port) >= 0x20)) {
- pr_err("%s: invalid port id\n", phy_node->name);
+ pr_err("%pOFn: invalid port id\n", phy_node);
return -EINVAL;
}
port = be32_to_cpu(*_port);
@@ -112,7 +112,7 @@ static void phy_init(struct mtk_eth *eth, struct mtk_mac *mac,
phy->autoneg = AUTONEG_ENABLE;
phy->speed = 0;
phy->duplex = 0;
- phy->supported &= PHY_BASIC_FEATURES;
+ phy_set_max_speed(phy, SPEED_100);
phy->advertising = phy->supported | ADVERTISED_Autoneg;
phy_start_aneg(phy);
@@ -249,7 +249,7 @@ int mtk_mdio_init(struct mtk_eth *eth)
eth->mii_bus->priv = eth;
eth->mii_bus->parent = eth->dev;
- snprintf(eth->mii_bus->id, MII_BUS_ID_SIZE, "%s", mii_np->name);
+ snprintf(eth->mii_bus->id, MII_BUS_ID_SIZE, "%pOFn", mii_np);
err = of_mdiobus_register(eth->mii_bus, mii_np);
if (err)
goto err_free_bus;
diff --git a/drivers/staging/mt7621-eth/mtk_eth_soc.c b/drivers/staging/mt7621-eth/mtk_eth_soc.c
index 713507558568..363d3c978e02 100644
--- a/drivers/staging/mt7621-eth/mtk_eth_soc.c
+++ b/drivers/staging/mt7621-eth/mtk_eth_soc.c
@@ -2167,7 +2167,6 @@ static struct platform_driver mtk_driver = {
.remove = mtk_remove,
.driver = {
.name = "mtk_soc_eth",
- .owner = THIS_MODULE,
.of_match_table = of_mtk_match,
},
};
diff --git a/drivers/staging/mt7621-mmc/dbg.c b/drivers/staging/mt7621-mmc/dbg.c
index 6e518dce9029..829d3d0e895e 100644
--- a/drivers/staging/mt7621-mmc/dbg.c
+++ b/drivers/staging/mt7621-mmc/dbg.c
@@ -5,7 +5,8 @@
* is confidential and proprietary to MediaTek Inc. and/or its licensors.
* Without the prior written permission of MediaTek inc. and/or its licensors,
* any reproduction, modification, use or disclosure of MediaTek Software,
- * and information contained herein, in whole or in part, shall be strictly prohibited.
+ * and information contained herein, in whole or in part, shall be strictly
+ * prohibited.
*
* MediaTek Inc. (C) 2010. All rights reserved.
*
@@ -17,20 +18,22 @@
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
- * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
- * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
- * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
- * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
- * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
- * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
- * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
- * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
- * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
- * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO
+ * SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY
+ * ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY
+ * THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK
+ * SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO
+ * RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR STANDARD OR OPEN
+ * FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED
+ * HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK
+ * SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE
+ * PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
*
- * The following software/firmware and/or related documentation ("MediaTek Software")
- * have been modified by MediaTek Inc. All revisions are subject to any receiver's
- * applicable license agreements with MediaTek Inc.
+ * The following software/firmware and/or related documentation
+ * ("MediaTek Software") have been modified by MediaTek Inc. All revisions
+ * are subject to any receiver's applicable license agreements with MediaTek
+ * Inc.
*/
#include <linux/version.h>
@@ -66,23 +69,6 @@ u32 sdio_pro_enable; /* make sure gpt is enabled */
u32 sdio_pro_time; /* no more than 30s */
struct sdio_profile sdio_perfomance = {0};
-#if 0 /* --- chhung */
-void msdc_init_gpt(void)
-{
- GPT_CONFIG config;
-
- config.num = GPT6;
- config.mode = GPT_FREE_RUN;
- config.clkSrc = GPT_CLK_SRC_SYS;
- config.clkDiv = GPT_CLK_DIV_1; /* 13MHz GPT6 */
-
- if (GPT_Config(config) == FALSE)
- return;
-
- GPT_Start(GPT6);
-}
-#endif /* end of --- */
-
u32 msdc_time_calc(u32 old_L32, u32 old_H32, u32 new_L32, u32 new_H32)
{
u32 ret = 0;
@@ -91,7 +77,8 @@ u32 msdc_time_calc(u32 old_L32, u32 old_H32, u32 new_L32, u32 new_H32)
ret = new_L32 - old_L32;
} else if (new_H32 == (old_H32 + 1)) {
if (new_L32 > old_L32)
- pr_debug("msdc old_L<0x%x> new_L<0x%x>\n", old_L32, new_L32);
+ pr_debug("msdc old_L<0x%x> new_L<0x%x>\n",
+ old_L32, new_L32);
ret = (0xffffffff - old_L32);
ret += new_L32;
} else {
@@ -113,27 +100,33 @@ void msdc_sdio_profile(struct sdio_profile *result)
/* CMD52 Dump */
cmd = &result->cmd52_rx;
- pr_debug("sdio === CMD52 Rx <%d>times tick<%d> Max<%d> Min<%d> Aver<%d>\n", cmd->count, cmd->tot_tc,
- cmd->max_tc, cmd->min_tc, cmd->tot_tc / cmd->count);
+ pr_debug("sdio === CMD52 Rx <%d>times tick<%d> Max<%d> Min<%d> Aver<%d>\n",
+ cmd->count, cmd->tot_tc, cmd->max_tc, cmd->min_tc,
+ cmd->tot_tc / cmd->count);
cmd = &result->cmd52_tx;
- pr_debug("sdio === CMD52 Tx <%d>times tick<%d> Max<%d> Min<%d> Aver<%d>\n", cmd->count, cmd->tot_tc,
- cmd->max_tc, cmd->min_tc, cmd->tot_tc / cmd->count);
+ pr_debug("sdio === CMD52 Tx <%d>times tick<%d> Max<%d> Min<%d> Aver<%d>\n",
+ cmd->count, cmd->tot_tc, cmd->max_tc, cmd->min_tc,
+ cmd->tot_tc / cmd->count);
/* CMD53 Rx bytes + block mode */
for (i = 0; i < 512; i++) {
cmd = &result->cmd53_rx_byte[i];
if (cmd->count) {
- pr_debug("sdio<%6d><%3dB>_Rx_<%9d><%9d><%6d><%6d>_<%9dB><%2dM>\n", cmd->count, i, cmd->tot_tc,
- cmd->max_tc, cmd->min_tc, cmd->tot_tc / cmd->count,
- cmd->tot_bytes, (cmd->tot_bytes / 10) * 13 / (cmd->tot_tc / 10));
+ pr_debug("sdio<%6d><%3dB>_Rx_<%9d><%9d><%6d><%6d>_<%9dB><%2dM>\n",
+ cmd->count, i, cmd->tot_tc, cmd->max_tc,
+ cmd->min_tc, cmd->tot_tc / cmd->count,
+ cmd->tot_bytes,
+ (cmd->tot_bytes / 10) * 13 / (cmd->tot_tc / 10));
}
}
for (i = 0; i < 100; i++) {
cmd = &result->cmd53_rx_blk[i];
if (cmd->count) {
- pr_debug("sdio<%6d><%3d>B_Rx_<%9d><%9d><%6d><%6d>_<%9dB><%2dM>\n", cmd->count, i, cmd->tot_tc,
- cmd->max_tc, cmd->min_tc, cmd->tot_tc / cmd->count,
- cmd->tot_bytes, (cmd->tot_bytes / 10) * 13 / (cmd->tot_tc / 10));
+ pr_debug("sdio<%6d><%3d>B_Rx_<%9d><%9d><%6d><%6d>_<%9dB><%2dM>\n",
+ cmd->count, i, cmd->tot_tc, cmd->max_tc,
+ cmd->min_tc, cmd->tot_tc / cmd->count,
+ cmd->tot_bytes,
+ (cmd->tot_bytes / 10) * 13 / (cmd->tot_tc / 10));
}
}
@@ -141,17 +134,21 @@ void msdc_sdio_profile(struct sdio_profile *result)
for (i = 0; i < 512; i++) {
cmd = &result->cmd53_tx_byte[i];
if (cmd->count) {
- pr_debug("sdio<%6d><%3dB>_Tx_<%9d><%9d><%6d><%6d>_<%9dB><%2dM>\n", cmd->count, i, cmd->tot_tc,
- cmd->max_tc, cmd->min_tc, cmd->tot_tc / cmd->count,
- cmd->tot_bytes, (cmd->tot_bytes / 10) * 13 / (cmd->tot_tc / 10));
+ pr_debug("sdio<%6d><%3dB>_Tx_<%9d><%9d><%6d><%6d>_<%9dB><%2dM>\n",
+ cmd->count, i, cmd->tot_tc, cmd->max_tc,
+ cmd->min_tc, cmd->tot_tc / cmd->count,
+ cmd->tot_bytes,
+ (cmd->tot_bytes / 10) * 13 / (cmd->tot_tc / 10));
}
}
for (i = 0; i < 100; i++) {
cmd = &result->cmd53_tx_blk[i];
if (cmd->count) {
- pr_debug("sdio<%6d><%3d>B_Tx_<%9d><%9d><%6d><%6d>_<%9dB><%2dM>\n", cmd->count, i, cmd->tot_tc,
- cmd->max_tc, cmd->min_tc, cmd->tot_tc / cmd->count,
- cmd->tot_bytes, (cmd->tot_bytes / 10) * 13 / (cmd->tot_tc / 10));
+ pr_debug("sdio<%6d><%3d>B_Tx_<%9d><%9d><%6d><%6d>_<%9dB><%2dM>\n",
+ cmd->count, i, cmd->tot_tc, cmd->max_tc,
+ cmd->min_tc, cmd->tot_tc / cmd->count,
+ cmd->tot_bytes,
+ (cmd->tot_bytes / 10) * 13 / (cmd->tot_tc / 10));
}
}
@@ -222,7 +219,8 @@ static int msdc_debug_proc_read(struct seq_file *s, void *p)
seq_puts(s, "Index<3> + SDIO_PROFILE + TIME\n");
seq_puts(s, "-> echo 3 1 0x1E >msdc_bebug -> enable sdio_profile, 30s\n");
- seq_printf(s, "-> SDIO_PROFILE<%d> TIME<%ds>\n", sdio_pro_enable, sdio_pro_time);
+ seq_printf(s, "-> SDIO_PROFILE<%d> TIME<%ds>\n",
+ sdio_pro_enable, sdio_pro_time);
seq_puts(s, "=========================================\n\n");
return 0;
@@ -249,7 +247,9 @@ static ssize_t msdc_debug_proc_write(struct file *file,
cmd_buf[count] = '\0';
pr_debug("msdc Write %s\n", cmd_buf);
- sscanf(cmd_buf, "%x %x %x", &cmd, &p1, &p2);
+ ret = sscanf(cmd_buf, "%x %x %x", &cmd, &p1, &p2);
+ if (ret != 3)
+ return -EINVAL;
if (cmd == SD_TOOL_ZONE) {
id = p1;
@@ -266,10 +266,8 @@ static ssize_t msdc_debug_proc_write(struct file *file,
}
} else if (cmd == SD_TOOL_SDIO_PROFILE) {
if (p1 == 1) { /* enable profile */
- if (gpt_enable == 0) {
- // msdc_init_gpt(); /* --- by chhung */
+ if (gpt_enable == 0)
gpt_enable = 1;
- }
sdio_pro_enable = 1;
if (p2 == 0)
p2 = 1;
diff --git a/drivers/staging/mt7621-mmc/dbg.h b/drivers/staging/mt7621-mmc/dbg.h
index 2f2c56b73987..2d447b2d92ae 100644
--- a/drivers/staging/mt7621-mmc/dbg.h
+++ b/drivers/staging/mt7621-mmc/dbg.h
@@ -5,7 +5,8 @@
* is confidential and proprietary to MediaTek Inc. and/or its licensors.
* Without the prior written permission of MediaTek inc. and/or its licensors,
* any reproduction, modification, use or disclosure of MediaTek Software,
- * and information contained herein, in whole or in part, shall be strictly prohibited.
+ * and information contained herein, in whole or in part, shall be strictly
+ * prohibited.
*
* MediaTek Inc. (C) 2010. All rights reserved.
*
@@ -18,19 +19,20 @@
* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
- * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
- * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
- * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
- * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
- * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
- * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
- * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
- * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
- * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY
+ * ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY
+ * THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK
+ * SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO
+ * RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR STANDARD OR OPEN
+ * FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED
+ * HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK
+ * SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE
+ * PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
*
- * The following software/firmware and/or related documentation ("MediaTek Software")
- * have been modified by MediaTek Inc. All revisions are subject to any receiver's
- * applicable license agreements with MediaTek Inc.
+ * The following software/firmware and/or related documentation
+ * ("MediaTek Software") have been modified by MediaTek Inc. All revisions are
+ * subject to any receiver's applicable license agreements with MediaTek Inc.
*/
#ifndef __MT_MSDC_DEUBG__
#define __MT_MSDC_DEUBG__
@@ -74,75 +76,25 @@ enum msdc_dbg {
};
/* Debug message event */
-#define DBG_EVT_NONE (0) /* No event */
-#define DBG_EVT_DMA (1 << 0) /* DMA related event */
-#define DBG_EVT_CMD (1 << 1) /* MSDC CMD related event */
-#define DBG_EVT_RSP (1 << 2) /* MSDC CMD RSP related event */
-#define DBG_EVT_INT (1 << 3) /* MSDC INT event */
-#define DBG_EVT_CFG (1 << 4) /* MSDC CFG event */
-#define DBG_EVT_FUC (1 << 5) /* Function event */
-#define DBG_EVT_OPS (1 << 6) /* Read/Write operation event */
-#define DBG_EVT_FIO (1 << 7) /* FIFO operation event */
-#define DBG_EVT_WRN (1 << 8) /* Warning event */
-#define DBG_EVT_PWR (1 << 9) /* Power event */
+#define DBG_EVT_NONE (0) /* No event */
+#define DBG_EVT_DMA BIT(0) /* DMA related event */
+#define DBG_EVT_CMD BIT(1) /* MSDC CMD related event */
+#define DBG_EVT_RSP BIT(2) /* MSDC CMD RSP related event */
+#define DBG_EVT_INT BIT(3) /* MSDC INT event */
+#define DBG_EVT_CFG BIT(4) /* MSDC CFG event */
+#define DBG_EVT_FUC BIT(5) /* Function event */
+#define DBG_EVT_OPS BIT(6) /* Read/Write operation event */
+#define DBG_EVT_FIO BIT(7) /* FIFO operation event */
+#define DBG_EVT_WRN BIT(8) /* Warning event */
+#define DBG_EVT_PWR BIT(9) /* Power event */
#define DBG_EVT_ALL (0xffffffff)
#define DBG_EVT_MASK (DBG_EVT_ALL)
extern unsigned int sd_debug_zone[4];
#define TAG "msdc"
-#if 0 /* +++ chhung */
-#define BUG_ON(x) \
-do { \
- if (x) { \
- printk("[BUG] %s LINE:%d FILE:%s\n", #x, __LINE__, __FILE__); \
- while (1) \
- ; \
- } \
-} while (0)
-#endif /* end of +++ */
-
-#define N_MSG(evt, fmt, args...)
-/*
-do { \
- if ((DBG_EVT_##evt) & sd_debug_zone[host->id]) { \
- printk(KERN_ERR TAG"%d -> "fmt" <- %s() : L<%d> PID<%s><0x%x>\n", \
- host->id, ##args , __FUNCTION__, __LINE__, current->comm, current->pid); \
- } \
-} while(0)
-*/
-
-#define ERR_MSG(fmt, args...) \
-do { \
- printk(KERN_ERR TAG"%d -> "fmt" <- %s() : L<%d> PID<%s><0x%x>\n", \
- host->id, ##args, __FUNCTION__, __LINE__, current->comm, current->pid); \
-} while (0);
-
-#if 1
-//defined CONFIG_MTK_MMC_CD_POLL
-#define INIT_MSG(fmt, args...)
-#define IRQ_MSG(fmt, args...)
-#else
-#define INIT_MSG(fmt, args...) \
-do { \
- printk(KERN_ERR TAG"%d -> "fmt" <- %s() : L<%d> PID<%s><0x%x>\n", \
- host->id, ##args, __FUNCTION__, __LINE__, current->comm, current->pid); \
-} while (0);
-
-/* PID in ISR in not corrent */
-#define IRQ_MSG(fmt, args...) \
-do { \
- printk(KERN_ERR TAG"%d -> "fmt" <- %s() : L<%d>\n", \
- host->id, ##args, __FUNCTION__, __LINE__); \
-} while (0);
-#endif
-
void msdc_debug_proc_init(void);
-#if 0 /* --- chhung */
-void msdc_init_gpt(void);
-extern void GPT_GetCounter64(UINT32 *cntL32, UINT32 *cntH32);
-#endif /* end of --- */
u32 msdc_time_calc(u32 old_L32, u32 old_H32, u32 new_L32, u32 new_H32);
void msdc_performance(u32 opcode, u32 sizes, u32 bRx, u32 ticks);
diff --git a/drivers/staging/mt7621-mmc/sd.c b/drivers/staging/mt7621-mmc/sd.c
index 04d23cc7cd4a..0379f9c96f2a 100644
--- a/drivers/staging/mt7621-mmc/sd.c
+++ b/drivers/staging/mt7621-mmc/sd.c
@@ -72,11 +72,6 @@
#define GPIO_PULL_DOWN (0)
#define GPIO_PULL_UP (1)
-#if 0 /* --- by chhung */
-#define MSDC_CLKSRC_REG (0xf100000C)
-#define PDN_REG (0xF1000010)
-#endif /* end of --- */
-
#define DEFAULT_DEBOUNCE (8) /* 8 cycles */
#define DEFAULT_DTOC (40) /* data timeout counter. 65536x40 sclk. */
@@ -100,26 +95,6 @@ static int cd_active_low = 1;
//#define PERI_MSDC2_PDN (17)
//#define PERI_MSDC3_PDN (18)
-#if 0 /* --- by chhung */
-/* gate means clock power down */
-static int g_clk_gate = 0;
-#define msdc_gate_clock(id) \
- do { \
- g_clk_gate &= ~(1 << ((id) + PERI_MSDC0_PDN)); \
- } while (0)
-/* not like power down register. 1 means clock on. */
-#define msdc_ungate_clock(id) \
- do { \
- g_clk_gate |= 1 << ((id) + PERI_MSDC0_PDN); \
- } while (0)
-
-// do we need sync object or not
-void msdc_clk_status(int *status)
-{
- *status = g_clk_gate;
-}
-#endif /* end of --- */
-
/* +++ by chhung */
struct msdc_hw msdc0_hw = {
.clk_src = 0,
@@ -169,11 +144,6 @@ static void msdc_clr_fifo(struct msdc_host *host)
sdr_clr_bits(host->base + MSDC_INTEN, val); \
} while (0)
-#define msdc_irq_restore(val) \
- do { \
- sdr_set_bits(host->base + MSDC_INTEN, val); \
- } while (0)
-
/* clock source for host: global */
#if defined(CONFIG_SOC_MT7620)
static u32 hclks[] = {48000000}; /* +/- by chhung */
@@ -181,34 +151,6 @@ static u32 hclks[] = {48000000}; /* +/- by chhung */
static u32 hclks[] = {50000000}; /* +/- by chhung */
#endif
-//============================================
-// the power for msdc host controller: global
-// always keep the VMC on.
-//============================================
-#define msdc_vcore_on(host) \
- do { \
- INIT_MSG("[+]VMC ref. count<%d>", ++host->pwr_ref); \
- (void)hwPowerOn(MT65XX_POWER_LDO_VMC, VOL_3300, "SD"); \
- } while (0)
-#define msdc_vcore_off(host) \
- do { \
- INIT_MSG("[-]VMC ref. count<%d>", --host->pwr_ref); \
- (void)hwPowerDown(MT65XX_POWER_LDO_VMC, "SD"); \
- } while (0)
-
-//====================================
-// the vdd output for card: global
-// always keep the VMCH on.
-//====================================
-#define msdc_vdd_on(host) \
- do { \
- (void)hwPowerOn(MT65XX_POWER_LDO_VMCH, VOL_3300, "SD"); \
- } while (0)
-#define msdc_vdd_off(host) \
- do { \
- (void)hwPowerDown(MT65XX_POWER_LDO_VMCH, "SD"); \
- } while (0)
-
#define sdc_is_busy() (readl(host->base + SDC_STS) & SDC_STS_SDCBUSY)
#define sdc_is_cmd_busy() (readl(host->base + SDC_STS) & SDC_STS_CMDBUSY)
@@ -232,144 +174,6 @@ static unsigned int msdc_do_command(struct msdc_host *host,
static int msdc_tune_cmdrsp(struct msdc_host *host, struct mmc_command *cmd);
-#ifdef MT6575_SD_DEBUG
-static void msdc_dump_card_status(struct msdc_host *host, u32 status)
-{
-/* N_MSG is currently a no-op */
-#if 0
- static char *state[] = {
- "Idle", /* 0 */
- "Ready", /* 1 */
- "Ident", /* 2 */
- "Stby", /* 3 */
- "Tran", /* 4 */
- "Data", /* 5 */
- "Rcv", /* 6 */
- "Prg", /* 7 */
- "Dis", /* 8 */
- "Reserved", /* 9 */
- "Reserved", /* 10 */
- "Reserved", /* 11 */
- "Reserved", /* 12 */
- "Reserved", /* 13 */
- "Reserved", /* 14 */
- "I/O mode", /* 15 */
- };
-#endif
- if (status & R1_OUT_OF_RANGE)
- N_MSG(RSP, "[CARD_STATUS] Out of Range");
- if (status & R1_ADDRESS_ERROR)
- N_MSG(RSP, "[CARD_STATUS] Address Error");
- if (status & R1_BLOCK_LEN_ERROR)
- N_MSG(RSP, "[CARD_STATUS] Block Len Error");
- if (status & R1_ERASE_SEQ_ERROR)
- N_MSG(RSP, "[CARD_STATUS] Erase Seq Error");
- if (status & R1_ERASE_PARAM)
- N_MSG(RSP, "[CARD_STATUS] Erase Param");
- if (status & R1_WP_VIOLATION)
- N_MSG(RSP, "[CARD_STATUS] WP Violation");
- if (status & R1_CARD_IS_LOCKED)
- N_MSG(RSP, "[CARD_STATUS] Card is Locked");
- if (status & R1_LOCK_UNLOCK_FAILED)
- N_MSG(RSP, "[CARD_STATUS] Lock/Unlock Failed");
- if (status & R1_COM_CRC_ERROR)
- N_MSG(RSP, "[CARD_STATUS] Command CRC Error");
- if (status & R1_ILLEGAL_COMMAND)
- N_MSG(RSP, "[CARD_STATUS] Illegal Command");
- if (status & R1_CARD_ECC_FAILED)
- N_MSG(RSP, "[CARD_STATUS] Card ECC Failed");
- if (status & R1_CC_ERROR)
- N_MSG(RSP, "[CARD_STATUS] CC Error");
- if (status & R1_ERROR)
- N_MSG(RSP, "[CARD_STATUS] Error");
- if (status & R1_UNDERRUN)
- N_MSG(RSP, "[CARD_STATUS] Underrun");
- if (status & R1_OVERRUN)
- N_MSG(RSP, "[CARD_STATUS] Overrun");
- if (status & R1_CID_CSD_OVERWRITE)
- N_MSG(RSP, "[CARD_STATUS] CID/CSD Overwrite");
- if (status & R1_WP_ERASE_SKIP)
- N_MSG(RSP, "[CARD_STATUS] WP Eraser Skip");
- if (status & R1_CARD_ECC_DISABLED)
- N_MSG(RSP, "[CARD_STATUS] Card ECC Disabled");
- if (status & R1_ERASE_RESET)
- N_MSG(RSP, "[CARD_STATUS] Erase Reset");
- if (status & R1_READY_FOR_DATA)
- N_MSG(RSP, "[CARD_STATUS] Ready for Data");
- if (status & R1_SWITCH_ERROR)
- N_MSG(RSP, "[CARD_STATUS] Switch error");
- if (status & R1_APP_CMD)
- N_MSG(RSP, "[CARD_STATUS] App Command");
-
- N_MSG(RSP, "[CARD_STATUS] '%s' State", state[R1_CURRENT_STATE(status)]);
-}
-
-static void msdc_dump_ocr_reg(struct msdc_host *host, u32 resp)
-{
- if (resp & (1 << 7))
- N_MSG(RSP, "[OCR] Low Voltage Range");
- if (resp & (1 << 15))
- N_MSG(RSP, "[OCR] 2.7-2.8 volt");
- if (resp & (1 << 16))
- N_MSG(RSP, "[OCR] 2.8-2.9 volt");
- if (resp & (1 << 17))
- N_MSG(RSP, "[OCR] 2.9-3.0 volt");
- if (resp & (1 << 18))
- N_MSG(RSP, "[OCR] 3.0-3.1 volt");
- if (resp & (1 << 19))
- N_MSG(RSP, "[OCR] 3.1-3.2 volt");
- if (resp & (1 << 20))
- N_MSG(RSP, "[OCR] 3.2-3.3 volt");
- if (resp & (1 << 21))
- N_MSG(RSP, "[OCR] 3.3-3.4 volt");
- if (resp & (1 << 22))
- N_MSG(RSP, "[OCR] 3.4-3.5 volt");
- if (resp & (1 << 23))
- N_MSG(RSP, "[OCR] 3.5-3.6 volt");
- if (resp & (1 << 24))
- N_MSG(RSP, "[OCR] Switching to 1.8V Accepted (S18A)");
- if (resp & (1 << 30))
- N_MSG(RSP, "[OCR] Card Capacity Status (CCS)");
- if (resp & (1 << 31))
- N_MSG(RSP, "[OCR] Card Power Up Status (Idle)");
- else
- N_MSG(RSP, "[OCR] Card Power Up Status (Busy)");
-}
-
-static void msdc_dump_rca_resp(struct msdc_host *host, u32 resp)
-{
- u32 status = (((resp >> 15) & 0x1) << 23) |
- (((resp >> 14) & 0x1) << 22) |
- (((resp >> 13) & 0x1) << 19) |
- (resp & 0x1fff);
-
- N_MSG(RSP, "[RCA] 0x%.4x", resp >> 16);
- msdc_dump_card_status(host, status);
-}
-
-static void msdc_dump_io_resp(struct msdc_host *host, u32 resp)
-{
- u32 flags = (resp >> 8) & 0xFF;
-#if 0
- char *state[] = {"DIS", "CMD", "TRN", "RFU"};
-#endif
- if (flags & (1 << 7))
- N_MSG(RSP, "[IO] COM_CRC_ERR");
- if (flags & (1 << 6))
- N_MSG(RSP, "[IO] Illegal command");
- if (flags & (1 << 3))
- N_MSG(RSP, "[IO] Error");
- if (flags & (1 << 2))
- N_MSG(RSP, "[IO] RFU");
- if (flags & (1 << 1))
- N_MSG(RSP, "[IO] Function number error");
- if (flags & (1 << 0))
- N_MSG(RSP, "[IO] Out of range");
-
- N_MSG(RSP, "[IO] State: %s, Data:0x%x", state[(resp >> 12) & 0x3], resp & 0xFF);
-}
-#endif
-
static void msdc_set_timeout(struct msdc_host *host, u32 ns, u32 clks)
{
u32 timeout, clk_ns;
@@ -384,9 +188,6 @@ static void msdc_set_timeout(struct msdc_host *host, u32 ns, u32 clks)
timeout = timeout > 255 ? 255 : timeout;
sdr_set_field(host->base + SDC_CFG, SDC_CFG_DTOC, timeout);
-
- N_MSG(OPS, "Set read data timeout: %dns %dclks -> %d x 65536 cycles",
- ns, clks, timeout + 1);
}
static void msdc_tasklet_card(struct work_struct *work)
@@ -395,7 +196,6 @@ static void msdc_tasklet_card(struct work_struct *work)
struct msdc_host, card_delaywork.work);
u32 inserted;
u32 status = 0;
- //u32 change = 0;
spin_lock(&host->lock);
@@ -405,16 +205,7 @@ static void msdc_tasklet_card(struct work_struct *work)
else
inserted = (status & MSDC_PS_CDSTS) ? 1 : 0;
-#if 0
- change = host->card_inserted ^ inserted;
- host->card_inserted = inserted;
-
- if (change && !host->suspend) {
- if (inserted)
- host->mmc->f_max = HOST_MAX_MCLK; // work around
- mmc_detect_change(host->mmc, msecs_to_jiffies(20));
- }
-#else /* Make sure: handle the last interrupt */
+ /* Make sure: handle the last interrupt */
host->card_inserted = inserted;
if (!host->suspend) {
@@ -422,24 +213,14 @@ static void msdc_tasklet_card(struct work_struct *work)
mmc_detect_change(host->mmc, msecs_to_jiffies(20));
}
- IRQ_MSG("card found<%s>", inserted ? "inserted" : "removed");
-#endif
-
spin_unlock(&host->lock);
}
-#if 0 /* --- by chhung */
-/* For E2 only */
-static u8 clk_src_bit[4] = {
- 0, 3, 5, 7
-};
-
static void msdc_select_clksrc(struct msdc_host *host, unsigned char clksrc)
{
u32 val;
BUG_ON(clksrc > 3);
- INIT_MSG("set clock source to <%d>", clksrc);
val = readl(host->base + MSDC_CLKSRC_REG);
if (readl(host->base + MSDC_ECO_VER) >= 4) {
@@ -466,7 +247,6 @@ static void msdc_set_mclk(struct msdc_host *host, int ddr, unsigned int hz)
//u8 clksrc = hw->clk_src;
if (!hz) { // set mmc system clock to 0 ?
- //ERR_MSG("set mclk to 0!!!");
msdc_reset_hw(host);
return;
}
@@ -509,11 +289,7 @@ static void msdc_set_mclk(struct msdc_host *host, int ddr, unsigned int hz)
host->mclk = hz;
msdc_set_timeout(host, host->timeout_ns, host->timeout_clks); // need?
- INIT_MSG("================");
- INIT_MSG("!!! Set<%dKHz> Source<%dKHz> -> sclk<%dKHz>", hz / 1000, hclk / 1000, sclk / 1000);
- INIT_MSG("================");
-
- msdc_irq_restore(flags);
+ sdr_set_bits(host->base + MSDC_INTEN, flags);
}
/* Fix me. when need to abort */
@@ -521,7 +297,7 @@ static void msdc_abort_data(struct msdc_host *host)
{
struct mmc_command *stop = host->mrq->stop;
- ERR_MSG("Need to Abort.");
+ dev_err(mmc_dev(host->mmc), "%d -> Need to Abort.\n", host->id);
msdc_reset_hw(host);
msdc_clr_fifo(host);
@@ -530,7 +306,8 @@ static void msdc_abort_data(struct msdc_host *host)
// need to check FIFO count 0 ?
if (stop) { /* try to stop, but may not success */
- ERR_MSG("stop when abort CMD<%d>", stop->opcode);
+ dev_err(mmc_dev(host->mmc), "%d -> stop when abort CMD<%d>\n",
+ host->id, stop->opcode);
(void)msdc_do_command(host, stop, 0, CMD_TIMEOUT);
}
@@ -539,126 +316,6 @@ static void msdc_abort_data(struct msdc_host *host)
//}
}
-#if 0 /* --- by chhung */
-static void msdc_pin_config(struct msdc_host *host, int mode)
-{
- struct msdc_hw *hw = host->hw;
- int pull = (mode == MSDC_PIN_PULL_UP) ? GPIO_PULL_UP : GPIO_PULL_DOWN;
-
- /* Config WP pin */
- if (hw->flags & MSDC_WP_PIN_EN) {
- if (hw->config_gpio_pin) /* NULL */
- hw->config_gpio_pin(MSDC_WP_PIN, pull);
- }
-
- switch (mode) {
- case MSDC_PIN_PULL_UP:
- //sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKPU, 1); /* Check & FIXME */
- //sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKPD, 0); /* Check & FIXME */
- sdr_set_field(host->base + MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDPU, 1);
- sdr_set_field(host->base + MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDPD, 0);
- sdr_set_field(host->base + MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATPU, 1);
- sdr_set_field(host->base + MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATPD, 0);
- break;
- case MSDC_PIN_PULL_DOWN:
- //sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKPU, 0); /* Check & FIXME */
- //sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKPD, 1); /* Check & FIXME */
- sdr_set_field(host->base + MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDPU, 0);
- sdr_set_field(host->base + MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDPD, 1);
- sdr_set_field(host->base + MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATPU, 0);
- sdr_set_field(host->base + MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATPD, 1);
- break;
- case MSDC_PIN_PULL_NONE:
- default:
- //sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKPU, 0); /* Check & FIXME */
- //sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKPD, 0); /* Check & FIXME */
- sdr_set_field(host->base + MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDPU, 0);
- sdr_set_field(host->base + MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDPD, 0);
- sdr_set_field(host->base + MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATPU, 0);
- sdr_set_field(host->base + MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATPD, 0);
- break;
- }
-
- N_MSG(CFG, "Pins mode(%d), down(%d), up(%d)",
- mode, MSDC_PIN_PULL_DOWN, MSDC_PIN_PULL_UP);
-}
-
-void msdc_pin_reset(struct msdc_host *host, int mode)
-{
- struct msdc_hw *hw = (struct msdc_hw *)host->hw;
- int pull = (mode == MSDC_PIN_PULL_UP) ? GPIO_PULL_UP : GPIO_PULL_DOWN;
-
- /* Config reset pin */
- if (hw->flags & MSDC_RST_PIN_EN) {
- if (hw->config_gpio_pin) /* NULL */
- hw->config_gpio_pin(MSDC_RST_PIN, pull);
-
- if (mode == MSDC_PIN_PULL_UP)
- sdr_clr_bits(host->base + EMMC_IOCON, EMMC_IOCON_BOOTRST);
- else
- sdr_set_bits(host->base + EMMC_IOCON, EMMC_IOCON_BOOTRST);
- }
-}
-
-static void msdc_core_power(struct msdc_host *host, int on)
-{
- N_MSG(CFG, "Turn %s %s power (copower: %d -> %d)",
- on ? "on" : "off", "core", host->core_power, on);
-
- if (on && host->core_power == 0) {
- msdc_vcore_on(host);
- host->core_power = 1;
- msleep(1);
- } else if (!on && host->core_power == 1) {
- msdc_vcore_off(host);
- host->core_power = 0;
- msleep(1);
- }
-}
-
-static void msdc_host_power(struct msdc_host *host, int on)
-{
- N_MSG(CFG, "Turn %s %s power ", on ? "on" : "off", "host");
-
- if (on) {
- //msdc_core_power(host, 1); // need do card detection.
- msdc_pin_reset(host, MSDC_PIN_PULL_UP);
- } else {
- msdc_pin_reset(host, MSDC_PIN_PULL_DOWN);
- //msdc_core_power(host, 0);
- }
-}
-
-static void msdc_card_power(struct msdc_host *host, int on)
-{
- N_MSG(CFG, "Turn %s %s power ", on ? "on" : "off", "card");
-
- if (on) {
- msdc_pin_config(host, MSDC_PIN_PULL_UP);
- //msdc_vdd_on(host); // need todo card detection.
- msleep(1);
- } else {
- //msdc_vdd_off(host);
- msdc_pin_config(host, MSDC_PIN_PULL_DOWN);
- msleep(1);
- }
-}
-
-static void msdc_set_power_mode(struct msdc_host *host, u8 mode)
-{
- N_MSG(CFG, "Set power mode(%d)", mode);
-
- if (host->power_mode == MMC_POWER_OFF && mode != MMC_POWER_OFF) {
- msdc_host_power(host, 1);
- msdc_card_power(host, 1);
- } else if (host->power_mode != MMC_POWER_OFF && mode == MMC_POWER_OFF) {
- msdc_card_power(host, 0);
- msdc_host_power(host, 0);
- }
- host->power_mode = mode;
-}
-#endif /* end of --- */
-
#ifdef CONFIG_PM
/*
register as callback function of WIFI(combo_sdio_register_pm) .
@@ -669,12 +326,6 @@ static void msdc_pm(pm_message_t state, void *data)
struct msdc_host *host = (struct msdc_host *)data;
int evt = state.event;
- if (evt == PM_EVENT_USER_RESUME || evt == PM_EVENT_USER_SUSPEND) {
- INIT_MSG("USR_%s: suspend<%d> power<%d>",
- evt == PM_EVENT_USER_RESUME ? "EVENT_USER_RESUME" : "EVENT_USER_SUSPEND",
- host->suspend, host->power_mode);
- }
-
if (evt == PM_EVENT_SUSPEND || evt == PM_EVENT_USER_SUSPEND) {
if (host->suspend) /* already suspend */ /* default 0*/
return;
@@ -687,14 +338,14 @@ static void msdc_pm(pm_message_t state, void *data)
host->pm_state = state; /* default PMSG_RESUME */
} else if (evt == PM_EVENT_RESUME || evt == PM_EVENT_USER_RESUME) {
- if (!host->suspend) {
- //ERR_MSG("warning: already resume");
+ if (!host->suspend)
return;
- }
/* No PM resume when USR suspend */
if (evt == PM_EVENT_RESUME && host->pm_state.event == PM_EVENT_USER_SUSPEND) {
- ERR_MSG("PM Resume when in USR Suspend"); /* won't happen. */
+ dev_err(mmc_dev(host->mmc),
+ "%d -> PM Resume when in USR Suspend\n",
+ host->id); /* won't happen. */
return;
}
@@ -802,8 +453,6 @@ static unsigned int msdc_command_start(struct msdc_host *host,
rawcmd &= ~(0x0FFF << 16);
}
- N_MSG(CMD, "CMD<%d><0x%.8x> Arg<0x%.8x>", opcode, rawcmd, cmd->arg);
-
tmo = jiffies + timeout;
if (opcode == MMC_SEND_STATUS) {
@@ -812,7 +461,9 @@ static unsigned int msdc_command_start(struct msdc_host *host,
break;
if (time_after(jiffies, tmo)) {
- ERR_MSG("XXX cmd_busy timeout: before CMD<%d>", opcode);
+ dev_err(mmc_dev(host->mmc),
+ "%d -> XXX cmd_busy timeout: before CMD<%d>\n",
+ host->id, opcode);
cmd->error = -ETIMEDOUT;
msdc_reset_hw(host);
goto end;
@@ -823,7 +474,9 @@ static unsigned int msdc_command_start(struct msdc_host *host,
if (!sdc_is_busy())
break;
if (time_after(jiffies, tmo)) {
- ERR_MSG("XXX sdc_busy timeout: before CMD<%d>", opcode);
+ dev_err(mmc_dev(host->mmc),
+ "%d -> XXX sdc_busy timeout: before CMD<%d>\n",
+ host->id, opcode);
cmd->error = -ETIMEDOUT;
msdc_reset_hw(host);
goto end;
@@ -862,7 +515,9 @@ static unsigned int msdc_command_resp(struct msdc_host *host,
spin_unlock(&host->lock);
if (!wait_for_completion_timeout(&host->cmd_done, 10 * timeout)) {
- ERR_MSG("XXX CMD<%d> wait_for_completion timeout ARG<0x%.8x>", opcode, cmd->arg);
+ dev_err(mmc_dev(host->mmc),
+ "%d -> XXX CMD<%d> wait_for_completion timeout ARG<0x%.8x>\n",
+ host->id, opcode, cmd->arg);
cmd->error = -ETIMEDOUT;
msdc_reset_hw(host);
}
@@ -872,40 +527,6 @@ static unsigned int msdc_command_resp(struct msdc_host *host,
host->cmd = NULL;
//end:
-#ifdef MT6575_SD_DEBUG
- switch (resp) {
- case RESP_NONE:
- N_MSG(RSP, "CMD_RSP(%d): %d RSP(%d)", opcode, cmd->error, resp);
- break;
- case RESP_R2:
- N_MSG(RSP, "CMD_RSP(%d): %d RSP(%d)= %.8x %.8x %.8x %.8x",
- opcode, cmd->error, resp, cmd->resp[0], cmd->resp[1],
- cmd->resp[2], cmd->resp[3]);
- break;
- default: /* Response types 1, 3, 4, 5, 6, 7(1b) */
- N_MSG(RSP, "CMD_RSP(%d): %d RSP(%d)= 0x%.8x",
- opcode, cmd->error, resp, cmd->resp[0]);
- if (cmd->error == 0) {
- switch (resp) {
- case RESP_R1:
- case RESP_R1B:
- msdc_dump_card_status(host, cmd->resp[0]);
- break;
- case RESP_R3:
- msdc_dump_ocr_reg(host, cmd->resp[0]);
- break;
- case RESP_R5:
- msdc_dump_io_resp(host, cmd->resp[0]);
- break;
- case RESP_R6:
- msdc_dump_rca_resp(host, cmd->resp[0]);
- break;
- }
- }
- break;
- }
-#endif
-
/* do we need to save card's RCA when SD_SEND_RELATIVE_ADDR */
if (!tune)
@@ -947,20 +568,9 @@ static unsigned int msdc_do_command(struct msdc_host *host,
end:
- N_MSG(CMD, " return<%d> resp<0x%.8x>", cmd->error, cmd->resp[0]);
return cmd->error;
}
-#if 0 /* --- by chhung */
-// DMA resume / start / stop
-static void msdc_dma_resume(struct msdc_host *host)
-{
- sdr_set_field(host->base + MSDC_DMA_CTRL, MSDC_DMA_CTRL_RESUME, 1);
-
- N_MSG(DMA, "DMA resume");
-}
-#endif /* end of --- */
-
static void msdc_dma_start(struct msdc_host *host)
{
u32 wints = MSDC_INTEN_XFER_COMPL | MSDC_INTEN_DATTMO | MSDC_INTEN_DATCRCERR;
@@ -968,8 +578,6 @@ static void msdc_dma_start(struct msdc_host *host)
sdr_set_bits(host->base + MSDC_INTEN, wints);
//dsb(); /* --- by chhung */
sdr_set_field(host->base + MSDC_DMA_CTRL, MSDC_DMA_CTRL_START, 1);
-
- N_MSG(DMA, "DMA start");
}
static void msdc_dma_stop(struct msdc_host *host)
@@ -977,7 +585,6 @@ static void msdc_dma_stop(struct msdc_host *host)
//u32 retries=500;
u32 wints = MSDC_INTEN_XFER_COMPL | MSDC_INTEN_DATTMO | MSDC_INTEN_DATCRCERR;
- N_MSG(DMA, "DMA status: 0x%.8x", readl(host->base + MSDC_DMA_CFG));
//while (readl(host->base + MSDC_DMA_CFG) & MSDC_DMA_CFG_STS);
sdr_set_field(host->base + MSDC_DMA_CTRL, MSDC_DMA_CTRL_STOP, 1);
@@ -986,8 +593,6 @@ static void msdc_dma_stop(struct msdc_host *host)
//dsb(); /* --- by chhung */
sdr_clr_bits(host->base + MSDC_INTEN, wints); /* Not just xfer_comp */
-
- N_MSG(DMA, "DMA stop");
}
/* calc checksum */
@@ -1010,8 +615,6 @@ static void msdc_dma_setup(struct msdc_host *host, struct msdc_dma *dma,
BUG_ON(sglen > MAX_BD_NUM); /* not support currently */
- N_MSG(DMA, "DMA sglen<%d> xfersz<%d>", sglen, host->xfer_size);
-
gpd = dma->gpd;
bd = dma->bd;
@@ -1044,10 +647,6 @@ static void msdc_dma_setup(struct msdc_host *host, struct msdc_dma *dma,
sdr_set_field(host->base + MSDC_DMA_CTRL, MSDC_DMA_CTRL_MODE, 1);
writel(PHYSADDR((u32)dma->gpd_addr), host->base + MSDC_DMA_SA);
-
- N_MSG(DMA, "DMA_CTRL = 0x%x", readl(host->base + MSDC_DMA_CTRL));
- N_MSG(DMA, "DMA_CFG = 0x%x", readl(host->base + MSDC_DMA_CFG));
- N_MSG(DMA, "DMA_SA = 0x%x", readl(host->base + MSDC_DMA_SA));
}
static int msdc_do_request(struct mmc_host *mmc, struct mmc_request *mrq)
@@ -1062,21 +661,14 @@ static int msdc_do_request(struct mmc_host *mmc, struct mmc_request *mrq)
#define SND_DAT 0
#define SND_CMD 1
- BUG_ON(mmc == NULL);
- BUG_ON(mrq == NULL);
+ BUG_ON(!mmc);
+ BUG_ON(!mrq);
host->error = 0;
cmd = mrq->cmd;
data = mrq->cmd->data;
-#if 0 /* --- by chhung */
- //if(host->id ==1){
- N_MSG(OPS, "enable clock!");
- msdc_ungate_clock(host->id);
- //}
-#endif /* end of --- */
-
if (!data) {
send_type = SND_CMD;
if (msdc_do_command(host, cmd, 1, CMD_TIMEOUT) != 0)
@@ -1125,15 +717,22 @@ static int msdc_do_request(struct mmc_host *mmc, struct mmc_request *mrq)
spin_unlock(&host->lock);
if (!wait_for_completion_timeout(&host->xfer_done, DAT_TIMEOUT)) {
- ERR_MSG("XXX CMD<%d> wait xfer_done<%d> timeout!!", cmd->opcode, data->blocks * data->blksz);
- ERR_MSG(" DMA_SA = 0x%x",
- readl(host->base + MSDC_DMA_SA));
- ERR_MSG(" DMA_CA = 0x%x",
- readl(host->base + MSDC_DMA_CA));
- ERR_MSG(" DMA_CTRL = 0x%x",
- readl(host->base + MSDC_DMA_CTRL));
- ERR_MSG(" DMA_CFG = 0x%x",
- readl(host->base + MSDC_DMA_CFG));
+ dev_err(mmc_dev(host->mmc),
+ "%d -> XXX CMD<%d> wait xfer_done<%d> timeout!!\n",
+ host->id, cmd->opcode,
+ data->blocks * data->blksz);
+ dev_err(mmc_dev(host->mmc),
+ "%d -> DMA_SA = 0x%x\n",
+ host->id, readl(host->base + MSDC_DMA_SA));
+ dev_err(mmc_dev(host->mmc),
+ "%d -> DMA_CA = 0x%x\n",
+ host->id, readl(host->base + MSDC_DMA_CA));
+ dev_err(mmc_dev(host->mmc),
+ "%d -> DMA_CTRL = 0x%x\n",
+ host->id, readl(host->base + MSDC_DMA_CTRL));
+ dev_err(mmc_dev(host->mmc),
+ "%d -> DMA_CFG = 0x%x\n",
+ host->id, readl(host->base + MSDC_DMA_CFG));
data->error = -ETIMEDOUT;
msdc_reset_hw(host);
@@ -1151,48 +750,13 @@ static int msdc_do_request(struct mmc_host *mmc, struct mmc_request *mrq)
}
done:
- if (data != NULL) {
+ if (data) {
host->data = NULL;
dma_unmap_sg(mmc_dev(mmc), data->sg, data->sg_len,
mmc_get_dma_dir(data));
host->blksz = 0;
-
-#if 0 // don't stop twice!
- if (host->hw->flags & MSDC_REMOVABLE && data->error) {
- msdc_abort_data(host);
- /* reset in IRQ, stop command has issued. -> No need */
- }
-#endif
-
- N_MSG(OPS, "CMD<%d> data<%s %s> blksz<%d> block<%d> error<%d>", cmd->opcode, (dma ? "dma" : "pio"),
- (read ? "read " : "write"), data->blksz, data->blocks, data->error);
}
-#if 0 /* --- by chhung */
-#if 1
- //if(host->id==1) {
- if (send_type == SND_CMD) {
- if (cmd->opcode == MMC_SEND_STATUS) {
- if ((cmd->resp[0] & CARD_READY_FOR_DATA) || (CARD_CURRENT_STATE(cmd->resp[0]) != 7)) {
- N_MSG(OPS, "disable clock, CMD13 IDLE");
- msdc_gate_clock(host->id);
- }
- } else {
- N_MSG(OPS, "disable clock, CMD<%d>", cmd->opcode);
- msdc_gate_clock(host->id);
- }
- } else {
- if (read) {
- N_MSG(OPS, "disable clock!!! Read CMD<%d>", cmd->opcode);
- msdc_gate_clock(host->id);
- }
- }
- //}
-#else
- msdc_gate_clock(host->id);
-#endif
-#endif /* end of --- */
-
if (mrq->cmd->error)
host->error = 0x001;
if (mrq->data && mrq->data->error)
@@ -1200,8 +764,6 @@ done:
if (mrq->stop && mrq->stop->error)
host->error |= 0x100;
- //if (host->error) ERR_MSG("host->error<%d>", host->error);
-
return host->error;
}
@@ -1213,11 +775,7 @@ static int msdc_app_cmd(struct mmc_host *mmc, struct msdc_host *host)
memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = MMC_APP_CMD;
-#if 0 /* bug: we meet mmc->card is null when ACMD6 */
- cmd.arg = mmc->card->rca << 16;
-#else
cmd.arg = host->app_cmd_arg;
-#endif
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
memset(&mrq, 0, sizeof(struct mmc_request));
@@ -1260,19 +818,27 @@ static int msdc_tune_cmdrsp(struct msdc_host *host, struct mmc_command *cmd)
if (host->app_cmd) {
result = msdc_app_cmd(host->mmc, host);
if (result) {
- ERR_MSG("TUNE_CMD app_cmd<%d> failed: RESP_RXDLY<%d>,R_SMPL<%d>",
- host->mrq->cmd->opcode, cur_rrdly, cur_rsmpl);
+ dev_err(mmc_dev(host->mmc),
+ "%d -> TUNE_CMD app_cmd<%d> failed: RESP_RXDLY<%d>,R_SMPL<%d>\n",
+ host->id,
+ host->mrq->cmd->opcode,
+ cur_rrdly, cur_rsmpl);
continue;
}
}
result = msdc_do_command(host, cmd, 0, CMD_TIMEOUT); // not tune.
- ERR_MSG("TUNE_CMD<%d> %s PAD_CMD_RESP_RXDLY[26:22]<%d> R_SMPL[1]<%d>", cmd->opcode,
- (result == 0) ? "PASS" : "FAIL", cur_rrdly, cur_rsmpl);
+ dev_err(mmc_dev(host->mmc),
+ "%d -> TUNE_CMD<%d> %s PAD_CMD_RESP_RXDLY[26:22]<%d> R_SMPL[1]<%d>\n",
+ host->id, cmd->opcode,
+ (result == 0) ? "PASS" : "FAIL", cur_rrdly,
+ cur_rsmpl);
if (result == 0)
return 0;
if (result != -EIO) {
- ERR_MSG("TUNE_CMD<%d> Error<%d> not -EIO", cmd->opcode, result);
+ dev_err(mmc_dev(host->mmc),
+ "%d -> TUNE_CMD<%d> Error<%d> not -EIO\n",
+ host->id, cmd->opcode, result);
return result;
}
@@ -1325,7 +891,10 @@ static int msdc_tune_bread(struct mmc_host *mmc, struct mmc_request *mrq)
if (host->app_cmd) {
result = msdc_app_cmd(host->mmc, host);
if (result) {
- ERR_MSG("TUNE_BREAD app_cmd<%d> failed", host->mrq->cmd->opcode);
+ dev_err(mmc_dev(host->mmc),
+ "%d -> TUNE_BREAD app_cmd<%d> failed\n",
+ host->id,
+ host->mrq->cmd->opcode);
continue;
}
}
@@ -1336,10 +905,13 @@ static int msdc_tune_bread(struct mmc_host *mmc, struct mmc_request *mrq)
&dcrc); /* RO */
if (!ddr)
dcrc &= ~SDC_DCRC_STS_NEG;
- ERR_MSG("TUNE_BREAD<%s> dcrc<0x%x> DATRDDLY0/1<0x%x><0x%x> dsmpl<0x%x>",
- (result == 0 && dcrc == 0) ? "PASS" : "FAIL", dcrc,
- readl(host->base + MSDC_DAT_RDDLY0),
- readl(host->base + MSDC_DAT_RDDLY1), cur_dsmpl);
+ dev_err(mmc_dev(host->mmc),
+ "%d -> TUNE_BREAD<%s> dcrc<0x%x> DATRDDLY0/1<0x%x><0x%x> dsmpl<0x%x>\n",
+ host->id,
+ (result == 0 && dcrc == 0) ? "PASS" : "FAIL",
+ dcrc, readl(host->base + MSDC_DAT_RDDLY0),
+ readl(host->base + MSDC_DAT_RDDLY1),
+ cur_dsmpl);
/* Fix me: result is 0, but dcrc is still exist */
if (result == 0 && dcrc == 0) {
@@ -1348,8 +920,11 @@ static int msdc_tune_bread(struct mmc_host *mmc, struct mmc_request *mrq)
/* there is a case: command timeout, and data phase not processed */
if (mrq->data->error != 0 &&
mrq->data->error != -EIO) {
- ERR_MSG("TUNE_READ: result<0x%x> cmd_error<%d> data_error<%d>",
- result, mrq->cmd->error, mrq->data->error);
+ dev_err(mmc_dev(host->mmc),
+ "%d -> TUNE_READ: result<0x%x> cmd_error<%d> data_error<%d>\n",
+ host->id, result,
+ mrq->cmd->error,
+ mrq->data->error);
goto done;
}
}
@@ -1458,13 +1033,18 @@ static int msdc_tune_bwrite(struct mmc_host *mmc, struct mmc_request *mrq)
if (host->app_cmd) {
result = msdc_app_cmd(host->mmc, host);
if (result) {
- ERR_MSG("TUNE_BWRITE app_cmd<%d> failed", host->mrq->cmd->opcode);
+ dev_err(mmc_dev(host->mmc),
+ "%d -> TUNE_BWRITE app_cmd<%d> failed\n",
+ host->id,
+ host->mrq->cmd->opcode);
continue;
}
}
result = msdc_do_request(mmc, mrq);
- ERR_MSG("TUNE_BWRITE<%s> DSPL<%d> DATWRDLY<%d> MSDC_DAT_RDDLY0<0x%x>",
+ dev_err(mmc_dev(host->mmc),
+ "%d -> TUNE_BWRITE<%s> DSPL<%d> DATWRDLY<%d> MSDC_DAT_RDDLY0<0x%x>\n",
+ host->id,
result == 0 ? "PASS" : "FAIL",
cur_dsmpl, cur_wrrdly, cur_rxdly0);
@@ -1473,8 +1053,11 @@ static int msdc_tune_bwrite(struct mmc_host *mmc, struct mmc_request *mrq)
} else {
/* there is a case: command timeout, and data phase not processed */
if (mrq->data->error != -EIO) {
- ERR_MSG("TUNE_READ: result<0x%x> cmd_error<%d> data_error<%d>",
- result, mrq->cmd->error, mrq->data->error);
+ dev_err(mmc_dev(host->mmc),
+ "%d -> TUNE_READ: result<0x%x> cmd_error<%d> data_error<%d>\n",
+ host->id, result,
+ mrq->cmd->error,
+ mrq->data->error);
goto done;
}
}
@@ -1508,7 +1091,8 @@ static int msdc_get_card_status(struct mmc_host *mmc, struct msdc_host *host, u3
if (mmc->card) {
cmd.arg = mmc->card->rca << 16;
} else {
- ERR_MSG("cmd13 mmc card is null");
+ dev_err(mmc_dev(host->mmc), "%d -> cmd13 mmc card is null\n",
+ host->id);
cmd.arg = host->app_cmd_arg;
}
cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
@@ -1535,7 +1119,8 @@ static int msdc_check_busy(struct mmc_host *mmc, struct msdc_host *host)
if (err)
return err;
/* need cmd12? */
- ERR_MSG("cmd<13> resp<0x%x>", status);
+ dev_err(mmc_dev(host->mmc), "%d -> cmd<13> resp<0x%x>\n",
+ host->id, status);
} while (R1_CURRENT_STATE(status) == 7);
return err;
@@ -1559,7 +1144,9 @@ static int msdc_tune_request(struct mmc_host *mmc, struct mmc_request *mrq)
} else {
ret = msdc_check_busy(mmc, host);
if (ret) {
- ERR_MSG("XXX cmd13 wait program done failed");
+ dev_err(mmc_dev(host->mmc),
+ "%d -> XXX cmd13 wait program done failed\n",
+ host->id);
return ret;
}
/* CRC and TO */
@@ -1575,22 +1162,10 @@ static void msdc_ops_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct msdc_host *host = mmc_priv(mmc);
- //=== for sdio profile ===
-#if 0 /* --- by chhung */
- u32 old_H32, old_L32, new_H32, new_L32;
- u32 ticks = 0, opcode = 0, sizes = 0, bRx = 0;
-#endif /* end of --- */
-
WARN_ON(host->mrq);
/* start to process */
spin_lock(&host->lock);
-#if 0 /* --- by chhung */
- if (sdio_pro_enable) { //=== for sdio profile ===
- if (mrq->cmd->opcode == 52 || mrq->cmd->opcode == 53)
- GPT_GetCounter64(&old_L32, &old_H32);
- }
-#endif /* end of --- */
host->mrq = mrq;
@@ -1610,26 +1185,6 @@ static void msdc_ops_request(struct mmc_host *mmc, struct mmc_request *mrq)
host->mrq = NULL;
-#if 0 /* --- by chhung */
- //=== for sdio profile ===
- if (sdio_pro_enable) {
- if (mrq->cmd->opcode == 52 || mrq->cmd->opcode == 53) {
- GPT_GetCounter64(&new_L32, &new_H32);
- ticks = msdc_time_calc(old_L32, old_H32, new_L32, new_H32);
-
- opcode = mrq->cmd->opcode;
- if (mrq->cmd->data) {
- sizes = mrq->cmd->data->blocks * mrq->cmd->data->blksz;
- bRx = mrq->cmd->data->flags & MMC_DATA_READ ? 1 : 0;
- } else {
- bRx = mrq->cmd->arg & 0x80000000 ? 1 : 0;
- }
-
- if (!mrq->cmd->error)
- msdc_performance(opcode, sizes, bRx, ticks);
- }
- }
-#endif /* end of --- */
spin_unlock(&host->lock);
mmc_request_done(mmc, mrq);
@@ -1659,8 +1214,6 @@ static void msdc_set_buswidth(struct msdc_host *host, u32 width)
}
writel(val, host->base + SDC_CFG);
-
- N_MSG(CFG, "Bus Width = %d", width);
}
/* ops.set_ios */
@@ -1698,7 +1251,6 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
switch (ios->power_mode) {
case MMC_POWER_OFF:
case MMC_POWER_UP:
- // msdc_set_power_mode(host, ios->power_mode); /* --- by chhung */
break;
case MMC_POWER_ON:
host->power_mode = MMC_POWER_ON;
@@ -1711,7 +1263,6 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
if (host->mclk != ios->clock) {
if (ios->clock > 25000000) {
//if (!(host->hw->flags & MSDC_REMOVABLE)) {
- INIT_MSG("SD data latch edge<%d>", MSDC_SMPL_FALLING);
sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_RSPL,
MSDC_SMPL_FALLING);
sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_DSPL,
@@ -1764,7 +1315,6 @@ static int msdc_ops_get_cd(struct mmc_host *mmc)
return 1;
#else
host->card_inserted = (host->pm_state.event == PM_EVENT_USER_RESUME) ? 1 : 0;
- INIT_MSG("sdio ops_get_cd<%d>", host->card_inserted);
return host->card_inserted;
#endif
}
@@ -1772,9 +1322,6 @@ static int msdc_ops_get_cd(struct mmc_host *mmc)
/* MSDC_CD_PIN_EN set for card */
if (host->hw->flags & MSDC_CD_PIN_EN) {
spin_lock_irqsave(&host->lock, flags);
-#if 0
- present = host->card_inserted; /* why not read from H/W: Fix me*/
-#else
// CD
present = readl(host->base + MSDC_PS) & MSDC_PS_CDSTS;
if (cd_active_low)
@@ -1782,13 +1329,11 @@ static int msdc_ops_get_cd(struct mmc_host *mmc)
else
present = present ? 1 : 0;
host->card_inserted = present;
-#endif
spin_unlock_irqrestore(&host->lock, flags);
} else {
present = 0; /* TODO? Check DAT3 pins for card detection */
}
- INIT_MSG("ops_get_cd return<%d>", present);
return present;
}
@@ -1823,19 +1368,12 @@ static irqreturn_t msdc_irq(int irq, void *dev_id)
if (intsts & MSDC_INT_CDSC) {
if (host->mmc->caps & MMC_CAP_NEEDS_POLL)
return IRQ_HANDLED;
- IRQ_MSG("MSDC_INT_CDSC irq<0x%.8x>", intsts);
schedule_delayed_work(&host->card_delaywork, HZ);
/* tuning when plug card ? */
}
- /* sdio interrupt */
- if (intsts & MSDC_INT_SDIOIRQ) {
- IRQ_MSG("XXX MSDC_INT_SDIOIRQ"); /* seems not sdio irq */
- //mmc_signal_sdio_irq(host->mmc);
- }
-
/* transfer complete interrupt */
- if (data != NULL) {
+ if (data) {
if (inten & MSDC_INT_XFER_COMPL) {
data->bytes_xfered = host->xfer_size;
complete(&host->xfer_done);
@@ -1847,13 +1385,10 @@ static irqreturn_t msdc_irq(int irq, void *dev_id)
msdc_clr_fifo(host);
msdc_clr_int();
- if (intsts & MSDC_INT_DATTMO) {
- IRQ_MSG("XXX CMD<%d> MSDC_INT_DATTMO", host->mrq->cmd->opcode);
+ if (intsts & MSDC_INT_DATTMO)
data->error = -ETIMEDOUT;
- } else if (intsts & MSDC_INT_DATCRCERR) {
- IRQ_MSG("XXX CMD<%d> MSDC_INT_DATCRCERR, SDC_DCRC_STS<0x%x>", host->mrq->cmd->opcode, readl(host->base + SDC_DCRC_STS));
+ else if (intsts & MSDC_INT_DATCRCERR)
data->error = -EIO;
- }
//if(readl(MSDC_INTEN) & MSDC_INT_XFER_COMPL) {
complete(&host->xfer_done); /* Read CRC come fast, XFER_COMPL not enabled */
@@ -1861,7 +1396,7 @@ static irqreturn_t msdc_irq(int irq, void *dev_id)
}
/* command interrupts */
- if ((cmd != NULL) && (intsts & cmdsts)) {
+ if (cmd && (intsts & cmdsts)) {
if ((intsts & MSDC_INT_CMDRDY) || (intsts & MSDC_INT_ACMDRDY) ||
(intsts & MSDC_INT_ACMD19_DONE)) {
u32 *rsp = &cmd->resp[0];
@@ -1883,16 +1418,8 @@ static irqreturn_t msdc_irq(int irq, void *dev_id)
break;
}
} else if ((intsts & MSDC_INT_RSPCRCERR) || (intsts & MSDC_INT_ACMDCRCERR)) {
- if (intsts & MSDC_INT_ACMDCRCERR)
- IRQ_MSG("XXX CMD<%d> MSDC_INT_ACMDCRCERR", cmd->opcode);
- else
- IRQ_MSG("XXX CMD<%d> MSDC_INT_RSPCRCERR", cmd->opcode);
cmd->error = -EIO;
} else if ((intsts & MSDC_INT_CMDTMO) || (intsts & MSDC_INT_ACMDTMO)) {
- if (intsts & MSDC_INT_ACMDTMO)
- IRQ_MSG("XXX CMD<%d> MSDC_INT_ACMDTMO", cmd->opcode);
- else
- IRQ_MSG("XXX CMD<%d> MSDC_INT_CMDTMO", cmd->opcode);
cmd->error = -ETIMEDOUT;
msdc_reset_hw(host);
msdc_clr_fifo(host);
@@ -1903,36 +1430,8 @@ static irqreturn_t msdc_irq(int irq, void *dev_id)
/* mmc irq interrupts */
if (intsts & MSDC_INT_MMCIRQ)
- printk(KERN_INFO "msdc[%d] MMCIRQ: SDC_CSTS=0x%.8x\r\n",
- host->id, readl(host->base + SDC_CSTS));
-
-#ifdef MT6575_SD_DEBUG
- {
-/* msdc_int_reg *int_reg = (msdc_int_reg*)&intsts;*/
- N_MSG(INT, "IRQ_EVT(0x%x): MMCIRQ(%d) CDSC(%d), ACRDY(%d), ACTMO(%d), ACCRE(%d) AC19DN(%d)",
- intsts,
- int_reg->mmcirq,
- int_reg->cdsc,
- int_reg->atocmdrdy,
- int_reg->atocmdtmo,
- int_reg->atocmdcrc,
- int_reg->atocmd19done);
- N_MSG(INT, "IRQ_EVT(0x%x): SDIO(%d) CMDRDY(%d), CMDTMO(%d), RSPCRC(%d), CSTA(%d)",
- intsts,
- int_reg->sdioirq,
- int_reg->cmdrdy,
- int_reg->cmdtmo,
- int_reg->rspcrc,
- int_reg->csta);
- N_MSG(INT, "IRQ_EVT(0x%x): XFCMP(%d) DXDONE(%d), DATTMO(%d), DATCRC(%d), DMAEMP(%d)",
- intsts,
- int_reg->xfercomp,
- int_reg->dxferdone,
- int_reg->dattmo,
- int_reg->datcrc,
- int_reg->dmaqempty);
- }
-#endif
+ dev_info(mmc_dev(host->mmc), "msdc[%d] MMCIRQ: SDC_CSTS=0x%.8x\r\n",
+ host->id, readl(host->base + SDC_CSTS));
return IRQ_HANDLED;
}
@@ -1958,14 +1457,11 @@ static void msdc_enable_cd_irq(struct msdc_host *host, int enable)
return;
}
- N_MSG(CFG, "CD IRQ Enable(%d)", enable);
-
if (enable) {
/* card detection circuit relies on the core power so that the core power
* shouldn't be turned off. Here adds a reference count to keep
* the core power alive.
*/
- //msdc_vcore_on(host); //did in msdc_init_hw()
if (hw->config_gpio_pin) /* NULL */
hw->config_gpio_pin(MSDC_CD_PIN, GPIO_PULL_UP);
@@ -1988,7 +1484,6 @@ static void msdc_enable_cd_irq(struct msdc_host *host, int enable)
/* Here decreases a reference count to core power since card
* detection circuit is shutdown.
*/
- //msdc_vcore_off(host);
}
}
@@ -1996,14 +1491,6 @@ static void msdc_enable_cd_irq(struct msdc_host *host, int enable)
static void msdc_init_hw(struct msdc_host *host)
{
- /* Power on */
-#if 0 /* --- by chhung */
- msdc_vcore_on(host);
- msdc_pin_reset(host, MSDC_PIN_PULL_UP);
- msdc_select_clksrc(host, hw->clk_src);
- enable_clock(PERI_MSDC0_PDN + host->id, "SD");
- msdc_vdd_on(host);
-#endif /* end of --- */
/* Configure to MMC/SD mode */
sdr_set_field(host->base + MSDC_CFG, MSDC_CFG_MODE, MSDC_SDMMC);
@@ -2035,10 +1522,6 @@ static void msdc_init_hw(struct msdc_host *host)
writel(0x00000000, host->base + MSDC_DAT_RDDLY1);
writel(0x00000000, host->base + MSDC_IOCON);
-#if 0 // use MT7620 default value: 0x403c004f
- /* bit0 modified: Rx Data Clock Source: 1 -> 2.0*/
- writel(0x003C000F, host->base + MSDC_PATCH_BIT0);
-#endif
if (readl(host->base + MSDC_ECO_VER) >= 4) {
if (host->id == 1) {
@@ -2094,8 +1577,6 @@ static void msdc_init_hw(struct msdc_host *host)
sdr_set_field(host->base + SDC_CFG, SDC_CFG_DTOC, DEFAULT_DTOC);
msdc_set_buswidth(host, MMC_BUS_WIDTH_1);
-
- N_MSG(FUC, "init hardware done!");
}
/* called by msdc_drv_remove */
@@ -2107,7 +1588,6 @@ static void msdc_deinit_hw(struct msdc_host *host)
/* Disable card detection */
msdc_enable_cd_irq(host, 0);
- // msdc_set_power_mode(host, MMC_POWER_OFF); /* make sure power down */ /* --- by chhung */
}
/* init gpd and bd list in msdc_drv_probe */
@@ -2289,7 +1769,8 @@ static int msdc_drv_remove(struct platform_device *pdev)
host = mmc_priv(mmc);
BUG_ON(!host);
- ERR_MSG("removed !!!");
+ dev_err(mmc_dev(host->mmc), "%d -> removed !!!\n",
+ host->id);
platform_set_drvdata(pdev, NULL);
mmc_remove_host(host->mmc);
@@ -2313,6 +1794,7 @@ static int msdc_drv_remove(struct platform_device *pdev)
static void msdc_drv_pm(struct platform_device *pdev, pm_message_t state)
{
struct mmc_host *mmc = platform_get_drvdata(pdev);
+
if (mmc) {
struct msdc_host *host = mmc_priv(mmc);
msdc_pm(state, (void *)host);
@@ -2370,7 +1852,7 @@ static int __init mt_msdc_init(void)
ret = platform_driver_register(&mt_msdc_driver);
if (ret) {
- printk(KERN_ERR DRV_NAME ": Can't register driver");
+ pr_err("%s: Can't register driver", DRV_NAME);
return ret;
}
diff --git a/drivers/staging/mt7621-pci/pci-mt7621.c b/drivers/staging/mt7621-pci/pci-mt7621.c
index a49e2795af6b..8371a9cdb164 100644
--- a/drivers/staging/mt7621-pci/pci-mt7621.c
+++ b/drivers/staging/mt7621-pci/pci-mt7621.c
@@ -122,7 +122,7 @@
#define RALINK_PCIE_CLK_EN BIT(21)
#define MEMORY_BASE 0x0
-static int pcie_link_status = 0;
+static int pcie_link_status;
/**
* struct mt7621_pcie_port - PCIe port information
@@ -214,7 +214,7 @@ write_config(struct mt7621_pcie *pcie, unsigned int dev, u32 reg, u32 val)
pcie_write(pcie, val, RALINK_PCI_CONFIG_DATA);
}
-void
+static void
set_pcie_phy(struct mt7621_pcie *pcie, u32 offset,
int start_b, int bits, int val)
{
@@ -225,7 +225,7 @@ set_pcie_phy(struct mt7621_pcie *pcie, u32 offset,
pcie_write(pcie, reg, offset);
}
-void
+static void
bypass_pipe_rst(struct mt7621_pcie *pcie)
{
/* PCIe Port 0 */
@@ -239,7 +239,7 @@ bypass_pipe_rst(struct mt7621_pcie *pcie)
set_pcie_phy(pcie, (RALINK_PCIEPHY_P2_CTL_OFFSET + 0x02c), 4, 1, 0x01); // rg_pe1_pipe_cmd_frc[4]
}
-void
+static void
set_phy_for_ssc(struct mt7621_pcie *pcie)
{
unsigned long reg = rt_sysc_r32(SYSC_REG_SYSTEM_CONFIG0);
@@ -387,15 +387,8 @@ static int mt7621_pcie_parse_dt(struct mt7621_pcie *pcie)
struct device *dev = pcie->dev;
struct device_node *node = dev->of_node;
struct resource regs;
- const char *type;
int err;
- type = of_get_property(node, "device_type", NULL);
- if (!type || strcmp(type, "pci") != 0) {
- dev_err(dev, "invalid \"device_type\" %s\n", type);
- return -EINVAL;
- }
-
err = of_address_to_resource(node, 0, &regs);
if (err) {
dev_err(dev, "missing \"reg\" property\n");
@@ -481,12 +474,12 @@ static int mt7621_pci_probe(struct platform_device *pdev)
ASSERT_SYSRST_PCIE(RALINK_PCIE0_RST | RALINK_PCIE1_RST | RALINK_PCIE2_RST);
- *(unsigned int *)(0xbe000060) &= ~(0x3<<10 | 0x3<<3);
- *(unsigned int *)(0xbe000060) |= 0x1<<10 | 0x1<<3;
+ *(unsigned int *)(0xbe000060) &= ~(0x3 << 10 | 0x3 << 3);
+ *(unsigned int *)(0xbe000060) |= BIT(10) | BIT(3);
mdelay(100);
- *(unsigned int *)(0xbe000600) |= 0x1<<19 | 0x1<<8 | 0x1<<7; // use GPIO19/GPIO8/GPIO7 (PERST_N/UART_RXD3/UART_TXD3)
+ *(unsigned int *)(0xbe000600) |= BIT(19) | BIT(8) | BIT(7); // use GPIO19/GPIO8/GPIO7 (PERST_N/UART_RXD3/UART_TXD3)
mdelay(100);
- *(unsigned int *)(0xbe000620) &= ~(0x1<<19 | 0x1<<8 | 0x1<<7); // clear DATA
+ *(unsigned int *)(0xbe000620) &= ~(BIT(19) | BIT(8) | BIT(7)); // clear DATA
mdelay(100);
@@ -496,18 +489,15 @@ static int mt7621_pci_probe(struct platform_device *pdev)
DEASSERT_SYSRST_PCIE(val);
- if ((*(unsigned int *)(0xbe00000c)&0xFFFF) == 0x0101) // MT7621 E2
+ if ((*(unsigned int *)(0xbe00000c) & 0xFFFF) == 0x0101) // MT7621 E2
bypass_pipe_rst(pcie);
set_phy_for_ssc(pcie);
- val = read_config(pcie, 0, 0x70c);
- printk("Port 0 N_FTS = %x\n", (unsigned int)val);
-
- val = read_config(pcie, 1, 0x70c);
- printk("Port 1 N_FTS = %x\n", (unsigned int)val);
-
- val = read_config(pcie, 2, 0x70c);
- printk("Port 2 N_FTS = %x\n", (unsigned int)val);
+ list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
+ u32 slot = port->slot;
+ val = read_config(pcie, slot, 0x70c);
+ dev_info(dev, "Port %d N_FTS = %x\n", (unsigned int)val, slot);
+ }
rt_sysc_m32(0, RALINK_PCIE_RST, RALINK_RSTCTRL);
rt_sysc_m32(0x30, 2 << 4, SYSC_REG_SYSTEM_CONFIG1);
@@ -520,18 +510,18 @@ static int mt7621_pci_probe(struct platform_device *pdev)
rt_sysc_m32(RALINK_PCIE_RST, 0, RALINK_RSTCTRL);
/* Use GPIO control instead of PERST_N */
- *(unsigned int *)(0xbe000620) |= 0x1<<19 | 0x1<<8 | 0x1<<7; // set DATA
+ *(unsigned int *)(0xbe000620) |= BIT(19) | BIT(8) | BIT(7); // set DATA
mdelay(1000);
if ((pcie_read(pcie, RT6855_PCIE0_OFFSET + RALINK_PCI_STATUS) & 0x1) == 0) {
printk("PCIE0 no card, disable it(RST&CLK)\n");
ASSERT_SYSRST_PCIE(RALINK_PCIE0_RST);
rt_sysc_m32(RALINK_PCIE0_CLK_EN, 0, RALINK_CLKCFG1);
- pcie_link_status &= ~(1<<0);
+ pcie_link_status &= ~(BIT(0));
} else {
- pcie_link_status |= 1<<0;
+ pcie_link_status |= BIT(0);
val = pcie_read(pcie, RALINK_PCI_PCIMSK_ADDR);
- val |= (1<<20); // enable pcie1 interrupt
+ val |= BIT(20); // enable pcie1 interrupt
pcie_write(pcie, val, RALINK_PCI_PCIMSK_ADDR);
}
@@ -539,11 +529,11 @@ static int mt7621_pci_probe(struct platform_device *pdev)
printk("PCIE1 no card, disable it(RST&CLK)\n");
ASSERT_SYSRST_PCIE(RALINK_PCIE1_RST);
rt_sysc_m32(RALINK_PCIE1_CLK_EN, 0, RALINK_CLKCFG1);
- pcie_link_status &= ~(1<<1);
+ pcie_link_status &= ~(BIT(1));
} else {
- pcie_link_status |= 1<<1;
+ pcie_link_status |= BIT(1);
val = pcie_read(pcie, RALINK_PCI_PCIMSK_ADDR);
- val |= (1<<21); // enable pcie1 interrupt
+ val |= BIT(21); // enable pcie1 interrupt
pcie_write(pcie, val, RALINK_PCI_PCIMSK_ADDR);
}
@@ -551,11 +541,11 @@ static int mt7621_pci_probe(struct platform_device *pdev)
printk("PCIE2 no card, disable it(RST&CLK)\n");
ASSERT_SYSRST_PCIE(RALINK_PCIE2_RST);
rt_sysc_m32(RALINK_PCIE2_CLK_EN, 0, RALINK_CLKCFG1);
- pcie_link_status &= ~(1<<2);
+ pcie_link_status &= ~(BIT(2));
} else {
- pcie_link_status |= 1<<2;
+ pcie_link_status |= BIT(2);
val = pcie_read(pcie, RALINK_PCI_PCIMSK_ADDR);
- val |= (1<<22); // enable pcie2 interrupt
+ val |= BIT(22); // enable pcie2 interrupt
pcie_write(pcie, val, RALINK_PCI_PCIMSK_ADDR);
}
@@ -654,26 +644,26 @@ pcie(2/1/0) link status pcie2_num pcie1_num pcie0_num
switch (pcie_link_status) {
case 7:
val = read_config(pcie, 2, 0x4);
- write_config(pcie, 2, 0x4, val|0x4);
+ write_config(pcie, 2, 0x4, val | 0x4);
val = read_config(pcie, 2, 0x70c);
- val &= ~(0xff)<<8;
- val |= 0x50<<8;
+ val &= ~(0xff) << 8;
+ val |= 0x50 << 8;
write_config(pcie, 2, 0x70c, val);
case 3:
case 5:
case 6:
val = read_config(pcie, 1, 0x4);
- write_config(pcie, 1, 0x4, val|0x4);
+ write_config(pcie, 1, 0x4, val | 0x4);
val = read_config(pcie, 1, 0x70c);
- val &= ~(0xff)<<8;
- val |= 0x50<<8;
+ val &= ~(0xff) << 8;
+ val |= 0x50 << 8;
write_config(pcie, 1, 0x70c, val);
default:
val = read_config(pcie, 0, 0x4);
- write_config(pcie, 0, 0x4, val|0x4); //bus master enable
+ write_config(pcie, 0, 0x4, val | 0x4); //bus master enable
val = read_config(pcie, 0, 0x70c);
- val &= ~(0xff)<<8;
- val |= 0x50<<8;
+ val &= ~(0xff) << 8;
+ val |= 0x50 << 8;
write_config(pcie, 0, 0x70c, val);
}
diff --git a/drivers/staging/octeon-usb/octeon-hcd.c b/drivers/staging/octeon-usb/octeon-hcd.c
index cff5e790b196..9c766f5b812f 100644
--- a/drivers/staging/octeon-usb/octeon-hcd.c
+++ b/drivers/staging/octeon-usb/octeon-hcd.c
@@ -377,29 +377,6 @@ struct octeon_hcd {
struct cvmx_usb_tx_fifo nonperiodic;
};
-/* This macro spins on a register waiting for it to reach a condition. */
-#define CVMX_WAIT_FOR_FIELD32(address, _union, cond, timeout_usec) \
- ({int result; \
- do { \
- u64 done = cvmx_get_cycle() + (u64)timeout_usec * \
- octeon_get_clock_rate() / 1000000; \
- union _union c; \
- \
- while (1) { \
- c.u32 = cvmx_usb_read_csr32(usb, address); \
- \
- if (cond) { \
- result = 0; \
- break; \
- } else if (cvmx_get_cycle() > done) { \
- result = -1; \
- break; \
- } else \
- __delay(100); \
- } \
- } while (0); \
- result; })
-
/*
* This macro logically sets a single field in a CSR. It does the sequence
* read, modify, and write
@@ -593,6 +570,33 @@ static inline int cvmx_usb_get_data_pid(struct cvmx_usb_pipe *pipe)
return 0; /* Data0 */
}
+/* Loops through register until txfflsh or rxfflsh become zero.*/
+static int cvmx_wait_tx_rx(struct octeon_hcd *usb, int fflsh_type)
+{
+ int result;
+ u64 address = CVMX_USBCX_GRSTCTL(usb->index);
+ u64 done = cvmx_get_cycle() + 100 *
+ (u64)octeon_get_clock_rate / 1000000;
+ union cvmx_usbcx_grstctl c;
+
+ while (1) {
+ c.u32 = cvmx_usb_read_csr32(usb, address);
+ if (fflsh_type == 0 && c.s.txfflsh == 0) {
+ result = 0;
+ break;
+ } else if (fflsh_type == 1 && c.s.rxfflsh == 0) {
+ result = 0;
+ break;
+ } else if (cvmx_get_cycle() > done) {
+ result = -1;
+ break;
+ }
+
+ __delay(100);
+ }
+ return result;
+}
+
static void cvmx_fifo_setup(struct octeon_hcd *usb)
{
union cvmx_usbcx_ghwcfg3 usbcx_ghwcfg3;
@@ -634,12 +638,10 @@ static void cvmx_fifo_setup(struct octeon_hcd *usb)
cvmx_usbcx_grstctl, txfnum, 0x10);
USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index),
cvmx_usbcx_grstctl, txfflsh, 1);
- CVMX_WAIT_FOR_FIELD32(CVMX_USBCX_GRSTCTL(usb->index),
- cvmx_usbcx_grstctl, c.s.txfflsh == 0, 100);
+ cvmx_wait_tx_rx(usb, 0);
USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index),
cvmx_usbcx_grstctl, rxfflsh, 1);
- CVMX_WAIT_FOR_FIELD32(CVMX_USBCX_GRSTCTL(usb->index),
- cvmx_usbcx_grstctl, c.s.rxfflsh == 0, 100);
+ cvmx_wait_tx_rx(usb, 1);
}
/**
@@ -2768,7 +2770,7 @@ static int cvmx_usb_poll_channel(struct octeon_hcd *usb, int channel)
(pipe->transfer_dir == CVMX_USB_DIRECTION_OUT))
pipe->flags |= CVMX_USB_PIPE_FLAGS_NEED_PING;
- if (unlikely(WARN_ON_ONCE(bytes_this_transfer < 0))) {
+ if (WARN_ON_ONCE(bytes_this_transfer < 0)) {
/*
* In some rare cases the DMA engine seems to get stuck and
* keeps substracting same byte count over and over again. In
diff --git a/drivers/staging/olpc_dcon/Kconfig b/drivers/staging/olpc_dcon/Kconfig
index c91a56f77bcb..192cc8d0853f 100644
--- a/drivers/staging/olpc_dcon/Kconfig
+++ b/drivers/staging/olpc_dcon/Kconfig
@@ -2,6 +2,7 @@ config FB_OLPC_DCON
tristate "One Laptop Per Child Display CONtroller support"
depends on OLPC && FB
depends on I2C
+ depends on BACKLIGHT_LCD_SUPPORT
depends on (GPIO_CS5535 || GPIO_CS5535=n)
select BACKLIGHT_CLASS_DEVICE
help
diff --git a/drivers/staging/olpc_dcon/olpc_dcon.c b/drivers/staging/olpc_dcon/olpc_dcon.c
index 2744c9f0920e..6b714f740ac3 100644
--- a/drivers/staging/olpc_dcon/olpc_dcon.c
+++ b/drivers/staging/olpc_dcon/olpc_dcon.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Mainly by David Woodhouse, somewhat modified by Jordan Crouse
*
@@ -5,10 +6,6 @@
* Copyright © 2006-2007 Advanced Micro Devices, Inc.
* Copyright © 2009 VIA Technology, Inc.
* Copyright (c) 2010-2011 Andres Salomon <dilinger@queued.net>
- *
- * This program is free software. You can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c b/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c
index 633c58ce24ee..ff145d493e1b 100644
--- a/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c
+++ b/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Mainly by David Woodhouse, somewhat modified by Jordan Crouse
*
@@ -5,10 +6,6 @@
* Copyright © 2006-2007 Advanced Micro Devices, Inc.
* Copyright © 2009 VIA Technology, Inc.
* Copyright (c) 2010 Andres Salomon <dilinger@queued.net>
- *
- * This program is free software. You can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c b/drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c
index 64584425b01c..838daa2be3ef 100644
--- a/drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c
+++ b/drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2009,2010 One Laptop per Child
- *
- * This program is free software. You can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/staging/pi433/rf69.c b/drivers/staging/pi433/rf69.c
index 085272fb393f..4fa6c0237e59 100644
--- a/drivers/staging/pi433/rf69.c
+++ b/drivers/staging/pi433/rf69.c
@@ -853,7 +853,6 @@ int rf69_write_fifo(struct spi_device *spi, u8 *buffer, unsigned int size)
#ifdef DEBUG_FIFO_ACCESS
int i;
#endif
- char spi_address = REG_FIFO | WRITE_BIT;
u8 local_buffer[FIFO_SIZE + 1];
if (size > FIFO_SIZE) {
@@ -862,7 +861,7 @@ int rf69_write_fifo(struct spi_device *spi, u8 *buffer, unsigned int size)
return -EMSGSIZE;
}
- local_buffer[0] = spi_address;
+ local_buffer[0] = REG_FIFO | WRITE_BIT;
memcpy(&local_buffer[1], buffer, size);
#ifdef DEBUG_FIFO_ACCESS
diff --git a/drivers/staging/rtl8188eu/Makefile b/drivers/staging/rtl8188eu/Makefile
index 4e606b03ec03..7da911c2ab89 100644
--- a/drivers/staging/rtl8188eu/Makefile
+++ b/drivers/staging/rtl8188eu/Makefile
@@ -28,7 +28,7 @@ r8188eu-y := \
hal/hal_intf.o \
hal/hal_com.o \
hal/odm.o \
- hal/odm_HWConfig.o \
+ hal/odm_hwconfig.o \
hal/odm_rtl8188e.o \
hal/rtl8188e_cmd.o \
hal/rtl8188e_dm.o \
diff --git a/drivers/staging/rtl8188eu/TODO b/drivers/staging/rtl8188eu/TODO
index 7581e25f231d..5faa0a9bba25 100644
--- a/drivers/staging/rtl8188eu/TODO
+++ b/drivers/staging/rtl8188eu/TODO
@@ -1,5 +1,5 @@
TODO:
-- find and remove remaining code valid only for 5 HGz. Most of the obvious
+- 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
diff --git a/drivers/staging/rtl8188eu/core/rtw_ap.c b/drivers/staging/rtl8188eu/core/rtw_ap.c
index 676d549ef786..1c319c2ca86d 100644
--- a/drivers/staging/rtl8188eu/core/rtw_ap.c
+++ b/drivers/staging/rtl8188eu/core/rtw_ap.c
@@ -36,7 +36,7 @@ void free_mlme_ap_info(struct adapter *padapter)
struct sta_priv *pstapriv = &padapter->stapriv;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
- struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
pmlmepriv->update_bcn = false;
pmlmeext->bstart_bss = false;
@@ -337,8 +337,6 @@ void add_RATid(struct adapter *padapter, struct sta_info *psta, u8 rssi_level)
unsigned char sta_band = 0, raid, shortGIrate = false;
unsigned int tx_ra_bitmap = 0;
struct ht_priv *psta_ht = NULL;
- struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
- struct wlan_bssid_ex *pcur_network = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network;
if (psta)
psta_ht = &psta->htpriv;
@@ -363,20 +361,13 @@ void add_RATid(struct adapter *padapter, struct sta_info *psta, u8 rssi_level)
shortGIrate = psta_ht->sgi;
}
- if (pcur_network->Configuration.DSConfig > 14) {
- /* 5G band */
- if (tx_ra_bitmap & 0xffff000)
- sta_band |= WIRELESS_11_5N | WIRELESS_11A;
- else
- sta_band |= WIRELESS_11A;
- } else {
- if (tx_ra_bitmap & 0xffff000)
- sta_band |= WIRELESS_11_24N | WIRELESS_11G | WIRELESS_11B;
- else if (tx_ra_bitmap & 0xff0)
- sta_band |= WIRELESS_11G | WIRELESS_11B;
- else
- sta_band |= WIRELESS_11B;
- }
+ if (tx_ra_bitmap & 0xffff000)
+ sta_band |= WIRELESS_11_24N | WIRELESS_11G | WIRELESS_11B;
+ else if (tx_ra_bitmap & 0xff0)
+ sta_band |= WIRELESS_11G | WIRELESS_11B;
+ else
+ sta_band |= WIRELESS_11B;
+
psta->wireless_mode = sta_band;
diff --git a/drivers/staging/rtl8188eu/core/rtw_cmd.c b/drivers/staging/rtl8188eu/core/rtw_cmd.c
index 59039211dad2..9b2a497aa413 100644
--- a/drivers/staging/rtl8188eu/core/rtw_cmd.c
+++ b/drivers/staging/rtl8188eu/core/rtw_cmd.c
@@ -243,11 +243,11 @@ u8 rtw_sitesurvey_cmd(struct adapter *padapter, struct ndis_802_11_ssid *ssid,
if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_SCAN, 1);
- ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+ ph2c = kzalloc(sizeof(*ph2c), GFP_ATOMIC);
if (!ph2c)
return _FAIL;
- psurveyPara = kzalloc(sizeof(struct sitesurvey_parm), GFP_ATOMIC);
+ psurveyPara = kzalloc(sizeof(*psurveyPara), GFP_ATOMIC);
if (!psurveyPara) {
kfree(ph2c);
return _FAIL;
@@ -325,7 +325,7 @@ u8 rtw_createbss_cmd(struct adapter *padapter)
else
RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, (" createbss for SSid:%s\n", pmlmepriv->assoc_ssid.Ssid));
- pcmd = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+ pcmd = kzalloc(sizeof(*pcmd), GFP_ATOMIC);
if (!pcmd) {
res = _FAIL;
goto exit;
@@ -367,7 +367,7 @@ u8 rtw_joinbss_cmd(struct adapter *padapter, struct wlan_network *pnetwork)
else
RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+Join cmd: SSid =[%s]\n", pmlmepriv->assoc_ssid.Ssid));
- pcmd = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+ pcmd = kzalloc(sizeof(*pcmd), GFP_ATOMIC);
if (!pcmd) {
res = _FAIL;
goto exit;
@@ -527,8 +527,8 @@ u8 rtw_setopmode_cmd(struct adapter *padapter, enum ndis_802_11_network_infra n
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
- ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
- psetop = kzalloc(sizeof(struct setopmode_parm), GFP_KERNEL);
+ ph2c = kzalloc(sizeof(*ph2c), GFP_KERNEL);
+ psetop = kzalloc(sizeof(*psetop), GFP_KERNEL);
if (!ph2c || !psetop) {
kfree(ph2c);
kfree(psetop);
@@ -552,9 +552,9 @@ u8 rtw_setstakey_cmd(struct adapter *padapter, u8 *psta, u8 unicast_key)
struct security_priv *psecuritypriv = &padapter->securitypriv;
struct sta_info *sta = (struct sta_info *)psta;
- ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
- psetstakey_para = kzalloc(sizeof(struct set_stakey_parm), GFP_KERNEL);
- psetstakey_rsp = kzalloc(sizeof(struct set_stakey_rsp), GFP_KERNEL);
+ ph2c = kzalloc(sizeof(*ph2c), GFP_KERNEL);
+ psetstakey_para = kzalloc(sizeof(*psetstakey_para), GFP_KERNEL);
+ psetstakey_rsp = kzalloc(sizeof(*psetstakey_rsp), GFP_KERNEL);
if (!ph2c || !psetstakey_para || !psetstakey_rsp) {
kfree(ph2c);
@@ -597,20 +597,20 @@ u8 rtw_clearstakey_cmd(struct adapter *padapter, u8 *psta, u8 entry, u8 enqueue)
if (!enqueue) {
clear_cam_entry(padapter, entry);
} else {
- ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+ ph2c = kzalloc(sizeof(*ph2c), GFP_ATOMIC);
if (!ph2c) {
res = _FAIL;
goto exit;
}
- psetstakey_para = kzalloc(sizeof(struct set_stakey_parm), GFP_ATOMIC);
+ psetstakey_para = kzalloc(sizeof(*psetstakey_para), GFP_ATOMIC);
if (!psetstakey_para) {
kfree(ph2c);
res = _FAIL;
goto exit;
}
- psetstakey_rsp = kzalloc(sizeof(struct set_stakey_rsp), GFP_ATOMIC);
+ psetstakey_rsp = kzalloc(sizeof(*psetstakey_rsp), GFP_ATOMIC);
if (!psetstakey_rsp) {
kfree(ph2c);
kfree(psetstakey_para);
@@ -642,13 +642,13 @@ u8 rtw_addbareq_cmd(struct adapter *padapter, u8 tid, u8 *addr)
struct addBaReq_parm *paddbareq_parm;
u8 res = _SUCCESS;
- ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+ ph2c = kzalloc(sizeof(*ph2c), GFP_ATOMIC);
if (!ph2c) {
res = _FAIL;
goto exit;
}
- paddbareq_parm = kzalloc(sizeof(struct addBaReq_parm), GFP_ATOMIC);
+ paddbareq_parm = kzalloc(sizeof(*paddbareq_parm), GFP_ATOMIC);
if (!paddbareq_parm) {
kfree(ph2c);
res = _FAIL;
@@ -677,13 +677,13 @@ u8 rtw_dynamic_chk_wk_cmd(struct adapter *padapter)
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
u8 res = _SUCCESS;
- ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+ ph2c = kzalloc(sizeof(*ph2c), GFP_ATOMIC);
if (!ph2c) {
res = _FAIL;
goto exit;
}
- pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC);
+ pdrvextra_cmd_parm = kzalloc(sizeof(*pdrvextra_cmd_parm), GFP_ATOMIC);
if (!pdrvextra_cmd_parm) {
kfree(ph2c);
res = _FAIL;
@@ -719,7 +719,7 @@ u8 rtw_set_chplan_cmd(struct adapter *padapter, u8 chplan, u8 enqueue)
}
/* prepare cmd parameter */
- setChannelPlan_param = kzalloc(sizeof(struct SetChannelPlan_param), GFP_KERNEL);
+ setChannelPlan_param = kzalloc(sizeof(*setChannelPlan_param), GFP_KERNEL);
if (!setChannelPlan_param) {
res = _FAIL;
goto exit;
@@ -728,7 +728,7 @@ u8 rtw_set_chplan_cmd(struct adapter *padapter, u8 chplan, u8 enqueue)
if (enqueue) {
/* need enqueue, prepare cmd_obj and enqueue */
- pcmdobj = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
+ pcmdobj = kzalloc(sizeof(*pcmdobj), GFP_KERNEL);
if (!pcmdobj) {
kfree(setChannelPlan_param);
res = _FAIL;
@@ -745,7 +745,6 @@ u8 rtw_set_chplan_cmd(struct adapter *padapter, u8 chplan, u8 enqueue)
kfree(setChannelPlan_param);
}
- /* do something based on res... */
if (res == _SUCCESS)
padapter->mlmepriv.ChannelPlan = chplan;
@@ -884,13 +883,13 @@ u8 rtw_lps_ctrl_wk_cmd(struct adapter *padapter, u8 lps_ctrl_type, u8 enqueue)
u8 res = _SUCCESS;
if (enqueue) {
- ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+ ph2c = kzalloc(sizeof(*ph2c), GFP_ATOMIC);
if (!ph2c) {
res = _FAIL;
goto exit;
}
- pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC);
+ pdrvextra_cmd_parm = kzalloc(sizeof(*pdrvextra_cmd_parm), GFP_ATOMIC);
if (!pdrvextra_cmd_parm) {
kfree(ph2c);
res = _FAIL;
@@ -926,13 +925,13 @@ u8 rtw_rpt_timer_cfg_cmd(struct adapter *padapter, u16 min_time)
u8 res = _SUCCESS;
- ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+ ph2c = kzalloc(sizeof(*ph2c), GFP_ATOMIC);
if (!ph2c) {
res = _FAIL;
goto exit;
}
- pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC);
+ pdrvextra_cmd_parm = kzalloc(sizeof(*pdrvextra_cmd_parm), GFP_ATOMIC);
if (!pdrvextra_cmd_parm) {
kfree(ph2c);
res = _FAIL;
@@ -967,13 +966,13 @@ u8 rtw_antenna_select_cmd(struct adapter *padapter, u8 antenna, u8 enqueue)
return res;
if (enqueue) {
- ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
+ ph2c = kzalloc(sizeof(*ph2c), GFP_KERNEL);
if (!ph2c) {
res = _FAIL;
goto exit;
}
- pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_KERNEL);
+ pdrvextra_cmd_parm = kzalloc(sizeof(*pdrvextra_cmd_parm), GFP_KERNEL);
if (!pdrvextra_cmd_parm) {
kfree(ph2c);
res = _FAIL;
@@ -1000,8 +999,8 @@ u8 rtw_ps_cmd(struct adapter *padapter)
struct drvextra_cmd_parm *pdrvextra_cmd_parm;
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
- ppscmd = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
- pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC);
+ ppscmd = kzalloc(sizeof(*ppscmd), GFP_ATOMIC);
+ pdrvextra_cmd_parm = kzalloc(sizeof(*pdrvextra_cmd_parm), GFP_ATOMIC);
if (!ppscmd || !pdrvextra_cmd_parm) {
kfree(ppscmd);
kfree(pdrvextra_cmd_parm);
@@ -1064,13 +1063,13 @@ u8 rtw_chk_hi_queue_cmd(struct adapter *padapter)
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
u8 res = _SUCCESS;
- ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
+ ph2c = kzalloc(sizeof(*ph2c), GFP_ATOMIC);
if (!ph2c) {
res = _FAIL;
goto exit;
}
- pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_KERNEL);
+ pdrvextra_cmd_parm = kzalloc(sizeof(*pdrvextra_cmd_parm), GFP_ATOMIC);
if (!pdrvextra_cmd_parm) {
kfree(ph2c);
res = _FAIL;
diff --git a/drivers/staging/rtl8188eu/core/rtw_debug.c b/drivers/staging/rtl8188eu/core/rtw_debug.c
index 67461fdf315c..6c2fe1a112ac 100644
--- a/drivers/staging/rtl8188eu/core/rtw_debug.c
+++ b/drivers/staging/rtl8188eu/core/rtw_debug.c
@@ -153,13 +153,11 @@ int proc_get_best_channel(char *page, char **start,
struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
int len = 0;
- u32 i, best_channel_24G = 1, best_channel_5G = 36, index_24G = 0, index_5G = 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;
- if (pmlmeext->channel_set[i].ChannelNum == 36)
- index_5G = i;
}
for (i = 0; pmlmeext->channel_set[i].ChannelNum != 0; i++) {
@@ -171,32 +169,11 @@ int proc_get_best_channel(char *page, char **start,
}
}
- /* 5G */
- if (pmlmeext->channel_set[i].ChannelNum >= 36 &&
- pmlmeext->channel_set[i].ChannelNum < 140) {
- /* Find primary channel */
- if (((pmlmeext->channel_set[i].ChannelNum - 36) % 8 == 0) &&
- (pmlmeext->channel_set[i].rx_count < pmlmeext->channel_set[index_5G].rx_count)) {
- index_5G = i;
- best_channel_5G = pmlmeext->channel_set[i].ChannelNum;
- }
- }
-
- if (pmlmeext->channel_set[i].ChannelNum >= 149 &&
- pmlmeext->channel_set[i].ChannelNum < 165) {
- /* find primary channel */
- if (((pmlmeext->channel_set[i].ChannelNum - 149) % 8 == 0) &&
- (pmlmeext->channel_set[i].rx_count < pmlmeext->channel_set[index_5G].rx_count)) {
- index_5G = i;
- best_channel_5G = pmlmeext->channel_set[i].ChannelNum;
- }
- }
/* debug */
len += snprintf(page + len, count - len, "The rx cnt of channel %3d = %d\n",
pmlmeext->channel_set[i].ChannelNum, pmlmeext->channel_set[i].rx_count);
}
- len += snprintf(page + len, count - len, "best_channel_5G = %d\n", best_channel_5G);
len += snprintf(page + len, count - len, "best_channel_24G = %d\n", best_channel_24G);
*eof = 1;
diff --git a/drivers/staging/rtl8188eu/core/rtw_efuse.c b/drivers/staging/rtl8188eu/core/rtw_efuse.c
index 0fd306a808c4..b7be71f904ed 100644
--- a/drivers/staging/rtl8188eu/core/rtw_efuse.c
+++ b/drivers/staging/rtl8188eu/core/rtw_efuse.c
@@ -22,13 +22,9 @@ enum{
};
/*
- * Function: efuse_power_switch
- *
- * Overview: When we want to enable write operation, we should change to
- * pwr on state. When we stop write, we should switch to 500k mode
- * and disable LDO 2.5V.
+ * When we want to enable write operation, we should change to pwr on state.
+ * When we stop write, we should switch to 500k mode and disable LDO 2.5V.
*/
-
void efuse_power_switch(struct adapter *pAdapter, u8 write, u8 pwrstate)
{
u8 tempval;
@@ -41,7 +37,7 @@ void efuse_power_switch(struct adapter *pAdapter, u8 write, u8 pwrstate)
tmpv16 = usb_read16(pAdapter, REG_SYS_ISO_CTRL);
if (!(tmpv16 & PWC_EV12V)) {
tmpv16 |= PWC_EV12V;
- usb_write16(pAdapter, REG_SYS_ISO_CTRL, tmpv16);
+ usb_write16(pAdapter, REG_SYS_ISO_CTRL, tmpv16);
}
/* Reset: 0x0000h[28], default valid */
tmpv16 = usb_read16(pAdapter, REG_SYS_FUNC_EN);
@@ -86,16 +82,20 @@ efuse_phymap_to_logical(u8 *phymap, u16 _offset, u16 _size_byte, u8 *pbuf)
u16 **eFuseWord = NULL;
u16 efuse_utilized = 0;
u8 u1temp = 0;
+ void **tmp = NULL;
efuseTbl = kzalloc(EFUSE_MAP_LEN_88E, GFP_KERNEL);
if (!efuseTbl)
return;
- eFuseWord = (u16 **)rtw_malloc2d(EFUSE_MAX_SECTION_88E, EFUSE_MAX_WORD_UNIT, sizeof(u16));
- if (!eFuseWord) {
+ tmp = kzalloc(EFUSE_MAX_SECTION_88E * (sizeof(void *) + EFUSE_MAX_WORD_UNIT * sizeof(u16)), GFP_KERNEL);
+ if (!tmp) {
DBG_88E("%s: alloc eFuseWord fail!\n", __func__);
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;
/* 0. Refresh efuse init map as all oxFF. */
for (i = 0; i < EFUSE_MAX_SECTION_88E; i++)
@@ -360,15 +360,13 @@ u8 Efuse_WordEnableDataWrite(struct adapter *pAdapter, u16 efuse_addr, u8 word_e
static u16 Efuse_GetCurrentSize(struct adapter *pAdapter)
{
- int bContinual = true;
u16 efuse_addr = 0;
u8 hoffset = 0, hworden = 0;
u8 efuse_data, word_cnts = 0;
rtw_hal_get_hwreg(pAdapter, HW_VAR_EFUSE_BYTES, (u8 *)&efuse_addr);
- while (bContinual &&
- efuse_OneByteRead(pAdapter, efuse_addr, &efuse_data) &&
+ while (efuse_OneByteRead(pAdapter, efuse_addr, &efuse_data) &&
AVAILABLE_EFUSE_ADDR(efuse_addr)) {
if (efuse_data != 0xFF) {
if ((efuse_data&0x1F) == 0x0F) { /* extended header */
@@ -390,7 +388,7 @@ static u16 Efuse_GetCurrentSize(struct adapter *pAdapter)
/* read next header */
efuse_addr = efuse_addr + (word_cnts*2)+1;
} else {
- bContinual = false;
+ break;
}
}
@@ -453,7 +451,7 @@ int Efuse_PgPacketRead(struct adapter *pAdapter, u8 offset, u8 *data)
bDataEmpty = false;
}
}
- if (bDataEmpty == false) {
+ if (!bDataEmpty) {
ReadState = PG_STATE_DATA;
} else {/* read next header */
efuse_addr = efuse_addr + (word_cnts*2)+1;
@@ -512,7 +510,7 @@ static bool hal_EfuseFixHeaderProcess(struct adapter *pAdapter, u8 efuseType, st
static bool hal_EfusePgPacketWrite2ByteHeader(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt)
{
- bool bRet = false;
+ bool ret = false;
u16 efuse_addr = *pAddr;
u16 efuse_max_available_len =
EFUSE_REAL_CONTENT_LEN_88E - EFUSE_OOB_PROTECT_BYTES_88E;
@@ -564,7 +562,7 @@ static bool hal_EfusePgPacketWrite2ByteHeader(struct adapter *pAdapter, u8 efuse
if (!hal_EfuseFixHeaderProcess(pAdapter, efuseType, &fixPkt, &efuse_addr))
return false;
} else {
- bRet = true;
+ ret = true;
break;
}
} else if ((tmp_header & 0x1F) == 0x0F) { /* wrong extended header */
@@ -574,12 +572,12 @@ static bool hal_EfusePgPacketWrite2ByteHeader(struct adapter *pAdapter, u8 efuse
}
*pAddr = efuse_addr;
- return bRet;
+ return ret;
}
static bool hal_EfusePgPacketWrite1ByteHeader(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt)
{
- bool bRet = false;
+ bool ret = false;
u8 pg_header = 0, tmp_header = 0;
u16 efuse_addr = *pAddr;
u8 repeatcnt = 0;
@@ -597,7 +595,7 @@ static bool hal_EfusePgPacketWrite1ByteHeader(struct adapter *pAdapter, u8 efuse
}
if (pg_header == tmp_header) {
- bRet = true;
+ ret = true;
} else {
struct pgpkt fixPkt;
@@ -609,7 +607,7 @@ static bool hal_EfusePgPacketWrite1ByteHeader(struct adapter *pAdapter, u8 efuse
}
*pAddr = efuse_addr;
- return bRet;
+ return ret;
}
static bool hal_EfusePgPacketWriteData(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt)
@@ -639,14 +637,14 @@ hal_EfusePgPacketWriteHeader(
u16 *pAddr,
struct pgpkt *pTargetPkt)
{
- bool bRet = false;
+ bool ret = false;
if (pTargetPkt->offset >= EFUSE_MAX_SECTION_BASE)
- bRet = hal_EfusePgPacketWrite2ByteHeader(pAdapter, efuseType, pAddr, pTargetPkt);
+ ret = hal_EfusePgPacketWrite2ByteHeader(pAdapter, efuseType, pAddr, pTargetPkt);
else
- bRet = hal_EfusePgPacketWrite1ByteHeader(pAdapter, efuseType, pAddr, pTargetPkt);
+ ret = hal_EfusePgPacketWrite1ByteHeader(pAdapter, efuseType, pAddr, pTargetPkt);
- return bRet;
+ return ret;
}
static bool wordEnMatched(struct pgpkt *pTargetPkt, struct pgpkt *pCurPkt,
@@ -678,19 +676,19 @@ static bool wordEnMatched(struct pgpkt *pTargetPkt, struct pgpkt *pCurPkt,
static bool hal_EfuseCheckIfDatafollowed(struct adapter *pAdapter, u8 word_cnts, u16 startAddr)
{
- bool bRet = false;
+ bool ret = false;
u8 i, efuse_data;
for (i = 0; i < (word_cnts*2); i++) {
if (efuse_OneByteRead(pAdapter, (startAddr+i), &efuse_data) && (efuse_data != 0xFF))
- bRet = true;
+ ret = true;
}
- return bRet;
+ return ret;
}
static bool hal_EfusePartialWriteCheck(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt)
{
- bool bRet = false;
+ bool ret = false;
u8 i, efuse_data = 0, cur_header = 0;
u8 matched_wden = 0, badworden = 0;
u16 startAddr = 0;
@@ -703,7 +701,7 @@ static bool hal_EfusePartialWriteCheck(struct adapter *pAdapter, u8 efuseType, u
while (1) {
if (startAddr >= efuse_max_available_len) {
- bRet = false;
+ ret = false;
break;
}
@@ -713,7 +711,7 @@ static bool hal_EfusePartialWriteCheck(struct adapter *pAdapter, u8 efuseType, u
startAddr++;
efuse_OneByteRead(pAdapter, startAddr, &efuse_data);
if (ALL_WORDS_DISABLED(efuse_data)) {
- bRet = false;
+ ret = false;
break;
} else {
curPkt.offset = ((cur_header & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1);
@@ -740,7 +738,7 @@ static bool hal_EfusePartialWriteCheck(struct adapter *pAdapter, u8 efuseType, u
PgWriteSuccess = Efuse_PgPacketWrite(pAdapter, pTargetPkt->offset, badworden, pTargetPkt->data);
if (!PgWriteSuccess) {
- bRet = false; /* write fail, return */
+ ret = false; /* write fail, return */
break;
}
}
@@ -756,11 +754,11 @@ static bool hal_EfusePartialWriteCheck(struct adapter *pAdapter, u8 efuseType, u
} else {
/* not used header, 0xff */
*pAddr = startAddr;
- bRet = true;
+ ret = true;
break;
}
}
- return bRet;
+ return ret;
}
static bool
@@ -868,9 +866,7 @@ u8 efuse_OneByteWrite(struct adapter *pAdapter, u16 addr, u8 data)
return result;
}
-/*
- * Overview: Read allowed word in current efuse section data.
- */
+/* Read allowed word in current efuse section data. */
void efuse_WordEnableDataRead(u8 word_en, u8 *sourdata, u8 *targetdata)
{
if (!(word_en & BIT(0))) {
@@ -891,9 +887,7 @@ void efuse_WordEnableDataRead(u8 word_en, u8 *sourdata, u8 *targetdata)
}
}
-/*
- * Overview: Read All Efuse content
- */
+/* Read All Efuse content */
static void Efuse_ReadAllMap(struct adapter *pAdapter, u8 efuseType, u8 *Efuse)
{
efuse_power_switch(pAdapter, false, true);
@@ -903,12 +897,8 @@ static void Efuse_ReadAllMap(struct adapter *pAdapter, u8 efuseType, u8 *Efuse)
efuse_power_switch(pAdapter, false, false);
}
-/*
- * Overview: Transfer current EFUSE content to shadow init and modify map.
- */
-void EFUSE_ShadowMapUpdate(
- struct adapter *pAdapter,
- u8 efuseType)
+/* Transfer current EFUSE content to shadow init and modify map. */
+void EFUSE_ShadowMapUpdate(struct adapter *pAdapter, u8 efuseType)
{
struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter);
diff --git a/drivers/staging/rtl8188eu/core/rtw_ieee80211.c b/drivers/staging/rtl8188eu/core/rtw_ieee80211.c
index 7d5cbaf50f1c..5c4ff81987bd 100644
--- a/drivers/staging/rtl8188eu/core/rtw_ieee80211.c
+++ b/drivers/staging/rtl8188eu/core/rtw_ieee80211.c
@@ -100,19 +100,13 @@ 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;
- } else { /* could be pure B, pure G, or B/G */
- if (rtw_is_cckratesonly_included(rate))
- return WIRELESS_11B;
- else if (rtw_is_cckrates_included(rate))
- return WIRELESS_11BG;
- else
- return WIRELESS_11G;
- }
+ /* could be pure B, pure G, or B/G */
+ if (rtw_is_cckratesonly_included(rate))
+ return WIRELESS_11B;
+ else if (rtw_is_cckrates_included(rate))
+ return WIRELESS_11BG;
+ else
+ return WIRELESS_11G;
}
u8 *rtw_set_fixed_ie(void *pbuf, unsigned int len, void *source,
@@ -252,7 +246,7 @@ int rtw_generate_ie(struct registry_priv *pregistrypriv)
wireless_mode = pregistrypriv->wireless_mode;
}
- rtw_set_supported_rate(pdev_network->SupportedRates, wireless_mode);
+ rtw_set_supported_rate(pdev_network->SupportedRates, wireless_mode);
rateLen = rtw_get_rateset_len(pdev_network->SupportedRates);
@@ -290,7 +284,7 @@ unsigned char *rtw_get_wpa_ie(unsigned char *pie, uint *wpa_ie_len, int limit)
if (pbuf) {
/* check if oui matches... */
- if (!memcmp((pbuf + 2), wpa_oui_type, sizeof(wpa_oui_type)) == false)
+ if (memcmp((pbuf + 2), wpa_oui_type, sizeof(wpa_oui_type)))
goto check_next_ie;
/* check version... */
diff --git a/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c b/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c
index c040f185074b..0b3eb0b40975 100644
--- a/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c
+++ b/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c
@@ -17,11 +17,11 @@ u8 rtw_do_join(struct adapter *padapter)
{
struct list_head *plist, *phead;
u8 *pibss = NULL;
- struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
- struct __queue *queue = &(pmlmepriv->scanned_queue);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct __queue *queue = &pmlmepriv->scanned_queue;
u8 ret = _SUCCESS;
- spin_lock_bh(&(pmlmepriv->scanned_queue.lock));
+ spin_lock_bh(&pmlmepriv->scanned_queue.lock);
phead = get_list_head(queue);
plist = phead->next;
@@ -36,7 +36,7 @@ u8 rtw_do_join(struct adapter *padapter)
pmlmepriv->to_join = true;
if (list_empty(&queue->queue)) {
- spin_unlock_bh(&(pmlmepriv->scanned_queue.lock));
+ spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
/* when set_ssid/set_bssid for rtw_do_join(), but scanning queue is empty */
@@ -60,18 +60,18 @@ u8 rtw_do_join(struct adapter *padapter)
} else {
int select_ret;
- spin_unlock_bh(&(pmlmepriv->scanned_queue.lock));
+ spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
select_ret = rtw_select_and_join_from_scanned_queue(pmlmepriv);
if (select_ret == _SUCCESS) {
pmlmepriv->to_join = false;
mod_timer(&pmlmepriv->assoc_timer,
jiffies + msecs_to_jiffies(MAX_JOIN_TIMEOUT));
} else {
- if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) {
+ if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) {
/* submit createbss_cmd to change to a ADHOC_MASTER */
/* pmlmepriv->lock has been acquired by caller... */
- struct wlan_bssid_ex *pdev_network = &(padapter->registrypriv.dev_network);
+ struct wlan_bssid_ex *pdev_network = &padapter->registrypriv.dev_network;
pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE;
@@ -136,16 +136,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) == true)
+ 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)) {
+ 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) == false)
+ 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"));
@@ -154,12 +154,12 @@ u8 rtw_set_802_11_bssid(struct adapter *padapter, u8 *bssid)
rtw_disassoc_cmd(padapter, 0, true);
- if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
+ if (check_fwstate(pmlmepriv, _FW_LINKED))
rtw_indicate_disconnect(padapter);
rtw_free_assoc_resources(padapter);
- if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) {
+ if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) {
_clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE);
set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
}
@@ -172,7 +172,7 @@ handle_tkip_countermeasure:
if (padapter->securitypriv.btkip_countermeasure) {
cur_time = jiffies;
- if ((cur_time - padapter->securitypriv.btkip_countermeasure_time) > 60 * HZ) {
+ if (cur_time - padapter->securitypriv.btkip_countermeasure_time > 60 * HZ) {
padapter->securitypriv.btkip_countermeasure = false;
padapter->securitypriv.btkip_countermeasure_time = 0;
} else {
@@ -220,18 +220,18 @@ u8 rtw_set_802_11_ssid(struct adapter *padapter, struct ndis_802_11_ssid *ssid)
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) == true)
+ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY))
goto handle_tkip_countermeasure;
- else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true)
+ else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING))
goto release_mlme_lock;
- if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE)) {
+ 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.SsidLength == ssid->SsidLength) &&
- (!memcmp(&pmlmepriv->assoc_ssid.Ssid, ssid->Ssid, ssid->SsidLength))) {
- if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == false)) {
+ if (pmlmepriv->assoc_ssid.SsidLength == ssid->SsidLength &&
+ !memcmp(&pmlmepriv->assoc_ssid.Ssid, ssid->Ssid, ssid->SsidLength)) {
+ 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)));
@@ -240,12 +240,12 @@ u8 rtw_set_802_11_ssid(struct adapter *padapter, struct ndis_802_11_ssid *ssid)
/* if in WIFI_ADHOC_MASTER_STATE | WIFI_ADHOC_STATE, create bss or rejoin again */
rtw_disassoc_cmd(padapter, 0, true);
- if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
+ if (check_fwstate(pmlmepriv, _FW_LINKED))
rtw_indicate_disconnect(padapter);
rtw_free_assoc_resources(padapter);
- if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) {
+ if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) {
_clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE);
set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
}
@@ -262,12 +262,12 @@ u8 rtw_set_802_11_ssid(struct adapter *padapter, struct ndis_802_11_ssid *ssid)
rtw_disassoc_cmd(padapter, 0, true);
- if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
+ if (check_fwstate(pmlmepriv, _FW_LINKED))
rtw_indicate_disconnect(padapter);
rtw_free_assoc_resources(padapter);
- if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) {
+ if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) {
_clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE);
set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
}
@@ -279,7 +279,7 @@ handle_tkip_countermeasure:
if (padapter->securitypriv.btkip_countermeasure) {
cur_time = jiffies;
- if ((cur_time - padapter->securitypriv.btkip_countermeasure_time) > 60 * HZ) {
+ if (cur_time - padapter->securitypriv.btkip_countermeasure_time > 60 * HZ) {
padapter->securitypriv.btkip_countermeasure = false;
padapter->securitypriv.btkip_countermeasure_time = 0;
} else {
@@ -291,7 +291,7 @@ handle_tkip_countermeasure:
memcpy(&pmlmepriv->assoc_ssid, ssid, sizeof(struct ndis_802_11_ssid));
pmlmepriv->assoc_by_bssid = false;
- if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true)
+ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY))
pmlmepriv->to_join = true;
else
status = rtw_do_join(padapter);
@@ -308,9 +308,9 @@ exit:
u8 rtw_set_802_11_infrastructure_mode(struct adapter *padapter,
enum ndis_802_11_network_infra networktype)
{
- struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
- struct wlan_network *cur_network = &pmlmepriv->cur_network;
- enum ndis_802_11_network_infra *pold_state = &(cur_network->network.InfrastructureMode);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ 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_,
("+rtw_set_802_11_infrastructure_mode: old =%d new =%d fw_state = 0x%08x\n",
@@ -331,16 +331,17 @@ u8 rtw_set_802_11_infrastructure_mode(struct adapter *padapter,
#endif
}
- if ((check_fwstate(pmlmepriv, _FW_LINKED)) ||
- (*pold_state == Ndis802_11IBSS))
+ if (check_fwstate(pmlmepriv, _FW_LINKED) ||
+ *pold_state == Ndis802_11IBSS)
rtw_disassoc_cmd(padapter, 0, true);
- if ((check_fwstate(pmlmepriv, _FW_LINKED)) ||
- (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)))
+ if (check_fwstate(pmlmepriv, _FW_LINKED) ||
+ check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE))
rtw_free_assoc_resources(padapter);
- if ((*pold_state == Ndis802_11Infrastructure) || (*pold_state == Ndis802_11IBSS)) {
- if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
+ if (*pold_state == Ndis802_11Infrastructure ||
+ *pold_state == Ndis802_11IBSS) {
+ if (check_fwstate(pmlmepriv, _FW_LINKED))
rtw_indicate_disconnect(padapter); /* will clr Linked_state; before this function, we must have checked whether issue dis-assoc_cmd or not */
}
@@ -394,8 +395,8 @@ u8 rtw_set_802_11_disassociate(struct adapter *padapter)
u8 rtw_set_802_11_bssid_list_scan(struct adapter *padapter, struct ndis_802_11_ssid *pssid, int ssid_max_num)
{
- struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
- u8 res = true;
+ 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)));
@@ -409,14 +410,14 @@ u8 rtw_set_802_11_bssid_list_scan(struct adapter *padapter, struct ndis_802_11_s
goto exit;
}
- if ((check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING)) ||
- (pmlmepriv->LinkDetectInfo.bBusyTraffic)) {
+ 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)) == true)
+ _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"));
@@ -444,7 +445,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));
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
+ ("set_802_11_auth.mode(): mode =%x\n", authmode));
psecuritypriv->ndisauthtype = authmode;
@@ -467,9 +469,9 @@ u8 rtw_set_802_11_authentication_mode(struct adapter *padapter, enum ndis_802_11
u8 rtw_set_802_11_add_wep(struct adapter *padapter, struct ndis_802_11_wep *wep)
{
- int keyid, res;
- struct security_priv *psecuritypriv = &(padapter->securitypriv);
- u8 ret = _SUCCESS;
+ int keyid, res;
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+ u8 ret = _SUCCESS;
keyid = wep->KeyIndex & 0x3fffffff;
@@ -497,7 +499,8 @@ u8 rtw_set_802_11_add_wep(struct adapter *padapter, struct ndis_802_11_wep *wep)
("rtw_set_802_11_add_wep:before memcpy, wep->KeyLength = 0x%x wep->KeyIndex = 0x%x keyid =%x\n",
wep->KeyLength, wep->KeyIndex, keyid));
- memcpy(&(psecuritypriv->dot11DefKey[keyid].skey[0]), &(wep->KeyMaterial), wep->KeyLength);
+ memcpy(&psecuritypriv->dot11DefKey[keyid].skey[0],
+ &wep->KeyMaterial, wep->KeyLength);
psecuritypriv->dot11DefKeylen[keyid] = wep->KeyLength;
@@ -527,31 +530,27 @@ exit:
return ret;
}
-/*
-* rtw_get_cur_max_rate -
-* @adapter: pointer to struct adapter structure
-*
-* Return 0 or 100Kbps
-*/
+/* Return 0 or 100Kbps */
u16 rtw_get_cur_max_rate(struct adapter *adapter)
{
- int i = 0;
- u8 *p;
- u16 rate = 0, max_rate = 0;
- struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
- struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ int i = 0;
+ u8 *p;
+ u16 rate = 0, max_rate = 0;
+ struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
struct registry_priv *pregistrypriv = &adapter->registrypriv;
- struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
- struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network;
- u8 bw_40MHz = 0, short_GI_20 = 0, short_GI_40 = 0;
- u32 ht_ielen = 0;
+ struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+ struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network;
+ u8 bw_40MHz = 0, short_GI_20 = 0, short_GI_40 = 0;
+ u32 ht_ielen = 0;
- if ((!check_fwstate(pmlmepriv, _FW_LINKED)) &&
- (!check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)))
+ if (!check_fwstate(pmlmepriv, _FW_LINKED) &&
+ !check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE))
return 0;
- if (pmlmeext->cur_wireless_mode & (WIRELESS_11_24N|WIRELESS_11_5N)) {
- p = rtw_get_ie(&pcur_bss->ies[12], _HT_CAPABILITY_IE_, &ht_ielen, pcur_bss->ie_length-12);
+ if (pmlmeext->cur_wireless_mode & (WIRELESS_11_24N | WIRELESS_11_5N)) {
+ p = rtw_get_ie(&pcur_bss->ies[12], _HT_CAPABILITY_IE_,
+ &ht_ielen, pcur_bss->ie_length - 12);
if (p && ht_ielen > 0) {
/* cur_bwmod is updated by beacon, pmlmeinfo is updated by association response */
bw_40MHz = (pmlmeext->cur_bwmode && (HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH & pmlmeinfo->HT_info.infos[0])) ? 1 : 0;
@@ -561,33 +560,28 @@ u16 rtw_get_cur_max_rate(struct adapter *adapter)
max_rate = rtw_mcs_rate(
RF_1T1R,
- bw_40MHz & (pregistrypriv->cbw40_enable),
+ bw_40MHz & pregistrypriv->cbw40_enable,
short_GI_20,
short_GI_40,
pmlmeinfo->HT_caps.mcs.rx_mask
);
}
} else {
- while ((pcur_bss->SupportedRates[i] != 0) && (pcur_bss->SupportedRates[i] != 0xFF)) {
- rate = pcur_bss->SupportedRates[i]&0x7F;
+ while (pcur_bss->SupportedRates[i] != 0 &&
+ pcur_bss->SupportedRates[i] != 0xFF) {
+ rate = pcur_bss->SupportedRates[i] & 0x7F;
if (rate > max_rate)
max_rate = rate;
i++;
}
- max_rate = max_rate*10/2;
+ max_rate *= 5;
}
return max_rate;
}
-/*
-* rtw_set_country -
-* @adapter: pointer to struct adapter structure
-* @country_code: string of country code
-*
-* Return _SUCCESS or _FAIL
-*/
+/* Return _SUCCESS or _FAIL */
int rtw_set_country(struct adapter *adapter, const char *country_code)
{
int i;
diff --git a/drivers/staging/rtl8188eu/core/rtw_led.c b/drivers/staging/rtl8188eu/core/rtw_led.c
index cbef871a7679..a2e7789aecbd 100644
--- a/drivers/staging/rtl8188eu/core/rtw_led.c
+++ b/drivers/staging/rtl8188eu/core/rtw_led.c
@@ -18,7 +18,7 @@ static void BlinkTimerCallback(struct timer_list *t)
struct LED_871x *pLed = from_timer(pLed, t, BlinkTimer);
struct adapter *padapter = pLed->padapter;
- if ((padapter->bSurpriseRemoved) || (padapter->bDriverStopped))
+ if (padapter->bSurpriseRemoved || padapter->bDriverStopped)
return;
schedule_work(&pLed->BlinkWorkItem);
@@ -95,10 +95,12 @@ static void SwLedBlink1(struct LED_871x *pLed)
/* Change LED according to BlinkingLedState specified. */
if (pLed->BlinkingLedState == RTW_LED_ON) {
SwLedOn(padapter, pLed);
- RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes));
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_,
+ ("Blinktimes (%d): turn on\n", pLed->BlinkTimes));
} else {
SwLedOff(padapter, pLed);
- RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes));
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_,
+ ("Blinktimes (%d): turn off\n", pLed->BlinkTimes));
}
if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
@@ -245,131 +247,134 @@ static void SwLedControlMode1(struct adapter *padapter, enum LED_CTL_MODE LedAct
case LED_CTL_POWER_ON:
case LED_CTL_START_TO_LINK:
case LED_CTL_NO_LINK:
- if (!pLed->bLedNoLinkBlinkInProgress) {
- if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed))
- return;
- if (pLed->bLedLinkBlinkInProgress) {
- del_timer_sync(&pLed->BlinkTimer);
- pLed->bLedLinkBlinkInProgress = false;
- }
- if (pLed->bLedBlinkInProgress) {
- del_timer_sync(&pLed->BlinkTimer);
- pLed->bLedBlinkInProgress = false;
- }
-
- pLed->bLedNoLinkBlinkInProgress = true;
- pLed->CurrLedState = LED_BLINK_SLOWLY;
- if (pLed->bLedOn)
- 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));
+ if (pLed->bLedNoLinkBlinkInProgress)
+ break;
+ if (pLed->CurrLedState == LED_BLINK_SCAN ||
+ IS_LED_WPS_BLINKING(pLed))
+ return;
+ if (pLed->bLedLinkBlinkInProgress) {
+ del_timer_sync(&pLed->BlinkTimer);
+ pLed->bLedLinkBlinkInProgress = false;
+ }
+ if (pLed->bLedBlinkInProgress) {
+ del_timer_sync(&pLed->BlinkTimer);
+ pLed->bLedBlinkInProgress = false;
}
+ pLed->bLedNoLinkBlinkInProgress = true;
+ pLed->CurrLedState = LED_BLINK_SLOWLY;
+ if (pLed->bLedOn)
+ 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));
break;
case LED_CTL_LINK:
- if (!pLed->bLedLinkBlinkInProgress) {
- if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed))
- return;
- if (pLed->bLedNoLinkBlinkInProgress) {
- del_timer_sync(&pLed->BlinkTimer);
- pLed->bLedNoLinkBlinkInProgress = false;
- }
- if (pLed->bLedBlinkInProgress) {
- del_timer_sync(&pLed->BlinkTimer);
- pLed->bLedBlinkInProgress = false;
- }
- pLed->bLedLinkBlinkInProgress = true;
- pLed->CurrLedState = LED_BLINK_NORMAL;
- if (pLed->bLedOn)
- pLed->BlinkingLedState = RTW_LED_OFF;
- else
- pLed->BlinkingLedState = RTW_LED_ON;
- mod_timer(&pLed->BlinkTimer, jiffies +
- msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA));
+ if (pLed->bLedLinkBlinkInProgress)
+ break;
+ if (pLed->CurrLedState == LED_BLINK_SCAN ||
+ IS_LED_WPS_BLINKING(pLed))
+ return;
+ if (pLed->bLedNoLinkBlinkInProgress) {
+ del_timer_sync(&pLed->BlinkTimer);
+ pLed->bLedNoLinkBlinkInProgress = false;
+ }
+ if (pLed->bLedBlinkInProgress) {
+ del_timer_sync(&pLed->BlinkTimer);
+ pLed->bLedBlinkInProgress = false;
}
+ pLed->bLedLinkBlinkInProgress = true;
+ pLed->CurrLedState = LED_BLINK_NORMAL;
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ mod_timer(&pLed->BlinkTimer, jiffies +
+ msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA));
break;
case LED_CTL_SITE_SURVEY:
- if ((pmlmepriv->LinkDetectInfo.bBusyTraffic) && (check_fwstate(pmlmepriv, _FW_LINKED))) {
- ;
- } else if (!pLed->bLedScanBlinkInProgress) {
- if (IS_LED_WPS_BLINKING(pLed))
- return;
- if (pLed->bLedNoLinkBlinkInProgress) {
- del_timer_sync(&pLed->BlinkTimer);
- pLed->bLedNoLinkBlinkInProgress = false;
- }
- if (pLed->bLedLinkBlinkInProgress) {
- del_timer_sync(&pLed->BlinkTimer);
- pLed->bLedLinkBlinkInProgress = false;
- }
- if (pLed->bLedBlinkInProgress) {
- del_timer_sync(&pLed->BlinkTimer);
- pLed->bLedBlinkInProgress = false;
- }
- pLed->bLedScanBlinkInProgress = true;
- pLed->CurrLedState = LED_BLINK_SCAN;
- pLed->BlinkTimes = 24;
- if (pLed->bLedOn)
- pLed->BlinkingLedState = RTW_LED_OFF;
- else
- pLed->BlinkingLedState = RTW_LED_ON;
- mod_timer(&pLed->BlinkTimer, jiffies +
- msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA));
+ if (pmlmepriv->LinkDetectInfo.bBusyTraffic &&
+ check_fwstate(pmlmepriv, _FW_LINKED))
+ break;
+ if (pLed->bLedScanBlinkInProgress)
+ break;
+ if (IS_LED_WPS_BLINKING(pLed))
+ return;
+ if (pLed->bLedNoLinkBlinkInProgress) {
+ del_timer_sync(&pLed->BlinkTimer);
+ pLed->bLedNoLinkBlinkInProgress = false;
+ }
+ if (pLed->bLedLinkBlinkInProgress) {
+ del_timer_sync(&pLed->BlinkTimer);
+ pLed->bLedLinkBlinkInProgress = false;
+ }
+ if (pLed->bLedBlinkInProgress) {
+ del_timer_sync(&pLed->BlinkTimer);
+ pLed->bLedBlinkInProgress = false;
}
+ pLed->bLedScanBlinkInProgress = true;
+ pLed->CurrLedState = LED_BLINK_SCAN;
+ pLed->BlinkTimes = 24;
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ mod_timer(&pLed->BlinkTimer, jiffies +
+ msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA));
break;
case LED_CTL_TX:
case LED_CTL_RX:
- if (!pLed->bLedBlinkInProgress) {
- if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed))
- return;
- if (pLed->bLedNoLinkBlinkInProgress) {
- del_timer_sync(&pLed->BlinkTimer);
- pLed->bLedNoLinkBlinkInProgress = false;
- }
- if (pLed->bLedLinkBlinkInProgress) {
- del_timer_sync(&pLed->BlinkTimer);
- pLed->bLedLinkBlinkInProgress = false;
- }
- pLed->bLedBlinkInProgress = true;
- pLed->CurrLedState = LED_BLINK_TXRX;
- pLed->BlinkTimes = 2;
- if (pLed->bLedOn)
- pLed->BlinkingLedState = RTW_LED_OFF;
- else
- pLed->BlinkingLedState = RTW_LED_ON;
- mod_timer(&pLed->BlinkTimer, jiffies +
- msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA));
+ if (pLed->bLedBlinkInProgress)
+ break;
+ if (pLed->CurrLedState == LED_BLINK_SCAN ||
+ IS_LED_WPS_BLINKING(pLed))
+ return;
+ if (pLed->bLedNoLinkBlinkInProgress) {
+ del_timer_sync(&pLed->BlinkTimer);
+ pLed->bLedNoLinkBlinkInProgress = false;
+ }
+ if (pLed->bLedLinkBlinkInProgress) {
+ del_timer_sync(&pLed->BlinkTimer);
+ pLed->bLedLinkBlinkInProgress = false;
}
+ pLed->bLedBlinkInProgress = true;
+ pLed->CurrLedState = LED_BLINK_TXRX;
+ pLed->BlinkTimes = 2;
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ mod_timer(&pLed->BlinkTimer, jiffies +
+ msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA));
break;
case LED_CTL_START_WPS: /* wait until xinpin finish */
case LED_CTL_START_WPS_BOTTON:
- if (!pLed->bLedWPSBlinkInProgress) {
- if (pLed->bLedNoLinkBlinkInProgress) {
- del_timer_sync(&pLed->BlinkTimer);
- pLed->bLedNoLinkBlinkInProgress = false;
- }
- if (pLed->bLedLinkBlinkInProgress) {
- del_timer_sync(&pLed->BlinkTimer);
- pLed->bLedLinkBlinkInProgress = false;
- }
- if (pLed->bLedBlinkInProgress) {
- del_timer_sync(&pLed->BlinkTimer);
- pLed->bLedBlinkInProgress = false;
- }
- if (pLed->bLedScanBlinkInProgress) {
- del_timer_sync(&pLed->BlinkTimer);
- pLed->bLedScanBlinkInProgress = false;
- }
- pLed->bLedWPSBlinkInProgress = true;
- pLed->CurrLedState = LED_BLINK_WPS;
- if (pLed->bLedOn)
- pLed->BlinkingLedState = RTW_LED_OFF;
- else
- pLed->BlinkingLedState = RTW_LED_ON;
- mod_timer(&pLed->BlinkTimer, jiffies +
- msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA));
+ if (pLed->bLedWPSBlinkInProgress)
+ break;
+ if (pLed->bLedNoLinkBlinkInProgress) {
+ del_timer_sync(&pLed->BlinkTimer);
+ pLed->bLedNoLinkBlinkInProgress = false;
+ }
+ if (pLed->bLedLinkBlinkInProgress) {
+ del_timer_sync(&pLed->BlinkTimer);
+ pLed->bLedLinkBlinkInProgress = false;
}
+ if (pLed->bLedBlinkInProgress) {
+ del_timer_sync(&pLed->BlinkTimer);
+ pLed->bLedBlinkInProgress = false;
+ }
+ if (pLed->bLedScanBlinkInProgress) {
+ del_timer_sync(&pLed->BlinkTimer);
+ pLed->bLedScanBlinkInProgress = false;
+ }
+ pLed->bLedWPSBlinkInProgress = true;
+ pLed->CurrLedState = LED_BLINK_WPS;
+ if (pLed->bLedOn)
+ pLed->BlinkingLedState = RTW_LED_OFF;
+ else
+ pLed->BlinkingLedState = RTW_LED_ON;
+ mod_timer(&pLed->BlinkTimer, jiffies +
+ msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA));
break;
case LED_CTL_STOP_WPS:
if (pLed->bLedNoLinkBlinkInProgress) {
@@ -378,7 +383,7 @@ static void SwLedControlMode1(struct adapter *padapter, enum LED_CTL_MODE LedAct
}
if (pLed->bLedLinkBlinkInProgress) {
del_timer_sync(&pLed->BlinkTimer);
- pLed->bLedLinkBlinkInProgress = false;
+ pLed->bLedLinkBlinkInProgress = false;
}
if (pLed->bLedBlinkInProgress) {
del_timer_sync(&pLed->BlinkTimer);
@@ -446,7 +451,8 @@ static void SwLedControlMode1(struct adapter *padapter, enum LED_CTL_MODE LedAct
break;
}
- RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Led %d\n", pLed->CurrLedState));
+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_,
+ ("Led %d\n", pLed->CurrLedState));
}
/* */
@@ -457,7 +463,7 @@ void BlinkHandler(struct LED_871x *pLed)
{
struct adapter *padapter = pLed->padapter;
- if ((padapter->bSurpriseRemoved) || (padapter->bDriverStopped))
+ if (padapter->bSurpriseRemoved || padapter->bDriverStopped)
return;
SwLedBlink1(pLed);
@@ -465,8 +471,8 @@ void BlinkHandler(struct LED_871x *pLed)
void LedControl8188eu(struct adapter *padapter, enum LED_CTL_MODE LedAction)
{
- if ((padapter->bSurpriseRemoved) || (padapter->bDriverStopped) ||
- (!padapter->hw_init_completed))
+ if (padapter->bSurpriseRemoved || padapter->bDriverStopped ||
+ !padapter->hw_init_completed)
return;
if ((padapter->pwrctrlpriv.rf_pwrstate != rf_on &&
diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme.c b/drivers/staging/rtl8188eu/core/rtw_mlme.c
index eca06f05c0c4..b9bd864f323c 100644
--- a/drivers/staging/rtl8188eu/core/rtw_mlme.c
+++ b/drivers/staging/rtl8188eu/core/rtw_mlme.c
@@ -20,7 +20,7 @@
#include <rtw_ioctl_set.h>
#include <linux/vmalloc.h>
-extern unsigned char MCS_rate_1R[16];
+extern const u8 MCS_rate_1R[16];
int rtw_init_mlme_priv(struct adapter *padapter)
{
@@ -228,7 +228,7 @@ int rtw_if_up(struct adapter *padapter)
int res;
if (padapter->bDriverStopped || padapter->bSurpriseRemoved ||
- (check_fwstate(&padapter->mlmepriv, _FW_LINKED) == false)) {
+ !check_fwstate(&padapter->mlmepriv, _FW_LINKED)) {
RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
("rtw_if_up:bDriverStopped(%d) OR bSurpriseRemoved(%d)",
padapter->bDriverStopped, padapter->bSurpriseRemoved));
@@ -305,7 +305,7 @@ static int is_same_ess(struct wlan_bssid_ex *a, struct wlan_bssid_ex *b)
int is_same_network(struct wlan_bssid_ex *src, struct wlan_bssid_ex *dst)
{
- u16 s_cap, d_cap;
+ u16 s_cap, d_cap;
__le16 le_scap, le_dcap;
memcpy((u8 *)&le_scap, rtw_get_capability_from_ie(src->ies), 2);
@@ -540,7 +540,7 @@ static int rtw_is_desired_network(struct adapter *adapter, struct wlan_network *
/* 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_evet\n"));
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("receive atimdone_event\n"));
}
void rtw_survey_event_callback(struct adapter *adapter, u8 *pbuf)
@@ -578,7 +578,7 @@ void rtw_survey_event_callback(struct adapter *adapter, u8 *pbuf)
}
/* lock pmlmepriv->lock when you accessing network_q */
- if ((check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) == false) {
+ if (!check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) {
if (pnetwork->Ssid.Ssid[0] == 0)
pnetwork->Ssid.SsidLength = 0;
rtw_add_network(adapter, pnetwork);
@@ -615,7 +615,7 @@ void rtw_surveydone_event_callback(struct adapter *adapter, u8 *pbuf)
if (pmlmepriv->to_join) {
if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true)) {
- if (check_fwstate(pmlmepriv, _FW_LINKED) == false) {
+ if (!check_fwstate(pmlmepriv, _FW_LINKED)) {
set_fwstate(pmlmepriv, _FW_UNDER_LINKING);
if (rtw_select_and_join_from_scanned_queue(pmlmepriv) == _SUCCESS) {
@@ -828,29 +828,6 @@ inline void rtw_indicate_scan_done(struct adapter *padapter, bool aborted)
rtw_os_indicate_scan_done(padapter, aborted);
}
-void rtw_scan_abort(struct adapter *adapter)
-{
- unsigned long start;
- struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
- struct mlme_ext_priv *pmlmeext = &(adapter->mlmeextpriv);
-
- start = jiffies;
- pmlmeext->scan_abort = true;
- while (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) &&
- jiffies_to_msecs(jiffies - start) <= 200) {
- if (adapter->bDriverStopped || adapter->bSurpriseRemoved)
- break;
- DBG_88E(FUNC_NDEV_FMT"fw_state=_FW_UNDER_SURVEY!\n", FUNC_NDEV_ARG(adapter->pnetdev));
- msleep(20);
- }
- if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) {
- if (!adapter->bDriverStopped && !adapter->bSurpriseRemoved)
- DBG_88E(FUNC_NDEV_FMT"waiting for scan_abort time out!\n", FUNC_NDEV_ARG(adapter->pnetdev));
- rtw_indicate_scan_done(adapter, true);
- }
- pmlmeext->scan_abort = false;
-}
-
static struct sta_info *rtw_joinbss_update_stainfo(struct adapter *padapter, struct wlan_network *pnetwork)
{
int i;
@@ -865,7 +842,7 @@ static struct sta_info *rtw_joinbss_update_stainfo(struct adapter *padapter, str
if (psta) { /* update ptarget_sta */
DBG_88E("%s\n", __func__);
psta->aid = pnetwork->join_res;
- psta->mac_id = 0;
+ psta->mac_id = 0;
/* sta mode */
rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, true);
/* security related */
@@ -1061,12 +1038,12 @@ void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf)
}
/* s4. indicate connect */
- if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) {
- 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)));
- }
+ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) {
+ 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);
@@ -1161,7 +1138,7 @@ void rtw_stassoc_event_callback(struct adapter *adapter, u8 *pbuf)
struct wlan_network *cur_network = &(pmlmepriv->cur_network);
struct wlan_network *ptarget_wlan = NULL;
- if (rtw_access_ctrl(adapter, pstassoc->macaddr) == false)
+ if (!rtw_access_ctrl(adapter, pstassoc->macaddr))
return;
#if defined(CONFIG_88EU_AP_MODE)
@@ -1437,17 +1414,17 @@ static int rtw_check_join_candidate(struct mlme_priv *pmlmepriv
/* check ssid, if needed */
if (pmlmepriv->assoc_ssid.SsidLength) {
if (competitor->network.Ssid.SsidLength != pmlmepriv->assoc_ssid.SsidLength ||
- !memcmp(competitor->network.Ssid.Ssid, pmlmepriv->assoc_ssid.Ssid, pmlmepriv->assoc_ssid.SsidLength) == false)
+ memcmp(competitor->network.Ssid.Ssid, pmlmepriv->assoc_ssid.Ssid, pmlmepriv->assoc_ssid.SsidLength))
goto exit;
}
- if (rtw_is_desired_network(adapter, competitor) == false)
+ if (!rtw_is_desired_network(adapter, competitor))
goto exit;
if (pmlmepriv->to_roaming) {
since_scan = jiffies - competitor->last_scanned;
if (jiffies_to_msecs(since_scan) >= RTW_SCAN_RESULT_EXPIRE ||
- is_same_ess(&competitor->network, &pmlmepriv->cur_network.network) == false)
+ !is_same_ess(&competitor->network, &pmlmepriv->cur_network.network))
goto exit;
}
@@ -1819,18 +1796,8 @@ 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 */
+ pdev_network->NetworkTypeInUse = Ndis802_11OFDM24;
break;
}
diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c
index 1115050077e4..6790b840aef8 100644
--- a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c
+++ b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c
@@ -39,7 +39,10 @@ extern unsigned char REALTEK_96B_IE[];
/********************************************************
MCS rate definitions
*********************************************************/
-unsigned char MCS_rate_1R[16] = {0xff, 0x00, 0x0, 0x0, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
+const u8 MCS_rate_1R[16] = {
+ 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
/********************************************************
ChannelPlan definitions
@@ -1513,7 +1516,7 @@ static int issue_deauth_ex(struct adapter *padapter, u8 *da,
break;
if (i < try_cnt && wait_ms > 0 && ret == _FAIL)
- msleep(wait_ms);
+ mdelay(wait_ms);
} while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0)));
if (ret != _FAIL) {
@@ -2401,10 +2404,7 @@ static void process_80211d(struct adapter *padapter, struct wlan_bssid_ex *bssid
p++;
for (j = 0; j < noc; j++) {
- if (fcn <= 14)
- channel = fcn + j; /* 2.4 GHz */
- else
- channel = fcn + j*4; /* 5 GHz */
+ channel = fcn + j;
chplan_ap.Channel[i++] = channel;
}
@@ -2481,14 +2481,6 @@ static void process_80211d(struct adapter *padapter, struct wlan_bssid_ex *bssid
j++;
}
- /* 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;
}
@@ -2982,11 +2974,11 @@ static unsigned int OnAssocReq(struct adapter *padapter,
/* checking SSID */
p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + ie_offset, _SSID_IE_, &ie_len,
pkt_len - WLAN_HDR_A3_LEN - ie_offset);
- if (!p)
- status = _STATS_FAILURE_;
- if (ie_len == 0) { /* broadcast ssid, however it is not allowed in assocreq */
+ if (!p || ie_len == 0) {
+ /* broadcast ssid, however it is not allowed in assocreq */
status = _STATS_FAILURE_;
+ goto OnAssocReqFail;
} else {
/* check if ssid match */
if (memcmp((void *)(p+2), cur->Ssid.Ssid, cur->Ssid.SsidLength))
@@ -3844,24 +3836,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},
-
- /*----------------------------------------------------------
- below 2 are reserved
- -----------------------------------------------------------*/
- {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},
+ {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},
};
int init_hw_mlme_ext(struct adapter *padapter)
@@ -3969,7 +3957,7 @@ static void init_channel_list(struct adapter *padapter,
if (!has_channel(channel_set, chanset_size, ch))
continue;
- if ((0 == padapter->registrypriv.ht_enable) && (8 == o->inc))
+ if (!padapter->registrypriv.ht_enable && o->inc == 8)
continue;
if ((0 == (padapter->registrypriv.cbw40_enable & BIT(1))) &&
diff --git a/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c b/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c
index 5ab6fc22a156..9764e85c000c 100644
--- a/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c
+++ b/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c
@@ -292,7 +292,7 @@ void rtw_set_rpwm(struct adapter *padapter, u8 pslv)
pslv = PS_STATE_S3;
}
- if ((pwrpriv->rpwm == pslv)) {
+ 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));
return;
@@ -344,7 +344,7 @@ static u8 PS_RDY_CHECK(struct adapter *padapter)
if (delta_time < LPS_DELAY_TIME)
return false;
- if ((check_fwstate(pmlmepriv, _FW_LINKED) == false) ||
+ if ((!check_fwstate(pmlmepriv, _FW_LINKED)) ||
(check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) ||
(check_fwstate(pmlmepriv, WIFI_AP_STATE)) ||
(check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) ||
@@ -352,7 +352,8 @@ static u8 PS_RDY_CHECK(struct adapter *padapter)
return false;
if (pwrpriv->bInSuspend)
return false;
- if ((padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) && (padapter->securitypriv.binstallGrpkey == false)) {
+ if (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X &&
+ !padapter->securitypriv.binstallGrpkey) {
DBG_88E("Group handshake still in progress !!!\n");
return false;
}
@@ -438,7 +439,7 @@ void LPS_Enter(struct adapter *padapter)
{
struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
- if (PS_RDY_CHECK(padapter) == false)
+ if (!PS_RDY_CHECK(padapter))
return;
if (pwrpriv->bLeisurePs) {
diff --git a/drivers/staging/rtl8188eu/core/rtw_recv.c b/drivers/staging/rtl8188eu/core/rtw_recv.c
index 17b4b9257b49..dc447cc78c32 100644
--- a/drivers/staging/rtl8188eu/core/rtw_recv.c
+++ b/drivers/staging/rtl8188eu/core/rtw_recv.c
@@ -233,7 +233,7 @@ static int recvframe_chkmic(struct adapter *adapter,
/* calculate mic code */
if (stainfo) {
- if (IS_MCAST(prxattrib->ra)) {
+ if (is_multicast_ether_addr(prxattrib->ra)) {
if (!psecuritypriv) {
res = _FAIL;
RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
@@ -321,11 +321,11 @@ static int recvframe_chkmic(struct adapter *adapter,
/* double check key_index for some timing issue , */
/* cannot compare with psecuritypriv->dot118021XGrpKeyid also cause timing issue */
- if ((IS_MCAST(prxattrib->ra) == true) && (prxattrib->key_index != pmlmeinfo->key_index))
+ if (is_multicast_ether_addr(prxattrib->ra) && prxattrib->key_index != pmlmeinfo->key_index)
brpt_micerror = false;
if ((prxattrib->bdecrypted) && (brpt_micerror)) {
- rtw_handle_tkip_mic_err(adapter, (u8)IS_MCAST(prxattrib->ra));
+ 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 {
@@ -335,7 +335,7 @@ static int recvframe_chkmic(struct adapter *adapter,
res = _FAIL;
} else {
/* mic checked ok */
- if ((!psecuritypriv->bcheck_grpkey) && (IS_MCAST(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"));
}
@@ -488,7 +488,7 @@ static struct recv_frame *portctrl(struct adapter *adapter,
prtnframe = precv_frame;
}
- return prtnframe;
+ return prtnframe;
}
static int recv_decache(struct recv_frame *precv_frame, u8 bretry,
@@ -648,7 +648,7 @@ int sta2sta_data_frame(struct adapter *adapter, struct recv_frame *precv_frame,
u8 *mybssid = get_bssid(pmlmepriv);
u8 *myhwaddr = myid(&adapter->eeprompriv);
u8 *sta_addr = NULL;
- int bmcast = IS_MCAST(pattrib->dst);
+ bool mcast = is_multicast_ether_addr(pattrib->dst);
if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) ||
(check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) {
@@ -659,7 +659,7 @@ int sta2sta_data_frame(struct adapter *adapter, struct recv_frame *precv_frame,
goto exit;
}
- if ((memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast)) {
+ if (memcmp(myhwaddr, pattrib->dst, ETH_ALEN) && !mcast) {
ret = _FAIL;
goto exit;
}
@@ -681,9 +681,9 @@ int sta2sta_data_frame(struct adapter *adapter, struct recv_frame *precv_frame,
}
sta_addr = pattrib->bssid;
} else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
- if (bmcast) {
+ if (mcast) {
/* For AP mode, if DA == MCAST, then BSSID should be also MCAST */
- if (!IS_MCAST(pattrib->bssid)) {
+ if (!is_multicast_ether_addr(pattrib->bssid)) {
ret = _FAIL;
goto exit;
}
@@ -700,7 +700,7 @@ int sta2sta_data_frame(struct adapter *adapter, struct recv_frame *precv_frame,
ret = _FAIL;
}
- if (bmcast)
+ if (mcast)
*psta = rtw_get_bcmc_stainfo(adapter);
else
*psta = rtw_get_stainfo(pstapriv, sta_addr); /* get ap_info */
@@ -727,7 +727,7 @@ static int ap2sta_data_frame(
struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
u8 *mybssid = get_bssid(pmlmepriv);
u8 *myhwaddr = myid(&adapter->eeprompriv);
- int bmcast = IS_MCAST(pattrib->dst);
+ bool mcast = is_multicast_ether_addr(pattrib->dst);
if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) &&
(check_fwstate(pmlmepriv, _FW_LINKED) == true ||
@@ -740,7 +740,7 @@ static int ap2sta_data_frame(
}
/* da should be for me */
- if ((memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast)) {
+ 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;
@@ -755,7 +755,7 @@ static int ap2sta_data_frame(
(" %s: compare BSSID fail ; BSSID=%pM\n", __func__, (pattrib->bssid)));
RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("mybssid=%pM\n", (mybssid)));
- if (!bmcast) {
+ if (!mcast) {
DBG_88E("issue_deauth to the nonassociated ap=%pM for the reason(7)\n", (pattrib->bssid));
issue_deauth(adapter, pattrib->bssid, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
}
@@ -764,7 +764,7 @@ static int ap2sta_data_frame(
goto exit;
}
- if (bmcast)
+ if (mcast)
*psta = rtw_get_bcmc_stainfo(adapter);
else
*psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /* get ap_info */
@@ -789,7 +789,7 @@ static int ap2sta_data_frame(
ret = RTW_RX_HANDLED;
goto exit;
} else {
- if (!memcmp(myhwaddr, pattrib->dst, ETH_ALEN) && (!bmcast)) {
+ if (!memcmp(myhwaddr, pattrib->dst, ETH_ALEN) && !mcast) {
*psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /* get sta_info */
if (*psta == NULL) {
DBG_88E("issue_deauth to the ap =%pM for the reason(7)\n", (pattrib->bssid));
@@ -1129,9 +1129,9 @@ static int validate_recv_data_frame(struct adapter *adapter,
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_MCAST(pattrib->ra(0x%02x))=%d^^^^^^^^^^^^^^^6\n", pattrib->ra[0], IS_MCAST(pattrib->ra)));
+ 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_MCAST(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));
@@ -1283,8 +1283,8 @@ static int wlanhdr_to_ethhdr(struct recv_frame *precvframe)
psnap_type = ptr+pattrib->hdrlen + pattrib->iv_len+SNAP_SIZE;
/* convert hdr + possible LLC headers into Ethernet header */
if ((!memcmp(psnap, rtw_rfc1042_header, SNAP_SIZE) &&
- (!memcmp(psnap_type, SNAP_ETH_TYPE_IPX, 2) == false) &&
- (!memcmp(psnap_type, SNAP_ETH_TYPE_APPLETALK_AARP, 2) == false)) ||
+ memcmp(psnap_type, SNAP_ETH_TYPE_IPX, 2) &&
+ memcmp(psnap_type, SNAP_ETH_TYPE_APPLETALK_AARP, 2)) ||
!memcmp(psnap, rtw_bridge_tunnel_header, SNAP_SIZE)) {
/* remove RFC1042 or Bridge-Tunnel encapsulation and replace EtherType */
bsnaphdr = true;
@@ -1971,7 +1971,8 @@ static int recv_func(struct adapter *padapter, struct recv_frame *rframe)
if (ret == _SUCCESS) {
/* check if need to enqueue into uc_swdec_pending_queue*/
if (check_fwstate(mlmepriv, WIFI_STATION_STATE) &&
- !IS_MCAST(prxattrib->ra) && prxattrib->encrypt > 0 &&
+ !is_multicast_ether_addr(prxattrib->ra) &&
+ prxattrib->encrypt > 0 &&
prxattrib->bdecrypted == 0 &&
!is_wep_enc(psecuritypriv->dot11PrivacyAlgrthm) &&
!psecuritypriv->busetkipkey) {
@@ -2041,7 +2042,7 @@ static void rtw_signal_stat_timer_hdl(struct timer_list *t)
}
/* update value of signal_strength, rssi, signal_qual */
- if (check_fwstate(&adapter->mlmepriv, _FW_UNDER_SURVEY) == false) {
+ if (!check_fwstate(&adapter->mlmepriv, _FW_UNDER_SURVEY)) {
tmp_s = avg_signal_strength +
(_alpha - 1) * recvpriv->signal_strength;
tmp_s = DIV_ROUND_UP(tmp_s, _alpha);
diff --git a/drivers/staging/rtl8188eu/core/rtw_security.c b/drivers/staging/rtl8188eu/core/rtw_security.c
index 2a48b09ea9ae..f7407632e80b 100644
--- a/drivers/staging/rtl8188eu/core/rtw_security.c
+++ b/drivers/staging/rtl8188eu/core/rtw_security.c
@@ -353,7 +353,7 @@ void rtw_seccalctkipmic(u8 *key, u8 *header, u8 *data, u32 data_len, u8 *mic_cod
/* Michael MIC pseudo header: DA, SA, 3 x 0, Priority */
if (header[1]&1) { /* ToDS == 1 */
- rtw_secmicappend(&micdata, &header[16], 6); /* DA */
+ rtw_secmicappend(&micdata, &header[16], 6); /* DA */
if (header[1]&2) /* From Ds == 1 */
rtw_secmicappend(&micdata, &header[24], 6);
else
@@ -608,7 +608,7 @@ u32 rtw_tkip_encrypt(struct adapter *padapter, u8 *pxmitframe)
if (stainfo != NULL) {
RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("%s: stainfo!= NULL!!!\n", __func__));
- if (IS_MCAST(pattrib->ra))
+ if (is_multicast_ether_addr(pattrib->ra))
prwskey = psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey;
else
prwskey = &stainfo->dot118021x_UncstKey.skey[0];
@@ -678,7 +678,7 @@ u32 rtw_tkip_decrypt(struct adapter *padapter, u8 *precvframe)
if (prxattrib->encrypt == _TKIP_) {
stainfo = rtw_get_stainfo(&padapter->stapriv, &prxattrib->ta[0]);
if (stainfo) {
- if (IS_MCAST(prxattrib->ra)) {
+ 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__);
@@ -1250,7 +1250,7 @@ u32 rtw_aes_encrypt(struct adapter *padapter, u8 *pxmitframe)
if (stainfo) {
RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("%s: stainfo!= NULL!!!\n", __func__));
- if (IS_MCAST(pattrib->ra))
+ if (is_multicast_ether_addr(pattrib->ra))
prwskey = psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey;
else
prwskey = &stainfo->dot118021x_UncstKey.skey[0];
@@ -1273,8 +1273,7 @@ u32 rtw_aes_encrypt(struct adapter *padapter, u8 *pxmitframe)
}
}
-
- return res;
+ return res;
}
u32 rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe)
@@ -1296,7 +1295,7 @@ u32 rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe)
struct security_priv *psecuritypriv = &padapter->securitypriv;
char iv[8], icv[8];
- if (IS_MCAST(prxattrib->ra)) {
+ if (is_multicast_ether_addr(prxattrib->ra)) {
/* in concurrent we should use sw descrypt in group key, so we remove this message */
if (!psecuritypriv->binstallGrpkey) {
res = _FAIL;
diff --git a/drivers/staging/rtl8188eu/core/rtw_wlan_util.c b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c
index b9406583e501..3e05e2c7f61b 100644
--- a/drivers/staging/rtl8188eu/core/rtw_wlan_util.c
+++ b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c
@@ -107,26 +107,20 @@ unsigned char networktype_to_raid(unsigned char network_type)
u8 judge_network_type(struct adapter *padapter, unsigned char *rate, int ratelen)
{
u8 network_type = 0;
- struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
- struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
- if (pmlmeext->cur_channel > 14) {
- if (pmlmeinfo->HT_enable)
- network_type = WIRELESS_11_5N;
+ if (pmlmeinfo->HT_enable)
+ network_type = WIRELESS_11_24N;
- network_type |= WIRELESS_11A;
- } else {
- if (pmlmeinfo->HT_enable)
- network_type = WIRELESS_11_24N;
-
- if ((cckratesonly_included(rate, ratelen)) == true)
- network_type |= WIRELESS_11B;
- else if ((cckrates_included(rate, ratelen)) == true)
- network_type |= WIRELESS_11BG;
- else
- network_type |= WIRELESS_11G;
- }
- return network_type;
+ if (cckratesonly_included(rate, ratelen))
+ network_type |= WIRELESS_11B;
+ else if (cckrates_included(rate, ratelen))
+ network_type |= WIRELESS_11BG;
+ else
+ network_type |= WIRELESS_11G;
+
+ return network_type;
}
static unsigned char ratetbl_val_2wifirate(unsigned char rate)
@@ -460,9 +454,9 @@ void write_cam(struct adapter *padapter, u8 entry, u16 ctrl, u8 *mac, u8 *key)
void clear_cam_entry(struct adapter *padapter, u8 entry)
{
- unsigned char null_sta[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
- unsigned char null_key[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ u8 null_sta[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ u8 null_key[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
write_cam(padapter, entry, 0, null_sta, null_key);
}
@@ -852,7 +846,7 @@ int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len)
unsigned char ht_info_infos_0;
int ssid_len;
- if (is_client_associated_to_ap(Adapter) == false)
+ if (!is_client_associated_to_ap(Adapter))
return true;
len = packet_len - sizeof(struct ieee80211_hdr_3addr);
@@ -862,7 +856,7 @@ int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len)
return _FAIL;
}
- if (!memcmp(cur_network->network.MacAddress, pbssid, 6) == false) {
+ 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));
return true;
@@ -1419,32 +1413,25 @@ void update_wireless_mode(struct adapter *padapter)
{
int ratelen, network_type = 0;
u32 SIFS_Timer;
- struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
- struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
- struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network);
- unsigned char *rate = cur_network->SupportedRates;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+ struct wlan_bssid_ex *cur_network = &pmlmeinfo->network;
+ unsigned char *rate = cur_network->SupportedRates;
ratelen = rtw_get_rateset_len(cur_network->SupportedRates);
- if ((pmlmeinfo->HT_info_enable) && (pmlmeinfo->HT_caps_enable))
+ if (pmlmeinfo->HT_info_enable && pmlmeinfo->HT_caps_enable)
pmlmeinfo->HT_enable = 1;
- if (pmlmeext->cur_channel > 14) {
- if (pmlmeinfo->HT_enable)
- network_type = WIRELESS_11_5N;
+ if (pmlmeinfo->HT_enable)
+ network_type = WIRELESS_11_24N;
- network_type |= WIRELESS_11A;
- } else {
- if (pmlmeinfo->HT_enable)
- network_type = WIRELESS_11_24N;
-
- if ((cckratesonly_included(rate, ratelen)) == true)
- network_type |= WIRELESS_11B;
- else if ((cckrates_included(rate, ratelen)) == true)
- network_type |= WIRELESS_11BG;
- else
- network_type |= WIRELESS_11G;
- }
+ if (cckratesonly_included(rate, ratelen))
+ network_type |= WIRELESS_11B;
+ else if (cckrates_included(rate, ratelen))
+ network_type |= WIRELESS_11BG;
+ else
+ network_type |= WIRELESS_11G;
pmlmeext->cur_wireless_mode = network_type & padapter->registrypriv.wireless_mode;
diff --git a/drivers/staging/rtl8188eu/core/rtw_xmit.c b/drivers/staging/rtl8188eu/core/rtw_xmit.c
index 2130d78e0d9f..0a3e710590ed 100644
--- a/drivers/staging/rtl8188eu/core/rtw_xmit.c
+++ b/drivers/staging/rtl8188eu/core/rtw_xmit.c
@@ -77,8 +77,6 @@ s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter)
goto exit;
}
pxmitpriv->pxmit_frame_buf = PTR_ALIGN(pxmitpriv->pallocated_frame_buf, 4);
- /* pxmitpriv->pxmit_frame_buf = pxmitpriv->pallocated_frame_buf + 4 - */
- /* ((size_t) (pxmitpriv->pallocated_frame_buf) &3); */
pxframe = (struct xmit_frame *)pxmitpriv->pxmit_frame_buf;
@@ -115,8 +113,6 @@ s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter)
}
pxmitpriv->pxmitbuf = PTR_ALIGN(pxmitpriv->pallocated_xmitbuf, 4);
- /* pxmitpriv->pxmitbuf = pxmitpriv->pallocated_xmitbuf + 4 - */
- /* ((size_t) (pxmitpriv->pallocated_xmitbuf) &3); */
pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmitbuf;
@@ -254,10 +250,12 @@ static void update_attrib_vcs_info(struct adapter *padapter, struct xmit_frame *
else /* no frag */
sz = pattrib->last_txcmdsz;
- /* (1) RTS_Threshold is compared to the MPDU, not MSDU. */
- /* (2) If there are more than one frag in this MSDU, only the first frag uses protection frame. */
- /* Other fragments are protected by previous fragment. */
- /* So we only need to check the length of first fragment. */
+ /* (1) RTS_Threshold is compared to the MPDU, not MSDU.
+ * (2) If there are more than one frag in this MSDU,
+ * only the first frag uses protection frame.
+ * Other fragments are protected by previous fragment.
+ * So we only need to check the length of first fragment.
+ */
if (pmlmeext->cur_wireless_mode < WIRELESS_11_24N || padapter->registrypriv.wifi_spec) {
if (sz > padapter->registrypriv.rts_thresh) {
pattrib->vcs_mode = RTS_CTS;
@@ -321,13 +319,6 @@ static void update_attrib_vcs_info(struct adapter *padapter, struct xmit_frame *
static void update_attrib_phy_info(struct pkt_attrib *pattrib, struct sta_info *psta)
{
- /*if (psta->rtsen)
- pattrib->vcs_mode = RTS_CTS;
- else if (psta->cts2self)
- pattrib->vcs_mode = CTS_TO_SELF;
- else
- pattrib->vcs_mode = NONE_VCS;*/
-
pattrib->mdata = 0;
pattrib->eosp = 0;
pattrib->triggered = 0;
@@ -344,9 +335,9 @@ static void update_attrib_phy_info(struct pkt_attrib *pattrib, struct sta_info *
pattrib->retry_ctrl = false;
}
-u8 qos_acm(u8 acm_mask, u8 priority)
+u8 qos_acm(u8 acm_mask, u8 priority)
{
- u8 change_priority = priority;
+ u8 change_priority = priority;
switch (priority) {
case 0:
@@ -368,7 +359,8 @@ u8 qos_acm(u8 acm_mask, u8 priority)
change_priority = 5;
break;
default:
- DBG_88E("qos_acm(): invalid pattrib->priority: %d!!!\n", priority);
+ DBG_88E("%s(): invalid pattrib->priority: %d!!!\n",
+ __func__, priority);
break;
}
@@ -383,8 +375,10 @@ static void set_qos(struct sk_buff *skb, struct pkt_attrib *pattrib)
skb_copy_bits(skb, ETH_HLEN, &ip_hdr, sizeof(ip_hdr));
pattrib->priority = ip_hdr.tos >> 5;
} else if (pattrib->ether_type == ETH_P_PAE) {
- /* "When priority processing of data frames is supported, */
- /* a STA's SME should send EAPOL-Key frames at the highest priority." */
+ /* When priority processing of data frames is supported,
+ * a STA's SME should send EAPOL-Key frames at the highest
+ * priority.
+ */
pattrib->priority = 7;
} else {
pattrib->priority = 0;
@@ -399,7 +393,7 @@ static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct p
struct sta_info *psta = NULL;
struct ethhdr etherhdr;
- int bmcast;
+ bool mcast;
struct sta_priv *pstapriv = &padapter->stapriv;
struct security_priv *psecuritypriv = &padapter->securitypriv;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
@@ -430,8 +424,10 @@ static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct p
pattrib->pktlen = pkt->len - ETH_HLEN;
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 */
+ /* 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.
+ */
u8 tmp[24];
skb_copy_bits(pkt, ETH_HLEN, tmp, 24);
@@ -460,10 +456,10 @@ static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct p
if ((pattrib->ether_type == ETH_P_ARP) || (pattrib->ether_type == ETH_P_PAE) || (pattrib->dhcp_pkt == 1))
rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_SPECIAL_PACKET, 1);
- bmcast = IS_MCAST(pattrib->ra);
+ mcast = is_multicast_ether_addr(pattrib->ra);
/* get sta_info */
- if (bmcast) {
+ if (mcast) {
psta = rtw_get_bcmc_stainfo(padapter);
} else {
psta = rtw_get_stainfo(pstapriv, pattrib->ra);
@@ -494,7 +490,8 @@ static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct p
pattrib->subtype = WIFI_DATA_TYPE;
pattrib->priority = 0;
- if (check_fwstate(pmlmepriv, WIFI_AP_STATE|WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE)) {
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE |
+ WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE)) {
if (psta->qos_option)
set_qos(pkt, pattrib);
} else {
@@ -517,7 +514,7 @@ static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct p
goto exit;
}
} else {
- GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt, bmcast);
+ GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt, mcast);
switch (psecuritypriv->dot11AuthAlgrthm) {
case dot11AuthAlgrthm_Open:
@@ -526,7 +523,7 @@ static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct p
pattrib->key_idx = (u8)psecuritypriv->dot11PrivacyKeyIndex;
break;
case dot11AuthAlgrthm_8021X:
- if (bmcast)
+ if (mcast)
pattrib->key_idx = (u8)psecuritypriv->dot118021XGrpKeyid;
else
pattrib->key_idx = 0;
@@ -596,7 +593,6 @@ static s32 xmitframe_addmic(struct adapter *padapter, struct xmit_frame *pxmitfr
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
u8 priority[4] = {0x0, 0x0, 0x0, 0x0};
u8 hw_hdr_offset = 0;
- int bmcst = IS_MCAST(pattrib->ra);
if (pattrib->psta)
stainfo = pattrib->psta;
@@ -605,7 +601,7 @@ static s32 xmitframe_addmic(struct adapter *padapter, struct xmit_frame *pxmitfr
hw_hdr_offset = TXDESC_SIZE + (pxmitframe->pkt_offset * PACKET_OFFSET_SZ);
- if (pattrib->encrypt == _TKIP_) {/* if (psecuritypriv->dot11PrivacyAlgrthm == _TKIP_PRIVACY_) */
+ if (pattrib->encrypt == _TKIP_) {
/* encode mic code */
if (stainfo) {
u8 null_key[16] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
@@ -614,30 +610,27 @@ static s32 xmitframe_addmic(struct adapter *padapter, struct xmit_frame *pxmitfr
pframe = pxmitframe->buf_addr + hw_hdr_offset;
- if (bmcst) {
+ if (is_multicast_ether_addr(pattrib->ra)) {
if (!memcmp(psecuritypriv->dot118021XGrptxmickey[psecuritypriv->dot118021XGrpKeyid].skey, null_key, 16))
return _FAIL;
/* start to calculate the mic code */
rtw_secmicsetkey(&micdata, psecuritypriv->dot118021XGrptxmickey[psecuritypriv->dot118021XGrpKeyid].skey);
} else {
- if (!memcmp(&stainfo->dot11tkiptxmickey.skey[0], null_key, 16)) {
- /* DbgPrint("\nxmitframe_addmic:stainfo->dot11tkiptxmickey == 0\n"); */
- /* msleep(10); */
+ if (!memcmp(&stainfo->dot11tkiptxmickey.skey[0], null_key, 16))
return _FAIL;
- }
/* start to calculate the mic code */
rtw_secmicsetkey(&micdata, &stainfo->dot11tkiptxmickey.skey[0]);
}
- if (pframe[1]&1) { /* ToDS == 1 */
+ if (pframe[1] & 1) { /* ToDS == 1 */
rtw_secmicappend(&micdata, &pframe[16], 6); /* DA */
- if (pframe[1]&2) /* From Ds == 1 */
+ if (pframe[1] & 2) /* From Ds == 1 */
rtw_secmicappend(&micdata, &pframe[24], 6);
else
rtw_secmicappend(&micdata, &pframe[10], 6);
} else { /* ToDS == 0 */
rtw_secmicappend(&micdata, &pframe[4], 6); /* DA */
- if (pframe[1]&2) /* From Ds == 1 */
+ if (pframe[1] & 2) /* From Ds == 1 */
rtw_secmicappend(&micdata, &pframe[16], 6);
else
rtw_secmicappend(&micdata, &pframe[10], 6);
@@ -654,23 +647,31 @@ static s32 xmitframe_addmic(struct adapter *padapter, struct xmit_frame *pxmitfr
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)));
+ curfragnum, *payload, *(payload + 1),
+ *(payload + 2), *(payload + 3),
+ *(payload + 4), *(payload + 5),
+ *(payload + 6), *(payload + 7)));
- payload = payload+pattrib->hdrlen+pattrib->iv_len;
+ 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-pattrib->iv_len-((pattrib->bswenc) ? pattrib->icv_len : 0);
+ if (curfragnum + 1 == pattrib->nr_frags) {
+ length = pattrib->last_txcmdsz -
+ pattrib->hdrlen -
+ pattrib->iv_len -
+ ((pattrib->bswenc) ?
+ pattrib->icv_len : 0);
rtw_secmicappend(&micdata, payload, length);
- payload = payload+length;
+ payload += length;
} else {
- length = pxmitpriv->frag_len-pattrib->hdrlen-pattrib->iv_len-((pattrib->bswenc) ? pattrib->icv_len : 0);
+ length = pxmitpriv->frag_len -
+ pattrib->hdrlen -
+ pattrib->iv_len -
+ ((pattrib->bswenc) ?
+ pattrib->icv_len : 0);
rtw_secmicappend(&micdata, payload, length);
- payload = payload+length+pattrib->icv_len;
+ 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));
}
}
@@ -686,8 +687,8 @@ static s32 xmitframe_addmic(struct adapter *padapter, struct xmit_frame *pxmitfr
pattrib->last_txcmdsz += 8;
RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("\n ======== last pkt ========\n"));
- payload = payload-pattrib->last_txcmdsz+8;
- for (curfragnum = 0; curfragnum < pattrib->last_txcmdsz; curfragnum = curfragnum+8)
+ 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),
@@ -743,12 +744,10 @@ s32 rtw_make_wlanhdr(struct adapter *padapter, u8 *hdr, struct pkt_attrib *pattr
struct sta_info *psta;
- int bmcst = IS_MCAST(pattrib->ra);
-
if (pattrib->psta) {
psta = pattrib->psta;
} else {
- if (bmcst)
+ if (is_multicast_ether_addr(pattrib->ra))
psta = rtw_get_bcmc_stainfo(padapter);
else
psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra);
@@ -836,11 +835,11 @@ s32 rtw_make_wlanhdr(struct adapter *padapter, u8 *hdr, struct pkt_attrib *pattr
if (SN_LESS(pattrib->seqnum, tx_seq)) {
pattrib->ampdu_en = false;/* AGG BK */
} else if (SN_EQUAL(pattrib->seqnum, tx_seq)) {
- psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = (tx_seq+1)&0xfff;
+ psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = (tx_seq + 1) & 0xfff;
pattrib->ampdu_en = true;/* AGG EN */
} else {
- psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = (pattrib->seqnum+1)&0xfff;
+ psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = (pattrib->seqnum + 1) & 0xfff;
pattrib->ampdu_en = true;/* AGG EN */
}
}
@@ -856,9 +855,9 @@ s32 rtw_txframes_pending(struct adapter *padapter)
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
return (!list_empty(&pxmitpriv->be_pending.queue) ||
- !list_empty(&pxmitpriv->bk_pending.queue) ||
- !list_empty(&pxmitpriv->vi_pending.queue) ||
- !list_empty(&pxmitpriv->vo_pending.queue));
+ !list_empty(&pxmitpriv->bk_pending.queue) ||
+ !list_empty(&pxmitpriv->vi_pending.queue) ||
+ !list_empty(&pxmitpriv->vo_pending.queue));
}
s32 rtw_txframes_sta_ac_pending(struct adapter *padapter, struct pkt_attrib *pattrib)
@@ -914,7 +913,7 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
struct pkt_attrib *pattrib = &pxmitframe->attrib;
u8 *pbuf_start;
- s32 bmcst = IS_MCAST(pattrib->ra);
+ bool mcast = is_multicast_ether_addr(pattrib->ra);
s32 res = _SUCCESS;
size_t remainder = pkt->len - ETH_HLEN;
@@ -964,13 +963,13 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct
WEP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx);
break;
case _TKIP_:
- if (bmcst)
+ if (mcast)
TKIP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx);
else
TKIP_IV(pattrib->iv, psta->dot11txpn, 0);
break;
case _AES_:
- if (bmcst)
+ if (mcast)
AES_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx);
else
AES_IV(pattrib->iv, psta->dot11txpn, 0);
@@ -981,7 +980,10 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct
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)));
+ __func__,
+ padapter->securitypriv.dot11PrivacyKeyIndex,
+ pattrib->iv[3], *pframe, *(pframe + 1),
+ *(pframe + 2), *(pframe + 3)));
pframe += pattrib->iv_len;
@@ -997,7 +999,7 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct
if ((pattrib->icv_len > 0) && (pattrib->bswenc))
mpdu_len -= pattrib->icv_len;
- mem_sz = min_t(size_t, bmcst ? pattrib->pktlen : mpdu_len, remainder);
+ mem_sz = min_t(size_t, mcast ? pattrib->pktlen : mpdu_len, remainder);
skb_copy_bits(pkt, pkt->len - remainder, pframe, mem_sz);
remainder -= mem_sz;
@@ -1010,7 +1012,7 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct
frg_inx++;
- if (bmcst || remainder == 0) {
+ if (mcast || remainder == 0) {
pattrib->nr_frags = frg_inx;
pattrib->last_txcmdsz = pattrib->hdrlen + pattrib->iv_len + ((pattrib->nr_frags == 1) ? llc_sz : 0) +
@@ -1041,7 +1043,7 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct
xmitframe_swencrypt(padapter, pxmitframe);
- if (!bmcst)
+ if (!mcast)
update_attrib_vcs_info(padapter, pxmitframe);
else
pattrib->vcs_mode = NONE_VCS;
@@ -1121,7 +1123,7 @@ void rtw_count_tx_stats(struct adapter *padapter, struct xmit_frame *pxmitframe,
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
- if ((pxmitframe->frame_tag&0x0f) == DATA_FRAMETAG) {
+ if ((pxmitframe->frame_tag & 0x0f) == DATA_FRAMETAG) {
pxmitpriv->tx_bytes += sz;
pmlmepriv->LinkDetectInfo.NumTxOkInPeriod += pxmitframe->agg_num;
@@ -1147,7 +1149,6 @@ 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;
- /* pxmitbuf->ext_tag = true; */
if (pxmitbuf->sctx) {
DBG_88E("%s pxmitbuf->sctx is not NULL\n", __func__);
rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_ALLOC);
@@ -1184,8 +1185,6 @@ struct xmit_buf *rtw_alloc_xmitbuf(struct xmit_priv *pxmitpriv)
struct xmit_buf *pxmitbuf;
struct __queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue;
- /* DBG_88E("+rtw_alloc_xmitbuf\n"); */
-
spin_lock_irqsave(&pfree_xmitbuf_queue->lock, irql);
pxmitbuf = list_first_entry_or_null(&pfree_xmitbuf_queue->queue,
struct xmit_buf, list);
@@ -1276,7 +1275,6 @@ struct xmit_frame *rtw_alloc_xmitframe(struct xmit_priv *pxmitpriv)
pxframe->pxmitbuf = NULL;
memset(&pxframe->attrib, 0, sizeof(struct pkt_attrib));
- /* pxframe->attrib.psta = NULL; */
pxframe->frame_tag = DATA_FRAMETAG;
@@ -1350,7 +1348,6 @@ s32 rtw_xmitframe_enqueue(struct adapter *padapter, struct xmit_frame *pxmitfram
if (rtw_xmit_classifier(padapter, pxmitframe) == _FAIL) {
RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
("%s: drop xmit pkt for classifier fail\n", __func__));
-/* pxmitframe->pkt = NULL; */
return _FAIL;
}
@@ -1429,7 +1426,8 @@ exit:
return pxmitframe;
}
-struct tx_servq *rtw_get_sta_pending(struct adapter *padapter, struct sta_info *psta, int up, u8 *ac)
+struct tx_servq *rtw_get_sta_pending(struct adapter *padapter,
+ struct sta_info *psta, int up, u8 *ac)
{
struct tx_servq *ptxservq;
@@ -1438,26 +1436,30 @@ struct tx_servq *rtw_get_sta_pending(struct adapter *padapter, struct sta_info *
case 2:
ptxservq = &psta->sta_xmitpriv.bk_q;
*(ac) = 3;
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("%s : BK\n", __func__));
+ 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__));
+ 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__));
+ 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__));
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_,
+ ("%s : BE\n", __func__));
break;
}
@@ -1617,7 +1619,7 @@ s32 rtw_xmit(struct adapter *padapter, struct sk_buff **ppkt)
spin_unlock_bh(&pxmitpriv->lock);
#endif
- if (rtw_hal_xmit(padapter, pxmitframe) == false)
+ if (!rtw_hal_xmit(padapter, pxmitframe))
return 1;
return 0;
@@ -1632,9 +1634,9 @@ int xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_fra
struct sta_priv *pstapriv = &padapter->stapriv;
struct pkt_attrib *pattrib = &pxmitframe->attrib;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
- int bmcst = IS_MCAST(pattrib->ra);
+ bool mcast = is_multicast_ether_addr(pattrib->ra);
- if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == false)
+ if (!check_fwstate(pmlmepriv, WIFI_AP_STATE))
return ret;
if (pattrib->psta)
@@ -1646,12 +1648,12 @@ int xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_fra
return ret;
if (pattrib->triggered == 1) {
- if (bmcst)
+ if (mcast)
pattrib->qsel = 0x11;/* HIQ */
return ret;
}
- if (bmcst) {
+ if (mcast) {
spin_lock_bh(&psta->sleep_q.lock);
if (pstapriv->sta_dz_bitmap) {/* if any one sta is in ps mode */
@@ -1676,10 +1678,10 @@ int xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_fra
spin_lock_bh(&psta->sleep_q.lock);
- if (psta->state&WIFI_SLEEP_STATE) {
+ if (psta->state & WIFI_SLEEP_STATE) {
u8 wmmps_ac = 0;
- if (pstapriv->sta_dz_bitmap&BIT(psta->aid)) {
+ if (pstapriv->sta_dz_bitmap & BIT(psta->aid)) {
list_del_init(&pxmitframe->list);
list_add_tail(&pxmitframe->list, get_list_head(&psta->sleep_q));
@@ -1773,21 +1775,26 @@ void stop_sta_xmit(struct adapter *padapter, struct sta_info *psta)
pstapriv->sta_dz_bitmap |= BIT(psta->aid);
- dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->vo_q.sta_pending);
+ dequeue_xmitframes_to_sleeping_queue(padapter, psta,
+ &pstaxmitpriv->vo_q.sta_pending);
list_del_init(&pstaxmitpriv->vo_q.tx_pending);
- dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->vi_q.sta_pending);
+ dequeue_xmitframes_to_sleeping_queue(padapter, psta,
+ &pstaxmitpriv->vi_q.sta_pending);
list_del_init(&pstaxmitpriv->vi_q.tx_pending);
- dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->be_q.sta_pending);
+ dequeue_xmitframes_to_sleeping_queue(padapter, psta,
+ &pstaxmitpriv->be_q.sta_pending);
list_del_init(&pstaxmitpriv->be_q.tx_pending);
- dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->bk_q.sta_pending);
+ dequeue_xmitframes_to_sleeping_queue(padapter, psta,
+ &pstaxmitpriv->bk_q.sta_pending);
list_del_init(&pstaxmitpriv->bk_q.tx_pending);
/* for BC/MC Frames */
pstaxmitpriv = &psta_bmc->sta_xmitpriv;
- dequeue_xmitframes_to_sleeping_queue(padapter, psta_bmc, &pstaxmitpriv->be_q.sta_pending);
+ dequeue_xmitframes_to_sleeping_queue(padapter, psta_bmc,
+ &pstaxmitpriv->be_q.sta_pending);
list_del_init(&pstaxmitpriv->be_q.tx_pending);
spin_unlock_bh(&pxmitpriv->lock);
@@ -1863,7 +1870,7 @@ void wakeup_sta_to_xmit(struct adapter *padapter, struct sta_info *psta)
update_mask = BIT(0);
- if (psta->state&WIFI_SLEEP_STATE)
+ if (psta->state & WIFI_SLEEP_STATE)
psta->state ^= WIFI_SLEEP_STATE;
if (psta->state & WIFI_STA_ALIVE_CHK_STATE) {
@@ -1881,7 +1888,7 @@ void wakeup_sta_to_xmit(struct adapter *padapter, struct sta_info *psta)
if (!psta_bmc)
return;
- if ((pstapriv->sta_dz_bitmap&0xfffe) == 0x0) { /* no any sta in ps mode */
+ if ((pstapriv->sta_dz_bitmap & 0xfffe) == 0x0) { /* no any sta in ps mode */
spin_lock_bh(&psta_bmc->sleep_q.lock);
xmitframe_phead = get_list_head(&psta_bmc->sleep_q);
diff --git a/drivers/staging/rtl8188eu/hal/bb_cfg.c b/drivers/staging/rtl8188eu/hal/bb_cfg.c
index 1862c1396c85..11e0bb9c67d7 100644
--- a/drivers/staging/rtl8188eu/hal/bb_cfg.c
+++ b/drivers/staging/rtl8188eu/hal/bb_cfg.c
@@ -1,9 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
-*
-* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
-*
-******************************************************************************/
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ ******************************************************************************/
#include "odm_precomp.h"
diff --git a/drivers/staging/rtl8188eu/hal/fw.c b/drivers/staging/rtl8188eu/hal/fw.c
index 1b8341f40995..486ee4bd4744 100644
--- a/drivers/staging/rtl8188eu/hal/fw.c
+++ b/drivers/staging/rtl8188eu/hal/fw.c
@@ -98,9 +98,9 @@ static void rtl88e_firmware_selfreset(struct adapter *adapt)
{
u8 u1b_tmp;
- u1b_tmp = usb_read8(adapt, REG_SYS_FUNC_EN+1);
- usb_write8(adapt, REG_SYS_FUNC_EN+1, (u1b_tmp & (~BIT(2))));
- usb_write8(adapt, REG_SYS_FUNC_EN+1, (u1b_tmp | BIT(2)));
+ u1b_tmp = usb_read8(adapt, REG_SYS_FUNC_EN + 1);
+ usb_write8(adapt, REG_SYS_FUNC_EN + 1, (u1b_tmp & (~BIT(2))));
+ usb_write8(adapt, REG_SYS_FUNC_EN + 1, (u1b_tmp | BIT(2)));
}
static int _rtl88e_fw_free_to_go(struct adapter *adapt)
diff --git a/drivers/staging/rtl8188eu/hal/hal8188e_rate_adaptive.c b/drivers/staging/rtl8188eu/hal/hal8188e_rate_adaptive.c
index 464c11710398..6dbd7d261f1e 100644
--- a/drivers/staging/rtl8188eu/hal/hal8188e_rate_adaptive.c
+++ b/drivers/staging/rtl8188eu/hal/hal8188e_rate_adaptive.c
@@ -418,14 +418,16 @@ static int odm_ARFBRefresh_8188E(struct odm_dm_struct *dm_odm, struct odm_ra_inf
} else {
pRaInfo->LowestRate = 0;
}
- if (pRaInfo->HighestRate > 0x13)
- pRaInfo->PTModeSS = 3;
- else if (pRaInfo->HighestRate > 0x0b)
- pRaInfo->PTModeSS = 2;
- else if (pRaInfo->HighestRate > 0x0b)
- pRaInfo->PTModeSS = 1;
- else
- pRaInfo->PTModeSS = 0;
+
+ if (pRaInfo->HighestRate > 0x13)
+ pRaInfo->PTModeSS = 3;
+ else if (pRaInfo->HighestRate > 0x0b)
+ pRaInfo->PTModeSS = 2;
+ else if (pRaInfo->HighestRate > 0x0b)
+ pRaInfo->PTModeSS = 1;
+ else
+ pRaInfo->PTModeSS = 0;
+
ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD,
("ODM_ARFBRefresh_8188E(): PTModeSS =%d\n", pRaInfo->PTModeSS));
diff --git a/drivers/staging/rtl8188eu/hal/hal_com.c b/drivers/staging/rtl8188eu/hal/hal_com.c
index 7202e1767fc0..ff481fbd074c 100644
--- a/drivers/staging/rtl8188eu/hal/hal_com.c
+++ b/drivers/staging/rtl8188eu/hal/hal_com.c
@@ -45,9 +45,8 @@ void dump_chip_info(struct HAL_VERSION chip_vers)
#define CHAN_PLAN_HW 0x80
/* return the final channel plan decision */
-u8 hal_com_get_channel_plan(struct adapter *padapter, u8 hw_channel_plan,
- u8 sw_channel_plan, u8 def_channel_plan,
- bool load_fail)
+u8 hal_com_get_channel_plan(u8 hw_channel_plan, u8 sw_channel_plan,
+ u8 def_channel_plan, bool load_fail)
{
u8 sw_cfg;
u8 chnlplan;
@@ -119,7 +118,7 @@ u8 MRateToHwRate(u8 rate)
return ret;
}
-void HalSetBrateCfg(struct adapter *adapt, u8 *brates, u16 *rate_cfg)
+void hal_set_brate_cfg(u8 *brates, u16 *rate_cfg)
{
u8 i, is_brate, brate;
@@ -263,10 +262,10 @@ static void three_out_pipe(struct adapter *adapter, bool wifi_cfg)
}
}
-bool Hal_MappingOutPipe(struct adapter *adapter, u8 numoutpipe)
+bool hal_mapping_out_pipe(struct adapter *adapter, u8 numoutpipe)
{
struct registry_priv *pregistrypriv = &adapter->registrypriv;
- bool wifi_cfg = (pregistrypriv->wifi_spec) ? true : false;
+ bool wifi_cfg = (pregistrypriv->wifi_spec) ? true : false;
bool result = true;
switch (numoutpipe) {
diff --git a/drivers/staging/rtl8188eu/hal/odm.c b/drivers/staging/rtl8188eu/hal/odm.c
index 9d567838a43a..4ab490c1c13b 100644
--- a/drivers/staging/rtl8188eu/hal/odm.c
+++ b/drivers/staging/rtl8188eu/hal/odm.c
@@ -418,7 +418,7 @@ void odm_DIG(struct odm_dm_struct *pDM_Odm)
/* 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(): Abnornally false alarm case.\n"));
+ 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++;
@@ -768,22 +768,7 @@ u32 ODM_Get_Rate_Bitmap(struct odm_dm_struct *pDM_Odm, u32 macid, u32 ra_mask, u
return rate_bitmap;
}
-/*-----------------------------------------------------------------------------
- * Function: odm_RefreshRateAdaptiveMask()
- *
- * Overview: Update rate table mask according to rssi
- *
- * Input: NONE
- *
- * Output: NONE
- *
- * Return: NONE
- *
- * Revised History:
- * When Who Remark
- * 05/27/2009 hpfan Create Version 0.
- *
- *---------------------------------------------------------------------------*/
+/* Update rate table mask according to rssi */
void odm_RefreshRateAdaptiveMask(struct odm_dm_struct *pDM_Odm)
{
if (!(pDM_Odm->SupportAbility & ODM_BB_RA_MASK))
@@ -1074,7 +1059,7 @@ void odm_EdcaTurboCheckCE(struct odm_dm_struct *pDM_Odm)
struct mlme_ext_priv *pmlmeext = &(Adapter->mlmeextpriv);
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
- if ((pregpriv->wifi_spec == 1))/* (pmlmeinfo->HT_enable == 0)) */
+ if (pregpriv->wifi_spec == 1) /* (pmlmeinfo->HT_enable == 0)) */
goto dm_CheckEdcaTurbo_EXIT;
if (pmlmeinfo->assoc_AP_vendor >= HT_IOT_PEER_MAX)
diff --git a/drivers/staging/rtl8188eu/hal/odm_HWConfig.c b/drivers/staging/rtl8188eu/hal/odm_hwconfig.c
index 0464dc41f860..82d6b2e18b29 100644
--- a/drivers/staging/rtl8188eu/hal/odm_HWConfig.c
+++ b/drivers/staging/rtl8188eu/hal/odm_hwconfig.c
@@ -14,52 +14,48 @@
#define READ_AND_CONFIG_MP(ic, txt) (ODM_ReadAndConfig##txt##ic(dm_odm))
#define READ_AND_CONFIG_TC(ic, txt) (ODM_ReadAndConfig_TC##txt##ic(dm_odm))
-static u8 odm_QueryRxPwrPercentage(s8 AntPower)
+static u8 odm_query_rxpwrpercentage(s8 antpower)
{
- if ((AntPower <= -100) || (AntPower >= 20))
- return 0;
- else if (AntPower >= 0)
- return 100;
+ if ((antpower <= -100) || (antpower >= 20))
+ return 0;
+ else if (antpower >= 0)
+ return 100;
else
- return 100+AntPower;
+ return 100 + antpower;
}
/* 2012/01/12 MH MOve some signal strength smooth method to MP HAL layer. */
/* IF other SW team do not support the feature, remove this section.?? */
-static s32 odm_SignalScaleMapping_92CSeries(struct odm_dm_struct *dm_odm, s32 CurrSig)
+static s32 odm_signal_scale_mapping(struct odm_dm_struct *dm_odm, s32 currsig)
{
- s32 RetSig = 0;
-
- if (CurrSig >= 51 && CurrSig <= 100)
- RetSig = 100;
- else if (CurrSig >= 41 && CurrSig <= 50)
- RetSig = 80 + ((CurrSig - 40)*2);
- else if (CurrSig >= 31 && CurrSig <= 40)
- RetSig = 66 + (CurrSig - 30);
- else if (CurrSig >= 21 && CurrSig <= 30)
- RetSig = 54 + (CurrSig - 20);
- else if (CurrSig >= 10 && CurrSig <= 20)
- RetSig = 42 + (((CurrSig - 10) * 2) / 3);
- else if (CurrSig >= 5 && CurrSig <= 9)
- RetSig = 22 + (((CurrSig - 5) * 3) / 2);
- else if (CurrSig >= 1 && CurrSig <= 4)
- RetSig = 6 + (((CurrSig - 1) * 3) / 2);
+ s32 retsig = 0;
+
+ if (currsig >= 51 && currsig <= 100)
+ retsig = 100;
+ else if (currsig >= 41 && currsig <= 50)
+ retsig = 80 + ((currsig - 40) * 2);
+ else if (currsig >= 31 && currsig <= 40)
+ retsig = 66 + (currsig - 30);
+ else if (currsig >= 21 && currsig <= 30)
+ retsig = 54 + (currsig - 20);
+ else if (currsig >= 10 && currsig <= 20)
+ retsig = 42 + (((currsig - 10) * 2) / 3);
+ else if (currsig >= 5 && currsig <= 9)
+ retsig = 22 + (((currsig - 5) * 3) / 2);
+ else if (currsig >= 1 && currsig <= 4)
+ retsig = 6 + (((currsig - 1) * 3) / 2);
else
- RetSig = CurrSig;
- return RetSig;
-}
+ retsig = currsig;
-static s32 odm_SignalScaleMapping(struct odm_dm_struct *dm_odm, s32 CurrSig)
-{
- return odm_SignalScaleMapping_92CSeries(dm_odm, CurrSig);
+ return retsig;
}
-static u8 odm_EVMdbToPercentage(s8 Value)
+static u8 odm_evm_db_to_percentage(s8 value)
{
/* -33dB~0dB to 0%~99% */
s8 ret_val;
- ret_val = Value;
+ ret_val = value;
if (ret_val >= 0)
ret_val = 0;
@@ -115,42 +111,42 @@ static void odm_RxPhyStatus92CSeries_Parsing(struct odm_dm_struct *dm_odm,
switch (LNA_idx) {
case 7:
if (VGA_idx <= 27)
- rx_pwr_all = -100 + 2*(27-VGA_idx); /* VGA_idx = 27~2 */
+ rx_pwr_all = -100 + 2 * (27-VGA_idx); /* VGA_idx = 27~2 */
else
rx_pwr_all = -100;
break;
case 6:
- rx_pwr_all = -48 + 2*(2-VGA_idx); /* VGA_idx = 2~0 */
+ rx_pwr_all = -48 + 2 * (2-VGA_idx); /* VGA_idx = 2~0 */
break;
case 5:
- rx_pwr_all = -42 + 2*(7-VGA_idx); /* VGA_idx = 7~5 */
+ rx_pwr_all = -42 + 2 * (7-VGA_idx); /* VGA_idx = 7~5 */
break;
case 4:
- rx_pwr_all = -36 + 2*(7-VGA_idx); /* VGA_idx = 7~4 */
+ rx_pwr_all = -36 + 2 * (7-VGA_idx); /* VGA_idx = 7~4 */
break;
case 3:
- rx_pwr_all = -24 + 2*(7-VGA_idx); /* VGA_idx = 7~0 */
+ rx_pwr_all = -24 + 2 * (7-VGA_idx); /* VGA_idx = 7~0 */
break;
case 2:
if (cck_highpwr)
- rx_pwr_all = -12 + 2*(5-VGA_idx); /* VGA_idx = 5~0 */
+ rx_pwr_all = -12 + 2 * (5-VGA_idx); /* VGA_idx = 5~0 */
else
- rx_pwr_all = -6 + 2*(5-VGA_idx);
+ rx_pwr_all = -6 + 2 * (5-VGA_idx);
break;
case 1:
- rx_pwr_all = 8-2*VGA_idx;
+ rx_pwr_all = 8-2 * VGA_idx;
break;
case 0:
- rx_pwr_all = 14-2*VGA_idx;
+ rx_pwr_all = 14-2 * VGA_idx;
break;
default:
break;
}
rx_pwr_all += 6;
- PWDB_ALL = odm_QueryRxPwrPercentage(rx_pwr_all);
+ PWDB_ALL = odm_query_rxpwrpercentage(rx_pwr_all);
if (!cck_highpwr) {
if (PWDB_ALL >= 80)
- PWDB_ALL = ((PWDB_ALL-80)<<1)+((PWDB_ALL-80)>>1)+80;
+ PWDB_ALL = ((PWDB_ALL-80)<<1) + ((PWDB_ALL-80)>>1) + 80;
else if ((PWDB_ALL <= 78) && (PWDB_ALL >= 20))
PWDB_ALL += 3;
if (PWDB_ALL > 100)
@@ -185,17 +181,17 @@ static void odm_RxPhyStatus92CSeries_Parsing(struct odm_dm_struct *dm_odm,
/* (1)Get RSSI for HT rate */
- for (i = RF_PATH_A; i < RF_PATH_MAX; i++) {
+ for (i = RF_PATH_A; i < RF_PATH_MAX; i++) {
/* 2008/01/30 MH we will judge RF RX path now. */
if (dm_odm->RFPathRxEnable & BIT(i))
rf_rx_num++;
- rx_pwr[i] = ((pPhyStaRpt->path_agc[i].gain & 0x3F)*2) - 110;
+ rx_pwr[i] = ((pPhyStaRpt->path_agc[i].gain & 0x3F) * 2) - 110;
pPhyInfo->RxPwr[i] = rx_pwr[i];
/* Translate DBM to percentage. */
- RSSI = odm_QueryRxPwrPercentage(rx_pwr[i]);
+ RSSI = odm_query_rxpwrpercentage(rx_pwr[i]);
total_rssi += RSSI;
/* Modification for ext-LNA board */
@@ -218,7 +214,7 @@ static void odm_RxPhyStatus92CSeries_Parsing(struct odm_dm_struct *dm_odm,
/* (2)PWDB, Average PWDB calculated by hardware (for rate adaptive) */
rx_pwr_all = (((pPhyStaRpt->cck_sig_qual_ofdm_pwdb_all) >> 1) & 0x7f) - 110;
- PWDB_ALL = odm_QueryRxPwrPercentage(rx_pwr_all);
+ PWDB_ALL = odm_query_rxpwrpercentage(rx_pwr_all);
PWDB_ALL_BT = PWDB_ALL;
pPhyInfo->RxPWDBAll = PWDB_ALL;
@@ -236,7 +232,7 @@ static void odm_RxPhyStatus92CSeries_Parsing(struct odm_dm_struct *dm_odm,
/* Do not use shift operation like "rx_evmX >>= 1" because the compilor of free build environment */
/* fill most significant bit to "zero" when doing shifting operation which may change a negative */
/* 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 */
+ EVM = odm_evm_db_to_percentage((pPhyStaRpt->stream_rxevm[i])); /* dbm */
if (pPktinfo->bPacketMatchBSSID) {
if (i == RF_PATH_A) /* Fill value in RFD, Get the first spatial stream only */
@@ -248,10 +244,10 @@ static void odm_RxPhyStatus92CSeries_Parsing(struct odm_dm_struct *dm_odm,
/* UI BSS List signal strength(in percentage), make it good looking, from 0~100. */
/* It is assigned to the BSS List in GetValueFromBeaconOrProbeRsp(). */
if (isCCKrate) {
- pPhyInfo->SignalStrength = (u8)(odm_SignalScaleMapping(dm_odm, PWDB_ALL));/* PWDB_ALL; */
+ pPhyInfo->SignalStrength = (u8)(odm_signal_scale_mapping(dm_odm, PWDB_ALL));/* PWDB_ALL; */
} else {
if (rf_rx_num != 0)
- pPhyInfo->SignalStrength = (u8)(odm_SignalScaleMapping(dm_odm, total_rssi /= rf_rx_num));
+ pPhyInfo->SignalStrength = (u8)(odm_signal_scale_mapping(dm_odm, total_rssi /= rf_rx_num));
}
/* For 92C/92D HW (Hybrid) Antenna Diversity */
@@ -339,12 +335,12 @@ static void odm_Process_RSSIForDM(struct odm_dm_struct *dm_odm,
} else {
if (pPhyInfo->RxPWDBAll > (u32)UndecoratedSmoothedOFDM) {
UndecoratedSmoothedOFDM =
- (((UndecoratedSmoothedOFDM)*(Rx_Smooth_Factor-1)) +
+ (((UndecoratedSmoothedOFDM) * (Rx_Smooth_Factor-1)) +
(RSSI_Ave)) / (Rx_Smooth_Factor);
UndecoratedSmoothedOFDM = UndecoratedSmoothedOFDM + 1;
} else {
UndecoratedSmoothedOFDM =
- (((UndecoratedSmoothedOFDM)*(Rx_Smooth_Factor-1)) +
+ (((UndecoratedSmoothedOFDM) * (Rx_Smooth_Factor-1)) +
(RSSI_Ave)) / (Rx_Smooth_Factor);
}
}
@@ -382,7 +378,7 @@ static void odm_Process_RSSIForDM(struct odm_dm_struct *dm_odm,
if (pEntry->rssi_stat.ValidBit == 64) {
Weighting = min_t(u32, OFDM_pkt << 4, 64);
- UndecoratedSmoothedPWDB = (Weighting*UndecoratedSmoothedOFDM+(64-Weighting)*UndecoratedSmoothedCCK)>>6;
+ UndecoratedSmoothedPWDB = (Weighting * UndecoratedSmoothedOFDM + (64-Weighting) * UndecoratedSmoothedCCK)>>6;
} else {
if (pEntry->rssi_stat.ValidBit != 0)
UndecoratedSmoothedPWDB = (OFDM_pkt * UndecoratedSmoothedOFDM +
diff --git a/drivers/staging/rtl8188eu/hal/odm_rtl8188e.c b/drivers/staging/rtl8188eu/hal/odm_rtl8188e.c
index d5001920f77c..251bd8aba3b1 100644
--- a/drivers/staging/rtl8188eu/hal/odm_rtl8188e.c
+++ b/drivers/staging/rtl8188eu/hal/odm_rtl8188e.c
@@ -13,7 +13,7 @@ static void dm_rx_hw_antena_div_init(struct odm_dm_struct *dm_odm)
struct adapter *adapter = dm_odm->Adapter;
u32 value32;
- if (*(dm_odm->mp_mode) == 1) {
+ if (*dm_odm->mp_mode == 1) {
dm_odm->AntDivType = CGCS_RX_SW_ANTDIV;
phy_set_bb_reg(adapter, ODM_REG_IGI_A_11N, BIT(7), 0);
phy_set_bb_reg(adapter, ODM_REG_LNA_SWITCH_11N, BIT(31), 1);
@@ -23,7 +23,7 @@ static void dm_rx_hw_antena_div_init(struct odm_dm_struct *dm_odm)
/* MAC Setting */
value32 = phy_query_bb_reg(adapter, ODM_REG_ANTSEL_PIN_11N, bMaskDWord);
phy_set_bb_reg(adapter, ODM_REG_ANTSEL_PIN_11N, bMaskDWord,
- value32|(BIT(23) | BIT(25)));
+ value32 | (BIT(23) | BIT(25)));
/* Pin Settings */
phy_set_bb_reg(adapter, ODM_REG_PIN_CTRL_11N, BIT(9) | BIT(8), 0);
phy_set_bb_reg(adapter, ODM_REG_RX_ANT_CTRL_11N, BIT(10), 0);
@@ -44,7 +44,7 @@ static void dm_trx_hw_antenna_div_init(struct odm_dm_struct *dm_odm)
struct adapter *adapter = dm_odm->Adapter;
u32 value32;
- if (*(dm_odm->mp_mode) == 1) {
+ if (*dm_odm->mp_mode == 1) {
dm_odm->AntDivType = CGCS_RX_SW_ANTDIV;
phy_set_bb_reg(adapter, ODM_REG_IGI_A_11N, BIT(7), 0);
phy_set_bb_reg(adapter, ODM_REG_RX_ANT_CTRL_11N,
@@ -55,7 +55,7 @@ static void dm_trx_hw_antenna_div_init(struct odm_dm_struct *dm_odm)
/* MAC Setting */
value32 = phy_query_bb_reg(adapter, ODM_REG_ANTSEL_PIN_11N, bMaskDWord);
phy_set_bb_reg(adapter, ODM_REG_ANTSEL_PIN_11N, bMaskDWord,
- value32|(BIT(23) | BIT(25)));
+ value32 | (BIT(23) | BIT(25)));
/* Pin Settings */
phy_set_bb_reg(adapter, ODM_REG_PIN_CTRL_11N, BIT(9) | BIT(8), 0);
phy_set_bb_reg(adapter, ODM_REG_RX_ANT_CTRL_11N, BIT(10), 0);
@@ -88,11 +88,9 @@ static void dm_fast_training_init(struct odm_dm_struct *dm_odm)
struct adapter *adapter = dm_odm->Adapter;
u32 value32, i;
struct fast_ant_train *dm_fat_tbl = &dm_odm->DM_FatTable;
- u32 AntCombination = 2;
- if (*(dm_odm->mp_mode) == 1) {
+ if (*dm_odm->mp_mode == 1)
return;
- }
for (i = 0; i < 6; i++) {
dm_fat_tbl->Bssid[i] = 0;
@@ -105,9 +103,11 @@ static void dm_fast_training_init(struct odm_dm_struct *dm_odm)
/* MAC Setting */
value32 = phy_query_bb_reg(adapter, 0x4c, bMaskDWord);
- phy_set_bb_reg(adapter, 0x4c, bMaskDWord, value32|(BIT(23) | BIT(25)));
+ phy_set_bb_reg(adapter, 0x4c, bMaskDWord,
+ value32 | (BIT(23) | BIT(25)));
value32 = phy_query_bb_reg(adapter, 0x7B4, bMaskDWord);
- phy_set_bb_reg(adapter, 0x7b4, bMaskDWord, value32|(BIT(16) | BIT(17)));
+ phy_set_bb_reg(adapter, 0x7b4, bMaskDWord,
+ value32 | (BIT(16) | BIT(17)));
/* Match MAC ADDR */
phy_set_bb_reg(adapter, 0x7b4, 0xFFFF, 0);
@@ -120,35 +120,12 @@ static void dm_fast_training_init(struct odm_dm_struct *dm_odm)
phy_set_bb_reg(adapter, 0xca4, bMaskDWord, 0x000000a0);
/* antenna mapping table */
- if (AntCombination == 2) {
- if (!dm_odm->bIsMPChip) { /* testchip */
- phy_set_bb_reg(adapter, 0x858, BIT(10) | BIT(9) | BIT(8), 1);
- phy_set_bb_reg(adapter, 0x858, BIT(13) | BIT(12) | BIT(11), 2);
- } else { /* MPchip */
- phy_set_bb_reg(adapter, 0x914, bMaskByte0, 1);
- phy_set_bb_reg(adapter, 0x914, bMaskByte1, 2);
- }
- } else if (AntCombination == 7) {
- if (!dm_odm->bIsMPChip) { /* testchip */
- phy_set_bb_reg(adapter, 0x858, BIT(10) | BIT(9) | BIT(8), 0);
- phy_set_bb_reg(adapter, 0x858, BIT(13) | BIT(12) | BIT(11), 1);
- phy_set_bb_reg(adapter, 0x878, BIT(16), 0);
- phy_set_bb_reg(adapter, 0x858, BIT(15) | BIT(14), 2);
- phy_set_bb_reg(adapter, 0x878, BIT(19) | BIT(18) | BIT(17), 3);
- phy_set_bb_reg(adapter, 0x878, BIT(22) | BIT(21) | BIT(20), 4);
- phy_set_bb_reg(adapter, 0x878, BIT(25) | BIT(24) | BIT(23), 5);
- phy_set_bb_reg(adapter, 0x878, BIT(28) | BIT(27) | BIT(26), 6);
- phy_set_bb_reg(adapter, 0x878, BIT(31) | BIT(30) | BIT(29), 7);
- } else { /* MPchip */
- phy_set_bb_reg(adapter, 0x914, bMaskByte0, 0);
- phy_set_bb_reg(adapter, 0x914, bMaskByte1, 1);
- phy_set_bb_reg(adapter, 0x914, bMaskByte2, 2);
- phy_set_bb_reg(adapter, 0x914, bMaskByte3, 3);
- phy_set_bb_reg(adapter, 0x918, bMaskByte0, 4);
- phy_set_bb_reg(adapter, 0x918, bMaskByte1, 5);
- phy_set_bb_reg(adapter, 0x918, bMaskByte2, 6);
- phy_set_bb_reg(adapter, 0x918, bMaskByte3, 7);
- }
+ if (!dm_odm->bIsMPChip) { /* testchip */
+ phy_set_bb_reg(adapter, 0x858, BIT(10) | BIT(9) | BIT(8), 1);
+ phy_set_bb_reg(adapter, 0x858, BIT(13) | BIT(12) | BIT(11), 2);
+ } else { /* MPchip */
+ phy_set_bb_reg(adapter, 0x914, bMaskByte0, 1);
+ phy_set_bb_reg(adapter, 0x914, bMaskByte1, 2);
}
/* Default Ant Setting when no fast training */
@@ -157,7 +134,7 @@ static void dm_fast_training_init(struct odm_dm_struct *dm_odm)
phy_set_bb_reg(adapter, 0x864, BIT(8) | BIT(7) | BIT(6), 1);
/* Enter Traing state */
- phy_set_bb_reg(adapter, 0x864, BIT(2) | BIT(1) | BIT(0), (AntCombination-1));
+ phy_set_bb_reg(adapter, 0x864, BIT(2) | BIT(1) | BIT(0), 1);
phy_set_bb_reg(adapter, 0xc50, BIT(7), 1);
}
@@ -219,8 +196,8 @@ static void update_tx_ant_88eu(struct odm_dm_struct *dm_odm, u8 ant, u32 mac_id)
else
target_ant = AUX_ANT_CG_TRX;
dm_fat_tbl->antsel_a[mac_id] = target_ant & BIT(0);
- dm_fat_tbl->antsel_b[mac_id] = (target_ant & BIT(1))>>1;
- dm_fat_tbl->antsel_c[mac_id] = (target_ant & BIT(2))>>2;
+ dm_fat_tbl->antsel_b[mac_id] = (target_ant & BIT(1)) >> 1;
+ dm_fat_tbl->antsel_c[mac_id] = (target_ant & BIT(2)) >> 2;
}
void rtl88eu_dm_set_tx_ant_by_tx_info(struct odm_dm_struct *dm_odm,
@@ -273,11 +250,13 @@ static void rtl88eu_dm_hw_ant_div(struct odm_dm_struct *dm_odm)
for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) {
entry = dm_odm->pODM_StaInfo[i];
if (IS_STA_VALID(entry)) {
- /* 2 Caculate RSSI per Antenna */
+ /* 2 Calculate RSSI per Antenna */
main_rssi = (dm_fat_tbl->MainAnt_Cnt[i] != 0) ?
- (dm_fat_tbl->MainAnt_Sum[i]/dm_fat_tbl->MainAnt_Cnt[i]) : 0;
+ (dm_fat_tbl->MainAnt_Sum[i] /
+ dm_fat_tbl->MainAnt_Cnt[i]) : 0;
aux_rssi = (dm_fat_tbl->AuxAnt_Cnt[i] != 0) ?
- (dm_fat_tbl->AuxAnt_Sum[i]/dm_fat_tbl->AuxAnt_Cnt[i]) : 0;
+ (dm_fat_tbl->AuxAnt_Sum[i] /
+ dm_fat_tbl->AuxAnt_Cnt[i]) : 0;
target_ant = (main_rssi >= aux_rssi) ? MAIN_ANT : AUX_ANT;
/* 2 Select max_rssi for DIG */
local_max_rssi = max(main_rssi, aux_rssi);
diff --git a/drivers/staging/rtl8188eu/hal/phy.c b/drivers/staging/rtl8188eu/hal/phy.c
index 3c7cf8720df8..482d48e003b7 100644
--- a/drivers/staging/rtl8188eu/hal/phy.c
+++ b/drivers/staging/rtl8188eu/hal/phy.c
@@ -298,25 +298,6 @@ void rtw_hal_set_chan(struct adapter *adapt, u8 channel)
#define ODM_TXPWRTRACK_MAX_IDX_88E 6
-static u8 get_right_chnl_for_iqk(u8 chnl)
-{
- u8 place;
- u8 channel_all[ODM_TARGET_CHNL_NUM_2G_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, 149, 151, 153,
- 155, 157, 159, 161, 163, 165
- };
-
- if (chnl > 14) {
- for (place = 0; place < sizeof(channel_all); place++) {
- if (channel_all[place] == chnl)
- return ++place;
- }
- }
- return 0;
-}
-
void rtl88eu_dm_txpower_track_adjust(struct odm_dm_struct *dm_odm, u8 type,
u8 *direction, u32 *out_write_val)
{
@@ -1215,7 +1196,7 @@ void rtl88eu_phy_iq_calibrate(struct adapter *adapt, bool recovery)
{
struct odm_dm_struct *dm_odm = &adapt->HalData->odmpriv;
s32 result[4][8];
- u8 i, final, chn_index;
+ u8 i, final;
bool pathaok, pathbok;
s32 reg_e94, reg_e9c, reg_ea4, reg_eb4, reg_ebc, reg_ec4;
bool is12simular, is13simular, is23simular;
@@ -1324,12 +1305,10 @@ void rtl88eu_phy_iq_calibrate(struct adapter *adapt, bool recovery)
(reg_ec4 == 0));
}
- chn_index = get_right_chnl_for_iqk(adapt->HalData->CurrentChannel);
-
if (final < 4) {
for (i = 0; i < IQK_Matrix_REG_NUM; i++)
- dm_odm->RFCalibrateInfo.IQKMatrixRegSetting[chn_index].Value[0][i] = result[final][i];
- dm_odm->RFCalibrateInfo.IQKMatrixRegSetting[chn_index].bIQKDone = true;
+ dm_odm->RFCalibrateInfo.IQKMatrixRegSetting[0].Value[0][i] = result[final][i];
+ dm_odm->RFCalibrateInfo.IQKMatrixRegSetting[0].bIQKDone = true;
}
save_adda_registers(adapt, iqk_bb_reg_92c,
diff --git a/drivers/staging/rtl8188eu/hal/pwrseq.c b/drivers/staging/rtl8188eu/hal/pwrseq.c
index 4aa1dec0b5e4..f7890a8f4673 100644
--- a/drivers/staging/rtl8188eu/hal/pwrseq.c
+++ b/drivers/staging/rtl8188eu/hal/pwrseq.c
@@ -8,9 +8,8 @@
#include "pwrseq.h"
#include <rtl8188e_hal.h>
-/*
- drivers should parse below arrays and do the corresponding actions
-*/
+/* drivers should parse below arrays and do the corresponding actions */
+
/* 3 Power on Array */
struct wl_pwr_cfg rtl8188E_power_on_flow[RTL8188E_TRANS_CARDEMU_TO_ACT_STEPS +
RTL8188E_TRANS_END_STEPS] = {
diff --git a/drivers/staging/rtl8188eu/hal/rf_cfg.c b/drivers/staging/rtl8188eu/hal/rf_cfg.c
index 0700d8bd448d..02aeb12c9870 100644
--- a/drivers/staging/rtl8188eu/hal/rf_cfg.c
+++ b/drivers/staging/rtl8188eu/hal/rf_cfg.c
@@ -177,7 +177,7 @@ static void rtl8188e_config_rf_reg(struct adapter *adapt,
u32 content = 0x1000; /*RF Content: radio_a_txt*/
u32 maskforphyset = content & 0xE000;
- rtl_rfreg_delay(adapt, RF90_PATH_A, addr | maskforphyset,
+ rtl_rfreg_delay(adapt, RF_PATH_A, addr | maskforphyset,
RFREG_OFFSET_MASK,
data);
}
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c b/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c
index 607170775fa5..31e80d693f32 100644
--- a/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c
@@ -240,8 +240,7 @@ s32 InitLLTTable(struct adapter *padapter, u8 txpktbuf_bndy)
return status;
}
-void
-Hal_InitPGData88E(struct adapter *padapter)
+void Hal_InitPGData88E(struct adapter *padapter)
{
struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter);
@@ -258,11 +257,7 @@ Hal_InitPGData88E(struct adapter *padapter)
}
}
-void
-Hal_EfuseParseIDCode88E(
- struct adapter *padapter,
- u8 *hwinfo
- )
+void Hal_EfuseParseIDCode88E(struct adapter *padapter, u8 *hwinfo)
{
struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter);
u16 EEPROMId;
@@ -378,58 +373,20 @@ static void Hal_ReadPowerValueFromPROM_8188E(struct txpowerinfo24g *pwrInfo24G,
}
}
-static u8 Hal_GetChnlGroup88E(u8 chnl, u8 *pGroup)
+static void Hal_GetChnlGroup88E(u8 chnl, u8 *group)
{
- u8 bIn24G = true;
-
- if (chnl <= 14) {
- bIn24G = true;
-
- if (chnl < 3) /* Channel 1-2 */
- *pGroup = 0;
- else if (chnl < 6) /* Channel 3-5 */
- *pGroup = 1;
- else if (chnl < 9) /* Channel 6-8 */
- *pGroup = 2;
- else if (chnl < 12) /* Channel 9-11 */
- *pGroup = 3;
- else if (chnl < 14) /* Channel 12-13 */
- *pGroup = 4;
- else if (chnl == 14) /* Channel 14 */
- *pGroup = 5;
- } else {
- /* probably, this branch is suitable only for 5 GHz */
-
- bIn24G = false;
-
- if (chnl <= 40)
- *pGroup = 0;
- else if (chnl <= 48)
- *pGroup = 1;
- else if (chnl <= 56)
- *pGroup = 2;
- else if (chnl <= 64)
- *pGroup = 3;
- else if (chnl <= 104)
- *pGroup = 4;
- else if (chnl <= 112)
- *pGroup = 5;
- else if (chnl <= 120)
- *pGroup = 5;
- else if (chnl <= 128)
- *pGroup = 6;
- else if (chnl <= 136)
- *pGroup = 7;
- else if (chnl <= 144)
- *pGroup = 8;
- else if (chnl <= 153)
- *pGroup = 9;
- else if (chnl <= 161)
- *pGroup = 10;
- else if (chnl <= 177)
- *pGroup = 11;
- }
- return bIn24G;
+ if (chnl < 3) /* Channel 1-2 */
+ *group = 0;
+ else if (chnl < 6) /* Channel 3-5 */
+ *group = 1;
+ else if (chnl < 9) /* Channel 6-8 */
+ *group = 2;
+ else if (chnl < 12) /* Channel 9-11 */
+ *group = 3;
+ else if (chnl < 14) /* Channel 12-13 */
+ *group = 4;
+ else if (chnl == 14) /* Channel 14 */
+ *group = 5;
}
void Hal_ReadPowerSavingMode88E(struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail)
@@ -461,7 +418,7 @@ void Hal_ReadTxPowerInfo88E(struct adapter *padapter, u8 *PROMContent, bool Auto
struct hal_data_8188e *pHalData = padapter->HalData;
struct txpowerinfo24g pwrInfo24G;
u8 ch, group;
- u8 bIn24G, TxCount;
+ u8 TxCount;
Hal_ReadPowerValueFromPROM_8188E(&pwrInfo24G, PROMContent, AutoLoadFail);
@@ -469,19 +426,16 @@ void Hal_ReadTxPowerInfo88E(struct adapter *padapter, u8 *PROMContent, bool Auto
pHalData->bTXPowerDataReadFromEEPORM = true;
for (ch = 0; ch < CHANNEL_MAX_NUMBER; ch++) {
- bIn24G = Hal_GetChnlGroup88E(ch, &group);
- if (bIn24G) {
- pHalData->Index24G_CCK_Base[0][ch] = pwrInfo24G.IndexCCK_Base[0][group];
- if (ch == 14)
- pHalData->Index24G_BW40_Base[0][ch] = pwrInfo24G.IndexBW40_Base[0][4];
- else
- pHalData->Index24G_BW40_Base[0][ch] = pwrInfo24G.IndexBW40_Base[0][group];
- }
- if (bIn24G) {
- 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]);
- }
+ Hal_GetChnlGroup88E(ch, &group);
+ pHalData->Index24G_CCK_Base[0][ch] = pwrInfo24G.IndexCCK_Base[0][group];
+ if (ch == 14)
+ 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];
@@ -551,8 +505,7 @@ void Hal_EfuseParseEEPROMVer88E(struct adapter *padapter, u8 *hwinfo, bool AutoL
void rtl8188e_EfuseParseChnlPlan(struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail)
{
padapter->mlmepriv.ChannelPlan =
- hal_com_get_channel_plan(padapter,
- hwinfo ? hwinfo[EEPROM_ChannelPlan_88E] : 0xFF,
+ hal_com_get_channel_plan(hwinfo ? hwinfo[EEPROM_ChannelPlan_88E] : 0xFF,
padapter->registrypriv.channel_plan,
RT_CHANNEL_DOMAIN_WORLD_WIDE_13, AutoLoadFail);
diff --git a/drivers/staging/rtl8188eu/hal/usb_halinit.c b/drivers/staging/rtl8188eu/hal/usb_halinit.c
index 12864b648fa8..70c02c49b177 100644
--- a/drivers/staging/rtl8188eu/hal/usb_halinit.c
+++ b/drivers/staging/rtl8188eu/hal/usb_halinit.c
@@ -52,7 +52,7 @@ static bool HalUsbSetQueuePipeMapping8188EUsb(struct adapter *adapt, u8 NumInPip
/* All config other than above support one Bulk IN and one Interrupt IN. */
- result = Hal_MappingOutPipe(adapt, NumOutPipe);
+ result = hal_mapping_out_pipe(adapt, NumOutPipe);
return result;
}
@@ -785,13 +785,13 @@ 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);
+ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_TURN_ON_BLOCK);
_BBTurnOnBlock(Adapter);
-HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_SECURITY);
+ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_SECURITY);
invalidate_cam_all(Adapter);
-HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MISC11);
+ 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);
@@ -816,7 +816,7 @@ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MISC11);
/* Nav limit , suggest by scott */
usb_write8(Adapter, 0x652, 0x0);
-HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_HAL_DM);
+ 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 */
@@ -840,8 +840,8 @@ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_HAL_DM);
/* 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. */
+ 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) {
rtl88eu_phy_iq_calibrate(Adapter, true);
@@ -850,12 +850,12 @@ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_IQK);
haldata->odmpriv.RFCalibrateInfo.bIQKInitialized = true;
}
-HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_PW_TRACK);
+ 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_LCK);
+ rtl88eu_phy_lc_calibrate(Adapter);
}
/* HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_PABIAS); */
@@ -866,7 +866,7 @@ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_LCK);
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);
+ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_END);
DBG_88E("%s in %dms\n", __func__,
jiffies_to_msecs(jiffies - init_start_time));
@@ -980,7 +980,7 @@ u32 rtw_hal_inirp_init(struct adapter *Adapter)
/* 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) == false) {
+ 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;
@@ -1267,7 +1267,7 @@ void rtw_hal_set_hwreg(struct adapter *Adapter, u8 variable, u8 *val)
/* Select RRSR (in Legacy-OFDM and CCK) */
/* For 8190, we select only 24M, 12M, 6M, 11M, 5.5M, 2M, and 1M from the Basic rate. */
/* We do not use other rates. */
- HalSetBrateCfg(Adapter, val, &BrateCfg);
+ hal_set_brate_cfg(val, &BrateCfg);
DBG_88E("HW_VAR_BASIC_RATE: BrateCfg(%#x)\n", BrateCfg);
/* 2011.03.30 add by Luke Lee */
diff --git a/drivers/staging/rtl8188eu/include/drv_types.h b/drivers/staging/rtl8188eu/include/drv_types.h
index 4ae095837bef..35c0946bc65d 100644
--- a/drivers/staging/rtl8188eu/include/drv_types.h
+++ b/drivers/staging/rtl8188eu/include/drv_types.h
@@ -24,11 +24,16 @@
#include <rtw_recv.h>
#include <hal_intf.h>
#include <hal_com.h>
-#include <rtw_qos.h>
#include <rtw_security.h>
#include <rtw_pwrctrl.h>
#include <rtw_eeprom.h>
#include <sta_info.h>
+
+struct qos_priv {
+ /* bit mask option: u-apsd, s-apsd, ts, block ack... */
+ unsigned int qos_option;
+};
+
#include <rtw_mlme.h>
#include <rtw_debug.h>
#include <rtw_rf.h>
diff --git a/drivers/staging/rtl8188eu/include/hal_com.h b/drivers/staging/rtl8188eu/include/hal_com.h
index 428a2a92820e..2f7bdade40a5 100644
--- a/drivers/staging/rtl8188eu/include/hal_com.h
+++ b/drivers/staging/rtl8188eu/include/hal_com.h
@@ -139,18 +139,14 @@ void dump_chip_info(struct HAL_VERSION ChipVersion);
/* return the final channel plan decision */
-u8 hal_com_get_channel_plan(struct adapter *padapter,
- u8 hw_channel_plan,
- u8 sw_channel_plan,
- u8 def_channel_plan,
- bool AutoLoadFail
-);
+u8 hal_com_get_channel_plan(u8 hw_channel_plan, u8 sw_channel_plan,
+ u8 def_channel_plan, bool load_fail);
u8 MRateToHwRate(u8 rate);
-void HalSetBrateCfg(struct adapter *Adapter, u8 *mBratesOS, u16 *pBrateCfg);
+void hal_set_brate_cfg(u8 *brates, u16 *rate_cfg);
-bool Hal_MappingOutPipe(struct adapter *pAdapter, u8 NumOutPipe);
+bool hal_mapping_out_pipe(struct adapter *adapter, u8 numoutpipe);
void hal_init_macaddr(struct adapter *adapter);
#endif /* __HAL_COMMON_H__ */
diff --git a/drivers/staging/rtl8188eu/include/odm_HWConfig.h b/drivers/staging/rtl8188eu/include/odm_hwconfig.h
index 8cef32dc6350..8cef32dc6350 100644
--- a/drivers/staging/rtl8188eu/include/odm_HWConfig.h
+++ b/drivers/staging/rtl8188eu/include/odm_hwconfig.h
diff --git a/drivers/staging/rtl8188eu/include/odm_precomp.h b/drivers/staging/rtl8188eu/include/odm_precomp.h
index 658a938df4c1..6efddc8f1675 100644
--- a/drivers/staging/rtl8188eu/include/odm_precomp.h
+++ b/drivers/staging/rtl8188eu/include/odm_precomp.h
@@ -22,14 +22,14 @@
/* 2 OutSrc Header Files */
#include "odm.h"
-#include "odm_HWConfig.h"
+#include "odm_hwconfig.h"
#include "odm_debug.h"
#include "../../rtlwifi/phydm/phydm_regdefine11n.h"
#include "hal8188e_rate_adaptive.h" /* for RA,Power training */
#include "rtl8188e_hal.h"
-#include "odm_reg.h"
+#include "../../rtlwifi/phydm/phydm_reg.h"
#include "odm_rtl8188e.h"
diff --git a/drivers/staging/rtl8188eu/include/odm_reg.h b/drivers/staging/rtl8188eu/include/odm_reg.h
deleted file mode 100644
index b56549ba1256..000000000000
--- a/drivers/staging/rtl8188eu/include/odm_reg.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
- *
- ******************************************************************************/
-/* */
-/* File Name: odm_reg.h */
-/* */
-/* Description: */
-/* */
-/* This file is for general register definition. */
-/* */
-/* */
-/* */
-#ifndef __HAL_ODM_REG_H__
-#define __HAL_ODM_REG_H__
-
-/* */
-/* Register Definition */
-/* */
-
-/* MAC REG */
-#define ODM_BB_RESET 0x002
-#define ODM_DUMMY 0x4fe
-#define ODM_EDCA_VO_PARAM 0x500
-#define ODM_EDCA_VI_PARAM 0x504
-#define ODM_EDCA_BE_PARAM 0x508
-#define ODM_EDCA_BK_PARAM 0x50C
-#define ODM_TXPAUSE 0x522
-
-/* BB REG */
-#define ODM_FPGA_PHY0_PAGE8 0x800
-#define ODM_PSD_SETTING 0x808
-#define ODM_AFE_SETTING 0x818
-#define ODM_TXAGC_B_6_18 0x830
-#define ODM_TXAGC_B_24_54 0x834
-#define ODM_TXAGC_B_MCS32_5 0x838
-#define ODM_TXAGC_B_MCS0_MCS3 0x83c
-#define ODM_TXAGC_B_MCS4_MCS7 0x848
-#define ODM_TXAGC_B_MCS8_MCS11 0x84c
-#define ODM_ANALOG_REGISTER 0x85c
-#define ODM_RF_INTERFACE_OUTPUT 0x860
-#define ODM_TXAGC_B_MCS12_MCS15 0x868
-#define ODM_TXAGC_B_11_A_2_11 0x86c
-#define ODM_AD_DA_LSB_MASK 0x874
-#define ODM_ENABLE_3_WIRE 0x88c
-#define ODM_PSD_REPORT 0x8b4
-#define ODM_R_ANT_SELECT 0x90c
-#define ODM_CCK_ANT_SELECT 0xa07
-#define ODM_CCK_PD_THRESH 0xa0a
-#define ODM_CCK_RF_REG1 0xa11
-#define ODM_CCK_MATCH_FILTER 0xa20
-#define ODM_CCK_RAKE_MAC 0xa2e
-#define ODM_CCK_CNT_RESET 0xa2d
-#define ODM_CCK_TX_DIVERSITY 0xa2f
-#define ODM_CCK_FA_CNT_MSB 0xa5b
-#define ODM_CCK_FA_CNT_LSB 0xa5c
-#define ODM_CCK_NEW_FUNCTION 0xa75
-#define ODM_OFDM_PHY0_PAGE_C 0xc00
-#define ODM_OFDM_RX_ANT 0xc04
-#define ODM_R_A_RXIQI 0xc14
-#define ODM_R_A_AGC_CORE1 0xc50
-#define ODM_R_A_AGC_CORE2 0xc54
-#define ODM_R_B_AGC_CORE1 0xc58
-#define ODM_R_AGC_PAR 0xc70
-#define ODM_R_HTSTF_AGC_PAR 0xc7c
-#define ODM_TX_PWR_TRAINING_A 0xc90
-#define ODM_TX_PWR_TRAINING_B 0xc98
-#define ODM_OFDM_FA_CNT1 0xcf0
-#define ODM_OFDM_PHY0_PAGE_D 0xd00
-#define ODM_OFDM_FA_CNT2 0xda0
-#define ODM_OFDM_FA_CNT3 0xda4
-#define ODM_OFDM_FA_CNT4 0xda8
-#define ODM_TXAGC_A_6_18 0xe00
-#define ODM_TXAGC_A_24_54 0xe04
-#define ODM_TXAGC_A_1_MCS32 0xe08
-#define ODM_TXAGC_A_MCS0_MCS3 0xe10
-#define ODM_TXAGC_A_MCS4_MCS7 0xe14
-#define ODM_TXAGC_A_MCS8_MCS11 0xe18
-#define ODM_TXAGC_A_MCS12_MCS15 0xe1c
-
-/* RF REG */
-#define ODM_GAIN_SETTING 0x00
-#define ODM_CHANNEL 0x18
-
-/* Ant Detect Reg */
-#define ODM_DPDT 0x300
-
-/* PSD Init */
-#define ODM_PSDREG 0x808
-
-/* 92D Path Div */
-#define PATHDIV_REG 0xB30
-#define PATHDIV_TRI 0xBA0
-
-
-/* */
-/* Bitmap Definition */
-/* */
-
-#define BIT_FA_RESET BIT(0)
-
-
-
-#endif
diff --git a/drivers/staging/rtl8188eu/include/osdep_service.h b/drivers/staging/rtl8188eu/include/osdep_service.h
index fbcba79a0927..cfe5698fbbb1 100644
--- a/drivers/staging/rtl8188eu/include/osdep_service.h
+++ b/drivers/staging/rtl8188eu/include/osdep_service.h
@@ -64,8 +64,6 @@ static inline int rtw_netif_queue_stopped(struct net_device *pnetdev)
u8 *_rtw_malloc(u32 sz);
#define rtw_malloc(sz) _rtw_malloc((sz))
-void *rtw_malloc2d(int h, int w, int size);
-
void _rtw_init_queue(struct __queue *pqueue);
struct rtw_netdev_priv_indicator {
diff --git a/drivers/staging/rtl8188eu/include/phy.h b/drivers/staging/rtl8188eu/include/phy.h
index e99ac3910787..40901d6dcaf5 100644
--- a/drivers/staging/rtl8188eu/include/phy.h
+++ b/drivers/staging/rtl8188eu/include/phy.h
@@ -4,7 +4,6 @@
#define IQK_DELAY_TIME_88E 10
#define index_mapping_NUM_88E 15
#define AVG_THERMAL_NUM_88E 4
-#define ODM_TARGET_CHNL_NUM_2G_5G 59
bool rtl88eu_phy_mac_config(struct adapter *adapt);
bool rtl88eu_phy_rf_config(struct adapter *adapt);
diff --git a/drivers/staging/rtl8188eu/include/rtw_mlme.h b/drivers/staging/rtl8188eu/include/rtw_mlme.h
index 35997c521c35..8d9d663f0645 100644
--- a/drivers/staging/rtl8188eu/include/rtw_mlme.h
+++ b/drivers/staging/rtl8188eu/include/rtw_mlme.h
@@ -214,7 +214,7 @@ void hostapd_mode_unload(struct adapter *padapter);
extern unsigned char WPA_TKIP_CIPHER[4];
extern unsigned char RSN_TKIP_CIPHER[4];
extern unsigned char REALTEK_96B_IE[];
-extern unsigned char MCS_rate_1R[16];
+extern const u8 MCS_rate_1R[16];
void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf);
void rtw_survey_event_callback(struct adapter *adapter, u8 *pbuf);
@@ -311,7 +311,6 @@ void rtw_free_assoc_resources_locked(struct adapter *adapter);
void rtw_indicate_disconnect(struct adapter *adapter);
void rtw_indicate_connect(struct adapter *adapter);
void rtw_indicate_scan_done(struct adapter *padapter, bool aborted);
-void rtw_scan_abort(struct adapter *adapter);
int rtw_restruct_sec_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie,
uint in_len);
diff --git a/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h b/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h
index ade68af15e04..9526da3efcc4 100644
--- a/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h
+++ b/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h
@@ -231,22 +231,22 @@ enum SCAN_STATE {
};
struct mlme_handler {
- unsigned int num;
- char *str;
+ unsigned int num;
+ const char *str;
unsigned int (*func)(struct adapter *adapt, struct recv_frame *frame);
};
struct action_handler {
- unsigned int num;
- char *str;
+ unsigned int num;
+ const char *str;
unsigned int (*func)(struct adapter *adapt, struct recv_frame *frame);
};
-struct ss_res {
- int state;
- int bss_cnt;
- int channel_idx;
- int scan_mode;
+struct ss_res {
+ int state;
+ int bss_cnt;
+ int channel_idx;
+ int scan_mode;
u8 ssid_num;
u8 ch_num;
struct ndis_802_11_ssid ssid[RTW_SSID_SCAN_AMOUNT];
diff --git a/drivers/staging/rtl8188eu/include/rtw_qos.h b/drivers/staging/rtl8188eu/include/rtw_qos.h
deleted file mode 100644
index bf617da3cd6c..000000000000
--- a/drivers/staging/rtl8188eu/include/rtw_qos.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
- *
- ******************************************************************************/
-#ifndef _RTW_QOS_H_
-#define _RTW_QOS_H_
-
-#include <osdep_service.h>
-
-struct qos_priv {
- unsigned int qos_option; /* bit mask option: u-apsd,
- * s-apsd, ts, block ack...
- */
-};
-
-#endif /* _RTL871X_QOS_H_ */
diff --git a/drivers/staging/rtl8188eu/include/wifi.h b/drivers/staging/rtl8188eu/include/wifi.h
index 259bf2cce2d5..0664d5f30a96 100644
--- a/drivers/staging/rtl8188eu/include/wifi.h
+++ b/drivers/staging/rtl8188eu/include/wifi.h
@@ -257,14 +257,6 @@ enum WIFI_REG_DOMAIN {
#define GetAddr4Ptr(pbuf) ((unsigned char *)((size_t)(pbuf) + 24))
-static inline int IS_MCAST(unsigned char *da)
-{
- if ((*da) & 0x01)
- return true;
- else
- return false;
-}
-
static inline unsigned char *get_da(unsigned char *pframe)
{
unsigned char *da;
diff --git a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c
index bee3c3a7a7a9..4ecd2ff48c41 100644
--- a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c
+++ b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c
@@ -421,7 +421,7 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param,
ret = -EOPNOTSUPP;
goto exit;
}
- memcpy(&(psecuritypriv->dot11DefKey[wep_key_idx].skey[0]), pwep->KeyMaterial, pwep->KeyLength);
+ memcpy(&(psecuritypriv->dot11DefKey[wep_key_idx].skey[0]), pwep->KeyMaterial, pwep->KeyLength);
psecuritypriv->dot11DefKeylen[wep_key_idx] = pwep->KeyLength;
rtw_set_key(padapter, psecuritypriv, wep_key_idx, 0);
}
@@ -737,7 +737,7 @@ static int rtw_wx_set_mode(struct net_device *dev, struct iw_request_info *a,
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) == false) {
+ if (!rtw_set_802_11_infrastructure_mode(padapter, networkType)) {
ret = -EPERM;
goto exit;
}
@@ -1000,8 +1000,7 @@ static int rtw_wx_set_wap(struct net_device *dev,
spin_unlock_bh(&queue->lock);
rtw_set_802_11_authentication_mode(padapter, authmode);
- /* set_802_11_encryption_mode(padapter, padapter->securitypriv.ndisencryptstatus); */
- if (rtw_set_802_11_bssid(padapter, temp->sa_data) == false) {
+ if (!rtw_set_802_11_bssid(padapter, temp->sa_data)) {
ret = -1;
goto exit;
}
@@ -1317,8 +1316,8 @@ static int rtw_wx_set_essid(struct net_device *dev,
RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("rtw_wx_set_essid: ssid =[%s]\n", src_ssid));
spin_lock_bh(&queue->lock);
- phead = get_list_head(queue);
- pmlmepriv->pscanned = phead->next;
+ phead = get_list_head(queue);
+ pmlmepriv->pscanned = phead->next;
while (phead != pmlmepriv->pscanned) {
pnetwork = container_of(pmlmepriv->pscanned, struct wlan_network, list);
@@ -1354,7 +1353,7 @@ static int rtw_wx_set_essid(struct net_device *dev,
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) == false) {
+ if (!rtw_set_802_11_ssid(padapter, &ndis_ssid)) {
ret = -1;
goto exit;
}
@@ -1370,7 +1369,7 @@ static int rtw_wx_get_essid(struct net_device *dev,
struct iw_request_info *a,
union iwreq_data *wrqu, char *extra)
{
- u32 len, ret = 0;
+ u32 len;
struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network;
@@ -1388,7 +1387,7 @@ static int rtw_wx_get_essid(struct net_device *dev,
wrqu->essid.length = len;
wrqu->essid.flags = 1;
- return ret;
+ return 0;
}
static int rtw_wx_set_rate(struct net_device *dev,
@@ -1400,7 +1399,7 @@ static int rtw_wx_set_rate(struct net_device *dev,
u32 target_rate = wrqu->bitrate.value;
u32 fixed = wrqu->bitrate.fixed;
u32 ratevalue = 0;
- u8 mpdatarate[NumRates] = {11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0xff};
+ u8 mpdatarate[NumRates] = {11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0xff};
RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, (" rtw_wx_set_rate\n"));
RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("target_rate = %d, fixed = %d\n", target_rate, fixed));
@@ -1673,7 +1672,7 @@ static int rtw_wx_set_enc(struct net_device *dev,
memcpy(wep.KeyMaterial, keybuf, wep.KeyLength);
- if (rtw_set_802_11_add_wep(padapter, &wep) == false) {
+ if (!rtw_set_802_11_add_wep(padapter, &wep)) {
if (rf_on == pwrpriv->rf_pwrstate)
ret = -EOPNOTSUPP;
goto exit;
@@ -2278,7 +2277,7 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param,
/* don't update "psecuritypriv->dot11PrivacyAlgrthm" and */
/* psecuritypriv->dot11PrivacyKeyIndex = keyid", but can rtw_set_key to cam */
- memcpy(&(psecuritypriv->dot11DefKey[wep_key_idx].skey[0]), pwep->KeyMaterial, pwep->KeyLength);
+ memcpy(&(psecuritypriv->dot11DefKey[wep_key_idx].skey[0]), pwep->KeyMaterial, pwep->KeyLength);
psecuritypriv->dot11DefKeylen[wep_key_idx] = pwep->KeyLength;
@@ -2496,7 +2495,7 @@ static int rtw_add_sta(struct net_device *dev, struct ieee_param *param)
psta->htpriv.ht_option = false;
}
- if (pmlmepriv->htpriv.ht_option == false)
+ if (!pmlmepriv->htpriv.ht_option)
psta->htpriv.ht_option = false;
update_sta_info_apmode(padapter, psta);
diff --git a/drivers/staging/rtl8188eu/os_dep/mlme_linux.c b/drivers/staging/rtl8188eu/os_dep/mlme_linux.c
index 238c1d9cdc7b..d5ceb3beabbc 100644
--- a/drivers/staging/rtl8188eu/os_dep/mlme_linux.c
+++ b/drivers/staging/rtl8188eu/os_dep/mlme_linux.c
@@ -78,7 +78,7 @@ void rtw_os_indicate_disconnect(struct adapter *adapter)
{
netif_carrier_off(adapter->pnetdev); /* Do it first for tx broadcast pkt after disconnection issue! */
rtw_indicate_wx_disassoc_event(adapter);
- rtw_reset_securitypriv(adapter);
+ rtw_reset_securitypriv(adapter);
}
void rtw_report_sec_ie(struct adapter *adapter, u8 authmode, u8 *sec_ie)
diff --git a/drivers/staging/rtl8188eu/os_dep/os_intfs.c b/drivers/staging/rtl8188eu/os_dep/os_intfs.c
index 0a9877d85c79..dac9f98b4808 100644
--- a/drivers/staging/rtl8188eu/os_dep/os_intfs.c
+++ b/drivers/staging/rtl8188eu/os_dep/os_intfs.c
@@ -643,7 +643,7 @@ int ips_netdrv_open(struct adapter *padapter)
mod_timer(&padapter->mlmepriv.dynamic_chk_timer,
jiffies + msecs_to_jiffies(5000));
- return _SUCCESS;
+ return _SUCCESS;
netdev_open_error:
DBG_88E("-ips_netdrv_open - drv_open failure, bup =%d\n", padapter->bup);
diff --git a/drivers/staging/rtl8188eu/os_dep/osdep_service.c b/drivers/staging/rtl8188eu/os_dep/osdep_service.c
index 78daef6704ac..105f3f21bdea 100644
--- a/drivers/staging/rtl8188eu/os_dep/osdep_service.c
+++ b/drivers/staging/rtl8188eu/os_dep/osdep_service.c
@@ -18,20 +18,6 @@ u8 *_rtw_malloc(u32 sz)
return kmalloc(sz, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
}
-void *rtw_malloc2d(int h, int w, int size)
-{
- int j;
- void **a = kzalloc(h * sizeof(void *) + h * w * size, GFP_KERNEL);
-
- if (!a)
- goto out;
-
- for (j = 0; j < h; j++)
- a[j] = ((char *)(a + h)) + j * w * size;
-out:
- return a;
-}
-
void _rtw_init_queue(struct __queue *pqueue)
{
INIT_LIST_HEAD(&pqueue->queue);
diff --git a/drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c b/drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c
index 5ddfc2ead127..d6a499692e96 100644
--- a/drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c
+++ b/drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c
@@ -84,7 +84,7 @@ static int recvbuf2recvframe(struct adapter *adapt, struct sk_buff *pskb)
if ((pattrib->pkt_len <= 0) || (pkt_offset > transfer_len)) {
RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("recvbuf2recvframe: pkt_len<=0\n"));
- DBG_88E("%s()-%d: RX Warning!,pkt_len<=0 or pkt_offset> transfoer_len\n", __func__, __LINE__);
+ 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;
}
@@ -606,7 +606,7 @@ static void usb_write_port_complete(struct urb *purb, struct pt_regs *regs)
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_, ("usb_write_port_complete: EINPROGESS\n"));
+ RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_write_port_complete: EINPROGRESS\n"));
goto check_completion;
} else if (purb->status == -ENOENT) {
DBG_88E("%s: -ENOENT\n", __func__);
diff --git a/drivers/staging/rtl8188eu/os_dep/xmit_linux.c b/drivers/staging/rtl8188eu/os_dep/xmit_linux.c
index d8ef9b5d81a8..017e1d628461 100644
--- a/drivers/staging/rtl8188eu/os_dep/xmit_linux.c
+++ b/drivers/staging/rtl8188eu/os_dep/xmit_linux.c
@@ -14,7 +14,8 @@
#include <xmit_osdep.h>
#include <osdep_intf.h>
-int rtw_os_xmit_resource_alloc(struct adapter *padapter, struct xmit_buf *pxmitbuf, u32 alloc_sz)
+int rtw_os_xmit_resource_alloc(struct adapter *padapter,
+ struct xmit_buf *pxmitbuf, u32 alloc_sz)
{
int i;
@@ -45,11 +46,11 @@ void rtw_os_xmit_resource_free(struct xmit_buf *pxmitbuf)
kfree(pxmitbuf->pallocated_buf);
}
-#define WMM_XMIT_THRESHOLD (NR_XMITFRAME*2/5)
+#define WMM_XMIT_THRESHOLD (NR_XMITFRAME * 2 / 5)
void rtw_os_pkt_complete(struct adapter *padapter, struct sk_buff *pkt)
{
- u16 queue;
+ u16 queue;
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
queue = skb_get_queue_mapping(pkt);
@@ -89,10 +90,11 @@ void rtw_os_xmit_schedule(struct adapter *padapter)
spin_unlock_bh(&pxmitpriv->lock);
}
-static void rtw_check_xmit_resource(struct adapter *padapter, struct sk_buff *pkt)
+static void rtw_check_xmit_resource(struct adapter *padapter,
+ struct sk_buff *pkt)
{
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
- u16 queue;
+ u16 queue;
queue = skb_get_queue_mapping(pkt);
if (padapter->registrypriv.wifi_spec) {
@@ -109,12 +111,12 @@ static void rtw_check_xmit_resource(struct adapter *padapter, struct sk_buff *pk
static int rtw_mlcst2unicst(struct adapter *padapter, struct sk_buff *skb)
{
- struct sta_priv *pstapriv = &padapter->stapriv;
+ struct sta_priv *pstapriv = &padapter->stapriv;
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
struct list_head *phead, *plist;
struct sk_buff *newskb;
struct sta_info *psta = NULL;
- s32 res;
+ s32 res;
spin_lock_bh(&pstapriv->asoc_list_lock);
phead = &pstapriv->asoc_list;
@@ -126,7 +128,7 @@ static int rtw_mlcst2unicst(struct adapter *padapter, struct sk_buff *skb)
plist = plist->next;
- /* avoid come from STA1 and send back STA1 */
+ /* avoid come from STA1 and send back STA1 */
if (!memcmp(psta->hwaddr, &skb->data[6], 6))
continue;
@@ -136,18 +138,24 @@ 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__);
+ 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__);
+ DBG_88E("%s-%d: skb_copy() failed!\n",
+ __func__, __LINE__);
pxmitpriv->tx_drop++;
spin_unlock_bh(&pstapriv->asoc_list_lock);
- return false; /* Caller shall tx this multicast frame via normal way. */
+
+ /* Caller shall tx this multicast frame
+ * via normal way.
+ */
+ return false;
}
}
@@ -156,17 +164,18 @@ static int rtw_mlcst2unicst(struct adapter *padapter, struct sk_buff *skb)
return true;
}
-int rtw_xmit_entry(struct sk_buff *pkt, struct net_device *pnetdev)
+int rtw_xmit_entry(struct sk_buff *pkt, struct net_device *pnetdev)
{
struct adapter *padapter = (struct adapter *)rtw_netdev_priv(pnetdev);
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
- struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ 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) == false) {
- RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("rtw_xmit_entry: rtw_if_up fail\n"));
+ if (!rtw_if_up(padapter)) {
+ RT_TRACE(_module_xmit_osdep_c_, _drv_err_,
+ ("%s: rtw_if_up fail\n", __func__));
goto drop_packet;
}
@@ -175,7 +184,7 @@ int rtw_xmit_entry(struct sk_buff *pkt, struct net_device *pnetdev)
if (!rtw_mc2u_disable && check_fwstate(pmlmepriv, WIFI_AP_STATE) &&
(IP_MCAST_MAC(pkt->data) || ICMPV6_MCAST_MAC(pkt->data)) &&
(padapter->registrypriv.wifi_spec == 0)) {
- if (pxmitpriv->free_xmitframe_cnt > (NR_XMITFRAME/4)) {
+ if (pxmitpriv->free_xmitframe_cnt > NR_XMITFRAME / 4) {
res = rtw_mlcst2unicst(padapter, pkt);
if (res)
goto exit;
@@ -187,13 +196,15 @@ 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_, ("rtw_xmit_entry: tx_pkts=%d\n", (u32)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_, ("rtw_xmit_entry: drop, tx_drop=%d\n", (u32)pxmitpriv->tx_drop));
+ RT_TRACE(_module_xmit_osdep_c_, _drv_notice_,
+ ("%s: drop, tx_drop=%d\n", __func__, (u32)pxmitpriv->tx_drop));
exit:
return 0;
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c
index d2605158546b..96f265eee007 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c
@@ -1149,7 +1149,7 @@ static enum reset_type _rtl92e_tx_check_stuck(struct net_device *dev)
if (skb_queue_len(&ring->queue) == 0) {
continue;
} else {
- skb = (&ring->queue)->next;
+ skb = __skb_peek(&ring->queue);
tcb_desc = (struct cb_desc *)(skb->cb +
MAX_DEV_ADDR_SIZE);
tcb_desc->nStuckCount++;
diff --git a/drivers/staging/rtl8192e/rtllib_crypt_tkip.c b/drivers/staging/rtl8192e/rtllib_crypt_tkip.c
index 9f18be14dda6..f38f1f74fcd6 100644
--- a/drivers/staging/rtl8192e/rtllib_crypt_tkip.c
+++ b/drivers/staging/rtl8192e/rtllib_crypt_tkip.c
@@ -49,9 +49,9 @@ struct rtllib_tkip_data {
u32 dot11RSNAStatsTKIPLocalMICFailures;
int key_idx;
- struct crypto_skcipher *rx_tfm_arc4;
+ struct crypto_sync_skcipher *rx_tfm_arc4;
struct crypto_shash *rx_tfm_michael;
- struct crypto_skcipher *tx_tfm_arc4;
+ struct crypto_sync_skcipher *tx_tfm_arc4;
struct crypto_shash *tx_tfm_michael;
/* scratch buffers for virt_to_page() (crypto API) */
u8 rx_hdr[16];
@@ -66,8 +66,7 @@ static void *rtllib_tkip_init(int key_idx)
if (priv == NULL)
goto fail;
priv->key_idx = key_idx;
- priv->tx_tfm_arc4 = crypto_alloc_skcipher("ecb(arc4)", 0,
- CRYPTO_ALG_ASYNC);
+ priv->tx_tfm_arc4 = crypto_alloc_sync_skcipher("ecb(arc4)", 0, 0);
if (IS_ERR(priv->tx_tfm_arc4)) {
pr_debug("Could not allocate crypto API arc4\n");
priv->tx_tfm_arc4 = NULL;
@@ -81,8 +80,7 @@ static void *rtllib_tkip_init(int key_idx)
goto fail;
}
- priv->rx_tfm_arc4 = crypto_alloc_skcipher("ecb(arc4)", 0,
- CRYPTO_ALG_ASYNC);
+ priv->rx_tfm_arc4 = crypto_alloc_sync_skcipher("ecb(arc4)", 0, 0);
if (IS_ERR(priv->rx_tfm_arc4)) {
pr_debug("Could not allocate crypto API arc4\n");
priv->rx_tfm_arc4 = NULL;
@@ -100,9 +98,9 @@ static void *rtllib_tkip_init(int key_idx)
fail:
if (priv) {
crypto_free_shash(priv->tx_tfm_michael);
- crypto_free_skcipher(priv->tx_tfm_arc4);
+ crypto_free_sync_skcipher(priv->tx_tfm_arc4);
crypto_free_shash(priv->rx_tfm_michael);
- crypto_free_skcipher(priv->rx_tfm_arc4);
+ crypto_free_sync_skcipher(priv->rx_tfm_arc4);
kfree(priv);
}
@@ -116,9 +114,9 @@ static void rtllib_tkip_deinit(void *priv)
if (_priv) {
crypto_free_shash(_priv->tx_tfm_michael);
- crypto_free_skcipher(_priv->tx_tfm_arc4);
+ crypto_free_sync_skcipher(_priv->tx_tfm_arc4);
crypto_free_shash(_priv->rx_tfm_michael);
- crypto_free_skcipher(_priv->rx_tfm_arc4);
+ crypto_free_sync_skcipher(_priv->rx_tfm_arc4);
}
kfree(priv);
}
@@ -337,7 +335,7 @@ static int rtllib_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
*pos++ = (tkey->tx_iv32 >> 24) & 0xff;
if (!tcb_desc->bHwSec) {
- SKCIPHER_REQUEST_ON_STACK(req, tkey->tx_tfm_arc4);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(req, tkey->tx_tfm_arc4);
icv = skb_put(skb, 4);
crc = ~crc32_le(~0, pos, len);
@@ -349,8 +347,8 @@ static int rtllib_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
sg_init_one(&sg, pos, len+4);
- crypto_skcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16);
- skcipher_request_set_tfm(req, tkey->tx_tfm_arc4);
+ crypto_sync_skcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16);
+ skcipher_request_set_sync_tfm(req, tkey->tx_tfm_arc4);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, &sg, &sg, len + 4, NULL);
ret = crypto_skcipher_encrypt(req);
@@ -420,7 +418,7 @@ static int rtllib_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
pos += 8;
if (!tcb_desc->bHwSec || (skb->cb[0] == 1)) {
- SKCIPHER_REQUEST_ON_STACK(req, tkey->rx_tfm_arc4);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(req, tkey->rx_tfm_arc4);
if ((iv32 < tkey->rx_iv32 ||
(iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16)) &&
@@ -447,8 +445,8 @@ static int rtllib_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
sg_init_one(&sg, pos, plen+4);
- crypto_skcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16);
- skcipher_request_set_tfm(req, tkey->rx_tfm_arc4);
+ crypto_sync_skcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16);
+ skcipher_request_set_sync_tfm(req, tkey->rx_tfm_arc4);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, &sg, &sg, plen + 4, NULL);
err = crypto_skcipher_decrypt(req);
@@ -664,9 +662,9 @@ static int rtllib_tkip_set_key(void *key, int len, u8 *seq, void *priv)
struct rtllib_tkip_data *tkey = priv;
int keyidx;
struct crypto_shash *tfm = tkey->tx_tfm_michael;
- struct crypto_skcipher *tfm2 = tkey->tx_tfm_arc4;
+ struct crypto_sync_skcipher *tfm2 = tkey->tx_tfm_arc4;
struct crypto_shash *tfm3 = tkey->rx_tfm_michael;
- struct crypto_skcipher *tfm4 = tkey->rx_tfm_arc4;
+ struct crypto_sync_skcipher *tfm4 = tkey->rx_tfm_arc4;
keyidx = tkey->key_idx;
memset(tkey, 0, sizeof(*tkey));
diff --git a/drivers/staging/rtl8192e/rtllib_crypt_wep.c b/drivers/staging/rtl8192e/rtllib_crypt_wep.c
index b3343a5d0fd6..d11ec39171d5 100644
--- a/drivers/staging/rtl8192e/rtllib_crypt_wep.c
+++ b/drivers/staging/rtl8192e/rtllib_crypt_wep.c
@@ -27,8 +27,8 @@ struct prism2_wep_data {
u8 key[WEP_KEY_LEN + 1];
u8 key_len;
u8 key_idx;
- struct crypto_skcipher *tx_tfm;
- struct crypto_skcipher *rx_tfm;
+ struct crypto_sync_skcipher *tx_tfm;
+ struct crypto_sync_skcipher *rx_tfm;
};
@@ -41,13 +41,13 @@ static void *prism2_wep_init(int keyidx)
goto fail;
priv->key_idx = keyidx;
- priv->tx_tfm = crypto_alloc_skcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
+ priv->tx_tfm = crypto_alloc_sync_skcipher("ecb(arc4)", 0, 0);
if (IS_ERR(priv->tx_tfm)) {
pr_debug("rtllib_crypt_wep: could not allocate crypto API arc4\n");
priv->tx_tfm = NULL;
goto fail;
}
- priv->rx_tfm = crypto_alloc_skcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
+ priv->rx_tfm = crypto_alloc_sync_skcipher("ecb(arc4)", 0, 0);
if (IS_ERR(priv->rx_tfm)) {
pr_debug("rtllib_crypt_wep: could not allocate crypto API arc4\n");
priv->rx_tfm = NULL;
@@ -61,8 +61,8 @@ static void *prism2_wep_init(int keyidx)
fail:
if (priv) {
- crypto_free_skcipher(priv->tx_tfm);
- crypto_free_skcipher(priv->rx_tfm);
+ crypto_free_sync_skcipher(priv->tx_tfm);
+ crypto_free_sync_skcipher(priv->rx_tfm);
kfree(priv);
}
return NULL;
@@ -74,8 +74,8 @@ static void prism2_wep_deinit(void *priv)
struct prism2_wep_data *_priv = priv;
if (_priv) {
- crypto_free_skcipher(_priv->tx_tfm);
- crypto_free_skcipher(_priv->rx_tfm);
+ crypto_free_sync_skcipher(_priv->tx_tfm);
+ crypto_free_sync_skcipher(_priv->rx_tfm);
}
kfree(priv);
}
@@ -135,7 +135,7 @@ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
memcpy(key + 3, wep->key, wep->key_len);
if (!tcb_desc->bHwSec) {
- SKCIPHER_REQUEST_ON_STACK(req, wep->tx_tfm);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(req, wep->tx_tfm);
/* Append little-endian CRC32 and encrypt it to produce ICV */
crc = ~crc32_le(~0, pos, len);
@@ -146,8 +146,8 @@ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
icv[3] = crc >> 24;
sg_init_one(&sg, pos, len+4);
- crypto_skcipher_setkey(wep->tx_tfm, key, klen);
- skcipher_request_set_tfm(req, wep->tx_tfm);
+ crypto_sync_skcipher_setkey(wep->tx_tfm, key, klen);
+ skcipher_request_set_sync_tfm(req, wep->tx_tfm);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, &sg, &sg, len + 4, NULL);
err = crypto_skcipher_encrypt(req);
@@ -199,11 +199,11 @@ static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
plen = skb->len - hdr_len - 8;
if (!tcb_desc->bHwSec) {
- SKCIPHER_REQUEST_ON_STACK(req, wep->rx_tfm);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(req, wep->rx_tfm);
sg_init_one(&sg, pos, plen+4);
- crypto_skcipher_setkey(wep->rx_tfm, key, klen);
- skcipher_request_set_tfm(req, wep->rx_tfm);
+ crypto_sync_skcipher_setkey(wep->rx_tfm, key, klen);
+ skcipher_request_set_sync_tfm(req, wep->rx_tfm);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, &sg, &sg, plen + 4, NULL);
err = crypto_skcipher_decrypt(req);
diff --git a/drivers/staging/rtl8192e/rtllib_softmac.c b/drivers/staging/rtl8192e/rtllib_softmac.c
index 919231fec09c..287d0c11fa38 100644
--- a/drivers/staging/rtl8192e/rtllib_softmac.c
+++ b/drivers/staging/rtl8192e/rtllib_softmac.c
@@ -1680,19 +1680,19 @@ inline void rtllib_softmac_new_net(struct rtllib_device *ieee,
(ssidbroad && !ssidset) || (!ssidbroad && ssidset))) ||
(!apset && ssidset && ssidbroad && ssidmatch) ||
(ieee->is_roaming && ssidset && ssidbroad && ssidmatch)) {
- /* if the essid is hidden replace it with the
- * essid provided by the user.
+ /* Save the essid so that if it is hidden, it is
+ * replaced with the essid provided by the user.
*/
if (!ssidbroad) {
- strncpy(tmp_ssid, ieee->current_network.ssid,
- IW_ESSID_MAX_SIZE);
+ memcpy(tmp_ssid, ieee->current_network.ssid,
+ ieee->current_network.ssid_len);
tmp_ssid_len = ieee->current_network.ssid_len;
}
- memcpy(&ieee->current_network, net,
- sizeof(struct rtllib_network));
+ memcpy(&ieee->current_network, net,
+ sizeof(ieee->current_network));
if (!ssidbroad) {
- strncpy(ieee->current_network.ssid, tmp_ssid,
- IW_ESSID_MAX_SIZE);
+ memcpy(ieee->current_network.ssid, tmp_ssid,
+ tmp_ssid_len);
ieee->current_network.ssid_len = tmp_ssid_len;
}
netdev_info(ieee->dev,
diff --git a/drivers/staging/rtl8192u/ieee80211/dot11d.c b/drivers/staging/rtl8192u/ieee80211/dot11d.c
index 2fb575a2b6ab..130ddfe9868f 100644
--- a/drivers/staging/rtl8192u/ieee80211/dot11d.c
+++ b/drivers/staging/rtl8192u/ieee80211/dot11d.c
@@ -3,42 +3,42 @@
#include "dot11d.h"
-void Dot11d_Init(struct ieee80211_device *ieee)
+void rtl8192u_dot11d_init(struct ieee80211_device *ieee)
{
- struct rt_dot11d_info *pDot11dInfo = GET_DOT11D_INFO(ieee);
+ struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(ieee);
- pDot11dInfo->enabled = false;
+ dot11d_info->dot11d_enabled = false;
- pDot11dInfo->state = DOT11D_STATE_NONE;
- pDot11dInfo->country_ie_len = 0;
- memset(pDot11dInfo->channel_map, 0, MAX_CHANNEL_NUMBER + 1);
- memset(pDot11dInfo->max_tx_pwr_dbm_list, 0xFF, MAX_CHANNEL_NUMBER+1);
+ dot11d_info->state = DOT11D_STATE_NONE;
+ dot11d_info->country_ie_len = 0;
+ memset(dot11d_info->channel_map, 0, MAX_CHANNEL_NUMBER + 1);
+ memset(dot11d_info->max_tx_pwr_dbm_list, 0xFF, MAX_CHANNEL_NUMBER+1);
RESET_CIE_WATCHDOG(ieee);
- netdev_info(ieee->dev, "Dot11d_Init()\n");
+ netdev_info(ieee->dev, "rtl8192u_dot11d_init()\n");
}
-EXPORT_SYMBOL(Dot11d_Init);
+EXPORT_SYMBOL(rtl8192u_dot11d_init);
/* Reset to the state as we are just entering a regulatory domain. */
-void Dot11d_Reset(struct ieee80211_device *ieee)
+void dot11d_reset(struct ieee80211_device *ieee)
{
u32 i;
- struct rt_dot11d_info *pDot11dInfo = GET_DOT11D_INFO(ieee);
+ struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(ieee);
/* Clear old channel map */
- memset(pDot11dInfo->channel_map, 0, MAX_CHANNEL_NUMBER+1);
- memset(pDot11dInfo->max_tx_pwr_dbm_list, 0xFF, MAX_CHANNEL_NUMBER+1);
+ memset(dot11d_info->channel_map, 0, MAX_CHANNEL_NUMBER+1);
+ memset(dot11d_info->max_tx_pwr_dbm_list, 0xFF, MAX_CHANNEL_NUMBER+1);
/* Set new channel map */
for (i = 1; i <= 11; i++)
- (pDot11dInfo->channel_map)[i] = 1;
+ (dot11d_info->channel_map)[i] = 1;
for (i = 12; i <= 14; i++)
- (pDot11dInfo->channel_map)[i] = 2;
+ (dot11d_info->channel_map)[i] = 2;
- pDot11dInfo->state = DOT11D_STATE_NONE;
- pDot11dInfo->country_ie_len = 0;
+ dot11d_info->state = DOT11D_STATE_NONE;
+ dot11d_info->country_ie_len = 0;
RESET_CIE_WATCHDOG(ieee);
}
-EXPORT_SYMBOL(Dot11d_Reset);
+EXPORT_SYMBOL(dot11d_reset);
/*
* Update country IE from Beacon or Probe Resopnse and configure PHY for
@@ -49,15 +49,15 @@ EXPORT_SYMBOL(Dot11d_Reset);
* 1. IS_DOT11D_ENABLE() is TRUE.
* 2. Input IE is an valid one.
*/
-void Dot11d_UpdateCountryIe(struct ieee80211_device *dev, u8 *pTaddr,
+void dot11d_update_country_ie(struct ieee80211_device *dev, u8 *pTaddr,
u16 CoutryIeLen, u8 *pCoutryIe)
{
- struct rt_dot11d_info *pDot11dInfo = GET_DOT11D_INFO(dev);
+ struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(dev);
u8 i, j, NumTriples, MaxChnlNum;
struct chnl_txpower_triple *pTriple;
- memset(pDot11dInfo->channel_map, 0, MAX_CHANNEL_NUMBER+1);
- memset(pDot11dInfo->max_tx_pwr_dbm_list, 0xFF, MAX_CHANNEL_NUMBER+1);
+ memset(dot11d_info->channel_map, 0, MAX_CHANNEL_NUMBER+1);
+ memset(dot11d_info->max_tx_pwr_dbm_list, 0xFF, MAX_CHANNEL_NUMBER+1);
MaxChnlNum = 0;
NumTriples = (CoutryIeLen - 3) / 3; /* skip 3-byte country string. */
pTriple = (struct chnl_txpower_triple *)(pCoutryIe + 3);
@@ -66,20 +66,20 @@ void Dot11d_UpdateCountryIe(struct ieee80211_device *dev, u8 *pTaddr,
/* It is not in a monotonically increasing order, so
* stop processing.
*/
- netdev_err(dev->dev, "Dot11d_UpdateCountryIe(): Invalid country IE, skip it........1\n");
+ netdev_err(dev->dev, "dot11d_update_country_ie(): Invalid country IE, skip it........1\n");
return;
}
if (MAX_CHANNEL_NUMBER < (pTriple->first_channel + pTriple->num_channels)) {
/* It is not a valid set of channel id, so stop
* processing.
*/
- netdev_err(dev->dev, "Dot11d_UpdateCountryIe(): Invalid country IE, skip it........2\n");
+ netdev_err(dev->dev, "dot11d_update_country_ie(): Invalid country IE, skip it........2\n");
return;
}
for (j = 0; j < pTriple->num_channels; j++) {
- pDot11dInfo->channel_map[pTriple->first_channel + j] = 1;
- pDot11dInfo->max_tx_pwr_dbm_list[pTriple->first_channel + j] = pTriple->max_tx_pwr_dbm;
+ dot11d_info->channel_map[pTriple->first_channel + j] = 1;
+ dot11d_info->max_tx_pwr_dbm_list[pTriple->first_channel + j] = pTriple->max_tx_pwr_dbm;
MaxChnlNum = pTriple->first_channel + j;
}
@@ -87,90 +87,90 @@ void Dot11d_UpdateCountryIe(struct ieee80211_device *dev, u8 *pTaddr,
}
netdev_info(dev->dev, "Channel List:");
for (i = 1; i <= MAX_CHANNEL_NUMBER; i++)
- if (pDot11dInfo->channel_map[i] > 0)
+ if (dot11d_info->channel_map[i] > 0)
netdev_info(dev->dev, " %d", i);
netdev_info(dev->dev, "\n");
UPDATE_CIE_SRC(dev, pTaddr);
- pDot11dInfo->country_ie_len = CoutryIeLen;
- memcpy(pDot11dInfo->country_ie_buf, pCoutryIe, CoutryIeLen);
- pDot11dInfo->state = DOT11D_STATE_LEARNED;
+ dot11d_info->country_ie_len = CoutryIeLen;
+ memcpy(dot11d_info->country_ie_buf, pCoutryIe, CoutryIeLen);
+ dot11d_info->state = DOT11D_STATE_LEARNED;
}
-EXPORT_SYMBOL(Dot11d_UpdateCountryIe);
+EXPORT_SYMBOL(dot11d_update_country_ie);
-u8 DOT11D_GetMaxTxPwrInDbm(struct ieee80211_device *dev, u8 Channel)
+u8 dot11d_get_max_tx_pwr_in_dbm(struct ieee80211_device *dev, u8 Channel)
{
- struct rt_dot11d_info *pDot11dInfo = GET_DOT11D_INFO(dev);
+ struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(dev);
u8 MaxTxPwrInDbm = 255;
if (Channel > MAX_CHANNEL_NUMBER) {
- netdev_err(dev->dev, "DOT11D_GetMaxTxPwrInDbm(): Invalid Channel\n");
+ netdev_err(dev->dev, "dot11d_get_max_tx_pwr_in_dbm(): Invalid Channel\n");
return MaxTxPwrInDbm;
}
- if (pDot11dInfo->channel_map[Channel])
- MaxTxPwrInDbm = pDot11dInfo->max_tx_pwr_dbm_list[Channel];
+ if (dot11d_info->channel_map[Channel])
+ MaxTxPwrInDbm = dot11d_info->max_tx_pwr_dbm_list[Channel];
return MaxTxPwrInDbm;
}
-EXPORT_SYMBOL(DOT11D_GetMaxTxPwrInDbm);
+EXPORT_SYMBOL(dot11d_get_max_tx_pwr_in_dbm);
-void DOT11D_ScanComplete(struct ieee80211_device *dev)
+void dot11d_scan_complete(struct ieee80211_device *dev)
{
- struct rt_dot11d_info *pDot11dInfo = GET_DOT11D_INFO(dev);
+ struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(dev);
- switch (pDot11dInfo->state) {
+ switch (dot11d_info->state) {
case DOT11D_STATE_LEARNED:
- pDot11dInfo->state = DOT11D_STATE_DONE;
+ dot11d_info->state = DOT11D_STATE_DONE;
break;
case DOT11D_STATE_DONE:
if (GET_CIE_WATCHDOG(dev) == 0) {
/* Reset country IE if previous one is gone. */
- Dot11d_Reset(dev);
+ dot11d_reset(dev);
}
break;
case DOT11D_STATE_NONE:
break;
}
}
-EXPORT_SYMBOL(DOT11D_ScanComplete);
+EXPORT_SYMBOL(dot11d_scan_complete);
-int IsLegalChannel(struct ieee80211_device *dev, u8 channel)
+int is_legal_channel(struct ieee80211_device *dev, u8 channel)
{
- struct rt_dot11d_info *pDot11dInfo = GET_DOT11D_INFO(dev);
+ struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(dev);
if (channel > MAX_CHANNEL_NUMBER) {
- netdev_err(dev->dev, "IsLegalChannel(): Invalid Channel\n");
+ netdev_err(dev->dev, "is_legal_channel(): Invalid Channel\n");
return 0;
}
- if (pDot11dInfo->channel_map[channel] > 0)
+ if (dot11d_info->channel_map[channel] > 0)
return 1;
return 0;
}
-EXPORT_SYMBOL(IsLegalChannel);
+EXPORT_SYMBOL(is_legal_channel);
-int ToLegalChannel(struct ieee80211_device *dev, u8 channel)
+int to_legal_channel(struct ieee80211_device *dev, u8 channel)
{
- struct rt_dot11d_info *pDot11dInfo = GET_DOT11D_INFO(dev);
+ struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(dev);
u8 default_chn = 0;
u32 i = 0;
for (i = 1; i <= MAX_CHANNEL_NUMBER; i++) {
- if (pDot11dInfo->channel_map[i] > 0) {
+ if (dot11d_info->channel_map[i] > 0) {
default_chn = i;
break;
}
}
if (channel > MAX_CHANNEL_NUMBER) {
- netdev_err(dev->dev, "IsLegalChannel(): Invalid Channel\n");
+ netdev_err(dev->dev, "is_legal_channel(): Invalid Channel\n");
return default_chn;
}
- if (pDot11dInfo->channel_map[channel] > 0)
+ if (dot11d_info->channel_map[channel] > 0)
return channel;
return default_chn;
}
-EXPORT_SYMBOL(ToLegalChannel);
+EXPORT_SYMBOL(to_legal_channel);
diff --git a/drivers/staging/rtl8192u/ieee80211/dot11d.h b/drivers/staging/rtl8192u/ieee80211/dot11d.h
index 363a6bed18dd..8b485fa18089 100644
--- a/drivers/staging/rtl8192u/ieee80211/dot11d.h
+++ b/drivers/staging/rtl8192u/ieee80211/dot11d.h
@@ -17,74 +17,41 @@ enum dot11d_state {
};
struct rt_dot11d_info {
- bool enabled; /* dot11MultiDomainCapabilityEnabled */
-
u16 country_ie_len; /* > 0 if country_ie_buf[] contains valid country information element. */
+
+ /* country_ie_src_addr u16 aligned for comparison and copy */
+ u8 country_ie_src_addr[ETH_ALEN]; /* Source AP of the country IE. */
u8 country_ie_buf[MAX_IE_LEN];
- u8 country_ie_src_addr[6]; /* Source AP of the country IE. */
u8 country_ie_watchdog;
u8 channel_map[MAX_CHANNEL_NUMBER + 1]; /* !Value 0: Invalid, 1: Valid (active scan), 2: Valid (passive scan) */
u8 max_tx_pwr_dbm_list[MAX_CHANNEL_NUMBER + 1];
enum dot11d_state state;
+ u8 dot11d_enabled; /* dot11MultiDomainCapabilityEnabled */
};
-#define eqMacAddr(a, b) (((a)[0] == (b)[0] && \
- (a)[1] == (b)[1] && (a)[2] == (b)[2] && (a)[3] == (b)[3] && \
- (a)[4] == (b)[4] && (a)[5] == (b)[5]) ? 1 : 0)
-#define cpMacAddr(des, src) ((des)[0] = (src)[0], \
- (des)[1] = (src)[1], (des)[2] = (src)[2], \
- (des)[3] = (src)[3], (des)[4] = (src)[4], \
- (des)[5] = (src)[5])
-#define GET_DOT11D_INFO(__pIeeeDev) ((struct rt_dot11d_info *)((__pIeeeDev)->pDot11dInfo))
-
-#define IS_DOT11D_ENABLE(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->enabled)
-#define IS_COUNTRY_IE_VALID(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->country_ie_len > 0)
-
-#define IS_EQUAL_CIE_SRC(__pIeeeDev, __pTa) eqMacAddr(GET_DOT11D_INFO(__pIeeeDev)->country_ie_src_addr, __pTa)
-#define UPDATE_CIE_SRC(__pIeeeDev, __pTa) cpMacAddr(GET_DOT11D_INFO(__pIeeeDev)->country_ie_src_addr, __pTa)
-
-#define GET_CIE_WATCHDOG(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->country_ie_watchdog)
-#define RESET_CIE_WATCHDOG(__pIeeeDev) (GET_CIE_WATCHDOG(__pIeeeDev) = 0)
-#define UPDATE_CIE_WATCHDOG(__pIeeeDev) (++GET_CIE_WATCHDOG(__pIeeeDev))
-
-void
-Dot11d_Init(
- struct ieee80211_device *dev
- );
-
-void
-Dot11d_Reset(
- struct ieee80211_device *dev
- );
+#define GET_DOT11D_INFO(ieee_dev) ((struct rt_dot11d_info *)((ieee_dev)->dot11d_info))
-void
-Dot11d_UpdateCountryIe(
- struct ieee80211_device *dev,
- u8 *pTaddr,
- u16 CoutryIeLen,
- u8 *pCoutryIe
- );
+#define IS_DOT11D_ENABLE(ieee_dev) (GET_DOT11D_INFO(ieee_dev)->dot11d_enabled)
+#define IS_COUNTRY_IE_VALID(ieee_dev) (GET_DOT11D_INFO(ieee_dev)->country_ie_len > 0)
-u8
-DOT11D_GetMaxTxPwrInDbm(
- struct ieee80211_device *dev,
- u8 Channel
- );
+#define IS_EQUAL_CIE_SRC(ieee_dev, addr) ether_addr_equal(GET_DOT11D_INFO(ieee_dev)->country_ie_src_addr, addr)
+#define UPDATE_CIE_SRC(ieee_dev, addr) ether_addr_copy(GET_DOT11D_INFO(ieee_dev)->country_ie_src_addr, addr)
-void
-DOT11D_ScanComplete(
- struct ieee80211_device *dev
- );
+#define GET_CIE_WATCHDOG(ieee_dev) (GET_DOT11D_INFO(ieee_dev)->country_ie_watchdog)
+#define RESET_CIE_WATCHDOG(ieee_dev) (GET_CIE_WATCHDOG(ieee_dev) = 0)
+#define UPDATE_CIE_WATCHDOG(ieee_dev) (++GET_CIE_WATCHDOG(ieee_dev))
-int IsLegalChannel(
- struct ieee80211_device *dev,
- u8 channel
-);
+void rtl8192u_dot11d_init(struct ieee80211_device *dev);
+void dot11d_reset(struct ieee80211_device *dev);
+void dot11d_update_country_ie(struct ieee80211_device *dev,
+ u8 *addr,
+ u16 coutry_ie_len,
+ u8 *coutry_ie);
+u8 dot11d_get_max_tx_pwr_in_dbm(struct ieee80211_device *dev, u8 channel);
+void dot11d_scan_complete(struct ieee80211_device *dev);
+int is_legal_channel(struct ieee80211_device *dev, u8 channel);
+int to_legal_channel(struct ieee80211_device *dev, u8 channel);
-int ToLegalChannel(
- struct ieee80211_device *dev,
- u8 channel
-);
#endif /* #ifndef __INC_DOT11D_H */
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211.h b/drivers/staging/rtl8192u/ieee80211/ieee80211.h
index 3cfeac0d7214..8aa536d79900 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211.h
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211.h
@@ -1329,8 +1329,13 @@ typedef enum _erp_t {
struct ieee80211_network {
/* These entries are used to identify a unique network */
- u8 bssid[ETH_ALEN];
+ u8 bssid[ETH_ALEN]; /* u16 aligned! */
u8 channel;
+
+ // CCXv4 S59, MBSSID.
+ bool bMBssidValid;
+ u8 MBssid[ETH_ALEN]; /* u16 aligned! */
+ u8 MBssidMask;
/* Ensure null-terminated for any debug msgs */
u8 ssid[IW_ESSID_MAX_SIZE + 1];
u8 ssid_len;
@@ -1341,10 +1346,6 @@ struct ieee80211_network {
bool bCkipSupported;
bool bCcxRmEnable;
u16 CcxRmState[2];
- // CCXv4 S59, MBSSID.
- bool bMBssidValid;
- u8 MBssidMask;
- u8 MBssid[6];
// CCX 2 S38, WLAN Device Version Number element. Annie, 2006-08-20.
bool bWithCcxVerNum;
u8 BssCcxVerNumber;
@@ -1771,7 +1772,7 @@ struct ieee80211_device {
/* map of allowed channels. 0 is dummy */
// FIXME: remember to default to a basic channel plan depending of the PHY type
- void *pDot11dInfo;
+ void *dot11d_info;
bool bGlobalDomain;
int rate; /* current rate */
int basic_rate;
@@ -2378,11 +2379,8 @@ u8 HTGetHighestMCSRate(struct ieee80211_device *ieee,
extern u8 MCS_FILTER_ALL[];
extern u16 MCS_DATA_RATE[2][2][77];
u8 HTCCheck(struct ieee80211_device *ieee, u8 *pFrame);
-//extern void HTSetConnectBwModeCallback(unsigned long data);
void HTResetIOTSetting(PRT_HIGH_THROUGHPUT pHTInfo);
bool IsHTHalfNmodeAPs(struct ieee80211_device *ieee);
-u16 HTHalfMcsToDataRate(struct ieee80211_device *ieee, u8 nMcsRate);
-u16 HTMcsToDataRate(struct ieee80211_device *ieee, u8 nMcsRate);
u16 TxCountToDataRate(struct ieee80211_device *ieee, u8 nDataRate);
//function in BAPROC.c
int ieee80211_rx_ADDBAReq(struct ieee80211_device *ieee, struct sk_buff *skb);
@@ -2395,7 +2393,7 @@ void TsInitDelBA(struct ieee80211_device *ieee,
void BaSetupTimeOut(struct timer_list *t);
void TxBaInactTimeout(struct timer_list *t);
void RxBaInactTimeout(struct timer_list *t);
-void ResetBaEntry(PBA_RECORD pBA);
+void ResetBaEntry(struct ba_record *pBA);
//function in TS.c
bool GetTs(
struct ieee80211_device *ieee,
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_tkip.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_tkip.c
index 1088fa0aee0e..829fa4bd253c 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_tkip.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_tkip.c
@@ -53,9 +53,9 @@ struct ieee80211_tkip_data {
int key_idx;
- struct crypto_skcipher *rx_tfm_arc4;
+ struct crypto_sync_skcipher *rx_tfm_arc4;
struct crypto_shash *rx_tfm_michael;
- struct crypto_skcipher *tx_tfm_arc4;
+ struct crypto_sync_skcipher *tx_tfm_arc4;
struct crypto_shash *tx_tfm_michael;
/* scratch buffers for virt_to_page() (crypto API) */
@@ -71,8 +71,7 @@ static void *ieee80211_tkip_init(int key_idx)
goto fail;
priv->key_idx = key_idx;
- priv->tx_tfm_arc4 = crypto_alloc_skcipher("ecb(arc4)", 0,
- CRYPTO_ALG_ASYNC);
+ priv->tx_tfm_arc4 = crypto_alloc_sync_skcipher("ecb(arc4)", 0, 0);
if (IS_ERR(priv->tx_tfm_arc4)) {
printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
"crypto API arc4\n");
@@ -88,8 +87,7 @@ static void *ieee80211_tkip_init(int key_idx)
goto fail;
}
- priv->rx_tfm_arc4 = crypto_alloc_skcipher("ecb(arc4)", 0,
- CRYPTO_ALG_ASYNC);
+ priv->rx_tfm_arc4 = crypto_alloc_sync_skcipher("ecb(arc4)", 0, 0);
if (IS_ERR(priv->rx_tfm_arc4)) {
printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
"crypto API arc4\n");
@@ -110,9 +108,9 @@ static void *ieee80211_tkip_init(int key_idx)
fail:
if (priv) {
crypto_free_shash(priv->tx_tfm_michael);
- crypto_free_skcipher(priv->tx_tfm_arc4);
+ crypto_free_sync_skcipher(priv->tx_tfm_arc4);
crypto_free_shash(priv->rx_tfm_michael);
- crypto_free_skcipher(priv->rx_tfm_arc4);
+ crypto_free_sync_skcipher(priv->rx_tfm_arc4);
kfree(priv);
}
@@ -126,9 +124,9 @@ static void ieee80211_tkip_deinit(void *priv)
if (_priv) {
crypto_free_shash(_priv->tx_tfm_michael);
- crypto_free_skcipher(_priv->tx_tfm_arc4);
+ crypto_free_sync_skcipher(_priv->tx_tfm_arc4);
crypto_free_shash(_priv->rx_tfm_michael);
- crypto_free_skcipher(_priv->rx_tfm_arc4);
+ crypto_free_sync_skcipher(_priv->rx_tfm_arc4);
}
kfree(priv);
}
@@ -340,7 +338,7 @@ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
*pos++ = (tkey->tx_iv32 >> 24) & 0xff;
if (!tcb_desc->bHwSec) {
- SKCIPHER_REQUEST_ON_STACK(req, tkey->tx_tfm_arc4);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(req, tkey->tx_tfm_arc4);
icv = skb_put(skb, 4);
crc = ~crc32_le(~0, pos, len);
@@ -348,9 +346,9 @@ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
icv[1] = crc >> 8;
icv[2] = crc >> 16;
icv[3] = crc >> 24;
- crypto_skcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16);
+ crypto_sync_skcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16);
sg_init_one(&sg, pos, len+4);
- skcipher_request_set_tfm(req, tkey->tx_tfm_arc4);
+ skcipher_request_set_sync_tfm(req, tkey->tx_tfm_arc4);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, &sg, &sg, len + 4, NULL);
ret = crypto_skcipher_encrypt(req);
@@ -418,7 +416,7 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
pos += 8;
if (!tcb_desc->bHwSec) {
- SKCIPHER_REQUEST_ON_STACK(req, tkey->rx_tfm_arc4);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(req, tkey->rx_tfm_arc4);
if (iv32 < tkey->rx_iv32 ||
(iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16)) {
@@ -440,10 +438,10 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
plen = skb->len - hdr_len - 12;
- crypto_skcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16);
+ crypto_sync_skcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16);
sg_init_one(&sg, pos, plen+4);
- skcipher_request_set_tfm(req, tkey->rx_tfm_arc4);
+ skcipher_request_set_sync_tfm(req, tkey->rx_tfm_arc4);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, &sg, &sg, plen + 4, NULL);
@@ -663,9 +661,9 @@ static int ieee80211_tkip_set_key(void *key, int len, u8 *seq, void *priv)
struct ieee80211_tkip_data *tkey = priv;
int keyidx;
struct crypto_shash *tfm = tkey->tx_tfm_michael;
- struct crypto_skcipher *tfm2 = tkey->tx_tfm_arc4;
+ struct crypto_sync_skcipher *tfm2 = tkey->tx_tfm_arc4;
struct crypto_shash *tfm3 = tkey->rx_tfm_michael;
- struct crypto_skcipher *tfm4 = tkey->rx_tfm_arc4;
+ struct crypto_sync_skcipher *tfm4 = tkey->rx_tfm_arc4;
keyidx = tkey->key_idx;
memset(tkey, 0, sizeof(*tkey));
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_wep.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_wep.c
index b9f86be9e52b..d4a1bf0caa7a 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_wep.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_wep.c
@@ -32,8 +32,8 @@ struct prism2_wep_data {
u8 key[WEP_KEY_LEN + 1];
u8 key_len;
u8 key_idx;
- struct crypto_skcipher *tx_tfm;
- struct crypto_skcipher *rx_tfm;
+ struct crypto_sync_skcipher *tx_tfm;
+ struct crypto_sync_skcipher *rx_tfm;
};
@@ -46,10 +46,10 @@ static void *prism2_wep_init(int keyidx)
return NULL;
priv->key_idx = keyidx;
- priv->tx_tfm = crypto_alloc_skcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
+ priv->tx_tfm = crypto_alloc_sync_skcipher("ecb(arc4)", 0, 0);
if (IS_ERR(priv->tx_tfm))
goto free_priv;
- priv->rx_tfm = crypto_alloc_skcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
+ priv->rx_tfm = crypto_alloc_sync_skcipher("ecb(arc4)", 0, 0);
if (IS_ERR(priv->rx_tfm))
goto free_tx;
@@ -58,7 +58,7 @@ static void *prism2_wep_init(int keyidx)
return priv;
free_tx:
- crypto_free_skcipher(priv->tx_tfm);
+ crypto_free_sync_skcipher(priv->tx_tfm);
free_priv:
kfree(priv);
return NULL;
@@ -70,8 +70,8 @@ static void prism2_wep_deinit(void *priv)
struct prism2_wep_data *_priv = priv;
if (_priv) {
- crypto_free_skcipher(_priv->tx_tfm);
- crypto_free_skcipher(_priv->rx_tfm);
+ crypto_free_sync_skcipher(_priv->tx_tfm);
+ crypto_free_sync_skcipher(_priv->rx_tfm);
}
kfree(priv);
}
@@ -128,7 +128,7 @@ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
memcpy(key + 3, wep->key, wep->key_len);
if (!tcb_desc->bHwSec) {
- SKCIPHER_REQUEST_ON_STACK(req, wep->tx_tfm);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(req, wep->tx_tfm);
/* Append little-endian CRC32 and encrypt it to produce ICV */
crc = ~crc32_le(~0, pos, len);
@@ -138,10 +138,10 @@ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
icv[2] = crc >> 16;
icv[3] = crc >> 24;
- crypto_skcipher_setkey(wep->tx_tfm, key, klen);
+ crypto_sync_skcipher_setkey(wep->tx_tfm, key, klen);
sg_init_one(&sg, pos, len+4);
- skcipher_request_set_tfm(req, wep->tx_tfm);
+ skcipher_request_set_sync_tfm(req, wep->tx_tfm);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, &sg, &sg, len + 4, NULL);
@@ -193,12 +193,12 @@ static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
plen = skb->len - hdr_len - 8;
if (!tcb_desc->bHwSec) {
- SKCIPHER_REQUEST_ON_STACK(req, wep->rx_tfm);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(req, wep->rx_tfm);
- crypto_skcipher_setkey(wep->rx_tfm, key, klen);
+ crypto_sync_skcipher_setkey(wep->rx_tfm, key, klen);
sg_init_one(&sg, pos, plen+4);
- skcipher_request_set_tfm(req, wep->rx_tfm);
+ skcipher_request_set_sync_tfm(req, wep->rx_tfm);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, &sg, &sg, plen + 4, NULL);
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c
index 90a097f2cd4e..d7975aa335b2 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*******************************************************************************
*
* Copyright(c) 2004 Intel Corporation. All rights reserved.
@@ -28,10 +29,9 @@
* James P. Ketrenos <ipw2100-admin@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
- *******************************************************************************/
+ ******************************************************************************/
#include <linux/compiler.h>
-/* #include <linux/config.h> */
#include <linux/errno.h>
#include <linux/if_arp.h>
#include <linux/in6.h>
@@ -64,9 +64,9 @@ static inline int ieee80211_networks_allocate(struct ieee80211_device *ieee)
if (ieee->networks)
return 0;
- ieee->networks = kcalloc(
- MAX_NETWORK_COUNT, sizeof(struct ieee80211_network),
- GFP_KERNEL);
+ ieee->networks = kcalloc(MAX_NETWORK_COUNT,
+ sizeof(struct ieee80211_network),
+ GFP_KERNEL);
if (!ieee->networks) {
printk(KERN_WARNING "%s: Out of memory allocating beacons\n",
ieee->dev->name);
@@ -94,7 +94,6 @@ static inline void ieee80211_networks_initialize(struct ieee80211_device *ieee)
list_add_tail(&ieee->networks[i].list, &ieee->network_free_list);
}
-
struct net_device *alloc_ieee80211(int sizeof_priv)
{
struct ieee80211_device *ieee;
@@ -110,7 +109,7 @@ struct net_device *alloc_ieee80211(int sizeof_priv)
}
ieee = netdev_priv(dev);
- memset(ieee, 0, sizeof(struct ieee80211_device)+sizeof_priv);
+ memset(ieee, 0, sizeof(struct ieee80211_device) + sizeof_priv);
ieee->dev = dev;
err = ieee80211_networks_allocate(ieee);
@@ -121,7 +120,6 @@ struct net_device *alloc_ieee80211(int sizeof_priv)
}
ieee80211_networks_initialize(ieee);
-
/* Default fragmentation threshold is maximum payload size */
ieee->fts = DEFAULT_FTS;
ieee->scan_age = DEFAULT_MAX_SCAN_AGE;
@@ -159,6 +157,11 @@ struct net_device *alloc_ieee80211(int sizeof_priv)
ieee->pHTInfo = kzalloc(sizeof(RT_HIGH_THROUGHPUT), GFP_KERNEL);
if (ieee->pHTInfo == NULL) {
IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't alloc memory for HTInfo\n");
+
+ /* By this point in code ieee80211_networks_allocate() has been
+ * successfully called so the memory allocated should be freed
+ */
+ ieee80211_networks_free(ieee);
goto failed;
}
HTUpdateDefaultSetting(ieee);
@@ -169,9 +172,9 @@ struct net_device *alloc_ieee80211(int sizeof_priv)
INIT_LIST_HEAD(&ieee->ibss_mac_hash[i]);
for (i = 0; i < 17; i++) {
- ieee->last_rxseq_num[i] = -1;
- ieee->last_rxfrag_num[i] = -1;
- ieee->last_packet_time[i] = 0;
+ ieee->last_rxseq_num[i] = -1;
+ ieee->last_rxfrag_num[i] = -1;
+ ieee->last_packet_time[i] = 0;
}
/* These function were added to load crypte module autoly */
@@ -186,7 +189,6 @@ struct net_device *alloc_ieee80211(int sizeof_priv)
return NULL;
}
-
void free_ieee80211(struct net_device *dev)
{
struct ieee80211_device *ieee = netdev_priv(dev);
@@ -202,6 +204,7 @@ void free_ieee80211(struct net_device *dev)
for (i = 0; i < WEP_KEYS; i++) {
struct ieee80211_crypt_data *crypt = ieee->crypt[i];
+
if (crypt) {
if (crypt->ops)
crypt->ops->deinit(crypt->priv);
@@ -217,8 +220,7 @@ void free_ieee80211(struct net_device *dev)
#ifdef CONFIG_IEEE80211_DEBUG
u32 ieee80211_debug_level;
-static int debug = \
- // IEEE80211_DL_INFO |
+static int debug = // IEEE80211_DL_INFO |
// IEEE80211_DL_WX |
// IEEE80211_DL_SCAN |
// IEEE80211_DL_STATE |
@@ -247,10 +249,11 @@ static int show_debug_level(struct seq_file *m, void *v)
}
static ssize_t write_debug_level(struct file *file, const char __user *buffer,
- size_t count, loff_t *ppos)
+ size_t count, loff_t *ppos)
{
unsigned long val;
int err = kstrtoul_from_user(buffer, count, 0, &val);
+
if (err)
return err;
ieee80211_debug_level = val;
@@ -277,7 +280,7 @@ int __init ieee80211_debug_init(void)
ieee80211_debug_level = debug;
ieee80211_proc = proc_mkdir(DRV_NAME, init_net.proc_net);
- if (ieee80211_proc == NULL) {
+ if (!ieee80211_proc) {
IEEE80211_ERROR("Unable to create " DRV_NAME
" proc directory\n");
return -EIO;
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
index 28cae82d795c..5147f7c01e31 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
@@ -794,7 +794,7 @@ static u8 parse_subframe(struct sk_buff *skb,
}
if (rx_stats->bContainHTC) {
- LLCOffset += sHTCLng;
+ LLCOffset += HTCLNG;
}
// Null packet, don't indicate it to upper layer
ChkLength = LLCOffset;/* + (Frame_WEP(frame)!=0 ?Adapter->MgntInfo.SecurityInfo.EncryptionHeadOverhead:0);*/
@@ -1582,7 +1582,7 @@ static inline void ieee80211_extract_country_ie(
if (!IS_COUNTRY_IE_VALID(ieee))
{
- Dot11d_UpdateCountryIe(ieee, addr2, info_element->len, info_element->data);
+ dot11d_update_country_ie(ieee, addr2, info_element->len, info_element->data);
}
}
@@ -1944,7 +1944,7 @@ int ieee80211_parse_info_param(struct ieee80211_device *ieee,
{
network->bMBssidValid = true;
network->MBssidMask = 0xff << (network->MBssidMask);
- cpMacAddr(network->MBssid, network->bssid);
+ ether_addr_copy(network->MBssid, network->bssid);
network->MBssid[5] &= network->MBssidMask;
}
else
@@ -2439,7 +2439,7 @@ static inline void ieee80211_process_probe_response(
// then wireless adapter should do active scan from ch1~11 and
// passive scan from ch12~14
- if (!IsLegalChannel(ieee, network->channel))
+ if (!is_legal_channel(ieee, network->channel))
goto out;
if (ieee->bGlobalDomain)
{
@@ -2448,7 +2448,7 @@ static inline void ieee80211_process_probe_response(
// Case 1: Country code
if(IS_COUNTRY_IE_VALID(ieee) )
{
- if (!IsLegalChannel(ieee, network->channel)) {
+ if (!is_legal_channel(ieee, network->channel)) {
printk("GetScanInfo(): For Country code, filter probe response at channel(%d).\n", network->channel);
goto out;
}
@@ -2469,7 +2469,7 @@ static inline void ieee80211_process_probe_response(
// Case 1: Country code
if(IS_COUNTRY_IE_VALID(ieee) )
{
- if (!IsLegalChannel(ieee, network->channel)) {
+ if (!is_legal_channel(ieee, network->channel)) {
printk("GetScanInfo(): For Country code, filter beacon at channel(%d).\n",network->channel);
goto out;
}
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
index 212cc9ccbb96..8635faf84316 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
@@ -464,7 +464,7 @@ out:
} else {
ieee->sync_scan_hurryup = 0;
if (IS_DOT11D_ENABLE(ieee))
- DOT11D_ScanComplete(ieee);
+ dot11d_scan_complete(ieee);
mutex_unlock(&ieee->scan_mutex);
}
}
@@ -504,7 +504,7 @@ static void ieee80211_softmac_scan_wq(struct work_struct *work)
return;
out:
if (IS_DOT11D_ENABLE(ieee))
- DOT11D_ScanComplete(ieee);
+ dot11d_scan_complete(ieee);
ieee->actscanning = false;
watchdog = 0;
ieee->scanning = 0;
@@ -2357,7 +2357,7 @@ void ieee80211_disassociate(struct ieee80211_device *ieee)
if (ieee->data_hard_stop)
ieee->data_hard_stop(ieee->dev);
if (IS_DOT11D_ENABLE(ieee))
- Dot11d_Reset(ieee);
+ dot11d_reset(ieee);
ieee->state = IEEE80211_NOLINK;
ieee->is_set_key = false;
ieee->link_change(ieee->dev);
@@ -2542,8 +2542,8 @@ void ieee80211_softmac_init(struct ieee80211_device *ieee)
for (i = 0; i < 5; i++)
ieee->seq_ctrl[i] = 0;
- ieee->pDot11dInfo = kzalloc(sizeof(struct rt_dot11d_info), GFP_KERNEL);
- if (!ieee->pDot11dInfo)
+ ieee->dot11d_info = kzalloc(sizeof(struct rt_dot11d_info), GFP_KERNEL);
+ if (!ieee->dot11d_info)
IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't alloc memory for DOT11D\n");
//added for AP roaming
ieee->LinkDetectInfo.SlotNum = 2;
@@ -2603,8 +2603,8 @@ void ieee80211_softmac_init(struct ieee80211_device *ieee)
void ieee80211_softmac_free(struct ieee80211_device *ieee)
{
mutex_lock(&ieee->wx_mutex);
- kfree(ieee->pDot11dInfo);
- ieee->pDot11dInfo = NULL;
+ kfree(ieee->dot11d_info);
+ ieee->dot11d_info = NULL;
del_timer_sync(&ieee->associate_timer);
cancel_delayed_work(&ieee->associate_retry_wq);
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
index cc4049de975d..024fa2702546 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
@@ -335,14 +335,14 @@ static void ieee80211_tx_query_agg_cap(struct ieee80211_device *ieee,
printk("===>can't get TS\n");
return;
}
- if (!pTxTs->tx_admitted_ba_record.bValid)
+ if (!pTxTs->tx_admitted_ba_record.valid)
{
TsStartAddBaProcess(ieee, pTxTs);
goto FORCED_AGG_SETTING;
}
else if (!pTxTs->using_ba)
{
- if (SN_LESS(pTxTs->tx_admitted_ba_record.BaStartSeqCtrl.field.SeqNum, (pTxTs->tx_cur_seq + 1) % 4096))
+ if (SN_LESS(pTxTs->tx_admitted_ba_record.start_seq_ctrl.field.seq_num, (pTxTs->tx_cur_seq + 1) % 4096))
pTxTs->using_ba = true;
else
goto FORCED_AGG_SETTING;
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c
index f2fcdec9bd17..fa59c712c74b 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c
@@ -147,13 +147,13 @@ static inline char *rtl819x_translate_scan(struct ieee80211_device *ieee,
if (network->mode >= IEEE_N_24G)//add N rate here;
{
- PHT_CAPABILITY_ELE ht_cap = NULL;
+ struct ht_capability_ele *ht_cap = NULL;
bool is40M = false, isShortGI = false;
u8 max_mcs = 0;
if (!memcmp(network->bssht.bdHTCapBuf, EWC11NHTCap, 4))
- ht_cap = (PHT_CAPABILITY_ELE)&network->bssht.bdHTCapBuf[4];
+ ht_cap = (struct ht_capability_ele *)&network->bssht.bdHTCapBuf[4];
else
- ht_cap = (PHT_CAPABILITY_ELE)&network->bssht.bdHTCapBuf[0];
+ ht_cap = (struct ht_capability_ele *)&network->bssht.bdHTCapBuf[0];
is40M = (ht_cap->ChlWidth)?1:0;
isShortGI = (ht_cap->ChlWidth)?
((ht_cap->ShortGI40Mhz)?1:0):
diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_BA.h b/drivers/staging/rtl8192u/ieee80211/rtl819x_BA.h
index b6a76aae4832..1a727856ba53 100644
--- a/drivers/staging/rtl8192u/ieee80211/rtl819x_BA.h
+++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_BA.h
@@ -2,67 +2,53 @@
#ifndef _BATYPE_H_
#define _BATYPE_H_
-#define TOTAL_TXBA_NUM 16
-#define TOTAL_RXBA_NUM 16
+#define BA_SETUP_TIMEOUT 200
-#define BA_SETUP_TIMEOUT 200
-#define BA_INACT_TIMEOUT 60000
+#define BA_POLICY_DELAYED 0
+#define BA_POLICY_IMMEDIATE 1
-#define BA_POLICY_DELAYED 0
-#define BA_POLICY_IMMEDIATE 1
-
-#define ADDBA_STATUS_SUCCESS 0
+#define ADDBA_STATUS_SUCCESS 0
#define ADDBA_STATUS_REFUSED 37
#define ADDBA_STATUS_INVALID_PARAM 38
-#define DELBA_REASON_QSTA_LEAVING 36
-#define DELBA_REASON_END_BA 37
-#define DELBA_REASON_UNKNOWN_BA 38
-#define DELBA_REASON_TIMEOUT 39
-/* whether need define BA Action frames here?
-struct ieee80211_ADDBA_Req{
- struct ieee80211_header_data header;
- u8 category;
- u8
-} __attribute__ ((packed));
-*/
-//Is this need?I put here just to make it easier to define structure BA_RECORD //WB
-typedef union _SEQUENCE_CONTROL{
- u16 ShortData;
+#define DELBA_REASON_END_BA 37
+#define DELBA_REASON_UNKNOWN_BA 38
+#define DELBA_REASON_TIMEOUT 39
+
+union sequence_control {
+ u16 short_data;
struct {
- u16 FragNum:4;
- u16 SeqNum:12;
+ u16 frag_num:4;
+ u16 seq_num:12;
} field;
-} SEQUENCE_CONTROL, *PSEQUENCE_CONTROL;
+};
-typedef union _BA_PARAM_SET {
- u8 charData[2];
- u16 shortData;
+union ba_param_set {
+ u16 short_data;
struct {
- u16 AMSDU_Support:1;
- u16 BAPolicy:1;
- u16 TID:4;
- u16 BufferSize:10;
+ u16 amsdu_support:1;
+ u16 ba_policy:1;
+ u16 tid:4;
+ u16 buffer_size:10;
} field;
-} BA_PARAM_SET, *PBA_PARAM_SET;
+};
-typedef union _DELBA_PARAM_SET {
- u8 charData[2];
- u16 shortData;
+union delba_param_set {
+ u16 short_data;
struct {
- u16 Reserved:11;
- u16 Initiator:1;
- u16 TID:4;
+ u16 reserved:11;
+ u16 initiator:1;
+ u16 tid:4;
} field;
-} DELBA_PARAM_SET, *PDELBA_PARAM_SET;
-
-typedef struct _BA_RECORD {
- struct timer_list Timer;
- u8 bValid;
- u8 DialogToken;
- BA_PARAM_SET BaParamSet;
- u16 BaTimeoutValue;
- SEQUENCE_CONTROL BaStartSeqCtrl;
-} BA_RECORD, *PBA_RECORD;
+};
+
+struct ba_record {
+ struct timer_list timer;
+ u8 valid;
+ u8 dialog_token;
+ union ba_param_set param_set;
+ u16 timeout_value;
+ union sequence_control start_seq_ctrl;
+};
#endif //end _BATYPE_H_
diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c
index 01b631c2a180..109445407cec 100644
--- a/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c
+++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c
@@ -12,26 +12,26 @@
/********************************************************************************************************************
*function: Activate BA entry. And if Time is nozero, start timer.
- * input: PBA_RECORD pBA //BA entry to be enabled
+ * input: struct ba_record *pBA //BA entry to be enabled
* u16 Time //indicate time delay.
* output: none
********************************************************************************************************************/
-static void ActivateBAEntry(struct ieee80211_device *ieee, PBA_RECORD pBA, u16 Time)
+static void ActivateBAEntry(struct ieee80211_device *ieee, struct ba_record *pBA, u16 Time)
{
- pBA->bValid = true;
+ pBA->valid = true;
if (Time != 0)
- mod_timer(&pBA->Timer, jiffies + msecs_to_jiffies(Time));
+ mod_timer(&pBA->timer, jiffies + msecs_to_jiffies(Time));
}
/********************************************************************************************************************
*function: deactivate BA entry, including its timer.
- * input: PBA_RECORD pBA //BA entry to be disabled
+ * input: struct ba_record *pBA //BA entry to be disabled
* output: none
********************************************************************************************************************/
-static void DeActivateBAEntry(struct ieee80211_device *ieee, PBA_RECORD pBA)
+static void DeActivateBAEntry(struct ieee80211_device *ieee, struct ba_record *pBA)
{
- pBA->bValid = false;
- del_timer_sync(&pBA->Timer);
+ pBA->valid = false;
+ del_timer_sync(&pBA->timer);
}
/********************************************************************************************************************
*function: deactivete BA entry in Tx Ts, and send DELBA.
@@ -42,18 +42,18 @@ static void DeActivateBAEntry(struct ieee80211_device *ieee, PBA_RECORD pBA)
********************************************************************************************************************/
static u8 TxTsDeleteBA(struct ieee80211_device *ieee, struct tx_ts_record *pTxTs)
{
- PBA_RECORD pAdmittedBa = &pTxTs->tx_admitted_ba_record; //These two BA entries must exist in TS structure
- PBA_RECORD pPendingBa = &pTxTs->tx_pending_ba_record;
+ struct ba_record *pAdmittedBa = &pTxTs->tx_admitted_ba_record; //These two BA entries must exist in TS structure
+ struct ba_record *pPendingBa = &pTxTs->tx_pending_ba_record;
u8 bSendDELBA = false;
// Delete pending BA
- if (pPendingBa->bValid) {
+ if (pPendingBa->valid) {
DeActivateBAEntry(ieee, pPendingBa);
bSendDELBA = true;
}
// Delete admitted BA
- if (pAdmittedBa->bValid) {
+ if (pAdmittedBa->valid) {
DeActivateBAEntry(ieee, pAdmittedBa);
bSendDELBA = true;
}
@@ -70,10 +70,10 @@ static u8 TxTsDeleteBA(struct ieee80211_device *ieee, struct tx_ts_record *pTxTs
********************************************************************************************************************/
static u8 RxTsDeleteBA(struct ieee80211_device *ieee, struct rx_ts_record *pRxTs)
{
- PBA_RECORD pBa = &pRxTs->rx_admitted_ba_record;
+ struct ba_record *pBa = &pRxTs->rx_admitted_ba_record;
u8 bSendDELBA = false;
- if (pBa->bValid) {
+ if (pBa->valid) {
DeActivateBAEntry(ieee, pBa);
bSendDELBA = true;
}
@@ -84,28 +84,28 @@ static u8 RxTsDeleteBA(struct ieee80211_device *ieee, struct rx_ts_record *pRxTs
/********************************************************************************************************************
*function: reset BA entry
* input:
- * PBA_RECORD pBA //entry to be reset
+ * struct ba_record *pBA //entry to be reset
* output: none
********************************************************************************************************************/
-void ResetBaEntry(PBA_RECORD pBA)
+void ResetBaEntry(struct ba_record *pBA)
{
- pBA->bValid = false;
- pBA->BaParamSet.shortData = 0;
- pBA->BaTimeoutValue = 0;
- pBA->DialogToken = 0;
- pBA->BaStartSeqCtrl.ShortData = 0;
+ pBA->valid = false;
+ pBA->param_set.short_data = 0;
+ pBA->timeout_value = 0;
+ pBA->dialog_token = 0;
+ pBA->start_seq_ctrl.short_data = 0;
}
//These functions need porting here or not?
/*******************************************************************************************************************************
*function: construct ADDBAREQ and ADDBARSP frame here together.
* input: u8* Dst //ADDBA frame's destination
- * PBA_RECORD pBA //BA_RECORD entry which stores the necessary information for BA.
+ * struct ba_record *pBA //BA_RECORD entry which stores the necessary information for BA.
* u16 StatusCode //status code in RSP and I will use it to indicate whether it's RSP or REQ(will I?)
* u8 type //indicate whether it's RSP(ACT_ADDBARSP) ow REQ(ACT_ADDBAREQ)
* output: none
* return: sk_buff* skb //return constructed skb to xmit
*******************************************************************************************************************************/
-static struct sk_buff *ieee80211_ADDBA(struct ieee80211_device *ieee, u8 *Dst, PBA_RECORD pBA, u16 StatusCode, u8 type)
+static struct sk_buff *ieee80211_ADDBA(struct ieee80211_device *ieee, u8 *Dst, struct ba_record *pBA, u16 StatusCode, u8 type)
{
struct sk_buff *skb = NULL;
struct rtl_80211_hdr_3addr *BAReq = NULL;
@@ -140,7 +140,7 @@ static struct sk_buff *ieee80211_ADDBA(struct ieee80211_device *ieee, u8 *Dst, P
*tag++ = ACT_CAT_BA;
*tag++ = type;
// Dialog Token
- *tag++ = pBA->DialogToken;
+ *tag++ = pBA->dialog_token;
if (ACT_ADDBARSP == type) {
// Status Code
@@ -151,16 +151,16 @@ static struct sk_buff *ieee80211_ADDBA(struct ieee80211_device *ieee, u8 *Dst, P
}
// BA Parameter Set
- put_unaligned_le16(pBA->BaParamSet.shortData, tag);
+ put_unaligned_le16(pBA->param_set.short_data, tag);
tag += 2;
// BA Timeout Value
- put_unaligned_le16(pBA->BaTimeoutValue, tag);
+ put_unaligned_le16(pBA->timeout_value, tag);
tag += 2;
if (ACT_ADDBAREQ == type) {
// BA Start SeqCtrl
- memcpy(tag, (u8 *)&(pBA->BaStartSeqCtrl), 2);
+ memcpy(tag, (u8 *)&(pBA->start_seq_ctrl), 2);
tag += 2;
}
@@ -173,7 +173,7 @@ static struct sk_buff *ieee80211_ADDBA(struct ieee80211_device *ieee, u8 *Dst, P
/********************************************************************************************************************
*function: construct DELBA frame
* input: u8* dst //DELBA frame's destination
- * PBA_RECORD pBA //BA_RECORD entry which stores the necessary information for BA
+ * struct ba_record *pBA //BA_RECORD entry which stores the necessary information for BA
* enum tr_select TxRxSelect //TX RX direction
* u16 ReasonCode //status code.
* output: none
@@ -182,12 +182,12 @@ static struct sk_buff *ieee80211_ADDBA(struct ieee80211_device *ieee, u8 *Dst, P
static struct sk_buff *ieee80211_DELBA(
struct ieee80211_device *ieee,
u8 *dst,
- PBA_RECORD pBA,
+ struct ba_record *pBA,
enum tr_select TxRxSelect,
u16 ReasonCode
)
{
- DELBA_PARAM_SET DelbaParamSet;
+ union delba_param_set DelbaParamSet;
struct sk_buff *skb = NULL;
struct rtl_80211_hdr_3addr *Delba = NULL;
u8 *tag = NULL;
@@ -201,8 +201,8 @@ static struct sk_buff *ieee80211_DELBA(
memset(&DelbaParamSet, 0, 2);
- DelbaParamSet.field.Initiator = (TxRxSelect == TX_DIR) ? 1 : 0;
- DelbaParamSet.field.TID = pBA->BaParamSet.field.TID;
+ DelbaParamSet.field.initiator = (TxRxSelect == TX_DIR) ? 1 : 0;
+ DelbaParamSet.field.tid = pBA->param_set.field.tid;
skb = dev_alloc_skb(len + sizeof(struct rtl_80211_hdr_3addr)); //need to add something others? FIXME
if (!skb) {
@@ -226,7 +226,7 @@ static struct sk_buff *ieee80211_DELBA(
// DELBA Parameter Set
- put_unaligned_le16(DelbaParamSet.shortData, tag);
+ put_unaligned_le16(DelbaParamSet.short_data, tag);
tag += 2;
// Reason Code
@@ -243,12 +243,12 @@ static struct sk_buff *ieee80211_DELBA(
/********************************************************************************************************************
*function: send ADDBAReq frame out
* input: u8* dst //ADDBAReq frame's destination
- * PBA_RECORD pBA //BA_RECORD entry which stores the necessary information for BA
+ * struct ba_record *pBA //BA_RECORD entry which stores the necessary information for BA
* output: none
* notice: If any possible, please hide pBA in ieee. And temporarily use Manage Queue as softmac_mgmt_xmit() usually does
********************************************************************************************************************/
static void ieee80211_send_ADDBAReq(struct ieee80211_device *ieee,
- u8 *dst, PBA_RECORD pBA)
+ u8 *dst, struct ba_record *pBA)
{
struct sk_buff *skb;
skb = ieee80211_ADDBA(ieee, dst, pBA, 0, ACT_ADDBAREQ); //construct ACT_ADDBAREQ frames so set statuscode zero.
@@ -266,13 +266,13 @@ static void ieee80211_send_ADDBAReq(struct ieee80211_device *ieee,
/********************************************************************************************************************
*function: send ADDBARSP frame out
* input: u8* dst //DELBA frame's destination
- * PBA_RECORD pBA //BA_RECORD entry which stores the necessary information for BA
+ * struct ba_record *pBA //BA_RECORD entry which stores the necessary information for BA
* u16 StatusCode //RSP StatusCode
* output: none
* notice: If any possible, please hide pBA in ieee. And temporarily use Manage Queue as softmac_mgmt_xmit() usually does
********************************************************************************************************************/
static void ieee80211_send_ADDBARsp(struct ieee80211_device *ieee, u8 *dst,
- PBA_RECORD pBA, u16 StatusCode)
+ struct ba_record *pBA, u16 StatusCode)
{
struct sk_buff *skb;
skb = ieee80211_ADDBA(ieee, dst, pBA, StatusCode, ACT_ADDBARSP); //construct ACT_ADDBARSP frames
@@ -289,7 +289,7 @@ static void ieee80211_send_ADDBARsp(struct ieee80211_device *ieee, u8 *dst,
/********************************************************************************************************************
*function: send ADDBARSP frame out
* input: u8* dst //DELBA frame's destination
- * PBA_RECORD pBA //BA_RECORD entry which stores the necessary information for BA
+ * struct ba_record *pBA //BA_RECORD entry which stores the necessary information for BA
* enum tr_select TxRxSelect //TX or RX
* u16 ReasonCode //DEL ReasonCode
* output: none
@@ -297,7 +297,7 @@ static void ieee80211_send_ADDBARsp(struct ieee80211_device *ieee, u8 *dst,
********************************************************************************************************************/
static void ieee80211_send_DELBA(struct ieee80211_device *ieee, u8 *dst,
- PBA_RECORD pBA, enum tr_select TxRxSelect,
+ struct ba_record *pBA, enum tr_select TxRxSelect,
u16 ReasonCode)
{
struct sk_buff *skb;
@@ -321,10 +321,10 @@ int ieee80211_rx_ADDBAReq(struct ieee80211_device *ieee, struct sk_buff *skb)
struct rtl_80211_hdr_3addr *req = NULL;
u16 rc = 0;
u8 *dst = NULL, *pDialogToken = NULL, *tag = NULL;
- PBA_RECORD pBA = NULL;
- PBA_PARAM_SET pBaParamSet = NULL;
+ struct ba_record *pBA = NULL;
+ union ba_param_set *pBaParamSet = NULL;
u16 *pBaTimeoutVal = NULL;
- PSEQUENCE_CONTROL pBaStartSeqCtrl = NULL;
+ union sequence_control *pBaStartSeqCtrl = NULL;
struct rx_ts_record *pTS = NULL;
if (skb->len < sizeof(struct rtl_80211_hdr_3addr) + 9) {
@@ -342,9 +342,9 @@ int ieee80211_rx_ADDBAReq(struct ieee80211_device *ieee, struct sk_buff *skb)
dst = &req->addr2[0];
tag += sizeof(struct rtl_80211_hdr_3addr);
pDialogToken = tag + 2; //category+action
- pBaParamSet = (PBA_PARAM_SET)(tag + 3); //+DialogToken
+ pBaParamSet = (union ba_param_set *)(tag + 3); //+DialogToken
pBaTimeoutVal = (u16 *)(tag + 5);
- pBaStartSeqCtrl = (PSEQUENCE_CONTROL)(req + 7);
+ pBaStartSeqCtrl = (union sequence_control *)(req + 7);
netdev_info(ieee->dev, "====================>rx ADDBAREQ from :%pM\n", dst);
//some other capability is not ready now.
@@ -362,7 +362,7 @@ int ieee80211_rx_ADDBAReq(struct ieee80211_device *ieee, struct sk_buff *skb)
ieee,
(struct ts_common_info **)(&pTS),
dst,
- (u8)(pBaParamSet->field.TID),
+ (u8)(pBaParamSet->field.tid),
RX_DIR,
true)) {
rc = ADDBA_STATUS_REFUSED;
@@ -371,10 +371,10 @@ int ieee80211_rx_ADDBAReq(struct ieee80211_device *ieee, struct sk_buff *skb)
}
pBA = &pTS->rx_admitted_ba_record;
// To Determine the ADDBA Req content
- // We can do much more check here, including BufferSize, AMSDU_Support, Policy, StartSeqCtrl...
+ // We can do much more check here, including buffer_size, AMSDU_Support, Policy, StartSeqCtrl...
// I want to check StartSeqCtrl to make sure when we start aggregation!!!
//
- if (pBaParamSet->field.BAPolicy == BA_POLICY_DELAYED) {
+ if (pBaParamSet->field.ba_policy == BA_POLICY_DELAYED) {
rc = ADDBA_STATUS_INVALID_PARAM;
IEEE80211_DEBUG(IEEE80211_DL_ERR, "BA Policy is not correct in %s()\n", __func__);
goto OnADDBAReq_Fail;
@@ -382,16 +382,16 @@ int ieee80211_rx_ADDBAReq(struct ieee80211_device *ieee, struct sk_buff *skb)
// Admit the ADDBA Request
//
DeActivateBAEntry(ieee, pBA);
- pBA->DialogToken = *pDialogToken;
- pBA->BaParamSet = *pBaParamSet;
- pBA->BaTimeoutValue = *pBaTimeoutVal;
- pBA->BaStartSeqCtrl = *pBaStartSeqCtrl;
+ pBA->dialog_token = *pDialogToken;
+ pBA->param_set = *pBaParamSet;
+ pBA->timeout_value = *pBaTimeoutVal;
+ pBA->start_seq_ctrl = *pBaStartSeqCtrl;
//for half N mode we only aggregate 1 frame
if (ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev))
- pBA->BaParamSet.field.BufferSize = 1;
+ pBA->param_set.field.buffer_size = 1;
else
- pBA->BaParamSet.field.BufferSize = 32;
- ActivateBAEntry(ieee, pBA, pBA->BaTimeoutValue);
+ pBA->param_set.field.buffer_size = 32;
+ ActivateBAEntry(ieee, pBA, pBA->timeout_value);
ieee80211_send_ADDBARsp(ieee, dst, pBA, ADDBA_STATUS_SUCCESS);
// End of procedure.
@@ -399,11 +399,11 @@ int ieee80211_rx_ADDBAReq(struct ieee80211_device *ieee, struct sk_buff *skb)
OnADDBAReq_Fail:
{
- BA_RECORD BA;
- BA.BaParamSet = *pBaParamSet;
- BA.BaTimeoutValue = *pBaTimeoutVal;
- BA.DialogToken = *pDialogToken;
- BA.BaParamSet.field.BAPolicy = BA_POLICY_IMMEDIATE;
+ struct ba_record BA;
+ BA.param_set = *pBaParamSet;
+ BA.timeout_value = *pBaTimeoutVal;
+ BA.dialog_token = *pDialogToken;
+ BA.param_set.field.ba_policy = BA_POLICY_IMMEDIATE;
ieee80211_send_ADDBARsp(ieee, dst, &BA, rc);
return 0; //we send RSP out.
}
@@ -419,11 +419,11 @@ OnADDBAReq_Fail:
int ieee80211_rx_ADDBARsp(struct ieee80211_device *ieee, struct sk_buff *skb)
{
struct rtl_80211_hdr_3addr *rsp = NULL;
- PBA_RECORD pPendingBA, pAdmittedBA;
+ struct ba_record *pPendingBA, *pAdmittedBA;
struct tx_ts_record *pTS = NULL;
u8 *dst = NULL, *pDialogToken = NULL, *tag = NULL;
u16 *pStatusCode = NULL, *pBaTimeoutVal = NULL;
- PBA_PARAM_SET pBaParamSet = NULL;
+ union ba_param_set *pBaParamSet = NULL;
u16 ReasonCode;
if (skb->len < sizeof(struct rtl_80211_hdr_3addr) + 9) {
@@ -439,7 +439,7 @@ int ieee80211_rx_ADDBARsp(struct ieee80211_device *ieee, struct sk_buff *skb)
tag += sizeof(struct rtl_80211_hdr_3addr);
pDialogToken = tag + 2;
pStatusCode = (u16 *)(tag + 3);
- pBaParamSet = (PBA_PARAM_SET)(tag + 5);
+ pBaParamSet = (union ba_param_set *)(tag + 5);
pBaTimeoutVal = (u16 *)(tag + 7);
// Check the capability
@@ -461,7 +461,7 @@ int ieee80211_rx_ADDBARsp(struct ieee80211_device *ieee, struct sk_buff *skb)
ieee,
(struct ts_common_info **)(&pTS),
dst,
- (u8)(pBaParamSet->field.TID),
+ (u8)(pBaParamSet->field.tid),
TX_DIR,
false)) {
IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't get TS in %s()\n", __func__);
@@ -478,11 +478,11 @@ int ieee80211_rx_ADDBARsp(struct ieee80211_device *ieee, struct sk_buff *skb)
// Check if related BA is waiting for setup.
// If not, reject by sending DELBA frame.
//
- if (pAdmittedBA->bValid) {
+ if (pAdmittedBA->valid) {
// Since BA is already setup, we ignore all other ADDBA Response.
IEEE80211_DEBUG(IEEE80211_DL_BA, "OnADDBARsp(): Recv ADDBA Rsp. Drop because already admit it! \n");
return -1;
- } else if ((!pPendingBA->bValid) || (*pDialogToken != pPendingBA->DialogToken)) {
+ } else if ((!pPendingBA->valid) || (*pDialogToken != pPendingBA->dialog_token)) {
IEEE80211_DEBUG(IEEE80211_DL_ERR, "OnADDBARsp(): Recv ADDBA Rsp. BA invalid, DELBA! \n");
ReasonCode = DELBA_REASON_UNKNOWN_BA;
goto OnADDBARsp_Reject;
@@ -498,7 +498,7 @@ int ieee80211_rx_ADDBARsp(struct ieee80211_device *ieee, struct sk_buff *skb)
// We can compare the value of BA parameter set that Peer returned and Self sent.
// If it is OK, then admitted. Or we can send DELBA to cancel BA mechanism.
//
- if (pBaParamSet->field.BAPolicy == BA_POLICY_DELAYED) {
+ if (pBaParamSet->field.ba_policy == BA_POLICY_DELAYED) {
// Since this is a kind of ADDBA failed, we delay next ADDBA process.
pTS->add_ba_req_delayed = true;
DeActivateBAEntry(ieee, pAdmittedBA);
@@ -510,10 +510,10 @@ int ieee80211_rx_ADDBARsp(struct ieee80211_device *ieee, struct sk_buff *skb)
//
// Admitted condition
//
- pAdmittedBA->DialogToken = *pDialogToken;
- pAdmittedBA->BaTimeoutValue = *pBaTimeoutVal;
- pAdmittedBA->BaStartSeqCtrl = pPendingBA->BaStartSeqCtrl;
- pAdmittedBA->BaParamSet = *pBaParamSet;
+ pAdmittedBA->dialog_token = *pDialogToken;
+ pAdmittedBA->timeout_value = *pBaTimeoutVal;
+ pAdmittedBA->start_seq_ctrl = pPendingBA->start_seq_ctrl;
+ pAdmittedBA->param_set = *pBaParamSet;
DeActivateBAEntry(ieee, pAdmittedBA);
ActivateBAEntry(ieee, pAdmittedBA, *pBaTimeoutVal);
} else {
@@ -526,8 +526,8 @@ int ieee80211_rx_ADDBARsp(struct ieee80211_device *ieee, struct sk_buff *skb)
OnADDBARsp_Reject:
{
- BA_RECORD BA;
- BA.BaParamSet = *pBaParamSet;
+ struct ba_record BA;
+ BA.param_set = *pBaParamSet;
ieee80211_send_DELBA(ieee, dst, &BA, TX_DIR, ReasonCode);
return 0;
}
@@ -543,7 +543,7 @@ OnADDBARsp_Reject:
int ieee80211_rx_DELBA(struct ieee80211_device *ieee, struct sk_buff *skb)
{
struct rtl_80211_hdr_3addr *delba = NULL;
- PDELBA_PARAM_SET pDelBaParamSet = NULL;
+ union delba_param_set *pDelBaParamSet = NULL;
u8 *dst = NULL;
if (skb->len < sizeof(struct rtl_80211_hdr_3addr) + 6) {
@@ -563,16 +563,16 @@ int ieee80211_rx_DELBA(struct ieee80211_device *ieee, struct sk_buff *skb)
IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len);
delba = (struct rtl_80211_hdr_3addr *)skb->data;
dst = &delba->addr2[0];
- pDelBaParamSet = (PDELBA_PARAM_SET)&delba->payload[2];
+ pDelBaParamSet = (union delba_param_set *)&delba->payload[2];
- if (pDelBaParamSet->field.Initiator == 1) {
+ if (pDelBaParamSet->field.initiator == 1) {
struct rx_ts_record *pRxTs;
if (!GetTs(
ieee,
(struct ts_common_info **)&pRxTs,
dst,
- (u8)pDelBaParamSet->field.TID,
+ (u8)pDelBaParamSet->field.tid,
RX_DIR,
false)) {
IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't get TS for RXTS in %s()\n", __func__);
@@ -587,7 +587,7 @@ int ieee80211_rx_DELBA(struct ieee80211_device *ieee, struct sk_buff *skb)
ieee,
(struct ts_common_info **)&pTxTs,
dst,
- (u8)pDelBaParamSet->field.TID,
+ (u8)pDelBaParamSet->field.tid,
TX_DIR,
false)) {
IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't get TS for TXTS in %s()\n", __func__);
@@ -615,22 +615,22 @@ TsInitAddBA(
u8 bOverwritePending
)
{
- PBA_RECORD pBA = &pTS->tx_pending_ba_record;
+ struct ba_record *pBA = &pTS->tx_pending_ba_record;
- if (pBA->bValid && !bOverwritePending)
+ if (pBA->valid && !bOverwritePending)
return;
// Set parameters to "Pending" variable set
DeActivateBAEntry(ieee, pBA);
- pBA->DialogToken++; // DialogToken: Only keep the latest dialog token
- pBA->BaParamSet.field.AMSDU_Support = 0; // Do not support A-MSDU with A-MPDU now!!
- pBA->BaParamSet.field.BAPolicy = Policy; // Policy: Delayed or Immediate
- pBA->BaParamSet.field.TID = pTS->ts_common_info.t_spec.ts_info.uc_tsid; // TID
- // BufferSize: This need to be set according to A-MPDU vector
- pBA->BaParamSet.field.BufferSize = 32; // BufferSize: This need to be set according to A-MPDU vector
- pBA->BaTimeoutValue = 0; // Timeout value: Set 0 to disable Timer
- pBA->BaStartSeqCtrl.field.SeqNum = (pTS->tx_cur_seq + 3) % 4096; // Block Ack will start after 3 packets later.
+ pBA->dialog_token++; // DialogToken: Only keep the latest dialog token
+ pBA->param_set.field.amsdu_support = 0; // Do not support A-MSDU with A-MPDU now!!
+ pBA->param_set.field.ba_policy = Policy; // Policy: Delayed or Immediate
+ pBA->param_set.field.tid = pTS->ts_common_info.t_spec.ts_info.uc_tsid; // TID
+ // buffer_size: This need to be set according to A-MPDU vector
+ pBA->param_set.field.buffer_size = 32; // buffer_size: This need to be set according to A-MPDU vector
+ pBA->timeout_value = 0; // Timeout value: Set 0 to disable Timer
+ pBA->start_seq_ctrl.field.seq_num = (pTS->tx_cur_seq + 3) % 4096; // Block Ack will start after 3 packets later.
ActivateBAEntry(ieee, pBA, BA_SETUP_TIMEOUT);
@@ -647,7 +647,7 @@ TsInitDelBA(struct ieee80211_device *ieee, struct ts_common_info *pTsCommonInfo,
ieee80211_send_DELBA(
ieee,
pTsCommonInfo->addr,
- (pTxTs->tx_admitted_ba_record.bValid)?(&pTxTs->tx_admitted_ba_record):(&pTxTs->tx_pending_ba_record),
+ (pTxTs->tx_admitted_ba_record.valid)?(&pTxTs->tx_admitted_ba_record):(&pTxTs->tx_pending_ba_record),
TxRxSelect,
DELBA_REASON_END_BA);
} else if (TxRxSelect == RX_DIR) {
@@ -669,16 +669,16 @@ TsInitDelBA(struct ieee80211_device *ieee, struct ts_common_info *pTsCommonInfo,
********************************************************************************************************************/
void BaSetupTimeOut(struct timer_list *t)
{
- struct tx_ts_record *pTxTs = from_timer(pTxTs, t, tx_pending_ba_record.Timer);
+ struct tx_ts_record *pTxTs = from_timer(pTxTs, t, tx_pending_ba_record.timer);
pTxTs->add_ba_req_in_progress = false;
pTxTs->add_ba_req_delayed = true;
- pTxTs->tx_pending_ba_record.bValid = false;
+ pTxTs->tx_pending_ba_record.valid = false;
}
void TxBaInactTimeout(struct timer_list *t)
{
- struct tx_ts_record *pTxTs = from_timer(pTxTs, t, tx_admitted_ba_record.Timer);
+ struct tx_ts_record *pTxTs = from_timer(pTxTs, t, tx_admitted_ba_record.timer);
struct ieee80211_device *ieee = container_of(pTxTs, struct ieee80211_device, TxTsRecord[pTxTs->num]);
TxTsDeleteBA(ieee, pTxTs);
ieee80211_send_DELBA(
@@ -691,7 +691,7 @@ void TxBaInactTimeout(struct timer_list *t)
void RxBaInactTimeout(struct timer_list *t)
{
- struct rx_ts_record *pRxTs = from_timer(pRxTs, t, rx_admitted_ba_record.Timer);
+ struct rx_ts_record *pRxTs = from_timer(pRxTs, t, rx_admitted_ba_record.timer);
struct ieee80211_device *ieee = container_of(pRxTs, struct ieee80211_device, RxTsRecord[pRxTs->num]);
RxTsDeleteBA(ieee, pRxTs);
diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_HT.h b/drivers/staging/rtl8192u/ieee80211/rtl819x_HT.h
index 7d54a7cd9514..64d5359cf7e2 100644
--- a/drivers/staging/rtl8192u/ieee80211/rtl819x_HT.h
+++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_HT.h
@@ -2,40 +2,34 @@
#ifndef _RTL819XU_HTTYPE_H_
#define _RTL819XU_HTTYPE_H_
-//------------------------------------------------------------
-// The HT Capability element is present in beacons, association request,
-// reassociation request and probe response frames
-//------------------------------------------------------------
-
-//
-// MIMO Power Save Settings
-//
-#define MIMO_PS_STATIC 0
-
-//
-// There should be 128 bits to cover all of the MCS rates. However, since
-// 8190 does not support too much rates, one integer is quite enough.
-//
-
-#define sHTCLng 4
+/*
+ * The HT Capability element is present in beacons, association request,
+ * reassociation request and probe response frames
+ */
+/*
+ * MIMO Power Save Settings
+ */
+#define MIMO_PS_STATIC 0
-#define HT_SUPPORTED_MCS_1SS_BITMAP 0x000000ff
-#define HT_SUPPORTED_MCS_2SS_BITMAP 0x0000ff00
-#define HT_SUPPORTED_MCS_1SS_2SS_BITMAP HT_MCS_1SS_BITMAP|HT_MCS_1SS_2SS_BITMAP
+/*
+ * There should be 128 bits to cover all of the MCS rates. However, since
+ * 8190 does not support too much rates, one integer is quite enough.
+ */
+#define HTCLNG 4
-//
-// Represent Channel Width in HT Capabilities
-//
+/*
+ * Represent Channel Width in HT Capabilities
+ */
enum ht_channel_width {
HT_CHANNEL_WIDTH_20 = 0,
HT_CHANNEL_WIDTH_20_40 = 1,
};
-//
-// Represent Extension Channel Offset in HT Capabilities
-// This is available only in 40Mhz mode.
-//
+/*
+ * Represent Extension Channel Offset in HT Capabilities
+ * This is available only in 40Mhz mode.
+ */
enum ht_extension_chan_offset {
HT_EXTCHNL_OFFSET_NO_EXT = 0,
HT_EXTCHNL_OFFSET_UPPER = 1,
@@ -43,53 +37,7 @@ enum ht_extension_chan_offset {
HT_EXTCHNL_OFFSET_LOWER = 3,
};
-typedef enum _CHNLOP {
- CHNLOP_NONE = 0, // No Action now
- CHNLOP_SCAN = 1, // Scan in progress
- CHNLOP_SWBW = 2, // Bandwidth switching in progress
- CHNLOP_SWCHNL = 3, // Software Channel switching in progress
-} CHNLOP, *PCHNLOP;
-
-// Determine if the Channel Operation is in progress
-#define CHHLOP_IN_PROGRESS(_pHTInfo) \
- ((_pHTInfo)->ChnlOp > CHNLOP_NONE) ? TRUE : FALSE
-
-/*
-typedef union _HT_CAPABILITY{
- u16 ShortData;
- u8 CharData[2];
- struct
- {
- u16 AdvCoding:1;
- u16 ChlWidth:1;
- u16 MimoPwrSave:2;
- u16 GreenField:1;
- u16 ShortGI20Mhz:1;
- u16 ShortGI40Mhz:1;
- u16 STBC:1;
- u16 BeamForm:1;
- u16 DelayBA:1;
- u16 MaxAMSDUSize:1;
- u16 DssCCk:1;
- u16 PSMP:1;
- u16 Rsvd:3;
- }Field;
-}HT_CAPABILITY, *PHT_CAPABILITY;
-
-typedef union _HT_CAPABILITY_MACPARA{
- u8 ShortData;
- u8 CharData[1];
- struct
- {
- u8 MaxRxAMPDU:2;
- u8 MPDUDensity:2;
- u8 Rsvd:4;
- }Field;
-}HT_CAPABILITY_MACPARA, *PHT_CAPABILITY_MACPARA;
-*/
-
-typedef struct _HT_CAPABILITY_ELE {
-
+struct ht_capability_ele {
//HT capability info
u8 AdvCoding:1;
u8 ChlWidth:1;
@@ -114,7 +62,6 @@ typedef struct _HT_CAPABILITY_ELE {
//Supported MCS set
u8 MCS[16];
-
//Extended HT Capability Info
u16 ExtHTCapInfo;
@@ -124,13 +71,12 @@ typedef struct _HT_CAPABILITY_ELE {
//Antenna Selection Capabilities
u8 ASCap;
-} __attribute__ ((packed)) HT_CAPABILITY_ELE, *PHT_CAPABILITY_ELE;
-
-//------------------------------------------------------------
-// The HT Information element is present in beacons
-// Only AP is required to include this element
-//------------------------------------------------------------
+} __packed;
+/*
+ * The HT Information element is present in beacons
+ * Only AP is required to include this element
+ */
typedef struct _HT_INFORMATION_ELE {
u8 ControlChl;
@@ -169,12 +115,11 @@ typedef enum _HT_AGGRE_MODE_E {
HT_AGG_FORCE_DISABLE = 2,
}HT_AGGRE_MODE_E, *PHT_AGGRE_MODE_E;
-//------------------------------------------------------------
-// The Data structure is used to keep HT related variables when card is
-// configured as non-AP STA mode. **Note** Current_xxx should be set
-// to default value in HTInitializeHTInfo()
-//------------------------------------------------------------
-
+/*
+ * The Data structure is used to keep HT related variables when card is
+ * configured as non-AP STA mode. **Note** Current_xxx should be set
+ * to default value in HTInitializeHTInfo()
+ */
typedef struct _RT_HIGH_THROUGHPUT {
u8 bEnableHT;
u8 bCurrentHTSupport;
@@ -194,23 +139,20 @@ typedef struct _RT_HIGH_THROUGHPUT {
// 802.11n spec version for "peer"
HT_SPEC_VER ePeerHTSpecVer;
-
// HT related information for "Self"
- HT_CAPABILITY_ELE SelfHTCap; // This is HT cap element sent to peer STA, which also indicate HT Rx capabilities.
+ struct ht_capability_ele SelfHTCap; // This is HT cap element sent to peer STA, which also indicate HT Rx capabilities.
HT_INFORMATION_ELE SelfHTInfo; // This is HT info element sent to peer STA, which also indicate HT Rx capabilities.
// HT related information for "Peer"
u8 PeerHTCapBuf[32];
u8 PeerHTInfoBuf[32];
-
// A-MSDU related
u8 bAMSDU_Support; // This indicates Tx A-MSDU capability
u16 nAMSDU_MaxSize; // This indicates Tx A-MSDU capability
u8 bCurrent_AMSDU_Support; // This indicates Tx A-MSDU capability
u16 nCurrent_AMSDU_MaxSize; // This indicates Tx A-MSDU capability
-
// AMPDU related <2006.08.10 Emily>
u8 bAMPDUEnable; // This indicate Tx A-MPDU capability
u8 bCurrentAMPDUEnable; // This indicate Tx A-MPDU capability
@@ -243,7 +185,6 @@ typedef struct _RT_HIGH_THROUGHPUT {
// For Bandwidth Switching
u8 bSwBwInProgress;
- CHNLOP ChnlOp; // software switching channel in progress. By Bruce, 2008-02-15.
u8 SwBwStep;
//struct timer_list SwBwTimer; //moved to ieee80211_device. as timer_list need include some header file here.
@@ -278,13 +219,11 @@ typedef struct _RT_HIGH_THROUGHPUT {
u32 IOTAction;
} __attribute__ ((packed)) RT_HIGH_THROUGHPUT, *PRT_HIGH_THROUGHPUT;
-//------------------------------------------------------------
-// The Data structure is used to keep HT related variable for "each AP"
-// when card is configured as "STA mode"
-//------------------------------------------------------------
-
+/*
+ * The Data structure is used to keep HT related variable for "each AP"
+ * when card is configured as "STA mode"
+ */
typedef struct _BSS_HT {
-
u8 bdSupportHT;
// HT related elements
@@ -294,7 +233,7 @@ typedef struct _BSS_HT {
u16 bdHTInfoLen;
HT_SPEC_VER bdHTSpecVer;
- //HT_CAPABILITY_ELE bdHTCapEle;
+ //struct ht_capability_ele bdHTCapEle;
//HT_INFORMATION_ELE bdHTInfoEle;
u8 bdRT2RTAggregation;
@@ -304,27 +243,27 @@ typedef struct _BSS_HT {
extern u8 MCS_FILTER_ALL[16];
extern u8 MCS_FILTER_1SS[16];
-/* 2007/07/11 MH Modify the macro. Becaus STA may link with a N-AP. If we set
- STA in A/B/G mode and AP is still in N mode. The macro will be wrong. We have
- to add a macro to judge wireless mode. */
+/*
+ * 2007/07/11 MH Modify the macro. Becaus STA may link with a N-AP. If we set
+ * STA in A/B/G mode and AP is still in N mode. The macro will be wrong. We have
+ * to add a macro to judge wireless mode.
+ */
#define PICK_RATE(_nLegacyRate, _nMcsRate) \
- (_nMcsRate==0)?(_nLegacyRate&0x7f):(_nMcsRate)
+ (_nMcsRate == 0) ? (_nLegacyRate & 0x7f) : (_nMcsRate)
/* 2007/07/12 MH We only define legacy and HT wireless mode now. */
#define LEGACY_WIRELESS_MODE IEEE_MODE_MASK
#define CURRENT_RATE(WirelessMode, LegacyRate, HTRate) \
- ((WirelessMode & (LEGACY_WIRELESS_MODE))!=0)?\
- (LegacyRate):\
+ ((WirelessMode & (LEGACY_WIRELESS_MODE)) != 0) ?\
+ (LegacyRate) :\
(PICK_RATE(LegacyRate, HTRate))
-
-
// MCS Bw 40 {1~7, 12~15,32}
#define RATE_ADPT_1SS_MASK 0xFF
#define RATE_ADPT_2SS_MASK 0xF0 //Skip MCS8~11 because mcs7 > mcs6, 9, 10, 11. 2007.01.16 by Emily
#define RATE_ADPT_MCS32_MASK 0x01
-#define IS_11N_MCS_RATE(rate) (rate&0x80)
+#define IS_11N_MCS_RATE(rate) (rate & 0x80)
typedef enum _HT_AGGRE_SIZE {
HT_AGG_SIZE_8K = 0,
@@ -341,13 +280,13 @@ typedef enum _HT_IOT_PEER
HT_IOT_PEER_BROADCOM = 2,
HT_IOT_PEER_RALINK = 3,
HT_IOT_PEER_ATHEROS = 4,
- HT_IOT_PEER_CISCO= 5,
+ HT_IOT_PEER_CISCO = 5,
HT_IOT_PEER_MAX = 6
}HT_IOT_PEER_E, *PHTIOT_PEER_E;
-//
-// IOT Action for different AP
-//
+/*
+ * IOT Action for different AP
+ */
typedef enum _HT_IOT_ACTION {
HT_IOT_ACT_TX_USE_AMSDU_4K = 0x00000001,
HT_IOT_ACT_TX_USE_AMSDU_8K = 0x00000002,
diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c
index b948eae5909d..c73a8058cf87 100644
--- a/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c
+++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c
@@ -130,15 +130,15 @@ void HTUpdateDefaultSetting(struct ieee80211_device *ieee)
*/
void HTDebugHTCapability(u8 *CapIE, u8 *TitleString)
{
- static u8 EWC11NHTCap[] = {0x00, 0x90, 0x4c, 0x33}; // For 11n EWC definition, 2007.07.17, by Emily
- PHT_CAPABILITY_ELE pCapELE;
+ static u8 EWC11NHTCap[] = {0x00, 0x90, 0x4c, 0x33}; // For 11n EWC definition, 2007.07.17, by Emily
+ struct ht_capability_ele *pCapELE;
if (!memcmp(CapIE, EWC11NHTCap, sizeof(EWC11NHTCap))) {
//EWC IE
IEEE80211_DEBUG(IEEE80211_DL_HT, "EWC IE in %s()\n", __func__);
- pCapELE = (PHT_CAPABILITY_ELE)(&CapIE[4]);
+ pCapELE = (struct ht_capability_ele *)(&CapIE[4]);
} else {
- pCapELE = (PHT_CAPABILITY_ELE)(&CapIE[0]);
+ pCapELE = (struct ht_capability_ele *)(&CapIE[0]);
}
IEEE80211_DEBUG(IEEE80211_DL_HT, "<Log HT Capability>. Called by %s\n", TitleString);
@@ -216,64 +216,7 @@ void HTDebugHTInfo(u8 *InfoIE, u8 *TitleString)
pHTInfoEle->BasicMSC[1], pHTInfoEle->BasicMSC[2], pHTInfoEle->BasicMSC[3], pHTInfoEle->BasicMSC[4]);
}
-/*
- * Return: true if station in half n mode and AP supports 40 bw
- */
-static bool IsHTHalfNmode40Bandwidth(struct ieee80211_device *ieee)
-{
- bool retValue = false;
- PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo;
-
- if (!pHTInfo->bCurrentHTSupport) // wireless is n mode
- retValue = false;
- else if (!pHTInfo->bRegBW40MHz) // station supports 40 bw
- retValue = false;
- else if (!ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev)) // station in half n mode
- retValue = false;
- else if (((PHT_CAPABILITY_ELE)(pHTInfo->PeerHTCapBuf))->ChlWidth) // ap support 40 bw
- retValue = true;
- else
- retValue = false;
-
- return retValue;
-}
-
-static bool IsHTHalfNmodeSGI(struct ieee80211_device *ieee, bool is40MHz)
-{
- bool retValue = false;
- PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo;
-
- if (!pHTInfo->bCurrentHTSupport) // wireless is n mode
- retValue = false;
- else if (!ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev)) // station in half n mode
- retValue = false;
- else if (is40MHz) { // ap support 40 bw
- if (((PHT_CAPABILITY_ELE)(pHTInfo->PeerHTCapBuf))->ShortGI40Mhz) // ap support 40 bw short GI
- retValue = true;
- else
- retValue = false;
- } else {
- if (((PHT_CAPABILITY_ELE)(pHTInfo->PeerHTCapBuf))->ShortGI20Mhz) // ap support 40 bw short GI
- retValue = true;
- else
- retValue = false;
- }
-
- return retValue;
-}
-
-u16 HTHalfMcsToDataRate(struct ieee80211_device *ieee, u8 nMcsRate)
-{
- u8 is40MHz;
- u8 isShortGI;
-
- is40MHz = (IsHTHalfNmode40Bandwidth(ieee)) ? 1 : 0;
- isShortGI = (IsHTHalfNmodeSGI(ieee, is40MHz)) ? 1 : 0;
-
- return MCS_DATA_RATE[is40MHz][isShortGI][(nMcsRate & 0x7f)];
-}
-
-u16 HTMcsToDataRate(struct ieee80211_device *ieee, u8 nMcsRate)
+static u16 HTMcsToDataRate(struct ieee80211_device *ieee, u8 nMcsRate)
{
PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo;
@@ -530,7 +473,7 @@ void HTResetIOTSetting(PRT_HIGH_THROUGHPUT pHTInfo)
void HTConstructCapabilityElement(struct ieee80211_device *ieee, u8 *posHTCap, u8 *len, u8 IsEncrypt)
{
PRT_HIGH_THROUGHPUT pHT = ieee->pHTInfo;
- PHT_CAPABILITY_ELE pCapELE = NULL;
+ struct ht_capability_ele *pCapELE = NULL;
//u8 bIsDeclareMCS13;
if (!posHTCap || !pHT) {
@@ -544,9 +487,9 @@ void HTConstructCapabilityElement(struct ieee80211_device *ieee, u8 *posHTCap, u
u8 EWC11NHTCap[] = {0x00, 0x90, 0x4c, 0x33}; // For 11n EWC definition, 2007.07.17, by Emily
memcpy(posHTCap, EWC11NHTCap, sizeof(EWC11NHTCap));
- pCapELE = (PHT_CAPABILITY_ELE)&posHTCap[4];
+ pCapELE = (struct ht_capability_ele *)&posHTCap[4];
} else {
- pCapELE = (PHT_CAPABILITY_ELE)posHTCap;
+ pCapELE = (struct ht_capability_ele *)posHTCap;
}
//HT capability info
@@ -894,11 +837,10 @@ static u8 HTFilterMCSRate(struct ieee80211_device *ieee, u8 *pSupportMCS,
return true;
}
-void HTSetConnectBwMode(struct ieee80211_device *ieee, enum ht_channel_width Bandwidth, enum ht_extension_chan_offset Offset);
void HTOnAssocRsp(struct ieee80211_device *ieee)
{
PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo;
- PHT_CAPABILITY_ELE pPeerHTCap = NULL;
+ struct ht_capability_ele *pPeerHTCap = NULL;
PHT_INFORMATION_ELE pPeerHTInfo = NULL;
u16 nMaxAMSDUSize = 0;
u8 *pMcsFilter = NULL;
@@ -913,16 +855,16 @@ void HTOnAssocRsp(struct ieee80211_device *ieee)
return;
}
IEEE80211_DEBUG(IEEE80211_DL_HT, "===> HTOnAssocRsp_wq(): HT_ENABLE\n");
-// IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA, pHTInfo->PeerHTCapBuf, sizeof(HT_CAPABILITY_ELE));
+// IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA, pHTInfo->PeerHTCapBuf, sizeof(struct ht_capability_ele));
// IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA, pHTInfo->PeerHTInfoBuf, sizeof(HT_INFORMATION_ELE));
// HTDebugHTCapability(pHTInfo->PeerHTCapBuf,"HTOnAssocRsp_wq");
// HTDebugHTInfo(pHTInfo->PeerHTInfoBuf,"HTOnAssocRsp_wq");
//
if (!memcmp(pHTInfo->PeerHTCapBuf, EWC11NHTCap, sizeof(EWC11NHTCap)))
- pPeerHTCap = (PHT_CAPABILITY_ELE)(&pHTInfo->PeerHTCapBuf[4]);
+ pPeerHTCap = (struct ht_capability_ele *)(&pHTInfo->PeerHTCapBuf[4]);
else
- pPeerHTCap = (PHT_CAPABILITY_ELE)(pHTInfo->PeerHTCapBuf);
+ pPeerHTCap = (struct ht_capability_ele *)(pHTInfo->PeerHTCapBuf);
if (!memcmp(pHTInfo->PeerHTInfoBuf, EWC11NHTInfo, sizeof(EWC11NHTInfo)))
pPeerHTInfo = (PHT_INFORMATION_ELE)(&pHTInfo->PeerHTInfoBuf[4]);
@@ -932,7 +874,7 @@ void HTOnAssocRsp(struct ieee80211_device *ieee)
////////////////////////////////////////////////////////
// Configurations:
////////////////////////////////////////////////////////
- IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA | IEEE80211_DL_HT, pPeerHTCap, sizeof(HT_CAPABILITY_ELE));
+ IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA | IEEE80211_DL_HT, pPeerHTCap, sizeof(struct ht_capability_ele));
// IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_HT, pPeerHTInfo, sizeof(HT_INFORMATION_ELE));
// Config Supported Channel Width setting
//
@@ -1069,7 +1011,6 @@ void HTOnAssocRsp(struct ieee80211_device *ieee)
pHTInfo->CurrentOpMode = pPeerHTInfo->OptMode;
}
-void HTSetConnectBwModeCallback(struct ieee80211_device *ieee);
/*
*function: initialize HT info(struct PRT_HIGH_THROUGHPUT)
* input: struct ieee80211_device* ieee
@@ -1122,7 +1063,6 @@ void HTInitializeHTInfo(struct ieee80211_device *ieee)
memset(&pHTInfo->PeerHTInfoBuf, 0, sizeof(pHTInfo->PeerHTInfoBuf));
pHTInfo->bSwBwInProgress = false;
- pHTInfo->ChnlOp = CHNLOP_NONE;
// Set default IEEE spec for Draft N
pHTInfo->ePeerHTSpecVer = HT_SPEC_VER_IEEE;
@@ -1177,7 +1117,7 @@ void HTResetSelfAndSavePeerSetting(struct ieee80211_device *ieee, struct ieee802
{
PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo;
// u16 nMaxAMSDUSize;
-// PHT_CAPABILITY_ELE pPeerHTCap = (PHT_CAPABILITY_ELE)pNetwork->bssht.bdHTCapBuf;
+// struct ht_capability_ele *pPeerHTCap = (struct ht_capability_ele *)pNetwork->bssht.bdHTCapBuf;
// PHT_INFORMATION_ELE pPeerHTInfo = (PHT_INFORMATION_ELE)pNetwork->bssht.bdHTInfoBuf;
// u8* pMcsFilter;
u8 bIOTAction = 0;
@@ -1250,8 +1190,8 @@ void HTResetSelfAndSavePeerSetting(struct ieee80211_device *ieee, struct ieee802
void HTUpdateSelfAndPeerSetting(struct ieee80211_device *ieee, struct ieee80211_network *pNetwork)
{
- PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo;
-// PHT_CAPABILITY_ELE pPeerHTCap = (PHT_CAPABILITY_ELE)pNetwork->bssht.bdHTCapBuf;
+ PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo;
+// struct ht_capability_ele *pPeerHTCap = (struct ht_capability_ele *)pNetwork->bssht.bdHTCapBuf;
PHT_INFORMATION_ELE pPeerHTInfo = (PHT_INFORMATION_ELE)pNetwork->bssht.bdHTInfoBuf;
if (pHTInfo->bCurrentHTSupport) {
@@ -1287,6 +1227,29 @@ u8 HTCCheck(struct ieee80211_device *ieee, u8 *pFrame)
return false;
}
+static void HTSetConnectBwModeCallback(struct ieee80211_device *ieee)
+{
+ PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo;
+
+ IEEE80211_DEBUG(IEEE80211_DL_HT, "======>%s()\n", __func__);
+
+ if (pHTInfo->bCurBW40MHz) {
+ if (pHTInfo->CurSTAExtChnlOffset == HT_EXTCHNL_OFFSET_UPPER)
+ ieee->set_chan(ieee->dev, ieee->current_network.channel + 2);
+ else if (pHTInfo->CurSTAExtChnlOffset == HT_EXTCHNL_OFFSET_LOWER)
+ ieee->set_chan(ieee->dev, ieee->current_network.channel - 2);
+ else
+ ieee->set_chan(ieee->dev, ieee->current_network.channel);
+
+ ieee->SetBWModeHandler(ieee->dev, HT_CHANNEL_WIDTH_20_40, pHTInfo->CurSTAExtChnlOffset);
+ } else {
+ ieee->set_chan(ieee->dev, ieee->current_network.channel);
+ ieee->SetBWModeHandler(ieee->dev, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT);
+ }
+
+ pHTInfo->bSwBwInProgress = false;
+}
+
/*
* This function set bandwidth mode in protocol layer.
*/
@@ -1337,26 +1300,3 @@ void HTSetConnectBwMode(struct ieee80211_device *ieee, enum ht_channel_width Ban
// spin_unlock_irqrestore(&(ieee->bw_spinlock), flags);
}
-
-void HTSetConnectBwModeCallback(struct ieee80211_device *ieee)
-{
- PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo;
-
- IEEE80211_DEBUG(IEEE80211_DL_HT, "======>%s()\n", __func__);
-
- if (pHTInfo->bCurBW40MHz) {
- if (pHTInfo->CurSTAExtChnlOffset == HT_EXTCHNL_OFFSET_UPPER)
- ieee->set_chan(ieee->dev, ieee->current_network.channel + 2);
- else if (pHTInfo->CurSTAExtChnlOffset == HT_EXTCHNL_OFFSET_LOWER)
- ieee->set_chan(ieee->dev, ieee->current_network.channel - 2);
- else
- ieee->set_chan(ieee->dev, ieee->current_network.channel);
-
- ieee->SetBWModeHandler(ieee->dev, HT_CHANNEL_WIDTH_20_40, pHTInfo->CurSTAExtChnlOffset);
- } else {
- ieee->set_chan(ieee->dev, ieee->current_network.channel);
- ieee->SetBWModeHandler(ieee->dev, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT);
- }
-
- pHTInfo->bSwBwInProgress = false;
-}
diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_TS.h b/drivers/staging/rtl8192u/ieee80211/rtl819x_TS.h
index 924d4b373099..7ed140009760 100644
--- a/drivers/staging/rtl8192u/ieee80211/rtl819x_TS.h
+++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_TS.h
@@ -78,8 +78,8 @@ struct ts_common_info {
struct tx_ts_record {
struct ts_common_info ts_common_info;
u16 tx_cur_seq;
- BA_RECORD tx_pending_ba_record;
- BA_RECORD tx_admitted_ba_record;
+ struct ba_record tx_pending_ba_record;
+ struct ba_record tx_admitted_ba_record;
u8 add_ba_req_in_progress;
u8 add_ba_req_delayed;
u8 using_ba;
@@ -93,7 +93,7 @@ struct rx_ts_record {
u16 rx_timeout_indicate_seq;
struct list_head rx_pending_pkt_list;
struct timer_list rx_pkt_pending_timer;
- BA_RECORD rx_admitted_ba_record;
+ struct ba_record rx_admitted_ba_record;
u16 rx_last_seq_num;
u8 rx_last_frag_num;
u8 num;
diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c
index d46d8f468671..c76715ffa08b 100644
--- a/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c
+++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c
@@ -36,11 +36,11 @@ static void RxPktPendingTimeout(struct timer_list *t)
bool bPktInBuf = false;
spin_lock_irqsave(&(ieee->reorder_spinlock), flags);
- IEEE80211_DEBUG(IEEE80211_DL_REORDER,"==================>%s()\n",__func__);
+ IEEE80211_DEBUG(IEEE80211_DL_REORDER, "==================>%s()\n", __func__);
if(pRxTs->rx_timeout_indicate_seq != 0xffff) {
// Indicate the pending packets sequentially according to SeqNum until meet the gap.
while(!list_empty(&pRxTs->rx_pending_pkt_list)) {
- pReorderEntry = (PRX_REORDER_ENTRY)list_entry(pRxTs->rx_pending_pkt_list.prev,RX_REORDER_ENTRY,List);
+ pReorderEntry = (PRX_REORDER_ENTRY)list_entry(pRxTs->rx_pending_pkt_list.prev, RX_REORDER_ENTRY, List);
if(index == 0)
pRxTs->rx_indicate_seq = pReorderEntry->SeqNum;
@@ -51,7 +51,7 @@ static void RxPktPendingTimeout(struct timer_list *t)
if(SN_EQUAL(pReorderEntry->SeqNum, pRxTs->rx_indicate_seq))
pRxTs->rx_indicate_seq = (pRxTs->rx_indicate_seq + 1) % 4096;
- IEEE80211_DEBUG(IEEE80211_DL_REORDER,"RxPktPendingTimeout(): IndicateSeq: %d\n", pReorderEntry->SeqNum);
+ IEEE80211_DEBUG(IEEE80211_DL_REORDER, "RxPktPendingTimeout(): IndicateSeq: %d\n", pReorderEntry->SeqNum);
ieee->stats_IndicateArray[index] = pReorderEntry->prxb;
index++;
@@ -151,9 +151,9 @@ void TSInitialize(struct ieee80211_device *ieee)
timer_setup(&pTxTS->ts_common_info.inact_timer, TsInactTimeout,
0);
timer_setup(&pTxTS->ts_add_ba_timer, TsAddBaProcess, 0);
- timer_setup(&pTxTS->tx_pending_ba_record.Timer, BaSetupTimeOut,
+ timer_setup(&pTxTS->tx_pending_ba_record.timer, BaSetupTimeOut,
0);
- timer_setup(&pTxTS->tx_admitted_ba_record.Timer,
+ timer_setup(&pTxTS->tx_admitted_ba_record.timer,
TxBaInactTimeout, 0);
ResetTxTsEntry(pTxTS);
list_add_tail(&pTxTS->ts_common_info.list, &ieee->Tx_TS_Unused_List);
@@ -171,7 +171,7 @@ void TSInitialize(struct ieee80211_device *ieee)
0);
timer_setup(&pRxTS->ts_common_info.inact_timer, TsInactTimeout,
0);
- timer_setup(&pRxTS->rx_admitted_ba_record.Timer,
+ timer_setup(&pRxTS->rx_admitted_ba_record.timer,
RxBaInactTimeout, 0);
timer_setup(&pRxTS->rx_pkt_pending_timer, RxPktPendingTimeout, 0);
ResetRxTsEntry(pRxTS);
@@ -426,7 +426,7 @@ static void RemoveTsEntry(struct ieee80211_device *ieee, struct ts_common_info *
while(!list_empty(&pRxTS->rx_pending_pkt_list)) {
spin_lock_irqsave(&(ieee->reorder_spinlock), flags);
//pRxReorderEntry = list_entry(&pRxTS->rx_pending_pkt_list.prev,RX_REORDER_ENTRY,List);
- pRxReorderEntry = (PRX_REORDER_ENTRY)list_entry(pRxTS->rx_pending_pkt_list.prev,RX_REORDER_ENTRY,List);
+ pRxReorderEntry = (PRX_REORDER_ENTRY)list_entry(pRxTS->rx_pending_pkt_list.prev, RX_REORDER_ENTRY, List);
list_del_init(&pRxReorderEntry->List);
{
int i = 0;
@@ -529,7 +529,7 @@ void TsStartAddBaProcess(struct ieee80211_device *ieee, struct tx_ts_record *pTx
mod_timer(&pTxTS->ts_add_ba_timer,
jiffies + msecs_to_jiffies(TS_ADDBA_DELAY));
} else {
- IEEE80211_DEBUG(IEEE80211_DL_BA,"TsStartAddBaProcess(): Immediately Start ADDBA now!!\n");
+ IEEE80211_DEBUG(IEEE80211_DL_BA, "TsStartAddBaProcess(): Immediately Start ADDBA now!!\n");
mod_timer(&pTxTS->ts_add_ba_timer, jiffies+10); //set 10 ticks
}
} else {
diff --git a/drivers/staging/rtl8192u/r8180_93cx6.h b/drivers/staging/rtl8192u/r8180_93cx6.h
index 643d465e7105..0cdd00a4f7b8 100644
--- a/drivers/staging/rtl8192u/r8180_93cx6.h
+++ b/drivers/staging/rtl8192u/r8180_93cx6.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* This is part of rtl8187 OpenSource driver
* Copyright (C) Andrea Merello 2004-2005 <andrea.merello@gmail.com>
@@ -21,22 +22,4 @@
#define EPROM_DELAY 10
-#define EPROM_ANAPARAM_ADDRLWORD 0xd
-#define EPROM_ANAPARAM_ADDRHWORD 0xe
-
-#define EPROM_RFCHIPID 0x6
-#define EPROM_TXPW_BASE 0x05
-#define EPROM_RFCHIPID_RTL8225U 5
-#define EPROM_RF_PARAM 0x4
-#define EPROM_CONFIG2 0xc
-
-#define EPROM_VERSION 0x1E
-#define MAC_ADR 0x7
-
-#define CIS 0x18
-
-#define EPROM_TXPW0 0x16
-#define EPROM_TXPW2 0x1b
-#define EPROM_TXPW1 0x3d
-
int eprom_read(struct net_device *dev, u32 addr); /* reads a 16 bits word */
diff --git a/drivers/staging/rtl8192u/r8190_rtl8256.c b/drivers/staging/rtl8192u/r8190_rtl8256.c
index 9b7f822e9762..a8c8e8c0660d 100644
--- a/drivers/staging/rtl8192u/r8190_rtl8256.c
+++ b/drivers/staging/rtl8192u/r8190_rtl8256.c
@@ -14,6 +14,11 @@
#include "r819xU_phy.h"
#include "r8190_rtl8256.h"
+/*
+ * Forward declaration of local functions
+ */
+static void phy_rf8256_config_para_file(struct net_device *dev);
+
/*--------------------------------------------------------------------------
* Overview: set RF band width (20M or 40M)
* Input: struct net_device* dev
@@ -23,7 +28,7 @@
* Note: 8226 support both 20M and 40 MHz
*--------------------------------------------------------------------------
*/
-void PHY_SetRF8256Bandwidth(struct net_device *dev, enum ht_channel_width Bandwidth)
+void phy_set_rf8256_bandwidth(struct net_device *dev, enum ht_channel_width Bandwidth)
{
u8 eRFPath;
struct r8192_priv *priv = ieee80211_priv(dev);
@@ -37,9 +42,9 @@ void PHY_SetRF8256Bandwidth(struct net_device *dev, enum ht_channel_width Bandwi
switch (Bandwidth) {
case HT_CHANNEL_WIDTH_20:
- if (priv->card_8192_version == VERSION_819xU_A
+ if (priv->card_8192_version == VERSION_819XU_A
|| priv->card_8192_version
- == VERSION_819xU_B) { /* 8256 D-cut, E-cut, xiong: consider it later! */
+ == VERSION_819XU_B) { /* 8256 D-cut, E-cut, xiong: consider it later! */
rtl8192_phy_SetRFReg(dev,
(enum rf90_radio_path_e)eRFPath,
0x0b, bMask12Bits, 0x100); /* phy para:1ba */
@@ -53,11 +58,11 @@ void PHY_SetRF8256Bandwidth(struct net_device *dev, enum ht_channel_width Bandwi
(enum rf90_radio_path_e)eRFPath,
0x14, bMask12Bits, 0x5ab);
} else {
- RT_TRACE(COMP_ERR, "PHY_SetRF8256Bandwidth(): unknown hardware version\n");
+ RT_TRACE(COMP_ERR, "phy_set_rf8256_bandwidth(): unknown hardware version\n");
}
break;
case HT_CHANNEL_WIDTH_20_40:
- if (priv->card_8192_version == VERSION_819xU_A || priv->card_8192_version == VERSION_819xU_B) { /* 8256 D-cut, E-cut, xiong: consider it later! */
+ if (priv->card_8192_version == VERSION_819XU_A || priv->card_8192_version == VERSION_819XU_B) { /* 8256 D-cut, E-cut, xiong: consider it later! */
rtl8192_phy_SetRFReg(dev, (enum rf90_radio_path_e)eRFPath, 0x0b, bMask12Bits, 0x300); /* phy para:3ba */
rtl8192_phy_SetRFReg(dev, (enum rf90_radio_path_e)eRFPath, 0x2c, bMask12Bits, 0x3df);
rtl8192_phy_SetRFReg(dev, (enum rf90_radio_path_e)eRFPath, 0x0e, bMask12Bits, 0x0a1);
@@ -68,11 +73,11 @@ void PHY_SetRF8256Bandwidth(struct net_device *dev, enum ht_channel_width Bandwi
else
rtl8192_phy_SetRFReg(dev, (enum rf90_radio_path_e)eRFPath, 0x14, bMask12Bits, 0x5ab);
} else {
- RT_TRACE(COMP_ERR, "PHY_SetRF8256Bandwidth(): unknown hardware version\n");
+ RT_TRACE(COMP_ERR, "phy_set_rf8256_bandwidth(): unknown hardware version\n");
}
break;
default:
- RT_TRACE(COMP_ERR, "PHY_SetRF8256Bandwidth(): unknown Bandwidth: %#X\n", Bandwidth);
+ RT_TRACE(COMP_ERR, "phy_set_rf8256_bandwidth(): unknown Bandwidth: %#X\n", Bandwidth);
break;
}
@@ -85,7 +90,7 @@ void PHY_SetRF8256Bandwidth(struct net_device *dev, enum ht_channel_width Bandwi
* Return: NONE
*--------------------------------------------------------------------------
*/
-void PHY_RF8256_Config(struct net_device *dev)
+void phy_rf8256_config(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
/* Initialize general global value
@@ -94,7 +99,7 @@ void PHY_RF8256_Config(struct net_device *dev)
*/
priv->NumTotalRFPath = RTL819X_TOTAL_RF_PATH;
/* Config BB and RF */
- phy_RF8256_Config_ParaFile(dev);
+ phy_rf8256_config_para_file(dev);
}
/*--------------------------------------------------------------------------
* Overview: Interface to config 8256
@@ -103,7 +108,7 @@ void PHY_RF8256_Config(struct net_device *dev)
* Return: NONE
*--------------------------------------------------------------------------
*/
-void phy_RF8256_Config_ParaFile(struct net_device *dev)
+static void phy_rf8256_config_para_file(struct net_device *dev)
{
u32 u4RegValue = 0;
u8 eRFPath;
@@ -152,7 +157,7 @@ void phy_RF8256_Config_ParaFile(struct net_device *dev)
* TODO: this function should be removed on ASIC , Emily 2007.2.2
*/
if (rtl8192_phy_checkBBAndRF(dev, HW90_BLOCK_RF, (enum rf90_radio_path_e)eRFPath)) {
- RT_TRACE(COMP_ERR, "PHY_RF8256_Config():Check Radio[%d] Fail!!\n", eRFPath);
+ RT_TRACE(COMP_ERR, "phy_rf8256_config():Check Radio[%d] Fail!!\n", eRFPath);
goto phy_RF8256_Config_ParaFile_Fail;
}
@@ -207,7 +212,7 @@ void phy_RF8256_Config_ParaFile(struct net_device *dev)
}
if (ret) {
- RT_TRACE(COMP_ERR, "phy_RF8256_Config_ParaFile():Radio[%d] Fail!!", eRFPath);
+ RT_TRACE(COMP_ERR, "phy_rf8256_config_para_file():Radio[%d] Fail!!", eRFPath);
goto phy_RF8256_Config_ParaFile_Fail;
}
@@ -221,7 +226,7 @@ phy_RF8256_Config_ParaFile_Fail:
}
-void PHY_SetRF8256CCKTxPower(struct net_device *dev, u8 powerlevel)
+void phy_set_rf8256_cck_tx_power(struct net_device *dev, u8 powerlevel)
{
u32 TxAGC = 0;
struct r8192_priv *priv = ieee80211_priv(dev);
@@ -240,7 +245,7 @@ void PHY_SetRF8256CCKTxPower(struct net_device *dev, u8 powerlevel)
}
-void PHY_SetRF8256OFDMTxPower(struct net_device *dev, u8 powerlevel)
+void phy_set_rf8256_ofdm_tx_power(struct net_device *dev, u8 powerlevel)
{
struct r8192_priv *priv = ieee80211_priv(dev);
/* Joseph TxPower for 8192 testing */
diff --git a/drivers/staging/rtl8192u/r8190_rtl8256.h b/drivers/staging/rtl8192u/r8190_rtl8256.h
index 29b926cad14b..9ea67f86f911 100644
--- a/drivers/staging/rtl8192u/r8190_rtl8256.h
+++ b/drivers/staging/rtl8192u/r8190_rtl8256.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* This is part of the rtl8180-sa2400 driver
* released under the GPL (See file COPYING for details).
@@ -14,10 +15,10 @@
#define RTL8225H
#define RTL819X_TOTAL_RF_PATH 2 /* for 8192U */
-void PHY_SetRF8256Bandwidth(struct net_device *dev, enum ht_channel_width Bandwidth);
-void PHY_RF8256_Config(struct net_device *dev);
-void phy_RF8256_Config_ParaFile(struct net_device *dev);
-void PHY_SetRF8256CCKTxPower(struct net_device *dev, u8 powerlevel);
-void PHY_SetRF8256OFDMTxPower(struct net_device *dev, u8 powerlevel);
+void phy_set_rf8256_bandwidth(struct net_device *dev,
+ enum ht_channel_width bandwidth);
+void phy_rf8256_config(struct net_device *dev);
+void phy_set_rf8256_cck_tx_power(struct net_device *dev, u8 powerlevel);
+void phy_set_rf8256_ofdm_tx_power(struct net_device *dev, u8 powerlevel);
#endif
diff --git a/drivers/staging/rtl8192u/r8192U.h b/drivers/staging/rtl8192u/r8192U.h
index 94a148994069..e65a893fd084 100644
--- a/drivers/staging/rtl8192u/r8192U.h
+++ b/drivers/staging/rtl8192u/r8192U.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* This is part of rtl8187 OpenSource driver.
* Copyright (C) Andrea Merello 2004-2005 <andrea.merello@gmail.com>
@@ -39,19 +40,19 @@
#include "ieee80211/ieee80211.h"
#define RTL8192U
-#define RTL819xU_MODULE_NAME "rtl819xU"
+#define RTL819XU_MODULE_NAME "rtl819xU"
/* HW security */
#define MAX_KEY_LEN 61
#define KEY_BUF_SIZE 5
-#define Rx_Smooth_Factor 20
+#define RX_SMOOTH_FACTOR 20
#define DMESG(x, a...)
#define DMESGW(x, a...)
#define DMESGE(x, a...)
extern u32 rt_global_debug_component;
#define RT_TRACE(component, x, args...) \
do { \
- if (rt_global_debug_component & component) \
+ if (rt_global_debug_component & (component)) \
pr_debug("RTL8192U: " x "\n", ##args); \
} while (0)
@@ -111,7 +112,7 @@ extern u32 rt_global_debug_component;
do { \
if ((rt_global_debug_component & (level)) == (level)) { \
int i; \
- u8 *pdata = (u8 *) data; \
+ u8 *pdata = (u8 *)data; \
pr_debug("RTL8192U: %s()\n", __func__); \
for (i = 0; i < (int)(datalen); i++) { \
printk("%2x ", pdata[i]); \
@@ -798,6 +799,18 @@ typedef enum _tag_TxCmd_Config_Index {
TXCMD_XXXX_CTRL,
} DCMD_TXCMD_OP;
+enum version_819xu {
+ VERSION_819XU_A, // A-cut
+ VERSION_819XU_B, // B-cut
+ VERSION_819XU_C,// C-cut
+};
+
+//added for different RF type
+enum rt_rf_type {
+ RF_1T2R = 0,
+ RF_2T4R,
+};
+
typedef struct r8192_priv {
struct usb_device *udev;
/* For maintain info from eeprom */
@@ -815,7 +828,7 @@ typedef struct r8192_priv {
/* O: rtl8192, 1: rtl8185 V B/C, 2: rtl8185 V D */
short card_8192;
/* If TCR reports card V B/C, this discriminates */
- u8 card_8192_version;
+ enum version_819xu card_8192_version;
short enable_gpio0;
enum card_type {
PCI, MINIPCI, CARDBUS, USB
@@ -838,7 +851,7 @@ typedef struct r8192_priv {
struct mutex wx_mutex;
- u8 rf_type; /* 0: 1T2R, 1: 2T4R */
+ enum rt_rf_type rf_type; /* 0: 1T2R, 1: 2T4R */
RT_RF_TYPE_819xU rf_chip;
short (*rf_set_sens)(struct net_device *dev, short sens);
@@ -864,9 +877,9 @@ typedef struct r8192_priv {
int rx_inx;
#endif
- struct sk_buff_head rx_queue;
- struct sk_buff_head skb_queue;
- struct work_struct qos_activate;
+ struct sk_buff_head rx_queue;
+ struct sk_buff_head skb_queue;
+ struct work_struct qos_activate;
short tx_urb_index;
atomic_t tx_pending[0x10]; /* UART_PRIORITY + 1 */
@@ -1014,7 +1027,7 @@ typedef struct r8192_priv {
u8 nrxAMPDU_aggr_num;
/* For gpio */
- bool bHwRadioOff;
+ bool bHwRadioOff;
u32 reset_count;
bool bpbc_pressed;
@@ -1079,9 +1092,6 @@ bool init_firmware(struct net_device *dev);
short rtl819xU_tx_cmd(struct net_device *dev, struct sk_buff *skb);
short rtl8192_tx(struct net_device *dev, struct sk_buff *skb);
-u32 read_cam(struct net_device *dev, u8 addr);
-void write_cam(struct net_device *dev, u8 addr, u32 data);
-
int read_nic_byte(struct net_device *dev, int x, u8 *data);
int read_nic_byte_E(struct net_device *dev, int x, u8 *data);
int read_nic_dword(struct net_device *dev, int x, u32 *data);
@@ -1094,22 +1104,12 @@ void force_pci_posting(struct net_device *dev);
void rtl8192_rtx_disable(struct net_device *dev);
void rtl8192_rx_enable(struct net_device *dev);
-void rtl8192_tx_enable(struct net_device *dev);
-
-void rtl8192_disassociate(struct net_device *dev);
-void rtl8185_set_rf_pins_enable(struct net_device *dev, u32 a);
-void rtl8192_set_anaparam(struct net_device *dev, u32 a);
-void rtl8185_set_anaparam2(struct net_device *dev, u32 a);
void rtl8192_update_msr(struct net_device *dev);
int rtl8192_down(struct net_device *dev);
int rtl8192_up(struct net_device *dev);
void rtl8192_commit(struct net_device *dev);
void rtl8192_set_chan(struct net_device *dev, short ch);
-void write_phy(struct net_device *dev, u8 adr, u8 data);
-void write_phy_cck(struct net_device *dev, u8 adr, u32 data);
-void write_phy_ofdm(struct net_device *dev, u8 adr, u32 data);
-void rtl8185_tx_antenna(struct net_device *dev, u8 ant);
void rtl8192_set_rxconf(struct net_device *dev);
void rtl819xusb_beacon_tx(struct net_device *dev, u16 tx_rate);
diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c
index e218b5c20642..0ac0bbf7d923 100644
--- a/drivers/staging/rtl8192u/r8192U_core.c
+++ b/drivers/staging/rtl8192u/r8192U_core.c
@@ -128,7 +128,7 @@ static void rtl8192_usb_disconnect(struct usb_interface *intf);
static struct usb_driver rtl8192_usb_driver = {
- .name = RTL819xU_MODULE_NAME, /* Driver name */
+ .name = RTL819XU_MODULE_NAME, /* Driver name */
.id_table = rtl8192_usb_id_tbl, /* PCI_ID table */
.probe = rtl8192_usb_probe, /* probe fn */
.disconnect = rtl8192_usb_disconnect, /* remove fn */
@@ -183,7 +183,7 @@ static void rtl819x_set_channel_map(u8 channel_plan, struct r8192_priv *priv)
case COUNTRY_CODE_ISRAEL:
case COUNTRY_CODE_TELEC:
case COUNTRY_CODE_MIC:
- Dot11d_Init(ieee);
+ rtl8192u_dot11d_init(ieee);
ieee->bGlobalDomain = false;
/* actually 8225 & 8256 rf chips only support B,G,24N mode */
if ((priv->rf_chip == RF_8225) || (priv->rf_chip == RF_8256)) {
@@ -211,8 +211,8 @@ static void rtl819x_set_channel_map(u8 channel_plan, struct r8192_priv *priv)
/* this flag enabled to follow 11d country IE setting,
* otherwise, it shall follow global domain settings.
*/
- GET_DOT11D_INFO(ieee)->enabled = 0;
- Dot11d_Reset(ieee);
+ GET_DOT11D_INFO(ieee)->dot11d_enabled = 0;
+ dot11d_reset(ieee);
ieee->bGlobalDomain = true;
break;
@@ -237,22 +237,6 @@ static void CamResetAllEntry(struct net_device *dev)
write_nic_dword(dev, RWCAM, ulcommand);
}
-
-void write_cam(struct net_device *dev, u8 addr, u32 data)
-{
- write_nic_dword(dev, WCAMI, data);
- write_nic_dword(dev, RWCAM, BIT(31) | BIT(16) | (addr & 0xff));
-}
-
-u32 read_cam(struct net_device *dev, u8 addr)
-{
- u32 data;
-
- write_nic_dword(dev, RWCAM, 0x80000000 | (addr & 0xff));
- read_nic_dword(dev, 0xa8, &data);
- return data;
-}
-
int write_nic_byte_E(struct net_device *dev, int indx, u8 data)
{
int status;
@@ -643,7 +627,7 @@ static int __maybe_unused proc_get_stats_rx(struct seq_file *m, void *v)
static void rtl8192_proc_module_init(void)
{
RT_TRACE(COMP_INIT, "Initializing proc filesystem");
- rtl8192_proc = proc_mkdir(RTL819xU_MODULE_NAME, init_net.proc_net);
+ rtl8192_proc = proc_mkdir(RTL819XU_MODULE_NAME, init_net.proc_net);
}
static void rtl8192_proc_init_one(struct net_device *dev)
@@ -846,13 +830,6 @@ void rtl8192_rx_enable(struct net_device *dev)
rtl8192_rx_initiate(dev);
}
-
-void rtl8192_tx_enable(struct net_device *dev)
-{
-}
-
-
-
void rtl8192_rtx_disable(struct net_device *dev)
{
u8 cmd;
@@ -1997,7 +1974,7 @@ static void rtl8192_update_ratr_table(struct net_device *dev)
break;
case IEEE_N_24G:
case IEEE_N_5G:
- if (ieee->pHTInfo->PeerMimoPs == 0) { /* MIMO_PS_STATIC */
+ if (ieee->pHTInfo->PeerMimoPs == MIMO_PS_STATIC) {
ratr_value &= 0x0007F007;
} else {
if (priv->rf_type == RF_1T2R)
@@ -2382,20 +2359,20 @@ static int rtl8192_read_eeprom_info(struct net_device *dev)
if (ret < 0)
return ret;
priv->eeprom_pid = (u16)ret;
- ret = eprom_read(dev, EEPROM_ChannelPlan >> 1);
+ ret = eprom_read(dev, EEPROM_CHANNEL_PLAN >> 1);
if (ret < 0)
return ret;
tmpValue = (u16)ret;
priv->eeprom_ChannelPlan = (tmpValue & 0xff00) >> 8;
priv->btxpowerdata_readfromEEPORM = true;
- ret = eprom_read(dev, (EEPROM_Customer_ID >> 1)) >> 8;
+ ret = eprom_read(dev, (EEPROM_CUSTOMER_ID >> 1)) >> 8;
if (ret < 0)
return ret;
priv->eeprom_CustomerID = (u16)ret;
} else {
priv->eeprom_vid = 0;
priv->eeprom_pid = 0;
- priv->card_8192_version = VERSION_819xU_B;
+ priv->card_8192_version = VERSION_819XU_B;
priv->eeprom_ChannelPlan = 0;
priv->eeprom_CustomerID = 0;
}
@@ -2422,48 +2399,48 @@ static int rtl8192_read_eeprom_info(struct net_device *dev)
priv->rf_type = RTL819X_DEFAULT_RF_TYPE; /* default 1T2R */
priv->rf_chip = RF_8256;
- if (priv->card_8192_version == (u8)VERSION_819xU_A) {
+ if (priv->card_8192_version == VERSION_819XU_A) {
/* read Tx power gain offset of legacy OFDM to HT rate */
if (bLoad_From_EEPOM) {
- ret = eprom_read(dev, (EEPROM_TxPowerDiff >> 1));
+ ret = eprom_read(dev, (EEPROM_TX_POWER_DIFF >> 1));
if (ret < 0)
return ret;
priv->EEPROMTxPowerDiff = ((u16)ret & 0xff00) >> 8;
} else
- priv->EEPROMTxPowerDiff = EEPROM_Default_TxPower;
+ priv->EEPROMTxPowerDiff = EEPROM_DEFAULT_TX_POWER;
RT_TRACE(COMP_EPROM, "TxPowerDiff:%d\n", priv->EEPROMTxPowerDiff);
/* read ThermalMeter from EEPROM */
if (bLoad_From_EEPOM) {
- ret = eprom_read(dev, (EEPROM_ThermalMeter >> 1));
+ ret = eprom_read(dev, (EEPROM_THERMAL_METER >> 1));
if (ret < 0)
return ret;
priv->EEPROMThermalMeter = (u8)((u16)ret & 0x00ff);
} else
- priv->EEPROMThermalMeter = EEPROM_Default_ThermalMeter;
+ priv->EEPROMThermalMeter = EEPROM_DEFAULT_THERNAL_METER;
RT_TRACE(COMP_EPROM, "ThermalMeter:%d\n", priv->EEPROMThermalMeter);
/* for tx power track */
priv->TSSI_13dBm = priv->EEPROMThermalMeter * 100;
/* read antenna tx power offset of B/C/D to A from EEPROM */
if (bLoad_From_EEPOM) {
- ret = eprom_read(dev, (EEPROM_PwDiff >> 1));
+ ret = eprom_read(dev, (EEPROM_PW_DIFF >> 1));
if (ret < 0)
return ret;
priv->EEPROMPwDiff = ((u16)ret & 0x0f00) >> 8;
} else
- priv->EEPROMPwDiff = EEPROM_Default_PwDiff;
+ priv->EEPROMPwDiff = EEPROM_DEFAULT_PW_DIFF;
RT_TRACE(COMP_EPROM, "TxPwDiff:%d\n", priv->EEPROMPwDiff);
/* Read CrystalCap from EEPROM */
if (bLoad_From_EEPOM) {
- ret = eprom_read(dev, (EEPROM_CrystalCap >> 1));
+ ret = eprom_read(dev, (EEPROM_CRYSTAL_CAP >> 1));
if (ret < 0)
return ret;
priv->EEPROMCrystalCap = (u16)ret & 0x0f;
} else
- priv->EEPROMCrystalCap = EEPROM_Default_CrystalCap;
+ priv->EEPROMCrystalCap = EEPROM_DEFAULT_CRYSTAL_CAP;
RT_TRACE(COMP_EPROM, "CrystalCap = %d\n", priv->EEPROMCrystalCap);
/* get per-channel Tx power level */
if (bLoad_From_EEPOM) {
- ret = eprom_read(dev, (EEPROM_TxPwIndex_Ver >> 1));
+ ret = eprom_read(dev, (EEPROM_TX_PW_INDEX_VER >> 1));
if (ret < 0)
return ret;
priv->EEPROM_Def_Ver = ((u16)ret & 0xff00) >> 8;
@@ -2474,7 +2451,7 @@ static int rtl8192_read_eeprom_info(struct net_device *dev)
int i;
if (bLoad_From_EEPOM) {
- ret = eprom_read(dev, (EEPROM_TxPwIndex_CCK >> 1));
+ ret = eprom_read(dev, (EEPROM_TX_PW_INDEX_CCK >> 1));
if (ret < 0)
return ret;
priv->EEPROMTxPowerLevelCCK = ((u16)ret & 0xff) >> 8;
@@ -2483,10 +2460,10 @@ static int rtl8192_read_eeprom_info(struct net_device *dev)
RT_TRACE(COMP_EPROM, "CCK Tx Power Levl: 0x%02x\n", priv->EEPROMTxPowerLevelCCK);
for (i = 0; i < 3; i++) {
if (bLoad_From_EEPOM) {
- ret = eprom_read(dev, (EEPROM_TxPwIndex_OFDM_24G + i) >> 1);
+ ret = eprom_read(dev, (EEPROM_TX_PW_INDEX_OFDM_24G + i) >> 1);
if (ret < 0)
return ret;
- if (((EEPROM_TxPwIndex_OFDM_24G + i) % 2) == 0)
+ if (((EEPROM_TX_PW_INDEX_OFDM_24G + i) % 2) == 0)
tmpValue = (u16)ret & 0x00ff;
else
tmpValue = ((u16)ret & 0xff00) >> 8;
@@ -2498,7 +2475,7 @@ static int rtl8192_read_eeprom_info(struct net_device *dev)
}
} else if (priv->EEPROM_Def_Ver == 1) {
if (bLoad_From_EEPOM) {
- ret = eprom_read(dev, EEPROM_TxPwIndex_CCK_V1 >> 1);
+ ret = eprom_read(dev, EEPROM_TX_PW_INDEX_CCK_V1 >> 1);
if (ret < 0)
return ret;
tmpValue = ((u16)ret & 0xff00) >> 8;
@@ -2508,7 +2485,7 @@ static int rtl8192_read_eeprom_info(struct net_device *dev)
priv->EEPROMTxPowerLevelCCK_V1[0] = (u8)tmpValue;
if (bLoad_From_EEPOM) {
- ret = eprom_read(dev, (EEPROM_TxPwIndex_CCK_V1 + 2) >> 1);
+ ret = eprom_read(dev, (EEPROM_TX_PW_INDEX_CCK_V1 + 2) >> 1);
if (ret < 0)
return ret;
tmpValue = (u16)ret;
@@ -2517,12 +2494,12 @@ static int rtl8192_read_eeprom_info(struct net_device *dev)
*((u16 *)(&priv->EEPROMTxPowerLevelCCK_V1[1])) = tmpValue;
if (bLoad_From_EEPOM)
tmpValue = eprom_read(dev,
- EEPROM_TxPwIndex_OFDM_24G_V1 >> 1);
+ EEPROM_TX_PW_INDEX_OFDM_24G_V1 >> 1);
else
tmpValue = 0x1010;
*((u16 *)(&priv->EEPROMTxPowerLevelOFDM24G[0])) = tmpValue;
if (bLoad_From_EEPOM)
- tmpValue = eprom_read(dev, (EEPROM_TxPwIndex_OFDM_24G_V1 + 2) >> 1);
+ tmpValue = eprom_read(dev, (EEPROM_TX_PW_INDEX_OFDM_24G_V1 + 2) >> 1);
else
tmpValue = 0x10;
priv->EEPROMTxPowerLevelOFDM24G[2] = (u8)tmpValue;
@@ -2567,7 +2544,7 @@ static int rtl8192_read_eeprom_info(struct net_device *dev)
* 92U does not enable TX power tracking.
*/
priv->ThermalMeter[0] = priv->EEPROMThermalMeter;
- } /* end if VersionID == VERSION_819xU_A */
+ } /* end if VersionID == VERSION_819XU_A */
/* for dlink led */
switch (priv->eeprom_CustomerID) {
@@ -2872,7 +2849,7 @@ static bool rtl8192_adapter_start(struct net_device *dev)
rtl8192_phy_configmac(dev);
- if (priv->card_8192_version == (u8)VERSION_819xU_A) {
+ if (priv->card_8192_version == VERSION_819XU_A) {
rtl8192_phy_getTxPower(dev);
rtl8192_phy_setTxPower(dev, priv->chan);
}
@@ -3998,13 +3975,13 @@ static void rtl8192_process_phyinfo(struct r8192_priv *priv, u8 *buffer,
pprevious_stats->RxMIMOSignalStrength[rfpath];
if (pprevious_stats->RxMIMOSignalStrength[rfpath] > priv->stats.rx_rssi_percentage[rfpath]) {
priv->stats.rx_rssi_percentage[rfpath] =
- ((priv->stats.rx_rssi_percentage[rfpath] * (Rx_Smooth_Factor - 1)) +
- (pprevious_stats->RxMIMOSignalStrength[rfpath])) / (Rx_Smooth_Factor);
+ ((priv->stats.rx_rssi_percentage[rfpath] * (RX_SMOOTH_FACTOR - 1)) +
+ (pprevious_stats->RxMIMOSignalStrength[rfpath])) / (RX_SMOOTH_FACTOR);
priv->stats.rx_rssi_percentage[rfpath] = priv->stats.rx_rssi_percentage[rfpath] + 1;
} else {
priv->stats.rx_rssi_percentage[rfpath] =
- ((priv->stats.rx_rssi_percentage[rfpath] * (Rx_Smooth_Factor - 1)) +
- (pprevious_stats->RxMIMOSignalStrength[rfpath])) / (Rx_Smooth_Factor);
+ ((priv->stats.rx_rssi_percentage[rfpath] * (RX_SMOOTH_FACTOR - 1)) +
+ (pprevious_stats->RxMIMOSignalStrength[rfpath])) / (RX_SMOOTH_FACTOR);
}
RT_TRACE(COMP_DBG,
"priv->stats.rx_rssi_percentage[rfPath] = %d\n",
@@ -4049,13 +4026,13 @@ static void rtl8192_process_phyinfo(struct r8192_priv *priv, u8 *buffer,
pprevious_stats->RxPWDBAll;
if (pprevious_stats->RxPWDBAll > (u32)priv->undecorated_smoothed_pwdb) {
priv->undecorated_smoothed_pwdb =
- (((priv->undecorated_smoothed_pwdb) * (Rx_Smooth_Factor - 1)) +
- (pprevious_stats->RxPWDBAll)) / (Rx_Smooth_Factor);
+ (((priv->undecorated_smoothed_pwdb) * (RX_SMOOTH_FACTOR - 1)) +
+ (pprevious_stats->RxPWDBAll)) / (RX_SMOOTH_FACTOR);
priv->undecorated_smoothed_pwdb = priv->undecorated_smoothed_pwdb + 1;
} else {
priv->undecorated_smoothed_pwdb =
- (((priv->undecorated_smoothed_pwdb) * (Rx_Smooth_Factor - 1)) +
- (pprevious_stats->RxPWDBAll)) / (Rx_Smooth_Factor);
+ (((priv->undecorated_smoothed_pwdb) * (RX_SMOOTH_FACTOR - 1)) +
+ (pprevious_stats->RxPWDBAll)) / (RX_SMOOTH_FACTOR);
}
}
@@ -4098,8 +4075,8 @@ static void rtl8192_process_phyinfo(struct r8192_priv *priv, u8 *buffer,
if (priv->stats.rx_evm_percentage[nspatial_stream] == 0) /* initialize */
priv->stats.rx_evm_percentage[nspatial_stream] = pprevious_stats->RxMIMOSignalQuality[nspatial_stream];
priv->stats.rx_evm_percentage[nspatial_stream] =
- ((priv->stats.rx_evm_percentage[nspatial_stream] * (Rx_Smooth_Factor - 1)) +
- (pprevious_stats->RxMIMOSignalQuality[nspatial_stream] * 1)) / (Rx_Smooth_Factor);
+ ((priv->stats.rx_evm_percentage[nspatial_stream] * (RX_SMOOTH_FACTOR - 1)) +
+ (pprevious_stats->RxMIMOSignalQuality[nspatial_stream] * 1)) / (RX_SMOOTH_FACTOR);
}
}
}
@@ -4460,15 +4437,15 @@ static void TranslateRxSignalStuff819xUsb(struct sk_buff *skb,
/* Check if the received packet is acceptable. */
bpacket_match_bssid = (type != IEEE80211_FTYPE_CTL) &&
- (eqMacAddr(priv->ieee80211->current_network.bssid, (fc & IEEE80211_FCTL_TODS) ? hdr->addr1 : (fc & IEEE80211_FCTL_FROMDS) ? hdr->addr2 : hdr->addr3))
+ (ether_addr_equal(priv->ieee80211->current_network.bssid, (fc & IEEE80211_FCTL_TODS) ? hdr->addr1 : (fc & IEEE80211_FCTL_FROMDS) ? hdr->addr2 : hdr->addr3))
&& (!pstats->bHwError) && (!pstats->bCRC) && (!pstats->bICV);
bpacket_toself = bpacket_match_bssid &
- (eqMacAddr(praddr, priv->ieee80211->dev->dev_addr));
+ (ether_addr_equal(praddr, priv->ieee80211->dev->dev_addr));
if (WLAN_FC_GET_FRAMETYPE(fc) == IEEE80211_STYPE_BEACON)
bPacketBeacon = true;
if (WLAN_FC_GET_FRAMETYPE(fc) == IEEE80211_STYPE_BLOCKACK) {
- if ((eqMacAddr(praddr, dev->dev_addr)))
+ if ((ether_addr_equal(praddr, dev->dev_addr)))
bToSelfBA = true;
}
diff --git a/drivers/staging/rtl8192u/r8192U_hw.h b/drivers/staging/rtl8192u/r8192U_hw.h
index 00a123d44207..5a958335681d 100644
--- a/drivers/staging/rtl8192u/r8192U_hw.h
+++ b/drivers/staging/rtl8192u/r8192U_hw.h
@@ -20,24 +20,6 @@
#ifndef R8192_HW
#define R8192_HW
-typedef enum _VERSION_819xU {
- VERSION_819xU_A, // A-cut
- VERSION_819xU_B, // B-cut
- VERSION_819xU_C,// C-cut
-} VERSION_819xU, *PVERSION_819xU;
-//added for different RF type
-typedef enum _RT_RF_TYPE_DEF {
- RF_1T2R = 0,
- RF_2T4R,
-
- RF_819X_MAX_TYPE
-} RT_RF_TYPE_DEF;
-
-
-typedef enum _BaseBand_Config_Type {
- BaseBand_Config_PHY_REG = 0, //Radio Path A
- BaseBand_Config_AGC_TAB = 1, //Radio Path B
-} BaseBand_Config_Type, *PBaseBand_Config_Type;
#define RTL8187_REQT_READ 0xc0
#define RTL8187_REQT_WRITE 0x40
#define RTL8187_REQ_GET_REGS 0x05
@@ -47,58 +29,33 @@ typedef enum _BaseBand_Config_Type {
#define MAX_RX_URB 16
#define R8180_MAX_RETRY 255
-//#define MAX_RX_NORMAL_URB 3
-//#define MAX_RX_COMMAND_URB 2
-#define RX_URB_SIZE 9100
-
-#define BB_ANTATTEN_CHAN14 0x0c
-#define BB_ANTENNA_B 0x40
-#define BB_HOST_BANG BIT(30)
-#define BB_HOST_BANG_EN BIT(2)
-#define BB_HOST_BANG_CLK BIT(1)
-#define BB_HOST_BANG_RW BIT(3)
-#define BB_HOST_BANG_DATA 1
+#define RX_URB_SIZE 9100
-//#if (RTL819X_FPGA_VER & RTL819X_FPGA_VIVI_070920)
-#define AFR 0x010
-#define AFR_CardBEn BIT(0)
-#define AFR_CLKRUN_SEL BIT(1)
-#define AFR_FuncRegEn BIT(2)
#define RTL8190_EEPROM_ID 0x8129
#define EEPROM_VID 0x02
#define EEPROM_PID 0x04
#define EEPROM_NODE_ADDRESS_BYTE_0 0x0C
-#define EEPROM_TxPowerDiff 0x1F
-#define EEPROM_ThermalMeter 0x20
-#define EEPROM_PwDiff 0x21 //0x21
-#define EEPROM_CrystalCap 0x22 //0x22
+#define EEPROM_TX_POWER_DIFF 0x1F
+#define EEPROM_THERMAL_METER 0x20
+#define EEPROM_PW_DIFF 0x21 //0x21
+#define EEPROM_CRYSTAL_CAP 0x22 //0x22
-#define EEPROM_TxPwIndex_CCK 0x23 //0x23
-#define EEPROM_TxPwIndex_OFDM_24G 0x24 //0x24~0x26
-#define EEPROM_TxPwIndex_CCK_V1 0x29 //0x29~0x2B
-#define EEPROM_TxPwIndex_OFDM_24G_V1 0x2C //0x2C~0x2E
-#define EEPROM_TxPwIndex_Ver 0x27 //0x27
+#define EEPROM_TX_PW_INDEX_CCK 0x23 //0x23
+#define EEPROM_TX_PW_INDEX_OFDM_24G 0x24 //0x24~0x26
+#define EEPROM_TX_PW_INDEX_CCK_V1 0x29 //0x29~0x2B
+#define EEPROM_TX_PW_INDEX_OFDM_24G_V1 0x2C //0x2C~0x2E
+#define EEPROM_TX_PW_INDEX_VER 0x27 //0x27
-#define EEPROM_Default_TxPowerDiff 0x0
-#define EEPROM_Default_ThermalMeter 0x7
-#define EEPROM_Default_PwDiff 0x4
-#define EEPROM_Default_CrystalCap 0x5
-#define EEPROM_Default_TxPower 0x1010
-#define EEPROM_Customer_ID 0x7B //0x7B:CustomerID
-#define EEPROM_ChannelPlan 0x16 //0x7C
-#define EEPROM_IC_VER 0x7d //0x7D
-#define EEPROM_CRC 0x7e //0x7E~0x7F
+#define EEPROM_DEFAULT_THERNAL_METER 0x7
+#define EEPROM_DEFAULT_PW_DIFF 0x4
+#define EEPROM_DEFAULT_CRYSTAL_CAP 0x5
+#define EEPROM_DEFAULT_TX_POWER 0x1010
+#define EEPROM_CUSTOMER_ID 0x7B //0x7B:CustomerID
+#define EEPROM_CHANNEL_PLAN 0x16 //0x7C
-#define EEPROM_CID_DEFAULT 0x0
-#define EEPROM_CID_CAMEO 0x1
#define EEPROM_CID_RUNTOP 0x2
-#define EEPROM_CID_Senao 0x3
-#define EEPROM_CID_TOSHIBA 0x4 // Toshiba setting, Merge by Jacken, 2008/01/31
-#define EEPROM_CID_NetCore 0x5
-#define EEPROM_CID_Nettronix 0x6
-#define EEPROM_CID_Pronet 0x7
#define EEPROM_CID_DLINK 0x8
#define AC_PARAM_TXOP_LIMIT_OFFSET 16
@@ -108,18 +65,16 @@ typedef enum _BaseBand_Config_Type {
//#endif
enum _RTL8192Usb_HW {
+ MAC0 = 0x000,
+ MAC4 = 0x004,
- PCIF = 0x009, // PCI Function Register 0x0009h~0x000bh
#define BB_GLOBAL_RESET_BIT 0x1
BB_GLOBAL_RESET = 0x020, // BasebandGlobal Reset Register
BSSIDR = 0x02E, // BSSID Register
CMDR = 0x037, // Command register
-#define CR_RST 0x10
#define CR_RE 0x08
#define CR_TE 0x04
-#define CR_MulRW 0x01
SIFS = 0x03E, // SIFS register
- TCR = 0x040, // Transmit Configuration Register
#define TCR_MXDMA_2048 7
#define TCR_LRL_OFFSET 0
@@ -132,26 +87,16 @@ enum _RTL8192Usb_HW {
BIT(22) | BIT(23))
#define RX_FIFO_THRESHOLD_MASK (BIT(13) | BIT(14) | BIT(15))
#define RX_FIFO_THRESHOLD_SHIFT 13
-#define RX_FIFO_THRESHOLD_128 3
-#define RX_FIFO_THRESHOLD_256 4
-#define RX_FIFO_THRESHOLD_512 5
-#define RX_FIFO_THRESHOLD_1024 6
#define RX_FIFO_THRESHOLD_NONE 7
#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.
-#define RCR_ENCS2 BIT(30) // Enable Carrier Sense Detection Method 2
-#define RCR_ENCS1 BIT(29) // Enable Carrier Sense Detection Method 1
-#define RCR_ENMBID BIT(27) // Enable Multiple BssId.
-#define RCR_ACKTXBW (BIT(24) | BIT(25)) // TXBW Setting of ACK frames
#define RCR_CBSSID BIT(23) // Accept BSSID match packet
#define RCR_APWRMGT BIT(22) // Accept power management packet
-#define RCR_ADD3 BIT(21) // Accept address 3 match packet
#define RCR_AMF BIT(20) // Accept management type frame
#define RCR_ACF BIT(19) // Accept control type frame
#define RCR_ADF BIT(18) // Accept data type frame
-#define RCR_RXFTH BIT(13) // Rx FIFO Threshold
#define RCR_AICV BIT(12) // Accept ICV error packet
#define RCR_ACRC32 BIT(5) // Accept CRC32 error packet
#define RCR_AB BIT(3) // Accept broadcast packet
@@ -160,14 +105,10 @@ enum _RTL8192Usb_HW {
#define RCR_AAP BIT(0) // Accept all unicast packet
SLOT_TIME = 0x049, // Slot Time Register
ACK_TIMEOUT = 0x04c, // Ack Timeout Register
- PIFS_TIME = 0x04d, // PIFS time
- USTIME = 0x04e, // Microsecond Tuning Register, Sets the microsecond time unit used by MAC clock.
EDCAPARA_BE = 0x050, // EDCA Parameter of AC BE
EDCAPARA_BK = 0x054, // EDCA Parameter of AC BK
EDCAPARA_VO = 0x058, // EDCA Parameter of AC VO
EDCAPARA_VI = 0x05C, // EDCA Parameter of AC VI
- RFPC = 0x05F, // Rx FIFO Packet Count
- CWRR = 0x060, // Contention Window Report Register
BCN_TCFG = 0x062, // Beacon Time Configuration
#define BCN_TCFG_CW_SHIFT 8
#define BCN_TCFG_IFS 0
@@ -178,7 +119,6 @@ enum _RTL8192Usb_HW {
BCN_ERR_THRESH = 0x078, // Beacon Error Threshold
RWCAM = 0x0A0, //IN 8190 Data Sheet is called CAMcmd
WCAMI = 0x0A4, // Software write CAM input content
- RCAMO = 0x0A8, // Software read/write CAM config
SECR = 0x0B0, //Security Configuration Register
#define SCR_TxUseDK BIT(0) //Force Tx Use Default Key
#define SCR_RxUseDK BIT(1) //Force Rx Use Default Key
@@ -186,21 +126,6 @@ enum _RTL8192Usb_HW {
#define SCR_RxDecEnable BIT(3) //Enable Rx Decryption
#define SCR_SKByA2 BIT(4) //Search kEY BY A2
#define SCR_NoSKMC BIT(5) //No Key Search for Multicast
-#define SCR_UseDK 0x01
-#define SCR_TxSecEnable 0x02
-#define SCR_RxSecEnable 0x04
- TPPoll = 0x0fd, // Transmit priority polling register
- PSR = 0x0ff, // Page Select Register
-#define CPU_CCK_LOOPBACK 0x00030000
-#define CPU_GEN_SYSTEM_RESET 0x00000001
-#define CPU_GEN_FIRMWARE_RESET 0x00000008
-#define CPU_GEN_BOOT_RDY 0x00000010
-#define CPU_GEN_FIRM_RDY 0x00000020
-#define CPU_GEN_PUT_CODE_OK 0x00000080
-#define CPU_GEN_BB_RST 0x00000100
-#define CPU_GEN_PWR_STB_CPU 0x00000004
-#define CPU_GEN_NO_LOOPBACK_MSK 0xFFF8FFFF // Set bit18,17,16 to 0. Set bit19
-#define CPU_GEN_NO_LOOPBACK_SET 0x00080000 // Set BIT19 to 1
//----------------------------------------------------------------------------
// 8190 CPU General Register (offset 0x100, 4 byte)
@@ -216,72 +141,20 @@ enum _RTL8192Usb_HW {
#define CPU_GEN_NO_LOOPBACK_MSK 0xFFF8FFFF // Set bit18,17,16 to 0. Set bit19
#define CPU_GEN_NO_LOOPBACK_SET 0x00080000 // Set BIT19 to 1
CPU_GEN = 0x100, // CPU Reset Register
- LED1Cfg = 0x154,// LED1 Configuration Register
- LED0Cfg = 0x155,// LED0 Configuration Register
- AcmAvg = 0x170, // ACM Average Period Register
AcmHwCtrl = 0x171, // ACM Hardware Control Register
//----------------------------------------------------------------------------
////
//// 8190 AcmHwCtrl bits (offset 0x171, 1 byte)
////----------------------------------------------------------------------------
//
-#define AcmHw_HwEn BIT(0)
#define AcmHw_BeqEn BIT(1)
-#define AcmHw_ViqEn BIT(2)
-#define AcmHw_VoqEn BIT(3)
-#define AcmHw_BeqStatus BIT(4)
-#define AcmHw_ViqStatus BIT(5)
-#define AcmHw_VoqStatus BIT(6)
- AcmFwCtrl = 0x172, // ACM Firmware Control Register
- AES_11N_FIX = 0x173,
- VOAdmTime = 0x174, // VO Queue Admitted Time Register
- VIAdmTime = 0x178, // VI Queue Admitted Time Register
- BEAdmTime = 0x17C, // BE Queue Admitted Time Register
RQPN1 = 0x180, // Reserved Queue Page Number , Vo Vi, Be, Bk
RQPN2 = 0x184, // Reserved Queue Page Number, HCCA, Cmd, Mgnt, High
RQPN3 = 0x188, // Reserved Queue Page Number, Bcn, Public,
-// QPRR = 0x1E0, // Queue Page Report per TID
QPNR = 0x1D0, //0x1F0, // Queue Packet Number report per TID
- BQDA = 0x200, // Beacon Queue Descriptor Address
- HQDA = 0x204, // High Priority Queue Descriptor Address
- CQDA = 0x208, // Command Queue Descriptor Address
- MQDA = 0x20C, // Management Queue Descriptor Address
- HCCAQDA = 0x210, // HCCA Queue Descriptor Address
- VOQDA = 0x214, // VO Queue Descriptor Address
- VIQDA = 0x218, // VI Queue Descriptor Address
- BEQDA = 0x21C, // BE Queue Descriptor Address
- BKQDA = 0x220, // BK Queue Descriptor Address
- RCQDA = 0x224, // Receive command Queue Descriptor Address
- RDQDA = 0x228, // Receive Queue Descriptor Start Address
-
- MAR0 = 0x240, // Multicast filter.
- MAR4 = 0x244,
-
- CCX_PERIOD = 0x250, // CCX Measurement Period Register, in unit of TU.
- CLM_RESULT = 0x251, // CCA Busy fraction register.
- NHM_PERIOD = 0x252, // NHM Measurement Period register, in unit of TU.
- NHM_THRESHOLD0 = 0x253, // Noise Histogram Meashorement0.
- NHM_THRESHOLD1 = 0x254, // Noise Histogram Meashorement1.
- NHM_THRESHOLD2 = 0x255, // Noise Histogram Meashorement2.
- NHM_THRESHOLD3 = 0x256, // Noise Histogram Meashorement3.
- NHM_THRESHOLD4 = 0x257, // Noise Histogram Meashorement4.
- NHM_THRESHOLD5 = 0x258, // Noise Histogram Meashorement5.
- NHM_THRESHOLD6 = 0x259, // Noise Histogram Meashorement6
-
- MCTRL = 0x25A, // Measurement Control
-
- NHM_RPI_COUNTER0 = 0x264, // Noise Histogram RPI counter0, the fraction of signal strength < NHM_THRESHOLD0.
- NHM_RPI_COUNTER1 = 0x265, // Noise Histogram RPI counter1, the fraction of signal strength in (NHM_THRESHOLD0, NHM_THRESHOLD1].
- NHM_RPI_COUNTER2 = 0x266, // Noise Histogram RPI counter2, the fraction of signal strength in (NHM_THRESHOLD1, NHM_THRESHOLD2].
- NHM_RPI_COUNTER3 = 0x267, // Noise Histogram RPI counter3, the fraction of signal strength in (NHM_THRESHOLD2, NHM_THRESHOLD3].
- NHM_RPI_COUNTER4 = 0x268, // Noise Histogram RPI counter4, the fraction of signal strength in (NHM_THRESHOLD3, NHM_THRESHOLD4].
- NHM_RPI_COUNTER5 = 0x269, // Noise Histogram RPI counter5, the fraction of signal strength in (NHM_THRESHOLD4, NHM_THRESHOLD5].
- NHM_RPI_COUNTER6 = 0x26A, // Noise Histogram RPI counter6, the fraction of signal strength in (NHM_THRESHOLD5, NHM_THRESHOLD6].
- NHM_RPI_COUNTER7 = 0x26B, // Noise Histogram RPI counter7, the fraction of signal strength in (NHM_THRESHOLD6, NHM_THRESHOLD7].
-#define BW_OPMODE_11J BIT(0)
#define BW_OPMODE_5G BIT(1)
#define BW_OPMODE_20MHZ BIT(2)
BW_OPMODE = 0x300, // Bandwidth operation mode
@@ -292,18 +165,10 @@ enum _RTL8192Usb_HW {
#define MSR_LINK_SHIFT 0
#define MSR_LINK_ADHOC 1
#define MSR_LINK_MASTER 3
-#define MSR_LINK_ENEDCA BIT(4)
RETRY_LIMIT = 0x304, // Retry Limit [15:8]-short, [7:0]-long
#define RETRY_LIMIT_SHORT_SHIFT 8
#define RETRY_LIMIT_LONG_SHIFT 0
- TSFR = 0x308,
RRSR = 0x310, // Response Rate Set
-#define RRSR_RSC_OFFSET 21
-#define RRSR_SHORT_OFFSET 23
-#define RRSR_RSC_DUPLICATE 0x600000
-#define RRSR_RSC_LOWSUBCHNL 0x400000
-#define RRSR_RSC_UPSUBCHANL 0x200000
-#define RRSR_SHORT 0x800000
#define RRSR_1M BIT(0)
#define RRSR_2M BIT(1)
#define RRSR_5_5M BIT(2)
@@ -316,17 +181,9 @@ enum _RTL8192Usb_HW {
#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)
#define BRSR_AckShortPmb BIT(23) // CCK ACK: use Short Preamble or not.
- RATR0 = 0x320, // Rate Adaptive Table register1
UFWP = 0x318,
+ RATR0 = 0x320, // Rate Adaptive Table register1
DRIVER_RSSI = 0x32c, // Driver tell Firmware current RSSI
//----------------------------------------------------------------------------
// 8190 Rate Adaptive Table Register (offset 0x320, 4 byte)
@@ -372,41 +229,18 @@ enum _RTL8192Usb_HW {
#define RATE_ALL_OFDM_2SS RATR_MCS8|RATR_MCS9 |RATR_MCS10|RATR_MCS11| \
RATR_MCS12|RATR_MCS13|RATR_MCS14|RATR_MCS15
- MCS_TXAGC = 0x340, // MCS AGC
- CCK_TXAGC = 0x348, // CCK AGC
-// ISR = 0x350, // Interrupt Status Register
-// IMR = 0x354, // Interrupt Mask Register
-// IMR_POLL = 0x360,
- MacBlkCtrl = 0x403, // Mac block on/off control register
-
EPROM_CMD = 0xfe58,
#define Cmd9346CR_9356SEL BIT(4)
-#define EPROM_CMD_RESERVED_MASK BIT(5)
#define EPROM_CMD_OPERATING_MODE_SHIFT 6
-#define EPROM_CMD_OPERATING_MODE_MASK (BIT(7) | BIT(6))
-#define EPROM_CMD_CONFIG 0x3
#define EPROM_CMD_NORMAL 0
-#define EPROM_CMD_LOAD 1
#define EPROM_CMD_PROGRAM 2
#define EPROM_CS_BIT BIT(3)
#define EPROM_CK_BIT BIT(2)
#define EPROM_W_BIT BIT(1)
#define EPROM_R_BIT BIT(0)
-
- MAC0 = 0x000,
- MAC1 = 0x001,
- MAC2 = 0x002,
- MAC3 = 0x003,
- MAC4 = 0x004,
- MAC5 = 0x005,
-
};
//----------------------------------------------------------------------------
// 818xB AnaParm & AnaParm2 Register
//----------------------------------------------------------------------------
-//#define ANAPARM_ASIC_ON 0x45090658
-//#define ANAPARM2_ASIC_ON 0x727f3f52
#define GPI 0x108
-#define GPO 0x109
-#define GPE 0x10a
#endif
diff --git a/drivers/staging/rtl8192u/r819xU_firmware.c b/drivers/staging/rtl8192u/r819xU_firmware.c
index 9c7e19aedff1..c3ea906f3af3 100644
--- a/drivers/staging/rtl8192u/r819xU_firmware.c
+++ b/drivers/staging/rtl8192u/r819xU_firmware.c
@@ -208,8 +208,8 @@ bool init_firmware(struct net_device *dev)
u32 file_length = 0;
u8 *mapped_file = NULL;
u32 init_step = 0;
- opt_rst_type_e rst_opt = OPT_SYSTEM_RESET;
- firmware_init_step_e starting_state = FW_INIT_STEP0_BOOT;
+ enum opt_rst_type_e rst_opt = OPT_SYSTEM_RESET;
+ enum firmware_init_step_e starting_state = FW_INIT_STEP0_BOOT;
rt_firmware *pfirmware = priv->pFirmware;
const struct firmware *fw_entry;
diff --git a/drivers/staging/rtl8192u/r819xU_firmware.h b/drivers/staging/rtl8192u/r819xU_firmware.h
index cccd1c82ffe0..b84344c1e62b 100644
--- a/drivers/staging/rtl8192u/r819xU_firmware.h
+++ b/drivers/staging/rtl8192u/r819xU_firmware.h
@@ -2,19 +2,18 @@
#ifndef __INC_FIRMWARE_H
#define __INC_FIRMWARE_H
-#define RTL8190_CPU_START_OFFSET 0x80
#define GET_COMMAND_PACKET_FRAG_THRESHOLD(v) \
- (4*(v/4) - 8 - USB_HWDESC_HEADER_LEN)
+ (4 * ((v) / 4) - 8 - USB_HWDESC_HEADER_LEN)
-typedef enum _firmware_init_step {
+enum firmware_init_step_e {
FW_INIT_STEP0_BOOT = 0,
FW_INIT_STEP1_MAIN = 1,
FW_INIT_STEP2_DATA = 2,
-} firmware_init_step_e;
+};
-typedef enum _opt_rst_type {
+enum opt_rst_type_e {
OPT_SYSTEM_RESET = 0,
OPT_FIRMWARE_RESET = 1,
-} opt_rst_type_e;
+};
#endif
diff --git a/drivers/staging/rtl8192u/r819xU_phy.c b/drivers/staging/rtl8192u/r819xU_phy.c
index 7ee10d49894b..5f04afe53d69 100644
--- a/drivers/staging/rtl8192u/r819xU_phy.c
+++ b/drivers/staging/rtl8192u/r819xU_phy.c
@@ -511,7 +511,8 @@ void rtl8192_phy_configmac(struct net_device *dev)
* notice: BB parameters may change all the time, so please make
* sure it has been synced with the newest.
*****************************************************************************/
-void rtl8192_phyConfigBB(struct net_device *dev, u8 ConfigType)
+static void rtl8192_phyConfigBB(struct net_device *dev,
+ enum baseband_config_type ConfigType)
{
u32 i;
@@ -525,7 +526,7 @@ void rtl8192_phyConfigBB(struct net_device *dev, u8 ConfigType)
Rtl8190AGCTAB_Array_Table = Rtl819XAGCTAB_ArrayDTM;
}
#endif
- if (ConfigType == BaseBand_Config_PHY_REG) {
+ if (ConfigType == BASEBAND_CONFIG_PHY_REG) {
for (i = 0; i < PHY_REG_1T2RArrayLength; i += 2) {
rtl8192_setBBreg(dev, Rtl8192UsbPHY_REG_1T2RArray[i],
bMaskDWord,
@@ -535,7 +536,7 @@ void rtl8192_phyConfigBB(struct net_device *dev, u8 ConfigType)
i, Rtl8192UsbPHY_REG_1T2RArray[i],
Rtl8192UsbPHY_REG_1T2RArray[i+1]);
}
- } else if (ConfigType == BaseBand_Config_AGC_TAB) {
+ } else if (ConfigType == BASEBAND_CONFIG_AGC_TAB) {
for (i = 0; i < AGCTAB_ArrayLength; i += 2) {
rtl8192_setBBreg(dev, Rtl8192UsbAGCTAB_Array[i],
bMaskDWord, Rtl8192UsbAGCTAB_Array[i+1]);
@@ -793,7 +794,7 @@ static void rtl8192_BB_Config_ParaFile(struct net_device *dev)
(enum rf90_radio_path_e)0);
if (status != 0) {
RT_TRACE((COMP_ERR | COMP_PHY),
- "PHY_RF8256_Config(): Check PHY%d Fail!!\n",
+ "phy_rf8256_config(): Check PHY%d Fail!!\n",
eCheckItem-1);
return;
}
@@ -802,7 +803,7 @@ static void rtl8192_BB_Config_ParaFile(struct net_device *dev)
rtl8192_setBBreg(dev, rFPGA0_RFMOD, bCCKEn|bOFDMEn, 0x0);
/* ----BB Register Initilazation---- */
/* ==m==>Set PHY REG From Header<==m== */
- rtl8192_phyConfigBB(dev, BaseBand_Config_PHY_REG);
+ rtl8192_phyConfigBB(dev, BASEBAND_CONFIG_PHY_REG);
/* ----Set BB reset de-Active---- */
read_nic_dword(dev, CPU_GEN, &reg_u32);
@@ -810,11 +811,11 @@ static void rtl8192_BB_Config_ParaFile(struct net_device *dev)
/* ----BB AGC table Initialization---- */
/* ==m==>Set PHY REG From Header<==m== */
- rtl8192_phyConfigBB(dev, BaseBand_Config_AGC_TAB);
+ rtl8192_phyConfigBB(dev, BASEBAND_CONFIG_AGC_TAB);
/* ----Enable XSTAL ---- */
write_nic_byte_E(dev, 0x5e, 0x00);
- if (priv->card_8192_version == (u8)VERSION_819xU_A) {
+ if (priv->card_8192_version == VERSION_819XU_A) {
/* Antenna gain offset from B/C/D to A */
reg_u32 = priv->AntennaTxPwDiff[1]<<4 |
priv->AntennaTxPwDiff[0];
@@ -917,8 +918,8 @@ void rtl8192_phy_setTxPower(struct net_device *dev, u8 channel)
switch (priv->rf_chip) {
case RF_8256:
/* need further implement */
- PHY_SetRF8256CCKTxPower(dev, powerlevel);
- PHY_SetRF8256OFDMTxPower(dev, powerlevelOFDM24G);
+ phy_set_rf8256_cck_tx_power(dev, powerlevel);
+ phy_set_rf8256_ofdm_tx_power(dev, powerlevelOFDM24G);
break;
default:
RT_TRACE((COMP_PHY|COMP_ERR),
@@ -940,7 +941,7 @@ void rtl8192_phy_RFConfig(struct net_device *dev)
switch (priv->rf_chip) {
case RF_8256:
- PHY_RF8256_Config(dev);
+ phy_rf8256_config(dev);
break;
default:
RT_TRACE(COMP_ERR, "error chip id\n");
@@ -1065,8 +1066,8 @@ static void rtl8192_SetTxPowerLevel(struct net_device *dev, u8 channel)
break;
case RF_8256:
- PHY_SetRF8256CCKTxPower(dev, powerlevel);
- PHY_SetRF8256OFDMTxPower(dev, powerlevelOFDM24G);
+ phy_set_rf8256_cck_tx_power(dev, powerlevel);
+ phy_set_rf8256_ofdm_tx_power(dev, powerlevelOFDM24G);
break;
case RF_8258:
@@ -1271,7 +1272,7 @@ static u8 rtl8192_phy_SwChnlStepByStep(struct net_device *dev, u8 channel,
RT_TRACE(COMP_CH, "%s() stage: %d, step: %d, channel: %d\n",
__func__, *stage, *step, channel);
- if (!IsLegalChannel(priv->ieee80211, channel)) {
+ if (!is_legal_channel(priv->ieee80211, channel)) {
RT_TRACE(COMP_ERR, "set to illegal channel: %d\n", channel);
/* return true to tell upper caller function this channel
* setting is finished! Or it will in while loop.
@@ -1367,7 +1368,7 @@ static u8 rtl8192_phy_SwChnlStepByStep(struct net_device *dev, u8 channel,
switch (CurrentCmd->cmd_id) {
case CMD_ID_SET_TX_PWR_LEVEL:
- if (priv->card_8192_version == (u8)VERSION_819xU_A)
+ if (priv->card_8192_version == VERSION_819XU_A)
/* consider it later! */
rtl8192_SetTxPowerLevel(dev, channel);
break;
@@ -1633,7 +1634,7 @@ void rtl8192_SetBWModeWorkItem(struct net_device *dev)
break;
case RF_8256:
- PHY_SetRF8256Bandwidth(dev, priv->CurrentChannelBW);
+ phy_set_rf8256_bandwidth(dev, priv->CurrentChannelBW);
break;
case RF_8258:
diff --git a/drivers/staging/rtl8192u/r819xU_phy.h b/drivers/staging/rtl8192u/r819xU_phy.h
index c7ec3182857f..8c2933264407 100644
--- a/drivers/staging/rtl8192u/r819xU_phy.h
+++ b/drivers/staging/rtl8192u/r819xU_phy.h
@@ -7,6 +7,11 @@
#define MAX_RFDEPENDCMD_CNT 16
#define MAX_POSTCMD_CNT 16
+enum baseband_config_type {
+ BASEBAND_CONFIG_PHY_REG = 0, //Radio Path A
+ BASEBAND_CONFIG_AGC_TAB = 1, //Radio Path B
+};
+
enum switch_chan_cmd_id {
CMD_ID_END,
CMD_ID_SET_TX_PWR_LEVEL,
@@ -52,7 +57,6 @@ u32 rtl8192_phy_QueryRFReg(struct net_device *dev,
enum rf90_radio_path_e e_rfpath,
u32 reg_addr, u32 bitmask);
void rtl8192_phy_configmac(struct net_device *dev);
-void rtl8192_phyConfigBB(struct net_device *dev, u8 ConfigType);
u8 rtl8192_phy_checkBBAndRF(struct net_device *dev,
enum hw90_block_e CheckBlock,
enum rf90_radio_path_e e_rfpath);
diff --git a/drivers/staging/rtl8712/basic_types.h b/drivers/staging/rtl8712/basic_types.h
index f5c0231891b1..4ad7f35b1644 100644
--- a/drivers/staging/rtl8712/basic_types.h
+++ b/drivers/staging/rtl8712/basic_types.h
@@ -1,16 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/drv_types.h b/drivers/staging/rtl8712/drv_types.h
index ede99e96984f..48d62fe6c8d4 100644
--- a/drivers/staging/rtl8712/drv_types.h
+++ b/drivers/staging/rtl8712/drv_types.h
@@ -1,16 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/ethernet.h b/drivers/staging/rtl8712/ethernet.h
index 039da36fad3d..4b9b8a97a0bc 100644
--- a/drivers/staging/rtl8712/ethernet.h
+++ b/drivers/staging/rtl8712/ethernet.h
@@ -1,16 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/hal_init.c b/drivers/staging/rtl8712/hal_init.c
index 2a3f0746ee2c..7cdd609cab6c 100644
--- a/drivers/staging/rtl8712/hal_init.c
+++ b/drivers/staging/rtl8712/hal_init.c
@@ -1,18 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
* hal_init.c
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
* Linux device driver for RTL8192SU
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/ieee80211.c b/drivers/staging/rtl8712/ieee80211.c
index 7a4c00e49a88..bb4f56a5fb01 100644
--- a/drivers/staging/rtl8712/ieee80211.c
+++ b/drivers/staging/rtl8712/ieee80211.c
@@ -1,18 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
* ieee80211.c
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
* Linux device driver for RTL8192SU
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/ieee80211.h b/drivers/staging/rtl8712/ieee80211.h
index d605dfd02200..1470771daa62 100644
--- a/drivers/staging/rtl8712/ieee80211.h
+++ b/drivers/staging/rtl8712/ieee80211.h
@@ -1,19 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, see <http://www.gnu.org/licenses/>.
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/mlme_linux.c b/drivers/staging/rtl8712/mlme_linux.c
index baaa52f04560..9d156efbc9ed 100644
--- a/drivers/staging/rtl8712/mlme_linux.c
+++ b/drivers/staging/rtl8712/mlme_linux.c
@@ -1,22 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
* mlme_linux.c
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
* Linux device driver for RTL8192SU
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/mlme_osdep.h b/drivers/staging/rtl8712/mlme_osdep.h
index a20fe81f921f..9eaf94f072ff 100644
--- a/drivers/staging/rtl8712/mlme_osdep.h
+++ b/drivers/staging/rtl8712/mlme_osdep.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/mp_custom_oid.h b/drivers/staging/rtl8712/mp_custom_oid.h
index 40510089b781..a9fac87fcabc 100644
--- a/drivers/staging/rtl8712/mp_custom_oid.h
+++ b/drivers/staging/rtl8712/mp_custom_oid.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/os_intfs.c b/drivers/staging/rtl8712/os_intfs.c
index ff4e451c10f9..2d3f38007299 100644
--- a/drivers/staging/rtl8712/os_intfs.c
+++ b/drivers/staging/rtl8712/os_intfs.c
@@ -1,18 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
* os_intfs.c
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
* Linux device driver for RTL8192SU
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/osdep_intf.h b/drivers/staging/rtl8712/osdep_intf.h
index 5d37e1f951cf..2cc25db1a91d 100644
--- a/drivers/staging/rtl8712/osdep_intf.h
+++ b/drivers/staging/rtl8712/osdep_intf.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/osdep_service.h b/drivers/staging/rtl8712/osdep_service.h
index 5d33020554cd..e939c4a954b3 100644
--- a/drivers/staging/rtl8712/osdep_service.h
+++ b/drivers/staging/rtl8712/osdep_service.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/recv_linux.c b/drivers/staging/rtl8712/recv_linux.c
index 8cf4286f6318..4e20cbafa9fb 100644
--- a/drivers/staging/rtl8712/recv_linux.c
+++ b/drivers/staging/rtl8712/recv_linux.c
@@ -1,22 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
* recv_linux.c
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
* Linux device driver for RTL8192SU
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/recv_osdep.h b/drivers/staging/rtl8712/recv_osdep.h
index 1f4986e940a3..dcd3b484c793 100644
--- a/drivers/staging/rtl8712/recv_osdep.h
+++ b/drivers/staging/rtl8712/recv_osdep.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl8712_bitdef.h b/drivers/staging/rtl8712/rtl8712_bitdef.h
index dee35fe2587a..a4a687dcc2e7 100644
--- a/drivers/staging/rtl8712/rtl8712_bitdef.h
+++ b/drivers/staging/rtl8712/rtl8712_bitdef.h
@@ -1,21 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- *
******************************************************************************/
#ifndef __RTL8712_BITDEF_H__
diff --git a/drivers/staging/rtl8712/rtl8712_cmd.c b/drivers/staging/rtl8712/rtl8712_cmd.c
index b1dfe9f46619..1920d02f7c9f 100644
--- a/drivers/staging/rtl8712/rtl8712_cmd.c
+++ b/drivers/staging/rtl8712/rtl8712_cmd.c
@@ -1,22 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
* rtl8712_cmd.c
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
* Linux device driver for RTL8192SU
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl8712_cmd.h b/drivers/staging/rtl8712/rtl8712_cmd.h
index 9181bb6b04c3..92fb77666d44 100644
--- a/drivers/staging/rtl8712/rtl8712_cmd.h
+++ b/drivers/staging/rtl8712/rtl8712_cmd.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl8712_cmdctrl_bitdef.h b/drivers/staging/rtl8712/rtl8712_cmdctrl_bitdef.h
index 4b8985d50098..e125c7222ab5 100644
--- a/drivers/staging/rtl8712/rtl8712_cmdctrl_bitdef.h
+++ b/drivers/staging/rtl8712/rtl8712_cmdctrl_bitdef.h
@@ -1,21 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- *
******************************************************************************/
#ifndef __RTL8712_CMDCTRL_BITDEF_H__
#define __RTL8712_CMDCTRL_BITDEF_H__
diff --git a/drivers/staging/rtl8712/rtl8712_cmdctrl_regdef.h b/drivers/staging/rtl8712/rtl8712_cmdctrl_regdef.h
index 8df42a70399f..fc67771c89b7 100644
--- a/drivers/staging/rtl8712/rtl8712_cmdctrl_regdef.h
+++ b/drivers/staging/rtl8712/rtl8712_cmdctrl_regdef.h
@@ -1,21 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- *
******************************************************************************/
#ifndef __RTL8712_CMDCTRL_REGDEF_H__
#define __RTL8712_CMDCTRL_REGDEF_H__
diff --git a/drivers/staging/rtl8712/rtl8712_debugctrl_bitdef.h b/drivers/staging/rtl8712/rtl8712_debugctrl_bitdef.h
index 4b3436795cb1..bb3863467f0d 100644
--- a/drivers/staging/rtl8712/rtl8712_debugctrl_bitdef.h
+++ b/drivers/staging/rtl8712/rtl8712_debugctrl_bitdef.h
@@ -1,21 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- *
******************************************************************************/
#ifndef __RTL8712_DEBUGCTRL_BITDEF_H__
#define __RTL8712_DEBUGCTRL_BITDEF_H__
diff --git a/drivers/staging/rtl8712/rtl8712_debugctrl_regdef.h b/drivers/staging/rtl8712/rtl8712_debugctrl_regdef.h
index d7c964d436a1..319220e9d53d 100644
--- a/drivers/staging/rtl8712/rtl8712_debugctrl_regdef.h
+++ b/drivers/staging/rtl8712/rtl8712_debugctrl_regdef.h
@@ -1,21 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- *
******************************************************************************/
#ifndef __RTL8712_DEBUGCTRL_REGDEF_H__
#define __RTL8712_DEBUGCTRL_REGDEF_H__
diff --git a/drivers/staging/rtl8712/rtl8712_edcasetting_bitdef.h b/drivers/staging/rtl8712/rtl8712_edcasetting_bitdef.h
index 32dab81f1767..9048d6a65296 100644
--- a/drivers/staging/rtl8712/rtl8712_edcasetting_bitdef.h
+++ b/drivers/staging/rtl8712/rtl8712_edcasetting_bitdef.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl8712_edcasetting_regdef.h b/drivers/staging/rtl8712/rtl8712_edcasetting_regdef.h
index d992cb8b1c73..02ec9f3bba66 100644
--- a/drivers/staging/rtl8712/rtl8712_edcasetting_regdef.h
+++ b/drivers/staging/rtl8712/rtl8712_edcasetting_regdef.h
@@ -1,21 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- *
******************************************************************************/
#ifndef __RTL8712_EDCASETTING_REGDEF_H__
#define __RTL8712_EDCASETTING_REGDEF_H__
diff --git a/drivers/staging/rtl8712/rtl8712_efuse.c b/drivers/staging/rtl8712/rtl8712_efuse.c
index d90213eb5e20..8bc45ffd3029 100644
--- a/drivers/staging/rtl8712/rtl8712_efuse.c
+++ b/drivers/staging/rtl8712/rtl8712_efuse.c
@@ -1,22 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* rtl8712_efuse.c
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
* Linux device driver for RTL8192SU
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl8712_event.h b/drivers/staging/rtl8712/rtl8712_event.h
index cad7085c3f8a..0d3e5feadcc0 100644
--- a/drivers/staging/rtl8712/rtl8712_event.h
+++ b/drivers/staging/rtl8712/rtl8712_event.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl8712_fifoctrl_bitdef.h b/drivers/staging/rtl8712/rtl8712_fifoctrl_bitdef.h
index bd8240476d71..f09645fa1886 100644
--- a/drivers/staging/rtl8712/rtl8712_fifoctrl_bitdef.h
+++ b/drivers/staging/rtl8712/rtl8712_fifoctrl_bitdef.h
@@ -1,21 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- *
******************************************************************************/
#ifndef __RTL8712_FIFOCTRL_BITDEF_H__
#define __RTL8712_FIFOCTRL_BITDEF_H__
diff --git a/drivers/staging/rtl8712/rtl8712_fifoctrl_regdef.h b/drivers/staging/rtl8712/rtl8712_fifoctrl_regdef.h
index 6d527380fd29..189fdeb16d7d 100644
--- a/drivers/staging/rtl8712/rtl8712_fifoctrl_regdef.h
+++ b/drivers/staging/rtl8712/rtl8712_fifoctrl_regdef.h
@@ -1,21 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- *
******************************************************************************/
#ifndef __RTL8712_FIFOCTRL_REGDEF_H__
#define __RTL8712_FIFOCTRL_REGDEF_H__
diff --git a/drivers/staging/rtl8712/rtl8712_gp_bitdef.h b/drivers/staging/rtl8712/rtl8712_gp_bitdef.h
index 66c35c990983..ee651fb3fde3 100644
--- a/drivers/staging/rtl8712/rtl8712_gp_bitdef.h
+++ b/drivers/staging/rtl8712/rtl8712_gp_bitdef.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl8712_gp_regdef.h b/drivers/staging/rtl8712/rtl8712_gp_regdef.h
index a0379360d0a3..892a7fb13923 100644
--- a/drivers/staging/rtl8712/rtl8712_gp_regdef.h
+++ b/drivers/staging/rtl8712/rtl8712_gp_regdef.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl8712_hal.h b/drivers/staging/rtl8712/rtl8712_hal.h
index 84456bb560ef..42f519739128 100644
--- a/drivers/staging/rtl8712/rtl8712_hal.h
+++ b/drivers/staging/rtl8712/rtl8712_hal.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl8712_interrupt_bitdef.h b/drivers/staging/rtl8712/rtl8712_interrupt_bitdef.h
index 2a561d2862e0..e9732a1bcd7e 100644
--- a/drivers/staging/rtl8712/rtl8712_interrupt_bitdef.h
+++ b/drivers/staging/rtl8712/rtl8712_interrupt_bitdef.h
@@ -1,21 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- *
******************************************************************************/
#ifndef __RTL8712_INTERRUPT_BITDEF_H__
#define __RTL8712_INTERRUPT_BITDEF_H__
diff --git a/drivers/staging/rtl8712/rtl8712_io.c b/drivers/staging/rtl8712/rtl8712_io.c
index 391eff37f573..8eb79f73c014 100644
--- a/drivers/staging/rtl8712/rtl8712_io.c
+++ b/drivers/staging/rtl8712/rtl8712_io.c
@@ -1,22 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
* rtl8712_io.c
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
* Linux device driver for RTL8192SU
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl8712_led.c b/drivers/staging/rtl8712/rtl8712_led.c
index 0aa97c9dcced..5b1004b2df47 100644
--- a/drivers/staging/rtl8712/rtl8712_led.c
+++ b/drivers/staging/rtl8712/rtl8712_led.c
@@ -1,22 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
* rtl8712_led.c
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
* Linux device driver for RTL8192SU
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl8712_macsetting_bitdef.h b/drivers/staging/rtl8712/rtl8712_macsetting_bitdef.h
index 28e0a7ebcad7..3d9f40fa8469 100644
--- a/drivers/staging/rtl8712/rtl8712_macsetting_bitdef.h
+++ b/drivers/staging/rtl8712/rtl8712_macsetting_bitdef.h
@@ -1,21 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- *
******************************************************************************/
#ifndef __RTL8712_MACSETTING_BITDEF_H__
#define __RTL8712_MACSETTING_BITDEF_H__
diff --git a/drivers/staging/rtl8712/rtl8712_macsetting_regdef.h b/drivers/staging/rtl8712/rtl8712_macsetting_regdef.h
index ced0da9332d5..e8cb2eee9294 100644
--- a/drivers/staging/rtl8712/rtl8712_macsetting_regdef.h
+++ b/drivers/staging/rtl8712/rtl8712_macsetting_regdef.h
@@ -1,21 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- *
******************************************************************************/
#ifndef __RTL8712_MACSETTING_REGDEF_H__
#define __RTL8712_MACSETTING_REGDEF_H__
diff --git a/drivers/staging/rtl8712/rtl8712_powersave_bitdef.h b/drivers/staging/rtl8712/rtl8712_powersave_bitdef.h
index 8fc689416519..53e0d6b440f3 100644
--- a/drivers/staging/rtl8712/rtl8712_powersave_bitdef.h
+++ b/drivers/staging/rtl8712/rtl8712_powersave_bitdef.h
@@ -1,21 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- *
******************************************************************************/
#ifndef __RTL8712_POWERSAVE_BITDEF_H__
#define __RTL8712_POWERSAVE_BITDEF_H__
diff --git a/drivers/staging/rtl8712/rtl8712_powersave_regdef.h b/drivers/staging/rtl8712/rtl8712_powersave_regdef.h
index 4632ddd5d1f7..1bcfde4b1c11 100644
--- a/drivers/staging/rtl8712/rtl8712_powersave_regdef.h
+++ b/drivers/staging/rtl8712/rtl8712_powersave_regdef.h
@@ -1,21 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- *
******************************************************************************/
#ifndef __RTL8712_POWERSAVE_REGDEF_H__
#define __RTL8712_POWERSAVE_REGDEF_H__
diff --git a/drivers/staging/rtl8712/rtl8712_ratectrl_bitdef.h b/drivers/staging/rtl8712/rtl8712_ratectrl_bitdef.h
index 6d3d6e8522fb..1de51c48f9c1 100644
--- a/drivers/staging/rtl8712/rtl8712_ratectrl_bitdef.h
+++ b/drivers/staging/rtl8712/rtl8712_ratectrl_bitdef.h
@@ -1,21 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- *
******************************************************************************/
#ifndef __RTL8712_RATECTRL_BITDEF_H__
#define __RTL8712_RATECTRL_BITDEF_H__
diff --git a/drivers/staging/rtl8712/rtl8712_ratectrl_regdef.h b/drivers/staging/rtl8712/rtl8712_ratectrl_regdef.h
index 73dfc3610154..a3eaee0e1b69 100644
--- a/drivers/staging/rtl8712/rtl8712_ratectrl_regdef.h
+++ b/drivers/staging/rtl8712/rtl8712_ratectrl_regdef.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl8712_recv.c b/drivers/staging/rtl8712/rtl8712_recv.c
index 4264cd341f03..5bf9070b7a28 100644
--- a/drivers/staging/rtl8712/rtl8712_recv.c
+++ b/drivers/staging/rtl8712/rtl8712_recv.c
@@ -1,22 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
* rtl8712_recv.c
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
* Linux device driver for RTL8192SU
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl8712_recv.h b/drivers/staging/rtl8712/rtl8712_recv.h
index 0352e6fafd90..6954c5bfbcaf 100644
--- a/drivers/staging/rtl8712/rtl8712_recv.h
+++ b/drivers/staging/rtl8712/rtl8712_recv.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl8712_regdef.h b/drivers/staging/rtl8712/rtl8712_regdef.h
index e7bca55b59d0..28aec9aa539f 100644
--- a/drivers/staging/rtl8712/rtl8712_regdef.h
+++ b/drivers/staging/rtl8712/rtl8712_regdef.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl8712_security_bitdef.h b/drivers/staging/rtl8712/rtl8712_security_bitdef.h
index 05dafa0c3333..1c26a7eca64a 100644
--- a/drivers/staging/rtl8712/rtl8712_security_bitdef.h
+++ b/drivers/staging/rtl8712/rtl8712_security_bitdef.h
@@ -1,21 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- *
******************************************************************************/
#ifndef __RTL8712_SECURITY_BITDEF_H__
#define __RTL8712_SECURITY_BITDEF_H__
diff --git a/drivers/staging/rtl8712/rtl8712_spec.h b/drivers/staging/rtl8712/rtl8712_spec.h
index 51e042815cc9..c0bab4c49ae9 100644
--- a/drivers/staging/rtl8712/rtl8712_spec.h
+++ b/drivers/staging/rtl8712/rtl8712_spec.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl8712_syscfg_bitdef.h b/drivers/staging/rtl8712/rtl8712_syscfg_bitdef.h
index 2e66d28d6918..a328ca9b340c 100644
--- a/drivers/staging/rtl8712/rtl8712_syscfg_bitdef.h
+++ b/drivers/staging/rtl8712/rtl8712_syscfg_bitdef.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl8712_syscfg_regdef.h b/drivers/staging/rtl8712/rtl8712_syscfg_regdef.h
index 767dfdf8d83f..e95eb5832ec4 100644
--- a/drivers/staging/rtl8712/rtl8712_syscfg_regdef.h
+++ b/drivers/staging/rtl8712/rtl8712_syscfg_regdef.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl8712_timectrl_bitdef.h b/drivers/staging/rtl8712/rtl8712_timectrl_bitdef.h
index 724421582421..1af5f1dd3c20 100644
--- a/drivers/staging/rtl8712/rtl8712_timectrl_bitdef.h
+++ b/drivers/staging/rtl8712/rtl8712_timectrl_bitdef.h
@@ -1,21 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- *
******************************************************************************/
#ifndef __RTL8712_TIMECTRL_BITDEF_H__
#define __RTL8712_TIMECTRL_BITDEF_H__
diff --git a/drivers/staging/rtl8712/rtl8712_timectrl_regdef.h b/drivers/staging/rtl8712/rtl8712_timectrl_regdef.h
index 106916c7e310..b51603f1b880 100644
--- a/drivers/staging/rtl8712/rtl8712_timectrl_regdef.h
+++ b/drivers/staging/rtl8712/rtl8712_timectrl_regdef.h
@@ -1,21 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- *
******************************************************************************/
#ifndef __RTL8712_TIMECTRL_REGDEF_H__
#define __RTL8712_TIMECTRL_REGDEF_H__
diff --git a/drivers/staging/rtl8712/rtl8712_wmac_bitdef.h b/drivers/staging/rtl8712/rtl8712_wmac_bitdef.h
index 61a3603aa587..d3b45c6cd855 100644
--- a/drivers/staging/rtl8712/rtl8712_wmac_bitdef.h
+++ b/drivers/staging/rtl8712/rtl8712_wmac_bitdef.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl8712_wmac_regdef.h b/drivers/staging/rtl8712/rtl8712_wmac_regdef.h
index d9f8347ab461..662383fe7a8d 100644
--- a/drivers/staging/rtl8712/rtl8712_wmac_regdef.h
+++ b/drivers/staging/rtl8712/rtl8712_wmac_regdef.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl8712_xmit.c b/drivers/staging/rtl8712/rtl8712_xmit.c
index fb64c2891e22..aa6fb516f398 100644
--- a/drivers/staging/rtl8712/rtl8712_xmit.c
+++ b/drivers/staging/rtl8712/rtl8712_xmit.c
@@ -1,22 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
* rtl8712_xmit.c
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
* Linux device driver for RTL8192SU
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl8712_xmit.h b/drivers/staging/rtl8712/rtl8712_xmit.h
index 02b1593ada01..9be8fb70c92e 100644
--- a/drivers/staging/rtl8712/rtl8712_xmit.h
+++ b/drivers/staging/rtl8712/rtl8712_xmit.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl871x_cmd.c b/drivers/staging/rtl8712/rtl871x_cmd.c
index 620cee8b8514..05a78ac24987 100644
--- a/drivers/staging/rtl8712/rtl871x_cmd.c
+++ b/drivers/staging/rtl8712/rtl871x_cmd.c
@@ -1,22 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
* rtl871x_cmd.c
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
* Linux device driver for RTL8192SU
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl871x_cmd.h b/drivers/staging/rtl8712/rtl871x_cmd.h
index 24da2ccea04f..75a126d8e26c 100644
--- a/drivers/staging/rtl8712/rtl871x_cmd.h
+++ b/drivers/staging/rtl8712/rtl871x_cmd.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl871x_debug.h b/drivers/staging/rtl8712/rtl871x_debug.h
index 74468b058258..a427547c02ba 100644
--- a/drivers/staging/rtl8712/rtl871x_debug.h
+++ b/drivers/staging/rtl8712/rtl871x_debug.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl871x_eeprom.c b/drivers/staging/rtl8712/rtl871x_eeprom.c
index 4e713610ad8b..948bd0c757b5 100644
--- a/drivers/staging/rtl8712/rtl871x_eeprom.c
+++ b/drivers/staging/rtl8712/rtl871x_eeprom.c
@@ -1,22 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
* rtl871x_eeprom.c
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
* Linux device driver for RTL8192SU
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl871x_eeprom.h b/drivers/staging/rtl8712/rtl871x_eeprom.h
index 497276e53bbe..7bdeb2aaa025 100644
--- a/drivers/staging/rtl8712/rtl871x_eeprom.h
+++ b/drivers/staging/rtl8712/rtl871x_eeprom.h
@@ -1,21 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- *
******************************************************************************/
#ifndef __RTL871X_EEPROM_H__
#define __RTL871X_EEPROM_H__
diff --git a/drivers/staging/rtl8712/rtl871x_event.h b/drivers/staging/rtl8712/rtl871x_event.h
index 517137906e6c..d9a5476d2426 100644
--- a/drivers/staging/rtl8712/rtl871x_event.h
+++ b/drivers/staging/rtl8712/rtl871x_event.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl871x_ht.h b/drivers/staging/rtl8712/rtl871x_ht.h
index 513f458ea07c..ebd78665775d 100644
--- a/drivers/staging/rtl8712/rtl871x_ht.h
+++ b/drivers/staging/rtl8712/rtl871x_ht.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl871x_io.c b/drivers/staging/rtl8712/rtl871x_io.c
index 3a10940db9b7..17dafeffd6f4 100644
--- a/drivers/staging/rtl8712/rtl871x_io.c
+++ b/drivers/staging/rtl8712/rtl871x_io.c
@@ -1,22 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
* rtl871x_io.c
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
* Linux device driver for RTL8192SU
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
@@ -68,7 +56,7 @@ static uint _init_intf_hdl(struct _adapter *padapter,
set_intf_option(&pintf_hdl->intf_option);
set_intf_funs(pintf_hdl);
set_intf_ops(&pintf_hdl->io_ops);
- pintf_priv->intf_dev = (u8 *)&(padapter->dvobjpriv);
+ pintf_priv->intf_dev = (u8 *)&padapter->dvobjpriv;
if (init_intf_priv(pintf_priv) == _FAIL)
goto _init_intf_hdl_fail;
return _SUCCESS;
@@ -92,7 +80,7 @@ static uint register_intf_hdl(u8 *dev, struct intf_hdl *pintfhdl)
pintfhdl->intf_option = 0;
pintfhdl->adapter = dev;
- pintfhdl->intf_dev = (u8 *)&(adapter->dvobjpriv);
+ pintfhdl->intf_dev = (u8 *)&adapter->dvobjpriv;
if (!_init_intf_hdl(adapter, pintfhdl))
goto register_intf_hdl_fail;
return _SUCCESS;
@@ -135,7 +123,7 @@ uint r8712_alloc_io_queue(struct _adapter *adapter)
list_add_tail(&pio_req->list, &pio_queue->free_ioreqs);
pio_req++;
}
- if ((register_intf_hdl((u8 *)adapter, &(pio_queue->intf))) == _FAIL)
+ if ((register_intf_hdl((u8 *)adapter, &pio_queue->intf)) == _FAIL)
goto alloc_io_queue_fail;
adapter->pio_queue = pio_queue;
return _SUCCESS;
diff --git a/drivers/staging/rtl8712/rtl871x_io.h b/drivers/staging/rtl8712/rtl871x_io.h
index dd054d7367b3..28941423b7ed 100644
--- a/drivers/staging/rtl8712/rtl871x_io.h
+++ b/drivers/staging/rtl8712/rtl871x_io.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
index c3ff7c3e6681..e723357ac8c0 100644
--- a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
+++ b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
@@ -1,22 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
* rtl871x_ioctl_linux.c
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
* Linux device driver for RTL8192SU
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
@@ -67,11 +55,6 @@ static const long ieee80211_wlan_frequencies[] = {
2472, 2484
};
-static const char * const iw_operation_mode[] = {
- "Auto", "Ad-Hoc", "Managed", "Master", "Repeater", "Secondary",
- "Monitor"
-};
-
void r8712_indicate_wx_assoc_event(struct _adapter *padapter)
{
union iwreq_data wrqu;
@@ -1789,7 +1772,7 @@ static int r871x_wx_set_enc_ext(struct net_device *dev,
return -ENOMEM;
param->cmd = IEEE_CMD_SET_ENCRYPTION;
eth_broadcast_addr(param->sta_addr);
- strncpy((char *)param->u.crypt.alg, alg_name, IEEE_CRYPT_ALG_NAME_LEN);
+ strlcpy((char *)param->u.crypt.alg, alg_name, IEEE_CRYPT_ALG_NAME_LEN);
if (pext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
param->u.crypt.set_tx = 0;
if (pext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_rtl.c b/drivers/staging/rtl8712/rtl871x_ioctl_rtl.c
index ca769f781e96..2dc20da21679 100644
--- a/drivers/staging/rtl8712/rtl871x_ioctl_rtl.c
+++ b/drivers/staging/rtl8712/rtl871x_ioctl_rtl.c
@@ -1,22 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
* rtl871x_ioctl_rtl.c
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
* Linux device driver for RTL8192SU
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_rtl.h b/drivers/staging/rtl8712/rtl871x_ioctl_rtl.h
index 3bcceae3cbeb..7c0b880ac686 100644
--- a/drivers/staging/rtl8712/rtl871x_ioctl_rtl.h
+++ b/drivers/staging/rtl8712/rtl871x_ioctl_rtl.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_set.c b/drivers/staging/rtl8712/rtl871x_ioctl_set.c
index f4a53df7f2c1..2622d5e3bff9 100644
--- a/drivers/staging/rtl8712/rtl871x_ioctl_set.c
+++ b/drivers/staging/rtl8712/rtl871x_ioctl_set.c
@@ -1,22 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
* rtl871x_ioctl_set.c
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
* Linux device driver for RTL8192SU
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_set.h b/drivers/staging/rtl8712/rtl871x_ioctl_set.h
index 2c94cd151c96..8b1085aea962 100644
--- a/drivers/staging/rtl8712/rtl871x_ioctl_set.h
+++ b/drivers/staging/rtl8712/rtl871x_ioctl_set.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl871x_led.h b/drivers/staging/rtl8712/rtl871x_led.h
index adfbc400a18d..ee19c873cf01 100644
--- a/drivers/staging/rtl8712/rtl871x_led.h
+++ b/drivers/staging/rtl8712/rtl871x_led.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl871x_mlme.c b/drivers/staging/rtl8712/rtl871x_mlme.c
index ac547ddd72d1..a7374006a9fb 100644
--- a/drivers/staging/rtl8712/rtl871x_mlme.c
+++ b/drivers/staging/rtl8712/rtl871x_mlme.c
@@ -1,22 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
* rtl871x_mlme.c
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
* Linux device driver for RTL8192SU
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl871x_mlme.h b/drivers/staging/rtl8712/rtl871x_mlme.h
index 918947f38151..8a54181f4816 100644
--- a/drivers/staging/rtl8712/rtl871x_mlme.h
+++ b/drivers/staging/rtl8712/rtl871x_mlme.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl871x_mp.c b/drivers/staging/rtl8712/rtl871x_mp.c
index ba208a2e1e4e..1d5364f5a518 100644
--- a/drivers/staging/rtl8712/rtl871x_mp.c
+++ b/drivers/staging/rtl8712/rtl871x_mp.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl871x_mp.h b/drivers/staging/rtl8712/rtl871x_mp.h
index 8df452e3e3ce..e79a67676469 100644
--- a/drivers/staging/rtl8712/rtl871x_mp.h
+++ b/drivers/staging/rtl8712/rtl871x_mp.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl871x_mp_ioctl.c b/drivers/staging/rtl8712/rtl871x_mp_ioctl.c
index 6e264a8d0087..588346da1412 100644
--- a/drivers/staging/rtl8712/rtl871x_mp_ioctl.c
+++ b/drivers/staging/rtl8712/rtl871x_mp_ioctl.c
@@ -1,22 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
* rtl871x_mp_ioctl.c
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
* Linux device driver for RTL8192SU
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl871x_mp_ioctl.h b/drivers/staging/rtl8712/rtl871x_mp_ioctl.h
index 741006f1e45a..44cd911f2aa1 100644
--- a/drivers/staging/rtl8712/rtl871x_mp_ioctl.h
+++ b/drivers/staging/rtl8712/rtl871x_mp_ioctl.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl871x_pwrctrl.c b/drivers/staging/rtl8712/rtl871x_pwrctrl.c
index ae4c9567bb55..351984fe254e 100644
--- a/drivers/staging/rtl8712/rtl871x_pwrctrl.c
+++ b/drivers/staging/rtl8712/rtl871x_pwrctrl.c
@@ -1,22 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
* rtl871x_pwrctrl.c
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
* Linux device driver for RTL8192SU
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl871x_pwrctrl.h b/drivers/staging/rtl8712/rtl871x_pwrctrl.h
index bd2c3a2df48b..11b5034f203d 100644
--- a/drivers/staging/rtl8712/rtl871x_pwrctrl.h
+++ b/drivers/staging/rtl8712/rtl871x_pwrctrl.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl871x_recv.c b/drivers/staging/rtl8712/rtl871x_recv.c
index 2ef31a4e9a6b..f10896df094b 100644
--- a/drivers/staging/rtl8712/rtl871x_recv.c
+++ b/drivers/staging/rtl8712/rtl871x_recv.c
@@ -1,22 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
* rtl871x_recv.c
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
* Linux device driver for RTL8192SU
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl871x_rf.h b/drivers/staging/rtl8712/rtl871x_rf.h
index 133ed6462928..cc54453cd424 100644
--- a/drivers/staging/rtl8712/rtl871x_rf.h
+++ b/drivers/staging/rtl8712/rtl871x_rf.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl871x_security.c b/drivers/staging/rtl8712/rtl871x_security.c
index 1075eacdb441..f82645011d02 100644
--- a/drivers/staging/rtl8712/rtl871x_security.c
+++ b/drivers/staging/rtl8712/rtl871x_security.c
@@ -1,22 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
* rtl871x_security.c
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
* Linux device driver for RTL8192SU
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl871x_security.h b/drivers/staging/rtl8712/rtl871x_security.h
index 46b88a41d236..25b4d379766d 100644
--- a/drivers/staging/rtl8712/rtl871x_security.h
+++ b/drivers/staging/rtl8712/rtl871x_security.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl871x_sta_mgt.c b/drivers/staging/rtl8712/rtl871x_sta_mgt.c
index e2d75e4c473f..9648ee15b40e 100644
--- a/drivers/staging/rtl8712/rtl871x_sta_mgt.c
+++ b/drivers/staging/rtl8712/rtl871x_sta_mgt.c
@@ -1,22 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
* rtl871x_sta_mgt.c
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
* Linux device driver for RTL8192SU
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl871x_wlan_sme.h b/drivers/staging/rtl8712/rtl871x_wlan_sme.h
index 44924d5de217..97ea1451426c 100644
--- a/drivers/staging/rtl8712/rtl871x_wlan_sme.h
+++ b/drivers/staging/rtl8712/rtl871x_wlan_sme.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/rtl871x_xmit.c b/drivers/staging/rtl8712/rtl871x_xmit.c
index a8ae14ce6613..5c7dc9c6f76b 100644
--- a/drivers/staging/rtl8712/rtl871x_xmit.c
+++ b/drivers/staging/rtl8712/rtl871x_xmit.c
@@ -1,22 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
* rtl871x_xmit.c
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
* Linux device driver for RTL8192SU
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
@@ -433,7 +421,7 @@ static sint xmitframe_addmic(struct _adapter *padapter,
r8712_secmicappend(&micdata, payload,
length);
payload = payload + length;
- } else{
+ } else {
length = pxmitpriv->frag_len -
pattrib->hdrlen - pattrib->iv_len -
((psecuritypriv->sw_encrypt) ?
diff --git a/drivers/staging/rtl8712/rtl871x_xmit.h b/drivers/staging/rtl8712/rtl871x_xmit.h
index 40927277f498..3bea2e374f13 100644
--- a/drivers/staging/rtl8712/rtl871x_xmit.h
+++ b/drivers/staging/rtl8712/rtl871x_xmit.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/sta_info.h b/drivers/staging/rtl8712/sta_info.h
index 742dfa0ca817..45dbed10295f 100644
--- a/drivers/staging/rtl8712/sta_info.h
+++ b/drivers/staging/rtl8712/sta_info.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/usb_halinit.c b/drivers/staging/rtl8712/usb_halinit.c
index 0b159850f5a2..02e73c2412d4 100644
--- a/drivers/staging/rtl8712/usb_halinit.c
+++ b/drivers/staging/rtl8712/usb_halinit.c
@@ -1,22 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
* usb_halinit.c
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
* Linux device driver for RTL8192SU
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/usb_intf.c b/drivers/staging/rtl8712/usb_intf.c
index 85eadddfaf06..92d75d7c51ae 100644
--- a/drivers/staging/rtl8712/usb_intf.c
+++ b/drivers/staging/rtl8712/usb_intf.c
@@ -1,22 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
* usb_intf.c
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
* Linux device driver for RTL8192SU
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/usb_ops.c b/drivers/staging/rtl8712/usb_ops.c
index 332e2e51d778..eef52d5c730a 100644
--- a/drivers/staging/rtl8712/usb_ops.c
+++ b/drivers/staging/rtl8712/usb_ops.c
@@ -1,22 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
* usb_ops.c
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
* Linux device driver for RTL8192SU
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/usb_ops.h b/drivers/staging/rtl8712/usb_ops.h
index 78e775a46364..d62975447d29 100644
--- a/drivers/staging/rtl8712/usb_ops.h
+++ b/drivers/staging/rtl8712/usb_ops.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/usb_ops_linux.c b/drivers/staging/rtl8712/usb_ops_linux.c
index 6d12a96fa65f..ee5968808332 100644
--- a/drivers/staging/rtl8712/usb_ops_linux.c
+++ b/drivers/staging/rtl8712/usb_ops_linux.c
@@ -1,22 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
* usb_ops_linux.c
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
* Linux device driver for RTL8192SU
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/usb_osintf.h b/drivers/staging/rtl8712/usb_osintf.h
index 609f9210cc46..ddfa405d0c9b 100644
--- a/drivers/staging/rtl8712/usb_osintf.h
+++ b/drivers/staging/rtl8712/usb_osintf.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/wifi.h b/drivers/staging/rtl8712/wifi.h
index 00a4302e9983..77346debea03 100644
--- a/drivers/staging/rtl8712/wifi.h
+++ b/drivers/staging/rtl8712/wifi.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/wlan_bssdef.h b/drivers/staging/rtl8712/wlan_bssdef.h
index 9dc9ce5a2ccc..b54ccaacc527 100644
--- a/drivers/staging/rtl8712/wlan_bssdef.h
+++ b/drivers/staging/rtl8712/wlan_bssdef.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/xmit_linux.c b/drivers/staging/rtl8712/xmit_linux.c
index 4ee4136b5c28..8bcb0775411f 100644
--- a/drivers/staging/rtl8712/xmit_linux.c
+++ b/drivers/staging/rtl8712/xmit_linux.c
@@ -1,22 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
* xmit_linux.c
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
* Linux device driver for RTL8192SU
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8712/xmit_osdep.h b/drivers/staging/rtl8712/xmit_osdep.h
index 8eba7ca0ddef..21f6b31e0f50 100644
--- a/drivers/staging/rtl8712/xmit_osdep.h
+++ b/drivers/staging/rtl8712/xmit_osdep.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/******************************************************************************
*
* Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
* Modifications for inclusion into the Linux staging tree are
* Copyright(c) 2010 Larry Finger. All rights reserved.
*
diff --git a/drivers/staging/rtl8723bs/core/rtw_ap.c b/drivers/staging/rtl8723bs/core/rtw_ap.c
index faf4b4158cfa..2691241bfd84 100644
--- a/drivers/staging/rtl8723bs/core/rtw_ap.c
+++ b/drivers/staging/rtl8723bs/core/rtw_ap.c
@@ -861,7 +861,7 @@ void start_bss_network(struct adapter *padapter, u8 *pbuf)
update_hw_ht_param(padapter);
}
- if (pmlmepriv->cur_network.join_res != true) { /* setting only at first time */
+ if (!pmlmepriv->cur_network.join_res) { /* setting only at first time */
/* WEP Key will be set before this function, do not clear CAM. */
if (
@@ -899,7 +899,7 @@ void start_bss_network(struct adapter *padapter, u8 *pbuf)
rtw_hal_set_hwreg(padapter, HW_VAR_DO_IQK, NULL);
- if (pmlmepriv->cur_network.join_res != true) { /* setting only at first time */
+ if (!pmlmepriv->cur_network.join_res) { /* setting only at first time */
/* u32 initialgain; */
@@ -992,7 +992,7 @@ void start_bss_network(struct adapter *padapter, u8 *pbuf)
);
- if (true == pmlmeext->bstart_bss) {
+ if (pmlmeext->bstart_bss) {
update_beacon(padapter, _TIM_IE_, NULL, true);
@@ -1047,7 +1047,7 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len)
DBG_871X("%s, len =%d\n", __func__, len);
- if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
+ if (!check_fwstate(pmlmepriv, WIFI_AP_STATE))
return _FAIL;
@@ -1379,7 +1379,7 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len)
}
/* ht_cap */
- if (pregistrypriv->ht_enable && ht_cap == true) {
+ if (pregistrypriv->ht_enable && ht_cap) {
pmlmepriv->htpriv.ht_option = true;
pmlmepriv->qospriv.qos_option = 1;
@@ -1482,7 +1482,7 @@ int rtw_acl_add_sta(struct adapter *padapter, u8 *addr)
spin_unlock_bh(&(pacl_node_q->lock));
- if (added == true)
+ if (added)
return ret;
@@ -1492,7 +1492,7 @@ int rtw_acl_add_sta(struct adapter *padapter, u8 *addr)
paclnode = &pacl_list->aclnode[i];
- if (paclnode->valid == false) {
+ if (!paclnode->valid) {
INIT_LIST_HEAD(&paclnode->list);
@@ -1547,7 +1547,7 @@ int rtw_acl_remove_sta(struct adapter *padapter, u8 *addr)
!memcmp(baddr, addr, ETH_ALEN)
) {
- if (paclnode->valid == true) {
+ if (paclnode->valid) {
paclnode->valid = false;
@@ -1912,7 +1912,7 @@ void update_beacon(struct adapter *padapter, u8 ie_id, u8 *oui, u8 tx)
pmlmeext = &(padapter->mlmeextpriv);
/* pmlmeinfo = &(pmlmeext->mlmext_info); */
- if (false == pmlmeext->bstart_bss)
+ if (!pmlmeext->bstart_bss)
return;
spin_lock_bh(&pmlmepriv->bcn_update_lock);
@@ -1998,7 +1998,7 @@ static int rtw_ht_operation_update(struct adapter *padapter)
struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
struct ht_priv *phtpriv_ap = &pmlmepriv->htpriv;
- if (pmlmepriv->htpriv.ht_option == true)
+ if (pmlmepriv->htpriv.ht_option)
return 0;
/* if (!iface->conf->ieee80211n || iface->conf->ht_op_mode_fixed) */
@@ -2066,7 +2066,7 @@ static int rtw_ht_operation_update(struct adapter *padapter)
void associated_clients_update(struct adapter *padapter, u8 updated)
{
/* update associcated stations cap. */
- if (updated == true) {
+ if (updated) {
struct list_head *phead, *plist;
struct sta_info *psta = NULL;
@@ -2458,7 +2458,7 @@ void sta_info_update(struct adapter *padapter, struct sta_info *psta)
psta->htpriv.ht_option = false;
}
- if (pmlmepriv->htpriv.ht_option == false)
+ if (!pmlmepriv->htpriv.ht_option)
psta->htpriv.ht_option = false;
update_sta_info_apmode(padapter, psta);
diff --git a/drivers/staging/rtl8723bs/core/rtw_debug.c b/drivers/staging/rtl8723bs/core/rtw_debug.c
index f852fde47350..a2a2cefd1786 100644
--- a/drivers/staging/rtl8723bs/core/rtw_debug.c
+++ b/drivers/staging/rtl8723bs/core/rtw_debug.c
@@ -657,7 +657,7 @@ int proc_get_suspend_resume_info(struct seq_file *m, void *v)
DBG_871X_SEL_NL(m, "dbg_enwow_dload_fw_fail_cnt =%d\n", pdbgpriv->dbg_enwow_dload_fw_fail_cnt);
DBG_871X_SEL_NL(m, "dbg_ips_drvopen_fail_cnt =%d\n", pdbgpriv->dbg_ips_drvopen_fail_cnt);
DBG_871X_SEL_NL(m, "dbg_poll_fail_cnt =%d\n", pdbgpriv->dbg_poll_fail_cnt);
- DBG_871X_SEL_NL(m, "dbg_rpwm_toogle_cnt =%d\n", pdbgpriv->dbg_rpwm_toogle_cnt);
+ DBG_871X_SEL_NL(m, "dbg_rpwm_toggle_cnt =%d\n", pdbgpriv->dbg_rpwm_toggle_cnt);
DBG_871X_SEL_NL(m, "dbg_rpwm_timeout_fail_cnt =%d\n", pdbgpriv->dbg_rpwm_timeout_fail_cnt);
return 0;
diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme.c b/drivers/staging/rtl8723bs/core/rtw_mlme.c
index f9392b8db49b..4c5d5cf9dfe0 100644
--- a/drivers/staging/rtl8723bs/core/rtw_mlme.c
+++ b/drivers/staging/rtl8723bs/core/rtw_mlme.c
@@ -802,7 +802,7 @@ int rtw_is_desired_network(struct adapter *adapter, struct wlan_network *pnetwor
/* 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_evet\n"));
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("receive atimdone_event\n"));
}
diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c
index 0952d15f6d40..69c7abc0e3a5 100644
--- a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c
+++ b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c
@@ -1267,13 +1267,12 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame)
/* checking SSID */
p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + ie_offset, _SSID_IE_, &ie_len,
pkt_len - WLAN_HDR_A3_LEN - ie_offset);
- if (p == NULL) {
- status = _STATS_FAILURE_;
- }
- if (ie_len == 0) /* broadcast ssid, however it is not allowed in assocreq */
+ if (!p || ie_len == 0) {
+ /* broadcast ssid, however it is not allowed in assocreq */
status = _STATS_FAILURE_;
- else {
+ goto OnAssocReqFail;
+ } else {
/* check if ssid match */
if (memcmp((void *)(p+2), cur->Ssid.Ssid, cur->Ssid.SsidLength))
status = _STATS_FAILURE_;
@@ -3796,7 +3795,7 @@ int issue_deauth_ex(struct adapter *padapter, u8 *da, unsigned short reason, int
break;
if (i < try_cnt && wait_ms > 0 && ret == _FAIL)
- msleep(wait_ms);
+ mdelay(wait_ms);
} while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0)));
diff --git a/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c b/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c
index 110bbe340b78..59a667753266 100644
--- a/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c
+++ b/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c
@@ -1232,7 +1232,7 @@ int _rtw_pwr_wakeup(struct adapter *padapter, u32 ips_deffer_ms, const char *cal
if (pwrpriv->ps_processing) {
DBG_871X("%s wait ps_processing...\n", __func__);
while (pwrpriv->ps_processing && jiffies_to_msecs(jiffies - start) <= 3000)
- msleep(10);
+ mdelay(10);
if (pwrpriv->ps_processing)
DBG_871X("%s wait ps_processing timeout\n", __func__);
else
@@ -1244,7 +1244,7 @@ int _rtw_pwr_wakeup(struct adapter *padapter, u32 ips_deffer_ms, const char *cal
while (pwrpriv->bInSuspend
&& jiffies_to_msecs(jiffies - start) <= 3000
) {
- msleep(10);
+ mdelay(10);
}
if (pwrpriv->bInSuspend)
DBG_871X("%s wait bInSuspend timeout\n", __func__);
diff --git a/drivers/staging/rtl8723bs/core/rtw_security.c b/drivers/staging/rtl8723bs/core/rtw_security.c
index 6c8ac9e86c9f..240818b4a2c9 100644
--- a/drivers/staging/rtl8723bs/core/rtw_security.c
+++ b/drivers/staging/rtl8723bs/core/rtw_security.c
@@ -1543,7 +1543,7 @@ u32 rtw_aes_encrypt(struct adapter *padapter, u8 *pxmitframe)
pframe = ((struct xmit_frame *)pxmitframe)->buf_addr + hw_hdr_offset;
/* 4 start to encrypt each fragment */
- if ((pattrib->encrypt == _AES_)) {
+ if (pattrib->encrypt == _AES_) {
RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_aes_encrypt: stainfo!= NULL!!!\n"));
if (IS_MCAST(pattrib->ra))
@@ -1866,8 +1866,7 @@ u32 rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe)
pframe = (unsigned char *)((union recv_frame *)precvframe)->u.hdr.rx_data;
/* 4 start to encrypt each fragment */
- if ((prxattrib->encrypt == _AES_)) {
-
+ if (prxattrib->encrypt == _AES_) {
stainfo = rtw_get_stainfo(&padapter->stapriv, &prxattrib->ta[0]);
if (stainfo != NULL) {
RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_aes_decrypt: stainfo!= NULL!!!\n"));
diff --git a/drivers/staging/rtl8723bs/hal/hal_com_phycfg.c b/drivers/staging/rtl8723bs/hal/hal_com_phycfg.c
index 0d2c61b67d0e..12c1cd590056 100644
--- a/drivers/staging/rtl8723bs/hal/hal_com_phycfg.c
+++ b/drivers/staging/rtl8723bs/hal/hal_com_phycfg.c
@@ -2919,7 +2919,6 @@ int PHY_ConfigRFWithTxPwrTrackParaFile(struct adapter *Adapter, char *pFileName)
struct hal_com_data *pHalData = GET_HAL_DATA(Adapter);
int rlen = 0, rtStatus = _FAIL;
char *szLine, *ptmp;
- u32 i = 0;
if (!(Adapter->registrypriv.load_phy_file & LOAD_RF_TXPWR_TRACK_PARA_FILE))
return rtStatus;
@@ -2958,8 +2957,10 @@ int PHY_ConfigRFWithTxPwrTrackParaFile(struct adapter *Adapter, char *pFileName)
char band[5] = "", path[5] = "", sign[5] = "";
char chnl[5] = "", rate[10] = "";
char data[300] = ""; /* 100 is too small */
+ const int len = strlen(szLine);
+ int i;
- if (strlen(szLine) < 10 || szLine[0] != '[')
+ if (len < 10 || szLine[0] != '[')
continue;
strncpy(band, szLine+1, 2);
@@ -2973,7 +2974,7 @@ int PHY_ConfigRFWithTxPwrTrackParaFile(struct adapter *Adapter, char *pFileName)
if (!ParseQualifiedString(szLine, &i, chnl, '[', ']')) {
/* DBG_871X("Fail to parse channel group!\n"); */
}
- while (szLine[i] != '{' && i < strlen(szLine))
+ while (i < len && szLine[i] != '{')
i++;
if (!ParseQualifiedString(szLine, &i, data, '{', '}')) {
/* DBG_871X("Fail to parse data!\n"); */
@@ -3083,7 +3084,7 @@ static int phy_ParsePowerLimitTableFile(struct adapter *Adapter, char *buffer)
if (colNum > TXPWR_LMT_MAX_REGULATION_NUM) {
DBG_871X(
- "unvalid col number %d (greater than max %d)\n",
+ "invalid col number %d (greater than max %d)\n",
colNum, TXPWR_LMT_MAX_REGULATION_NUM
);
return _FAIL;
@@ -3101,7 +3102,7 @@ static int phy_ParsePowerLimitTableFile(struct adapter *Adapter, char *buffer)
/* DBG_871X("regulation %s!\n", regulation[forCnt]); */
if (regulation_name_cnt == 0) {
- DBG_871X("unvalid number of regulation!\n");
+ DBG_871X("invalid number of regulation!\n");
return _FAIL;
}
}
diff --git a/drivers/staging/rtl8723bs/hal/odm_DIG.c b/drivers/staging/rtl8723bs/hal/odm_DIG.c
index a12fdce77eae..4fa6cd315cf7 100644
--- a/drivers/staging/rtl8723bs/hal/odm_DIG.c
+++ b/drivers/staging/rtl8723bs/hal/odm_DIG.c
@@ -655,7 +655,7 @@ void odm_DIG(void *pDM_VOID)
ODM_COMP_DIG,
ODM_DBG_LOUD,
(
- "odm_DIG(): Abnrormal #beacon (%d) case in STA mode: Force lower bound to 0x%x !!!!!!\n\n",
+ "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
)
@@ -671,7 +671,7 @@ void odm_DIG(void *pDM_VOID)
ODM_COMP_DIG,
ODM_DBG_LOUD,
(
- "odm_DIG(): Abnrormal lower bound case: Force lower bound to 0x%x !!!!!!\n\n",
+ "odm_DIG(): Abnormal lower bound case: Force lower bound to 0x%x !!!!!!\n\n",
pDM_DigTable->rx_gain_range_min
)
);
diff --git a/drivers/staging/rtl8723bs/hal/odm_EdcaTurboCheck.c b/drivers/staging/rtl8723bs/hal/odm_EdcaTurboCheck.c
index acc64fa8f166..0e674f39ef03 100644
--- a/drivers/staging/rtl8723bs/hal/odm_EdcaTurboCheck.c
+++ b/drivers/staging/rtl8723bs/hal/odm_EdcaTurboCheck.c
@@ -97,7 +97,7 @@ void odm_EdcaTurboCheckCE(void *pDM_VOID)
return;
}
- if ((pregpriv->wifi_spec == 1)) {
+ if (pregpriv->wifi_spec == 1) {
precvpriv->bIsAnyNonBEPkts = false;
return;
}
diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c
index 592917fc00aa..c7e55618b9a8 100644
--- a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c
+++ b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c
@@ -3348,7 +3348,7 @@ static void hw_var_set_opmode(struct adapter *padapter, u8 variable, u8 *val)
/* disable atim wnd */
rtw_write8(padapter, REG_BCN_CTRL, DIS_TSF_UDT|EN_BCN_FUNCTION|DIS_ATIM);
/* rtw_write8(padapter, REG_BCN_CTRL, 0x18); */
- } else if ((mode == _HW_STATE_ADHOC_) /*|| (mode == _HW_STATE_AP_)*/) {
+ } else if (mode == _HW_STATE_ADHOC_) {
ResumeTxBeacon(padapter);
rtw_write8(padapter, REG_BCN_CTRL, DIS_TSF_UDT|EN_BCN_FUNCTION|DIS_BCNQ_SUB);
} else if (mode == _HW_STATE_AP_) {
diff --git a/drivers/staging/rtl8723bs/include/drv_types.h b/drivers/staging/rtl8723bs/include/drv_types.h
index c57f290f605a..062fda9962be 100644
--- a/drivers/staging/rtl8723bs/include/drv_types.h
+++ b/drivers/staging/rtl8723bs/include/drv_types.h
@@ -381,7 +381,7 @@ struct debug_priv {
u32 dbg_enwow_dload_fw_fail_cnt;
u32 dbg_ips_drvopen_fail_cnt;
u32 dbg_poll_fail_cnt;
- u32 dbg_rpwm_toogle_cnt;
+ u32 dbg_rpwm_toggle_cnt;
u32 dbg_rpwm_timeout_fail_cnt;
u64 dbg_rx_fifo_last_overflow;
u64 dbg_rx_fifo_curr_overflow;
diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c b/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c
index c38298d960ff..28bfdbdc6e76 100644
--- a/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c
+++ b/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c
@@ -209,9 +209,9 @@ static char *translate_scan(struct adapter *padapter,
i++;
}
- if (vht_cap == true) {
+ if (vht_cap) {
max_rate = vht_data_rate;
- } else if (ht_cap == true) {
+ } else if (ht_cap) {
if (mcs_rate&0x8000) { /* MCS15 */
max_rate = (bw_40MHz) ? ((short_GI)?300:270):((short_GI)?144:130);
} else if (mcs_rate&0x0080) { /* MCS7 */
@@ -337,7 +337,7 @@ static char *translate_scan(struct adapter *padapter,
#ifdef CONFIG_SIGNAL_DISPLAY_DBM
- iwe.u.qual.level = (u8) translate_percentage_to_dbm(ss);/* dbm */
+ iwe.u.qual.level = (u8)translate_percentage_to_dbm(ss);/* dbm */
#else
#ifdef CONFIG_SKIP_SIGNAL_SCALE_MAPPING
{
@@ -392,7 +392,7 @@ exit:
static int wpa_set_auth_algs(struct net_device *dev, u32 value)
{
- struct adapter *padapter = (struct adapter *) rtw_netdev_priv(dev);
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
int ret = 0;
if ((value & WLAN_AUTH_SHARED_KEY) && (value & WLAN_AUTH_OPEN)) {
@@ -436,7 +436,7 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param,
param->u.crypt.err = 0;
param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0';
- if (param_len < (u32) ((u8 *) param->u.crypt.key - (u8 *) param) + param->u.crypt.key_len) {
+ if (param_len < (u32)((u8 *)param->u.crypt.key - (u8 *)param) + param->u.crypt.key_len) {
ret = -EINVAL;
goto exit;
}
@@ -528,8 +528,8 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param,
}
if (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) { /* 802_1x */
- struct sta_info * psta,*pbcmc_sta;
- struct sta_priv * pstapriv = &padapter->stapriv;
+ struct sta_info *psta, *pbcmc_sta;
+ struct sta_priv *pstapriv = &padapter->stapriv;
if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_MP_STATE) == true) { /* sta mode */
psta = rtw_get_stainfo(pstapriv, get_bssid(pmlmepriv));
@@ -862,7 +862,7 @@ static int rtw_wx_set_mode(struct net_device *dev, struct iw_request_info *a,
goto exit;
}
- if (padapter->hw_init_completed ==false) {
+ if (!padapter->hw_init_completed) {
ret = -EPERM;
goto exit;
}
@@ -946,7 +946,7 @@ static int rtw_wx_set_pmkid(struct net_device *dev,
u8 j, blInserted = false;
int intReturn = false;
struct security_priv *psecuritypriv = &padapter->securitypriv;
- struct iw_pmksa* pPMK = (struct iw_pmksa*) extra;
+ struct iw_pmksa* pPMK = (struct iw_pmksa*)extra;
u8 strZeroMacAddress[ ETH_ALEN ] = { 0x00 };
u8 strIssueBssid[ ETH_ALEN ] = { 0x00 };
@@ -1236,7 +1236,7 @@ static int rtw_wx_set_mlme(struct net_device *dev,
int ret = 0;
u16 reason;
struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- struct iw_mlme *mlme = (struct iw_mlme *) extra;
+ struct iw_mlme *mlme = (struct iw_mlme *)extra;
if (mlme == NULL)
@@ -1295,7 +1295,7 @@ static int rtw_wx_set_scan(struct net_device *dev, struct iw_request_info *a,
goto exit;
}
- if (padapter->hw_init_completed ==false) {
+ if (!padapter->hw_init_completed ) {
ret = -1;
goto exit;
}
@@ -1303,7 +1303,7 @@ static int rtw_wx_set_scan(struct net_device *dev, struct iw_request_info *a,
/* When Busy Traffic, driver do not site survey. So driver return success. */
/* wpa_supplicant will not issue SIOCSIWSCAN cmd again after scan timeout. */
/* modify by thomas 2011-02-22. */
- if (pmlmepriv->LinkDetectInfo.bBusyTraffic == true) {
+ if (pmlmepriv->LinkDetectInfo.bBusyTraffic) {
indicate_wx_scan_complete_event(padapter);
goto exit;
}
@@ -2390,7 +2390,7 @@ static int rtw_wx_set_channel_plan(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
- u8 channel_plan_req = (u8) (*((int *)wrqu));
+ u8 channel_plan_req = (u8)(*((int *)wrqu));
if (_SUCCESS == rtw_set_chplan_cmd(padapter, channel_plan_req, 1, 1))
DBG_871X("%s set channel_plan = 0x%02X\n", __func__, channel_plan_req);
@@ -2584,7 +2584,7 @@ static int rtw_wps_start(struct net_device *dev,
goto exit;
}
- uintRet = copy_from_user((void*) &u32wps_start, pdata->pointer, 4);
+ uintRet = copy_from_user((void*)&u32wps_start, pdata->pointer, 4);
if (u32wps_start == 0)
u32wps_start = *extra;
@@ -4229,7 +4229,7 @@ static int rtw_hostapd_ioctl(struct net_device *dev, struct iw_point *p)
* so, we just check hw_init_completed
*/
- if (padapter->hw_init_completed ==false) {
+ if (!padapter->hw_init_completed) {
ret = -EPERM;
goto out;
}
diff --git a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c
index 6d02904de63f..7c03b69b8ed3 100644
--- a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c
+++ b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c
@@ -22,7 +22,7 @@ static const struct sdio_device_id sdio_ids[] =
{ SDIO_DEVICE(0x024c, 0xb723), },
{ /* end: all zeroes */ },
};
-static const struct acpi_device_id acpi_ids[] = {
+static const struct acpi_device_id acpi_ids[] __used = {
{"OBDA8723", 0x0000},
{}
};
diff --git a/drivers/staging/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/staging/rtlwifi/btcoexist/halbtcoutsrc.c
index 4d1f9bf53c53..24e19ffd4431 100644
--- a/drivers/staging/rtlwifi/btcoexist/halbtcoutsrc.c
+++ b/drivers/staging/rtlwifi/btcoexist/halbtcoutsrc.c
@@ -281,11 +281,9 @@ bool halbtc_send_bt_mp_operation(struct btc_coexist *btcoexist, u8 op_code,
static void halbtc_leave_lps(struct btc_coexist *btcoexist)
{
struct rtl_priv *rtlpriv;
- struct rtl_ps_ctl *ppsc;
bool ap_enable = false;
rtlpriv = btcoexist->adapter;
- ppsc = rtl_psc(rtlpriv);
btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE,
&ap_enable);
@@ -304,11 +302,9 @@ static void halbtc_leave_lps(struct btc_coexist *btcoexist)
static void halbtc_enter_lps(struct btc_coexist *btcoexist)
{
struct rtl_priv *rtlpriv;
- struct rtl_ps_ctl *ppsc;
bool ap_enable = false;
rtlpriv = btcoexist->adapter;
- ppsc = rtl_psc(rtlpriv);
btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE,
&ap_enable);
@@ -1261,13 +1257,13 @@ bool exhalbtc_initlize_variables_wifi_only(struct rtl_priv *rtlpriv)
switch (rtlpriv->rtlhal.interface) {
case INTF_PCI:
- wifionly_cfg->chip_interface = BTC_INTF_PCI;
+ wifionly_cfg->chip_interface = WIFIONLY_INTF_PCI;
break;
case INTF_USB:
- wifionly_cfg->chip_interface = BTC_INTF_USB;
+ wifionly_cfg->chip_interface = WIFIONLY_INTF_USB;
break;
default:
- wifionly_cfg->chip_interface = BTC_INTF_UNKNOWN;
+ wifionly_cfg->chip_interface = WIFIONLY_INTF_UNKNOWN;
break;
}
diff --git a/drivers/staging/rtlwifi/efuse.c b/drivers/staging/rtlwifi/efuse.c
index 1dc71455f270..abb0f720cf21 100644
--- a/drivers/staging/rtlwifi/efuse.c
+++ b/drivers/staging/rtlwifi/efuse.c
@@ -245,7 +245,8 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf)
if (!efuse_word)
goto out;
for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) {
- efuse_word[i] = kcalloc(efuse_max_section, sizeof(u16), GFP_ATOMIC);
+ efuse_word[i] = kcalloc(efuse_max_section, sizeof(u16),
+ GFP_ATOMIC);
if (!efuse_word[i])
goto done;
}
diff --git a/drivers/staging/rtlwifi/halmac/rtl_halmac.c b/drivers/staging/rtlwifi/halmac/rtl_halmac.c
index f0c6fc8c6aca..7bfc9620479a 100644
--- a/drivers/staging/rtlwifi/halmac/rtl_halmac.c
+++ b/drivers/staging/rtlwifi/halmac/rtl_halmac.c
@@ -209,7 +209,7 @@ static int init_halmac_event_with_waittime(struct rtl_priv *rtlpriv,
if (!rtlpriv->halmac.indicator[id].comp) {
comp = kzalloc(sizeof(*comp), GFP_KERNEL);
if (!comp)
- return -1;
+ return -ENOMEM;
} else {
RT_TRACE(rtlpriv, COMP_HALMAC, DBG_LOUD,
"%s: <WARN> id(%d) sctx is not NULL!!\n", __func__,
@@ -359,7 +359,7 @@ static int init_priv(struct rtl_halmac *halmac)
size = sizeof(*indicator) * count;
indicator = kzalloc(size, GFP_KERNEL);
if (!indicator)
- return -1;
+ return -ENOMEM;
halmac->indicator = indicator;
return 0;
diff --git a/drivers/staging/rtlwifi/phydm/phydm_adc_sampling.c b/drivers/staging/rtlwifi/phydm/phydm_adc_sampling.c
index 42020101380a..d6cea73fa185 100644
--- a/drivers/staging/rtlwifi/phydm/phydm_adc_sampling.c
+++ b/drivers/staging/rtlwifi/phydm/phydm_adc_sampling.c
@@ -555,7 +555,7 @@ void phydm_lamode_trigger_setting(void *dm_void, char input[][16], u32 *_used,
output + used, out_len - used,
"{En} {0:BB,1:BB_MAC,2:RF0,3:RF1,4:MAC}\n {BB:dbg_port[bit],BB_MAC:0-ok/1-fail/2-cca,MAC:ref} {DMA type} {TrigTime}\n {polling_time/ref_mask} {dbg_port} {0:P_Edge, 1:N_Edge} {SpRate:0-80M,1-40M,2-20M} {Capture num}\n");
/**/
- } else if ((is_enable_la_mode == 1)) {
+ } else if (is_enable_la_mode == 1) {
PHYDM_SSCANF(input[2], DCMD_DECIMAL, &var1[1]);
trig_mode = (u8)var1[1];
diff --git a/drivers/staging/rtlwifi/phydm/phydm_dig.c b/drivers/staging/rtlwifi/phydm/phydm_dig.c
index 3115e7bdc749..f10776fbe2d9 100644
--- a/drivers/staging/rtlwifi/phydm/phydm_dig.c
+++ b/drivers/staging/rtlwifi/phydm/phydm_dig.c
@@ -813,7 +813,7 @@ void odm_DIG(void *dm_void)
dig_tab->rx_gain_range_min = 0x1c;
ODM_RT_TRACE(
dm, ODM_COMP_DIG,
- "DIG: Abnrormal #beacon (%d) case in STA mode: Force lower bound to 0x%x\n",
+ "DIG: Abnormal #beacon (%d) case in STA mode: Force lower bound to 0x%x\n",
dm->phy_dbg_info.num_qry_beacon_pkt,
dig_tab->rx_gain_range_min);
}
@@ -824,7 +824,7 @@ void odm_DIG(void *dm_void)
dig_tab->rx_gain_range_min = dig_tab->rx_gain_range_max;
ODM_RT_TRACE(
dm, ODM_COMP_DIG,
- "DIG: Abnrormal lower bound case: Force lower bound to 0x%x\n",
+ "DIG: Abnormal lower bound case: Force lower bound to 0x%x\n",
dig_tab->rx_gain_range_min);
}
diff --git a/drivers/staging/rtlwifi/regd.c b/drivers/staging/rtlwifi/regd.c
index 3afd206ce4b1..5213ca771175 100644
--- a/drivers/staging/rtlwifi/regd.c
+++ b/drivers/staging/rtlwifi/regd.c
@@ -410,7 +410,7 @@ int rtl_regd_init(struct ieee80211_hw *hw,
struct wiphy *wiphy = hw->wiphy;
struct country_code_to_enum_rd *country = NULL;
- if (!wiphy || !&rtlpriv->regd)
+ if (!wiphy)
return -EINVAL;
/* init country_code from efuse channel plan */
diff --git a/drivers/staging/rtlwifi/wifi.h b/drivers/staging/rtlwifi/wifi.h
index a45f0eb69d3f..9cb6c7906213 100644
--- a/drivers/staging/rtlwifi/wifi.h
+++ b/drivers/staging/rtlwifi/wifi.h
@@ -1840,10 +1840,6 @@ struct rtl_efuse {
u8 efuse_map[2][EFUSE_MAX_LOGICAL_SIZE];
u16 efuse_usedbytes;
u8 efuse_usedpercentage;
-#ifdef EFUSE_REPG_WORKAROUND
- bool efuse_re_pg_sec1flag;
- u8 efuse_re_pg_data[8];
-#endif
u8 autoload_failflag;
u8 autoload_status;
diff --git a/drivers/staging/rts5208/ms.c b/drivers/staging/rts5208/ms.c
index 3a71dbb6d24a..f53adf15c685 100644
--- a/drivers/staging/rts5208/ms.c
+++ b/drivers/staging/rts5208/ms.c
@@ -111,9 +111,8 @@ static int ms_transfer_data(struct rtsx_chip *chip, u8 trans_mode,
u8 val, err_code = 0;
enum dma_data_direction dir;
- if (!buf || !buf_len) {
+ if (!buf || !buf_len)
return STATUS_FAIL;
- }
if (trans_mode == MS_TM_AUTO_READ) {
dir = DMA_FROM_DEVICE;
@@ -162,12 +161,11 @@ static int ms_transfer_data(struct rtsx_chip *chip, u8 trans_mode,
}
retval = rtsx_read_register(chip, MS_TRANS_CFG, &val);
- if (retval) {
+ if (retval)
return retval;
- }
- if (val & (MS_INT_CMDNK | MS_INT_ERR | MS_CRC16_ERR | MS_RDY_TIMEOUT)) {
+
+ if (val & (MS_INT_CMDNK | MS_INT_ERR | MS_CRC16_ERR | MS_RDY_TIMEOUT))
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
@@ -178,9 +176,8 @@ static int ms_write_bytes(struct rtsx_chip *chip,
struct ms_info *ms_card = &chip->ms_card;
int retval, i;
- if (!data || (data_len < cnt)) {
+ if (!data || (data_len < cnt))
return STATUS_ERROR;
- }
rtsx_init_cmd(chip);
@@ -244,9 +241,8 @@ static int ms_read_bytes(struct rtsx_chip *chip,
int retval, i;
u8 *ptr;
- if (!data) {
+ if (!data)
return STATUS_ERROR;
- }
rtsx_init_cmd(chip);
@@ -371,14 +367,12 @@ static int ms_set_init_para(struct rtsx_chip *chip)
}
retval = switch_clock(chip, ms_card->ms_clock);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = select_card(chip, MS_CARD);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
@@ -389,14 +383,12 @@ static int ms_switch_clock(struct rtsx_chip *chip)
int retval;
retval = select_card(chip, MS_CARD);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = switch_clock(chip, ms_card->ms_clock);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
@@ -409,60 +401,59 @@ static int ms_pull_ctl_disable(struct rtsx_chip *chip)
retval = rtsx_write_register(chip, CARD_PULL_CTL1, 0xFF,
MS_D1_PD | MS_D2_PD | MS_CLK_PD |
MS_D6_PD);
- if (retval) {
+ if (retval)
return retval;
- }
+
retval = rtsx_write_register(chip, CARD_PULL_CTL2, 0xFF,
MS_D3_PD | MS_D0_PD | MS_BS_PD |
XD_D4_PD);
- if (retval) {
+ if (retval)
return retval;
- }
+
retval = rtsx_write_register(chip, CARD_PULL_CTL3, 0xFF,
MS_D7_PD | XD_CE_PD | XD_CLE_PD |
XD_CD_PU);
- if (retval) {
+ if (retval)
return retval;
- }
+
retval = rtsx_write_register(chip, CARD_PULL_CTL4, 0xFF,
XD_RDY_PD | SD_D3_PD | SD_D2_PD |
XD_ALE_PD);
- if (retval) {
+ if (retval)
return retval;
- }
+
retval = rtsx_write_register(chip, CARD_PULL_CTL5, 0xFF,
MS_INS_PU | SD_WP_PD | SD_CD_PU |
SD_CMD_PD);
- if (retval) {
+ if (retval)
return retval;
- }
+
retval = rtsx_write_register(chip, CARD_PULL_CTL6, 0xFF,
MS_D5_PD | MS_D4_PD);
- if (retval) {
+ if (retval)
return retval;
- }
+
} else if (CHECK_PID(chip, 0x5288)) {
if (CHECK_BARO_PKG(chip, QFN)) {
retval = rtsx_write_register(chip, CARD_PULL_CTL1,
0xFF, 0x55);
- if (retval) {
+ if (retval)
return retval;
- }
+
retval = rtsx_write_register(chip, CARD_PULL_CTL2,
0xFF, 0x55);
- if (retval) {
+ if (retval)
return retval;
- }
+
retval = rtsx_write_register(chip, CARD_PULL_CTL3,
0xFF, 0x4B);
- if (retval) {
+ if (retval)
return retval;
- }
+
retval = rtsx_write_register(chip, CARD_PULL_CTL4,
0xFF, 0x69);
- if (retval) {
+ if (retval)
return retval;
- }
}
}
@@ -502,9 +493,8 @@ static int ms_pull_ctl_enable(struct rtsx_chip *chip)
}
retval = rtsx_send_cmd(chip, MS_CARD, 100);
- if (retval < 0) {
+ if (retval < 0)
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
@@ -523,36 +513,31 @@ static int ms_prepare_reset(struct rtsx_chip *chip)
ms_card->pro_under_formatting = 0;
retval = ms_power_off_card3v3(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (!chip->ft2_fast_mode)
wait_timeout(250);
retval = enable_card_clock(chip, MS_CARD);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (chip->asic_code) {
retval = ms_pull_ctl_enable(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
} else {
retval = rtsx_write_register(chip, FPGA_PULL_CTL,
FPGA_MS_PULL_CTL_BIT | 0x20, 0);
- if (retval) {
+ if (retval)
return retval;
- }
}
if (!chip->ft2_fast_mode) {
retval = card_power_on(chip, MS_CARD);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
wait_timeout(150);
@@ -572,9 +557,8 @@ static int ms_prepare_reset(struct rtsx_chip *chip)
retval = rtsx_write_register(chip, CARD_OE, MS_OUTPUT_EN,
MS_OUTPUT_EN);
- if (retval) {
+ if (retval)
return retval;
- }
if (chip->asic_code) {
retval = rtsx_write_register(chip, MS_CFG, 0xFF,
@@ -582,34 +566,31 @@ static int ms_prepare_reset(struct rtsx_chip *chip)
PUSH_TIME_DEFAULT |
NO_EXTEND_TOGGLE |
MS_BUS_WIDTH_1);
- if (retval) {
+ if (retval)
return retval;
- }
+
} else {
retval = rtsx_write_register(chip, MS_CFG, 0xFF,
SAMPLE_TIME_FALLING |
PUSH_TIME_DEFAULT |
NO_EXTEND_TOGGLE |
MS_BUS_WIDTH_1);
- if (retval) {
+ if (retval)
return retval;
- }
}
retval = rtsx_write_register(chip, MS_TRANS_CFG, 0xFF,
NO_WAIT_INT | NO_AUTO_READ_INT_REG);
- if (retval) {
+ if (retval)
return retval;
- }
+
retval = rtsx_write_register(chip, CARD_STOP, MS_STOP | MS_CLR_ERR,
MS_STOP | MS_CLR_ERR);
- if (retval) {
+ if (retval)
return retval;
- }
retval = ms_set_init_para(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
@@ -621,9 +602,8 @@ static int ms_identify_media_type(struct rtsx_chip *chip, int switch_8bit_bus)
u8 val;
retval = ms_set_rw_reg_addr(chip, Pro_StatusReg, 6, SystemParm, 1);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
retval = ms_transfer_tpc(chip, MS_TM_READ_BYTES, READ_REG,
@@ -631,14 +611,13 @@ static int ms_identify_media_type(struct rtsx_chip *chip, int switch_8bit_bus)
if (retval == STATUS_SUCCESS)
break;
}
- if (i == MS_MAX_RETRY_COUNT) {
+ if (i == MS_MAX_RETRY_COUNT)
return STATUS_FAIL;
- }
retval = rtsx_read_register(chip, PPBUF_BASE2 + 2, &val);
- if (retval) {
+ if (retval)
return retval;
- }
+
dev_dbg(rtsx_dev(chip), "Type register: 0x%x\n", val);
if (val != 0x01) {
if (val != 0x02)
@@ -648,9 +627,9 @@ static int ms_identify_media_type(struct rtsx_chip *chip, int switch_8bit_bus)
}
retval = rtsx_read_register(chip, PPBUF_BASE2 + 4, &val);
- if (retval) {
+ if (retval)
return retval;
- }
+
dev_dbg(rtsx_dev(chip), "Category register: 0x%x\n", val);
if (val != 0) {
ms_card->check_ms_flow = 1;
@@ -658,15 +637,15 @@ static int ms_identify_media_type(struct rtsx_chip *chip, int switch_8bit_bus)
}
retval = rtsx_read_register(chip, PPBUF_BASE2 + 5, &val);
- if (retval) {
+ if (retval)
return retval;
- }
+
dev_dbg(rtsx_dev(chip), "Class register: 0x%x\n", val);
if (val == 0) {
retval = rtsx_read_register(chip, PPBUF_BASE2, &val);
- if (retval) {
+ if (retval)
return retval;
- }
+
if (val & WRT_PRTCT)
chip->card_wp |= MS_CARD;
else
@@ -682,9 +661,9 @@ static int ms_identify_media_type(struct rtsx_chip *chip, int switch_8bit_bus)
ms_card->ms_type |= TYPE_MSPRO;
retval = rtsx_read_register(chip, PPBUF_BASE2 + 3, &val);
- if (retval) {
+ if (retval)
return retval;
- }
+
dev_dbg(rtsx_dev(chip), "IF Mode register: 0x%x\n", val);
if (val == 0) {
ms_card->ms_type &= 0x0F;
@@ -720,13 +699,11 @@ static int ms_confirm_cpu_startup(struct rtsx_chip *chip)
if (retval == STATUS_SUCCESS)
break;
}
- if (i == MS_MAX_RETRY_COUNT) {
+ if (i == MS_MAX_RETRY_COUNT)
return STATUS_FAIL;
- }
- if (k > 100) {
+ if (k > 100)
return STATUS_FAIL;
- }
k++;
wait_timeout(100);
@@ -737,16 +714,14 @@ static int ms_confirm_cpu_startup(struct rtsx_chip *chip)
if (retval == STATUS_SUCCESS)
break;
}
- if (i == MS_MAX_RETRY_COUNT) {
+ if (i == MS_MAX_RETRY_COUNT)
return STATUS_FAIL;
- }
if (val & INT_REG_ERR) {
- if (val & INT_REG_CMDNK) {
+ if (val & INT_REG_CMDNK)
chip->card_wp |= (MS_CARD);
- } else {
+ else
return STATUS_FAIL;
- }
}
/* -- end confirm CPU startup */
@@ -766,9 +741,8 @@ static int ms_switch_parallel_bus(struct rtsx_chip *chip)
if (retval == STATUS_SUCCESS)
break;
}
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
@@ -787,27 +761,24 @@ static int ms_switch_8bit_bus(struct rtsx_chip *chip)
if (retval == STATUS_SUCCESS)
break;
}
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = rtsx_write_register(chip, MS_CFG, 0x98,
MS_BUS_WIDTH_8 | SAMPLE_TIME_FALLING);
- if (retval) {
+ if (retval)
return retval;
- }
+
ms_card->ms_type |= MS_8BIT;
retval = ms_set_init_para(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
retval = ms_transfer_tpc(chip, MS_TM_READ_BYTES, GET_INT,
1, NO_WAIT_INT);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
}
return STATUS_SUCCESS;
@@ -820,19 +791,16 @@ static int ms_pro_reset_flow(struct rtsx_chip *chip, int switch_8bit_bus)
for (i = 0; i < 3; i++) {
retval = ms_prepare_reset(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = ms_identify_media_type(chip, switch_8bit_bus);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = ms_confirm_cpu_startup(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = ms_switch_parallel_bus(chip);
if (retval != STATUS_SUCCESS) {
@@ -846,25 +814,22 @@ static int ms_pro_reset_flow(struct rtsx_chip *chip, int switch_8bit_bus)
}
}
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
/* Switch MS-PRO into Parallel mode */
retval = rtsx_write_register(chip, MS_CFG, 0x18, MS_BUS_WIDTH_4);
- if (retval) {
+ if (retval)
return retval;
- }
+
retval = rtsx_write_register(chip, MS_CFG, PUSH_TIME_ODD,
PUSH_TIME_ODD);
- if (retval) {
+ if (retval)
return retval;
- }
retval = ms_set_init_para(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
/* If MSPro HG Card, We shall try to switch to 8-bit bus */
if (CHK_MSHG(ms_card) && chip->support_ms_8bit && switch_8bit_bus) {
@@ -887,9 +852,8 @@ static int msxc_change_power(struct rtsx_chip *chip, u8 mode)
ms_cleanup_work(chip);
retval = ms_set_rw_reg_addr(chip, 0, 0, Pro_DataCount1, 6);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
buf[0] = 0;
buf[1] = mode;
@@ -899,22 +863,19 @@ static int msxc_change_power(struct rtsx_chip *chip, u8 mode)
buf[5] = 0;
retval = ms_write_bytes(chip, PRO_WRITE_REG, 6, NO_WAIT_INT, buf, 6);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = ms_send_cmd(chip, XC_CHG_POWER, WAIT_INT);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = rtsx_read_register(chip, MS_TRANS_CFG, buf);
- if (retval) {
+ if (retval)
return retval;
- }
- if (buf[0] & (MS_INT_CMDNK | MS_INT_ERR)) {
+
+ if (buf[0] & (MS_INT_CMDNK | MS_INT_ERR))
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
@@ -936,9 +897,8 @@ static int ms_read_attribute_info(struct rtsx_chip *chip)
#endif
retval = ms_set_rw_reg_addr(chip, Pro_IntReg, 2, Pro_SystemParm, 7);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (CHK_MS8BIT(ms_card))
data[0] = PARALLEL_8BIT_IF;
@@ -960,14 +920,12 @@ static int ms_read_attribute_info(struct rtsx_chip *chip)
if (retval == STATUS_SUCCESS)
break;
}
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
buf = kmalloc(64 * 512, GFP_KERNEL);
- if (!buf) {
+ if (!buf)
return STATUS_ERROR;
- }
for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
retval = ms_send_cmd(chip, PRO_READ_ATRB, WAIT_INT);
@@ -1150,18 +1108,15 @@ static int ms_read_attribute_info(struct rtsx_chip *chip)
#ifdef SUPPORT_MSXC
if (CHK_MSXC(ms_card)) {
- if (class_code != 0x03) {
+ if (class_code != 0x03)
return STATUS_FAIL;
- }
} else {
- if (class_code != 0x02) {
+ if (class_code != 0x02)
return STATUS_FAIL;
- }
}
#else
- if (class_code != 0x02) {
+ if (class_code != 0x02)
return STATUS_FAIL;
- }
#endif
if (device_type != 0x00) {
@@ -1173,9 +1128,8 @@ static int ms_read_attribute_info(struct rtsx_chip *chip)
}
}
- if (sub_class & 0xC0) {
+ if (sub_class & 0xC0)
return STATUS_FAIL;
- }
dev_dbg(rtsx_dev(chip), "class_code: 0x%x, device_type: 0x%x, sub_class: 0x%x\n",
class_code, device_type, sub_class);
@@ -1223,18 +1177,16 @@ retry:
if (retval != STATUS_SUCCESS) {
if (ms_card->switch_8bit_fail) {
retval = ms_pro_reset_flow(chip, 0);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
} else {
return STATUS_FAIL;
}
}
retval = ms_read_attribute_info(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
#ifdef XC_POWERCLASS
if (CHK_HG8BIT(ms_card))
@@ -1274,9 +1226,8 @@ retry:
#ifdef SUPPORT_MAGIC_GATE
retval = mg_set_tpc_para_sub(chip, 0, 0);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
#endif
if (CHK_HG8BIT(ms_card))
@@ -1293,14 +1244,12 @@ static int ms_read_status_reg(struct rtsx_chip *chip)
u8 val[2];
retval = ms_set_rw_reg_addr(chip, StatusReg0, 2, 0, 0);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = ms_read_bytes(chip, READ_REG, 2, NO_WAIT_INT, val, 2);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (val[1] & (STS_UCDT | STS_UCEX | STS_UCFG)) {
ms_set_err_code(chip, MS_FLASH_READ_ERROR);
@@ -1319,9 +1268,8 @@ static int ms_read_extra_data(struct rtsx_chip *chip,
retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE,
SystemParm, 6);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (CHK_MS4BIT(ms_card)) {
/* Parallel interface */
@@ -1342,9 +1290,8 @@ static int ms_read_extra_data(struct rtsx_chip *chip,
if (retval == STATUS_SUCCESS)
break;
}
- if (i == MS_MAX_RETRY_COUNT) {
+ if (i == MS_MAX_RETRY_COUNT)
return STATUS_FAIL;
- }
ms_set_err_code(chip, MS_NO_ERROR);
@@ -1353,15 +1300,13 @@ static int ms_read_extra_data(struct rtsx_chip *chip,
if (retval == STATUS_SUCCESS)
break;
}
- if (i == MS_MAX_RETRY_COUNT) {
+ if (i == MS_MAX_RETRY_COUNT)
return STATUS_FAIL;
- }
ms_set_err_code(chip, MS_NO_ERROR);
retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (val & INT_REG_CMDNK) {
ms_set_err_code(chip, MS_CMD_NK);
@@ -1370,24 +1315,21 @@ static int ms_read_extra_data(struct rtsx_chip *chip,
if (val & INT_REG_CED) {
if (val & INT_REG_ERR) {
retval = ms_read_status_reg(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = ms_set_rw_reg_addr(chip, OverwriteFlag,
MS_EXTRA_SIZE, SystemParm,
6);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
}
}
retval = ms_read_bytes(chip, READ_REG, MS_EXTRA_SIZE, NO_WAIT_INT,
data, MS_EXTRA_SIZE);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (buf && buf_len) {
if (buf_len > MS_EXTRA_SIZE)
@@ -1405,15 +1347,13 @@ static int ms_write_extra_data(struct rtsx_chip *chip, u16 block_addr,
int retval, i;
u8 val, data[16];
- if (!buf || (buf_len < MS_EXTRA_SIZE)) {
+ if (!buf || (buf_len < MS_EXTRA_SIZE))
return STATUS_FAIL;
- }
retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE,
SystemParm, 6 + MS_EXTRA_SIZE);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (CHK_MS4BIT(ms_card))
data[0] = 0x88;
@@ -1431,20 +1371,17 @@ static int ms_write_extra_data(struct rtsx_chip *chip, u16 block_addr,
retval = ms_write_bytes(chip, WRITE_REG, (6 + MS_EXTRA_SIZE),
NO_WAIT_INT, data, 16);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
ms_set_err_code(chip, MS_NO_ERROR);
retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (val & INT_REG_CMDNK) {
ms_set_err_code(chip, MS_CMD_NK);
@@ -1468,9 +1405,8 @@ static int ms_read_page(struct rtsx_chip *chip, u16 block_addr, u8 page_num)
retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE,
SystemParm, 6);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (CHK_MS4BIT(ms_card))
data[0] = 0x88;
@@ -1484,20 +1420,17 @@ static int ms_read_page(struct rtsx_chip *chip, u16 block_addr, u8 page_num)
data[5] = page_num;
retval = ms_write_bytes(chip, WRITE_REG, 6, NO_WAIT_INT, data, 6);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = ms_send_cmd(chip, BLOCK_READ, WAIT_INT);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
ms_set_err_code(chip, MS_NO_ERROR);
retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (val & INT_REG_CMDNK) {
ms_set_err_code(chip, MS_CMD_NK);
@@ -1524,13 +1457,11 @@ static int ms_read_page(struct rtsx_chip *chip, u16 block_addr, u8 page_num)
retval = ms_transfer_tpc(chip, MS_TM_NORMAL_READ, READ_PAGE_DATA,
0, NO_WAIT_INT);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
- if (ms_check_err_code(chip, MS_FLASH_WRITE_ERROR)) {
+ if (ms_check_err_code(chip, MS_FLASH_WRITE_ERROR))
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
@@ -1542,15 +1473,13 @@ static int ms_set_bad_block(struct rtsx_chip *chip, u16 phy_blk)
u8 val, data[8], extra[MS_EXTRA_SIZE];
retval = ms_read_extra_data(chip, phy_blk, 0, extra, MS_EXTRA_SIZE);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE,
SystemParm, 7);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
ms_set_err_code(chip, MS_NO_ERROR);
@@ -1568,20 +1497,17 @@ static int ms_set_bad_block(struct rtsx_chip *chip, u16 phy_blk)
data[7] = 0xFF;
retval = ms_write_bytes(chip, WRITE_REG, 7, NO_WAIT_INT, data, 7);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
ms_set_err_code(chip, MS_NO_ERROR);
retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (val & INT_REG_CMDNK) {
ms_set_err_code(chip, MS_CMD_NK);
@@ -1606,9 +1532,8 @@ static int ms_erase_block(struct rtsx_chip *chip, u16 phy_blk)
retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE,
SystemParm, 6);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
ms_set_err_code(chip, MS_NO_ERROR);
@@ -1624,21 +1549,18 @@ static int ms_erase_block(struct rtsx_chip *chip, u16 phy_blk)
data[5] = 0;
retval = ms_write_bytes(chip, WRITE_REG, 6, NO_WAIT_INT, data, 6);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
ERASE_RTY:
retval = ms_send_cmd(chip, BLOCK_ERASE, WAIT_INT);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
ms_set_err_code(chip, MS_NO_ERROR);
retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (val & INT_REG_CMDNK) {
if (i < 3) {
@@ -1701,9 +1623,8 @@ static int ms_init_page(struct rtsx_chip *chip, u16 phy_blk, u16 log_blk,
retval = ms_write_extra_data(chip, phy_blk, i,
extra, MS_EXTRA_SIZE);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
}
return STATUS_SUCCESS;
@@ -1723,30 +1644,25 @@ static int ms_copy_page(struct rtsx_chip *chip, u16 old_blk, u16 new_blk,
start_page, end_page);
retval = ms_read_extra_data(chip, new_blk, 0, extra, MS_EXTRA_SIZE);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = ms_read_status_reg(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = rtsx_read_register(chip, PPBUF_BASE2, &val);
- if (retval) {
+ if (retval)
return retval;
- }
if (val & BUF_FULL) {
retval = ms_send_cmd(chip, CLEAR_BUF, WAIT_INT);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (!(val & INT_REG_CED)) {
ms_set_err_code(chip, MS_FLASH_WRITE_ERROR);
@@ -1764,9 +1680,8 @@ static int ms_copy_page(struct rtsx_chip *chip, u16 old_blk, u16 new_blk,
retval = ms_set_rw_reg_addr(chip, OverwriteFlag,
MS_EXTRA_SIZE, SystemParm, 6);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
ms_set_err_code(chip, MS_NO_ERROR);
@@ -1783,20 +1698,17 @@ static int ms_copy_page(struct rtsx_chip *chip, u16 old_blk, u16 new_blk,
retval = ms_write_bytes(chip, WRITE_REG, 6, NO_WAIT_INT,
data, 6);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = ms_send_cmd(chip, BLOCK_READ, WAIT_INT);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
ms_set_err_code(chip, MS_NO_ERROR);
retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (val & INT_REG_CMDNK) {
ms_set_err_code(chip, MS_CMD_NK);
@@ -1817,9 +1729,8 @@ static int ms_copy_page(struct rtsx_chip *chip, u16 old_blk, u16 new_blk,
MS_TM_NORMAL_READ,
READ_PAGE_DATA,
0, NO_WAIT_INT);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (uncorrect_flag) {
ms_set_page_status(log_blk, setPS_NG,
@@ -1854,9 +1765,8 @@ static int ms_copy_page(struct rtsx_chip *chip, u16 old_blk, u16 new_blk,
if (retval == STATUS_SUCCESS)
break;
}
- if (rty_cnt == MS_MAX_RETRY_COUNT) {
+ if (rty_cnt == MS_MAX_RETRY_COUNT)
return STATUS_FAIL;
- }
}
if (!(val & INT_REG_BREQ)) {
@@ -1895,20 +1805,17 @@ static int ms_copy_page(struct rtsx_chip *chip, u16 old_blk, u16 new_blk,
retval = ms_write_bytes(chip, WRITE_REG, (6 + MS_EXTRA_SIZE),
NO_WAIT_INT, data, 16);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
ms_set_err_code(chip, MS_NO_ERROR);
retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (val & INT_REG_CMDNK) {
ms_set_err_code(chip, MS_CMD_NK);
@@ -1926,9 +1833,8 @@ static int ms_copy_page(struct rtsx_chip *chip, u16 old_blk, u16 new_blk,
retval = ms_set_rw_reg_addr(chip, OverwriteFlag,
MS_EXTRA_SIZE, SystemParm,
7);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
ms_set_err_code(chip, MS_NO_ERROR);
@@ -1947,21 +1853,18 @@ static int ms_copy_page(struct rtsx_chip *chip, u16 old_blk, u16 new_blk,
retval = ms_write_bytes(chip, WRITE_REG, 7,
NO_WAIT_INT, data, 8);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
ms_set_err_code(chip, MS_NO_ERROR);
retval = ms_read_bytes(chip, GET_INT, 1,
NO_WAIT_INT, &val, 1);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (val & INT_REG_CMDNK) {
ms_set_err_code(chip, MS_CMD_NK);
@@ -1992,26 +1895,23 @@ static int reset_ms(struct rtsx_chip *chip)
#endif
retval = ms_prepare_reset(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
ms_card->ms_type |= TYPE_MS;
retval = ms_send_cmd(chip, MS_RESET, NO_WAIT_INT);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = ms_read_status_reg(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = rtsx_read_register(chip, PPBUF_BASE2, &val);
- if (retval) {
+ if (retval)
return retval;
- }
+
if (val & WRT_PRTCT)
chip->card_wp |= MS_CARD;
else
@@ -2059,9 +1959,8 @@ RE_SEARCH:
}
retval = ms_read_page(chip, ms_card->boot_block, 0);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
/* Read MS system information as sys_info */
rtsx_init_cmd(chip);
@@ -2070,9 +1969,8 @@ RE_SEARCH:
rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + 0x1A0 + i, 0, 0);
retval = rtsx_send_cmd(chip, MS_CARD, 100);
- if (retval < 0) {
+ if (retval < 0)
return STATUS_FAIL;
- }
ptr = rtsx_get_cmd_data(chip);
memcpy(ms_card->raw_sys_info, ptr, 96);
@@ -2094,9 +1992,8 @@ RE_SEARCH:
rtsx_add_cmd(chip, READ_REG_CMD, MS_4bit_Support, 0, 0);
retval = rtsx_send_cmd(chip, MS_CARD, 100);
- if (retval < 0) {
+ if (retval < 0)
return STATUS_FAIL;
- }
ptr = rtsx_get_cmd_data(chip);
@@ -2169,33 +2066,29 @@ RE_SEARCH:
/* Switch I/F Mode */
if (ptr[15]) {
retval = ms_set_rw_reg_addr(chip, 0, 0, SystemParm, 1);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = rtsx_write_register(chip, PPBUF_BASE2, 0xFF, 0x88);
- if (retval) {
+ if (retval)
return retval;
- }
+
retval = rtsx_write_register(chip, PPBUF_BASE2 + 1, 0xFF, 0);
- if (retval) {
+ if (retval)
return retval;
- }
retval = ms_transfer_tpc(chip, MS_TM_WRITE_BYTES, WRITE_REG, 1,
NO_WAIT_INT);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = rtsx_write_register(chip, MS_CFG,
0x58 | MS_NO_CHECK_INT,
MS_BUS_WIDTH_4 |
PUSH_TIME_ODD |
MS_NO_CHECK_INT);
- if (retval) {
+ if (retval)
return retval;
- }
ms_card->ms_type |= MS_4BIT;
}
@@ -2221,28 +2114,24 @@ static int ms_init_l2p_tbl(struct rtsx_chip *chip)
size = ms_card->segment_cnt * sizeof(struct zone_entry);
ms_card->segment = vzalloc(size);
- if (!ms_card->segment) {
+ if (!ms_card->segment)
return STATUS_FAIL;
- }
retval = ms_read_page(chip, ms_card->boot_block, 1);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
goto INIT_FAIL;
- }
reg_addr = PPBUF_BASE2;
for (i = 0; i < (((ms_card->total_block >> 9) * 10) + 1); i++) {
int block_no;
retval = rtsx_read_register(chip, reg_addr++, &val1);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
goto INIT_FAIL;
- }
retval = rtsx_read_register(chip, reg_addr++, &val2);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
goto INIT_FAIL;
- }
defect_block = ((u16)val1 << 8) | val2;
if (defect_block == 0xFFFF)
@@ -2403,9 +2292,8 @@ static int ms_build_l2p_tbl(struct rtsx_chip *chip, int seg_no)
if (!ms_card->segment) {
retval = ms_init_l2p_tbl(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return retval;
- }
}
if (ms_card->segment[seg_no].build_flag) {
@@ -2423,17 +2311,15 @@ static int ms_build_l2p_tbl(struct rtsx_chip *chip, int seg_no)
if (!segment->l2p_table) {
segment->l2p_table = vmalloc(array_size(table_size, 2));
- if (!segment->l2p_table) {
+ if (!segment->l2p_table)
goto BUILD_FAIL;
- }
}
memset((u8 *)(segment->l2p_table), 0xff, table_size * 2);
if (!segment->free_table) {
segment->free_table = vmalloc(MS_FREE_TABLE_CNT * 2);
- if (!segment->free_table) {
+ if (!segment->free_table)
goto BUILD_FAIL;
- }
}
memset((u8 *)(segment->free_table), 0xff, MS_FREE_TABLE_CNT * 2);
@@ -2558,9 +2444,8 @@ static int ms_build_l2p_tbl(struct rtsx_chip *chip, int seg_no)
return STATUS_SUCCESS;
}
retval = ms_init_page(chip, phy_blk, log_blk, 0, 1);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
goto BUILD_FAIL;
- }
segment->l2p_table[idx] = phy_blk;
if (seg_no == ms_card->segment_cnt - 1) {
@@ -2591,16 +2476,14 @@ static int ms_build_l2p_tbl(struct rtsx_chip *chip, int seg_no)
retval = ms_copy_page(chip, tmp_blk, phy_blk,
log_blk, 0,
ms_card->page_off + 1);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
segment->l2p_table[log_blk] = phy_blk;
retval = ms_set_bad_block(chip, tmp_blk);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
}
}
}
@@ -2626,14 +2509,12 @@ int reset_ms_card(struct rtsx_chip *chip)
memset(ms_card, 0, sizeof(struct ms_info));
retval = enable_card_clock(chip, MS_CARD);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = select_card(chip, MS_CARD);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
ms_card->ms_type = 0;
@@ -2641,27 +2522,24 @@ int reset_ms_card(struct rtsx_chip *chip)
if (retval != STATUS_SUCCESS) {
if (ms_card->check_ms_flow) {
retval = reset_ms(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
} else {
return STATUS_FAIL;
}
}
retval = ms_set_init_para(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (!CHK_MSPRO(ms_card)) {
/* Build table for the last segment,
* to check if L2P table block exists, erasing it
*/
retval = ms_build_l2p_tbl(chip, seg_no);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
}
dev_dbg(rtsx_dev(chip), "ms_card->ms_type = 0x%x\n", ms_card->ms_type);
@@ -2690,9 +2568,8 @@ static int mspro_set_rw_cmd(struct rtsx_chip *chip,
if (retval == STATUS_SUCCESS)
break;
}
- if (i == MS_MAX_RETRY_COUNT) {
+ if (i == MS_MAX_RETRY_COUNT)
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
@@ -2731,9 +2608,8 @@ static inline int ms_auto_tune_clock(struct rtsx_chip *chip)
}
retval = ms_switch_clock(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
@@ -2782,9 +2658,8 @@ static int mspro_rw_multi_sector(struct scsi_cmnd *srb,
}
retval = ms_switch_clock(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (srb->sc_data_direction == DMA_FROM_DEVICE)
trans_mode = MS_TM_AUTO_READ;
@@ -2792,9 +2667,8 @@ static int mspro_rw_multi_sector(struct scsi_cmnd *srb,
trans_mode = MS_TM_AUTO_WRITE;
retval = rtsx_read_register(chip, MS_TRANS_CFG, &val);
- if (retval) {
+ if (retval)
return retval;
- }
if (ms_card->seq_mode) {
if ((ms_card->pre_dir != srb->sc_data_direction) ||
@@ -2808,9 +2682,8 @@ static int mspro_rw_multi_sector(struct scsi_cmnd *srb,
ms_card->total_sec_cnt = 0;
if (val & MS_INT_BREQ) {
retval = ms_send_cmd(chip, PRO_STOP, WAIT_INT);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
rtsx_write_register(chip, RBCTL, RB_FLUSH,
RB_FLUSH);
@@ -3019,14 +2892,12 @@ int mspro_format(struct scsi_cmnd *srb, struct rtsx_chip *chip,
u16 para;
retval = ms_switch_clock(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = ms_set_rw_reg_addr(chip, 0x00, 0x00, Pro_TPCParm, 0x01);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
memset(buf, 0, 2);
switch (short_data_len) {
@@ -3051,9 +2922,8 @@ int mspro_format(struct scsi_cmnd *srb, struct rtsx_chip *chip,
if (retval == STATUS_SUCCESS)
break;
}
- if (i == MS_MAX_RETRY_COUNT) {
+ if (i == MS_MAX_RETRY_COUNT)
return STATUS_FAIL;
- }
if (quick_format)
para = 0x0000;
@@ -3061,18 +2931,15 @@ int mspro_format(struct scsi_cmnd *srb, struct rtsx_chip *chip,
para = 0x0001;
retval = mspro_set_rw_cmd(chip, 0, para, PRO_FORMAT);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = rtsx_read_register(chip, MS_TRANS_CFG, &tmp);
- if (retval) {
+ if (retval)
return retval;
- }
- if (tmp & (MS_INT_CMDNK | MS_INT_ERR)) {
+ if (tmp & (MS_INT_CMDNK | MS_INT_ERR))
return STATUS_FAIL;
- }
if ((tmp & (MS_INT_BREQ | MS_INT_CED)) == MS_INT_BREQ) {
ms_card->pro_under_formatting = 1;
@@ -3113,9 +2980,8 @@ static int ms_read_multiple_pages(struct rtsx_chip *chip, u16 phy_blk,
retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE,
SystemParm, 6);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (CHK_MS4BIT(ms_card))
data[0] = 0x88;
@@ -3134,16 +3000,14 @@ static int ms_read_multiple_pages(struct rtsx_chip *chip, u16 phy_blk,
if (retval == STATUS_SUCCESS)
break;
}
- if (i == MS_MAX_RETRY_COUNT) {
+ if (i == MS_MAX_RETRY_COUNT)
return STATUS_FAIL;
- }
ms_set_err_code(chip, MS_NO_ERROR);
retval = ms_send_cmd(chip, BLOCK_READ, WAIT_INT);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
ptr = buf;
@@ -3156,9 +3020,8 @@ static int ms_read_multiple_pages(struct rtsx_chip *chip, u16 phy_blk,
}
retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (val & INT_REG_CMDNK) {
ms_set_err_code(chip, MS_CMD_NK);
@@ -3197,16 +3060,14 @@ static int ms_read_multiple_pages(struct rtsx_chip *chip, u16 phy_blk,
if (page_addr == (end_page - 1)) {
if (!(val & INT_REG_CED)) {
retval = ms_send_cmd(chip, BLOCK_END, WAIT_INT);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
}
retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT,
&val, 1);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (!(val & INT_REG_CED)) {
ms_set_err_code(chip, MS_FLASH_READ_ERROR);
@@ -3280,9 +3141,8 @@ static int ms_write_multiple_pages(struct rtsx_chip *chip, u16 old_blk,
if (!start_page) {
retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE,
SystemParm, 7);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (CHK_MS4BIT(ms_card))
data[0] = 0x88;
@@ -3299,28 +3159,24 @@ static int ms_write_multiple_pages(struct rtsx_chip *chip, u16 old_blk,
retval = ms_write_bytes(chip, WRITE_REG, 7, NO_WAIT_INT,
data, 8);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
ms_set_err_code(chip, MS_NO_ERROR);
retval = ms_transfer_tpc(chip, MS_TM_READ_BYTES, GET_INT, 1,
NO_WAIT_INT);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
}
retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE,
SystemParm, (6 + MS_EXTRA_SIZE));
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
ms_set_err_code(chip, MS_NO_ERROR);
@@ -3352,23 +3208,20 @@ static int ms_write_multiple_pages(struct rtsx_chip *chip, u16 old_blk,
if (retval == STATUS_SUCCESS)
break;
}
- if (i == MS_MAX_RETRY_COUNT) {
+ if (i == MS_MAX_RETRY_COUNT)
return STATUS_FAIL;
- }
for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT);
if (retval == STATUS_SUCCESS)
break;
}
- if (i == MS_MAX_RETRY_COUNT) {
+ if (i == MS_MAX_RETRY_COUNT)
return STATUS_FAIL;
- }
retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
ptr = buf;
for (page_addr = start_page; page_addr < end_page; page_addr++) {
@@ -3421,16 +3274,14 @@ static int ms_write_multiple_pages(struct rtsx_chip *chip, u16 old_blk,
ms_set_err_code(chip, MS_TO_ERROR);
rtsx_clear_ms_error(chip);
- if (retval == -ETIMEDOUT) {
+ if (retval == -ETIMEDOUT)
return STATUS_TIMEDOUT;
- }
return STATUS_FAIL;
}
retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if ((end_page - start_page) == 1) {
if (!(val & INT_REG_CED)) {
@@ -3442,16 +3293,14 @@ static int ms_write_multiple_pages(struct rtsx_chip *chip, u16 old_blk,
if (!(val & INT_REG_CED)) {
retval = ms_send_cmd(chip, BLOCK_END,
WAIT_INT);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
}
retval = ms_read_bytes(chip, GET_INT, 1,
NO_WAIT_INT, &val, 1);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
}
if ((page_addr == (end_page - 1)) ||
@@ -3479,9 +3328,8 @@ static int ms_finish_write(struct rtsx_chip *chip, u16 old_blk, u16 new_blk,
retval = ms_copy_page(chip, old_blk, new_blk, log_blk,
page_off, ms_card->page_off + 1);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
seg_no = old_blk >> 9;
@@ -3507,9 +3355,8 @@ static int ms_prepare_write(struct rtsx_chip *chip, u16 old_blk, u16 new_blk,
if (start_page) {
retval = ms_copy_page(chip, old_blk, new_blk, log_blk,
0, start_page);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
}
return STATUS_SUCCESS;
@@ -3524,9 +3371,8 @@ int ms_delay_write(struct rtsx_chip *chip)
if (delay_write->delay_write_flag) {
retval = ms_set_init_para(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
delay_write->delay_write_flag = 0;
retval = ms_finish_write(chip,
@@ -3534,9 +3380,8 @@ int ms_delay_write(struct rtsx_chip *chip)
delay_write->new_phyblock,
delay_write->logblock,
delay_write->pageoff);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
}
return STATUS_SUCCESS;
@@ -3850,14 +3695,12 @@ static int ms_poll_int(struct rtsx_chip *chip)
rtsx_add_cmd(chip, CHECK_REG_CMD, MS_TRANS_CFG, MS_INT_CED, MS_INT_CED);
retval = rtsx_send_cmd(chip, MS_CARD, 5000);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
val = *rtsx_get_cmd_data(chip);
- if (val & MS_INT_ERR) {
+ if (val & MS_INT_ERR)
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
@@ -3920,9 +3763,8 @@ static int mg_send_ex_cmd(struct rtsx_chip *chip, u8 cmd, u8 entry_num)
if (retval == STATUS_SUCCESS)
break;
}
- if (i == MS_MAX_RETRY_COUNT) {
+ if (i == MS_MAX_RETRY_COUNT)
return STATUS_FAIL;
- }
if (check_ms_err(chip)) {
rtsx_clear_ms_error(chip);
@@ -3943,9 +3785,8 @@ static int mg_set_tpc_para_sub(struct rtsx_chip *chip, int type,
else
retval = ms_set_rw_reg_addr(chip, 0, 0, Pro_DataCount1, 6);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
buf[0] = 0;
buf[1] = 0;
@@ -3957,9 +3798,8 @@ static int mg_set_tpc_para_sub(struct rtsx_chip *chip, int type,
}
retval = ms_write_bytes(chip, PRO_WRITE_REG, (type == 0) ? 1 : 6,
NO_WAIT_INT, buf, 6);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
@@ -3979,9 +3819,8 @@ int mg_set_leaf_id(struct scsi_cmnd *srb, struct rtsx_chip *chip)
ms_cleanup_work(chip);
retval = ms_switch_clock(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = mg_send_ex_cmd(chip, MG_SET_LID, 0);
if (retval != STATUS_SUCCESS) {
@@ -4019,14 +3858,12 @@ int mg_get_local_EKB(struct scsi_cmnd *srb, struct rtsx_chip *chip)
ms_cleanup_work(chip);
retval = ms_switch_clock(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
buf = kmalloc(1540, GFP_KERNEL);
- if (!buf) {
+ if (!buf)
return STATUS_ERROR;
- }
buf[0] = 0x04;
buf[1] = 0x1A;
@@ -4073,9 +3910,8 @@ int mg_chg(struct scsi_cmnd *srb, struct rtsx_chip *chip)
ms_cleanup_work(chip);
retval = ms_switch_clock(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = mg_send_ex_cmd(chip, MG_GET_ID, 0);
if (retval != STATUS_SUCCESS) {
@@ -4148,9 +3984,8 @@ int mg_get_rsp_chg(struct scsi_cmnd *srb, struct rtsx_chip *chip)
ms_cleanup_work(chip);
retval = ms_switch_clock(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = mg_send_ex_cmd(chip, MG_MAKE_RMS, 0);
if (retval != STATUS_SUCCESS) {
@@ -4204,9 +4039,8 @@ int mg_rsp(struct scsi_cmnd *srb, struct rtsx_chip *chip)
ms_cleanup_work(chip);
retval = ms_switch_clock(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = mg_send_ex_cmd(chip, MG_MAKE_KSE, 0);
if (retval != STATUS_SUCCESS) {
@@ -4251,14 +4085,12 @@ int mg_get_ICV(struct scsi_cmnd *srb, struct rtsx_chip *chip)
ms_cleanup_work(chip);
retval = ms_switch_clock(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
buf = kmalloc(1028, GFP_KERNEL);
- if (!buf) {
+ if (!buf)
return STATUS_ERROR;
- }
buf[0] = 0x04;
buf[1] = 0x02;
@@ -4307,14 +4139,12 @@ int mg_set_ICV(struct scsi_cmnd *srb, struct rtsx_chip *chip)
ms_cleanup_work(chip);
retval = ms_switch_clock(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
buf = kmalloc(1028, GFP_KERNEL);
- if (!buf) {
+ if (!buf)
return STATUS_ERROR;
- }
bufflen = min_t(int, 1028, scsi_bufflen(srb));
rtsx_stor_get_xfer_buf(buf, bufflen, srb);
@@ -4433,32 +4263,28 @@ int ms_power_off_card3v3(struct rtsx_chip *chip)
int retval;
retval = disable_card_clock(chip, MS_CARD);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (chip->asic_code) {
retval = ms_pull_ctl_disable(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
} else {
retval = rtsx_write_register(chip, FPGA_PULL_CTL,
FPGA_MS_PULL_CTL_BIT | 0x20,
FPGA_MS_PULL_CTL_BIT);
- if (retval) {
+ if (retval)
return retval;
- }
}
retval = rtsx_write_register(chip, CARD_OE, MS_OUTPUT_EN, 0);
- if (retval) {
+ if (retval)
return retval;
- }
+
if (!chip->ft2_fast_mode) {
retval = card_power_off(chip, MS_CARD);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
}
return STATUS_SUCCESS;
@@ -4486,9 +4312,8 @@ int release_ms_card(struct rtsx_chip *chip)
#endif
retval = ms_power_off_card3v3(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
diff --git a/drivers/staging/rts5208/rtsx_card.c b/drivers/staging/rts5208/rtsx_card.c
index d26a8e372fce..6dc541e06fb9 100644
--- a/drivers/staging/rts5208/rtsx_card.c
+++ b/drivers/staging/rts5208/rtsx_card.c
@@ -647,9 +647,8 @@ int switch_ssc_clock(struct rtsx_chip *chip, int clk)
dev_dbg(rtsx_dev(chip), "Switch SSC clock to %dMHz (cur_clk = %d)\n",
clk, chip->cur_clk);
- if ((clk <= 2) || (n > max_n)) {
+ if ((clk <= 2) || (n > max_n))
return STATUS_FAIL;
- }
mcu_cnt = (u8)(125 / clk + 3);
if (mcu_cnt > 7)
@@ -688,15 +687,13 @@ int switch_ssc_clock(struct rtsx_chip *chip, int clk)
}
retval = rtsx_send_cmd(chip, 0, WAIT_TIME);
- if (retval < 0) {
+ if (retval < 0)
return STATUS_ERROR;
- }
udelay(10);
retval = rtsx_write_register(chip, CLK_CTL, CLK_LOW_FREQ, 0);
- if (retval) {
+ if (retval)
return retval;
- }
chip->cur_clk = clk;
@@ -790,49 +787,41 @@ int switch_normal_clock(struct rtsx_chip *chip, int clk)
}
retval = rtsx_write_register(chip, CLK_CTL, 0xFF, CLK_LOW_FREQ);
- if (retval) {
+ if (retval)
return retval;
- }
if (sd_vpclk_phase_reset) {
retval = rtsx_write_register(chip, SD_VPCLK0_CTL,
PHASE_NOT_RESET, 0);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, SD_VPCLK1_CTL,
PHASE_NOT_RESET, 0);
- if (retval) {
+ if (retval)
return retval;
- }
}
retval = rtsx_write_register(chip, CLK_DIV, 0xFF,
(div << 4) | mcu_cnt);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, CLK_SEL, 0xFF, sel);
- if (retval) {
+ if (retval)
return retval;
- }
if (sd_vpclk_phase_reset) {
udelay(200);
retval = rtsx_write_register(chip, SD_VPCLK0_CTL,
PHASE_NOT_RESET, PHASE_NOT_RESET);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, SD_VPCLK1_CTL,
PHASE_NOT_RESET, PHASE_NOT_RESET);
- if (retval) {
+ if (retval)
return retval;
- }
udelay(200);
}
retval = rtsx_write_register(chip, CLK_CTL, 0xFF, 0);
- if (retval) {
+ if (retval)
return retval;
- }
chip->cur_clk = clk;
@@ -878,9 +867,8 @@ int enable_card_clock(struct rtsx_chip *chip, u8 card)
clk_en |= MS_CLK_EN;
retval = rtsx_write_register(chip, CARD_CLK_EN, clk_en, clk_en);
- if (retval) {
+ if (retval)
return retval;
- }
return STATUS_SUCCESS;
}
@@ -898,9 +886,8 @@ int disable_card_clock(struct rtsx_chip *chip, u8 card)
clk_en |= MS_CLK_EN;
retval = rtsx_write_register(chip, CARD_CLK_EN, clk_en, 0);
- if (retval) {
+ if (retval)
return retval;
- }
return STATUS_SUCCESS;
}
@@ -924,9 +911,8 @@ int card_power_on(struct rtsx_chip *chip, u8 card)
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PWR_CTL, mask, val1);
retval = rtsx_send_cmd(chip, 0, 100);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
udelay(chip->pmos_pwr_on_interval);
@@ -934,9 +920,8 @@ int card_power_on(struct rtsx_chip *chip, u8 card)
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PWR_CTL, mask, val2);
retval = rtsx_send_cmd(chip, 0, 100);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
@@ -955,9 +940,8 @@ int card_power_off(struct rtsx_chip *chip, u8 card)
}
retval = rtsx_write_register(chip, CARD_PWR_CTL, mask, val);
- if (retval) {
+ if (retval)
return retval;
- }
return STATUS_SUCCESS;
}
@@ -969,9 +953,8 @@ int card_rw(struct scsi_cmnd *srb, struct rtsx_chip *chip,
unsigned int lun = SCSI_LUN(srb);
int i;
- if (!chip->rw_card[lun]) {
+ if (!chip->rw_card[lun])
return STATUS_FAIL;
- }
for (i = 0; i < 3; i++) {
chip->rw_need_retry = 0;
@@ -1009,36 +992,33 @@ int card_share_mode(struct rtsx_chip *chip, int card)
if (CHECK_PID(chip, 0x5208)) {
mask = CARD_SHARE_MASK;
- if (card == SD_CARD) {
+ if (card == SD_CARD)
value = CARD_SHARE_48_SD;
- } else if (card == MS_CARD) {
+ else if (card == MS_CARD)
value = CARD_SHARE_48_MS;
- } else if (card == XD_CARD) {
+ else if (card == XD_CARD)
value = CARD_SHARE_48_XD;
- } else {
+ else
return STATUS_FAIL;
- }
} else if (CHECK_PID(chip, 0x5288)) {
mask = 0x03;
- if (card == SD_CARD) {
+ if (card == SD_CARD)
value = CARD_SHARE_BAROSSA_SD;
- } else if (card == MS_CARD) {
+ else if (card == MS_CARD)
value = CARD_SHARE_BAROSSA_MS;
- } else if (card == XD_CARD) {
+ else if (card == XD_CARD)
value = CARD_SHARE_BAROSSA_XD;
- } else {
+ else
return STATUS_FAIL;
- }
} else {
return STATUS_FAIL;
}
retval = rtsx_write_register(chip, CARD_SHARE_MODE, mask, value);
- if (retval) {
+ if (retval)
return retval;
- }
return STATUS_SUCCESS;
}
@@ -1050,28 +1030,25 @@ int select_card(struct rtsx_chip *chip, int card)
if (chip->cur_card != card) {
u8 mod;
- if (card == SD_CARD) {
+ if (card == SD_CARD)
mod = SD_MOD_SEL;
- } else if (card == MS_CARD) {
+ else if (card == MS_CARD)
mod = MS_MOD_SEL;
- } else if (card == XD_CARD) {
+ else if (card == XD_CARD)
mod = XD_MOD_SEL;
- } else if (card == SPI_CARD) {
+ else if (card == SPI_CARD)
mod = SPI_MOD_SEL;
- } else {
+ else
return STATUS_FAIL;
- }
retval = rtsx_write_register(chip, CARD_SELECT, 0x07, mod);
- if (retval) {
+ if (retval)
return retval;
- }
chip->cur_card = card;
retval = card_share_mode(chip, card);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
}
return STATUS_SUCCESS;
@@ -1120,9 +1097,8 @@ int detect_card_cd(struct rtsx_chip *chip, int card)
}
status = rtsx_readl(chip, RTSX_BIPR);
- if (!(status & card_cd)) {
+ if (!(status & card_cd))
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
diff --git a/drivers/staging/rts5208/rtsx_card.h b/drivers/staging/rts5208/rtsx_card.h
index ac165d8a081c..820b1113ea89 100644
--- a/drivers/staging/rts5208/rtsx_card.h
+++ b/drivers/staging/rts5208/rtsx_card.h
@@ -1062,9 +1062,8 @@ static inline int card_power_off_all(struct rtsx_chip *chip)
int retval;
retval = rtsx_write_register(chip, CARD_PWR_CTL, 0x0F, 0x0F);
- if (retval) {
+ if (retval)
return retval;
- }
return STATUS_SUCCESS;
}
diff --git a/drivers/staging/rts5208/rtsx_chip.c b/drivers/staging/rts5208/rtsx_chip.c
index 6b1234bff09c..94fb35429bf1 100644
--- a/drivers/staging/rts5208/rtsx_chip.c
+++ b/drivers/staging/rts5208/rtsx_chip.c
@@ -116,34 +116,29 @@ static int rtsx_pre_handle_sdio_old(struct rtsx_chip *chip)
0xFF,
MS_INS_PU | SD_WP_PU |
SD_CD_PU | SD_CMD_PU);
- if (retval) {
+ if (retval)
return retval;
- }
} else {
retval = rtsx_write_register(chip, FPGA_PULL_CTL,
0xFF,
FPGA_SD_PULL_CTL_EN);
- if (retval) {
+ if (retval)
return retval;
- }
}
retval = rtsx_write_register(chip, CARD_SHARE_MODE, 0xFF,
CARD_SHARE_48_SD);
- if (retval) {
+ if (retval)
return retval;
- }
/* Enable SDIO internal clock */
retval = rtsx_write_register(chip, 0xFF2C, 0x01, 0x01);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, SDIO_CTRL, 0xFF,
SDIO_BUS_CTRL | SDIO_CD_CTRL);
- if (retval) {
+ if (retval)
return retval;
- }
chip->sd_int = 1;
chip->sd_io = 1;
@@ -164,16 +159,14 @@ static int rtsx_pre_handle_sdio_new(struct rtsx_chip *chip)
if (chip->driver_first_load) {
if (CHECK_PID(chip, 0x5288)) {
retval = rtsx_read_register(chip, 0xFE5A, &tmp);
- if (retval) {
+ if (retval)
return retval;
- }
if (tmp & 0x08)
sw_bypass_sd = true;
} else if (CHECK_PID(chip, 0x5208)) {
retval = rtsx_read_register(chip, 0xFE70, &tmp);
- if (retval) {
+ if (retval)
return retval;
- }
if (tmp & 0x80)
sw_bypass_sd = true;
}
@@ -192,9 +185,8 @@ static int rtsx_pre_handle_sdio_new(struct rtsx_chip *chip)
u8 cd_toggle_mask = 0;
retval = rtsx_read_register(chip, TLPTISTAT, &tmp);
- if (retval) {
+ if (retval)
return retval;
- }
cd_toggle_mask = 0x08;
if (tmp & cd_toggle_mask) {
@@ -202,22 +194,19 @@ static int rtsx_pre_handle_sdio_new(struct rtsx_chip *chip)
if (CHECK_PID(chip, 0x5288)) {
retval = rtsx_write_register(chip, 0xFE5A,
0x08, 0x00);
- if (retval) {
+ if (retval)
return retval;
- }
} else if (CHECK_PID(chip, 0x5208)) {
retval = rtsx_write_register(chip, 0xFE70,
0x80, 0x00);
- if (retval) {
+ if (retval)
return retval;
- }
}
retval = rtsx_write_register(chip, TLPTISTAT, 0xFF,
tmp);
- if (retval) {
+ if (retval)
return retval;
- }
chip->need_reset |= SD_CARD;
} else {
@@ -225,36 +214,31 @@ static int rtsx_pre_handle_sdio_new(struct rtsx_chip *chip)
if (chip->asic_code) {
retval = sd_pull_ctl_enable(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
} else {
retval = rtsx_write_register
(chip, FPGA_PULL_CTL,
FPGA_SD_PULL_CTL_BIT | 0x20,
0);
- if (retval) {
+ if (retval)
return retval;
- }
}
retval = card_share_mode(chip, SD_CARD);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
/* Enable sdio_bus_auto_switch */
if (CHECK_PID(chip, 0x5288)) {
retval = rtsx_write_register(chip, 0xFE5A,
0x08, 0x08);
- if (retval) {
+ if (retval)
return retval;
- }
} else if (CHECK_PID(chip, 0x5208)) {
retval = rtsx_write_register(chip, 0xFE70,
0x80, 0x80);
- if (retval) {
+ if (retval)
return retval;
- }
}
chip->chip_insert_with_sdio = 1;
@@ -262,9 +246,8 @@ static int rtsx_pre_handle_sdio_new(struct rtsx_chip *chip)
}
} else {
retval = rtsx_write_register(chip, TLPTISTAT, 0x08, 0x08);
- if (retval) {
+ if (retval)
return retval;
- }
chip->need_reset |= SD_CARD;
}
@@ -283,32 +266,28 @@ static int rtsx_reset_aspm(struct rtsx_chip *chip)
ret = rtsx_write_cfg_dw(chip, 2, 0xC0, 0xFF,
chip->aspm_l0s_l1_en);
- if (ret != STATUS_SUCCESS) {
+ if (ret != STATUS_SUCCESS)
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
if (CHECK_PID(chip, 0x5208)) {
ret = rtsx_write_register(chip, ASPM_FORCE_CTL, 0xFF, 0x3F);
- if (ret) {
+ if (ret)
return ret;
- }
}
ret = rtsx_write_config_byte(chip, LCTLR, chip->aspm_l0s_l1_en);
- if (ret != STATUS_SUCCESS) {
+ if (ret != STATUS_SUCCESS)
return STATUS_FAIL;
- }
chip->aspm_level[0] = chip->aspm_l0s_l1_en;
if (CHK_SDIO_EXIST(chip)) {
chip->aspm_level[1] = chip->aspm_l0s_l1_en;
ret = rtsx_write_cfg_dw(chip, CHECK_PID(chip, 0x5288) ? 2 : 1,
0xC0, 0xFF, chip->aspm_l0s_l1_en);
- if (ret != STATUS_SUCCESS) {
+ if (ret != STATUS_SUCCESS)
return STATUS_FAIL;
- }
}
chip->aspm_enabled = 1;
@@ -327,9 +306,8 @@ static int rtsx_enable_pcie_intr(struct rtsx_chip *chip)
if (chip->phy_debug_mode) {
ret = rtsx_write_register(chip, CDRESUMECTL, 0x77, 0);
- if (ret) {
+ if (ret)
return ret;
- }
rtsx_disable_bus_int(chip);
} else {
rtsx_enable_bus_int(chip);
@@ -339,27 +317,23 @@ static int rtsx_enable_pcie_intr(struct rtsx_chip *chip)
u16 reg;
ret = rtsx_read_phy_register(chip, 0x00, &reg);
- if (ret != STATUS_SUCCESS) {
+ if (ret != STATUS_SUCCESS)
return STATUS_FAIL;
- }
reg &= 0xFE7F;
reg |= 0x80;
ret = rtsx_write_phy_register(chip, 0x00, reg);
- if (ret != STATUS_SUCCESS) {
+ if (ret != STATUS_SUCCESS)
return STATUS_FAIL;
- }
ret = rtsx_read_phy_register(chip, 0x1C, &reg);
- if (ret != STATUS_SUCCESS) {
+ if (ret != STATUS_SUCCESS)
return STATUS_FAIL;
- }
reg &= 0xFFF7;
ret = rtsx_write_phy_register(chip, 0x1C, reg);
- if (ret != STATUS_SUCCESS) {
+ if (ret != STATUS_SUCCESS)
return STATUS_FAIL;
- }
}
if (chip->driver_first_load && (chip->ic_version < IC_VER_C))
@@ -377,100 +351,85 @@ int rtsx_reset_chip(struct rtsx_chip *chip)
rtsx_disable_aspm(chip);
retval = rtsx_write_register(chip, HOST_SLEEP_STATE, 0x03, 0x00);
- if (retval) {
+ if (retval)
return retval;
- }
/* Disable card clock */
retval = rtsx_write_register(chip, CARD_CLK_EN, 0x1E, 0);
- if (retval) {
+ if (retval)
return retval;
- }
#ifdef SUPPORT_OCP
/* SSC power on, OCD power on */
if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) {
retval = rtsx_write_register(chip, FPDCTL, OC_POWER_DOWN, 0);
- if (retval) {
+ if (retval)
return retval;
- }
} else {
retval = rtsx_write_register(chip, FPDCTL, OC_POWER_DOWN,
MS_OC_POWER_DOWN);
- if (retval) {
+ if (retval)
return retval;
- }
}
retval = rtsx_write_register(chip, OCPPARA1, OCP_TIME_MASK,
OCP_TIME_800);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, OCPPARA2, OCP_THD_MASK,
OCP_THD_244_946);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, OCPCTL, 0xFF,
CARD_OC_INT_EN | CARD_DETECT_EN);
- if (retval) {
+ if (retval)
return retval;
- }
#else
/* OC power down */
retval = rtsx_write_register(chip, FPDCTL, OC_POWER_DOWN,
OC_POWER_DOWN);
- if (retval) {
+ if (retval)
return retval;
- }
#endif
if (!CHECK_PID(chip, 0x5288)) {
retval = rtsx_write_register(chip, CARD_GPIO_DIR, 0xFF, 0x03);
- if (retval) {
+ if (retval)
return retval;
- }
}
/* Turn off LED */
retval = rtsx_write_register(chip, CARD_GPIO, 0xFF, 0x03);
- if (retval) {
+ if (retval)
return retval;
- }
/* Reset delink mode */
retval = rtsx_write_register(chip, CHANGE_LINK_STATE, 0x0A, 0);
- if (retval) {
+ if (retval)
return retval;
- }
/* Card driving select */
retval = rtsx_write_register(chip, CARD_DRIVE_SEL, 0xFF,
chip->card_drive_sel);
- if (retval) {
+ if (retval)
return retval;
- }
#ifdef LED_AUTO_BLINK
retval = rtsx_write_register(chip, CARD_AUTO_BLINK, 0xFF,
LED_BLINK_SPEED | BLINK_EN | LED_GPIO0);
- if (retval) {
+ if (retval)
return retval;
- }
#endif
if (chip->asic_code) {
/* Enable SSC Clock */
retval = rtsx_write_register(chip, SSC_CTL1, 0xFF,
SSC_8X_EN | SSC_SEL_4M);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, SSC_CTL2, 0xFF, 0x12);
- if (retval) {
+ if (retval)
return retval;
- }
}
/*
@@ -482,72 +441,61 @@ int rtsx_reset_chip(struct rtsx_chip *chip)
* bit[4] u_non_sticky_rst_n_dbg rst_value = 0
*/
retval = rtsx_write_register(chip, CHANGE_LINK_STATE, 0x16, 0x10);
- if (retval) {
+ if (retval)
return retval;
- }
/* Enable ASPM */
if (chip->aspm_l0s_l1_en) {
retval = rtsx_reset_aspm(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
} else {
if (chip->asic_code && CHECK_PID(chip, 0x5208)) {
retval = rtsx_write_phy_register(chip, 0x07, 0x0129);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
}
retval = rtsx_write_config_byte(chip, LCTLR,
chip->aspm_l0s_l1_en);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
}
retval = rtsx_write_config_byte(chip, 0x81, 1);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (CHK_SDIO_EXIST(chip)) {
retval = rtsx_write_cfg_dw(chip,
CHECK_PID(chip, 0x5288) ? 2 : 1,
0xC0, 0xFF00, 0x0100);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
}
if (CHECK_PID(chip, 0x5288) && !CHK_SDIO_EXIST(chip)) {
retval = rtsx_write_cfg_dw(chip, 2, 0xC0, 0xFFFF, 0x0103);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = rtsx_write_cfg_dw(chip, 2, 0x84, 0xFF, 0x03);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
}
retval = rtsx_write_register(chip, IRQSTAT0, LINK_RDY_INT,
LINK_RDY_INT);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, PERST_GLITCH_WIDTH, 0xFF, 0x80);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_enable_pcie_intr(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
chip->need_reset = 0;
@@ -569,17 +517,15 @@ int rtsx_reset_chip(struct rtsx_chip *chip)
#else /* HW_AUTO_SWITCH_SD_BUS */
retval = rtsx_pre_handle_sdio_old(chip);
#endif /* HW_AUTO_SWITCH_SD_BUS */
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
} else {
chip->sd_io = 0;
retval = rtsx_write_register(chip, SDIO_CTRL,
SDIO_BUS_CTRL | SDIO_CD_CTRL, 0);
- if (retval) {
+ if (retval)
return retval;
- }
}
nextcard:
@@ -590,78 +536,67 @@ nextcard:
if (chip->int_reg & CARD_EXIST) {
retval = rtsx_write_register(chip, SSC_CTL1, SSC_RSTB,
SSC_RSTB);
- if (retval) {
+ if (retval)
return retval;
- }
}
dev_dbg(rtsx_dev(chip), "In %s, chip->need_reset = 0x%x\n", __func__,
(unsigned int)(chip->need_reset));
retval = rtsx_write_register(chip, RCCTL, 0x01, 0x00);
- if (retval) {
+ if (retval)
return retval;
- }
if (CHECK_PID(chip, 0x5208) || CHECK_PID(chip, 0x5288)) {
/* Turn off main power when entering S3/S4 state */
retval = rtsx_write_register(chip, MAIN_PWR_OFF_CTL, 0x03,
0x03);
- if (retval) {
+ if (retval)
return retval;
- }
}
if (chip->remote_wakeup_en && !chip->auto_delink_en) {
retval = rtsx_write_register(chip, WAKE_SEL_CTL, 0x07, 0x07);
- if (retval) {
+ if (retval)
return retval;
- }
if (chip->aux_pwr_exist) {
retval = rtsx_write_register(chip, PME_FORCE_CTL,
0xFF, 0x33);
- if (retval) {
+ if (retval)
return retval;
- }
}
} else {
retval = rtsx_write_register(chip, WAKE_SEL_CTL, 0x07, 0x04);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, PME_FORCE_CTL, 0xFF, 0x30);
- if (retval) {
+ if (retval)
return retval;
- }
}
if (CHECK_PID(chip, 0x5208) && (chip->ic_version >= IC_VER_D)) {
retval = rtsx_write_register(chip, PETXCFG, 0x1C, 0x14);
- if (retval) {
+ if (retval)
return retval;
- }
}
if (chip->asic_code && CHECK_PID(chip, 0x5208)) {
retval = rtsx_clr_phy_reg_bit(chip, 0x1C, 2);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
}
if (chip->ft2_fast_mode) {
retval = rtsx_write_register(chip, CARD_PWR_CTL, 0xFF,
MS_PARTIAL_POWER_ON |
SD_PARTIAL_POWER_ON);
- if (retval) {
+ if (retval)
return retval;
- }
udelay(chip->pmos_pwr_on_interval);
retval = rtsx_write_register(chip, CARD_PWR_CTL, 0xFF,
MS_POWER_ON | SD_POWER_ON);
- if (retval) {
+ if (retval)
return retval;
- }
wait_timeout(200);
}
@@ -715,20 +650,17 @@ static int rts5208_init(struct rtsx_chip *chip)
u8 val = 0;
retval = rtsx_write_register(chip, CLK_SEL, 0x03, 0x03);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_read_register(chip, CLK_SEL, &val);
- if (retval) {
+ if (retval)
return retval;
- }
chip->asic_code = val == 0 ? 1 : 0;
if (chip->asic_code) {
retval = rtsx_read_phy_register(chip, 0x1C, &reg);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
dev_dbg(rtsx_dev(chip), "Value of phy register 0x1C is 0x%x\n",
reg);
@@ -737,24 +669,21 @@ static int rts5208_init(struct rtsx_chip *chip)
} else {
retval = rtsx_read_register(chip, 0xFE80, &val);
- if (retval) {
+ if (retval)
return retval;
- }
chip->ic_version = val;
chip->phy_debug_mode = 0;
}
retval = rtsx_read_register(chip, PDINFO, &val);
- if (retval) {
+ if (retval)
return retval;
- }
dev_dbg(rtsx_dev(chip), "PDINFO: 0x%x\n", val);
chip->aux_pwr_exist = val & AUX_PWR_DETECTED ? 1 : 0;
retval = rtsx_read_register(chip, 0xFE50, &val);
- if (retval) {
+ if (retval)
return retval;
- }
chip->hw_bypass_sd = val & 0x01 ? 1 : 0;
rtsx_read_config_byte(chip, 0x0E, &val);
@@ -765,9 +694,8 @@ static int rts5208_init(struct rtsx_chip *chip)
if (chip->use_hw_setting) {
retval = rtsx_read_register(chip, CHANGE_LINK_STATE, &val);
- if (retval) {
+ if (retval)
return retval;
- }
chip->auto_delink_en = val & 0x80 ? 1 : 0;
}
@@ -781,42 +709,36 @@ static int rts5288_init(struct rtsx_chip *chip)
u32 lval = 0;
retval = rtsx_write_register(chip, CLK_SEL, 0x03, 0x03);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_read_register(chip, CLK_SEL, &val);
- if (retval) {
+ if (retval)
return retval;
- }
chip->asic_code = val == 0 ? 1 : 0;
chip->ic_version = 0;
chip->phy_debug_mode = 0;
retval = rtsx_read_register(chip, PDINFO, &val);
- if (retval) {
+ if (retval)
return retval;
- }
dev_dbg(rtsx_dev(chip), "PDINFO: 0x%x\n", val);
chip->aux_pwr_exist = val & AUX_PWR_DETECTED ? 1 : 0;
retval = rtsx_read_register(chip, CARD_SHARE_MODE, &val);
- if (retval) {
+ if (retval)
return retval;
- }
dev_dbg(rtsx_dev(chip), "CARD_SHARE_MODE: 0x%x\n", val);
chip->baro_pkg = val & 0x04 ? QFN : LQFP;
retval = rtsx_read_register(chip, 0xFE5A, &val);
- if (retval) {
+ if (retval)
return retval;
- }
chip->hw_bypass_sd = val & 0x10 ? 1 : 0;
retval = rtsx_read_cfg_dw(chip, 0, 0x718, &lval);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
max_func = (u8)((lval >> 29) & 0x07);
dev_dbg(rtsx_dev(chip), "Max function number: %d\n", max_func);
@@ -827,9 +749,8 @@ static int rts5288_init(struct rtsx_chip *chip)
if (chip->use_hw_setting) {
retval = rtsx_read_register(chip, CHANGE_LINK_STATE, &val);
- if (retval) {
+ if (retval)
return retval;
- }
chip->auto_delink_en = val & 0x80 ? 1 : 0;
if (CHECK_BARO_PKG(chip, LQFP))
@@ -905,28 +826,24 @@ int rtsx_init_chip(struct rtsx_chip *chip)
chip->mmc_ddr_tx_phase = 0;
retval = rtsx_write_register(chip, FPDCTL, SSC_POWER_DOWN, 0);
- if (retval) {
+ if (retval)
return retval;
- }
wait_timeout(200);
retval = rtsx_write_register(chip, CLK_DIV, 0x07, 0x07);
- if (retval) {
+ if (retval)
return retval;
- }
dev_dbg(rtsx_dev(chip), "chip->use_hw_setting = %d\n",
chip->use_hw_setting);
if (CHECK_PID(chip, 0x5208)) {
retval = rts5208_init(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
} else if (CHECK_PID(chip, 0x5288)) {
retval = rts5288_init(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
}
if (chip->ss_en == 2)
@@ -973,9 +890,8 @@ int rtsx_init_chip(struct rtsx_chip *chip)
}
retval = rtsx_reset_chip(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
@@ -1403,9 +1319,8 @@ int rtsx_write_register(struct rtsx_chip *chip, u16 addr, u8 mask, u8 data)
for (i = 0; i < MAX_RW_REG_CNT; i++) {
val = rtsx_readl(chip, RTSX_HAIMR);
if ((val & BIT(31)) == 0) {
- if (data != (u8)val) {
+ if (data != (u8)val)
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
@@ -1432,9 +1347,8 @@ int rtsx_read_register(struct rtsx_chip *chip, u16 addr, u8 *data)
break;
}
- if (i >= MAX_RW_REG_CNT) {
+ if (i >= MAX_RW_REG_CNT)
return STATUS_TIMEDOUT;
- }
if (data)
*data = (u8)(val & 0xFF);
@@ -1454,9 +1368,8 @@ int rtsx_write_cfg_dw(struct rtsx_chip *chip, u8 func_no, u16 addr, u32 mask,
retval = rtsx_write_register(chip, CFGDATA0 + i,
0xFF,
(u8)(val & mask & 0xFF));
- if (retval) {
+ if (retval)
return retval;
- }
mode |= (1 << i);
}
mask >>= 8;
@@ -1465,27 +1378,23 @@ int rtsx_write_cfg_dw(struct rtsx_chip *chip, u8 func_no, u16 addr, u32 mask,
if (mode) {
retval = rtsx_write_register(chip, CFGADDR0, 0xFF, (u8)addr);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, CFGADDR1, 0xFF,
(u8)(addr >> 8));
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, CFGRWCTL, 0xFF,
0x80 | mode |
((func_no & 0x03) << 4));
- if (retval) {
+ if (retval)
return retval;
- }
for (i = 0; i < MAX_RW_REG_CNT; i++) {
retval = rtsx_read_register(chip, CFGRWCTL, &tmp);
- if (retval) {
+ if (retval)
return retval;
- }
if ((tmp & 0x80) == 0)
break;
}
@@ -1502,33 +1411,28 @@ int rtsx_read_cfg_dw(struct rtsx_chip *chip, u8 func_no, u16 addr, u32 *val)
u32 data = 0;
retval = rtsx_write_register(chip, CFGADDR0, 0xFF, (u8)addr);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, CFGADDR1, 0xFF, (u8)(addr >> 8));
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, CFGRWCTL, 0xFF,
0x80 | ((func_no & 0x03) << 4));
- if (retval) {
+ if (retval)
return retval;
- }
for (i = 0; i < MAX_RW_REG_CNT; i++) {
retval = rtsx_read_register(chip, CFGRWCTL, &tmp);
- if (retval) {
+ if (retval)
return retval;
- }
if ((tmp & 0x80) == 0)
break;
}
for (i = 0; i < 4; i++) {
retval = rtsx_read_register(chip, CFGDATA0 + i, &tmp);
- if (retval) {
+ if (retval)
return retval;
- }
data |= (u32)tmp << (i * 8);
}
@@ -1547,9 +1451,8 @@ int rtsx_write_cfg_seq(struct rtsx_chip *chip, u8 func, u16 addr, u8 *buf,
int dw_len, i, j;
int retval;
- if (!buf) {
+ if (!buf)
return STATUS_NOMEM;
- }
if ((len + offset) % 4)
dw_len = (len + offset) / 4 + 1;
@@ -1559,9 +1462,8 @@ int rtsx_write_cfg_seq(struct rtsx_chip *chip, u8 func, u16 addr, u8 *buf,
dev_dbg(rtsx_dev(chip), "dw_len = %d\n", dw_len);
data = vzalloc(array_size(dw_len, 4));
- if (!data) {
+ if (!data)
return STATUS_NOMEM;
- }
mask = vzalloc(array_size(dw_len, 4));
if (!mask) {
@@ -1617,9 +1519,8 @@ int rtsx_read_cfg_seq(struct rtsx_chip *chip, u8 func, u16 addr, u8 *buf,
dev_dbg(rtsx_dev(chip), "dw_len = %d\n", dw_len);
data = vmalloc(array_size(dw_len, 4));
- if (!data) {
+ if (!data)
return STATUS_NOMEM;
- }
for (i = 0; i < dw_len; i++) {
retval = rtsx_read_cfg_dw(chip, func, aligned_addr + i * 4,
@@ -1655,36 +1556,30 @@ int rtsx_write_phy_register(struct rtsx_chip *chip, u8 addr, u16 val)
u8 tmp;
retval = rtsx_write_register(chip, PHYDATA0, 0xFF, (u8)val);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, PHYDATA1, 0xFF, (u8)(val >> 8));
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, PHYADDR, 0xFF, addr);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, PHYRWCTL, 0xFF, 0x81);
- if (retval) {
+ if (retval)
return retval;
- }
for (i = 0; i < 100000; i++) {
retval = rtsx_read_register(chip, PHYRWCTL, &tmp);
- if (retval) {
+ if (retval)
return retval;
- }
if (!(tmp & 0x80)) {
finished = true;
break;
}
}
- if (!finished) {
+ if (!finished)
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
@@ -1698,38 +1593,32 @@ int rtsx_read_phy_register(struct rtsx_chip *chip, u8 addr, u16 *val)
u8 tmp;
retval = rtsx_write_register(chip, PHYADDR, 0xFF, addr);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, PHYRWCTL, 0xFF, 0x80);
- if (retval) {
+ if (retval)
return retval;
- }
for (i = 0; i < 100000; i++) {
retval = rtsx_read_register(chip, PHYRWCTL, &tmp);
- if (retval) {
+ if (retval)
return retval;
- }
if (!(tmp & 0x80)) {
finished = true;
break;
}
}
- if (!finished) {
+ if (!finished)
return STATUS_FAIL;
- }
retval = rtsx_read_register(chip, PHYDATA0, &tmp);
- if (retval) {
+ if (retval)
return retval;
- }
data = tmp;
retval = rtsx_read_register(chip, PHYDATA1, &tmp);
- if (retval) {
+ if (retval)
return retval;
- }
data |= (u16)tmp << 8;
if (val)
@@ -1745,28 +1634,24 @@ int rtsx_read_efuse(struct rtsx_chip *chip, u8 addr, u8 *val)
u8 data = 0;
retval = rtsx_write_register(chip, EFUSE_CTRL, 0xFF, 0x80 | addr);
- if (retval) {
+ if (retval)
return retval;
- }
for (i = 0; i < 100; i++) {
retval = rtsx_read_register(chip, EFUSE_CTRL, &data);
- if (retval) {
+ if (retval)
return retval;
- }
if (!(data & 0x80))
break;
udelay(1);
}
- if (data & 0x80) {
+ if (data & 0x80)
return STATUS_TIMEDOUT;
- }
retval = rtsx_read_register(chip, EFUSE_DATA, &data);
- if (retval) {
+ if (retval)
return retval;
- }
if (val)
*val = data;
@@ -1787,28 +1672,24 @@ int rtsx_write_efuse(struct rtsx_chip *chip, u8 addr, u8 val)
dev_dbg(rtsx_dev(chip), "Write 0x%x to 0x%x\n", tmp, addr);
retval = rtsx_write_register(chip, EFUSE_DATA, 0xFF, tmp);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, EFUSE_CTRL, 0xFF,
0xA0 | addr);
- if (retval) {
+ if (retval)
return retval;
- }
for (j = 0; j < 100; j++) {
retval = rtsx_read_register(chip, EFUSE_CTRL, &data);
- if (retval) {
+ if (retval)
return retval;
- }
if (!(data & 0x80))
break;
wait_timeout(3);
}
- if (data & 0x80) {
+ if (data & 0x80)
return STATUS_TIMEDOUT;
- }
wait_timeout(5);
}
@@ -1822,16 +1703,14 @@ int rtsx_clr_phy_reg_bit(struct rtsx_chip *chip, u8 reg, u8 bit)
u16 value;
retval = rtsx_read_phy_register(chip, reg, &value);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (value & (1 << bit)) {
value &= ~(1 << bit);
retval = rtsx_write_phy_register(chip, reg, value);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
}
return STATUS_SUCCESS;
@@ -1843,16 +1722,14 @@ int rtsx_set_phy_reg_bit(struct rtsx_chip *chip, u8 reg, u8 bit)
u16 value;
retval = rtsx_read_phy_register(chip, reg, &value);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if ((value & (1 << bit)) == 0) {
value |= (1 << bit);
retval = rtsx_write_phy_register(chip, reg, value);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
}
return STATUS_SUCCESS;
@@ -2153,9 +2030,8 @@ int rtsx_read_ppbuf(struct rtsx_chip *chip, u8 *buf, int buf_len)
u16 reg_addr;
u8 *ptr;
- if (!buf) {
+ if (!buf)
return STATUS_ERROR;
- }
ptr = buf;
reg_addr = PPBUF_BASE2;
@@ -2166,9 +2042,8 @@ int rtsx_read_ppbuf(struct rtsx_chip *chip, u8 *buf, int buf_len)
rtsx_add_cmd(chip, READ_REG_CMD, reg_addr++, 0, 0);
retval = rtsx_send_cmd(chip, 0, 250);
- if (retval < 0) {
+ if (retval < 0)
return STATUS_FAIL;
- }
memcpy(ptr, rtsx_get_cmd_data(chip), 256);
ptr += 256;
@@ -2181,9 +2056,8 @@ int rtsx_read_ppbuf(struct rtsx_chip *chip, u8 *buf, int buf_len)
rtsx_add_cmd(chip, READ_REG_CMD, reg_addr++, 0, 0);
retval = rtsx_send_cmd(chip, 0, 250);
- if (retval < 0) {
+ if (retval < 0)
return STATUS_FAIL;
- }
}
memcpy(ptr, rtsx_get_cmd_data(chip), buf_len % 256);
@@ -2198,9 +2072,8 @@ int rtsx_write_ppbuf(struct rtsx_chip *chip, u8 *buf, int buf_len)
u16 reg_addr;
u8 *ptr;
- if (!buf) {
+ if (!buf)
return STATUS_ERROR;
- }
ptr = buf;
reg_addr = PPBUF_BASE2;
@@ -2214,9 +2087,8 @@ int rtsx_write_ppbuf(struct rtsx_chip *chip, u8 *buf, int buf_len)
}
retval = rtsx_send_cmd(chip, 0, 250);
- if (retval < 0) {
+ if (retval < 0)
return STATUS_FAIL;
- }
}
if (buf_len % 256) {
@@ -2229,9 +2101,8 @@ int rtsx_write_ppbuf(struct rtsx_chip *chip, u8 *buf, int buf_len)
}
retval = rtsx_send_cmd(chip, 0, 250);
- if (retval < 0) {
+ if (retval < 0)
return STATUS_FAIL;
- }
}
return STATUS_SUCCESS;
@@ -2239,9 +2110,8 @@ int rtsx_write_ppbuf(struct rtsx_chip *chip, u8 *buf, int buf_len)
int rtsx_check_chip_exist(struct rtsx_chip *chip)
{
- if (rtsx_readl(chip, 0) == 0xFFFFFFFF) {
+ if (rtsx_readl(chip, 0) == 0xFFFFFFFF)
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
@@ -2264,9 +2134,8 @@ int rtsx_force_power_on(struct rtsx_chip *chip, u8 ctl)
if (mask) {
retval = rtsx_write_register(chip, FPDCTL, mask, 0);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (CHECK_PID(chip, 0x5288))
wait_timeout(200);
@@ -2294,9 +2163,8 @@ int rtsx_force_power_down(struct rtsx_chip *chip, u8 ctl)
if (mask) {
val = mask;
retval = rtsx_write_register(chip, FPDCTL, mask, val);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
}
return STATUS_SUCCESS;
diff --git a/drivers/staging/rts5208/rtsx_scsi.c b/drivers/staging/rts5208/rtsx_scsi.c
index c9a6d97938f6..9c594a778425 100644
--- a/drivers/staging/rts5208/rtsx_scsi.c
+++ b/drivers/staging/rts5208/rtsx_scsi.c
@@ -507,9 +507,8 @@ static int inquiry(struct scsi_cmnd *srb, struct rtsx_chip *chip)
}
buf = vmalloc(scsi_bufflen(srb));
- if (!buf) {
+ if (!buf)
return TRANSPORT_ERROR;
- }
#ifdef SUPPORT_MAGIC_GATE
if ((chip->mspro_formatter_enable) &&
@@ -637,9 +636,8 @@ static int request_sense(struct scsi_cmnd *srb, struct rtsx_chip *chip)
}
buf = vmalloc(scsi_bufflen(srb));
- if (!buf) {
+ if (!buf)
return TRANSPORT_ERROR;
- }
tmp = (unsigned char *)sense;
memcpy(buf, tmp, scsi_bufflen(srb));
@@ -783,9 +781,8 @@ static int mode_sense(struct scsi_cmnd *srb, struct rtsx_chip *chip)
#endif
buf = kmalloc(data_size, GFP_KERNEL);
- if (!buf) {
+ if (!buf)
return TRANSPORT_ERROR;
- }
page_code = srb->cmnd[2] & 0x3f;
@@ -999,9 +996,8 @@ static int read_format_capacity(struct scsi_cmnd *srb, struct rtsx_chip *chip)
buf_len = (scsi_bufflen(srb) > 12) ? 0x14 : 12;
buf = kmalloc(buf_len, GFP_KERNEL);
- if (!buf) {
+ if (!buf)
return TRANSPORT_ERROR;
- }
buf[i++] = 0;
buf[i++] = 0;
@@ -1076,9 +1072,8 @@ static int read_capacity(struct scsi_cmnd *srb, struct rtsx_chip *chip)
}
buf = kmalloc(8, GFP_KERNEL);
- if (!buf) {
+ if (!buf)
return TRANSPORT_ERROR;
- }
card_size = get_card_size(chip, lun);
buf[0] = (unsigned char)((card_size - 1) >> 24);
@@ -1116,9 +1111,8 @@ static int read_eeprom(struct scsi_cmnd *srb, struct rtsx_chip *chip)
len = ((u16)srb->cmnd[4] << 8) | srb->cmnd[5];
buf = vmalloc(len);
- if (!buf) {
+ if (!buf)
return TRANSPORT_ERROR;
- }
retval = rtsx_force_power_on(chip, SSC_PDCTL);
if (retval != STATUS_SUCCESS) {
@@ -1180,9 +1174,8 @@ static int write_eeprom(struct scsi_cmnd *srb, struct rtsx_chip *chip)
len = (unsigned short)min_t(unsigned int, scsi_bufflen(srb),
len);
buf = vmalloc(len);
- if (!buf) {
+ if (!buf)
return TRANSPORT_ERROR;
- }
rtsx_stor_get_xfer_buf(buf, len, srb);
scsi_set_resid(srb, scsi_bufflen(srb) - len);
@@ -1227,9 +1220,8 @@ static int read_mem(struct scsi_cmnd *srb, struct rtsx_chip *chip)
}
buf = vmalloc(len);
- if (!buf) {
+ if (!buf)
return TRANSPORT_ERROR;
- }
retval = rtsx_force_power_on(chip, SSC_PDCTL);
if (retval != STATUS_SUCCESS) {
@@ -1282,9 +1274,8 @@ static int write_mem(struct scsi_cmnd *srb, struct rtsx_chip *chip)
len = (unsigned short)min_t(unsigned int, scsi_bufflen(srb), len);
buf = vmalloc(len);
- if (!buf) {
+ if (!buf)
return TRANSPORT_ERROR;
- }
rtsx_stor_get_xfer_buf(buf, len, srb);
scsi_set_resid(srb, scsi_bufflen(srb) - len);
@@ -1702,41 +1693,35 @@ static int set_chip_mode(struct scsi_cmnd *srb, struct rtsx_chip *chip)
if (phy_debug_mode) {
chip->phy_debug_mode = 1;
retval = rtsx_write_register(chip, CDRESUMECTL, 0x77, 0);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return TRANSPORT_FAILED;
- }
rtsx_disable_bus_int(chip);
retval = rtsx_read_phy_register(chip, 0x1C, &reg);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return TRANSPORT_FAILED;
- }
reg |= 0x0001;
retval = rtsx_write_phy_register(chip, 0x1C, reg);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return TRANSPORT_FAILED;
- }
} else {
chip->phy_debug_mode = 0;
retval = rtsx_write_register(chip, CDRESUMECTL, 0x77, 0x77);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return TRANSPORT_FAILED;
- }
rtsx_enable_bus_int(chip);
retval = rtsx_read_phy_register(chip, 0x1C, &reg);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return TRANSPORT_FAILED;
- }
reg &= 0xFFFE;
retval = rtsx_write_phy_register(chip, 0x1C, reg);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return TRANSPORT_FAILED;
- }
}
return TRANSPORT_GOOD;
@@ -1840,9 +1825,8 @@ static int read_phy_register(struct scsi_cmnd *srb, struct rtsx_chip *chip)
if (len) {
buf = vmalloc(len);
- if (!buf) {
+ if (!buf)
return TRANSPORT_ERROR;
- }
retval = rtsx_force_power_on(chip, SSC_PDCTL);
if (retval != STATUS_SUCCESS) {
@@ -1903,9 +1887,8 @@ static int write_phy_register(struct scsi_cmnd *srb, struct rtsx_chip *chip)
len);
buf = vmalloc(len);
- if (!buf) {
+ if (!buf)
return TRANSPORT_ERROR;
- }
rtsx_stor_get_xfer_buf(buf, len, srb);
scsi_set_resid(srb, scsi_bufflen(srb) - len);
@@ -1999,9 +1982,8 @@ static int read_eeprom2(struct scsi_cmnd *srb, struct rtsx_chip *chip)
len = ((u16)srb->cmnd[6] << 8) | srb->cmnd[7];
buf = vmalloc(len);
- if (!buf) {
+ if (!buf)
return TRANSPORT_ERROR;
- }
retval = rtsx_force_power_on(chip, SSC_PDCTL);
if (retval != STATUS_SUCCESS) {
@@ -2049,9 +2031,8 @@ static int write_eeprom2(struct scsi_cmnd *srb, struct rtsx_chip *chip)
len = (unsigned short)min_t(unsigned int, scsi_bufflen(srb), len);
buf = vmalloc(len);
- if (!buf) {
+ if (!buf)
return TRANSPORT_ERROR;
- }
rtsx_stor_get_xfer_buf(buf, len, srb);
scsi_set_resid(srb, scsi_bufflen(srb) - len);
@@ -2096,9 +2077,8 @@ static int read_efuse(struct scsi_cmnd *srb, struct rtsx_chip *chip)
len = srb->cmnd[5];
buf = vmalloc(len);
- if (!buf) {
+ if (!buf)
return TRANSPORT_ERROR;
- }
retval = rtsx_force_power_on(chip, SSC_PDCTL);
if (retval != STATUS_SUCCESS) {
@@ -2147,9 +2127,8 @@ static int write_efuse(struct scsi_cmnd *srb, struct rtsx_chip *chip)
len = (u8)min_t(unsigned int, scsi_bufflen(srb), len);
buf = vmalloc(len);
- if (!buf) {
+ if (!buf)
return TRANSPORT_ERROR;
- }
rtsx_stor_get_xfer_buf(buf, len, srb);
scsi_set_resid(srb, scsi_bufflen(srb) - len);
@@ -2215,29 +2194,25 @@ exit:
vfree(buf);
retval = card_power_off(chip, SPI_CARD);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return TRANSPORT_ERROR;
- }
if (chip->asic_code) {
retval = rtsx_write_register(chip, PWR_GATE_CTRL,
LDO3318_PWR_MASK, LDO_OFF);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return TRANSPORT_ERROR;
- }
wait_timeout(600);
retval = rtsx_write_phy_register(chip, 0x08, val);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return TRANSPORT_ERROR;
- }
retval = rtsx_write_register(chip, PWR_GATE_CTRL,
LDO3318_PWR_MASK, LDO_ON);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return TRANSPORT_ERROR;
- }
}
return result;
@@ -2278,9 +2253,8 @@ static int read_cfg_byte(struct scsi_cmnd *srb, struct rtsx_chip *chip)
}
buf = vmalloc(len);
- if (!buf) {
+ if (!buf)
return TRANSPORT_ERROR;
- }
retval = rtsx_read_cfg_seq(chip, func, addr, buf, len);
if (retval != STATUS_SUCCESS) {
@@ -2335,9 +2309,8 @@ static int write_cfg_byte(struct scsi_cmnd *srb, struct rtsx_chip *chip)
len = (unsigned short)min_t(unsigned int, scsi_bufflen(srb), len);
buf = vmalloc(len);
- if (!buf) {
+ if (!buf)
return TRANSPORT_ERROR;
- }
rtsx_stor_get_xfer_buf(buf, len, srb);
scsi_set_resid(srb, scsi_bufflen(srb) - len);
@@ -2657,9 +2630,8 @@ static int spi_vendor_cmd(struct scsi_cmnd *srb, struct rtsx_chip *chip)
rtsx_write_register(chip, CARD_GPIO_DIR, 0x07, gpio_dir);
- if (result != STATUS_SUCCESS) {
+ if (result != STATUS_SUCCESS)
return TRANSPORT_FAILED;
- }
return TRANSPORT_GOOD;
}
@@ -2849,9 +2821,8 @@ static int get_ms_information(struct scsi_cmnd *srb, struct rtsx_chip *chip)
}
buf = kmalloc(buf_len, GFP_KERNEL);
- if (!buf) {
+ if (!buf)
return TRANSPORT_ERROR;
- }
i = 0;
/* GET Memory Stick Media Information Response Header */
@@ -3025,9 +2996,8 @@ static int mg_report_key(struct scsi_cmnd *srb, struct rtsx_chip *chip)
(srb->cmnd[8] == 0x04) &&
(srb->cmnd[9] == 0x1C)) {
retval = mg_get_local_EKB(srb, chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return TRANSPORT_FAILED;
- }
} else {
set_sense_type(chip, lun,
@@ -3041,9 +3011,8 @@ static int mg_report_key(struct scsi_cmnd *srb, struct rtsx_chip *chip)
(srb->cmnd[8] == 0x00) &&
(srb->cmnd[9] == 0x24)) {
retval = mg_get_rsp_chg(srb, chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return TRANSPORT_FAILED;
- }
} else {
set_sense_type(chip, lun,
@@ -3062,9 +3031,8 @@ static int mg_report_key(struct scsi_cmnd *srb, struct rtsx_chip *chip)
(srb->cmnd[4] == 0x00) &&
(srb->cmnd[5] < 32)) {
retval = mg_get_ICV(srb, chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return TRANSPORT_FAILED;
- }
} else {
set_sense_type(chip, lun,
@@ -3131,9 +3099,8 @@ static int mg_send_key(struct scsi_cmnd *srb, struct rtsx_chip *chip)
(srb->cmnd[8] == 0x00) &&
(srb->cmnd[9] == 0x0C)) {
retval = mg_set_leaf_id(srb, chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return TRANSPORT_FAILED;
- }
} else {
set_sense_type(chip, lun,
@@ -3147,9 +3114,8 @@ static int mg_send_key(struct scsi_cmnd *srb, struct rtsx_chip *chip)
(srb->cmnd[8] == 0x00) &&
(srb->cmnd[9] == 0x0C)) {
retval = mg_chg(srb, chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return TRANSPORT_FAILED;
- }
} else {
set_sense_type(chip, lun,
@@ -3163,9 +3129,8 @@ static int mg_send_key(struct scsi_cmnd *srb, struct rtsx_chip *chip)
(srb->cmnd[8] == 0x00) &&
(srb->cmnd[9] == 0x0C)) {
retval = mg_rsp(srb, chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return TRANSPORT_FAILED;
- }
} else {
set_sense_type(chip, lun,
@@ -3184,9 +3149,8 @@ static int mg_send_key(struct scsi_cmnd *srb, struct rtsx_chip *chip)
(srb->cmnd[4] == 0x00) &&
(srb->cmnd[5] < 32)) {
retval = mg_set_ICV(srb, chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return TRANSPORT_FAILED;
- }
} else {
set_sense_type(chip, lun,
diff --git a/drivers/staging/rts5208/sd.c b/drivers/staging/rts5208/sd.c
index e7efa34195c7..ff1a9aa152ce 100644
--- a/drivers/staging/rts5208/sd.c
+++ b/drivers/staging/rts5208/sd.c
@@ -109,9 +109,8 @@ static int sd_check_data0_status(struct rtsx_chip *chip)
u8 stat;
retval = rtsx_read_register(chip, REG_SD_STAT1, &stat);
- if (retval) {
+ if (retval)
return retval;
- }
if (!(stat & SD_DAT0_STATUS)) {
sd_set_err_code(chip, SD_BUSY);
@@ -234,9 +233,8 @@ RTY_SEND_CMD:
if ((cmd_idx != SEND_RELATIVE_ADDR) &&
(cmd_idx != SEND_IF_COND)) {
if (cmd_idx != STOP_TRANSMISSION) {
- if (ptr[1] & 0x80) {
+ if (ptr[1] & 0x80)
return STATUS_FAIL;
- }
}
#ifdef SUPPORT_SD_LOCK
if (ptr[1] & 0x7D) {
@@ -284,9 +282,8 @@ static int sd_read_data(struct rtsx_chip *chip,
if (!buf)
buf_len = 0;
- if (buf_len > 512) {
+ if (buf_len > 512)
return STATUS_FAIL;
- }
rtsx_init_cmd(chip);
@@ -331,9 +328,8 @@ static int sd_read_data(struct rtsx_chip *chip,
if (buf && buf_len) {
retval = rtsx_read_ppbuf(chip, buf, buf_len);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
}
return STATUS_SUCCESS;
@@ -359,9 +355,8 @@ static int sd_write_data(struct rtsx_chip *chip, u8 trans_mode,
if (buf && buf_len) {
retval = rtsx_write_ppbuf(chip, buf, buf_len);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
}
rtsx_init_cmd(chip);
@@ -426,9 +421,8 @@ static int sd_check_csd(struct rtsx_chip *chip, char check_wp)
break;
}
- if (i == 6) {
+ if (i == 6)
return STATUS_FAIL;
- }
memcpy(sd_card->raw_csd, rsp + 1, 15);
@@ -543,9 +537,8 @@ static int sd_set_sample_push_timing(struct rtsx_chip *chip)
}
retval = rtsx_write_register(chip, REG_SD_CFG1, 0x1C, val);
- if (retval) {
+ if (retval)
return retval;
- }
return STATUS_SUCCESS;
}
@@ -606,9 +599,8 @@ static int sd_set_clock_divider(struct rtsx_chip *chip, u8 clk_div)
val = 0x20;
retval = rtsx_write_register(chip, REG_SD_CFG1, mask, val);
- if (retval) {
+ if (retval)
return retval;
- }
return STATUS_SUCCESS;
}
@@ -619,16 +611,14 @@ static int sd_set_init_para(struct rtsx_chip *chip)
int retval;
retval = sd_set_sample_push_timing(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
sd_choose_proper_clock(chip);
retval = switch_clock(chip, sd_card->sd_clock);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
@@ -651,9 +641,8 @@ int sd_select_card(struct rtsx_chip *chip, int select)
}
retval = sd_send_cmd_get_rsp(chip, cmd_idx, addr, cmd_type, NULL, 0);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
@@ -667,9 +656,8 @@ static int sd_update_lock_status(struct rtsx_chip *chip)
retval = sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr,
SD_RSP_TYPE_R1, rsp, 5);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (rsp[1] & 0x02)
sd_card->sd_lock_status |= SD_LOCKED;
@@ -679,9 +667,8 @@ static int sd_update_lock_status(struct rtsx_chip *chip)
dev_dbg(rtsx_dev(chip), "sd_card->sd_lock_status = 0x%x\n",
sd_card->sd_lock_status);
- if (rsp[1] & 0x01) {
+ if (rsp[1] & 0x01)
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
@@ -698,9 +685,8 @@ static int sd_wait_state_data_ready(struct rtsx_chip *chip, u8 state,
retval = sd_send_cmd_get_rsp(chip, SEND_STATUS,
sd_card->sd_addr, SD_RSP_TYPE_R1,
rsp, 5);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (((rsp[3] & 0x1E) == state) &&
((rsp[3] & 0x01) == data_ready))
@@ -719,31 +705,27 @@ static int sd_change_bank_voltage(struct rtsx_chip *chip, u8 voltage)
retval = rtsx_write_phy_register(chip, 0x08,
0x4FC0 |
chip->phy_voltage);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
} else {
retval = rtsx_write_register(chip, SD_PAD_CTL,
SD_IO_USING_1V8, 0);
- if (retval) {
+ if (retval)
return retval;
- }
}
} else if (voltage == SD_IO_1V8) {
if (chip->asic_code) {
retval = rtsx_write_phy_register(chip, 0x08,
0x4C40 |
chip->phy_voltage);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
} else {
retval = rtsx_write_register(chip, SD_PAD_CTL,
SD_IO_USING_1V8,
SD_IO_USING_1V8);
- if (retval) {
+ if (retval)
return retval;
- }
}
} else {
return STATUS_FAIL;
@@ -760,22 +742,19 @@ static int sd_voltage_switch(struct rtsx_chip *chip)
retval = rtsx_write_register(chip, SD_BUS_STAT,
SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP,
SD_CLK_TOGGLE_EN);
- if (retval) {
+ if (retval)
return retval;
- }
retval = sd_send_cmd_get_rsp(chip, VOLTAGE_SWITCH, 0, SD_RSP_TYPE_R1,
NULL, 0);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
udelay(chip->sd_voltage_switch_delay);
retval = rtsx_read_register(chip, SD_BUS_STAT, &stat);
- if (retval) {
+ if (retval)
return retval;
- }
if (stat & (SD_CMD_STATUS | SD_DAT3_STATUS | SD_DAT2_STATUS |
SD_DAT1_STATUS | SD_DAT0_STATUS)) {
return STATUS_FAIL;
@@ -783,27 +762,23 @@ static int sd_voltage_switch(struct rtsx_chip *chip)
retval = rtsx_write_register(chip, SD_BUS_STAT, 0xFF,
SD_CLK_FORCE_STOP);
- if (retval) {
+ if (retval)
return retval;
- }
retval = sd_change_bank_voltage(chip, SD_IO_1V8);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
wait_timeout(50);
retval = rtsx_write_register(chip, SD_BUS_STAT, 0xFF,
SD_CLK_TOGGLE_EN);
- if (retval) {
+ if (retval)
return retval;
- }
wait_timeout(10);
retval = rtsx_read_register(chip, SD_BUS_STAT, &stat);
- if (retval) {
+ if (retval)
return retval;
- }
if ((stat & (SD_CMD_STATUS | SD_DAT3_STATUS | SD_DAT2_STATUS |
SD_DAT1_STATUS | SD_DAT0_STATUS)) !=
(SD_CMD_STATUS | SD_DAT3_STATUS | SD_DAT2_STATUS |
@@ -817,9 +792,8 @@ static int sd_voltage_switch(struct rtsx_chip *chip)
retval = rtsx_write_register(chip, SD_BUS_STAT,
SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0);
- if (retval) {
+ if (retval)
return retval;
- }
return STATUS_SUCCESS;
}
@@ -831,23 +805,19 @@ static int sd_reset_dcm(struct rtsx_chip *chip, u8 tune_dir)
if (tune_dir == TUNE_RX) {
retval = rtsx_write_register(chip, DCM_DRP_CTL, 0xFF,
DCM_RESET | DCM_RX);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, DCM_DRP_CTL, 0xFF, DCM_RX);
- if (retval) {
+ if (retval)
return retval;
- }
} else {
retval = rtsx_write_register(chip, DCM_DRP_CTL, 0xFF,
DCM_RESET | DCM_TX);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, DCM_DRP_CTL, 0xFF, DCM_TX);
- if (retval) {
+ if (retval)
return retval;
- }
}
return STATUS_SUCCESS;
@@ -877,28 +847,23 @@ static int sd_change_phase(struct rtsx_chip *chip, u8 sample_point, u8 tune_dir)
if (chip->asic_code) {
retval = rtsx_write_register(chip, CLK_CTL, CHANGE_CLK,
CHANGE_CLK);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, SD_VP_CTL, 0x1F,
sample_point);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, SD_VPCLK0_CTL,
PHASE_NOT_RESET, 0);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, SD_VPCLK0_CTL,
PHASE_NOT_RESET, PHASE_NOT_RESET);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, CLK_CTL, CHANGE_CLK, 0);
- if (retval) {
+ if (retval)
return retval;
- }
} else {
rtsx_read_register(chip, SD_VP_CTL, &val);
dev_dbg(rtsx_dev(chip), "SD_VP_CTL: 0x%x\n", val);
@@ -909,30 +874,26 @@ static int sd_change_phase(struct rtsx_chip *chip, u8 sample_point, u8 tune_dir)
retval = rtsx_write_register(chip, SD_VP_CTL,
PHASE_CHANGE,
PHASE_CHANGE);
- if (retval) {
+ if (retval)
return retval;
- }
udelay(50);
retval = rtsx_write_register(chip, SD_VP_CTL, 0xFF,
PHASE_CHANGE |
PHASE_NOT_RESET |
sample_point);
- if (retval) {
+ if (retval)
return retval;
- }
} else {
retval = rtsx_write_register(chip, CLK_CTL,
CHANGE_CLK, CHANGE_CLK);
- if (retval) {
+ if (retval)
return retval;
- }
udelay(50);
retval = rtsx_write_register(chip, SD_VP_CTL, 0xFF,
PHASE_NOT_RESET |
sample_point);
- if (retval) {
+ if (retval)
return retval;
- }
}
udelay(100);
@@ -942,45 +903,38 @@ static int sd_change_phase(struct rtsx_chip *chip, u8 sample_point, u8 tune_dir)
rtsx_add_cmd(chip, CHECK_REG_CMD, SD_DCMPS_CTL,
DCMPS_CHANGE_DONE, DCMPS_CHANGE_DONE);
retval = rtsx_send_cmd(chip, SD_CARD, 100);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
goto fail;
- }
val = *rtsx_get_cmd_data(chip);
- if (val & DCMPS_ERROR) {
+ if (val & DCMPS_ERROR)
goto fail;
- }
- if ((val & DCMPS_CURRENT_PHASE) != sample_point) {
+ if ((val & DCMPS_CURRENT_PHASE) != sample_point)
goto fail;
- }
retval = rtsx_write_register(chip, SD_DCMPS_CTL,
DCMPS_CHANGE, 0);
- if (retval) {
+ if (retval)
return retval;
- }
if (ddr_rx) {
retval = rtsx_write_register(chip, SD_VP_CTL,
PHASE_CHANGE, 0);
- if (retval) {
+ if (retval)
return retval;
- }
} else {
retval = rtsx_write_register(chip, CLK_CTL,
CHANGE_CLK, 0);
- if (retval) {
+ if (retval)
return retval;
- }
}
udelay(50);
}
retval = rtsx_write_register(chip, SD_CFG1, SD_ASYNC_FIFO_NOT_RST, 0);
- if (retval) {
+ if (retval)
return retval;
- }
return STATUS_SUCCESS;
@@ -1005,9 +959,8 @@ static int sd_check_spec(struct rtsx_chip *chip, u8 bus_width)
retval = sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr,
SD_RSP_TYPE_R1, NULL, 0);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
cmd[0] = 0x40 | SEND_SCR;
cmd[1] = 0;
@@ -1024,9 +977,8 @@ static int sd_check_spec(struct rtsx_chip *chip, u8 bus_width)
memcpy(sd_card->raw_scr, buf, 8);
- if ((buf[0] & 0x0F) == 0) {
+ if ((buf[0] & 0x0F) == 0)
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
@@ -1207,29 +1159,25 @@ static int sd_check_switch_mode(struct rtsx_chip *chip, u8 mode, u8 func_group,
dev_dbg(rtsx_dev(chip), "Maximum current consumption: %dmA\n",
cc);
- if ((cc == 0) || (cc > 800)) {
+ if ((cc == 0) || (cc > 800))
return STATUS_FAIL;
- }
retval = sd_query_switch_result(chip, func_group,
func_to_switch, buf, 64);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if ((cc > 400) || (func_to_switch > CURRENT_LIMIT_400)) {
retval = rtsx_write_register(chip, OCPPARA2,
SD_OCP_THD_MASK,
chip->sd_800mA_ocp_thd);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, CARD_PWR_CTL,
PMOS_STRG_MASK,
PMOS_STRG_800mA);
- if (retval) {
+ if (retval)
return retval;
- }
}
}
@@ -1278,9 +1226,8 @@ static int sd_check_switch(struct rtsx_chip *chip,
}
retval = rtsx_read_register(chip, SD_STAT1, &stat);
- if (retval) {
+ if (retval)
return retval;
- }
if (stat & SD_CRC16_ERR) {
dev_dbg(rtsx_dev(chip), "SD CRC16 error when switching mode\n");
return STATUS_FAIL;
@@ -1293,9 +1240,8 @@ static int sd_check_switch(struct rtsx_chip *chip,
wait_timeout(20);
}
- if (!switch_good) {
+ if (!switch_good)
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
@@ -1310,9 +1256,8 @@ static int sd_switch_function(struct rtsx_chip *chip, u8 bus_width)
/* Get supported functions */
retval = sd_check_switch_mode(chip, SD_CHECK_MODE, NO_ARGUMENT,
NO_ARGUMENT, bus_width);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
sd_card->func_group1_mask &= ~(sd_card->sd_switch_fail);
@@ -1394,13 +1339,11 @@ static int sd_switch_function(struct rtsx_chip *chip, u8 bus_width)
if (CHK_SD_DDR50(sd_card)) {
retval = rtsx_write_register(chip, SD_PUSH_POINT_CTL, 0x06,
0x04);
- if (retval) {
+ if (retval)
return retval;
- }
retval = sd_set_sample_push_timing(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
}
if (!func_to_switch || (func_to_switch == HS_SUPPORT)) {
@@ -1454,9 +1397,8 @@ static int sd_switch_function(struct rtsx_chip *chip, u8 bus_width)
retval = sd_check_switch(chip, SD_FUNC_GROUP_4, func_to_switch,
bus_width);
if (retval != STATUS_SUCCESS) {
- if (sd_check_err_code(chip, SD_NO_CARD)) {
+ if (sd_check_err_code(chip, SD_NO_CARD))
return STATUS_FAIL;
- }
}
dev_dbg(rtsx_dev(chip), "Switch current limit finished! (%d)\n",
retval);
@@ -1464,9 +1406,8 @@ static int sd_switch_function(struct rtsx_chip *chip, u8 bus_width)
if (CHK_SD_DDR50(sd_card)) {
retval = rtsx_write_register(chip, SD_PUSH_POINT_CTL, 0x06, 0);
- if (retval) {
+ if (retval)
return retval;
- }
}
return STATUS_SUCCESS;
@@ -1480,9 +1421,8 @@ static int sd_wait_data_idle(struct rtsx_chip *chip)
for (i = 0; i < 100; i++) {
retval = rtsx_read_register(chip, SD_DATA_STATE, &val);
- if (retval) {
+ if (retval)
return retval;
- }
if (val & SD_DATA_IDLE) {
retval = STATUS_SUCCESS;
break;
@@ -1500,9 +1440,8 @@ static int sd_sdr_tuning_rx_cmd(struct rtsx_chip *chip, u8 sample_point)
u8 cmd[5];
retval = sd_change_phase(chip, sample_point, TUNE_RX);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
cmd[0] = 0x40 | SEND_TUNING_PATTERN;
cmd[1] = 0;
@@ -1529,17 +1468,15 @@ static int sd_ddr_tuning_rx_cmd(struct rtsx_chip *chip, u8 sample_point)
u8 cmd[5];
retval = sd_change_phase(chip, sample_point, TUNE_RX);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
dev_dbg(rtsx_dev(chip), "sd ddr tuning rx\n");
retval = sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr,
SD_RSP_TYPE_R1, NULL, 0);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
cmd[0] = 0x40 | SD_STATUS;
cmd[1] = 0;
@@ -1573,9 +1510,8 @@ static int mmc_ddr_tuning_rx_cmd(struct rtsx_chip *chip, u8 sample_point)
bus_width = SD_BUS_WIDTH_1;
retval = sd_change_phase(chip, sample_point, TUNE_RX);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
dev_dbg(rtsx_dev(chip), "mmc ddr tuning rx\n");
@@ -1603,15 +1539,13 @@ static int sd_sdr_tuning_tx_cmd(struct rtsx_chip *chip, u8 sample_point)
int retval;
retval = sd_change_phase(chip, sample_point, TUNE_TX);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = rtsx_write_register(chip, SD_CFG3, SD_RSP_80CLK_TIMEOUT_EN,
SD_RSP_80CLK_TIMEOUT_EN);
- if (retval) {
+ if (retval)
return retval;
- }
retval = sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr,
SD_RSP_TYPE_R1, NULL, 0);
@@ -1625,9 +1559,8 @@ static int sd_sdr_tuning_tx_cmd(struct rtsx_chip *chip, u8 sample_point)
retval = rtsx_write_register(chip, SD_CFG3, SD_RSP_80CLK_TIMEOUT_EN,
0);
- if (retval) {
+ if (retval)
return retval;
- }
return STATUS_SUCCESS;
}
@@ -1639,9 +1572,8 @@ static int sd_ddr_tuning_tx_cmd(struct rtsx_chip *chip, u8 sample_point)
u8 cmd[5], bus_width;
retval = sd_change_phase(chip, sample_point, TUNE_TX);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (CHK_SD(sd_card)) {
bus_width = SD_BUS_WIDTH_4;
@@ -1655,15 +1587,13 @@ static int sd_ddr_tuning_tx_cmd(struct rtsx_chip *chip, u8 sample_point)
}
retval = sd_wait_state_data_ready(chip, 0x08, 1, 1000);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = rtsx_write_register(chip, SD_CFG3, SD_RSP_80CLK_TIMEOUT_EN,
SD_RSP_80CLK_TIMEOUT_EN);
- if (retval) {
+ if (retval)
return retval;
- }
cmd[0] = 0x40 | PROGRAM_CSD;
cmd[1] = 0;
@@ -1681,9 +1611,8 @@ static int sd_ddr_tuning_tx_cmd(struct rtsx_chip *chip, u8 sample_point)
retval = rtsx_write_register(chip, SD_CFG3, SD_RSP_80CLK_TIMEOUT_EN,
0);
- if (retval) {
+ if (retval)
return retval;
- }
sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr, SD_RSP_TYPE_R1,
NULL, 0);
@@ -1826,11 +1755,10 @@ static int sd_tuning_rx(struct rtsx_chip *chip)
tuning_cmd = sd_sdr_tuning_rx_cmd;
} else {
- if (CHK_MMC_DDR52(sd_card)) {
+ if (CHK_MMC_DDR52(sd_card))
tuning_cmd = mmc_ddr_tuning_rx_cmd;
- } else {
+ else
return STATUS_FAIL;
- }
}
for (i = 0; i < 3; i++) {
@@ -1855,14 +1783,12 @@ static int sd_tuning_rx(struct rtsx_chip *chip)
dev_dbg(rtsx_dev(chip), "RX phase_map = 0x%08x\n", phase_map);
final_phase = sd_search_final_phase(chip, phase_map, TUNE_RX);
- if (final_phase == 0xFF) {
+ if (final_phase == 0xFF)
return STATUS_FAIL;
- }
retval = sd_change_phase(chip, final_phase, TUNE_RX);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
@@ -1877,9 +1803,8 @@ static int sd_ddr_pre_tuning_tx(struct rtsx_chip *chip)
retval = rtsx_write_register(chip, SD_CFG3, SD_RSP_80CLK_TIMEOUT_EN,
SD_RSP_80CLK_TIMEOUT_EN);
- if (retval) {
+ if (retval)
return retval;
- }
phase_map = 0;
for (i = MAX_PHASE; i >= 0; i--) {
@@ -1904,22 +1829,19 @@ static int sd_ddr_pre_tuning_tx(struct rtsx_chip *chip)
retval = rtsx_write_register(chip, SD_CFG3, SD_RSP_80CLK_TIMEOUT_EN,
0);
- if (retval) {
+ if (retval)
return retval;
- }
dev_dbg(rtsx_dev(chip), "DDR TX pre tune phase_map = 0x%08x\n",
phase_map);
final_phase = sd_search_final_phase(chip, phase_map, TUNE_TX);
- if (final_phase == 0xFF) {
+ if (final_phase == 0xFF)
return STATUS_FAIL;
- }
retval = sd_change_phase(chip, final_phase, TUNE_TX);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
dev_dbg(rtsx_dev(chip), "DDR TX pre tune phase: %d\n",
(int)final_phase);
@@ -1943,11 +1865,10 @@ static int sd_tuning_tx(struct rtsx_chip *chip)
tuning_cmd = sd_sdr_tuning_tx_cmd;
} else {
- if (CHK_MMC_DDR52(sd_card)) {
+ if (CHK_MMC_DDR52(sd_card))
tuning_cmd = sd_ddr_tuning_tx_cmd;
- } else {
+ else
return STATUS_FAIL;
- }
}
for (i = 0; i < 3; i++) {
@@ -1974,14 +1895,12 @@ static int sd_tuning_tx(struct rtsx_chip *chip)
dev_dbg(rtsx_dev(chip), "TX phase_map = 0x%08x\n", phase_map);
final_phase = sd_search_final_phase(chip, phase_map, TUNE_TX);
- if (final_phase == 0xFF) {
+ if (final_phase == 0xFF)
return STATUS_FAIL;
- }
retval = sd_change_phase(chip, final_phase, TUNE_TX);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
@@ -1991,14 +1910,12 @@ static int sd_sdr_tuning(struct rtsx_chip *chip)
int retval;
retval = sd_tuning_tx(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = sd_tuning_rx(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
@@ -2009,27 +1926,23 @@ static int sd_ddr_tuning(struct rtsx_chip *chip)
if (!(chip->sd_ctl & SD_DDR_TX_PHASE_SET_BY_USER)) {
retval = sd_ddr_pre_tuning_tx(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
} else {
retval = sd_change_phase(chip, (u8)chip->sd_ddr_tx_phase,
TUNE_TX);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
}
retval = sd_tuning_rx(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (!(chip->sd_ctl & SD_DDR_TX_PHASE_SET_BY_USER)) {
retval = sd_tuning_tx(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
}
return STATUS_SUCCESS;
@@ -2041,27 +1954,23 @@ static int mmc_ddr_tuning(struct rtsx_chip *chip)
if (!(chip->sd_ctl & MMC_DDR_TX_PHASE_SET_BY_USER)) {
retval = sd_ddr_pre_tuning_tx(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
} else {
retval = sd_change_phase(chip, (u8)chip->mmc_ddr_tx_phase,
TUNE_TX);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
}
retval = sd_tuning_rx(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (!(chip->sd_ctl & MMC_DDR_TX_PHASE_SET_BY_USER)) {
retval = sd_tuning_tx(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
}
return STATUS_SUCCESS;
@@ -2074,14 +1983,12 @@ int sd_switch_clock(struct rtsx_chip *chip)
int re_tuning = 0;
retval = select_card(chip, SD_CARD);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = switch_clock(chip, sd_card->sd_clock);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (re_tuning) {
if (CHK_SD(sd_card)) {
@@ -2094,9 +2001,8 @@ int sd_switch_clock(struct rtsx_chip *chip)
retval = mmc_ddr_tuning(chip);
}
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
}
return STATUS_SUCCESS;
@@ -2126,25 +2032,21 @@ static int sd_prepare_reset(struct rtsx_chip *chip)
chip->sd_io = 0;
retval = sd_set_init_para(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return retval;
- }
retval = rtsx_write_register(chip, REG_SD_CFG1, 0xFF, 0x40);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, CARD_STOP, SD_STOP | SD_CLR_ERR,
SD_STOP | SD_CLR_ERR);
- if (retval) {
+ if (retval)
return retval;
- }
retval = select_card(chip, SD_CARD);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
@@ -2157,60 +2059,50 @@ static int sd_pull_ctl_disable(struct rtsx_chip *chip)
retval = rtsx_write_register(chip, CARD_PULL_CTL1, 0xFF,
XD_D3_PD | SD_D7_PD | SD_CLK_PD |
SD_D5_PD);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, CARD_PULL_CTL2, 0xFF,
SD_D6_PD | SD_D0_PD | SD_D1_PD |
XD_D5_PD);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, CARD_PULL_CTL3, 0xFF,
SD_D4_PD | XD_CE_PD | XD_CLE_PD |
XD_CD_PU);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, CARD_PULL_CTL4, 0xFF,
XD_RDY_PD | SD_D3_PD | SD_D2_PD |
XD_ALE_PD);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, CARD_PULL_CTL5, 0xFF,
MS_INS_PU | SD_WP_PD | SD_CD_PU |
SD_CMD_PD);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, CARD_PULL_CTL6, 0xFF,
MS_D5_PD | MS_D4_PD);
- if (retval) {
+ if (retval)
return retval;
- }
} else if (CHECK_PID(chip, 0x5288)) {
if (CHECK_BARO_PKG(chip, QFN)) {
retval = rtsx_write_register(chip, CARD_PULL_CTL1,
0xFF, 0x55);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, CARD_PULL_CTL2,
0xFF, 0x55);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, CARD_PULL_CTL3,
0xFF, 0x4B);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, CARD_PULL_CTL4,
0xFF, 0x69);
- if (retval) {
+ if (retval)
return retval;
- }
}
}
@@ -2250,9 +2142,8 @@ int sd_pull_ctl_enable(struct rtsx_chip *chip)
}
retval = rtsx_send_cmd(chip, SD_CARD, 100);
- if (retval < 0) {
+ if (retval < 0)
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
@@ -2262,36 +2153,31 @@ static int sd_init_power(struct rtsx_chip *chip)
int retval;
retval = sd_power_off_card3v3(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (!chip->ft2_fast_mode)
wait_timeout(250);
retval = enable_card_clock(chip, SD_CARD);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (chip->asic_code) {
retval = sd_pull_ctl_enable(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
} else {
retval = rtsx_write_register(chip, FPGA_PULL_CTL,
FPGA_SD_PULL_CTL_BIT | 0x20, 0);
- if (retval) {
+ if (retval)
return retval;
- }
}
if (!chip->ft2_fast_mode) {
retval = card_power_on(chip, SD_CARD);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
wait_timeout(260);
@@ -2306,9 +2192,8 @@ static int sd_init_power(struct rtsx_chip *chip)
retval = rtsx_write_register(chip, CARD_OE, SD_OUTPUT_EN,
SD_OUTPUT_EN);
- if (retval) {
+ if (retval)
return retval;
- }
return STATUS_SUCCESS;
}
@@ -2318,14 +2203,12 @@ static int sd_dummy_clock(struct rtsx_chip *chip)
int retval;
retval = rtsx_write_register(chip, REG_SD_CFG3, 0x01, 0x01);
- if (retval) {
+ if (retval)
return retval;
- }
wait_timeout(5);
retval = rtsx_write_register(chip, REG_SD_CFG3, 0x01, 0);
- if (retval) {
+ if (retval)
return retval;
- }
return STATUS_SUCCESS;
}
@@ -2373,9 +2256,8 @@ static int sd_check_wp_state(struct rtsx_chip *chip)
retval = sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr,
SD_RSP_TYPE_R1, NULL, 0);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
cmd[0] = 0x40 | SD_STATUS;
cmd[1] = 0;
@@ -2689,9 +2571,8 @@ SD_UNLOCK_ENTRY:
retval = rtsx_write_register(chip, SD30_DRIVE_SEL, 0x07,
chip->sd30_drive_sel_1v8);
- if (retval) {
+ if (retval)
return retval;
- }
retval = sd_set_init_para(chip);
if (retval != STATUS_SUCCESS)
@@ -2753,14 +2634,12 @@ SD_UNLOCK_ENTRY:
if (sd_card->sd_lock_status & SD_UNLOCK_POW_ON) {
retval = rtsx_write_register(chip, REG_SD_BLOCK_CNT_H, 0xFF,
0x02);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, REG_SD_BLOCK_CNT_L, 0xFF,
0x00);
- if (retval) {
+ if (retval)
return retval;
- }
}
#endif
@@ -2780,9 +2659,8 @@ static int mmc_test_switch_bus(struct rtsx_chip *chip, u8 width)
retval = sd_send_cmd_get_rsp(chip, BUSTEST_W, 0, SD_RSP_TYPE_R1, NULL,
0);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return SWITCH_FAIL;
- }
if (width == MMC_8BIT_BUS) {
buf[0] = 0x55;
@@ -2798,9 +2676,8 @@ static int mmc_test_switch_bus(struct rtsx_chip *chip, u8 width)
}
retval = rtsx_write_register(chip, REG_SD_CFG3, 0x02, 0x02);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return SWITCH_ERR;
- }
retval = sd_write_data(chip, SD_TM_AUTO_WRITE_3, NULL, 0, byte_cnt, 1,
bus_width, buf, len, 100);
@@ -2811,9 +2688,8 @@ static int mmc_test_switch_bus(struct rtsx_chip *chip, u8 width)
}
retval = rtsx_write_register(chip, REG_SD_CFG3, 0x02, 0);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return SWITCH_ERR;
- }
dev_dbg(rtsx_dev(chip), "SD/MMC CMD %d\n", BUSTEST_R);
@@ -2979,9 +2855,8 @@ static int mmc_switch_timing_bus(struct rtsx_chip *chip, bool switch_ddr)
sd_choose_proper_clock(chip);
retval = switch_clock(chip, sd_card->sd_clock);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
/* Test Bus Procedure */
retval = mmc_test_switch_bus(chip, MMC_8BIT_BUS);
@@ -3028,18 +2903,16 @@ static int reset_mmc(struct rtsx_chip *chip)
switch_fail:
retval = sd_prepare_reset(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return retval;
- }
SET_MMC(sd_card);
RTY_MMC_RST:
retval = sd_send_cmd_get_rsp(chip, GO_IDLE_STATE, 0, SD_RSP_TYPE_R0,
NULL, 0);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
do {
if (detect_card_cd(chip, SD_CARD) != STATUS_SUCCESS) {
@@ -3075,9 +2948,8 @@ RTY_MMC_RST:
i++;
} while (!(rsp[1] & 0x80) && (i < 255));
- if (i == 255) {
+ if (i == 255)
return STATUS_FAIL;
- }
if ((rsp[1] & 0x60) == 0x40)
SET_MMC_SECTOR_MODE(sd_card);
@@ -3086,47 +2958,40 @@ RTY_MMC_RST:
retval = sd_send_cmd_get_rsp(chip, ALL_SEND_CID, 0, SD_RSP_TYPE_R2,
NULL, 0);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
sd_card->sd_addr = 0x00100000;
retval = sd_send_cmd_get_rsp(chip, SET_RELATIVE_ADDR, sd_card->sd_addr,
SD_RSP_TYPE_R6, rsp, 5);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = sd_check_csd(chip, 1);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
spec_ver = (sd_card->raw_csd[0] & 0x3C) >> 2;
retval = sd_select_card(chip, 1);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, 0x200, SD_RSP_TYPE_R1,
NULL, 0);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
#ifdef SUPPORT_SD_LOCK
MMC_UNLOCK_ENTRY:
retval = sd_update_lock_status(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
#endif
retval = sd_set_clock_divider(chip, SD_CLK_DIVIDE_0);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
chip->card_bus_width[chip->card2lun[SD_CARD]] = 1;
@@ -3136,30 +3001,26 @@ MMC_UNLOCK_ENTRY:
retval = mmc_switch_timing_bus(chip, switch_ddr);
if (retval != STATUS_SUCCESS) {
retval = sd_init_power(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
sd_card->mmc_dont_switch_bus = 1;
goto switch_fail;
}
}
- if (CHK_MMC_SECTOR_MODE(sd_card) && (sd_card->capacity == 0)) {
+ if (CHK_MMC_SECTOR_MODE(sd_card) && (sd_card->capacity == 0))
return STATUS_FAIL;
- }
if (switch_ddr && CHK_MMC_DDR52(sd_card)) {
retval = sd_set_init_para(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = mmc_ddr_tuning(chip);
if (retval != STATUS_SUCCESS) {
retval = sd_init_power(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
switch_ddr = false;
goto switch_fail;
@@ -3170,9 +3031,8 @@ MMC_UNLOCK_ENTRY:
retval = sd_read_lba0(chip);
if (retval != STATUS_SUCCESS) {
retval = sd_init_power(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
switch_ddr = false;
goto switch_fail;
@@ -3185,14 +3045,12 @@ MMC_UNLOCK_ENTRY:
if (sd_card->sd_lock_status & SD_UNLOCK_POW_ON) {
retval = rtsx_write_register(chip, REG_SD_BLOCK_CNT_H, 0xFF,
0x02);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, REG_SD_BLOCK_CNT_L, 0xFF,
0x00);
- if (retval) {
+ if (retval)
return retval;
- }
}
#endif
@@ -3214,88 +3072,74 @@ int reset_sd_card(struct rtsx_chip *chip)
chip->capacity[chip->card2lun[SD_CARD]] = 0;
retval = enable_card_clock(chip, SD_CARD);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (chip->ignore_sd && CHK_SDIO_EXIST(chip) &&
!CHK_SDIO_IGNORED(chip)) {
if (chip->asic_code) {
retval = sd_pull_ctl_enable(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
} else {
retval = rtsx_write_register(chip, FPGA_PULL_CTL,
FPGA_SD_PULL_CTL_BIT |
0x20, 0);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
}
retval = card_share_mode(chip, SD_CARD);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
chip->sd_io = 1;
return STATUS_FAIL;
}
retval = sd_init_power(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (chip->sd_ctl & RESET_MMC_FIRST) {
retval = reset_mmc(chip);
if (retval != STATUS_SUCCESS) {
- if (sd_check_err_code(chip, SD_NO_CARD)) {
+ if (sd_check_err_code(chip, SD_NO_CARD))
return STATUS_FAIL;
- }
retval = reset_sd(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
}
} else {
retval = reset_sd(chip);
if (retval != STATUS_SUCCESS) {
- if (sd_check_err_code(chip, SD_NO_CARD)) {
+ if (sd_check_err_code(chip, SD_NO_CARD))
return STATUS_FAIL;
- }
- if (chip->sd_io) {
+ if (chip->sd_io)
return STATUS_FAIL;
- }
retval = reset_mmc(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
}
}
retval = sd_set_clock_divider(chip, SD_CLK_DIVIDE_0);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = rtsx_write_register(chip, REG_SD_BYTE_CNT_L, 0xFF, 0);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, REG_SD_BYTE_CNT_H, 0xFF, 2);
- if (retval) {
+ if (retval)
return retval;
- }
chip->capacity[chip->card2lun[SD_CARD]] = sd_card->capacity;
retval = sd_set_init_para(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
dev_dbg(rtsx_dev(chip), "sd_card->sd_type = 0x%x\n", sd_card->sd_type);
@@ -3321,40 +3165,33 @@ static int reset_mmc_only(struct rtsx_chip *chip)
chip->capacity[chip->card2lun[SD_CARD]] = sd_card->capacity = 0;
retval = enable_card_clock(chip, SD_CARD);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = sd_init_power(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = reset_mmc(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = sd_set_clock_divider(chip, SD_CLK_DIVIDE_0);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = rtsx_write_register(chip, REG_SD_BYTE_CNT_L, 0xFF, 0);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, REG_SD_BYTE_CNT_H, 0xFF, 2);
- if (retval) {
+ if (retval)
return retval;
- }
chip->capacity[chip->card2lun[SD_CARD]] = sd_card->capacity;
retval = sd_set_init_para(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
dev_dbg(rtsx_dev(chip), "In %s, sd_card->sd_type = 0x%x\n",
__func__, sd_card->sd_type);
@@ -3380,9 +3217,8 @@ static int wait_data_buf_ready(struct rtsx_chip *chip)
retval = sd_send_cmd_get_rsp(chip, SEND_STATUS,
sd_card->sd_addr, SD_RSP_TYPE_R1,
NULL, 0);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (sd_card->sd_data_buf_ready) {
return sd_send_cmd_get_rsp(chip, SEND_STATUS,
@@ -3460,9 +3296,8 @@ static inline int sd_auto_tune_clock(struct rtsx_chip *chip)
}
retval = sd_switch_clock(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
@@ -3819,9 +3654,8 @@ RTY_SEND_CMD:
if (rsp_type & SD_WAIT_BUSY_END) {
retval = sd_check_data0_status(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return retval;
- }
} else {
sd_set_err_code(chip, SD_TO_ERR);
}
@@ -3859,9 +3693,8 @@ RTY_SEND_CMD:
if ((cmd_idx == SELECT_CARD) || (cmd_idx == APP_CMD) ||
(cmd_idx == SEND_STATUS) || (cmd_idx == STOP_TRANSMISSION)) {
if ((cmd_idx != STOP_TRANSMISSION) && !special_check) {
- if (ptr[1] & 0x80) {
+ if (ptr[1] & 0x80)
return STATUS_FAIL;
- }
}
#ifdef SUPPORT_SD_LOCK
if (ptr[1] & 0x7D) {
@@ -3870,15 +3703,13 @@ RTY_SEND_CMD:
#endif
return STATUS_FAIL;
}
- if (ptr[2] & 0xF8) {
+ if (ptr[2] & 0xF8)
return STATUS_FAIL;
- }
if (cmd_idx == SELECT_CARD) {
if (rsp_type == SD_RSP_TYPE_R2) {
- if ((ptr[3] & 0x1E) != 0x04) {
+ if ((ptr[3] & 0x1E) != 0x04)
return STATUS_FAIL;
- }
}
}
}
@@ -3915,9 +3746,8 @@ int ext_sd_get_rsp(struct rtsx_chip *chip, int len, u8 *rsp, u8 rsp_type)
rtsx_add_cmd(chip, READ_REG_CMD, REG_SD_CMD5, 0xFF, 0);
retval = rtsx_send_cmd(chip, SD_CARD, 100);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (rsp) {
int min_len = (rsp_len < len) ? rsp_len : len;
@@ -4057,9 +3887,8 @@ int sd_execute_no_data(struct scsi_cmnd *srb, struct rtsx_chip *chip)
}
retval = sd_switch_clock(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return TRANSPORT_FAILED;
- }
if (sd_card->pre_cmd_err) {
sd_card->pre_cmd_err = 0;
@@ -4085,39 +3914,34 @@ int sd_execute_no_data(struct scsi_cmnd *srb, struct rtsx_chip *chip)
sd_card->last_rsp_type = rsp_type;
retval = sd_switch_clock(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return TRANSPORT_FAILED;
- }
#ifdef SUPPORT_SD_LOCK
if ((sd_card->sd_lock_status & SD_LOCK_1BIT_MODE) == 0) {
if (CHK_MMC_8BIT(sd_card)) {
retval = rtsx_write_register(chip, REG_SD_CFG1, 0x03,
SD_BUS_WIDTH_8);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return TRANSPORT_FAILED;
- }
} else if (CHK_SD(sd_card) || CHK_MMC_4BIT(sd_card)) {
retval = rtsx_write_register(chip, REG_SD_CFG1, 0x03,
SD_BUS_WIDTH_4);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return TRANSPORT_FAILED;
- }
}
}
#else
retval = rtsx_write_register(chip, REG_SD_CFG1, 0x03, SD_BUS_WIDTH_4);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return TRANSPORT_FAILED;
- }
#endif
if (standby) {
retval = sd_select_card(chip, 0);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
goto sd_execute_cmd_failed;
- }
}
if (acmd) {
@@ -4125,29 +3949,25 @@ int sd_execute_no_data(struct scsi_cmnd *srb, struct rtsx_chip *chip)
sd_card->sd_addr,
SD_RSP_TYPE_R1, NULL, 0,
false);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
goto sd_execute_cmd_failed;
- }
}
retval = ext_sd_send_cmd_get_rsp(chip, cmd_idx, arg, rsp_type,
sd_card->rsp, rsp_len, false);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
goto sd_execute_cmd_failed;
- }
if (standby) {
retval = sd_select_card(chip, 1);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
goto sd_execute_cmd_failed;
- }
}
#ifdef SUPPORT_SD_LOCK
retval = sd_update_lock_status(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
goto sd_execute_cmd_failed;
- }
#endif
scsi_set_resid(srb, 0);
@@ -4186,9 +4006,8 @@ int sd_execute_read_data(struct scsi_cmnd *srb, struct rtsx_chip *chip)
}
retval = sd_switch_clock(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return TRANSPORT_FAILED;
- }
cmd_idx = srb->cmnd[2] & 0x3F;
if (srb->cmnd[1] & 0x04)
@@ -4211,9 +4030,8 @@ int sd_execute_read_data(struct scsi_cmnd *srb, struct rtsx_chip *chip)
sd_card->last_rsp_type = rsp_type;
retval = sd_switch_clock(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return TRANSPORT_FAILED;
- }
#ifdef SUPPORT_SD_LOCK
if ((sd_card->sd_lock_status & SD_LOCK_1BIT_MODE) == 0) {
@@ -4235,16 +4053,14 @@ int sd_execute_read_data(struct scsi_cmnd *srb, struct rtsx_chip *chip)
retval = ext_sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, data_len,
SD_RSP_TYPE_R1, NULL, 0,
false);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
goto sd_execute_read_cmd_failed;
- }
}
if (standby) {
retval = sd_select_card(chip, 0);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
goto sd_execute_read_cmd_failed;
- }
}
if (acmd) {
@@ -4252,9 +4068,8 @@ int sd_execute_read_data(struct scsi_cmnd *srb, struct rtsx_chip *chip)
sd_card->sd_addr,
SD_RSP_TYPE_R1, NULL, 0,
false);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
goto sd_execute_read_cmd_failed;
- }
}
if (data_len <= 512) {
@@ -4273,9 +4088,8 @@ int sd_execute_read_data(struct scsi_cmnd *srb, struct rtsx_chip *chip)
cmd[4] = srb->cmnd[6];
buf = kmalloc(data_len, GFP_KERNEL);
- if (!buf) {
+ if (!buf)
return TRANSPORT_ERROR;
- }
retval = sd_read_data(chip, SD_TM_NORMAL_READ, cmd, 5, byte_cnt,
blk_cnt, bus_width, buf, data_len, 2000);
@@ -4340,43 +4154,37 @@ int sd_execute_read_data(struct scsi_cmnd *srb, struct rtsx_chip *chip)
}
retval = ext_sd_get_rsp(chip, rsp_len, sd_card->rsp, rsp_type);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
goto sd_execute_read_cmd_failed;
- }
if (standby) {
retval = sd_select_card(chip, 1);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
goto sd_execute_read_cmd_failed;
- }
}
if (send_cmd12) {
retval = ext_sd_send_cmd_get_rsp(chip, STOP_TRANSMISSION, 0,
SD_RSP_TYPE_R1b, NULL, 0,
false);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
goto sd_execute_read_cmd_failed;
- }
}
if (data_len < 512) {
retval = ext_sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, 0x200,
SD_RSP_TYPE_R1, NULL, 0,
false);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
goto sd_execute_read_cmd_failed;
- }
retval = rtsx_write_register(chip, SD_BYTE_CNT_H, 0xFF, 0x02);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
goto sd_execute_read_cmd_failed;
- }
retval = rtsx_write_register(chip, SD_BYTE_CNT_L, 0xFF, 0x00);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
goto sd_execute_read_cmd_failed;
- }
}
if ((srb->cmnd[1] & 0x02) || (srb->cmnd[1] & 0x04))
@@ -4390,9 +4198,8 @@ int sd_execute_read_data(struct scsi_cmnd *srb, struct rtsx_chip *chip)
if (retval == STATUS_SUCCESS)
break;
}
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
goto sd_execute_read_cmd_failed;
- }
scsi_set_resid(srb, 0);
return TRANSPORT_GOOD;
@@ -4438,9 +4245,8 @@ int sd_execute_write_data(struct scsi_cmnd *srb, struct rtsx_chip *chip)
}
retval = sd_switch_clock(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return TRANSPORT_FAILED;
- }
cmd_idx = srb->cmnd[2] & 0x3F;
if (srb->cmnd[1] & 0x04)
@@ -4472,48 +4278,42 @@ int sd_execute_write_data(struct scsi_cmnd *srb, struct rtsx_chip *chip)
sd_card->last_rsp_type = rsp_type;
retval = sd_switch_clock(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return TRANSPORT_FAILED;
- }
#ifdef SUPPORT_SD_LOCK
if ((sd_card->sd_lock_status & SD_LOCK_1BIT_MODE) == 0) {
if (CHK_MMC_8BIT(sd_card)) {
retval = rtsx_write_register(chip, REG_SD_CFG1, 0x03,
SD_BUS_WIDTH_8);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return TRANSPORT_FAILED;
- }
} else if (CHK_SD(sd_card) || CHK_MMC_4BIT(sd_card)) {
retval = rtsx_write_register(chip, REG_SD_CFG1, 0x03,
SD_BUS_WIDTH_4);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return TRANSPORT_FAILED;
- }
}
}
#else
retval = rtsx_write_register(chip, REG_SD_CFG1, 0x03, SD_BUS_WIDTH_4);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return TRANSPORT_FAILED;
- }
#endif
if (data_len < 512) {
retval = ext_sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, data_len,
SD_RSP_TYPE_R1, NULL, 0,
false);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
goto sd_execute_write_cmd_failed;
- }
}
if (standby) {
retval = sd_select_card(chip, 0);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
goto sd_execute_write_cmd_failed;
- }
}
if (acmd) {
@@ -4521,25 +4321,22 @@ int sd_execute_write_data(struct scsi_cmnd *srb, struct rtsx_chip *chip)
sd_card->sd_addr,
SD_RSP_TYPE_R1, NULL, 0,
false);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
goto sd_execute_write_cmd_failed;
- }
}
retval = ext_sd_send_cmd_get_rsp(chip, cmd_idx, arg, rsp_type,
sd_card->rsp, rsp_len, false);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
goto sd_execute_write_cmd_failed;
- }
if (data_len <= 512) {
u16 i;
u8 *buf;
buf = kmalloc(data_len, GFP_KERNEL);
- if (!buf) {
+ if (!buf)
return TRANSPORT_ERROR;
- }
rtsx_stor_get_xfer_buf(buf, data_len, srb);
@@ -4663,37 +4460,32 @@ int sd_execute_write_data(struct scsi_cmnd *srb, struct rtsx_chip *chip)
if (standby) {
retval = sd_select_card(chip, 1);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
goto sd_execute_write_cmd_failed;
- }
}
if (send_cmd12) {
retval = ext_sd_send_cmd_get_rsp(chip, STOP_TRANSMISSION, 0,
SD_RSP_TYPE_R1b, NULL, 0,
false);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
goto sd_execute_write_cmd_failed;
- }
}
if (data_len < 512) {
retval = ext_sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, 0x200,
SD_RSP_TYPE_R1, NULL, 0,
false);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
goto sd_execute_write_cmd_failed;
- }
retval = rtsx_write_register(chip, SD_BYTE_CNT_H, 0xFF, 0x02);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
goto sd_execute_write_cmd_failed;
- }
retval = rtsx_write_register(chip, SD_BYTE_CNT_L, 0xFF, 0x00);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
goto sd_execute_write_cmd_failed;
- }
}
if ((srb->cmnd[1] & 0x02) || (srb->cmnd[1] & 0x04))
@@ -4707,9 +4499,8 @@ int sd_execute_write_data(struct scsi_cmnd *srb, struct rtsx_chip *chip)
if (retval == STATUS_SUCCESS)
break;
}
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
goto sd_execute_write_cmd_failed;
- }
#ifdef SUPPORT_SD_LOCK
if (cmd_idx == LOCK_UNLOCK) {
@@ -4888,36 +4679,31 @@ int sd_power_off_card3v3(struct rtsx_chip *chip)
int retval;
retval = disable_card_clock(chip, SD_CARD);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = rtsx_write_register(chip, CARD_OE, SD_OUTPUT_EN, 0);
- if (retval) {
+ if (retval)
return retval;
- }
if (!chip->ft2_fast_mode) {
retval = card_power_off(chip, SD_CARD);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
mdelay(50);
}
if (chip->asic_code) {
retval = sd_pull_ctl_disable(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
} else {
retval = rtsx_write_register(chip, FPGA_PULL_CTL,
FPGA_SD_PULL_CTL_BIT | 0x20,
FPGA_SD_PULL_CTL_BIT);
- if (retval) {
+ if (retval)
return retval;
- }
}
return STATUS_SUCCESS;
@@ -4944,9 +4730,8 @@ int release_sd_card(struct rtsx_chip *chip)
memset(sd_card->raw_scr, 0, 8);
retval = sd_power_off_card3v3(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
diff --git a/drivers/staging/rts5208/spi.c b/drivers/staging/rts5208/spi.c
index 4675668ad977..110cb9093f30 100644
--- a/drivers/staging/rts5208/spi.c
+++ b/drivers/staging/rts5208/spi.c
@@ -41,14 +41,12 @@ static int spi_init(struct rtsx_chip *chip)
retval = rtsx_write_register(chip, SPI_CONTROL, 0xFF,
CS_POLARITY_LOW | DTO_MSB_FIRST
| SPI_MASTER | SPI_MODE0 | SPI_AUTO);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, SPI_TCTL, EDO_TIMING_MASK,
SAMPLE_DELAY_HALF);
- if (retval) {
+ if (retval)
return retval;
- }
return STATUS_SUCCESS;
}
@@ -60,42 +58,35 @@ static int spi_set_init_para(struct rtsx_chip *chip)
retval = rtsx_write_register(chip, SPI_CLK_DIVIDER1, 0xFF,
(u8)(spi->clk_div >> 8));
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, SPI_CLK_DIVIDER0, 0xFF,
(u8)(spi->clk_div));
- if (retval) {
+ if (retval)
return retval;
- }
retval = switch_clock(chip, spi->spi_clock);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = select_card(chip, SPI_CARD);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = rtsx_write_register(chip, CARD_CLK_EN, SPI_CLK_EN,
SPI_CLK_EN);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, CARD_OE, SPI_OUTPUT_EN,
SPI_OUTPUT_EN);
- if (retval) {
+ if (retval)
return retval;
- }
wait_timeout(10);
retval = spi_init(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
@@ -247,47 +238,39 @@ static int spi_init_eeprom(struct rtsx_chip *chip)
clk = CLK_30;
retval = rtsx_write_register(chip, SPI_CLK_DIVIDER1, 0xFF, 0x00);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, SPI_CLK_DIVIDER0, 0xFF, 0x27);
- if (retval) {
+ if (retval)
return retval;
- }
retval = switch_clock(chip, clk);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = select_card(chip, SPI_CARD);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = rtsx_write_register(chip, CARD_CLK_EN, SPI_CLK_EN,
SPI_CLK_EN);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, CARD_OE, SPI_OUTPUT_EN,
SPI_OUTPUT_EN);
- if (retval) {
+ if (retval)
return retval;
- }
wait_timeout(10);
retval = rtsx_write_register(chip, SPI_CONTROL, 0xFF,
CS_POLARITY_HIGH | SPI_EEPROM_AUTO);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, SPI_TCTL, EDO_TIMING_MASK,
SAMPLE_DELAY_HALF);
- if (retval) {
+ if (retval)
return retval;
- }
return STATUS_SUCCESS;
}
@@ -306,9 +289,8 @@ static int spi_eeprom_program_enable(struct rtsx_chip *chip)
SPI_TRANSFER0_END);
retval = rtsx_send_cmd(chip, 0, 100);
- if (retval < 0) {
+ if (retval < 0)
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
@@ -318,14 +300,12 @@ int spi_erase_eeprom_chip(struct rtsx_chip *chip)
int retval;
retval = spi_init_eeprom(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = spi_eeprom_program_enable(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
rtsx_init_cmd(chip);
@@ -339,14 +319,12 @@ int spi_erase_eeprom_chip(struct rtsx_chip *chip)
SPI_TRANSFER0_END);
retval = rtsx_send_cmd(chip, 0, 100);
- if (retval < 0) {
+ if (retval < 0)
return STATUS_FAIL;
- }
retval = rtsx_write_register(chip, CARD_GPIO_DIR, 0x01, 0x01);
- if (retval) {
+ if (retval)
return retval;
- }
return STATUS_SUCCESS;
}
@@ -356,14 +334,12 @@ int spi_erase_eeprom_byte(struct rtsx_chip *chip, u16 addr)
int retval;
retval = spi_init_eeprom(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = spi_eeprom_program_enable(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
rtsx_init_cmd(chip);
@@ -379,14 +355,12 @@ int spi_erase_eeprom_byte(struct rtsx_chip *chip, u16 addr)
SPI_TRANSFER0_END);
retval = rtsx_send_cmd(chip, 0, 100);
- if (retval < 0) {
+ if (retval < 0)
return STATUS_FAIL;
- }
retval = rtsx_write_register(chip, CARD_GPIO_DIR, 0x01, 0x01);
- if (retval) {
+ if (retval)
return retval;
- }
return STATUS_SUCCESS;
}
@@ -397,9 +371,8 @@ int spi_read_eeprom(struct rtsx_chip *chip, u16 addr, u8 *val)
u8 data;
retval = spi_init_eeprom(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
rtsx_init_cmd(chip);
@@ -416,23 +389,20 @@ int spi_read_eeprom(struct rtsx_chip *chip, u16 addr, u8 *val)
SPI_TRANSFER0_END);
retval = rtsx_send_cmd(chip, 0, 100);
- if (retval < 0) {
+ if (retval < 0)
return STATUS_FAIL;
- }
wait_timeout(5);
retval = rtsx_read_register(chip, SPI_DATA, &data);
- if (retval) {
+ if (retval)
return retval;
- }
if (val)
*val = data;
retval = rtsx_write_register(chip, CARD_GPIO_DIR, 0x01, 0x01);
- if (retval) {
+ if (retval)
return retval;
- }
return STATUS_SUCCESS;
}
@@ -442,14 +412,12 @@ int spi_write_eeprom(struct rtsx_chip *chip, u16 addr, u8 val)
int retval;
retval = spi_init_eeprom(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = spi_eeprom_program_enable(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
rtsx_init_cmd(chip);
@@ -466,14 +434,12 @@ int spi_write_eeprom(struct rtsx_chip *chip, u16 addr, u8 val)
SPI_TRANSFER0_END);
retval = rtsx_send_cmd(chip, 0, 100);
- if (retval < 0) {
+ if (retval < 0)
return STATUS_FAIL;
- }
retval = rtsx_write_register(chip, CARD_GPIO_DIR, 0x01, 0x01);
- if (retval) {
+ if (retval)
return retval;
- }
return STATUS_SUCCESS;
}
@@ -577,9 +543,8 @@ int spi_read_flash_id(struct scsi_cmnd *srb, struct rtsx_chip *chip)
if (len) {
buf = kmalloc(len, GFP_KERNEL);
- if (!buf) {
+ if (!buf)
return STATUS_ERROR;
- }
retval = rtsx_read_ppbuf(chip, buf, len);
if (retval != STATUS_SUCCESS) {
@@ -621,9 +586,8 @@ int spi_read_flash(struct scsi_cmnd *srb, struct rtsx_chip *chip)
}
buf = kmalloc(SF_PAGE_LEN, GFP_KERNEL);
- if (!buf) {
+ if (!buf)
return STATUS_ERROR;
- }
while (len) {
u16 pagelen = SF_PAGE_LEN - (u8)addr;
@@ -716,9 +680,8 @@ int spi_write_flash(struct scsi_cmnd *srb, struct rtsx_chip *chip)
if (program_mode == BYTE_PROGRAM) {
buf = kmalloc(4, GFP_KERNEL);
- if (!buf) {
+ if (!buf)
return STATUS_ERROR;
- }
while (len) {
retval = sf_enable_write(chip, SPI_WREN);
@@ -762,14 +725,12 @@ int spi_write_flash(struct scsi_cmnd *srb, struct rtsx_chip *chip)
int first_byte = 1;
retval = sf_enable_write(chip, SPI_WREN);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
buf = kmalloc(4, GFP_KERNEL);
- if (!buf) {
+ if (!buf)
return STATUS_ERROR;
- }
while (len) {
rtsx_stor_access_xfer_buf(buf, 1, srb, &index, &offset,
@@ -808,19 +769,16 @@ int spi_write_flash(struct scsi_cmnd *srb, struct rtsx_chip *chip)
kfree(buf);
retval = sf_disable_write(chip, SPI_WRDI);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = sf_polling_status(chip, 100);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
} else if (program_mode == PAGE_PROGRAM) {
buf = kmalloc(SF_PAGE_LEN, GFP_KERNEL);
- if (!buf) {
+ if (!buf)
return STATUS_NOMEM;
- }
while (len) {
u16 pagelen = SF_PAGE_LEN - (u8)addr;
@@ -893,24 +851,20 @@ int spi_erase_flash(struct scsi_cmnd *srb, struct rtsx_chip *chip)
if (erase_mode == PAGE_ERASE) {
retval = sf_enable_write(chip, SPI_WREN);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = sf_erase(chip, ins, 1, addr);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
} else if (erase_mode == CHIP_ERASE) {
retval = sf_enable_write(chip, SPI_WREN);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = sf_erase(chip, ins, 0, 0);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
} else {
spi_set_err_code(chip, SPI_INVALID_COMMAND);
return STATUS_FAIL;
@@ -935,9 +889,8 @@ int spi_write_flash_status(struct scsi_cmnd *srb, struct rtsx_chip *chip)
}
retval = sf_enable_write(chip, ewsr);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
rtsx_init_cmd(chip);
diff --git a/drivers/staging/rts5208/xd.c b/drivers/staging/rts5208/xd.c
index 261d868a3072..d71f19ceb6fa 100644
--- a/drivers/staging/rts5208/xd.c
+++ b/drivers/staging/rts5208/xd.c
@@ -60,9 +60,8 @@ static int xd_set_init_para(struct rtsx_chip *chip)
xd_card->xd_clock = CLK_50;
retval = switch_clock(chip, xd_card->xd_clock);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
@@ -73,14 +72,12 @@ static int xd_switch_clock(struct rtsx_chip *chip)
int retval;
retval = select_card(chip, XD_CARD);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = switch_clock(chip, xd_card->xd_clock);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
@@ -102,9 +99,8 @@ static int xd_read_id(struct rtsx_chip *chip, u8 id_cmd, u8 *id_buf, u8 buf_len)
rtsx_add_cmd(chip, READ_REG_CMD, (u16)(XD_ADDRESS1 + i), 0, 0);
retval = rtsx_send_cmd(chip, XD_CARD, 20);
- if (retval < 0) {
+ if (retval < 0)
return STATUS_FAIL;
- }
ptr = rtsx_get_cmd_data(chip) + 1;
if (id_buf && buf_len) {
@@ -173,9 +169,8 @@ static int xd_read_redundant(struct rtsx_chip *chip, u32 page_addr,
rtsx_add_cmd(chip, READ_REG_CMD, XD_PARITY, 0, 0);
retval = rtsx_send_cmd(chip, XD_CARD, 500);
- if (retval < 0) {
+ if (retval < 0)
return STATUS_FAIL;
- }
if (buf && buf_len) {
u8 *ptr = rtsx_get_cmd_data(chip) + 1;
@@ -193,9 +188,8 @@ static int xd_read_data_from_ppb(struct rtsx_chip *chip, int offset,
{
int retval, i;
- if (!buf || (buf_len < 0)) {
+ if (!buf || (buf_len < 0))
return STATUS_FAIL;
- }
rtsx_init_cmd(chip);
@@ -220,9 +214,8 @@ static int xd_read_cis(struct rtsx_chip *chip, u32 page_addr, u8 *buf,
int retval;
u8 reg;
- if (!buf || (buf_len < 10)) {
+ if (!buf || (buf_len < 10))
return STATUS_FAIL;
- }
rtsx_init_cmd(chip);
@@ -246,36 +239,31 @@ static int xd_read_cis(struct rtsx_chip *chip, u32 page_addr, u8 *buf,
}
retval = rtsx_read_register(chip, XD_PAGE_STATUS, &reg);
- if (retval) {
+ if (retval)
return retval;
- }
if (reg != XD_GPG) {
rtsx_clear_xd_error(chip);
return STATUS_FAIL;
}
retval = rtsx_read_register(chip, XD_CTL, &reg);
- if (retval) {
+ if (retval)
return retval;
- }
if (!(reg & XD_ECC1_ERROR) || !(reg & XD_ECC1_UNCORRECTABLE)) {
retval = xd_read_data_from_ppb(chip, 0, buf, buf_len);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (reg & XD_ECC1_ERROR) {
u8 ecc_bit, ecc_byte;
retval = rtsx_read_register(chip, XD_ECC_BIT1,
&ecc_bit);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_read_register(chip, XD_ECC_BYTE1,
&ecc_byte);
- if (retval) {
+ if (retval)
return retval;
- }
dev_dbg(rtsx_dev(chip), "ECC_BIT1 = 0x%x, ECC_BYTE1 = 0x%x\n",
ecc_bit, ecc_byte);
@@ -291,22 +279,19 @@ static int xd_read_cis(struct rtsx_chip *chip, u32 page_addr, u8 *buf,
rtsx_clear_xd_error(chip);
retval = xd_read_data_from_ppb(chip, 256, buf, buf_len);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (reg & XD_ECC2_ERROR) {
u8 ecc_bit, ecc_byte;
retval = rtsx_read_register(chip, XD_ECC_BIT2,
&ecc_bit);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_read_register(chip, XD_ECC_BYTE2,
&ecc_byte);
- if (retval) {
+ if (retval)
return retval;
- }
dev_dbg(rtsx_dev(chip), "ECC_BIT2 = 0x%x, ECC_BYTE2 = 0x%x\n",
ecc_bit, ecc_byte);
@@ -404,68 +389,58 @@ static int xd_pull_ctl_disable(struct rtsx_chip *chip)
XD_D2_PD |
XD_D1_PD |
XD_D0_PD);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, CARD_PULL_CTL2, 0xFF,
XD_D7_PD |
XD_D6_PD |
XD_D5_PD |
XD_D4_PD);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, CARD_PULL_CTL3, 0xFF,
XD_WP_PD |
XD_CE_PD |
XD_CLE_PD |
XD_CD_PU);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, CARD_PULL_CTL4, 0xFF,
XD_RDY_PD |
XD_WE_PD |
XD_RE_PD |
XD_ALE_PD);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, CARD_PULL_CTL5, 0xFF,
MS_INS_PU |
SD_WP_PD |
SD_CD_PU |
SD_CMD_PD);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, CARD_PULL_CTL6, 0xFF,
MS_D5_PD | MS_D4_PD);
- if (retval) {
+ if (retval)
return retval;
- }
} else if (CHECK_PID(chip, 0x5288)) {
if (CHECK_BARO_PKG(chip, QFN)) {
retval = rtsx_write_register(chip, CARD_PULL_CTL1,
0xFF, 0x55);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, CARD_PULL_CTL2,
0xFF, 0x55);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, CARD_PULL_CTL3,
0xFF, 0x4B);
- if (retval) {
+ if (retval)
return retval;
- }
retval = rtsx_write_register(chip, CARD_PULL_CTL4,
0xFF, 0x69);
- if (retval) {
+ if (retval)
return retval;
- }
}
}
@@ -479,9 +454,8 @@ static int reset_xd(struct rtsx_chip *chip)
u8 *ptr, id_buf[4], redunt[11];
retval = select_card(chip, XD_CARD);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
rtsx_init_cmd(chip);
@@ -505,15 +479,13 @@ static int reset_xd(struct rtsx_chip *chip)
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_OE, XD_OUTPUT_EN, 0);
retval = rtsx_send_cmd(chip, XD_CARD, 100);
- if (retval < 0) {
+ if (retval < 0)
return STATUS_FAIL;
- }
if (!chip->ft2_fast_mode) {
retval = card_power_off(chip, XD_CARD);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
wait_timeout(250);
@@ -529,14 +501,12 @@ static int reset_xd(struct rtsx_chip *chip)
}
retval = rtsx_send_cmd(chip, XD_CARD, 100);
- if (retval < 0) {
+ if (retval < 0)
return STATUS_FAIL;
- }
retval = card_power_on(chip, XD_CARD);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
#ifdef SUPPORT_OCP
wait_timeout(50);
@@ -565,17 +535,15 @@ static int reset_xd(struct rtsx_chip *chip)
rtsx_add_cmd(chip, WRITE_REG_CMD, XD_CTL, XD_CE_DISEN, XD_CE_DISEN);
retval = rtsx_send_cmd(chip, XD_CARD, 100);
- if (retval < 0) {
+ if (retval < 0)
return STATUS_FAIL;
- }
if (!chip->ft2_fast_mode)
wait_timeout(200);
retval = xd_set_init_para(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
/* Read ID to check if the timing setting is right */
for (i = 0; i < 4; i++) {
@@ -598,9 +566,8 @@ static int reset_xd(struct rtsx_chip *chip)
rtsx_add_cmd(chip, READ_REG_CMD, XD_CTL, 0, 0);
retval = rtsx_send_cmd(chip, XD_CARD, 100);
- if (retval < 0) {
+ if (retval < 0)
return STATUS_FAIL;
- }
ptr = rtsx_get_cmd_data(chip) + 1;
@@ -612,9 +579,8 @@ static int reset_xd(struct rtsx_chip *chip)
continue;
retval = xd_read_id(chip, READ_ID, id_buf, 4);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
dev_dbg(rtsx_dev(chip), "READ_ID: 0x%x 0x%x 0x%x 0x%x\n",
id_buf[0], id_buf[1], id_buf[2], id_buf[3]);
@@ -694,9 +660,8 @@ static int reset_xd(struct rtsx_chip *chip)
/* Confirm timing setting */
for (j = 0; j < 10; j++) {
retval = xd_read_id(chip, READ_ID, id_buf, 4);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (id_buf[1] != xd_card->device_code)
break;
@@ -716,22 +681,19 @@ static int reset_xd(struct rtsx_chip *chip)
}
retval = xd_read_id(chip, READ_xD_ID, id_buf, 4);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
dev_dbg(rtsx_dev(chip), "READ_xD_ID: 0x%x 0x%x 0x%x 0x%x\n",
id_buf[0], id_buf[1], id_buf[2], id_buf[3]);
- if (id_buf[2] != XD_ID_CODE) {
+ if (id_buf[2] != XD_ID_CODE)
return STATUS_FAIL;
- }
/* Search CIS block */
for (i = 0; i < 24; i++) {
u32 page_addr;
- if (detect_card_cd(chip, XD_CARD) != STATUS_SUCCESS) {
+ if (detect_card_cd(chip, XD_CARD) != STATUS_SUCCESS)
return STATUS_FAIL;
- }
page_addr = (u32)i << xd_card->block_shift;
@@ -769,9 +731,8 @@ static int reset_xd(struct rtsx_chip *chip)
page_addr += j;
retval = xd_read_cis(chip, page_addr, buf, 10);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if ((buf[0] == 0x01) && (buf[1] == 0x03) &&
(buf[2] == 0xD9) &&
@@ -841,17 +802,15 @@ static int xd_init_l2p_tbl(struct rtsx_chip *chip)
dev_dbg(rtsx_dev(chip), "%s: zone_cnt = %d\n", __func__,
xd_card->zone_cnt);
- if (xd_card->zone_cnt < 1) {
+ if (xd_card->zone_cnt < 1)
return STATUS_FAIL;
- }
size = xd_card->zone_cnt * sizeof(struct zone_entry);
dev_dbg(rtsx_dev(chip), "Buffer size for l2p table is %d\n", size);
xd_card->zone = vmalloc(size);
- if (!xd_card->zone) {
+ if (!xd_card->zone)
return STATUS_ERROR;
- }
for (i = 0; i < xd_card->zone_cnt; i++) {
xd_card->zone[i].build_flag = 0;
@@ -1028,19 +987,16 @@ int reset_xd_card(struct rtsx_chip *chip)
xd_card->delay_write.delay_write_flag = 0;
retval = enable_card_clock(chip, XD_CARD);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = reset_xd(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = xd_init_l2p_tbl(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
@@ -1054,9 +1010,8 @@ static int xd_mark_bad_block(struct rtsx_chip *chip, u32 phy_blk)
dev_dbg(rtsx_dev(chip), "mark block 0x%x as bad block\n", phy_blk);
- if (phy_blk == BLK_NOT_FOUND) {
+ if (phy_blk == BLK_NOT_FOUND)
return STATUS_FAIL;
- }
rtsx_init_cmd(chip);
@@ -1107,12 +1062,10 @@ static int xd_init_page(struct rtsx_chip *chip, u32 phy_blk,
dev_dbg(rtsx_dev(chip), "Init block 0x%x\n", phy_blk);
- if (start_page > end_page) {
+ if (start_page > end_page)
return STATUS_FAIL;
- }
- if (phy_blk == BLK_NOT_FOUND) {
+ if (phy_blk == BLK_NOT_FOUND)
return STATUS_FAIL;
- }
rtsx_init_cmd(chip);
@@ -1164,13 +1117,11 @@ static int xd_copy_page(struct rtsx_chip *chip, u32 old_blk, u32 new_blk,
dev_dbg(rtsx_dev(chip), "Copy page from block 0x%x to block 0x%x\n",
old_blk, new_blk);
- if (start_page > end_page) {
+ if (start_page > end_page)
return STATUS_FAIL;
- }
- if ((old_blk == BLK_NOT_FOUND) || (new_blk == BLK_NOT_FOUND)) {
+ if ((old_blk == BLK_NOT_FOUND) || (new_blk == BLK_NOT_FOUND))
return STATUS_FAIL;
- }
old_page = (old_blk << xd_card->block_shift) + start_page;
new_page = (new_blk << xd_card->block_shift) + start_page;
@@ -1179,9 +1130,8 @@ static int xd_copy_page(struct rtsx_chip *chip, u32 old_blk, u32 new_blk,
retval = rtsx_write_register(chip, CARD_DATA_SOURCE, 0x01,
PINGPONG_BUFFER);
- if (retval) {
+ if (retval)
return retval;
- }
for (i = start_page; i < end_page; i++) {
if (detect_card_cd(chip, XD_CARD) != STATUS_SUCCESS) {
@@ -1287,9 +1237,8 @@ static int xd_reset_cmd(struct rtsx_chip *chip)
rtsx_add_cmd(chip, READ_REG_CMD, XD_CTL, 0, 0);
retval = rtsx_send_cmd(chip, XD_CARD, 100);
- if (retval < 0) {
+ if (retval < 0)
return STATUS_FAIL;
- }
ptr = rtsx_get_cmd_data(chip) + 1;
if (((ptr[0] & READY_FLAG) == READY_STATE) && (ptr[1] & XD_RDY))
@@ -1305,9 +1254,8 @@ static int xd_erase_block(struct rtsx_chip *chip, u32 phy_blk)
u8 reg = 0, *ptr;
int i, retval;
- if (phy_blk == BLK_NOT_FOUND) {
+ if (phy_blk == BLK_NOT_FOUND)
return STATUS_FAIL;
- }
page_addr = phy_blk << xd_card->block_shift;
@@ -1333,9 +1281,8 @@ static int xd_erase_block(struct rtsx_chip *chip, u32 phy_blk)
}
xd_set_err_code(chip, XD_ERASE_FAIL);
retval = xd_reset_cmd(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
continue;
}
@@ -1382,17 +1329,15 @@ static int xd_build_l2p_tbl(struct rtsx_chip *chip, int zone_no)
if (!zone->l2p_table) {
zone->l2p_table = vmalloc(2000);
- if (!zone->l2p_table) {
+ if (!zone->l2p_table)
goto build_fail;
- }
}
memset((u8 *)(zone->l2p_table), 0xff, 2000);
if (!zone->free_table) {
zone->free_table = vmalloc(XD_FREE_TABLE_CNT * 2);
- if (!zone->free_table) {
+ if (!zone->free_table)
goto build_fail;
- }
}
memset((u8 *)(zone->free_table), 0xff, XD_FREE_TABLE_CNT * 2);
@@ -1555,9 +1500,8 @@ static int xd_send_cmd(struct rtsx_chip *chip, u8 cmd)
XD_TRANSFER_END, XD_TRANSFER_END);
retval = rtsx_send_cmd(chip, XD_CARD, 200);
- if (retval < 0) {
+ if (retval < 0)
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
@@ -1636,17 +1580,15 @@ static int xd_read_multiple_pages(struct rtsx_chip *chip, u32 phy_blk,
fail:
retval = rtsx_read_register(chip, XD_PAGE_STATUS, &reg_val);
- if (retval) {
+ if (retval)
return retval;
- }
if (reg_val != XD_GPG)
xd_set_err_code(chip, XD_PRG_ERROR);
retval = rtsx_read_register(chip, XD_CTL, &reg_val);
- if (retval) {
+ if (retval)
return retval;
- }
if (((reg_val & (XD_ECC1_ERROR | XD_ECC1_UNCORRECTABLE)) ==
(XD_ECC1_ERROR | XD_ECC1_UNCORRECTABLE)) ||
@@ -1702,9 +1644,8 @@ static int xd_finish_write(struct rtsx_chip *chip,
dev_dbg(rtsx_dev(chip), "new_blk = 0x%x, ", new_blk);
dev_dbg(rtsx_dev(chip), "log_blk = 0x%x\n", log_blk);
- if (page_off > xd_card->page_off) {
+ if (page_off > xd_card->page_off)
return STATUS_FAIL;
- }
zone_no = (int)(log_blk / 1000);
log_off = (u16)(log_blk % 1000);
@@ -1760,9 +1701,8 @@ static int xd_prepare_write(struct rtsx_chip *chip,
if (page_off) {
retval = xd_copy_page(chip, old_blk, new_blk, 0, page_off);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
}
return STATUS_SUCCESS;
@@ -1858,9 +1798,8 @@ static int xd_write_multiple_pages(struct rtsx_chip *chip, u32 old_blk,
fail:
retval = rtsx_read_register(chip, XD_DAT, &reg_val);
- if (retval) {
+ if (retval)
return retval;
- }
if (reg_val & PROGRAM_ERROR) {
xd_set_err_code(chip, XD_PRG_ERROR);
xd_mark_bad_block(chip, new_blk);
@@ -1880,9 +1819,8 @@ int xd_delay_write(struct rtsx_chip *chip)
if (delay_write->delay_write_flag) {
dev_dbg(rtsx_dev(chip), "%s\n", __func__);
retval = xd_switch_clock(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
delay_write->delay_write_flag = 0;
retval = xd_finish_write(chip,
@@ -1890,9 +1828,8 @@ int xd_delay_write(struct rtsx_chip *chip)
delay_write->new_phyblock,
delay_write->logblock,
delay_write->pageoff);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
}
return STATUS_SUCCESS;
@@ -1924,9 +1861,8 @@ int xd_rw(struct scsi_cmnd *srb, struct rtsx_chip *chip,
ptr = (u8 *)scsi_sglist(srb);
retval = xd_switch_clock(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
if (detect_card_cd(chip, XD_CARD) != STATUS_SUCCESS) {
chip->card_fail |= XD_CARD;
@@ -2180,34 +2116,29 @@ int xd_power_off_card3v3(struct rtsx_chip *chip)
int retval;
retval = disable_card_clock(chip, XD_CARD);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
retval = rtsx_write_register(chip, CARD_OE, XD_OUTPUT_EN, 0);
- if (retval) {
+ if (retval)
return retval;
- }
if (!chip->ft2_fast_mode) {
retval = card_power_off(chip, XD_CARD);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
wait_timeout(50);
}
if (chip->asic_code) {
retval = xd_pull_ctl_disable(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
} else {
retval = rtsx_write_register(chip, FPGA_PULL_CTL, 0xFF, 0xDF);
- if (retval) {
+ if (retval)
return retval;
- }
}
return STATUS_SUCCESS;
@@ -2227,9 +2158,8 @@ int release_xd_card(struct rtsx_chip *chip)
xd_free_l2p_tbl(chip);
retval = xd_power_off_card3v3(chip);
- if (retval != STATUS_SUCCESS) {
+ if (retval != STATUS_SUCCESS)
return STATUS_FAIL;
- }
return STATUS_SUCCESS;
}
diff --git a/drivers/staging/sm750fb/ddk750_mode.c b/drivers/staging/sm750fb/ddk750_mode.c
index 7e22d093b091..4dac691ad1b1 100644
--- a/drivers/staging/sm750fb/ddk750_mode.c
+++ b/drivers/staging/sm750fb/ddk750_mode.c
@@ -131,7 +131,7 @@ static int programModeRegisters(struct mode_parameter *pModeParam,
DISPLAY_CTRL_HSYNC_PHASE |
DISPLAY_CTRL_TIMING | DISPLAY_CTRL_PLANE);
- poke32(CRT_DISPLAY_CTRL, tmp | reg);
+ poke32(CRT_DISPLAY_CTRL, tmp | reg);
}
} else if (pll->clockType == PRIMARY_PLL) {
diff --git a/drivers/staging/sm750fb/ddk750_sii164.c b/drivers/staging/sm750fb/ddk750_sii164.c
index 4b34a083f5cf..8391f57d5383 100644
--- a/drivers/staging/sm750fb/ddk750_sii164.c
+++ b/drivers/staging/sm750fb/ddk750_sii164.c
@@ -39,8 +39,8 @@ unsigned short sii164GetVendorID(void)
{
unsigned short vendorID;
- vendorID = ((unsigned short) i2cReadReg(SII164_I2C_ADDRESS, SII164_VENDOR_ID_HIGH) << 8) |
- (unsigned short) i2cReadReg(SII164_I2C_ADDRESS, SII164_VENDOR_ID_LOW);
+ vendorID = ((unsigned short)i2cReadReg(SII164_I2C_ADDRESS, SII164_VENDOR_ID_HIGH) << 8) |
+ (unsigned short)i2cReadReg(SII164_I2C_ADDRESS, SII164_VENDOR_ID_LOW);
return vendorID;
}
@@ -56,8 +56,8 @@ unsigned short sii164GetDeviceID(void)
{
unsigned short deviceID;
- deviceID = ((unsigned short) i2cReadReg(SII164_I2C_ADDRESS, SII164_DEVICE_ID_HIGH) << 8) |
- (unsigned short) i2cReadReg(SII164_I2C_ADDRESS, SII164_DEVICE_ID_LOW);
+ deviceID = ((unsigned short)i2cReadReg(SII164_I2C_ADDRESS, SII164_DEVICE_ID_HIGH) << 8) |
+ (unsigned short)i2cReadReg(SII164_I2C_ADDRESS, SII164_DEVICE_ID_LOW);
return deviceID;
}
diff --git a/drivers/staging/sm750fb/sm750.c b/drivers/staging/sm750fb/sm750.c
index 846d7d243994..e9f10c2669ea 100644
--- a/drivers/staging/sm750fb/sm750.c
+++ b/drivers/staging/sm750fb/sm750.c
@@ -1007,7 +1007,7 @@ NO_PARAM:
}
}
-static void sm750fb_frambuffer_release(struct sm750_dev *sm750_dev)
+static void sm750fb_framebuffer_release(struct sm750_dev *sm750_dev)
{
struct fb_info *fb_info;
@@ -1019,7 +1019,7 @@ static void sm750fb_frambuffer_release(struct sm750_dev *sm750_dev)
}
}
-static int sm750fb_frambuffer_alloc(struct sm750_dev *sm750_dev, int fbidx)
+static int sm750fb_framebuffer_alloc(struct sm750_dev *sm750_dev, int fbidx)
{
struct fb_info *fb_info;
struct lynxfb_par *par;
@@ -1137,7 +1137,7 @@ static int lynxfb_pci_probe(struct pci_dev *pdev,
/* allocate frame buffer info structures according to g_dualview */
max_fb = g_dualview ? 2 : 1;
for (fbidx = 0; fbidx < max_fb; fbidx++) {
- err = sm750fb_frambuffer_alloc(sm750_dev, fbidx);
+ err = sm750fb_framebuffer_alloc(sm750_dev, fbidx);
if (err)
goto release_fb;
}
@@ -1145,7 +1145,7 @@ static int lynxfb_pci_probe(struct pci_dev *pdev,
return 0;
release_fb:
- sm750fb_frambuffer_release(sm750_dev);
+ sm750fb_framebuffer_release(sm750_dev);
return err;
}
@@ -1155,7 +1155,7 @@ static void lynxfb_pci_remove(struct pci_dev *pdev)
sm750_dev = pci_get_drvdata(pdev);
- sm750fb_frambuffer_release(sm750_dev);
+ sm750fb_framebuffer_release(sm750_dev);
arch_phys_wc_del(sm750_dev->mtrr.vram);
iounmap(sm750_dev->pvReg);
diff --git a/drivers/staging/speakup/spk_ttyio.c b/drivers/staging/speakup/spk_ttyio.c
index eac63aab8162..979e3ae249c1 100644
--- a/drivers/staging/speakup/spk_ttyio.c
+++ b/drivers/staging/speakup/spk_ttyio.c
@@ -227,9 +227,9 @@ static int spk_ttyio_out_unicode(struct spk_synth *in_synth, u16 ch)
{
int ret;
- if (ch < 0x80)
+ if (ch < 0x80) {
ret = spk_ttyio_out(in_synth, ch);
- else if (ch < 0x800) {
+ } else if (ch < 0x800) {
ret = spk_ttyio_out(in_synth, 0xc0 | (ch >> 6));
ret &= spk_ttyio_out(in_synth, 0x80 | (ch & 0x3f));
} else {
diff --git a/drivers/staging/vboxvideo/TODO b/drivers/staging/vboxvideo/TODO
index 468eea856ca6..2e0f99c3f10c 100644
--- a/drivers/staging/vboxvideo/TODO
+++ b/drivers/staging/vboxvideo/TODO
@@ -1,5 +1,4 @@
TODO:
--Move the driver over to the atomic API
-Get a full review from the drm-maintainers on dri-devel done on this driver
-Extend this TODO with the results of that review
diff --git a/drivers/staging/vboxvideo/vbox_drv.c b/drivers/staging/vboxvideo/vbox_drv.c
index 69cc508af1bc..257030460fb6 100644
--- a/drivers/staging/vboxvideo/vbox_drv.c
+++ b/drivers/staging/vboxvideo/vbox_drv.c
@@ -49,139 +49,140 @@ static const struct pci_device_id pciidlist[] = {
};
MODULE_DEVICE_TABLE(pci, pciidlist);
+static struct drm_fb_helper_funcs vbox_fb_helper_funcs = {
+ .fb_probe = vboxfb_create,
+};
+
static int vbox_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
- struct drm_device *dev = NULL;
+ struct vbox_private *vbox;
int ret = 0;
- dev = drm_dev_alloc(&driver, &pdev->dev);
- if (IS_ERR(dev)) {
- ret = PTR_ERR(dev);
- goto err_drv_alloc;
+ if (!vbox_check_supported(VBE_DISPI_ID_HGSMI))
+ return -ENODEV;
+
+ vbox = kzalloc(sizeof(*vbox), GFP_KERNEL);
+ if (!vbox)
+ return -ENOMEM;
+
+ ret = drm_dev_init(&vbox->ddev, &driver, &pdev->dev);
+ if (ret) {
+ kfree(vbox);
+ return ret;
}
+ vbox->ddev.pdev = pdev;
+ vbox->ddev.dev_private = vbox;
+ pci_set_drvdata(pdev, vbox);
+ mutex_init(&vbox->hw_mutex);
+
ret = pci_enable_device(pdev);
if (ret)
- goto err_pci_enable;
-
- dev->pdev = pdev;
- pci_set_drvdata(pdev, dev);
+ goto err_dev_put;
- ret = vbox_driver_load(dev);
+ ret = vbox_hw_init(vbox);
if (ret)
- goto err_vbox_driver_load;
+ goto err_pci_disable;
- ret = drm_dev_register(dev, 0);
+ ret = vbox_mm_init(vbox);
if (ret)
- goto err_drv_dev_register;
-
- return ret;
-
- err_drv_dev_register:
- vbox_driver_unload(dev);
- err_vbox_driver_load:
- pci_disable_device(pdev);
- err_pci_enable:
- drm_dev_put(dev);
- err_drv_alloc:
- return ret;
-}
-
-static void vbox_pci_remove(struct pci_dev *pdev)
-{
- struct drm_device *dev = pci_get_drvdata(pdev);
-
- drm_dev_unregister(dev);
- vbox_driver_unload(dev);
- drm_dev_put(dev);
-}
+ goto err_hw_fini;
-static int vbox_drm_freeze(struct drm_device *dev)
-{
- struct vbox_private *vbox = dev->dev_private;
+ ret = vbox_mode_init(vbox);
+ if (ret)
+ goto err_mm_fini;
- drm_kms_helper_poll_disable(dev);
+ ret = vbox_irq_init(vbox);
+ if (ret)
+ goto err_mode_fini;
- pci_save_state(dev->pdev);
+ ret = drm_fb_helper_fbdev_setup(&vbox->ddev, &vbox->fb_helper,
+ &vbox_fb_helper_funcs, 32,
+ vbox->num_crtcs);
+ if (ret)
+ goto err_irq_fini;
- drm_fb_helper_set_suspend_unlocked(&vbox->fbdev->helper, true);
+ ret = drm_dev_register(&vbox->ddev, 0);
+ if (ret)
+ goto err_fbdev_fini;
return 0;
-}
-
-static int vbox_drm_thaw(struct drm_device *dev)
-{
- struct vbox_private *vbox = dev->dev_private;
-
- drm_mode_config_reset(dev);
- drm_helper_resume_force_mode(dev);
- drm_fb_helper_set_suspend_unlocked(&vbox->fbdev->helper, false);
- return 0;
+err_fbdev_fini:
+ vbox_fbdev_fini(vbox);
+err_irq_fini:
+ vbox_irq_fini(vbox);
+err_mode_fini:
+ vbox_mode_fini(vbox);
+err_mm_fini:
+ vbox_mm_fini(vbox);
+err_hw_fini:
+ vbox_hw_fini(vbox);
+err_pci_disable:
+ pci_disable_device(pdev);
+err_dev_put:
+ drm_dev_put(&vbox->ddev);
+ return ret;
}
-static int vbox_drm_resume(struct drm_device *dev)
+static void vbox_pci_remove(struct pci_dev *pdev)
{
- int ret;
-
- if (pci_enable_device(dev->pdev))
- return -EIO;
-
- ret = vbox_drm_thaw(dev);
- if (ret)
- return ret;
-
- drm_kms_helper_poll_enable(dev);
-
- return 0;
+ struct vbox_private *vbox = pci_get_drvdata(pdev);
+
+ drm_dev_unregister(&vbox->ddev);
+ vbox_fbdev_fini(vbox);
+ vbox_irq_fini(vbox);
+ vbox_mode_fini(vbox);
+ vbox_mm_fini(vbox);
+ vbox_hw_fini(vbox);
+ drm_dev_put(&vbox->ddev);
}
static int vbox_pm_suspend(struct device *dev)
{
- struct pci_dev *pdev = to_pci_dev(dev);
- struct drm_device *ddev = pci_get_drvdata(pdev);
+ struct vbox_private *vbox = dev_get_drvdata(dev);
int error;
- error = vbox_drm_freeze(ddev);
+ error = drm_mode_config_helper_suspend(&vbox->ddev);
if (error)
return error;
- pci_disable_device(pdev);
- pci_set_power_state(pdev, PCI_D3hot);
+ pci_save_state(vbox->ddev.pdev);
+ pci_disable_device(vbox->ddev.pdev);
+ pci_set_power_state(vbox->ddev.pdev, PCI_D3hot);
return 0;
}
static int vbox_pm_resume(struct device *dev)
{
- struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
+ struct vbox_private *vbox = dev_get_drvdata(dev);
+
+ if (pci_enable_device(vbox->ddev.pdev))
+ return -EIO;
- return vbox_drm_resume(ddev);
+ return drm_mode_config_helper_resume(&vbox->ddev);
}
static int vbox_pm_freeze(struct device *dev)
{
- struct pci_dev *pdev = to_pci_dev(dev);
- struct drm_device *ddev = pci_get_drvdata(pdev);
-
- if (!ddev || !ddev->dev_private)
- return -ENODEV;
+ struct vbox_private *vbox = dev_get_drvdata(dev);
- return vbox_drm_freeze(ddev);
+ return drm_mode_config_helper_suspend(&vbox->ddev);
}
static int vbox_pm_thaw(struct device *dev)
{
- struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
+ struct vbox_private *vbox = dev_get_drvdata(dev);
- return vbox_drm_thaw(ddev);
+ return drm_mode_config_helper_resume(&vbox->ddev);
}
static int vbox_pm_poweroff(struct device *dev)
{
- struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
+ struct vbox_private *vbox = dev_get_drvdata(dev);
- return vbox_drm_freeze(ddev);
+ return drm_mode_config_helper_suspend(&vbox->ddev);
}
static const struct dev_pm_ops vbox_pm_ops = {
@@ -259,10 +260,10 @@ static void vbox_master_drop(struct drm_device *dev, struct drm_file *file_priv)
static struct drm_driver driver = {
.driver_features =
DRIVER_MODESET | DRIVER_GEM | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
- DRIVER_PRIME,
+ DRIVER_PRIME | DRIVER_ATOMIC,
.dev_priv_size = 0,
- .lastclose = vbox_driver_lastclose,
+ .lastclose = drm_fb_helper_lastclose,
.master_set = vbox_master_set,
.master_drop = vbox_master_drop,
diff --git a/drivers/staging/vboxvideo/vbox_drv.h b/drivers/staging/vboxvideo/vbox_drv.h
index 594f84272957..fa933d422951 100644
--- a/drivers/staging/vboxvideo/vbox_drv.h
+++ b/drivers/staging/vboxvideo/vbox_drv.h
@@ -72,10 +72,16 @@
sizeof(struct hgsmi_host_flags))
#define HOST_FLAGS_OFFSET GUEST_HEAP_USABLE_SIZE
-struct vbox_fbdev;
+struct vbox_framebuffer {
+ struct drm_framebuffer base;
+ struct drm_gem_object *obj;
+};
struct vbox_private {
- struct drm_device *dev;
+ /* Must be first; or we must define our own release callback */
+ struct drm_device ddev;
+ struct drm_fb_helper fb_helper;
+ struct vbox_framebuffer afb;
u8 __iomem *guest_heap;
u8 __iomem *vbva_buffers;
@@ -90,13 +96,9 @@ struct vbox_private {
/** Array of structures for receiving mode hints. */
struct vbva_modehint *last_mode_hints;
- struct vbox_fbdev *fbdev;
-
int fb_mtrr;
struct {
- struct drm_global_reference mem_global_ref;
- struct ttm_bo_global_ref bo_global_ref;
struct ttm_bo_device bdev;
} ttm;
@@ -115,21 +117,12 @@ struct vbox_private {
* encompassing all screen ones or is the fbdev console active?
*/
bool single_framebuffer;
- u32 cursor_width;
- u32 cursor_height;
- u32 cursor_hot_x;
- u32 cursor_hot_y;
- size_t cursor_data_size;
u8 cursor_data[CURSOR_DATA_SIZE];
};
#undef CURSOR_PIXEL_COUNT
#undef CURSOR_DATA_SIZE
-int vbox_driver_load(struct drm_device *dev);
-void vbox_driver_unload(struct drm_device *dev);
-void vbox_driver_lastclose(struct drm_device *dev);
-
struct vbox_gem_object;
struct vbox_connector {
@@ -145,43 +138,51 @@ struct vbox_connector {
struct vbox_crtc {
struct drm_crtc base;
- bool blanked;
bool disconnected;
unsigned int crtc_id;
u32 fb_offset;
bool cursor_enabled;
u32 x_hint;
u32 y_hint;
+ /*
+ * When setting a mode we not only pass the mode to the hypervisor,
+ * but also information on how to map / translate input coordinates
+ * for the emulated USB tablet. This input-mapping may change when
+ * the mode on *another* crtc changes.
+ *
+ * This means that sometimes we must do a modeset on other crtc-s then
+ * the one being changed to update the input-mapping. Including crtc-s
+ * which may be disabled inside the guest (shown as a black window
+ * on the host unless closed by the user).
+ *
+ * With atomic modesetting the mode-info of disabled crtcs gets zeroed
+ * yet we need it when updating the input-map to avoid resizing the
+ * window as a side effect of a mode_set on another crtc. Therefor we
+ * cache the info of the last mode below.
+ */
+ u32 width;
+ u32 height;
+ u32 x;
+ u32 y;
};
struct vbox_encoder {
struct drm_encoder base;
};
-struct vbox_framebuffer {
- struct drm_framebuffer base;
- struct drm_gem_object *obj;
-};
-
-struct vbox_fbdev {
- struct drm_fb_helper helper;
- struct vbox_framebuffer afb;
- int size;
- struct ttm_bo_kmap_obj mapping;
- int x1, y1, x2, y2; /* dirty rect */
- spinlock_t dirty_lock;
-};
-
#define to_vbox_crtc(x) container_of(x, struct vbox_crtc, base)
#define to_vbox_connector(x) container_of(x, struct vbox_connector, base)
#define to_vbox_encoder(x) container_of(x, struct vbox_encoder, base)
#define to_vbox_framebuffer(x) container_of(x, struct vbox_framebuffer, base)
-int vbox_mode_init(struct drm_device *dev);
-void vbox_mode_fini(struct drm_device *dev);
+bool vbox_check_supported(u16 id);
+int vbox_hw_init(struct vbox_private *vbox);
+void vbox_hw_fini(struct vbox_private *vbox);
+
+int vbox_mode_init(struct vbox_private *vbox);
+void vbox_mode_fini(struct vbox_private *vbox);
#define DRM_MODE_FB_CMD drm_mode_fb_cmd2
-#define CRTC_FB(crtc) ((crtc)->primary->fb)
void vbox_enable_accel(struct vbox_private *vbox);
void vbox_disable_accel(struct vbox_private *vbox);
@@ -191,14 +192,14 @@ void vbox_framebuffer_dirty_rectangles(struct drm_framebuffer *fb,
struct drm_clip_rect *rects,
unsigned int num_rects);
-int vbox_framebuffer_init(struct drm_device *dev,
+int vbox_framebuffer_init(struct vbox_private *vbox,
struct vbox_framebuffer *vbox_fb,
const struct DRM_MODE_FB_CMD *mode_cmd,
struct drm_gem_object *obj);
-int vbox_fbdev_init(struct drm_device *dev);
-void vbox_fbdev_fini(struct drm_device *dev);
-void vbox_fbdev_set_base(struct vbox_private *vbox, unsigned long gpu_addr);
+int vboxfb_create(struct drm_fb_helper *helper,
+ struct drm_fb_helper_surface_size *sizes);
+void vbox_fbdev_fini(struct vbox_private *vbox);
struct vbox_bo {
struct ttm_buffer_object bo;
@@ -218,6 +219,11 @@ static inline struct vbox_bo *vbox_bo(struct ttm_buffer_object *bo)
#define to_vbox_obj(x) container_of(x, struct vbox_gem_object, base)
+static inline u64 vbox_bo_gpu_offset(struct vbox_bo *bo)
+{
+ return bo->bo.offset;
+}
+
int vbox_dumb_create(struct drm_file *file,
struct drm_device *dev,
struct drm_mode_create_dumb *args);
@@ -232,13 +238,13 @@ int vbox_dumb_mmap_offset(struct drm_file *file,
int vbox_mm_init(struct vbox_private *vbox);
void vbox_mm_fini(struct vbox_private *vbox);
-int vbox_bo_create(struct drm_device *dev, int size, int align,
+int vbox_bo_create(struct vbox_private *vbox, int size, int align,
u32 flags, struct vbox_bo **pvboxbo);
-int vbox_gem_create(struct drm_device *dev,
+int vbox_gem_create(struct vbox_private *vbox,
u32 size, bool iskernel, struct drm_gem_object **obj);
-int vbox_bo_pin(struct vbox_bo *bo, u32 pl_flag, u64 *gpu_addr);
+int vbox_bo_pin(struct vbox_bo *bo, u32 pl_flag);
int vbox_bo_unpin(struct vbox_bo *bo);
static inline int vbox_bo_reserve(struct vbox_bo *bo, bool no_wait)
@@ -262,6 +268,8 @@ static inline void vbox_bo_unreserve(struct vbox_bo *bo)
void vbox_ttm_placement(struct vbox_bo *bo, int domain);
int vbox_bo_push_sysram(struct vbox_bo *bo);
int vbox_mmap(struct file *filp, struct vm_area_struct *vma);
+void *vbox_bo_kmap(struct vbox_bo *bo);
+void vbox_bo_kunmap(struct vbox_bo *bo);
/* vbox_prime.c */
int vbox_gem_prime_pin(struct drm_gem_object *obj);
diff --git a/drivers/staging/vboxvideo/vbox_fb.c b/drivers/staging/vboxvideo/vbox_fb.c
index 034f8ffa8f20..d1a1f74c8de3 100644
--- a/drivers/staging/vboxvideo/vbox_fb.c
+++ b/drivers/staging/vboxvideo/vbox_fb.c
@@ -66,38 +66,19 @@ static struct fb_ops vboxfb_ops = {
.fb_debug_leave = drm_fb_helper_debug_leave,
};
-static int vboxfb_create_object(struct vbox_fbdev *fbdev,
- struct DRM_MODE_FB_CMD *mode_cmd,
- struct drm_gem_object **gobj_p)
+int vboxfb_create(struct drm_fb_helper *helper,
+ struct drm_fb_helper_surface_size *sizes)
{
- struct drm_device *dev = fbdev->helper.dev;
- u32 size;
- struct drm_gem_object *gobj;
- u32 pitch = mode_cmd->pitches[0];
- int ret;
-
- size = pitch * mode_cmd->height;
- ret = vbox_gem_create(dev, size, true, &gobj);
- if (ret)
- return ret;
-
- *gobj_p = gobj;
-
- return 0;
-}
-
-static int vboxfb_create(struct drm_fb_helper *helper,
- struct drm_fb_helper_surface_size *sizes)
-{
- struct vbox_fbdev *fbdev =
- container_of(helper, struct vbox_fbdev, helper);
- struct drm_device *dev = fbdev->helper.dev;
+ struct vbox_private *vbox =
+ container_of(helper, struct vbox_private, fb_helper);
+ struct pci_dev *pdev = vbox->ddev.pdev;
struct DRM_MODE_FB_CMD mode_cmd;
struct drm_framebuffer *fb;
struct fb_info *info;
struct drm_gem_object *gobj;
struct vbox_bo *bo;
int size, ret;
+ u64 gpu_addr;
u32 pitch;
mode_cmd.width = sizes->surface_width;
@@ -109,45 +90,35 @@ static int vboxfb_create(struct drm_fb_helper *helper,
size = pitch * mode_cmd.height;
- ret = vboxfb_create_object(fbdev, &mode_cmd, &gobj);
+ ret = vbox_gem_create(vbox, size, true, &gobj);
if (ret) {
DRM_ERROR("failed to create fbcon backing object %d\n", ret);
return ret;
}
- ret = vbox_framebuffer_init(dev, &fbdev->afb, &mode_cmd, gobj);
+ ret = vbox_framebuffer_init(vbox, &vbox->afb, &mode_cmd, gobj);
if (ret)
return ret;
bo = gem_to_vbox_bo(gobj);
- ret = vbox_bo_reserve(bo, false);
+ ret = vbox_bo_pin(bo, TTM_PL_FLAG_VRAM);
if (ret)
return ret;
- ret = vbox_bo_pin(bo, TTM_PL_FLAG_VRAM, NULL);
- if (ret) {
- vbox_bo_unreserve(bo);
- return ret;
- }
-
- ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
- vbox_bo_unreserve(bo);
- if (ret) {
- DRM_ERROR("failed to kmap fbcon\n");
- return ret;
- }
-
info = drm_fb_helper_alloc_fbi(helper);
if (IS_ERR(info))
- return -PTR_ERR(info);
+ return PTR_ERR(info);
- info->par = fbdev;
+ info->screen_size = size;
+ info->screen_base = (char __iomem *)vbox_bo_kmap(bo);
+ if (IS_ERR(info->screen_base))
+ return PTR_ERR(info->screen_base);
- fbdev->size = size;
+ info->par = helper;
- fb = &fbdev->afb.base;
- fbdev->helper.fb = fb;
+ fb = &vbox->afb.base;
+ helper->fb = fb;
strcpy(info->fix.id, "vboxdrmfb");
@@ -162,15 +133,16 @@ static int vboxfb_create(struct drm_fb_helper *helper,
* This seems to be done for safety checking that the framebuffer
* is not registered twice by different drivers.
*/
- info->apertures->ranges[0].base = pci_resource_start(dev->pdev, 0);
- info->apertures->ranges[0].size = pci_resource_len(dev->pdev, 0);
+ info->apertures->ranges[0].base = pci_resource_start(pdev, 0);
+ info->apertures->ranges[0].size = pci_resource_len(pdev, 0);
drm_fb_helper_fill_fix(info, fb->pitches[0], fb->format->depth);
- drm_fb_helper_fill_var(info, &fbdev->helper, sizes->fb_width,
+ drm_fb_helper_fill_var(info, helper, sizes->fb_width,
sizes->fb_height);
- info->screen_base = (char __iomem *)bo->kmap.virtual;
- info->screen_size = size;
+ gpu_addr = vbox_bo_gpu_offset(bo);
+ info->fix.smem_start = info->apertures->ranges[0].base + gpu_addr;
+ info->fix.smem_len = vbox->available_vram_size - gpu_addr;
#ifdef CONFIG_DRM_KMS_FB_HELPER
info->fbdefio = &vbox_defio;
@@ -184,86 +156,30 @@ static int vboxfb_create(struct drm_fb_helper *helper,
return 0;
}
-static struct drm_fb_helper_funcs vbox_fb_helper_funcs = {
- .fb_probe = vboxfb_create,
-};
-
-void vbox_fbdev_fini(struct drm_device *dev)
+void vbox_fbdev_fini(struct vbox_private *vbox)
{
- struct vbox_private *vbox = dev->dev_private;
- struct vbox_fbdev *fbdev = vbox->fbdev;
- struct vbox_framebuffer *afb = &fbdev->afb;
+ struct vbox_framebuffer *afb = &vbox->afb;
#ifdef CONFIG_DRM_KMS_FB_HELPER
- if (fbdev->helper.fbdev && fbdev->helper.fbdev->fbdefio)
- fb_deferred_io_cleanup(fbdev->helper.fbdev);
+ if (vbox->fb_helper.fbdev && vbox->fb_helper.fbdev->fbdefio)
+ fb_deferred_io_cleanup(vbox->fb_helper.fbdev);
#endif
- drm_fb_helper_unregister_fbi(&fbdev->helper);
+ drm_fb_helper_unregister_fbi(&vbox->fb_helper);
if (afb->obj) {
struct vbox_bo *bo = gem_to_vbox_bo(afb->obj);
- if (!vbox_bo_reserve(bo, false)) {
- if (bo->kmap.virtual)
- ttm_bo_kunmap(&bo->kmap);
- /*
- * QXL does this, but is it really needed before
- * freeing?
- */
- if (bo->pin_count)
- vbox_bo_unpin(bo);
- vbox_bo_unreserve(bo);
- }
+ vbox_bo_kunmap(bo);
+
+ if (bo->pin_count)
+ vbox_bo_unpin(bo);
+
drm_gem_object_put_unlocked(afb->obj);
afb->obj = NULL;
}
- drm_fb_helper_fini(&fbdev->helper);
+ drm_fb_helper_fini(&vbox->fb_helper);
drm_framebuffer_unregister_private(&afb->base);
drm_framebuffer_cleanup(&afb->base);
}
-
-int vbox_fbdev_init(struct drm_device *dev)
-{
- struct vbox_private *vbox = dev->dev_private;
- struct vbox_fbdev *fbdev;
- int ret;
-
- fbdev = devm_kzalloc(dev->dev, sizeof(*fbdev), GFP_KERNEL);
- if (!fbdev)
- return -ENOMEM;
-
- vbox->fbdev = fbdev;
- spin_lock_init(&fbdev->dirty_lock);
-
- drm_fb_helper_prepare(dev, &fbdev->helper, &vbox_fb_helper_funcs);
- ret = drm_fb_helper_init(dev, &fbdev->helper, vbox->num_crtcs);
- if (ret)
- return ret;
-
- ret = drm_fb_helper_single_add_all_connectors(&fbdev->helper);
- if (ret)
- goto err_fini;
-
- /* disable all the possible outputs/crtcs before entering KMS mode */
- drm_helper_disable_unused_functions(dev);
-
- ret = drm_fb_helper_initial_config(&fbdev->helper, 32);
- if (ret)
- goto err_fini;
-
- return 0;
-
-err_fini:
- drm_fb_helper_fini(&fbdev->helper);
- return ret;
-}
-
-void vbox_fbdev_set_base(struct vbox_private *vbox, unsigned long gpu_addr)
-{
- struct fb_info *fbdev = vbox->fbdev->helper.fbdev;
-
- fbdev->fix.smem_start = fbdev->apertures->ranges[0].base + gpu_addr;
- fbdev->fix.smem_len = vbox->available_vram_size - gpu_addr;
-}
diff --git a/drivers/staging/vboxvideo/vbox_irq.c b/drivers/staging/vboxvideo/vbox_irq.c
index 74abdf02d9fd..09f858ec1369 100644
--- a/drivers/staging/vboxvideo/vbox_irq.c
+++ b/drivers/staging/vboxvideo/vbox_irq.c
@@ -123,7 +123,7 @@ static void validate_or_set_position_hints(struct vbox_private *vbox)
*/
static void vbox_update_mode_hints(struct vbox_private *vbox)
{
- struct drm_device *dev = vbox->dev;
+ struct drm_device *dev = &vbox->ddev;
struct drm_connector *connector;
struct vbox_connector *vbox_conn;
struct vbva_modehint *hints;
@@ -179,7 +179,7 @@ static void vbox_hotplug_worker(struct work_struct *work)
hotplug_work);
vbox_update_mode_hints(vbox);
- drm_kms_helper_hotplug_event(vbox->dev);
+ drm_kms_helper_hotplug_event(&vbox->ddev);
}
int vbox_irq_init(struct vbox_private *vbox)
@@ -187,11 +187,11 @@ int vbox_irq_init(struct vbox_private *vbox)
INIT_WORK(&vbox->hotplug_work, vbox_hotplug_worker);
vbox_update_mode_hints(vbox);
- return drm_irq_install(vbox->dev, vbox->dev->pdev->irq);
+ return drm_irq_install(&vbox->ddev, vbox->ddev.pdev->irq);
}
void vbox_irq_fini(struct vbox_private *vbox)
{
- drm_irq_uninstall(vbox->dev);
+ drm_irq_uninstall(&vbox->ddev);
flush_work(&vbox->hotplug_work);
}
diff --git a/drivers/staging/vboxvideo/vbox_main.c b/drivers/staging/vboxvideo/vbox_main.c
index 429f6a453619..7466c1103ff6 100644
--- a/drivers/staging/vboxvideo/vbox_main.c
+++ b/drivers/staging/vboxvideo/vbox_main.c
@@ -102,24 +102,30 @@ void vbox_framebuffer_dirty_rectangles(struct drm_framebuffer *fb,
unsigned int num_rects)
{
struct vbox_private *vbox = fb->dev->dev_private;
+ struct drm_display_mode *mode;
struct drm_crtc *crtc;
+ int crtc_x, crtc_y;
unsigned int i;
mutex_lock(&vbox->hw_mutex);
list_for_each_entry(crtc, &fb->dev->mode_config.crtc_list, head) {
- if (CRTC_FB(crtc) != fb)
+ if (crtc->primary->state->fb != fb)
continue;
+ mode = &crtc->state->mode;
+ crtc_x = crtc->primary->state->src_x >> 16;
+ crtc_y = crtc->primary->state->src_y >> 16;
+
vbox_enable_accel(vbox);
for (i = 0; i < num_rects; ++i) {
struct vbva_cmd_hdr cmd_hdr;
unsigned int crtc_id = to_vbox_crtc(crtc)->crtc_id;
- if ((rects[i].x1 > crtc->x + crtc->hwmode.hdisplay) ||
- (rects[i].y1 > crtc->y + crtc->hwmode.vdisplay) ||
- (rects[i].x2 < crtc->x) ||
- (rects[i].y2 < crtc->y))
+ if ((rects[i].x1 > crtc_x + mode->hdisplay) ||
+ (rects[i].y1 > crtc_y + mode->vdisplay) ||
+ (rects[i].x2 < crtc_x) ||
+ (rects[i].y2 < crtc_y))
continue;
cmd_hdr.x = (s16)rects[i].x1;
@@ -155,16 +161,16 @@ static const struct drm_framebuffer_funcs vbox_fb_funcs = {
.dirty = vbox_user_framebuffer_dirty,
};
-int vbox_framebuffer_init(struct drm_device *dev,
+int vbox_framebuffer_init(struct vbox_private *vbox,
struct vbox_framebuffer *vbox_fb,
const struct DRM_MODE_FB_CMD *mode_cmd,
struct drm_gem_object *obj)
{
int ret;
- drm_helper_mode_fill_fb_struct(dev, &vbox_fb->base, mode_cmd);
+ drm_helper_mode_fill_fb_struct(&vbox->ddev, &vbox_fb->base, mode_cmd);
vbox_fb->obj = obj;
- ret = drm_framebuffer_init(dev, &vbox_fb->base, &vbox_fb_funcs);
+ ret = drm_framebuffer_init(&vbox->ddev, &vbox_fb->base, &vbox_fb_funcs);
if (ret) {
DRM_ERROR("framebuffer init failed %d\n", ret);
return ret;
@@ -173,45 +179,11 @@ int vbox_framebuffer_init(struct drm_device *dev,
return 0;
}
-static struct drm_framebuffer *vbox_user_framebuffer_create(
- struct drm_device *dev,
- struct drm_file *filp,
- const struct drm_mode_fb_cmd2 *mode_cmd)
-{
- struct drm_gem_object *obj;
- struct vbox_framebuffer *vbox_fb;
- int ret = -ENOMEM;
-
- obj = drm_gem_object_lookup(filp, mode_cmd->handles[0]);
- if (!obj)
- return ERR_PTR(-ENOENT);
-
- vbox_fb = kzalloc(sizeof(*vbox_fb), GFP_KERNEL);
- if (!vbox_fb)
- goto err_unref_obj;
-
- ret = vbox_framebuffer_init(dev, vbox_fb, mode_cmd, obj);
- if (ret)
- goto err_free_vbox_fb;
-
- return &vbox_fb->base;
-
-err_free_vbox_fb:
- kfree(vbox_fb);
-err_unref_obj:
- drm_gem_object_put_unlocked(obj);
- return ERR_PTR(ret);
-}
-
-static const struct drm_mode_config_funcs vbox_mode_funcs = {
- .fb_create = vbox_user_framebuffer_create,
-};
-
static int vbox_accel_init(struct vbox_private *vbox)
{
unsigned int i;
- vbox->vbva_info = devm_kcalloc(vbox->dev->dev, vbox->num_crtcs,
+ vbox->vbva_info = devm_kcalloc(vbox->ddev.dev, vbox->num_crtcs,
sizeof(*vbox->vbva_info), GFP_KERNEL);
if (!vbox->vbva_info)
return -ENOMEM;
@@ -219,7 +191,7 @@ static int vbox_accel_init(struct vbox_private *vbox)
/* Take a command buffer for each screen from the end of usable VRAM. */
vbox->available_vram_size -= vbox->num_crtcs * VBVA_MIN_BUFFER_SIZE;
- vbox->vbva_buffers = pci_iomap_range(vbox->dev->pdev, 0,
+ vbox->vbva_buffers = pci_iomap_range(vbox->ddev.pdev, 0,
vbox->available_vram_size,
vbox->num_crtcs *
VBVA_MIN_BUFFER_SIZE);
@@ -238,7 +210,7 @@ static int vbox_accel_init(struct vbox_private *vbox)
static void vbox_accel_fini(struct vbox_private *vbox)
{
vbox_disable_accel(vbox);
- pci_iounmap(vbox->dev->pdev, vbox->vbva_buffers);
+ pci_iounmap(vbox->ddev.pdev, vbox->vbva_buffers);
}
/** Do we support the 4.3 plus mode hint reporting interface? */
@@ -262,7 +234,7 @@ static bool have_hgsmi_mode_hints(struct vbox_private *vbox)
return have_hints == VINF_SUCCESS && have_cursor == VINF_SUCCESS;
}
-static bool vbox_check_supported(u16 id)
+bool vbox_check_supported(u16 id)
{
u16 dispi_id;
@@ -276,7 +248,7 @@ static bool vbox_check_supported(u16 id)
* Set up our heaps and data exchange buffers in VRAM before handing the rest
* to the memory manager.
*/
-static int vbox_hw_init(struct vbox_private *vbox)
+int vbox_hw_init(struct vbox_private *vbox)
{
int ret = -ENOMEM;
@@ -287,7 +259,7 @@ static int vbox_hw_init(struct vbox_private *vbox)
/* Map guest-heap at end of vram */
vbox->guest_heap =
- pci_iomap_range(vbox->dev->pdev, 0, GUEST_HEAP_OFFSET(vbox),
+ pci_iomap_range(vbox->ddev.pdev, 0, GUEST_HEAP_OFFSET(vbox),
GUEST_HEAP_SIZE);
if (!vbox->guest_heap)
return -ENOMEM;
@@ -322,7 +294,7 @@ static int vbox_hw_init(struct vbox_private *vbox)
goto err_destroy_guest_pool;
}
- vbox->last_mode_hints = devm_kcalloc(vbox->dev->dev, vbox->num_crtcs,
+ vbox->last_mode_hints = devm_kcalloc(vbox->ddev.dev, vbox->num_crtcs,
sizeof(struct vbva_modehint),
GFP_KERNEL);
if (!vbox->last_mode_hints) {
@@ -339,102 +311,18 @@ static int vbox_hw_init(struct vbox_private *vbox)
err_destroy_guest_pool:
gen_pool_destroy(vbox->guest_pool);
err_unmap_guest_heap:
- pci_iounmap(vbox->dev->pdev, vbox->guest_heap);
+ pci_iounmap(vbox->ddev.pdev, vbox->guest_heap);
return ret;
}
-static void vbox_hw_fini(struct vbox_private *vbox)
+void vbox_hw_fini(struct vbox_private *vbox)
{
vbox_accel_fini(vbox);
gen_pool_destroy(vbox->guest_pool);
- pci_iounmap(vbox->dev->pdev, vbox->guest_heap);
-}
-
-int vbox_driver_load(struct drm_device *dev)
-{
- struct vbox_private *vbox;
- int ret = 0;
-
- if (!vbox_check_supported(VBE_DISPI_ID_HGSMI))
- return -ENODEV;
-
- vbox = devm_kzalloc(dev->dev, sizeof(*vbox), GFP_KERNEL);
- if (!vbox)
- return -ENOMEM;
-
- dev->dev_private = vbox;
- vbox->dev = dev;
-
- mutex_init(&vbox->hw_mutex);
-
- ret = vbox_hw_init(vbox);
- if (ret)
- return ret;
-
- ret = vbox_mm_init(vbox);
- if (ret)
- goto err_hw_fini;
-
- drm_mode_config_init(dev);
-
- dev->mode_config.funcs = (void *)&vbox_mode_funcs;
- dev->mode_config.min_width = 64;
- dev->mode_config.min_height = 64;
- dev->mode_config.preferred_depth = 24;
- dev->mode_config.max_width = VBE_DISPI_MAX_XRES;
- dev->mode_config.max_height = VBE_DISPI_MAX_YRES;
-
- ret = vbox_mode_init(dev);
- if (ret)
- goto err_drm_mode_cleanup;
-
- ret = vbox_irq_init(vbox);
- if (ret)
- goto err_mode_fini;
-
- ret = vbox_fbdev_init(dev);
- if (ret)
- goto err_irq_fini;
-
- return 0;
-
-err_irq_fini:
- vbox_irq_fini(vbox);
-err_mode_fini:
- vbox_mode_fini(dev);
-err_drm_mode_cleanup:
- drm_mode_config_cleanup(dev);
- vbox_mm_fini(vbox);
-err_hw_fini:
- vbox_hw_fini(vbox);
- return ret;
-}
-
-void vbox_driver_unload(struct drm_device *dev)
-{
- struct vbox_private *vbox = dev->dev_private;
-
- vbox_fbdev_fini(dev);
- vbox_irq_fini(vbox);
- vbox_mode_fini(dev);
- drm_mode_config_cleanup(dev);
- vbox_mm_fini(vbox);
- vbox_hw_fini(vbox);
+ pci_iounmap(vbox->ddev.pdev, vbox->guest_heap);
}
-/**
- * @note this is described in the DRM framework documentation. AST does not
- * have it, but we get an oops on driver unload if it is not present.
- */
-void vbox_driver_lastclose(struct drm_device *dev)
-{
- struct vbox_private *vbox = dev->dev_private;
-
- if (vbox->fbdev)
- drm_fb_helper_restore_fbdev_mode_unlocked(&vbox->fbdev->helper);
-}
-
-int vbox_gem_create(struct drm_device *dev,
+int vbox_gem_create(struct vbox_private *vbox,
u32 size, bool iskernel, struct drm_gem_object **obj)
{
struct vbox_bo *vboxbo;
@@ -446,7 +334,7 @@ int vbox_gem_create(struct drm_device *dev,
if (size == 0)
return -EINVAL;
- ret = vbox_bo_create(dev, size, 0, 0, &vboxbo);
+ ret = vbox_bo_create(vbox, size, 0, 0, &vboxbo);
if (ret) {
if (ret != -ERESTARTSYS)
DRM_ERROR("failed to allocate GEM object\n");
@@ -461,14 +349,16 @@ int vbox_gem_create(struct drm_device *dev,
int vbox_dumb_create(struct drm_file *file,
struct drm_device *dev, struct drm_mode_create_dumb *args)
{
- int ret;
+ struct vbox_private *vbox =
+ container_of(dev, struct vbox_private, ddev);
struct drm_gem_object *gobj;
u32 handle;
+ int ret;
args->pitch = args->width * ((args->bpp + 7) / 8);
args->size = args->pitch * args->height;
- ret = vbox_gem_create(dev, args->size, false, &gobj);
+ ret = vbox_gem_create(vbox, args->size, false, &gobj);
if (ret)
return ret;
@@ -482,24 +372,11 @@ int vbox_dumb_create(struct drm_file *file,
return 0;
}
-static void vbox_bo_unref(struct vbox_bo **bo)
-{
- struct ttm_buffer_object *tbo;
-
- if ((*bo) == NULL)
- return;
-
- tbo = &((*bo)->bo);
- ttm_bo_unref(&tbo);
- if (!tbo)
- *bo = NULL;
-}
-
void vbox_gem_free_object(struct drm_gem_object *obj)
{
struct vbox_bo *vbox_bo = gem_to_vbox_bo(obj);
- vbox_bo_unref(&vbox_bo);
+ ttm_bo_put(&vbox_bo->bo);
}
static inline u64 vbox_bo_mmap_offset(struct vbox_bo *bo)
diff --git a/drivers/staging/vboxvideo/vbox_mode.c b/drivers/staging/vboxvideo/vbox_mode.c
index 79836c8fb909..6acc965247ff 100644
--- a/drivers/staging/vboxvideo/vbox_mode.c
+++ b/drivers/staging/vboxvideo/vbox_mode.c
@@ -32,25 +32,22 @@
* Hans de Goede <hdegoede@redhat.com>
*/
#include <linux/export.h>
+#include <drm/drm_atomic.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_plane_helper.h>
+#include <drm/drm_atomic_helper.h>
#include "vbox_drv.h"
#include "vboxvideo.h"
#include "hgsmi_channels.h"
-static int vbox_cursor_set2(struct drm_crtc *crtc, struct drm_file *file_priv,
- u32 handle, u32 width, u32 height,
- s32 hot_x, s32 hot_y);
-static int vbox_cursor_move(struct drm_crtc *crtc, int x, int y);
-
/**
* Set a graphics mode. Poke any required values into registers, do an HGSMI
* mode set and tell the host we support advanced graphics functions.
*/
-static void vbox_do_modeset(struct drm_crtc *crtc,
- const struct drm_display_mode *mode)
+static void vbox_do_modeset(struct drm_crtc *crtc)
{
+ struct drm_framebuffer *fb = crtc->primary->state->fb;
struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
struct vbox_private *vbox;
int width, height, bpp, pitch;
@@ -58,12 +55,12 @@ static void vbox_do_modeset(struct drm_crtc *crtc,
s32 x_offset, y_offset;
vbox = crtc->dev->dev_private;
- width = mode->hdisplay ? mode->hdisplay : 640;
- height = mode->vdisplay ? mode->vdisplay : 480;
- bpp = crtc->enabled ? CRTC_FB(crtc)->format->cpp[0] * 8 : 32;
- pitch = crtc->enabled ? CRTC_FB(crtc)->pitches[0] : width * bpp / 8;
- x_offset = vbox->single_framebuffer ? crtc->x : vbox_crtc->x_hint;
- y_offset = vbox->single_framebuffer ? crtc->y : vbox_crtc->y_hint;
+ width = vbox_crtc->width ? vbox_crtc->width : 640;
+ height = vbox_crtc->height ? vbox_crtc->height : 480;
+ bpp = fb ? fb->format->cpp[0] * 8 : 32;
+ pitch = fb ? fb->pitches[0] : width * bpp / 8;
+ x_offset = vbox->single_framebuffer ? vbox_crtc->x : vbox_crtc->x_hint;
+ y_offset = vbox->single_framebuffer ? vbox_crtc->y : vbox_crtc->y_hint;
/*
* This is the old way of setting graphics modes. It assumed one screen
@@ -71,31 +68,29 @@ static void vbox_do_modeset(struct drm_crtc *crtc,
* VirtualBox, certain parts of the code still assume that the first
* screen is programmed this way, so try to fake it.
*/
- if (vbox_crtc->crtc_id == 0 && crtc->enabled &&
+ if (vbox_crtc->crtc_id == 0 && fb &&
vbox_crtc->fb_offset / pitch < 0xffff - crtc->y &&
vbox_crtc->fb_offset % (bpp / 8) == 0) {
vbox_write_ioport(VBE_DISPI_INDEX_XRES, width);
vbox_write_ioport(VBE_DISPI_INDEX_YRES, height);
vbox_write_ioport(VBE_DISPI_INDEX_VIRT_WIDTH, pitch * 8 / bpp);
- vbox_write_ioport(VBE_DISPI_INDEX_BPP,
- CRTC_FB(crtc)->format->cpp[0] * 8);
+ vbox_write_ioport(VBE_DISPI_INDEX_BPP, bpp);
vbox_write_ioport(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED);
vbox_write_ioport(
VBE_DISPI_INDEX_X_OFFSET,
- vbox_crtc->fb_offset % pitch / bpp * 8 + crtc->x);
+ vbox_crtc->fb_offset % pitch / bpp * 8 + vbox_crtc->x);
vbox_write_ioport(VBE_DISPI_INDEX_Y_OFFSET,
- vbox_crtc->fb_offset / pitch + crtc->y);
+ vbox_crtc->fb_offset / pitch + vbox_crtc->y);
}
flags = VBVA_SCREEN_F_ACTIVE;
- flags |= (crtc->enabled && !vbox_crtc->blanked) ?
- 0 : VBVA_SCREEN_F_BLANK;
+ flags |= (fb && crtc->state->active) ? 0 : VBVA_SCREEN_F_BLANK;
flags |= vbox_crtc->disconnected ? VBVA_SCREEN_F_DISABLED : 0;
hgsmi_process_display_info(vbox->guest_pool, vbox_crtc->crtc_id,
x_offset, y_offset,
- crtc->x * bpp / 8 + crtc->y * pitch,
- pitch, width, height,
- vbox_crtc->blanked ? 0 : bpp, flags);
+ vbox_crtc->x * bpp / 8 +
+ vbox_crtc->y * pitch,
+ pitch, width, height, bpp, flags);
}
static int vbox_set_view(struct drm_crtc *crtc)
@@ -132,34 +127,6 @@ static int vbox_set_view(struct drm_crtc *crtc)
return 0;
}
-static void vbox_crtc_dpms(struct drm_crtc *crtc, int mode)
-{
- struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
- struct vbox_private *vbox = crtc->dev->dev_private;
-
- switch (mode) {
- case DRM_MODE_DPMS_ON:
- vbox_crtc->blanked = false;
- break;
- case DRM_MODE_DPMS_STANDBY:
- case DRM_MODE_DPMS_SUSPEND:
- case DRM_MODE_DPMS_OFF:
- vbox_crtc->blanked = true;
- break;
- }
-
- mutex_lock(&vbox->hw_mutex);
- vbox_do_modeset(crtc, &crtc->hwmode);
- mutex_unlock(&vbox->hw_mutex);
-}
-
-static bool vbox_crtc_mode_fixup(struct drm_crtc *crtc,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
-{
- return true;
-}
-
/*
* Try to map the layout of virtual screens to the range of the input device.
* Return true if we need to re-set the crtc modes due to screen offset
@@ -169,7 +136,7 @@ static bool vbox_set_up_input_mapping(struct vbox_private *vbox)
{
struct drm_crtc *crtci;
struct drm_connector *connectori;
- struct drm_framebuffer *fb1 = NULL;
+ struct drm_framebuffer *fb, *fb1 = NULL;
bool single_framebuffer = true;
bool old_single_framebuffer = vbox->single_framebuffer;
u16 width = 0, height = 0;
@@ -179,30 +146,30 @@ static bool vbox_set_up_input_mapping(struct vbox_private *vbox)
* If so then screen layout can be deduced from the crtc offsets.
* Same fall-back if this is the fbdev frame-buffer.
*/
- list_for_each_entry(crtci, &vbox->dev->mode_config.crtc_list, head) {
+ list_for_each_entry(crtci, &vbox->ddev.mode_config.crtc_list, head) {
+ fb = crtci->primary->state->fb;
+ if (!fb)
+ continue;
+
if (!fb1) {
- fb1 = CRTC_FB(crtci);
- if (to_vbox_framebuffer(fb1) == &vbox->fbdev->afb)
+ fb1 = fb;
+ if (to_vbox_framebuffer(fb1) == &vbox->afb)
break;
- } else if (CRTC_FB(crtci) && fb1 != CRTC_FB(crtci)) {
+ } else if (fb != fb1) {
single_framebuffer = false;
}
}
- if (single_framebuffer) {
- list_for_each_entry(crtci, &vbox->dev->mode_config.crtc_list,
- head) {
- if (to_vbox_crtc(crtci)->crtc_id != 0)
- continue;
+ if (!fb1)
+ return false;
- vbox->single_framebuffer = true;
- vbox->input_mapping_width = CRTC_FB(crtci)->width;
- vbox->input_mapping_height = CRTC_FB(crtci)->height;
- return old_single_framebuffer !=
- vbox->single_framebuffer;
- }
+ if (single_framebuffer) {
+ vbox->single_framebuffer = true;
+ vbox->input_mapping_width = fb1->width;
+ vbox->input_mapping_height = fb1->height;
+ return old_single_framebuffer != vbox->single_framebuffer;
}
/* Otherwise calculate the total span of all screens. */
- list_for_each_entry(connectori, &vbox->dev->mode_config.connector_list,
+ list_for_each_entry(connectori, &vbox->ddev.mode_config.connector_list,
head) {
struct vbox_connector *vbox_connector =
to_vbox_connector(connectori);
@@ -221,180 +188,462 @@ static bool vbox_set_up_input_mapping(struct vbox_private *vbox)
return old_single_framebuffer != vbox->single_framebuffer;
}
-static int vbox_crtc_do_set_base(struct drm_crtc *crtc,
- struct drm_framebuffer *old_fb,
- struct drm_framebuffer *new_fb,
- int x, int y)
+static void vbox_crtc_set_base_and_mode(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ struct drm_display_mode *mode,
+ int x, int y)
{
+ struct vbox_bo *bo = gem_to_vbox_bo(to_vbox_framebuffer(fb)->obj);
struct vbox_private *vbox = crtc->dev->dev_private;
struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
- struct drm_gem_object *obj;
- struct vbox_framebuffer *vbox_fb;
- struct vbox_bo *bo;
- int ret;
- u64 gpu_addr;
-
- /* Unpin the previous fb. */
- if (old_fb) {
- vbox_fb = to_vbox_framebuffer(old_fb);
- obj = vbox_fb->obj;
- bo = gem_to_vbox_bo(obj);
- ret = vbox_bo_reserve(bo, false);
- if (ret)
- return ret;
+ bool needs_modeset = drm_atomic_crtc_needs_modeset(crtc->state);
+
+ mutex_lock(&vbox->hw_mutex);
- vbox_bo_unpin(bo);
- vbox_bo_unreserve(bo);
+ vbox_crtc->width = mode->hdisplay;
+ vbox_crtc->height = mode->vdisplay;
+ vbox_crtc->x = x;
+ vbox_crtc->y = y;
+ vbox_crtc->fb_offset = vbox_bo_gpu_offset(bo);
+
+ /* vbox_do_modeset() checks vbox->single_framebuffer so update it now */
+ if (needs_modeset && vbox_set_up_input_mapping(vbox)) {
+ struct drm_crtc *crtci;
+
+ list_for_each_entry(crtci, &vbox->ddev.mode_config.crtc_list,
+ head) {
+ if (crtci == crtc)
+ continue;
+ vbox_do_modeset(crtci);
+ }
}
- vbox_fb = to_vbox_framebuffer(new_fb);
- obj = vbox_fb->obj;
- bo = gem_to_vbox_bo(obj);
+ vbox_set_view(crtc);
+ vbox_do_modeset(crtc);
- ret = vbox_bo_reserve(bo, false);
- if (ret)
- return ret;
+ if (needs_modeset)
+ hgsmi_update_input_mapping(vbox->guest_pool, 0, 0,
+ vbox->input_mapping_width,
+ vbox->input_mapping_height);
- ret = vbox_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr);
- if (ret) {
- vbox_bo_unreserve(bo);
- return ret;
+ mutex_unlock(&vbox->hw_mutex);
+}
+
+static void vbox_crtc_atomic_enable(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_crtc_state)
+{
+}
+
+static void vbox_crtc_atomic_disable(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_crtc_state)
+{
+}
+
+static void vbox_crtc_atomic_flush(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_crtc_state)
+{
+ struct drm_pending_vblank_event *event;
+ unsigned long flags;
+
+ if (crtc->state && crtc->state->event) {
+ event = crtc->state->event;
+ crtc->state->event = NULL;
+
+ spin_lock_irqsave(&crtc->dev->event_lock, flags);
+ drm_crtc_send_vblank_event(crtc, event);
+ spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
}
+}
- if (&vbox->fbdev->afb == vbox_fb)
- vbox_fbdev_set_base(vbox, gpu_addr);
- vbox_bo_unreserve(bo);
+static const struct drm_crtc_helper_funcs vbox_crtc_helper_funcs = {
+ .atomic_enable = vbox_crtc_atomic_enable,
+ .atomic_disable = vbox_crtc_atomic_disable,
+ .atomic_flush = vbox_crtc_atomic_flush,
+};
- /* vbox_set_start_address_crt1(crtc, (u32)gpu_addr); */
- vbox_crtc->fb_offset = gpu_addr;
- if (vbox_set_up_input_mapping(vbox)) {
- struct drm_crtc *crtci;
+static void vbox_crtc_destroy(struct drm_crtc *crtc)
+{
+ drm_crtc_cleanup(crtc);
+ kfree(crtc);
+}
- list_for_each_entry(crtci, &vbox->dev->mode_config.crtc_list,
- head) {
- vbox_set_view(crtc);
- vbox_do_modeset(crtci, &crtci->mode);
- }
+static const struct drm_crtc_funcs vbox_crtc_funcs = {
+ .set_config = drm_atomic_helper_set_config,
+ .page_flip = drm_atomic_helper_page_flip,
+ /* .gamma_set = vbox_crtc_gamma_set, */
+ .destroy = vbox_crtc_destroy,
+ .reset = drm_atomic_helper_crtc_reset,
+ .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+};
+
+static int vbox_primary_atomic_check(struct drm_plane *plane,
+ struct drm_plane_state *new_state)
+{
+ struct drm_crtc_state *crtc_state = NULL;
+
+ if (new_state->crtc) {
+ crtc_state = drm_atomic_get_existing_crtc_state(
+ new_state->state, new_state->crtc);
+ if (WARN_ON(!crtc_state))
+ return -EINVAL;
}
- return 0;
+ return drm_atomic_helper_check_plane_state(new_state, crtc_state,
+ DRM_PLANE_HELPER_NO_SCALING,
+ DRM_PLANE_HELPER_NO_SCALING,
+ false, true);
}
-static int vbox_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
- struct drm_framebuffer *old_fb)
+static void vbox_primary_atomic_update(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
{
- return vbox_crtc_do_set_base(crtc, old_fb, CRTC_FB(crtc), x, y);
+ struct drm_crtc *crtc = plane->state->crtc;
+ struct drm_framebuffer *fb = plane->state->fb;
+
+ vbox_crtc_set_base_and_mode(crtc, fb, &crtc->state->mode,
+ plane->state->src_x >> 16,
+ plane->state->src_y >> 16);
}
-static int vbox_crtc_mode_set(struct drm_crtc *crtc,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode,
- int x, int y, struct drm_framebuffer *old_fb)
+static void vbox_primary_atomic_disable(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
{
- struct vbox_private *vbox = crtc->dev->dev_private;
+ struct drm_crtc *crtc = old_state->crtc;
+
+ /* vbox_do_modeset checks plane->state->fb and will disable if NULL */
+ vbox_crtc_set_base_and_mode(crtc, old_state->fb, &crtc->state->mode,
+ old_state->src_x >> 16,
+ old_state->src_y >> 16);
+}
+
+static int vbox_primary_prepare_fb(struct drm_plane *plane,
+ struct drm_plane_state *new_state)
+{
+ struct vbox_bo *bo;
int ret;
- vbox_crtc_mode_set_base(crtc, x, y, old_fb);
+ if (!new_state->fb)
+ return 0;
- mutex_lock(&vbox->hw_mutex);
- ret = vbox_set_view(crtc);
- if (!ret)
- vbox_do_modeset(crtc, mode);
- hgsmi_update_input_mapping(vbox->guest_pool, 0, 0,
- vbox->input_mapping_width,
- vbox->input_mapping_height);
- mutex_unlock(&vbox->hw_mutex);
+ bo = gem_to_vbox_bo(to_vbox_framebuffer(new_state->fb)->obj);
+ ret = vbox_bo_pin(bo, TTM_PL_FLAG_VRAM);
+ if (ret)
+ DRM_WARN("Error %d pinning new fb, out of video mem?\n", ret);
return ret;
}
-static int vbox_crtc_page_flip(struct drm_crtc *crtc,
- struct drm_framebuffer *fb,
- struct drm_pending_vblank_event *event,
- uint32_t page_flip_flags,
- struct drm_modeset_acquire_ctx *ctx)
+static void vbox_primary_cleanup_fb(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
{
- struct vbox_private *vbox = crtc->dev->dev_private;
- struct drm_device *drm = vbox->dev;
- unsigned long flags;
- int rc;
+ struct vbox_bo *bo;
- rc = vbox_crtc_do_set_base(crtc, CRTC_FB(crtc), fb, 0, 0);
- if (rc)
- return rc;
+ if (!old_state->fb)
+ return;
- mutex_lock(&vbox->hw_mutex);
- vbox_set_view(crtc);
- vbox_do_modeset(crtc, &crtc->mode);
- mutex_unlock(&vbox->hw_mutex);
+ bo = gem_to_vbox_bo(to_vbox_framebuffer(old_state->fb)->obj);
+ vbox_bo_unpin(bo);
+}
- spin_lock_irqsave(&drm->event_lock, flags);
+static int vbox_cursor_atomic_check(struct drm_plane *plane,
+ struct drm_plane_state *new_state)
+{
+ struct drm_crtc_state *crtc_state = NULL;
+ u32 width = new_state->crtc_w;
+ u32 height = new_state->crtc_h;
+ int ret;
- if (event)
- drm_crtc_send_vblank_event(crtc, event);
+ if (new_state->crtc) {
+ crtc_state = drm_atomic_get_existing_crtc_state(
+ new_state->state, new_state->crtc);
+ if (WARN_ON(!crtc_state))
+ return -EINVAL;
+ }
- spin_unlock_irqrestore(&drm->event_lock, flags);
+ ret = drm_atomic_helper_check_plane_state(new_state, crtc_state,
+ DRM_PLANE_HELPER_NO_SCALING,
+ DRM_PLANE_HELPER_NO_SCALING,
+ true, true);
+ if (ret)
+ return ret;
+
+ if (!new_state->fb)
+ return 0;
+
+ if (width > VBOX_MAX_CURSOR_WIDTH || height > VBOX_MAX_CURSOR_HEIGHT ||
+ width == 0 || height == 0)
+ return -EINVAL;
return 0;
}
-static void vbox_crtc_disable(struct drm_crtc *crtc)
+/**
+ * Copy the ARGB image and generate the mask, which is needed in case the host
+ * does not support ARGB cursors. The mask is a 1BPP bitmap with the bit set
+ * if the corresponding alpha value in the ARGB image is greater than 0xF0.
+ */
+static void copy_cursor_image(u8 *src, u8 *dst, u32 width, u32 height,
+ size_t mask_size)
{
+ size_t line_size = (width + 7) / 8;
+ u32 i, j;
+
+ memcpy(dst + mask_size, src, width * height * 4);
+ for (i = 0; i < height; ++i)
+ for (j = 0; j < width; ++j)
+ if (((u32 *)src)[i * width + j] > 0xf0000000)
+ dst[i * line_size + j / 8] |= (0x80 >> (j % 8));
}
-static void vbox_crtc_prepare(struct drm_crtc *crtc)
+static void vbox_cursor_atomic_update(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
{
+ struct vbox_private *vbox =
+ container_of(plane->dev, struct vbox_private, ddev);
+ struct vbox_crtc *vbox_crtc = to_vbox_crtc(plane->state->crtc);
+ struct drm_framebuffer *fb = plane->state->fb;
+ struct vbox_bo *bo = gem_to_vbox_bo(to_vbox_framebuffer(fb)->obj);
+ u32 width = plane->state->crtc_w;
+ u32 height = plane->state->crtc_h;
+ size_t data_size, mask_size;
+ u32 flags;
+ u8 *src;
+
+ /*
+ * VirtualBox uses the host windowing system to draw the cursor so
+ * moves are a no-op, we only need to upload new cursor sprites.
+ */
+ if (fb == old_state->fb)
+ return;
+
+ mutex_lock(&vbox->hw_mutex);
+
+ vbox_crtc->cursor_enabled = true;
+
+ /* pinning is done in prepare/cleanup framebuffer */
+ src = vbox_bo_kmap(bo);
+ if (IS_ERR(src)) {
+ mutex_unlock(&vbox->hw_mutex);
+ DRM_WARN("Could not kmap cursor bo, skipping update\n");
+ return;
+ }
+
+ /*
+ * The mask must be calculated based on the alpha
+ * channel, one bit per ARGB word, and must be 32-bit
+ * padded.
+ */
+ mask_size = ((width + 7) / 8 * height + 3) & ~3;
+ data_size = width * height * 4 + mask_size;
+
+ copy_cursor_image(src, vbox->cursor_data, width, height, mask_size);
+ vbox_bo_kunmap(bo);
+
+ flags = VBOX_MOUSE_POINTER_VISIBLE | VBOX_MOUSE_POINTER_SHAPE |
+ VBOX_MOUSE_POINTER_ALPHA;
+ hgsmi_update_pointer_shape(vbox->guest_pool, flags,
+ min_t(u32, max(fb->hot_x, 0), width),
+ min_t(u32, max(fb->hot_y, 0), height),
+ width, height, vbox->cursor_data, data_size);
+
+ mutex_unlock(&vbox->hw_mutex);
}
-static void vbox_crtc_commit(struct drm_crtc *crtc)
+static void vbox_cursor_atomic_disable(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
{
-}
+ struct vbox_private *vbox =
+ container_of(plane->dev, struct vbox_private, ddev);
+ struct vbox_crtc *vbox_crtc = to_vbox_crtc(old_state->crtc);
+ bool cursor_enabled = false;
+ struct drm_crtc *crtci;
-static const struct drm_crtc_helper_funcs vbox_crtc_helper_funcs = {
- .dpms = vbox_crtc_dpms,
- .mode_fixup = vbox_crtc_mode_fixup,
- .mode_set = vbox_crtc_mode_set,
- /* .mode_set_base = vbox_crtc_mode_set_base, */
- .disable = vbox_crtc_disable,
- .prepare = vbox_crtc_prepare,
- .commit = vbox_crtc_commit,
-};
+ mutex_lock(&vbox->hw_mutex);
-static void vbox_crtc_reset(struct drm_crtc *crtc)
+ vbox_crtc->cursor_enabled = false;
+
+ list_for_each_entry(crtci, &vbox->ddev.mode_config.crtc_list, head) {
+ if (to_vbox_crtc(crtci)->cursor_enabled)
+ cursor_enabled = true;
+ }
+
+ if (!cursor_enabled)
+ hgsmi_update_pointer_shape(vbox->guest_pool, 0, 0, 0,
+ 0, 0, NULL, 0);
+
+ mutex_unlock(&vbox->hw_mutex);
+}
+
+static int vbox_cursor_prepare_fb(struct drm_plane *plane,
+ struct drm_plane_state *new_state)
{
+ struct vbox_bo *bo;
+
+ if (!new_state->fb)
+ return 0;
+
+ bo = gem_to_vbox_bo(to_vbox_framebuffer(new_state->fb)->obj);
+ return vbox_bo_pin(bo, TTM_PL_FLAG_SYSTEM);
}
-static void vbox_crtc_destroy(struct drm_crtc *crtc)
+static void vbox_cursor_cleanup_fb(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
{
- drm_crtc_cleanup(crtc);
- kfree(crtc);
+ struct vbox_bo *bo;
+
+ if (!plane->state->fb)
+ return;
+
+ bo = gem_to_vbox_bo(to_vbox_framebuffer(plane->state->fb)->obj);
+ vbox_bo_unpin(bo);
}
-static const struct drm_crtc_funcs vbox_crtc_funcs = {
- .cursor_move = vbox_cursor_move,
- .cursor_set2 = vbox_cursor_set2,
- .reset = vbox_crtc_reset,
- .set_config = drm_crtc_helper_set_config,
- /* .gamma_set = vbox_crtc_gamma_set, */
- .page_flip = vbox_crtc_page_flip,
- .destroy = vbox_crtc_destroy,
+static const uint32_t vbox_cursor_plane_formats[] = {
+ DRM_FORMAT_ARGB8888,
};
+static const struct drm_plane_helper_funcs vbox_cursor_helper_funcs = {
+ .atomic_check = vbox_cursor_atomic_check,
+ .atomic_update = vbox_cursor_atomic_update,
+ .atomic_disable = vbox_cursor_atomic_disable,
+ .prepare_fb = vbox_cursor_prepare_fb,
+ .cleanup_fb = vbox_cursor_cleanup_fb,
+};
+
+static const struct drm_plane_funcs vbox_cursor_plane_funcs = {
+ .update_plane = drm_atomic_helper_update_plane,
+ .disable_plane = drm_atomic_helper_disable_plane,
+ .destroy = drm_primary_helper_destroy,
+ .reset = drm_atomic_helper_plane_reset,
+ .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+};
+
+static const uint32_t vbox_primary_plane_formats[] = {
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_ARGB8888,
+};
+
+static const struct drm_plane_helper_funcs vbox_primary_helper_funcs = {
+ .atomic_check = vbox_primary_atomic_check,
+ .atomic_update = vbox_primary_atomic_update,
+ .atomic_disable = vbox_primary_atomic_disable,
+ .prepare_fb = vbox_primary_prepare_fb,
+ .cleanup_fb = vbox_primary_cleanup_fb,
+};
+
+static const struct drm_plane_funcs vbox_primary_plane_funcs = {
+ .update_plane = drm_atomic_helper_update_plane,
+ .disable_plane = drm_atomic_helper_disable_plane,
+ .destroy = drm_primary_helper_destroy,
+ .reset = drm_atomic_helper_plane_reset,
+ .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+};
+
+static struct drm_plane *vbox_create_plane(struct vbox_private *vbox,
+ unsigned int possible_crtcs,
+ enum drm_plane_type type)
+{
+ const struct drm_plane_helper_funcs *helper_funcs = NULL;
+ const struct drm_plane_funcs *funcs;
+ struct drm_plane *plane;
+ const uint32_t *formats;
+ int num_formats;
+ int err;
+
+ if (type == DRM_PLANE_TYPE_PRIMARY) {
+ funcs = &vbox_primary_plane_funcs;
+ formats = vbox_primary_plane_formats;
+ helper_funcs = &vbox_primary_helper_funcs;
+ num_formats = ARRAY_SIZE(vbox_primary_plane_formats);
+ } else if (type == DRM_PLANE_TYPE_CURSOR) {
+ funcs = &vbox_cursor_plane_funcs;
+ formats = vbox_cursor_plane_formats;
+ helper_funcs = &vbox_cursor_helper_funcs;
+ num_formats = ARRAY_SIZE(vbox_cursor_plane_formats);
+ } else {
+ return ERR_PTR(-EINVAL);
+ }
+
+ plane = kzalloc(sizeof(*plane), GFP_KERNEL);
+ if (!plane)
+ return ERR_PTR(-ENOMEM);
+
+ err = drm_universal_plane_init(&vbox->ddev, plane, possible_crtcs,
+ funcs, formats, num_formats,
+ NULL, type, NULL);
+ if (err)
+ goto free_plane;
+
+ drm_plane_helper_add(plane, helper_funcs);
+
+ return plane;
+
+free_plane:
+ kfree(plane);
+ return ERR_PTR(-EINVAL);
+}
+
static struct vbox_crtc *vbox_crtc_init(struct drm_device *dev, unsigned int i)
{
+ struct vbox_private *vbox =
+ container_of(dev, struct vbox_private, ddev);
+ struct drm_plane *cursor = NULL;
struct vbox_crtc *vbox_crtc;
+ struct drm_plane *primary;
+ u32 caps = 0;
+ int ret;
+
+ ret = hgsmi_query_conf(vbox->guest_pool,
+ VBOX_VBVA_CONF32_CURSOR_CAPABILITIES, &caps);
+ if (ret)
+ return ERR_PTR(ret);
vbox_crtc = kzalloc(sizeof(*vbox_crtc), GFP_KERNEL);
if (!vbox_crtc)
- return NULL;
+ return ERR_PTR(-ENOMEM);
+
+ primary = vbox_create_plane(vbox, 1 << i, DRM_PLANE_TYPE_PRIMARY);
+ if (IS_ERR(primary)) {
+ ret = PTR_ERR(primary);
+ goto free_mem;
+ }
+
+ if ((caps & VBOX_VBVA_CURSOR_CAPABILITY_HARDWARE)) {
+ cursor = vbox_create_plane(vbox, 1 << i, DRM_PLANE_TYPE_CURSOR);
+ if (IS_ERR(cursor)) {
+ ret = PTR_ERR(cursor);
+ goto clean_primary;
+ }
+ } else {
+ DRM_WARN("VirtualBox host is too old, no cursor support\n");
+ }
vbox_crtc->crtc_id = i;
- drm_crtc_init(dev, &vbox_crtc->base, &vbox_crtc_funcs);
+ ret = drm_crtc_init_with_planes(dev, &vbox_crtc->base, primary, cursor,
+ &vbox_crtc_funcs, NULL);
+ if (ret)
+ goto clean_cursor;
+
drm_mode_crtc_set_gamma_size(&vbox_crtc->base, 256);
drm_crtc_helper_add(&vbox_crtc->base, &vbox_crtc_helper_funcs);
return vbox_crtc;
+
+clean_cursor:
+ if (cursor) {
+ drm_plane_cleanup(cursor);
+ kfree(cursor);
+ }
+clean_primary:
+ drm_plane_cleanup(primary);
+ kfree(primary);
+free_mem:
+ kfree(vbox_crtc);
+ return ERR_PTR(ret);
}
static void vbox_encoder_destroy(struct drm_encoder *encoder)
@@ -403,55 +652,10 @@ static void vbox_encoder_destroy(struct drm_encoder *encoder)
kfree(encoder);
}
-static struct drm_encoder *vbox_best_single_encoder(struct drm_connector
- *connector)
-{
- int enc_id = connector->encoder_ids[0];
-
- /* pick the encoder ids */
- if (enc_id)
- return drm_encoder_find(connector->dev, NULL, enc_id);
-
- return NULL;
-}
-
static const struct drm_encoder_funcs vbox_enc_funcs = {
.destroy = vbox_encoder_destroy,
};
-static void vbox_encoder_dpms(struct drm_encoder *encoder, int mode)
-{
-}
-
-static bool vbox_mode_fixup(struct drm_encoder *encoder,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
-{
- return true;
-}
-
-static void vbox_encoder_mode_set(struct drm_encoder *encoder,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
-{
-}
-
-static void vbox_encoder_prepare(struct drm_encoder *encoder)
-{
-}
-
-static void vbox_encoder_commit(struct drm_encoder *encoder)
-{
-}
-
-static const struct drm_encoder_helper_funcs vbox_enc_helper_funcs = {
- .dpms = vbox_encoder_dpms,
- .mode_fixup = vbox_mode_fixup,
- .prepare = vbox_encoder_prepare,
- .commit = vbox_encoder_commit,
- .mode_set = vbox_encoder_mode_set,
-};
-
static struct drm_encoder *vbox_encoder_init(struct drm_device *dev,
unsigned int i)
{
@@ -463,7 +667,6 @@ static struct drm_encoder *vbox_encoder_init(struct drm_device *dev,
drm_encoder_init(dev, &vbox_encoder->base, &vbox_enc_funcs,
DRM_MODE_ENCODER_DAC, NULL);
- drm_encoder_helper_add(&vbox_encoder->base, &vbox_enc_helper_funcs);
vbox_encoder->base.possible_crtcs = 1 << i;
return &vbox_encoder->base;
@@ -589,29 +792,23 @@ static int vbox_get_modes(struct drm_connector *connector)
if (vbox_connector->vbox_crtc->x_hint != -1)
drm_object_property_set_value(&connector->base,
- vbox->dev->mode_config.suggested_x_property,
+ vbox->ddev.mode_config.suggested_x_property,
vbox_connector->vbox_crtc->x_hint);
else
drm_object_property_set_value(&connector->base,
- vbox->dev->mode_config.suggested_x_property, 0);
+ vbox->ddev.mode_config.suggested_x_property, 0);
if (vbox_connector->vbox_crtc->y_hint != -1)
drm_object_property_set_value(&connector->base,
- vbox->dev->mode_config.suggested_y_property,
+ vbox->ddev.mode_config.suggested_y_property,
vbox_connector->vbox_crtc->y_hint);
else
drm_object_property_set_value(&connector->base,
- vbox->dev->mode_config.suggested_y_property, 0);
+ vbox->ddev.mode_config.suggested_y_property, 0);
return num_modes;
}
-static enum drm_mode_status vbox_mode_valid(struct drm_connector *connector,
- struct drm_display_mode *mode)
-{
- return MODE_OK;
-}
-
static void vbox_connector_destroy(struct drm_connector *connector)
{
drm_connector_unregister(connector);
@@ -648,16 +845,16 @@ static int vbox_fill_modes(struct drm_connector *connector, u32 max_x,
}
static const struct drm_connector_helper_funcs vbox_connector_helper_funcs = {
- .mode_valid = vbox_mode_valid,
.get_modes = vbox_get_modes,
- .best_encoder = vbox_best_single_encoder,
};
static const struct drm_connector_funcs vbox_connector_funcs = {
- .dpms = drm_helper_connector_dpms,
.detect = vbox_connector_detect,
.fill_modes = vbox_fill_modes,
.destroy = vbox_connector_destroy,
+ .reset = drm_atomic_helper_connector_reset,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
static int vbox_connector_init(struct drm_device *dev,
@@ -686,225 +883,92 @@ static int vbox_connector_init(struct drm_device *dev,
dev->mode_config.suggested_x_property, 0);
drm_object_attach_property(&connector->base,
dev->mode_config.suggested_y_property, 0);
- drm_connector_register(connector);
drm_connector_attach_encoder(connector, encoder);
return 0;
}
-int vbox_mode_init(struct drm_device *dev)
+static struct drm_framebuffer *vbox_user_framebuffer_create(
+ struct drm_device *dev,
+ struct drm_file *filp,
+ const struct drm_mode_fb_cmd2 *mode_cmd)
{
- struct vbox_private *vbox = dev->dev_private;
- struct drm_encoder *encoder;
- struct vbox_crtc *vbox_crtc;
- unsigned int i;
- int ret;
+ struct vbox_private *vbox =
+ container_of(dev, struct vbox_private, ddev);
+ struct drm_gem_object *obj;
+ struct vbox_framebuffer *vbox_fb;
+ int ret = -ENOMEM;
- /* vbox_cursor_init(dev); */
- for (i = 0; i < vbox->num_crtcs; ++i) {
- vbox_crtc = vbox_crtc_init(dev, i);
- if (!vbox_crtc)
- return -ENOMEM;
- encoder = vbox_encoder_init(dev, i);
- if (!encoder)
- return -ENOMEM;
- ret = vbox_connector_init(dev, vbox_crtc, encoder);
- if (ret)
- return ret;
- }
+ obj = drm_gem_object_lookup(filp, mode_cmd->handles[0]);
+ if (!obj)
+ return ERR_PTR(-ENOENT);
- return 0;
-}
+ vbox_fb = kzalloc(sizeof(*vbox_fb), GFP_KERNEL);
+ if (!vbox_fb)
+ goto err_unref_obj;
-void vbox_mode_fini(struct drm_device *dev)
-{
- /* vbox_cursor_fini(dev); */
-}
+ ret = vbox_framebuffer_init(vbox, vbox_fb, mode_cmd, obj);
+ if (ret)
+ goto err_free_vbox_fb;
-/**
- * Copy the ARGB image and generate the mask, which is needed in case the host
- * does not support ARGB cursors. The mask is a 1BPP bitmap with the bit set
- * if the corresponding alpha value in the ARGB image is greater than 0xF0.
- */
-static void copy_cursor_image(u8 *src, u8 *dst, u32 width, u32 height,
- size_t mask_size)
-{
- size_t line_size = (width + 7) / 8;
- u32 i, j;
+ return &vbox_fb->base;
- memcpy(dst + mask_size, src, width * height * 4);
- for (i = 0; i < height; ++i)
- for (j = 0; j < width; ++j)
- if (((u32 *)src)[i * width + j] > 0xf0000000)
- dst[i * line_size + j / 8] |= (0x80 >> (j % 8));
+err_free_vbox_fb:
+ kfree(vbox_fb);
+err_unref_obj:
+ drm_gem_object_put_unlocked(obj);
+ return ERR_PTR(ret);
}
-static int vbox_cursor_set2(struct drm_crtc *crtc, struct drm_file *file_priv,
- u32 handle, u32 width, u32 height,
- s32 hot_x, s32 hot_y)
+static const struct drm_mode_config_funcs vbox_mode_funcs = {
+ .fb_create = vbox_user_framebuffer_create,
+ .atomic_check = drm_atomic_helper_check,
+ .atomic_commit = drm_atomic_helper_commit,
+};
+
+int vbox_mode_init(struct vbox_private *vbox)
{
- struct vbox_private *vbox = crtc->dev->dev_private;
- struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
- struct ttm_bo_kmap_obj uobj_map;
- size_t data_size, mask_size;
- struct drm_gem_object *obj;
- u32 flags, caps = 0;
- struct vbox_bo *bo;
- bool src_isiomem;
- u8 *dst = NULL;
- u8 *src;
+ struct drm_device *dev = &vbox->ddev;
+ struct drm_encoder *encoder;
+ struct vbox_crtc *vbox_crtc;
+ unsigned int i;
int ret;
- /*
- * Re-set this regularly as in 5.0.20 and earlier the information was
- * lost on save and restore.
- */
- hgsmi_update_input_mapping(vbox->guest_pool, 0, 0,
- vbox->input_mapping_width,
- vbox->input_mapping_height);
- if (!handle) {
- bool cursor_enabled = false;
- struct drm_crtc *crtci;
-
- /* Hide cursor. */
- vbox_crtc->cursor_enabled = false;
- list_for_each_entry(crtci, &vbox->dev->mode_config.crtc_list,
- head) {
- if (to_vbox_crtc(crtci)->cursor_enabled)
- cursor_enabled = true;
- }
-
- if (!cursor_enabled)
- hgsmi_update_pointer_shape(vbox->guest_pool, 0, 0, 0,
- 0, 0, NULL, 0);
- return 0;
- }
-
- vbox_crtc->cursor_enabled = true;
-
- if (width > VBOX_MAX_CURSOR_WIDTH || height > VBOX_MAX_CURSOR_HEIGHT ||
- width == 0 || height == 0)
- return -EINVAL;
-
- ret = hgsmi_query_conf(vbox->guest_pool,
- VBOX_VBVA_CONF32_CURSOR_CAPABILITIES, &caps);
- if (ret)
- return ret;
-
- if (!(caps & VBOX_VBVA_CURSOR_CAPABILITY_HARDWARE)) {
- /*
- * -EINVAL means cursor_set2() not supported, -EAGAIN means
- * retry at once.
- */
- return -EBUSY;
- }
-
- obj = drm_gem_object_lookup(file_priv, handle);
- if (!obj) {
- DRM_ERROR("Cannot find cursor object %x for crtc\n", handle);
- return -ENOENT;
- }
+ drm_mode_config_init(dev);
- bo = gem_to_vbox_bo(obj);
- ret = vbox_bo_reserve(bo, false);
- if (ret)
- goto out_unref_obj;
+ dev->mode_config.funcs = (void *)&vbox_mode_funcs;
+ dev->mode_config.min_width = 0;
+ dev->mode_config.min_height = 0;
+ dev->mode_config.preferred_depth = 24;
+ dev->mode_config.max_width = VBE_DISPI_MAX_XRES;
+ dev->mode_config.max_height = VBE_DISPI_MAX_YRES;
- /*
- * The mask must be calculated based on the alpha
- * channel, one bit per ARGB word, and must be 32-bit
- * padded.
- */
- mask_size = ((width + 7) / 8 * height + 3) & ~3;
- data_size = width * height * 4 + mask_size;
- vbox->cursor_hot_x = min_t(u32, max(hot_x, 0), width);
- vbox->cursor_hot_y = min_t(u32, max(hot_y, 0), height);
- vbox->cursor_width = width;
- vbox->cursor_height = height;
- vbox->cursor_data_size = data_size;
- dst = vbox->cursor_data;
-
- ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &uobj_map);
- if (ret) {
- vbox->cursor_data_size = 0;
- goto out_unreserve_bo;
- }
-
- src = ttm_kmap_obj_virtual(&uobj_map, &src_isiomem);
- if (src_isiomem) {
- DRM_ERROR("src cursor bo not in main memory\n");
- ret = -EIO;
- goto out_unmap_bo;
+ for (i = 0; i < vbox->num_crtcs; ++i) {
+ vbox_crtc = vbox_crtc_init(dev, i);
+ if (IS_ERR(vbox_crtc)) {
+ ret = PTR_ERR(vbox_crtc);
+ goto err_drm_mode_cleanup;
+ }
+ encoder = vbox_encoder_init(dev, i);
+ if (!encoder) {
+ ret = -ENOMEM;
+ goto err_drm_mode_cleanup;
+ }
+ ret = vbox_connector_init(dev, vbox_crtc, encoder);
+ if (ret)
+ goto err_drm_mode_cleanup;
}
- copy_cursor_image(src, dst, width, height, mask_size);
-
- flags = VBOX_MOUSE_POINTER_VISIBLE | VBOX_MOUSE_POINTER_SHAPE |
- VBOX_MOUSE_POINTER_ALPHA;
- ret = hgsmi_update_pointer_shape(vbox->guest_pool, flags,
- vbox->cursor_hot_x, vbox->cursor_hot_y,
- width, height, dst, data_size);
-out_unmap_bo:
- ttm_bo_kunmap(&uobj_map);
-out_unreserve_bo:
- vbox_bo_unreserve(bo);
-out_unref_obj:
- drm_gem_object_put_unlocked(obj);
+ drm_mode_config_reset(dev);
+ return 0;
+err_drm_mode_cleanup:
+ drm_mode_config_cleanup(dev);
return ret;
}
-static int vbox_cursor_move(struct drm_crtc *crtc, int x, int y)
+void vbox_mode_fini(struct vbox_private *vbox)
{
- struct vbox_private *vbox = crtc->dev->dev_private;
- u32 flags = VBOX_MOUSE_POINTER_VISIBLE |
- VBOX_MOUSE_POINTER_SHAPE | VBOX_MOUSE_POINTER_ALPHA;
- s32 crtc_x =
- vbox->single_framebuffer ? crtc->x : to_vbox_crtc(crtc)->x_hint;
- s32 crtc_y =
- vbox->single_framebuffer ? crtc->y : to_vbox_crtc(crtc)->y_hint;
- u32 host_x, host_y;
- u32 hot_x = 0;
- u32 hot_y = 0;
- int ret;
-
- /*
- * We compare these to unsigned later and don't
- * need to handle negative.
- */
- if (x + crtc_x < 0 || y + crtc_y < 0 || vbox->cursor_data_size == 0)
- return 0;
-
- ret = hgsmi_cursor_position(vbox->guest_pool, true, x + crtc_x,
- y + crtc_y, &host_x, &host_y);
-
- /*
- * The only reason we have vbox_cursor_move() is that some older clients
- * might use DRM_IOCTL_MODE_CURSOR instead of DRM_IOCTL_MODE_CURSOR2 and
- * use DRM_MODE_CURSOR_MOVE to set the hot-spot.
- *
- * However VirtualBox 5.0.20 and earlier has a bug causing it to return
- * 0,0 as host cursor location after a save and restore.
- *
- * To work around this we ignore a 0, 0 return, since missing the odd
- * time when it legitimately happens is not going to hurt much.
- */
- if (ret || (host_x == 0 && host_y == 0))
- return ret;
-
- if (x + crtc_x < host_x)
- hot_x = min(host_x - x - crtc_x, vbox->cursor_width);
- if (y + crtc_y < host_y)
- hot_y = min(host_y - y - crtc_y, vbox->cursor_height);
-
- if (hot_x == vbox->cursor_hot_x && hot_y == vbox->cursor_hot_y)
- return 0;
-
- vbox->cursor_hot_x = hot_x;
- vbox->cursor_hot_y = hot_y;
-
- return hgsmi_update_pointer_shape(vbox->guest_pool, flags,
- hot_x, hot_y, vbox->cursor_width, vbox->cursor_height,
- vbox->cursor_data, vbox->cursor_data_size);
+ drm_mode_config_cleanup(&vbox->ddev);
}
diff --git a/drivers/staging/vboxvideo/vbox_ttm.c b/drivers/staging/vboxvideo/vbox_ttm.c
index 548edb7c494b..b36ec019c332 100644
--- a/drivers/staging/vboxvideo/vbox_ttm.c
+++ b/drivers/staging/vboxvideo/vbox_ttm.c
@@ -35,61 +35,6 @@ static inline struct vbox_private *vbox_bdev(struct ttm_bo_device *bd)
return container_of(bd, struct vbox_private, ttm.bdev);
}
-static int vbox_ttm_mem_global_init(struct drm_global_reference *ref)
-{
- return ttm_mem_global_init(ref->object);
-}
-
-static void vbox_ttm_mem_global_release(struct drm_global_reference *ref)
-{
- ttm_mem_global_release(ref->object);
-}
-
-/**
- * Adds the vbox memory manager object/structures to the global memory manager.
- */
-static int vbox_ttm_global_init(struct vbox_private *vbox)
-{
- struct drm_global_reference *global_ref;
- int ret;
-
- global_ref = &vbox->ttm.mem_global_ref;
- global_ref->global_type = DRM_GLOBAL_TTM_MEM;
- global_ref->size = sizeof(struct ttm_mem_global);
- global_ref->init = &vbox_ttm_mem_global_init;
- global_ref->release = &vbox_ttm_mem_global_release;
- ret = drm_global_item_ref(global_ref);
- if (ret) {
- DRM_ERROR("Failed setting up TTM memory subsystem.\n");
- return ret;
- }
-
- vbox->ttm.bo_global_ref.mem_glob = vbox->ttm.mem_global_ref.object;
- global_ref = &vbox->ttm.bo_global_ref.ref;
- global_ref->global_type = DRM_GLOBAL_TTM_BO;
- global_ref->size = sizeof(struct ttm_bo_global);
- global_ref->init = &ttm_bo_global_init;
- global_ref->release = &ttm_bo_global_release;
-
- ret = drm_global_item_ref(global_ref);
- if (ret) {
- DRM_ERROR("Failed setting up TTM BO subsystem.\n");
- drm_global_item_unref(&vbox->ttm.mem_global_ref);
- return ret;
- }
-
- return 0;
-}
-
-/**
- * Removes the vbox memory manager object from the global memory manager.
- */
-static void vbox_ttm_global_release(struct vbox_private *vbox)
-{
- drm_global_item_unref(&vbox->ttm.bo_global_ref.ref);
- drm_global_item_unref(&vbox->ttm.mem_global_ref);
-}
-
static void vbox_bo_ttm_destroy(struct ttm_buffer_object *tbo)
{
struct vbox_bo *bo;
@@ -169,7 +114,7 @@ static int vbox_ttm_io_mem_reserve(struct ttm_bo_device *bdev,
return 0;
case TTM_PL_VRAM:
mem->bus.offset = mem->start << PAGE_SHIFT;
- mem->bus.base = pci_resource_start(vbox->dev->pdev, 0);
+ mem->bus.base = pci_resource_start(vbox->ddev.pdev, 0);
mem->bus.is_iomem = true;
break;
default:
@@ -224,21 +169,16 @@ static struct ttm_bo_driver vbox_bo_driver = {
int vbox_mm_init(struct vbox_private *vbox)
{
int ret;
- struct drm_device *dev = vbox->dev;
+ struct drm_device *dev = &vbox->ddev;
struct ttm_bo_device *bdev = &vbox->ttm.bdev;
- ret = vbox_ttm_global_init(vbox);
- if (ret)
- return ret;
-
ret = ttm_bo_device_init(&vbox->ttm.bdev,
- vbox->ttm.bo_global_ref.ref.object,
&vbox_bo_driver,
dev->anon_inode->i_mapping,
DRM_FILE_PAGE_OFFSET, true);
if (ret) {
DRM_ERROR("Error initialising bo driver; %d\n", ret);
- goto err_ttm_global_release;
+ return ret;
}
ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM,
@@ -260,8 +200,6 @@ int vbox_mm_init(struct vbox_private *vbox)
err_device_release:
ttm_bo_device_release(&vbox->ttm.bdev);
-err_ttm_global_release:
- vbox_ttm_global_release(vbox);
return ret;
}
@@ -269,13 +207,12 @@ void vbox_mm_fini(struct vbox_private *vbox)
{
#ifdef DRM_MTRR_WC
drm_mtrr_del(vbox->fb_mtrr,
- pci_resource_start(vbox->dev->pdev, 0),
- pci_resource_len(vbox->dev->pdev, 0), DRM_MTRR_WC);
+ pci_resource_start(vbox->ddev.pdev, 0),
+ pci_resource_len(vbox->ddev.pdev, 0), DRM_MTRR_WC);
#else
arch_phys_wc_del(vbox->fb_mtrr);
#endif
ttm_bo_device_release(&vbox->ttm.bdev);
- vbox_ttm_global_release(vbox);
}
void vbox_ttm_placement(struct vbox_bo *bo, int domain)
@@ -305,10 +242,9 @@ void vbox_ttm_placement(struct vbox_bo *bo, int domain)
}
}
-int vbox_bo_create(struct drm_device *dev, int size, int align,
+int vbox_bo_create(struct vbox_private *vbox, int size, int align,
u32 flags, struct vbox_bo **pvboxbo)
{
- struct vbox_private *vbox = dev->dev_private;
struct vbox_bo *vboxbo;
size_t acc_size;
int ret;
@@ -317,7 +253,7 @@ int vbox_bo_create(struct drm_device *dev, int size, int align,
if (!vboxbo)
return -ENOMEM;
- ret = drm_gem_object_init(dev, &vboxbo->gem, size);
+ ret = drm_gem_object_init(&vbox->ddev, &vboxbo->gem, size);
if (ret)
goto err_free_vboxbo;
@@ -344,39 +280,32 @@ err_free_vboxbo:
return ret;
}
-static inline u64 vbox_bo_gpu_offset(struct vbox_bo *bo)
-{
- return bo->bo.offset;
-}
-
-int vbox_bo_pin(struct vbox_bo *bo, u32 pl_flag, u64 *gpu_addr)
+int vbox_bo_pin(struct vbox_bo *bo, u32 pl_flag)
{
struct ttm_operation_ctx ctx = { false, false };
int i, ret;
if (bo->pin_count) {
bo->pin_count++;
- if (gpu_addr)
- *gpu_addr = vbox_bo_gpu_offset(bo);
-
return 0;
}
+ ret = vbox_bo_reserve(bo, false);
+ if (ret)
+ return ret;
+
vbox_ttm_placement(bo, pl_flag);
for (i = 0; i < bo->placement.num_placement; i++)
bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT;
ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx);
- if (ret)
- return ret;
-
- bo->pin_count = 1;
+ if (ret == 0)
+ bo->pin_count = 1;
- if (gpu_addr)
- *gpu_addr = vbox_bo_gpu_offset(bo);
+ vbox_bo_unreserve(bo);
- return 0;
+ return ret;
}
int vbox_bo_unpin(struct vbox_bo *bo)
@@ -392,14 +321,20 @@ int vbox_bo_unpin(struct vbox_bo *bo)
if (bo->pin_count)
return 0;
+ ret = vbox_bo_reserve(bo, false);
+ if (ret) {
+ DRM_ERROR("Error %d reserving bo, leaving it pinned\n", ret);
+ return ret;
+ }
+
for (i = 0; i < bo->placement.num_placement; i++)
bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT;
ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx);
- if (ret)
- return ret;
- return 0;
+ vbox_bo_unreserve(bo);
+
+ return ret;
}
/*
@@ -420,8 +355,10 @@ int vbox_bo_push_sysram(struct vbox_bo *bo)
if (bo->pin_count)
return 0;
- if (bo->kmap.virtual)
+ if (bo->kmap.virtual) {
ttm_bo_kunmap(&bo->kmap);
+ bo->kmap.virtual = NULL;
+ }
vbox_ttm_placement(bo, TTM_PL_FLAG_SYSTEM);
@@ -450,3 +387,27 @@ int vbox_mmap(struct file *filp, struct vm_area_struct *vma)
return ttm_bo_mmap(filp, vma, &vbox->ttm.bdev);
}
+
+void *vbox_bo_kmap(struct vbox_bo *bo)
+{
+ int ret;
+
+ if (bo->kmap.virtual)
+ return bo->kmap.virtual;
+
+ ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
+ if (ret) {
+ DRM_ERROR("Error kmapping bo: %d\n", ret);
+ return NULL;
+ }
+
+ return bo->kmap.virtual;
+}
+
+void vbox_bo_kunmap(struct vbox_bo *bo)
+{
+ if (bo->kmap.virtual) {
+ ttm_bo_kunmap(&bo->kmap);
+ bo->kmap.virtual = NULL;
+ }
+}
diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c
index ec468d5719b1..a6ec72a5f0be 100644
--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c
+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c
@@ -1,23 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright 2011 Broadcom Corporation. All rights reserved. */
-#include <linux/platform_device.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/jiffies.h>
-#include <linux/slab.h>
-#include <linux/time.h>
-#include <linux/wait.h>
-#include <linux/delay.h>
-#include <linux/moduleparam.h>
-#include <linux/sched.h>
-
#include <sound/core.h>
#include <sound/control.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/rawmidi.h>
-#include <sound/initval.h>
#include <sound/tlv.h>
#include <sound/asoundef.h>
@@ -27,6 +12,21 @@
#define CTRL_VOL_MAX 400
#define CTRL_VOL_MIN -10239 /* originally -10240 */
+static int bcm2835_audio_set_chip_ctls(struct bcm2835_chip *chip)
+{
+ int i, err = 0;
+
+ /* change ctls for all substreams */
+ for (i = 0; i < MAX_SUBSTREAMS; i++) {
+ if (chip->alsa_stream[i]) {
+ err = bcm2835_audio_set_ctls(chip->alsa_stream[i]);
+ if (err < 0)
+ break;
+ }
+ }
+ return err;
+}
+
static int snd_bcm2835_ctl_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
@@ -49,41 +49,15 @@ static int snd_bcm2835_ctl_info(struct snd_kcontrol *kcontrol,
return 0;
}
-/* toggles mute on or off depending on the value of nmute, and returns
- * 1 if the mute value was changed, otherwise 0
- */
-static int toggle_mute(struct bcm2835_chip *chip, int nmute)
-{
- /* if settings are ok, just return 0 */
- if (chip->mute == nmute)
- return 0;
-
- /* if the sound is muted then we need to unmute */
- if (chip->mute == CTRL_VOL_MUTE) {
- chip->volume = chip->old_volume; /* copy the old volume back */
- audio_info("Unmuting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
- } else /* otherwise we mute */ {
- chip->old_volume = chip->volume;
- chip->volume = 26214; /* set volume to minimum level AKA mute */
- audio_info("Muting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
- }
-
- chip->mute = nmute;
- return 1;
-}
-
static int snd_bcm2835_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
- if (mutex_lock_interruptible(&chip->audio_mutex))
- return -EINTR;
-
- BUG_ON(!chip && !(chip->avail_substreams & AVAIL_SUBSTREAMS_MASK));
+ mutex_lock(&chip->audio_mutex);
if (kcontrol->private_value == PCM_PLAYBACK_VOLUME)
- ucontrol->value.integer.value[0] = chip2alsa(chip->volume);
+ ucontrol->value.integer.value[0] = chip->volume;
else if (kcontrol->private_value == PCM_PLAYBACK_MUTE)
ucontrol->value.integer.value[0] = chip->mute;
else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE)
@@ -97,79 +71,60 @@ static int snd_bcm2835_ctl_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
+ int val, *valp;
int changed = 0;
- if (mutex_lock_interruptible(&chip->audio_mutex))
- return -EINTR;
-
- if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
- audio_info("Volume change attempted.. volume = %d new_volume = %d\n", chip->volume, (int)ucontrol->value.integer.value[0]);
- if (chip->mute == CTRL_VOL_MUTE) {
- /* changed = toggle_mute(chip, CTRL_VOL_UNMUTE); */
- changed = 1; /* should return 0 to signify no change but the mixer takes this as the opposite sign (no idea why) */
- goto unlock;
- }
- if (changed || (ucontrol->value.integer.value[0] != chip2alsa(chip->volume))) {
- chip->volume = alsa2chip(ucontrol->value.integer.value[0]);
- changed = 1;
- }
-
- } else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
- /* Now implemented */
- audio_info(" Mute attempted\n");
- changed = toggle_mute(chip, ucontrol->value.integer.value[0]);
-
- } else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
- if (ucontrol->value.integer.value[0] != chip->dest) {
- chip->dest = ucontrol->value.integer.value[0];
- changed = 1;
- }
+ if (kcontrol->private_value == PCM_PLAYBACK_VOLUME)
+ valp = &chip->volume;
+ else if (kcontrol->private_value == PCM_PLAYBACK_MUTE)
+ valp = &chip->mute;
+ else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE)
+ valp = &chip->dest;
+ else
+ return -EINVAL;
+
+ val = ucontrol->value.integer.value[0];
+ mutex_lock(&chip->audio_mutex);
+ if (val != *valp) {
+ *valp = val;
+ changed = 1;
+ if (bcm2835_audio_set_chip_ctls(chip))
+ dev_err(chip->card->dev, "Failed to set ALSA controls..\n");
}
-
- if (changed && bcm2835_audio_set_ctls(chip))
- dev_err(chip->card->dev, "Failed to set ALSA controls..\n");
-
-unlock:
mutex_unlock(&chip->audio_mutex);
return changed;
}
static DECLARE_TLV_DB_SCALE(snd_bcm2835_db_scale, CTRL_VOL_MIN, 1, 1);
-static struct snd_kcontrol_new snd_bcm2835_ctl[] = {
+static const struct snd_kcontrol_new snd_bcm2835_ctl[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "PCM Playback Volume",
- .index = 0,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
.private_value = PCM_PLAYBACK_VOLUME,
.info = snd_bcm2835_ctl_info,
.get = snd_bcm2835_ctl_get,
.put = snd_bcm2835_ctl_put,
- .count = 1,
.tlv = {.p = snd_bcm2835_db_scale}
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "PCM Playback Switch",
- .index = 0,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
.private_value = PCM_PLAYBACK_MUTE,
.info = snd_bcm2835_ctl_info,
.get = snd_bcm2835_ctl_get,
.put = snd_bcm2835_ctl_put,
- .count = 1,
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "PCM Playback Route",
- .index = 0,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
.private_value = PCM_PLAYBACK_DEVICE,
.info = snd_bcm2835_ctl_info,
.get = snd_bcm2835_ctl_get,
.put = snd_bcm2835_ctl_put,
- .count = 1,
},
};
@@ -187,8 +142,7 @@ static int snd_bcm2835_spdif_default_get(struct snd_kcontrol *kcontrol,
struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
int i;
- if (mutex_lock_interruptible(&chip->audio_mutex))
- return -EINTR;
+ mutex_lock(&chip->audio_mutex);
for (i = 0; i < 4; i++)
ucontrol->value.iec958.status[i] =
@@ -205,8 +159,7 @@ static int snd_bcm2835_spdif_default_put(struct snd_kcontrol *kcontrol,
unsigned int val = 0;
int i, change;
- if (mutex_lock_interruptible(&chip->audio_mutex))
- return -EINTR;
+ mutex_lock(&chip->audio_mutex);
for (i = 0; i < 4; i++)
val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
@@ -237,51 +190,7 @@ static int snd_bcm2835_spdif_mask_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static int snd_bcm2835_spdif_stream_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
- uinfo->count = 1;
- return 0;
-}
-
-static int snd_bcm2835_spdif_stream_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
- int i;
-
- if (mutex_lock_interruptible(&chip->audio_mutex))
- return -EINTR;
-
- for (i = 0; i < 4; i++)
- ucontrol->value.iec958.status[i] =
- (chip->spdif_status >> (i * 8)) & 0xff;
-
- mutex_unlock(&chip->audio_mutex);
- return 0;
-}
-
-static int snd_bcm2835_spdif_stream_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
- unsigned int val = 0;
- int i, change;
-
- if (mutex_lock_interruptible(&chip->audio_mutex))
- return -EINTR;
-
- for (i = 0; i < 4; i++)
- val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
- change = val != chip->spdif_status;
- chip->spdif_status = val;
-
- mutex_unlock(&chip->audio_mutex);
- return change;
-}
-
-static struct snd_kcontrol_new snd_bcm2835_spdif[] = {
+static const struct snd_kcontrol_new snd_bcm2835_spdif[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
@@ -296,39 +205,34 @@ static struct snd_kcontrol_new snd_bcm2835_spdif[] = {
.info = snd_bcm2835_spdif_mask_info,
.get = snd_bcm2835_spdif_mask_get,
},
- {
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
- SNDRV_CTL_ELEM_ACCESS_INACTIVE,
- .iface = SNDRV_CTL_ELEM_IFACE_PCM,
- .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM),
- .info = snd_bcm2835_spdif_stream_info,
- .get = snd_bcm2835_spdif_stream_get,
- .put = snd_bcm2835_spdif_stream_put,
- },
};
-int snd_bcm2835_new_ctl(struct bcm2835_chip *chip)
+static int create_ctls(struct bcm2835_chip *chip, size_t size,
+ const struct snd_kcontrol_new *kctls)
{
- int err;
- unsigned int idx;
+ int i, err;
- strcpy(chip->card->mixername, "Broadcom Mixer");
- for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_ctl); idx++) {
- err = snd_ctl_add(chip->card,
- snd_ctl_new1(&snd_bcm2835_ctl[idx], chip));
- if (err < 0)
- return err;
- }
- for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_spdif); idx++) {
- err = snd_ctl_add(chip->card,
- snd_ctl_new1(&snd_bcm2835_spdif[idx], chip));
+ for (i = 0; i < size; i++) {
+ err = snd_ctl_add(chip->card, snd_ctl_new1(&kctls[i], chip));
if (err < 0)
return err;
}
return 0;
}
-static struct snd_kcontrol_new snd_bcm2835_headphones_ctl[] = {
+int snd_bcm2835_new_ctl(struct bcm2835_chip *chip)
+{
+ int err;
+
+ strcpy(chip->card->mixername, "Broadcom Mixer");
+ err = create_ctls(chip, ARRAY_SIZE(snd_bcm2835_ctl), snd_bcm2835_ctl);
+ if (err < 0)
+ return err;
+ return create_ctls(chip, ARRAY_SIZE(snd_bcm2835_spdif),
+ snd_bcm2835_spdif);
+}
+
+static const struct snd_kcontrol_new snd_bcm2835_headphones_ctl[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Headphone Playback Volume",
@@ -357,21 +261,12 @@ static struct snd_kcontrol_new snd_bcm2835_headphones_ctl[] = {
int snd_bcm2835_new_headphones_ctl(struct bcm2835_chip *chip)
{
- int err;
- unsigned int idx;
-
strcpy(chip->card->mixername, "Broadcom Mixer");
- for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_headphones_ctl); idx++) {
- err = snd_ctl_add(chip->card,
- snd_ctl_new1(&snd_bcm2835_headphones_ctl[idx],
- chip));
- if (err)
- return err;
- }
- return 0;
+ return create_ctls(chip, ARRAY_SIZE(snd_bcm2835_headphones_ctl),
+ snd_bcm2835_headphones_ctl);
}
-static struct snd_kcontrol_new snd_bcm2835_hdmi[] = {
+static const struct snd_kcontrol_new snd_bcm2835_hdmi[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "HDMI Playback Volume",
@@ -400,16 +295,8 @@ static struct snd_kcontrol_new snd_bcm2835_hdmi[] = {
int snd_bcm2835_new_hdmi_ctl(struct bcm2835_chip *chip)
{
- int err;
- unsigned int idx;
-
strcpy(chip->card->mixername, "Broadcom Mixer");
- for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_hdmi); idx++) {
- err = snd_ctl_add(chip->card,
- snd_ctl_new1(&snd_bcm2835_hdmi[idx], chip));
- if (err)
- return err;
- }
- return 0;
+ return create_ctls(chip, ARRAY_SIZE(snd_bcm2835_hdmi),
+ snd_bcm2835_hdmi);
}
diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
index 8359cf881bef..e66da11af5cf 100644
--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
@@ -11,7 +11,8 @@
/* hardware definition */
static const struct snd_pcm_hardware snd_bcm2835_playback_hw = {
.info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_DRAIN_TRIGGER | SNDRV_PCM_INFO_SYNC_APPLPTR),
.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
.rate_min = 8000,
@@ -27,7 +28,8 @@ static const struct snd_pcm_hardware snd_bcm2835_playback_hw = {
static const struct snd_pcm_hardware snd_bcm2835_playback_spdif_hw = {
.info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_DRAIN_TRIGGER | SNDRV_PCM_INFO_SYNC_APPLPTR),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_44100 |
SNDRV_PCM_RATE_48000,
@@ -44,48 +46,37 @@ static const struct snd_pcm_hardware snd_bcm2835_playback_spdif_hw = {
static void snd_bcm2835_playback_free(struct snd_pcm_runtime *runtime)
{
- audio_info("Freeing up alsa stream here ..\n");
kfree(runtime->private_data);
- runtime->private_data = NULL;
}
-void bcm2835_playback_fifo(struct bcm2835_alsa_stream *alsa_stream)
+void bcm2835_playback_fifo(struct bcm2835_alsa_stream *alsa_stream,
+ unsigned int bytes)
{
- unsigned int consumed = 0;
- int new_period = 0;
-
- audio_info("alsa_stream=%p substream=%p\n", alsa_stream,
- alsa_stream ? alsa_stream->substream : 0);
-
- if (alsa_stream->open)
- consumed = bcm2835_audio_retrieve_buffers(alsa_stream);
-
- /* We get called only if playback was triggered, So, the number of buffers we retrieve in
- * each iteration are the buffers that have been played out already
- */
-
- if (alsa_stream->period_size) {
- if ((alsa_stream->pos / alsa_stream->period_size) !=
- ((alsa_stream->pos + consumed) / alsa_stream->period_size))
- new_period = 1;
- }
- audio_debug("updating pos cur: %d + %d max:%d period_bytes:%d, hw_ptr: %d new_period:%d\n",
- alsa_stream->pos,
- consumed,
- alsa_stream->buffer_size,
- (int) (alsa_stream->period_size * alsa_stream->substream->runtime->periods),
- frames_to_bytes(alsa_stream->substream->runtime, alsa_stream->substream->runtime->status->hw_ptr),
- new_period);
- if (alsa_stream->buffer_size) {
- alsa_stream->pos += consumed & ~(1 << 30);
- alsa_stream->pos %= alsa_stream->buffer_size;
+ struct snd_pcm_substream *substream = alsa_stream->substream;
+ unsigned int pos;
+
+ if (!alsa_stream->period_size)
+ return;
+
+ if (bytes >= alsa_stream->buffer_size) {
+ snd_pcm_stream_lock(substream);
+ snd_pcm_stop(substream,
+ alsa_stream->draining ?
+ SNDRV_PCM_STATE_SETUP :
+ SNDRV_PCM_STATE_XRUN);
+ snd_pcm_stream_unlock(substream);
+ return;
}
- if (alsa_stream->substream) {
- if (new_period)
- snd_pcm_period_elapsed(alsa_stream->substream);
- } else {
- audio_warning(" unexpected NULL substream\n");
+ pos = atomic_read(&alsa_stream->pos);
+ pos += bytes;
+ pos %= alsa_stream->buffer_size;
+ atomic_set(&alsa_stream->pos, pos);
+
+ alsa_stream->period_offset += bytes;
+ if (alsa_stream->period_offset >= alsa_stream->period_size) {
+ alsa_stream->period_offset %= alsa_stream->period_size;
+ snd_pcm_period_elapsed(substream);
}
}
@@ -99,11 +90,7 @@ static int snd_bcm2835_playback_open_generic(
int idx;
int err;
- if (mutex_lock_interruptible(&chip->audio_mutex)) {
- audio_error("Interrupted whilst waiting for lock\n");
- return -EINTR;
- }
- audio_info("Alsa open (%d)\n", substream->number);
+ mutex_lock(&chip->audio_mutex);
idx = substream->number;
if (spdif && chip->opened) {
@@ -114,21 +101,13 @@ static int snd_bcm2835_playback_open_generic(
goto out;
}
if (idx >= MAX_SUBSTREAMS) {
- audio_error
- ("substream(%d) device doesn't exist max(%d) substreams allowed\n",
+ dev_err(chip->dev,
+ "substream(%d) device doesn't exist max(%d) substreams allowed\n",
idx, MAX_SUBSTREAMS);
err = -ENODEV;
goto out;
}
- /* Check if we are ready */
- if (!(chip->avail_substreams & (1 << idx))) {
- /* We are not ready yet */
- audio_error("substream(%d) device is not ready yet\n", idx);
- err = -EAGAIN;
- goto out;
- }
-
alsa_stream = kzalloc(sizeof(*alsa_stream), GFP_KERNEL);
if (!alsa_stream) {
err = -ENOMEM;
@@ -140,8 +119,6 @@ static int snd_bcm2835_playback_open_generic(
alsa_stream->substream = substream;
alsa_stream->idx = idx;
- spin_lock_init(&alsa_stream->lock);
-
err = bcm2835_audio_open(alsa_stream);
if (err) {
kfree(alsa_stream);
@@ -162,11 +139,14 @@ static int snd_bcm2835_playback_open_generic(
SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
16);
+ /* position update is in 10ms order */
+ snd_pcm_hw_constraint_minmax(runtime,
+ SNDRV_PCM_HW_PARAM_PERIOD_TIME,
+ 10 * 1000, UINT_MAX);
+
chip->alsa_stream[idx] = alsa_stream;
chip->opened |= (1 << idx);
- alsa_stream->open = 1;
- alsa_stream->draining = 1;
out:
mutex_unlock(&chip->audio_mutex);
@@ -194,37 +174,15 @@ static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream)
struct bcm2835_alsa_stream *alsa_stream;
chip = snd_pcm_substream_chip(substream);
- if (mutex_lock_interruptible(&chip->audio_mutex)) {
- audio_error("Interrupted whilst waiting for lock\n");
- return -EINTR;
- }
+ mutex_lock(&chip->audio_mutex);
runtime = substream->runtime;
alsa_stream = runtime->private_data;
- audio_info("Alsa close\n");
-
- /*
- * Call stop if it's still running. This happens when app
- * is force killed and we don't get a stop trigger.
- */
- if (alsa_stream->running) {
- int err;
-
- err = bcm2835_audio_stop(alsa_stream);
- alsa_stream->running = 0;
- if (err)
- audio_error(" Failed to STOP alsa device\n");
- }
-
alsa_stream->period_size = 0;
alsa_stream->buffer_size = 0;
- if (alsa_stream->open) {
- alsa_stream->open = 0;
- bcm2835_audio_close(alsa_stream);
- }
- if (alsa_stream->chip)
- alsa_stream->chip->alsa_stream[alsa_stream->idx] = NULL;
+ bcm2835_audio_close(alsa_stream);
+ alsa_stream->chip->alsa_stream[alsa_stream->idx] = NULL;
/*
* Do not free up alsa_stream here, it will be freed up by
* runtime->private_free callback we registered in *_open above
@@ -241,22 +199,7 @@ static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream)
static int snd_bcm2835_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
- int err;
-
- err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
- if (err < 0) {
- audio_error
- (" pcm_lib_malloc failed to allocated pages for buffers\n");
- return err;
- }
-
- alsa_stream->channels = params_channels(params);
- alsa_stream->params_rate = params_rate(params);
- alsa_stream->pcm_format_width = snd_pcm_format_width(params_format(params));
-
- return err;
+ return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
}
/* hw_free callback */
@@ -274,9 +217,6 @@ static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
int channels;
int err;
- if (mutex_lock_interruptible(&chip->audio_mutex))
- return -EINTR;
-
/* notify the vchiq that it should enter spdif passthrough mode by
* setting channels=0 (see
* https://github.com/raspberrypi/linux/issues/528)
@@ -284,18 +224,13 @@ static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
if (chip->spdif_status & IEC958_AES0_NONAUDIO)
channels = 0;
else
- channels = alsa_stream->channels;
+ channels = runtime->channels;
err = bcm2835_audio_set_params(alsa_stream, channels,
- alsa_stream->params_rate,
- alsa_stream->pcm_format_width);
+ runtime->rate,
+ snd_pcm_format_width(runtime->format));
if (err < 0)
- audio_error(" error setting hw params\n");
-
- bcm2835_audio_setup(alsa_stream);
-
- /* in preparation of the stream, set the controls (volume level) of the stream */
- bcm2835_audio_set_ctls(alsa_stream->chip);
+ return err;
memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect));
@@ -305,13 +240,10 @@ static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
- alsa_stream->pos = 0;
-
- audio_debug("buffer_size=%d, period_size=%d pos=%d frame_bits=%d\n",
- alsa_stream->buffer_size, alsa_stream->period_size,
- alsa_stream->pos, runtime->frame_bits);
+ atomic_set(&alsa_stream->pos, 0);
+ alsa_stream->period_offset = 0;
+ alsa_stream->draining = false;
- mutex_unlock(&chip->audio_mutex);
return 0;
}
@@ -321,12 +253,8 @@ static void snd_bcm2835_pcm_transfer(struct snd_pcm_substream *substream,
struct snd_pcm_runtime *runtime = substream->runtime;
struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
void *src = (void *) (substream->runtime->dma_area + rec->sw_data);
- int err;
-
- err = bcm2835_audio_write(alsa_stream, bytes, src);
- if (err)
- audio_error(" Failed to transfer to alsa device (%d)\n", err);
+ bcm2835_audio_write(alsa_stream, bytes, src);
}
static int snd_bcm2835_pcm_ack(struct snd_pcm_substream *substream)
@@ -335,7 +263,6 @@ static int snd_bcm2835_pcm_ack(struct snd_pcm_substream *substream)
struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
struct snd_pcm_indirect *pcm_indirect = &alsa_stream->pcm_indirect;
- pcm_indirect->hw_queue_size = runtime->hw.buffer_bytes_max;
return snd_pcm_indirect_playback_transfer(substream, pcm_indirect,
snd_bcm2835_pcm_transfer);
}
@@ -345,50 +272,18 @@ static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
- int err = 0;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
- audio_debug("bcm2835_AUDIO_TRIGGER_START running=%d\n",
- alsa_stream->running);
- if (!alsa_stream->running) {
- err = bcm2835_audio_start(alsa_stream);
- if (!err) {
- alsa_stream->pcm_indirect.hw_io =
- alsa_stream->pcm_indirect.hw_data =
- bytes_to_frames(runtime,
- alsa_stream->pos);
- substream->ops->ack(substream);
- alsa_stream->running = 1;
- alsa_stream->draining = 1;
- } else {
- audio_error(" Failed to START alsa device (%d)\n", err);
- }
- }
- break;
+ return bcm2835_audio_start(alsa_stream);
+ case SNDRV_PCM_TRIGGER_DRAIN:
+ alsa_stream->draining = true;
+ return bcm2835_audio_drain(alsa_stream);
case SNDRV_PCM_TRIGGER_STOP:
- audio_debug
- ("bcm2835_AUDIO_TRIGGER_STOP running=%d draining=%d\n",
- alsa_stream->running, runtime->status->state == SNDRV_PCM_STATE_DRAINING);
- if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
- audio_info("DRAINING\n");
- alsa_stream->draining = 1;
- } else {
- audio_info("DROPPING\n");
- alsa_stream->draining = 0;
- }
- if (alsa_stream->running) {
- err = bcm2835_audio_stop(alsa_stream);
- if (err != 0)
- audio_error(" Failed to STOP alsa device (%d)\n", err);
- alsa_stream->running = 0;
- }
- break;
+ return bcm2835_audio_stop(alsa_stream);
default:
- err = -EINVAL;
+ return -EINVAL;
}
-
- return err;
}
/* pointer callback */
@@ -398,31 +293,16 @@ snd_bcm2835_pcm_pointer(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
- audio_debug("pcm_pointer... (%d) hwptr=%d appl=%d pos=%d\n", 0,
- frames_to_bytes(runtime, runtime->status->hw_ptr),
- frames_to_bytes(runtime, runtime->control->appl_ptr),
- alsa_stream->pos);
-
return snd_pcm_indirect_playback_pointer(substream,
&alsa_stream->pcm_indirect,
- alsa_stream->pos);
-}
-
-static int snd_bcm2835_pcm_lib_ioctl(struct snd_pcm_substream *substream,
- unsigned int cmd, void *arg)
-{
- int ret = snd_pcm_lib_ioctl(substream, cmd, arg);
-
- audio_info(" .. substream=%p, cmd=%d, arg=%p (%x) ret=%d\n", substream,
- cmd, arg, arg ? *(unsigned int *)arg : 0, ret);
- return ret;
+ atomic_read(&alsa_stream->pos));
}
/* operators */
static const struct snd_pcm_ops snd_bcm2835_playback_ops = {
.open = snd_bcm2835_playback_open,
.close = snd_bcm2835_playback_close,
- .ioctl = snd_bcm2835_pcm_lib_ioctl,
+ .ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_bcm2835_pcm_hw_params,
.hw_free = snd_bcm2835_pcm_hw_free,
.prepare = snd_bcm2835_pcm_prepare,
@@ -434,7 +314,7 @@ static const struct snd_pcm_ops snd_bcm2835_playback_ops = {
static const struct snd_pcm_ops snd_bcm2835_playback_spdif_ops = {
.open = snd_bcm2835_playback_spdif_open,
.close = snd_bcm2835_playback_close,
- .ioctl = snd_bcm2835_pcm_lib_ioctl,
+ .ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_bcm2835_pcm_hw_params,
.hw_free = snd_bcm2835_pcm_hw_free,
.prepare = snd_bcm2835_pcm_prepare,
@@ -444,104 +324,36 @@ static const struct snd_pcm_ops snd_bcm2835_playback_spdif_ops = {
};
/* create a pcm device */
-int snd_bcm2835_new_pcm(struct bcm2835_chip *chip, u32 numchannels)
-{
- struct snd_pcm *pcm;
- int err;
-
- mutex_init(&chip->audio_mutex);
- if (mutex_lock_interruptible(&chip->audio_mutex)) {
- audio_error("Interrupted whilst waiting for lock\n");
- return -EINTR;
- }
- err = snd_pcm_new(chip->card, "bcm2835 ALSA", 0, numchannels, 0, &pcm);
- if (err < 0)
- goto out;
- pcm->private_data = chip;
- strcpy(pcm->name, "bcm2835 ALSA");
- chip->pcm = pcm;
- chip->dest = AUDIO_DEST_AUTO;
- chip->volume = alsa2chip(0);
- chip->mute = CTRL_VOL_UNMUTE; /*disable mute on startup */
- /* set operators */
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
- &snd_bcm2835_playback_ops);
-
- /* pre-allocation of buffers */
- /* NOTE: this may fail */
- snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
- snd_dma_continuous_data(GFP_KERNEL),
- snd_bcm2835_playback_hw.buffer_bytes_max,
- snd_bcm2835_playback_hw.buffer_bytes_max);
-
-out:
- mutex_unlock(&chip->audio_mutex);
-
- return 0;
-}
-
-int snd_bcm2835_new_spdif_pcm(struct bcm2835_chip *chip)
+int snd_bcm2835_new_pcm(struct bcm2835_chip *chip, const char *name,
+ int idx, enum snd_bcm2835_route route,
+ u32 numchannels, bool spdif)
{
struct snd_pcm *pcm;
int err;
- if (mutex_lock_interruptible(&chip->audio_mutex)) {
- audio_error("Interrupted whilst waiting for lock\n");
- return -EINTR;
- }
- err = snd_pcm_new(chip->card, "bcm2835 ALSA", 1, 1, 0, &pcm);
- if (err < 0)
- goto out;
-
- pcm->private_data = chip;
- strcpy(pcm->name, "bcm2835 IEC958/HDMI");
- chip->pcm_spdif = pcm;
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
- &snd_bcm2835_playback_spdif_ops);
-
- /* pre-allocation of buffers */
- /* NOTE: this may fail */
- snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
- snd_dma_continuous_data(GFP_KERNEL),
- snd_bcm2835_playback_spdif_hw.buffer_bytes_max, snd_bcm2835_playback_spdif_hw.buffer_bytes_max);
-out:
- mutex_unlock(&chip->audio_mutex);
-
- return 0;
-}
-
-int snd_bcm2835_new_simple_pcm(struct bcm2835_chip *chip,
- const char *name,
- enum snd_bcm2835_route route,
- u32 numchannels)
-{
- struct snd_pcm *pcm;
- int err;
-
- mutex_init(&chip->audio_mutex);
-
- err = snd_pcm_new(chip->card, name, 0, numchannels,
- 0, &pcm);
+ err = snd_pcm_new(chip->card, name, idx, numchannels, 0, &pcm);
if (err)
return err;
pcm->private_data = chip;
+ pcm->nonatomic = true;
strcpy(pcm->name, name);
- chip->pcm = pcm;
- chip->dest = route;
- chip->volume = alsa2chip(0);
- chip->mute = CTRL_VOL_UNMUTE;
+ if (!spdif) {
+ chip->dest = route;
+ chip->volume = 0;
+ chip->mute = CTRL_VOL_UNMUTE;
+ }
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ spdif ? &snd_bcm2835_playback_spdif_ops :
&snd_bcm2835_playback_ops);
- snd_pcm_lib_preallocate_pages_for_all(
- pcm,
- SNDRV_DMA_TYPE_CONTINUOUS,
- snd_dma_continuous_data(GFP_KERNEL),
- snd_bcm2835_playback_hw.buffer_bytes_max,
- snd_bcm2835_playback_hw.buffer_bytes_max);
+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+ chip->card->dev, 128 * 1024, 128 * 1024);
+ if (spdif)
+ chip->pcm_spdif = pcm;
+ else
+ chip->pcm = pcm;
return 0;
}
-
diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
index 868e2d6aaf1b..781754f36da7 100644
--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
@@ -1,190 +1,99 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright 2011 Broadcom Corporation. All rights reserved. */
-#include <linux/device.h>
-#include <sound/core.h>
-#include <sound/initval.h>
-#include <sound/pcm.h>
-#include <linux/io.h>
-#include <linux/interrupt.h>
-#include <linux/fs.h>
-#include <linux/file.h>
-#include <linux/mm.h>
-#include <linux/syscalls.h>
-#include <linux/uaccess.h>
#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/atomic.h>
#include <linux/module.h>
#include <linux/completion.h>
-
#include "bcm2835.h"
-
-/* ---- Include Files -------------------------------------------------------- */
-
#include "vc_vchi_audioserv_defs.h"
-/* ---- Private Constants and Types ------------------------------------------ */
-
-#define BCM2835_AUDIO_STOP 0
-#define BCM2835_AUDIO_START 1
-#define BCM2835_AUDIO_WRITE 2
-
-/* Logging macros (for remapping to other logging mechanisms, i.e., printf) */
-#ifdef AUDIO_DEBUG_ENABLE
-#define LOG_ERR(fmt, arg...) pr_err("%s:%d " fmt, __func__, __LINE__, ##arg)
-#define LOG_WARN(fmt, arg...) pr_info("%s:%d " fmt, __func__, __LINE__, ##arg)
-#define LOG_INFO(fmt, arg...) pr_info("%s:%d " fmt, __func__, __LINE__, ##arg)
-#define LOG_DBG(fmt, arg...) pr_info("%s:%d " fmt, __func__, __LINE__, ##arg)
-#else
-#define LOG_ERR(fmt, arg...) pr_err("%s:%d " fmt, __func__, __LINE__, ##arg)
-#define LOG_WARN(fmt, arg...) no_printk(fmt, ##arg)
-#define LOG_INFO(fmt, arg...) no_printk(fmt, ##arg)
-#define LOG_DBG(fmt, arg...) no_printk(fmt, ##arg)
-#endif
-
struct bcm2835_audio_instance {
- unsigned int num_connections;
- VCHI_SERVICE_HANDLE_T vchi_handle[VCHI_MAX_NUM_CONNECTIONS];
+ struct device *dev;
+ VCHI_SERVICE_HANDLE_T vchi_handle;
struct completion msg_avail_comp;
struct mutex vchi_mutex;
struct bcm2835_alsa_stream *alsa_stream;
int result;
+ unsigned int max_packet;
short peer_version;
};
static bool force_bulk;
+module_param(force_bulk, bool, 0444);
+MODULE_PARM_DESC(force_bulk, "Force use of vchiq bulk for audio");
-/* ---- Private Variables ---------------------------------------------------- */
-
-/* ---- Private Function Prototypes ------------------------------------------ */
-
-/* ---- Private Functions ---------------------------------------------------- */
-
-static int bcm2835_audio_stop_worker(struct bcm2835_alsa_stream *alsa_stream);
-static int bcm2835_audio_start_worker(struct bcm2835_alsa_stream *alsa_stream);
-static int bcm2835_audio_write_worker(struct bcm2835_alsa_stream *alsa_stream,
- unsigned int count, void *src);
-
-// Routine to send a message across a service
-
-static int
-bcm2835_vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,
- void *data,
- unsigned int size)
+static void bcm2835_audio_lock(struct bcm2835_audio_instance *instance)
{
- return vchi_queue_kernel_message(handle,
- data,
- size);
+ mutex_lock(&instance->vchi_mutex);
+ vchi_service_use(instance->vchi_handle);
}
-static const u32 BCM2835_AUDIO_WRITE_COOKIE1 = ('B' << 24 | 'C' << 16 |
- 'M' << 8 | 'A');
-static const u32 BCM2835_AUDIO_WRITE_COOKIE2 = ('D' << 24 | 'A' << 16 |
- 'T' << 8 | 'A');
-
-struct bcm2835_audio_work {
- struct work_struct my_work;
- struct bcm2835_alsa_stream *alsa_stream;
- int cmd;
- void *src;
- unsigned int count;
-};
-
-static void my_wq_function(struct work_struct *work)
+static void bcm2835_audio_unlock(struct bcm2835_audio_instance *instance)
{
- struct bcm2835_audio_work *w =
- container_of(work, struct bcm2835_audio_work, my_work);
- int ret = -9;
-
- switch (w->cmd) {
- case BCM2835_AUDIO_START:
- ret = bcm2835_audio_start_worker(w->alsa_stream);
- break;
- case BCM2835_AUDIO_STOP:
- ret = bcm2835_audio_stop_worker(w->alsa_stream);
- break;
- case BCM2835_AUDIO_WRITE:
- ret = bcm2835_audio_write_worker(w->alsa_stream, w->count,
- w->src);
- break;
- default:
- LOG_ERR(" Unexpected work: %p:%d\n", w->alsa_stream, w->cmd);
- break;
- }
- kfree((void *)work);
+ vchi_service_release(instance->vchi_handle);
+ mutex_unlock(&instance->vchi_mutex);
}
-int bcm2835_audio_start(struct bcm2835_alsa_stream *alsa_stream)
+static int bcm2835_audio_send_msg_locked(struct bcm2835_audio_instance *instance,
+ struct vc_audio_msg *m, bool wait)
{
- struct bcm2835_audio_work *work;
+ int status;
- work = kmalloc(sizeof(*work), GFP_ATOMIC);
- /*--- Queue some work (item 1) ---*/
- if (!work) {
- LOG_ERR(" .. Error: NULL work kmalloc\n");
- return -ENOMEM;
+ if (wait) {
+ instance->result = -1;
+ init_completion(&instance->msg_avail_comp);
}
- INIT_WORK(&work->my_work, my_wq_function);
- work->alsa_stream = alsa_stream;
- work->cmd = BCM2835_AUDIO_START;
- if (!queue_work(alsa_stream->my_wq, &work->my_work)) {
- kfree(work);
- return -EBUSY;
- }
- return 0;
-}
-
-int bcm2835_audio_stop(struct bcm2835_alsa_stream *alsa_stream)
-{
- struct bcm2835_audio_work *work;
- work = kmalloc(sizeof(*work), GFP_ATOMIC);
- /*--- Queue some work (item 1) ---*/
- if (!work) {
- LOG_ERR(" .. Error: NULL work kmalloc\n");
- return -ENOMEM;
+ status = vchi_queue_kernel_message(instance->vchi_handle,
+ m, sizeof(*m));
+ if (status) {
+ dev_err(instance->dev,
+ "vchi message queue failed: %d, msg=%d\n",
+ status, m->type);
+ return -EIO;
}
- INIT_WORK(&work->my_work, my_wq_function);
- work->alsa_stream = alsa_stream;
- work->cmd = BCM2835_AUDIO_STOP;
- if (!queue_work(alsa_stream->my_wq, &work->my_work)) {
- kfree(work);
- return -EBUSY;
+
+ if (wait) {
+ if (!wait_for_completion_timeout(&instance->msg_avail_comp,
+ msecs_to_jiffies(10 * 1000))) {
+ dev_err(instance->dev,
+ "vchi message timeout, msg=%d\n", m->type);
+ return -ETIMEDOUT;
+ } else if (instance->result) {
+ dev_err(instance->dev,
+ "vchi message response error:%d, msg=%d\n",
+ instance->result, m->type);
+ return -EIO;
+ }
}
+
return 0;
}
-int bcm2835_audio_write(struct bcm2835_alsa_stream *alsa_stream,
- unsigned int count, void *src)
+static int bcm2835_audio_send_msg(struct bcm2835_audio_instance *instance,
+ struct vc_audio_msg *m, bool wait)
{
- struct bcm2835_audio_work *work;
+ int err;
- work = kmalloc(sizeof(*work), GFP_ATOMIC);
- /*--- Queue some work (item 1) ---*/
- if (!work) {
- LOG_ERR(" .. Error: NULL work kmalloc\n");
- return -ENOMEM;
- }
- INIT_WORK(&work->my_work, my_wq_function);
- work->alsa_stream = alsa_stream;
- work->cmd = BCM2835_AUDIO_WRITE;
- work->src = src;
- work->count = count;
- if (!queue_work(alsa_stream->my_wq, &work->my_work)) {
- kfree(work);
- return -EBUSY;
- }
- return 0;
+ bcm2835_audio_lock(instance);
+ err = bcm2835_audio_send_msg_locked(instance, m, wait);
+ bcm2835_audio_unlock(instance);
+ return err;
}
-static void my_workqueue_quit(struct bcm2835_alsa_stream *alsa_stream)
+static int bcm2835_audio_send_simple(struct bcm2835_audio_instance *instance,
+ int type, bool wait)
{
- flush_workqueue(alsa_stream->my_wq);
- destroy_workqueue(alsa_stream->my_wq);
- alsa_stream->my_wq = NULL;
+ struct vc_audio_msg m = { .type = type };
+
+ return bcm2835_audio_send_msg(instance, &m, wait);
}
+static const u32 BCM2835_AUDIO_WRITE_COOKIE1 = ('B' << 24 | 'C' << 16 |
+ 'M' << 8 | 'A');
+static const u32 BCM2835_AUDIO_WRITE_COOKIE2 = ('D' << 24 | 'A' << 16 |
+ 'T' << 8 | 'A');
+
static void audio_vchi_callback(void *param,
const VCHI_CALLBACK_REASON_T reason,
void *msg_handle)
@@ -197,172 +106,87 @@ static void audio_vchi_callback(void *param,
if (reason != VCHI_CALLBACK_MSG_AVAILABLE)
return;
- if (!instance) {
- LOG_ERR(" .. instance is null\n");
- BUG();
- return;
- }
- if (!instance->vchi_handle[0]) {
- LOG_ERR(" .. instance->vchi_handle[0] is null\n");
- BUG();
- return;
- }
- status = vchi_msg_dequeue(instance->vchi_handle[0],
+ status = vchi_msg_dequeue(instance->vchi_handle,
&m, sizeof(m), &msg_len, VCHI_FLAGS_NONE);
if (m.type == VC_AUDIO_MSG_TYPE_RESULT) {
- LOG_DBG(" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_RESULT, success=%d\n",
- instance, m.u.result.success);
instance->result = m.u.result.success;
complete(&instance->msg_avail_comp);
} else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
- struct bcm2835_alsa_stream *alsa_stream = instance->alsa_stream;
-
- LOG_DBG(" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_COMPLETE, complete=%d\n",
- instance, m.u.complete.count);
if (m.u.complete.cookie1 != BCM2835_AUDIO_WRITE_COOKIE1 ||
m.u.complete.cookie2 != BCM2835_AUDIO_WRITE_COOKIE2)
- LOG_ERR(" .. response is corrupt\n");
- else if (alsa_stream) {
- atomic_add(m.u.complete.count,
- &alsa_stream->retrieved);
- bcm2835_playback_fifo(alsa_stream);
- } else {
- LOG_ERR(" .. unexpected alsa_stream=%p\n",
- alsa_stream);
- }
+ dev_err(instance->dev, "invalid cookie\n");
+ else
+ bcm2835_playback_fifo(instance->alsa_stream,
+ m.u.complete.count);
} else {
- LOG_ERR(" .. unexpected m.type=%d\n", m.type);
+ dev_err(instance->dev, "unexpected callback type=%d\n", m.type);
}
}
-static struct bcm2835_audio_instance *
+static int
vc_vchi_audio_init(VCHI_INSTANCE_T vchi_instance,
- VCHI_CONNECTION_T **vchi_connections,
- unsigned int num_connections)
+ struct bcm2835_audio_instance *instance)
{
- unsigned int i;
- struct bcm2835_audio_instance *instance;
+ SERVICE_CREATION_T params = {
+ .version = VCHI_VERSION_EX(VC_AUDIOSERV_VER, VC_AUDIOSERV_MIN_VER),
+ .service_id = VC_AUDIO_SERVER_NAME,
+ .callback = audio_vchi_callback,
+ .callback_param = instance,
+ };
int status;
- int ret;
-
- LOG_DBG("%s: start", __func__);
- if (num_connections > VCHI_MAX_NUM_CONNECTIONS) {
- LOG_ERR("%s: unsupported number of connections %u (max=%u)\n",
- __func__, num_connections, VCHI_MAX_NUM_CONNECTIONS);
-
- return ERR_PTR(-EINVAL);
- }
- /* Allocate memory for this instance */
- instance = kzalloc(sizeof(*instance), GFP_KERNEL);
- if (!instance)
- return ERR_PTR(-ENOMEM);
-
- instance->num_connections = num_connections;
-
- /* Create a lock for exclusive, serialized VCHI connection access */
- mutex_init(&instance->vchi_mutex);
/* Open the VCHI service connections */
- for (i = 0; i < num_connections; i++) {
- SERVICE_CREATION_T params = {
- .version = VCHI_VERSION_EX(VC_AUDIOSERV_VER, VC_AUDIOSERV_MIN_VER),
- .service_id = VC_AUDIO_SERVER_NAME,
- .connection = vchi_connections[i],
- .rx_fifo_size = 0,
- .tx_fifo_size = 0,
- .callback = audio_vchi_callback,
- .callback_param = instance,
- .want_unaligned_bulk_rx = 1, //TODO: remove VCOS_FALSE
- .want_unaligned_bulk_tx = 1, //TODO: remove VCOS_FALSE
- .want_crc = 0
- };
-
- LOG_DBG("%s: about to open %i\n", __func__, i);
- status = vchi_service_open(vchi_instance, &params,
- &instance->vchi_handle[i]);
-
- LOG_DBG("%s: opened %i: %p=%d\n", __func__, i, instance->vchi_handle[i], status);
- if (status) {
- LOG_ERR("%s: failed to open VCHI service connection (status=%d)\n",
- __func__, status);
- ret = -EPERM;
- goto err_close_services;
- }
- /* Finished with the service for now */
- vchi_service_release(instance->vchi_handle[i]);
- }
-
- LOG_DBG("%s: okay\n", __func__);
- return instance;
+ status = vchi_service_open(vchi_instance, &params,
+ &instance->vchi_handle);
-err_close_services:
- for (i = 0; i < instance->num_connections; i++) {
- LOG_ERR("%s: closing %i: %p\n", __func__, i, instance->vchi_handle[i]);
- if (instance->vchi_handle[i])
- vchi_service_close(instance->vchi_handle[i]);
+ if (status) {
+ dev_err(instance->dev,
+ "failed to open VCHI service connection (status=%d)\n",
+ status);
+ kfree(instance);
+ return -EPERM;
}
- kfree(instance);
- LOG_ERR("%s: error\n", __func__);
+ /* Finished with the service for now */
+ vchi_service_release(instance->vchi_handle);
- return ERR_PTR(ret);
+ return 0;
}
-static int vc_vchi_audio_deinit(struct bcm2835_audio_instance *instance)
+static void vc_vchi_audio_deinit(struct bcm2835_audio_instance *instance)
{
- unsigned int i;
-
- if (!instance) {
- LOG_ERR("%s: invalid handle %p\n", __func__, instance);
-
- return -1;
- }
+ int status;
- LOG_DBG(" .. about to lock (%d)\n", instance->num_connections);
- if (mutex_lock_interruptible(&instance->vchi_mutex)) {
- LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",
- instance->num_connections);
- return -EINTR;
- }
+ mutex_lock(&instance->vchi_mutex);
+ vchi_service_use(instance->vchi_handle);
/* Close all VCHI service connections */
- for (i = 0; i < instance->num_connections; i++) {
- int status;
-
- LOG_DBG(" .. %i:closing %p\n", i, instance->vchi_handle[i]);
- vchi_service_use(instance->vchi_handle[i]);
-
- status = vchi_service_close(instance->vchi_handle[i]);
- if (status) {
- LOG_DBG("%s: failed to close VCHI service connection (status=%d)\n",
- __func__, status);
- }
+ status = vchi_service_close(instance->vchi_handle);
+ if (status) {
+ dev_err(instance->dev,
+ "failed to close VCHI service connection (status=%d)\n",
+ status);
}
mutex_unlock(&instance->vchi_mutex);
-
- kfree(instance);
-
- return 0;
}
-int bcm2835_new_vchi_ctx(struct bcm2835_vchi_ctx *vchi_ctx)
+int bcm2835_new_vchi_ctx(struct device *dev, struct bcm2835_vchi_ctx *vchi_ctx)
{
int ret;
/* Initialize and create a VCHI connection */
ret = vchi_initialise(&vchi_ctx->vchi_instance);
if (ret) {
- LOG_ERR("%s: failed to initialise VCHI instance (ret=%d)\n",
- __func__, ret);
-
+ dev_err(dev, "failed to initialise VCHI instance (ret=%d)\n",
+ ret);
return -EIO;
}
- ret = vchi_connect(NULL, 0, vchi_ctx->vchi_instance);
+ ret = vchi_connect(vchi_ctx->vchi_instance);
if (ret) {
- LOG_ERR("%s: failed to connect VCHI instance (ret=%d)\n",
- __func__, ret);
+ dev_dbg(dev, "failed to connect VCHI instance (ret=%d)\n",
+ ret);
kfree(vchi_ctx->vchi_instance);
vchi_ctx->vchi_instance = NULL;
@@ -381,473 +205,170 @@ void bcm2835_free_vchi_ctx(struct bcm2835_vchi_ctx *vchi_ctx)
vchi_ctx->vchi_instance = NULL;
}
-static int bcm2835_audio_open_connection(struct bcm2835_alsa_stream *alsa_stream)
-{
- struct bcm2835_audio_instance *instance =
- (struct bcm2835_audio_instance *)alsa_stream->instance;
- struct bcm2835_vchi_ctx *vhci_ctx = alsa_stream->chip->vchi_ctx;
-
- LOG_INFO("%s: start\n", __func__);
- BUG_ON(instance);
- if (instance) {
- LOG_ERR("%s: VCHI instance already open (%p)\n",
- __func__, instance);
- instance->alsa_stream = alsa_stream;
- alsa_stream->instance = instance;
- return 0;
- }
-
- /* Initialize an instance of the audio service */
- instance = vc_vchi_audio_init(vhci_ctx->vchi_instance,
- &vhci_ctx->vchi_connection, 1);
-
- if (IS_ERR(instance)) {
- LOG_ERR("%s: failed to initialize audio service\n", __func__);
-
- /* vchi_instance is retained for use the next time. */
- return PTR_ERR(instance);
- }
-
- instance->alsa_stream = alsa_stream;
- alsa_stream->instance = instance;
-
- LOG_DBG(" success !\n");
-
- return 0;
-}
-
int bcm2835_audio_open(struct bcm2835_alsa_stream *alsa_stream)
{
+ struct bcm2835_vchi_ctx *vchi_ctx = alsa_stream->chip->vchi_ctx;
struct bcm2835_audio_instance *instance;
- struct vc_audio_msg m;
- int status;
- int ret;
+ int err;
- alsa_stream->my_wq = alloc_workqueue("my_queue", WQ_HIGHPRI, 1);
- if (!alsa_stream->my_wq)
+ /* Allocate memory for this instance */
+ instance = kzalloc(sizeof(*instance), GFP_KERNEL);
+ if (!instance)
return -ENOMEM;
+ mutex_init(&instance->vchi_mutex);
+ instance->dev = alsa_stream->chip->dev;
+ instance->alsa_stream = alsa_stream;
+ alsa_stream->instance = instance;
- ret = bcm2835_audio_open_connection(alsa_stream);
- if (ret)
- goto free_wq;
-
- instance = alsa_stream->instance;
- LOG_DBG(" instance (%p)\n", instance);
-
- if (mutex_lock_interruptible(&instance->vchi_mutex)) {
- LOG_DBG("Interrupted whilst waiting for lock on (%d)\n", instance->num_connections);
- ret = -EINTR;
- goto free_wq;
- }
- vchi_service_use(instance->vchi_handle[0]);
-
- m.type = VC_AUDIO_MSG_TYPE_OPEN;
-
- /* Send the message to the videocore */
- status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
- &m, sizeof(m));
-
- if (status) {
- LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
- __func__, status);
-
- ret = -1;
- goto unlock;
- }
+ err = vc_vchi_audio_init(vchi_ctx->vchi_instance,
+ instance);
+ if (err < 0)
+ goto free_instance;
- ret = 0;
+ err = bcm2835_audio_send_simple(instance, VC_AUDIO_MSG_TYPE_OPEN,
+ false);
+ if (err < 0)
+ goto deinit;
-unlock:
- vchi_service_release(instance->vchi_handle[0]);
- mutex_unlock(&instance->vchi_mutex);
+ bcm2835_audio_lock(instance);
+ vchi_get_peer_version(instance->vchi_handle, &instance->peer_version);
+ bcm2835_audio_unlock(instance);
+ if (instance->peer_version < 2 || force_bulk)
+ instance->max_packet = 0; /* bulk transfer */
+ else
+ instance->max_packet = 4000;
-free_wq:
- if (ret)
- destroy_workqueue(alsa_stream->my_wq);
+ return 0;
- return ret;
+ deinit:
+ vc_vchi_audio_deinit(instance);
+ free_instance:
+ alsa_stream->instance = NULL;
+ kfree(instance);
+ return err;
}
-static int bcm2835_audio_set_ctls_chan(struct bcm2835_alsa_stream *alsa_stream,
- struct bcm2835_chip *chip)
+int bcm2835_audio_set_ctls(struct bcm2835_alsa_stream *alsa_stream)
{
- struct vc_audio_msg m;
- struct bcm2835_audio_instance *instance = alsa_stream->instance;
- int status;
- int ret;
-
- LOG_INFO(" Setting ALSA dest(%d), volume(%d)\n",
- chip->dest, chip->volume);
-
- if (mutex_lock_interruptible(&instance->vchi_mutex)) {
- LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",
- instance->num_connections);
- return -EINTR;
- }
- vchi_service_use(instance->vchi_handle[0]);
-
- instance->result = -1;
+ struct bcm2835_chip *chip = alsa_stream->chip;
+ struct vc_audio_msg m = {};
m.type = VC_AUDIO_MSG_TYPE_CONTROL;
m.u.control.dest = chip->dest;
- m.u.control.volume = chip->volume;
+ if (!chip->mute)
+ m.u.control.volume = CHIP_MIN_VOLUME;
+ else
+ m.u.control.volume = alsa2chip(chip->volume);
- /* Create the message available completion */
- init_completion(&instance->msg_avail_comp);
-
- /* Send the message to the videocore */
- status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
- &m, sizeof(m));
-
- if (status) {
- LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
- __func__, status);
-
- ret = -1;
- goto unlock;
- }
-
- /* We are expecting a reply from the videocore */
- wait_for_completion(&instance->msg_avail_comp);
-
- if (instance->result) {
- LOG_ERR("%s: result=%d\n", __func__, instance->result);
-
- ret = -1;
- goto unlock;
- }
-
- ret = 0;
-
-unlock:
- vchi_service_release(instance->vchi_handle[0]);
- mutex_unlock(&instance->vchi_mutex);
-
- return ret;
-}
-
-int bcm2835_audio_set_ctls(struct bcm2835_chip *chip)
-{
- int i;
- int ret = 0;
-
- LOG_DBG(" Setting ALSA dest(%d), volume(%d)\n", chip->dest, chip->volume);
-
- /* change ctls for all substreams */
- for (i = 0; i < MAX_SUBSTREAMS; i++) {
- if (chip->avail_substreams & (1 << i)) {
- if (!chip->alsa_stream[i]) {
- LOG_DBG(" No ALSA stream available?! %i:%p (%x)\n", i, chip->alsa_stream[i], chip->avail_substreams);
- ret = 0;
- } else if (bcm2835_audio_set_ctls_chan(chip->alsa_stream[i], chip) != 0) {
- LOG_ERR("Couldn't set the controls for stream %d\n", i);
- ret = -1;
- } else {
- LOG_DBG(" Controls set for stream %d\n", i);
- }
- }
- }
- return ret;
+ return bcm2835_audio_send_msg(alsa_stream->instance, &m, true);
}
int bcm2835_audio_set_params(struct bcm2835_alsa_stream *alsa_stream,
unsigned int channels, unsigned int samplerate,
unsigned int bps)
{
- struct vc_audio_msg m;
- struct bcm2835_audio_instance *instance = alsa_stream->instance;
- int status;
- int ret;
-
- LOG_INFO(" Setting ALSA channels(%d), samplerate(%d), bits-per-sample(%d)\n",
- channels, samplerate, bps);
+ struct vc_audio_msg m = {
+ .type = VC_AUDIO_MSG_TYPE_CONFIG,
+ .u.config.channels = channels,
+ .u.config.samplerate = samplerate,
+ .u.config.bps = bps,
+ };
+ int err;
/* resend ctls - alsa_stream may not have been open when first send */
- ret = bcm2835_audio_set_ctls_chan(alsa_stream, alsa_stream->chip);
- if (ret) {
- LOG_ERR(" Alsa controls not supported\n");
- return -EINVAL;
- }
-
- if (mutex_lock_interruptible(&instance->vchi_mutex)) {
- LOG_DBG("Interrupted whilst waiting for lock on (%d)\n", instance->num_connections);
- return -EINTR;
- }
- vchi_service_use(instance->vchi_handle[0]);
-
- instance->result = -1;
+ err = bcm2835_audio_set_ctls(alsa_stream);
+ if (err)
+ return err;
- m.type = VC_AUDIO_MSG_TYPE_CONFIG;
- m.u.config.channels = channels;
- m.u.config.samplerate = samplerate;
- m.u.config.bps = bps;
-
- /* Create the message available completion */
- init_completion(&instance->msg_avail_comp);
-
- /* Send the message to the videocore */
- status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
- &m, sizeof(m));
-
- if (status) {
- LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
- __func__, status);
-
- ret = -1;
- goto unlock;
- }
-
- /* We are expecting a reply from the videocore */
- wait_for_completion(&instance->msg_avail_comp);
-
- if (instance->result) {
- LOG_ERR("%s: result=%d", __func__, instance->result);
-
- ret = -1;
- goto unlock;
- }
-
- ret = 0;
-
-unlock:
- vchi_service_release(instance->vchi_handle[0]);
- mutex_unlock(&instance->vchi_mutex);
-
- return ret;
+ return bcm2835_audio_send_msg(alsa_stream->instance, &m, true);
}
-int bcm2835_audio_setup(struct bcm2835_alsa_stream *alsa_stream)
+int bcm2835_audio_start(struct bcm2835_alsa_stream *alsa_stream)
{
-
- return 0;
+ return bcm2835_audio_send_simple(alsa_stream->instance,
+ VC_AUDIO_MSG_TYPE_START, false);
}
-static int bcm2835_audio_start_worker(struct bcm2835_alsa_stream *alsa_stream)
+int bcm2835_audio_stop(struct bcm2835_alsa_stream *alsa_stream)
{
- struct vc_audio_msg m;
- struct bcm2835_audio_instance *instance = alsa_stream->instance;
- int status;
- int ret;
-
- if (mutex_lock_interruptible(&instance->vchi_mutex)) {
- LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",
- instance->num_connections);
- return -EINTR;
- }
- vchi_service_use(instance->vchi_handle[0]);
-
- m.type = VC_AUDIO_MSG_TYPE_START;
-
- /* Send the message to the videocore */
- status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
- &m, sizeof(m));
-
- if (status) {
- LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
- __func__, status);
-
- ret = -1;
- goto unlock;
- }
-
- ret = 0;
-
-unlock:
- vchi_service_release(instance->vchi_handle[0]);
- mutex_unlock(&instance->vchi_mutex);
- return ret;
+ return bcm2835_audio_send_simple(alsa_stream->instance,
+ VC_AUDIO_MSG_TYPE_STOP, false);
}
-static int bcm2835_audio_stop_worker(struct bcm2835_alsa_stream *alsa_stream)
+int bcm2835_audio_drain(struct bcm2835_alsa_stream *alsa_stream)
{
- struct vc_audio_msg m;
- struct bcm2835_audio_instance *instance = alsa_stream->instance;
- int status;
- int ret;
-
- if (mutex_lock_interruptible(&instance->vchi_mutex)) {
- LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",
- instance->num_connections);
- return -EINTR;
- }
- vchi_service_use(instance->vchi_handle[0]);
-
- m.type = VC_AUDIO_MSG_TYPE_STOP;
- m.u.stop.draining = alsa_stream->draining;
-
- /* Send the message to the videocore */
- status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
- &m, sizeof(m));
-
- if (status) {
- LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
- __func__, status);
+ struct vc_audio_msg m = {
+ .type = VC_AUDIO_MSG_TYPE_STOP,
+ .u.stop.draining = 1,
+ };
- ret = -1;
- goto unlock;
- }
-
- ret = 0;
-
-unlock:
- vchi_service_release(instance->vchi_handle[0]);
- mutex_unlock(&instance->vchi_mutex);
- return ret;
+ return bcm2835_audio_send_msg(alsa_stream->instance, &m, false);
}
int bcm2835_audio_close(struct bcm2835_alsa_stream *alsa_stream)
{
- struct vc_audio_msg m;
struct bcm2835_audio_instance *instance = alsa_stream->instance;
- int status;
- int ret;
+ int err;
- my_workqueue_quit(alsa_stream);
-
- if (mutex_lock_interruptible(&instance->vchi_mutex)) {
- LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",
- instance->num_connections);
- return -EINTR;
- }
- vchi_service_use(instance->vchi_handle[0]);
-
- m.type = VC_AUDIO_MSG_TYPE_CLOSE;
-
- /* Create the message available completion */
- init_completion(&instance->msg_avail_comp);
-
- /* Send the message to the videocore */
- status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
- &m, sizeof(m));
-
- if (status) {
- LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
- __func__, status);
- ret = -1;
- goto unlock;
- }
-
- /* We are expecting a reply from the videocore */
- wait_for_completion(&instance->msg_avail_comp);
-
- if (instance->result) {
- LOG_ERR("%s: failed result (result=%d)\n",
- __func__, instance->result);
-
- ret = -1;
- goto unlock;
- }
-
- ret = 0;
-
-unlock:
- vchi_service_release(instance->vchi_handle[0]);
- mutex_unlock(&instance->vchi_mutex);
+ err = bcm2835_audio_send_simple(alsa_stream->instance,
+ VC_AUDIO_MSG_TYPE_CLOSE, true);
/* Stop the audio service */
vc_vchi_audio_deinit(instance);
alsa_stream->instance = NULL;
+ kfree(instance);
- return ret;
+ return err;
}
-static int bcm2835_audio_write_worker(struct bcm2835_alsa_stream *alsa_stream,
- unsigned int count, void *src)
+int bcm2835_audio_write(struct bcm2835_alsa_stream *alsa_stream,
+ unsigned int size, void *src)
{
- struct vc_audio_msg m;
struct bcm2835_audio_instance *instance = alsa_stream->instance;
- int status;
- int ret;
-
- LOG_INFO(" Writing %d bytes from %p\n", count, src);
-
- if (mutex_lock_interruptible(&instance->vchi_mutex)) {
- LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",
- instance->num_connections);
- return -EINTR;
- }
- vchi_service_use(instance->vchi_handle[0]);
-
- if (instance->peer_version == 0 &&
- vchi_get_peer_version(instance->vchi_handle[0], &instance->peer_version) == 0)
- LOG_DBG("%s: client version %d connected\n", __func__, instance->peer_version);
-
- m.type = VC_AUDIO_MSG_TYPE_WRITE;
- m.u.write.count = count;
- // old version uses bulk, new version uses control
- m.u.write.max_packet = instance->peer_version < 2 || force_bulk ? 0 : 4000;
- m.u.write.cookie1 = BCM2835_AUDIO_WRITE_COOKIE1;
- m.u.write.cookie2 = BCM2835_AUDIO_WRITE_COOKIE2;
- m.u.write.silence = src == NULL;
-
- /* Send the message to the videocore */
- status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
- &m, sizeof(m));
+ struct vc_audio_msg m = {
+ .type = VC_AUDIO_MSG_TYPE_WRITE,
+ .u.write.count = size,
+ .u.write.max_packet = instance->max_packet,
+ .u.write.cookie1 = BCM2835_AUDIO_WRITE_COOKIE1,
+ .u.write.cookie2 = BCM2835_AUDIO_WRITE_COOKIE2,
+ };
+ unsigned int count;
+ int err, status;
- if (status) {
- LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
- __func__, status);
+ if (!size)
+ return 0;
- ret = -1;
+ bcm2835_audio_lock(instance);
+ err = bcm2835_audio_send_msg_locked(instance, &m, false);
+ if (err < 0)
goto unlock;
- }
- if (!m.u.write.silence) {
- if (!m.u.write.max_packet) {
- /* Send the message to the videocore */
- status = vchi_bulk_queue_transmit(instance->vchi_handle[0],
- src, count,
- 0 * VCHI_FLAGS_BLOCK_UNTIL_QUEUED
- +
- 1 * VCHI_FLAGS_BLOCK_UNTIL_DATA_READ,
- NULL);
- } else {
- while (count > 0) {
- int bytes = min_t(int, m.u.write.max_packet, count);
-
- status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
- src, bytes);
- src = (char *)src + bytes;
- count -= bytes;
- }
- }
- if (status) {
- LOG_ERR("%s: failed on vchi_bulk_queue_transmit (status=%d)\n",
- __func__, status);
- ret = -1;
- goto unlock;
+ count = size;
+ if (!instance->max_packet) {
+ /* Send the message to the videocore */
+ status = vchi_bulk_queue_transmit(instance->vchi_handle,
+ src, count,
+ VCHI_FLAGS_BLOCK_UNTIL_DATA_READ,
+ NULL);
+ } else {
+ while (count > 0) {
+ int bytes = min(instance->max_packet, count);
+
+ status = vchi_queue_kernel_message(instance->vchi_handle,
+ src, bytes);
+ src += bytes;
+ count -= bytes;
}
}
- ret = 0;
-
-unlock:
- vchi_service_release(instance->vchi_handle[0]);
- mutex_unlock(&instance->vchi_mutex);
- return ret;
-}
-
-/**
- * Returns all buffers from arm->vc
- */
-void bcm2835_audio_flush_buffers(struct bcm2835_alsa_stream *alsa_stream)
-{
-}
-
-/**
- * Forces VC to flush(drop) its filled playback buffers and
- * return them the us. (VC->ARM)
- */
-void bcm2835_audio_flush_playback_buffers(struct bcm2835_alsa_stream *alsa_stream)
-{
-}
-unsigned int bcm2835_audio_retrieve_buffers(struct bcm2835_alsa_stream *alsa_stream)
-{
- unsigned int count = atomic_read(&alsa_stream->retrieved);
+ if (status) {
+ dev_err(instance->dev,
+ "failed on %d bytes transfer (status=%d)\n",
+ size, status);
+ err = -EIO;
+ }
- atomic_sub(count, &alsa_stream->retrieved);
- return count;
+ unlock:
+ bcm2835_audio_unlock(instance);
+ return err;
}
-
-module_param(force_bulk, bool, 0444);
-MODULE_PARM_DESC(force_bulk, "Force use of vchiq bulk for audio");
diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
index da0fa34501fa..87d56ab1ffa0 100644
--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
@@ -22,38 +22,6 @@ module_param(enable_compat_alsa, bool, 0444);
MODULE_PARM_DESC(enable_compat_alsa,
"Enables ALSA compatibility virtual audio device");
-static void snd_devm_unregister_child(struct device *dev, void *res)
-{
- struct device *childdev = *(struct device **)res;
- struct bcm2835_chip *chip = dev_get_drvdata(childdev);
- struct snd_card *card = chip->card;
-
- snd_card_free(card);
-
- device_unregister(childdev);
-}
-
-static int snd_devm_add_child(struct device *dev, struct device *child)
-{
- struct device **dr;
- int ret;
-
- dr = devres_alloc(snd_devm_unregister_child, sizeof(*dr), GFP_KERNEL);
- if (!dr)
- return -ENOMEM;
-
- ret = device_add(child);
- if (ret) {
- devres_free(dr);
- return ret;
- }
-
- *dr = child;
- devres_add(dev, dr);
-
- return 0;
-}
-
static void bcm2835_devm_free_vchi_ctx(struct device *dev, void *res)
{
struct bcm2835_vchi_ctx *vchi_ctx = res;
@@ -73,7 +41,7 @@ static int bcm2835_devm_add_vchi_ctx(struct device *dev)
memset(vchi_ctx, 0, sizeof(*vchi_ctx));
- ret = bcm2835_new_vchi_ctx(vchi_ctx);
+ ret = bcm2835_new_vchi_ctx(dev, vchi_ctx);
if (ret) {
devres_free(vchi_ctx);
return ret;
@@ -84,101 +52,6 @@ static int bcm2835_devm_add_vchi_ctx(struct device *dev)
return 0;
}
-static void snd_bcm2835_release(struct device *dev)
-{
- struct bcm2835_chip *chip = dev_get_drvdata(dev);
-
- kfree(chip);
-}
-
-static struct device *
-snd_create_device(struct device *parent,
- struct device_driver *driver,
- const char *name)
-{
- struct device *device;
- int ret;
-
- device = devm_kzalloc(parent, sizeof(*device), GFP_KERNEL);
- if (!device)
- return ERR_PTR(-ENOMEM);
-
- device_initialize(device);
- device->parent = parent;
- device->driver = driver;
- device->release = snd_bcm2835_release;
-
- dev_set_name(device, "%s", name);
-
- ret = snd_devm_add_child(parent, device);
- if (ret)
- return ERR_PTR(ret);
-
- return device;
-}
-
-/* component-destructor
- * (see "Management of Cards and Components")
- */
-static int snd_bcm2835_dev_free(struct snd_device *device)
-{
- struct bcm2835_chip *chip = device->device_data;
- struct snd_card *card = chip->card;
-
- snd_device_free(card, chip);
-
- return 0;
-}
-
-/* chip-specific constructor
- * (see "Management of Cards and Components")
- */
-static int snd_bcm2835_create(struct snd_card *card,
- struct bcm2835_chip **rchip)
-{
- struct bcm2835_chip *chip;
- int err;
- static struct snd_device_ops ops = {
- .dev_free = snd_bcm2835_dev_free,
- };
-
- *rchip = NULL;
-
- chip = kzalloc(sizeof(*chip), GFP_KERNEL);
- if (!chip)
- return -ENOMEM;
-
- chip->card = card;
-
- chip->vchi_ctx = devres_find(card->dev->parent,
- bcm2835_devm_free_vchi_ctx, NULL, NULL);
- if (!chip->vchi_ctx) {
- kfree(chip);
- return -ENODEV;
- }
-
- err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
- if (err) {
- kfree(chip);
- return err;
- }
-
- *rchip = chip;
- return 0;
-}
-
-static struct snd_card *snd_bcm2835_card_new(struct device *dev)
-{
- struct snd_card *card;
- int ret;
-
- ret = snd_card_new(dev, -1, NULL, THIS_MODULE, 0, &card);
- if (ret)
- return ERR_PTR(ret);
-
- return card;
-}
-
typedef int (*bcm2835_audio_newpcm_func)(struct bcm2835_chip *chip,
const char *name,
enum snd_bcm2835_route route,
@@ -203,17 +76,26 @@ static int bcm2835_audio_alsa_newpcm(struct bcm2835_chip *chip,
{
int err;
- err = snd_bcm2835_new_pcm(chip, numchannels - 1);
+ err = snd_bcm2835_new_pcm(chip, "bcm2835 ALSA", 0, AUDIO_DEST_AUTO,
+ numchannels - 1, false);
if (err)
return err;
- err = snd_bcm2835_new_spdif_pcm(chip);
+ err = snd_bcm2835_new_pcm(chip, "bcm2835 IEC958/HDMI", 1, 0, 1, true);
if (err)
return err;
return 0;
}
+static int bcm2835_audio_simple_newpcm(struct bcm2835_chip *chip,
+ const char *name,
+ enum snd_bcm2835_route route,
+ u32 numchannels)
+{
+ return snd_bcm2835_new_pcm(chip, name, 0, route, numchannels, false);
+}
+
static struct bcm2835_audio_driver bcm2835_audio_alsa = {
.driver = {
.name = "bcm2835_alsa",
@@ -234,7 +116,7 @@ static struct bcm2835_audio_driver bcm2835_audio_hdmi = {
.shortname = "bcm2835 HDMI",
.longname = "bcm2835 HDMI",
.minchannels = 1,
- .newpcm = snd_bcm2835_new_simple_pcm,
+ .newpcm = bcm2835_audio_simple_newpcm,
.newctl = snd_bcm2835_new_hdmi_ctl,
.route = AUDIO_DEST_HDMI
};
@@ -247,7 +129,7 @@ static struct bcm2835_audio_driver bcm2835_audio_headphones = {
.shortname = "bcm2835 Headphones",
.longname = "bcm2835 Headphones",
.minchannels = 1,
- .newpcm = snd_bcm2835_new_simple_pcm,
+ .newpcm = bcm2835_audio_simple_newpcm,
.newctl = snd_bcm2835_new_headphones_ctl,
.route = AUDIO_DEST_HEADPHONES
};
@@ -272,71 +154,75 @@ static struct bcm2835_audio_drivers children_devices[] = {
},
};
-static int snd_add_child_device(struct device *device,
+static void bcm2835_card_free(void *data)
+{
+ snd_card_free(data);
+}
+
+static int snd_add_child_device(struct device *dev,
struct bcm2835_audio_driver *audio_driver,
u32 numchans)
{
struct snd_card *card;
- struct device *child;
struct bcm2835_chip *chip;
- int err, i;
-
- child = snd_create_device(device, &audio_driver->driver,
- audio_driver->driver.name);
- if (IS_ERR(child)) {
- dev_err(device,
- "Unable to create child device %p, error %ld",
- audio_driver->driver.name,
- PTR_ERR(child));
- return PTR_ERR(child);
+ int err;
+
+ err = snd_card_new(dev, -1, NULL, THIS_MODULE, sizeof(*chip), &card);
+ if (err < 0) {
+ dev_err(dev, "Failed to create card");
+ return err;
}
- card = snd_bcm2835_card_new(child);
- if (IS_ERR(card)) {
- dev_err(child, "Failed to create card");
- return PTR_ERR(card);
+ chip = card->private_data;
+ chip->card = card;
+ chip->dev = dev;
+ mutex_init(&chip->audio_mutex);
+
+ chip->vchi_ctx = devres_find(dev,
+ bcm2835_devm_free_vchi_ctx, NULL, NULL);
+ if (!chip->vchi_ctx) {
+ err = -ENODEV;
+ goto error;
}
- snd_card_set_dev(card, child);
strcpy(card->driver, audio_driver->driver.name);
strcpy(card->shortname, audio_driver->shortname);
strcpy(card->longname, audio_driver->longname);
- err = snd_bcm2835_create(card, &chip);
- if (err) {
- dev_err(child, "Failed to create chip, error %d\n", err);
- return err;
- }
-
- chip->dev = child;
-
err = audio_driver->newpcm(chip, audio_driver->shortname,
audio_driver->route,
numchans);
if (err) {
- dev_err(child, "Failed to create pcm, error %d\n", err);
- return err;
+ dev_err(dev, "Failed to create pcm, error %d\n", err);
+ goto error;
}
err = audio_driver->newctl(chip);
if (err) {
- dev_err(child, "Failed to create controls, error %d\n", err);
- return err;
+ dev_err(dev, "Failed to create controls, error %d\n", err);
+ goto error;
}
- for (i = 0; i < numchans; i++)
- chip->avail_substreams |= (1 << i);
-
err = snd_card_register(card);
if (err) {
- dev_err(child, "Failed to register card, error %d\n", err);
- return err;
+ dev_err(dev, "Failed to register card, error %d\n", err);
+ goto error;
}
- dev_set_drvdata(child, chip);
- dev_info(child, "card created with %d channels\n", numchans);
+ dev_set_drvdata(dev, chip);
+
+ err = devm_add_action(dev, bcm2835_card_free, card);
+ if (err < 0) {
+ dev_err(dev, "Failed to add devm action, err %d\n", err);
+ goto error;
+ }
+ dev_info(dev, "card created with %d channels\n", numchans);
return 0;
+
+ error:
+ snd_card_free(card);
+ return err;
}
static int snd_add_child_devices(struct device *device, u32 numchans)
diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
index 5dc427240a1d..34a0125ce646 100644
--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
@@ -5,59 +5,12 @@
#define __SOUND_ARM_BCM2835_H
#include <linux/device.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
#include <linux/wait.h>
#include <sound/core.h>
-#include <sound/initval.h>
#include <sound/pcm.h>
-#include <sound/pcm_params.h>
#include <sound/pcm-indirect.h>
-#include <linux/workqueue.h>
-
#include "interface/vchi/vchi.h"
-/*
- * #define AUDIO_DEBUG_ENABLE
- * #define AUDIO_VERBOSE_DEBUG_ENABLE
- */
-
-/* Debug macros */
-
-#ifdef AUDIO_DEBUG_ENABLE
-#ifdef AUDIO_VERBOSE_DEBUG_ENABLE
-
-#define audio_debug(fmt, arg...) \
- pr_info("%s:%d " fmt, __func__, __LINE__, ##arg)
-
-#define audio_info(fmt, arg...) \
- pr_info("%s:%d " fmt, __func__, __LINE__, ##arg)
-
-#else
-
-#define audio_debug(fmt, arg...)
-
-#define audio_info(fmt, arg...)
-
-#endif /* AUDIO_VERBOSE_DEBUG_ENABLE */
-
-#else
-
-#define audio_debug(fmt, arg...)
-
-#define audio_info(fmt, arg...)
-
-#endif /* AUDIO_DEBUG_ENABLE */
-
-#define audio_error(fmt, arg...) \
- pr_err("%s:%d " fmt, __func__, __LINE__, ##arg)
-
-#define audio_warning(fmt, arg...) \
- pr_warn("%s:%d " fmt, __func__, __LINE__, ##arg)
-
-#define audio_alert(fmt, arg...) \
- pr_alert("%s:%d " fmt, __func__, __LINE__, ##arg)
-
#define MAX_SUBSTREAMS (8)
#define AVAIL_SUBSTREAMS_MASK (0xff)
@@ -74,6 +27,8 @@ enum {
// convert chip to alsa volume
#define chip2alsa(vol) -(((vol) * 100) >> 8)
+#define CHIP_MIN_VOLUME 26214 /* minimum level aka mute */
+
/* Some constants for values .. */
enum snd_bcm2835_route {
AUDIO_DEST_AUTO = 0,
@@ -90,7 +45,6 @@ enum snd_bcm2835_ctrl {
struct bcm2835_vchi_ctx {
VCHI_INSTANCE_T vchi_instance;
- VCHI_CONNECTION_T *vchi_connection;
};
/* definition of the chip-specific record */
@@ -98,13 +52,10 @@ struct bcm2835_chip {
struct snd_card *card;
struct snd_pcm *pcm;
struct snd_pcm *pcm_spdif;
- /* Bitmat for valid reg_base and irq numbers */
- unsigned int avail_substreams;
struct device *dev;
struct bcm2835_alsa_stream *alsa_stream[MAX_SUBSTREAMS];
int volume;
- int old_volume; /* stores the volume value whist muted */
int dest;
int mute;
@@ -120,38 +71,26 @@ struct bcm2835_alsa_stream {
struct snd_pcm_substream *substream;
struct snd_pcm_indirect pcm_indirect;
- spinlock_t lock;
-
- int open;
- int running;
int draining;
- int channels;
- int params_rate;
- int pcm_format_width;
-
- unsigned int pos;
+ atomic_t pos;
+ unsigned int period_offset;
unsigned int buffer_size;
unsigned int period_size;
- atomic_t retrieved;
struct bcm2835_audio_instance *instance;
- struct workqueue_struct *my_wq;
int idx;
};
int snd_bcm2835_new_ctl(struct bcm2835_chip *chip);
-int snd_bcm2835_new_pcm(struct bcm2835_chip *chip, u32 numchannels);
-int snd_bcm2835_new_spdif_pcm(struct bcm2835_chip *chip);
-int snd_bcm2835_new_simple_pcm(struct bcm2835_chip *chip,
- const char *name,
- enum snd_bcm2835_route route,
- u32 numchannels);
+int snd_bcm2835_new_pcm(struct bcm2835_chip *chip, const char *name,
+ int idx, enum snd_bcm2835_route route,
+ u32 numchannels, bool spdif);
int snd_bcm2835_new_hdmi_ctl(struct bcm2835_chip *chip);
int snd_bcm2835_new_headphones_ctl(struct bcm2835_chip *chip);
-int bcm2835_new_vchi_ctx(struct bcm2835_vchi_ctx *vchi_ctx);
+int bcm2835_new_vchi_ctx(struct device *dev, struct bcm2835_vchi_ctx *vchi_ctx);
void bcm2835_free_vchi_ctx(struct bcm2835_vchi_ctx *vchi_ctx);
int bcm2835_audio_open(struct bcm2835_alsa_stream *alsa_stream);
@@ -159,16 +98,15 @@ int bcm2835_audio_close(struct bcm2835_alsa_stream *alsa_stream);
int bcm2835_audio_set_params(struct bcm2835_alsa_stream *alsa_stream,
unsigned int channels, unsigned int samplerate,
unsigned int bps);
-int bcm2835_audio_setup(struct bcm2835_alsa_stream *alsa_stream);
int bcm2835_audio_start(struct bcm2835_alsa_stream *alsa_stream);
int bcm2835_audio_stop(struct bcm2835_alsa_stream *alsa_stream);
-int bcm2835_audio_set_ctls(struct bcm2835_chip *chip);
+int bcm2835_audio_drain(struct bcm2835_alsa_stream *alsa_stream);
+int bcm2835_audio_set_ctls(struct bcm2835_alsa_stream *alsa_stream);
int bcm2835_audio_write(struct bcm2835_alsa_stream *alsa_stream,
unsigned int count,
void *src);
-void bcm2835_playback_fifo(struct bcm2835_alsa_stream *alsa_stream);
+void bcm2835_playback_fifo(struct bcm2835_alsa_stream *alsa_stream,
+ unsigned int size);
unsigned int bcm2835_audio_retrieve_buffers(struct bcm2835_alsa_stream *alsa_stream);
-void bcm2835_audio_flush_buffers(struct bcm2835_alsa_stream *alsa_stream);
-void bcm2835_audio_flush_playback_buffers(struct bcm2835_alsa_stream *alsa_stream);
#endif /* __SOUND_ARM_BCM2835_H */
diff --git a/drivers/staging/vc04_services/bcm2835-camera/TODO b/drivers/staging/vc04_services/bcm2835-camera/TODO
index cefce72d814f..6c2b4ffe4996 100644
--- a/drivers/staging/vc04_services/bcm2835-camera/TODO
+++ b/drivers/staging/vc04_services/bcm2835-camera/TODO
@@ -15,9 +15,3 @@ padding in the V4L2 spec, but that padding doesn't match what the
hardware can do. If we exposed the native padding requirements
through the V4L2 "multiplanar" formats, the firmware would have one
less copy it needed to do.
-
-3) Port to ARM64
-
-The bulk_receive() does some manual cache flushing that are 32-bit ARM
-only, which we should convert to proper cross-platform APIs.
-
diff --git a/drivers/staging/vc04_services/bcm2835-camera/controls.c b/drivers/staging/vc04_services/bcm2835-camera/controls.c
index cff7b1e07153..a2c55cb2192a 100644
--- a/drivers/staging/vc04_services/bcm2835-camera/controls.c
+++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c
@@ -1106,7 +1106,7 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = {
{
V4L2_CID_POWER_LINE_FREQUENCY, MMAL_CONTROL_TYPE_STD_MENU,
0, ARRAY_SIZE(mains_freq_qmenu) - 1,
- 1, 1, NULL,
+ 1, 1, mains_freq_qmenu,
MMAL_PARAMETER_FLICKER_AVOID,
&ctrl_set_flicker_avoidance,
false
diff --git a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c b/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c
index 51e5b04ff0f5..cc2d9933b969 100644
--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c
+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c
@@ -21,7 +21,6 @@
#include <linux/slab.h>
#include <linux/completion.h>
#include <linux/vmalloc.h>
-#include <asm/cacheflush.h>
#include <media/videobuf2-vmalloc.h>
#include "mmal-common.h"
@@ -1803,19 +1802,12 @@ int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance)
{
int status;
struct vchiq_mmal_instance *instance;
- static VCHI_CONNECTION_T *vchi_connection;
static VCHI_INSTANCE_T vchi_instance;
SERVICE_CREATION_T params = {
.version = VCHI_VERSION_EX(VC_MMAL_VER, VC_MMAL_MIN_VER),
.service_id = VC_MMAL_SERVER_NAME,
- .connection = vchi_connection,
- .rx_fifo_size = 0,
- .tx_fifo_size = 0,
.callback = service_callback,
.callback_param = NULL,
- .want_unaligned_bulk_rx = 1,
- .want_unaligned_bulk_tx = 1,
- .want_crc = 0
};
/* compile time checks to ensure structure size as they are
@@ -1839,7 +1831,7 @@ int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance)
return -EIO;
}
- status = vchi_connect(NULL, 0, vchi_instance);
+ status = vchi_connect(vchi_instance);
if (status) {
pr_err("Failed to connect VCHI instance (status=%d)\n", status);
return -EIO;
diff --git a/drivers/staging/vc04_services/interface/vchi/connections/connection.h b/drivers/staging/vc04_services/interface/vchi/connections/connection.h
deleted file mode 100644
index 67c84386c65a..000000000000
--- a/drivers/staging/vc04_services/interface/vchi/connections/connection.h
+++ /dev/null
@@ -1,324 +0,0 @@
-/**
- * Copyright (c) 2010-2012 Broadcom. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- * to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * 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.
- */
-
-#ifndef CONNECTION_H_
-#define CONNECTION_H_
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/semaphore.h>
-
-#include "interface/vchi/vchi_cfg_internal.h"
-#include "interface/vchi/vchi_common.h"
-#include "interface/vchi/message_drivers/message.h"
-
-/******************************************************************************
- Global defs
- *****************************************************************************/
-
-// Opaque handle for a connection / service pair
-typedef struct opaque_vchi_connection_connected_service_handle_t *VCHI_CONNECTION_SERVICE_HANDLE_T;
-
-// opaque handle to the connection state information
-typedef struct opaque_vchi_connection_info_t VCHI_CONNECTION_STATE_T;
-
-typedef struct vchi_connection_t VCHI_CONNECTION_T;
-
-/******************************************************************************
- API
- *****************************************************************************/
-
-// Routine to init a connection with a particular low level driver
-typedef VCHI_CONNECTION_STATE_T * (*VCHI_CONNECTION_INIT_T)( struct vchi_connection_t * connection,
- const VCHI_MESSAGE_DRIVER_T * driver );
-
-// Routine to control CRC enabling at a connection level
-typedef int32_t (*VCHI_CONNECTION_CRC_CONTROL_T)( VCHI_CONNECTION_STATE_T *state_handle,
- VCHI_CRC_CONTROL_T control );
-
-// Routine to create a service
-typedef int32_t (*VCHI_CONNECTION_SERVICE_CONNECT_T)( VCHI_CONNECTION_STATE_T *state_handle,
- int32_t service_id,
- uint32_t rx_fifo_size,
- uint32_t tx_fifo_size,
- int server,
- VCHI_CALLBACK_T callback,
- void *callback_param,
- int32_t want_crc,
- int32_t want_unaligned_bulk_rx,
- int32_t want_unaligned_bulk_tx,
- VCHI_CONNECTION_SERVICE_HANDLE_T *service_handle );
-
-// Routine to close a service
-typedef int32_t (*VCHI_CONNECTION_SERVICE_DISCONNECT_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle );
-
-// Routine to queue a message
-typedef int32_t (*VCHI_CONNECTION_SERVICE_QUEUE_MESSAGE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
- const void *data,
- uint32_t data_size,
- VCHI_FLAGS_T flags,
- void *msg_handle );
-
-// scatter-gather (vector) message queueing
-typedef int32_t (*VCHI_CONNECTION_SERVICE_QUEUE_MESSAGEV_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
- VCHI_MSG_VECTOR_T *vector,
- uint32_t count,
- VCHI_FLAGS_T flags,
- void *msg_handle );
-
-// Routine to dequeue a message
-typedef int32_t (*VCHI_CONNECTION_SERVICE_DEQUEUE_MESSAGE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
- void *data,
- uint32_t max_data_size_to_read,
- uint32_t *actual_msg_size,
- VCHI_FLAGS_T flags );
-
-// Routine to peek at a message
-typedef int32_t (*VCHI_CONNECTION_SERVICE_PEEK_MESSAGE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
- void **data,
- uint32_t *msg_size,
- VCHI_FLAGS_T flags );
-
-// Routine to hold a message
-typedef int32_t (*VCHI_CONNECTION_SERVICE_HOLD_MESSAGE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
- void **data,
- uint32_t *msg_size,
- VCHI_FLAGS_T flags,
- void **message_handle );
-
-// Routine to initialise a received message iterator
-typedef int32_t (*VCHI_CONNECTION_SERVICE_LOOKAHEAD_MESSAGE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
- VCHI_MSG_ITER_T *iter,
- VCHI_FLAGS_T flags );
-
-// Routine to release a held message
-typedef int32_t (*VCHI_CONNECTION_HELD_MSG_RELEASE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
- void *message_handle );
-
-// Routine to get info on a held message
-typedef int32_t (*VCHI_CONNECTION_HELD_MSG_INFO_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
- void *message_handle,
- void **data,
- int32_t *msg_size,
- uint32_t *tx_timestamp,
- uint32_t *rx_timestamp );
-
-// Routine to check whether the iterator has a next message
-typedef int32_t (*VCHI_CONNECTION_MSG_ITER_HAS_NEXT_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service,
- const VCHI_MSG_ITER_T *iter );
-
-// Routine to advance the iterator
-typedef int32_t (*VCHI_CONNECTION_MSG_ITER_NEXT_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service,
- VCHI_MSG_ITER_T *iter,
- void **data,
- uint32_t *msg_size );
-
-// Routine to remove the last message returned by the iterator
-typedef int32_t (*VCHI_CONNECTION_MSG_ITER_REMOVE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service,
- VCHI_MSG_ITER_T *iter );
-
-// Routine to hold the last message returned by the iterator
-typedef int32_t (*VCHI_CONNECTION_MSG_ITER_HOLD_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service,
- VCHI_MSG_ITER_T *iter,
- void **msg_handle );
-
-// Routine to transmit bulk data
-typedef int32_t (*VCHI_CONNECTION_BULK_QUEUE_TRANSMIT_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
- const void *data_src,
- uint32_t data_size,
- VCHI_FLAGS_T flags,
- void *bulk_handle );
-
-// Routine to receive data
-typedef int32_t (*VCHI_CONNECTION_BULK_QUEUE_RECEIVE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
- void *data_dst,
- uint32_t data_size,
- VCHI_FLAGS_T flags,
- void *bulk_handle );
-
-// Routine to report if a server is available
-typedef int32_t (*VCHI_CONNECTION_SERVER_PRESENT)( VCHI_CONNECTION_STATE_T *state, int32_t service_id, int32_t peer_flags );
-
-// Routine to report the number of RX slots available
-typedef int (*VCHI_CONNECTION_RX_SLOTS_AVAILABLE)( const VCHI_CONNECTION_STATE_T *state );
-
-// Routine to report the RX slot size
-typedef uint32_t (*VCHI_CONNECTION_RX_SLOT_SIZE)( const VCHI_CONNECTION_STATE_T *state );
-
-// Callback to indicate that the other side has added a buffer to the rx bulk DMA FIFO
-typedef void (*VCHI_CONNECTION_RX_BULK_BUFFER_ADDED)(VCHI_CONNECTION_STATE_T *state,
- int32_t service,
- uint32_t length,
- MESSAGE_TX_CHANNEL_T channel,
- uint32_t channel_params,
- uint32_t data_length,
- uint32_t data_offset);
-
-// Callback to inform a service that a Xon or Xoff message has been received
-typedef void (*VCHI_CONNECTION_FLOW_CONTROL)(VCHI_CONNECTION_STATE_T *state, int32_t service_id, int32_t xoff);
-
-// Callback to inform a service that a server available reply message has been received
-typedef void (*VCHI_CONNECTION_SERVER_AVAILABLE_REPLY)(VCHI_CONNECTION_STATE_T *state, int32_t service_id, uint32_t flags);
-
-// Callback to indicate that bulk auxiliary messages have arrived
-typedef void (*VCHI_CONNECTION_BULK_AUX_RECEIVED)(VCHI_CONNECTION_STATE_T *state);
-
-// Callback to indicate that bulk auxiliary messages have arrived
-typedef void (*VCHI_CONNECTION_BULK_AUX_TRANSMITTED)(VCHI_CONNECTION_STATE_T *state, void *handle);
-
-// Callback with all the connection info you require
-typedef void (*VCHI_CONNECTION_INFO)(VCHI_CONNECTION_STATE_T *state, uint32_t protocol_version, uint32_t slot_size, uint32_t num_slots, uint32_t min_bulk_size);
-
-// Callback to inform of a disconnect
-typedef void (*VCHI_CONNECTION_DISCONNECT)(VCHI_CONNECTION_STATE_T *state, uint32_t flags);
-
-// Callback to inform of a power control request
-typedef void (*VCHI_CONNECTION_POWER_CONTROL)(VCHI_CONNECTION_STATE_T *state, MESSAGE_TX_CHANNEL_T channel, int32_t enable);
-
-// allocate memory suitably aligned for this connection
-typedef void * (*VCHI_BUFFER_ALLOCATE)(VCHI_CONNECTION_SERVICE_HANDLE_T service_handle, uint32_t * length);
-
-// free memory allocated by buffer_allocate
-typedef void (*VCHI_BUFFER_FREE)(VCHI_CONNECTION_SERVICE_HANDLE_T service_handle, void * address);
-
-/******************************************************************************
- System driver struct
- *****************************************************************************/
-
-struct opaque_vchi_connection_api_t {
- // Routine to init the connection
- VCHI_CONNECTION_INIT_T init;
-
- // Connection-level CRC control
- VCHI_CONNECTION_CRC_CONTROL_T crc_control;
-
- // Routine to connect to or create service
- VCHI_CONNECTION_SERVICE_CONNECT_T service_connect;
-
- // Routine to disconnect from a service
- VCHI_CONNECTION_SERVICE_DISCONNECT_T service_disconnect;
-
- // Routine to queue a message
- VCHI_CONNECTION_SERVICE_QUEUE_MESSAGE_T service_queue_msg;
-
- // scatter-gather (vector) message queue
- VCHI_CONNECTION_SERVICE_QUEUE_MESSAGEV_T service_queue_msgv;
-
- // Routine to dequeue a message
- VCHI_CONNECTION_SERVICE_DEQUEUE_MESSAGE_T service_dequeue_msg;
-
- // Routine to peek at a message
- VCHI_CONNECTION_SERVICE_PEEK_MESSAGE_T service_peek_msg;
-
- // Routine to hold a message
- VCHI_CONNECTION_SERVICE_HOLD_MESSAGE_T service_hold_msg;
-
- // Routine to initialise a received message iterator
- VCHI_CONNECTION_SERVICE_LOOKAHEAD_MESSAGE_T service_look_ahead_msg;
-
- // Routine to release a message
- VCHI_CONNECTION_HELD_MSG_RELEASE_T held_msg_release;
-
- // Routine to get information on a held message
- VCHI_CONNECTION_HELD_MSG_INFO_T held_msg_info;
-
- // Routine to check for next message on iterator
- VCHI_CONNECTION_MSG_ITER_HAS_NEXT_T msg_iter_has_next;
-
- // Routine to get next message on iterator
- VCHI_CONNECTION_MSG_ITER_NEXT_T msg_iter_next;
-
- // Routine to remove the last message returned by iterator
- VCHI_CONNECTION_MSG_ITER_REMOVE_T msg_iter_remove;
-
- // Routine to hold the last message returned by iterator
- VCHI_CONNECTION_MSG_ITER_HOLD_T msg_iter_hold;
-
- // Routine to transmit bulk data
- VCHI_CONNECTION_BULK_QUEUE_TRANSMIT_T bulk_queue_transmit;
-
- // Routine to receive data
- VCHI_CONNECTION_BULK_QUEUE_RECEIVE_T bulk_queue_receive;
-
- // Routine to report the available servers
- VCHI_CONNECTION_SERVER_PRESENT server_present;
-
- // Routine to report the number of RX slots available
- VCHI_CONNECTION_RX_SLOTS_AVAILABLE connection_rx_slots_available;
-
- // Routine to report the RX slot size
- VCHI_CONNECTION_RX_SLOT_SIZE connection_rx_slot_size;
-
- // Callback to indicate that the other side has added a buffer to the rx bulk DMA FIFO
- VCHI_CONNECTION_RX_BULK_BUFFER_ADDED rx_bulk_buffer_added;
-
- // Callback to inform a service that a Xon or Xoff message has been received
- VCHI_CONNECTION_FLOW_CONTROL flow_control;
-
- // Callback to inform a service that a server available reply message has been received
- VCHI_CONNECTION_SERVER_AVAILABLE_REPLY server_available_reply;
-
- // Callback to indicate that bulk auxiliary messages have arrived
- VCHI_CONNECTION_BULK_AUX_RECEIVED bulk_aux_received;
-
- // Callback to indicate that a bulk auxiliary message has been transmitted
- VCHI_CONNECTION_BULK_AUX_TRANSMITTED bulk_aux_transmitted;
-
- // Callback to provide information about the connection
- VCHI_CONNECTION_INFO connection_info;
-
- // Callback to notify that peer has requested disconnect
- VCHI_CONNECTION_DISCONNECT disconnect;
-
- // Callback to notify that peer has requested power change
- VCHI_CONNECTION_POWER_CONTROL power_control;
-
- // allocate memory suitably aligned for this connection
- VCHI_BUFFER_ALLOCATE buffer_allocate;
-
- // free memory allocated by buffer_allocate
- VCHI_BUFFER_FREE buffer_free;
-
-};
-
-struct vchi_connection_t {
- const VCHI_CONNECTION_API_T *api;
- VCHI_CONNECTION_STATE_T *state;
-#ifdef VCHI_COARSE_LOCKING
- struct semaphore sem;
-#endif
-};
-
-#endif /* CONNECTION_H_ */
-
-/****************************** End of file **********************************/
diff --git a/drivers/staging/vc04_services/interface/vchi/message_drivers/message.h b/drivers/staging/vc04_services/interface/vchi/message_drivers/message.h
deleted file mode 100644
index 834263f278cf..000000000000
--- a/drivers/staging/vc04_services/interface/vchi/message_drivers/message.h
+++ /dev/null
@@ -1,196 +0,0 @@
-/**
- * Copyright (c) 2010-2012 Broadcom. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- * to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * 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.
- */
-
-#ifndef _VCHI_MESSAGE_H_
-#define _VCHI_MESSAGE_H_
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/semaphore.h>
-
-#include "interface/vchi/vchi_cfg_internal.h"
-#include "interface/vchi/vchi_common.h"
-
-typedef enum message_event_type {
- MESSAGE_EVENT_NONE,
- MESSAGE_EVENT_NOP,
- MESSAGE_EVENT_MESSAGE,
- MESSAGE_EVENT_SLOT_COMPLETE,
- MESSAGE_EVENT_RX_BULK_PAUSED,
- MESSAGE_EVENT_RX_BULK_COMPLETE,
- MESSAGE_EVENT_TX_COMPLETE,
- MESSAGE_EVENT_MSG_DISCARDED
-} MESSAGE_EVENT_TYPE_T;
-
-typedef enum vchi_msg_flags {
- VCHI_MSG_FLAGS_NONE = 0x0,
- VCHI_MSG_FLAGS_TERMINATE_DMA = 0x1
-} VCHI_MSG_FLAGS_T;
-
-typedef enum message_tx_channel {
- MESSAGE_TX_CHANNEL_MESSAGE = 0,
- MESSAGE_TX_CHANNEL_BULK = 1 // drivers may provide multiple bulk channels, from 1 upwards
-} MESSAGE_TX_CHANNEL_T;
-
-// Macros used for cycling through bulk channels
-#define MESSAGE_TX_CHANNEL_BULK_PREV(c) (MESSAGE_TX_CHANNEL_BULK+((c)-MESSAGE_TX_CHANNEL_BULK+VCHI_MAX_BULK_TX_CHANNELS_PER_CONNECTION-1)%VCHI_MAX_BULK_TX_CHANNELS_PER_CONNECTION)
-#define MESSAGE_TX_CHANNEL_BULK_NEXT(c) (MESSAGE_TX_CHANNEL_BULK+((c)-MESSAGE_TX_CHANNEL_BULK+1)%VCHI_MAX_BULK_TX_CHANNELS_PER_CONNECTION)
-
-typedef enum message_rx_channel {
- MESSAGE_RX_CHANNEL_MESSAGE = 0,
- MESSAGE_RX_CHANNEL_BULK = 1 // drivers may provide multiple bulk channels, from 1 upwards
-} MESSAGE_RX_CHANNEL_T;
-
-// Message receive slot information
-typedef struct rx_msg_slot_info {
-
- struct rx_msg_slot_info *next;
- //struct slot_info *prev;
-#if !defined VCHI_COARSE_LOCKING
- struct semaphore sem;
-#endif
-
- uint8_t *addr; // base address of slot
- uint32_t len; // length of slot in bytes
-
- uint32_t write_ptr; // hardware causes this to advance
- uint32_t read_ptr; // this module does the reading
- int active; // is this slot in the hardware dma fifo?
- uint32_t msgs_parsed; // count how many messages are in this slot
- uint32_t msgs_released; // how many messages have been released
- void *state; // connection state information
- uint8_t ref_count[VCHI_MAX_SERVICES_PER_CONNECTION]; // reference count for slots held by services
-} RX_MSG_SLOTINFO_T;
-
-// The message driver no longer needs to know about the fields of RX_BULK_SLOTINFO_T - sort this out.
-// In particular, it mustn't use addr and len - they're the client buffer, but the message
-// driver will be tasked with sending the aligned core section.
-typedef struct rx_bulk_slotinfo_t {
- struct rx_bulk_slotinfo_t *next;
-
- struct semaphore *blocking;
-
- // needed by DMA
- void *addr;
- uint32_t len;
-
- // needed for the callback
- void *service;
- void *handle;
- VCHI_FLAGS_T flags;
-} RX_BULK_SLOTINFO_T;
-
-/* ----------------------------------------------------------------------
- * each connection driver will have a pool of the following struct.
- *
- * the pool will be managed by vchi_qman_*
- * this means there will be multiple queues (single linked lists)
- * a given struct message_info will be on exactly one of these queues
- * at any one time
- * -------------------------------------------------------------------- */
-typedef struct rx_message_info {
-
- struct message_info *next;
- //struct message_info *prev;
-
- uint8_t *addr;
- uint32_t len;
- RX_MSG_SLOTINFO_T *slot; // points to whichever slot contains this message
- uint32_t tx_timestamp;
- uint32_t rx_timestamp;
-
-} RX_MESSAGE_INFO_T;
-
-typedef struct {
- MESSAGE_EVENT_TYPE_T type;
-
- struct {
- // for messages
- void *addr; // address of message
- uint16_t slot_delta; // whether this message indicated slot delta
- uint32_t len; // length of message
- RX_MSG_SLOTINFO_T *slot; // slot this message is in
- int32_t service; // service id this message is destined for
- uint32_t tx_timestamp; // timestamp from the header
- uint32_t rx_timestamp; // timestamp when we parsed it
- } message;
-
- // FIXME: cleanup slot reporting...
- RX_MSG_SLOTINFO_T *rx_msg;
- RX_BULK_SLOTINFO_T *rx_bulk;
- void *tx_handle;
- MESSAGE_TX_CHANNEL_T tx_channel;
-
-} MESSAGE_EVENT_T;
-
-// callbacks
-typedef void VCHI_MESSAGE_DRIVER_EVENT_CALLBACK_T( void *state );
-
-typedef struct {
- VCHI_MESSAGE_DRIVER_EVENT_CALLBACK_T *event_callback;
-} VCHI_MESSAGE_DRIVER_OPEN_T;
-
-// handle to this instance of message driver (as returned by ->open)
-typedef struct opaque_mhandle_t *VCHI_MDRIVER_HANDLE_T;
-
-struct opaque_vchi_message_driver_t {
- VCHI_MDRIVER_HANDLE_T *(*open)( VCHI_MESSAGE_DRIVER_OPEN_T *params, void *state );
- int32_t (*suspending)( VCHI_MDRIVER_HANDLE_T *handle );
- int32_t (*resumed)( VCHI_MDRIVER_HANDLE_T *handle );
- int32_t (*power_control)( VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_TX_CHANNEL_T, int32_t enable );
- int32_t (*add_msg_rx_slot)( VCHI_MDRIVER_HANDLE_T *handle, RX_MSG_SLOTINFO_T *slot ); // rx message
- int32_t (*add_bulk_rx)( VCHI_MDRIVER_HANDLE_T *handle, void *data, uint32_t len, RX_BULK_SLOTINFO_T *slot ); // rx data (bulk)
- int32_t (*send)( VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_TX_CHANNEL_T channel, const void *data, uint32_t len, VCHI_MSG_FLAGS_T flags, void *send_handle ); // tx (message & bulk)
- void (*next_event)( VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_EVENT_T *event ); // get the next event from message_driver
- int32_t (*enable)( VCHI_MDRIVER_HANDLE_T *handle );
- int32_t (*form_message)( VCHI_MDRIVER_HANDLE_T *handle, int32_t service_id, VCHI_MSG_VECTOR_T *vector, uint32_t count, void
- *address, uint32_t length_avail, uint32_t max_total_length, int32_t pad_to_fill, int32_t allow_partial );
-
- int32_t (*update_message)( VCHI_MDRIVER_HANDLE_T *handle, void *dest, int16_t *slot_count );
- int32_t (*buffer_aligned)( VCHI_MDRIVER_HANDLE_T *handle, int tx, int uncached, const void *address, const uint32_t length );
- void * (*allocate_buffer)( VCHI_MDRIVER_HANDLE_T *handle, uint32_t *length );
- void (*free_buffer)( VCHI_MDRIVER_HANDLE_T *handle, void *address );
- int (*rx_slot_size)( VCHI_MDRIVER_HANDLE_T *handle, int msg_size );
- int (*tx_slot_size)( VCHI_MDRIVER_HANDLE_T *handle, int msg_size );
-
- int32_t (*tx_supports_terminate)( const VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_TX_CHANNEL_T channel );
- uint32_t (*tx_bulk_chunk_size)( const VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_TX_CHANNEL_T channel );
- int (*tx_alignment)( const VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_TX_CHANNEL_T channel );
- int (*rx_alignment)( const VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_RX_CHANNEL_T channel );
- void (*form_bulk_aux)( VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_TX_CHANNEL_T channel, const void *data, uint32_t len, uint32_t chunk_size, const void **aux_data, int32_t *aux_len );
- void (*debug)( VCHI_MDRIVER_HANDLE_T *handle );
-};
-
-#endif // _VCHI_MESSAGE_H_
-
-/****************************** End of file ***********************************/
diff --git a/drivers/staging/vc04_services/interface/vchi/vchi.h b/drivers/staging/vc04_services/interface/vchi/vchi.h
index 66a3a060fad2..01381904775d 100644
--- a/drivers/staging/vc04_services/interface/vchi/vchi.h
+++ b/drivers/staging/vc04_services/interface/vchi/vchi.h
@@ -36,7 +36,6 @@
#include "interface/vchi/vchi_cfg.h"
#include "interface/vchi/vchi_common.h"
-#include "interface/vchi/connections/connection.h"
#include "vchi_mh.h"
/******************************************************************************
@@ -60,46 +59,8 @@ struct vchi_version {
#define VCHI_VERSION(v_) { v_, v_ }
#define VCHI_VERSION_EX(v_, m_) { v_, m_ }
-typedef enum {
- VCHI_VEC_POINTER,
- VCHI_VEC_HANDLE,
- VCHI_VEC_LIST
-} VCHI_MSG_VECTOR_TYPE_T;
-
-typedef struct vchi_msg_vector_ex {
-
- VCHI_MSG_VECTOR_TYPE_T type;
- union {
- // a memory handle
- struct {
- VCHI_MEM_HANDLE_T handle;
- uint32_t offset;
- int32_t vec_len;
- } handle;
-
- // an ordinary data pointer
- struct {
- const void *vec_base;
- int32_t vec_len;
- } ptr;
-
- // a nested vector list
- struct {
- struct vchi_msg_vector_ex *vec;
- uint32_t vec_len;
- } list;
- } u;
-} VCHI_MSG_VECTOR_EX_T;
-
-// Construct an entry in a msg vector for a pointer (p) of length (l)
-#define VCHI_VEC_POINTER(p,l) VCHI_VEC_POINTER, { { (VCHI_MEM_HANDLE_T)(p), (l) } }
-
-// Construct an entry in a msg vector for a message handle (h), starting at offset (o) of length (l)
-#define VCHI_VEC_HANDLE(h,o,l) VCHI_VEC_HANDLE, { { (h), (o), (l) } }
-
// Macros to manipulate 'FOURCC' values
-#define MAKE_FOURCC(x) ((int32_t)( (x[0] << 24) | (x[1] << 16) | (x[2] << 8) | x[3] ))
-#define FOURCC_TO_CHAR(x) (x >> 24) & 0xFF,(x >> 16) & 0xFF,(x >> 8) & 0xFF, x & 0xFF
+#define MAKE_FOURCC(x) ((int32_t)((x[0] << 24) | (x[1] << 16) | (x[2] << 8) | x[3]))
// Opaque service information
struct opaque_vchi_service_t;
@@ -115,20 +76,8 @@ typedef struct {
typedef struct {
struct vchi_version version;
int32_t service_id;
- VCHI_CONNECTION_T *connection;
- uint32_t rx_fifo_size;
- uint32_t tx_fifo_size;
VCHI_CALLBACK_T callback;
void *callback_param;
- /* client intends to receive bulk transfers of
- odd lengths or into unaligned buffers */
- int32_t want_unaligned_bulk_rx;
- /* client intends to transmit bulk transfers of
- odd lengths or out of unaligned buffers */
- int32_t want_unaligned_bulk_tx;
- /* client wants to check CRCs on (bulk) xfers.
- Only needs to be set at 1 end - will do both directions. */
- int32_t want_crc;
} SERVICE_CREATION_T;
// Opaque handle for a VCHI instance
@@ -137,15 +86,6 @@ typedef struct opaque_vchi_instance_handle_t *VCHI_INSTANCE_T;
// Opaque handle for a server or client
typedef struct opaque_vchi_service_handle_t *VCHI_SERVICE_HANDLE_T;
-// Service registration & startup
-typedef void (*VCHI_SERVICE_INIT)(VCHI_INSTANCE_T initialise_instance, VCHI_CONNECTION_T **connections, uint32_t num_connections);
-
-typedef struct service_info_tag {
- const char * const vll_filename; /* VLL to load to start this service. This is an empty string if VLL is "static" */
- VCHI_SERVICE_INIT init; /* Service initialisation function */
- void *vll_handle; /* VLL handle; NULL when unloaded or a "static VLL" in build */
-} SERVICE_INFO_T;
-
/******************************************************************************
Global funcs - implementation is specific to which side you are on (local / remote)
*****************************************************************************/
@@ -154,28 +94,19 @@ typedef struct service_info_tag {
extern "C" {
#endif
-extern /*@observer@*/ VCHI_CONNECTION_T * vchi_create_connection( const VCHI_CONNECTION_API_T * function_table,
- const VCHI_MESSAGE_DRIVER_T * low_level);
-
// Routine used to initialise the vchi on both local + remote connections
-extern int32_t vchi_initialise( VCHI_INSTANCE_T *instance_handle );
+extern int32_t vchi_initialise(VCHI_INSTANCE_T *instance_handle);
-extern int32_t vchi_exit( void );
+extern int32_t vchi_exit(void);
-extern int32_t vchi_connect( VCHI_CONNECTION_T **connections,
- const uint32_t num_connections,
- VCHI_INSTANCE_T instance_handle );
+extern int32_t vchi_connect(VCHI_INSTANCE_T instance_handle);
//When this is called, ensure that all services have no data pending.
//Bulk transfers can remain 'queued'
-extern int32_t vchi_disconnect( VCHI_INSTANCE_T instance_handle );
-
-// Global control over bulk CRC checking
-extern int32_t vchi_crc_control( VCHI_CONNECTION_T *connection,
- VCHI_CRC_CONTROL_T control );
+extern int32_t vchi_disconnect(VCHI_INSTANCE_T instance_handle);
// helper functions
-extern void * vchi_allocate_buffer(VCHI_SERVICE_HANDLE_T handle, uint32_t *length);
+extern void *vchi_allocate_buffer(VCHI_SERVICE_HANDLE_T handle, uint32_t *length);
extern void vchi_free_buffer(VCHI_SERVICE_HANDLE_T handle, void *address);
extern uint32_t vchi_current_time(VCHI_INSTANCE_T instance_handle);
@@ -183,32 +114,32 @@ extern uint32_t vchi_current_time(VCHI_INSTANCE_T instance_handle);
Global service API
*****************************************************************************/
// Routine to create a named service
-extern int32_t vchi_service_create( VCHI_INSTANCE_T instance_handle,
- SERVICE_CREATION_T *setup,
- VCHI_SERVICE_HANDLE_T *handle );
+extern int32_t vchi_service_create(VCHI_INSTANCE_T instance_handle,
+ SERVICE_CREATION_T *setup,
+ VCHI_SERVICE_HANDLE_T *handle);
// Routine to destroy a service
-extern int32_t vchi_service_destroy( const VCHI_SERVICE_HANDLE_T handle );
+extern int32_t vchi_service_destroy(const VCHI_SERVICE_HANDLE_T handle);
// Routine to open a named service
-extern int32_t vchi_service_open( VCHI_INSTANCE_T instance_handle,
- SERVICE_CREATION_T *setup,
- VCHI_SERVICE_HANDLE_T *handle);
+extern int32_t vchi_service_open(VCHI_INSTANCE_T instance_handle,
+ SERVICE_CREATION_T *setup,
+ VCHI_SERVICE_HANDLE_T *handle);
-extern int32_t vchi_get_peer_version( const VCHI_SERVICE_HANDLE_T handle,
- short *peer_version );
+extern int32_t vchi_get_peer_version(const VCHI_SERVICE_HANDLE_T handle,
+ short *peer_version);
// Routine to close a named service
-extern int32_t vchi_service_close( const VCHI_SERVICE_HANDLE_T handle );
+extern int32_t vchi_service_close(const VCHI_SERVICE_HANDLE_T handle);
// Routine to increment ref count on a named service
-extern int32_t vchi_service_use( const VCHI_SERVICE_HANDLE_T handle );
+extern int32_t vchi_service_use(const VCHI_SERVICE_HANDLE_T handle);
// Routine to decrement ref count on a named service
-extern int32_t vchi_service_release( const VCHI_SERVICE_HANDLE_T handle );
+extern int32_t vchi_service_release(const VCHI_SERVICE_HANDLE_T handle);
// Routine to set a control option for a named service
-extern int32_t vchi_service_set_option( const VCHI_SERVICE_HANDLE_T handle,
+extern int32_t vchi_service_set_option(const VCHI_SERVICE_HANDLE_T handle,
VCHI_SERVICE_OPTION_T option,
int value);
@@ -226,128 +157,120 @@ vchi_queue_user_message(VCHI_SERVICE_HANDLE_T handle,
// Routine to receive a msg from a service
// Dequeue is equivalent to hold, copy into client buffer, release
-extern int32_t vchi_msg_dequeue( VCHI_SERVICE_HANDLE_T handle,
- void *data,
- uint32_t max_data_size_to_read,
- uint32_t *actual_msg_size,
- VCHI_FLAGS_T flags );
+extern int32_t vchi_msg_dequeue(VCHI_SERVICE_HANDLE_T handle,
+ void *data,
+ uint32_t max_data_size_to_read,
+ uint32_t *actual_msg_size,
+ VCHI_FLAGS_T flags);
// Routine to look at a message in place.
// The message is not dequeued, so a subsequent call to peek or dequeue
// will return the same message.
-extern int32_t vchi_msg_peek( VCHI_SERVICE_HANDLE_T handle,
- void **data,
- uint32_t *msg_size,
- VCHI_FLAGS_T flags );
+extern int32_t vchi_msg_peek(VCHI_SERVICE_HANDLE_T handle,
+ void **data,
+ uint32_t *msg_size,
+ VCHI_FLAGS_T flags);
// Routine to remove a message after it has been read in place with peek
// The first message on the queue is dequeued.
-extern int32_t vchi_msg_remove( VCHI_SERVICE_HANDLE_T handle );
+extern int32_t vchi_msg_remove(VCHI_SERVICE_HANDLE_T handle);
// Routine to look at a message in place.
// The message is dequeued, so the caller is left holding it; the descriptor is
// filled in and must be released when the user has finished with the message.
-extern int32_t vchi_msg_hold( VCHI_SERVICE_HANDLE_T handle,
- void **data, // } may be NULL, as info can be
- uint32_t *msg_size, // } obtained from HELD_MSG_T
- VCHI_FLAGS_T flags,
- VCHI_HELD_MSG_T *message_descriptor );
+extern int32_t vchi_msg_hold(VCHI_SERVICE_HANDLE_T handle,
+ void **data, // } may be NULL, as info can be
+ uint32_t *msg_size, // } obtained from HELD_MSG_T
+ VCHI_FLAGS_T flags,
+ VCHI_HELD_MSG_T *message_descriptor);
// Initialise an iterator to look through messages in place
-extern int32_t vchi_msg_look_ahead( VCHI_SERVICE_HANDLE_T handle,
- VCHI_MSG_ITER_T *iter,
- VCHI_FLAGS_T flags );
+extern int32_t vchi_msg_look_ahead(VCHI_SERVICE_HANDLE_T handle,
+ VCHI_MSG_ITER_T *iter,
+ VCHI_FLAGS_T flags);
/******************************************************************************
Global service support API - operations on held messages and message iterators
*****************************************************************************/
// Routine to get the address of a held message
-extern void *vchi_held_msg_ptr( const VCHI_HELD_MSG_T *message );
+extern void *vchi_held_msg_ptr(const VCHI_HELD_MSG_T *message);
// Routine to get the size of a held message
-extern int32_t vchi_held_msg_size( const VCHI_HELD_MSG_T *message );
+extern int32_t vchi_held_msg_size(const VCHI_HELD_MSG_T *message);
// Routine to get the transmit timestamp as written into the header by the peer
-extern uint32_t vchi_held_msg_tx_timestamp( const VCHI_HELD_MSG_T *message );
+extern uint32_t vchi_held_msg_tx_timestamp(const VCHI_HELD_MSG_T *message);
// Routine to get the reception timestamp, written as we parsed the header
-extern uint32_t vchi_held_msg_rx_timestamp( const VCHI_HELD_MSG_T *message );
+extern uint32_t vchi_held_msg_rx_timestamp(const VCHI_HELD_MSG_T *message);
// Routine to release a held message after it has been processed
-extern int32_t vchi_held_msg_release( VCHI_HELD_MSG_T *message );
+extern int32_t vchi_held_msg_release(VCHI_HELD_MSG_T *message);
// Indicates whether the iterator has a next message.
-extern int32_t vchi_msg_iter_has_next( const VCHI_MSG_ITER_T *iter );
+extern int32_t vchi_msg_iter_has_next(const VCHI_MSG_ITER_T *iter);
// Return the pointer and length for the next message and advance the iterator.
-extern int32_t vchi_msg_iter_next( VCHI_MSG_ITER_T *iter,
- void **data,
- uint32_t *msg_size );
+extern int32_t vchi_msg_iter_next(VCHI_MSG_ITER_T *iter,
+ void **data,
+ uint32_t *msg_size);
// Remove the last message returned by vchi_msg_iter_next.
// Can only be called once after each call to vchi_msg_iter_next.
-extern int32_t vchi_msg_iter_remove( VCHI_MSG_ITER_T *iter );
+extern int32_t vchi_msg_iter_remove(VCHI_MSG_ITER_T *iter);
// Hold the last message returned by vchi_msg_iter_next.
// Can only be called once after each call to vchi_msg_iter_next.
-extern int32_t vchi_msg_iter_hold( VCHI_MSG_ITER_T *iter,
- VCHI_HELD_MSG_T *message );
+extern int32_t vchi_msg_iter_hold(VCHI_MSG_ITER_T *iter,
+ VCHI_HELD_MSG_T *message);
// Return information for the next message, and hold it, advancing the iterator.
-extern int32_t vchi_msg_iter_hold_next( VCHI_MSG_ITER_T *iter,
- void **data, // } may be NULL
- uint32_t *msg_size, // }
- VCHI_HELD_MSG_T *message );
+extern int32_t vchi_msg_iter_hold_next(VCHI_MSG_ITER_T *iter,
+ void **data, // } may be NULL
+ uint32_t *msg_size, // }
+ VCHI_HELD_MSG_T *message);
/******************************************************************************
Global bulk API
*****************************************************************************/
// Routine to prepare interface for a transfer from the other side
-extern int32_t vchi_bulk_queue_receive( VCHI_SERVICE_HANDLE_T handle,
- void *data_dst,
- uint32_t data_size,
- VCHI_FLAGS_T flags,
- void *transfer_handle );
+extern int32_t vchi_bulk_queue_receive(VCHI_SERVICE_HANDLE_T handle,
+ void *data_dst,
+ uint32_t data_size,
+ VCHI_FLAGS_T flags,
+ void *transfer_handle);
// Prepare interface for a transfer from the other side into relocatable memory.
-int32_t vchi_bulk_queue_receive_reloc( const VCHI_SERVICE_HANDLE_T handle,
- VCHI_MEM_HANDLE_T h_dst,
- uint32_t offset,
- uint32_t data_size,
- const VCHI_FLAGS_T flags,
- void * const bulk_handle );
+int32_t vchi_bulk_queue_receive_reloc(const VCHI_SERVICE_HANDLE_T handle,
+ VCHI_MEM_HANDLE_T h_dst,
+ uint32_t offset,
+ uint32_t data_size,
+ const VCHI_FLAGS_T flags,
+ void * const bulk_handle);
// Routine to queue up data ready for transfer to the other (once they have signalled they are ready)
-extern int32_t vchi_bulk_queue_transmit( VCHI_SERVICE_HANDLE_T handle,
- const void *data_src,
- uint32_t data_size,
- VCHI_FLAGS_T flags,
- void *transfer_handle );
+extern int32_t vchi_bulk_queue_transmit(VCHI_SERVICE_HANDLE_T handle,
+ const void *data_src,
+ uint32_t data_size,
+ VCHI_FLAGS_T flags,
+ void *transfer_handle);
/******************************************************************************
Configuration plumbing
*****************************************************************************/
-// function prototypes for the different mid layers (the state info gives the different physical connections)
-extern const VCHI_CONNECTION_API_T *single_get_func_table( void );
-//extern const VCHI_CONNECTION_API_T *local_server_get_func_table( void );
-//extern const VCHI_CONNECTION_API_T *local_client_get_func_table( void );
-
-// declare all message drivers here
-const VCHI_MESSAGE_DRIVER_T *vchi_mphi_message_driver_func_table( void );
-
#ifdef __cplusplus
}
#endif
-extern int32_t vchi_bulk_queue_transmit_reloc( VCHI_SERVICE_HANDLE_T handle,
- VCHI_MEM_HANDLE_T h_src,
- uint32_t offset,
- uint32_t data_size,
- VCHI_FLAGS_T flags,
- void *transfer_handle );
+extern int32_t vchi_bulk_queue_transmit_reloc(VCHI_SERVICE_HANDLE_T handle,
+ VCHI_MEM_HANDLE_T h_src,
+ uint32_t offset,
+ uint32_t data_size,
+ VCHI_FLAGS_T flags,
+ void *transfer_handle);
#endif /* VCHI_H_ */
/****************************** End of file **********************************/
diff --git a/drivers/staging/vc04_services/interface/vchi/vchi_cfg.h b/drivers/staging/vc04_services/interface/vchi/vchi_cfg.h
index b6f42b86f206..0d3c468c3504 100644
--- a/drivers/staging/vc04_services/interface/vchi/vchi_cfg.h
+++ b/drivers/staging/vc04_services/interface/vchi/vchi_cfg.h
@@ -138,7 +138,7 @@
* can guarantee this by enabling unaligned transmits).
* Not API. */
#ifndef VCHI_MIN_BULK_SIZE
-# define VCHI_MIN_BULK_SIZE ( VCHI_MAX_MSG_SIZE / 2 < 4096 ? VCHI_MAX_MSG_SIZE / 2 : 4096 )
+# define VCHI_MIN_BULK_SIZE (VCHI_MAX_MSG_SIZE / 2 < 4096 ? VCHI_MAX_MSG_SIZE / 2 : 4096)
#endif
/* Maximum size of bulk transmission chunks, for each interface type. A trade-off between
diff --git a/drivers/staging/vc04_services/interface/vchi/vchi_cfg_internal.h b/drivers/staging/vc04_services/interface/vchi/vchi_cfg_internal.h
deleted file mode 100644
index 35dcba4837d4..000000000000
--- a/drivers/staging/vc04_services/interface/vchi/vchi_cfg_internal.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/**
- * Copyright (c) 2010-2012 Broadcom. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- * to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * 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.
- */
-
-#ifndef VCHI_CFG_INTERNAL_H_
-#define VCHI_CFG_INTERNAL_H_
-
-/****************************************************************************************
- * Control optimisation attempts.
- ***************************************************************************************/
-
-// Don't use lots of short-term locks - use great long ones, reducing the overall locks-per-second
-#define VCHI_COARSE_LOCKING
-
-// Avoid lock then unlock on exit from blocking queue operations (msg tx, bulk rx/tx)
-// (only relevant if VCHI_COARSE_LOCKING)
-#define VCHI_ELIDE_BLOCK_EXIT_LOCK
-
-// Avoid lock on non-blocking peek
-// (only relevant if VCHI_COARSE_LOCKING)
-#define VCHI_AVOID_PEEK_LOCK
-
-// Use one slot-handler thread per connection, rather than 1 thread dealing with all connections in rotation.
-#define VCHI_MULTIPLE_HANDLER_THREADS
-
-// Put free descriptors onto the head of the free queue, rather than the tail, so that we don't thrash
-// our way through the pool of descriptors.
-#define VCHI_PUSH_FREE_DESCRIPTORS_ONTO_HEAD
-
-// Don't issue a MSG_AVAILABLE callback for every single message. Possibly only safe if VCHI_COARSE_LOCKING.
-#define VCHI_FEWER_MSG_AVAILABLE_CALLBACKS
-
-// Don't use message descriptors for TX messages that don't need them
-#define VCHI_MINIMISE_TX_MSG_DESCRIPTORS
-
-// Nano-locks for multiqueue
-//#define VCHI_MQUEUE_NANOLOCKS
-
-// Lock-free(er) dequeuing
-//#define VCHI_RX_NANOLOCKS
-
-#endif /*VCHI_CFG_INTERNAL_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 e76720903064..83d740feab96 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
@@ -109,7 +109,8 @@ free_pagelist(struct vchiq_pagelist_info *pagelistinfo,
int vchiq_platform_init(struct platform_device *pdev, VCHIQ_STATE_T *state)
{
struct device *dev = &pdev->dev;
- struct rpi_firmware *fw = platform_get_drvdata(pdev);
+ struct vchiq_drvdata *drvdata = platform_get_drvdata(pdev);
+ struct rpi_firmware *fw = drvdata->fw;
VCHIQ_SLOT_ZERO_T *vchiq_slot_zero;
struct resource *res;
void *slot_mem;
@@ -127,6 +128,7 @@ int vchiq_platform_init(struct platform_device *pdev, VCHIQ_STATE_T *state)
if (err < 0)
return err;
+ g_cache_line_size = drvdata->cache_line_size;
g_fragments_size = 2 * g_cache_line_size;
/* Allocate space for the channels in coherent memory */
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 bc05c69383b8..ea789376de0f 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
@@ -170,6 +170,14 @@ static struct device *vchiq_dev;
static DEFINE_SPINLOCK(msg_queue_spinlock);
static struct platform_device *bcm2835_camera;
+static struct vchiq_drvdata bcm2835_drvdata = {
+ .cache_line_size = 32,
+};
+
+static struct vchiq_drvdata bcm2836_drvdata = {
+ .cache_line_size = 64,
+};
+
static const char *const ioctl_names[] = {
"CONNECT",
"SHUTDOWN",
@@ -3573,12 +3581,25 @@ void vchiq_platform_conn_state_changed(VCHIQ_STATE_T *state,
}
}
+static const struct of_device_id vchiq_of_match[] = {
+ { .compatible = "brcm,bcm2835-vchiq", .data = &bcm2835_drvdata },
+ { .compatible = "brcm,bcm2836-vchiq", .data = &bcm2836_drvdata },
+ {},
+};
+MODULE_DEVICE_TABLE(of, vchiq_of_match);
+
static int vchiq_probe(struct platform_device *pdev)
{
struct device_node *fw_node;
- struct rpi_firmware *fw;
+ const struct of_device_id *of_id;
+ struct vchiq_drvdata *drvdata;
int err;
+ of_id = of_match_node(vchiq_of_match, pdev->dev.of_node);
+ drvdata = (struct vchiq_drvdata *)of_id->data;
+ if (!drvdata)
+ return -EINVAL;
+
fw_node = of_find_compatible_node(NULL, NULL,
"raspberrypi,bcm2835-firmware");
if (!fw_node) {
@@ -3586,12 +3607,12 @@ static int vchiq_probe(struct platform_device *pdev)
return -ENOENT;
}
- fw = rpi_firmware_get(fw_node);
+ drvdata->fw = rpi_firmware_get(fw_node);
of_node_put(fw_node);
- if (!fw)
+ if (!drvdata->fw)
return -EPROBE_DEFER;
- platform_set_drvdata(pdev, fw);
+ platform_set_drvdata(pdev, drvdata);
err = vchiq_platform_init(pdev, &g_state);
if (err != 0)
@@ -3661,12 +3682,6 @@ static int vchiq_remove(struct platform_device *pdev)
return 0;
}
-static const struct of_device_id vchiq_of_match[] = {
- { .compatible = "brcm,bcm2835-vchiq", },
- {},
-};
-MODULE_DEVICE_TABLE(of, vchiq_of_match);
-
static struct platform_driver vchiq_driver = {
.driver = {
.name = "bcm2835_vchiq",
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 40bb0c63b1a9..2f3ebc99cbcf 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h
@@ -123,6 +123,11 @@ typedef struct vchiq_arm_state_struct {
} VCHIQ_ARM_STATE_T;
+struct vchiq_drvdata {
+ const unsigned int cache_line_size;
+ struct rpi_firmware *fw;
+};
+
extern int vchiq_arm_log_level;
extern int vchiq_susp_log_level;
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_genversion b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_genversion
deleted file mode 100644
index dd1f324a8654..000000000000
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_genversion
+++ /dev/null
@@ -1,88 +0,0 @@
-#!/usr/bin/perl -w
-# SPDX-License-Identifier: GPL-2.0
-
-use strict;
-
-#
-# Generate a version from available information
-#
-
-my $prefix = shift @ARGV;
-my $root = shift @ARGV;
-
-
-if ( not defined $root ) {
- die "usage: $0 prefix root-dir\n";
-}
-
-if ( ! -d $root ) {
- die "root directory $root not found\n";
-}
-
-my $version = "unknown";
-my $tainted = "";
-
-if ( -d "$root/.git" ) {
- # attempt to work out git version. only do so
- # on a linux build host, as cygwin builds are
- # already slow enough
-
- if ( -f "/usr/bin/git" || -f "/usr/local/bin/git" ) {
- if (not open(F, "git --git-dir $root/.git rev-parse --verify HEAD|")) {
- $version = "no git version";
- }
- else {
- $version = <F>;
- $version =~ s/[ \r\n]*$//; # chomp may not be enough (cygwin).
- $version =~ s/^[ \r\n]*//; # chomp may not be enough (cygwin).
- }
-
- if (open(G, "git --git-dir $root/.git status --porcelain|")) {
- $tainted = <G>;
- $tainted =~ s/[ \r\n]*$//; # chomp may not be enough (cygwin).
- $tainted =~ s/^[ \r\n]*//; # chomp may not be enough (cygwin).
- if (length $tainted) {
- $version = join ' ', $version, "(tainted)";
- }
- else {
- $version = join ' ', $version, "(clean)";
- }
- }
- }
-}
-
-my $hostname = `hostname`;
-$hostname =~ s/[ \r\n]*$//; # chomp may not be enough (cygwin).
-$hostname =~ s/^[ \r\n]*//; # chomp may not be enough (cygwin).
-
-
-print STDERR "Version $version\n";
-print <<EOF;
-#include "${prefix}_build_info.h"
-#include <linux/broadcom/vc_debug_sym.h>
-
-VC_DEBUG_DECLARE_STRING_VAR( ${prefix}_build_hostname, "$hostname" );
-VC_DEBUG_DECLARE_STRING_VAR( ${prefix}_build_version, "$version" );
-VC_DEBUG_DECLARE_STRING_VAR( ${prefix}_build_time, __TIME__ );
-VC_DEBUG_DECLARE_STRING_VAR( ${prefix}_build_date, __DATE__ );
-
-const char *vchiq_get_build_hostname( void )
-{
- return vchiq_build_hostname;
-}
-
-const char *vchiq_get_build_version( void )
-{
- return vchiq_build_version;
-}
-
-const char *vchiq_get_build_date( void )
-{
- return vchiq_build_date;
-}
-
-const char *vchiq_get_build_time( void )
-{
- return vchiq_build_time;
-}
-EOF
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_shim.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_shim.c
index dddc828390d0..c3223fcdaf87 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_shim.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_shim.c
@@ -50,33 +50,6 @@ struct shim_service {
void *callback_param;
};
-/* ----------------------------------------------------------------------
- * return pointer to the mphi message driver function table
- * -------------------------------------------------------------------- */
-const VCHI_MESSAGE_DRIVER_T *
-vchi_mphi_message_driver_func_table(void)
-{
- return NULL;
-}
-
-/* ----------------------------------------------------------------------
- * return a pointer to the 'single' connection driver fops
- * -------------------------------------------------------------------- */
-const VCHI_CONNECTION_API_T *
-single_get_func_table(void)
-{
- return NULL;
-}
-
-VCHI_CONNECTION_T *vchi_create_connection(
- const VCHI_CONNECTION_API_T *function_table,
- const VCHI_MESSAGE_DRIVER_T *low_level)
-{
- (void)function_table;
- (void)low_level;
- return NULL;
-}
-
/***********************************************************
* Name: vchi_msg_peek
*
@@ -517,9 +490,7 @@ EXPORT_SYMBOL(vchi_initialise);
/***********************************************************
* Name: vchi_connect
*
- * Arguments: VCHI_CONNECTION_T **connections
- * const uint32_t num_connections
- * VCHI_INSTANCE_T instance_handle)
+ * Arguments: VCHI_INSTANCE_T instance_handle
*
* Description: Starts the command service on each connection,
* causing INIT messages to be pinged back and forth
@@ -527,15 +498,10 @@ EXPORT_SYMBOL(vchi_initialise);
* Returns: 0 if successful, failure otherwise
*
***********************************************************/
-int32_t vchi_connect(VCHI_CONNECTION_T **connections,
- const uint32_t num_connections,
- VCHI_INSTANCE_T instance_handle)
+int32_t vchi_connect(VCHI_INSTANCE_T instance_handle)
{
VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
- (void)connections;
- (void)num_connections;
-
return vchiq_connect(instance);
}
EXPORT_SYMBOL(vchi_connect);
diff --git a/drivers/staging/vt6655/rxtx.c b/drivers/staging/vt6655/rxtx.c
index 9c4a5325afc7..a7c1e46a953e 100644
--- a/drivers/staging/vt6655/rxtx.c
+++ b/drivers/staging/vt6655/rxtx.c
@@ -65,6 +65,7 @@ static const unsigned short wFB_Opt0[2][5] = {
{RATE_12M, RATE_18M, RATE_24M, RATE_36M, RATE_48M}, /* fallback_rate0 */
{RATE_12M, RATE_12M, RATE_18M, RATE_24M, RATE_36M}, /* fallback_rate1 */
};
+
static const unsigned short wFB_Opt1[2][5] = {
{RATE_12M, RATE_18M, RATE_24M, RATE_24M, RATE_36M}, /* fallback_rate0 */
{RATE_6M, RATE_6M, RATE_12M, RATE_12M, RATE_18M}, /* fallback_rate1 */
@@ -212,12 +213,12 @@ s_uGetRTSCTSRsvTime(
} else if (byRTSRsvType == 3) { /* CTSTxRrvTime_ba, only in 2.4GHZ */
uCTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopCCKBasicRate);
uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate);
- uRrvTime = uCTSTime + uAckTime + uDataTime + 2*pDevice->uSIFS;
+ uRrvTime = uCTSTime + uAckTime + uDataTime + 2 * pDevice->uSIFS;
return cpu_to_le16((u16)uRrvTime);
}
/* RTSRrvTime */
- uRrvTime = uRTSTime + uCTSTime + uAckTime + uDataTime + 3*pDevice->uSIFS;
+ uRrvTime = uRTSTime + uCTSTime + uAckTime + uDataTime + 3 * pDevice->uSIFS;
return cpu_to_le16((u16)uRrvTime);
}
@@ -240,7 +241,7 @@ s_uGetDataDuration(
bool bLastFrag = false;
unsigned int uAckTime = 0, uNextPktTime = 0;
- if (uFragIdx == (uMACfragNum-1))
+ if (uFragIdx == (uMACfragNum - 1))
bLastFrag = true;
switch (byDurType) {
@@ -253,7 +254,7 @@ s_uGetDataDuration(
return 0;
}
} else {/* First Frag or Mid Frag */
- if (uFragIdx == (uMACfragNum-2))
+ if (uFragIdx == (uMACfragNum - 2))
uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wRate, bNeedAck);
else
uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wRate, bNeedAck);
@@ -276,7 +277,7 @@ s_uGetDataDuration(
return 0;
}
} else {/* First Frag or Mid Frag */
- if (uFragIdx == (uMACfragNum-2))
+ if (uFragIdx == (uMACfragNum - 2))
uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wRate, bNeedAck);
else
uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wRate, bNeedAck);
@@ -305,7 +306,7 @@ s_uGetDataDuration(
else if (wRate > RATE_54M)
wRate = RATE_54M;
- if (uFragIdx == (uMACfragNum-2))
+ if (uFragIdx == (uMACfragNum - 2))
uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wFB_Opt0[FB_RATE0][wRate-RATE_18M], bNeedAck);
else
uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt0[FB_RATE0][wRate-RATE_18M], bNeedAck);
@@ -316,7 +317,7 @@ s_uGetDataDuration(
else if (wRate > RATE_54M)
wRate = RATE_54M;
- if (uFragIdx == (uMACfragNum-2))
+ if (uFragIdx == (uMACfragNum - 2))
uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wFB_Opt1[FB_RATE0][wRate-RATE_18M], bNeedAck);
else
uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE0][wRate-RATE_18M], bNeedAck);
@@ -346,7 +347,7 @@ s_uGetDataDuration(
else if (wRate > RATE_54M)
wRate = RATE_54M;
- if (uFragIdx == (uMACfragNum-2))
+ if (uFragIdx == (uMACfragNum - 2))
uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wFB_Opt0[FB_RATE1][wRate-RATE_18M], bNeedAck);
else
uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt0[FB_RATE1][wRate-RATE_18M], bNeedAck);
@@ -357,7 +358,7 @@ s_uGetDataDuration(
else if (wRate > RATE_54M)
wRate = RATE_54M;
- if (uFragIdx == (uMACfragNum-2))
+ if (uFragIdx == (uMACfragNum - 2))
uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wFB_Opt1[FB_RATE1][wRate-RATE_18M], bNeedAck);
else
uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE1][wRate-RATE_18M], bNeedAck);
@@ -1093,7 +1094,7 @@ s_cbFillTxBufHead(struct vnt_private *pDevice, unsigned char byPktType,
sizeof(struct vnt_tx_datahead_g);
} else { /* RTS_needless */
pvRrvTime = (void *)(pbyTxBufferAddr + wTxBufSize);
- pMICHDR = (struct vnt_mic_hdr *) (pbyTxBufferAddr + wTxBufSize + sizeof(struct vnt_rrv_time_cts));
+ pMICHDR = (struct vnt_mic_hdr *)(pbyTxBufferAddr + wTxBufSize + sizeof(struct vnt_rrv_time_cts));
pvRTS = NULL;
pvCTS = (void *) (pbyTxBufferAddr + wTxBufSize + sizeof(struct vnt_rrv_time_cts) + cbMICHDR);
pvTxDataHd = (void *)(pbyTxBufferAddr + wTxBufSize +
@@ -1105,7 +1106,7 @@ s_cbFillTxBufHead(struct vnt_private *pDevice, unsigned char byPktType,
/* Auto Fall Back */
if (bRTS) {/* RTS_need */
pvRrvTime = (void *)(pbyTxBufferAddr + wTxBufSize);
- pMICHDR = (struct vnt_mic_hdr *) (pbyTxBufferAddr + wTxBufSize + sizeof(struct vnt_rrv_time_rts));
+ pMICHDR = (struct vnt_mic_hdr *)(pbyTxBufferAddr + wTxBufSize + sizeof(struct vnt_rrv_time_rts));
pvRTS = (void *) (pbyTxBufferAddr + wTxBufSize + sizeof(struct vnt_rrv_time_rts) + cbMICHDR);
pvCTS = NULL;
pvTxDataHd = (void *)(pbyTxBufferAddr + wTxBufSize + sizeof(struct vnt_rrv_time_rts) +
@@ -1114,7 +1115,7 @@ s_cbFillTxBufHead(struct vnt_private *pDevice, unsigned char byPktType,
cbMICHDR + sizeof(struct vnt_rts_g_fb) + sizeof(struct vnt_tx_datahead_g_fb);
} else { /* RTS_needless */
pvRrvTime = (void *)(pbyTxBufferAddr + wTxBufSize);
- pMICHDR = (struct vnt_mic_hdr *) (pbyTxBufferAddr + wTxBufSize + sizeof(struct vnt_rrv_time_cts));
+ pMICHDR = (struct vnt_mic_hdr *)(pbyTxBufferAddr + wTxBufSize + sizeof(struct vnt_rrv_time_cts));
pvRTS = NULL;
pvCTS = (void *)(pbyTxBufferAddr + wTxBufSize + sizeof(struct vnt_rrv_time_cts) + cbMICHDR);
pvTxDataHd = (void *)(pbyTxBufferAddr + wTxBufSize + sizeof(struct vnt_rrv_time_cts) +
@@ -1128,7 +1129,7 @@ s_cbFillTxBufHead(struct vnt_private *pDevice, unsigned char byPktType,
if (byFBOption == AUTO_FB_NONE) {
if (bRTS) {
pvRrvTime = (void *)(pbyTxBufferAddr + wTxBufSize);
- pMICHDR = (struct vnt_mic_hdr *) (pbyTxBufferAddr + wTxBufSize + sizeof(struct vnt_rrv_time_ab));
+ pMICHDR = (struct vnt_mic_hdr *)(pbyTxBufferAddr + wTxBufSize + sizeof(struct vnt_rrv_time_ab));
pvRTS = (void *)(pbyTxBufferAddr + wTxBufSize + sizeof(struct vnt_rrv_time_ab) + cbMICHDR);
pvCTS = NULL;
pvTxDataHd = (void *)(pbyTxBufferAddr + wTxBufSize +
@@ -1137,7 +1138,7 @@ s_cbFillTxBufHead(struct vnt_private *pDevice, unsigned char byPktType,
cbMICHDR + sizeof(struct vnt_rts_ab) + sizeof(struct vnt_tx_datahead_ab);
} else { /* RTS_needless, need MICHDR */
pvRrvTime = (void *)(pbyTxBufferAddr + wTxBufSize);
- pMICHDR = (struct vnt_mic_hdr *) (pbyTxBufferAddr + wTxBufSize + sizeof(struct vnt_rrv_time_ab));
+ pMICHDR = (struct vnt_mic_hdr *)(pbyTxBufferAddr + wTxBufSize + sizeof(struct vnt_rrv_time_ab));
pvRTS = NULL;
pvCTS = NULL;
pvTxDataHd = (void *)(pbyTxBufferAddr + wTxBufSize + sizeof(struct vnt_rrv_time_ab) + cbMICHDR);
diff --git a/drivers/staging/wilc1000/Kconfig b/drivers/staging/wilc1000/Kconfig
index 73f7fefd3bc3..f9d3ad41c862 100644
--- a/drivers/staging/wilc1000/Kconfig
+++ b/drivers/staging/wilc1000/Kconfig
@@ -1,13 +1,13 @@
config WILC1000
tristate
- ---help---
+ help
This module only support IEEE 802.11n WiFi.
config WILC1000_SDIO
tristate "Atmel WILC1000 SDIO (WiFi only)"
depends on CFG80211 && INET && MMC
select WILC1000
- ---help---
+ help
This module adds support for the SDIO interface of adapters using
WILC1000 chipset. The Atmel WILC1000 SDIO is a full speed interface.
It meets SDIO card specification version 2.0. The interface supports
@@ -21,7 +21,7 @@ config WILC1000_SPI
tristate "Atmel WILC1000 SPI (WiFi only)"
depends on CFG80211 && INET && SPI
select WILC1000
- ---help---
+ help
This module adds support for the SPI interface of adapters using
WILC1000 chipset. The Atmel WILC1000 has a Serial Peripheral
Interface (SPI) that operates as a SPI slave. This SPI interface can
@@ -34,7 +34,7 @@ config WILC1000_HW_OOB_INTR
bool "WILC1000 out of band interrupt"
depends on WILC1000_SDIO
default n
- ---help---
+ help
This option enables out-of-band interrupt support for the WILC1000
chipset. This OOB interrupt is intended to provide a faster interrupt
mechanism for SDIO host controllers that don't support SDIO interrupt.
diff --git a/drivers/staging/wilc1000/Makefile b/drivers/staging/wilc1000/Makefile
index ee7e26b886a5..37e8560e501e 100644
--- a/drivers/staging/wilc1000/Makefile
+++ b/drivers/staging/wilc1000/Makefile
@@ -4,12 +4,9 @@ obj-$(CONFIG_WILC1000) += wilc1000.o
ccflags-y += -DFIRMWARE_1002=\"atmel/wilc1002_firmware.bin\" \
-DFIRMWARE_1003=\"atmel/wilc1003_firmware.bin\"
-ccflags-y += -I$(src)/ -DWILC_ASIC_A0 -DWILC_DEBUGFS
-
wilc1000-objs := wilc_wfi_cfgoperations.o linux_wlan.o linux_mon.o \
coreconfigurator.o host_interface.o \
- wilc_wlan_cfg.o wilc_debugfs.o \
- wilc_wlan.o
+ wilc_wlan_cfg.o wilc_wlan.o
obj-$(CONFIG_WILC1000_SDIO) += wilc1000-sdio.o
wilc1000-sdio-objs += wilc_sdio.o
diff --git a/drivers/staging/wilc1000/coreconfigurator.c b/drivers/staging/wilc1000/coreconfigurator.c
index e5420676afb3..d6d3a971be43 100644
--- a/drivers/staging/wilc1000/coreconfigurator.c
+++ b/drivers/staging/wilc1000/coreconfigurator.c
@@ -116,7 +116,7 @@ static inline void get_address3(u8 *msa, u8 *addr)
memcpy(addr, msa + 16, 6);
}
-static inline void get_BSSID(u8 *data, u8 *bssid)
+static inline void get_bssid(u8 *data, u8 *bssid)
{
if (get_from_ds(data) == 1)
get_address2(data, bssid);
@@ -233,7 +233,7 @@ s32 wilc_parse_network_info(u8 *msg_buffer,
network_info->tsf_hi = tsf_lo | ((u64)tsf_hi << 32);
get_ssid(msa, network_info->ssid, &network_info->ssid_len);
- get_BSSID(msa, network_info->bssid);
+ get_bssid(msa, network_info->bssid);
network_info->ch = get_current_channel_802_11n(msa, rx_len
+ FCS_LEN);
diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c
index 42d8accb1f60..01db8999335e 100644
--- a/drivers/staging/wilc1000/host_interface.c
+++ b/drivers/staging/wilc1000/host_interface.c
@@ -90,6 +90,7 @@ struct beacon_attr {
struct set_multicast {
bool enabled;
u32 cnt;
+ u8 *mc_list;
};
struct del_all_sta {
@@ -186,23 +187,7 @@ struct join_bss_param {
};
static struct host_if_drv *terminated_handle;
-bool wilc_optaining_ip;
-static u8 p2p_listen_state;
-static struct workqueue_struct *hif_workqueue;
-static struct completion hif_driver_comp;
static struct mutex hif_deinit_lock;
-static struct timer_list periodic_rssi;
-static struct wilc_vif *periodic_rssi_vif;
-
-u8 wilc_multicast_mac_addr_list[WILC_MULTICAST_TABLE_SIZE][ETH_ALEN];
-
-static u8 rcv_assoc_resp[MAX_ASSOC_RESP_FRAME_SIZE];
-
-static u8 set_ip[2][4];
-static u8 get_ip[2][4];
-static u32 clients_count;
-
-static int host_int_get_ipaddress(struct wilc_vif *vif, u8 *ip_addr, u8 idx);
/* 'msg' should be free by the caller for syc */
static struct host_if_msg*
@@ -229,7 +214,11 @@ wilc_alloc_work(struct wilc_vif *vif, void (*work_fun)(struct work_struct *),
static int wilc_enqueue_work(struct host_if_msg *msg)
{
INIT_WORK(&msg->work, msg->fn);
- if (!hif_workqueue || !queue_work(hif_workqueue, &msg->work))
+
+ if (!msg->vif || !msg->vif->wilc || !msg->vif->wilc->hif_workqueue)
+ return -EINVAL;
+
+ if (!queue_work(msg->vif->wilc->hif_workqueue, &msg->work))
return -EINVAL;
return 0;
@@ -320,10 +309,12 @@ static void handle_set_wfi_drv_handler(struct work_struct *work)
if (ret)
netdev_err(vif->ndev, "Failed to set driver handler\n");
- complete(&hif_driver_comp);
kfree(buffer);
free_msg:
+ if (msg->is_sync)
+ complete(&msg->work_comp);
+
kfree(msg);
}
@@ -343,73 +334,12 @@ static void handle_set_operation_mode(struct work_struct *work)
ret = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
wilc_get_vif_idx(vif));
- if (hif_op_mode->mode == IDLE_MODE)
- complete(&hif_driver_comp);
-
if (ret)
netdev_err(vif->ndev, "Failed to set operation mode\n");
kfree(msg);
}
-static void handle_set_ip_address(struct work_struct *work)
-{
- struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
- struct wilc_vif *vif = msg->vif;
- u8 *ip_addr = msg->body.ip_info.ip_addr;
- u8 idx = msg->body.ip_info.idx;
- int ret;
- struct wid wid;
- char firmware_ip_addr[4] = {0};
-
- if (ip_addr[0] < 192)
- ip_addr[0] = 0;
-
- memcpy(set_ip[idx], ip_addr, IP_ALEN);
-
- wid.id = WID_IP_ADDRESS;
- wid.type = WID_STR;
- wid.val = ip_addr;
- wid.size = IP_ALEN;
-
- ret = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
- wilc_get_vif_idx(vif));
-
- host_int_get_ipaddress(vif, firmware_ip_addr, idx);
-
- if (ret)
- netdev_err(vif->ndev, "Failed to set IP address\n");
- kfree(msg);
-}
-
-static void handle_get_ip_address(struct work_struct *work)
-{
- struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
- struct wilc_vif *vif = msg->vif;
- u8 idx = msg->body.ip_info.idx;
- int ret;
- struct wid wid;
-
- wid.id = WID_IP_ADDRESS;
- wid.type = WID_STR;
- wid.val = kmalloc(IP_ALEN, GFP_KERNEL);
- wid.size = IP_ALEN;
-
- ret = wilc_send_config_pkt(vif, GET_CFG, &wid, 1,
- wilc_get_vif_idx(vif));
-
- memcpy(get_ip[idx], wid.val, IP_ALEN);
-
- kfree(wid.val);
-
- if (memcmp(get_ip[idx], set_ip[idx], IP_ALEN) != 0)
- wilc_setup_ipaddress(vif, set_ip[idx], idx);
-
- if (ret)
- netdev_err(vif->ndev, "Failed to get IP address\n");
- kfree(msg);
-}
-
static void handle_get_mac_address(struct work_struct *work)
{
struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
@@ -791,7 +721,7 @@ static void handle_scan(struct work_struct *work)
goto error;
}
- if (wilc_optaining_ip || wilc_connecting) {
+ if (vif->obtaining_ip || vif->connecting) {
netdev_err(vif->ndev, "Don't do obss scan\n");
result = -EBUSY;
goto error;
@@ -883,7 +813,6 @@ error:
kfree(msg);
}
-u8 wilc_connected_ssid[6] = {0};
static void handle_connect(struct work_struct *work)
{
struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
@@ -905,11 +834,6 @@ static void handle_connect(struct work_struct *work)
return;
}
- if (memcmp(conn_attr->bssid, wilc_connected_ssid, ETH_ALEN) == 0) {
- netdev_err(vif->ndev, "Discard connect request\n");
- goto error;
- }
-
bss_param = conn_attr->params;
if (!bss_param) {
netdev_err(vif->ndev, "Required BSSID not found\n");
@@ -1089,10 +1013,6 @@ static void handle_connect(struct work_struct *work)
cur_byte = wid_list[wid_cnt].val;
wid_cnt++;
- if (conn_attr->bssid)
- memcpy(wilc_connected_ssid,
- conn_attr->bssid, ETH_ALEN);
-
result = wilc_send_config_pkt(vif, SET_CFG, wid_list,
wid_cnt,
wilc_get_vif_idx(vif));
@@ -1215,8 +1135,6 @@ static void handle_connect_timeout(struct work_struct *work)
kfree(hif_drv->usr_conn_req.ies);
hif_drv->usr_conn_req.ies = NULL;
- eth_zero_addr(wilc_connected_ssid);
-
out:
kfree(msg);
}
@@ -1456,10 +1374,10 @@ done:
kfree(msg);
}
-static s32 host_int_get_assoc_res_info(struct wilc_vif *vif,
- u8 *assoc_resp_info,
- u32 max_assoc_resp_info_len,
- u32 *rcvd_assoc_resp_info_len)
+static void host_int_get_assoc_res_info(struct wilc_vif *vif,
+ u8 *assoc_resp_info,
+ u32 max_assoc_resp_info_len,
+ u32 *rcvd_assoc_resp_info_len)
{
int result;
struct wid wid;
@@ -1474,11 +1392,10 @@ static s32 host_int_get_assoc_res_info(struct wilc_vif *vif,
if (result) {
*rcvd_assoc_resp_info_len = 0;
netdev_err(vif->ndev, "Failed to send association response\n");
- return -EINVAL;
+ return;
}
*rcvd_assoc_resp_info_len = wid.size;
- return result;
}
static inline void host_int_free_user_conn_req(struct host_if_drv *hif_drv)
@@ -1504,16 +1421,16 @@ static inline void host_int_parse_assoc_resp_info(struct wilc_vif *vif,
if (mac_status == MAC_STATUS_CONNECTED) {
u32 assoc_resp_info_len;
- memset(rcv_assoc_resp, 0, MAX_ASSOC_RESP_FRAME_SIZE);
+ memset(hif_drv->assoc_resp, 0, MAX_ASSOC_RESP_FRAME_SIZE);
- host_int_get_assoc_res_info(vif, rcv_assoc_resp,
+ host_int_get_assoc_res_info(vif, hif_drv->assoc_resp,
MAX_ASSOC_RESP_FRAME_SIZE,
&assoc_resp_info_len);
if (assoc_resp_info_len != 0) {
s32 err = 0;
- err = wilc_parse_assoc_resp_info(rcv_assoc_resp,
+ err = wilc_parse_assoc_resp_info(hif_drv->assoc_resp,
assoc_resp_info_len,
&conn_info);
if (err)
@@ -1523,16 +1440,6 @@ static inline void host_int_parse_assoc_resp_info(struct wilc_vif *vif,
}
}
- if (mac_status == MAC_STATUS_CONNECTED &&
- conn_info.status != WLAN_STATUS_SUCCESS) {
- netdev_err(vif->ndev,
- "Received MAC status is MAC_STATUS_CONNECTED, Assoc Resp is not SUCCESS\n");
- eth_zero_addr(wilc_connected_ssid);
- } else if (mac_status == MAC_STATUS_DISCONNECTED) {
- netdev_err(vif->ndev, "Received MAC status is MAC_STATUS_DISCONNECTED\n");
- eth_zero_addr(wilc_connected_ssid);
- }
-
if (hif_drv->usr_conn_req.bssid) {
memcpy(conn_info.bssid, hif_drv->usr_conn_req.bssid, 6);
@@ -1562,8 +1469,8 @@ static inline void host_int_parse_assoc_resp_info(struct wilc_vif *vif,
hif_drv->hif_state = HOST_IF_CONNECTED;
- wilc_optaining_ip = true;
- mod_timer(&wilc_during_ip_timer,
+ vif->obtaining_ip = true;
+ mod_timer(&vif->during_ip_timer,
jiffies + msecs_to_jiffies(10000));
} else {
hif_drv->hif_state = HOST_IF_IDLE;
@@ -1595,7 +1502,7 @@ static inline void host_int_handle_disconnect(struct wilc_vif *vif)
disconn_info.ie_len = 0;
if (conn_result) {
- wilc_optaining_ip = false;
+ vif->obtaining_ip = false;
wilc_set_power_mgmt(vif, 0, 0);
conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF, NULL, 0,
@@ -1942,11 +1849,9 @@ static void handle_disconnect(struct work_struct *work)
wid.val = (s8 *)&dummy_reason_code;
wid.size = sizeof(char);
- wilc_optaining_ip = false;
+ vif->obtaining_ip = false;
wilc_set_power_mgmt(vif, 0, 0);
- eth_zero_addr(wilc_connected_ssid);
-
result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
wilc_get_vif_idx(vif));
@@ -2076,9 +1981,9 @@ static void handle_get_statistics(struct work_struct *work)
if (stats->link_speed > TCP_ACK_FILTER_LINK_SPEED_THRESH &&
stats->link_speed != DEFAULT_LINK_SPEED)
- wilc_enable_tcp_ack_filter(true);
+ wilc_enable_tcp_ack_filter(vif, true);
else if (stats->link_speed != DEFAULT_LINK_SPEED)
- wilc_enable_tcp_ack_filter(false);
+ wilc_enable_tcp_ack_filter(vif, false);
/* free 'msg' for async command, for sync caller will free it */
if (msg->is_sync)
@@ -2397,7 +2302,7 @@ static int handle_remain_on_chan(struct wilc_vif *vif,
goto error;
}
- if (wilc_optaining_ip || wilc_connecting) {
+ if (vif->obtaining_ip || vif->connecting) {
result = -EBUSY;
goto error;
}
@@ -2422,7 +2327,6 @@ static int handle_remain_on_chan(struct wilc_vif *vif,
netdev_err(vif->ndev, "Failed to set remain on channel\n");
error:
- p2p_listen_state = 1;
hif_drv->remain_on_ch_timer_vif = vif;
mod_timer(&hif_drv->remain_on_ch_timer,
jiffies + msecs_to_jiffies(hif_remain_ch->duration));
@@ -2478,8 +2382,9 @@ static void handle_listen_state_expired(struct work_struct *work)
struct wid wid;
int result;
struct host_if_drv *hif_drv = vif->hif_drv;
+ struct wilc_priv *priv = wdev_priv(vif->ndev->ieee80211_ptr);
- if (p2p_listen_state) {
+ if (priv->p2p_listen_state) {
remain_on_chan_flag = false;
wid.id = WID_REMAIN_ON_CHAN;
wid.type = WID_STR;
@@ -2504,7 +2409,6 @@ static void handle_listen_state_expired(struct work_struct *work)
hif_drv->remain_on_ch.expired(hif_drv->remain_on_ch.arg,
hif_remain_ch->id);
}
- p2p_listen_state = 0;
} else {
netdev_dbg(vif->ndev, "Not in listen state\n");
}
@@ -2589,8 +2493,8 @@ static void handle_set_mcast_filter(struct work_struct *work)
*cur_byte++ = ((hif_set_mc->cnt >> 16) & 0xFF);
*cur_byte++ = ((hif_set_mc->cnt >> 24) & 0xFF);
- if (hif_set_mc->cnt > 0)
- memcpy(cur_byte, wilc_multicast_mac_addr_list,
+ if (hif_set_mc->cnt > 0 && hif_set_mc->mc_list)
+ memcpy(cur_byte, hif_set_mc->mc_list,
((hif_set_mc->cnt) * ETH_ALEN));
result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
@@ -2599,6 +2503,7 @@ static void handle_set_mcast_filter(struct work_struct *work)
netdev_err(vif->ndev, "Failed to send setup multicast\n");
error:
+ kfree(hif_set_mc->mc_list);
kfree(wid.val);
kfree(msg);
}
@@ -2661,14 +2566,6 @@ static void handle_remain_on_chan_work(struct work_struct *work)
kfree(msg);
}
-static void handle_hif_exit_work(struct work_struct *work)
-{
- struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
-
- /* free 'msg' data in caller */
- complete(&msg->work_comp);
-}
-
static void handle_scan_complete(struct work_struct *work)
{
struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
@@ -3195,12 +3092,12 @@ int wilc_set_mac_chnl_num(struct wilc_vif *vif, u8 channel)
}
int wilc_set_wfi_drv_handler(struct wilc_vif *vif, int index, u8 mode,
- u8 ifc_id)
+ u8 ifc_id, bool is_sync)
{
int result;
struct host_if_msg *msg;
- msg = wilc_alloc_work(vif, handle_set_wfi_drv_handler, false);
+ msg = wilc_alloc_work(vif, handle_set_wfi_drv_handler, is_sync);
if (IS_ERR(msg))
return PTR_ERR(msg);
@@ -3212,8 +3109,12 @@ int wilc_set_wfi_drv_handler(struct wilc_vif *vif, int index, u8 mode,
if (result) {
netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
kfree(msg);
+ return result;
}
+ if (is_sync)
+ wait_for_completion(&msg->work_comp);
+
return result;
}
@@ -3421,9 +3322,9 @@ int wilc_hif_set_cfg(struct wilc_vif *vif,
return result;
}
-static void get_periodic_rssi(struct timer_list *unused)
+static void get_periodic_rssi(struct timer_list *t)
{
- struct wilc_vif *vif = periodic_rssi_vif;
+ struct wilc_vif *vif = from_timer(vif, t, periodic_rssi);
if (!vif->hif_drv) {
netdev_err(vif->ndev, "%s: hif driver is NULL", __func__);
@@ -3431,9 +3332,9 @@ static void get_periodic_rssi(struct timer_list *unused)
}
if (vif->hif_drv->hif_state == HOST_IF_CONNECTED)
- wilc_get_statistics(vif, &vif->wilc->dummy_statistics, false);
+ wilc_get_statistics(vif, &vif->periodic_stat, false);
- mod_timer(&periodic_rssi, jiffies + msecs_to_jiffies(5000));
+ mod_timer(&vif->periodic_rssi, jiffies + msecs_to_jiffies(5000));
}
int wilc_init(struct net_device *dev, struct host_if_drv **hif_drv_handler)
@@ -3455,25 +3356,13 @@ int wilc_init(struct net_device *dev, struct host_if_drv **hif_drv_handler)
break;
}
- wilc_optaining_ip = false;
+ vif->obtaining_ip = false;
- if (clients_count == 0) {
- init_completion(&hif_driver_comp);
+ if (wilc->clients_count == 0)
mutex_init(&hif_deinit_lock);
- }
- if (clients_count == 0) {
- hif_workqueue = create_singlethread_workqueue("WILC_wq");
- if (!hif_workqueue) {
- netdev_err(vif->ndev, "Failed to create workqueue\n");
- kfree(hif_drv);
- return -ENOMEM;
- }
-
- periodic_rssi_vif = vif;
- timer_setup(&periodic_rssi, get_periodic_rssi, 0);
- mod_timer(&periodic_rssi, jiffies + msecs_to_jiffies(5000));
- }
+ timer_setup(&vif->periodic_rssi, get_periodic_rssi, 0);
+ mod_timer(&vif->periodic_rssi, jiffies + msecs_to_jiffies(5000));
timer_setup(&hif_drv->scan_timer, timer_scan_cb, 0);
timer_setup(&hif_drv->connect_timer, timer_connect_cb, 0);
@@ -3493,7 +3382,7 @@ int wilc_init(struct net_device *dev, struct host_if_drv **hif_drv_handler)
mutex_unlock(&hif_drv->cfg_values_lock);
- clients_count++;
+ wilc->clients_count++;
return 0;
}
@@ -3514,11 +3403,10 @@ int wilc_deinit(struct wilc_vif *vif)
del_timer_sync(&hif_drv->scan_timer);
del_timer_sync(&hif_drv->connect_timer);
- del_timer_sync(&periodic_rssi);
+ del_timer_sync(&vif->periodic_rssi);
del_timer_sync(&hif_drv->remain_on_ch_timer);
- wilc_set_wfi_drv_handler(vif, 0, 0, 0);
- wait_for_completion(&hif_driver_comp);
+ wilc_set_wfi_drv_handler(vif, 0, 0, 0, true);
if (hif_drv->usr_scan_req.scan_result) {
hif_drv->usr_scan_req.scan_result(SCAN_EVENT_ABORTED, NULL,
@@ -3529,25 +3417,9 @@ int wilc_deinit(struct wilc_vif *vif)
hif_drv->hif_state = HOST_IF_IDLE;
- if (clients_count == 1) {
- struct host_if_msg *msg;
-
- msg = wilc_alloc_work(vif, handle_hif_exit_work, true);
- if (!IS_ERR(msg)) {
- result = wilc_enqueue_work(msg);
- if (result)
- netdev_err(vif->ndev, "deinit : Error(%d)\n",
- result);
- else
- wait_for_completion(&msg->work_comp);
- kfree(msg);
- }
- destroy_workqueue(hif_workqueue);
- }
-
kfree(hif_drv);
- clients_count--;
+ vif->wilc->clients_count--;
terminated_handle = NULL;
mutex_unlock(&hif_deinit_lock);
return result;
@@ -3743,14 +3615,14 @@ int wilc_listen_state_expired(struct wilc_vif *vif, u32 session_id)
return result;
}
-int wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg)
+void wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg)
{
int result;
struct host_if_msg *msg;
msg = wilc_alloc_work(vif, handle_register_frame, false);
if (IS_ERR(msg))
- return PTR_ERR(msg);
+ return;
switch (frame_type) {
case ACTION:
@@ -3772,8 +3644,6 @@ int wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg)
netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
kfree(msg);
}
-
- return result;
}
int wilc_add_beacon(struct wilc_vif *vif, u32 interval, u32 dtim_period,
@@ -3992,8 +3862,8 @@ int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled, u32 timeout)
return result;
}
-int wilc_setup_multicast_filter(struct wilc_vif *vif, bool enabled,
- u32 count)
+int wilc_setup_multicast_filter(struct wilc_vif *vif, bool enabled, u32 count,
+ u8 *mc_list)
{
int result;
struct host_if_msg *msg;
@@ -4004,6 +3874,7 @@ int wilc_setup_multicast_filter(struct wilc_vif *vif, bool enabled,
msg->body.multicast_info.enabled = enabled;
msg->body.multicast_info.cnt = count;
+ msg->body.multicast_info.mc_list = mc_list;
result = wilc_enqueue_work(msg);
if (result) {
@@ -4013,48 +3884,6 @@ int wilc_setup_multicast_filter(struct wilc_vif *vif, bool enabled,
return result;
}
-int wilc_setup_ipaddress(struct wilc_vif *vif, u8 *ip_addr, u8 idx)
-{
- int result;
- struct host_if_msg *msg;
-
- msg = wilc_alloc_work(vif, handle_set_ip_address, false);
- if (IS_ERR(msg))
- return PTR_ERR(msg);
-
- msg->body.ip_info.ip_addr = ip_addr;
- msg->body.ip_info.idx = idx;
-
- result = wilc_enqueue_work(msg);
- if (result) {
- netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
- kfree(msg);
- }
-
- return result;
-}
-
-static int host_int_get_ipaddress(struct wilc_vif *vif, u8 *ip_addr, u8 idx)
-{
- int result;
- struct host_if_msg *msg;
-
- msg = wilc_alloc_work(vif, handle_get_ip_address, false);
- if (IS_ERR(msg))
- return PTR_ERR(msg);
-
- msg->body.ip_info.ip_addr = ip_addr;
- msg->body.ip_info.idx = idx;
-
- result = wilc_enqueue_work(msg);
- if (result) {
- netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
- kfree(msg);
- }
-
- return result;
-}
-
int wilc_set_tx_power(struct wilc_vif *vif, u8 tx_power)
{
int ret;
diff --git a/drivers/staging/wilc1000/host_interface.h b/drivers/staging/wilc1000/host_interface.h
index 84866a62a4d4..33fb7318734b 100644
--- a/drivers/staging/wilc1000/host_interface.h
+++ b/drivers/staging/wilc1000/host_interface.h
@@ -9,8 +9,6 @@
#include <linux/ieee80211.h>
#include "coreconfigurator.h"
-#define IP_ALEN 4
-
#define IDLE_MODE 0x00
#define AP_MODE 0x01
#define STATION_MODE 0x02
@@ -284,6 +282,7 @@ struct host_if_drv {
bool ifc_up;
int driver_handler_id;
+ u8 assoc_resp[MAX_ASSOC_RESP_FRAME_SIZE];
};
struct add_sta_param {
@@ -341,18 +340,17 @@ int wilc_del_station(struct wilc_vif *vif, const u8 *mac_addr);
int wilc_edit_station(struct wilc_vif *vif,
struct add_sta_param *sta_param);
int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled, u32 timeout);
-int wilc_setup_multicast_filter(struct wilc_vif *vif, bool enabled,
- u32 count);
-int wilc_setup_ipaddress(struct wilc_vif *vif, u8 *ip_addr, u8 idx);
+int wilc_setup_multicast_filter(struct wilc_vif *vif, bool enabled, u32 count,
+ u8 *mc_list);
int wilc_remain_on_channel(struct wilc_vif *vif, u32 session_id,
u32 duration, u16 chan,
wilc_remain_on_chan_expired expired,
wilc_remain_on_chan_ready ready,
void *user_arg);
int wilc_listen_state_expired(struct wilc_vif *vif, u32 session_id);
-int wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg);
+void wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg);
int wilc_set_wfi_drv_handler(struct wilc_vif *vif, int index, u8 mode,
- u8 ifc_id);
+ u8 ifc_id, bool is_sync);
int wilc_set_operation_mode(struct wilc_vif *vif, u32 mode);
int wilc_get_statistics(struct wilc_vif *vif, struct rf_info *stats,
bool is_sync);
@@ -361,11 +359,4 @@ int wilc_get_vif_idx(struct wilc_vif *vif);
int wilc_set_tx_power(struct wilc_vif *vif, u8 tx_power);
int wilc_get_tx_power(struct wilc_vif *vif, u8 *tx_power);
-extern bool wilc_optaining_ip;
-extern u8 wilc_connected_ssid[6];
-extern u8 wilc_multicast_mac_addr_list[WILC_MULTICAST_TABLE_SIZE][ETH_ALEN];
-
-extern int wilc_connecting;
-extern struct timer_list wilc_during_ip_timer;
-
#endif
diff --git a/drivers/staging/wilc1000/linux_mon.c b/drivers/staging/wilc1000/linux_mon.c
index 1afdb9e86bc1..a63446818eac 100644
--- a/drivers/staging/wilc1000/linux_mon.c
+++ b/drivers/staging/wilc1000/linux_mon.c
@@ -253,7 +253,7 @@ struct net_device *wilc_wfi_init_mon_interface(const char *name,
return wilc_wfi_mon;
}
-int wilc_wfi_deinit_mon_interface(void)
+void wilc_wfi_deinit_mon_interface(void)
{
bool rollback_lock = false;
@@ -270,5 +270,4 @@ int wilc_wfi_deinit_mon_interface(void)
}
wilc_wfi_mon = NULL;
}
- return 0;
}
diff --git a/drivers/staging/wilc1000/linux_wlan.c b/drivers/staging/wilc1000/linux_wlan.c
index 3b8d237decbf..76c901235e93 100644
--- a/drivers/staging/wilc1000/linux_wlan.c
+++ b/drivers/staging/wilc1000/linux_wlan.c
@@ -12,8 +12,6 @@
#include "wilc_wfi_cfgoperations.h"
-bool wilc_enable_ps = true;
-
static int dev_state_ev_handler(struct notifier_block *this,
unsigned long event, void *ptr)
{
@@ -50,11 +48,11 @@ static int dev_state_ev_handler(struct notifier_block *this,
case NETDEV_UP:
if (vif->iftype == STATION_MODE || vif->iftype == CLIENT_MODE) {
hif_drv->ifc_up = 1;
- wilc_optaining_ip = false;
- del_timer(&wilc_during_ip_timer);
+ vif->obtaining_ip = false;
+ del_timer(&vif->during_ip_timer);
}
- if (wilc_enable_ps)
+ if (vif->wilc->enable_ps)
wilc_set_power_mgmt(vif, 1, 0);
netdev_dbg(dev, "[%s] Up IP\n", dev_iface->ifa_label);
@@ -63,14 +61,13 @@ static int dev_state_ev_handler(struct notifier_block *this,
netdev_dbg(dev, "IP add=%d:%d:%d:%d\n",
ip_addr_buf[0], ip_addr_buf[1],
ip_addr_buf[2], ip_addr_buf[3]);
- wilc_setup_ipaddress(vif, ip_addr_buf, vif->idx);
break;
case NETDEV_DOWN:
if (vif->iftype == STATION_MODE || vif->iftype == CLIENT_MODE) {
hif_drv->ifc_up = 0;
- wilc_optaining_ip = false;
+ vif->obtaining_ip = false;
}
if (memcmp(dev_iface->ifa_label, wlan_dev_name, 5) == 0)
@@ -85,8 +82,6 @@ static int dev_state_ev_handler(struct notifier_block *this,
ip_addr_buf[0], ip_addr_buf[1],
ip_addr_buf[2], ip_addr_buf[3]);
- wilc_setup_ipaddress(vif, ip_addr_buf, vif->idx);
-
break;
default:
@@ -164,9 +159,9 @@ static void deinit_irq(struct net_device *dev)
void wilc_mac_indicate(struct wilc *wilc)
{
- int status;
+ s8 status;
- wilc_wlan_cfg_get_val(WID_STATUS, (unsigned char *)&status, 4);
+ wilc_wlan_cfg_get_val(wilc, WID_STATUS, &status, 1);
if (wilc->mac_status == MAC_STATUS_INIT) {
wilc->mac_status = status;
complete(&wilc->sync_event);
@@ -197,14 +192,12 @@ static struct net_device *get_if_handler(struct wilc *wilc, u8 *mac_header)
return NULL;
}
-int wilc_wlan_set_bssid(struct net_device *wilc_netdev, u8 *bssid, u8 mode)
+void wilc_wlan_set_bssid(struct net_device *wilc_netdev, u8 *bssid, u8 mode)
{
struct wilc_vif *vif = netdev_priv(wilc_netdev);
memcpy(vif->bssid, bssid, 6);
vif->mode = mode;
-
- return 0;
}
int wilc_wlan_get_num_conn_ifcs(struct wilc *wilc)
@@ -269,9 +262,6 @@ static int wilc_wlan_get_firmware(struct net_device *dev)
netdev_info(dev, "loading firmware %s\n", firmware);
- if (!(&vif->ndev->dev))
- goto fail;
-
if (request_firmware(&wilc_firmware, firmware, wilc->dev) != 0) {
netdev_err(dev, "%s - firmware not available\n", firmware);
ret = -1;
@@ -532,7 +522,7 @@ fail:
return -1;
}
-static int wlan_deinit_locks(struct net_device *dev)
+static void wlan_deinit_locks(struct net_device *dev)
{
struct wilc_vif *vif = netdev_priv(dev);
struct wilc *wilc = vif->wilc;
@@ -540,8 +530,6 @@ static int wlan_deinit_locks(struct net_device *dev)
mutex_destroy(&wilc->hif_cs);
mutex_destroy(&wilc->rxq_cs);
mutex_destroy(&wilc->txq_add_to_head_cs);
-
- return 0;
}
static void wlan_deinitialize_threads(struct net_device *dev)
@@ -595,7 +583,7 @@ static void wilc_wlan_deinitialize(struct net_device *dev)
}
}
-static int wlan_init_locks(struct net_device *dev)
+static void wlan_init_locks(struct net_device *dev)
{
struct wilc_vif *vif = netdev_priv(dev);
struct wilc *wl = vif->wilc;
@@ -611,8 +599,6 @@ static int wlan_init_locks(struct net_device *dev)
init_completion(&wl->cfg_event);
init_completion(&wl->sync_event);
init_completion(&wl->txq_thread_started);
-
- return 0;
}
static int wlan_initialize_threads(struct net_device *dev)
@@ -688,7 +674,7 @@ static int wilc_wlan_initialize(struct net_device *dev, struct wilc_vif *vif)
int size;
char firmware_ver[20];
- size = wilc_wlan_cfg_get_val(WID_FIRMWARE_VERSION,
+ size = wilc_wlan_cfg_get_val(wl, WID_FIRMWARE_VERSION,
firmware_ver,
sizeof(firmware_ver));
firmware_ver[size] = '\0';
@@ -740,6 +726,7 @@ static int wilc_mac_open(struct net_device *ndev)
{
struct wilc_vif *vif = netdev_priv(ndev);
struct wilc *wl = vif->wilc;
+ struct wilc_priv *priv = wdev_priv(vif->ndev->ieee80211_ptr);
unsigned char mac_add[ETH_ALEN] = {0};
int ret = 0;
int i = 0;
@@ -764,7 +751,8 @@ static int wilc_mac_open(struct net_device *ndev)
for (i = 0; i < wl->vif_num; i++) {
if (ndev == wl->vif[i]->ndev) {
wilc_set_wfi_drv_handler(vif, wilc_get_vif_idx(vif),
- vif->iftype, vif->ifc_id);
+ vif->iftype, vif->ifc_id,
+ false);
wilc_set_operation_mode(vif, vif->iftype);
break;
}
@@ -792,6 +780,7 @@ static int wilc_mac_open(struct net_device *ndev)
vif->frame_reg[1].reg);
netif_wake_queue(ndev);
wl->open_ifcs++;
+ priv->p2p.local_random = 0x01;
vif->mac_opened = 1;
return 0;
}
@@ -807,35 +796,39 @@ static void wilc_set_multicast_list(struct net_device *dev)
{
struct netdev_hw_addr *ha;
struct wilc_vif *vif = netdev_priv(dev);
- int i = 0;
+ int i;
+ u8 *mc_list;
+ u8 *cur_mc;
if (dev->flags & IFF_PROMISC)
return;
if (dev->flags & IFF_ALLMULTI ||
dev->mc.count > WILC_MULTICAST_TABLE_SIZE) {
- wilc_setup_multicast_filter(vif, false, 0);
+ wilc_setup_multicast_filter(vif, false, 0, NULL);
return;
}
if (dev->mc.count == 0) {
- wilc_setup_multicast_filter(vif, true, 0);
+ wilc_setup_multicast_filter(vif, true, 0, NULL);
return;
}
+ mc_list = kmalloc_array(dev->mc.count, ETH_ALEN, GFP_KERNEL);
+ if (!mc_list)
+ return;
+
+ cur_mc = mc_list;
+ i = 0;
netdev_for_each_mc_addr(ha, dev) {
- memcpy(wilc_multicast_mac_addr_list[i], ha->addr, ETH_ALEN);
- netdev_dbg(dev, "Entry[%d]: %x:%x:%x:%x:%x:%x\n", i,
- wilc_multicast_mac_addr_list[i][0],
- wilc_multicast_mac_addr_list[i][1],
- wilc_multicast_mac_addr_list[i][2],
- wilc_multicast_mac_addr_list[i][3],
- wilc_multicast_mac_addr_list[i][4],
- wilc_multicast_mac_addr_list[i][5]);
+ memcpy(cur_mc, ha->addr, ETH_ALEN);
+ netdev_dbg(dev, "Entry[%d]: %pM\n", i, cur_mc);
i++;
+ cur_mc += ETH_ALEN;
}
- wilc_setup_multicast_filter(vif, true, (dev->mc.count));
+ if (wilc_setup_multicast_filter(vif, true, dev->mc.count, mc_list))
+ kfree(mc_list);
}
static void linux_wlan_tx_complete(void *priv, int status)
@@ -1016,15 +1009,18 @@ void wilc_netdev_cleanup(struct wilc *wilc)
{
int i;
- if (wilc && (wilc->vif[0]->ndev || wilc->vif[1]->ndev))
+ if (!wilc)
+ return;
+
+ if (wilc->vif[0]->ndev || wilc->vif[1]->ndev)
unregister_inetaddr_notifier(&g_dev_notifier);
- if (wilc && wilc->firmware) {
+ if (wilc->firmware) {
release_firmware(wilc->firmware);
wilc->firmware = NULL;
}
- if (wilc && (wilc->vif[0]->ndev || wilc->vif[1]->ndev)) {
+ if (wilc->vif[0]->ndev || wilc->vif[1]->ndev) {
for (i = 0; i < NUM_CONCURRENT_IFC; i++)
if (wilc->vif[i]->ndev)
if (wilc->vif[i]->mac_opened)
@@ -1037,6 +1033,10 @@ void wilc_netdev_cleanup(struct wilc *wilc)
}
}
+ flush_workqueue(wilc->hif_workqueue);
+ destroy_workqueue(wilc->hif_workqueue);
+ wilc_wlan_cfg_deinit(wilc);
+ kfree(wilc->bus_data);
kfree(wilc);
}
EXPORT_SYMBOL_GPL(wilc_netdev_cleanup);
@@ -1062,20 +1062,34 @@ int wilc_netdev_init(struct wilc **wilc, struct device *dev, int io_type,
if (!wl)
return -ENOMEM;
+ ret = wilc_wlan_cfg_init(wl);
+ if (ret)
+ goto free_wl;
+
*wilc = wl;
wl->io_type = io_type;
wl->hif_func = ops;
+ wl->enable_ps = true;
+ wl->chip_ps_state = CHIP_WAKEDUP;
INIT_LIST_HEAD(&wl->txq_head.list);
INIT_LIST_HEAD(&wl->rxq_head.list);
+ wl->hif_workqueue = create_singlethread_workqueue("WILC_wq");
+ if (!wl->hif_workqueue) {
+ ret = -ENOMEM;
+ goto free_cfg;
+ }
+
register_inetaddr_notifier(&g_dev_notifier);
for (i = 0; i < NUM_CONCURRENT_IFC; i++) {
struct wireless_dev *wdev;
ndev = alloc_etherdev(sizeof(struct wilc_vif));
- if (!ndev)
- return -ENOMEM;
+ if (!ndev) {
+ ret = -ENOMEM;
+ goto free_ndev;
+ }
vif = netdev_priv(ndev);
memset(vif, 0, sizeof(struct wilc_vif));
@@ -1096,15 +1110,14 @@ int wilc_netdev_init(struct wilc **wilc, struct device *dev, int io_type,
ndev->netdev_ops = &wilc_netdev_ops;
wdev = wilc_create_wiphy(ndev, dev);
-
- if (dev)
- SET_NETDEV_DEV(ndev, dev);
-
if (!wdev) {
netdev_err(ndev, "Can't register WILC Wiphy\n");
- return -1;
+ ret = -ENOMEM;
+ goto free_ndev;
}
+ SET_NETDEV_DEV(ndev, dev);
+
vif->ndev->ieee80211_ptr = wdev;
vif->ndev->ml_priv = vif;
wdev->netdev = vif->ndev;
@@ -1115,13 +1128,33 @@ int wilc_netdev_init(struct wilc **wilc, struct device *dev, int io_type,
ret = register_netdev(ndev);
if (ret)
- return ret;
+ goto free_ndev;
vif->iftype = STATION_MODE;
vif->mac_opened = 0;
}
return 0;
+
+free_ndev:
+ for (; i >= 0; i--) {
+ if (wl->vif[i]) {
+ if (wl->vif[i]->iftype == STATION_MODE)
+ unregister_netdev(wl->vif[i]->ndev);
+
+ if (wl->vif[i]->ndev) {
+ wilc_free_wiphy(wl->vif[i]->ndev);
+ free_netdev(wl->vif[i]->ndev);
+ }
+ }
+ }
+ unregister_inetaddr_notifier(&g_dev_notifier);
+ destroy_workqueue(wl->hif_workqueue);
+free_cfg:
+ wilc_wlan_cfg_deinit(wl);
+free_wl:
+ kfree(wl);
+ return ret;
}
EXPORT_SYMBOL_GPL(wilc_netdev_init);
diff --git a/drivers/staging/wilc1000/wilc_debugfs.c b/drivers/staging/wilc1000/wilc_debugfs.c
deleted file mode 100644
index 8001df66b8c2..000000000000
--- a/drivers/staging/wilc1000/wilc_debugfs.c
+++ /dev/null
@@ -1,115 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
- * All rights reserved.
- */
-
-#if defined(WILC_DEBUGFS)
-#include <linux/module.h>
-#include <linux/debugfs.h>
-
-#include "wilc_wlan_if.h"
-
-static struct dentry *wilc_dir;
-
-#define DEBUG BIT(0)
-#define INFO BIT(1)
-#define WRN BIT(2)
-#define ERR BIT(3)
-
-#define DBG_LEVEL_ALL (DEBUG | INFO | WRN | ERR)
-static atomic_t WILC_DEBUG_LEVEL = ATOMIC_INIT(ERR);
-EXPORT_SYMBOL_GPL(WILC_DEBUG_LEVEL);
-
-static ssize_t wilc_debug_level_read(struct file *file, char __user *userbuf,
- size_t count, loff_t *ppos)
-{
- char buf[128];
- int res = 0;
-
- /* only allow read from start */
- if (*ppos > 0)
- return 0;
-
- res = scnprintf(buf, sizeof(buf), "Debug Level: %x\n",
- atomic_read(&WILC_DEBUG_LEVEL));
-
- return simple_read_from_buffer(userbuf, count, ppos, buf, res);
-}
-
-static ssize_t wilc_debug_level_write(struct file *filp,
- const char __user *buf, size_t count,
- loff_t *ppos)
-{
- int flag = 0;
- int ret;
-
- ret = kstrtouint_from_user(buf, count, 16, &flag);
- if (ret)
- return ret;
-
- if (flag > DBG_LEVEL_ALL) {
- pr_info("%s, value (0x%08x) is out of range, stay previous flag (0x%08x)\n",
- __func__, flag, atomic_read(&WILC_DEBUG_LEVEL));
- return -EINVAL;
- }
-
- atomic_set(&WILC_DEBUG_LEVEL, (int)flag);
-
- if (flag == 0)
- pr_info("Debug-level disabled\n");
- else
- pr_info("Debug-level enabled\n");
-
- return count;
-}
-
-#define FOPS(_open, _read, _write, _poll) { \
- .owner = THIS_MODULE, \
- .open = (_open), \
- .read = (_read), \
- .write = (_write), \
- .poll = (_poll), \
-}
-
-struct wilc_debugfs_info_t {
- const char *name;
- int perm;
- unsigned int data;
- const struct file_operations fops;
-};
-
-static struct wilc_debugfs_info_t debugfs_info[] = {
- {
- "wilc_debug_level",
- 0666,
- (DEBUG | ERR),
- FOPS(NULL, wilc_debug_level_read, wilc_debug_level_write, NULL),
- },
-};
-
-static int __init wilc_debugfs_init(void)
-{
- int i;
- struct wilc_debugfs_info_t *info;
-
- wilc_dir = debugfs_create_dir("wilc_wifi", NULL);
- for (i = 0; i < ARRAY_SIZE(debugfs_info); i++) {
- info = &debugfs_info[i];
- debugfs_create_file(info->name,
- info->perm,
- wilc_dir,
- &info->data,
- &info->fops);
- }
- return 0;
-}
-module_init(wilc_debugfs_init);
-
-static void __exit wilc_debugfs_remove(void)
-{
- debugfs_remove_recursive(wilc_dir);
-}
-module_exit(wilc_debugfs_remove);
-
-#endif
diff --git a/drivers/staging/wilc1000/wilc_sdio.c b/drivers/staging/wilc1000/wilc_sdio.c
index b2080d8b801f..ca351c950344 100644
--- a/drivers/staging/wilc1000/wilc_sdio.c
+++ b/drivers/staging/wilc1000/wilc_sdio.c
@@ -30,7 +30,6 @@ struct wilc_sdio {
int has_thrpt_enh3;
};
-static struct wilc_sdio g_sdio;
static const struct wilc_hif_func wilc_hif_sdio;
static int sdio_write_reg(struct wilc *wilc, u32 addr, u32 data);
@@ -109,6 +108,11 @@ static int linux_sdio_probe(struct sdio_func *func,
struct wilc *wilc;
int ret;
struct gpio_desc *gpio = NULL;
+ struct wilc_sdio *sdio_priv;
+
+ sdio_priv = kzalloc(sizeof(*sdio_priv), GFP_KERNEL);
+ if (!sdio_priv)
+ return -ENOMEM;
if (IS_ENABLED(CONFIG_WILC1000_HW_OOB_INTR)) {
gpio = gpiod_get(&func->dev, "irq", GPIOD_IN);
@@ -124,9 +128,11 @@ static int linux_sdio_probe(struct sdio_func *func,
ret = wilc_netdev_init(&wilc, &func->dev, HIF_SDIO, &wilc_hif_sdio);
if (ret) {
dev_err(&func->dev, "Couldn't initialize netdev\n");
+ kfree(sdio_priv);
return ret;
}
sdio_set_drvdata(func, wilc);
+ wilc->bus_data = sdio_priv;
wilc->dev = &func->dev;
wilc->gpio_irq = gpio;
@@ -381,6 +387,7 @@ fail:
static int sdio_write_reg(struct wilc *wilc, u32 addr, u32 data)
{
struct sdio_func *func = dev_to_sdio_func(wilc->dev);
+ struct wilc_sdio *sdio_priv = wilc->bus_data;
int ret;
cpu_to_le32s(&data);
@@ -415,7 +422,7 @@ static int sdio_write_reg(struct wilc *wilc, u32 addr, u32 data)
cmd.increment = 1;
cmd.count = 4;
cmd.buffer = (u8 *)&data;
- cmd.block_size = g_sdio.block_size;
+ cmd.block_size = sdio_priv->block_size;
ret = wilc_sdio_cmd53(wilc, &cmd);
if (ret) {
dev_err(&func->dev,
@@ -434,7 +441,8 @@ fail:
static int sdio_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
{
struct sdio_func *func = dev_to_sdio_func(wilc->dev);
- u32 block_size = g_sdio.block_size;
+ struct wilc_sdio *sdio_priv = wilc->bus_data;
+ u32 block_size = sdio_priv->block_size;
struct sdio_cmd53 cmd;
int nblk, nleft, ret;
@@ -523,6 +531,7 @@ fail:
static int sdio_read_reg(struct wilc *wilc, u32 addr, u32 *data)
{
struct sdio_func *func = dev_to_sdio_func(wilc->dev);
+ struct wilc_sdio *sdio_priv = wilc->bus_data;
int ret;
if (addr >= 0xf0 && addr <= 0xff) {
@@ -553,7 +562,7 @@ static int sdio_read_reg(struct wilc *wilc, u32 addr, u32 *data)
cmd.count = 4;
cmd.buffer = (u8 *)data;
- cmd.block_size = g_sdio.block_size;
+ cmd.block_size = sdio_priv->block_size;
ret = wilc_sdio_cmd53(wilc, &cmd);
if (ret) {
dev_err(&func->dev,
@@ -574,7 +583,8 @@ fail:
static int sdio_read(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
{
struct sdio_func *func = dev_to_sdio_func(wilc->dev);
- u32 block_size = g_sdio.block_size;
+ struct wilc_sdio *sdio_priv = wilc->bus_data;
+ u32 block_size = sdio_priv->block_size;
struct sdio_cmd53 cmd;
int nblk, nleft, ret;
@@ -674,14 +684,13 @@ static int sdio_deinit(struct wilc *wilc)
static int sdio_init(struct wilc *wilc, bool resume)
{
struct sdio_func *func = dev_to_sdio_func(wilc->dev);
+ struct wilc_sdio *sdio_priv = wilc->bus_data;
struct sdio_cmd52 cmd;
int loop, ret;
u32 chipid;
- if (!resume) {
- memset(&g_sdio, 0, sizeof(struct wilc_sdio));
- g_sdio.irq_gpio = wilc->dev_irq_num;
- }
+ if (!resume)
+ sdio_priv->irq_gpio = wilc->dev_irq_num;
/**
* function 0 csa enable
@@ -704,7 +713,7 @@ static int sdio_init(struct wilc *wilc, bool resume)
dev_err(&func->dev, "Fail cmd 52, set func 0 block size...\n");
goto fail;
}
- g_sdio.block_size = WILC_SDIO_BLOCK_SIZE;
+ sdio_priv->block_size = WILC_SDIO_BLOCK_SIZE;
/**
* enable func1 IO
@@ -778,11 +787,11 @@ static int sdio_init(struct wilc *wilc, bool resume)
}
dev_err(&func->dev, "chipid (%08x)\n", chipid);
if ((chipid & 0xfff) > 0x2a0)
- g_sdio.has_thrpt_enh3 = 1;
+ sdio_priv->has_thrpt_enh3 = 1;
else
- g_sdio.has_thrpt_enh3 = 0;
+ sdio_priv->has_thrpt_enh3 = 0;
dev_info(&func->dev, "has_thrpt_enh3 = %d...\n",
- g_sdio.has_thrpt_enh3);
+ sdio_priv->has_thrpt_enh3);
}
return 1;
@@ -820,6 +829,7 @@ static int sdio_read_size(struct wilc *wilc, u32 *size)
static int sdio_read_int(struct wilc *wilc, u32 *int_status)
{
struct sdio_func *func = dev_to_sdio_func(wilc->dev);
+ struct wilc_sdio *sdio_priv = wilc->bus_data;
u32 tmp;
struct sdio_cmd52 cmd;
@@ -828,7 +838,7 @@ static int sdio_read_int(struct wilc *wilc, u32 *int_status)
/**
* Read IRQ flags
**/
- if (!g_sdio.irq_gpio) {
+ if (!sdio_priv->irq_gpio) {
int i;
cmd.function = 1;
@@ -848,7 +858,7 @@ static int sdio_read_int(struct wilc *wilc, u32 *int_status)
tmp |= INT_4;
if (cmd.data & BIT(6))
tmp |= INT_5;
- for (i = g_sdio.nint; i < MAX_NUM_INT; i++) {
+ for (i = sdio_priv->nint; i < MAX_NUM_INT; i++) {
if ((tmp >> (IRG_FLAGS_OFFSET + i)) & 0x1) {
dev_err(&func->dev,
"Unexpected interrupt (1) : tmp=%x, data=%x\n",
@@ -877,13 +887,14 @@ static int sdio_read_int(struct wilc *wilc, u32 *int_status)
static int sdio_clear_int_ext(struct wilc *wilc, u32 val)
{
struct sdio_func *func = dev_to_sdio_func(wilc->dev);
+ struct wilc_sdio *sdio_priv = wilc->bus_data;
int ret;
int vmm_ctl;
- if (g_sdio.has_thrpt_enh3) {
+ if (sdio_priv->has_thrpt_enh3) {
u32 reg;
- if (g_sdio.irq_gpio) {
+ if (sdio_priv->irq_gpio) {
u32 flags;
flags = val & (BIT(MAX_NUN_INT_THRPT_ENH2) - 1);
@@ -919,7 +930,7 @@ static int sdio_clear_int_ext(struct wilc *wilc, u32 val)
}
return 1;
}
- if (g_sdio.irq_gpio) {
+ if (sdio_priv->irq_gpio) {
/* has_thrpt_enh2 uses register 0xf8 to clear interrupts. */
/*
* Cannot clear multiple interrupts.
@@ -932,7 +943,7 @@ static int sdio_clear_int_ext(struct wilc *wilc, u32 val)
int i;
ret = 1;
- for (i = 0; i < g_sdio.nint; i++) {
+ for (i = 0; i < sdio_priv->nint; i++) {
if (flags & 1) {
struct sdio_cmd52 cmd;
@@ -956,7 +967,7 @@ static int sdio_clear_int_ext(struct wilc *wilc, u32 val)
}
if (!ret)
goto fail;
- for (i = g_sdio.nint; i < MAX_NUM_INT; i++) {
+ for (i = sdio_priv->nint; i < MAX_NUM_INT; i++) {
if (flags & 1)
dev_err(&func->dev,
"Unexpected interrupt cleared %d...\n",
@@ -1001,6 +1012,7 @@ fail:
static int sdio_sync_ext(struct wilc *wilc, int nint)
{
struct sdio_func *func = dev_to_sdio_func(wilc->dev);
+ struct wilc_sdio *sdio_priv = wilc->bus_data;
u32 reg;
if (nint > MAX_NUM_INT) {
@@ -1013,7 +1025,7 @@ static int sdio_sync_ext(struct wilc *wilc, int nint)
return 0;
}
- g_sdio.nint = nint;
+ sdio_priv->nint = nint;
/**
* Disable power sequencer
@@ -1029,7 +1041,7 @@ static int sdio_sync_ext(struct wilc *wilc, int nint)
return 0;
}
- if (g_sdio.irq_gpio) {
+ if (sdio_priv->irq_gpio) {
u32 reg;
int ret, i;
diff --git a/drivers/staging/wilc1000/wilc_spi.c b/drivers/staging/wilc1000/wilc_spi.c
index 5517477d875a..cef127b249fb 100644
--- a/drivers/staging/wilc1000/wilc_spi.c
+++ b/drivers/staging/wilc1000/wilc_spi.c
@@ -14,7 +14,6 @@ struct wilc_spi {
int has_thrpt_enh;
};
-static struct wilc_spi g_spi;
static const struct wilc_hif_func wilc_hif_spi;
/********************************************
@@ -107,6 +106,11 @@ static int wilc_bus_probe(struct spi_device *spi)
int ret;
struct wilc *wilc;
struct gpio_desc *gpio;
+ struct wilc_spi *spi_priv;
+
+ spi_priv = kzalloc(sizeof(*spi_priv), GFP_KERNEL);
+ if (!spi_priv)
+ return -ENOMEM;
gpio = gpiod_get(&spi->dev, "irq", GPIOD_IN);
if (IS_ERR(gpio)) {
@@ -117,11 +121,14 @@ static int wilc_bus_probe(struct spi_device *spi)
}
ret = wilc_netdev_init(&wilc, NULL, HIF_SPI, &wilc_hif_spi);
- if (ret)
+ if (ret) {
+ kfree(spi_priv);
return ret;
+ }
spi_set_drvdata(spi, wilc);
wilc->dev = &spi->dev;
+ wilc->bus_data = spi_priv;
wilc->gpio_irq = gpio;
return 0;
@@ -275,6 +282,7 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz,
u8 clockless)
{
struct spi_device *spi = to_spi_device(wilc->dev);
+ struct wilc_spi *spi_priv = wilc->bus_data;
u8 wb[32], rb[32];
u8 wix, rix;
u32 len2;
@@ -375,7 +383,7 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz,
if (result != N_OK)
return result;
- if (!g_spi.crc_off)
+ if (!spi_priv->crc_off)
wb[len - 1] = (crc7(0x7f, (const u8 *)&wb[0], len - 1)) << 1;
else
len -= 1;
@@ -393,7 +401,7 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz,
} else if (cmd == CMD_INTERNAL_READ || cmd == CMD_SINGLE_READ) {
int tmp = NUM_RSP_BYTES + NUM_DATA_HDR_BYTES + NUM_DATA_BYTES
+ NUM_DUMMY_BYTES;
- if (!g_spi.crc_off)
+ if (!spi_priv->crc_off)
len2 = len + tmp + NUM_CRC_BYTES;
else
len2 = len + tmp;
@@ -485,7 +493,7 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz,
return N_FAIL;
}
- if (!g_spi.crc_off) {
+ if (!spi_priv->crc_off) {
/*
* Read Crc
*/
@@ -527,7 +535,7 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz,
/*
* Read Crc
*/
- if (!g_spi.crc_off && wilc_spi_rx(wilc, crc, 2)) {
+ if (!spi_priv->crc_off && wilc_spi_rx(wilc, crc, 2)) {
dev_err(&spi->dev,
"Failed block crc read, bus err\n");
return N_FAIL;
@@ -585,7 +593,7 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz,
/*
* Read Crc
*/
- if (!g_spi.crc_off && wilc_spi_rx(wilc, crc, 2)) {
+ if (!spi_priv->crc_off && wilc_spi_rx(wilc, crc, 2)) {
dev_err(&spi->dev,
"Failed block crc read, bus err\n");
result = N_FAIL;
@@ -602,6 +610,7 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz,
static int spi_data_write(struct wilc *wilc, u8 *b, u32 sz)
{
struct spi_device *spi = to_spi_device(wilc->dev);
+ struct wilc_spi *spi_priv = wilc->bus_data;
int ix, nbytes;
int result = 1;
u8 cmd, order, crc[2] = {0};
@@ -648,7 +657,7 @@ static int spi_data_write(struct wilc *wilc, u8 *b, u32 sz)
/*
* Write Crc
*/
- if (!g_spi.crc_off) {
+ if (!spi_priv->crc_off) {
if (wilc_spi_tx(wilc, crc, 2)) {
dev_err(&spi->dev, "Failed data block crc write, bus error...\n");
result = N_FAIL;
@@ -816,6 +825,7 @@ static int _wilc_spi_deinit(struct wilc *wilc)
static int wilc_spi_init(struct wilc *wilc, bool resume)
{
struct spi_device *spi = to_spi_device(wilc->dev);
+ struct wilc_spi *spi_priv = wilc->bus_data;
u32 reg;
u32 chipid;
static int isinit;
@@ -828,12 +838,9 @@ static int wilc_spi_init(struct wilc *wilc, bool resume)
return 1;
}
- memset(&g_spi, 0, sizeof(struct wilc_spi));
-
/*
* configure protocol
*/
- g_spi.crc_off = 0;
/*
* TODO: We can remove the CRC trials if there is a definite
@@ -845,7 +852,7 @@ static int wilc_spi_init(struct wilc *wilc, bool resume)
* Read failed. Try with CRC off. This might happen when module
* is removed but chip isn't reset
*/
- g_spi.crc_off = 1;
+ spi_priv->crc_off = 1;
dev_err(&spi->dev,
"Failed read with CRC on, retrying with CRC off\n");
if (!spi_internal_read(wilc, WILC_SPI_PROTOCOL_OFFSET, &reg)) {
@@ -857,7 +864,7 @@ static int wilc_spi_init(struct wilc *wilc, bool resume)
return 0;
}
}
- if (g_spi.crc_off == 0) {
+ if (spi_priv->crc_off == 0) {
reg &= ~0xc; /* disable crc checking */
reg &= ~0x70;
reg |= (0x5 << 4);
@@ -867,7 +874,7 @@ static int wilc_spi_init(struct wilc *wilc, bool resume)
__LINE__);
return 0;
}
- g_spi.crc_off = 1;
+ spi_priv->crc_off = 1;
}
/*
@@ -878,7 +885,7 @@ static int wilc_spi_init(struct wilc *wilc, bool resume)
return 0;
}
- g_spi.has_thrpt_enh = 1;
+ spi_priv->has_thrpt_enh = 1;
isinit = 1;
@@ -888,9 +895,10 @@ static int wilc_spi_init(struct wilc *wilc, bool resume)
static int wilc_spi_read_size(struct wilc *wilc, u32 *size)
{
struct spi_device *spi = to_spi_device(wilc->dev);
+ struct wilc_spi *spi_priv = wilc->bus_data;
int ret;
- if (g_spi.has_thrpt_enh) {
+ if (spi_priv->has_thrpt_enh) {
ret = spi_internal_read(wilc, 0xe840 - WILC_SPI_REG_BASE,
size);
*size = *size & IRQ_DMA_WD_CNT_MASK;
@@ -915,6 +923,7 @@ static int wilc_spi_read_size(struct wilc *wilc, u32 *size)
static int wilc_spi_read_int(struct wilc *wilc, u32 *int_status)
{
struct spi_device *spi = to_spi_device(wilc->dev);
+ struct wilc_spi *spi_priv = wilc->bus_data;
int ret;
u32 tmp;
u32 byte_cnt;
@@ -923,7 +932,7 @@ static int wilc_spi_read_int(struct wilc *wilc, u32 *int_status)
u32 irq_flags;
int k = IRG_FLAGS_OFFSET + 5;
- if (g_spi.has_thrpt_enh) {
+ if (spi_priv->has_thrpt_enh) {
ret = spi_internal_read(wilc, 0xe840 - WILC_SPI_REG_BASE,
int_status);
return ret;
@@ -943,12 +952,12 @@ static int wilc_spi_read_int(struct wilc *wilc, u32 *int_status)
wilc_spi_read_reg(wilc, 0x1a90, &irq_flags);
tmp |= ((irq_flags >> 27) << IRG_FLAGS_OFFSET);
- if (g_spi.nint > 5) {
+ if (spi_priv->nint > 5) {
wilc_spi_read_reg(wilc, 0x1a94, &irq_flags);
tmp |= (((irq_flags >> 0) & 0x7) << k);
}
- unknown_mask = ~((1ul << g_spi.nint) - 1);
+ unknown_mask = ~((1ul << spi_priv->nint) - 1);
if ((tmp >> IRG_FLAGS_OFFSET) & unknown_mask) {
dev_err(&spi->dev,
@@ -968,11 +977,12 @@ static int wilc_spi_read_int(struct wilc *wilc, u32 *int_status)
static int wilc_spi_clear_int_ext(struct wilc *wilc, u32 val)
{
struct spi_device *spi = to_spi_device(wilc->dev);
+ struct wilc_spi *spi_priv = wilc->bus_data;
int ret;
u32 flags;
u32 tbl_ctl;
- if (g_spi.has_thrpt_enh) {
+ if (spi_priv->has_thrpt_enh) {
ret = spi_internal_write(wilc, 0xe844 - WILC_SPI_REG_BASE,
val);
return ret;
@@ -983,7 +993,7 @@ static int wilc_spi_clear_int_ext(struct wilc *wilc, u32 val)
int i;
ret = 1;
- for (i = 0; i < g_spi.nint; i++) {
+ for (i = 0; i < spi_priv->nint; i++) {
/*
* No matter what you write 1 or 0,
* it will clear interrupt.
@@ -1001,7 +1011,7 @@ static int wilc_spi_clear_int_ext(struct wilc *wilc, u32 val)
0x10c8 + i * 4);
return ret;
}
- for (i = g_spi.nint; i < MAX_NUM_INT; i++) {
+ for (i = spi_priv->nint; i < MAX_NUM_INT; i++) {
if (flags & 1)
dev_err(&spi->dev,
"Unexpected interrupt cleared %d...\n",
@@ -1041,6 +1051,7 @@ static int wilc_spi_clear_int_ext(struct wilc *wilc, u32 val)
static int wilc_spi_sync_ext(struct wilc *wilc, int nint)
{
struct spi_device *spi = to_spi_device(wilc->dev);
+ struct wilc_spi *spi_priv = wilc->bus_data;
u32 reg;
int ret, i;
@@ -1049,7 +1060,7 @@ static int wilc_spi_sync_ext(struct wilc *wilc, int nint)
return 0;
}
- g_spi.nint = nint;
+ spi_priv->nint = nint;
/*
* interrupt pin mux select
diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c
index 7cd033004651..4fbbbbd5a64b 100644
--- a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c
+++ b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c
@@ -82,12 +82,6 @@ static const struct wiphy_wowlan_support wowlan_support = {
.flags = WIPHY_WOWLAN_ANY
};
-static struct network_info last_scanned_shadow[MAX_NUM_SCANNED_NETWORKS_SHADOW];
-static u32 last_scanned_cnt;
-struct timer_list wilc_during_ip_timer;
-static struct timer_list aging_timer;
-static u8 op_ifcs;
-
#define CHAN2G(_channel, _freq, _flags) { \
.band = NL80211_BAND_2GHZ, \
.center_freq = (_freq), \
@@ -143,10 +137,7 @@ struct p2p_mgmt_data {
static u8 wlan_channel = INVALID_CHANNEL;
static u8 curr_channel;
static u8 p2p_oui[] = {0x50, 0x6f, 0x9A, 0x09};
-static u8 p2p_local_random = 0x01;
-static u8 p2p_recv_random;
static u8 p2p_vendor_spec[] = {0xdd, 0x05, 0x00, 0x08, 0x40, 0x03};
-static bool wilc_ie;
static struct ieee80211_supported_band wilc_band_2ghz = {
.channels = ieee80211_2ghz_channels,
@@ -158,25 +149,18 @@ static struct ieee80211_supported_band wilc_band_2ghz = {
#define AGING_TIME (9 * 1000)
#define DURING_IP_TIME_OUT 15000
-static void clear_shadow_scan(void)
+static void clear_shadow_scan(struct wilc_priv *priv)
{
int i;
- if (op_ifcs != 0)
- return;
-
- del_timer_sync(&aging_timer);
+ for (i = 0; i < priv->scanned_cnt; i++) {
+ kfree(priv->scanned_shadow[i].ies);
+ priv->scanned_shadow[i].ies = NULL;
- for (i = 0; i < last_scanned_cnt; i++) {
- if (last_scanned_shadow[last_scanned_cnt].ies) {
- kfree(last_scanned_shadow[i].ies);
- last_scanned_shadow[last_scanned_cnt].ies = NULL;
- }
-
- kfree(last_scanned_shadow[i].join_params);
- last_scanned_shadow[i].join_params = NULL;
+ kfree(priv->scanned_shadow[i].join_params);
+ priv->scanned_shadow[i].join_params = NULL;
}
- last_scanned_cnt = 0;
+ priv->scanned_cnt = 0;
}
static u32 get_rssi_avg(struct network_info *network_info)
@@ -198,14 +182,14 @@ static void refresh_scan(struct wilc_priv *priv, bool direct_scan)
struct wiphy *wiphy = priv->dev->ieee80211_ptr->wiphy;
int i;
- for (i = 0; i < last_scanned_cnt; i++) {
+ for (i = 0; i < priv->scanned_cnt; i++) {
struct network_info *network_info;
s32 freq;
struct ieee80211_channel *channel;
int rssi;
struct cfg80211_bss *bss;
- network_info = &last_scanned_shadow[i];
+ network_info = &priv->scanned_shadow[i];
if (!memcmp("DIRECT-", network_info->ssid, 7) && !direct_scan)
continue;
@@ -229,62 +213,68 @@ static void refresh_scan(struct wilc_priv *priv, bool direct_scan)
}
}
-static void reset_shadow_found(void)
+static void reset_shadow_found(struct wilc_priv *priv)
{
int i;
- for (i = 0; i < last_scanned_cnt; i++)
- last_scanned_shadow[i].found = 0;
+ for (i = 0; i < priv->scanned_cnt; i++)
+ priv->scanned_shadow[i].found = 0;
}
-static void update_scan_time(void)
+static void update_scan_time(struct wilc_priv *priv)
{
int i;
- for (i = 0; i < last_scanned_cnt; i++)
- last_scanned_shadow[i].time_scan = jiffies;
+ for (i = 0; i < priv->scanned_cnt; i++)
+ priv->scanned_shadow[i].time_scan = jiffies;
}
-static void remove_network_from_shadow(struct timer_list *unused)
+static void remove_network_from_shadow(struct timer_list *t)
{
+ struct wilc_priv *priv = from_timer(priv, t, aging_timer);
unsigned long now = jiffies;
int i, j;
- for (i = 0; i < last_scanned_cnt; i++) {
- if (!time_after(now, last_scanned_shadow[i].time_scan +
+ for (i = 0; i < priv->scanned_cnt; i++) {
+ if (!time_after(now, priv->scanned_shadow[i].time_scan +
(unsigned long)(SCAN_RESULT_EXPIRE)))
continue;
- kfree(last_scanned_shadow[i].ies);
- last_scanned_shadow[i].ies = NULL;
+ kfree(priv->scanned_shadow[i].ies);
+ priv->scanned_shadow[i].ies = NULL;
- kfree(last_scanned_shadow[i].join_params);
+ kfree(priv->scanned_shadow[i].join_params);
- for (j = i; (j < last_scanned_cnt - 1); j++)
- last_scanned_shadow[j] = last_scanned_shadow[j + 1];
+ for (j = i; (j < priv->scanned_cnt - 1); j++)
+ priv->scanned_shadow[j] = priv->scanned_shadow[j + 1];
- last_scanned_cnt--;
+ priv->scanned_cnt--;
}
- if (last_scanned_cnt != 0)
- mod_timer(&aging_timer, jiffies + msecs_to_jiffies(AGING_TIME));
+ if (priv->scanned_cnt != 0)
+ mod_timer(&priv->aging_timer,
+ jiffies + msecs_to_jiffies(AGING_TIME));
}
-static void clear_during_ip(struct timer_list *unused)
+static void clear_during_ip(struct timer_list *t)
{
- wilc_optaining_ip = false;
+ struct wilc_vif *vif = from_timer(vif, t, during_ip_timer);
+
+ vif->obtaining_ip = false;
}
-static int is_network_in_shadow(struct network_info *nw_info, void *user_void)
+static int is_network_in_shadow(struct network_info *nw_info,
+ struct wilc_priv *priv)
{
int state = -1;
int i;
- if (last_scanned_cnt == 0) {
- mod_timer(&aging_timer, jiffies + msecs_to_jiffies(AGING_TIME));
+ if (priv->scanned_cnt == 0) {
+ mod_timer(&priv->aging_timer,
+ jiffies + msecs_to_jiffies(AGING_TIME));
state = -1;
} else {
- for (i = 0; i < last_scanned_cnt; i++) {
- if (memcmp(last_scanned_shadow[i].bssid,
+ for (i = 0; i < priv->scanned_cnt; i++) {
+ if (memcmp(priv->scanned_shadow[i].bssid,
nw_info->bssid, 6) == 0) {
state = i;
break;
@@ -295,23 +285,23 @@ static int is_network_in_shadow(struct network_info *nw_info, void *user_void)
}
static void add_network_to_shadow(struct network_info *nw_info,
- void *user_void, void *join_params)
+ struct wilc_priv *priv, void *join_params)
{
- int ap_found = is_network_in_shadow(nw_info, user_void);
+ int ap_found = is_network_in_shadow(nw_info, priv);
u32 ap_index = 0;
u8 rssi_index = 0;
struct network_info *shadow_nw_info;
- if (last_scanned_cnt >= MAX_NUM_SCANNED_NETWORKS_SHADOW)
+ if (priv->scanned_cnt >= MAX_NUM_SCANNED_NETWORKS_SHADOW)
return;
if (ap_found == -1) {
- ap_index = last_scanned_cnt;
- last_scanned_cnt++;
+ ap_index = priv->scanned_cnt;
+ priv->scanned_cnt++;
} else {
ap_index = ap_found;
}
- shadow_nw_info = &last_scanned_shadow[ap_index];
+ shadow_nw_info = &priv->scanned_shadow[ap_index];
rssi_index = shadow_nw_info->rssi_history.index;
shadow_nw_info->rssi_history.samples[rssi_index++] = nw_info->rssi;
if (rssi_index == NUM_RSSI) {
@@ -403,7 +393,7 @@ static void cfg_scan_result(enum scan_event scan_event,
u32 i;
for (i = 0; i < priv->rcvd_ch_cnt; i++) {
- if (memcmp(last_scanned_shadow[i].bssid,
+ if (memcmp(priv->scanned_shadow[i].bssid,
network_info->bssid, 6) == 0)
break;
}
@@ -411,8 +401,8 @@ static void cfg_scan_result(enum scan_event scan_event,
if (i >= priv->rcvd_ch_cnt)
return;
- last_scanned_shadow[i].rssi = network_info->rssi;
- last_scanned_shadow[i].time_scan = jiffies;
+ priv->scanned_shadow[i].rssi = network_info->rssi;
+ priv->scanned_shadow[i].time_scan = jiffies;
}
} else if (scan_event == SCAN_EVENT_DONE) {
refresh_scan(priv, false);
@@ -438,7 +428,7 @@ static void cfg_scan_result(enum scan_event scan_event,
.aborted = false,
};
- update_scan_time();
+ update_scan_time(priv);
refresh_scan(priv, false);
cfg80211_scan_done(priv->scan_req, &info);
@@ -449,19 +439,17 @@ static void cfg_scan_result(enum scan_event scan_event,
}
}
-static inline bool wilc_wfi_cfg_scan_time_expired(int i)
+static inline bool wilc_cfg_scan_time_expired(struct wilc_priv *priv, int i)
{
unsigned long now = jiffies;
- if (time_after(now, last_scanned_shadow[i].time_scan_cached +
+ if (time_after(now, priv->scanned_shadow[i].time_scan_cached +
(unsigned long)(nl80211_SCAN_RESULT_EXPIRE - (1 * HZ))))
return true;
else
return false;
}
-int wilc_connecting;
-
static void cfg_connect_result(enum conn_event conn_disconn_evt,
struct connect_info *conn_info,
u8 mac_status,
@@ -475,7 +463,7 @@ static void cfg_connect_result(enum conn_event conn_disconn_evt,
struct host_if_drv *wfi_drv = priv->hif_drv;
u8 null_bssid[ETH_ALEN] = {0};
- wilc_connecting = 0;
+ vif->connecting = false;
if (conn_disconn_evt == CONN_DISCONN_EVENT_CONN_RESP) {
u16 connect_status;
@@ -487,7 +475,6 @@ static void cfg_connect_result(enum conn_event conn_disconn_evt,
connect_status = WLAN_STATUS_UNSPECIFIED_FAILURE;
wilc_wlan_set_bssid(priv->dev, null_bssid,
STATION_MODE);
- eth_zero_addr(wilc_connected_ssid);
if (!wfi_drv->p2p_connect)
wlan_channel = INVALID_CHANNEL;
@@ -502,11 +489,11 @@ static void cfg_connect_result(enum conn_event conn_disconn_evt,
memcpy(priv->associated_bss, conn_info->bssid,
ETH_ALEN);
- for (i = 0; i < last_scanned_cnt; i++) {
- if (memcmp(last_scanned_shadow[i].bssid,
+ for (i = 0; i < priv->scanned_cnt; i++) {
+ if (memcmp(priv->scanned_shadow[i].bssid,
conn_info->bssid,
ETH_ALEN) == 0) {
- if (wilc_wfi_cfg_scan_time_expired(i))
+ if (wilc_cfg_scan_time_expired(priv, i))
scan_refresh = true;
break;
@@ -524,13 +511,12 @@ static void cfg_connect_result(enum conn_event conn_disconn_evt,
conn_info->resp_ies_len, connect_status,
GFP_KERNEL);
} else if (conn_disconn_evt == CONN_DISCONN_EVENT_DISCONN_NOTIF) {
- wilc_optaining_ip = false;
- p2p_local_random = 0x01;
- p2p_recv_random = 0x00;
- wilc_ie = false;
+ vif->obtaining_ip = false;
+ priv->p2p.local_random = 0x01;
+ priv->p2p.recv_random = 0x00;
+ priv->p2p.is_wilc_ie = false;
eth_zero_addr(priv->associated_bss);
wilc_wlan_set_bssid(priv->dev, null_bssid, STATION_MODE);
- eth_zero_addr(wilc_connected_ssid);
if (!wfi_drv->p2p_connect)
wlan_channel = INVALID_CHANNEL;
@@ -620,7 +606,7 @@ static int scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
priv->rcvd_ch_cnt = 0;
- reset_shadow_found();
+ reset_shadow_found(priv);
priv->cfg_scanning = true;
if (request->n_channels <= MAX_NUM_SCANNED_NETWORKS) {
@@ -673,25 +659,25 @@ static int connect(struct wiphy *wiphy, struct net_device *dev,
enum authtype auth_type = ANY;
u32 cipher_group;
- wilc_connecting = 1;
+ vif->connecting = true;
if (!(strncmp(sme->ssid, "DIRECT-", 7)))
wfi_drv->p2p_connect = 1;
else
wfi_drv->p2p_connect = 0;
- for (i = 0; i < last_scanned_cnt; i++) {
- if (sme->ssid_len == last_scanned_shadow[i].ssid_len &&
- memcmp(last_scanned_shadow[i].ssid,
+ for (i = 0; i < priv->scanned_cnt; i++) {
+ if (sme->ssid_len == priv->scanned_shadow[i].ssid_len &&
+ memcmp(priv->scanned_shadow[i].ssid,
sme->ssid,
sme->ssid_len) == 0) {
if (!sme->bssid) {
if (sel_bssi_idx == UINT_MAX ||
- last_scanned_shadow[i].rssi >
- last_scanned_shadow[sel_bssi_idx].rssi)
+ priv->scanned_shadow[i].rssi >
+ priv->scanned_shadow[sel_bssi_idx].rssi)
sel_bssi_idx = i;
} else {
- if (memcmp(last_scanned_shadow[i].bssid,
+ if (memcmp(priv->scanned_shadow[i].bssid,
sme->bssid,
ETH_ALEN) == 0) {
sel_bssi_idx = i;
@@ -701,12 +687,16 @@ static int connect(struct wiphy *wiphy, struct net_device *dev,
}
}
- if (sel_bssi_idx < last_scanned_cnt) {
- nw_info = &last_scanned_shadow[sel_bssi_idx];
+ if (sel_bssi_idx < priv->scanned_cnt) {
+ nw_info = &priv->scanned_shadow[sel_bssi_idx];
} else {
ret = -ENOENT;
- wilc_connecting = 0;
- return ret;
+ goto out_error;
+ }
+
+ if (ether_addr_equal_unaligned(vif->bssid, nw_info->bssid)) {
+ ret = -EALREADY;
+ goto out_error;
}
memset(priv->wep_key, 0, sizeof(priv->wep_key));
@@ -748,8 +738,7 @@ static int connect(struct wiphy *wiphy, struct net_device *dev,
ret = -ENOTSUPP;
netdev_err(dev, "%s: Unsupported cipher\n",
__func__);
- wilc_connecting = 0;
- return ret;
+ goto out_error;
}
}
@@ -796,13 +785,18 @@ static int connect(struct wiphy *wiphy, struct net_device *dev,
security, auth_type,
nw_info->ch,
nw_info->join_params);
- if (ret != 0) {
+ if (ret) {
+ u8 null_bssid[ETH_ALEN] = {0};
+
netdev_err(dev, "wilc_set_join_req(): Error\n");
ret = -ENOENT;
- wilc_connecting = 0;
- return ret;
+ wilc_wlan_set_bssid(dev, null_bssid, STATION_MODE);
+ goto out_error;
}
+ return 0;
+out_error:
+ vif->connecting = false;
return ret;
}
@@ -816,7 +810,7 @@ static int disconnect(struct wiphy *wiphy, struct net_device *dev,
int ret;
u8 null_bssid[ETH_ALEN] = {0};
- wilc_connecting = 0;
+ vif->connecting = false;
if (!wilc)
return -EIO;
@@ -832,9 +826,9 @@ static int disconnect(struct wiphy *wiphy, struct net_device *dev,
wlan_channel = INVALID_CHANNEL;
wilc_wlan_set_bssid(priv->dev, null_bssid, STATION_MODE);
- p2p_local_random = 0x01;
- p2p_recv_random = 0x00;
- wilc_ie = false;
+ priv->p2p.local_random = 0x01;
+ priv->p2p.recv_random = 0x00;
+ priv->p2p.is_wilc_ie = false;
wfi_drv->p2p_timeout = 0;
ret = wilc_disconnect(vif, reason_code);
@@ -1132,9 +1126,9 @@ static int get_station(struct wiphy *wiphy, struct net_device *dev,
if (stats.link_speed > TCP_ACK_FILTER_LINK_SPEED_THRESH &&
stats.link_speed != DEFAULT_LINK_SPEED)
- wilc_enable_tcp_ack_filter(true);
+ wilc_enable_tcp_ack_filter(vif, true);
else if (stats.link_speed != DEFAULT_LINK_SPEED)
- wilc_enable_tcp_ack_filter(false);
+ wilc_enable_tcp_ack_filter(vif, false);
}
return 0;
}
@@ -1333,20 +1327,21 @@ static void wilc_wfi_cfg_parse_rx_vendor_spec(struct wilc_priv *priv, u8 *buff,
struct wilc_vif *vif = netdev_priv(priv->dev);
subtype = buff[P2P_PUB_ACTION_SUBTYPE];
- if ((subtype == GO_NEG_REQ || subtype == GO_NEG_RSP) && !wilc_ie) {
+ if ((subtype == GO_NEG_REQ || subtype == GO_NEG_RSP) &&
+ !priv->p2p.is_wilc_ie) {
for (i = P2P_PUB_ACTION_SUBTYPE; i < size; i++) {
if (!memcmp(p2p_vendor_spec, &buff[i], 6)) {
- p2p_recv_random = buff[i + 6];
- wilc_ie = true;
+ priv->p2p.recv_random = buff[i + 6];
+ priv->p2p.is_wilc_ie = true;
break;
}
}
}
- if (p2p_local_random <= p2p_recv_random) {
+ if (priv->p2p.local_random <= priv->p2p.recv_random) {
netdev_dbg(vif->ndev,
"PEER WILL BE GO LocaRand=%02x RecvRand %02x\n",
- p2p_local_random, p2p_recv_random);
+ priv->p2p.local_random, priv->p2p.recv_random);
return;
}
@@ -1414,7 +1409,7 @@ void wilc_wfi_p2p_rx(struct net_device *dev, u8 *buff, u32 size)
size);
if ((subtype == GO_NEG_REQ || subtype == GO_NEG_RSP) &&
- wilc_ie)
+ priv->p2p.is_wilc_ie)
size -= 7;
break;
@@ -1506,7 +1501,8 @@ static int cancel_remain_on_channel(struct wiphy *wiphy,
priv->remain_on_ch_params.listen_session_id);
}
-static void wilc_wfi_cfg_tx_vendor_spec(struct p2p_mgmt_data *mgmt_tx,
+static void wilc_wfi_cfg_tx_vendor_spec(struct wilc_priv *priv,
+ struct p2p_mgmt_data *mgmt_tx,
struct cfg80211_mgmt_tx_params *params,
u8 iftype, u32 buf_len)
{
@@ -1516,17 +1512,16 @@ static void wilc_wfi_cfg_tx_vendor_spec(struct p2p_mgmt_data *mgmt_tx,
u8 subtype = buf[P2P_PUB_ACTION_SUBTYPE];
if (subtype == GO_NEG_REQ || subtype == GO_NEG_RSP) {
- if (p2p_local_random == 1 &&
- p2p_recv_random < p2p_local_random) {
- get_random_bytes(&p2p_local_random, 1);
- p2p_local_random++;
+ if (priv->p2p.local_random == 1 &&
+ priv->p2p.recv_random < priv->p2p.local_random) {
+ get_random_bytes(&priv->p2p.local_random, 1);
+ priv->p2p.local_random++;
}
}
- if (p2p_local_random <= p2p_recv_random || !(subtype == GO_NEG_REQ ||
- subtype == GO_NEG_RSP ||
- subtype == P2P_INV_REQ ||
- subtype == P2P_INV_RSP))
+ if (priv->p2p.local_random <= priv->p2p.recv_random ||
+ !(subtype == GO_NEG_REQ || subtype == GO_NEG_RSP ||
+ subtype == P2P_INV_REQ || subtype == P2P_INV_RSP))
return;
for (i = P2P_PUB_ACTION_SUBTYPE + 2; i < len; i++) {
@@ -1550,7 +1545,7 @@ static void wilc_wfi_cfg_tx_vendor_spec(struct p2p_mgmt_data *mgmt_tx,
memcpy(&mgmt_tx->buff[len], p2p_vendor_spec,
vendor_spec_len);
- mgmt_tx->buff[len + vendor_spec_len] = p2p_local_random;
+ mgmt_tx->buff[len + vendor_spec_len] = priv->p2p.local_random;
mgmt_tx->size = buf_len;
}
}
@@ -1569,7 +1564,7 @@ static int mgmt_tx(struct wiphy *wiphy,
struct wilc_priv *priv = wiphy_priv(wiphy);
struct host_if_drv *wfi_drv = priv->hif_drv;
struct wilc_vif *vif = netdev_priv(wdev->netdev);
- u32 buf_len = len + sizeof(p2p_vendor_spec) + sizeof(p2p_local_random);
+ u32 buf_len = len + sizeof(p2p_vendor_spec) + sizeof(priv->p2p.local_random);
int ret = 0;
*cookie = (unsigned long)buf;
@@ -1617,8 +1612,8 @@ static int mgmt_tx(struct wiphy *wiphy,
case PUBLIC_ACT_VENDORSPEC:
if (!memcmp(p2p_oui, &buf[ACTION_SUBTYPE_ID + 1], 4))
- wilc_wfi_cfg_tx_vendor_spec(mgmt_tx, params,
- vif->iftype,
+ wilc_wfi_cfg_tx_vendor_spec(priv, mgmt_tx,
+ params, vif->iftype,
buf_len);
else
netdev_dbg(vif->ndev,
@@ -1732,7 +1727,7 @@ static int set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
if (!priv->hif_drv)
return -EIO;
- if (wilc_enable_ps)
+ if (vif->wilc->enable_ps)
wilc_set_power_mgmt(vif, enabled, timeout);
return 0;
@@ -1746,15 +1741,15 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev,
struct wilc_vif *vif = netdev_priv(dev);
struct wilc *wl = vif->wilc;
- p2p_local_random = 0x01;
- p2p_recv_random = 0x00;
- wilc_ie = false;
- wilc_optaining_ip = false;
- del_timer(&wilc_during_ip_timer);
+ priv->p2p.local_random = 0x01;
+ priv->p2p.recv_random = 0x00;
+ priv->p2p.is_wilc_ie = false;
+ vif->obtaining_ip = false;
+ del_timer(&vif->during_ip_timer);
switch (type) {
case NL80211_IFTYPE_STATION:
- wilc_connecting = 0;
+ vif->connecting = false;
dev->ieee80211_ptr->iftype = type;
priv->wdev->iftype = type;
vif->monitor_flag = 0;
@@ -1764,46 +1759,46 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev,
memset(priv->assoc_stainfo.sta_associated_bss, 0,
MAX_NUM_STA * ETH_ALEN);
- wilc_enable_ps = true;
+ wl->enable_ps = true;
wilc_set_power_mgmt(vif, 1, 0);
break;
case NL80211_IFTYPE_P2P_CLIENT:
- wilc_connecting = 0;
+ vif->connecting = false;
dev->ieee80211_ptr->iftype = type;
priv->wdev->iftype = type;
vif->monitor_flag = 0;
vif->iftype = CLIENT_MODE;
wilc_set_operation_mode(vif, STATION_MODE);
- wilc_enable_ps = false;
+ wl->enable_ps = false;
wilc_set_power_mgmt(vif, 0, 0);
break;
case NL80211_IFTYPE_AP:
- wilc_enable_ps = false;
+ wl->enable_ps = false;
dev->ieee80211_ptr->iftype = type;
priv->wdev->iftype = type;
vif->iftype = AP_MODE;
if (wl->initialized) {
wilc_set_wfi_drv_handler(vif, wilc_get_vif_idx(vif),
- 0, vif->ifc_id);
+ 0, vif->ifc_id, false);
wilc_set_operation_mode(vif, AP_MODE);
wilc_set_power_mgmt(vif, 0, 0);
}
break;
case NL80211_IFTYPE_P2P_GO:
- wilc_optaining_ip = true;
- mod_timer(&wilc_during_ip_timer,
+ vif->obtaining_ip = true;
+ mod_timer(&vif->during_ip_timer,
jiffies + msecs_to_jiffies(DURING_IP_TIME_OUT));
wilc_set_operation_mode(vif, AP_MODE);
dev->ieee80211_ptr->iftype = type;
priv->wdev->iftype = type;
vif->iftype = GO_MODE;
- wilc_enable_ps = false;
+ wl->enable_ps = false;
wilc_set_power_mgmt(vif, 0, 0);
break;
@@ -2154,8 +2149,12 @@ struct wireless_dev *wilc_create_wiphy(struct net_device *net,
set_wiphy_dev(wdev->wiphy, dev);
ret = wiphy_register(wdev->wiphy);
- if (ret)
+ if (ret) {
netdev_err(net, "Cannot register wiphy device\n");
+ wiphy_free(wdev->wiphy);
+ kfree(wdev);
+ return NULL;
+ }
priv->dev = net;
return wdev;
@@ -2165,12 +2164,10 @@ int wilc_init_host_int(struct net_device *net)
{
int ret;
struct wilc_priv *priv = wdev_priv(net->ieee80211_ptr);
+ struct wilc_vif *vif = netdev_priv(priv->dev);
- if (op_ifcs == 0) {
- timer_setup(&aging_timer, remove_network_from_shadow, 0);
- timer_setup(&wilc_during_ip_timer, clear_during_ip, 0);
- }
- op_ifcs++;
+ timer_setup(&priv->aging_timer, remove_network_from_shadow, 0);
+ timer_setup(&vif->during_ip_timer, clear_during_ip, 0);
priv->p2p_listen_state = false;
@@ -2182,7 +2179,7 @@ int wilc_init_host_int(struct net_device *net)
return ret;
}
-int wilc_deinit_host_int(struct net_device *net)
+void wilc_deinit_host_int(struct net_device *net)
{
int ret;
struct wilc_priv *priv = wdev_priv(net->ieee80211_ptr);
@@ -2190,19 +2187,15 @@ int wilc_deinit_host_int(struct net_device *net)
priv->p2p_listen_state = false;
- op_ifcs--;
-
mutex_destroy(&priv->scan_req_lock);
ret = wilc_deinit(vif);
- clear_shadow_scan();
- if (op_ifcs == 0)
- del_timer_sync(&wilc_during_ip_timer);
+ del_timer_sync(&priv->aging_timer);
+ clear_shadow_scan(priv);
+ del_timer_sync(&vif->during_ip_timer);
if (ret)
netdev_err(net, "Error while deinitializing host interface\n");
-
- return ret;
}
void wilc_free_wiphy(struct net_device *net)
diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.h b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.h
index be412b65926c..4812c8e2c79b 100644
--- a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.h
+++ b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.h
@@ -11,10 +11,10 @@
struct wireless_dev *wilc_create_wiphy(struct net_device *net,
struct device *dev);
void wilc_free_wiphy(struct net_device *net);
-int wilc_deinit_host_int(struct net_device *net);
+void wilc_deinit_host_int(struct net_device *net);
int wilc_init_host_int(struct net_device *net);
void wilc_wfi_monitor_rx(u8 *buff, u32 size);
-int wilc_wfi_deinit_mon_interface(void);
+void wilc_wfi_deinit_mon_interface(void);
struct net_device *wilc_wfi_init_mon_interface(const char *name,
struct net_device *real_dev);
void wilc_mgmt_frame_register(struct wiphy *wiphy, struct wireless_dev *wdev,
diff --git a/drivers/staging/wilc1000/wilc_wfi_netdevice.h b/drivers/staging/wilc1000/wilc_wfi_netdevice.h
index b7eee772f3fe..4f05a16c778e 100644
--- a/drivers/staging/wilc1000/wilc_wfi_netdevice.h
+++ b/drivers/staging/wilc1000/wilc_wfi_netdevice.h
@@ -16,6 +16,7 @@
#include "host_interface.h"
#include "wilc_wlan.h"
+#include "wilc_wlan_cfg.h"
#define FLOW_CONTROL_LOWER_THRESHOLD 128
#define FLOW_CONTROL_UPPER_THRESHOLD 256
@@ -68,6 +69,12 @@ struct wilc_wfi_p2p_listen_params {
u32 listen_session_id;
};
+struct wilc_p2p_var {
+ u8 local_random;
+ u8 recv_random;
+ bool is_wilc_ie;
+};
+
struct wilc_priv {
struct wireless_dev *wdev;
struct cfg80211_scan_request *scan_req;
@@ -94,7 +101,10 @@ struct wilc_priv {
/* mutexes */
struct mutex scan_req_lock;
bool p2p_listen_state;
-
+ struct timer_list aging_timer;
+ struct network_info scanned_shadow[MAX_NUM_SCANNED_NETWORKS_SHADOW];
+ int scanned_cnt;
+ struct wilc_p2p_var p2p;
};
struct frame_reg {
@@ -102,6 +112,32 @@ struct frame_reg {
bool reg;
};
+#define MAX_TCP_SESSION 25
+#define MAX_PENDING_ACKS 256
+
+struct ack_session_info {
+ u32 seq_num;
+ u32 bigger_ack_num;
+ u16 src_port;
+ u16 dst_port;
+ u16 status;
+};
+
+struct pending_acks {
+ u32 ack_num;
+ u32 session_index;
+ struct txq_entry_t *txqe;
+};
+
+struct tcp_ack_filter {
+ struct ack_session_info ack_session_info[2 * MAX_TCP_SESSION];
+ struct pending_acks pending_acks[MAX_PENDING_ACKS];
+ u32 pending_base;
+ u32 tcp_session;
+ u32 pending_acks_idx;
+ bool enabled;
+};
+
struct wilc_vif {
u8 idx;
u8 iftype;
@@ -116,12 +152,18 @@ struct wilc_vif {
struct net_device *ndev;
u8 mode;
u8 ifc_id;
+ struct timer_list during_ip_timer;
+ bool obtaining_ip;
+ struct timer_list periodic_rssi;
+ struct rf_info periodic_stat;
+ struct tcp_ack_filter ack_filter;
+ bool connecting;
};
struct wilc {
const struct wilc_hif_func *hif_func;
int io_type;
- int mac_status;
+ s8 mac_status;
struct gpio_desc *gpio_irq;
bool initialized;
int dev_irq_num;
@@ -165,7 +207,12 @@ struct wilc {
struct device *dev;
bool suspend_event;
- struct rf_info dummy_statistics;
+ bool enable_ps;
+ int clients_count;
+ struct workqueue_struct *hif_workqueue;
+ enum chip_ps_states chip_ps_state;
+ struct wilc_cfg cfg;
+ void *bus_data;
};
struct wilc_wfi_mon_priv {
@@ -178,6 +225,6 @@ void wilc_netdev_cleanup(struct wilc *wilc);
int wilc_netdev_init(struct wilc **wilc, struct device *dev, int io_type,
const struct wilc_hif_func *ops);
void wilc_wfi_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size);
-int wilc_wlan_set_bssid(struct net_device *wilc_netdev, u8 *bssid, u8 mode);
+void wilc_wlan_set_bssid(struct net_device *wilc_netdev, u8 *bssid, u8 mode);
#endif
diff --git a/drivers/staging/wilc1000/wilc_wlan.c b/drivers/staging/wilc1000/wilc_wlan.c
index 8b184aa30d25..a48c906b2443 100644
--- a/drivers/staging/wilc1000/wilc_wlan.c
+++ b/drivers/staging/wilc1000/wilc_wlan.c
@@ -9,8 +9,6 @@
#include "wilc_wfi_netdevice.h"
#include "wilc_wlan_cfg.h"
-static enum chip_ps_states chip_ps_state = CHIP_WAKEDUP;
-
static inline bool is_wilc1000(u32 id)
{
return ((id & 0xfffff000) == 0x100000 ? true : false);
@@ -73,8 +71,8 @@ static void wilc_wlan_txq_add_to_tail(struct net_device *dev,
complete(&wilc->txq_event);
}
-static int wilc_wlan_txq_add_to_head(struct wilc_vif *vif,
- struct txq_entry_t *tqe)
+static void wilc_wlan_txq_add_to_head(struct wilc_vif *vif,
+ struct txq_entry_t *tqe)
{
unsigned long flags;
struct wilc *wilc = vif->wilc;
@@ -89,69 +87,47 @@ static int wilc_wlan_txq_add_to_head(struct wilc_vif *vif,
spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
mutex_unlock(&wilc->txq_add_to_head_cs);
complete(&wilc->txq_event);
-
- return 0;
}
-struct ack_session_info;
-struct ack_session_info {
- u32 seq_num;
- u32 bigger_ack_num;
- u16 src_port;
- u16 dst_port;
- u16 status;
-};
-
-struct pending_acks_info {
- u32 ack_num;
- u32 session_index;
- struct txq_entry_t *txqe;
-};
-
#define NOT_TCP_ACK (-1)
-#define MAX_TCP_SESSION 25
-#define MAX_PENDING_ACKS 256
-static struct ack_session_info ack_session_info[2 * MAX_TCP_SESSION];
-static struct pending_acks_info pending_acks_info[MAX_PENDING_ACKS];
-
-static u32 pending_base;
-static u32 tcp_session;
-static u32 pending_acks;
-
-static inline int add_tcp_session(u32 src_prt, u32 dst_prt, u32 seq)
+static inline void add_tcp_session(struct wilc_vif *vif, u32 src_prt,
+ u32 dst_prt, u32 seq)
{
- if (tcp_session < 2 * MAX_TCP_SESSION) {
- ack_session_info[tcp_session].seq_num = seq;
- ack_session_info[tcp_session].bigger_ack_num = 0;
- ack_session_info[tcp_session].src_port = src_prt;
- ack_session_info[tcp_session].dst_port = dst_prt;
- tcp_session++;
+ struct tcp_ack_filter *f = &vif->ack_filter;
+
+ if (f->tcp_session < 2 * MAX_TCP_SESSION) {
+ f->ack_session_info[f->tcp_session].seq_num = seq;
+ f->ack_session_info[f->tcp_session].bigger_ack_num = 0;
+ f->ack_session_info[f->tcp_session].src_port = src_prt;
+ f->ack_session_info[f->tcp_session].dst_port = dst_prt;
+ f->tcp_session++;
}
- return 0;
}
-static inline int update_tcp_session(u32 index, u32 ack)
+static inline void update_tcp_session(struct wilc_vif *vif, u32 index, u32 ack)
{
+ struct tcp_ack_filter *f = &vif->ack_filter;
+
if (index < 2 * MAX_TCP_SESSION &&
- ack > ack_session_info[index].bigger_ack_num)
- ack_session_info[index].bigger_ack_num = ack;
- return 0;
+ ack > f->ack_session_info[index].bigger_ack_num)
+ f->ack_session_info[index].bigger_ack_num = ack;
}
-static inline int add_tcp_pending_ack(u32 ack, u32 session_index,
- struct txq_entry_t *txqe)
+static inline void add_tcp_pending_ack(struct wilc_vif *vif, u32 ack,
+ u32 session_index,
+ struct txq_entry_t *txqe)
{
- u32 i = pending_base + pending_acks;
+ struct tcp_ack_filter *f = &vif->ack_filter;
+ u32 i = f->pending_base + f->pending_acks_idx;
if (i < MAX_PENDING_ACKS) {
- pending_acks_info[i].ack_num = ack;
- pending_acks_info[i].txqe = txqe;
- pending_acks_info[i].session_index = session_index;
- txqe->tcp_pending_ack_idx = i;
- pending_acks++;
+ f->pending_acks[i].ack_num = ack;
+ f->pending_acks[i].txqe = txqe;
+ f->pending_acks[i].session_index = session_index;
+ txqe->ack_idx = i;
+ f->pending_acks_idx++;
}
- return 0;
}
static inline void tcp_process(struct net_device *dev, struct txq_entry_t *tqe)
@@ -162,72 +138,79 @@ static inline void tcp_process(struct net_device *dev, struct txq_entry_t *tqe)
unsigned long flags;
struct wilc_vif *vif = netdev_priv(dev);
struct wilc *wilc = vif->wilc;
+ struct tcp_ack_filter *f = &vif->ack_filter;
+ const struct iphdr *ip_hdr_ptr;
+ const struct tcphdr *tcp_hdr_ptr;
+ u32 ihl, total_length, data_offset;
spin_lock_irqsave(&wilc->txq_spinlock, flags);
- if (eth_hdr_ptr->h_proto == htons(ETH_P_IP)) {
- const struct iphdr *ip_hdr_ptr = buffer + ETH_HLEN;
+ if (eth_hdr_ptr->h_proto != htons(ETH_P_IP))
+ goto out;
- if (ip_hdr_ptr->protocol == IPPROTO_TCP) {
- const struct tcphdr *tcp_hdr_ptr;
- u32 IHL, total_length, data_offset;
+ ip_hdr_ptr = buffer + ETH_HLEN;
- IHL = ip_hdr_ptr->ihl << 2;
- tcp_hdr_ptr = buffer + ETH_HLEN + IHL;
- total_length = ntohs(ip_hdr_ptr->tot_len);
+ if (ip_hdr_ptr->protocol != IPPROTO_TCP)
+ goto out;
- data_offset = tcp_hdr_ptr->doff << 2;
- if (total_length == (IHL + data_offset)) {
- u32 seq_no, ack_no;
+ ihl = ip_hdr_ptr->ihl << 2;
+ tcp_hdr_ptr = buffer + ETH_HLEN + ihl;
+ total_length = ntohs(ip_hdr_ptr->tot_len);
- seq_no = ntohl(tcp_hdr_ptr->seq);
- ack_no = ntohl(tcp_hdr_ptr->ack_seq);
- for (i = 0; i < tcp_session; i++) {
- u32 j = ack_session_info[i].seq_num;
+ data_offset = tcp_hdr_ptr->doff << 2;
+ if (total_length == (ihl + data_offset)) {
+ u32 seq_no, ack_no;
- if (i < 2 * MAX_TCP_SESSION &&
- j == seq_no) {
- update_tcp_session(i, ack_no);
- break;
- }
- }
- if (i == tcp_session)
- add_tcp_session(0, 0, seq_no);
+ seq_no = ntohl(tcp_hdr_ptr->seq);
+ ack_no = ntohl(tcp_hdr_ptr->ack_seq);
+ for (i = 0; i < f->tcp_session; i++) {
+ u32 j = f->ack_session_info[i].seq_num;
- add_tcp_pending_ack(ack_no, i, tqe);
+ if (i < 2 * MAX_TCP_SESSION &&
+ j == seq_no) {
+ update_tcp_session(vif, i, ack_no);
+ break;
}
}
+ if (i == f->tcp_session)
+ add_tcp_session(vif, 0, 0, seq_no);
+
+ add_tcp_pending_ack(vif, ack_no, i, tqe);
}
+
+out:
spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
}
-static int wilc_wlan_txq_filter_dup_tcp_ack(struct net_device *dev)
+static void wilc_wlan_txq_filter_dup_tcp_ack(struct net_device *dev)
{
struct wilc_vif *vif = netdev_priv(dev);
struct wilc *wilc = vif->wilc;
+ struct tcp_ack_filter *f = &vif->ack_filter;
u32 i = 0;
u32 dropped = 0;
unsigned long flags;
spin_lock_irqsave(&wilc->txq_spinlock, flags);
- for (i = pending_base; i < (pending_base + pending_acks); i++) {
- u32 session_index;
+ for (i = f->pending_base;
+ i < (f->pending_base + f->pending_acks_idx); i++) {
+ u32 index;
u32 bigger_ack_num;
if (i >= MAX_PENDING_ACKS)
break;
- session_index = pending_acks_info[i].session_index;
+ index = f->pending_acks[i].session_index;
- if (session_index >= 2 * MAX_TCP_SESSION)
+ if (index >= 2 * MAX_TCP_SESSION)
break;
- bigger_ack_num = ack_session_info[session_index].bigger_ack_num;
+ bigger_ack_num = f->ack_session_info[index].bigger_ack_num;
- if (pending_acks_info[i].ack_num < bigger_ack_num) {
+ if (f->pending_acks[i].ack_num < bigger_ack_num) {
struct txq_entry_t *tqe;
- tqe = pending_acks_info[i].txqe;
+ tqe = f->pending_acks[i].txqe;
if (tqe) {
wilc_wlan_txq_remove(wilc, tqe);
tqe->status = 1;
@@ -239,13 +222,13 @@ static int wilc_wlan_txq_filter_dup_tcp_ack(struct net_device *dev)
}
}
}
- pending_acks = 0;
- tcp_session = 0;
+ f->pending_acks_idx = 0;
+ f->tcp_session = 0;
- if (pending_base == 0)
- pending_base = MAX_TCP_SESSION;
+ if (f->pending_base == 0)
+ f->pending_base = MAX_TCP_SESSION;
else
- pending_base = 0;
+ f->pending_base = 0;
spin_unlock_irqrestore(&wilc->txq_spinlock, flags);
@@ -254,15 +237,11 @@ static int wilc_wlan_txq_filter_dup_tcp_ack(struct net_device *dev)
msecs_to_jiffies(1));
dropped--;
}
-
- return 1;
}
-static bool enabled;
-
-void wilc_enable_tcp_ack_filter(bool value)
+void wilc_enable_tcp_ack_filter(struct wilc_vif *vif, bool value)
{
- enabled = value;
+ vif->ack_filter.enabled = value;
}
static int wilc_wlan_txq_add_cfg_pkt(struct wilc_vif *vif, u8 *buffer,
@@ -287,12 +266,9 @@ static int wilc_wlan_txq_add_cfg_pkt(struct wilc_vif *vif, u8 *buffer,
tqe->buffer_size = buffer_size;
tqe->tx_complete_func = NULL;
tqe->priv = NULL;
- tqe->tcp_pending_ack_idx = NOT_TCP_ACK;
+ tqe->ack_idx = NOT_TCP_ACK;
- if (wilc_wlan_txq_add_to_head(vif, tqe)) {
- kfree(tqe);
- return 0;
- }
+ wilc_wlan_txq_add_to_head(vif, tqe);
return 1;
}
@@ -319,8 +295,8 @@ int wilc_wlan_txq_add_net_pkt(struct net_device *dev, void *priv, u8 *buffer,
tqe->tx_complete_func = func;
tqe->priv = priv;
- tqe->tcp_pending_ack_idx = NOT_TCP_ACK;
- if (enabled)
+ tqe->ack_idx = NOT_TCP_ACK;
+ if (vif->ack_filter.enabled)
tcp_process(dev, tqe);
wilc_wlan_txq_add_to_tail(dev, tqe);
return wilc->txq_entries;
@@ -347,7 +323,7 @@ int wilc_wlan_txq_add_mgmt_pkt(struct net_device *dev, void *priv, u8 *buffer,
tqe->buffer_size = buffer_size;
tqe->tx_complete_func = func;
tqe->priv = priv;
- tqe->tcp_pending_ack_idx = NOT_TCP_ACK;
+ tqe->ack_idx = NOT_TCP_ACK;
wilc_wlan_txq_add_to_tail(dev, tqe);
return 1;
}
@@ -436,7 +412,7 @@ void chip_wakeup(struct wilc *wilc)
} while (wilc_get_chipid(wilc, true) == 0);
} else if ((wilc->io_type & 0x1) == HIF_SDIO) {
wilc->hif_func->hif_write_reg(wilc, 0xfa, 1);
- udelay(200);
+ usleep_range(200, 400);
wilc->hif_func->hif_read_reg(wilc, 0xf0, &reg);
do {
wilc->hif_func->hif_write_reg(wilc, 0xf0,
@@ -457,7 +433,7 @@ void chip_wakeup(struct wilc *wilc)
} while ((clk_status_reg & 0x1) == 0);
}
- if (chip_ps_state == CHIP_SLEEPING_MANUAL) {
+ if (wilc->chip_ps_state == CHIP_SLEEPING_MANUAL) {
if (wilc_get_chipid(wilc, false) < 0x1002b0) {
u32 val32;
@@ -470,20 +446,20 @@ void chip_wakeup(struct wilc *wilc)
wilc->hif_func->hif_write_reg(wilc, 0x1e9c, val32);
}
}
- chip_ps_state = CHIP_WAKEDUP;
+ wilc->chip_ps_state = CHIP_WAKEDUP;
}
EXPORT_SYMBOL_GPL(chip_wakeup);
void wilc_chip_sleep_manually(struct wilc *wilc)
{
- if (chip_ps_state != CHIP_WAKEDUP)
+ if (wilc->chip_ps_state != CHIP_WAKEDUP)
return;
acquire_bus(wilc, ACQUIRE_ONLY);
chip_allow_sleep(wilc);
wilc->hif_func->hif_write_reg(wilc, 0x10a8, 1);
- chip_ps_state = CHIP_SLEEPING_MANUAL;
+ wilc->chip_ps_state = CHIP_SLEEPING_MANUAL;
release_bus(wilc, RELEASE_ONLY);
}
EXPORT_SYMBOL_GPL(wilc_chip_sleep_manually);
@@ -685,9 +661,9 @@ int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count)
tqe->status = 1;
if (tqe->tx_complete_func)
tqe->tx_complete_func(tqe->priv, tqe->status);
- if (tqe->tcp_pending_ack_idx != NOT_TCP_ACK &&
- tqe->tcp_pending_ack_idx < MAX_PENDING_ACKS)
- pending_acks_info[tqe->tcp_pending_ack_idx].txqe = NULL;
+ if (tqe->ack_idx != NOT_TCP_ACK &&
+ tqe->ack_idx < MAX_PENDING_ACKS)
+ vif->ack_filter.pending_acks[tqe->ack_idx].txqe = NULL;
kfree(tqe);
} while (--entries);
@@ -1218,9 +1194,9 @@ int wilc_wlan_cfg_get(struct wilc_vif *vif, int start, u16 wid, int commit,
return ret_size;
}
-int wilc_wlan_cfg_get_val(u16 wid, u8 *buffer, u32 buffer_size)
+int wilc_wlan_cfg_get_val(struct wilc *wl, u16 wid, u8 *buffer, u32 buffer_size)
{
- return wilc_wlan_cfg_get_wid_value(wid, buffer, buffer_size);
+ return wilc_wlan_cfg_get_wid_value(wl, wid, buffer, buffer_size);
}
int wilc_send_config_pkt(struct wilc_vif *vif, u8 mode, struct wid *wids,
@@ -1240,7 +1216,8 @@ int wilc_send_config_pkt(struct wilc_vif *vif, u8 mode, struct wid *wids,
}
}
for (i = 0; i < count; i++) {
- wids[i].size = wilc_wlan_cfg_get_val(wids[i].id,
+ wids[i].size = wilc_wlan_cfg_get_val(vif->wilc,
+ wids[i].id,
wids[i].val,
wids[i].size);
}
@@ -1339,11 +1316,6 @@ int wilc_wlan_init(struct net_device *dev)
goto fail;
}
- if (!wilc_wlan_cfg_init()) {
- ret = -ENOBUFS;
- goto fail;
- }
-
if (!wilc->tx_buffer)
wilc->tx_buffer = kmalloc(LINUX_TX_SIZE, GFP_KERNEL);
diff --git a/drivers/staging/wilc1000/wilc_wlan.h b/drivers/staging/wilc1000/wilc_wlan.h
index 7467188dbf2f..27667131de1a 100644
--- a/drivers/staging/wilc1000/wilc_wlan.h
+++ b/drivers/staging/wilc1000/wilc_wlan.h
@@ -212,7 +212,7 @@
struct txq_entry_t {
struct list_head list;
int type;
- int tcp_pending_ack_idx;
+ int ack_idx;
u8 *buffer;
int buffer_size;
void *priv;
@@ -277,19 +277,19 @@ int wilc_wlan_cfg_set(struct wilc_vif *vif, int start, u16 wid, u8 *buffer,
u32 buffer_size, int commit, u32 drv_handler);
int wilc_wlan_cfg_get(struct wilc_vif *vif, int start, u16 wid, int commit,
u32 drv_handler);
-int wilc_wlan_cfg_get_val(u16 wid, u8 *buffer, u32 buffer_size);
+int wilc_wlan_cfg_get_val(struct wilc *wl, u16 wid, u8 *buffer,
+ u32 buffer_size);
int wilc_wlan_txq_add_mgmt_pkt(struct net_device *dev, void *priv, u8 *buffer,
u32 buffer_size, wilc_tx_complete_func_t func);
void wilc_chip_sleep_manually(struct wilc *wilc);
-void wilc_enable_tcp_ack_filter(bool value);
+void wilc_enable_tcp_ack_filter(struct wilc_vif *vif, bool value);
int wilc_wlan_get_num_conn_ifcs(struct wilc *wilc);
netdev_tx_t wilc_mac_xmit(struct sk_buff *skb, struct net_device *dev);
void wilc_wfi_p2p_rx(struct net_device *dev, u8 *buff, u32 size);
void host_wakeup_notify(struct wilc *wilc);
void host_sleep_notify(struct wilc *wilc);
-extern bool wilc_enable_ps;
void chip_allow_sleep(struct wilc *wilc);
void chip_wakeup(struct wilc *wilc);
int wilc_send_config_pkt(struct wilc_vif *vif, u8 mode, struct wid *wids,
diff --git a/drivers/staging/wilc1000/wilc_wlan_cfg.c b/drivers/staging/wilc1000/wilc_wlan_cfg.c
index 421576386ab4..faa001c75681 100644
--- a/drivers/staging/wilc1000/wilc_wlan_cfg.c
+++ b/drivers/staging/wilc1000/wilc_wlan_cfg.c
@@ -8,6 +8,7 @@
#include "wilc_wlan.h"
#include "wilc_wlan_cfg.h"
#include "coreconfigurator.h"
+#include "wilc_wfi_netdevice.h"
enum cfg_cmd_type {
CFG_BYTE_CMD = 0,
@@ -17,134 +18,30 @@ enum cfg_cmd_type {
CFG_BIN_CMD = 4
};
-struct wilc_mac_cfg {
- int mac_status;
- u8 mac_address[7];
- u8 ip_address[5];
- u8 bssid[7];
- u8 ssid[34];
- u8 firmware_version[129];
- u8 supp_rate[24];
- u8 wep_key[28];
- u8 i_psk[66];
- u8 hw_product_version[33];
- u8 phyversion[17];
- u8 supp_username[21];
- u8 supp_password[64];
- u8 assoc_req[256];
- u8 assoc_rsp[256];
- u8 firmware_info[8];
- u8 scan_result[256];
- u8 scan_result1[256];
-};
-
-static struct wilc_mac_cfg g_mac;
-
-static struct wilc_cfg_byte g_cfg_byte[] = {
- {WID_BSS_TYPE, 0},
- {WID_CURRENT_TX_RATE, 0},
- {WID_CURRENT_CHANNEL, 0},
- {WID_PREAMBLE, 0},
- {WID_11G_OPERATING_MODE, 0},
+static const struct wilc_cfg_byte g_cfg_byte[] = {
{WID_STATUS, 0},
- {WID_SCAN_TYPE, 0},
- {WID_KEY_ID, 0},
- {WID_QOS_ENABLE, 0},
- {WID_POWER_MANAGEMENT, 0},
- {WID_11I_MODE, 0},
- {WID_AUTH_TYPE, 0},
- {WID_SITE_SURVEY, 0},
- {WID_LISTEN_INTERVAL, 0},
- {WID_DTIM_PERIOD, 0},
- {WID_ACK_POLICY, 0},
- {WID_BCAST_SSID, 0},
- {WID_REKEY_POLICY, 0},
- {WID_SHORT_SLOT_ALLOWED, 0},
- {WID_START_SCAN_REQ, 0},
{WID_RSSI, 0},
{WID_LINKSPEED, 0},
- {WID_AUTO_RX_SENSITIVITY, 0},
- {WID_DATAFLOW_CONTROL, 0},
- {WID_SCAN_FILTER, 0},
- {WID_11N_PROT_MECH, 0},
- {WID_11N_ERP_PROT_TYPE, 0},
- {WID_11N_ENABLE, 0},
- {WID_11N_OPERATING_MODE, 0},
- {WID_11N_OBSS_NONHT_DETECTION, 0},
- {WID_11N_HT_PROT_TYPE, 0},
- {WID_11N_RIFS_PROT_ENABLE, 0},
- {WID_11N_SMPS_MODE, 0},
- {WID_11N_CURRENT_TX_MCS, 0},
- {WID_11N_SHORT_GI_ENABLE, 0},
- {WID_RIFS_MODE, 0},
- {WID_TX_ABORT_CONFIG, 0},
- {WID_11N_IMMEDIATE_BA_ENABLED, 0},
- {WID_11N_TXOP_PROT_DISABLE, 0},
{WID_NIL, 0}
};
-static struct wilc_cfg_hword g_cfg_hword[] = {
- {WID_LINK_LOSS_THRESHOLD, 0},
- {WID_RTS_THRESHOLD, 0},
- {WID_FRAG_THRESHOLD, 0},
- {WID_SHORT_RETRY_LIMIT, 0},
- {WID_LONG_RETRY_LIMIT, 0},
- {WID_BEACON_INTERVAL, 0},
- {WID_RX_SENSE, 0},
- {WID_ACTIVE_SCAN_TIME, 0},
- {WID_PASSIVE_SCAN_TIME, 0},
- {WID_SITE_SURVEY_SCAN_TIME, 0},
- {WID_JOIN_START_TIMEOUT, 0},
- {WID_AUTH_TIMEOUT, 0},
- {WID_ASOC_TIMEOUT, 0},
- {WID_11I_PROTOCOL_TIMEOUT, 0},
- {WID_EAPOL_RESPONSE_TIMEOUT, 0},
- {WID_11N_SIG_QUAL_VAL, 0},
- {WID_CCA_THRESHOLD, 0},
+static const struct wilc_cfg_hword g_cfg_hword[] = {
{WID_NIL, 0}
};
-static struct wilc_cfg_word g_cfg_word[] = {
+static const struct wilc_cfg_word g_cfg_word[] = {
{WID_FAILED_COUNT, 0},
- {WID_RETRY_COUNT, 0},
- {WID_MULTIPLE_RETRY_COUNT, 0},
- {WID_FRAME_DUPLICATE_COUNT, 0},
- {WID_ACK_FAILURE_COUNT, 0},
{WID_RECEIVED_FRAGMENT_COUNT, 0},
- {WID_MCAST_RECEIVED_FRAME_COUNT, 0},
- {WID_FCS_ERROR_COUNT, 0},
{WID_SUCCESS_FRAME_COUNT, 0},
- {WID_TX_FRAGMENT_COUNT, 0},
- {WID_TX_MULTICAST_FRAME_COUNT, 0},
- {WID_RTS_SUCCESS_COUNT, 0},
- {WID_RTS_FAILURE_COUNT, 0},
- {WID_WEP_UNDECRYPTABLE_COUNT, 0},
- {WID_REKEY_PERIOD, 0},
- {WID_REKEY_PACKET_COUNT, 0},
- {WID_HW_RX_COUNT, 0},
{WID_GET_INACTIVE_TIME, 0},
{WID_NIL, 0}
};
-static struct wilc_cfg_str g_cfg_str[] = {
- {WID_SSID, g_mac.ssid}, /* 33 + 1 bytes */
- {WID_FIRMWARE_VERSION, g_mac.firmware_version},
- {WID_OPERATIONAL_RATE_SET, g_mac.supp_rate},
- {WID_BSSID, g_mac.bssid}, /* 6 bytes */
- {WID_WEP_KEY_VALUE, g_mac.wep_key}, /* 27 bytes */
- {WID_11I_PSK, g_mac.i_psk}, /* 65 bytes */
- {WID_HARDWARE_VERSION, g_mac.hw_product_version},
- {WID_MAC_ADDR, g_mac.mac_address},
- {WID_PHY_VERSION, g_mac.phyversion},
- {WID_SUPP_USERNAME, g_mac.supp_username},
- {WID_SUPP_PASSWORD, g_mac.supp_password},
- {WID_SITE_SURVEY_RESULTS, g_mac.scan_result},
- {WID_SITE_SURVEY_RESULTS, g_mac.scan_result1},
- {WID_ASSOC_REQ_INFO, g_mac.assoc_req},
- {WID_ASSOC_RES_INFO, g_mac.assoc_rsp},
- {WID_FIRMWARE_INFO, g_mac.firmware_version},
- {WID_IP_ADDRESS, g_mac.ip_address},
+static const struct wilc_cfg_str g_cfg_str[] = {
+ {WID_FIRMWARE_VERSION, NULL},
+ {WID_MAC_ADDR, NULL},
+ {WID_ASSOC_RES_INFO, NULL},
{WID_NIL, NULL}
};
@@ -265,7 +162,7 @@ static int wilc_wlan_cfg_set_bin(u8 *frame, u32 offset, u16 id, u8 *b, u32 size)
********************************************/
#define GET_WID_TYPE(wid) (((wid) >> 12) & 0x7)
-static void wilc_wlan_parse_response_frame(u8 *info, int size)
+static void wilc_wlan_parse_response_frame(struct wilc *wl, u8 *info, int size)
{
u16 wid;
u32 len = 0, i = 0;
@@ -277,11 +174,11 @@ static void wilc_wlan_parse_response_frame(u8 *info, int size)
switch (GET_WID_TYPE(wid)) {
case WID_CHAR:
do {
- if (g_cfg_byte[i].id == WID_NIL)
+ if (wl->cfg.b[i].id == WID_NIL)
break;
- if (g_cfg_byte[i].id == wid) {
- g_cfg_byte[i].val = info[4];
+ if (wl->cfg.b[i].id == wid) {
+ wl->cfg.b[i].val = info[4];
break;
}
i++;
@@ -291,12 +188,12 @@ static void wilc_wlan_parse_response_frame(u8 *info, int size)
case WID_SHORT:
do {
- if (g_cfg_hword[i].id == WID_NIL)
+ if (wl->cfg.hw[i].id == WID_NIL)
break;
- if (g_cfg_hword[i].id == wid) {
- g_cfg_hword[i].val = (info[4] |
- (info[5] << 8));
+ if (wl->cfg.hw[i].id == wid) {
+ wl->cfg.hw[i].val = (info[4] |
+ (info[5] << 8));
break;
}
i++;
@@ -306,14 +203,14 @@ static void wilc_wlan_parse_response_frame(u8 *info, int size)
case WID_INT:
do {
- if (g_cfg_word[i].id == WID_NIL)
+ if (wl->cfg.w[i].id == WID_NIL)
break;
- if (g_cfg_word[i].id == wid) {
- g_cfg_word[i].val = (info[4] |
- (info[5] << 8) |
- (info[6] << 16) |
- (info[7] << 24));
+ if (wl->cfg.w[i].id == wid) {
+ wl->cfg.w[i].val = (info[4] |
+ (info[5] << 8) |
+ (info[6] << 16) |
+ (info[7] << 24));
break;
}
i++;
@@ -323,17 +220,11 @@ static void wilc_wlan_parse_response_frame(u8 *info, int size)
case WID_STR:
do {
- if (g_cfg_str[i].id == WID_NIL)
+ if (wl->cfg.s[i].id == WID_NIL)
break;
- if (g_cfg_str[i].id == wid) {
- if (wid == WID_SITE_SURVEY_RESULTS) {
- static int toggle;
-
- i += toggle;
- toggle ^= 1;
- }
- memcpy(g_cfg_str[i].str, &info[2],
+ if (wl->cfg.s[i].id == wid) {
+ memcpy(wl->cfg.s[i].str, &info[2],
(info[2] + 2));
break;
}
@@ -350,22 +241,28 @@ static void wilc_wlan_parse_response_frame(u8 *info, int size)
}
}
-static int wilc_wlan_parse_info_frame(u8 *info, int size)
+static void wilc_wlan_parse_info_frame(struct wilc *wl, u8 *info)
{
- struct wilc_mac_cfg *pd = &g_mac;
u32 wid, len;
- int type = WILC_CFG_RSP_STATUS;
wid = info[0] | (info[1] << 8);
len = info[2];
if (len == 1 && wid == WID_STATUS) {
- pd->mac_status = info[3];
- type = WILC_CFG_RSP_STATUS;
- }
+ int i = 0;
- return type;
+ do {
+ if (wl->cfg.b[i].id == WID_NIL)
+ break;
+
+ if (wl->cfg.b[i].id == wid) {
+ wl->cfg.b[i].val = info[3];
+ break;
+ }
+ i++;
+ } while (1);
+ }
}
/********************************************
@@ -424,24 +321,20 @@ int wilc_wlan_cfg_get_wid(u8 *frame, u32 offset, u16 id)
return 2;
}
-int wilc_wlan_cfg_get_wid_value(u16 wid, u8 *buffer, u32 buffer_size)
+int wilc_wlan_cfg_get_wid_value(struct wilc *wl, u16 wid, u8 *buffer,
+ u32 buffer_size)
{
u32 type = (wid >> 12) & 0xf;
int i, ret = 0;
- if (wid == WID_STATUS) {
- *((u32 *)buffer) = g_mac.mac_status;
- return 4;
- }
-
i = 0;
if (type == CFG_BYTE_CMD) {
do {
- if (g_cfg_byte[i].id == WID_NIL)
+ if (wl->cfg.b[i].id == WID_NIL)
break;
- if (g_cfg_byte[i].id == wid) {
- memcpy(buffer, &g_cfg_byte[i].val, 1);
+ if (wl->cfg.b[i].id == wid) {
+ memcpy(buffer, &wl->cfg.b[i].val, 1);
ret = 1;
break;
}
@@ -449,11 +342,11 @@ int wilc_wlan_cfg_get_wid_value(u16 wid, u8 *buffer, u32 buffer_size)
} while (1);
} else if (type == CFG_HWORD_CMD) {
do {
- if (g_cfg_hword[i].id == WID_NIL)
+ if (wl->cfg.hw[i].id == WID_NIL)
break;
- if (g_cfg_hword[i].id == wid) {
- memcpy(buffer, &g_cfg_hword[i].val, 2);
+ if (wl->cfg.hw[i].id == wid) {
+ memcpy(buffer, &wl->cfg.hw[i].val, 2);
ret = 2;
break;
}
@@ -461,11 +354,11 @@ int wilc_wlan_cfg_get_wid_value(u16 wid, u8 *buffer, u32 buffer_size)
} while (1);
} else if (type == CFG_WORD_CMD) {
do {
- if (g_cfg_word[i].id == WID_NIL)
+ if (wl->cfg.w[i].id == WID_NIL)
break;
- if (g_cfg_word[i].id == wid) {
- memcpy(buffer, &g_cfg_word[i].val, 4);
+ if (wl->cfg.w[i].id == wid) {
+ memcpy(buffer, &wl->cfg.w[i].val, 4);
ret = 4;
break;
}
@@ -473,23 +366,17 @@ int wilc_wlan_cfg_get_wid_value(u16 wid, u8 *buffer, u32 buffer_size)
} while (1);
} else if (type == CFG_STR_CMD) {
do {
- u32 id = g_cfg_str[i].id;
+ u32 id = wl->cfg.s[i].id;
if (id == WID_NIL)
break;
if (id == wid) {
- u32 size = g_cfg_str[i].str[0] |
- (g_cfg_str[i].str[1] << 8);
+ u32 size = (wl->cfg.s[i].str[0] |
+ (wl->cfg.s[i].str[1] << 8));
if (buffer_size >= size) {
- if (id == WID_SITE_SURVEY_RESULTS) {
- static int toggle;
-
- i += toggle;
- toggle ^= 1;
- }
- memcpy(buffer, &g_cfg_str[i].str[2],
+ memcpy(buffer, &wl->cfg.s[i].str[2],
size);
ret = size;
}
@@ -498,14 +385,12 @@ int wilc_wlan_cfg_get_wid_value(u16 wid, u8 *buffer, u32 buffer_size)
i++;
} while (1);
}
-
return ret;
}
-int wilc_wlan_cfg_indicate_rx(struct wilc *wilc, u8 *frame, int size,
- struct wilc_cfg_rsp *rsp)
+void wilc_wlan_cfg_indicate_rx(struct wilc *wilc, u8 *frame, int size,
+ struct wilc_cfg_rsp *rsp)
{
- int ret = 1;
u8 msg_type;
u8 msg_id;
@@ -513,6 +398,7 @@ int wilc_wlan_cfg_indicate_rx(struct wilc *wilc, u8 *frame, int size,
msg_id = frame[1]; /* seq no */
frame += 4;
size -= 4;
+ rsp->type = 0;
/*
* The valid types of response messages are
@@ -523,13 +409,14 @@ int wilc_wlan_cfg_indicate_rx(struct wilc *wilc, u8 *frame, int size,
switch (msg_type) {
case 'R':
- wilc_wlan_parse_response_frame(frame, size);
+ wilc_wlan_parse_response_frame(wilc, frame, size);
rsp->type = WILC_CFG_RSP;
rsp->seq_no = msg_id;
break;
case 'I':
- rsp->type = wilc_wlan_parse_info_frame(frame, size);
+ wilc_wlan_parse_info_frame(wilc, frame);
+ rsp->type = WILC_CFG_RSP_STATUS;
rsp->seq_no = msg_id;
/*call host interface info parse as well*/
wilc_gnrl_async_info_received(wilc, frame - 4, size + 4);
@@ -537,7 +424,6 @@ int wilc_wlan_cfg_indicate_rx(struct wilc *wilc, u8 *frame, int size,
case 'N':
wilc_network_info_received(wilc, frame - 4, size + 4);
- rsp->type = 0;
break;
case 'S':
@@ -545,17 +431,67 @@ int wilc_wlan_cfg_indicate_rx(struct wilc *wilc, u8 *frame, int size,
break;
default:
- rsp->type = 0;
rsp->seq_no = msg_id;
- ret = 0;
break;
}
+}
- return ret;
+int wilc_wlan_cfg_init(struct wilc *wl)
+{
+ struct wilc_cfg_str_vals *str_vals;
+ int i = 0;
+
+ wl->cfg.b = kmemdup(g_cfg_byte, sizeof(g_cfg_byte), GFP_KERNEL);
+ if (!wl->cfg.b)
+ return -ENOMEM;
+
+ wl->cfg.hw = kmemdup(g_cfg_hword, sizeof(g_cfg_hword), GFP_KERNEL);
+ if (!wl->cfg.hw)
+ goto out_b;
+
+ wl->cfg.w = kmemdup(g_cfg_word, sizeof(g_cfg_word), GFP_KERNEL);
+ if (!wl->cfg.w)
+ goto out_hw;
+
+ wl->cfg.s = kmemdup(g_cfg_str, sizeof(g_cfg_str), GFP_KERNEL);
+ if (!wl->cfg.s)
+ goto out_w;
+
+ str_vals = kzalloc(sizeof(*str_vals), GFP_KERNEL);
+ if (!str_vals)
+ goto out_s;
+
+ wl->cfg.str_vals = str_vals;
+ /* store the string cfg parameters */
+ wl->cfg.s[i].id = WID_FIRMWARE_VERSION;
+ wl->cfg.s[i].str = str_vals->firmware_version;
+ i++;
+ wl->cfg.s[i].id = WID_MAC_ADDR;
+ wl->cfg.s[i].str = str_vals->mac_address;
+ i++;
+ wl->cfg.s[i].id = WID_ASSOC_RES_INFO;
+ wl->cfg.s[i].str = str_vals->assoc_rsp;
+ i++;
+ wl->cfg.s[i].id = WID_NIL;
+ wl->cfg.s[i].str = NULL;
+ return 0;
+
+out_s:
+ kfree(wl->cfg.s);
+out_w:
+ kfree(wl->cfg.w);
+out_hw:
+ kfree(wl->cfg.hw);
+out_b:
+ kfree(wl->cfg.b);
+ return -ENOMEM;
}
-int wilc_wlan_cfg_init(void)
+void wilc_wlan_cfg_deinit(struct wilc *wl)
{
- memset((void *)&g_mac, 0, sizeof(struct wilc_mac_cfg));
- return 1;
+ kfree(wl->cfg.b);
+ kfree(wl->cfg.hw);
+ kfree(wl->cfg.w);
+ kfree(wl->cfg.s);
+ kfree(wl->cfg.str_vals);
}
diff --git a/drivers/staging/wilc1000/wilc_wlan_cfg.h b/drivers/staging/wilc1000/wilc_wlan_cfg.h
index 0c649d1f6f11..e5ca6cea0682 100644
--- a/drivers/staging/wilc1000/wilc_wlan_cfg.h
+++ b/drivers/staging/wilc1000/wilc_wlan_cfg.h
@@ -9,7 +9,7 @@
struct wilc_cfg_byte {
u16 id;
- u16 val;
+ u8 val;
};
struct wilc_cfg_hword {
@@ -27,12 +27,28 @@ struct wilc_cfg_str {
u8 *str;
};
+struct wilc_cfg_str_vals {
+ u8 mac_address[7];
+ u8 firmware_version[129];
+ u8 assoc_rsp[256];
+};
+
+struct wilc_cfg {
+ struct wilc_cfg_byte *b;
+ struct wilc_cfg_hword *hw;
+ struct wilc_cfg_word *w;
+ struct wilc_cfg_str *s;
+ struct wilc_cfg_str_vals *str_vals;
+};
+
struct wilc;
int wilc_wlan_cfg_set_wid(u8 *frame, u32 offset, u16 id, u8 *buf, int size);
int wilc_wlan_cfg_get_wid(u8 *frame, u32 offset, u16 id);
-int wilc_wlan_cfg_get_wid_value(u16 wid, u8 *buffer, u32 buffer_size);
-int wilc_wlan_cfg_indicate_rx(struct wilc *wilc, u8 *frame, int size,
- struct wilc_cfg_rsp *rsp);
-int wilc_wlan_cfg_init(void);
+int wilc_wlan_cfg_get_wid_value(struct wilc *wl, u16 wid, u8 *buffer,
+ u32 buffer_size);
+void wilc_wlan_cfg_indicate_rx(struct wilc *wilc, u8 *frame, int size,
+ struct wilc_cfg_rsp *rsp);
+int wilc_wlan_cfg_init(struct wilc *wl);
+void wilc_wlan_cfg_deinit(struct wilc *wl);
#endif
diff --git a/drivers/staging/wilc1000/wilc_wlan_if.h b/drivers/staging/wilc1000/wilc_wlan_if.h
index b81a73b9bd67..ce2066b74287 100644
--- a/drivers/staging/wilc1000/wilc_wlan_if.h
+++ b/drivers/staging/wilc1000/wilc_wlan_if.h
@@ -204,10 +204,6 @@ enum wid_type {
WID_STR = 3,
WID_BIN_DATA = 4,
WID_BIN = 5,
- WID_IP = 6,
- WID_ADR = 7,
- WID_UNDEF = 8,
- WID_TYPE_FORCE_32BIT = 0xFFFFFFFF
};
struct wid {
diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c
index d4cf09b11e33..47f2ee926a77 100644
--- a/drivers/staging/wlan-ng/cfg80211.c
+++ b/drivers/staging/wlan-ng/cfg80211.c
@@ -76,7 +76,7 @@ static int prism2_domibset_uint32(struct wlandevice *wlandev, u32 did, u32 data)
struct p80211item_uint32 *mibitem =
(struct p80211item_uint32 *)&msg.mibattribute.data;
- msg.msgcode = DIDmsg_dot11req_mibset;
+ msg.msgcode = DIDMSG_DOT11REQ_MIBSET;
mibitem->did = did;
mibitem->data = data;
@@ -90,7 +90,7 @@ static int prism2_domibset_pstr32(struct wlandevice *wlandev,
struct p80211item_pstr32 *mibitem =
(struct p80211item_pstr32 *)&msg.mibattribute.data;
- msg.msgcode = DIDmsg_dot11req_mibset;
+ msg.msgcode = DIDMSG_DOT11REQ_MIBSET;
mibitem->did = did;
mibitem->data.len = len;
memcpy(mibitem->data.data, data, len);
@@ -129,7 +129,7 @@ static int prism2_change_virtual_intf(struct wiphy *wiphy,
/* Set Operation mode to the PORT TYPE RID */
result = prism2_domibset_uint32(wlandev,
- DIDmib_p2_p2Static_p2CnfPortType,
+ DIDMIB_P2_STATIC_CNFPORTTYPE,
data);
if (result)
@@ -158,12 +158,12 @@ static int prism2_add_key(struct wiphy *wiphy, struct net_device *dev,
}
if (prism2_domibset_uint32(wlandev,
- DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID,
+ DIDMIB_DOT11SMT_PRIVACYTABLE_WEPDEFAULTKEYID,
key_index))
return -EFAULT;
/* send key to driver */
- did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_key(key_index + 1);
+ did = didmib_dot11smt_wepdefaultkeystable_key(key_index + 1);
if (prism2_domibset_pstr32(wlandev, did, params->key_len, params->key))
return -EFAULT;
@@ -216,7 +216,7 @@ static int prism2_del_key(struct wiphy *wiphy, struct net_device *dev,
return -EINVAL;
/* send key to driver */
- did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_key(key_index + 1);
+ did = didmib_dot11smt_wepdefaultkeystable_key(key_index + 1);
result = prism2_domibset_pstr32(wlandev, did, 13, "0000000000000");
if (result)
@@ -234,7 +234,7 @@ static int prism2_set_default_key(struct wiphy *wiphy, struct net_device *dev,
int result = 0;
result = prism2_domibset_uint32(wlandev,
- DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID,
+ DIDMIB_DOT11SMT_PRIVACYTABLE_WEPDEFAULTKEYID,
key_index);
if (result)
@@ -256,7 +256,7 @@ static int prism2_get_station(struct wiphy *wiphy, struct net_device *dev,
return -EOPNOTSUPP;
/* build request message */
- quality.msgcode = DIDmsg_lnxreq_commsquality;
+ quality.msgcode = DIDMSG_LNXREQ_COMMSQUALITY;
quality.dbm.data = P80211ENUM_truth_true;
quality.dbm.status = P80211ENUM_msgitem_status_data_ok;
@@ -311,7 +311,7 @@ static int prism2_scan(struct wiphy *wiphy,
priv->scan_request = request;
memset(&msg1, 0x00, sizeof(msg1));
- msg1.msgcode = DIDmsg_dot11req_scan;
+ msg1.msgcode = DIDMSG_DOT11REQ_SCAN;
msg1.bsstype.data = P80211ENUM_bsstype_any;
memset(&msg1.bssid.data.data, 0xFF, sizeof(msg1.bssid.data.data));
@@ -350,7 +350,7 @@ static int prism2_scan(struct wiphy *wiphy,
int freq;
memset(&msg2, 0, sizeof(msg2));
- msg2.msgcode = DIDmsg_dot11req_scan_results;
+ msg2.msgcode = DIDMSG_DOT11REQ_SCAN_RESULTS;
msg2.bssindex.data = i;
result = p80211req_dorequest(wlandev, (u8 *)&msg2);
@@ -410,7 +410,7 @@ static int prism2_set_wiphy_params(struct wiphy *wiphy, u32 changed)
data = wiphy->rts_threshold;
result = prism2_domibset_uint32(wlandev,
- DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold,
+ DIDMIB_DOT11MAC_OPERATIONTABLE_RTSTHRESHOLD,
data);
if (result) {
err = -EFAULT;
@@ -425,7 +425,7 @@ static int prism2_set_wiphy_params(struct wiphy *wiphy, u32 changed)
data = wiphy->frag_threshold;
result = prism2_domibset_uint32(wlandev,
- DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold,
+ DIDMIB_DOT11MAC_OPERATIONTABLE_FRAGMENTATIONTHRESHOLD,
data);
if (result) {
err = -EFAULT;
@@ -455,7 +455,7 @@ static int prism2_connect(struct wiphy *wiphy, struct net_device *dev,
if (channel) {
chan = ieee80211_frequency_to_channel(channel->center_freq);
result = prism2_domibset_uint32(wlandev,
- DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel,
+ DIDMIB_DOT11PHY_DSSSTABLE_CURRENTCHANNEL,
chan);
if (result)
goto exit;
@@ -482,13 +482,13 @@ static int prism2_connect(struct wiphy *wiphy, struct net_device *dev,
}
result = prism2_domibset_uint32(wlandev,
- DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID,
+ DIDMIB_DOT11SMT_PRIVACYTABLE_WEPDEFAULTKEYID,
sme->key_idx);
if (result)
goto exit;
/* send key to driver */
- did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_key(
+ did = didmib_dot11smt_wepdefaultkeystable_key(
sme->key_idx + 1);
result = prism2_domibset_pstr32(wlandev,
did, sme->key_len,
@@ -502,13 +502,13 @@ static int prism2_connect(struct wiphy *wiphy, struct net_device *dev,
* seems reasonable anyways
*/
result = prism2_domibset_uint32(wlandev,
- DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked,
+ DIDMIB_DOT11SMT_PRIVACYTABLE_PRIVACYINVOKED,
P80211ENUM_truth_true);
if (result)
goto exit;
result = prism2_domibset_uint32(wlandev,
- DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted,
+ DIDMIB_DOT11SMT_PRIVACYTABLE_EXCLUDEUNENCRYPTED,
P80211ENUM_truth_true);
if (result)
goto exit;
@@ -518,13 +518,13 @@ static int prism2_connect(struct wiphy *wiphy, struct net_device *dev,
* and exclude unencrypted
*/
result = prism2_domibset_uint32(wlandev,
- DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked,
+ DIDMIB_DOT11SMT_PRIVACYTABLE_PRIVACYINVOKED,
P80211ENUM_truth_false);
if (result)
goto exit;
result = prism2_domibset_uint32(wlandev,
- DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted,
+ DIDMIB_DOT11SMT_PRIVACYTABLE_EXCLUDEUNENCRYPTED,
P80211ENUM_truth_false);
if (result)
goto exit;
@@ -533,7 +533,7 @@ static int prism2_connect(struct wiphy *wiphy, struct net_device *dev,
/* Now do the actual join. Note there is no way that I can
* see to request a specific bssid
*/
- msg_join.msgcode = DIDmsg_lnxreq_autojoin;
+ msg_join.msgcode = DIDMSG_LNXREQ_AUTOJOIN;
memcpy(msg_join.ssid.data.data, sme->ssid, length);
msg_join.ssid.data.len = length;
@@ -556,7 +556,7 @@ static int prism2_disconnect(struct wiphy *wiphy, struct net_device *dev,
int err = 0;
/* Do a join, with a bogus ssid. Thats the only way I can think of */
- msg_join.msgcode = DIDmsg_lnxreq_autojoin;
+ msg_join.msgcode = DIDMSG_LNXREQ_AUTOJOIN;
memcpy(msg_join.ssid.data.data, "---", 3);
msg_join.ssid.data.len = 3;
@@ -595,7 +595,7 @@ static int prism2_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
data = MBM_TO_DBM(mbm);
result = prism2_domibset_uint32(wlandev,
- DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel,
+ DIDMIB_DOT11PHY_TXPOWERTABLE_CURRENTTXPOWERLEVEL,
data);
if (result) {
@@ -618,9 +618,8 @@ static int prism2_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
int err = 0;
mibitem = (struct p80211item_uint32 *)&msg.mibattribute.data;
- msg.msgcode = DIDmsg_dot11req_mibget;
- mibitem->did =
- DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel;
+ msg.msgcode = DIDMSG_DOT11REQ_MIBGET;
+ mibitem->did = DIDMIB_DOT11PHY_TXPOWERTABLE_CURRENTTXPOWERLEVEL;
result = p80211req_dorequest(wlandev, (u8 *)&msg);
diff --git a/drivers/staging/wlan-ng/hfa384x_usb.c b/drivers/staging/wlan-ng/hfa384x_usb.c
index 16f7dd266e3b..6261881e9bcd 100644
--- a/drivers/staging/wlan-ng/hfa384x_usb.c
+++ b/drivers/staging/wlan-ng/hfa384x_usb.c
@@ -3605,36 +3605,32 @@ static void hfa384x_usbout_callback(struct urb *urb)
prism2sta_ev_alloc(wlandev);
break;
- case -EPIPE:
- {
- struct hfa384x *hw = wlandev->priv;
+ case -EPIPE: {
+ struct hfa384x *hw = wlandev->priv;
- netdev_warn(hw->wlandev->netdev,
- "%s tx pipe stalled: requesting reset\n",
- wlandev->netdev->name);
- if (!test_and_set_bit
- (WORK_TX_HALT, &hw->usb_flags))
- schedule_work(&hw->usb_work);
- wlandev->netdev->stats.tx_errors++;
- break;
- }
+ netdev_warn(hw->wlandev->netdev,
+ "%s tx pipe stalled: requesting reset\n",
+ wlandev->netdev->name);
+ if (!test_and_set_bit(WORK_TX_HALT, &hw->usb_flags))
+ schedule_work(&hw->usb_work);
+ wlandev->netdev->stats.tx_errors++;
+ break;
+ }
case -EPROTO:
case -ETIMEDOUT:
- case -EILSEQ:
- {
- struct hfa384x *hw = wlandev->priv;
-
- if (!test_and_set_bit
- (THROTTLE_TX, &hw->usb_flags) &&
- !timer_pending(&hw->throttle)) {
- mod_timer(&hw->throttle,
- jiffies + THROTTLE_JIFFIES);
- }
- wlandev->netdev->stats.tx_errors++;
- netif_stop_queue(wlandev->netdev);
- break;
+ case -EILSEQ: {
+ struct hfa384x *hw = wlandev->priv;
+
+ if (!test_and_set_bit(THROTTLE_TX, &hw->usb_flags) &&
+ !timer_pending(&hw->throttle)) {
+ mod_timer(&hw->throttle,
+ jiffies + THROTTLE_JIFFIES);
}
+ wlandev->netdev->stats.tx_errors++;
+ netif_stop_queue(wlandev->netdev);
+ break;
+ }
case -ENOENT:
case -ESHUTDOWN:
diff --git a/drivers/staging/wlan-ng/p80211conv.c b/drivers/staging/wlan-ng/p80211conv.c
index 91debcf20646..0ff5fda81b05 100644
--- a/drivers/staging/wlan-ng/p80211conv.c
+++ b/drivers/staging/wlan-ng/p80211conv.c
@@ -430,7 +430,7 @@ int skb_p80211_to_ether(struct wlandevice *wlandev, u32 ethconv,
/* A bogus length ethfrm has been sent. */
/* Is someone trying an oflow attack? */
netdev_err(netdev, "DIXII frame too large (%ld > %d)\n",
- (long int)(payload_length -
+ (long)(payload_length -
sizeof(struct wlan_llc) -
sizeof(struct wlan_snap)), netdev->mtu);
return 1;
diff --git a/drivers/staging/wlan-ng/p80211metadef.h b/drivers/staging/wlan-ng/p80211metadef.h
index e63b4b557d0a..1b91b64c12ed 100644
--- a/drivers/staging/wlan-ng/p80211metadef.h
+++ b/drivers/staging/wlan-ng/p80211metadef.h
@@ -1,6 +1,5 @@
/* SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1) */
-/* This file is GENERATED AUTOMATICALLY. DO NOT EDIT OR MODIFY.
- * --------------------------------------------------------------------
+/* --------------------------------------------------------------------
*
* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
* --------------------------------------------------------------------
@@ -48,201 +47,201 @@
#ifndef _P80211MKMETADEF_H
#define _P80211MKMETADEF_H
-#define DIDmsg_dot11req_mibget \
+#define DIDMSG_DOT11REQ_MIBGET \
(P80211DID_MKSECTION(1) | \
P80211DID_MKGROUP(1))
-#define DIDmsg_dot11req_mibget_mibattribute \
+#define DIDMSG_DOT11REQ_MIBGET_MIBATTRIBUTE \
(P80211DID_MKSECTION(1) | \
P80211DID_MKGROUP(1) | \
P80211DID_MKITEM(1) | 0x00000000)
-#define DIDmsg_dot11req_mibget_resultcode \
+#define DIDMSG_DOT11REQ_MIBGET_RESULTCODE \
(P80211DID_MKSECTION(1) | \
P80211DID_MKGROUP(1) | \
P80211DID_MKITEM(2) | 0x00000000)
-#define DIDmsg_dot11req_mibset \
+#define DIDMSG_DOT11REQ_MIBSET \
(P80211DID_MKSECTION(1) | \
P80211DID_MKGROUP(2))
-#define DIDmsg_dot11req_mibset_mibattribute \
+#define DIDMSG_DOT11REQ_MIBSET_MIBATTRIBUTE \
(P80211DID_MKSECTION(1) | \
P80211DID_MKGROUP(2) | \
P80211DID_MKITEM(1) | 0x00000000)
-#define DIDmsg_dot11req_mibset_resultcode \
+#define DIDMSG_DOT11REQ_MIBSET_RESULTCODE \
(P80211DID_MKSECTION(1) | \
P80211DID_MKGROUP(2) | \
P80211DID_MKITEM(2) | 0x00000000)
-#define DIDmsg_dot11req_scan \
+#define DIDMSG_DOT11REQ_SCAN \
(P80211DID_MKSECTION(1) | \
P80211DID_MKGROUP(4))
-#define DIDmsg_dot11req_scan_results \
+#define DIDMSG_DOT11REQ_SCAN_RESULTS \
(P80211DID_MKSECTION(1) | \
P80211DID_MKGROUP(5))
-#define DIDmsg_dot11req_start \
+#define DIDMSG_DOT11REQ_START \
(P80211DID_MKSECTION(1) | \
P80211DID_MKGROUP(13))
-#define DIDmsg_dot11ind_authenticate \
+#define DIDMSG_DOT11IND_AUTHENTICATE \
(P80211DID_MKSECTION(2) | \
P80211DID_MKGROUP(1))
-#define DIDmsg_dot11ind_associate \
+#define DIDMSG_DOT11IND_ASSOCIATE \
(P80211DID_MKSECTION(2) | \
P80211DID_MKGROUP(3))
-#define DIDmsg_lnxreq_ifstate \
+#define DIDMSG_LNXREQ_IFSTATE \
(P80211DID_MKSECTION(3) | \
P80211DID_MKGROUP(1))
-#define DIDmsg_lnxreq_wlansniff \
+#define DIDMSG_LNXREQ_WLANSNIFF \
(P80211DID_MKSECTION(3) | \
P80211DID_MKGROUP(2))
-#define DIDmsg_lnxreq_hostwep \
+#define DIDMSG_LNXREQ_HOSTWEP \
(P80211DID_MKSECTION(3) | \
P80211DID_MKGROUP(3))
-#define DIDmsg_lnxreq_commsquality \
+#define DIDMSG_LNXREQ_COMMSQUALITY \
(P80211DID_MKSECTION(3) | \
P80211DID_MKGROUP(4))
-#define DIDmsg_lnxreq_autojoin \
+#define DIDMSG_LNXREQ_AUTOJOIN \
(P80211DID_MKSECTION(3) | \
P80211DID_MKGROUP(5))
-#define DIDmsg_p2req_readpda \
+#define DIDMSG_P2REQ_READPDA \
(P80211DID_MKSECTION(5) | \
P80211DID_MKGROUP(2))
-#define DIDmsg_p2req_readpda_pda \
+#define DIDMSG_P2REQ_READPDA_PDA \
(P80211DID_MKSECTION(5) | \
P80211DID_MKGROUP(2) | \
P80211DID_MKITEM(1) | 0x00000000)
-#define DIDmsg_p2req_readpda_resultcode \
+#define DIDMSG_P2REQ_READPDA_RESULTCODE \
(P80211DID_MKSECTION(5) | \
P80211DID_MKGROUP(2) | \
P80211DID_MKITEM(2) | 0x00000000)
-#define DIDmsg_p2req_ramdl_state \
+#define DIDMSG_P2REQ_RAMDL_STATE \
(P80211DID_MKSECTION(5) | \
P80211DID_MKGROUP(11))
-#define DIDmsg_p2req_ramdl_state_enable \
+#define DIDMSG_P2REQ_RAMDL_STATE_ENABLE \
(P80211DID_MKSECTION(5) | \
P80211DID_MKGROUP(11) | \
P80211DID_MKITEM(1) | 0x00000000)
-#define DIDmsg_p2req_ramdl_state_exeaddr \
+#define DIDMSG_P2REQ_RAMDL_STATE_EXEADDR \
(P80211DID_MKSECTION(5) | \
P80211DID_MKGROUP(11) | \
P80211DID_MKITEM(2) | 0x00000000)
-#define DIDmsg_p2req_ramdl_state_resultcode \
+#define DIDMSG_P2REQ_RAMDL_STATE_RESULTCODE \
(P80211DID_MKSECTION(5) | \
P80211DID_MKGROUP(11) | \
P80211DID_MKITEM(3) | 0x00000000)
-#define DIDmsg_p2req_ramdl_write \
+#define DIDMSG_P2REQ_RAMDL_WRITE \
(P80211DID_MKSECTION(5) | \
P80211DID_MKGROUP(12))
-#define DIDmsg_p2req_ramdl_write_addr \
+#define DIDMSG_P2REQ_RAMDL_WRITE_ADDR \
(P80211DID_MKSECTION(5) | \
P80211DID_MKGROUP(12) | \
P80211DID_MKITEM(1) | 0x00000000)
-#define DIDmsg_p2req_ramdl_write_len \
+#define DIDMSG_P2REQ_RAMDL_WRITE_LEN \
(P80211DID_MKSECTION(5) | \
P80211DID_MKGROUP(12) | \
P80211DID_MKITEM(2) | 0x00000000)
-#define DIDmsg_p2req_ramdl_write_data \
+#define DIDMSG_P2REQ_RAMDL_WRITE_DATA \
(P80211DID_MKSECTION(5) | \
P80211DID_MKGROUP(12) | \
P80211DID_MKITEM(3) | 0x00000000)
-#define DIDmsg_p2req_ramdl_write_resultcode \
+#define DIDMSG_P2REQ_RAMDL_WRITE_RESULTCODE \
(P80211DID_MKSECTION(5) | \
P80211DID_MKGROUP(12) | \
P80211DID_MKITEM(4) | 0x00000000)
-#define DIDmsg_p2req_flashdl_state \
+#define DIDMSG_P2REQ_FLASHDL_STATE \
(P80211DID_MKSECTION(5) | \
P80211DID_MKGROUP(13))
-#define DIDmsg_p2req_flashdl_write \
+#define DIDMSG_P2REQ_FLASHDL_WRITE \
(P80211DID_MKSECTION(5) | \
P80211DID_MKGROUP(14))
-#define DIDmib_cat_dot11smt \
+#define DIDMIB_CAT_DOT11SMT \
P80211DID_MKSECTION(1)
-#define DIDmib_dot11smt_dot11WEPDefaultKeysTable \
+#define DIDMIB_DOT11SMT_WEPDEFAULTKEYSTABLE \
(P80211DID_MKSECTION(1) | \
P80211DID_MKGROUP(4))
-#define DIDmib_dot11smt_dot11WEPDefaultKeysTable_key(_i) \
- (DIDmib_dot11smt_dot11WEPDefaultKeysTable | \
+#define didmib_dot11smt_wepdefaultkeystable_key(_i) \
+ (DIDMIB_DOT11SMT_WEPDEFAULTKEYSTABLE | \
P80211DID_MKITEM(_i) | 0x0c000000)
-#define DIDmib_dot11smt_dot11PrivacyTable \
+#define DIDMIB_DOT11SMT_PRIVACYTABLE \
(P80211DID_MKSECTION(1) | \
P80211DID_MKGROUP(6))
-#define DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked \
+#define DIDMIB_DOT11SMT_PRIVACYTABLE_PRIVACYINVOKED \
(P80211DID_MKSECTION(1) | \
P80211DID_MKGROUP(6) | \
P80211DID_MKITEM(1) | 0x18000000)
-#define DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID \
+#define DIDMIB_DOT11SMT_PRIVACYTABLE_WEPDEFAULTKEYID \
(P80211DID_MKSECTION(1) | \
P80211DID_MKGROUP(6) | \
P80211DID_MKITEM(2) | 0x18000000)
-#define DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted \
+#define DIDMIB_DOT11SMT_PRIVACYTABLE_EXCLUDEUNENCRYPTED \
(P80211DID_MKSECTION(1) | \
P80211DID_MKGROUP(6) | \
P80211DID_MKITEM(4) | 0x18000000)
-#define DIDmib_dot11mac_dot11OperationTable \
+#define DIDMIB_DOT11MAC_OPERATIONTABLE \
(P80211DID_MKSECTION(2) | \
P80211DID_MKGROUP(1))
-#define DIDmib_dot11mac_dot11OperationTable_dot11MACAddress \
+#define DIDMIB_DOT11MAC_OPERATIONTABLE_MACADDRESS \
(P80211DID_MKSECTION(2) | \
P80211DID_MKGROUP(1) | \
P80211DID_MKITEM(1) | 0x18000000)
-#define DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold \
+#define DIDMIB_DOT11MAC_OPERATIONTABLE_RTSTHRESHOLD \
(P80211DID_MKSECTION(2) | \
P80211DID_MKGROUP(1) | \
P80211DID_MKITEM(2) | 0x18000000)
-#define DIDmib_dot11mac_dot11OperationTable_dot11ShortRetryLimit \
+#define DIDMIB_DOT11MAC_OPERATIONTABLE_SHORTRETRYLIMIT \
(P80211DID_MKSECTION(2) | \
P80211DID_MKGROUP(1) | \
P80211DID_MKITEM(3) | 0x10000000)
-#define DIDmib_dot11mac_dot11OperationTable_dot11LongRetryLimit \
+#define DIDMIB_DOT11MAC_OPERATIONTABLE_LONGRETRYLIMIT \
(P80211DID_MKSECTION(2) | \
P80211DID_MKGROUP(1) | \
P80211DID_MKITEM(4) | 0x10000000)
-#define DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold \
+#define DIDMIB_DOT11MAC_OPERATIONTABLE_FRAGMENTATIONTHRESHOLD \
(P80211DID_MKSECTION(2) | \
P80211DID_MKGROUP(1) | \
P80211DID_MKITEM(5) | 0x18000000)
-#define DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime \
+#define DIDMIB_DOT11MAC_OPERATIONTABLE_MAXTRANSMITMSDULIFETIME \
(P80211DID_MKSECTION(2) | \
P80211DID_MKGROUP(1) | \
P80211DID_MKITEM(6) | 0x10000000)
-#define DIDmib_cat_dot11phy \
+#define DIDMIB_CAT_DOT11PHY \
P80211DID_MKSECTION(3)
-#define DIDmib_dot11phy_dot11PhyOperationTable \
+#define DIDMIB_DOT11PHY_OPERATIONTABLE \
(P80211DID_MKSECTION(3) | \
P80211DID_MKGROUP(1))
-#define DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel \
+#define DIDMIB_DOT11PHY_TXPOWERTABLE_CURRENTTXPOWERLEVEL \
(P80211DID_MKSECTION(3) | \
P80211DID_MKGROUP(3) | \
P80211DID_MKITEM(10) | 0x18000000)
-#define DIDmib_dot11phy_dot11PhyDSSSTable \
+#define DIDMIB_DOT11PHY_DSSSTABLE \
(P80211DID_MKSECTION(3) | \
P80211DID_MKGROUP(5))
-#define DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel \
+#define DIDMIB_DOT11PHY_DSSSTABLE_CURRENTCHANNEL \
(P80211DID_MKSECTION(3) | \
P80211DID_MKGROUP(5) | \
P80211DID_MKITEM(1) | 0x10000000)
-#define DIDmib_cat_lnx \
+#define DIDMIB_CAT_LNX \
P80211DID_MKSECTION(4)
-#define DIDmib_lnx_lnxConfigTable \
+#define DIDMIB_LNX_CONFIGTABLE \
(P80211DID_MKSECTION(4) | \
P80211DID_MKGROUP(1))
-#define DIDmib_lnx_lnxConfigTable_lnxRSNAIE \
+#define DIDMIB_LNX_CONFIGTABLE_RSNAIE \
(P80211DID_MKSECTION(4) | \
P80211DID_MKGROUP(1) | \
P80211DID_MKITEM(1) | 0x18000000)
-#define DIDmib_cat_p2 \
+#define DIDMIB_CAT_P2 \
P80211DID_MKSECTION(5)
-#define DIDmib_p2_p2Static \
+#define DIDMIB_P2_STATIC \
(P80211DID_MKSECTION(5) | \
P80211DID_MKGROUP(2))
-#define DIDmib_p2_p2Static_p2CnfPortType \
+#define DIDMIB_P2_STATIC_CNFPORTTYPE \
(P80211DID_MKSECTION(5) | \
P80211DID_MKGROUP(2) | \
P80211DID_MKITEM(1) | 0x18000000)
-#define DIDmib_p2_p2NIC_p2PRISupRange \
+#define DIDMIB_P2_NIC_PRISUPRANGE \
(P80211DID_MKSECTION(5) | \
P80211DID_MKGROUP(5) | \
P80211DID_MKITEM(6) | 0x10000000)
-#define DIDmib_p2_p2MAC \
+#define DIDMIB_P2_MAC \
(P80211DID_MKSECTION(5) | \
P80211DID_MKGROUP(6))
-#define DIDmib_p2_p2MAC_p2CurrentTxRate \
+#define DIDMIB_P2_MAC_CURRENTTXRATE \
(P80211DID_MKSECTION(5) | \
P80211DID_MKGROUP(6) | \
P80211DID_MKITEM(12) | 0x10000000)
diff --git a/drivers/staging/wlan-ng/p80211metastruct.h b/drivers/staging/wlan-ng/p80211metastruct.h
index 5602ec606074..4adc64580185 100644
--- a/drivers/staging/wlan-ng/p80211metastruct.h
+++ b/drivers/staging/wlan-ng/p80211metastruct.h
@@ -1,6 +1,5 @@
/* SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1) */
-/* This file is GENERATED AUTOMATICALLY. DO NOT EDIT OR MODIFY.
- * --------------------------------------------------------------------
+/* --------------------------------------------------------------------
*
* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
* --------------------------------------------------------------------
diff --git a/drivers/staging/wlan-ng/p80211netdev.c b/drivers/staging/wlan-ng/p80211netdev.c
index 8258cb5a335d..a70fb84f38f1 100644
--- a/drivers/staging/wlan-ng/p80211netdev.c
+++ b/drivers/staging/wlan-ng/p80211netdev.c
@@ -638,25 +638,25 @@ static int p80211knetdev_set_mac_address(struct net_device *dev, void *addr)
/* Set up a dot11req_mibset */
memset(&dot11req, 0, sizeof(dot11req));
- dot11req.msgcode = DIDmsg_dot11req_mibset;
+ dot11req.msgcode = DIDMSG_DOT11REQ_MIBSET;
dot11req.msglen = sizeof(dot11req);
memcpy(dot11req.devname,
((struct wlandevice *)dev->ml_priv)->name,
WLAN_DEVNAMELEN_MAX - 1);
/* Set up the mibattribute argument */
- mibattr->did = DIDmsg_dot11req_mibset_mibattribute;
+ mibattr->did = DIDMSG_DOT11REQ_MIBSET_MIBATTRIBUTE;
mibattr->status = P80211ENUM_msgitem_status_data_ok;
mibattr->len = sizeof(mibattr->data);
- macaddr->did = DIDmib_dot11mac_dot11OperationTable_dot11MACAddress;
+ macaddr->did = DIDMIB_DOT11MAC_OPERATIONTABLE_MACADDRESS;
macaddr->status = P80211ENUM_msgitem_status_data_ok;
macaddr->len = sizeof(macaddr->data);
macaddr->data.len = ETH_ALEN;
memcpy(&macaddr->data.data, new_addr->sa_data, ETH_ALEN);
/* Set up the resultcode argument */
- resultcode->did = DIDmsg_dot11req_mibset_resultcode;
+ resultcode->did = DIDMSG_DOT11REQ_MIBSET_RESULTCODE;
resultcode->status = P80211ENUM_msgitem_status_no_value;
resultcode->len = sizeof(resultcode->data);
resultcode->data = 0;
@@ -927,10 +927,6 @@ static int p80211_rx_typedrop(struct wlandevice *wlandev, u16 fc)
/* Classify frame, increment counter */
ftype = WLAN_GET_FC_FTYPE(fc);
fstype = WLAN_GET_FC_FSTYPE(fc);
-#if 0
- netdev_dbg(wlandev->netdev, "rx_typedrop : ftype=%d fstype=%d.\n",
- ftype, fstype);
-#endif
switch (ftype) {
case WLAN_FTYPE_MGMT:
if ((wlandev->netdev->flags & IFF_PROMISC) ||
diff --git a/drivers/staging/wlan-ng/p80211req.c b/drivers/staging/wlan-ng/p80211req.c
index c36d01469afc..9f5c1267d829 100644
--- a/drivers/staging/wlan-ng/p80211req.c
+++ b/drivers/staging/wlan-ng/p80211req.c
@@ -117,7 +117,7 @@ int p80211req_dorequest(struct wlandevice *wlandev, u8 *msgbuf)
/* Check to make sure the MSD is running */
if (!((wlandev->msdstate == WLAN_MSD_HWPRESENT &&
- msg->msgcode == DIDmsg_lnxreq_ifstate) ||
+ msg->msgcode == DIDMSG_LNXREQ_IFSTATE) ||
wlandev->msdstate == WLAN_MSD_RUNNING ||
wlandev->msdstate == WLAN_MSD_FWLOAD)) {
return -ENODEV;
@@ -125,7 +125,7 @@ int p80211req_dorequest(struct wlandevice *wlandev, u8 *msgbuf)
/* Check Permissions */
if (!capable(CAP_NET_ADMIN) &&
- (msg->msgcode != DIDmsg_dot11req_mibget)) {
+ (msg->msgcode != DIDMSG_DOT11REQ_MIBGET)) {
netdev_err(wlandev->netdev,
"%s: only dot11req_mibget allowed for non-root.\n",
wlandev->name);
@@ -172,7 +172,7 @@ static void p80211req_handlemsg(struct wlandevice *wlandev,
struct p80211msg *msg)
{
switch (msg->msgcode) {
- case DIDmsg_lnxreq_hostwep:{
+ case DIDMSG_LNXREQ_HOSTWEP: {
struct p80211msg_lnxreq_hostwep *req =
(struct p80211msg_lnxreq_hostwep *)msg;
wlandev->hostwep &=
@@ -182,15 +182,15 @@ static void p80211req_handlemsg(struct wlandevice *wlandev,
if (req->encrypt.data == P80211ENUM_truth_true)
wlandev->hostwep |= HOSTWEP_ENCRYPT;
- break;
+ break;
}
- case DIDmsg_dot11req_mibget:
- case DIDmsg_dot11req_mibset:{
- int isget = (msg->msgcode == DIDmsg_dot11req_mibget);
+ case DIDMSG_DOT11REQ_MIBGET:
+ case DIDMSG_DOT11REQ_MIBSET: {
+ int isget = (msg->msgcode == DIDMSG_DOT11REQ_MIBGET);
struct p80211msg_dot11req_mibget *mib_msg =
(struct p80211msg_dot11req_mibget *)msg;
p80211req_mibset_mibget(wlandev, mib_msg, isget);
- break;
+ break;
}
} /* switch msg->msgcode */
}
@@ -205,17 +205,17 @@ static void p80211req_mibset_mibget(struct wlandevice *wlandev,
u8 *key = mibitem->data + sizeof(struct p80211pstrd);
switch (mibitem->did) {
- case DIDmib_dot11smt_dot11WEPDefaultKeysTable_key(1):
- case DIDmib_dot11smt_dot11WEPDefaultKeysTable_key(2):
- case DIDmib_dot11smt_dot11WEPDefaultKeysTable_key(3):
- case DIDmib_dot11smt_dot11WEPDefaultKeysTable_key(4):
+ case didmib_dot11smt_wepdefaultkeystable_key(1):
+ case didmib_dot11smt_wepdefaultkeystable_key(2):
+ case didmib_dot11smt_wepdefaultkeystable_key(3):
+ case didmib_dot11smt_wepdefaultkeystable_key(4):
if (!isget)
wep_change_key(wlandev,
P80211DID_ITEM(mibitem->did) - 1,
key, pstr->len);
break;
- case DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID:{
+ case DIDMIB_DOT11SMT_PRIVACYTABLE_WEPDEFAULTKEYID: {
u32 *data = (u32 *)mibitem->data;
if (isget) {
@@ -224,21 +224,21 @@ static void p80211req_mibset_mibget(struct wlandevice *wlandev,
wlandev->hostwep &= ~(HOSTWEP_DEFAULTKEY_MASK);
wlandev->hostwep |= (*data & HOSTWEP_DEFAULTKEY_MASK);
}
- break;
+ break;
}
- case DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked:{
+ case DIDMIB_DOT11SMT_PRIVACYTABLE_PRIVACYINVOKED: {
u32 *data = (u32 *)mibitem->data;
p80211req_handle_action(wlandev, data, isget,
HOSTWEP_PRIVACYINVOKED);
- break;
+ break;
}
- case DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted:{
+ case DIDMIB_DOT11SMT_PRIVACYTABLE_EXCLUDEUNENCRYPTED: {
u32 *data = (u32 *)mibitem->data;
p80211req_handle_action(wlandev, data, isget,
HOSTWEP_EXCLUDEUNENCRYPTED);
- break;
+ break;
}
}
}
diff --git a/drivers/staging/wlan-ng/prism2fw.c b/drivers/staging/wlan-ng/prism2fw.c
index 4fb91294570d..f99626ca6bdc 100644
--- a/drivers/staging/wlan-ng/prism2fw.c
+++ b/drivers/staging/wlan-ng/prism2fw.c
@@ -294,17 +294,17 @@ static int prism2_fwapply(const struct ihex_binrec *rfptr,
/* read the card's PRI-SUP */
memset(&getmsg, 0, sizeof(getmsg));
- getmsg.msgcode = DIDmsg_dot11req_mibget;
+ getmsg.msgcode = DIDMSG_DOT11REQ_MIBGET;
getmsg.msglen = sizeof(getmsg);
strcpy(getmsg.devname, wlandev->name);
- getmsg.mibattribute.did = DIDmsg_dot11req_mibget_mibattribute;
+ getmsg.mibattribute.did = DIDMSG_DOT11REQ_MIBGET_MIBATTRIBUTE;
getmsg.mibattribute.status = P80211ENUM_msgitem_status_data_ok;
- getmsg.resultcode.did = DIDmsg_dot11req_mibget_resultcode;
+ getmsg.resultcode.did = DIDMSG_DOT11REQ_MIBGET_RESULTCODE;
getmsg.resultcode.status = P80211ENUM_msgitem_status_no_value;
item = (struct p80211itemd *)getmsg.mibattribute.data;
- item->did = DIDmib_p2_p2NIC_p2PRISupRange;
+ item->did = DIDMIB_P2_NIC_PRISUPRANGE;
item->status = P80211ENUM_msgitem_status_no_value;
data = (u32 *)item->data;
@@ -706,7 +706,7 @@ static int plugimage(struct imgchunk *fchunk, unsigned int nfchunks,
pr_warn("warning: Failed to find PDR for plugrec 0x%04x.\n",
s3plug[i].itemcode);
continue; /* and move on to the next PDR */
-#if 0
+
/* MSM: They swear that unless it's the MAC address,
* the serial number, or the TX calibration records,
* then there's reasonable defaults in the f/w
@@ -714,9 +714,6 @@ static int plugimage(struct imgchunk *fchunk, unsigned int nfchunks,
* should only be a warning, not fatal.
* TODO: add fatals for the PDRs mentioned above.
*/
- result = 1;
- continue;
-#endif
}
/* Validate plug len against PDR len */
@@ -790,13 +787,13 @@ static int read_cardpda(struct pda *pda, struct wlandevice *wlandev)
return -ENOMEM;
/* set up the msg */
- msg->msgcode = DIDmsg_p2req_readpda;
+ msg->msgcode = DIDMSG_P2REQ_READPDA;
msg->msglen = sizeof(msg);
strcpy(msg->devname, wlandev->name);
- msg->pda.did = DIDmsg_p2req_readpda_pda;
+ msg->pda.did = DIDMSG_P2REQ_READPDA_PDA;
msg->pda.len = HFA384x_PDA_LEN_MAX;
msg->pda.status = P80211ENUM_msgitem_status_no_value;
- msg->resultcode.did = DIDmsg_p2req_readpda_resultcode;
+ msg->resultcode.did = DIDMSG_P2REQ_READPDA_RESULTCODE;
msg->resultcode.len = sizeof(u32);
msg->resultcode.status = P80211ENUM_msgitem_status_no_value;
@@ -1024,11 +1021,11 @@ static int writeimage(struct wlandevice *wlandev, struct imgchunk *fchunk,
/* Initialize the messages */
strcpy(rstmsg->devname, wlandev->name);
- rstmsg->msgcode = DIDmsg_p2req_ramdl_state;
+ rstmsg->msgcode = DIDMSG_P2REQ_RAMDL_STATE;
rstmsg->msglen = sizeof(*rstmsg);
- rstmsg->enable.did = DIDmsg_p2req_ramdl_state_enable;
- rstmsg->exeaddr.did = DIDmsg_p2req_ramdl_state_exeaddr;
- rstmsg->resultcode.did = DIDmsg_p2req_ramdl_state_resultcode;
+ rstmsg->enable.did = DIDMSG_P2REQ_RAMDL_STATE_ENABLE;
+ rstmsg->exeaddr.did = DIDMSG_P2REQ_RAMDL_STATE_EXEADDR;
+ rstmsg->resultcode.did = DIDMSG_P2REQ_RAMDL_STATE_RESULTCODE;
rstmsg->enable.status = P80211ENUM_msgitem_status_data_ok;
rstmsg->exeaddr.status = P80211ENUM_msgitem_status_data_ok;
rstmsg->resultcode.status = P80211ENUM_msgitem_status_no_value;
@@ -1037,12 +1034,12 @@ static int writeimage(struct wlandevice *wlandev, struct imgchunk *fchunk,
rstmsg->resultcode.len = sizeof(u32);
strcpy(rwrmsg->devname, wlandev->name);
- rwrmsg->msgcode = DIDmsg_p2req_ramdl_write;
+ rwrmsg->msgcode = DIDMSG_P2REQ_RAMDL_WRITE;
rwrmsg->msglen = sizeof(*rwrmsg);
- rwrmsg->addr.did = DIDmsg_p2req_ramdl_write_addr;
- rwrmsg->len.did = DIDmsg_p2req_ramdl_write_len;
- rwrmsg->data.did = DIDmsg_p2req_ramdl_write_data;
- rwrmsg->resultcode.did = DIDmsg_p2req_ramdl_write_resultcode;
+ rwrmsg->addr.did = DIDMSG_P2REQ_RAMDL_WRITE_ADDR;
+ rwrmsg->len.did = DIDMSG_P2REQ_RAMDL_WRITE_LEN;
+ rwrmsg->data.did = DIDMSG_P2REQ_RAMDL_WRITE_DATA;
+ rwrmsg->resultcode.did = DIDMSG_P2REQ_RAMDL_WRITE_RESULTCODE;
rwrmsg->addr.status = P80211ENUM_msgitem_status_data_ok;
rwrmsg->len.status = P80211ENUM_msgitem_status_data_ok;
rwrmsg->data.status = P80211ENUM_msgitem_status_data_ok;
diff --git a/drivers/staging/wlan-ng/prism2mib.c b/drivers/staging/wlan-ng/prism2mib.c
index e88baf715cec..5c0dad42f523 100644
--- a/drivers/staging/wlan-ng/prism2mib.c
+++ b/drivers/staging/wlan-ng/prism2mib.c
@@ -148,89 +148,89 @@ static int prism2mib_priv(struct mibrec *mib,
static struct mibrec mibtab[] = {
/* dot11smt MIB's */
- {DIDmib_dot11smt_dot11WEPDefaultKeysTable_key(1),
+ {didmib_dot11smt_wepdefaultkeystable_key(1),
F_STA | F_WRITE,
HFA384x_RID_CNFWEPDEFAULTKEY0, 0, 0,
prism2mib_wepdefaultkey},
- {DIDmib_dot11smt_dot11WEPDefaultKeysTable_key(2),
+ {didmib_dot11smt_wepdefaultkeystable_key(2),
F_STA | F_WRITE,
HFA384x_RID_CNFWEPDEFAULTKEY1, 0, 0,
prism2mib_wepdefaultkey},
- {DIDmib_dot11smt_dot11WEPDefaultKeysTable_key(3),
+ {didmib_dot11smt_wepdefaultkeystable_key(3),
F_STA | F_WRITE,
HFA384x_RID_CNFWEPDEFAULTKEY2, 0, 0,
prism2mib_wepdefaultkey},
- {DIDmib_dot11smt_dot11WEPDefaultKeysTable_key(4),
+ {didmib_dot11smt_wepdefaultkeystable_key(4),
F_STA | F_WRITE,
HFA384x_RID_CNFWEPDEFAULTKEY3, 0, 0,
prism2mib_wepdefaultkey},
- {DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked,
+ {DIDMIB_DOT11SMT_PRIVACYTABLE_PRIVACYINVOKED,
F_STA | F_READ | F_WRITE,
HFA384x_RID_CNFWEPFLAGS, HFA384x_WEPFLAGS_PRIVINVOKED, 0,
prism2mib_privacyinvoked},
- {DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID,
+ {DIDMIB_DOT11SMT_PRIVACYTABLE_WEPDEFAULTKEYID,
F_STA | F_READ | F_WRITE,
HFA384x_RID_CNFWEPDEFAULTKEYID, 0, 0,
prism2mib_uint32},
- {DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted,
+ {DIDMIB_DOT11SMT_PRIVACYTABLE_EXCLUDEUNENCRYPTED,
F_STA | F_READ | F_WRITE,
HFA384x_RID_CNFWEPFLAGS, HFA384x_WEPFLAGS_EXCLUDE, 0,
prism2mib_excludeunencrypted},
/* dot11mac MIB's */
- {DIDmib_dot11mac_dot11OperationTable_dot11MACAddress,
+ {DIDMIB_DOT11MAC_OPERATIONTABLE_MACADDRESS,
F_STA | F_READ | F_WRITE,
HFA384x_RID_CNFOWNMACADDR, HFA384x_RID_CNFOWNMACADDR_LEN, 0,
prism2mib_bytearea2pstr},
- {DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold,
+ {DIDMIB_DOT11MAC_OPERATIONTABLE_RTSTHRESHOLD,
F_STA | F_READ | F_WRITE,
HFA384x_RID_RTSTHRESH, 0, 0,
prism2mib_uint32},
- {DIDmib_dot11mac_dot11OperationTable_dot11ShortRetryLimit,
+ {DIDMIB_DOT11MAC_OPERATIONTABLE_SHORTRETRYLIMIT,
F_STA | F_READ,
HFA384x_RID_SHORTRETRYLIMIT, 0, 0,
prism2mib_uint32},
- {DIDmib_dot11mac_dot11OperationTable_dot11LongRetryLimit,
+ {DIDMIB_DOT11MAC_OPERATIONTABLE_LONGRETRYLIMIT,
F_STA | F_READ,
HFA384x_RID_LONGRETRYLIMIT, 0, 0,
prism2mib_uint32},
- {DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold,
+ {DIDMIB_DOT11MAC_OPERATIONTABLE_FRAGMENTATIONTHRESHOLD,
F_STA | F_READ | F_WRITE,
HFA384x_RID_FRAGTHRESH, 0, 0,
prism2mib_fragmentationthreshold},
- {DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime,
+ {DIDMIB_DOT11MAC_OPERATIONTABLE_MAXTRANSMITMSDULIFETIME,
F_STA | F_READ,
HFA384x_RID_MAXTXLIFETIME, 0, 0,
prism2mib_uint32},
/* dot11phy MIB's */
- {DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel,
+ {DIDMIB_DOT11PHY_DSSSTABLE_CURRENTCHANNEL,
F_STA | F_READ,
HFA384x_RID_CURRENTCHANNEL, 0, 0,
prism2mib_uint32},
- {DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel,
+ {DIDMIB_DOT11PHY_TXPOWERTABLE_CURRENTTXPOWERLEVEL,
F_STA | F_READ | F_WRITE,
HFA384x_RID_TXPOWERMAX, 0, 0,
prism2mib_uint32},
/* p2Static MIB's */
- {DIDmib_p2_p2Static_p2CnfPortType,
+ {DIDMIB_P2_STATIC_CNFPORTTYPE,
F_STA | F_READ | F_WRITE,
HFA384x_RID_CNFPORTTYPE, 0, 0,
prism2mib_uint32},
/* p2MAC MIB's */
- {DIDmib_p2_p2MAC_p2CurrentTxRate,
+ {DIDMIB_P2_MAC_CURRENTTXRATE,
F_STA | F_READ,
HFA384x_RID_CURRENTTXRATE, 0, 0,
prism2mib_uint32},
/* And finally, lnx mibs */
- {DIDmib_lnx_lnxConfigTable_lnxRSNAIE,
+ {DIDMIB_LNX_CONFIGTABLE_RSNAIE,
F_STA | F_READ | F_WRITE,
HFA384x_RID_CNFWPADATA, 0, 0,
prism2mib_priv},
@@ -301,7 +301,7 @@ int prism2mgmt_mibset_mibget(struct wlandevice *wlandev, void *msgp)
** this is a "mibset" so make make sure that the MIB may be written.
*/
- isget = (msg->msgcode == DIDmsg_dot11req_mibget);
+ isget = (msg->msgcode == DIDMSG_DOT11REQ_MIBGET);
if (isget) {
if (!(mib->flag & F_READ)) {
@@ -707,27 +707,27 @@ static int prism2mib_priv(struct mibrec *mib,
struct p80211pstrd *pstr = data;
switch (mib->did) {
- case DIDmib_lnx_lnxConfigTable_lnxRSNAIE:{
- struct hfa384x_wpa_data wpa;
+ case DIDMIB_LNX_CONFIGTABLE_RSNAIE: {
+ struct hfa384x_wpa_data wpa;
- if (isget) {
- hfa384x_drvr_getconfig(hw,
- HFA384x_RID_CNFWPADATA,
- (u8 *)&wpa,
- sizeof(wpa));
- pstr->len = le16_to_cpu(wpa.datalen);
- memcpy(pstr->data, wpa.data, pstr->len);
- } else {
- wpa.datalen = cpu_to_le16(pstr->len);
- memcpy(wpa.data, pstr->data, pstr->len);
-
- hfa384x_drvr_setconfig(hw,
- HFA384x_RID_CNFWPADATA,
- (u8 *)&wpa,
- sizeof(wpa));
- }
- break;
+ if (isget) {
+ hfa384x_drvr_getconfig(hw,
+ HFA384x_RID_CNFWPADATA,
+ (u8 *)&wpa,
+ sizeof(wpa));
+ pstr->len = le16_to_cpu(wpa.datalen);
+ memcpy(pstr->data, wpa.data, pstr->len);
+ } else {
+ wpa.datalen = cpu_to_le16(pstr->len);
+ memcpy(wpa.data, pstr->data, pstr->len);
+
+ hfa384x_drvr_setconfig(hw,
+ HFA384x_RID_CNFWPADATA,
+ (u8 *)&wpa,
+ sizeof(wpa));
}
+ break;
+ }
default:
netdev_err(wlandev->netdev, "Unhandled DID 0x%08x\n", mib->did);
}
diff --git a/drivers/staging/wlan-ng/prism2sta.c b/drivers/staging/wlan-ng/prism2sta.c
index 914970249680..fb5441399131 100644
--- a/drivers/staging/wlan-ng/prism2sta.c
+++ b/drivers/staging/wlan-ng/prism2sta.c
@@ -288,99 +288,93 @@ static int prism2sta_mlmerequest(struct wlandevice *wlandev,
int result = 0;
switch (msg->msgcode) {
- case DIDmsg_dot11req_mibget:
+ case DIDMSG_DOT11REQ_MIBGET:
pr_debug("Received mibget request\n");
result = prism2mgmt_mibset_mibget(wlandev, msg);
break;
- case DIDmsg_dot11req_mibset:
+ case DIDMSG_DOT11REQ_MIBSET:
pr_debug("Received mibset request\n");
result = prism2mgmt_mibset_mibget(wlandev, msg);
break;
- case DIDmsg_dot11req_scan:
+ case DIDMSG_DOT11REQ_SCAN:
pr_debug("Received scan request\n");
result = prism2mgmt_scan(wlandev, msg);
break;
- case DIDmsg_dot11req_scan_results:
+ case DIDMSG_DOT11REQ_SCAN_RESULTS:
pr_debug("Received scan_results request\n");
result = prism2mgmt_scan_results(wlandev, msg);
break;
- case DIDmsg_dot11req_start:
+ case DIDMSG_DOT11REQ_START:
pr_debug("Received mlme start request\n");
result = prism2mgmt_start(wlandev, msg);
break;
/*
* Prism2 specific messages
*/
- case DIDmsg_p2req_readpda:
+ case DIDMSG_P2REQ_READPDA:
pr_debug("Received mlme readpda request\n");
result = prism2mgmt_readpda(wlandev, msg);
break;
- case DIDmsg_p2req_ramdl_state:
+ case DIDMSG_P2REQ_RAMDL_STATE:
pr_debug("Received mlme ramdl_state request\n");
result = prism2mgmt_ramdl_state(wlandev, msg);
break;
- case DIDmsg_p2req_ramdl_write:
+ case DIDMSG_P2REQ_RAMDL_WRITE:
pr_debug("Received mlme ramdl_write request\n");
result = prism2mgmt_ramdl_write(wlandev, msg);
break;
- case DIDmsg_p2req_flashdl_state:
+ case DIDMSG_P2REQ_FLASHDL_STATE:
pr_debug("Received mlme flashdl_state request\n");
result = prism2mgmt_flashdl_state(wlandev, msg);
break;
- case DIDmsg_p2req_flashdl_write:
+ case DIDMSG_P2REQ_FLASHDL_WRITE:
pr_debug("Received mlme flashdl_write request\n");
result = prism2mgmt_flashdl_write(wlandev, msg);
break;
/*
* Linux specific messages
*/
- case DIDmsg_lnxreq_hostwep:
+ case DIDMSG_LNXREQ_HOSTWEP:
break; /* ignore me. */
- case DIDmsg_lnxreq_ifstate:
- {
- struct p80211msg_lnxreq_ifstate *ifstatemsg;
-
- pr_debug("Received mlme ifstate request\n");
- ifstatemsg = (struct p80211msg_lnxreq_ifstate *)msg;
- result =
- prism2sta_ifstate(wlandev,
- ifstatemsg->ifstate.data);
- ifstatemsg->resultcode.status =
- P80211ENUM_msgitem_status_data_ok;
- ifstatemsg->resultcode.data = result;
- result = 0;
- }
+ case DIDMSG_LNXREQ_IFSTATE: {
+ struct p80211msg_lnxreq_ifstate *ifstatemsg;
+
+ pr_debug("Received mlme ifstate request\n");
+ ifstatemsg = (struct p80211msg_lnxreq_ifstate *)msg;
+ result = prism2sta_ifstate(wlandev,
+ ifstatemsg->ifstate.data);
+ ifstatemsg->resultcode.status =
+ P80211ENUM_msgitem_status_data_ok;
+ ifstatemsg->resultcode.data = result;
+ result = 0;
break;
- case DIDmsg_lnxreq_wlansniff:
+ }
+ case DIDMSG_LNXREQ_WLANSNIFF:
pr_debug("Received mlme wlansniff request\n");
result = prism2mgmt_wlansniff(wlandev, msg);
break;
- case DIDmsg_lnxreq_autojoin:
+ case DIDMSG_LNXREQ_AUTOJOIN:
pr_debug("Received mlme autojoin request\n");
result = prism2mgmt_autojoin(wlandev, msg);
break;
- case DIDmsg_lnxreq_commsquality:{
- struct p80211msg_lnxreq_commsquality *qualmsg;
+ case DIDMSG_LNXREQ_COMMSQUALITY: {
+ struct p80211msg_lnxreq_commsquality *qualmsg;
- pr_debug("Received commsquality request\n");
+ pr_debug("Received commsquality request\n");
- qualmsg = (struct p80211msg_lnxreq_commsquality *)msg;
+ qualmsg = (struct p80211msg_lnxreq_commsquality *)msg;
- qualmsg->link.status =
- P80211ENUM_msgitem_status_data_ok;
- qualmsg->level.status =
- P80211ENUM_msgitem_status_data_ok;
- qualmsg->noise.status =
- P80211ENUM_msgitem_status_data_ok;
+ qualmsg->link.status = P80211ENUM_msgitem_status_data_ok;
+ qualmsg->level.status = P80211ENUM_msgitem_status_data_ok;
+ qualmsg->noise.status = P80211ENUM_msgitem_status_data_ok;
- qualmsg->link.data = le16_to_cpu(hw->qual.cq_curr_bss);
- qualmsg->level.data =
- le16_to_cpu(hw->qual.asl_curr_bss);
- qualmsg->noise.data = le16_to_cpu(hw->qual.anl_curr_fc);
- qualmsg->txrate.data = hw->txrate;
+ qualmsg->link.data = le16_to_cpu(hw->qual.cq_curr_bss);
+ qualmsg->level.data = le16_to_cpu(hw->qual.asl_curr_bss);
+ qualmsg->noise.data = le16_to_cpu(hw->qual.anl_curr_fc);
+ qualmsg->txrate.data = hw->txrate;
- break;
- }
+ break;
+ }
default:
netdev_warn(wlandev->netdev,
"Unknown mgmt request message 0x%08x",
@@ -1949,8 +1943,8 @@ void prism2sta_commsqual_defer(struct work_struct *data)
}
/* Get the signal rate */
- msg.msgcode = DIDmsg_dot11req_mibget;
- mibitem->did = DIDmib_p2_p2MAC_p2CurrentTxRate;
+ msg.msgcode = DIDMSG_DOT11REQ_MIBGET;
+ mibitem->did = DIDMIB_P2_MAC_CURRENTTXRATE;
result = p80211req_dorequest(wlandev, (u8 *)&msg);
if (result) {
diff --git a/drivers/target/iscsi/cxgbit/cxgbit_cm.c b/drivers/target/iscsi/cxgbit/cxgbit_cm.c
index 8de16016b6de..71888b979ab5 100644
--- a/drivers/target/iscsi/cxgbit/cxgbit_cm.c
+++ b/drivers/target/iscsi/cxgbit/cxgbit_cm.c
@@ -598,9 +598,12 @@ out:
mutex_unlock(&cdev_list_lock);
}
+static void __cxgbit_free_conn(struct cxgbit_sock *csk);
+
void cxgbit_free_np(struct iscsi_np *np)
{
struct cxgbit_np *cnp = np->np_context;
+ struct cxgbit_sock *csk, *tmp;
cnp->com.state = CSK_STATE_DEAD;
if (cnp->com.cdev)
@@ -608,6 +611,13 @@ void cxgbit_free_np(struct iscsi_np *np)
else
cxgbit_free_all_np(cnp);
+ spin_lock_bh(&cnp->np_accept_lock);
+ list_for_each_entry_safe(csk, tmp, &cnp->np_accept_list, accept_node) {
+ list_del_init(&csk->accept_node);
+ __cxgbit_free_conn(csk);
+ }
+ spin_unlock_bh(&cnp->np_accept_lock);
+
np->np_context = NULL;
cxgbit_put_cnp(cnp);
}
@@ -705,9 +715,9 @@ void cxgbit_abort_conn(struct cxgbit_sock *csk)
csk->tid, 600, __func__);
}
-void cxgbit_free_conn(struct iscsi_conn *conn)
+static void __cxgbit_free_conn(struct cxgbit_sock *csk)
{
- struct cxgbit_sock *csk = conn->context;
+ struct iscsi_conn *conn = csk->conn;
bool release = false;
pr_debug("%s: state %d\n",
@@ -716,7 +726,7 @@ void cxgbit_free_conn(struct iscsi_conn *conn)
spin_lock_bh(&csk->lock);
switch (csk->com.state) {
case CSK_STATE_ESTABLISHED:
- if (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT) {
+ if (conn && (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT)) {
csk->com.state = CSK_STATE_CLOSING;
cxgbit_send_halfclose(csk);
} else {
@@ -741,6 +751,11 @@ void cxgbit_free_conn(struct iscsi_conn *conn)
cxgbit_put_csk(csk);
}
+void cxgbit_free_conn(struct iscsi_conn *conn)
+{
+ __cxgbit_free_conn(conn->context);
+}
+
static void cxgbit_set_emss(struct cxgbit_sock *csk, u16 opt)
{
csk->emss = csk->com.cdev->lldi.mtus[TCPOPT_MSS_G(opt)] -
@@ -803,6 +818,7 @@ void _cxgbit_free_csk(struct kref *kref)
spin_unlock_bh(&cdev->cskq.lock);
cxgbit_free_skb(csk);
+ cxgbit_put_cnp(csk->cnp);
cxgbit_put_cdev(cdev);
kfree(csk);
@@ -1351,6 +1367,7 @@ cxgbit_pass_accept_req(struct cxgbit_device *cdev, struct sk_buff *skb)
goto rel_skb;
}
+ cxgbit_get_cnp(cnp);
cxgbit_get_cdev(cdev);
spin_lock(&cdev->cskq.lock);
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index cc756a123fd8..c1d5a173553d 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -4355,7 +4355,7 @@ int iscsit_close_session(struct iscsi_session *sess)
transport_deregister_session(sess->se_sess);
if (sess->sess_ops->ErrorRecoveryLevel == 2)
- iscsit_free_connection_recovery_entires(sess);
+ iscsit_free_connection_recovery_entries(sess);
iscsit_free_all_ooo_cmdsns(sess);
diff --git a/drivers/target/iscsi/iscsi_target_erl0.c b/drivers/target/iscsi/iscsi_target_erl0.c
index 718fe9a1b709..1193cf884a28 100644
--- a/drivers/target/iscsi/iscsi_target_erl0.c
+++ b/drivers/target/iscsi/iscsi_target_erl0.c
@@ -770,21 +770,8 @@ void iscsit_handle_time2retain_timeout(struct timer_list *t)
pr_err("Time2Retain timer expired for SID: %u, cleaning up"
" iSCSI session.\n", sess->sid);
- {
- struct iscsi_tiqn *tiqn = tpg->tpg_tiqn;
-
- if (tiqn) {
- spin_lock(&tiqn->sess_err_stats.lock);
- strcpy(tiqn->sess_err_stats.last_sess_fail_rem_name,
- (void *)sess->sess_ops->InitiatorName);
- tiqn->sess_err_stats.last_sess_failure_type =
- ISCSI_SESS_ERR_CXN_TIMEOUT;
- tiqn->sess_err_stats.cxn_timeout_errors++;
- atomic_long_inc(&sess->conn_timeout_errors);
- spin_unlock(&tiqn->sess_err_stats.lock);
- }
- }
+ iscsit_fill_cxn_timeout_err_stats(sess);
spin_unlock_bh(&se_tpg->session_lock);
iscsit_close_session(sess);
}
diff --git a/drivers/target/iscsi/iscsi_target_erl1.c b/drivers/target/iscsi/iscsi_target_erl1.c
index 5efa42b939a1..a211e8154f4c 100644
--- a/drivers/target/iscsi/iscsi_target_erl1.c
+++ b/drivers/target/iscsi/iscsi_target_erl1.c
@@ -1169,15 +1169,21 @@ void iscsit_handle_dataout_timeout(struct timer_list *t)
na = iscsit_tpg_get_node_attrib(sess);
if (!sess->sess_ops->ErrorRecoveryLevel) {
- pr_debug("Unable to recover from DataOut timeout while"
- " in ERL=0.\n");
+ pr_err("Unable to recover from DataOut timeout while"
+ " in ERL=0, closing iSCSI connection for I_T Nexus"
+ " %s,i,0x%6phN,%s,t,0x%02x\n",
+ sess->sess_ops->InitiatorName, sess->isid,
+ sess->tpg->tpg_tiqn->tiqn, (u32)sess->tpg->tpgt);
goto failure;
}
if (++cmd->dataout_timeout_retries == na->dataout_timeout_retries) {
- pr_debug("Command ITT: 0x%08x exceeded max retries"
- " for DataOUT timeout %u, closing iSCSI connection.\n",
- cmd->init_task_tag, na->dataout_timeout_retries);
+ pr_err("Command ITT: 0x%08x exceeded max retries"
+ " for DataOUT timeout %u, closing iSCSI connection for"
+ " I_T Nexus %s,i,0x%6phN,%s,t,0x%02x\n",
+ cmd->init_task_tag, na->dataout_timeout_retries,
+ sess->sess_ops->InitiatorName, sess->isid,
+ sess->tpg->tpg_tiqn->tiqn, (u32)sess->tpg->tpgt);
goto failure;
}
@@ -1224,6 +1230,7 @@ void iscsit_handle_dataout_timeout(struct timer_list *t)
failure:
spin_unlock_bh(&cmd->dataout_timeout_lock);
+ iscsit_fill_cxn_timeout_err_stats(sess);
iscsit_cause_connection_reinstatement(conn, 0);
iscsit_dec_conn_usage_count(conn);
}
diff --git a/drivers/target/iscsi/iscsi_target_erl2.c b/drivers/target/iscsi/iscsi_target_erl2.c
index 8df9c90f3db3..b08b620b1bf0 100644
--- a/drivers/target/iscsi/iscsi_target_erl2.c
+++ b/drivers/target/iscsi/iscsi_target_erl2.c
@@ -125,7 +125,7 @@ struct iscsi_conn_recovery *iscsit_get_inactive_connection_recovery_entry(
return NULL;
}
-void iscsit_free_connection_recovery_entires(struct iscsi_session *sess)
+void iscsit_free_connection_recovery_entries(struct iscsi_session *sess)
{
struct iscsi_cmd *cmd, *cmd_tmp;
struct iscsi_conn_recovery *cr, *cr_tmp;
diff --git a/drivers/target/iscsi/iscsi_target_erl2.h b/drivers/target/iscsi/iscsi_target_erl2.h
index 93e180d68d07..a39b0caf2337 100644
--- a/drivers/target/iscsi/iscsi_target_erl2.h
+++ b/drivers/target/iscsi/iscsi_target_erl2.h
@@ -13,7 +13,7 @@ extern void iscsit_create_conn_recovery_datain_values(struct iscsi_cmd *, __be32
extern void iscsit_create_conn_recovery_dataout_values(struct iscsi_cmd *);
extern struct iscsi_conn_recovery *iscsit_get_inactive_connection_recovery_entry(
struct iscsi_session *, u16);
-extern void iscsit_free_connection_recovery_entires(struct iscsi_session *);
+extern void iscsit_free_connection_recovery_entries(struct iscsi_session *);
extern int iscsit_remove_active_connection_recovery_entry(
struct iscsi_conn_recovery *, struct iscsi_session *);
extern int iscsit_remove_cmd_from_connection_recovery(struct iscsi_cmd *,
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c
index bb90c80ff388..ae3209efd0e0 100644
--- a/drivers/target/iscsi/iscsi_target_login.c
+++ b/drivers/target/iscsi/iscsi_target_login.c
@@ -578,7 +578,7 @@ int iscsi_login_post_auth_non_zero_tsih(
}
/*
- * Check for any connection recovery entires containing CID.
+ * Check for any connection recovery entries containing CID.
* We use the original ExpStatSN sent in the first login request
* to acknowledge commands for the failed connection.
*
diff --git a/drivers/target/iscsi/iscsi_target_stat.c b/drivers/target/iscsi/iscsi_target_stat.c
index df0a39811dc2..bb98882bdaa7 100644
--- a/drivers/target/iscsi/iscsi_target_stat.c
+++ b/drivers/target/iscsi/iscsi_target_stat.c
@@ -328,10 +328,10 @@ static ssize_t iscsi_stat_tgt_attr_fail_intr_name_show(struct config_item *item,
{
struct iscsi_tiqn *tiqn = iscsi_tgt_attr_tiqn(item);
struct iscsi_login_stats *lstat = &tiqn->login_stats;
- unsigned char buf[224];
+ unsigned char buf[ISCSI_IQN_LEN];
spin_lock(&lstat->lock);
- snprintf(buf, 224, "%s", lstat->last_intr_fail_name[0] ?
+ snprintf(buf, ISCSI_IQN_LEN, "%s", lstat->last_intr_fail_name[0] ?
lstat->last_intr_fail_name : NONE);
spin_unlock(&lstat->lock);
diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c
index 49be1e41290c..36b742932c72 100644
--- a/drivers/target/iscsi/iscsi_target_util.c
+++ b/drivers/target/iscsi/iscsi_target_util.c
@@ -915,6 +915,7 @@ static int iscsit_add_nopin(struct iscsi_conn *conn, int want_response)
void iscsit_handle_nopin_response_timeout(struct timer_list *t)
{
struct iscsi_conn *conn = from_timer(conn, t, nopin_response_timer);
+ struct iscsi_session *sess = conn->sess;
iscsit_inc_conn_usage_count(conn);
@@ -925,28 +926,14 @@ void iscsit_handle_nopin_response_timeout(struct timer_list *t)
return;
}
- pr_debug("Did not receive response to NOPIN on CID: %hu on"
- " SID: %u, failing connection.\n", conn->cid,
- conn->sess->sid);
+ pr_err("Did not receive response to NOPIN on CID: %hu, failing"
+ " connection for I_T Nexus %s,i,0x%6phN,%s,t,0x%02x\n",
+ conn->cid, sess->sess_ops->InitiatorName, sess->isid,
+ sess->tpg->tpg_tiqn->tiqn, (u32)sess->tpg->tpgt);
conn->nopin_response_timer_flags &= ~ISCSI_TF_RUNNING;
spin_unlock_bh(&conn->nopin_timer_lock);
- {
- struct iscsi_portal_group *tpg = conn->sess->tpg;
- struct iscsi_tiqn *tiqn = tpg->tpg_tiqn;
-
- if (tiqn) {
- spin_lock_bh(&tiqn->sess_err_stats.lock);
- strcpy(tiqn->sess_err_stats.last_sess_fail_rem_name,
- conn->sess->sess_ops->InitiatorName);
- tiqn->sess_err_stats.last_sess_failure_type =
- ISCSI_SESS_ERR_CXN_TIMEOUT;
- tiqn->sess_err_stats.cxn_timeout_errors++;
- atomic_long_inc(&conn->sess->conn_timeout_errors);
- spin_unlock_bh(&tiqn->sess_err_stats.lock);
- }
- }
-
+ iscsit_fill_cxn_timeout_err_stats(sess);
iscsit_cause_connection_reinstatement(conn, 0);
iscsit_dec_conn_usage_count(conn);
}
@@ -1258,8 +1245,7 @@ static int iscsit_do_rx_data(
return -1;
memset(&msg, 0, sizeof(struct msghdr));
- iov_iter_kvec(&msg.msg_iter, READ | ITER_KVEC,
- count->iov, count->iov_count, data);
+ iov_iter_kvec(&msg.msg_iter, READ, count->iov, count->iov_count, data);
while (msg_data_left(&msg)) {
rx_loop = sock_recvmsg(conn->sock, &msg, MSG_WAITALL);
@@ -1315,8 +1301,7 @@ int tx_data(
memset(&msg, 0, sizeof(struct msghdr));
- iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC,
- iov, iov_count, data);
+ iov_iter_kvec(&msg.msg_iter, WRITE, iov, iov_count, data);
while (msg_data_left(&msg)) {
int tx_loop = sock_sendmsg(conn->sock, &msg);
@@ -1405,3 +1390,22 @@ struct iscsi_tiqn *iscsit_snmp_get_tiqn(struct iscsi_conn *conn)
return tpg->tpg_tiqn;
}
+
+void iscsit_fill_cxn_timeout_err_stats(struct iscsi_session *sess)
+{
+ struct iscsi_portal_group *tpg = sess->tpg;
+ struct iscsi_tiqn *tiqn = tpg->tpg_tiqn;
+
+ if (!tiqn)
+ return;
+
+ spin_lock_bh(&tiqn->sess_err_stats.lock);
+ strlcpy(tiqn->sess_err_stats.last_sess_fail_rem_name,
+ sess->sess_ops->InitiatorName,
+ sizeof(tiqn->sess_err_stats.last_sess_fail_rem_name));
+ tiqn->sess_err_stats.last_sess_failure_type =
+ ISCSI_SESS_ERR_CXN_TIMEOUT;
+ tiqn->sess_err_stats.cxn_timeout_errors++;
+ atomic_long_inc(&sess->conn_timeout_errors);
+ spin_unlock_bh(&tiqn->sess_err_stats.lock);
+}
diff --git a/drivers/target/iscsi/iscsi_target_util.h b/drivers/target/iscsi/iscsi_target_util.h
index d66dfc212624..68e84803b0a1 100644
--- a/drivers/target/iscsi/iscsi_target_util.h
+++ b/drivers/target/iscsi/iscsi_target_util.h
@@ -67,5 +67,6 @@ extern int rx_data(struct iscsi_conn *, struct kvec *, int, int);
extern int tx_data(struct iscsi_conn *, struct kvec *, int, int);
extern void iscsit_collect_login_stats(struct iscsi_conn *, u8, u8);
extern struct iscsi_tiqn *iscsit_snmp_get_tiqn(struct iscsi_conn *);
+extern void iscsit_fill_cxn_timeout_err_stats(struct iscsi_session *);
#endif /*** ISCSI_TARGET_UTIL_H ***/
diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c
index e46ca968009c..4f134b0c3e29 100644
--- a/drivers/target/target_core_alua.c
+++ b/drivers/target/target_core_alua.c
@@ -268,7 +268,7 @@ target_emulate_report_target_port_groups(struct se_cmd *cmd)
}
transport_kunmap_data_sg(cmd);
- target_complete_cmd(cmd, GOOD);
+ target_complete_cmd_with_length(cmd, GOOD, rd_len + 4);
return 0;
}
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c
index 16751ae55d7b..49b110d1b972 100644
--- a/drivers/target/target_core_file.c
+++ b/drivers/target/target_core_file.c
@@ -303,7 +303,7 @@ fd_execute_rw_aio(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
len += sg->length;
}
- iov_iter_bvec(&iter, ITER_BVEC | is_write, bvec, sgl_nents, len);
+ iov_iter_bvec(&iter, is_write, bvec, sgl_nents, len);
aio_cmd->cmd = cmd;
aio_cmd->len = len;
@@ -353,7 +353,7 @@ static int fd_do_rw(struct se_cmd *cmd, struct file *fd,
len += sg->length;
}
- iov_iter_bvec(&iter, ITER_BVEC, bvec, sgl_nents, len);
+ iov_iter_bvec(&iter, READ, bvec, sgl_nents, len);
if (is_write)
ret = vfs_iter_write(fd, &iter, &pos, 0);
else
@@ -490,7 +490,7 @@ fd_execute_write_same(struct se_cmd *cmd)
len += se_dev->dev_attrib.block_size;
}
- iov_iter_bvec(&iter, ITER_BVEC, bvec, nolb, len);
+ iov_iter_bvec(&iter, READ, bvec, nolb, len);
ret = vfs_iter_write(fd_dev->fd_file, &iter, &pos, 0);
kfree(bvec);
diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c
index ce1321a5cb7b..b5ed9c377060 100644
--- a/drivers/target/target_core_iblock.c
+++ b/drivers/target/target_core_iblock.c
@@ -514,7 +514,7 @@ iblock_execute_write_same(struct se_cmd *cmd)
}
/* Always in 512 byte units for Linux/Block */
- block_lba += sg->length >> IBLOCK_LBA_SHIFT;
+ block_lba += sg->length >> SECTOR_SHIFT;
sectors -= 1;
}
@@ -635,14 +635,15 @@ static ssize_t iblock_show_configfs_dev_params(struct se_device *dev, char *b)
}
static int
-iblock_alloc_bip(struct se_cmd *cmd, struct bio *bio)
+iblock_alloc_bip(struct se_cmd *cmd, struct bio *bio,
+ struct sg_mapping_iter *miter)
{
struct se_device *dev = cmd->se_dev;
struct blk_integrity *bi;
struct bio_integrity_payload *bip;
struct iblock_dev *ib_dev = IBLOCK_DEV(dev);
- struct scatterlist *sg;
- int i, rc;
+ int rc;
+ size_t resid, len;
bi = bdev_get_integrity(ib_dev->ibd_bd);
if (!bi) {
@@ -650,31 +651,39 @@ iblock_alloc_bip(struct se_cmd *cmd, struct bio *bio)
return -ENODEV;
}
- bip = bio_integrity_alloc(bio, GFP_NOIO, cmd->t_prot_nents);
+ bip = bio_integrity_alloc(bio, GFP_NOIO,
+ min_t(unsigned int, cmd->t_prot_nents, BIO_MAX_PAGES));
if (IS_ERR(bip)) {
pr_err("Unable to allocate bio_integrity_payload\n");
return PTR_ERR(bip);
}
- bip->bip_iter.bi_size = (cmd->data_length / dev->dev_attrib.block_size) *
- dev->prot_length;
- bip->bip_iter.bi_sector = bio->bi_iter.bi_sector;
+ bip->bip_iter.bi_size = bio_integrity_bytes(bi, bio_sectors(bio));
+ bip_set_seed(bip, bio->bi_iter.bi_sector);
pr_debug("IBLOCK BIP Size: %u Sector: %llu\n", bip->bip_iter.bi_size,
(unsigned long long)bip->bip_iter.bi_sector);
- for_each_sg(cmd->t_prot_sg, sg, cmd->t_prot_nents, i) {
+ resid = bip->bip_iter.bi_size;
+ while (resid > 0 && sg_miter_next(miter)) {
- rc = bio_integrity_add_page(bio, sg_page(sg), sg->length,
- sg->offset);
- if (rc != sg->length) {
+ len = min_t(size_t, miter->length, resid);
+ rc = bio_integrity_add_page(bio, miter->page, len,
+ offset_in_page(miter->addr));
+ if (rc != len) {
pr_err("bio_integrity_add_page() failed; %d\n", rc);
+ sg_miter_stop(miter);
return -ENOMEM;
}
- pr_debug("Added bio integrity page: %p length: %d offset; %d\n",
- sg_page(sg), sg->length, sg->offset);
+ pr_debug("Added bio integrity page: %p length: %zu offset: %lu\n",
+ miter->page, len, offset_in_page(miter->addr));
+
+ resid -= len;
+ if (len < miter->length)
+ miter->consumed -= miter->length - len;
}
+ sg_miter_stop(miter);
return 0;
}
@@ -686,12 +695,13 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
struct se_device *dev = cmd->se_dev;
sector_t block_lba = target_to_linux_sector(dev, cmd->t_task_lba);
struct iblock_req *ibr;
- struct bio *bio, *bio_start;
+ struct bio *bio;
struct bio_list list;
struct scatterlist *sg;
u32 sg_num = sgl_nents;
unsigned bio_cnt;
- int i, op, op_flags = 0;
+ int i, rc, op, op_flags = 0;
+ struct sg_mapping_iter prot_miter;
if (data_direction == DMA_TO_DEVICE) {
struct iblock_dev *ib_dev = IBLOCK_DEV(dev);
@@ -726,13 +736,17 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
if (!bio)
goto fail_free_ibr;
- bio_start = bio;
bio_list_init(&list);
bio_list_add(&list, bio);
refcount_set(&ibr->pending, 2);
bio_cnt = 1;
+ if (cmd->prot_type && dev->dev_attrib.pi_prot_type)
+ sg_miter_start(&prot_miter, cmd->t_prot_sg, cmd->t_prot_nents,
+ op == REQ_OP_READ ? SG_MITER_FROM_SG :
+ SG_MITER_TO_SG);
+
for_each_sg(sgl, sg, sgl_nents, i) {
/*
* XXX: if the length the device accepts is shorter than the
@@ -741,6 +755,12 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
*/
while (bio_add_page(bio, sg_page(sg), sg->length, sg->offset)
!= sg->length) {
+ if (cmd->prot_type && dev->dev_attrib.pi_prot_type) {
+ rc = iblock_alloc_bip(cmd, bio, &prot_miter);
+ if (rc)
+ goto fail_put_bios;
+ }
+
if (bio_cnt >= IBLOCK_MAX_BIO_PER_TASK) {
iblock_submit_bios(&list);
bio_cnt = 0;
@@ -757,12 +777,12 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
}
/* Always in 512 byte units for Linux/Block */
- block_lba += sg->length >> IBLOCK_LBA_SHIFT;
+ block_lba += sg->length >> SECTOR_SHIFT;
sg_num--;
}
if (cmd->prot_type && dev->dev_attrib.pi_prot_type) {
- int rc = iblock_alloc_bip(cmd, bio_start);
+ rc = iblock_alloc_bip(cmd, bio, &prot_miter);
if (rc)
goto fail_put_bios;
}
diff --git a/drivers/target/target_core_iblock.h b/drivers/target/target_core_iblock.h
index 9cc3843404d4..cefc641145b3 100644
--- a/drivers/target/target_core_iblock.h
+++ b/drivers/target/target_core_iblock.h
@@ -9,7 +9,6 @@
#define IBLOCK_VERSION "4.0"
#define IBLOCK_MAX_CDBS 16
-#define IBLOCK_LBA_SHIFT 9
struct iblock_req {
refcount_t pending;
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c
index ebac2b49b9c6..1ac1f7d2e6c9 100644
--- a/drivers/target/target_core_sbc.c
+++ b/drivers/target/target_core_sbc.c
@@ -360,6 +360,10 @@ static sense_reason_t xdreadwrite_callback(struct se_cmd *cmd, bool success,
unsigned int offset;
sense_reason_t ret = TCM_NO_SENSE;
int i, count;
+
+ if (!success)
+ return 0;
+
/*
* From sbc3r22.pdf section 5.48 XDWRITEREAD (10) command
*
@@ -425,14 +429,8 @@ static sense_reason_t compare_and_write_post(struct se_cmd *cmd, bool success,
struct se_device *dev = cmd->se_dev;
sense_reason_t ret = TCM_NO_SENSE;
- /*
- * Only set SCF_COMPARE_AND_WRITE_POST to force a response fall-through
- * within target_complete_ok_work() if the command was successfully
- * sent to the backend driver.
- */
spin_lock_irq(&cmd->t_state_lock);
- if (cmd->transport_state & CMD_T_SENT) {
- cmd->se_cmd_flags |= SCF_COMPARE_AND_WRITE_POST;
+ if (success) {
*post_ret = 1;
if (cmd->scsi_status == SAM_STAT_CHECK_CONDITION)
@@ -453,7 +451,8 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool succes
int *post_ret)
{
struct se_device *dev = cmd->se_dev;
- struct scatterlist *write_sg = NULL, *sg;
+ struct sg_table write_tbl = { };
+ struct scatterlist *write_sg, *sg;
unsigned char *buf = NULL, *addr;
struct sg_mapping_iter m;
unsigned int offset = 0, len;
@@ -494,14 +493,12 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool succes
goto out;
}
- write_sg = kmalloc_array(cmd->t_data_nents, sizeof(*write_sg),
- GFP_KERNEL);
- if (!write_sg) {
+ if (sg_alloc_table(&write_tbl, cmd->t_data_nents, GFP_KERNEL) < 0) {
pr_err("Unable to allocate compare_and_write sg\n");
ret = TCM_OUT_OF_RESOURCES;
goto out;
}
- sg_init_table(write_sg, cmd->t_data_nents);
+ write_sg = write_tbl.sgl;
/*
* Setup verify and write data payloads from total NumberLBAs.
*/
@@ -597,7 +594,7 @@ out:
* sbc_compare_and_write() before the original READ I/O submission.
*/
up(&dev->caw_sem);
- kfree(write_sg);
+ sg_free_table(&write_tbl);
kfree(buf);
return ret;
}
diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c
index cb0461a10808..f459118bc11b 100644
--- a/drivers/target/target_core_spc.c
+++ b/drivers/target/target_core_spc.c
@@ -636,9 +636,9 @@ spc_emulate_evpd_b2(struct se_cmd *cmd, unsigned char *buf)
/*
* The unmap_zeroes_data set means that the underlying device supports
- * REQ_DISCARD and has the discard_zeroes_data bit set. This satisfies
- * the SBC requirements for LBPRZ, meaning that a subsequent read
- * will return zeroes after an UNMAP or WRITE SAME (16) to an LBA
+ * REQ_OP_DISCARD and has the discard_zeroes_data bit set. This
+ * satisfies the SBC requirements for LBPRZ, meaning that a subsequent
+ * read will return zeroes after an UNMAP or WRITE SAME (16) to an LBA
* See sbc4r36 6.6.4.
*/
if (((dev->dev_attrib.emulate_tpu != 0) ||
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 86c0156e6c88..2cfd61d62e97 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -205,19 +205,19 @@ void transport_subsystem_check_init(void)
if (sub_api_initialized)
return;
- ret = request_module("target_core_iblock");
+ ret = IS_ENABLED(CONFIG_TCM_IBLOCK) && request_module("target_core_iblock");
if (ret != 0)
pr_err("Unable to load target_core_iblock\n");
- ret = request_module("target_core_file");
+ ret = IS_ENABLED(CONFIG_TCM_FILEIO) && request_module("target_core_file");
if (ret != 0)
pr_err("Unable to load target_core_file\n");
- ret = request_module("target_core_pscsi");
+ ret = IS_ENABLED(CONFIG_TCM_PSCSI) && request_module("target_core_pscsi");
if (ret != 0)
pr_err("Unable to load target_core_pscsi\n");
- ret = request_module("target_core_user");
+ ret = IS_ENABLED(CONFIG_TCM_USER2) && request_module("target_core_user");
if (ret != 0)
pr_err("Unable to load target_core_user\n");
@@ -1778,7 +1778,7 @@ EXPORT_SYMBOL(target_submit_tmr);
void transport_generic_request_failure(struct se_cmd *cmd,
sense_reason_t sense_reason)
{
- int ret = 0, post_ret = 0;
+ int ret = 0, post_ret;
pr_debug("-----[ Storage Engine Exception; sense_reason %d\n",
sense_reason);
@@ -1789,12 +1789,7 @@ void transport_generic_request_failure(struct se_cmd *cmd,
*/
transport_complete_task_attr(cmd);
- /*
- * Handle special case for COMPARE_AND_WRITE failure, where the
- * callback is expected to drop the per device ->caw_sem.
- */
- if ((cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) &&
- cmd->transport_complete_callback)
+ if (cmd->transport_complete_callback)
cmd->transport_complete_callback(cmd, false, &post_ret);
if (transport_check_aborted_status(cmd, 1))
@@ -2012,7 +2007,7 @@ void target_execute_cmd(struct se_cmd *cmd)
* Determine if frontend context caller is requesting the stopping of
* this command for frontend exceptions.
*
- * If the received CDB has aleady been aborted stop processing it here.
+ * If the received CDB has already been aborted stop processing it here.
*/
spin_lock_irq(&cmd->t_state_lock);
if (__transport_check_aborted_status(cmd, 1)) {
@@ -2516,7 +2511,7 @@ transport_generic_new_cmd(struct se_cmd *cmd)
}
/*
- * Determine is the TCM fabric module has already allocated physical
+ * Determine if the TCM fabric module has already allocated physical
* memory, and is directly calling transport_generic_map_mem_to_cmd()
* beforehand.
*/
@@ -2754,7 +2749,7 @@ static void target_release_cmd_kref(struct kref *kref)
if (se_sess) {
spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
list_del_init(&se_cmd->se_cmd_list);
- if (list_empty(&se_sess->sess_cmd_list))
+ if (se_sess->sess_tearing_down && list_empty(&se_sess->sess_cmd_list))
wake_up(&se_sess->cmd_list_wq);
spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
}
@@ -2907,7 +2902,7 @@ void target_wait_for_sess_cmds(struct se_session *se_sess)
spin_lock_irq(&se_sess->sess_cmd_lock);
do {
- ret = wait_event_interruptible_lock_irq_timeout(
+ ret = wait_event_lock_irq_timeout(
se_sess->cmd_list_wq,
list_empty(&se_sess->sess_cmd_list),
se_sess->sess_cmd_lock, 180 * HZ);
diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c
index 2718a933c0c6..70adcfdca8d1 100644
--- a/drivers/target/target_core_xcopy.c
+++ b/drivers/target/target_core_xcopy.c
@@ -391,7 +391,6 @@ out:
struct xcopy_pt_cmd {
bool remote_port;
struct se_cmd se_cmd;
- struct xcopy_op *xcopy_op;
struct completion xpt_passthrough_sem;
unsigned char sense_buffer[TRANSPORT_SENSE_BUFFER];
};
@@ -596,8 +595,6 @@ static int target_xcopy_setup_pt_cmd(
* X-COPY PUSH or X-COPY PULL based upon where the CDB was received.
*/
target_xcopy_init_pt_lun(se_dev, cmd, remote_port);
-
- xpt_cmd->xcopy_op = xop;
target_xcopy_setup_pt_port(xpt_cmd, xop, remote_port);
cmd->tag = 0;
diff --git a/drivers/tc/tc.c b/drivers/tc/tc.c
index 3be9519654e5..cf3fad2cb871 100644
--- a/drivers/tc/tc.c
+++ b/drivers/tc/tc.c
@@ -2,7 +2,7 @@
* TURBOchannel bus services.
*
* Copyright (c) Harald Koerfgen, 1998
- * Copyright (c) 2001, 2003, 2005, 2006 Maciej W. Rozycki
+ * Copyright (c) 2001, 2003, 2005, 2006, 2018 Maciej W. Rozycki
* Copyright (c) 2005 James Simmons
*
* This file is subject to the terms and conditions of the GNU
@@ -10,6 +10,7 @@
* directory of this archive for more details.
*/
#include <linux/compiler.h>
+#include <linux/dma-mapping.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/ioport.h>
@@ -92,6 +93,11 @@ static void __init tc_bus_add_devices(struct tc_bus *tbus)
tdev->dev.bus = &tc_bus_type;
tdev->slot = slot;
+ /* TURBOchannel has 34-bit DMA addressing (16GiB space). */
+ tdev->dma_mask = DMA_BIT_MASK(34);
+ tdev->dev.dma_mask = &tdev->dma_mask;
+ tdev->dev.coherent_dma_mask = DMA_BIT_MASK(34);
+
for (i = 0; i < 8; i++) {
tdev->firmware[i] =
readb(module + offset + TC_FIRM_VER + 4 * i);
diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
index e1aafe842d66..34dce850067b 100644
--- a/drivers/tee/optee/core.c
+++ b/drivers/tee/optee/core.c
@@ -696,7 +696,7 @@ static int __init optee_driver_init(void)
return -ENODEV;
np = of_find_matching_node(fw_np, optee_match);
- if (!np)
+ if (!np || !of_device_is_available(np))
return -ENODEV;
optee = optee_probe(np);
diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
index dd46b758852a..7b2bb4c50058 100644
--- a/drivers/tee/tee_core.c
+++ b/drivers/tee/tee_core.c
@@ -38,15 +38,13 @@ static DEFINE_SPINLOCK(driver_lock);
static struct class *tee_class;
static dev_t tee_devt;
-static int tee_open(struct inode *inode, struct file *filp)
+static struct tee_context *teedev_open(struct tee_device *teedev)
{
int rc;
- struct tee_device *teedev;
struct tee_context *ctx;
- teedev = container_of(inode->i_cdev, struct tee_device, cdev);
if (!tee_device_get(teedev))
- return -EINVAL;
+ return ERR_PTR(-EINVAL);
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx) {
@@ -57,16 +55,16 @@ static int tee_open(struct inode *inode, struct file *filp)
kref_init(&ctx->refcount);
ctx->teedev = teedev;
INIT_LIST_HEAD(&ctx->list_shm);
- filp->private_data = ctx;
rc = teedev->desc->ops->open(ctx);
if (rc)
goto err;
- return 0;
+ return ctx;
err:
kfree(ctx);
tee_device_put(teedev);
- return rc;
+ return ERR_PTR(rc);
+
}
void teedev_ctx_get(struct tee_context *ctx)
@@ -100,6 +98,18 @@ static void teedev_close_context(struct tee_context *ctx)
teedev_ctx_put(ctx);
}
+static int tee_open(struct inode *inode, struct file *filp)
+{
+ struct tee_context *ctx;
+
+ ctx = teedev_open(container_of(inode->i_cdev, struct tee_device, cdev));
+ if (IS_ERR(ctx))
+ return PTR_ERR(ctx);
+
+ filp->private_data = ctx;
+ return 0;
+}
+
static int tee_release(struct inode *inode, struct file *filp)
{
teedev_close_context(filp->private_data);
@@ -928,6 +938,95 @@ void *tee_get_drvdata(struct tee_device *teedev)
}
EXPORT_SYMBOL_GPL(tee_get_drvdata);
+struct match_dev_data {
+ struct tee_ioctl_version_data *vers;
+ const void *data;
+ int (*match)(struct tee_ioctl_version_data *, const void *);
+};
+
+static int match_dev(struct device *dev, const void *data)
+{
+ const struct match_dev_data *match_data = data;
+ struct tee_device *teedev = container_of(dev, struct tee_device, dev);
+
+ teedev->desc->ops->get_version(teedev, match_data->vers);
+ return match_data->match(match_data->vers, match_data->data);
+}
+
+struct tee_context *
+tee_client_open_context(struct tee_context *start,
+ int (*match)(struct tee_ioctl_version_data *,
+ const void *),
+ const void *data, struct tee_ioctl_version_data *vers)
+{
+ struct device *dev = NULL;
+ struct device *put_dev = NULL;
+ struct tee_context *ctx = NULL;
+ struct tee_ioctl_version_data v;
+ struct match_dev_data match_data = { vers ? vers : &v, data, match };
+
+ if (start)
+ dev = &start->teedev->dev;
+
+ do {
+ dev = class_find_device(tee_class, dev, &match_data, match_dev);
+ if (!dev) {
+ ctx = ERR_PTR(-ENOENT);
+ break;
+ }
+
+ put_device(put_dev);
+ put_dev = dev;
+
+ ctx = teedev_open(container_of(dev, struct tee_device, dev));
+ } while (IS_ERR(ctx) && PTR_ERR(ctx) != -ENOMEM);
+
+ put_device(put_dev);
+ return ctx;
+}
+EXPORT_SYMBOL_GPL(tee_client_open_context);
+
+void tee_client_close_context(struct tee_context *ctx)
+{
+ teedev_close_context(ctx);
+}
+EXPORT_SYMBOL_GPL(tee_client_close_context);
+
+void tee_client_get_version(struct tee_context *ctx,
+ struct tee_ioctl_version_data *vers)
+{
+ ctx->teedev->desc->ops->get_version(ctx->teedev, vers);
+}
+EXPORT_SYMBOL_GPL(tee_client_get_version);
+
+int tee_client_open_session(struct tee_context *ctx,
+ struct tee_ioctl_open_session_arg *arg,
+ struct tee_param *param)
+{
+ if (!ctx->teedev->desc->ops->open_session)
+ return -EINVAL;
+ return ctx->teedev->desc->ops->open_session(ctx, arg, param);
+}
+EXPORT_SYMBOL_GPL(tee_client_open_session);
+
+int tee_client_close_session(struct tee_context *ctx, u32 session)
+{
+ if (!ctx->teedev->desc->ops->close_session)
+ return -EINVAL;
+ return ctx->teedev->desc->ops->close_session(ctx, session);
+}
+EXPORT_SYMBOL_GPL(tee_client_close_session);
+
+int tee_client_invoke_func(struct tee_context *ctx,
+ struct tee_ioctl_invoke_arg *arg,
+ struct tee_param *param)
+{
+ if (!ctx->teedev->desc->ops->invoke_func)
+ return -EINVAL;
+ return ctx->teedev->desc->ops->invoke_func(ctx, arg, param);
+}
+EXPORT_SYMBOL_GPL(tee_client_invoke_func);
+
static int __init tee_init(void)
{
int rc;
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 0e69edc77d18..5422523c03f8 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -432,7 +432,7 @@ source "drivers/thermal/samsung/Kconfig"
endmenu
menu "STMicroelectronics thermal drivers"
-depends on ARCH_STI && OF
+depends on (ARCH_STI || ARCH_STM32) && OF
source "drivers/thermal/st/Kconfig"
endmenu
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 610344eb3e03..82bb50dc6423 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -53,7 +53,7 @@ obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/
obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal/
obj-$(CONFIG_INTEL_BXT_PMIC_THERMAL) += intel_bxt_pmic_thermal.o
obj-$(CONFIG_INTEL_PCH_THERMAL) += intel_pch_thermal.o
-obj-$(CONFIG_ST_THERMAL) += st/
+obj-y += st/
obj-$(CONFIG_QCOM_TSENS) += qcom/
obj-y += tegra/
obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o
diff --git a/drivers/thermal/armada_thermal.c b/drivers/thermal/armada_thermal.c
index 2c2f6d93034e..92f67d40f2e9 100644
--- a/drivers/thermal/armada_thermal.c
+++ b/drivers/thermal/armada_thermal.c
@@ -526,8 +526,8 @@ static int armada_thermal_probe_legacy(struct platform_device *pdev,
/* First memory region points towards the status register */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (IS_ERR(res))
- return PTR_ERR(res);
+ if (!res)
+ return -EIO;
/*
* Edit the resource start address and length to map over all the
diff --git a/drivers/thermal/da9062-thermal.c b/drivers/thermal/da9062-thermal.c
index dd8dd947b7f0..01b0cb994457 100644
--- a/drivers/thermal/da9062-thermal.c
+++ b/drivers/thermal/da9062-thermal.c
@@ -106,7 +106,7 @@ static void da9062_thermal_poll_on(struct work_struct *work)
THERMAL_EVENT_UNSPECIFIED);
delay = msecs_to_jiffies(thermal->zone->passive_delay);
- schedule_delayed_work(&thermal->work, delay);
+ queue_delayed_work(system_freezable_wq, &thermal->work, delay);
return;
}
@@ -125,7 +125,7 @@ static irqreturn_t da9062_thermal_irq_handler(int irq, void *data)
struct da9062_thermal *thermal = data;
disable_irq_nosync(thermal->irq);
- schedule_delayed_work(&thermal->work, 0);
+ queue_delayed_work(system_freezable_wq, &thermal->work, 0);
return IRQ_HANDLED;
}
diff --git a/drivers/thermal/hisi_thermal.c b/drivers/thermal/hisi_thermal.c
index 761d0559c268..c4111a98f1a7 100644
--- a/drivers/thermal/hisi_thermal.c
+++ b/drivers/thermal/hisi_thermal.c
@@ -55,25 +55,39 @@
#define HI3660_TEMP_STEP (205)
#define HI3660_TEMP_LAG (4000)
-#define HI6220_DEFAULT_SENSOR 2
-#define HI3660_DEFAULT_SENSOR 1
+#define HI6220_CLUSTER0_SENSOR 2
+#define HI6220_CLUSTER1_SENSOR 1
+
+#define HI3660_LITTLE_SENSOR 0
+#define HI3660_BIG_SENSOR 1
+#define HI3660_G3D_SENSOR 2
+#define HI3660_MODEM_SENSOR 3
+
+struct hisi_thermal_data;
struct hisi_thermal_sensor {
+ struct hisi_thermal_data *data;
struct thermal_zone_device *tzd;
+ const char *irq_name;
uint32_t id;
uint32_t thres_temp;
};
+struct hisi_thermal_ops {
+ int (*get_temp)(struct hisi_thermal_sensor *sensor);
+ int (*enable_sensor)(struct hisi_thermal_sensor *sensor);
+ int (*disable_sensor)(struct hisi_thermal_sensor *sensor);
+ int (*irq_handler)(struct hisi_thermal_sensor *sensor);
+ int (*probe)(struct hisi_thermal_data *data);
+};
+
struct hisi_thermal_data {
- int (*get_temp)(struct hisi_thermal_data *data);
- int (*enable_sensor)(struct hisi_thermal_data *data);
- int (*disable_sensor)(struct hisi_thermal_data *data);
- int (*irq_handler)(struct hisi_thermal_data *data);
+ const struct hisi_thermal_ops *ops;
+ struct hisi_thermal_sensor *sensor;
struct platform_device *pdev;
struct clk *clk;
- struct hisi_thermal_sensor sensor;
void __iomem *regs;
- int irq;
+ int nr_sensors;
};
/*
@@ -266,30 +280,40 @@ static inline void hi6220_thermal_hdak_set(void __iomem *addr, int value)
(value << 4), addr + HI6220_TEMP0_CFG);
}
-static int hi6220_thermal_irq_handler(struct hisi_thermal_data *data)
+static int hi6220_thermal_irq_handler(struct hisi_thermal_sensor *sensor)
{
+ struct hisi_thermal_data *data = sensor->data;
+
hi6220_thermal_alarm_clear(data->regs, 1);
return 0;
}
-static int hi3660_thermal_irq_handler(struct hisi_thermal_data *data)
+static int hi3660_thermal_irq_handler(struct hisi_thermal_sensor *sensor)
{
- hi3660_thermal_alarm_clear(data->regs, data->sensor.id, 1);
+ struct hisi_thermal_data *data = sensor->data;
+
+ hi3660_thermal_alarm_clear(data->regs, sensor->id, 1);
return 0;
}
-static int hi6220_thermal_get_temp(struct hisi_thermal_data *data)
+static int hi6220_thermal_get_temp(struct hisi_thermal_sensor *sensor)
{
+ struct hisi_thermal_data *data = sensor->data;
+
return hi6220_thermal_get_temperature(data->regs);
}
-static int hi3660_thermal_get_temp(struct hisi_thermal_data *data)
+static int hi3660_thermal_get_temp(struct hisi_thermal_sensor *sensor)
{
- return hi3660_thermal_get_temperature(data->regs, data->sensor.id);
+ struct hisi_thermal_data *data = sensor->data;
+
+ return hi3660_thermal_get_temperature(data->regs, sensor->id);
}
-static int hi6220_thermal_disable_sensor(struct hisi_thermal_data *data)
+static int hi6220_thermal_disable_sensor(struct hisi_thermal_sensor *sensor)
{
+ struct hisi_thermal_data *data = sensor->data;
+
/* disable sensor module */
hi6220_thermal_enable(data->regs, 0);
hi6220_thermal_alarm_enable(data->regs, 0);
@@ -300,16 +324,18 @@ static int hi6220_thermal_disable_sensor(struct hisi_thermal_data *data)
return 0;
}
-static int hi3660_thermal_disable_sensor(struct hisi_thermal_data *data)
+static int hi3660_thermal_disable_sensor(struct hisi_thermal_sensor *sensor)
{
+ struct hisi_thermal_data *data = sensor->data;
+
/* disable sensor module */
- hi3660_thermal_alarm_enable(data->regs, data->sensor.id, 0);
+ hi3660_thermal_alarm_enable(data->regs, sensor->id, 0);
return 0;
}
-static int hi6220_thermal_enable_sensor(struct hisi_thermal_data *data)
+static int hi6220_thermal_enable_sensor(struct hisi_thermal_sensor *sensor)
{
- struct hisi_thermal_sensor *sensor = &data->sensor;
+ struct hisi_thermal_data *data = sensor->data;
int ret;
/* enable clock for tsensor */
@@ -345,10 +371,10 @@ static int hi6220_thermal_enable_sensor(struct hisi_thermal_data *data)
return 0;
}
-static int hi3660_thermal_enable_sensor(struct hisi_thermal_data *data)
+static int hi3660_thermal_enable_sensor(struct hisi_thermal_sensor *sensor)
{
unsigned int value;
- struct hisi_thermal_sensor *sensor = &data->sensor;
+ struct hisi_thermal_data *data = sensor->data;
/* disable interrupt */
hi3660_thermal_alarm_enable(data->regs, sensor->id, 0);
@@ -371,21 +397,8 @@ static int hi6220_thermal_probe(struct hisi_thermal_data *data)
{
struct platform_device *pdev = data->pdev;
struct device *dev = &pdev->dev;
- struct resource *res;
int ret;
- data->get_temp = hi6220_thermal_get_temp;
- data->enable_sensor = hi6220_thermal_enable_sensor;
- data->disable_sensor = hi6220_thermal_disable_sensor;
- data->irq_handler = hi6220_thermal_irq_handler;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- data->regs = devm_ioremap_resource(dev, res);
- if (IS_ERR(data->regs)) {
- dev_err(dev, "failed to get io address\n");
- return PTR_ERR(data->regs);
- }
-
data->clk = devm_clk_get(dev, "thermal_clk");
if (IS_ERR(data->clk)) {
ret = PTR_ERR(data->clk);
@@ -394,11 +407,14 @@ static int hi6220_thermal_probe(struct hisi_thermal_data *data)
return ret;
}
- data->irq = platform_get_irq(pdev, 0);
- if (data->irq < 0)
- return data->irq;
+ data->sensor = devm_kzalloc(dev, sizeof(*data->sensor), GFP_KERNEL);
+ if (!data->sensor)
+ return -ENOMEM;
- data->sensor.id = HI6220_DEFAULT_SENSOR;
+ data->sensor[0].id = HI6220_CLUSTER0_SENSOR;
+ data->sensor[0].irq_name = "tsensor_intr";
+ data->sensor[0].data = data;
+ data->nr_sensors = 1;
return 0;
}
@@ -407,38 +423,34 @@ static int hi3660_thermal_probe(struct hisi_thermal_data *data)
{
struct platform_device *pdev = data->pdev;
struct device *dev = &pdev->dev;
- struct resource *res;
- data->get_temp = hi3660_thermal_get_temp;
- data->enable_sensor = hi3660_thermal_enable_sensor;
- data->disable_sensor = hi3660_thermal_disable_sensor;
- data->irq_handler = hi3660_thermal_irq_handler;
+ data->nr_sensors = 2;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- data->regs = devm_ioremap_resource(dev, res);
- if (IS_ERR(data->regs)) {
- dev_err(dev, "failed to get io address\n");
- return PTR_ERR(data->regs);
- }
+ data->sensor = devm_kzalloc(dev, sizeof(*data->sensor) *
+ data->nr_sensors, GFP_KERNEL);
+ if (!data->sensor)
+ return -ENOMEM;
- data->irq = platform_get_irq(pdev, 0);
- if (data->irq < 0)
- return data->irq;
+ data->sensor[0].id = HI3660_BIG_SENSOR;
+ data->sensor[0].irq_name = "tsensor_a73";
+ data->sensor[0].data = data;
- data->sensor.id = HI3660_DEFAULT_SENSOR;
+ data->sensor[1].id = HI3660_LITTLE_SENSOR;
+ data->sensor[1].irq_name = "tsensor_a53";
+ data->sensor[1].data = data;
return 0;
}
static int hisi_thermal_get_temp(void *__data, int *temp)
{
- struct hisi_thermal_data *data = __data;
- struct hisi_thermal_sensor *sensor = &data->sensor;
+ struct hisi_thermal_sensor *sensor = __data;
+ struct hisi_thermal_data *data = sensor->data;
- *temp = data->get_temp(data);
+ *temp = data->ops->get_temp(sensor);
- dev_dbg(&data->pdev->dev, "id=%d, temp=%d, thres=%d\n",
- sensor->id, *temp, sensor->thres_temp);
+ dev_dbg(&data->pdev->dev, "tzd=%p, id=%d, temp=%d, thres=%d\n",
+ sensor->tzd, sensor->id, *temp, sensor->thres_temp);
return 0;
}
@@ -449,38 +461,39 @@ static const struct thermal_zone_of_device_ops hisi_of_thermal_ops = {
static irqreturn_t hisi_thermal_alarm_irq_thread(int irq, void *dev)
{
- struct hisi_thermal_data *data = dev;
- struct hisi_thermal_sensor *sensor = &data->sensor;
+ struct hisi_thermal_sensor *sensor = dev;
+ struct hisi_thermal_data *data = sensor->data;
int temp = 0;
- data->irq_handler(data);
+ data->ops->irq_handler(sensor);
- hisi_thermal_get_temp(data, &temp);
+ hisi_thermal_get_temp(sensor, &temp);
if (temp >= sensor->thres_temp) {
- dev_crit(&data->pdev->dev, "THERMAL ALARM: %d > %d\n",
- temp, sensor->thres_temp);
+ dev_crit(&data->pdev->dev,
+ "sensor <%d> THERMAL ALARM: %d > %d\n",
+ sensor->id, temp, sensor->thres_temp);
- thermal_zone_device_update(data->sensor.tzd,
+ thermal_zone_device_update(sensor->tzd,
THERMAL_EVENT_UNSPECIFIED);
} else {
- dev_crit(&data->pdev->dev, "THERMAL ALARM stopped: %d < %d\n",
- temp, sensor->thres_temp);
+ dev_crit(&data->pdev->dev,
+ "sensor <%d> THERMAL ALARM stopped: %d < %d\n",
+ sensor->id, temp, sensor->thres_temp);
}
return IRQ_HANDLED;
}
static int hisi_thermal_register_sensor(struct platform_device *pdev,
- struct hisi_thermal_data *data,
struct hisi_thermal_sensor *sensor)
{
int ret, i;
const struct thermal_trip *trip;
sensor->tzd = devm_thermal_zone_of_sensor_register(&pdev->dev,
- sensor->id, data,
+ sensor->id, sensor,
&hisi_of_thermal_ops);
if (IS_ERR(sensor->tzd)) {
ret = PTR_ERR(sensor->tzd);
@@ -502,14 +515,30 @@ static int hisi_thermal_register_sensor(struct platform_device *pdev,
return 0;
}
+static const struct hisi_thermal_ops hi6220_ops = {
+ .get_temp = hi6220_thermal_get_temp,
+ .enable_sensor = hi6220_thermal_enable_sensor,
+ .disable_sensor = hi6220_thermal_disable_sensor,
+ .irq_handler = hi6220_thermal_irq_handler,
+ .probe = hi6220_thermal_probe,
+};
+
+static const struct hisi_thermal_ops hi3660_ops = {
+ .get_temp = hi3660_thermal_get_temp,
+ .enable_sensor = hi3660_thermal_enable_sensor,
+ .disable_sensor = hi3660_thermal_disable_sensor,
+ .irq_handler = hi3660_thermal_irq_handler,
+ .probe = hi3660_thermal_probe,
+};
+
static const struct of_device_id of_hisi_thermal_match[] = {
{
.compatible = "hisilicon,tsensor",
- .data = hi6220_thermal_probe
+ .data = &hi6220_ops,
},
{
.compatible = "hisilicon,hi3660-tsensor",
- .data = hi3660_thermal_probe
+ .data = &hi3660_ops,
},
{ /* end */ }
};
@@ -527,9 +556,9 @@ static void hisi_thermal_toggle_sensor(struct hisi_thermal_sensor *sensor,
static int hisi_thermal_probe(struct platform_device *pdev)
{
struct hisi_thermal_data *data;
- int (*platform_probe)(struct hisi_thermal_data *);
struct device *dev = &pdev->dev;
- int ret;
+ struct resource *res;
+ int i, ret;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
@@ -537,41 +566,50 @@ static int hisi_thermal_probe(struct platform_device *pdev)
data->pdev = pdev;
platform_set_drvdata(pdev, data);
+ data->ops = of_device_get_match_data(dev);
- platform_probe = of_device_get_match_data(dev);
- if (!platform_probe) {
- dev_err(dev, "failed to get probe func\n");
- return -EINVAL;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ data->regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(data->regs)) {
+ dev_err(dev, "failed to get io address\n");
+ return PTR_ERR(data->regs);
}
- ret = platform_probe(data);
+ ret = data->ops->probe(data);
if (ret)
return ret;
- ret = hisi_thermal_register_sensor(pdev, data,
- &data->sensor);
- if (ret) {
- dev_err(dev, "failed to register thermal sensor: %d\n", ret);
- return ret;
- }
+ for (i = 0; i < data->nr_sensors; i++) {
+ struct hisi_thermal_sensor *sensor = &data->sensor[i];
- ret = data->enable_sensor(data);
- if (ret) {
- dev_err(dev, "Failed to setup the sensor: %d\n", ret);
- return ret;
- }
+ ret = hisi_thermal_register_sensor(pdev, sensor);
+ if (ret) {
+ dev_err(dev, "failed to register thermal sensor: %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = platform_get_irq_byname(pdev, sensor->irq_name);
+ if (ret < 0)
+ return ret;
- if (data->irq) {
- ret = devm_request_threaded_irq(dev, data->irq, NULL,
- hisi_thermal_alarm_irq_thread,
- IRQF_ONESHOT, "hisi_thermal", data);
+ ret = devm_request_threaded_irq(dev, ret, NULL,
+ hisi_thermal_alarm_irq_thread,
+ IRQF_ONESHOT, sensor->irq_name,
+ sensor);
if (ret < 0) {
- dev_err(dev, "failed to request alarm irq: %d\n", ret);
+ dev_err(dev, "Failed to request alarm irq: %d\n", ret);
return ret;
}
- }
- hisi_thermal_toggle_sensor(&data->sensor, true);
+ ret = data->ops->enable_sensor(sensor);
+ if (ret) {
+ dev_err(dev, "Failed to setup the sensor: %d\n", ret);
+ return ret;
+ }
+
+ hisi_thermal_toggle_sensor(sensor, true);
+ }
return 0;
}
@@ -579,11 +617,14 @@ static int hisi_thermal_probe(struct platform_device *pdev)
static int hisi_thermal_remove(struct platform_device *pdev)
{
struct hisi_thermal_data *data = platform_get_drvdata(pdev);
- struct hisi_thermal_sensor *sensor = &data->sensor;
+ int i;
- hisi_thermal_toggle_sensor(sensor, false);
+ for (i = 0; i < data->nr_sensors; i++) {
+ struct hisi_thermal_sensor *sensor = &data->sensor[i];
- data->disable_sensor(data);
+ hisi_thermal_toggle_sensor(sensor, false);
+ data->ops->disable_sensor(sensor);
+ }
return 0;
}
@@ -592,8 +633,10 @@ static int hisi_thermal_remove(struct platform_device *pdev)
static int hisi_thermal_suspend(struct device *dev)
{
struct hisi_thermal_data *data = dev_get_drvdata(dev);
+ int i;
- data->disable_sensor(data);
+ for (i = 0; i < data->nr_sensors; i++)
+ data->ops->disable_sensor(&data->sensor[i]);
return 0;
}
@@ -601,8 +644,12 @@ static int hisi_thermal_suspend(struct device *dev)
static int hisi_thermal_resume(struct device *dev)
{
struct hisi_thermal_data *data = dev_get_drvdata(dev);
+ int i, ret = 0;
+
+ for (i = 0; i < data->nr_sensors; i++)
+ ret |= data->ops->enable_sensor(&data->sensor[i]);
- return data->enable_sensor(data);
+ return ret;
}
#endif
diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
index aa452acb60b6..15661549eb67 100644
--- a/drivers/thermal/imx_thermal.c
+++ b/drivers/thermal/imx_thermal.c
@@ -725,7 +725,7 @@ static int imx_thermal_probe(struct platform_device *pdev)
} else {
ret = imx_init_from_tempmon_data(pdev);
if (ret) {
- dev_err(&pdev->dev, "failed to init from from fsl,tempmon-data\n");
+ dev_err(&pdev->dev, "failed to init from fsl,tempmon-data\n");
return ret;
}
}
@@ -762,9 +762,7 @@ static int imx_thermal_probe(struct platform_device *pdev)
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev,
"failed to get thermal clk: %d\n", ret);
- cpufreq_cooling_unregister(data->cdev);
- cpufreq_cpu_put(data->policy);
- return ret;
+ goto cpufreq_put;
}
/*
@@ -777,9 +775,7 @@ static int imx_thermal_probe(struct platform_device *pdev)
ret = clk_prepare_enable(data->thermal_clk);
if (ret) {
dev_err(&pdev->dev, "failed to enable thermal clk: %d\n", ret);
- cpufreq_cooling_unregister(data->cdev);
- cpufreq_cpu_put(data->policy);
- return ret;
+ goto cpufreq_put;
}
data->tz = thermal_zone_device_register("imx_thermal_zone",
@@ -792,10 +788,7 @@ static int imx_thermal_probe(struct platform_device *pdev)
ret = PTR_ERR(data->tz);
dev_err(&pdev->dev,
"failed to register thermal zone device %d\n", ret);
- clk_disable_unprepare(data->thermal_clk);
- cpufreq_cooling_unregister(data->cdev);
- cpufreq_cpu_put(data->policy);
- return ret;
+ goto clk_disable;
}
dev_info(&pdev->dev, "%s CPU temperature grade - max:%dC"
@@ -827,14 +820,20 @@ static int imx_thermal_probe(struct platform_device *pdev)
0, "imx_thermal", data);
if (ret < 0) {
dev_err(&pdev->dev, "failed to request alarm irq: %d\n", ret);
- clk_disable_unprepare(data->thermal_clk);
- thermal_zone_device_unregister(data->tz);
- cpufreq_cooling_unregister(data->cdev);
- cpufreq_cpu_put(data->policy);
- return ret;
+ goto thermal_zone_unregister;
}
return 0;
+
+thermal_zone_unregister:
+ thermal_zone_device_unregister(data->tz);
+clk_disable:
+ clk_disable_unprepare(data->thermal_clk);
+cpufreq_put:
+ cpufreq_cooling_unregister(data->cdev);
+ cpufreq_cpu_put(data->policy);
+
+ return ret;
}
static int imx_thermal_remove(struct platform_device *pdev)
diff --git a/drivers/thermal/intel_soc_dts_thermal.c b/drivers/thermal/intel_soc_dts_thermal.c
index 1e47511a6bd5..d748527d7a38 100644
--- a/drivers/thermal/intel_soc_dts_thermal.c
+++ b/drivers/thermal/intel_soc_dts_thermal.c
@@ -45,7 +45,7 @@ static irqreturn_t soc_irq_thread_fn(int irq, void *dev_data)
}
static const struct x86_cpu_id soc_thermal_ids[] = {
- { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT1, 0,
+ { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT, 0,
BYT_SOC_DTS_APIC_IRQ},
{}
};
diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
index 4f2816559205..4bfdb4a1e47d 100644
--- a/drivers/thermal/of-thermal.c
+++ b/drivers/thermal/of-thermal.c
@@ -19,23 +19,34 @@
/*** Private data structures to represent thermal device tree data ***/
/**
- * struct __thermal_bind_param - a match between trip and cooling device
+ * struct __thermal_cooling_bind_param - a cooling device for a trip point
* @cooling_device: a pointer to identify the referred cooling device
- * @trip_id: the trip point index
- * @usage: the percentage (from 0 to 100) of cooling contribution
* @min: minimum cooling state used at this trip point
* @max: maximum cooling state used at this trip point
*/
-struct __thermal_bind_params {
+struct __thermal_cooling_bind_param {
struct device_node *cooling_device;
- unsigned int trip_id;
- unsigned int usage;
unsigned long min;
unsigned long max;
};
/**
+ * struct __thermal_bind_param - a match between trip and cooling device
+ * @tcbp: a pointer to an array of cooling devices
+ * @count: number of elements in array
+ * @trip_id: the trip point index
+ * @usage: the percentage (from 0 to 100) of cooling contribution
+ */
+
+struct __thermal_bind_params {
+ struct __thermal_cooling_bind_param *tcbp;
+ unsigned int count;
+ unsigned int trip_id;
+ unsigned int usage;
+};
+
+/**
* struct __thermal_zone - internal representation of a thermal zone
* @mode: current thermal zone device mode (enabled/disabled)
* @passive_delay: polling interval while passive cooling is activated
@@ -192,25 +203,31 @@ static int of_thermal_bind(struct thermal_zone_device *thermal,
struct thermal_cooling_device *cdev)
{
struct __thermal_zone *data = thermal->devdata;
- int i;
+ struct __thermal_bind_params *tbp;
+ struct __thermal_cooling_bind_param *tcbp;
+ int i, j;
if (!data || IS_ERR(data))
return -ENODEV;
/* find where to bind */
for (i = 0; i < data->num_tbps; i++) {
- struct __thermal_bind_params *tbp = data->tbps + i;
+ tbp = data->tbps + i;
- if (tbp->cooling_device == cdev->np) {
- int ret;
+ for (j = 0; j < tbp->count; j++) {
+ tcbp = tbp->tcbp + j;
- ret = thermal_zone_bind_cooling_device(thermal,
+ if (tcbp->cooling_device == cdev->np) {
+ int ret;
+
+ ret = thermal_zone_bind_cooling_device(thermal,
tbp->trip_id, cdev,
- tbp->max,
- tbp->min,
+ tcbp->max,
+ tcbp->min,
tbp->usage);
- if (ret)
- return ret;
+ if (ret)
+ return ret;
+ }
}
}
@@ -221,22 +238,28 @@ static int of_thermal_unbind(struct thermal_zone_device *thermal,
struct thermal_cooling_device *cdev)
{
struct __thermal_zone *data = thermal->devdata;
- int i;
+ struct __thermal_bind_params *tbp;
+ struct __thermal_cooling_bind_param *tcbp;
+ int i, j;
if (!data || IS_ERR(data))
return -ENODEV;
/* find where to unbind */
for (i = 0; i < data->num_tbps; i++) {
- struct __thermal_bind_params *tbp = data->tbps + i;
+ tbp = data->tbps + i;
+
+ for (j = 0; j < tbp->count; j++) {
+ tcbp = tbp->tcbp + j;
- if (tbp->cooling_device == cdev->np) {
- int ret;
+ if (tcbp->cooling_device == cdev->np) {
+ int ret;
- ret = thermal_zone_unbind_cooling_device(thermal,
- tbp->trip_id, cdev);
- if (ret)
- return ret;
+ ret = thermal_zone_unbind_cooling_device(thermal,
+ tbp->trip_id, cdev);
+ if (ret)
+ return ret;
+ }
}
}
@@ -486,8 +509,8 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
if (sensor_specs.args_count >= 1) {
id = sensor_specs.args[0];
WARN(sensor_specs.args_count > 1,
- "%s: too many cells in sensor specifier %d\n",
- sensor_specs.np->name, sensor_specs.args_count);
+ "%pOFn: too many cells in sensor specifier %d\n",
+ sensor_specs.np, sensor_specs.args_count);
} else {
id = 0;
}
@@ -655,8 +678,9 @@ static int thermal_of_populate_bind_params(struct device_node *np,
int ntrips)
{
struct of_phandle_args cooling_spec;
+ struct __thermal_cooling_bind_param *__tcbp;
struct device_node *trip;
- int ret, i;
+ int ret, i, count;
u32 prop;
/* Default weight. Usage is optional */
@@ -683,20 +707,44 @@ static int thermal_of_populate_bind_params(struct device_node *np,
goto end;
}
- ret = of_parse_phandle_with_args(np, "cooling-device", "#cooling-cells",
- 0, &cooling_spec);
- if (ret < 0) {
- pr_err("missing cooling_device property\n");
+ count = of_count_phandle_with_args(np, "cooling-device",
+ "#cooling-cells");
+ if (!count) {
+ pr_err("Add a cooling_device property with at least one device\n");
goto end;
}
- __tbp->cooling_device = cooling_spec.np;
- if (cooling_spec.args_count >= 2) { /* at least min and max */
- __tbp->min = cooling_spec.args[0];
- __tbp->max = cooling_spec.args[1];
- } else {
- pr_err("wrong reference to cooling device, missing limits\n");
+
+ __tcbp = kcalloc(count, sizeof(*__tcbp), GFP_KERNEL);
+ if (!__tcbp)
+ goto end;
+
+ for (i = 0; i < count; i++) {
+ ret = of_parse_phandle_with_args(np, "cooling-device",
+ "#cooling-cells", i, &cooling_spec);
+ if (ret < 0) {
+ pr_err("Invalid cooling-device entry\n");
+ goto free_tcbp;
+ }
+
+ __tcbp[i].cooling_device = cooling_spec.np;
+
+ if (cooling_spec.args_count >= 2) { /* at least min and max */
+ __tcbp[i].min = cooling_spec.args[0];
+ __tcbp[i].max = cooling_spec.args[1];
+ } else {
+ pr_err("wrong reference to cooling device, missing limits\n");
+ }
}
+ __tbp->tcbp = __tcbp;
+ __tbp->count = count;
+
+ goto end;
+
+free_tcbp:
+ for (i = i - 1; i >= 0; i--)
+ of_node_put(__tcbp[i].cooling_device);
+ kfree(__tcbp);
end:
of_node_put(trip);
@@ -903,8 +951,16 @@ finish:
return tz;
free_tbps:
- for (i = i - 1; i >= 0; i--)
- of_node_put(tz->tbps[i].cooling_device);
+ for (i = i - 1; i >= 0; i--) {
+ struct __thermal_bind_params *tbp = tz->tbps + i;
+ int j;
+
+ for (j = 0; j < tbp->count; j++)
+ of_node_put(tbp->tcbp[j].cooling_device);
+
+ kfree(tbp->tcbp);
+ }
+
kfree(tz->tbps);
free_trips:
for (i = 0; i < tz->ntrips; i++)
@@ -920,10 +976,18 @@ free_tz:
static inline void of_thermal_free_zone(struct __thermal_zone *tz)
{
- int i;
+ struct __thermal_bind_params *tbp;
+ int i, j;
+
+ for (i = 0; i < tz->num_tbps; i++) {
+ tbp = tz->tbps + i;
+
+ for (j = 0; j < tbp->count; j++)
+ of_node_put(tbp->tcbp[j].cooling_device);
+
+ kfree(tbp->tcbp);
+ }
- for (i = 0; i < tz->num_tbps; i++)
- of_node_put(tz->tbps[i].cooling_device);
kfree(tz->tbps);
for (i = 0; i < tz->ntrips; i++)
of_node_put(tz->trips[i].np);
@@ -963,8 +1027,8 @@ int __init of_parse_thermal_zones(void)
tz = thermal_of_build_thermal_zone(child);
if (IS_ERR(tz)) {
- pr_err("failed to build thermal zone %s: %ld\n",
- child->name,
+ pr_err("failed to build thermal zone %pOFn: %ld\n",
+ child,
PTR_ERR(tz));
continue;
}
@@ -998,7 +1062,7 @@ int __init of_parse_thermal_zones(void)
tz->passive_delay,
tz->polling_delay);
if (IS_ERR(zone)) {
- pr_err("Failed to build %s zone %ld\n", child->name,
+ pr_err("Failed to build %pOFn zone %ld\n", child,
PTR_ERR(zone));
kfree(tzp);
kfree(ops);
diff --git a/drivers/thermal/qcom-spmi-temp-alarm.c b/drivers/thermal/qcom-spmi-temp-alarm.c
index ad4f3a8d6560..b2d5d5bf4a9b 100644
--- a/drivers/thermal/qcom-spmi-temp-alarm.c
+++ b/drivers/thermal/qcom-spmi-temp-alarm.c
@@ -23,6 +23,8 @@
#include <linux/regmap.h>
#include <linux/thermal.h>
+#include "thermal_core.h"
+
#define QPNP_TM_REG_TYPE 0x04
#define QPNP_TM_REG_SUBTYPE 0x05
#define QPNP_TM_REG_STATUS 0x08
@@ -37,9 +39,11 @@
#define STATUS_GEN2_STATE_MASK GENMASK(6, 4)
#define STATUS_GEN2_STATE_SHIFT 4
-#define SHUTDOWN_CTRL1_OVERRIDE_MASK GENMASK(7, 6)
+#define SHUTDOWN_CTRL1_OVERRIDE_S2 BIT(6)
#define SHUTDOWN_CTRL1_THRESHOLD_MASK GENMASK(1, 0)
+#define SHUTDOWN_CTRL1_RATE_25HZ BIT(3)
+
#define ALARM_CTRL_FORCE_ENABLE BIT(7)
/*
@@ -56,12 +60,19 @@
#define TEMP_THRESH_STEP 5000 /* Threshold step: 5 C */
#define THRESH_MIN 0
+#define THRESH_MAX 3
+
+/* Stage 2 Threshold Min: 125 C */
+#define STAGE2_THRESHOLD_MIN 125000
+/* Stage 2 Threshold Max: 140 C */
+#define STAGE2_THRESHOLD_MAX 140000
/* Temperature in Milli Celsius reported during stage 0 if no ADC is present */
#define DEFAULT_TEMP 37000
struct qpnp_tm_chip {
struct regmap *map;
+ struct device *dev;
struct thermal_zone_device *tz_dev;
unsigned int subtype;
long temp;
@@ -69,6 +80,10 @@ struct qpnp_tm_chip {
unsigned int stage;
unsigned int prev_stage;
unsigned int base;
+ /* protects .thresh, .stage and chip registers */
+ struct mutex lock;
+ bool initialized;
+
struct iio_channel *adc;
};
@@ -125,6 +140,8 @@ static int qpnp_tm_update_temp_no_adc(struct qpnp_tm_chip *chip)
unsigned int stage, stage_new, stage_old;
int ret;
+ WARN_ON(!mutex_is_locked(&chip->lock));
+
ret = qpnp_tm_get_temp_stage(chip);
if (ret < 0)
return ret;
@@ -163,8 +180,15 @@ static int qpnp_tm_get_temp(void *data, int *temp)
if (!temp)
return -EINVAL;
+ if (!chip->initialized) {
+ *temp = DEFAULT_TEMP;
+ return 0;
+ }
+
if (!chip->adc) {
+ mutex_lock(&chip->lock);
ret = qpnp_tm_update_temp_no_adc(chip);
+ mutex_unlock(&chip->lock);
if (ret < 0)
return ret;
} else {
@@ -180,8 +204,72 @@ static int qpnp_tm_get_temp(void *data, int *temp)
return 0;
}
+static int qpnp_tm_update_critical_trip_temp(struct qpnp_tm_chip *chip,
+ int temp)
+{
+ u8 reg;
+ bool disable_s2_shutdown = false;
+
+ WARN_ON(!mutex_is_locked(&chip->lock));
+
+ /*
+ * Default: S2 and S3 shutdown enabled, thresholds at
+ * 105C/125C/145C, monitoring at 25Hz
+ */
+ reg = SHUTDOWN_CTRL1_RATE_25HZ;
+
+ if (temp == THERMAL_TEMP_INVALID ||
+ temp < STAGE2_THRESHOLD_MIN) {
+ chip->thresh = THRESH_MIN;
+ goto skip;
+ }
+
+ if (temp <= STAGE2_THRESHOLD_MAX) {
+ chip->thresh = THRESH_MAX -
+ ((STAGE2_THRESHOLD_MAX - temp) /
+ TEMP_THRESH_STEP);
+ disable_s2_shutdown = true;
+ } else {
+ chip->thresh = THRESH_MAX;
+
+ if (chip->adc)
+ disable_s2_shutdown = true;
+ else
+ dev_warn(chip->dev,
+ "No ADC is configured and critical temperature is above the maximum stage 2 threshold of 140 C! Configuring stage 2 shutdown at 140 C.\n");
+ }
+
+skip:
+ reg |= chip->thresh;
+ if (disable_s2_shutdown)
+ reg |= SHUTDOWN_CTRL1_OVERRIDE_S2;
+
+ return qpnp_tm_write(chip, QPNP_TM_REG_SHUTDOWN_CTRL1, reg);
+}
+
+static int qpnp_tm_set_trip_temp(void *data, int trip, int temp)
+{
+ struct qpnp_tm_chip *chip = data;
+ const struct thermal_trip *trip_points;
+ int ret;
+
+ trip_points = of_thermal_get_trip_points(chip->tz_dev);
+ if (!trip_points)
+ return -EINVAL;
+
+ if (trip_points[trip].type != THERMAL_TRIP_CRITICAL)
+ return 0;
+
+ mutex_lock(&chip->lock);
+ ret = qpnp_tm_update_critical_trip_temp(chip, temp);
+ mutex_unlock(&chip->lock);
+
+ return ret;
+}
+
static const struct thermal_zone_of_device_ops qpnp_tm_sensor_ops = {
.get_temp = qpnp_tm_get_temp,
+ .set_trip_temp = qpnp_tm_set_trip_temp,
};
static irqreturn_t qpnp_tm_isr(int irq, void *data)
@@ -193,6 +281,29 @@ static irqreturn_t qpnp_tm_isr(int irq, void *data)
return IRQ_HANDLED;
}
+static int qpnp_tm_get_critical_trip_temp(struct qpnp_tm_chip *chip)
+{
+ int ntrips;
+ const struct thermal_trip *trips;
+ int i;
+
+ ntrips = of_thermal_get_ntrips(chip->tz_dev);
+ if (ntrips <= 0)
+ return THERMAL_TEMP_INVALID;
+
+ trips = of_thermal_get_trip_points(chip->tz_dev);
+ if (!trips)
+ return THERMAL_TEMP_INVALID;
+
+ for (i = 0; i < ntrips; i++) {
+ if (of_thermal_is_trip_valid(chip->tz_dev, i) &&
+ trips[i].type == THERMAL_TRIP_CRITICAL)
+ return trips[i].temperature;
+ }
+
+ return THERMAL_TEMP_INVALID;
+}
+
/*
* This function initializes the internal temp value based on only the
* current thermal stage and threshold. Setup threshold control and
@@ -203,17 +314,20 @@ static int qpnp_tm_init(struct qpnp_tm_chip *chip)
unsigned int stage;
int ret;
u8 reg = 0;
+ int crit_temp;
+
+ mutex_lock(&chip->lock);
ret = qpnp_tm_read(chip, QPNP_TM_REG_SHUTDOWN_CTRL1, &reg);
if (ret < 0)
- return ret;
+ goto out;
chip->thresh = reg & SHUTDOWN_CTRL1_THRESHOLD_MASK;
chip->temp = DEFAULT_TEMP;
ret = qpnp_tm_get_temp_stage(chip);
if (ret < 0)
- return ret;
+ goto out;
chip->stage = ret;
stage = chip->subtype == QPNP_TM_SUBTYPE_GEN1
@@ -224,21 +338,19 @@ static int qpnp_tm_init(struct qpnp_tm_chip *chip)
(stage - 1) * TEMP_STAGE_STEP +
TEMP_THRESH_MIN;
- /*
- * Set threshold and disable software override of stage 2 and 3
- * shutdowns.
- */
- chip->thresh = THRESH_MIN;
- reg &= ~(SHUTDOWN_CTRL1_OVERRIDE_MASK | SHUTDOWN_CTRL1_THRESHOLD_MASK);
- reg |= chip->thresh & SHUTDOWN_CTRL1_THRESHOLD_MASK;
- ret = qpnp_tm_write(chip, QPNP_TM_REG_SHUTDOWN_CTRL1, reg);
+ crit_temp = qpnp_tm_get_critical_trip_temp(chip);
+ ret = qpnp_tm_update_critical_trip_temp(chip, crit_temp);
if (ret < 0)
- return ret;
+ goto out;
/* Enable the thermal alarm PMIC module in always-on mode. */
reg = ALARM_CTRL_FORCE_ENABLE;
ret = qpnp_tm_write(chip, QPNP_TM_REG_ALARM_CTRL, reg);
+ chip->initialized = true;
+
+out:
+ mutex_unlock(&chip->lock);
return ret;
}
@@ -257,6 +369,9 @@ static int qpnp_tm_probe(struct platform_device *pdev)
return -ENOMEM;
dev_set_drvdata(&pdev->dev, chip);
+ chip->dev = &pdev->dev;
+
+ mutex_init(&chip->lock);
chip->map = dev_get_regmap(pdev->dev.parent, NULL);
if (!chip->map)
@@ -302,6 +417,18 @@ static int qpnp_tm_probe(struct platform_device *pdev)
chip->subtype = subtype;
+ /*
+ * Register the sensor before initializing the hardware to be able to
+ * read the trip points. get_temp() returns the default temperature
+ * before the hardware initialization is completed.
+ */
+ chip->tz_dev = devm_thermal_zone_of_sensor_register(
+ &pdev->dev, 0, chip, &qpnp_tm_sensor_ops);
+ if (IS_ERR(chip->tz_dev)) {
+ dev_err(&pdev->dev, "failed to register sensor\n");
+ return PTR_ERR(chip->tz_dev);
+ }
+
ret = qpnp_tm_init(chip);
if (ret < 0) {
dev_err(&pdev->dev, "init failed\n");
@@ -313,12 +440,7 @@ static int qpnp_tm_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
- chip->tz_dev = devm_thermal_zone_of_sensor_register(&pdev->dev, 0, chip,
- &qpnp_tm_sensor_ops);
- if (IS_ERR(chip->tz_dev)) {
- dev_err(&pdev->dev, "failed to register sensor\n");
- return PTR_ERR(chip->tz_dev);
- }
+ thermal_zone_device_update(chip->tz_dev, THERMAL_EVENT_UNSPECIFIED);
return 0;
}
diff --git a/drivers/thermal/qcom/tsens-8916.c b/drivers/thermal/qcom/tsens-8916.c
index fdf561b8b81d..c6dd620ac029 100644
--- a/drivers/thermal/qcom/tsens-8916.c
+++ b/drivers/thermal/qcom/tsens-8916.c
@@ -1,15 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <linux/platform_device.h>
@@ -109,5 +100,6 @@ static const struct tsens_ops ops_8916 = {
const struct tsens_data data_8916 = {
.num_sensors = 5,
.ops = &ops_8916,
+ .reg_offsets = { [SROT_CTRL_OFFSET] = 0x0 },
.hw_ids = (unsigned int []){0, 1, 2, 4, 5 },
};
diff --git a/drivers/thermal/qcom/tsens-8960.c b/drivers/thermal/qcom/tsens-8960.c
index 0451277d3a8f..0f0adb302a7b 100644
--- a/drivers/thermal/qcom/tsens-8960.c
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -1,15 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <linux/platform_device.h>
@@ -69,7 +60,7 @@ static int suspend_8960(struct tsens_device *tmdev)
{
int ret;
unsigned int mask;
- struct regmap *map = tmdev->map;
+ struct regmap *map = tmdev->tm_map;
ret = regmap_read(map, THRESHOLD_ADDR, &tmdev->ctx.threshold);
if (ret)
@@ -94,7 +85,7 @@ static int suspend_8960(struct tsens_device *tmdev)
static int resume_8960(struct tsens_device *tmdev)
{
int ret;
- struct regmap *map = tmdev->map;
+ struct regmap *map = tmdev->tm_map;
ret = regmap_update_bits(map, CNTL_ADDR, SW_RST, SW_RST);
if (ret)
@@ -126,12 +117,12 @@ static int enable_8960(struct tsens_device *tmdev, int id)
int ret;
u32 reg, mask;
- ret = regmap_read(tmdev->map, CNTL_ADDR, &reg);
+ ret = regmap_read(tmdev->tm_map, CNTL_ADDR, &reg);
if (ret)
return ret;
mask = BIT(id + SENSOR0_SHIFT);
- ret = regmap_write(tmdev->map, CNTL_ADDR, reg | SW_RST);
+ ret = regmap_write(tmdev->tm_map, CNTL_ADDR, reg | SW_RST);
if (ret)
return ret;
@@ -140,7 +131,7 @@ static int enable_8960(struct tsens_device *tmdev, int id)
else
reg |= mask | SLP_CLK_ENA_8660 | EN;
- ret = regmap_write(tmdev->map, CNTL_ADDR, reg);
+ ret = regmap_write(tmdev->tm_map, CNTL_ADDR, reg);
if (ret)
return ret;
@@ -157,7 +148,7 @@ static void disable_8960(struct tsens_device *tmdev)
mask <<= SENSOR0_SHIFT;
mask |= EN;
- ret = regmap_read(tmdev->map, CNTL_ADDR, &reg_cntl);
+ ret = regmap_read(tmdev->tm_map, CNTL_ADDR, &reg_cntl);
if (ret)
return;
@@ -168,7 +159,7 @@ static void disable_8960(struct tsens_device *tmdev)
else
reg_cntl &= ~SLP_CLK_ENA_8660;
- regmap_write(tmdev->map, CNTL_ADDR, reg_cntl);
+ regmap_write(tmdev->tm_map, CNTL_ADDR, reg_cntl);
}
static int init_8960(struct tsens_device *tmdev)
@@ -176,8 +167,8 @@ static int init_8960(struct tsens_device *tmdev)
int ret, i;
u32 reg_cntl;
- tmdev->map = dev_get_regmap(tmdev->dev, NULL);
- if (!tmdev->map)
+ tmdev->tm_map = dev_get_regmap(tmdev->dev, NULL);
+ if (!tmdev->tm_map)
return -ENODEV;
/*
@@ -193,14 +184,14 @@ static int init_8960(struct tsens_device *tmdev)
}
reg_cntl = SW_RST;
- ret = regmap_update_bits(tmdev->map, CNTL_ADDR, SW_RST, reg_cntl);
+ ret = regmap_update_bits(tmdev->tm_map, CNTL_ADDR, SW_RST, reg_cntl);
if (ret)
return ret;
if (tmdev->num_sensors > 1) {
reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18);
reg_cntl &= ~SW_RST;
- ret = regmap_update_bits(tmdev->map, CONFIG_ADDR,
+ ret = regmap_update_bits(tmdev->tm_map, CONFIG_ADDR,
CONFIG_MASK, CONFIG);
} else {
reg_cntl |= SLP_CLK_ENA_8660 | (MEASURE_PERIOD << 16);
@@ -209,12 +200,12 @@ static int init_8960(struct tsens_device *tmdev)
}
reg_cntl |= GENMASK(tmdev->num_sensors - 1, 0) << SENSOR0_SHIFT;
- ret = regmap_write(tmdev->map, CNTL_ADDR, reg_cntl);
+ ret = regmap_write(tmdev->tm_map, CNTL_ADDR, reg_cntl);
if (ret)
return ret;
reg_cntl |= EN;
- ret = regmap_write(tmdev->map, CNTL_ADDR, reg_cntl);
+ ret = regmap_write(tmdev->tm_map, CNTL_ADDR, reg_cntl);
if (ret)
return ret;
@@ -261,12 +252,12 @@ static int get_temp_8960(struct tsens_device *tmdev, int id, int *temp)
timeout = jiffies + usecs_to_jiffies(TIMEOUT_US);
do {
- ret = regmap_read(tmdev->map, INT_STATUS_ADDR, &trdy);
+ ret = regmap_read(tmdev->tm_map, INT_STATUS_ADDR, &trdy);
if (ret)
return ret;
if (!(trdy & TRDY_MASK))
continue;
- ret = regmap_read(tmdev->map, s->status, &code);
+ ret = regmap_read(tmdev->tm_map, s->status, &code);
if (ret)
return ret;
*temp = code_to_mdegC(code, s);
diff --git a/drivers/thermal/qcom/tsens-8974.c b/drivers/thermal/qcom/tsens-8974.c
index 9baf77e8cbe3..3d3fda3d731b 100644
--- a/drivers/thermal/qcom/tsens-8974.c
+++ b/drivers/thermal/qcom/tsens-8974.c
@@ -1,15 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <linux/platform_device.h>
@@ -241,4 +232,5 @@ static const struct tsens_ops ops_8974 = {
const struct tsens_data data_8974 = {
.num_sensors = 11,
.ops = &ops_8974,
+ .reg_offsets = { [SROT_CTRL_OFFSET] = 0x0 },
};
diff --git a/drivers/thermal/qcom/tsens-common.c b/drivers/thermal/qcom/tsens-common.c
index 6207d8d92351..3be4be2e0465 100644
--- a/drivers/thermal/qcom/tsens-common.c
+++ b/drivers/thermal/qcom/tsens-common.c
@@ -1,15 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <linux/err.h>
@@ -21,7 +12,11 @@
#include <linux/regmap.h>
#include "tsens.h"
-#define S0_ST_ADDR 0x1030
+/* SROT */
+#define TSENS_EN BIT(0)
+
+/* TM */
+#define STATUS_OFFSET 0x30
#define SN_ADDR_OFFSET 0x4
#define SN_ST_TEMP_MASK 0x3ff
#define CAL_DEGC_PT1 30
@@ -107,8 +102,8 @@ int get_temp_common(struct tsens_device *tmdev, int id, int *temp)
unsigned int status_reg;
int last_temp = 0, ret;
- status_reg = S0_ST_ADDR + s->hw_id * SN_ADDR_OFFSET;
- ret = regmap_read(tmdev->map, status_reg, &code);
+ status_reg = tmdev->tm_offset + STATUS_OFFSET + s->hw_id * SN_ADDR_OFFSET;
+ ret = regmap_read(tmdev->tm_map, status_reg, &code);
if (ret)
return ret;
last_temp = code & SN_ST_TEMP_MASK;
@@ -126,29 +121,52 @@ static const struct regmap_config tsens_config = {
int __init init_common(struct tsens_device *tmdev)
{
- void __iomem *base;
+ void __iomem *tm_base, *srot_base;
struct resource *res;
+ u32 code;
+ int ret;
struct platform_device *op = of_find_device_by_node(tmdev->dev->of_node);
+ u16 ctrl_offset = tmdev->reg_offsets[SROT_CTRL_OFFSET];
if (!op)
return -EINVAL;
- /* The driver only uses the TM register address space for now */
if (op->num_resources > 1) {
+ /* DT with separate SROT and TM address space */
tmdev->tm_offset = 0;
+ res = platform_get_resource(op, IORESOURCE_MEM, 1);
+ srot_base = devm_ioremap_resource(&op->dev, res);
+ if (IS_ERR(srot_base))
+ return PTR_ERR(srot_base);
+
+ tmdev->srot_map = devm_regmap_init_mmio(tmdev->dev,
+ srot_base, &tsens_config);
+ if (IS_ERR(tmdev->srot_map))
+ return PTR_ERR(tmdev->srot_map);
+
} else {
/* old DTs where SROT and TM were in a contiguous 2K block */
tmdev->tm_offset = 0x1000;
}
res = platform_get_resource(op, IORESOURCE_MEM, 0);
- base = devm_ioremap_resource(&op->dev, res);
- if (IS_ERR(base))
- return PTR_ERR(base);
-
- tmdev->map = devm_regmap_init_mmio(tmdev->dev, base, &tsens_config);
- if (IS_ERR(tmdev->map))
- return PTR_ERR(tmdev->map);
+ tm_base = devm_ioremap_resource(&op->dev, res);
+ if (IS_ERR(tm_base))
+ return PTR_ERR(tm_base);
+
+ tmdev->tm_map = devm_regmap_init_mmio(tmdev->dev, tm_base, &tsens_config);
+ if (IS_ERR(tmdev->tm_map))
+ return PTR_ERR(tmdev->tm_map);
+
+ if (tmdev->srot_map) {
+ ret = regmap_read(tmdev->srot_map, ctrl_offset, &code);
+ if (ret)
+ return ret;
+ if (!(code & TSENS_EN)) {
+ dev_err(tmdev->dev, "tsens device is not enabled\n");
+ return -ENODEV;
+ }
+ }
return 0;
}
diff --git a/drivers/thermal/qcom/tsens-v2.c b/drivers/thermal/qcom/tsens-v2.c
index 44da02f594ac..381a212872bf 100644
--- a/drivers/thermal/qcom/tsens-v2.c
+++ b/drivers/thermal/qcom/tsens-v2.c
@@ -21,7 +21,7 @@ static int get_temp_tsens_v2(struct tsens_device *tmdev, int id, int *temp)
int ret;
status_reg = tmdev->tm_offset + STATUS_OFFSET + s->hw_id * 4;
- ret = regmap_read(tmdev->map, status_reg, &code);
+ ret = regmap_read(tmdev->tm_map, status_reg, &code);
if (ret)
return ret;
last_temp = code & LAST_TEMP_MASK;
@@ -29,7 +29,7 @@ static int get_temp_tsens_v2(struct tsens_device *tmdev, int id, int *temp)
goto done;
/* Try a second time */
- ret = regmap_read(tmdev->map, status_reg, &code);
+ ret = regmap_read(tmdev->tm_map, status_reg, &code);
if (ret)
return ret;
if (code & STATUS_VALID_BIT) {
@@ -40,7 +40,7 @@ static int get_temp_tsens_v2(struct tsens_device *tmdev, int id, int *temp)
}
/* Try a third/last time */
- ret = regmap_read(tmdev->map, status_reg, &code);
+ ret = regmap_read(tmdev->tm_map, status_reg, &code);
if (ret)
return ret;
if (code & STATUS_VALID_BIT) {
@@ -68,10 +68,12 @@ static const struct tsens_ops ops_generic_v2 = {
const struct tsens_data data_tsens_v2 = {
.ops = &ops_generic_v2,
+ .reg_offsets = { [SROT_CTRL_OFFSET] = 0x4 },
};
/* Kept around for backward compatibility with old msm8996.dtsi */
const struct tsens_data data_8996 = {
.num_sensors = 13,
.ops = &ops_generic_v2,
+ .reg_offsets = { [SROT_CTRL_OFFSET] = 0x4 },
};
diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
index a2c9bfae3d86..f1ec9bbe4717 100644
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -1,15 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <linux/err.h>
@@ -89,11 +80,6 @@ static int tsens_register(struct tsens_device *tmdev)
{
int i;
struct thermal_zone_device *tzd;
- u32 *hw_id, n = tmdev->num_sensors;
-
- hw_id = devm_kcalloc(tmdev->dev, n, sizeof(u32), GFP_KERNEL);
- if (!hw_id)
- return -ENOMEM;
for (i = 0; i < tmdev->num_sensors; i++) {
tmdev->sensor[i].tmdev = tmdev;
@@ -158,6 +144,9 @@ static int tsens_probe(struct platform_device *pdev)
else
tmdev->sensor[i].hw_id = i;
}
+ for (i = 0; i < REG_ARRAY_SIZE; i++) {
+ tmdev->reg_offsets[i] = data->reg_offsets[i];
+ }
if (!tmdev->ops || !tmdev->ops->init || !tmdev->ops->get_temp)
return -EINVAL;
diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
index 14331eb45a86..7b7feee5dc46 100644
--- a/drivers/thermal/qcom/tsens.h
+++ b/drivers/thermal/qcom/tsens.h
@@ -1,15 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
+
#ifndef __QCOM_TSENS_H__
#define __QCOM_TSENS_H__
@@ -55,15 +48,23 @@ struct tsens_ops {
int (*get_trend)(struct tsens_device *, int, enum thermal_trend *);
};
+enum reg_list {
+ SROT_CTRL_OFFSET,
+
+ REG_ARRAY_SIZE,
+};
+
/**
* struct tsens_data - tsens instance specific data
* @num_sensors: Max number of sensors supported by platform
* @ops: operations the tsens instance supports
* @hw_ids: Subset of sensors ids supported by platform, if not the first n
+ * @reg_offsets: Register offsets for commonly used registers
*/
struct tsens_data {
const u32 num_sensors;
const struct tsens_ops *ops;
+ const u16 reg_offsets[REG_ARRAY_SIZE];
unsigned int *hw_ids;
};
@@ -76,8 +77,10 @@ struct tsens_context {
struct tsens_device {
struct device *dev;
u32 num_sensors;
- struct regmap *map;
+ struct regmap *tm_map;
+ struct regmap *srot_map;
u32 tm_offset;
+ u16 reg_offsets[REG_ARRAY_SIZE];
struct tsens_context ctx;
const struct tsens_ops *ops;
struct tsens_sensor sensor[0];
diff --git a/drivers/thermal/qoriq_thermal.c b/drivers/thermal/qoriq_thermal.c
index 450ed66edf58..18c711b19514 100644
--- a/drivers/thermal/qoriq_thermal.c
+++ b/drivers/thermal/qoriq_thermal.c
@@ -119,8 +119,8 @@ static int qoriq_tmu_get_sensor_id(void)
if (sensor_specs.args_count >= 1) {
id = sensor_specs.args[0];
WARN(sensor_specs.args_count > 1,
- "%s: too many cells in sensor specifier %d\n",
- sensor_specs.np->name, sensor_specs.args_count);
+ "%pOFn: too many cells in sensor specifier %d\n",
+ sensor_specs.np, sensor_specs.args_count);
} else {
id = 0;
}
@@ -294,6 +294,7 @@ static SIMPLE_DEV_PM_OPS(qoriq_tmu_pm_ops,
static const struct of_device_id qoriq_tmu_match[] = {
{ .compatible = "fsl,qoriq-tmu", },
+ { .compatible = "fsl,imx8mq-tmu", },
{},
};
MODULE_DEVICE_TABLE(of, qoriq_tmu_match);
diff --git a/drivers/thermal/rcar_gen3_thermal.c b/drivers/thermal/rcar_gen3_thermal.c
index 7aed5337bdd3..75786cc8e2f9 100644
--- a/drivers/thermal/rcar_gen3_thermal.c
+++ b/drivers/thermal/rcar_gen3_thermal.c
@@ -318,9 +318,11 @@ static void rcar_gen3_thermal_init(struct rcar_gen3_thermal_tsc *tsc)
}
static const struct of_device_id rcar_gen3_thermal_dt_ids[] = {
+ { .compatible = "renesas,r8a774a1-thermal", },
{ .compatible = "renesas,r8a7795-thermal", },
{ .compatible = "renesas,r8a7796-thermal", },
{ .compatible = "renesas,r8a77965-thermal", },
+ { .compatible = "renesas,r8a77980-thermal", },
{},
};
MODULE_DEVICE_TABLE(of, rcar_gen3_thermal_dt_ids);
diff --git a/drivers/thermal/rcar_thermal.c b/drivers/thermal/rcar_thermal.c
index 78f932822d38..8014a207d8d9 100644
--- a/drivers/thermal/rcar_thermal.c
+++ b/drivers/thermal/rcar_thermal.c
@@ -113,6 +113,10 @@ static const struct of_device_id rcar_thermal_dt_ids[] = {
.data = &rcar_gen2_thermal,
},
{
+ .compatible = "renesas,thermal-r8a77970",
+ .data = &rcar_gen3_thermal,
+ },
+ {
.compatible = "renesas,thermal-r8a77995",
.data = &rcar_gen3_thermal,
},
@@ -434,8 +438,8 @@ static irqreturn_t rcar_thermal_irq(int irq, void *data)
rcar_thermal_for_each_priv(priv, common) {
if (rcar_thermal_had_changed(priv, status)) {
rcar_thermal_irq_disable(priv);
- schedule_delayed_work(&priv->work,
- msecs_to_jiffies(300));
+ queue_delayed_work(system_freezable_wq, &priv->work,
+ msecs_to_jiffies(300));
}
}
@@ -453,6 +457,7 @@ static int rcar_thermal_remove(struct platform_device *pdev)
rcar_thermal_for_each_priv(priv, common) {
rcar_thermal_irq_disable(priv);
+ cancel_delayed_work_sync(&priv->work);
if (priv->chip->use_of_thermal)
thermal_remove_hwmon_sysfs(priv->zone);
else
@@ -492,7 +497,7 @@ static int rcar_thermal_probe(struct platform_device *pdev)
pm_runtime_get_sync(dev);
for (i = 0; i < chip->nirqs; i++) {
- irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, i);
if (!irq)
continue;
if (!common->base) {
diff --git a/drivers/thermal/st/Kconfig b/drivers/thermal/st/Kconfig
index 490fdbe22eea..b80f9a9e4f8f 100644
--- a/drivers/thermal/st/Kconfig
+++ b/drivers/thermal/st/Kconfig
@@ -1,3 +1,7 @@
+#
+# STMicroelectronics thermal drivers configuration
+#
+
config ST_THERMAL
tristate "Thermal sensors on STMicroelectronics STi series of SoCs"
help
@@ -10,3 +14,13 @@ config ST_THERMAL_SYSCFG
config ST_THERMAL_MEMMAP
select ST_THERMAL
tristate "STi series memory mapped access based thermal sensors"
+
+config STM32_THERMAL
+ tristate "Thermal framework support on STMicroelectronics STM32 series of SoCs"
+ depends on MACH_STM32MP157
+ default y
+ help
+ Support for thermal framework on STMicroelectronics STM32 series of
+ SoCs. This thermal driver allows to access to general thermal framework
+ functionalities and to acces to SoC sensor functionalities. This
+ configuration is fully dependent of MACH_STM32MP157.
diff --git a/drivers/thermal/st/Makefile b/drivers/thermal/st/Makefile
index b38878977bd8..b2b9e9b96296 100644
--- a/drivers/thermal/st/Makefile
+++ b/drivers/thermal/st/Makefile
@@ -1,3 +1,4 @@
obj-$(CONFIG_ST_THERMAL) := st_thermal.o
obj-$(CONFIG_ST_THERMAL_SYSCFG) += st_thermal_syscfg.o
obj-$(CONFIG_ST_THERMAL_MEMMAP) += st_thermal_memmap.o
+obj-$(CONFIG_STM32_THERMAL) := stm_thermal.o \ No newline at end of file
diff --git a/drivers/thermal/st/stm_thermal.c b/drivers/thermal/st/stm_thermal.c
new file mode 100644
index 000000000000..47623da0f91b
--- /dev/null
+++ b/drivers/thermal/st/stm_thermal.c
@@ -0,0 +1,760 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Author: David Hernandez Sanchez <david.hernandezsanchez@st.com> for
+ * STMicroelectronics.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/thermal.h>
+
+#include "../thermal_core.h"
+#include "../thermal_hwmon.h"
+
+/* DTS register offsets */
+#define DTS_CFGR1_OFFSET 0x0
+#define DTS_T0VALR1_OFFSET 0x8
+#define DTS_RAMPVALR_OFFSET 0X10
+#define DTS_ITR1_OFFSET 0x14
+#define DTS_DR_OFFSET 0x1C
+#define DTS_SR_OFFSET 0x20
+#define DTS_ITENR_OFFSET 0x24
+#define DTS_CIFR_OFFSET 0x28
+
+/* DTS_CFGR1 register mask definitions */
+#define HSREF_CLK_DIV_MASK GENMASK(30, 24)
+#define TS1_SMP_TIME_MASK GENMASK(19, 16)
+#define TS1_INTRIG_SEL_MASK GENMASK(11, 8)
+
+/* DTS_T0VALR1 register mask definitions */
+#define TS1_T0_MASK GENMASK(17, 16)
+#define TS1_FMT0_MASK GENMASK(15, 0)
+
+/* DTS_RAMPVALR register mask definitions */
+#define TS1_RAMP_COEFF_MASK GENMASK(15, 0)
+
+/* DTS_ITR1 register mask definitions */
+#define TS1_HITTHD_MASK GENMASK(31, 16)
+#define TS1_LITTHD_MASK GENMASK(15, 0)
+
+/* DTS_DR register mask definitions */
+#define TS1_MFREQ_MASK GENMASK(15, 0)
+
+/* Less significant bit position definitions */
+#define TS1_T0_POS 16
+#define TS1_SMP_TIME_POS 16
+#define TS1_HITTHD_POS 16
+#define HSREF_CLK_DIV_POS 24
+
+/* DTS_CFGR1 bit definitions */
+#define TS1_EN BIT(0)
+#define TS1_START BIT(4)
+#define REFCLK_SEL BIT(20)
+#define REFCLK_LSE REFCLK_SEL
+#define Q_MEAS_OPT BIT(21)
+#define CALIBRATION_CONTROL Q_MEAS_OPT
+
+/* DTS_SR bit definitions */
+#define TS_RDY BIT(15)
+/* Bit definitions below are common for DTS_SR, DTS_ITENR and DTS_CIFR */
+#define HIGH_THRESHOLD BIT(2)
+#define LOW_THRESHOLD BIT(1)
+
+/* Constants */
+#define ADJUST 100
+#define ONE_MHZ 1000000
+#define POLL_TIMEOUT 5000
+#define STARTUP_TIME 40
+#define TS1_T0_VAL0 30
+#define TS1_T0_VAL1 130
+#define NO_HW_TRIG 0
+
+/* The Thermal Framework expects millidegrees */
+#define mcelsius(temp) ((temp) * 1000)
+
+/* The Sensor expects oC degrees */
+#define celsius(temp) ((temp) / 1000)
+
+struct stm_thermal_sensor {
+ struct device *dev;
+ struct thermal_zone_device *th_dev;
+ enum thermal_device_mode mode;
+ struct clk *clk;
+ int high_temp;
+ int low_temp;
+ int temp_critical;
+ int temp_passive;
+ unsigned int low_temp_enabled;
+ int num_trips;
+ int irq;
+ unsigned int irq_enabled;
+ void __iomem *base;
+ int t0, fmt0, ramp_coeff;
+};
+
+static irqreturn_t stm_thermal_alarm_irq(int irq, void *sdata)
+{
+ struct stm_thermal_sensor *sensor = sdata;
+
+ disable_irq_nosync(irq);
+ sensor->irq_enabled = false;
+
+ return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t stm_thermal_alarm_irq_thread(int irq, void *sdata)
+{
+ u32 value;
+ struct stm_thermal_sensor *sensor = sdata;
+
+ /* read IT reason in SR and clear flags */
+ value = readl_relaxed(sensor->base + DTS_SR_OFFSET);
+
+ if ((value & LOW_THRESHOLD) == LOW_THRESHOLD)
+ writel_relaxed(LOW_THRESHOLD, sensor->base + DTS_CIFR_OFFSET);
+
+ if ((value & HIGH_THRESHOLD) == HIGH_THRESHOLD)
+ writel_relaxed(HIGH_THRESHOLD, sensor->base + DTS_CIFR_OFFSET);
+
+ thermal_zone_device_update(sensor->th_dev, THERMAL_EVENT_UNSPECIFIED);
+
+ return IRQ_HANDLED;
+}
+
+static int stm_sensor_power_on(struct stm_thermal_sensor *sensor)
+{
+ int ret;
+ u32 value;
+
+ /* Enable sensor */
+ value = readl_relaxed(sensor->base + DTS_CFGR1_OFFSET);
+ value |= TS1_EN;
+ writel_relaxed(value, sensor->base + DTS_CFGR1_OFFSET);
+
+ /*
+ * The DTS block can be enabled by setting TSx_EN bit in
+ * DTS_CFGRx register. It requires a startup time of
+ * 40μs. Use 5 ms as arbitrary timeout.
+ */
+ ret = readl_poll_timeout(sensor->base + DTS_SR_OFFSET,
+ value, (value & TS_RDY),
+ STARTUP_TIME, POLL_TIMEOUT);
+ if (ret)
+ return ret;
+
+ /* Start continuous measuring */
+ value = readl_relaxed(sensor->base +
+ DTS_CFGR1_OFFSET);
+ value |= TS1_START;
+ writel_relaxed(value, sensor->base +
+ DTS_CFGR1_OFFSET);
+
+ return 0;
+}
+
+static int stm_sensor_power_off(struct stm_thermal_sensor *sensor)
+{
+ u32 value;
+
+ /* Stop measuring */
+ value = readl_relaxed(sensor->base + DTS_CFGR1_OFFSET);
+ value &= ~TS1_START;
+ writel_relaxed(value, sensor->base + DTS_CFGR1_OFFSET);
+
+ /* Ensure stop is taken into account */
+ usleep_range(STARTUP_TIME, POLL_TIMEOUT);
+
+ /* Disable sensor */
+ value = readl_relaxed(sensor->base + DTS_CFGR1_OFFSET);
+ value &= ~TS1_EN;
+ writel_relaxed(value, sensor->base + DTS_CFGR1_OFFSET);
+
+ /* Ensure disable is taken into account */
+ return readl_poll_timeout(sensor->base + DTS_SR_OFFSET, value,
+ !(value & TS_RDY),
+ STARTUP_TIME, POLL_TIMEOUT);
+}
+
+static int stm_thermal_calibration(struct stm_thermal_sensor *sensor)
+{
+ u32 value, clk_freq;
+ u32 prescaler;
+
+ /* Figure out prescaler value for PCLK during calibration */
+ clk_freq = clk_get_rate(sensor->clk);
+ if (!clk_freq)
+ return -EINVAL;
+
+ prescaler = 0;
+ clk_freq /= ONE_MHZ;
+ if (clk_freq) {
+ while (prescaler <= clk_freq)
+ prescaler++;
+ }
+
+ value = readl_relaxed(sensor->base + DTS_CFGR1_OFFSET);
+
+ /* Clear prescaler */
+ value &= ~HSREF_CLK_DIV_MASK;
+
+ /* Set prescaler. pclk_freq/prescaler < 1MHz */
+ value |= (prescaler << HSREF_CLK_DIV_POS);
+
+ /* Select PCLK as reference clock */
+ value &= ~REFCLK_SEL;
+
+ /* Set maximal sampling time for better precision */
+ value |= TS1_SMP_TIME_MASK;
+
+ /* Measure with calibration */
+ value &= ~CALIBRATION_CONTROL;
+
+ /* select trigger */
+ value &= ~TS1_INTRIG_SEL_MASK;
+ value |= NO_HW_TRIG;
+
+ writel_relaxed(value, sensor->base + DTS_CFGR1_OFFSET);
+
+ return 0;
+}
+
+/* Fill in DTS structure with factory sensor values */
+static int stm_thermal_read_factory_settings(struct stm_thermal_sensor *sensor)
+{
+ /* Retrieve engineering calibration temperature */
+ sensor->t0 = readl_relaxed(sensor->base + DTS_T0VALR1_OFFSET) &
+ TS1_T0_MASK;
+ if (!sensor->t0)
+ sensor->t0 = TS1_T0_VAL0;
+ else
+ sensor->t0 = TS1_T0_VAL1;
+
+ /* Retrieve fmt0 and put it on Hz */
+ sensor->fmt0 = ADJUST * readl_relaxed(sensor->base + DTS_T0VALR1_OFFSET)
+ & TS1_FMT0_MASK;
+
+ /* Retrieve ramp coefficient */
+ sensor->ramp_coeff = readl_relaxed(sensor->base + DTS_RAMPVALR_OFFSET) &
+ TS1_RAMP_COEFF_MASK;
+
+ if (!sensor->fmt0 || !sensor->ramp_coeff) {
+ dev_err(sensor->dev, "%s: wrong setting\n", __func__);
+ return -EINVAL;
+ }
+
+ dev_dbg(sensor->dev, "%s: T0 = %doC, FMT0 = %dHz, RAMP_COEFF = %dHz/oC",
+ __func__, sensor->t0, sensor->fmt0, sensor->ramp_coeff);
+
+ return 0;
+}
+
+static int stm_thermal_calculate_threshold(struct stm_thermal_sensor *sensor,
+ int temp, u32 *th)
+{
+ int freqM;
+ u32 sampling_time;
+
+ /* Retrieve the number of periods to sample */
+ sampling_time = (readl_relaxed(sensor->base + DTS_CFGR1_OFFSET) &
+ TS1_SMP_TIME_MASK) >> TS1_SMP_TIME_POS;
+
+ /* Figure out the CLK_PTAT frequency for a given temperature */
+ freqM = ((temp - sensor->t0) * sensor->ramp_coeff)
+ + sensor->fmt0;
+
+ dev_dbg(sensor->dev, "%s: freqM for threshold = %d Hz",
+ __func__, freqM);
+
+ /* Figure out the threshold sample number */
+ *th = clk_get_rate(sensor->clk);
+ if (!*th)
+ return -EINVAL;
+
+ *th = *th / freqM;
+
+ *th *= sampling_time;
+
+ return 0;
+}
+
+static int stm_thermal_set_threshold(struct stm_thermal_sensor *sensor)
+{
+ u32 value, th;
+ int ret;
+
+ value = readl_relaxed(sensor->base + DTS_ITR1_OFFSET);
+
+ /* Erase threshold content */
+ value &= ~(TS1_LITTHD_MASK | TS1_HITTHD_MASK);
+
+ /* Retrieve the sample threshold number th for a given temperature */
+ ret = stm_thermal_calculate_threshold(sensor, sensor->high_temp, &th);
+ if (ret)
+ return ret;
+
+ value |= th & TS1_LITTHD_MASK;
+
+ if (sensor->low_temp_enabled) {
+ /* Retrieve the sample threshold */
+ ret = stm_thermal_calculate_threshold(sensor, sensor->low_temp,
+ &th);
+ if (ret)
+ return ret;
+
+ value |= (TS1_HITTHD_MASK & (th << TS1_HITTHD_POS));
+ }
+
+ /* Write value on the Low interrupt threshold */
+ writel_relaxed(value, sensor->base + DTS_ITR1_OFFSET);
+
+ return 0;
+}
+
+/* Disable temperature interrupt */
+static int stm_disable_irq(struct stm_thermal_sensor *sensor)
+{
+ u32 value;
+
+ /* Disable IT generation for low and high thresholds */
+ value = readl_relaxed(sensor->base + DTS_ITENR_OFFSET);
+ writel_relaxed(value & ~(LOW_THRESHOLD | HIGH_THRESHOLD),
+ sensor->base + DTS_ITENR_OFFSET);
+
+ dev_dbg(sensor->dev, "%s: IT disabled on sensor side", __func__);
+
+ return 0;
+}
+
+/* Enable temperature interrupt */
+static int stm_enable_irq(struct stm_thermal_sensor *sensor)
+{
+ u32 value;
+
+ /*
+ * Code below enables High temperature threshold using a low threshold
+ * sampling value
+ */
+
+ /* Make sure LOW_THRESHOLD IT is clear before enabling */
+ writel_relaxed(LOW_THRESHOLD, sensor->base + DTS_CIFR_OFFSET);
+
+ /* Enable IT generation for low threshold */
+ value = readl_relaxed(sensor->base + DTS_ITENR_OFFSET);
+ value |= LOW_THRESHOLD;
+
+ /* Enable the low temperature threshold if needed */
+ if (sensor->low_temp_enabled) {
+ /* Make sure HIGH_THRESHOLD IT is clear before enabling */
+ writel_relaxed(HIGH_THRESHOLD, sensor->base + DTS_CIFR_OFFSET);
+
+ /* Enable IT generation for high threshold */
+ value |= HIGH_THRESHOLD;
+ }
+
+ /* Enable thresholds */
+ writel_relaxed(value, sensor->base + DTS_ITENR_OFFSET);
+
+ dev_dbg(sensor->dev, "%s: IT enabled on sensor side", __func__);
+
+ return 0;
+}
+
+static int stm_thermal_update_threshold(struct stm_thermal_sensor *sensor)
+{
+ int ret;
+
+ sensor->mode = THERMAL_DEVICE_DISABLED;
+
+ ret = stm_sensor_power_off(sensor);
+ if (ret)
+ return ret;
+
+ ret = stm_disable_irq(sensor);
+ if (ret)
+ return ret;
+
+ ret = stm_thermal_set_threshold(sensor);
+ if (ret)
+ return ret;
+
+ ret = stm_enable_irq(sensor);
+ if (ret)
+ return ret;
+
+ ret = stm_sensor_power_on(sensor);
+ if (ret)
+ return ret;
+
+ sensor->mode = THERMAL_DEVICE_ENABLED;
+
+ return 0;
+}
+
+/* Callback to get temperature from HW */
+static int stm_thermal_get_temp(void *data, int *temp)
+{
+ struct stm_thermal_sensor *sensor = data;
+ u32 sampling_time;
+ int freqM, ret;
+
+ if (sensor->mode != THERMAL_DEVICE_ENABLED)
+ return -EAGAIN;
+
+ /* Retrieve the number of samples */
+ ret = readl_poll_timeout(sensor->base + DTS_DR_OFFSET, freqM,
+ (freqM & TS1_MFREQ_MASK), STARTUP_TIME,
+ POLL_TIMEOUT);
+
+ if (ret)
+ return ret;
+
+ if (!freqM)
+ return -ENODATA;
+
+ /* Retrieve the number of periods sampled */
+ sampling_time = (readl_relaxed(sensor->base + DTS_CFGR1_OFFSET) &
+ TS1_SMP_TIME_MASK) >> TS1_SMP_TIME_POS;
+
+ /* Figure out the number of samples per period */
+ freqM /= sampling_time;
+
+ /* Figure out the CLK_PTAT frequency */
+ freqM = clk_get_rate(sensor->clk) / freqM;
+ if (!freqM)
+ return -EINVAL;
+
+ dev_dbg(sensor->dev, "%s: freqM=%d\n", __func__, freqM);
+
+ /* Figure out the temperature in mili celsius */
+ *temp = mcelsius(sensor->t0 + ((freqM - sensor->fmt0) /
+ sensor->ramp_coeff));
+
+ dev_dbg(sensor->dev, "%s: temperature = %d millicelsius",
+ __func__, *temp);
+
+ /* Update thresholds */
+ if (sensor->num_trips > 1) {
+ /* Update alarm threshold value to next higher trip point */
+ if (sensor->high_temp == sensor->temp_passive &&
+ celsius(*temp) >= sensor->temp_passive) {
+ sensor->high_temp = sensor->temp_critical;
+ sensor->low_temp = sensor->temp_passive;
+ sensor->low_temp_enabled = true;
+ ret = stm_thermal_update_threshold(sensor);
+ if (ret)
+ return ret;
+ }
+
+ if (sensor->high_temp == sensor->temp_critical &&
+ celsius(*temp) < sensor->temp_passive) {
+ sensor->high_temp = sensor->temp_passive;
+ sensor->low_temp_enabled = false;
+ ret = stm_thermal_update_threshold(sensor);
+ if (ret)
+ return ret;
+ }
+
+ /*
+ * Re-enable alarm IRQ if temperature below critical
+ * temperature
+ */
+ if (!sensor->irq_enabled &&
+ (celsius(*temp) < sensor->temp_critical)) {
+ sensor->irq_enabled = true;
+ enable_irq(sensor->irq);
+ }
+ }
+
+ return 0;
+}
+
+/* Registers DTS irq to be visible by GIC */
+static int stm_register_irq(struct stm_thermal_sensor *sensor)
+{
+ struct device *dev = sensor->dev;
+ struct platform_device *pdev = to_platform_device(dev);
+ int ret;
+
+ sensor->irq = platform_get_irq(pdev, 0);
+ if (sensor->irq < 0) {
+ dev_err(dev, "%s: Unable to find IRQ\n", __func__);
+ return sensor->irq;
+ }
+
+ ret = devm_request_threaded_irq(dev, sensor->irq,
+ stm_thermal_alarm_irq,
+ stm_thermal_alarm_irq_thread,
+ IRQF_ONESHOT,
+ dev->driver->name, sensor);
+ if (ret) {
+ dev_err(dev, "%s: Failed to register IRQ %d\n", __func__,
+ sensor->irq);
+ return ret;
+ }
+
+ sensor->irq_enabled = true;
+
+ dev_dbg(dev, "%s: thermal IRQ registered", __func__);
+
+ return 0;
+}
+
+static int stm_thermal_sensor_off(struct stm_thermal_sensor *sensor)
+{
+ int ret;
+
+ ret = stm_sensor_power_off(sensor);
+ if (ret)
+ return ret;
+
+ clk_disable_unprepare(sensor->clk);
+
+ return 0;
+}
+
+static int stm_thermal_prepare(struct stm_thermal_sensor *sensor)
+{
+ int ret;
+ struct device *dev = sensor->dev;
+
+ ret = clk_prepare_enable(sensor->clk);
+ if (ret)
+ return ret;
+
+ ret = stm_thermal_calibration(sensor);
+ if (ret)
+ goto thermal_unprepare;
+
+ /* Set threshold(s) for IRQ */
+ ret = stm_thermal_set_threshold(sensor);
+ if (ret)
+ goto thermal_unprepare;
+
+ ret = stm_enable_irq(sensor);
+ if (ret)
+ goto thermal_unprepare;
+
+ ret = stm_sensor_power_on(sensor);
+ if (ret) {
+ dev_err(dev, "%s: failed to power on sensor\n", __func__);
+ goto irq_disable;
+ }
+
+ return 0;
+
+irq_disable:
+ stm_disable_irq(sensor);
+
+thermal_unprepare:
+ clk_disable_unprepare(sensor->clk);
+
+ return ret;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int stm_thermal_suspend(struct device *dev)
+{
+ int ret;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct stm_thermal_sensor *sensor = platform_get_drvdata(pdev);
+
+ ret = stm_thermal_sensor_off(sensor);
+ if (ret)
+ return ret;
+
+ sensor->mode = THERMAL_DEVICE_DISABLED;
+
+ return 0;
+}
+
+static int stm_thermal_resume(struct device *dev)
+{
+ int ret;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct stm_thermal_sensor *sensor = platform_get_drvdata(pdev);
+
+ ret = stm_thermal_prepare(sensor);
+ if (ret)
+ return ret;
+
+ sensor->mode = THERMAL_DEVICE_ENABLED;
+
+ return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+SIMPLE_DEV_PM_OPS(stm_thermal_pm_ops, stm_thermal_suspend, stm_thermal_resume);
+
+static const struct thermal_zone_of_device_ops stm_tz_ops = {
+ .get_temp = stm_thermal_get_temp,
+};
+
+static const struct of_device_id stm_thermal_of_match[] = {
+ { .compatible = "st,stm32-thermal"},
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, stm_thermal_of_match);
+
+static int stm_thermal_probe(struct platform_device *pdev)
+{
+ struct stm_thermal_sensor *sensor;
+ struct resource *res;
+ const struct thermal_trip *trip;
+ void __iomem *base;
+ int ret, i;
+
+ if (!pdev->dev.of_node) {
+ dev_err(&pdev->dev, "%s: device tree node not found\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ sensor = devm_kzalloc(&pdev->dev, sizeof(*sensor), GFP_KERNEL);
+ if (!sensor)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, sensor);
+
+ sensor->dev = &pdev->dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ /* Populate sensor */
+ sensor->base = base;
+
+ ret = stm_thermal_read_factory_settings(sensor);
+ if (ret)
+ return ret;
+
+ sensor->clk = devm_clk_get(&pdev->dev, "pclk");
+ if (IS_ERR(sensor->clk)) {
+ dev_err(&pdev->dev, "%s: failed to fetch PCLK clock\n",
+ __func__);
+ return PTR_ERR(sensor->clk);
+ }
+
+ /* Register IRQ into GIC */
+ ret = stm_register_irq(sensor);
+ if (ret)
+ return ret;
+
+ sensor->th_dev = devm_thermal_zone_of_sensor_register(&pdev->dev, 0,
+ sensor,
+ &stm_tz_ops);
+
+ if (IS_ERR(sensor->th_dev)) {
+ dev_err(&pdev->dev, "%s: thermal zone sensor registering KO\n",
+ __func__);
+ ret = PTR_ERR(sensor->th_dev);
+ return ret;
+ }
+
+ if (!sensor->th_dev->ops->get_crit_temp) {
+ /* Critical point must be provided */
+ ret = -EINVAL;
+ goto err_tz;
+ }
+
+ ret = sensor->th_dev->ops->get_crit_temp(sensor->th_dev,
+ &sensor->temp_critical);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Not able to read critical_temp: %d\n", ret);
+ goto err_tz;
+ }
+
+ sensor->temp_critical = celsius(sensor->temp_critical);
+
+ /* Set thresholds for IRQ */
+ sensor->high_temp = sensor->temp_critical;
+
+ trip = of_thermal_get_trip_points(sensor->th_dev);
+ sensor->num_trips = of_thermal_get_ntrips(sensor->th_dev);
+
+ /* Find out passive temperature if it exists */
+ for (i = (sensor->num_trips - 1); i >= 0; i--) {
+ if (trip[i].type == THERMAL_TRIP_PASSIVE) {
+ sensor->temp_passive = celsius(trip[i].temperature);
+ /* Update high temperature threshold */
+ sensor->high_temp = sensor->temp_passive;
+ }
+ }
+
+ /*
+ * Ensure low_temp_enabled flag is disabled.
+ * By disabling low_temp_enabled, low threshold IT will not be
+ * configured neither enabled because it is not needed as high
+ * threshold is set on the lowest temperature trip point after
+ * probe.
+ */
+ sensor->low_temp_enabled = false;
+
+ /* Configure and enable HW sensor */
+ ret = stm_thermal_prepare(sensor);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Not able to enable sensor: %d\n", ret);
+ goto err_tz;
+ }
+
+ /*
+ * Thermal_zone doesn't enable hwmon as default,
+ * enable it here
+ */
+ sensor->th_dev->tzp->no_hwmon = false;
+ ret = thermal_add_hwmon_sysfs(sensor->th_dev);
+ if (ret)
+ goto err_tz;
+
+ sensor->mode = THERMAL_DEVICE_ENABLED;
+
+ dev_info(&pdev->dev, "%s: Driver initialized successfully\n",
+ __func__);
+
+ return 0;
+
+err_tz:
+ thermal_zone_of_sensor_unregister(&pdev->dev, sensor->th_dev);
+ return ret;
+}
+
+static int stm_thermal_remove(struct platform_device *pdev)
+{
+ struct stm_thermal_sensor *sensor = platform_get_drvdata(pdev);
+
+ stm_thermal_sensor_off(sensor);
+ thermal_remove_hwmon_sysfs(sensor->th_dev);
+ thermal_zone_of_sensor_unregister(&pdev->dev, sensor->th_dev);
+
+ return 0;
+}
+
+static struct platform_driver stm_thermal_driver = {
+ .driver = {
+ .name = "stm_thermal",
+ .pm = &stm_thermal_pm_ops,
+ .of_match_table = stm_thermal_of_match,
+ },
+ .probe = stm_thermal_probe,
+ .remove = stm_thermal_remove,
+};
+module_platform_driver(stm_thermal_driver);
+
+MODULE_DESCRIPTION("STMicroelectronics STM32 Thermal Sensor Driver");
+MODULE_AUTHOR("David Hernandez Sanchez <david.hernandezsanchez@st.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:stm_thermal");
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 6ab982309e6a..d6ebc1cf6aa9 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -290,10 +290,12 @@ static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
int delay)
{
if (delay > 1000)
- mod_delayed_work(system_freezable_wq, &tz->poll_queue,
+ mod_delayed_work(system_freezable_power_efficient_wq,
+ &tz->poll_queue,
round_jiffies(msecs_to_jiffies(delay)));
else if (delay)
- mod_delayed_work(system_freezable_wq, &tz->poll_queue,
+ mod_delayed_work(system_freezable_power_efficient_wq,
+ &tz->poll_queue,
msecs_to_jiffies(delay));
else
cancel_delayed_work(&tz->poll_queue);
@@ -1102,8 +1104,9 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
mutex_unlock(&thermal_list_lock);
ida_simple_remove(&thermal_cdev_ida, cdev->id);
- device_unregister(&cdev->device);
+ device_del(&cdev->device);
thermal_cooling_device_destroy_sysfs(cdev);
+ put_device(&cdev->device);
}
EXPORT_SYMBOL_GPL(thermal_cooling_device_unregister);
diff --git a/drivers/thunderbolt/cap.c b/drivers/thunderbolt/cap.c
index c2277b8ee88d..9553305c63ea 100644
--- a/drivers/thunderbolt/cap.c
+++ b/drivers/thunderbolt/cap.c
@@ -1,8 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Thunderbolt Cactus Ridge driver - capabilities lookup
+ * Thunderbolt driver - capabilities lookup
*
* Copyright (c) 2014 Andreas Noever <andreas.noever@gmail.com>
+ * Copyright (C) 2018, Intel Corporation
*/
#include <linux/slab.h>
diff --git a/drivers/thunderbolt/ctl.c b/drivers/thunderbolt/ctl.c
index 37a7f4c735d0..73b386de4d15 100644
--- a/drivers/thunderbolt/ctl.c
+++ b/drivers/thunderbolt/ctl.c
@@ -1,8 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Thunderbolt Cactus Ridge driver - control channel and configuration commands
+ * Thunderbolt driver - control channel and configuration commands
*
* Copyright (c) 2014 Andreas Noever <andreas.noever@gmail.com>
+ * Copyright (C) 2018, Intel Corporation
*/
#include <linux/crc32.h>
@@ -631,7 +632,7 @@ struct tb_ctl *tb_ctl_alloc(struct tb_nhi *nhi, event_cb cb, void *cb_data)
ctl->rx_packets[i]->frame.callback = tb_ctl_rx_callback;
}
- tb_ctl_info(ctl, "control channel created\n");
+ tb_ctl_dbg(ctl, "control channel created\n");
return ctl;
err:
tb_ctl_free(ctl);
@@ -662,8 +663,7 @@ void tb_ctl_free(struct tb_ctl *ctl)
tb_ctl_pkg_free(ctl->rx_packets[i]);
- if (ctl->frame_pool)
- dma_pool_destroy(ctl->frame_pool);
+ dma_pool_destroy(ctl->frame_pool);
kfree(ctl);
}
@@ -673,7 +673,7 @@ void tb_ctl_free(struct tb_ctl *ctl)
void tb_ctl_start(struct tb_ctl *ctl)
{
int i;
- tb_ctl_info(ctl, "control channel starting...\n");
+ tb_ctl_dbg(ctl, "control channel starting...\n");
tb_ring_start(ctl->tx); /* is used to ack hotplug packets, start first */
tb_ring_start(ctl->rx);
for (i = 0; i < TB_CTL_RX_PKG_COUNT; i++)
@@ -702,7 +702,7 @@ void tb_ctl_stop(struct tb_ctl *ctl)
if (!list_empty(&ctl->request_queue))
tb_ctl_WARN(ctl, "dangling request in request_queue\n");
INIT_LIST_HEAD(&ctl->request_queue);
- tb_ctl_info(ctl, "control channel stopped\n");
+ tb_ctl_dbg(ctl, "control channel stopped\n");
}
/* public interface, commands */
diff --git a/drivers/thunderbolt/ctl.h b/drivers/thunderbolt/ctl.h
index 3062e0b5f71e..2f1a1e111110 100644
--- a/drivers/thunderbolt/ctl.h
+++ b/drivers/thunderbolt/ctl.h
@@ -1,8 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
- * Thunderbolt Cactus Ridge driver - control channel and configuration commands
+ * Thunderbolt driver - control channel and configuration commands
*
* Copyright (c) 2014 Andreas Noever <andreas.noever@gmail.com>
+ * Copyright (C) 2018, Intel Corporation
*/
#ifndef _TB_CFG
diff --git a/drivers/thunderbolt/dma_port.c b/drivers/thunderbolt/dma_port.c
index f2701194f810..847dd07a7b17 100644
--- a/drivers/thunderbolt/dma_port.c
+++ b/drivers/thunderbolt/dma_port.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Thunderbolt DMA configuration based mailbox support
*
* Copyright (C) 2017, Intel Corporation
* Authors: Michael Jamet <michael.jamet@intel.com>
* Mika Westerberg <mika.westerberg@linux.intel.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/delay.h>
diff --git a/drivers/thunderbolt/dma_port.h b/drivers/thunderbolt/dma_port.h
index c4a69e0fbff7..7deadd97ce31 100644
--- a/drivers/thunderbolt/dma_port.h
+++ b/drivers/thunderbolt/dma_port.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Thunderbolt DMA configuration based mailbox support
*
* Copyright (C) 2017, Intel Corporation
* Authors: Michael Jamet <michael.jamet@intel.com>
* Mika Westerberg <mika.westerberg@linux.intel.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#ifndef DMA_PORT_H_
diff --git a/drivers/thunderbolt/domain.c b/drivers/thunderbolt/domain.c
index 092381e2accf..93e562f18d40 100644
--- a/drivers/thunderbolt/domain.c
+++ b/drivers/thunderbolt/domain.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Thunderbolt bus support
*
* Copyright (C) 2017, Intel Corporation
- * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
*/
#include <linux/device.h>
diff --git a/drivers/thunderbolt/eeprom.c b/drivers/thunderbolt/eeprom.c
index 3e8caf22c294..81e8ac4c5805 100644
--- a/drivers/thunderbolt/eeprom.c
+++ b/drivers/thunderbolt/eeprom.c
@@ -1,8 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Thunderbolt Cactus Ridge driver - eeprom access
+ * Thunderbolt driver - eeprom access
*
* Copyright (c) 2014 Andreas Noever <andreas.noever@gmail.com>
+ * Copyright (C) 2018, Intel Corporation
*/
#include <linux/crc32.h>
@@ -540,7 +541,7 @@ int tb_drom_read(struct tb_switch *sw)
return res;
size &= 0x3ff;
size += TB_DROM_DATA_START;
- tb_sw_info(sw, "reading drom (length: %#x)\n", size);
+ tb_sw_dbg(sw, "reading drom (length: %#x)\n", size);
if (size < sizeof(*header)) {
tb_sw_warn(sw, "drom too small, aborting\n");
return -EIO;
diff --git a/drivers/thunderbolt/icm.c b/drivers/thunderbolt/icm.c
index e1e264a9a4c7..e3fc920af682 100644
--- a/drivers/thunderbolt/icm.c
+++ b/drivers/thunderbolt/icm.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Internal Thunderbolt Connection Manager. This is a firmware running on
* the Thunderbolt host controller performing most of the low-level
@@ -6,10 +7,6 @@
* Copyright (C) 2017, Intel Corporation
* Authors: Michael Jamet <michael.jamet@intel.com>
* Mika Westerberg <mika.westerberg@linux.intel.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/delay.h>
@@ -738,14 +735,6 @@ icm_fr_xdomain_connected(struct tb *tb, const struct icm_pkg_header *hdr)
u8 link, depth;
u64 route;
- /*
- * After NVM upgrade adding root switch device fails because we
- * initiated reset. During that time ICM might still send
- * XDomain connected message which we ignore here.
- */
- if (!tb->root_switch)
- return;
-
link = pkg->link_info & ICM_LINK_INFO_LINK_MASK;
depth = (pkg->link_info & ICM_LINK_INFO_DEPTH_MASK) >>
ICM_LINK_INFO_DEPTH_SHIFT;
@@ -1037,14 +1026,6 @@ icm_tr_device_connected(struct tb *tb, const struct icm_pkg_header *hdr)
if (pkg->hdr.packet_id)
return;
- /*
- * After NVM upgrade adding root switch device fails because we
- * initiated reset. During that time ICM might still send device
- * connected message which we ignore here.
- */
- if (!tb->root_switch)
- return;
-
route = get_route(pkg->route_hi, pkg->route_lo);
authorized = pkg->link_info & ICM_LINK_INFO_APPROVED;
security_level = (pkg->hdr.flags & ICM_FLAGS_SLEVEL_MASK) >>
@@ -1408,19 +1389,26 @@ static void icm_handle_notification(struct work_struct *work)
mutex_lock(&tb->lock);
- switch (n->pkg->code) {
- case ICM_EVENT_DEVICE_CONNECTED:
- icm->device_connected(tb, n->pkg);
- break;
- case ICM_EVENT_DEVICE_DISCONNECTED:
- icm->device_disconnected(tb, n->pkg);
- break;
- case ICM_EVENT_XDOMAIN_CONNECTED:
- icm->xdomain_connected(tb, n->pkg);
- break;
- case ICM_EVENT_XDOMAIN_DISCONNECTED:
- icm->xdomain_disconnected(tb, n->pkg);
- break;
+ /*
+ * When the domain is stopped we flush its workqueue but before
+ * that the root switch is removed. In that case we should treat
+ * the queued events as being canceled.
+ */
+ if (tb->root_switch) {
+ switch (n->pkg->code) {
+ case ICM_EVENT_DEVICE_CONNECTED:
+ icm->device_connected(tb, n->pkg);
+ break;
+ case ICM_EVENT_DEVICE_DISCONNECTED:
+ icm->device_disconnected(tb, n->pkg);
+ break;
+ case ICM_EVENT_XDOMAIN_CONNECTED:
+ icm->xdomain_connected(tb, n->pkg);
+ break;
+ case ICM_EVENT_XDOMAIN_DISCONNECTED:
+ icm->xdomain_disconnected(tb, n->pkg);
+ break;
+ }
}
mutex_unlock(&tb->lock);
diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c
index 88cff05a1808..9aa44f9762a3 100644
--- a/drivers/thunderbolt/nhi.c
+++ b/drivers/thunderbolt/nhi.c
@@ -1,10 +1,11 @@
/*
- * Thunderbolt Cactus Ridge driver - NHI driver
+ * Thunderbolt driver - NHI driver
*
* The NHI (native host interface) is the pci device that allows us to send and
* receive frames from the thunderbolt bus.
*
* Copyright (c) 2014 Andreas Noever <andreas.noever@gmail.com>
+ * Copyright (C) 2018, Intel Corporation
*/
#include <linux/pm_runtime.h>
@@ -95,9 +96,9 @@ static void ring_interrupt_active(struct tb_ring *ring, bool active)
else
new = old & ~mask;
- dev_info(&ring->nhi->pdev->dev,
- "%s interrupt at register %#x bit %d (%#x -> %#x)\n",
- active ? "enabling" : "disabling", reg, bit, old, new);
+ dev_dbg(&ring->nhi->pdev->dev,
+ "%s interrupt at register %#x bit %d (%#x -> %#x)\n",
+ active ? "enabling" : "disabling", reg, bit, old, new);
if (new == old)
dev_WARN(&ring->nhi->pdev->dev,
@@ -476,8 +477,9 @@ static struct tb_ring *tb_ring_alloc(struct tb_nhi *nhi, u32 hop, int size,
void *poll_data)
{
struct tb_ring *ring = NULL;
- dev_info(&nhi->pdev->dev, "allocating %s ring %d of size %d\n",
- transmit ? "TX" : "RX", hop, size);
+
+ dev_dbg(&nhi->pdev->dev, "allocating %s ring %d of size %d\n",
+ transmit ? "TX" : "RX", hop, size);
/* Tx Ring 2 is reserved for E2E workaround */
if (transmit && hop == RING_E2E_UNUSED_HOPID)
@@ -585,8 +587,8 @@ void tb_ring_start(struct tb_ring *ring)
dev_WARN(&ring->nhi->pdev->dev, "ring already started\n");
goto err;
}
- dev_info(&ring->nhi->pdev->dev, "starting %s %d\n",
- RING_TYPE(ring), ring->hop);
+ dev_dbg(&ring->nhi->pdev->dev, "starting %s %d\n",
+ RING_TYPE(ring), ring->hop);
if (ring->flags & RING_FLAG_FRAME) {
/* Means 4096 */
@@ -647,8 +649,8 @@ void tb_ring_stop(struct tb_ring *ring)
{
spin_lock_irq(&ring->nhi->lock);
spin_lock(&ring->lock);
- dev_info(&ring->nhi->pdev->dev, "stopping %s %d\n",
- RING_TYPE(ring), ring->hop);
+ dev_dbg(&ring->nhi->pdev->dev, "stopping %s %d\n",
+ RING_TYPE(ring), ring->hop);
if (ring->nhi->going_away)
goto err;
if (!ring->running) {
@@ -716,10 +718,8 @@ void tb_ring_free(struct tb_ring *ring)
ring->descriptors_dma = 0;
- dev_info(&ring->nhi->pdev->dev,
- "freeing %s %d\n",
- RING_TYPE(ring),
- ring->hop);
+ dev_dbg(&ring->nhi->pdev->dev, "freeing %s %d\n", RING_TYPE(ring),
+ ring->hop);
/**
* ring->work can no longer be scheduled (it is scheduled only
@@ -931,7 +931,8 @@ static int nhi_runtime_resume(struct device *dev)
static void nhi_shutdown(struct tb_nhi *nhi)
{
int i;
- dev_info(&nhi->pdev->dev, "shutdown\n");
+
+ dev_dbg(&nhi->pdev->dev, "shutdown\n");
for (i = 0; i < nhi->hop_count; i++) {
if (nhi->tx_rings[i])
@@ -1059,7 +1060,7 @@ static int nhi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return -ENODEV;
}
- dev_info(&nhi->pdev->dev, "NHI initialized, starting thunderbolt\n");
+ dev_dbg(&nhi->pdev->dev, "NHI initialized, starting thunderbolt\n");
res = tb_domain_add(tb);
if (res) {
@@ -1191,5 +1192,5 @@ static void __exit nhi_unload(void)
tb_domain_exit();
}
-fs_initcall(nhi_init);
+rootfs_initcall(nhi_init);
module_exit(nhi_unload);
diff --git a/drivers/thunderbolt/nhi.h b/drivers/thunderbolt/nhi.h
index 1696a4560948..1b5d47ecd3ed 100644
--- a/drivers/thunderbolt/nhi.h
+++ b/drivers/thunderbolt/nhi.h
@@ -1,8 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
- * Thunderbolt Cactus Ridge driver - NHI driver
+ * Thunderbolt driver - NHI driver
*
* Copyright (c) 2014 Andreas Noever <andreas.noever@gmail.com>
+ * Copyright (C) 2018, Intel Corporation
*/
#ifndef DSL3510_H_
diff --git a/drivers/thunderbolt/nhi_regs.h b/drivers/thunderbolt/nhi_regs.h
index b3e49d19c01e..a60bd98c1d04 100644
--- a/drivers/thunderbolt/nhi_regs.h
+++ b/drivers/thunderbolt/nhi_regs.h
@@ -3,6 +3,7 @@
* Thunderbolt driver - NHI registers
*
* Copyright (c) 2014 Andreas Noever <andreas.noever@gmail.com>
+ * Copyright (C) 2018, Intel Corporation
*/
#ifndef NHI_REGS_H_
diff --git a/drivers/thunderbolt/path.c b/drivers/thunderbolt/path.c
index ff49ad880bfd..a11956522bac 100644
--- a/drivers/thunderbolt/path.c
+++ b/drivers/thunderbolt/path.c
@@ -13,19 +13,19 @@
static void tb_dump_hop(struct tb_port *port, struct tb_regs_hop *hop)
{
- tb_port_info(port, " Hop through port %d to hop %d (%s)\n",
- hop->out_port, hop->next_hop,
- hop->enable ? "enabled" : "disabled");
- tb_port_info(port, " Weight: %d Priority: %d Credits: %d Drop: %d\n",
- hop->weight, hop->priority,
- hop->initial_credits, hop->drop_packages);
- tb_port_info(port, " Counter enabled: %d Counter index: %d\n",
- hop->counter_enable, hop->counter);
- tb_port_info(port, " Flow Control (In/Eg): %d/%d Shared Buffer (In/Eg): %d/%d\n",
- hop->ingress_fc, hop->egress_fc,
- hop->ingress_shared_buffer, hop->egress_shared_buffer);
- tb_port_info(port, " Unknown1: %#x Unknown2: %#x Unknown3: %#x\n",
- hop->unknown1, hop->unknown2, hop->unknown3);
+ tb_port_dbg(port, " Hop through port %d to hop %d (%s)\n",
+ hop->out_port, hop->next_hop,
+ hop->enable ? "enabled" : "disabled");
+ tb_port_dbg(port, " Weight: %d Priority: %d Credits: %d Drop: %d\n",
+ hop->weight, hop->priority,
+ hop->initial_credits, hop->drop_packages);
+ tb_port_dbg(port, " Counter enabled: %d Counter index: %d\n",
+ hop->counter_enable, hop->counter);
+ tb_port_dbg(port, " Flow Control (In/Eg): %d/%d Shared Buffer (In/Eg): %d/%d\n",
+ hop->ingress_fc, hop->egress_fc,
+ hop->ingress_shared_buffer, hop->egress_shared_buffer);
+ tb_port_dbg(port, " Unknown1: %#x Unknown2: %#x Unknown3: %#x\n",
+ hop->unknown1, hop->unknown2, hop->unknown3);
}
/**
diff --git a/drivers/thunderbolt/property.c b/drivers/thunderbolt/property.c
index 8fe913a95b4a..b2f0d6386cee 100644
--- a/drivers/thunderbolt/property.c
+++ b/drivers/thunderbolt/property.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Thunderbolt XDomain property support
*
* Copyright (C) 2017, Intel Corporation
* Authors: Michael Jamet <michael.jamet@intel.com>
* Mika Westerberg <mika.westerberg@linux.intel.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/err.h>
diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c
index 7442bc4c6433..52ff854f0d6c 100644
--- a/drivers/thunderbolt/switch.c
+++ b/drivers/thunderbolt/switch.c
@@ -1,8 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Thunderbolt Cactus Ridge driver - switch/port utility functions
+ * Thunderbolt driver - switch/port utility functions
*
* Copyright (c) 2014 Andreas Noever <andreas.noever@gmail.com>
+ * Copyright (C) 2018, Intel Corporation
*/
#include <linux/delay.h>
@@ -436,15 +437,15 @@ 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)
{
- tb_info(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);
- tb_info(tb, " Max hop id (in/out): %d/%d\n",
- port->max_in_hop_id, port->max_out_hop_id);
- tb_info(tb, " Max counters: %d\n", port->max_counters);
- tb_info(tb, " NFC Credits: %#x\n", port->nfc_credits);
+ 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);
+ 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);
}
/**
@@ -605,20 +606,18 @@ static int tb_init_port(struct tb_port *port)
static void tb_dump_switch(struct tb *tb, struct tb_regs_switch_header *sw)
{
- tb_info(tb,
- " Switch: %x:%x (Revision: %d, TB Version: %d)\n",
- sw->vendor_id, sw->device_id, sw->revision,
- sw->thunderbolt_version);
- tb_info(tb, " Max Port Number: %d\n", sw->max_port_number);
- tb_info(tb, " Config:\n");
- tb_info(tb,
+ tb_dbg(tb, " Switch: %x:%x (Revision: %d, TB Version: %d)\n",
+ sw->vendor_id, sw->device_id, sw->revision,
+ sw->thunderbolt_version);
+ tb_dbg(tb, " Max Port Number: %d\n", sw->max_port_number);
+ tb_dbg(tb, " Config:\n");
+ tb_dbg(tb,
" Upstream Port Number: %d Depth: %d Route String: %#llx Enabled: %d, PlugEventsDelay: %dms\n",
- sw->upstream_port_number, sw->depth,
- (((u64) sw->route_hi) << 32) | sw->route_lo,
- sw->enabled, sw->plug_events_delay);
- tb_info(tb,
- " unknown1: %#x unknown4: %#x\n",
- sw->__unknown1, sw->__unknown4);
+ sw->upstream_port_number, sw->depth,
+ (((u64) sw->route_hi) << 32) | sw->route_lo,
+ sw->enabled, sw->plug_events_delay);
+ tb_dbg(tb, " unknown1: %#x unknown4: %#x\n",
+ sw->__unknown1, sw->__unknown4);
}
/**
@@ -634,7 +633,7 @@ int tb_switch_reset(struct tb *tb, u64 route)
header.route_lo = route,
header.enabled = true,
};
- tb_info(tb, "resetting switch at %llx\n", route);
+ tb_dbg(tb, "resetting switch at %llx\n", route);
res.err = tb_cfg_write(tb->ctl, ((u32 *) &header) + 2, route,
0, 2, 2, 2);
if (res.err)
@@ -1139,7 +1138,7 @@ struct tb_switch *tb_switch_alloc(struct tb *tb, struct device *parent,
if (tb_cfg_read(tb->ctl, &sw->config, route, 0, TB_CFG_SWITCH, 0, 5))
goto err_free_sw_ports;
- tb_info(tb, "current switch config:\n");
+ tb_dbg(tb, "current switch config:\n");
tb_dump_switch(tb, &sw->config);
/* configure switch */
@@ -1246,9 +1245,8 @@ int tb_switch_configure(struct tb_switch *sw)
int ret;
route = tb_route(sw);
- tb_info(tb,
- "initializing Switch at %#llx (depth: %d, up port: %d)\n",
- route, tb_route_length(route), sw->config.upstream_port_number);
+ tb_dbg(tb, "initializing Switch at %#llx (depth: %d, up port: %d)\n",
+ route, tb_route_length(route), sw->config.upstream_port_number);
if (sw->config.vendor_id != PCI_VENDOR_ID_INTEL)
tb_sw_warn(sw, "unknown switch vendor id %#x\n",
@@ -1386,13 +1384,13 @@ int tb_switch_add(struct tb_switch *sw)
tb_sw_warn(sw, "tb_eeprom_read_rom failed\n");
return ret;
}
- tb_sw_info(sw, "uid: %#llx\n", sw->uid);
+ tb_sw_dbg(sw, "uid: %#llx\n", sw->uid);
tb_switch_set_uuid(sw);
for (i = 0; i <= sw->config.max_port_number; i++) {
if (sw->ports[i].disabled) {
- tb_port_info(&sw->ports[i], "disabled by eeprom\n");
+ tb_port_dbg(&sw->ports[i], "disabled by eeprom\n");
continue;
}
ret = tb_init_port(&sw->ports[i]);
@@ -1405,6 +1403,14 @@ int tb_switch_add(struct tb_switch *sw)
if (ret)
return ret;
+ if (tb_route(sw)) {
+ dev_info(&sw->dev, "new device found, vendor=%#x device=%#x\n",
+ sw->vendor, sw->device);
+ if (sw->vendor_name && sw->device_name)
+ dev_info(&sw->dev, "%s %s\n", sw->vendor_name,
+ sw->device_name);
+ }
+
ret = tb_switch_nvm_add(sw);
if (ret) {
device_del(&sw->dev);
@@ -1456,6 +1462,9 @@ void tb_switch_remove(struct tb_switch *sw)
tb_plug_events_active(sw, false);
tb_switch_nvm_remove(sw);
+
+ if (tb_route(sw))
+ dev_info(&sw->dev, "device disconnected\n");
device_unregister(&sw->dev);
}
@@ -1483,7 +1492,7 @@ void tb_sw_set_unplugged(struct tb_switch *sw)
int tb_switch_resume(struct tb_switch *sw)
{
int i, err;
- tb_sw_info(sw, "resuming switch\n");
+ tb_sw_dbg(sw, "resuming switch\n");
/*
* Check for UID of the connected switches except for root
diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c
index 1424581fd9af..30e02c716f6c 100644
--- a/drivers/thunderbolt/tb.c
+++ b/drivers/thunderbolt/tb.c
@@ -404,10 +404,10 @@ static int tb_suspend_noirq(struct tb *tb)
{
struct tb_cm *tcm = tb_priv(tb);
- tb_info(tb, "suspending...\n");
+ tb_dbg(tb, "suspending...\n");
tb_switch_suspend(tb->root_switch);
tcm->hotplug_active = false; /* signal tb_handle_hotplug to quit */
- tb_info(tb, "suspend finished\n");
+ tb_dbg(tb, "suspend finished\n");
return 0;
}
@@ -417,7 +417,7 @@ static int tb_resume_noirq(struct tb *tb)
struct tb_cm *tcm = tb_priv(tb);
struct tb_pci_tunnel *tunnel, *n;
- tb_info(tb, "resuming...\n");
+ tb_dbg(tb, "resuming...\n");
/* remove any pci devices the firmware might have setup */
tb_switch_reset(tb, 0);
@@ -432,12 +432,12 @@ static int tb_resume_noirq(struct tb *tb)
* the pcie links need some time to get going.
* 100ms works for me...
*/
- tb_info(tb, "tunnels restarted, sleeping for 100ms\n");
+ tb_dbg(tb, "tunnels restarted, sleeping for 100ms\n");
msleep(100);
}
/* Allow tb_handle_hotplug to progress events */
tcm->hotplug_active = true;
- tb_info(tb, "resume finished\n");
+ tb_dbg(tb, "resume finished\n");
return 0;
}
diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h
index 5067d69d0501..52584c4003e3 100644
--- a/drivers/thunderbolt/tb.h
+++ b/drivers/thunderbolt/tb.h
@@ -1,8 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
- * Thunderbolt Cactus Ridge driver - bus logic (NHI independent)
+ * Thunderbolt driver - bus logic (NHI independent)
*
* Copyright (c) 2014 Andreas Noever <andreas.noever@gmail.com>
+ * Copyright (C) 2018, Intel Corporation
*/
#ifndef TB_H_
@@ -327,7 +328,7 @@ static inline int tb_port_write(struct tb_port *port, const void *buffer,
#define tb_WARN(tb, fmt, arg...) dev_WARN(&(tb)->nhi->pdev->dev, fmt, ## arg)
#define tb_warn(tb, fmt, arg...) dev_warn(&(tb)->nhi->pdev->dev, fmt, ## arg)
#define tb_info(tb, fmt, arg...) dev_info(&(tb)->nhi->pdev->dev, fmt, ## arg)
-
+#define tb_dbg(tb, fmt, arg...) dev_dbg(&(tb)->nhi->pdev->dev, fmt, ## arg)
#define __TB_SW_PRINT(level, sw, fmt, arg...) \
do { \
@@ -338,7 +339,7 @@ static inline int tb_port_write(struct tb_port *port, const void *buffer,
#define tb_sw_WARN(sw, fmt, arg...) __TB_SW_PRINT(tb_WARN, sw, fmt, ##arg)
#define tb_sw_warn(sw, fmt, arg...) __TB_SW_PRINT(tb_warn, sw, fmt, ##arg)
#define tb_sw_info(sw, fmt, arg...) __TB_SW_PRINT(tb_info, sw, fmt, ##arg)
-
+#define tb_sw_dbg(sw, fmt, arg...) __TB_SW_PRINT(tb_dbg, sw, fmt, ##arg)
#define __TB_PORT_PRINT(level, _port, fmt, arg...) \
do { \
@@ -352,6 +353,8 @@ static inline int tb_port_write(struct tb_port *port, const void *buffer,
__TB_PORT_PRINT(tb_warn, port, fmt, ##arg)
#define tb_port_info(port, fmt, arg...) \
__TB_PORT_PRINT(tb_info, port, fmt, ##arg)
+#define tb_port_dbg(port, fmt, arg...) \
+ __TB_PORT_PRINT(tb_dbg, port, fmt, ##arg)
struct tb *icm_probe(struct tb_nhi *nhi);
struct tb *tb_probe(struct tb_nhi *nhi);
diff --git a/drivers/thunderbolt/tb_msgs.h b/drivers/thunderbolt/tb_msgs.h
index 2487e162c885..02c84aa3d018 100644
--- a/drivers/thunderbolt/tb_msgs.h
+++ b/drivers/thunderbolt/tb_msgs.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Thunderbolt control channel messages
*
* Copyright (C) 2014 Andreas Noever <andreas.noever@gmail.com>
* Copyright (C) 2017, Intel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#ifndef _TB_MSGS
diff --git a/drivers/thunderbolt/tb_regs.h b/drivers/thunderbolt/tb_regs.h
index 693b0353c3fe..6f1ff04ee195 100644
--- a/drivers/thunderbolt/tb_regs.h
+++ b/drivers/thunderbolt/tb_regs.h
@@ -1,12 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
- * Thunderbolt Cactus Ridge driver - Port/Switch config area registers
+ * Thunderbolt driver - Port/Switch config area registers
*
* Every thunderbolt device consists (logically) of a switch with multiple
* ports. Every port contains up to four config regions (HOPS, PORT, SWITCH,
* COUNTERS) which are used to configure the device.
*
* Copyright (c) 2014 Andreas Noever <andreas.noever@gmail.com>
+ * Copyright (C) 2018, Intel Corporation
*/
#ifndef _TB_REGS
diff --git a/drivers/thunderbolt/xdomain.c b/drivers/thunderbolt/xdomain.c
index db8bece63327..e27dd8beb94b 100644
--- a/drivers/thunderbolt/xdomain.c
+++ b/drivers/thunderbolt/xdomain.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Thunderbolt XDomain discovery protocol support
*
* Copyright (C) 2017, Intel Corporation
* Authors: Michael Jamet <michael.jamet@intel.com>
* Mika Westerberg <mika.westerberg@linux.intel.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/device.h>
diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c
index 34dead614149..8330fd809a05 100644
--- a/drivers/tty/amiserial.c
+++ b/drivers/tty/amiserial.c
@@ -996,63 +996,55 @@ static void rs_unthrottle(struct tty_struct * tty)
* ------------------------------------------------------------
*/
-static int get_serial_info(struct tty_struct *tty, struct serial_state *state,
- struct serial_struct __user * retinfo)
+static int get_serial_info(struct tty_struct *tty, struct serial_struct *ss)
{
- struct serial_struct tmp;
-
- memset(&tmp, 0, sizeof(tmp));
+ struct serial_state *state = tty->driver_data;
+
tty_lock(tty);
- tmp.line = tty->index;
- tmp.port = state->port;
- tmp.flags = state->tport.flags;
- tmp.xmit_fifo_size = state->xmit_fifo_size;
- tmp.baud_base = state->baud_base;
- tmp.close_delay = state->tport.close_delay;
- tmp.closing_wait = state->tport.closing_wait;
- tmp.custom_divisor = state->custom_divisor;
+ ss->line = tty->index;
+ ss->port = state->port;
+ ss->flags = state->tport.flags;
+ ss->xmit_fifo_size = state->xmit_fifo_size;
+ ss->baud_base = state->baud_base;
+ ss->close_delay = state->tport.close_delay;
+ ss->closing_wait = state->tport.closing_wait;
+ ss->custom_divisor = state->custom_divisor;
tty_unlock(tty);
- if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
- return -EFAULT;
return 0;
}
-static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
- struct serial_struct __user * new_info)
+static int set_serial_info(struct tty_struct *tty, struct serial_struct *ss)
{
+ struct serial_state *state = tty->driver_data;
struct tty_port *port = &state->tport;
- struct serial_struct new_serial;
bool change_spd;
int retval = 0;
- if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
- return -EFAULT;
-
tty_lock(tty);
- change_spd = ((new_serial.flags ^ port->flags) & ASYNC_SPD_MASK) ||
- new_serial.custom_divisor != state->custom_divisor;
- if (new_serial.irq || new_serial.port != state->port ||
- new_serial.xmit_fifo_size != state->xmit_fifo_size) {
+ change_spd = ((ss->flags ^ port->flags) & ASYNC_SPD_MASK) ||
+ ss->custom_divisor != state->custom_divisor;
+ if (ss->irq || ss->port != state->port ||
+ ss->xmit_fifo_size != state->xmit_fifo_size) {
tty_unlock(tty);
return -EINVAL;
}
if (!serial_isroot()) {
- if ((new_serial.baud_base != state->baud_base) ||
- (new_serial.close_delay != port->close_delay) ||
- (new_serial.xmit_fifo_size != state->xmit_fifo_size) ||
- ((new_serial.flags & ~ASYNC_USR_MASK) !=
+ if ((ss->baud_base != state->baud_base) ||
+ (ss->close_delay != port->close_delay) ||
+ (ss->xmit_fifo_size != state->xmit_fifo_size) ||
+ ((ss->flags & ~ASYNC_USR_MASK) !=
(port->flags & ~ASYNC_USR_MASK))) {
tty_unlock(tty);
return -EPERM;
}
port->flags = ((port->flags & ~ASYNC_USR_MASK) |
- (new_serial.flags & ASYNC_USR_MASK));
- state->custom_divisor = new_serial.custom_divisor;
+ (ss->flags & ASYNC_USR_MASK));
+ state->custom_divisor = ss->custom_divisor;
goto check_and_exit;
}
- if (new_serial.baud_base < 9600) {
+ if (ss->baud_base < 9600) {
tty_unlock(tty);
return -EINVAL;
}
@@ -1062,19 +1054,19 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
* At this point, we start making changes.....
*/
- state->baud_base = new_serial.baud_base;
+ state->baud_base = ss->baud_base;
port->flags = ((port->flags & ~ASYNC_FLAGS) |
- (new_serial.flags & ASYNC_FLAGS));
- state->custom_divisor = new_serial.custom_divisor;
- port->close_delay = new_serial.close_delay * HZ/100;
- port->closing_wait = new_serial.closing_wait * HZ/100;
+ (ss->flags & ASYNC_FLAGS));
+ state->custom_divisor = ss->custom_divisor;
+ port->close_delay = ss->close_delay * HZ/100;
+ port->closing_wait = ss->closing_wait * HZ/100;
port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
check_and_exit:
if (tty_port_initialized(port)) {
if (change_spd) {
/* warn about deprecation unless clearing */
- if (new_serial.flags & ASYNC_SPD_MASK)
+ if (ss->flags & ASYNC_SPD_MASK)
dev_warn_ratelimited(tty->dev, "use of SPD flags is deprecated\n");
change_speed(tty, state, NULL);
}
@@ -1084,7 +1076,6 @@ check_and_exit:
return retval;
}
-
/*
* get_lsr_info - get line status register info
*
@@ -1224,30 +1215,19 @@ static int rs_ioctl(struct tty_struct *tty,
if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
return -ENODEV;
- if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
- (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
+ if ((cmd != TIOCSERCONFIG) &&
(cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
if (tty_io_error(tty))
return -EIO;
}
switch (cmd) {
- case TIOCGSERIAL:
- return get_serial_info(tty, info, argp);
- case TIOCSSERIAL:
- return set_serial_info(tty, info, argp);
case TIOCSERCONFIG:
return 0;
case TIOCSERGETLSR: /* Get line status register */
return get_lsr_info(info, argp);
- case TIOCSERGSTRUCT:
- if (copy_to_user(argp,
- info, sizeof(struct serial_state)))
- return -EFAULT;
- return 0;
-
/*
* Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
* - mask passed in arg for lines of interest
@@ -1288,12 +1268,6 @@ static int rs_ioctl(struct tty_struct *tty,
finish_wait(&info->tport.delta_msr_wait, &wait);
return ret;
- case TIOCSERGWILD:
- case TIOCSERSWILD:
- /* "setserial -W" is called in Debian boot */
- printk ("TIOCSER?WILD ioctl obsolete, ignored.\n");
- return 0;
-
default:
return -ENOIOCTLCMD;
}
@@ -1607,6 +1581,8 @@ static const struct tty_operations serial_ops = {
.tiocmget = rs_tiocmget,
.tiocmset = rs_tiocmset,
.get_icount = rs_get_icount,
+ .set_serial = set_serial_info,
+ .get_serial = get_serial_info,
.proc_show = rs_proc_show,
};
diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c
index 6d3c58051ce3..4562c8060d09 100644
--- a/drivers/tty/cyclades.c
+++ b/drivers/tty/cyclades.c
@@ -2257,44 +2257,45 @@ static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty)
}
} /* set_line_char */
-static int cy_get_serial_info(struct cyclades_port *info,
- struct serial_struct __user *retinfo)
+static int cy_get_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
+ struct cyclades_port *info = tty->driver_data;
struct cyclades_card *cinfo = info->card;
- struct serial_struct tmp = {
- .type = info->type,
- .line = info->line,
- .port = (info->card - cy_card) * 0x100 + info->line -
- cinfo->first_line,
- .irq = cinfo->irq,
- .flags = info->port.flags,
- .close_delay = info->port.close_delay,
- .closing_wait = info->port.closing_wait,
- .baud_base = info->baud,
- .custom_divisor = info->custom_divisor,
- };
- return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
+
+ if (serial_paranoia_check(info, tty->name, "cy_ioctl"))
+ return -ENODEV;
+ ss->type = info->type;
+ ss->line = info->line;
+ ss->port = (info->card - cy_card) * 0x100 + info->line -
+ cinfo->first_line;
+ ss->irq = cinfo->irq;
+ ss->flags = info->port.flags;
+ ss->close_delay = info->port.close_delay;
+ ss->closing_wait = info->port.closing_wait;
+ ss->baud_base = info->baud;
+ ss->custom_divisor = info->custom_divisor;
+ return 0;
}
-static int
-cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty,
- struct serial_struct __user *new_info)
+static int cy_set_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
- struct serial_struct new_serial;
+ struct cyclades_port *info = tty->driver_data;
int old_flags;
int ret;
- if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
- return -EFAULT;
+ if (serial_paranoia_check(info, tty->name, "cy_ioctl"))
+ return -ENODEV;
mutex_lock(&info->port.mutex);
old_flags = info->port.flags;
if (!capable(CAP_SYS_ADMIN)) {
- if (new_serial.close_delay != info->port.close_delay ||
- new_serial.baud_base != info->baud ||
- (new_serial.flags & ASYNC_FLAGS &
+ if (ss->close_delay != info->port.close_delay ||
+ ss->baud_base != info->baud ||
+ (ss->flags & ASYNC_FLAGS &
~ASYNC_USR_MASK) !=
(info->port.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK))
{
@@ -2302,9 +2303,9 @@ cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty,
return -EPERM;
}
info->port.flags = (info->port.flags & ~ASYNC_USR_MASK) |
- (new_serial.flags & ASYNC_USR_MASK);
- info->baud = new_serial.baud_base;
- info->custom_divisor = new_serial.custom_divisor;
+ (ss->flags & ASYNC_USR_MASK);
+ info->baud = ss->baud_base;
+ info->custom_divisor = ss->custom_divisor;
goto check_and_exit;
}
@@ -2313,18 +2314,18 @@ cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty,
* At this point, we start making changes.....
*/
- info->baud = new_serial.baud_base;
- info->custom_divisor = new_serial.custom_divisor;
+ info->baud = ss->baud_base;
+ info->custom_divisor = ss->custom_divisor;
info->port.flags = (info->port.flags & ~ASYNC_FLAGS) |
- (new_serial.flags & ASYNC_FLAGS);
- info->port.close_delay = new_serial.close_delay * HZ / 100;
- info->port.closing_wait = new_serial.closing_wait * HZ / 100;
+ (ss->flags & ASYNC_FLAGS);
+ info->port.close_delay = ss->close_delay * HZ / 100;
+ info->port.closing_wait = ss->closing_wait * HZ / 100;
check_and_exit:
if (tty_port_initialized(&info->port)) {
- if ((new_serial.flags ^ old_flags) & ASYNC_SPD_MASK) {
+ if ((ss->flags ^ old_flags) & ASYNC_SPD_MASK) {
/* warn about deprecation unless clearing */
- if (new_serial.flags & ASYNC_SPD_MASK)
+ if (ss->flags & ASYNC_SPD_MASK)
dev_warn_ratelimited(tty->dev, "use of SPD flags is deprecated\n");
}
cy_set_line_char(info, tty);
@@ -2698,12 +2699,6 @@ cy_ioctl(struct tty_struct *tty,
case CYGETWAIT:
ret_val = info->port.closing_wait / (HZ / 100);
break;
- case TIOCGSERIAL:
- ret_val = cy_get_serial_info(info, argp);
- break;
- case TIOCSSERIAL:
- ret_val = cy_set_serial_info(info, tty, argp);
- break;
case TIOCSERGETLSR: /* Get line status register */
ret_val = get_lsr_info(info, argp);
break;
@@ -4011,6 +4006,8 @@ static const struct tty_operations cy_ops = {
.tiocmget = cy_tiocmget,
.tiocmset = cy_tiocmset,
.get_icount = cy_get_icount,
+ .set_serial = cy_set_serial_info,
+ .get_serial = cy_get_serial_info,
.proc_show = cyclades_proc_show,
};
diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c
index eea4049b5dcc..769e0a5d1dfc 100644
--- a/drivers/tty/ehv_bytechan.c
+++ b/drivers/tty/ehv_bytechan.c
@@ -128,8 +128,8 @@ static int find_console_handle(void)
*/
iprop = of_get_property(np, "hv-handle", NULL);
if (!iprop) {
- pr_err("ehv-bc: no 'hv-handle' property in %s node\n",
- np->name);
+ pr_err("ehv-bc: no 'hv-handle' property in %pOFn node\n",
+ np);
return 0;
}
stdout_bc = be32_to_cpu(*iprop);
@@ -661,8 +661,8 @@ static int ehv_bc_tty_probe(struct platform_device *pdev)
iprop = of_get_property(np, "hv-handle", NULL);
if (!iprop) {
- dev_err(&pdev->dev, "no 'hv-handle' property in %s node\n",
- np->name);
+ dev_err(&pdev->dev, "no 'hv-handle' property in %pOFn node\n",
+ np);
return -ENODEV;
}
@@ -682,8 +682,8 @@ static int ehv_bc_tty_probe(struct platform_device *pdev)
bc->rx_irq = irq_of_parse_and_map(np, 0);
bc->tx_irq = irq_of_parse_and_map(np, 1);
if ((bc->rx_irq == NO_IRQ) || (bc->tx_irq == NO_IRQ)) {
- dev_err(&pdev->dev, "no 'interrupts' property in %s node\n",
- np->name);
+ dev_err(&pdev->dev, "no 'interrupts' property in %pOFn node\n",
+ np);
ret = -ENODEV;
goto error;
}
diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c
index 1ef751c27ac6..fad3401e604d 100644
--- a/drivers/tty/ipwireless/tty.c
+++ b/drivers/tty/ipwireless/tty.c
@@ -248,22 +248,29 @@ static int ipw_write_room(struct tty_struct *linux_tty)
return room;
}
-static int ipwireless_get_serial_info(struct ipw_tty *tty,
- struct serial_struct __user *retinfo)
+static int ipwireless_get_serial_info(struct tty_struct *linux_tty,
+ struct serial_struct *ss)
{
- struct serial_struct tmp;
+ struct ipw_tty *tty = linux_tty->driver_data;
- memset(&tmp, 0, sizeof(tmp));
- tmp.type = PORT_UNKNOWN;
- tmp.line = tty->index;
- tmp.baud_base = 115200;
+ if (!tty)
+ return -ENODEV;
- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return -EFAULT;
+ if (!tty->port.count)
+ return -EINVAL;
+ ss->type = PORT_UNKNOWN;
+ ss->line = tty->index;
+ ss->baud_base = 115200;
return 0;
}
+static int ipwireless_set_serial_info(struct tty_struct *linux_tty,
+ struct serial_struct *ss)
+{
+ return 0; /* Keeps the PCMCIA scripts happy. */
+}
+
static int ipw_chars_in_buffer(struct tty_struct *linux_tty)
{
struct ipw_tty *tty = linux_tty->driver_data;
@@ -386,15 +393,6 @@ static int ipw_ioctl(struct tty_struct *linux_tty,
return -EINVAL;
/* FIXME: Exactly how is the tty object locked here .. */
-
- switch (cmd) {
- case TIOCGSERIAL:
- return ipwireless_get_serial_info(tty, (void __user *) arg);
-
- case TIOCSSERIAL:
- return 0; /* Keeps the PCMCIA scripts happy. */
- }
-
if (tty->tty_type == TTYTYPE_MODEM) {
switch (cmd) {
case PPPIOCGCHAN:
@@ -561,6 +559,8 @@ static const struct tty_operations tty_ops = {
.chars_in_buffer = ipw_chars_in_buffer,
.tiocmget = ipw_tiocmget,
.tiocmset = ipw_tiocmset,
+ .set_serial = ipwireless_set_serial_info,
+ .get_serial = ipwireless_get_serial_info,
};
int ipwireless_tty_init(void)
diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c
index 8d96e86966f1..e04a43e89f6b 100644
--- a/drivers/tty/isicom.c
+++ b/drivers/tty/isicom.c
@@ -1091,34 +1091,33 @@ static int isicom_tiocmset(struct tty_struct *tty,
}
static int isicom_set_serial_info(struct tty_struct *tty,
- struct serial_struct __user *info)
+ struct serial_struct *ss)
{
struct isi_port *port = tty->driver_data;
- struct serial_struct newinfo;
int reconfig_port;
- if (copy_from_user(&newinfo, info, sizeof(newinfo)))
- return -EFAULT;
+ if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
+ return -ENODEV;
mutex_lock(&port->port.mutex);
reconfig_port = ((port->port.flags & ASYNC_SPD_MASK) !=
- (newinfo.flags & ASYNC_SPD_MASK));
+ (ss->flags & ASYNC_SPD_MASK));
if (!capable(CAP_SYS_ADMIN)) {
- if ((newinfo.close_delay != port->port.close_delay) ||
- (newinfo.closing_wait != port->port.closing_wait) ||
- ((newinfo.flags & ~ASYNC_USR_MASK) !=
+ if ((ss->close_delay != port->port.close_delay) ||
+ (ss->closing_wait != port->port.closing_wait) ||
+ ((ss->flags & ~ASYNC_USR_MASK) !=
(port->port.flags & ~ASYNC_USR_MASK))) {
mutex_unlock(&port->port.mutex);
return -EPERM;
}
port->port.flags = ((port->port.flags & ~ASYNC_USR_MASK) |
- (newinfo.flags & ASYNC_USR_MASK));
+ (ss->flags & ASYNC_USR_MASK));
} else {
- port->port.close_delay = newinfo.close_delay;
- port->port.closing_wait = newinfo.closing_wait;
+ port->port.close_delay = ss->close_delay;
+ port->port.closing_wait = ss->closing_wait;
port->port.flags = ((port->port.flags & ~ASYNC_FLAGS) |
- (newinfo.flags & ASYNC_FLAGS));
+ (ss->flags & ASYNC_FLAGS));
}
if (reconfig_port) {
unsigned long flags;
@@ -1130,46 +1129,24 @@ static int isicom_set_serial_info(struct tty_struct *tty,
return 0;
}
-static int isicom_get_serial_info(struct isi_port *port,
- struct serial_struct __user *info)
-{
- struct serial_struct out_info;
-
- mutex_lock(&port->port.mutex);
- memset(&out_info, 0, sizeof(out_info));
-/* out_info.type = ? */
- out_info.line = port - isi_ports;
- out_info.port = port->card->base;
- out_info.irq = port->card->irq;
- out_info.flags = port->port.flags;
-/* out_info.baud_base = ? */
- out_info.close_delay = port->port.close_delay;
- out_info.closing_wait = port->port.closing_wait;
- mutex_unlock(&port->port.mutex);
- if (copy_to_user(info, &out_info, sizeof(out_info)))
- return -EFAULT;
- return 0;
-}
-
-static int isicom_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
+static int isicom_get_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
struct isi_port *port = tty->driver_data;
- void __user *argp = (void __user *)arg;
if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
return -ENODEV;
- switch (cmd) {
- case TIOCGSERIAL:
- return isicom_get_serial_info(port, argp);
-
- case TIOCSSERIAL:
- return isicom_set_serial_info(tty, argp);
-
- default:
- return -ENOIOCTLCMD;
- }
+ mutex_lock(&port->port.mutex);
+/* ss->type = ? */
+ ss->line = port - isi_ports;
+ ss->port = port->card->base;
+ ss->irq = port->card->irq;
+ ss->flags = port->port.flags;
+/* ss->baud_base = ? */
+ ss->close_delay = port->port.close_delay;
+ ss->closing_wait = port->port.closing_wait;
+ mutex_unlock(&port->port.mutex);
return 0;
}
@@ -1273,7 +1250,6 @@ static const struct tty_operations isicom_ops = {
.flush_chars = isicom_flush_chars,
.write_room = isicom_write_room,
.chars_in_buffer = isicom_chars_in_buffer,
- .ioctl = isicom_ioctl,
.set_termios = isicom_set_termios,
.throttle = isicom_throttle,
.unthrottle = isicom_unthrottle,
@@ -1284,6 +1260,8 @@ static const struct tty_operations isicom_ops = {
.tiocmget = isicom_tiocmget,
.tiocmset = isicom_tiocmset,
.break_ctl = isicom_send_break,
+ .get_serial = isicom_get_serial_info,
+ .set_serial = isicom_set_serial_info,
};
static const struct tty_port_operations isicom_port_ops = {
diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c
index 250a19f042d7..3a1a5e0ee93f 100644
--- a/drivers/tty/moxa.c
+++ b/drivers/tty/moxa.c
@@ -221,8 +221,8 @@ static int MoxaPortRxQueue(struct moxa_port *);
static int MoxaPortTxFree(struct moxa_port *);
static void MoxaPortTxDisable(struct moxa_port *);
static void MoxaPortTxEnable(struct moxa_port *);
-static int moxa_get_serial_info(struct moxa_port *, struct serial_struct __user *);
-static int moxa_set_serial_info(struct moxa_port *, struct serial_struct __user *);
+static int moxa_get_serial_info(struct tty_struct *, struct serial_struct *);
+static int moxa_set_serial_info(struct tty_struct *, struct serial_struct *);
static void MoxaSetFifo(struct moxa_port *port, int enable);
/*
@@ -375,16 +375,6 @@ copy:
}
break;
}
- case TIOCGSERIAL:
- mutex_lock(&ch->port.mutex);
- ret = moxa_get_serial_info(ch, argp);
- mutex_unlock(&ch->port.mutex);
- break;
- case TIOCSSERIAL:
- mutex_lock(&ch->port.mutex);
- ret = moxa_set_serial_info(ch, argp);
- mutex_unlock(&ch->port.mutex);
- break;
default:
ret = -ENOIOCTLCMD;
}
@@ -415,6 +405,8 @@ static const struct tty_operations moxa_ops = {
.break_ctl = moxa_break_ctl,
.tiocmget = moxa_tiocmget,
.tiocmset = moxa_tiocmset,
+ .set_serial = moxa_set_serial_info,
+ .get_serial = moxa_get_serial_info,
};
static const struct tty_port_operations moxa_port_ops = {
@@ -2034,46 +2026,55 @@ static void MoxaPortTxEnable(struct moxa_port *port)
moxafunc(port->tableAddr, FC_SetXonState, Magic_code);
}
-static int moxa_get_serial_info(struct moxa_port *info,
- struct serial_struct __user *retinfo)
+static int moxa_get_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
- struct serial_struct tmp = {
- .type = info->type,
- .line = info->port.tty->index,
- .flags = info->port.flags,
- .baud_base = 921600,
- .close_delay = info->port.close_delay
- };
- return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
+ struct moxa_port *info = tty->driver_data;
+
+ if (tty->index == MAX_PORTS)
+ return -EINVAL;
+ if (!info)
+ return -ENODEV;
+ mutex_lock(&info->port.mutex);
+ ss->type = info->type,
+ ss->line = info->port.tty->index,
+ ss->flags = info->port.flags,
+ ss->baud_base = 921600,
+ ss->close_delay = info->port.close_delay;
+ mutex_unlock(&info->port.mutex);
+ return 0;
}
-static int moxa_set_serial_info(struct moxa_port *info,
- struct serial_struct __user *new_info)
+static int moxa_set_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
- struct serial_struct new_serial;
+ struct moxa_port *info = tty->driver_data;
- if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
- return -EFAULT;
+ if (tty->index == MAX_PORTS)
+ return -EINVAL;
+ if (!info)
+ return -ENODEV;
- if (new_serial.irq != 0 || new_serial.port != 0 ||
- new_serial.custom_divisor != 0 ||
- new_serial.baud_base != 921600)
+ if (ss->irq != 0 || ss->port != 0 ||
+ ss->custom_divisor != 0 ||
+ ss->baud_base != 921600)
return -EPERM;
+ mutex_lock(&info->port.mutex);
if (!capable(CAP_SYS_ADMIN)) {
- if (((new_serial.flags & ~ASYNC_USR_MASK) !=
- (info->port.flags & ~ASYNC_USR_MASK)))
+ if (((ss->flags & ~ASYNC_USR_MASK) !=
+ (info->port.flags & ~ASYNC_USR_MASK))) {
+ mutex_unlock(&info->port.mutex);
return -EPERM;
- } else
- info->port.close_delay = new_serial.close_delay * HZ / 100;
-
- new_serial.flags = (new_serial.flags & ~ASYNC_FLAGS);
- new_serial.flags |= (info->port.flags & ASYNC_FLAGS);
+ }
+ }
+ info->port.close_delay = ss->close_delay * HZ / 100;
- MoxaSetFifo(info, new_serial.type == PORT_16550A);
+ MoxaSetFifo(info, ss->type == PORT_16550A);
- info->type = new_serial.type;
+ info->type = ss->type;
+ mutex_unlock(&info->port.mutex);
return 0;
}
diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c
index 8bc15cb67a58..9d00ff5ef961 100644
--- a/drivers/tty/mxser.c
+++ b/drivers/tty/mxser.c
@@ -1207,76 +1207,90 @@ static int mxser_chars_in_buffer(struct tty_struct *tty)
* ------------------------------------------------------------
*/
static int mxser_get_serial_info(struct tty_struct *tty,
- struct serial_struct __user *retinfo)
+ struct serial_struct *ss)
{
struct mxser_port *info = tty->driver_data;
- struct serial_struct tmp = {
- .type = info->type,
- .line = tty->index,
- .port = info->ioaddr,
- .irq = info->board->irq,
- .flags = info->port.flags,
- .baud_base = info->baud_base,
- .close_delay = info->port.close_delay,
- .closing_wait = info->port.closing_wait,
- .custom_divisor = info->custom_divisor,
- };
- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return -EFAULT;
+ struct tty_port *port = &info->port;
+
+ if (tty->index == MXSER_PORTS)
+ return -ENOTTY;
+
+ mutex_lock(&port->mutex);
+ ss->type = info->type,
+ ss->line = tty->index,
+ ss->port = info->ioaddr,
+ ss->irq = info->board->irq,
+ ss->flags = info->port.flags,
+ ss->baud_base = info->baud_base,
+ ss->close_delay = info->port.close_delay,
+ ss->closing_wait = info->port.closing_wait,
+ ss->custom_divisor = info->custom_divisor,
+ mutex_unlock(&port->mutex);
return 0;
}
static int mxser_set_serial_info(struct tty_struct *tty,
- struct serial_struct __user *new_info)
+ struct serial_struct *ss)
{
struct mxser_port *info = tty->driver_data;
struct tty_port *port = &info->port;
- struct serial_struct new_serial;
speed_t baud;
unsigned long sl_flags;
unsigned int flags;
int retval = 0;
- if (!new_info || !info->ioaddr)
+ 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 (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
- return -EFAULT;
+ }
- if (new_serial.irq != info->board->irq ||
- new_serial.port != info->ioaddr)
+ if (ss->irq != info->board->irq ||
+ ss->port != info->ioaddr) {
+ mutex_unlock(&port->mutex);
return -EINVAL;
+ }
flags = port->flags & ASYNC_SPD_MASK;
if (!capable(CAP_SYS_ADMIN)) {
- if ((new_serial.baud_base != info->baud_base) ||
- (new_serial.close_delay != info->port.close_delay) ||
- ((new_serial.flags & ~ASYNC_USR_MASK) != (info->port.flags & ~ASYNC_USR_MASK)))
+ if ((ss->baud_base != info->baud_base) ||
+ (ss->close_delay != info->port.close_delay) ||
+ ((ss->flags & ~ASYNC_USR_MASK) != (info->port.flags & ~ASYNC_USR_MASK))) {
+ mutex_unlock(&port->mutex);
return -EPERM;
+ }
info->port.flags = ((info->port.flags & ~ASYNC_USR_MASK) |
- (new_serial.flags & ASYNC_USR_MASK));
+ (ss->flags & ASYNC_USR_MASK));
} else {
/*
* OK, past this point, all the error checking has been done.
* At this point, we start making changes.....
*/
port->flags = ((port->flags & ~ASYNC_FLAGS) |
- (new_serial.flags & ASYNC_FLAGS));
- port->close_delay = new_serial.close_delay * HZ / 100;
- port->closing_wait = new_serial.closing_wait * HZ / 100;
+ (ss->flags & ASYNC_FLAGS));
+ port->close_delay = ss->close_delay * HZ / 100;
+ port->closing_wait = ss->closing_wait * HZ / 100;
port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST &&
- (new_serial.baud_base != info->baud_base ||
- new_serial.custom_divisor !=
+ (ss->baud_base != info->baud_base ||
+ ss->custom_divisor !=
info->custom_divisor)) {
- if (new_serial.custom_divisor == 0)
+ if (ss->custom_divisor == 0) {
+ mutex_unlock(&port->mutex);
return -EINVAL;
- baud = new_serial.baud_base / new_serial.custom_divisor;
+ }
+ baud = ss->baud_base / ss->custom_divisor;
tty_encode_baud_rate(tty, baud, baud);
}
}
- info->type = new_serial.type;
+ info->type = ss->type;
process_txrx_fifo(info);
@@ -1291,6 +1305,7 @@ static int mxser_set_serial_info(struct tty_struct *tty,
if (retval == 0)
tty_port_set_initialized(port, 1);
}
+ mutex_unlock(&port->mutex);
return retval;
}
@@ -1660,11 +1675,9 @@ static int mxser_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
struct mxser_port *info = tty->driver_data;
- struct tty_port *port = &info->port;
struct async_icount cnow;
unsigned long flags;
void __user *argp = (void __user *)arg;
- int retval;
if (tty->index == MXSER_PORTS)
return mxser_ioctl_special(cmd, argp);
@@ -1708,20 +1721,10 @@ static int mxser_ioctl(struct tty_struct *tty,
return 0;
}
- if (cmd != TIOCGSERIAL && cmd != TIOCMIWAIT && tty_io_error(tty))
+ if (cmd != TIOCMIWAIT && tty_io_error(tty))
return -EIO;
switch (cmd) {
- case TIOCGSERIAL:
- mutex_lock(&port->mutex);
- retval = mxser_get_serial_info(tty, argp);
- mutex_unlock(&port->mutex);
- return retval;
- case TIOCSSERIAL:
- mutex_lock(&port->mutex);
- retval = mxser_set_serial_info(tty, argp);
- mutex_unlock(&port->mutex);
- return retval;
case TIOCSERGETLSR: /* Get line status register */
return mxser_get_lsr_info(info, argp);
/*
@@ -2325,6 +2328,8 @@ static const struct tty_operations mxser_ops = {
.wait_until_sent = mxser_wait_until_sent,
.tiocmget = mxser_tiocmget,
.tiocmset = mxser_tiocmset,
+ .set_serial = mxser_set_serial_info,
+ .get_serial = mxser_get_serial_info,
.get_icount = mxser_get_icount,
};
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index 86b7e20ffd7f..6f7da9a9d76f 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -2614,14 +2614,6 @@ static int gsmld_ioctl(struct tty_struct *tty, struct file *file,
}
}
-#ifdef CONFIG_COMPAT
-static long gsmld_compat_ioctl(struct tty_struct *tty, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- return gsmld_ioctl(tty, file, cmd, arg);
-}
-#endif
-
/*
* Network interface
*
@@ -2833,9 +2825,6 @@ static struct tty_ldisc_ops tty_ldisc_packet = {
.flush_buffer = gsmld_flush_buffer,
.read = gsmld_read,
.write = gsmld_write,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = gsmld_compat_ioctl,
-#endif
.ioctl = gsmld_ioctl,
.poll = gsmld_poll,
.receive_buf = gsmld_receive_buf,
diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c
index dbf1ab36758e..749a608c40b0 100644
--- a/drivers/tty/n_r3964.c
+++ b/drivers/tty/n_r3964.c
@@ -134,6 +134,10 @@ 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);
@@ -149,6 +153,9 @@ static struct tty_ldisc_ops tty_ldisc_N_R3964 = {
.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,
@@ -1210,6 +1217,21 @@ static int r3964_ioctl(struct tty_struct *tty, struct file *file,
}
}
+#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");
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 431742201709..3ad460219fd6 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -152,17 +152,28 @@ static inline unsigned char *echo_buf_addr(struct n_tty_data *ldata, size_t i)
return &ldata->echo_buf[i & (N_TTY_BUF_SIZE - 1)];
}
+/* If we are not echoing the data, perhaps this is a secret so erase it */
+static void zero_buffer(struct tty_struct *tty, u8 *buffer, int size)
+{
+ bool icanon = !!L_ICANON(tty);
+ bool no_echo = !L_ECHO(tty);
+
+ if (icanon && no_echo)
+ memset(buffer, 0x00, size);
+}
+
static int tty_copy_to_user(struct tty_struct *tty, void __user *to,
size_t tail, size_t n)
{
struct n_tty_data *ldata = tty->disc_data;
size_t size = N_TTY_BUF_SIZE - tail;
- const void *from = read_buf_addr(ldata, tail);
+ void *from = read_buf_addr(ldata, tail);
int uncopied;
if (n > size) {
tty_audit_add_data(tty, from, size);
uncopied = copy_to_user(to, from, size);
+ zero_buffer(tty, from, size - uncopied);
if (uncopied)
return uncopied;
to += size;
@@ -171,7 +182,9 @@ static int tty_copy_to_user(struct tty_struct *tty, void __user *to,
}
tty_audit_add_data(tty, from, n);
- return copy_to_user(to, from, n);
+ uncopied = copy_to_user(to, from, n);
+ zero_buffer(tty, from, n - uncopied);
+ return uncopied;
}
/**
@@ -1960,11 +1973,12 @@ static int copy_from_read_buf(struct tty_struct *tty,
n = min(head - ldata->read_tail, N_TTY_BUF_SIZE - tail);
n = min(*nr, n);
if (n) {
- const unsigned char *from = read_buf_addr(ldata, tail);
+ unsigned char *from = read_buf_addr(ldata, tail);
retval = copy_to_user(*b, from, n);
n -= retval;
is_eof = n == 1 && *from == EOF_CHAR(tty);
tty_audit_add_data(tty, from, n);
+ zero_buffer(tty, from, n);
smp_store_release(&ldata->read_tail, ldata->read_tail + n);
/* Turn single EOF into zero-length read */
if (L_EXTPROC(tty) && ldata->icanon && is_eof &&
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index 678406e0948b..00099a8439d2 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -28,6 +28,7 @@
#include <linux/mount.h>
#include <linux/file.h>
#include <linux/ioctl.h>
+#include <linux/compat.h>
#undef TTY_DEBUG_HANGUP
#ifdef TTY_DEBUG_HANGUP
@@ -488,6 +489,7 @@ static int pty_bsd_ioctl(struct tty_struct *tty,
return -ENOIOCTLCMD;
}
+#ifdef CONFIG_COMPAT
static long pty_bsd_compat_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
@@ -495,8 +497,11 @@ static long pty_bsd_compat_ioctl(struct tty_struct *tty,
* PTY ioctls don't require any special translation between 32-bit and
* 64-bit userspace, they are already compatible.
*/
- return pty_bsd_ioctl(tty, cmd, arg);
+ return pty_bsd_ioctl(tty, cmd, (unsigned long)compat_ptr(arg));
}
+#else
+#define pty_bsd_compat_ioctl NULL
+#endif
static int legacy_count = CONFIG_LEGACY_PTY_COUNT;
/*
@@ -676,6 +681,7 @@ static int pty_unix98_ioctl(struct tty_struct *tty,
return -ENOIOCTLCMD;
}
+#ifdef CONFIG_COMPAT
static long pty_unix98_compat_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
@@ -683,8 +689,12 @@ static long pty_unix98_compat_ioctl(struct tty_struct *tty,
* PTY ioctls don't require any special translation between 32-bit and
* 64-bit userspace, they are already compatible.
*/
- return pty_unix98_ioctl(tty, cmd, arg);
+ return pty_unix98_ioctl(tty, cmd,
+ cmd == TIOCSIG ? arg : (unsigned long)compat_ptr(arg));
}
+#else
+#define pty_unix98_compat_ioctl NULL
+#endif
/**
* ptm_unix98_lookup - find a pty master
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 8fe3d0ed229e..94f3e1c64490 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -130,12 +130,8 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
l = l->next;
- if (l == i->head && pass_counter++ > PASS_LIMIT) {
- /* If we hit this, we're dead. */
- printk_ratelimited(KERN_ERR
- "serial8250: too much work for irq%d\n", irq);
+ if (l == i->head && pass_counter++ > PASS_LIMIT)
break;
- }
} while (l != end);
spin_unlock(&i->lock);
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index fa8dcb470640..d31b975dd3fd 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -630,10 +630,6 @@ static int dw8250_probe(struct platform_device *pdev)
if (!data->skip_autocfg)
dw8250_setup_port(p);
-#ifdef CONFIG_PM
- uart.capabilities |= UART_CAP_RPM;
-#endif
-
/* If we have a valid fifosize, try hooking up DMA */
if (p->fifosize) {
data->dma.rxconf.src_maxburst = p->fifosize / 4;
diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c
index af8beefe9b5c..877fd7f8a8ed 100644
--- a/drivers/tty/serial/8250/8250_of.c
+++ b/drivers/tty/serial/8250/8250_of.c
@@ -58,7 +58,7 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
struct resource resource;
struct device_node *np = ofdev->dev.of_node;
u32 clk, spd, prop;
- int ret;
+ int ret, irq;
memset(port, 0, sizeof *port);
@@ -143,21 +143,27 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
if (ret >= 0)
port->line = ret;
- port->irq = irq_of_parse_and_map(np, 0);
- if (!port->irq) {
- ret = -EPROBE_DEFER;
- goto err_unprepare;
+ irq = of_irq_get(np, 0);
+ if (irq < 0) {
+ if (irq == -EPROBE_DEFER) {
+ ret = -EPROBE_DEFER;
+ goto err_unprepare;
+ }
+ /* IRQ support not mandatory */
+ irq = 0;
}
+ port->irq = irq;
+
info->rst = devm_reset_control_get_optional_shared(&ofdev->dev, NULL);
if (IS_ERR(info->rst)) {
ret = PTR_ERR(info->rst);
- goto err_dispose;
+ goto err_unprepare;
}
ret = reset_control_deassert(info->rst);
if (ret)
- goto err_dispose;
+ goto err_unprepare;
port->type = type;
port->uartclk = clk;
@@ -184,8 +190,6 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
port->handle_irq = fsl8250_handle_irq;
return 0;
-err_dispose:
- irq_dispose_mapping(port->irq);
err_unprepare:
clk_disable_unprepare(info->clk);
err_pmruntime:
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 3f779d25ec0c..f776b3eafb96 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -552,11 +552,30 @@ static unsigned int serial_icr_read(struct uart_8250_port *up, int offset)
*/
static void serial8250_clear_fifos(struct uart_8250_port *p)
{
+ unsigned char fcr;
+ unsigned char clr_mask = UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT;
+
if (p->capabilities & UART_CAP_FIFO) {
- serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO);
- serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO |
- UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
- serial_out(p, UART_FCR, 0);
+ /*
+ * Make sure to avoid changing FCR[7:3] and ENABLE_FIFO bits.
+ * In case ENABLE_FIFO is not set, there is nothing to flush
+ * so just return. Furthermore, on certain implementations of
+ * the 8250 core, the FCR[7:3] bits may only be changed under
+ * specific conditions and changing them if those conditions
+ * are not met can have nasty side effects. One such core is
+ * the 8250-omap present in TI AM335x.
+ */
+ fcr = serial_in(p, UART_FCR);
+
+ /* FIFO is not enabled, there's nothing to clear. */
+ if (!(fcr & UART_FCR_ENABLE_FIFO))
+ return;
+
+ fcr |= clr_mask;
+ serial_out(p, UART_FCR, fcr);
+
+ fcr &= ~clr_mask;
+ serial_out(p, UART_FCR, fcr);
}
}
@@ -1448,7 +1467,7 @@ static void __do_stop_tx_rs485(struct uart_8250_port *p)
* Enable previously disabled RX interrupts.
*/
if (!(p->port.rs485.flags & SER_RS485_RX_DURING_TX)) {
- serial8250_clear_and_reinit_fifos(p);
+ serial8250_clear_fifos(p);
p->ier |= UART_IER_RLSI | UART_IER_RDI;
serial_port_out(&p->port, UART_IER, p->ier);
diff --git a/drivers/tty/serial/8250/8250_uniphier.c b/drivers/tty/serial/8250/8250_uniphier.c
index 28d88ccf5a0c..164ba133437a 100644
--- a/drivers/tty/serial/8250/8250_uniphier.c
+++ b/drivers/tty/serial/8250/8250_uniphier.c
@@ -12,9 +12,6 @@
#include "8250.h"
-/* Most (but not all) of UniPhier UART devices have 64-depth FIFO. */
-#define UNIPHIER_UART_DEFAULT_FIFO_SIZE 64
-
/*
* This hardware is similar to 8250, but its register map is a bit different:
* - MMIO32 (regshift = 2)
@@ -158,42 +155,6 @@ static void uniphier_serial_dl_write(struct uart_8250_port *up, int value)
writel(value, up->port.membase + UNIPHIER_UART_DLR);
}
-static int uniphier_of_serial_setup(struct device *dev, struct uart_port *port,
- struct uniphier8250_priv *priv)
-{
- int ret;
- u32 prop;
- struct device_node *np = dev->of_node;
-
- ret = of_alias_get_id(np, "serial");
- if (ret < 0) {
- dev_err(dev, "failed to get alias id\n");
- return ret;
- }
- port->line = ret;
-
- /* Get clk rate through clk driver */
- 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);
- }
-
- ret = clk_prepare_enable(priv->clk);
- if (ret < 0)
- return ret;
-
- port->uartclk = clk_get_rate(priv->clk);
-
- /* Check for fifo size */
- if (of_property_read_u32(np, "fifo-size", &prop) == 0)
- port->fifosize = prop;
- else
- port->fifosize = UNIPHIER_UART_DEFAULT_FIFO_SIZE;
-
- return 0;
-}
-
static int uniphier_uart_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -226,10 +187,25 @@ static int uniphier_uart_probe(struct platform_device *pdev)
memset(&up, 0, sizeof(up));
- ret = uniphier_of_serial_setup(dev, &up.port, priv);
- if (ret < 0)
+ ret = of_alias_get_id(dev->of_node, "serial");
+ if (ret < 0) {
+ dev_err(dev, "failed to get alias id\n");
+ return ret;
+ }
+ up.port.line = ret;
+
+ 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);
+ }
+
+ ret = clk_prepare_enable(priv->clk);
+ if (ret)
return ret;
+ up.port.uartclk = clk_get_rate(priv->clk);
+
spin_lock_init(&priv->atomic_write_lock);
up.port.dev = dev;
@@ -241,10 +217,14 @@ static int uniphier_uart_probe(struct platform_device *pdev)
up.port.type = PORT_16550A;
up.port.iotype = UPIO_MEM32;
+ up.port.fifosize = 64;
up.port.regshift = UNIPHIER_UART_REGSHIFT;
up.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE;
up.capabilities = UART_CAP_FIFO;
+ if (of_property_read_bool(dev->of_node, "auto-flow-control"))
+ up.capabilities |= UART_CAP_AFE;
+
up.port.serial_in = uniphier_serial_in;
up.port.serial_out = uniphier_serial_out;
up.dl_read = uniphier_serial_dl_read;
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index f005eaf8bc57..15c2c5463835 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -375,7 +375,7 @@ config SERIAL_8250_RT288X
config SERIAL_8250_OMAP
tristate "Support for OMAP internal UART (8250 based driver)"
- depends on SERIAL_8250 && ARCH_OMAP2PLUS
+ depends on SERIAL_8250 && (ARCH_OMAP2PLUS || ARCH_K3)
help
If you have a machine based on an Texas Instruments OMAP CPU you
can enable its onboard serial ports by enabling this option.
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index df8bd0c7b97d..32886c304641 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -118,6 +118,7 @@ config SERIAL_ATMEL
depends on ARCH_AT91 || COMPILE_TEST
select SERIAL_CORE
select SERIAL_MCTRL_GPIO if GPIOLIB
+ select MFD_AT91_USART
help
This enables the driver for the on-chip UARTs of the Atmel
AT91 processors.
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 8e4428725848..05147fe24343 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -34,6 +34,7 @@
#include <linux/suspend.h>
#include <linux/mm.h>
+#include <asm/div64.h>
#include <asm/io.h>
#include <asm/ioctls.h>
@@ -147,6 +148,8 @@ struct atmel_uart_port {
struct circ_buf rx_ring;
struct mctrl_gpios *gpios;
+ u32 backup_mode; /* MR saved during iso7816 operations */
+ u32 backup_brgr; /* BRGR saved during iso7816 operations */
unsigned int tx_done_mask;
u32 fifo_size;
u32 rts_high;
@@ -163,6 +166,10 @@ struct atmel_uart_port {
unsigned int pending_status;
spinlock_t lock_suspended;
+ /* ISO7816 */
+ unsigned int fidi_min;
+ unsigned int fidi_max;
+
#ifdef CONFIG_PM
struct {
u32 cr;
@@ -193,8 +200,7 @@ static struct console atmel_console;
#if defined(CONFIG_OF)
static const struct of_device_id atmel_serial_dt_ids[] = {
- { .compatible = "atmel,at91rm9200-usart" },
- { .compatible = "atmel,at91sam9260-usart" },
+ { .compatible = "atmel,at91rm9200-usart-serial" },
{ /* sentinel */ }
};
#endif
@@ -362,6 +368,127 @@ static int atmel_config_rs485(struct uart_port *port,
return 0;
}
+static unsigned int atmel_calc_cd(struct uart_port *port,
+ struct serial_iso7816 *iso7816conf)
+{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ unsigned int cd;
+ u64 mck_rate;
+
+ mck_rate = (u64)clk_get_rate(atmel_port->clk);
+ do_div(mck_rate, iso7816conf->clk);
+ cd = mck_rate;
+ return cd;
+}
+
+static unsigned int atmel_calc_fidi(struct uart_port *port,
+ struct serial_iso7816 *iso7816conf)
+{
+ u64 fidi = 0;
+
+ if (iso7816conf->sc_fi && iso7816conf->sc_di) {
+ fidi = (u64)iso7816conf->sc_fi;
+ do_div(fidi, iso7816conf->sc_di);
+ }
+ return (u32)fidi;
+}
+
+/* Enable or disable the iso7816 support */
+/* Called with interrupts disabled */
+static int atmel_config_iso7816(struct uart_port *port,
+ struct serial_iso7816 *iso7816conf)
+{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ unsigned int mode;
+ unsigned int cd, fidi;
+ int ret = 0;
+
+ /* Disable interrupts */
+ atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask);
+
+ mode = atmel_uart_readl(port, ATMEL_US_MR);
+
+ if (iso7816conf->flags & SER_ISO7816_ENABLED) {
+ mode &= ~ATMEL_US_USMODE;
+
+ if (iso7816conf->tg > 255) {
+ dev_err(port->dev, "ISO7816: Timeguard exceeding 255\n");
+ memset(iso7816conf, 0, sizeof(struct serial_iso7816));
+ ret = -EINVAL;
+ goto err_out;
+ }
+
+ if ((iso7816conf->flags & SER_ISO7816_T_PARAM)
+ == SER_ISO7816_T(0)) {
+ mode |= ATMEL_US_USMODE_ISO7816_T0 | ATMEL_US_DSNACK;
+ } else if ((iso7816conf->flags & SER_ISO7816_T_PARAM)
+ == SER_ISO7816_T(1)) {
+ mode |= ATMEL_US_USMODE_ISO7816_T1 | ATMEL_US_INACK;
+ } else {
+ dev_err(port->dev, "ISO7816: Type not supported\n");
+ memset(iso7816conf, 0, sizeof(struct serial_iso7816));
+ ret = -EINVAL;
+ goto err_out;
+ }
+
+ mode &= ~(ATMEL_US_USCLKS | ATMEL_US_NBSTOP | ATMEL_US_PAR);
+
+ /* select mck clock, and output */
+ mode |= ATMEL_US_USCLKS_MCK | ATMEL_US_CLKO;
+ /* set parity for normal/inverse mode + max iterations */
+ mode |= ATMEL_US_PAR_EVEN | ATMEL_US_NBSTOP_1 | ATMEL_US_MAX_ITER(3);
+
+ cd = atmel_calc_cd(port, iso7816conf);
+ fidi = atmel_calc_fidi(port, iso7816conf);
+ if (fidi == 0) {
+ dev_warn(port->dev, "ISO7816 fidi = 0, Generator generates no signal\n");
+ } else if (fidi < atmel_port->fidi_min
+ || fidi > atmel_port->fidi_max) {
+ dev_err(port->dev, "ISO7816 fidi = %u, value not supported\n", fidi);
+ memset(iso7816conf, 0, sizeof(struct serial_iso7816));
+ ret = -EINVAL;
+ goto err_out;
+ }
+
+ if (!(port->iso7816.flags & SER_ISO7816_ENABLED)) {
+ /* port not yet in iso7816 mode: store configuration */
+ atmel_port->backup_mode = atmel_uart_readl(port, ATMEL_US_MR);
+ atmel_port->backup_brgr = atmel_uart_readl(port, ATMEL_US_BRGR);
+ }
+
+ atmel_uart_writel(port, ATMEL_US_TTGR, iso7816conf->tg);
+ atmel_uart_writel(port, ATMEL_US_BRGR, cd);
+ atmel_uart_writel(port, ATMEL_US_FIDI, fidi);
+
+ atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXDIS | ATMEL_US_RXEN);
+ atmel_port->tx_done_mask = ATMEL_US_TXEMPTY | ATMEL_US_NACK | ATMEL_US_ITERATION;
+ } else {
+ dev_dbg(port->dev, "Setting UART back to RS232\n");
+ /* back to last RS232 settings */
+ mode = atmel_port->backup_mode;
+ memset(iso7816conf, 0, sizeof(struct serial_iso7816));
+ atmel_uart_writel(port, ATMEL_US_TTGR, 0);
+ atmel_uart_writel(port, ATMEL_US_BRGR, atmel_port->backup_brgr);
+ atmel_uart_writel(port, ATMEL_US_FIDI, 0x174);
+
+ if (atmel_use_pdc_tx(port))
+ atmel_port->tx_done_mask = ATMEL_US_ENDTX |
+ ATMEL_US_TXBUFE;
+ else
+ atmel_port->tx_done_mask = ATMEL_US_TXRDY;
+ }
+
+ port->iso7816 = *iso7816conf;
+
+ atmel_uart_writel(port, ATMEL_US_MR, mode);
+
+err_out:
+ /* Enable interrupts */
+ atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask);
+
+ return ret;
+}
+
/*
* Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty.
*/
@@ -481,8 +608,9 @@ static void atmel_stop_tx(struct uart_port *port)
/* Disable interrupts */
atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask);
- if ((port->rs485.flags & SER_RS485_ENABLED) &&
- !(port->rs485.flags & SER_RS485_RX_DURING_TX))
+ if (((port->rs485.flags & SER_RS485_ENABLED) &&
+ !(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
+ port->iso7816.flags & SER_ISO7816_ENABLED)
atmel_start_rx(port);
}
@@ -500,8 +628,9 @@ static void atmel_start_tx(struct uart_port *port)
return;
if (atmel_use_pdc_tx(port) || atmel_use_dma_tx(port))
- if ((port->rs485.flags & SER_RS485_ENABLED) &&
- !(port->rs485.flags & SER_RS485_RX_DURING_TX))
+ if (((port->rs485.flags & SER_RS485_ENABLED) &&
+ !(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
+ port->iso7816.flags & SER_ISO7816_ENABLED)
atmel_stop_rx(port);
if (atmel_use_pdc_tx(port))
@@ -799,8 +928,9 @@ static void atmel_complete_tx_dma(void *arg)
*/
if (!uart_circ_empty(xmit))
atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx);
- else if ((port->rs485.flags & SER_RS485_ENABLED) &&
- !(port->rs485.flags & SER_RS485_RX_DURING_TX)) {
+ else if (((port->rs485.flags & SER_RS485_ENABLED) &&
+ !(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
+ port->iso7816.flags & SER_ISO7816_ENABLED) {
/* DMA done, stop TX, start RX for RS485 */
atmel_start_rx(port);
}
@@ -915,6 +1045,7 @@ static void atmel_tx_dma(struct uart_port *port)
static int atmel_prepare_tx_dma(struct uart_port *port)
{
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ struct device *mfd_dev = port->dev->parent;
dma_cap_mask_t mask;
struct dma_slave_config config;
int ret, nent;
@@ -922,7 +1053,7 @@ static int atmel_prepare_tx_dma(struct uart_port *port)
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
- atmel_port->chan_tx = dma_request_slave_channel(port->dev, "tx");
+ atmel_port->chan_tx = dma_request_slave_channel(mfd_dev, "tx");
if (atmel_port->chan_tx == NULL)
goto chan_err;
dev_info(port->dev, "using %s for tx DMA transfers\n",
@@ -1093,6 +1224,7 @@ static void atmel_rx_from_dma(struct uart_port *port)
static int atmel_prepare_rx_dma(struct uart_port *port)
{
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ struct device *mfd_dev = port->dev->parent;
struct dma_async_tx_descriptor *desc;
dma_cap_mask_t mask;
struct dma_slave_config config;
@@ -1104,7 +1236,7 @@ static int atmel_prepare_rx_dma(struct uart_port *port)
dma_cap_zero(mask);
dma_cap_set(DMA_CYCLIC, mask);
- atmel_port->chan_rx = dma_request_slave_channel(port->dev, "rx");
+ atmel_port->chan_rx = dma_request_slave_channel(mfd_dev, "rx");
if (atmel_port->chan_rx == NULL)
goto chan_err;
dev_info(port->dev, "using %s for rx DMA transfers\n",
@@ -1281,6 +1413,9 @@ atmel_handle_status(struct uart_port *port, unsigned int pending,
wake_up_interruptible(&port->state->port.delta_msr_wait);
}
}
+
+ if (pending & (ATMEL_US_NACK | ATMEL_US_ITERATION))
+ dev_dbg(port->dev, "ISO7816 ERROR (0x%08x)\n", pending);
}
/*
@@ -1373,8 +1508,9 @@ static void atmel_tx_pdc(struct uart_port *port)
atmel_uart_writel(port, ATMEL_US_IER,
atmel_port->tx_done_mask);
} else {
- if ((port->rs485.flags & SER_RS485_ENABLED) &&
- !(port->rs485.flags & SER_RS485_RX_DURING_TX)) {
+ if (((port->rs485.flags & SER_RS485_ENABLED) &&
+ !(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
+ port->iso7816.flags & SER_ISO7816_ENABLED) {
/* DMA done, stop TX, start RX for RS485 */
atmel_start_rx(port);
}
@@ -1726,6 +1862,22 @@ static void atmel_get_ip_name(struct uart_port *port)
atmel_port->has_frac_baudrate = true;
atmel_port->has_hw_timer = true;
atmel_port->rtor = ATMEL_US_RTOR;
+ version = atmel_uart_readl(port, ATMEL_US_VERSION);
+ switch (version) {
+ case 0x814: /* sama5d2 */
+ /* fall through */
+ case 0x701: /* sama5d4 */
+ atmel_port->fidi_min = 3;
+ atmel_port->fidi_max = 65535;
+ break;
+ case 0x502: /* sam9x5, sama5d3 */
+ atmel_port->fidi_min = 3;
+ atmel_port->fidi_max = 2047;
+ break;
+ default:
+ atmel_port->fidi_min = 1;
+ atmel_port->fidi_max = 2047;
+ }
} else if (name == dbgu_uart) {
dev_dbg(port->dev, "Dbgu or uart without hw timer\n");
} else {
@@ -2099,6 +2251,17 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
atmel_uart_writel(port, ATMEL_US_TTGR,
port->rs485.delay_rts_after_send);
mode |= ATMEL_US_USMODE_RS485;
+ } else if (port->iso7816.flags & SER_ISO7816_ENABLED) {
+ atmel_uart_writel(port, ATMEL_US_TTGR, port->iso7816.tg);
+ /* select mck clock, and output */
+ mode |= ATMEL_US_USCLKS_MCK | ATMEL_US_CLKO;
+ /* set max iterations */
+ mode |= ATMEL_US_MAX_ITER(3);
+ if ((port->iso7816.flags & SER_ISO7816_T_PARAM)
+ == SER_ISO7816_T(0))
+ mode |= ATMEL_US_USMODE_ISO7816_T0;
+ else
+ mode |= ATMEL_US_USMODE_ISO7816_T1;
} else if (termios->c_cflag & CRTSCTS) {
/* RS232 with hardware handshake (RTS/CTS) */
if (atmel_use_fifo(port) &&
@@ -2175,7 +2338,8 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
}
quot = cd | fp << ATMEL_US_FP_OFFSET;
- atmel_uart_writel(port, ATMEL_US_BRGR, quot);
+ if (!(port->iso7816.flags & SER_ISO7816_ENABLED))
+ atmel_uart_writel(port, ATMEL_US_BRGR, quot);
atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN | ATMEL_US_RXEN);
atmel_port->tx_stopped = false;
@@ -2222,8 +2386,8 @@ static const char *atmel_type(struct uart_port *port)
*/
static void atmel_release_port(struct uart_port *port)
{
- struct platform_device *pdev = to_platform_device(port->dev);
- int size = pdev->resource[0].end - pdev->resource[0].start + 1;
+ struct platform_device *mpdev = to_platform_device(port->dev->parent);
+ int size = resource_size(mpdev->resource);
release_mem_region(port->mapbase, size);
@@ -2238,8 +2402,8 @@ static void atmel_release_port(struct uart_port *port)
*/
static int atmel_request_port(struct uart_port *port)
{
- struct platform_device *pdev = to_platform_device(port->dev);
- int size = pdev->resource[0].end - pdev->resource[0].start + 1;
+ struct platform_device *mpdev = to_platform_device(port->dev->parent);
+ int size = resource_size(mpdev->resource);
if (!request_mem_region(port->mapbase, size, "atmel_serial"))
return -EBUSY;
@@ -2341,27 +2505,29 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
{
int ret;
struct uart_port *port = &atmel_port->uart;
+ struct platform_device *mpdev = to_platform_device(pdev->dev.parent);
atmel_init_property(atmel_port, pdev);
atmel_set_ops(port);
- uart_get_rs485_mode(&pdev->dev, &port->rs485);
+ uart_get_rs485_mode(&mpdev->dev, &port->rs485);
port->iotype = UPIO_MEM;
port->flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP;
port->ops = &atmel_pops;
port->fifosize = 1;
port->dev = &pdev->dev;
- port->mapbase = pdev->resource[0].start;
- port->irq = pdev->resource[1].start;
+ port->mapbase = mpdev->resource[0].start;
+ port->irq = mpdev->resource[1].start;
port->rs485_config = atmel_config_rs485;
- port->membase = NULL;
+ port->iso7816_config = atmel_config_iso7816;
+ port->membase = NULL;
memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring));
/* for console, the clock could already be configured */
if (!atmel_port->clk) {
- atmel_port->clk = clk_get(&pdev->dev, "usart");
+ atmel_port->clk = clk_get(&mpdev->dev, "usart");
if (IS_ERR(atmel_port->clk)) {
ret = PTR_ERR(atmel_port->clk);
atmel_port->clk = NULL;
@@ -2378,8 +2544,12 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
/* only enable clock when USART is in use */
}
- /* Use TXEMPTY for interrupt when rs485 else TXRDY or ENDTX|TXBUFE */
- if (port->rs485.flags & SER_RS485_ENABLED)
+ /*
+ * Use TXEMPTY for interrupt when rs485 or ISO7816 else TXRDY or
+ * ENDTX|TXBUFE
+ */
+ if (port->rs485.flags & SER_RS485_ENABLED ||
+ port->iso7816.flags & SER_ISO7816_ENABLED)
atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
else if (atmel_use_pdc_tx(port)) {
port->fifosize = PDC_BUFFER_SIZE;
@@ -2694,13 +2864,22 @@ static void atmel_serial_probe_fifos(struct atmel_uart_port *atmel_port,
static int atmel_serial_probe(struct platform_device *pdev)
{
struct atmel_uart_port *atmel_port;
- struct device_node *np = pdev->dev.of_node;
+ struct device_node *np = pdev->dev.parent->of_node;
void *data;
int ret = -ENODEV;
bool rs485_enabled;
BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1));
+ /*
+ * In device tree there is no node with "atmel,at91rm9200-usart-serial"
+ * as compatible string. This driver is probed by at91-usart mfd driver
+ * which is just a wrapper over the atmel_serial driver and
+ * spi-at91-usart driver. All attributes needed by this driver are
+ * found in of_node of parent.
+ */
+ pdev->dev.of_node = np;
+
ret = of_alias_get_id(np, "serial");
if (ret < 0)
/* port id not found in platform data nor device-tree aliases:
@@ -2836,6 +3015,7 @@ static int atmel_serial_remove(struct platform_device *pdev)
clk_put(atmel_port->clk);
atmel_port->clk = NULL;
+ pdev->dev.of_node = NULL;
return ret;
}
@@ -2846,7 +3026,7 @@ static struct platform_driver atmel_serial_driver = {
.suspend = atmel_serial_suspend,
.resume = atmel_serial_resume,
.driver = {
- .name = "atmel_usart",
+ .name = "atmel_usart_serial",
.of_match_table = of_match_ptr(atmel_serial_dt_ids),
},
};
diff --git a/drivers/tty/serial/atmel_serial.h b/drivers/tty/serial/atmel_serial.h
index ba3a2437cde4..d811d4f2d0c0 100644
--- a/drivers/tty/serial/atmel_serial.h
+++ b/drivers/tty/serial/atmel_serial.h
@@ -78,7 +78,8 @@
#define ATMEL_US_OVER BIT(19) /* Oversampling Mode */
#define ATMEL_US_INACK BIT(20) /* Inhibit Non Acknowledge */
#define ATMEL_US_DSNACK BIT(21) /* Disable Successive NACK */
-#define ATMEL_US_MAX_ITER GENMASK(26, 24) /* Max Iterations */
+#define ATMEL_US_MAX_ITER_MASK GENMASK(26, 24) /* Max Iterations */
+#define ATMEL_US_MAX_ITER(n) (((n) << 24) & ATMEL_US_MAX_ITER_MASK)
#define ATMEL_US_FILTER BIT(28) /* Infrared Receive Line Filter */
#define ATMEL_US_IER 0x08 /* Interrupt Enable Register */
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
index e5389591bb4f..b929c7ae3a27 100644
--- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
@@ -24,7 +24,7 @@
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/device.h>
-#include <linux/bootmem.h>
+#include <linux/memblock.h>
#include <linux/dma-mapping.h>
#include <linux/fs_uart_pd.h>
#include <linux/of_address.h>
@@ -1155,8 +1155,8 @@ static int cpm_uart_init_port(struct device_node *np,
if (!pinfo->clk) {
data = of_get_property(np, "fsl,cpm-brg", &len);
if (!data || len != 4) {
- printk(KERN_ERR "CPM UART %s has no/invalid "
- "fsl,cpm-brg property.\n", np->name);
+ printk(KERN_ERR "CPM UART %pOFn has no/invalid "
+ "fsl,cpm-brg property.\n", np);
return -EINVAL;
}
pinfo->brg = *data;
@@ -1164,8 +1164,8 @@ static int cpm_uart_init_port(struct device_node *np,
data = of_get_property(np, "fsl,cpm-command", &len);
if (!data || len != 4) {
- printk(KERN_ERR "CPM UART %s has no/invalid "
- "fsl,cpm-command property.\n", np->name);
+ printk(KERN_ERR "CPM UART %pOFn has no/invalid "
+ "fsl,cpm-command property.\n", np);
return -EINVAL;
}
pinfo->command = *data;
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c
index 4eba17f3d293..56fc527015cb 100644
--- a/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c
+++ b/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c
@@ -19,7 +19,7 @@
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/device.h>
-#include <linux/bootmem.h>
+#include <linux/memblock.h>
#include <linux/dma-mapping.h>
#include <asm/io.h>
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.c
index e3bff068dc3c..6a1cd03bfe39 100644
--- a/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.c
+++ b/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.c
@@ -19,7 +19,7 @@
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/device.h>
-#include <linux/bootmem.h>
+#include <linux/memblock.h>
#include <linux/dma-mapping.h>
#include <asm/io.h>
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index 3f8d1274fc85..00c220e4f43c 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -232,6 +232,8 @@
/* IMX lpuart has four extra unused regs located at the beginning */
#define IMX_REG_OFF 0x10
+static DEFINE_IDA(fsl_lpuart_ida);
+
struct lpuart_port {
struct uart_port port;
struct clk *clk;
@@ -2143,8 +2145,11 @@ static int lpuart_probe(struct platform_device *pdev)
ret = of_alias_get_id(np, "serial");
if (ret < 0) {
- dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
- return ret;
+ ret = ida_simple_get(&fsl_lpuart_ida, 0, UART_NR, GFP_KERNEL);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "port line is full, add device failed\n");
+ return ret;
+ }
}
if (ret >= ARRAY_SIZE(lpuart_ports)) {
dev_err(&pdev->dev, "serial%d out of range\n", ret);
@@ -2246,6 +2251,8 @@ static int lpuart_remove(struct platform_device *pdev)
uart_remove_one_port(&lpuart_reg, &sport->port);
+ ida_simple_remove(&fsl_lpuart_ida, sport->port.line);
+
clk_disable_unprepare(sport->clk);
if (sport->dma_tx_chan)
@@ -2384,6 +2391,7 @@ static int __init lpuart_serial_init(void)
static void __exit lpuart_serial_exit(void)
{
+ ida_destroy(&fsl_lpuart_ida);
platform_driver_unregister(&lpuart_driver);
uart_unregister_driver(&lpuart_reg);
}
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 0f67197a3783..d4e051b578f6 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -24,6 +24,7 @@
#include <linux/serial.h>
#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/rational.h>
#include <linux/slab.h>
#include <linux/of.h>
@@ -706,27 +707,25 @@ static irqreturn_t imx_uart_rtsint(int irq, void *dev_id)
{
struct imx_port *sport = dev_id;
u32 usr1;
- unsigned long flags;
- spin_lock_irqsave(&sport->port.lock, flags);
+ spin_lock(&sport->port.lock);
imx_uart_writel(sport, USR1_RTSD, USR1);
usr1 = imx_uart_readl(sport, USR1) & USR1_RTSS;
uart_handle_cts_change(&sport->port, !!usr1);
wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
- spin_unlock_irqrestore(&sport->port.lock, flags);
+ spin_unlock(&sport->port.lock);
return IRQ_HANDLED;
}
static irqreturn_t imx_uart_txint(int irq, void *dev_id)
{
struct imx_port *sport = dev_id;
- unsigned long flags;
- spin_lock_irqsave(&sport->port.lock, flags);
+ spin_lock(&sport->port.lock);
imx_uart_transmit_buffer(sport);
- spin_unlock_irqrestore(&sport->port.lock, flags);
+ spin_unlock(&sport->port.lock);
return IRQ_HANDLED;
}
@@ -735,9 +734,8 @@ static irqreturn_t imx_uart_rxint(int irq, void *dev_id)
struct imx_port *sport = dev_id;
unsigned int rx, flg, ignored = 0;
struct tty_port *port = &sport->port.state->port;
- unsigned long flags;
- spin_lock_irqsave(&sport->port.lock, flags);
+ spin_lock(&sport->port.lock);
while (imx_uart_readl(sport, USR2) & USR2_RDR) {
u32 usr2;
@@ -797,7 +795,7 @@ static irqreturn_t imx_uart_rxint(int irq, void *dev_id)
}
out:
- spin_unlock_irqrestore(&sport->port.lock, flags);
+ spin_unlock(&sport->port.lock);
tty_flip_buffer_push(port);
return IRQ_HANDLED;
}
@@ -903,13 +901,11 @@ static irqreturn_t imx_uart_int(int irq, void *dev_id)
}
if (usr1 & USR1_DTRD) {
- unsigned long flags;
-
imx_uart_writel(sport, USR1_DTRD, USR1);
- spin_lock_irqsave(&sport->port.lock, flags);
+ spin_lock(&sport->port.lock);
imx_uart_mctrl_check(sport);
- spin_unlock_irqrestore(&sport->port.lock, flags);
+ spin_unlock(&sport->port.lock);
ret = IRQ_HANDLED;
}
@@ -2384,8 +2380,13 @@ static int imx_uart_remove(struct platform_device *pdev)
static void imx_uart_restore_context(struct imx_port *sport)
{
- if (!sport->context_saved)
+ unsigned long flags;
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+ if (!sport->context_saved) {
+ spin_unlock_irqrestore(&sport->port.lock, flags);
return;
+ }
imx_uart_writel(sport, sport->saved_reg[4], UFCR);
imx_uart_writel(sport, sport->saved_reg[5], UESC);
@@ -2398,11 +2399,15 @@ static void imx_uart_restore_context(struct imx_port *sport)
imx_uart_writel(sport, sport->saved_reg[2], UCR3);
imx_uart_writel(sport, sport->saved_reg[3], UCR4);
sport->context_saved = false;
+ spin_unlock_irqrestore(&sport->port.lock, flags);
}
static void imx_uart_save_context(struct imx_port *sport)
{
+ unsigned long flags;
+
/* Save necessary regs */
+ spin_lock_irqsave(&sport->port.lock, flags);
sport->saved_reg[0] = imx_uart_readl(sport, UCR1);
sport->saved_reg[1] = imx_uart_readl(sport, UCR2);
sport->saved_reg[2] = imx_uart_readl(sport, UCR3);
@@ -2414,6 +2419,7 @@ static void imx_uart_save_context(struct imx_port *sport)
sport->saved_reg[8] = imx_uart_readl(sport, UBMR);
sport->saved_reg[9] = imx_uart_readl(sport, IMX21_UTS);
sport->context_saved = true;
+ spin_unlock_irqrestore(&sport->port.lock, flags);
}
static void imx_uart_enable_wakeup(struct imx_port *sport, bool on)
@@ -2447,6 +2453,8 @@ static int imx_uart_suspend_noirq(struct device *dev)
clk_disable(sport->clk_ipg);
+ pinctrl_pm_select_sleep_state(dev);
+
return 0;
}
@@ -2455,6 +2463,8 @@ static int imx_uart_resume_noirq(struct device *dev)
struct imx_port *sport = dev_get_drvdata(dev);
int ret;
+ pinctrl_pm_select_default_state(dev);
+
ret = clk_enable(sport->clk_ipg);
if (ret)
return ret;
diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c
index b4ba2b1dab76..baeeeaec3f03 100644
--- a/drivers/tty/serial/kgdboc.c
+++ b/drivers/tty/serial/kgdboc.c
@@ -8,6 +8,9 @@
*
* 2007-2008 (c) Jason Wessel - Wind River Systems, Inc.
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/ctype.h>
#include <linux/kgdb.h>
@@ -128,19 +131,6 @@ static void kgdboc_unregister_kbd(void)
#define kgdboc_restore_input()
#endif /* ! CONFIG_KDB_KEYBOARD */
-static int kgdboc_option_setup(char *opt)
-{
- if (strlen(opt) >= MAX_CONFIG_LEN) {
- printk(KERN_ERR "kgdboc: config string too long\n");
- return -ENOSPC;
- }
- strcpy(config, opt);
-
- return 0;
-}
-
-__setup("kgdboc=", kgdboc_option_setup);
-
static void cleanup_kgdboc(void)
{
if (kgdb_unregister_nmi_console())
@@ -154,15 +144,13 @@ static int configure_kgdboc(void)
{
struct tty_driver *p;
int tty_line = 0;
- int err;
+ int err = -ENODEV;
char *cptr = config;
struct console *cons;
- err = kgdboc_option_setup(config);
- if (err || !strlen(config) || isspace(config[0]))
+ if (!strlen(config) || isspace(config[0]))
goto noconfig;
- err = -ENODEV;
kgdboc_io_ops.is_console = 0;
kgdb_tty_driver = NULL;
@@ -248,7 +236,7 @@ static int param_set_kgdboc_var(const char *kmessage,
int len = strlen(kmessage);
if (len >= MAX_CONFIG_LEN) {
- printk(KERN_ERR "kgdboc: config string too long\n");
+ pr_err("config string too long\n");
return -ENOSPC;
}
@@ -259,8 +247,7 @@ static int param_set_kgdboc_var(const char *kmessage,
}
if (kgdb_connected) {
- printk(KERN_ERR
- "kgdboc: Cannot reconfigure while KGDB is connected.\n");
+ pr_err("Cannot reconfigure while KGDB is connected.\n");
return -EBUSY;
}
@@ -311,6 +298,25 @@ static struct kgdb_io kgdboc_io_ops = {
};
#ifdef CONFIG_KGDB_SERIAL_CONSOLE
+static int kgdboc_option_setup(char *opt)
+{
+ if (!opt) {
+ pr_err("config string not provided\n");
+ return -EINVAL;
+ }
+
+ if (strlen(opt) >= MAX_CONFIG_LEN) {
+ pr_err("config string too long\n");
+ return -ENOSPC;
+ }
+ strcpy(config, opt);
+
+ return 0;
+}
+
+__setup("kgdboc=", kgdboc_option_setup);
+
+
/* This is only available if kgdboc is a built in for early debugging */
static int __init kgdboc_early_init(char *opt)
{
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index 76aa289652f7..27235a526cce 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -1634,8 +1634,9 @@ static int mxs_auart_request_gpio_irq(struct mxs_auart_port *s)
/*
* If something went wrong, rollback.
+ * Be careful: i may be unsigned.
*/
- while (err && (--i >= 0))
+ while (err && (i-- > 0))
if (irq[i] >= 0)
free_irq(irq[i], s);
diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c
index 3d21790d961e..a9d40988e1c8 100644
--- a/drivers/tty/serial/pmac_zilog.c
+++ b/drivers/tty/serial/pmac_zilog.c
@@ -219,7 +219,7 @@ static void pmz_interrupt_control(struct uart_pmac_port *uap, int enable)
static bool pmz_receive_chars(struct uart_pmac_port *uap)
{
struct tty_port *port;
- unsigned char ch, r1, drop, error, flag;
+ unsigned char ch, r1, drop, flag;
int loops = 0;
/* Sanity check, make sure the old bug is no longer happening */
@@ -231,7 +231,6 @@ static bool pmz_receive_chars(struct uart_pmac_port *uap)
port = &uap->port.state->port;
while (1) {
- error = 0;
drop = 0;
r1 = read_zsreg(uap, R1);
@@ -273,7 +272,6 @@ static bool pmz_receive_chars(struct uart_pmac_port *uap)
uap->port.icount.rx++;
if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR | BRK_ABRT)) {
- error = 1;
if (r1 & BRK_ABRT) {
pmz_debug("pmz: got break !\n");
r1 &= ~(PAR_ERR | CRC_ERR);
@@ -1566,9 +1564,9 @@ static int pmz_attach(struct macio_dev *mdev, const struct of_device_id *match)
* to work around bugs in ancient Apple device-trees
*/
if (macio_request_resources(uap->dev, "pmac_zilog"))
- printk(KERN_WARNING "%s: Failed to request resource"
+ printk(KERN_WARNING "%pOFn: Failed to request resource"
", port still active\n",
- uap->node->name);
+ uap->node);
else
uap->flags |= PMACZILOG_FLAG_RSRC_REQUESTED;
diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c
index 29ec34387246..d3b5261ee80a 100644
--- a/drivers/tty/serial/qcom_geni_serial.c
+++ b/drivers/tty/serial/qcom_geni_serial.c
@@ -851,6 +851,23 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport)
{
struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
unsigned int rxstale = DEFAULT_BITS_PER_CHAR * STALE_TIMEOUT;
+ u32 proto;
+
+ if (uart_console(uport))
+ port->tx_bytes_pw = 1;
+ else
+ port->tx_bytes_pw = 4;
+ port->rx_bytes_pw = RX_BYTES_PW;
+
+ proto = geni_se_read_proto(&port->se);
+ if (proto != GENI_SE_UART) {
+ dev_err(uport->dev, "Invalid FW loaded, proto: %d\n", proto);
+ return -ENXIO;
+ }
+
+ qcom_geni_serial_stop_rx(uport);
+
+ get_tx_fifo_size(port);
set_rfr_wm(port);
writel_relaxed(rxstale, uport->membase + SE_UART_RX_STALE_CNT);
@@ -868,36 +885,25 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport)
geni_se_init(&port->se, port->rx_wm, port->rx_rfr);
geni_se_select_mode(&port->se, port->xfer_mode);
if (!uart_console(uport)) {
- port->rx_fifo = devm_kzalloc(uport->dev,
- port->rx_fifo_depth * sizeof(u32), GFP_KERNEL);
+ port->rx_fifo = devm_kcalloc(uport->dev,
+ port->rx_fifo_depth, sizeof(u32), GFP_KERNEL);
if (!port->rx_fifo)
return -ENOMEM;
}
port->setup = true;
+
return 0;
}
static int qcom_geni_serial_startup(struct uart_port *uport)
{
int ret;
- u32 proto;
struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
scnprintf(port->name, sizeof(port->name),
"qcom_serial_%s%d",
(uart_console(uport) ? "console" : "uart"), uport->line);
- if (!uart_console(uport)) {
- port->tx_bytes_pw = 4;
- port->rx_bytes_pw = RX_BYTES_PW;
- }
- proto = geni_se_read_proto(&port->se);
- if (proto != GENI_SE_UART) {
- dev_err(uport->dev, "Invalid FW loaded, proto: %d\n", proto);
- return -ENXIO;
- }
-
- get_tx_fifo_size(port);
if (!port->setup) {
ret = qcom_geni_serial_port_setup(uport);
if (ret)
@@ -1056,6 +1062,7 @@ static int __init qcom_geni_console_setup(struct console *co, char *options)
int bits = 8;
int parity = 'n';
int flow = 'n';
+ int ret;
if (co->index >= GENI_UART_CONS_PORTS || co->index < 0)
return -ENXIO;
@@ -1071,21 +1078,10 @@ static int __init qcom_geni_console_setup(struct console *co, char *options)
if (unlikely(!uport->membase))
return -ENXIO;
- if (geni_se_resources_on(&port->se)) {
- dev_err(port->se.dev, "Error turning on resources\n");
- return -ENXIO;
- }
-
- if (unlikely(geni_se_read_proto(&port->se) != GENI_SE_UART)) {
- geni_se_resources_off(&port->se);
- return -ENXIO;
- }
-
if (!port->setup) {
- port->tx_bytes_pw = 1;
- port->rx_bytes_pw = RX_BYTES_PW;
- qcom_geni_serial_stop_rx(uport);
- qcom_geni_serial_port_setup(uport);
+ ret = qcom_geni_serial_port_setup(uport);
+ if (ret)
+ return ret;
}
if (options)
@@ -1203,11 +1199,12 @@ static void qcom_geni_serial_pm(struct uart_port *uport,
{
struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
+ /* If we've never been called, treat it as off */
+ if (old_state == UART_PM_STATE_UNDEFINED)
+ old_state = UART_PM_STATE_OFF;
+
if (new_state == UART_PM_STATE_ON && old_state == UART_PM_STATE_OFF)
geni_se_resources_on(&port->se);
- else if (!uart_console(uport) && (new_state == UART_PM_STATE_ON &&
- old_state == UART_PM_STATE_UNDEFINED))
- geni_se_resources_on(&port->se);
else if (new_state == UART_PM_STATE_OFF &&
old_state == UART_PM_STATE_ON)
geni_se_resources_off(&port->se);
@@ -1263,14 +1260,12 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
if (of_device_is_compatible(pdev->dev.of_node, "qcom,geni-debug-uart"))
console = true;
- if (pdev->dev.of_node) {
- if (console) {
- drv = &qcom_geni_console_driver;
- 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");
- }
+ if (console) {
+ drv = &qcom_geni_console_driver;
+ 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");
}
port = get_port_from_line(line, console);
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index 2f8fa184aafa..da1bd4bba8a9 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -1941,7 +1941,11 @@ static int s3c24xx_serial_resume(struct device *dev)
if (port) {
clk_prepare_enable(ourport->clk);
+ if (!IS_ERR(ourport->baudclk))
+ clk_prepare_enable(ourport->baudclk);
s3c24xx_serial_resetport(port, s3c24xx_port_to_cfg(port));
+ if (!IS_ERR(ourport->baudclk))
+ clk_disable_unprepare(ourport->baudclk);
clk_disable_unprepare(ourport->clk);
uart_resume_port(&s3c24xx_uart_drv, port);
@@ -1964,7 +1968,11 @@ static int s3c24xx_serial_resume_noirq(struct device *dev)
if (rx_enabled(port))
uintm &= ~S3C64XX_UINTM_RXD_MSK;
clk_prepare_enable(ourport->clk);
+ if (!IS_ERR(ourport->baudclk))
+ clk_prepare_enable(ourport->baudclk);
wr_regl(port, S3C64XX_UINTM, uintm);
+ if (!IS_ERR(ourport->baudclk))
+ clk_disable_unprepare(ourport->baudclk);
clk_disable_unprepare(ourport->clk);
}
}
diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
index 243c96025053..268098681856 100644
--- a/drivers/tty/serial/sc16is7xx.c
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -328,6 +328,7 @@ struct sc16is7xx_port {
struct kthread_worker kworker;
struct task_struct *kworker_task;
struct kthread_work irq_work;
+ struct mutex efr_lock;
struct sc16is7xx_one p[0];
};
@@ -499,6 +500,21 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud)
div /= 4;
}
+ /* In an amazing feat of design, the Enhanced Features Register shares
+ * the address of the Interrupt Identification Register, and is
+ * switched in by writing a magic value (0xbf) to the Line Control
+ * Register. Any interrupt firing during this time will see the EFR
+ * where it expects the IIR to be, leading to "Unexpected interrupt"
+ * messages.
+ *
+ * Prevent this possibility by claiming a mutex while accessing the
+ * EFR, and claiming the same mutex from within the interrupt handler.
+ * This is similar to disabling the interrupt, but that doesn't work
+ * because the bulk of the interrupt processing is run as a workqueue
+ * job in thread context.
+ */
+ mutex_lock(&s->efr_lock);
+
lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG);
/* Open the LCR divisors for configuration */
@@ -514,6 +530,8 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud)
/* Put LCR back to the normal mode */
sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr);
+ mutex_unlock(&s->efr_lock);
+
sc16is7xx_port_update(port, SC16IS7XX_MCR_REG,
SC16IS7XX_MCR_CLKSEL_BIT,
prescaler);
@@ -657,7 +675,7 @@ static void sc16is7xx_handle_tx(struct uart_port *port)
uart_write_wakeup(port);
}
-static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
+static bool sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
{
struct uart_port *port = &s->p[portno].port;
@@ -666,7 +684,7 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
iir = sc16is7xx_port_read(port, SC16IS7XX_IIR_REG);
if (iir & SC16IS7XX_IIR_NO_INT_BIT)
- break;
+ return false;
iir &= SC16IS7XX_IIR_ID_MASK;
@@ -688,16 +706,27 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
port->line, iir);
break;
}
- } while (1);
+ } while (0);
+ return true;
}
static void sc16is7xx_ist(struct kthread_work *ws)
{
struct sc16is7xx_port *s = to_sc16is7xx_port(ws, irq_work);
- int i;
- for (i = 0; i < s->devtype->nr_uart; ++i)
- sc16is7xx_port_irq(s, i);
+ mutex_lock(&s->efr_lock);
+
+ while (1) {
+ bool keep_polling = false;
+ int i;
+
+ for (i = 0; i < s->devtype->nr_uart; ++i)
+ keep_polling |= sc16is7xx_port_irq(s, i);
+ if (!keep_polling)
+ break;
+ }
+
+ mutex_unlock(&s->efr_lock);
}
static irqreturn_t sc16is7xx_irq(int irq, void *dev_id)
@@ -892,6 +921,9 @@ static void sc16is7xx_set_termios(struct uart_port *port,
if (!(termios->c_cflag & CREAD))
port->ignore_status_mask |= SC16IS7XX_LSR_BRK_ERROR_MASK;
+ /* As above, claim the mutex while accessing the EFR. */
+ mutex_lock(&s->efr_lock);
+
sc16is7xx_port_write(port, SC16IS7XX_LCR_REG,
SC16IS7XX_LCR_CONF_MODE_B);
@@ -913,6 +945,8 @@ static void sc16is7xx_set_termios(struct uart_port *port,
/* Update LCR register */
sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr);
+ mutex_unlock(&s->efr_lock);
+
/* Get baud rate generator configuration */
baud = uart_get_baud_rate(port, termios, old,
port->uartclk / 16 / 4 / 0xffff,
@@ -1178,6 +1212,7 @@ static int sc16is7xx_probe(struct device *dev,
s->regmap = regmap;
s->devtype = devtype;
dev_set_drvdata(dev, s);
+ mutex_init(&s->efr_lock);
kthread_init_worker(&s->kworker);
kthread_init_work(&s->irq_work, sc16is7xx_ist);
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 80bb56facfb6..c439a5a1e6c0 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -778,17 +778,13 @@ out:
return ret;
}
-static int uart_get_info_user(struct tty_port *port,
- struct serial_struct __user *retinfo)
+static int uart_get_info_user(struct tty_struct *tty,
+ struct serial_struct *ss)
{
- struct serial_struct tmp;
-
- if (uart_get_info(port, &tmp) < 0)
- return -EIO;
+ struct uart_state *state = tty->driver_data;
+ struct tty_port *port = &state->port;
- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return -EFAULT;
- return 0;
+ return uart_get_info(port, ss) < 0 ? -EIO : 0;
}
static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
@@ -990,16 +986,13 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
return retval;
}
-static int uart_set_info_user(struct tty_struct *tty, struct uart_state *state,
- struct serial_struct __user *newinfo)
+static int uart_set_info_user(struct tty_struct *tty, struct serial_struct *ss)
{
- struct serial_struct new_serial;
+ struct uart_state *state = tty->driver_data;
struct tty_port *port = &state->port;
int retval;
- if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
- return -EFAULT;
-
+ down_write(&tty->termios_rwsem);
/*
* This semaphore protects port->count. It is also
* very useful to prevent opens. Also, take the
@@ -1008,8 +1001,9 @@ static int uart_set_info_user(struct tty_struct *tty, struct uart_state *state,
* under us.
*/
mutex_lock(&port->mutex);
- retval = uart_set_info(tty, port, state, &new_serial);
+ retval = uart_set_info(tty, port, state, ss);
mutex_unlock(&port->mutex);
+ up_write(&tty->termios_rwsem);
return retval;
}
@@ -1308,6 +1302,58 @@ static int uart_set_rs485_config(struct uart_port *port,
return 0;
}
+static int uart_get_iso7816_config(struct uart_port *port,
+ struct serial_iso7816 __user *iso7816)
+{
+ unsigned long flags;
+ struct serial_iso7816 aux;
+
+ if (!port->iso7816_config)
+ return -ENOIOCTLCMD;
+
+ spin_lock_irqsave(&port->lock, flags);
+ aux = port->iso7816;
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ if (copy_to_user(iso7816, &aux, sizeof(aux)))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int uart_set_iso7816_config(struct uart_port *port,
+ struct serial_iso7816 __user *iso7816_user)
+{
+ struct serial_iso7816 iso7816;
+ int i, ret;
+ unsigned long flags;
+
+ if (!port->iso7816_config)
+ return -ENOIOCTLCMD;
+
+ if (copy_from_user(&iso7816, iso7816_user, sizeof(*iso7816_user)))
+ return -EFAULT;
+
+ /*
+ * There are 5 words reserved for future use. Check that userspace
+ * doesn't put stuff in there to prevent breakages in the future.
+ */
+ for (i = 0; i < 5; i++)
+ if (iso7816.reserved[i])
+ return -EINVAL;
+
+ spin_lock_irqsave(&port->lock, flags);
+ ret = port->iso7816_config(port, &iso7816);
+ spin_unlock_irqrestore(&port->lock, flags);
+ if (ret)
+ return ret;
+
+ if (copy_to_user(iso7816_user, &port->iso7816, sizeof(port->iso7816)))
+ return -EFAULT;
+
+ return 0;
+}
+
/*
* Called via sys_ioctl. We can use spin_lock_irq() here.
*/
@@ -1325,26 +1371,11 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
* These ioctls don't rely on the hardware to be present.
*/
switch (cmd) {
- case TIOCGSERIAL:
- ret = uart_get_info_user(port, uarg);
- break;
-
- case TIOCSSERIAL:
- down_write(&tty->termios_rwsem);
- ret = uart_set_info_user(tty, state, uarg);
- up_write(&tty->termios_rwsem);
- break;
-
case TIOCSERCONFIG:
down_write(&tty->termios_rwsem);
ret = uart_do_autoconfig(tty, state);
up_write(&tty->termios_rwsem);
break;
-
- case TIOCSERGWILD: /* obsolete */
- case TIOCSERSWILD: /* obsolete */
- ret = 0;
- break;
}
if (ret != -ENOIOCTLCMD)
@@ -1392,6 +1423,14 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
case TIOCSRS485:
ret = uart_set_rs485_config(uport, uarg);
break;
+
+ case TIOCSISO7816:
+ ret = uart_set_iso7816_config(state->uart_port, uarg);
+ break;
+
+ case TIOCGISO7816:
+ ret = uart_get_iso7816_config(state->uart_port, uarg);
+ break;
default:
if (uport->ops->ioctl)
ret = uport->ops->ioctl(uport, cmd, arg);
@@ -2413,6 +2452,8 @@ static const struct tty_operations uart_ops = {
#endif
.tiocmget = uart_tiocmget,
.tiocmset = uart_tiocmset,
+ .set_serial = uart_set_info_user,
+ .get_serial = uart_get_info_user,
.get_icount = uart_get_icount,
#ifdef CONFIG_CONSOLE_POLL
.poll_init = uart_poll_init,
diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c
index 1c06325beaca..39ed56214cd3 100644
--- a/drivers/tty/serial/serial_mctrl_gpio.c
+++ b/drivers/tty/serial/serial_mctrl_gpio.c
@@ -40,7 +40,7 @@ void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
{
enum mctrl_gpio_idx i;
struct gpio_desc *desc_array[UART_GPIO_MAX];
- int value_array[UART_GPIO_MAX];
+ DECLARE_BITMAP(values, UART_GPIO_MAX);
unsigned int count = 0;
if (gpios == NULL)
@@ -49,10 +49,11 @@ void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
for (i = 0; i < UART_GPIO_MAX; i++)
if (gpios->gpio[i] && mctrl_gpios_desc[i].dir_out) {
desc_array[count] = gpios->gpio[i];
- value_array[count] = !!(mctrl & mctrl_gpios_desc[i].mctrl);
+ __assign_bit(count, values,
+ mctrl & mctrl_gpios_desc[i].mctrl);
count++;
}
- gpiod_set_array_value(count, desc_array, value_array);
+ gpiod_set_array_value(count, desc_array, NULL, values);
}
EXPORT_SYMBOL_GPL(mctrl_gpio_set);
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index ac4424bf6b13..cc56cb3b3eca 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -292,6 +292,33 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
},
/*
+ * The "SCIFA" that is in RZ/T and RZ/A2.
+ * 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.
+ */
+ [SCIx_RZ_SCIFA_REGTYPE] = {
+ .regs = {
+ [SCSMR] = { 0x00, 16 },
+ [SCBRR] = { 0x02, 8 },
+ [SCSCR] = { 0x04, 16 },
+ [SCxTDR] = { 0x06, 8 },
+ [SCxSR] = { 0x08, 16 },
+ [SCxRDR] = { 0x0A, 8 },
+ [SCFCR] = { 0x0C, 16 },
+ [SCFDR] = { 0x0E, 16 },
+ [SCSPTR] = { 0x10, 16 },
+ [SCLSR] = { 0x12, 16 },
+ },
+ .fifosize = 16,
+ .overrun_reg = SCLSR,
+ .overrun_mask = SCLSR_ORER,
+ .sampling_rate_mask = SCI_SR(32),
+ .error_mask = SCIF_DEFAULT_ERROR_MASK,
+ .error_clear = SCIF_ERROR_CLEAR,
+ },
+
+ /*
* Common SH-3 SCIF definitions.
*/
[SCIx_SH3_SCIF_REGTYPE] = {
@@ -319,15 +346,15 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
[SCIx_SH4_SCIF_REGTYPE] = {
.regs = {
[SCSMR] = { 0x00, 16 },
- [SCBRR] = { 0x02, 8 },
- [SCSCR] = { 0x04, 16 },
- [SCxTDR] = { 0x06, 8 },
- [SCxSR] = { 0x08, 16 },
- [SCxRDR] = { 0x0a, 8 },
- [SCFCR] = { 0x0c, 16 },
- [SCFDR] = { 0x0e, 16 },
- [SCSPTR] = { 0x10, 16 },
- [SCLSR] = { 0x12, 16 },
+ [SCBRR] = { 0x04, 8 },
+ [SCSCR] = { 0x08, 16 },
+ [SCxTDR] = { 0x0c, 8 },
+ [SCxSR] = { 0x10, 16 },
+ [SCxRDR] = { 0x14, 8 },
+ [SCFCR] = { 0x18, 16 },
+ [SCFDR] = { 0x1c, 16 },
+ [SCSPTR] = { 0x20, 16 },
+ [SCLSR] = { 0x24, 16 },
},
.fifosize = 16,
.overrun_reg = SCLSR,
@@ -1489,7 +1516,7 @@ static struct dma_chan *sci_request_dma_chan(struct uart_port *port,
chan = dma_request_slave_channel(port->dev,
dir == DMA_MEM_TO_DEV ? "tx" : "rx");
if (!chan) {
- dev_warn(port->dev, "dma_request_slave_channel failed\n");
+ dev_dbg(port->dev, "dma_request_slave_channel failed\n");
return NULL;
}
@@ -1587,10 +1614,10 @@ static void sci_request_dma(struct uart_port *port)
hrtimer_init(&s->rx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
s->rx_timer.function = rx_timer_fn;
+ s->chan_rx_saved = s->chan_rx = chan;
+
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
sci_submit_rx(s);
-
- s->chan_rx_saved = s->chan_rx = chan;
}
}
@@ -2810,7 +2837,7 @@ static int sci_init_single(struct platform_device *dev,
{
struct uart_port *port = &sci_port->port;
const struct resource *res;
- unsigned int i, regtype;
+ unsigned int i;
int ret;
sci_port->cfg = p;
@@ -2847,7 +2874,6 @@ static int sci_init_single(struct platform_device *dev,
if (unlikely(sci_port->params == NULL))
return -EINVAL;
- regtype = sci_port->params - sci_port_params;
switch (p->type) {
case PORT_SCIFB:
sci_port->rx_trigger = 48;
@@ -2902,10 +2928,6 @@ static int sci_init_single(struct platform_device *dev,
port->regshift = 1;
}
- if (regtype == SCIx_SH4_SCIF_REGTYPE)
- if (sci_port->reg_size >= 0x20)
- port->regshift = 1;
-
/*
* The UART port needs an IRQ value, so we peg this to the RX IRQ
* for the multi-IRQ ports, which is where we are primarily
@@ -3080,6 +3102,7 @@ static struct uart_driver sci_uart_driver = {
static int sci_remove(struct platform_device *dev)
{
struct sci_port *port = platform_get_drvdata(dev);
+ unsigned int type = port->port.type; /* uart_remove_... clears it */
sci_ports_in_use &= ~BIT(port->port.line);
uart_remove_one_port(&sci_uart_driver, &port->port);
@@ -3090,8 +3113,7 @@ static int sci_remove(struct platform_device *dev)
sysfs_remove_file(&dev->dev.kobj,
&dev_attr_rx_fifo_trigger.attr);
}
- if (port->port.type == PORT_SCIFA || port->port.type == PORT_SCIFB ||
- port->port.type == PORT_HSCIF) {
+ if (type == PORT_SCIFA || type == PORT_SCIFB || type == PORT_HSCIF) {
sysfs_remove_file(&dev->dev.kobj,
&dev_attr_rx_fifo_timeout.attr);
}
@@ -3110,6 +3132,10 @@ static const struct of_device_id of_sci_match[] = {
.compatible = "renesas,scif-r7s72100",
.data = SCI_OF_DATA(PORT_SCIF, SCIx_SH2_SCIF_FIFODATA_REGTYPE),
},
+ {
+ .compatible = "renesas,scif-r7s9210",
+ .data = SCI_OF_DATA(PORT_SCIF, SCIx_RZ_SCIFA_REGTYPE),
+ },
/* Family-specific types */
{
.compatible = "renesas,rcar-gen1-scif",
@@ -3388,6 +3414,12 @@ static int __init scif_early_console_setup(struct earlycon_device *device,
{
return early_console_setup(device, PORT_SCIF);
}
+static int __init rzscifa_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ 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)
{
@@ -3406,6 +3438,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(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/sn_console.c b/drivers/tty/serial/sn_console.c
index 42b9aded4eb1..fe9170731c16 100644
--- a/drivers/tty/serial/sn_console.c
+++ b/drivers/tty/serial/sn_console.c
@@ -888,7 +888,7 @@ sn_sal_console_write(struct console *co, const char *s, unsigned count)
/* somebody really wants this output, might be an
* oops, kdb, panic, etc. make sure they get it. */
- if (spin_is_locked(&port->sc_port.lock)) {
+ if (!spin_trylock_irqsave(&port->sc_port.lock, flags)) {
int lhead = port->sc_port.state->xmit.head;
int ltail = port->sc_port.state->xmit.tail;
int counter, got_lock = 0;
@@ -905,13 +905,11 @@ sn_sal_console_write(struct console *co, const char *s, unsigned count)
*/
for (counter = 0; counter < 150; mdelay(125), counter++) {
- if (!spin_is_locked(&port->sc_port.lock)
- || stole_lock) {
- if (!stole_lock) {
- spin_lock_irqsave(&port->sc_port.lock,
- flags);
- got_lock = 1;
- }
+ if (stole_lock)
+ break;
+
+ if (spin_trylock_irqsave(&port->sc_port.lock, flags)) {
+ got_lock = 1;
break;
} else {
/* still locked */
@@ -938,7 +936,6 @@ sn_sal_console_write(struct console *co, const char *s, unsigned count)
puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count);
} else {
stole_lock = 0;
- spin_lock_irqsave(&port->sc_port.lock, flags);
sn_transmit_chars(port, 1);
spin_unlock_irqrestore(&port->sc_port.lock, flags);
diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c
index 828f1143859c..4287ca305b6b 100644
--- a/drivers/tty/serial/sprd_serial.c
+++ b/drivers/tty/serial/sprd_serial.c
@@ -45,6 +45,8 @@
/* data number in TX and RX fifo */
#define SPRD_STS1 0x000C
+#define SPRD_RX_FIFO_CNT_MASK GENMASK(7, 0)
+#define SPRD_TX_FIFO_CNT_MASK GENMASK(15, 8)
/* interrupt enable register and its BITs */
#define SPRD_IEN 0x0010
@@ -66,67 +68,62 @@
#define SPRD_LCR_DATA_LEN6 0x4
#define SPRD_LCR_DATA_LEN7 0x8
#define SPRD_LCR_DATA_LEN8 0xc
-#define SPRD_LCR_PARITY (BIT(0) | BIT(1))
+#define SPRD_LCR_PARITY (BIT(0) | BIT(1))
#define SPRD_LCR_PARITY_EN 0x2
#define SPRD_LCR_EVEN_PAR 0x0
#define SPRD_LCR_ODD_PAR 0x1
/* control register 1 */
-#define SPRD_CTL1 0x001C
+#define SPRD_CTL1 0x001C
#define RX_HW_FLOW_CTL_THLD BIT(6)
#define RX_HW_FLOW_CTL_EN BIT(7)
#define TX_HW_FLOW_CTL_EN BIT(8)
#define RX_TOUT_THLD_DEF 0x3E00
-#define RX_HFC_THLD_DEF 0x40
+#define RX_HFC_THLD_DEF 0x40
/* fifo threshold register */
#define SPRD_CTL2 0x0020
-#define THLD_TX_EMPTY 0x40
-#define THLD_RX_FULL 0x40
+#define THLD_TX_EMPTY 0x40
+#define THLD_TX_EMPTY_SHIFT 8
+#define THLD_RX_FULL 0x40
/* config baud rate register */
#define SPRD_CLKD0 0x0024
+#define SPRD_CLKD0_MASK GENMASK(15, 0)
#define SPRD_CLKD1 0x0028
+#define SPRD_CLKD1_MASK GENMASK(20, 16)
+#define SPRD_CLKD1_SHIFT 16
/* interrupt mask status register */
-#define SPRD_IMSR 0x002C
-#define SPRD_IMSR_RX_FIFO_FULL BIT(0)
+#define SPRD_IMSR 0x002C
+#define SPRD_IMSR_RX_FIFO_FULL BIT(0)
#define SPRD_IMSR_TX_FIFO_EMPTY BIT(1)
-#define SPRD_IMSR_BREAK_DETECT BIT(7)
-#define SPRD_IMSR_TIMEOUT BIT(13)
-
-struct reg_backup {
- u32 ien;
- u32 ctrl0;
- u32 ctrl1;
- u32 ctrl2;
- u32 clkd0;
- u32 clkd1;
- u32 dspwait;
-};
+#define SPRD_IMSR_BREAK_DETECT BIT(7)
+#define SPRD_IMSR_TIMEOUT BIT(13)
struct sprd_uart_port {
struct uart_port port;
- struct reg_backup reg_bak;
char name[16];
};
static struct sprd_uart_port *sprd_port[UART_NR_MAX];
static int sprd_ports_num;
-static inline unsigned int serial_in(struct uart_port *port, int offset)
+static inline unsigned int serial_in(struct uart_port *port,
+ unsigned int offset)
{
return readl_relaxed(port->membase + offset);
}
-static inline void serial_out(struct uart_port *port, int offset, int value)
+static inline void serial_out(struct uart_port *port, unsigned int offset,
+ int value)
{
writel_relaxed(value, port->membase + offset);
}
static unsigned int sprd_tx_empty(struct uart_port *port)
{
- if (serial_in(port, SPRD_STS1) & 0xff00)
+ if (serial_in(port, SPRD_STS1) & SPRD_TX_FIFO_CNT_MASK)
return 0;
else
return TIOCSER_TEMT;
@@ -224,14 +221,15 @@ static inline void sprd_rx(struct uart_port *port)
struct tty_port *tty = &port->state->port;
unsigned int ch, flag, lsr, max_count = SPRD_TIMEOUT;
- while ((serial_in(port, SPRD_STS1) & 0x00ff) && max_count--) {
+ while ((serial_in(port, SPRD_STS1) & SPRD_RX_FIFO_CNT_MASK) &&
+ max_count--) {
lsr = serial_in(port, SPRD_LSR);
ch = serial_in(port, SPRD_RXD);
flag = TTY_NORMAL;
port->icount.rx++;
if (lsr & (SPRD_LSR_BI | SPRD_LSR_PE |
- SPRD_LSR_FE | SPRD_LSR_OE))
+ SPRD_LSR_FE | SPRD_LSR_OE))
if (handle_lsr_errors(port, &lsr, &flag))
continue;
if (uart_handle_sysrq_char(port, ch))
@@ -294,8 +292,8 @@ static irqreturn_t sprd_handle_irq(int irq, void *dev_id)
if (ims & SPRD_IMSR_TIMEOUT)
serial_out(port, SPRD_ICLR, SPRD_ICLR_TIMEOUT);
- if (ims & (SPRD_IMSR_RX_FIFO_FULL |
- SPRD_IMSR_BREAK_DETECT | SPRD_IMSR_TIMEOUT))
+ if (ims & (SPRD_IMSR_RX_FIFO_FULL | SPRD_IMSR_BREAK_DETECT |
+ SPRD_IMSR_TIMEOUT))
sprd_rx(port);
if (ims & SPRD_IMSR_TX_FIFO_EMPTY)
@@ -314,16 +312,17 @@ static int sprd_startup(struct uart_port *port)
struct sprd_uart_port *sp;
unsigned long flags;
- serial_out(port, SPRD_CTL2, ((THLD_TX_EMPTY << 8) | THLD_RX_FULL));
+ serial_out(port, SPRD_CTL2,
+ THLD_TX_EMPTY << THLD_TX_EMPTY_SHIFT | THLD_RX_FULL);
/* clear rx fifo */
timeout = SPRD_TIMEOUT;
- while (timeout-- && serial_in(port, SPRD_STS1) & 0x00ff)
+ while (timeout-- && serial_in(port, SPRD_STS1) & SPRD_RX_FIFO_CNT_MASK)
serial_in(port, SPRD_RXD);
/* clear tx fifo */
timeout = SPRD_TIMEOUT;
- while (timeout-- && serial_in(port, SPRD_STS1) & 0xff00)
+ while (timeout-- && serial_in(port, SPRD_STS1) & SPRD_TX_FIFO_CNT_MASK)
cpu_relax();
/* clear interrupt */
@@ -334,7 +333,7 @@ static int sprd_startup(struct uart_port *port)
sp = container_of(port, struct sprd_uart_port, port);
snprintf(sp->name, sizeof(sp->name), "sprd_serial%d", port->line);
ret = devm_request_irq(port->dev, port->irq, sprd_handle_irq,
- IRQF_SHARED, sp->name, port);
+ IRQF_SHARED, sp->name, port);
if (ret) {
dev_err(port->dev, "fail to request serial irq %d, ret=%d\n",
port->irq, ret);
@@ -362,8 +361,8 @@ static void sprd_shutdown(struct uart_port *port)
}
static void sprd_set_termios(struct uart_port *port,
- struct ktermios *termios,
- struct ktermios *old)
+ struct ktermios *termios,
+ struct ktermios *old)
{
unsigned int baud, quot;
unsigned int lcr = 0, fc;
@@ -444,10 +443,11 @@ static void sprd_set_termios(struct uart_port *port,
}
/* clock divider bit0~bit15 */
- serial_out(port, SPRD_CLKD0, quot & 0xffff);
+ serial_out(port, SPRD_CLKD0, quot & SPRD_CLKD0_MASK);
/* clock divider bit16~bit20 */
- serial_out(port, SPRD_CLKD1, (quot & 0x1f0000) >> 16);
+ serial_out(port, SPRD_CLKD1,
+ (quot & SPRD_CLKD1_MASK) >> SPRD_CLKD1_SHIFT);
serial_out(port, SPRD_LCR, lcr);
fc |= RX_TOUT_THLD_DEF | RX_HFC_THLD_DEF;
serial_out(port, SPRD_CTL1, fc);
@@ -480,8 +480,7 @@ static void sprd_config_port(struct uart_port *port, int flags)
port->type = PORT_SPRD;
}
-static int sprd_verify_port(struct uart_port *port,
- struct serial_struct *ser)
+static int sprd_verify_port(struct uart_port *port, struct serial_struct *ser)
{
if (ser->type != PORT_SPRD)
return -EINVAL;
@@ -521,7 +520,7 @@ static void wait_for_xmitr(struct uart_port *port)
if (--tmout == 0)
break;
udelay(1);
- } while (status & 0xff00);
+ } while (status & SPRD_TX_FIFO_CNT_MASK);
}
static void sprd_console_putchar(struct uart_port *port, int ch)
@@ -531,7 +530,7 @@ static void sprd_console_putchar(struct uart_port *port, int ch)
}
static void sprd_console_write(struct console *co, const char *s,
- unsigned int count)
+ unsigned int count)
{
struct uart_port *port = &sprd_port[co->index]->port;
int locked = 1;
@@ -594,23 +593,21 @@ static void sprd_putc(struct uart_port *port, int c)
unsigned int timeout = SPRD_TIMEOUT;
while (timeout-- &&
- !(readl(port->membase + SPRD_LSR) & SPRD_LSR_TX_OVER))
+ !(readl(port->membase + SPRD_LSR) & SPRD_LSR_TX_OVER))
cpu_relax();
writeb(c, port->membase + SPRD_TXD);
}
-static void sprd_early_write(struct console *con, const char *s,
- unsigned n)
+static void sprd_early_write(struct console *con, const char *s, unsigned int n)
{
struct earlycon_device *dev = con->data;
uart_console_write(&dev->port, s, n, sprd_putc);
}
-static int __init sprd_early_console_setup(
- struct earlycon_device *device,
- const char *opt)
+static int __init sprd_early_console_setup(struct earlycon_device *device,
+ const char *opt)
{
if (!device->port.membase)
return -ENODEV;
@@ -692,8 +689,8 @@ static int sprd_probe(struct platform_device *pdev)
index = sprd_probe_dt_alias(index, &pdev->dev);
- sprd_port[index] = devm_kzalloc(&pdev->dev,
- sizeof(*sprd_port[index]), GFP_KERNEL);
+ sprd_port[index] = devm_kzalloc(&pdev->dev, sizeof(*sprd_port[index]),
+ GFP_KERNEL);
if (!sprd_port[index])
return -ENOMEM;
@@ -712,15 +709,12 @@ static int sprd_probe(struct platform_device *pdev)
up->uartclk = clk_get_rate(clk);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "not provide mem resource\n");
- return -ENODEV;
- }
- up->mapbase = res->start;
up->membase = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(up->membase))
return PTR_ERR(up->membase);
+ up->mapbase = res->start;
+
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "not provide irq resource: %d\n", irq);
diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c
index 98d3eadd2fd0..f0344adc86db 100644
--- a/drivers/tty/serial/uartlite.c
+++ b/drivers/tty/serial/uartlite.c
@@ -55,6 +55,11 @@
#define ULITE_CONTROL_RST_RX 0x02
#define ULITE_CONTROL_IE 0x10
+/* Static pointer to console port */
+#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
+static struct uart_port *console_port;
+#endif
+
struct uartlite_data {
const struct uartlite_reg_ops *reg_ops;
struct clk *clk;
@@ -472,7 +477,7 @@ static void ulite_console_putchar(struct uart_port *port, int ch)
static void ulite_console_write(struct console *co, const char *s,
unsigned int count)
{
- struct uart_port *port = &ulite_ports[co->index];
+ struct uart_port *port = console_port;
unsigned long flags;
unsigned int ier;
int locked = 1;
@@ -506,10 +511,8 @@ static int ulite_console_setup(struct console *co, char *options)
int parity = 'n';
int flow = 'n';
- if (co->index < 0 || co->index >= ULITE_NR_UARTS)
- return -EINVAL;
- port = &ulite_ports[co->index];
+ port = console_port;
/* Has the device been initialized yet? */
if (!port->mapbase) {
@@ -541,14 +544,6 @@ static struct console ulite_console = {
.data = &ulite_uart_driver,
};
-static int __init ulite_console_init(void)
-{
- register_console(&ulite_console);
- return 0;
-}
-
-console_initcall(ulite_console_init);
-
static void early_uartlite_putc(struct uart_port *port, int c)
{
/*
@@ -660,6 +655,17 @@ 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) {
@@ -669,6 +675,12 @@ 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;
}
@@ -776,13 +788,26 @@ static int ulite_probe(struct platform_device *pdev)
pdata->clk = NULL;
}
- ret = clk_prepare(pdata->clk);
+ ret = clk_prepare_enable(pdata->clk);
if (ret) {
dev_err(&pdev->dev, "Failed to prepare clock\n");
return ret;
}
- return ulite_assign(&pdev->dev, id, res->start, irq, pdata);
+ if (!ulite_uart_driver.state) {
+ dev_dbg(&pdev->dev, "uartlite: calling uart_register_driver()\n");
+ ret = uart_register_driver(&ulite_uart_driver);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to register driver\n");
+ return ret;
+ }
+ }
+
+ ret = ulite_assign(&pdev->dev, id, res->start, irq, pdata);
+
+ clk_disable(pdata->clk);
+
+ return ret;
}
static int ulite_remove(struct platform_device *pdev)
@@ -813,25 +838,9 @@ static struct platform_driver ulite_platform_driver = {
static int __init ulite_init(void)
{
- int ret;
-
- pr_debug("uartlite: calling uart_register_driver()\n");
- ret = uart_register_driver(&ulite_uart_driver);
- if (ret)
- goto err_uart;
pr_debug("uartlite: calling platform_driver_register()\n");
- ret = platform_driver_register(&ulite_platform_driver);
- if (ret)
- goto err_plat;
-
- return 0;
-
-err_plat:
- uart_unregister_driver(&ulite_uart_driver);
-err_uart:
- pr_err("registering uartlite driver failed: err=%i\n", ret);
- return ret;
+ return platform_driver_register(&ulite_platform_driver);
}
static void __exit ulite_exit(void)
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index a48f19b1b88f..57c66d2c3471 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -30,8 +30,6 @@
#define CDNS_UART_TTY_NAME "ttyPS"
#define CDNS_UART_NAME "xuartps"
#define CDNS_UART_MAJOR 0 /* use dynamic node allocation */
-#define CDNS_UART_MINOR 0 /* works best with devtmpfs */
-#define CDNS_UART_NR_PORTS 2
#define CDNS_UART_FIFO_SIZE 64 /* FIFO size */
#define CDNS_UART_REGISTER_SPACE 0x1000
@@ -180,7 +178,9 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
* @port: Pointer to the UART port
* @uartclk: Reference clock
* @pclk: APB clock
+ * @cdns_uart_driver: Pointer to UART driver
* @baud: Current baud rate
+ * @id: Port ID
* @clk_rate_change_nb: Notifier block for clock changes
* @quirks: Flags for RXBS support.
*/
@@ -188,7 +188,9 @@ struct cdns_uart {
struct uart_port *port;
struct clk *uartclk;
struct clk *pclk;
+ struct uart_driver *cdns_uart_driver;
unsigned int baud;
+ int id;
struct notifier_block clk_rate_change_nb;
u32 quirks;
};
@@ -1003,13 +1005,12 @@ static void cdns_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
val = readl(port->membase + CDNS_UART_MODEMCR);
mode_reg = readl(port->membase + CDNS_UART_MR);
- val &= ~(CDNS_UART_MODEMCR_RTS | CDNS_UART_MODEMCR_DTR);
+ val &= ~(CDNS_UART_MODEMCR_RTS | CDNS_UART_MODEMCR_DTR |
+ CDNS_UART_MODEMCR_FCM);
mode_reg &= ~CDNS_UART_MR_CHMODE_MASK;
- if (mctrl & TIOCM_RTS)
- val |= CDNS_UART_MODEMCR_RTS;
- if (mctrl & TIOCM_DTR)
- val |= CDNS_UART_MODEMCR_DTR;
+ if (mctrl & TIOCM_RTS || mctrl & TIOCM_DTR)
+ val |= CDNS_UART_MODEMCR_FCM;
if (mctrl & TIOCM_LOOP)
mode_reg |= CDNS_UART_MR_CHMODE_L_LOOP;
else
@@ -1217,7 +1218,7 @@ static void cdns_uart_console_write(struct console *co, const char *s,
*
* Return: 0 on success, negative errno otherwise.
*/
-static int __init cdns_uart_console_setup(struct console *co, char *options)
+static int cdns_uart_console_setup(struct console *co, char *options)
{
struct uart_port *port = console_port;
@@ -1237,32 +1238,8 @@ static int __init cdns_uart_console_setup(struct console *co, char *options)
return uart_set_options(port, co, baud, parity, bits, flow);
}
-
-static struct uart_driver cdns_uart_uart_driver;
-
-static struct console cdns_uart_console = {
- .name = CDNS_UART_TTY_NAME,
- .write = cdns_uart_console_write,
- .device = uart_console_device,
- .setup = cdns_uart_console_setup,
- .flags = CON_PRINTBUFFER,
- .index = -1, /* Specified on the cmdline (e.g. console=ttyPS ) */
- .data = &cdns_uart_uart_driver,
-};
#endif /* CONFIG_SERIAL_XILINX_PS_UART_CONSOLE */
-static struct uart_driver cdns_uart_uart_driver = {
- .owner = THIS_MODULE,
- .driver_name = CDNS_UART_NAME,
- .dev_name = CDNS_UART_TTY_NAME,
- .major = CDNS_UART_MAJOR,
- .minor = CDNS_UART_MINOR,
- .nr = CDNS_UART_NR_PORTS,
-#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
- .cons = &cdns_uart_console,
-#endif
-};
-
#ifdef CONFIG_PM_SLEEP
/**
* cdns_uart_suspend - suspend event
@@ -1273,24 +1250,12 @@ static struct uart_driver cdns_uart_uart_driver = {
static int cdns_uart_suspend(struct device *device)
{
struct uart_port *port = dev_get_drvdata(device);
- struct tty_struct *tty;
- struct device *tty_dev;
- int may_wake = 0;
-
- /* Get the tty which could be NULL so don't assume it's valid */
- tty = tty_port_tty_get(&port->state->port);
- if (tty) {
- tty_dev = tty->dev;
- may_wake = device_may_wakeup(tty_dev);
- tty_kref_put(tty);
- }
+ struct cdns_uart *cdns_uart = port->private_data;
+ int may_wake;
- /*
- * Call the API provided in serial_core.c file which handles
- * the suspend.
- */
- uart_suspend_port(&cdns_uart_uart_driver, port);
- if (!(console_suspend_enabled && !may_wake)) {
+ may_wake = device_may_wakeup(device);
+
+ if (console_suspend_enabled && may_wake) {
unsigned long flags = 0;
spin_lock_irqsave(&port->lock, flags);
@@ -1305,7 +1270,11 @@ static int cdns_uart_suspend(struct device *device)
spin_unlock_irqrestore(&port->lock, flags);
}
- return 0;
+ /*
+ * Call the API provided in serial_core.c file which handles
+ * the suspend.
+ */
+ return uart_suspend_port(cdns_uart->cdns_uart_driver, port);
}
/**
@@ -1317,23 +1286,14 @@ static int cdns_uart_suspend(struct device *device)
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;
u32 ctrl_reg;
- struct tty_struct *tty;
- struct device *tty_dev;
- int may_wake = 0;
-
- /* Get the tty which could be NULL so don't assume it's valid */
- tty = tty_port_tty_get(&port->state->port);
- if (tty) {
- tty_dev = tty->dev;
- may_wake = device_may_wakeup(tty_dev);
- tty_kref_put(tty);
- }
+ int may_wake;
- if (console_suspend_enabled && !may_wake) {
- struct cdns_uart *cdns_uart = port->private_data;
+ may_wake = device_may_wakeup(device);
+ if (console_suspend_enabled && !may_wake) {
clk_enable(cdns_uart->pclk);
clk_enable(cdns_uart->uartclk);
@@ -1367,7 +1327,7 @@ static int cdns_uart_resume(struct device *device)
spin_unlock_irqrestore(&port->lock, flags);
}
- return uart_resume_port(&cdns_uart_uart_driver, port);
+ return uart_resume_port(cdns_uart->cdns_uart_driver, port);
}
#endif /* ! CONFIG_PM_SLEEP */
static int __maybe_unused cdns_runtime_suspend(struct device *dev)
@@ -1409,6 +1369,90 @@ static const struct of_device_id cdns_uart_of_match[] = {
};
MODULE_DEVICE_TABLE(of, cdns_uart_of_match);
+/*
+ * Maximum number of instances without alias IDs but if there is alias
+ * which target "< MAX_UART_INSTANCES" range this ID can't be used.
+ */
+#define MAX_UART_INSTANCES 32
+
+/* Stores static aliases list */
+static DECLARE_BITMAP(alias_bitmap, MAX_UART_INSTANCES);
+static int alias_bitmap_initialized;
+
+/* Stores actual bitmap of allocated IDs with alias IDs together */
+static DECLARE_BITMAP(bitmap, MAX_UART_INSTANCES);
+/* Protect bitmap operations to have unique IDs */
+static DEFINE_MUTEX(bitmap_lock);
+
+static int cdns_get_id(struct platform_device *pdev)
+{
+ int id, ret;
+
+ mutex_lock(&bitmap_lock);
+
+ /* Alias list is stable that's why get alias bitmap only once */
+ if (!alias_bitmap_initialized) {
+ ret = of_alias_get_alias_list(cdns_uart_of_match, "serial",
+ alias_bitmap, MAX_UART_INSTANCES);
+ if (ret && ret != -EOVERFLOW) {
+ mutex_unlock(&bitmap_lock);
+ return ret;
+ }
+
+ alias_bitmap_initialized++;
+ }
+
+ /* Make sure that alias ID is not taken by instance without alias */
+ bitmap_or(bitmap, bitmap, alias_bitmap, MAX_UART_INSTANCES);
+
+ dev_dbg(&pdev->dev, "Alias bitmap: %*pb\n",
+ MAX_UART_INSTANCES, bitmap);
+
+ /* Look for a serialN alias */
+ id = of_alias_get_id(pdev->dev.of_node, "serial");
+ if (id < 0) {
+ dev_warn(&pdev->dev,
+ "No serial alias passed. Using the first free id\n");
+
+ /*
+ * Start with id 0 and check if there is no serial0 alias
+ * which points to device which is compatible with this driver.
+ * If alias exists then try next free position.
+ */
+ id = 0;
+
+ for (;;) {
+ dev_info(&pdev->dev, "Checking id %d\n", id);
+ id = find_next_zero_bit(bitmap, MAX_UART_INSTANCES, id);
+
+ /* No free empty instance */
+ if (id == MAX_UART_INSTANCES) {
+ dev_err(&pdev->dev, "No free ID\n");
+ mutex_unlock(&bitmap_lock);
+ return -EINVAL;
+ }
+
+ dev_dbg(&pdev->dev, "The empty id is %d\n", id);
+ /* Check if ID is empty */
+ if (!test_and_set_bit(id, bitmap)) {
+ /* Break the loop if bit is taken */
+ dev_dbg(&pdev->dev,
+ "Selected ID %d allocation passed\n",
+ id);
+ break;
+ }
+ dev_dbg(&pdev->dev,
+ "Selected ID %d allocation failed\n", id);
+ /* if taking bit fails then try next one */
+ id++;
+ }
+ }
+
+ mutex_unlock(&bitmap_lock);
+
+ return id;
+}
+
/**
* cdns_uart_probe - Platform driver probe
* @pdev: Pointer to the platform device structure
@@ -1417,11 +1461,16 @@ MODULE_DEVICE_TABLE(of, cdns_uart_of_match);
*/
static int cdns_uart_probe(struct platform_device *pdev)
{
- int rc, id, irq;
+ int rc, irq;
struct uart_port *port;
struct resource *res;
struct cdns_uart *cdns_uart_data;
const struct of_device_id *match;
+ struct uart_driver *cdns_uart_uart_driver;
+ char *driver_name;
+#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
+ struct console *cdns_uart_console;
+#endif
cdns_uart_data = devm_kzalloc(&pdev->dev, sizeof(*cdns_uart_data),
GFP_KERNEL);
@@ -1431,6 +1480,63 @@ static int cdns_uart_probe(struct platform_device *pdev)
if (!port)
return -ENOMEM;
+ cdns_uart_uart_driver = devm_kzalloc(&pdev->dev,
+ sizeof(*cdns_uart_uart_driver),
+ GFP_KERNEL);
+ if (!cdns_uart_uart_driver)
+ return -ENOMEM;
+
+ cdns_uart_data->id = cdns_get_id(pdev);
+ if (cdns_uart_data->id < 0)
+ return cdns_uart_data->id;
+
+ /* There is a need to use unique driver name */
+ driver_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s%d",
+ CDNS_UART_NAME, cdns_uart_data->id);
+ if (!driver_name) {
+ rc = -ENOMEM;
+ goto err_out_id;
+ }
+
+ cdns_uart_uart_driver->owner = THIS_MODULE;
+ cdns_uart_uart_driver->driver_name = driver_name;
+ cdns_uart_uart_driver->dev_name = CDNS_UART_TTY_NAME;
+ cdns_uart_uart_driver->major = CDNS_UART_MAJOR;
+ cdns_uart_uart_driver->minor = cdns_uart_data->id;
+ cdns_uart_uart_driver->nr = 1;
+
+#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
+ cdns_uart_console = devm_kzalloc(&pdev->dev, sizeof(*cdns_uart_console),
+ GFP_KERNEL);
+ if (!cdns_uart_console)
+ return -ENOMEM;
+
+ strncpy(cdns_uart_console->name, CDNS_UART_TTY_NAME,
+ sizeof(cdns_uart_console->name));
+ cdns_uart_console->index = cdns_uart_data->id;
+ cdns_uart_console->write = cdns_uart_console_write;
+ cdns_uart_console->device = uart_console_device;
+ cdns_uart_console->setup = cdns_uart_console_setup;
+ cdns_uart_console->flags = CON_PRINTBUFFER;
+ cdns_uart_console->data = cdns_uart_uart_driver;
+ cdns_uart_uart_driver->cons = cdns_uart_console;
+#endif
+
+ rc = uart_register_driver(cdns_uart_uart_driver);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "Failed to register driver\n");
+ goto err_out_id;
+ }
+
+ cdns_uart_data->cdns_uart_driver = cdns_uart_uart_driver;
+
+ /*
+ * Setting up proper name_base needs to be done after uart
+ * registration because tty_driver structure is not filled.
+ * name_base is 0 by default.
+ */
+ cdns_uart_uart_driver->tty_driver->name_base = cdns_uart_data->id;
+
match = of_match_node(cdns_uart_of_match, pdev->dev.of_node);
if (match && match->data) {
const struct cdns_platform_data *data = match->data;
@@ -1446,7 +1552,8 @@ static int cdns_uart_probe(struct platform_device *pdev)
}
if (IS_ERR(cdns_uart_data->pclk)) {
dev_err(&pdev->dev, "pclk clock not found.\n");
- return PTR_ERR(cdns_uart_data->pclk);
+ rc = PTR_ERR(cdns_uart_data->pclk);
+ goto err_out_unregister_driver;
}
cdns_uart_data->uartclk = devm_clk_get(&pdev->dev, "uart_clk");
@@ -1457,13 +1564,14 @@ static int cdns_uart_probe(struct platform_device *pdev)
}
if (IS_ERR(cdns_uart_data->uartclk)) {
dev_err(&pdev->dev, "uart_clk clock not found.\n");
- return PTR_ERR(cdns_uart_data->uartclk);
+ rc = PTR_ERR(cdns_uart_data->uartclk);
+ goto err_out_unregister_driver;
}
rc = clk_prepare_enable(cdns_uart_data->pclk);
if (rc) {
dev_err(&pdev->dev, "Unable to enable pclk clock.\n");
- return rc;
+ goto err_out_unregister_driver;
}
rc = clk_prepare_enable(cdns_uart_data->uartclk);
if (rc) {
@@ -1490,28 +1598,14 @@ static int cdns_uart_probe(struct platform_device *pdev)
&cdns_uart_data->clk_rate_change_nb))
dev_warn(&pdev->dev, "Unable to register clock notifier.\n");
#endif
- /* Look for a serialN alias */
- id = of_alias_get_id(pdev->dev.of_node, "serial");
- if (id < 0)
- id = 0;
-
- if (id >= CDNS_UART_NR_PORTS) {
- dev_err(&pdev->dev, "Cannot get uart_port structure\n");
- rc = -ENODEV;
- goto err_out_notif_unreg;
- }
/* At this point, we've got an empty uart_port struct, initialize it */
spin_lock_init(&port->lock);
- port->membase = NULL;
- port->irq = 0;
port->type = PORT_UNKNOWN;
port->iotype = UPIO_MEM32;
port->flags = UPF_BOOT_AUTOCONF;
port->ops = &cdns_uart_ops;
port->fifosize = CDNS_UART_FIFO_SIZE;
- port->line = id;
- port->dev = NULL;
/*
* Register the port.
@@ -1538,11 +1632,11 @@ static int cdns_uart_probe(struct platform_device *pdev)
* If register_console() don't assign value, then console_port pointer
* is cleanup.
*/
- if (cdns_uart_uart_driver.cons->index == -1)
+ if (!console_port)
console_port = port;
#endif
- rc = uart_add_one_port(&cdns_uart_uart_driver, port);
+ rc = uart_add_one_port(cdns_uart_uart_driver, port);
if (rc) {
dev_err(&pdev->dev,
"uart_add_one_port() failed; err=%i\n", rc);
@@ -1551,7 +1645,8 @@ static int cdns_uart_probe(struct platform_device *pdev)
#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
/* This is not port which is used for console that's why clean it up */
- if (cdns_uart_uart_driver.cons->index == -1)
+ if (console_port == port &&
+ !(cdns_uart_uart_driver->cons->flags & CON_ENABLED))
console_port = NULL;
#endif
@@ -1561,7 +1656,6 @@ err_out_pm_disable:
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
-err_out_notif_unreg:
#ifdef CONFIG_COMMON_CLK
clk_notifier_unregister(cdns_uart_data->uartclk,
&cdns_uart_data->clk_rate_change_nb);
@@ -1570,7 +1664,13 @@ err_out_clk_disable:
clk_disable_unprepare(cdns_uart_data->uartclk);
err_out_clk_dis_pclk:
clk_disable_unprepare(cdns_uart_data->pclk);
-
+err_out_unregister_driver:
+ uart_unregister_driver(cdns_uart_data->cdns_uart_driver);
+err_out_id:
+ mutex_lock(&bitmap_lock);
+ if (cdns_uart_data->id < MAX_UART_INSTANCES)
+ clear_bit(cdns_uart_data->id, bitmap);
+ mutex_unlock(&bitmap_lock);
return rc;
}
@@ -1591,13 +1691,24 @@ static int cdns_uart_remove(struct platform_device *pdev)
clk_notifier_unregister(cdns_uart_data->uartclk,
&cdns_uart_data->clk_rate_change_nb);
#endif
- rc = uart_remove_one_port(&cdns_uart_uart_driver, port);
+ rc = uart_remove_one_port(cdns_uart_data->cdns_uart_driver, port);
port->mapbase = 0;
+ mutex_lock(&bitmap_lock);
+ if (cdns_uart_data->id < MAX_UART_INSTANCES)
+ clear_bit(cdns_uart_data->id, bitmap);
+ mutex_unlock(&bitmap_lock);
clk_disable_unprepare(cdns_uart_data->uartclk);
clk_disable_unprepare(cdns_uart_data->pclk);
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
+
+#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
+ if (console_port == port)
+ console_port = NULL;
+#endif
+
+ uart_unregister_driver(cdns_uart_data->cdns_uart_driver);
return rc;
}
@@ -1613,28 +1724,14 @@ static struct platform_driver cdns_uart_platform_driver = {
static int __init cdns_uart_init(void)
{
- int retval = 0;
-
- /* Register the cdns_uart driver with the serial core */
- retval = uart_register_driver(&cdns_uart_uart_driver);
- if (retval)
- return retval;
-
/* Register the platform driver */
- retval = platform_driver_register(&cdns_uart_platform_driver);
- if (retval)
- uart_unregister_driver(&cdns_uart_uart_driver);
-
- return retval;
+ return platform_driver_register(&cdns_uart_platform_driver);
}
static void __exit cdns_uart_exit(void)
{
/* Unregister the platform driver */
platform_driver_unregister(&cdns_uart_platform_driver);
-
- /* Unregister the cdns_uart driver */
- uart_unregister_driver(&cdns_uart_uart_driver);
}
arch_initcall(cdns_uart_init);
diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c
index fbdf4d01c6a9..d55c858d6058 100644
--- a/drivers/tty/synclink.c
+++ b/drivers/tty/synclink.c
@@ -2959,8 +2959,7 @@ static int mgsl_ioctl(struct tty_struct *tty,
if (mgsl_paranoia_check(info, tty->name, "mgsl_ioctl"))
return -ENODEV;
- if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
- (cmd != TIOCMIWAIT)) {
+ if (cmd != TIOCMIWAIT) {
if (tty_io_error(tty))
return -EIO;
}
diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c
index a94086597ebd..e8a9047de451 100644
--- a/drivers/tty/synclink_gt.c
+++ b/drivers/tty/synclink_gt.c
@@ -1029,8 +1029,7 @@ static int ioctl(struct tty_struct *tty,
return -ENODEV;
DBGINFO(("%s ioctl() cmd=%08X\n", info->device_name, cmd));
- if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
- (cmd != TIOCMIWAIT)) {
+ if (cmd != TIOCMIWAIT) {
if (tty_io_error(tty))
return -EIO;
}
@@ -1186,14 +1185,13 @@ static long slgt_compat_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
struct slgt_info *info = tty->driver_data;
- int rc = -ENOIOCTLCMD;
+ int rc;
if (sanity_check(info, tty->name, "compat_ioctl"))
return -ENODEV;
DBGINFO(("%s compat_ioctl() cmd=%08X\n", info->device_name, cmd));
switch (cmd) {
-
case MGSL_IOCSPARAMS32:
rc = set_params32(info, compat_ptr(arg));
break;
@@ -1213,18 +1211,11 @@ static long slgt_compat_ioctl(struct tty_struct *tty,
case MGSL_IOCWAITGPIO:
case MGSL_IOCGXSYNC:
case MGSL_IOCGXCTRL:
- case MGSL_IOCSTXIDLE:
- case MGSL_IOCTXENABLE:
- case MGSL_IOCRXENABLE:
- case MGSL_IOCTXABORT:
- case TIOCMIWAIT:
- case MGSL_IOCSIF:
- case MGSL_IOCSXSYNC:
- case MGSL_IOCSXCTRL:
- rc = ioctl(tty, cmd, arg);
+ rc = ioctl(tty, cmd, (unsigned long)compat_ptr(arg));
break;
+ default:
+ rc = ioctl(tty, cmd, arg);
}
-
DBGINFO(("%s compat_ioctl() cmd=%08X rc=%d\n", info->device_name, cmd, rc));
return rc;
}
diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c
index 1e4d5b9c981a..fcb91bf7a15b 100644
--- a/drivers/tty/synclinkmp.c
+++ b/drivers/tty/synclinkmp.c
@@ -1259,8 +1259,7 @@ static int ioctl(struct tty_struct *tty,
if (sanity_check(info, tty->name, "ioctl"))
return -ENODEV;
- if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
- (cmd != TIOCMIWAIT)) {
+ if (cmd != TIOCMIWAIT) {
if (tty_io_error(tty))
return -EIO;
}
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index 06ed20dd01ba..ad1ee5d01b53 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -348,7 +348,7 @@ static void send_sig_all(int sig)
if (is_global_init(p))
continue;
- do_send_sig_info(sig, SEND_SIG_FORCED, p, PIDTYPE_MAX);
+ do_send_sig_info(sig, SEND_SIG_PRIV, p, PIDTYPE_MAX);
}
read_unlock(&tasklist_lock);
}
diff --git a/drivers/tty/tty_baudrate.c b/drivers/tty/tty_baudrate.c
index 7576ceace571..f438eaa68246 100644
--- a/drivers/tty/tty_baudrate.c
+++ b/drivers/tty/tty_baudrate.c
@@ -77,7 +77,7 @@ speed_t tty_termios_baud_rate(struct ktermios *termios)
else
cbaud += 15;
}
- return baud_table[cbaud];
+ return cbaud >= n_baud_table ? 0 : baud_table[cbaud];
}
EXPORT_SYMBOL(tty_termios_baud_rate);
@@ -113,7 +113,7 @@ speed_t tty_termios_input_baud_rate(struct ktermios *termios)
else
cbaud += 15;
}
- return baud_table[cbaud];
+ return cbaud >= n_baud_table ? 0 : baud_table[cbaud];
#else /* IBSHIFT */
return tty_termios_baud_rate(termios);
#endif /* IBSHIFT */
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index c996b6859c5e..77070c2d1240 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -118,9 +118,12 @@ void tty_buffer_free_all(struct tty_port *port)
struct tty_bufhead *buf = &port->buf;
struct tty_buffer *p, *next;
struct llist_node *llist;
+ unsigned int freed = 0;
+ int still_used;
while ((p = buf->head) != NULL) {
buf->head = p->next;
+ freed += p->size;
if (p->size > 0)
kfree(p);
}
@@ -132,7 +135,9 @@ void tty_buffer_free_all(struct tty_port *port)
buf->head = &buf->sentinel;
buf->tail = &buf->sentinel;
- atomic_set(&buf->mem_used, 0);
+ still_used = atomic_xchg(&buf->mem_used, 0);
+ WARN(still_used != freed, "we still have not freed %d bytes!",
+ still_used - freed);
}
/**
@@ -468,11 +473,15 @@ receive_buf(struct tty_port *port, struct tty_buffer *head, int count)
{
unsigned char *p = char_buf_ptr(head, head->read);
char *f = NULL;
+ int n;
if (~head->flags & TTYB_NORMAL)
f = flag_buf_ptr(head, head->read);
- return port->client_ops->receive_buf(port, p, f, count);
+ n = port->client_ops->receive_buf(port, p, f, count);
+ if (n > 0)
+ memset(p, 0, n);
+ return n;
}
/**
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 5e5da9acaf0a..ee80dfbd5442 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -97,6 +97,7 @@
#include <linux/seq_file.h>
#include <linux/serial.h>
#include <linux/ratelimit.h>
+#include <linux/compat.h>
#include <linux/uaccess.h>
@@ -408,7 +409,7 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line)
mutex_lock(&tty_mutex);
/* Search through the tty devices to look for a match */
list_for_each_entry(p, &tty_drivers, tty_drivers) {
- if (strncmp(name, p->name, len) != 0)
+ if (!len || strncmp(name, p->name, len) != 0)
continue;
stp = str;
if (*stp == ',')
@@ -2293,34 +2294,6 @@ static int tioccons(struct file *file)
}
/**
- * fionbio - non blocking ioctl
- * @file: file to set blocking value
- * @p: user parameter
- *
- * Historical tty interfaces had a blocking control ioctl before
- * the generic functionality existed. This piece of history is preserved
- * in the expected tty API of posix OS's.
- *
- * Locking: none, the open file handle ensures it won't go away.
- */
-
-static int fionbio(struct file *file, int __user *p)
-{
- int nonblock;
-
- if (get_user(nonblock, p))
- return -EFAULT;
-
- spin_lock(&file->f_lock);
- if (nonblock)
- file->f_flags |= O_NONBLOCK;
- else
- file->f_flags &= ~O_NONBLOCK;
- spin_unlock(&file->f_lock);
- return 0;
-}
-
-/**
* tiocsetd - set line discipline
* @tty: tty device
* @p: pointer to user data
@@ -2488,22 +2461,40 @@ static int tty_tiocgicount(struct tty_struct *tty, void __user *arg)
return 0;
}
-static void tty_warn_deprecated_flags(struct serial_struct __user *ss)
+static int tty_tiocsserial(struct tty_struct *tty, struct serial_struct __user *ss)
{
static DEFINE_RATELIMIT_STATE(depr_flags,
DEFAULT_RATELIMIT_INTERVAL,
DEFAULT_RATELIMIT_BURST);
char comm[TASK_COMM_LEN];
+ struct serial_struct v;
int flags;
- if (get_user(flags, &ss->flags))
- return;
+ if (copy_from_user(&v, ss, sizeof(struct serial_struct)))
+ return -EFAULT;
- flags &= ASYNC_DEPRECATED;
+ flags = v.flags & ASYNC_DEPRECATED;
if (flags && __ratelimit(&depr_flags))
pr_warn("%s: '%s' is using deprecated serial flags (with no effect): %.8x\n",
__func__, get_task_comm(comm, current), flags);
+ if (!tty->ops->set_serial)
+ return -ENOTTY;
+ return tty->ops->set_serial(tty, &v);
+}
+
+static int tty_tiocgserial(struct tty_struct *tty, struct serial_struct __user *ss)
+{
+ struct serial_struct v;
+ int err;
+
+ memset(&v, 0, sizeof(struct serial_struct));
+ if (!tty->ops->get_serial)
+ return -ENOTTY;
+ err = tty->ops->get_serial(tty, &v);
+ if (!err && copy_to_user(ss, &v, sizeof(struct serial_struct)))
+ err = -EFAULT;
+ return err;
}
/*
@@ -2566,8 +2557,6 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return tiocswinsz(real_tty, p);
case TIOCCONS:
return real_tty != tty ? -EINVAL : tioccons(file);
- case FIONBIO:
- return fionbio(file, p);
case TIOCEXCL:
set_bit(TTY_EXCLUSIVE, &tty->flags);
return 0;
@@ -2622,11 +2611,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case TIOCMBIS:
return tty_tiocmset(tty, cmd, p);
case TIOCGICOUNT:
- retval = tty_tiocgicount(tty, p);
- /* For the moment allow fall through to the old method */
- if (retval != -EINVAL)
- return retval;
- break;
+ return tty_tiocgicount(tty, p);
case TCFLSH:
switch (arg) {
case TCIFLUSH:
@@ -2637,8 +2622,9 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
}
break;
case TIOCSSERIAL:
- tty_warn_deprecated_flags(p);
- break;
+ return tty_tiocsserial(tty, p);
+ case TIOCGSERIAL:
+ return tty_tiocgserial(tty, p);
case TIOCGPTPEER:
/* Special because the struct file is needed */
return ptm_open_peer(file, tty, (int)arg);
@@ -2666,6 +2652,81 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
}
#ifdef CONFIG_COMPAT
+
+struct serial_struct32 {
+ compat_int_t type;
+ compat_int_t line;
+ compat_uint_t port;
+ compat_int_t irq;
+ compat_int_t flags;
+ compat_int_t xmit_fifo_size;
+ compat_int_t custom_divisor;
+ compat_int_t baud_base;
+ unsigned short close_delay;
+ char io_type;
+ char reserved_char[1];
+ compat_int_t hub6;
+ unsigned short closing_wait; /* time to wait before closing */
+ unsigned short closing_wait2; /* no longer used... */
+ compat_uint_t iomem_base;
+ unsigned short iomem_reg_shift;
+ unsigned int port_high;
+ /* compat_ulong_t iomap_base FIXME */
+ compat_int_t reserved[1];
+};
+
+static int compat_tty_tiocsserial(struct tty_struct *tty,
+ struct serial_struct32 __user *ss)
+{
+ static DEFINE_RATELIMIT_STATE(depr_flags,
+ DEFAULT_RATELIMIT_INTERVAL,
+ DEFAULT_RATELIMIT_BURST);
+ char comm[TASK_COMM_LEN];
+ struct serial_struct32 v32;
+ struct serial_struct v;
+ int flags;
+
+ if (copy_from_user(&v32, ss, sizeof(struct serial_struct32)))
+ return -EFAULT;
+
+ memcpy(&v, &v32, offsetof(struct serial_struct32, iomem_base));
+ v.iomem_base = compat_ptr(v32.iomem_base);
+ v.iomem_reg_shift = v32.iomem_reg_shift;
+ v.port_high = v32.port_high;
+ v.iomap_base = 0;
+
+ flags = v.flags & ASYNC_DEPRECATED;
+
+ if (flags && __ratelimit(&depr_flags))
+ pr_warn("%s: '%s' is using deprecated serial flags (with no effect): %.8x\n",
+ __func__, get_task_comm(comm, current), flags);
+ if (!tty->ops->set_serial)
+ return -ENOTTY;
+ return tty->ops->set_serial(tty, &v);
+}
+
+static int compat_tty_tiocgserial(struct tty_struct *tty,
+ struct serial_struct32 __user *ss)
+{
+ struct serial_struct32 v32;
+ struct serial_struct v;
+ int err;
+ memset(&v, 0, sizeof(struct serial_struct));
+
+ if (!tty->ops->set_serial)
+ return -ENOTTY;
+ err = tty->ops->get_serial(tty, &v);
+ if (!err) {
+ memcpy(&v32, &v, offsetof(struct serial_struct32, iomem_base));
+ v32.iomem_base = (unsigned long)v.iomem_base >> 32 ?
+ 0xfffffff : ptr_to_compat(v.iomem_base);
+ v32.iomem_reg_shift = v.iomem_reg_shift;
+ v32.port_high = v.port_high;
+ if (copy_to_user(ss, &v32, sizeof(struct serial_struct32)))
+ err = -EFAULT;
+ }
+ return err;
+}
static long tty_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
@@ -2673,9 +2734,90 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd,
struct tty_ldisc *ld;
int retval = -ENOIOCTLCMD;
+ switch (cmd) {
+ case TIOCSTI:
+ case TIOCGWINSZ:
+ case TIOCSWINSZ:
+ case TIOCGEXCL:
+ case TIOCGETD:
+ case TIOCSETD:
+ case TIOCGDEV:
+ case TIOCMGET:
+ case TIOCMSET:
+ case TIOCMBIC:
+ case TIOCMBIS:
+ case TIOCGICOUNT:
+ case TIOCGPGRP:
+ case TIOCSPGRP:
+ case TIOCGSID:
+ case TIOCSERGETLSR:
+ case TIOCGRS485:
+ case TIOCSRS485:
+#ifdef TIOCGETP
+ case TIOCGETP:
+ case TIOCSETP:
+ case TIOCSETN:
+#endif
+#ifdef TIOCGETC
+ case TIOCGETC:
+ case TIOCSETC:
+#endif
+#ifdef TIOCGLTC
+ case TIOCGLTC:
+ case TIOCSLTC:
+#endif
+ case TCSETSF:
+ case TCSETSW:
+ case TCSETS:
+ case TCGETS:
+#ifdef TCGETS2
+ case TCGETS2:
+ case TCSETSF2:
+ case TCSETSW2:
+ case TCSETS2:
+#endif
+ case TCGETA:
+ case TCSETAF:
+ case TCSETAW:
+ case TCSETA:
+ case TIOCGLCKTRMIOS:
+ case TIOCSLCKTRMIOS:
+#ifdef TCGETX
+ case TCGETX:
+ case TCSETX:
+ case TCSETXW:
+ case TCSETXF:
+#endif
+ case TIOCGSOFTCAR:
+ case TIOCSSOFTCAR:
+ return tty_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
+ case TIOCCONS:
+ case TIOCEXCL:
+ case TIOCNXCL:
+ case TIOCVHANGUP:
+ case TIOCSBRK:
+ case TIOCCBRK:
+ case TCSBRK:
+ case TCSBRKP:
+ case TCFLSH:
+ case TIOCGPTPEER:
+ case TIOCNOTTY:
+ case TIOCSCTTY:
+ case TCXONC:
+ case TIOCMIWAIT:
+ case TIOCSERCONFIG:
+ return tty_ioctl(file, cmd, arg);
+ }
+
if (tty_paranoia_check(tty, file_inode(file), "tty_ioctl"))
return -EINVAL;
+ switch (cmd) {
+ case TIOCSSERIAL:
+ return compat_tty_tiocsserial(tty, compat_ptr(arg));
+ case TIOCGSERIAL:
+ return compat_tty_tiocgserial(tty, compat_ptr(arg));
+ }
if (tty->ops->compat_ioctl) {
retval = tty->ops->compat_ioctl(tty, cmd, arg);
if (retval != -ENOIOCTLCMD)
@@ -2687,8 +2829,9 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd,
return hung_up_tty_compat_ioctl(file, cmd, arg);
if (ld->ops->compat_ioctl)
retval = ld->ops->compat_ioctl(tty, file, cmd, arg);
- else
- retval = n_tty_compat_ioctl_helper(tty, file, cmd, arg);
+ if (retval == -ENOIOCTLCMD && ld->ops->ioctl)
+ retval = ld->ops->ioctl(tty, file,
+ (unsigned long)compat_ptr(cmd), arg);
tty_ldisc_deref(ld);
return retval;
@@ -2743,7 +2886,7 @@ void __do_SAK(struct tty_struct *tty)
do_each_pid_task(session, PIDTYPE_SID, p) {
tty_notice(tty, "SAK: killed process %d (%s): by session\n",
task_pid_nr(p), p->comm);
- send_sig(SIGKILL, p, 1);
+ group_send_sig_info(SIGKILL, SEND_SIG_PRIV, p, PIDTYPE_SID);
} while_each_pid_task(session, PIDTYPE_SID, p);
/* Now kill any processes that happen to have the tty open */
@@ -2751,7 +2894,7 @@ void __do_SAK(struct tty_struct *tty)
if (p->signal->tty == tty) {
tty_notice(tty, "SAK: killed process %d (%s): by controlling tty\n",
task_pid_nr(p), p->comm);
- send_sig(SIGKILL, p, 1);
+ group_send_sig_info(SIGKILL, SEND_SIG_PRIV, p, PIDTYPE_SID);
continue;
}
task_lock(p);
@@ -2759,7 +2902,7 @@ void __do_SAK(struct tty_struct *tty)
if (i != 0) {
tty_notice(tty, "SAK: killed process %d (%s): by fd#%d\n",
task_pid_nr(p), p->comm, i - 1);
- force_sig(SIGKILL, p);
+ group_send_sig_info(SIGKILL, SEND_SIG_PRIV, p, PIDTYPE_SID);
}
task_unlock(p);
} while_each_thread(g, p);
diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c
index d99fec44036c..9245fffdbceb 100644
--- a/drivers/tty/tty_ioctl.c
+++ b/drivers/tty/tty_ioctl.c
@@ -941,19 +941,3 @@ int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
}
}
EXPORT_SYMBOL(n_tty_ioctl_helper);
-
-#ifdef CONFIG_COMPAT
-long n_tty_compat_ioctl_helper(struct tty_struct *tty, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- switch (cmd) {
- case TIOCGLCKTRMIOS:
- case TIOCSLCKTRMIOS:
- return tty_mode_ioctl(tty, file, cmd, (unsigned long) compat_ptr(arg));
- default:
- return -ENOIOCTLCMD;
- }
-}
-EXPORT_SYMBOL(n_tty_compat_ioctl_helper);
-#endif
-
diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
index 25d736880013..cb6075096a5b 100644
--- a/drivers/tty/tty_port.c
+++ b/drivers/tty/tty_port.c
@@ -279,7 +279,6 @@ EXPORT_SYMBOL(tty_port_put);
* Return a refcount protected tty instance or NULL if the port is not
* associated with a tty (eg due to close or hangup)
*/
-
struct tty_struct *tty_port_tty_get(struct tty_port *port)
{
unsigned long flags;
@@ -300,7 +299,6 @@ EXPORT_SYMBOL(tty_port_tty_get);
* Associate the port and tty pair. Manages any internal refcounts.
* Pass NULL to deassociate a port
*/
-
void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
{
unsigned long flags;
@@ -343,7 +341,6 @@ out:
*
* Caller holds tty lock.
*/
-
void tty_port_hangup(struct tty_port *port)
{
struct tty_struct *tty;
@@ -399,7 +396,6 @@ EXPORT_SYMBOL_GPL(tty_port_tty_wakeup);
* to hide some internal details. This will eventually become entirely
* internal to the tty port.
*/
-
int tty_port_carrier_raised(struct tty_port *port)
{
if (port->ops->carrier_raised == NULL)
@@ -416,7 +412,6 @@ EXPORT_SYMBOL(tty_port_carrier_raised);
* to hide some internal details. This will eventually become entirely
* internal to the tty port.
*/
-
void tty_port_raise_dtr_rts(struct tty_port *port)
{
if (port->ops->dtr_rts)
@@ -432,7 +427,6 @@ EXPORT_SYMBOL(tty_port_raise_dtr_rts);
* to hide some internal details. This will eventually become entirely
* internal to the tty port.
*/
-
void tty_port_lower_dtr_rts(struct tty_port *port)
{
if (port->ops->dtr_rts)
@@ -464,7 +458,6 @@ EXPORT_SYMBOL(tty_port_lower_dtr_rts);
* NB: May drop and reacquire tty lock when blocking, so tty and tty_port
* may have changed state (eg., may have been hung up).
*/
-
int tty_port_block_til_ready(struct tty_port *port,
struct tty_struct *tty, struct file *filp)
{
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 55370e651db3..41ec8e5010f3 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -1548,7 +1548,7 @@ static void csi_K(struct vc_data *vc, int vpar)
scr_memsetw(start + offset, vc->vc_video_erase_char, 2 * count);
vc->vc_need_wrap = 0;
if (con_should_update(vc))
- do_update_region(vc, (unsigned long) start, count);
+ do_update_region(vc, (unsigned long)(start + offset), count);
}
static void csi_X(struct vc_data *vc, int vpar) /* erase the following vpar positions */
diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c
index 73cdc0d633dd..8b0ed139592f 100644
--- a/drivers/tty/vt/vt_ioctl.c
+++ b/drivers/tty/vt/vt_ioctl.c
@@ -1175,17 +1175,13 @@ long vt_compat_ioctl(struct tty_struct *tty,
{
struct vc_data *vc = tty->driver_data;
struct console_font_op op; /* used in multiple places here */
- unsigned int console;
- void __user *up = (void __user *)arg;
+ unsigned int console = vc->vc_num;
+ void __user *up = compat_ptr(arg);
int perm;
- int ret = 0;
- console = vc->vc_num;
- if (!vc_cons_allocated(console)) { /* impossible? */
- ret = -ENOIOCTLCMD;
- goto out;
- }
+ if (!vc_cons_allocated(console)) /* impossible? */
+ return -ENOIOCTLCMD;
/*
* To have permissions to do most of the vt ioctls, we either have
@@ -1201,17 +1197,14 @@ long vt_compat_ioctl(struct tty_struct *tty,
*/
case PIO_FONTX:
case GIO_FONTX:
- ret = compat_fontx_ioctl(cmd, up, perm, &op);
- break;
+ return compat_fontx_ioctl(cmd, up, perm, &op);
case KDFONTOP:
- ret = compat_kdfontop_ioctl(up, perm, &op, vc);
- break;
+ return compat_kdfontop_ioctl(up, perm, &op, vc);
case PIO_UNIMAP:
case GIO_UNIMAP:
- ret = compat_unimap_ioctl(cmd, up, perm, vc);
- break;
+ return compat_unimap_ioctl(cmd, up, perm, vc);
/*
* all these treat 'arg' as an integer
@@ -1236,21 +1229,15 @@ long vt_compat_ioctl(struct tty_struct *tty,
case VT_DISALLOCATE:
case VT_RESIZE:
case VT_RESIZEX:
- goto fallback;
+ return vt_ioctl(tty, cmd, arg);
/*
* the rest has a compatible data structure behind arg,
* but we have to convert it to a proper 64 bit pointer.
*/
default:
- arg = (unsigned long)compat_ptr(arg);
- goto fallback;
+ return vt_ioctl(tty, cmd, (unsigned long)up);
}
-out:
- return ret;
-
-fallback:
- return vt_ioctl(tty, cmd, arg);
}
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index 70a7981b94b3..85644669fbe7 100644
--- a/drivers/uio/uio.c
+++ b/drivers/uio/uio.c
@@ -274,6 +274,8 @@ static struct class uio_class = {
.dev_groups = uio_groups,
};
+static bool uio_class_registered;
+
/*
* device functions
*/
@@ -668,7 +670,7 @@ static vm_fault_t uio_vma_fault(struct vm_fault *vmf)
struct page *page;
unsigned long offset;
void *addr;
- int ret = 0;
+ vm_fault_t ret = 0;
int mi;
mutex_lock(&idev->info_lock);
@@ -736,7 +738,8 @@ static int uio_mmap_physical(struct vm_area_struct *vma)
return -EINVAL;
vma->vm_ops = &uio_physical_vm_ops;
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ if (idev->info->mem[mi].memtype == UIO_MEM_PHYS)
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
/*
* We cannot use the vm_iomap_memory() helper here,
@@ -793,18 +796,19 @@ static int uio_mmap(struct file *filep, struct vm_area_struct *vma)
}
switch (idev->info->mem[mi].memtype) {
- case UIO_MEM_PHYS:
- ret = uio_mmap_physical(vma);
- break;
- case UIO_MEM_LOGICAL:
- case UIO_MEM_VIRTUAL:
- ret = uio_mmap_logical(vma);
- break;
- default:
- ret = -EINVAL;
+ case UIO_MEM_IOVA:
+ case UIO_MEM_PHYS:
+ ret = uio_mmap_physical(vma);
+ break;
+ case UIO_MEM_LOGICAL:
+ case UIO_MEM_VIRTUAL:
+ ret = uio_mmap_logical(vma);
+ break;
+ default:
+ ret = -EINVAL;
}
-out:
+ out:
mutex_unlock(&idev->info_lock);
return ret;
}
@@ -876,6 +880,9 @@ static int init_uio_class(void)
printk(KERN_ERR "class_register failed for uio\n");
goto err_class_register;
}
+
+ uio_class_registered = true;
+
return 0;
err_class_register:
@@ -886,6 +893,7 @@ exit:
static void release_uio_class(void)
{
+ uio_class_registered = false;
class_unregister(&uio_class);
uio_major_cleanup();
}
@@ -912,6 +920,9 @@ int __uio_register_device(struct module *owner,
struct uio_device *idev;
int ret = 0;
+ if (!uio_class_registered)
+ return -EPROBE_DEFER;
+
if (!parent || !info || !info->name || !info->version)
return -EINVAL;
diff --git a/drivers/uio/uio_dmem_genirq.c b/drivers/uio/uio_dmem_genirq.c
index e1134a4d97f3..003badaef5f3 100644
--- a/drivers/uio/uio_dmem_genirq.c
+++ b/drivers/uio/uio_dmem_genirq.c
@@ -163,7 +163,8 @@ static int uio_dmem_genirq_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "unable to kmalloc\n");
goto bad2;
}
- uioinfo->name = pdev->dev.of_node->name;
+ uioinfo->name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%pOFn",
+ pdev->dev.of_node);
uioinfo->version = "devicetree";
/* Multiple IRQs are not supported */
diff --git a/drivers/uio/uio_fsl_elbc_gpcm.c b/drivers/uio/uio_fsl_elbc_gpcm.c
index bbc17effae5e..9cc37fe07d35 100644
--- a/drivers/uio/uio_fsl_elbc_gpcm.c
+++ b/drivers/uio/uio_fsl_elbc_gpcm.c
@@ -382,8 +382,7 @@ static int uio_fsl_elbc_gpcm_probe(struct platform_device *pdev)
}
/* set all UIO data */
- if (node->name)
- info->mem[0].name = kstrdup(node->name, GFP_KERNEL);
+ info->mem[0].name = kasprintf(GFP_KERNEL, "%pOFn", node);
info->mem[0].addr = res.start;
info->mem[0].size = resource_size(&res);
info->mem[0].memtype = UIO_MEM_PHYS;
diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c
index e401be8321ab..c2493d011225 100644
--- a/drivers/uio/uio_hv_generic.c
+++ b/drivers/uio/uio_hv_generic.c
@@ -17,7 +17,6 @@
* # echo -n "ed963694-e847-4b2a-85af-bc9cfc11d6f3" \
* > /sys/bus/vmbus/drivers/uio_hv_generic/bind
*/
-#define DEBUG 1
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/device.h>
@@ -33,13 +32,13 @@
#include "../hv/hyperv_vmbus.h"
-#define DRIVER_VERSION "0.02.0"
+#define DRIVER_VERSION "0.02.1"
#define DRIVER_AUTHOR "Stephen Hemminger <sthemmin at microsoft.com>"
#define DRIVER_DESC "Generic UIO driver for VMBus devices"
#define HV_RING_SIZE 512 /* pages */
-#define SEND_BUFFER_SIZE (15 * 1024 * 1024)
-#define RECV_BUFFER_SIZE (15 * 1024 * 1024)
+#define SEND_BUFFER_SIZE (16 * 1024 * 1024)
+#define RECV_BUFFER_SIZE (31 * 1024 * 1024)
/*
* List of resources to be mapped to user space
@@ -56,6 +55,7 @@ enum hv_uio_map {
struct hv_uio_private_data {
struct uio_info info;
struct hv_device *device;
+ atomic_t refcnt;
void *recv_buf;
u32 recv_gpadl;
@@ -129,13 +129,12 @@ static int hv_uio_ring_mmap(struct file *filp, struct kobject *kobj,
{
struct vmbus_channel *channel
= container_of(kobj, struct vmbus_channel, kobj);
- struct hv_device *dev = channel->primary_channel->device_obj;
- u16 q_idx = channel->offermsg.offer.sub_channel_index;
+ void *ring_buffer = page_address(channel->ringbuffer_page);
- dev_dbg(&dev->device, "mmap channel %u pages %#lx at %#lx\n",
- q_idx, vma_pages(vma), vma->vm_pgoff);
+ if (channel->state != CHANNEL_OPENED_STATE)
+ return -ENODEV;
- return vm_iomap_memory(vma, virt_to_phys(channel->ringbuffer_pages),
+ return vm_iomap_memory(vma, virt_to_phys(ring_buffer),
channel->ringbuffer_pagecount << PAGE_SHIFT);
}
@@ -176,58 +175,104 @@ hv_uio_new_channel(struct vmbus_channel *new_sc)
}
}
+/* free the reserved buffers for send and receive */
static void
hv_uio_cleanup(struct hv_device *dev, struct hv_uio_private_data *pdata)
{
- if (pdata->send_gpadl)
+ if (pdata->send_gpadl) {
vmbus_teardown_gpadl(dev->channel, pdata->send_gpadl);
- vfree(pdata->send_buf);
+ pdata->send_gpadl = 0;
+ vfree(pdata->send_buf);
+ }
- if (pdata->recv_gpadl)
+ if (pdata->recv_gpadl) {
vmbus_teardown_gpadl(dev->channel, pdata->recv_gpadl);
- vfree(pdata->recv_buf);
+ pdata->recv_gpadl = 0;
+ vfree(pdata->recv_buf);
+ }
+}
+
+/* VMBus primary channel is opened on first use */
+static int
+hv_uio_open(struct uio_info *info, struct inode *inode)
+{
+ struct hv_uio_private_data *pdata
+ = container_of(info, struct hv_uio_private_data, info);
+ struct hv_device *dev = pdata->device;
+ int ret;
+
+ if (atomic_inc_return(&pdata->refcnt) != 1)
+ return 0;
+
+ ret = vmbus_connect_ring(dev->channel,
+ hv_uio_channel_cb, dev->channel);
+
+ if (ret == 0)
+ dev->channel->inbound.ring_buffer->interrupt_mask = 1;
+ else
+ atomic_dec(&pdata->refcnt);
+
+ return ret;
+}
+
+/* VMBus primary channel is closed on last close */
+static int
+hv_uio_release(struct uio_info *info, struct inode *inode)
+{
+ struct hv_uio_private_data *pdata
+ = container_of(info, struct hv_uio_private_data, info);
+ struct hv_device *dev = pdata->device;
+ int ret = 0;
+
+ if (atomic_dec_and_test(&pdata->refcnt))
+ ret = vmbus_disconnect_ring(dev->channel);
+
+ return ret;
}
static int
hv_uio_probe(struct hv_device *dev,
const struct hv_vmbus_device_id *dev_id)
{
+ struct vmbus_channel *channel = dev->channel;
struct hv_uio_private_data *pdata;
+ void *ring_buffer;
int ret;
+ /* Communicating with host has to be via shared memory not hypercall */
+ if (!channel->offermsg.monitor_allocated) {
+ dev_err(&dev->device, "vmbus channel requires hypercall\n");
+ return -ENOTSUPP;
+ }
+
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
- ret = vmbus_open(dev->channel, HV_RING_SIZE * PAGE_SIZE,
- HV_RING_SIZE * PAGE_SIZE, NULL, 0,
- hv_uio_channel_cb, dev->channel);
+ ret = vmbus_alloc_ring(channel, HV_RING_SIZE * PAGE_SIZE,
+ HV_RING_SIZE * PAGE_SIZE);
if (ret)
goto fail;
- /* Communicating with host has to be via shared memory not hypercall */
- if (!dev->channel->offermsg.monitor_allocated) {
- dev_err(&dev->device, "vmbus channel requires hypercall\n");
- ret = -ENOTSUPP;
- goto fail_close;
- }
-
- dev->channel->inbound.ring_buffer->interrupt_mask = 1;
- set_channel_read_mode(dev->channel, HV_CALL_ISR);
+ set_channel_read_mode(channel, HV_CALL_ISR);
/* Fill general uio info */
pdata->info.name = "uio_hv_generic";
pdata->info.version = DRIVER_VERSION;
pdata->info.irqcontrol = hv_uio_irqcontrol;
+ pdata->info.open = hv_uio_open;
+ pdata->info.release = hv_uio_release;
pdata->info.irq = UIO_IRQ_CUSTOM;
+ atomic_set(&pdata->refcnt, 0);
/* mem resources */
pdata->info.mem[TXRX_RING_MAP].name = "txrx_rings";
+ ring_buffer = page_address(channel->ringbuffer_page);
pdata->info.mem[TXRX_RING_MAP].addr
- = (uintptr_t)dev->channel->ringbuffer_pages;
+ = (uintptr_t)virt_to_phys(ring_buffer);
pdata->info.mem[TXRX_RING_MAP].size
- = dev->channel->ringbuffer_pagecount << PAGE_SHIFT;
- pdata->info.mem[TXRX_RING_MAP].memtype = UIO_MEM_LOGICAL;
+ = channel->ringbuffer_pagecount << PAGE_SHIFT;
+ pdata->info.mem[TXRX_RING_MAP].memtype = UIO_MEM_IOVA;
pdata->info.mem[INT_PAGE_MAP].name = "int_page";
pdata->info.mem[INT_PAGE_MAP].addr
@@ -247,7 +292,7 @@ hv_uio_probe(struct hv_device *dev,
goto fail_close;
}
- ret = vmbus_establish_gpadl(dev->channel, pdata->recv_buf,
+ ret = vmbus_establish_gpadl(channel, pdata->recv_buf,
RECV_BUFFER_SIZE, &pdata->recv_gpadl);
if (ret)
goto fail_close;
@@ -261,14 +306,13 @@ hv_uio_probe(struct hv_device *dev,
pdata->info.mem[RECV_BUF_MAP].size = RECV_BUFFER_SIZE;
pdata->info.mem[RECV_BUF_MAP].memtype = UIO_MEM_VIRTUAL;
-
pdata->send_buf = vzalloc(SEND_BUFFER_SIZE);
if (pdata->send_buf == NULL) {
ret = -ENOMEM;
goto fail_close;
}
- ret = vmbus_establish_gpadl(dev->channel, pdata->send_buf,
+ ret = vmbus_establish_gpadl(channel, pdata->send_buf,
SEND_BUFFER_SIZE, &pdata->send_gpadl);
if (ret)
goto fail_close;
@@ -290,10 +334,10 @@ hv_uio_probe(struct hv_device *dev,
goto fail_close;
}
- vmbus_set_chn_rescind_callback(dev->channel, hv_uio_rescind);
- vmbus_set_sc_create_callback(dev->channel, hv_uio_new_channel);
+ vmbus_set_chn_rescind_callback(channel, hv_uio_rescind);
+ vmbus_set_sc_create_callback(channel, hv_uio_new_channel);
- ret = sysfs_create_bin_file(&dev->channel->kobj, &ring_buffer_bin_attr);
+ ret = sysfs_create_bin_file(&channel->kobj, &ring_buffer_bin_attr);
if (ret)
dev_notice(&dev->device,
"sysfs create ring bin file failed; %d\n", ret);
@@ -304,7 +348,6 @@ hv_uio_probe(struct hv_device *dev,
fail_close:
hv_uio_cleanup(dev, pdata);
- vmbus_close(dev->channel);
fail:
kfree(pdata);
@@ -322,7 +365,8 @@ hv_uio_remove(struct hv_device *dev)
uio_unregister_device(&pdata->info);
hv_uio_cleanup(dev, pdata);
hv_set_drvdata(dev, NULL);
- vmbus_close(dev->channel);
+
+ vmbus_free_ring(dev->channel);
kfree(pdata);
return 0;
}
diff --git a/drivers/uio/uio_pdrv_genirq.c b/drivers/uio/uio_pdrv_genirq.c
index f598ecddc8a7..6c759934bff3 100644
--- a/drivers/uio/uio_pdrv_genirq.c
+++ b/drivers/uio/uio_pdrv_genirq.c
@@ -118,7 +118,8 @@ static int uio_pdrv_genirq_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "unable to kmalloc\n");
return -ENOMEM;
}
- uioinfo->name = pdev->dev.of_node->name;
+ uioinfo->name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%pOFn",
+ pdev->dev.of_node);
uioinfo->version = "devicetree";
/* Multiple IRQs are not supported */
}
diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c
index 19f5f5f2a48a..09b37c0d075d 100644
--- a/drivers/usb/chipidea/ci_hdrc_imx.c
+++ b/drivers/usb/chipidea/ci_hdrc_imx.c
@@ -364,8 +364,7 @@ static void ci_hdrc_imx_shutdown(struct platform_device *pdev)
ci_hdrc_imx_remove(pdev);
}
-#ifdef CONFIG_PM
-static int imx_controller_suspend(struct device *dev)
+static int __maybe_unused imx_controller_suspend(struct device *dev)
{
struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
@@ -377,7 +376,7 @@ static int imx_controller_suspend(struct device *dev)
return 0;
}
-static int imx_controller_resume(struct device *dev)
+static int __maybe_unused imx_controller_resume(struct device *dev)
{
struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
int ret = 0;
@@ -408,8 +407,7 @@ clk_disable:
return ret;
}
-#ifdef CONFIG_PM_SLEEP
-static int ci_hdrc_imx_suspend(struct device *dev)
+static int __maybe_unused ci_hdrc_imx_suspend(struct device *dev)
{
int ret;
@@ -431,7 +429,7 @@ static int ci_hdrc_imx_suspend(struct device *dev)
return imx_controller_suspend(dev);
}
-static int ci_hdrc_imx_resume(struct device *dev)
+static int __maybe_unused ci_hdrc_imx_resume(struct device *dev)
{
struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
int ret;
@@ -445,9 +443,8 @@ static int ci_hdrc_imx_resume(struct device *dev)
return ret;
}
-#endif /* CONFIG_PM_SLEEP */
-static int ci_hdrc_imx_runtime_suspend(struct device *dev)
+static int __maybe_unused ci_hdrc_imx_runtime_suspend(struct device *dev)
{
struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
int ret;
@@ -466,13 +463,11 @@ static int ci_hdrc_imx_runtime_suspend(struct device *dev)
return imx_controller_suspend(dev);
}
-static int ci_hdrc_imx_runtime_resume(struct device *dev)
+static int __maybe_unused ci_hdrc_imx_runtime_resume(struct device *dev)
{
return imx_controller_resume(dev);
}
-#endif /* CONFIG_PM */
-
static const struct dev_pm_ops ci_hdrc_imx_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(ci_hdrc_imx_suspend, ci_hdrc_imx_resume)
SET_RUNTIME_PM_OPS(ci_hdrc_imx_runtime_suspend,
@@ -492,7 +487,7 @@ static struct platform_driver ci_hdrc_imx_driver = {
module_platform_driver(ci_hdrc_imx_driver);
MODULE_ALIAS("platform:imx-usb");
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("CI HDRC i.MX USB binding");
MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>");
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 85fc6db48e44..7bfcbb23c2a4 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -53,6 +53,7 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
@@ -723,6 +724,24 @@ static int ci_get_platdata(struct device *dev,
else
cable->connected = false;
}
+
+ platdata->pctl = devm_pinctrl_get(dev);
+ if (!IS_ERR(platdata->pctl)) {
+ struct pinctrl_state *p;
+
+ p = pinctrl_lookup_state(platdata->pctl, "default");
+ if (!IS_ERR(p))
+ platdata->pins_default = p;
+
+ p = pinctrl_lookup_state(platdata->pctl, "host");
+ if (!IS_ERR(p))
+ platdata->pins_host = p;
+
+ p = pinctrl_lookup_state(platdata->pctl, "device");
+ if (!IS_ERR(p))
+ platdata->pins_device = p;
+ }
+
return 0;
}
diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c
index 4638d9b066be..d858a82c4f44 100644
--- a/drivers/usb/chipidea/host.c
+++ b/drivers/usb/chipidea/host.c
@@ -13,6 +13,7 @@
#include <linux/usb/hcd.h>
#include <linux/usb/chipidea.h>
#include <linux/regulator/consumer.h>
+#include <linux/pinctrl/consumer.h>
#include "../host/ehci.h"
@@ -153,6 +154,10 @@ static int host_start(struct ci_hdrc *ci)
}
}
+ if (ci->platdata->pins_host)
+ pinctrl_select_state(ci->platdata->pctl,
+ ci->platdata->pins_host);
+
ret = usb_add_hcd(hcd, 0, 0);
if (ret) {
goto disable_reg;
@@ -197,6 +202,10 @@ static void host_stop(struct ci_hdrc *ci)
}
ci->hcd = NULL;
ci->otg.host = NULL;
+
+ if (ci->platdata->pins_host && ci->platdata->pins_default)
+ pinctrl_select_state(ci->platdata->pctl,
+ ci->platdata->pins_default);
}
diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c
index db4ceffcf2a6..f25d4827fd49 100644
--- a/drivers/usb/chipidea/otg.c
+++ b/drivers/usb/chipidea/otg.c
@@ -203,14 +203,17 @@ static void ci_otg_work(struct work_struct *work)
}
pm_runtime_get_sync(ci->dev);
+
if (ci->id_event) {
ci->id_event = false;
ci_handle_id_switch(ci);
- } else if (ci->b_sess_valid_event) {
+ }
+
+ if (ci->b_sess_valid_event) {
ci->b_sess_valid_event = false;
ci_handle_vbus_change(ci);
- } else
- dev_err(ci->dev, "unexpected event occurs at %s\n", __func__);
+ }
+
pm_runtime_put_sync(ci->dev);
enable_irq(ci->irq);
diff --git a/drivers/usb/chipidea/otg.h b/drivers/usb/chipidea/otg.h
index 7e7428e48bfa..4f8b8179ec96 100644
--- a/drivers/usb/chipidea/otg.h
+++ b/drivers/usb/chipidea/otg.h
@@ -17,7 +17,8 @@ void ci_handle_vbus_change(struct ci_hdrc *ci);
static inline void ci_otg_queue_work(struct ci_hdrc *ci)
{
disable_irq_nosync(ci->irq);
- queue_work(ci->wq, &ci->work);
+ if (queue_work(ci->wq, &ci->work) == false)
+ enable_irq(ci->irq);
}
#endif /* __DRIVERS_USB_CHIPIDEA_OTG_H */
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 9852ec5e6e01..829e947cabf5 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -15,6 +15,7 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/usb/otg-fsm.h>
@@ -1965,6 +1966,10 @@ void ci_hdrc_gadget_destroy(struct ci_hdrc *ci)
static int udc_id_switch_for_device(struct ci_hdrc *ci)
{
+ if (ci->platdata->pins_device)
+ pinctrl_select_state(ci->platdata->pctl,
+ ci->platdata->pins_device);
+
if (ci->is_otg)
/* Clear and enable BSV irq */
hw_write_otgsc(ci, OTGSC_BSVIS | OTGSC_BSVIE,
@@ -1983,6 +1988,10 @@ static void udc_id_switch_for_host(struct ci_hdrc *ci)
hw_write_otgsc(ci, OTGSC_BSVIE | OTGSC_BSVIS, OTGSC_BSVIS);
ci->vbus_active = 0;
+
+ if (ci->platdata->pins_device && ci->platdata->pins_default)
+ pinctrl_select_state(ci->platdata->pctl,
+ ci->platdata->pins_default);
}
/**
diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c
index 34ad5bf8acd8..def80ff547e4 100644
--- a/drivers/usb/chipidea/usbmisc_imx.c
+++ b/drivers/usb/chipidea/usbmisc_imx.c
@@ -343,6 +343,8 @@ static int usbmisc_imx6q_init(struct imx_usbmisc_data *data)
} else if (data->oc_polarity == 1) {
/* High active */
reg &= ~(MX6_BM_OVER_CUR_DIS | MX6_BM_OVER_CUR_POLARITY);
+ } else {
+ reg &= ~(MX6_BM_OVER_CUR_DIS);
}
writel(reg, usbmisc->base + data->index * 4);
@@ -633,6 +635,6 @@ static struct platform_driver usbmisc_imx_driver = {
module_platform_driver(usbmisc_imx_driver);
MODULE_ALIAS("platform:usbmisc-imx");
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("driver for imx usb non-core registers");
MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>");
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index f9b40a9dc4d3..47d75c20c211 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -310,17 +310,17 @@ static void acm_process_notification(struct acm *acm, unsigned char *buf)
if (difference & ACM_CTRL_DSR)
acm->iocount.dsr++;
- if (difference & ACM_CTRL_BRK)
- acm->iocount.brk++;
- if (difference & ACM_CTRL_RI)
- acm->iocount.rng++;
if (difference & ACM_CTRL_DCD)
acm->iocount.dcd++;
- if (difference & ACM_CTRL_FRAMING)
+ if (newctrl & ACM_CTRL_BRK)
+ acm->iocount.brk++;
+ if (newctrl & ACM_CTRL_RI)
+ acm->iocount.rng++;
+ if (newctrl & ACM_CTRL_FRAMING)
acm->iocount.frame++;
- if (difference & ACM_CTRL_PARITY)
+ if (newctrl & ACM_CTRL_PARITY)
acm->iocount.parity++;
- if (difference & ACM_CTRL_OVERRUN)
+ if (newctrl & ACM_CTRL_OVERRUN)
acm->iocount.overrun++;
spin_unlock_irqrestore(&acm->read_lock, flags);
@@ -355,7 +355,6 @@ static void acm_ctrl_irq(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- acm->nb_index = 0;
dev_dbg(&acm->control->dev,
"%s - urb shutting down with status: %d\n",
__func__, status);
@@ -885,37 +884,28 @@ static int acm_tty_tiocmset(struct tty_struct *tty,
return acm_set_control(acm, acm->ctrlout = newctrl);
}
-static int get_serial_info(struct acm *acm, struct serial_struct __user *info)
+static int get_serial_info(struct tty_struct *tty, struct serial_struct *ss)
{
- struct serial_struct tmp;
+ struct acm *acm = tty->driver_data;
- memset(&tmp, 0, sizeof(tmp));
- tmp.xmit_fifo_size = acm->writesize;
- tmp.baud_base = le32_to_cpu(acm->line.dwDTERate);
- tmp.close_delay = acm->port.close_delay / 10;
- tmp.closing_wait = acm->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
+ ss->xmit_fifo_size = acm->writesize;
+ ss->baud_base = le32_to_cpu(acm->line.dwDTERate);
+ ss->close_delay = acm->port.close_delay / 10;
+ ss->closing_wait = acm->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
ASYNC_CLOSING_WAIT_NONE :
acm->port.closing_wait / 10;
-
- if (copy_to_user(info, &tmp, sizeof(tmp)))
- return -EFAULT;
- else
- return 0;
+ return 0;
}
-static int set_serial_info(struct acm *acm,
- struct serial_struct __user *newinfo)
+static int set_serial_info(struct tty_struct *tty, struct serial_struct *ss)
{
- struct serial_struct new_serial;
+ struct acm *acm = tty->driver_data;
unsigned int closing_wait, close_delay;
int retval = 0;
- if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
- return -EFAULT;
-
- close_delay = new_serial.close_delay * 10;
- closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
- ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10;
+ close_delay = ss->close_delay * 10;
+ closing_wait = ss->closing_wait == ASYNC_CLOSING_WAIT_NONE ?
+ ASYNC_CLOSING_WAIT_NONE : ss->closing_wait * 10;
mutex_lock(&acm->port.mutex);
@@ -1000,12 +990,6 @@ static int acm_tty_ioctl(struct tty_struct *tty,
int rv = -ENOIOCTLCMD;
switch (cmd) {
- case TIOCGSERIAL: /* gets serial port data */
- rv = get_serial_info(acm, (struct serial_struct __user *) arg);
- break;
- case TIOCSSERIAL:
- rv = set_serial_info(acm, (struct serial_struct __user *) arg);
- break;
case TIOCMIWAIT:
rv = usb_autopm_get_interface(acm->control);
if (rv < 0) {
@@ -1514,6 +1498,7 @@ static void acm_disconnect(struct usb_interface *intf)
{
struct acm *acm = usb_get_intfdata(intf);
struct tty_struct *tty;
+ int i;
/* sibling interface is already cleaning up */
if (!acm)
@@ -1544,6 +1529,11 @@ static void acm_disconnect(struct usb_interface *intf)
tty_unregister_device(acm_tty_driver, acm->minor);
+ usb_free_urb(acm->ctrlurb);
+ for (i = 0; i < ACM_NW; i++)
+ usb_free_urb(acm->wb[i].urb);
+ for (i = 0; i < acm->rx_buflimit; i++)
+ usb_free_urb(acm->read_urbs[i]);
acm_write_buffers_free(acm);
usb_free_coherent(acm->dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
acm_read_buffers_free(acm);
@@ -1636,6 +1626,7 @@ static int acm_pre_reset(struct usb_interface *intf)
struct acm *acm = usb_get_intfdata(intf);
clear_bit(EVENT_RX_STALL, &acm->flags);
+ acm->nb_index = 0; /* pending control transfers are lost */
return 0;
}
@@ -1925,6 +1916,8 @@ static const struct tty_operations acm_ops = {
.set_termios = acm_tty_set_termios,
.tiocmget = acm_tty_tiocmget,
.tiocmset = acm_tty_tiocmset,
+ .get_serial = get_serial_info,
+ .set_serial = set_serial_info,
.get_icount = acm_tty_get_icount,
};
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 83ffa5a14c3d..4942122b2346 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -5,6 +5,7 @@
* Copyright (C) 2007 Stefan Kopp, Gechingen, Germany
* Copyright (C) 2008 Novell, Inc.
* Copyright (C) 2008 Greg Kroah-Hartman <gregkh@suse.de>
+ * Copyright (C) 2018 IVI Foundation, Inc.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -21,21 +22,24 @@
#include <linux/compat.h>
#include <linux/usb/tmc.h>
+/* Increment API VERSION when changing tmc.h with new flags or ioctls
+ * or when changing a significant behavior of the driver.
+ */
+#define USBTMC_API_VERSION (2)
#define USBTMC_HEADER_SIZE 12
#define USBTMC_MINOR_BASE 176
-/*
- * Size of driver internal IO buffer. Must be multiple of 4 and at least as
- * large as wMaxPacketSize (which is usually 512 bytes).
- */
-#define USBTMC_SIZE_IOBUFFER 2048
-
/* Minimum USB timeout (in milliseconds) */
#define USBTMC_MIN_TIMEOUT 100
/* Default USB timeout (in milliseconds) */
#define USBTMC_TIMEOUT 5000
+/* Max number of urbs used in write transfers */
+#define MAX_URBS_IN_FLIGHT 16
+/* I/O buffer size used in generic read/write functions */
+#define USBTMC_BUFSIZE (4096)
+
/*
* Maximum number of read cycles to empty bulk in endpoint during CLEAR and
* ABORT_BULK_IN requests. Ends the loop if (for whatever reason) a short
@@ -79,6 +83,9 @@ struct usbtmc_device_data {
u8 bTag_last_write; /* needed for abort */
u8 bTag_last_read; /* needed for abort */
+ /* packet size of IN bulk */
+ u16 wMaxPacketSize;
+
/* data for interrupt in endpoint handling */
u8 bNotify1;
u8 bNotify2;
@@ -95,11 +102,6 @@ struct usbtmc_device_data {
/* coalesced usb488_caps from usbtmc_dev_capabilities */
__u8 usb488_caps;
- /* attributes from the USB TMC spec for this device */
- u8 TermChar;
- bool TermCharEnabled;
- bool auto_abort;
-
bool zombie; /* fd of disconnected device */
struct usbtmc_dev_capabilities capabilities;
@@ -121,13 +123,34 @@ struct usbtmc_file_data {
u32 timeout;
u8 srq_byte;
atomic_t srq_asserted;
+ atomic_t closing;
+ u8 bmTransferAttributes; /* member of DEV_DEP_MSG_IN */
+
u8 eom_val;
u8 term_char;
bool term_char_enabled;
+ bool auto_abort;
+
+ spinlock_t err_lock; /* lock for errors */
+
+ struct usb_anchor submitted;
+
+ /* data for generic_write */
+ struct semaphore limit_write_sem;
+ u32 out_transfer_size;
+ int out_status;
+
+ /* data for generic_read */
+ u32 in_transfer_size;
+ int in_status;
+ int in_urbs_used;
+ struct usb_anchor in_anchor;
+ wait_queue_head_t wait_bulk_in;
};
/* Forward declarations */
static struct usb_driver usbtmc_driver;
+static void usbtmc_draw_down(struct usbtmc_file_data *file_data);
static void usbtmc_delete(struct kref *kref)
{
@@ -153,6 +176,12 @@ static int usbtmc_open(struct inode *inode, struct file *filp)
if (!file_data)
return -ENOMEM;
+ spin_lock_init(&file_data->err_lock);
+ sema_init(&file_data->limit_write_sem, MAX_URBS_IN_FLIGHT);
+ init_usb_anchor(&file_data->submitted);
+ init_usb_anchor(&file_data->in_anchor);
+ init_waitqueue_head(&file_data->wait_bulk_in);
+
data = usb_get_intfdata(intf);
/* Protect reference to data from file structure until release */
kref_get(&data->kref);
@@ -160,10 +189,12 @@ static int usbtmc_open(struct inode *inode, struct file *filp)
mutex_lock(&data->io_mutex);
file_data->data = data;
- /* copy default values from device settings */
+ atomic_set(&file_data->closing, 0);
+
file_data->timeout = USBTMC_TIMEOUT;
- file_data->term_char = data->TermChar;
- file_data->term_char_enabled = data->TermCharEnabled;
+ file_data->term_char = '\n';
+ file_data->term_char_enabled = 0;
+ file_data->auto_abort = 0;
file_data->eom_val = 1;
INIT_LIST_HEAD(&file_data->file_elem);
@@ -178,6 +209,40 @@ static int usbtmc_open(struct inode *inode, struct file *filp)
return 0;
}
+/*
+ * usbtmc_flush - called before file handle is closed
+ */
+static int usbtmc_flush(struct file *file, fl_owner_t id)
+{
+ struct usbtmc_file_data *file_data;
+ struct usbtmc_device_data *data;
+
+ file_data = file->private_data;
+ if (file_data == NULL)
+ return -ENODEV;
+
+ atomic_set(&file_data->closing, 1);
+ data = file_data->data;
+
+ /* wait for io to stop */
+ mutex_lock(&data->io_mutex);
+
+ usbtmc_draw_down(file_data);
+
+ spin_lock_irq(&file_data->err_lock);
+ file_data->in_status = 0;
+ file_data->in_transfer_size = 0;
+ file_data->in_urbs_used = 0;
+ file_data->out_status = 0;
+ file_data->out_transfer_size = 0;
+ spin_unlock_irq(&file_data->err_lock);
+
+ wake_up_interruptible_all(&data->waitq);
+ mutex_unlock(&data->io_mutex);
+
+ return 0;
+}
+
static int usbtmc_release(struct inode *inode, struct file *file)
{
struct usbtmc_file_data *file_data = file->private_data;
@@ -197,18 +262,17 @@ static int usbtmc_release(struct inode *inode, struct file *file)
return 0;
}
-static int usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data *data)
+static int usbtmc_ioctl_abort_bulk_in_tag(struct usbtmc_device_data *data,
+ u8 tag)
{
u8 *buffer;
struct device *dev;
int rv;
int n;
int actual;
- struct usb_host_interface *current_setting;
- int max_size;
dev = &data->intf->dev;
- buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL);
+ buffer = kmalloc(USBTMC_BUFSIZE, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
@@ -216,86 +280,88 @@ static int usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data *data)
usb_rcvctrlpipe(data->usb_dev, 0),
USBTMC_REQUEST_INITIATE_ABORT_BULK_IN,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
- data->bTag_last_read, data->bulk_in,
- buffer, 2, USBTMC_TIMEOUT);
+ tag, data->bulk_in,
+ buffer, 2, USB_CTRL_GET_TIMEOUT);
if (rv < 0) {
dev_err(dev, "usb_control_msg returned %d\n", rv);
goto exit;
}
- dev_dbg(dev, "INITIATE_ABORT_BULK_IN returned %x\n", buffer[0]);
+ dev_dbg(dev, "INITIATE_ABORT_BULK_IN returned %x with tag %02x\n",
+ buffer[0], buffer[1]);
if (buffer[0] == USBTMC_STATUS_FAILED) {
+ /* No transfer in progress and the Bulk-OUT FIFO is empty. */
rv = 0;
goto exit;
}
- if (buffer[0] != USBTMC_STATUS_SUCCESS) {
- dev_err(dev, "INITIATE_ABORT_BULK_IN returned %x\n",
- buffer[0]);
- rv = -EPERM;
+ if (buffer[0] == USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS) {
+ /* The device returns this status if either:
+ * - There is a transfer in progress, but the specified bTag
+ * does not match.
+ * - There is no transfer in progress, but the Bulk-OUT FIFO
+ * is not empty.
+ */
+ rv = -ENOMSG;
goto exit;
}
- max_size = 0;
- current_setting = data->intf->cur_altsetting;
- for (n = 0; n < current_setting->desc.bNumEndpoints; n++)
- if (current_setting->endpoint[n].desc.bEndpointAddress ==
- data->bulk_in)
- max_size = usb_endpoint_maxp(&current_setting->endpoint[n].desc);
-
- if (max_size == 0) {
- dev_err(dev, "Couldn't get wMaxPacketSize\n");
+ if (buffer[0] != USBTMC_STATUS_SUCCESS) {
+ dev_err(dev, "INITIATE_ABORT_BULK_IN returned %x\n",
+ buffer[0]);
rv = -EPERM;
goto exit;
}
- dev_dbg(&data->intf->dev, "wMaxPacketSize is %d\n", max_size);
-
n = 0;
- do {
- dev_dbg(dev, "Reading from bulk in EP\n");
+usbtmc_abort_bulk_in_status:
+ dev_dbg(dev, "Reading from bulk in EP\n");
- rv = usb_bulk_msg(data->usb_dev,
- usb_rcvbulkpipe(data->usb_dev,
- data->bulk_in),
- buffer, USBTMC_SIZE_IOBUFFER,
- &actual, USBTMC_TIMEOUT);
+ /* Data must be present. So use low timeout 300 ms */
+ actual = 0;
+ rv = usb_bulk_msg(data->usb_dev,
+ usb_rcvbulkpipe(data->usb_dev,
+ data->bulk_in),
+ buffer, USBTMC_BUFSIZE,
+ &actual, 300);
- n++;
+ print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE, 16, 1,
+ buffer, actual, true);
- if (rv < 0) {
- dev_err(dev, "usb_bulk_msg returned %d\n", rv);
+ n++;
+
+ if (rv < 0) {
+ dev_err(dev, "usb_bulk_msg returned %d\n", rv);
+ if (rv != -ETIMEDOUT)
goto exit;
- }
- } while ((actual == max_size) &&
- (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN));
+ }
- if (actual == max_size) {
+ if (actual == USBTMC_BUFSIZE)
+ goto usbtmc_abort_bulk_in_status;
+
+ if (n >= USBTMC_MAX_READS_TO_CLEAR_BULK_IN) {
dev_err(dev, "Couldn't clear device buffer within %d cycles\n",
USBTMC_MAX_READS_TO_CLEAR_BULK_IN);
rv = -EPERM;
goto exit;
}
- n = 0;
-
-usbtmc_abort_bulk_in_status:
rv = usb_control_msg(data->usb_dev,
usb_rcvctrlpipe(data->usb_dev, 0),
USBTMC_REQUEST_CHECK_ABORT_BULK_IN_STATUS,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
0, data->bulk_in, buffer, 0x08,
- USBTMC_TIMEOUT);
+ USB_CTRL_GET_TIMEOUT);
if (rv < 0) {
dev_err(dev, "usb_control_msg returned %d\n", rv);
goto exit;
}
- dev_dbg(dev, "INITIATE_ABORT_BULK_IN returned %x\n", buffer[0]);
+ dev_dbg(dev, "CHECK_ABORT_BULK_IN returned %x\n", buffer[0]);
if (buffer[0] == USBTMC_STATUS_SUCCESS) {
rv = 0;
@@ -303,46 +369,30 @@ usbtmc_abort_bulk_in_status:
}
if (buffer[0] != USBTMC_STATUS_PENDING) {
- dev_err(dev, "INITIATE_ABORT_BULK_IN returned %x\n", buffer[0]);
+ dev_err(dev, "CHECK_ABORT_BULK_IN returned %x\n", buffer[0]);
rv = -EPERM;
goto exit;
}
- if (buffer[1] == 1)
- do {
- dev_dbg(dev, "Reading from bulk in EP\n");
-
- rv = usb_bulk_msg(data->usb_dev,
- usb_rcvbulkpipe(data->usb_dev,
- data->bulk_in),
- buffer, USBTMC_SIZE_IOBUFFER,
- &actual, USBTMC_TIMEOUT);
-
- n++;
-
- if (rv < 0) {
- dev_err(dev, "usb_bulk_msg returned %d\n", rv);
- goto exit;
- }
- } while ((actual == max_size) &&
- (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN));
-
- if (actual == max_size) {
- dev_err(dev, "Couldn't clear device buffer within %d cycles\n",
- USBTMC_MAX_READS_TO_CLEAR_BULK_IN);
- rv = -EPERM;
- goto exit;
+ if ((buffer[1] & 1) > 0) {
+ /* The device has 1 or more queued packets the Host can read */
+ goto usbtmc_abort_bulk_in_status;
}
- goto usbtmc_abort_bulk_in_status;
-
+ /* The Host must send CHECK_ABORT_BULK_IN_STATUS at a later time. */
+ rv = -EAGAIN;
exit:
kfree(buffer);
return rv;
+}
+static int usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data *data)
+{
+ return usbtmc_ioctl_abort_bulk_in_tag(data, data->bTag_last_read);
}
-static int usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data *data)
+static int usbtmc_ioctl_abort_bulk_out_tag(struct usbtmc_device_data *data,
+ u8 tag)
{
struct device *dev;
u8 *buffer;
@@ -359,8 +409,8 @@ static int usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data *data)
usb_rcvctrlpipe(data->usb_dev, 0),
USBTMC_REQUEST_INITIATE_ABORT_BULK_OUT,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
- data->bTag_last_write, data->bulk_out,
- buffer, 2, USBTMC_TIMEOUT);
+ tag, data->bulk_out,
+ buffer, 2, USB_CTRL_GET_TIMEOUT);
if (rv < 0) {
dev_err(dev, "usb_control_msg returned %d\n", rv);
@@ -379,12 +429,14 @@ static int usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data *data)
n = 0;
usbtmc_abort_bulk_out_check_status:
+ /* do not stress device with subsequent requests */
+ msleep(50);
rv = usb_control_msg(data->usb_dev,
usb_rcvctrlpipe(data->usb_dev, 0),
USBTMC_REQUEST_CHECK_ABORT_BULK_OUT_STATUS,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
0, data->bulk_out, buffer, 0x08,
- USBTMC_TIMEOUT);
+ USB_CTRL_GET_TIMEOUT);
n++;
if (rv < 0) {
dev_err(dev, "usb_control_msg returned %d\n", rv);
@@ -418,6 +470,11 @@ exit:
return rv;
}
+static int usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data *data)
+{
+ return usbtmc_ioctl_abort_bulk_out_tag(data, data->bTag_last_write);
+}
+
static int usbtmc488_ioctl_read_stb(struct usbtmc_file_data *file_data,
void __user *arg)
{
@@ -457,7 +514,7 @@ static int usbtmc488_ioctl_read_stb(struct usbtmc_file_data *file_data,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
data->iin_bTag,
data->ifnum,
- buffer, 0x03, USBTMC_TIMEOUT);
+ buffer, 0x03, USB_CTRL_GET_TIMEOUT);
if (rv < 0) {
dev_err(dev, "stb usb_control_msg returned %d\n", rv);
goto exit;
@@ -510,6 +567,54 @@ static int usbtmc488_ioctl_read_stb(struct usbtmc_file_data *file_data,
return rv;
}
+static int usbtmc488_ioctl_wait_srq(struct usbtmc_file_data *file_data,
+ __u32 __user *arg)
+{
+ struct usbtmc_device_data *data = file_data->data;
+ struct device *dev = &data->intf->dev;
+ int rv;
+ u32 timeout;
+ unsigned long expire;
+
+ if (!data->iin_ep_present) {
+ dev_dbg(dev, "no interrupt endpoint present\n");
+ return -EFAULT;
+ }
+
+ if (get_user(timeout, arg))
+ return -EFAULT;
+
+ expire = msecs_to_jiffies(timeout);
+
+ mutex_unlock(&data->io_mutex);
+
+ rv = wait_event_interruptible_timeout(
+ data->waitq,
+ atomic_read(&file_data->srq_asserted) != 0 ||
+ atomic_read(&file_data->closing),
+ expire);
+
+ mutex_lock(&data->io_mutex);
+
+ /* Note! disconnect or close could be called in the meantime */
+ if (atomic_read(&file_data->closing) || data->zombie)
+ rv = -ENODEV;
+
+ if (rv < 0) {
+ /* dev can be invalid now! */
+ pr_debug("%s - wait interrupted %d\n", __func__, rv);
+ return rv;
+ }
+
+ if (rv == 0) {
+ dev_dbg(dev, "%s - wait timed out\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ dev_dbg(dev, "%s - srq asserted\n", __func__);
+ return 0;
+}
+
static int usbtmc488_ioctl_simple(struct usbtmc_device_data *data,
void __user *arg, unsigned int cmd)
{
@@ -543,7 +648,7 @@ static int usbtmc488_ioctl_simple(struct usbtmc_device_data *data,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
wValue,
data->ifnum,
- buffer, 0x01, USBTMC_TIMEOUT);
+ buffer, 0x01, USB_CTRL_GET_TIMEOUT);
if (rv < 0) {
dev_err(dev, "simple usb_control_msg failed %d\n", rv);
goto exit;
@@ -610,6 +715,559 @@ static int usbtmc488_ioctl_trigger(struct usbtmc_file_data *file_data)
return 0;
}
+static struct urb *usbtmc_create_urb(void)
+{
+ const size_t bufsize = USBTMC_BUFSIZE;
+ u8 *dmabuf = NULL;
+ struct urb *urb = usb_alloc_urb(0, GFP_KERNEL);
+
+ if (!urb)
+ return NULL;
+
+ dmabuf = kmalloc(bufsize, GFP_KERNEL);
+ if (!dmabuf) {
+ usb_free_urb(urb);
+ return NULL;
+ }
+
+ urb->transfer_buffer = dmabuf;
+ urb->transfer_buffer_length = bufsize;
+ urb->transfer_flags |= URB_FREE_BUFFER;
+ return urb;
+}
+
+static void usbtmc_read_bulk_cb(struct urb *urb)
+{
+ struct usbtmc_file_data *file_data = urb->context;
+ int status = urb->status;
+ unsigned long flags;
+
+ /* sync/async unlink faults aren't errors */
+ if (status) {
+ if (!(/* status == -ENOENT || */
+ status == -ECONNRESET ||
+ status == -EREMOTEIO || /* Short packet */
+ status == -ESHUTDOWN))
+ dev_err(&file_data->data->intf->dev,
+ "%s - nonzero read bulk status received: %d\n",
+ __func__, status);
+
+ spin_lock_irqsave(&file_data->err_lock, flags);
+ if (!file_data->in_status)
+ file_data->in_status = status;
+ spin_unlock_irqrestore(&file_data->err_lock, flags);
+ }
+
+ spin_lock_irqsave(&file_data->err_lock, flags);
+ file_data->in_transfer_size += urb->actual_length;
+ dev_dbg(&file_data->data->intf->dev,
+ "%s - total size: %u current: %d status: %d\n",
+ __func__, file_data->in_transfer_size,
+ urb->actual_length, status);
+ spin_unlock_irqrestore(&file_data->err_lock, flags);
+ usb_anchor_urb(urb, &file_data->in_anchor);
+
+ wake_up_interruptible(&file_data->wait_bulk_in);
+ wake_up_interruptible(&file_data->data->waitq);
+}
+
+static inline bool usbtmc_do_transfer(struct usbtmc_file_data *file_data)
+{
+ bool data_or_error;
+
+ spin_lock_irq(&file_data->err_lock);
+ data_or_error = !usb_anchor_empty(&file_data->in_anchor)
+ || file_data->in_status;
+ spin_unlock_irq(&file_data->err_lock);
+ dev_dbg(&file_data->data->intf->dev, "%s: returns %d\n", __func__,
+ data_or_error);
+ return data_or_error;
+}
+
+static ssize_t usbtmc_generic_read(struct usbtmc_file_data *file_data,
+ void __user *user_buffer,
+ u32 transfer_size,
+ u32 *transferred,
+ u32 flags)
+{
+ struct usbtmc_device_data *data = file_data->data;
+ struct device *dev = &data->intf->dev;
+ u32 done = 0;
+ u32 remaining;
+ const u32 bufsize = USBTMC_BUFSIZE;
+ int retval = 0;
+ u32 max_transfer_size;
+ unsigned long expire;
+ int bufcount = 1;
+ int again = 0;
+
+ /* mutex already locked */
+
+ *transferred = done;
+
+ max_transfer_size = transfer_size;
+
+ if (flags & USBTMC_FLAG_IGNORE_TRAILER) {
+ /* The device may send extra alignment bytes (up to
+ * wMaxPacketSize – 1) to avoid sending a zero-length
+ * packet
+ */
+ remaining = transfer_size;
+ if ((max_transfer_size % data->wMaxPacketSize) == 0)
+ max_transfer_size += (data->wMaxPacketSize - 1);
+ } else {
+ /* round down to bufsize to avoid truncated data left */
+ if (max_transfer_size > bufsize) {
+ max_transfer_size =
+ roundup(max_transfer_size + 1 - bufsize,
+ bufsize);
+ }
+ remaining = max_transfer_size;
+ }
+
+ spin_lock_irq(&file_data->err_lock);
+
+ if (file_data->in_status) {
+ /* return the very first error */
+ retval = file_data->in_status;
+ spin_unlock_irq(&file_data->err_lock);
+ goto error;
+ }
+
+ if (flags & USBTMC_FLAG_ASYNC) {
+ if (usb_anchor_empty(&file_data->in_anchor))
+ again = 1;
+
+ if (file_data->in_urbs_used == 0) {
+ file_data->in_transfer_size = 0;
+ file_data->in_status = 0;
+ }
+ } else {
+ file_data->in_transfer_size = 0;
+ file_data->in_status = 0;
+ }
+
+ if (max_transfer_size == 0) {
+ bufcount = 0;
+ } else {
+ bufcount = roundup(max_transfer_size, bufsize) / bufsize;
+ if (bufcount > file_data->in_urbs_used)
+ bufcount -= file_data->in_urbs_used;
+ else
+ bufcount = 0;
+
+ if (bufcount + file_data->in_urbs_used > MAX_URBS_IN_FLIGHT) {
+ bufcount = MAX_URBS_IN_FLIGHT -
+ file_data->in_urbs_used;
+ }
+ }
+ spin_unlock_irq(&file_data->err_lock);
+
+ dev_dbg(dev, "%s: requested=%u flags=0x%X size=%u bufs=%d used=%d\n",
+ __func__, transfer_size, flags,
+ max_transfer_size, bufcount, file_data->in_urbs_used);
+
+ while (bufcount > 0) {
+ u8 *dmabuf = NULL;
+ struct urb *urb = usbtmc_create_urb();
+
+ if (!urb) {
+ retval = -ENOMEM;
+ goto error;
+ }
+
+ dmabuf = urb->transfer_buffer;
+
+ usb_fill_bulk_urb(urb, data->usb_dev,
+ usb_rcvbulkpipe(data->usb_dev, data->bulk_in),
+ dmabuf, bufsize,
+ usbtmc_read_bulk_cb, file_data);
+
+ usb_anchor_urb(urb, &file_data->submitted);
+ retval = usb_submit_urb(urb, GFP_KERNEL);
+ /* urb is anchored. We can release our reference. */
+ usb_free_urb(urb);
+ if (unlikely(retval)) {
+ usb_unanchor_urb(urb);
+ goto error;
+ }
+ file_data->in_urbs_used++;
+ bufcount--;
+ }
+
+ if (again) {
+ dev_dbg(dev, "%s: ret=again\n", __func__);
+ return -EAGAIN;
+ }
+
+ if (user_buffer == NULL)
+ return -EINVAL;
+
+ expire = msecs_to_jiffies(file_data->timeout);
+
+ while (max_transfer_size > 0) {
+ u32 this_part;
+ struct urb *urb = NULL;
+
+ if (!(flags & USBTMC_FLAG_ASYNC)) {
+ dev_dbg(dev, "%s: before wait time %lu\n",
+ __func__, expire);
+ retval = wait_event_interruptible_timeout(
+ file_data->wait_bulk_in,
+ usbtmc_do_transfer(file_data),
+ expire);
+
+ dev_dbg(dev, "%s: wait returned %d\n",
+ __func__, retval);
+
+ if (retval <= 0) {
+ if (retval == 0)
+ retval = -ETIMEDOUT;
+ goto error;
+ }
+ }
+
+ urb = usb_get_from_anchor(&file_data->in_anchor);
+ if (!urb) {
+ if (!(flags & USBTMC_FLAG_ASYNC)) {
+ /* synchronous case: must not happen */
+ retval = -EFAULT;
+ goto error;
+ }
+
+ /* asynchronous case: ready, do not block or wait */
+ *transferred = done;
+ dev_dbg(dev, "%s: (async) done=%u ret=0\n",
+ __func__, done);
+ return 0;
+ }
+
+ file_data->in_urbs_used--;
+
+ if (max_transfer_size > urb->actual_length)
+ max_transfer_size -= urb->actual_length;
+ else
+ max_transfer_size = 0;
+
+ if (remaining > urb->actual_length)
+ this_part = urb->actual_length;
+ else
+ this_part = remaining;
+
+ print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE, 16, 1,
+ urb->transfer_buffer, urb->actual_length, true);
+
+ if (copy_to_user(user_buffer + done,
+ urb->transfer_buffer, this_part)) {
+ usb_free_urb(urb);
+ retval = -EFAULT;
+ goto error;
+ }
+
+ remaining -= this_part;
+ done += this_part;
+
+ spin_lock_irq(&file_data->err_lock);
+ if (urb->status) {
+ /* return the very first error */
+ retval = file_data->in_status;
+ spin_unlock_irq(&file_data->err_lock);
+ usb_free_urb(urb);
+ goto error;
+ }
+ spin_unlock_irq(&file_data->err_lock);
+
+ if (urb->actual_length < bufsize) {
+ /* short packet or ZLP received => ready */
+ usb_free_urb(urb);
+ retval = 1;
+ break;
+ }
+
+ if (!(flags & USBTMC_FLAG_ASYNC) &&
+ max_transfer_size > (bufsize * file_data->in_urbs_used)) {
+ /* resubmit, since other buffers still not enough */
+ usb_anchor_urb(urb, &file_data->submitted);
+ retval = usb_submit_urb(urb, GFP_KERNEL);
+ if (unlikely(retval)) {
+ usb_unanchor_urb(urb);
+ usb_free_urb(urb);
+ goto error;
+ }
+ file_data->in_urbs_used++;
+ }
+ usb_free_urb(urb);
+ retval = 0;
+ }
+
+error:
+ *transferred = done;
+
+ dev_dbg(dev, "%s: before kill\n", __func__);
+ /* Attention: killing urbs can take long time (2 ms) */
+ usb_kill_anchored_urbs(&file_data->submitted);
+ dev_dbg(dev, "%s: after kill\n", __func__);
+ usb_scuttle_anchored_urbs(&file_data->in_anchor);
+ file_data->in_urbs_used = 0;
+ file_data->in_status = 0; /* no spinlock needed here */
+ dev_dbg(dev, "%s: done=%u ret=%d\n", __func__, done, retval);
+
+ return retval;
+}
+
+static ssize_t usbtmc_ioctl_generic_read(struct usbtmc_file_data *file_data,
+ void __user *arg)
+{
+ struct usbtmc_message msg;
+ ssize_t retval = 0;
+
+ /* mutex already locked */
+
+ if (copy_from_user(&msg, arg, sizeof(struct usbtmc_message)))
+ return -EFAULT;
+
+ retval = usbtmc_generic_read(file_data, msg.message,
+ msg.transfer_size, &msg.transferred,
+ msg.flags);
+
+ if (put_user(msg.transferred,
+ &((struct usbtmc_message __user *)arg)->transferred))
+ return -EFAULT;
+
+ return retval;
+}
+
+static void usbtmc_write_bulk_cb(struct urb *urb)
+{
+ struct usbtmc_file_data *file_data = urb->context;
+ int wakeup = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&file_data->err_lock, flags);
+ file_data->out_transfer_size += urb->actual_length;
+
+ /* sync/async unlink faults aren't errors */
+ if (urb->status) {
+ if (!(urb->status == -ENOENT ||
+ urb->status == -ECONNRESET ||
+ urb->status == -ESHUTDOWN))
+ dev_err(&file_data->data->intf->dev,
+ "%s - nonzero write bulk status received: %d\n",
+ __func__, urb->status);
+
+ if (!file_data->out_status) {
+ file_data->out_status = urb->status;
+ wakeup = 1;
+ }
+ }
+ spin_unlock_irqrestore(&file_data->err_lock, flags);
+
+ dev_dbg(&file_data->data->intf->dev,
+ "%s - write bulk total size: %u\n",
+ __func__, file_data->out_transfer_size);
+
+ up(&file_data->limit_write_sem);
+ if (usb_anchor_empty(&file_data->submitted) || wakeup)
+ wake_up_interruptible(&file_data->data->waitq);
+}
+
+static ssize_t usbtmc_generic_write(struct usbtmc_file_data *file_data,
+ const void __user *user_buffer,
+ u32 transfer_size,
+ u32 *transferred,
+ u32 flags)
+{
+ struct usbtmc_device_data *data = file_data->data;
+ struct device *dev;
+ u32 done = 0;
+ u32 remaining;
+ unsigned long expire;
+ const u32 bufsize = USBTMC_BUFSIZE;
+ struct urb *urb = NULL;
+ int retval = 0;
+ u32 timeout;
+
+ *transferred = 0;
+
+ /* Get pointer to private data structure */
+ dev = &data->intf->dev;
+
+ dev_dbg(dev, "%s: size=%u flags=0x%X sema=%u\n",
+ __func__, transfer_size, flags,
+ file_data->limit_write_sem.count);
+
+ if (flags & USBTMC_FLAG_APPEND) {
+ spin_lock_irq(&file_data->err_lock);
+ retval = file_data->out_status;
+ spin_unlock_irq(&file_data->err_lock);
+ if (retval < 0)
+ return retval;
+ } else {
+ spin_lock_irq(&file_data->err_lock);
+ file_data->out_transfer_size = 0;
+ file_data->out_status = 0;
+ spin_unlock_irq(&file_data->err_lock);
+ }
+
+ remaining = transfer_size;
+ if (remaining > INT_MAX)
+ remaining = INT_MAX;
+
+ timeout = file_data->timeout;
+ expire = msecs_to_jiffies(timeout);
+
+ while (remaining > 0) {
+ u32 this_part, aligned;
+ u8 *buffer = NULL;
+
+ if (flags & USBTMC_FLAG_ASYNC) {
+ if (down_trylock(&file_data->limit_write_sem)) {
+ retval = (done)?(0):(-EAGAIN);
+ goto exit;
+ }
+ } else {
+ retval = down_timeout(&file_data->limit_write_sem,
+ expire);
+ if (retval < 0) {
+ retval = -ETIMEDOUT;
+ goto error;
+ }
+ }
+
+ spin_lock_irq(&file_data->err_lock);
+ retval = file_data->out_status;
+ spin_unlock_irq(&file_data->err_lock);
+ if (retval < 0) {
+ up(&file_data->limit_write_sem);
+ goto error;
+ }
+
+ /* prepare next urb to send */
+ urb = usbtmc_create_urb();
+ if (!urb) {
+ retval = -ENOMEM;
+ up(&file_data->limit_write_sem);
+ goto error;
+ }
+ buffer = urb->transfer_buffer;
+
+ if (remaining > bufsize)
+ this_part = bufsize;
+ else
+ this_part = remaining;
+
+ if (copy_from_user(buffer, user_buffer + done, this_part)) {
+ retval = -EFAULT;
+ up(&file_data->limit_write_sem);
+ goto error;
+ }
+
+ print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE,
+ 16, 1, buffer, this_part, true);
+
+ /* fill bulk with 32 bit alignment to meet USBTMC specification
+ * (size + 3 & ~3) rounds up and simplifies user code
+ */
+ aligned = (this_part + 3) & ~3;
+ dev_dbg(dev, "write(size:%u align:%u done:%u)\n",
+ (unsigned int)this_part,
+ (unsigned int)aligned,
+ (unsigned int)done);
+
+ usb_fill_bulk_urb(urb, data->usb_dev,
+ usb_sndbulkpipe(data->usb_dev, data->bulk_out),
+ urb->transfer_buffer, aligned,
+ usbtmc_write_bulk_cb, file_data);
+
+ usb_anchor_urb(urb, &file_data->submitted);
+ retval = usb_submit_urb(urb, GFP_KERNEL);
+ if (unlikely(retval)) {
+ usb_unanchor_urb(urb);
+ up(&file_data->limit_write_sem);
+ goto error;
+ }
+
+ usb_free_urb(urb);
+ urb = NULL; /* urb will be finally released by usb driver */
+
+ remaining -= this_part;
+ done += this_part;
+ }
+
+ /* All urbs are on the fly */
+ if (!(flags & USBTMC_FLAG_ASYNC)) {
+ if (!usb_wait_anchor_empty_timeout(&file_data->submitted,
+ timeout)) {
+ retval = -ETIMEDOUT;
+ goto error;
+ }
+ }
+
+ retval = 0;
+ goto exit;
+
+error:
+ usb_kill_anchored_urbs(&file_data->submitted);
+exit:
+ usb_free_urb(urb);
+
+ spin_lock_irq(&file_data->err_lock);
+ if (!(flags & USBTMC_FLAG_ASYNC))
+ done = file_data->out_transfer_size;
+ if (!retval && file_data->out_status)
+ retval = file_data->out_status;
+ spin_unlock_irq(&file_data->err_lock);
+
+ *transferred = done;
+
+ dev_dbg(dev, "%s: done=%u, retval=%d, urbstat=%d\n",
+ __func__, done, retval, file_data->out_status);
+
+ return retval;
+}
+
+static ssize_t usbtmc_ioctl_generic_write(struct usbtmc_file_data *file_data,
+ void __user *arg)
+{
+ struct usbtmc_message msg;
+ ssize_t retval = 0;
+
+ /* mutex already locked */
+
+ if (copy_from_user(&msg, arg, sizeof(struct usbtmc_message)))
+ return -EFAULT;
+
+ retval = usbtmc_generic_write(file_data, msg.message,
+ msg.transfer_size, &msg.transferred,
+ msg.flags);
+
+ if (put_user(msg.transferred,
+ &((struct usbtmc_message __user *)arg)->transferred))
+ return -EFAULT;
+
+ return retval;
+}
+
+/*
+ * Get the generic write result
+ */
+static ssize_t usbtmc_ioctl_write_result(struct usbtmc_file_data *file_data,
+ void __user *arg)
+{
+ u32 transferred;
+ int retval;
+
+ spin_lock_irq(&file_data->err_lock);
+ transferred = file_data->out_transfer_size;
+ retval = file_data->out_status;
+ spin_unlock_irq(&file_data->err_lock);
+
+ if (put_user(transferred, (__u32 __user *)arg))
+ return -EFAULT;
+
+ return retval;
+}
+
/*
* Sends a REQUEST_DEV_DEP_MSG_IN message on the Bulk-OUT endpoint.
* @transfer_size: number of bytes to request from the device.
@@ -619,7 +1277,7 @@ static int usbtmc488_ioctl_trigger(struct usbtmc_file_data *file_data)
* Also updates bTag_last_write.
*/
static int send_request_dev_dep_msg_in(struct usbtmc_file_data *file_data,
- size_t transfer_size)
+ u32 transfer_size)
{
struct usbtmc_device_data *data = file_data->data;
int retval;
@@ -662,12 +1320,11 @@ static int send_request_dev_dep_msg_in(struct usbtmc_file_data *file_data,
data->bTag++;
kfree(buffer);
- if (retval < 0) {
- dev_err(&data->intf->dev, "usb_bulk_msg in send_request_dev_dep_msg_in() returned %d\n", retval);
- return retval;
- }
+ if (retval < 0)
+ dev_err(&data->intf->dev, "%s returned %d\n",
+ __func__, retval);
- return 0;
+ return retval;
}
static ssize_t usbtmc_read(struct file *filp, char __user *buf,
@@ -676,20 +1333,20 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
struct usbtmc_file_data *file_data;
struct usbtmc_device_data *data;
struct device *dev;
+ const u32 bufsize = USBTMC_BUFSIZE;
u32 n_characters;
u8 *buffer;
int actual;
- size_t done;
- size_t remaining;
+ u32 done = 0;
+ u32 remaining;
int retval;
- size_t this_part;
/* Get pointer to private data structure */
file_data = filp->private_data;
data = file_data->data;
dev = &data->intf->dev;
- buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL);
+ buffer = kmalloc(bufsize, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
@@ -699,124 +1356,116 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
goto exit;
}
- dev_dbg(dev, "usb_bulk_msg_in: count(%zu)\n", count);
+ if (count > INT_MAX)
+ count = INT_MAX;
+
+ dev_dbg(dev, "%s(count:%zu)\n", __func__, count);
retval = send_request_dev_dep_msg_in(file_data, count);
if (retval < 0) {
- if (data->auto_abort)
+ if (file_data->auto_abort)
usbtmc_ioctl_abort_bulk_out(data);
goto exit;
}
/* Loop until we have fetched everything we requested */
remaining = count;
- this_part = remaining;
- done = 0;
+ actual = 0;
- while (remaining > 0) {
- /* Send bulk URB */
- retval = usb_bulk_msg(data->usb_dev,
- usb_rcvbulkpipe(data->usb_dev,
- data->bulk_in),
- buffer, USBTMC_SIZE_IOBUFFER, &actual,
- file_data->timeout);
-
- dev_dbg(dev, "usb_bulk_msg: retval(%u), done(%zu), remaining(%zu), actual(%d)\n", retval, done, remaining, actual);
+ /* Send bulk URB */
+ retval = usb_bulk_msg(data->usb_dev,
+ usb_rcvbulkpipe(data->usb_dev,
+ data->bulk_in),
+ buffer, bufsize, &actual,
+ file_data->timeout);
- /* Store bTag (in case we need to abort) */
- data->bTag_last_read = data->bTag;
+ dev_dbg(dev, "%s: bulk_msg retval(%u), actual(%d)\n",
+ __func__, retval, actual);
- if (retval < 0) {
- dev_dbg(dev, "Unable to read data, error %d\n", retval);
- if (data->auto_abort)
- usbtmc_ioctl_abort_bulk_in(data);
- goto exit;
- }
-
- /* Parse header in first packet */
- if (done == 0) {
- /* Sanity checks for the header */
- if (actual < USBTMC_HEADER_SIZE) {
- dev_err(dev, "Device sent too small first packet: %u < %u\n", actual, USBTMC_HEADER_SIZE);
- if (data->auto_abort)
- usbtmc_ioctl_abort_bulk_in(data);
- goto exit;
- }
+ /* Store bTag (in case we need to abort) */
+ data->bTag_last_read = data->bTag;
- if (buffer[0] != 2) {
- dev_err(dev, "Device sent reply with wrong MsgID: %u != 2\n", buffer[0]);
- if (data->auto_abort)
- usbtmc_ioctl_abort_bulk_in(data);
- goto exit;
- }
+ if (retval < 0) {
+ if (file_data->auto_abort)
+ usbtmc_ioctl_abort_bulk_in(data);
+ goto exit;
+ }
- if (buffer[1] != data->bTag_last_write) {
- dev_err(dev, "Device sent reply with wrong bTag: %u != %u\n", buffer[1], data->bTag_last_write);
- if (data->auto_abort)
- usbtmc_ioctl_abort_bulk_in(data);
- goto exit;
- }
+ /* Sanity checks for the header */
+ if (actual < USBTMC_HEADER_SIZE) {
+ dev_err(dev, "Device sent too small first packet: %u < %u\n",
+ actual, USBTMC_HEADER_SIZE);
+ if (file_data->auto_abort)
+ usbtmc_ioctl_abort_bulk_in(data);
+ goto exit;
+ }
- /* How many characters did the instrument send? */
- n_characters = buffer[4] +
- (buffer[5] << 8) +
- (buffer[6] << 16) +
- (buffer[7] << 24);
+ if (buffer[0] != 2) {
+ dev_err(dev, "Device sent reply with wrong MsgID: %u != 2\n",
+ buffer[0]);
+ if (file_data->auto_abort)
+ usbtmc_ioctl_abort_bulk_in(data);
+ goto exit;
+ }
- if (n_characters > this_part) {
- dev_err(dev, "Device wants to return more data than requested: %u > %zu\n", n_characters, count);
- if (data->auto_abort)
- usbtmc_ioctl_abort_bulk_in(data);
- goto exit;
- }
+ if (buffer[1] != data->bTag_last_write) {
+ dev_err(dev, "Device sent reply with wrong bTag: %u != %u\n",
+ buffer[1], data->bTag_last_write);
+ if (file_data->auto_abort)
+ usbtmc_ioctl_abort_bulk_in(data);
+ goto exit;
+ }
- /* Remove the USBTMC header */
- actual -= USBTMC_HEADER_SIZE;
+ /* How many characters did the instrument send? */
+ n_characters = buffer[4] +
+ (buffer[5] << 8) +
+ (buffer[6] << 16) +
+ (buffer[7] << 24);
- /* Check if the message is smaller than requested */
- if (remaining > n_characters)
- remaining = n_characters;
- /* Remove padding if it exists */
- if (actual > remaining)
- actual = remaining;
+ file_data->bmTransferAttributes = buffer[8];
- dev_dbg(dev, "Bulk-IN header: N_characters(%u), bTransAttr(%u)\n", n_characters, buffer[8]);
+ dev_dbg(dev, "Bulk-IN header: N_characters(%u), bTransAttr(%u)\n",
+ n_characters, buffer[8]);
- remaining -= actual;
+ if (n_characters > remaining) {
+ dev_err(dev, "Device wants to return more data than requested: %u > %zu\n",
+ n_characters, count);
+ if (file_data->auto_abort)
+ usbtmc_ioctl_abort_bulk_in(data);
+ goto exit;
+ }
- /* Terminate if end-of-message bit received from device */
- if ((buffer[8] & 0x01) && (actual >= n_characters))
- remaining = 0;
+ print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE,
+ 16, 1, buffer, actual, true);
- dev_dbg(dev, "Bulk-IN header: remaining(%zu), buf(%p), buffer(%p) done(%zu)\n", remaining,buf,buffer,done);
+ remaining = n_characters;
+ /* Remove the USBTMC header */
+ actual -= USBTMC_HEADER_SIZE;
- /* Copy buffer to user space */
- if (copy_to_user(buf + done, &buffer[USBTMC_HEADER_SIZE], actual)) {
- /* There must have been an addressing problem */
- retval = -EFAULT;
- goto exit;
- }
- done += actual;
- }
- else {
- if (actual > remaining)
- actual = remaining;
+ /* Remove padding if it exists */
+ if (actual > remaining)
+ actual = remaining;
- remaining -= actual;
+ remaining -= actual;
- dev_dbg(dev, "Bulk-IN header cont: actual(%u), done(%zu), remaining(%zu), buf(%p), buffer(%p)\n", actual, done, remaining,buf,buffer);
+ /* Copy buffer to user space */
+ if (copy_to_user(buf, &buffer[USBTMC_HEADER_SIZE], actual)) {
+ /* There must have been an addressing problem */
+ retval = -EFAULT;
+ goto exit;
+ }
- /* Copy buffer to user space */
- if (copy_to_user(buf + done, buffer, actual)) {
- /* There must have been an addressing problem */
- retval = -EFAULT;
- goto exit;
- }
- done += actual;
- }
+ if ((actual + USBTMC_HEADER_SIZE) == bufsize) {
+ retval = usbtmc_generic_read(file_data, buf + actual,
+ remaining,
+ &done,
+ USBTMC_FLAG_IGNORE_TRAILER);
+ if (retval < 0)
+ goto exit;
}
+ done += actual;
/* Update file position value */
*f_pos = *f_pos + done;
@@ -833,113 +1482,152 @@ static ssize_t usbtmc_write(struct file *filp, const char __user *buf,
{
struct usbtmc_file_data *file_data;
struct usbtmc_device_data *data;
+ struct urb *urb = NULL;
+ ssize_t retval = 0;
u8 *buffer;
- int retval;
- int actual;
- unsigned long int n_bytes;
- int remaining;
- int done;
- int this_part;
+ u32 remaining, done;
+ u32 transfersize, aligned, buflen;
file_data = filp->private_data;
data = file_data->data;
- buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL);
- if (!buffer)
- return -ENOMEM;
-
mutex_lock(&data->io_mutex);
+
if (data->zombie) {
retval = -ENODEV;
goto exit;
}
- remaining = count;
done = 0;
- while (remaining > 0) {
- if (remaining > USBTMC_SIZE_IOBUFFER - USBTMC_HEADER_SIZE) {
- this_part = USBTMC_SIZE_IOBUFFER - USBTMC_HEADER_SIZE;
- buffer[8] = 0;
- } else {
- this_part = remaining;
- buffer[8] = file_data->eom_val;
- }
+ spin_lock_irq(&file_data->err_lock);
+ file_data->out_transfer_size = 0;
+ file_data->out_status = 0;
+ spin_unlock_irq(&file_data->err_lock);
- /* Setup IO buffer for DEV_DEP_MSG_OUT message */
- buffer[0] = 1;
- buffer[1] = data->bTag;
- buffer[2] = ~data->bTag;
- buffer[3] = 0; /* Reserved */
- buffer[4] = this_part >> 0;
- buffer[5] = this_part >> 8;
- buffer[6] = this_part >> 16;
- buffer[7] = this_part >> 24;
- /* buffer[8] is set above... */
- buffer[9] = 0; /* Reserved */
- buffer[10] = 0; /* Reserved */
- buffer[11] = 0; /* Reserved */
-
- if (copy_from_user(&buffer[USBTMC_HEADER_SIZE], buf + done, this_part)) {
- retval = -EFAULT;
- goto exit;
- }
+ if (!count)
+ goto exit;
- n_bytes = roundup(USBTMC_HEADER_SIZE + this_part, 4);
- memset(buffer + USBTMC_HEADER_SIZE + this_part, 0, n_bytes - (USBTMC_HEADER_SIZE + this_part));
+ if (down_trylock(&file_data->limit_write_sem)) {
+ /* previous calls were async */
+ retval = -EBUSY;
+ goto exit;
+ }
- do {
- retval = usb_bulk_msg(data->usb_dev,
- usb_sndbulkpipe(data->usb_dev,
- data->bulk_out),
- buffer, n_bytes,
- &actual, file_data->timeout);
- if (retval != 0)
- break;
- n_bytes -= actual;
- } while (n_bytes);
-
- data->bTag_last_write = data->bTag;
+ urb = usbtmc_create_urb();
+ if (!urb) {
+ retval = -ENOMEM;
+ up(&file_data->limit_write_sem);
+ goto exit;
+ }
+
+ buffer = urb->transfer_buffer;
+ buflen = urb->transfer_buffer_length;
+
+ if (count > INT_MAX) {
+ transfersize = INT_MAX;
+ buffer[8] = 0;
+ } else {
+ transfersize = count;
+ buffer[8] = file_data->eom_val;
+ }
+
+ /* Setup IO buffer for DEV_DEP_MSG_OUT message */
+ buffer[0] = 1;
+ buffer[1] = data->bTag;
+ buffer[2] = ~data->bTag;
+ buffer[3] = 0; /* Reserved */
+ buffer[4] = transfersize >> 0;
+ buffer[5] = transfersize >> 8;
+ buffer[6] = transfersize >> 16;
+ buffer[7] = transfersize >> 24;
+ /* buffer[8] is set above... */
+ buffer[9] = 0; /* Reserved */
+ buffer[10] = 0; /* Reserved */
+ buffer[11] = 0; /* Reserved */
+
+ remaining = transfersize;
+
+ if (transfersize + USBTMC_HEADER_SIZE > buflen) {
+ transfersize = buflen - USBTMC_HEADER_SIZE;
+ aligned = buflen;
+ } else {
+ aligned = (transfersize + (USBTMC_HEADER_SIZE + 3)) & ~3;
+ }
+
+ if (copy_from_user(&buffer[USBTMC_HEADER_SIZE], buf, transfersize)) {
+ retval = -EFAULT;
+ up(&file_data->limit_write_sem);
+ goto exit;
+ }
+
+ dev_dbg(&data->intf->dev, "%s(size:%u align:%u)\n", __func__,
+ (unsigned int)transfersize, (unsigned int)aligned);
+
+ print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE,
+ 16, 1, buffer, aligned, true);
+
+ usb_fill_bulk_urb(urb, data->usb_dev,
+ usb_sndbulkpipe(data->usb_dev, data->bulk_out),
+ urb->transfer_buffer, aligned,
+ usbtmc_write_bulk_cb, file_data);
+
+ usb_anchor_urb(urb, &file_data->submitted);
+ retval = usb_submit_urb(urb, GFP_KERNEL);
+ if (unlikely(retval)) {
+ usb_unanchor_urb(urb);
+ up(&file_data->limit_write_sem);
+ goto exit;
+ }
+
+ remaining -= transfersize;
+
+ data->bTag_last_write = data->bTag;
+ data->bTag++;
+
+ if (!data->bTag)
data->bTag++;
- if (!data->bTag)
- data->bTag++;
+ /* call generic_write even when remaining = 0 */
+ retval = usbtmc_generic_write(file_data, buf + transfersize, remaining,
+ &done, USBTMC_FLAG_APPEND);
+ /* truncate alignment bytes */
+ if (done > remaining)
+ done = remaining;
- if (retval < 0) {
- dev_err(&data->intf->dev,
- "Unable to send data, error %d\n", retval);
- if (data->auto_abort)
- usbtmc_ioctl_abort_bulk_out(data);
- goto exit;
- }
+ /*add size of first urb*/
+ done += transfersize;
- remaining -= this_part;
- done += this_part;
+ if (retval < 0) {
+ usb_kill_anchored_urbs(&file_data->submitted);
+
+ dev_err(&data->intf->dev,
+ "Unable to send data, error %d\n", (int)retval);
+ if (file_data->auto_abort)
+ usbtmc_ioctl_abort_bulk_out(data);
+ goto exit;
}
- retval = count;
+ retval = done;
exit:
+ usb_free_urb(urb);
mutex_unlock(&data->io_mutex);
- kfree(buffer);
return retval;
}
static int usbtmc_ioctl_clear(struct usbtmc_device_data *data)
{
- struct usb_host_interface *current_setting;
- struct usb_endpoint_descriptor *desc;
struct device *dev;
u8 *buffer;
int rv;
int n;
int actual = 0;
- int max_size;
dev = &data->intf->dev;
dev_dbg(dev, "Sending INITIATE_CLEAR request\n");
- buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL);
+ buffer = kmalloc(USBTMC_BUFSIZE, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
@@ -947,7 +1635,7 @@ static int usbtmc_ioctl_clear(struct usbtmc_device_data *data)
usb_rcvctrlpipe(data->usb_dev, 0),
USBTMC_REQUEST_INITIATE_CLEAR,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- 0, 0, buffer, 1, USBTMC_TIMEOUT);
+ 0, 0, buffer, 1, USB_CTRL_GET_TIMEOUT);
if (rv < 0) {
dev_err(dev, "usb_control_msg returned %d\n", rv);
goto exit;
@@ -961,22 +1649,6 @@ static int usbtmc_ioctl_clear(struct usbtmc_device_data *data)
goto exit;
}
- max_size = 0;
- current_setting = data->intf->cur_altsetting;
- for (n = 0; n < current_setting->desc.bNumEndpoints; n++) {
- desc = &current_setting->endpoint[n].desc;
- if (desc->bEndpointAddress == data->bulk_in)
- max_size = usb_endpoint_maxp(desc);
- }
-
- if (max_size == 0) {
- dev_err(dev, "Couldn't get wMaxPacketSize\n");
- rv = -EPERM;
- goto exit;
- }
-
- dev_dbg(dev, "wMaxPacketSize is %d\n", max_size);
-
n = 0;
usbtmc_clear_check_status:
@@ -987,7 +1659,7 @@ usbtmc_clear_check_status:
usb_rcvctrlpipe(data->usb_dev, 0),
USBTMC_REQUEST_CHECK_CLEAR_STATUS,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- 0, 0, buffer, 2, USBTMC_TIMEOUT);
+ 0, 0, buffer, 2, USB_CTRL_GET_TIMEOUT);
if (rv < 0) {
dev_err(dev, "usb_control_msg returned %d\n", rv);
goto exit;
@@ -1004,15 +1676,20 @@ usbtmc_clear_check_status:
goto exit;
}
- if (buffer[1] == 1)
+ if ((buffer[1] & 1) != 0) {
do {
dev_dbg(dev, "Reading from bulk in EP\n");
+ actual = 0;
rv = usb_bulk_msg(data->usb_dev,
usb_rcvbulkpipe(data->usb_dev,
data->bulk_in),
- buffer, USBTMC_SIZE_IOBUFFER,
- &actual, USBTMC_TIMEOUT);
+ buffer, USBTMC_BUFSIZE,
+ &actual, USB_CTRL_GET_TIMEOUT);
+
+ print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE,
+ 16, 1, buffer, actual, true);
+
n++;
if (rv < 0) {
@@ -1020,10 +1697,15 @@ usbtmc_clear_check_status:
rv);
goto exit;
}
- } while ((actual == max_size) &&
+ } while ((actual == USBTMC_BUFSIZE) &&
(n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN));
+ } else {
+ /* do not stress device with subsequent requests */
+ msleep(50);
+ n++;
+ }
- if (actual == max_size) {
+ if (n >= USBTMC_MAX_READS_TO_CLEAR_BULK_IN) {
dev_err(dev, "Couldn't clear device buffer within %d cycles\n",
USBTMC_MAX_READS_TO_CLEAR_BULK_IN);
rv = -EPERM;
@@ -1037,7 +1719,7 @@ usbtmc_clear_bulk_out_halt:
rv = usb_clear_halt(data->usb_dev,
usb_sndbulkpipe(data->usb_dev, data->bulk_out));
if (rv < 0) {
- dev_err(dev, "usb_control_msg returned %d\n", rv);
+ dev_err(dev, "usb_clear_halt returned %d\n", rv);
goto exit;
}
rv = 0;
@@ -1054,12 +1736,9 @@ static int usbtmc_ioctl_clear_out_halt(struct usbtmc_device_data *data)
rv = usb_clear_halt(data->usb_dev,
usb_sndbulkpipe(data->usb_dev, data->bulk_out));
- if (rv < 0) {
- dev_err(&data->usb_dev->dev, "usb_control_msg returned %d\n",
- rv);
- return rv;
- }
- return 0;
+ if (rv < 0)
+ dev_err(&data->usb_dev->dev, "%s returned %d\n", __func__, rv);
+ return rv;
}
static int usbtmc_ioctl_clear_in_halt(struct usbtmc_device_data *data)
@@ -1069,11 +1748,33 @@ static int usbtmc_ioctl_clear_in_halt(struct usbtmc_device_data *data)
rv = usb_clear_halt(data->usb_dev,
usb_rcvbulkpipe(data->usb_dev, data->bulk_in));
- if (rv < 0) {
- dev_err(&data->usb_dev->dev, "usb_control_msg returned %d\n",
- rv);
- return rv;
- }
+ if (rv < 0)
+ dev_err(&data->usb_dev->dev, "%s returned %d\n", __func__, rv);
+ return rv;
+}
+
+static int usbtmc_ioctl_cancel_io(struct usbtmc_file_data *file_data)
+{
+ spin_lock_irq(&file_data->err_lock);
+ file_data->in_status = -ECANCELED;
+ file_data->out_status = -ECANCELED;
+ spin_unlock_irq(&file_data->err_lock);
+ usb_kill_anchored_urbs(&file_data->submitted);
+ return 0;
+}
+
+static int usbtmc_ioctl_cleanup_io(struct usbtmc_file_data *file_data)
+{
+ usb_kill_anchored_urbs(&file_data->submitted);
+ usb_scuttle_anchored_urbs(&file_data->in_anchor);
+ spin_lock_irq(&file_data->err_lock);
+ file_data->in_status = 0;
+ file_data->in_transfer_size = 0;
+ file_data->out_status = 0;
+ file_data->out_transfer_size = 0;
+ spin_unlock_irq(&file_data->err_lock);
+
+ file_data->in_urbs_used = 0;
return 0;
}
@@ -1090,7 +1791,7 @@ static int get_capabilities(struct usbtmc_device_data *data)
rv = usb_control_msg(data->usb_dev, usb_rcvctrlpipe(data->usb_dev, 0),
USBTMC_REQUEST_GET_CAPABILITIES,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- 0, 0, buffer, 0x18, USBTMC_TIMEOUT);
+ 0, 0, buffer, 0x18, USB_CTRL_GET_TIMEOUT);
if (rv < 0) {
dev_err(dev, "usb_control_msg returned %d\n", rv);
goto err_out;
@@ -1147,72 +1848,6 @@ static const struct attribute_group capability_attr_grp = {
.attrs = capability_attrs,
};
-static ssize_t TermChar_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct usb_interface *intf = to_usb_interface(dev);
- struct usbtmc_device_data *data = usb_get_intfdata(intf);
-
- return sprintf(buf, "%c\n", data->TermChar);
-}
-
-static ssize_t TermChar_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct usb_interface *intf = to_usb_interface(dev);
- struct usbtmc_device_data *data = usb_get_intfdata(intf);
-
- if (count < 1)
- return -EINVAL;
- data->TermChar = buf[0];
- return count;
-}
-static DEVICE_ATTR_RW(TermChar);
-
-#define data_attribute(name) \
-static ssize_t name##_show(struct device *dev, \
- struct device_attribute *attr, char *buf) \
-{ \
- struct usb_interface *intf = to_usb_interface(dev); \
- struct usbtmc_device_data *data = usb_get_intfdata(intf); \
- \
- return sprintf(buf, "%d\n", data->name); \
-} \
-static ssize_t name##_store(struct device *dev, \
- struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- struct usb_interface *intf = to_usb_interface(dev); \
- struct usbtmc_device_data *data = usb_get_intfdata(intf); \
- ssize_t result; \
- unsigned val; \
- \
- result = sscanf(buf, "%u\n", &val); \
- if (result != 1) \
- result = -EINVAL; \
- data->name = val; \
- if (result < 0) \
- return result; \
- else \
- return count; \
-} \
-static DEVICE_ATTR_RW(name)
-
-data_attribute(TermCharEnabled);
-data_attribute(auto_abort);
-
-static struct attribute *data_attrs[] = {
- &dev_attr_TermChar.attr,
- &dev_attr_TermCharEnabled.attr,
- &dev_attr_auto_abort.attr,
- NULL,
-};
-
-static const struct attribute_group data_attr_grp = {
- .attrs = data_attrs,
-};
-
static int usbtmc_ioctl_indicator_pulse(struct usbtmc_device_data *data)
{
struct device *dev;
@@ -1229,7 +1864,7 @@ static int usbtmc_ioctl_indicator_pulse(struct usbtmc_device_data *data)
usb_rcvctrlpipe(data->usb_dev, 0),
USBTMC_REQUEST_INDICATOR_PULSE,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- 0, 0, buffer, 0x01, USBTMC_TIMEOUT);
+ 0, 0, buffer, 0x01, USB_CTRL_GET_TIMEOUT);
if (rv < 0) {
dev_err(dev, "usb_control_msg returned %d\n", rv);
@@ -1250,6 +1885,63 @@ exit:
return rv;
}
+static int usbtmc_ioctl_request(struct usbtmc_device_data *data,
+ void __user *arg)
+{
+ struct device *dev = &data->intf->dev;
+ struct usbtmc_ctrlrequest request;
+ u8 *buffer = NULL;
+ int rv;
+ unsigned long res;
+
+ res = copy_from_user(&request, arg, sizeof(struct usbtmc_ctrlrequest));
+ if (res)
+ return -EFAULT;
+
+ if (request.req.wLength > USBTMC_BUFSIZE)
+ return -EMSGSIZE;
+
+ if (request.req.wLength) {
+ buffer = kmalloc(request.req.wLength, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ if ((request.req.bRequestType & USB_DIR_IN) == 0) {
+ /* Send control data to device */
+ res = copy_from_user(buffer, request.data,
+ request.req.wLength);
+ if (res) {
+ rv = -EFAULT;
+ goto exit;
+ }
+ }
+ }
+
+ rv = usb_control_msg(data->usb_dev,
+ usb_rcvctrlpipe(data->usb_dev, 0),
+ request.req.bRequest,
+ request.req.bRequestType,
+ request.req.wValue,
+ request.req.wIndex,
+ buffer, request.req.wLength, USB_CTRL_GET_TIMEOUT);
+
+ if (rv < 0) {
+ dev_err(dev, "%s failed %d\n", __func__, rv);
+ goto exit;
+ }
+
+ if (rv && (request.req.bRequestType & USB_DIR_IN)) {
+ /* Read control data from device */
+ res = copy_to_user(request.data, buffer, rv);
+ if (res)
+ rv = -EFAULT;
+ }
+
+ exit:
+ kfree(buffer);
+ return rv;
+}
+
/*
* Get the usb timeout value
*/
@@ -1331,6 +2023,7 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
struct usbtmc_file_data *file_data;
struct usbtmc_device_data *data;
int retval = -EBADRQC;
+ __u8 tmp_byte;
file_data = file->private_data;
data = file_data->data;
@@ -1366,6 +2059,10 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
retval = usbtmc_ioctl_abort_bulk_in(data);
break;
+ case USBTMC_IOCTL_CTRL_REQUEST:
+ retval = usbtmc_ioctl_request(data, (void __user *)arg);
+ break;
+
case USBTMC_IOCTL_GET_TIMEOUT:
retval = usbtmc_ioctl_get_timeout(file_data,
(void __user *)arg);
@@ -1386,12 +2083,29 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
(void __user *)arg);
break;
+ case USBTMC_IOCTL_WRITE:
+ retval = usbtmc_ioctl_generic_write(file_data,
+ (void __user *)arg);
+ break;
+
+ case USBTMC_IOCTL_READ:
+ retval = usbtmc_ioctl_generic_read(file_data,
+ (void __user *)arg);
+ break;
+
+ case USBTMC_IOCTL_WRITE_RESULT:
+ retval = usbtmc_ioctl_write_result(file_data,
+ (void __user *)arg);
+ break;
+
+ case USBTMC_IOCTL_API_VERSION:
+ retval = put_user(USBTMC_API_VERSION,
+ (__u32 __user *)arg);
+ break;
+
case USBTMC488_IOCTL_GET_CAPS:
- retval = copy_to_user((void __user *)arg,
- &data->usb488_caps,
- sizeof(data->usb488_caps));
- if (retval)
- retval = -EFAULT;
+ retval = put_user(data->usb488_caps,
+ (unsigned char __user *)arg);
break;
case USBTMC488_IOCTL_READ_STB:
@@ -1417,6 +2131,30 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case USBTMC488_IOCTL_TRIGGER:
retval = usbtmc488_ioctl_trigger(file_data);
break;
+
+ case USBTMC488_IOCTL_WAIT_SRQ:
+ retval = usbtmc488_ioctl_wait_srq(file_data,
+ (__u32 __user *)arg);
+ break;
+
+ case USBTMC_IOCTL_MSG_IN_ATTR:
+ retval = put_user(file_data->bmTransferAttributes,
+ (__u8 __user *)arg);
+ break;
+
+ case USBTMC_IOCTL_AUTO_ABORT:
+ retval = get_user(tmp_byte, (unsigned char __user *)arg);
+ if (retval == 0)
+ file_data->auto_abort = !!tmp_byte;
+ break;
+
+ case USBTMC_IOCTL_CANCEL_IO:
+ retval = usbtmc_ioctl_cancel_io(file_data);
+ break;
+
+ case USBTMC_IOCTL_CLEANUP_IO:
+ retval = usbtmc_ioctl_cleanup_io(file_data);
+ break;
}
skip_io_on_zombie:
@@ -1446,7 +2184,28 @@ static __poll_t usbtmc_poll(struct file *file, poll_table *wait)
poll_wait(file, &data->waitq, wait);
- mask = (atomic_read(&file_data->srq_asserted)) ? EPOLLPRI : 0;
+ /* Note that EPOLLPRI is now assigned to SRQ, and
+ * EPOLLIN|EPOLLRDNORM to normal read data.
+ */
+ mask = 0;
+ if (atomic_read(&file_data->srq_asserted))
+ mask |= EPOLLPRI;
+
+ /* Note that the anchor submitted includes all urbs for BULK IN
+ * and OUT. So EPOLLOUT is signaled when BULK OUT is empty and
+ * all BULK IN urbs are completed and moved to in_anchor.
+ */
+ if (usb_anchor_empty(&file_data->submitted))
+ mask |= (EPOLLOUT | EPOLLWRNORM);
+ if (!usb_anchor_empty(&file_data->in_anchor))
+ mask |= (EPOLLIN | EPOLLRDNORM);
+
+ spin_lock_irq(&file_data->err_lock);
+ if (file_data->in_status || file_data->out_status)
+ mask |= EPOLLERR;
+ spin_unlock_irq(&file_data->err_lock);
+
+ dev_dbg(&data->intf->dev, "poll mask = %x\n", mask);
no_poll:
mutex_unlock(&data->io_mutex);
@@ -1459,6 +2218,7 @@ static const struct file_operations fops = {
.write = usbtmc_write,
.open = usbtmc_open,
.release = usbtmc_release,
+ .flush = usbtmc_flush,
.unlocked_ioctl = usbtmc_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = usbtmc_ioctl,
@@ -1552,7 +2312,9 @@ static void usbtmc_free_int(struct usbtmc_device_data *data)
return;
usb_kill_urb(data->iin_urb);
kfree(data->iin_buffer);
+ data->iin_buffer = NULL;
usb_free_urb(data->iin_urb);
+ data->iin_urb = NULL;
kref_put(&data->kref, usbtmc_delete);
}
@@ -1585,8 +2347,6 @@ static int usbtmc_probe(struct usb_interface *intf,
/* Initialize USBTMC bTag and other fields */
data->bTag = 1;
- data->TermCharEnabled = 0;
- data->TermChar = '\n';
/* 2 <= bTag <= 127 USBTMC-USB488 subclass specification 4.3.1 */
data->iin_bTag = 2;
@@ -1603,6 +2363,7 @@ static int usbtmc_probe(struct usb_interface *intf,
}
data->bulk_in = bulk_in->bEndpointAddress;
+ data->wMaxPacketSize = usb_endpoint_maxp(bulk_in);
dev_dbg(&intf->dev, "Found bulk in endpoint at %u\n", data->bulk_in);
data->bulk_out = bulk_out->bEndpointAddress;
@@ -1659,12 +2420,10 @@ static int usbtmc_probe(struct usb_interface *intf,
}
}
- retcode = sysfs_create_group(&intf->dev.kobj, &data_attr_grp);
-
retcode = usb_register_dev(intf, &usbtmc_class);
if (retcode) {
- dev_err(&intf->dev, "Not able to get a minor"
- " (base %u, slice default): %d\n", USBTMC_MINOR_BASE,
+ dev_err(&intf->dev, "Not able to get a minor (base %u, slice default): %d\n",
+ USBTMC_MINOR_BASE,
retcode);
goto error_register;
}
@@ -1674,7 +2433,6 @@ static int usbtmc_probe(struct usb_interface *intf,
error_register:
sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp);
- sysfs_remove_group(&intf->dev.kobj, &data_attr_grp);
usbtmc_free_int(data);
err_put:
kref_put(&data->kref, usbtmc_delete);
@@ -1684,26 +2442,103 @@ err_put:
static void usbtmc_disconnect(struct usb_interface *intf)
{
struct usbtmc_device_data *data = usb_get_intfdata(intf);
+ struct list_head *elem;
usb_deregister_dev(intf, &usbtmc_class);
sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp);
- sysfs_remove_group(&intf->dev.kobj, &data_attr_grp);
mutex_lock(&data->io_mutex);
data->zombie = 1;
wake_up_interruptible_all(&data->waitq);
+ list_for_each(elem, &data->file_list) {
+ struct usbtmc_file_data *file_data;
+
+ file_data = list_entry(elem,
+ struct usbtmc_file_data,
+ file_elem);
+ usb_kill_anchored_urbs(&file_data->submitted);
+ usb_scuttle_anchored_urbs(&file_data->in_anchor);
+ }
mutex_unlock(&data->io_mutex);
usbtmc_free_int(data);
kref_put(&data->kref, usbtmc_delete);
}
+static void usbtmc_draw_down(struct usbtmc_file_data *file_data)
+{
+ int time;
+
+ time = usb_wait_anchor_empty_timeout(&file_data->submitted, 1000);
+ if (!time)
+ usb_kill_anchored_urbs(&file_data->submitted);
+ usb_scuttle_anchored_urbs(&file_data->in_anchor);
+}
+
static int usbtmc_suspend(struct usb_interface *intf, pm_message_t message)
{
- /* this driver does not have pending URBs */
+ struct usbtmc_device_data *data = usb_get_intfdata(intf);
+ struct list_head *elem;
+
+ if (!data)
+ return 0;
+
+ mutex_lock(&data->io_mutex);
+ list_for_each(elem, &data->file_list) {
+ struct usbtmc_file_data *file_data;
+
+ file_data = list_entry(elem,
+ struct usbtmc_file_data,
+ file_elem);
+ usbtmc_draw_down(file_data);
+ }
+
+ if (data->iin_ep_present && data->iin_urb)
+ usb_kill_urb(data->iin_urb);
+
+ mutex_unlock(&data->io_mutex);
return 0;
}
static int usbtmc_resume(struct usb_interface *intf)
{
+ struct usbtmc_device_data *data = usb_get_intfdata(intf);
+ int retcode = 0;
+
+ if (data->iin_ep_present && data->iin_urb)
+ retcode = usb_submit_urb(data->iin_urb, GFP_KERNEL);
+ if (retcode)
+ dev_err(&intf->dev, "Failed to submit iin_urb\n");
+
+ return retcode;
+}
+
+static int usbtmc_pre_reset(struct usb_interface *intf)
+{
+ struct usbtmc_device_data *data = usb_get_intfdata(intf);
+ struct list_head *elem;
+
+ if (!data)
+ return 0;
+
+ mutex_lock(&data->io_mutex);
+
+ list_for_each(elem, &data->file_list) {
+ struct usbtmc_file_data *file_data;
+
+ file_data = list_entry(elem,
+ struct usbtmc_file_data,
+ file_elem);
+ usbtmc_ioctl_cancel_io(file_data);
+ }
+
+ return 0;
+}
+
+static int usbtmc_post_reset(struct usb_interface *intf)
+{
+ struct usbtmc_device_data *data = usb_get_intfdata(intf);
+
+ mutex_unlock(&data->io_mutex);
+
return 0;
}
@@ -1714,6 +2549,8 @@ static struct usb_driver usbtmc_driver = {
.disconnect = usbtmc_disconnect,
.suspend = usbtmc_suspend,
.resume = usbtmc_resume,
+ .pre_reset = usbtmc_pre_reset,
+ .post_reset = usbtmc_post_reset,
};
module_usb_driver(usbtmc_driver);
diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c
index 77eef8acff94..f641342cdec0 100644
--- a/drivers/usb/core/buffer.c
+++ b/drivers/usb/core/buffer.c
@@ -101,12 +101,8 @@ void hcd_buffer_destroy(struct usb_hcd *hcd)
return;
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
- struct dma_pool *pool = hcd->pool[i];
-
- if (pool) {
- dma_pool_destroy(pool);
- hcd->pool[i] = NULL;
- }
+ dma_pool_destroy(hcd->pool[i]);
+ hcd->pool[i] = NULL;
}
}
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 244417d0dfd1..a75bc0b8a50f 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -582,7 +582,7 @@ static void async_completed(struct urb *urb)
{
struct async *as = urb->context;
struct usb_dev_state *ps = as->ps;
- struct siginfo sinfo;
+ struct kernel_siginfo sinfo;
struct pid *pid = NULL;
const struct cred *cred = NULL;
unsigned long flags;
@@ -1474,8 +1474,6 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
u = 0;
switch (uurb->type) {
case USBDEVFS_URB_TYPE_CONTROL:
- if (is_in)
- allow_short = true;
if (!usb_endpoint_xfer_control(&ep->desc))
return -EINVAL;
/* min 8 byte setup packet */
@@ -1505,6 +1503,8 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
is_in = 0;
uurb->endpoint &= ~USB_DIR_IN;
}
+ if (is_in)
+ allow_short = true;
snoop(&ps->dev->dev, "control urb: bRequestType=%02x "
"bRequest=%02x wValue=%04x "
"wIndex=%04x wLength=%04x\n",
@@ -2617,7 +2617,7 @@ const struct file_operations usbdev_file_operations = {
static void usbdev_remove(struct usb_device *udev)
{
struct usb_dev_state *ps;
- struct siginfo sinfo;
+ struct kernel_siginfo sinfo;
while (!list_empty(&udev->filelist)) {
ps = list_entry(udev->filelist.next, struct usb_dev_state, list);
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index a1f225f077cd..53564386ed57 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -510,7 +510,6 @@ int usb_driver_claim_interface(struct usb_driver *driver,
struct usb_interface *iface, void *priv)
{
struct device *dev;
- struct usb_device *udev;
int retval = 0;
if (!iface)
@@ -524,8 +523,6 @@ int usb_driver_claim_interface(struct usb_driver *driver,
if (!iface->authorized)
return -ENODEV;
- udev = interface_to_usbdev(iface);
-
dev->driver = &driver->drvwrap.driver;
usb_set_intfdata(iface, priv);
iface->needs_binding = 0;
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index bc8242bc4564..356b05c82dbc 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -21,6 +21,7 @@
#include <linux/usb.h>
#include <linux/usb/hcd.h>
+#include <uapi/linux/usb/audio.h>
#include "usb.h"
static inline const char *plural(int n)
@@ -42,6 +43,16 @@ static int is_activesync(struct usb_interface_descriptor *desc)
&& desc->bInterfaceProtocol == 1;
}
+static bool is_audio(struct usb_interface_descriptor *desc)
+{
+ return desc->bInterfaceClass == USB_CLASS_AUDIO;
+}
+
+static bool is_uac3_config(struct usb_interface_descriptor *desc)
+{
+ return desc->bInterfaceProtocol == UAC_VERSION_3;
+}
+
int usb_choose_configuration(struct usb_device *udev)
{
int i;
@@ -121,6 +132,22 @@ int usb_choose_configuration(struct usb_device *udev)
#endif
}
+ /*
+ * Select first configuration as default for audio so that
+ * devices that don't comply with UAC3 protocol are supported.
+ * But, still iterate through other configurations and
+ * select UAC3 compliant config if present.
+ */
+ if (i == 0 && num_configs > 1 && desc && is_audio(desc)) {
+ best = c;
+ continue;
+ }
+
+ if (i > 0 && desc && is_audio(desc) && is_uac3_config(desc)) {
+ best = c;
+ break;
+ }
+
/* From the remaining configs, choose the first one whose
* first interface is for a non-vendor-specific class.
* Reason: Linux is more likely to have a class driver
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 1c21955fe7c0..487025d31d44 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1738,7 +1738,6 @@ static void __usb_hcd_giveback_urb(struct urb *urb)
struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus);
struct usb_anchor *anchor = urb->anchor;
int status = urb->unlinked;
- unsigned long flags;
urb->hcpriv = NULL;
if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
@@ -1755,20 +1754,7 @@ static void __usb_hcd_giveback_urb(struct urb *urb)
/* pass ownership to the completion handler */
urb->status = status;
-
- /*
- * We disable local IRQs here avoid possible deadlock because
- * drivers may call spin_lock() to hold lock which might be
- * acquired in one hard interrupt handler.
- *
- * The local_irq_save()/local_irq_restore() around complete()
- * will be removed if current USB drivers have been cleaned up
- * and no one may trigger the above deadlock situation when
- * running complete() in tasklet.
- */
- local_irq_save(flags);
urb->complete(urb);
- local_irq_restore(flags);
usb_anchor_resume_wakeups(anchor);
atomic_dec(&urb->use_count);
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 462ce49f683a..c6077d582d29 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -28,6 +28,7 @@
#include <linux/mutex.h>
#include <linux/random.h>
#include <linux/pm_qos.h>
+#include <linux/kobject.h>
#include <linux/uaccess.h>
#include <asm/byteorder.h>
@@ -2660,11 +2661,13 @@ static bool use_new_scheme(struct usb_device *udev, int retry,
{
int old_scheme_first_port =
port_dev->quirks & USB_PORT_QUIRK_OLD_SCHEME;
+ int quick_enumeration = (udev->speed == USB_SPEED_HIGH);
if (udev->speed >= USB_SPEED_SUPER)
return false;
- return USE_NEW_SCHEME(retry, old_scheme_first_port || old_scheme_first);
+ return USE_NEW_SCHEME(retry, old_scheme_first_port || old_scheme_first
+ || quick_enumeration);
}
/* Is a USB 3.0 port in the Inactive or Compliance Mode state?
@@ -5147,6 +5150,42 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
usb_lock_port(port_dev);
}
+/* Handle notifying userspace about hub over-current events */
+static void port_over_current_notify(struct usb_port *port_dev)
+{
+ static char *envp[] = { NULL, NULL, NULL };
+ struct device *hub_dev;
+ char *port_dev_path;
+
+ sysfs_notify(&port_dev->dev.kobj, NULL, "over_current_count");
+
+ hub_dev = port_dev->dev.parent;
+
+ if (!hub_dev)
+ return;
+
+ port_dev_path = kobject_get_path(&port_dev->dev.kobj, GFP_KERNEL);
+ if (!port_dev_path)
+ return;
+
+ envp[0] = kasprintf(GFP_KERNEL, "OVER_CURRENT_PORT=%s", port_dev_path);
+ if (!envp[0])
+ goto exit_path;
+
+ envp[1] = kasprintf(GFP_KERNEL, "OVER_CURRENT_COUNT=%u",
+ port_dev->over_current_count);
+ if (!envp[1])
+ goto exit;
+
+ kobject_uevent_env(&hub_dev->kobj, KOBJ_CHANGE, envp);
+
+ kfree(envp[1]);
+exit:
+ kfree(envp[0]);
+exit_path:
+ kfree(port_dev_path);
+}
+
static void port_event(struct usb_hub *hub, int port1)
__must_hold(&port_dev->status_lock)
{
@@ -5189,6 +5228,7 @@ static void port_event(struct usb_hub *hub, int port1)
if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
u16 status = 0, unused;
port_dev->over_current_count++;
+ port_over_current_notify(port_dev);
dev_dbg(&port_dev->dev, "over-current change #%u\n",
port_dev->over_current_count);
diff --git a/drivers/usb/core/phy.c b/drivers/usb/core/phy.c
index 9879767452a2..38b2c776c4b4 100644
--- a/drivers/usb/core/phy.c
+++ b/drivers/usb/core/phy.c
@@ -23,10 +23,11 @@ static int usb_phy_roothub_add_phy(struct device *dev, int index,
struct list_head *list)
{
struct usb_phy_roothub *roothub_entry;
- struct phy *phy = devm_of_phy_get_by_index(dev, dev->of_node, index);
+ struct phy *phy;
- if (IS_ERR_OR_NULL(phy)) {
- if (!phy || PTR_ERR(phy) == -ENODEV)
+ phy = devm_of_phy_get_by_index(dev, dev->of_node, index);
+ if (IS_ERR(phy)) {
+ if (PTR_ERR(phy) == -ENODEV)
return 0;
else
return PTR_ERR(phy);
diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c
index 4a2143195395..1a06a4b5fbb1 100644
--- a/drivers/usb/core/port.c
+++ b/drivers/usb/core/port.c
@@ -16,6 +16,15 @@ static int usb_port_block_power_off;
static const struct attribute_group *port_dev_group[];
+static ssize_t location_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_port *port_dev = to_usb_port(dev);
+
+ return sprintf(buf, "0x%08x\n", port_dev->location);
+}
+static DEVICE_ATTR_RO(location);
+
static ssize_t connect_type_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -140,6 +149,7 @@ static DEVICE_ATTR_RW(usb3_lpm_permit);
static struct attribute *port_dev_attrs[] = {
&dev_attr_connect_type.attr,
+ &dev_attr_location.attr,
&dev_attr_quirks.attr,
&dev_attr_over_current_count.attr,
NULL,
diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index cc9c93affa14..30bab8463c96 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -393,6 +393,20 @@ enum dwc2_ep0_state {
* 0 - No
* 1 - Yes
* @hird_threshold: Value of BESL or HIRD Threshold.
+ * @ref_clk_per: Indicates in terms of pico seconds the period
+ * of ref_clk.
+ * 62500 - 16MHz
+ * 58823 - 17MHz
+ * 52083 - 19.2MHz
+ * 50000 - 20MHz
+ * 41666 - 24MHz
+ * 33333 - 30MHz (default)
+ * 25000 - 40MHz
+ * @sof_cnt_wkup_alert: Indicates in term of number of SOF's after which
+ * the controller should generate an interrupt if the
+ * device had been in L1 state until that period.
+ * This is used by SW to initiate Remote WakeUp in the
+ * controller so as to sync to the uF number from the host.
* @activate_stm_fs_transceiver: Activate internal transceiver using GGPIO
* register.
* 0 - Deactivate the transceiver (default)
@@ -416,6 +430,9 @@ enum dwc2_ep0_state {
* back to DWC2_SPEED_PARAM_HIGH while device is gone.
* 0 - No (default)
* 1 - Yes
+ * @service_interval: Enable service interval based scheduling.
+ * 0 - No
+ * 1 - Yes
*
* The following parameters may be specified when starting the module. These
* parameters define how the DWC_otg controller should be configured. A
@@ -461,6 +478,7 @@ struct dwc2_core_params {
bool lpm_clock_gating;
bool besl;
bool hird_threshold_en;
+ bool service_interval;
u8 hird_threshold;
bool activate_stm_fs_transceiver;
bool ipg_isoc_en;
@@ -468,6 +486,10 @@ struct dwc2_core_params {
u32 max_transfer_size;
u32 ahbcfg;
+ /* GREFCLK parameters */
+ u32 ref_clk_per;
+ u16 sof_cnt_wkup_alert;
+
/* Host parameters */
bool host_dma;
bool dma_desc_enable;
@@ -605,6 +627,10 @@ struct dwc2_core_params {
* FIFO sizing is enabled 16 to 32768
* Actual maximum value is autodetected and also
* the default.
+ * @service_interval_mode: For enabling service interval based scheduling in the
+ * controller.
+ * 0 - Disable
+ * 1 - Enable
*/
struct dwc2_hw_params {
unsigned op_mode:3;
@@ -635,6 +661,7 @@ struct dwc2_hw_params {
unsigned utmi_phy_data_width:2;
unsigned lpm_mode:1;
unsigned ipg_isoc_en:1;
+ unsigned service_interval_mode:1;
u32 snpsid;
u32 dev_ep_dirs;
u32 g_tx_fifo_size[MAX_EPS_CHANNELS];
@@ -1354,6 +1381,7 @@ int dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg);
int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg);
int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg);
void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg);
+void dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg);
#else
static inline int dwc2_hsotg_remove(struct dwc2_hsotg *dwc2)
{ return 0; }
@@ -1388,6 +1416,7 @@ static inline int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg)
static inline int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg)
{ return 0; }
static inline void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg) {}
+static inline void dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg) {}
#endif
#if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
diff --git a/drivers/usb/dwc2/debugfs.c b/drivers/usb/dwc2/debugfs.c
index 22d015b0424f..7f62f4cdc265 100644
--- a/drivers/usb/dwc2/debugfs.c
+++ b/drivers/usb/dwc2/debugfs.c
@@ -701,6 +701,7 @@ static int params_show(struct seq_file *seq, void *v)
print_param(seq, p, besl);
print_param(seq, p, hird_threshold_en);
print_param(seq, p, hird_threshold);
+ print_param(seq, p, service_interval);
print_param(seq, p, host_dma);
print_param(seq, p, g_dma);
print_param(seq, p, g_dma_desc);
diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index 220c0f9b89b0..2d6d2c8244de 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -123,6 +123,24 @@ static inline void dwc2_gadget_incr_frame_num(struct dwc2_hsotg_ep *hs_ep)
}
/**
+ * dwc2_gadget_dec_frame_num_by_one - Decrements the targeted frame number
+ * by one.
+ * @hs_ep: The endpoint.
+ *
+ * This function used in service interval based scheduling flow to calculate
+ * descriptor frame number filed value. For service interval mode frame
+ * number in descriptor should point to last (u)frame in the interval.
+ *
+ */
+static inline void dwc2_gadget_dec_frame_num_by_one(struct dwc2_hsotg_ep *hs_ep)
+{
+ if (hs_ep->target_frame)
+ hs_ep->target_frame -= 1;
+ else
+ hs_ep->target_frame = DSTS_SOFFN_LIMIT;
+}
+
+/**
* dwc2_hsotg_en_gsint - enable one or more of the general interrupt
* @hsotg: The device state
* @ints: A bitmask of the interrupts to enable
@@ -228,6 +246,27 @@ int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg)
}
/**
+ * dwc2_gadget_wkup_alert_handler - Handler for WKUP_ALERT interrupt
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ *
+ */
+static void dwc2_gadget_wkup_alert_handler(struct dwc2_hsotg *hsotg)
+{
+ u32 gintsts2;
+ u32 gintmsk2;
+
+ gintsts2 = dwc2_readl(hsotg, GINTSTS2);
+ gintmsk2 = dwc2_readl(hsotg, GINTMSK2);
+
+ if (gintsts2 & GINTSTS2_WKUP_ALERT_INT) {
+ dev_dbg(hsotg->dev, "%s: Wkup_Alert_Int\n", __func__);
+ dwc2_clear_bit(hsotg, GINTSTS2, GINTSTS2_WKUP_ALERT_INT);
+ dwc2_set_bit(hsotg, DCFG, DCTL_RMTWKUPSIG);
+ }
+}
+
+/**
* dwc2_hsotg_tx_fifo_average_depth - returns average depth of device mode
* TX FIFOs
*
@@ -2812,6 +2851,23 @@ static void dwc2_gadget_handle_nak(struct dwc2_hsotg_ep *hs_ep)
if (using_desc_dma(hsotg)) {
hs_ep->target_frame = hsotg->frame_number;
dwc2_gadget_incr_frame_num(hs_ep);
+
+ /* In service interval mode target_frame must
+ * be set to last (u)frame of the service interval.
+ */
+ if (hsotg->params.service_interval) {
+ /* Set target_frame to the first (u)frame of
+ * the service interval
+ */
+ hs_ep->target_frame &= ~hs_ep->interval + 1;
+
+ /* Set target_frame to the last (u)frame of
+ * the service interval
+ */
+ dwc2_gadget_incr_frame_num(hs_ep);
+ dwc2_gadget_dec_frame_num_by_one(hs_ep);
+ }
+
dwc2_gadget_start_isoc_ddma(hs_ep);
return;
}
@@ -3109,6 +3165,8 @@ static void kill_all_requests(struct dwc2_hsotg *hsotg,
dwc2_hsotg_txfifo_flush(hsotg, ep->fifo_index);
}
+static int dwc2_hsotg_ep_disable(struct usb_ep *ep);
+
/**
* dwc2_hsotg_disconnect - disconnect service
* @hsotg: The device state.
@@ -3127,13 +3185,12 @@ void dwc2_hsotg_disconnect(struct dwc2_hsotg *hsotg)
hsotg->connected = 0;
hsotg->test_mode = 0;
+ /* all endpoints should be shutdown */
for (ep = 0; ep < hsotg->num_of_eps; ep++) {
if (hsotg->eps_in[ep])
- kill_all_requests(hsotg, hsotg->eps_in[ep],
- -ESHUTDOWN);
+ dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep);
if (hsotg->eps_out[ep])
- kill_all_requests(hsotg, hsotg->eps_out[ep],
- -ESHUTDOWN);
+ dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep);
}
call_gadget(hsotg, disconnect);
@@ -3191,13 +3248,23 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
u32 val;
u32 usbcfg;
u32 dcfg = 0;
+ int ep;
/* Kill any ep0 requests as controller will be reinitialized */
kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET);
- if (!is_usb_reset)
+ if (!is_usb_reset) {
if (dwc2_core_reset(hsotg, true))
return;
+ } else {
+ /* all endpoints should be shutdown */
+ for (ep = 1; ep < hsotg->num_of_eps; ep++) {
+ if (hsotg->eps_in[ep])
+ dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep);
+ if (hsotg->eps_out[ep])
+ dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep);
+ }
+ }
/*
* we must now enable ep0 ready for host detection and then
@@ -3312,6 +3379,10 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
dwc2_set_bit(hsotg, DIEPMSK, DIEPMSK_BNAININTRMSK);
}
+ /* Enable Service Interval mode if supported */
+ if (using_desc_dma(hsotg) && hsotg->params.service_interval)
+ dwc2_set_bit(hsotg, DCTL, DCTL_SERVICE_INTERVAL_SUPPORTED);
+
dwc2_writel(hsotg, 0, DAINTMSK);
dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
@@ -3368,6 +3439,10 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
/* configure the core to support LPM */
dwc2_gadget_init_lpm(hsotg);
+ /* program GREFCLK register if needed */
+ if (using_desc_dma(hsotg) && hsotg->params.service_interval)
+ dwc2_gadget_program_ref_clk(hsotg);
+
/* must be at-least 3ms to allow bus to see disconnect */
mdelay(3);
@@ -3676,6 +3751,10 @@ irq_retry:
if (gintsts & IRQ_RETRY_MASK && --retry_count > 0)
goto irq_retry;
+ /* Check WKUP_ALERT interrupt*/
+ if (hsotg->params.service_interval)
+ dwc2_gadget_wkup_alert_handler(hsotg);
+
spin_unlock(&hsotg->lock);
return IRQ_HANDLED;
@@ -3993,6 +4072,7 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep)
unsigned long flags;
u32 epctrl_reg;
u32 ctrl;
+ int locked;
dev_dbg(hsotg->dev, "%s(ep %p)\n", __func__, ep);
@@ -4008,7 +4088,9 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep)
epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index);
- spin_lock_irqsave(&hsotg->lock, flags);
+ locked = spin_is_locked(&hsotg->lock);
+ if (!locked)
+ spin_lock_irqsave(&hsotg->lock, flags);
ctrl = dwc2_readl(hsotg, epctrl_reg);
@@ -4032,7 +4114,9 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep)
hs_ep->fifo_index = 0;
hs_ep->fifo_size = 0;
- spin_unlock_irqrestore(&hsotg->lock, flags);
+ if (!locked)
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+
return 0;
}
@@ -4944,6 +5028,29 @@ void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg)
val |= hsotg->params.besl ? GLPMCFG_ENBESL : 0;
dwc2_writel(hsotg, val, GLPMCFG);
dev_dbg(hsotg->dev, "GLPMCFG=0x%08x\n", dwc2_readl(hsotg, GLPMCFG));
+
+ /* Unmask WKUP_ALERT Interrupt */
+ if (hsotg->params.service_interval)
+ dwc2_set_bit(hsotg, GINTMSK2, GINTMSK2_WKUP_ALERT_INT_MSK);
+}
+
+/**
+ * dwc2_gadget_program_ref_clk - Program GREFCLK register in device mode
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ *
+ */
+void dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg)
+{
+ u32 val = 0;
+
+ val |= GREFCLK_REF_CLK_MODE;
+ val |= hsotg->params.ref_clk_per << GREFCLK_REFCLKPER_SHIFT;
+ val |= hsotg->params.sof_cnt_wkup_alert <<
+ GREFCLK_SOF_CNT_WKUP_ALERT_SHIFT;
+
+ dwc2_writel(hsotg, val, GREFCLK);
+ dev_dbg(hsotg->dev, "GREFCLK=0x%08x\n", dwc2_readl(hsotg, GREFCLK));
}
/**
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 2bd6e6bfc241..dd82fa516f3f 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -358,16 +358,10 @@ static void dwc2_gusbcfg_init(struct dwc2_hsotg *hsotg)
static int dwc2_vbus_supply_init(struct dwc2_hsotg *hsotg)
{
- int ret;
-
- hsotg->vbus_supply = devm_regulator_get_optional(hsotg->dev, "vbus");
- if (IS_ERR(hsotg->vbus_supply)) {
- ret = PTR_ERR(hsotg->vbus_supply);
- hsotg->vbus_supply = NULL;
- return ret == -ENODEV ? 0 : ret;
- }
+ if (hsotg->vbus_supply)
+ return regulator_enable(hsotg->vbus_supply);
- return regulator_enable(hsotg->vbus_supply);
+ return 0;
}
static int dwc2_vbus_supply_exit(struct dwc2_hsotg *hsotg)
@@ -1328,14 +1322,11 @@ static void dwc2_hc_write_packet(struct dwc2_hsotg *hsotg,
u32 remaining_count;
u32 byte_count;
u32 dword_count;
- u32 __iomem *data_fifo;
u32 *data_buf = (u32 *)chan->xfer_buf;
if (dbg_hc(chan))
dev_vdbg(hsotg->dev, "%s()\n", __func__);
- data_fifo = (u32 __iomem *)(hsotg->regs + HCFIFO(chan->hc_num));
-
remaining_count = chan->xfer_len - chan->xfer_count;
if (remaining_count > chan->max_packet)
byte_count = chan->max_packet;
@@ -3564,6 +3555,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
u32 port_status;
u32 speed;
u32 pcgctl;
+ u32 pwr;
switch (typereq) {
case ClearHubFeature:
@@ -3612,8 +3604,11 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
dev_dbg(hsotg->dev,
"ClearPortFeature USB_PORT_FEAT_POWER\n");
hprt0 = dwc2_read_hprt0(hsotg);
+ pwr = hprt0 & HPRT0_PWR;
hprt0 &= ~HPRT0_PWR;
dwc2_writel(hsotg, hprt0, HPRT0);
+ if (pwr)
+ dwc2_vbus_supply_exit(hsotg);
break;
case USB_PORT_FEAT_INDICATOR:
@@ -3823,8 +3818,11 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
dev_dbg(hsotg->dev,
"SetPortFeature - USB_PORT_FEAT_POWER\n");
hprt0 = dwc2_read_hprt0(hsotg);
+ pwr = hprt0 & HPRT0_PWR;
hprt0 |= HPRT0_PWR;
dwc2_writel(hsotg, hprt0, HPRT0);
+ if (!pwr)
+ dwc2_vbus_supply_init(hsotg);
break;
case USB_PORT_FEAT_RESET:
@@ -3841,6 +3839,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
dwc2_writel(hsotg, 0, PCGCTL);
hprt0 = dwc2_read_hprt0(hsotg);
+ pwr = hprt0 & HPRT0_PWR;
/* Clear suspend bit if resetting from suspend state */
hprt0 &= ~HPRT0_SUSP;
@@ -3854,6 +3853,8 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
dev_dbg(hsotg->dev,
"In host mode, hprt0=%08x\n", hprt0);
dwc2_writel(hsotg, hprt0, HPRT0);
+ if (!pwr)
+ dwc2_vbus_supply_init(hsotg);
}
/* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */
@@ -4393,6 +4394,8 @@ static int _dwc2_hcd_start(struct usb_hcd *hcd)
struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
struct usb_bus *bus = hcd_to_bus(hcd);
unsigned long flags;
+ u32 hprt0;
+ int ret;
dev_dbg(hsotg->dev, "DWC OTG HCD START\n");
@@ -4408,6 +4411,17 @@ static int _dwc2_hcd_start(struct usb_hcd *hcd)
dwc2_hcd_reinit(hsotg);
+ hprt0 = dwc2_read_hprt0(hsotg);
+ /* Has vbus power been turned on in dwc2_core_host_init ? */
+ if (hprt0 & HPRT0_PWR) {
+ /* Enable external vbus supply before resuming root hub */
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+ ret = dwc2_vbus_supply_init(hsotg);
+ if (ret)
+ return ret;
+ spin_lock_irqsave(&hsotg->lock, flags);
+ }
+
/* Initialize and connect root hub if one is not already attached */
if (bus->root_hub) {
dev_dbg(hsotg->dev, "DWC OTG HCD Has Root Hub\n");
@@ -4417,7 +4431,7 @@ static int _dwc2_hcd_start(struct usb_hcd *hcd)
spin_unlock_irqrestore(&hsotg->lock, flags);
- return dwc2_vbus_supply_init(hsotg);
+ return 0;
}
/*
@@ -4428,6 +4442,7 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd)
{
struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
unsigned long flags;
+ u32 hprt0;
/* Turn off all host-specific interrupts */
dwc2_disable_host_interrupts(hsotg);
@@ -4436,6 +4451,7 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd)
synchronize_irq(hcd->irq);
spin_lock_irqsave(&hsotg->lock, flags);
+ hprt0 = dwc2_read_hprt0(hsotg);
/* Ensure hcd is disconnected */
dwc2_hcd_disconnect(hsotg, true);
dwc2_hcd_stop(hsotg);
@@ -4444,7 +4460,9 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd)
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
spin_unlock_irqrestore(&hsotg->lock, flags);
- dwc2_vbus_supply_exit(hsotg);
+ /* keep balanced supply init/exit by checking HPRT0_PWR */
+ if (hprt0 & HPRT0_PWR)
+ dwc2_vbus_supply_exit(hsotg);
usleep_range(1000, 3000);
}
@@ -4482,7 +4500,9 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd)
hprt0 |= HPRT0_SUSP;
hprt0 &= ~HPRT0_PWR;
dwc2_writel(hsotg, hprt0, HPRT0);
+ spin_unlock_irqrestore(&hsotg->lock, flags);
dwc2_vbus_supply_exit(hsotg);
+ spin_lock_irqsave(&hsotg->lock, flags);
}
/* Enter partial_power_down */
diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h
index 0ca8e7bc7aaf..2b1ea441b7d4 100644
--- a/drivers/usb/dwc2/hw.h
+++ b/drivers/usb/dwc2/hw.h
@@ -312,6 +312,7 @@
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT 14
#define GHWCFG4_ACG_SUPPORTED BIT(12)
#define GHWCFG4_IPG_ISOC_SUPPORTED BIT(11)
+#define GHWCFG4_SERVICE_INTERVAL_SUPPORTED BIT(10)
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8 0
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_16 1
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16 2
@@ -404,6 +405,19 @@
#define ADPCTL_PRB_DSCHRG_MASK (0x3 << 0)
#define ADPCTL_PRB_DSCHRG_SHIFT 0
+#define GREFCLK HSOTG_REG(0x0064)
+#define GREFCLK_REFCLKPER_MASK (0x1ffff << 15)
+#define GREFCLK_REFCLKPER_SHIFT 15
+#define GREFCLK_REF_CLK_MODE BIT(14)
+#define GREFCLK_SOF_CNT_WKUP_ALERT_MASK (0x3ff)
+#define GREFCLK_SOF_CNT_WKUP_ALERT_SHIFT 0
+
+#define GINTMSK2 HSOTG_REG(0x0068)
+#define GINTMSK2_WKUP_ALERT_INT_MSK BIT(0)
+
+#define GINTSTS2 HSOTG_REG(0x006c)
+#define GINTSTS2_WKUP_ALERT_INT BIT(0)
+
#define HPTXFSIZ HSOTG_REG(0x100)
/* Use FIFOSIZE_* constants to access this register */
@@ -443,6 +457,7 @@
#define DCFG_DEVSPD_FS48 3
#define DCTL HSOTG_REG(0x804)
+#define DCTL_SERVICE_INTERVAL_SUPPORTED BIT(19)
#define DCTL_PWRONPRGDONE BIT(11)
#define DCTL_CGOUTNAK BIT(10)
#define DCTL_SGOUTNAK BIT(9)
diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c
index bf7052e037d6..7c1b6938f212 100644
--- a/drivers/usb/dwc2/params.c
+++ b/drivers/usb/dwc2/params.c
@@ -81,6 +81,7 @@ static void dwc2_set_rk_params(struct dwc2_hsotg *hsotg)
p->host_perio_tx_fifo_size = 256;
p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 <<
GAHBCFG_HBSTLEN_SHIFT;
+ p->power_down = 0;
}
static void dwc2_set_ltq_params(struct dwc2_hsotg *hsotg)
@@ -299,9 +300,12 @@ static void dwc2_set_default_params(struct dwc2_hsotg *hsotg)
p->hird_threshold_en = true;
p->hird_threshold = 4;
p->ipg_isoc_en = false;
+ p->service_interval = false;
p->max_packet_count = hw->max_packet_count;
p->max_transfer_size = hw->max_transfer_size;
p->ahbcfg = GAHBCFG_HBSTLEN_INCR << GAHBCFG_HBSTLEN_SHIFT;
+ p->ref_clk_per = 33333;
+ p->sof_cnt_wkup_alert = 100;
if ((hsotg->dr_mode == USB_DR_MODE_HOST) ||
(hsotg->dr_mode == USB_DR_MODE_OTG)) {
@@ -592,6 +596,7 @@ static void dwc2_check_params(struct dwc2_hsotg *hsotg)
CHECK_BOOL(besl, (hsotg->hw_params.snpsid >= DWC2_CORE_REV_3_00a));
CHECK_BOOL(hird_threshold_en, hsotg->params.lpm);
CHECK_RANGE(hird_threshold, 0, hsotg->params.besl ? 12 : 7, 0);
+ CHECK_BOOL(service_interval, hw->service_interval_mode);
CHECK_RANGE(max_packet_count,
15, hw->max_packet_count,
hw->max_packet_count);
@@ -780,6 +785,8 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)
GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT;
hw->acg_enable = !!(hwcfg4 & GHWCFG4_ACG_SUPPORTED);
hw->ipg_isoc_en = !!(hwcfg4 & GHWCFG4_IPG_ISOC_SUPPORTED);
+ hw->service_interval_mode = !!(hwcfg4 &
+ GHWCFG4_SERVICE_INTERVAL_SUPPORTED);
/* fifo sizes */
hw->rx_fifo_size = (grxfsiz & GRXFSIZ_DEPTH_MASK) >>
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
index 577642895b57..c0b64d483552 100644
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -432,6 +432,14 @@ static int dwc2_driver_probe(struct platform_device *dev)
if (retval)
return retval;
+ hsotg->vbus_supply = devm_regulator_get_optional(hsotg->dev, "vbus");
+ if (IS_ERR(hsotg->vbus_supply)) {
+ retval = PTR_ERR(hsotg->vbus_supply);
+ hsotg->vbus_supply = NULL;
+ if (retval != -ENODEV)
+ return retval;
+ }
+
retval = dwc2_lowlevel_hw_enable(hsotg);
if (retval)
return retval;
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index 518ead12458d..1a0404fda596 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -113,7 +113,7 @@ config USB_DWC3_ST
config USB_DWC3_QCOM
tristate "Qualcomm Platform"
- depends on ARCH_QCOM || COMPILE_TEST
+ depends on EXTCON && (ARCH_QCOM || COMPILE_TEST)
depends on OF
default USB_DWC3
help
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 88c80fcc39f5..becfbb87f791 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -756,7 +756,7 @@ static void dwc3_core_setup_global_control(struct dwc3 *dwc)
/* check if current dwc3 is on simulation board */
if (dwc->hwparams.hwparams6 & DWC3_GHWPARAMS6_EN_FPGA) {
- dev_info(dwc->dev, "Running with FPGA optmizations\n");
+ dev_info(dwc->dev, "Running with FPGA optimizations\n");
dwc->is_fpga = true;
}
diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c
index a94fb1ba8f2c..cb7fcd7c0ad8 100644
--- a/drivers/usb/dwc3/dwc3-exynos.c
+++ b/drivers/usb/dwc3/dwc3-exynos.c
@@ -13,80 +13,30 @@
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
-#include <linux/usb/otg.h>
-#include <linux/usb/usb_phy_generic.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/regulator/consumer.h>
+#define DWC3_EXYNOS_MAX_CLOCKS 4
+
+struct dwc3_exynos_driverdata {
+ const char *clk_names[DWC3_EXYNOS_MAX_CLOCKS];
+ int num_clks;
+ int suspend_clk_idx;
+};
+
struct dwc3_exynos {
- struct platform_device *usb2_phy;
- struct platform_device *usb3_phy;
struct device *dev;
- struct clk *clk;
- struct clk *susp_clk;
- struct clk *axius_clk;
+ const char **clk_names;
+ struct clk *clks[DWC3_EXYNOS_MAX_CLOCKS];
+ int num_clks;
+ int suspend_clk_idx;
struct regulator *vdd33;
struct regulator *vdd10;
};
-static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos)
-{
- struct usb_phy_generic_platform_data pdata;
- struct platform_device *pdev;
- int ret;
-
- memset(&pdata, 0x00, sizeof(pdata));
-
- pdev = platform_device_alloc("usb_phy_generic", PLATFORM_DEVID_AUTO);
- if (!pdev)
- return -ENOMEM;
-
- exynos->usb2_phy = pdev;
- pdata.type = USB_PHY_TYPE_USB2;
- pdata.gpio_reset = -1;
-
- ret = platform_device_add_data(exynos->usb2_phy, &pdata, sizeof(pdata));
- if (ret)
- goto err1;
-
- pdev = platform_device_alloc("usb_phy_generic", PLATFORM_DEVID_AUTO);
- if (!pdev) {
- ret = -ENOMEM;
- goto err1;
- }
-
- exynos->usb3_phy = pdev;
- pdata.type = USB_PHY_TYPE_USB3;
-
- ret = platform_device_add_data(exynos->usb3_phy, &pdata, sizeof(pdata));
- if (ret)
- goto err2;
-
- ret = platform_device_add(exynos->usb2_phy);
- if (ret)
- goto err2;
-
- ret = platform_device_add(exynos->usb3_phy);
- if (ret)
- goto err3;
-
- return 0;
-
-err3:
- platform_device_del(exynos->usb2_phy);
-
-err2:
- platform_device_put(exynos->usb3_phy);
-
-err1:
- platform_device_put(exynos->usb2_phy);
-
- return ret;
-}
-
static int dwc3_exynos_remove_child(struct device *dev, void *unused)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -101,47 +51,42 @@ static int dwc3_exynos_probe(struct platform_device *pdev)
struct dwc3_exynos *exynos;
struct device *dev = &pdev->dev;
struct device_node *node = dev->of_node;
-
- int ret;
+ const struct dwc3_exynos_driverdata *driver_data;
+ int i, ret;
exynos = devm_kzalloc(dev, sizeof(*exynos), GFP_KERNEL);
if (!exynos)
return -ENOMEM;
- platform_set_drvdata(pdev, exynos);
+ driver_data = of_device_get_match_data(dev);
+ exynos->dev = dev;
+ exynos->num_clks = driver_data->num_clks;
+ exynos->clk_names = (const char **)driver_data->clk_names;
+ exynos->suspend_clk_idx = driver_data->suspend_clk_idx;
- exynos->dev = dev;
+ platform_set_drvdata(pdev, exynos);
- exynos->clk = devm_clk_get(dev, "usbdrd30");
- if (IS_ERR(exynos->clk)) {
- dev_err(dev, "couldn't get clock\n");
- return -EINVAL;
+ for (i = 0; i < exynos->num_clks; i++) {
+ exynos->clks[i] = devm_clk_get(dev, exynos->clk_names[i]);
+ if (IS_ERR(exynos->clks[i])) {
+ dev_err(dev, "failed to get clock: %s\n",
+ exynos->clk_names[i]);
+ return PTR_ERR(exynos->clks[i]);
+ }
}
- ret = clk_prepare_enable(exynos->clk);
- if (ret)
- return ret;
- exynos->susp_clk = devm_clk_get(dev, "usbdrd30_susp_clk");
- if (IS_ERR(exynos->susp_clk))
- exynos->susp_clk = NULL;
- ret = clk_prepare_enable(exynos->susp_clk);
- if (ret)
- goto susp_clk_err;
-
- if (of_device_is_compatible(node, "samsung,exynos7-dwusb3")) {
- exynos->axius_clk = devm_clk_get(dev, "usbdrd30_axius_clk");
- if (IS_ERR(exynos->axius_clk)) {
- dev_err(dev, "no AXI UpScaler clk specified\n");
- ret = -ENODEV;
- goto axius_clk_err;
+ for (i = 0; i < exynos->num_clks; i++) {
+ ret = clk_prepare_enable(exynos->clks[i]);
+ if (ret) {
+ while (--i > 0)
+ clk_disable_unprepare(exynos->clks[i]);
+ return ret;
}
- ret = clk_prepare_enable(exynos->axius_clk);
- if (ret)
- goto axius_clk_err;
- } else {
- exynos->axius_clk = NULL;
}
+ if (exynos->suspend_clk_idx >= 0)
+ clk_prepare_enable(exynos->clks[exynos->suspend_clk_idx]);
+
exynos->vdd33 = devm_regulator_get(dev, "vdd33");
if (IS_ERR(exynos->vdd33)) {
ret = PTR_ERR(exynos->vdd33);
@@ -164,12 +109,6 @@ static int dwc3_exynos_probe(struct platform_device *pdev)
goto vdd10_err;
}
- ret = dwc3_exynos_register_phys(exynos);
- if (ret) {
- dev_err(dev, "couldn't register PHYs\n");
- goto phys_err;
- }
-
if (node) {
ret = of_platform_populate(node, NULL, NULL, dev);
if (ret) {
@@ -185,32 +124,31 @@ static int dwc3_exynos_probe(struct platform_device *pdev)
return 0;
populate_err:
- platform_device_unregister(exynos->usb2_phy);
- platform_device_unregister(exynos->usb3_phy);
-phys_err:
regulator_disable(exynos->vdd10);
vdd10_err:
regulator_disable(exynos->vdd33);
vdd33_err:
- clk_disable_unprepare(exynos->axius_clk);
-axius_clk_err:
- clk_disable_unprepare(exynos->susp_clk);
-susp_clk_err:
- clk_disable_unprepare(exynos->clk);
+ for (i = exynos->num_clks - 1; i >= 0; i--)
+ clk_disable_unprepare(exynos->clks[i]);
+
+ if (exynos->suspend_clk_idx >= 0)
+ clk_disable_unprepare(exynos->clks[exynos->suspend_clk_idx]);
+
return ret;
}
static int dwc3_exynos_remove(struct platform_device *pdev)
{
struct dwc3_exynos *exynos = platform_get_drvdata(pdev);
+ int i;
device_for_each_child(&pdev->dev, NULL, dwc3_exynos_remove_child);
- platform_device_unregister(exynos->usb2_phy);
- platform_device_unregister(exynos->usb3_phy);
- clk_disable_unprepare(exynos->axius_clk);
- clk_disable_unprepare(exynos->susp_clk);
- clk_disable_unprepare(exynos->clk);
+ for (i = exynos->num_clks - 1; i >= 0; i--)
+ clk_disable_unprepare(exynos->clks[i]);
+
+ if (exynos->suspend_clk_idx >= 0)
+ clk_disable_unprepare(exynos->clks[exynos->suspend_clk_idx]);
regulator_disable(exynos->vdd33);
regulator_disable(exynos->vdd10);
@@ -218,10 +156,36 @@ static int dwc3_exynos_remove(struct platform_device *pdev)
return 0;
}
+static const struct dwc3_exynos_driverdata exynos5250_drvdata = {
+ .clk_names = { "usbdrd30" },
+ .num_clks = 1,
+ .suspend_clk_idx = -1,
+};
+
+static const struct dwc3_exynos_driverdata exynos5433_drvdata = {
+ .clk_names = { "aclk", "susp_clk", "pipe_pclk", "phyclk" },
+ .num_clks = 4,
+ .suspend_clk_idx = 1,
+};
+
+static const struct dwc3_exynos_driverdata exynos7_drvdata = {
+ .clk_names = { "usbdrd30", "usbdrd30_susp_clk", "usbdrd30_axius_clk" },
+ .num_clks = 3,
+ .suspend_clk_idx = 1,
+};
+
static const struct of_device_id exynos_dwc3_match[] = {
- { .compatible = "samsung,exynos5250-dwusb3" },
- { .compatible = "samsung,exynos7-dwusb3" },
- {},
+ {
+ .compatible = "samsung,exynos5250-dwusb3",
+ .data = &exynos5250_drvdata,
+ }, {
+ .compatible = "samsung,exynos5433-dwusb3",
+ .data = &exynos5433_drvdata,
+ }, {
+ .compatible = "samsung,exynos7-dwusb3",
+ .data = &exynos7_drvdata,
+ }, {
+ }
};
MODULE_DEVICE_TABLE(of, exynos_dwc3_match);
@@ -229,9 +193,10 @@ MODULE_DEVICE_TABLE(of, exynos_dwc3_match);
static int dwc3_exynos_suspend(struct device *dev)
{
struct dwc3_exynos *exynos = dev_get_drvdata(dev);
+ int i;
- clk_disable(exynos->axius_clk);
- clk_disable(exynos->clk);
+ for (i = exynos->num_clks - 1; i >= 0; i--)
+ clk_disable_unprepare(exynos->clks[i]);
regulator_disable(exynos->vdd33);
regulator_disable(exynos->vdd10);
@@ -242,7 +207,7 @@ static int dwc3_exynos_suspend(struct device *dev)
static int dwc3_exynos_resume(struct device *dev)
{
struct dwc3_exynos *exynos = dev_get_drvdata(dev);
- int ret;
+ int i, ret;
ret = regulator_enable(exynos->vdd33);
if (ret) {
@@ -255,13 +220,14 @@ static int dwc3_exynos_resume(struct device *dev)
return ret;
}
- clk_enable(exynos->clk);
- clk_enable(exynos->axius_clk);
-
- /* runtime set active to reflect active state. */
- pm_runtime_disable(dev);
- pm_runtime_set_active(dev);
- pm_runtime_enable(dev);
+ for (i = 0; i < exynos->num_clks; i++) {
+ ret = clk_prepare_enable(exynos->clks[i]);
+ if (ret) {
+ while (--i > 0)
+ clk_disable_unprepare(exynos->clks[i]);
+ return ret;
+ }
+ }
return 0;
}
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 2b53194081ba..679c12e14522 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -270,27 +270,36 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd,
const struct usb_endpoint_descriptor *desc = dep->endpoint.desc;
struct dwc3 *dwc = dep->dwc;
u32 timeout = 1000;
+ u32 saved_config = 0;
u32 reg;
int cmd_status = 0;
- int susphy = false;
int ret = -EINVAL;
/*
- * Synopsys Databook 2.60a states, on section 6.3.2.5.[1-8], that if
- * we're issuing an endpoint command, we must check if
- * GUSB2PHYCFG.SUSPHY bit is set. If it is, then we need to clear it.
+ * When operating in USB 2.0 speeds (HS/FS), if GUSB2PHYCFG.ENBLSLPM or
+ * GUSB2PHYCFG.SUSPHY is set, it must be cleared before issuing an
+ * endpoint command.
*
- * We will also set SUSPHY bit to what it was before returning as stated
- * by the same section on Synopsys databook.
+ * Save and clear both GUSB2PHYCFG.ENBLSLPM and GUSB2PHYCFG.SUSPHY
+ * settings. Restore them after the command is completed.
+ *
+ * DWC_usb3 3.30a and DWC_usb31 1.90a programming guide section 3.2.2
*/
if (dwc->gadget.speed <= USB_SPEED_HIGH) {
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
if (unlikely(reg & DWC3_GUSB2PHYCFG_SUSPHY)) {
- susphy = true;
+ saved_config |= DWC3_GUSB2PHYCFG_SUSPHY;
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
- dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
}
+
+ if (reg & DWC3_GUSB2PHYCFG_ENBLSLPM) {
+ saved_config |= DWC3_GUSB2PHYCFG_ENBLSLPM;
+ reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
+ }
+
+ if (saved_config)
+ dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
}
if (DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_STARTTRANSFER) {
@@ -389,9 +398,9 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd,
}
}
- if (unlikely(susphy)) {
+ if (saved_config) {
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
- reg |= DWC3_GUSB2PHYCFG_SUSPHY;
+ reg |= saved_config;
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
}
diff --git a/drivers/usb/early/xhci-dbc.c b/drivers/usb/early/xhci-dbc.c
index e15e896f356c..d2652dccc699 100644
--- a/drivers/usb/early/xhci-dbc.c
+++ b/drivers/usb/early/xhci-dbc.c
@@ -12,7 +12,7 @@
#include <linux/console.h>
#include <linux/pci_regs.h>
#include <linux/pci_ids.h>
-#include <linux/bootmem.h>
+#include <linux/memblock.h>
#include <linux/io.h>
#include <asm/pci-direct.h>
#include <asm/fixmap.h>
@@ -94,7 +94,7 @@ static void * __init xdbc_get_page(dma_addr_t *dma_addr)
{
void *virt;
- virt = alloc_bootmem_pages_nopanic(PAGE_SIZE);
+ virt = memblock_alloc_nopanic(PAGE_SIZE, PAGE_SIZE);
if (!virt)
return NULL;
@@ -191,7 +191,7 @@ static void __init xdbc_free_ring(struct xdbc_ring *ring)
if (!seg)
return;
- free_bootmem(seg->dma, PAGE_SIZE);
+ memblock_free(seg->dma, PAGE_SIZE);
ring->segment = NULL;
}
@@ -675,10 +675,10 @@ int __init early_xdbc_setup_hardware(void)
xdbc_free_ring(&xdbc.in_ring);
if (xdbc.table_dma)
- free_bootmem(xdbc.table_dma, PAGE_SIZE);
+ memblock_free(xdbc.table_dma, PAGE_SIZE);
if (xdbc.out_dma)
- free_bootmem(xdbc.out_dma, PAGE_SIZE);
+ memblock_free(xdbc.out_dma, PAGE_SIZE);
xdbc.table_base = NULL;
xdbc.out_buf = NULL;
@@ -717,17 +717,14 @@ static void xdbc_handle_port_status(struct xdbc_trb *evt_trb)
static void xdbc_handle_tx_event(struct xdbc_trb *evt_trb)
{
- size_t remain_length;
u32 comp_code;
int ep_id;
comp_code = GET_COMP_CODE(le32_to_cpu(evt_trb->field[2]));
- remain_length = EVENT_TRB_LEN(le32_to_cpu(evt_trb->field[2]));
ep_id = TRB_TO_EP_ID(le32_to_cpu(evt_trb->field[3]));
switch (comp_code) {
case COMP_SUCCESS:
- remain_length = 0;
case COMP_SHORT_PACKET:
break;
case COMP_TRB_ERROR:
@@ -1000,8 +997,8 @@ free_and_quit:
xdbc_free_ring(&xdbc.evt_ring);
xdbc_free_ring(&xdbc.out_ring);
xdbc_free_ring(&xdbc.in_ring);
- free_bootmem(xdbc.table_dma, PAGE_SIZE);
- free_bootmem(xdbc.out_dma, PAGE_SIZE);
+ memblock_free(xdbc.table_dma, PAGE_SIZE);
+ memblock_free(xdbc.out_dma, PAGE_SIZE);
writel(0, &xdbc.xdbc_reg->control);
early_iounmap(xdbc.xhci_base, xdbc.xhci_length);
diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c
index ca8a4b53c59f..043f97ad8f22 100644
--- a/drivers/usb/gadget/function/f_mass_storage.c
+++ b/drivers/usb/gadget/function/f_mass_storage.c
@@ -221,6 +221,8 @@
#include <linux/usb/gadget.h>
#include <linux/usb/composite.h>
+#include <linux/nospec.h>
+
#include "configfs.h"
@@ -403,7 +405,7 @@ static void raise_exception(struct fsg_common *common, enum fsg_state new_state)
common->exception_req_tag = common->ep0_req_tag;
common->state = new_state;
if (common->thread_task)
- send_sig_info(SIGUSR1, SEND_SIG_FORCED,
+ send_sig_info(SIGUSR1, SEND_SIG_PRIV,
common->thread_task);
}
spin_unlock_irqrestore(&common->lock, flags);
@@ -2311,7 +2313,7 @@ static void handle_exception(struct fsg_common *common)
* into a high-priority EXIT exception.
*/
for (;;) {
- int sig = kernel_dequeue_signal(NULL);
+ int sig = kernel_dequeue_signal();
if (!sig)
break;
if (sig != SIGUSR1) {
@@ -3152,6 +3154,7 @@ static struct config_group *fsg_lun_make(struct config_group *group,
fsg_opts = to_fsg_opts(&group->cg_item);
if (num >= FSG_MAX_LUNS)
return ERR_PTR(-ERANGE);
+ num = array_index_nospec(num, FSG_MAX_LUNS);
mutex_lock(&fsg_opts->lock);
if (fsg_opts->refcnt || fsg_opts->common->luns[num]) {
diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c
index d582921f7257..db2d4980cb35 100644
--- a/drivers/usb/gadget/function/f_uac2.c
+++ b/drivers/usb/gadget/function/f_uac2.c
@@ -22,12 +22,8 @@
* controlled by two clock sources :
* CLK_5 := c_srate, and CLK_6 := p_srate
*/
-#define USB_OUT_IT_ID 1
-#define IO_IN_IT_ID 2
-#define IO_OUT_OT_ID 3
-#define USB_IN_OT_ID 4
-#define USB_OUT_CLK_ID 5
-#define USB_IN_CLK_ID 6
+#define USB_OUT_CLK_ID (out_clk_src_desc.bClockID)
+#define USB_IN_CLK_ID (in_clk_src_desc.bClockID)
#define CONTROL_ABSENT 0
#define CONTROL_RDONLY 1
@@ -43,6 +39,9 @@
#define UNFLW_CTRL 8
#define OVFLW_CTRL 10
+#define EPIN_EN(_opts) ((_opts)->p_chmask != 0)
+#define EPOUT_EN(_opts) ((_opts)->c_chmask != 0)
+
struct f_uac2 {
struct g_audio g_audio;
u8 ac_intf, as_in_intf, as_out_intf;
@@ -135,7 +134,7 @@ static struct uac_clock_source_descriptor in_clk_src_desc = {
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC2_CLOCK_SOURCE,
- .bClockID = USB_IN_CLK_ID,
+ /* .bClockID = DYNAMIC */
.bmAttributes = UAC_CLOCK_SOURCE_TYPE_INT_FIXED,
.bmControls = (CONTROL_RDONLY << CLK_FREQ_CTRL),
.bAssocTerminal = 0,
@@ -147,7 +146,7 @@ static struct uac_clock_source_descriptor out_clk_src_desc = {
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC2_CLOCK_SOURCE,
- .bClockID = USB_OUT_CLK_ID,
+ /* .bClockID = DYNAMIC */
.bmAttributes = UAC_CLOCK_SOURCE_TYPE_INT_FIXED,
.bmControls = (CONTROL_RDONLY << CLK_FREQ_CTRL),
.bAssocTerminal = 0,
@@ -159,10 +158,10 @@ static struct uac2_input_terminal_descriptor usb_out_it_desc = {
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC_INPUT_TERMINAL,
- .bTerminalID = USB_OUT_IT_ID,
+ /* .bTerminalID = DYNAMIC */
.wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING),
.bAssocTerminal = 0,
- .bCSourceID = USB_OUT_CLK_ID,
+ /* .bCSourceID = DYNAMIC */
.iChannelNames = 0,
.bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL),
};
@@ -173,10 +172,10 @@ static struct uac2_input_terminal_descriptor io_in_it_desc = {
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC_INPUT_TERMINAL,
- .bTerminalID = IO_IN_IT_ID,
+ /* .bTerminalID = DYNAMIC */
.wTerminalType = cpu_to_le16(UAC_INPUT_TERMINAL_UNDEFINED),
.bAssocTerminal = 0,
- .bCSourceID = USB_IN_CLK_ID,
+ /* .bCSourceID = DYNAMIC */
.iChannelNames = 0,
.bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL),
};
@@ -187,11 +186,11 @@ static struct uac2_output_terminal_descriptor usb_in_ot_desc = {
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC_OUTPUT_TERMINAL,
- .bTerminalID = USB_IN_OT_ID,
+ /* .bTerminalID = DYNAMIC */
.wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING),
.bAssocTerminal = 0,
- .bSourceID = IO_IN_IT_ID,
- .bCSourceID = USB_IN_CLK_ID,
+ /* .bSourceID = DYNAMIC */
+ /* .bCSourceID = DYNAMIC */
.bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL),
};
@@ -201,11 +200,11 @@ static struct uac2_output_terminal_descriptor io_out_ot_desc = {
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC_OUTPUT_TERMINAL,
- .bTerminalID = IO_OUT_OT_ID,
+ /* .bTerminalID = DYNAMIC */
.wTerminalType = cpu_to_le16(UAC_OUTPUT_TERMINAL_UNDEFINED),
.bAssocTerminal = 0,
- .bSourceID = USB_OUT_IT_ID,
- .bCSourceID = USB_OUT_CLK_ID,
+ /* .bSourceID = DYNAMIC */
+ /* .bCSourceID = DYNAMIC */
.bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL),
};
@@ -253,7 +252,7 @@ static struct uac2_as_header_descriptor as_out_hdr_desc = {
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC_AS_GENERAL,
- .bTerminalLink = USB_OUT_IT_ID,
+ /* .bTerminalLink = DYNAMIC */
.bmControls = 0,
.bFormatType = UAC_FORMAT_TYPE_I,
.bmFormats = cpu_to_le32(UAC_FORMAT_TYPE_I_PCM),
@@ -330,7 +329,7 @@ static struct uac2_as_header_descriptor as_in_hdr_desc = {
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC_AS_GENERAL,
- .bTerminalLink = USB_IN_OT_ID,
+ /* .bTerminalLink = DYNAMIC */
.bmControls = 0,
.bFormatType = UAC_FORMAT_TYPE_I,
.bmFormats = cpu_to_le32(UAC_FORMAT_TYPE_I_PCM),
@@ -471,6 +470,125 @@ static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts,
le16_to_cpu(ep_desc->wMaxPacketSize)));
}
+/* Use macro to overcome line length limitation */
+#define USBDHDR(p) (struct usb_descriptor_header *)(p)
+
+static void setup_descriptor(struct f_uac2_opts *opts)
+{
+ /* patch descriptors */
+ int i = 1; /* ID's start with 1 */
+
+ if (EPOUT_EN(opts))
+ usb_out_it_desc.bTerminalID = i++;
+ if (EPIN_EN(opts))
+ io_in_it_desc.bTerminalID = i++;
+ if (EPOUT_EN(opts))
+ io_out_ot_desc.bTerminalID = i++;
+ if (EPIN_EN(opts))
+ usb_in_ot_desc.bTerminalID = i++;
+ if (EPOUT_EN(opts))
+ out_clk_src_desc.bClockID = i++;
+ if (EPIN_EN(opts))
+ in_clk_src_desc.bClockID = i++;
+
+ usb_out_it_desc.bCSourceID = out_clk_src_desc.bClockID;
+ usb_in_ot_desc.bSourceID = io_in_it_desc.bTerminalID;
+ usb_in_ot_desc.bCSourceID = in_clk_src_desc.bClockID;
+ io_in_it_desc.bCSourceID = in_clk_src_desc.bClockID;
+ io_out_ot_desc.bCSourceID = out_clk_src_desc.bClockID;
+ io_out_ot_desc.bSourceID = usb_out_it_desc.bTerminalID;
+ as_out_hdr_desc.bTerminalLink = usb_out_it_desc.bTerminalID;
+ as_in_hdr_desc.bTerminalLink = usb_in_ot_desc.bTerminalID;
+
+ iad_desc.bInterfaceCount = 1;
+ ac_hdr_desc.wTotalLength = 0;
+
+ if (EPIN_EN(opts)) {
+ u16 len = le16_to_cpu(ac_hdr_desc.wTotalLength);
+
+ len += sizeof(in_clk_src_desc);
+ len += sizeof(usb_in_ot_desc);
+ len += sizeof(io_in_it_desc);
+ ac_hdr_desc.wTotalLength = cpu_to_le16(len);
+ iad_desc.bInterfaceCount++;
+ }
+ if (EPOUT_EN(opts)) {
+ u16 len = le16_to_cpu(ac_hdr_desc.wTotalLength);
+
+ len += sizeof(out_clk_src_desc);
+ len += sizeof(usb_out_it_desc);
+ len += sizeof(io_out_ot_desc);
+ ac_hdr_desc.wTotalLength = cpu_to_le16(len);
+ iad_desc.bInterfaceCount++;
+ }
+
+ i = 0;
+ fs_audio_desc[i++] = USBDHDR(&iad_desc);
+ fs_audio_desc[i++] = USBDHDR(&std_ac_if_desc);
+ fs_audio_desc[i++] = USBDHDR(&ac_hdr_desc);
+ if (EPIN_EN(opts))
+ fs_audio_desc[i++] = USBDHDR(&in_clk_src_desc);
+ if (EPOUT_EN(opts)) {
+ fs_audio_desc[i++] = USBDHDR(&out_clk_src_desc);
+ fs_audio_desc[i++] = USBDHDR(&usb_out_it_desc);
+ }
+ if (EPIN_EN(opts)) {
+ fs_audio_desc[i++] = USBDHDR(&io_in_it_desc);
+ fs_audio_desc[i++] = USBDHDR(&usb_in_ot_desc);
+ }
+ if (EPOUT_EN(opts)) {
+ fs_audio_desc[i++] = USBDHDR(&io_out_ot_desc);
+ fs_audio_desc[i++] = USBDHDR(&std_as_out_if0_desc);
+ fs_audio_desc[i++] = USBDHDR(&std_as_out_if1_desc);
+ fs_audio_desc[i++] = USBDHDR(&as_out_hdr_desc);
+ fs_audio_desc[i++] = USBDHDR(&as_out_fmt1_desc);
+ fs_audio_desc[i++] = USBDHDR(&fs_epout_desc);
+ fs_audio_desc[i++] = USBDHDR(&as_iso_out_desc);
+ }
+ if (EPIN_EN(opts)) {
+ fs_audio_desc[i++] = USBDHDR(&std_as_in_if0_desc);
+ fs_audio_desc[i++] = USBDHDR(&std_as_in_if1_desc);
+ fs_audio_desc[i++] = USBDHDR(&as_in_hdr_desc);
+ fs_audio_desc[i++] = USBDHDR(&as_in_fmt1_desc);
+ fs_audio_desc[i++] = USBDHDR(&fs_epin_desc);
+ fs_audio_desc[i++] = USBDHDR(&as_iso_in_desc);
+ }
+ fs_audio_desc[i] = NULL;
+
+ i = 0;
+ hs_audio_desc[i++] = USBDHDR(&iad_desc);
+ hs_audio_desc[i++] = USBDHDR(&std_ac_if_desc);
+ hs_audio_desc[i++] = USBDHDR(&ac_hdr_desc);
+ if (EPIN_EN(opts))
+ hs_audio_desc[i++] = USBDHDR(&in_clk_src_desc);
+ if (EPOUT_EN(opts)) {
+ hs_audio_desc[i++] = USBDHDR(&out_clk_src_desc);
+ hs_audio_desc[i++] = USBDHDR(&usb_out_it_desc);
+ }
+ if (EPIN_EN(opts)) {
+ hs_audio_desc[i++] = USBDHDR(&io_in_it_desc);
+ hs_audio_desc[i++] = USBDHDR(&usb_in_ot_desc);
+ }
+ if (EPOUT_EN(opts)) {
+ hs_audio_desc[i++] = USBDHDR(&io_out_ot_desc);
+ hs_audio_desc[i++] = USBDHDR(&std_as_out_if0_desc);
+ hs_audio_desc[i++] = USBDHDR(&std_as_out_if1_desc);
+ hs_audio_desc[i++] = USBDHDR(&as_out_hdr_desc);
+ hs_audio_desc[i++] = USBDHDR(&as_out_fmt1_desc);
+ hs_audio_desc[i++] = USBDHDR(&hs_epout_desc);
+ hs_audio_desc[i++] = USBDHDR(&as_iso_out_desc);
+ }
+ if (EPIN_EN(opts)) {
+ hs_audio_desc[i++] = USBDHDR(&std_as_in_if0_desc);
+ hs_audio_desc[i++] = USBDHDR(&std_as_in_if1_desc);
+ hs_audio_desc[i++] = USBDHDR(&as_in_hdr_desc);
+ hs_audio_desc[i++] = USBDHDR(&as_in_fmt1_desc);
+ hs_audio_desc[i++] = USBDHDR(&hs_epin_desc);
+ hs_audio_desc[i++] = USBDHDR(&as_iso_in_desc);
+ }
+ hs_audio_desc[i] = NULL;
+}
+
static int
afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
{
@@ -530,25 +648,29 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
uac2->ac_intf = ret;
uac2->ac_alt = 0;
- ret = usb_interface_id(cfg, fn);
- if (ret < 0) {
- dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
- return ret;
+ if (EPOUT_EN(uac2_opts)) {
+ ret = usb_interface_id(cfg, fn);
+ if (ret < 0) {
+ dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
+ return ret;
+ }
+ std_as_out_if0_desc.bInterfaceNumber = ret;
+ std_as_out_if1_desc.bInterfaceNumber = ret;
+ uac2->as_out_intf = ret;
+ uac2->as_out_alt = 0;
}
- std_as_out_if0_desc.bInterfaceNumber = ret;
- std_as_out_if1_desc.bInterfaceNumber = ret;
- uac2->as_out_intf = ret;
- uac2->as_out_alt = 0;
- ret = usb_interface_id(cfg, fn);
- if (ret < 0) {
- dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
- return ret;
+ if (EPIN_EN(uac2_opts)) {
+ ret = usb_interface_id(cfg, fn);
+ if (ret < 0) {
+ dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
+ return ret;
+ }
+ std_as_in_if0_desc.bInterfaceNumber = ret;
+ std_as_in_if1_desc.bInterfaceNumber = ret;
+ uac2->as_in_intf = ret;
+ uac2->as_in_alt = 0;
}
- std_as_in_if0_desc.bInterfaceNumber = ret;
- std_as_in_if1_desc.bInterfaceNumber = ret;
- uac2->as_in_intf = ret;
- uac2->as_in_alt = 0;
/* Calculate wMaxPacketSize according to audio bandwidth */
set_ep_max_packet_size(uac2_opts, &fs_epin_desc, 1000, true);
@@ -556,16 +678,20 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
set_ep_max_packet_size(uac2_opts, &hs_epin_desc, 8000, true);
set_ep_max_packet_size(uac2_opts, &hs_epout_desc, 8000, false);
- agdev->out_ep = usb_ep_autoconfig(gadget, &fs_epout_desc);
- if (!agdev->out_ep) {
- dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
- return -ENODEV;
+ if (EPOUT_EN(uac2_opts)) {
+ agdev->out_ep = usb_ep_autoconfig(gadget, &fs_epout_desc);
+ if (!agdev->out_ep) {
+ dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
+ return -ENODEV;
+ }
}
- agdev->in_ep = usb_ep_autoconfig(gadget, &fs_epin_desc);
- if (!agdev->in_ep) {
- dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
- return -ENODEV;
+ if (EPIN_EN(uac2_opts)) {
+ agdev->in_ep = usb_ep_autoconfig(gadget, &fs_epin_desc);
+ if (!agdev->in_ep) {
+ dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
+ return -ENODEV;
+ }
}
agdev->in_ep_maxpsize = max_t(u16,
@@ -578,6 +704,8 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress;
hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress;
+ setup_descriptor(uac2_opts);
+
ret = usb_assign_descriptors(fn, fs_audio_desc, hs_audio_desc, NULL,
NULL);
if (ret)
diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
index d8ce7868fe22..8c99392df593 100644
--- a/drivers/usb/gadget/function/f_uvc.c
+++ b/drivers/usb/gadget/function/f_uvc.c
@@ -197,12 +197,6 @@ static const struct usb_descriptor_header * const uvc_ss_streaming[] = {
NULL,
};
-void uvc_set_trace_param(unsigned int trace)
-{
- uvc_gadget_trace_param = trace;
-}
-EXPORT_SYMBOL(uvc_set_trace_param);
-
/* --------------------------------------------------------------------------
* Control requests
*/
@@ -232,13 +226,8 @@ uvc_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
struct v4l2_event v4l2_event;
struct uvc_event *uvc_event = (void *)&v4l2_event.u.data;
- /* printk(KERN_INFO "setup request %02x %02x value %04x index %04x %04x\n",
- * ctrl->bRequestType, ctrl->bRequest, le16_to_cpu(ctrl->wValue),
- * le16_to_cpu(ctrl->wIndex), le16_to_cpu(ctrl->wLength));
- */
-
if ((ctrl->bRequestType & USB_TYPE_MASK) != USB_TYPE_CLASS) {
- INFO(f->config->cdev, "invalid request type\n");
+ uvcg_info(f, "invalid request type\n");
return -EINVAL;
}
@@ -272,7 +261,7 @@ uvc_function_get_alt(struct usb_function *f, unsigned interface)
{
struct uvc_device *uvc = to_uvc(f);
- INFO(f->config->cdev, "uvc_function_get_alt(%u)\n", interface);
+ uvcg_info(f, "%s(%u)\n", __func__, interface);
if (interface == uvc->control_intf)
return 0;
@@ -291,13 +280,13 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
struct uvc_event *uvc_event = (void *)&v4l2_event.u.data;
int ret;
- INFO(cdev, "uvc_function_set_alt(%u, %u)\n", interface, alt);
+ uvcg_info(f, "%s(%u, %u)\n", __func__, interface, alt);
if (interface == uvc->control_intf) {
if (alt)
return -EINVAL;
- INFO(cdev, "reset UVC Control\n");
+ uvcg_info(f, "reset UVC Control\n");
usb_ep_disable(uvc->control_ep);
if (!uvc->control_ep->desc)
@@ -348,7 +337,7 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
if (!uvc->video.ep)
return -EINVAL;
- INFO(cdev, "reset UVC\n");
+ uvcg_info(f, "reset UVC\n");
usb_ep_disable(uvc->video.ep);
ret = config_ep_by_speed(f->config->cdev->gadget,
@@ -373,7 +362,7 @@ uvc_function_disable(struct usb_function *f)
struct uvc_device *uvc = to_uvc(f);
struct v4l2_event v4l2_event;
- INFO(f->config->cdev, "uvc_function_disable\n");
+ uvcg_info(f, "%s()\n", __func__);
memset(&v4l2_event, 0, sizeof(v4l2_event));
v4l2_event.type = UVC_EVENT_DISCONNECT;
@@ -392,21 +381,19 @@ uvc_function_disable(struct usb_function *f)
void
uvc_function_connect(struct uvc_device *uvc)
{
- struct usb_composite_dev *cdev = uvc->func.config->cdev;
int ret;
if ((ret = usb_function_activate(&uvc->func)) < 0)
- INFO(cdev, "UVC connect failed with %d\n", ret);
+ uvcg_info(&uvc->func, "UVC connect failed with %d\n", ret);
}
void
uvc_function_disconnect(struct uvc_device *uvc)
{
- struct usb_composite_dev *cdev = uvc->func.config->cdev;
int ret;
if ((ret = usb_function_deactivate(&uvc->func)) < 0)
- INFO(cdev, "UVC disconnect failed with %d\n", ret);
+ uvcg_info(&uvc->func, "UVC disconnect failed with %d\n", ret);
}
/* --------------------------------------------------------------------------
@@ -605,7 +592,7 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
struct f_uvc_opts *opts;
int ret = -EINVAL;
- INFO(cdev, "uvc_function_bind\n");
+ uvcg_info(f, "%s()\n", __func__);
opts = fi_to_f_uvc_opts(f->fi);
/* Sanity check the streaming endpoint module parameters.
@@ -618,8 +605,8 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
if (opts->streaming_maxburst &&
(opts->streaming_maxpacket % 1024) != 0) {
opts->streaming_maxpacket = roundup(opts->streaming_maxpacket, 1024);
- INFO(cdev, "overriding streaming_maxpacket to %d\n",
- opts->streaming_maxpacket);
+ uvcg_info(f, "overriding streaming_maxpacket to %d\n",
+ opts->streaming_maxpacket);
}
/* Fill in the FS/HS/SS Video Streaming specific descriptors from the
@@ -658,7 +645,7 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
/* Allocate endpoints. */
ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep);
if (!ep) {
- INFO(cdev, "Unable to allocate control EP\n");
+ uvcg_info(f, "Unable to allocate control EP\n");
goto error;
}
uvc->control_ep = ep;
@@ -672,7 +659,7 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep);
if (!ep) {
- INFO(cdev, "Unable to allocate streaming EP\n");
+ uvcg_info(f, "Unable to allocate streaming EP\n");
goto error;
}
uvc->video.ep = ep;
@@ -699,12 +686,14 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
uvc_iad.bFirstInterface = ret;
uvc_control_intf.bInterfaceNumber = ret;
uvc->control_intf = ret;
+ opts->control_interface = ret;
if ((ret = usb_interface_id(c, f)) < 0)
goto error;
uvc_streaming_intf_alt0.bInterfaceNumber = ret;
uvc_streaming_intf_alt1.bInterfaceNumber = ret;
uvc->streaming_intf = ret;
+ opts->streaming_interface = ret;
/* Copy descriptors */
f->fs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL);
@@ -743,19 +732,19 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
uvc->control_req->context = uvc;
if (v4l2_device_register(&cdev->gadget->dev, &uvc->v4l2_dev)) {
- printk(KERN_INFO "v4l2_device_register failed\n");
+ uvcg_err(f, "failed to register V4L2 device\n");
goto error;
}
/* Initialise video. */
- ret = uvcg_video_init(&uvc->video);
+ ret = uvcg_video_init(&uvc->video, uvc);
if (ret < 0)
goto error;
/* Register a V4L2 device. */
ret = uvc_register_video(uvc);
if (ret < 0) {
- printk(KERN_INFO "Unable to register video device\n");
+ uvcg_err(f, "failed to register video device\n");
goto error;
}
@@ -792,6 +781,7 @@ static struct usb_function_instance *uvc_alloc_inst(void)
struct uvc_output_terminal_descriptor *od;
struct uvc_color_matching_descriptor *md;
struct uvc_descriptor_header **ctl_cls;
+ int ret;
opts = kzalloc(sizeof(*opts), GFP_KERNEL);
if (!opts)
@@ -868,7 +858,12 @@ static struct usb_function_instance *uvc_alloc_inst(void)
opts->streaming_interval = 1;
opts->streaming_maxpacket = 1024;
- uvcg_attach_configfs(opts);
+ ret = uvcg_attach_configfs(opts);
+ if (ret < 0) {
+ kfree(opts);
+ return ERR_PTR(ret);
+ }
+
return &opts->func_inst;
}
@@ -886,7 +881,7 @@ static void uvc_unbind(struct usb_configuration *c, struct usb_function *f)
struct usb_composite_dev *cdev = c->cdev;
struct uvc_device *uvc = to_uvc(f);
- INFO(cdev, "%s\n", __func__);
+ uvcg_info(f, "%s\n", __func__);
device_remove_file(&uvc->vdev.dev, &dev_attr_function_name);
video_unregister_device(&uvc->vdev);
diff --git a/drivers/usb/gadget/function/u_uvc.h b/drivers/usb/gadget/function/u_uvc.h
index 2ed292e94fbc..5242d489e20a 100644
--- a/drivers/usb/gadget/function/u_uvc.h
+++ b/drivers/usb/gadget/function/u_uvc.h
@@ -25,6 +25,9 @@ struct f_uvc_opts {
unsigned int streaming_maxpacket;
unsigned int streaming_maxburst;
+ unsigned int control_interface;
+ unsigned int streaming_interface;
+
/*
* Control descriptors array pointers for full-/high-speed and
* super-speed. They point by default to the uvc_fs_control_cls and
diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h
index 93cf78b420fe..099d650082e5 100644
--- a/drivers/usb/gadget/function/uvc.h
+++ b/drivers/usb/gadget/function/uvc.h
@@ -24,6 +24,7 @@
struct usb_ep;
struct usb_request;
struct uvc_descriptor_header;
+struct uvc_device;
/* ------------------------------------------------------------------------
* Debugging, printing and logging
@@ -51,14 +52,12 @@ extern unsigned int uvc_gadget_trace_param;
printk(KERN_DEBUG "uvcvideo: " msg); \
} while (0)
-#define uvc_warn_once(dev, warn, msg...) \
- do { \
- if (!test_and_set_bit(warn, &dev->warnings)) \
- printk(KERN_INFO "uvcvideo: " msg); \
- } while (0)
-
-#define uvc_printk(level, msg...) \
- printk(level "uvcvideo: " msg)
+#define uvcg_dbg(f, fmt, args...) \
+ dev_dbg(&(f)->config->cdev->gadget->dev, "%s: " fmt, (f)->name, ##args)
+#define uvcg_info(f, fmt, args...) \
+ dev_info(&(f)->config->cdev->gadget->dev, "%s: " fmt, (f)->name, ##args)
+#define uvcg_err(f, fmt, args...) \
+ dev_err(&(f)->config->cdev->gadget->dev, "%s: " fmt, (f)->name, ##args)
/* ------------------------------------------------------------------------
* Driver specific constants
@@ -73,6 +72,7 @@ extern unsigned int uvc_gadget_trace_param;
*/
struct uvc_video {
+ struct uvc_device *uvc;
struct usb_ep *ep;
/* Frame parameters */
diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c
index b51f0d278826..bc1e2af566c3 100644
--- a/drivers/usb/gadget/function/uvc_configfs.c
+++ b/drivers/usb/gadget/function/uvc_configfs.c
@@ -9,9 +9,16 @@
*
* Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
*/
+
+#include <linux/sort.h>
+
#include "u_uvc.h"
#include "uvc_configfs.h"
+/* -----------------------------------------------------------------------------
+ * Global Utility Structures and Macros
+ */
+
#define UVCG_STREAMING_CONTROL_SIZE 1
#define UVC_ATTR(prefix, cname, aname) \
@@ -31,13 +38,93 @@ static struct configfs_attribute prefix##attr_##cname = { \
.show = prefix##cname##_show, \
}
+#define le8_to_cpu(x) (x)
+#define cpu_to_le8(x) (x)
+
+static int uvcg_config_compare_u32(const void *l, const void *r)
+{
+ u32 li = *(const u32 *)l;
+ u32 ri = *(const u32 *)r;
+
+ return li < ri ? -1 : li == ri ? 0 : 1;
+}
+
static inline struct f_uvc_opts *to_f_uvc_opts(struct config_item *item)
{
return container_of(to_config_group(item), struct f_uvc_opts,
func_inst.group);
}
-/* control/header/<NAME> */
+struct uvcg_config_group_type {
+ struct config_item_type type;
+ const char *name;
+ const struct uvcg_config_group_type **children;
+ int (*create_children)(struct config_group *group);
+};
+
+static void uvcg_config_item_release(struct config_item *item)
+{
+ struct config_group *group = to_config_group(item);
+
+ kfree(group);
+}
+
+static struct configfs_item_operations uvcg_config_item_ops = {
+ .release = uvcg_config_item_release,
+};
+
+static int uvcg_config_create_group(struct config_group *parent,
+ const struct uvcg_config_group_type *type);
+
+static int uvcg_config_create_children(struct config_group *group,
+ const struct uvcg_config_group_type *type)
+{
+ const struct uvcg_config_group_type **child;
+ int ret;
+
+ if (type->create_children)
+ return type->create_children(group);
+
+ for (child = type->children; child && *child; ++child) {
+ ret = uvcg_config_create_group(group, *child);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int uvcg_config_create_group(struct config_group *parent,
+ const struct uvcg_config_group_type *type)
+{
+ struct config_group *group;
+
+ group = kzalloc(sizeof(*group), GFP_KERNEL);
+ if (!group)
+ return -ENOMEM;
+
+ config_group_init_type_name(group, type->name, &type->type);
+ configfs_add_default_group(group, parent);
+
+ return uvcg_config_create_children(group, type);
+}
+
+static void uvcg_config_remove_children(struct config_group *group)
+{
+ struct config_group *child, *n;
+
+ list_for_each_entry_safe(child, n, &group->default_groups, group_entry) {
+ list_del(&child->group_entry);
+ uvcg_config_remove_children(child);
+ config_item_put(&child->cg_item);
+ }
+}
+
+/* -----------------------------------------------------------------------------
+ * control/header/<NAME>
+ * control/header
+ */
+
DECLARE_UVC_HEADER_DESCRIPTOR(1);
struct uvcg_control_header {
@@ -51,9 +138,9 @@ static struct uvcg_control_header *to_uvcg_control_header(struct config_item *it
return container_of(item, struct uvcg_control_header, item);
}
-#define UVCG_CTRL_HDR_ATTR(cname, aname, conv, str2u, uxx, vnoc, limit) \
+#define UVCG_CTRL_HDR_ATTR(cname, aname, bits, limit) \
static ssize_t uvcg_control_header_##cname##_show( \
- struct config_item *item, char *page) \
+ struct config_item *item, char *page) \
{ \
struct uvcg_control_header *ch = to_uvcg_control_header(item); \
struct f_uvc_opts *opts; \
@@ -67,7 +154,7 @@ static ssize_t uvcg_control_header_##cname##_show( \
opts = to_f_uvc_opts(opts_item); \
\
mutex_lock(&opts->lock); \
- result = sprintf(page, "%d\n", conv(ch->desc.aname)); \
+ result = sprintf(page, "%u\n", le##bits##_to_cpu(ch->desc.aname));\
mutex_unlock(&opts->lock); \
\
mutex_unlock(su_mutex); \
@@ -83,7 +170,7 @@ uvcg_control_header_##cname##_store(struct config_item *item, \
struct config_item *opts_item; \
struct mutex *su_mutex = &ch->item.ci_group->cg_subsys->su_mutex;\
int ret; \
- uxx num; \
+ u##bits num; \
\
mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
\
@@ -96,7 +183,7 @@ uvcg_control_header_##cname##_store(struct config_item *item, \
goto end; \
} \
\
- ret = str2u(page, 0, &num); \
+ ret = kstrtou##bits(page, 0, &num); \
if (ret) \
goto end; \
\
@@ -104,7 +191,7 @@ uvcg_control_header_##cname##_store(struct config_item *item, \
ret = -EINVAL; \
goto end; \
} \
- ch->desc.aname = vnoc(num); \
+ ch->desc.aname = cpu_to_le##bits(num); \
ret = len; \
end: \
mutex_unlock(&opts->lock); \
@@ -114,11 +201,9 @@ end: \
\
UVC_ATTR(uvcg_control_header_, cname, aname)
-UVCG_CTRL_HDR_ATTR(bcd_uvc, bcdUVC, le16_to_cpu, kstrtou16, u16, cpu_to_le16,
- 0xffff);
+UVCG_CTRL_HDR_ATTR(bcd_uvc, bcdUVC, 16, 0xffff);
-UVCG_CTRL_HDR_ATTR(dw_clock_frequency, dwClockFrequency, le32_to_cpu, kstrtou32,
- u32, cpu_to_le32, 0x7fffffff);
+UVCG_CTRL_HDR_ATTR(dw_clock_frequency, dwClockFrequency, 32, 0x7fffffff);
#undef UVCG_CTRL_HDR_ATTR
@@ -129,6 +214,7 @@ static struct configfs_attribute *uvcg_control_header_attrs[] = {
};
static const struct config_item_type uvcg_control_header_type = {
+ .ct_item_ops = &uvcg_config_item_ops,
.ct_attrs = uvcg_control_header_attrs,
.ct_owner = THIS_MODULE,
};
@@ -153,60 +239,42 @@ static struct config_item *uvcg_control_header_make(struct config_group *group,
return &h->item;
}
-static void uvcg_control_header_drop(struct config_group *group,
- struct config_item *item)
-{
- struct uvcg_control_header *h = to_uvcg_control_header(item);
-
- kfree(h);
-}
-
-/* control/header */
-static struct uvcg_control_header_grp {
- struct config_group group;
-} uvcg_control_header_grp;
-
static struct configfs_group_operations uvcg_control_header_grp_ops = {
.make_item = uvcg_control_header_make,
- .drop_item = uvcg_control_header_drop,
};
-static const struct config_item_type uvcg_control_header_grp_type = {
- .ct_group_ops = &uvcg_control_header_grp_ops,
- .ct_owner = THIS_MODULE,
+static const struct uvcg_config_group_type uvcg_control_header_grp_type = {
+ .type = {
+ .ct_item_ops = &uvcg_config_item_ops,
+ .ct_group_ops = &uvcg_control_header_grp_ops,
+ .ct_owner = THIS_MODULE,
+ },
+ .name = "header",
};
-/* control/processing/default */
-static struct uvcg_default_processing {
- struct config_group group;
-} uvcg_default_processing;
-
-static inline struct uvcg_default_processing
-*to_uvcg_default_processing(struct config_item *item)
-{
- return container_of(to_config_group(item),
- struct uvcg_default_processing, group);
-}
+/* -----------------------------------------------------------------------------
+ * control/processing/default
+ */
-#define UVCG_DEFAULT_PROCESSING_ATTR(cname, aname, conv) \
+#define UVCG_DEFAULT_PROCESSING_ATTR(cname, aname, bits) \
static ssize_t uvcg_default_processing_##cname##_show( \
struct config_item *item, char *page) \
{ \
- struct uvcg_default_processing *dp = to_uvcg_default_processing(item); \
+ struct config_group *group = to_config_group(item); \
struct f_uvc_opts *opts; \
struct config_item *opts_item; \
- struct mutex *su_mutex = &dp->group.cg_subsys->su_mutex; \
+ struct mutex *su_mutex = &group->cg_subsys->su_mutex; \
struct uvc_processing_unit_descriptor *pd; \
int result; \
\
mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
\
- opts_item = dp->group.cg_item.ci_parent->ci_parent->ci_parent; \
+ opts_item = group->cg_item.ci_parent->ci_parent->ci_parent; \
opts = to_f_uvc_opts(opts_item); \
pd = &opts->uvc_processing; \
\
mutex_lock(&opts->lock); \
- result = sprintf(page, "%d\n", conv(pd->aname)); \
+ result = sprintf(page, "%u\n", le##bits##_to_cpu(pd->aname)); \
mutex_unlock(&opts->lock); \
\
mutex_unlock(su_mutex); \
@@ -215,37 +283,33 @@ static ssize_t uvcg_default_processing_##cname##_show( \
\
UVC_ATTR_RO(uvcg_default_processing_, cname, aname)
-#define identity_conv(x) (x)
-
-UVCG_DEFAULT_PROCESSING_ATTR(b_unit_id, bUnitID, identity_conv);
-UVCG_DEFAULT_PROCESSING_ATTR(b_source_id, bSourceID, identity_conv);
-UVCG_DEFAULT_PROCESSING_ATTR(w_max_multiplier, wMaxMultiplier, le16_to_cpu);
-UVCG_DEFAULT_PROCESSING_ATTR(i_processing, iProcessing, identity_conv);
-
-#undef identity_conv
+UVCG_DEFAULT_PROCESSING_ATTR(b_unit_id, bUnitID, 8);
+UVCG_DEFAULT_PROCESSING_ATTR(b_source_id, bSourceID, 8);
+UVCG_DEFAULT_PROCESSING_ATTR(w_max_multiplier, wMaxMultiplier, 16);
+UVCG_DEFAULT_PROCESSING_ATTR(i_processing, iProcessing, 8);
#undef UVCG_DEFAULT_PROCESSING_ATTR
static ssize_t uvcg_default_processing_bm_controls_show(
struct config_item *item, char *page)
{
- struct uvcg_default_processing *dp = to_uvcg_default_processing(item);
+ struct config_group *group = to_config_group(item);
struct f_uvc_opts *opts;
struct config_item *opts_item;
- struct mutex *su_mutex = &dp->group.cg_subsys->su_mutex;
+ struct mutex *su_mutex = &group->cg_subsys->su_mutex;
struct uvc_processing_unit_descriptor *pd;
int result, i;
char *pg = page;
mutex_lock(su_mutex); /* for navigating configfs hierarchy */
- opts_item = dp->group.cg_item.ci_parent->ci_parent->ci_parent;
+ opts_item = group->cg_item.ci_parent->ci_parent->ci_parent;
opts = to_f_uvc_opts(opts_item);
pd = &opts->uvc_processing;
mutex_lock(&opts->lock);
for (result = 0, i = 0; i < pd->bControlSize; ++i) {
- result += sprintf(pg, "%d\n", pd->bmControls[i]);
+ result += sprintf(pg, "%u\n", pd->bmControls[i]);
pg = page + result;
}
mutex_unlock(&opts->lock);
@@ -266,54 +330,55 @@ static struct configfs_attribute *uvcg_default_processing_attrs[] = {
NULL,
};
-static const struct config_item_type uvcg_default_processing_type = {
- .ct_attrs = uvcg_default_processing_attrs,
- .ct_owner = THIS_MODULE,
+static const struct uvcg_config_group_type uvcg_default_processing_type = {
+ .type = {
+ .ct_item_ops = &uvcg_config_item_ops,
+ .ct_attrs = uvcg_default_processing_attrs,
+ .ct_owner = THIS_MODULE,
+ },
+ .name = "default",
};
-/* struct uvcg_processing {}; */
-
-/* control/processing */
-static struct uvcg_processing_grp {
- struct config_group group;
-} uvcg_processing_grp;
+/* -----------------------------------------------------------------------------
+ * control/processing
+ */
-static const struct config_item_type uvcg_processing_grp_type = {
- .ct_owner = THIS_MODULE,
+static const struct uvcg_config_group_type uvcg_processing_grp_type = {
+ .type = {
+ .ct_item_ops = &uvcg_config_item_ops,
+ .ct_owner = THIS_MODULE,
+ },
+ .name = "processing",
+ .children = (const struct uvcg_config_group_type*[]) {
+ &uvcg_default_processing_type,
+ NULL,
+ },
};
-/* control/terminal/camera/default */
-static struct uvcg_default_camera {
- struct config_group group;
-} uvcg_default_camera;
-
-static inline struct uvcg_default_camera
-*to_uvcg_default_camera(struct config_item *item)
-{
- return container_of(to_config_group(item),
- struct uvcg_default_camera, group);
-}
+/* -----------------------------------------------------------------------------
+ * control/terminal/camera/default
+ */
-#define UVCG_DEFAULT_CAMERA_ATTR(cname, aname, conv) \
+#define UVCG_DEFAULT_CAMERA_ATTR(cname, aname, bits) \
static ssize_t uvcg_default_camera_##cname##_show( \
struct config_item *item, char *page) \
{ \
- struct uvcg_default_camera *dc = to_uvcg_default_camera(item); \
+ struct config_group *group = to_config_group(item); \
struct f_uvc_opts *opts; \
struct config_item *opts_item; \
- struct mutex *su_mutex = &dc->group.cg_subsys->su_mutex; \
+ struct mutex *su_mutex = &group->cg_subsys->su_mutex; \
struct uvc_camera_terminal_descriptor *cd; \
int result; \
\
mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
\
- opts_item = dc->group.cg_item.ci_parent->ci_parent->ci_parent-> \
+ opts_item = group->cg_item.ci_parent->ci_parent->ci_parent-> \
ci_parent; \
opts = to_f_uvc_opts(opts_item); \
cd = &opts->uvc_camera_terminal; \
\
mutex_lock(&opts->lock); \
- result = sprintf(page, "%d\n", conv(cd->aname)); \
+ result = sprintf(page, "%u\n", le##bits##_to_cpu(cd->aname)); \
mutex_unlock(&opts->lock); \
\
mutex_unlock(su_mutex); \
@@ -323,44 +388,40 @@ static ssize_t uvcg_default_camera_##cname##_show( \
\
UVC_ATTR_RO(uvcg_default_camera_, cname, aname)
-#define identity_conv(x) (x)
-
-UVCG_DEFAULT_CAMERA_ATTR(b_terminal_id, bTerminalID, identity_conv);
-UVCG_DEFAULT_CAMERA_ATTR(w_terminal_type, wTerminalType, le16_to_cpu);
-UVCG_DEFAULT_CAMERA_ATTR(b_assoc_terminal, bAssocTerminal, identity_conv);
-UVCG_DEFAULT_CAMERA_ATTR(i_terminal, iTerminal, identity_conv);
+UVCG_DEFAULT_CAMERA_ATTR(b_terminal_id, bTerminalID, 8);
+UVCG_DEFAULT_CAMERA_ATTR(w_terminal_type, wTerminalType, 16);
+UVCG_DEFAULT_CAMERA_ATTR(b_assoc_terminal, bAssocTerminal, 8);
+UVCG_DEFAULT_CAMERA_ATTR(i_terminal, iTerminal, 8);
UVCG_DEFAULT_CAMERA_ATTR(w_objective_focal_length_min, wObjectiveFocalLengthMin,
- le16_to_cpu);
+ 16);
UVCG_DEFAULT_CAMERA_ATTR(w_objective_focal_length_max, wObjectiveFocalLengthMax,
- le16_to_cpu);
+ 16);
UVCG_DEFAULT_CAMERA_ATTR(w_ocular_focal_length, wOcularFocalLength,
- le16_to_cpu);
-
-#undef identity_conv
+ 16);
#undef UVCG_DEFAULT_CAMERA_ATTR
static ssize_t uvcg_default_camera_bm_controls_show(
struct config_item *item, char *page)
{
- struct uvcg_default_camera *dc = to_uvcg_default_camera(item);
+ struct config_group *group = to_config_group(item);
struct f_uvc_opts *opts;
struct config_item *opts_item;
- struct mutex *su_mutex = &dc->group.cg_subsys->su_mutex;
+ struct mutex *su_mutex = &group->cg_subsys->su_mutex;
struct uvc_camera_terminal_descriptor *cd;
int result, i;
char *pg = page;
mutex_lock(su_mutex); /* for navigating configfs hierarchy */
- opts_item = dc->group.cg_item.ci_parent->ci_parent->ci_parent->
+ opts_item = group->cg_item.ci_parent->ci_parent->ci_parent->
ci_parent;
opts = to_f_uvc_opts(opts_item);
cd = &opts->uvc_camera_terminal;
mutex_lock(&opts->lock);
for (result = 0, i = 0; i < cd->bControlSize; ++i) {
- result += sprintf(pg, "%d\n", cd->bmControls[i]);
+ result += sprintf(pg, "%u\n", cd->bmControls[i]);
pg = page + result;
}
mutex_unlock(&opts->lock);
@@ -383,54 +444,55 @@ static struct configfs_attribute *uvcg_default_camera_attrs[] = {
NULL,
};
-static const struct config_item_type uvcg_default_camera_type = {
- .ct_attrs = uvcg_default_camera_attrs,
- .ct_owner = THIS_MODULE,
+static const struct uvcg_config_group_type uvcg_default_camera_type = {
+ .type = {
+ .ct_item_ops = &uvcg_config_item_ops,
+ .ct_attrs = uvcg_default_camera_attrs,
+ .ct_owner = THIS_MODULE,
+ },
+ .name = "default",
};
-/* struct uvcg_camera {}; */
-
-/* control/terminal/camera */
-static struct uvcg_camera_grp {
- struct config_group group;
-} uvcg_camera_grp;
+/* -----------------------------------------------------------------------------
+ * control/terminal/camera
+ */
-static const struct config_item_type uvcg_camera_grp_type = {
- .ct_owner = THIS_MODULE,
+static const struct uvcg_config_group_type uvcg_camera_grp_type = {
+ .type = {
+ .ct_item_ops = &uvcg_config_item_ops,
+ .ct_owner = THIS_MODULE,
+ },
+ .name = "camera",
+ .children = (const struct uvcg_config_group_type*[]) {
+ &uvcg_default_camera_type,
+ NULL,
+ },
};
-/* control/terminal/output/default */
-static struct uvcg_default_output {
- struct config_group group;
-} uvcg_default_output;
-
-static inline struct uvcg_default_output
-*to_uvcg_default_output(struct config_item *item)
-{
- return container_of(to_config_group(item),
- struct uvcg_default_output, group);
-}
+/* -----------------------------------------------------------------------------
+ * control/terminal/output/default
+ */
-#define UVCG_DEFAULT_OUTPUT_ATTR(cname, aname, conv) \
+#define UVCG_DEFAULT_OUTPUT_ATTR(cname, aname, bits) \
static ssize_t uvcg_default_output_##cname##_show( \
- struct config_item *item, char *page) \
+ struct config_item *item, char *page) \
{ \
- struct uvcg_default_output *dout = to_uvcg_default_output(item); \
+ struct config_group *group = to_config_group(item); \
struct f_uvc_opts *opts; \
struct config_item *opts_item; \
- struct mutex *su_mutex = &dout->group.cg_subsys->su_mutex; \
+ struct mutex *su_mutex = &group->cg_subsys->su_mutex; \
struct uvc_output_terminal_descriptor *cd; \
int result; \
\
mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
\
- opts_item = dout->group.cg_item.ci_parent->ci_parent-> \
+ opts_item = group->cg_item.ci_parent->ci_parent-> \
ci_parent->ci_parent; \
opts = to_f_uvc_opts(opts_item); \
cd = &opts->uvc_output_terminal; \
\
mutex_lock(&opts->lock); \
- result = sprintf(page, "%d\n", conv(cd->aname)); \
+ result = sprintf(page, "%u\n", le##bits##_to_cpu(cd->aname)); \
mutex_unlock(&opts->lock); \
\
mutex_unlock(su_mutex); \
@@ -440,15 +502,11 @@ static ssize_t uvcg_default_output_##cname##_show( \
\
UVC_ATTR_RO(uvcg_default_output_, cname, aname)
-#define identity_conv(x) (x)
-
-UVCG_DEFAULT_OUTPUT_ATTR(b_terminal_id, bTerminalID, identity_conv);
-UVCG_DEFAULT_OUTPUT_ATTR(w_terminal_type, wTerminalType, le16_to_cpu);
-UVCG_DEFAULT_OUTPUT_ATTR(b_assoc_terminal, bAssocTerminal, identity_conv);
-UVCG_DEFAULT_OUTPUT_ATTR(b_source_id, bSourceID, identity_conv);
-UVCG_DEFAULT_OUTPUT_ATTR(i_terminal, iTerminal, identity_conv);
-
-#undef identity_conv
+UVCG_DEFAULT_OUTPUT_ATTR(b_terminal_id, bTerminalID, 8);
+UVCG_DEFAULT_OUTPUT_ATTR(w_terminal_type, wTerminalType, 16);
+UVCG_DEFAULT_OUTPUT_ATTR(b_assoc_terminal, bAssocTerminal, 8);
+UVCG_DEFAULT_OUTPUT_ATTR(b_source_id, bSourceID, 8);
+UVCG_DEFAULT_OUTPUT_ATTR(i_terminal, iTerminal, 8);
#undef UVCG_DEFAULT_OUTPUT_ATTR
@@ -461,47 +519,68 @@ static struct configfs_attribute *uvcg_default_output_attrs[] = {
NULL,
};
-static const struct config_item_type uvcg_default_output_type = {
- .ct_attrs = uvcg_default_output_attrs,
- .ct_owner = THIS_MODULE,
+static const struct uvcg_config_group_type uvcg_default_output_type = {
+ .type = {
+ .ct_item_ops = &uvcg_config_item_ops,
+ .ct_attrs = uvcg_default_output_attrs,
+ .ct_owner = THIS_MODULE,
+ },
+ .name = "default",
};
-/* struct uvcg_output {}; */
-
-/* control/terminal/output */
-static struct uvcg_output_grp {
- struct config_group group;
-} uvcg_output_grp;
+/* -----------------------------------------------------------------------------
+ * control/terminal/output
+ */
-static const struct config_item_type uvcg_output_grp_type = {
- .ct_owner = THIS_MODULE,
+static const struct uvcg_config_group_type uvcg_output_grp_type = {
+ .type = {
+ .ct_item_ops = &uvcg_config_item_ops,
+ .ct_owner = THIS_MODULE,
+ },
+ .name = "output",
+ .children = (const struct uvcg_config_group_type*[]) {
+ &uvcg_default_output_type,
+ NULL,
+ },
};
-/* control/terminal */
-static struct uvcg_terminal_grp {
- struct config_group group;
-} uvcg_terminal_grp;
+/* -----------------------------------------------------------------------------
+ * control/terminal
+ */
-static const struct config_item_type uvcg_terminal_grp_type = {
- .ct_owner = THIS_MODULE,
+static const struct uvcg_config_group_type uvcg_terminal_grp_type = {
+ .type = {
+ .ct_item_ops = &uvcg_config_item_ops,
+ .ct_owner = THIS_MODULE,
+ },
+ .name = "terminal",
+ .children = (const struct uvcg_config_group_type*[]) {
+ &uvcg_camera_grp_type,
+ &uvcg_output_grp_type,
+ NULL,
+ },
};
-/* control/class/{fs} */
-static struct uvcg_control_class {
- struct config_group group;
-} uvcg_control_class_fs, uvcg_control_class_ss;
+/* -----------------------------------------------------------------------------
+ * control/class/{fs|ss}
+ */
+struct uvcg_control_class_group {
+ struct config_group group;
+ const char *name;
+};
static inline struct uvc_descriptor_header
**uvcg_get_ctl_class_arr(struct config_item *i, struct f_uvc_opts *o)
{
- struct uvcg_control_class *cl = container_of(to_config_group(i),
- struct uvcg_control_class, group);
+ struct uvcg_control_class_group *group =
+ container_of(i, struct uvcg_control_class_group,
+ group.cg_item);
- if (cl == &uvcg_control_class_fs)
+ if (!strcmp(group->name, "fs"))
return o->uvc_fs_control_cls;
- if (cl == &uvcg_control_class_ss)
+ if (!strcmp(group->name, "ss"))
return o->uvc_ss_control_cls;
return NULL;
@@ -544,6 +623,7 @@ static int uvcg_control_class_allow_link(struct config_item *src,
unlock:
mutex_unlock(&opts->lock);
out:
+ config_item_put(header);
mutex_unlock(su_mutex);
return ret;
}
@@ -579,10 +659,12 @@ static void uvcg_control_class_drop_link(struct config_item *src,
unlock:
mutex_unlock(&opts->lock);
out:
+ config_item_put(header);
mutex_unlock(su_mutex);
}
static struct configfs_item_operations uvcg_control_class_item_ops = {
+ .release = uvcg_config_item_release,
.allow_link = uvcg_control_class_allow_link,
.drop_link = uvcg_control_class_drop_link,
};
@@ -592,37 +674,99 @@ static const struct config_item_type uvcg_control_class_type = {
.ct_owner = THIS_MODULE,
};
-/* control/class */
-static struct uvcg_control_class_grp {
- struct config_group group;
-} uvcg_control_class_grp;
+/* -----------------------------------------------------------------------------
+ * control/class
+ */
+
+static int uvcg_control_class_create_children(struct config_group *parent)
+{
+ static const char * const names[] = { "fs", "ss" };
+ unsigned int i;
-static const struct config_item_type uvcg_control_class_grp_type = {
- .ct_owner = THIS_MODULE,
+ for (i = 0; i < ARRAY_SIZE(names); ++i) {
+ struct uvcg_control_class_group *group;
+
+ group = kzalloc(sizeof(*group), GFP_KERNEL);
+ if (!group)
+ return -ENOMEM;
+
+ group->name = names[i];
+
+ config_group_init_type_name(&group->group, group->name,
+ &uvcg_control_class_type);
+ configfs_add_default_group(&group->group, parent);
+ }
+
+ return 0;
+}
+
+static const struct uvcg_config_group_type uvcg_control_class_grp_type = {
+ .type = {
+ .ct_item_ops = &uvcg_config_item_ops,
+ .ct_owner = THIS_MODULE,
+ },
+ .name = "class",
+ .create_children = uvcg_control_class_create_children,
};
-/* control */
-static struct uvcg_control_grp {
- struct config_group group;
-} uvcg_control_grp;
+/* -----------------------------------------------------------------------------
+ * control
+ */
+
+static ssize_t uvcg_default_control_b_interface_number_show(
+ struct config_item *item, char *page)
+{
+ struct config_group *group = to_config_group(item);
+ struct mutex *su_mutex = &group->cg_subsys->su_mutex;
+ struct config_item *opts_item;
+ struct f_uvc_opts *opts;
+ int result = 0;
+
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+ opts_item = item->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+
+ mutex_lock(&opts->lock);
+ result += sprintf(page, "%u\n", opts->control_interface);
+ mutex_unlock(&opts->lock);
+
+ mutex_unlock(su_mutex);
+
+ return result;
+}
+
+UVC_ATTR_RO(uvcg_default_control_, b_interface_number, bInterfaceNumber);
-static const struct config_item_type uvcg_control_grp_type = {
- .ct_owner = THIS_MODULE,
+static struct configfs_attribute *uvcg_default_control_attrs[] = {
+ &uvcg_default_control_attr_b_interface_number,
+ NULL,
};
-/* streaming/uncompressed */
-static struct uvcg_uncompressed_grp {
- struct config_group group;
-} uvcg_uncompressed_grp;
+static const struct uvcg_config_group_type uvcg_control_grp_type = {
+ .type = {
+ .ct_item_ops = &uvcg_config_item_ops,
+ .ct_attrs = uvcg_default_control_attrs,
+ .ct_owner = THIS_MODULE,
+ },
+ .name = "control",
+ .children = (const struct uvcg_config_group_type*[]) {
+ &uvcg_control_header_grp_type,
+ &uvcg_processing_grp_type,
+ &uvcg_terminal_grp_type,
+ &uvcg_control_class_grp_type,
+ NULL,
+ },
+};
-/* streaming/mjpeg */
-static struct uvcg_mjpeg_grp {
- struct config_group group;
-} uvcg_mjpeg_grp;
+/* -----------------------------------------------------------------------------
+ * streaming/uncompressed
+ * streaming/mjpeg
+ */
-static struct config_item *fmt_parent[] = {
- &uvcg_uncompressed_grp.group.cg_item,
- &uvcg_mjpeg_grp.group.cg_item,
+static const char * const uvcg_format_names[] = {
+ "uncompressed",
+ "mjpeg",
};
enum uvcg_format_type {
@@ -706,7 +850,11 @@ struct uvcg_format_ptr {
struct list_head entry;
};
-/* streaming/header/<NAME> */
+/* -----------------------------------------------------------------------------
+ * streaming/header/<NAME>
+ * streaming/header
+ */
+
struct uvcg_streaming_header {
struct config_item item;
struct uvc_input_header_descriptor desc;
@@ -720,6 +868,8 @@ static struct uvcg_streaming_header *to_uvcg_streaming_header(struct config_item
return container_of(item, struct uvcg_streaming_header, item);
}
+static void uvcg_format_set_indices(struct config_group *fmt);
+
static int uvcg_streaming_header_allow_link(struct config_item *src,
struct config_item *target)
{
@@ -744,10 +894,22 @@ static int uvcg_streaming_header_allow_link(struct config_item *src,
goto out;
}
- for (i = 0; i < ARRAY_SIZE(fmt_parent); ++i)
- if (target->ci_parent == fmt_parent[i])
+ /*
+ * Linking is only allowed to direct children of the format nodes
+ * (streaming/uncompressed or streaming/mjpeg nodes). First check that
+ * the grand-parent of the target matches the grand-parent of the source
+ * (the streaming node), and then verify that the target parent is a
+ * format node.
+ */
+ if (src->ci_parent->ci_parent != target->ci_parent->ci_parent)
+ goto out;
+
+ for (i = 0; i < ARRAY_SIZE(uvcg_format_names); ++i) {
+ if (!strcmp(target->ci_parent->ci_name, uvcg_format_names[i]))
break;
- if (i == ARRAY_SIZE(fmt_parent))
+ }
+
+ if (i == ARRAY_SIZE(uvcg_format_names))
goto out;
target_fmt = container_of(to_config_group(target), struct uvcg_format,
@@ -755,6 +917,8 @@ static int uvcg_streaming_header_allow_link(struct config_item *src,
if (!target_fmt)
goto out;
+ uvcg_format_set_indices(to_config_group(target));
+
format_ptr = kzalloc(sizeof(*format_ptr), GFP_KERNEL);
if (!format_ptr) {
ret = -ENOMEM;
@@ -764,6 +928,7 @@ static int uvcg_streaming_header_allow_link(struct config_item *src,
format_ptr->fmt = target_fmt;
list_add_tail(&format_ptr->entry, &src_hdr->formats);
++src_hdr->num_fmt;
+ ++target_fmt->linked;
out:
mutex_unlock(&opts->lock);
@@ -801,19 +966,22 @@ static void uvcg_streaming_header_drop_link(struct config_item *src,
break;
}
+ --target_fmt->linked;
+
out:
mutex_unlock(&opts->lock);
mutex_unlock(su_mutex);
}
static struct configfs_item_operations uvcg_streaming_header_item_ops = {
- .allow_link = uvcg_streaming_header_allow_link,
- .drop_link = uvcg_streaming_header_drop_link,
+ .release = uvcg_config_item_release,
+ .allow_link = uvcg_streaming_header_allow_link,
+ .drop_link = uvcg_streaming_header_drop_link,
};
-#define UVCG_STREAMING_HEADER_ATTR(cname, aname, conv) \
+#define UVCG_STREAMING_HEADER_ATTR(cname, aname, bits) \
static ssize_t uvcg_streaming_header_##cname##_show( \
- struct config_item *item, char *page) \
+ struct config_item *item, char *page) \
{ \
struct uvcg_streaming_header *sh = to_uvcg_streaming_header(item); \
struct f_uvc_opts *opts; \
@@ -827,7 +995,7 @@ static ssize_t uvcg_streaming_header_##cname##_show( \
opts = to_f_uvc_opts(opts_item); \
\
mutex_lock(&opts->lock); \
- result = sprintf(page, "%d\n", conv(sh->desc.aname)); \
+ result = sprintf(page, "%u\n", le##bits##_to_cpu(sh->desc.aname));\
mutex_unlock(&opts->lock); \
\
mutex_unlock(su_mutex); \
@@ -836,16 +1004,11 @@ static ssize_t uvcg_streaming_header_##cname##_show( \
\
UVC_ATTR_RO(uvcg_streaming_header_, cname, aname)
-#define identity_conv(x) (x)
-
-UVCG_STREAMING_HEADER_ATTR(bm_info, bmInfo, identity_conv);
-UVCG_STREAMING_HEADER_ATTR(b_terminal_link, bTerminalLink, identity_conv);
-UVCG_STREAMING_HEADER_ATTR(b_still_capture_method, bStillCaptureMethod,
- identity_conv);
-UVCG_STREAMING_HEADER_ATTR(b_trigger_support, bTriggerSupport, identity_conv);
-UVCG_STREAMING_HEADER_ATTR(b_trigger_usage, bTriggerUsage, identity_conv);
-
-#undef identity_conv
+UVCG_STREAMING_HEADER_ATTR(bm_info, bmInfo, 8);
+UVCG_STREAMING_HEADER_ATTR(b_terminal_link, bTerminalLink, 8);
+UVCG_STREAMING_HEADER_ATTR(b_still_capture_method, bStillCaptureMethod, 8);
+UVCG_STREAMING_HEADER_ATTR(b_trigger_support, bTriggerSupport, 8);
+UVCG_STREAMING_HEADER_ATTR(b_trigger_usage, bTriggerUsage, 8);
#undef UVCG_STREAMING_HEADER_ATTR
@@ -884,31 +1047,26 @@ static struct config_item
return &h->item;
}
-static void uvcg_streaming_header_drop(struct config_group *group,
- struct config_item *item)
-{
- struct uvcg_streaming_header *h = to_uvcg_streaming_header(item);
-
- kfree(h);
-}
-
-/* streaming/header */
-static struct uvcg_streaming_header_grp {
- struct config_group group;
-} uvcg_streaming_header_grp;
-
static struct configfs_group_operations uvcg_streaming_header_grp_ops = {
.make_item = uvcg_streaming_header_make,
- .drop_item = uvcg_streaming_header_drop,
};
-static const struct config_item_type uvcg_streaming_header_grp_type = {
- .ct_group_ops = &uvcg_streaming_header_grp_ops,
- .ct_owner = THIS_MODULE,
+static const struct uvcg_config_group_type uvcg_streaming_header_grp_type = {
+ .type = {
+ .ct_item_ops = &uvcg_config_item_ops,
+ .ct_group_ops = &uvcg_streaming_header_grp_ops,
+ .ct_owner = THIS_MODULE,
+ },
+ .name = "header",
};
-/* streaming/<mode>/<format>/<NAME> */
+/* -----------------------------------------------------------------------------
+ * streaming/<mode>/<format>/<NAME>
+ */
+
struct uvcg_frame {
+ struct config_item item;
+ enum uvcg_format_type fmt_type;
struct {
u8 b_length;
u8 b_descriptor_type;
@@ -924,8 +1082,6 @@ struct uvcg_frame {
u8 b_frame_interval_type;
} __attribute__((packed)) frame;
u32 *dw_frame_interval;
- enum uvcg_format_type fmt_type;
- struct config_item item;
};
static struct uvcg_frame *to_uvcg_frame(struct config_item *item)
@@ -933,7 +1089,7 @@ static struct uvcg_frame *to_uvcg_frame(struct config_item *item)
return container_of(item, struct uvcg_frame, item);
}
-#define UVCG_FRAME_ATTR(cname, aname, to_cpu_endian, to_little_endian, bits) \
+#define UVCG_FRAME_ATTR(cname, aname, bits) \
static ssize_t uvcg_frame_##cname##_show(struct config_item *item, char *page)\
{ \
struct uvcg_frame *f = to_uvcg_frame(item); \
@@ -948,7 +1104,7 @@ static ssize_t uvcg_frame_##cname##_show(struct config_item *item, char *page)\
opts = to_f_uvc_opts(opts_item); \
\
mutex_lock(&opts->lock); \
- result = sprintf(page, "%d\n", to_cpu_endian(f->frame.cname)); \
+ result = sprintf(page, "%u\n", f->frame.cname); \
mutex_unlock(&opts->lock); \
\
mutex_unlock(su_mutex); \
@@ -963,8 +1119,8 @@ static ssize_t uvcg_frame_##cname##_store(struct config_item *item, \
struct config_item *opts_item; \
struct uvcg_format *fmt; \
struct mutex *su_mutex = &f->item.ci_group->cg_subsys->su_mutex;\
+ typeof(f->frame.cname) num; \
int ret; \
- u##bits num; \
\
ret = kstrtou##bits(page, 0, &num); \
if (ret) \
@@ -982,7 +1138,7 @@ static ssize_t uvcg_frame_##cname##_store(struct config_item *item, \
goto end; \
} \
\
- f->frame.cname = to_little_endian(num); \
+ f->frame.cname = num; \
ret = len; \
end: \
mutex_unlock(&opts->lock); \
@@ -992,20 +1148,48 @@ end: \
\
UVC_ATTR(uvcg_frame_, cname, aname);
-#define noop_conversion(x) (x)
+static ssize_t uvcg_frame_b_frame_index_show(struct config_item *item,
+ char *page)
+{
+ struct uvcg_frame *f = to_uvcg_frame(item);
+ struct uvcg_format *fmt;
+ struct f_uvc_opts *opts;
+ struct config_item *opts_item;
+ struct config_item *fmt_item;
+ struct mutex *su_mutex = &f->item.ci_group->cg_subsys->su_mutex;
+ int result;
+
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+ fmt_item = f->item.ci_parent;
+ fmt = to_uvcg_format(fmt_item);
-UVCG_FRAME_ATTR(bm_capabilities, bmCapabilities, noop_conversion,
- noop_conversion, 8);
-UVCG_FRAME_ATTR(w_width, wWidth, le16_to_cpu, cpu_to_le16, 16);
-UVCG_FRAME_ATTR(w_height, wHeight, le16_to_cpu, cpu_to_le16, 16);
-UVCG_FRAME_ATTR(dw_min_bit_rate, dwMinBitRate, le32_to_cpu, cpu_to_le32, 32);
-UVCG_FRAME_ATTR(dw_max_bit_rate, dwMaxBitRate, le32_to_cpu, cpu_to_le32, 32);
-UVCG_FRAME_ATTR(dw_max_video_frame_buffer_size, dwMaxVideoFrameBufferSize,
- le32_to_cpu, cpu_to_le32, 32);
-UVCG_FRAME_ATTR(dw_default_frame_interval, dwDefaultFrameInterval,
- le32_to_cpu, cpu_to_le32, 32);
+ if (!fmt->linked) {
+ result = -EBUSY;
+ goto out;
+ }
-#undef noop_conversion
+ opts_item = fmt_item->ci_parent->ci_parent->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+
+ mutex_lock(&opts->lock);
+ result = sprintf(page, "%u\n", f->frame.b_frame_index);
+ mutex_unlock(&opts->lock);
+
+out:
+ mutex_unlock(su_mutex);
+ return result;
+}
+
+UVC_ATTR_RO(uvcg_frame_, b_frame_index, bFrameIndex);
+
+UVCG_FRAME_ATTR(bm_capabilities, bmCapabilities, 8);
+UVCG_FRAME_ATTR(w_width, wWidth, 16);
+UVCG_FRAME_ATTR(w_height, wHeight, 16);
+UVCG_FRAME_ATTR(dw_min_bit_rate, dwMinBitRate, 32);
+UVCG_FRAME_ATTR(dw_max_bit_rate, dwMaxBitRate, 32);
+UVCG_FRAME_ATTR(dw_max_video_frame_buffer_size, dwMaxVideoFrameBufferSize, 32);
+UVCG_FRAME_ATTR(dw_default_frame_interval, dwDefaultFrameInterval, 32);
#undef UVCG_FRAME_ATTR
@@ -1026,8 +1210,7 @@ static ssize_t uvcg_frame_dw_frame_interval_show(struct config_item *item,
mutex_lock(&opts->lock);
for (result = 0, i = 0; i < frm->frame.b_frame_interval_type; ++i) {
- result += sprintf(pg, "%d\n",
- le32_to_cpu(frm->dw_frame_interval[i]));
+ result += sprintf(pg, "%u\n", frm->dw_frame_interval[i]);
pg = page + result;
}
mutex_unlock(&opts->lock);
@@ -1052,7 +1235,7 @@ static inline int __uvcg_fill_frm_intrv(char *buf, void *priv)
return ret;
interv = priv;
- **interv = cpu_to_le32(num);
+ **interv = num;
++*interv;
return 0;
@@ -1129,6 +1312,8 @@ static ssize_t uvcg_frame_dw_frame_interval_store(struct config_item *item,
kfree(ch->dw_frame_interval);
ch->dw_frame_interval = frm_intrv;
ch->frame.b_frame_interval_type = n;
+ sort(ch->dw_frame_interval, n, sizeof(*ch->dw_frame_interval),
+ uvcg_config_compare_u32, NULL);
ret = len;
end:
@@ -1140,6 +1325,7 @@ end:
UVC_ATTR(uvcg_frame_, dw_frame_interval, dwFrameInterval);
static struct configfs_attribute *uvcg_frame_attrs[] = {
+ &uvcg_frame_attr_b_frame_index,
&uvcg_frame_attr_bm_capabilities,
&uvcg_frame_attr_w_width,
&uvcg_frame_attr_w_height,
@@ -1152,6 +1338,7 @@ static struct configfs_attribute *uvcg_frame_attrs[] = {
};
static const struct config_item_type uvcg_frame_type = {
+ .ct_item_ops = &uvcg_config_item_ops,
.ct_attrs = uvcg_frame_attrs,
.ct_owner = THIS_MODULE,
};
@@ -1170,12 +1357,12 @@ static struct config_item *uvcg_frame_make(struct config_group *group,
h->frame.b_descriptor_type = USB_DT_CS_INTERFACE;
h->frame.b_frame_index = 1;
- h->frame.w_width = cpu_to_le16(640);
- h->frame.w_height = cpu_to_le16(360);
- h->frame.dw_min_bit_rate = cpu_to_le32(18432000);
- h->frame.dw_max_bit_rate = cpu_to_le32(55296000);
- h->frame.dw_max_video_frame_buffer_size = cpu_to_le32(460800);
- h->frame.dw_default_frame_interval = cpu_to_le32(666666);
+ h->frame.w_width = 640;
+ h->frame.w_height = 360;
+ h->frame.dw_min_bit_rate = 18432000;
+ h->frame.dw_max_bit_rate = 55296000;
+ h->frame.dw_max_video_frame_buffer_size = 460800;
+ h->frame.dw_default_frame_interval = 666666;
opts_item = group->cg_item.ci_parent->ci_parent->ci_parent;
opts = to_f_uvc_opts(opts_item);
@@ -1203,7 +1390,6 @@ static struct config_item *uvcg_frame_make(struct config_group *group,
static void uvcg_frame_drop(struct config_group *group, struct config_item *item)
{
- struct uvcg_frame *h = to_uvcg_frame(item);
struct uvcg_format *fmt;
struct f_uvc_opts *opts;
struct config_item *opts_item;
@@ -1214,11 +1400,31 @@ static void uvcg_frame_drop(struct config_group *group, struct config_item *item
mutex_lock(&opts->lock);
fmt = to_uvcg_format(&group->cg_item);
--fmt->num_frames;
- kfree(h);
mutex_unlock(&opts->lock);
+
+ config_item_put(item);
+}
+
+static void uvcg_format_set_indices(struct config_group *fmt)
+{
+ struct config_item *ci;
+ unsigned int i = 1;
+
+ list_for_each_entry(ci, &fmt->cg_children, ci_entry) {
+ struct uvcg_frame *frm;
+
+ if (ci->ci_type != &uvcg_frame_type)
+ continue;
+
+ frm = to_uvcg_frame(ci);
+ frm->frame.b_frame_index = i++;
+ }
}
-/* streaming/uncompressed/<NAME> */
+/* -----------------------------------------------------------------------------
+ * streaming/uncompressed/<NAME>
+ */
+
struct uvcg_uncompressed {
struct uvcg_format fmt;
struct uvc_format_uncompressed desc;
@@ -1290,7 +1496,7 @@ end:
UVC_ATTR(uvcg_uncompressed_, guid_format, guidFormat);
-#define UVCG_UNCOMPRESSED_ATTR_RO(cname, aname, conv) \
+#define UVCG_UNCOMPRESSED_ATTR_RO(cname, aname, bits) \
static ssize_t uvcg_uncompressed_##cname##_show( \
struct config_item *item, char *page) \
{ \
@@ -1306,7 +1512,7 @@ static ssize_t uvcg_uncompressed_##cname##_show( \
opts = to_f_uvc_opts(opts_item); \
\
mutex_lock(&opts->lock); \
- result = sprintf(page, "%d\n", conv(u->desc.aname)); \
+ result = sprintf(page, "%u\n", le##bits##_to_cpu(u->desc.aname));\
mutex_unlock(&opts->lock); \
\
mutex_unlock(su_mutex); \
@@ -1315,7 +1521,7 @@ static ssize_t uvcg_uncompressed_##cname##_show( \
\
UVC_ATTR_RO(uvcg_uncompressed_, cname, aname);
-#define UVCG_UNCOMPRESSED_ATTR(cname, aname, conv) \
+#define UVCG_UNCOMPRESSED_ATTR(cname, aname, bits) \
static ssize_t uvcg_uncompressed_##cname##_show( \
struct config_item *item, char *page) \
{ \
@@ -1331,7 +1537,7 @@ static ssize_t uvcg_uncompressed_##cname##_show( \
opts = to_f_uvc_opts(opts_item); \
\
mutex_lock(&opts->lock); \
- result = sprintf(page, "%d\n", conv(u->desc.aname)); \
+ result = sprintf(page, "%u\n", le##bits##_to_cpu(u->desc.aname));\
mutex_unlock(&opts->lock); \
\
mutex_unlock(su_mutex); \
@@ -1378,16 +1584,12 @@ end: \
\
UVC_ATTR(uvcg_uncompressed_, cname, aname);
-#define identity_conv(x) (x)
-
-UVCG_UNCOMPRESSED_ATTR(b_bits_per_pixel, bBitsPerPixel, identity_conv);
-UVCG_UNCOMPRESSED_ATTR(b_default_frame_index, bDefaultFrameIndex,
- identity_conv);
-UVCG_UNCOMPRESSED_ATTR_RO(b_aspect_ratio_x, bAspectRatioX, identity_conv);
-UVCG_UNCOMPRESSED_ATTR_RO(b_aspect_ratio_y, bAspectRatioY, identity_conv);
-UVCG_UNCOMPRESSED_ATTR_RO(bm_interface_flags, bmInterfaceFlags, identity_conv);
-
-#undef identity_conv
+UVCG_UNCOMPRESSED_ATTR_RO(b_format_index, bFormatIndex, 8);
+UVCG_UNCOMPRESSED_ATTR(b_bits_per_pixel, bBitsPerPixel, 8);
+UVCG_UNCOMPRESSED_ATTR(b_default_frame_index, bDefaultFrameIndex, 8);
+UVCG_UNCOMPRESSED_ATTR_RO(b_aspect_ratio_x, bAspectRatioX, 8);
+UVCG_UNCOMPRESSED_ATTR_RO(b_aspect_ratio_y, bAspectRatioY, 8);
+UVCG_UNCOMPRESSED_ATTR_RO(bm_interface_flags, bmInterfaceFlags, 8);
#undef UVCG_UNCOMPRESSED_ATTR
#undef UVCG_UNCOMPRESSED_ATTR_RO
@@ -1410,6 +1612,7 @@ uvcg_uncompressed_bma_controls_store(struct config_item *item,
UVC_ATTR(uvcg_uncompressed_, bma_controls, bmaControls);
static struct configfs_attribute *uvcg_uncompressed_attrs[] = {
+ &uvcg_uncompressed_attr_b_format_index,
&uvcg_uncompressed_attr_guid_format,
&uvcg_uncompressed_attr_b_bits_per_pixel,
&uvcg_uncompressed_attr_b_default_frame_index,
@@ -1421,6 +1624,7 @@ static struct configfs_attribute *uvcg_uncompressed_attrs[] = {
};
static const struct config_item_type uvcg_uncompressed_type = {
+ .ct_item_ops = &uvcg_config_item_ops,
.ct_group_ops = &uvcg_uncompressed_group_ops,
.ct_attrs = uvcg_uncompressed_attrs,
.ct_owner = THIS_MODULE,
@@ -1457,25 +1661,23 @@ static struct config_group *uvcg_uncompressed_make(struct config_group *group,
return &h->fmt.group;
}
-static void uvcg_uncompressed_drop(struct config_group *group,
- struct config_item *item)
-{
- struct uvcg_uncompressed *h = to_uvcg_uncompressed(item);
-
- kfree(h);
-}
-
static struct configfs_group_operations uvcg_uncompressed_grp_ops = {
.make_group = uvcg_uncompressed_make,
- .drop_item = uvcg_uncompressed_drop,
};
-static const struct config_item_type uvcg_uncompressed_grp_type = {
- .ct_group_ops = &uvcg_uncompressed_grp_ops,
- .ct_owner = THIS_MODULE,
+static const struct uvcg_config_group_type uvcg_uncompressed_grp_type = {
+ .type = {
+ .ct_item_ops = &uvcg_config_item_ops,
+ .ct_group_ops = &uvcg_uncompressed_grp_ops,
+ .ct_owner = THIS_MODULE,
+ },
+ .name = "uncompressed",
};
-/* streaming/mjpeg/<NAME> */
+/* -----------------------------------------------------------------------------
+ * streaming/mjpeg/<NAME>
+ */
+
struct uvcg_mjpeg {
struct uvcg_format fmt;
struct uvc_format_mjpeg desc;
@@ -1493,7 +1695,7 @@ static struct configfs_group_operations uvcg_mjpeg_group_ops = {
.drop_item = uvcg_frame_drop,
};
-#define UVCG_MJPEG_ATTR_RO(cname, aname, conv) \
+#define UVCG_MJPEG_ATTR_RO(cname, aname, bits) \
static ssize_t uvcg_mjpeg_##cname##_show(struct config_item *item, char *page)\
{ \
struct uvcg_mjpeg *u = to_uvcg_mjpeg(item); \
@@ -1508,7 +1710,7 @@ static ssize_t uvcg_mjpeg_##cname##_show(struct config_item *item, char *page)\
opts = to_f_uvc_opts(opts_item); \
\
mutex_lock(&opts->lock); \
- result = sprintf(page, "%d\n", conv(u->desc.aname)); \
+ result = sprintf(page, "%u\n", le##bits##_to_cpu(u->desc.aname));\
mutex_unlock(&opts->lock); \
\
mutex_unlock(su_mutex); \
@@ -1517,7 +1719,7 @@ static ssize_t uvcg_mjpeg_##cname##_show(struct config_item *item, char *page)\
\
UVC_ATTR_RO(uvcg_mjpeg_, cname, aname)
-#define UVCG_MJPEG_ATTR(cname, aname, conv) \
+#define UVCG_MJPEG_ATTR(cname, aname, bits) \
static ssize_t uvcg_mjpeg_##cname##_show(struct config_item *item, char *page)\
{ \
struct uvcg_mjpeg *u = to_uvcg_mjpeg(item); \
@@ -1532,7 +1734,7 @@ static ssize_t uvcg_mjpeg_##cname##_show(struct config_item *item, char *page)\
opts = to_f_uvc_opts(opts_item); \
\
mutex_lock(&opts->lock); \
- result = sprintf(page, "%d\n", conv(u->desc.aname)); \
+ result = sprintf(page, "%u\n", le##bits##_to_cpu(u->desc.aname));\
mutex_unlock(&opts->lock); \
\
mutex_unlock(su_mutex); \
@@ -1579,16 +1781,12 @@ end: \
\
UVC_ATTR(uvcg_mjpeg_, cname, aname)
-#define identity_conv(x) (x)
-
-UVCG_MJPEG_ATTR(b_default_frame_index, bDefaultFrameIndex,
- identity_conv);
-UVCG_MJPEG_ATTR_RO(bm_flags, bmFlags, identity_conv);
-UVCG_MJPEG_ATTR_RO(b_aspect_ratio_x, bAspectRatioX, identity_conv);
-UVCG_MJPEG_ATTR_RO(b_aspect_ratio_y, bAspectRatioY, identity_conv);
-UVCG_MJPEG_ATTR_RO(bm_interface_flags, bmInterfaceFlags, identity_conv);
-
-#undef identity_conv
+UVCG_MJPEG_ATTR_RO(b_format_index, bFormatIndex, 8);
+UVCG_MJPEG_ATTR(b_default_frame_index, bDefaultFrameIndex, 8);
+UVCG_MJPEG_ATTR_RO(bm_flags, bmFlags, 8);
+UVCG_MJPEG_ATTR_RO(b_aspect_ratio_x, bAspectRatioX, 8);
+UVCG_MJPEG_ATTR_RO(b_aspect_ratio_y, bAspectRatioY, 8);
+UVCG_MJPEG_ATTR_RO(bm_interface_flags, bmInterfaceFlags, 8);
#undef UVCG_MJPEG_ATTR
#undef UVCG_MJPEG_ATTR_RO
@@ -1611,6 +1809,7 @@ uvcg_mjpeg_bma_controls_store(struct config_item *item,
UVC_ATTR(uvcg_mjpeg_, bma_controls, bmaControls);
static struct configfs_attribute *uvcg_mjpeg_attrs[] = {
+ &uvcg_mjpeg_attr_b_format_index,
&uvcg_mjpeg_attr_b_default_frame_index,
&uvcg_mjpeg_attr_bm_flags,
&uvcg_mjpeg_attr_b_aspect_ratio_x,
@@ -1621,6 +1820,7 @@ static struct configfs_attribute *uvcg_mjpeg_attrs[] = {
};
static const struct config_item_type uvcg_mjpeg_type = {
+ .ct_item_ops = &uvcg_config_item_ops,
.ct_group_ops = &uvcg_mjpeg_group_ops,
.ct_attrs = uvcg_mjpeg_attrs,
.ct_owner = THIS_MODULE,
@@ -1651,56 +1851,42 @@ static struct config_group *uvcg_mjpeg_make(struct config_group *group,
return &h->fmt.group;
}
-static void uvcg_mjpeg_drop(struct config_group *group,
- struct config_item *item)
-{
- struct uvcg_mjpeg *h = to_uvcg_mjpeg(item);
-
- kfree(h);
-}
-
static struct configfs_group_operations uvcg_mjpeg_grp_ops = {
.make_group = uvcg_mjpeg_make,
- .drop_item = uvcg_mjpeg_drop,
};
-static const struct config_item_type uvcg_mjpeg_grp_type = {
- .ct_group_ops = &uvcg_mjpeg_grp_ops,
- .ct_owner = THIS_MODULE,
+static const struct uvcg_config_group_type uvcg_mjpeg_grp_type = {
+ .type = {
+ .ct_item_ops = &uvcg_config_item_ops,
+ .ct_group_ops = &uvcg_mjpeg_grp_ops,
+ .ct_owner = THIS_MODULE,
+ },
+ .name = "mjpeg",
};
-/* streaming/color_matching/default */
-static struct uvcg_default_color_matching {
- struct config_group group;
-} uvcg_default_color_matching;
-
-static inline struct uvcg_default_color_matching
-*to_uvcg_default_color_matching(struct config_item *item)
-{
- return container_of(to_config_group(item),
- struct uvcg_default_color_matching, group);
-}
+/* -----------------------------------------------------------------------------
+ * streaming/color_matching/default
+ */
-#define UVCG_DEFAULT_COLOR_MATCHING_ATTR(cname, aname, conv) \
+#define UVCG_DEFAULT_COLOR_MATCHING_ATTR(cname, aname, bits) \
static ssize_t uvcg_default_color_matching_##cname##_show( \
- struct config_item *item, char *page) \
+ struct config_item *item, char *page) \
{ \
- struct uvcg_default_color_matching *dc = \
- to_uvcg_default_color_matching(item); \
+ struct config_group *group = to_config_group(item); \
struct f_uvc_opts *opts; \
struct config_item *opts_item; \
- struct mutex *su_mutex = &dc->group.cg_subsys->su_mutex; \
+ struct mutex *su_mutex = &group->cg_subsys->su_mutex; \
struct uvc_color_matching_descriptor *cd; \
int result; \
\
mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
\
- opts_item = dc->group.cg_item.ci_parent->ci_parent->ci_parent; \
+ opts_item = group->cg_item.ci_parent->ci_parent->ci_parent; \
opts = to_f_uvc_opts(opts_item); \
cd = &opts->uvc_color_matching; \
\
mutex_lock(&opts->lock); \
- result = sprintf(page, "%d\n", conv(cd->aname)); \
+ result = sprintf(page, "%u\n", le##bits##_to_cpu(cd->aname)); \
mutex_unlock(&opts->lock); \
\
mutex_unlock(su_mutex); \
@@ -1709,16 +1895,10 @@ static ssize_t uvcg_default_color_matching_##cname##_show( \
\
UVC_ATTR_RO(uvcg_default_color_matching_, cname, aname)
-#define identity_conv(x) (x)
-
-UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_color_primaries, bColorPrimaries,
- identity_conv);
+UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_color_primaries, bColorPrimaries, 8);
UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_transfer_characteristics,
- bTransferCharacteristics, identity_conv);
-UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_matrix_coefficients, bMatrixCoefficients,
- identity_conv);
-
-#undef identity_conv
+ bTransferCharacteristics, 8);
+UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_matrix_coefficients, bMatrixCoefficients, 8);
#undef UVCG_DEFAULT_COLOR_MATCHING_ATTR
@@ -1729,41 +1909,54 @@ static struct configfs_attribute *uvcg_default_color_matching_attrs[] = {
NULL,
};
-static const struct config_item_type uvcg_default_color_matching_type = {
- .ct_attrs = uvcg_default_color_matching_attrs,
- .ct_owner = THIS_MODULE,
+static const struct uvcg_config_group_type uvcg_default_color_matching_type = {
+ .type = {
+ .ct_item_ops = &uvcg_config_item_ops,
+ .ct_attrs = uvcg_default_color_matching_attrs,
+ .ct_owner = THIS_MODULE,
+ },
+ .name = "default",
};
-/* struct uvcg_color_matching {}; */
-
-/* streaming/color_matching */
-static struct uvcg_color_matching_grp {
- struct config_group group;
-} uvcg_color_matching_grp;
+/* -----------------------------------------------------------------------------
+ * streaming/color_matching
+ */
-static const struct config_item_type uvcg_color_matching_grp_type = {
- .ct_owner = THIS_MODULE,
+static const struct uvcg_config_group_type uvcg_color_matching_grp_type = {
+ .type = {
+ .ct_item_ops = &uvcg_config_item_ops,
+ .ct_owner = THIS_MODULE,
+ },
+ .name = "color_matching",
+ .children = (const struct uvcg_config_group_type*[]) {
+ &uvcg_default_color_matching_type,
+ NULL,
+ },
};
-/* streaming/class/{fs|hs|ss} */
-static struct uvcg_streaming_class {
- struct config_group group;
-} uvcg_streaming_class_fs, uvcg_streaming_class_hs, uvcg_streaming_class_ss;
+/* -----------------------------------------------------------------------------
+ * streaming/class/{fs|hs|ss}
+ */
+struct uvcg_streaming_class_group {
+ struct config_group group;
+ const char *name;
+};
static inline struct uvc_descriptor_header
***__uvcg_get_stream_class_arr(struct config_item *i, struct f_uvc_opts *o)
{
- struct uvcg_streaming_class *cl = container_of(to_config_group(i),
- struct uvcg_streaming_class, group);
+ struct uvcg_streaming_class_group *group =
+ container_of(i, struct uvcg_streaming_class_group,
+ group.cg_item);
- if (cl == &uvcg_streaming_class_fs)
+ if (!strcmp(group->name, "fs"))
return &o->uvc_fs_streaming_cls;
- if (cl == &uvcg_streaming_class_hs)
+ if (!strcmp(group->name, "hs"))
return &o->uvc_hs_streaming_cls;
- if (cl == &uvcg_streaming_class_ss)
+ if (!strcmp(group->name, "ss"))
return &o->uvc_ss_streaming_cls;
return NULL;
@@ -1922,24 +2115,22 @@ static int __uvcg_fill_strm(void *priv1, void *priv2, void *priv3, int n,
struct uvcg_format *fmt = priv1;
if (fmt->type == UVCG_UNCOMPRESSED) {
- struct uvc_format_uncompressed *unc = *dest;
struct uvcg_uncompressed *u =
container_of(fmt, struct uvcg_uncompressed,
fmt);
+ u->desc.bFormatIndex = n + 1;
+ u->desc.bNumFrameDescriptors = fmt->num_frames;
memcpy(*dest, &u->desc, sizeof(u->desc));
*dest += sizeof(u->desc);
- unc->bNumFrameDescriptors = fmt->num_frames;
- unc->bFormatIndex = n + 1;
} else if (fmt->type == UVCG_MJPEG) {
- struct uvc_format_mjpeg *mjp = *dest;
struct uvcg_mjpeg *m =
container_of(fmt, struct uvcg_mjpeg, fmt);
+ m->desc.bFormatIndex = n + 1;
+ m->desc.bNumFrameDescriptors = fmt->num_frames;
memcpy(*dest, &m->desc, sizeof(m->desc));
*dest += sizeof(m->desc);
- mjp->bNumFrameDescriptors = fmt->num_frames;
- mjp->bFormatIndex = n + 1;
} else {
return -EINVAL;
}
@@ -2038,6 +2229,7 @@ static int uvcg_streaming_class_allow_link(struct config_item *src,
unlock:
mutex_unlock(&opts->lock);
out:
+ config_item_put(header);
mutex_unlock(su_mutex);
return ret;
}
@@ -2078,10 +2270,12 @@ static void uvcg_streaming_class_drop_link(struct config_item *src,
unlock:
mutex_unlock(&opts->lock);
out:
+ config_item_put(header);
mutex_unlock(su_mutex);
}
static struct configfs_item_operations uvcg_streaming_class_item_ops = {
+ .release = uvcg_config_item_release,
.allow_link = uvcg_streaming_class_allow_link,
.drop_link = uvcg_streaming_class_drop_link,
};
@@ -2091,36 +2285,109 @@ static const struct config_item_type uvcg_streaming_class_type = {
.ct_owner = THIS_MODULE,
};
-/* streaming/class */
-static struct uvcg_streaming_class_grp {
- struct config_group group;
-} uvcg_streaming_class_grp;
+/* -----------------------------------------------------------------------------
+ * streaming/class
+ */
+
+static int uvcg_streaming_class_create_children(struct config_group *parent)
+{
+ static const char * const names[] = { "fs", "hs", "ss" };
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(names); ++i) {
+ struct uvcg_streaming_class_group *group;
+
+ group = kzalloc(sizeof(*group), GFP_KERNEL);
+ if (!group)
+ return -ENOMEM;
-static const struct config_item_type uvcg_streaming_class_grp_type = {
- .ct_owner = THIS_MODULE,
+ group->name = names[i];
+
+ config_group_init_type_name(&group->group, group->name,
+ &uvcg_streaming_class_type);
+ configfs_add_default_group(&group->group, parent);
+ }
+
+ return 0;
+}
+
+static const struct uvcg_config_group_type uvcg_streaming_class_grp_type = {
+ .type = {
+ .ct_item_ops = &uvcg_config_item_ops,
+ .ct_owner = THIS_MODULE,
+ },
+ .name = "class",
+ .create_children = uvcg_streaming_class_create_children,
};
-/* streaming */
-static struct uvcg_streaming_grp {
- struct config_group group;
-} uvcg_streaming_grp;
+/* -----------------------------------------------------------------------------
+ * streaming
+ */
-static const struct config_item_type uvcg_streaming_grp_type = {
- .ct_owner = THIS_MODULE,
+static ssize_t uvcg_default_streaming_b_interface_number_show(
+ struct config_item *item, char *page)
+{
+ struct config_group *group = to_config_group(item);
+ struct mutex *su_mutex = &group->cg_subsys->su_mutex;
+ struct config_item *opts_item;
+ struct f_uvc_opts *opts;
+ int result = 0;
+
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+ opts_item = item->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+
+ mutex_lock(&opts->lock);
+ result += sprintf(page, "%u\n", opts->streaming_interface);
+ mutex_unlock(&opts->lock);
+
+ mutex_unlock(su_mutex);
+
+ return result;
+}
+
+UVC_ATTR_RO(uvcg_default_streaming_, b_interface_number, bInterfaceNumber);
+
+static struct configfs_attribute *uvcg_default_streaming_attrs[] = {
+ &uvcg_default_streaming_attr_b_interface_number,
+ NULL,
+};
+
+static const struct uvcg_config_group_type uvcg_streaming_grp_type = {
+ .type = {
+ .ct_item_ops = &uvcg_config_item_ops,
+ .ct_attrs = uvcg_default_streaming_attrs,
+ .ct_owner = THIS_MODULE,
+ },
+ .name = "streaming",
+ .children = (const struct uvcg_config_group_type*[]) {
+ &uvcg_streaming_header_grp_type,
+ &uvcg_uncompressed_grp_type,
+ &uvcg_mjpeg_grp_type,
+ &uvcg_color_matching_grp_type,
+ &uvcg_streaming_class_grp_type,
+ NULL,
+ },
};
-static void uvc_attr_release(struct config_item *item)
+/* -----------------------------------------------------------------------------
+ * UVC function
+ */
+
+static void uvc_func_item_release(struct config_item *item)
{
struct f_uvc_opts *opts = to_f_uvc_opts(item);
+ uvcg_config_remove_children(to_config_group(item));
usb_put_function_instance(&opts->func_inst);
}
-static struct configfs_item_operations uvc_item_ops = {
- .release = uvc_attr_release,
+static struct configfs_item_operations uvc_func_item_ops = {
+ .release = uvc_func_item_release,
};
-#define UVCG_OPTS_ATTR(cname, aname, conv, str2u, uxx, vnoc, limit) \
+#define UVCG_OPTS_ATTR(cname, aname, limit) \
static ssize_t f_uvc_opts_##cname##_show( \
struct config_item *item, char *page) \
{ \
@@ -2128,7 +2395,7 @@ static ssize_t f_uvc_opts_##cname##_show( \
int result; \
\
mutex_lock(&opts->lock); \
- result = sprintf(page, "%d\n", conv(opts->cname)); \
+ result = sprintf(page, "%u\n", opts->cname); \
mutex_unlock(&opts->lock); \
\
return result; \
@@ -2139,8 +2406,8 @@ f_uvc_opts_##cname##_store(struct config_item *item, \
const char *page, size_t len) \
{ \
struct f_uvc_opts *opts = to_f_uvc_opts(item); \
+ unsigned int num; \
int ret; \
- uxx num; \
\
mutex_lock(&opts->lock); \
if (opts->refcnt) { \
@@ -2148,7 +2415,7 @@ f_uvc_opts_##cname##_store(struct config_item *item, \
goto end; \
} \
\
- ret = str2u(page, 0, &num); \
+ ret = kstrtouint(page, 0, &num); \
if (ret) \
goto end; \
\
@@ -2156,7 +2423,7 @@ f_uvc_opts_##cname##_store(struct config_item *item, \
ret = -EINVAL; \
goto end; \
} \
- opts->cname = vnoc(num); \
+ opts->cname = num; \
ret = len; \
end: \
mutex_unlock(&opts->lock); \
@@ -2165,16 +2432,9 @@ end: \
\
UVC_ATTR(f_uvc_opts_, cname, cname)
-#define identity_conv(x) (x)
-
-UVCG_OPTS_ATTR(streaming_interval, streaming_interval, identity_conv,
- kstrtou8, u8, identity_conv, 16);
-UVCG_OPTS_ATTR(streaming_maxpacket, streaming_maxpacket, le16_to_cpu,
- kstrtou16, u16, le16_to_cpu, 3072);
-UVCG_OPTS_ATTR(streaming_maxburst, streaming_maxburst, identity_conv,
- kstrtou8, u8, identity_conv, 15);
-
-#undef identity_conv
+UVCG_OPTS_ATTR(streaming_interval, streaming_interval, 16);
+UVCG_OPTS_ATTR(streaming_maxpacket, streaming_maxpacket, 3072);
+UVCG_OPTS_ATTR(streaming_maxburst, streaming_maxburst, 15);
#undef UVCG_OPTS_ATTR
@@ -2185,123 +2445,31 @@ static struct configfs_attribute *uvc_attrs[] = {
NULL,
};
-static const struct config_item_type uvc_func_type = {
- .ct_item_ops = &uvc_item_ops,
- .ct_attrs = uvc_attrs,
- .ct_owner = THIS_MODULE,
+static const struct uvcg_config_group_type uvc_func_type = {
+ .type = {
+ .ct_item_ops = &uvc_func_item_ops,
+ .ct_attrs = uvc_attrs,
+ .ct_owner = THIS_MODULE,
+ },
+ .name = "",
+ .children = (const struct uvcg_config_group_type*[]) {
+ &uvcg_control_grp_type,
+ &uvcg_streaming_grp_type,
+ NULL,
+ },
};
int uvcg_attach_configfs(struct f_uvc_opts *opts)
{
- config_group_init_type_name(&uvcg_control_header_grp.group,
- "header",
- &uvcg_control_header_grp_type);
-
- config_group_init_type_name(&uvcg_default_processing.group,
- "default", &uvcg_default_processing_type);
- config_group_init_type_name(&uvcg_processing_grp.group,
- "processing", &uvcg_processing_grp_type);
- configfs_add_default_group(&uvcg_default_processing.group,
- &uvcg_processing_grp.group);
-
- config_group_init_type_name(&uvcg_default_camera.group,
- "default", &uvcg_default_camera_type);
- config_group_init_type_name(&uvcg_camera_grp.group,
- "camera", &uvcg_camera_grp_type);
- configfs_add_default_group(&uvcg_default_camera.group,
- &uvcg_camera_grp.group);
-
- config_group_init_type_name(&uvcg_default_output.group,
- "default", &uvcg_default_output_type);
- config_group_init_type_name(&uvcg_output_grp.group,
- "output", &uvcg_output_grp_type);
- configfs_add_default_group(&uvcg_default_output.group,
- &uvcg_output_grp.group);
-
- config_group_init_type_name(&uvcg_terminal_grp.group,
- "terminal", &uvcg_terminal_grp_type);
- configfs_add_default_group(&uvcg_camera_grp.group,
- &uvcg_terminal_grp.group);
- configfs_add_default_group(&uvcg_output_grp.group,
- &uvcg_terminal_grp.group);
-
- config_group_init_type_name(&uvcg_control_class_fs.group,
- "fs", &uvcg_control_class_type);
- config_group_init_type_name(&uvcg_control_class_ss.group,
- "ss", &uvcg_control_class_type);
- config_group_init_type_name(&uvcg_control_class_grp.group,
- "class",
- &uvcg_control_class_grp_type);
- configfs_add_default_group(&uvcg_control_class_fs.group,
- &uvcg_control_class_grp.group);
- configfs_add_default_group(&uvcg_control_class_ss.group,
- &uvcg_control_class_grp.group);
-
- config_group_init_type_name(&uvcg_control_grp.group,
- "control",
- &uvcg_control_grp_type);
- configfs_add_default_group(&uvcg_control_header_grp.group,
- &uvcg_control_grp.group);
- configfs_add_default_group(&uvcg_processing_grp.group,
- &uvcg_control_grp.group);
- configfs_add_default_group(&uvcg_terminal_grp.group,
- &uvcg_control_grp.group);
- configfs_add_default_group(&uvcg_control_class_grp.group,
- &uvcg_control_grp.group);
-
- config_group_init_type_name(&uvcg_streaming_header_grp.group,
- "header",
- &uvcg_streaming_header_grp_type);
- config_group_init_type_name(&uvcg_uncompressed_grp.group,
- "uncompressed",
- &uvcg_uncompressed_grp_type);
- config_group_init_type_name(&uvcg_mjpeg_grp.group,
- "mjpeg",
- &uvcg_mjpeg_grp_type);
- config_group_init_type_name(&uvcg_default_color_matching.group,
- "default",
- &uvcg_default_color_matching_type);
- config_group_init_type_name(&uvcg_color_matching_grp.group,
- "color_matching",
- &uvcg_color_matching_grp_type);
- configfs_add_default_group(&uvcg_default_color_matching.group,
- &uvcg_color_matching_grp.group);
-
- config_group_init_type_name(&uvcg_streaming_class_fs.group,
- "fs", &uvcg_streaming_class_type);
- config_group_init_type_name(&uvcg_streaming_class_hs.group,
- "hs", &uvcg_streaming_class_type);
- config_group_init_type_name(&uvcg_streaming_class_ss.group,
- "ss", &uvcg_streaming_class_type);
- config_group_init_type_name(&uvcg_streaming_class_grp.group,
- "class", &uvcg_streaming_class_grp_type);
- configfs_add_default_group(&uvcg_streaming_class_fs.group,
- &uvcg_streaming_class_grp.group);
- configfs_add_default_group(&uvcg_streaming_class_hs.group,
- &uvcg_streaming_class_grp.group);
- configfs_add_default_group(&uvcg_streaming_class_ss.group,
- &uvcg_streaming_class_grp.group);
-
- config_group_init_type_name(&uvcg_streaming_grp.group,
- "streaming", &uvcg_streaming_grp_type);
- configfs_add_default_group(&uvcg_streaming_header_grp.group,
- &uvcg_streaming_grp.group);
- configfs_add_default_group(&uvcg_uncompressed_grp.group,
- &uvcg_streaming_grp.group);
- configfs_add_default_group(&uvcg_mjpeg_grp.group,
- &uvcg_streaming_grp.group);
- configfs_add_default_group(&uvcg_color_matching_grp.group,
- &uvcg_streaming_grp.group);
- configfs_add_default_group(&uvcg_streaming_class_grp.group,
- &uvcg_streaming_grp.group);
-
- config_group_init_type_name(&opts->func_inst.group,
- "",
- &uvc_func_type);
- configfs_add_default_group(&uvcg_control_grp.group,
- &opts->func_inst.group);
- configfs_add_default_group(&uvcg_streaming_grp.group,
- &opts->func_inst.group);
+ int ret;
- return 0;
+ config_group_init_type_name(&opts->func_inst.group, uvc_func_type.name,
+ &uvc_func_type.type);
+
+ ret = uvcg_config_create_children(&opts->func_inst.group,
+ &uvc_func_type);
+ if (ret < 0)
+ config_group_put(&opts->func_inst.group);
+
+ return ret;
}
diff --git a/drivers/usb/gadget/function/uvc_queue.c b/drivers/usb/gadget/function/uvc_queue.c
index 9e33d5206d54..f2497cb96abb 100644
--- a/drivers/usb/gadget/function/uvc_queue.c
+++ b/drivers/usb/gadget/function/uvc_queue.c
@@ -166,7 +166,7 @@ int uvcg_queue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf)
unsigned long flags;
int ret;
- ret = vb2_qbuf(&queue->queue, buf);
+ ret = vb2_qbuf(&queue->queue, NULL, buf);
if (ret < 0)
return ret;
diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c
index 7f1ca3b57823..a1183eccee22 100644
--- a/drivers/usb/gadget/function/uvc_v4l2.c
+++ b/drivers/usb/gadget/function/uvc_v4l2.c
@@ -115,8 +115,8 @@ uvc_v4l2_set_format(struct file *file, void *fh, struct v4l2_format *fmt)
}
if (i == ARRAY_SIZE(uvc_formats)) {
- printk(KERN_INFO "Unsupported format 0x%08x.\n",
- fmt->fmt.pix.pixelformat);
+ uvcg_info(&uvc->func, "Unsupported format 0x%08x.\n",
+ fmt->fmt.pix.pixelformat);
return -EINVAL;
}
diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c
index d3567b90343a..5c042f380708 100644
--- a/drivers/usb/gadget/function/uvc_video.c
+++ b/drivers/usb/gadget/function/uvc_video.c
@@ -125,6 +125,23 @@ uvc_video_encode_isoc(struct usb_request *req, struct uvc_video *video,
* Request handling
*/
+static int uvcg_video_ep_queue(struct uvc_video *video, struct usb_request *req)
+{
+ int ret;
+
+ ret = usb_ep_queue(video->ep, req, GFP_ATOMIC);
+ if (ret < 0) {
+ uvcg_err(&video->uvc->func, "Failed to queue request (%d).\n",
+ ret);
+
+ /* Isochronous endpoints can't be halted. */
+ if (usb_endpoint_xfer_bulk(video->ep->desc))
+ usb_ep_set_halt(video->ep);
+ }
+
+ return ret;
+}
+
/*
* I somehow feel that synchronisation won't be easy to achieve here. We have
* three events that control USB requests submission:
@@ -169,13 +186,14 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
break;
case -ESHUTDOWN: /* disconnect from host. */
- printk(KERN_DEBUG "VS request cancelled.\n");
+ uvcg_dbg(&video->uvc->func, "VS request cancelled.\n");
uvcg_queue_cancel(queue, 1);
goto requeue;
default:
- printk(KERN_INFO "VS request completed with status %d.\n",
- req->status);
+ uvcg_info(&video->uvc->func,
+ "VS request completed with status %d.\n",
+ req->status);
uvcg_queue_cancel(queue, 0);
goto requeue;
}
@@ -189,14 +207,13 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
video->encode(req, video, buf);
- if ((ret = usb_ep_queue(ep, req, GFP_ATOMIC)) < 0) {
- printk(KERN_INFO "Failed to queue request (%d).\n", ret);
- usb_ep_set_halt(ep);
- spin_unlock_irqrestore(&video->queue.irqlock, flags);
+ ret = uvcg_video_ep_queue(video, req);
+ spin_unlock_irqrestore(&video->queue.irqlock, flags);
+
+ if (ret < 0) {
uvcg_queue_cancel(queue, 0);
goto requeue;
}
- spin_unlock_irqrestore(&video->queue.irqlock, flags);
return;
@@ -316,15 +333,13 @@ int uvcg_video_pump(struct uvc_video *video)
video->encode(req, video, buf);
/* Queue the USB request */
- ret = usb_ep_queue(video->ep, req, GFP_ATOMIC);
+ ret = uvcg_video_ep_queue(video, req);
+ spin_unlock_irqrestore(&queue->irqlock, flags);
+
if (ret < 0) {
- printk(KERN_INFO "Failed to queue request (%d)\n", ret);
- usb_ep_set_halt(video->ep);
- spin_unlock_irqrestore(&queue->irqlock, flags);
uvcg_queue_cancel(queue, 0);
break;
}
- spin_unlock_irqrestore(&queue->irqlock, flags);
}
spin_lock_irqsave(&video->req_lock, flags);
@@ -342,8 +357,8 @@ int uvcg_video_enable(struct uvc_video *video, int enable)
int ret;
if (video->ep == NULL) {
- printk(KERN_INFO "Video enable failed, device is "
- "uninitialized.\n");
+ uvcg_info(&video->uvc->func,
+ "Video enable failed, device is uninitialized.\n");
return -ENODEV;
}
@@ -375,11 +390,12 @@ int uvcg_video_enable(struct uvc_video *video, int enable)
/*
* Initialize the UVC video stream.
*/
-int uvcg_video_init(struct uvc_video *video)
+int uvcg_video_init(struct uvc_video *video, struct uvc_device *uvc)
{
INIT_LIST_HEAD(&video->req_free);
spin_lock_init(&video->req_lock);
+ video->uvc = uvc;
video->fcc = V4L2_PIX_FMT_YUYV;
video->bpp = 16;
video->width = 320;
diff --git a/drivers/usb/gadget/function/uvc_video.h b/drivers/usb/gadget/function/uvc_video.h
index 7d77122b0ff9..278dc52c7604 100644
--- a/drivers/usb/gadget/function/uvc_video.h
+++ b/drivers/usb/gadget/function/uvc_video.h
@@ -18,6 +18,6 @@ int uvcg_video_pump(struct uvc_video *video);
int uvcg_video_enable(struct uvc_video *video, int enable);
-int uvcg_video_init(struct uvc_video *video);
+int uvcg_video_init(struct uvc_video *video, struct uvc_device *uvc);
#endif /* __UVC_VIDEO_H__ */
diff --git a/drivers/usb/gadget/udc/aspeed-vhub/epn.c b/drivers/usb/gadget/udc/aspeed-vhub/epn.c
index 5939eb1e97f2..4a28e3fbeb0b 100644
--- a/drivers/usb/gadget/udc/aspeed-vhub/epn.c
+++ b/drivers/usb/gadget/udc/aspeed-vhub/epn.c
@@ -353,7 +353,7 @@ static int ast_vhub_epn_queue(struct usb_ep* u_ep, struct usb_request *u_req,
/* Endpoint enabled ? */
if (!ep->epn.enabled || !u_ep->desc || !ep->dev || !ep->d_idx ||
!ep->dev->enabled || ep->dev->suspended) {
- EPDBG(ep,"Enqueing request on wrong or disabled EP\n");
+ EPDBG(ep, "Enqueuing request on wrong or disabled EP\n");
return -ESHUTDOWN;
}
diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c
index 17147b8c771e..11247322d587 100644
--- a/drivers/usb/gadget/udc/atmel_usba_udc.c
+++ b/drivers/usb/gadget/udc/atmel_usba_udc.c
@@ -2004,7 +2004,6 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
struct usba_udc *udc)
{
u32 val;
- const char *name;
struct device_node *np = pdev->dev.of_node;
const struct of_device_id *match;
struct device_node *pp;
@@ -2018,6 +2017,8 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
udc->errata = match->data;
udc->pmc = syscon_regmap_lookup_by_compatible("atmel,at91sam9g45-pmc");
if (IS_ERR(udc->pmc))
+ udc->pmc = syscon_regmap_lookup_by_compatible("atmel,at91sam9rl-pmc");
+ if (IS_ERR(udc->pmc))
udc->pmc = syscon_regmap_lookup_by_compatible("atmel,at91sam9x5-pmc");
if (udc->errata && IS_ERR(udc->pmc))
return ERR_CAST(udc->pmc);
@@ -2094,11 +2095,6 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
ep->can_dma = of_property_read_bool(pp, "atmel,can-dma");
ep->can_isoc = of_property_read_bool(pp, "atmel,can-isoc");
- ret = of_property_read_string(pp, "name", &name);
- if (ret) {
- dev_err(&pdev->dev, "of_probe: name error(%d)\n", ret);
- goto err;
- }
sprintf(ep->name, "ep%d", ep->index);
ep->ep.name = ep->name;
diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
index af88b48c1cea..87d6b12779f2 100644
--- a/drivers/usb/gadget/udc/core.c
+++ b/drivers/usb/gadget/udc/core.c
@@ -690,6 +690,9 @@ EXPORT_SYMBOL_GPL(usb_gadget_connect);
* as a disconnect (when a VBUS session is active). Not all systems
* support software pullup controls.
*
+ * Following a successful disconnect, invoke the ->disconnect() callback
+ * for the current gadget driver so that UDC drivers don't need to.
+ *
* Returns zero on success, else negative errno.
*/
int usb_gadget_disconnect(struct usb_gadget *gadget)
@@ -711,8 +714,10 @@ int usb_gadget_disconnect(struct usb_gadget *gadget)
}
ret = gadget->ops->pullup(gadget, 0);
- if (!ret)
+ if (!ret) {
gadget->connected = 0;
+ gadget->udc->driver->disconnect(gadget);
+ }
out:
trace_usb_gadget_disconnect(gadget, ret);
@@ -1281,7 +1286,6 @@ static void usb_gadget_remove_driver(struct usb_udc *udc)
kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
usb_gadget_disconnect(udc->gadget);
- udc->driver->disconnect(udc->gadget);
udc->driver->unbind(udc->gadget);
usb_gadget_udc_stop(udc);
@@ -1471,7 +1475,6 @@ static ssize_t soft_connect_store(struct device *dev,
usb_gadget_connect(udc->gadget);
} else if (sysfs_streq(buf, "disconnect")) {
usb_gadget_disconnect(udc->gadget);
- udc->driver->disconnect(udc->gadget);
usb_gadget_udc_stop(udc);
} else {
dev_err(dev, "unsupported command '%s'\n", buf);
diff --git a/drivers/usb/gadget/udc/fotg210-udc.c b/drivers/usb/gadget/udc/fotg210-udc.c
index 587c5037ff07..bc6abaea907d 100644
--- a/drivers/usb/gadget/udc/fotg210-udc.c
+++ b/drivers/usb/gadget/udc/fotg210-udc.c
@@ -741,7 +741,7 @@ static void fotg210_get_status(struct fotg210_udc *fotg210,
fotg210->ep0_req->length = 2;
spin_unlock(&fotg210->lock);
- fotg210_ep_queue(fotg210->gadget.ep0, fotg210->ep0_req, GFP_KERNEL);
+ fotg210_ep_queue(fotg210->gadget.ep0, fotg210->ep0_req, GFP_ATOMIC);
spin_lock(&fotg210->lock);
}
diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c
index be59309e848c..20141c3096f6 100644
--- a/drivers/usb/gadget/udc/fsl_udc_core.c
+++ b/drivers/usb/gadget/udc/fsl_udc_core.c
@@ -2234,8 +2234,10 @@ static void fsl_udc_release(struct device *dev)
Internal structure setup functions
*******************************************************************/
/*------------------------------------------------------------------
- * init resource for globle controller
- * Return the udc handle on success or NULL on failure
+ * init resource for global controller called by fsl_udc_probe()
+ * On success the udc handle is initialized, on failure it is
+ * unchanged (reset).
+ * Return 0 on success and -1 on allocation failure
------------------------------------------------------------------*/
static int struct_udc_setup(struct fsl_udc *udc,
struct platform_device *pdev)
@@ -2247,8 +2249,10 @@ static int struct_udc_setup(struct fsl_udc *udc,
udc->phy_mode = pdata->phy_mode;
udc->eps = kcalloc(udc->max_ep, sizeof(struct fsl_ep), GFP_KERNEL);
- if (!udc->eps)
- return -1;
+ if (!udc->eps) {
+ ERR("kmalloc udc endpoint status failed\n");
+ goto eps_alloc_failed;
+ }
/* initialized QHs, take care of alignment */
size = udc->max_ep * sizeof(struct ep_queue_head);
@@ -2262,8 +2266,7 @@ static int struct_udc_setup(struct fsl_udc *udc,
&udc->ep_qh_dma, GFP_KERNEL);
if (!udc->ep_qh) {
ERR("malloc QHs for udc failed\n");
- kfree(udc->eps);
- return -1;
+ goto ep_queue_alloc_failed;
}
udc->ep_qh_size = size;
@@ -2272,8 +2275,17 @@ static int struct_udc_setup(struct fsl_udc *udc,
/* FIXME: fsl_alloc_request() ignores ep argument */
udc->status_req = container_of(fsl_alloc_request(NULL, GFP_KERNEL),
struct fsl_req, req);
+ if (!udc->status_req) {
+ ERR("kzalloc for udc status request failed\n");
+ goto udc_status_alloc_failed;
+ }
+
/* allocate a small amount of memory to get valid address */
udc->status_req->req.buf = kmalloc(8, GFP_KERNEL);
+ if (!udc->status_req->req.buf) {
+ ERR("kzalloc for udc request buffer failed\n");
+ goto udc_req_buf_alloc_failed;
+ }
udc->resume_state = USB_STATE_NOTATTACHED;
udc->usb_state = USB_STATE_POWERED;
@@ -2281,6 +2293,18 @@ static int struct_udc_setup(struct fsl_udc *udc,
udc->remote_wakeup = 0; /* default to 0 on reset */
return 0;
+
+udc_req_buf_alloc_failed:
+ kfree(udc->status_req);
+udc_status_alloc_failed:
+ kfree(udc->ep_qh);
+ udc->ep_qh_size = 0;
+ep_queue_alloc_failed:
+ kfree(udc->eps);
+eps_alloc_failed:
+ udc->phy_mode = 0;
+ return -1;
+
}
/*----------------------------------------------------------------
diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c
index 95f52232493b..cafde053788b 100644
--- a/drivers/usb/gadget/udc/mv_udc_core.c
+++ b/drivers/usb/gadget/udc/mv_udc_core.c
@@ -185,7 +185,7 @@ static int process_ep_req(struct mv_udc *udc, int index,
else
bit_pos = 1 << (16 + curr_req->ep->ep_num);
- while ((curr_dqh->curr_dtd_ptr == curr_dtd->td_dma)) {
+ while (curr_dqh->curr_dtd_ptr == curr_dtd->td_dma) {
if (curr_dtd->dtd_next == EP_QUEUE_HEAD_NEXT_TERMINATE) {
while (readl(&udc->op_regs->epstatus) & bit_pos)
udelay(1);
diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c
index b02ab2a8d927..e7dae5379e04 100644
--- a/drivers/usb/gadget/udc/net2280.c
+++ b/drivers/usb/gadget/udc/net2280.c
@@ -1550,9 +1550,6 @@ static int net2280_pullup(struct usb_gadget *_gadget, int is_on)
spin_unlock_irqrestore(&dev->lock, flags);
- if (!is_on && dev->driver)
- dev->driver->disconnect(&dev->gadget);
-
return 0;
}
diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c
index e1656f361e08..cdffbd1e0316 100644
--- a/drivers/usb/gadget/udc/renesas_usb3.c
+++ b/drivers/usb/gadget/udc/renesas_usb3.c
@@ -2437,6 +2437,9 @@ static ssize_t renesas_usb3_b_device_write(struct file *file,
else
usb3->forced_b_device = false;
+ if (usb3->workaround_for_vbus)
+ usb3_disconnect(usb3);
+
/* Let this driver call usb3_connect() anyway */
usb3_check_id(usb3);
@@ -2600,6 +2603,13 @@ static const struct renesas_usb3_priv renesas_usb3_priv_gen3 = {
.ramsize_per_pipe = SZ_4K,
};
+static const struct renesas_usb3_priv renesas_usb3_priv_r8a77990 = {
+ .ramsize_per_ramif = SZ_16K,
+ .num_ramif = 4,
+ .ramsize_per_pipe = SZ_4K,
+ .workaround_for_vbus = true,
+};
+
static const struct of_device_id usb3_of_match[] = {
{
.compatible = "renesas,r8a7795-usb3-peri",
@@ -2618,6 +2628,10 @@ static const struct soc_device_attribute renesas_usb3_quirks_match[] = {
.soc_id = "r8a7795", .revision = "ES1.*",
.data = &renesas_usb3_priv_r8a7795_es1,
},
+ {
+ .soc_id = "r8a77990",
+ .data = &renesas_usb3_priv_r8a77990,
+ },
{ /* sentinel */ },
};
diff --git a/drivers/usb/gadget/udc/udc-xilinx.c b/drivers/usb/gadget/udc/udc-xilinx.c
index 6407e433bc78..b1f4104d1283 100644
--- a/drivers/usb/gadget/udc/udc-xilinx.c
+++ b/drivers/usb/gadget/udc/udc-xilinx.c
@@ -1078,7 +1078,7 @@ static int xudc_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
unsigned long flags;
if (!ep->desc) {
- dev_dbg(udc->dev, "%s:queing request to disabled %s\n",
+ dev_dbg(udc->dev, "%s: queuing request to disabled %s\n",
__func__, ep->name);
return -ESHUTDOWN;
}
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 1a4ea98cac2a..16758b12a5e9 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -276,7 +276,7 @@ config USB_EHCI_EXYNOS
Enable support for the Samsung Exynos SOC's on-chip EHCI controller.
config USB_EHCI_MV
- bool "EHCI support for Marvell PXA/MMP USB controller"
+ tristate "EHCI support for Marvell PXA/MMP USB controller"
depends on (ARCH_PXA || ARCH_MMP)
select USB_EHCI_ROOT_HUB_TT
---help---
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index e6235269c151..84514f71ae44 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -87,6 +87,7 @@ obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o
obj-$(CONFIG_USB_FSL_USB2) += fsl-mph-dr-of.o
obj-$(CONFIG_USB_EHCI_FSL) += fsl-mph-dr-of.o
obj-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o
+obj-$(CONFIG_USB_EHCI_MV) += ehci-mv.o
obj-$(CONFIG_USB_HCD_BCMA) += bcma-hcd.o
obj-$(CONFIG_USB_HCD_SSB) += ssb-hcd.o
obj-$(CONFIG_USB_FOTG210_HCD) += fotg210-hcd.o
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 8608ac513fb7..cdafa97f632d 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -730,9 +730,9 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
/* normal [4.15.1.2] or error [4.15.1.1] completion */
if (likely ((status & (STS_INT|STS_ERR)) != 0)) {
if (likely ((status & STS_ERR) == 0))
- COUNT (ehci->stats.normal);
+ INCR(ehci->stats.normal);
else
- COUNT (ehci->stats.error);
+ INCR(ehci->stats.error);
bh = 1;
}
@@ -756,7 +756,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
if (cmd & CMD_IAAD)
ehci_dbg(ehci, "IAA with IAAD still set?\n");
if (ehci->iaa_in_progress)
- COUNT(ehci->stats.iaa);
+ INCR(ehci->stats.iaa);
end_iaa_cycle(ehci);
}
@@ -1286,11 +1286,6 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ehci_grlib_driver
#endif
-#ifdef CONFIG_USB_EHCI_MV
-#include "ehci-mv.c"
-#define PLATFORM_DRIVER ehci_mv_driver
-#endif
-
static int __init ehci_hcd_init(void)
{
int retval = 0;
diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c
index de764459e05a..f26109eafdbf 100644
--- a/drivers/usb/host/ehci-mv.c
+++ b/drivers/usb/host/ehci-mv.c
@@ -12,24 +12,33 @@
#include <linux/err.h>
#include <linux/usb/otg.h>
#include <linux/platform_data/mv_usb.h>
+#include <linux/io.h>
+
+#include <linux/usb/hcd.h>
+
+#include "ehci.h"
+
+/* registers */
+#define U2x_CAPREGS_OFFSET 0x100
#define CAPLENGTH_MASK (0xff)
-struct ehci_hcd_mv {
- struct usb_hcd *hcd;
+#define hcd_to_ehci_hcd_mv(h) ((struct ehci_hcd_mv *)hcd_to_ehci(h)->priv)
+struct ehci_hcd_mv {
/* Which mode does this ehci running OTG/Host ? */
int mode;
- void __iomem *phy_regs;
+ void __iomem *base;
void __iomem *cap_regs;
void __iomem *op_regs;
struct usb_phy *otg;
+ struct clk *clk;
- struct mv_usb_platform_data *pdata;
+ struct phy *phy;
- struct clk *clk;
+ int (*set_vbus)(unsigned int vbus);
};
static void ehci_clock_enable(struct ehci_hcd_mv *ehci_mv)
@@ -44,29 +53,20 @@ static void ehci_clock_disable(struct ehci_hcd_mv *ehci_mv)
static int mv_ehci_enable(struct ehci_hcd_mv *ehci_mv)
{
- int retval;
-
ehci_clock_enable(ehci_mv);
- if (ehci_mv->pdata->phy_init) {
- retval = ehci_mv->pdata->phy_init(ehci_mv->phy_regs);
- if (retval)
- return retval;
- }
-
- return 0;
+ return phy_init(ehci_mv->phy);
}
static void mv_ehci_disable(struct ehci_hcd_mv *ehci_mv)
{
- if (ehci_mv->pdata->phy_deinit)
- ehci_mv->pdata->phy_deinit(ehci_mv->phy_regs);
+ phy_exit(ehci_mv->phy);
ehci_clock_disable(ehci_mv);
}
static int mv_ehci_reset(struct usb_hcd *hcd)
{
struct device *dev = hcd->self.controller;
- struct ehci_hcd_mv *ehci_mv = dev_get_drvdata(dev);
+ struct ehci_hcd_mv *ehci_mv = hcd_to_ehci_hcd_mv(hcd);
int retval;
if (ehci_mv == NULL) {
@@ -83,46 +83,11 @@ static int mv_ehci_reset(struct usb_hcd *hcd)
return retval;
}
-static const struct hc_driver mv_ehci_hc_driver = {
- .description = hcd_name,
- .product_desc = "Marvell EHCI",
- .hcd_priv_size = sizeof(struct ehci_hcd),
-
- /*
- * generic hardware linkage
- */
- .irq = ehci_irq,
- .flags = HCD_MEMORY | HCD_USB2 | HCD_BH,
-
- /*
- * basic lifecycle operations
- */
- .reset = mv_ehci_reset,
- .start = ehci_run,
- .stop = ehci_stop,
- .shutdown = ehci_shutdown,
-
- /*
- * managing i/o requests and associated device resources
- */
- .urb_enqueue = ehci_urb_enqueue,
- .urb_dequeue = ehci_urb_dequeue,
- .endpoint_disable = ehci_endpoint_disable,
- .endpoint_reset = ehci_endpoint_reset,
- .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
-
- /*
- * scheduling support
- */
- .get_frame_number = ehci_get_frame,
-
- /*
- * root hub support
- */
- .hub_status_data = ehci_hub_status_data,
- .hub_control = ehci_hub_control,
- .bus_suspend = ehci_bus_suspend,
- .bus_resume = ehci_bus_resume,
+static struct hc_driver __read_mostly ehci_platform_hc_driver;
+
+static const struct ehci_driver_overrides platform_overrides __initconst = {
+ .reset = mv_ehci_reset,
+ .extra_priv_size = sizeof(struct ehci_hcd_mv),
};
static int mv_ehci_probe(struct platform_device *pdev)
@@ -135,27 +100,29 @@ static int mv_ehci_probe(struct platform_device *pdev)
int retval = -ENODEV;
u32 offset;
- if (!pdata) {
- dev_err(&pdev->dev, "missing platform_data\n");
- return -ENODEV;
- }
-
if (usb_disabled())
return -ENODEV;
- hcd = usb_create_hcd(&mv_ehci_hc_driver, &pdev->dev, "mv ehci");
+ hcd = usb_create_hcd(&ehci_platform_hc_driver, &pdev->dev, "mv ehci");
if (!hcd)
return -ENOMEM;
- ehci_mv = devm_kzalloc(&pdev->dev, sizeof(*ehci_mv), GFP_KERNEL);
- if (ehci_mv == NULL) {
- retval = -ENOMEM;
- goto err_put_hcd;
+ platform_set_drvdata(pdev, hcd);
+ ehci_mv = hcd_to_ehci_hcd_mv(hcd);
+
+ ehci_mv->mode = MV_USB_MODE_HOST;
+ if (pdata) {
+ ehci_mv->mode = pdata->mode;
+ ehci_mv->set_vbus = pdata->set_vbus;
}
- platform_set_drvdata(pdev, ehci_mv);
- ehci_mv->pdata = pdata;
- ehci_mv->hcd = hcd;
+ ehci_mv->phy = devm_phy_get(&pdev->dev, "usb");
+ if (IS_ERR(ehci_mv->phy)) {
+ retval = PTR_ERR(ehci_mv->phy);
+ if (retval != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Failed to get phy.\n");
+ goto err_put_hcd;
+ }
ehci_mv->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(ehci_mv->clk)) {
@@ -164,17 +131,12 @@ static int mv_ehci_probe(struct platform_device *pdev)
goto err_put_hcd;
}
- r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phyregs");
- ehci_mv->phy_regs = devm_ioremap_resource(&pdev->dev, r);
- if (IS_ERR(ehci_mv->phy_regs)) {
- retval = PTR_ERR(ehci_mv->phy_regs);
- goto err_put_hcd;
- }
- r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "capregs");
- ehci_mv->cap_regs = devm_ioremap_resource(&pdev->dev, r);
- if (IS_ERR(ehci_mv->cap_regs)) {
- retval = PTR_ERR(ehci_mv->cap_regs);
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ ehci_mv->base = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(ehci_mv->base)) {
+ retval = PTR_ERR(ehci_mv->base);
goto err_put_hcd;
}
@@ -184,6 +146,8 @@ static int mv_ehci_probe(struct platform_device *pdev)
goto err_put_hcd;
}
+ ehci_mv->cap_regs =
+ (void __iomem *) ((unsigned long) ehci_mv->base + U2x_CAPREGS_OFFSET);
offset = readl(ehci_mv->cap_regs) & CAPLENGTH_MASK;
ehci_mv->op_regs =
(void __iomem *) ((unsigned long) ehci_mv->cap_regs + offset);
@@ -202,7 +166,6 @@ static int mv_ehci_probe(struct platform_device *pdev)
ehci = hcd_to_ehci(hcd);
ehci->caps = (struct ehci_caps *) ehci_mv->cap_regs;
- ehci_mv->mode = pdata->mode;
if (ehci_mv->mode == MV_USB_MODE_OTG) {
ehci_mv->otg = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
if (IS_ERR(ehci_mv->otg)) {
@@ -227,8 +190,8 @@ static int mv_ehci_probe(struct platform_device *pdev)
/* otg will enable clock before use as host */
mv_ehci_disable(ehci_mv);
} else {
- if (pdata->set_vbus)
- pdata->set_vbus(1);
+ if (ehci_mv->set_vbus)
+ ehci_mv->set_vbus(1);
retval = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
if (retval) {
@@ -239,9 +202,6 @@ static int mv_ehci_probe(struct platform_device *pdev)
device_wakeup_enable(hcd->self.controller);
}
- if (pdata->private_init)
- pdata->private_init(ehci_mv->op_regs, ehci_mv->phy_regs);
-
dev_info(&pdev->dev,
"successful find EHCI device with regs 0x%p irq %d"
" working in %s mode\n", hcd->regs, hcd->irq,
@@ -250,8 +210,8 @@ static int mv_ehci_probe(struct platform_device *pdev)
return 0;
err_set_vbus:
- if (pdata->set_vbus)
- pdata->set_vbus(0);
+ if (ehci_mv->set_vbus)
+ ehci_mv->set_vbus(0);
err_disable_clk:
mv_ehci_disable(ehci_mv);
err_put_hcd:
@@ -262,8 +222,8 @@ err_put_hcd:
static int mv_ehci_remove(struct platform_device *pdev)
{
- struct ehci_hcd_mv *ehci_mv = platform_get_drvdata(pdev);
- struct usb_hcd *hcd = ehci_mv->hcd;
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct ehci_hcd_mv *ehci_mv = hcd_to_ehci_hcd_mv(hcd);
if (hcd->rh_registered)
usb_remove_hcd(hcd);
@@ -272,8 +232,8 @@ static int mv_ehci_remove(struct platform_device *pdev)
otg_set_host(ehci_mv->otg->otg, NULL);
if (ehci_mv->mode == MV_USB_MODE_HOST) {
- if (ehci_mv->pdata->set_vbus)
- ehci_mv->pdata->set_vbus(0);
+ if (ehci_mv->set_vbus)
+ ehci_mv->set_vbus(0);
mv_ehci_disable(ehci_mv);
}
@@ -295,8 +255,7 @@ static const struct platform_device_id ehci_id_table[] = {
static void mv_ehci_shutdown(struct platform_device *pdev)
{
- struct ehci_hcd_mv *ehci_mv = platform_get_drvdata(pdev);
- struct usb_hcd *hcd = ehci_mv->hcd;
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
if (!hcd->rh_registered)
return;
@@ -305,13 +264,41 @@ static void mv_ehci_shutdown(struct platform_device *pdev)
hcd->driver->shutdown(hcd);
}
+static const struct of_device_id ehci_mv_dt_ids[] = {
+ { .compatible = "marvell,pxau2o-ehci", },
+ {},
+};
+
static struct platform_driver ehci_mv_driver = {
.probe = mv_ehci_probe,
.remove = mv_ehci_remove,
.shutdown = mv_ehci_shutdown,
.driver = {
- .name = "mv-ehci",
- .bus = &platform_bus_type,
- },
+ .name = "mv-ehci",
+ .bus = &platform_bus_type,
+ .of_match_table = ehci_mv_dt_ids,
+ },
.id_table = ehci_id_table,
};
+
+static int __init ehci_platform_init(void)
+{
+ if (usb_disabled())
+ return -ENODEV;
+
+ ehci_init_driver(&ehci_platform_hc_driver, &platform_overrides);
+ return platform_driver_register(&ehci_mv_driver);
+}
+module_init(ehci_platform_init);
+
+static void __exit ehci_platform_cleanup(void)
+{
+ platform_driver_unregister(&ehci_mv_driver);
+}
+module_exit(ehci_platform_cleanup);
+
+MODULE_DESCRIPTION("Marvell EHCI driver");
+MODULE_AUTHOR("Chao Xie <chao.xie@marvell.com>");
+MODULE_AUTHOR("Neil Zhang <zhangwm@marvell.com>");
+MODULE_ALIAS("mv-ehci");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 327630405695..aa2f77f1506d 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -245,12 +245,12 @@ ehci_urb_done(struct ehci_hcd *ehci, struct urb *urb, int status)
}
if (unlikely(urb->unlinked)) {
- COUNT(ehci->stats.unlink);
+ INCR(ehci->stats.unlink);
} else {
/* report non-error and short read status as zero */
if (status == -EINPROGRESS || status == -EREMOTEIO)
status = 0;
- COUNT(ehci->stats.complete);
+ INCR(ehci->stats.complete);
}
#ifdef EHCI_URB_TRACE
diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c
index 4fcebda4b79d..a79c8ac0a55f 100644
--- a/drivers/usb/host/ehci-timer.c
+++ b/drivers/usb/host/ehci-timer.c
@@ -347,7 +347,7 @@ static void ehci_iaa_watchdog(struct ehci_hcd *ehci)
*/
status = ehci_readl(ehci, &ehci->regs->status);
if ((status & STS_IAA) || !(cmd & CMD_IAAD)) {
- COUNT(ehci->stats.lost_iaa);
+ INCR(ehci->stats.lost_iaa);
ehci_writel(ehci, STS_IAA, &ehci->regs->status);
}
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index c8e9a48e1d51..ac5e967907d1 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -235,9 +235,9 @@ struct ehci_hcd { /* one per controller */
/* irq statistics */
#ifdef EHCI_STATS
struct ehci_stats stats;
-# define COUNT(x) ((x)++)
+# define INCR(x) ((x)++)
#else
-# define COUNT(x)
+# define INCR(x) do {} while (0)
#endif
/* debug files */
diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c
index e64eb47770c8..0da68df259c8 100644
--- a/drivers/usb/host/fotg210-hcd.c
+++ b/drivers/usb/host/fotg210-hcd.c
@@ -31,6 +31,7 @@
#include <linux/uaccess.h>
#include <linux/platform_device.h>
#include <linux/io.h>
+#include <linux/clk.h>
#include <asm/byteorder.h>
#include <asm/irq.h>
@@ -1285,7 +1286,7 @@ static void fotg210_iaa_watchdog(struct fotg210_hcd *fotg210)
*/
status = fotg210_readl(fotg210, &fotg210->regs->status);
if ((status & STS_IAA) || !(cmd & CMD_IAAD)) {
- COUNT(fotg210->stats.lost_iaa);
+ INCR(fotg210->stats.lost_iaa);
fotg210_writel(fotg210, STS_IAA,
&fotg210->regs->status);
}
@@ -2204,12 +2205,12 @@ __acquires(fotg210->lock)
}
if (unlikely(urb->unlinked)) {
- COUNT(fotg210->stats.unlink);
+ INCR(fotg210->stats.unlink);
} else {
/* report non-error and short read status as zero */
if (status == -EINPROGRESS || status == -EREMOTEIO)
status = 0;
- COUNT(fotg210->stats.complete);
+ INCR(fotg210->stats.complete);
}
#ifdef FOTG210_URB_TRACE
@@ -5153,9 +5154,9 @@ static irqreturn_t fotg210_irq(struct usb_hcd *hcd)
/* normal [4.15.1.2] or error [4.15.1.1] completion */
if (likely((status & (STS_INT|STS_ERR)) != 0)) {
if (likely((status & STS_ERR) == 0))
- COUNT(fotg210->stats.normal);
+ INCR(fotg210->stats.normal);
else
- COUNT(fotg210->stats.error);
+ INCR(fotg210->stats.error);
bh = 1;
}
@@ -5180,7 +5181,7 @@ static irqreturn_t fotg210_irq(struct usb_hcd *hcd)
if (cmd & CMD_IAAD)
fotg210_dbg(fotg210, "IAA with IAAD still set?\n");
if (fotg210->async_iaa) {
- COUNT(fotg210->stats.iaa);
+ INCR(fotg210->stats.iaa);
end_unlink_async(fotg210);
} else
fotg210_dbg(fotg210, "IAA with nothing unlinked?\n");
@@ -5596,7 +5597,7 @@ static int fotg210_hcd_probe(struct platform_device *pdev)
hcd->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(hcd->regs)) {
retval = PTR_ERR(hcd->regs);
- goto failed;
+ goto failed_put_hcd;
}
hcd->rsrc_start = res->start;
@@ -5606,22 +5607,43 @@ static int fotg210_hcd_probe(struct platform_device *pdev)
fotg210->caps = hcd->regs;
+ /* It's OK not to supply this clock */
+ fotg210->pclk = clk_get(dev, "PCLK");
+ if (!IS_ERR(fotg210->pclk)) {
+ retval = clk_prepare_enable(fotg210->pclk);
+ if (retval) {
+ dev_err(dev, "failed to enable PCLK\n");
+ goto failed_put_hcd;
+ }
+ } else if (PTR_ERR(fotg210->pclk) == -EPROBE_DEFER) {
+ /*
+ * Percolate deferrals, for anything else,
+ * just live without the clocking.
+ */
+ retval = PTR_ERR(fotg210->pclk);
+ goto failed_dis_clk;
+ }
+
retval = fotg210_setup(hcd);
if (retval)
- goto failed;
+ goto failed_dis_clk;
fotg210_init(fotg210);
retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (retval) {
dev_err(dev, "failed to add hcd with err %d\n", retval);
- goto failed;
+ goto failed_dis_clk;
}
device_wakeup_enable(hcd->self.controller);
+ platform_set_drvdata(pdev, hcd);
return retval;
-failed:
+failed_dis_clk:
+ if (!IS_ERR(fotg210->pclk))
+ clk_disable_unprepare(fotg210->pclk);
+failed_put_hcd:
usb_put_hcd(hcd);
fail_create_hcd:
dev_err(dev, "init %s fail, %d\n", dev_name(dev), retval);
@@ -5635,11 +5657,11 @@ fail_create_hcd:
*/
static int fotg210_hcd_remove(struct platform_device *pdev)
{
- struct device *dev = &pdev->dev;
- struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
- if (!hcd)
- return 0;
+ if (!IS_ERR(fotg210->pclk))
+ clk_disable_unprepare(fotg210->pclk);
usb_remove_hcd(hcd);
usb_put_hcd(hcd);
diff --git a/drivers/usb/host/fotg210.h b/drivers/usb/host/fotg210.h
index 7fcd785c7bc8..1b4db95e5c43 100644
--- a/drivers/usb/host/fotg210.h
+++ b/drivers/usb/host/fotg210.h
@@ -177,11 +177,14 @@ struct fotg210_hcd { /* one per controller */
/* irq statistics */
#ifdef FOTG210_STATS
struct fotg210_stats stats;
-# define COUNT(x) ((x)++)
+# define INCR(x) ((x)++)
#else
-# define COUNT(x)
+# define INCR(x) do {} while (0)
#endif
+ /* silicon clock */
+ struct clk *pclk;
+
/* debug files */
struct dentry *debug_dir;
};
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index e98673954020..ec6739ef3129 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -551,6 +551,8 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev)
pdata->overcurrent_pin[i] =
devm_gpiod_get_index_optional(&pdev->dev, "atmel,oc",
i, GPIOD_IN);
+ if (!pdata->overcurrent_pin[i])
+ continue;
if (IS_ERR(pdata->overcurrent_pin[i])) {
err = PTR_ERR(pdata->overcurrent_pin[i]);
dev_err(&pdev->dev, "unable to claim gpio \"overcurrent\": %d\n", err);
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index 3625a5c1a41b..3ce71cbfbb58 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -783,15 +783,9 @@ static void quirk_usb_handoff_ohci(struct pci_dev *pdev)
/* disable interrupts */
writel((u32) ~0, base + OHCI_INTRDISABLE);
- /* Reset the USB bus, if the controller isn't already in RESET */
- if (control & OHCI_HCFS) {
- /* Go into RESET, preserving RWC (and possibly IR) */
- writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL);
- readl(base + OHCI_CONTROL);
-
- /* drive bus reset for at least 50 ms (7.1.7.5) */
- msleep(50);
- }
+ /* Go into the USB_RESET state, preserving RWC (and possibly IR) */
+ writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL);
+ readl(base + OHCI_CONTROL);
/* software reset of the controller, preserving HcFmInterval */
if (!no_fminterval)
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 7e2a531ba321..12eea73d9f20 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -900,6 +900,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
set_bit(wIndex, &bus_state->resuming_ports);
bus_state->resume_done[wIndex] = timeout;
mod_timer(&hcd->rh_timer, timeout);
+ usb_hcd_start_port_resume(&hcd->self, wIndex);
}
/* Has resume been signalled for USB_RESUME_TIME yet? */
} else if (time_after_eq(jiffies,
@@ -940,6 +941,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
clear_bit(wIndex, &bus_state->rexit_ports);
}
+ usb_hcd_end_port_resume(&hcd->self, wIndex);
bus_state->port_c_suspend |= 1 << wIndex;
bus_state->suspended_ports &= ~(1 << wIndex);
} else {
@@ -962,6 +964,7 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
(raw_port_status & PORT_PLS_MASK) != XDEV_RESUME) {
bus_state->resume_done[wIndex] = 0;
clear_bit(wIndex, &bus_state->resuming_ports);
+ usb_hcd_end_port_resume(&hcd->self, wIndex);
}
@@ -1337,6 +1340,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
goto error;
set_bit(wIndex, &bus_state->resuming_ports);
+ usb_hcd_start_port_resume(&hcd->self, wIndex);
xhci_set_link_state(xhci, ports[wIndex],
XDEV_RESUME);
spin_unlock_irqrestore(&xhci->lock, flags);
@@ -1345,6 +1349,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
xhci_set_link_state(xhci, ports[wIndex],
XDEV_U0);
clear_bit(wIndex, &bus_state->resuming_ports);
+ usb_hcd_end_port_resume(&hcd->self, wIndex);
}
bus_state->port_c_suspend |= 1 << wIndex;
diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
index fa33d6e5b1cb..fea555570ad4 100644
--- a/drivers/usb/host/xhci-mtk-sch.c
+++ b/drivers/usb/host/xhci-mtk-sch.c
@@ -13,14 +13,20 @@
#include "xhci.h"
#include "xhci-mtk.h"
+#define SSP_BW_BOUNDARY 130000
#define SS_BW_BOUNDARY 51000
/* table 5-5. High-speed Isoc Transaction Limits in usb_20 spec */
#define HS_BW_BOUNDARY 6144
/* usb2 spec section11.18.1: at most 188 FS bytes per microframe */
#define FS_PAYLOAD_MAX 188
+/*
+ * max number of microframes for split transfer,
+ * for fs isoc in : 1 ss + 1 idle + 7 cs
+ */
+#define TT_MICROFRAMES_MAX 9
/* mtk scheduler bitmasks */
-#define EP_BPKTS(p) ((p) & 0x3f)
+#define EP_BPKTS(p) ((p) & 0x7f)
#define EP_BCSCOUNT(p) (((p) & 0x7) << 8)
#define EP_BBM(p) ((p) << 11)
#define EP_BOFFSET(p) ((p) & 0x3fff)
@@ -51,7 +57,7 @@ static int get_bw_index(struct xhci_hcd *xhci, struct usb_device *udev,
virt_dev = xhci->devs[udev->slot_id];
- if (udev->speed == USB_SPEED_SUPER) {
+ if (udev->speed >= USB_SPEED_SUPER) {
if (usb_endpoint_dir_out(&ep->desc))
bw_index = (virt_dev->real_port - 1) * 2;
else
@@ -64,25 +70,167 @@ static int get_bw_index(struct xhci_hcd *xhci, struct usb_device *udev,
return bw_index;
}
+static u32 get_esit(struct xhci_ep_ctx *ep_ctx)
+{
+ u32 esit;
+
+ esit = 1 << CTX_TO_EP_INTERVAL(le32_to_cpu(ep_ctx->ep_info));
+ if (esit > XHCI_MTK_MAX_ESIT)
+ esit = XHCI_MTK_MAX_ESIT;
+
+ return esit;
+}
+
+static struct mu3h_sch_tt *find_tt(struct usb_device *udev)
+{
+ struct usb_tt *utt = udev->tt;
+ struct mu3h_sch_tt *tt, **tt_index, **ptt;
+ unsigned int port;
+ bool allocated_index = false;
+
+ if (!utt)
+ return NULL; /* Not below a TT */
+
+ /*
+ * Find/create our data structure.
+ * For hubs with a single TT, we get it directly.
+ * For hubs with multiple TTs, there's an extra level of pointers.
+ */
+ tt_index = NULL;
+ if (utt->multi) {
+ tt_index = utt->hcpriv;
+ if (!tt_index) { /* Create the index array */
+ tt_index = kcalloc(utt->hub->maxchild,
+ sizeof(*tt_index), GFP_KERNEL);
+ if (!tt_index)
+ return ERR_PTR(-ENOMEM);
+ utt->hcpriv = tt_index;
+ allocated_index = true;
+ }
+ port = udev->ttport - 1;
+ ptt = &tt_index[port];
+ } else {
+ port = 0;
+ ptt = (struct mu3h_sch_tt **) &utt->hcpriv;
+ }
+
+ tt = *ptt;
+ if (!tt) { /* Create the mu3h_sch_tt */
+ tt = kzalloc(sizeof(*tt), GFP_KERNEL);
+ if (!tt) {
+ if (allocated_index) {
+ utt->hcpriv = NULL;
+ kfree(tt_index);
+ }
+ return ERR_PTR(-ENOMEM);
+ }
+ INIT_LIST_HEAD(&tt->ep_list);
+ tt->usb_tt = utt;
+ tt->tt_port = port;
+ *ptt = tt;
+ }
+
+ return tt;
+}
+
+/* Release the TT above udev, if it's not in use */
+static void drop_tt(struct usb_device *udev)
+{
+ struct usb_tt *utt = udev->tt;
+ struct mu3h_sch_tt *tt, **tt_index, **ptt;
+ int i, cnt;
+
+ if (!utt || !utt->hcpriv)
+ return; /* Not below a TT, or never allocated */
+
+ cnt = 0;
+ if (utt->multi) {
+ tt_index = utt->hcpriv;
+ ptt = &tt_index[udev->ttport - 1];
+ /* How many entries are left in tt_index? */
+ for (i = 0; i < utt->hub->maxchild; ++i)
+ cnt += !!tt_index[i];
+ } else {
+ tt_index = NULL;
+ ptt = (struct mu3h_sch_tt **)&utt->hcpriv;
+ }
+
+ tt = *ptt;
+ if (!tt || !list_empty(&tt->ep_list))
+ return; /* never allocated , or still in use*/
+
+ *ptt = NULL;
+ kfree(tt);
+
+ if (cnt == 1) {
+ utt->hcpriv = NULL;
+ kfree(tt_index);
+ }
+}
+
+static struct mu3h_sch_ep_info *create_sch_ep(struct usb_device *udev,
+ struct usb_host_endpoint *ep, struct xhci_ep_ctx *ep_ctx)
+{
+ struct mu3h_sch_ep_info *sch_ep;
+ struct mu3h_sch_tt *tt = NULL;
+ u32 len_bw_budget_table;
+ size_t mem_size;
+
+ if (is_fs_or_ls(udev->speed))
+ len_bw_budget_table = TT_MICROFRAMES_MAX;
+ else if ((udev->speed >= USB_SPEED_SUPER)
+ && usb_endpoint_xfer_isoc(&ep->desc))
+ len_bw_budget_table = get_esit(ep_ctx);
+ else
+ len_bw_budget_table = 1;
+
+ mem_size = sizeof(struct mu3h_sch_ep_info) +
+ len_bw_budget_table * sizeof(u32);
+ sch_ep = kzalloc(mem_size, GFP_KERNEL);
+ if (!sch_ep)
+ return ERR_PTR(-ENOMEM);
+
+ if (is_fs_or_ls(udev->speed)) {
+ tt = find_tt(udev);
+ if (IS_ERR(tt)) {
+ kfree(sch_ep);
+ return ERR_PTR(-ENOMEM);
+ }
+ }
+
+ sch_ep->sch_tt = tt;
+ sch_ep->ep = ep;
+
+ return sch_ep;
+}
+
static void setup_sch_info(struct usb_device *udev,
struct xhci_ep_ctx *ep_ctx, struct mu3h_sch_ep_info *sch_ep)
{
u32 ep_type;
- u32 ep_interval;
- u32 max_packet_size;
+ u32 maxpkt;
u32 max_burst;
u32 mult;
u32 esit_pkts;
+ u32 max_esit_payload;
+ u32 *bwb_table = sch_ep->bw_budget_table;
+ int i;
ep_type = CTX_TO_EP_TYPE(le32_to_cpu(ep_ctx->ep_info2));
- ep_interval = CTX_TO_EP_INTERVAL(le32_to_cpu(ep_ctx->ep_info));
- max_packet_size = MAX_PACKET_DECODED(le32_to_cpu(ep_ctx->ep_info2));
+ maxpkt = MAX_PACKET_DECODED(le32_to_cpu(ep_ctx->ep_info2));
max_burst = CTX_TO_MAX_BURST(le32_to_cpu(ep_ctx->ep_info2));
mult = CTX_TO_EP_MULT(le32_to_cpu(ep_ctx->ep_info));
-
- sch_ep->esit = 1 << ep_interval;
+ max_esit_payload =
+ (CTX_TO_MAX_ESIT_PAYLOAD_HI(
+ le32_to_cpu(ep_ctx->ep_info)) << 16) |
+ CTX_TO_MAX_ESIT_PAYLOAD(le32_to_cpu(ep_ctx->tx_info));
+
+ sch_ep->esit = get_esit(ep_ctx);
+ sch_ep->ep_type = ep_type;
+ sch_ep->maxpkt = maxpkt;
sch_ep->offset = 0;
sch_ep->burst_mode = 0;
+ sch_ep->repeat = 0;
if (udev->speed == USB_SPEED_HIGH) {
sch_ep->cs_count = 0;
@@ -93,7 +241,6 @@ static void setup_sch_info(struct usb_device *udev,
* in a interval
*/
sch_ep->num_budget_microframes = 1;
- sch_ep->repeat = 0;
/*
* xHCI spec section6.2.3.4
@@ -101,19 +248,33 @@ static void setup_sch_info(struct usb_device *udev,
* opportunities per microframe
*/
sch_ep->pkts = max_burst + 1;
- sch_ep->bw_cost_per_microframe = max_packet_size * sch_ep->pkts;
- } else if (udev->speed == USB_SPEED_SUPER) {
+ sch_ep->bw_cost_per_microframe = maxpkt * sch_ep->pkts;
+ bwb_table[0] = sch_ep->bw_cost_per_microframe;
+ } else if (udev->speed >= USB_SPEED_SUPER) {
/* usb3_r1 spec section4.4.7 & 4.4.8 */
sch_ep->cs_count = 0;
- esit_pkts = (mult + 1) * (max_burst + 1);
+ sch_ep->burst_mode = 1;
+ /*
+ * some device's (d)wBytesPerInterval is set as 0,
+ * then max_esit_payload is 0, so evaluate esit_pkts from
+ * mult and burst
+ */
+ esit_pkts = DIV_ROUND_UP(max_esit_payload, maxpkt);
+ if (esit_pkts == 0)
+ esit_pkts = (mult + 1) * (max_burst + 1);
+
if (ep_type == INT_IN_EP || ep_type == INT_OUT_EP) {
sch_ep->pkts = esit_pkts;
sch_ep->num_budget_microframes = 1;
- sch_ep->repeat = 0;
+ bwb_table[0] = maxpkt * sch_ep->pkts;
}
if (ep_type == ISOC_IN_EP || ep_type == ISOC_OUT_EP) {
- if (esit_pkts <= sch_ep->esit)
+ u32 remainder;
+
+ if (sch_ep->esit == 1)
+ sch_ep->pkts = esit_pkts;
+ else if (esit_pkts <= sch_ep->esit)
sch_ep->pkts = 1;
else
sch_ep->pkts = roundup_pow_of_two(esit_pkts)
@@ -122,43 +283,48 @@ static void setup_sch_info(struct usb_device *udev,
sch_ep->num_budget_microframes =
DIV_ROUND_UP(esit_pkts, sch_ep->pkts);
- if (sch_ep->num_budget_microframes > 1)
- sch_ep->repeat = 1;
- else
- sch_ep->repeat = 0;
+ sch_ep->repeat = !!(sch_ep->num_budget_microframes > 1);
+ sch_ep->bw_cost_per_microframe = maxpkt * sch_ep->pkts;
+
+ remainder = sch_ep->bw_cost_per_microframe;
+ remainder *= sch_ep->num_budget_microframes;
+ remainder -= (maxpkt * esit_pkts);
+ for (i = 0; i < sch_ep->num_budget_microframes - 1; i++)
+ bwb_table[i] = sch_ep->bw_cost_per_microframe;
+
+ /* last one <= bw_cost_per_microframe */
+ bwb_table[i] = remainder;
}
- sch_ep->bw_cost_per_microframe = max_packet_size * sch_ep->pkts;
} else if (is_fs_or_ls(udev->speed)) {
+ sch_ep->pkts = 1; /* at most one packet for each microframe */
/*
- * usb_20 spec section11.18.4
- * assume worst cases
+ * num_budget_microframes and cs_count will be updated when
+ * check TT for INT_OUT_EP, ISOC/INT_IN_EP type
*/
- sch_ep->repeat = 0;
- sch_ep->pkts = 1; /* at most one packet for each microframe */
- if (ep_type == INT_IN_EP || ep_type == INT_OUT_EP) {
- sch_ep->cs_count = 3; /* at most need 3 CS*/
- /* one for SS and one for budgeted transaction */
- sch_ep->num_budget_microframes = sch_ep->cs_count + 2;
- sch_ep->bw_cost_per_microframe = max_packet_size;
- }
- if (ep_type == ISOC_OUT_EP) {
+ sch_ep->cs_count = DIV_ROUND_UP(maxpkt, FS_PAYLOAD_MAX);
+ sch_ep->num_budget_microframes = sch_ep->cs_count;
+ sch_ep->bw_cost_per_microframe =
+ (maxpkt < FS_PAYLOAD_MAX) ? maxpkt : FS_PAYLOAD_MAX;
+ /* init budget table */
+ if (ep_type == ISOC_OUT_EP) {
+ for (i = 0; i < sch_ep->num_budget_microframes; i++)
+ bwb_table[i] = sch_ep->bw_cost_per_microframe;
+ } else if (ep_type == INT_OUT_EP) {
+ /* only first one consumes bandwidth, others as zero */
+ bwb_table[0] = sch_ep->bw_cost_per_microframe;
+ } else { /* INT_IN_EP or ISOC_IN_EP */
+ bwb_table[0] = 0; /* start split */
+ bwb_table[1] = 0; /* idle */
/*
- * the best case FS budget assumes that 188 FS bytes
- * occur in each microframe
+ * due to cs_count will be updated according to cs
+ * position, assign all remainder budget array
+ * elements as @bw_cost_per_microframe, but only first
+ * @num_budget_microframes elements will be used later
*/
- sch_ep->num_budget_microframes = DIV_ROUND_UP(
- max_packet_size, FS_PAYLOAD_MAX);
- sch_ep->bw_cost_per_microframe = FS_PAYLOAD_MAX;
- sch_ep->cs_count = sch_ep->num_budget_microframes;
- }
- if (ep_type == ISOC_IN_EP) {
- /* at most need additional two CS. */
- sch_ep->cs_count = DIV_ROUND_UP(
- max_packet_size, FS_PAYLOAD_MAX) + 2;
- sch_ep->num_budget_microframes = sch_ep->cs_count + 2;
- sch_ep->bw_cost_per_microframe = FS_PAYLOAD_MAX;
+ for (i = 2; i < TT_MICROFRAMES_MAX; i++)
+ bwb_table[i] = sch_ep->bw_cost_per_microframe;
}
}
}
@@ -169,6 +335,7 @@ static u32 get_max_bw(struct mu3h_sch_bw_info *sch_bw,
{
u32 num_esit;
u32 max_bw = 0;
+ u32 bw;
int i;
int j;
@@ -177,15 +344,17 @@ static u32 get_max_bw(struct mu3h_sch_bw_info *sch_bw,
u32 base = offset + i * sch_ep->esit;
for (j = 0; j < sch_ep->num_budget_microframes; j++) {
- if (sch_bw->bus_bw[base + j] > max_bw)
- max_bw = sch_bw->bus_bw[base + j];
+ bw = sch_bw->bus_bw[base + j] +
+ sch_ep->bw_budget_table[j];
+ if (bw > max_bw)
+ max_bw = bw;
}
}
return max_bw;
}
static void update_bus_bw(struct mu3h_sch_bw_info *sch_bw,
- struct mu3h_sch_ep_info *sch_ep, int bw_cost)
+ struct mu3h_sch_ep_info *sch_ep, bool used)
{
u32 num_esit;
u32 base;
@@ -195,9 +364,105 @@ static void update_bus_bw(struct mu3h_sch_bw_info *sch_bw,
num_esit = XHCI_MTK_MAX_ESIT / sch_ep->esit;
for (i = 0; i < num_esit; i++) {
base = sch_ep->offset + i * sch_ep->esit;
+ for (j = 0; j < sch_ep->num_budget_microframes; j++) {
+ if (used)
+ sch_bw->bus_bw[base + j] +=
+ sch_ep->bw_budget_table[j];
+ else
+ sch_bw->bus_bw[base + j] -=
+ sch_ep->bw_budget_table[j];
+ }
+ }
+}
+
+static int check_sch_tt(struct usb_device *udev,
+ struct mu3h_sch_ep_info *sch_ep, u32 offset)
+{
+ struct mu3h_sch_tt *tt = sch_ep->sch_tt;
+ u32 extra_cs_count;
+ u32 fs_budget_start;
+ u32 start_ss, last_ss;
+ u32 start_cs, last_cs;
+ int i;
+
+ start_ss = offset % 8;
+ fs_budget_start = (start_ss + 1) % 8;
+
+ if (sch_ep->ep_type == ISOC_OUT_EP) {
+ last_ss = start_ss + sch_ep->cs_count - 1;
+
+ /*
+ * usb_20 spec section11.18:
+ * must never schedule Start-Split in Y6
+ */
+ if (!(start_ss == 7 || last_ss < 6))
+ return -ERANGE;
+
+ for (i = 0; i < sch_ep->cs_count; i++)
+ if (test_bit(offset + i, tt->split_bit_map))
+ return -ERANGE;
+
+ } else {
+ u32 cs_count = DIV_ROUND_UP(sch_ep->maxpkt, FS_PAYLOAD_MAX);
+
+ /*
+ * usb_20 spec section11.18:
+ * must never schedule Start-Split in Y6
+ */
+ if (start_ss == 6)
+ return -ERANGE;
+
+ /* one uframe for ss + one uframe for idle */
+ start_cs = (start_ss + 2) % 8;
+ last_cs = start_cs + cs_count - 1;
+
+ if (last_cs > 7)
+ return -ERANGE;
+
+ if (sch_ep->ep_type == ISOC_IN_EP)
+ extra_cs_count = (last_cs == 7) ? 1 : 2;
+ else /* ep_type : INTR IN / INTR OUT */
+ extra_cs_count = (fs_budget_start == 6) ? 1 : 2;
+
+ cs_count += extra_cs_count;
+ if (cs_count > 7)
+ cs_count = 7; /* HW limit */
+
+ for (i = 0; i < cs_count + 2; i++) {
+ if (test_bit(offset + i, tt->split_bit_map))
+ return -ERANGE;
+ }
+
+ sch_ep->cs_count = cs_count;
+ /* one for ss, the other for idle */
+ sch_ep->num_budget_microframes = cs_count + 2;
+
+ /*
+ * if interval=1, maxp >752, num_budge_micoframe is larger
+ * than sch_ep->esit, will overstep boundary
+ */
+ if (sch_ep->num_budget_microframes > sch_ep->esit)
+ sch_ep->num_budget_microframes = sch_ep->esit;
+ }
+
+ return 0;
+}
+
+static void update_sch_tt(struct usb_device *udev,
+ struct mu3h_sch_ep_info *sch_ep)
+{
+ struct mu3h_sch_tt *tt = sch_ep->sch_tt;
+ u32 base, num_esit;
+ int i, j;
+
+ num_esit = XHCI_MTK_MAX_ESIT / sch_ep->esit;
+ for (i = 0; i < num_esit; i++) {
+ base = sch_ep->offset + i * sch_ep->esit;
for (j = 0; j < sch_ep->num_budget_microframes; j++)
- sch_bw->bus_bw[base + j] += bw_cost;
+ set_bit(base + j, tt->split_bit_map);
}
+
+ list_add_tail(&sch_ep->tt_endpoint, &tt->ep_list);
}
static int check_sch_bw(struct usb_device *udev,
@@ -205,17 +470,16 @@ static int check_sch_bw(struct usb_device *udev,
{
u32 offset;
u32 esit;
- u32 num_budget_microframes;
u32 min_bw;
u32 min_index;
u32 worst_bw;
u32 bw_boundary;
-
- if (sch_ep->esit > XHCI_MTK_MAX_ESIT)
- sch_ep->esit = XHCI_MTK_MAX_ESIT;
+ u32 min_num_budget;
+ u32 min_cs_count;
+ bool tt_offset_ok = false;
+ int ret;
esit = sch_ep->esit;
- num_budget_microframes = sch_ep->num_budget_microframes;
/*
* Search through all possible schedule microframes.
@@ -223,36 +487,56 @@ static int check_sch_bw(struct usb_device *udev,
*/
min_bw = ~0;
min_index = 0;
+ min_cs_count = sch_ep->cs_count;
+ min_num_budget = sch_ep->num_budget_microframes;
for (offset = 0; offset < esit; offset++) {
- if ((offset + num_budget_microframes) > sch_ep->esit)
- break;
+ if (is_fs_or_ls(udev->speed)) {
+ ret = check_sch_tt(udev, sch_ep, offset);
+ if (ret)
+ continue;
+ else
+ tt_offset_ok = true;
+ }
- /*
- * usb_20 spec section11.18:
- * must never schedule Start-Split in Y6
- */
- if (is_fs_or_ls(udev->speed) && (offset % 8 == 6))
- continue;
+ if ((offset + sch_ep->num_budget_microframes) > sch_ep->esit)
+ break;
worst_bw = get_max_bw(sch_bw, sch_ep, offset);
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;
}
if (min_bw == 0)
break;
}
- sch_ep->offset = min_index;
- bw_boundary = (udev->speed == USB_SPEED_SUPER)
- ? SS_BW_BOUNDARY : HS_BW_BOUNDARY;
+ if (udev->speed == USB_SPEED_SUPER_PLUS)
+ bw_boundary = SSP_BW_BOUNDARY;
+ else if (udev->speed == USB_SPEED_SUPER)
+ bw_boundary = SS_BW_BOUNDARY;
+ else
+ bw_boundary = HS_BW_BOUNDARY;
/* check bandwidth */
- if (min_bw + sch_ep->bw_cost_per_microframe > bw_boundary)
+ if (min_bw > bw_boundary)
return -ERANGE;
+ sch_ep->offset = min_index;
+ sch_ep->cs_count = min_cs_count;
+ sch_ep->num_budget_microframes = min_num_budget;
+
+ if (is_fs_or_ls(udev->speed)) {
+ /* all offset for tt is not ok*/
+ if (!tt_offset_ok)
+ return -ERANGE;
+
+ update_sch_tt(udev, sch_ep);
+ }
+
/* update bus bandwidth info */
- update_bus_bw(sch_bw, sch_ep, sch_ep->bw_cost_per_microframe);
+ update_bus_bw(sch_bw, sch_ep, 1);
return 0;
}
@@ -347,8 +631,8 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
bw_index = get_bw_index(xhci, udev, ep);
sch_bw = &sch_array[bw_index];
- sch_ep = kzalloc(sizeof(struct mu3h_sch_ep_info), GFP_NOIO);
- if (!sch_ep)
+ sch_ep = create_sch_ep(udev, ep, ep_ctx);
+ if (IS_ERR_OR_NULL(sch_ep))
return -ENOMEM;
setup_sch_info(udev, ep_ctx, sch_ep);
@@ -356,12 +640,14 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
ret = check_sch_bw(udev, sch_bw, sch_ep);
if (ret) {
xhci_err(xhci, "Not enough bandwidth!\n");
+ if (is_fs_or_ls(udev->speed))
+ drop_tt(udev);
+
kfree(sch_ep);
return -ENOSPC;
}
list_add_tail(&sch_ep->endpoint, &sch_bw->bw_ep_list);
- sch_ep->ep = ep;
ep_ctx->reserved[0] |= cpu_to_le32(EP_BPKTS(sch_ep->pkts)
| EP_BCSCOUNT(sch_ep->cs_count) | EP_BBM(sch_ep->burst_mode));
@@ -406,9 +692,12 @@ void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
list_for_each_entry(sch_ep, &sch_bw->bw_ep_list, endpoint) {
if (sch_ep->ep == ep) {
- update_bus_bw(sch_bw, sch_ep,
- -sch_ep->bw_cost_per_microframe);
+ update_bus_bw(sch_bw, sch_ep, 0);
list_del(&sch_ep->endpoint);
+ if (is_fs_or_ls(udev->speed)) {
+ list_del(&sch_ep->tt_endpoint);
+ drop_tt(udev);
+ }
kfree(sch_ep);
break;
}
diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c
index 7334da9e9779..71d0d33c3286 100644
--- a/drivers/usb/host/xhci-mtk.c
+++ b/drivers/usb/host/xhci-mtk.c
@@ -642,10 +642,10 @@ static int __maybe_unused xhci_mtk_resume(struct device *dev)
xhci_mtk_host_enable(mtk);
xhci_dbg(xhci, "%s: restart port polling\n", __func__);
- set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
- usb_hcd_poll_rh_status(hcd);
set_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags);
usb_hcd_poll_rh_status(xhci->shared_hcd);
+ set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
+ usb_hcd_poll_rh_status(hcd);
return 0;
}
diff --git a/drivers/usb/host/xhci-mtk.h b/drivers/usb/host/xhci-mtk.h
index cc59d80b663b..8be8c5f7ff62 100644
--- a/drivers/usb/host/xhci-mtk.h
+++ b/drivers/usb/host/xhci-mtk.h
@@ -20,6 +20,19 @@
#define XHCI_MTK_MAX_ESIT 64
/**
+ * @split_bit_map: used to avoid split microframes overlay
+ * @ep_list: Endpoints using this TT
+ * @usb_tt: usb TT related
+ * @tt_port: TT port number
+ */
+struct mu3h_sch_tt {
+ DECLARE_BITMAP(split_bit_map, XHCI_MTK_MAX_ESIT);
+ struct list_head ep_list;
+ struct usb_tt *usb_tt;
+ int tt_port;
+};
+
+/**
* struct mu3h_sch_bw_info: schedule information for bandwidth domain
*
* @bus_bw: array to keep track of bandwidth already used at each uframes
@@ -41,6 +54,10 @@ struct mu3h_sch_bw_info {
* (@repeat==1) scheduled within the interval
* @bw_cost_per_microframe: bandwidth cost per microframe
* @endpoint: linked into bandwidth domain which it belongs to
+ * @tt_endpoint: linked into mu3h_sch_tt's list which it belongs to
+ * @sch_tt: mu3h_sch_tt linked into
+ * @ep_type: endpoint type
+ * @maxpkt: max packet size of endpoint
* @ep: address of usb_host_endpoint struct
* @offset: which uframe of the interval that transfer should be
* scheduled first time within the interval
@@ -57,12 +74,17 @@ struct mu3h_sch_bw_info {
* times; 1: distribute the (bMaxBurst+1)*(Mult+1) packets
* according to @pkts and @repeat. normal mode is used by
* default
+ * @bw_budget_table: table to record bandwidth budget per microframe
*/
struct mu3h_sch_ep_info {
u32 esit;
u32 num_budget_microframes;
u32 bw_cost_per_microframe;
struct list_head endpoint;
+ struct list_head tt_endpoint;
+ struct mu3h_sch_tt *sch_tt;
+ u32 ep_type;
+ u32 maxpkt;
void *ep;
/*
* mtk xHCI scheduling information put into reserved DWs
@@ -73,6 +95,7 @@ struct mu3h_sch_ep_info {
u32 pkts;
u32 cs_count;
u32 burst_mode;
+ u32 bw_budget_table[0];
};
#define MU3C_U3_PORT_MAX 4
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 6372edf339d9..01c57055c0c5 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -41,6 +41,13 @@
#define PCI_DEVICE_ID_INTEL_BROXTON_B_XHCI 0x1aa8
#define PCI_DEVICE_ID_INTEL_APL_XHCI 0x5aa8
#define PCI_DEVICE_ID_INTEL_DNV_XHCI 0x19d0
+#define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_2C_XHCI 0x15b5
+#define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_4C_XHCI 0x15b6
+#define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_2C_XHCI 0x15db
+#define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_4C_XHCI 0x15d4
+#define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_2C_XHCI 0x15e9
+#define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_4C_XHCI 0x15ec
+#define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_DD_XHCI 0x15f0
#define PCI_DEVICE_ID_AMD_PROMONTORYA_4 0x43b9
#define PCI_DEVICE_ID_AMD_PROMONTORYA_3 0x43ba
@@ -179,16 +186,30 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
xhci->quirks |= XHCI_PME_STUCK_QUIRK;
}
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
- pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI) {
+ pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI)
xhci->quirks |= XHCI_SSIC_PORT_UNUSED;
+ if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
+ (pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI ||
+ pdev->device == PCI_DEVICE_ID_INTEL_APL_XHCI))
xhci->quirks |= XHCI_INTEL_USB_ROLE_SW;
- }
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
(pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI ||
+ pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI ||
+ pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_APL_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_DNV_XHCI))
xhci->quirks |= XHCI_MISSING_CAS;
+ if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
+ (pdev->device == PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_2C_XHCI ||
+ pdev->device == PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_4C_XHCI ||
+ pdev->device == PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_2C_XHCI ||
+ pdev->device == PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_4C_XHCI ||
+ pdev->device == PCI_DEVICE_ID_INTEL_TITAN_RIDGE_2C_XHCI ||
+ pdev->device == PCI_DEVICE_ID_INTEL_TITAN_RIDGE_4C_XHCI ||
+ pdev->device == PCI_DEVICE_ID_INTEL_TITAN_RIDGE_DD_XHCI))
+ xhci->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW;
+
if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
pdev->device == PCI_DEVICE_ID_EJ168) {
xhci->quirks |= XHCI_RESET_ON_RESUME;
@@ -332,6 +353,9 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
/* USB-2 and USB-3 roothubs initialized, allow runtime pm suspend */
pm_runtime_put_noidle(&dev->dev);
+ if (xhci->quirks & XHCI_DEFAULT_PM_RUNTIME_ALLOW)
+ pm_runtime_allow(&dev->dev);
+
return 0;
put_usb3_hcd:
@@ -349,6 +373,10 @@ static void xhci_pci_remove(struct pci_dev *dev)
xhci = hcd_to_xhci(pci_get_drvdata(dev));
xhci->xhc_state |= XHCI_STATE_REMOVING;
+
+ if (xhci->quirks & XHCI_DEFAULT_PM_RUNTIME_ALLOW)
+ pm_runtime_forbid(&dev->dev);
+
if (xhci->shared_hcd) {
usb_remove_hcd(xhci->shared_hcd);
usb_put_hcd(xhci->shared_hcd);
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 94e939249b2b..32b5574ad5c5 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -18,6 +18,7 @@
#include <linux/usb/phy.h>
#include <linux/slab.h>
#include <linux/acpi.h>
+#include <linux/usb/of.h>
#include "xhci.h"
#include "xhci-plat.h"
@@ -305,6 +306,8 @@ static int xhci_plat_probe(struct platform_device *pdev)
hcd->skip_phy_initialization = 1;
}
+ hcd->tpl_support = of_usb_host_tpl_support(sysdev->of_node);
+ xhci->shared_hcd->tpl_support = hcd->tpl_support;
ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (ret)
goto disable_usb_phy;
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index f0a99aa0ac58..a8d92c90fb58 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1155,6 +1155,10 @@ static void xhci_handle_cmd_reset_ep(struct xhci_hcd *xhci, int slot_id,
/* Clear our internal halted state */
xhci->devs[slot_id]->eps[ep_index].ep_state &= ~EP_HALTED;
}
+
+ /* if this was a soft reset, then restart */
+ if ((le32_to_cpu(trb->generic.field[3])) & TRB_TSP)
+ ring_doorbell_for_active_rings(xhci, slot_id, ep_index);
}
static void xhci_handle_cmd_enable_slot(struct xhci_hcd *xhci, int slot_id,
@@ -1602,6 +1606,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
mod_timer(&hcd->rh_timer,
bus_state->resume_done[hcd_portnum]);
+ usb_hcd_start_port_resume(&hcd->self, hcd_portnum);
bogus_port_status = true;
}
}
@@ -2132,10 +2137,16 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
union xhci_trb *ep_trb, struct xhci_transfer_event *event,
struct xhci_virt_ep *ep, int *status)
{
+ struct xhci_slot_ctx *slot_ctx;
struct xhci_ring *ep_ring;
u32 trb_comp_code;
u32 remaining, requested, ep_trb_len;
+ unsigned int slot_id;
+ int ep_index;
+ slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags));
+ slot_ctx = xhci_get_slot_ctx(xhci, xhci->devs[slot_id]->out_ctx);
+ ep_index = TRB_TO_EP_ID(le32_to_cpu(event->flags)) - 1;
ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer));
trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len));
remaining = EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));
@@ -2144,6 +2155,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
switch (trb_comp_code) {
case COMP_SUCCESS:
+ ep_ring->err_count = 0;
/* handle success with untransferred data as short packet */
if (ep_trb != td->last_trb || remaining) {
xhci_warn(xhci, "WARN Successful completion on short TX\n");
@@ -2167,6 +2179,14 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
ep_trb_len = 0;
remaining = 0;
break;
+ case COMP_USB_TRANSACTION_ERROR:
+ if ((ep_ring->err_count++ > MAX_SOFT_RETRY) ||
+ le32_to_cpu(slot_ctx->tt_info) & TT_SLOT)
+ break;
+ *status = 0;
+ xhci_cleanup_halted_endpoint(xhci, slot_id, ep_index,
+ ep_ring->stream_id, td, EP_SOFT_RESET);
+ return 0;
default:
/* do nothing */
break;
diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c
index 4b463e5202a4..6b5db344de30 100644
--- a/drivers/usb/host/xhci-tegra.c
+++ b/drivers/usb/host/xhci-tegra.c
@@ -18,6 +18,7 @@
#include <linux/phy/tegra/xusb.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
+#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
@@ -107,35 +108,35 @@
#define IMEM_BLOCK_SIZE 256
struct tegra_xusb_fw_header {
- u32 boot_loadaddr_in_imem;
- u32 boot_codedfi_offset;
- u32 boot_codetag;
- u32 boot_codesize;
- u32 phys_memaddr;
- u16 reqphys_memsize;
- u16 alloc_phys_memsize;
- u32 rodata_img_offset;
- u32 rodata_section_start;
- u32 rodata_section_end;
- u32 main_fnaddr;
- u32 fwimg_cksum;
- u32 fwimg_created_time;
- u32 imem_resident_start;
- u32 imem_resident_end;
- u32 idirect_start;
- u32 idirect_end;
- u32 l2_imem_start;
- u32 l2_imem_end;
- u32 version_id;
+ __le32 boot_loadaddr_in_imem;
+ __le32 boot_codedfi_offset;
+ __le32 boot_codetag;
+ __le32 boot_codesize;
+ __le32 phys_memaddr;
+ __le16 reqphys_memsize;
+ __le16 alloc_phys_memsize;
+ __le32 rodata_img_offset;
+ __le32 rodata_section_start;
+ __le32 rodata_section_end;
+ __le32 main_fnaddr;
+ __le32 fwimg_cksum;
+ __le32 fwimg_created_time;
+ __le32 imem_resident_start;
+ __le32 imem_resident_end;
+ __le32 idirect_start;
+ __le32 idirect_end;
+ __le32 l2_imem_start;
+ __le32 l2_imem_end;
+ __le32 version_id;
u8 init_ddirect;
u8 reserved[3];
- u32 phys_addr_log_buffer;
- u32 total_log_entries;
- u32 dequeue_ptr;
- u32 dummy_var[2];
- u32 fwimg_len;
+ __le32 phys_addr_log_buffer;
+ __le32 total_log_entries;
+ __le32 dequeue_ptr;
+ __le32 dummy_var[2];
+ __le32 fwimg_len;
u8 magic[8];
- u32 ss_low_power_entry_timeout;
+ __le32 ss_low_power_entry_timeout;
u8 num_hsic_port;
u8 padding[139]; /* Pad to 256 bytes */
};
@@ -194,6 +195,11 @@ struct tegra_xusb {
struct reset_control *host_rst;
struct reset_control *ss_rst;
+ struct device *genpd_dev_host;
+ struct device *genpd_dev_ss;
+ struct device_link *genpd_dl_host;
+ struct device_link *genpd_dl_ss;
+
struct phy **phys;
unsigned int num_phys;
@@ -928,6 +934,57 @@ static int tegra_xusb_load_firmware(struct tegra_xusb *tegra)
return 0;
}
+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->genpd_dev_ss)
+ dev_pm_domain_detach(tegra->genpd_dev_ss, true);
+ if (tegra->genpd_dev_host)
+ dev_pm_domain_detach(tegra->genpd_dev_host, true);
+}
+
+static int tegra_xusb_powerdomain_init(struct device *dev,
+ struct tegra_xusb *tegra)
+{
+ int err;
+
+ tegra->genpd_dev_host = dev_pm_domain_attach_by_name(dev, "xusb_host");
+ if (IS_ERR(tegra->genpd_dev_host)) {
+ err = PTR_ERR(tegra->genpd_dev_host);
+ dev_err(dev, "failed to get host pm-domain: %d\n", err);
+ return err;
+ }
+
+ tegra->genpd_dev_ss = dev_pm_domain_attach_by_name(dev, "xusb_ss");
+ if (IS_ERR(tegra->genpd_dev_ss)) {
+ err = PTR_ERR(tegra->genpd_dev_ss);
+ dev_err(dev, "failed to get superspeed pm-domain: %d\n", err);
+ 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->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_probe(struct platform_device *pdev)
{
struct tegra_xusb_mbox_msg msg;
@@ -1038,7 +1095,7 @@ static int tegra_xusb_probe(struct platform_device *pdev)
goto put_padctl;
}
- if (!pdev->dev.pm_domain) {
+ if (!of_property_read_bool(pdev->dev.of_node, "power-domains")) {
tegra->host_rst = devm_reset_control_get(&pdev->dev,
"xusb_host");
if (IS_ERR(tegra->host_rst)) {
@@ -1069,17 +1126,22 @@ static int tegra_xusb_probe(struct platform_device *pdev)
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 disable_xusba;
+ goto put_padctl;
}
+ } else {
+ err = tegra_xusb_powerdomain_init(&pdev->dev, tegra);
+ if (err)
+ goto put_powerdomains;
}
tegra->supplies = devm_kcalloc(&pdev->dev, tegra->soc->num_supplies,
sizeof(*tegra->supplies), GFP_KERNEL);
if (!tegra->supplies) {
err = -ENOMEM;
- goto disable_xusbc;
+ goto put_powerdomains;
}
for (i = 0; i < tegra->soc->num_supplies; i++)
@@ -1089,7 +1151,7 @@ static int tegra_xusb_probe(struct platform_device *pdev)
tegra->supplies);
if (err) {
dev_err(&pdev->dev, "failed to get regulators: %d\n", err);
- goto disable_xusbc;
+ goto put_powerdomains;
}
for (i = 0; i < tegra->soc->num_types; i++)
@@ -1099,7 +1161,7 @@ static int tegra_xusb_probe(struct platform_device *pdev)
sizeof(*tegra->phys), GFP_KERNEL);
if (!tegra->phys) {
err = -ENOMEM;
- goto disable_xusbc;
+ goto put_powerdomains;
}
for (i = 0, k = 0; i < tegra->soc->num_types; i++) {
@@ -1115,7 +1177,7 @@ static int tegra_xusb_probe(struct platform_device *pdev)
"failed to get PHY %s: %ld\n", prop,
PTR_ERR(phy));
err = PTR_ERR(phy);
- goto disable_xusbc;
+ goto put_powerdomains;
}
tegra->phys[k++] = phy;
@@ -1126,7 +1188,7 @@ static int tegra_xusb_probe(struct platform_device *pdev)
dev_name(&pdev->dev));
if (!tegra->hcd) {
err = -ENOMEM;
- goto disable_xusbc;
+ goto put_powerdomains;
}
/*
@@ -1222,12 +1284,13 @@ put_rpm:
disable_rpm:
pm_runtime_disable(&pdev->dev);
usb_put_hcd(tegra->hcd);
-disable_xusbc:
- if (!pdev->dev.pm_domain)
+put_powerdomains:
+ if (!of_property_read_bool(pdev->dev.of_node, "power-domains")) {
tegra_powergate_power_off(TEGRA_POWERGATE_XUSBC);
-disable_xusba:
- if (!pdev->dev.pm_domain)
tegra_powergate_power_off(TEGRA_POWERGATE_XUSBA);
+ } else {
+ tegra_xusb_powerdomain_remove(&pdev->dev, tegra);
+ }
put_padctl:
tegra_xusb_padctl_put(tegra->padctl);
return err;
@@ -1249,6 +1312,13 @@ static int tegra_xusb_remove(struct platform_device *pdev)
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&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_padctl_put(tegra->padctl);
return 0;
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 6230a578324c..bf0b3692dc9a 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1496,6 +1496,7 @@ static inline const char *xhci_trb_type_string(u8 type)
/* How much data is left before the 64KB boundary? */
#define TRB_BUFF_LEN_UP_TO_BOUNDARY(addr) (TRB_MAX_BUFF_SIZE - \
(addr & (TRB_MAX_BUFF_SIZE - 1)))
+#define MAX_SOFT_RETRY 3
struct xhci_segment {
union xhci_trb *trbs;
@@ -1583,6 +1584,7 @@ struct xhci_ring {
* if we own the TRB (if we are the consumer). See section 4.9.1.
*/
u32 cycle_state;
+ unsigned int err_count;
unsigned int stream_id;
unsigned int num_segs;
unsigned int num_trbs_free;
@@ -1846,6 +1848,7 @@ struct xhci_hcd {
#define XHCI_SUSPEND_DELAY BIT_ULL(30)
#define XHCI_INTEL_USB_ROLE_SW BIT_ULL(31)
#define XHCI_ZERO_64B_REGS BIT_ULL(32)
+#define XHCI_DEFAULT_PM_RUNTIME_ALLOW BIT_ULL(33)
unsigned int num_active_eps;
unsigned int limit_active_eps;
diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c
index d746c26a8055..bd539f3058bc 100644
--- a/drivers/usb/misc/appledisplay.c
+++ b/drivers/usb/misc/appledisplay.c
@@ -146,8 +146,11 @@ static int appledisplay_bl_update_status(struct backlight_device *bd)
pdata->msgdata, 2,
ACD_USB_TIMEOUT);
mutex_unlock(&pdata->sysfslock);
-
- return retval;
+
+ if (retval < 0)
+ return retval;
+ else
+ return 0;
}
static int appledisplay_bl_get_brightness(struct backlight_device *bd)
diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
index c2991b8a65ce..ba05dd80a020 100644
--- a/drivers/usb/misc/iowarrior.c
+++ b/drivers/usb/misc/iowarrior.c
@@ -808,8 +808,8 @@ static int iowarrior_probe(struct usb_interface *interface,
dev->int_in_endpoint->bInterval);
/* create an internal buffer for interrupt data from the device */
dev->read_queue =
- kmalloc(((dev->report_size + 1) * MAX_INTERRUPT_BUFFER),
- GFP_KERNEL);
+ kmalloc_array(dev->report_size + 1, MAX_INTERRUPT_BUFFER,
+ GFP_KERNEL);
if (!dev->read_queue)
goto error;
/* Get the serial-number of the chip */
diff --git a/drivers/usb/misc/trancevibrator.c b/drivers/usb/misc/trancevibrator.c
index b3e1f553954a..ac357ce2d1a6 100644
--- a/drivers/usb/misc/trancevibrator.c
+++ b/drivers/usb/misc/trancevibrator.c
@@ -46,7 +46,9 @@ static ssize_t speed_store(struct device *dev, struct device_attribute *attr,
struct trancevibrator *tv = usb_get_intfdata(intf);
int temp, retval, old;
- temp = simple_strtoul(buf, NULL, 10);
+ retval = kstrtoint(buf, 10, &temp);
+ if (retval)
+ return retval;
if (temp > 255)
temp = 255;
else if (temp < 0)
diff --git a/drivers/usb/mtu3/mtu3_core.c b/drivers/usb/mtu3/mtu3_core.c
index d045d8458f81..ae70b9bfd797 100644
--- a/drivers/usb/mtu3/mtu3_core.c
+++ b/drivers/usb/mtu3/mtu3_core.c
@@ -185,8 +185,8 @@ static void mtu3_intr_enable(struct mtu3 *mtu)
if (mtu->is_u3_ip) {
/* Enable U3 LTSSM interrupts */
- value = HOT_RST_INTR | WARM_RST_INTR | VBUS_RISE_INTR |
- VBUS_FALL_INTR | ENTER_U3_INTR | EXIT_U3_INTR;
+ value = HOT_RST_INTR | WARM_RST_INTR |
+ ENTER_U3_INTR | EXIT_U3_INTR;
mtu3_writel(mbase, U3D_LTSSM_INTR_ENABLE, value);
}
diff --git a/drivers/usb/mtu3/mtu3_gadget.c b/drivers/usb/mtu3/mtu3_gadget.c
index 5c60a8c5a0b5..bbcd3332471d 100644
--- a/drivers/usb/mtu3/mtu3_gadget.c
+++ b/drivers/usb/mtu3/mtu3_gadget.c
@@ -585,6 +585,17 @@ static const struct usb_gadget_ops mtu3_gadget_ops = {
.udc_stop = mtu3_gadget_stop,
};
+static void mtu3_state_reset(struct mtu3 *mtu)
+{
+ mtu->address = 0;
+ mtu->ep0_state = MU3D_EP0_STATE_SETUP;
+ mtu->may_wakeup = 0;
+ mtu->u1_enable = 0;
+ mtu->u2_enable = 0;
+ mtu->delayed_status = false;
+ mtu->test_mode = false;
+}
+
static void init_hw_ep(struct mtu3 *mtu, struct mtu3_ep *mep,
u32 epnum, u32 is_in)
{
@@ -702,6 +713,7 @@ void mtu3_gadget_disconnect(struct mtu3 *mtu)
spin_lock(&mtu->lock);
}
+ mtu3_state_reset(mtu);
usb_gadget_set_state(&mtu->g, USB_STATE_NOTATTACHED);
}
@@ -712,12 +724,6 @@ void mtu3_gadget_reset(struct mtu3 *mtu)
/* report disconnect, if we didn't flush EP state */
if (mtu->g.speed != USB_SPEED_UNKNOWN)
mtu3_gadget_disconnect(mtu);
-
- mtu->address = 0;
- mtu->ep0_state = MU3D_EP0_STATE_SETUP;
- mtu->may_wakeup = 0;
- mtu->u1_enable = 0;
- mtu->u2_enable = 0;
- mtu->delayed_status = false;
- mtu->test_mode = false;
+ else
+ mtu3_state_reset(mtu);
}
diff --git a/drivers/usb/phy/phy-ab8500-usb.c b/drivers/usb/phy/phy-ab8500-usb.c
index 66143ab8c043..aaf363f19714 100644
--- a/drivers/usb/phy/phy-ab8500-usb.c
+++ b/drivers/usb/phy/phy-ab8500-usb.c
@@ -505,15 +505,19 @@ static int abx500_usb_link_status_update(struct ab8500_usb *ab)
if (is_ab8500(ab->ab8500)) {
enum ab8500_usb_link_status lsts;
- abx500_get_register_interruptible(ab->dev,
+ ret = abx500_get_register_interruptible(ab->dev,
AB8500_USB, AB8500_USB_LINE_STAT_REG, &reg);
+ if (ret < 0)
+ return ret;
lsts = (reg >> 3) & 0x0F;
ret = ab8500_usb_link_status_update(ab, lsts);
} else if (is_ab8505(ab->ab8500)) {
enum ab8505_usb_link_status lsts;
- abx500_get_register_interruptible(ab->dev,
+ ret = abx500_get_register_interruptible(ab->dev,
AB8500_USB, AB8505_USB_LINE_STAT_REG, &reg);
+ if (ret < 0)
+ return ret;
lsts = (reg >> 3) & 0x1F;
ret = ab8505_usb_link_status_update(ab, lsts);
}
diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c
index e5aa24c1e4fd..1b1bb0ad40c3 100644
--- a/drivers/usb/phy/phy-mxs-usb.c
+++ b/drivers/usb/phy/phy-mxs-usb.c
@@ -563,7 +563,7 @@ static enum usb_charger_type mxs_charger_primary_detection(struct mxs_phy *x)
regmap_read(regmap, ANADIG_USB1_CHRG_DET_STAT, &val);
if (!(val & ANADIG_USB1_CHRG_DET_STAT_CHRG_DETECTED)) {
chgr_type = SDP_TYPE;
- dev_dbg(x->phy.dev, "It is a stardard downstream port\n");
+ dev_dbg(x->phy.dev, "It is a standard downstream port\n");
}
/* Disable charger detector */
diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c
index 4310df46639d..a3e1290d682d 100644
--- a/drivers/usb/renesas_usbhs/common.c
+++ b/drivers/usb/renesas_usbhs/common.c
@@ -5,6 +5,7 @@
* Copyright (C) 2011 Renesas Solutions Corp.
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
*/
+#include <linux/clk.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/io.h>
@@ -12,6 +13,7 @@
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/pm_runtime.h>
+#include <linux/reset.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include "common.h"
@@ -290,6 +292,79 @@ static void usbhsc_set_buswait(struct usbhs_priv *priv)
usbhs_bset(priv, BUSWAIT, 0x000F, wait);
}
+static bool usbhsc_is_multi_clks(struct usbhs_priv *priv)
+{
+ if (priv->dparam.type == USBHS_TYPE_RCAR_GEN3 ||
+ priv->dparam.type == USBHS_TYPE_RCAR_GEN3_WITH_PLL)
+ return true;
+
+ return false;
+}
+
+static int usbhsc_clk_get(struct device *dev, struct usbhs_priv *priv)
+{
+ if (!usbhsc_is_multi_clks(priv))
+ return 0;
+
+ /* The first clock should exist */
+ priv->clks[0] = of_clk_get(dev->of_node, 0);
+ if (IS_ERR(priv->clks[0]))
+ return PTR_ERR(priv->clks[0]);
+
+ /*
+ * To backward compatibility with old DT, this driver checks the return
+ * value if it's -ENOENT or not.
+ */
+ priv->clks[1] = of_clk_get(dev->of_node, 1);
+ if (PTR_ERR(priv->clks[1]) == -ENOENT)
+ priv->clks[1] = NULL;
+ else if (IS_ERR(priv->clks[1]))
+ return PTR_ERR(priv->clks[1]);
+
+ return 0;
+}
+
+static void usbhsc_clk_put(struct usbhs_priv *priv)
+{
+ int i;
+
+ if (!usbhsc_is_multi_clks(priv))
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(priv->clks); i++)
+ clk_put(priv->clks[i]);
+}
+
+static int usbhsc_clk_prepare_enable(struct usbhs_priv *priv)
+{
+ int i, ret;
+
+ if (!usbhsc_is_multi_clks(priv))
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(priv->clks); i++) {
+ ret = clk_prepare_enable(priv->clks[i]);
+ if (ret) {
+ while (--i >= 0)
+ clk_disable_unprepare(priv->clks[i]);
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+static void usbhsc_clk_disable_unprepare(struct usbhs_priv *priv)
+{
+ int i;
+
+ if (!usbhsc_is_multi_clks(priv))
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(priv->clks); i++)
+ clk_disable_unprepare(priv->clks[i]);
+}
+
/*
* platform default param
*/
@@ -340,6 +415,10 @@ static void usbhsc_power_ctrl(struct usbhs_priv *priv, int enable)
/* enable PM */
pm_runtime_get_sync(dev);
+ /* enable clks */
+ if (usbhsc_clk_prepare_enable(priv))
+ return;
+
/* enable platform power */
usbhs_platform_call(priv, power_ctrl, pdev, priv->base, enable);
@@ -352,6 +431,9 @@ static void usbhsc_power_ctrl(struct usbhs_priv *priv, int enable)
/* disable platform power */
usbhs_platform_call(priv, power_ctrl, pdev, priv->base, enable);
+ /* disable clks */
+ usbhsc_clk_disable_unprepare(priv);
+
/* disable PM */
pm_runtime_put_sync(dev);
}
@@ -478,6 +560,10 @@ static const struct of_device_id usbhs_of_match[] = {
.data = (void *)USBHS_TYPE_RCAR_GEN3,
},
{
+ .compatible = "renesas,usbhs-r8a77990",
+ .data = (void *)USBHS_TYPE_RCAR_GEN3_WITH_PLL,
+ },
+ {
.compatible = "renesas,usbhs-r8a77995",
.data = (void *)USBHS_TYPE_RCAR_GEN3_WITH_PLL,
},
@@ -574,6 +660,10 @@ static int usbhs_probe(struct platform_device *pdev)
return PTR_ERR(priv->edev);
}
+ priv->rsts = devm_reset_control_array_get_optional_shared(&pdev->dev);
+ if (IS_ERR(priv->rsts))
+ return PTR_ERR(priv->rsts);
+
/*
* care platform info
*/
@@ -591,15 +681,6 @@ static int usbhs_probe(struct platform_device *pdev)
break;
case USBHS_TYPE_RCAR_GEN3_WITH_PLL:
priv->pfunc = usbhs_rcar3_with_pll_ops;
- if (!IS_ERR_OR_NULL(priv->edev)) {
- priv->nb.notifier_call = priv->pfunc.notifier;
- ret = devm_extcon_register_notifier(&pdev->dev,
- priv->edev,
- EXTCON_USB_HOST,
- &priv->nb);
- if (ret < 0)
- dev_err(&pdev->dev, "no notifier registered\n");
- }
break;
case USBHS_TYPE_RZA1:
priv->pfunc = usbhs_rza1_ops;
@@ -658,6 +739,14 @@ static int usbhs_probe(struct platform_device *pdev)
/* dev_set_drvdata should be called after usbhs_mod_init */
platform_set_drvdata(pdev, priv);
+ ret = reset_control_deassert(priv->rsts);
+ if (ret)
+ goto probe_fail_rst;
+
+ ret = usbhsc_clk_get(&pdev->dev, priv);
+ if (ret)
+ goto probe_fail_clks;
+
/*
* deviece reset here because
* USB device might be used in boot loader.
@@ -711,6 +800,10 @@ static int usbhs_probe(struct platform_device *pdev)
return ret;
probe_end_mod_exit:
+ usbhsc_clk_put(priv);
+probe_fail_clks:
+ reset_control_assert(priv->rsts);
+probe_fail_rst:
usbhs_mod_remove(priv);
probe_end_fifo_exit:
usbhs_fifo_remove(priv);
@@ -739,6 +832,8 @@ static int usbhs_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
usbhs_platform_call(priv, hardware_exit, pdev);
+ usbhsc_clk_put(priv);
+ reset_control_assert(priv->rsts);
usbhs_mod_remove(priv);
usbhs_fifo_remove(priv);
usbhs_pipe_remove(priv);
diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h
index 6137f7942c05..3777af848a35 100644
--- a/drivers/usb/renesas_usbhs/common.h
+++ b/drivers/usb/renesas_usbhs/common.h
@@ -8,8 +8,10 @@
#ifndef RENESAS_USB_DRIVER_H
#define RENESAS_USB_DRIVER_H
+#include <linux/clk.h>
#include <linux/extcon.h>
#include <linux/platform_device.h>
+#include <linux/reset.h>
#include <linux/usb/renesas_usbhs.h>
struct usbhs_priv;
@@ -255,7 +257,6 @@ struct usbhs_priv {
struct platform_device *pdev;
struct extcon_dev *edev;
- struct notifier_block nb;
spinlock_t lock;
@@ -277,6 +278,8 @@ struct usbhs_priv {
struct usbhs_fifo_info fifo_info;
struct phy *phy;
+ struct reset_control *rsts;
+ struct clk *clks[2];
};
/*
diff --git a/drivers/usb/renesas_usbhs/rcar3.c b/drivers/usb/renesas_usbhs/rcar3.c
index d0ea4ff89622..aa3820448286 100644
--- a/drivers/usb/renesas_usbhs/rcar3.c
+++ b/drivers/usb/renesas_usbhs/rcar3.c
@@ -27,7 +27,6 @@
* Remarks: bit[31:11] and bit[9:6] should be 0
*/
#define UGCTRL2_RESERVED_3 0x00000001 /* bit[3:0] should be B'0001 */
-#define UGCTRL2_USB0SEL_EHCI 0x00000010
#define UGCTRL2_USB0SEL_HSUSB 0x00000020
#define UGCTRL2_USB0SEL_OTG 0x00000030
#define UGCTRL2_VBUSSEL 0x00000400
@@ -50,14 +49,6 @@ static void usbhs_rcar3_set_ugctrl2(struct usbhs_priv *priv, u32 val)
usbhs_write32(priv, UGCTRL2, val | UGCTRL2_RESERVED_3);
}
-static void usbhs_rcar3_set_usbsel(struct usbhs_priv *priv, bool ehci)
-{
- if (ehci)
- usbhs_rcar3_set_ugctrl2(priv, UGCTRL2_USB0SEL_EHCI);
- else
- usbhs_rcar3_set_ugctrl2(priv, UGCTRL2_USB0SEL_HSUSB);
-}
-
static int usbhs_rcar3_power_ctrl(struct platform_device *pdev,
void __iomem *base, int enable)
{
@@ -83,14 +74,11 @@ static int usbhs_rcar3_power_and_pll_ctrl(struct platform_device *pdev,
struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
u32 val;
int timeout = 1000;
- bool is_host = false;
if (enable) {
usbhs_write32(priv, UGCTRL, 0); /* release PLLRESET */
- if (priv->edev)
- is_host = extcon_get_state(priv->edev, EXTCON_USB_HOST);
-
- usbhs_rcar3_set_usbsel(priv, is_host);
+ usbhs_rcar3_set_ugctrl2(priv,
+ UGCTRL2_USB0SEL_OTG | UGCTRL2_VBUSSEL);
usbhs_bset(priv, LPSTS, LPSTS_SUSPM, LPSTS_SUSPM);
do {
@@ -112,16 +100,6 @@ static int usbhs_rcar3_get_id(struct platform_device *pdev)
return USBHS_GADGET;
}
-static int usbhs_rcar3_notifier(struct notifier_block *nb, unsigned long event,
- void *data)
-{
- struct usbhs_priv *priv = container_of(nb, struct usbhs_priv, nb);
-
- usbhs_rcar3_set_usbsel(priv, !!event);
-
- return NOTIFY_DONE;
-}
-
const struct renesas_usbhs_platform_callback usbhs_rcar3_ops = {
.power_ctrl = usbhs_rcar3_power_ctrl,
.get_id = usbhs_rcar3_get_id,
@@ -130,5 +108,4 @@ const struct renesas_usbhs_platform_callback usbhs_rcar3_ops = {
const struct renesas_usbhs_platform_callback usbhs_rcar3_with_pll_ops = {
.power_ctrl = usbhs_rcar3_power_and_pll_ctrl,
.get_id = usbhs_rcar3_get_id,
- .notifier = usbhs_rcar3_notifier,
};
diff --git a/drivers/usb/roles/intel-xhci-usb-role-switch.c b/drivers/usb/roles/intel-xhci-usb-role-switch.c
index 1fb3dd0f1dfa..277de96181f9 100644
--- a/drivers/usb/roles/intel-xhci-usb-role-switch.c
+++ b/drivers/usb/roles/intel-xhci-usb-role-switch.c
@@ -161,6 +161,8 @@ static int intel_xhci_usb_remove(struct platform_device *pdev)
{
struct intel_xhci_usb_data *data = platform_get_drvdata(pdev);
+ pm_runtime_disable(&pdev->dev);
+
usb_role_switch_unregister(data->role_sw);
return 0;
}
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index 7796ad8e33c6..ff38aa8963cf 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -397,38 +397,16 @@ err_free:
return result;
}
-static int ark3116_get_serial_info(struct usb_serial_port *port,
- struct serial_struct __user *retinfo)
-{
- struct serial_struct tmp;
-
- memset(&tmp, 0, sizeof(tmp));
-
- tmp.type = PORT_16654;
- tmp.line = port->minor;
- tmp.port = port->port_number;
- tmp.baud_base = 460800;
-
- if (copy_to_user(retinfo, &tmp, sizeof(tmp)))
- return -EFAULT;
-
- return 0;
-}
-
-static int ark3116_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
+static int ark3116_get_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
struct usb_serial_port *port = tty->driver_data;
- void __user *user_arg = (void __user *)arg;
-
- switch (cmd) {
- case TIOCGSERIAL:
- return ark3116_get_serial_info(port, user_arg);
- default:
- break;
- }
- return -ENOIOCTLCMD;
+ ss->type = PORT_16654;
+ ss->line = port->minor;
+ ss->port = port->port_number;
+ ss->baud_base = 460800;
+ return 0;
}
static int ark3116_tiocmget(struct tty_struct *tty)
@@ -668,7 +646,7 @@ static struct usb_serial_driver ark3116_device = {
.port_remove = ark3116_port_remove,
.set_termios = ark3116_set_termios,
.init_termios = ark3116_init_termios,
- .ioctl = ark3116_ioctl,
+ .get_serial = ark3116_get_serial_info,
.tiocmget = ark3116_tiocmget,
.tiocmset = ark3116_tiocmset,
.tiocmiwait = usb_serial_generic_tiocmiwait,
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index e0035c023120..ed51bc48eea6 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -378,7 +378,7 @@ static int cypress_serial_control(struct tty_struct *tty,
retval = -ENOTTY;
goto out;
}
- dev_dbg(dev, "%s - retreiving serial line settings\n", __func__);
+ dev_dbg(dev, "%s - retrieving serial line settings\n", __func__);
do {
retval = usb_control_msg(port->serial->dev,
usb_rcvctrlpipe(port->serial->dev, 0),
@@ -769,7 +769,7 @@ send:
usb_fill_int_urb(port->interrupt_out_urb, port->serial->dev,
usb_sndintpipe(port->serial->dev, port->interrupt_out_endpointAddress),
- port->interrupt_out_buffer, port->interrupt_out_size,
+ port->interrupt_out_buffer, actual_size,
cypress_write_int_callback, port, priv->write_urb_interval);
result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC);
if (result) {
@@ -863,7 +863,7 @@ static void cypress_set_termios(struct tty_struct *tty,
struct cypress_private *priv = usb_get_serial_port_data(port);
struct device *dev = &port->dev;
int data_bits, stop_bits, parity_type, parity_enable;
- unsigned cflag, iflag;
+ unsigned int cflag;
unsigned long flags;
__u8 oldlines;
int linechange = 0;
@@ -899,7 +899,6 @@ static void cypress_set_termios(struct tty_struct *tty,
tty->termios.c_cflag &= ~(CMSPAR|CRTSCTS);
cflag = tty->termios.c_cflag;
- iflag = tty->termios.c_iflag;
/* check if there are new settings */
if (old_termios) {
diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 96036f87b1de..0dcdcb4b2cde 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -583,36 +583,16 @@ static int f81232_carrier_raised(struct usb_serial_port *port)
return 0;
}
-static int f81232_get_serial_info(struct usb_serial_port *port,
- unsigned long arg)
-{
- struct serial_struct ser;
-
- memset(&ser, 0, sizeof(ser));
-
- ser.type = PORT_16550A;
- ser.line = port->minor;
- ser.port = port->port_number;
- ser.baud_base = F81232_MAX_BAUDRATE;
-
- if (copy_to_user((void __user *)arg, &ser, sizeof(ser)))
- return -EFAULT;
-
- return 0;
-}
-
-static int f81232_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
+static int f81232_get_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
struct usb_serial_port *port = tty->driver_data;
- switch (cmd) {
- case TIOCGSERIAL:
- return f81232_get_serial_info(port, arg);
- default:
- break;
- }
- return -ENOIOCTLCMD;
+ ss->type = PORT_16550A;
+ ss->line = port->minor;
+ ss->port = port->port_number;
+ ss->baud_base = F81232_MAX_BAUDRATE;
+ return 0;
}
static void f81232_interrupt_work(struct work_struct *work)
@@ -665,7 +645,7 @@ static struct usb_serial_driver f81232_device = {
.close = f81232_close,
.dtr_rts = f81232_dtr_rts,
.carrier_raised = f81232_carrier_raised,
- .ioctl = f81232_ioctl,
+ .get_serial = f81232_get_serial_info,
.break_ctl = f81232_break_ctl,
.set_termios = f81232_set_termios,
.tiocmget = f81232_tiocmget,
diff --git a/drivers/usb/serial/f81534.c b/drivers/usb/serial/f81534.c
index 4dfbff20bda4..380933db34dd 100644
--- a/drivers/usb/serial/f81534.c
+++ b/drivers/usb/serial/f81534.c
@@ -1139,43 +1139,21 @@ static void f81534_close(struct usb_serial_port *port)
mutex_unlock(&serial_priv->urb_mutex);
}
-static int f81534_get_serial_info(struct usb_serial_port *port,
- struct serial_struct __user *retinfo)
+static int f81534_get_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
+ struct usb_serial_port *port = tty->driver_data;
struct f81534_port_private *port_priv;
- struct serial_struct tmp;
port_priv = usb_get_serial_port_data(port);
- memset(&tmp, 0, sizeof(tmp));
-
- tmp.type = PORT_16550A;
- tmp.port = port->port_number;
- tmp.line = port->minor;
- tmp.baud_base = port_priv->baud_base;
-
- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return -EFAULT;
-
+ ss->type = PORT_16550A;
+ ss->port = port->port_number;
+ ss->line = port->minor;
+ ss->baud_base = port_priv->baud_base;
return 0;
}
-static int f81534_ioctl(struct tty_struct *tty, unsigned int cmd,
- unsigned long arg)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct serial_struct __user *buf = (struct serial_struct __user *)arg;
-
- switch (cmd) {
- case TIOCGSERIAL:
- return f81534_get_serial_info(port, buf);
- default:
- break;
- }
-
- return -ENOIOCTLCMD;
-}
-
static void f81534_process_per_serial_block(struct usb_serial_port *port,
u8 *data)
{
@@ -1581,7 +1559,7 @@ static struct usb_serial_driver f81534_device = {
.break_ctl = f81534_break_ctl,
.dtr_rts = f81534_dtr_rts,
.process_read_urb = f81534_process_read_urb,
- .ioctl = f81534_ioctl,
+ .get_serial = f81534_get_serial_info,
.tiocmget = f81534_tiocmget,
.tiocmset = f81534_tiocmset,
.write_bulk_callback = f81534_write_usb_callback,
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index b5cef322826f..609198d9594c 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -39,6 +39,7 @@
#include <linux/uaccess.h>
#include <linux/usb.h>
#include <linux/serial.h>
+#include <linux/gpio/driver.h>
#include <linux/usb/serial.h>
#include "ftdi_sio.h"
#include "ftdi_sio_ids.h"
@@ -72,6 +73,15 @@ struct ftdi_private {
unsigned int latency; /* latency setting in use */
unsigned short max_packet_size;
struct mutex cfg_lock; /* Avoid mess by parallel calls of config ioctl() and change_speed() */
+#ifdef CONFIG_GPIOLIB
+ struct gpio_chip gc;
+ struct mutex gpio_lock; /* protects GPIO state */
+ bool gpio_registered; /* is the gpiochip in kernel registered */
+ bool gpio_used; /* true if the user requested a gpio */
+ u8 gpio_altfunc; /* which pins are in gpio mode */
+ u8 gpio_output; /* pin directions cache */
+ u8 gpio_value; /* pin value for outputs */
+#endif
};
/* struct ftdi_sio_quirk is used by devices requiring special attention. */
@@ -1055,6 +1065,10 @@ static int ftdi_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear);
static int ftdi_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg);
+static int get_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss);
+static int set_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss);
static void ftdi_break_ctl(struct tty_struct *tty, int break_state);
static bool ftdi_tx_empty(struct usb_serial_port *port);
static int ftdi_get_modem_status(struct usb_serial_port *port,
@@ -1091,6 +1105,8 @@ static struct usb_serial_driver ftdi_sio_device = {
.tiocmiwait = usb_serial_generic_tiocmiwait,
.get_icount = usb_serial_generic_get_icount,
.ioctl = ftdi_ioctl,
+ .get_serial = get_serial_info,
+ .set_serial = set_serial_info,
.set_termios = ftdi_set_termios,
.break_ctl = ftdi_break_ctl,
.tx_empty = ftdi_tx_empty,
@@ -1443,48 +1459,42 @@ static int read_latency_timer(struct usb_serial_port *port)
return 0;
}
-static int get_serial_info(struct usb_serial_port *port,
- struct serial_struct __user *retinfo)
+static int get_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
+ struct usb_serial_port *port = tty->driver_data;
struct ftdi_private *priv = usb_get_serial_port_data(port);
- struct serial_struct tmp;
- memset(&tmp, 0, sizeof(tmp));
- tmp.flags = priv->flags;
- tmp.baud_base = priv->baud_base;
- tmp.custom_divisor = priv->custom_divisor;
- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return -EFAULT;
+ ss->flags = priv->flags;
+ ss->baud_base = priv->baud_base;
+ ss->custom_divisor = priv->custom_divisor;
return 0;
}
static int set_serial_info(struct tty_struct *tty,
- struct usb_serial_port *port, struct serial_struct __user *newinfo)
+ struct serial_struct *ss)
{
+ struct usb_serial_port *port = tty->driver_data;
struct ftdi_private *priv = usb_get_serial_port_data(port);
- struct serial_struct new_serial;
struct ftdi_private old_priv;
- if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
- return -EFAULT;
-
mutex_lock(&priv->cfg_lock);
old_priv = *priv;
/* Do error checking and permission checking */
if (!capable(CAP_SYS_ADMIN)) {
- if ((new_serial.flags ^ priv->flags) & ~ASYNC_USR_MASK) {
+ if ((ss->flags ^ priv->flags) & ~ASYNC_USR_MASK) {
mutex_unlock(&priv->cfg_lock);
return -EPERM;
}
priv->flags = ((priv->flags & ~ASYNC_USR_MASK) |
- (new_serial.flags & ASYNC_USR_MASK));
- priv->custom_divisor = new_serial.custom_divisor;
+ (ss->flags & ASYNC_USR_MASK));
+ priv->custom_divisor = ss->custom_divisor;
goto check_and_exit;
}
- if (new_serial.baud_base != priv->baud_base) {
+ if (ss->baud_base != priv->baud_base) {
mutex_unlock(&priv->cfg_lock);
return -EINVAL;
}
@@ -1492,8 +1502,8 @@ static int set_serial_info(struct tty_struct *tty,
/* Make the changes - these are privileged changes! */
priv->flags = ((priv->flags & ~ASYNC_FLAGS) |
- (new_serial.flags & ASYNC_FLAGS));
- priv->custom_divisor = new_serial.custom_divisor;
+ (ss->flags & ASYNC_FLAGS));
+ priv->custom_divisor = ss->custom_divisor;
check_and_exit:
write_latency_timer(port);
@@ -1507,10 +1517,8 @@ check_and_exit:
dev_warn_ratelimited(&port->dev, "use of SPD flags is deprecated\n");
change_speed(tty, port);
- mutex_unlock(&priv->cfg_lock);
}
- else
- mutex_unlock(&priv->cfg_lock);
+ mutex_unlock(&priv->cfg_lock);
return 0;
}
@@ -1766,6 +1774,375 @@ static void remove_sysfs_attrs(struct usb_serial_port *port)
}
+#ifdef CONFIG_GPIOLIB
+
+static int ftdi_set_bitmode(struct usb_serial_port *port, u8 mode)
+{
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+ struct usb_serial *serial = port->serial;
+ int result;
+ u16 val;
+
+ val = (mode << 8) | (priv->gpio_output << 4) | priv->gpio_value;
+ result = usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_BITMODE_REQUEST,
+ FTDI_SIO_SET_BITMODE_REQUEST_TYPE, val,
+ priv->interface, NULL, 0, WDR_TIMEOUT);
+ if (result < 0) {
+ dev_err(&serial->interface->dev,
+ "bitmode request failed for value 0x%04x: %d\n",
+ val, result);
+ }
+
+ return result;
+}
+
+static int ftdi_set_cbus_pins(struct usb_serial_port *port)
+{
+ return ftdi_set_bitmode(port, FTDI_SIO_BITMODE_CBUS);
+}
+
+static int ftdi_exit_cbus_mode(struct usb_serial_port *port)
+{
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+
+ priv->gpio_output = 0;
+ priv->gpio_value = 0;
+ return ftdi_set_bitmode(port, FTDI_SIO_BITMODE_RESET);
+}
+
+static int ftdi_gpio_request(struct gpio_chip *gc, unsigned int offset)
+{
+ struct usb_serial_port *port = gpiochip_get_data(gc);
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+ int result;
+
+ if (priv->gpio_altfunc & BIT(offset))
+ return -ENODEV;
+
+ mutex_lock(&priv->gpio_lock);
+ if (!priv->gpio_used) {
+ /* Set default pin states, as we cannot get them from device */
+ priv->gpio_output = 0x00;
+ priv->gpio_value = 0x00;
+ result = ftdi_set_cbus_pins(port);
+ if (result) {
+ mutex_unlock(&priv->gpio_lock);
+ return result;
+ }
+
+ priv->gpio_used = true;
+ }
+ mutex_unlock(&priv->gpio_lock);
+
+ return 0;
+}
+
+static int ftdi_read_cbus_pins(struct usb_serial_port *port)
+{
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+ struct usb_serial *serial = port->serial;
+ unsigned char *buf;
+ int result;
+
+ buf = kmalloc(1, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ result = usb_control_msg(serial->dev,
+ usb_rcvctrlpipe(serial->dev, 0),
+ FTDI_SIO_READ_PINS_REQUEST,
+ FTDI_SIO_READ_PINS_REQUEST_TYPE, 0,
+ priv->interface, buf, 1, WDR_TIMEOUT);
+ if (result < 1) {
+ if (result >= 0)
+ result = -EIO;
+ } else {
+ result = buf[0];
+ }
+
+ kfree(buf);
+
+ return result;
+}
+
+static int ftdi_gpio_get(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct usb_serial_port *port = gpiochip_get_data(gc);
+ int result;
+
+ result = ftdi_read_cbus_pins(port);
+ if (result < 0)
+ return result;
+
+ return !!(result & BIT(gpio));
+}
+
+static void ftdi_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value)
+{
+ struct usb_serial_port *port = gpiochip_get_data(gc);
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+
+ mutex_lock(&priv->gpio_lock);
+
+ if (value)
+ priv->gpio_value |= BIT(gpio);
+ else
+ priv->gpio_value &= ~BIT(gpio);
+
+ ftdi_set_cbus_pins(port);
+
+ mutex_unlock(&priv->gpio_lock);
+}
+
+static int ftdi_gpio_get_multiple(struct gpio_chip *gc, unsigned long *mask,
+ unsigned long *bits)
+{
+ struct usb_serial_port *port = gpiochip_get_data(gc);
+ int result;
+
+ result = ftdi_read_cbus_pins(port);
+ if (result < 0)
+ return result;
+
+ *bits = result & *mask;
+
+ return 0;
+}
+
+static void ftdi_gpio_set_multiple(struct gpio_chip *gc, unsigned long *mask,
+ unsigned long *bits)
+{
+ struct usb_serial_port *port = gpiochip_get_data(gc);
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+
+ mutex_lock(&priv->gpio_lock);
+
+ priv->gpio_value &= ~(*mask);
+ priv->gpio_value |= *bits & *mask;
+ ftdi_set_cbus_pins(port);
+
+ mutex_unlock(&priv->gpio_lock);
+}
+
+static int ftdi_gpio_direction_get(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct usb_serial_port *port = gpiochip_get_data(gc);
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+
+ return !(priv->gpio_output & BIT(gpio));
+}
+
+static int ftdi_gpio_direction_input(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct usb_serial_port *port = gpiochip_get_data(gc);
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+ int result;
+
+ mutex_lock(&priv->gpio_lock);
+
+ priv->gpio_output &= ~BIT(gpio);
+ result = ftdi_set_cbus_pins(port);
+
+ mutex_unlock(&priv->gpio_lock);
+
+ return result;
+}
+
+static int ftdi_gpio_direction_output(struct gpio_chip *gc, unsigned int gpio,
+ int value)
+{
+ struct usb_serial_port *port = gpiochip_get_data(gc);
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+ int result;
+
+ mutex_lock(&priv->gpio_lock);
+
+ priv->gpio_output |= BIT(gpio);
+ if (value)
+ priv->gpio_value |= BIT(gpio);
+ else
+ priv->gpio_value &= ~BIT(gpio);
+
+ result = ftdi_set_cbus_pins(port);
+
+ mutex_unlock(&priv->gpio_lock);
+
+ return result;
+}
+
+static int ftdi_read_eeprom(struct usb_serial *serial, void *dst, u16 addr,
+ u16 nbytes)
+{
+ int read = 0;
+
+ if (addr % 2 != 0)
+ return -EINVAL;
+ if (nbytes % 2 != 0)
+ return -EINVAL;
+
+ /* Read EEPROM two bytes at a time */
+ while (read < nbytes) {
+ int rv;
+
+ rv = usb_control_msg(serial->dev,
+ usb_rcvctrlpipe(serial->dev, 0),
+ FTDI_SIO_READ_EEPROM_REQUEST,
+ FTDI_SIO_READ_EEPROM_REQUEST_TYPE,
+ 0, (addr + read) / 2, dst + read, 2,
+ WDR_TIMEOUT);
+ if (rv < 2) {
+ if (rv >= 0)
+ return -EIO;
+ else
+ return rv;
+ }
+
+ read += rv;
+ }
+
+ return 0;
+}
+
+static int ftdi_gpio_init_ft232r(struct usb_serial_port *port)
+{
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+ u16 cbus_config;
+ u8 *buf;
+ int ret;
+ int i;
+
+ buf = kmalloc(2, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ ret = ftdi_read_eeprom(port->serial, buf, 0x14, 2);
+ if (ret < 0)
+ goto out_free;
+
+ cbus_config = le16_to_cpup((__le16 *)buf);
+ dev_dbg(&port->dev, "cbus_config = 0x%04x\n", cbus_config);
+
+ priv->gc.ngpio = 4;
+
+ priv->gpio_altfunc = 0xff;
+ for (i = 0; i < priv->gc.ngpio; ++i) {
+ if ((cbus_config & 0xf) == FTDI_FT232R_CBUS_MUX_GPIO)
+ priv->gpio_altfunc &= ~BIT(i);
+ cbus_config >>= 4;
+ }
+out_free:
+ kfree(buf);
+
+ return ret;
+}
+
+static int ftdi_gpio_init_ftx(struct usb_serial_port *port)
+{
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+ struct usb_serial *serial = port->serial;
+ const u16 cbus_cfg_addr = 0x1a;
+ const u16 cbus_cfg_size = 4;
+ u8 *cbus_cfg_buf;
+ int result;
+ u8 i;
+
+ cbus_cfg_buf = kmalloc(cbus_cfg_size, GFP_KERNEL);
+ if (!cbus_cfg_buf)
+ return -ENOMEM;
+
+ result = ftdi_read_eeprom(serial, cbus_cfg_buf,
+ cbus_cfg_addr, cbus_cfg_size);
+ if (result < 0)
+ goto out_free;
+
+ /* FIXME: FT234XD alone has 1 GPIO, but how to recognize this IC? */
+ priv->gc.ngpio = 4;
+
+ /* Determine which pins are configured for CBUS bitbanging */
+ priv->gpio_altfunc = 0xff;
+ for (i = 0; i < priv->gc.ngpio; ++i) {
+ if (cbus_cfg_buf[i] == FTDI_FTX_CBUS_MUX_GPIO)
+ priv->gpio_altfunc &= ~BIT(i);
+ }
+
+out_free:
+ kfree(cbus_cfg_buf);
+
+ return result;
+}
+
+static int ftdi_gpio_init(struct usb_serial_port *port)
+{
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+ struct usb_serial *serial = port->serial;
+ int result;
+
+ switch (priv->chip_type) {
+ case FT232RL:
+ result = ftdi_gpio_init_ft232r(port);
+ break;
+ case FTX:
+ result = ftdi_gpio_init_ftx(port);
+ break;
+ default:
+ return 0;
+ }
+
+ if (result < 0)
+ return result;
+
+ mutex_init(&priv->gpio_lock);
+
+ priv->gc.label = "ftdi-cbus";
+ priv->gc.request = ftdi_gpio_request;
+ priv->gc.get_direction = ftdi_gpio_direction_get;
+ priv->gc.direction_input = ftdi_gpio_direction_input;
+ priv->gc.direction_output = ftdi_gpio_direction_output;
+ priv->gc.get = ftdi_gpio_get;
+ priv->gc.set = ftdi_gpio_set;
+ priv->gc.get_multiple = ftdi_gpio_get_multiple;
+ priv->gc.set_multiple = ftdi_gpio_set_multiple;
+ priv->gc.owner = THIS_MODULE;
+ priv->gc.parent = &serial->interface->dev;
+ priv->gc.base = -1;
+ priv->gc.can_sleep = true;
+
+ result = gpiochip_add_data(&priv->gc, port);
+ if (!result)
+ priv->gpio_registered = true;
+
+ return result;
+}
+
+static void ftdi_gpio_remove(struct usb_serial_port *port)
+{
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+
+ if (priv->gpio_registered) {
+ gpiochip_remove(&priv->gc);
+ priv->gpio_registered = false;
+ }
+
+ if (priv->gpio_used) {
+ /* Exiting CBUS-mode does not reset pin states. */
+ ftdi_exit_cbus_mode(port);
+ priv->gpio_used = false;
+ }
+}
+
+#else
+
+static int ftdi_gpio_init(struct usb_serial_port *port)
+{
+ return 0;
+}
+
+static void ftdi_gpio_remove(struct usb_serial_port *port) { }
+
+#endif /* CONFIG_GPIOLIB */
+
/*
* ***************************************************************************
* FTDI driver specific functions
@@ -1794,7 +2171,7 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
{
struct ftdi_private *priv;
const struct ftdi_sio_quirk *quirk = usb_get_serial_data(port->serial);
-
+ int result;
priv = kzalloc(sizeof(struct ftdi_private), GFP_KERNEL);
if (!priv)
@@ -1813,6 +2190,14 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
priv->latency = 16;
write_latency_timer(port);
create_sysfs_attrs(port);
+
+ result = ftdi_gpio_init(port);
+ if (result < 0) {
+ dev_err(&port->serial->interface->dev,
+ "GPIO initialisation failed: %d\n",
+ result);
+ }
+
return 0;
}
@@ -1930,6 +2315,8 @@ static int ftdi_sio_port_remove(struct usb_serial_port *port)
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
+ ftdi_gpio_remove(port);
+
remove_sysfs_attrs(port);
kfree(priv);
@@ -2452,10 +2839,6 @@ static int ftdi_ioctl(struct tty_struct *tty,
void __user *argp = (void __user *)arg;
switch (cmd) {
- case TIOCGSERIAL:
- return get_serial_info(port, argp);
- case TIOCSSERIAL:
- return set_serial_info(tty, port, argp);
case TIOCSERGETLSR:
return get_lsr_info(port, argp);
default:
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index dcd0b6e05baf..a79a1325b4d9 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -35,7 +35,10 @@
#define FTDI_SIO_SET_EVENT_CHAR 6 /* Set the event character */
#define FTDI_SIO_SET_ERROR_CHAR 7 /* Set the error character */
#define FTDI_SIO_SET_LATENCY_TIMER 9 /* Set the latency timer */
-#define FTDI_SIO_GET_LATENCY_TIMER 10 /* Get the latency timer */
+#define FTDI_SIO_GET_LATENCY_TIMER 0x0a /* Get the latency timer */
+#define FTDI_SIO_SET_BITMODE 0x0b /* Set bitbang mode */
+#define FTDI_SIO_READ_PINS 0x0c /* Read immediate value of pins */
+#define FTDI_SIO_READ_EEPROM 0x90 /* Read EEPROM */
/* Interface indices for FT2232, FT2232H and FT4232H devices */
#define INTERFACE_A 1
@@ -433,6 +436,29 @@ enum ftdi_sio_baudrate {
* 1 = active
*/
+/* FTDI_SIO_SET_BITMODE */
+#define FTDI_SIO_SET_BITMODE_REQUEST_TYPE 0x40
+#define FTDI_SIO_SET_BITMODE_REQUEST FTDI_SIO_SET_BITMODE
+
+/* Possible bitmodes for FTDI_SIO_SET_BITMODE_REQUEST */
+#define FTDI_SIO_BITMODE_RESET 0x00
+#define FTDI_SIO_BITMODE_CBUS 0x20
+
+/* FTDI_SIO_READ_PINS */
+#define FTDI_SIO_READ_PINS_REQUEST_TYPE 0xc0
+#define FTDI_SIO_READ_PINS_REQUEST FTDI_SIO_READ_PINS
+
+/*
+ * FTDI_SIO_READ_EEPROM
+ *
+ * EEPROM format found in FTDI AN_201, "FT-X MTP memory Configuration",
+ * http://www.ftdichip.com/Support/Documents/AppNotes/AN_201_FT-X%20MTP%20Memory%20Configuration.pdf
+ */
+#define FTDI_SIO_READ_EEPROM_REQUEST_TYPE 0xc0
+#define FTDI_SIO_READ_EEPROM_REQUEST FTDI_SIO_READ_EEPROM
+
+#define FTDI_FTX_CBUS_MUX_GPIO 0x8
+#define FTDI_FT232R_CBUS_MUX_GPIO 0xa
/* Descriptors returned by the device
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index 97c69d373ca6..4ca31c0e4174 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -1637,24 +1637,20 @@ static int edge_tiocmget(struct tty_struct *tty)
return result;
}
-static int get_serial_info(struct edgeport_port *edge_port,
- struct serial_struct __user *retinfo)
+static int get_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
- struct serial_struct tmp;
-
- memset(&tmp, 0, sizeof(tmp));
-
- tmp.type = PORT_16550A;
- tmp.line = edge_port->port->minor;
- tmp.port = edge_port->port->port_number;
- tmp.irq = 0;
- tmp.xmit_fifo_size = edge_port->maxTxCredits;
- tmp.baud_base = 9600;
- tmp.close_delay = 5*HZ;
- tmp.closing_wait = 30*HZ;
+ struct usb_serial_port *port = tty->driver_data;
+ struct edgeport_port *edge_port = usb_get_serial_port_data(port);
- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return -EFAULT;
+ ss->type = PORT_16550A;
+ ss->line = edge_port->port->minor;
+ ss->port = edge_port->port->port_number;
+ ss->irq = 0;
+ ss->xmit_fifo_size = edge_port->maxTxCredits;
+ ss->baud_base = 9600;
+ ss->close_delay = 5*HZ;
+ ss->closing_wait = 30*HZ;
return 0;
}
@@ -1667,17 +1663,12 @@ static int edge_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
struct usb_serial_port *port = tty->driver_data;
- DEFINE_WAIT(wait);
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
switch (cmd) {
case TIOCSERGETLSR:
dev_dbg(&port->dev, "%s TIOCSERGETLSR\n", __func__);
return get_lsr_info(edge_port, (unsigned int __user *) arg);
-
- case TIOCGSERIAL:
- dev_dbg(&port->dev, "%s TIOCGSERIAL\n", __func__);
- return get_serial_info(edge_port, (struct serial_struct __user *) arg);
}
return -ENOIOCTLCMD;
}
@@ -3126,6 +3117,7 @@ static struct usb_serial_driver edgeport_2port_device = {
.set_termios = edge_set_termios,
.tiocmget = edge_tiocmget,
.tiocmset = edge_tiocmset,
+ .get_serial = get_serial_info,
.tiocmiwait = usb_serial_generic_tiocmiwait,
.get_icount = usb_serial_generic_get_icount,
.write = edge_write,
@@ -3161,6 +3153,7 @@ static struct usb_serial_driver edgeport_4port_device = {
.set_termios = edge_set_termios,
.tiocmget = edge_tiocmget,
.tiocmset = edge_tiocmset,
+ .get_serial = get_serial_info,
.tiocmiwait = usb_serial_generic_tiocmiwait,
.get_icount = usb_serial_generic_get_icount,
.write = edge_write,
@@ -3196,6 +3189,7 @@ static struct usb_serial_driver edgeport_8port_device = {
.set_termios = edge_set_termios,
.tiocmget = edge_tiocmget,
.tiocmset = edge_tiocmset,
+ .get_serial = get_serial_info,
.tiocmiwait = usb_serial_generic_tiocmiwait,
.get_icount = usb_serial_generic_get_icount,
.write = edge_write,
@@ -3231,6 +3225,7 @@ static struct usb_serial_driver epic_device = {
.set_termios = edge_set_termios,
.tiocmget = edge_tiocmget,
.tiocmset = edge_tiocmset,
+ .get_serial = get_serial_info,
.tiocmiwait = usb_serial_generic_tiocmiwait,
.get_icount = usb_serial_generic_get_icount,
.write = edge_write,
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index 6d1d6efa3055..c327d4cf7928 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -2437,47 +2437,28 @@ static int edge_tiocmget(struct tty_struct *tty)
return result;
}
-static int get_serial_info(struct edgeport_port *edge_port,
- struct serial_struct __user *retinfo)
+static int get_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
- struct serial_struct tmp;
+ struct usb_serial_port *port = tty->driver_data;
+ struct edgeport_port *edge_port = usb_get_serial_port_data(port);
unsigned cwait;
cwait = edge_port->port->port.closing_wait;
if (cwait != ASYNC_CLOSING_WAIT_NONE)
cwait = jiffies_to_msecs(cwait) / 10;
- memset(&tmp, 0, sizeof(tmp));
-
- tmp.type = PORT_16550A;
- tmp.line = edge_port->port->minor;
- tmp.port = edge_port->port->port_number;
- tmp.irq = 0;
- tmp.xmit_fifo_size = edge_port->port->bulk_out_size;
- tmp.baud_base = 9600;
- tmp.close_delay = 5*HZ;
- tmp.closing_wait = cwait;
-
- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return -EFAULT;
+ ss->type = PORT_16550A;
+ ss->line = edge_port->port->minor;
+ ss->port = edge_port->port->port_number;
+ ss->irq = 0;
+ ss->xmit_fifo_size = edge_port->port->bulk_out_size;
+ ss->baud_base = 9600;
+ ss->close_delay = 5*HZ;
+ ss->closing_wait = cwait;
return 0;
}
-static int edge_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct edgeport_port *edge_port = usb_get_serial_port_data(port);
-
- switch (cmd) {
- case TIOCGSERIAL:
- dev_dbg(&port->dev, "%s - TIOCGSERIAL\n", __func__);
- return get_serial_info(edge_port,
- (struct serial_struct __user *) arg);
- }
- return -ENOIOCTLCMD;
-}
-
static void edge_break(struct tty_struct *tty, int break_state)
{
struct usb_serial_port *port = tty->driver_data;
@@ -2738,7 +2719,7 @@ static struct usb_serial_driver edgeport_1port_device = {
.release = edge_release,
.port_probe = edge_port_probe,
.port_remove = edge_port_remove,
- .ioctl = edge_ioctl,
+ .get_serial = get_serial_info,
.set_termios = edge_set_termios,
.tiocmget = edge_tiocmget,
.tiocmset = edge_tiocmset,
@@ -2777,7 +2758,7 @@ static struct usb_serial_driver edgeport_2port_device = {
.release = edge_release,
.port_probe = edge_port_probe,
.port_remove = edge_port_remove,
- .ioctl = edge_ioctl,
+ .get_serial = get_serial_info,
.set_termios = edge_set_termios,
.tiocmget = edge_tiocmget,
.tiocmset = edge_tiocmset,
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index 27109522fd8b..fc52ac75fbf6 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -1786,69 +1786,20 @@ static int mos7720_tiocmset(struct tty_struct *tty,
return 0;
}
-static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd,
- unsigned int __user *value)
+static int get_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
- unsigned int mcr;
- unsigned int arg;
-
- struct usb_serial_port *port;
-
- if (mos7720_port == NULL)
- return -1;
-
- port = (struct usb_serial_port *)mos7720_port->port;
- mcr = mos7720_port->shadowMCR;
-
- if (copy_from_user(&arg, value, sizeof(int)))
- return -EFAULT;
-
- switch (cmd) {
- case TIOCMBIS:
- if (arg & TIOCM_RTS)
- mcr |= UART_MCR_RTS;
- if (arg & TIOCM_DTR)
- mcr |= UART_MCR_RTS;
- if (arg & TIOCM_LOOP)
- mcr |= UART_MCR_LOOP;
- break;
-
- case TIOCMBIC:
- if (arg & TIOCM_RTS)
- mcr &= ~UART_MCR_RTS;
- if (arg & TIOCM_DTR)
- mcr &= ~UART_MCR_RTS;
- if (arg & TIOCM_LOOP)
- mcr &= ~UART_MCR_LOOP;
- break;
-
- }
-
- mos7720_port->shadowMCR = mcr;
- write_mos_reg(port->serial, port->port_number, MOS7720_MCR,
- mos7720_port->shadowMCR);
-
- return 0;
-}
-
-static int get_serial_info(struct moschip_port *mos7720_port,
- struct serial_struct __user *retinfo)
-{
- struct serial_struct tmp;
-
- memset(&tmp, 0, sizeof(tmp));
-
- tmp.type = PORT_16550A;
- tmp.line = mos7720_port->port->minor;
- tmp.port = mos7720_port->port->port_number;
- tmp.irq = 0;
- tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE;
- tmp.baud_base = 9600;
- tmp.close_delay = 5*HZ;
- tmp.closing_wait = 30*HZ;
+ struct usb_serial_port *port = tty->driver_data;
+ struct moschip_port *mos7720_port = usb_get_serial_port_data(port);
- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return -EFAULT;
+ ss->type = PORT_16550A;
+ ss->line = mos7720_port->port->minor;
+ ss->port = mos7720_port->port->port_number;
+ ss->irq = 0;
+ ss->xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE;
+ ss->baud_base = 9600;
+ ss->close_delay = 5*HZ;
+ ss->closing_wait = 30*HZ;
return 0;
}
@@ -1867,18 +1818,6 @@ static int mos7720_ioctl(struct tty_struct *tty,
dev_dbg(&port->dev, "%s TIOCSERGETLSR\n", __func__);
return get_lsr_info(tty, mos7720_port,
(unsigned int __user *)arg);
-
- /* FIXME: These should be using the mode methods */
- case TIOCMBIS:
- case TIOCMBIC:
- dev_dbg(&port->dev, "%s TIOCMSET/TIOCMBIC/TIOCMSET\n", __func__);
- return set_modem_info(mos7720_port, cmd,
- (unsigned int __user *)arg);
-
- case TIOCGSERIAL:
- dev_dbg(&port->dev, "%s TIOCGSERIAL\n", __func__);
- return get_serial_info(mos7720_port,
- (struct serial_struct __user *)arg);
}
return -ENOIOCTLCMD;
@@ -2015,6 +1954,7 @@ static struct usb_serial_driver moschip7720_2port_driver = {
.ioctl = mos7720_ioctl,
.tiocmget = mos7720_tiocmget,
.tiocmset = mos7720_tiocmset,
+ .get_serial = get_serial_info,
.set_termios = mos7720_set_termios,
.write = mos7720_write,
.write_room = mos7720_write_room,
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index b42bad85097a..88828b4b8c44 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -1931,27 +1931,20 @@ static int mos7840_get_lsr_info(struct tty_struct *tty,
* function to get information about serial port
*****************************************************************************/
-static int mos7840_get_serial_info(struct moschip_port *mos7840_port,
- struct serial_struct __user *retinfo)
+static int mos7840_get_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
- struct serial_struct tmp;
-
- if (mos7840_port == NULL)
- return -1;
-
- memset(&tmp, 0, sizeof(tmp));
-
- tmp.type = PORT_16550A;
- tmp.line = mos7840_port->port->minor;
- tmp.port = mos7840_port->port->port_number;
- tmp.irq = 0;
- tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE;
- tmp.baud_base = 9600;
- tmp.close_delay = 5 * HZ;
- tmp.closing_wait = 30 * HZ;
+ struct usb_serial_port *port = tty->driver_data;
+ struct moschip_port *mos7840_port = mos7840_get_port_private(port);
- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return -EFAULT;
+ ss->type = PORT_16550A;
+ ss->line = mos7840_port->port->minor;
+ ss->port = mos7840_port->port->port_number;
+ ss->irq = 0;
+ ss->xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE;
+ ss->baud_base = 9600;
+ ss->close_delay = 5 * HZ;
+ ss->closing_wait = 30 * HZ;
return 0;
}
@@ -1982,13 +1975,6 @@ static int mos7840_ioctl(struct tty_struct *tty,
dev_dbg(&port->dev, "%s TIOCSERGETLSR\n", __func__);
return mos7840_get_lsr_info(tty, argp);
- case TIOCGSERIAL:
- dev_dbg(&port->dev, "%s TIOCGSERIAL\n", __func__);
- return mos7840_get_serial_info(mos7840_port, argp);
-
- case TIOCSSERIAL:
- dev_dbg(&port->dev, "%s TIOCSSERIAL\n", __func__);
- break;
default:
break;
}
@@ -2376,6 +2362,7 @@ static struct usb_serial_driver moschip7840_4port_device = {
.calc_num_ports = mos7840_calc_num_ports,
.probe = mos7840_probe,
.ioctl = mos7840_ioctl,
+ .get_serial = mos7840_get_serial_info,
.set_termios = mos7840_set_termios,
.break_ctl = mos7840_break,
.tiocmget = mos7840_tiocmget,
diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c
index caa0746326fd..cb7aac9cd9e7 100644
--- a/drivers/usb/serial/opticon.c
+++ b/drivers/usb/serial/opticon.c
@@ -328,42 +328,23 @@ static int opticon_tiocmset(struct tty_struct *tty,
return 0;
}
-static int get_serial_info(struct usb_serial_port *port,
- struct serial_struct __user *serial)
+static int get_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
- struct serial_struct tmp;
-
- memset(&tmp, 0x00, sizeof(tmp));
+ struct usb_serial_port *port = tty->driver_data;
/* fake emulate a 16550 uart to make userspace code happy */
- tmp.type = PORT_16550A;
- tmp.line = port->minor;
- tmp.port = 0;
- tmp.irq = 0;
- tmp.xmit_fifo_size = 1024;
- tmp.baud_base = 9600;
- tmp.close_delay = 5*HZ;
- tmp.closing_wait = 30*HZ;
-
- if (copy_to_user(serial, &tmp, sizeof(*serial)))
- return -EFAULT;
+ ss->type = PORT_16550A;
+ ss->line = port->minor;
+ ss->port = 0;
+ ss->irq = 0;
+ ss->xmit_fifo_size = 1024;
+ ss->baud_base = 9600;
+ ss->close_delay = 5*HZ;
+ ss->closing_wait = 30*HZ;
return 0;
}
-static int opticon_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
-{
- struct usb_serial_port *port = tty->driver_data;
-
- switch (cmd) {
- case TIOCGSERIAL:
- return get_serial_info(port,
- (struct serial_struct __user *)arg);
- }
-
- return -ENOIOCTLCMD;
-}
-
static int opticon_port_probe(struct usb_serial_port *port)
{
struct opticon_private *priv;
@@ -404,7 +385,7 @@ static struct usb_serial_driver opticon_device = {
.write_room = opticon_write_room,
.throttle = usb_serial_generic_throttle,
.unthrottle = usb_serial_generic_unthrottle,
- .ioctl = opticon_ioctl,
+ .get_serial = get_serial_info,
.tiocmget = opticon_tiocmget,
.tiocmset = opticon_tiocmset,
.process_read_urb = opticon_process_read_urb,
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 0215b70c4efc..e24ff16d4147 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -561,6 +561,9 @@ static void option_instat_callback(struct urb *urb);
/* Interface is reserved */
#define RSVD(ifnum) ((BIT(ifnum) & 0xff) << 0)
+/* Interface must have two endpoints */
+#define NUMEP2 BIT(16)
+
static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
@@ -1081,8 +1084,9 @@ static const struct usb_device_id option_ids[] = {
.driver_info = RSVD(4) },
{ USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_BG96),
.driver_info = RSVD(4) },
- { USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06),
- .driver_info = RSVD(4) | RSVD(5) },
+ { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06, 0xff, 0xff, 0xff),
+ .driver_info = RSVD(1) | RSVD(2) | RSVD(3) | RSVD(4) | NUMEP2 },
+ { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06, 0xff, 0, 0) },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6001) },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_300) },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6003),
@@ -1962,7 +1966,8 @@ static struct usb_serial_driver option_1port_device = {
.chars_in_buffer = usb_wwan_chars_in_buffer,
.tiocmget = usb_wwan_tiocmget,
.tiocmset = usb_wwan_tiocmset,
- .ioctl = usb_wwan_ioctl,
+ .get_serial = usb_wwan_get_serial_info,
+ .set_serial = usb_wwan_set_serial_info,
.attach = option_attach,
.release = option_release,
.port_probe = usb_wwan_port_probe,
@@ -1999,6 +2004,13 @@ static int option_probe(struct usb_serial *serial,
if (device_flags & RSVD(iface_desc->bInterfaceNumber))
return -ENODEV;
+ /*
+ * Allow matching on bNumEndpoints for devices whose interface numbers
+ * can change (e.g. Quectel EP06).
+ */
+ if (device_flags & NUMEP2 && iface_desc->bNumEndpoints != 2)
+ return -ENODEV;
+
/* Store the device flags so we can use them during attach. */
usb_set_serial_data(serial, (void *)device_flags);
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index e41f725ac7aa..a4e0d13fc121 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -808,29 +808,16 @@ static int pl2303_carrier_raised(struct usb_serial_port *port)
return 0;
}
-static int pl2303_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
+static int pl2303_get_serial(struct tty_struct *tty,
+ struct serial_struct *ss)
{
- struct serial_struct ser;
struct usb_serial_port *port = tty->driver_data;
- switch (cmd) {
- case TIOCGSERIAL:
- memset(&ser, 0, sizeof ser);
- ser.type = PORT_16654;
- ser.line = port->minor;
- ser.port = port->port_number;
- ser.baud_base = 460800;
-
- if (copy_to_user((void __user *)arg, &ser, sizeof ser))
- return -EFAULT;
-
- return 0;
- default:
- break;
- }
-
- return -ENOIOCTLCMD;
+ ss->type = PORT_16654;
+ ss->line = port->minor;
+ ss->port = port->port_number;
+ ss->baud_base = 460800;
+ return 0;
}
static void pl2303_set_break(struct usb_serial_port *port, bool enable)
@@ -1016,7 +1003,7 @@ static struct usb_serial_driver pl2303_device = {
.close = pl2303_close,
.dtr_rts = pl2303_dtr_rts,
.carrier_raised = pl2303_carrier_raised,
- .ioctl = pl2303_ioctl,
+ .get_serial = pl2303_get_serial,
.break_ctl = pl2303_break_ctl,
.set_termios = pl2303_set_termios,
.tiocmget = pl2303_tiocmget,
diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c
index b61c2a9b6b11..f2fbe1ec9701 100644
--- a/drivers/usb/serial/quatech2.c
+++ b/drivers/usb/serial/quatech2.c
@@ -453,39 +453,19 @@ static void qt2_disconnect(struct usb_serial *serial)
usb_kill_urb(serial_priv->read_urb);
}
-static int get_serial_info(struct usb_serial_port *port,
- struct serial_struct __user *retinfo)
-{
- struct serial_struct tmp;
-
- memset(&tmp, 0, sizeof(tmp));
- tmp.line = port->minor;
- tmp.port = 0;
- tmp.irq = 0;
- tmp.xmit_fifo_size = port->bulk_out_size;
- tmp.baud_base = 9600;
- tmp.close_delay = 5*HZ;
- tmp.closing_wait = 30*HZ;
-
- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return -EFAULT;
- return 0;
-}
-
-static int qt2_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
+static int get_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
struct usb_serial_port *port = tty->driver_data;
- switch (cmd) {
- case TIOCGSERIAL:
- return get_serial_info(port,
- (struct serial_struct __user *)arg);
- default:
- break;
- }
-
- return -ENOIOCTLCMD;
+ ss->line = port->minor;
+ ss->port = 0;
+ ss->irq = 0;
+ ss->xmit_fifo_size = port->bulk_out_size;
+ ss->baud_base = 9600;
+ ss->close_delay = 5*HZ;
+ ss->closing_wait = 30*HZ;
+ return 0;
}
static void qt2_process_status(struct usb_serial_port *port, unsigned char *ch)
@@ -1013,7 +993,7 @@ static struct usb_serial_driver qt2_device = {
.tiocmset = qt2_tiocmset,
.tiocmiwait = usb_serial_generic_tiocmiwait,
.get_icount = usb_serial_generic_get_icount,
- .ioctl = qt2_ioctl,
+ .get_serial = get_serial_info,
.set_termios = qt2_set_termios,
};
diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c
index 0900b47b5f57..f6aea9f1be1a 100644
--- a/drivers/usb/serial/ssu100.c
+++ b/drivers/usb/serial/ssu100.c
@@ -331,39 +331,19 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port)
return usb_serial_generic_open(tty, port);
}
-static int get_serial_info(struct usb_serial_port *port,
- struct serial_struct __user *retinfo)
-{
- struct serial_struct tmp;
-
- memset(&tmp, 0, sizeof(tmp));
- tmp.line = port->minor;
- tmp.port = 0;
- tmp.irq = 0;
- tmp.xmit_fifo_size = port->bulk_out_size;
- tmp.baud_base = 9600;
- tmp.close_delay = 5*HZ;
- tmp.closing_wait = 30*HZ;
-
- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return -EFAULT;
- return 0;
-}
-
-static int ssu100_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
+static int get_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
struct usb_serial_port *port = tty->driver_data;
- switch (cmd) {
- case TIOCGSERIAL:
- return get_serial_info(port,
- (struct serial_struct __user *) arg);
- default:
- break;
- }
-
- return -ENOIOCTLCMD;
+ ss->line = port->minor;
+ ss->port = 0;
+ ss->irq = 0;
+ ss->xmit_fifo_size = port->bulk_out_size;
+ ss->baud_base = 9600;
+ ss->close_delay = 5*HZ;
+ ss->closing_wait = 30*HZ;
+ return 0;
}
static int ssu100_attach(struct usb_serial *serial)
@@ -566,7 +546,7 @@ static struct usb_serial_driver ssu100_device = {
.tiocmset = ssu100_tiocmset,
.tiocmiwait = usb_serial_generic_tiocmiwait,
.get_icount = usb_serial_generic_get_icount,
- .ioctl = ssu100_ioctl,
+ .get_serial = get_serial_info,
.set_termios = ssu100_set_termios,
};
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index e3c5832337e0..dd0ad67aa71e 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -313,8 +313,6 @@ static 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);
-static int ti_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg);
static void ti_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios);
static int ti_tiocmget(struct tty_struct *tty);
@@ -330,10 +328,10 @@ static void ti_recv(struct usb_serial_port *port, unsigned char *data,
static void ti_send(struct ti_port *tport);
static int ti_set_mcr(struct ti_port *tport, unsigned int mcr);
static int ti_get_lsr(struct ti_port *tport, u8 *lsr);
-static int ti_get_serial_info(struct ti_port *tport,
- struct serial_struct __user *ret_arg);
-static int ti_set_serial_info(struct tty_struct *tty, struct ti_port *tport,
- struct serial_struct __user *new_arg);
+static int ti_get_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss);
+static int ti_set_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss);
static void ti_handle_new_msr(struct ti_port *tport, u8 msr);
static void ti_stop_read(struct ti_port *tport, struct tty_struct *tty);
@@ -436,7 +434,8 @@ static struct usb_serial_driver ti_1port_device = {
.tx_empty = ti_tx_empty,
.throttle = ti_throttle,
.unthrottle = ti_unthrottle,
- .ioctl = ti_ioctl,
+ .get_serial = ti_get_serial_info,
+ .set_serial = ti_set_serial_info,
.set_termios = ti_set_termios,
.tiocmget = ti_tiocmget,
.tiocmset = ti_tiocmset,
@@ -469,7 +468,8 @@ static struct usb_serial_driver ti_2port_device = {
.tx_empty = ti_tx_empty,
.throttle = ti_throttle,
.unthrottle = ti_unthrottle,
- .ioctl = ti_ioctl,
+ .get_serial = ti_get_serial_info,
+ .set_serial = ti_set_serial_info,
.set_termios = ti_set_termios,
.tiocmget = ti_tiocmget,
.tiocmset = ti_tiocmset,
@@ -902,24 +902,6 @@ static void ti_unthrottle(struct tty_struct *tty)
}
}
-static int ti_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct ti_port *tport = usb_get_serial_port_data(port);
-
- switch (cmd) {
- case TIOCGSERIAL:
- return ti_get_serial_info(tport,
- (struct serial_struct __user *)arg);
- case TIOCSSERIAL:
- return ti_set_serial_info(tty, tport,
- (struct serial_struct __user *)arg);
- }
- return -ENOIOCTLCMD;
-}
-
-
static void ti_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
{
@@ -1417,45 +1399,37 @@ free_data:
}
-static int ti_get_serial_info(struct ti_port *tport,
- struct serial_struct __user *ret_arg)
+static int ti_get_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
- struct usb_serial_port *port = tport->tp_port;
- struct serial_struct ret_serial;
+ struct usb_serial_port *port = tty->driver_data;
+ struct ti_port *tport = usb_get_serial_port_data(port);
unsigned cwait;
cwait = port->port.closing_wait;
if (cwait != ASYNC_CLOSING_WAIT_NONE)
cwait = jiffies_to_msecs(cwait) / 10;
- memset(&ret_serial, 0, sizeof(ret_serial));
-
- ret_serial.type = PORT_16550A;
- ret_serial.line = port->minor;
- ret_serial.port = port->port_number;
- ret_serial.xmit_fifo_size = kfifo_size(&port->write_fifo);
- ret_serial.baud_base = tport->tp_tdev->td_is_3410 ? 921600 : 460800;
- ret_serial.closing_wait = cwait;
-
- if (copy_to_user(ret_arg, &ret_serial, sizeof(*ret_arg)))
- return -EFAULT;
-
+ ss->type = PORT_16550A;
+ ss->line = port->minor;
+ ss->port = port->port_number;
+ ss->xmit_fifo_size = kfifo_size(&port->write_fifo);
+ ss->baud_base = tport->tp_tdev->td_is_3410 ? 921600 : 460800;
+ ss->closing_wait = cwait;
return 0;
}
-static int ti_set_serial_info(struct tty_struct *tty, struct ti_port *tport,
- struct serial_struct __user *new_arg)
+static int ti_set_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
- struct serial_struct new_serial;
+ struct usb_serial_port *port = tty->driver_data;
+ struct ti_port *tport = usb_get_serial_port_data(port);
unsigned cwait;
- if (copy_from_user(&new_serial, new_arg, sizeof(new_serial)))
- return -EFAULT;
-
- cwait = new_serial.closing_wait;
+ cwait = ss->closing_wait;
if (cwait != ASYNC_CLOSING_WAIT_NONE)
- cwait = msecs_to_jiffies(10 * new_serial.closing_wait);
+ cwait = msecs_to_jiffies(10 * ss->closing_wait);
tport->tp_port->port.closing_wait = cwait;
diff --git a/drivers/usb/serial/usb-serial-simple.c b/drivers/usb/serial/usb-serial-simple.c
index 40864c2bd9dc..4d0273508043 100644
--- a/drivers/usb/serial/usb-serial-simple.c
+++ b/drivers/usb/serial/usb-serial-simple.c
@@ -84,7 +84,8 @@ DEVICE(moto_modem, MOTO_IDS);
/* Motorola Tetra driver */
#define MOTOROLA_TETRA_IDS() \
- { USB_DEVICE(0x0cad, 0x9011) } /* Motorola Solutions TETRA PEI */
+ { USB_DEVICE(0x0cad, 0x9011) }, /* Motorola Solutions TETRA PEI */ \
+ { USB_DEVICE(0x0cad, 0x9012) } /* MTP6550 */
DEVICE(motorola_tetra, MOTOROLA_TETRA_IDS);
/* Novatel Wireless GPS driver */
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index f7aaa7f079e1..7e89efbf2c28 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -396,6 +396,24 @@ static void serial_unthrottle(struct tty_struct *tty)
port->serial->type->unthrottle(tty);
}
+static int serial_get_serial(struct tty_struct *tty, struct serial_struct *ss)
+{
+ struct usb_serial_port *port = tty->driver_data;
+
+ if (port->serial->type->get_serial)
+ return port->serial->type->get_serial(tty, ss);
+ return -ENOTTY;
+}
+
+static int serial_set_serial(struct tty_struct *tty, struct serial_struct *ss)
+{
+ struct usb_serial_port *port = tty->driver_data;
+
+ if (port->serial->type->set_serial)
+ return port->serial->type->set_serial(tty, ss);
+ return -ENOTTY;
+}
+
static int serial_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
@@ -1177,6 +1195,8 @@ static const struct tty_operations serial_ops = {
.tiocmget = serial_tiocmget,
.tiocmset = serial_tiocmset,
.get_icount = serial_get_icount,
+ .set_serial = serial_set_serial,
+ .get_serial = serial_get_serial,
.cleanup = serial_cleanup,
.install = serial_install,
.proc_show = serial_proc_show,
diff --git a/drivers/usb/serial/usb-wwan.h b/drivers/usb/serial/usb-wwan.h
index d28dab4b9eff..1c120eaf4091 100644
--- a/drivers/usb/serial/usb-wwan.h
+++ b/drivers/usb/serial/usb-wwan.h
@@ -15,8 +15,10 @@ extern 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_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg);
+extern int usb_wwan_get_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss);
+extern int usb_wwan_set_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss);
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);
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index 912472f26e4f..7e855c87e4f7 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -132,38 +132,32 @@ int usb_wwan_tiocmset(struct tty_struct *tty,
}
EXPORT_SYMBOL(usb_wwan_tiocmset);
-static int get_serial_info(struct usb_serial_port *port,
- struct serial_struct __user *retinfo)
+int usb_wwan_get_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
- struct serial_struct tmp;
-
- memset(&tmp, 0, sizeof(tmp));
- tmp.line = port->minor;
- tmp.port = port->port_number;
- tmp.baud_base = tty_get_baud_rate(port->port.tty);
- tmp.close_delay = port->port.close_delay / 10;
- tmp.closing_wait = port->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
+ struct usb_serial_port *port = tty->driver_data;
+
+ ss->line = port->minor;
+ ss->port = port->port_number;
+ ss->baud_base = tty_get_baud_rate(port->port.tty);
+ ss->close_delay = port->port.close_delay / 10;
+ ss->closing_wait = port->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
ASYNC_CLOSING_WAIT_NONE :
port->port.closing_wait / 10;
-
- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return -EFAULT;
return 0;
}
+EXPORT_SYMBOL(usb_wwan_get_serial_info);
-static int set_serial_info(struct usb_serial_port *port,
- struct serial_struct __user *newinfo)
+int usb_wwan_set_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
- struct serial_struct new_serial;
+ struct usb_serial_port *port = tty->driver_data;
unsigned int closing_wait, close_delay;
int retval = 0;
- if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
- return -EFAULT;
-
- close_delay = new_serial.close_delay * 10;
- closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
- ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10;
+ close_delay = ss->close_delay * 10;
+ closing_wait = ss->closing_wait == ASYNC_CLOSING_WAIT_NONE ?
+ ASYNC_CLOSING_WAIT_NONE : ss->closing_wait * 10;
mutex_lock(&port->port.mutex);
@@ -181,30 +175,7 @@ static int set_serial_info(struct usb_serial_port *port,
mutex_unlock(&port->port.mutex);
return retval;
}
-
-int usb_wwan_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
-{
- struct usb_serial_port *port = tty->driver_data;
-
- dev_dbg(&port->dev, "%s cmd 0x%04x\n", __func__, cmd);
-
- switch (cmd) {
- case TIOCGSERIAL:
- return get_serial_info(port,
- (struct serial_struct __user *) arg);
- case TIOCSSERIAL:
- return set_serial_info(port,
- (struct serial_struct __user *) arg);
- default:
- break;
- }
-
- dev_dbg(&port->dev, "%s arg not supported\n", __func__);
-
- return -ENOIOCTLCMD;
-}
-EXPORT_SYMBOL(usb_wwan_ioctl);
+EXPORT_SYMBOL(usb_wwan_set_serial_info);
int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count)
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index 1c7b46a8620c..aefd84f88b59 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -83,8 +83,8 @@ static int whiteheat_port_remove(struct usb_serial_port *port);
static int whiteheat_open(struct tty_struct *tty,
struct usb_serial_port *port);
static void whiteheat_close(struct usb_serial_port *port);
-static int whiteheat_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg);
+static int whiteheat_get_serial(struct tty_struct *tty,
+ struct serial_struct *ss);
static void whiteheat_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old);
static int whiteheat_tiocmget(struct tty_struct *tty);
@@ -120,7 +120,7 @@ static struct usb_serial_driver whiteheat_device = {
.port_remove = whiteheat_port_remove,
.open = whiteheat_open,
.close = whiteheat_close,
- .ioctl = whiteheat_ioctl,
+ .get_serial = whiteheat_get_serial,
.set_termios = whiteheat_set_termios,
.break_ctl = whiteheat_break_ctl,
.tiocmget = whiteheat_tiocmget,
@@ -442,33 +442,21 @@ static int whiteheat_tiocmset(struct tty_struct *tty,
}
-static int whiteheat_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
+static int whiteheat_get_serial(struct tty_struct *tty,
+ struct serial_struct *ss)
{
struct usb_serial_port *port = tty->driver_data;
- struct serial_struct serstruct;
- void __user *user_arg = (void __user *)arg;
-
- switch (cmd) {
- case TIOCGSERIAL:
- memset(&serstruct, 0, sizeof(serstruct));
- serstruct.type = PORT_16654;
- serstruct.line = port->minor;
- serstruct.port = port->port_number;
- serstruct.xmit_fifo_size = kfifo_size(&port->write_fifo);
- serstruct.custom_divisor = 0;
- serstruct.baud_base = 460800;
- serstruct.close_delay = CLOSING_DELAY;
- serstruct.closing_wait = CLOSING_DELAY;
-
- if (copy_to_user(user_arg, &serstruct, sizeof(serstruct)))
- return -EFAULT;
- break;
- default:
- break;
- }
- return -ENOIOCTLCMD;
+ ss->type = PORT_16654;
+ ss->line = port->minor;
+ ss->port = port->port_number;
+ ss->xmit_fifo_size = kfifo_size(&port->write_fifo);
+ ss->custom_divisor = 0;
+ ss->baud_base = 460800;
+ ss->close_delay = CLOSING_DELAY;
+ ss->closing_wait = CLOSING_DELAY;
+
+ return 0;
}
diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig
index ec84758f0e23..6fd427284b12 100644
--- a/drivers/usb/storage/Kconfig
+++ b/drivers/usb/storage/Kconfig
@@ -23,16 +23,16 @@ config USB_STORAGE
To compile this driver as a module, choose M here: the
module will be called usb-storage.
+if USB_STORAGE
+
config USB_STORAGE_DEBUG
bool "USB Mass Storage verbose debug"
- depends on USB_STORAGE
help
Say Y here in order to have the USB Mass Storage code generate
verbose debugging messages.
config USB_STORAGE_REALTEK
tristate "Realtek Card Reader support"
- depends on USB_STORAGE
help
Say Y here to include additional code to support the power-saving function
for Realtek RTS51xx USB card readers.
@@ -46,7 +46,6 @@ config REALTEK_AUTOPM
config USB_STORAGE_DATAFAB
tristate "Datafab Compact Flash Reader support"
- depends on USB_STORAGE
help
Support for certain Datafab CompactFlash readers.
Datafab has a web page at <http://www.datafab.com/>.
@@ -55,7 +54,6 @@ config USB_STORAGE_DATAFAB
config USB_STORAGE_FREECOM
tristate "Freecom USB/ATAPI Bridge support"
- depends on USB_STORAGE
help
Support for the Freecom USB to IDE/ATAPI adaptor.
Freecom has a web page at <http://www.freecom.de/>.
@@ -64,7 +62,6 @@ config USB_STORAGE_FREECOM
config USB_STORAGE_ISD200
tristate "ISD-200 USB/ATA Bridge support"
- depends on USB_STORAGE
---help---
Say Y here if you want to use USB Mass Store devices based
on the In-Systems Design ISD-200 USB/ATA bridge.
@@ -82,7 +79,6 @@ config USB_STORAGE_ISD200
config USB_STORAGE_USBAT
tristate "USBAT/USBAT02-based storage support"
- depends on USB_STORAGE
help
Say Y here to include additional code to support storage devices
based on the SCM/Shuttle USBAT/USBAT02 processors.
@@ -105,7 +101,6 @@ config USB_STORAGE_USBAT
config USB_STORAGE_SDDR09
tristate "SanDisk SDDR-09 (and other SmartMedia, including DPCM) support"
- depends on USB_STORAGE
help
Say Y here to include additional code to support the Sandisk SDDR-09
SmartMedia reader in the USB Mass Storage driver.
@@ -115,7 +110,6 @@ config USB_STORAGE_SDDR09
config USB_STORAGE_SDDR55
tristate "SanDisk SDDR-55 SmartMedia support"
- depends on USB_STORAGE
help
Say Y here to include additional code to support the Sandisk SDDR-55
SmartMedia reader in the USB Mass Storage driver.
@@ -124,7 +118,6 @@ config USB_STORAGE_SDDR55
config USB_STORAGE_JUMPSHOT
tristate "Lexar Jumpshot Compact Flash Reader"
- depends on USB_STORAGE
help
Say Y here to include additional code to support the Lexar Jumpshot
USB CompactFlash reader.
@@ -133,7 +126,6 @@ config USB_STORAGE_JUMPSHOT
config USB_STORAGE_ALAUDA
tristate "Olympus MAUSB-10/Fuji DPC-R1 support"
- depends on USB_STORAGE
help
Say Y here to include additional code to support the Olympus MAUSB-10
and Fujifilm DPC-R1 USB Card reader/writer devices.
@@ -145,7 +137,6 @@ config USB_STORAGE_ALAUDA
config USB_STORAGE_ONETOUCH
tristate "Support OneTouch Button on Maxtor Hard Drives"
- depends on USB_STORAGE
depends on INPUT=y || INPUT=USB_STORAGE
help
Say Y here to include additional code to support the Maxtor OneTouch
@@ -160,7 +151,6 @@ config USB_STORAGE_ONETOUCH
config USB_STORAGE_KARMA
tristate "Support for Rio Karma music player"
- depends on USB_STORAGE
help
Say Y here to include additional code to support the Rio Karma
USB interface.
@@ -174,7 +164,6 @@ config USB_STORAGE_KARMA
config USB_STORAGE_CYPRESS_ATACB
tristate "SAT emulation on Cypress USB/ATA Bridge with ATACB"
- depends on USB_STORAGE
---help---
Say Y here if you want to use SAT (ata pass through) on devices based
on the Cypress USB/ATA bridge supporting ATACB. This will allow you
@@ -187,19 +176,15 @@ config USB_STORAGE_CYPRESS_ATACB
config USB_STORAGE_ENE_UB6250
tristate "USB ENE card reader support"
- depends on SCSI
- depends on USB_STORAGE
---help---
Say Y here if you wish to control a ENE SD/MS Card reader.
Note that this driver does not support SM cards.
- This option depends on 'SCSI' support being enabled, but you
- probably also need 'SCSI device support: SCSI disk support'
- (BLK_DEV_SD) for most USB storage devices.
-
To compile this driver as a module, choose M here: the
module will be called ums-eneub6250.
+endif # USB_STORAGE
+
config USB_UAS
tristate "USB Attached SCSI"
depends on SCSI && USB_STORAGE
diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c
index f5e4500d9970..2b474d60b4db 100644
--- a/drivers/usb/storage/isd200.c
+++ b/drivers/usb/storage/isd200.c
@@ -1153,7 +1153,7 @@ static int isd200_get_inquiry_data( struct us_data *us )
/* Fill in vendor identification fields */
src = (__be16 *)&id[ATA_ID_PROD];
dest = (__u16*)info->InquiryData.VendorId;
- for (i=0;i<4;i++)
+ for (i = 0; i < 4; i++)
dest[i] = be16_to_cpu(src[i]);
src = (__be16 *)&id[ATA_ID_PROD + 8/2];
diff --git a/drivers/usb/typec/Kconfig b/drivers/usb/typec/Kconfig
index 00878c386dd0..30a847c2089d 100644
--- a/drivers/usb/typec/Kconfig
+++ b/drivers/usb/typec/Kconfig
@@ -45,50 +45,7 @@ menuconfig TYPEC
if TYPEC
-config TYPEC_TCPM
- tristate "USB Type-C Port Controller Manager"
- depends on USB
- select USB_ROLE_SWITCH
- select POWER_SUPPLY
- help
- The Type-C Port Controller Manager provides a USB PD and USB Type-C
- state machine for use with Type-C Port Controllers.
-
-if TYPEC_TCPM
-
-config TYPEC_TCPCI
- tristate "Type-C Port Controller Interface driver"
- depends on I2C
- select REGMAP_I2C
- help
- Type-C Port Controller driver for TCPCI-compliant controller.
-
-config TYPEC_RT1711H
- tristate "Richtek RT1711H Type-C chip driver"
- depends on I2C
- select TYPEC_TCPCI
- help
- Richtek RT1711H Type-C chip driver that works with
- Type-C Port Controller Manager to provide USB PD and USB
- Type-C functionalities.
-
-source "drivers/usb/typec/fusb302/Kconfig"
-
-config TYPEC_WCOVE
- tristate "Intel WhiskeyCove PMIC USB Type-C PHY driver"
- depends on ACPI
- depends on INTEL_SOC_PMIC
- depends on INTEL_PMC_IPC
- depends on BXT_WC_PMIC_OPREGION
- help
- This driver adds support for USB Type-C detection on Intel Broxton
- platforms that have Intel Whiskey Cove PMIC. The driver can detect the
- role and cable orientation.
-
- To compile this driver as module, choose M here: the module will be
- called typec_wcove
-
-endif # TYPEC_TCPM
+source "drivers/usb/typec/tcpm/Kconfig"
source "drivers/usb/typec/ucsi/Kconfig"
diff --git a/drivers/usb/typec/Makefile b/drivers/usb/typec/Makefile
index 45b0aef428a8..6696b7263d61 100644
--- a/drivers/usb/typec/Makefile
+++ b/drivers/usb/typec/Makefile
@@ -2,11 +2,7 @@
obj-$(CONFIG_TYPEC) += typec.o
typec-y := class.o mux.o bus.o
obj-$(CONFIG_TYPEC) += altmodes/
-obj-$(CONFIG_TYPEC_TCPM) += tcpm.o
-obj-y += fusb302/
-obj-$(CONFIG_TYPEC_WCOVE) += typec_wcove.o
+obj-$(CONFIG_TYPEC_TCPM) += tcpm/
obj-$(CONFIG_TYPEC_UCSI) += ucsi/
obj-$(CONFIG_TYPEC_TPS6598X) += tps6598x.o
obj-$(CONFIG_TYPEC) += mux/
-obj-$(CONFIG_TYPEC_TCPCI) += tcpci.o
-obj-$(CONFIG_TYPEC_RT1711H) += tcpci_rt1711h.o
diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
index e61dffb27a0c..5db0593ca0bd 100644
--- a/drivers/usb/typec/class.c
+++ b/drivers/usb/typec/class.c
@@ -1322,7 +1322,7 @@ void typec_set_pwr_role(struct typec_port *port, enum typec_role role)
EXPORT_SYMBOL_GPL(typec_set_pwr_role);
/**
- * typec_set_pwr_role - Report VCONN source change
+ * typec_set_vconn_role - Report VCONN source change
* @port: The USB Type-C Port which VCONN role changed
* @role: Source when @port is sourcing VCONN, or Sink when it's not
*
@@ -1500,7 +1500,7 @@ typec_port_register_altmode(struct typec_port *port,
sprintf(id, "id%04xm%02x", desc->svid, desc->mode);
- mux = typec_mux_get(port->dev.parent, id);
+ mux = typec_mux_get(&port->dev, id);
if (IS_ERR(mux))
return ERR_CAST(mux);
@@ -1540,18 +1540,6 @@ struct typec_port *typec_register_port(struct device *parent,
return ERR_PTR(id);
}
- port->sw = typec_switch_get(cap->fwnode ? &port->dev : parent);
- if (IS_ERR(port->sw)) {
- ret = PTR_ERR(port->sw);
- goto err_switch;
- }
-
- port->mux = typec_mux_get(parent, "typec-mux");
- if (IS_ERR(port->mux)) {
- ret = PTR_ERR(port->mux);
- goto err_mux;
- }
-
switch (cap->type) {
case TYPEC_PORT_SRC:
port->pwr_role = TYPEC_SOURCE;
@@ -1592,13 +1580,26 @@ struct typec_port *typec_register_port(struct device *parent,
port->port_type = cap->type;
port->prefer_role = cap->prefer_role;
+ device_initialize(&port->dev);
port->dev.class = typec_class;
port->dev.parent = parent;
port->dev.fwnode = cap->fwnode;
port->dev.type = &typec_port_dev_type;
dev_set_name(&port->dev, "port%d", id);
- ret = device_register(&port->dev);
+ port->sw = typec_switch_get(&port->dev);
+ if (IS_ERR(port->sw)) {
+ put_device(&port->dev);
+ return ERR_CAST(port->sw);
+ }
+
+ port->mux = typec_mux_get(&port->dev, "typec-mux");
+ if (IS_ERR(port->mux)) {
+ put_device(&port->dev);
+ return ERR_CAST(port->mux);
+ }
+
+ ret = device_add(&port->dev);
if (ret) {
dev_err(parent, "failed to register port (%d)\n", ret);
put_device(&port->dev);
@@ -1606,15 +1607,6 @@ struct typec_port *typec_register_port(struct device *parent,
}
return port;
-
-err_mux:
- typec_switch_put(port->sw);
-
-err_switch:
- ida_simple_remove(&typec_index_ida, port->id);
- kfree(port);
-
- return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(typec_register_port);
diff --git a/drivers/usb/typec/fusb302/Kconfig b/drivers/usb/typec/fusb302/Kconfig
deleted file mode 100644
index fce099ff39fe..000000000000
--- a/drivers/usb/typec/fusb302/Kconfig
+++ /dev/null
@@ -1,7 +0,0 @@
-config TYPEC_FUSB302
- tristate "Fairchild FUSB302 Type-C chip driver"
- depends on I2C
- help
- The Fairchild FUSB302 Type-C chip driver that works with
- Type-C Port Controller Manager to provide USB PD and USB
- Type-C functionalities.
diff --git a/drivers/usb/typec/fusb302/Makefile b/drivers/usb/typec/fusb302/Makefile
deleted file mode 100644
index 3b51b33631a0..000000000000
--- a/drivers/usb/typec/fusb302/Makefile
+++ /dev/null
@@ -1,2 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_TYPEC_FUSB302) += fusb302.o
diff --git a/drivers/usb/typec/tcpm/Kconfig b/drivers/usb/typec/tcpm/Kconfig
new file mode 100644
index 000000000000..f03ea8a61768
--- /dev/null
+++ b/drivers/usb/typec/tcpm/Kconfig
@@ -0,0 +1,52 @@
+config TYPEC_TCPM
+ tristate "USB Type-C Port Controller Manager"
+ depends on USB
+ select USB_ROLE_SWITCH
+ select POWER_SUPPLY
+ help
+ The Type-C Port Controller Manager provides a USB PD and USB Type-C
+ state machine for use with Type-C Port Controllers.
+
+if TYPEC_TCPM
+
+config TYPEC_TCPCI
+ tristate "Type-C Port Controller Interface driver"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ Type-C Port Controller driver for TCPCI-compliant controller.
+
+if TYPEC_TCPCI
+
+config TYPEC_RT1711H
+ tristate "Richtek RT1711H Type-C chip driver"
+ help
+ Richtek RT1711H Type-C chip driver that works with
+ Type-C Port Controller Manager to provide USB PD and USB
+ Type-C functionalities.
+
+endif # TYPEC_TCPCI
+
+config TYPEC_FUSB302
+ tristate "Fairchild FUSB302 Type-C chip driver"
+ depends on I2C
+ help
+ The Fairchild FUSB302 Type-C chip driver that works with
+ Type-C Port Controller Manager to provide USB PD and USB
+ Type-C functionalities.
+
+config TYPEC_WCOVE
+ tristate "Intel WhiskeyCove PMIC USB Type-C PHY driver"
+ depends on ACPI
+ depends on INTEL_SOC_PMIC
+ depends on INTEL_PMC_IPC
+ depends on BXT_WC_PMIC_OPREGION
+ help
+ This driver adds support for USB Type-C on Intel Broxton platforms
+ that have Intel Whiskey Cove PMIC. The driver works with USB Type-C
+ Port Controller Manager to provide USB PD and Type-C functionalities.
+
+ To compile this driver as module, choose M here: the module will be
+ called typec_wcove.ko
+
+endif # TYPEC_TCPM
diff --git a/drivers/usb/typec/tcpm/Makefile b/drivers/usb/typec/tcpm/Makefile
new file mode 100644
index 000000000000..a5ff6c8eb892
--- /dev/null
+++ b/drivers/usb/typec/tcpm/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_TYPEC_TCPM) += tcpm.o
+obj-$(CONFIG_TYPEC_FUSB302) += fusb302.o
+obj-$(CONFIG_TYPEC_WCOVE) += typec_wcove.o
+typec_wcove-y := wcove.o
+obj-$(CONFIG_TYPEC_TCPCI) += tcpci.o
+obj-$(CONFIG_TYPEC_RT1711H) += tcpci_rt1711h.o
diff --git a/drivers/usb/typec/fusb302/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index 82bed9810be6..43b64d9309d0 100644
--- a/drivers/usb/typec/fusb302/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -42,19 +42,12 @@
#define T_BC_LVL_DEBOUNCE_DELAY_MS 30
enum toggling_mode {
- TOGGLINE_MODE_OFF,
+ TOGGLING_MODE_OFF,
TOGGLING_MODE_DRP,
TOGGLING_MODE_SNK,
TOGGLING_MODE_SRC,
};
-static const char * const toggling_mode_name[] = {
- [TOGGLINE_MODE_OFF] = "toggling_OFF",
- [TOGGLING_MODE_DRP] = "toggling_DRP",
- [TOGGLING_MODE_SNK] = "toggling_SNK",
- [TOGGLING_MODE_SRC] = "toggling_SRC",
-};
-
enum src_current_status {
SRC_CURRENT_DEFAULT,
SRC_CURRENT_MEDIUM,
@@ -601,7 +594,7 @@ static int fusb302_set_toggling(struct fusb302_chip *chip,
chip->intr_comp_chng = false;
/* configure toggling mode: none/snk/src/drp */
switch (mode) {
- case TOGGLINE_MODE_OFF:
+ case TOGGLING_MODE_OFF:
ret = fusb302_i2c_mask_write(chip, FUSB_REG_CONTROL2,
FUSB_REG_CONTROL2_MODE_MASK,
FUSB_REG_CONTROL2_MODE_NONE);
@@ -633,7 +626,7 @@ static int fusb302_set_toggling(struct fusb302_chip *chip,
break;
}
- if (mode == TOGGLINE_MODE_OFF) {
+ if (mode == TOGGLING_MODE_OFF) {
/* mask TOGDONE interrupt */
ret = fusb302_i2c_set_bits(chip, FUSB_REG_MASKA,
FUSB_REG_MASKA_TOGDONE);
@@ -686,6 +679,7 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum typec_cc_status cc)
int ret = 0;
bool pull_up, pull_down;
u8 rd_mda;
+ enum toggling_mode mode;
mutex_lock(&chip->lock);
switch (cc) {
@@ -709,7 +703,7 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum typec_cc_status cc)
ret = -EINVAL;
goto done;
}
- ret = fusb302_set_toggling(chip, TOGGLINE_MODE_OFF);
+ ret = fusb302_set_toggling(chip, TOGGLING_MODE_OFF);
if (ret < 0) {
fusb302_log(chip, "cannot stop toggling, ret=%d", ret);
goto done;
@@ -771,6 +765,29 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum typec_cc_status cc)
chip->intr_comp_chng = false;
}
fusb302_log(chip, "cc := %s", typec_cc_status_name[cc]);
+
+ /* Enable detection for fixed SNK or SRC only roles */
+ switch (cc) {
+ case TYPEC_CC_RD:
+ mode = TOGGLING_MODE_SNK;
+ break;
+ case TYPEC_CC_RP_DEF:
+ case TYPEC_CC_RP_1_5:
+ case TYPEC_CC_RP_3_0:
+ mode = TOGGLING_MODE_SRC;
+ break;
+ default:
+ mode = TOGGLING_MODE_OFF;
+ break;
+ }
+
+ if (mode != TOGGLING_MODE_OFF) {
+ ret = fusb302_set_toggling(chip, mode);
+ if (ret < 0)
+ fusb302_log(chip,
+ "cannot set fixed role toggling mode, ret=%d",
+ ret);
+ }
done:
mutex_unlock(&chip->lock);
@@ -1178,10 +1195,6 @@ static const u32 src_pdo[] = {
PDO_FIXED(5000, 400, PDO_FIXED_FLAGS),
};
-static const u32 snk_pdo[] = {
- PDO_FIXED(5000, 400, PDO_FIXED_FLAGS),
-};
-
static const struct tcpc_config fusb302_tcpc_config = {
.src_pdo = src_pdo,
.nr_src_pdo = ARRAY_SIZE(src_pdo),
@@ -1303,7 +1316,7 @@ static int fusb302_handle_togdone_snk(struct fusb302_chip *chip,
tcpm_cc_change(chip->tcpm_port);
}
/* turn off toggling */
- ret = fusb302_set_toggling(chip, TOGGLINE_MODE_OFF);
+ ret = fusb302_set_toggling(chip, TOGGLING_MODE_OFF);
if (ret < 0) {
fusb302_log(chip,
"cannot set toggling mode off, ret=%d", ret);
@@ -1399,7 +1412,7 @@ static int fusb302_handle_togdone_src(struct fusb302_chip *chip,
tcpm_cc_change(chip->tcpm_port);
}
/* turn off toggling */
- ret = fusb302_set_toggling(chip, TOGGLINE_MODE_OFF);
+ ret = fusb302_set_toggling(chip, TOGGLING_MODE_OFF);
if (ret < 0) {
fusb302_log(chip,
"cannot set toggling mode off, ret=%d", ret);
@@ -1730,12 +1743,14 @@ static int fusb302_probe(struct i2c_client *client,
return -ENOMEM;
chip->i2c_client = client;
- i2c_set_clientdata(client, chip);
chip->dev = &client->dev;
chip->tcpc_config = fusb302_tcpc_config;
chip->tcpc_dev.config = &chip->tcpc_config;
mutex_init(&chip->lock);
+ chip->tcpc_dev.fwnode =
+ device_get_named_child_node(dev, "connector");
+
if (!device_property_read_u32(dev, "fcs,operating-sink-microwatt", &v))
chip->tcpc_config.operating_snk_mw = v / 1000;
@@ -1756,22 +1771,17 @@ static int fusb302_probe(struct i2c_client *client,
return -EPROBE_DEFER;
}
- fusb302_debugfs_init(chip);
+ chip->vbus = devm_regulator_get(chip->dev, "vbus");
+ if (IS_ERR(chip->vbus))
+ return PTR_ERR(chip->vbus);
chip->wq = create_singlethread_workqueue(dev_name(chip->dev));
- if (!chip->wq) {
- ret = -ENOMEM;
- goto clear_client_data;
- }
+ if (!chip->wq)
+ return -ENOMEM;
+
INIT_DELAYED_WORK(&chip->bc_lvl_handler, fusb302_bc_lvl_handler_work);
init_tcpc_dev(&chip->tcpc_dev);
- chip->vbus = devm_regulator_get(chip->dev, "vbus");
- if (IS_ERR(chip->vbus)) {
- ret = PTR_ERR(chip->vbus);
- goto destroy_workqueue;
- }
-
if (client->irq) {
chip->gpio_int_n_irq = client->irq;
} else {
@@ -1797,15 +1807,15 @@ static int fusb302_probe(struct i2c_client *client,
goto tcpm_unregister_port;
}
enable_irq_wake(chip->gpio_int_n_irq);
+ fusb302_debugfs_init(chip);
+ i2c_set_clientdata(client, chip);
+
return ret;
tcpm_unregister_port:
tcpm_unregister_port(chip->tcpm_port);
destroy_workqueue:
destroy_workqueue(chip->wq);
-clear_client_data:
- i2c_set_clientdata(client, NULL);
- fusb302_debugfs_exit(chip);
return ret;
}
@@ -1816,7 +1826,6 @@ static int fusb302_remove(struct i2c_client *client)
tcpm_unregister_port(chip->tcpm_port);
destroy_workqueue(chip->wq);
- i2c_set_clientdata(client, NULL);
fusb302_debugfs_exit(chip);
return 0;
diff --git a/drivers/usb/typec/fusb302/fusb302_reg.h b/drivers/usb/typec/tcpm/fusb302_reg.h
index 00b39d365478..00b39d365478 100644
--- a/drivers/usb/typec/fusb302/fusb302_reg.h
+++ b/drivers/usb/typec/tcpm/fusb302_reg.h
diff --git a/drivers/usb/typec/tcpci.c b/drivers/usb/typec/tcpm/tcpci.c
index ac6b418b15f1..ac6b418b15f1 100644
--- a/drivers/usb/typec/tcpci.c
+++ b/drivers/usb/typec/tcpm/tcpci.c
diff --git a/drivers/usb/typec/tcpci.h b/drivers/usb/typec/tcpm/tcpci.h
index 303ebde26546..303ebde26546 100644
--- a/drivers/usb/typec/tcpci.h
+++ b/drivers/usb/typec/tcpm/tcpci.h
diff --git a/drivers/usb/typec/tcpci_rt1711h.c b/drivers/usb/typec/tcpm/tcpci_rt1711h.c
index 017389021b96..017389021b96 100644
--- a/drivers/usb/typec/tcpci_rt1711h.c
+++ b/drivers/usb/typec/tcpm/tcpci_rt1711h.c
diff --git a/drivers/usb/typec/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
index 4f1f4215f3d6..dbbd71f754d0 100644
--- a/drivers/usb/typec/tcpm.c
+++ b/drivers/usb/typec/tcpm/tcpm.c
@@ -1430,8 +1430,8 @@ static enum pdo_err tcpm_caps_err(struct tcpm_port *port, const u32 *pdo,
if (pdo_apdo_type(pdo[i]) != APDO_TYPE_PPS)
break;
- if (pdo_pps_apdo_max_current(pdo[i]) <
- pdo_pps_apdo_max_current(pdo[i - 1]))
+ if (pdo_pps_apdo_max_voltage(pdo[i]) <
+ pdo_pps_apdo_max_voltage(pdo[i - 1]))
return PDO_ERR_PPS_APDO_NOT_SORTED;
else if (pdo_pps_apdo_min_voltage(pdo[i]) ==
pdo_pps_apdo_min_voltage(pdo[i - 1]) &&
@@ -2209,7 +2209,7 @@ static unsigned int tcpm_pd_select_pps_apdo(struct tcpm_port *port)
{
unsigned int i, j, max_mw = 0, max_mv = 0;
unsigned int min_src_mv, max_src_mv, src_ma, src_mw;
- unsigned int min_snk_mv, max_snk_mv, snk_ma;
+ unsigned int min_snk_mv, max_snk_mv;
u32 pdo;
unsigned int src_pdo = 0, snk_pdo = 0;
@@ -2253,8 +2253,6 @@ static unsigned int tcpm_pd_select_pps_apdo(struct tcpm_port *port)
pdo_pps_apdo_min_voltage(pdo);
max_snk_mv =
pdo_pps_apdo_max_voltage(pdo);
- snk_ma =
- pdo_pps_apdo_max_current(pdo);
break;
default:
tcpm_log(port,
@@ -2402,7 +2400,7 @@ static int tcpm_pd_send_request(struct tcpm_port *port)
static int tcpm_pd_build_pps_request(struct tcpm_port *port, u32 *rdo)
{
- unsigned int out_mv, op_ma, op_mw, min_mv, max_mv, max_ma, flags;
+ unsigned int out_mv, op_ma, op_mw, max_mv, max_ma, flags;
enum pd_pdo_type type;
unsigned int src_pdo_index;
u32 pdo;
@@ -2420,7 +2418,6 @@ static int tcpm_pd_build_pps_request(struct tcpm_port *port, u32 *rdo)
tcpm_log(port, "Invalid APDO selected!");
return -EINVAL;
}
- min_mv = port->pps_data.min_volt;
max_mv = port->pps_data.max_volt;
max_ma = port->pps_data.max_curr;
out_mv = port->pps_data.out_volt;
@@ -4116,6 +4113,9 @@ static int tcpm_pps_set_op_curr(struct tcpm_port *port, u16 op_curr)
goto port_unlock;
}
+ /* Round down operating current to align with PPS valid steps */
+ op_curr = op_curr - (op_curr % RDO_PROG_CURR_MA_STEP);
+
reinit_completion(&port->pps_complete);
port->pps_data.op_curr = op_curr;
port->pps_status = 0;
@@ -4169,6 +4169,9 @@ static int tcpm_pps_set_out_volt(struct tcpm_port *port, u16 out_volt)
goto port_unlock;
}
+ /* Round down output voltage to align with PPS valid steps */
+ out_volt = out_volt - (out_volt % RDO_PROG_VOLT_MV_STEP);
+
reinit_completion(&port->pps_complete);
port->pps_data.out_volt = out_volt;
port->pps_status = 0;
diff --git a/drivers/usb/typec/typec_wcove.c b/drivers/usb/typec/tcpm/wcove.c
index 423208e19383..423208e19383 100644
--- a/drivers/usb/typec/typec_wcove.c
+++ b/drivers/usb/typec/tcpm/wcove.c
diff --git a/drivers/usb/typec/ucsi/Kconfig b/drivers/usb/typec/ucsi/Kconfig
index e36d6c73c4a4..78118883f96c 100644
--- a/drivers/usb/typec/ucsi/Kconfig
+++ b/drivers/usb/typec/ucsi/Kconfig
@@ -23,6 +23,16 @@ config TYPEC_UCSI
if TYPEC_UCSI
+config UCSI_CCG
+ tristate "UCSI Interface Driver for Cypress CCGx"
+ depends on I2C
+ help
+ This driver enables UCSI support on platforms that expose a
+ Cypress CCGx Type-C controller over I2C interface.
+
+ To compile the driver as a module, choose M here: the module will be
+ called ucsi_ccg.
+
config UCSI_ACPI
tristate "UCSI ACPI Interface Driver"
depends on ACPI
diff --git a/drivers/usb/typec/ucsi/Makefile b/drivers/usb/typec/ucsi/Makefile
index 7afbea512207..2f4900b26210 100644
--- a/drivers/usb/typec/ucsi/Makefile
+++ b/drivers/usb/typec/ucsi/Makefile
@@ -8,3 +8,5 @@ typec_ucsi-y := ucsi.o
typec_ucsi-$(CONFIG_TRACING) += trace.o
obj-$(CONFIG_UCSI_ACPI) += ucsi_acpi.o
+
+obj-$(CONFIG_UCSI_CCG) += ucsi_ccg.o
diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c
new file mode 100644
index 000000000000..de8a43bdff68
--- /dev/null
+++ b/drivers/usb/typec/ucsi/ucsi_ccg.c
@@ -0,0 +1,307 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * UCSI driver for Cypress CCGx Type-C controller
+ *
+ * Copyright (C) 2017-2018 NVIDIA Corporation. All rights reserved.
+ * Author: Ajay Gupta <ajayg@nvidia.com>
+ *
+ * Some code borrowed from drivers/usb/typec/ucsi/ucsi_acpi.c
+ */
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+
+#include <asm/unaligned.h>
+#include "ucsi.h"
+
+struct ucsi_ccg {
+ struct device *dev;
+ struct ucsi *ucsi;
+ struct ucsi_ppm ppm;
+ struct i2c_client *client;
+};
+
+#define CCGX_RAB_INTR_REG 0x06
+#define CCGX_RAB_UCSI_CONTROL 0x39
+#define CCGX_RAB_UCSI_CONTROL_START BIT(0)
+#define CCGX_RAB_UCSI_CONTROL_STOP BIT(1)
+#define CCGX_RAB_UCSI_DATA_BLOCK(offset) (0xf000 | ((offset) & 0xff))
+
+static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
+{
+ struct i2c_client *client = uc->client;
+ const struct i2c_adapter_quirks *quirks = client->adapter->quirks;
+ unsigned char buf[2];
+ struct i2c_msg msgs[] = {
+ {
+ .addr = client->addr,
+ .flags = 0x0,
+ .len = sizeof(buf),
+ .buf = buf,
+ },
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .buf = data,
+ },
+ };
+ u32 rlen, rem_len = len, max_read_len = len;
+ int status;
+
+ /* check any max_read_len limitation on i2c adapter */
+ if (quirks && quirks->max_read_len)
+ max_read_len = quirks->max_read_len;
+
+ while (rem_len > 0) {
+ msgs[1].buf = &data[len - rem_len];
+ rlen = min_t(u16, rem_len, max_read_len);
+ msgs[1].len = rlen;
+ put_unaligned_le16(rab, buf);
+ status = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (status < 0) {
+ dev_err(uc->dev, "i2c_transfer failed %d\n", status);
+ return status;
+ }
+ rab += rlen;
+ rem_len -= rlen;
+ }
+
+ return 0;
+}
+
+static int ccg_write(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
+{
+ struct i2c_client *client = uc->client;
+ unsigned char *buf;
+ struct i2c_msg msgs[] = {
+ {
+ .addr = client->addr,
+ .flags = 0x0,
+ }
+ };
+ int status;
+
+ buf = kzalloc(len + sizeof(rab), GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ put_unaligned_le16(rab, buf);
+ memcpy(buf + sizeof(rab), data, len);
+
+ msgs[0].len = len + sizeof(rab);
+ msgs[0].buf = buf;
+
+ status = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (status < 0) {
+ dev_err(uc->dev, "i2c_transfer failed %d\n", status);
+ kfree(buf);
+ return status;
+ }
+
+ kfree(buf);
+ return 0;
+}
+
+static int ucsi_ccg_init(struct ucsi_ccg *uc)
+{
+ unsigned int count = 10;
+ u8 data;
+ int status;
+
+ data = CCGX_RAB_UCSI_CONTROL_STOP;
+ status = ccg_write(uc, CCGX_RAB_UCSI_CONTROL, &data, sizeof(data));
+ if (status < 0)
+ return status;
+
+ data = CCGX_RAB_UCSI_CONTROL_START;
+ status = ccg_write(uc, CCGX_RAB_UCSI_CONTROL, &data, sizeof(data));
+ if (status < 0)
+ return status;
+
+ /*
+ * Flush CCGx RESPONSE queue by acking interrupts. Above ucsi control
+ * register write will push response which must be cleared.
+ */
+ do {
+ status = ccg_read(uc, CCGX_RAB_INTR_REG, &data, sizeof(data));
+ if (status < 0)
+ return status;
+
+ if (!data)
+ return 0;
+
+ status = ccg_write(uc, CCGX_RAB_INTR_REG, &data, sizeof(data));
+ if (status < 0)
+ return status;
+
+ usleep_range(10000, 11000);
+ } while (--count);
+
+ return -ETIMEDOUT;
+}
+
+static int ucsi_ccg_send_data(struct ucsi_ccg *uc)
+{
+ u8 *ppm = (u8 *)uc->ppm.data;
+ int status;
+ u16 rab;
+
+ rab = CCGX_RAB_UCSI_DATA_BLOCK(offsetof(struct ucsi_data, message_out));
+ status = ccg_write(uc, rab, ppm +
+ offsetof(struct ucsi_data, message_out),
+ sizeof(uc->ppm.data->message_out));
+ if (status < 0)
+ return status;
+
+ rab = CCGX_RAB_UCSI_DATA_BLOCK(offsetof(struct ucsi_data, ctrl));
+ return ccg_write(uc, rab, ppm + offsetof(struct ucsi_data, ctrl),
+ sizeof(uc->ppm.data->ctrl));
+}
+
+static int ucsi_ccg_recv_data(struct ucsi_ccg *uc)
+{
+ u8 *ppm = (u8 *)uc->ppm.data;
+ int status;
+ u16 rab;
+
+ rab = CCGX_RAB_UCSI_DATA_BLOCK(offsetof(struct ucsi_data, cci));
+ status = ccg_read(uc, rab, ppm + offsetof(struct ucsi_data, cci),
+ sizeof(uc->ppm.data->cci));
+ if (status < 0)
+ return status;
+
+ rab = CCGX_RAB_UCSI_DATA_BLOCK(offsetof(struct ucsi_data, message_in));
+ return ccg_read(uc, rab, ppm + offsetof(struct ucsi_data, message_in),
+ sizeof(uc->ppm.data->message_in));
+}
+
+static int ucsi_ccg_ack_interrupt(struct ucsi_ccg *uc)
+{
+ int status;
+ unsigned char data;
+
+ status = ccg_read(uc, CCGX_RAB_INTR_REG, &data, sizeof(data));
+ if (status < 0)
+ return status;
+
+ return ccg_write(uc, CCGX_RAB_INTR_REG, &data, sizeof(data));
+}
+
+static int ucsi_ccg_sync(struct ucsi_ppm *ppm)
+{
+ struct ucsi_ccg *uc = container_of(ppm, struct ucsi_ccg, ppm);
+ int status;
+
+ status = ucsi_ccg_recv_data(uc);
+ if (status < 0)
+ return status;
+
+ /* ack interrupt to allow next command to run */
+ return ucsi_ccg_ack_interrupt(uc);
+}
+
+static int ucsi_ccg_cmd(struct ucsi_ppm *ppm, struct ucsi_control *ctrl)
+{
+ struct ucsi_ccg *uc = container_of(ppm, struct ucsi_ccg, ppm);
+
+ ppm->data->ctrl.raw_cmd = ctrl->raw_cmd;
+ return ucsi_ccg_send_data(uc);
+}
+
+static irqreturn_t ccg_irq_handler(int irq, void *data)
+{
+ struct ucsi_ccg *uc = data;
+
+ ucsi_notify(uc->ucsi);
+
+ return IRQ_HANDLED;
+}
+
+static int ucsi_ccg_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct ucsi_ccg *uc;
+ int status;
+ u16 rab;
+
+ uc = devm_kzalloc(dev, sizeof(*uc), GFP_KERNEL);
+ if (!uc)
+ return -ENOMEM;
+
+ uc->ppm.data = devm_kzalloc(dev, sizeof(struct ucsi_data), GFP_KERNEL);
+ if (!uc->ppm.data)
+ return -ENOMEM;
+
+ uc->ppm.cmd = ucsi_ccg_cmd;
+ uc->ppm.sync = ucsi_ccg_sync;
+ uc->dev = dev;
+ uc->client = client;
+
+ /* reset ccg device and initialize ucsi */
+ status = ucsi_ccg_init(uc);
+ if (status < 0) {
+ dev_err(uc->dev, "ucsi_ccg_init failed - %d\n", status);
+ return status;
+ }
+
+ status = devm_request_threaded_irq(dev, client->irq, NULL,
+ ccg_irq_handler,
+ IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
+ dev_name(dev), uc);
+ if (status < 0) {
+ dev_err(uc->dev, "request_threaded_irq failed - %d\n", status);
+ return status;
+ }
+
+ uc->ucsi = ucsi_register_ppm(dev, &uc->ppm);
+ if (IS_ERR(uc->ucsi)) {
+ dev_err(uc->dev, "ucsi_register_ppm failed\n");
+ return PTR_ERR(uc->ucsi);
+ }
+
+ rab = CCGX_RAB_UCSI_DATA_BLOCK(offsetof(struct ucsi_data, version));
+ status = ccg_read(uc, rab, (u8 *)(uc->ppm.data) +
+ offsetof(struct ucsi_data, version),
+ sizeof(uc->ppm.data->version));
+ if (status < 0) {
+ ucsi_unregister_ppm(uc->ucsi);
+ return status;
+ }
+
+ i2c_set_clientdata(client, uc);
+ return 0;
+}
+
+static int ucsi_ccg_remove(struct i2c_client *client)
+{
+ struct ucsi_ccg *uc = i2c_get_clientdata(client);
+
+ ucsi_unregister_ppm(uc->ucsi);
+
+ return 0;
+}
+
+static const struct i2c_device_id ucsi_ccg_device_id[] = {
+ {"ccgx-ucsi", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, ucsi_ccg_device_id);
+
+static struct i2c_driver ucsi_ccg_driver = {
+ .driver = {
+ .name = "ucsi_ccg",
+ },
+ .probe = ucsi_ccg_probe,
+ .remove = ucsi_ccg_remove,
+ .id_table = ucsi_ccg_device_id,
+};
+
+module_i2c_driver(ucsi_ccg_driver);
+
+MODULE_AUTHOR("Ajay Gupta <ajayg@nvidia.com>");
+MODULE_DESCRIPTION("UCSI driver for Cypress CCGx Type-C controller");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/usbip/usbip_common.c b/drivers/usb/usbip/usbip_common.c
index 9756752c0681..45da3e01c7b0 100644
--- a/drivers/usb/usbip/usbip_common.c
+++ b/drivers/usb/usbip/usbip_common.c
@@ -309,7 +309,7 @@ int usbip_recv(struct socket *sock, void *buf, int size)
if (!sock || !buf || !size)
return -EINVAL;
- iov_iter_kvec(&msg.msg_iter, READ|ITER_KVEC, &iov, 1, size);
+ iov_iter_kvec(&msg.msg_iter, READ, &iov, 1, size);
usbip_dbg_xmit("enter\n");
diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c
index d11f3f8dad40..1e592ec94ba4 100644
--- a/drivers/usb/usbip/vhci_hcd.c
+++ b/drivers/usb/usbip/vhci_hcd.c
@@ -318,8 +318,9 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
struct vhci_hcd *vhci_hcd;
struct vhci *vhci;
int retval = 0;
- int rhport;
+ int rhport = -1;
unsigned long flags;
+ bool invalid_rhport = false;
u32 prev_port_status[VHCI_HC_PORTS];
@@ -334,9 +335,19 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
usbip_dbg_vhci_rh("typeReq %x wValue %x wIndex %x\n", typeReq, wValue,
wIndex);
- if (wIndex > VHCI_HC_PORTS)
- pr_err("invalid port number %d\n", wIndex);
- rhport = wIndex - 1;
+ /*
+ * wIndex can be 0 for some request types (typeReq). rhport is
+ * in valid range when wIndex >= 1 and < VHCI_HC_PORTS.
+ *
+ * Reference port_status[] only with valid rhport when
+ * invalid_rhport is false.
+ */
+ if (wIndex < 1 || wIndex > VHCI_HC_PORTS) {
+ invalid_rhport = true;
+ if (wIndex > VHCI_HC_PORTS)
+ pr_err("invalid port number %d\n", wIndex);
+ } else
+ rhport = wIndex - 1;
vhci_hcd = hcd_to_vhci_hcd(hcd);
vhci = vhci_hcd->vhci;
@@ -345,8 +356,9 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
/* store old status and compare now and old later */
if (usbip_dbg_flag_vhci_rh) {
- memcpy(prev_port_status, vhci_hcd->port_status,
- sizeof(prev_port_status));
+ if (!invalid_rhport)
+ memcpy(prev_port_status, vhci_hcd->port_status,
+ sizeof(prev_port_status));
}
switch (typeReq) {
@@ -354,8 +366,10 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
usbip_dbg_vhci_rh(" ClearHubFeature\n");
break;
case ClearPortFeature:
- if (rhport < 0)
+ if (invalid_rhport) {
+ pr_err("invalid port number %d\n", wIndex);
goto error;
+ }
switch (wValue) {
case USB_PORT_FEAT_SUSPEND:
if (hcd->speed == HCD_USB3) {
@@ -415,9 +429,10 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
break;
case GetPortStatus:
usbip_dbg_vhci_rh(" GetPortStatus port %x\n", wIndex);
- if (wIndex < 1) {
+ if (invalid_rhport) {
pr_err("invalid port number %d\n", wIndex);
retval = -EPIPE;
+ goto error;
}
/* we do not care about resume. */
@@ -513,16 +528,20 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
goto error;
}
- if (rhport < 0)
+ if (invalid_rhport) {
+ pr_err("invalid port number %d\n", wIndex);
goto error;
+ }
vhci_hcd->port_status[rhport] |= USB_PORT_STAT_SUSPEND;
break;
case USB_PORT_FEAT_POWER:
usbip_dbg_vhci_rh(
" SetPortFeature: USB_PORT_FEAT_POWER\n");
- if (rhport < 0)
+ if (invalid_rhport) {
+ pr_err("invalid port number %d\n", wIndex);
goto error;
+ }
if (hcd->speed == HCD_USB3)
vhci_hcd->port_status[rhport] |= USB_SS_PORT_STAT_POWER;
else
@@ -531,8 +550,10 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
case USB_PORT_FEAT_BH_PORT_RESET:
usbip_dbg_vhci_rh(
" SetPortFeature: USB_PORT_FEAT_BH_PORT_RESET\n");
- if (rhport < 0)
+ if (invalid_rhport) {
+ pr_err("invalid port number %d\n", wIndex);
goto error;
+ }
/* Applicable only for USB3.0 hub */
if (hcd->speed != HCD_USB3) {
pr_err("USB_PORT_FEAT_BH_PORT_RESET req not "
@@ -543,8 +564,10 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
case USB_PORT_FEAT_RESET:
usbip_dbg_vhci_rh(
" SetPortFeature: USB_PORT_FEAT_RESET\n");
- if (rhport < 0)
+ if (invalid_rhport) {
+ pr_err("invalid port number %d\n", wIndex);
goto error;
+ }
/* if it's already enabled, disable */
if (hcd->speed == HCD_USB3) {
vhci_hcd->port_status[rhport] = 0;
@@ -565,8 +588,10 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
default:
usbip_dbg_vhci_rh(" SetPortFeature: default %d\n",
wValue);
- if (rhport < 0)
+ if (invalid_rhport) {
+ pr_err("invalid port number %d\n", wIndex);
goto error;
+ }
if (hcd->speed == HCD_USB3) {
if ((vhci_hcd->port_status[rhport] &
USB_SS_PORT_STAT_POWER) != 0) {
@@ -608,7 +633,7 @@ error:
if (usbip_dbg_flag_vhci_rh) {
pr_debug("port %d\n", rhport);
/* Only dump valid port status */
- if (rhport >= 0) {
+ if (!invalid_rhport) {
dump_port_status_diff(prev_port_status[rhport],
vhci_hcd->port_status[rhport],
hcd->speed == HCD_USB3);
@@ -618,8 +643,10 @@ error:
spin_unlock_irqrestore(&vhci->lock, flags);
- if ((vhci_hcd->port_status[rhport] & PORT_C_MASK) != 0)
+ if (!invalid_rhport &&
+ (vhci_hcd->port_status[rhport] & PORT_C_MASK) != 0) {
usb_hcd_poll_rh_status(hcd);
+ }
return retval;
}
diff --git a/drivers/usb/usbip/vudc_main.c b/drivers/usb/usbip/vudc_main.c
index 3fc22037a82f..390733e6937e 100644
--- a/drivers/usb/usbip/vudc_main.c
+++ b/drivers/usb/usbip/vudc_main.c
@@ -73,6 +73,10 @@ static int __init init(void)
cleanup:
list_for_each_entry_safe(udc_dev, udc_dev2, &vudc_devices, dev_entry) {
list_del(&udc_dev->dev_entry);
+ /*
+ * Just do platform_device_del() here, put_vudc_device()
+ * calls the platform_device_put()
+ */
platform_device_del(udc_dev->pdev);
put_vudc_device(udc_dev);
}
@@ -89,7 +93,11 @@ static void __exit cleanup(void)
list_for_each_entry_safe(udc_dev, udc_dev2, &vudc_devices, dev_entry) {
list_del(&udc_dev->dev_entry);
- platform_device_unregister(udc_dev->pdev);
+ /*
+ * Just do platform_device_del() here, put_vudc_device()
+ * calls the platform_device_put()
+ */
+ platform_device_del(udc_dev->pdev);
put_vudc_device(udc_dev);
}
platform_driver_unregister(&vudc_driver);
diff --git a/drivers/usb/wusbcore/crypto.c b/drivers/usb/wusbcore/crypto.c
index aff50eb09ca9..68ddee86a886 100644
--- a/drivers/usb/wusbcore/crypto.c
+++ b/drivers/usb/wusbcore/crypto.c
@@ -189,7 +189,7 @@ struct wusb_mac_scratch {
* NOTE: blen is not aligned to a block size, we'll pad zeros, that's
* what sg[4] is for. Maybe there is a smarter way to do this.
*/
-static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc,
+static int wusb_ccm_mac(struct crypto_sync_skcipher *tfm_cbc,
struct crypto_cipher *tfm_aes,
struct wusb_mac_scratch *scratch,
void *mic,
@@ -198,7 +198,7 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc,
size_t blen)
{
int result = 0;
- SKCIPHER_REQUEST_ON_STACK(req, tfm_cbc);
+ SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm_cbc);
struct scatterlist sg[4], sg_dst;
void *dst_buf;
size_t dst_size;
@@ -224,7 +224,7 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc,
if (!dst_buf)
goto error_dst_buf;
- iv = kzalloc(crypto_skcipher_ivsize(tfm_cbc), GFP_KERNEL);
+ iv = kzalloc(crypto_sync_skcipher_ivsize(tfm_cbc), GFP_KERNEL);
if (!iv)
goto error_iv;
@@ -251,7 +251,7 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc,
sg_set_page(&sg[3], ZERO_PAGE(0), zero_padding, 0);
sg_init_one(&sg_dst, dst_buf, dst_size);
- skcipher_request_set_tfm(req, tfm_cbc);
+ skcipher_request_set_sync_tfm(req, tfm_cbc);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, sg, &sg_dst, dst_size, iv);
result = crypto_skcipher_encrypt(req);
@@ -298,19 +298,19 @@ ssize_t wusb_prf(void *out, size_t out_size,
{
ssize_t result, bytes = 0, bitr;
struct aes_ccm_nonce n = *_n;
- struct crypto_skcipher *tfm_cbc;
+ struct crypto_sync_skcipher *tfm_cbc;
struct crypto_cipher *tfm_aes;
struct wusb_mac_scratch *scratch;
u64 sfn = 0;
__le64 sfn_le;
- tfm_cbc = crypto_alloc_skcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
+ tfm_cbc = crypto_alloc_sync_skcipher("cbc(aes)", 0, 0);
if (IS_ERR(tfm_cbc)) {
result = PTR_ERR(tfm_cbc);
printk(KERN_ERR "E: can't load CBC(AES): %d\n", (int)result);
goto error_alloc_cbc;
}
- result = crypto_skcipher_setkey(tfm_cbc, key, 16);
+ result = crypto_sync_skcipher_setkey(tfm_cbc, key, 16);
if (result < 0) {
printk(KERN_ERR "E: can't set CBC key: %d\n", (int)result);
goto error_setkey_cbc;
@@ -351,7 +351,7 @@ error_setkey_aes:
crypto_free_cipher(tfm_aes);
error_alloc_aes:
error_setkey_cbc:
- crypto_free_skcipher(tfm_cbc);
+ crypto_free_sync_skcipher(tfm_cbc);
error_alloc_cbc:
return result;
}
diff --git a/drivers/usb/wusbcore/wa-rpipe.c b/drivers/usb/wusbcore/wa-rpipe.c
index 38884aac862b..a5734cbcd5ad 100644
--- a/drivers/usb/wusbcore/wa-rpipe.c
+++ b/drivers/usb/wusbcore/wa-rpipe.c
@@ -470,9 +470,7 @@ error:
int wa_rpipes_create(struct wahc *wa)
{
wa->rpipes = le16_to_cpu(wa->wa_descr->wNumRPipes);
- wa->rpipe_bm = kcalloc(BITS_TO_LONGS(wa->rpipes),
- sizeof(unsigned long),
- GFP_KERNEL);
+ wa->rpipe_bm = bitmap_zalloc(wa->rpipes, GFP_KERNEL);
if (wa->rpipe_bm == NULL)
return -ENOMEM;
return 0;
@@ -487,7 +485,7 @@ void wa_rpipes_destroy(struct wahc *wa)
dev_err(dev, "BUG: pipes not released on exit: %*pb\n",
wa->rpipes, wa->rpipe_bm);
}
- kfree(wa->rpipe_bm);
+ bitmap_free(wa->rpipe_bm);
}
/*
diff --git a/drivers/vfio/Kconfig b/drivers/vfio/Kconfig
index c84333eb5eb5..9de5ed38da83 100644
--- a/drivers/vfio/Kconfig
+++ b/drivers/vfio/Kconfig
@@ -21,7 +21,7 @@ config VFIO_VIRQFD
menuconfig VFIO
tristate "VFIO Non-Privileged userspace driver framework"
depends on IOMMU_API
- select VFIO_IOMMU_TYPE1 if (X86 || S390 || ARM_SMMU || ARM_SMMU_V3)
+ select VFIO_IOMMU_TYPE1 if (X86 || S390 || ARM || ARM64)
select ANON_INODES
help
VFIO provides a framework for secure userspace device drivers.
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
index cddb453a1ba5..50cdedfca9fe 100644
--- a/drivers/vfio/pci/vfio_pci.c
+++ b/drivers/vfio/pci/vfio_pci.c
@@ -434,10 +434,14 @@ static int vfio_pci_get_irq_count(struct vfio_pci_device *vdev, int irq_type)
{
if (irq_type == VFIO_PCI_INTX_IRQ_INDEX) {
u8 pin;
+
+ if (!IS_ENABLED(CONFIG_VFIO_PCI_INTX) ||
+ vdev->nointx || vdev->pdev->is_virtfn)
+ return 0;
+
pci_read_config_byte(vdev->pdev, PCI_INTERRUPT_PIN, &pin);
- if (IS_ENABLED(CONFIG_VFIO_PCI_INTX) && !vdev->nointx && pin)
- return 1;
+ return pin ? 1 : 0;
} else if (irq_type == VFIO_PCI_MSI_IRQ_INDEX) {
u8 pos;
u16 flags;
diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c
index 115a36f6f403..423ea1f98441 100644
--- a/drivers/vfio/pci/vfio_pci_config.c
+++ b/drivers/vfio/pci/vfio_pci_config.c
@@ -1180,8 +1180,10 @@ static int vfio_msi_cap_len(struct vfio_pci_device *vdev, u8 pos)
return -ENOMEM;
ret = init_pci_cap_msi_perm(vdev->msi_perm, len, flags);
- if (ret)
+ if (ret) {
+ kfree(vdev->msi_perm);
return ret;
+ }
return len;
}
@@ -1610,6 +1612,15 @@ static int vfio_ecap_init(struct vfio_pci_device *vdev)
}
/*
+ * Nag about hardware bugs, hopefully to have vendors fix them, but at least
+ * to collect a list of dependencies for the VF INTx pin quirk below.
+ */
+static const struct pci_device_id known_bogus_vf_intx_pin[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x270c) },
+ {}
+};
+
+/*
* For each device we allocate a pci_config_map that indicates the
* capability occupying each dword and thus the struct perm_bits we
* use for read and write. We also allocate a virtualized config
@@ -1674,6 +1685,24 @@ int vfio_config_init(struct vfio_pci_device *vdev)
if (pdev->is_virtfn) {
*(__le16 *)&vconfig[PCI_VENDOR_ID] = cpu_to_le16(pdev->vendor);
*(__le16 *)&vconfig[PCI_DEVICE_ID] = cpu_to_le16(pdev->device);
+
+ /*
+ * Per SR-IOV spec rev 1.1, 3.4.1.18 the interrupt pin register
+ * does not apply to VFs and VFs must implement this register
+ * as read-only with value zero. Userspace is not readily able
+ * to identify whether a device is a VF and thus that the pin
+ * definition on the device is bogus should it violate this
+ * requirement. We already virtualize the pin register for
+ * other purposes, so we simply need to replace the bogus value
+ * and consider VFs when we determine INTx IRQ count.
+ */
+ if (vconfig[PCI_INTERRUPT_PIN] &&
+ !pci_match_id(known_bogus_vf_intx_pin, pdev))
+ pci_warn(pdev,
+ "Hardware bug: VF reports bogus INTx pin %d\n",
+ vconfig[PCI_INTERRUPT_PIN]);
+
+ vconfig[PCI_INTERRUPT_PIN] = 0; /* Gratuitous for good VFs */
}
if (!IS_ENABLED(CONFIG_VFIO_PCI_INTX) || vdev->nointx)
diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c
index 96721b154454..b30926e11d87 100644
--- a/drivers/vfio/vfio_iommu_spapr_tce.c
+++ b/drivers/vfio/vfio_iommu_spapr_tce.c
@@ -444,7 +444,7 @@ static void tce_iommu_unuse_page_v2(struct tce_container *container,
struct mm_iommu_table_group_mem_t *mem = NULL;
int ret;
unsigned long hpa = 0;
- __be64 *pua = IOMMU_TABLE_USERSPACE_ENTRY(tbl, entry);
+ __be64 *pua = IOMMU_TABLE_USERSPACE_ENTRY_RO(tbl, entry);
if (!pua)
return;
@@ -467,8 +467,27 @@ static int tce_iommu_clear(struct tce_container *container,
unsigned long oldhpa;
long ret;
enum dma_data_direction direction;
+ unsigned long lastentry = entry + pages;
+
+ for ( ; entry < lastentry; ++entry) {
+ if (tbl->it_indirect_levels && tbl->it_userspace) {
+ /*
+ * For multilevel tables, we can take a shortcut here
+ * and skip some TCEs as we know that the userspace
+ * addresses cache is a mirror of the real TCE table
+ * and if it is missing some indirect levels, then
+ * the hardware table does not have them allocated
+ * either and therefore does not require updating.
+ */
+ __be64 *pua = IOMMU_TABLE_USERSPACE_ENTRY_RO(tbl,
+ entry);
+ if (!pua) {
+ /* align to level_size which is power of two */
+ entry |= tbl->it_level_size - 1;
+ continue;
+ }
+ }
- for ( ; pages; --pages, ++entry) {
cond_resched();
direction = DMA_NONE;
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index 4e656f89cb22..ab11b2bee273 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -116,6 +116,8 @@ struct vhost_net_virtqueue {
* For RX, number of batched heads
*/
int done_idx;
+ /* Number of XDP frames batched */
+ int batched_xdp;
/* an array of userspace buffers info */
struct ubuf_info *ubuf_info;
/* Reference counting for outstanding ubufs.
@@ -123,6 +125,8 @@ struct vhost_net_virtqueue {
struct vhost_net_ubuf_ref *ubufs;
struct ptr_ring *rx_ring;
struct vhost_net_buf rxq;
+ /* Batched XDP buffs */
+ struct xdp_buff *xdp;
};
struct vhost_net {
@@ -338,6 +342,11 @@ static bool vhost_sock_zcopy(struct socket *sock)
sock_flag(sock->sk, SOCK_ZEROCOPY);
}
+static bool vhost_sock_xdp(struct socket *sock)
+{
+ return sock_flag(sock->sk, SOCK_XDP);
+}
+
/* In case of DMA done not in order in lower device driver for some reason.
* upend_idx is used to track end of used idx, done_idx is used to track head
* of used idx. Once lower device DMA done contiguously, we will signal KVM
@@ -444,32 +453,120 @@ static void vhost_net_signal_used(struct vhost_net_virtqueue *nvq)
nvq->done_idx = 0;
}
+static void vhost_tx_batch(struct vhost_net *net,
+ struct vhost_net_virtqueue *nvq,
+ struct socket *sock,
+ struct msghdr *msghdr)
+{
+ struct tun_msg_ctl ctl = {
+ .type = TUN_MSG_PTR,
+ .num = nvq->batched_xdp,
+ .ptr = nvq->xdp,
+ };
+ int err;
+
+ if (nvq->batched_xdp == 0)
+ goto signal_used;
+
+ msghdr->msg_control = &ctl;
+ err = sock->ops->sendmsg(sock, msghdr, 0);
+ if (unlikely(err < 0)) {
+ vq_err(&nvq->vq, "Fail to batch sending packets\n");
+ return;
+ }
+
+signal_used:
+ vhost_net_signal_used(nvq);
+ nvq->batched_xdp = 0;
+}
+
+static int sock_has_rx_data(struct socket *sock)
+{
+ if (unlikely(!sock))
+ return 0;
+
+ if (sock->ops->peek_len)
+ return sock->ops->peek_len(sock);
+
+ return skb_queue_empty(&sock->sk->sk_receive_queue);
+}
+
+static void vhost_net_busy_poll_try_queue(struct vhost_net *net,
+ struct vhost_virtqueue *vq)
+{
+ if (!vhost_vq_avail_empty(&net->dev, vq)) {
+ vhost_poll_queue(&vq->poll);
+ } else if (unlikely(vhost_enable_notify(&net->dev, vq))) {
+ vhost_disable_notify(&net->dev, vq);
+ vhost_poll_queue(&vq->poll);
+ }
+}
+
+static void vhost_net_busy_poll(struct vhost_net *net,
+ struct vhost_virtqueue *rvq,
+ struct vhost_virtqueue *tvq,
+ bool *busyloop_intr,
+ bool poll_rx)
+{
+ unsigned long busyloop_timeout;
+ unsigned long endtime;
+ struct socket *sock;
+ struct vhost_virtqueue *vq = poll_rx ? tvq : rvq;
+
+ mutex_lock_nested(&vq->mutex, poll_rx ? VHOST_NET_VQ_TX: VHOST_NET_VQ_RX);
+ vhost_disable_notify(&net->dev, vq);
+ sock = rvq->private_data;
+
+ busyloop_timeout = poll_rx ? rvq->busyloop_timeout:
+ tvq->busyloop_timeout;
+
+ preempt_disable();
+ endtime = busy_clock() + busyloop_timeout;
+
+ while (vhost_can_busy_poll(endtime)) {
+ if (vhost_has_work(&net->dev)) {
+ *busyloop_intr = true;
+ break;
+ }
+
+ if ((sock_has_rx_data(sock) &&
+ !vhost_vq_avail_empty(&net->dev, rvq)) ||
+ !vhost_vq_avail_empty(&net->dev, tvq))
+ break;
+
+ cpu_relax();
+ }
+
+ preempt_enable();
+
+ if (poll_rx || sock_has_rx_data(sock))
+ vhost_net_busy_poll_try_queue(net, vq);
+ else if (!poll_rx) /* On tx here, sock has no rx data. */
+ vhost_enable_notify(&net->dev, rvq);
+
+ mutex_unlock(&vq->mutex);
+}
+
static int vhost_net_tx_get_vq_desc(struct vhost_net *net,
- struct vhost_net_virtqueue *nvq,
+ struct vhost_net_virtqueue *tnvq,
unsigned int *out_num, unsigned int *in_num,
- bool *busyloop_intr)
+ struct msghdr *msghdr, bool *busyloop_intr)
{
- struct vhost_virtqueue *vq = &nvq->vq;
- unsigned long uninitialized_var(endtime);
- int r = vhost_get_vq_desc(vq, vq->iov, ARRAY_SIZE(vq->iov),
+ struct vhost_net_virtqueue *rnvq = &net->vqs[VHOST_NET_VQ_RX];
+ struct vhost_virtqueue *rvq = &rnvq->vq;
+ struct vhost_virtqueue *tvq = &tnvq->vq;
+
+ int r = vhost_get_vq_desc(tvq, tvq->iov, ARRAY_SIZE(tvq->iov),
out_num, in_num, NULL, NULL);
- if (r == vq->num && vq->busyloop_timeout) {
- if (!vhost_sock_zcopy(vq->private_data))
- vhost_net_signal_used(nvq);
- preempt_disable();
- endtime = busy_clock() + vq->busyloop_timeout;
- while (vhost_can_busy_poll(endtime)) {
- if (vhost_has_work(vq->dev)) {
- *busyloop_intr = true;
- break;
- }
- if (!vhost_vq_avail_empty(vq->dev, vq))
- break;
- cpu_relax();
- }
- preempt_enable();
- r = vhost_get_vq_desc(vq, vq->iov, ARRAY_SIZE(vq->iov),
+ if (r == tvq->num && tvq->busyloop_timeout) {
+ /* Flush batched packets first */
+ if (!vhost_sock_zcopy(tvq->private_data))
+ vhost_tx_batch(net, tnvq, tvq->private_data, msghdr);
+
+ vhost_net_busy_poll(net, rvq, tvq, busyloop_intr, false);
+
+ r = vhost_get_vq_desc(tvq, tvq->iov, ARRAY_SIZE(tvq->iov),
out_num, in_num, NULL, NULL);
}
@@ -512,7 +609,7 @@ static int get_tx_bufs(struct vhost_net *net,
struct vhost_virtqueue *vq = &nvq->vq;
int ret;
- ret = vhost_net_tx_get_vq_desc(net, nvq, out, in, busyloop_intr);
+ ret = vhost_net_tx_get_vq_desc(net, nvq, out, in, msg, busyloop_intr);
if (ret < 0 || ret == vq->num)
return ret;
@@ -540,6 +637,80 @@ static bool tx_can_batch(struct vhost_virtqueue *vq, size_t total_len)
!vhost_vq_avail_empty(vq->dev, vq);
}
+#define VHOST_NET_RX_PAD (NET_IP_ALIGN + NET_SKB_PAD)
+
+static int vhost_net_build_xdp(struct vhost_net_virtqueue *nvq,
+ struct iov_iter *from)
+{
+ struct vhost_virtqueue *vq = &nvq->vq;
+ struct socket *sock = vq->private_data;
+ struct page_frag *alloc_frag = &current->task_frag;
+ struct virtio_net_hdr *gso;
+ struct xdp_buff *xdp = &nvq->xdp[nvq->batched_xdp];
+ struct tun_xdp_hdr *hdr;
+ size_t len = iov_iter_count(from);
+ int headroom = vhost_sock_xdp(sock) ? XDP_PACKET_HEADROOM : 0;
+ int buflen = SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+ int pad = SKB_DATA_ALIGN(VHOST_NET_RX_PAD + headroom + nvq->sock_hlen);
+ int sock_hlen = nvq->sock_hlen;
+ void *buf;
+ int copied;
+
+ if (unlikely(len < nvq->sock_hlen))
+ return -EFAULT;
+
+ if (SKB_DATA_ALIGN(len + pad) +
+ SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) > PAGE_SIZE)
+ return -ENOSPC;
+
+ buflen += SKB_DATA_ALIGN(len + pad);
+ alloc_frag->offset = ALIGN((u64)alloc_frag->offset, SMP_CACHE_BYTES);
+ if (unlikely(!skb_page_frag_refill(buflen, alloc_frag, GFP_KERNEL)))
+ return -ENOMEM;
+
+ buf = (char *)page_address(alloc_frag->page) + alloc_frag->offset;
+ copied = copy_page_from_iter(alloc_frag->page,
+ alloc_frag->offset +
+ offsetof(struct tun_xdp_hdr, gso),
+ sock_hlen, from);
+ if (copied != sock_hlen)
+ return -EFAULT;
+
+ hdr = buf;
+ gso = &hdr->gso;
+
+ if ((gso->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) &&
+ vhost16_to_cpu(vq, gso->csum_start) +
+ vhost16_to_cpu(vq, gso->csum_offset) + 2 >
+ vhost16_to_cpu(vq, gso->hdr_len)) {
+ gso->hdr_len = cpu_to_vhost16(vq,
+ vhost16_to_cpu(vq, gso->csum_start) +
+ vhost16_to_cpu(vq, gso->csum_offset) + 2);
+
+ if (vhost16_to_cpu(vq, gso->hdr_len) > len)
+ return -EINVAL;
+ }
+
+ len -= sock_hlen;
+ copied = copy_page_from_iter(alloc_frag->page,
+ alloc_frag->offset + pad,
+ len, from);
+ if (copied != len)
+ return -EFAULT;
+
+ xdp->data_hard_start = buf;
+ xdp->data = buf + pad;
+ xdp->data_end = xdp->data + len;
+ hdr->buflen = buflen;
+
+ get_page(alloc_frag->page);
+ alloc_frag->offset += buflen;
+
+ ++nvq->batched_xdp;
+
+ return 0;
+}
+
static void handle_tx_copy(struct vhost_net *net, struct socket *sock)
{
struct vhost_net_virtqueue *nvq = &net->vqs[VHOST_NET_VQ_TX];
@@ -556,10 +727,14 @@ static void handle_tx_copy(struct vhost_net *net, struct socket *sock)
size_t len, total_len = 0;
int err;
int sent_pkts = 0;
+ bool sock_can_batch = (sock->sk->sk_sndbuf == INT_MAX);
for (;;) {
bool busyloop_intr = false;
+ if (nvq->done_idx == VHOST_NET_BATCH)
+ vhost_tx_batch(net, nvq, sock, &msg);
+
head = get_tx_bufs(net, nvq, &msg, &out, &in, &len,
&busyloop_intr);
/* On error, stop handling until the next kick. */
@@ -577,14 +752,34 @@ static void handle_tx_copy(struct vhost_net *net, struct socket *sock)
break;
}
- vq->heads[nvq->done_idx].id = cpu_to_vhost32(vq, head);
- vq->heads[nvq->done_idx].len = 0;
-
total_len += len;
- if (tx_can_batch(vq, total_len))
- msg.msg_flags |= MSG_MORE;
- else
- msg.msg_flags &= ~MSG_MORE;
+
+ /* For simplicity, TX batching is only enabled if
+ * sndbuf is unlimited.
+ */
+ if (sock_can_batch) {
+ err = vhost_net_build_xdp(nvq, &msg.msg_iter);
+ if (!err) {
+ goto done;
+ } else if (unlikely(err != -ENOSPC)) {
+ vhost_tx_batch(net, nvq, sock, &msg);
+ vhost_discard_vq_desc(vq, 1);
+ vhost_net_enable_vq(net, vq);
+ break;
+ }
+
+ /* We can't build XDP buff, go for single
+ * packet path but let's flush batched
+ * packets.
+ */
+ vhost_tx_batch(net, nvq, sock, &msg);
+ msg.msg_control = NULL;
+ } else {
+ if (tx_can_batch(vq, total_len))
+ msg.msg_flags |= MSG_MORE;
+ else
+ msg.msg_flags &= ~MSG_MORE;
+ }
/* TODO: Check specific error and bomb out unless ENOBUFS? */
err = sock->ops->sendmsg(sock, &msg, len);
@@ -596,15 +791,17 @@ static void handle_tx_copy(struct vhost_net *net, struct socket *sock)
if (err != len)
pr_debug("Truncated TX packet: len %d != %zd\n",
err, len);
- if (++nvq->done_idx >= VHOST_NET_BATCH)
- vhost_net_signal_used(nvq);
+done:
+ vq->heads[nvq->done_idx].id = cpu_to_vhost32(vq, head);
+ vq->heads[nvq->done_idx].len = 0;
+ ++nvq->done_idx;
if (vhost_exceeds_weight(++sent_pkts, total_len)) {
vhost_poll_queue(&vq->poll);
break;
}
}
- vhost_net_signal_used(nvq);
+ vhost_tx_batch(net, nvq, sock, &msg);
}
static void handle_tx_zerocopy(struct vhost_net *net, struct socket *sock)
@@ -620,6 +817,7 @@ static void handle_tx_zerocopy(struct vhost_net *net, struct socket *sock)
.msg_controllen = 0,
.msg_flags = MSG_DONTWAIT,
};
+ struct tun_msg_ctl ctl;
size_t len, total_len = 0;
int err;
struct vhost_net_ubuf_ref *uninitialized_var(ubufs);
@@ -664,8 +862,10 @@ static void handle_tx_zerocopy(struct vhost_net *net, struct socket *sock)
ubuf->ctx = nvq->ubufs;
ubuf->desc = nvq->upend_idx;
refcount_set(&ubuf->refcnt, 1);
- msg.msg_control = ubuf;
- msg.msg_controllen = sizeof(ubuf);
+ msg.msg_control = &ctl;
+ ctl.type = TUN_MSG_UBUF;
+ ctl.ptr = ubuf;
+ msg.msg_controllen = sizeof(ctl);
ubufs = nvq->ubufs;
atomic_inc(&ubufs->refcount);
nvq->upend_idx = (nvq->upend_idx + 1) % UIO_MAXIOV;
@@ -716,7 +916,7 @@ static void handle_tx(struct vhost_net *net)
struct vhost_virtqueue *vq = &nvq->vq;
struct socket *sock;
- mutex_lock(&vq->mutex);
+ mutex_lock_nested(&vq->mutex, VHOST_NET_VQ_TX);
sock = vq->private_data;
if (!sock)
goto out;
@@ -757,16 +957,6 @@ static int peek_head_len(struct vhost_net_virtqueue *rvq, struct sock *sk)
return len;
}
-static int sk_has_rx_data(struct sock *sk)
-{
- struct socket *sock = sk->sk_socket;
-
- if (sock->ops->peek_len)
- return sock->ops->peek_len(sock);
-
- return skb_queue_empty(&sk->sk_receive_queue);
-}
-
static int vhost_net_rx_peek_head_len(struct vhost_net *net, struct sock *sk,
bool *busyloop_intr)
{
@@ -774,41 +964,13 @@ static int vhost_net_rx_peek_head_len(struct vhost_net *net, struct sock *sk,
struct vhost_net_virtqueue *tnvq = &net->vqs[VHOST_NET_VQ_TX];
struct vhost_virtqueue *rvq = &rnvq->vq;
struct vhost_virtqueue *tvq = &tnvq->vq;
- unsigned long uninitialized_var(endtime);
int len = peek_head_len(rnvq, sk);
- if (!len && tvq->busyloop_timeout) {
+ if (!len && rvq->busyloop_timeout) {
/* Flush batched heads first */
vhost_net_signal_used(rnvq);
/* Both tx vq and rx socket were polled here */
- mutex_lock_nested(&tvq->mutex, 1);
- vhost_disable_notify(&net->dev, tvq);
-
- preempt_disable();
- endtime = busy_clock() + tvq->busyloop_timeout;
-
- while (vhost_can_busy_poll(endtime)) {
- if (vhost_has_work(&net->dev)) {
- *busyloop_intr = true;
- break;
- }
- if ((sk_has_rx_data(sk) &&
- !vhost_vq_avail_empty(&net->dev, rvq)) ||
- !vhost_vq_avail_empty(&net->dev, tvq))
- break;
- cpu_relax();
- }
-
- preempt_enable();
-
- if (!vhost_vq_avail_empty(&net->dev, tvq)) {
- vhost_poll_queue(&tvq->poll);
- } else if (unlikely(vhost_enable_notify(&net->dev, tvq))) {
- vhost_disable_notify(&net->dev, tvq);
- vhost_poll_queue(&tvq->poll);
- }
-
- mutex_unlock(&tvq->mutex);
+ vhost_net_busy_poll(net, rvq, tvq, busyloop_intr, true);
len = peek_head_len(rnvq, sk);
}
@@ -923,7 +1085,7 @@ static void handle_rx(struct vhost_net *net)
__virtio16 num_buffers;
int recv_pkts = 0;
- mutex_lock_nested(&vq->mutex, 0);
+ mutex_lock_nested(&vq->mutex, VHOST_NET_VQ_RX);
sock = vq->private_data;
if (!sock)
goto out;
@@ -1078,6 +1240,7 @@ static int vhost_net_open(struct inode *inode, struct file *f)
struct vhost_dev *dev;
struct vhost_virtqueue **vqs;
void **queue;
+ struct xdp_buff *xdp;
int i;
n = kvmalloc(sizeof *n, GFP_KERNEL | __GFP_RETRY_MAYFAIL);
@@ -1098,6 +1261,15 @@ static int vhost_net_open(struct inode *inode, struct file *f)
}
n->vqs[VHOST_NET_VQ_RX].rxq.queue = queue;
+ xdp = kmalloc_array(VHOST_NET_BATCH, sizeof(*xdp), GFP_KERNEL);
+ if (!xdp) {
+ kfree(vqs);
+ kvfree(n);
+ kfree(queue);
+ return -ENOMEM;
+ }
+ n->vqs[VHOST_NET_VQ_TX].xdp = xdp;
+
dev = &n->dev;
vqs[VHOST_NET_VQ_TX] = &n->vqs[VHOST_NET_VQ_TX].vq;
vqs[VHOST_NET_VQ_RX] = &n->vqs[VHOST_NET_VQ_RX].vq;
@@ -1108,6 +1280,7 @@ static int vhost_net_open(struct inode *inode, struct file *f)
n->vqs[i].ubuf_info = NULL;
n->vqs[i].upend_idx = 0;
n->vqs[i].done_idx = 0;
+ n->vqs[i].batched_xdp = 0;
n->vqs[i].vhost_hlen = 0;
n->vqs[i].sock_hlen = 0;
n->vqs[i].rx_ring = NULL;
@@ -1191,6 +1364,7 @@ static int vhost_net_release(struct inode *inode, struct file *f)
* since jobs can re-queue themselves. */
vhost_net_flush(n);
kfree(n->vqs[VHOST_NET_VQ_RX].rxq.queue);
+ kfree(n->vqs[VHOST_NET_VQ_TX].xdp);
kfree(n->dev.vqs);
kvfree(n);
return 0;
diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c
index c24bb690680b..50dffe83714c 100644
--- a/drivers/vhost/scsi.c
+++ b/drivers/vhost/scsi.c
@@ -203,6 +203,19 @@ struct vhost_scsi {
int vs_events_nr; /* num of pending events, protected by vq->mutex */
};
+/*
+ * Context for processing request and control queue operations.
+ */
+struct vhost_scsi_ctx {
+ int head;
+ unsigned int out, in;
+ size_t req_size, rsp_size;
+ size_t out_size, in_size;
+ u8 *target, *lunp;
+ void *req;
+ struct iov_iter out_iter;
+};
+
static struct workqueue_struct *vhost_scsi_workqueue;
/* Global spinlock to protect vhost_scsi TPG list for vhost IOCTL access */
@@ -800,24 +813,120 @@ vhost_scsi_send_bad_target(struct vhost_scsi *vs,
pr_err("Faulted on virtio_scsi_cmd_resp\n");
}
+static int
+vhost_scsi_get_desc(struct vhost_scsi *vs, struct vhost_virtqueue *vq,
+ struct vhost_scsi_ctx *vc)
+{
+ int ret = -ENXIO;
+
+ vc->head = vhost_get_vq_desc(vq, vq->iov,
+ ARRAY_SIZE(vq->iov), &vc->out, &vc->in,
+ NULL, NULL);
+
+ pr_debug("vhost_get_vq_desc: head: %d, out: %u in: %u\n",
+ vc->head, vc->out, vc->in);
+
+ /* On error, stop handling until the next kick. */
+ if (unlikely(vc->head < 0))
+ goto done;
+
+ /* Nothing new? Wait for eventfd to tell us they refilled. */
+ if (vc->head == vq->num) {
+ if (unlikely(vhost_enable_notify(&vs->dev, vq))) {
+ vhost_disable_notify(&vs->dev, vq);
+ ret = -EAGAIN;
+ }
+ goto done;
+ }
+
+ /*
+ * Get the size of request and response buffers.
+ * FIXME: Not correct for BIDI operation
+ */
+ vc->out_size = iov_length(vq->iov, vc->out);
+ vc->in_size = iov_length(&vq->iov[vc->out], vc->in);
+
+ /*
+ * Copy over the virtio-scsi request header, which for a
+ * ANY_LAYOUT enabled guest may span multiple iovecs, or a
+ * single iovec may contain both the header + outgoing
+ * WRITE payloads.
+ *
+ * copy_from_iter() will advance out_iter, so that it will
+ * point at the start of the outgoing WRITE payload, if
+ * DMA_TO_DEVICE is set.
+ */
+ iov_iter_init(&vc->out_iter, WRITE, vq->iov, vc->out, vc->out_size);
+ ret = 0;
+
+done:
+ return ret;
+}
+
+static int
+vhost_scsi_chk_size(struct vhost_virtqueue *vq, struct vhost_scsi_ctx *vc)
+{
+ if (unlikely(vc->in_size < vc->rsp_size)) {
+ vq_err(vq,
+ "Response buf too small, need min %zu bytes got %zu",
+ vc->rsp_size, vc->in_size);
+ return -EINVAL;
+ } else if (unlikely(vc->out_size < vc->req_size)) {
+ vq_err(vq,
+ "Request buf too small, need min %zu bytes got %zu",
+ vc->req_size, vc->out_size);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int
+vhost_scsi_get_req(struct vhost_virtqueue *vq, struct vhost_scsi_ctx *vc,
+ struct vhost_scsi_tpg **tpgp)
+{
+ int ret = -EIO;
+
+ if (unlikely(!copy_from_iter_full(vc->req, vc->req_size,
+ &vc->out_iter))) {
+ vq_err(vq, "Faulted on copy_from_iter\n");
+ } else if (unlikely(*vc->lunp != 1)) {
+ /* virtio-scsi spec requires byte 0 of the lun to be 1 */
+ vq_err(vq, "Illegal virtio-scsi lun: %u\n", *vc->lunp);
+ } else {
+ struct vhost_scsi_tpg **vs_tpg, *tpg;
+
+ vs_tpg = vq->private_data; /* validated at handler entry */
+
+ tpg = READ_ONCE(vs_tpg[*vc->target]);
+ if (unlikely(!tpg)) {
+ vq_err(vq, "Target 0x%x does not exist\n", *vc->target);
+ } else {
+ if (tpgp)
+ *tpgp = tpg;
+ ret = 0;
+ }
+ }
+
+ return ret;
+}
+
static void
vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
{
struct vhost_scsi_tpg **vs_tpg, *tpg;
struct virtio_scsi_cmd_req v_req;
struct virtio_scsi_cmd_req_pi v_req_pi;
+ struct vhost_scsi_ctx vc;
struct vhost_scsi_cmd *cmd;
- struct iov_iter out_iter, in_iter, prot_iter, data_iter;
+ struct iov_iter in_iter, prot_iter, data_iter;
u64 tag;
u32 exp_data_len, data_direction;
- unsigned int out = 0, in = 0;
- int head, ret, prot_bytes;
- size_t req_size, rsp_size = sizeof(struct virtio_scsi_cmd_resp);
- size_t out_size, in_size;
+ int ret, prot_bytes;
u16 lun;
- u8 *target, *lunp, task_attr;
+ u8 task_attr;
bool t10_pi = vhost_has_feature(vq, VIRTIO_SCSI_F_T10_PI);
- void *req, *cdb;
+ void *cdb;
mutex_lock(&vq->mutex);
/*
@@ -828,85 +937,47 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
if (!vs_tpg)
goto out;
+ memset(&vc, 0, sizeof(vc));
+ vc.rsp_size = sizeof(struct virtio_scsi_cmd_resp);
+
vhost_disable_notify(&vs->dev, vq);
for (;;) {
- head = vhost_get_vq_desc(vq, vq->iov,
- ARRAY_SIZE(vq->iov), &out, &in,
- NULL, NULL);
- pr_debug("vhost_get_vq_desc: head: %d, out: %u in: %u\n",
- head, out, in);
- /* On error, stop handling until the next kick. */
- if (unlikely(head < 0))
- break;
- /* Nothing new? Wait for eventfd to tell us they refilled. */
- if (head == vq->num) {
- if (unlikely(vhost_enable_notify(&vs->dev, vq))) {
- vhost_disable_notify(&vs->dev, vq);
- continue;
- }
- break;
- }
- /*
- * Check for a sane response buffer so we can report early
- * errors back to the guest.
- */
- if (unlikely(vq->iov[out].iov_len < rsp_size)) {
- vq_err(vq, "Expecting at least virtio_scsi_cmd_resp"
- " size, got %zu bytes\n", vq->iov[out].iov_len);
- break;
- }
+ ret = vhost_scsi_get_desc(vs, vq, &vc);
+ if (ret)
+ goto err;
+
/*
* Setup pointers and values based upon different virtio-scsi
* request header if T10_PI is enabled in KVM guest.
*/
if (t10_pi) {
- req = &v_req_pi;
- req_size = sizeof(v_req_pi);
- lunp = &v_req_pi.lun[0];
- target = &v_req_pi.lun[1];
+ vc.req = &v_req_pi;
+ vc.req_size = sizeof(v_req_pi);
+ vc.lunp = &v_req_pi.lun[0];
+ vc.target = &v_req_pi.lun[1];
} else {
- req = &v_req;
- req_size = sizeof(v_req);
- lunp = &v_req.lun[0];
- target = &v_req.lun[1];
+ vc.req = &v_req;
+ vc.req_size = sizeof(v_req);
+ vc.lunp = &v_req.lun[0];
+ vc.target = &v_req.lun[1];
}
- /*
- * FIXME: Not correct for BIDI operation
- */
- out_size = iov_length(vq->iov, out);
- in_size = iov_length(&vq->iov[out], in);
/*
- * Copy over the virtio-scsi request header, which for a
- * ANY_LAYOUT enabled guest may span multiple iovecs, or a
- * single iovec may contain both the header + outgoing
- * WRITE payloads.
- *
- * copy_from_iter() will advance out_iter, so that it will
- * point at the start of the outgoing WRITE payload, if
- * DMA_TO_DEVICE is set.
+ * Validate the size of request and response buffers.
+ * Check for a sane response buffer so we can report
+ * early errors back to the guest.
*/
- iov_iter_init(&out_iter, WRITE, vq->iov, out, out_size);
+ ret = vhost_scsi_chk_size(vq, &vc);
+ if (ret)
+ goto err;
- if (unlikely(!copy_from_iter_full(req, req_size, &out_iter))) {
- vq_err(vq, "Faulted on copy_from_iter\n");
- vhost_scsi_send_bad_target(vs, vq, head, out);
- continue;
- }
- /* virtio-scsi spec requires byte 0 of the lun to be 1 */
- if (unlikely(*lunp != 1)) {
- vq_err(vq, "Illegal virtio-scsi lun: %u\n", *lunp);
- vhost_scsi_send_bad_target(vs, vq, head, out);
- continue;
- }
+ ret = vhost_scsi_get_req(vq, &vc, &tpg);
+ if (ret)
+ goto err;
+
+ ret = -EIO; /* bad target on any error from here on */
- tpg = READ_ONCE(vs_tpg[*target]);
- if (unlikely(!tpg)) {
- /* Target does not exist, fail the request */
- vhost_scsi_send_bad_target(vs, vq, head, out);
- continue;
- }
/*
* Determine data_direction by calculating the total outgoing
* iovec sizes + incoming iovec sizes vs. virtio-scsi request +
@@ -924,17 +995,17 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
*/
prot_bytes = 0;
- if (out_size > req_size) {
+ if (vc.out_size > vc.req_size) {
data_direction = DMA_TO_DEVICE;
- exp_data_len = out_size - req_size;
- data_iter = out_iter;
- } else if (in_size > rsp_size) {
+ exp_data_len = vc.out_size - vc.req_size;
+ data_iter = vc.out_iter;
+ } else if (vc.in_size > vc.rsp_size) {
data_direction = DMA_FROM_DEVICE;
- exp_data_len = in_size - rsp_size;
+ exp_data_len = vc.in_size - vc.rsp_size;
- iov_iter_init(&in_iter, READ, &vq->iov[out], in,
- rsp_size + exp_data_len);
- iov_iter_advance(&in_iter, rsp_size);
+ iov_iter_init(&in_iter, READ, &vq->iov[vc.out], vc.in,
+ vc.rsp_size + exp_data_len);
+ iov_iter_advance(&in_iter, vc.rsp_size);
data_iter = in_iter;
} else {
data_direction = DMA_NONE;
@@ -950,21 +1021,20 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
if (data_direction != DMA_TO_DEVICE) {
vq_err(vq, "Received non zero pi_bytesout,"
" but wrong data_direction\n");
- vhost_scsi_send_bad_target(vs, vq, head, out);
- continue;
+ goto err;
}
prot_bytes = vhost32_to_cpu(vq, v_req_pi.pi_bytesout);
} else if (v_req_pi.pi_bytesin) {
if (data_direction != DMA_FROM_DEVICE) {
vq_err(vq, "Received non zero pi_bytesin,"
" but wrong data_direction\n");
- vhost_scsi_send_bad_target(vs, vq, head, out);
- continue;
+ goto err;
}
prot_bytes = vhost32_to_cpu(vq, v_req_pi.pi_bytesin);
}
/*
- * Set prot_iter to data_iter, and advance past any
+ * Set prot_iter to data_iter and truncate it to
+ * prot_bytes, and advance data_iter past any
* preceeding prot_bytes that may be present.
*
* Also fix up the exp_data_len to reflect only the
@@ -973,6 +1043,7 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
if (prot_bytes) {
exp_data_len -= prot_bytes;
prot_iter = data_iter;
+ iov_iter_truncate(&prot_iter, prot_bytes);
iov_iter_advance(&data_iter, prot_bytes);
}
tag = vhost64_to_cpu(vq, v_req_pi.tag);
@@ -996,8 +1067,7 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
vq_err(vq, "Received SCSI CDB with command_size: %d that"
" exceeds SCSI_MAX_VARLEN_CDB_SIZE: %d\n",
scsi_command_size(cdb), VHOST_SCSI_MAX_CDB_SIZE);
- vhost_scsi_send_bad_target(vs, vq, head, out);
- continue;
+ goto err;
}
cmd = vhost_scsi_get_tag(vq, tpg, cdb, tag, lun, task_attr,
exp_data_len + prot_bytes,
@@ -1005,13 +1075,12 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
if (IS_ERR(cmd)) {
vq_err(vq, "vhost_scsi_get_tag failed %ld\n",
PTR_ERR(cmd));
- vhost_scsi_send_bad_target(vs, vq, head, out);
- continue;
+ goto err;
}
cmd->tvc_vhost = vs;
cmd->tvc_vq = vq;
- cmd->tvc_resp_iov = vq->iov[out];
- cmd->tvc_in_iovs = in;
+ cmd->tvc_resp_iov = vq->iov[vc.out];
+ cmd->tvc_in_iovs = vc.in;
pr_debug("vhost_scsi got command opcode: %#02x, lun: %d\n",
cmd->tvc_cdb[0], cmd->tvc_lun);
@@ -1019,14 +1088,12 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
" %d\n", cmd, exp_data_len, prot_bytes, data_direction);
if (data_direction != DMA_NONE) {
- ret = vhost_scsi_mapal(cmd,
- prot_bytes, &prot_iter,
- exp_data_len, &data_iter);
- if (unlikely(ret)) {
+ if (unlikely(vhost_scsi_mapal(cmd, prot_bytes,
+ &prot_iter, exp_data_len,
+ &data_iter))) {
vq_err(vq, "Failed to map iov to sgl\n");
vhost_scsi_release_cmd(&cmd->tvc_se_cmd);
- vhost_scsi_send_bad_target(vs, vq, head, out);
- continue;
+ goto err;
}
}
/*
@@ -1034,7 +1101,7 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
* complete the virtio-scsi request in TCM callback context via
* vhost_scsi_queue_data_in() and vhost_scsi_queue_status()
*/
- cmd->tvc_vq_desc = head;
+ cmd->tvc_vq_desc = vc.head;
/*
* Dispatch cmd descriptor for cmwq execution in process
* context provided by vhost_scsi_workqueue. This also ensures
@@ -1043,6 +1110,166 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
*/
INIT_WORK(&cmd->work, vhost_scsi_submission_work);
queue_work(vhost_scsi_workqueue, &cmd->work);
+ ret = 0;
+err:
+ /*
+ * ENXIO: No more requests, or read error, wait for next kick
+ * EINVAL: Invalid response buffer, drop the request
+ * EIO: Respond with bad target
+ * EAGAIN: Pending request
+ */
+ if (ret == -ENXIO)
+ break;
+ else if (ret == -EIO)
+ vhost_scsi_send_bad_target(vs, vq, vc.head, vc.out);
+ }
+out:
+ mutex_unlock(&vq->mutex);
+}
+
+static void
+vhost_scsi_send_tmf_reject(struct vhost_scsi *vs,
+ struct vhost_virtqueue *vq,
+ struct vhost_scsi_ctx *vc)
+{
+ struct virtio_scsi_ctrl_tmf_resp __user *resp;
+ struct virtio_scsi_ctrl_tmf_resp rsp;
+ int ret;
+
+ pr_debug("%s\n", __func__);
+ memset(&rsp, 0, sizeof(rsp));
+ rsp.response = VIRTIO_SCSI_S_FUNCTION_REJECTED;
+ resp = vq->iov[vc->out].iov_base;
+ ret = __copy_to_user(resp, &rsp, sizeof(rsp));
+ if (!ret)
+ vhost_add_used_and_signal(&vs->dev, vq, vc->head, 0);
+ else
+ pr_err("Faulted on virtio_scsi_ctrl_tmf_resp\n");
+}
+
+static void
+vhost_scsi_send_an_resp(struct vhost_scsi *vs,
+ struct vhost_virtqueue *vq,
+ struct vhost_scsi_ctx *vc)
+{
+ struct virtio_scsi_ctrl_an_resp __user *resp;
+ struct virtio_scsi_ctrl_an_resp rsp;
+ int ret;
+
+ pr_debug("%s\n", __func__);
+ memset(&rsp, 0, sizeof(rsp)); /* event_actual = 0 */
+ rsp.response = VIRTIO_SCSI_S_OK;
+ resp = vq->iov[vc->out].iov_base;
+ ret = __copy_to_user(resp, &rsp, sizeof(rsp));
+ if (!ret)
+ vhost_add_used_and_signal(&vs->dev, vq, vc->head, 0);
+ else
+ pr_err("Faulted on virtio_scsi_ctrl_an_resp\n");
+}
+
+static void
+vhost_scsi_ctl_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
+{
+ union {
+ __virtio32 type;
+ struct virtio_scsi_ctrl_an_req an;
+ struct virtio_scsi_ctrl_tmf_req tmf;
+ } v_req;
+ struct vhost_scsi_ctx vc;
+ size_t typ_size;
+ int ret;
+
+ mutex_lock(&vq->mutex);
+ /*
+ * We can handle the vq only after the endpoint is setup by calling the
+ * VHOST_SCSI_SET_ENDPOINT ioctl.
+ */
+ if (!vq->private_data)
+ goto out;
+
+ memset(&vc, 0, sizeof(vc));
+
+ vhost_disable_notify(&vs->dev, vq);
+
+ for (;;) {
+ ret = vhost_scsi_get_desc(vs, vq, &vc);
+ if (ret)
+ goto err;
+
+ /*
+ * Get the request type first in order to setup
+ * other parameters dependent on the type.
+ */
+ vc.req = &v_req.type;
+ typ_size = sizeof(v_req.type);
+
+ if (unlikely(!copy_from_iter_full(vc.req, typ_size,
+ &vc.out_iter))) {
+ vq_err(vq, "Faulted on copy_from_iter tmf type\n");
+ /*
+ * The size of the response buffer depends on the
+ * request type and must be validated against it.
+ * Since the request type is not known, don't send
+ * a response.
+ */
+ continue;
+ }
+
+ switch (v_req.type) {
+ case VIRTIO_SCSI_T_TMF:
+ vc.req = &v_req.tmf;
+ vc.req_size = sizeof(struct virtio_scsi_ctrl_tmf_req);
+ vc.rsp_size = sizeof(struct virtio_scsi_ctrl_tmf_resp);
+ vc.lunp = &v_req.tmf.lun[0];
+ vc.target = &v_req.tmf.lun[1];
+ break;
+ case VIRTIO_SCSI_T_AN_QUERY:
+ case VIRTIO_SCSI_T_AN_SUBSCRIBE:
+ vc.req = &v_req.an;
+ vc.req_size = sizeof(struct virtio_scsi_ctrl_an_req);
+ vc.rsp_size = sizeof(struct virtio_scsi_ctrl_an_resp);
+ vc.lunp = &v_req.an.lun[0];
+ vc.target = NULL;
+ break;
+ default:
+ vq_err(vq, "Unknown control request %d", v_req.type);
+ continue;
+ }
+
+ /*
+ * Validate the size of request and response buffers.
+ * Check for a sane response buffer so we can report
+ * early errors back to the guest.
+ */
+ ret = vhost_scsi_chk_size(vq, &vc);
+ if (ret)
+ goto err;
+
+ /*
+ * Get the rest of the request now that its size is known.
+ */
+ vc.req += typ_size;
+ vc.req_size -= typ_size;
+
+ ret = vhost_scsi_get_req(vq, &vc, NULL);
+ if (ret)
+ goto err;
+
+ if (v_req.type == VIRTIO_SCSI_T_TMF)
+ vhost_scsi_send_tmf_reject(vs, vq, &vc);
+ else
+ vhost_scsi_send_an_resp(vs, vq, &vc);
+err:
+ /*
+ * ENXIO: No more requests, or read error, wait for next kick
+ * EINVAL: Invalid response buffer, drop the request
+ * EIO: Respond with bad target
+ * EAGAIN: Pending request
+ */
+ if (ret == -ENXIO)
+ break;
+ else if (ret == -EIO)
+ vhost_scsi_send_bad_target(vs, vq, vc.head, vc.out);
}
out:
mutex_unlock(&vq->mutex);
@@ -1050,7 +1277,12 @@ out:
static void vhost_scsi_ctl_handle_kick(struct vhost_work *work)
{
+ struct vhost_virtqueue *vq = container_of(work, struct vhost_virtqueue,
+ poll.work);
+ struct vhost_scsi *vs = container_of(vq->dev, struct vhost_scsi, dev);
+
pr_debug("%s: The handling func for control queue.\n", __func__);
+ vhost_scsi_ctl_handle_vq(vs, vq);
}
static void
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index b13c6b4b2c66..3a5f81a66d34 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -30,6 +30,7 @@
#include <linux/sched/mm.h>
#include <linux/sched/signal.h>
#include <linux/interval_tree_generic.h>
+#include <linux/nospec.h>
#include "vhost.h"
@@ -294,8 +295,11 @@ static void vhost_vq_meta_reset(struct vhost_dev *d)
{
int i;
- for (i = 0; i < d->nvqs; ++i)
+ for (i = 0; i < d->nvqs; ++i) {
+ mutex_lock(&d->vqs[i]->mutex);
__vhost_vq_meta_reset(d->vqs[i]);
+ mutex_unlock(&d->vqs[i]->mutex);
+ }
}
static void vhost_vq_reset(struct vhost_dev *dev,
@@ -891,20 +895,6 @@ static inline void __user *__vhost_get_user(struct vhost_virtqueue *vq,
#define vhost_get_used(vq, x, ptr) \
vhost_get_user(vq, x, ptr, VHOST_ADDR_USED)
-static void vhost_dev_lock_vqs(struct vhost_dev *d)
-{
- int i = 0;
- for (i = 0; i < d->nvqs; ++i)
- mutex_lock_nested(&d->vqs[i]->mutex, i);
-}
-
-static void vhost_dev_unlock_vqs(struct vhost_dev *d)
-{
- int i = 0;
- for (i = 0; i < d->nvqs; ++i)
- mutex_unlock(&d->vqs[i]->mutex);
-}
-
static int vhost_new_umem_range(struct vhost_umem *umem,
u64 start, u64 size, u64 end,
u64 userspace_addr, int perm)
@@ -954,7 +944,10 @@ static void vhost_iotlb_notify_vq(struct vhost_dev *d,
if (msg->iova <= vq_msg->iova &&
msg->iova + msg->size - 1 >= vq_msg->iova &&
vq_msg->type == VHOST_IOTLB_MISS) {
+ mutex_lock(&node->vq->mutex);
vhost_poll_queue(&node->vq->poll);
+ mutex_unlock(&node->vq->mutex);
+
list_del(&node->node);
kfree(node);
}
@@ -986,7 +979,6 @@ static int vhost_process_iotlb_msg(struct vhost_dev *dev,
int ret = 0;
mutex_lock(&dev->mutex);
- vhost_dev_lock_vqs(dev);
switch (msg->type) {
case VHOST_IOTLB_UPDATE:
if (!dev->iotlb) {
@@ -1020,7 +1012,6 @@ static int vhost_process_iotlb_msg(struct vhost_dev *dev,
break;
}
- vhost_dev_unlock_vqs(dev);
mutex_unlock(&dev->mutex);
return ret;
@@ -1397,6 +1388,7 @@ long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *arg
if (idx >= d->nvqs)
return -ENOBUFS;
+ idx = array_index_nospec(idx, d->nvqs);
vq = d->vqs[idx];
mutex_lock(&vq->mutex);
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 2919e2334052..71ee978c848f 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -111,22 +111,6 @@ config LCD_HP700
If you have an HP Jornada 700 series handheld (710/720/728)
say Y to enable LCD control driver.
-config LCD_S6E63M0
- tristate "S6E63M0 AMOLED LCD Driver"
- depends on SPI && BACKLIGHT_CLASS_DEVICE
- default n
- help
- If you have an S6E63M0 LCD Panel, say Y to enable its
- LCD control driver.
-
-config LCD_LD9040
- tristate "LD9040 AMOLED LCD Driver"
- depends on SPI && BACKLIGHT_CLASS_DEVICE
- default n
- help
- If you have an LD9040 Panel, say Y to enable its
- control driver.
-
config LCD_AMS369FG06
tristate "AMS369FG06 AMOLED LCD Driver"
depends on SPI && BACKLIGHT_CLASS_DEVICE
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 0dcc2c745c03..63c507c07437 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -9,13 +9,11 @@ obj-$(CONFIG_LCD_HX8357) += hx8357.o
obj-$(CONFIG_LCD_ILI922X) += ili922x.o
obj-$(CONFIG_LCD_ILI9320) += ili9320.o
obj-$(CONFIG_LCD_L4F00242T03) += l4f00242t03.o
-obj-$(CONFIG_LCD_LD9040) += ld9040.o
obj-$(CONFIG_LCD_LMS283GF05) += lms283gf05.o
obj-$(CONFIG_LCD_LMS501KF03) += lms501kf03.o
obj-$(CONFIG_LCD_LTV350QV) += ltv350qv.o
obj-$(CONFIG_LCD_OTM3225A) += otm3225a.o
obj-$(CONFIG_LCD_PLATFORM) += platform_lcd.o
-obj-$(CONFIG_LCD_S6E63M0) += s6e63m0.o
obj-$(CONFIG_LCD_TDO24M) += tdo24m.o
obj-$(CONFIG_LCD_TOSA) += tosa_lcd.o
obj-$(CONFIG_LCD_VGG2432A4) += vgg2432a4.o
diff --git a/drivers/video/backlight/adp5520_bl.c b/drivers/video/backlight/adp5520_bl.c
index 35373e2065b2..5e38353b4423 100644
--- a/drivers/video/backlight/adp5520_bl.c
+++ b/drivers/video/backlight/adp5520_bl.c
@@ -391,7 +391,7 @@ static struct platform_driver adp5520_bl_driver = {
module_platform_driver(adp5520_bl_driver);
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("ADP5520(01) Backlight Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:adp5520-backlight");
diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c
index f1dc41cf19e3..85318236da2f 100644
--- a/drivers/video/backlight/adp8860_bl.c
+++ b/drivers/video/backlight/adp8860_bl.c
@@ -822,5 +822,5 @@ static struct i2c_driver adp8860_driver = {
module_i2c_driver(adp8860_driver);
MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("ADP8860 Backlight driver");
diff --git a/drivers/video/backlight/adp8870_bl.c b/drivers/video/backlight/adp8870_bl.c
index 4fec9aa92d9b..8d50e0299578 100644
--- a/drivers/video/backlight/adp8870_bl.c
+++ b/drivers/video/backlight/adp8870_bl.c
@@ -992,5 +992,5 @@ static struct i2c_driver adp8870_driver = {
module_i2c_driver(adp8870_driver);
MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("ADP8870 Backlight driver");
diff --git a/drivers/video/backlight/as3711_bl.c b/drivers/video/backlight/as3711_bl.c
index ca544aa764b8..33f0f0f2e8b3 100644
--- a/drivers/video/backlight/as3711_bl.c
+++ b/drivers/video/backlight/as3711_bl.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* AS3711 PMIC backlight driver, using DCDC Step Up Converters
*
* Copyright (C) 2012 Renesas Electronics Corporation
* Author: Guennadi Liakhovetski, <g.liakhovetski@gmx.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the version 2 of the GNU General Public License as
- * published by the Free Software Foundation
*/
#include <linux/backlight.h>
@@ -488,5 +485,5 @@ module_platform_driver(as3711_backlight_driver);
MODULE_DESCRIPTION("Backlight Driver for AS3711 PMICs");
MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:as3711-backlight");
diff --git a/drivers/video/backlight/ld9040.c b/drivers/video/backlight/ld9040.c
deleted file mode 100644
index 677f8abba27c..000000000000
--- a/drivers/video/backlight/ld9040.c
+++ /dev/null
@@ -1,811 +0,0 @@
-/*
- * ld9040 AMOLED LCD panel driver.
- *
- * Copyright (c) 2011 Samsung Electronics
- * Author: Donghwa Lee <dh09.lee@samsung.com>
- * Derived from drivers/video/backlight/s6e63m0.c
- *
- * 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.
- */
-
-#include <linux/backlight.h>
-#include <linux/delay.h>
-#include <linux/fb.h>
-#include <linux/gpio.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/kernel.h>
-#include <linux/lcd.h>
-#include <linux/module.h>
-#include <linux/regulator/consumer.h>
-#include <linux/spi/spi.h>
-#include <linux/wait.h>
-
-#include "ld9040_gamma.h"
-
-#define SLEEPMSEC 0x1000
-#define ENDDEF 0x2000
-#define DEFMASK 0xFF00
-#define COMMAND_ONLY 0xFE
-#define DATA_ONLY 0xFF
-
-#define MIN_BRIGHTNESS 0
-#define MAX_BRIGHTNESS 24
-
-struct ld9040 {
- struct device *dev;
- struct spi_device *spi;
- unsigned int power;
- unsigned int current_brightness;
-
- struct lcd_device *ld;
- struct backlight_device *bd;
- struct lcd_platform_data *lcd_pd;
-
- struct mutex lock;
- bool enabled;
-};
-
-static struct regulator_bulk_data supplies[] = {
- { .supply = "vdd3", },
- { .supply = "vci", },
-};
-
-static void ld9040_regulator_enable(struct ld9040 *lcd)
-{
- int ret = 0;
- struct lcd_platform_data *pd = NULL;
-
- pd = lcd->lcd_pd;
- mutex_lock(&lcd->lock);
- if (!lcd->enabled) {
- ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies);
- if (ret)
- goto out;
-
- lcd->enabled = true;
- }
- msleep(pd->power_on_delay);
-out:
- mutex_unlock(&lcd->lock);
-}
-
-static void ld9040_regulator_disable(struct ld9040 *lcd)
-{
- int ret = 0;
-
- mutex_lock(&lcd->lock);
- if (lcd->enabled) {
- ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies);
- if (ret)
- goto out;
-
- lcd->enabled = false;
- }
-out:
- mutex_unlock(&lcd->lock);
-}
-
-static const unsigned short seq_swreset[] = {
- 0x01, COMMAND_ONLY,
- ENDDEF, 0x00
-};
-
-static const unsigned short seq_user_setting[] = {
- 0xF0, 0x5A,
-
- DATA_ONLY, 0x5A,
- ENDDEF, 0x00
-};
-
-static const unsigned short seq_elvss_on[] = {
- 0xB1, 0x0D,
-
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x16,
- ENDDEF, 0x00
-};
-
-static const unsigned short seq_gtcon[] = {
- 0xF7, 0x09,
-
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x00,
- ENDDEF, 0x00
-};
-
-static const unsigned short seq_panel_condition[] = {
- 0xF8, 0x05,
-
- DATA_ONLY, 0x65,
- DATA_ONLY, 0x96,
- DATA_ONLY, 0x71,
- DATA_ONLY, 0x7D,
- DATA_ONLY, 0x19,
- DATA_ONLY, 0x3B,
- DATA_ONLY, 0x0D,
- DATA_ONLY, 0x19,
- DATA_ONLY, 0x7E,
- DATA_ONLY, 0x0D,
- DATA_ONLY, 0xE2,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x7E,
- DATA_ONLY, 0x7D,
- DATA_ONLY, 0x07,
- DATA_ONLY, 0x07,
- DATA_ONLY, 0x20,
- DATA_ONLY, 0x20,
- DATA_ONLY, 0x20,
- DATA_ONLY, 0x02,
- DATA_ONLY, 0x02,
- ENDDEF, 0x00
-};
-
-static const unsigned short seq_gamma_set1[] = {
- 0xF9, 0x00,
-
- DATA_ONLY, 0xA7,
- DATA_ONLY, 0xB4,
- DATA_ONLY, 0xAE,
- DATA_ONLY, 0xBF,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x91,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0xB2,
- DATA_ONLY, 0xB4,
- DATA_ONLY, 0xAA,
- DATA_ONLY, 0xBB,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0xAC,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0xB3,
- DATA_ONLY, 0xB1,
- DATA_ONLY, 0xAA,
- DATA_ONLY, 0xBC,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0xB3,
- ENDDEF, 0x00
-};
-
-static const unsigned short seq_gamma_ctrl[] = {
- 0xFB, 0x02,
-
- DATA_ONLY, 0x5A,
- ENDDEF, 0x00
-};
-
-static const unsigned short seq_gamma_start[] = {
- 0xF9, COMMAND_ONLY,
-
- ENDDEF, 0x00
-};
-
-static const unsigned short seq_apon[] = {
- 0xF3, 0x00,
-
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x0A,
- DATA_ONLY, 0x02,
- ENDDEF, 0x00
-};
-
-static const unsigned short seq_display_ctrl[] = {
- 0xF2, 0x02,
-
- DATA_ONLY, 0x08,
- DATA_ONLY, 0x08,
- DATA_ONLY, 0x10,
- DATA_ONLY, 0x10,
- ENDDEF, 0x00
-};
-
-static const unsigned short seq_manual_pwr[] = {
- 0xB0, 0x04,
- ENDDEF, 0x00
-};
-
-static const unsigned short seq_pwr_ctrl[] = {
- 0xF4, 0x0A,
-
- DATA_ONLY, 0x87,
- DATA_ONLY, 0x25,
- DATA_ONLY, 0x6A,
- DATA_ONLY, 0x44,
- DATA_ONLY, 0x02,
- DATA_ONLY, 0x88,
- ENDDEF, 0x00
-};
-
-static const unsigned short seq_sleep_out[] = {
- 0x11, COMMAND_ONLY,
- ENDDEF, 0x00
-};
-
-static const unsigned short seq_sleep_in[] = {
- 0x10, COMMAND_ONLY,
- ENDDEF, 0x00
-};
-
-static const unsigned short seq_display_on[] = {
- 0x29, COMMAND_ONLY,
- ENDDEF, 0x00
-};
-
-static const unsigned short seq_display_off[] = {
- 0x28, COMMAND_ONLY,
- ENDDEF, 0x00
-};
-
-static const unsigned short seq_vci1_1st_en[] = {
- 0xF3, 0x10,
-
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x02,
- ENDDEF, 0x00
-};
-
-static const unsigned short seq_vl1_en[] = {
- 0xF3, 0x11,
-
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x02,
- ENDDEF, 0x00
-};
-
-static const unsigned short seq_vl2_en[] = {
- 0xF3, 0x13,
-
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x02,
- ENDDEF, 0x00
-};
-
-static const unsigned short seq_vci1_2nd_en[] = {
- 0xF3, 0x33,
-
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x02,
- ENDDEF, 0x00
-};
-
-static const unsigned short seq_vl3_en[] = {
- 0xF3, 0x37,
-
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x02,
- ENDDEF, 0x00
-};
-
-static const unsigned short seq_vreg1_amp_en[] = {
- 0xF3, 0x37,
-
- DATA_ONLY, 0x01,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x02,
- ENDDEF, 0x00
-};
-
-static const unsigned short seq_vgh_amp_en[] = {
- 0xF3, 0x37,
-
- DATA_ONLY, 0x11,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x02,
- ENDDEF, 0x00
-};
-
-static const unsigned short seq_vgl_amp_en[] = {
- 0xF3, 0x37,
-
- DATA_ONLY, 0x31,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x02,
- ENDDEF, 0x00
-};
-
-static const unsigned short seq_vmos_amp_en[] = {
- 0xF3, 0x37,
-
- DATA_ONLY, 0xB1,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x03,
- ENDDEF, 0x00
-};
-
-static const unsigned short seq_vint_amp_en[] = {
- 0xF3, 0x37,
-
- DATA_ONLY, 0xF1,
- /* DATA_ONLY, 0x71, VMOS/VBL/VBH not used */
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x03,
- /* DATA_ONLY, 0x02, VMOS/VBL/VBH not used */
- ENDDEF, 0x00
-};
-
-static const unsigned short seq_vbh_amp_en[] = {
- 0xF3, 0x37,
-
- DATA_ONLY, 0xF9,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x03,
- ENDDEF, 0x00
-};
-
-static const unsigned short seq_vbl_amp_en[] = {
- 0xF3, 0x37,
-
- DATA_ONLY, 0xFD,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x03,
- ENDDEF, 0x00
-};
-
-static const unsigned short seq_gam_amp_en[] = {
- 0xF3, 0x37,
-
- DATA_ONLY, 0xFF,
- /* DATA_ONLY, 0x73, VMOS/VBL/VBH not used */
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x03,
- /* DATA_ONLY, 0x02, VMOS/VBL/VBH not used */
- ENDDEF, 0x00
-};
-
-static const unsigned short seq_sd_amp_en[] = {
- 0xF3, 0x37,
-
- DATA_ONLY, 0xFF,
- /* DATA_ONLY, 0x73, VMOS/VBL/VBH not used */
- DATA_ONLY, 0x80,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x03,
- /* DATA_ONLY, 0x02, VMOS/VBL/VBH not used */
- ENDDEF, 0x00
-};
-
-static const unsigned short seq_gls_en[] = {
- 0xF3, 0x37,
-
- DATA_ONLY, 0xFF,
- /* DATA_ONLY, 0x73, VMOS/VBL/VBH not used */
- DATA_ONLY, 0x81,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x03,
- /* DATA_ONLY, 0x02, VMOS/VBL/VBH not used */
- ENDDEF, 0x00
-};
-
-static const unsigned short seq_els_en[] = {
- 0xF3, 0x37,
-
- DATA_ONLY, 0xFF,
- /* DATA_ONLY, 0x73, VMOS/VBL/VBH not used */
- DATA_ONLY, 0x83,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x03,
- /* DATA_ONLY, 0x02, VMOS/VBL/VBH not used */
- ENDDEF, 0x00
-};
-
-static const unsigned short seq_el_on[] = {
- 0xF3, 0x37,
-
- DATA_ONLY, 0xFF,
- /* DATA_ONLY, 0x73, VMOS/VBL/VBH not used */
- DATA_ONLY, 0x87,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x03,
- /* DATA_ONLY, 0x02, VMOS/VBL/VBH not used */
- ENDDEF, 0x00
-};
-
-static int ld9040_spi_write_byte(struct ld9040 *lcd, int addr, int data)
-{
- u16 buf[1];
- struct spi_message msg;
-
- struct spi_transfer xfer = {
- .len = 2,
- .tx_buf = buf,
- };
-
- buf[0] = (addr << 8) | data;
-
- spi_message_init(&msg);
- spi_message_add_tail(&xfer, &msg);
-
- return spi_sync(lcd->spi, &msg);
-}
-
-static int ld9040_spi_write(struct ld9040 *lcd, unsigned char address,
- unsigned char command)
-{
- int ret = 0;
-
- if (address != DATA_ONLY)
- ret = ld9040_spi_write_byte(lcd, 0x0, address);
- if (command != COMMAND_ONLY)
- ret = ld9040_spi_write_byte(lcd, 0x1, command);
-
- return ret;
-}
-
-static int ld9040_panel_send_sequence(struct ld9040 *lcd,
- const unsigned short *wbuf)
-{
- int ret = 0, i = 0;
-
- while ((wbuf[i] & DEFMASK) != ENDDEF) {
- if ((wbuf[i] & DEFMASK) != SLEEPMSEC) {
- ret = ld9040_spi_write(lcd, wbuf[i], wbuf[i+1]);
- if (ret)
- break;
- } else {
- msleep(wbuf[i+1]);
- }
- i += 2;
- }
-
- return ret;
-}
-
-static int _ld9040_gamma_ctl(struct ld9040 *lcd, const unsigned int *gamma)
-{
- unsigned int i = 0;
- int ret = 0;
-
- /* start gamma table updating. */
- ret = ld9040_panel_send_sequence(lcd, seq_gamma_start);
- if (ret) {
- dev_err(lcd->dev, "failed to disable gamma table updating.\n");
- goto gamma_err;
- }
-
- for (i = 0 ; i < GAMMA_TABLE_COUNT; i++) {
- ret = ld9040_spi_write(lcd, DATA_ONLY, gamma[i]);
- if (ret) {
- dev_err(lcd->dev, "failed to set gamma table.\n");
- goto gamma_err;
- }
- }
-
- /* update gamma table. */
- ret = ld9040_panel_send_sequence(lcd, seq_gamma_ctrl);
- if (ret)
- dev_err(lcd->dev, "failed to update gamma table.\n");
-
-gamma_err:
- return ret;
-}
-
-static int ld9040_gamma_ctl(struct ld9040 *lcd, int gamma)
-{
- return _ld9040_gamma_ctl(lcd, gamma_table.gamma_22_table[gamma]);
-}
-
-static int ld9040_ldi_init(struct ld9040 *lcd)
-{
- int ret, i;
- static const unsigned short *init_seq[] = {
- seq_user_setting,
- seq_panel_condition,
- seq_display_ctrl,
- seq_manual_pwr,
- seq_elvss_on,
- seq_gtcon,
- seq_gamma_set1,
- seq_gamma_ctrl,
- seq_sleep_out,
- };
-
- for (i = 0; i < ARRAY_SIZE(init_seq); i++) {
- ret = ld9040_panel_send_sequence(lcd, init_seq[i]);
- /* workaround: minimum delay time for transferring CMD */
- usleep_range(300, 310);
- if (ret)
- break;
- }
-
- return ret;
-}
-
-static int ld9040_ldi_enable(struct ld9040 *lcd)
-{
- return ld9040_panel_send_sequence(lcd, seq_display_on);
-}
-
-static int ld9040_ldi_disable(struct ld9040 *lcd)
-{
- int ret;
-
- ret = ld9040_panel_send_sequence(lcd, seq_display_off);
- ret = ld9040_panel_send_sequence(lcd, seq_sleep_in);
-
- return ret;
-}
-
-static int ld9040_power_is_on(int power)
-{
- return power <= FB_BLANK_NORMAL;
-}
-
-static int ld9040_power_on(struct ld9040 *lcd)
-{
- int ret = 0;
- struct lcd_platform_data *pd;
-
- pd = lcd->lcd_pd;
-
- /* lcd power on */
- ld9040_regulator_enable(lcd);
-
- if (!pd->reset) {
- dev_err(lcd->dev, "reset is NULL.\n");
- return -EINVAL;
- }
-
- pd->reset(lcd->ld);
- msleep(pd->reset_delay);
-
- ret = ld9040_ldi_init(lcd);
- if (ret) {
- dev_err(lcd->dev, "failed to initialize ldi.\n");
- return ret;
- }
-
- ret = ld9040_ldi_enable(lcd);
- if (ret) {
- dev_err(lcd->dev, "failed to enable ldi.\n");
- return ret;
- }
-
- return 0;
-}
-
-static int ld9040_power_off(struct ld9040 *lcd)
-{
- int ret;
- struct lcd_platform_data *pd;
-
- pd = lcd->lcd_pd;
-
- ret = ld9040_ldi_disable(lcd);
- if (ret) {
- dev_err(lcd->dev, "lcd setting failed.\n");
- return -EIO;
- }
-
- msleep(pd->power_off_delay);
-
- /* lcd power off */
- ld9040_regulator_disable(lcd);
-
- return 0;
-}
-
-static int ld9040_power(struct ld9040 *lcd, int power)
-{
- int ret = 0;
-
- if (ld9040_power_is_on(power) && !ld9040_power_is_on(lcd->power))
- ret = ld9040_power_on(lcd);
- else if (!ld9040_power_is_on(power) && ld9040_power_is_on(lcd->power))
- ret = ld9040_power_off(lcd);
-
- if (!ret)
- lcd->power = power;
-
- return ret;
-}
-
-static int ld9040_set_power(struct lcd_device *ld, int power)
-{
- struct ld9040 *lcd = lcd_get_data(ld);
-
- if (power != FB_BLANK_UNBLANK && power != FB_BLANK_POWERDOWN &&
- power != FB_BLANK_NORMAL) {
- dev_err(lcd->dev, "power value should be 0, 1 or 4.\n");
- return -EINVAL;
- }
-
- return ld9040_power(lcd, power);
-}
-
-static int ld9040_get_power(struct lcd_device *ld)
-{
- struct ld9040 *lcd = lcd_get_data(ld);
-
- return lcd->power;
-}
-
-static int ld9040_set_brightness(struct backlight_device *bd)
-{
- int ret = 0, brightness = bd->props.brightness;
- struct ld9040 *lcd = bl_get_data(bd);
-
- if (brightness < MIN_BRIGHTNESS ||
- brightness > bd->props.max_brightness) {
- dev_err(&bd->dev, "lcd brightness should be %d to %d.\n",
- MIN_BRIGHTNESS, MAX_BRIGHTNESS);
- return -EINVAL;
- }
-
- ret = ld9040_gamma_ctl(lcd, bd->props.brightness);
- if (ret) {
- dev_err(&bd->dev, "lcd brightness setting failed.\n");
- return -EIO;
- }
-
- return ret;
-}
-
-static struct lcd_ops ld9040_lcd_ops = {
- .set_power = ld9040_set_power,
- .get_power = ld9040_get_power,
-};
-
-static const struct backlight_ops ld9040_backlight_ops = {
- .update_status = ld9040_set_brightness,
-};
-
-static int ld9040_probe(struct spi_device *spi)
-{
- int ret = 0;
- struct ld9040 *lcd = NULL;
- struct lcd_device *ld = NULL;
- struct backlight_device *bd = NULL;
- struct backlight_properties props;
-
- lcd = devm_kzalloc(&spi->dev, sizeof(struct ld9040), GFP_KERNEL);
- if (!lcd)
- return -ENOMEM;
-
- /* ld9040 lcd panel uses 3-wire 9bits SPI Mode. */
- spi->bits_per_word = 9;
-
- ret = spi_setup(spi);
- if (ret < 0) {
- dev_err(&spi->dev, "spi setup failed.\n");
- return ret;
- }
-
- lcd->spi = spi;
- lcd->dev = &spi->dev;
-
- lcd->lcd_pd = dev_get_platdata(&spi->dev);
- if (!lcd->lcd_pd) {
- dev_err(&spi->dev, "platform data is NULL.\n");
- return -EINVAL;
- }
-
- mutex_init(&lcd->lock);
-
- ret = devm_regulator_bulk_get(lcd->dev, ARRAY_SIZE(supplies), supplies);
- if (ret) {
- dev_err(lcd->dev, "Failed to get regulators: %d\n", ret);
- return ret;
- }
-
- ld = devm_lcd_device_register(&spi->dev, "ld9040", &spi->dev, lcd,
- &ld9040_lcd_ops);
- if (IS_ERR(ld))
- return PTR_ERR(ld);
-
- lcd->ld = ld;
-
- memset(&props, 0, sizeof(struct backlight_properties));
- props.type = BACKLIGHT_RAW;
- props.max_brightness = MAX_BRIGHTNESS;
-
- bd = devm_backlight_device_register(&spi->dev, "ld9040-bl", &spi->dev,
- lcd, &ld9040_backlight_ops, &props);
- if (IS_ERR(bd))
- return PTR_ERR(bd);
-
- bd->props.brightness = MAX_BRIGHTNESS;
- lcd->bd = bd;
-
- /*
- * if lcd panel was on from bootloader like u-boot then
- * do not lcd on.
- */
- if (!lcd->lcd_pd->lcd_enabled) {
- /*
- * if lcd panel was off from bootloader then
- * current lcd status is powerdown and then
- * it enables lcd panel.
- */
- lcd->power = FB_BLANK_POWERDOWN;
-
- ld9040_power(lcd, FB_BLANK_UNBLANK);
- } else {
- lcd->power = FB_BLANK_UNBLANK;
- }
-
- spi_set_drvdata(spi, lcd);
-
- dev_info(&spi->dev, "ld9040 panel driver has been probed.\n");
- return 0;
-}
-
-static int ld9040_remove(struct spi_device *spi)
-{
- struct ld9040 *lcd = spi_get_drvdata(spi);
-
- ld9040_power(lcd, FB_BLANK_POWERDOWN);
- return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int ld9040_suspend(struct device *dev)
-{
- struct ld9040 *lcd = dev_get_drvdata(dev);
-
- dev_dbg(dev, "lcd->power = %d\n", lcd->power);
-
- /*
- * when lcd panel is suspend, lcd panel becomes off
- * regardless of status.
- */
- return ld9040_power(lcd, FB_BLANK_POWERDOWN);
-}
-
-static int ld9040_resume(struct device *dev)
-{
- struct ld9040 *lcd = dev_get_drvdata(dev);
-
- lcd->power = FB_BLANK_POWERDOWN;
-
- return ld9040_power(lcd, FB_BLANK_UNBLANK);
-}
-#endif
-
-static SIMPLE_DEV_PM_OPS(ld9040_pm_ops, ld9040_suspend, ld9040_resume);
-
-/* Power down all displays on reboot, poweroff or halt. */
-static void ld9040_shutdown(struct spi_device *spi)
-{
- struct ld9040 *lcd = spi_get_drvdata(spi);
-
- ld9040_power(lcd, FB_BLANK_POWERDOWN);
-}
-
-static struct spi_driver ld9040_driver = {
- .driver = {
- .name = "ld9040",
- .pm = &ld9040_pm_ops,
- },
- .probe = ld9040_probe,
- .remove = ld9040_remove,
- .shutdown = ld9040_shutdown,
-};
-
-module_spi_driver(ld9040_driver);
-
-MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
-MODULE_DESCRIPTION("ld9040 LCD Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/backlight/ld9040_gamma.h b/drivers/video/backlight/ld9040_gamma.h
deleted file mode 100644
index c5e586d97385..000000000000
--- a/drivers/video/backlight/ld9040_gamma.h
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Gamma level definitions.
- *
- * Copyright (c) 2011 Samsung Electronics
- * InKi Dae <inki.dae@samsung.com>
- * Donghwa Lee <dh09.lee@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef _LD9040_BRIGHTNESS_H
-#define _LD9040_BRIGHTNESS_H
-
-#define MAX_GAMMA_LEVEL 25
-#define GAMMA_TABLE_COUNT 21
-
-/* gamma value: 2.2 */
-static const unsigned int ld9040_22_300[] = {
- 0x00, 0xa7, 0xb4, 0xae, 0xbf, 0x00, 0x91,
- 0x00, 0xb2, 0xb4, 0xaa, 0xbb, 0x00, 0xac,
- 0x00, 0xb3, 0xb1, 0xaa, 0xbc, 0x00, 0xb3
-};
-
-static const unsigned int ld9040_22_290[] = {
- 0x00, 0xa9, 0xb7, 0xae, 0xbd, 0x00, 0x89,
- 0x00, 0xb7, 0xb6, 0xa8, 0xba, 0x00, 0xa4,
- 0x00, 0xb1, 0xb4, 0xaa, 0xbb, 0x00, 0xaa
-};
-
-static const unsigned int ld9040_22_280[] = {
- 0x00, 0xa9, 0xb6, 0xad, 0xbf, 0x00, 0x86,
- 0x00, 0xb8, 0xb5, 0xa8, 0xbc, 0x00, 0xa0,
- 0x00, 0xb3, 0xb3, 0xa9, 0xbc, 0x00, 0xa7
-};
-
-static const unsigned int ld9040_22_270[] = {
- 0x00, 0xa8, 0xb8, 0xae, 0xbe, 0x00, 0x84,
- 0x00, 0xb9, 0xb7, 0xa8, 0xbc, 0x00, 0x9d,
- 0x00, 0xb2, 0xb5, 0xaa, 0xbc, 0x00, 0xa4
-
-};
-static const unsigned int ld9040_22_260[] = {
- 0x00, 0xa4, 0xb8, 0xb0, 0xbf, 0x00, 0x80,
- 0x00, 0xb8, 0xb6, 0xaa, 0xbc, 0x00, 0x9a,
- 0x00, 0xb0, 0xb5, 0xab, 0xbd, 0x00, 0xa0
-};
-
-static const unsigned int ld9040_22_250[] = {
- 0x00, 0xa4, 0xb9, 0xaf, 0xc1, 0x00, 0x7d,
- 0x00, 0xb9, 0xb6, 0xaa, 0xbb, 0x00, 0x97,
- 0x00, 0xb1, 0xb5, 0xaa, 0xbf, 0x00, 0x9d
-};
-
-static const unsigned int ld9040_22_240[] = {
- 0x00, 0xa2, 0xb9, 0xaf, 0xc2, 0x00, 0x7a,
- 0x00, 0xb9, 0xb7, 0xaa, 0xbd, 0x00, 0x94,
- 0x00, 0xb0, 0xb5, 0xab, 0xbf, 0x00, 0x9a
-};
-
-static const unsigned int ld9040_22_230[] = {
- 0x00, 0xa0, 0xb9, 0xaf, 0xc3, 0x00, 0x77,
- 0x00, 0xb9, 0xb7, 0xab, 0xbe, 0x00, 0x90,
- 0x00, 0xb0, 0xb6, 0xab, 0xbf, 0x00, 0x97
-};
-
-static const unsigned int ld9040_22_220[] = {
- 0x00, 0x9e, 0xba, 0xb0, 0xc2, 0x00, 0x75,
- 0x00, 0xb9, 0xb8, 0xab, 0xbe, 0x00, 0x8e,
- 0x00, 0xb0, 0xb6, 0xac, 0xbf, 0x00, 0x94
-};
-
-static const unsigned int ld9040_22_210[] = {
- 0x00, 0x9c, 0xb9, 0xb0, 0xc4, 0x00, 0x72,
- 0x00, 0xb8, 0xb8, 0xac, 0xbf, 0x00, 0x8a,
- 0x00, 0xb0, 0xb6, 0xac, 0xc0, 0x00, 0x91
-};
-
-static const unsigned int ld9040_22_200[] = {
- 0x00, 0x9a, 0xba, 0xb1, 0xc4, 0x00, 0x6f,
- 0x00, 0xb8, 0xb8, 0xad, 0xc0, 0x00, 0x86,
- 0x00, 0xb0, 0xb7, 0xad, 0xc0, 0x00, 0x8d
-};
-
-static const unsigned int ld9040_22_190[] = {
- 0x00, 0x97, 0xba, 0xb2, 0xc5, 0x00, 0x6c,
- 0x00, 0xb8, 0xb8, 0xae, 0xc1, 0x00, 0x82,
- 0x00, 0xb0, 0xb6, 0xae, 0xc2, 0x00, 0x89
-};
-
-static const unsigned int ld9040_22_180[] = {
- 0x00, 0x93, 0xba, 0xb3, 0xc5, 0x00, 0x69,
- 0x00, 0xb8, 0xb9, 0xae, 0xc1, 0x00, 0x7f,
- 0x00, 0xb0, 0xb6, 0xae, 0xc3, 0x00, 0x85
-};
-
-static const unsigned int ld9040_22_170[] = {
- 0x00, 0x8b, 0xb9, 0xb3, 0xc7, 0x00, 0x65,
- 0x00, 0xb7, 0xb8, 0xaf, 0xc3, 0x00, 0x7a,
- 0x00, 0x80, 0xb6, 0xae, 0xc4, 0x00, 0x81
-};
-
-static const unsigned int ld9040_22_160[] = {
- 0x00, 0x89, 0xba, 0xb3, 0xc8, 0x00, 0x62,
- 0x00, 0xb6, 0xba, 0xaf, 0xc3, 0x00, 0x76,
- 0x00, 0xaf, 0xb7, 0xae, 0xc4, 0x00, 0x7e
-};
-
-static const unsigned int ld9040_22_150[] = {
- 0x00, 0x82, 0xba, 0xb4, 0xc7, 0x00, 0x5f,
- 0x00, 0xb5, 0xba, 0xb0, 0xc3, 0x00, 0x72,
- 0x00, 0xae, 0xb8, 0xb0, 0xc3, 0x00, 0x7a
-};
-
-static const unsigned int ld9040_22_140[] = {
- 0x00, 0x7b, 0xbb, 0xb4, 0xc8, 0x00, 0x5b,
- 0x00, 0xb5, 0xba, 0xb1, 0xc4, 0x00, 0x6e,
- 0x00, 0xae, 0xb9, 0xb0, 0xc5, 0x00, 0x75
-};
-
-static const unsigned int ld9040_22_130[] = {
- 0x00, 0x71, 0xbb, 0xb5, 0xc8, 0x00, 0x57,
- 0x00, 0xb5, 0xbb, 0xb0, 0xc5, 0x00, 0x6a,
- 0x00, 0xae, 0xb9, 0xb1, 0xc6, 0x00, 0x70
-};
-
-static const unsigned int ld9040_22_120[] = {
- 0x00, 0x47, 0xba, 0xb6, 0xca, 0x00, 0x53,
- 0x00, 0xb5, 0xbb, 0xb3, 0xc6, 0x00, 0x65,
- 0x00, 0xae, 0xb8, 0xb3, 0xc7, 0x00, 0x6c
-};
-
-static const unsigned int ld9040_22_110[] = {
- 0x00, 0x13, 0xbb, 0xb7, 0xca, 0x00, 0x4f,
- 0x00, 0xb4, 0xbb, 0xb3, 0xc7, 0x00, 0x60,
- 0x00, 0xad, 0xb8, 0xb4, 0xc7, 0x00, 0x67
-};
-
-static const unsigned int ld9040_22_100[] = {
- 0x00, 0x13, 0xba, 0xb8, 0xcb, 0x00, 0x4b,
- 0x00, 0xb3, 0xbc, 0xb4, 0xc7, 0x00, 0x5c,
- 0x00, 0xac, 0xb8, 0xb4, 0xc8, 0x00, 0x62
-};
-
-static const unsigned int ld9040_22_90[] = {
- 0x00, 0x13, 0xb9, 0xb8, 0xcd, 0x00, 0x46,
- 0x00, 0xb1, 0xbc, 0xb5, 0xc8, 0x00, 0x56,
- 0x00, 0xaa, 0xb8, 0xb4, 0xc9, 0x00, 0x5d
-};
-
-static const unsigned int ld9040_22_80[] = {
- 0x00, 0x13, 0xba, 0xb9, 0xcd, 0x00, 0x41,
- 0x00, 0xb0, 0xbe, 0xb5, 0xc9, 0x00, 0x51,
- 0x00, 0xa9, 0xb9, 0xb5, 0xca, 0x00, 0x57
-};
-
-static const unsigned int ld9040_22_70[] = {
- 0x00, 0x13, 0xb9, 0xb9, 0xd0, 0x00, 0x3c,
- 0x00, 0xaf, 0xbf, 0xb6, 0xcb, 0x00, 0x4b,
- 0x00, 0xa8, 0xb9, 0xb5, 0xcc, 0x00, 0x52
-};
-
-static const unsigned int ld9040_22_50[] = {
- 0x00, 0x13, 0xb2, 0xba, 0xd2, 0x00, 0x30,
- 0x00, 0xaf, 0xc0, 0xb8, 0xcd, 0x00, 0x3d,
- 0x00, 0xa8, 0xb8, 0xb7, 0xcd, 0x00, 0x44
-};
-
-struct ld9040_gamma {
- unsigned int *gamma_22_table[MAX_GAMMA_LEVEL];
-};
-
-static struct ld9040_gamma gamma_table = {
- .gamma_22_table[0] = (unsigned int *)&ld9040_22_50,
- .gamma_22_table[1] = (unsigned int *)&ld9040_22_70,
- .gamma_22_table[2] = (unsigned int *)&ld9040_22_80,
- .gamma_22_table[3] = (unsigned int *)&ld9040_22_90,
- .gamma_22_table[4] = (unsigned int *)&ld9040_22_100,
- .gamma_22_table[5] = (unsigned int *)&ld9040_22_110,
- .gamma_22_table[6] = (unsigned int *)&ld9040_22_120,
- .gamma_22_table[7] = (unsigned int *)&ld9040_22_130,
- .gamma_22_table[8] = (unsigned int *)&ld9040_22_140,
- .gamma_22_table[9] = (unsigned int *)&ld9040_22_150,
- .gamma_22_table[10] = (unsigned int *)&ld9040_22_160,
- .gamma_22_table[11] = (unsigned int *)&ld9040_22_170,
- .gamma_22_table[12] = (unsigned int *)&ld9040_22_180,
- .gamma_22_table[13] = (unsigned int *)&ld9040_22_190,
- .gamma_22_table[14] = (unsigned int *)&ld9040_22_200,
- .gamma_22_table[15] = (unsigned int *)&ld9040_22_210,
- .gamma_22_table[16] = (unsigned int *)&ld9040_22_220,
- .gamma_22_table[17] = (unsigned int *)&ld9040_22_230,
- .gamma_22_table[18] = (unsigned int *)&ld9040_22_240,
- .gamma_22_table[19] = (unsigned int *)&ld9040_22_250,
- .gamma_22_table[20] = (unsigned int *)&ld9040_22_260,
- .gamma_22_table[21] = (unsigned int *)&ld9040_22_270,
- .gamma_22_table[22] = (unsigned int *)&ld9040_22_280,
- .gamma_22_table[23] = (unsigned int *)&ld9040_22_290,
- .gamma_22_table[24] = (unsigned int *)&ld9040_22_300,
-};
-
-#endif
diff --git a/drivers/video/backlight/lm3639_bl.c b/drivers/video/backlight/lm3639_bl.c
index cd50df5807ea..086611c7bc03 100644
--- a/drivers/video/backlight/lm3639_bl.c
+++ b/drivers/video/backlight/lm3639_bl.c
@@ -400,10 +400,8 @@ static int lm3639_remove(struct i2c_client *client)
regmap_write(pchip->regmap, REG_ENABLE, 0x00);
- if (&pchip->cdev_torch)
- led_classdev_unregister(&pchip->cdev_torch);
- if (&pchip->cdev_flash)
- led_classdev_unregister(&pchip->cdev_flash);
+ led_classdev_unregister(&pchip->cdev_torch);
+ led_classdev_unregister(&pchip->cdev_flash);
if (pchip->bled)
device_remove_file(&(pchip->bled->dev), &dev_attr_bled_mode);
return 0;
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index bdfcc0a71db1..678b27063198 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -28,10 +28,8 @@
struct pwm_bl_data {
struct pwm_device *pwm;
struct device *dev;
- unsigned int period;
unsigned int lth_brightness;
unsigned int *levels;
- bool enabled;
struct regulator *power_supply;
struct gpio_desc *enable_gpio;
unsigned int scale;
@@ -46,31 +44,35 @@ struct pwm_bl_data {
void (*exit)(struct device *);
};
-static void pwm_backlight_power_on(struct pwm_bl_data *pb, int brightness)
+static void pwm_backlight_power_on(struct pwm_bl_data *pb)
{
+ struct pwm_state state;
int err;
- if (pb->enabled)
+ pwm_get_state(pb->pwm, &state);
+ if (state.enabled)
return;
err = regulator_enable(pb->power_supply);
if (err < 0)
dev_err(pb->dev, "failed to enable power supply\n");
- pwm_enable(pb->pwm);
+ state.enabled = true;
+ pwm_apply_state(pb->pwm, &state);
if (pb->post_pwm_on_delay)
msleep(pb->post_pwm_on_delay);
if (pb->enable_gpio)
gpiod_set_value_cansleep(pb->enable_gpio, 1);
-
- pb->enabled = true;
}
static void pwm_backlight_power_off(struct pwm_bl_data *pb)
{
- if (!pb->enabled)
+ struct pwm_state state;
+
+ pwm_get_state(pb->pwm, &state);
+ if (!state.enabled)
return;
if (pb->enable_gpio)
@@ -79,24 +81,27 @@ static void pwm_backlight_power_off(struct pwm_bl_data *pb)
if (pb->pwm_off_delay)
msleep(pb->pwm_off_delay);
- pwm_config(pb->pwm, 0, pb->period);
- pwm_disable(pb->pwm);
+ state.enabled = false;
+ state.duty_cycle = 0;
+ pwm_apply_state(pb->pwm, &state);
regulator_disable(pb->power_supply);
- pb->enabled = false;
}
static int compute_duty_cycle(struct pwm_bl_data *pb, int brightness)
{
unsigned int lth = pb->lth_brightness;
+ struct pwm_state state;
u64 duty_cycle;
+ pwm_get_state(pb->pwm, &state);
+
if (pb->levels)
duty_cycle = pb->levels[brightness];
else
duty_cycle = brightness;
- duty_cycle *= pb->period - lth;
+ duty_cycle *= state.period - lth;
do_div(duty_cycle, pb->scale);
return duty_cycle + lth;
@@ -106,7 +111,7 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
{
struct pwm_bl_data *pb = bl_get_data(bl);
int brightness = bl->props.brightness;
- int duty_cycle;
+ struct pwm_state state;
if (bl->props.power != FB_BLANK_UNBLANK ||
bl->props.fb_blank != FB_BLANK_UNBLANK ||
@@ -117,9 +122,10 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
brightness = pb->notify(pb->dev, brightness);
if (brightness > 0) {
- duty_cycle = compute_duty_cycle(pb, brightness);
- pwm_config(pb->pwm, duty_cycle, pb->period);
- pwm_backlight_power_on(pb, brightness);
+ pwm_get_state(pb->pwm, &state);
+ state.duty_cycle = compute_duty_cycle(pb, brightness);
+ pwm_apply_state(pb->pwm, &state);
+ pwm_backlight_power_on(pb);
} else
pwm_backlight_power_off(pb);
@@ -447,7 +453,6 @@ static int pwm_backlight_probe(struct platform_device *pdev)
struct device_node *node = pdev->dev.of_node;
struct pwm_bl_data *pb;
struct pwm_state state;
- struct pwm_args pargs;
unsigned int i;
int ret;
@@ -478,7 +483,6 @@ static int pwm_backlight_probe(struct platform_device *pdev)
pb->check_fb = data->check_fb;
pb->exit = data->exit;
pb->dev = &pdev->dev;
- pb->enabled = false;
pb->post_pwm_on_delay = data->post_pwm_on_delay;
pb->pwm_off_delay = data->pwm_off_delay;
@@ -539,10 +543,26 @@ static int pwm_backlight_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "got pwm for backlight\n");
- if (!data->levels) {
- /* Get the PWM period (in nanoseconds) */
- pwm_get_state(pb->pwm, &state);
+ /* Sync up PWM state. */
+ pwm_init_state(pb->pwm, &state);
+ /*
+ * The DT case will set the pwm_period_ns field to 0 and store the
+ * period, parsed from the DT, in the PWM device. For the non-DT case,
+ * set the period from platform data if it has not already been set
+ * via the PWM lookup table.
+ */
+ if (!state.period && (data->pwm_period_ns > 0))
+ state.period = data->pwm_period_ns;
+
+ ret = pwm_apply_state(pb->pwm, &state);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to apply initial PWM state: %d\n",
+ ret);
+ goto err_alloc;
+ }
+
+ if (!data->levels) {
ret = pwm_backlight_brightness_default(&pdev->dev, data,
state.period);
if (ret < 0) {
@@ -559,24 +579,7 @@ static int pwm_backlight_probe(struct platform_device *pdev)
pb->levels = data->levels;
}
- /*
- * FIXME: pwm_apply_args() should be removed when switching to
- * the atomic PWM API.
- */
- pwm_apply_args(pb->pwm);
-
- /*
- * The DT case will set the pwm_period_ns field to 0 and store the
- * period, parsed from the DT, in the PWM device. For the non-DT case,
- * set the period from platform data if it has not already been set
- * via the PWM lookup table.
- */
- pwm_get_args(pb->pwm, &pargs);
- pb->period = pargs.period;
- if (!pb->period && (data->pwm_period_ns > 0))
- pb->period = data->pwm_period_ns;
-
- pb->lth_brightness = data->lth_brightness * (pb->period / pb->scale);
+ pb->lth_brightness = data->lth_brightness * (state.period / pb->scale);
memset(&props, 0, sizeof(struct backlight_properties));
props.type = BACKLIGHT_RAW;
diff --git a/drivers/video/backlight/s6e63m0.c b/drivers/video/backlight/s6e63m0.c
deleted file mode 100644
index 3c4a22a3063a..000000000000
--- a/drivers/video/backlight/s6e63m0.c
+++ /dev/null
@@ -1,857 +0,0 @@
-/*
- * S6E63M0 AMOLED LCD panel driver.
- *
- * Author: InKi Dae <inki.dae@samsung.com>
- *
- * Derived from drivers/video/omap/lcd-apollon.c
- *
- * 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.
- */
-
-#include <linux/backlight.h>
-#include <linux/delay.h>
-#include <linux/fb.h>
-#include <linux/gpio.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/kernel.h>
-#include <linux/lcd.h>
-#include <linux/module.h>
-#include <linux/spi/spi.h>
-#include <linux/wait.h>
-
-#include "s6e63m0_gamma.h"
-
-#define SLEEPMSEC 0x1000
-#define ENDDEF 0x2000
-#define DEFMASK 0xFF00
-#define COMMAND_ONLY 0xFE
-#define DATA_ONLY 0xFF
-
-#define MIN_BRIGHTNESS 0
-#define MAX_BRIGHTNESS 10
-
-struct s6e63m0 {
- struct device *dev;
- struct spi_device *spi;
- unsigned int power;
- unsigned int current_brightness;
- unsigned int gamma_mode;
- unsigned int gamma_table_count;
- struct lcd_device *ld;
- struct backlight_device *bd;
- struct lcd_platform_data *lcd_pd;
-};
-
-static const unsigned short seq_panel_condition_set[] = {
- 0xF8, 0x01,
- DATA_ONLY, 0x27,
- DATA_ONLY, 0x27,
- DATA_ONLY, 0x07,
- DATA_ONLY, 0x07,
- DATA_ONLY, 0x54,
- DATA_ONLY, 0x9f,
- DATA_ONLY, 0x63,
- DATA_ONLY, 0x86,
- DATA_ONLY, 0x1a,
- DATA_ONLY, 0x33,
- DATA_ONLY, 0x0d,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x00,
-
- ENDDEF, 0x0000
-};
-
-static const unsigned short seq_display_condition_set[] = {
- 0xf2, 0x02,
- DATA_ONLY, 0x03,
- DATA_ONLY, 0x1c,
- DATA_ONLY, 0x10,
- DATA_ONLY, 0x10,
-
- 0xf7, 0x03,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x00,
-
- ENDDEF, 0x0000
-};
-
-static const unsigned short seq_gamma_setting[] = {
- 0xfa, 0x00,
- DATA_ONLY, 0x18,
- DATA_ONLY, 0x08,
- DATA_ONLY, 0x24,
- DATA_ONLY, 0x64,
- DATA_ONLY, 0x56,
- DATA_ONLY, 0x33,
- DATA_ONLY, 0xb6,
- DATA_ONLY, 0xba,
- DATA_ONLY, 0xa8,
- DATA_ONLY, 0xac,
- DATA_ONLY, 0xb1,
- DATA_ONLY, 0x9d,
- DATA_ONLY, 0xc1,
- DATA_ONLY, 0xc1,
- DATA_ONLY, 0xb7,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x9c,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x9f,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0xd6,
-
- 0xfa, 0x01,
-
- ENDDEF, 0x0000
-};
-
-static const unsigned short seq_etc_condition_set[] = {
- 0xf6, 0x00,
- DATA_ONLY, 0x8c,
- DATA_ONLY, 0x07,
-
- 0xb3, 0xc,
-
- 0xb5, 0x2c,
- DATA_ONLY, 0x12,
- DATA_ONLY, 0x0c,
- DATA_ONLY, 0x0a,
- DATA_ONLY, 0x10,
- DATA_ONLY, 0x0e,
- DATA_ONLY, 0x17,
- DATA_ONLY, 0x13,
- DATA_ONLY, 0x1f,
- DATA_ONLY, 0x1a,
- DATA_ONLY, 0x2a,
- DATA_ONLY, 0x24,
- DATA_ONLY, 0x1f,
- DATA_ONLY, 0x1b,
- DATA_ONLY, 0x1a,
- DATA_ONLY, 0x17,
-
- DATA_ONLY, 0x2b,
- DATA_ONLY, 0x26,
- DATA_ONLY, 0x22,
- DATA_ONLY, 0x20,
- DATA_ONLY, 0x3a,
- DATA_ONLY, 0x34,
- DATA_ONLY, 0x30,
- DATA_ONLY, 0x2c,
- DATA_ONLY, 0x29,
- DATA_ONLY, 0x26,
- DATA_ONLY, 0x25,
- DATA_ONLY, 0x23,
- DATA_ONLY, 0x21,
- DATA_ONLY, 0x20,
- DATA_ONLY, 0x1e,
- DATA_ONLY, 0x1e,
-
- 0xb6, 0x00,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x11,
- DATA_ONLY, 0x22,
- DATA_ONLY, 0x33,
- DATA_ONLY, 0x44,
- DATA_ONLY, 0x44,
- DATA_ONLY, 0x44,
-
- DATA_ONLY, 0x55,
- DATA_ONLY, 0x55,
- DATA_ONLY, 0x66,
- DATA_ONLY, 0x66,
- DATA_ONLY, 0x66,
- DATA_ONLY, 0x66,
- DATA_ONLY, 0x66,
- DATA_ONLY, 0x66,
-
- 0xb7, 0x2c,
- DATA_ONLY, 0x12,
- DATA_ONLY, 0x0c,
- DATA_ONLY, 0x0a,
- DATA_ONLY, 0x10,
- DATA_ONLY, 0x0e,
- DATA_ONLY, 0x17,
- DATA_ONLY, 0x13,
- DATA_ONLY, 0x1f,
- DATA_ONLY, 0x1a,
- DATA_ONLY, 0x2a,
- DATA_ONLY, 0x24,
- DATA_ONLY, 0x1f,
- DATA_ONLY, 0x1b,
- DATA_ONLY, 0x1a,
- DATA_ONLY, 0x17,
-
- DATA_ONLY, 0x2b,
- DATA_ONLY, 0x26,
- DATA_ONLY, 0x22,
- DATA_ONLY, 0x20,
- DATA_ONLY, 0x3a,
- DATA_ONLY, 0x34,
- DATA_ONLY, 0x30,
- DATA_ONLY, 0x2c,
- DATA_ONLY, 0x29,
- DATA_ONLY, 0x26,
- DATA_ONLY, 0x25,
- DATA_ONLY, 0x23,
- DATA_ONLY, 0x21,
- DATA_ONLY, 0x20,
- DATA_ONLY, 0x1e,
- DATA_ONLY, 0x1e,
-
- 0xb8, 0x00,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x11,
- DATA_ONLY, 0x22,
- DATA_ONLY, 0x33,
- DATA_ONLY, 0x44,
- DATA_ONLY, 0x44,
- DATA_ONLY, 0x44,
-
- DATA_ONLY, 0x55,
- DATA_ONLY, 0x55,
- DATA_ONLY, 0x66,
- DATA_ONLY, 0x66,
- DATA_ONLY, 0x66,
- DATA_ONLY, 0x66,
- DATA_ONLY, 0x66,
- DATA_ONLY, 0x66,
-
- 0xb9, 0x2c,
- DATA_ONLY, 0x12,
- DATA_ONLY, 0x0c,
- DATA_ONLY, 0x0a,
- DATA_ONLY, 0x10,
- DATA_ONLY, 0x0e,
- DATA_ONLY, 0x17,
- DATA_ONLY, 0x13,
- DATA_ONLY, 0x1f,
- DATA_ONLY, 0x1a,
- DATA_ONLY, 0x2a,
- DATA_ONLY, 0x24,
- DATA_ONLY, 0x1f,
- DATA_ONLY, 0x1b,
- DATA_ONLY, 0x1a,
- DATA_ONLY, 0x17,
-
- DATA_ONLY, 0x2b,
- DATA_ONLY, 0x26,
- DATA_ONLY, 0x22,
- DATA_ONLY, 0x20,
- DATA_ONLY, 0x3a,
- DATA_ONLY, 0x34,
- DATA_ONLY, 0x30,
- DATA_ONLY, 0x2c,
- DATA_ONLY, 0x29,
- DATA_ONLY, 0x26,
- DATA_ONLY, 0x25,
- DATA_ONLY, 0x23,
- DATA_ONLY, 0x21,
- DATA_ONLY, 0x20,
- DATA_ONLY, 0x1e,
- DATA_ONLY, 0x1e,
-
- 0xba, 0x00,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x11,
- DATA_ONLY, 0x22,
- DATA_ONLY, 0x33,
- DATA_ONLY, 0x44,
- DATA_ONLY, 0x44,
- DATA_ONLY, 0x44,
-
- DATA_ONLY, 0x55,
- DATA_ONLY, 0x55,
- DATA_ONLY, 0x66,
- DATA_ONLY, 0x66,
- DATA_ONLY, 0x66,
- DATA_ONLY, 0x66,
- DATA_ONLY, 0x66,
- DATA_ONLY, 0x66,
-
- 0xc1, 0x4d,
- DATA_ONLY, 0x96,
- DATA_ONLY, 0x1d,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x01,
- DATA_ONLY, 0xdf,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x03,
- DATA_ONLY, 0x1f,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x00,
- DATA_ONLY, 0x03,
- DATA_ONLY, 0x06,
- DATA_ONLY, 0x09,
- DATA_ONLY, 0x0d,
- DATA_ONLY, 0x0f,
- DATA_ONLY, 0x12,
- DATA_ONLY, 0x15,
- DATA_ONLY, 0x18,
-
- 0xb2, 0x10,
- DATA_ONLY, 0x10,
- DATA_ONLY, 0x0b,
- DATA_ONLY, 0x05,
-
- ENDDEF, 0x0000
-};
-
-static const unsigned short seq_acl_on[] = {
- /* ACL on */
- 0xc0, 0x01,
-
- ENDDEF, 0x0000
-};
-
-static const unsigned short seq_acl_off[] = {
- /* ACL off */
- 0xc0, 0x00,
-
- ENDDEF, 0x0000
-};
-
-static const unsigned short seq_elvss_on[] = {
- /* ELVSS on */
- 0xb1, 0x0b,
-
- ENDDEF, 0x0000
-};
-
-static const unsigned short seq_elvss_off[] = {
- /* ELVSS off */
- 0xb1, 0x0a,
-
- ENDDEF, 0x0000
-};
-
-static const unsigned short seq_stand_by_off[] = {
- 0x11, COMMAND_ONLY,
-
- ENDDEF, 0x0000
-};
-
-static const unsigned short seq_stand_by_on[] = {
- 0x10, COMMAND_ONLY,
-
- ENDDEF, 0x0000
-};
-
-static const unsigned short seq_display_on[] = {
- 0x29, COMMAND_ONLY,
-
- ENDDEF, 0x0000
-};
-
-
-static int s6e63m0_spi_write_byte(struct s6e63m0 *lcd, int addr, int data)
-{
- u16 buf[1];
- struct spi_message msg;
-
- struct spi_transfer xfer = {
- .len = 2,
- .tx_buf = buf,
- };
-
- buf[0] = (addr << 8) | data;
-
- spi_message_init(&msg);
- spi_message_add_tail(&xfer, &msg);
-
- return spi_sync(lcd->spi, &msg);
-}
-
-static int s6e63m0_spi_write(struct s6e63m0 *lcd, unsigned char address,
- unsigned char command)
-{
- int ret = 0;
-
- if (address != DATA_ONLY)
- ret = s6e63m0_spi_write_byte(lcd, 0x0, address);
- if (command != COMMAND_ONLY)
- ret = s6e63m0_spi_write_byte(lcd, 0x1, command);
-
- return ret;
-}
-
-static int s6e63m0_panel_send_sequence(struct s6e63m0 *lcd,
- const unsigned short *wbuf)
-{
- int ret = 0, i = 0;
-
- while ((wbuf[i] & DEFMASK) != ENDDEF) {
- if ((wbuf[i] & DEFMASK) != SLEEPMSEC) {
- ret = s6e63m0_spi_write(lcd, wbuf[i], wbuf[i+1]);
- if (ret)
- break;
- } else {
- msleep(wbuf[i+1]);
- }
- i += 2;
- }
-
- return ret;
-}
-
-static int _s6e63m0_gamma_ctl(struct s6e63m0 *lcd, const unsigned int *gamma)
-{
- unsigned int i = 0;
- int ret = 0;
-
- /* disable gamma table updating. */
- ret = s6e63m0_spi_write(lcd, 0xfa, 0x00);
- if (ret) {
- dev_err(lcd->dev, "failed to disable gamma table updating.\n");
- goto gamma_err;
- }
-
- for (i = 0 ; i < GAMMA_TABLE_COUNT; i++) {
- ret = s6e63m0_spi_write(lcd, DATA_ONLY, gamma[i]);
- if (ret) {
- dev_err(lcd->dev, "failed to set gamma table.\n");
- goto gamma_err;
- }
- }
-
- /* update gamma table. */
- ret = s6e63m0_spi_write(lcd, 0xfa, 0x01);
- if (ret)
- dev_err(lcd->dev, "failed to update gamma table.\n");
-
-gamma_err:
- return ret;
-}
-
-static int s6e63m0_gamma_ctl(struct s6e63m0 *lcd, int gamma)
-{
- int ret = 0;
-
- ret = _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_22_table[gamma]);
-
- return ret;
-}
-
-
-static int s6e63m0_ldi_init(struct s6e63m0 *lcd)
-{
- int ret, i;
- const unsigned short *init_seq[] = {
- seq_panel_condition_set,
- seq_display_condition_set,
- seq_gamma_setting,
- seq_etc_condition_set,
- seq_acl_on,
- seq_elvss_on,
- };
-
- for (i = 0; i < ARRAY_SIZE(init_seq); i++) {
- ret = s6e63m0_panel_send_sequence(lcd, init_seq[i]);
- if (ret)
- break;
- }
-
- return ret;
-}
-
-static int s6e63m0_ldi_enable(struct s6e63m0 *lcd)
-{
- int ret = 0, i;
- const unsigned short *enable_seq[] = {
- seq_stand_by_off,
- seq_display_on,
- };
-
- for (i = 0; i < ARRAY_SIZE(enable_seq); i++) {
- ret = s6e63m0_panel_send_sequence(lcd, enable_seq[i]);
- if (ret)
- break;
- }
-
- return ret;
-}
-
-static int s6e63m0_ldi_disable(struct s6e63m0 *lcd)
-{
- int ret;
-
- ret = s6e63m0_panel_send_sequence(lcd, seq_stand_by_on);
-
- return ret;
-}
-
-static int s6e63m0_power_is_on(int power)
-{
- return power <= FB_BLANK_NORMAL;
-}
-
-static int s6e63m0_power_on(struct s6e63m0 *lcd)
-{
- int ret = 0;
- struct lcd_platform_data *pd;
- struct backlight_device *bd;
-
- pd = lcd->lcd_pd;
- bd = lcd->bd;
-
- if (!pd->power_on) {
- dev_err(lcd->dev, "power_on is NULL.\n");
- return -EINVAL;
- }
-
- pd->power_on(lcd->ld, 1);
- msleep(pd->power_on_delay);
-
- if (!pd->reset) {
- dev_err(lcd->dev, "reset is NULL.\n");
- return -EINVAL;
- }
-
- pd->reset(lcd->ld);
- msleep(pd->reset_delay);
-
- ret = s6e63m0_ldi_init(lcd);
- if (ret) {
- dev_err(lcd->dev, "failed to initialize ldi.\n");
- return ret;
- }
-
- ret = s6e63m0_ldi_enable(lcd);
- if (ret) {
- dev_err(lcd->dev, "failed to enable ldi.\n");
- return ret;
- }
-
- /* set brightness to current value after power on or resume. */
- ret = s6e63m0_gamma_ctl(lcd, bd->props.brightness);
- if (ret) {
- dev_err(lcd->dev, "lcd gamma setting failed.\n");
- return ret;
- }
-
- return 0;
-}
-
-static int s6e63m0_power_off(struct s6e63m0 *lcd)
-{
- int ret;
- struct lcd_platform_data *pd;
-
- pd = lcd->lcd_pd;
-
- ret = s6e63m0_ldi_disable(lcd);
- if (ret) {
- dev_err(lcd->dev, "lcd setting failed.\n");
- return -EIO;
- }
-
- msleep(pd->power_off_delay);
-
- pd->power_on(lcd->ld, 0);
-
- return 0;
-}
-
-static int s6e63m0_power(struct s6e63m0 *lcd, int power)
-{
- int ret = 0;
-
- if (s6e63m0_power_is_on(power) && !s6e63m0_power_is_on(lcd->power))
- ret = s6e63m0_power_on(lcd);
- else if (!s6e63m0_power_is_on(power) && s6e63m0_power_is_on(lcd->power))
- ret = s6e63m0_power_off(lcd);
-
- if (!ret)
- lcd->power = power;
-
- return ret;
-}
-
-static int s6e63m0_set_power(struct lcd_device *ld, int power)
-{
- struct s6e63m0 *lcd = lcd_get_data(ld);
-
- if (power != FB_BLANK_UNBLANK && power != FB_BLANK_POWERDOWN &&
- power != FB_BLANK_NORMAL) {
- dev_err(lcd->dev, "power value should be 0, 1 or 4.\n");
- return -EINVAL;
- }
-
- return s6e63m0_power(lcd, power);
-}
-
-static int s6e63m0_get_power(struct lcd_device *ld)
-{
- struct s6e63m0 *lcd = lcd_get_data(ld);
-
- return lcd->power;
-}
-
-static int s6e63m0_set_brightness(struct backlight_device *bd)
-{
- int ret = 0, brightness = bd->props.brightness;
- struct s6e63m0 *lcd = bl_get_data(bd);
-
- if (brightness < MIN_BRIGHTNESS ||
- brightness > bd->props.max_brightness) {
- dev_err(&bd->dev, "lcd brightness should be %d to %d.\n",
- MIN_BRIGHTNESS, MAX_BRIGHTNESS);
- return -EINVAL;
- }
-
- ret = s6e63m0_gamma_ctl(lcd, bd->props.brightness);
- if (ret) {
- dev_err(&bd->dev, "lcd brightness setting failed.\n");
- return -EIO;
- }
-
- return ret;
-}
-
-static struct lcd_ops s6e63m0_lcd_ops = {
- .set_power = s6e63m0_set_power,
- .get_power = s6e63m0_get_power,
-};
-
-static const struct backlight_ops s6e63m0_backlight_ops = {
- .update_status = s6e63m0_set_brightness,
-};
-
-static ssize_t s6e63m0_sysfs_show_gamma_mode(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct s6e63m0 *lcd = dev_get_drvdata(dev);
- char temp[10];
-
- switch (lcd->gamma_mode) {
- case 0:
- sprintf(temp, "2.2 mode\n");
- strcat(buf, temp);
- break;
- case 1:
- sprintf(temp, "1.9 mode\n");
- strcat(buf, temp);
- break;
- case 2:
- sprintf(temp, "1.7 mode\n");
- strcat(buf, temp);
- break;
- default:
- dev_info(dev, "gamma mode could be 0:2.2, 1:1.9 or 2:1.7)n");
- break;
- }
-
- return strlen(buf);
-}
-
-static ssize_t s6e63m0_sysfs_store_gamma_mode(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len)
-{
- struct s6e63m0 *lcd = dev_get_drvdata(dev);
- struct backlight_device *bd = NULL;
- int brightness, rc;
-
- rc = kstrtouint(buf, 0, &lcd->gamma_mode);
- if (rc < 0)
- return rc;
-
- bd = lcd->bd;
-
- brightness = bd->props.brightness;
-
- switch (lcd->gamma_mode) {
- case 0:
- _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_22_table[brightness]);
- break;
- case 1:
- _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_19_table[brightness]);
- break;
- case 2:
- _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_17_table[brightness]);
- break;
- default:
- dev_info(dev, "gamma mode could be 0:2.2, 1:1.9 or 2:1.7\n");
- _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_22_table[brightness]);
- break;
- }
- return len;
-}
-
-static DEVICE_ATTR(gamma_mode, 0644,
- s6e63m0_sysfs_show_gamma_mode, s6e63m0_sysfs_store_gamma_mode);
-
-static ssize_t s6e63m0_sysfs_show_gamma_table(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct s6e63m0 *lcd = dev_get_drvdata(dev);
- char temp[3];
-
- sprintf(temp, "%u\n", lcd->gamma_table_count);
- strcpy(buf, temp);
-
- return strlen(buf);
-}
-static DEVICE_ATTR(gamma_table, 0444,
- s6e63m0_sysfs_show_gamma_table, NULL);
-
-static int s6e63m0_probe(struct spi_device *spi)
-{
- int ret = 0;
- struct s6e63m0 *lcd = NULL;
- struct lcd_device *ld = NULL;
- struct backlight_device *bd = NULL;
- struct backlight_properties props;
-
- lcd = devm_kzalloc(&spi->dev, sizeof(struct s6e63m0), GFP_KERNEL);
- if (!lcd)
- return -ENOMEM;
-
- /* s6e63m0 lcd panel uses 3-wire 9bits SPI Mode. */
- spi->bits_per_word = 9;
-
- ret = spi_setup(spi);
- if (ret < 0) {
- dev_err(&spi->dev, "spi setup failed.\n");
- return ret;
- }
-
- lcd->spi = spi;
- lcd->dev = &spi->dev;
-
- lcd->lcd_pd = dev_get_platdata(&spi->dev);
- if (!lcd->lcd_pd) {
- dev_err(&spi->dev, "platform data is NULL.\n");
- return -EINVAL;
- }
-
- ld = devm_lcd_device_register(&spi->dev, "s6e63m0", &spi->dev, lcd,
- &s6e63m0_lcd_ops);
- if (IS_ERR(ld))
- return PTR_ERR(ld);
-
- lcd->ld = ld;
-
- memset(&props, 0, sizeof(struct backlight_properties));
- props.type = BACKLIGHT_RAW;
- props.max_brightness = MAX_BRIGHTNESS;
-
- bd = devm_backlight_device_register(&spi->dev, "s6e63m0bl-bl",
- &spi->dev, lcd, &s6e63m0_backlight_ops,
- &props);
- if (IS_ERR(bd))
- return PTR_ERR(bd);
-
- bd->props.brightness = MAX_BRIGHTNESS;
- lcd->bd = bd;
-
- /*
- * it gets gamma table count available so it gets user
- * know that.
- */
- lcd->gamma_table_count =
- sizeof(gamma_table) / (MAX_GAMMA_LEVEL * sizeof(int *));
-
- ret = device_create_file(&(spi->dev), &dev_attr_gamma_mode);
- if (ret < 0)
- dev_err(&(spi->dev), "failed to add sysfs entries\n");
-
- ret = device_create_file(&(spi->dev), &dev_attr_gamma_table);
- if (ret < 0)
- dev_err(&(spi->dev), "failed to add sysfs entries\n");
-
- /*
- * if lcd panel was on from bootloader like u-boot then
- * do not lcd on.
- */
- if (!lcd->lcd_pd->lcd_enabled) {
- /*
- * if lcd panel was off from bootloader then
- * current lcd status is powerdown and then
- * it enables lcd panel.
- */
- lcd->power = FB_BLANK_POWERDOWN;
-
- s6e63m0_power(lcd, FB_BLANK_UNBLANK);
- } else {
- lcd->power = FB_BLANK_UNBLANK;
- }
-
- spi_set_drvdata(spi, lcd);
-
- dev_info(&spi->dev, "s6e63m0 panel driver has been probed.\n");
-
- return 0;
-}
-
-static int s6e63m0_remove(struct spi_device *spi)
-{
- struct s6e63m0 *lcd = spi_get_drvdata(spi);
-
- s6e63m0_power(lcd, FB_BLANK_POWERDOWN);
- device_remove_file(&spi->dev, &dev_attr_gamma_table);
- device_remove_file(&spi->dev, &dev_attr_gamma_mode);
-
- return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int s6e63m0_suspend(struct device *dev)
-{
- struct s6e63m0 *lcd = dev_get_drvdata(dev);
-
- dev_dbg(dev, "lcd->power = %d\n", lcd->power);
-
- /*
- * when lcd panel is suspend, lcd panel becomes off
- * regardless of status.
- */
- return s6e63m0_power(lcd, FB_BLANK_POWERDOWN);
-}
-
-static int s6e63m0_resume(struct device *dev)
-{
- struct s6e63m0 *lcd = dev_get_drvdata(dev);
-
- lcd->power = FB_BLANK_POWERDOWN;
-
- return s6e63m0_power(lcd, FB_BLANK_UNBLANK);
-}
-#endif
-
-static SIMPLE_DEV_PM_OPS(s6e63m0_pm_ops, s6e63m0_suspend, s6e63m0_resume);
-
-/* Power down all displays on reboot, poweroff or halt. */
-static void s6e63m0_shutdown(struct spi_device *spi)
-{
- struct s6e63m0 *lcd = spi_get_drvdata(spi);
-
- s6e63m0_power(lcd, FB_BLANK_POWERDOWN);
-}
-
-static struct spi_driver s6e63m0_driver = {
- .driver = {
- .name = "s6e63m0",
- .pm = &s6e63m0_pm_ops,
- },
- .probe = s6e63m0_probe,
- .remove = s6e63m0_remove,
- .shutdown = s6e63m0_shutdown,
-};
-
-module_spi_driver(s6e63m0_driver);
-
-MODULE_AUTHOR("InKi Dae <inki.dae@samsung.com>");
-MODULE_DESCRIPTION("S6E63M0 LCD Driver");
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/video/backlight/s6e63m0_gamma.h b/drivers/video/backlight/s6e63m0_gamma.h
deleted file mode 100644
index 2c44bdb0696b..000000000000
--- a/drivers/video/backlight/s6e63m0_gamma.h
+++ /dev/null
@@ -1,266 +0,0 @@
-/* linux/drivers/video/samsung/s6e63m0_brightness.h
- *
- * Gamma level definitions.
- *
- * Copyright (c) 2009 Samsung Electronics
- * InKi Dae <inki.dae@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef _S6E63M0_BRIGHTNESS_H
-#define _S6E63M0_BRIGHTNESS_H
-
-#define MAX_GAMMA_LEVEL 11
-#define GAMMA_TABLE_COUNT 21
-
-/* gamma value: 2.2 */
-static const unsigned int s6e63m0_22_300[] = {
- 0x18, 0x08, 0x24, 0x5f, 0x50, 0x2d, 0xB6,
- 0xB9, 0xA7, 0xAd, 0xB1, 0x9f, 0xbe, 0xC0,
- 0xB5, 0x00, 0xa0, 0x00, 0xa4, 0x00, 0xdb
-};
-
-static const unsigned int s6e63m0_22_280[] = {
- 0x18, 0x08, 0x24, 0x64, 0x56, 0x33, 0xB6,
- 0xBA, 0xA8, 0xAC, 0xB1, 0x9D, 0xC1, 0xC1,
- 0xB7, 0x00, 0x9C, 0x00, 0x9F, 0x00, 0xD6
-};
-
-static const unsigned int s6e63m0_22_260[] = {
- 0x18, 0x08, 0x24, 0x66, 0x58, 0x34, 0xB6,
- 0xBA, 0xA7, 0xAF, 0xB3, 0xA0, 0xC1, 0xC2,
- 0xB7, 0x00, 0x97, 0x00, 0x9A, 0x00, 0xD1
-
-};
-
-static const unsigned int s6e63m0_22_240[] = {
- 0x18, 0x08, 0x24, 0x62, 0x54, 0x30, 0xB9,
- 0xBB, 0xA9, 0xB0, 0xB3, 0xA1, 0xC1, 0xC3,
- 0xB7, 0x00, 0x91, 0x00, 0x95, 0x00, 0xDA
-
-};
-static const unsigned int s6e63m0_22_220[] = {
- 0x18, 0x08, 0x24, 0x63, 0x53, 0x31, 0xB8,
- 0xBC, 0xA9, 0xB0, 0xB5, 0xA2, 0xC4, 0xC4,
- 0xB8, 0x00, 0x8B, 0x00, 0x8E, 0x00, 0xC2
-};
-
-static const unsigned int s6e63m0_22_200[] = {
- 0x18, 0x08, 0x24, 0x66, 0x55, 0x34, 0xBA,
- 0xBD, 0xAB, 0xB1, 0xB5, 0xA3, 0xC5, 0xC6,
- 0xB9, 0x00, 0x85, 0x00, 0x88, 0x00, 0xBA
-};
-
-static const unsigned int s6e63m0_22_170[] = {
- 0x18, 0x08, 0x24, 0x69, 0x54, 0x37, 0xBB,
- 0xBE, 0xAC, 0xB4, 0xB7, 0xA6, 0xC7, 0xC8,
- 0xBC, 0x00, 0x7B, 0x00, 0x7E, 0x00, 0xAB
-};
-
-static const unsigned int s6e63m0_22_140[] = {
- 0x18, 0x08, 0x24, 0x6C, 0x54, 0x3A, 0xBC,
- 0xBF, 0xAC, 0xB7, 0xBB, 0xA9, 0xC9, 0xC9,
- 0xBE, 0x00, 0x71, 0x00, 0x73, 0x00, 0x9E
-};
-
-static const unsigned int s6e63m0_22_110[] = {
- 0x18, 0x08, 0x24, 0x70, 0x51, 0x3E, 0xBF,
- 0xC1, 0xAF, 0xB9, 0xBC, 0xAB, 0xCC, 0xCC,
- 0xC2, 0x00, 0x65, 0x00, 0x67, 0x00, 0x8D
-};
-
-static const unsigned int s6e63m0_22_90[] = {
- 0x18, 0x08, 0x24, 0x73, 0x4A, 0x3D, 0xC0,
- 0xC2, 0xB1, 0xBB, 0xBE, 0xAC, 0xCE, 0xCF,
- 0xC5, 0x00, 0x5D, 0x00, 0x5E, 0x00, 0x82
-};
-
-static const unsigned int s6e63m0_22_30[] = {
- 0x18, 0x08, 0x24, 0x78, 0xEC, 0x3D, 0xC8,
- 0xC2, 0xB6, 0xC4, 0xC7, 0xB6, 0xD5, 0xD7,
- 0xCC, 0x00, 0x39, 0x00, 0x36, 0x00, 0x51
-};
-
-/* gamma value: 1.9 */
-static const unsigned int s6e63m0_19_300[] = {
- 0x18, 0x08, 0x24, 0x61, 0x5F, 0x39, 0xBA,
- 0xBD, 0xAD, 0xB1, 0xB6, 0xA5, 0xC4, 0xC5,
- 0xBC, 0x00, 0xA0, 0x00, 0xA4, 0x00, 0xDB
-};
-
-static const unsigned int s6e63m0_19_280[] = {
- 0x18, 0x08, 0x24, 0x61, 0x60, 0x39, 0xBB,
- 0xBE, 0xAD, 0xB2, 0xB6, 0xA6, 0xC5, 0xC7,
- 0xBD, 0x00, 0x9B, 0x00, 0x9E, 0x00, 0xD5
-};
-
-static const unsigned int s6e63m0_19_260[] = {
- 0x18, 0x08, 0x24, 0x63, 0x61, 0x3B, 0xBA,
- 0xBE, 0xAC, 0xB3, 0xB8, 0xA7, 0xC6, 0xC8,
- 0xBD, 0x00, 0x96, 0x00, 0x98, 0x00, 0xCF
-};
-
-static const unsigned int s6e63m0_19_240[] = {
- 0x18, 0x08, 0x24, 0x67, 0x64, 0x3F, 0xBB,
- 0xBE, 0xAD, 0xB3, 0xB9, 0xA7, 0xC8, 0xC9,
- 0xBE, 0x00, 0x90, 0x00, 0x92, 0x00, 0xC8
-};
-
-static const unsigned int s6e63m0_19_220[] = {
- 0x18, 0x08, 0x24, 0x68, 0x64, 0x40, 0xBC,
- 0xBF, 0xAF, 0xB4, 0xBA, 0xA9, 0xC8, 0xCA,
- 0xBE, 0x00, 0x8B, 0x00, 0x8C, 0x00, 0xC0
-};
-
-static const unsigned int s6e63m0_19_200[] = {
- 0x18, 0x08, 0x24, 0x68, 0x64, 0x3F, 0xBE,
- 0xC0, 0xB0, 0xB6, 0xBB, 0xAB, 0xC8, 0xCB,
- 0xBF, 0x00, 0x85, 0x00, 0x86, 0x00, 0xB8
-};
-
-static const unsigned int s6e63m0_19_170[] = {
- 0x18, 0x08, 0x24, 0x69, 0x64, 0x40, 0xBF,
- 0xC1, 0xB0, 0xB9, 0xBE, 0xAD, 0xCB, 0xCD,
- 0xC2, 0x00, 0x7A, 0x00, 0x7B, 0x00, 0xAA
-};
-
-static const unsigned int s6e63m0_19_140[] = {
- 0x18, 0x08, 0x24, 0x6E, 0x65, 0x45, 0xC0,
- 0xC3, 0xB2, 0xBA, 0xBE, 0xAE, 0xCD, 0xD0,
- 0xC4, 0x00, 0x70, 0x00, 0x70, 0x00, 0x9C
-};
-
-static const unsigned int s6e63m0_19_110[] = {
- 0x18, 0x08, 0x24, 0x6F, 0x65, 0x46, 0xC2,
- 0xC4, 0xB3, 0xBF, 0xC2, 0xB2, 0xCF, 0xD1,
- 0xC6, 0x00, 0x64, 0x00, 0x64, 0x00, 0x8D
-};
-
-static const unsigned int s6e63m0_19_90[] = {
- 0x18, 0x08, 0x24, 0x74, 0x60, 0x4A, 0xC3,
- 0xC6, 0xB5, 0xBF, 0xC3, 0xB2, 0xD2, 0xD3,
- 0xC8, 0x00, 0x5B, 0x00, 0x5B, 0x00, 0x81
-};
-
-static const unsigned int s6e63m0_19_30[] = {
- 0x18, 0x08, 0x24, 0x84, 0x45, 0x4F, 0xCA,
- 0xCB, 0xBC, 0xC9, 0xCB, 0xBC, 0xDA, 0xDA,
- 0xD0, 0x00, 0x35, 0x00, 0x34, 0x00, 0x4E
-};
-
-/* gamma value: 1.7 */
-static const unsigned int s6e63m0_17_300[] = {
- 0x18, 0x08, 0x24, 0x70, 0x70, 0x4F, 0xBF,
- 0xC2, 0xB2, 0xB8, 0xBC, 0xAC, 0xCB, 0xCD,
- 0xC3, 0x00, 0xA0, 0x00, 0xA4, 0x00, 0xDB
-};
-
-static const unsigned int s6e63m0_17_280[] = {
- 0x18, 0x08, 0x24, 0x71, 0x71, 0x50, 0xBF,
- 0xC2, 0xB2, 0xBA, 0xBE, 0xAE, 0xCB, 0xCD,
- 0xC3, 0x00, 0x9C, 0x00, 0x9F, 0x00, 0xD6
-};
-
-static const unsigned int s6e63m0_17_260[] = {
- 0x18, 0x08, 0x24, 0x72, 0x72, 0x50, 0xC0,
- 0xC3, 0xB4, 0xB9, 0xBE, 0xAE, 0xCC, 0xCF,
- 0xC4, 0x00, 0x97, 0x00, 0x9A, 0x00, 0xD1
-};
-
-static const unsigned int s6e63m0_17_240[] = {
- 0x18, 0x08, 0x24, 0x71, 0x72, 0x4F, 0xC2,
- 0xC4, 0xB5, 0xBB, 0xBF, 0xB0, 0xCC, 0xCF,
- 0xC3, 0x00, 0x91, 0x00, 0x95, 0x00, 0xCA
-};
-
-static const unsigned int s6e63m0_17_220[] = {
- 0x18, 0x08, 0x24, 0x71, 0x73, 0x4F, 0xC2,
- 0xC5, 0xB5, 0xBD, 0xC0, 0xB2, 0xCD, 0xD1,
- 0xC5, 0x00, 0x8B, 0x00, 0x8E, 0x00, 0xC2
-};
-
-static const unsigned int s6e63m0_17_200[] = {
- 0x18, 0x08, 0x24, 0x72, 0x75, 0x51, 0xC2,
- 0xC6, 0xB5, 0xBF, 0xC1, 0xB3, 0xCE, 0xD1,
- 0xC6, 0x00, 0x85, 0x00, 0x88, 0x00, 0xBA
-};
-
-static const unsigned int s6e63m0_17_170[] = {
- 0x18, 0x08, 0x24, 0x75, 0x77, 0x54, 0xC3,
- 0xC7, 0xB7, 0xC0, 0xC3, 0xB4, 0xD1, 0xD3,
- 0xC9, 0x00, 0x7B, 0x00, 0x7E, 0x00, 0xAB
-};
-
-static const unsigned int s6e63m0_17_140[] = {
- 0x18, 0x08, 0x24, 0x7B, 0x77, 0x58, 0xC3,
- 0xC8, 0xB8, 0xC2, 0xC6, 0xB6, 0xD3, 0xD4,
- 0xCA, 0x00, 0x71, 0x00, 0x73, 0x00, 0x9E
-};
-
-static const unsigned int s6e63m0_17_110[] = {
- 0x18, 0x08, 0x24, 0x81, 0x7B, 0x5D, 0xC6,
- 0xCA, 0xBB, 0xC3, 0xC7, 0xB8, 0xD6, 0xD8,
- 0xCD, 0x00, 0x65, 0x00, 0x67, 0x00, 0x8D
-};
-
-static const unsigned int s6e63m0_17_90[] = {
- 0x18, 0x08, 0x24, 0x82, 0x7A, 0x5B, 0xC8,
- 0xCB, 0xBD, 0xC5, 0xCA, 0xBA, 0xD6, 0xD8,
- 0xCE, 0x00, 0x5D, 0x00, 0x5E, 0x00, 0x82
-};
-
-static const unsigned int s6e63m0_17_30[] = {
- 0x18, 0x08, 0x24, 0x8F, 0x73, 0x63, 0xD1,
- 0xD0, 0xC5, 0xCC, 0xD1, 0xC2, 0xDE, 0xE0,
- 0xD6, 0x00, 0x39, 0x00, 0x36, 0x00, 0x51
-};
-
-struct s6e63m0_gamma {
- unsigned int *gamma_22_table[MAX_GAMMA_LEVEL];
- unsigned int *gamma_19_table[MAX_GAMMA_LEVEL];
- unsigned int *gamma_17_table[MAX_GAMMA_LEVEL];
-};
-
-static struct s6e63m0_gamma gamma_table = {
- .gamma_22_table[0] = (unsigned int *)&s6e63m0_22_30,
- .gamma_22_table[1] = (unsigned int *)&s6e63m0_22_90,
- .gamma_22_table[2] = (unsigned int *)&s6e63m0_22_110,
- .gamma_22_table[3] = (unsigned int *)&s6e63m0_22_140,
- .gamma_22_table[4] = (unsigned int *)&s6e63m0_22_170,
- .gamma_22_table[5] = (unsigned int *)&s6e63m0_22_200,
- .gamma_22_table[6] = (unsigned int *)&s6e63m0_22_220,
- .gamma_22_table[7] = (unsigned int *)&s6e63m0_22_240,
- .gamma_22_table[8] = (unsigned int *)&s6e63m0_22_260,
- .gamma_22_table[9] = (unsigned int *)&s6e63m0_22_280,
- .gamma_22_table[10] = (unsigned int *)&s6e63m0_22_300,
-
- .gamma_19_table[0] = (unsigned int *)&s6e63m0_19_30,
- .gamma_19_table[1] = (unsigned int *)&s6e63m0_19_90,
- .gamma_19_table[2] = (unsigned int *)&s6e63m0_19_110,
- .gamma_19_table[3] = (unsigned int *)&s6e63m0_19_140,
- .gamma_19_table[4] = (unsigned int *)&s6e63m0_19_170,
- .gamma_19_table[5] = (unsigned int *)&s6e63m0_19_200,
- .gamma_19_table[6] = (unsigned int *)&s6e63m0_19_220,
- .gamma_19_table[7] = (unsigned int *)&s6e63m0_19_240,
- .gamma_19_table[8] = (unsigned int *)&s6e63m0_19_260,
- .gamma_19_table[9] = (unsigned int *)&s6e63m0_19_280,
- .gamma_19_table[10] = (unsigned int *)&s6e63m0_19_300,
-
- .gamma_17_table[0] = (unsigned int *)&s6e63m0_17_30,
- .gamma_17_table[1] = (unsigned int *)&s6e63m0_17_90,
- .gamma_17_table[2] = (unsigned int *)&s6e63m0_17_110,
- .gamma_17_table[3] = (unsigned int *)&s6e63m0_17_140,
- .gamma_17_table[4] = (unsigned int *)&s6e63m0_17_170,
- .gamma_17_table[5] = (unsigned int *)&s6e63m0_17_200,
- .gamma_17_table[6] = (unsigned int *)&s6e63m0_17_220,
- .gamma_17_table[7] = (unsigned int *)&s6e63m0_17_240,
- .gamma_17_table[8] = (unsigned int *)&s6e63m0_17_260,
- .gamma_17_table[9] = (unsigned int *)&s6e63m0_17_280,
- .gamma_17_table[10] = (unsigned int *)&s6e63m0_17_300,
-};
-
-#endif
-
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index 591a13a59787..e413f54208f4 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -2,6 +2,12 @@
# fbdev configuration
#
+config FB_CMDLINE
+ bool
+
+config FB_NOTIFY
+ bool
+
menuconfig FB
tristate "Support for frame buffer devices"
select FB_CMDLINE
@@ -41,7 +47,6 @@ menuconfig FB
config FIRMWARE_EDID
bool "Enable firmware EDID"
depends on FB
- default n
---help---
This enables access to the EDID transferred from the firmware.
On the i386, this is from the Video BIOS. Enable this if DDC/I2C
@@ -54,23 +59,15 @@ config FIRMWARE_EDID
combination with certain motherboards and monitors are known to
suffer from this problem.
-config FB_CMDLINE
- bool
-
-config FB_NOTIFY
- bool
-
config FB_DDC
tristate
depends on FB
select I2C_ALGOBIT
select I2C
- default n
config FB_BOOT_VESA_SUPPORT
bool
depends on FB
- default n
---help---
If true, at least one selected framebuffer driver can take advantage
of VESA video modes set at an early boot stage via the vga= parameter.
@@ -78,7 +75,6 @@ config FB_BOOT_VESA_SUPPORT
config FB_CFB_FILLRECT
tristate
depends on FB
- default n
---help---
Include the cfb_fillrect function for generic software rectangle
filling. This is used by drivers that don't provide their own
@@ -87,7 +83,6 @@ config FB_CFB_FILLRECT
config FB_CFB_COPYAREA
tristate
depends on FB
- default n
---help---
Include the cfb_copyarea function for generic software area copying.
This is used by drivers that don't provide their own (accelerated)
@@ -96,7 +91,6 @@ config FB_CFB_COPYAREA
config FB_CFB_IMAGEBLIT
tristate
depends on FB
- default n
---help---
Include the cfb_imageblit function for generic software image
blitting. This is used by drivers that don't provide their own
@@ -105,7 +99,6 @@ config FB_CFB_IMAGEBLIT
config FB_CFB_REV_PIXELS_IN_BYTE
bool
depends on FB
- default n
---help---
Allow generic frame-buffer functions to work on displays with 1, 2
and 4 bits per pixel depths which has opposite order of pixels in
@@ -114,7 +107,6 @@ config FB_CFB_REV_PIXELS_IN_BYTE
config FB_SYS_FILLRECT
tristate
depends on FB
- default n
---help---
Include the sys_fillrect function for generic software rectangle
filling. This is used by drivers that don't provide their own
@@ -123,7 +115,6 @@ config FB_SYS_FILLRECT
config FB_SYS_COPYAREA
tristate
depends on FB
- default n
---help---
Include the sys_copyarea function for generic software area copying.
This is used by drivers that don't provide their own (accelerated)
@@ -132,7 +123,6 @@ config FB_SYS_COPYAREA
config FB_SYS_IMAGEBLIT
tristate
depends on FB
- default n
---help---
Include the sys_imageblit function for generic software image
blitting. This is used by drivers that don't provide their own
@@ -141,7 +131,6 @@ config FB_SYS_IMAGEBLIT
config FB_PROVIDE_GET_FB_UNMAPPED_AREA
bool
depends on FB
- default n
---help---
Allow generic frame-buffer to provide get_fb_unmapped_area
function.
@@ -173,7 +162,6 @@ endchoice
config FB_SYS_FOPS
tristate
depends on FB
- default n
config FB_DEFERRED_IO
bool
@@ -187,7 +175,6 @@ config FB_HECUBA
config FB_SVGALIB
tristate
depends on FB
- default n
---help---
Common utility functions useful to fbdev drivers of VGA-based
cards.
@@ -195,19 +182,16 @@ config FB_SVGALIB
config FB_MACMODES
tristate
depends on FB
- default n
config FB_BACKLIGHT
bool
depends on FB
select BACKLIGHT_LCD_SUPPORT
select BACKLIGHT_CLASS_DEVICE
- default n
config FB_MODE_HELPERS
bool "Enable Video Mode Handling Helpers"
depends on FB
- default n
---help---
This enables functions for handling video modes using the
Generalized Timing Formula and the EDID parser. A few drivers rely
@@ -218,7 +202,6 @@ config FB_MODE_HELPERS
config FB_TILEBLITTING
bool "Enable Tile Blitting Support"
depends on FB
- default n
---help---
This enables tile blitting. Tile blitting is a drawing technique
where the screen is divided into rectangular sections (tiles), whereas
@@ -329,16 +312,9 @@ config FB_ACORN
hardware found in Acorn RISC PCs and other ARM-based machines. If
unsure, say N.
-config FB_CLPS711X_OLD
- tristate
- select FB_CFB_FILLRECT
- select FB_CFB_COPYAREA
- select FB_CFB_IMAGEBLIT
-
config FB_CLPS711X
tristate "CLPS711X LCD support"
depends on FB && (ARCH_CLPS711X || COMPILE_TEST)
- select FB_CLPS711X_OLD if ARCH_CLPS711X && !ARCH_MULTIPLATFORM
select BACKLIGHT_LCD_SUPPORT
select FB_MODE_HELPERS
select FB_SYS_FILLRECT
@@ -936,7 +912,6 @@ config FB_NVIDIA_I2C
config FB_NVIDIA_DEBUG
bool "Lots of debug output"
depends on FB_NVIDIA
- default n
help
Say Y here if you want the nVidia driver to output all sorts
of debugging information to provide to the maintainer when
@@ -983,7 +958,6 @@ config FB_RIVA_I2C
config FB_RIVA_DEBUG
bool "Lots of debug output"
depends on FB_RIVA
- default n
help
Say Y here if you want the Riva driver to output all sorts
of debugging information to provide to the maintainer when
@@ -1266,7 +1240,6 @@ config FB_RADEON_BACKLIGHT
config FB_RADEON_DEBUG
bool "Lots of debug output from Radeon driver"
depends on FB_RADEON
- default n
help
Say Y here if you want the Radeon driver to output all sorts
of debugging information to provide to the maintainer when
@@ -1399,7 +1372,6 @@ config FB_SAVAGE_I2C
config FB_SAVAGE_ACCEL
bool "Enable Console Acceleration"
depends on FB_SAVAGE
- default n
help
This option will compile in console acceleration support. If
the resulting framebuffer console has bothersome glitches, then
@@ -1456,8 +1428,6 @@ if FB_VIA
config FB_VIA_DIRECT_PROCFS
bool "direct hardware access via procfs (DEPRECATED)(DANGEROUS)"
- depends on FB_VIA
- default n
help
Allow direct hardware access to some output registers via procfs.
This is dangerous but may provide the only chance to get the
@@ -1466,8 +1436,6 @@ config FB_VIA_DIRECT_PROCFS
config FB_VIA_X_COMPATIBILITY
bool "X server compatibility"
- depends on FB_VIA
- default n
help
This option reduces the functionality (power saving, ...) of the
framebuffer to avoid negative impact on the OpenChrome X server.
@@ -1692,7 +1660,6 @@ config FB_WM8505
config FB_WMT_GE_ROPS
bool "VT8500/WM8xxx accelerated raster ops support"
depends on (FB = y) && (FB_VT8500 || FB_WM8505)
- default n
help
This adds support for accelerated raster operations on the
VIA VT8500 and Wondermedia 85xx series SoCs.
@@ -1802,17 +1769,14 @@ config FB_PXA
config FB_PXA_OVERLAY
bool "Support PXA27x/PXA3xx Overlay(s) as framebuffer"
- default n
depends on FB_PXA && (PXA27x || PXA3xx)
config FB_PXA_SMARTPANEL
bool "PXA Smartpanel LCD support"
- default n
depends on FB_PXA
config FB_PXA_PARAMETERS
bool "PXA LCD command line parameters"
- default n
depends on FB_PXA
---help---
Enable the use of kernel command line or module parameters
@@ -1850,7 +1814,6 @@ config FB_MBX
config FB_MBX_DEBUG
bool "Enable debugging info via debugfs"
depends on FB_MBX && DEBUG_FS
- default n
---help---
Enable this if you want debugging information using the debug
filesystem (debugfs)
@@ -2240,7 +2203,7 @@ config FB_MX3
config FB_BROADSHEET
tristate "E-Ink Broadsheet/Epson S1D13521 controller support"
- depends on FB
+ depends on FB && (ARCH_PXA || COMPILE_TEST)
select FB_SYS_FILLRECT
select FB_SYS_COPYAREA
select FB_SYS_IMAGEBLIT
@@ -2308,10 +2271,6 @@ config FB_SIMPLE
Configuration re: surface address, size, and format must be provided
through device tree, or plain old platform data.
-source "drivers/video/fbdev/omap/Kconfig"
-source "drivers/video/fbdev/omap2/Kconfig"
-source "drivers/video/fbdev/mmp/Kconfig"
-
config FB_SSD1307
tristate "Solomon SSD1307 framebuffer support"
depends on FB && I2C
@@ -2341,3 +2300,7 @@ config FB_SM712
This driver is also available as a module. The module will be
called sm712fb. If you want to compile it as a module, say M
here and read <file:Documentation/kbuild/modules.txt>.
+
+source "drivers/video/fbdev/omap/Kconfig"
+source "drivers/video/fbdev/omap2/Kconfig"
+source "drivers/video/fbdev/mmp/Kconfig"
diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile
index 13c900320c2c..846b0c9ea9db 100644
--- a/drivers/video/fbdev/Makefile
+++ b/drivers/video/fbdev/Makefile
@@ -14,7 +14,6 @@ obj-$(CONFIG_FB_WMT_GE_ROPS) += wmt_ge_rops.o
obj-$(CONFIG_FB_AMIGA) += amifb.o c2p_planar.o
obj-$(CONFIG_FB_ARC) += arcfb.o
obj-$(CONFIG_FB_CLPS711X) += clps711x-fb.o
-obj-$(CONFIG_FB_CLPS711X_OLD) += clps711xfb.o
obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o
obj-$(CONFIG_FB_GRVGA) += grvga.o
obj-$(CONFIG_FB_PM2) += pm2fb.o
diff --git a/drivers/video/fbdev/arcfb.c b/drivers/video/fbdev/arcfb.c
index 7e87d0d61658..a48741aab240 100644
--- a/drivers/video/fbdev/arcfb.c
+++ b/drivers/video/fbdev/arcfb.c
@@ -419,6 +419,8 @@ static int arcfb_ioctl(struct fb_info *info,
schedule();
finish_wait(&arcfb_waitq, &wait);
}
+ /* fall through */
+
case FBIO_GETCONTROL2:
{
unsigned char ctl2;
diff --git a/drivers/video/fbdev/atmel_lcdfb.c b/drivers/video/fbdev/atmel_lcdfb.c
index 076d24afbd72..4ed55e6bbb84 100644
--- a/drivers/video/fbdev/atmel_lcdfb.c
+++ b/drivers/video/fbdev/atmel_lcdfb.c
@@ -22,6 +22,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <video/of_videomode.h>
#include <video/of_display_timing.h>
#include <linux/regulator/consumer.h>
#include <video/videomode.h>
@@ -1028,11 +1029,11 @@ static int atmel_lcdfb_of_init(struct atmel_lcdfb_info *sinfo)
struct device *dev = &sinfo->pdev->dev;
struct device_node *np =dev->of_node;
struct device_node *display_np;
- struct device_node *timings_np;
- struct display_timings *timings;
struct atmel_lcdfb_power_ctrl_gpio *og;
bool is_gpio_power = false;
+ struct fb_videomode fb_vm;
struct gpio_desc *gpiod;
+ struct videomode vm;
int ret = -ENOENT;
int i;
@@ -1105,44 +1106,18 @@ static int atmel_lcdfb_of_init(struct atmel_lcdfb_info *sinfo)
pdata->lcdcon_is_backlight = of_property_read_bool(display_np, "atmel,lcdcon-backlight");
pdata->lcdcon_pol_negative = of_property_read_bool(display_np, "atmel,lcdcon-backlight-inverted");
- timings = of_get_display_timings(display_np);
- if (!timings) {
- dev_err(dev, "failed to get display timings\n");
- ret = -EINVAL;
+ ret = of_get_videomode(display_np, &vm, OF_USE_NATIVE_MODE);
+ if (ret) {
+ dev_err(dev, "failed to get videomode from DT\n");
goto put_display_node;
}
- timings_np = of_get_child_by_name(display_np, "display-timings");
- if (!timings_np) {
- dev_err(dev, "failed to find display-timings node\n");
- ret = -ENODEV;
+ ret = fb_videomode_from_videomode(&vm, &fb_vm);
+ if (ret < 0)
goto put_display_node;
- }
- for (i = 0; i < of_get_child_count(timings_np); i++) {
- struct videomode vm;
- struct fb_videomode fb_vm;
-
- ret = videomode_from_timings(timings, &vm, i);
- if (ret < 0)
- goto put_timings_node;
- ret = fb_videomode_from_videomode(&vm, &fb_vm);
- if (ret < 0)
- goto put_timings_node;
-
- fb_add_videomode(&fb_vm, &info->modelist);
- }
-
- /*
- * FIXME: Make sure we are not referencing any fields in display_np
- * and timings_np and drop our references to them before returning to
- * avoid leaking the nodes on probe deferral and driver unbind.
- */
-
- return 0;
+ fb_add_videomode(&fb_vm, &info->modelist);
-put_timings_node:
- of_node_put(timings_np);
put_display_node:
of_node_put(display_np);
return ret;
diff --git a/drivers/video/fbdev/aty/atyfb.h b/drivers/video/fbdev/aty/atyfb.h
index 8235b285dbb2..e5a347c58180 100644
--- a/drivers/video/fbdev/aty/atyfb.h
+++ b/drivers/video/fbdev/aty/atyfb.h
@@ -147,6 +147,7 @@ struct atyfb_par {
u16 pci_id;
u32 accel_flags;
int blitter_may_be_busy;
+ unsigned fifo_space;
int asleep;
int lock_blank;
unsigned long res_start;
@@ -333,6 +334,8 @@ extern const struct aty_pll_ops aty_pll_ct; /* Integrated */
extern void aty_set_pll_ct(const struct fb_info *info, const union aty_pll *pll);
extern u8 aty_ld_pll_ct(int offset, const struct atyfb_par *par);
+extern const u8 aty_postdividers[8];
+
/*
* Hardware cursor support
@@ -344,10 +347,13 @@ extern int aty_init_cursor(struct fb_info *info);
* Hardware acceleration
*/
-static inline void wait_for_fifo(u16 entries, const struct atyfb_par *par)
+static inline void wait_for_fifo(u16 entries, struct atyfb_par *par)
{
- while ((aty_ld_le32(FIFO_STAT, par) & 0xffff) >
- ((u32) (0x8000 >> entries)));
+ unsigned fifo_space = par->fifo_space;
+ while (entries > fifo_space) {
+ fifo_space = 16 - fls(aty_ld_le32(FIFO_STAT, par) & 0xffff);
+ }
+ par->fifo_space = fifo_space - entries;
}
static inline void wait_for_idle(struct atyfb_par *par)
@@ -357,9 +363,8 @@ static inline void wait_for_idle(struct atyfb_par *par)
par->blitter_may_be_busy = 0;
}
-extern void aty_reset_engine(const struct atyfb_par *par);
+extern void aty_reset_engine(struct atyfb_par *par);
extern void aty_init_engine(struct atyfb_par *par, struct fb_info *info);
-extern u8 aty_ld_pll_ct(int offset, const struct atyfb_par *par);
void atyfb_copyarea(struct fb_info *info, const struct fb_copyarea *area);
void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
diff --git a/drivers/video/fbdev/aty/atyfb_base.c b/drivers/video/fbdev/aty/atyfb_base.c
index a9a8272f7a6e..b6fe103df145 100644
--- a/drivers/video/fbdev/aty/atyfb_base.c
+++ b/drivers/video/fbdev/aty/atyfb_base.c
@@ -1480,24 +1480,28 @@ static int atyfb_set_par(struct fb_info *info)
base = 0x2000;
printk("debug atyfb: Mach64 non-shadow register values:");
for (i = 0; i < 256; i = i+4) {
- if (i % 16 == 0)
- printk("\ndebug atyfb: 0x%04X: ", base + i);
- printk(" %08X", aty_ld_le32(i, par));
+ if (i % 16 == 0) {
+ pr_cont("\n");
+ printk("debug atyfb: 0x%04X: ", base + i);
+ }
+ pr_cont(" %08X", aty_ld_le32(i, par));
}
- printk("\n\n");
+ pr_cont("\n\n");
#ifdef CONFIG_FB_ATY_CT
/* PLL registers */
base = 0x00;
printk("debug atyfb: Mach64 PLL register values:");
for (i = 0; i < 64; i++) {
- if (i % 16 == 0)
- printk("\ndebug atyfb: 0x%02X: ", base + i);
+ if (i % 16 == 0) {
+ pr_cont("\n");
+ printk("debug atyfb: 0x%02X: ", base + i);
+ }
if (i % 4 == 0)
- printk(" ");
- printk("%02X", aty_ld_pll_ct(i, par));
+ pr_cont(" ");
+ pr_cont("%02X", aty_ld_pll_ct(i, par));
}
- printk("\n\n");
+ pr_cont("\n\n");
#endif /* CONFIG_FB_ATY_CT */
#ifdef CONFIG_FB_ATY_GENERIC_LCD
@@ -1509,19 +1513,19 @@ static int atyfb_set_par(struct fb_info *info)
for (i = 0; i <= POWER_MANAGEMENT; i++) {
if (i == EXT_VERT_STRETCH)
continue;
- printk("\ndebug atyfb: 0x%04X: ",
+ pr_cont("\ndebug atyfb: 0x%04X: ",
lt_lcd_regs[i]);
- printk(" %08X", aty_ld_lcd(i, par));
+ pr_cont(" %08X", aty_ld_lcd(i, par));
}
} else {
for (i = 0; i < 64; i++) {
if (i % 4 == 0)
- printk("\ndebug atyfb: 0x%02X: ",
+ pr_cont("\ndebug atyfb: 0x%02X: ",
base + i);
- printk(" %08X", aty_ld_lcd(i, par));
+ pr_cont(" %08X", aty_ld_lcd(i, par));
}
}
- printk("\n\n");
+ pr_cont("\n\n");
}
#endif /* CONFIG_FB_ATY_GENERIC_LCD */
}
@@ -2597,8 +2601,8 @@ static int aty_init(struct fb_info *info)
aty_ld_le32(DSP_ON_OFF, par),
aty_ld_le32(CLOCK_CNTL, par));
for (i = 0; i < 40; i++)
- printk(" %02x", aty_ld_pll_ct(i, par));
- printk("\n");
+ pr_cont(" %02x", aty_ld_pll_ct(i, par));
+ pr_cont("\n");
}
#endif
if (par->pll_ops->init_pll)
@@ -3087,17 +3091,18 @@ static int atyfb_setup_sparc(struct pci_dev *pdev, struct fb_info *info,
/*
* PLL Reference Divider M:
*/
- M = pll_regs[2];
+ M = pll_regs[PLL_REF_DIV];
/*
* PLL Feedback Divider N (Dependent on CLOCK_CNTL):
*/
- N = pll_regs[7 + (clock_cntl & 3)];
+ N = pll_regs[VCLK0_FB_DIV + (clock_cntl & 3)];
/*
* PLL Post Divider P (Dependent on CLOCK_CNTL):
*/
- P = 1 << (pll_regs[6] >> ((clock_cntl & 3) << 1));
+ P = aty_postdividers[((pll_regs[VCLK_POST_DIV] >> ((clock_cntl & 3) << 1)) & 3) |
+ ((pll_regs[PLL_EXT_CNTL] >> (2 + (clock_cntl & 3))) & 4)];
/*
* PLL Divider Q:
diff --git a/drivers/video/fbdev/aty/mach64_accel.c b/drivers/video/fbdev/aty/mach64_accel.c
index 2541a0e0de76..e4b2c89baee2 100644
--- a/drivers/video/fbdev/aty/mach64_accel.c
+++ b/drivers/video/fbdev/aty/mach64_accel.c
@@ -37,7 +37,7 @@ static u32 rotation24bpp(u32 dx, u32 direction)
return ((rotation << 8) | DST_24_ROTATION_ENABLE);
}
-void aty_reset_engine(const struct atyfb_par *par)
+void aty_reset_engine(struct atyfb_par *par)
{
/* reset engine */
aty_st_le32(GEN_TEST_CNTL,
@@ -50,6 +50,8 @@ void aty_reset_engine(const struct atyfb_par *par)
/* HOST errors */
aty_st_le32(BUS_CNTL,
aty_ld_le32(BUS_CNTL, par) | BUS_HOST_ERR_ACK | BUS_FIFO_ERR_ACK, par);
+
+ par->fifo_space = 0;
}
static void reset_GTC_3D_engine(const struct atyfb_par *par)
@@ -127,7 +129,7 @@ void aty_init_engine(struct atyfb_par *par, struct fb_info *info)
/* set host attributes */
wait_for_fifo(13, par);
- aty_st_le32(HOST_CNTL, 0, par);
+ aty_st_le32(HOST_CNTL, HOST_BYTE_ALIGN, par);
/* set pattern attributes */
aty_st_le32(PAT_REG0, 0, par);
@@ -233,7 +235,8 @@ void atyfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
rotation = rotation24bpp(dx, direction);
}
- wait_for_fifo(4, par);
+ wait_for_fifo(5, par);
+ aty_st_le32(DP_PIX_WIDTH, par->crtc.dp_pix_width, par);
aty_st_le32(DP_SRC, FRGD_SRC_BLIT, par);
aty_st_le32(SRC_Y_X, (sx << 16) | sy, par);
aty_st_le32(SRC_HEIGHT1_WIDTH1, (width << 16) | area->height, par);
@@ -269,7 +272,8 @@ void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
rotation = rotation24bpp(dx, DST_X_LEFT_TO_RIGHT);
}
- wait_for_fifo(3, par);
+ wait_for_fifo(4, par);
+ aty_st_le32(DP_PIX_WIDTH, par->crtc.dp_pix_width, par);
aty_st_le32(DP_FRGD_CLR, color, par);
aty_st_le32(DP_SRC,
BKGD_SRC_BKGD_CLR | FRGD_SRC_FRGD_CLR | MONO_SRC_ONE,
@@ -284,7 +288,7 @@ void atyfb_imageblit(struct fb_info *info, const struct fb_image *image)
{
struct atyfb_par *par = (struct atyfb_par *) info->par;
u32 src_bytes, dx = image->dx, dy = image->dy, width = image->width;
- u32 pix_width_save, pix_width, host_cntl, rotation = 0, src, mix;
+ u32 pix_width, rotation = 0, src, mix;
if (par->asleep)
return;
@@ -296,8 +300,7 @@ void atyfb_imageblit(struct fb_info *info, const struct fb_image *image)
return;
}
- pix_width = pix_width_save = aty_ld_le32(DP_PIX_WIDTH, par);
- host_cntl = aty_ld_le32(HOST_CNTL, par) | HOST_BYTE_ALIGN;
+ pix_width = par->crtc.dp_pix_width;
switch (image->depth) {
case 1:
@@ -345,7 +348,7 @@ void atyfb_imageblit(struct fb_info *info, const struct fb_image *image)
* since Rage 3D IIc we have DP_HOST_TRIPLE_EN bit
* this hwaccelerated triple has an issue with not aligned data
*/
- if (M64_HAS(HW_TRIPLE) && image->width % 8 == 0)
+ if (image->depth == 1 && M64_HAS(HW_TRIPLE) && image->width % 8 == 0)
pix_width |= DP_HOST_TRIPLE_EN;
}
@@ -370,19 +373,18 @@ void atyfb_imageblit(struct fb_info *info, const struct fb_image *image)
mix = FRGD_MIX_D_XOR_S | BKGD_MIX_D;
}
- wait_for_fifo(6, par);
- aty_st_le32(DP_WRITE_MASK, 0xFFFFFFFF, par);
+ wait_for_fifo(5, par);
aty_st_le32(DP_PIX_WIDTH, pix_width, par);
aty_st_le32(DP_MIX, mix, par);
aty_st_le32(DP_SRC, src, par);
- aty_st_le32(HOST_CNTL, host_cntl, par);
+ aty_st_le32(HOST_CNTL, HOST_BYTE_ALIGN, par);
aty_st_le32(DST_CNTL, DST_Y_TOP_TO_BOTTOM | DST_X_LEFT_TO_RIGHT | rotation, par);
draw_rect(dx, dy, width, image->height, par);
src_bytes = (((image->width * image->depth) + 7) / 8) * image->height;
/* manual triple each pixel */
- if (info->var.bits_per_pixel == 24 && !(pix_width & DP_HOST_TRIPLE_EN)) {
+ if (image->depth == 1 && info->var.bits_per_pixel == 24 && !(pix_width & DP_HOST_TRIPLE_EN)) {
int inbit, outbit, mult24, byte_id_in_dword, width;
u8 *pbitmapin = (u8*)image->data, *pbitmapout;
u32 hostdword;
@@ -415,7 +417,7 @@ void atyfb_imageblit(struct fb_info *info, const struct fb_image *image)
}
}
wait_for_fifo(1, par);
- aty_st_le32(HOST_DATA0, hostdword, par);
+ aty_st_le32(HOST_DATA0, le32_to_cpu(hostdword), par);
}
} else {
u32 *pbitmap, dwords = (src_bytes + 3) / 4;
@@ -424,8 +426,4 @@ void atyfb_imageblit(struct fb_info *info, const struct fb_image *image)
aty_st_le32(HOST_DATA0, get_unaligned_le32(pbitmap), par);
}
}
-
- /* restore pix_width */
- wait_for_fifo(1, par);
- aty_st_le32(DP_PIX_WIDTH, pix_width_save, par);
}
diff --git a/drivers/video/fbdev/aty/mach64_ct.c b/drivers/video/fbdev/aty/mach64_ct.c
index 74a62aa193c0..f87cc81f4fa2 100644
--- a/drivers/video/fbdev/aty/mach64_ct.c
+++ b/drivers/video/fbdev/aty/mach64_ct.c
@@ -115,7 +115,7 @@ static void aty_st_pll_ct(int offset, u8 val, const struct atyfb_par *par)
*/
#define Maximum_DSP_PRECISION 7
-static u8 postdividers[] = {1,2,4,8,3};
+const u8 aty_postdividers[8] = {1,2,4,8,3,5,6,12};
static int aty_dsp_gt(const struct fb_info *info, u32 bpp, struct pll_ct *pll)
{
@@ -222,7 +222,7 @@ static int aty_valid_pll_ct(const struct fb_info *info, u32 vclk_per, struct pll
pll->vclk_post_div += (q < 64*8);
pll->vclk_post_div += (q < 32*8);
}
- pll->vclk_post_div_real = postdividers[pll->vclk_post_div];
+ pll->vclk_post_div_real = aty_postdividers[pll->vclk_post_div];
// pll->vclk_post_div <<= 6;
pll->vclk_fb_div = q * pll->vclk_post_div_real / 8;
pllvclk = (1000000 * 2 * pll->vclk_fb_div) /
@@ -513,7 +513,7 @@ static int aty_init_pll_ct(const struct fb_info *info, union aty_pll *pll)
u8 mclk_fb_div, pll_ext_cntl;
pll->ct.pll_ref_div = aty_ld_pll_ct(PLL_REF_DIV, par);
pll_ext_cntl = aty_ld_pll_ct(PLL_EXT_CNTL, par);
- pll->ct.xclk_post_div_real = postdividers[pll_ext_cntl & 0x07];
+ pll->ct.xclk_post_div_real = aty_postdividers[pll_ext_cntl & 0x07];
mclk_fb_div = aty_ld_pll_ct(MCLK_FB_DIV, par);
if (pll_ext_cntl & PLL_MFB_TIMES_4_2B)
mclk_fb_div <<= 1;
@@ -535,7 +535,7 @@ static int aty_init_pll_ct(const struct fb_info *info, union aty_pll *pll)
xpost_div += (q < 64*8);
xpost_div += (q < 32*8);
}
- pll->ct.xclk_post_div_real = postdividers[xpost_div];
+ pll->ct.xclk_post_div_real = aty_postdividers[xpost_div];
pll->ct.mclk_fb_div = q * pll->ct.xclk_post_div_real / 8;
#ifdef CONFIG_PPC
@@ -584,7 +584,7 @@ static int aty_init_pll_ct(const struct fb_info *info, union aty_pll *pll)
mpost_div += (q < 64*8);
mpost_div += (q < 32*8);
}
- sclk_post_div_real = postdividers[mpost_div];
+ sclk_post_div_real = aty_postdividers[mpost_div];
pll->ct.sclk_fb_div = q * sclk_post_div_real / 8;
pll->ct.spll_cntl2 = mpost_div << 4;
#ifdef DEBUG
diff --git a/drivers/video/fbdev/cg14.c b/drivers/video/fbdev/cg14.c
index 8de88b129b62..9af54c2368fd 100644
--- a/drivers/video/fbdev/cg14.c
+++ b/drivers/video/fbdev/cg14.c
@@ -355,9 +355,7 @@ static int cg14_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
static void cg14_init_fix(struct fb_info *info, int linebytes,
struct device_node *dp)
{
- const char *name = dp->name;
-
- strlcpy(info->fix.id, name, sizeof(info->fix.id));
+ snprintf(info->fix.id, sizeof(info->fix.id), "%pOFn", dp);
info->fix.type = FB_TYPE_PACKED_PIXELS;
info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
diff --git a/drivers/video/fbdev/cg3.c b/drivers/video/fbdev/cg3.c
index 6c334260cf53..1bd95b02f3aa 100644
--- a/drivers/video/fbdev/cg3.c
+++ b/drivers/video/fbdev/cg3.c
@@ -246,7 +246,7 @@ static int cg3_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
static void cg3_init_fix(struct fb_info *info, int linebytes,
struct device_node *dp)
{
- strlcpy(info->fix.id, dp->name, sizeof(info->fix.id));
+ snprintf(info->fix.id, sizeof(info->fix.id), "%pOFn", dp);
info->fix.type = FB_TYPE_PACKED_PIXELS;
info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
diff --git a/drivers/video/fbdev/chipsfb.c b/drivers/video/fbdev/chipsfb.c
index f103665cad43..40182ed85648 100644
--- a/drivers/video/fbdev/chipsfb.c
+++ b/drivers/video/fbdev/chipsfb.c
@@ -27,7 +27,6 @@
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/console.h>
-#include <asm/io.h>
#ifdef CONFIG_PMAC_BACKLIGHT
#include <asm/backlight.h>
@@ -401,7 +400,7 @@ static int chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent)
#endif /* CONFIG_PMAC_BACKLIGHT */
#ifdef CONFIG_PPC
- p->screen_base = __ioremap(addr, 0x200000, _PAGE_NO_CACHE);
+ p->screen_base = ioremap_wc(addr, 0x200000);
#else
p->screen_base = ioremap(addr, 0x200000);
#endif
diff --git a/drivers/video/fbdev/clps711xfb.c b/drivers/video/fbdev/clps711xfb.c
deleted file mode 100644
index 7693aea8fb23..000000000000
--- a/drivers/video/fbdev/clps711xfb.c
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * linux/drivers/video/clps711xfb.c
- *
- * Copyright (C) 2000-2001 Deep Blue Solutions Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Framebuffer driver for the CLPS7111 and EP7212 processors.
- */
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/fb.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-
-#include <mach/hardware.h>
-#include <asm/mach-types.h>
-#include <linux/uaccess.h>
-
-struct fb_info *cfb;
-
-#define CMAP_MAX_SIZE 16
-
-/*
- * LCD AC Prescale. This comes from the LCD panel manufacturers specifications.
- * This determines how many clocks + 1 of CL1 before the M signal toggles.
- * The number of lines on the display must not be divisible by this number.
- */
-static unsigned int lcd_ac_prescale = 13;
-
-/*
- * Set a single color register. Return != 0 for invalid regno.
- */
-static int
-clps7111fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp, struct fb_info *info)
-{
- unsigned int level, mask, shift, pal;
-
- if (regno >= (1 << info->var.bits_per_pixel))
- return 1;
-
- /* gray = 0.30*R + 0.58*G + 0.11*B */
- level = (red * 77 + green * 151 + blue * 28) >> 20;
-
- /*
- * On an LCD, a high value is dark, while a low value is light.
- * So we invert the level.
- *
- * This isn't true on all machines, so we only do it on EDB7211.
- * --rmk
- */
- if (machine_is_edb7211()) {
- level = 15 - level;
- }
-
- shift = 4 * (regno & 7);
- level <<= shift;
- mask = 15 << shift;
- level &= mask;
-
- regno = regno < 8 ? PALLSW : PALMSW;
-
- pal = clps_readl(regno);
- pal = (pal & ~mask) | level;
- clps_writel(pal, regno);
-
- return 0;
-}
-
-/*
- * Validate the purposed mode.
- */
-static int
-clps7111fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
-{
- var->transp.msb_right = 0;
- var->transp.offset = 0;
- var->transp.length = 0;
- var->red.msb_right = 0;
- var->red.offset = 0;
- var->red.length = var->bits_per_pixel;
- var->green = var->red;
- var->blue = var->red;
-
- if (var->bits_per_pixel > 4)
- return -EINVAL;
-
- return 0;
-}
-
-/*
- * Set the hardware state.
- */
-static int
-clps7111fb_set_par(struct fb_info *info)
-{
- unsigned int lcdcon, syscon, pixclock;
-
- switch (info->var.bits_per_pixel) {
- case 1:
- info->fix.visual = FB_VISUAL_MONO01;
- break;
- case 2:
- info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
- break;
- case 4:
- info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
- break;
- }
-
- info->fix.line_length = info->var.xres_virtual * info->var.bits_per_pixel / 8;
-
- lcdcon = (info->var.xres_virtual * info->var.yres_virtual * info->var.bits_per_pixel) / 128 - 1;
- lcdcon |= ((info->var.xres_virtual / 16) - 1) << 13;
- lcdcon |= lcd_ac_prescale << 25;
-
- /*
- * Calculate pixel prescale value from the pixclock. This is:
- * 36.864MHz / pixclock_mhz - 1.
- * However, pixclock is in picoseconds, so this ends up being:
- * 36864000 * pixclock_ps / 10^12 - 1
- * and this will overflow the 32-bit math. We perform this as
- * (9 * 4096000 == 36864000):
- * pixclock_ps * 9 * (4096000 / 10^12) - 1
- */
- pixclock = 9 * info->var.pixclock / 244140 - 1;
- lcdcon |= pixclock << 19;
-
- if (info->var.bits_per_pixel == 4)
- lcdcon |= LCDCON_GSMD;
- if (info->var.bits_per_pixel >= 2)
- lcdcon |= LCDCON_GSEN;
-
- /*
- * LCDCON must only be changed while the LCD is disabled
- */
- syscon = clps_readl(SYSCON1);
- clps_writel(syscon & ~SYSCON1_LCDEN, SYSCON1);
- clps_writel(lcdcon, LCDCON);
- clps_writel(syscon | SYSCON1_LCDEN, SYSCON1);
- return 0;
-}
-
-static int clps7111fb_blank(int blank, struct fb_info *info)
-{
- /* Enable/Disable LCD controller. */
- if (blank)
- clps_writel(clps_readl(SYSCON1) & ~SYSCON1_LCDEN, SYSCON1);
- else
- clps_writel(clps_readl(SYSCON1) | SYSCON1_LCDEN, SYSCON1);
-
- return 0;
-}
-
-static struct fb_ops clps7111fb_ops = {
- .owner = THIS_MODULE,
- .fb_check_var = clps7111fb_check_var,
- .fb_set_par = clps7111fb_set_par,
- .fb_setcolreg = clps7111fb_setcolreg,
- .fb_blank = clps7111fb_blank,
- .fb_fillrect = cfb_fillrect,
- .fb_copyarea = cfb_copyarea,
- .fb_imageblit = cfb_imageblit,
-};
-
-static void clps711x_guess_lcd_params(struct fb_info *info)
-{
- unsigned int lcdcon, syscon, size;
- unsigned long phys_base = PAGE_OFFSET;
- void *virt_base = (void *)PAGE_OFFSET;
-
- info->var.xres_virtual = 640;
- info->var.yres_virtual = 240;
- info->var.bits_per_pixel = 4;
- info->var.activate = FB_ACTIVATE_NOW;
- info->var.height = -1;
- info->var.width = -1;
- info->var.pixclock = 93006; /* 10.752MHz pixel clock */
-
- /*
- * If the LCD controller is already running, decode the values
- * in LCDCON to xres/yres/bpp/pixclock/acprescale
- */
- syscon = clps_readl(SYSCON1);
- if (syscon & SYSCON1_LCDEN) {
- lcdcon = clps_readl(LCDCON);
-
- /*
- * Decode GSMD and GSEN bits to bits per pixel
- */
- switch (lcdcon & (LCDCON_GSMD | LCDCON_GSEN)) {
- case LCDCON_GSMD | LCDCON_GSEN:
- info->var.bits_per_pixel = 4;
- break;
-
- case LCDCON_GSEN:
- info->var.bits_per_pixel = 2;
- break;
-
- default:
- info->var.bits_per_pixel = 1;
- break;
- }
-
- /*
- * Decode xres/yres
- */
- info->var.xres_virtual = (((lcdcon >> 13) & 0x3f) + 1) * 16;
- info->var.yres_virtual = (((lcdcon & 0x1fff) + 1) * 128) /
- (info->var.xres_virtual *
- info->var.bits_per_pixel);
-
- /*
- * Calculate pixclock
- */
- info->var.pixclock = (((lcdcon >> 19) & 0x3f) + 1) * 244140 / 9;
-
- /*
- * Grab AC prescale
- */
- lcd_ac_prescale = (lcdcon >> 25) & 0x1f;
- }
-
- info->var.xres = info->var.xres_virtual;
- info->var.yres = info->var.yres_virtual;
- info->var.grayscale = info->var.bits_per_pixel > 1;
-
- size = info->var.xres * info->var.yres * info->var.bits_per_pixel / 8;
-
- /*
- * Might be worth checking to see if we can use the on-board
- * RAM if size here...
- * CLPS7110 - no on-board SRAM
- * EP7212 - 38400 bytes
- */
- if (size <= 38400) {
- printk(KERN_INFO "CLPS711xFB: could use on-board SRAM?\n");
- }
-
- if ((syscon & SYSCON1_LCDEN) == 0) {
- /*
- * The display isn't running. Ensure that
- * the display memory is empty.
- */
- memset(virt_base, 0, size);
- }
-
- info->screen_base = virt_base;
- info->fix.smem_start = phys_base;
- info->fix.smem_len = PAGE_ALIGN(size);
- info->fix.type = FB_TYPE_PACKED_PIXELS;
-}
-
-static int clps711x_fb_probe(struct platform_device *pdev)
-{
- int err = -ENOMEM;
-
- if (fb_get_options("clps711xfb", NULL))
- return -ENODEV;
-
- cfb = kzalloc(sizeof(*cfb), GFP_KERNEL);
- if (!cfb)
- goto out;
-
- strcpy(cfb->fix.id, "clps711x");
-
- cfb->fbops = &clps7111fb_ops;
- cfb->flags = FBINFO_DEFAULT;
-
- clps711x_guess_lcd_params(cfb);
-
- fb_alloc_cmap(&cfb->cmap, CMAP_MAX_SIZE, 0);
-
- err = register_framebuffer(cfb);
-
-out: return err;
-}
-
-static int clps711x_fb_remove(struct platform_device *pdev)
-{
- unregister_framebuffer(cfb);
- kfree(cfb);
-
- return 0;
-}
-
-static struct platform_driver clps711x_fb_driver = {
- .driver = {
- .name = "video-clps711x",
- },
- .probe = clps711x_fb_probe,
- .remove = clps711x_fb_remove,
-};
-module_platform_driver(clps711x_fb_driver);
-
-MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
-MODULE_DESCRIPTION("CLPS711X framebuffer driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/controlfb.c b/drivers/video/fbdev/controlfb.c
index 8d14b29aafea..9cb0ef7ac29e 100644
--- a/drivers/video/fbdev/controlfb.c
+++ b/drivers/video/fbdev/controlfb.c
@@ -48,9 +48,7 @@
#include <linux/nvram.h>
#include <linux/adb.h>
#include <linux/cuda.h>
-#include <asm/io.h>
#include <asm/prom.h>
-#include <asm/pgtable.h>
#include <asm/btext.h>
#include "macmodes.h"
@@ -715,8 +713,7 @@ static int __init control_of_init(struct device_node *dp)
goto error_out;
}
/* map at most 8MB for the frame buffer */
- p->frame_buffer = __ioremap(p->frame_buffer_phys, 0x800000,
- _PAGE_WRITETHRU);
+ p->frame_buffer = ioremap_wt(p->frame_buffer_phys, 0x800000);
if (!p->control_regs_phys ||
!request_mem_region(p->control_regs_phys, p->control_regs_size,
diff --git a/drivers/video/fbdev/core/fbmon.c b/drivers/video/fbdev/core/fbmon.c
index 852d86c1c527..dd3128990776 100644
--- a/drivers/video/fbdev/core/fbmon.c
+++ b/drivers/video/fbdev/core/fbmon.c
@@ -1480,8 +1480,8 @@ int of_get_fb_videomode(struct device_node *np, struct fb_videomode *fb,
if (ret)
return ret;
- pr_debug("%pOF: got %dx%d display mode from %s\n",
- np, vm.hactive, vm.vactive, np->name);
+ pr_debug("%pOF: got %dx%d display mode\n",
+ np, vm.hactive, vm.vactive);
dump_fb_videomode(fb);
return 0;
diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c
index 3946649b85c8..ba906876cc45 100644
--- a/drivers/video/fbdev/efifb.c
+++ b/drivers/video/fbdev/efifb.c
@@ -42,6 +42,7 @@ struct bmp_dib_header {
u32 colors_important;
} __packed;
+static bool use_bgrt = true;
static bool request_mem_succeeded = false;
static u64 mem_flags = EFI_MEMORY_WC | EFI_MEMORY_UC;
@@ -160,6 +161,9 @@ static void efifb_show_boot_graphics(struct fb_info *info)
void *bgrt_image = NULL;
u8 *dst = info->screen_base;
+ if (!use_bgrt)
+ return;
+
if (!bgrt_tab.image_address) {
pr_info("efifb: No BGRT, not showing boot graphics\n");
return;
@@ -290,6 +294,8 @@ static int efifb_setup(char *options)
screen_info.lfb_width = simple_strtoul(this_opt+6, NULL, 0);
else if (!strcmp(this_opt, "nowc"))
mem_flags &= ~EFI_MEMORY_WC;
+ else if (!strcmp(this_opt, "nobgrt"))
+ use_bgrt = false;
}
}
diff --git a/drivers/video/fbdev/fsl-diu-fb.c b/drivers/video/fbdev/fsl-diu-fb.c
index bc9eb8afc313..332a56b6811f 100644
--- a/drivers/video/fbdev/fsl-diu-fb.c
+++ b/drivers/video/fbdev/fsl-diu-fb.c
@@ -1925,7 +1925,7 @@ static int __init fsl_diu_init(void)
pr_info("Freescale Display Interface Unit (DIU) framebuffer driver\n");
#ifdef CONFIG_NOT_COHERENT_CACHE
- np = of_find_node_by_type(NULL, "cpu");
+ np = of_get_cpu_node(0, NULL);
if (!np) {
pr_err("fsl-diu-fb: can't find 'cpu' device node\n");
return -ENODEV;
diff --git a/drivers/video/fbdev/imsttfb.c b/drivers/video/fbdev/imsttfb.c
index ecdcf358ad5e..901ca4ed10e9 100644
--- a/drivers/video/fbdev/imsttfb.c
+++ b/drivers/video/fbdev/imsttfb.c
@@ -1473,7 +1473,7 @@ static int imsttfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
dp = pci_device_to_OF_node(pdev);
if(dp)
- printk(KERN_INFO "%s: OF name %s\n",__func__, dp->name);
+ printk(KERN_INFO "%s: OF name %pOFn\n",__func__, dp);
else if (IS_ENABLED(CONFIG_OF))
printk(KERN_ERR "imsttfb: no OF node for pci device\n");
diff --git a/drivers/video/fbdev/leo.c b/drivers/video/fbdev/leo.c
index 71862188f528..446ac3364bad 100644
--- a/drivers/video/fbdev/leo.c
+++ b/drivers/video/fbdev/leo.c
@@ -434,7 +434,7 @@ static int leo_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
static void
leo_init_fix(struct fb_info *info, struct device_node *dp)
{
- strlcpy(info->fix.id, dp->name, sizeof(info->fix.id));
+ snprintf(info->fix.id, sizeof(info->fix.id), "%pOFn", dp);
info->fix.type = FB_TYPE_PACKED_PIXELS;
info->fix.visual = FB_VISUAL_TRUECOLOR;
diff --git a/drivers/video/fbdev/mmp/hw/Kconfig b/drivers/video/fbdev/mmp/hw/Kconfig
index c735d133895c..fcb711143fb2 100644
--- a/drivers/video/fbdev/mmp/hw/Kconfig
+++ b/drivers/video/fbdev/mmp/hw/Kconfig
@@ -3,7 +3,6 @@ if MMP_DISP
config MMP_DISP_CONTROLLER
bool "mmp display controller hw support"
depends on CPU_PXA910 || CPU_MMP2
- default n
help
Marvell MMP display hw controller support
this controller is used on Marvell PXA910 and
diff --git a/drivers/video/fbdev/mmp/panel/Kconfig b/drivers/video/fbdev/mmp/panel/Kconfig
index 808890f7064b..f58558795f39 100644
--- a/drivers/video/fbdev/mmp/panel/Kconfig
+++ b/drivers/video/fbdev/mmp/panel/Kconfig
@@ -2,6 +2,5 @@
config MMP_PANEL_TPOHVGA
bool "tpohvga panel TJ032MD01BW support"
depends on SPI_MASTER
- default n
help
tpohvga panel support
diff --git a/drivers/video/fbdev/offb.c b/drivers/video/fbdev/offb.c
index 77c0a2f45b3b..31f769d67195 100644
--- a/drivers/video/fbdev/offb.c
+++ b/drivers/video/fbdev/offb.c
@@ -419,9 +419,13 @@ static void __init offb_init_fb(const char *name,
var = &info->var;
info->par = par;
- strcpy(fix->id, "OFfb ");
- strncat(fix->id, name, sizeof(fix->id) - sizeof("OFfb "));
- fix->id[sizeof(fix->id) - 1] = '\0';
+ if (name) {
+ strcpy(fix->id, "OFfb ");
+ strncat(fix->id, name, sizeof(fix->id) - sizeof("OFfb "));
+ fix->id[sizeof(fix->id) - 1] = '\0';
+ } else
+ snprintf(fix->id, sizeof(fix->id), "OFfb %pOFn", dp);
+
var->xres = var->xres_virtual = width;
var->yres = var->yres_virtual = height;
@@ -644,7 +648,7 @@ static void __init offb_init_nodriver(struct device_node *dp, int no_real_node)
/* kludge for valkyrie */
if (strcmp(dp->name, "valkyrie") == 0)
address += 0x1000;
- offb_init_fb(no_real_node ? "bootx" : dp->name,
+ offb_init_fb(no_real_node ? "bootx" : NULL,
width, height, depth, pitch, address,
foreign_endian, no_real_node ? NULL : dp);
}
diff --git a/drivers/video/fbdev/omap/lcd_ams_delta.c b/drivers/video/fbdev/omap/lcd_ams_delta.c
index e8c748a0dfe2..cddbd00cbf9f 100644
--- a/drivers/video/fbdev/omap/lcd_ams_delta.c
+++ b/drivers/video/fbdev/omap/lcd_ams_delta.c
@@ -24,11 +24,10 @@
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
#include <linux/lcd.h>
-#include <linux/gpio.h>
#include <mach/hardware.h>
-#include <mach/board-ams-delta.h>
#include "omapfb.h"
@@ -41,6 +40,8 @@
/* LCD class device section */
static int ams_delta_lcd;
+static struct gpio_desc *gpiod_vblen;
+static struct gpio_desc *gpiod_ndisp;
static int ams_delta_lcd_set_power(struct lcd_device *dev, int power)
{
@@ -99,41 +100,17 @@ static struct lcd_ops ams_delta_lcd_ops = {
/* omapfb panel section */
-static const struct gpio _gpios[] = {
- {
- .gpio = AMS_DELTA_GPIO_PIN_LCD_VBLEN,
- .flags = GPIOF_OUT_INIT_LOW,
- .label = "lcd_vblen",
- },
- {
- .gpio = AMS_DELTA_GPIO_PIN_LCD_NDISP,
- .flags = GPIOF_OUT_INIT_LOW,
- .label = "lcd_ndisp",
- },
-};
-
-static int ams_delta_panel_init(struct lcd_panel *panel,
- struct omapfb_device *fbdev)
-{
- return gpio_request_array(_gpios, ARRAY_SIZE(_gpios));
-}
-
-static void ams_delta_panel_cleanup(struct lcd_panel *panel)
-{
- gpio_free_array(_gpios, ARRAY_SIZE(_gpios));
-}
-
static int ams_delta_panel_enable(struct lcd_panel *panel)
{
- gpio_set_value(AMS_DELTA_GPIO_PIN_LCD_NDISP, 1);
- gpio_set_value(AMS_DELTA_GPIO_PIN_LCD_VBLEN, 1);
+ gpiod_set_value(gpiod_ndisp, 1);
+ gpiod_set_value(gpiod_vblen, 1);
return 0;
}
static void ams_delta_panel_disable(struct lcd_panel *panel)
{
- gpio_set_value(AMS_DELTA_GPIO_PIN_LCD_VBLEN, 0);
- gpio_set_value(AMS_DELTA_GPIO_PIN_LCD_NDISP, 0);
+ gpiod_set_value(gpiod_vblen, 0);
+ gpiod_set_value(gpiod_ndisp, 0);
}
static struct lcd_panel ams_delta_panel = {
@@ -154,8 +131,6 @@ static struct lcd_panel ams_delta_panel = {
.pcd = 0,
.acb = 37,
- .init = ams_delta_panel_init,
- .cleanup = ams_delta_panel_cleanup,
.enable = ams_delta_panel_enable,
.disable = ams_delta_panel_disable,
};
@@ -166,9 +141,23 @@ static struct lcd_panel ams_delta_panel = {
static int ams_delta_panel_probe(struct platform_device *pdev)
{
struct lcd_device *lcd_device = NULL;
-#ifdef CONFIG_LCD_CLASS_DEVICE
int ret;
+ gpiod_vblen = devm_gpiod_get(&pdev->dev, "vblen", GPIOD_OUT_LOW);
+ if (IS_ERR(gpiod_vblen)) {
+ ret = PTR_ERR(gpiod_vblen);
+ dev_err(&pdev->dev, "VBLEN GPIO request failed (%d)\n", ret);
+ return ret;
+ }
+
+ gpiod_ndisp = devm_gpiod_get(&pdev->dev, "ndisp", GPIOD_OUT_LOW);
+ if (IS_ERR(gpiod_ndisp)) {
+ ret = PTR_ERR(gpiod_ndisp);
+ dev_err(&pdev->dev, "NDISP GPIO request failed (%d)\n", ret);
+ return ret;
+ }
+
+#ifdef CONFIG_LCD_CLASS_DEVICE
lcd_device = lcd_device_register("omapfb", &pdev->dev, NULL,
&ams_delta_lcd_ops);
diff --git a/drivers/video/fbdev/omap2/omapfb/dss/Kconfig b/drivers/video/fbdev/omap2/omapfb/dss/Kconfig
index 6d0bb27e4f85..356b89b378d4 100644
--- a/drivers/video/fbdev/omap2/omapfb/dss/Kconfig
+++ b/drivers/video/fbdev/omap2/omapfb/dss/Kconfig
@@ -10,7 +10,6 @@ config FB_OMAP2_DSS
config FB_OMAP2_DSS_DEBUG
bool "Debug support"
- default n
help
This enables printing of debug messages. Alternatively, debug messages
can also be enabled by setting CONFIG_DYNAMIC_DEBUG and then setting
@@ -19,7 +18,6 @@ config FB_OMAP2_DSS_DEBUG
config FB_OMAP2_DSS_DEBUGFS
bool "Debugfs filesystem support"
depends on DEBUG_FS
- default n
help
This enables debugfs for OMAPDSS at <debugfs>/omapdss. This enables
querying about clock configuration and register configuration of dss,
@@ -28,7 +26,6 @@ config FB_OMAP2_DSS_DEBUGFS
config FB_OMAP2_DSS_COLLECT_IRQ_STATS
bool "Collect DSS IRQ statistics"
depends on FB_OMAP2_DSS_DEBUGFS
- default n
help
Collect DSS IRQ statistics, printable via debugfs.
@@ -45,7 +42,6 @@ config FB_OMAP2_DSS_DPI
config FB_OMAP2_DSS_RFBI
bool "RFBI support"
depends on BROKEN
- default n
help
MIPI DBI support (RFBI, Remote Framebuffer Interface, in Texas
Instrument's terminology).
@@ -73,7 +69,6 @@ config FB_OMAP4_DSS_HDMI
config FB_OMAP5_DSS_HDMI
bool "HDMI support for OMAP5"
- default n
select FB_OMAP2_DSS_HDMI_COMMON
help
HDMI Interface for OMAP5 and similar cores. This adds the High
@@ -82,7 +77,6 @@ config FB_OMAP5_DSS_HDMI
config FB_OMAP2_DSS_SDI
bool "SDI support"
- default n
help
SDI (Serial Display Interface) support.
@@ -91,7 +85,6 @@ config FB_OMAP2_DSS_SDI
config FB_OMAP2_DSS_DSI
bool "DSI support"
- default n
help
MIPI DSI (Display Serial Interface) support.
diff --git a/drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c b/drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c
index ef69273074ba..a3edb20ea4c3 100644
--- a/drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c
+++ b/drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c
@@ -496,6 +496,9 @@ static int omapfb_memory_read(struct fb_info *fbi,
if (!access_ok(VERIFY_WRITE, mr->buffer, mr->buffer_size))
return -EFAULT;
+ if (mr->w > 4096 || mr->h > 4096)
+ return -EINVAL;
+
if (mr->w * mr->h * 3 > mr->buffer_size)
return -EINVAL;
@@ -509,7 +512,7 @@ static int omapfb_memory_read(struct fb_info *fbi,
mr->x, mr->y, mr->w, mr->h);
if (r > 0) {
- if (copy_to_user(mr->buffer, buf, mr->buffer_size))
+ if (copy_to_user(mr->buffer, buf, r))
r = -EFAULT;
}
diff --git a/drivers/video/fbdev/p9100.c b/drivers/video/fbdev/p9100.c
index 64de5cda541d..c4283e9e95af 100644
--- a/drivers/video/fbdev/p9100.c
+++ b/drivers/video/fbdev/p9100.c
@@ -239,7 +239,7 @@ static int p9100_ioctl(struct fb_info *info, unsigned int cmd,
static void p9100_init_fix(struct fb_info *info, int linebytes, struct device_node *dp)
{
- strlcpy(info->fix.id, dp->name, sizeof(info->fix.id));
+ snprintf(info->fix.id, sizeof(info->fix.id), "%pOFn", dp);
info->fix.type = FB_TYPE_PACKED_PIXELS;
info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
diff --git a/drivers/video/fbdev/platinumfb.c b/drivers/video/fbdev/platinumfb.c
index 377d3399a3ad..bf6b7fb83cf4 100644
--- a/drivers/video/fbdev/platinumfb.c
+++ b/drivers/video/fbdev/platinumfb.c
@@ -32,9 +32,7 @@
#include <linux/nvram.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
-#include <asm/io.h>
#include <asm/prom.h>
-#include <asm/pgtable.h>
#include "macmodes.h"
#include "platinumfb.h"
@@ -577,8 +575,7 @@ static int platinumfb_probe(struct platform_device* odev)
/* frame buffer - map only 4MB */
pinfo->frame_buffer_phys = pinfo->rsrc_fb.start;
- pinfo->frame_buffer = __ioremap(pinfo->rsrc_fb.start, 0x400000,
- _PAGE_WRITETHRU);
+ pinfo->frame_buffer = ioremap_wt(pinfo->rsrc_fb.start, 0x400000);
pinfo->base_frame_buffer = pinfo->frame_buffer;
/* registers */
diff --git a/drivers/video/fbdev/pxa168fb.c b/drivers/video/fbdev/pxa168fb.c
index def3a501acd6..e31340fad3c7 100644
--- a/drivers/video/fbdev/pxa168fb.c
+++ b/drivers/video/fbdev/pxa168fb.c
@@ -405,9 +405,6 @@ static int pxa168fb_set_par(struct fb_info *info)
struct fb_var_screeninfo *var = &info->var;
struct fb_videomode mode;
u32 x;
- struct pxa168fb_mach_info *mi;
-
- mi = dev_get_platdata(fbi->dev);
/*
* Set additional mode info.
@@ -712,7 +709,7 @@ static int pxa168fb_probe(struct platform_device *pdev)
/*
* enable controller clock
*/
- clk_enable(fbi->clk);
+ clk_prepare_enable(fbi->clk);
pxa168fb_set_par(info);
@@ -767,7 +764,7 @@ static int pxa168fb_probe(struct platform_device *pdev)
failed_free_cmap:
fb_dealloc_cmap(&info->cmap);
failed_free_clk:
- clk_disable(fbi->clk);
+ clk_disable_unprepare(fbi->clk);
failed_free_fbmem:
dma_free_coherent(fbi->dev, info->fix.smem_len,
info->screen_base, fbi->fb_start_dma);
@@ -807,7 +804,7 @@ static int pxa168fb_remove(struct platform_device *pdev)
dma_free_wc(fbi->dev, PAGE_ALIGN(info->fix.smem_len),
info->screen_base, info->fix.smem_start);
- clk_disable(fbi->clk);
+ clk_disable_unprepare(fbi->clk);
framebuffer_release(info);
diff --git a/drivers/video/fbdev/sbuslib.c b/drivers/video/fbdev/sbuslib.c
index a436d44f1b7f..01a7110e61a7 100644
--- a/drivers/video/fbdev/sbuslib.c
+++ b/drivers/video/fbdev/sbuslib.c
@@ -106,11 +106,11 @@ int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg,
struct fbtype __user *f = (struct fbtype __user *) arg;
if (put_user(type, &f->fb_type) ||
- __put_user(info->var.yres, &f->fb_height) ||
- __put_user(info->var.xres, &f->fb_width) ||
- __put_user(fb_depth, &f->fb_depth) ||
- __put_user(0, &f->fb_cmsize) ||
- __put_user(fb_size, &f->fb_cmsize))
+ put_user(info->var.yres, &f->fb_height) ||
+ put_user(info->var.xres, &f->fb_width) ||
+ put_user(fb_depth, &f->fb_depth) ||
+ put_user(0, &f->fb_cmsize) ||
+ put_user(fb_size, &f->fb_cmsize))
return -EFAULT;
return 0;
}
@@ -125,10 +125,10 @@ int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg,
unsigned int index, count, i;
if (get_user(index, &c->index) ||
- __get_user(count, &c->count) ||
- __get_user(ured, &c->red) ||
- __get_user(ugreen, &c->green) ||
- __get_user(ublue, &c->blue))
+ get_user(count, &c->count) ||
+ get_user(ured, &c->red) ||
+ get_user(ugreen, &c->green) ||
+ get_user(ublue, &c->blue))
return -EFAULT;
cmap.len = 1;
@@ -165,13 +165,13 @@ int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg,
u8 red, green, blue;
if (get_user(index, &c->index) ||
- __get_user(count, &c->count) ||
- __get_user(ured, &c->red) ||
- __get_user(ugreen, &c->green) ||
- __get_user(ublue, &c->blue))
+ get_user(count, &c->count) ||
+ get_user(ured, &c->red) ||
+ get_user(ugreen, &c->green) ||
+ get_user(ublue, &c->blue))
return -EFAULT;
- if (index + count > cmap->len)
+ if (index > cmap->len || count > cmap->len - index)
return -EINVAL;
for (i = 0; i < count; i++) {
diff --git a/drivers/video/fbdev/sh7760fb.c b/drivers/video/fbdev/sh7760fb.c
index 96de91d76623..405715b60ec7 100644
--- a/drivers/video/fbdev/sh7760fb.c
+++ b/drivers/video/fbdev/sh7760fb.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* SH7760/SH7763 LCDC Framebuffer driver.
*
@@ -5,10 +6,6 @@
* Manuel Lauss <mano@roarinelk.homelinux.net>
* (c) 2008 Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.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.
- *
* PLEASE HAVE A LOOK AT Documentation/fb/sh7760fb.txt!
*
* Thanks to Siegfried Schaefer <s.schaefer at schaefer-edv.de>
@@ -587,4 +584,4 @@ module_platform_driver(sh7760_lcdc_driver);
MODULE_AUTHOR("Nobuhiro Iwamatsu, Manuel Lauss");
MODULE_DESCRIPTION("FBdev for SH7760/63 integrated LCD Controller");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/fbdev/sis/init301.c b/drivers/video/fbdev/sis/init301.c
index 27a2b72e50e8..a8fb41f1a258 100644
--- a/drivers/video/fbdev/sis/init301.c
+++ b/drivers/video/fbdev/sis/init301.c
@@ -848,9 +848,7 @@ SiS_PanelDelay(struct SiS_Private *SiS_Pr, unsigned short DelayTime)
SiS_DDC2Delay(SiS_Pr, 0x4000);
}
- } else if((SiS_Pr->SiS_IF_DEF_LVDS == 1) /* ||
- (SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) ||
- (SiS_Pr->SiS_CustomT == CUT_CLEVO1400) */ ) { /* 315 series, LVDS; Special */
+ } else if (SiS_Pr->SiS_IF_DEF_LVDS == 1) { /* 315 series, LVDS; Special */
if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) {
PanelID = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36);
diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c
index 6439231f2db2..4061a20cfe24 100644
--- a/drivers/video/fbdev/ssd1307fb.c
+++ b/drivers/video/fbdev/ssd1307fb.c
@@ -667,9 +667,9 @@ static int ssd1307fb_probe(struct i2c_client *client,
if (par->reset) {
/* Reset the screen */
- gpiod_set_value(par->reset, 0);
+ gpiod_set_value_cansleep(par->reset, 0);
udelay(4);
- gpiod_set_value(par->reset, 1);
+ gpiod_set_value_cansleep(par->reset, 1);
udelay(4);
}
diff --git a/drivers/video/fbdev/stifb.c b/drivers/video/fbdev/stifb.c
index 045e8afe398b..9e88e3f594c2 100644
--- a/drivers/video/fbdev/stifb.c
+++ b/drivers/video/fbdev/stifb.c
@@ -1157,7 +1157,7 @@ static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref)
dev_name);
goto out_err0;
}
- /* fall though */
+ /* fall through */
case S9000_ID_ARTIST:
case S9000_ID_HCRX:
case S9000_ID_TIMBER:
diff --git a/drivers/video/fbdev/udlfb.c b/drivers/video/fbdev/udlfb.c
index afbd6101c78e..070026a7e55a 100644
--- a/drivers/video/fbdev/udlfb.c
+++ b/drivers/video/fbdev/udlfb.c
@@ -916,8 +916,6 @@ static int dlfb_ops_open(struct fb_info *info, int user)
dlfb->fb_count++;
- kref_get(&dlfb->kref);
-
if (fb_defio && (info->fbdefio == NULL)) {
/* enable defio at last moment if not disabled by client */
@@ -940,14 +938,17 @@ static int dlfb_ops_open(struct fb_info *info, int user)
return 0;
}
-/*
- * Called when all client interfaces to start transactions have been disabled,
- * and all references to our device instance (dlfb_data) are released.
- * Every transaction must have a reference, so we know are fully spun down
- */
-static void dlfb_free(struct kref *kref)
+static void dlfb_ops_destroy(struct fb_info *info)
{
- struct dlfb_data *dlfb = container_of(kref, struct dlfb_data, kref);
+ struct dlfb_data *dlfb = info->par;
+
+ if (info->cmap.len != 0)
+ fb_dealloc_cmap(&info->cmap);
+ if (info->monspecs.modedb)
+ fb_destroy_modedb(info->monspecs.modedb);
+ vfree(info->screen_base);
+
+ fb_destroy_modelist(&info->modelist);
while (!list_empty(&dlfb->deferred_free)) {
struct dlfb_deferred_free *d = list_entry(dlfb->deferred_free.next, struct dlfb_deferred_free, list);
@@ -957,40 +958,13 @@ static void dlfb_free(struct kref *kref)
}
vfree(dlfb->backing_buffer);
kfree(dlfb->edid);
+ usb_put_dev(dlfb->udev);
kfree(dlfb);
-}
-
-static void dlfb_free_framebuffer(struct dlfb_data *dlfb)
-{
- struct fb_info *info = dlfb->info;
-
- if (info) {
- unregister_framebuffer(info);
-
- if (info->cmap.len != 0)
- fb_dealloc_cmap(&info->cmap);
- if (info->monspecs.modedb)
- fb_destroy_modedb(info->monspecs.modedb);
- vfree(info->screen_base);
-
- fb_destroy_modelist(&info->modelist);
-
- dlfb->info = NULL;
-
- /* Assume info structure is freed after this point */
- framebuffer_release(info);
- }
- /* ref taken in probe() as part of registering framebfufer */
- kref_put(&dlfb->kref, dlfb_free);
+ /* Assume info structure is freed after this point */
+ framebuffer_release(info);
}
-static void dlfb_free_framebuffer_work(struct work_struct *work)
-{
- struct dlfb_data *dlfb = container_of(work, struct dlfb_data,
- free_framebuffer_work.work);
- dlfb_free_framebuffer(dlfb);
-}
/*
* Assumes caller is holding info->lock mutex (for open and release at least)
*/
@@ -1000,10 +974,6 @@ static int dlfb_ops_release(struct fb_info *info, int user)
dlfb->fb_count--;
- /* We can't free fb_info here - fbmem will touch it when we return */
- if (dlfb->virtualized && (dlfb->fb_count == 0))
- schedule_delayed_work(&dlfb->free_framebuffer_work, HZ);
-
if ((dlfb->fb_count == 0) && (info->fbdefio)) {
fb_deferred_io_cleanup(info);
kfree(info->fbdefio);
@@ -1013,8 +983,6 @@ static int dlfb_ops_release(struct fb_info *info, int user)
dev_dbg(info->dev, "release, user=%d count=%d\n", user, dlfb->fb_count);
- kref_put(&dlfb->kref, dlfb_free);
-
return 0;
}
@@ -1172,6 +1140,7 @@ static struct fb_ops dlfb_ops = {
.fb_blank = dlfb_ops_blank,
.fb_check_var = dlfb_ops_check_var,
.fb_set_par = dlfb_ops_set_par,
+ .fb_destroy = dlfb_ops_destroy,
};
@@ -1615,12 +1584,13 @@ success:
return true;
}
-static void dlfb_init_framebuffer_work(struct work_struct *work);
-
static int dlfb_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
+ int i;
+ const struct device_attribute *attr;
struct dlfb_data *dlfb;
+ struct fb_info *info;
int retval = -ENOMEM;
struct usb_device *usbdev = interface_to_usbdev(intf);
@@ -1631,10 +1601,9 @@ static int dlfb_usb_probe(struct usb_interface *intf,
goto error;
}
- kref_init(&dlfb->kref); /* matching kref_put in usb .disconnect fn */
INIT_LIST_HEAD(&dlfb->deferred_free);
- dlfb->udev = usbdev;
+ dlfb->udev = usb_get_dev(usbdev);
usb_set_intfdata(intf, dlfb);
dev_dbg(&intf->dev, "console enable=%d\n", console);
@@ -1657,42 +1626,6 @@ static int dlfb_usb_probe(struct usb_interface *intf,
}
- if (!dlfb_alloc_urb_list(dlfb, WRITES_IN_FLIGHT, MAX_TRANSFER)) {
- retval = -ENOMEM;
- dev_err(&intf->dev, "unable to allocate urb list\n");
- goto error;
- }
-
- kref_get(&dlfb->kref); /* matching kref_put in free_framebuffer_work */
-
- /* We don't register a new USB class. Our client interface is dlfbev */
-
- /* Workitem keep things fast & simple during USB enumeration */
- INIT_DELAYED_WORK(&dlfb->init_framebuffer_work,
- dlfb_init_framebuffer_work);
- schedule_delayed_work(&dlfb->init_framebuffer_work, 0);
-
- return 0;
-
-error:
- if (dlfb) {
-
- kref_put(&dlfb->kref, dlfb_free); /* last ref from kref_init */
-
- /* dev has been deallocated. Do not dereference */
- }
-
- return retval;
-}
-
-static void dlfb_init_framebuffer_work(struct work_struct *work)
-{
- int i, retval;
- struct fb_info *info;
- const struct device_attribute *attr;
- struct dlfb_data *dlfb = container_of(work, struct dlfb_data,
- init_framebuffer_work.work);
-
/* allocates framebuffer driver structure, not framebuffer memory */
info = framebuffer_alloc(0, &dlfb->udev->dev);
if (!info) {
@@ -1706,17 +1639,22 @@ static void dlfb_init_framebuffer_work(struct work_struct *work)
dlfb->ops = dlfb_ops;
info->fbops = &dlfb->ops;
+ INIT_LIST_HEAD(&info->modelist);
+
+ if (!dlfb_alloc_urb_list(dlfb, WRITES_IN_FLIGHT, MAX_TRANSFER)) {
+ retval = -ENOMEM;
+ dev_err(&intf->dev, "unable to allocate urb list\n");
+ goto error;
+ }
+
+ /* We don't register a new USB class. Our client interface is dlfbev */
+
retval = fb_alloc_cmap(&info->cmap, 256, 0);
if (retval < 0) {
dev_err(info->device, "cmap allocation failed: %d\n", retval);
goto error;
}
- INIT_DELAYED_WORK(&dlfb->free_framebuffer_work,
- dlfb_free_framebuffer_work);
-
- INIT_LIST_HEAD(&info->modelist);
-
retval = dlfb_setup_modes(dlfb, info, NULL, 0);
if (retval != 0) {
dev_err(info->device,
@@ -1760,10 +1698,16 @@ static void dlfb_init_framebuffer_work(struct work_struct *work)
dev_name(info->dev), info->var.xres, info->var.yres,
((dlfb->backing_buffer) ?
info->fix.smem_len * 2 : info->fix.smem_len) >> 10);
- return;
+ return 0;
error:
- dlfb_free_framebuffer(dlfb);
+ if (dlfb->info) {
+ dlfb_ops_destroy(dlfb->info);
+ } else if (dlfb) {
+ usb_put_dev(dlfb->udev);
+ kfree(dlfb);
+ }
+ return retval;
}
static void dlfb_usb_disconnect(struct usb_interface *intf)
@@ -1791,20 +1735,9 @@ static void dlfb_usb_disconnect(struct usb_interface *intf)
for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++)
device_remove_file(info->dev, &fb_device_attrs[i]);
device_remove_bin_file(info->dev, &edid_attr);
- unlink_framebuffer(info);
}
- usb_set_intfdata(intf, NULL);
- dlfb->udev = NULL;
-
- /* if clients still have us open, will be freed on last close */
- if (dlfb->fb_count == 0)
- schedule_delayed_work(&dlfb->free_framebuffer_work, 0);
-
- /* release reference taken by kref_init in probe() */
- kref_put(&dlfb->kref, dlfb_free);
-
- /* consider dlfb_data freed */
+ unregister_framebuffer(info);
}
static struct usb_driver dlfb_driver = {
diff --git a/drivers/video/fbdev/valkyriefb.c b/drivers/video/fbdev/valkyriefb.c
index 275fb98236d3..d51c3a8009cb 100644
--- a/drivers/video/fbdev/valkyriefb.c
+++ b/drivers/video/fbdev/valkyriefb.c
@@ -54,13 +54,11 @@
#include <linux/nvram.h>
#include <linux/adb.h>
#include <linux/cuda.h>
-#include <asm/io.h>
#ifdef CONFIG_MAC
#include <asm/macintosh.h>
#else
#include <asm/prom.h>
#endif
-#include <asm/pgtable.h>
#include "macmodes.h"
#include "valkyriefb.h"
@@ -318,7 +316,7 @@ static void __init valkyrie_choose_mode(struct fb_info_valkyrie *p)
int __init valkyriefb_init(void)
{
struct fb_info_valkyrie *p;
- unsigned long frame_buffer_phys, cmap_regs_phys, flags;
+ unsigned long frame_buffer_phys, cmap_regs_phys;
int err;
char *option = NULL;
@@ -337,7 +335,6 @@ int __init valkyriefb_init(void)
/* Hardcoded addresses... welcome to 68k Macintosh country :-) */
frame_buffer_phys = 0xf9000000;
cmap_regs_phys = 0x50f24000;
- flags = IOMAP_NOCACHE_SER; /* IOMAP_WRITETHROUGH?? */
#else /* ppc (!CONFIG_MAC) */
{
struct device_node *dp;
@@ -354,7 +351,6 @@ int __init valkyriefb_init(void)
frame_buffer_phys = r.start;
cmap_regs_phys = r.start + 0x304000;
- flags = _PAGE_WRITETHRU;
}
#endif /* ppc (!CONFIG_MAC) */
@@ -369,7 +365,11 @@ int __init valkyriefb_init(void)
}
p->total_vram = 0x100000;
p->frame_buffer_phys = frame_buffer_phys;
- p->frame_buffer = __ioremap(frame_buffer_phys, p->total_vram, flags);
+#ifdef CONFIG_MAC
+ p->frame_buffer = ioremap_nocache(frame_buffer_phys, p->total_vram);
+#else
+ p->frame_buffer = ioremap_wt(frame_buffer_phys, p->total_vram);
+#endif
p->cmap_regs_phys = cmap_regs_phys;
p->cmap_regs = ioremap(p->cmap_regs_phys, 0x1000);
p->valkyrie_regs_phys = cmap_regs_phys+0x6000;
diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index 38716eb50408..799ae49774f5 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -31,7 +31,7 @@
#define hdmi_log(fmt, ...) dev_printk(level, dev, fmt, ##__VA_ARGS__)
-static u8 hdmi_infoframe_checksum(u8 *ptr, size_t size)
+static u8 hdmi_infoframe_checksum(const u8 *ptr, size_t size)
{
u8 csum = 0;
size_t i;
@@ -68,8 +68,36 @@ int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
}
EXPORT_SYMBOL(hdmi_avi_infoframe_init);
+static int hdmi_avi_infoframe_check_only(const struct hdmi_avi_infoframe *frame)
+{
+ if (frame->type != HDMI_INFOFRAME_TYPE_AVI ||
+ frame->version != 2 ||
+ frame->length != HDMI_AVI_INFOFRAME_SIZE)
+ return -EINVAL;
+
+ if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
+ return -EINVAL;
+
+ return 0;
+}
+
/**
- * hdmi_avi_infoframe_pack() - write HDMI AVI infoframe to binary buffer
+ * hdmi_avi_infoframe_check() - check a HDMI AVI infoframe
+ * @frame: HDMI AVI infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame)
+{
+ return hdmi_avi_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_avi_infoframe_check);
+
+/**
+ * hdmi_avi_infoframe_pack_only() - write HDMI AVI infoframe to binary buffer
* @frame: HDMI AVI infoframe
* @buffer: destination buffer
* @size: size of buffer
@@ -82,20 +110,22 @@ EXPORT_SYMBOL(hdmi_avi_infoframe_init);
* Returns the number of bytes packed into the binary buffer or a negative
* error code on failure.
*/
-ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
- size_t size)
+ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
+ void *buffer, size_t size)
{
u8 *ptr = buffer;
size_t length;
+ int ret;
+
+ ret = hdmi_avi_infoframe_check_only(frame);
+ if (ret)
+ return ret;
length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
if (size < length)
return -ENOSPC;
- if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
- return -EINVAL;
-
memset(buffer, 0, size);
ptr[0] = frame->type;
@@ -152,6 +182,36 @@ ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
return length;
}
+EXPORT_SYMBOL(hdmi_avi_infoframe_pack_only);
+
+/**
+ * hdmi_avi_infoframe_pack() - check a HDMI AVI infoframe,
+ * and write it to binary buffer
+ * @frame: HDMI AVI infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which it packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. This function
+ * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame,
+ void *buffer, size_t size)
+{
+ int ret;
+
+ ret = hdmi_avi_infoframe_check(frame);
+ if (ret)
+ return ret;
+
+ return hdmi_avi_infoframe_pack_only(frame, buffer, size);
+}
EXPORT_SYMBOL(hdmi_avi_infoframe_pack);
/**
@@ -178,8 +238,33 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
}
EXPORT_SYMBOL(hdmi_spd_infoframe_init);
+static int hdmi_spd_infoframe_check_only(const struct hdmi_spd_infoframe *frame)
+{
+ if (frame->type != HDMI_INFOFRAME_TYPE_SPD ||
+ frame->version != 1 ||
+ frame->length != HDMI_SPD_INFOFRAME_SIZE)
+ return -EINVAL;
+
+ return 0;
+}
+
/**
- * hdmi_spd_infoframe_pack() - write HDMI SPD infoframe to binary buffer
+ * hdmi_spd_infoframe_check() - check a HDMI SPD infoframe
+ * @frame: HDMI SPD infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame)
+{
+ return hdmi_spd_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_spd_infoframe_check);
+
+/**
+ * hdmi_spd_infoframe_pack_only() - write HDMI SPD infoframe to binary buffer
* @frame: HDMI SPD infoframe
* @buffer: destination buffer
* @size: size of buffer
@@ -192,11 +277,16 @@ EXPORT_SYMBOL(hdmi_spd_infoframe_init);
* Returns the number of bytes packed into the binary buffer or a negative
* error code on failure.
*/
-ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
- size_t size)
+ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
+ void *buffer, size_t size)
{
u8 *ptr = buffer;
size_t length;
+ int ret;
+
+ ret = hdmi_spd_infoframe_check_only(frame);
+ if (ret)
+ return ret;
length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
@@ -222,6 +312,36 @@ ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
return length;
}
+EXPORT_SYMBOL(hdmi_spd_infoframe_pack_only);
+
+/**
+ * hdmi_spd_infoframe_pack() - check a HDMI SPD infoframe,
+ * and write it to binary buffer
+ * @frame: HDMI SPD infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which it packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. This function
+ * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame,
+ void *buffer, size_t size)
+{
+ int ret;
+
+ ret = hdmi_spd_infoframe_check(frame);
+ if (ret)
+ return ret;
+
+ return hdmi_spd_infoframe_pack_only(frame, buffer, size);
+}
EXPORT_SYMBOL(hdmi_spd_infoframe_pack);
/**
@@ -242,8 +362,33 @@ int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
}
EXPORT_SYMBOL(hdmi_audio_infoframe_init);
+static int hdmi_audio_infoframe_check_only(const struct hdmi_audio_infoframe *frame)
+{
+ if (frame->type != HDMI_INFOFRAME_TYPE_AUDIO ||
+ frame->version != 1 ||
+ frame->length != HDMI_AUDIO_INFOFRAME_SIZE)
+ return -EINVAL;
+
+ return 0;
+}
+
/**
- * hdmi_audio_infoframe_pack() - write HDMI audio infoframe to binary buffer
+ * hdmi_audio_infoframe_check() - check a HDMI audio infoframe
+ * @frame: HDMI audio infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame)
+{
+ return hdmi_audio_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_audio_infoframe_check);
+
+/**
+ * hdmi_audio_infoframe_pack_only() - write HDMI audio infoframe to binary buffer
* @frame: HDMI audio infoframe
* @buffer: destination buffer
* @size: size of buffer
@@ -256,12 +401,17 @@ EXPORT_SYMBOL(hdmi_audio_infoframe_init);
* Returns the number of bytes packed into the binary buffer or a negative
* error code on failure.
*/
-ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
- void *buffer, size_t size)
+ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
+ void *buffer, size_t size)
{
unsigned char channels;
u8 *ptr = buffer;
size_t length;
+ int ret;
+
+ ret = hdmi_audio_infoframe_check_only(frame);
+ if (ret)
+ return ret;
length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
@@ -297,6 +447,36 @@ ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
return length;
}
+EXPORT_SYMBOL(hdmi_audio_infoframe_pack_only);
+
+/**
+ * hdmi_audio_infoframe_pack() - check a HDMI Audio infoframe,
+ * and write it to binary buffer
+ * @frame: HDMI Audio infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which it packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. This function
+ * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
+ void *buffer, size_t size)
+{
+ int ret;
+
+ ret = hdmi_audio_infoframe_check(frame);
+ if (ret)
+ return ret;
+
+ return hdmi_audio_infoframe_pack_only(frame, buffer, size);
+}
EXPORT_SYMBOL(hdmi_audio_infoframe_pack);
/**
@@ -319,6 +499,7 @@ int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
* value
*/
frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID;
+ frame->length = 4;
return 0;
}
@@ -335,8 +516,42 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
return 4;
}
+static int hdmi_vendor_infoframe_check_only(const struct hdmi_vendor_infoframe *frame)
+{
+ if (frame->type != HDMI_INFOFRAME_TYPE_VENDOR ||
+ frame->version != 1 ||
+ frame->oui != HDMI_IEEE_OUI)
+ return -EINVAL;
+
+ /* only one of those can be supplied */
+ if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
+ return -EINVAL;
+
+ if (frame->length != hdmi_vendor_infoframe_length(frame))
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * hdmi_vendor_infoframe_check() - check a HDMI vendor infoframe
+ * @frame: HDMI infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame)
+{
+ frame->length = hdmi_vendor_infoframe_length(frame);
+
+ return hdmi_vendor_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_vendor_infoframe_check);
+
/**
- * hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary buffer
+ * hdmi_vendor_infoframe_pack_only() - write a HDMI vendor infoframe to binary buffer
* @frame: HDMI infoframe
* @buffer: destination buffer
* @size: size of buffer
@@ -349,17 +564,16 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
* Returns the number of bytes packed into the binary buffer or a negative
* error code on failure.
*/
-ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
- void *buffer, size_t size)
+ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
+ void *buffer, size_t size)
{
u8 *ptr = buffer;
size_t length;
+ int ret;
- /* only one of those can be supplied */
- if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
- return -EINVAL;
-
- frame->length = hdmi_vendor_infoframe_length(frame);
+ ret = hdmi_vendor_infoframe_check_only(frame);
+ if (ret)
+ return ret;
length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
@@ -394,24 +608,134 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
return length;
}
+EXPORT_SYMBOL(hdmi_vendor_infoframe_pack_only);
+
+/**
+ * hdmi_vendor_infoframe_pack() - check a HDMI Vendor infoframe,
+ * and write it to binary buffer
+ * @frame: HDMI Vendor infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which it packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. This function
+ * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
+ void *buffer, size_t size)
+{
+ int ret;
+
+ ret = hdmi_vendor_infoframe_check(frame);
+ if (ret)
+ return ret;
+
+ return hdmi_vendor_infoframe_pack_only(frame, buffer, size);
+}
EXPORT_SYMBOL(hdmi_vendor_infoframe_pack);
+static int
+hdmi_vendor_any_infoframe_check_only(const union hdmi_vendor_any_infoframe *frame)
+{
+ if (frame->any.type != HDMI_INFOFRAME_TYPE_VENDOR ||
+ frame->any.version != 1)
+ return -EINVAL;
+
+ return 0;
+}
+
+/*
+ * hdmi_vendor_any_infoframe_check() - check a vendor infoframe
+ */
+static int
+hdmi_vendor_any_infoframe_check(union hdmi_vendor_any_infoframe *frame)
+{
+ int ret;
+
+ ret = hdmi_vendor_any_infoframe_check_only(frame);
+ if (ret)
+ return ret;
+
+ /* we only know about HDMI vendor infoframes */
+ if (frame->any.oui != HDMI_IEEE_OUI)
+ return -EINVAL;
+
+ return hdmi_vendor_infoframe_check(&frame->hdmi);
+}
+
/*
- * hdmi_vendor_any_infoframe_pack() - write a vendor infoframe to binary buffer
+ * hdmi_vendor_any_infoframe_pack_only() - write a vendor infoframe to binary buffer
*/
static ssize_t
-hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
- void *buffer, size_t size)
+hdmi_vendor_any_infoframe_pack_only(const union hdmi_vendor_any_infoframe *frame,
+ void *buffer, size_t size)
{
+ int ret;
+
+ ret = hdmi_vendor_any_infoframe_check_only(frame);
+ if (ret)
+ return ret;
+
/* we only know about HDMI vendor infoframes */
if (frame->any.oui != HDMI_IEEE_OUI)
return -EINVAL;
- return hdmi_vendor_infoframe_pack(&frame->hdmi, buffer, size);
+ return hdmi_vendor_infoframe_pack_only(&frame->hdmi, buffer, size);
+}
+
+/*
+ * hdmi_vendor_any_infoframe_pack() - check a vendor infoframe,
+ * and write it to binary buffer
+ */
+static ssize_t
+hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
+ void *buffer, size_t size)
+{
+ int ret;
+
+ ret = hdmi_vendor_any_infoframe_check(frame);
+ if (ret)
+ return ret;
+
+ return hdmi_vendor_any_infoframe_pack_only(frame, buffer, size);
}
/**
- * hdmi_infoframe_pack() - write a HDMI infoframe to binary buffer
+ * hdmi_infoframe_check() - check a HDMI infoframe
+ * @frame: HDMI infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int
+hdmi_infoframe_check(union hdmi_infoframe *frame)
+{
+ switch (frame->any.type) {
+ case HDMI_INFOFRAME_TYPE_AVI:
+ return hdmi_avi_infoframe_check(&frame->avi);
+ case HDMI_INFOFRAME_TYPE_SPD:
+ return hdmi_spd_infoframe_check(&frame->spd);
+ case HDMI_INFOFRAME_TYPE_AUDIO:
+ return hdmi_audio_infoframe_check(&frame->audio);
+ case HDMI_INFOFRAME_TYPE_VENDOR:
+ return hdmi_vendor_any_infoframe_check(&frame->vendor);
+ default:
+ WARN(1, "Bad infoframe type %d\n", frame->any.type);
+ return -EINVAL;
+ }
+}
+EXPORT_SYMBOL(hdmi_infoframe_check);
+
+/**
+ * hdmi_infoframe_pack_only() - write a HDMI infoframe to binary buffer
* @frame: HDMI infoframe
* @buffer: destination buffer
* @size: size of buffer
@@ -425,7 +749,56 @@ hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
* error code on failure.
*/
ssize_t
-hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size)
+hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t size)
+{
+ ssize_t length;
+
+ switch (frame->any.type) {
+ case HDMI_INFOFRAME_TYPE_AVI:
+ length = hdmi_avi_infoframe_pack_only(&frame->avi,
+ buffer, size);
+ break;
+ case HDMI_INFOFRAME_TYPE_SPD:
+ length = hdmi_spd_infoframe_pack_only(&frame->spd,
+ buffer, size);
+ break;
+ case HDMI_INFOFRAME_TYPE_AUDIO:
+ length = hdmi_audio_infoframe_pack_only(&frame->audio,
+ buffer, size);
+ break;
+ case HDMI_INFOFRAME_TYPE_VENDOR:
+ length = hdmi_vendor_any_infoframe_pack_only(&frame->vendor,
+ buffer, size);
+ break;
+ default:
+ WARN(1, "Bad infoframe type %d\n", frame->any.type);
+ length = -EINVAL;
+ }
+
+ return length;
+}
+EXPORT_SYMBOL(hdmi_infoframe_pack_only);
+
+/**
+ * hdmi_infoframe_pack() - check a HDMI infoframe,
+ * and write it to binary buffer
+ * @frame: HDMI infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which it packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. This function
+ * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t
+hdmi_infoframe_pack(union hdmi_infoframe *frame,
+ void *buffer, size_t size)
{
ssize_t length;
@@ -471,7 +844,7 @@ static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
static void hdmi_infoframe_log_header(const char *level,
struct device *dev,
- struct hdmi_any_infoframe *frame)
+ const struct hdmi_any_infoframe *frame)
{
hdmi_log("HDMI infoframe: %s, version %u, length %u\n",
hdmi_infoframe_type_get_name(frame->type),
@@ -592,10 +965,10 @@ hdmi_extended_colorimetry_get_name(enum hdmi_extended_colorimetry ext_col)
return "xvYCC 709";
case HDMI_EXTENDED_COLORIMETRY_S_YCC_601:
return "sYCC 601";
- case HDMI_EXTENDED_COLORIMETRY_ADOBE_YCC_601:
- return "Adobe YCC 601";
- case HDMI_EXTENDED_COLORIMETRY_ADOBE_RGB:
- return "Adobe RGB";
+ case HDMI_EXTENDED_COLORIMETRY_OPYCC_601:
+ return "opYCC 601";
+ case HDMI_EXTENDED_COLORIMETRY_OPRGB:
+ return "opRGB";
case HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM:
return "BT.2020 Constant Luminance";
case HDMI_EXTENDED_COLORIMETRY_BT2020:
@@ -673,10 +1046,10 @@ hdmi_content_type_get_name(enum hdmi_content_type content_type)
*/
static void hdmi_avi_infoframe_log(const char *level,
struct device *dev,
- struct hdmi_avi_infoframe *frame)
+ const struct hdmi_avi_infoframe *frame)
{
hdmi_infoframe_log_header(level, dev,
- (struct hdmi_any_infoframe *)frame);
+ (const struct hdmi_any_infoframe *)frame);
hdmi_log(" colorspace: %s\n",
hdmi_colorspace_get_name(frame->colorspace));
@@ -750,12 +1123,12 @@ static const char *hdmi_spd_sdi_get_name(enum hdmi_spd_sdi sdi)
*/
static void hdmi_spd_infoframe_log(const char *level,
struct device *dev,
- struct hdmi_spd_infoframe *frame)
+ const struct hdmi_spd_infoframe *frame)
{
u8 buf[17];
hdmi_infoframe_log_header(level, dev,
- (struct hdmi_any_infoframe *)frame);
+ (const struct hdmi_any_infoframe *)frame);
memset(buf, 0, sizeof(buf));
@@ -886,10 +1259,10 @@ hdmi_audio_coding_type_ext_get_name(enum hdmi_audio_coding_type_ext ctx)
*/
static void hdmi_audio_infoframe_log(const char *level,
struct device *dev,
- struct hdmi_audio_infoframe *frame)
+ const struct hdmi_audio_infoframe *frame)
{
hdmi_infoframe_log_header(level, dev,
- (struct hdmi_any_infoframe *)frame);
+ (const struct hdmi_any_infoframe *)frame);
if (frame->channels)
hdmi_log(" channels: %u\n", frame->channels - 1);
@@ -949,12 +1322,12 @@ hdmi_3d_structure_get_name(enum hdmi_3d_structure s3d_struct)
static void
hdmi_vendor_any_infoframe_log(const char *level,
struct device *dev,
- union hdmi_vendor_any_infoframe *frame)
+ const union hdmi_vendor_any_infoframe *frame)
{
- struct hdmi_vendor_infoframe *hvf = &frame->hdmi;
+ const struct hdmi_vendor_infoframe *hvf = &frame->hdmi;
hdmi_infoframe_log_header(level, dev,
- (struct hdmi_any_infoframe *)frame);
+ (const struct hdmi_any_infoframe *)frame);
if (frame->any.oui != HDMI_IEEE_OUI) {
hdmi_log(" not a HDMI vendor infoframe\n");
@@ -984,7 +1357,7 @@ hdmi_vendor_any_infoframe_log(const char *level,
*/
void hdmi_infoframe_log(const char *level,
struct device *dev,
- union hdmi_infoframe *frame)
+ const union hdmi_infoframe *frame)
{
switch (frame->any.type) {
case HDMI_INFOFRAME_TYPE_AVI:
@@ -1005,8 +1378,9 @@ EXPORT_SYMBOL(hdmi_infoframe_log);
/**
* hdmi_avi_infoframe_unpack() - unpack binary buffer to a HDMI AVI infoframe
- * @buffer: source buffer
* @frame: HDMI AVI infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
*
* Unpacks the information contained in binary @buffer into a structured
* @frame of the HDMI Auxiliary Video (AVI) information frame.
@@ -1016,11 +1390,14 @@ EXPORT_SYMBOL(hdmi_infoframe_log);
* Returns 0 on success or a negative error code on failure.
*/
static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
- void *buffer)
+ const void *buffer, size_t size)
{
- u8 *ptr = buffer;
+ const u8 *ptr = buffer;
int ret;
+ if (size < HDMI_INFOFRAME_SIZE(AVI))
+ return -EINVAL;
+
if (ptr[0] != HDMI_INFOFRAME_TYPE_AVI ||
ptr[1] != 2 ||
ptr[2] != HDMI_AVI_INFOFRAME_SIZE)
@@ -1068,8 +1445,9 @@ static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
/**
* hdmi_spd_infoframe_unpack() - unpack binary buffer to a HDMI SPD infoframe
- * @buffer: source buffer
* @frame: HDMI SPD infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
*
* Unpacks the information contained in binary @buffer into a structured
* @frame of the HDMI Source Product Description (SPD) information frame.
@@ -1079,11 +1457,14 @@ static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
* Returns 0 on success or a negative error code on failure.
*/
static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
- void *buffer)
+ const void *buffer, size_t size)
{
- u8 *ptr = buffer;
+ const u8 *ptr = buffer;
int ret;
+ if (size < HDMI_INFOFRAME_SIZE(SPD))
+ return -EINVAL;
+
if (ptr[0] != HDMI_INFOFRAME_TYPE_SPD ||
ptr[1] != 1 ||
ptr[2] != HDMI_SPD_INFOFRAME_SIZE) {
@@ -1106,8 +1487,9 @@ static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
/**
* hdmi_audio_infoframe_unpack() - unpack binary buffer to a HDMI AUDIO infoframe
- * @buffer: source buffer
* @frame: HDMI Audio infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
*
* Unpacks the information contained in binary @buffer into a structured
* @frame of the HDMI Audio information frame.
@@ -1117,11 +1499,14 @@ static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
* Returns 0 on success or a negative error code on failure.
*/
static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
- void *buffer)
+ const void *buffer, size_t size)
{
- u8 *ptr = buffer;
+ const u8 *ptr = buffer;
int ret;
+ if (size < HDMI_INFOFRAME_SIZE(AUDIO))
+ return -EINVAL;
+
if (ptr[0] != HDMI_INFOFRAME_TYPE_AUDIO ||
ptr[1] != 1 ||
ptr[2] != HDMI_AUDIO_INFOFRAME_SIZE) {
@@ -1151,8 +1536,9 @@ static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
/**
* hdmi_vendor_infoframe_unpack() - unpack binary buffer to a HDMI vendor infoframe
- * @buffer: source buffer
* @frame: HDMI Vendor infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
*
* Unpacks the information contained in binary @buffer into a structured
* @frame of the HDMI Vendor information frame.
@@ -1163,14 +1549,17 @@ static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
*/
static int
hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
- void *buffer)
+ const void *buffer, size_t size)
{
- u8 *ptr = buffer;
+ const u8 *ptr = buffer;
size_t length;
int ret;
u8 hdmi_video_format;
struct hdmi_vendor_infoframe *hvf = &frame->hdmi;
+ if (size < HDMI_INFOFRAME_HEADER_SIZE)
+ return -EINVAL;
+
if (ptr[0] != HDMI_INFOFRAME_TYPE_VENDOR ||
ptr[1] != 1 ||
(ptr[2] != 4 && ptr[2] != 5 && ptr[2] != 6))
@@ -1178,6 +1567,9 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
length = ptr[2];
+ if (size < HDMI_INFOFRAME_HEADER_SIZE + length)
+ return -EINVAL;
+
if (hdmi_infoframe_checksum(buffer,
HDMI_INFOFRAME_HEADER_SIZE + length) != 0)
return -EINVAL;
@@ -1224,8 +1616,9 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
/**
* hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
- * @buffer: source buffer
* @frame: HDMI infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
*
* Unpacks the information contained in binary buffer @buffer into a structured
* @frame of a HDMI infoframe.
@@ -1234,23 +1627,27 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
*
* Returns 0 on success or a negative error code on failure.
*/
-int hdmi_infoframe_unpack(union hdmi_infoframe *frame, void *buffer)
+int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
+ const void *buffer, size_t size)
{
int ret;
- u8 *ptr = buffer;
+ const u8 *ptr = buffer;
+
+ if (size < HDMI_INFOFRAME_HEADER_SIZE)
+ return -EINVAL;
switch (ptr[0]) {
case HDMI_INFOFRAME_TYPE_AVI:
- ret = hdmi_avi_infoframe_unpack(&frame->avi, buffer);
+ ret = hdmi_avi_infoframe_unpack(&frame->avi, buffer, size);
break;
case HDMI_INFOFRAME_TYPE_SPD:
- ret = hdmi_spd_infoframe_unpack(&frame->spd, buffer);
+ ret = hdmi_spd_infoframe_unpack(&frame->spd, buffer, size);
break;
case HDMI_INFOFRAME_TYPE_AUDIO:
- ret = hdmi_audio_infoframe_unpack(&frame->audio, buffer);
+ ret = hdmi_audio_infoframe_unpack(&frame->audio, buffer, size);
break;
case HDMI_INFOFRAME_TYPE_VENDOR:
- ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer);
+ ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer, size);
break;
default:
ret = -EINVAL;
diff --git a/drivers/video/of_display_timing.c b/drivers/video/of_display_timing.c
index 5244e93ceafc..c2e7aa103fa5 100644
--- a/drivers/video/of_display_timing.c
+++ b/drivers/video/of_display_timing.c
@@ -170,7 +170,7 @@ struct display_timings *of_get_display_timings(const struct device_node *np)
goto entryfail;
}
- pr_debug("%pOF: using %s as default timing\n", np, entry->name);
+ pr_debug("%pOF: using %pOFn as default timing\n", np, entry);
native_mode = entry;
diff --git a/drivers/video/vgastate.c b/drivers/video/vgastate.c
index 548c751d2415..122fb3c3ec9d 100644
--- a/drivers/video/vgastate.c
+++ b/drivers/video/vgastate.c
@@ -455,7 +455,7 @@ int save_vga(struct vgastate *state)
return 0;
}
-int restore_vga (struct vgastate *state)
+int restore_vga(struct vgastate *state)
{
if (state->vidstate == NULL)
return 1;
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index d1c1f6283729..728ecd1eea30 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -41,13 +41,34 @@
#define VIRTIO_BALLOON_ARRAY_PFNS_MAX 256
#define VIRTBALLOON_OOM_NOTIFY_PRIORITY 80
+#define VIRTIO_BALLOON_FREE_PAGE_ALLOC_FLAG (__GFP_NORETRY | __GFP_NOWARN | \
+ __GFP_NOMEMALLOC)
+/* The order of free page blocks to report to host */
+#define VIRTIO_BALLOON_FREE_PAGE_ORDER (MAX_ORDER - 1)
+/* The size of a free page block in bytes */
+#define VIRTIO_BALLOON_FREE_PAGE_SIZE \
+ (1 << (VIRTIO_BALLOON_FREE_PAGE_ORDER + PAGE_SHIFT))
+
#ifdef CONFIG_BALLOON_COMPACTION
static struct vfsmount *balloon_mnt;
#endif
+enum virtio_balloon_vq {
+ VIRTIO_BALLOON_VQ_INFLATE,
+ VIRTIO_BALLOON_VQ_DEFLATE,
+ VIRTIO_BALLOON_VQ_STATS,
+ VIRTIO_BALLOON_VQ_FREE_PAGE,
+ VIRTIO_BALLOON_VQ_MAX
+};
+
struct virtio_balloon {
struct virtio_device *vdev;
- struct virtqueue *inflate_vq, *deflate_vq, *stats_vq;
+ struct virtqueue *inflate_vq, *deflate_vq, *stats_vq, *free_page_vq;
+
+ /* Balloon's own wq for cpu-intensive work items */
+ struct workqueue_struct *balloon_wq;
+ /* The free page reporting work item submitted to the balloon wq */
+ struct work_struct report_free_page_work;
/* The balloon servicing is delegated to a freezable workqueue. */
struct work_struct update_balloon_stats_work;
@@ -57,6 +78,18 @@ struct virtio_balloon {
spinlock_t stop_update_lock;
bool stop_update;
+ /* The list of allocated free pages, waiting to be given back to mm */
+ struct list_head free_page_list;
+ spinlock_t free_page_list_lock;
+ /* The number of free page blocks on the above list */
+ unsigned long num_free_page_blocks;
+ /* The cmd id received from host */
+ u32 cmd_id_received;
+ /* The cmd id that is actively in use */
+ __virtio32 cmd_id_active;
+ /* Buffer to store the stop sign */
+ __virtio32 cmd_id_stop;
+
/* Waiting for host to ack the pages we released. */
wait_queue_head_t acked;
@@ -320,17 +353,6 @@ static void stats_handle_request(struct virtio_balloon *vb)
virtqueue_kick(vq);
}
-static void virtballoon_changed(struct virtio_device *vdev)
-{
- struct virtio_balloon *vb = vdev->priv;
- unsigned long flags;
-
- spin_lock_irqsave(&vb->stop_update_lock, flags);
- if (!vb->stop_update)
- queue_work(system_freezable_wq, &vb->update_balloon_size_work);
- spin_unlock_irqrestore(&vb->stop_update_lock, flags);
-}
-
static inline s64 towards_target(struct virtio_balloon *vb)
{
s64 target;
@@ -347,6 +369,60 @@ static inline s64 towards_target(struct virtio_balloon *vb)
return target - vb->num_pages;
}
+/* Gives back @num_to_return blocks of free pages to mm. */
+static unsigned long return_free_pages_to_mm(struct virtio_balloon *vb,
+ unsigned long num_to_return)
+{
+ struct page *page;
+ unsigned long num_returned;
+
+ spin_lock_irq(&vb->free_page_list_lock);
+ for (num_returned = 0; num_returned < num_to_return; num_returned++) {
+ page = balloon_page_pop(&vb->free_page_list);
+ if (!page)
+ break;
+ free_pages((unsigned long)page_address(page),
+ VIRTIO_BALLOON_FREE_PAGE_ORDER);
+ }
+ vb->num_free_page_blocks -= num_returned;
+ spin_unlock_irq(&vb->free_page_list_lock);
+
+ return num_returned;
+}
+
+static void virtballoon_changed(struct virtio_device *vdev)
+{
+ struct virtio_balloon *vb = vdev->priv;
+ unsigned long flags;
+ s64 diff = towards_target(vb);
+
+ if (diff) {
+ spin_lock_irqsave(&vb->stop_update_lock, flags);
+ if (!vb->stop_update)
+ queue_work(system_freezable_wq,
+ &vb->update_balloon_size_work);
+ spin_unlock_irqrestore(&vb->stop_update_lock, flags);
+ }
+
+ if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT)) {
+ virtio_cread(vdev, struct virtio_balloon_config,
+ free_page_report_cmd_id, &vb->cmd_id_received);
+ if (vb->cmd_id_received == VIRTIO_BALLOON_CMD_ID_DONE) {
+ /* Pass ULONG_MAX to give back all the free pages */
+ return_free_pages_to_mm(vb, ULONG_MAX);
+ } else if (vb->cmd_id_received != VIRTIO_BALLOON_CMD_ID_STOP &&
+ vb->cmd_id_received !=
+ virtio32_to_cpu(vdev, vb->cmd_id_active)) {
+ spin_lock_irqsave(&vb->stop_update_lock, flags);
+ if (!vb->stop_update) {
+ queue_work(vb->balloon_wq,
+ &vb->report_free_page_work);
+ }
+ spin_unlock_irqrestore(&vb->stop_update_lock, flags);
+ }
+ }
+}
+
static void update_balloon_size(struct virtio_balloon *vb)
{
u32 actual = vb->num_pages;
@@ -389,26 +465,44 @@ static void update_balloon_size_func(struct work_struct *work)
static int init_vqs(struct virtio_balloon *vb)
{
- struct virtqueue *vqs[3];
- vq_callback_t *callbacks[] = { balloon_ack, balloon_ack, stats_request };
- static const char * const names[] = { "inflate", "deflate", "stats" };
- int err, nvqs;
+ struct virtqueue *vqs[VIRTIO_BALLOON_VQ_MAX];
+ vq_callback_t *callbacks[VIRTIO_BALLOON_VQ_MAX];
+ const char *names[VIRTIO_BALLOON_VQ_MAX];
+ int err;
/*
- * We expect two virtqueues: inflate and deflate, and
- * optionally stat.
+ * Inflateq and deflateq are used unconditionally. The names[]
+ * will be NULL if the related feature is not enabled, which will
+ * cause no allocation for the corresponding virtqueue in find_vqs.
*/
- nvqs = virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_STATS_VQ) ? 3 : 2;
- err = virtio_find_vqs(vb->vdev, nvqs, vqs, callbacks, names, NULL);
+ callbacks[VIRTIO_BALLOON_VQ_INFLATE] = balloon_ack;
+ names[VIRTIO_BALLOON_VQ_INFLATE] = "inflate";
+ callbacks[VIRTIO_BALLOON_VQ_DEFLATE] = balloon_ack;
+ names[VIRTIO_BALLOON_VQ_DEFLATE] = "deflate";
+ names[VIRTIO_BALLOON_VQ_STATS] = NULL;
+ names[VIRTIO_BALLOON_VQ_FREE_PAGE] = NULL;
+
+ if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_STATS_VQ)) {
+ names[VIRTIO_BALLOON_VQ_STATS] = "stats";
+ callbacks[VIRTIO_BALLOON_VQ_STATS] = stats_request;
+ }
+
+ if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT)) {
+ names[VIRTIO_BALLOON_VQ_FREE_PAGE] = "free_page_vq";
+ callbacks[VIRTIO_BALLOON_VQ_FREE_PAGE] = NULL;
+ }
+
+ err = vb->vdev->config->find_vqs(vb->vdev, VIRTIO_BALLOON_VQ_MAX,
+ vqs, callbacks, names, NULL, NULL);
if (err)
return err;
- vb->inflate_vq = vqs[0];
- vb->deflate_vq = vqs[1];
+ vb->inflate_vq = vqs[VIRTIO_BALLOON_VQ_INFLATE];
+ vb->deflate_vq = vqs[VIRTIO_BALLOON_VQ_DEFLATE];
if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_STATS_VQ)) {
struct scatterlist sg;
unsigned int num_stats;
- vb->stats_vq = vqs[2];
+ vb->stats_vq = vqs[VIRTIO_BALLOON_VQ_STATS];
/*
* Prime this virtqueue with one buffer so the hypervisor can
@@ -426,9 +520,145 @@ static int init_vqs(struct virtio_balloon *vb)
}
virtqueue_kick(vb->stats_vq);
}
+
+ if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))
+ vb->free_page_vq = vqs[VIRTIO_BALLOON_VQ_FREE_PAGE];
+
+ return 0;
+}
+
+static int send_cmd_id_start(struct virtio_balloon *vb)
+{
+ struct scatterlist sg;
+ struct virtqueue *vq = vb->free_page_vq;
+ int err, unused;
+
+ /* Detach all the used buffers from the vq */
+ while (virtqueue_get_buf(vq, &unused))
+ ;
+
+ vb->cmd_id_active = cpu_to_virtio32(vb->vdev, vb->cmd_id_received);
+ sg_init_one(&sg, &vb->cmd_id_active, sizeof(vb->cmd_id_active));
+ err = virtqueue_add_outbuf(vq, &sg, 1, &vb->cmd_id_active, GFP_KERNEL);
+ if (!err)
+ virtqueue_kick(vq);
+ return err;
+}
+
+static int send_cmd_id_stop(struct virtio_balloon *vb)
+{
+ struct scatterlist sg;
+ struct virtqueue *vq = vb->free_page_vq;
+ int err, unused;
+
+ /* Detach all the used buffers from the vq */
+ while (virtqueue_get_buf(vq, &unused))
+ ;
+
+ sg_init_one(&sg, &vb->cmd_id_stop, sizeof(vb->cmd_id_stop));
+ err = virtqueue_add_outbuf(vq, &sg, 1, &vb->cmd_id_stop, GFP_KERNEL);
+ if (!err)
+ virtqueue_kick(vq);
+ return err;
+}
+
+static int get_free_page_and_send(struct virtio_balloon *vb)
+{
+ struct virtqueue *vq = vb->free_page_vq;
+ struct page *page;
+ struct scatterlist sg;
+ int err, unused;
+ void *p;
+
+ /* Detach all the used buffers from the vq */
+ while (virtqueue_get_buf(vq, &unused))
+ ;
+
+ page = alloc_pages(VIRTIO_BALLOON_FREE_PAGE_ALLOC_FLAG,
+ VIRTIO_BALLOON_FREE_PAGE_ORDER);
+ /*
+ * When the allocation returns NULL, it indicates that we have got all
+ * the possible free pages, so return -EINTR to stop.
+ */
+ if (!page)
+ return -EINTR;
+
+ p = page_address(page);
+ sg_init_one(&sg, p, VIRTIO_BALLOON_FREE_PAGE_SIZE);
+ /* There is always 1 entry reserved for the cmd id to use. */
+ if (vq->num_free > 1) {
+ err = virtqueue_add_inbuf(vq, &sg, 1, p, GFP_KERNEL);
+ if (unlikely(err)) {
+ free_pages((unsigned long)p,
+ VIRTIO_BALLOON_FREE_PAGE_ORDER);
+ return err;
+ }
+ virtqueue_kick(vq);
+ spin_lock_irq(&vb->free_page_list_lock);
+ balloon_page_push(&vb->free_page_list, page);
+ vb->num_free_page_blocks++;
+ spin_unlock_irq(&vb->free_page_list_lock);
+ } else {
+ /*
+ * The vq has no available entry to add this page block, so
+ * just free it.
+ */
+ free_pages((unsigned long)p, VIRTIO_BALLOON_FREE_PAGE_ORDER);
+ }
+
+ return 0;
+}
+
+static int send_free_pages(struct virtio_balloon *vb)
+{
+ int err;
+ u32 cmd_id_active;
+
+ while (1) {
+ /*
+ * If a stop id or a new cmd id was just received from host,
+ * stop the reporting.
+ */
+ cmd_id_active = virtio32_to_cpu(vb->vdev, vb->cmd_id_active);
+ if (cmd_id_active != vb->cmd_id_received)
+ break;
+
+ /*
+ * The free page blocks are allocated and sent to host one by
+ * one.
+ */
+ err = get_free_page_and_send(vb);
+ if (err == -EINTR)
+ break;
+ else if (unlikely(err))
+ return err;
+ }
+
return 0;
}
+static void report_free_page_func(struct work_struct *work)
+{
+ int err;
+ struct virtio_balloon *vb = container_of(work, struct virtio_balloon,
+ report_free_page_work);
+ struct device *dev = &vb->vdev->dev;
+
+ /* Start by sending the received cmd id to host with an outbuf. */
+ err = send_cmd_id_start(vb);
+ if (unlikely(err))
+ dev_err(dev, "Failed to send a start id, err = %d\n", err);
+
+ err = send_free_pages(vb);
+ if (unlikely(err))
+ dev_err(dev, "Failed to send a free page, err = %d\n", err);
+
+ /* End by sending a stop id to host with an outbuf. */
+ err = send_cmd_id_stop(vb);
+ if (unlikely(err))
+ dev_err(dev, "Failed to send a stop id, err = %d\n", err);
+}
+
#ifdef CONFIG_BALLOON_COMPACTION
/*
* virtballoon_migratepage - perform the balloon page migration on behalf of
@@ -512,14 +742,23 @@ static struct file_system_type balloon_fs = {
#endif /* CONFIG_BALLOON_COMPACTION */
-static unsigned long virtio_balloon_shrinker_scan(struct shrinker *shrinker,
- struct shrink_control *sc)
+static unsigned long shrink_free_pages(struct virtio_balloon *vb,
+ unsigned long pages_to_free)
{
- unsigned long pages_to_free, pages_freed = 0;
- struct virtio_balloon *vb = container_of(shrinker,
- struct virtio_balloon, shrinker);
+ unsigned long blocks_to_free, blocks_freed;
- pages_to_free = sc->nr_to_scan * VIRTIO_BALLOON_PAGES_PER_PAGE;
+ pages_to_free = round_up(pages_to_free,
+ 1 << VIRTIO_BALLOON_FREE_PAGE_ORDER);
+ blocks_to_free = pages_to_free >> VIRTIO_BALLOON_FREE_PAGE_ORDER;
+ blocks_freed = return_free_pages_to_mm(vb, blocks_to_free);
+
+ return blocks_freed << VIRTIO_BALLOON_FREE_PAGE_ORDER;
+}
+
+static unsigned long shrink_balloon_pages(struct virtio_balloon *vb,
+ unsigned long pages_to_free)
+{
+ unsigned long pages_freed = 0;
/*
* One invocation of leak_balloon can deflate at most
@@ -527,12 +766,33 @@ static unsigned long virtio_balloon_shrinker_scan(struct shrinker *shrinker,
* multiple times to deflate pages till reaching pages_to_free.
*/
while (vb->num_pages && pages_to_free) {
+ pages_freed += leak_balloon(vb, pages_to_free) /
+ VIRTIO_BALLOON_PAGES_PER_PAGE;
pages_to_free -= pages_freed;
- pages_freed += leak_balloon(vb, pages_to_free);
}
update_balloon_size(vb);
- return pages_freed / VIRTIO_BALLOON_PAGES_PER_PAGE;
+ return pages_freed;
+}
+
+static unsigned long virtio_balloon_shrinker_scan(struct shrinker *shrinker,
+ struct shrink_control *sc)
+{
+ unsigned long pages_to_free, pages_freed = 0;
+ struct virtio_balloon *vb = container_of(shrinker,
+ struct virtio_balloon, shrinker);
+
+ pages_to_free = sc->nr_to_scan * VIRTIO_BALLOON_PAGES_PER_PAGE;
+
+ if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))
+ pages_freed = shrink_free_pages(vb, pages_to_free);
+
+ if (pages_freed >= pages_to_free)
+ return pages_freed;
+
+ pages_freed += shrink_balloon_pages(vb, pages_to_free - pages_freed);
+
+ return pages_freed;
}
static unsigned long virtio_balloon_shrinker_count(struct shrinker *shrinker,
@@ -540,8 +800,12 @@ static unsigned long virtio_balloon_shrinker_count(struct shrinker *shrinker,
{
struct virtio_balloon *vb = container_of(shrinker,
struct virtio_balloon, shrinker);
+ unsigned long count;
- return vb->num_pages / VIRTIO_BALLOON_PAGES_PER_PAGE;
+ count = vb->num_pages / VIRTIO_BALLOON_PAGES_PER_PAGE;
+ count += vb->num_free_page_blocks >> VIRTIO_BALLOON_FREE_PAGE_ORDER;
+
+ return count;
}
static void virtio_balloon_unregister_shrinker(struct virtio_balloon *vb)
@@ -561,6 +825,7 @@ static int virtio_balloon_register_shrinker(struct virtio_balloon *vb)
static int virtballoon_probe(struct virtio_device *vdev)
{
struct virtio_balloon *vb;
+ __u32 poison_val;
int err;
if (!vdev->config->get) {
@@ -604,6 +869,36 @@ static int virtballoon_probe(struct virtio_device *vdev)
}
vb->vb_dev_info.inode->i_mapping->a_ops = &balloon_aops;
#endif
+ if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT)) {
+ /*
+ * There is always one entry reserved for cmd id, so the ring
+ * size needs to be at least two to report free page hints.
+ */
+ if (virtqueue_get_vring_size(vb->free_page_vq) < 2) {
+ err = -ENOSPC;
+ goto out_del_vqs;
+ }
+ vb->balloon_wq = alloc_workqueue("balloon-wq",
+ WQ_FREEZABLE | WQ_CPU_INTENSIVE, 0);
+ if (!vb->balloon_wq) {
+ err = -ENOMEM;
+ goto out_del_vqs;
+ }
+ INIT_WORK(&vb->report_free_page_work, report_free_page_func);
+ vb->cmd_id_received = VIRTIO_BALLOON_CMD_ID_STOP;
+ vb->cmd_id_active = cpu_to_virtio32(vb->vdev,
+ VIRTIO_BALLOON_CMD_ID_STOP);
+ vb->cmd_id_stop = cpu_to_virtio32(vb->vdev,
+ VIRTIO_BALLOON_CMD_ID_STOP);
+ vb->num_free_page_blocks = 0;
+ spin_lock_init(&vb->free_page_list_lock);
+ INIT_LIST_HEAD(&vb->free_page_list);
+ if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_PAGE_POISON)) {
+ memset(&poison_val, PAGE_POISON, sizeof(poison_val));
+ virtio_cwrite(vb->vdev, struct virtio_balloon_config,
+ poison_val, &poison_val);
+ }
+ }
/*
* We continue to use VIRTIO_BALLOON_F_DEFLATE_ON_OOM to decide if a
* shrinker needs to be registered to relieve memory pressure.
@@ -611,7 +906,7 @@ static int virtballoon_probe(struct virtio_device *vdev)
if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM)) {
err = virtio_balloon_register_shrinker(vb);
if (err)
- goto out_del_vqs;
+ goto out_del_balloon_wq;
}
virtio_device_ready(vdev);
@@ -619,6 +914,9 @@ static int virtballoon_probe(struct virtio_device *vdev)
virtballoon_changed(vdev);
return 0;
+out_del_balloon_wq:
+ if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))
+ destroy_workqueue(vb->balloon_wq);
out_del_vqs:
vdev->config->del_vqs(vdev);
out_free_vb:
@@ -652,6 +950,11 @@ static void virtballoon_remove(struct virtio_device *vdev)
cancel_work_sync(&vb->update_balloon_size_work);
cancel_work_sync(&vb->update_balloon_stats_work);
+ if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT)) {
+ cancel_work_sync(&vb->report_free_page_work);
+ destroy_workqueue(vb->balloon_wq);
+ }
+
remove_common(vb);
#ifdef CONFIG_BALLOON_COMPACTION
if (vb->vb_dev_info.inode)
@@ -695,6 +998,9 @@ static int virtballoon_restore(struct virtio_device *vdev)
static int virtballoon_validate(struct virtio_device *vdev)
{
+ if (!page_poisoning_enabled())
+ __virtio_clear_bit(vdev, VIRTIO_BALLOON_F_PAGE_POISON);
+
__virtio_clear_bit(vdev, VIRTIO_F_IOMMU_PLATFORM);
return 0;
}
@@ -703,6 +1009,8 @@ static unsigned int features[] = {
VIRTIO_BALLOON_F_MUST_TELL_HOST,
VIRTIO_BALLOON_F_STATS_VQ,
VIRTIO_BALLOON_F_DEFLATE_ON_OOM,
+ VIRTIO_BALLOON_F_FREE_PAGE_HINT,
+ VIRTIO_BALLOON_F_PAGE_POISON,
};
static struct virtio_driver virtio_balloon_driver = {
diff --git a/drivers/vme/vme.c b/drivers/vme/vme.c
index 92500f6bdad1..520a5f9c27de 100644
--- a/drivers/vme/vme.c
+++ b/drivers/vme/vme.c
@@ -1890,7 +1890,6 @@ static int __vme_register_driver_bus(struct vme_driver *drv,
err_reg:
put_device(&vdev->dev);
- kfree(vdev);
err_devalloc:
list_for_each_entry_safe(vdev, tmp, &drv->devices, drv_list) {
list_del(&vdev->drv_list);
diff --git a/drivers/w1/masters/omap_hdq.c b/drivers/w1/masters/omap_hdq.c
index 83fc9aab34e8..3099052e1243 100644
--- a/drivers/w1/masters/omap_hdq.c
+++ b/drivers/w1/masters/omap_hdq.c
@@ -763,6 +763,8 @@ static int omap_hdq_remove(struct platform_device *pdev)
/* remove module dependency */
pm_runtime_disable(&pdev->dev);
+ w1_remove_master_device(&omap_w1_master);
+
return 0;
}
diff --git a/drivers/w1/slaves/w1_ds2438.c b/drivers/w1/slaves/w1_ds2438.c
index bf641a191d07..7c4e33dbee4d 100644
--- a/drivers/w1/slaves/w1_ds2438.c
+++ b/drivers/w1/slaves/w1_ds2438.c
@@ -186,8 +186,8 @@ static int w1_ds2438_change_config_bit(struct w1_slave *sl, u8 mask, u8 value)
return -1;
}
-static uint16_t w1_ds2438_get_voltage(struct w1_slave *sl,
- int adc_input, uint16_t *voltage)
+static int w1_ds2438_get_voltage(struct w1_slave *sl,
+ int adc_input, uint16_t *voltage)
{
unsigned int retries = W1_DS2438_RETRIES;
u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/];
@@ -235,6 +235,25 @@ post_unlock:
return ret;
}
+static int w1_ds2438_get_current(struct w1_slave *sl, int16_t *voltage)
+{
+ u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/];
+ int ret;
+
+ mutex_lock(&sl->master->bus_mutex);
+
+ if (w1_ds2438_get_page(sl, 0, w1_buf) == 0) {
+ /* The voltage measured across current sense resistor RSENS. */
+ *voltage = (((int16_t) w1_buf[DS2438_CURRENT_MSB]) << 8) | ((int16_t) w1_buf[DS2438_CURRENT_LSB]);
+ ret = 0;
+ } else
+ ret = -1;
+
+ mutex_unlock(&sl->master->bus_mutex);
+
+ return ret;
+}
+
static ssize_t iad_write(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr, char *buf,
loff_t off, size_t count)
@@ -257,6 +276,27 @@ static ssize_t iad_write(struct file *filp, struct kobject *kobj,
return ret;
}
+static ssize_t iad_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;
+ int16_t voltage;
+
+ if (off != 0)
+ return 0;
+ if (!buf)
+ return -EINVAL;
+
+ if (w1_ds2438_get_current(sl, &voltage) == 0) {
+ ret = snprintf(buf, count, "%i\n", voltage);
+ } else
+ ret = -EIO;
+
+ return ret;
+}
+
static ssize_t page0_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr, char *buf,
loff_t off, size_t count)
@@ -272,9 +312,13 @@ static ssize_t page0_read(struct file *filp, struct kobject *kobj,
mutex_lock(&sl->master->bus_mutex);
+ /* Read no more than page0 size */
+ if (count > DS2438_PAGE_SIZE)
+ count = DS2438_PAGE_SIZE;
+
if (w1_ds2438_get_page(sl, 0, w1_buf) == 0) {
- memcpy(buf, &w1_buf, DS2438_PAGE_SIZE);
- ret = DS2438_PAGE_SIZE;
+ memcpy(buf, &w1_buf, count);
+ ret = count;
} else
ret = -EIO;
@@ -289,7 +333,6 @@ static ssize_t temperature_read(struct file *filp, struct kobject *kobj,
{
struct w1_slave *sl = kobj_to_w1_slave(kobj);
int ret;
- ssize_t c = PAGE_SIZE;
int16_t temp;
if (off != 0)
@@ -298,8 +341,7 @@ static ssize_t temperature_read(struct file *filp, struct kobject *kobj,
return -EINVAL;
if (w1_ds2438_get_temperature(sl, &temp) == 0) {
- c -= snprintf(buf + PAGE_SIZE - c, c, "%d\n", temp);
- ret = PAGE_SIZE - c;
+ ret = snprintf(buf, count, "%i\n", temp);
} else
ret = -EIO;
@@ -312,7 +354,6 @@ static ssize_t vad_read(struct file *filp, struct kobject *kobj,
{
struct w1_slave *sl = kobj_to_w1_slave(kobj);
int ret;
- ssize_t c = PAGE_SIZE;
uint16_t voltage;
if (off != 0)
@@ -321,8 +362,7 @@ static ssize_t vad_read(struct file *filp, struct kobject *kobj,
return -EINVAL;
if (w1_ds2438_get_voltage(sl, DS2438_ADC_INPUT_VAD, &voltage) == 0) {
- c -= snprintf(buf + PAGE_SIZE - c, c, "%d\n", voltage);
- ret = PAGE_SIZE - c;
+ ret = snprintf(buf, count, "%u\n", voltage);
} else
ret = -EIO;
@@ -335,7 +375,6 @@ static ssize_t vdd_read(struct file *filp, struct kobject *kobj,
{
struct w1_slave *sl = kobj_to_w1_slave(kobj);
int ret;
- ssize_t c = PAGE_SIZE;
uint16_t voltage;
if (off != 0)
@@ -344,15 +383,14 @@ static ssize_t vdd_read(struct file *filp, struct kobject *kobj,
return -EINVAL;
if (w1_ds2438_get_voltage(sl, DS2438_ADC_INPUT_VDD, &voltage) == 0) {
- c -= snprintf(buf + PAGE_SIZE - c, c, "%d\n", voltage);
- ret = PAGE_SIZE - c;
+ ret = snprintf(buf, count, "%u\n", voltage);
} else
ret = -EIO;
return ret;
}
-static BIN_ATTR(iad, S_IRUGO | S_IWUSR | S_IWGRP, NULL, iad_write, 1);
+static BIN_ATTR(iad, S_IRUGO | S_IWUSR | S_IWGRP, iad_read, iad_write, 0);
static BIN_ATTR_RO(page0, DS2438_PAGE_SIZE);
static BIN_ATTR_RO(temperature, 0/* real length varies */);
static BIN_ATTR_RO(vad, 0/* real length varies */);
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 5ea8909a41f9..2d64333f4782 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -273,6 +273,17 @@ config ARM_SBSA_WATCHDOG
To compile this driver as module, choose M here: The module
will be called sbsa_gwdt.
+config ARMADA_37XX_WATCHDOG
+ tristate "Armada 37xx watchdog"
+ depends on ARCH_MVEBU || COMPILE_TEST
+ select MFD_SYSCON
+ select WATCHDOG_CORE
+ help
+ Say Y here to include support for the watchdog timer found on
+ Marvell Armada 37xx SoCs.
+ To compile this driver as a module, choose M here: the
+ module will be called armada_37xx_wdt.
+
config ASM9260_WATCHDOG
tristate "Alphascale ASM9260 watchdog"
depends on MACH_ASM9260 || COMPILE_TEST
@@ -1621,6 +1632,7 @@ config IMGPDC_WDT
config LANTIQ_WDT
tristate "Lantiq SoC watchdog"
depends on LANTIQ
+ select WATCHDOG_CORE
help
Hardware driver for the Lantiq SoC Watchdog Timer.
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index bf92e7bf9ce0..f69cdff5ad7f 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
# ARM Architecture
obj-$(CONFIG_ARM_SP805_WATCHDOG) += sp805_wdt.o
obj-$(CONFIG_ARM_SBSA_WATCHDOG) += sbsa_gwdt.o
+obj-$(CONFIG_ARMADA_37XX_WATCHDOG) += armada_37xx_wdt.o
obj-$(CONFIG_ASM9260_WATCHDOG) += asm9260_wdt.o
obj-$(CONFIG_AT91RM9200_WATCHDOG) += at91rm9200_wdt.o
obj-$(CONFIG_AT91SAM9X_WATCHDOG) += at91sam9_wdt.o
diff --git a/drivers/watchdog/armada_37xx_wdt.c b/drivers/watchdog/armada_37xx_wdt.c
new file mode 100644
index 000000000000..4b4054f54df9
--- /dev/null
+++ b/drivers/watchdog/armada_37xx_wdt.c
@@ -0,0 +1,388 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Watchdog driver for Marvell Armada 37xx SoCs
+ *
+ * Author: Marek Behun <marek.behun@nic.cz>
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+#include <linux/watchdog.h>
+
+/*
+ * There are four counters that can be used for watchdog on Armada 37xx.
+ * The addresses for counter control registers are register base plus ID*0x10,
+ * where ID is 0, 1, 2 or 3.
+ *
+ * In this driver we use IDs 0 and 1. Counter ID 1 is used as watchdog counter,
+ * while counter ID 0 is used to implement pinging the watchdog: counter ID 1 is
+ * set to restart counting from initial value on counter ID 0 end count event.
+ * Pinging is done by forcing immediate end count event on counter ID 0.
+ * If only one counter was used, pinging would have to be implemented by
+ * disabling and enabling the counter, leaving the system in a vulnerable state
+ * for a (really) short period of time.
+ *
+ * Counters ID 2 and 3 are enabled by default even before U-Boot loads,
+ * therefore this driver does not provide a way to use them, eg. by setting a
+ * property in device tree.
+ */
+
+#define CNTR_ID_RETRIGGER 0
+#define CNTR_ID_WDOG 1
+
+/* relative to cpu_misc */
+#define WDT_TIMER_SELECT 0x64
+#define WDT_TIMER_SELECT_MASK 0xf
+#define WDT_TIMER_SELECT_VAL BIT(CNTR_ID_WDOG)
+
+/* relative to reg */
+#define CNTR_CTRL(id) ((id) * 0x10)
+#define CNTR_CTRL_ENABLE 0x0001
+#define CNTR_CTRL_ACTIVE 0x0002
+#define CNTR_CTRL_MODE_MASK 0x000c
+#define CNTR_CTRL_MODE_ONESHOT 0x0000
+#define CNTR_CTRL_MODE_HWSIG 0x000c
+#define CNTR_CTRL_TRIG_SRC_MASK 0x00f0
+#define CNTR_CTRL_TRIG_SRC_PREV_CNTR 0x0050
+#define CNTR_CTRL_PRESCALE_MASK 0xff00
+#define CNTR_CTRL_PRESCALE_MIN 2
+#define CNTR_CTRL_PRESCALE_SHIFT 8
+
+#define CNTR_COUNT_LOW(id) (CNTR_CTRL(id) + 0x4)
+#define CNTR_COUNT_HIGH(id) (CNTR_CTRL(id) + 0x8)
+
+#define WATCHDOG_TIMEOUT 120
+
+static unsigned int timeout;
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds");
+
+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) ")");
+
+struct armada_37xx_watchdog {
+ struct watchdog_device wdt;
+ struct regmap *cpu_misc;
+ void __iomem *reg;
+ u64 timeout; /* in clock ticks */
+ unsigned long clk_rate;
+ struct clk *clk;
+};
+
+static u64 get_counter_value(struct armada_37xx_watchdog *dev, int id)
+{
+ u64 val;
+
+ /*
+ * when low is read, high is latched into flip-flops so that it can be
+ * read consistently without using software debouncing
+ */
+ val = readl(dev->reg + CNTR_COUNT_LOW(id));
+ val |= ((u64)readl(dev->reg + CNTR_COUNT_HIGH(id))) << 32;
+
+ return val;
+}
+
+static void set_counter_value(struct armada_37xx_watchdog *dev, int id, u64 val)
+{
+ writel(val & 0xffffffff, dev->reg + CNTR_COUNT_LOW(id));
+ writel(val >> 32, dev->reg + CNTR_COUNT_HIGH(id));
+}
+
+static void counter_enable(struct armada_37xx_watchdog *dev, int id)
+{
+ u32 reg;
+
+ reg = readl(dev->reg + CNTR_CTRL(id));
+ reg |= CNTR_CTRL_ENABLE;
+ writel(reg, dev->reg + CNTR_CTRL(id));
+}
+
+static void counter_disable(struct armada_37xx_watchdog *dev, int id)
+{
+ u32 reg;
+
+ reg = readl(dev->reg + CNTR_CTRL(id));
+ reg &= ~CNTR_CTRL_ENABLE;
+ writel(reg, dev->reg + CNTR_CTRL(id));
+}
+
+static void init_counter(struct armada_37xx_watchdog *dev, int id, u32 mode,
+ u32 trig_src)
+{
+ u32 reg;
+
+ reg = readl(dev->reg + CNTR_CTRL(id));
+
+ reg &= ~(CNTR_CTRL_MODE_MASK | CNTR_CTRL_PRESCALE_MASK |
+ CNTR_CTRL_TRIG_SRC_MASK);
+
+ /* set mode */
+ reg |= mode & CNTR_CTRL_MODE_MASK;
+
+ /* set prescaler to the min value */
+ reg |= CNTR_CTRL_PRESCALE_MIN << CNTR_CTRL_PRESCALE_SHIFT;
+
+ /* set trigger source */
+ reg |= trig_src & CNTR_CTRL_TRIG_SRC_MASK;
+
+ writel(reg, dev->reg + CNTR_CTRL(id));
+}
+
+static int armada_37xx_wdt_ping(struct watchdog_device *wdt)
+{
+ struct armada_37xx_watchdog *dev = watchdog_get_drvdata(wdt);
+
+ /* counter 1 is retriggered by forcing end count on counter 0 */
+ counter_disable(dev, CNTR_ID_RETRIGGER);
+ counter_enable(dev, CNTR_ID_RETRIGGER);
+
+ return 0;
+}
+
+static unsigned int armada_37xx_wdt_get_timeleft(struct watchdog_device *wdt)
+{
+ struct armada_37xx_watchdog *dev = watchdog_get_drvdata(wdt);
+ u64 res;
+
+ res = get_counter_value(dev, CNTR_ID_WDOG) * CNTR_CTRL_PRESCALE_MIN;
+ do_div(res, dev->clk_rate);
+
+ return res;
+}
+
+static int armada_37xx_wdt_set_timeout(struct watchdog_device *wdt,
+ unsigned int timeout)
+{
+ struct armada_37xx_watchdog *dev = watchdog_get_drvdata(wdt);
+
+ wdt->timeout = timeout;
+
+ /*
+ * Compute the timeout in clock rate. We use smallest possible
+ * prescaler, which divides the clock rate by 2
+ * (CNTR_CTRL_PRESCALE_MIN).
+ */
+ dev->timeout = (u64)dev->clk_rate * timeout;
+ do_div(dev->timeout, CNTR_CTRL_PRESCALE_MIN);
+
+ return 0;
+}
+
+static bool armada_37xx_wdt_is_running(struct armada_37xx_watchdog *dev)
+{
+ u32 reg;
+
+ regmap_read(dev->cpu_misc, WDT_TIMER_SELECT, &reg);
+ if ((reg & WDT_TIMER_SELECT_MASK) != WDT_TIMER_SELECT_VAL)
+ return false;
+
+ reg = readl(dev->reg + CNTR_CTRL(CNTR_ID_WDOG));
+ return !!(reg & CNTR_CTRL_ACTIVE);
+}
+
+static int armada_37xx_wdt_start(struct watchdog_device *wdt)
+{
+ struct armada_37xx_watchdog *dev = watchdog_get_drvdata(wdt);
+
+ /* select counter 1 as watchdog counter */
+ regmap_write(dev->cpu_misc, WDT_TIMER_SELECT, WDT_TIMER_SELECT_VAL);
+
+ /* init counter 0 as retrigger counter for counter 1 */
+ init_counter(dev, CNTR_ID_RETRIGGER, CNTR_CTRL_MODE_ONESHOT, 0);
+ set_counter_value(dev, CNTR_ID_RETRIGGER, 0);
+
+ /* init counter 1 to be retriggerable by counter 0 end count */
+ init_counter(dev, CNTR_ID_WDOG, CNTR_CTRL_MODE_HWSIG,
+ CNTR_CTRL_TRIG_SRC_PREV_CNTR);
+ set_counter_value(dev, CNTR_ID_WDOG, dev->timeout);
+
+ /* enable counter 1 */
+ counter_enable(dev, CNTR_ID_WDOG);
+
+ /* start counter 1 by forcing immediate end count on counter 0 */
+ counter_enable(dev, CNTR_ID_RETRIGGER);
+
+ return 0;
+}
+
+static int armada_37xx_wdt_stop(struct watchdog_device *wdt)
+{
+ struct armada_37xx_watchdog *dev = watchdog_get_drvdata(wdt);
+
+ counter_disable(dev, CNTR_ID_WDOG);
+ counter_disable(dev, CNTR_ID_RETRIGGER);
+ regmap_write(dev->cpu_misc, WDT_TIMER_SELECT, 0);
+
+ return 0;
+}
+
+static const struct watchdog_info armada_37xx_wdt_info = {
+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
+ .identity = "Armada 37xx Watchdog",
+};
+
+static const struct watchdog_ops armada_37xx_wdt_ops = {
+ .owner = THIS_MODULE,
+ .start = armada_37xx_wdt_start,
+ .stop = armada_37xx_wdt_stop,
+ .ping = armada_37xx_wdt_ping,
+ .set_timeout = armada_37xx_wdt_set_timeout,
+ .get_timeleft = armada_37xx_wdt_get_timeleft,
+};
+
+static int armada_37xx_wdt_probe(struct platform_device *pdev)
+{
+ struct armada_37xx_watchdog *dev;
+ struct resource *res;
+ struct regmap *regmap;
+ int ret;
+
+ dev = devm_kzalloc(&pdev->dev, sizeof(struct armada_37xx_watchdog),
+ GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ dev->wdt.info = &armada_37xx_wdt_info;
+ dev->wdt.ops = &armada_37xx_wdt_ops;
+
+ regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+ "marvell,system-controller");
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+ dev->cpu_misc = regmap;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+ dev->reg = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+
+ /* init clock */
+ dev->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(dev->clk))
+ return PTR_ERR(dev->clk);
+
+ ret = clk_prepare_enable(dev->clk);
+ if (ret)
+ return ret;
+
+ dev->clk_rate = clk_get_rate(dev->clk);
+ if (!dev->clk_rate) {
+ ret = -EINVAL;
+ goto disable_clk;
+ }
+
+ /*
+ * Since the timeout in seconds is given as 32 bit unsigned int, and
+ * the counters hold 64 bit values, even after multiplication by clock
+ * rate the counter can hold timeout of UINT_MAX seconds.
+ */
+ dev->wdt.min_timeout = 1;
+ dev->wdt.max_timeout = UINT_MAX;
+ dev->wdt.parent = &pdev->dev;
+
+ /* default value, possibly override by module parameter or dtb */
+ dev->wdt.timeout = WATCHDOG_TIMEOUT;
+ watchdog_init_timeout(&dev->wdt, timeout, &pdev->dev);
+
+ platform_set_drvdata(pdev, &dev->wdt);
+ watchdog_set_drvdata(&dev->wdt, dev);
+
+ armada_37xx_wdt_set_timeout(&dev->wdt, dev->wdt.timeout);
+
+ if (armada_37xx_wdt_is_running(dev))
+ set_bit(WDOG_HW_RUNNING, &dev->wdt.status);
+
+ watchdog_set_nowayout(&dev->wdt, nowayout);
+ ret = watchdog_register_device(&dev->wdt);
+ if (ret)
+ goto disable_clk;
+
+ dev_info(&pdev->dev, "Initial timeout %d sec%s\n",
+ dev->wdt.timeout, nowayout ? ", nowayout" : "");
+
+ return 0;
+
+disable_clk:
+ clk_disable_unprepare(dev->clk);
+ return ret;
+}
+
+static int armada_37xx_wdt_remove(struct platform_device *pdev)
+{
+ struct watchdog_device *wdt = platform_get_drvdata(pdev);
+ struct armada_37xx_watchdog *dev = watchdog_get_drvdata(wdt);
+
+ watchdog_unregister_device(wdt);
+ clk_disable_unprepare(dev->clk);
+ return 0;
+}
+
+static void armada_37xx_wdt_shutdown(struct platform_device *pdev)
+{
+ struct watchdog_device *wdt = platform_get_drvdata(pdev);
+
+ armada_37xx_wdt_stop(wdt);
+}
+
+static int __maybe_unused armada_37xx_wdt_suspend(struct device *dev)
+{
+ struct watchdog_device *wdt = dev_get_drvdata(dev);
+
+ return armada_37xx_wdt_stop(wdt);
+}
+
+static int __maybe_unused armada_37xx_wdt_resume(struct device *dev)
+{
+ struct watchdog_device *wdt = dev_get_drvdata(dev);
+
+ if (watchdog_active(wdt))
+ return armada_37xx_wdt_start(wdt);
+
+ return 0;
+}
+
+static const struct dev_pm_ops armada_37xx_wdt_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(armada_37xx_wdt_suspend,
+ armada_37xx_wdt_resume)
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id armada_37xx_wdt_match[] = {
+ { .compatible = "marvell,armada-3700-wdt", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, armada_37xx_wdt_match);
+#endif
+
+static struct platform_driver armada_37xx_wdt_driver = {
+ .probe = armada_37xx_wdt_probe,
+ .remove = armada_37xx_wdt_remove,
+ .shutdown = armada_37xx_wdt_shutdown,
+ .driver = {
+ .name = "armada_37xx_wdt",
+ .of_match_table = of_match_ptr(armada_37xx_wdt_match),
+ .pm = &armada_37xx_wdt_dev_pm_ops,
+ },
+};
+
+module_platform_driver(armada_37xx_wdt_driver);
+
+MODULE_AUTHOR("Marek Behun <marek.behun@nic.cz>");
+MODULE_DESCRIPTION("Armada 37xx CPU Watchdog");
+
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:armada_37xx_wdt");
diff --git a/drivers/watchdog/booke_wdt.c b/drivers/watchdog/booke_wdt.c
index 3ad1e44bef44..6e78a34c2370 100644
--- a/drivers/watchdog/booke_wdt.c
+++ b/drivers/watchdog/booke_wdt.c
@@ -25,7 +25,7 @@
/* If the kernel parameter wdt=1, the watchdog will be enabled at boot.
* Also, the wdt_period sets the watchdog timer period timeout.
* For E500 cpus the wdt_period sets which bit changing from 0->1 will
- * trigger a watchog timeout. This watchdog timeout will occur 3 times, the
+ * trigger a watchdog timeout. This watchdog timeout will occur 3 times, the
* first time nothing will happen, the second time a watchdog exception will
* occur, and the final time the board will reset.
*/
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c
index 9dc62a461451..93562304f7aa 100644
--- a/drivers/watchdog/hpwdt.c
+++ b/drivers/watchdog/hpwdt.c
@@ -26,7 +26,7 @@
#include <linux/watchdog.h>
#include <asm/nmi.h>
-#define HPWDT_VERSION "2.0.0"
+#define HPWDT_VERSION "2.0.1"
#define SECS_TO_TICKS(secs) ((secs) * 1000 / 128)
#define TICKS_TO_SECS(ticks) ((ticks) * 128 / 1000)
#define HPWDT_MAX_TIMER TICKS_TO_SECS(65535)
@@ -162,7 +162,7 @@ static int hpwdt_pretimeout(unsigned int ulReason, struct pt_regs *regs)
if (ilo5 && ulReason == NMI_UNKNOWN && !mynmi)
return NMI_DONE;
- if (ilo5 && !pretimeout)
+ if (ilo5 && !pretimeout && !mynmi)
return NMI_DONE;
hpwdt_stop();
@@ -205,9 +205,7 @@ static struct watchdog_device hpwdt_dev = {
.min_timeout = 1,
.max_timeout = HPWDT_MAX_TIMER,
.timeout = DEFAULT_MARGIN,
-#ifdef CONFIG_HPWDT_NMI_DECODING
.pretimeout = PRETIMEOUT_SEC,
-#endif
};
@@ -313,6 +311,12 @@ static int hpwdt_init_one(struct pci_dev *dev,
if (watchdog_init_timeout(&hpwdt_dev, soft_margin, NULL))
dev_warn(&dev->dev, "Invalid soft_margin: %d.\n", soft_margin);
+ if (pretimeout && hpwdt_dev.timeout <= PRETIMEOUT_SEC) {
+ dev_warn(&dev->dev, "timeout <= pretimeout. Setting pretimeout to zero\n");
+ pretimeout = 0;
+ }
+ hpwdt_dev.pretimeout = pretimeout ? PRETIMEOUT_SEC : 0;
+
hpwdt_dev.parent = &dev->dev;
retval = watchdog_register_device(&hpwdt_dev);
if (retval < 0) {
@@ -320,9 +324,12 @@ static int hpwdt_init_one(struct pci_dev *dev,
goto error_wd_register;
}
- dev_info(&dev->dev, "HPE Watchdog Timer Driver: %s"
- ", timer margin: %d seconds (nowayout=%d).\n",
- HPWDT_VERSION, hpwdt_dev.timeout, nowayout);
+ dev_info(&dev->dev, "HPE Watchdog Timer Driver: Version: %s\n",
+ HPWDT_VERSION);
+ dev_info(&dev->dev, "timeout: %d seconds (nowayout=%d)\n",
+ hpwdt_dev.timeout, nowayout);
+ dev_info(&dev->dev, "pretimeout: %s.\n",
+ pretimeout ? "on" : "off");
if (dev->subsystem_vendor == PCI_VENDOR_ID_HP_3PAR)
ilo5 = true;
@@ -364,6 +371,9 @@ MODULE_VERSION(HPWDT_VERSION);
module_param(soft_margin, int, 0);
MODULE_PARM_DESC(soft_margin, "Watchdog timeout in seconds");
+module_param_named(timeout, soft_margin, int, 0);
+MODULE_PARM_DESC(timeout, "Alias of soft_margin");
+
module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
diff --git a/drivers/watchdog/iTCO_vendor.h b/drivers/watchdog/iTCO_vendor.h
index 7b82a7c6e7c3..0f7373ba10d5 100644
--- a/drivers/watchdog/iTCO_vendor.h
+++ b/drivers/watchdog/iTCO_vendor.h
@@ -3,14 +3,10 @@
#ifdef CONFIG_ITCO_VENDOR_SUPPORT
extern void iTCO_vendor_pre_start(struct resource *, unsigned int);
extern void iTCO_vendor_pre_stop(struct resource *);
-extern void iTCO_vendor_pre_keepalive(struct resource *, unsigned int);
-extern void iTCO_vendor_pre_set_heartbeat(unsigned int);
extern int iTCO_vendor_check_noreboot_on(void);
#else
#define iTCO_vendor_pre_start(acpibase, heartbeat) {}
#define iTCO_vendor_pre_stop(acpibase) {}
-#define iTCO_vendor_pre_keepalive(acpibase, heartbeat) {}
-#define iTCO_vendor_pre_set_heartbeat(heartbeat) {}
#define iTCO_vendor_check_noreboot_on() 1
/* 1=check noreboot; 0=don't check */
#endif
diff --git a/drivers/watchdog/iTCO_vendor_support.c b/drivers/watchdog/iTCO_vendor_support.c
index b6b2f90b5d44..68a9d9cc2eb8 100644
--- a/drivers/watchdog/iTCO_vendor_support.c
+++ b/drivers/watchdog/iTCO_vendor_support.c
@@ -38,7 +38,7 @@
/* List of vendor support modes */
/* SuperMicro Pentium 3 Era 370SSE+-OEM1/P3TSSE */
#define SUPERMICRO_OLD_BOARD 1
-/* SuperMicro Pentium 4 / Xeon 4 / EMT64T Era Systems */
+/* SuperMicro Pentium 4 / Xeon 4 / EMT64T Era Systems - no longer supported */
#define SUPERMICRO_NEW_BOARD 2
/* Broken BIOS */
#define BROKEN_BIOS 911
@@ -46,8 +46,7 @@
static int vendorsupport;
module_param(vendorsupport, int, 0);
MODULE_PARM_DESC(vendorsupport, "iTCO vendor specific support mode, default="
- "0 (none), 1=SuperMicro Pent3, 2=SuperMicro Pent4+, "
- "911=Broken SMI BIOS");
+ "0 (none), 1=SuperMicro Pent3, 911=Broken SMI BIOS");
/*
* Vendor Specific Support
@@ -98,143 +97,6 @@ static void supermicro_old_pre_stop(struct resource *smires)
}
/*
- * Vendor Support: 2
- * Board: Super Micro Computer Inc. P4SBx, P4DPx
- * iTCO chipset: ICH4
- *
- * Code contributed by: R. Seretny <lkpatches@paypc.com>
- * Documentation obtained by R. Seretny from SuperMicro Technical Support
- *
- * To enable Watchdog function:
- * 1. BIOS
- * For P4SBx:
- * BIOS setup -> Advanced -> Integrated Peripherals -> Watch Dog Feature
- * For P4DPx:
- * BIOS setup -> Advanced -> I/O Device Configuration -> Watch Dog
- * This setting enables or disables Watchdog function. When enabled, the
- * default watchdog timer is set to be 5 minutes (about 4m35s). It is
- * enough to load and run the OS. The application (service or driver) has
- * to take over the control once OS is running up and before watchdog
- * expires.
- *
- * 2. JUMPER
- * For P4SBx: JP39
- * For P4DPx: JP37
- * This jumper is used for safety. Closed is enabled. This jumper
- * prevents user enables watchdog in BIOS by accident.
- *
- * To enable Watch Dog function, both BIOS and JUMPER must be enabled.
- *
- * The documentation lists motherboards P4SBx and P4DPx series as of
- * 20-March-2002. However, this code works flawlessly with much newer
- * motherboards, such as my X6DHR-8G2 (SuperServer 6014H-82).
- *
- * The original iTCO driver as written does not actually reset the
- * watchdog timer on these machines, as a result they reboot after five
- * minutes.
- *
- * NOTE: You may leave the Watchdog function disabled in the SuperMicro
- * BIOS to avoid a "boot-race"... This driver will enable watchdog
- * functionality even if it's disabled in the BIOS once the /dev/watchdog
- * file is opened.
- */
-
-/* I/O Port's */
-#define SM_REGINDEX 0x2e /* SuperMicro ICH4+ Register Index */
-#define SM_DATAIO 0x2f /* SuperMicro ICH4+ Register Data I/O */
-
-/* Control Register's */
-#define SM_CTLPAGESW 0x07 /* SuperMicro ICH4+ Control Page Switch */
-#define SM_CTLPAGE 0x08 /* SuperMicro ICH4+ Control Page Num */
-
-#define SM_WATCHENABLE 0x30 /* Watchdog enable: Bit 0: 0=off, 1=on */
-
-#define SM_WATCHPAGE 0x87 /* Watchdog unlock control page */
-
-#define SM_ENDWATCH 0xAA /* Watchdog lock control page */
-
-#define SM_COUNTMODE 0xf5 /* Watchdog count mode select */
- /* (Bit 3: 0 = seconds, 1 = minutes */
-
-#define SM_WATCHTIMER 0xf6 /* 8-bits, Watchdog timer counter (RW) */
-
-#define SM_RESETCONTROL 0xf7 /* Watchdog reset control */
- /* Bit 6: timer is reset by kbd interrupt */
- /* Bit 7: timer is reset by mouse interrupt */
-
-static void supermicro_new_unlock_watchdog(void)
-{
- /* Write 0x87 to port 0x2e twice */
- outb(SM_WATCHPAGE, SM_REGINDEX);
- outb(SM_WATCHPAGE, SM_REGINDEX);
- /* Switch to watchdog control page */
- outb(SM_CTLPAGESW, SM_REGINDEX);
- outb(SM_CTLPAGE, SM_DATAIO);
-}
-
-static void supermicro_new_lock_watchdog(void)
-{
- outb(SM_ENDWATCH, SM_REGINDEX);
-}
-
-static void supermicro_new_pre_start(unsigned int heartbeat)
-{
- unsigned int val;
-
- supermicro_new_unlock_watchdog();
-
- /* Watchdog timer setting needs to be in seconds*/
- outb(SM_COUNTMODE, SM_REGINDEX);
- val = inb(SM_DATAIO);
- val &= 0xF7;
- outb(val, SM_DATAIO);
-
- /* Write heartbeat interval to WDOG */
- outb(SM_WATCHTIMER, SM_REGINDEX);
- outb((heartbeat & 255), SM_DATAIO);
-
- /* Make sure keyboard/mouse interrupts don't interfere */
- outb(SM_RESETCONTROL, SM_REGINDEX);
- val = inb(SM_DATAIO);
- val &= 0x3f;
- outb(val, SM_DATAIO);
-
- /* enable watchdog by setting bit 0 of Watchdog Enable to 1 */
- outb(SM_WATCHENABLE, SM_REGINDEX);
- val = inb(SM_DATAIO);
- val |= 0x01;
- outb(val, SM_DATAIO);
-
- supermicro_new_lock_watchdog();
-}
-
-static void supermicro_new_pre_stop(void)
-{
- unsigned int val;
-
- supermicro_new_unlock_watchdog();
-
- /* disable watchdog by setting bit 0 of Watchdog Enable to 0 */
- outb(SM_WATCHENABLE, SM_REGINDEX);
- val = inb(SM_DATAIO);
- val &= 0xFE;
- outb(val, SM_DATAIO);
-
- supermicro_new_lock_watchdog();
-}
-
-static void supermicro_new_pre_set_heartbeat(unsigned int heartbeat)
-{
- supermicro_new_unlock_watchdog();
-
- /* reset watchdog timeout to heartveat value */
- outb(SM_WATCHTIMER, SM_REGINDEX);
- outb((heartbeat & 255), SM_DATAIO);
-
- supermicro_new_lock_watchdog();
-}
-
-/*
* Vendor Support: 911
* Board: Some Intel ICHx based motherboards
* iTCO chipset: ICH7+
@@ -298,9 +160,6 @@ void iTCO_vendor_pre_start(struct resource *smires,
case SUPERMICRO_OLD_BOARD:
supermicro_old_pre_start(smires);
break;
- case SUPERMICRO_NEW_BOARD:
- supermicro_new_pre_start(heartbeat);
- break;
case BROKEN_BIOS:
broken_bios_start(smires);
break;
@@ -314,9 +173,6 @@ void iTCO_vendor_pre_stop(struct resource *smires)
case SUPERMICRO_OLD_BOARD:
supermicro_old_pre_stop(smires);
break;
- case SUPERMICRO_NEW_BOARD:
- supermicro_new_pre_stop();
- break;
case BROKEN_BIOS:
broken_bios_stop(smires);
break;
@@ -324,20 +180,6 @@ void iTCO_vendor_pre_stop(struct resource *smires)
}
EXPORT_SYMBOL(iTCO_vendor_pre_stop);
-void iTCO_vendor_pre_keepalive(struct resource *smires, unsigned int heartbeat)
-{
- if (vendorsupport == SUPERMICRO_NEW_BOARD)
- supermicro_new_pre_set_heartbeat(heartbeat);
-}
-EXPORT_SYMBOL(iTCO_vendor_pre_keepalive);
-
-void iTCO_vendor_pre_set_heartbeat(unsigned int heartbeat)
-{
- if (vendorsupport == SUPERMICRO_NEW_BOARD)
- supermicro_new_pre_set_heartbeat(heartbeat);
-}
-EXPORT_SYMBOL(iTCO_vendor_pre_set_heartbeat);
-
int iTCO_vendor_check_noreboot_on(void)
{
switch (vendorsupport) {
@@ -351,6 +193,12 @@ EXPORT_SYMBOL(iTCO_vendor_check_noreboot_on);
static int __init iTCO_vendor_init_module(void)
{
+ if (vendorsupport == SUPERMICRO_NEW_BOARD) {
+ pr_warn("Option vendorsupport=%d is no longer supported, "
+ "please use the w83627hf_wdt driver instead\n",
+ SUPERMICRO_NEW_BOARD);
+ return -EINVAL;
+ }
pr_info("vendor-support=%d\n", vendorsupport);
return 0;
}
diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c
index 347f0389b089..0a5318b7865e 100644
--- a/drivers/watchdog/iTCO_wdt.c
+++ b/drivers/watchdog/iTCO_wdt.c
@@ -304,8 +304,6 @@ static int iTCO_wdt_ping(struct watchdog_device *wd_dev)
spin_lock(&p->io_lock);
- iTCO_vendor_pre_keepalive(p->smi_res, wd_dev->timeout);
-
/* Reload the timer by writing to the TCO Timer Counter register */
if (p->iTCO_version >= 2) {
outw(0x01, TCO_RLD(p));
@@ -342,8 +340,6 @@ static int iTCO_wdt_set_timeout(struct watchdog_device *wd_dev, unsigned int t)
(p->iTCO_version == 1 && tmrval > 0x03f))
return -EINVAL;
- iTCO_vendor_pre_set_heartbeat(tmrval);
-
/* Write new heartbeat to watchdog */
if (p->iTCO_version >= 2) {
spin_lock(&p->io_lock);
diff --git a/drivers/watchdog/lantiq_wdt.c b/drivers/watchdog/lantiq_wdt.c
index 7f43cefa0eae..83da84d6074b 100644
--- a/drivers/watchdog/lantiq_wdt.c
+++ b/drivers/watchdog/lantiq_wdt.c
@@ -8,11 +8,8 @@
* Based on EP93xx wdt driver
*/
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/miscdevice.h>
+#include <linux/bitops.h>
#include <linux/watchdog.h>
#include <linux/of_platform.h>
#include <linux/uaccess.h>
@@ -40,169 +37,128 @@
* essentially the following two magic passwords need to be written to allow
* IO access to the WDT core
*/
-#define LTQ_WDT_PW1 0x00BE0000
-#define LTQ_WDT_PW2 0x00DC0000
-
-#define LTQ_WDT_CR 0x0 /* watchdog control register */
-#define LTQ_WDT_SR 0x8 /* watchdog status register */
+#define LTQ_WDT_CR_PW1 0x00BE0000
+#define LTQ_WDT_CR_PW2 0x00DC0000
+
+#define LTQ_WDT_CR 0x0 /* watchdog control register */
+#define LTQ_WDT_CR_GEN BIT(31) /* enable bit */
+/* Pre-warning limit set to 1/16 of max WDT period */
+#define LTQ_WDT_CR_PWL (0x3 << 26)
+/* set clock divider to 0x40000 */
+#define LTQ_WDT_CR_CLKDIV (0x3 << 24)
+#define LTQ_WDT_CR_PW_MASK GENMASK(23, 16) /* Password field */
+#define LTQ_WDT_CR_MAX_TIMEOUT ((1 << 16) - 1) /* The reload field is 16 bit */
+#define LTQ_WDT_SR 0x8 /* watchdog status register */
+#define LTQ_WDT_SR_EN BIT(31) /* Enable */
+#define LTQ_WDT_SR_VALUE_MASK GENMASK(15, 0) /* Timer value */
-#define LTQ_WDT_SR_EN (0x1 << 31) /* enable bit */
-#define LTQ_WDT_SR_PWD (0x3 << 26) /* turn on power */
-#define LTQ_WDT_SR_CLKDIV (0x3 << 24) /* turn on clock and set */
- /* divider to 0x40000 */
#define LTQ_WDT_DIVIDER 0x40000
-#define LTQ_MAX_TIMEOUT ((1 << 16) - 1) /* the reload field is 16 bit */
static bool nowayout = WATCHDOG_NOWAYOUT;
-static void __iomem *ltq_wdt_membase;
-static unsigned long ltq_io_region_clk_rate;
+struct ltq_wdt_hw {
+ int (*bootstatus_get)(struct device *dev);
+};
-static unsigned long ltq_wdt_bootstatus;
-static unsigned long ltq_wdt_in_use;
-static int ltq_wdt_timeout = 30;
-static int ltq_wdt_ok_to_close;
+struct ltq_wdt_priv {
+ struct watchdog_device wdt;
+ void __iomem *membase;
+ unsigned long clk_rate;
+};
-static void
-ltq_wdt_enable(void)
+static u32 ltq_wdt_r32(struct ltq_wdt_priv *priv, u32 offset)
{
- unsigned long int timeout = ltq_wdt_timeout *
- (ltq_io_region_clk_rate / LTQ_WDT_DIVIDER) + 0x1000;
- if (timeout > LTQ_MAX_TIMEOUT)
- timeout = LTQ_MAX_TIMEOUT;
-
- /* write the first password magic */
- ltq_w32(LTQ_WDT_PW1, ltq_wdt_membase + LTQ_WDT_CR);
- /* write the second magic plus the configuration and new timeout */
- ltq_w32(LTQ_WDT_SR_EN | LTQ_WDT_SR_PWD | LTQ_WDT_SR_CLKDIV |
- LTQ_WDT_PW2 | timeout, ltq_wdt_membase + LTQ_WDT_CR);
+ return __raw_readl(priv->membase + offset);
}
-static void
-ltq_wdt_disable(void)
+static void ltq_wdt_w32(struct ltq_wdt_priv *priv, u32 val, u32 offset)
{
- /* write the first password magic */
- ltq_w32(LTQ_WDT_PW1, ltq_wdt_membase + LTQ_WDT_CR);
- /*
- * write the second password magic with no config
- * this turns the watchdog off
- */
- ltq_w32(LTQ_WDT_PW2, ltq_wdt_membase + LTQ_WDT_CR);
+ __raw_writel(val, priv->membase + offset);
}
-static ssize_t
-ltq_wdt_write(struct file *file, const char __user *data,
- size_t len, loff_t *ppos)
+static void ltq_wdt_mask(struct ltq_wdt_priv *priv, u32 clear, u32 set,
+ u32 offset)
{
- if (len) {
- if (!nowayout) {
- size_t i;
-
- ltq_wdt_ok_to_close = 0;
- for (i = 0; i != len; i++) {
- char c;
-
- if (get_user(c, data + i))
- return -EFAULT;
- if (c == 'V')
- ltq_wdt_ok_to_close = 1;
- else
- ltq_wdt_ok_to_close = 0;
- }
- }
- ltq_wdt_enable();
- }
+ u32 val = ltq_wdt_r32(priv, offset);
- return len;
+ val &= ~(clear);
+ val |= set;
+ ltq_wdt_w32(priv, val, offset);
}
-static struct watchdog_info ident = {
+static struct ltq_wdt_priv *ltq_wdt_get_priv(struct watchdog_device *wdt)
+{
+ return container_of(wdt, struct ltq_wdt_priv, wdt);
+}
+
+static struct watchdog_info ltq_wdt_info = {
.options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
- WDIOF_CARDRESET,
+ WDIOF_CARDRESET,
.identity = "ltq_wdt",
};
-static long
-ltq_wdt_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
+static int ltq_wdt_start(struct watchdog_device *wdt)
{
- int ret = -ENOTTY;
-
- switch (cmd) {
- case WDIOC_GETSUPPORT:
- ret = copy_to_user((struct watchdog_info __user *)arg, &ident,
- sizeof(ident)) ? -EFAULT : 0;
- break;
-
- case WDIOC_GETBOOTSTATUS:
- ret = put_user(ltq_wdt_bootstatus, (int __user *)arg);
- break;
-
- case WDIOC_GETSTATUS:
- ret = put_user(0, (int __user *)arg);
- break;
-
- case WDIOC_SETTIMEOUT:
- ret = get_user(ltq_wdt_timeout, (int __user *)arg);
- if (!ret)
- ltq_wdt_enable();
- /* intentional drop through */
- case WDIOC_GETTIMEOUT:
- ret = put_user(ltq_wdt_timeout, (int __user *)arg);
- break;
-
- case WDIOC_KEEPALIVE:
- ltq_wdt_enable();
- ret = 0;
- break;
- }
- return ret;
+ struct ltq_wdt_priv *priv = ltq_wdt_get_priv(wdt);
+ u32 timeout;
+
+ timeout = wdt->timeout * priv->clk_rate;
+
+ ltq_wdt_mask(priv, LTQ_WDT_CR_PW_MASK, LTQ_WDT_CR_PW1, LTQ_WDT_CR);
+ /* write the second magic plus the configuration and new timeout */
+ ltq_wdt_mask(priv, LTQ_WDT_CR_PW_MASK | LTQ_WDT_CR_MAX_TIMEOUT,
+ LTQ_WDT_CR_GEN | LTQ_WDT_CR_PWL | LTQ_WDT_CR_CLKDIV |
+ LTQ_WDT_CR_PW2 | timeout,
+ LTQ_WDT_CR);
+
+ return 0;
}
-static int
-ltq_wdt_open(struct inode *inode, struct file *file)
+static int ltq_wdt_stop(struct watchdog_device *wdt)
{
- if (test_and_set_bit(0, &ltq_wdt_in_use))
- return -EBUSY;
- ltq_wdt_in_use = 1;
- ltq_wdt_enable();
+ struct ltq_wdt_priv *priv = ltq_wdt_get_priv(wdt);
- return nonseekable_open(inode, file);
+ ltq_wdt_mask(priv, LTQ_WDT_CR_PW_MASK, LTQ_WDT_CR_PW1, LTQ_WDT_CR);
+ ltq_wdt_mask(priv, LTQ_WDT_CR_GEN | LTQ_WDT_CR_PW_MASK,
+ LTQ_WDT_CR_PW2, LTQ_WDT_CR);
+
+ return 0;
}
-static int
-ltq_wdt_release(struct inode *inode, struct file *file)
+static int ltq_wdt_ping(struct watchdog_device *wdt)
{
- if (ltq_wdt_ok_to_close)
- ltq_wdt_disable();
- else
- pr_err("watchdog closed without warning\n");
- ltq_wdt_ok_to_close = 0;
- clear_bit(0, &ltq_wdt_in_use);
+ struct ltq_wdt_priv *priv = ltq_wdt_get_priv(wdt);
+ u32 timeout;
+
+ timeout = wdt->timeout * priv->clk_rate;
+
+ ltq_wdt_mask(priv, LTQ_WDT_CR_PW_MASK, LTQ_WDT_CR_PW1, LTQ_WDT_CR);
+ /* write the second magic plus the configuration and new timeout */
+ ltq_wdt_mask(priv, LTQ_WDT_CR_PW_MASK | LTQ_WDT_CR_MAX_TIMEOUT,
+ LTQ_WDT_CR_PW2 | timeout, LTQ_WDT_CR);
return 0;
}
-static const struct file_operations ltq_wdt_fops = {
- .owner = THIS_MODULE,
- .write = ltq_wdt_write,
- .unlocked_ioctl = ltq_wdt_ioctl,
- .open = ltq_wdt_open,
- .release = ltq_wdt_release,
- .llseek = no_llseek,
-};
+static unsigned int ltq_wdt_get_timeleft(struct watchdog_device *wdt)
+{
+ struct ltq_wdt_priv *priv = ltq_wdt_get_priv(wdt);
+ u64 timeout;
-static struct miscdevice ltq_wdt_miscdev = {
- .minor = WATCHDOG_MINOR,
- .name = "watchdog",
- .fops = &ltq_wdt_fops,
-};
+ timeout = ltq_wdt_r32(priv, LTQ_WDT_SR) & LTQ_WDT_SR_VALUE_MASK;
+ return do_div(timeout, priv->clk_rate);
+}
-typedef int (*ltq_wdt_bootstatus_set)(struct platform_device *pdev);
+static const struct watchdog_ops ltq_wdt_ops = {
+ .owner = THIS_MODULE,
+ .start = ltq_wdt_start,
+ .stop = ltq_wdt_stop,
+ .ping = ltq_wdt_ping,
+ .get_timeleft = ltq_wdt_get_timeleft,
+};
-static int ltq_wdt_bootstatus_xrx(struct platform_device *pdev)
+static int ltq_wdt_xrx_bootstatus_get(struct device *dev)
{
- struct device *dev = &pdev->dev;
struct regmap *rcu_regmap;
u32 val;
int err;
@@ -216,14 +172,13 @@ static int ltq_wdt_bootstatus_xrx(struct platform_device *pdev)
return err;
if (val & LTQ_XRX_RCU_RST_STAT_WDT)
- ltq_wdt_bootstatus = WDIOF_CARDRESET;
+ return WDIOF_CARDRESET;
return 0;
}
-static int ltq_wdt_bootstatus_falcon(struct platform_device *pdev)
+static int ltq_wdt_falcon_bootstatus_get(struct device *dev)
{
- struct device *dev = &pdev->dev;
struct regmap *rcu_regmap;
u32 val;
int err;
@@ -238,62 +193,90 @@ static int ltq_wdt_bootstatus_falcon(struct platform_device *pdev)
return err;
if ((val & LTQ_FALCON_SYS1_CPU0RS_MASK) == LTQ_FALCON_SYS1_CPU0RS_WDT)
- ltq_wdt_bootstatus = WDIOF_CARDRESET;
+ return WDIOF_CARDRESET;
return 0;
}
-static int
-ltq_wdt_probe(struct platform_device *pdev)
+static int ltq_wdt_probe(struct platform_device *pdev)
{
- struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ struct device *dev = &pdev->dev;
+ struct ltq_wdt_priv *priv;
+ struct watchdog_device *wdt;
+ struct resource *res;
struct clk *clk;
- ltq_wdt_bootstatus_set ltq_wdt_bootstatus_set;
+ const struct ltq_wdt_hw *ltq_wdt_hw;
int ret;
+ u32 status;
- ltq_wdt_membase = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(ltq_wdt_membase))
- return PTR_ERR(ltq_wdt_membase);
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
- ltq_wdt_bootstatus_set = of_device_get_match_data(&pdev->dev);
- if (ltq_wdt_bootstatus_set) {
- ret = ltq_wdt_bootstatus_set(pdev);
- if (ret)
- return ret;
- }
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->membase = devm_ioremap_resource(dev, res);
+ if (IS_ERR(priv->membase))
+ return PTR_ERR(priv->membase);
/* we do not need to enable the clock as it is always running */
clk = clk_get_io();
- if (IS_ERR(clk)) {
- dev_err(&pdev->dev, "Failed to get clock\n");
- return -ENOENT;
+ priv->clk_rate = clk_get_rate(clk) / LTQ_WDT_DIVIDER;
+ if (!priv->clk_rate) {
+ dev_err(dev, "clock rate less than divider %i\n",
+ LTQ_WDT_DIVIDER);
+ return -EINVAL;
}
- ltq_io_region_clk_rate = clk_get_rate(clk);
- clk_put(clk);
- dev_info(&pdev->dev, "Init done\n");
- return misc_register(&ltq_wdt_miscdev);
-}
+ wdt = &priv->wdt;
+ wdt->info = &ltq_wdt_info;
+ wdt->ops = &ltq_wdt_ops;
+ wdt->min_timeout = 1;
+ wdt->max_timeout = LTQ_WDT_CR_MAX_TIMEOUT / priv->clk_rate;
+ wdt->timeout = wdt->max_timeout;
+ wdt->parent = dev;
+
+ ltq_wdt_hw = of_device_get_match_data(dev);
+ if (ltq_wdt_hw && ltq_wdt_hw->bootstatus_get) {
+ ret = ltq_wdt_hw->bootstatus_get(dev);
+ if (ret >= 0)
+ wdt->bootstatus = ret;
+ }
-static int
-ltq_wdt_remove(struct platform_device *pdev)
-{
- misc_deregister(&ltq_wdt_miscdev);
+ watchdog_set_nowayout(wdt, nowayout);
+ watchdog_init_timeout(wdt, 0, dev);
+
+ status = ltq_wdt_r32(priv, LTQ_WDT_SR);
+ if (status & LTQ_WDT_SR_EN) {
+ /*
+ * If the watchdog is already running overwrite it with our
+ * new settings. Stop is not needed as the start call will
+ * replace all settings anyway.
+ */
+ ltq_wdt_start(wdt);
+ set_bit(WDOG_HW_RUNNING, &wdt->status);
+ }
- return 0;
+ return devm_watchdog_register_device(dev, wdt);
}
+static const struct ltq_wdt_hw ltq_wdt_xrx100 = {
+ .bootstatus_get = ltq_wdt_xrx_bootstatus_get,
+};
+
+static const struct ltq_wdt_hw ltq_wdt_falcon = {
+ .bootstatus_get = ltq_wdt_falcon_bootstatus_get,
+};
+
static const struct of_device_id ltq_wdt_match[] = {
- { .compatible = "lantiq,wdt", .data = NULL},
- { .compatible = "lantiq,xrx100-wdt", .data = ltq_wdt_bootstatus_xrx },
- { .compatible = "lantiq,falcon-wdt", .data = ltq_wdt_bootstatus_falcon },
+ { .compatible = "lantiq,wdt", .data = NULL },
+ { .compatible = "lantiq,xrx100-wdt", .data = &ltq_wdt_xrx100 },
+ { .compatible = "lantiq,falcon-wdt", .data = &ltq_wdt_falcon },
{},
};
MODULE_DEVICE_TABLE(of, ltq_wdt_match);
static struct platform_driver ltq_wdt_driver = {
.probe = ltq_wdt_probe,
- .remove = ltq_wdt_remove,
.driver = {
.name = "wdt",
.of_match_table = ltq_wdt_match,
diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c
index aca2d6323f8a..069072e6747d 100644
--- a/drivers/watchdog/mpc8xxx_wdt.c
+++ b/drivers/watchdog/mpc8xxx_wdt.c
@@ -17,8 +17,6 @@
* option) any later version.
*/
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -49,6 +47,7 @@ struct mpc8xxx_wdt {
struct mpc8xxx_wdt_type {
int prescaler;
bool hw_enabled;
+ u32 rsr_mask;
};
struct mpc8xxx_wdt_ddata {
@@ -137,36 +136,55 @@ static int mpc8xxx_wdt_probe(struct platform_device *ofdev)
struct mpc8xxx_wdt_ddata *ddata;
u32 freq = fsl_get_sys_freq();
bool enabled;
+ struct device *dev = &ofdev->dev;
- wdt_type = of_device_get_match_data(&ofdev->dev);
+ wdt_type = of_device_get_match_data(dev);
if (!wdt_type)
return -EINVAL;
if (!freq || freq == -1)
return -EINVAL;
- ddata = devm_kzalloc(&ofdev->dev, sizeof(*ddata), GFP_KERNEL);
+ ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
if (!ddata)
return -ENOMEM;
res = platform_get_resource(ofdev, IORESOURCE_MEM, 0);
- ddata->base = devm_ioremap_resource(&ofdev->dev, res);
+ ddata->base = devm_ioremap_resource(dev, res);
if (IS_ERR(ddata->base))
return PTR_ERR(ddata->base);
enabled = in_be32(&ddata->base->swcrr) & SWCRR_SWEN;
if (!enabled && wdt_type->hw_enabled) {
- pr_info("could not be enabled in software\n");
+ dev_info(dev, "could not be enabled in software\n");
return -ENODEV;
}
+ res = platform_get_resource(ofdev, IORESOURCE_MEM, 1);
+ if (res) {
+ bool status;
+ u32 __iomem *rsr = ioremap(res->start, resource_size(res));
+
+ if (!rsr)
+ return -ENOMEM;
+
+ status = in_be32(rsr) & wdt_type->rsr_mask;
+ ddata->wdd.bootstatus = status ? WDIOF_CARDRESET : 0;
+ /* clear reset status bits related to watchdog timer */
+ out_be32(rsr, wdt_type->rsr_mask);
+ iounmap(rsr);
+
+ dev_info(dev, "Last boot was %scaused by watchdog\n",
+ status ? "" : "not ");
+ }
+
spin_lock_init(&ddata->lock);
ddata->wdd.info = &mpc8xxx_wdt_info,
ddata->wdd.ops = &mpc8xxx_wdt_ops,
ddata->wdd.timeout = WATCHDOG_TIMEOUT;
- watchdog_init_timeout(&ddata->wdd, timeout, &ofdev->dev);
+ watchdog_init_timeout(&ddata->wdd, timeout, dev);
watchdog_set_nowayout(&ddata->wdd, nowayout);
@@ -189,12 +207,13 @@ static int mpc8xxx_wdt_probe(struct platform_device *ofdev)
ret = watchdog_register_device(&ddata->wdd);
if (ret) {
- pr_err("cannot register watchdog device (err=%d)\n", ret);
+ dev_err(dev, "cannot register watchdog device (err=%d)\n", ret);
return ret;
}
- pr_info("WDT driver for MPC8xxx initialized. mode:%s timeout=%d sec\n",
- reset ? "reset" : "interrupt", ddata->wdd.timeout);
+ dev_info(dev,
+ "WDT driver for MPC8xxx initialized. mode:%s timeout=%d sec\n",
+ reset ? "reset" : "interrupt", ddata->wdd.timeout);
platform_set_drvdata(ofdev, ddata);
return 0;
@@ -204,8 +223,8 @@ static int mpc8xxx_wdt_remove(struct platform_device *ofdev)
{
struct mpc8xxx_wdt_ddata *ddata = platform_get_drvdata(ofdev);
- pr_crit("Watchdog removed, expect the %s soon!\n",
- reset ? "reset" : "machine check exception");
+ dev_crit(&ofdev->dev, "Watchdog removed, expect the %s soon!\n",
+ reset ? "reset" : "machine check exception");
watchdog_unregister_device(&ddata->wdd);
return 0;
@@ -216,6 +235,7 @@ static const struct of_device_id mpc8xxx_wdt_match[] = {
.compatible = "mpc83xx_wdt",
.data = &(struct mpc8xxx_wdt_type) {
.prescaler = 0x10000,
+ .rsr_mask = BIT(3), /* RSR Bit SWRS */
},
},
{
@@ -223,6 +243,7 @@ static const struct of_device_id mpc8xxx_wdt_match[] = {
.data = &(struct mpc8xxx_wdt_type) {
.prescaler = 0x10000,
.hw_enabled = true,
+ .rsr_mask = BIT(20), /* RSTRSCR Bit WDT_RR */
},
},
{
@@ -230,6 +251,7 @@ static const struct of_device_id mpc8xxx_wdt_match[] = {
.data = &(struct mpc8xxx_wdt_type) {
.prescaler = 0x800,
.hw_enabled = true,
+ .rsr_mask = BIT(28), /* RSR Bit SWRS */
},
},
{},
diff --git a/drivers/watchdog/renesas_wdt.c b/drivers/watchdog/renesas_wdt.c
index 88d81feba4e6..0d74c3e48979 100644
--- a/drivers/watchdog/renesas_wdt.c
+++ b/drivers/watchdog/renesas_wdt.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Watchdog driver for Renesas WDT watchdog
*
* Copyright (C) 2015-17 Wolfram Sang, Sang Engineering <wsa@sang-engineering.com>
* Copyright (C) 2015-17 Renesas Electronics Corporation
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
*/
#include <linux/bitops.h>
#include <linux/clk.h>
@@ -234,6 +231,7 @@ static int rwdt_probe(struct platform_device *pdev)
watchdog_set_drvdata(&priv->wdev, priv);
watchdog_set_nowayout(&priv->wdev, nowayout);
watchdog_set_restart_priority(&priv->wdev, 0);
+ watchdog_stop_on_unregister(&priv->wdev);
/* This overrides the default timeout only if DT configuration was found */
ret = watchdog_init_timeout(&priv->wdev, 0, &pdev->dev);
diff --git a/drivers/watchdog/rza_wdt.c b/drivers/watchdog/rza_wdt.c
index e618218d2374..781bb572e6af 100644
--- a/drivers/watchdog/rza_wdt.c
+++ b/drivers/watchdog/rza_wdt.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Renesas RZ/A Series WDT Driver
*
* Copyright (C) 2017 Renesas Electronics America, Inc.
* Copyright (C) 2017 Chris Brandt
- *
- * 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/bitops.h>
@@ -14,6 +11,7 @@
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/of_address.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/watchdog.h>
@@ -34,12 +32,45 @@
#define WRCSR_RSTE BIT(6)
#define WRCSR_CLEAR_WOVF 0xA500 /* special value */
+/* The maximum CKS register setting value to get the longest timeout */
+#define CKS_3BIT 0x7
+#define CKS_4BIT 0xF
+
+#define DIVIDER_3BIT 16384 /* Clock divider when CKS = 0x7 */
+#define DIVIDER_4BIT 4194304 /* Clock divider when CKS = 0xF */
+
struct rza_wdt {
struct watchdog_device wdev;
void __iomem *base;
struct clk *clk;
+ u8 count;
+ u8 cks;
};
+static void rza_wdt_calc_timeout(struct rza_wdt *priv, int timeout)
+{
+ unsigned long rate = clk_get_rate(priv->clk);
+ unsigned int ticks;
+
+ if (priv->cks == CKS_4BIT) {
+ ticks = DIV_ROUND_UP(timeout * rate, DIVIDER_4BIT);
+
+ /*
+ * Since max_timeout was set in probe, we know that the timeout
+ * value passed will never calculate to a tick value greater
+ * than 256.
+ */
+ priv->count = 256 - ticks;
+
+ } else {
+ /* Start timer with longest timeout */
+ priv->count = 0;
+ }
+
+ pr_debug("%s: timeout set to %u (WTCNT=%d)\n", __func__,
+ timeout, priv->count);
+}
+
static int rza_wdt_start(struct watchdog_device *wdev)
{
struct rza_wdt *priv = watchdog_get_drvdata(wdev);
@@ -51,13 +82,12 @@ static int rza_wdt_start(struct watchdog_device *wdev)
readb(priv->base + WRCSR);
writew(WRCSR_CLEAR_WOVF, priv->base + WRCSR);
- /*
- * Start timer with slowest clock source and reset option enabled.
- */
+ rza_wdt_calc_timeout(priv, wdev->timeout);
+
writew(WRCSR_MAGIC | WRCSR_RSTE, priv->base + WRCSR);
- writew(WTCNT_MAGIC | 0, priv->base + WTCNT);
- writew(WTCSR_MAGIC | WTSCR_WT | WTSCR_TME | WTSCR_CKS(7),
- priv->base + WTCSR);
+ writew(WTCNT_MAGIC | priv->count, priv->base + WTCNT);
+ writew(WTCSR_MAGIC | WTSCR_WT | WTSCR_TME |
+ WTSCR_CKS(priv->cks), priv->base + WTCSR);
return 0;
}
@@ -75,8 +105,17 @@ static int rza_wdt_ping(struct watchdog_device *wdev)
{
struct rza_wdt *priv = watchdog_get_drvdata(wdev);
- writew(WTCNT_MAGIC | 0, priv->base + WTCNT);
+ writew(WTCNT_MAGIC | priv->count, priv->base + WTCNT);
+
+ pr_debug("%s: timeout = %u\n", __func__, wdev->timeout);
+
+ return 0;
+}
+static int rza_set_timeout(struct watchdog_device *wdev, unsigned int timeout)
+{
+ wdev->timeout = timeout;
+ rza_wdt_start(wdev);
return 0;
}
@@ -121,6 +160,7 @@ static const struct watchdog_ops rza_wdt_ops = {
.start = rza_wdt_start,
.stop = rza_wdt_stop,
.ping = rza_wdt_ping,
+ .set_timeout = rza_set_timeout,
.restart = rza_wdt_restart,
};
@@ -150,20 +190,28 @@ static int rza_wdt_probe(struct platform_device *pdev)
return -ENOENT;
}
- /* Assume slowest clock rate possible (CKS=7) */
- rate /= 16384;
-
priv->wdev.info = &rza_wdt_ident,
priv->wdev.ops = &rza_wdt_ops,
priv->wdev.parent = &pdev->dev;
- /*
- * Since the max possible timeout of our 8-bit count register is less
- * than a second, we must use max_hw_heartbeat_ms.
- */
- priv->wdev.max_hw_heartbeat_ms = (1000 * U8_MAX) / rate;
- dev_dbg(&pdev->dev, "max hw timeout of %dms\n",
- priv->wdev.max_hw_heartbeat_ms);
+ priv->cks = (u8)(uintptr_t)of_device_get_match_data(&pdev->dev);
+ if (priv->cks == CKS_4BIT) {
+ /* Assume slowest clock rate possible (CKS=0xF) */
+ priv->wdev.max_timeout = (DIVIDER_4BIT * U8_MAX) / rate;
+
+ } else if (priv->cks == CKS_3BIT) {
+ /* Assume slowest clock rate possible (CKS=7) */
+ rate /= DIVIDER_3BIT;
+
+ /*
+ * Since the max possible timeout of our 8-bit count
+ * register is less than a second, we must use
+ * max_hw_heartbeat_ms.
+ */
+ priv->wdev.max_hw_heartbeat_ms = (1000 * U8_MAX) / rate;
+ dev_dbg(&pdev->dev, "max hw timeout of %dms\n",
+ priv->wdev.max_hw_heartbeat_ms);
+ }
priv->wdev.min_timeout = 1;
priv->wdev.timeout = DEFAULT_TIMEOUT;
@@ -179,7 +227,8 @@ static int rza_wdt_probe(struct platform_device *pdev)
}
static const struct of_device_id rza_wdt_of_match[] = {
- { .compatible = "renesas,rza-wdt", },
+ { .compatible = "renesas,r7s9210-wdt", .data = (void *)CKS_4BIT, },
+ { .compatible = "renesas,rza-wdt", .data = (void *)CKS_3BIT, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, rza_wdt_of_match);
diff --git a/drivers/watchdog/sama5d4_wdt.c b/drivers/watchdog/sama5d4_wdt.c
index 255169916dbb..1e93c1b0e3cf 100644
--- a/drivers/watchdog/sama5d4_wdt.c
+++ b/drivers/watchdog/sama5d4_wdt.c
@@ -247,11 +247,7 @@ static int sama5d4_wdt_probe(struct platform_device *pdev)
}
}
- ret = watchdog_init_timeout(wdd, wdt_timeout, &pdev->dev);
- if (ret) {
- dev_err(&pdev->dev, "unable to set timeout value\n");
- return ret;
- }
+ watchdog_init_timeout(wdd, wdt_timeout, &pdev->dev);
timeout = WDT_SEC2TICKS(wdd->timeout);
diff --git a/drivers/watchdog/ts4800_wdt.c b/drivers/watchdog/ts4800_wdt.c
index 2b8de8602b67..89843b16b04a 100644
--- a/drivers/watchdog/ts4800_wdt.c
+++ b/drivers/watchdog/ts4800_wdt.c
@@ -135,6 +135,7 @@ static int ts4800_wdt_probe(struct platform_device *pdev)
/* set regmap and offset to know where to write */
wdt->feed_offset = reg;
wdt->regmap = syscon_node_to_regmap(syscon_np);
+ of_node_put(syscon_np);
if (IS_ERR(wdt->regmap)) {
dev_err(&pdev->dev, "cannot get parent's regmap\n");
return PTR_ERR(wdt->regmap);
diff --git a/drivers/watchdog/via_wdt.c b/drivers/watchdog/via_wdt.c
index b085ef1084ec..d56d0a927a1e 100644
--- a/drivers/watchdog/via_wdt.c
+++ b/drivers/watchdog/via_wdt.c
@@ -30,7 +30,7 @@
#define VIA_WDT_CONF_MMIO 0x02 /* 1: enable watchdog MMIO */
/*
- * The MMIO region contains the watchog control register and the
+ * The MMIO region contains the watchdog control register and the
* hardware timer counter.
*/
#define VIA_WDT_MMIO_LEN 8 /* MMIO region length in bytes */
@@ -82,7 +82,7 @@ static inline void wdt_reset(void)
/*
* Timer tick: the timer will make sure that the watchdog timer hardware
* is being reset in time. The conditions to do this are:
- * 1) the watchog timer has been started and /dev/watchdog is open
+ * 1) the watchdog timer has been started and /dev/watchdog is open
* and there is still time left before userspace should send the
* next heartbeat/ping. (note: the internal heartbeat is much smaller
* then the external/userspace heartbeat).
diff --git a/drivers/watchdog/w83627hf_wdt.c b/drivers/watchdog/w83627hf_wdt.c
index 7817836bff55..4b9365d4de7a 100644
--- a/drivers/watchdog/w83627hf_wdt.c
+++ b/drivers/watchdog/w83627hf_wdt.c
@@ -50,7 +50,7 @@ static int cr_wdt_csr; /* WDT control & status register */
enum chips { w83627hf, w83627s, w83697hf, w83697ug, w83637hf, w83627thf,
w83687thf, w83627ehf, w83627dhg, w83627uhg, w83667hg, w83627dhg_p,
w83667hg_b, nct6775, nct6776, nct6779, nct6791, nct6792, nct6793,
- nct6795, nct6102 };
+ nct6795, nct6796, nct6102 };
static int timeout; /* in seconds */
module_param(timeout, int, 0);
@@ -100,6 +100,7 @@ MODULE_PARM_DESC(early_disable, "Disable watchdog at boot time (default=0)");
#define NCT6792_ID 0xc9
#define NCT6793_ID 0xd1
#define NCT6795_ID 0xd3
+#define NCT6796_ID 0xd4 /* also NCT9697D, NCT9698D */
#define W83627HF_WDT_TIMEOUT 0xf6
#define W83697HF_WDT_TIMEOUT 0xf4
@@ -209,6 +210,7 @@ static int w83627hf_init(struct watchdog_device *wdog, enum chips chip)
case nct6792:
case nct6793:
case nct6795:
+ case nct6796:
case nct6102:
/*
* These chips have a fixed WDTO# output pin (W83627UHG),
@@ -407,6 +409,9 @@ static int wdt_find(int addr)
case NCT6795_ID:
ret = nct6795;
break;
+ case NCT6796_ID:
+ ret = nct6796;
+ break;
case NCT6102_ID:
ret = nct6102;
cr_wdt_timeout = NCT6102D_WDT_TIMEOUT;
@@ -450,6 +455,7 @@ static int __init wdt_init(void)
"NCT6792",
"NCT6793",
"NCT6795",
+ "NCT6796",
"NCT6102",
};
diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c
index ffbdc4642ea5..f6c24b22b37c 100644
--- a/drivers/watchdog/watchdog_dev.c
+++ b/drivers/watchdog/watchdog_dev.c
@@ -1019,16 +1019,16 @@ static void watchdog_cdev_unregister(struct watchdog_device *wdd)
old_wd_data = NULL;
}
- mutex_lock(&wd_data->lock);
- wd_data->wdd = NULL;
- wdd->wd_data = NULL;
- mutex_unlock(&wd_data->lock);
-
if (watchdog_active(wdd) &&
test_bit(WDOG_STOP_ON_UNREGISTER, &wdd->status)) {
watchdog_stop(wdd);
}
+ mutex_lock(&wd_data->lock);
+ wd_data->wdd = NULL;
+ wdd->wd_data = NULL;
+ mutex_unlock(&wd_data->lock);
+
hrtimer_cancel(&wd_data->timer);
kthread_cancel_work_sync(&wd_data->work);
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
index 90d387b50ab7..815b9e9bb975 100644
--- a/drivers/xen/Kconfig
+++ b/drivers/xen/Kconfig
@@ -12,7 +12,6 @@ config XEN_BALLOON
config XEN_SELFBALLOONING
bool "Dynamically self-balloon kernel memory to target"
depends on XEN && XEN_BALLOON && CLEANCACHE && SWAP && XEN_TMEM
- default n
help
Self-ballooning dynamically balloons available kernel memory driven
by the current usage of anonymous memory ("committed AS") and
@@ -27,7 +26,6 @@ config XEN_SELFBALLOONING
config XEN_BALLOON_MEMORY_HOTPLUG
bool "Memory hotplug support for Xen balloon driver"
- default n
depends on XEN_BALLOON && MEMORY_HOTPLUG
help
Memory hotplug support for Xen balloon driver allows expanding memory
@@ -86,7 +84,7 @@ config XEN_SCRUB_PAGES_DEFAULT
help
Scrub pages before returning them to the system for reuse by
other domains. This makes sure that any confidential data
- is not accidentally visible to other domains. Is it more
+ is not accidentally visible to other domains. It is more
secure, but slightly less efficient. This can be controlled with
xen_scrub_pages=0 parameter and
/sys/devices/system/xen_memory/xen_memory0/scrub_pages.
@@ -105,8 +103,7 @@ config XEN_DEV_EVTCHN
config XEN_BACKEND
bool "Backend driver support"
- depends on XEN_DOM0
- default y
+ default XEN_DOM0
help
Support for backend device drivers that provide I/O services
to other virtual machines.
@@ -227,7 +224,6 @@ config XEN_PCIDEV_BACKEND
config XEN_PVCALLS_FRONTEND
tristate "XEN PV Calls frontend driver"
depends on INET && XEN
- default n
select XEN_XENBUS_FRONTEND
help
Experimental frontend for the Xen PV Calls protocol
@@ -238,7 +234,6 @@ config XEN_PVCALLS_FRONTEND
config XEN_PVCALLS_BACKEND
bool "XEN PV Calls backend driver"
depends on INET && XEN && XEN_BACKEND
- default n
help
Experimental backend for the Xen PV Calls protocol
(https://xenbits.xen.org/docs/unstable/misc/pvcalls.html). It
@@ -264,7 +259,6 @@ config XEN_PRIVCMD
config XEN_STUB
bool "Xen stub drivers"
depends on XEN && X86_64 && BROKEN
- default n
help
Allow kernel to install stub drivers, to reserve space for Xen drivers,
i.e. memory hotplug and cpu hotplug, and to block native drivers loaded,
@@ -275,7 +269,6 @@ config XEN_STUB
config XEN_ACPI_HOTPLUG_MEMORY
tristate "Xen ACPI memory hotplug"
depends on XEN_DOM0 && XEN_STUB && ACPI
- default n
help
This is Xen ACPI memory hotplug.
@@ -287,7 +280,6 @@ config XEN_ACPI_HOTPLUG_CPU
tristate "Xen ACPI cpu hotplug"
depends on XEN_DOM0 && XEN_STUB && ACPI
select ACPI_CONTAINER
- default n
help
Xen ACPI cpu enumerating and hotplugging
@@ -316,7 +308,6 @@ config XEN_ACPI_PROCESSOR
config XEN_MCE_LOG
bool "Xen platform mcelog"
depends on XEN_DOM0 && X86_64 && X86_MCE
- default n
help
Allow kernel fetching MCE error from Xen platform and
converting it into Linux mcelog format for mcelog tools
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c
index e12bb256036f..fdfc64f5acea 100644
--- a/drivers/xen/balloon.c
+++ b/drivers/xen/balloon.c
@@ -44,7 +44,7 @@
#include <linux/cred.h>
#include <linux/errno.h>
#include <linux/mm.h>
-#include <linux/bootmem.h>
+#include <linux/memblock.h>
#include <linux/pagemap.h>
#include <linux/highmem.h>
#include <linux/mutex.h>
@@ -395,7 +395,10 @@ static enum bp_state reserve_additional_memory(void)
* callers drop the mutex before trying again.
*/
mutex_unlock(&balloon_mutex);
+ /* add_memory_resource() requires the device_hotplug lock */
+ lock_device_hotplug();
rc = add_memory_resource(nid, resource, memhp_auto_online);
+ unlock_device_hotplug();
mutex_lock(&balloon_mutex);
if (rc) {
diff --git a/drivers/xen/biomerge.c b/drivers/xen/biomerge.c
index 55ed80c3a17c..f3fbb700f569 100644
--- a/drivers/xen/biomerge.c
+++ b/drivers/xen/biomerge.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/bio.h>
-#include <linux/io.h>
#include <linux/export.h>
+#include <xen/xen.h>
#include <xen/page.h>
bool xen_biovec_phys_mergeable(const struct bio_vec *vec1,
@@ -20,4 +20,3 @@ bool xen_biovec_phys_mergeable(const struct bio_vec *vec1,
return false;
#endif
}
-EXPORT_SYMBOL(xen_biovec_phys_mergeable);
diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c
index e6c1934734b7..93194f3e7540 100644
--- a/drivers/xen/events/events_base.c
+++ b/drivers/xen/events/events_base.c
@@ -28,7 +28,7 @@
#include <linux/irq.h>
#include <linux/moduleparam.h>
#include <linux/string.h>
-#include <linux/bootmem.h>
+#include <linux/memblock.h>
#include <linux/slab.h>
#include <linux/irqnr.h>
#include <linux/pci.h>
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c
index 84575baceebc..7ea6fb6a2e5d 100644
--- a/drivers/xen/grant-table.c
+++ b/drivers/xen/grant-table.c
@@ -33,7 +33,7 @@
#define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt
-#include <linux/bootmem.h>
+#include <linux/memblock.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/slab.h>
@@ -914,7 +914,7 @@ int gnttab_dma_free_pages(struct gnttab_dma_alloc_args *args)
ret = xenmem_reservation_increase(args->nr_pages, args->frames);
if (ret != args->nr_pages) {
- pr_debug("Failed to decrease reservation for DMA buffer\n");
+ pr_debug("Failed to increase reservation for DMA buffer\n");
ret = -EFAULT;
} else {
ret = 0;
diff --git a/drivers/xen/privcmd-buf.c b/drivers/xen/privcmd-buf.c
index df1ed37c3269..de01a6d0059d 100644
--- a/drivers/xen/privcmd-buf.c
+++ b/drivers/xen/privcmd-buf.c
@@ -21,15 +21,9 @@
MODULE_LICENSE("GPL");
-static unsigned int limit = 64;
-module_param(limit, uint, 0644);
-MODULE_PARM_DESC(limit, "Maximum number of pages that may be allocated by "
- "the privcmd-buf device per open file");
-
struct privcmd_buf_private {
struct mutex lock;
struct list_head list;
- unsigned int allocated;
};
struct privcmd_buf_vma_private {
@@ -60,13 +54,10 @@ static void privcmd_buf_vmapriv_free(struct privcmd_buf_vma_private *vma_priv)
{
unsigned int i;
- vma_priv->file_priv->allocated -= vma_priv->n_pages;
-
list_del(&vma_priv->list);
for (i = 0; i < vma_priv->n_pages; i++)
- if (vma_priv->pages[i])
- __free_page(vma_priv->pages[i]);
+ __free_page(vma_priv->pages[i]);
kfree(vma_priv);
}
@@ -146,8 +137,7 @@ static int privcmd_buf_mmap(struct file *file, struct vm_area_struct *vma)
unsigned int i;
int ret = 0;
- if (!(vma->vm_flags & VM_SHARED) || count > limit ||
- file_priv->allocated + count > limit)
+ if (!(vma->vm_flags & VM_SHARED))
return -EINVAL;
vma_priv = kzalloc(sizeof(*vma_priv) + count * sizeof(void *),
@@ -155,19 +145,15 @@ static int privcmd_buf_mmap(struct file *file, struct vm_area_struct *vma)
if (!vma_priv)
return -ENOMEM;
- vma_priv->n_pages = count;
- count = 0;
- for (i = 0; i < vma_priv->n_pages; i++) {
+ for (i = 0; i < count; i++) {
vma_priv->pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO);
if (!vma_priv->pages[i])
break;
- count++;
+ vma_priv->n_pages++;
}
mutex_lock(&file_priv->lock);
- file_priv->allocated += count;
-
vma_priv->file_priv = file_priv;
vma_priv->users = 1;
diff --git a/drivers/xen/pvcalls-back.c b/drivers/xen/pvcalls-back.c
index b1092fbefa63..2e5d845b5091 100644
--- a/drivers/xen/pvcalls-back.c
+++ b/drivers/xen/pvcalls-back.c
@@ -137,13 +137,13 @@ static void pvcalls_conn_back_read(void *opaque)
if (masked_prod < masked_cons) {
vec[0].iov_base = data->in + masked_prod;
vec[0].iov_len = wanted;
- iov_iter_kvec(&msg.msg_iter, ITER_KVEC|WRITE, vec, 1, wanted);
+ iov_iter_kvec(&msg.msg_iter, WRITE, vec, 1, wanted);
} else {
vec[0].iov_base = data->in + masked_prod;
vec[0].iov_len = array_size - masked_prod;
vec[1].iov_base = data->in;
vec[1].iov_len = wanted - vec[0].iov_len;
- iov_iter_kvec(&msg.msg_iter, ITER_KVEC|WRITE, vec, 2, wanted);
+ iov_iter_kvec(&msg.msg_iter, WRITE, vec, 2, wanted);
}
atomic_set(&map->read, 0);
@@ -195,13 +195,13 @@ static void pvcalls_conn_back_write(struct sock_mapping *map)
if (pvcalls_mask(prod, array_size) > pvcalls_mask(cons, array_size)) {
vec[0].iov_base = data->out + pvcalls_mask(cons, array_size);
vec[0].iov_len = size;
- iov_iter_kvec(&msg.msg_iter, ITER_KVEC|READ, vec, 1, size);
+ iov_iter_kvec(&msg.msg_iter, READ, vec, 1, size);
} else {
vec[0].iov_base = data->out + pvcalls_mask(cons, array_size);
vec[0].iov_len = array_size - pvcalls_mask(cons, array_size);
vec[1].iov_base = data->out;
vec[1].iov_len = size - vec[0].iov_len;
- iov_iter_kvec(&msg.msg_iter, ITER_KVEC|READ, vec, 2, size);
+ iov_iter_kvec(&msg.msg_iter, READ, vec, 2, size);
}
atomic_set(&map->write, 0);
diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
index a6f9ba85dc4b..2a7f545bd0b5 100644
--- a/drivers/xen/swiotlb-xen.c
+++ b/drivers/xen/swiotlb-xen.c
@@ -35,7 +35,7 @@
#define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt
-#include <linux/bootmem.h>
+#include <linux/memblock.h>
#include <linux/dma-direct.h>
#include <linux/export.h>
#include <xen/swiotlb-xen.h>
@@ -217,7 +217,8 @@ retry:
* Get IO TLB memory from any location.
*/
if (early)
- xen_io_tlb_start = alloc_bootmem_pages(PAGE_ALIGN(bytes));
+ xen_io_tlb_start = memblock_alloc(PAGE_ALIGN(bytes),
+ PAGE_SIZE);
else {
#define SLABS_PER_PAGE (1 << (PAGE_SHIFT - IO_TLB_SHIFT))
#define IO_TLB_MIN_SLABS ((1<<20) >> IO_TLB_SHIFT)
@@ -247,7 +248,8 @@ retry:
xen_io_tlb_nslabs);
if (rc) {
if (early)
- free_bootmem(__pa(xen_io_tlb_start), PAGE_ALIGN(bytes));
+ memblock_free(__pa(xen_io_tlb_start),
+ PAGE_ALIGN(bytes));
else {
free_pages((unsigned long)xen_io_tlb_start, order);
xen_io_tlb_start = NULL;
@@ -303,6 +305,9 @@ xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
*/
flags &= ~(__GFP_DMA | __GFP_HIGHMEM);
+ /* Convert the size to actually allocated. */
+ size = 1UL << (order + XEN_PAGE_SHIFT);
+
/* On ARM this function returns an ioremap'ped virtual address for
* which virt_to_phys doesn't return the corresponding physical
* address. In fact on ARM virt_to_phys only works for kernel direct
@@ -351,6 +356,9 @@ xen_swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr,
* physical address */
phys = xen_bus_to_phys(dev_addr);
+ /* Convert the size to actually allocated. */
+ size = 1UL << (order + XEN_PAGE_SHIFT);
+
if (((dev_addr + size - 1 <= dma_mask)) ||
range_straddles_page_boundary(phys, size))
xen_destroy_contiguous_region(phys, order);
@@ -662,7 +670,7 @@ xen_swiotlb_dma_mmap(struct device *dev, struct vm_area_struct *vma,
return xen_get_dma_ops(dev)->mmap(dev, vma, cpu_addr,
dma_addr, size, attrs);
#endif
- return dma_common_mmap(dev, vma, cpu_addr, dma_addr, size);
+ return dma_common_mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
}
/*
@@ -689,7 +697,7 @@ xen_swiotlb_get_sgtable(struct device *dev, struct sg_table *sgt,
handle, size, attrs);
}
#endif
- return dma_common_get_sgtable(dev, sgt, cpu_addr, handle, size);
+ return dma_common_get_sgtable(dev, sgt, cpu_addr, handle, size, attrs);
}
static int xen_swiotlb_mapping_error(struct device *dev, dma_addr_t dma_addr)
diff --git a/drivers/xen/time.c b/drivers/xen/time.c
index 3e741cd1409c..0968859c29d0 100644
--- a/drivers/xen/time.c
+++ b/drivers/xen/time.c
@@ -175,7 +175,7 @@ void __init xen_time_setup_guest(void)
xen_runstate_remote = !HYPERVISOR_vm_assist(VMASST_CMD_enable,
VMASST_TYPE_runstate_update_flag);
- pv_time_ops.steal_clock = xen_steal_clock;
+ pv_ops.time.steal_clock = xen_steal_clock;
static_key_slow_inc(&paravirt_steal_enabled);
if (xen_runstate_remote)
diff --git a/drivers/xen/xen-acpi-pad.c b/drivers/xen/xen-acpi-pad.c
index 23d1808fe027..e25ab76b9c99 100644
--- a/drivers/xen/xen-acpi-pad.c
+++ b/drivers/xen/xen-acpi-pad.c
@@ -19,6 +19,7 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/acpi.h>
+#include <xen/xen.h>
#include <xen/interface/version.h>
#include <xen/xen-ops.h>
#include <asm/xen/hypercall.h>
diff --git a/drivers/xen/xen-balloon.c b/drivers/xen/xen-balloon.c
index 63c1494a8d73..2acbfe104e46 100644
--- a/drivers/xen/xen-balloon.c
+++ b/drivers/xen/xen-balloon.c
@@ -76,12 +76,15 @@ static void watch_target(struct xenbus_watch *watch,
if (!watch_fired) {
watch_fired = true;
- err = xenbus_scanf(XBT_NIL, "memory", "static-max", "%llu",
- &static_max);
- if (err != 1)
- static_max = new_target;
- else
+
+ if ((xenbus_scanf(XBT_NIL, "memory", "static-max",
+ "%llu", &static_max) == 1) ||
+ (xenbus_scanf(XBT_NIL, "memory", "memory_static_max",
+ "%llu", &static_max) == 1))
static_max >>= PAGE_SHIFT - 10;
+ else
+ static_max = new_target;
+
target_diff = (xen_pv_domain() || xen_initial_domain()) ? 0
: static_max - balloon_stats.target_pages;
}
diff --git a/drivers/xen/xen-selfballoon.c b/drivers/xen/xen-selfballoon.c
index 55988b8418ee..5165aa82bf7d 100644
--- a/drivers/xen/xen-selfballoon.c
+++ b/drivers/xen/xen-selfballoon.c
@@ -68,7 +68,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
-#include <linux/bootmem.h>
+#include <linux/memblock.h>
#include <linux/swap.h>
#include <linux/mm.h>
#include <linux/mman.h>
diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c
index a1c17000129b..e17ca8156171 100644
--- a/drivers/xen/xenbus/xenbus_client.c
+++ b/drivers/xen/xenbus/xenbus_client.c
@@ -278,10 +278,8 @@ static void xenbus_va_dev_error(struct xenbus_device *dev, int err,
dev_err(&dev->dev, "%s\n", printf_buffer);
path_buffer = kasprintf(GFP_KERNEL, "error/%s", dev->nodename);
- if (!path_buffer ||
- xenbus_write(XBT_NIL, path_buffer, "error", printf_buffer))
- dev_err(&dev->dev, "failed to write error node for %s (%s)\n",
- dev->nodename, printf_buffer);
+ if (path_buffer)
+ xenbus_write(XBT_NIL, path_buffer, "error", printf_buffer);
kfree(printf_buffer);
kfree(path_buffer);